Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntonio Vazquez <blendergit@gmail.com>2019-10-02 14:15:37 +0300
committerAntonio Vazquez <blendergit@gmail.com>2019-10-02 14:15:37 +0300
commit386ba094988fc793f8e060d15438566e5e2d2cae (patch)
tree4cbde50b5d1d7a45c89ee99c29dd1b86d1d97b59
parent6129e20cec4639aebf335ff13b2ba0c59670662d (diff)
parentf97a64aa9b7b384f8221a1ef4f2eef9cde1238db (diff)
Merge branch 'master' into temp-gpencil-drw-engine
Conflicts: source/blender/draw/engines/gpencil/gpencil_engine.c
-rw-r--r--.clang-format11
-rw-r--r--CMakeLists.txt30
-rw-r--r--GNUmakefile38
-rw-r--r--build_files/build_environment/CMakeLists.txt2
-rw-r--r--build_files/build_environment/cmake/blendthumb.cmake67
-rw-r--r--build_files/build_environment/cmake/check_software.cmake53
-rw-r--r--build_files/build_environment/cmake/harvest.cmake3
-rwxr-xr-xbuild_files/build_environment/install_deps.sh7
-rw-r--r--build_files/buildbot/buildbot_utils.py112
-rw-r--r--build_files/buildbot/slave_compile.py212
-rw-r--r--build_files/buildbot/slave_pack.py320
-rw-r--r--build_files/buildbot/slave_rsync.py24
-rw-r--r--build_files/buildbot/slave_test.py63
-rw-r--r--build_files/buildbot/slave_update.py31
-rw-r--r--build_files/cmake/Modules/FindOptiX.cmake57
-rw-r--r--build_files/cmake/Modules/GTestTesting.cmake23
-rw-r--r--build_files/cmake/buildinfo.cmake21
-rw-r--r--build_files/cmake/config/blender_full.cmake1
-rw-r--r--build_files/cmake/config/blender_lite.cmake2
-rw-r--r--build_files/cmake/config/blender_release.cmake2
-rw-r--r--build_files/cmake/macros.cmake2
-rw-r--r--build_files/cmake/platform/platform_apple.cmake4
-rwxr-xr-xbuild_files/utils/make_test.py75
-rwxr-xr-xbuild_files/utils/make_update.py168
-rwxr-xr-xbuild_files/utils/make_utils.py64
-rw-r--r--build_files/windows/check_libraries.cmd9
-rw-r--r--build_files/windows/configure_ninja.cmd12
-rw-r--r--build_files/windows/find_dependencies.cmd12
-rw-r--r--build_files/windows/format.cmd5
-rw-r--r--build_files/windows/parse_arguments.cmd13
-rw-r--r--build_files/windows/reset_variables.cmd1
-rw-r--r--build_files/windows/show_help.cmd1
-rw-r--r--build_files/windows/test.cmd13
-rw-r--r--build_files/windows/update_sources.cmd25
-rwxr-xr-xdoc/manpage/blender.1.py21
-rw-r--r--doc/python_api/examples/bpy.types.Depsgraph.1.py2
-rw-r--r--doc/python_api/examples/bpy.types.UIList.2.py1
-rw-r--r--doc/python_api/rst/info_tips_and_tricks.rst2
-rw-r--r--extern/CMakeLists.txt5
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/AUTHORS26
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/CMakeLists.txt373
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/INSTALL167
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/LICENSE32
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/NEWS337
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/README50
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/cmake/FindCOIN.cmake110
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/cmake/FindGLPK.cmake55
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/cmake/FindGhostscript.cmake10
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/cmake/FindILOG.cmake102
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/cmake/FindSOPLEX.cmake23
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/cmake/LEMONConfig.cmake.in13
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/cmake/nsis/lemon.icobin0 -> 22486 bytes
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/cmake/nsis/uninstall.icobin0 -> 15086 bytes
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/cmake/version.cmake1
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/cmake/version.cmake.in1
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/contrib/CMakeLists.txt19
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/demo/CMakeLists.txt19
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/demo/arg_parser_demo.cc112
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/demo/digraph.lgf29
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/demo/graph_to_eps_demo.cc206
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/demo/lgf_demo.cc70
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/CMakeLists.txt91
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/adaptors.h3638
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc473
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.h440
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/assert.h214
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/base.cc37
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bellman_ford.h1116
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bfs.h1754
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bin_heap.h347
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/binomial_heap.h445
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/alteration_notifier.h472
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/array_map.h351
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/bezier.h174
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/default_map.h182
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/edge_set_extender.h627
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/enable_if.h131
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/graph_adaptor_extender.h401
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/graph_extender.h1332
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/lock.h65
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/map_extender.h332
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/path_dump.h177
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/solver_bits.h194
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/traits.h388
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/variant.h494
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/vector_map.h244
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/windows.cc166
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/windows.h44
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/bucket_heap.h594
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/capacity_scaling.h1014
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/cbc.cc460
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/cbc.h129
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/christofides_tsp.h254
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/circulation.h807
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/clp.cc464
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/clp.h164
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/color.cc44
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/color.h204
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/concept_check.h77
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/bpgraph.h1029
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/digraph.h491
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/graph.h788
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/graph_components.h2134
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/heap.h324
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/maps.h223
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/path.h312
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/config.h.in22
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/connectivity.h1688
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/core.h2506
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/cost_scaling.h1607
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/counter.h249
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/cplex.cc994
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/cplex.h292
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/cycle_canceling.h1230
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/dfs.h1637
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/dheap.h352
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/dijkstra.h1303
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/dim2.h726
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/dimacs.h448
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/edge_set.h1420
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/edmonds_karp.h556
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/elevator.h982
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/error.h276
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/euler.h287
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/fib_heap.h475
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/fractional_matching.h2139
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/full_graph.h1082
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/glpk.cc1012
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/glpk.h263
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/gomory_hu.h568
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/graph_to_eps.h1186
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/greedy_tsp.h251
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/grid_graph.h699
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/grosso_locatelli_pullan_mc.h840
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/hao_orlin.h1015
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/hartmann_orlin_mmc.h654
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/howard_mmc.h651
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/hypercube_graph.h459
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/insertion_tsp.h533
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/karp_mmc.h590
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/kruskal.h324
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/lemon.pc.in10
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_reader.h3854
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_writer.h2687
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/list_graph.h2510
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/lp.h95
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_base.cc30
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_base.h2147
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_skeleton.cc143
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_skeleton.h234
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/maps.h4057
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/matching.h3505
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/math.h77
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/max_cardinality_search.h794
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/min_cost_arborescence.h808
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/nagamochi_ibaraki.h702
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/nauty_reader.h113
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/nearest_neighbor_tsp.h238
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h1659
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/opt2_tsp.h367
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/pairing_heap.h474
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/path.h1164
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/planarity.h2754
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/preflow.h985
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/quad_heap.h343
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/radix_heap.h438
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/radix_sort.h487
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/random.cc29
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/random.h1005
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/smart_graph.h1344
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/soplex.cc465
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/soplex.h158
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/static_graph.h476
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/suurballe.h776
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/time_measure.h610
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/tolerance.h242
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/unionfind.h1824
-rwxr-xr-xextern/quadriflow/3rd/lemon-1.3.1/scripts/unify-sources.sh390
-rwxr-xr-xextern/quadriflow/3rd/lemon-1.3.1/scripts/valgrind-wrapper.sh22
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/CMakeLists.txt161
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/adaptors_test.cc1468
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/arc_look_up_test.cc84
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/bellman_ford_test.cc289
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/bfs_test.cc239
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/bpgraph_test.cc456
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/circulation_test.cc169
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/connectivity_test.cc316
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/counter_test.cc118
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/dfs_test.cc238
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/digraph_test.cc569
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/dijkstra_test.cc246
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/dim_test.cc87
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/edge_set_test.cc396
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/error_test.cc90
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/euler_test.cc225
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/fractional_matching_test.cc527
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/gomory_hu_test.cc142
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/graph_copy_test.cc388
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/graph_test.cc603
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/graph_test.h421
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/graph_utils_test.cc217
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/hao_orlin_test.cc164
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/heap_test.cc310
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/kruskal_test.cc147
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/lgf_reader_writer_test.cc578
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/lgf_test.cc169
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/lp_test.cc470
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/maps_test.cc1022
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/matching_test.cc449
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/max_cardinality_search_test.cc162
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/max_clique_test.cc188
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/max_flow_test.cc395
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/min_cost_arborescence_test.cc207
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/min_cost_flow_test.cc548
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/min_mean_cycle_test.cc223
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/mip_test.cc171
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/nagamochi_ibaraki_test.cc142
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/path_test.cc339
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/planarity_test.cc262
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/radix_sort_test.cc266
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/random_test.cc40
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/suurballe_test.cc267
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/test_tools.h50
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/test_tools_fail.cc25
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/test_tools_pass.cc25
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/time_measure_test.cc60
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/tsp_test.cc287
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/test/unionfind_test.cc102
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/tools/CMakeLists.txt31
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/tools/dimacs-solver.cc279
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/tools/dimacs-to-lgf.cc148
-rwxr-xr-xextern/quadriflow/3rd/lemon-1.3.1/tools/lemon-0.x-to-1.x.sh134
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/tools/lgf-gen.cc847
-rw-r--r--extern/quadriflow/3rd/pcg32/pcg32/pcg32.h209
-rw-r--r--extern/quadriflow/3rd/pss/pss/parallel_stable_sort.h140
-rw-r--r--extern/quadriflow/3rd/pss/pss/pss_common.h106
-rw-r--r--extern/quadriflow/CMakeLists.txt107
-rw-r--r--extern/quadriflow/LICENSE.txt37
-rw-r--r--extern/quadriflow/README.blender5
-rw-r--r--extern/quadriflow/README.md134
-rw-r--r--extern/quadriflow/patches/blender.patch102
-rw-r--r--extern/quadriflow/src/Optimizer.cu281
-rw-r--r--extern/quadriflow/src/adjacent-matrix.cpp35
-rw-r--r--extern/quadriflow/src/adjacent-matrix.hpp37
-rw-r--r--extern/quadriflow/src/compare-key.hpp102
-rw-r--r--extern/quadriflow/src/config.hpp34
-rw-r--r--extern/quadriflow/src/dedge.cpp487
-rw-r--r--extern/quadriflow/src/dedge.hpp25
-rw-r--r--extern/quadriflow/src/disajoint-tree.hpp151
-rw-r--r--extern/quadriflow/src/dset.hpp163
-rw-r--r--extern/quadriflow/src/field-math.hpp483
-rw-r--r--extern/quadriflow/src/flow.hpp375
-rw-r--r--extern/quadriflow/src/hierarchy.cpp1344
-rw-r--r--extern/quadriflow/src/hierarchy.hpp99
-rw-r--r--extern/quadriflow/src/loader.cpp159
-rw-r--r--extern/quadriflow/src/loader.hpp15
-rw-r--r--extern/quadriflow/src/localsat.cpp295
-rw-r--r--extern/quadriflow/src/localsat.hpp31
-rw-r--r--extern/quadriflow/src/main.cpp127
-rw-r--r--extern/quadriflow/src/merge-vertex.cpp44
-rw-r--r--extern/quadriflow/src/merge-vertex.hpp14
-rw-r--r--extern/quadriflow/src/optimizer.cpp1419
-rw-r--r--extern/quadriflow/src/optimizer.hpp56
-rw-r--r--extern/quadriflow/src/parametrizer-flip.cpp583
-rw-r--r--extern/quadriflow/src/parametrizer-int.cpp425
-rw-r--r--extern/quadriflow/src/parametrizer-mesh.cpp615
-rw-r--r--extern/quadriflow/src/parametrizer-scale.cpp119
-rw-r--r--extern/quadriflow/src/parametrizer-sing.cpp142
-rw-r--r--extern/quadriflow/src/parametrizer.cpp247
-rw-r--r--extern/quadriflow/src/parametrizer.hpp177
-rw-r--r--extern/quadriflow/src/post-solver.cpp427
-rw-r--r--extern/quadriflow/src/post-solver.hpp64
-rw-r--r--extern/quadriflow/src/serialize.hpp127
-rw-r--r--extern/quadriflow/src/subdivide.cpp516
-rw-r--r--extern/quadriflow/src/subdivide.hpp17
-rw-r--r--intern/CMakeLists.txt5
-rw-r--r--intern/cycles/CMakeLists.txt18
-rw-r--r--intern/cycles/blender/CMakeLists.txt4
-rw-r--r--intern/cycles/blender/addon/engine.py6
-rw-r--r--intern/cycles/blender/addon/properties.py106
-rw-r--r--intern/cycles/blender/addon/ui.py92
-rw-r--r--intern/cycles/blender/blender_camera.cpp2
-rw-r--r--intern/cycles/blender/blender_device.cpp7
-rw-r--r--intern/cycles/blender/blender_mesh.cpp20
-rw-r--r--intern/cycles/blender/blender_object.cpp25
-rw-r--r--intern/cycles/blender/blender_python.cpp25
-rw-r--r--intern/cycles/blender/blender_session.cpp21
-rw-r--r--intern/cycles/blender/blender_session.h2
-rw-r--r--intern/cycles/blender/blender_shader.cpp116
-rw-r--r--intern/cycles/blender/blender_sync.cpp28
-rw-r--r--intern/cycles/blender/blender_sync.h17
-rw-r--r--intern/cycles/blender/blender_viewport.cpp88
-rw-r--r--intern/cycles/blender/blender_viewport.h56
-rw-r--r--intern/cycles/bvh/CMakeLists.txt2
-rw-r--r--intern/cycles/bvh/bvh.cpp60
-rw-r--r--intern/cycles/bvh/bvh.h14
-rw-r--r--intern/cycles/bvh/bvh2.cpp5
-rw-r--r--intern/cycles/bvh/bvh2.h2
-rw-r--r--intern/cycles/bvh/bvh4.cpp5
-rw-r--r--intern/cycles/bvh/bvh4.h2
-rw-r--r--intern/cycles/bvh/bvh8.cpp5
-rw-r--r--intern/cycles/bvh/bvh8.h2
-rw-r--r--intern/cycles/bvh/bvh_embree.cpp15
-rw-r--r--intern/cycles/bvh/bvh_embree.h5
-rw-r--r--intern/cycles/bvh/bvh_optix.cpp215
-rw-r--r--intern/cycles/bvh/bvh_optix.h53
-rw-r--r--intern/cycles/device/CMakeLists.txt4
-rw-r--r--intern/cycles/device/device.cpp31
-rw-r--r--intern/cycles/device/device.h18
-rw-r--r--intern/cycles/device/device_cpu.cpp6
-rw-r--r--intern/cycles/device/device_cuda.cpp5
-rw-r--r--intern/cycles/device/device_intern.h4
-rw-r--r--intern/cycles/device/device_memory.cpp23
-rw-r--r--intern/cycles/device/device_memory.h16
-rw-r--r--intern/cycles/device/device_multi.cpp18
-rw-r--r--intern/cycles/device/device_optix.cpp1970
-rw-r--r--intern/cycles/device/opencl/opencl_split.cpp2
-rw-r--r--intern/cycles/device/opencl/opencl_util.cpp11
-rw-r--r--intern/cycles/graph/node.h2
-rw-r--r--intern/cycles/kernel/CMakeLists.txt80
-rw-r--r--intern/cycles/kernel/bvh/bvh.h444
-rw-r--r--intern/cycles/kernel/closure/bsdf.h37
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet.h12
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet_multi.h20
-rw-r--r--intern/cycles/kernel/closure/bsdf_util.h14
-rw-r--r--intern/cycles/kernel/geom/geom_curve_intersect.h4
-rw-r--r--intern/cycles/kernel/geom/geom_patch.h14
-rw-r--r--intern/cycles/kernel/geom/geom_primitive.h21
-rw-r--r--intern/cycles/kernel/geom/geom_subd_triangle.h124
-rw-r--r--intern/cycles/kernel/geom/geom_triangle.h47
-rw-r--r--intern/cycles/kernel/kernel_compat_cuda.h1
-rw-r--r--intern/cycles/kernel/kernel_compat_opencl.h1
-rw-r--r--intern/cycles/kernel/kernel_compat_optix.h89
-rw-r--r--intern/cycles/kernel/kernel_emission.h4
-rw-r--r--intern/cycles/kernel/kernel_film.h100
-rw-r--r--intern/cycles/kernel/kernel_globals.h41
-rw-r--r--intern/cycles/kernel/kernel_jitter.h34
-rw-r--r--intern/cycles/kernel/kernel_passes.h4
-rw-r--r--intern/cycles/kernel/kernel_path.h31
-rw-r--r--intern/cycles/kernel/kernel_path_surface.h24
-rw-r--r--intern/cycles/kernel/kernel_path_volume.h18
-rw-r--r--intern/cycles/kernel/kernel_random.h7
-rw-r--r--intern/cycles/kernel/kernel_shader.h16
-rw-r--r--intern/cycles/kernel/kernel_shadow.h54
-rw-r--r--intern/cycles/kernel/kernel_subsurface.h20
-rw-r--r--intern/cycles/kernel/kernel_types.h59
-rw-r--r--intern/cycles/kernel/kernel_volume.h6
-rw-r--r--intern/cycles/kernel/kernels/optix/kernel_optix.cu294
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp65
-rw-r--r--intern/cycles/kernel/shaders/CMakeLists.txt6
-rw-r--r--intern/cycles/kernel/shaders/node_brick_texture.osl1
-rw-r--r--intern/cycles/kernel/shaders/node_checker_texture.osl1
-rw-r--r--intern/cycles/kernel/shaders/node_gradient_texture.osl1
-rw-r--r--intern/cycles/kernel/shaders/node_hash.h81
-rw-r--r--intern/cycles/kernel/shaders/node_ies_light.osl1
-rw-r--r--intern/cycles/kernel/shaders/node_magic_texture.osl1
-rw-r--r--intern/cycles/kernel/shaders/node_mapping.osl61
-rw-r--r--intern/cycles/kernel/shaders/node_musgrave_texture.osl744
-rw-r--r--intern/cycles/kernel/shaders/node_noise.h198
-rw-r--r--intern/cycles/kernel/shaders/node_noise_texture.osl128
-rw-r--r--intern/cycles/kernel/shaders/node_texture.h165
-rw-r--r--intern/cycles/kernel/shaders/node_vertex_color.osl41
-rw-r--r--intern/cycles/kernel/shaders/node_voronoi_texture.osl1077
-rw-r--r--intern/cycles/kernel/shaders/node_wave_texture.osl4
-rw-r--r--intern/cycles/kernel/shaders/vector2.h291
-rw-r--r--intern/cycles/kernel/shaders/vector4.h327
-rw-r--r--intern/cycles/kernel/svm/svm.h24
-rw-r--r--intern/cycles/kernel/svm/svm_attribute.h29
-rw-r--r--intern/cycles/kernel/svm/svm_color_util.h8
-rw-r--r--intern/cycles/kernel/svm/svm_fractal_noise.h131
-rw-r--r--intern/cycles/kernel/svm/svm_mapping.h28
-rw-r--r--intern/cycles/kernel/svm/svm_mapping_util.h39
-rw-r--r--intern/cycles/kernel/svm/svm_musgrave.h809
-rw-r--r--intern/cycles/kernel/svm/svm_noise.h666
-rw-r--r--intern/cycles/kernel/svm/svm_noisetex.h178
-rw-r--r--intern/cycles/kernel/svm/svm_texture.h63
-rw-r--r--intern/cycles/kernel/svm/svm_types.h27
-rw-r--r--intern/cycles/kernel/svm/svm_vertex_color.h92
-rw-r--r--intern/cycles/kernel/svm/svm_voronoi.h1226
-rw-r--r--intern/cycles/kernel/svm/svm_wave.h2
-rw-r--r--intern/cycles/render/attribute.cpp3
-rw-r--r--intern/cycles/render/buffers.cpp2
-rw-r--r--intern/cycles/render/buffers.h1
-rw-r--r--intern/cycles/render/constant_fold.cpp17
-rw-r--r--intern/cycles/render/constant_fold.h1
-rw-r--r--intern/cycles/render/denoising.cpp4
-rw-r--r--intern/cycles/render/film.cpp46
-rw-r--r--intern/cycles/render/film.h3
-rw-r--r--intern/cycles/render/mesh.cpp57
-rw-r--r--intern/cycles/render/mesh.h26
-rw-r--r--intern/cycles/render/mesh_displace.cpp75
-rw-r--r--intern/cycles/render/mesh_subdivision.cpp133
-rw-r--r--intern/cycles/render/nodes.cpp326
-rw-r--r--intern/cycles/render/nodes.h31
-rw-r--r--intern/cycles/render/session.cpp46
-rw-r--r--intern/cycles/render/session.h6
-rw-r--r--intern/cycles/render/shader.cpp2
-rw-r--r--intern/cycles/subd/CMakeLists.txt1
-rw-r--r--intern/cycles/subd/subd_dice.cpp257
-rw-r--r--intern/cycles/subd/subd_dice.h75
-rw-r--r--intern/cycles/subd/subd_patch.h11
-rw-r--r--intern/cycles/subd/subd_split.cpp729
-rw-r--r--intern/cycles/subd/subd_split.h38
-rw-r--r--intern/cycles/subd/subd_subpatch.h219
-rw-r--r--intern/cycles/util/CMakeLists.txt1
-rw-r--r--intern/cycles/util/util_aligned_malloc.cpp8
-rw-r--r--intern/cycles/util/util_color.h18
-rw-r--r--intern/cycles/util/util_debug.cpp18
-rw-r--r--intern/cycles/util/util_debug.h16
-rw-r--r--intern/cycles/util/util_defines.h1
-rw-r--r--intern/cycles/util/util_deque.h28
-rw-r--r--intern/cycles/util/util_hash.h109
-rw-r--r--intern/cycles/util/util_map.h1
-rw-r--r--intern/cycles/util/util_math.h72
-rw-r--r--intern/cycles/util/util_math_float2.h31
-rw-r--r--intern/cycles/util/util_math_float3.h12
-rw-r--r--intern/cycles/util/util_math_float4.h42
-rw-r--r--intern/cycles/util/util_param.h5
-rw-r--r--intern/cycles/util/util_ssef.h26
-rw-r--r--intern/cycles/util/util_ssei.h9
-rw-r--r--intern/cycles/util/util_system.cpp2
-rw-r--r--intern/cycles/util/util_transform.h26
-rw-r--r--intern/ffmpeg/ffmpeg_compat.h38
-rw-r--r--intern/ghost/GHOST_C-api.h12
-rw-r--r--intern/ghost/GHOST_ISystem.h2
-rw-r--r--intern/ghost/GHOST_IWindow.h6
-rw-r--r--intern/ghost/GHOST_Types.h21
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp8
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerCocoa.mm3
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm180
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.h2
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm187
-rw-r--r--intern/ghost/intern/GHOST_WindowSDL.cpp92
-rw-r--r--intern/ghost/intern/GHOST_WindowSDL.h1
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp223
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h2
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp134
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.h3
-rw-r--r--intern/guardedalloc/intern/mallocn.c9
-rw-r--r--intern/libmv/libmv/autotrack/callbacks.h2
-rw-r--r--intern/libmv/libmv/base/aligned_malloc.cc7
-rw-r--r--intern/libmv/libmv/tracking/brute_region_tracker.cc2
-rw-r--r--intern/memutil/MEM_RefCounted.h10
-rw-r--r--intern/quadriflow/CMakeLists.txt45
-rw-r--r--intern/quadriflow/quadriflow_capi.cpp238
-rw-r--r--intern/quadriflow/quadriflow_capi.hpp54
-rw-r--r--intern/utfconv/utfconv.h36
-rw-r--r--make.bat19
-rw-r--r--release/darwin/Blender.app/Contents/Resources/arrowdown.pdfbin0 -> 4114 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/arrowleft.pdfbin0 -> 4108 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/arrowright.pdfbin0 -> 4113 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/arrowup.pdfbin0 -> 4105 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/crossc.pdfbin0 -> 4079 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/eraser.pdfbin0 -> 4187 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/eyedropper.pdfbin0 -> 4500 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/knife.pdfbin0 -> 4134 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/paint_cursor_cross.pdfbin0 -> 4300 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/paint_cursor_dot.pdfbin0 -> 4147 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/pen.pdfbin0 -> 4173 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/scrollew.pdfbin0 -> 4157 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/scrollns.pdfbin0 -> 4175 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/scrollnsew.pdfbin0 -> 4317 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/splith.pdfbin0 -> 4351 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/splitv.pdfbin0 -> 4343 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/zoomin.pdf674
-rw-r--r--release/darwin/Blender.app/Contents/Resources/zoomout.pdf676
-rw-r--r--release/darwin/buildbot/background.tifbin0 -> 20286 bytes
-rwxr-xr-xrelease/darwin/bundle.sh5
-rw-r--r--release/datafiles/blender_icons.svg28800
-rw-r--r--release/datafiles/blender_icons16/icon16_brush_blob.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_checkmark.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_desktop.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_disk_drive.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_external_drive.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_file.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_file_archive.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_file_blank.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_file_cache.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_file_folder.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_file_hidden.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_filebrowser.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_network_drive.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_newfolder.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_snap_edge.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_snap_face.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_snap_face_center.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_snap_grid.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_snap_increment.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_snap_midpoint.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_snap_perpendicular.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_snap_vertex.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_snap_volume.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_system.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_transform_origins.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_brush_blob.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_checkmark.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_desktop.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_disk_drive.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_external_drive.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_file.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_file_archive.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_file_blank.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_file_cache.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_file_folder.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_file_hidden.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_filebrowser.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_network_drive.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_newfolder.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_snap_edge.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_snap_face.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_snap_face_center.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_snap_grid.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_snap_increment.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_snap_midpoint.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_snap_perpendicular.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_snap_vertex.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_snap_volume.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_system.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_transform_origins.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons_geom.py2
-rw-r--r--release/datafiles/brushicons/gp_brush_airbrush.pngbin0 -> 7897 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_chisel.pngbin0 -> 6701 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_marker.pngbin5996 -> 6148 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.draw_sharp.datbin0 -> 2492 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.elastic_deform.datbin0 -> 19340 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.mask.datbin2420 -> 1916 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.pinch.datbin2834 -> 2456 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.pose.datbin0 -> 1322 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.simplify.datbin3050 -> 5480 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.snake_hook.datbin2024 -> 5624 bytes
-rw-r--r--release/datafiles/icons/ops.sculpt.border_hide.datbin764 -> 620 bytes
-rw-r--r--release/datafiles/icons/ops.sculpt.border_mask.datbin980 -> 980 bytes
-rw-r--r--release/datafiles/icons/ops.sculpt.mesh_filter.datbin0 -> 2060 bytes
m---------release/datafiles/locale0
-rw-r--r--release/datafiles/prvicons.pngbin3518 -> 12172 bytes
-rw-r--r--release/datafiles/prvicons.svg1191
-rwxr-xr-xrelease/datafiles/prvicons_update.py2
-rw-r--r--release/datafiles/userdef/userdef_default.c32
-rw-r--r--release/datafiles/userdef/userdef_default_theme.c16
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/freestyle/styles/apriori_density.py4
-rw-r--r--release/scripts/modules/bl_app_override/__init__.py8
-rw-r--r--release/scripts/modules/bl_i18n_utils/bl_extract_messages.py7
-rwxr-xr-xrelease/scripts/modules/bl_i18n_utils/utils_rtl.py32
-rw-r--r--release/scripts/modules/bl_keymap_utils/io.py2
-rw-r--r--release/scripts/modules/bpy_extras/image_utils.py37
-rw-r--r--release/scripts/modules/bpy_extras/io_utils.py71
-rw-r--r--release/scripts/modules/bpy_extras/node_shader_utils.py62
-rw-r--r--release/scripts/modules/bpy_extras/view3d_utils.py44
-rw-r--r--release/scripts/modules/bpy_types.py94
-rw-r--r--release/scripts/modules/console/complete_import.py2
-rw-r--r--release/scripts/modules/rna_info.py2
-rw-r--r--release/scripts/modules/rna_manual_reference.py189
-rw-r--r--release/scripts/modules/rna_prop_ui.py7
-rw-r--r--release/scripts/presets/interface_theme/blender_light.xml65
-rw-r--r--release/scripts/presets/keyconfig/blender.py10
-rw-r--r--release/scripts/presets/keyconfig/blender_27x.py10
-rw-r--r--release/scripts/presets/keyconfig/industry_compatible.py46
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py179
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py100
-rw-r--r--release/scripts/startup/bl_operators/add_mesh_torus.py12
-rw-r--r--release/scripts/startup/bl_operators/clip.py14
-rw-r--r--release/scripts/startup/bl_operators/freestyle.py8
-rw-r--r--release/scripts/startup/bl_operators/mask.py2
-rw-r--r--release/scripts/startup/bl_operators/presets.py6
-rw-r--r--release/scripts/startup/bl_operators/rigidbody.py2
-rw-r--r--release/scripts/startup/bl_operators/sequencer.py229
-rw-r--r--release/scripts/startup/bl_operators/userpref.py2
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_smart_project.py24
-rw-r--r--release/scripts/startup/bl_operators/wm.py458
-rw-r--r--release/scripts/startup/bl_ui/properties_constraint.py15
-rw-r--r--release/scripts/startup/bl_ui/properties_data_bone.py6
-rw-r--r--release/scripts/startup/bl_ui/properties_data_camera.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_data_empty.py1
-rw-r--r--release/scripts/startup/bl_ui/properties_data_gpencil.py8
-rw-r--r--release/scripts/startup/bl_ui/properties_data_lattice.py7
-rw-r--r--release/scripts/startup/bl_ui/properties_data_light.py14
-rw-r--r--release/scripts/startup/bl_ui/properties_data_mesh.py26
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py22
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py85
-rw-r--r--release/scripts/startup/bl_ui/properties_material.py51
-rw-r--r--release/scripts/startup/bl_ui/properties_material_gpencil.py12
-rw-r--r--release/scripts/startup/bl_ui/properties_object.py12
-rw-r--r--release/scripts/startup/bl_ui/properties_particle.py107
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py32
-rw-r--r--release/scripts/startup/bl_ui/properties_scene.py2
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py9
-rw-r--r--release/scripts/startup/bl_ui/space_console.py3
-rw-r--r--release/scripts/startup/bl_ui/space_filebrowser.py326
-rw-r--r--release/scripts/startup/bl_ui/space_image.py4
-rw-r--r--release/scripts/startup/bl_ui/space_info.py9
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py34
-rw-r--r--release/scripts/startup/bl_ui/space_time.py15
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py52
-rw-r--r--release/scripts/startup/bl_ui/space_topbar.py7
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py82
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py448
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py130
-rw-r--r--release/scripts/startup/nodeitems_builtins.py1
-rw-r--r--release/windows/blendthumb/src/BlenderThumb.cpp320
-rw-r--r--release/windows/blendthumb/src/Dll.cpp273
-rw-r--r--release/windows/icons/cursors/arrowdown.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/arrowleft.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/arrowright.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/arrowup.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/cross.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/crossa.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/crossb.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/crossc.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/eraser.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/eyedropper.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/forbidden.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/handopen.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/knife.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/moveew.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/movens.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/pencil.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/pointer.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/scrollew.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/scrollns.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/scrollnsew.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/splith.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/splitv.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/zoomin.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/zoomout.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/winblender.rc27
-rw-r--r--source/blender/CMakeLists.txt4
-rw-r--r--source/blender/alembic/ABC_alembic.h5
-rw-r--r--source/blender/alembic/intern/abc_archive.cc20
-rw-r--r--source/blender/alembic/intern/abc_archive.h4
-rw-r--r--source/blender/alembic/intern/abc_curves.cc26
-rw-r--r--source/blender/alembic/intern/abc_customdata.cc34
-rw-r--r--source/blender/alembic/intern/abc_exporter.cc15
-rw-r--r--source/blender/alembic/intern/abc_exporter.h2
-rw-r--r--source/blender/alembic/intern/abc_hair.cc22
-rw-r--r--source/blender/alembic/intern/abc_mesh.cc69
-rw-r--r--source/blender/alembic/intern/abc_nurbs.cc14
-rw-r--r--source/blender/alembic/intern/abc_object.cc16
-rw-r--r--source/blender/alembic/intern/abc_transform.cc2
-rw-r--r--source/blender/alembic/intern/abc_util.cc8
-rw-r--r--source/blender/alembic/intern/alembic_capi.cc23
-rw-r--r--source/blender/avi/intern/avi_options.c4
-rw-r--r--source/blender/blendthumb/CMakeLists.txt (renamed from release/windows/blendthumb/CMakeLists.txt)16
-rw-r--r--source/blender/blendthumb/src/BlendThumb.def (renamed from release/windows/blendthumb/src/BlendThumb.def)0
-rw-r--r--source/blender/blendthumb/src/BlendThumb.rc (renamed from release/windows/blendthumb/src/BlendThumb.rc)0
-rw-r--r--source/blender/blendthumb/src/BlenderThumb.cpp321
-rw-r--r--source/blender/blendthumb/src/Dll.cpp280
-rw-r--r--source/blender/blenfont/intern/blf.c36
-rw-r--r--source/blender/blenfont/intern/blf_font.c269
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c65
-rw-r--r--source/blender/blenfont/intern/blf_internal.h16
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h7
-rw-r--r--source/blender/blenfont/intern/blf_thumbs.c2
-rw-r--r--source/blender/blenkernel/BKE_action.h1
-rw-r--r--source/blender/blenkernel/BKE_animsys.h3
-rw-r--r--source/blender/blenkernel/BKE_armature.h1
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h4
-rw-r--r--source/blender/blenkernel/BKE_brush.h6
-rw-r--r--source/blender/blenkernel/BKE_callbacks.h84
-rw-r--r--source/blender/blenkernel/BKE_camera.h2
-rw-r--r--source/blender/blenkernel/BKE_collection.h6
-rw-r--r--source/blender/blenkernel/BKE_context.h4
-rw-r--r--source/blender/blenkernel/BKE_curve.h9
-rw-r--r--source/blender/blenkernel/BKE_editmesh.h5
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h3
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h18
-rw-r--r--source/blender/blenkernel/BKE_gpencil_modifier.h5
-rw-r--r--source/blender/blenkernel/BKE_layer.h5
-rw-r--r--source/blender/blenkernel/BKE_library.h3
-rw-r--r--source/blender/blenkernel/BKE_library_override.h8
-rw-r--r--source/blender/blenkernel/BKE_library_remap.h2
-rw-r--r--source/blender/blenkernel/BKE_material.h4
-rw-r--r--source/blender/blenkernel/BKE_mesh.h40
-rw-r--r--source/blender/blenkernel/BKE_mesh_remesh_voxel.h21
-rw-r--r--source/blender/blenkernel/BKE_mirror.h45
-rw-r--r--source/blender/blenkernel/BKE_multires.h4
-rw-r--r--source/blender/blenkernel/BKE_node.h24
-rw-r--r--source/blender/blenkernel/BKE_object.h14
-rw-r--r--source/blender/blenkernel/BKE_object_facemap.h5
-rw-r--r--source/blender/blenkernel/BKE_paint.h22
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h76
-rw-r--r--source/blender/blenkernel/BKE_scene.h3
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h27
-rw-r--r--source/blender/blenkernel/BKE_shrinkwrap.h10
-rw-r--r--source/blender/blenkernel/BKE_studiolight.h25
-rw-r--r--source/blender/blenkernel/BKE_subdiv.h2
-rw-r--r--source/blender/blenkernel/BKE_subdiv_ccg.h2
-rw-r--r--source/blender/blenkernel/BKE_subdiv_deform.h40
-rw-r--r--source/blender/blenkernel/BKE_subdiv_eval.h7
-rw-r--r--source/blender/blenkernel/BKE_subdiv_topology.h31
-rw-r--r--source/blender/blenkernel/CMakeLists.txt25
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c4
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c14
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c50
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c16
-rw-r--r--source/blender/blenkernel/intern/appdir.c2
-rw-r--r--source/blender/blenkernel/intern/armature.c114
-rw-r--r--source/blender/blenkernel/intern/blender.c4
-rw-r--r--source/blender/blenkernel/intern/brush.c693
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c2
-rw-r--r--source/blender/blenkernel/intern/cachefile.c2
-rw-r--r--source/blender/blenkernel/intern/callbacks.c (renamed from source/blender/blenlib/intern/callbacks.c)56
-rw-r--r--source/blender/blenkernel/intern/camera.c21
-rw-r--r--source/blender/blenkernel/intern/collection.c35
-rw-r--r--source/blender/blenkernel/intern/collision.c16
-rw-r--r--source/blender/blenkernel/intern/constraint.c238
-rw-r--r--source/blender/blenkernel/intern/context.c8
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c80
-rw-r--r--source/blender/blenkernel/intern/curve.c132
-rw-r--r--source/blender/blenkernel/intern/customdata.c150
-rw-r--r--source/blender/blenkernel/intern/editlattice.c31
-rw-r--r--source/blender/blenkernel/intern/editmesh.c21
-rw-r--r--source/blender/blenkernel/intern/fcurve.c90
-rw-r--r--source/blender/blenkernel/intern/gpencil.c500
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c23
-rw-r--r--source/blender/blenkernel/intern/icons.c10
-rw-r--r--source/blender/blenkernel/intern/image.c49
-rw-r--r--source/blender/blenkernel/intern/lattice.c6
-rw-r--r--source/blender/blenkernel/intern/layer.c137
-rw-r--r--source/blender/blenkernel/intern/library.c60
-rw-r--r--source/blender/blenkernel/intern/library_override.c117
-rw-r--r--source/blender/blenkernel/intern/library_remap.c12
-rw-r--r--source/blender/blenkernel/intern/light.c43
-rw-r--r--source/blender/blenkernel/intern/lightprobe.c15
-rw-r--r--source/blender/blenkernel/intern/linestyle.c37
-rw-r--r--source/blender/blenkernel/intern/material.c54
-rw-r--r--source/blender/blenkernel/intern/mball.c8
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c2
-rw-r--r--source/blender/blenkernel/intern/mesh.c203
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.c20
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c18
-rw-r--r--source/blender/blenkernel/intern/mesh_remesh_voxel.c259
-rw-r--r--source/blender/blenkernel/intern/mirror.c413
-rw-r--r--source/blender/blenkernel/intern/multires.c156
-rw-r--r--source/blender/blenkernel/intern/multires_reshape.c4
-rw-r--r--source/blender/blenkernel/intern/node.c94
-rw-r--r--source/blender/blenkernel/intern/object.c111
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c27
-rw-r--r--source/blender/blenkernel/intern/object_facemap.c38
-rw-r--r--source/blender/blenkernel/intern/object_update.c1
-rw-r--r--source/blender/blenkernel/intern/ocean.c58
-rw-r--r--source/blender/blenkernel/intern/packedFile.c17
-rw-r--r--source/blender/blenkernel/intern/paint.c44
-rw-r--r--source/blender/blenkernel/intern/particle.c16
-rw-r--r--source/blender/blenkernel/intern/particle_child.c6
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c12
-rw-r--r--source/blender/blenkernel/intern/particle_system.c6
-rw-r--r--source/blender/blenkernel/intern/pbvh.c583
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c21
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h5
-rw-r--r--source/blender/blenkernel/intern/pointcache.c61
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c2
-rw-r--r--source/blender/blenkernel/intern/scene.c441
-rw-r--r--source/blender/blenkernel/intern/screen.c19
-rw-r--r--source/blender/blenkernel/intern/seqcache.c104
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c24
-rw-r--r--source/blender/blenkernel/intern/seqprefetch.c453
-rw-r--r--source/blender/blenkernel/intern/sequencer.c36
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c62
-rw-r--r--source/blender/blenkernel/intern/smoke.c10
-rw-r--r--source/blender/blenkernel/intern/softbody.c10
-rw-r--r--source/blender/blenkernel/intern/speaker.c14
-rw-r--r--source/blender/blenkernel/intern/studiolight.c314
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg.c49
-rw-r--r--source/blender/blenkernel/intern/subdiv_converter_mesh.c2
-rw-r--r--source/blender/blenkernel/intern/subdiv_deform.c237
-rw-r--r--source/blender/blenkernel/intern/subdiv_eval.c23
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c23
-rw-r--r--source/blender/blenkernel/intern/subdiv_topology.c34
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c12
-rw-r--r--source/blender/blenkernel/intern/texture.c124
-rw-r--r--source/blender/blenkernel/intern/tracking.c6
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c20
-rw-r--r--source/blender/blenkernel/intern/tracking_solver.c2
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c18
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c6
-rw-r--r--source/blender/blenkernel/intern/undo_system.c2
-rw-r--r--source/blender/blenkernel/intern/world.c20
-rw-r--r--source/blender/blenlib/BLI_allocator.h129
-rw-r--r--source/blender/blenlib/BLI_array.h5
-rw-r--r--source/blender/blenlib/BLI_array_cxx.h197
-rw-r--r--source/blender/blenlib/BLI_array_ref.h426
-rw-r--r--source/blender/blenlib/BLI_callbacks.h73
-rw-r--r--source/blender/blenlib/BLI_fileops.h9
-rw-r--r--source/blender/blenlib/BLI_gsqueue.h6
-rw-r--r--source/blender/blenlib/BLI_hash_cxx.h111
-rw-r--r--source/blender/blenlib/BLI_index_range.h196
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h22
-rw-r--r--source/blender/blenlib/BLI_kdtree_impl.h10
-rw-r--r--source/blender/blenlib/BLI_listbase.h1
-rw-r--r--source/blender/blenlib/BLI_listbase_wrapper.h100
-rw-r--r--source/blender/blenlib/BLI_map.h724
-rw-r--r--source/blender/blenlib/BLI_math_base.h5
-rw-r--r--source/blender/blenlib/BLI_math_geom.h19
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h10
-rw-r--r--source/blender/blenlib/BLI_math_rotation.h2
-rw-r--r--source/blender/blenlib/BLI_math_vector.h5
-rw-r--r--source/blender/blenlib/BLI_memblock.h11
-rw-r--r--source/blender/blenlib/BLI_memory_utils_cxx.h84
-rw-r--r--source/blender/blenlib/BLI_open_addressing.h305
-rw-r--r--source/blender/blenlib/BLI_polyfill_2d_beautify.h5
-rw-r--r--source/blender/blenlib/BLI_set.h483
-rw-r--r--source/blender/blenlib/BLI_sort.h2
-rw-r--r--source/blender/blenlib/BLI_stack_cxx.h145
-rw-r--r--source/blender/blenlib/BLI_string.h2
-rw-r--r--source/blender/blenlib/BLI_string_map.h425
-rw-r--r--source/blender/blenlib/BLI_string_ref.h247
-rw-r--r--source/blender/blenlib/BLI_system.h9
-rw-r--r--source/blender/blenlib/BLI_temporary_allocator.h64
-rw-r--r--source/blender/blenlib/BLI_temporary_allocator_cxx.h38
-rw-r--r--source/blender/blenlib/BLI_timer.h4
-rw-r--r--source/blender/blenlib/BLI_vector.h607
-rw-r--r--source/blender/blenlib/BLI_vector_set.h425
-rw-r--r--source/blender/blenlib/CMakeLists.txt23
-rw-r--r--source/blender/blenlib/intern/BLI_filelist.c82
-rw-r--r--source/blender/blenlib/intern/BLI_index_range.cc60
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c212
-rw-r--r--source/blender/blenlib/intern/BLI_linklist.c2
-rw-r--r--source/blender/blenlib/intern/BLI_memblock.c23
-rw-r--r--source/blender/blenlib/intern/BLI_temporary_allocator.cc115
-rw-r--r--source/blender/blenlib/intern/BLI_timer.c39
-rw-r--r--source/blender/blenlib/intern/delaunay_2d.c136
-rw-r--r--source/blender/blenlib/intern/fileops.c5
-rw-r--r--source/blender/blenlib/intern/gsqueue.c216
-rw-r--r--source/blender/blenlib/intern/hash_md5.c4
-rw-r--r--source/blender/blenlib/intern/list_sort_impl.h4
-rw-r--r--source/blender/blenlib/intern/listbase.c23
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c24
-rw-r--r--source/blender/blenlib/intern/math_geom.c121
-rw-r--r--source/blender/blenlib/intern/math_interp.c4
-rw-r--r--source/blender/blenlib/intern/math_matrix.c144
-rw-r--r--source/blender/blenlib/intern/math_rotation.c44
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c34
-rw-r--r--source/blender/blenlib/intern/path_util.c8
-rw-r--r--source/blender/blenlib/intern/polyfill_2d_beautify.c34
-rw-r--r--source/blender/blenlib/intern/sort.c2
-rw-r--r--source/blender/blenlib/intern/stack.c15
-rw-r--r--source/blender/blenlib/intern/storage.c6
-rw-r--r--source/blender/blenlib/intern/string.c20
-rw-r--r--source/blender/blenlib/intern/string_utf8.c10
-rw-r--r--source/blender/blenlib/intern/system.c13
-rw-r--r--source/blender/blenlib/intern/task.c56
-rw-r--r--source/blender/blenlib/intern/voronoi_2d.c2
-rw-r--r--source/blender/blenlib/intern/winstuff.c12
-rw-r--r--source/blender/blenloader/intern/readfile.c198
-rw-r--r--source/blender/blenloader/intern/versioning_250.c3
-rw-r--r--source/blender/blenloader/intern/versioning_260.c11
-rw-r--r--source/blender/blenloader/intern/versioning_270.c8
-rw-r--r--source/blender/blenloader/intern/versioning_280.c227
-rw-r--r--source/blender/blenloader/intern/versioning_cycles.c480
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c138
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c2
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c20
-rw-r--r--source/blender/blenloader/intern/writefile.c25
-rw-r--r--source/blender/bmesh/CMakeLists.txt2
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c23
-rw-r--r--source/blender/bmesh/intern/bmesh_operators_private.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon_edgenet.c6
-rw-r--r--source/blender/bmesh/intern/bmesh_query.c28
-rw-r--r--source/blender/bmesh/intern/bmesh_query.h7
-rw-r--r--source/blender/bmesh/operators/bmo_bridge.c4
-rw-r--r--source/blender/bmesh/operators/bmo_inset.c2
-rw-r--r--source/blender/bmesh/operators/bmo_removedoubles.c31
-rw-r--r--source/blender/bmesh/tools/bmesh_beautify.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect_edges.c911
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect_edges.h29
-rw-r--r--source/blender/collada/AnimationExporter.cpp2
-rw-r--r--source/blender/collada/AnimationImporter.cpp2
-rw-r--r--source/blender/collada/BCAnimationCurve.cpp4
-rw-r--r--source/blender/collada/BCAnimationSampler.cpp4
-rw-r--r--source/blender/collada/BlenderContext.cpp2
-rw-r--r--source/blender/collada/DocumentImporter.cpp12
-rw-r--r--source/blender/collada/SceneExporter.cpp2
-rw-r--r--source/blender/compositor/intern/COM_Debug.cpp14
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.cpp6
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.cpp4
-rw-r--r--source/blender/compositor/nodes/COM_CornerPinNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_CryptomatteNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.h5
-rw-r--r--source/blender/compositor/nodes/COM_KeyingNode.h5
-rw-r--r--source/blender/compositor/nodes/COM_KeyingScreenNode.h5
-rw-r--r--source/blender/compositor/nodes/COM_OutputFileNode.cpp4
-rw-r--r--source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h5
-rw-r--r--source/blender/compositor/nodes/COM_RenderLayersNode.h5
-rw-r--r--source/blender/compositor/nodes/COM_TextureNode.h5
-rw-r--r--source/blender/compositor/nodes/COM_TrackPositionNode.h5
-rw-r--r--source/blender/compositor/operations/COM_BlurBaseOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_DenoiseOperation.cpp111
-rw-r--r--source/blender/compositor/operations/COM_DenoiseOperation.h9
-rw-r--r--source/blender/compositor/operations/COM_DilateErodeOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_DisplaceOperation.cpp8
-rw-r--r--source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp18
-rw-r--r--source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp16
-rw-r--r--source/blender/compositor/operations/COM_GlareStreaksOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_KeyingBlurOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_KeyingClipOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_MapUVOperation.cpp8
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp8
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.cpp10
-rw-r--r--source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp8
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp2
-rw-r--r--source/blender/depsgraph/CMakeLists.txt2
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h14
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h7
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h12
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.h10
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.cc4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc42
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h136
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc87
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h180
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.cc8
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_transitive.cc2
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc4
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc17
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h5
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc151
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.cc12
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc3
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_foreach.cc26
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_iter.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_registry.cc74
-rw-r--r--source/blender/depsgraph/intern/depsgraph_registry.h38
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc46
-rw-r--r--source/blender/draw/CMakeLists.txt10
-rw-r--r--source/blender/draw/engines/basic/basic_engine.c3
-rw-r--r--source/blender/draw/engines/eevee/eevee_bloom.c12
-rw-r--r--source/blender/draw/engines/eevee/eevee_data.c21
-rw-r--r--source/blender/draw/engines/eevee/eevee_depth_of_field.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c26
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.c34
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c24
-rw-r--r--source/blender/draw/engines/eevee/eevee_lights.c1438
-rw-r--r--source/blender/draw/engines/eevee/eevee_lookdev.c5
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c207
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h261
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c17
-rw-r--r--source/blender/draw/engines/eevee/eevee_sampling.c129
-rw-r--r--source/blender/draw/engines/eevee/eevee_screen_raytrace.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_shadows.c412
-rw-r--r--source/blender/draw/engines/eevee/eevee_shadows_cascade.c439
-rw-r--r--source/blender/draw/engines/eevee/eevee_shadows_cube.c225
-rw-r--r--source/blender/draw/engines/eevee/eevee_subsurface.c136
-rw-r--r--source/blender/draw/engines/eevee/eevee_temporal_sampling.c6
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c49
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl102
-rw-r--r--source/blender/draw/engines/eevee/shaders/default_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/default_world_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl43
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl165
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/lights_lib.glsl407
-rw-r--r--source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl54
-rw-r--r--source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl199
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_process_geom.glsl36
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_process_vert.glsl32
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl322
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl22
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl2
-rw-r--r--source/blender/draw/engines/external/external_engine.c5
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c6
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_utils.c374
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c94
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h11
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_render.c7
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl4
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl18
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl4
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl19
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl5
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl19
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl3
-rw-r--r--source/blender/draw/engines/select/select_draw_utils.c21
-rw-r--r--source/blender/draw/engines/select/select_engine.c4
-rw-r--r--source/blender/draw/engines/select/select_private.h2
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl14
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl6
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl8
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl38
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl12
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl12
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl10
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl7
-rw-r--r--source/blender/draw/engines/workbench/workbench_deferred.c42
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_dof.c6
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_taa.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_forward.c84
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.c147
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.h32
-rw-r--r--source/blender/draw/engines/workbench/workbench_render.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_studiolight.c18
-rw-r--r--source/blender/draw/engines/workbench/workbench_volume.c10
-rw-r--r--source/blender/draw/intern/DRW_render.h47
-rw-r--r--source/blender/draw/intern/draw_anim_viz.c11
-rw-r--r--source/blender/draw/intern/draw_cache.c91
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h22
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.c74
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h6
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curve.c24
-rw-r--r--source/blender/draw/intern/draw_cache_impl_lattice.c4
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c126
-rw-r--r--source/blender/draw/intern/draw_cache_impl_metaball.c2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c41
-rw-r--r--source/blender/draw/intern/draw_common.c39
-rw-r--r--source/blender/draw/intern/draw_common.h4
-rw-r--r--source/blender/draw/intern/draw_debug.c4
-rw-r--r--source/blender/draw/intern/draw_hair.c51
-rw-r--r--source/blender/draw/intern/draw_instance_data.c12
-rw-r--r--source/blender/draw/intern/draw_instance_data.h2
-rw-r--r--source/blender/draw/intern/draw_manager.c287
-rw-r--r--source/blender/draw/intern/draw_manager.h320
-rw-r--r--source/blender/draw/intern/draw_manager_data.c916
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c719
-rw-r--r--source/blender/draw/intern/draw_manager_profiling.c6
-rw-r--r--source/blender/draw/modes/edit_armature_mode.c2
-rw-r--r--source/blender/draw/modes/edit_curve_mode.c12
-rw-r--r--source/blender/draw/modes/edit_mesh_mode.c18
-rw-r--r--source/blender/draw/modes/object_mode.c385
-rw-r--r--source/blender/draw/modes/overlay_mode.c38
-rw-r--r--source/blender/draw/modes/pose_mode.c2
-rw-r--r--source/blender/draw/modes/shaders/common_view_lib.glsl70
-rw-r--r--source/blender/draw/modes/shaders/object_color_axes_vert.glsl35
-rw-r--r--source/blender/draw/modes/shaders/object_empty_image_frag.glsl6
-rw-r--r--source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl12
-rw-r--r--source/blender/draw/modes/shaders/object_outline_detect_frag.glsl40
-rw-r--r--source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl14
-rw-r--r--source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl7
-rw-r--r--source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl17
-rw-r--r--source/blender/draw/modes/shaders/paint_face_vert.glsl2
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c3
-rw-r--r--source/blender/editors/animation/anim_draw.c2
-rw-r--r--source/blender/editors/animation/anim_filter.c5
-rw-r--r--source/blender/editors/animation/anim_markers.c2
-rw-r--r--source/blender/editors/animation/anim_motion_paths.c269
-rw-r--r--source/blender/editors/animation/drivers.c53
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c4
-rw-r--r--source/blender/editors/animation/keyframes_draw.c1
-rw-r--r--source/blender/editors/armature/armature_edit.c6
-rw-r--r--source/blender/editors/armature/armature_select.c9
-rw-r--r--source/blender/editors/armature/armature_skinning.c4
-rw-r--r--source/blender/editors/armature/armature_utils.c2
-rw-r--r--source/blender/editors/armature/pose_edit.c47
-rw-r--r--source/blender/editors/armature/pose_select.c3
-rw-r--r--source/blender/editors/armature/pose_slide.c2
-rw-r--r--source/blender/editors/armature/pose_transform.c253
-rw-r--r--source/blender/editors/armature/pose_utils.c3
-rw-r--r--source/blender/editors/curve/curve_ops.c3
-rw-r--r--source/blender/editors/curve/editcurve.c11
-rw-r--r--source/blender/editors/curve/editcurve_add.c1
-rw-r--r--source/blender/editors/curve/editcurve_paint.c8
-rw-r--r--source/blender/editors/curve/editcurve_select.c14
-rw-r--r--source/blender/editors/curve/editcurve_undo.c2
-rw-r--r--source/blender/editors/curve/editfont.c4
-rw-r--r--source/blender/editors/curve/editfont_undo.c2
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt6
-rw-r--r--source/blender/editors/gizmo_library/gizmo_draw_utils.c3
-rw-r--r--source/blender/editors/gizmo_library/gizmo_library_presets.c7
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c1
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c1
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c4
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c16
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c4
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c2
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c3
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c4
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c8
-rw-r--r--source/blender/editors/gpencil/gpencil_add_monkey.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_add_stroke.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c90
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c146
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c110
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c34
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h5
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_merge.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c581
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c30
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c108
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c56
-rw-r--r--source/blender/editors/include/ED_anim_api.h20
-rw-r--r--source/blender/editors/include/ED_armature.h11
-rw-r--r--source/blender/editors/include/ED_datafiles.h6
-rw-r--r--source/blender/editors/include/ED_fileselect.h56
-rw-r--r--source/blender/editors/include/ED_gpencil.h10
-rw-r--r--source/blender/editors/include/ED_image.h2
-rw-r--r--source/blender/editors/include/ED_keyframing.h13
-rw-r--r--source/blender/editors/include/ED_mesh.h43
-rw-r--r--source/blender/editors/include/ED_object.h10
-rw-r--r--source/blender/editors/include/ED_paint.h33
-rw-r--r--source/blender/editors/include/ED_particle.h10
-rw-r--r--source/blender/editors/include/ED_screen.h9
-rw-r--r--source/blender/editors/include/ED_sculpt.h5
-rw-r--r--source/blender/editors/include/ED_transform.h5
-rw-r--r--source/blender/editors/include/ED_view3d.h8
-rw-r--r--source/blender/editors/include/UI_icons.h22
-rw-r--r--source/blender/editors/include/UI_interface.h17
-rw-r--r--source/blender/editors/include/UI_resources.h3
-rw-r--r--source/blender/editors/interface/interface.c268
-rw-r--r--source/blender/editors/interface/interface_anim.c2
-rw-r--r--source/blender/editors/interface/interface_context_menu.c47
-rw-r--r--source/blender/editors/interface/interface_draw.c18
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c4
-rw-r--r--source/blender/editors/interface/interface_eyedropper_colorband.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_datablock.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_depth.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_driver.c2
-rw-r--r--source/blender/editors/interface/interface_handlers.c205
-rw-r--r--source/blender/editors/interface/interface_icons.c18
-rw-r--r--source/blender/editors/interface/interface_icons_event.c2
-rw-r--r--source/blender/editors/interface/interface_intern.h29
-rw-r--r--source/blender/editors/interface/interface_layout.c91
-rw-r--r--source/blender/editors/interface/interface_ops.c63
-rw-r--r--source/blender/editors/interface/interface_query.c48
-rw-r--r--source/blender/editors/interface/interface_region_menu_popup.c2
-rw-r--r--source/blender/editors/interface/interface_region_popup.c2
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c18
-rw-r--r--source/blender/editors/interface/interface_templates.c277
-rw-r--r--source/blender/editors/interface/interface_widgets.c342
-rw-r--r--source/blender/editors/interface/resources.c14
-rw-r--r--source/blender/editors/interface/view2d.c72
-rw-r--r--source/blender/editors/interface/view2d_gizmo_navigate.c8
-rw-r--r--source/blender/editors/interface/view2d_ops.c12
-rw-r--r--source/blender/editors/io/io_alembic.c7
-rw-r--r--source/blender/editors/lattice/editlattice_select.c6
-rw-r--r--source/blender/editors/mask/mask_add.c2
-rw-r--r--source/blender/editors/mask/mask_draw.c3
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt2
-rw-r--r--source/blender/editors/mesh/editface.c2
-rw-r--r--source/blender/editors/mesh/editmesh_add_gizmo.c2
-rw-r--r--source/blender/editors/mesh/editmesh_automerge.c160
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c3
-rw-r--r--source/blender/editors/mesh/editmesh_bisect.c2
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c8
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c32
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c6
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c20
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c4
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c273
-rw-r--r--source/blender/editors/mesh/editmesh_path.c9
-rw-r--r--source/blender/editors/mesh/editmesh_polybuild.c189
-rw-r--r--source/blender/editors/mesh/editmesh_preselect_elem.c206
-rw-r--r--source/blender/editors/mesh/editmesh_select.c597
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c23
-rw-r--r--source/blender/editors/mesh/mesh_intern.h10
-rw-r--r--source/blender/editors/mesh/mesh_ops.c23
-rw-r--r--source/blender/editors/mesh/meshtools.c40
-rw-r--r--source/blender/editors/metaball/mball_edit.c6
-rw-r--r--source/blender/editors/object/object_add.c29
-rw-r--r--source/blender/editors/object/object_bake.c4
-rw-r--r--source/blender/editors/object/object_bake_api.c2
-rw-r--r--source/blender/editors/object/object_collection.c8
-rw-r--r--source/blender/editors/object/object_constraint.c4
-rw-r--r--source/blender/editors/object/object_edit.c133
-rw-r--r--source/blender/editors/object/object_intern.h3
-rw-r--r--source/blender/editors/object/object_modifier.c8
-rw-r--r--source/blender/editors/object/object_ops.c3
-rw-r--r--source/blender/editors/object/object_relations.c41
-rw-r--r--source/blender/editors/object/object_remesh.c535
-rw-r--r--source/blender/editors/object/object_transform.c13
-rw-r--r--source/blender/editors/object/object_vgroup.c6
-rw-r--r--source/blender/editors/object/object_warp.c6
-rw-r--r--source/blender/editors/physics/particle_edit.c362
-rw-r--r--source/blender/editors/physics/particle_edit_undo.c27
-rw-r--r--source/blender/editors/physics/particle_object.c15
-rw-r--r--source/blender/editors/physics/rigidbody_constraint.c9
-rw-r--r--source/blender/editors/render/render_internal.c2
-rw-r--r--source/blender/editors/render/render_preview.c2
-rw-r--r--source/blender/editors/render/render_update.c2
-rw-r--r--source/blender/editors/render/render_view.c11
-rw-r--r--source/blender/editors/scene/scene_edit.c7
-rw-r--r--source/blender/editors/screen/area.c40
-rw-r--r--source/blender/editors/screen/area_query.c2
-rw-r--r--source/blender/editors/screen/area_utils.c1
-rw-r--r--source/blender/editors/screen/glutil.c7
-rw-r--r--source/blender/editors/screen/screen_context.c8
-rw-r--r--source/blender/editors/screen/screen_draw.c6
-rw-r--r--source/blender/editors/screen/screen_edit.c175
-rw-r--r--source/blender/editors/screen/screen_ops.c113
-rw-r--r--source/blender/editors/screen/screen_user_menu.c24
-rw-r--r--source/blender/editors/screen/workspace_edit.c10
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt2
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c461
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve_undo.c1
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c23
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c20
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c15
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c80
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_undo.c625
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h31
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c63
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c10
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c206
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c12
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c44
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_ops.c14
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_utils.c30
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c17
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c3712
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h97
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c15
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c9
-rw-r--r--source/blender/editors/sound/sound_ops.c2
-rw-r--r--source/blender/editors/space_action/action_edit.c8
-rw-r--r--source/blender/editors/space_action/action_select.c42
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c1
-rw-r--r--source/blender/editors/space_clip/clip_dopesheet_draw.c1
-rw-r--r--source/blender/editors/space_clip/clip_draw.c288
-rw-r--r--source/blender/editors/space_clip/clip_intern.h3
-rw-r--r--source/blender/editors/space_clip/clip_ops.c184
-rw-r--r--source/blender/editors/space_clip/clip_utils.c1
-rw-r--r--source/blender/editors/space_clip/space_clip.c2
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c8
-rw-r--r--source/blender/editors/space_clip/tracking_ops_plane.c4
-rw-r--r--source/blender/editors/space_clip/tracking_ops_solve.c6
-rw-r--r--source/blender/editors/space_clip/tracking_ops_track.c14
-rw-r--r--source/blender/editors/space_clip/tracking_ops_utils.c4
-rw-r--r--source/blender/editors/space_clip/tracking_select.c4
-rw-r--r--source/blender/editors/space_console/console_ops.c2
-rw-r--r--source/blender/editors/space_console/space_console.c7
-rw-r--r--source/blender/editors/space_file/file_draw.c680
-rw-r--r--source/blender/editors/space_file/file_intern.h23
-rw-r--r--source/blender/editors/space_file/file_ops.c218
-rw-r--r--source/blender/editors/space_file/file_panels.c116
-rw-r--r--source/blender/editors/space_file/filelist.c177
-rw-r--r--source/blender/editors/space_file/filelist.h6
-rw-r--r--source/blender/editors/space_file/filesel.c369
-rw-r--r--source/blender/editors/space_file/fsmenu.c19
-rw-r--r--source/blender/editors/space_file/space_file.c169
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c17
-rw-r--r--source/blender/editors/space_graph/graph_draw.c11
-rw-r--r--source/blender/editors/space_graph/graph_edit.c12
-rw-r--r--source/blender/editors/space_image/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_image/image_edit.c18
-rw-r--r--source/blender/editors/space_image/image_intern.h3
-rw-r--r--source/blender/editors/space_image/image_ops.c366
-rw-r--r--source/blender/editors/space_image/image_undo.c1032
-rw-r--r--source/blender/editors/space_image/space_image.c2
-rw-r--r--source/blender/editors/space_info/info_stats.c10
-rw-r--r--source/blender/editors/space_nla/nla_draw.c1
-rw-r--r--source/blender/editors/space_node/drawnode.c87
-rw-r--r--source/blender/editors/space_node/node_add.c2
-rw-r--r--source/blender/editors/space_node/node_draw.c23
-rw-r--r--source/blender/editors/space_node/node_edit.c5
-rw-r--r--source/blender/editors/space_node/node_group.c20
-rw-r--r--source/blender/editors/space_node/node_relationships.c14
-rw-r--r--source/blender/editors/space_node/node_select.c60
-rw-r--r--source/blender/editors/space_node/node_templates.c14
-rw-r--r--source/blender/editors/space_node/space_node.c8
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c8
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.c6
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c20
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c3
-rw-r--r--source/blender/editors/space_outliner/outliner_sync.c45
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c28
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c8
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c5
-rw-r--r--source/blender/editors/space_script/script_edit.c3
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c16
-rw-r--r--source/blender/editors/space_sequencer/sequencer_buttons.c1
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c14
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c2
-rw-r--r--source/blender/editors/space_text/space_text.c7
-rw-r--r--source/blender/editors/space_text/text_ops.c6
-rw-r--r--source/blender/editors/space_userpref/space_userpref.c2
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt6
-rw-r--r--source/blender/editors/space_view3d/drawobject.c4
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c69
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_camera_control.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_draw_legacy.c14
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate.c24
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c126
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_ruler.c5
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c12
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c20
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c142
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c2
-rw-r--r--source/blender/editors/transform/CMakeLists.txt21
-rw-r--r--source/blender/editors/transform/transform.c503
-rw-r--r--source/blender/editors/transform/transform.h135
-rw-r--r--source/blender/editors/transform/transform_conversions.c9925
-rw-r--r--source/blender/editors/transform/transform_convert.c2743
-rw-r--r--source/blender/editors/transform/transform_convert.h141
-rw-r--r--source/blender/editors/transform/transform_convert_action.c575
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c933
-rw-r--r--source/blender/editors/transform/transform_convert_cursor.c129
-rw-r--r--source/blender/editors/transform/transform_convert_curve.c422
-rw-r--r--source/blender/editors/transform/transform_convert_gpencil.c371
-rw-r--r--source/blender/editors/transform/transform_convert_graph.c700
-rw-r--r--source/blender/editors/transform/transform_convert_lattice.c113
-rw-r--r--source/blender/editors/transform/transform_convert_mask.c442
-rw-r--r--source/blender/editors/transform/transform_convert_mball.c130
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c1645
-rw-r--r--source/blender/editors/transform/transform_convert_nla.c265
-rw-r--r--source/blender/editors/transform/transform_convert_node.c195
-rw-r--r--source/blender/editors/transform/transform_convert_object.c949
-rw-r--r--source/blender/editors/transform/transform_convert_paintcurve.c227
-rw-r--r--source/blender/editors/transform/transform_convert_particle.c248
-rw-r--r--source/blender/editors/transform/transform_convert_sculpt.c105
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c769
-rw-r--r--source/blender/editors/transform/transform_convert_tracking.c692
-rw-r--r--source/blender/editors/transform/transform_generics.c89
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c35
-rw-r--r--source/blender/editors/transform/transform_input.c4
-rw-r--r--source/blender/editors/transform/transform_ops.c8
-rw-r--r--source/blender/editors/transform/transform_snap.c12
-rw-r--r--source/blender/editors/transform/transform_snap_object.c297
-rw-r--r--source/blender/editors/undo/ed_undo.c12
-rw-r--r--source/blender/editors/util/ed_util.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_buttons.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c168
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c10
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c14
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp9
-rw-r--r--source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp11
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c16
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h14
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c62
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c6
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c2
-rw-r--r--source/blender/gpu/CMakeLists.txt92
-rw-r--r--source/blender/gpu/GPU_batch.h11
-rw-r--r--source/blender/gpu/GPU_buffers.h20
-rw-r--r--source/blender/gpu/GPU_shader_interface.h9
-rw-r--r--source/blender/gpu/GPU_viewport.h10
-rw-r--r--source/blender/gpu/intern/gpu_attr_binding.c4
-rw-r--r--source/blender/gpu/intern/gpu_batch.c257
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c249
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c133
-rw-r--r--source/blender/gpu/intern/gpu_codegen.h3
-rw-r--r--source/blender/gpu/intern/gpu_draw.c11
-rw-r--r--source/blender/gpu/intern/gpu_element.c6
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c23
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.c19
-rw-r--r--source/blender/gpu/intern/gpu_immediate.c38
-rw-r--r--source/blender/gpu/intern/gpu_immediate_util.c21
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c5
-rw-r--r--source/blender/gpu/intern/gpu_material.c21
-rw-r--r--source/blender/gpu/intern/gpu_material_library.h655
-rw-r--r--source/blender/gpu/intern/gpu_private.h4
-rw-r--r--source/blender/gpu/intern/gpu_select.c1
-rw-r--r--source/blender/gpu/intern/gpu_select_pick.c1
-rw-r--r--source/blender/gpu/intern/gpu_select_sample_query.c1
-rw-r--r--source/blender/gpu/intern/gpu_shader.c23
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.c21
-rw-r--r--source/blender/gpu/intern/gpu_texture.c12
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer.c2
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format.c8
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c30
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl20
-rw-r--r--source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl19
-rw-r--r--source/blender/gpu/shaders/gpu_shader_geometry.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl7
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl7
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl10
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_vert.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl3874
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl13
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl15
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl6
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_background.glsl11
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_bevel.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_blackbody.glsl13
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_bright_contrast.glsl10
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl44
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl6
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_clamp.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_color_ramp.glsl28
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl111
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_combine_rgb.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_combine_xyz.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl13
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl12
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl41
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl10
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl111
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl37
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl14
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl46
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl32
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl16
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl21
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl217
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl8
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl14
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_invert.glsl5
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl19
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl7
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl31
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl10
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl27
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_math.glsl130
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl151
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl291
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl294
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_normal.glsl5
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl22
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl16
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl8
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl11
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl23
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl418
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl16
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_rgb_curves.glsl73
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_rgb_to_bw.glsl5
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl9
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_separate_rgb.glsl6
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_separate_xyz.glsl6
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_set.glsl44
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl21
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_squeeze.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl27
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl25
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl78
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_checker.glsl17
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl44
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_gradient.glsl47
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl355
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl61
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl887
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl99
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl1064
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl42
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl21
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl92
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl9
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl13
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl11
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_uv_map.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl8
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl30
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl100
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl9
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vertex_color.glsl5
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl8
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl88
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl67
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl8
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl31
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl25
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp22
-rw-r--r--source/blender/imbuf/IMB_imbuf.h36
-rw-r--r--source/blender/imbuf/intern/IMB_anim.h2
-rw-r--r--source/blender/imbuf/intern/IMB_filetype.h2
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c4
-rw-r--r--source/blender/imbuf/intern/anim_movie.c61
-rw-r--r--source/blender/imbuf/intern/colormanagement.c3
-rw-r--r--source/blender/imbuf/intern/dds/FlipDXT.cpp8
-rw-r--r--source/blender/imbuf/intern/filetype.c4
-rw-r--r--source/blender/imbuf/intern/indexer.c8
-rw-r--r--source/blender/imbuf/intern/jp2.c2
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp6
-rw-r--r--source/blender/imbuf/intern/rectop.c90
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c4
-rw-r--r--source/blender/imbuf/intern/targa.c4
-rw-r--r--source/blender/imbuf/intern/util.c4
-rw-r--r--source/blender/makesdna/DNA_ID.h15
-rw-r--r--source/blender/makesdna/DNA_anim_types.h30
-rw-r--r--source/blender/makesdna/DNA_armature_types.h19
-rw-r--r--source/blender/makesdna/DNA_brush_defaults.h105
-rw-r--r--source/blender/makesdna/DNA_brush_types.h44
-rw-r--r--source/blender/makesdna/DNA_cachefile_defaults.h49
-rw-r--r--source/blender/makesdna/DNA_camera_defaults.h67
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h87
-rw-r--r--source/blender/makesdna/DNA_curve_defaults.h59
-rw-r--r--source/blender/makesdna/DNA_curve_types.h7
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h3
-rw-r--r--source/blender/makesdna/DNA_defaults.h46
-rw-r--r--source/blender/makesdna/DNA_genfile.h2
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h9
-rw-r--r--source/blender/makesdna/DNA_image_defaults.h46
-rw-r--r--source/blender/makesdna/DNA_lattice_defaults.h44
-rw-r--r--source/blender/makesdna/DNA_layer_types.h6
-rw-r--r--source/blender/makesdna/DNA_light_defaults.h76
-rw-r--r--source/blender/makesdna/DNA_light_types.h10
-rw-r--r--source/blender/makesdna/DNA_lightprobe_defaults.h51
-rw-r--r--source/blender/makesdna/DNA_linestyle_defaults.h61
-rw-r--r--source/blender/makesdna/DNA_material_defaults.h55
-rw-r--r--source/blender/makesdna/DNA_mesh_defaults.h45
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h16
-rw-r--r--source/blender/makesdna/DNA_meta_defaults.h44
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h20
-rw-r--r--source/blender/makesdna/DNA_movieclip_types.h2
-rw-r--r--source/blender/makesdna/DNA_node_types.h55
-rw-r--r--source/blender/makesdna/DNA_object_defaults.h77
-rw-r--r--source/blender/makesdna/DNA_object_types.h20
-rw-r--r--source/blender/makesdna/DNA_scene_defaults.h368
-rw-r--r--source/blender/makesdna/DNA_scene_types.h23
-rw-r--r--source/blender/makesdna/DNA_screen_types.h12
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h4
-rw-r--r--source/blender/makesdna/DNA_space_types.h27
-rw-r--r--source/blender/makesdna/DNA_speaker_defaults.h51
-rw-r--r--source/blender/makesdna/DNA_texture_defaults.h155
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h151
-rw-r--r--source/blender/makesdna/DNA_vec_defaults.h55
-rw-r--r--source/blender/makesdna/DNA_view3d_defaults.h116
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h16
-rw-r--r--source/blender/makesdna/DNA_world_defaults.h49
-rw-r--r--source/blender/makesdna/intern/CMakeLists.txt21
-rw-r--r--source/blender/makesdna/intern/dna_defaults.c273
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c23
-rw-r--r--source/blender/makesrna/RNA_access.h29
-rw-r--r--source/blender/makesrna/RNA_enum_types.h2
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt11
-rw-r--r--source/blender/makesrna/intern/makesrna.c39
-rw-r--r--source/blender/makesrna/intern/rna_ID.c21
-rw-r--r--source/blender/makesrna/intern/rna_access.c158
-rw-r--r--source/blender/makesrna/intern/rna_access_compare_override.c4
-rw-r--r--source/blender/makesrna/intern/rna_animation.c3
-rw-r--r--source/blender/makesrna/intern/rna_animviz.c4
-rw-r--r--source/blender/makesrna/intern/rna_armature.c159
-rw-r--r--source/blender/makesrna/intern/rna_armature_api.c5
-rw-r--r--source/blender/makesrna/intern/rna_boid.c4
-rw-r--r--source/blender/makesrna/intern/rna_brush.c115
-rw-r--r--source/blender/makesrna/intern/rna_camera.c12
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c169
-rw-r--r--source/blender/makesrna/intern/rna_curve.c17
-rw-r--r--source/blender/makesrna/intern/rna_define.c380
-rw-r--r--source/blender/makesrna/intern/rna_dynamicpaint.c4
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c36
-rw-r--r--source/blender/makesrna/intern/rna_fluidsim.c2
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c27
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c21
-rw-r--r--source/blender/makesrna/intern/rna_internal.h12
-rw-r--r--source/blender/makesrna/intern/rna_layer.c34
-rw-r--r--source/blender/makesrna/intern/rna_light.c59
-rw-r--r--source/blender/makesrna/intern/rna_lightprobe.c12
-rw-r--r--source/blender/makesrna/intern/rna_linestyle.c2
-rw-r--r--source/blender/makesrna/intern/rna_material.c2
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c87
-rw-r--r--source/blender/makesrna/intern/rna_meta.c2
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c54
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c224
-rw-r--r--source/blender/makesrna/intern/rna_object.c71
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c85
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c125
-rw-r--r--source/blender/makesrna/intern/rna_particle.c8
-rw-r--r--source/blender/makesrna/intern/rna_pose.c50
-rw-r--r--source/blender/makesrna/intern/rna_rna.c5
-rw-r--r--source/blender/makesrna/intern/rna_scene.c228
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c34
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c41
-rw-r--r--source/blender/makesrna/intern/rna_shader_fx.c4
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c6
-rw-r--r--source/blender/makesrna/intern/rna_space.c293
-rw-r--r--source/blender/makesrna/intern/rna_space_api.c3
-rw-r--r--source/blender/makesrna/intern/rna_texture.c49
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c6
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c7
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c104
-rw-r--r--source/blender/makesrna/intern/rna_wm.c36
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c46
-rw-r--r--source/blender/modifiers/CMakeLists.txt4
-rw-r--r--source/blender/modifiers/intern/MOD_armature.c2
-rw-r--r--source/blender/modifiers/intern/MOD_array.c8
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c2
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c4
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c2
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c112
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c2
-rw-r--r--source/blender/modifiers/intern/MOD_datatransfer.c2
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c6
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c5
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c2
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c22
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim_util.c6
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c4
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciandeform.c10
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciansmooth.c8
-rw-r--r--source/blender/modifiers/intern/MOD_lattice.c2
-rw-r--r--source/blender/modifiers/intern/MOD_mask.c10
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache_mdd.c4
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache_pc2.c4
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c2
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c375
-rw-r--r--source/blender/modifiers/intern/MOD_multires.c37
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c5
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c2
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c2
-rw-r--r--source/blender/modifiers/intern/MOD_remesh.c1
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c75
-rw-r--r--source/blender/modifiers/intern/MOD_shrinkwrap.c6
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c10
-rw-r--r--source/blender/modifiers/intern/MOD_smooth.c148
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c70
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c36
-rw-r--r--source/blender/modifiers/intern/MOD_surface.c2
-rw-r--r--source/blender/modifiers/intern/MOD_surfacedeform.c68
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c2
-rw-r--r--source/blender/modifiers/intern/MOD_util.c12
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c42
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.c4
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c4
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c2
-rw-r--r--source/blender/nodes/CMakeLists.txt3
-rw-r--r--source/blender/nodes/NOD_shader.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorbalance.c4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cryptomatte.c4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_denoise.c2
-rw-r--r--source/blender/nodes/intern/node_exec.c10
-rw-r--r--source/blender/nodes/intern/node_util.c10
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c433
-rw-r--r--source/blender/nodes/shader/node_shader_util.c30
-rw-r--r--source/blender/nodes/shader/node_shader_util.h6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_attribute.c9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bump.c35
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_common.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_curves.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_geometry.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_hueSatVal.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mapping.c102
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mixRgb.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal_map.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_brick.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_checker.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_coord.c31
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.c7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_gradient.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.c11
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_magic.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c91
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.c41
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c145
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_wave.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_uvmap.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vectTransform.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vertex_color.c58
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_common.c4
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_proc.c146
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp14
-rw-r--r--source/blender/physics/intern/ConstrainedConjugateGradient.h2
-rw-r--r--source/blender/physics/intern/eigen_utils.h26
-rw-r--r--source/blender/physics/intern/hair_volume.cpp84
-rw-r--r--source/blender/physics/intern/implicit_blender.c24
-rw-r--r--source/blender/physics/intern/implicit_eigen.cpp44
-rw-r--r--source/blender/python/generic/bgl.c2
-rw-r--r--source/blender/python/generic/idprop_py_api.c3
-rw-r--r--source/blender/python/generic/imbuf_py_api.c122
-rw-r--r--source/blender/python/generic/py_capi_utils.c31
-rw-r--r--source/blender/python/generic/py_capi_utils.h11
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.c3
-rw-r--r--source/blender/python/gpu/gpu_py_shader.c1
-rw-r--r--source/blender/python/intern/CMakeLists.txt4
-rw-r--r--source/blender/python/intern/bpy.c98
-rw-r--r--source/blender/python/intern/bpy_app_build_options.c7
-rw-r--r--source/blender/python/intern/bpy_app_handlers.c64
-rw-r--r--source/blender/python/intern/bpy_props.c12
-rw-r--r--source/blender/python/intern/bpy_rna.c87
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c4
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c48
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c21
-rw-r--r--source/blender/python/mathutils/mathutils_noise.c4
-rw-r--r--source/blender/python/rna_dump.py6
-rw-r--r--source/blender/render/intern/source/bake_api.c10
-rw-r--r--source/blender/render/intern/source/external_engine.c2
-rw-r--r--source/blender/render/intern/source/imagetexture.c4
-rw-r--r--source/blender/render/intern/source/pipeline.c70
-rw-r--r--source/blender/render/intern/source/pointdensity.c10
-rw-r--r--source/blender/windowmanager/WM_api.h19
-rw-r--r--source/blender/windowmanager/WM_types.h16
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo.c1
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c1
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c1645
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c2
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c22
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c198
-rw-r--r--source/blender/windowmanager/intern/wm_files.c79
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c9
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c28
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c49
-rw-r--r--source/blender/windowmanager/intern/wm_operator_type.c35
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c112
-rw-r--r--source/blender/windowmanager/intern/wm_splash_screen.c20
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c1
-rw-r--r--source/blender/windowmanager/intern/wm_window.c50
-rw-r--r--source/blender/windowmanager/wm_cursors.h117
-rw-r--r--source/blender/windowmanager/wm_event_system.h4
-rw-r--r--source/creator/CMakeLists.txt20
-rw-r--r--source/creator/creator.c4
-rw-r--r--source/creator/creator_args.c16
-rw-r--r--source/creator/creator_signals.c6
m---------source/tools0
-rw-r--r--tests/CMakeLists.txt29
-rw-r--r--tests/gtests/alembic/abc_export_test.cc2
-rw-r--r--tests/gtests/blenlib/BLI_array_ref_test.cc266
-rw-r--r--tests/gtests/blenlib/BLI_array_test.cc103
-rw-r--r--tests/gtests/blenlib/BLI_delaunay_2d_test.cc30
-rw-r--r--tests/gtests/blenlib/BLI_index_range_test.cc131
-rw-r--r--tests/gtests/blenlib/BLI_map_test.cc288
-rw-r--r--tests/gtests/blenlib/BLI_math_base_test.cc30
-rw-r--r--tests/gtests/blenlib/BLI_set_test.cc203
-rw-r--r--tests/gtests/blenlib/BLI_stack_cxx_test.cc63
-rw-r--r--tests/gtests/blenlib/BLI_string_map_test.cc210
-rw-r--r--tests/gtests/blenlib/BLI_string_ref_test.cc230
-rw-r--r--tests/gtests/blenlib/BLI_vector_set_test.cc113
-rw-r--r--tests/gtests/blenlib/BLI_vector_test.cc414
-rw-r--r--tests/gtests/blenlib/CMakeLists.txt12
-rw-r--r--tests/python/CMakeLists.txt106
-rw-r--r--tests/python/bl_load_py_modules.py2
-rw-r--r--tests/python/bl_pyapi_idprop_datablock.py3
-rwxr-xr-xtests/python/eevee_render_tests.py54
-rwxr-xr-xtests/python/ffmpeg_tests.py9
1741 files changed, 223164 insertions, 41324 deletions
diff --git a/.clang-format b/.clang-format
index b81403c46ce..be3546fc49d 100644
--- a/.clang-format
+++ b/.clang-format
@@ -221,6 +221,17 @@ ForEachMacros:
- ITER_BEGIN
- ITER_PIXELS
- ITER_SLOTS
+ - ITER_SLOTS_BEGIN
+ - LOOP_EDITED_POINTS
+ - LOOP_KEYS
+ - LOOP_POINTS
+ - LOOP_SELECTED_KEYS
+ - LOOP_SELECTED_POINTS
+ - LOOP_TAGGED_KEYS
+ - LOOP_TAGGED_POINTS
+ - LOOP_UNSELECTED_POINTS
+ - LOOP_VISIBLE_KEYS
+ - LOOP_VISIBLE_POINTS
- LISTBASE_CIRCULAR_BACKWARD_BEGIN
- LISTBASE_CIRCULAR_FORWARD_BEGIN
- LISTBASE_FOREACH
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 16ac322ebdd..cddb93dd7ab 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -263,6 +263,8 @@ endif()
option(WITH_HEADLESS "Build without graphical support (renderfarm, server mode only)" OFF)
mark_as_advanced(WITH_HEADLESS)
+option(WITH_QUADRIFLOW "Build with quadriflow remesher support" ON)
+
option(WITH_AUDASPACE "Build with blenders audio library (only disable if you know what you're doing!)" ON)
option(WITH_SYSTEM_AUDASPACE "Build with external audaspace library installed on the system (only enable if you know what you're doing!)" OFF)
mark_as_advanced(WITH_AUDASPACE)
@@ -424,6 +426,7 @@ mark_as_advanced(WITH_CYCLES_DEBUG)
mark_as_advanced(WITH_CYCLES_NATIVE_ONLY)
option(WITH_CYCLES_DEVICE_CUDA "Enable Cycles CUDA compute support" ON)
+option(WITH_CYCLES_DEVICE_OPTIX "Enable Cycles OptiX support" OFF)
option(WITH_CYCLES_DEVICE_OPENCL "Enable Cycles OpenCL compute support" ON)
option(WITH_CYCLES_NETWORK "Enable Cycles compute over network support (EXPERIMENTAL and unfinished)" OFF)
mark_as_advanced(WITH_CYCLES_DEVICE_CUDA)
@@ -673,6 +676,7 @@ if(NOT WITH_BOOST)
set_and_warn(WITH_INTERNATIONAL OFF)
set_and_warn(WITH_OPENVDB OFF)
set_and_warn(WITH_OPENCOLORIO OFF)
+ set_and_warn(WITH_QUADRIFLOW OFF)
elseif(WITH_CYCLES OR WITH_OPENIMAGEIO OR WITH_INTERNATIONAL OR
WITH_OPENVDB OR WITH_OPENCOLORIO)
# Keep enabled
@@ -752,14 +756,12 @@ if(NOT WITH_CUDA_DYNLOAD)
endif()
#-----------------------------------------------------------------------------
-# Check for valid directories
-# ... a partial checkout may cause this.
-#
-# note: we need to check for a known subdir in both cases.
-# since uninitialized git submodules will give blank dirs
+# Check check if submodules are cloned
if(WITH_INTERNATIONAL)
- if(NOT EXISTS "${CMAKE_SOURCE_DIR}/release/datafiles/locale/languages")
+ file(GLOB RESULT "${CMAKE_SOURCE_DIR}/release/datafiles/locale")
+ list(LENGTH RESULT DIR_LEN)
+ if(DIR_LEN EQUAL 0)
message(WARNING
"Translation path '${CMAKE_SOURCE_DIR}/release/datafiles/locale' is missing, "
"This is a 'git submodule', which are known not to work with bridges to other version "
@@ -781,7 +783,9 @@ if(WITH_PYTHON)
message(FATAL_ERROR "At least Python 3.7 is required to build")
endif()
- if(NOT EXISTS "${CMAKE_SOURCE_DIR}/release/scripts/addons/modules")
+ file(GLOB RESULT "${CMAKE_SOURCE_DIR}/release/scripts/addons")
+ list(LENGTH RESULT DIR_LEN)
+ if(DIR_LEN EQUAL 0)
message(WARNING
"Addons path '${CMAKE_SOURCE_DIR}/release/scripts/addons' is missing, "
"This is a 'git submodule', which are known not to work with bridges to other version "
@@ -1430,7 +1434,6 @@ if(CMAKE_COMPILER_IS_GNUCC)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_NO_DIV_BY_ZERO -Wno-div-by-zero)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_TYPE_LIMITS -Wtype-limits)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_ERROR_RETURN_TYPE -Werror=return-type)
- ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_ERROR_IMPLICIT_FUNCTION_DECLARATION -Werror=implicit-function-declaration)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_NO_CHAR_SUBSCRIPTS -Wno-char-subscripts)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_NO_UNKNOWN_PRAGMAS -Wno-unknown-pragmas)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_POINTER_ARITH -Wpointer-arith)
@@ -1607,15 +1610,19 @@ if(WITH_PYTHON)
endif()
endif()
-if(
+if(MSVC)
+ # MSVC needs to be tested first, since clang on windows will
+ # match the compiler test below but clang-cl does not accept -std=c++11
+ # since it is on by default and cannot be turned off.
+ #
+ # Nothing special is needed, C++11 features are available by default.
+elseif(
CMAKE_COMPILER_IS_GNUCC OR
CMAKE_C_COMPILER_ID MATCHES "Clang" OR
CMAKE_C_COMPILER_ID MATCHES "Intel"
)
# TODO(sergey): Do we want c++11 or gnu-c++11 here?
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
-elseif(MSVC)
- # Nothing special is needed, C++11 features are available by default.
else()
message(FATAL_ERROR "Unknown compiler ${CMAKE_C_COMPILER_ID}, can't enable C++11 build")
endif()
@@ -1766,6 +1773,7 @@ if(FIRST_RUN)
info_cfg_option(WITH_OPENIMAGEDENOISE)
info_cfg_option(WITH_OPENVDB)
info_cfg_option(WITH_ALEMBIC)
+ info_cfg_option(WITH_QUADRIFLOW)
info_cfg_text("Compiler Options:")
info_cfg_option(WITH_BUILDINFO)
diff --git a/GNUmakefile b/GNUmakefile
index 4462a13207e..e52fd38a7e3 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -62,8 +62,7 @@ Testing Targets
Not associated with building Blender.
* test:
- Run ctest, currently tests import/export,
- operator execution and that python modules load
+ Run automated tests with ctest.
* test_cmake:
Runs our own cmake file checker
which detects errors in the cmake file list definitions
@@ -193,6 +192,16 @@ ifndef PYTHON
PYTHON:=python3
endif
+# For macOS python3 is not installed by default, so fallback to python binary
+# in libraries, or python 2 for running make update to get it.
+ifeq ($(OS_NCASE),darwin)
+ ifeq (, $(shell command -v $(PYTHON)))
+ PYTHON:=../lib/darwin/python/bin/python3.7m
+ ifeq (, $(shell command -v $(PYTHON)))
+ PYTHON:=python
+ endif
+ endif
+endif
# -----------------------------------------------------------------------------
# additional targets for the build configuration
@@ -233,12 +242,19 @@ endif
ifneq "$(findstring ninja, $(MAKECMDGOALS))" ""
BUILD_CMAKE_ARGS:=$(BUILD_CMAKE_ARGS) -G Ninja
BUILD_COMMAND:=ninja
+ DEPS_BUILD_COMMAND:=ninja
else
ifneq ("$(wildcard $(BUILD_DIR)/build.ninja)","")
BUILD_COMMAND:=ninja
else
BUILD_COMMAND:=make -s
endif
+
+ ifneq ("$(wildcard $(DEPS_BUILD_DIR)/build.ninja)","")
+ DEPS_BUILD_COMMAND:=ninja
+ else
+ DEPS_BUILD_COMMAND:=make -s
+ endif
endif
# -----------------------------------------------------------------------------
@@ -333,7 +349,7 @@ deps: .FORCE
@echo
@echo Building dependencies ...
- $(BUILD_COMMAND) -C "$(DEPS_BUILD_DIR)" -j $(NPROCS) $(DEPS_TARGET)
+ $(DEPS_BUILD_COMMAND) -C "$(DEPS_BUILD_DIR)" -j $(NPROCS) $(DEPS_TARGET)
@echo
@echo Dependencies successfully built and installed to $(DEPS_INSTALL_DIR).
@echo
@@ -368,7 +384,7 @@ package_archive: .FORCE
# Tests
#
test: .FORCE
- cd $(BUILD_DIR) ; ctest . --output-on-failure
+ $(PYTHON) ./build_files/utils/make_test.py "$(BUILD_DIR)"
# run pep8 check check on scripts we distribute.
test_pep8: .FORCE
@@ -524,21 +540,11 @@ icons_geom: .FORCE
"$(BLENDER_DIR)/release/datafiles/blender_icons_geom_update.py"
update: .FORCE
- if [ "$(OS_NCASE)" = "darwin" ] && [ ! -d "../lib/$(OS_NCASE)" ]; then \
- svn checkout https://svn.blender.org/svnroot/bf-blender/trunk/lib/$(OS_NCASE) ../lib/$(OS_NCASE) ; \
- fi
- if [ -d "../lib" ]; then \
- svn cleanup ../lib/* ; \
- svn update ../lib/* ; \
- fi
- git pull --rebase
- git submodule update --init --recursive
- git submodule foreach git checkout master
- git submodule foreach git pull --rebase origin master
+ $(PYTHON) ./build_files/utils/make_update.py
format: .FORCE
PATH="../lib/${OS_NCASE}/llvm/bin/:$(PATH)" \
- python3 source/tools/utils_maintenance/clang_format_paths.py $(PATHS)
+ $(PYTHON) source/tools/utils_maintenance/clang_format_paths.py $(PATHS)
# -----------------------------------------------------------------------------
diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt
index 1b387cb86a2..9756ad28454 100644
--- a/build_files/build_environment/CMakeLists.txt
+++ b/build_files/build_environment/CMakeLists.txt
@@ -43,6 +43,7 @@ project("BlenderDependencies")
cmake_minimum_required(VERSION 3.5)
include(ExternalProject)
+include(cmake/check_software.cmake)
include(cmake/options.cmake)
include(cmake/versions.cmake)
@@ -57,7 +58,6 @@ else()
endif()
include(cmake/zlib.cmake)
-include(cmake/blendthumb.cmake)
include(cmake/openal.cmake)
include(cmake/png.cmake)
include(cmake/jpeg.cmake)
diff --git a/build_files/build_environment/cmake/blendthumb.cmake b/build_files/build_environment/cmake/blendthumb.cmake
deleted file mode 100644
index f4cc6ee9d37..00000000000
--- a/build_files/build_environment/cmake/blendthumb.cmake
+++ /dev/null
@@ -1,67 +0,0 @@
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-if(BUILD_MODE STREQUAL Release)
- if(WIN32)
- set(THUMB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../release/windows/blendthumb)
-
- ExternalProject_Add(external_zlib_32
- URL ${ZLIB_URI}
- CMAKE_GENERATOR ${GENERATOR_32}
- URL_HASH MD5=${ZLIB_HASH}
- DOWNLOAD_DIR ${DOWNLOAD_DIR}
- PREFIX ${BUILD_DIR}/zlib32
- CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/zlib32 ${DEFAULT_CMAKE_FLAGS}
- INSTALL_DIR ${LIBDIR}/zlib32
- )
-
- ExternalProject_Add(external_zlib_64
- URL ${ZLIB_URI}
- CMAKE_GENERATOR ${GENERATOR_64}
- URL_HASH MD5=${ZLIB_HASH}
- DOWNLOAD_DIR ${DOWNLOAD_DIR}
- PREFIX ${BUILD_DIR}/zlib64
- CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/zlib64 ${DEFAULT_CMAKE_FLAGS}
- INSTALL_DIR ${LIBDIR}/zlib64
- )
-
- ExternalProject_Add(external_blendthumb_32
- CMAKE_GENERATOR ${GENERATOR_32}
- SOURCE_DIR ${THUMB_DIR}
- PREFIX ${BUILD_DIR}/blendthumb32
- CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/blendThumb32 ${DEFAULT_CMAKE_FLAGS} -DZLIB_INCLUDE=${LIBDIR}/zlib32/include -DZLIB_LIBS=${LIBDIR}/zlib32/lib/zlibstatic.lib
- INSTALL_DIR ${LIBDIR}/blendthumb32
- )
- add_dependencies(
- external_blendthumb_32
- external_zlib_32
- )
-
- ExternalProject_Add(external_blendthumb_64
- CMAKE_GENERATOR ${GENERATOR_64}
- SOURCE_DIR ${THUMB_DIR}
- PREFIX ${BUILD_DIR}/blendthumb64
- CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/blendThumb64 ${DEFAULT_CMAKE_FLAGS} -DZLIB_INCLUDE=${LIBDIR}/zlib64/include -DZLIB_LIBS=${LIBDIR}/zlib64/lib/zlibstatic.lib
- INSTALL_DIR ${LIBDIR}/blendthumb64
- )
- add_dependencies(
- external_blendthumb_64
- external_zlib_64
- )
- endif()
-endif()
diff --git a/build_files/build_environment/cmake/check_software.cmake b/build_files/build_environment/cmake/check_software.cmake
new file mode 100644
index 00000000000..30dea754e20
--- /dev/null
+++ b/build_files/build_environment/cmake/check_software.cmake
@@ -0,0 +1,53 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+if(UNIX)
+ set(_required_software
+ autoconf
+ automake
+ libtoolize
+ nasm
+ yasm
+ tclsh
+ )
+
+ foreach(_software ${_required_software})
+ find_program(_software_find NAMES ${_software})
+ if(NOT _software_find)
+ set(_software_missing "${_software_missing}${_software} ")
+ endif()
+ unset(_software_find CACHE)
+ endforeach()
+
+ if(_software_missing)
+ message(
+ "\n"
+ "Missing software for building Blender dependencies:\n"
+ " ${_software_missing}\n"
+ "\n"
+ "On Debian and Ubuntu:\n"
+ " apt install autoconf automake libtool yasm nasm tcl\n"
+ "\n"
+ "On macOS (with homebrew):\n"
+ " brew install cmake autoconf automake libtool yasm nasm\n"
+ "\n"
+ "Other platforms:\n"
+ " Install equivalent packages.\n")
+ message(FATAL_ERROR "Install missing software before continuing")
+ endif()
+endif()
diff --git a/build_files/build_environment/cmake/harvest.cmake b/build_files/build_environment/cmake/harvest.cmake
index 97e4a6b69d4..526e72e2e33 100644
--- a/build_files/build_environment/cmake/harvest.cmake
+++ b/build_files/build_environment/cmake/harvest.cmake
@@ -51,9 +51,6 @@ if(BUILD_MODE STREQUAL Release)
# tiff
${CMAKE_COMMAND} -E copy ${LIBDIR}/tiff/lib/tiff.lib ${HARVEST_TARGET}/tiff/lib/libtiff.lib &&
${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/tiff/include/ ${HARVEST_TARGET}/tiff/include/ &&
- # BlendThumb
- ${CMAKE_COMMAND} -E copy ${LIBDIR}/BlendThumb64/bin/blendthumb.dll ${HARVEST_TARGET}/ThumbHandler/lib/BlendThumb64.dll &&
- ${CMAKE_COMMAND} -E copy ${LIBDIR}/BlendThumb32/bin/blendthumb.dll ${HARVEST_TARGET}/ThumbHandler/lib/BlendThumb.dll &&
# hidapi
${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/hidapi/ ${HARVEST_TARGET}/hidapi/ &&
# webp, straight up copy
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index ddc896725eb..f594add3a5b 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -1107,13 +1107,14 @@ _create_inst_shortcut() {
# ldconfig
run_ldconfig() {
_lib_path="$INST/$1/lib"
+ _lib64_path="$INST/$1/lib64"
_ldconf_path="/etc/ld.so.conf.d/$1.conf"
PRINT ""
if [ ! $SUDO ]; then
WARNING "--no-sudo enabled, impossible to run ldconfig for $1, you'll have to do it yourself..."
else
INFO "Running ldconfig for $1..."
- $SUDO sh -c "echo \"$_lib_path\" > $_ldconf_path"
+ $SUDO sh -c "/bin/echo -e \"$_lib_path\n$_lib64_path\" > $_ldconf_path"
$SUDO /sbin/ldconfig # XXX OpenSuse does not include sbin in command path with sudo!!!
fi
PRINT ""
@@ -2683,6 +2684,8 @@ compile_OIDN() {
INFO "Own OpenImageDenoise-$OIDN_VERSION is up to date, nothing to do!"
INFO "If you want to force rebuild of this lib, use the --force-oidn option."
fi
+
+ run_ldconfig "oidn"
}
#### Build FFMPEG ####
@@ -3451,7 +3454,7 @@ install_RPM() {
$SUDO dnf -y update
elif [ "$RPM" = "RHEL" ]; then
- if [ "`grep '6\.' /etc/redhat-release`" ]; then
+ if [ "`grep '[^.]6\.' /etc/redhat-release`" ]; then
ERROR "Building with GCC 4.4 is not supported!"
exit 1
else
diff --git a/build_files/buildbot/buildbot_utils.py b/build_files/buildbot/buildbot_utils.py
new file mode 100644
index 00000000000..6891b91aa1e
--- /dev/null
+++ b/build_files/buildbot/buildbot_utils.py
@@ -0,0 +1,112 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import argparse
+import os
+import subprocess
+import sys
+
+class Builder:
+ def __init__(self, name, branch):
+ self.name = name
+ self.branch = branch
+
+ # Buildbot runs from build/ directory
+ self.blender_dir = os.path.abspath(os.path.join('..', 'blender.git'))
+ self.build_dir = os.path.abspath(os.path.join('..', 'build', name))
+ self.install_dir = os.path.abspath(os.path.join('..', 'install', name))
+ self.upload_dir = os.path.abspath(os.path.join('..', 'install'))
+
+ # Detect platform
+ if name.startswith('mac'):
+ self.platform = 'mac'
+ self.command_prefix = []
+ elif name.startswith('linux'):
+ self.platform = 'linux'
+ self.command_prefix = ['scl', 'enable', 'devtoolset-6', '--']
+ elif name.startswith('win'):
+ self.platform = 'win'
+ self.command_prefix = []
+ else:
+ raise ValueError('Unkonw platform for builder ' + self.platform)
+
+ # Always 64 bit now
+ self.bits = 64
+
+def create_builder_from_arguments():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('builder_name')
+ parser.add_argument('branch', default='master', nargs='?')
+ args = parser.parse_args()
+ return Builder(args.builder_name, args.branch)
+
+
+class VersionInfo:
+ def __init__(self, builder):
+ # Get version information
+ buildinfo_h = os.path.join(builder.build_dir, "source", "creator", "buildinfo.h")
+ blender_h = os.path.join(builder.blender_dir, "source", "blender", "blenkernel", "BKE_blender_version.h")
+
+ version_number = int(self._parse_header_file(blender_h, 'BLENDER_VERSION'))
+ self.version = "%d.%d" % (version_number // 100, version_number % 100)
+ self.version_char = self._parse_header_file(blender_h, 'BLENDER_VERSION_CHAR')
+ self.version_cycle = self._parse_header_file(blender_h, 'BLENDER_VERSION_CYCLE')
+ self.version_cycle_number = self._parse_header_file(blender_h, 'BLENDER_VERSION_CYCLE_NUMBER')
+ self.hash = self._parse_header_file(buildinfo_h, 'BUILD_HASH')[1:-1]
+
+ if self.version_cycle == "release":
+ # Final release
+ self.full_version = self.version + self.version_char
+ self.is_development_build = False
+ elif self.version_cycle == "rc":
+ # Release candidate
+ version_cycle = self.version_cycle + self.version_cycle_number
+ if len(self.version_char) == 0:
+ self.full_version = self.version + version_cycle
+ else:
+ self.full_version = self.version + self.version_char + '-' + version_cycle
+ self.is_development_build = False
+ else:
+ # Development build
+ self.full_version = self.version + '-' + self.hash
+ self.is_development_build = True
+
+ def _parse_header_file(self, filename, define):
+ import re
+ regex = re.compile("^#\s*define\s+%s\s+(.*)" % define)
+ with open(filename, "r") as file:
+ for l in file:
+ match = regex.match(l)
+ if match:
+ return match.group(1)
+ return None
+
+
+def call(cmd, env=None, exit_on_error=True):
+ print(' '.join(cmd))
+
+ # Flush to ensure correct order output on Windows.
+ sys.stdout.flush()
+ sys.stderr.flush()
+
+ retcode = subprocess.call(cmd, env=env)
+ if exit_on_error and retcode != 0:
+ sys.exit(retcode)
+ return retcode
diff --git a/build_files/buildbot/slave_compile.py b/build_files/buildbot/slave_compile.py
index 55543055e5b..0da0ead819f 100644
--- a/build_files/buildbot/slave_compile.py
+++ b/build_files/buildbot/slave_compile.py
@@ -18,149 +18,83 @@
# <pep8 compliant>
+import buildbot_utils
import os
-import subprocess
-import sys
import shutil
-# get builder name
-if len(sys.argv) < 2:
- sys.stderr.write("Not enough arguments, expecting builder name\n")
- sys.exit(1)
-
-builder = sys.argv[1]
-
-# we run from build/ directory
-blender_dir = os.path.join('..', 'blender.git')
-
-
-def parse_header_file(filename, define):
- import re
- regex = re.compile("^#\s*define\s+%s\s+(.*)" % define)
- with open(filename, "r") as file:
- for l in file:
- match = regex.match(l)
- if match:
- return match.group(1)
- return None
-
-if 'cmake' in builder:
- # cmake
-
- # Some fine-tuning configuration
- blender_dir = os.path.abspath(blender_dir)
- build_dir = os.path.abspath(os.path.join('..', 'build', builder))
- install_dir = os.path.abspath(os.path.join('..', 'install', builder))
- targets = ['blender']
- command_prefix = []
-
- bits = 64
-
- # Config file to be used (relative to blender's sources root)
- cmake_config_file = "build_files/cmake/config/blender_release.cmake"
-
- # Set build options.
- cmake_options = []
- cmake_extra_options = ['-DCMAKE_BUILD_TYPE:STRING=Release',
- '-DWITH_GTESTS=ON']
-
- if builder.startswith('mac'):
- # Set up OSX architecture
- if builder.endswith('x86_64_10_9_cmake'):
- cmake_extra_options.append('-DCMAKE_OSX_ARCHITECTURES:STRING=x86_64')
- cmake_extra_options.append('-DCMAKE_OSX_DEPLOYMENT_TARGET=10.9')
-
- elif builder.startswith('win'):
- if builder.startswith('win64'):
- cmake_options.extend(['-G', 'Visual Studio 15 2017 Win64'])
- elif builder.startswith('win32'):
- bits = 32
- cmake_options.extend(['-G', 'Visual Studio 15 2017'])
-
- elif builder.startswith('linux'):
- cmake_config_file = "build_files/buildbot/config/blender_linux.cmake"
- tokens = builder.split("_")
- glibc = tokens[1]
- if glibc == 'glibc224':
- deb_name = "stretch"
- if builder.endswith('x86_64_cmake'):
- chroot_name = 'buildbot_' + deb_name + '_x86_64'
- elif builder.endswith('i686_cmake'):
- bits = 32
- chroot_name = 'buildbot_' + deb_name + '_i686'
- command_prefix = ['schroot', '-c', chroot_name, '--']
- elif glibc == 'glibc217':
- command_prefix = ['scl', 'enable', 'devtoolset-6', '--']
-
- cmake_options.append("-C" + os.path.join(blender_dir, cmake_config_file))
-
- # Prepare CMake options needed to configure cuda binaries compilation, 64bit only.
- if bits == 64:
- cmake_options.append("-DWITH_CYCLES_CUDA_BINARIES=ON")
- cmake_options.append("-DCUDA_64_BIT_DEVICE_CODE=ON")
- else:
- cmake_options.append("-DWITH_CYCLES_CUDA_BINARIES=OFF")
+def get_cmake_options(builder):
+ config_file = "build_files/cmake/config/blender_release.cmake"
+ options = ['-DCMAKE_BUILD_TYPE:STRING=Release', '-DWITH_GTESTS=ON']
+
+ if builder.platform == 'mac':
+ options.append('-DCMAKE_OSX_ARCHITECTURES:STRING=x86_64')
+ options.append('-DCMAKE_OSX_DEPLOYMENT_TARGET=10.9')
+ elif builder.platform == 'win':
+ options.extend(['-G', 'Visual Studio 15 2017 Win64'])
+ elif builder.platform == 'linux':
+ config_file = "build_files/buildbot/config/blender_linux.cmake"
+
+ optix_sdk_dir = os.path.join(builder.blender_dir, '..', '..', 'NVIDIA-Optix-SDK')
+ options.append('-DOPTIX_ROOT_DIR:PATH=' + optix_sdk_dir)
+
+ options.append("-C" + os.path.join(builder.blender_dir, config_file))
+ options.append("-DCMAKE_INSTALL_PREFIX=%s" % (builder.install_dir))
- cmake_options.append("-DCMAKE_INSTALL_PREFIX=%s" % (install_dir))
+ return options
- cmake_options += cmake_extra_options
+def update_git(builder):
+ # Do extra git fetch because not all platform/git/buildbot combinations
+ # update the origin remote, causing buildinfo to detect local changes.
+ os.chdir(builder.blender_dir)
+ print("Fetching remotes")
+ command = ['git', 'fetch', '--all']
+ buildbot_utils.call(builder.command_prefix + command)
+
+def clean_directories(builder):
# Make sure no garbage remained from the previous run
- if os.path.isdir(install_dir):
- shutil.rmtree(install_dir)
-
- for target in targets:
- print("Building target %s" % (target))
- # Construct build directory name based on the target
- target_build_dir = build_dir
- target_command_prefix = command_prefix[:]
- if target != 'blender':
- target_build_dir += '_' + target
- target_name = 'install'
- # Tweaking CMake options to respect the target
- target_cmake_options = cmake_options[:]
- # Do extra git fetch because not all platform/git/buildbot combinations
- # update the origin remote, causing buildinfo to detect local changes.
- os.chdir(blender_dir)
- print("Fetching remotes")
- command = ['git', 'fetch', '--all']
- print(command)
- retcode = subprocess.call(target_command_prefix + command)
- if retcode != 0:
- sys.exit(retcode)
- # Make sure build directory exists and enter it
- if not os.path.isdir(target_build_dir):
- os.mkdir(target_build_dir)
- os.chdir(target_build_dir)
- # Configure the build
- print("CMake options:")
- print(target_cmake_options)
- if os.path.exists('CMakeCache.txt'):
- print("Removing CMake cache")
- os.remove('CMakeCache.txt')
- # Remove buildinfo files to force buildbot to re-generate them.
- for buildinfo in ('buildinfo.h', 'buildinfo.h.txt', ):
- full_path = os.path.join('source', 'creator', buildinfo)
- if os.path.exists(full_path):
- print("Removing {}" . format(buildinfo))
- os.remove(full_path)
- retcode = subprocess.call(target_command_prefix + ['cmake', blender_dir] + target_cmake_options)
- if retcode != 0:
- print('Configuration FAILED!')
- sys.exit(retcode)
-
- if 'win32' in builder or 'win64' in builder:
- command = ['cmake', '--build', '.', '--target', target_name, '--config', 'Release']
- else:
- command = ['make', '-s', '-j2', target_name]
-
- print("Executing command:")
- print(command)
- retcode = subprocess.call(target_command_prefix + command)
-
- if retcode != 0:
- sys.exit(retcode)
-
-else:
- print("Unknown building system")
- sys.exit(1)
+ if os.path.isdir(builder.install_dir):
+ shutil.rmtree(builder.install_dir)
+
+ # Make sure build directory exists and enter it
+ os.makedirs(builder.build_dir, exist_ok=True)
+
+ # Remove buildinfo files to force buildbot to re-generate them.
+ for buildinfo in ('buildinfo.h', 'buildinfo.h.txt', ):
+ full_path = os.path.join(builder.build_dir, 'source', 'creator', buildinfo)
+ if os.path.exists(full_path):
+ print("Removing {}" . format(buildinfo))
+ os.remove(full_path)
+
+def cmake_configure(builder):
+ # CMake configuration
+ os.chdir(builder.build_dir)
+
+ cmake_cache = os.path.join(builder.build_dir, 'CMakeCache.txt')
+ if os.path.exists(cmake_cache):
+ print("Removing CMake cache")
+ os.remove(cmake_cache)
+
+ print("CMake configure:")
+ cmake_options = get_cmake_options(builder)
+ command = ['cmake', builder.blender_dir] + cmake_options
+ buildbot_utils.call(builder.command_prefix + command)
+
+def cmake_build(builder):
+ # CMake build
+ os.chdir(builder.build_dir)
+
+ if builder.platform == 'win':
+ command = ['cmake', '--build', '.', '--target', 'install', '--config', 'Release']
+ else:
+ command = ['make', '-s', '-j2', 'install']
+
+ print("CMake build:")
+ buildbot_utils.call(builder.command_prefix + command)
+
+if __name__ == "__main__":
+ builder = buildbot_utils.create_builder_from_arguments()
+ update_git(builder)
+ clean_directories(builder)
+ cmake_configure(builder)
+ cmake_build(builder)
diff --git a/build_files/buildbot/slave_pack.py b/build_files/buildbot/slave_pack.py
index b29b078ca85..a7729843a0e 100644
--- a/build_files/buildbot/slave_pack.py
+++ b/build_files/buildbot/slave_pack.py
@@ -22,47 +22,36 @@
# system and zipping it into buildbot_upload.zip. This is then uploaded
# to the master in the next buildbot step.
+import buildbot_utils
import os
-import subprocess
import sys
-import zipfile
-# get builder name
-if len(sys.argv) < 2:
- sys.stderr.write("Not enough arguments, expecting builder name\n")
- sys.exit(1)
+def get_package_name(builder, platform=None):
+ info = buildbot_utils.VersionInfo(builder)
-builder = sys.argv[1]
-# Never write branch if it is master.
-branch = sys.argv[2] if (len(sys.argv) >= 3 and sys.argv[2] != 'master') else ''
+ package_name = 'blender-' + info.full_version
+ if platform:
+ package_name += '-' + platform
+ if builder.branch != 'master' and info.is_development_build:
+ package_name = builder.branch + "-" + package_name
-blender_dir = os.path.join('..', 'blender.git')
-build_dir = os.path.join('..', 'build', builder)
-install_dir = os.path.join('..', 'install', builder)
-buildbot_upload_zip = os.path.abspath(os.path.join(os.path.dirname(install_dir), "buildbot_upload.zip"))
+ return package_name
-upload_filename = None # Name of the archive to be uploaded
- # (this is the name of archive which will appear on the
- # download page)
-upload_filepath = None # Filepath to be uploaded to the server
- # (this folder will be packed)
+def create_buildbot_upload_zip(builder, package_files):
+ import zipfile
+ buildbot_upload_zip = os.path.join(builder.upload_dir, "buildbot_upload.zip")
+ if os.path.exists(buildbot_upload_zip):
+ os.remove(buildbot_upload_zip)
-def parse_header_file(filename, define):
- import re
- regex = re.compile("^#\s*define\s+%s\s+(.*)" % define)
- with open(filename, "r") as file:
- for l in file:
- match = regex.match(l)
- if match:
- return match.group(1)
- return None
-
-
-# Make sure install directory always exists
-if not os.path.exists(install_dir):
- os.makedirs(install_dir)
-
+ try:
+ z = zipfile.ZipFile(buildbot_upload_zip, "w", compression=zipfile.ZIP_STORED)
+ for filepath, filename in package_files:
+ z.write(filepath, arcname=filename)
+ z.close()
+ except Exception as ex:
+ sys.stderr.write('Create buildbot_upload.zip failed: ' + str(ex) + '\n')
+ sys.exit(1)
def create_tar_bz2(src, dest, package_name):
# One extra to remove leading os.sep when cleaning root for package_root
@@ -80,163 +69,120 @@ def create_tar_bz2(src, dest, package_name):
package.add(entry[0], entry[1], recursive=False)
package.close()
+def cleanup_files(dirpath, extension):
+ for f in os.listdir(dirpath):
+ filepath = os.path.join(dirpath, f)
+ if os.path.isfile(filepath) and f.endswith(extension):
+ os.remove(filepath)
-if builder.find('cmake') != -1:
- # CMake
- if 'win' in builder or 'mac' in builder:
- os.chdir(build_dir)
-
- files = [f for f in os.listdir('.') if os.path.isfile(f) and f.endswith('.zip')]
- for f in files:
- os.remove(f)
- retcode = subprocess.call(['cpack', '-G', 'ZIP'])
- result_file = [f for f in os.listdir('.') if os.path.isfile(f) and f.endswith('.zip')][0]
-
- # TODO(sergey): Such magic usually happens in SCon's packaging but we don't have it
- # in the CMake yet. For until then we do some magic here.
- tokens = result_file.split('-')
- blender_version = tokens[1].split('.')
- blender_full_version = '.'.join(blender_version[0:2])
- git_hash = tokens[2].split('.')[1]
- platform = builder.split('_')[0]
- if platform == 'mac':
- # Special exception for OSX
- platform = 'OSX-10.9-'
- if builder.endswith('x86_64_10_9_cmake'):
- platform += 'x86_64'
- if builder.endswith('vc2015'):
- platform += "-vc14"
- builderified_name = 'blender-{}-{}-{}'.format(blender_full_version, git_hash, platform)
- # NOTE: Blender 2.7 is already respected by blender_full_version.
- if branch != '' and branch != 'blender2.7':
- builderified_name = branch + "-" + builderified_name
-
- os.rename(result_file, "{}.zip".format(builderified_name))
- # create zip file
- try:
- if os.path.exists(buildbot_upload_zip):
- os.remove(buildbot_upload_zip)
- z = zipfile.ZipFile(buildbot_upload_zip, "w", compression=zipfile.ZIP_STORED)
- z.write("{}.zip".format(builderified_name))
- z.close()
- sys.exit(retcode)
- except Exception as ex:
- sys.stderr.write('Create buildbot_upload.zip failed' + str(ex) + '\n')
- sys.exit(1)
-
- elif builder.startswith('linux_'):
- blender = os.path.join(install_dir, 'blender')
-
- buildinfo_h = os.path.join(build_dir, "source", "creator", "buildinfo.h")
- blender_h = os.path.join(blender_dir, "source", "blender", "blenkernel", "BKE_blender_version.h")
-
- # Get version information
- blender_version = int(parse_header_file(blender_h, 'BLENDER_VERSION'))
- blender_version = "%d.%d" % (blender_version // 100, blender_version % 100)
- blender_hash = parse_header_file(buildinfo_h, 'BUILD_HASH')[1:-1]
- blender_glibc = builder.split('_')[1]
- command_prefix = []
- bits = 64
- blender_arch = 'x86_64'
-
- if blender_glibc == 'glibc224':
- if builder.endswith('x86_64_cmake'):
- chroot_name = 'buildbot_stretch_x86_64'
- elif builder.endswith('i686_cmake'):
- chroot_name = 'buildbot_stretch_i686'
- bits = 32
- blender_arch = 'i686'
- command_prefix = ['schroot', '-c', chroot_name, '--']
- elif blender_glibc == 'glibc217':
- command_prefix = ['scl', 'enable', 'devtoolset-6', '--']
-
- # Strip all unused symbols from the binaries
- print("Stripping binaries...")
- subprocess.call(command_prefix + ['strip', '--strip-all', blender])
-
- print("Stripping python...")
- py_target = os.path.join(install_dir, blender_version)
- subprocess.call(command_prefix + ['find', py_target, '-iname', '*.so', '-exec', 'strip', '-s', '{}', ';'])
-
- # Copy all specific files which are too specific to be copied by
- # the CMake rules themselves
- print("Copying extra scripts and libs...")
-
- extra = '/' + os.path.join('home', 'sources', 'release-builder', 'extra')
- mesalibs = os.path.join(extra, 'mesalibs' + str(bits) + '.tar.bz2')
- software_gl = os.path.join(blender_dir, 'release', 'bin', 'blender-softwaregl')
- icons = os.path.join(blender_dir, 'release', 'freedesktop', 'icons')
-
- os.system('tar -xpf %s -C %s' % (mesalibs, install_dir))
- os.system('cp %s %s' % (software_gl, install_dir))
- os.system('cp -r %s %s' % (icons, install_dir))
- os.system('chmod 755 %s' % (os.path.join(install_dir, 'blender-softwaregl')))
-
- # Construct archive name
- package_name = 'blender-%s-%s-linux-%s-%s' % (blender_version,
- blender_hash,
- blender_glibc,
- blender_arch)
- # NOTE: Blender 2.7 is already respected by blender_full_version.
- if branch != '' and branch != 'blender2.7':
- package_name = branch + "-" + package_name
-
- upload_filename = package_name + ".tar.bz2"
-
- print("Creating .tar.bz2 archive")
- upload_filepath = install_dir + '.tar.bz2'
- create_tar_bz2(install_dir, upload_filepath, package_name)
-else:
- print("Unknown building system")
- sys.exit(1)
-
-
-if upload_filepath is None:
- # clean release directory if it already exists
- release_dir = 'release'
-
- if os.path.exists(release_dir):
- for f in os.listdir(release_dir):
- if os.path.isfile(os.path.join(release_dir, f)):
- os.remove(os.path.join(release_dir, f))
-
- # create release package
- try:
- subprocess.call(['make', 'package_archive'])
- except Exception as ex:
- sys.stderr.write('Make package release failed' + str(ex) + '\n')
- sys.exit(1)
- # find release directory, must exist this time
- if not os.path.exists(release_dir):
- sys.stderr.write("Failed to find release directory %r.\n" % release_dir)
- sys.exit(1)
+def pack_mac(builder):
+ info = buildbot_utils.VersionInfo(builder)
- # find release package
- file = None
- filepath = None
+ os.chdir(builder.build_dir)
+ cleanup_files(builder.build_dir, '.dmg')
- for f in os.listdir(release_dir):
- rf = os.path.join(release_dir, f)
- if os.path.isfile(rf) and f.startswith('blender'):
- file = f
- filepath = rf
+ package_name = get_package_name(builder, 'macOS')
+ package_filename = package_name + '.dmg'
+ package_filepath = os.path.join(builder.build_dir, package_filename)
- if not file:
- sys.stderr.write("Failed to find release package.\n")
- sys.exit(1)
+ release_dir = os.path.join(builder.blender_dir, 'release', 'darwin')
+ bundle_sh = os.path.join(release_dir, 'bundle.sh')
+
+ command = [bundle_sh]
+ command += ['--source', builder.install_dir]
+ command += ['--dmg', package_filepath]
+ if info.is_development_build:
+ background_image = os.path.join(release_dir, 'buildbot', 'background.tif')
+ command += ['--background-image', background_image]
+ buildbot_utils.call(command)
+
+ create_buildbot_upload_zip(builder, [(package_filepath, package_filename)])
+
+
+def pack_win(builder):
+ info = buildbot_utils.VersionInfo(builder)
+
+ os.chdir(builder.build_dir)
+ cleanup_files(builder.build_dir, '.zip')
+
+ # CPack will add the platform name
+ cpack_name = get_package_name(builder, None)
+ package_name = get_package_name(builder, 'windows' + str(builder.bits))
+
+ command = ['cmake', '-DCPACK_OVERRIDE_PACKAGENAME:STRING=' + cpack_name, '.']
+ buildbot_utils.call(builder.command_prefix + command)
+ command = ['cpack', '-G', 'ZIP']
+ buildbot_utils.call(builder.command_prefix + command)
+
+ package_filename = package_name + '.zip'
+ package_filepath = os.path.join(builder.build_dir, package_filename)
+ package_files = [(package_filepath, package_filename)]
+
+ if info.version_cycle == 'release':
+ # Installer only for final release builds, otherwise will get
+ # 'this product is already installed' messages.
+ command = ['cpack', '-G', 'WIX']
+ buildbot_utils.call(builder.command_prefix + command)
+
+ package_filename = package_name + '.msi'
+ package_filepath = os.path.join(builder.build_dir, package_filename)
+ package_files += [(package_filepath, package_filename)]
+
+ create_buildbot_upload_zip(builder, package_files)
+
+
+def pack_linux(builder):
+ blender_executable = os.path.join(builder.install_dir, 'blender')
+
+ info = buildbot_utils.VersionInfo(builder)
+ blender_glibc = builder.name.split('_')[1]
+ blender_arch = 'x86_64'
+
+ # Strip all unused symbols from the binaries
+ print("Stripping binaries...")
+ buildbot_utils.call(builder.command_prefix + ['strip', '--strip-all', blender_executable])
+
+ print("Stripping python...")
+ py_target = os.path.join(builder.install_dir, info.version)
+ buildbot_utils.call(builder.command_prefix + ['find', py_target, '-iname', '*.so', '-exec', 'strip', '-s', '{}', ';'])
+
+ # Copy all specific files which are too specific to be copied by
+ # the CMake rules themselves
+ print("Copying extra scripts and libs...")
+
+ extra = '/' + os.path.join('home', 'sources', 'release-builder', 'extra')
+ mesalibs = os.path.join(extra, 'mesalibs' + str(builder.bits) + '.tar.bz2')
+ software_gl = os.path.join(builder.blender_dir, 'release', 'bin', 'blender-softwaregl')
+ icons = os.path.join(builder.blender_dir, 'release', 'freedesktop', 'icons')
+
+ os.system('tar -xpf %s -C %s' % (mesalibs, builder.install_dir))
+ os.system('cp %s %s' % (software_gl, builder.install_dir))
+ os.system('cp -r %s %s' % (icons, builder.install_dir))
+ os.system('chmod 755 %s' % (os.path.join(builder.install_dir, 'blender-softwaregl')))
+
+ # Construct package name
+ platform_name = 'linux-' + blender_glibc + '-' + blender_arch
+ package_name = get_package_name(builder, platform_name)
+ package_filename = package_name + ".tar.bz2"
+
+ print("Creating .tar.bz2 archive")
+ package_filepath = builder.install_dir + '.tar.bz2'
+ create_tar_bz2(builder.install_dir, package_filepath, package_name)
+
+ # Create buildbot_upload.zip
+ create_buildbot_upload_zip(builder, [(package_filepath, package_filename)])
+
+
+if __name__ == "__main__":
+ builder = buildbot_utils.create_builder_from_arguments()
+
+ # Make sure install directory always exists
+ os.makedirs(builder.install_dir, exist_ok=True)
- upload_filename = file
- upload_filepath = filepath
-
-# create zip file
-try:
- upload_zip = os.path.join(buildbot_upload_zip)
- if os.path.exists(upload_zip):
- os.remove(upload_zip)
- z = zipfile.ZipFile(upload_zip, "w", compression=zipfile.ZIP_STORED)
- z.write(upload_filepath, arcname=upload_filename)
- z.close()
-except Exception as ex:
- sys.stderr.write('Create buildbot_upload.zip failed' + str(ex) + '\n')
- sys.exit(1)
+ if builder.platform == 'mac':
+ pack_mac(builder)
+ elif builder.platform == 'win':
+ pack_win(builder)
+ elif builder.platform == 'linux':
+ pack_linux(builder)
diff --git a/build_files/buildbot/slave_rsync.py b/build_files/buildbot/slave_rsync.py
index 6936232a495..19f1e67408d 100644
--- a/build_files/buildbot/slave_rsync.py
+++ b/build_files/buildbot/slave_rsync.py
@@ -21,23 +21,17 @@
# Runs on buildbot slave, rsync zip directly to buildbot server rather
# than using upload which is much slower
+import buildbot_utils
import os
import sys
-# get builder name
-if len(sys.argv) < 2:
- sys.stderr.write("Not enough arguments, expecting builder name\n")
- sys.exit(1)
+if __name__ == "__main__":
+ builder = buildbot_utils.create_builder_from_arguments()
-builder = sys.argv[1]
+ # rsync, this assumes ssh keys are setup so no password is needed
+ local_zip = "buildbot_upload.zip"
+ remote_folder = "builder.blender.org:/data/buildbot-master/uploaded/"
+ remote_zip = remote_folder + "buildbot_upload_" + builder.name + ".zip"
-# rsync, this assumes ssh keys are setup so no password is needed
-local_zip = "buildbot_upload.zip"
-remote_folder = "builder.blender.org:/data/buildbot-master/uploaded/"
-remote_zip = remote_folder + "buildbot_upload_" + builder + ".zip"
-command = "rsync -avz %s %s" % (local_zip, remote_zip)
-
-print(command)
-
-ret = os.system(command)
-sys.exit(ret)
+ command = ["rsync", "-avz", local_zip, remote_zip]
+ buildbot_utils.call(command)
diff --git a/build_files/buildbot/slave_test.py b/build_files/buildbot/slave_test.py
index ff186d8cd45..b959568a5c6 100644
--- a/build_files/buildbot/slave_test.py
+++ b/build_files/buildbot/slave_test.py
@@ -18,59 +18,22 @@
# <pep8 compliant>
-import subprocess
+import buildbot_utils
import os
import sys
-# get builder name
-if len(sys.argv) < 2:
- sys.stderr.write("Not enough arguments, expecting builder name\n")
- sys.exit(1)
+def get_ctest_arguments(builder):
+ args = ['--output-on-failure']
+ if builder.platform == 'win':
+ args += ['-C', 'Release']
+ return args
-builder = sys.argv[1]
+def test(builder):
+ os.chdir(builder.build_dir)
-# we run from build/ directory
-blender_dir = '../blender.git'
+ command = builder.command_prefix + ['ctest'] + get_ctest_arguments(builder)
+ buildbot_utils.call(command)
-if "cmake" in builder:
- print("Automated tests are still DISABLED!")
- sys.exit(0)
-
- build_dir = os.path.abspath(os.path.join('..', 'build', builder))
- install_dir = os.path.abspath(os.path.join('..', 'install', builder))
- # NOTE: For quick test only to see if the approach work.
- # n the future must be replaced with an actual blender version.
- blender_version = '2.80'
- blender_version_dir = os.path.join(install_dir, blender_version)
- command_prefix = []
- extra_ctest_args = []
-
- if builder.startswith('win'):
- extra_ctest_args += ['-C', 'Release']
- elif builder.startswith('linux'):
- tokens = builder.split("_")
- glibc = tokens[1]
- if glibc == 'glibc224':
- deb_name = "stretch"
- if builder.endswith('x86_64_cmake'):
- chroot_name = 'buildbot_' + deb_name + '_x86_64'
- elif builder.endswith('i686_cmake'):
- chroot_name = 'buildbot_' + deb_name + '_i686'
- command_prefix = ['schroot', '--preserve-environment', '-c', chroot_name, '--']
- elif glibc == 'glibc217':
- command_prefix = ['scl', 'enable', 'devtoolset-6', '--']
-
- ctest_env = os.environ.copy()
- ctest_env['BLENDER_SYSTEM_SCRIPTS'] = os.path.join(blender_version_dir, 'scripts')
- ctest_env['BLENDER_SYSTEM_DATAFILES'] = os.path.join(blender_version_dir, 'datafiles')
-
- os.chdir(build_dir)
- retcode = subprocess.call(command_prefix + ['ctest', '--output-on-failure'] + extra_ctest_args,
- env=ctest_env)
-
- # Always exit with a success, for until we know all the tests are passing
- # on all builders.
- sys.exit(0)
-else:
- print("Unknown building system")
- sys.exit(1)
+if __name__ == "__main__":
+ builder = buildbot_utils.create_builder_from_arguments()
+ test(builder)
diff --git a/build_files/buildbot/slave_update.py b/build_files/buildbot/slave_update.py
new file mode 100644
index 00000000000..39f449b87bc
--- /dev/null
+++ b/build_files/buildbot/slave_update.py
@@ -0,0 +1,31 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import buildbot_utils
+import os
+import sys
+
+if __name__ == "__main__":
+ builder = buildbot_utils.create_builder_from_arguments()
+ os.chdir(builder.blender_dir)
+
+ # Run make update which handles all libraries and submodules.
+ make_update = os.path.join(builder.blender_dir, "build_files", "utils", "make_update.py")
+ buildbot_utils.call([sys.executable, make_update, '--no-blender', "--use-tests"])
diff --git a/build_files/cmake/Modules/FindOptiX.cmake b/build_files/cmake/Modules/FindOptiX.cmake
new file mode 100644
index 00000000000..56fd2fd1396
--- /dev/null
+++ b/build_files/cmake/Modules/FindOptiX.cmake
@@ -0,0 +1,57 @@
+# - Find OptiX library
+# Find the native OptiX includes and library
+# This module defines
+# OPTIX_INCLUDE_DIRS, where to find optix.h, Set when
+# OPTIX_INCLUDE_DIR is found.
+# OPTIX_ROOT_DIR, The base directory to search for OptiX.
+# This can also be an environment variable.
+# OPTIX_FOUND, If false, do not try to use OptiX.
+
+#=============================================================================
+# Copyright 2019 Blender Foundation.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+# If OPTIX_ROOT_DIR was defined in the environment, use it.
+IF(NOT OPTIX_ROOT_DIR AND NOT $ENV{OPTIX_ROOT_DIR} STREQUAL "")
+ SET(OPTIX_ROOT_DIR $ENV{OPTIX_ROOT_DIR})
+ENDIF()
+
+SET(_optix_SEARCH_DIRS
+ ${OPTIX_ROOT_DIR}
+ "$ENV{PROGRAMDATA}/NVIDIA Corporation/OptiX SDK 7.0.0"
+ /usr/local
+ /sw # Fink
+ /opt/local # DarwinPorts
+)
+
+FIND_PATH(OPTIX_INCLUDE_DIR
+ NAMES
+ optix.h
+ HINTS
+ ${_optix_SEARCH_DIRS}
+ PATH_SUFFIXES
+ include
+)
+
+# handle the QUIETLY and REQUIRED arguments and set OPTIX_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(OptiX DEFAULT_MSG
+ OPTIX_INCLUDE_DIR)
+
+IF(OPTIX_FOUND)
+ SET(OPTIX_INCLUDE_DIRS ${OPTIX_INCLUDE_DIR})
+ENDIF(OPTIX_FOUND)
+
+MARK_AS_ADVANCED(
+ OPTIX_INCLUDE_DIR
+)
+
+UNSET(_optix_SEARCH_DIRS)
diff --git a/build_files/cmake/Modules/GTestTesting.cmake b/build_files/cmake/Modules/GTestTesting.cmake
index 47edbdf37a6..1c98a6456b8 100644
--- a/build_files/cmake/Modules/GTestTesting.cmake
+++ b/build_files/cmake/Modules/GTestTesting.cmake
@@ -14,12 +14,15 @@
macro(BLENDER_SRC_GTEST_EX NAME SRC EXTRA_LIBS DO_ADD_TEST)
if(WITH_GTESTS)
+ set(TARGET_NAME ${NAME}_test)
get_property(_current_include_directories
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
PROPERTY INCLUDE_DIRECTORIES)
set(TEST_INC
${_current_include_directories}
${CMAKE_SOURCE_DIR}/tests/gtests
+ )
+ set(TEST_INC_SYS
${GLOG_INCLUDE_DIRS}
${GFLAGS_INCLUDE_DIRS}
${CMAKE_SOURCE_DIR}/extern/gtest/include
@@ -27,8 +30,10 @@ macro(BLENDER_SRC_GTEST_EX NAME SRC EXTRA_LIBS DO_ADD_TEST)
)
unset(_current_include_directories)
- add_executable(${NAME}_test ${SRC})
- target_link_libraries(${NAME}_test
+ add_executable(${TARGET_NAME} ${SRC})
+ target_include_directories(${TARGET_NAME} PUBLIC "${TEST_INC}")
+ target_include_directories(${TARGET_NAME} SYSTEM PUBLIC "${TEST_INC_SYS}")
+ target_link_libraries(${TARGET_NAME}
${EXTRA_LIBS}
${PLATFORM_LINKLIBS}
bf_testing_main
@@ -41,20 +46,22 @@ macro(BLENDER_SRC_GTEST_EX NAME SRC EXTRA_LIBS DO_ADD_TEST)
${GLOG_LIBRARIES}
${GFLAGS_LIBRARIES})
if(WITH_OPENMP_STATIC)
- target_link_libraries(${NAME}_test ${OpenMP_LIBRARIES})
+ target_link_libraries(${TARGET_NAME} ${OpenMP_LIBRARIES})
endif()
- set_target_properties(${NAME}_test PROPERTIES
+ set_target_properties(${TARGET_NAME} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${TESTS_OUTPUT_DIR}"
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${TESTS_OUTPUT_DIR}"
- RUNTIME_OUTPUT_DIRECTORY_DEBUG "${TESTS_OUTPUT_DIR}"
- INCLUDE_DIRECTORIES "${TEST_INC}")
+ RUNTIME_OUTPUT_DIRECTORY_DEBUG "${TESTS_OUTPUT_DIR}")
if(${DO_ADD_TEST})
- add_test(NAME ${NAME}_test COMMAND ${TESTS_OUTPUT_DIR}/${NAME}_test WORKING_DIRECTORY $<TARGET_FILE_DIR:blender>)
+ add_test(NAME ${TARGET_NAME} COMMAND ${TESTS_OUTPUT_DIR}/${TARGET_NAME} WORKING_DIRECTORY ${TEST_INSTALL_DIR})
# Don't fail tests on leaks since these often happen in external libraries
# that we can't fix.
- set_tests_properties(${NAME}_test PROPERTIES ENVIRONMENT LSAN_OPTIONS=exitcode=0)
+ set_tests_properties(${TARGET_NAME} PROPERTIES ENVIRONMENT LSAN_OPTIONS=exitcode=0)
endif()
+ unset(TEST_INC)
+ unset(TEST_INC_SYS)
+ unset(TARGET_NAME)
endif()
endmacro()
diff --git a/build_files/cmake/buildinfo.cmake b/build_files/cmake/buildinfo.cmake
index ec43534528a..cef6b94ee2e 100644
--- a/build_files/cmake/buildinfo.cmake
+++ b/build_files/cmake/buildinfo.cmake
@@ -145,22 +145,13 @@ if(EXISTS ${SOURCE_DIR}/.git)
unset(_git_changed_files)
endif()
-# BUILD_PLATFORM and BUILD_PLATFORM are taken from CMake
+# BUILD_PLATFORM is taken from CMake
# but BUILD_DATE and BUILD_TIME are platform dependent
-if(UNIX)
- if(NOT BUILD_DATE)
- execute_process(COMMAND date "+%Y-%m-%d" OUTPUT_VARIABLE BUILD_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
- endif()
- if(NOT BUILD_TIME)
- execute_process(COMMAND date "+%H:%M:%S" OUTPUT_VARIABLE BUILD_TIME OUTPUT_STRIP_TRAILING_WHITESPACE)
- endif()
-elseif(WIN32)
- if(NOT BUILD_DATE)
- execute_process(COMMAND cmd /c date /t OUTPUT_VARIABLE BUILD_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
- endif()
- if(NOT BUILD_TIME)
- execute_process(COMMAND cmd /c time /t OUTPUT_VARIABLE BUILD_TIME OUTPUT_STRIP_TRAILING_WHITESPACE)
- endif()
+if(NOT BUILD_DATE)
+ STRING(TIMESTAMP BUILD_DATE "%Y-%m-%d" UTC)
+endif()
+if(NOT BUILD_TIME)
+ STRING(TIMESTAMP BUILD_TIME "%H:%M:%S" UTC)
endif()
# Write a file with the BUILD_HASH define
diff --git a/build_files/cmake/config/blender_full.cmake b/build_files/cmake/config/blender_full.cmake
index 75c5e0f34c1..403d38f6a05 100644
--- a/build_files/cmake/config/blender_full.cmake
+++ b/build_files/cmake/config/blender_full.cmake
@@ -46,6 +46,7 @@ set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE)
set(WITH_OPENVDB ON CACHE BOOL "" FORCE)
set(WITH_OPENVDB_BLOSC ON CACHE BOOL "" FORCE)
set(WITH_PYTHON_INSTALL ON CACHE BOOL "" FORCE)
+set(WITH_QUADRIFLOW ON CACHE BOOL "" FORCE)
set(WITH_RAYOPTIMIZATION ON CACHE BOOL "" FORCE)
set(WITH_SDL ON CACHE BOOL "" FORCE)
set(WITH_X11_XINPUT ON CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake
index 6596d1db674..37cbfa27972 100644
--- a/build_files/cmake/config/blender_lite.cmake
+++ b/build_files/cmake/config/blender_lite.cmake
@@ -17,6 +17,7 @@ set(WITH_CODEC_FFMPEG OFF CACHE BOOL "" FORCE)
set(WITH_CODEC_SNDFILE OFF CACHE BOOL "" FORCE)
set(WITH_CYCLES OFF CACHE BOOL "" FORCE)
set(WITH_CYCLES_OSL OFF CACHE BOOL "" FORCE)
+set(WITH_CYCLES_DEVICE_OPTIX OFF CACHE BOOL "" FORCE)
set(WITH_DRACO OFF CACHE BOOL "" FORCE)
set(WITH_FFTW3 OFF CACHE BOOL "" FORCE)
set(WITH_LIBMV OFF CACHE BOOL "" FORCE)
@@ -50,6 +51,7 @@ set(WITH_OPENIMAGEIO OFF CACHE BOOL "" FORCE)
set(WITH_OPENMP OFF CACHE BOOL "" FORCE)
set(WITH_OPENSUBDIV OFF CACHE BOOL "" FORCE)
set(WITH_OPENVDB OFF CACHE BOOL "" FORCE)
+set(WITH_QUADRIFLOW OFF CACHE BOOL "" FORCE)
set(WITH_RAYOPTIMIZATION OFF CACHE BOOL "" FORCE)
set(WITH_SDL OFF CACHE BOOL "" FORCE)
set(WITH_X11_XINPUT OFF CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/config/blender_release.cmake b/build_files/cmake/config/blender_release.cmake
index 08218a5e57c..cb338f40a7b 100644
--- a/build_files/cmake/config/blender_release.cmake
+++ b/build_files/cmake/config/blender_release.cmake
@@ -47,6 +47,7 @@ set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE)
set(WITH_OPENVDB ON CACHE BOOL "" FORCE)
set(WITH_OPENVDB_BLOSC ON CACHE BOOL "" FORCE)
set(WITH_PYTHON_INSTALL ON CACHE BOOL "" FORCE)
+set(WITH_QUADRIFLOW ON CACHE BOOL "" FORCE)
set(WITH_RAYOPTIMIZATION ON CACHE BOOL "" FORCE)
set(WITH_SDL ON CACHE BOOL "" FORCE)
set(WITH_X11_XINPUT ON CACHE BOOL "" FORCE)
@@ -56,6 +57,7 @@ set(WITH_MEM_JEMALLOC ON CACHE BOOL "" FORCE)
set(WITH_CYCLES_CUDA_BINARIES ON CACHE BOOL "" FORCE)
set(WITH_CYCLES_CUBIN_COMPILER OFF CACHE BOOL "" FORCE)
set(CYCLES_CUDA_BINARIES_ARCH sm_30;sm_35;sm_37;sm_50;sm_52;sm_60;sm_61;sm_70;sm_75 CACHE STRING "" FORCE)
+set(WITH_CYCLES_DEVICE_OPTIX ON CACHE BOOL "" FORCE)
# platform dependent options
if(UNIX AND NOT APPLE)
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index f6756cb514c..e159dd9e5ee 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -719,7 +719,7 @@ macro(remove_strict_flags)
endif()
if(MSVC)
- remove_cc_flag(/w34189) # Restore warn C4189 (unused variable) back to w4
+ remove_cc_flag(/w34189) # Restore warn C4189 (unused variable) back to w4
endif()
endmacro()
diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake
index e79359e9f3b..249546dd216 100644
--- a/build_files/cmake/platform/platform_apple.cmake
+++ b/build_files/cmake/platform/platform_apple.cmake
@@ -322,7 +322,6 @@ endif()
if(WITH_LLVM)
set(LLVM_ROOT_DIR ${LIBDIR}/llvm)
- set(LLVM_VERSION 3.4)
if(EXISTS "${LLVM_ROOT_DIR}/bin/llvm-config")
set(LLVM_CONFIG "${LLVM_ROOT_DIR}/bin/llvm-config")
else()
@@ -334,6 +333,9 @@ if(WITH_LLVM)
execute_process(COMMAND ${LLVM_CONFIG} --prefix
OUTPUT_VARIABLE LLVM_ROOT_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND ${LLVM_CONFIG} --includedir
+ OUTPUT_VARIABLE LLVM_INCLUDE_DIRS
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND ${LLVM_CONFIG} --libdir
OUTPUT_VARIABLE LLVM_LIBPATH
OUTPUT_STRIP_TRAILING_WHITESPACE)
diff --git a/build_files/utils/make_test.py b/build_files/utils/make_test.py
new file mode 100755
index 00000000000..a8a6afc43cc
--- /dev/null
+++ b/build_files/utils/make_test.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+#
+# "make test" for all platforms, running automated tests.
+
+import argparse
+import os
+import shutil
+import sys
+
+import make_utils
+from make_utils import call
+
+# Parse arguments
+
+def parse_arguments():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--ctest-command", default="ctest")
+ parser.add_argument("--cmake-command", default="cmake")
+ parser.add_argument("--svn-command", default="svn")
+ parser.add_argument("--git-command", default="git")
+ parser.add_argument("--config", default="")
+ parser.add_argument("build_directory")
+ return parser.parse_args()
+
+args = parse_arguments()
+git_command = args.git_command
+svn_command = args.svn_command
+ctest_command = args.ctest_command
+cmake_command = args.cmake_command
+config = args.config
+build_dir = args.build_directory
+
+if make_utils.command_missing(ctest_command):
+ sys.stderr.write("ctest not found, can't run tests\n")
+ sys.exit(1)
+
+if make_utils.command_missing(git_command):
+ sys.stderr.write("git not found, can't run tests\n")
+ sys.exit(1)
+
+# Test if we are building a specific release version.
+release_version = make_utils.git_branch_release_version(git_command)
+lib_tests_dirpath = os.path.join('..', 'lib', "tests")
+
+if not os.path.exists(lib_tests_dirpath):
+ print("Tests files not found, downloading...")
+
+ if make_utils.command_missing(svn_command):
+ sys.stderr.write("svn not found, can't checkout test files\n")
+ sys.exit(1)
+
+ if make_utils.command_missing(cmake_command):
+ sys.stderr.write("cmake not found, can't checkout test files\n")
+ sys.exit(1)
+
+ svn_url = make_utils.svn_libraries_base_url(release_version) + "/tests"
+ call([svn_command, "checkout", svn_url, lib_tests_dirpath])
+
+ # Run cmake again to detect tests files.
+ os.chdir(build_dir)
+ call([cmake_command, "."])
+
+# Run tests
+tests_dir = os.path.join(build_dir, "tests")
+os.makedirs(tests_dir, exist_ok=True)
+
+os.chdir(build_dir)
+command = [ctest_command, ".", "--output-on-failure"]
+if len(config):
+ command += ["-C", config]
+ tests_log = "log_" + config + ".txt"
+else:
+ tests_log = "log.txt"
+command += ["-O", os.path.join(tests_dir, tests_log)]
+call(command)
diff --git a/build_files/utils/make_update.py b/build_files/utils/make_update.py
new file mode 100755
index 00000000000..3ecfa218432
--- /dev/null
+++ b/build_files/utils/make_update.py
@@ -0,0 +1,168 @@
+#!/usr/bin/env python3
+#
+# "make update" for all platforms, updating svn libraries and tests and Blender
+# git repository and submodules.
+#
+# For release branches, this will check out the appropriate branches of
+# submodules and libraries.
+
+import argparse
+import os
+import shutil
+import sys
+
+import make_utils
+from make_utils import call, check_output
+
+def print_stage(text):
+ print("")
+ print(text)
+ print("")
+
+# Parse arguments
+def parse_arguments():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--no-libraries", action="store_true")
+ parser.add_argument("--no-blender", action="store_true")
+ parser.add_argument("--no-submodules", action="store_true")
+ parser.add_argument("--use-tests", action="store_true")
+ parser.add_argument("--svn-command", default="svn")
+ parser.add_argument("--git-command", default="git")
+ return parser.parse_args()
+
+# Setup for precompiled libraries and tests from svn.
+def svn_update(args, release_version):
+ svn_non_interactive = [args.svn_command, '--non-interactive']
+
+ lib_dirpath = os.path.join('..', 'lib')
+ svn_url = make_utils.svn_libraries_base_url(release_version)
+
+ # Checkout precompiled libraries
+ if sys.platform == 'darwin':
+ lib_platform = "darwin"
+ elif sys.platform == 'win32':
+ # Windows checkout is usually handled by bat scripts since python3 to run
+ # this script is bundled as part of the precompiled libraries. However it
+ # is used by the buildbot.
+ lib_platform = "win64_vc14"
+ else:
+ # No precompiled libraries for Linux.
+ lib_platform = None
+
+ if lib_platform:
+ lib_platform_dirpath = os.path.join(lib_dirpath, lib_platform)
+
+ if not os.path.exists(lib_platform_dirpath):
+ print_stage("Checking out Precompiled Libraries")
+
+ if make_utils.command_missing(args.svn_command):
+ sys.stderr.write("svn not found, can't checkout libraries\n")
+ sys.exit(1)
+
+ svn_url_platform = svn_url + lib_platform
+ call(svn_non_interactive + ["checkout", svn_url_platform, lib_platform_dirpath])
+
+ if args.use_tests:
+ lib_tests = "tests"
+ lib_tests_dirpath = os.path.join(lib_dirpath, lib_tests)
+
+ if not os.path.exists(lib_tests_dirpath):
+ print_stage("Checking out Tests")
+
+ if make_utils.command_missing(args.svn_command):
+ sys.stderr.write("svn not found, can't checkout tests\n")
+ sys.exit(1)
+
+ svn_url_tests = svn_url + lib_tests
+ call(svn_non_interactive + ["checkout", svn_url_tests, lib_tests_dirpath])
+
+ # Update precompiled libraries and tests
+ print_stage("Updating Precompiled Libraries and Tests")
+
+ if os.path.isdir(lib_dirpath):
+ for dirname in os.listdir(lib_dirpath):
+ if dirname == ".svn":
+ continue
+
+ dirpath = os.path.join(lib_dirpath, dirname)
+ svn_dirpath = os.path.join(dirpath, ".svn")
+ svn_root_dirpath = os.path.join(lib_dirpath, ".svn")
+
+ if os.path.isdir(dirpath) and \
+ (os.path.exists(svn_dirpath) or os.path.exists(svn_root_dirpath)):
+ if make_utils.command_missing(args.svn_command):
+ sys.stderr.write("svn not found, can't update libraries\n")
+ sys.exit(1)
+
+ call(svn_non_interactive + ["cleanup", dirpath])
+ call(svn_non_interactive + ["switch", svn_url + dirname, dirpath])
+ call(svn_non_interactive + ["update", dirpath])
+
+
+# Update blender repository.
+def blender_update_skip(args):
+ if make_utils.command_missing(args.git_command):
+ sys.stderr.write("git not found, can't update code\n")
+ sys.exit(1)
+
+ # Abort if a rebase is still progress.
+ rebase_merge = check_output([args.git_command, 'rev-parse', '--git-path', 'rebase-merge'])
+ rebase_apply = check_output([args.git_command, 'rev-parse', '--git-path', 'rebase-apply'])
+ merge_head = check_output([args.git_command, 'rev-parse', '--git-path', 'MERGE_HEAD'])
+ if os.path.exists(rebase_merge) or \
+ os.path.exists(rebase_apply) or \
+ os.path.exists(merge_head):
+ return "rebase or merge in progress, complete it first"
+
+ # Abort if uncommitted changes.
+ changes = check_output([args.git_command, 'status', '--porcelain', '--untracked-files=no'])
+ if len(changes) != 0:
+ return "you have unstaged changes"
+
+ # Test if there is an upstream branch configured
+ branch = check_output([args.git_command, "rev-parse", "--abbrev-ref", "HEAD"])
+ remote = check_output([args.git_command, "config", "branch." + branch + ".remote"], exit_on_error=False)
+ if len(remote) == 0:
+ return "no remote branch to pull from"
+
+ return None
+
+def blender_update(args):
+ print_stage("Updating Blender Git Repository")
+ call([args.git_command, "pull", "--rebase"])
+
+
+# Update submodules.
+def submodules_update(args, release_version):
+ print_stage("Updating Submodules")
+ if make_utils.command_missing(args.git_command):
+ sys.stderr.write("git not found, can't update code\n")
+ sys.exit(1)
+
+ call([args.git_command, "submodule", "update", "--init", "--recursive"])
+ if not release_version:
+ # Update submodules to latest master if not building a specific release.
+ # In that case submodules are set to a specific revision, which is checked
+ # out by running "git submodule update".
+ call([args.git_command, "submodule", "foreach", "git", "checkout", "master"])
+ call([args.git_command, "submodule", "foreach", "git", "pull", "--rebase", "origin", "master"])
+
+
+if __name__ == "__main__":
+ args = parse_arguments()
+ blender_skipped = None
+
+ # Test if we are building a specific release version.
+ release_version = make_utils.git_branch_release_version(args.git_command)
+
+ if not args.no_libraries:
+ svn_update(args, release_version)
+ if not args.no_blender:
+ blender_skipped = blender_update_skip(args)
+ if not blender_skipped:
+ blender_update(args)
+ if not args.no_submodules:
+ submodules_update(args, release_version)
+
+ if blender_skipped:
+ print_stage("Blender repository skipped: " + blender_skipped)
diff --git a/build_files/utils/make_utils.py b/build_files/utils/make_utils.py
new file mode 100755
index 00000000000..5fedd792149
--- /dev/null
+++ b/build_files/utils/make_utils.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python3
+#
+# Utility functions for make update and make tests.
+
+import re
+import shutil
+import subprocess
+import sys
+
+def call(cmd, exit_on_error=True):
+ print(" ".join(cmd))
+
+ # Flush to ensure correct order output on Windows.
+ sys.stdout.flush()
+ sys.stderr.flush()
+
+ retcode = subprocess.call(cmd)
+ if exit_on_error and retcode != 0:
+ sys.exit(retcode)
+ return retcode
+
+def check_output(cmd, exit_on_error=True):
+ # Flush to ensure correct order output on Windows.
+ sys.stdout.flush()
+ sys.stderr.flush()
+
+ try:
+ output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, universal_newlines=True)
+ except subprocess.CalledProcessError as e:
+ if exit_on_error:
+ sys.stderr.write(" ".join(cmd))
+ sys.stderr.write(e.output + "\n")
+ sys.exit(e.returncode)
+ output = ""
+
+ return output.strip()
+
+def git_branch_release_version(git_command):
+ # Test if we are building a specific release version.
+ try:
+ branch = subprocess.check_output([git_command, "rev-parse", "--abbrev-ref", "HEAD"])
+ except subprocess.CalledProcessError as e:
+ sys.stderr.write("Failed to get Blender git branch\n")
+ sys.exit(1)
+
+ branch = branch.strip().decode('utf8')
+ release_version = re.search("^blender-v(.*)-release$", branch)
+ if release_version:
+ release_version = release_version.group(1)
+ return release_version
+
+def svn_libraries_base_url(release_version):
+ if release_version:
+ svn_branch = "tags/blender-" + release_version + "-release"
+ else:
+ svn_branch = "trunk"
+ return "https://svn.blender.org/svnroot/bf-blender/" + svn_branch + "/lib/"
+
+def command_missing(command):
+ # Support running with Python 2 for macOS
+ if sys.version_info >= (3, 0):
+ return shutil.which(command) is None
+ else:
+ return False
diff --git a/build_files/windows/check_libraries.cmd b/build_files/windows/check_libraries.cmd
index fcae2c90657..b838c7d7d19 100644
--- a/build_files/windows/check_libraries.cmd
+++ b/build_files/windows/check_libraries.cmd
@@ -39,6 +39,15 @@ if NOT EXIST %BUILD_VS_LIBDIR% (
)
)
)
+) else (
+ if NOT EXIST %PYTHON% (
+ if not "%SVN%"=="" (
+ echo.
+ echo Python not found in external libraries, updating to latest version
+ echo.
+ "%SVN%" update %BUILD_VS_LIBDIR%
+ )
+ )
)
if NOT EXIST %BUILD_VS_LIBDIR% (
diff --git a/build_files/windows/configure_ninja.cmd b/build_files/windows/configure_ninja.cmd
index 995d8d56fa8..8f766e855a6 100644
--- a/build_files/windows/configure_ninja.cmd
+++ b/build_files/windows/configure_ninja.cmd
@@ -30,9 +30,15 @@ set LLVM_DIR=
:DetectionComplete
set CC=%LLVM_DIR%\bin\clang-cl
set CXX=%LLVM_DIR%\bin\clang-cl
- rem build and tested against 2017 15.7
- set CFLAGS=-m64 -fmsc-version=1914
- set CXXFLAGS=-m64 -fmsc-version=1914
+ if "%BUILD_VS_YEAR%" == "2019" (
+ rem build and tested against 2019 16.2
+ set CFLAGS=-m64 -fmsc-version=1922
+ set CXXFLAGS=-m64 -fmsc-version=1922
+ ) else (
+ rem build and tested against 2017 15.7
+ set CFLAGS=-m64 -fmsc-version=1914
+ set CXXFLAGS=-m64 -fmsc-version=1914
+ )
if "%WITH_ASAN%"=="1" (
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -DWITH_COMPILER_ASAN=On
)
diff --git a/build_files/windows/find_dependencies.cmd b/build_files/windows/find_dependencies.cmd
index a861cf1c98b..7419a0bc77e 100644
--- a/build_files/windows/find_dependencies.cmd
+++ b/build_files/windows/find_dependencies.cmd
@@ -1,13 +1,17 @@
REM find all dependencies and set the corresponding environment variables.
for %%X in (svn.exe) do (set SVN=%%~$PATH:X)
for %%X in (cmake.exe) do (set CMAKE=%%~$PATH:X)
+for %%X in (ctest.exe) do (set CTEST=%%~$PATH:X)
for %%X in (git.exe) do (set GIT=%%~$PATH:X)
+set PYTHON=%BLENDER_DIR%\..\lib\win64_vc14\python\37\bin\python.exe
if NOT "%verbose%" == "" (
- echo svn : "%SVN%"
- echo cmake : "%CMAKE%"
- echo git : "%GIT%"
+ echo svn : "%SVN%"
+ echo cmake : "%CMAKE%"
+ echo ctest : "%CTEST%"
+ echo git : "%GIT%"
+ echo python : "%PYTHON%"
)
if "%CMAKE%" == "" (
echo Cmake not found in path, required for building, exiting...
exit /b 1
-) \ No newline at end of file
+)
diff --git a/build_files/windows/format.cmd b/build_files/windows/format.cmd
index f036257e220..43f8b61727d 100644
--- a/build_files/windows/format.cmd
+++ b/build_files/windows/format.cmd
@@ -9,7 +9,7 @@ exit /b 1
:detect_done
echo found clang-format in %CF_PATH%
-if EXIST %BLENDER_DIR%\..\lib\win64_vc14\python\37\bin\python.exe (
+if EXIST %PYTHON% (
set PYTHON=%BLENDER_DIR%\..\lib\win64_vc14\python\37\bin\python.exe
goto detect_python_done
)
@@ -25,6 +25,7 @@ set FORMAT_PATHS=%BLENDER_DIR%\source\tools\utils_maintenance\clang_format_paths
REM The formatting script expects clang-format to be in the current PATH.
set PATH=%CF_PATH%;%PATH%
-%PYTHON% %FORMAT_PATHS% %FORMAT_ARGS%
+REM Use -B to avoid writing __pycache__ in lib directory and causing update conflicts.
+%PYTHON% -B %FORMAT_PATHS% %FORMAT_ARGS%
:EOF
diff --git a/build_files/windows/parse_arguments.cmd b/build_files/windows/parse_arguments.cmd
index 3f40ef1f5ef..5f60e321a56 100644
--- a/build_files/windows/parse_arguments.cmd
+++ b/build_files/windows/parse_arguments.cmd
@@ -13,7 +13,7 @@ if NOT "%1" == "" (
set BUILD_TYPE=Debug
REM Build Configurations
) else if "%1" == "builddir" (
- set BUILD_DIR_OVERRRIDE="%BLENDER_DIR%..\%2"
+ set BUILD_DIR_OVERRRIDE=%BLENDER_DIR%..\%2
shift /1
) else if "%1" == "with_tests" (
set TESTS_CMAKE_ARGS=%TESTS_CMAKE_ARGS% -DWITH_GTESTS=On
@@ -82,18 +82,19 @@ if NOT "%1" == "" (
REM Non-Build Commands
) else if "%1" == "update" (
SET BUILD_UPDATE=1
- set BUILD_UPDATE_SVN=1
- set BUILD_UPDATE_GIT=1
+ set BUILD_UPDATE_ARGS=
) else if "%1" == "code_update" (
SET BUILD_UPDATE=1
- set BUILD_UPDATE_SVN=0
- set BUILD_UPDATE_GIT=1
+ set BUILD_UPDATE_ARGS="--no-libraries"
) else if "%1" == "ninja" (
SET BUILD_WITH_NINJA=1
) else if "%1" == "clean" (
set MUST_CLEAN=1
) else if "%1" == "verbose" (
set VERBOSE=1
+ ) else if "%1" == "test" (
+ set TEST=1
+ set NOBUILD=1
) else if "%1" == "format" (
set FORMAT=1
set FORMAT_ARGS=%2 %3 %4 %5 %6 %7 %8 %9
@@ -108,4 +109,4 @@ if NOT "%1" == "" (
:EOF
exit /b 0
:ERR
-exit /b 1 \ No newline at end of file
+exit /b 1
diff --git a/build_files/windows/reset_variables.cmd b/build_files/windows/reset_variables.cmd
index 8b74cec238d..48a61aff44a 100644
--- a/build_files/windows/reset_variables.cmd
+++ b/build_files/windows/reset_variables.cmd
@@ -29,3 +29,4 @@ set ASAN_CMAKE_ARGS=
set WITH_PYDEBUG=
set PYDEBUG_CMAKE_ARGS=
set FORMAT=
+set TEST=
diff --git a/build_files/windows/show_help.cmd b/build_files/windows/show_help.cmd
index d0469688b5a..30f75316499 100644
--- a/build_files/windows/show_help.cmd
+++ b/build_files/windows/show_help.cmd
@@ -13,6 +13,7 @@ echo - update ^(Update both SVN and GIT^)
echo - code_update ^(Update only GIT^)
echo - nobuild ^(only generate project files^)
echo - showhash ^(Show git hashes of source tree^)
+echo - test ^(Run automated tests with ctest^)
echo - format [path] ^(Format the source using clang-format, path is optional, requires python 3.x to be available^)
echo.
echo Configuration options
diff --git a/build_files/windows/test.cmd b/build_files/windows/test.cmd
new file mode 100644
index 00000000000..cad6b50e8bb
--- /dev/null
+++ b/build_files/windows/test.cmd
@@ -0,0 +1,13 @@
+if EXIST %PYTHON% (
+ goto detect_python_done
+)
+
+echo python not found in lib folder
+exit /b 1
+
+:detect_python_done
+
+REM Use -B to avoid writing __pycache__ in lib directory and causing update conflicts.
+%PYTHON% -B %BLENDER_DIR%\build_files\utils\make_test.py --git-command "%GIT%" --svn-command "%SVN%" --cmake-command="%CMAKE%" --ctest-command="%CTEST%" --config="%BUILD_TYPE%" %BUILD_DIR%
+
+:EOF
diff --git a/build_files/windows/update_sources.cmd b/build_files/windows/update_sources.cmd
index 1f571eaf92d..f8fbd383090 100644
--- a/build_files/windows/update_sources.cmd
+++ b/build_files/windows/update_sources.cmd
@@ -1,18 +1,13 @@
-if "%BUILD_UPDATE_SVN%" == "1" (
- if "%SVN%" == "" (
- echo svn not found, cannot update libraries
- goto UPDATE_GIT
- )
- "%SVN%" up "%BLENDER_DIR%/../lib/*"
+if EXIST %PYTHON% (
+ goto detect_python_done
)
-:UPDATE_GIT
-if "%BUILD_UPDATE_GIT%" == "1" (
- if "%GIT%" == "" (
- echo Git not found, cannot update code
- goto EOF
- )
- "%GIT%" pull --rebase
- "%GIT%" submodule foreach git pull --rebase origin master
-)
+echo python not found in lib folder
+exit /b 1
+
+:detect_python_done
+
+REM Use -B to avoid writing __pycache__ in lib directory and causing update conflicts.
+%PYTHON% -B %BLENDER_DIR%\build_files\utils\make_update.py --git-command "%GIT%" --svn-command "%SVN%" %BUILD_UPDATE_ARGS%
+
:EOF
diff --git a/doc/manpage/blender.1.py b/doc/manpage/blender.1.py
index 4be16c15ec7..fc2200ab859 100755
--- a/doc/manpage/blender.1.py
+++ b/doc/manpage/blender.1.py
@@ -30,11 +30,11 @@ and <output-filename> is where to write the generated man page.
# <pep8 compliant>
+import os
import subprocess
import sys
import time
-import datetime
def man_format(data):
@@ -52,11 +52,18 @@ outfilename = sys.argv[2]
cmd = [blender_bin, "--help"]
print(" executing:", " ".join(cmd))
-blender_help = subprocess.check_output(cmd).decode(encoding="utf-8")
-blender_version = subprocess.check_output([blender_bin, "--version"]).decode(encoding="utf-8").strip()
-blender_version = blender_version.split("build")[0].rstrip()
-blender_version = blender_version.partition(" ")[2] # remove 'Blender' prefix.
-date_string = datetime.date.fromtimestamp(time.time()).strftime("%B %d, %Y")
+blender_help = subprocess.run(
+ cmd, env={"ASAN_OPTIONS": "exitcode=0"}, check=True, stdout=subprocess.PIPE).stdout.decode(encoding="utf-8")
+blender_version = subprocess.run(
+ [blender_bin, "--version"], env={"ASAN_OPTIONS": "exitcode=0"}, check=True, stdout=subprocess.PIPE).stdout.decode(encoding="utf-8").strip()
+blender_version, blender_date = (blender_version.split("build") + [None, None])[0:2]
+blender_version = blender_version.rstrip().partition(" ")[2] # remove 'Blender' prefix.
+if blender_date is None:
+ # Happens when built without WITH_BUILD_INFO e.g.
+ date_string = time.strftime("%B %d, %Y", time.gmtime(int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))))
+else:
+ blender_date = blender_date.strip().partition(" ")[2] # remove 'date:' prefix
+ date_string = time.strftime("%B %d, %Y", time.strptime(blender_date, "%Y-%m-%d"))
outfile = open(outfilename, "w")
fw = outfile.write
@@ -80,7 +87,7 @@ is a full-featured 3D application. It supports the entirety of the 3D pipeline -
Use Blender to create 3D images and animations, films and commercials, content for games, architectural and industrial visualizatons, and scientific visualizations.
-http://www.blender.org''')
+https://www.blender.org''')
fw('''
.SH OPTIONS''')
diff --git a/doc/python_api/examples/bpy.types.Depsgraph.1.py b/doc/python_api/examples/bpy.types.Depsgraph.1.py
index 7425c0db15f..e3f35c53bc5 100644
--- a/doc/python_api/examples/bpy.types.Depsgraph.1.py
+++ b/doc/python_api/examples/bpy.types.Depsgraph.1.py
@@ -35,7 +35,7 @@ class OBJECT_OT_evaluated_example(bpy.types.Operator):
# modifiers.
#
# For mesh objects the object.data will be a mesh with all modifiers applied.
- # This means that in access to vertices or faces after modifier stack happens via fields of
+ # This means that in access to vertices or faces after modifier stack happens via fields of
# object_eval.object.
#
# For other types of objects the object_eval.data does not have modifiers applied on it,
diff --git a/doc/python_api/examples/bpy.types.UIList.2.py b/doc/python_api/examples/bpy.types.UIList.2.py
index 6c2b113932a..5f3ecbf116c 100644
--- a/doc/python_api/examples/bpy.types.UIList.2.py
+++ b/doc/python_api/examples/bpy.types.UIList.2.py
@@ -210,4 +210,3 @@ def unregister():
if __name__ == "__main__":
register()
-
diff --git a/doc/python_api/rst/info_tips_and_tricks.rst b/doc/python_api/rst/info_tips_and_tricks.rst
index 5b6736973ca..5c19e652480 100644
--- a/doc/python_api/rst/info_tips_and_tricks.rst
+++ b/doc/python_api/rst/info_tips_and_tricks.rst
@@ -301,7 +301,7 @@ Advantages include:
This is marked advanced because to run Blender as a Python module requires a special build option.
For instructions on building see
-`Building Blender as a Python module <https://wiki.blender.org/index.php/User:Ideasman42/BlenderAsPyModule>`_
+`Building Blender as a Python module <https://wiki.blender.org/wiki/Building_Blender/Other/BlenderAsPyModule>`_
Python Safety (Build Option)
diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt
index 3b2a8c172aa..0d9010b15ea 100644
--- a/extern/CMakeLists.txt
+++ b/extern/CMakeLists.txt
@@ -105,3 +105,8 @@ if(WITH_AUDASPACE AND NOT WITH_SYSTEM_AUDASPACE)
set(AUDASPACE_CMAKE_CFG ${CMAKE_CURRENT_SOURCE_DIR}/audaspace/blender_config.cmake)
add_subdirectory(audaspace)
endif()
+
+if(WITH_QUADRIFLOW)
+ set(QUADRIFLOW_CMAKE_CFG ${CMAKE_CURRENT_SOURCE_DIR}/quadriflow/blender_config.cmake)
+ add_subdirectory(quadriflow)
+endif()
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/AUTHORS b/extern/quadriflow/3rd/lemon-1.3.1/AUTHORS
new file mode 100644
index 00000000000..4019ca6213a
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/AUTHORS
@@ -0,0 +1,26 @@
+The main developers of release series 1.x are
+
+ * Balazs Dezso <deba@inf.elte.hu>
+ * Alpar Juttner <alpar@cs.elte.hu>
+ * Peter Kovacs <kpeter@inf.elte.hu>
+ * Akos Ladanyi <ladanyi@tmit.bme.hu>
+
+For more complete list of contributors, please visit the history of
+the LEMON source code repository: http://lemon.cs.elte.hu/hg/lemon
+
+Moreover, this version is heavily based on version 0.x of LEMON. Here
+is the list of people who contributed to those versions.
+
+ * Mihaly Barasz <klao@cs.elte.hu>
+ * Johanna Becker <beckerjc@cs.elte.hu>
+ * Attila Bernath <athos@cs.elte.hu>
+ * Balazs Dezso <deba@inf.elte.hu>
+ * Peter Hegyi <hegyi@tmit.bme.hu>
+ * Alpar Juttner <alpar@cs.elte.hu>
+ * Peter Kovacs <kpeter@inf.elte.hu>
+ * Akos Ladanyi <ladanyi@tmit.bme.hu>
+ * Marton Makai <marci@cs.elte.hu>
+ * Jacint Szabo <jacint@cs.elte.hu>
+
+Again, please visit the history of the old LEMON repository for more
+details: http://lemon.cs.elte.hu/hg/lemon-0.x \ No newline at end of file
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/CMakeLists.txt b/extern/quadriflow/3rd/lemon-1.3.1/CMakeLists.txt
new file mode 100644
index 00000000000..7aa6d430906
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/CMakeLists.txt
@@ -0,0 +1,373 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 3.1)
+
+SET(PROJECT_NAME "LEMON")
+PROJECT(${PROJECT_NAME})
+
+INCLUDE(FindPythonInterp)
+INCLUDE(FindWget)
+
+IF(EXISTS ${PROJECT_SOURCE_DIR}/cmake/version.cmake)
+ INCLUDE(${PROJECT_SOURCE_DIR}/cmake/version.cmake)
+ELSEIF(DEFINED ENV{LEMON_VERSION})
+ SET(LEMON_VERSION $ENV{LEMON_VERSION} CACHE STRING "LEMON version string.")
+ELSE()
+ EXECUTE_PROCESS(
+ COMMAND
+ hg log -r. --template "{latesttag}"
+ WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+ OUTPUT_VARIABLE HG_REVISION_TAG
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ EXECUTE_PROCESS(
+ COMMAND
+ hg log -r. --template "{latesttagdistance}"
+ WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+ OUTPUT_VARIABLE HG_REVISION_DIST
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ EXECUTE_PROCESS(
+ COMMAND
+ hg log -r. --template "{node|short}"
+ WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+ OUTPUT_VARIABLE HG_REVISION_ID
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+
+ IF(HG_REVISION_TAG STREQUAL "")
+ SET(HG_REVISION_ID "hg-tip")
+ ELSE()
+ IF(HG_REVISION_TAG STREQUAL "null")
+ SET(HG_REVISION_TAG "trunk")
+ ELSEIF(HG_REVISION_TAG MATCHES "^r")
+ STRING(SUBSTRING ${HG_REVISION_TAG} 1 -1 HG_REVISION_TAG)
+ ENDIF()
+ IF(HG_REVISION_DIST STREQUAL "0")
+ SET(HG_REVISION ${HG_REVISION_TAG})
+ ELSE()
+ SET(HG_REVISION
+ "${HG_REVISION_TAG}+${HG_REVISION_DIST}-${HG_REVISION_ID}")
+ ENDIF()
+ ENDIF()
+
+ SET(LEMON_VERSION ${HG_REVISION} CACHE STRING "LEMON version string.")
+ENDIF()
+
+SET(PROJECT_VERSION ${LEMON_VERSION})
+
+SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
+
+FIND_PACKAGE(Doxygen)
+FIND_PACKAGE(Ghostscript)
+
+SET(LEMON_ENABLE_GLPK YES CACHE STRING "Enable GLPK solver backend.")
+SET(LEMON_ENABLE_ILOG YES CACHE STRING "Enable ILOG (CPLEX) solver backend.")
+SET(LEMON_ENABLE_COIN YES CACHE STRING "Enable COIN solver backend.")
+SET(LEMON_ENABLE_SOPLEX YES CACHE STRING "Enable SoPlex solver backend.")
+
+IF(LEMON_ENABLE_GLPK)
+ FIND_PACKAGE(GLPK 4.33)
+ENDIF(LEMON_ENABLE_GLPK)
+IF(LEMON_ENABLE_ILOG)
+ FIND_PACKAGE(ILOG)
+ENDIF(LEMON_ENABLE_ILOG)
+IF(LEMON_ENABLE_COIN)
+ FIND_PACKAGE(COIN)
+ENDIF(LEMON_ENABLE_COIN)
+IF(LEMON_ENABLE_SOPLEX)
+ FIND_PACKAGE(SOPLEX)
+ENDIF(LEMON_ENABLE_SOPLEX)
+
+IF(GLPK_FOUND)
+ SET(LEMON_HAVE_LP TRUE)
+ SET(LEMON_HAVE_MIP TRUE)
+ SET(LEMON_HAVE_GLPK TRUE)
+ENDIF(GLPK_FOUND)
+IF(ILOG_FOUND)
+ SET(LEMON_HAVE_LP TRUE)
+ SET(LEMON_HAVE_MIP TRUE)
+ SET(LEMON_HAVE_CPLEX TRUE)
+ENDIF(ILOG_FOUND)
+IF(COIN_FOUND)
+ SET(LEMON_HAVE_LP TRUE)
+ SET(LEMON_HAVE_MIP TRUE)
+ SET(LEMON_HAVE_CLP TRUE)
+ SET(LEMON_HAVE_CBC TRUE)
+ENDIF(COIN_FOUND)
+IF(SOPLEX_FOUND)
+ SET(LEMON_HAVE_LP TRUE)
+ SET(LEMON_HAVE_SOPLEX TRUE)
+ENDIF(SOPLEX_FOUND)
+
+IF(ILOG_FOUND)
+ SET(DEFAULT_LP "CPLEX")
+ SET(DEFAULT_MIP "CPLEX")
+ELSEIF(COIN_FOUND)
+ SET(DEFAULT_LP "CLP")
+ SET(DEFAULT_MIP "CBC")
+ELSEIF(GLPK_FOUND)
+ SET(DEFAULT_LP "GLPK")
+ SET(DEFAULT_MIP "GLPK")
+ELSEIF(SOPLEX_FOUND)
+ SET(DEFAULT_LP "SOPLEX")
+ENDIF()
+
+IF(NOT LEMON_DEFAULT_LP OR
+ (NOT ILOG_FOUND AND (LEMON_DEFAULT_LP STREQUAL "CPLEX")) OR
+ (NOT COIN_FOUND AND (LEMON_DEFAULT_LP STREQUAL "CLP")) OR
+ (NOT GLPK_FOUND AND (LEMON_DEFAULT_LP STREQUAL "GLPK")) OR
+ (NOT SOPLEX_FOUND AND (LEMON_DEFAULT_LP STREQUAL "SOPLEX")))
+ SET(LEMON_DEFAULT_LP ${DEFAULT_LP} CACHE STRING
+ "Default LP solver backend (GLPK, CPLEX, CLP or SOPLEX)" FORCE)
+ELSE()
+ SET(LEMON_DEFAULT_LP ${DEFAULT_LP} CACHE STRING
+ "Default LP solver backend (GLPK, CPLEX, CLP or SOPLEX)")
+ENDIF()
+IF(NOT LEMON_DEFAULT_MIP OR
+ (NOT ILOG_FOUND AND (LEMON_DEFAULT_MIP STREQUAL "CPLEX")) OR
+ (NOT COIN_FOUND AND (LEMON_DEFAULT_MIP STREQUAL "CBC")) OR
+ (NOT GLPK_FOUND AND (LEMON_DEFAULT_MIP STREQUAL "GLPK")))
+ SET(LEMON_DEFAULT_MIP ${DEFAULT_MIP} CACHE STRING
+ "Default MIP solver backend (GLPK, CPLEX or CBC)" FORCE)
+ELSE()
+ SET(LEMON_DEFAULT_MIP ${DEFAULT_MIP} CACHE STRING
+ "Default MIP solver backend (GLPK, CPLEX or CBC)")
+ENDIF()
+
+
+IF(DEFINED ENV{LEMON_CXX_WARNING})
+ SET(CXX_WARNING $ENV{LEMON_CXX_WARNING})
+ELSE()
+ IF(CMAKE_COMPILER_IS_GNUCXX)
+ SET(CXX_WARNING "-Wall -W -Wunused -Wformat=2 -Wctor-dtor-privacy -Wnon-virtual-dtor -Wno-char-subscripts -Wwrite-strings -Wno-char-subscripts -Wreturn-type -Wcast-qual -Wcast-align -Wsign-promo -Woverloaded-virtual -fno-strict-aliasing -Wold-style-cast -Wno-unknown-pragmas")
+ SET(CMAKE_CXX_FLAGS_DEBUG CACHE STRING "-ggdb")
+ SET(CMAKE_C_FLAGS_DEBUG CACHE STRING "-ggdb")
+ ELSEIF(MSVC)
+ # This part is unnecessary 'casue the same is set by the lemon/core.h.
+ # Still keep it as an example.
+ SET(CXX_WARNING "/wd4250 /wd4355 /wd4503 /wd4800 /wd4996")
+ # Suppressed warnings:
+ # C4250: 'class1' : inherits 'class2::member' via dominance
+ # C4355: 'this' : used in base member initializer list
+ # C4503: 'function' : decorated name length exceeded, name was truncated
+ # C4800: 'type' : forcing value to bool 'true' or 'false'
+ # (performance warning)
+ # C4996: 'function': was declared deprecated
+ ELSE()
+ SET(CXX_WARNING "-Wall")
+ ENDIF()
+ENDIF()
+SET(LEMON_CXX_WARNING_FLAGS ${CXX_WARNING} CACHE STRING "LEMON warning flags.")
+
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LEMON_CXX_WARNING_FLAGS}")
+
+IF(MSVC)
+ SET( CMAKE_CXX_FLAGS_MAINTAINER "/WX ${CMAKE_CXX_FLAGS_DEBUG}" CACHE STRING
+ "Flags used by the C++ compiler during maintainer builds."
+ )
+ SET( CMAKE_C_FLAGS_MAINTAINER "/WX ${CMAKE_CXX_FLAGS_DEBUG}" CACHE STRING
+ "Flags used by the C compiler during maintainer builds."
+ )
+ SET( CMAKE_EXE_LINKER_FLAGS_MAINTAINER
+ "${CMAKE_EXE_LINKER_FLAGS_DEBUG}" CACHE STRING
+ "Flags used for linking binaries during maintainer builds."
+ )
+ SET( CMAKE_SHARED_LINKER_FLAGS_MAINTAINER
+ "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}" CACHE STRING
+ "Flags used by the shared libraries linker during maintainer builds."
+ )
+ELSE()
+ SET( CMAKE_CXX_FLAGS_MAINTAINER "-Werror -ggdb -O0" CACHE STRING
+ "Flags used by the C++ compiler during maintainer builds."
+ )
+ SET( CMAKE_C_FLAGS_MAINTAINER "-Werror -O0" CACHE STRING
+ "Flags used by the C compiler during maintainer builds."
+ )
+ SET( CMAKE_EXE_LINKER_FLAGS_MAINTAINER
+ "${CMAKE_EXE_LINKER_FLAGS_DEBUG}" CACHE STRING
+ "Flags used for linking binaries during maintainer builds."
+ )
+ SET( CMAKE_SHARED_LINKER_FLAGS_MAINTAINER
+ "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}" CACHE STRING
+ "Flags used by the shared libraries linker during maintainer builds."
+ )
+ENDIF()
+
+MARK_AS_ADVANCED(
+ CMAKE_CXX_FLAGS_MAINTAINER
+ CMAKE_C_FLAGS_MAINTAINER
+ CMAKE_EXE_LINKER_FLAGS_MAINTAINER
+ CMAKE_SHARED_LINKER_FLAGS_MAINTAINER )
+
+IF(CMAKE_CONFIGURATION_TYPES)
+ LIST(APPEND CMAKE_CONFIGURATION_TYPES Maintainer)
+ LIST(REMOVE_DUPLICATES CMAKE_CONFIGURATION_TYPES)
+ SET(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" CACHE STRING
+ "Add the configurations that we need"
+ FORCE)
+ endif()
+
+IF(NOT CMAKE_BUILD_TYPE)
+ SET(CMAKE_BUILD_TYPE "Release")
+ENDIF()
+
+SET( CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING
+ "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel Maintainer."
+ FORCE )
+
+
+INCLUDE(CheckTypeSize)
+CHECK_TYPE_SIZE("long long" LONG_LONG)
+SET(LEMON_HAVE_LONG_LONG ${HAVE_LONG_LONG})
+
+INCLUDE(FindThreads)
+
+IF(NOT LEMON_THREADING)
+ IF(CMAKE_USE_PTHREADS_INIT)
+ SET(LEMON_THREADING "Pthread")
+ ELSEIF(CMAKE_USE_WIN32_THREADS_INIT)
+ SET(LEMON_THREADING "Win32")
+ ELSE()
+ SET(LEMON_THREADING "None")
+ ENDIF()
+ENDIF()
+
+SET( LEMON_THREADING "${LEMON_THREADING}" CACHE STRING
+ "Choose the threading library, options are: Pthread Win32 None."
+ FORCE )
+
+IF(LEMON_THREADING STREQUAL "Pthread")
+ SET(LEMON_USE_PTHREAD TRUE)
+ELSEIF(LEMON_THREADING STREQUAL "Win32")
+ SET(LEMON_USE_WIN32_THREADS TRUE)
+ENDIF()
+
+ENABLE_TESTING()
+
+IF(${CMAKE_BUILD_TYPE} STREQUAL "Maintainer")
+ ADD_CUSTOM_TARGET(check ALL COMMAND ${CMAKE_CTEST_COMMAND})
+ELSE()
+ ADD_CUSTOM_TARGET(check COMMAND ${CMAKE_CTEST_COMMAND})
+ENDIF()
+
+ADD_SUBDIRECTORY(lemon)
+IF(${CMAKE_SOURCE_DIR} STREQUAL ${PROJECT_SOURCE_DIR})
+ ADD_SUBDIRECTORY(contrib)
+ ADD_SUBDIRECTORY(demo)
+ ADD_SUBDIRECTORY(tools)
+ ADD_SUBDIRECTORY(doc)
+ ADD_SUBDIRECTORY(test)
+ENDIF()
+
+CONFIGURE_FILE(
+ ${PROJECT_SOURCE_DIR}/cmake/LEMONConfig.cmake.in
+ ${PROJECT_BINARY_DIR}/cmake/LEMONConfig.cmake
+ @ONLY
+)
+IF(UNIX)
+ INSTALL(
+ FILES ${PROJECT_BINARY_DIR}/cmake/LEMONConfig.cmake
+ DESTINATION share/lemon/cmake
+ )
+ELSEIF(WIN32)
+ INSTALL(
+ FILES ${PROJECT_BINARY_DIR}/cmake/LEMONConfig.cmake
+ DESTINATION cmake
+ )
+ENDIF()
+
+CONFIGURE_FILE(
+ ${PROJECT_SOURCE_DIR}/cmake/version.cmake.in
+ ${PROJECT_BINARY_DIR}/cmake/version.cmake
+ @ONLY
+)
+
+SET(ARCHIVE_BASE_NAME ${CMAKE_PROJECT_NAME})
+STRING(TOLOWER ${ARCHIVE_BASE_NAME} ARCHIVE_BASE_NAME)
+SET(ARCHIVE_NAME ${ARCHIVE_BASE_NAME}-${PROJECT_VERSION})
+ADD_CUSTOM_TARGET(dist
+ COMMAND cmake -E remove_directory ${ARCHIVE_NAME}
+ COMMAND hg archive ${ARCHIVE_NAME}
+ COMMAND cmake -E copy cmake/version.cmake ${ARCHIVE_NAME}/cmake/version.cmake
+ COMMAND tar -czf ${ARCHIVE_BASE_NAME}-nodoc-${PROJECT_VERSION}.tar.gz ${ARCHIVE_NAME}
+ COMMAND zip -r ${ARCHIVE_BASE_NAME}-nodoc-${PROJECT_VERSION}.zip ${ARCHIVE_NAME}
+ COMMAND cmake -E copy_directory doc/html ${ARCHIVE_NAME}/doc/html
+ COMMAND tar -czf ${ARCHIVE_NAME}.tar.gz ${ARCHIVE_NAME}
+ COMMAND zip -r ${ARCHIVE_NAME}.zip ${ARCHIVE_NAME}
+ COMMAND cmake -E copy_directory doc/html ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION}
+ COMMAND tar -czf ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION}.tar.gz ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION}
+ COMMAND zip -r ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION}.zip ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION}
+ COMMAND cmake -E remove_directory ${ARCHIVE_NAME}
+ COMMAND cmake -E remove_directory ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION}
+ DEPENDS html
+ WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
+
+# CPACK config (Basically for NSIS)
+IF(${CMAKE_SOURCE_DIR} STREQUAL ${PROJECT_SOURCE_DIR})
+ SET(CPACK_PACKAGE_NAME ${PROJECT_NAME})
+ SET(CPACK_PACKAGE_VENDOR "EGRES")
+ SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY
+ "LEMON - Library for Efficient Modeling and Optimization in Networks")
+ SET(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
+
+ SET(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
+
+ SET(CPACK_PACKAGE_INSTALL_DIRECTORY
+ "${PROJECT_NAME} ${PROJECT_VERSION}")
+ SET(CPACK_PACKAGE_INSTALL_REGISTRY_KEY
+ "${PROJECT_NAME} ${PROJECT_VERSION}")
+
+ SET(CPACK_COMPONENTS_ALL headers library html_documentation bin)
+
+ SET(CPACK_COMPONENT_HEADERS_DISPLAY_NAME "C++ headers")
+ SET(CPACK_COMPONENT_LIBRARY_DISPLAY_NAME "Dynamic-link library")
+ SET(CPACK_COMPONENT_BIN_DISPLAY_NAME "Command line utilities")
+ SET(CPACK_COMPONENT_HTML_DOCUMENTATION_DISPLAY_NAME "HTML documentation")
+
+ SET(CPACK_COMPONENT_HEADERS_DESCRIPTION
+ "C++ header files")
+ SET(CPACK_COMPONENT_LIBRARY_DESCRIPTION
+ "DLL and import library")
+ SET(CPACK_COMPONENT_BIN_DESCRIPTION
+ "Command line utilities")
+ SET(CPACK_COMPONENT_HTML_DOCUMENTATION_DESCRIPTION
+ "Doxygen generated documentation")
+
+ SET(CPACK_COMPONENT_HEADERS_DEPENDS library)
+
+ SET(CPACK_COMPONENT_HEADERS_GROUP "Development")
+ SET(CPACK_COMPONENT_LIBRARY_GROUP "Development")
+ SET(CPACK_COMPONENT_HTML_DOCUMENTATION_GROUP "Documentation")
+
+ SET(CPACK_COMPONENT_GROUP_DEVELOPMENT_DESCRIPTION
+ "Components needed to develop software using LEMON")
+ SET(CPACK_COMPONENT_GROUP_DOCUMENTATION_DESCRIPTION
+ "Documentation of LEMON")
+
+ SET(CPACK_ALL_INSTALL_TYPES Full Developer)
+
+ SET(CPACK_COMPONENT_HEADERS_INSTALL_TYPES Developer Full)
+ SET(CPACK_COMPONENT_LIBRARY_INSTALL_TYPES Developer Full)
+ SET(CPACK_COMPONENT_HTML_DOCUMENTATION_INSTALL_TYPES Full)
+
+ SET(CPACK_GENERATOR "NSIS")
+ SET(CPACK_NSIS_MUI_ICON "${PROJECT_SOURCE_DIR}/cmake/nsis/lemon.ico")
+ SET(CPACK_NSIS_MUI_UNIICON "${PROJECT_SOURCE_DIR}/cmake/nsis/uninstall.ico")
+ #SET(CPACK_PACKAGE_ICON "${PROJECT_SOURCE_DIR}/cmake/nsis\\\\installer.bmp")
+ SET(CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\lemon.ico")
+ SET(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} ${PROJECT_NAME}")
+ SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\lemon.cs.elte.hu")
+ SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\lemon.cs.elte.hu")
+ SET(CPACK_NSIS_CONTACT "lemon-user@lemon.cs.elte.hu")
+ SET(CPACK_NSIS_CREATE_ICONS_EXTRA "
+ CreateShortCut \\\"$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Documentation.lnk\\\" \\\"$INSTDIR\\\\share\\\\doc\\\\index.html\\\"
+ ")
+ SET(CPACK_NSIS_DELETE_ICONS_EXTRA "
+ !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP
+ Delete \\\"$SMPROGRAMS\\\\$MUI_TEMP\\\\Documentation.lnk\\\"
+ ")
+
+ INCLUDE(CPack)
+ENDIF()
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/INSTALL b/extern/quadriflow/3rd/lemon-1.3.1/INSTALL
new file mode 100644
index 00000000000..3fba5b263f7
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/INSTALL
@@ -0,0 +1,167 @@
+Installation Instructions
+=========================
+
+This file contains instructions for building and installing LEMON from
+source on Linux. The process on Windows is similar.
+
+Note that it is not necessary to install LEMON in order to use
+it. Instead, you can easily integrate it with your own code
+directly. For instructions, see
+https://lemon.cs.elte.hu/trac/lemon/wiki/HowToCompile
+
+
+In order to install LEMON from the extracted source tarball you have to
+issue the following commands:
+
+ 1. Step into the root of the source directory.
+
+ $ cd lemon-x.y.z
+
+ 2. Create a build subdirectory and step into it.
+
+ $ mkdir build
+ $ cd build
+
+ 3. Perform system checks and create the makefiles.
+
+ $ cmake ..
+
+ 4. Build LEMON.
+
+ $ make
+
+ This command compiles the non-template part of LEMON into
+ libemon.a file. It also compiles the programs in the 'tools' and
+ 'demo' subdirectories.
+
+ 5. [Optional] Compile and run the self-tests.
+
+ $ make check
+
+ 5. [Optional] Generate the user documentation.
+
+ $ make html
+
+ The release tarballs already include the documentation.
+
+ Note that for this step you need to have the following tools
+ installed: Python, Doxygen, Graphviz, Ghostscript, LaTeX.
+
+ 6. [Optional] Install LEMON
+
+ $ make install
+
+ This command installs LEMON under /usr/local (you will need root
+ privileges to be able to do that). If you want to install it to
+ some other location, then pass the
+ -DCMAKE_INSTALL_PREFIX=DIRECTORY flag to cmake in Step 3.
+ For example:
+
+ $ cmake -DCMAKE_INSTALL_PREFIX=/home/username/lemon'
+
+Configure Options and Variables
+===============================
+
+In Step 3, you can customize the build process by passing options to CMAKE.
+
+$ cmake [OPTIONS] ..
+
+You find a list of the most useful options below.
+
+-DCMAKE_INSTALL_PREFIX=PREFIX
+
+ Set the installation prefix to PREFIX. By default it is /usr/local.
+
+-DCMAKE_BUILD_TYPE=[Release|Debug|Maintainer|...]
+
+ This sets the compiler options. The choices are the following
+
+ 'Release': A strong optimization is turned on (-O3 with gcc). This
+ is the default setting and we strongly recommend using this for
+ the final compilation.
+
+ 'Debug': Optimization is turned off and debug info is added (-O0
+ -ggdb with gcc). If is recommended during the development.
+
+ 'Maintainer': The same as 'Debug' but the compiler warnings are
+ converted to errors (-Werror with gcc). In addition, 'make' will
+ also automatically compile and execute the test codes. It is the
+ best way of ensuring that LEMON codebase is clean and safe.
+
+ 'RelWithDebInfo': Optimized build with debug info.
+
+ 'MinSizeRel': Size optimized build (-Os with gcc)
+
+-DTEST_WITH_VALGRIND=YES
+
+ Using this, the test codes will be executed using valgrind. It is a
+ very effective way of identifying indexing problems and memory leaks.
+
+-DCMAKE_CXX_COMPILER=path-to-compiler
+
+ Change the compiler to be used.
+
+-DBUILD_SHARED_LIBS=TRUE
+
+ Build shared library instead of static one. Think twice if you
+ really want to use this option.
+
+-DLEMON_DOC_SOURCE_BROWSER=YES
+
+ Include the browsable cross referenced LEMON source code into the
+ doc. It makes the doc quite bloated, but may be useful for
+ developing LEMON itself.
+
+-DLEMON_DOC_USE_MATHJAX=YES
+
+ Use MathJax (http://mathjax.org) for rendering the math formulae in
+ the doc. It of much higher quality compared to the default LaTeX
+ generated static images and it allows copy&paste of the formulae to
+ LaTeX, Open Office, MS Word etc. documents.
+
+ On the other hand, it needs either Internet access or a locally
+ installed version of MathJax to properly render the doc.
+
+-DLEMON_DOC_MATHJAX_RELPATH=DIRECTORY
+
+ The location of the MathJax library. It defaults to
+ http://www.mathjax.org/mathjax, which necessitates Internet access
+ for proper rendering. The easiest way to make it usable offline is
+ to set this parameter to 'mathjax' and copy all files of the MathJax
+ library into the 'doc/html/mathjax' subdirectory of the build
+ location.
+
+ See http://docs.mathjax.org/en/latest/installation.html for more details.
+
+
+-DLEMON_ENABLE_GLPK=NO
+-DLEMON_ENABLE_COIN=NO
+-DLEMON_ENABLE_ILOG=NO
+
+ Enable optional third party libraries. They are all enabled by default.
+
+-DLEMON_DEFAULT_LP=GLPK
+
+ Sets the default LP solver backend. The supported values are
+ CPLEX, CLP and GLPK. By default, it is set to the first one which
+ is enabled and succesfully discovered.
+
+-DLEMON_DEFAULT_MIP=GLPK
+
+ Sets the default MIP solver backend. The supported values are
+ CPLEX, CBC and GLPK. By default, it is set to the first one which
+ is enabled and succesfully discovered.
+
+-DGLPK_ROOT_DIR=DIRECTORY
+-DCOIN_ROOT_DIR=DIRECTORY
+-DILOG_ROOT_DIR=DIRECTORY
+
+ Root directory prefixes of optional third party libraries.
+
+Makefile Variables
+==================
+
+make VERBOSE=1
+
+ This results in a more verbose output by showing the full
+ compiler and linker commands. \ No newline at end of file
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/LICENSE b/extern/quadriflow/3rd/lemon-1.3.1/LICENSE
new file mode 100644
index 00000000000..5b1c4255062
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/LICENSE
@@ -0,0 +1,32 @@
+LEMON code without an explicit copyright notice is covered by the following
+copyright/license.
+
+Copyright (C) 2003-2012 Egervary Jeno Kombinatorikus Optimalizalasi
+Kutatocsoport (Egervary Combinatorial Optimization Research Group,
+EGRES).
+
+===========================================================================
+Boost Software License, Version 1.0
+===========================================================================
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/NEWS b/extern/quadriflow/3rd/lemon-1.3.1/NEWS
new file mode 100644
index 00000000000..7908ca3a455
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/NEWS
@@ -0,0 +1,337 @@
+2014-07-07 Version 1.3.1 released
+
+ Bugfix release.
+
+ #484: Require CMAKE 2.8
+ #471, #472, #480: Various clang compatibility fixes
+ #481, #482: Fix shared lib build and versioning
+ #476: Fix invalid map query in NearestNeighborTsp
+ #478: Bugfix in debug checking and lower bound handling
+ in min cost flow algorithms
+ #479, #465: Bugfix in default LP/MIP backend settings
+ #476: Bugfix in tsp_test
+ #487: Add missing include header and std:: namespace spec.
+ #474: Fix division by zero error in NetworkSimplex
+
+2013-08-10 Version 1.3 released
+
+ This is major feature release
+
+ * New data structures
+
+ #69 : Bipartite graph concepts and implementations
+
+ * New algorithms
+
+ #177: Port Edmonds-Karp algorithm
+ #380, #405: Heuristic algorithm for the max clique problem
+ #386: Heuristic algorithms for symmetric TSP
+ ----: Nagamochi-Ibaraki algorithm [5087694945e4]
+ #397, #56: Max. cardinality search
+
+ * Other new features
+
+ #223: Thread safe graph and graph map implementations
+ #442: Different TimeStamp print formats
+ #457: File export functionality to LpBase
+ #362: Bidirectional iterator support for radixSort()
+
+ * Implementation improvements
+
+ ----: Network Simplex
+ #391: Better update process, pivot rule and arc mixing
+ #435: Improved Altering List pivot rule
+ #417: Various fine tunings in CostScaling
+ #438: Optional iteration limit in HowardMmc
+ #436: Ensure strongly polynomial running time for CycleCanceling
+ while keeping the same performance
+ ----: Make the CBC interface be compatible with latest CBC releases
+ [ee581a0ecfbf]
+
+ * CMAKE has become the default build environment (#434)
+
+ ----: Autotool support has been dropped
+ ----: Improved LP/MIP configuration
+ #465: Enable/disable options for LP/MIP backends
+ #446: Better CPLEX discovery
+ #460: Add cmake config to find SoPlex
+ ----: Allow CPACK configuration on all platforms
+ #390: Add 'Maintainer' CMAKE build type
+ #388: Add 'check' target.
+ #401: Add contrib dir
+ #389: Better version string setting in CMAKE
+ #433: Support shared library build
+ #416: Support testing with valgrind
+
+ * Doc improvements
+
+ #395: SOURCE_BROWSER Doxygen switch is configurable from CMAKE
+ update-external-tags CMAKE target
+ #455: Optionally use MathJax for rendering the math formulae
+ #402, #437, #459, #456, #463: Various doc improvements
+
+ * Bugfixes (compared to release 1.2):
+
+ #432: Add missing doc/template.h and doc/references.bib to release
+ tarball
+ ----: Intel C++ compatibility fixes
+ #441: Fix buggy reinitialization in _solver_bits::VarIndex::clear()
+ #444: Bugfix in path copy constructors and assignment operators
+ #447: Bugfix in AllArcLookUp<>
+ #448: Bugfix in adaptor_test.cc
+ #449: Fix clang compilation warnings and errors
+ #440: Fix a bug + remove redundant typedefs in dimacs-solver
+ #453: Avoid GCC 4.7 compiler warnings
+ #445: Fix missing initialization in CplexEnv::CplexEnv()
+ #428: Add missing lemon/lemon.pc.cmake to the release tarball
+ #393: Create and install lemon.pc
+ #429: Fix VS warnings
+ #430: Fix LpBase::Constr two-side limit bug
+ #392: Bug fix in Dfs::start(s,t)
+ #414: Fix wrong initialization in Preflow
+ #418: Better Win CodeBlock/MinGW support
+ #419: Build environment improvements
+ - Build of mip_test and lp_test precede the running of the tests
+ - Also search for coin libs under ${COIN_ROOT_DIR}/lib/coin
+ - Do not look for COIN_VOL libraries
+ #382: Allow lgf file without Arc maps
+ #417: Bug fix in CostScaling
+ #366: Fix Pred[Matrix]MapPath::empty()
+ #371: Bug fix in (di)graphCopy()
+ The target graph is cleared before adding nodes and arcs/edges.
+ #364: Add missing UndirectedTags
+ #368: Fix the usage of std::numeric_limits<>::min() in Network Simplex
+ #372: Fix a critical bug in preflow
+ #461: Bugfix in assert.h
+ #470: Fix compilation issues related to various gcc versions
+ #446: Fix #define indicating CPLEX availability
+ #294: Add explicit namespace to
+ ignore_unused_variable_warning() usages
+ #420: Bugfix in IterableValueMap
+ #439: Bugfix in biNodeConnected()
+
+
+2010-03-19 Version 1.2 released
+
+ This is major feature release
+
+ * New algorithms
+ * Bellman-Ford algorithm (#51)
+ * Minimum mean cycle algorithms (#179)
+ * Karp, Hartman-Orlin and Howard algorithms
+ * New minimum cost flow algorithms (#180)
+ * Cost Scaling algorithms
+ * Capacity Scaling algorithm
+ * Cycle-Canceling algorithms
+ * Planarity related algorithms (#62)
+ * Planarity checking algorithm
+ * Planar embedding algorithm
+ * Schnyder's planar drawing algorithm
+ * Coloring planar graphs with five or six colors
+ * Fractional matching algorithms (#314)
+ * New data structures
+ * StaticDigraph structure (#68)
+ * Several new priority queue structures (#50, #301)
+ * Fibonacci, Radix, Bucket, Pairing, Binomial
+ D-ary and fourary heaps (#301)
+ * Iterable map structures (#73)
+ * Other new tools and functionality
+ * Map utility functions (#320)
+ * Reserve functions are added to ListGraph and SmartGraph (#311)
+ * A resize() function is added to HypercubeGraph (#311)
+ * A count() function is added to CrossRefMap (#302)
+ * Support for multiple targets in Suurballe using fullInit() (#181)
+ * Traits class and named parameters for Suurballe (#323)
+ * Separate reset() and resetParams() functions in NetworkSimplex
+ to handle graph changes (#327)
+ * tolerance() functions are added to HaoOrlin (#306)
+ * Implementation improvements
+ * Improvements in weighted matching algorithms (#314)
+ * Jumpstart initialization
+ * ArcIt iteration is based on out-arc lists instead of in-arc lists
+ in ListDigraph (#311)
+ * Faster add row operation in CbcMip (#203)
+ * Better implementation for split() in ListDigraph (#311)
+ * ArgParser can also throw exception instead of exit(1) (#332)
+ * Miscellaneous
+ * A simple interactive bootstrap script
+ * Doc improvements (#62,#180,#299,#302,#303,#304,#307,#311,#331,#315,
+ #316,#319)
+ * BibTeX references in the doc (#184)
+ * Optionally use valgrind when running tests
+ * Also check ReferenceMapTag in concept checks (#312)
+ * dimacs-solver uses long long type by default.
+ * Several bugfixes (compared to release 1.1):
+ #295: Suppress MSVC warnings using pragmas
+ ----: Various CMAKE related improvements
+ * Remove duplications from doc/CMakeLists.txt
+ * Rename documentation install folder from 'docs' to 'html'
+ * Add tools/CMakeLists.txt to the tarball
+ * Generate and install LEMONConfig.cmake
+ * Change the label of the html project in Visual Studio
+ * Fix the check for the 'long long' type
+ * Put the version string into config.h
+ * Minor CMake improvements
+ * Set the version to 'hg-tip' if everything fails
+ #311: Add missing 'explicit' keywords
+ #302: Fix the implementation and doc of CrossRefMap
+ #308: Remove duplicate list_graph.h entry from source list
+ #307: Bugfix in Preflow and Circulation
+ #305: Bugfix and extension in the rename script
+ #312: Also check ReferenceMapTag in concept checks
+ #250: Bugfix in pathSource() and pathTarget()
+ #321: Use pathCopy(from,to) instead of copyPath(to,from)
+ #322: Distribure LEMONConfig.cmake.in
+ #330: Bug fix in map_extender.h
+ #336: Fix the date field comment of graphToEps() output
+ #323: Bug fix in Suurballe
+ #335: Fix clear() function in ExtendFindEnum
+ #337: Use void* as the LPX object pointer
+ #317: Fix (and improve) error message in mip_test.cc
+ Remove unnecessary OsiCbc dependency
+ #356: Allow multiple executions of weighted matching algorithms (#356)
+
+2009-05-13 Version 1.1 released
+
+ This is the second stable release of the 1.x series. It
+ features a better coverage of the tools available in the 0.x
+ series, a thoroughly reworked LP/MIP interface plus various
+ improvements in the existing tools.
+
+ * Much improved M$ Windows support
+ * Various improvements in the CMAKE build system
+ * Compilation warnings are fixed/suppressed
+ * Support IBM xlC compiler
+ * New algorithms
+ * Connectivity related algorithms (#61)
+ * Euler walks (#65)
+ * Preflow push-relabel max. flow algorithm (#176)
+ * Circulation algorithm (push-relabel based) (#175)
+ * Suurballe algorithm (#47)
+ * Gomory-Hu algorithm (#66)
+ * Hao-Orlin algorithm (#58)
+ * Edmond's maximum cardinality and weighted matching algorithms
+ in general graphs (#48,#265)
+ * Minimum cost arborescence/branching (#60)
+ * Network Simplex min. cost flow algorithm (#234)
+ * New data structures
+ * Full graph structure (#57)
+ * Grid graph structure (#57)
+ * Hypercube graph structure (#57)
+ * Graph adaptors (#67)
+ * ArcSet and EdgeSet classes (#67)
+ * Elevator class (#174)
+ * Other new tools
+ * LP/MIP interface (#44)
+ * Support for GLPK, CPLEX, Soplex, COIN-OR CLP and CBC
+ * Reader for the Nauty file format (#55)
+ * DIMACS readers (#167)
+ * Radix sort algorithms (#72)
+ * RangeIdMap and CrossRefMap (#160)
+ * New command line tools
+ * DIMACS to LGF converter (#182)
+ * lgf-gen - a graph generator (#45)
+ * DIMACS solver utility (#226)
+ * Other code improvements
+ * Lognormal distribution added to Random (#102)
+ * Better (i.e. O(1) time) item counting in SmartGraph (#3)
+ * The standard maps of graphs are guaranteed to be
+ reference maps (#190)
+ * Miscellaneous
+ * Various doc improvements
+ * Improved 0.x -> 1.x converter script
+
+ * Several bugfixes (compared to release 1.0):
+ #170: Bugfix SmartDigraph::split()
+ #171: Bugfix in SmartGraph::restoreSnapshot()
+ #172: Extended test cases for graphs and digraphs
+ #173: Bugfix in Random
+ * operator()s always return a double now
+ * the faulty real<Num>(Num) and real<Num>(Num,Num)
+ have been removed
+ #187: Remove DijkstraWidestPathOperationTraits
+ #61: Bugfix in DfsVisit
+ #193: Bugfix in GraphReader::skipSection()
+ #195: Bugfix in ConEdgeIt()
+ #197: Bugfix in heap unionfind
+ * This bug affects Edmond's general matching algorithms
+ #207: Fix 'make install' without 'make html' using CMAKE
+ #208: Suppress or fix VS2008 compilation warnings
+ ----: Update the LEMON icon
+ ----: Enable the component-based installer
+ (in installers made by CPACK)
+ ----: Set the proper version for CMAKE in the tarballs
+ (made by autotools)
+ ----: Minor clarification in the LICENSE file
+ ----: Add missing unistd.h include to time_measure.h
+ #204: Compilation bug fixed in graph_to_eps.h with VS2005
+ #214,#215: windows.h should never be included by LEMON headers
+ #230: Build systems check the availability of 'long long' type
+ #229: Default implementation of Tolerance<> is used for integer types
+ #211,#212: Various fixes for compiling on AIX
+ ----: Improvements in CMAKE config
+ - docs is installed in share/doc/
+ - detects newer versions of Ghostscript
+ #239: Fix missing 'inline' specifier in time_measure.h
+ #274,#280: Install lemon/config.h
+ #275: Prefix macro names with LEMON_ in lemon/config.h
+ ----: Small script for making the release tarballs added
+ ----: Minor improvement in unify-sources.sh (a76f55d7d397)
+
+2009-03-27 LEMON joins to the COIN-OR initiative
+
+ COIN-OR (Computational Infrastructure for Operations Research,
+ http://www.coin-or.org) project is an initiative to spur the
+ development of open-source software for the operations research
+ community.
+
+2008-10-13 Version 1.0 released
+
+ This is the first stable release of LEMON. Compared to the 0.x
+ release series, it features a considerably smaller but more
+ matured set of tools. The API has also completely revised and
+ changed in several places.
+
+ * The major name changes compared to the 0.x series (see the
+ Migration Guide in the doc for more details)
+ * Graph -> Digraph, UGraph -> Graph
+ * Edge -> Arc, UEdge -> Edge
+ * source(UEdge)/target(UEdge) -> u(Edge)/v(Edge)
+ * Other improvements
+ * Better documentation
+ * Reviewed and cleaned up codebase
+ * CMake based build system (along with the autotools based one)
+ * Contents of the library (ported from 0.x)
+ * Algorithms
+ * breadth-first search (bfs.h)
+ * depth-first search (dfs.h)
+ * Dijkstra's algorithm (dijkstra.h)
+ * Kruskal's algorithm (kruskal.h)
+ * Data structures
+ * graph data structures (list_graph.h, smart_graph.h)
+ * path data structures (path.h)
+ * binary heap data structure (bin_heap.h)
+ * union-find data structures (unionfind.h)
+ * miscellaneous property maps (maps.h)
+ * two dimensional vector and bounding box (dim2.h)
+ * Concepts
+ * graph structure concepts (concepts/digraph.h, concepts/graph.h,
+ concepts/graph_components.h)
+ * concepts for other structures (concepts/heap.h, concepts/maps.h,
+ concepts/path.h)
+ * Tools
+ * Mersenne twister random number generator (random.h)
+ * tools for measuring cpu and wall clock time (time_measure.h)
+ * tools for counting steps and events (counter.h)
+ * tool for parsing command line arguments (arg_parser.h)
+ * tool for visualizing graphs (graph_to_eps.h)
+ * tools for reading and writing data in LEMON Graph Format
+ (lgf_reader.h, lgf_writer.h)
+ * tools to handle the anomalies of calculations with
+ floating point numbers (tolerance.h)
+ * tools to manage RGB colors (color.h)
+ * Infrastructure
+ * extended assertion handling (assert.h)
+ * exception classes and error handling (error.h)
+ * concept checking (concept_check.h)
+ * commonly used mathematical constants (math.h)
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/README b/extern/quadriflow/3rd/lemon-1.3.1/README
new file mode 100644
index 00000000000..52a768c3911
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/README
@@ -0,0 +1,50 @@
+=====================================================================
+LEMON - a Library for Efficient Modeling and Optimization in Networks
+=====================================================================
+
+LEMON is an open source library written in C++. It provides
+easy-to-use implementations of common data structures and algorithms
+in the area of optimization and helps implementing new ones. The main
+focus is on graphs and graph algorithms, thus it is especially
+suitable for solving design and optimization problems of
+telecommunication networks. To achieve wide usability its data
+structures and algorithms provide generic interfaces.
+
+Contents
+========
+
+LICENSE
+
+ Copying, distribution and modification conditions and terms.
+
+NEWS
+
+ News and version history.
+
+INSTALL
+
+ General building and installation instructions.
+
+lemon/
+
+ Source code of LEMON library.
+
+doc/
+
+ Documentation of LEMON. The starting page is doc/html/index.html.
+
+demo/
+
+ Some example programs to make you easier to get familiar with LEMON.
+
+scripts/
+
+ Scripts that make it easier to develop LEMON.
+
+test/
+
+ Programs to check the integrity and correctness of LEMON.
+
+tools/
+
+ Various utilities related to LEMON.
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindCOIN.cmake b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindCOIN.cmake
new file mode 100644
index 00000000000..d4ed735df94
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindCOIN.cmake
@@ -0,0 +1,110 @@
+SET(COIN_ROOT_DIR "" CACHE PATH "COIN root directory")
+
+FIND_PATH(COIN_INCLUDE_DIR coin/CoinUtilsConfig.h
+ HINTS ${COIN_ROOT_DIR}/include
+)
+FIND_LIBRARY(COIN_CBC_LIBRARY
+ NAMES Cbc libCbc
+ HINTS ${COIN_ROOT_DIR}/lib/coin
+ HINTS ${COIN_ROOT_DIR}/lib
+)
+FIND_LIBRARY(COIN_CBC_SOLVER_LIBRARY
+ NAMES CbcSolver libCbcSolver
+ HINTS ${COIN_ROOT_DIR}/lib/coin
+ HINTS ${COIN_ROOT_DIR}/lib
+)
+FIND_LIBRARY(COIN_CGL_LIBRARY
+ NAMES Cgl libCgl
+ HINTS ${COIN_ROOT_DIR}/lib/coin
+ HINTS ${COIN_ROOT_DIR}/lib
+)
+FIND_LIBRARY(COIN_CLP_LIBRARY
+ NAMES Clp libClp
+ HINTS ${COIN_ROOT_DIR}/lib/coin
+ HINTS ${COIN_ROOT_DIR}/lib
+)
+FIND_LIBRARY(COIN_COIN_UTILS_LIBRARY
+ NAMES CoinUtils libCoinUtils
+ HINTS ${COIN_ROOT_DIR}/lib/coin
+ HINTS ${COIN_ROOT_DIR}/lib
+)
+FIND_LIBRARY(COIN_OSI_LIBRARY
+ NAMES Osi libOsi
+ HINTS ${COIN_ROOT_DIR}/lib/coin
+ HINTS ${COIN_ROOT_DIR}/lib
+)
+FIND_LIBRARY(COIN_OSI_CBC_LIBRARY
+ NAMES OsiCbc libOsiCbc
+ HINTS ${COIN_ROOT_DIR}/lib/coin
+ HINTS ${COIN_ROOT_DIR}/lib
+)
+FIND_LIBRARY(COIN_OSI_CLP_LIBRARY
+ NAMES OsiClp libOsiClp
+ HINTS ${COIN_ROOT_DIR}/lib/coin
+ HINTS ${COIN_ROOT_DIR}/lib
+)
+FIND_LIBRARY(COIN_OSI_VOL_LIBRARY
+ NAMES OsiVol libOsiVol
+ HINTS ${COIN_ROOT_DIR}/lib/coin
+ HINTS ${COIN_ROOT_DIR}/lib
+)
+FIND_LIBRARY(COIN_VOL_LIBRARY
+ NAMES Vol libVol
+ HINTS ${COIN_ROOT_DIR}/lib/coin
+ HINTS ${COIN_ROOT_DIR}/lib
+)
+
+FIND_LIBRARY(COIN_ZLIB_LIBRARY
+ NAMES z libz
+ HINTS ${COIN_ROOT_DIR}/lib/coin
+ HINTS ${COIN_ROOT_DIR}/lib
+)
+FIND_LIBRARY(COIN_BZ2_LIBRARY
+ NAMES bz2 libbz2
+ HINTS ${COIN_ROOT_DIR}/lib/coin
+ HINTS ${COIN_ROOT_DIR}/lib
+)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(COIN DEFAULT_MSG
+ COIN_INCLUDE_DIR
+ COIN_CBC_LIBRARY
+ COIN_CBC_SOLVER_LIBRARY
+ COIN_CGL_LIBRARY
+ COIN_CLP_LIBRARY
+ COIN_COIN_UTILS_LIBRARY
+ COIN_OSI_LIBRARY
+ COIN_OSI_CBC_LIBRARY
+ COIN_OSI_CLP_LIBRARY
+ # COIN_OSI_VOL_LIBRARY
+ # COIN_VOL_LIBRARY
+)
+
+IF(COIN_FOUND)
+ SET(COIN_INCLUDE_DIRS ${COIN_INCLUDE_DIR})
+ SET(COIN_CLP_LIBRARIES "${COIN_CLP_LIBRARY};${COIN_COIN_UTILS_LIBRARY};${COIN_ZLIB_LIBRARY};${COIN_BZ2_LIBRARY}")
+ IF(COIN_ZLIB_LIBRARY)
+ SET(COIN_CLP_LIBRARIES "${COIN_CLP_LIBRARIES};${COIN_ZLIB_LIBRARY}")
+ ENDIF(COIN_ZLIB_LIBRARY)
+ IF(COIN_BZ2_LIBRARY)
+ SET(COIN_CLP_LIBRARIES "${COIN_CLP_LIBRARIES};${COIN_BZ2_LIBRARY}")
+ ENDIF(COIN_BZ2_LIBRARY)
+ SET(COIN_CBC_LIBRARIES "${COIN_CBC_LIBRARY};${COIN_CBC_SOLVER_LIBRARY};${COIN_CGL_LIBRARY};${COIN_OSI_LIBRARY};${COIN_OSI_CBC_LIBRARY};${COIN_OSI_CLP_LIBRARY};${COIN_ZLIB_LIBRARY};${COIN_BZ2_LIBRARY};${COIN_CLP_LIBRARIES}")
+ SET(COIN_LIBRARIES ${COIN_CBC_LIBRARIES})
+ENDIF(COIN_FOUND)
+
+MARK_AS_ADVANCED(
+ COIN_INCLUDE_DIR
+ COIN_CBC_LIBRARY
+ COIN_CBC_SOLVER_LIBRARY
+ COIN_CGL_LIBRARY
+ COIN_CLP_LIBRARY
+ COIN_COIN_UTILS_LIBRARY
+ COIN_OSI_LIBRARY
+ COIN_OSI_CBC_LIBRARY
+ COIN_OSI_CLP_LIBRARY
+ COIN_OSI_VOL_LIBRARY
+ COIN_VOL_LIBRARY
+ COIN_ZLIB_LIBRARY
+ COIN_BZ2_LIBRARY
+)
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindGLPK.cmake b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindGLPK.cmake
new file mode 100644
index 00000000000..55e5e3ee056
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindGLPK.cmake
@@ -0,0 +1,55 @@
+SET(GLPK_ROOT_DIR "" CACHE PATH "GLPK root directory")
+
+SET(GLPK_REGKEY "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\Glpk;InstallPath]")
+GET_FILENAME_COMPONENT(GLPK_ROOT_PATH ${GLPK_REGKEY} ABSOLUTE)
+
+FIND_PATH(GLPK_INCLUDE_DIR
+ glpk.h
+ PATHS ${GLPK_REGKEY}/include
+ HINTS ${GLPK_ROOT_DIR}/include
+)
+FIND_LIBRARY(GLPK_LIBRARY
+ glpk
+ PATHS ${GLPK_REGKEY}/lib
+ HINTS ${GLPK_ROOT_DIR}/lib
+)
+
+IF(GLPK_INCLUDE_DIR AND GLPK_LIBRARY)
+ FILE(READ ${GLPK_INCLUDE_DIR}/glpk.h GLPK_GLPK_H)
+
+ STRING(REGEX MATCH "define[ ]+GLP_MAJOR_VERSION[ ]+[0-9]+" GLPK_MAJOR_VERSION_LINE "${GLPK_GLPK_H}")
+ STRING(REGEX REPLACE "define[ ]+GLP_MAJOR_VERSION[ ]+([0-9]+)" "\\1" GLPK_VERSION_MAJOR "${GLPK_MAJOR_VERSION_LINE}")
+
+ STRING(REGEX MATCH "define[ ]+GLP_MINOR_VERSION[ ]+[0-9]+" GLPK_MINOR_VERSION_LINE "${GLPK_GLPK_H}")
+ STRING(REGEX REPLACE "define[ ]+GLP_MINOR_VERSION[ ]+([0-9]+)" "\\1" GLPK_VERSION_MINOR "${GLPK_MINOR_VERSION_LINE}")
+
+ SET(GLPK_VERSION_STRING "${GLPK_VERSION_MAJOR}.${GLPK_VERSION_MINOR}")
+
+ IF(GLPK_FIND_VERSION)
+ IF(GLPK_FIND_VERSION_COUNT GREATER 2)
+ MESSAGE(SEND_ERROR "unexpected version string")
+ ENDIF(GLPK_FIND_VERSION_COUNT GREATER 2)
+
+ MATH(EXPR GLPK_REQUESTED_VERSION "${GLPK_FIND_VERSION_MAJOR}*100 + ${GLPK_FIND_VERSION_MINOR}")
+ MATH(EXPR GLPK_FOUND_VERSION "${GLPK_VERSION_MAJOR}*100 + ${GLPK_VERSION_MINOR}")
+
+ IF(GLPK_FOUND_VERSION LESS GLPK_REQUESTED_VERSION)
+ SET(GLPK_PROPER_VERSION_FOUND FALSE)
+ ELSE(GLPK_FOUND_VERSION LESS GLPK_REQUESTED_VERSION)
+ SET(GLPK_PROPER_VERSION_FOUND TRUE)
+ ENDIF(GLPK_FOUND_VERSION LESS GLPK_REQUESTED_VERSION)
+ ELSE(GLPK_FIND_VERSION)
+ SET(GLPK_PROPER_VERSION_FOUND TRUE)
+ ENDIF(GLPK_FIND_VERSION)
+ENDIF(GLPK_INCLUDE_DIR AND GLPK_LIBRARY)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLPK DEFAULT_MSG GLPK_LIBRARY GLPK_INCLUDE_DIR GLPK_PROPER_VERSION_FOUND)
+
+IF(GLPK_FOUND)
+ SET(GLPK_INCLUDE_DIRS ${GLPK_INCLUDE_DIR})
+ SET(GLPK_LIBRARIES ${GLPK_LIBRARY})
+ SET(GLPK_BIN_DIR ${GLPK_ROOT_PATH}/bin)
+ENDIF(GLPK_FOUND)
+
+MARK_AS_ADVANCED(GLPK_LIBRARY GLPK_INCLUDE_DIR GLPK_BIN_DIR)
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindGhostscript.cmake b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindGhostscript.cmake
new file mode 100644
index 00000000000..3366a000e1b
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindGhostscript.cmake
@@ -0,0 +1,10 @@
+INCLUDE(FindPackageHandleStandardArgs)
+
+FIND_PROGRAM(GHOSTSCRIPT_EXECUTABLE
+ NAMES gs gswin32c
+ PATHS "$ENV{ProgramFiles}/gs"
+ PATH_SUFFIXES gs8.61/bin gs8.62/bin gs8.63/bin gs8.64/bin gs8.65/bin
+ DOC "Ghostscript: PostScript and PDF language interpreter and previewer."
+)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Ghostscript DEFAULT_MSG GHOSTSCRIPT_EXECUTABLE)
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindILOG.cmake b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindILOG.cmake
new file mode 100644
index 00000000000..a09fc9a2753
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindILOG.cmake
@@ -0,0 +1,102 @@
+FIND_PATH(ILOG_ROOT_DIR
+ NAMES cplex
+ DOC "CPLEX STUDIO root directory"
+ PATHS /opt/ibm/ILOG /usr/local/ibm/ILOG /usr/local/ILOG /usr/local/ilog
+ PATHS "$ENV{HOME}/ILOG" "$ENV{HOME}/.local/ILOG"
+ PATHS "$ENV{HOME}/ibm/ILOG" "$ENV{HOME}/.local/ibm/ILOG"
+ PATHS "C:/Program Files/IBM/ILOG"
+ PATH_SUFFIXES "CPLEX_Studio126" "CPLEX_Studio125"
+ "CPLEX_Studio124" "CPLEX_Studio123" "CPLEX_Studio122"
+ NO_DEFAULT_PATH
+)
+
+IF(WIN32)
+ IF(MSVC_VERSION STREQUAL "1400")
+ SET(ILOG_WIN_COMPILER "windows_vs2005")
+ ELSEIF(MSVC_VERSION STREQUAL "1500")
+ SET(ILOG_WIN_COMPILER "windows_vs2008")
+ ELSEIF(MSVC_VERSION STREQUAL "1600")
+ SET(ILOG_WIN_COMPILER "windows_vs2010")
+ ELSE()
+ SET(ILOG_WIN_COMPILER "windows_vs2008")
+ ENDIF()
+ IF(CMAKE_CL_64)
+ SET(ILOG_WIN_COMPILER "x64_${ILOG_WIN_COMPILER}")
+ SET(ILOG_WIN_PLATFORM "x64_win32")
+ ELSE()
+ SET(ILOG_WIN_COMPILER "x86_${ILOG_WIN_COMPILER}")
+ SET(ILOG_WIN_PLATFORM "x86_win32")
+ ENDIF()
+ENDIF()
+
+FIND_PATH(ILOG_CPLEX_ROOT_DIR
+ NAMES include/ilcplex
+ HINTS ${ILOG_ROOT_DIR}/cplex ${ILOG_ROOT_DIR}/cplex121
+ ${ILOG_ROOT_DIR}/cplex122 ${ILOG_ROOT_DIR}/cplex123
+ DOC "CPLEX root directory"
+ NO_DEFAULT_PATH
+)
+
+FIND_PATH(ILOG_CONCERT_ROOT_DIR
+ NAMES include/ilconcert
+ HINTS ${ILOG_ROOT_DIR}/concert ${ILOG_ROOT_DIR}/concert29
+ DOC "CONCERT root directory"
+ NO_DEFAULT_PATH
+)
+
+FIND_PATH(ILOG_CPLEX_INCLUDE_DIR
+ ilcplex/cplex.h
+ HINTS ${ILOG_CPLEX_ROOT_DIR}/include
+ NO_DEFAULT_PATH
+)
+
+FIND_PATH(ILOG_CONCERT_INCLUDE_DIR
+ ilconcert/ilobasic.h
+ HINTS ${ILOG_CONCERT_ROOT_DIR}/include
+ NO_DEFAULT_PATH
+)
+
+FIND_LIBRARY(ILOG_CPLEX_LIBRARY
+ cplex cplex121 cplex122 cplex123 cplex124
+ HINTS ${ILOG_CPLEX_ROOT_DIR}/lib/x86_sles10_4.1/static_pic
+ ${ILOG_CPLEX_ROOT_DIR}/lib/x86-64_sles10_4.1/static_pic
+ ${ILOG_CPLEX_ROOT_DIR}/lib/x86_debian4.0_4.1/static_pic
+ ${ILOG_CPLEX_ROOT_DIR}/lib/x86-64_debian4.0_4.1/static_pic
+ ${ILOG_CPLEX_ROOT_DIR}/lib/${ILOG_WIN_COMPILER}/stat_mda
+ NO_DEFAULT_PATH
+ )
+
+FIND_LIBRARY(ILOG_CONCERT_LIBRARY
+ concert
+ HINTS ${ILOG_CONCERT_ROOT_DIR}/lib/x86_sles10_4.1/static_pic
+ ${ILOG_CONCERT_ROOT_DIR}/lib/x86-64_sles10_4.1/static_pic
+ ${ILOG_CONCERT_ROOT_DIR}/lib/x86_debian4.0_4.1/static_pic
+ ${ILOG_CONCERT_ROOT_DIR}/lib/x86-64_debian4.0_4.1/static_pic
+ ${ILOG_CONCERT_ROOT_DIR}/lib/${ILOG_WIN_COMPILER}/stat_mda
+ NO_DEFAULT_PATH
+ )
+
+FIND_FILE(ILOG_CPLEX_DLL
+ cplex121.dll cplex122.dll cplex123.dll cplex124.dll
+ HINTS ${ILOG_CPLEX_ROOT_DIR}/bin/${ILOG_WIN_PLATFORM}
+ NO_DEFAULT_PATH
+ )
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(ILOG
+ DEFAULT_MSG ILOG_CPLEX_LIBRARY ILOG_CPLEX_INCLUDE_DIR
+ )
+
+IF(ILOG_FOUND)
+ SET(ILOG_INCLUDE_DIRS ${ILOG_CPLEX_INCLUDE_DIR} ${ILOG_CONCERT_INCLUDE_DIR})
+ SET(ILOG_LIBRARIES ${ILOG_CPLEX_LIBRARY} ${ILOG_CONCERT_LIBRARY})
+ IF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ # SET(CPLEX_LIBRARIES "${CPLEX_LIBRARIES};m;pthread")
+ SET(ILOG_LIBRARIES ${ILOG_LIBRARIES} "m" "pthread")
+ ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ENDIF(ILOG_FOUND)
+
+MARK_AS_ADVANCED(
+ ILOG_CPLEX_LIBRARY ILOG_CPLEX_INCLUDE_DIR ILOG_CPLEX_DLL
+ ILOG_CONCERT_LIBRARY ILOG_CONCERT_INCLUDE_DIR ILOG_CONCERT_DLL
+ )
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindSOPLEX.cmake b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindSOPLEX.cmake
new file mode 100644
index 00000000000..d27cff0f3e1
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindSOPLEX.cmake
@@ -0,0 +1,23 @@
+SET(SOPLEX_ROOT_DIR "" CACHE PATH "SoPlex root directory")
+
+FIND_PATH(SOPLEX_INCLUDE_DIR
+ soplex.h
+ HINTS ${SOPLEX_ROOT_DIR}/src
+)
+FIND_LIBRARY(SOPLEX_LIBRARY
+ soplex
+ HINTS ${SOPLEX_ROOT_DIR}/lib
+)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(SOPLEX DEFAULT_MSG SOPLEX_LIBRARY SOPLEX_INCLUDE_DIR)
+
+IF(SOPLEX_FOUND)
+ SET(SOPLEX_INCLUDE_DIRS ${SOPLEX_INCLUDE_DIR})
+ SET(SOPLEX_LIBRARIES ${SOPLEX_LIBRARY})
+ IF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ SET(SOPLEX_LIBRARIES "${SOPLEX_LIBRARIES};z")
+ ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ENDIF(SOPLEX_FOUND)
+
+MARK_AS_ADVANCED(SOPLEX_LIBRARY SOPLEX_INCLUDE_DIR)
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/LEMONConfig.cmake.in b/extern/quadriflow/3rd/lemon-1.3.1/cmake/LEMONConfig.cmake.in
new file mode 100644
index 00000000000..b0d2d8b4c3f
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/cmake/LEMONConfig.cmake.in
@@ -0,0 +1,13 @@
+SET(LEMON_INCLUDE_DIR "@CMAKE_INSTALL_PREFIX@/include" CACHE PATH "LEMON include directory")
+SET(LEMON_INCLUDE_DIRS "${LEMON_INCLUDE_DIR}")
+
+IF(UNIX)
+ SET(LEMON_LIB_NAME "libemon.a")
+ELSEIF(WIN32)
+ SET(LEMON_LIB_NAME "lemon.lib")
+ENDIF(UNIX)
+
+SET(LEMON_LIBRARY "@CMAKE_INSTALL_PREFIX@/lib/${LEMON_LIB_NAME}" CACHE FILEPATH "LEMON library")
+SET(LEMON_LIBRARIES "${LEMON_LIBRARY}")
+
+MARK_AS_ADVANCED(LEMON_LIBRARY LEMON_INCLUDE_DIR)
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/nsis/lemon.ico b/extern/quadriflow/3rd/lemon-1.3.1/cmake/nsis/lemon.ico
new file mode 100644
index 00000000000..bbfd8c143d9
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/cmake/nsis/lemon.ico
Binary files differ
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/nsis/uninstall.ico b/extern/quadriflow/3rd/lemon-1.3.1/cmake/nsis/uninstall.ico
new file mode 100644
index 00000000000..7495f7c3c27
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/cmake/nsis/uninstall.ico
Binary files differ
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/version.cmake b/extern/quadriflow/3rd/lemon-1.3.1/cmake/version.cmake
new file mode 100644
index 00000000000..91369e1cac7
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/cmake/version.cmake
@@ -0,0 +1 @@
+SET(LEMON_VERSION "1.3.1" CACHE STRING "LEMON version string.")
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/version.cmake.in b/extern/quadriflow/3rd/lemon-1.3.1/cmake/version.cmake.in
new file mode 100644
index 00000000000..7cd4b689926
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/cmake/version.cmake.in
@@ -0,0 +1 @@
+SET(LEMON_VERSION "@LEMON_VERSION@" CACHE STRING "LEMON version string.")
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/contrib/CMakeLists.txt b/extern/quadriflow/3rd/lemon-1.3.1/contrib/CMakeLists.txt
new file mode 100644
index 00000000000..b6c11e2aad4
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/contrib/CMakeLists.txt
@@ -0,0 +1,19 @@
+INCLUDE_DIRECTORIES(
+ ${PROJECT_SOURCE_DIR}
+ ${PROJECT_BINARY_DIR}
+)
+
+LINK_DIRECTORIES(
+ ${PROJECT_BINARY_DIR}/lemon
+)
+
+# Uncomment (and adjust) the following two lines. 'myprog' is the name
+# of the final executable ('.exe' will automatically be added to the
+# name on Windows) and 'myprog-main.cc' is the source code it is
+# compiled from. You can add more source files separated by
+# whitespaces. Moreover, you can add multiple similar blocks if you
+# want to build more than one executables.
+
+# ADD_EXECUTABLE(myprog myprog-main.cc)
+# TARGET_LINK_LIBRARIES(myprog lemon)
+
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/demo/CMakeLists.txt b/extern/quadriflow/3rd/lemon-1.3.1/demo/CMakeLists.txt
new file mode 100644
index 00000000000..e0566f407f0
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/demo/CMakeLists.txt
@@ -0,0 +1,19 @@
+INCLUDE_DIRECTORIES(
+ ${PROJECT_SOURCE_DIR}
+ ${PROJECT_BINARY_DIR}
+)
+
+LINK_DIRECTORIES(
+ ${PROJECT_BINARY_DIR}/lemon
+)
+
+SET(DEMOS
+ arg_parser_demo
+ graph_to_eps_demo
+ lgf_demo
+)
+
+FOREACH(DEMO_NAME ${DEMOS})
+ ADD_EXECUTABLE(${DEMO_NAME} ${DEMO_NAME}.cc)
+ TARGET_LINK_LIBRARIES(${DEMO_NAME} lemon)
+ENDFOREACH()
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/demo/arg_parser_demo.cc b/extern/quadriflow/3rd/lemon-1.3.1/demo/arg_parser_demo.cc
new file mode 100644
index 00000000000..1bafac0c860
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/demo/arg_parser_demo.cc
@@ -0,0 +1,112 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2010
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+///\ingroup demos
+///\file
+///\brief Argument parser demo
+///
+/// This example shows how the argument parser can be used.
+///
+/// \include arg_parser_demo.cc
+
+#include <lemon/arg_parser.h>
+
+using namespace lemon;
+int main(int argc, char **argv)
+{
+ // Initialize the argument parser
+ ArgParser ap(argc, argv);
+ int i;
+ std::string s;
+ double d = 1.0;
+ bool b, nh;
+ bool g1, g2, g3;
+
+ // Add a mandatory integer option with storage reference
+ ap.refOption("n", "An integer input.", i, true);
+ // Add a double option with storage reference (the default value is 1.0)
+ ap.refOption("val", "A double input.", d);
+ // Add a double option without storage reference (the default value is 3.14)
+ ap.doubleOption("val2", "A double input.", 3.14);
+ // Set synonym for -val option
+ ap.synonym("vals", "val");
+ // Add a string option
+ ap.refOption("name", "A string input.", s);
+ // Add bool options
+ ap.refOption("f", "A switch.", b)
+ .refOption("nohelp", "", nh)
+ .refOption("gra", "Choice A", g1)
+ .refOption("grb", "Choice B", g2)
+ .refOption("grc", "Choice C", g3);
+ // Bundle -gr* options into a group
+ ap.optionGroup("gr", "gra")
+ .optionGroup("gr", "grb")
+ .optionGroup("gr", "grc");
+ // Set the group mandatory
+ ap.mandatoryGroup("gr");
+ // Set the options of the group exclusive (only one option can be given)
+ ap.onlyOneGroup("gr");
+ // Add non-parsed arguments (e.g. input files)
+ ap.other("infile", "The input file.")
+ .other("...");
+
+ // Throw an exception when problems occurs. The default behavior is to
+ // exit(1) on these cases, but this makes Valgrind falsely warn
+ // about memory leaks.
+ ap.throwOnProblems();
+
+ // Perform the parsing process
+ // (in case of any error it terminates the program)
+ // The try {} construct is necessary only if the ap.trowOnProblems()
+ // setting is in use.
+ try {
+ ap.parse();
+ } catch (ArgParserException &) { return 1; }
+
+ // Check each option if it has been given and print its value
+ std::cout << "Parameters of '" << ap.commandName() << "':\n";
+
+ std::cout << " Value of -n: " << i << std::endl;
+ if(ap.given("val")) std::cout << " Value of -val: " << d << std::endl;
+ if(ap.given("val2")) {
+ d = ap["val2"];
+ std::cout << " Value of -val2: " << d << std::endl;
+ }
+ if(ap.given("name")) std::cout << " Value of -name: " << s << std::endl;
+ if(ap.given("f")) std::cout << " -f is given\n";
+ if(ap.given("nohelp")) std::cout << " Value of -nohelp: " << nh << std::endl;
+ if(ap.given("gra")) std::cout << " -gra is given\n";
+ if(ap.given("grb")) std::cout << " -grb is given\n";
+ if(ap.given("grc")) std::cout << " -grc is given\n";
+
+ switch(ap.files().size()) {
+ case 0:
+ std::cout << " No file argument was given.\n";
+ break;
+ case 1:
+ std::cout << " 1 file argument was given. It is:\n";
+ break;
+ default:
+ std::cout << " "
+ << ap.files().size() << " file arguments were given. They are:\n";
+ }
+ for(unsigned int i=0;i<ap.files().size();++i)
+ std::cout << " '" << ap.files()[i] << "'\n";
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/demo/digraph.lgf b/extern/quadriflow/3rd/lemon-1.3.1/demo/digraph.lgf
new file mode 100644
index 00000000000..83ba7da13c2
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/demo/digraph.lgf
@@ -0,0 +1,29 @@
+@nodes
+label
+0
+1
+2
+3
+4
+5
+6
+7
+@arcs
+ label capacity
+0 1 0 16
+0 2 1 12
+0 3 2 20
+1 2 3 10
+1 4 4 10
+1 5 5 13
+2 3 6 10
+2 4 7 8
+2 6 8 8
+5 3 9 20
+3 6 10 25
+4 7 11 15
+5 7 12 15
+6 7 13 18
+@attributes
+source 0
+target 7
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/demo/graph_to_eps_demo.cc b/extern/quadriflow/3rd/lemon-1.3.1/demo/graph_to_eps_demo.cc
new file mode 100644
index 00000000000..f2f55a92861
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/demo/graph_to_eps_demo.cc
@@ -0,0 +1,206 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+/// \ingroup demos
+/// \file
+/// \brief Demo of the graph drawing function \ref graphToEps()
+///
+/// This demo program shows examples how to use the function \ref
+/// graphToEps(). It takes no input but simply creates seven
+/// <tt>.eps</tt> files demonstrating the capability of \ref
+/// graphToEps(), and showing how to draw directed graphs,
+/// how to handle parallel egdes, how to change the properties (like
+/// color, shape, size, title etc.) of nodes and arcs individually
+/// using appropriate graph maps.
+///
+/// \include graph_to_eps_demo.cc
+
+#include<lemon/list_graph.h>
+#include<lemon/graph_to_eps.h>
+#include<lemon/math.h>
+
+using namespace std;
+using namespace lemon;
+
+int main()
+{
+ Palette palette;
+ Palette paletteW(true);
+
+ // Create a small digraph
+ ListDigraph g;
+ typedef ListDigraph::Node Node;
+ typedef ListDigraph::NodeIt NodeIt;
+ typedef ListDigraph::Arc Arc;
+ typedef dim2::Point<int> Point;
+
+ Node n1=g.addNode();
+ Node n2=g.addNode();
+ Node n3=g.addNode();
+ Node n4=g.addNode();
+ Node n5=g.addNode();
+
+ ListDigraph::NodeMap<Point> coords(g);
+ ListDigraph::NodeMap<double> sizes(g);
+ ListDigraph::NodeMap<int> colors(g);
+ ListDigraph::NodeMap<int> shapes(g);
+ ListDigraph::ArcMap<int> acolors(g);
+ ListDigraph::ArcMap<int> widths(g);
+
+ coords[n1]=Point(50,50); sizes[n1]=1; colors[n1]=1; shapes[n1]=0;
+ coords[n2]=Point(50,70); sizes[n2]=2; colors[n2]=2; shapes[n2]=2;
+ coords[n3]=Point(70,70); sizes[n3]=1; colors[n3]=3; shapes[n3]=0;
+ coords[n4]=Point(70,50); sizes[n4]=2; colors[n4]=4; shapes[n4]=1;
+ coords[n5]=Point(85,60); sizes[n5]=3; colors[n5]=5; shapes[n5]=2;
+
+ Arc a;
+
+ a=g.addArc(n1,n2); acolors[a]=0; widths[a]=1;
+ a=g.addArc(n2,n3); acolors[a]=0; widths[a]=1;
+ a=g.addArc(n3,n5); acolors[a]=0; widths[a]=3;
+ a=g.addArc(n5,n4); acolors[a]=0; widths[a]=1;
+ a=g.addArc(n4,n1); acolors[a]=0; widths[a]=1;
+ a=g.addArc(n2,n4); acolors[a]=1; widths[a]=2;
+ a=g.addArc(n3,n4); acolors[a]=2; widths[a]=1;
+
+ IdMap<ListDigraph,Node> id(g);
+
+ // Create .eps files showing the digraph with different options
+ cout << "Create 'graph_to_eps_demo_out_1_pure.eps'" << endl;
+ graphToEps(g,"graph_to_eps_demo_out_1_pure.eps").
+ coords(coords).
+ title("Sample .eps figure").
+ copyright("(C) 2003-2009 LEMON Project").
+ run();
+
+ cout << "Create 'graph_to_eps_demo_out_2.eps'" << endl;
+ graphToEps(g,"graph_to_eps_demo_out_2.eps").
+ coords(coords).
+ title("Sample .eps figure").
+ copyright("(C) 2003-2009 LEMON Project").
+ absoluteNodeSizes().absoluteArcWidths().
+ nodeScale(2).nodeSizes(sizes).
+ nodeShapes(shapes).
+ nodeColors(composeMap(palette,colors)).
+ arcColors(composeMap(palette,acolors)).
+ arcWidthScale(.4).arcWidths(widths).
+ nodeTexts(id).nodeTextSize(3).
+ run();
+
+ cout << "Create 'graph_to_eps_demo_out_3_arr.eps'" << endl;
+ graphToEps(g,"graph_to_eps_demo_out_3_arr.eps").
+ title("Sample .eps figure (with arrowheads)").
+ copyright("(C) 2003-2009 LEMON Project").
+ absoluteNodeSizes().absoluteArcWidths().
+ nodeColors(composeMap(palette,colors)).
+ coords(coords).
+ nodeScale(2).nodeSizes(sizes).
+ nodeShapes(shapes).
+ arcColors(composeMap(palette,acolors)).
+ arcWidthScale(.4).arcWidths(widths).
+ nodeTexts(id).nodeTextSize(3).
+ drawArrows().arrowWidth(2).arrowLength(2).
+ run();
+
+ // Add more arcs to the digraph
+ a=g.addArc(n1,n4); acolors[a]=2; widths[a]=1;
+ a=g.addArc(n4,n1); acolors[a]=1; widths[a]=2;
+
+ a=g.addArc(n1,n2); acolors[a]=1; widths[a]=1;
+ a=g.addArc(n1,n2); acolors[a]=2; widths[a]=1;
+ a=g.addArc(n1,n2); acolors[a]=3; widths[a]=1;
+ a=g.addArc(n1,n2); acolors[a]=4; widths[a]=1;
+ a=g.addArc(n1,n2); acolors[a]=5; widths[a]=1;
+ a=g.addArc(n1,n2); acolors[a]=6; widths[a]=1;
+ a=g.addArc(n1,n2); acolors[a]=7; widths[a]=1;
+
+ cout << "Create 'graph_to_eps_demo_out_4_par.eps'" << endl;
+ graphToEps(g,"graph_to_eps_demo_out_4_par.eps").
+ title("Sample .eps figure (parallel arcs)").
+ copyright("(C) 2003-2009 LEMON Project").
+ absoluteNodeSizes().absoluteArcWidths().
+ nodeShapes(shapes).
+ coords(coords).
+ nodeScale(2).nodeSizes(sizes).
+ nodeColors(composeMap(palette,colors)).
+ arcColors(composeMap(palette,acolors)).
+ arcWidthScale(.4).arcWidths(widths).
+ nodeTexts(id).nodeTextSize(3).
+ enableParallel().parArcDist(1.5).
+ run();
+
+ cout << "Create 'graph_to_eps_demo_out_5_par_arr.eps'" << endl;
+ graphToEps(g,"graph_to_eps_demo_out_5_par_arr.eps").
+ title("Sample .eps figure (parallel arcs and arrowheads)").
+ copyright("(C) 2003-2009 LEMON Project").
+ absoluteNodeSizes().absoluteArcWidths().
+ nodeScale(2).nodeSizes(sizes).
+ coords(coords).
+ nodeShapes(shapes).
+ nodeColors(composeMap(palette,colors)).
+ arcColors(composeMap(palette,acolors)).
+ arcWidthScale(.3).arcWidths(widths).
+ nodeTexts(id).nodeTextSize(3).
+ enableParallel().parArcDist(1).
+ drawArrows().arrowWidth(1).arrowLength(1).
+ run();
+
+ cout << "Create 'graph_to_eps_demo_out_6_par_arr_a4.eps'" << endl;
+ graphToEps(g,"graph_to_eps_demo_out_6_par_arr_a4.eps").
+ title("Sample .eps figure (fits to A4)").
+ copyright("(C) 2003-2009 LEMON Project").
+ scaleToA4().
+ absoluteNodeSizes().absoluteArcWidths().
+ nodeScale(2).nodeSizes(sizes).
+ coords(coords).
+ nodeShapes(shapes).
+ nodeColors(composeMap(palette,colors)).
+ arcColors(composeMap(palette,acolors)).
+ arcWidthScale(.3).arcWidths(widths).
+ nodeTexts(id).nodeTextSize(3).
+ enableParallel().parArcDist(1).
+ drawArrows().arrowWidth(1).arrowLength(1).
+ run();
+
+ // Create an .eps file showing the colors of a default Palette
+ ListDigraph h;
+ ListDigraph::NodeMap<int> hcolors(h);
+ ListDigraph::NodeMap<Point> hcoords(h);
+
+ int cols=int(std::sqrt(double(palette.size())));
+ for(int i=0;i<int(paletteW.size());i++) {
+ Node n=h.addNode();
+ hcoords[n]=Point(1+i%cols,1+i/cols);
+ hcolors[n]=i;
+ }
+
+ cout << "Create 'graph_to_eps_demo_out_7_colors.eps'" << endl;
+ graphToEps(h,"graph_to_eps_demo_out_7_colors.eps").
+ scale(60).
+ title("Sample .eps figure (Palette demo)").
+ copyright("(C) 2003-2009 LEMON Project").
+ coords(hcoords).
+ absoluteNodeSizes().absoluteArcWidths().
+ nodeScale(.45).
+ distantColorNodeTexts().
+ nodeTexts(hcolors).nodeTextSize(.6).
+ nodeColors(composeMap(paletteW,hcolors)).
+ run();
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/demo/lgf_demo.cc b/extern/quadriflow/3rd/lemon-1.3.1/demo/lgf_demo.cc
new file mode 100644
index 00000000000..e2d31cdf440
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/demo/lgf_demo.cc
@@ -0,0 +1,70 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+///\ingroup demos
+///\file
+///\brief Demonstrating graph input and output
+///
+/// This program gives an example of how to read and write a digraph
+/// and additional maps from/to a stream or a file using the
+/// \ref lgf-format "LGF" format.
+///
+/// The \c "digraph.lgf" file:
+/// \include digraph.lgf
+///
+/// And the program which reads it and prints the digraph to the
+/// standard output:
+/// \include lgf_demo.cc
+
+#include <iostream>
+#include <lemon/smart_graph.h>
+#include <lemon/lgf_reader.h>
+#include <lemon/lgf_writer.h>
+
+using namespace lemon;
+
+int main() {
+ SmartDigraph g;
+ SmartDigraph::ArcMap<int> cap(g);
+ SmartDigraph::Node s, t;
+
+ try {
+ digraphReader(g, "digraph.lgf"). // read the directed graph into g
+ arcMap("capacity", cap). // read the 'capacity' arc map into cap
+ node("source", s). // read 'source' node to s
+ node("target", t). // read 'target' node to t
+ run();
+ } catch (Exception& error) { // check if there was any error
+ std::cerr << "Error: " << error.what() << std::endl;
+ return -1;
+ }
+
+ std::cout << "A digraph is read from 'digraph.lgf'." << std::endl;
+ std::cout << "Number of nodes: " << countNodes(g) << std::endl;
+ std::cout << "Number of arcs: " << countArcs(g) << std::endl;
+
+ std::cout << "We can write it to the standard output:" << std::endl;
+
+ digraphWriter(g). // write g to the standard output
+ arcMap("capacity", cap). // write cap into 'capacity'
+ node("source", s). // write s to 'source'
+ node("target", t). // write t to 'target'
+ run();
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/CMakeLists.txt b/extern/quadriflow/3rd/lemon-1.3.1/lemon/CMakeLists.txt
new file mode 100644
index 00000000000..4e6567e49c7
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/CMakeLists.txt
@@ -0,0 +1,91 @@
+INCLUDE_DIRECTORIES(
+ ${PROJECT_SOURCE_DIR}
+ ${PROJECT_BINARY_DIR}
+)
+
+CONFIGURE_FILE(
+ ${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/config.h
+)
+
+CONFIGURE_FILE(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lemon.pc.in
+ ${CMAKE_CURRENT_BINARY_DIR}/lemon.pc
+ @ONLY
+)
+
+SET(LEMON_SOURCES
+ arg_parser.cc
+ base.cc
+ color.cc
+ lp_base.cc
+ lp_skeleton.cc
+ random.cc
+ bits/windows.cc
+)
+
+IF(LEMON_HAVE_GLPK)
+ SET(LEMON_SOURCES ${LEMON_SOURCES} glpk.cc)
+ INCLUDE_DIRECTORIES(${GLPK_INCLUDE_DIRS})
+ IF(WIN32)
+ INSTALL(FILES ${GLPK_BIN_DIR}/glpk.dll DESTINATION bin)
+ INSTALL(FILES ${GLPK_BIN_DIR}/libltdl3.dll DESTINATION bin)
+ INSTALL(FILES ${GLPK_BIN_DIR}/zlib1.dll DESTINATION bin)
+ ENDIF()
+ENDIF()
+
+IF(LEMON_HAVE_CPLEX)
+ SET(LEMON_SOURCES ${LEMON_SOURCES} cplex.cc)
+ INCLUDE_DIRECTORIES(${ILOG_INCLUDE_DIRS})
+ENDIF()
+
+IF(LEMON_HAVE_CLP)
+ SET(LEMON_SOURCES ${LEMON_SOURCES} clp.cc)
+ INCLUDE_DIRECTORIES(${COIN_INCLUDE_DIRS})
+ENDIF()
+
+IF(LEMON_HAVE_CBC)
+ SET(LEMON_SOURCES ${LEMON_SOURCES} cbc.cc)
+ INCLUDE_DIRECTORIES(${COIN_INCLUDE_DIRS})
+ENDIF()
+
+IF(LEMON_HAVE_SOPLEX)
+ SET(LEMON_SOURCES ${LEMON_SOURCES} soplex.cc)
+ INCLUDE_DIRECTORIES(${SOPLEX_INCLUDE_DIRS})
+ENDIF()
+
+ADD_LIBRARY(lemon ${LEMON_SOURCES})
+
+TARGET_LINK_LIBRARIES(lemon
+ ${GLPK_LIBRARIES} ${COIN_LIBRARIES} ${ILOG_LIBRARIES} ${SOPLEX_LIBRARIES}
+ )
+
+IF(UNIX)
+ SET_TARGET_PROPERTIES(lemon PROPERTIES OUTPUT_NAME emon VERSION ${LEMON_VERSION} SOVERSION ${LEMON_VERSION})
+ENDIF()
+
+INSTALL(
+ TARGETS lemon
+ ARCHIVE DESTINATION lib
+ LIBRARY DESTINATION lib
+ COMPONENT library
+)
+
+INSTALL(
+ DIRECTORY . bits concepts
+ DESTINATION include/lemon
+ COMPONENT headers
+ FILES_MATCHING PATTERN "*.h"
+)
+
+INSTALL(
+ FILES ${CMAKE_CURRENT_BINARY_DIR}/config.h
+ DESTINATION include/lemon
+ COMPONENT headers
+)
+
+INSTALL(
+ FILES ${CMAKE_CURRENT_BINARY_DIR}/lemon.pc
+ DESTINATION lib/pkgconfig
+)
+
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/adaptors.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/adaptors.h
new file mode 100644
index 00000000000..1a40f8ea2c6
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/adaptors.h
@@ -0,0 +1,3638 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_ADAPTORS_H
+#define LEMON_ADAPTORS_H
+
+/// \ingroup graph_adaptors
+/// \file
+/// \brief Adaptor classes for digraphs and graphs
+///
+/// This file contains several useful adaptors for digraphs and graphs.
+
+#include <lemon/core.h>
+#include <lemon/maps.h>
+#include <lemon/bits/variant.h>
+
+#include <lemon/bits/graph_adaptor_extender.h>
+#include <lemon/bits/map_extender.h>
+#include <lemon/tolerance.h>
+
+#include <algorithm>
+
+namespace lemon {
+
+#ifdef _MSC_VER
+#define LEMON_SCOPE_FIX(OUTER, NESTED) OUTER::NESTED
+#else
+#define LEMON_SCOPE_FIX(OUTER, NESTED) typename OUTER::template NESTED
+#endif
+
+ template<typename DGR>
+ class DigraphAdaptorBase {
+ public:
+ typedef DGR Digraph;
+ typedef DigraphAdaptorBase Adaptor;
+
+ protected:
+ DGR* _digraph;
+ DigraphAdaptorBase() : _digraph(0) { }
+ void initialize(DGR& digraph) { _digraph = &digraph; }
+
+ public:
+ DigraphAdaptorBase(DGR& digraph) : _digraph(&digraph) { }
+
+ typedef typename DGR::Node Node;
+ typedef typename DGR::Arc Arc;
+
+ void first(Node& i) const { _digraph->first(i); }
+ void first(Arc& i) const { _digraph->first(i); }
+ void firstIn(Arc& i, const Node& n) const { _digraph->firstIn(i, n); }
+ void firstOut(Arc& i, const Node& n ) const { _digraph->firstOut(i, n); }
+
+ void next(Node& i) const { _digraph->next(i); }
+ void next(Arc& i) const { _digraph->next(i); }
+ void nextIn(Arc& i) const { _digraph->nextIn(i); }
+ void nextOut(Arc& i) const { _digraph->nextOut(i); }
+
+ Node source(const Arc& a) const { return _digraph->source(a); }
+ Node target(const Arc& a) const { return _digraph->target(a); }
+
+ typedef NodeNumTagIndicator<DGR> NodeNumTag;
+ int nodeNum() const { return _digraph->nodeNum(); }
+
+ typedef ArcNumTagIndicator<DGR> ArcNumTag;
+ int arcNum() const { return _digraph->arcNum(); }
+
+ typedef FindArcTagIndicator<DGR> FindArcTag;
+ Arc findArc(const Node& u, const Node& v, const Arc& prev = INVALID) const {
+ return _digraph->findArc(u, v, prev);
+ }
+
+ Node addNode() { return _digraph->addNode(); }
+ Arc addArc(const Node& u, const Node& v) { return _digraph->addArc(u, v); }
+
+ void erase(const Node& n) { _digraph->erase(n); }
+ void erase(const Arc& a) { _digraph->erase(a); }
+
+ void clear() { _digraph->clear(); }
+
+ int id(const Node& n) const { return _digraph->id(n); }
+ int id(const Arc& a) const { return _digraph->id(a); }
+
+ Node nodeFromId(int ix) const { return _digraph->nodeFromId(ix); }
+ Arc arcFromId(int ix) const { return _digraph->arcFromId(ix); }
+
+ int maxNodeId() const { return _digraph->maxNodeId(); }
+ int maxArcId() const { return _digraph->maxArcId(); }
+
+ typedef typename ItemSetTraits<DGR, Node>::ItemNotifier NodeNotifier;
+ NodeNotifier& notifier(Node) const { return _digraph->notifier(Node()); }
+
+ typedef typename ItemSetTraits<DGR, Arc>::ItemNotifier ArcNotifier;
+ ArcNotifier& notifier(Arc) const { return _digraph->notifier(Arc()); }
+
+ template <typename V>
+ class NodeMap : public DGR::template NodeMap<V> {
+ typedef typename DGR::template NodeMap<V> Parent;
+
+ public:
+ explicit NodeMap(const Adaptor& adaptor)
+ : Parent(*adaptor._digraph) {}
+ NodeMap(const Adaptor& adaptor, const V& value)
+ : Parent(*adaptor._digraph, value) { }
+
+ private:
+ NodeMap& operator=(const NodeMap& cmap) {
+ return operator=<NodeMap>(cmap);
+ }
+
+ template <typename CMap>
+ NodeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+
+ };
+
+ template <typename V>
+ class ArcMap : public DGR::template ArcMap<V> {
+ typedef typename DGR::template ArcMap<V> Parent;
+
+ public:
+ explicit ArcMap(const DigraphAdaptorBase<DGR>& adaptor)
+ : Parent(*adaptor._digraph) {}
+ ArcMap(const DigraphAdaptorBase<DGR>& adaptor, const V& value)
+ : Parent(*adaptor._digraph, value) {}
+
+ private:
+ ArcMap& operator=(const ArcMap& cmap) {
+ return operator=<ArcMap>(cmap);
+ }
+
+ template <typename CMap>
+ ArcMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+
+ };
+
+ };
+
+ template<typename GR>
+ class GraphAdaptorBase {
+ public:
+ typedef GR Graph;
+
+ protected:
+ GR* _graph;
+
+ GraphAdaptorBase() : _graph(0) {}
+
+ void initialize(GR& graph) { _graph = &graph; }
+
+ public:
+ GraphAdaptorBase(GR& graph) : _graph(&graph) {}
+
+ typedef typename GR::Node Node;
+ typedef typename GR::Arc Arc;
+ typedef typename GR::Edge Edge;
+
+ void first(Node& i) const { _graph->first(i); }
+ void first(Arc& i) const { _graph->first(i); }
+ void first(Edge& i) const { _graph->first(i); }
+ void firstIn(Arc& i, const Node& n) const { _graph->firstIn(i, n); }
+ void firstOut(Arc& i, const Node& n ) const { _graph->firstOut(i, n); }
+ void firstInc(Edge &i, bool &d, const Node &n) const {
+ _graph->firstInc(i, d, n);
+ }
+
+ void next(Node& i) const { _graph->next(i); }
+ void next(Arc& i) const { _graph->next(i); }
+ void next(Edge& i) const { _graph->next(i); }
+ void nextIn(Arc& i) const { _graph->nextIn(i); }
+ void nextOut(Arc& i) const { _graph->nextOut(i); }
+ void nextInc(Edge &i, bool &d) const { _graph->nextInc(i, d); }
+
+ Node u(const Edge& e) const { return _graph->u(e); }
+ Node v(const Edge& e) const { return _graph->v(e); }
+
+ Node source(const Arc& a) const { return _graph->source(a); }
+ Node target(const Arc& a) const { return _graph->target(a); }
+
+ typedef NodeNumTagIndicator<Graph> NodeNumTag;
+ int nodeNum() const { return _graph->nodeNum(); }
+
+ typedef ArcNumTagIndicator<Graph> ArcNumTag;
+ int arcNum() const { return _graph->arcNum(); }
+
+ typedef EdgeNumTagIndicator<Graph> EdgeNumTag;
+ int edgeNum() const { return _graph->edgeNum(); }
+
+ typedef FindArcTagIndicator<Graph> FindArcTag;
+ Arc findArc(const Node& u, const Node& v,
+ const Arc& prev = INVALID) const {
+ return _graph->findArc(u, v, prev);
+ }
+
+ typedef FindEdgeTagIndicator<Graph> FindEdgeTag;
+ Edge findEdge(const Node& u, const Node& v,
+ const Edge& prev = INVALID) const {
+ return _graph->findEdge(u, v, prev);
+ }
+
+ Node addNode() { return _graph->addNode(); }
+ Edge addEdge(const Node& u, const Node& v) { return _graph->addEdge(u, v); }
+
+ void erase(const Node& i) { _graph->erase(i); }
+ void erase(const Edge& i) { _graph->erase(i); }
+
+ void clear() { _graph->clear(); }
+
+ bool direction(const Arc& a) const { return _graph->direction(a); }
+ Arc direct(const Edge& e, bool d) const { return _graph->direct(e, d); }
+
+ int id(const Node& v) const { return _graph->id(v); }
+ int id(const Arc& a) const { return _graph->id(a); }
+ int id(const Edge& e) const { return _graph->id(e); }
+
+ Node nodeFromId(int ix) const { return _graph->nodeFromId(ix); }
+ Arc arcFromId(int ix) const { return _graph->arcFromId(ix); }
+ Edge edgeFromId(int ix) const { return _graph->edgeFromId(ix); }
+
+ int maxNodeId() const { return _graph->maxNodeId(); }
+ int maxArcId() const { return _graph->maxArcId(); }
+ int maxEdgeId() const { return _graph->maxEdgeId(); }
+
+ typedef typename ItemSetTraits<GR, Node>::ItemNotifier NodeNotifier;
+ NodeNotifier& notifier(Node) const { return _graph->notifier(Node()); }
+
+ typedef typename ItemSetTraits<GR, Arc>::ItemNotifier ArcNotifier;
+ ArcNotifier& notifier(Arc) const { return _graph->notifier(Arc()); }
+
+ typedef typename ItemSetTraits<GR, Edge>::ItemNotifier EdgeNotifier;
+ EdgeNotifier& notifier(Edge) const { return _graph->notifier(Edge()); }
+
+ template <typename V>
+ class NodeMap : public GR::template NodeMap<V> {
+ typedef typename GR::template NodeMap<V> Parent;
+
+ public:
+ explicit NodeMap(const GraphAdaptorBase<GR>& adapter)
+ : Parent(*adapter._graph) {}
+ NodeMap(const GraphAdaptorBase<GR>& adapter, const V& value)
+ : Parent(*adapter._graph, value) {}
+
+ private:
+ NodeMap& operator=(const NodeMap& cmap) {
+ return operator=<NodeMap>(cmap);
+ }
+
+ template <typename CMap>
+ NodeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+
+ };
+
+ template <typename V>
+ class ArcMap : public GR::template ArcMap<V> {
+ typedef typename GR::template ArcMap<V> Parent;
+
+ public:
+ explicit ArcMap(const GraphAdaptorBase<GR>& adapter)
+ : Parent(*adapter._graph) {}
+ ArcMap(const GraphAdaptorBase<GR>& adapter, const V& value)
+ : Parent(*adapter._graph, value) {}
+
+ private:
+ ArcMap& operator=(const ArcMap& cmap) {
+ return operator=<ArcMap>(cmap);
+ }
+
+ template <typename CMap>
+ ArcMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+ template <typename V>
+ class EdgeMap : public GR::template EdgeMap<V> {
+ typedef typename GR::template EdgeMap<V> Parent;
+
+ public:
+ explicit EdgeMap(const GraphAdaptorBase<GR>& adapter)
+ : Parent(*adapter._graph) {}
+ EdgeMap(const GraphAdaptorBase<GR>& adapter, const V& value)
+ : Parent(*adapter._graph, value) {}
+
+ private:
+ EdgeMap& operator=(const EdgeMap& cmap) {
+ return operator=<EdgeMap>(cmap);
+ }
+
+ template <typename CMap>
+ EdgeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+ };
+
+ template <typename DGR>
+ class ReverseDigraphBase : public DigraphAdaptorBase<DGR> {
+ typedef DigraphAdaptorBase<DGR> Parent;
+ public:
+ typedef DGR Digraph;
+ protected:
+ ReverseDigraphBase() : Parent() { }
+ public:
+ typedef typename Parent::Node Node;
+ typedef typename Parent::Arc Arc;
+
+ void firstIn(Arc& a, const Node& n) const { Parent::firstOut(a, n); }
+ void firstOut(Arc& a, const Node& n ) const { Parent::firstIn(a, n); }
+
+ void nextIn(Arc& a) const { Parent::nextOut(a); }
+ void nextOut(Arc& a) const { Parent::nextIn(a); }
+
+ Node source(const Arc& a) const { return Parent::target(a); }
+ Node target(const Arc& a) const { return Parent::source(a); }
+
+ Arc addArc(const Node& u, const Node& v) { return Parent::addArc(v, u); }
+
+ typedef FindArcTagIndicator<DGR> FindArcTag;
+ Arc findArc(const Node& u, const Node& v,
+ const Arc& prev = INVALID) const {
+ return Parent::findArc(v, u, prev);
+ }
+
+ };
+
+ /// \ingroup graph_adaptors
+ ///
+ /// \brief Adaptor class for reversing the orientation of the arcs in
+ /// a digraph.
+ ///
+ /// ReverseDigraph can be used for reversing the arcs in a digraph.
+ /// It conforms to the \ref concepts::Digraph "Digraph" concept.
+ ///
+ /// The adapted digraph can also be modified through this adaptor
+ /// by adding or removing nodes or arcs, unless the \c GR template
+ /// parameter is set to be \c const.
+ ///
+ /// This class provides item counting in the same time as the adapted
+ /// digraph structure.
+ ///
+ /// \tparam DGR The type of the adapted digraph.
+ /// It must conform to the \ref concepts::Digraph "Digraph" concept.
+ /// It can also be specified to be \c const.
+ ///
+ /// \note The \c Node and \c Arc types of this adaptor and the adapted
+ /// digraph are convertible to each other.
+ template<typename DGR>
+#ifdef DOXYGEN
+ class ReverseDigraph {
+#else
+ class ReverseDigraph :
+ public DigraphAdaptorExtender<ReverseDigraphBase<DGR> > {
+#endif
+ typedef DigraphAdaptorExtender<ReverseDigraphBase<DGR> > Parent;
+ public:
+ /// The type of the adapted digraph.
+ typedef DGR Digraph;
+ protected:
+ ReverseDigraph() { }
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Creates a reverse digraph adaptor for the given digraph.
+ explicit ReverseDigraph(DGR& digraph) {
+ Parent::initialize(digraph);
+ }
+ };
+
+ /// \brief Returns a read-only ReverseDigraph adaptor
+ ///
+ /// This function just returns a read-only \ref ReverseDigraph adaptor.
+ /// \ingroup graph_adaptors
+ /// \relates ReverseDigraph
+ template<typename DGR>
+ ReverseDigraph<const DGR> reverseDigraph(const DGR& digraph) {
+ return ReverseDigraph<const DGR>(digraph);
+ }
+
+
+ template <typename DGR, typename NF, typename AF, bool ch = true>
+ class SubDigraphBase : public DigraphAdaptorBase<DGR> {
+ typedef DigraphAdaptorBase<DGR> Parent;
+ public:
+ typedef DGR Digraph;
+ typedef NF NodeFilterMap;
+ typedef AF ArcFilterMap;
+
+ typedef SubDigraphBase Adaptor;
+ protected:
+ NF* _node_filter;
+ AF* _arc_filter;
+ SubDigraphBase()
+ : Parent(), _node_filter(0), _arc_filter(0) { }
+
+ void initialize(DGR& digraph, NF& node_filter, AF& arc_filter) {
+ Parent::initialize(digraph);
+ _node_filter = &node_filter;
+ _arc_filter = &arc_filter;
+ }
+
+ public:
+
+ typedef typename Parent::Node Node;
+ typedef typename Parent::Arc Arc;
+
+ void first(Node& i) const {
+ Parent::first(i);
+ while (i != INVALID && !(*_node_filter)[i]) Parent::next(i);
+ }
+
+ void first(Arc& i) const {
+ Parent::first(i);
+ while (i != INVALID && (!(*_arc_filter)[i]
+ || !(*_node_filter)[Parent::source(i)]
+ || !(*_node_filter)[Parent::target(i)]))
+ Parent::next(i);
+ }
+
+ void firstIn(Arc& i, const Node& n) const {
+ Parent::firstIn(i, n);
+ while (i != INVALID && (!(*_arc_filter)[i]
+ || !(*_node_filter)[Parent::source(i)]))
+ Parent::nextIn(i);
+ }
+
+ void firstOut(Arc& i, const Node& n) const {
+ Parent::firstOut(i, n);
+ while (i != INVALID && (!(*_arc_filter)[i]
+ || !(*_node_filter)[Parent::target(i)]))
+ Parent::nextOut(i);
+ }
+
+ void next(Node& i) const {
+ Parent::next(i);
+ while (i != INVALID && !(*_node_filter)[i]) Parent::next(i);
+ }
+
+ void next(Arc& i) const {
+ Parent::next(i);
+ while (i != INVALID && (!(*_arc_filter)[i]
+ || !(*_node_filter)[Parent::source(i)]
+ || !(*_node_filter)[Parent::target(i)]))
+ Parent::next(i);
+ }
+
+ void nextIn(Arc& i) const {
+ Parent::nextIn(i);
+ while (i != INVALID && (!(*_arc_filter)[i]
+ || !(*_node_filter)[Parent::source(i)]))
+ Parent::nextIn(i);
+ }
+
+ void nextOut(Arc& i) const {
+ Parent::nextOut(i);
+ while (i != INVALID && (!(*_arc_filter)[i]
+ || !(*_node_filter)[Parent::target(i)]))
+ Parent::nextOut(i);
+ }
+
+ void status(const Node& n, bool v) const { _node_filter->set(n, v); }
+ void status(const Arc& a, bool v) const { _arc_filter->set(a, v); }
+
+ bool status(const Node& n) const { return (*_node_filter)[n]; }
+ bool status(const Arc& a) const { return (*_arc_filter)[a]; }
+
+ typedef False NodeNumTag;
+ typedef False ArcNumTag;
+
+ typedef FindArcTagIndicator<DGR> FindArcTag;
+ Arc findArc(const Node& source, const Node& target,
+ const Arc& prev = INVALID) const {
+ if (!(*_node_filter)[source] || !(*_node_filter)[target]) {
+ return INVALID;
+ }
+ Arc arc = Parent::findArc(source, target, prev);
+ while (arc != INVALID && !(*_arc_filter)[arc]) {
+ arc = Parent::findArc(source, target, arc);
+ }
+ return arc;
+ }
+
+ public:
+
+ template <typename V>
+ class NodeMap
+ : public SubMapExtender<SubDigraphBase<DGR, NF, AF, ch>,
+ LEMON_SCOPE_FIX(DigraphAdaptorBase<DGR>, NodeMap<V>)> {
+ typedef SubMapExtender<SubDigraphBase<DGR, NF, AF, ch>,
+ LEMON_SCOPE_FIX(DigraphAdaptorBase<DGR>, NodeMap<V>)> Parent;
+
+ public:
+ typedef V Value;
+
+ NodeMap(const SubDigraphBase<DGR, NF, AF, ch>& adaptor)
+ : Parent(adaptor) {}
+ NodeMap(const SubDigraphBase<DGR, NF, AF, ch>& adaptor, const V& value)
+ : Parent(adaptor, value) {}
+
+ private:
+ NodeMap& operator=(const NodeMap& cmap) {
+ return operator=<NodeMap>(cmap);
+ }
+
+ template <typename CMap>
+ NodeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+ template <typename V>
+ class ArcMap
+ : public SubMapExtender<SubDigraphBase<DGR, NF, AF, ch>,
+ LEMON_SCOPE_FIX(DigraphAdaptorBase<DGR>, ArcMap<V>)> {
+ typedef SubMapExtender<SubDigraphBase<DGR, NF, AF, ch>,
+ LEMON_SCOPE_FIX(DigraphAdaptorBase<DGR>, ArcMap<V>)> Parent;
+
+ public:
+ typedef V Value;
+
+ ArcMap(const SubDigraphBase<DGR, NF, AF, ch>& adaptor)
+ : Parent(adaptor) {}
+ ArcMap(const SubDigraphBase<DGR, NF, AF, ch>& adaptor, const V& value)
+ : Parent(adaptor, value) {}
+
+ private:
+ ArcMap& operator=(const ArcMap& cmap) {
+ return operator=<ArcMap>(cmap);
+ }
+
+ template <typename CMap>
+ ArcMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+ };
+
+ template <typename DGR, typename NF, typename AF>
+ class SubDigraphBase<DGR, NF, AF, false>
+ : public DigraphAdaptorBase<DGR> {
+ typedef DigraphAdaptorBase<DGR> Parent;
+ public:
+ typedef DGR Digraph;
+ typedef NF NodeFilterMap;
+ typedef AF ArcFilterMap;
+
+ typedef SubDigraphBase Adaptor;
+ protected:
+ NF* _node_filter;
+ AF* _arc_filter;
+ SubDigraphBase()
+ : Parent(), _node_filter(0), _arc_filter(0) { }
+
+ void initialize(DGR& digraph, NF& node_filter, AF& arc_filter) {
+ Parent::initialize(digraph);
+ _node_filter = &node_filter;
+ _arc_filter = &arc_filter;
+ }
+
+ public:
+
+ typedef typename Parent::Node Node;
+ typedef typename Parent::Arc Arc;
+
+ void first(Node& i) const {
+ Parent::first(i);
+ while (i!=INVALID && !(*_node_filter)[i]) Parent::next(i);
+ }
+
+ void first(Arc& i) const {
+ Parent::first(i);
+ while (i!=INVALID && !(*_arc_filter)[i]) Parent::next(i);
+ }
+
+ void firstIn(Arc& i, const Node& n) const {
+ Parent::firstIn(i, n);
+ while (i!=INVALID && !(*_arc_filter)[i]) Parent::nextIn(i);
+ }
+
+ void firstOut(Arc& i, const Node& n) const {
+ Parent::firstOut(i, n);
+ while (i!=INVALID && !(*_arc_filter)[i]) Parent::nextOut(i);
+ }
+
+ void next(Node& i) const {
+ Parent::next(i);
+ while (i!=INVALID && !(*_node_filter)[i]) Parent::next(i);
+ }
+ void next(Arc& i) const {
+ Parent::next(i);
+ while (i!=INVALID && !(*_arc_filter)[i]) Parent::next(i);
+ }
+ void nextIn(Arc& i) const {
+ Parent::nextIn(i);
+ while (i!=INVALID && !(*_arc_filter)[i]) Parent::nextIn(i);
+ }
+
+ void nextOut(Arc& i) const {
+ Parent::nextOut(i);
+ while (i!=INVALID && !(*_arc_filter)[i]) Parent::nextOut(i);
+ }
+
+ void status(const Node& n, bool v) const { _node_filter->set(n, v); }
+ void status(const Arc& a, bool v) const { _arc_filter->set(a, v); }
+
+ bool status(const Node& n) const { return (*_node_filter)[n]; }
+ bool status(const Arc& a) const { return (*_arc_filter)[a]; }
+
+ typedef False NodeNumTag;
+ typedef False ArcNumTag;
+
+ typedef FindArcTagIndicator<DGR> FindArcTag;
+ Arc findArc(const Node& source, const Node& target,
+ const Arc& prev = INVALID) const {
+ if (!(*_node_filter)[source] || !(*_node_filter)[target]) {
+ return INVALID;
+ }
+ Arc arc = Parent::findArc(source, target, prev);
+ while (arc != INVALID && !(*_arc_filter)[arc]) {
+ arc = Parent::findArc(source, target, arc);
+ }
+ return arc;
+ }
+
+ template <typename V>
+ class NodeMap
+ : public SubMapExtender<SubDigraphBase<DGR, NF, AF, false>,
+ LEMON_SCOPE_FIX(DigraphAdaptorBase<DGR>, NodeMap<V>)> {
+ typedef SubMapExtender<SubDigraphBase<DGR, NF, AF, false>,
+ LEMON_SCOPE_FIX(DigraphAdaptorBase<DGR>, NodeMap<V>)> Parent;
+
+ public:
+ typedef V Value;
+
+ NodeMap(const SubDigraphBase<DGR, NF, AF, false>& adaptor)
+ : Parent(adaptor) {}
+ NodeMap(const SubDigraphBase<DGR, NF, AF, false>& adaptor, const V& value)
+ : Parent(adaptor, value) {}
+
+ private:
+ NodeMap& operator=(const NodeMap& cmap) {
+ return operator=<NodeMap>(cmap);
+ }
+
+ template <typename CMap>
+ NodeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+ template <typename V>
+ class ArcMap
+ : public SubMapExtender<SubDigraphBase<DGR, NF, AF, false>,
+ LEMON_SCOPE_FIX(DigraphAdaptorBase<DGR>, ArcMap<V>)> {
+ typedef SubMapExtender<SubDigraphBase<DGR, NF, AF, false>,
+ LEMON_SCOPE_FIX(DigraphAdaptorBase<DGR>, ArcMap<V>)> Parent;
+
+ public:
+ typedef V Value;
+
+ ArcMap(const SubDigraphBase<DGR, NF, AF, false>& adaptor)
+ : Parent(adaptor) {}
+ ArcMap(const SubDigraphBase<DGR, NF, AF, false>& adaptor, const V& value)
+ : Parent(adaptor, value) {}
+
+ private:
+ ArcMap& operator=(const ArcMap& cmap) {
+ return operator=<ArcMap>(cmap);
+ }
+
+ template <typename CMap>
+ ArcMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+ };
+
+ /// \ingroup graph_adaptors
+ ///
+ /// \brief Adaptor class for hiding nodes and arcs in a digraph
+ ///
+ /// SubDigraph can be used for hiding nodes and arcs in a digraph.
+ /// A \c bool node map and a \c bool arc map must be specified, which
+ /// define the filters for nodes and arcs.
+ /// Only the nodes and arcs with \c true filter value are
+ /// shown in the subdigraph. The arcs that are incident to hidden
+ /// nodes are also filtered out.
+ /// This adaptor conforms to the \ref concepts::Digraph "Digraph" concept.
+ ///
+ /// The adapted digraph can also be modified through this adaptor
+ /// by adding or removing nodes or arcs, unless the \c GR template
+ /// parameter is set to be \c const.
+ ///
+ /// This class provides only linear time counting for nodes and arcs.
+ ///
+ /// \tparam DGR The type of the adapted digraph.
+ /// It must conform to the \ref concepts::Digraph "Digraph" concept.
+ /// It can also be specified to be \c const.
+ /// \tparam NF The type of the node filter map.
+ /// It must be a \c bool (or convertible) node map of the
+ /// adapted digraph. The default type is
+ /// \ref concepts::Digraph::NodeMap "DGR::NodeMap<bool>".
+ /// \tparam AF The type of the arc filter map.
+ /// It must be \c bool (or convertible) arc map of the
+ /// adapted digraph. The default type is
+ /// \ref concepts::Digraph::ArcMap "DGR::ArcMap<bool>".
+ ///
+ /// \note The \c Node and \c Arc types of this adaptor and the adapted
+ /// digraph are convertible to each other.
+ ///
+ /// \see FilterNodes
+ /// \see FilterArcs
+#ifdef DOXYGEN
+ template<typename DGR, typename NF, typename AF>
+ class SubDigraph {
+#else
+ template<typename DGR,
+ typename NF = typename DGR::template NodeMap<bool>,
+ typename AF = typename DGR::template ArcMap<bool> >
+ class SubDigraph :
+ public DigraphAdaptorExtender<SubDigraphBase<DGR, NF, AF, true> > {
+#endif
+ public:
+ /// The type of the adapted digraph.
+ typedef DGR Digraph;
+ /// The type of the node filter map.
+ typedef NF NodeFilterMap;
+ /// The type of the arc filter map.
+ typedef AF ArcFilterMap;
+
+ typedef DigraphAdaptorExtender<SubDigraphBase<DGR, NF, AF, true> >
+ Parent;
+
+ typedef typename Parent::Node Node;
+ typedef typename Parent::Arc Arc;
+
+ protected:
+ SubDigraph() { }
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Creates a subdigraph for the given digraph with the
+ /// given node and arc filter maps.
+ SubDigraph(DGR& digraph, NF& node_filter, AF& arc_filter) {
+ Parent::initialize(digraph, node_filter, arc_filter);
+ }
+
+ /// \brief Sets the status of the given node
+ ///
+ /// This function sets the status of the given node.
+ /// It is done by simply setting the assigned value of \c n
+ /// to \c v in the node filter map.
+ void status(const Node& n, bool v) const { Parent::status(n, v); }
+
+ /// \brief Sets the status of the given arc
+ ///
+ /// This function sets the status of the given arc.
+ /// It is done by simply setting the assigned value of \c a
+ /// to \c v in the arc filter map.
+ void status(const Arc& a, bool v) const { Parent::status(a, v); }
+
+ /// \brief Returns the status of the given node
+ ///
+ /// This function returns the status of the given node.
+ /// It is \c true if the given node is enabled (i.e. not hidden).
+ bool status(const Node& n) const { return Parent::status(n); }
+
+ /// \brief Returns the status of the given arc
+ ///
+ /// This function returns the status of the given arc.
+ /// It is \c true if the given arc is enabled (i.e. not hidden).
+ bool status(const Arc& a) const { return Parent::status(a); }
+
+ /// \brief Disables the given node
+ ///
+ /// This function disables the given node in the subdigraph,
+ /// so the iteration jumps over it.
+ /// It is the same as \ref status() "status(n, false)".
+ void disable(const Node& n) const { Parent::status(n, false); }
+
+ /// \brief Disables the given arc
+ ///
+ /// This function disables the given arc in the subdigraph,
+ /// so the iteration jumps over it.
+ /// It is the same as \ref status() "status(a, false)".
+ void disable(const Arc& a) const { Parent::status(a, false); }
+
+ /// \brief Enables the given node
+ ///
+ /// This function enables the given node in the subdigraph.
+ /// It is the same as \ref status() "status(n, true)".
+ void enable(const Node& n) const { Parent::status(n, true); }
+
+ /// \brief Enables the given arc
+ ///
+ /// This function enables the given arc in the subdigraph.
+ /// It is the same as \ref status() "status(a, true)".
+ void enable(const Arc& a) const { Parent::status(a, true); }
+
+ };
+
+ /// \brief Returns a read-only SubDigraph adaptor
+ ///
+ /// This function just returns a read-only \ref SubDigraph adaptor.
+ /// \ingroup graph_adaptors
+ /// \relates SubDigraph
+ template<typename DGR, typename NF, typename AF>
+ SubDigraph<const DGR, NF, AF>
+ subDigraph(const DGR& digraph,
+ NF& node_filter, AF& arc_filter) {
+ return SubDigraph<const DGR, NF, AF>
+ (digraph, node_filter, arc_filter);
+ }
+
+ template<typename DGR, typename NF, typename AF>
+ SubDigraph<const DGR, const NF, AF>
+ subDigraph(const DGR& digraph,
+ const NF& node_filter, AF& arc_filter) {
+ return SubDigraph<const DGR, const NF, AF>
+ (digraph, node_filter, arc_filter);
+ }
+
+ template<typename DGR, typename NF, typename AF>
+ SubDigraph<const DGR, NF, const AF>
+ subDigraph(const DGR& digraph,
+ NF& node_filter, const AF& arc_filter) {
+ return SubDigraph<const DGR, NF, const AF>
+ (digraph, node_filter, arc_filter);
+ }
+
+ template<typename DGR, typename NF, typename AF>
+ SubDigraph<const DGR, const NF, const AF>
+ subDigraph(const DGR& digraph,
+ const NF& node_filter, const AF& arc_filter) {
+ return SubDigraph<const DGR, const NF, const AF>
+ (digraph, node_filter, arc_filter);
+ }
+
+
+ template <typename GR, typename NF, typename EF, bool ch = true>
+ class SubGraphBase : public GraphAdaptorBase<GR> {
+ typedef GraphAdaptorBase<GR> Parent;
+ public:
+ typedef GR Graph;
+ typedef NF NodeFilterMap;
+ typedef EF EdgeFilterMap;
+
+ typedef SubGraphBase Adaptor;
+ protected:
+
+ NF* _node_filter;
+ EF* _edge_filter;
+
+ SubGraphBase()
+ : Parent(), _node_filter(0), _edge_filter(0) { }
+
+ void initialize(GR& graph, NF& node_filter, EF& edge_filter) {
+ Parent::initialize(graph);
+ _node_filter = &node_filter;
+ _edge_filter = &edge_filter;
+ }
+
+ public:
+
+ typedef typename Parent::Node Node;
+ typedef typename Parent::Arc Arc;
+ typedef typename Parent::Edge Edge;
+
+ void first(Node& i) const {
+ Parent::first(i);
+ while (i!=INVALID && !(*_node_filter)[i]) Parent::next(i);
+ }
+
+ void first(Arc& i) const {
+ Parent::first(i);
+ while (i!=INVALID && (!(*_edge_filter)[i]
+ || !(*_node_filter)[Parent::source(i)]
+ || !(*_node_filter)[Parent::target(i)]))
+ Parent::next(i);
+ }
+
+ void first(Edge& i) const {
+ Parent::first(i);
+ while (i!=INVALID && (!(*_edge_filter)[i]
+ || !(*_node_filter)[Parent::u(i)]
+ || !(*_node_filter)[Parent::v(i)]))
+ Parent::next(i);
+ }
+
+ void firstIn(Arc& i, const Node& n) const {
+ Parent::firstIn(i, n);
+ while (i!=INVALID && (!(*_edge_filter)[i]
+ || !(*_node_filter)[Parent::source(i)]))
+ Parent::nextIn(i);
+ }
+
+ void firstOut(Arc& i, const Node& n) const {
+ Parent::firstOut(i, n);
+ while (i!=INVALID && (!(*_edge_filter)[i]
+ || !(*_node_filter)[Parent::target(i)]))
+ Parent::nextOut(i);
+ }
+
+ void firstInc(Edge& i, bool& d, const Node& n) const {
+ Parent::firstInc(i, d, n);
+ while (i!=INVALID && (!(*_edge_filter)[i]
+ || !(*_node_filter)[Parent::u(i)]
+ || !(*_node_filter)[Parent::v(i)]))
+ Parent::nextInc(i, d);
+ }
+
+ void next(Node& i) const {
+ Parent::next(i);
+ while (i!=INVALID && !(*_node_filter)[i]) Parent::next(i);
+ }
+
+ void next(Arc& i) const {
+ Parent::next(i);
+ while (i!=INVALID && (!(*_edge_filter)[i]
+ || !(*_node_filter)[Parent::source(i)]
+ || !(*_node_filter)[Parent::target(i)]))
+ Parent::next(i);
+ }
+
+ void next(Edge& i) const {
+ Parent::next(i);
+ while (i!=INVALID && (!(*_edge_filter)[i]
+ || !(*_node_filter)[Parent::u(i)]
+ || !(*_node_filter)[Parent::v(i)]))
+ Parent::next(i);
+ }
+
+ void nextIn(Arc& i) const {
+ Parent::nextIn(i);
+ while (i!=INVALID && (!(*_edge_filter)[i]
+ || !(*_node_filter)[Parent::source(i)]))
+ Parent::nextIn(i);
+ }
+
+ void nextOut(Arc& i) const {
+ Parent::nextOut(i);
+ while (i!=INVALID && (!(*_edge_filter)[i]
+ || !(*_node_filter)[Parent::target(i)]))
+ Parent::nextOut(i);
+ }
+
+ void nextInc(Edge& i, bool& d) const {
+ Parent::nextInc(i, d);
+ while (i!=INVALID && (!(*_edge_filter)[i]
+ || !(*_node_filter)[Parent::u(i)]
+ || !(*_node_filter)[Parent::v(i)]))
+ Parent::nextInc(i, d);
+ }
+
+ void status(const Node& n, bool v) const { _node_filter->set(n, v); }
+ void status(const Edge& e, bool v) const { _edge_filter->set(e, v); }
+
+ bool status(const Node& n) const { return (*_node_filter)[n]; }
+ bool status(const Edge& e) const { return (*_edge_filter)[e]; }
+
+ typedef False NodeNumTag;
+ typedef False ArcNumTag;
+ typedef False EdgeNumTag;
+
+ typedef FindArcTagIndicator<Graph> FindArcTag;
+ Arc findArc(const Node& u, const Node& v,
+ const Arc& prev = INVALID) const {
+ if (!(*_node_filter)[u] || !(*_node_filter)[v]) {
+ return INVALID;
+ }
+ Arc arc = Parent::findArc(u, v, prev);
+ while (arc != INVALID && !(*_edge_filter)[arc]) {
+ arc = Parent::findArc(u, v, arc);
+ }
+ return arc;
+ }
+
+ typedef FindEdgeTagIndicator<Graph> FindEdgeTag;
+ Edge findEdge(const Node& u, const Node& v,
+ const Edge& prev = INVALID) const {
+ if (!(*_node_filter)[u] || !(*_node_filter)[v]) {
+ return INVALID;
+ }
+ Edge edge = Parent::findEdge(u, v, prev);
+ while (edge != INVALID && !(*_edge_filter)[edge]) {
+ edge = Parent::findEdge(u, v, edge);
+ }
+ return edge;
+ }
+
+ template <typename V>
+ class NodeMap
+ : public SubMapExtender<SubGraphBase<GR, NF, EF, ch>,
+ LEMON_SCOPE_FIX(GraphAdaptorBase<GR>, NodeMap<V>)> {
+ typedef SubMapExtender<SubGraphBase<GR, NF, EF, ch>,
+ LEMON_SCOPE_FIX(GraphAdaptorBase<GR>, NodeMap<V>)> Parent;
+
+ public:
+ typedef V Value;
+
+ NodeMap(const SubGraphBase<GR, NF, EF, ch>& adaptor)
+ : Parent(adaptor) {}
+ NodeMap(const SubGraphBase<GR, NF, EF, ch>& adaptor, const V& value)
+ : Parent(adaptor, value) {}
+
+ private:
+ NodeMap& operator=(const NodeMap& cmap) {
+ return operator=<NodeMap>(cmap);
+ }
+
+ template <typename CMap>
+ NodeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+ template <typename V>
+ class ArcMap
+ : public SubMapExtender<SubGraphBase<GR, NF, EF, ch>,
+ LEMON_SCOPE_FIX(GraphAdaptorBase<GR>, ArcMap<V>)> {
+ typedef SubMapExtender<SubGraphBase<GR, NF, EF, ch>,
+ LEMON_SCOPE_FIX(GraphAdaptorBase<GR>, ArcMap<V>)> Parent;
+
+ public:
+ typedef V Value;
+
+ ArcMap(const SubGraphBase<GR, NF, EF, ch>& adaptor)
+ : Parent(adaptor) {}
+ ArcMap(const SubGraphBase<GR, NF, EF, ch>& adaptor, const V& value)
+ : Parent(adaptor, value) {}
+
+ private:
+ ArcMap& operator=(const ArcMap& cmap) {
+ return operator=<ArcMap>(cmap);
+ }
+
+ template <typename CMap>
+ ArcMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+ template <typename V>
+ class EdgeMap
+ : public SubMapExtender<SubGraphBase<GR, NF, EF, ch>,
+ LEMON_SCOPE_FIX(GraphAdaptorBase<GR>, EdgeMap<V>)> {
+ typedef SubMapExtender<SubGraphBase<GR, NF, EF, ch>,
+ LEMON_SCOPE_FIX(GraphAdaptorBase<GR>, EdgeMap<V>)> Parent;
+
+ public:
+ typedef V Value;
+
+ EdgeMap(const SubGraphBase<GR, NF, EF, ch>& adaptor)
+ : Parent(adaptor) {}
+
+ EdgeMap(const SubGraphBase<GR, NF, EF, ch>& adaptor, const V& value)
+ : Parent(adaptor, value) {}
+
+ private:
+ EdgeMap& operator=(const EdgeMap& cmap) {
+ return operator=<EdgeMap>(cmap);
+ }
+
+ template <typename CMap>
+ EdgeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+ };
+
+ template <typename GR, typename NF, typename EF>
+ class SubGraphBase<GR, NF, EF, false>
+ : public GraphAdaptorBase<GR> {
+ typedef GraphAdaptorBase<GR> Parent;
+ public:
+ typedef GR Graph;
+ typedef NF NodeFilterMap;
+ typedef EF EdgeFilterMap;
+
+ typedef SubGraphBase Adaptor;
+ protected:
+ NF* _node_filter;
+ EF* _edge_filter;
+ SubGraphBase()
+ : Parent(), _node_filter(0), _edge_filter(0) { }
+
+ void initialize(GR& graph, NF& node_filter, EF& edge_filter) {
+ Parent::initialize(graph);
+ _node_filter = &node_filter;
+ _edge_filter = &edge_filter;
+ }
+
+ public:
+
+ typedef typename Parent::Node Node;
+ typedef typename Parent::Arc Arc;
+ typedef typename Parent::Edge Edge;
+
+ void first(Node& i) const {
+ Parent::first(i);
+ while (i!=INVALID && !(*_node_filter)[i]) Parent::next(i);
+ }
+
+ void first(Arc& i) const {
+ Parent::first(i);
+ while (i!=INVALID && !(*_edge_filter)[i]) Parent::next(i);
+ }
+
+ void first(Edge& i) const {
+ Parent::first(i);
+ while (i!=INVALID && !(*_edge_filter)[i]) Parent::next(i);
+ }
+
+ void firstIn(Arc& i, const Node& n) const {
+ Parent::firstIn(i, n);
+ while (i!=INVALID && !(*_edge_filter)[i]) Parent::nextIn(i);
+ }
+
+ void firstOut(Arc& i, const Node& n) const {
+ Parent::firstOut(i, n);
+ while (i!=INVALID && !(*_edge_filter)[i]) Parent::nextOut(i);
+ }
+
+ void firstInc(Edge& i, bool& d, const Node& n) const {
+ Parent::firstInc(i, d, n);
+ while (i!=INVALID && !(*_edge_filter)[i]) Parent::nextInc(i, d);
+ }
+
+ void next(Node& i) const {
+ Parent::next(i);
+ while (i!=INVALID && !(*_node_filter)[i]) Parent::next(i);
+ }
+ void next(Arc& i) const {
+ Parent::next(i);
+ while (i!=INVALID && !(*_edge_filter)[i]) Parent::next(i);
+ }
+ void next(Edge& i) const {
+ Parent::next(i);
+ while (i!=INVALID && !(*_edge_filter)[i]) Parent::next(i);
+ }
+ void nextIn(Arc& i) const {
+ Parent::nextIn(i);
+ while (i!=INVALID && !(*_edge_filter)[i]) Parent::nextIn(i);
+ }
+
+ void nextOut(Arc& i) const {
+ Parent::nextOut(i);
+ while (i!=INVALID && !(*_edge_filter)[i]) Parent::nextOut(i);
+ }
+ void nextInc(Edge& i, bool& d) const {
+ Parent::nextInc(i, d);
+ while (i!=INVALID && !(*_edge_filter)[i]) Parent::nextInc(i, d);
+ }
+
+ void status(const Node& n, bool v) const { _node_filter->set(n, v); }
+ void status(const Edge& e, bool v) const { _edge_filter->set(e, v); }
+
+ bool status(const Node& n) const { return (*_node_filter)[n]; }
+ bool status(const Edge& e) const { return (*_edge_filter)[e]; }
+
+ typedef False NodeNumTag;
+ typedef False ArcNumTag;
+ typedef False EdgeNumTag;
+
+ typedef FindArcTagIndicator<Graph> FindArcTag;
+ Arc findArc(const Node& u, const Node& v,
+ const Arc& prev = INVALID) const {
+ Arc arc = Parent::findArc(u, v, prev);
+ while (arc != INVALID && !(*_edge_filter)[arc]) {
+ arc = Parent::findArc(u, v, arc);
+ }
+ return arc;
+ }
+
+ typedef FindEdgeTagIndicator<Graph> FindEdgeTag;
+ Edge findEdge(const Node& u, const Node& v,
+ const Edge& prev = INVALID) const {
+ Edge edge = Parent::findEdge(u, v, prev);
+ while (edge != INVALID && !(*_edge_filter)[edge]) {
+ edge = Parent::findEdge(u, v, edge);
+ }
+ return edge;
+ }
+
+ template <typename V>
+ class NodeMap
+ : public SubMapExtender<SubGraphBase<GR, NF, EF, false>,
+ LEMON_SCOPE_FIX(GraphAdaptorBase<GR>, NodeMap<V>)> {
+ typedef SubMapExtender<SubGraphBase<GR, NF, EF, false>,
+ LEMON_SCOPE_FIX(GraphAdaptorBase<GR>, NodeMap<V>)> Parent;
+
+ public:
+ typedef V Value;
+
+ NodeMap(const SubGraphBase<GR, NF, EF, false>& adaptor)
+ : Parent(adaptor) {}
+ NodeMap(const SubGraphBase<GR, NF, EF, false>& adaptor, const V& value)
+ : Parent(adaptor, value) {}
+
+ private:
+ NodeMap& operator=(const NodeMap& cmap) {
+ return operator=<NodeMap>(cmap);
+ }
+
+ template <typename CMap>
+ NodeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+ template <typename V>
+ class ArcMap
+ : public SubMapExtender<SubGraphBase<GR, NF, EF, false>,
+ LEMON_SCOPE_FIX(GraphAdaptorBase<GR>, ArcMap<V>)> {
+ typedef SubMapExtender<SubGraphBase<GR, NF, EF, false>,
+ LEMON_SCOPE_FIX(GraphAdaptorBase<GR>, ArcMap<V>)> Parent;
+
+ public:
+ typedef V Value;
+
+ ArcMap(const SubGraphBase<GR, NF, EF, false>& adaptor)
+ : Parent(adaptor) {}
+ ArcMap(const SubGraphBase<GR, NF, EF, false>& adaptor, const V& value)
+ : Parent(adaptor, value) {}
+
+ private:
+ ArcMap& operator=(const ArcMap& cmap) {
+ return operator=<ArcMap>(cmap);
+ }
+
+ template <typename CMap>
+ ArcMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+ template <typename V>
+ class EdgeMap
+ : public SubMapExtender<SubGraphBase<GR, NF, EF, false>,
+ LEMON_SCOPE_FIX(GraphAdaptorBase<GR>, EdgeMap<V>)> {
+ typedef SubMapExtender<SubGraphBase<GR, NF, EF, false>,
+ LEMON_SCOPE_FIX(GraphAdaptorBase<GR>, EdgeMap<V>)> Parent;
+
+ public:
+ typedef V Value;
+
+ EdgeMap(const SubGraphBase<GR, NF, EF, false>& adaptor)
+ : Parent(adaptor) {}
+
+ EdgeMap(const SubGraphBase<GR, NF, EF, false>& adaptor, const V& value)
+ : Parent(adaptor, value) {}
+
+ private:
+ EdgeMap& operator=(const EdgeMap& cmap) {
+ return operator=<EdgeMap>(cmap);
+ }
+
+ template <typename CMap>
+ EdgeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+ };
+
+ /// \ingroup graph_adaptors
+ ///
+ /// \brief Adaptor class for hiding nodes and edges in an undirected
+ /// graph.
+ ///
+ /// SubGraph can be used for hiding nodes and edges in a graph.
+ /// A \c bool node map and a \c bool edge map must be specified, which
+ /// define the filters for nodes and edges.
+ /// Only the nodes and edges with \c true filter value are
+ /// shown in the subgraph. The edges that are incident to hidden
+ /// nodes are also filtered out.
+ /// This adaptor conforms to the \ref concepts::Graph "Graph" concept.
+ ///
+ /// The adapted graph can also be modified through this adaptor
+ /// by adding or removing nodes or edges, unless the \c GR template
+ /// parameter is set to be \c const.
+ ///
+ /// This class provides only linear time counting for nodes, edges and arcs.
+ ///
+ /// \tparam GR The type of the adapted graph.
+ /// It must conform to the \ref concepts::Graph "Graph" concept.
+ /// It can also be specified to be \c const.
+ /// \tparam NF The type of the node filter map.
+ /// It must be a \c bool (or convertible) node map of the
+ /// adapted graph. The default type is
+ /// \ref concepts::Graph::NodeMap "GR::NodeMap<bool>".
+ /// \tparam EF The type of the edge filter map.
+ /// It must be a \c bool (or convertible) edge map of the
+ /// adapted graph. The default type is
+ /// \ref concepts::Graph::EdgeMap "GR::EdgeMap<bool>".
+ ///
+ /// \note The \c Node, \c Edge and \c Arc types of this adaptor and the
+ /// adapted graph are convertible to each other.
+ ///
+ /// \see FilterNodes
+ /// \see FilterEdges
+#ifdef DOXYGEN
+ template<typename GR, typename NF, typename EF>
+ class SubGraph {
+#else
+ template<typename GR,
+ typename NF = typename GR::template NodeMap<bool>,
+ typename EF = typename GR::template EdgeMap<bool> >
+ class SubGraph :
+ public GraphAdaptorExtender<SubGraphBase<GR, NF, EF, true> > {
+#endif
+ public:
+ /// The type of the adapted graph.
+ typedef GR Graph;
+ /// The type of the node filter map.
+ typedef NF NodeFilterMap;
+ /// The type of the edge filter map.
+ typedef EF EdgeFilterMap;
+
+ typedef GraphAdaptorExtender<SubGraphBase<GR, NF, EF, true> >
+ Parent;
+
+ typedef typename Parent::Node Node;
+ typedef typename Parent::Edge Edge;
+
+ protected:
+ SubGraph() { }
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Creates a subgraph for the given graph with the given node
+ /// and edge filter maps.
+ SubGraph(GR& graph, NF& node_filter, EF& edge_filter) {
+ this->initialize(graph, node_filter, edge_filter);
+ }
+
+ /// \brief Sets the status of the given node
+ ///
+ /// This function sets the status of the given node.
+ /// It is done by simply setting the assigned value of \c n
+ /// to \c v in the node filter map.
+ void status(const Node& n, bool v) const { Parent::status(n, v); }
+
+ /// \brief Sets the status of the given edge
+ ///
+ /// This function sets the status of the given edge.
+ /// It is done by simply setting the assigned value of \c e
+ /// to \c v in the edge filter map.
+ void status(const Edge& e, bool v) const { Parent::status(e, v); }
+
+ /// \brief Returns the status of the given node
+ ///
+ /// This function returns the status of the given node.
+ /// It is \c true if the given node is enabled (i.e. not hidden).
+ bool status(const Node& n) const { return Parent::status(n); }
+
+ /// \brief Returns the status of the given edge
+ ///
+ /// This function returns the status of the given edge.
+ /// It is \c true if the given edge is enabled (i.e. not hidden).
+ bool status(const Edge& e) const { return Parent::status(e); }
+
+ /// \brief Disables the given node
+ ///
+ /// This function disables the given node in the subdigraph,
+ /// so the iteration jumps over it.
+ /// It is the same as \ref status() "status(n, false)".
+ void disable(const Node& n) const { Parent::status(n, false); }
+
+ /// \brief Disables the given edge
+ ///
+ /// This function disables the given edge in the subgraph,
+ /// so the iteration jumps over it.
+ /// It is the same as \ref status() "status(e, false)".
+ void disable(const Edge& e) const { Parent::status(e, false); }
+
+ /// \brief Enables the given node
+ ///
+ /// This function enables the given node in the subdigraph.
+ /// It is the same as \ref status() "status(n, true)".
+ void enable(const Node& n) const { Parent::status(n, true); }
+
+ /// \brief Enables the given edge
+ ///
+ /// This function enables the given edge in the subgraph.
+ /// It is the same as \ref status() "status(e, true)".
+ void enable(const Edge& e) const { Parent::status(e, true); }
+
+ };
+
+ /// \brief Returns a read-only SubGraph adaptor
+ ///
+ /// This function just returns a read-only \ref SubGraph adaptor.
+ /// \ingroup graph_adaptors
+ /// \relates SubGraph
+ template<typename GR, typename NF, typename EF>
+ SubGraph<const GR, NF, EF>
+ subGraph(const GR& graph, NF& node_filter, EF& edge_filter) {
+ return SubGraph<const GR, NF, EF>
+ (graph, node_filter, edge_filter);
+ }
+
+ template<typename GR, typename NF, typename EF>
+ SubGraph<const GR, const NF, EF>
+ subGraph(const GR& graph, const NF& node_filter, EF& edge_filter) {
+ return SubGraph<const GR, const NF, EF>
+ (graph, node_filter, edge_filter);
+ }
+
+ template<typename GR, typename NF, typename EF>
+ SubGraph<const GR, NF, const EF>
+ subGraph(const GR& graph, NF& node_filter, const EF& edge_filter) {
+ return SubGraph<const GR, NF, const EF>
+ (graph, node_filter, edge_filter);
+ }
+
+ template<typename GR, typename NF, typename EF>
+ SubGraph<const GR, const NF, const EF>
+ subGraph(const GR& graph, const NF& node_filter, const EF& edge_filter) {
+ return SubGraph<const GR, const NF, const EF>
+ (graph, node_filter, edge_filter);
+ }
+
+
+ /// \ingroup graph_adaptors
+ ///
+ /// \brief Adaptor class for hiding nodes in a digraph or a graph.
+ ///
+ /// FilterNodes adaptor can be used for hiding nodes in a digraph or a
+ /// graph. A \c bool node map must be specified, which defines the filter
+ /// for the nodes. Only the nodes with \c true filter value and the
+ /// arcs/edges incident to nodes both with \c true filter value are shown
+ /// in the subgraph. This adaptor conforms to the \ref concepts::Digraph
+ /// "Digraph" concept or the \ref concepts::Graph "Graph" concept
+ /// depending on the \c GR template parameter.
+ ///
+ /// The adapted (di)graph can also be modified through this adaptor
+ /// by adding or removing nodes or arcs/edges, unless the \c GR template
+ /// parameter is set to be \c const.
+ ///
+ /// This class provides only linear time item counting.
+ ///
+ /// \tparam GR The type of the adapted digraph or graph.
+ /// It must conform to the \ref concepts::Digraph "Digraph" concept
+ /// or the \ref concepts::Graph "Graph" concept.
+ /// It can also be specified to be \c const.
+ /// \tparam NF The type of the node filter map.
+ /// It must be a \c bool (or convertible) node map of the
+ /// adapted (di)graph. The default type is
+ /// \ref concepts::Graph::NodeMap "GR::NodeMap<bool>".
+ ///
+ /// \note The \c Node and <tt>Arc/Edge</tt> types of this adaptor and the
+ /// adapted (di)graph are convertible to each other.
+#ifdef DOXYGEN
+ template<typename GR, typename NF>
+ class FilterNodes {
+#else
+ template<typename GR,
+ typename NF = typename GR::template NodeMap<bool>,
+ typename Enable = void>
+ class FilterNodes :
+ public DigraphAdaptorExtender<
+ SubDigraphBase<GR, NF, ConstMap<typename GR::Arc, Const<bool, true> >,
+ true> > {
+#endif
+ typedef DigraphAdaptorExtender<
+ SubDigraphBase<GR, NF, ConstMap<typename GR::Arc, Const<bool, true> >,
+ true> > Parent;
+
+ public:
+
+ typedef GR Digraph;
+ typedef NF NodeFilterMap;
+
+ typedef typename Parent::Node Node;
+
+ protected:
+ ConstMap<typename Digraph::Arc, Const<bool, true> > const_true_map;
+
+ FilterNodes() : const_true_map() {}
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Creates a subgraph for the given digraph or graph with the
+ /// given node filter map.
+ FilterNodes(GR& graph, NF& node_filter)
+ : Parent(), const_true_map()
+ {
+ Parent::initialize(graph, node_filter, const_true_map);
+ }
+
+ /// \brief Sets the status of the given node
+ ///
+ /// This function sets the status of the given node.
+ /// It is done by simply setting the assigned value of \c n
+ /// to \c v in the node filter map.
+ void status(const Node& n, bool v) const { Parent::status(n, v); }
+
+ /// \brief Returns the status of the given node
+ ///
+ /// This function returns the status of the given node.
+ /// It is \c true if the given node is enabled (i.e. not hidden).
+ bool status(const Node& n) const { return Parent::status(n); }
+
+ /// \brief Disables the given node
+ ///
+ /// This function disables the given node, so the iteration
+ /// jumps over it.
+ /// It is the same as \ref status() "status(n, false)".
+ void disable(const Node& n) const { Parent::status(n, false); }
+
+ /// \brief Enables the given node
+ ///
+ /// This function enables the given node.
+ /// It is the same as \ref status() "status(n, true)".
+ void enable(const Node& n) const { Parent::status(n, true); }
+
+ };
+
+ template<typename GR, typename NF>
+ class FilterNodes<GR, NF,
+ typename enable_if<UndirectedTagIndicator<GR> >::type> :
+ public GraphAdaptorExtender<
+ SubGraphBase<GR, NF, ConstMap<typename GR::Edge, Const<bool, true> >,
+ true> > {
+
+ typedef GraphAdaptorExtender<
+ SubGraphBase<GR, NF, ConstMap<typename GR::Edge, Const<bool, true> >,
+ true> > Parent;
+
+ public:
+
+ typedef GR Graph;
+ typedef NF NodeFilterMap;
+
+ typedef typename Parent::Node Node;
+
+ protected:
+ ConstMap<typename GR::Edge, Const<bool, true> > const_true_map;
+
+ FilterNodes() : const_true_map() {}
+
+ public:
+
+ FilterNodes(GR& graph, NodeFilterMap& node_filter) :
+ Parent(), const_true_map() {
+ Parent::initialize(graph, node_filter, const_true_map);
+ }
+
+ void status(const Node& n, bool v) const { Parent::status(n, v); }
+ bool status(const Node& n) const { return Parent::status(n); }
+ void disable(const Node& n) const { Parent::status(n, false); }
+ void enable(const Node& n) const { Parent::status(n, true); }
+
+ };
+
+
+ /// \brief Returns a read-only FilterNodes adaptor
+ ///
+ /// This function just returns a read-only \ref FilterNodes adaptor.
+ /// \ingroup graph_adaptors
+ /// \relates FilterNodes
+ template<typename GR, typename NF>
+ FilterNodes<const GR, NF>
+ filterNodes(const GR& graph, NF& node_filter) {
+ return FilterNodes<const GR, NF>(graph, node_filter);
+ }
+
+ template<typename GR, typename NF>
+ FilterNodes<const GR, const NF>
+ filterNodes(const GR& graph, const NF& node_filter) {
+ return FilterNodes<const GR, const NF>(graph, node_filter);
+ }
+
+ /// \ingroup graph_adaptors
+ ///
+ /// \brief Adaptor class for hiding arcs in a digraph.
+ ///
+ /// FilterArcs adaptor can be used for hiding arcs in a digraph.
+ /// A \c bool arc map must be specified, which defines the filter for
+ /// the arcs. Only the arcs with \c true filter value are shown in the
+ /// subdigraph. This adaptor conforms to the \ref concepts::Digraph
+ /// "Digraph" concept.
+ ///
+ /// The adapted digraph can also be modified through this adaptor
+ /// by adding or removing nodes or arcs, unless the \c GR template
+ /// parameter is set to be \c const.
+ ///
+ /// This class provides only linear time counting for nodes and arcs.
+ ///
+ /// \tparam DGR The type of the adapted digraph.
+ /// It must conform to the \ref concepts::Digraph "Digraph" concept.
+ /// It can also be specified to be \c const.
+ /// \tparam AF The type of the arc filter map.
+ /// It must be a \c bool (or convertible) arc map of the
+ /// adapted digraph. The default type is
+ /// \ref concepts::Digraph::ArcMap "DGR::ArcMap<bool>".
+ ///
+ /// \note The \c Node and \c Arc types of this adaptor and the adapted
+ /// digraph are convertible to each other.
+#ifdef DOXYGEN
+ template<typename DGR,
+ typename AF>
+ class FilterArcs {
+#else
+ template<typename DGR,
+ typename AF = typename DGR::template ArcMap<bool> >
+ class FilterArcs :
+ public DigraphAdaptorExtender<
+ SubDigraphBase<DGR, ConstMap<typename DGR::Node, Const<bool, true> >,
+ AF, false> > {
+#endif
+ typedef DigraphAdaptorExtender<
+ SubDigraphBase<DGR, ConstMap<typename DGR::Node, Const<bool, true> >,
+ AF, false> > Parent;
+
+ public:
+
+ /// The type of the adapted digraph.
+ typedef DGR Digraph;
+ /// The type of the arc filter map.
+ typedef AF ArcFilterMap;
+
+ typedef typename Parent::Arc Arc;
+
+ protected:
+ ConstMap<typename DGR::Node, Const<bool, true> > const_true_map;
+
+ FilterArcs() : const_true_map() {}
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Creates a subdigraph for the given digraph with the given arc
+ /// filter map.
+ FilterArcs(DGR& digraph, ArcFilterMap& arc_filter)
+ : Parent(), const_true_map() {
+ Parent::initialize(digraph, const_true_map, arc_filter);
+ }
+
+ /// \brief Sets the status of the given arc
+ ///
+ /// This function sets the status of the given arc.
+ /// It is done by simply setting the assigned value of \c a
+ /// to \c v in the arc filter map.
+ void status(const Arc& a, bool v) const { Parent::status(a, v); }
+
+ /// \brief Returns the status of the given arc
+ ///
+ /// This function returns the status of the given arc.
+ /// It is \c true if the given arc is enabled (i.e. not hidden).
+ bool status(const Arc& a) const { return Parent::status(a); }
+
+ /// \brief Disables the given arc
+ ///
+ /// This function disables the given arc in the subdigraph,
+ /// so the iteration jumps over it.
+ /// It is the same as \ref status() "status(a, false)".
+ void disable(const Arc& a) const { Parent::status(a, false); }
+
+ /// \brief Enables the given arc
+ ///
+ /// This function enables the given arc in the subdigraph.
+ /// It is the same as \ref status() "status(a, true)".
+ void enable(const Arc& a) const { Parent::status(a, true); }
+
+ };
+
+ /// \brief Returns a read-only FilterArcs adaptor
+ ///
+ /// This function just returns a read-only \ref FilterArcs adaptor.
+ /// \ingroup graph_adaptors
+ /// \relates FilterArcs
+ template<typename DGR, typename AF>
+ FilterArcs<const DGR, AF>
+ filterArcs(const DGR& digraph, AF& arc_filter) {
+ return FilterArcs<const DGR, AF>(digraph, arc_filter);
+ }
+
+ template<typename DGR, typename AF>
+ FilterArcs<const DGR, const AF>
+ filterArcs(const DGR& digraph, const AF& arc_filter) {
+ return FilterArcs<const DGR, const AF>(digraph, arc_filter);
+ }
+
+ /// \ingroup graph_adaptors
+ ///
+ /// \brief Adaptor class for hiding edges in a graph.
+ ///
+ /// FilterEdges adaptor can be used for hiding edges in a graph.
+ /// A \c bool edge map must be specified, which defines the filter for
+ /// the edges. Only the edges with \c true filter value are shown in the
+ /// subgraph. This adaptor conforms to the \ref concepts::Graph
+ /// "Graph" concept.
+ ///
+ /// The adapted graph can also be modified through this adaptor
+ /// by adding or removing nodes or edges, unless the \c GR template
+ /// parameter is set to be \c const.
+ ///
+ /// This class provides only linear time counting for nodes, edges and arcs.
+ ///
+ /// \tparam GR The type of the adapted graph.
+ /// It must conform to the \ref concepts::Graph "Graph" concept.
+ /// It can also be specified to be \c const.
+ /// \tparam EF The type of the edge filter map.
+ /// It must be a \c bool (or convertible) edge map of the
+ /// adapted graph. The default type is
+ /// \ref concepts::Graph::EdgeMap "GR::EdgeMap<bool>".
+ ///
+ /// \note The \c Node, \c Edge and \c Arc types of this adaptor and the
+ /// adapted graph are convertible to each other.
+#ifdef DOXYGEN
+ template<typename GR,
+ typename EF>
+ class FilterEdges {
+#else
+ template<typename GR,
+ typename EF = typename GR::template EdgeMap<bool> >
+ class FilterEdges :
+ public GraphAdaptorExtender<
+ SubGraphBase<GR, ConstMap<typename GR::Node, Const<bool, true> >,
+ EF, false> > {
+#endif
+ typedef GraphAdaptorExtender<
+ SubGraphBase<GR, ConstMap<typename GR::Node, Const<bool, true > >,
+ EF, false> > Parent;
+
+ public:
+
+ /// The type of the adapted graph.
+ typedef GR Graph;
+ /// The type of the edge filter map.
+ typedef EF EdgeFilterMap;
+
+ typedef typename Parent::Edge Edge;
+
+ protected:
+ ConstMap<typename GR::Node, Const<bool, true> > const_true_map;
+
+ FilterEdges() : const_true_map(true) {
+ Parent::setNodeFilterMap(const_true_map);
+ }
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Creates a subgraph for the given graph with the given edge
+ /// filter map.
+ FilterEdges(GR& graph, EF& edge_filter)
+ : Parent(), const_true_map() {
+ Parent::initialize(graph, const_true_map, edge_filter);
+ }
+
+ /// \brief Sets the status of the given edge
+ ///
+ /// This function sets the status of the given edge.
+ /// It is done by simply setting the assigned value of \c e
+ /// to \c v in the edge filter map.
+ void status(const Edge& e, bool v) const { Parent::status(e, v); }
+
+ /// \brief Returns the status of the given edge
+ ///
+ /// This function returns the status of the given edge.
+ /// It is \c true if the given edge is enabled (i.e. not hidden).
+ bool status(const Edge& e) const { return Parent::status(e); }
+
+ /// \brief Disables the given edge
+ ///
+ /// This function disables the given edge in the subgraph,
+ /// so the iteration jumps over it.
+ /// It is the same as \ref status() "status(e, false)".
+ void disable(const Edge& e) const { Parent::status(e, false); }
+
+ /// \brief Enables the given edge
+ ///
+ /// This function enables the given edge in the subgraph.
+ /// It is the same as \ref status() "status(e, true)".
+ void enable(const Edge& e) const { Parent::status(e, true); }
+
+ };
+
+ /// \brief Returns a read-only FilterEdges adaptor
+ ///
+ /// This function just returns a read-only \ref FilterEdges adaptor.
+ /// \ingroup graph_adaptors
+ /// \relates FilterEdges
+ template<typename GR, typename EF>
+ FilterEdges<const GR, EF>
+ filterEdges(const GR& graph, EF& edge_filter) {
+ return FilterEdges<const GR, EF>(graph, edge_filter);
+ }
+
+ template<typename GR, typename EF>
+ FilterEdges<const GR, const EF>
+ filterEdges(const GR& graph, const EF& edge_filter) {
+ return FilterEdges<const GR, const EF>(graph, edge_filter);
+ }
+
+
+ template <typename DGR>
+ class UndirectorBase {
+ public:
+ typedef DGR Digraph;
+ typedef UndirectorBase Adaptor;
+
+ typedef True UndirectedTag;
+
+ typedef typename Digraph::Arc Edge;
+ typedef typename Digraph::Node Node;
+
+ class Arc {
+ friend class UndirectorBase;
+ protected:
+ Edge _edge;
+ bool _forward;
+
+ Arc(const Edge& edge, bool forward)
+ : _edge(edge), _forward(forward) {}
+
+ public:
+ Arc() {}
+
+ Arc(Invalid) : _edge(INVALID), _forward(true) {}
+
+ operator const Edge&() const { return _edge; }
+
+ bool operator==(const Arc &other) const {
+ return _forward == other._forward && _edge == other._edge;
+ }
+ bool operator!=(const Arc &other) const {
+ return _forward != other._forward || _edge != other._edge;
+ }
+ bool operator<(const Arc &other) const {
+ return _forward < other._forward ||
+ (_forward == other._forward && _edge < other._edge);
+ }
+ };
+
+ void first(Node& n) const {
+ _digraph->first(n);
+ }
+
+ void next(Node& n) const {
+ _digraph->next(n);
+ }
+
+ void first(Arc& a) const {
+ _digraph->first(a._edge);
+ a._forward = true;
+ }
+
+ void next(Arc& a) const {
+ if (a._forward) {
+ a._forward = false;
+ } else {
+ _digraph->next(a._edge);
+ a._forward = true;
+ }
+ }
+
+ void first(Edge& e) const {
+ _digraph->first(e);
+ }
+
+ void next(Edge& e) const {
+ _digraph->next(e);
+ }
+
+ void firstOut(Arc& a, const Node& n) const {
+ _digraph->firstIn(a._edge, n);
+ if (a._edge != INVALID ) {
+ a._forward = false;
+ } else {
+ _digraph->firstOut(a._edge, n);
+ a._forward = true;
+ }
+ }
+ void nextOut(Arc &a) const {
+ if (!a._forward) {
+ Node n = _digraph->target(a._edge);
+ _digraph->nextIn(a._edge);
+ if (a._edge == INVALID) {
+ _digraph->firstOut(a._edge, n);
+ a._forward = true;
+ }
+ }
+ else {
+ _digraph->nextOut(a._edge);
+ }
+ }
+
+ void firstIn(Arc &a, const Node &n) const {
+ _digraph->firstOut(a._edge, n);
+ if (a._edge != INVALID ) {
+ a._forward = false;
+ } else {
+ _digraph->firstIn(a._edge, n);
+ a._forward = true;
+ }
+ }
+ void nextIn(Arc &a) const {
+ if (!a._forward) {
+ Node n = _digraph->source(a._edge);
+ _digraph->nextOut(a._edge);
+ if (a._edge == INVALID ) {
+ _digraph->firstIn(a._edge, n);
+ a._forward = true;
+ }
+ }
+ else {
+ _digraph->nextIn(a._edge);
+ }
+ }
+
+ void firstInc(Edge &e, bool &d, const Node &n) const {
+ d = true;
+ _digraph->firstOut(e, n);
+ if (e != INVALID) return;
+ d = false;
+ _digraph->firstIn(e, n);
+ }
+
+ void nextInc(Edge &e, bool &d) const {
+ if (d) {
+ Node s = _digraph->source(e);
+ _digraph->nextOut(e);
+ if (e != INVALID) return;
+ d = false;
+ _digraph->firstIn(e, s);
+ } else {
+ _digraph->nextIn(e);
+ }
+ }
+
+ Node u(const Edge& e) const {
+ return _digraph->source(e);
+ }
+
+ Node v(const Edge& e) const {
+ return _digraph->target(e);
+ }
+
+ Node source(const Arc &a) const {
+ return a._forward ? _digraph->source(a._edge) : _digraph->target(a._edge);
+ }
+
+ Node target(const Arc &a) const {
+ return a._forward ? _digraph->target(a._edge) : _digraph->source(a._edge);
+ }
+
+ static Arc direct(const Edge &e, bool d) {
+ return Arc(e, d);
+ }
+
+ static bool direction(const Arc &a) { return a._forward; }
+
+ Node nodeFromId(int ix) const { return _digraph->nodeFromId(ix); }
+ Arc arcFromId(int ix) const {
+ return direct(_digraph->arcFromId(ix >> 1), bool(ix & 1));
+ }
+ Edge edgeFromId(int ix) const { return _digraph->arcFromId(ix); }
+
+ int id(const Node &n) const { return _digraph->id(n); }
+ int id(const Arc &a) const {
+ return (_digraph->id(a) << 1) | (a._forward ? 1 : 0);
+ }
+ int id(const Edge &e) const { return _digraph->id(e); }
+
+ int maxNodeId() const { return _digraph->maxNodeId(); }
+ int maxArcId() const { return (_digraph->maxArcId() << 1) | 1; }
+ int maxEdgeId() const { return _digraph->maxArcId(); }
+
+ Node addNode() { return _digraph->addNode(); }
+ Edge addEdge(const Node& u, const Node& v) {
+ return _digraph->addArc(u, v);
+ }
+
+ void erase(const Node& i) { _digraph->erase(i); }
+ void erase(const Edge& i) { _digraph->erase(i); }
+
+ void clear() { _digraph->clear(); }
+
+ typedef NodeNumTagIndicator<Digraph> NodeNumTag;
+ int nodeNum() const { return _digraph->nodeNum(); }
+
+ typedef ArcNumTagIndicator<Digraph> ArcNumTag;
+ int arcNum() const { return 2 * _digraph->arcNum(); }
+
+ typedef ArcNumTag EdgeNumTag;
+ int edgeNum() const { return _digraph->arcNum(); }
+
+ typedef FindArcTagIndicator<Digraph> FindArcTag;
+ Arc findArc(Node s, Node t, Arc p = INVALID) const {
+ if (p == INVALID) {
+ Edge arc = _digraph->findArc(s, t);
+ if (arc != INVALID) return direct(arc, true);
+ arc = _digraph->findArc(t, s);
+ if (arc != INVALID) return direct(arc, false);
+ } else if (direction(p)) {
+ Edge arc = _digraph->findArc(s, t, p);
+ if (arc != INVALID) return direct(arc, true);
+ arc = _digraph->findArc(t, s);
+ if (arc != INVALID) return direct(arc, false);
+ } else {
+ Edge arc = _digraph->findArc(t, s, p);
+ if (arc != INVALID) return direct(arc, false);
+ }
+ return INVALID;
+ }
+
+ typedef FindArcTag FindEdgeTag;
+ Edge findEdge(Node s, Node t, Edge p = INVALID) const {
+ if (s != t) {
+ if (p == INVALID) {
+ Edge arc = _digraph->findArc(s, t);
+ if (arc != INVALID) return arc;
+ arc = _digraph->findArc(t, s);
+ if (arc != INVALID) return arc;
+ } else if (_digraph->source(p) == s) {
+ Edge arc = _digraph->findArc(s, t, p);
+ if (arc != INVALID) return arc;
+ arc = _digraph->findArc(t, s);
+ if (arc != INVALID) return arc;
+ } else {
+ Edge arc = _digraph->findArc(t, s, p);
+ if (arc != INVALID) return arc;
+ }
+ } else {
+ return _digraph->findArc(s, t, p);
+ }
+ return INVALID;
+ }
+
+ private:
+
+ template <typename V>
+ class ArcMapBase {
+ private:
+
+ typedef typename DGR::template ArcMap<V> MapImpl;
+
+ public:
+
+ typedef typename MapTraits<MapImpl>::ReferenceMapTag ReferenceMapTag;
+
+ typedef V Value;
+ typedef Arc Key;
+ typedef typename MapTraits<MapImpl>::ConstReturnValue ConstReturnValue;
+ typedef typename MapTraits<MapImpl>::ReturnValue ReturnValue;
+ typedef typename MapTraits<MapImpl>::ConstReturnValue ConstReference;
+ typedef typename MapTraits<MapImpl>::ReturnValue Reference;
+
+ ArcMapBase(const UndirectorBase<DGR>& adaptor) :
+ _forward(*adaptor._digraph), _backward(*adaptor._digraph) {}
+
+ ArcMapBase(const UndirectorBase<DGR>& adaptor, const V& value)
+ : _forward(*adaptor._digraph, value),
+ _backward(*adaptor._digraph, value) {}
+
+ void set(const Arc& a, const V& value) {
+ if (direction(a)) {
+ _forward.set(a, value);
+ } else {
+ _backward.set(a, value);
+ }
+ }
+
+ ConstReturnValue operator[](const Arc& a) const {
+ if (direction(a)) {
+ return _forward[a];
+ } else {
+ return _backward[a];
+ }
+ }
+
+ ReturnValue operator[](const Arc& a) {
+ if (direction(a)) {
+ return _forward[a];
+ } else {
+ return _backward[a];
+ }
+ }
+
+ protected:
+
+ MapImpl _forward, _backward;
+
+ };
+
+ public:
+
+ template <typename V>
+ class NodeMap : public DGR::template NodeMap<V> {
+ typedef typename DGR::template NodeMap<V> Parent;
+
+ public:
+ typedef V Value;
+
+ explicit NodeMap(const UndirectorBase<DGR>& adaptor)
+ : Parent(*adaptor._digraph) {}
+
+ NodeMap(const UndirectorBase<DGR>& adaptor, const V& value)
+ : Parent(*adaptor._digraph, value) { }
+
+ private:
+ NodeMap& operator=(const NodeMap& cmap) {
+ return operator=<NodeMap>(cmap);
+ }
+
+ template <typename CMap>
+ NodeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+
+ };
+
+ template <typename V>
+ class ArcMap
+ : public SubMapExtender<UndirectorBase<DGR>, ArcMapBase<V> > {
+ typedef SubMapExtender<UndirectorBase<DGR>, ArcMapBase<V> > Parent;
+
+ public:
+ typedef V Value;
+
+ explicit ArcMap(const UndirectorBase<DGR>& adaptor)
+ : Parent(adaptor) {}
+
+ ArcMap(const UndirectorBase<DGR>& adaptor, const V& value)
+ : Parent(adaptor, value) {}
+
+ private:
+ ArcMap& operator=(const ArcMap& cmap) {
+ return operator=<ArcMap>(cmap);
+ }
+
+ template <typename CMap>
+ ArcMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+ template <typename V>
+ class EdgeMap : public Digraph::template ArcMap<V> {
+ typedef typename Digraph::template ArcMap<V> Parent;
+
+ public:
+ typedef V Value;
+
+ explicit EdgeMap(const UndirectorBase<DGR>& adaptor)
+ : Parent(*adaptor._digraph) {}
+
+ EdgeMap(const UndirectorBase<DGR>& adaptor, const V& value)
+ : Parent(*adaptor._digraph, value) {}
+
+ private:
+ EdgeMap& operator=(const EdgeMap& cmap) {
+ return operator=<EdgeMap>(cmap);
+ }
+
+ template <typename CMap>
+ EdgeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+
+ };
+
+ typedef typename ItemSetTraits<DGR, Node>::ItemNotifier NodeNotifier;
+ NodeNotifier& notifier(Node) const { return _digraph->notifier(Node()); }
+
+ typedef typename ItemSetTraits<DGR, Edge>::ItemNotifier EdgeNotifier;
+ EdgeNotifier& notifier(Edge) const { return _digraph->notifier(Edge()); }
+
+ typedef EdgeNotifier ArcNotifier;
+ ArcNotifier& notifier(Arc) const { return _digraph->notifier(Edge()); }
+
+ protected:
+
+ UndirectorBase() : _digraph(0) {}
+
+ DGR* _digraph;
+
+ void initialize(DGR& digraph) {
+ _digraph = &digraph;
+ }
+
+ };
+
+ /// \ingroup graph_adaptors
+ ///
+ /// \brief Adaptor class for viewing a digraph as an undirected graph.
+ ///
+ /// Undirector adaptor can be used for viewing a digraph as an undirected
+ /// graph. All arcs of the underlying digraph are showed in the
+ /// adaptor as an edge (and also as a pair of arcs, of course).
+ /// This adaptor conforms to the \ref concepts::Graph "Graph" concept.
+ ///
+ /// The adapted digraph can also be modified through this adaptor
+ /// by adding or removing nodes or edges, unless the \c GR template
+ /// parameter is set to be \c const.
+ ///
+ /// This class provides item counting in the same time as the adapted
+ /// digraph structure.
+ ///
+ /// \tparam DGR The type of the adapted digraph.
+ /// It must conform to the \ref concepts::Digraph "Digraph" concept.
+ /// It can also be specified to be \c const.
+ ///
+ /// \note The \c Node type of this adaptor and the adapted digraph are
+ /// convertible to each other, moreover the \c Edge type of the adaptor
+ /// and the \c Arc type of the adapted digraph are also convertible to
+ /// each other.
+ /// (Thus the \c Arc type of the adaptor is convertible to the \c Arc type
+ /// of the adapted digraph.)
+ template<typename DGR>
+#ifdef DOXYGEN
+ class Undirector {
+#else
+ class Undirector :
+ public GraphAdaptorExtender<UndirectorBase<DGR> > {
+#endif
+ typedef GraphAdaptorExtender<UndirectorBase<DGR> > Parent;
+ public:
+ /// The type of the adapted digraph.
+ typedef DGR Digraph;
+ protected:
+ Undirector() { }
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Creates an undirected graph from the given digraph.
+ Undirector(DGR& digraph) {
+ this->initialize(digraph);
+ }
+
+ /// \brief Arc map combined from two original arc maps
+ ///
+ /// This map adaptor class adapts two arc maps of the underlying
+ /// digraph to get an arc map of the undirected graph.
+ /// Its value type is inherited from the first arc map type (\c FW).
+ /// \tparam FW The type of the "foward" arc map.
+ /// \tparam BK The type of the "backward" arc map.
+ template <typename FW, typename BK>
+ class CombinedArcMap {
+ public:
+
+ /// The key type of the map
+ typedef typename Parent::Arc Key;
+ /// The value type of the map
+ typedef typename FW::Value Value;
+
+ typedef typename MapTraits<FW>::ReferenceMapTag ReferenceMapTag;
+
+ typedef typename MapTraits<FW>::ReturnValue ReturnValue;
+ typedef typename MapTraits<FW>::ConstReturnValue ConstReturnValue;
+ typedef typename MapTraits<FW>::ReturnValue Reference;
+ typedef typename MapTraits<FW>::ConstReturnValue ConstReference;
+
+ /// Constructor
+ CombinedArcMap(FW& forward, BK& backward)
+ : _forward(&forward), _backward(&backward) {}
+
+ /// Sets the value associated with the given key.
+ void set(const Key& e, const Value& a) {
+ if (Parent::direction(e)) {
+ _forward->set(e, a);
+ } else {
+ _backward->set(e, a);
+ }
+ }
+
+ /// Returns the value associated with the given key.
+ ConstReturnValue operator[](const Key& e) const {
+ if (Parent::direction(e)) {
+ return (*_forward)[e];
+ } else {
+ return (*_backward)[e];
+ }
+ }
+
+ /// Returns a reference to the value associated with the given key.
+ ReturnValue operator[](const Key& e) {
+ if (Parent::direction(e)) {
+ return (*_forward)[e];
+ } else {
+ return (*_backward)[e];
+ }
+ }
+
+ protected:
+
+ FW* _forward;
+ BK* _backward;
+
+ };
+
+ /// \brief Returns a combined arc map
+ ///
+ /// This function just returns a combined arc map.
+ template <typename FW, typename BK>
+ static CombinedArcMap<FW, BK>
+ combinedArcMap(FW& forward, BK& backward) {
+ return CombinedArcMap<FW, BK>(forward, backward);
+ }
+
+ template <typename FW, typename BK>
+ static CombinedArcMap<const FW, BK>
+ combinedArcMap(const FW& forward, BK& backward) {
+ return CombinedArcMap<const FW, BK>(forward, backward);
+ }
+
+ template <typename FW, typename BK>
+ static CombinedArcMap<FW, const BK>
+ combinedArcMap(FW& forward, const BK& backward) {
+ return CombinedArcMap<FW, const BK>(forward, backward);
+ }
+
+ template <typename FW, typename BK>
+ static CombinedArcMap<const FW, const BK>
+ combinedArcMap(const FW& forward, const BK& backward) {
+ return CombinedArcMap<const FW, const BK>(forward, backward);
+ }
+
+ };
+
+ /// \brief Returns a read-only Undirector adaptor
+ ///
+ /// This function just returns a read-only \ref Undirector adaptor.
+ /// \ingroup graph_adaptors
+ /// \relates Undirector
+ template<typename DGR>
+ Undirector<const DGR> undirector(const DGR& digraph) {
+ return Undirector<const DGR>(digraph);
+ }
+
+
+ template <typename GR, typename DM>
+ class OrienterBase {
+ public:
+
+ typedef GR Graph;
+ typedef DM DirectionMap;
+
+ typedef typename GR::Node Node;
+ typedef typename GR::Edge Arc;
+
+ void reverseArc(const Arc& arc) {
+ _direction->set(arc, !(*_direction)[arc]);
+ }
+
+ void first(Node& i) const { _graph->first(i); }
+ void first(Arc& i) const { _graph->first(i); }
+ void firstIn(Arc& i, const Node& n) const {
+ bool d = true;
+ _graph->firstInc(i, d, n);
+ while (i != INVALID && d == (*_direction)[i]) _graph->nextInc(i, d);
+ }
+ void firstOut(Arc& i, const Node& n ) const {
+ bool d = true;
+ _graph->firstInc(i, d, n);
+ while (i != INVALID && d != (*_direction)[i]) _graph->nextInc(i, d);
+ }
+
+ void next(Node& i) const { _graph->next(i); }
+ void next(Arc& i) const { _graph->next(i); }
+ void nextIn(Arc& i) const {
+ bool d = !(*_direction)[i];
+ _graph->nextInc(i, d);
+ while (i != INVALID && d == (*_direction)[i]) _graph->nextInc(i, d);
+ }
+ void nextOut(Arc& i) const {
+ bool d = (*_direction)[i];
+ _graph->nextInc(i, d);
+ while (i != INVALID && d != (*_direction)[i]) _graph->nextInc(i, d);
+ }
+
+ Node source(const Arc& e) const {
+ return (*_direction)[e] ? _graph->u(e) : _graph->v(e);
+ }
+ Node target(const Arc& e) const {
+ return (*_direction)[e] ? _graph->v(e) : _graph->u(e);
+ }
+
+ typedef NodeNumTagIndicator<Graph> NodeNumTag;
+ int nodeNum() const { return _graph->nodeNum(); }
+
+ typedef EdgeNumTagIndicator<Graph> ArcNumTag;
+ int arcNum() const { return _graph->edgeNum(); }
+
+ typedef FindEdgeTagIndicator<Graph> FindArcTag;
+ Arc findArc(const Node& u, const Node& v,
+ const Arc& prev = INVALID) const {
+ Arc arc = _graph->findEdge(u, v, prev);
+ while (arc != INVALID && source(arc) != u) {
+ arc = _graph->findEdge(u, v, arc);
+ }
+ return arc;
+ }
+
+ Node addNode() {
+ return Node(_graph->addNode());
+ }
+
+ Arc addArc(const Node& u, const Node& v) {
+ Arc arc = _graph->addEdge(u, v);
+ _direction->set(arc, _graph->u(arc) == u);
+ return arc;
+ }
+
+ void erase(const Node& i) { _graph->erase(i); }
+ void erase(const Arc& i) { _graph->erase(i); }
+
+ void clear() { _graph->clear(); }
+
+ int id(const Node& v) const { return _graph->id(v); }
+ int id(const Arc& e) const { return _graph->id(e); }
+
+ Node nodeFromId(int idx) const { return _graph->nodeFromId(idx); }
+ Arc arcFromId(int idx) const { return _graph->edgeFromId(idx); }
+
+ int maxNodeId() const { return _graph->maxNodeId(); }
+ int maxArcId() const { return _graph->maxEdgeId(); }
+
+ typedef typename ItemSetTraits<GR, Node>::ItemNotifier NodeNotifier;
+ NodeNotifier& notifier(Node) const { return _graph->notifier(Node()); }
+
+ typedef typename ItemSetTraits<GR, Arc>::ItemNotifier ArcNotifier;
+ ArcNotifier& notifier(Arc) const { return _graph->notifier(Arc()); }
+
+ template <typename V>
+ class NodeMap : public GR::template NodeMap<V> {
+ typedef typename GR::template NodeMap<V> Parent;
+
+ public:
+
+ explicit NodeMap(const OrienterBase<GR, DM>& adapter)
+ : Parent(*adapter._graph) {}
+
+ NodeMap(const OrienterBase<GR, DM>& adapter, const V& value)
+ : Parent(*adapter._graph, value) {}
+
+ private:
+ NodeMap& operator=(const NodeMap& cmap) {
+ return operator=<NodeMap>(cmap);
+ }
+
+ template <typename CMap>
+ NodeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+
+ };
+
+ template <typename V>
+ class ArcMap : public GR::template EdgeMap<V> {
+ typedef typename Graph::template EdgeMap<V> Parent;
+
+ public:
+
+ explicit ArcMap(const OrienterBase<GR, DM>& adapter)
+ : Parent(*adapter._graph) { }
+
+ ArcMap(const OrienterBase<GR, DM>& adapter, const V& value)
+ : Parent(*adapter._graph, value) { }
+
+ private:
+ ArcMap& operator=(const ArcMap& cmap) {
+ return operator=<ArcMap>(cmap);
+ }
+
+ template <typename CMap>
+ ArcMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+
+
+ protected:
+ Graph* _graph;
+ DM* _direction;
+
+ void initialize(GR& graph, DM& direction) {
+ _graph = &graph;
+ _direction = &direction;
+ }
+
+ };
+
+ /// \ingroup graph_adaptors
+ ///
+ /// \brief Adaptor class for orienting the edges of a graph to get a digraph
+ ///
+ /// Orienter adaptor can be used for orienting the edges of a graph to
+ /// get a digraph. A \c bool edge map of the underlying graph must be
+ /// specified, which define the direction of the arcs in the adaptor.
+ /// The arcs can be easily reversed by the \c reverseArc() member function
+ /// of the adaptor.
+ /// This class conforms to the \ref concepts::Digraph "Digraph" concept.
+ ///
+ /// The adapted graph can also be modified through this adaptor
+ /// by adding or removing nodes or arcs, unless the \c GR template
+ /// parameter is set to be \c const.
+ ///
+ /// This class provides item counting in the same time as the adapted
+ /// graph structure.
+ ///
+ /// \tparam GR The type of the adapted graph.
+ /// It must conform to the \ref concepts::Graph "Graph" concept.
+ /// It can also be specified to be \c const.
+ /// \tparam DM The type of the direction map.
+ /// It must be a \c bool (or convertible) edge map of the
+ /// adapted graph. The default type is
+ /// \ref concepts::Graph::EdgeMap "GR::EdgeMap<bool>".
+ ///
+ /// \note The \c Node type of this adaptor and the adapted graph are
+ /// convertible to each other, moreover the \c Arc type of the adaptor
+ /// and the \c Edge type of the adapted graph are also convertible to
+ /// each other.
+#ifdef DOXYGEN
+ template<typename GR,
+ typename DM>
+ class Orienter {
+#else
+ template<typename GR,
+ typename DM = typename GR::template EdgeMap<bool> >
+ class Orienter :
+ public DigraphAdaptorExtender<OrienterBase<GR, DM> > {
+#endif
+ typedef DigraphAdaptorExtender<OrienterBase<GR, DM> > Parent;
+ public:
+
+ /// The type of the adapted graph.
+ typedef GR Graph;
+ /// The type of the direction edge map.
+ typedef DM DirectionMap;
+
+ typedef typename Parent::Arc Arc;
+
+ protected:
+ Orienter() { }
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Constructor of the adaptor.
+ Orienter(GR& graph, DM& direction) {
+ Parent::initialize(graph, direction);
+ }
+
+ /// \brief Reverses the given arc
+ ///
+ /// This function reverses the given arc.
+ /// It is done by simply negate the assigned value of \c a
+ /// in the direction map.
+ void reverseArc(const Arc& a) {
+ Parent::reverseArc(a);
+ }
+ };
+
+ /// \brief Returns a read-only Orienter adaptor
+ ///
+ /// This function just returns a read-only \ref Orienter adaptor.
+ /// \ingroup graph_adaptors
+ /// \relates Orienter
+ template<typename GR, typename DM>
+ Orienter<const GR, DM>
+ orienter(const GR& graph, DM& direction) {
+ return Orienter<const GR, DM>(graph, direction);
+ }
+
+ template<typename GR, typename DM>
+ Orienter<const GR, const DM>
+ orienter(const GR& graph, const DM& direction) {
+ return Orienter<const GR, const DM>(graph, direction);
+ }
+
+ namespace _adaptor_bits {
+
+ template <typename DGR, typename CM, typename FM, typename TL>
+ class ResForwardFilter {
+ public:
+
+ typedef typename DGR::Arc Key;
+ typedef bool Value;
+
+ private:
+
+ const CM* _capacity;
+ const FM* _flow;
+ TL _tolerance;
+
+ public:
+
+ ResForwardFilter(const CM& capacity, const FM& flow,
+ const TL& tolerance = TL())
+ : _capacity(&capacity), _flow(&flow), _tolerance(tolerance) { }
+
+ bool operator[](const typename DGR::Arc& a) const {
+ return _tolerance.positive((*_capacity)[a] - (*_flow)[a]);
+ }
+ };
+
+ template<typename DGR,typename CM, typename FM, typename TL>
+ class ResBackwardFilter {
+ public:
+
+ typedef typename DGR::Arc Key;
+ typedef bool Value;
+
+ private:
+
+ const CM* _capacity;
+ const FM* _flow;
+ TL _tolerance;
+
+ public:
+
+ ResBackwardFilter(const CM& capacity, const FM& flow,
+ const TL& tolerance = TL())
+ : _capacity(&capacity), _flow(&flow), _tolerance(tolerance) { }
+
+ bool operator[](const typename DGR::Arc& a) const {
+ return _tolerance.positive((*_flow)[a]);
+ }
+ };
+
+ }
+
+ /// \ingroup graph_adaptors
+ ///
+ /// \brief Adaptor class for composing the residual digraph for directed
+ /// flow and circulation problems.
+ ///
+ /// ResidualDigraph can be used for composing the \e residual digraph
+ /// for directed flow and circulation problems. Let \f$ G=(V, A) \f$
+ /// be a directed graph and let \f$ F \f$ be a number type.
+ /// Let \f$ flow, cap: A\to F \f$ be functions on the arcs.
+ /// This adaptor implements a digraph structure with node set \f$ V \f$
+ /// and arc set \f$ A_{forward}\cup A_{backward} \f$,
+ /// where \f$ A_{forward}=\{uv : uv\in A, flow(uv)<cap(uv)\} \f$ and
+ /// \f$ A_{backward}=\{vu : uv\in A, flow(uv)>0\} \f$, i.e. the so
+ /// called residual digraph.
+ /// When the union \f$ A_{forward}\cup A_{backward} \f$ is taken,
+ /// multiplicities are counted, i.e. the adaptor has exactly
+ /// \f$ |A_{forward}| + |A_{backward}|\f$ arcs (it may have parallel
+ /// arcs).
+ /// This class conforms to the \ref concepts::Digraph "Digraph" concept.
+ ///
+ /// This class provides only linear time counting for nodes and arcs.
+ ///
+ /// \tparam DGR The type of the adapted digraph.
+ /// It must conform to the \ref concepts::Digraph "Digraph" concept.
+ /// It is implicitly \c const.
+ /// \tparam CM The type of the capacity map.
+ /// It must be an arc map of some numerical type, which defines
+ /// the capacities in the flow problem. It is implicitly \c const.
+ /// The default type is
+ /// \ref concepts::Digraph::ArcMap "GR::ArcMap<int>".
+ /// \tparam FM The type of the flow map.
+ /// It must be an arc map of some numerical type, which defines
+ /// the flow values in the flow problem. The default type is \c CM.
+ /// \tparam TL The tolerance type for handling inexact computation.
+ /// The default tolerance type depends on the value type of the
+ /// capacity map.
+ ///
+ /// \note This adaptor is implemented using Undirector and FilterArcs
+ /// adaptors.
+ ///
+ /// \note The \c Node type of this adaptor and the adapted digraph are
+ /// convertible to each other, moreover the \c Arc type of the adaptor
+ /// is convertible to the \c Arc type of the adapted digraph.
+#ifdef DOXYGEN
+ template<typename DGR, typename CM, typename FM, typename TL>
+ class ResidualDigraph
+#else
+ template<typename DGR,
+ typename CM = typename DGR::template ArcMap<int>,
+ typename FM = CM,
+ typename TL = Tolerance<typename CM::Value> >
+ class ResidualDigraph
+ : public SubDigraph<
+ Undirector<const DGR>,
+ ConstMap<typename DGR::Node, Const<bool, true> >,
+ typename Undirector<const DGR>::template CombinedArcMap<
+ _adaptor_bits::ResForwardFilter<const DGR, CM, FM, TL>,
+ _adaptor_bits::ResBackwardFilter<const DGR, CM, FM, TL> > >
+#endif
+ {
+ public:
+
+ /// The type of the underlying digraph.
+ typedef DGR Digraph;
+ /// The type of the capacity map.
+ typedef CM CapacityMap;
+ /// The type of the flow map.
+ typedef FM FlowMap;
+ /// The tolerance type.
+ typedef TL Tolerance;
+
+ typedef typename CapacityMap::Value Value;
+ typedef ResidualDigraph Adaptor;
+
+ protected:
+
+ typedef Undirector<const Digraph> Undirected;
+
+ typedef ConstMap<typename DGR::Node, Const<bool, true> > NodeFilter;
+
+ typedef _adaptor_bits::ResForwardFilter<const DGR, CM,
+ FM, TL> ForwardFilter;
+
+ typedef _adaptor_bits::ResBackwardFilter<const DGR, CM,
+ FM, TL> BackwardFilter;
+
+ typedef typename Undirected::
+ template CombinedArcMap<ForwardFilter, BackwardFilter> ArcFilter;
+
+ typedef SubDigraph<Undirected, NodeFilter, ArcFilter> Parent;
+
+ const CapacityMap* _capacity;
+ FlowMap* _flow;
+
+ Undirected _graph;
+ NodeFilter _node_filter;
+ ForwardFilter _forward_filter;
+ BackwardFilter _backward_filter;
+ ArcFilter _arc_filter;
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Constructor of the residual digraph adaptor. The parameters are the
+ /// digraph, the capacity map, the flow map, and a tolerance object.
+ ResidualDigraph(const DGR& digraph, const CM& capacity,
+ FM& flow, const TL& tolerance = Tolerance())
+ : Parent(), _capacity(&capacity), _flow(&flow),
+ _graph(digraph), _node_filter(),
+ _forward_filter(capacity, flow, tolerance),
+ _backward_filter(capacity, flow, tolerance),
+ _arc_filter(_forward_filter, _backward_filter)
+ {
+ Parent::initialize(_graph, _node_filter, _arc_filter);
+ }
+
+ typedef typename Parent::Arc Arc;
+
+ /// \brief Returns the residual capacity of the given arc.
+ ///
+ /// Returns the residual capacity of the given arc.
+ Value residualCapacity(const Arc& a) const {
+ if (Undirected::direction(a)) {
+ return (*_capacity)[a] - (*_flow)[a];
+ } else {
+ return (*_flow)[a];
+ }
+ }
+
+ /// \brief Augments on the given arc in the residual digraph.
+ ///
+ /// Augments on the given arc in the residual digraph. It increases
+ /// or decreases the flow value on the original arc according to the
+ /// direction of the residual arc.
+ void augment(const Arc& a, const Value& v) const {
+ if (Undirected::direction(a)) {
+ _flow->set(a, (*_flow)[a] + v);
+ } else {
+ _flow->set(a, (*_flow)[a] - v);
+ }
+ }
+
+ /// \brief Returns \c true if the given residual arc is a forward arc.
+ ///
+ /// Returns \c true if the given residual arc has the same orientation
+ /// as the original arc, i.e. it is a so called forward arc.
+ static bool forward(const Arc& a) {
+ return Undirected::direction(a);
+ }
+
+ /// \brief Returns \c true if the given residual arc is a backward arc.
+ ///
+ /// Returns \c true if the given residual arc has the opposite orientation
+ /// than the original arc, i.e. it is a so called backward arc.
+ static bool backward(const Arc& a) {
+ return !Undirected::direction(a);
+ }
+
+ /// \brief Returns the forward oriented residual arc.
+ ///
+ /// Returns the forward oriented residual arc related to the given
+ /// arc of the underlying digraph.
+ static Arc forward(const typename Digraph::Arc& a) {
+ return Undirected::direct(a, true);
+ }
+
+ /// \brief Returns the backward oriented residual arc.
+ ///
+ /// Returns the backward oriented residual arc related to the given
+ /// arc of the underlying digraph.
+ static Arc backward(const typename Digraph::Arc& a) {
+ return Undirected::direct(a, false);
+ }
+
+ /// \brief Residual capacity map.
+ ///
+ /// This map adaptor class can be used for obtaining the residual
+ /// capacities as an arc map of the residual digraph.
+ /// Its value type is inherited from the capacity map.
+ class ResidualCapacity {
+ protected:
+ const Adaptor* _adaptor;
+ public:
+ /// The key type of the map
+ typedef Arc Key;
+ /// The value type of the map
+ typedef typename CapacityMap::Value Value;
+
+ /// Constructor
+ ResidualCapacity(const ResidualDigraph<DGR, CM, FM, TL>& adaptor)
+ : _adaptor(&adaptor) {}
+
+ /// Returns the value associated with the given residual arc
+ Value operator[](const Arc& a) const {
+ return _adaptor->residualCapacity(a);
+ }
+
+ };
+
+ /// \brief Returns a residual capacity map
+ ///
+ /// This function just returns a residual capacity map.
+ ResidualCapacity residualCapacity() const {
+ return ResidualCapacity(*this);
+ }
+
+ };
+
+ /// \brief Returns a (read-only) Residual adaptor
+ ///
+ /// This function just returns a (read-only) \ref ResidualDigraph adaptor.
+ /// \ingroup graph_adaptors
+ /// \relates ResidualDigraph
+ template<typename DGR, typename CM, typename FM>
+ ResidualDigraph<DGR, CM, FM>
+ residualDigraph(const DGR& digraph, const CM& capacity_map, FM& flow_map) {
+ return ResidualDigraph<DGR, CM, FM> (digraph, capacity_map, flow_map);
+ }
+
+
+ template <typename DGR>
+ class SplitNodesBase {
+ typedef DigraphAdaptorBase<const DGR> Parent;
+
+ public:
+
+ typedef DGR Digraph;
+ typedef SplitNodesBase Adaptor;
+
+ typedef typename DGR::Node DigraphNode;
+ typedef typename DGR::Arc DigraphArc;
+
+ class Node;
+ class Arc;
+
+ private:
+
+ template <typename T> class NodeMapBase;
+ template <typename T> class ArcMapBase;
+
+ public:
+
+ class Node : public DigraphNode {
+ friend class SplitNodesBase;
+ template <typename T> friend class NodeMapBase;
+ private:
+
+ bool _in;
+ Node(DigraphNode node, bool in)
+ : DigraphNode(node), _in(in) {}
+
+ public:
+
+ Node() {}
+ Node(Invalid) : DigraphNode(INVALID), _in(true) {}
+
+ bool operator==(const Node& node) const {
+ return DigraphNode::operator==(node) && _in == node._in;
+ }
+
+ bool operator!=(const Node& node) const {
+ return !(*this == node);
+ }
+
+ bool operator<(const Node& node) const {
+ return DigraphNode::operator<(node) ||
+ (DigraphNode::operator==(node) && _in < node._in);
+ }
+ };
+
+ class Arc {
+ friend class SplitNodesBase;
+ template <typename T> friend class ArcMapBase;
+ private:
+ typedef BiVariant<DigraphArc, DigraphNode> ArcImpl;
+
+ explicit Arc(const DigraphArc& arc) : _item(arc) {}
+ explicit Arc(const DigraphNode& node) : _item(node) {}
+
+ ArcImpl _item;
+
+ public:
+ Arc() {}
+ Arc(Invalid) : _item(DigraphArc(INVALID)) {}
+
+ bool operator==(const Arc& arc) const {
+ if (_item.firstState()) {
+ if (arc._item.firstState()) {
+ return _item.first() == arc._item.first();
+ }
+ } else {
+ if (arc._item.secondState()) {
+ return _item.second() == arc._item.second();
+ }
+ }
+ return false;
+ }
+
+ bool operator!=(const Arc& arc) const {
+ return !(*this == arc);
+ }
+
+ bool operator<(const Arc& arc) const {
+ if (_item.firstState()) {
+ if (arc._item.firstState()) {
+ return _item.first() < arc._item.first();
+ }
+ return false;
+ } else {
+ if (arc._item.secondState()) {
+ return _item.second() < arc._item.second();
+ }
+ return true;
+ }
+ }
+
+ operator DigraphArc() const { return _item.first(); }
+ operator DigraphNode() const { return _item.second(); }
+
+ };
+
+ void first(Node& n) const {
+ _digraph->first(n);
+ n._in = true;
+ }
+
+ void next(Node& n) const {
+ if (n._in) {
+ n._in = false;
+ } else {
+ n._in = true;
+ _digraph->next(n);
+ }
+ }
+
+ void first(Arc& e) const {
+ e._item.setSecond();
+ _digraph->first(e._item.second());
+ if (e._item.second() == INVALID) {
+ e._item.setFirst();
+ _digraph->first(e._item.first());
+ }
+ }
+
+ void next(Arc& e) const {
+ if (e._item.secondState()) {
+ _digraph->next(e._item.second());
+ if (e._item.second() == INVALID) {
+ e._item.setFirst();
+ _digraph->first(e._item.first());
+ }
+ } else {
+ _digraph->next(e._item.first());
+ }
+ }
+
+ void firstOut(Arc& e, const Node& n) const {
+ if (n._in) {
+ e._item.setSecond(n);
+ } else {
+ e._item.setFirst();
+ _digraph->firstOut(e._item.first(), n);
+ }
+ }
+
+ void nextOut(Arc& e) const {
+ if (!e._item.firstState()) {
+ e._item.setFirst(INVALID);
+ } else {
+ _digraph->nextOut(e._item.first());
+ }
+ }
+
+ void firstIn(Arc& e, const Node& n) const {
+ if (!n._in) {
+ e._item.setSecond(n);
+ } else {
+ e._item.setFirst();
+ _digraph->firstIn(e._item.first(), n);
+ }
+ }
+
+ void nextIn(Arc& e) const {
+ if (!e._item.firstState()) {
+ e._item.setFirst(INVALID);
+ } else {
+ _digraph->nextIn(e._item.first());
+ }
+ }
+
+ Node source(const Arc& e) const {
+ if (e._item.firstState()) {
+ return Node(_digraph->source(e._item.first()), false);
+ } else {
+ return Node(e._item.second(), true);
+ }
+ }
+
+ Node target(const Arc& e) const {
+ if (e._item.firstState()) {
+ return Node(_digraph->target(e._item.first()), true);
+ } else {
+ return Node(e._item.second(), false);
+ }
+ }
+
+ int id(const Node& n) const {
+ return (_digraph->id(n) << 1) | (n._in ? 0 : 1);
+ }
+ Node nodeFromId(int ix) const {
+ return Node(_digraph->nodeFromId(ix >> 1), (ix & 1) == 0);
+ }
+ int maxNodeId() const {
+ return 2 * _digraph->maxNodeId() + 1;
+ }
+
+ int id(const Arc& e) const {
+ if (e._item.firstState()) {
+ return _digraph->id(e._item.first()) << 1;
+ } else {
+ return (_digraph->id(e._item.second()) << 1) | 1;
+ }
+ }
+ Arc arcFromId(int ix) const {
+ if ((ix & 1) == 0) {
+ return Arc(_digraph->arcFromId(ix >> 1));
+ } else {
+ return Arc(_digraph->nodeFromId(ix >> 1));
+ }
+ }
+ int maxArcId() const {
+ return std::max(_digraph->maxNodeId() << 1,
+ (_digraph->maxArcId() << 1) | 1);
+ }
+
+ static bool inNode(const Node& n) {
+ return n._in;
+ }
+
+ static bool outNode(const Node& n) {
+ return !n._in;
+ }
+
+ static bool origArc(const Arc& e) {
+ return e._item.firstState();
+ }
+
+ static bool bindArc(const Arc& e) {
+ return e._item.secondState();
+ }
+
+ static Node inNode(const DigraphNode& n) {
+ return Node(n, true);
+ }
+
+ static Node outNode(const DigraphNode& n) {
+ return Node(n, false);
+ }
+
+ static Arc arc(const DigraphNode& n) {
+ return Arc(n);
+ }
+
+ static Arc arc(const DigraphArc& e) {
+ return Arc(e);
+ }
+
+ typedef True NodeNumTag;
+ int nodeNum() const {
+ return 2 * countNodes(*_digraph);
+ }
+
+ typedef True ArcNumTag;
+ int arcNum() const {
+ return countArcs(*_digraph) + countNodes(*_digraph);
+ }
+
+ typedef True FindArcTag;
+ Arc findArc(const Node& u, const Node& v,
+ const Arc& prev = INVALID) const {
+ if (inNode(u) && outNode(v)) {
+ if (static_cast<const DigraphNode&>(u) ==
+ static_cast<const DigraphNode&>(v) && prev == INVALID) {
+ return Arc(u);
+ }
+ }
+ else if (outNode(u) && inNode(v)) {
+ return Arc(::lemon::findArc(*_digraph, u, v, prev));
+ }
+ return INVALID;
+ }
+
+ private:
+
+ template <typename V>
+ class NodeMapBase
+ : public MapTraits<typename Parent::template NodeMap<V> > {
+ typedef typename Parent::template NodeMap<V> NodeImpl;
+ public:
+ typedef Node Key;
+ typedef V Value;
+ typedef typename MapTraits<NodeImpl>::ReferenceMapTag ReferenceMapTag;
+ typedef typename MapTraits<NodeImpl>::ReturnValue ReturnValue;
+ typedef typename MapTraits<NodeImpl>::ConstReturnValue ConstReturnValue;
+ typedef typename MapTraits<NodeImpl>::ReturnValue Reference;
+ typedef typename MapTraits<NodeImpl>::ConstReturnValue ConstReference;
+
+ NodeMapBase(const SplitNodesBase<DGR>& adaptor)
+ : _in_map(*adaptor._digraph), _out_map(*adaptor._digraph) {}
+ NodeMapBase(const SplitNodesBase<DGR>& adaptor, const V& value)
+ : _in_map(*adaptor._digraph, value),
+ _out_map(*adaptor._digraph, value) {}
+
+ void set(const Node& key, const V& val) {
+ if (SplitNodesBase<DGR>::inNode(key)) { _in_map.set(key, val); }
+ else {_out_map.set(key, val); }
+ }
+
+ ReturnValue operator[](const Node& key) {
+ if (SplitNodesBase<DGR>::inNode(key)) { return _in_map[key]; }
+ else { return _out_map[key]; }
+ }
+
+ ConstReturnValue operator[](const Node& key) const {
+ if (Adaptor::inNode(key)) { return _in_map[key]; }
+ else { return _out_map[key]; }
+ }
+
+ private:
+ NodeImpl _in_map, _out_map;
+ };
+
+ template <typename V>
+ class ArcMapBase
+ : public MapTraits<typename Parent::template ArcMap<V> > {
+ typedef typename Parent::template ArcMap<V> ArcImpl;
+ typedef typename Parent::template NodeMap<V> NodeImpl;
+ public:
+ typedef Arc Key;
+ typedef V Value;
+ typedef typename MapTraits<ArcImpl>::ReferenceMapTag ReferenceMapTag;
+ typedef typename MapTraits<ArcImpl>::ReturnValue ReturnValue;
+ typedef typename MapTraits<ArcImpl>::ConstReturnValue ConstReturnValue;
+ typedef typename MapTraits<ArcImpl>::ReturnValue Reference;
+ typedef typename MapTraits<ArcImpl>::ConstReturnValue ConstReference;
+
+ ArcMapBase(const SplitNodesBase<DGR>& adaptor)
+ : _arc_map(*adaptor._digraph), _node_map(*adaptor._digraph) {}
+ ArcMapBase(const SplitNodesBase<DGR>& adaptor, const V& value)
+ : _arc_map(*adaptor._digraph, value),
+ _node_map(*adaptor._digraph, value) {}
+
+ void set(const Arc& key, const V& val) {
+ if (SplitNodesBase<DGR>::origArc(key)) {
+ _arc_map.set(static_cast<const DigraphArc&>(key), val);
+ } else {
+ _node_map.set(static_cast<const DigraphNode&>(key), val);
+ }
+ }
+
+ ReturnValue operator[](const Arc& key) {
+ if (SplitNodesBase<DGR>::origArc(key)) {
+ return _arc_map[static_cast<const DigraphArc&>(key)];
+ } else {
+ return _node_map[static_cast<const DigraphNode&>(key)];
+ }
+ }
+
+ ConstReturnValue operator[](const Arc& key) const {
+ if (SplitNodesBase<DGR>::origArc(key)) {
+ return _arc_map[static_cast<const DigraphArc&>(key)];
+ } else {
+ return _node_map[static_cast<const DigraphNode&>(key)];
+ }
+ }
+
+ private:
+ ArcImpl _arc_map;
+ NodeImpl _node_map;
+ };
+
+ public:
+
+ template <typename V>
+ class NodeMap
+ : public SubMapExtender<SplitNodesBase<DGR>, NodeMapBase<V> > {
+ typedef SubMapExtender<SplitNodesBase<DGR>, NodeMapBase<V> > Parent;
+
+ public:
+ typedef V Value;
+
+ NodeMap(const SplitNodesBase<DGR>& adaptor)
+ : Parent(adaptor) {}
+
+ NodeMap(const SplitNodesBase<DGR>& adaptor, const V& value)
+ : Parent(adaptor, value) {}
+
+ private:
+ NodeMap& operator=(const NodeMap& cmap) {
+ return operator=<NodeMap>(cmap);
+ }
+
+ template <typename CMap>
+ NodeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+ template <typename V>
+ class ArcMap
+ : public SubMapExtender<SplitNodesBase<DGR>, ArcMapBase<V> > {
+ typedef SubMapExtender<SplitNodesBase<DGR>, ArcMapBase<V> > Parent;
+
+ public:
+ typedef V Value;
+
+ ArcMap(const SplitNodesBase<DGR>& adaptor)
+ : Parent(adaptor) {}
+
+ ArcMap(const SplitNodesBase<DGR>& adaptor, const V& value)
+ : Parent(adaptor, value) {}
+
+ private:
+ ArcMap& operator=(const ArcMap& cmap) {
+ return operator=<ArcMap>(cmap);
+ }
+
+ template <typename CMap>
+ ArcMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+ protected:
+
+ SplitNodesBase() : _digraph(0) {}
+
+ DGR* _digraph;
+
+ void initialize(Digraph& digraph) {
+ _digraph = &digraph;
+ }
+
+ };
+
+ /// \ingroup graph_adaptors
+ ///
+ /// \brief Adaptor class for splitting the nodes of a digraph.
+ ///
+ /// SplitNodes adaptor can be used for splitting each node into an
+ /// \e in-node and an \e out-node in a digraph. Formaly, the adaptor
+ /// replaces each node \f$ u \f$ in the digraph with two nodes,
+ /// namely node \f$ u_{in} \f$ and node \f$ u_{out} \f$.
+ /// If there is a \f$ (v, u) \f$ arc in the original digraph, then the
+ /// new target of the arc will be \f$ u_{in} \f$ and similarly the
+ /// source of each original \f$ (u, v) \f$ arc will be \f$ u_{out} \f$.
+ /// The adaptor adds an additional \e bind \e arc from \f$ u_{in} \f$
+ /// to \f$ u_{out} \f$ for each node \f$ u \f$ of the original digraph.
+ ///
+ /// The aim of this class is running an algorithm with respect to node
+ /// costs or capacities if the algorithm considers only arc costs or
+ /// capacities directly.
+ /// In this case you can use \c SplitNodes adaptor, and set the node
+ /// costs/capacities of the original digraph to the \e bind \e arcs
+ /// in the adaptor.
+ ///
+ /// This class provides item counting in the same time as the adapted
+ /// digraph structure.
+ ///
+ /// \tparam DGR The type of the adapted digraph.
+ /// It must conform to the \ref concepts::Digraph "Digraph" concept.
+ /// It is implicitly \c const.
+ ///
+ /// \note The \c Node type of this adaptor is converible to the \c Node
+ /// type of the adapted digraph.
+ template <typename DGR>
+#ifdef DOXYGEN
+ class SplitNodes {
+#else
+ class SplitNodes
+ : public DigraphAdaptorExtender<SplitNodesBase<const DGR> > {
+#endif
+ typedef DigraphAdaptorExtender<SplitNodesBase<const DGR> > Parent;
+
+ public:
+ typedef DGR Digraph;
+
+ typedef typename DGR::Node DigraphNode;
+ typedef typename DGR::Arc DigraphArc;
+
+ typedef typename Parent::Node Node;
+ typedef typename Parent::Arc Arc;
+
+ /// \brief Constructor
+ ///
+ /// Constructor of the adaptor.
+ SplitNodes(const DGR& g) {
+ Parent::initialize(g);
+ }
+
+ /// \brief Returns \c true if the given node is an in-node.
+ ///
+ /// Returns \c true if the given node is an in-node.
+ static bool inNode(const Node& n) {
+ return Parent::inNode(n);
+ }
+
+ /// \brief Returns \c true if the given node is an out-node.
+ ///
+ /// Returns \c true if the given node is an out-node.
+ static bool outNode(const Node& n) {
+ return Parent::outNode(n);
+ }
+
+ /// \brief Returns \c true if the given arc is an original arc.
+ ///
+ /// Returns \c true if the given arc is one of the arcs in the
+ /// original digraph.
+ static bool origArc(const Arc& a) {
+ return Parent::origArc(a);
+ }
+
+ /// \brief Returns \c true if the given arc is a bind arc.
+ ///
+ /// Returns \c true if the given arc is a bind arc, i.e. it connects
+ /// an in-node and an out-node.
+ static bool bindArc(const Arc& a) {
+ return Parent::bindArc(a);
+ }
+
+ /// \brief Returns the in-node created from the given original node.
+ ///
+ /// Returns the in-node created from the given original node.
+ static Node inNode(const DigraphNode& n) {
+ return Parent::inNode(n);
+ }
+
+ /// \brief Returns the out-node created from the given original node.
+ ///
+ /// Returns the out-node created from the given original node.
+ static Node outNode(const DigraphNode& n) {
+ return Parent::outNode(n);
+ }
+
+ /// \brief Returns the bind arc that corresponds to the given
+ /// original node.
+ ///
+ /// Returns the bind arc in the adaptor that corresponds to the given
+ /// original node, i.e. the arc connecting the in-node and out-node
+ /// of \c n.
+ static Arc arc(const DigraphNode& n) {
+ return Parent::arc(n);
+ }
+
+ /// \brief Returns the arc that corresponds to the given original arc.
+ ///
+ /// Returns the arc in the adaptor that corresponds to the given
+ /// original arc.
+ static Arc arc(const DigraphArc& a) {
+ return Parent::arc(a);
+ }
+
+ /// \brief Node map combined from two original node maps
+ ///
+ /// This map adaptor class adapts two node maps of the original digraph
+ /// to get a node map of the split digraph.
+ /// Its value type is inherited from the first node map type (\c IN).
+ /// \tparam IN The type of the node map for the in-nodes.
+ /// \tparam OUT The type of the node map for the out-nodes.
+ template <typename IN, typename OUT>
+ class CombinedNodeMap {
+ public:
+
+ /// The key type of the map
+ typedef Node Key;
+ /// The value type of the map
+ typedef typename IN::Value Value;
+
+ typedef typename MapTraits<IN>::ReferenceMapTag ReferenceMapTag;
+ typedef typename MapTraits<IN>::ReturnValue ReturnValue;
+ typedef typename MapTraits<IN>::ConstReturnValue ConstReturnValue;
+ typedef typename MapTraits<IN>::ReturnValue Reference;
+ typedef typename MapTraits<IN>::ConstReturnValue ConstReference;
+
+ /// Constructor
+ CombinedNodeMap(IN& in_map, OUT& out_map)
+ : _in_map(in_map), _out_map(out_map) {}
+
+ /// Returns the value associated with the given key.
+ Value operator[](const Key& key) const {
+ if (SplitNodesBase<const DGR>::inNode(key)) {
+ return _in_map[key];
+ } else {
+ return _out_map[key];
+ }
+ }
+
+ /// Returns a reference to the value associated with the given key.
+ Value& operator[](const Key& key) {
+ if (SplitNodesBase<const DGR>::inNode(key)) {
+ return _in_map[key];
+ } else {
+ return _out_map[key];
+ }
+ }
+
+ /// Sets the value associated with the given key.
+ void set(const Key& key, const Value& value) {
+ if (SplitNodesBase<const DGR>::inNode(key)) {
+ _in_map.set(key, value);
+ } else {
+ _out_map.set(key, value);
+ }
+ }
+
+ private:
+
+ IN& _in_map;
+ OUT& _out_map;
+
+ };
+
+
+ /// \brief Returns a combined node map
+ ///
+ /// This function just returns a combined node map.
+ template <typename IN, typename OUT>
+ static CombinedNodeMap<IN, OUT>
+ combinedNodeMap(IN& in_map, OUT& out_map) {
+ return CombinedNodeMap<IN, OUT>(in_map, out_map);
+ }
+
+ template <typename IN, typename OUT>
+ static CombinedNodeMap<const IN, OUT>
+ combinedNodeMap(const IN& in_map, OUT& out_map) {
+ return CombinedNodeMap<const IN, OUT>(in_map, out_map);
+ }
+
+ template <typename IN, typename OUT>
+ static CombinedNodeMap<IN, const OUT>
+ combinedNodeMap(IN& in_map, const OUT& out_map) {
+ return CombinedNodeMap<IN, const OUT>(in_map, out_map);
+ }
+
+ template <typename IN, typename OUT>
+ static CombinedNodeMap<const IN, const OUT>
+ combinedNodeMap(const IN& in_map, const OUT& out_map) {
+ return CombinedNodeMap<const IN, const OUT>(in_map, out_map);
+ }
+
+ /// \brief Arc map combined from an arc map and a node map of the
+ /// original digraph.
+ ///
+ /// This map adaptor class adapts an arc map and a node map of the
+ /// original digraph to get an arc map of the split digraph.
+ /// Its value type is inherited from the original arc map type (\c AM).
+ /// \tparam AM The type of the arc map.
+ /// \tparam NM the type of the node map.
+ template <typename AM, typename NM>
+ class CombinedArcMap {
+ public:
+
+ /// The key type of the map
+ typedef Arc Key;
+ /// The value type of the map
+ typedef typename AM::Value Value;
+
+ typedef typename MapTraits<AM>::ReferenceMapTag ReferenceMapTag;
+ typedef typename MapTraits<AM>::ReturnValue ReturnValue;
+ typedef typename MapTraits<AM>::ConstReturnValue ConstReturnValue;
+ typedef typename MapTraits<AM>::ReturnValue Reference;
+ typedef typename MapTraits<AM>::ConstReturnValue ConstReference;
+
+ /// Constructor
+ CombinedArcMap(AM& arc_map, NM& node_map)
+ : _arc_map(arc_map), _node_map(node_map) {}
+
+ /// Returns the value associated with the given key.
+ Value operator[](const Key& arc) const {
+ if (SplitNodesBase<const DGR>::origArc(arc)) {
+ return _arc_map[arc];
+ } else {
+ return _node_map[arc];
+ }
+ }
+
+ /// Returns a reference to the value associated with the given key.
+ Value& operator[](const Key& arc) {
+ if (SplitNodesBase<const DGR>::origArc(arc)) {
+ return _arc_map[arc];
+ } else {
+ return _node_map[arc];
+ }
+ }
+
+ /// Sets the value associated with the given key.
+ void set(const Arc& arc, const Value& val) {
+ if (SplitNodesBase<const DGR>::origArc(arc)) {
+ _arc_map.set(arc, val);
+ } else {
+ _node_map.set(arc, val);
+ }
+ }
+
+ private:
+
+ AM& _arc_map;
+ NM& _node_map;
+
+ };
+
+ /// \brief Returns a combined arc map
+ ///
+ /// This function just returns a combined arc map.
+ template <typename ArcMap, typename NodeMap>
+ static CombinedArcMap<ArcMap, NodeMap>
+ combinedArcMap(ArcMap& arc_map, NodeMap& node_map) {
+ return CombinedArcMap<ArcMap, NodeMap>(arc_map, node_map);
+ }
+
+ template <typename ArcMap, typename NodeMap>
+ static CombinedArcMap<const ArcMap, NodeMap>
+ combinedArcMap(const ArcMap& arc_map, NodeMap& node_map) {
+ return CombinedArcMap<const ArcMap, NodeMap>(arc_map, node_map);
+ }
+
+ template <typename ArcMap, typename NodeMap>
+ static CombinedArcMap<ArcMap, const NodeMap>
+ combinedArcMap(ArcMap& arc_map, const NodeMap& node_map) {
+ return CombinedArcMap<ArcMap, const NodeMap>(arc_map, node_map);
+ }
+
+ template <typename ArcMap, typename NodeMap>
+ static CombinedArcMap<const ArcMap, const NodeMap>
+ combinedArcMap(const ArcMap& arc_map, const NodeMap& node_map) {
+ return CombinedArcMap<const ArcMap, const NodeMap>(arc_map, node_map);
+ }
+
+ };
+
+ /// \brief Returns a (read-only) SplitNodes adaptor
+ ///
+ /// This function just returns a (read-only) \ref SplitNodes adaptor.
+ /// \ingroup graph_adaptors
+ /// \relates SplitNodes
+ template<typename DGR>
+ SplitNodes<DGR>
+ splitNodes(const DGR& digraph) {
+ return SplitNodes<DGR>(digraph);
+ }
+
+#undef LEMON_SCOPE_FIX
+
+} //namespace lemon
+
+#endif //LEMON_ADAPTORS_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc
new file mode 100644
index 00000000000..0eeba8ab6c2
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc
@@ -0,0 +1,473 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2010
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <lemon/arg_parser.h>
+
+namespace lemon {
+
+ void ArgParser::_terminate(ArgParserException::Reason reason) const
+ {
+ if(_exit_on_problems)
+ exit(1);
+ else throw(ArgParserException(reason));
+ }
+
+
+ void ArgParser::_showHelp(void *p)
+ {
+ (static_cast<ArgParser*>(p))->showHelp();
+ (static_cast<ArgParser*>(p))->_terminate(ArgParserException::HELP);
+ }
+
+ ArgParser::ArgParser(int argc, const char * const *argv)
+ :_argc(argc), _argv(argv), _command_name(argv[0]),
+ _exit_on_problems(true) {
+ funcOption("-help","Print a short help message",_showHelp,this);
+ synonym("help","-help");
+ synonym("h","-help");
+ }
+
+ ArgParser::~ArgParser()
+ {
+ for(Opts::iterator i=_opts.begin();i!=_opts.end();++i)
+ if(i->second.self_delete)
+ switch(i->second.type) {
+ case BOOL:
+ delete i->second.bool_p;
+ break;
+ case STRING:
+ delete i->second.string_p;
+ break;
+ case DOUBLE:
+ delete i->second.double_p;
+ break;
+ case INTEGER:
+ delete i->second.int_p;
+ break;
+ case UNKNOWN:
+ break;
+ case FUNC:
+ break;
+ }
+ }
+
+
+ ArgParser &ArgParser::intOption(const std::string &name,
+ const std::string &help,
+ int value, bool obl)
+ {
+ ParData p;
+ p.int_p=new int(value);
+ p.self_delete=true;
+ p.help=help;
+ p.type=INTEGER;
+ p.mandatory=obl;
+ _opts[name]=p;
+ return *this;
+ }
+
+ ArgParser &ArgParser::doubleOption(const std::string &name,
+ const std::string &help,
+ double value, bool obl)
+ {
+ ParData p;
+ p.double_p=new double(value);
+ p.self_delete=true;
+ p.help=help;
+ p.type=DOUBLE;
+ p.mandatory=obl;
+ _opts[name]=p;
+ return *this;
+ }
+
+ ArgParser &ArgParser::boolOption(const std::string &name,
+ const std::string &help,
+ bool value, bool obl)
+ {
+ ParData p;
+ p.bool_p=new bool(value);
+ p.self_delete=true;
+ p.help=help;
+ p.type=BOOL;
+ p.mandatory=obl;
+ _opts[name]=p;
+ return *this;
+ }
+
+ ArgParser &ArgParser::stringOption(const std::string &name,
+ const std::string &help,
+ std::string value, bool obl)
+ {
+ ParData p;
+ p.string_p=new std::string(value);
+ p.self_delete=true;
+ p.help=help;
+ p.type=STRING;
+ p.mandatory=obl;
+ _opts[name]=p;
+ return *this;
+ }
+
+ ArgParser &ArgParser::refOption(const std::string &name,
+ const std::string &help,
+ int &ref, bool obl)
+ {
+ ParData p;
+ p.int_p=&ref;
+ p.self_delete=false;
+ p.help=help;
+ p.type=INTEGER;
+ p.mandatory=obl;
+ _opts[name]=p;
+ return *this;
+ }
+
+ ArgParser &ArgParser::refOption(const std::string &name,
+ const std::string &help,
+ double &ref, bool obl)
+ {
+ ParData p;
+ p.double_p=&ref;
+ p.self_delete=false;
+ p.help=help;
+ p.type=DOUBLE;
+ p.mandatory=obl;
+ _opts[name]=p;
+ return *this;
+ }
+
+ ArgParser &ArgParser::refOption(const std::string &name,
+ const std::string &help,
+ bool &ref, bool obl)
+ {
+ ParData p;
+ p.bool_p=&ref;
+ p.self_delete=false;
+ p.help=help;
+ p.type=BOOL;
+ p.mandatory=obl;
+ _opts[name]=p;
+
+ ref = false;
+
+ return *this;
+ }
+
+ ArgParser &ArgParser::refOption(const std::string &name,
+ const std::string &help,
+ std::string &ref, bool obl)
+ {
+ ParData p;
+ p.string_p=&ref;
+ p.self_delete=false;
+ p.help=help;
+ p.type=STRING;
+ p.mandatory=obl;
+ _opts[name]=p;
+ return *this;
+ }
+
+ ArgParser &ArgParser::funcOption(const std::string &name,
+ const std::string &help,
+ void (*func)(void *),void *data)
+ {
+ ParData p;
+ p.func_p.p=func;
+ p.func_p.data=data;
+ p.self_delete=false;
+ p.help=help;
+ p.type=FUNC;
+ p.mandatory=false;
+ _opts[name]=p;
+ return *this;
+ }
+
+ ArgParser &ArgParser::optionGroup(const std::string &group,
+ const std::string &opt)
+ {
+ Opts::iterator i = _opts.find(opt);
+ LEMON_ASSERT(i!=_opts.end(), "Unknown option: '"+opt+"'");
+ LEMON_ASSERT(!(i->second.ingroup),
+ "Option already in option group: '"+opt+"'");
+ GroupData &g=_groups[group];
+ g.opts.push_back(opt);
+ i->second.ingroup=true;
+ return *this;
+ }
+
+ ArgParser &ArgParser::onlyOneGroup(const std::string &group)
+ {
+ GroupData &g=_groups[group];
+ g.only_one=true;
+ return *this;
+ }
+
+ ArgParser &ArgParser::synonym(const std::string &syn,
+ const std::string &opt)
+ {
+ Opts::iterator o = _opts.find(opt);
+ LEMON_ASSERT(o!=_opts.end(), "Unknown option: '"+opt+"'");
+ LEMON_ASSERT(_opts.find(syn)==_opts.end(), "Option already used: '"+syn+"'");
+ ParData p;
+ p.help=opt;
+ p.mandatory=false;
+ p.syn=true;
+ _opts[syn]=p;
+ o->second.has_syn=true;
+ return *this;
+ }
+
+ ArgParser &ArgParser::mandatoryGroup(const std::string &group)
+ {
+ GroupData &g=_groups[group];
+ g.mandatory=true;
+ return *this;
+ }
+
+ ArgParser &ArgParser::other(const std::string &name,
+ const std::string &help)
+ {
+ _others_help.push_back(OtherArg(name,help));
+ return *this;
+ }
+
+ void ArgParser::show(std::ostream &os,Opts::const_iterator i) const
+ {
+ os << "-" << i->first;
+ if(i->second.has_syn)
+ for(Opts::const_iterator j=_opts.begin();j!=_opts.end();++j)
+ if(j->second.syn&&j->second.help==i->first)
+ os << "|-" << j->first;
+ switch(i->second.type) {
+ case STRING:
+ os << " str";
+ break;
+ case INTEGER:
+ os << " int";
+ break;
+ case DOUBLE:
+ os << " num";
+ break;
+ default:
+ break;
+ }
+ }
+
+ void ArgParser::show(std::ostream &os,Groups::const_iterator i) const
+ {
+ GroupData::Opts::const_iterator o=i->second.opts.begin();
+ while(o!=i->second.opts.end()) {
+ show(os,_opts.find(*o));
+ ++o;
+ if(o!=i->second.opts.end()) os<<'|';
+ }
+ }
+
+ void ArgParser::showHelp(Opts::const_iterator i) const
+ {
+ if(i->second.help.size()==0||i->second.syn) return;
+ std::cerr << " ";
+ show(std::cerr,i);
+ std::cerr << std::endl;
+ std::cerr << " " << i->second.help << std::endl;
+ }
+ void ArgParser::showHelp(std::vector<ArgParser::OtherArg>::const_iterator i)
+ const
+ {
+ if(i->help.size()==0) return;
+ std::cerr << " " << i->name << std::endl
+ << " " << i->help << std::endl;
+ }
+
+ void ArgParser::shortHelp() const
+ {
+ const unsigned int LINE_LEN=77;
+ const std::string indent(" ");
+ std::cerr << "Usage:\n " << _command_name;
+ int pos=_command_name.size()+2;
+ for(Groups::const_iterator g=_groups.begin();g!=_groups.end();++g) {
+ std::ostringstream cstr;
+ cstr << ' ';
+ if(!g->second.mandatory) cstr << '[';
+ show(cstr,g);
+ if(!g->second.mandatory) cstr << ']';
+ if(pos+cstr.str().size()>LINE_LEN) {
+ std::cerr << std::endl << indent;
+ pos=indent.size();
+ }
+ std::cerr << cstr.str();
+ pos+=cstr.str().size();
+ }
+ for(Opts::const_iterator i=_opts.begin();i!=_opts.end();++i)
+ if(!i->second.ingroup&&!i->second.syn) {
+ std::ostringstream cstr;
+ cstr << ' ';
+ if(!i->second.mandatory) cstr << '[';
+ show(cstr,i);
+ if(!i->second.mandatory) cstr << ']';
+ if(pos+cstr.str().size()>LINE_LEN) {
+ std::cerr << std::endl << indent;
+ pos=indent.size();
+ }
+ std::cerr << cstr.str();
+ pos+=cstr.str().size();
+ }
+ for(std::vector<OtherArg>::const_iterator i=_others_help.begin();
+ i!=_others_help.end();++i)
+ {
+ std::ostringstream cstr;
+ cstr << ' ' << i->name;
+
+ if(pos+cstr.str().size()>LINE_LEN) {
+ std::cerr << std::endl << indent;
+ pos=indent.size();
+ }
+ std::cerr << cstr.str();
+ pos+=cstr.str().size();
+ }
+ std::cerr << std::endl;
+ }
+
+ void ArgParser::showHelp() const
+ {
+ shortHelp();
+ std::cerr << "Where:\n";
+ for(std::vector<OtherArg>::const_iterator i=_others_help.begin();
+ i!=_others_help.end();++i) showHelp(i);
+ for(Opts::const_iterator i=_opts.begin();i!=_opts.end();++i) showHelp(i);
+ _terminate(ArgParserException::HELP);
+ }
+
+
+ void ArgParser::unknownOpt(std::string arg) const
+ {
+ std::cerr << "\nUnknown option: " << arg << "\n";
+ std::cerr << "\nType '" << _command_name <<
+ " --help' to obtain a short summary on the usage.\n\n";
+ _terminate(ArgParserException::UNKNOWN_OPT);
+ }
+
+ void ArgParser::requiresValue(std::string arg, OptType t) const
+ {
+ std::cerr << "Argument '" << arg << "' requires a";
+ switch(t) {
+ case STRING:
+ std::cerr << " string";
+ break;
+ case INTEGER:
+ std::cerr << "n integer";
+ break;
+ case DOUBLE:
+ std::cerr << " floating point";
+ break;
+ default:
+ break;
+ }
+ std::cerr << " value\n\n";
+ showHelp();
+ }
+
+
+ void ArgParser::checkMandatories() const
+ {
+ bool ok=true;
+ for(Opts::const_iterator i=_opts.begin();i!=_opts.end();++i)
+ if(i->second.mandatory&&!i->second.set)
+ {
+ if(ok)
+ std::cerr << _command_name
+ << ": The following mandatory arguments are missing.\n";
+ ok=false;
+ showHelp(i);
+ }
+ for(Groups::const_iterator i=_groups.begin();i!=_groups.end();++i)
+ if(i->second.mandatory||i->second.only_one)
+ {
+ int set=0;
+ for(GroupData::Opts::const_iterator o=i->second.opts.begin();
+ o!=i->second.opts.end();++o)
+ if(_opts.find(*o)->second.set) ++set;
+ if(i->second.mandatory&&!set) {
+ std::cerr << _command_name <<
+ ": At least one of the following arguments is mandatory.\n";
+ ok=false;
+ for(GroupData::Opts::const_iterator o=i->second.opts.begin();
+ o!=i->second.opts.end();++o)
+ showHelp(_opts.find(*o));
+ }
+ if(i->second.only_one&&set>1) {
+ std::cerr << _command_name <<
+ ": At most one of the following arguments can be given.\n";
+ ok=false;
+ for(GroupData::Opts::const_iterator o=i->second.opts.begin();
+ o!=i->second.opts.end();++o)
+ showHelp(_opts.find(*o));
+ }
+ }
+ if(!ok) {
+ std::cerr << "\nType '" << _command_name <<
+ " --help' to obtain a short summary on the usage.\n\n";
+ _terminate(ArgParserException::INVALID_OPT);
+ }
+ }
+
+ ArgParser &ArgParser::parse()
+ {
+ for(int ar=1; ar<_argc; ++ar) {
+ std::string arg(_argv[ar]);
+ if (arg[0] != '-' || arg.size() == 1) {
+ _file_args.push_back(arg);
+ }
+ else {
+ Opts::iterator i = _opts.find(arg.substr(1));
+ if(i==_opts.end()) unknownOpt(arg);
+ else {
+ if(i->second.syn) i=_opts.find(i->second.help);
+ ParData &p(i->second);
+ if (p.type==BOOL) *p.bool_p=true;
+ else if (p.type==FUNC) p.func_p.p(p.func_p.data);
+ else if(++ar==_argc) requiresValue(arg, p.type);
+ else {
+ std::string val(_argv[ar]);
+ std::istringstream vals(val);
+ switch(p.type) {
+ case STRING:
+ *p.string_p=val;
+ break;
+ case INTEGER:
+ vals >> *p.int_p;
+ break;
+ case DOUBLE:
+ vals >> *p.double_p;
+ break;
+ default:
+ break;
+ }
+ if(p.type!=STRING&&(!vals||!vals.eof()))
+ requiresValue(arg, p.type);
+ }
+ p.set = true;
+ }
+ }
+ }
+ checkMandatories();
+
+ return *this;
+ }
+
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.h
new file mode 100644
index 00000000000..3fbe75c97e5
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.h
@@ -0,0 +1,440 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2010
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_ARG_PARSER_H
+#define LEMON_ARG_PARSER_H
+
+#include <vector>
+#include <map>
+#include <list>
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <algorithm>
+#include <lemon/assert.h>
+
+///\ingroup misc
+///\file
+///\brief A tool to parse command line arguments.
+
+namespace lemon {
+
+ ///Exception used by ArgParser
+
+ ///Exception used by ArgParser.
+ ///
+ class ArgParserException : public Exception {
+ public:
+ /// Reasons for failure
+
+ /// Reasons for failure.
+ ///
+ enum Reason {
+ HELP, ///< <tt>--help</tt> option was given.
+ UNKNOWN_OPT, ///< Unknown option was given.
+ INVALID_OPT ///< Invalid combination of options.
+ };
+
+ private:
+ Reason _reason;
+
+ public:
+ ///Constructor
+ ArgParserException(Reason r) throw() : _reason(r) {}
+ ///Virtual destructor
+ virtual ~ArgParserException() throw() {}
+ ///A short description of the exception
+ virtual const char* what() const throw() {
+ switch(_reason)
+ {
+ case HELP:
+ return "lemon::ArgParseException: ask for help";
+ break;
+ case UNKNOWN_OPT:
+ return "lemon::ArgParseException: unknown option";
+ break;
+ case INVALID_OPT:
+ return "lemon::ArgParseException: invalid combination of options";
+ break;
+ }
+ return "";
+ }
+ ///Return the reason for the failure
+ Reason reason() const {return _reason; }
+ };
+
+
+ ///Command line arguments parser
+
+ ///\ingroup misc
+ ///Command line arguments parser.
+ ///
+ ///For a complete example see the \ref arg_parser_demo.cc demo file.
+ class ArgParser {
+
+ static void _showHelp(void *p);
+ protected:
+
+ int _argc;
+ const char * const *_argv;
+
+ enum OptType { UNKNOWN=0, BOOL=1, STRING=2, DOUBLE=3, INTEGER=4, FUNC=5 };
+
+ class ParData {
+ public:
+ union {
+ bool *bool_p;
+ int *int_p;
+ double *double_p;
+ std::string *string_p;
+ struct {
+ void (*p)(void *);
+ void *data;
+ } func_p;
+
+ };
+ std::string help;
+ bool mandatory;
+ OptType type;
+ bool set;
+ bool ingroup;
+ bool has_syn;
+ bool syn;
+ bool self_delete;
+ ParData() : mandatory(false), type(UNKNOWN), set(false), ingroup(false),
+ has_syn(false), syn(false), self_delete(false) {}
+ };
+
+ typedef std::map<std::string,ParData> Opts;
+ Opts _opts;
+
+ class GroupData
+ {
+ public:
+ typedef std::list<std::string> Opts;
+ Opts opts;
+ bool only_one;
+ bool mandatory;
+ GroupData() :only_one(false), mandatory(false) {}
+ };
+
+ typedef std::map<std::string,GroupData> Groups;
+ Groups _groups;
+
+ struct OtherArg
+ {
+ std::string name;
+ std::string help;
+ OtherArg(std::string n, std::string h) :name(n), help(h) {}
+
+ };
+
+ std::vector<OtherArg> _others_help;
+ std::vector<std::string> _file_args;
+ std::string _command_name;
+
+
+ private:
+ //Bind a function to an option.
+
+ //\param name The name of the option. The leading '-' must be omitted.
+ //\param help A help string.
+ //\retval func The function to be called when the option is given. It
+ // must be of type "void f(void *)"
+ //\param data Data to be passed to \c func
+ ArgParser &funcOption(const std::string &name,
+ const std::string &help,
+ void (*func)(void *),void *data);
+
+ bool _exit_on_problems;
+
+ void _terminate(ArgParserException::Reason reason) const;
+
+ public:
+
+ ///Constructor
+ ArgParser(int argc, const char * const *argv);
+
+ ~ArgParser();
+
+ ///\name Options
+ ///
+
+ ///@{
+
+ ///Add a new integer type option
+
+ ///Add a new integer type option.
+ ///\param name The name of the option. The leading '-' must be omitted.
+ ///\param help A help string.
+ ///\param value A default value for the option.
+ ///\param obl Indicate if the option is mandatory.
+ ArgParser &intOption(const std::string &name,
+ const std::string &help,
+ int value=0, bool obl=false);
+
+ ///Add a new floating point type option
+
+ ///Add a new floating point type option.
+ ///\param name The name of the option. The leading '-' must be omitted.
+ ///\param help A help string.
+ ///\param value A default value for the option.
+ ///\param obl Indicate if the option is mandatory.
+ ArgParser &doubleOption(const std::string &name,
+ const std::string &help,
+ double value=0, bool obl=false);
+
+ ///Add a new bool type option
+
+ ///Add a new bool type option.
+ ///\param name The name of the option. The leading '-' must be omitted.
+ ///\param help A help string.
+ ///\param value A default value for the option.
+ ///\param obl Indicate if the option is mandatory.
+ ///\note A mandatory bool obtion is of very little use.
+ ArgParser &boolOption(const std::string &name,
+ const std::string &help,
+ bool value=false, bool obl=false);
+
+ ///Add a new string type option
+
+ ///Add a new string type option.
+ ///\param name The name of the option. The leading '-' must be omitted.
+ ///\param help A help string.
+ ///\param value A default value for the option.
+ ///\param obl Indicate if the option is mandatory.
+ ArgParser &stringOption(const std::string &name,
+ const std::string &help,
+ std::string value="", bool obl=false);
+
+ ///Give help string for non-parsed arguments.
+
+ ///With this function you can give help string for non-parsed arguments.
+ ///The parameter \c name will be printed in the short usage line, while
+ ///\c help gives a more detailed description.
+ ArgParser &other(const std::string &name,
+ const std::string &help="");
+
+ ///@}
+
+ ///\name Options with External Storage
+ ///Using this functions, the value of the option will be directly written
+ ///into a variable once the option appears in the command line.
+
+ ///@{
+
+ ///Add a new integer type option with a storage reference
+
+ ///Add a new integer type option with a storage reference.
+ ///\param name The name of the option. The leading '-' must be omitted.
+ ///\param help A help string.
+ ///\param obl Indicate if the option is mandatory.
+ ///\retval ref The value of the argument will be written to this variable.
+ ArgParser &refOption(const std::string &name,
+ const std::string &help,
+ int &ref, bool obl=false);
+
+ ///Add a new floating type option with a storage reference
+
+ ///Add a new floating type option with a storage reference.
+ ///\param name The name of the option. The leading '-' must be omitted.
+ ///\param help A help string.
+ ///\param obl Indicate if the option is mandatory.
+ ///\retval ref The value of the argument will be written to this variable.
+ ArgParser &refOption(const std::string &name,
+ const std::string &help,
+ double &ref, bool obl=false);
+
+ ///Add a new bool type option with a storage reference
+
+ ///Add a new bool type option with a storage reference.
+ ///\param name The name of the option. The leading '-' must be omitted.
+ ///\param help A help string.
+ ///\param obl Indicate if the option is mandatory.
+ ///\retval ref The value of the argument will be written to this variable.
+ ///\note A mandatory bool obtion is of very little use.
+ ArgParser &refOption(const std::string &name,
+ const std::string &help,
+ bool &ref, bool obl=false);
+
+ ///Add a new string type option with a storage reference
+
+ ///Add a new string type option with a storage reference.
+ ///\param name The name of the option. The leading '-' must be omitted.
+ ///\param help A help string.
+ ///\param obl Indicate if the option is mandatory.
+ ///\retval ref The value of the argument will be written to this variable.
+ ArgParser &refOption(const std::string &name,
+ const std::string &help,
+ std::string &ref, bool obl=false);
+
+ ///@}
+
+ ///\name Option Groups and Synonyms
+ ///
+
+ ///@{
+
+ ///Bundle some options into a group
+
+ /// You can group some option by calling this function repeatedly for each
+ /// option to be grouped with the same groupname.
+ ///\param group The group name.
+ ///\param opt The option name.
+ ArgParser &optionGroup(const std::string &group,
+ const std::string &opt);
+
+ ///Make the members of a group exclusive
+
+ ///If you call this function for a group, than at most one of them can be
+ ///given at the same time.
+ ArgParser &onlyOneGroup(const std::string &group);
+
+ ///Make a group mandatory
+
+ ///Using this function, at least one of the members of \c group
+ ///must be given.
+ ArgParser &mandatoryGroup(const std::string &group);
+
+ ///Create synonym to an option
+
+ ///With this function you can create a synonym \c syn of the
+ ///option \c opt.
+ ArgParser &synonym(const std::string &syn,
+ const std::string &opt);
+
+ ///@}
+
+ private:
+ void show(std::ostream &os,Opts::const_iterator i) const;
+ void show(std::ostream &os,Groups::const_iterator i) const;
+ void showHelp(Opts::const_iterator i) const;
+ void showHelp(std::vector<OtherArg>::const_iterator i) const;
+
+ void unknownOpt(std::string arg) const;
+
+ void requiresValue(std::string arg, OptType t) const;
+ void checkMandatories() const;
+
+ void shortHelp() const;
+ void showHelp() const;
+ public:
+
+ ///Start the parsing process
+ ArgParser &parse();
+
+ /// Synonym for parse()
+ ArgParser &run()
+ {
+ return parse();
+ }
+
+ ///Give back the command name (the 0th argument)
+ const std::string &commandName() const { return _command_name; }
+
+ ///Check if an opion has been given to the command.
+ bool given(std::string op) const
+ {
+ Opts::const_iterator i = _opts.find(op);
+ return i!=_opts.end()?i->second.set:false;
+ }
+
+
+ ///Magic type for operator[]
+
+ ///This is the type of the return value of ArgParser::operator[]().
+ ///It automatically converts to \c int, \c double, \c bool or
+ ///\c std::string if the type of the option matches, which is checked
+ ///with an \ref LEMON_ASSERT "assertion" (i.e. it performs runtime
+ ///type checking).
+ class RefType
+ {
+ const ArgParser &_parser;
+ std::string _name;
+ public:
+ ///\e
+ RefType(const ArgParser &p,const std::string &n) :_parser(p),_name(n) {}
+ ///\e
+ operator bool()
+ {
+ Opts::const_iterator i = _parser._opts.find(_name);
+ LEMON_ASSERT(i!=_parser._opts.end(),
+ std::string()+"Unkown option: '"+_name+"'");
+ LEMON_ASSERT(i->second.type==ArgParser::BOOL,
+ std::string()+"'"+_name+"' is a bool option");
+ return *(i->second.bool_p);
+ }
+ ///\e
+ operator std::string()
+ {
+ Opts::const_iterator i = _parser._opts.find(_name);
+ LEMON_ASSERT(i!=_parser._opts.end(),
+ std::string()+"Unkown option: '"+_name+"'");
+ LEMON_ASSERT(i->second.type==ArgParser::STRING,
+ std::string()+"'"+_name+"' is a string option");
+ return *(i->second.string_p);
+ }
+ ///\e
+ operator double()
+ {
+ Opts::const_iterator i = _parser._opts.find(_name);
+ LEMON_ASSERT(i!=_parser._opts.end(),
+ std::string()+"Unkown option: '"+_name+"'");
+ LEMON_ASSERT(i->second.type==ArgParser::DOUBLE ||
+ i->second.type==ArgParser::INTEGER,
+ std::string()+"'"+_name+"' is a floating point option");
+ return i->second.type==ArgParser::DOUBLE ?
+ *(i->second.double_p) : *(i->second.int_p);
+ }
+ ///\e
+ operator int()
+ {
+ Opts::const_iterator i = _parser._opts.find(_name);
+ LEMON_ASSERT(i!=_parser._opts.end(),
+ std::string()+"Unkown option: '"+_name+"'");
+ LEMON_ASSERT(i->second.type==ArgParser::INTEGER,
+ std::string()+"'"+_name+"' is an integer option");
+ return *(i->second.int_p);
+ }
+
+ };
+
+ ///Give back the value of an option
+
+ ///Give back the value of an option.
+ ///\sa RefType
+ RefType operator[](const std::string &n) const
+ {
+ return RefType(*this, n);
+ }
+
+ ///Give back the non-option type arguments.
+
+ ///Give back a reference to a vector consisting of the program arguments
+ ///not starting with a '-' character.
+ const std::vector<std::string> &files() const { return _file_args; }
+
+ ///Throw instead of exit in case of problems
+ void throwOnProblems()
+ {
+ _exit_on_problems=false;
+ }
+ };
+}
+
+#endif // LEMON_ARG_PARSER_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/assert.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/assert.h
new file mode 100644
index 00000000000..f6c1dfc8e59
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/assert.h
@@ -0,0 +1,214 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_ASSERT_H
+#define LEMON_ASSERT_H
+
+/// \ingroup exceptions
+/// \file
+/// \brief Extended assertion handling
+
+#include <lemon/error.h>
+
+namespace lemon {
+
+ inline void assert_fail_abort(const char *file, int line,
+ const char *function, const char* message,
+ const char *assertion)
+ {
+ std::cerr << file << ":" << line << ": ";
+ if (function)
+ std::cerr << function << ": ";
+ std::cerr << message;
+ if (assertion)
+ std::cerr << " (assertion '" << assertion << "' failed)";
+ std::cerr << std::endl;
+ std::abort();
+ }
+
+ namespace _assert_bits {
+
+
+ inline const char* cstringify(const std::string& str) {
+ return str.c_str();
+ }
+
+ inline const char* cstringify(const char* str) {
+ return str;
+ }
+ }
+}
+
+#endif // LEMON_ASSERT_H
+
+#undef LEMON_ASSERT
+#undef LEMON_DEBUG
+
+#if (defined(LEMON_ASSERT_ABORT) ? 1 : 0) + \
+ (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) > 1
+#error "LEMON assertion system is not set properly"
+#endif
+
+#if ((defined(LEMON_ASSERT_ABORT) ? 1 : 0) + \
+ (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) == 1 || \
+ defined(LEMON_ENABLE_ASSERTS)) && \
+ (defined(LEMON_DISABLE_ASSERTS) || \
+ defined(NDEBUG))
+#error "LEMON assertion system is not set properly"
+#endif
+
+
+#if defined LEMON_ASSERT_ABORT
+# undef LEMON_ASSERT_HANDLER
+# define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort
+#elif defined LEMON_ASSERT_CUSTOM
+# undef LEMON_ASSERT_HANDLER
+# ifndef LEMON_CUSTOM_ASSERT_HANDLER
+# error "LEMON_CUSTOM_ASSERT_HANDLER is not set"
+# endif
+# define LEMON_ASSERT_HANDLER LEMON_CUSTOM_ASSERT_HANDLER
+#elif defined LEMON_DISABLE_ASSERTS
+# undef LEMON_ASSERT_HANDLER
+#elif defined NDEBUG
+# undef LEMON_ASSERT_HANDLER
+#else
+# define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort
+#endif
+
+#ifndef LEMON_FUNCTION_NAME
+# if defined __GNUC__
+# define LEMON_FUNCTION_NAME (__PRETTY_FUNCTION__)
+# elif defined _MSC_VER
+# define LEMON_FUNCTION_NAME (__FUNCSIG__)
+# elif __STDC_VERSION__ >= 199901L
+# define LEMON_FUNCTION_NAME (__func__)
+# else
+# define LEMON_FUNCTION_NAME ("<unknown>")
+# endif
+#endif
+
+#ifdef DOXYGEN
+
+/// \ingroup exceptions
+///
+/// \brief Macro for assertion with customizable message
+///
+/// Macro for assertion with customizable message.
+/// \param exp An expression that must be convertible to \c bool. If it is \c
+/// false, then an assertion is raised. The concrete behaviour depends on the
+/// settings of the assertion system.
+/// \param msg A <tt>const char*</tt> parameter, which can be used to provide
+/// information about the circumstances of the failed assertion.
+///
+/// The assertions are enabled in the default behaviour.
+/// You can disable them with the following code:
+/// \code
+/// #define LEMON_DISABLE_ASSERTS
+/// \endcode
+/// or with compilation parameters:
+/// \code
+/// g++ -DLEMON_DISABLE_ASSERTS
+/// make CXXFLAGS='-DLEMON_DISABLE_ASSERTS'
+/// \endcode
+/// The checking is also disabled when the standard macro \c NDEBUG is defined.
+///
+/// As a default behaviour the failed assertion prints a short log message to
+/// the standard error and aborts the execution.
+///
+/// However, the following modes can be used in the assertion system:
+/// - \c LEMON_ASSERT_ABORT The failed assertion prints a short log message to
+/// the standard error and aborts the program. It is the default behaviour.
+/// - \c LEMON_ASSERT_CUSTOM The user can define own assertion handler
+/// function.
+/// \code
+/// void custom_assert_handler(const char* file, int line,
+/// const char* function, const char* message,
+/// const char* assertion);
+/// \endcode
+/// The name of the function should be defined as the \c
+/// LEMON_CUSTOM_ASSERT_HANDLER macro name.
+/// \code
+/// #define LEMON_CUSTOM_ASSERT_HANDLER custom_assert_handler
+/// \endcode
+/// Whenever an assertion is occured, the custom assertion
+/// handler is called with appropiate parameters.
+///
+/// The assertion mode can also be changed within one compilation unit.
+/// If the macros are redefined with other settings and the
+/// \ref lemon/assert.h "assert.h" file is reincluded, then the
+/// behaviour is changed appropiately to the new settings.
+# define LEMON_ASSERT(exp, msg) \
+ (static_cast<void> (!!(exp) ? 0 : ( \
+ LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \
+ LEMON_FUNCTION_NAME, \
+ ::lemon::_assert_bits::cstringify(msg), #exp), 0)))
+
+/// \ingroup exceptions
+///
+/// \brief Macro for internal assertions
+///
+/// Macro for internal assertions, it is used in the library to check
+/// the consistency of results of algorithms, several pre- and
+/// postconditions and invariants. The checking is disabled by
+/// default, but it can be turned on with the macro \c
+/// LEMON_ENABLE_DEBUG.
+/// \code
+/// #define LEMON_ENABLE_DEBUG
+/// \endcode
+/// or with compilation parameters:
+/// \code
+/// g++ -DLEMON_ENABLE_DEBUG
+/// make CXXFLAGS='-DLEMON_ENABLE_DEBUG'
+/// \endcode
+///
+/// This macro works like the \c LEMON_ASSERT macro, therefore the
+/// current behaviour depends on the settings of \c LEMON_ASSERT
+/// macro.
+///
+/// \see LEMON_ASSERT
+# define LEMON_DEBUG(exp, msg) \
+ (static_cast<void> (!!(exp) ? 0 : ( \
+ LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \
+ LEMON_FUNCTION_NAME, \
+ ::lemon::_assert_bits::cstringify(msg), #exp), 0)))
+
+#else
+
+# ifndef LEMON_ASSERT_HANDLER
+# define LEMON_ASSERT(exp, msg) (static_cast<void>(0))
+# define LEMON_DEBUG(exp, msg) (static_cast<void>(0))
+# else
+# define LEMON_ASSERT(exp, msg) \
+ (static_cast<void> (!!(exp) ? 0 : ( \
+ LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \
+ LEMON_FUNCTION_NAME, \
+ ::lemon::_assert_bits::cstringify(msg), \
+ #exp), 0)))
+# if defined LEMON_ENABLE_DEBUG
+# define LEMON_DEBUG(exp, msg) \
+ (static_cast<void> (!!(exp) ? 0 : ( \
+ LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \
+ LEMON_FUNCTION_NAME, \
+ ::lemon::_assert_bits::cstringify(msg), \
+ #exp), 0)))
+# else
+# define LEMON_DEBUG(exp, msg) (static_cast<void>(0))
+# endif
+# endif
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/base.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/base.cc
new file mode 100644
index 00000000000..a057b41cbc0
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/base.cc
@@ -0,0 +1,37 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+///\file
+///\brief Some basic non-inline functions and static global data.
+
+#include<lemon/tolerance.h>
+#include<lemon/core.h>
+#include<lemon/time_measure.h>
+namespace lemon {
+
+ float Tolerance<float>::def_epsilon = static_cast<float>(1e-4);
+ double Tolerance<double>::def_epsilon = 1e-10;
+ long double Tolerance<long double>::def_epsilon = 1e-14;
+
+#ifndef LEMON_ONLY_TEMPLATES
+ const Invalid INVALID = Invalid();
+#endif
+
+ TimeStamp::Format TimeStamp::_format = TimeStamp::NORMAL;
+
+} //namespace lemon
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bellman_ford.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bellman_ford.h
new file mode 100644
index 00000000000..310758ebb59
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bellman_ford.h
@@ -0,0 +1,1116 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_BELLMAN_FORD_H
+#define LEMON_BELLMAN_FORD_H
+
+/// \ingroup shortest_path
+/// \file
+/// \brief Bellman-Ford algorithm.
+
+#include <lemon/list_graph.h>
+#include <lemon/bits/path_dump.h>
+#include <lemon/core.h>
+#include <lemon/error.h>
+#include <lemon/maps.h>
+#include <lemon/path.h>
+
+#include <limits>
+
+namespace lemon {
+
+ /// \brief Default OperationTraits for the BellmanFord algorithm class.
+ ///
+ /// This operation traits class defines all computational operations
+ /// and constants that are used in the Bellman-Ford algorithm.
+ /// The default implementation is based on the \c numeric_limits class.
+ /// If the numeric type does not have infinity value, then the maximum
+ /// value is used as extremal infinity value.
+ template <
+ typename V,
+ bool has_inf = std::numeric_limits<V>::has_infinity>
+ struct BellmanFordDefaultOperationTraits {
+ /// \e
+ typedef V Value;
+ /// \brief Gives back the zero value of the type.
+ static Value zero() {
+ return static_cast<Value>(0);
+ }
+ /// \brief Gives back the positive infinity value of the type.
+ static Value infinity() {
+ return std::numeric_limits<Value>::infinity();
+ }
+ /// \brief Gives back the sum of the given two elements.
+ static Value plus(const Value& left, const Value& right) {
+ return left + right;
+ }
+ /// \brief Gives back \c true only if the first value is less than
+ /// the second.
+ static bool less(const Value& left, const Value& right) {
+ return left < right;
+ }
+ };
+
+ template <typename V>
+ struct BellmanFordDefaultOperationTraits<V, false> {
+ typedef V Value;
+ static Value zero() {
+ return static_cast<Value>(0);
+ }
+ static Value infinity() {
+ return std::numeric_limits<Value>::max();
+ }
+ static Value plus(const Value& left, const Value& right) {
+ if (left == infinity() || right == infinity()) return infinity();
+ return left + right;
+ }
+ static bool less(const Value& left, const Value& right) {
+ return left < right;
+ }
+ };
+
+ /// \brief Default traits class of BellmanFord class.
+ ///
+ /// Default traits class of BellmanFord class.
+ /// \param GR The type of the digraph.
+ /// \param LEN The type of the length map.
+ template<typename GR, typename LEN>
+ struct BellmanFordDefaultTraits {
+ /// The type of the digraph the algorithm runs on.
+ typedef GR Digraph;
+
+ /// \brief The type of the map that stores the arc lengths.
+ ///
+ /// The type of the map that stores the arc lengths.
+ /// It must conform to the \ref concepts::ReadMap "ReadMap" concept.
+ typedef LEN LengthMap;
+
+ /// The type of the arc lengths.
+ typedef typename LEN::Value Value;
+
+ /// \brief Operation traits for Bellman-Ford algorithm.
+ ///
+ /// It defines the used operations and the infinity value for the
+ /// given \c Value type.
+ /// \see BellmanFordDefaultOperationTraits
+ typedef BellmanFordDefaultOperationTraits<Value> OperationTraits;
+
+ /// \brief The type of the map that stores the last arcs of the
+ /// shortest paths.
+ ///
+ /// The type of the map that stores the last
+ /// arcs of the shortest paths.
+ /// It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ typedef typename GR::template NodeMap<typename GR::Arc> PredMap;
+
+ /// \brief Instantiates a \c PredMap.
+ ///
+ /// This function instantiates a \ref PredMap.
+ /// \param g is the digraph to which we would like to define the
+ /// \ref PredMap.
+ static PredMap *createPredMap(const GR& g) {
+ return new PredMap(g);
+ }
+
+ /// \brief The type of the map that stores the distances of the nodes.
+ ///
+ /// The type of the map that stores the distances of the nodes.
+ /// It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ typedef typename GR::template NodeMap<typename LEN::Value> DistMap;
+
+ /// \brief Instantiates a \c DistMap.
+ ///
+ /// This function instantiates a \ref DistMap.
+ /// \param g is the digraph to which we would like to define the
+ /// \ref DistMap.
+ static DistMap *createDistMap(const GR& g) {
+ return new DistMap(g);
+ }
+
+ };
+
+ /// \brief %BellmanFord algorithm class.
+ ///
+ /// \ingroup shortest_path
+ /// This class provides an efficient implementation of the Bellman-Ford
+ /// algorithm. The maximum time complexity of the algorithm is
+ /// <tt>O(nm)</tt>.
+ ///
+ /// The Bellman-Ford algorithm solves the single-source shortest path
+ /// problem when the arcs can have negative lengths, but the digraph
+ /// should not contain directed cycles with negative total length.
+ /// If all arc costs are non-negative, consider to use the Dijkstra
+ /// algorithm instead, since it is more efficient.
+ ///
+ /// The arc lengths are passed to the algorithm using a
+ /// \ref concepts::ReadMap "ReadMap", so it is easy to change it to any
+ /// kind of length. The type of the length values is determined by the
+ /// \ref concepts::ReadMap::Value "Value" type of the length map.
+ ///
+ /// There is also a \ref bellmanFord() "function-type interface" for the
+ /// Bellman-Ford algorithm, which is convenient in the simplier cases and
+ /// it can be used easier.
+ ///
+ /// \tparam GR The type of the digraph the algorithm runs on.
+ /// The default type is \ref ListDigraph.
+ /// \tparam LEN A \ref concepts::ReadMap "readable" arc map that specifies
+ /// the lengths of the arcs. The default map type is
+ /// \ref concepts::Digraph::ArcMap "GR::ArcMap<int>".
+ /// \tparam TR The traits class that defines various types used by the
+ /// algorithm. By default, it is \ref BellmanFordDefaultTraits
+ /// "BellmanFordDefaultTraits<GR, LEN>".
+ /// In most cases, this parameter should not be set directly,
+ /// consider to use the named template parameters instead.
+#ifdef DOXYGEN
+ template <typename GR, typename LEN, typename TR>
+#else
+ template <typename GR=ListDigraph,
+ typename LEN=typename GR::template ArcMap<int>,
+ typename TR=BellmanFordDefaultTraits<GR,LEN> >
+#endif
+ class BellmanFord {
+ public:
+
+ ///The type of the underlying digraph.
+ typedef typename TR::Digraph Digraph;
+
+ /// \brief The type of the arc lengths.
+ typedef typename TR::LengthMap::Value Value;
+ /// \brief The type of the map that stores the arc lengths.
+ typedef typename TR::LengthMap LengthMap;
+ /// \brief The type of the map that stores the last
+ /// arcs of the shortest paths.
+ typedef typename TR::PredMap PredMap;
+ /// \brief The type of the map that stores the distances of the nodes.
+ typedef typename TR::DistMap DistMap;
+ /// The type of the paths.
+ typedef PredMapPath<Digraph, PredMap> Path;
+ ///\brief The \ref lemon::BellmanFordDefaultOperationTraits
+ /// "operation traits class" of the algorithm.
+ typedef typename TR::OperationTraits OperationTraits;
+
+ ///\brief The \ref lemon::BellmanFordDefaultTraits "traits class"
+ ///of the algorithm.
+ typedef TR Traits;
+
+ private:
+
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::NodeIt NodeIt;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::OutArcIt OutArcIt;
+
+ // Pointer to the underlying digraph.
+ const Digraph *_gr;
+ // Pointer to the length map
+ const LengthMap *_length;
+ // Pointer to the map of predecessors arcs.
+ PredMap *_pred;
+ // Indicates if _pred is locally allocated (true) or not.
+ bool _local_pred;
+ // Pointer to the map of distances.
+ DistMap *_dist;
+ // Indicates if _dist is locally allocated (true) or not.
+ bool _local_dist;
+
+ typedef typename Digraph::template NodeMap<bool> MaskMap;
+ MaskMap *_mask;
+
+ std::vector<Node> _process;
+
+ // Creates the maps if necessary.
+ void create_maps() {
+ if(!_pred) {
+ _local_pred = true;
+ _pred = Traits::createPredMap(*_gr);
+ }
+ if(!_dist) {
+ _local_dist = true;
+ _dist = Traits::createDistMap(*_gr);
+ }
+ if(!_mask) {
+ _mask = new MaskMap(*_gr);
+ }
+ }
+
+ public :
+
+ typedef BellmanFord Create;
+
+ /// \name Named Template Parameters
+
+ ///@{
+
+ template <class T>
+ struct SetPredMapTraits : public Traits {
+ typedef T PredMap;
+ static PredMap *createPredMap(const Digraph&) {
+ LEMON_ASSERT(false, "PredMap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// \c PredMap type.
+ ///
+ /// \ref named-templ-param "Named parameter" for setting
+ /// \c PredMap type.
+ /// It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ template <class T>
+ struct SetPredMap
+ : public BellmanFord< Digraph, LengthMap, SetPredMapTraits<T> > {
+ typedef BellmanFord< Digraph, LengthMap, SetPredMapTraits<T> > Create;
+ };
+
+ template <class T>
+ struct SetDistMapTraits : public Traits {
+ typedef T DistMap;
+ static DistMap *createDistMap(const Digraph&) {
+ LEMON_ASSERT(false, "DistMap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// \c DistMap type.
+ ///
+ /// \ref named-templ-param "Named parameter" for setting
+ /// \c DistMap type.
+ /// It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ template <class T>
+ struct SetDistMap
+ : public BellmanFord< Digraph, LengthMap, SetDistMapTraits<T> > {
+ typedef BellmanFord< Digraph, LengthMap, SetDistMapTraits<T> > Create;
+ };
+
+ template <class T>
+ struct SetOperationTraitsTraits : public Traits {
+ typedef T OperationTraits;
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// \c OperationTraits type.
+ ///
+ /// \ref named-templ-param "Named parameter" for setting
+ /// \c OperationTraits type.
+ /// For more information, see \ref BellmanFordDefaultOperationTraits.
+ template <class T>
+ struct SetOperationTraits
+ : public BellmanFord< Digraph, LengthMap, SetOperationTraitsTraits<T> > {
+ typedef BellmanFord< Digraph, LengthMap, SetOperationTraitsTraits<T> >
+ Create;
+ };
+
+ ///@}
+
+ protected:
+
+ BellmanFord() {}
+
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ /// \param g The digraph the algorithm runs on.
+ /// \param length The length map used by the algorithm.
+ BellmanFord(const Digraph& g, const LengthMap& length) :
+ _gr(&g), _length(&length),
+ _pred(0), _local_pred(false),
+ _dist(0), _local_dist(false), _mask(0) {}
+
+ ///Destructor.
+ ~BellmanFord() {
+ if(_local_pred) delete _pred;
+ if(_local_dist) delete _dist;
+ if(_mask) delete _mask;
+ }
+
+ /// \brief Sets the length map.
+ ///
+ /// Sets the length map.
+ /// \return <tt>(*this)</tt>
+ BellmanFord &lengthMap(const LengthMap &map) {
+ _length = &map;
+ return *this;
+ }
+
+ /// \brief Sets the map that stores the predecessor arcs.
+ ///
+ /// Sets the map that stores the predecessor arcs.
+ /// If you don't use this function before calling \ref run()
+ /// or \ref init(), an instance will be allocated automatically.
+ /// The destructor deallocates this automatically allocated map,
+ /// of course.
+ /// \return <tt>(*this)</tt>
+ BellmanFord &predMap(PredMap &map) {
+ if(_local_pred) {
+ delete _pred;
+ _local_pred=false;
+ }
+ _pred = &map;
+ return *this;
+ }
+
+ /// \brief Sets the map that stores the distances of the nodes.
+ ///
+ /// Sets the map that stores the distances of the nodes calculated
+ /// by the algorithm.
+ /// If you don't use this function before calling \ref run()
+ /// or \ref init(), an instance will be allocated automatically.
+ /// The destructor deallocates this automatically allocated map,
+ /// of course.
+ /// \return <tt>(*this)</tt>
+ BellmanFord &distMap(DistMap &map) {
+ if(_local_dist) {
+ delete _dist;
+ _local_dist=false;
+ }
+ _dist = &map;
+ return *this;
+ }
+
+ /// \name Execution Control
+ /// The simplest way to execute the Bellman-Ford algorithm is to use
+ /// one of the member functions called \ref run().\n
+ /// If you need better control on the execution, you have to call
+ /// \ref init() first, then you can add several source nodes
+ /// with \ref addSource(). Finally the actual path computation can be
+ /// performed with \ref start(), \ref checkedStart() or
+ /// \ref limitedStart().
+
+ ///@{
+
+ /// \brief Initializes the internal data structures.
+ ///
+ /// Initializes the internal data structures. The optional parameter
+ /// is the initial distance of each node.
+ void init(const Value value = OperationTraits::infinity()) {
+ create_maps();
+ for (NodeIt it(*_gr); it != INVALID; ++it) {
+ _pred->set(it, INVALID);
+ _dist->set(it, value);
+ }
+ _process.clear();
+ if (OperationTraits::less(value, OperationTraits::infinity())) {
+ for (NodeIt it(*_gr); it != INVALID; ++it) {
+ _process.push_back(it);
+ _mask->set(it, true);
+ }
+ } else {
+ for (NodeIt it(*_gr); it != INVALID; ++it) {
+ _mask->set(it, false);
+ }
+ }
+ }
+
+ /// \brief Adds a new source node.
+ ///
+ /// This function adds a new source node. The optional second parameter
+ /// is the initial distance of the node.
+ void addSource(Node source, Value dst = OperationTraits::zero()) {
+ _dist->set(source, dst);
+ if (!(*_mask)[source]) {
+ _process.push_back(source);
+ _mask->set(source, true);
+ }
+ }
+
+ /// \brief Executes one round from the Bellman-Ford algorithm.
+ ///
+ /// If the algoritm calculated the distances in the previous round
+ /// exactly for the paths of at most \c k arcs, then this function
+ /// will calculate the distances exactly for the paths of at most
+ /// <tt>k+1</tt> arcs. Performing \c k iterations using this function
+ /// calculates the shortest path distances exactly for the paths
+ /// consisting of at most \c k arcs.
+ ///
+ /// \warning The paths with limited arc number cannot be retrieved
+ /// easily with \ref path() or \ref predArc() functions. If you also
+ /// need the shortest paths and not only the distances, you should
+ /// store the \ref predMap() "predecessor map" after each iteration
+ /// and build the path manually.
+ ///
+ /// \return \c true when the algorithm have not found more shorter
+ /// paths.
+ ///
+ /// \see ActiveIt
+ bool processNextRound() {
+ for (int i = 0; i < int(_process.size()); ++i) {
+ _mask->set(_process[i], false);
+ }
+ std::vector<Node> nextProcess;
+ std::vector<Value> values(_process.size());
+ for (int i = 0; i < int(_process.size()); ++i) {
+ values[i] = (*_dist)[_process[i]];
+ }
+ for (int i = 0; i < int(_process.size()); ++i) {
+ for (OutArcIt it(*_gr, _process[i]); it != INVALID; ++it) {
+ Node target = _gr->target(it);
+ Value relaxed = OperationTraits::plus(values[i], (*_length)[it]);
+ if (OperationTraits::less(relaxed, (*_dist)[target])) {
+ _pred->set(target, it);
+ _dist->set(target, relaxed);
+ if (!(*_mask)[target]) {
+ _mask->set(target, true);
+ nextProcess.push_back(target);
+ }
+ }
+ }
+ }
+ _process.swap(nextProcess);
+ return _process.empty();
+ }
+
+ /// \brief Executes one weak round from the Bellman-Ford algorithm.
+ ///
+ /// If the algorithm calculated the distances in the previous round
+ /// at least for the paths of at most \c k arcs, then this function
+ /// will calculate the distances at least for the paths of at most
+ /// <tt>k+1</tt> arcs.
+ /// This function does not make it possible to calculate the shortest
+ /// path distances exactly for paths consisting of at most \c k arcs,
+ /// this is why it is called weak round.
+ ///
+ /// \return \c true when the algorithm have not found more shorter
+ /// paths.
+ ///
+ /// \see ActiveIt
+ bool processNextWeakRound() {
+ for (int i = 0; i < int(_process.size()); ++i) {
+ _mask->set(_process[i], false);
+ }
+ std::vector<Node> nextProcess;
+ for (int i = 0; i < int(_process.size()); ++i) {
+ for (OutArcIt it(*_gr, _process[i]); it != INVALID; ++it) {
+ Node target = _gr->target(it);
+ Value relaxed =
+ OperationTraits::plus((*_dist)[_process[i]], (*_length)[it]);
+ if (OperationTraits::less(relaxed, (*_dist)[target])) {
+ _pred->set(target, it);
+ _dist->set(target, relaxed);
+ if (!(*_mask)[target]) {
+ _mask->set(target, true);
+ nextProcess.push_back(target);
+ }
+ }
+ }
+ }
+ _process.swap(nextProcess);
+ return _process.empty();
+ }
+
+ /// \brief Executes the algorithm.
+ ///
+ /// Executes the algorithm.
+ ///
+ /// This method runs the Bellman-Ford algorithm from the root node(s)
+ /// in order to compute the shortest path to each node.
+ ///
+ /// The algorithm computes
+ /// - the shortest path tree (forest),
+ /// - the distance of each node from the root(s).
+ ///
+ /// \pre init() must be called and at least one root node should be
+ /// added with addSource() before using this function.
+ void start() {
+ int num = countNodes(*_gr) - 1;
+ for (int i = 0; i < num; ++i) {
+ if (processNextWeakRound()) break;
+ }
+ }
+
+ /// \brief Executes the algorithm and checks the negative cycles.
+ ///
+ /// Executes the algorithm and checks the negative cycles.
+ ///
+ /// This method runs the Bellman-Ford algorithm from the root node(s)
+ /// in order to compute the shortest path to each node and also checks
+ /// if the digraph contains cycles with negative total length.
+ ///
+ /// The algorithm computes
+ /// - the shortest path tree (forest),
+ /// - the distance of each node from the root(s).
+ ///
+ /// \return \c false if there is a negative cycle in the digraph.
+ ///
+ /// \pre init() must be called and at least one root node should be
+ /// added with addSource() before using this function.
+ bool checkedStart() {
+ int num = countNodes(*_gr);
+ for (int i = 0; i < num; ++i) {
+ if (processNextWeakRound()) return true;
+ }
+ return _process.empty();
+ }
+
+ /// \brief Executes the algorithm with arc number limit.
+ ///
+ /// Executes the algorithm with arc number limit.
+ ///
+ /// This method runs the Bellman-Ford algorithm from the root node(s)
+ /// in order to compute the shortest path distance for each node
+ /// using only the paths consisting of at most \c num arcs.
+ ///
+ /// The algorithm computes
+ /// - the limited distance of each node from the root(s),
+ /// - the predecessor arc for each node.
+ ///
+ /// \warning The paths with limited arc number cannot be retrieved
+ /// easily with \ref path() or \ref predArc() functions. If you also
+ /// need the shortest paths and not only the distances, you should
+ /// store the \ref predMap() "predecessor map" after each iteration
+ /// and build the path manually.
+ ///
+ /// \pre init() must be called and at least one root node should be
+ /// added with addSource() before using this function.
+ void limitedStart(int num) {
+ for (int i = 0; i < num; ++i) {
+ if (processNextRound()) break;
+ }
+ }
+
+ /// \brief Runs the algorithm from the given root node.
+ ///
+ /// This method runs the Bellman-Ford algorithm from the given root
+ /// node \c s in order to compute the shortest path to each node.
+ ///
+ /// The algorithm computes
+ /// - the shortest path tree (forest),
+ /// - the distance of each node from the root(s).
+ ///
+ /// \note bf.run(s) is just a shortcut of the following code.
+ /// \code
+ /// bf.init();
+ /// bf.addSource(s);
+ /// bf.start();
+ /// \endcode
+ void run(Node s) {
+ init();
+ addSource(s);
+ start();
+ }
+
+ /// \brief Runs the algorithm from the given root node with arc
+ /// number limit.
+ ///
+ /// This method runs the Bellman-Ford algorithm from the given root
+ /// node \c s in order to compute the shortest path distance for each
+ /// node using only the paths consisting of at most \c num arcs.
+ ///
+ /// The algorithm computes
+ /// - the limited distance of each node from the root(s),
+ /// - the predecessor arc for each node.
+ ///
+ /// \warning The paths with limited arc number cannot be retrieved
+ /// easily with \ref path() or \ref predArc() functions. If you also
+ /// need the shortest paths and not only the distances, you should
+ /// store the \ref predMap() "predecessor map" after each iteration
+ /// and build the path manually.
+ ///
+ /// \note bf.run(s, num) is just a shortcut of the following code.
+ /// \code
+ /// bf.init();
+ /// bf.addSource(s);
+ /// bf.limitedStart(num);
+ /// \endcode
+ void run(Node s, int num) {
+ init();
+ addSource(s);
+ limitedStart(num);
+ }
+
+ ///@}
+
+ /// \brief LEMON iterator for getting the active nodes.
+ ///
+ /// This class provides a common style LEMON iterator that traverses
+ /// the active nodes of the Bellman-Ford algorithm after the last
+ /// phase. These nodes should be checked in the next phase to
+ /// find augmenting arcs outgoing from them.
+ class ActiveIt {
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// Constructor for getting the active nodes of the given BellmanFord
+ /// instance.
+ ActiveIt(const BellmanFord& algorithm) : _algorithm(&algorithm)
+ {
+ _index = _algorithm->_process.size() - 1;
+ }
+
+ /// \brief Invalid constructor.
+ ///
+ /// Invalid constructor.
+ ActiveIt(Invalid) : _algorithm(0), _index(-1) {}
+
+ /// \brief Conversion to \c Node.
+ ///
+ /// Conversion to \c Node.
+ operator Node() const {
+ return _index >= 0 ? _algorithm->_process[_index] : INVALID;
+ }
+
+ /// \brief Increment operator.
+ ///
+ /// Increment operator.
+ ActiveIt& operator++() {
+ --_index;
+ return *this;
+ }
+
+ bool operator==(const ActiveIt& it) const {
+ return static_cast<Node>(*this) == static_cast<Node>(it);
+ }
+ bool operator!=(const ActiveIt& it) const {
+ return static_cast<Node>(*this) != static_cast<Node>(it);
+ }
+ bool operator<(const ActiveIt& it) const {
+ return static_cast<Node>(*this) < static_cast<Node>(it);
+ }
+
+ private:
+ const BellmanFord* _algorithm;
+ int _index;
+ };
+
+ /// \name Query Functions
+ /// The result of the Bellman-Ford algorithm can be obtained using these
+ /// functions.\n
+ /// Either \ref run() or \ref init() should be called before using them.
+
+ ///@{
+
+ /// \brief The shortest path to the given node.
+ ///
+ /// Gives back the shortest path to the given node from the root(s).
+ ///
+ /// \warning \c t should be reached from the root(s).
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ Path path(Node t) const
+ {
+ return Path(*_gr, *_pred, t);
+ }
+
+ /// \brief The distance of the given node from the root(s).
+ ///
+ /// Returns the distance of the given node from the root(s).
+ ///
+ /// \warning If node \c v is not reached from the root(s), then
+ /// the return value of this function is undefined.
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ Value dist(Node v) const { return (*_dist)[v]; }
+
+ /// \brief Returns the 'previous arc' of the shortest path tree for
+ /// the given node.
+ ///
+ /// This function returns the 'previous arc' of the shortest path
+ /// tree for node \c v, i.e. it returns the last arc of a
+ /// shortest path from a root to \c v. It is \c INVALID if \c v
+ /// is not reached from the root(s) or if \c v is a root.
+ ///
+ /// The shortest path tree used here is equal to the shortest path
+ /// tree used in \ref predNode() and \ref predMap().
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ Arc predArc(Node v) const { return (*_pred)[v]; }
+
+ /// \brief Returns the 'previous node' of the shortest path tree for
+ /// the given node.
+ ///
+ /// This function returns the 'previous node' of the shortest path
+ /// tree for node \c v, i.e. it returns the last but one node of
+ /// a shortest path from a root to \c v. It is \c INVALID if \c v
+ /// is not reached from the root(s) or if \c v is a root.
+ ///
+ /// The shortest path tree used here is equal to the shortest path
+ /// tree used in \ref predArc() and \ref predMap().
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ Node predNode(Node v) const {
+ return (*_pred)[v] == INVALID ? INVALID : _gr->source((*_pred)[v]);
+ }
+
+ /// \brief Returns a const reference to the node map that stores the
+ /// distances of the nodes.
+ ///
+ /// Returns a const reference to the node map that stores the distances
+ /// of the nodes calculated by the algorithm.
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ const DistMap &distMap() const { return *_dist;}
+
+ /// \brief Returns a const reference to the node map that stores the
+ /// predecessor arcs.
+ ///
+ /// Returns a const reference to the node map that stores the predecessor
+ /// arcs, which form the shortest path tree (forest).
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ const PredMap &predMap() const { return *_pred; }
+
+ /// \brief Checks if a node is reached from the root(s).
+ ///
+ /// Returns \c true if \c v is reached from the root(s).
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ bool reached(Node v) const {
+ return (*_dist)[v] != OperationTraits::infinity();
+ }
+
+ /// \brief Gives back a negative cycle.
+ ///
+ /// This function gives back a directed cycle with negative total
+ /// length if the algorithm has already found one.
+ /// Otherwise it gives back an empty path.
+ lemon::Path<Digraph> negativeCycle() const {
+ typename Digraph::template NodeMap<int> state(*_gr, -1);
+ lemon::Path<Digraph> cycle;
+ for (int i = 0; i < int(_process.size()); ++i) {
+ if (state[_process[i]] != -1) continue;
+ for (Node v = _process[i]; (*_pred)[v] != INVALID;
+ v = _gr->source((*_pred)[v])) {
+ if (state[v] == i) {
+ cycle.addFront((*_pred)[v]);
+ for (Node u = _gr->source((*_pred)[v]); u != v;
+ u = _gr->source((*_pred)[u])) {
+ cycle.addFront((*_pred)[u]);
+ }
+ return cycle;
+ }
+ else if (state[v] >= 0) {
+ break;
+ }
+ state[v] = i;
+ }
+ }
+ return cycle;
+ }
+
+ ///@}
+ };
+
+ /// \brief Default traits class of bellmanFord() function.
+ ///
+ /// Default traits class of bellmanFord() function.
+ /// \tparam GR The type of the digraph.
+ /// \tparam LEN The type of the length map.
+ template <typename GR, typename LEN>
+ struct BellmanFordWizardDefaultTraits {
+ /// The type of the digraph the algorithm runs on.
+ typedef GR Digraph;
+
+ /// \brief The type of the map that stores the arc lengths.
+ ///
+ /// The type of the map that stores the arc lengths.
+ /// It must meet the \ref concepts::ReadMap "ReadMap" concept.
+ typedef LEN LengthMap;
+
+ /// The type of the arc lengths.
+ typedef typename LEN::Value Value;
+
+ /// \brief Operation traits for Bellman-Ford algorithm.
+ ///
+ /// It defines the used operations and the infinity value for the
+ /// given \c Value type.
+ /// \see BellmanFordDefaultOperationTraits
+ typedef BellmanFordDefaultOperationTraits<Value> OperationTraits;
+
+ /// \brief The type of the map that stores the last
+ /// arcs of the shortest paths.
+ ///
+ /// The type of the map that stores the last arcs of the shortest paths.
+ /// It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ typedef typename GR::template NodeMap<typename GR::Arc> PredMap;
+
+ /// \brief Instantiates a \c PredMap.
+ ///
+ /// This function instantiates a \ref PredMap.
+ /// \param g is the digraph to which we would like to define the
+ /// \ref PredMap.
+ static PredMap *createPredMap(const GR &g) {
+ return new PredMap(g);
+ }
+
+ /// \brief The type of the map that stores the distances of the nodes.
+ ///
+ /// The type of the map that stores the distances of the nodes.
+ /// It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ typedef typename GR::template NodeMap<Value> DistMap;
+
+ /// \brief Instantiates a \c DistMap.
+ ///
+ /// This function instantiates a \ref DistMap.
+ /// \param g is the digraph to which we would like to define the
+ /// \ref DistMap.
+ static DistMap *createDistMap(const GR &g) {
+ return new DistMap(g);
+ }
+
+ ///The type of the shortest paths.
+
+ ///The type of the shortest paths.
+ ///It must meet the \ref concepts::Path "Path" concept.
+ typedef lemon::Path<Digraph> Path;
+ };
+
+ /// \brief Default traits class used by BellmanFordWizard.
+ ///
+ /// Default traits class used by BellmanFordWizard.
+ /// \tparam GR The type of the digraph.
+ /// \tparam LEN The type of the length map.
+ template <typename GR, typename LEN>
+ class BellmanFordWizardBase
+ : public BellmanFordWizardDefaultTraits<GR, LEN> {
+
+ typedef BellmanFordWizardDefaultTraits<GR, LEN> Base;
+ protected:
+ // Type of the nodes in the digraph.
+ typedef typename Base::Digraph::Node Node;
+
+ // Pointer to the underlying digraph.
+ void *_graph;
+ // Pointer to the length map
+ void *_length;
+ // Pointer to the map of predecessors arcs.
+ void *_pred;
+ // Pointer to the map of distances.
+ void *_dist;
+ //Pointer to the shortest path to the target node.
+ void *_path;
+ //Pointer to the distance of the target node.
+ void *_di;
+
+ public:
+ /// Constructor.
+
+ /// This constructor does not require parameters, it initiates
+ /// all of the attributes to default values \c 0.
+ BellmanFordWizardBase() :
+ _graph(0), _length(0), _pred(0), _dist(0), _path(0), _di(0) {}
+
+ /// Constructor.
+
+ /// This constructor requires two parameters,
+ /// others are initiated to \c 0.
+ /// \param gr The digraph the algorithm runs on.
+ /// \param len The length map.
+ BellmanFordWizardBase(const GR& gr,
+ const LEN& len) :
+ _graph(reinterpret_cast<void*>(const_cast<GR*>(&gr))),
+ _length(reinterpret_cast<void*>(const_cast<LEN*>(&len))),
+ _pred(0), _dist(0), _path(0), _di(0) {}
+
+ };
+
+ /// \brief Auxiliary class for the function-type interface of the
+ /// \ref BellmanFord "Bellman-Ford" algorithm.
+ ///
+ /// This auxiliary class is created to implement the
+ /// \ref bellmanFord() "function-type interface" of the
+ /// \ref BellmanFord "Bellman-Ford" algorithm.
+ /// It does not have own \ref run() method, it uses the
+ /// functions and features of the plain \ref BellmanFord.
+ ///
+ /// This class should only be used through the \ref bellmanFord()
+ /// function, which makes it easier to use the algorithm.
+ ///
+ /// \tparam TR The traits class that defines various types used by the
+ /// algorithm.
+ template<class TR>
+ class BellmanFordWizard : public TR {
+ typedef TR Base;
+
+ typedef typename TR::Digraph Digraph;
+
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::NodeIt NodeIt;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::OutArcIt ArcIt;
+
+ typedef typename TR::LengthMap LengthMap;
+ typedef typename LengthMap::Value Value;
+ typedef typename TR::PredMap PredMap;
+ typedef typename TR::DistMap DistMap;
+ typedef typename TR::Path Path;
+
+ public:
+ /// Constructor.
+ BellmanFordWizard() : TR() {}
+
+ /// \brief Constructor that requires parameters.
+ ///
+ /// Constructor that requires parameters.
+ /// These parameters will be the default values for the traits class.
+ /// \param gr The digraph the algorithm runs on.
+ /// \param len The length map.
+ BellmanFordWizard(const Digraph& gr, const LengthMap& len)
+ : TR(gr, len) {}
+
+ /// \brief Copy constructor
+ BellmanFordWizard(const TR &b) : TR(b) {}
+
+ ~BellmanFordWizard() {}
+
+ /// \brief Runs the Bellman-Ford algorithm from the given source node.
+ ///
+ /// This method runs the Bellman-Ford algorithm from the given source
+ /// node in order to compute the shortest path to each node.
+ void run(Node s) {
+ BellmanFord<Digraph,LengthMap,TR>
+ bf(*reinterpret_cast<const Digraph*>(Base::_graph),
+ *reinterpret_cast<const LengthMap*>(Base::_length));
+ if (Base::_pred) bf.predMap(*reinterpret_cast<PredMap*>(Base::_pred));
+ if (Base::_dist) bf.distMap(*reinterpret_cast<DistMap*>(Base::_dist));
+ bf.run(s);
+ }
+
+ /// \brief Runs the Bellman-Ford algorithm to find the shortest path
+ /// between \c s and \c t.
+ ///
+ /// This method runs the Bellman-Ford algorithm from node \c s
+ /// in order to compute the shortest path to node \c t.
+ /// Actually, it computes the shortest path to each node, but using
+ /// this function you can retrieve the distance and the shortest path
+ /// for a single target node easier.
+ ///
+ /// \return \c true if \c t is reachable form \c s.
+ bool run(Node s, Node t) {
+ BellmanFord<Digraph,LengthMap,TR>
+ bf(*reinterpret_cast<const Digraph*>(Base::_graph),
+ *reinterpret_cast<const LengthMap*>(Base::_length));
+ if (Base::_pred) bf.predMap(*reinterpret_cast<PredMap*>(Base::_pred));
+ if (Base::_dist) bf.distMap(*reinterpret_cast<DistMap*>(Base::_dist));
+ bf.run(s);
+ if (Base::_path) *reinterpret_cast<Path*>(Base::_path) = bf.path(t);
+ if (Base::_di) *reinterpret_cast<Value*>(Base::_di) = bf.dist(t);
+ return bf.reached(t);
+ }
+
+ template<class T>
+ struct SetPredMapBase : public Base {
+ typedef T PredMap;
+ static PredMap *createPredMap(const Digraph &) { return 0; };
+ SetPredMapBase(const TR &b) : TR(b) {}
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// the predecessor map.
+ ///
+ /// \ref named-templ-param "Named parameter" for setting
+ /// the map that stores the predecessor arcs of the nodes.
+ template<class T>
+ BellmanFordWizard<SetPredMapBase<T> > predMap(const T &t) {
+ Base::_pred=reinterpret_cast<void*>(const_cast<T*>(&t));
+ return BellmanFordWizard<SetPredMapBase<T> >(*this);
+ }
+
+ template<class T>
+ struct SetDistMapBase : public Base {
+ typedef T DistMap;
+ static DistMap *createDistMap(const Digraph &) { return 0; };
+ SetDistMapBase(const TR &b) : TR(b) {}
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// the distance map.
+ ///
+ /// \ref named-templ-param "Named parameter" for setting
+ /// the map that stores the distances of the nodes calculated
+ /// by the algorithm.
+ template<class T>
+ BellmanFordWizard<SetDistMapBase<T> > distMap(const T &t) {
+ Base::_dist=reinterpret_cast<void*>(const_cast<T*>(&t));
+ return BellmanFordWizard<SetDistMapBase<T> >(*this);
+ }
+
+ template<class T>
+ struct SetPathBase : public Base {
+ typedef T Path;
+ SetPathBase(const TR &b) : TR(b) {}
+ };
+
+ /// \brief \ref named-func-param "Named parameter" for getting
+ /// the shortest path to the target node.
+ ///
+ /// \ref named-func-param "Named parameter" for getting
+ /// the shortest path to the target node.
+ template<class T>
+ BellmanFordWizard<SetPathBase<T> > path(const T &t)
+ {
+ Base::_path=reinterpret_cast<void*>(const_cast<T*>(&t));
+ return BellmanFordWizard<SetPathBase<T> >(*this);
+ }
+
+ /// \brief \ref named-func-param "Named parameter" for getting
+ /// the distance of the target node.
+ ///
+ /// \ref named-func-param "Named parameter" for getting
+ /// the distance of the target node.
+ BellmanFordWizard dist(const Value &d)
+ {
+ Base::_di=reinterpret_cast<void*>(const_cast<Value*>(&d));
+ return *this;
+ }
+
+ };
+
+ /// \brief Function type interface for the \ref BellmanFord "Bellman-Ford"
+ /// algorithm.
+ ///
+ /// \ingroup shortest_path
+ /// Function type interface for the \ref BellmanFord "Bellman-Ford"
+ /// algorithm.
+ ///
+ /// This function also has several \ref named-templ-func-param
+ /// "named parameters", they are declared as the members of class
+ /// \ref BellmanFordWizard.
+ /// The following examples show how to use these parameters.
+ /// \code
+ /// // Compute shortest path from node s to each node
+ /// bellmanFord(g,length).predMap(preds).distMap(dists).run(s);
+ ///
+ /// // Compute shortest path from s to t
+ /// bool reached = bellmanFord(g,length).path(p).dist(d).run(s,t);
+ /// \endcode
+ /// \warning Don't forget to put the \ref BellmanFordWizard::run() "run()"
+ /// to the end of the parameter list.
+ /// \sa BellmanFordWizard
+ /// \sa BellmanFord
+ template<typename GR, typename LEN>
+ BellmanFordWizard<BellmanFordWizardBase<GR,LEN> >
+ bellmanFord(const GR& digraph,
+ const LEN& length)
+ {
+ return BellmanFordWizard<BellmanFordWizardBase<GR,LEN> >(digraph, length);
+ }
+
+} //END OF NAMESPACE LEMON
+
+#endif
+
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bfs.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bfs.h
new file mode 100644
index 00000000000..e5f4e5c5a31
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bfs.h
@@ -0,0 +1,1754 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_BFS_H
+#define LEMON_BFS_H
+
+///\ingroup search
+///\file
+///\brief BFS algorithm.
+
+#include <lemon/list_graph.h>
+#include <lemon/bits/path_dump.h>
+#include <lemon/core.h>
+#include <lemon/error.h>
+#include <lemon/maps.h>
+#include <lemon/path.h>
+
+namespace lemon {
+
+ ///Default traits class of Bfs class.
+
+ ///Default traits class of Bfs class.
+ ///\tparam GR Digraph type.
+ template<class GR>
+ struct BfsDefaultTraits
+ {
+ ///The type of the digraph the algorithm runs on.
+ typedef GR Digraph;
+
+ ///\brief The type of the map that stores the predecessor
+ ///arcs of the shortest paths.
+ ///
+ ///The type of the map that stores the predecessor
+ ///arcs of the shortest paths.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ typedef typename Digraph::template NodeMap<typename Digraph::Arc> PredMap;
+ ///Instantiates a \c PredMap.
+
+ ///This function instantiates a \ref PredMap.
+ ///\param g is the digraph, to which we would like to define the
+ ///\ref PredMap.
+ static PredMap *createPredMap(const Digraph &g)
+ {
+ return new PredMap(g);
+ }
+
+ ///The type of the map that indicates which nodes are processed.
+
+ ///The type of the map that indicates which nodes are processed.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ ///By default, it is a NullMap.
+ typedef NullMap<typename Digraph::Node,bool> ProcessedMap;
+ ///Instantiates a \c ProcessedMap.
+
+ ///This function instantiates a \ref ProcessedMap.
+ ///\param g is the digraph, to which
+ ///we would like to define the \ref ProcessedMap
+#ifdef DOXYGEN
+ static ProcessedMap *createProcessedMap(const Digraph &g)
+#else
+ static ProcessedMap *createProcessedMap(const Digraph &)
+#endif
+ {
+ return new ProcessedMap();
+ }
+
+ ///The type of the map that indicates which nodes are reached.
+
+ ///The type of the map that indicates which nodes are reached.
+ ///It must conform to
+ ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept.
+ typedef typename Digraph::template NodeMap<bool> ReachedMap;
+ ///Instantiates a \c ReachedMap.
+
+ ///This function instantiates a \ref ReachedMap.
+ ///\param g is the digraph, to which
+ ///we would like to define the \ref ReachedMap.
+ static ReachedMap *createReachedMap(const Digraph &g)
+ {
+ return new ReachedMap(g);
+ }
+
+ ///The type of the map that stores the distances of the nodes.
+
+ ///The type of the map that stores the distances of the nodes.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ typedef typename Digraph::template NodeMap<int> DistMap;
+ ///Instantiates a \c DistMap.
+
+ ///This function instantiates a \ref DistMap.
+ ///\param g is the digraph, to which we would like to define the
+ ///\ref DistMap.
+ static DistMap *createDistMap(const Digraph &g)
+ {
+ return new DistMap(g);
+ }
+ };
+
+ ///%BFS algorithm class.
+
+ ///\ingroup search
+ ///This class provides an efficient implementation of the %BFS algorithm.
+ ///
+ ///There is also a \ref bfs() "function-type interface" for the BFS
+ ///algorithm, which is convenient in the simplier cases and it can be
+ ///used easier.
+ ///
+ ///\tparam GR The type of the digraph the algorithm runs on.
+ ///The default type is \ref ListDigraph.
+ ///\tparam TR The traits class that defines various types used by the
+ ///algorithm. By default, it is \ref BfsDefaultTraits
+ ///"BfsDefaultTraits<GR>".
+ ///In most cases, this parameter should not be set directly,
+ ///consider to use the named template parameters instead.
+#ifdef DOXYGEN
+ template <typename GR,
+ typename TR>
+#else
+ template <typename GR=ListDigraph,
+ typename TR=BfsDefaultTraits<GR> >
+#endif
+ class Bfs {
+ public:
+
+ ///The type of the digraph the algorithm runs on.
+ typedef typename TR::Digraph Digraph;
+
+ ///\brief The type of the map that stores the predecessor arcs of the
+ ///shortest paths.
+ typedef typename TR::PredMap PredMap;
+ ///The type of the map that stores the distances of the nodes.
+ typedef typename TR::DistMap DistMap;
+ ///The type of the map that indicates which nodes are reached.
+ typedef typename TR::ReachedMap ReachedMap;
+ ///The type of the map that indicates which nodes are processed.
+ typedef typename TR::ProcessedMap ProcessedMap;
+ ///The type of the paths.
+ typedef PredMapPath<Digraph, PredMap> Path;
+
+ ///The \ref lemon::BfsDefaultTraits "traits class" of the algorithm.
+ typedef TR Traits;
+
+ private:
+
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::NodeIt NodeIt;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::OutArcIt OutArcIt;
+
+ //Pointer to the underlying digraph.
+ const Digraph *G;
+ //Pointer to the map of predecessor arcs.
+ PredMap *_pred;
+ //Indicates if _pred is locally allocated (true) or not.
+ bool local_pred;
+ //Pointer to the map of distances.
+ DistMap *_dist;
+ //Indicates if _dist is locally allocated (true) or not.
+ bool local_dist;
+ //Pointer to the map of reached status of the nodes.
+ ReachedMap *_reached;
+ //Indicates if _reached is locally allocated (true) or not.
+ bool local_reached;
+ //Pointer to the map of processed status of the nodes.
+ ProcessedMap *_processed;
+ //Indicates if _processed is locally allocated (true) or not.
+ bool local_processed;
+
+ std::vector<typename Digraph::Node> _queue;
+ int _queue_head,_queue_tail,_queue_next_dist;
+ int _curr_dist;
+
+ //Creates the maps if necessary.
+ void create_maps()
+ {
+ if(!_pred) {
+ local_pred = true;
+ _pred = Traits::createPredMap(*G);
+ }
+ if(!_dist) {
+ local_dist = true;
+ _dist = Traits::createDistMap(*G);
+ }
+ if(!_reached) {
+ local_reached = true;
+ _reached = Traits::createReachedMap(*G);
+ }
+ if(!_processed) {
+ local_processed = true;
+ _processed = Traits::createProcessedMap(*G);
+ }
+ }
+
+ protected:
+
+ Bfs() {}
+
+ public:
+
+ typedef Bfs Create;
+
+ ///\name Named Template Parameters
+
+ ///@{
+
+ template <class T>
+ struct SetPredMapTraits : public Traits {
+ typedef T PredMap;
+ static PredMap *createPredMap(const Digraph &)
+ {
+ LEMON_ASSERT(false, "PredMap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///\c PredMap type.
+ ///
+ ///\ref named-templ-param "Named parameter" for setting
+ ///\c PredMap type.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ template <class T>
+ struct SetPredMap : public Bfs< Digraph, SetPredMapTraits<T> > {
+ typedef Bfs< Digraph, SetPredMapTraits<T> > Create;
+ };
+
+ template <class T>
+ struct SetDistMapTraits : public Traits {
+ typedef T DistMap;
+ static DistMap *createDistMap(const Digraph &)
+ {
+ LEMON_ASSERT(false, "DistMap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///\c DistMap type.
+ ///
+ ///\ref named-templ-param "Named parameter" for setting
+ ///\c DistMap type.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ template <class T>
+ struct SetDistMap : public Bfs< Digraph, SetDistMapTraits<T> > {
+ typedef Bfs< Digraph, SetDistMapTraits<T> > Create;
+ };
+
+ template <class T>
+ struct SetReachedMapTraits : public Traits {
+ typedef T ReachedMap;
+ static ReachedMap *createReachedMap(const Digraph &)
+ {
+ LEMON_ASSERT(false, "ReachedMap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///\c ReachedMap type.
+ ///
+ ///\ref named-templ-param "Named parameter" for setting
+ ///\c ReachedMap type.
+ ///It must conform to
+ ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept.
+ template <class T>
+ struct SetReachedMap : public Bfs< Digraph, SetReachedMapTraits<T> > {
+ typedef Bfs< Digraph, SetReachedMapTraits<T> > Create;
+ };
+
+ template <class T>
+ struct SetProcessedMapTraits : public Traits {
+ typedef T ProcessedMap;
+ static ProcessedMap *createProcessedMap(const Digraph &)
+ {
+ LEMON_ASSERT(false, "ProcessedMap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///\c ProcessedMap type.
+ ///
+ ///\ref named-templ-param "Named parameter" for setting
+ ///\c ProcessedMap type.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ template <class T>
+ struct SetProcessedMap : public Bfs< Digraph, SetProcessedMapTraits<T> > {
+ typedef Bfs< Digraph, SetProcessedMapTraits<T> > Create;
+ };
+
+ struct SetStandardProcessedMapTraits : public Traits {
+ typedef typename Digraph::template NodeMap<bool> ProcessedMap;
+ static ProcessedMap *createProcessedMap(const Digraph &g)
+ {
+ return new ProcessedMap(g);
+ return 0; // ignore warnings
+ }
+ };
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///\c ProcessedMap type to be <tt>Digraph::NodeMap<bool></tt>.
+ ///
+ ///\ref named-templ-param "Named parameter" for setting
+ ///\c ProcessedMap type to be <tt>Digraph::NodeMap<bool></tt>.
+ ///If you don't set it explicitly, it will be automatically allocated.
+ struct SetStandardProcessedMap :
+ public Bfs< Digraph, SetStandardProcessedMapTraits > {
+ typedef Bfs< Digraph, SetStandardProcessedMapTraits > Create;
+ };
+
+ ///@}
+
+ public:
+
+ ///Constructor.
+
+ ///Constructor.
+ ///\param g The digraph the algorithm runs on.
+ Bfs(const Digraph &g) :
+ G(&g),
+ _pred(NULL), local_pred(false),
+ _dist(NULL), local_dist(false),
+ _reached(NULL), local_reached(false),
+ _processed(NULL), local_processed(false)
+ { }
+
+ ///Destructor.
+ ~Bfs()
+ {
+ if(local_pred) delete _pred;
+ if(local_dist) delete _dist;
+ if(local_reached) delete _reached;
+ if(local_processed) delete _processed;
+ }
+
+ ///Sets the map that stores the predecessor arcs.
+
+ ///Sets the map that stores the predecessor arcs.
+ ///If you don't use this function before calling \ref run(Node) "run()"
+ ///or \ref init(), an instance will be allocated automatically.
+ ///The destructor deallocates this automatically allocated map,
+ ///of course.
+ ///\return <tt> (*this) </tt>
+ Bfs &predMap(PredMap &m)
+ {
+ if(local_pred) {
+ delete _pred;
+ local_pred=false;
+ }
+ _pred = &m;
+ return *this;
+ }
+
+ ///Sets the map that indicates which nodes are reached.
+
+ ///Sets the map that indicates which nodes are reached.
+ ///If you don't use this function before calling \ref run(Node) "run()"
+ ///or \ref init(), an instance will be allocated automatically.
+ ///The destructor deallocates this automatically allocated map,
+ ///of course.
+ ///\return <tt> (*this) </tt>
+ Bfs &reachedMap(ReachedMap &m)
+ {
+ if(local_reached) {
+ delete _reached;
+ local_reached=false;
+ }
+ _reached = &m;
+ return *this;
+ }
+
+ ///Sets the map that indicates which nodes are processed.
+
+ ///Sets the map that indicates which nodes are processed.
+ ///If you don't use this function before calling \ref run(Node) "run()"
+ ///or \ref init(), an instance will be allocated automatically.
+ ///The destructor deallocates this automatically allocated map,
+ ///of course.
+ ///\return <tt> (*this) </tt>
+ Bfs &processedMap(ProcessedMap &m)
+ {
+ if(local_processed) {
+ delete _processed;
+ local_processed=false;
+ }
+ _processed = &m;
+ return *this;
+ }
+
+ ///Sets the map that stores the distances of the nodes.
+
+ ///Sets the map that stores the distances of the nodes calculated by
+ ///the algorithm.
+ ///If you don't use this function before calling \ref run(Node) "run()"
+ ///or \ref init(), an instance will be allocated automatically.
+ ///The destructor deallocates this automatically allocated map,
+ ///of course.
+ ///\return <tt> (*this) </tt>
+ Bfs &distMap(DistMap &m)
+ {
+ if(local_dist) {
+ delete _dist;
+ local_dist=false;
+ }
+ _dist = &m;
+ return *this;
+ }
+
+ public:
+
+ ///\name Execution Control
+ ///The simplest way to execute the BFS algorithm is to use one of the
+ ///member functions called \ref run(Node) "run()".\n
+ ///If you need better control on the execution, you have to call
+ ///\ref init() first, then you can add several source nodes with
+ ///\ref addSource(). Finally the actual path computation can be
+ ///performed with one of the \ref start() functions.
+
+ ///@{
+
+ ///\brief Initializes the internal data structures.
+ ///
+ ///Initializes the internal data structures.
+ void init()
+ {
+ create_maps();
+ _queue.resize(countNodes(*G));
+ _queue_head=_queue_tail=0;
+ _curr_dist=1;
+ for ( NodeIt u(*G) ; u!=INVALID ; ++u ) {
+ _pred->set(u,INVALID);
+ _reached->set(u,false);
+ _processed->set(u,false);
+ }
+ }
+
+ ///Adds a new source node.
+
+ ///Adds a new source node to the set of nodes to be processed.
+ ///
+ void addSource(Node s)
+ {
+ if(!(*_reached)[s])
+ {
+ _reached->set(s,true);
+ _pred->set(s,INVALID);
+ _dist->set(s,0);
+ _queue[_queue_head++]=s;
+ _queue_next_dist=_queue_head;
+ }
+ }
+
+ ///Processes the next node.
+
+ ///Processes the next node.
+ ///
+ ///\return The processed node.
+ ///
+ ///\pre The queue must not be empty.
+ Node processNextNode()
+ {
+ if(_queue_tail==_queue_next_dist) {
+ _curr_dist++;
+ _queue_next_dist=_queue_head;
+ }
+ Node n=_queue[_queue_tail++];
+ _processed->set(n,true);
+ Node m;
+ for(OutArcIt e(*G,n);e!=INVALID;++e)
+ if(!(*_reached)[m=G->target(e)]) {
+ _queue[_queue_head++]=m;
+ _reached->set(m,true);
+ _pred->set(m,e);
+ _dist->set(m,_curr_dist);
+ }
+ return n;
+ }
+
+ ///Processes the next node.
+
+ ///Processes the next node and checks if the given target node
+ ///is reached. If the target node is reachable from the processed
+ ///node, then the \c reach parameter will be set to \c true.
+ ///
+ ///\param target The target node.
+ ///\retval reach Indicates if the target node is reached.
+ ///It should be initially \c false.
+ ///
+ ///\return The processed node.
+ ///
+ ///\pre The queue must not be empty.
+ Node processNextNode(Node target, bool& reach)
+ {
+ if(_queue_tail==_queue_next_dist) {
+ _curr_dist++;
+ _queue_next_dist=_queue_head;
+ }
+ Node n=_queue[_queue_tail++];
+ _processed->set(n,true);
+ Node m;
+ for(OutArcIt e(*G,n);e!=INVALID;++e)
+ if(!(*_reached)[m=G->target(e)]) {
+ _queue[_queue_head++]=m;
+ _reached->set(m,true);
+ _pred->set(m,e);
+ _dist->set(m,_curr_dist);
+ reach = reach || (target == m);
+ }
+ return n;
+ }
+
+ ///Processes the next node.
+
+ ///Processes the next node and checks if at least one of reached
+ ///nodes has \c true value in the \c nm node map. If one node
+ ///with \c true value is reachable from the processed node, then the
+ ///\c rnode parameter will be set to the first of such nodes.
+ ///
+ ///\param nm A \c bool (or convertible) node map that indicates the
+ ///possible targets.
+ ///\retval rnode The reached target node.
+ ///It should be initially \c INVALID.
+ ///
+ ///\return The processed node.
+ ///
+ ///\pre The queue must not be empty.
+ template<class NM>
+ Node processNextNode(const NM& nm, Node& rnode)
+ {
+ if(_queue_tail==_queue_next_dist) {
+ _curr_dist++;
+ _queue_next_dist=_queue_head;
+ }
+ Node n=_queue[_queue_tail++];
+ _processed->set(n,true);
+ Node m;
+ for(OutArcIt e(*G,n);e!=INVALID;++e)
+ if(!(*_reached)[m=G->target(e)]) {
+ _queue[_queue_head++]=m;
+ _reached->set(m,true);
+ _pred->set(m,e);
+ _dist->set(m,_curr_dist);
+ if (nm[m] && rnode == INVALID) rnode = m;
+ }
+ return n;
+ }
+
+ ///The next node to be processed.
+
+ ///Returns the next node to be processed or \c INVALID if the queue
+ ///is empty.
+ Node nextNode() const
+ {
+ return _queue_tail<_queue_head?_queue[_queue_tail]:INVALID;
+ }
+
+ ///Returns \c false if there are nodes to be processed.
+
+ ///Returns \c false if there are nodes to be processed
+ ///in the queue.
+ bool emptyQueue() const { return _queue_tail==_queue_head; }
+
+ ///Returns the number of the nodes to be processed.
+
+ ///Returns the number of the nodes to be processed
+ ///in the queue.
+ int queueSize() const { return _queue_head-_queue_tail; }
+
+ ///Executes the algorithm.
+
+ ///Executes the algorithm.
+ ///
+ ///This method runs the %BFS algorithm from the root node(s)
+ ///in order to compute the shortest path to each node.
+ ///
+ ///The algorithm computes
+ ///- the shortest path tree (forest),
+ ///- the distance of each node from the root(s).
+ ///
+ ///\pre init() must be called and at least one root node should be
+ ///added with addSource() before using this function.
+ ///
+ ///\note <tt>b.start()</tt> is just a shortcut of the following code.
+ ///\code
+ /// while ( !b.emptyQueue() ) {
+ /// b.processNextNode();
+ /// }
+ ///\endcode
+ void start()
+ {
+ while ( !emptyQueue() ) processNextNode();
+ }
+
+ ///Executes the algorithm until the given target node is reached.
+
+ ///Executes the algorithm until the given target node is reached.
+ ///
+ ///This method runs the %BFS algorithm from the root node(s)
+ ///in order to compute the shortest path to \c t.
+ ///
+ ///The algorithm computes
+ ///- the shortest path to \c t,
+ ///- the distance of \c t from the root(s).
+ ///
+ ///\pre init() must be called and at least one root node should be
+ ///added with addSource() before using this function.
+ ///
+ ///\note <tt>b.start(t)</tt> is just a shortcut of the following code.
+ ///\code
+ /// bool reach = false;
+ /// while ( !b.emptyQueue() && !reach ) {
+ /// b.processNextNode(t, reach);
+ /// }
+ ///\endcode
+ void start(Node t)
+ {
+ bool reach = false;
+ while ( !emptyQueue() && !reach ) processNextNode(t, reach);
+ }
+
+ ///Executes the algorithm until a condition is met.
+
+ ///Executes the algorithm until a condition is met.
+ ///
+ ///This method runs the %BFS algorithm from the root node(s) in
+ ///order to compute the shortest path to a node \c v with
+ /// <tt>nm[v]</tt> true, if such a node can be found.
+ ///
+ ///\param nm A \c bool (or convertible) node map. The algorithm
+ ///will stop when it reaches a node \c v with <tt>nm[v]</tt> true.
+ ///
+ ///\return The reached node \c v with <tt>nm[v]</tt> true or
+ ///\c INVALID if no such node was found.
+ ///
+ ///\pre init() must be called and at least one root node should be
+ ///added with addSource() before using this function.
+ ///
+ ///\note <tt>b.start(nm)</tt> is just a shortcut of the following code.
+ ///\code
+ /// Node rnode = INVALID;
+ /// while ( !b.emptyQueue() && rnode == INVALID ) {
+ /// b.processNextNode(nm, rnode);
+ /// }
+ /// return rnode;
+ ///\endcode
+ template<class NodeBoolMap>
+ Node start(const NodeBoolMap &nm)
+ {
+ Node rnode = INVALID;
+ while ( !emptyQueue() && rnode == INVALID ) {
+ processNextNode(nm, rnode);
+ }
+ return rnode;
+ }
+
+ ///Runs the algorithm from the given source node.
+
+ ///This method runs the %BFS algorithm from node \c s
+ ///in order to compute the shortest path to each node.
+ ///
+ ///The algorithm computes
+ ///- the shortest path tree,
+ ///- the distance of each node from the root.
+ ///
+ ///\note <tt>b.run(s)</tt> is just a shortcut of the following code.
+ ///\code
+ /// b.init();
+ /// b.addSource(s);
+ /// b.start();
+ ///\endcode
+ void run(Node s) {
+ init();
+ addSource(s);
+ start();
+ }
+
+ ///Finds the shortest path between \c s and \c t.
+
+ ///This method runs the %BFS algorithm from node \c s
+ ///in order to compute the shortest path to node \c t
+ ///(it stops searching when \c t is processed).
+ ///
+ ///\return \c true if \c t is reachable form \c s.
+ ///
+ ///\note Apart from the return value, <tt>b.run(s,t)</tt> is just a
+ ///shortcut of the following code.
+ ///\code
+ /// b.init();
+ /// b.addSource(s);
+ /// b.start(t);
+ ///\endcode
+ bool run(Node s,Node t) {
+ init();
+ addSource(s);
+ start(t);
+ return reached(t);
+ }
+
+ ///Runs the algorithm to visit all nodes in the digraph.
+
+ ///This method runs the %BFS algorithm in order to visit all nodes
+ ///in the digraph.
+ ///
+ ///\note <tt>b.run(s)</tt> is just a shortcut of the following code.
+ ///\code
+ /// b.init();
+ /// for (NodeIt n(gr); n != INVALID; ++n) {
+ /// if (!b.reached(n)) {
+ /// b.addSource(n);
+ /// b.start();
+ /// }
+ /// }
+ ///\endcode
+ void run() {
+ init();
+ for (NodeIt n(*G); n != INVALID; ++n) {
+ if (!reached(n)) {
+ addSource(n);
+ start();
+ }
+ }
+ }
+
+ ///@}
+
+ ///\name Query Functions
+ ///The results of the BFS algorithm can be obtained using these
+ ///functions.\n
+ ///Either \ref run(Node) "run()" or \ref start() should be called
+ ///before using them.
+
+ ///@{
+
+ ///The shortest path to the given node.
+
+ ///Returns the shortest path to the given node from the root(s).
+ ///
+ ///\warning \c t should be reached from the root(s).
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ Path path(Node t) const { return Path(*G, *_pred, t); }
+
+ ///The distance of the given node from the root(s).
+
+ ///Returns the distance of the given node from the root(s).
+ ///
+ ///\warning If node \c v is not reached from the root(s), then
+ ///the return value of this function is undefined.
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ int dist(Node v) const { return (*_dist)[v]; }
+
+ ///\brief Returns the 'previous arc' of the shortest path tree for
+ ///the given node.
+ ///
+ ///This function returns the 'previous arc' of the shortest path
+ ///tree for the node \c v, i.e. it returns the last arc of a
+ ///shortest path from a root to \c v. It is \c INVALID if \c v
+ ///is not reached from the root(s) or if \c v is a root.
+ ///
+ ///The shortest path tree used here is equal to the shortest path
+ ///tree used in \ref predNode() and \ref predMap().
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ Arc predArc(Node v) const { return (*_pred)[v];}
+
+ ///\brief Returns the 'previous node' of the shortest path tree for
+ ///the given node.
+ ///
+ ///This function returns the 'previous node' of the shortest path
+ ///tree for the node \c v, i.e. it returns the last but one node
+ ///of a shortest path from a root to \c v. It is \c INVALID
+ ///if \c v is not reached from the root(s) or if \c v is a root.
+ ///
+ ///The shortest path tree used here is equal to the shortest path
+ ///tree used in \ref predArc() and \ref predMap().
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ Node predNode(Node v) const { return (*_pred)[v]==INVALID ? INVALID:
+ G->source((*_pred)[v]); }
+
+ ///\brief Returns a const reference to the node map that stores the
+ /// distances of the nodes.
+ ///
+ ///Returns a const reference to the node map that stores the distances
+ ///of the nodes calculated by the algorithm.
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ const DistMap &distMap() const { return *_dist;}
+
+ ///\brief Returns a const reference to the node map that stores the
+ ///predecessor arcs.
+ ///
+ ///Returns a const reference to the node map that stores the predecessor
+ ///arcs, which form the shortest path tree (forest).
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ const PredMap &predMap() const { return *_pred;}
+
+ ///Checks if the given node is reached from the root(s).
+
+ ///Returns \c true if \c v is reached from the root(s).
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ bool reached(Node v) const { return (*_reached)[v]; }
+
+ ///@}
+ };
+
+ ///Default traits class of bfs() function.
+
+ ///Default traits class of bfs() function.
+ ///\tparam GR Digraph type.
+ template<class GR>
+ struct BfsWizardDefaultTraits
+ {
+ ///The type of the digraph the algorithm runs on.
+ typedef GR Digraph;
+
+ ///\brief The type of the map that stores the predecessor
+ ///arcs of the shortest paths.
+ ///
+ ///The type of the map that stores the predecessor
+ ///arcs of the shortest paths.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ typedef typename Digraph::template NodeMap<typename Digraph::Arc> PredMap;
+ ///Instantiates a PredMap.
+
+ ///This function instantiates a PredMap.
+ ///\param g is the digraph, to which we would like to define the
+ ///PredMap.
+ static PredMap *createPredMap(const Digraph &g)
+ {
+ return new PredMap(g);
+ }
+
+ ///The type of the map that indicates which nodes are processed.
+
+ ///The type of the map that indicates which nodes are processed.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ ///By default, it is a NullMap.
+ typedef NullMap<typename Digraph::Node,bool> ProcessedMap;
+ ///Instantiates a ProcessedMap.
+
+ ///This function instantiates a ProcessedMap.
+ ///\param g is the digraph, to which
+ ///we would like to define the ProcessedMap.
+#ifdef DOXYGEN
+ static ProcessedMap *createProcessedMap(const Digraph &g)
+#else
+ static ProcessedMap *createProcessedMap(const Digraph &)
+#endif
+ {
+ return new ProcessedMap();
+ }
+
+ ///The type of the map that indicates which nodes are reached.
+
+ ///The type of the map that indicates which nodes are reached.
+ ///It must conform to
+ ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept.
+ typedef typename Digraph::template NodeMap<bool> ReachedMap;
+ ///Instantiates a ReachedMap.
+
+ ///This function instantiates a ReachedMap.
+ ///\param g is the digraph, to which
+ ///we would like to define the ReachedMap.
+ static ReachedMap *createReachedMap(const Digraph &g)
+ {
+ return new ReachedMap(g);
+ }
+
+ ///The type of the map that stores the distances of the nodes.
+
+ ///The type of the map that stores the distances of the nodes.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ typedef typename Digraph::template NodeMap<int> DistMap;
+ ///Instantiates a DistMap.
+
+ ///This function instantiates a DistMap.
+ ///\param g is the digraph, to which we would like to define
+ ///the DistMap
+ static DistMap *createDistMap(const Digraph &g)
+ {
+ return new DistMap(g);
+ }
+
+ ///The type of the shortest paths.
+
+ ///The type of the shortest paths.
+ ///It must conform to the \ref concepts::Path "Path" concept.
+ typedef lemon::Path<Digraph> Path;
+ };
+
+ /// Default traits class used by BfsWizard
+
+ /// Default traits class used by BfsWizard.
+ /// \tparam GR The type of the digraph.
+ template<class GR>
+ class BfsWizardBase : public BfsWizardDefaultTraits<GR>
+ {
+
+ typedef BfsWizardDefaultTraits<GR> Base;
+ protected:
+ //The type of the nodes in the digraph.
+ typedef typename Base::Digraph::Node Node;
+
+ //Pointer to the digraph the algorithm runs on.
+ void *_g;
+ //Pointer to the map of reached nodes.
+ void *_reached;
+ //Pointer to the map of processed nodes.
+ void *_processed;
+ //Pointer to the map of predecessors arcs.
+ void *_pred;
+ //Pointer to the map of distances.
+ void *_dist;
+ //Pointer to the shortest path to the target node.
+ void *_path;
+ //Pointer to the distance of the target node.
+ int *_di;
+
+ public:
+ /// Constructor.
+
+ /// This constructor does not require parameters, it initiates
+ /// all of the attributes to \c 0.
+ BfsWizardBase() : _g(0), _reached(0), _processed(0), _pred(0),
+ _dist(0), _path(0), _di(0) {}
+
+ /// Constructor.
+
+ /// This constructor requires one parameter,
+ /// others are initiated to \c 0.
+ /// \param g The digraph the algorithm runs on.
+ BfsWizardBase(const GR &g) :
+ _g(reinterpret_cast<void*>(const_cast<GR*>(&g))),
+ _reached(0), _processed(0), _pred(0), _dist(0), _path(0), _di(0) {}
+
+ };
+
+ /// Auxiliary class for the function-type interface of BFS algorithm.
+
+ /// This auxiliary class is created to implement the
+ /// \ref bfs() "function-type interface" of \ref Bfs algorithm.
+ /// It does not have own \ref run(Node) "run()" method, it uses the
+ /// functions and features of the plain \ref Bfs.
+ ///
+ /// This class should only be used through the \ref bfs() function,
+ /// which makes it easier to use the algorithm.
+ ///
+ /// \tparam TR The traits class that defines various types used by the
+ /// algorithm.
+ template<class TR>
+ class BfsWizard : public TR
+ {
+ typedef TR Base;
+
+ typedef typename TR::Digraph Digraph;
+
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::NodeIt NodeIt;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::OutArcIt OutArcIt;
+
+ typedef typename TR::PredMap PredMap;
+ typedef typename TR::DistMap DistMap;
+ typedef typename TR::ReachedMap ReachedMap;
+ typedef typename TR::ProcessedMap ProcessedMap;
+ typedef typename TR::Path Path;
+
+ public:
+
+ /// Constructor.
+ BfsWizard() : TR() {}
+
+ /// Constructor that requires parameters.
+
+ /// Constructor that requires parameters.
+ /// These parameters will be the default values for the traits class.
+ /// \param g The digraph the algorithm runs on.
+ BfsWizard(const Digraph &g) :
+ TR(g) {}
+
+ ///Copy constructor
+ BfsWizard(const TR &b) : TR(b) {}
+
+ ~BfsWizard() {}
+
+ ///Runs BFS algorithm from the given source node.
+
+ ///This method runs BFS algorithm from node \c s
+ ///in order to compute the shortest path to each node.
+ void run(Node s)
+ {
+ Bfs<Digraph,TR> alg(*reinterpret_cast<const Digraph*>(Base::_g));
+ if (Base::_pred)
+ alg.predMap(*reinterpret_cast<PredMap*>(Base::_pred));
+ if (Base::_dist)
+ alg.distMap(*reinterpret_cast<DistMap*>(Base::_dist));
+ if (Base::_reached)
+ alg.reachedMap(*reinterpret_cast<ReachedMap*>(Base::_reached));
+ if (Base::_processed)
+ alg.processedMap(*reinterpret_cast<ProcessedMap*>(Base::_processed));
+ if (s!=INVALID)
+ alg.run(s);
+ else
+ alg.run();
+ }
+
+ ///Finds the shortest path between \c s and \c t.
+
+ ///This method runs BFS algorithm from node \c s
+ ///in order to compute the shortest path to node \c t
+ ///(it stops searching when \c t is processed).
+ ///
+ ///\return \c true if \c t is reachable form \c s.
+ bool run(Node s, Node t)
+ {
+ Bfs<Digraph,TR> alg(*reinterpret_cast<const Digraph*>(Base::_g));
+ if (Base::_pred)
+ alg.predMap(*reinterpret_cast<PredMap*>(Base::_pred));
+ if (Base::_dist)
+ alg.distMap(*reinterpret_cast<DistMap*>(Base::_dist));
+ if (Base::_reached)
+ alg.reachedMap(*reinterpret_cast<ReachedMap*>(Base::_reached));
+ if (Base::_processed)
+ alg.processedMap(*reinterpret_cast<ProcessedMap*>(Base::_processed));
+ alg.run(s,t);
+ if (Base::_path)
+ *reinterpret_cast<Path*>(Base::_path) = alg.path(t);
+ if (Base::_di)
+ *Base::_di = alg.dist(t);
+ return alg.reached(t);
+ }
+
+ ///Runs BFS algorithm to visit all nodes in the digraph.
+
+ ///This method runs BFS algorithm in order to visit all nodes
+ ///in the digraph.
+ void run()
+ {
+ run(INVALID);
+ }
+
+ template<class T>
+ struct SetPredMapBase : public Base {
+ typedef T PredMap;
+ static PredMap *createPredMap(const Digraph &) { return 0; };
+ SetPredMapBase(const TR &b) : TR(b) {}
+ };
+
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///the predecessor map.
+ ///
+ ///\ref named-templ-param "Named parameter" function for setting
+ ///the map that stores the predecessor arcs of the nodes.
+ template<class T>
+ BfsWizard<SetPredMapBase<T> > predMap(const T &t)
+ {
+ Base::_pred=reinterpret_cast<void*>(const_cast<T*>(&t));
+ return BfsWizard<SetPredMapBase<T> >(*this);
+ }
+
+ template<class T>
+ struct SetReachedMapBase : public Base {
+ typedef T ReachedMap;
+ static ReachedMap *createReachedMap(const Digraph &) { return 0; };
+ SetReachedMapBase(const TR &b) : TR(b) {}
+ };
+
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///the reached map.
+ ///
+ ///\ref named-templ-param "Named parameter" function for setting
+ ///the map that indicates which nodes are reached.
+ template<class T>
+ BfsWizard<SetReachedMapBase<T> > reachedMap(const T &t)
+ {
+ Base::_reached=reinterpret_cast<void*>(const_cast<T*>(&t));
+ return BfsWizard<SetReachedMapBase<T> >(*this);
+ }
+
+ template<class T>
+ struct SetDistMapBase : public Base {
+ typedef T DistMap;
+ static DistMap *createDistMap(const Digraph &) { return 0; };
+ SetDistMapBase(const TR &b) : TR(b) {}
+ };
+
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///the distance map.
+ ///
+ ///\ref named-templ-param "Named parameter" function for setting
+ ///the map that stores the distances of the nodes calculated
+ ///by the algorithm.
+ template<class T>
+ BfsWizard<SetDistMapBase<T> > distMap(const T &t)
+ {
+ Base::_dist=reinterpret_cast<void*>(const_cast<T*>(&t));
+ return BfsWizard<SetDistMapBase<T> >(*this);
+ }
+
+ template<class T>
+ struct SetProcessedMapBase : public Base {
+ typedef T ProcessedMap;
+ static ProcessedMap *createProcessedMap(const Digraph &) { return 0; };
+ SetProcessedMapBase(const TR &b) : TR(b) {}
+ };
+
+ ///\brief \ref named-func-param "Named parameter" for setting
+ ///the processed map.
+ ///
+ ///\ref named-templ-param "Named parameter" function for setting
+ ///the map that indicates which nodes are processed.
+ template<class T>
+ BfsWizard<SetProcessedMapBase<T> > processedMap(const T &t)
+ {
+ Base::_processed=reinterpret_cast<void*>(const_cast<T*>(&t));
+ return BfsWizard<SetProcessedMapBase<T> >(*this);
+ }
+
+ template<class T>
+ struct SetPathBase : public Base {
+ typedef T Path;
+ SetPathBase(const TR &b) : TR(b) {}
+ };
+ ///\brief \ref named-func-param "Named parameter"
+ ///for getting the shortest path to the target node.
+ ///
+ ///\ref named-func-param "Named parameter"
+ ///for getting the shortest path to the target node.
+ template<class T>
+ BfsWizard<SetPathBase<T> > path(const T &t)
+ {
+ Base::_path=reinterpret_cast<void*>(const_cast<T*>(&t));
+ return BfsWizard<SetPathBase<T> >(*this);
+ }
+
+ ///\brief \ref named-func-param "Named parameter"
+ ///for getting the distance of the target node.
+ ///
+ ///\ref named-func-param "Named parameter"
+ ///for getting the distance of the target node.
+ BfsWizard dist(const int &d)
+ {
+ Base::_di=const_cast<int*>(&d);
+ return *this;
+ }
+
+ };
+
+ ///Function-type interface for BFS algorithm.
+
+ /// \ingroup search
+ ///Function-type interface for BFS algorithm.
+ ///
+ ///This function also has several \ref named-func-param "named parameters",
+ ///they are declared as the members of class \ref BfsWizard.
+ ///The following examples show how to use these parameters.
+ ///\code
+ /// // Compute shortest path from node s to each node
+ /// bfs(g).predMap(preds).distMap(dists).run(s);
+ ///
+ /// // Compute shortest path from s to t
+ /// bool reached = bfs(g).path(p).dist(d).run(s,t);
+ ///\endcode
+ ///\warning Don't forget to put the \ref BfsWizard::run(Node) "run()"
+ ///to the end of the parameter list.
+ ///\sa BfsWizard
+ ///\sa Bfs
+ template<class GR>
+ BfsWizard<BfsWizardBase<GR> >
+ bfs(const GR &digraph)
+ {
+ return BfsWizard<BfsWizardBase<GR> >(digraph);
+ }
+
+#ifdef DOXYGEN
+ /// \brief Visitor class for BFS.
+ ///
+ /// This class defines the interface of the BfsVisit events, and
+ /// it could be the base of a real visitor class.
+ template <typename GR>
+ struct BfsVisitor {
+ typedef GR Digraph;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::Node Node;
+ /// \brief Called for the source node(s) of the BFS.
+ ///
+ /// This function is called for the source node(s) of the BFS.
+ void start(const Node& node) {}
+ /// \brief Called when a node is reached first time.
+ ///
+ /// This function is called when a node is reached first time.
+ void reach(const Node& node) {}
+ /// \brief Called when a node is processed.
+ ///
+ /// This function is called when a node is processed.
+ void process(const Node& node) {}
+ /// \brief Called when an arc reaches a new node.
+ ///
+ /// This function is called when the BFS finds an arc whose target node
+ /// is not reached yet.
+ void discover(const Arc& arc) {}
+ /// \brief Called when an arc is examined but its target node is
+ /// already discovered.
+ ///
+ /// This function is called when an arc is examined but its target node is
+ /// already discovered.
+ void examine(const Arc& arc) {}
+ };
+#else
+ template <typename GR>
+ struct BfsVisitor {
+ typedef GR Digraph;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::Node Node;
+ void start(const Node&) {}
+ void reach(const Node&) {}
+ void process(const Node&) {}
+ void discover(const Arc&) {}
+ void examine(const Arc&) {}
+
+ template <typename _Visitor>
+ struct Constraints {
+ void constraints() {
+ Arc arc;
+ Node node;
+ visitor.start(node);
+ visitor.reach(node);
+ visitor.process(node);
+ visitor.discover(arc);
+ visitor.examine(arc);
+ }
+ _Visitor& visitor;
+ Constraints() {}
+ };
+ };
+#endif
+
+ /// \brief Default traits class of BfsVisit class.
+ ///
+ /// Default traits class of BfsVisit class.
+ /// \tparam GR The type of the digraph the algorithm runs on.
+ template<class GR>
+ struct BfsVisitDefaultTraits {
+
+ /// \brief The type of the digraph the algorithm runs on.
+ typedef GR Digraph;
+
+ /// \brief The type of the map that indicates which nodes are reached.
+ ///
+ /// The type of the map that indicates which nodes are reached.
+ /// It must conform to
+ ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept.
+ typedef typename Digraph::template NodeMap<bool> ReachedMap;
+
+ /// \brief Instantiates a ReachedMap.
+ ///
+ /// This function instantiates a ReachedMap.
+ /// \param digraph is the digraph, to which
+ /// we would like to define the ReachedMap.
+ static ReachedMap *createReachedMap(const Digraph &digraph) {
+ return new ReachedMap(digraph);
+ }
+
+ };
+
+ /// \ingroup search
+ ///
+ /// \brief BFS algorithm class with visitor interface.
+ ///
+ /// This class provides an efficient implementation of the BFS algorithm
+ /// with visitor interface.
+ ///
+ /// The BfsVisit class provides an alternative interface to the Bfs
+ /// class. It works with callback mechanism, the BfsVisit object calls
+ /// the member functions of the \c Visitor class on every BFS event.
+ ///
+ /// This interface of the BFS algorithm should be used in special cases
+ /// when extra actions have to be performed in connection with certain
+ /// events of the BFS algorithm. Otherwise consider to use Bfs or bfs()
+ /// instead.
+ ///
+ /// \tparam GR The type of the digraph the algorithm runs on.
+ /// The default type is \ref ListDigraph.
+ /// The value of GR is not used directly by \ref BfsVisit,
+ /// it is only passed to \ref BfsVisitDefaultTraits.
+ /// \tparam VS The Visitor type that is used by the algorithm.
+ /// \ref BfsVisitor "BfsVisitor<GR>" is an empty visitor, which
+ /// does not observe the BFS events. If you want to observe the BFS
+ /// events, you should implement your own visitor class.
+ /// \tparam TR The traits class that defines various types used by the
+ /// algorithm. By default, it is \ref BfsVisitDefaultTraits
+ /// "BfsVisitDefaultTraits<GR>".
+ /// In most cases, this parameter should not be set directly,
+ /// consider to use the named template parameters instead.
+#ifdef DOXYGEN
+ template <typename GR, typename VS, typename TR>
+#else
+ template <typename GR = ListDigraph,
+ typename VS = BfsVisitor<GR>,
+ typename TR = BfsVisitDefaultTraits<GR> >
+#endif
+ class BfsVisit {
+ public:
+
+ ///The traits class.
+ typedef TR Traits;
+
+ ///The type of the digraph the algorithm runs on.
+ typedef typename Traits::Digraph Digraph;
+
+ ///The visitor type used by the algorithm.
+ typedef VS Visitor;
+
+ ///The type of the map that indicates which nodes are reached.
+ typedef typename Traits::ReachedMap ReachedMap;
+
+ private:
+
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::NodeIt NodeIt;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::OutArcIt OutArcIt;
+
+ //Pointer to the underlying digraph.
+ const Digraph *_digraph;
+ //Pointer to the visitor object.
+ Visitor *_visitor;
+ //Pointer to the map of reached status of the nodes.
+ ReachedMap *_reached;
+ //Indicates if _reached is locally allocated (true) or not.
+ bool local_reached;
+
+ std::vector<typename Digraph::Node> _list;
+ int _list_front, _list_back;
+
+ //Creates the maps if necessary.
+ void create_maps() {
+ if(!_reached) {
+ local_reached = true;
+ _reached = Traits::createReachedMap(*_digraph);
+ }
+ }
+
+ protected:
+
+ BfsVisit() {}
+
+ public:
+
+ typedef BfsVisit Create;
+
+ /// \name Named Template Parameters
+
+ ///@{
+ template <class T>
+ struct SetReachedMapTraits : public Traits {
+ typedef T ReachedMap;
+ static ReachedMap *createReachedMap(const Digraph &digraph) {
+ LEMON_ASSERT(false, "ReachedMap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// ReachedMap type.
+ ///
+ /// \ref named-templ-param "Named parameter" for setting ReachedMap type.
+ template <class T>
+ struct SetReachedMap : public BfsVisit< Digraph, Visitor,
+ SetReachedMapTraits<T> > {
+ typedef BfsVisit< Digraph, Visitor, SetReachedMapTraits<T> > Create;
+ };
+ ///@}
+
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ ///
+ /// \param digraph The digraph the algorithm runs on.
+ /// \param visitor The visitor object of the algorithm.
+ BfsVisit(const Digraph& digraph, Visitor& visitor)
+ : _digraph(&digraph), _visitor(&visitor),
+ _reached(0), local_reached(false) {}
+
+ /// \brief Destructor.
+ ~BfsVisit() {
+ if(local_reached) delete _reached;
+ }
+
+ /// \brief Sets the map that indicates which nodes are reached.
+ ///
+ /// Sets the map that indicates which nodes are reached.
+ /// If you don't use this function before calling \ref run(Node) "run()"
+ /// or \ref init(), an instance will be allocated automatically.
+ /// The destructor deallocates this automatically allocated map,
+ /// of course.
+ /// \return <tt> (*this) </tt>
+ BfsVisit &reachedMap(ReachedMap &m) {
+ if(local_reached) {
+ delete _reached;
+ local_reached = false;
+ }
+ _reached = &m;
+ return *this;
+ }
+
+ public:
+
+ /// \name Execution Control
+ /// The simplest way to execute the BFS algorithm is to use one of the
+ /// member functions called \ref run(Node) "run()".\n
+ /// If you need better control on the execution, you have to call
+ /// \ref init() first, then you can add several source nodes with
+ /// \ref addSource(). Finally the actual path computation can be
+ /// performed with one of the \ref start() functions.
+
+ /// @{
+
+ /// \brief Initializes the internal data structures.
+ ///
+ /// Initializes the internal data structures.
+ void init() {
+ create_maps();
+ _list.resize(countNodes(*_digraph));
+ _list_front = _list_back = -1;
+ for (NodeIt u(*_digraph) ; u != INVALID ; ++u) {
+ _reached->set(u, false);
+ }
+ }
+
+ /// \brief Adds a new source node.
+ ///
+ /// Adds a new source node to the set of nodes to be processed.
+ void addSource(Node s) {
+ if(!(*_reached)[s]) {
+ _reached->set(s,true);
+ _visitor->start(s);
+ _visitor->reach(s);
+ _list[++_list_back] = s;
+ }
+ }
+
+ /// \brief Processes the next node.
+ ///
+ /// Processes the next node.
+ ///
+ /// \return The processed node.
+ ///
+ /// \pre The queue must not be empty.
+ Node processNextNode() {
+ Node n = _list[++_list_front];
+ _visitor->process(n);
+ Arc e;
+ for (_digraph->firstOut(e, n); e != INVALID; _digraph->nextOut(e)) {
+ Node m = _digraph->target(e);
+ if (!(*_reached)[m]) {
+ _visitor->discover(e);
+ _visitor->reach(m);
+ _reached->set(m, true);
+ _list[++_list_back] = m;
+ } else {
+ _visitor->examine(e);
+ }
+ }
+ return n;
+ }
+
+ /// \brief Processes the next node.
+ ///
+ /// Processes the next node and checks if the given target node
+ /// is reached. If the target node is reachable from the processed
+ /// node, then the \c reach parameter will be set to \c true.
+ ///
+ /// \param target The target node.
+ /// \retval reach Indicates if the target node is reached.
+ /// It should be initially \c false.
+ ///
+ /// \return The processed node.
+ ///
+ /// \pre The queue must not be empty.
+ Node processNextNode(Node target, bool& reach) {
+ Node n = _list[++_list_front];
+ _visitor->process(n);
+ Arc e;
+ for (_digraph->firstOut(e, n); e != INVALID; _digraph->nextOut(e)) {
+ Node m = _digraph->target(e);
+ if (!(*_reached)[m]) {
+ _visitor->discover(e);
+ _visitor->reach(m);
+ _reached->set(m, true);
+ _list[++_list_back] = m;
+ reach = reach || (target == m);
+ } else {
+ _visitor->examine(e);
+ }
+ }
+ return n;
+ }
+
+ /// \brief Processes the next node.
+ ///
+ /// Processes the next node and checks if at least one of reached
+ /// nodes has \c true value in the \c nm node map. If one node
+ /// with \c true value is reachable from the processed node, then the
+ /// \c rnode parameter will be set to the first of such nodes.
+ ///
+ /// \param nm A \c bool (or convertible) node map that indicates the
+ /// possible targets.
+ /// \retval rnode The reached target node.
+ /// It should be initially \c INVALID.
+ ///
+ /// \return The processed node.
+ ///
+ /// \pre The queue must not be empty.
+ template <typename NM>
+ Node processNextNode(const NM& nm, Node& rnode) {
+ Node n = _list[++_list_front];
+ _visitor->process(n);
+ Arc e;
+ for (_digraph->firstOut(e, n); e != INVALID; _digraph->nextOut(e)) {
+ Node m = _digraph->target(e);
+ if (!(*_reached)[m]) {
+ _visitor->discover(e);
+ _visitor->reach(m);
+ _reached->set(m, true);
+ _list[++_list_back] = m;
+ if (nm[m] && rnode == INVALID) rnode = m;
+ } else {
+ _visitor->examine(e);
+ }
+ }
+ return n;
+ }
+
+ /// \brief The next node to be processed.
+ ///
+ /// Returns the next node to be processed or \c INVALID if the queue
+ /// is empty.
+ Node nextNode() const {
+ return _list_front != _list_back ? _list[_list_front + 1] : INVALID;
+ }
+
+ /// \brief Returns \c false if there are nodes
+ /// to be processed.
+ ///
+ /// Returns \c false if there are nodes
+ /// to be processed in the queue.
+ bool emptyQueue() const { return _list_front == _list_back; }
+
+ /// \brief Returns the number of the nodes to be processed.
+ ///
+ /// Returns the number of the nodes to be processed in the queue.
+ int queueSize() const { return _list_back - _list_front; }
+
+ /// \brief Executes the algorithm.
+ ///
+ /// Executes the algorithm.
+ ///
+ /// This method runs the %BFS algorithm from the root node(s)
+ /// in order to compute the shortest path to each node.
+ ///
+ /// The algorithm computes
+ /// - the shortest path tree (forest),
+ /// - the distance of each node from the root(s).
+ ///
+ /// \pre init() must be called and at least one root node should be added
+ /// with addSource() before using this function.
+ ///
+ /// \note <tt>b.start()</tt> is just a shortcut of the following code.
+ /// \code
+ /// while ( !b.emptyQueue() ) {
+ /// b.processNextNode();
+ /// }
+ /// \endcode
+ void start() {
+ while ( !emptyQueue() ) processNextNode();
+ }
+
+ /// \brief Executes the algorithm until the given target node is reached.
+ ///
+ /// Executes the algorithm until the given target node is reached.
+ ///
+ /// This method runs the %BFS algorithm from the root node(s)
+ /// in order to compute the shortest path to \c t.
+ ///
+ /// The algorithm computes
+ /// - the shortest path to \c t,
+ /// - the distance of \c t from the root(s).
+ ///
+ /// \pre init() must be called and at least one root node should be
+ /// added with addSource() before using this function.
+ ///
+ /// \note <tt>b.start(t)</tt> is just a shortcut of the following code.
+ /// \code
+ /// bool reach = false;
+ /// while ( !b.emptyQueue() && !reach ) {
+ /// b.processNextNode(t, reach);
+ /// }
+ /// \endcode
+ void start(Node t) {
+ bool reach = false;
+ while ( !emptyQueue() && !reach ) processNextNode(t, reach);
+ }
+
+ /// \brief Executes the algorithm until a condition is met.
+ ///
+ /// Executes the algorithm until a condition is met.
+ ///
+ /// This method runs the %BFS algorithm from the root node(s) in
+ /// order to compute the shortest path to a node \c v with
+ /// <tt>nm[v]</tt> true, if such a node can be found.
+ ///
+ /// \param nm must be a bool (or convertible) node map. The
+ /// algorithm will stop when it reaches a node \c v with
+ /// <tt>nm[v]</tt> true.
+ ///
+ /// \return The reached node \c v with <tt>nm[v]</tt> true or
+ /// \c INVALID if no such node was found.
+ ///
+ /// \pre init() must be called and at least one root node should be
+ /// added with addSource() before using this function.
+ ///
+ /// \note <tt>b.start(nm)</tt> is just a shortcut of the following code.
+ /// \code
+ /// Node rnode = INVALID;
+ /// while ( !b.emptyQueue() && rnode == INVALID ) {
+ /// b.processNextNode(nm, rnode);
+ /// }
+ /// return rnode;
+ /// \endcode
+ template <typename NM>
+ Node start(const NM &nm) {
+ Node rnode = INVALID;
+ while ( !emptyQueue() && rnode == INVALID ) {
+ processNextNode(nm, rnode);
+ }
+ return rnode;
+ }
+
+ /// \brief Runs the algorithm from the given source node.
+ ///
+ /// This method runs the %BFS algorithm from node \c s
+ /// in order to compute the shortest path to each node.
+ ///
+ /// The algorithm computes
+ /// - the shortest path tree,
+ /// - the distance of each node from the root.
+ ///
+ /// \note <tt>b.run(s)</tt> is just a shortcut of the following code.
+ ///\code
+ /// b.init();
+ /// b.addSource(s);
+ /// b.start();
+ ///\endcode
+ void run(Node s) {
+ init();
+ addSource(s);
+ start();
+ }
+
+ /// \brief Finds the shortest path between \c s and \c t.
+ ///
+ /// This method runs the %BFS algorithm from node \c s
+ /// in order to compute the shortest path to node \c t
+ /// (it stops searching when \c t is processed).
+ ///
+ /// \return \c true if \c t is reachable form \c s.
+ ///
+ /// \note Apart from the return value, <tt>b.run(s,t)</tt> is just a
+ /// shortcut of the following code.
+ ///\code
+ /// b.init();
+ /// b.addSource(s);
+ /// b.start(t);
+ ///\endcode
+ bool run(Node s,Node t) {
+ init();
+ addSource(s);
+ start(t);
+ return reached(t);
+ }
+
+ /// \brief Runs the algorithm to visit all nodes in the digraph.
+ ///
+ /// This method runs the %BFS algorithm in order to visit all nodes
+ /// in the digraph.
+ ///
+ /// \note <tt>b.run(s)</tt> is just a shortcut of the following code.
+ ///\code
+ /// b.init();
+ /// for (NodeIt n(gr); n != INVALID; ++n) {
+ /// if (!b.reached(n)) {
+ /// b.addSource(n);
+ /// b.start();
+ /// }
+ /// }
+ ///\endcode
+ void run() {
+ init();
+ for (NodeIt it(*_digraph); it != INVALID; ++it) {
+ if (!reached(it)) {
+ addSource(it);
+ start();
+ }
+ }
+ }
+
+ ///@}
+
+ /// \name Query Functions
+ /// The results of the BFS algorithm can be obtained using these
+ /// functions.\n
+ /// Either \ref run(Node) "run()" or \ref start() should be called
+ /// before using them.
+
+ ///@{
+
+ /// \brief Checks if the given node is reached from the root(s).
+ ///
+ /// Returns \c true if \c v is reached from the root(s).
+ ///
+ /// \pre Either \ref run(Node) "run()" or \ref init()
+ /// must be called before using this function.
+ bool reached(Node v) const { return (*_reached)[v]; }
+
+ ///@}
+
+ };
+
+} //END OF NAMESPACE LEMON
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bin_heap.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bin_heap.h
new file mode 100644
index 00000000000..02c66582210
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bin_heap.h
@@ -0,0 +1,347 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_BIN_HEAP_H
+#define LEMON_BIN_HEAP_H
+
+///\ingroup heaps
+///\file
+///\brief Binary heap implementation.
+
+#include <vector>
+#include <utility>
+#include <functional>
+
+namespace lemon {
+
+ /// \ingroup heaps
+ ///
+ /// \brief Binary heap data structure.
+ ///
+ /// This class implements the \e binary \e heap data structure.
+ /// It fully conforms to the \ref concepts::Heap "heap concept".
+ ///
+ /// \tparam PR Type of the priorities of the items.
+ /// \tparam IM A read-writable item map with \c int values, used
+ /// internally to handle the cross references.
+ /// \tparam CMP A functor class for comparing the priorities.
+ /// The default is \c std::less<PR>.
+#ifdef DOXYGEN
+ template <typename PR, typename IM, typename CMP>
+#else
+ template <typename PR, typename IM, typename CMP = std::less<PR> >
+#endif
+ class BinHeap {
+ public:
+
+ /// Type of the item-int map.
+ typedef IM ItemIntMap;
+ /// Type of the priorities.
+ typedef PR Prio;
+ /// Type of the items stored in the heap.
+ typedef typename ItemIntMap::Key Item;
+ /// Type of the item-priority pairs.
+ typedef std::pair<Item,Prio> Pair;
+ /// Functor type for comparing the priorities.
+ typedef CMP Compare;
+
+ /// \brief Type to represent the states of the items.
+ ///
+ /// Each item has a state associated to it. It can be "in heap",
+ /// "pre-heap" or "post-heap". The latter two are indifferent from the
+ /// heap's point of view, but may be useful to the user.
+ ///
+ /// The item-int map must be initialized in such way that it assigns
+ /// \c PRE_HEAP (<tt>-1</tt>) to any element to be put in the heap.
+ enum State {
+ IN_HEAP = 0, ///< = 0.
+ PRE_HEAP = -1, ///< = -1.
+ POST_HEAP = -2 ///< = -2.
+ };
+
+ private:
+ std::vector<Pair> _data;
+ Compare _comp;
+ ItemIntMap &_iim;
+
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ /// \param map A map that assigns \c int values to the items.
+ /// It is used internally to handle the cross references.
+ /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
+ explicit BinHeap(ItemIntMap &map) : _iim(map) {}
+
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ /// \param map A map that assigns \c int values to the items.
+ /// It is used internally to handle the cross references.
+ /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
+ /// \param comp The function object used for comparing the priorities.
+ BinHeap(ItemIntMap &map, const Compare &comp)
+ : _iim(map), _comp(comp) {}
+
+
+ /// \brief The number of items stored in the heap.
+ ///
+ /// This function returns the number of items stored in the heap.
+ int size() const { return _data.size(); }
+
+ /// \brief Check if the heap is empty.
+ ///
+ /// This function returns \c true if the heap is empty.
+ bool empty() const { return _data.empty(); }
+
+ /// \brief Make the heap empty.
+ ///
+ /// This functon makes the heap empty.
+ /// It does not change the cross reference map. If you want to reuse
+ /// a heap that is not surely empty, you should first clear it and
+ /// then you should set the cross reference map to \c PRE_HEAP
+ /// for each item.
+ void clear() {
+ _data.clear();
+ }
+
+ private:
+ static int parent(int i) { return (i-1)/2; }
+
+ static int secondChild(int i) { return 2*i+2; }
+ bool less(const Pair &p1, const Pair &p2) const {
+ return _comp(p1.second, p2.second);
+ }
+
+ int bubbleUp(int hole, Pair p) {
+ int par = parent(hole);
+ while( hole>0 && less(p,_data[par]) ) {
+ move(_data[par],hole);
+ hole = par;
+ par = parent(hole);
+ }
+ move(p, hole);
+ return hole;
+ }
+
+ int bubbleDown(int hole, Pair p, int length) {
+ int child = secondChild(hole);
+ while(child < length) {
+ if( less(_data[child-1], _data[child]) ) {
+ --child;
+ }
+ if( !less(_data[child], p) )
+ goto ok;
+ move(_data[child], hole);
+ hole = child;
+ child = secondChild(hole);
+ }
+ child--;
+ if( child<length && less(_data[child], p) ) {
+ move(_data[child], hole);
+ hole=child;
+ }
+ ok:
+ move(p, hole);
+ return hole;
+ }
+
+ void move(const Pair &p, int i) {
+ _data[i] = p;
+ _iim.set(p.first, i);
+ }
+
+ public:
+
+ /// \brief Insert a pair of item and priority into the heap.
+ ///
+ /// This function inserts \c p.first to the heap with priority
+ /// \c p.second.
+ /// \param p The pair to insert.
+ /// \pre \c p.first must not be stored in the heap.
+ void push(const Pair &p) {
+ int n = _data.size();
+ _data.resize(n+1);
+ bubbleUp(n, p);
+ }
+
+ /// \brief Insert an item into the heap with the given priority.
+ ///
+ /// This function inserts the given item into the heap with the
+ /// given priority.
+ /// \param i The item to insert.
+ /// \param p The priority of the item.
+ /// \pre \e i must not be stored in the heap.
+ void push(const Item &i, const Prio &p) { push(Pair(i,p)); }
+
+ /// \brief Return the item having minimum priority.
+ ///
+ /// This function returns the item having minimum priority.
+ /// \pre The heap must be non-empty.
+ Item top() const {
+ return _data[0].first;
+ }
+
+ /// \brief The minimum priority.
+ ///
+ /// This function returns the minimum priority.
+ /// \pre The heap must be non-empty.
+ Prio prio() const {
+ return _data[0].second;
+ }
+
+ /// \brief Remove the item having minimum priority.
+ ///
+ /// This function removes the item having minimum priority.
+ /// \pre The heap must be non-empty.
+ void pop() {
+ int n = _data.size()-1;
+ _iim.set(_data[0].first, POST_HEAP);
+ if (n > 0) {
+ bubbleDown(0, _data[n], n);
+ }
+ _data.pop_back();
+ }
+
+ /// \brief Remove the given item from the heap.
+ ///
+ /// This function removes the given item from the heap if it is
+ /// already stored.
+ /// \param i The item to delete.
+ /// \pre \e i must be in the heap.
+ void erase(const Item &i) {
+ int h = _iim[i];
+ int n = _data.size()-1;
+ _iim.set(_data[h].first, POST_HEAP);
+ if( h < n ) {
+ if ( bubbleUp(h, _data[n]) == h) {
+ bubbleDown(h, _data[n], n);
+ }
+ }
+ _data.pop_back();
+ }
+
+ /// \brief The priority of the given item.
+ ///
+ /// This function returns the priority of the given item.
+ /// \param i The item.
+ /// \pre \e i must be in the heap.
+ Prio operator[](const Item &i) const {
+ int idx = _iim[i];
+ return _data[idx].second;
+ }
+
+ /// \brief Set the priority of an item or insert it, if it is
+ /// not stored in the heap.
+ ///
+ /// This method sets the priority of the given item if it is
+ /// already stored in the heap. Otherwise it inserts the given
+ /// item into the heap with the given priority.
+ /// \param i The item.
+ /// \param p The priority.
+ void set(const Item &i, const Prio &p) {
+ int idx = _iim[i];
+ if( idx < 0 ) {
+ push(i,p);
+ }
+ else if( _comp(p, _data[idx].second) ) {
+ bubbleUp(idx, Pair(i,p));
+ }
+ else {
+ bubbleDown(idx, Pair(i,p), _data.size());
+ }
+ }
+
+ /// \brief Decrease the priority of an item to the given value.
+ ///
+ /// This function decreases the priority of an item to the given value.
+ /// \param i The item.
+ /// \param p The priority.
+ /// \pre \e i must be stored in the heap with priority at least \e p.
+ void decrease(const Item &i, const Prio &p) {
+ int idx = _iim[i];
+ bubbleUp(idx, Pair(i,p));
+ }
+
+ /// \brief Increase the priority of an item to the given value.
+ ///
+ /// This function increases the priority of an item to the given value.
+ /// \param i The item.
+ /// \param p The priority.
+ /// \pre \e i must be stored in the heap with priority at most \e p.
+ void increase(const Item &i, const Prio &p) {
+ int idx = _iim[i];
+ bubbleDown(idx, Pair(i,p), _data.size());
+ }
+
+ /// \brief Return the state of an item.
+ ///
+ /// This method returns \c PRE_HEAP if the given item has never
+ /// been in the heap, \c IN_HEAP if it is in the heap at the moment,
+ /// and \c POST_HEAP otherwise.
+ /// In the latter case it is possible that the item will get back
+ /// to the heap again.
+ /// \param i The item.
+ State state(const Item &i) const {
+ int s = _iim[i];
+ if( s>=0 )
+ s=0;
+ return State(s);
+ }
+
+ /// \brief Set the state of an item in the heap.
+ ///
+ /// This function sets the state of the given item in the heap.
+ /// It can be used to manually clear the heap when it is important
+ /// to achive better time complexity.
+ /// \param i The item.
+ /// \param st The state. It should not be \c IN_HEAP.
+ void state(const Item& i, State st) {
+ switch (st) {
+ case POST_HEAP:
+ case PRE_HEAP:
+ if (state(i) == IN_HEAP) {
+ erase(i);
+ }
+ _iim[i] = st;
+ break;
+ case IN_HEAP:
+ break;
+ }
+ }
+
+ /// \brief Replace an item in the heap.
+ ///
+ /// This function replaces item \c i with item \c j.
+ /// Item \c i must be in the heap, while \c j must be out of the heap.
+ /// After calling this method, item \c i will be out of the
+ /// heap and \c j will be in the heap with the same prioriority
+ /// as item \c i had before.
+ void replace(const Item& i, const Item& j) {
+ int idx = _iim[i];
+ _iim.set(i, _iim[j]);
+ _iim.set(j, idx);
+ _data[idx].first = j;
+ }
+
+ }; // class BinHeap
+
+} // namespace lemon
+
+#endif // LEMON_BIN_HEAP_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/binomial_heap.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/binomial_heap.h
new file mode 100644
index 00000000000..5bc13787058
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/binomial_heap.h
@@ -0,0 +1,445 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2010
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_BINOMIAL_HEAP_H
+#define LEMON_BINOMIAL_HEAP_H
+
+///\file
+///\ingroup heaps
+///\brief Binomial Heap implementation.
+
+#include <vector>
+#include <utility>
+#include <functional>
+#include <lemon/math.h>
+#include <lemon/counter.h>
+
+namespace lemon {
+
+ /// \ingroup heaps
+ ///
+ ///\brief Binomial heap data structure.
+ ///
+ /// This class implements the \e binomial \e heap data structure.
+ /// It fully conforms to the \ref concepts::Heap "heap concept".
+ ///
+ /// The methods \ref increase() and \ref erase() are not efficient
+ /// in a binomial heap. In case of many calls of these operations,
+ /// it is better to use other heap structure, e.g. \ref BinHeap
+ /// "binary heap".
+ ///
+ /// \tparam PR Type of the priorities of the items.
+ /// \tparam IM A read-writable item map with \c int values, used
+ /// internally to handle the cross references.
+ /// \tparam CMP A functor class for comparing the priorities.
+ /// The default is \c std::less<PR>.
+#ifdef DOXYGEN
+ template <typename PR, typename IM, typename CMP>
+#else
+ template <typename PR, typename IM, typename CMP = std::less<PR> >
+#endif
+ class BinomialHeap {
+ public:
+ /// Type of the item-int map.
+ typedef IM ItemIntMap;
+ /// Type of the priorities.
+ typedef PR Prio;
+ /// Type of the items stored in the heap.
+ typedef typename ItemIntMap::Key Item;
+ /// Functor type for comparing the priorities.
+ typedef CMP Compare;
+
+ /// \brief Type to represent the states of the items.
+ ///
+ /// Each item has a state associated to it. It can be "in heap",
+ /// "pre-heap" or "post-heap". The latter two are indifferent from the
+ /// heap's point of view, but may be useful to the user.
+ ///
+ /// The item-int map must be initialized in such way that it assigns
+ /// \c PRE_HEAP (<tt>-1</tt>) to any element to be put in the heap.
+ enum State {
+ IN_HEAP = 0, ///< = 0.
+ PRE_HEAP = -1, ///< = -1.
+ POST_HEAP = -2 ///< = -2.
+ };
+
+ private:
+ class Store;
+
+ std::vector<Store> _data;
+ int _min, _head;
+ ItemIntMap &_iim;
+ Compare _comp;
+ int _num_items;
+
+ public:
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ /// \param map A map that assigns \c int values to the items.
+ /// It is used internally to handle the cross references.
+ /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
+ explicit BinomialHeap(ItemIntMap &map)
+ : _min(0), _head(-1), _iim(map), _num_items(0) {}
+
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ /// \param map A map that assigns \c int values to the items.
+ /// It is used internally to handle the cross references.
+ /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
+ /// \param comp The function object used for comparing the priorities.
+ BinomialHeap(ItemIntMap &map, const Compare &comp)
+ : _min(0), _head(-1), _iim(map), _comp(comp), _num_items(0) {}
+
+ /// \brief The number of items stored in the heap.
+ ///
+ /// This function returns the number of items stored in the heap.
+ int size() const { return _num_items; }
+
+ /// \brief Check if the heap is empty.
+ ///
+ /// This function returns \c true if the heap is empty.
+ bool empty() const { return _num_items==0; }
+
+ /// \brief Make the heap empty.
+ ///
+ /// This functon makes the heap empty.
+ /// It does not change the cross reference map. If you want to reuse
+ /// a heap that is not surely empty, you should first clear it and
+ /// then you should set the cross reference map to \c PRE_HEAP
+ /// for each item.
+ void clear() {
+ _data.clear(); _min=0; _num_items=0; _head=-1;
+ }
+
+ /// \brief Set the priority of an item or insert it, if it is
+ /// not stored in the heap.
+ ///
+ /// This method sets the priority of the given item if it is
+ /// already stored in the heap. Otherwise it inserts the given
+ /// item into the heap with the given priority.
+ /// \param item The item.
+ /// \param value The priority.
+ void set (const Item& item, const Prio& value) {
+ int i=_iim[item];
+ if ( i >= 0 && _data[i].in ) {
+ if ( _comp(value, _data[i].prio) ) decrease(item, value);
+ if ( _comp(_data[i].prio, value) ) increase(item, value);
+ } else push(item, value);
+ }
+
+ /// \brief Insert an item into the heap with the given priority.
+ ///
+ /// This function inserts the given item into the heap with the
+ /// given priority.
+ /// \param item The item to insert.
+ /// \param value The priority of the item.
+ /// \pre \e item must not be stored in the heap.
+ void push (const Item& item, const Prio& value) {
+ int i=_iim[item];
+ if ( i<0 ) {
+ int s=_data.size();
+ _iim.set( item,s );
+ Store st;
+ st.name=item;
+ st.prio=value;
+ _data.push_back(st);
+ i=s;
+ }
+ else {
+ _data[i].parent=_data[i].right_neighbor=_data[i].child=-1;
+ _data[i].degree=0;
+ _data[i].in=true;
+ _data[i].prio=value;
+ }
+
+ if( 0==_num_items ) {
+ _head=i;
+ _min=i;
+ } else {
+ merge(i);
+ if( _comp(_data[i].prio, _data[_min].prio) ) _min=i;
+ }
+ ++_num_items;
+ }
+
+ /// \brief Return the item having minimum priority.
+ ///
+ /// This function returns the item having minimum priority.
+ /// \pre The heap must be non-empty.
+ Item top() const { return _data[_min].name; }
+
+ /// \brief The minimum priority.
+ ///
+ /// This function returns the minimum priority.
+ /// \pre The heap must be non-empty.
+ Prio prio() const { return _data[_min].prio; }
+
+ /// \brief The priority of the given item.
+ ///
+ /// This function returns the priority of the given item.
+ /// \param item The item.
+ /// \pre \e item must be in the heap.
+ const Prio& operator[](const Item& item) const {
+ return _data[_iim[item]].prio;
+ }
+
+ /// \brief Remove the item having minimum priority.
+ ///
+ /// This function removes the item having minimum priority.
+ /// \pre The heap must be non-empty.
+ void pop() {
+ _data[_min].in=false;
+
+ int head_child=-1;
+ if ( _data[_min].child!=-1 ) {
+ int child=_data[_min].child;
+ int neighb;
+ while( child!=-1 ) {
+ neighb=_data[child].right_neighbor;
+ _data[child].parent=-1;
+ _data[child].right_neighbor=head_child;
+ head_child=child;
+ child=neighb;
+ }
+ }
+
+ if ( _data[_head].right_neighbor==-1 ) {
+ // there was only one root
+ _head=head_child;
+ }
+ else {
+ // there were more roots
+ if( _head!=_min ) { unlace(_min); }
+ else { _head=_data[_head].right_neighbor; }
+ merge(head_child);
+ }
+ _min=findMin();
+ --_num_items;
+ }
+
+ /// \brief Remove the given item from the heap.
+ ///
+ /// This function removes the given item from the heap if it is
+ /// already stored.
+ /// \param item The item to delete.
+ /// \pre \e item must be in the heap.
+ void erase (const Item& item) {
+ int i=_iim[item];
+ if ( i >= 0 && _data[i].in ) {
+ decrease( item, _data[_min].prio-1 );
+ pop();
+ }
+ }
+
+ /// \brief Decrease the priority of an item to the given value.
+ ///
+ /// This function decreases the priority of an item to the given value.
+ /// \param item The item.
+ /// \param value The priority.
+ /// \pre \e item must be stored in the heap with priority at least \e value.
+ void decrease (Item item, const Prio& value) {
+ int i=_iim[item];
+ int p=_data[i].parent;
+ _data[i].prio=value;
+
+ while( p!=-1 && _comp(value, _data[p].prio) ) {
+ _data[i].name=_data[p].name;
+ _data[i].prio=_data[p].prio;
+ _data[p].name=item;
+ _data[p].prio=value;
+ _iim[_data[i].name]=i;
+ i=p;
+ p=_data[p].parent;
+ }
+ _iim[item]=i;
+ if ( _comp(value, _data[_min].prio) ) _min=i;
+ }
+
+ /// \brief Increase the priority of an item to the given value.
+ ///
+ /// This function increases the priority of an item to the given value.
+ /// \param item The item.
+ /// \param value The priority.
+ /// \pre \e item must be stored in the heap with priority at most \e value.
+ void increase (Item item, const Prio& value) {
+ erase(item);
+ push(item, value);
+ }
+
+ /// \brief Return the state of an item.
+ ///
+ /// This method returns \c PRE_HEAP if the given item has never
+ /// been in the heap, \c IN_HEAP if it is in the heap at the moment,
+ /// and \c POST_HEAP otherwise.
+ /// In the latter case it is possible that the item will get back
+ /// to the heap again.
+ /// \param item The item.
+ State state(const Item &item) const {
+ int i=_iim[item];
+ if( i>=0 ) {
+ if ( _data[i].in ) i=0;
+ else i=-2;
+ }
+ return State(i);
+ }
+
+ /// \brief Set the state of an item in the heap.
+ ///
+ /// This function sets the state of the given item in the heap.
+ /// It can be used to manually clear the heap when it is important
+ /// to achive better time complexity.
+ /// \param i The item.
+ /// \param st The state. It should not be \c IN_HEAP.
+ void state(const Item& i, State st) {
+ switch (st) {
+ case POST_HEAP:
+ case PRE_HEAP:
+ if (state(i) == IN_HEAP) {
+ erase(i);
+ }
+ _iim[i] = st;
+ break;
+ case IN_HEAP:
+ break;
+ }
+ }
+
+ private:
+
+ // Find the minimum of the roots
+ int findMin() {
+ if( _head!=-1 ) {
+ int min_loc=_head, min_val=_data[_head].prio;
+ for( int x=_data[_head].right_neighbor; x!=-1;
+ x=_data[x].right_neighbor ) {
+ if( _comp( _data[x].prio,min_val ) ) {
+ min_val=_data[x].prio;
+ min_loc=x;
+ }
+ }
+ return min_loc;
+ }
+ else return -1;
+ }
+
+ // Merge the heap with another heap starting at the given position
+ void merge(int a) {
+ if( _head==-1 || a==-1 ) return;
+ if( _data[a].right_neighbor==-1 &&
+ _data[a].degree<=_data[_head].degree ) {
+ _data[a].right_neighbor=_head;
+ _head=a;
+ } else {
+ interleave(a);
+ }
+ if( _data[_head].right_neighbor==-1 ) return;
+
+ int x=_head;
+ int x_prev=-1, x_next=_data[x].right_neighbor;
+ while( x_next!=-1 ) {
+ if( _data[x].degree!=_data[x_next].degree ||
+ ( _data[x_next].right_neighbor!=-1 &&
+ _data[_data[x_next].right_neighbor].degree==_data[x].degree ) ) {
+ x_prev=x;
+ x=x_next;
+ }
+ else {
+ if( _comp(_data[x_next].prio,_data[x].prio) ) {
+ if( x_prev==-1 ) {
+ _head=x_next;
+ } else {
+ _data[x_prev].right_neighbor=x_next;
+ }
+ fuse(x,x_next);
+ x=x_next;
+ }
+ else {
+ _data[x].right_neighbor=_data[x_next].right_neighbor;
+ fuse(x_next,x);
+ }
+ }
+ x_next=_data[x].right_neighbor;
+ }
+ }
+
+ // Interleave the elements of the given list into the list of the roots
+ void interleave(int a) {
+ int p=_head, q=a;
+ int curr=_data.size();
+ _data.push_back(Store());
+
+ while( p!=-1 || q!=-1 ) {
+ if( q==-1 || ( p!=-1 && _data[p].degree<_data[q].degree ) ) {
+ _data[curr].right_neighbor=p;
+ curr=p;
+ p=_data[p].right_neighbor;
+ }
+ else {
+ _data[curr].right_neighbor=q;
+ curr=q;
+ q=_data[q].right_neighbor;
+ }
+ }
+
+ _head=_data.back().right_neighbor;
+ _data.pop_back();
+ }
+
+ // Lace node a under node b
+ void fuse(int a, int b) {
+ _data[a].parent=b;
+ _data[a].right_neighbor=_data[b].child;
+ _data[b].child=a;
+
+ ++_data[b].degree;
+ }
+
+ // Unlace node a (if it has siblings)
+ void unlace(int a) {
+ int neighb=_data[a].right_neighbor;
+ int other=_head;
+
+ while( _data[other].right_neighbor!=a )
+ other=_data[other].right_neighbor;
+ _data[other].right_neighbor=neighb;
+ }
+
+ private:
+
+ class Store {
+ friend class BinomialHeap;
+
+ Item name;
+ int parent;
+ int right_neighbor;
+ int child;
+ int degree;
+ bool in;
+ Prio prio;
+
+ Store() : parent(-1), right_neighbor(-1), child(-1), degree(0),
+ in(true) {}
+ };
+ };
+
+} //namespace lemon
+
+#endif //LEMON_BINOMIAL_HEAP_H
+
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/alteration_notifier.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/alteration_notifier.h
new file mode 100644
index 00000000000..d14fe3634dd
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/alteration_notifier.h
@@ -0,0 +1,472 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_BITS_ALTERATION_NOTIFIER_H
+#define LEMON_BITS_ALTERATION_NOTIFIER_H
+
+#include <vector>
+#include <list>
+
+#include <lemon/core.h>
+#include <lemon/bits/lock.h>
+
+//\ingroup graphbits
+//\file
+//\brief Observer notifier for graph alteration observers.
+
+namespace lemon {
+
+ // \ingroup graphbits
+ //
+ // \brief Notifier class to notify observes about alterations in
+ // a container.
+ //
+ // The simple graphs can be refered as two containers: a node container
+ // and an edge container. But they do not store values directly, they
+ // are just key continars for more value containers, which are the
+ // node and edge maps.
+ //
+ // The node and edge sets of the graphs can be changed as we add or erase
+ // nodes and edges in the graph. LEMON would like to handle easily
+ // that the node and edge maps should contain values for all nodes or
+ // edges. If we want to check on every indicing if the map contains
+ // the current indicing key that cause a drawback in the performance
+ // in the library. We use another solution: we notify all maps about
+ // an alteration in the graph, which cause only drawback on the
+ // alteration of the graph.
+ //
+ // This class provides an interface to a node or edge container.
+ // The first() and next() member functions make possible
+ // to iterate on the keys of the container.
+ // The id() function returns an integer id for each key.
+ // The maxId() function gives back an upper bound of the ids.
+ //
+ // For the proper functonality of this class, we should notify it
+ // about each alteration in the container. The alterations have four type:
+ // add(), erase(), build() and clear(). The add() and
+ // erase() signal that only one or few items added or erased to or
+ // from the graph. If all items are erased from the graph or if a new graph
+ // is built from an empty graph, then it can be signaled with the
+ // clear() and build() members. Important rule that if we erase items
+ // from graphs we should first signal the alteration and after that erase
+ // them from the container, on the other way on item addition we should
+ // first extend the container and just after that signal the alteration.
+ //
+ // The alteration can be observed with a class inherited from the
+ // ObserverBase nested class. The signals can be handled with
+ // overriding the virtual functions defined in the base class. The
+ // observer base can be attached to the notifier with the
+ // attach() member and can be detached with detach() function. The
+ // alteration handlers should not call any function which signals
+ // an other alteration in the same notifier and should not
+ // detach any observer from the notifier.
+ //
+ // Alteration observers try to be exception safe. If an add() or
+ // a clear() function throws an exception then the remaining
+ // observeres will not be notified and the fulfilled additions will
+ // be rolled back by calling the erase() or clear() functions.
+ // Hence erase() and clear() should not throw exception.
+ // Actullay, they can throw only \ref ImmediateDetach exception,
+ // which detach the observer from the notifier.
+ //
+ // There are some cases, when the alteration observing is not completly
+ // reliable. If we want to carry out the node degree in the graph
+ // as in the \ref InDegMap and we use the reverseArc(), then it cause
+ // unreliable functionality. Because the alteration observing signals
+ // only erasing and adding but not the reversing, it will stores bad
+ // degrees. Apart form that the subgraph adaptors cannot even signal
+ // the alterations because just a setting in the filter map can modify
+ // the graph and this cannot be watched in any way.
+ //
+ // \param _Container The container which is observed.
+ // \param _Item The item type which is obserbved.
+
+ template <typename _Container, typename _Item>
+ class AlterationNotifier {
+ public:
+
+ typedef True Notifier;
+
+ typedef _Container Container;
+ typedef _Item Item;
+
+ // \brief Exception which can be called from clear() and
+ // erase().
+ //
+ // From the clear() and erase() function only this
+ // exception is allowed to throw. The exception immediatly
+ // detaches the current observer from the notifier. Because the
+ // clear() and erase() should not throw other exceptions
+ // it can be used to invalidate the observer.
+ struct ImmediateDetach {};
+
+ // \brief ObserverBase is the base class for the observers.
+ //
+ // ObserverBase is the abstract base class for the observers.
+ // It will be notified about an item was inserted into or
+ // erased from the graph.
+ //
+ // The observer interface contains some pure virtual functions
+ // to override. The add() and erase() functions are
+ // to notify the oberver when one item is added or erased.
+ //
+ // The build() and clear() members are to notify the observer
+ // about the container is built from an empty container or
+ // is cleared to an empty container.
+ class ObserverBase {
+ protected:
+ typedef AlterationNotifier Notifier;
+
+ friend class AlterationNotifier;
+
+ // \brief Default constructor.
+ //
+ // Default constructor for ObserverBase.
+ ObserverBase() : _notifier(0) {}
+
+ // \brief Constructor which attach the observer into notifier.
+ //
+ // Constructor which attach the observer into notifier.
+ ObserverBase(AlterationNotifier& nf) {
+ attach(nf);
+ }
+
+ // \brief Constructor which attach the obserever to the same notifier.
+ //
+ // Constructor which attach the obserever to the same notifier as
+ // the other observer is attached to.
+ ObserverBase(const ObserverBase& copy) {
+ if (copy.attached()) {
+ attach(*copy.notifier());
+ }
+ }
+
+ // \brief Destructor
+ virtual ~ObserverBase() {
+ if (attached()) {
+ detach();
+ }
+ }
+
+ // \brief Attaches the observer into an AlterationNotifier.
+ //
+ // This member attaches the observer into an AlterationNotifier.
+ void attach(AlterationNotifier& nf) {
+ nf.attach(*this);
+ }
+
+ // \brief Detaches the observer into an AlterationNotifier.
+ //
+ // This member detaches the observer from an AlterationNotifier.
+ void detach() {
+ _notifier->detach(*this);
+ }
+
+ // \brief Gives back a pointer to the notifier which the map
+ // attached into.
+ //
+ // This function gives back a pointer to the notifier which the map
+ // attached into.
+ Notifier* notifier() const { return const_cast<Notifier*>(_notifier); }
+
+ // Gives back true when the observer is attached into a notifier.
+ bool attached() const { return _notifier != 0; }
+
+ private:
+
+ ObserverBase& operator=(const ObserverBase& copy);
+
+ protected:
+
+ Notifier* _notifier;
+ typename std::list<ObserverBase*>::iterator _index;
+
+ // \brief The member function to notificate the observer about an
+ // item is added to the container.
+ //
+ // The add() member function notificates the observer about an item
+ // is added to the container. It have to be overrided in the
+ // subclasses.
+ virtual void add(const Item&) = 0;
+
+ // \brief The member function to notificate the observer about
+ // more item is added to the container.
+ //
+ // The add() member function notificates the observer about more item
+ // is added to the container. It have to be overrided in the
+ // subclasses.
+ virtual void add(const std::vector<Item>& items) = 0;
+
+ // \brief The member function to notificate the observer about an
+ // item is erased from the container.
+ //
+ // The erase() member function notificates the observer about an
+ // item is erased from the container. It have to be overrided in
+ // the subclasses.
+ virtual void erase(const Item&) = 0;
+
+ // \brief The member function to notificate the observer about
+ // more item is erased from the container.
+ //
+ // The erase() member function notificates the observer about more item
+ // is erased from the container. It have to be overrided in the
+ // subclasses.
+ virtual void erase(const std::vector<Item>& items) = 0;
+
+ // \brief The member function to notificate the observer about the
+ // container is built.
+ //
+ // The build() member function notificates the observer about the
+ // container is built from an empty container. It have to be
+ // overrided in the subclasses.
+ virtual void build() = 0;
+
+ // \brief The member function to notificate the observer about all
+ // items are erased from the container.
+ //
+ // The clear() member function notificates the observer about all
+ // items are erased from the container. It have to be overrided in
+ // the subclasses.
+ virtual void clear() = 0;
+
+ };
+
+ protected:
+
+ const Container* container;
+
+ typedef std::list<ObserverBase*> Observers;
+ Observers _observers;
+ lemon::bits::Lock _lock;
+
+ public:
+
+ // \brief Default constructor.
+ //
+ // The default constructor of the AlterationNotifier.
+ // It creates an empty notifier.
+ AlterationNotifier()
+ : container(0) {}
+
+ // \brief Constructor.
+ //
+ // Constructor with the observed container parameter.
+ AlterationNotifier(const Container& _container)
+ : container(&_container) {}
+
+ // \brief Copy Constructor of the AlterationNotifier.
+ //
+ // Copy constructor of the AlterationNotifier.
+ // It creates only an empty notifier because the copiable
+ // notifier's observers have to be registered still into that notifier.
+ AlterationNotifier(const AlterationNotifier& _notifier)
+ : container(_notifier.container) {}
+
+ // \brief Destructor.
+ //
+ // Destructor of the AlterationNotifier.
+ ~AlterationNotifier() {
+ typename Observers::iterator it;
+ for (it = _observers.begin(); it != _observers.end(); ++it) {
+ (*it)->_notifier = 0;
+ }
+ }
+
+ // \brief Sets the container.
+ //
+ // Sets the container.
+ void setContainer(const Container& _container) {
+ container = &_container;
+ }
+
+ protected:
+
+ AlterationNotifier& operator=(const AlterationNotifier&);
+
+ public:
+
+ // \brief First item in the container.
+ //
+ // Returns the first item in the container. It is
+ // for start the iteration on the container.
+ void first(Item& item) const {
+ container->first(item);
+ }
+
+ // \brief Next item in the container.
+ //
+ // Returns the next item in the container. It is
+ // for iterate on the container.
+ void next(Item& item) const {
+ container->next(item);
+ }
+
+ // \brief Returns the id of the item.
+ //
+ // Returns the id of the item provided by the container.
+ int id(const Item& item) const {
+ return container->id(item);
+ }
+
+ // \brief Returns the maximum id of the container.
+ //
+ // Returns the maximum id of the container.
+ int maxId() const {
+ return container->maxId(Item());
+ }
+
+ protected:
+
+ void attach(ObserverBase& observer) {
+ _lock.lock();
+ observer._index = _observers.insert(_observers.begin(), &observer);
+ observer._notifier = this;
+ _lock.unlock();
+ }
+
+ void detach(ObserverBase& observer) {
+ _lock.lock();
+ _observers.erase(observer._index);
+ observer._index = _observers.end();
+ observer._notifier = 0;
+ _lock.unlock();
+ }
+
+ public:
+
+ // \brief Notifies all the registed observers about an item added to
+ // the container.
+ //
+ // It notifies all the registed observers about an item added to
+ // the container.
+ void add(const Item& item) {
+ typename Observers::reverse_iterator it;
+ try {
+ for (it = _observers.rbegin(); it != _observers.rend(); ++it) {
+ (*it)->add(item);
+ }
+ } catch (...) {
+ typename Observers::iterator jt;
+ for (jt = it.base(); jt != _observers.end(); ++jt) {
+ (*jt)->erase(item);
+ }
+ throw;
+ }
+ }
+
+ // \brief Notifies all the registed observers about more item added to
+ // the container.
+ //
+ // It notifies all the registed observers about more item added to
+ // the container.
+ void add(const std::vector<Item>& items) {
+ typename Observers::reverse_iterator it;
+ try {
+ for (it = _observers.rbegin(); it != _observers.rend(); ++it) {
+ (*it)->add(items);
+ }
+ } catch (...) {
+ typename Observers::iterator jt;
+ for (jt = it.base(); jt != _observers.end(); ++jt) {
+ (*jt)->erase(items);
+ }
+ throw;
+ }
+ }
+
+ // \brief Notifies all the registed observers about an item erased from
+ // the container.
+ //
+ // It notifies all the registed observers about an item erased from
+ // the container.
+ void erase(const Item& item) throw() {
+ typename Observers::iterator it = _observers.begin();
+ while (it != _observers.end()) {
+ try {
+ (*it)->erase(item);
+ ++it;
+ } catch (const ImmediateDetach&) {
+ (*it)->_index = _observers.end();
+ (*it)->_notifier = 0;
+ it = _observers.erase(it);
+ }
+ }
+ }
+
+ // \brief Notifies all the registed observers about more item erased
+ // from the container.
+ //
+ // It notifies all the registed observers about more item erased from
+ // the container.
+ void erase(const std::vector<Item>& items) {
+ typename Observers::iterator it = _observers.begin();
+ while (it != _observers.end()) {
+ try {
+ (*it)->erase(items);
+ ++it;
+ } catch (const ImmediateDetach&) {
+ (*it)->_index = _observers.end();
+ (*it)->_notifier = 0;
+ it = _observers.erase(it);
+ }
+ }
+ }
+
+ // \brief Notifies all the registed observers about the container is
+ // built.
+ //
+ // Notifies all the registed observers about the container is built
+ // from an empty container.
+ void build() {
+ typename Observers::reverse_iterator it;
+ try {
+ for (it = _observers.rbegin(); it != _observers.rend(); ++it) {
+ (*it)->build();
+ }
+ } catch (...) {
+ typename Observers::iterator jt;
+ for (jt = it.base(); jt != _observers.end(); ++jt) {
+ (*jt)->clear();
+ }
+ throw;
+ }
+ }
+
+ // \brief Notifies all the registed observers about all items are
+ // erased.
+ //
+ // Notifies all the registed observers about all items are erased
+ // from the container.
+ void clear() {
+ typename Observers::iterator it = _observers.begin();
+ while (it != _observers.end()) {
+ try {
+ (*it)->clear();
+ ++it;
+ } catch (const ImmediateDetach&) {
+ (*it)->_index = _observers.end();
+ (*it)->_notifier = 0;
+ it = _observers.erase(it);
+ }
+ }
+ }
+ };
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/array_map.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/array_map.h
new file mode 100644
index 00000000000..355ee008246
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/array_map.h
@@ -0,0 +1,351 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_BITS_ARRAY_MAP_H
+#define LEMON_BITS_ARRAY_MAP_H
+
+#include <memory>
+
+#include <lemon/bits/traits.h>
+#include <lemon/bits/alteration_notifier.h>
+#include <lemon/concept_check.h>
+#include <lemon/concepts/maps.h>
+
+// \ingroup graphbits
+// \file
+// \brief Graph map based on the array storage.
+
+namespace lemon {
+
+ // \ingroup graphbits
+ //
+ // \brief Graph map based on the array storage.
+ //
+ // The ArrayMap template class is graph map structure that automatically
+ // updates the map when a key is added to or erased from the graph.
+ // This map uses the allocators to implement the container functionality.
+ //
+ // The template parameters are the Graph, the current Item type and
+ // the Value type of the map.
+ template <typename _Graph, typename _Item, typename _Value>
+ class ArrayMap
+ : public ItemSetTraits<_Graph, _Item>::ItemNotifier::ObserverBase {
+ public:
+ // The graph type.
+ typedef _Graph GraphType;
+ // The item type.
+ typedef _Item Item;
+ // The reference map tag.
+ typedef True ReferenceMapTag;
+
+ // The key type of the map.
+ typedef _Item Key;
+ // The value type of the map.
+ typedef _Value Value;
+
+ // The const reference type of the map.
+ typedef const _Value& ConstReference;
+ // The reference type of the map.
+ typedef _Value& Reference;
+
+ // The map type.
+ typedef ArrayMap Map;
+
+ // The notifier type.
+ typedef typename ItemSetTraits<_Graph, _Item>::ItemNotifier Notifier;
+
+ private:
+
+ // The MapBase of the Map which imlements the core regisitry function.
+ typedef typename Notifier::ObserverBase Parent;
+
+ typedef std::allocator<Value> Allocator;
+
+ public:
+
+ // \brief Graph initialized map constructor.
+ //
+ // Graph initialized map constructor.
+ explicit ArrayMap(const GraphType& graph) {
+ Parent::attach(graph.notifier(Item()));
+ allocate_memory();
+ Notifier* nf = Parent::notifier();
+ Item it;
+ for (nf->first(it); it != INVALID; nf->next(it)) {
+ int id = nf->id(it);;
+ allocator.construct(&(values[id]), Value());
+ }
+ }
+
+ // \brief Constructor to use default value to initialize the map.
+ //
+ // It constructs a map and initialize all of the the map.
+ ArrayMap(const GraphType& graph, const Value& value) {
+ Parent::attach(graph.notifier(Item()));
+ allocate_memory();
+ Notifier* nf = Parent::notifier();
+ Item it;
+ for (nf->first(it); it != INVALID; nf->next(it)) {
+ int id = nf->id(it);;
+ allocator.construct(&(values[id]), value);
+ }
+ }
+
+ private:
+ // \brief Constructor to copy a map of the same map type.
+ //
+ // Constructor to copy a map of the same map type.
+ ArrayMap(const ArrayMap& copy) : Parent() {
+ if (copy.attached()) {
+ attach(*copy.notifier());
+ }
+ capacity = copy.capacity;
+ if (capacity == 0) return;
+ values = allocator.allocate(capacity);
+ Notifier* nf = Parent::notifier();
+ Item it;
+ for (nf->first(it); it != INVALID; nf->next(it)) {
+ int id = nf->id(it);;
+ allocator.construct(&(values[id]), copy.values[id]);
+ }
+ }
+
+ // \brief Assign operator.
+ //
+ // This operator assigns for each item in the map the
+ // value mapped to the same item in the copied map.
+ // The parameter map should be indiced with the same
+ // itemset because this assign operator does not change
+ // the container of the map.
+ ArrayMap& operator=(const ArrayMap& cmap) {
+ return operator=<ArrayMap>(cmap);
+ }
+
+
+ // \brief Template assign operator.
+ //
+ // The given parameter should conform to the ReadMap
+ // concecpt and could be indiced by the current item set of
+ // the NodeMap. In this case the value for each item
+ // is assigned by the value of the given ReadMap.
+ template <typename CMap>
+ ArrayMap& operator=(const CMap& cmap) {
+ checkConcept<concepts::ReadMap<Key, _Value>, CMap>();
+ const typename Parent::Notifier* nf = Parent::notifier();
+ Item it;
+ for (nf->first(it); it != INVALID; nf->next(it)) {
+ set(it, cmap[it]);
+ }
+ return *this;
+ }
+
+ public:
+ // \brief The destructor of the map.
+ //
+ // The destructor of the map.
+ virtual ~ArrayMap() {
+ if (attached()) {
+ clear();
+ detach();
+ }
+ }
+
+ protected:
+
+ using Parent::attach;
+ using Parent::detach;
+ using Parent::attached;
+
+ public:
+
+ // \brief The subscript operator.
+ //
+ // The subscript operator. The map can be subscripted by the
+ // actual keys of the graph.
+ Value& operator[](const Key& key) {
+ int id = Parent::notifier()->id(key);
+ return values[id];
+ }
+
+ // \brief The const subscript operator.
+ //
+ // The const subscript operator. The map can be subscripted by the
+ // actual keys of the graph.
+ const Value& operator[](const Key& key) const {
+ int id = Parent::notifier()->id(key);
+ return values[id];
+ }
+
+ // \brief Setter function of the map.
+ //
+ // Setter function of the map. Equivalent with map[key] = val.
+ // This is a compatibility feature with the not dereferable maps.
+ void set(const Key& key, const Value& val) {
+ (*this)[key] = val;
+ }
+
+ protected:
+
+ // \brief Adds a new key to the map.
+ //
+ // It adds a new key to the map. It is called by the observer notifier
+ // and it overrides the add() member function of the observer base.
+ virtual void add(const Key& key) {
+ Notifier* nf = Parent::notifier();
+ int id = nf->id(key);
+ if (id >= capacity) {
+ int new_capacity = (capacity == 0 ? 1 : capacity);
+ while (new_capacity <= id) {
+ new_capacity <<= 1;
+ }
+ Value* new_values = allocator.allocate(new_capacity);
+ Item it;
+ for (nf->first(it); it != INVALID; nf->next(it)) {
+ int jd = nf->id(it);;
+ if (id != jd) {
+ allocator.construct(&(new_values[jd]), values[jd]);
+ allocator.destroy(&(values[jd]));
+ }
+ }
+ if (capacity != 0) allocator.deallocate(values, capacity);
+ values = new_values;
+ capacity = new_capacity;
+ }
+ allocator.construct(&(values[id]), Value());
+ }
+
+ // \brief Adds more new keys to the map.
+ //
+ // It adds more new keys to the map. It is called by the observer notifier
+ // and it overrides the add() member function of the observer base.
+ virtual void add(const std::vector<Key>& keys) {
+ Notifier* nf = Parent::notifier();
+ int max_id = -1;
+ for (int i = 0; i < int(keys.size()); ++i) {
+ int id = nf->id(keys[i]);
+ if (id > max_id) {
+ max_id = id;
+ }
+ }
+ if (max_id >= capacity) {
+ int new_capacity = (capacity == 0 ? 1 : capacity);
+ while (new_capacity <= max_id) {
+ new_capacity <<= 1;
+ }
+ Value* new_values = allocator.allocate(new_capacity);
+ Item it;
+ for (nf->first(it); it != INVALID; nf->next(it)) {
+ int id = nf->id(it);
+ bool found = false;
+ for (int i = 0; i < int(keys.size()); ++i) {
+ int jd = nf->id(keys[i]);
+ if (id == jd) {
+ found = true;
+ break;
+ }
+ }
+ if (found) continue;
+ allocator.construct(&(new_values[id]), values[id]);
+ allocator.destroy(&(values[id]));
+ }
+ if (capacity != 0) allocator.deallocate(values, capacity);
+ values = new_values;
+ capacity = new_capacity;
+ }
+ for (int i = 0; i < int(keys.size()); ++i) {
+ int id = nf->id(keys[i]);
+ allocator.construct(&(values[id]), Value());
+ }
+ }
+
+ // \brief Erase a key from the map.
+ //
+ // Erase a key from the map. It is called by the observer notifier
+ // and it overrides the erase() member function of the observer base.
+ virtual void erase(const Key& key) {
+ int id = Parent::notifier()->id(key);
+ allocator.destroy(&(values[id]));
+ }
+
+ // \brief Erase more keys from the map.
+ //
+ // Erase more keys from the map. It is called by the observer notifier
+ // and it overrides the erase() member function of the observer base.
+ virtual void erase(const std::vector<Key>& keys) {
+ for (int i = 0; i < int(keys.size()); ++i) {
+ int id = Parent::notifier()->id(keys[i]);
+ allocator.destroy(&(values[id]));
+ }
+ }
+
+ // \brief Builds the map.
+ //
+ // It builds the map. It is called by the observer notifier
+ // and it overrides the build() member function of the observer base.
+ virtual void build() {
+ Notifier* nf = Parent::notifier();
+ allocate_memory();
+ Item it;
+ for (nf->first(it); it != INVALID; nf->next(it)) {
+ int id = nf->id(it);;
+ allocator.construct(&(values[id]), Value());
+ }
+ }
+
+ // \brief Clear the map.
+ //
+ // It erase all items from the map. It is called by the observer notifier
+ // and it overrides the clear() member function of the observer base.
+ virtual void clear() {
+ Notifier* nf = Parent::notifier();
+ if (capacity != 0) {
+ Item it;
+ for (nf->first(it); it != INVALID; nf->next(it)) {
+ int id = nf->id(it);
+ allocator.destroy(&(values[id]));
+ }
+ allocator.deallocate(values, capacity);
+ capacity = 0;
+ }
+ }
+
+ private:
+
+ void allocate_memory() {
+ int max_id = Parent::notifier()->maxId();
+ if (max_id == -1) {
+ capacity = 0;
+ values = 0;
+ return;
+ }
+ capacity = 1;
+ while (capacity <= max_id) {
+ capacity <<= 1;
+ }
+ values = allocator.allocate(capacity);
+ }
+
+ int capacity;
+ Value* values;
+ Allocator allocator;
+
+ };
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/bezier.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/bezier.h
new file mode 100644
index 00000000000..9d8d1413d07
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/bezier.h
@@ -0,0 +1,174 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_BEZIER_H
+#define LEMON_BEZIER_H
+
+//\ingroup misc
+//\file
+//\brief Classes to compute with Bezier curves.
+//
+//Up to now this file is used internally by \ref graph_to_eps.h
+
+#include<lemon/dim2.h>
+
+namespace lemon {
+ namespace dim2 {
+
+class BezierBase {
+public:
+ typedef lemon::dim2::Point<double> Point;
+protected:
+ static Point conv(Point x,Point y,double t) {return (1-t)*x+t*y;}
+};
+
+class Bezier1 : public BezierBase
+{
+public:
+ Point p1,p2;
+
+ Bezier1() {}
+ Bezier1(Point _p1, Point _p2) :p1(_p1), p2(_p2) {}
+
+ Point operator()(double t) const
+ {
+ // return conv(conv(p1,p2,t),conv(p2,p3,t),t);
+ return conv(p1,p2,t);
+ }
+ Bezier1 before(double t) const
+ {
+ return Bezier1(p1,conv(p1,p2,t));
+ }
+
+ Bezier1 after(double t) const
+ {
+ return Bezier1(conv(p1,p2,t),p2);
+ }
+
+ Bezier1 revert() const { return Bezier1(p2,p1);}
+ Bezier1 operator()(double a,double b) const { return before(b).after(a/b); }
+ Point grad() const { return p2-p1; }
+ Point norm() const { return rot90(p2-p1); }
+ Point grad(double) const { return grad(); }
+ Point norm(double t) const { return rot90(grad(t)); }
+};
+
+class Bezier2 : public BezierBase
+{
+public:
+ Point p1,p2,p3;
+
+ Bezier2() {}
+ Bezier2(Point _p1, Point _p2, Point _p3) :p1(_p1), p2(_p2), p3(_p3) {}
+ Bezier2(const Bezier1 &b) : p1(b.p1), p2(conv(b.p1,b.p2,.5)), p3(b.p2) {}
+ Point operator()(double t) const
+ {
+ // return conv(conv(p1,p2,t),conv(p2,p3,t),t);
+ return ((1-t)*(1-t))*p1+(2*(1-t)*t)*p2+(t*t)*p3;
+ }
+ Bezier2 before(double t) const
+ {
+ Point q(conv(p1,p2,t));
+ Point r(conv(p2,p3,t));
+ return Bezier2(p1,q,conv(q,r,t));
+ }
+
+ Bezier2 after(double t) const
+ {
+ Point q(conv(p1,p2,t));
+ Point r(conv(p2,p3,t));
+ return Bezier2(conv(q,r,t),r,p3);
+ }
+ Bezier2 revert() const { return Bezier2(p3,p2,p1);}
+ Bezier2 operator()(double a,double b) const { return before(b).after(a/b); }
+ Bezier1 grad() const { return Bezier1(2.0*(p2-p1),2.0*(p3-p2)); }
+ Bezier1 norm() const { return Bezier1(2.0*rot90(p2-p1),2.0*rot90(p3-p2)); }
+ Point grad(double t) const { return grad()(t); }
+ Point norm(double t) const { return rot90(grad(t)); }
+};
+
+class Bezier3 : public BezierBase
+{
+public:
+ Point p1,p2,p3,p4;
+
+ Bezier3() {}
+ Bezier3(Point _p1, Point _p2, Point _p3, Point _p4)
+ : p1(_p1), p2(_p2), p3(_p3), p4(_p4) {}
+ Bezier3(const Bezier1 &b) : p1(b.p1), p2(conv(b.p1,b.p2,1.0/3.0)),
+ p3(conv(b.p1,b.p2,2.0/3.0)), p4(b.p2) {}
+ Bezier3(const Bezier2 &b) : p1(b.p1), p2(conv(b.p1,b.p2,2.0/3.0)),
+ p3(conv(b.p2,b.p3,1.0/3.0)), p4(b.p3) {}
+
+ Point operator()(double t) const
+ {
+ // return Bezier2(conv(p1,p2,t),conv(p2,p3,t),conv(p3,p4,t))(t);
+ return ((1-t)*(1-t)*(1-t))*p1+(3*t*(1-t)*(1-t))*p2+
+ (3*t*t*(1-t))*p3+(t*t*t)*p4;
+ }
+ Bezier3 before(double t) const
+ {
+ Point p(conv(p1,p2,t));
+ Point q(conv(p2,p3,t));
+ Point r(conv(p3,p4,t));
+ Point a(conv(p,q,t));
+ Point b(conv(q,r,t));
+ Point c(conv(a,b,t));
+ return Bezier3(p1,p,a,c);
+ }
+
+ Bezier3 after(double t) const
+ {
+ Point p(conv(p1,p2,t));
+ Point q(conv(p2,p3,t));
+ Point r(conv(p3,p4,t));
+ Point a(conv(p,q,t));
+ Point b(conv(q,r,t));
+ Point c(conv(a,b,t));
+ return Bezier3(c,b,r,p4);
+ }
+ Bezier3 revert() const { return Bezier3(p4,p3,p2,p1);}
+ Bezier3 operator()(double a,double b) const { return before(b).after(a/b); }
+ Bezier2 grad() const { return Bezier2(3.0*(p2-p1),3.0*(p3-p2),3.0*(p4-p3)); }
+ Bezier2 norm() const { return Bezier2(3.0*rot90(p2-p1),
+ 3.0*rot90(p3-p2),
+ 3.0*rot90(p4-p3)); }
+ Point grad(double t) const { return grad()(t); }
+ Point norm(double t) const { return rot90(grad(t)); }
+
+ template<class R,class F,class S,class D>
+ R recSplit(F &_f,const S &_s,D _d) const
+ {
+ const Point a=(p1+p2)/2;
+ const Point b=(p2+p3)/2;
+ const Point c=(p3+p4)/2;
+ const Point d=(a+b)/2;
+ const Point e=(b+c)/2;
+ // const Point f=(d+e)/2;
+ R f1=_f(Bezier3(p1,a,d,e),_d);
+ R f2=_f(Bezier3(e,d,c,p4),_d);
+ return _s(f1,f2);
+ }
+
+};
+
+
+} //END OF NAMESPACE dim2
+} //END OF NAMESPACE lemon
+
+#endif // LEMON_BEZIER_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/default_map.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/default_map.h
new file mode 100644
index 00000000000..23728e427ad
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/default_map.h
@@ -0,0 +1,182 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_BITS_DEFAULT_MAP_H
+#define LEMON_BITS_DEFAULT_MAP_H
+
+#include <lemon/config.h>
+#include <lemon/bits/array_map.h>
+#include <lemon/bits/vector_map.h>
+//#include <lemon/bits/debug_map.h>
+
+//\ingroup graphbits
+//\file
+//\brief Graph maps that construct and destruct their elements dynamically.
+
+namespace lemon {
+
+
+ //#ifndef LEMON_USE_DEBUG_MAP
+
+ template <typename _Graph, typename _Item, typename _Value>
+ struct DefaultMapSelector {
+ typedef ArrayMap<_Graph, _Item, _Value> Map;
+ };
+
+ // bool
+ template <typename _Graph, typename _Item>
+ struct DefaultMapSelector<_Graph, _Item, bool> {
+ typedef VectorMap<_Graph, _Item, bool> Map;
+ };
+
+ // char
+ template <typename _Graph, typename _Item>
+ struct DefaultMapSelector<_Graph, _Item, char> {
+ typedef VectorMap<_Graph, _Item, char> Map;
+ };
+
+ template <typename _Graph, typename _Item>
+ struct DefaultMapSelector<_Graph, _Item, signed char> {
+ typedef VectorMap<_Graph, _Item, signed char> Map;
+ };
+
+ template <typename _Graph, typename _Item>
+ struct DefaultMapSelector<_Graph, _Item, unsigned char> {
+ typedef VectorMap<_Graph, _Item, unsigned char> Map;
+ };
+
+
+ // int
+ template <typename _Graph, typename _Item>
+ struct DefaultMapSelector<_Graph, _Item, signed int> {
+ typedef VectorMap<_Graph, _Item, signed int> Map;
+ };
+
+ template <typename _Graph, typename _Item>
+ struct DefaultMapSelector<_Graph, _Item, unsigned int> {
+ typedef VectorMap<_Graph, _Item, unsigned int> Map;
+ };
+
+
+ // short
+ template <typename _Graph, typename _Item>
+ struct DefaultMapSelector<_Graph, _Item, signed short> {
+ typedef VectorMap<_Graph, _Item, signed short> Map;
+ };
+
+ template <typename _Graph, typename _Item>
+ struct DefaultMapSelector<_Graph, _Item, unsigned short> {
+ typedef VectorMap<_Graph, _Item, unsigned short> Map;
+ };
+
+
+ // long
+ template <typename _Graph, typename _Item>
+ struct DefaultMapSelector<_Graph, _Item, signed long> {
+ typedef VectorMap<_Graph, _Item, signed long> Map;
+ };
+
+ template <typename _Graph, typename _Item>
+ struct DefaultMapSelector<_Graph, _Item, unsigned long> {
+ typedef VectorMap<_Graph, _Item, unsigned long> Map;
+ };
+
+
+#if defined LEMON_HAVE_LONG_LONG
+
+ // long long
+ template <typename _Graph, typename _Item>
+ struct DefaultMapSelector<_Graph, _Item, signed long long> {
+ typedef VectorMap<_Graph, _Item, signed long long> Map;
+ };
+
+ template <typename _Graph, typename _Item>
+ struct DefaultMapSelector<_Graph, _Item, unsigned long long> {
+ typedef VectorMap<_Graph, _Item, unsigned long long> Map;
+ };
+
+#endif
+
+
+ // float
+ template <typename _Graph, typename _Item>
+ struct DefaultMapSelector<_Graph, _Item, float> {
+ typedef VectorMap<_Graph, _Item, float> Map;
+ };
+
+
+ // double
+ template <typename _Graph, typename _Item>
+ struct DefaultMapSelector<_Graph, _Item, double> {
+ typedef VectorMap<_Graph, _Item, double> Map;
+ };
+
+
+ // long double
+ template <typename _Graph, typename _Item>
+ struct DefaultMapSelector<_Graph, _Item, long double> {
+ typedef VectorMap<_Graph, _Item, long double> Map;
+ };
+
+
+ // pointer
+ template <typename _Graph, typename _Item, typename _Ptr>
+ struct DefaultMapSelector<_Graph, _Item, _Ptr*> {
+ typedef VectorMap<_Graph, _Item, _Ptr*> Map;
+ };
+
+// #else
+
+// template <typename _Graph, typename _Item, typename _Value>
+// struct DefaultMapSelector {
+// typedef DebugMap<_Graph, _Item, _Value> Map;
+// };
+
+// #endif
+
+ // DefaultMap class
+ template <typename _Graph, typename _Item, typename _Value>
+ class DefaultMap
+ : public DefaultMapSelector<_Graph, _Item, _Value>::Map {
+ typedef typename DefaultMapSelector<_Graph, _Item, _Value>::Map Parent;
+
+ public:
+ typedef DefaultMap<_Graph, _Item, _Value> Map;
+
+ typedef typename Parent::GraphType GraphType;
+ typedef typename Parent::Value Value;
+
+ explicit DefaultMap(const GraphType& graph) : Parent(graph) {}
+ DefaultMap(const GraphType& graph, const Value& value)
+ : Parent(graph, value) {}
+
+ DefaultMap& operator=(const DefaultMap& cmap) {
+ return operator=<DefaultMap>(cmap);
+ }
+
+ template <typename CMap>
+ DefaultMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+
+ };
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/edge_set_extender.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/edge_set_extender.h
new file mode 100644
index 00000000000..364ca2ee6a9
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/edge_set_extender.h
@@ -0,0 +1,627 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_BITS_EDGE_SET_EXTENDER_H
+#define LEMON_BITS_EDGE_SET_EXTENDER_H
+
+#include <lemon/core.h>
+#include <lemon/error.h>
+#include <lemon/bits/default_map.h>
+#include <lemon/bits/map_extender.h>
+
+//\ingroup digraphbits
+//\file
+//\brief Extenders for the arc set types
+namespace lemon {
+
+ // \ingroup digraphbits
+ //
+ // \brief Extender for the ArcSets
+ template <typename Base>
+ class ArcSetExtender : public Base {
+ typedef Base Parent;
+
+ public:
+
+ typedef ArcSetExtender Digraph;
+
+ // Base extensions
+
+ typedef typename Parent::Node Node;
+ typedef typename Parent::Arc Arc;
+
+ int maxId(Node) const {
+ return Parent::maxNodeId();
+ }
+
+ int maxId(Arc) const {
+ return Parent::maxArcId();
+ }
+
+ Node fromId(int id, Node) const {
+ return Parent::nodeFromId(id);
+ }
+
+ Arc fromId(int id, Arc) const {
+ return Parent::arcFromId(id);
+ }
+
+ Node oppositeNode(const Node &n, const Arc &e) const {
+ if (n == Parent::source(e))
+ return Parent::target(e);
+ else if(n==Parent::target(e))
+ return Parent::source(e);
+ else
+ return INVALID;
+ }
+
+
+ // Alteration notifier extensions
+
+ // The arc observer registry.
+ typedef AlterationNotifier<ArcSetExtender, Arc> ArcNotifier;
+
+ protected:
+
+ mutable ArcNotifier arc_notifier;
+
+ public:
+
+ using Parent::notifier;
+
+ // Gives back the arc alteration notifier.
+ ArcNotifier& notifier(Arc) const {
+ return arc_notifier;
+ }
+
+ // Iterable extensions
+
+ class NodeIt : public Node {
+ const Digraph* digraph;
+ public:
+
+ NodeIt() {}
+
+ NodeIt(Invalid i) : Node(i) { }
+
+ explicit NodeIt(const Digraph& _graph) : digraph(&_graph) {
+ _graph.first(static_cast<Node&>(*this));
+ }
+
+ NodeIt(const Digraph& _graph, const Node& node)
+ : Node(node), digraph(&_graph) {}
+
+ NodeIt& operator++() {
+ digraph->next(*this);
+ return *this;
+ }
+
+ };
+
+
+ class ArcIt : public Arc {
+ const Digraph* digraph;
+ public:
+
+ ArcIt() { }
+
+ ArcIt(Invalid i) : Arc(i) { }
+
+ explicit ArcIt(const Digraph& _graph) : digraph(&_graph) {
+ _graph.first(static_cast<Arc&>(*this));
+ }
+
+ ArcIt(const Digraph& _graph, const Arc& e) :
+ Arc(e), digraph(&_graph) { }
+
+ ArcIt& operator++() {
+ digraph->next(*this);
+ return *this;
+ }
+
+ };
+
+
+ class OutArcIt : public Arc {
+ const Digraph* digraph;
+ public:
+
+ OutArcIt() { }
+
+ OutArcIt(Invalid i) : Arc(i) { }
+
+ OutArcIt(const Digraph& _graph, const Node& node)
+ : digraph(&_graph) {
+ _graph.firstOut(*this, node);
+ }
+
+ OutArcIt(const Digraph& _graph, const Arc& arc)
+ : Arc(arc), digraph(&_graph) {}
+
+ OutArcIt& operator++() {
+ digraph->nextOut(*this);
+ return *this;
+ }
+
+ };
+
+
+ class InArcIt : public Arc {
+ const Digraph* digraph;
+ public:
+
+ InArcIt() { }
+
+ InArcIt(Invalid i) : Arc(i) { }
+
+ InArcIt(const Digraph& _graph, const Node& node)
+ : digraph(&_graph) {
+ _graph.firstIn(*this, node);
+ }
+
+ InArcIt(const Digraph& _graph, const Arc& arc) :
+ Arc(arc), digraph(&_graph) {}
+
+ InArcIt& operator++() {
+ digraph->nextIn(*this);
+ return *this;
+ }
+
+ };
+
+ // \brief Base node of the iterator
+ //
+ // Returns the base node (ie. the source in this case) of the iterator
+ Node baseNode(const OutArcIt &e) const {
+ return Parent::source(static_cast<const Arc&>(e));
+ }
+ // \brief Running node of the iterator
+ //
+ // Returns the running node (ie. the target in this case) of the
+ // iterator
+ Node runningNode(const OutArcIt &e) const {
+ return Parent::target(static_cast<const Arc&>(e));
+ }
+
+ // \brief Base node of the iterator
+ //
+ // Returns the base node (ie. the target in this case) of the iterator
+ Node baseNode(const InArcIt &e) const {
+ return Parent::target(static_cast<const Arc&>(e));
+ }
+ // \brief Running node of the iterator
+ //
+ // Returns the running node (ie. the source in this case) of the
+ // iterator
+ Node runningNode(const InArcIt &e) const {
+ return Parent::source(static_cast<const Arc&>(e));
+ }
+
+ using Parent::first;
+
+ // Mappable extension
+
+ template <typename _Value>
+ class ArcMap
+ : public MapExtender<DefaultMap<Digraph, Arc, _Value> > {
+ typedef MapExtender<DefaultMap<Digraph, Arc, _Value> > Parent;
+
+ public:
+ explicit ArcMap(const Digraph& _g)
+ : Parent(_g) {}
+ ArcMap(const Digraph& _g, const _Value& _v)
+ : Parent(_g, _v) {}
+
+ ArcMap& operator=(const ArcMap& cmap) {
+ return operator=<ArcMap>(cmap);
+ }
+
+ template <typename CMap>
+ ArcMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+
+ };
+
+
+ // Alteration extension
+
+ Arc addArc(const Node& from, const Node& to) {
+ Arc arc = Parent::addArc(from, to);
+ notifier(Arc()).add(arc);
+ return arc;
+ }
+
+ void clear() {
+ notifier(Arc()).clear();
+ Parent::clear();
+ }
+
+ void erase(const Arc& arc) {
+ notifier(Arc()).erase(arc);
+ Parent::erase(arc);
+ }
+
+ ArcSetExtender() {
+ arc_notifier.setContainer(*this);
+ }
+
+ ~ArcSetExtender() {
+ arc_notifier.clear();
+ }
+
+ };
+
+
+ // \ingroup digraphbits
+ //
+ // \brief Extender for the EdgeSets
+ template <typename Base>
+ class EdgeSetExtender : public Base {
+ typedef Base Parent;
+
+ public:
+
+ typedef EdgeSetExtender Graph;
+
+ typedef True UndirectedTag;
+
+ typedef typename Parent::Node Node;
+ typedef typename Parent::Arc Arc;
+ typedef typename Parent::Edge Edge;
+
+ int maxId(Node) const {
+ return Parent::maxNodeId();
+ }
+
+ int maxId(Arc) const {
+ return Parent::maxArcId();
+ }
+
+ int maxId(Edge) const {
+ return Parent::maxEdgeId();
+ }
+
+ Node fromId(int id, Node) const {
+ return Parent::nodeFromId(id);
+ }
+
+ Arc fromId(int id, Arc) const {
+ return Parent::arcFromId(id);
+ }
+
+ Edge fromId(int id, Edge) const {
+ return Parent::edgeFromId(id);
+ }
+
+ Node oppositeNode(const Node &n, const Edge &e) const {
+ if( n == Parent::u(e))
+ return Parent::v(e);
+ else if( n == Parent::v(e))
+ return Parent::u(e);
+ else
+ return INVALID;
+ }
+
+ Arc oppositeArc(const Arc &e) const {
+ return Parent::direct(e, !Parent::direction(e));
+ }
+
+ using Parent::direct;
+ Arc direct(const Edge &e, const Node &s) const {
+ return Parent::direct(e, Parent::u(e) == s);
+ }
+
+ typedef AlterationNotifier<EdgeSetExtender, Arc> ArcNotifier;
+ typedef AlterationNotifier<EdgeSetExtender, Edge> EdgeNotifier;
+
+
+ protected:
+
+ mutable ArcNotifier arc_notifier;
+ mutable EdgeNotifier edge_notifier;
+
+ public:
+
+ using Parent::notifier;
+
+ ArcNotifier& notifier(Arc) const {
+ return arc_notifier;
+ }
+
+ EdgeNotifier& notifier(Edge) const {
+ return edge_notifier;
+ }
+
+
+ class NodeIt : public Node {
+ const Graph* graph;
+ public:
+
+ NodeIt() {}
+
+ NodeIt(Invalid i) : Node(i) { }
+
+ explicit NodeIt(const Graph& _graph) : graph(&_graph) {
+ _graph.first(static_cast<Node&>(*this));
+ }
+
+ NodeIt(const Graph& _graph, const Node& node)
+ : Node(node), graph(&_graph) {}
+
+ NodeIt& operator++() {
+ graph->next(*this);
+ return *this;
+ }
+
+ };
+
+
+ class ArcIt : public Arc {
+ const Graph* graph;
+ public:
+
+ ArcIt() { }
+
+ ArcIt(Invalid i) : Arc(i) { }
+
+ explicit ArcIt(const Graph& _graph) : graph(&_graph) {
+ _graph.first(static_cast<Arc&>(*this));
+ }
+
+ ArcIt(const Graph& _graph, const Arc& e) :
+ Arc(e), graph(&_graph) { }
+
+ ArcIt& operator++() {
+ graph->next(*this);
+ return *this;
+ }
+
+ };
+
+
+ class OutArcIt : public Arc {
+ const Graph* graph;
+ public:
+
+ OutArcIt() { }
+
+ OutArcIt(Invalid i) : Arc(i) { }
+
+ OutArcIt(const Graph& _graph, const Node& node)
+ : graph(&_graph) {
+ _graph.firstOut(*this, node);
+ }
+
+ OutArcIt(const Graph& _graph, const Arc& arc)
+ : Arc(arc), graph(&_graph) {}
+
+ OutArcIt& operator++() {
+ graph->nextOut(*this);
+ return *this;
+ }
+
+ };
+
+
+ class InArcIt : public Arc {
+ const Graph* graph;
+ public:
+
+ InArcIt() { }
+
+ InArcIt(Invalid i) : Arc(i) { }
+
+ InArcIt(const Graph& _graph, const Node& node)
+ : graph(&_graph) {
+ _graph.firstIn(*this, node);
+ }
+
+ InArcIt(const Graph& _graph, const Arc& arc) :
+ Arc(arc), graph(&_graph) {}
+
+ InArcIt& operator++() {
+ graph->nextIn(*this);
+ return *this;
+ }
+
+ };
+
+
+ class EdgeIt : public Parent::Edge {
+ const Graph* graph;
+ public:
+
+ EdgeIt() { }
+
+ EdgeIt(Invalid i) : Edge(i) { }
+
+ explicit EdgeIt(const Graph& _graph) : graph(&_graph) {
+ _graph.first(static_cast<Edge&>(*this));
+ }
+
+ EdgeIt(const Graph& _graph, const Edge& e) :
+ Edge(e), graph(&_graph) { }
+
+ EdgeIt& operator++() {
+ graph->next(*this);
+ return *this;
+ }
+
+ };
+
+ class IncEdgeIt : public Parent::Edge {
+ friend class EdgeSetExtender;
+ const Graph* graph;
+ bool direction;
+ public:
+
+ IncEdgeIt() { }
+
+ IncEdgeIt(Invalid i) : Edge(i), direction(false) { }
+
+ IncEdgeIt(const Graph& _graph, const Node &n) : graph(&_graph) {
+ _graph.firstInc(*this, direction, n);
+ }
+
+ IncEdgeIt(const Graph& _graph, const Edge &ue, const Node &n)
+ : graph(&_graph), Edge(ue) {
+ direction = (_graph.source(ue) == n);
+ }
+
+ IncEdgeIt& operator++() {
+ graph->nextInc(*this, direction);
+ return *this;
+ }
+ };
+
+ // \brief Base node of the iterator
+ //
+ // Returns the base node (ie. the source in this case) of the iterator
+ Node baseNode(const OutArcIt &e) const {
+ return Parent::source(static_cast<const Arc&>(e));
+ }
+ // \brief Running node of the iterator
+ //
+ // Returns the running node (ie. the target in this case) of the
+ // iterator
+ Node runningNode(const OutArcIt &e) const {
+ return Parent::target(static_cast<const Arc&>(e));
+ }
+
+ // \brief Base node of the iterator
+ //
+ // Returns the base node (ie. the target in this case) of the iterator
+ Node baseNode(const InArcIt &e) const {
+ return Parent::target(static_cast<const Arc&>(e));
+ }
+ // \brief Running node of the iterator
+ //
+ // Returns the running node (ie. the source in this case) of the
+ // iterator
+ Node runningNode(const InArcIt &e) const {
+ return Parent::source(static_cast<const Arc&>(e));
+ }
+
+ // Base node of the iterator
+ //
+ // Returns the base node of the iterator
+ Node baseNode(const IncEdgeIt &e) const {
+ return e.direction ? this->u(e) : this->v(e);
+ }
+ // Running node of the iterator
+ //
+ // Returns the running node of the iterator
+ Node runningNode(const IncEdgeIt &e) const {
+ return e.direction ? this->v(e) : this->u(e);
+ }
+
+
+ template <typename _Value>
+ class ArcMap
+ : public MapExtender<DefaultMap<Graph, Arc, _Value> > {
+ typedef MapExtender<DefaultMap<Graph, Arc, _Value> > Parent;
+
+ public:
+ explicit ArcMap(const Graph& _g)
+ : Parent(_g) {}
+ ArcMap(const Graph& _g, const _Value& _v)
+ : Parent(_g, _v) {}
+
+ ArcMap& operator=(const ArcMap& cmap) {
+ return operator=<ArcMap>(cmap);
+ }
+
+ template <typename CMap>
+ ArcMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+
+ };
+
+
+ template <typename _Value>
+ class EdgeMap
+ : public MapExtender<DefaultMap<Graph, Edge, _Value> > {
+ typedef MapExtender<DefaultMap<Graph, Edge, _Value> > Parent;
+
+ public:
+ explicit EdgeMap(const Graph& _g)
+ : Parent(_g) {}
+
+ EdgeMap(const Graph& _g, const _Value& _v)
+ : Parent(_g, _v) {}
+
+ EdgeMap& operator=(const EdgeMap& cmap) {
+ return operator=<EdgeMap>(cmap);
+ }
+
+ template <typename CMap>
+ EdgeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+
+ };
+
+
+ // Alteration extension
+
+ Edge addEdge(const Node& from, const Node& to) {
+ Edge edge = Parent::addEdge(from, to);
+ notifier(Edge()).add(edge);
+ std::vector<Arc> arcs;
+ arcs.push_back(Parent::direct(edge, true));
+ arcs.push_back(Parent::direct(edge, false));
+ notifier(Arc()).add(arcs);
+ return edge;
+ }
+
+ void clear() {
+ notifier(Arc()).clear();
+ notifier(Edge()).clear();
+ Parent::clear();
+ }
+
+ void erase(const Edge& edge) {
+ std::vector<Arc> arcs;
+ arcs.push_back(Parent::direct(edge, true));
+ arcs.push_back(Parent::direct(edge, false));
+ notifier(Arc()).erase(arcs);
+ notifier(Edge()).erase(edge);
+ Parent::erase(edge);
+ }
+
+
+ EdgeSetExtender() {
+ arc_notifier.setContainer(*this);
+ edge_notifier.setContainer(*this);
+ }
+
+ ~EdgeSetExtender() {
+ edge_notifier.clear();
+ arc_notifier.clear();
+ }
+
+ };
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/enable_if.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/enable_if.h
new file mode 100644
index 00000000000..f0d8de4d3cc
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/enable_if.h
@@ -0,0 +1,131 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+// This file contains a modified version of the enable_if library from BOOST.
+// See the appropriate copyright notice below.
+
+// Boost enable_if library
+
+// Copyright 2003 (c) The Trustees of Indiana University.
+
+// Use, modification, and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// Authors: Jaakko Jarvi (jajarvi at osl.iu.edu)
+// Jeremiah Willcock (jewillco at osl.iu.edu)
+// Andrew Lumsdaine (lums at osl.iu.edu)
+
+
+#ifndef LEMON_BITS_ENABLE_IF_H
+#define LEMON_BITS_ENABLE_IF_H
+
+//\file
+//\brief Miscellaneous basic utilities
+
+namespace lemon
+{
+
+ // Basic type for defining "tags". A "YES" condition for \c enable_if.
+
+ // Basic type for defining "tags". A "YES" condition for \c enable_if.
+ //
+ //\sa False
+ struct True {
+ //\e
+ static const bool value = true;
+ };
+
+ // Basic type for defining "tags". A "NO" condition for \c enable_if.
+
+ // Basic type for defining "tags". A "NO" condition for \c enable_if.
+ //
+ //\sa True
+ struct False {
+ //\e
+ static const bool value = false;
+ };
+
+
+
+ template <typename T>
+ struct Wrap {
+ const T &value;
+ Wrap(const T &t) : value(t) {}
+ };
+
+ /**************** dummy class to avoid ambiguity ****************/
+
+ template<int T> struct dummy { dummy(int) {} };
+
+ /**************** enable_if from BOOST ****************/
+
+ template <typename Type, typename T = void>
+ struct exists {
+ typedef T type;
+ };
+
+
+ template <bool B, class T = void>
+ struct enable_if_c {
+ typedef T type;
+ };
+
+ template <class T>
+ struct enable_if_c<false, T> {};
+
+ template <class Cond, class T = void>
+ struct enable_if : public enable_if_c<Cond::value, T> {};
+
+ template <bool B, class T>
+ struct lazy_enable_if_c {
+ typedef typename T::type type;
+ };
+
+ template <class T>
+ struct lazy_enable_if_c<false, T> {};
+
+ template <class Cond, class T>
+ struct lazy_enable_if : public lazy_enable_if_c<Cond::value, T> {};
+
+
+ template <bool B, class T = void>
+ struct disable_if_c {
+ typedef T type;
+ };
+
+ template <class T>
+ struct disable_if_c<true, T> {};
+
+ template <class Cond, class T = void>
+ struct disable_if : public disable_if_c<Cond::value, T> {};
+
+ template <bool B, class T>
+ struct lazy_disable_if_c {
+ typedef typename T::type type;
+ };
+
+ template <class T>
+ struct lazy_disable_if_c<true, T> {};
+
+ template <class Cond, class T>
+ struct lazy_disable_if : public lazy_disable_if_c<Cond::value, T> {};
+
+} // namespace lemon
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/graph_adaptor_extender.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/graph_adaptor_extender.h
new file mode 100644
index 00000000000..c38c8e1d608
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/graph_adaptor_extender.h
@@ -0,0 +1,401 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_BITS_GRAPH_ADAPTOR_EXTENDER_H
+#define LEMON_BITS_GRAPH_ADAPTOR_EXTENDER_H
+
+#include <lemon/core.h>
+#include <lemon/error.h>
+
+namespace lemon {
+
+ template <typename _Digraph>
+ class DigraphAdaptorExtender : public _Digraph {
+ typedef _Digraph Parent;
+
+ public:
+
+ typedef _Digraph Digraph;
+ typedef DigraphAdaptorExtender Adaptor;
+
+ // Base extensions
+
+ typedef typename Parent::Node Node;
+ typedef typename Parent::Arc Arc;
+
+ int maxId(Node) const {
+ return Parent::maxNodeId();
+ }
+
+ int maxId(Arc) const {
+ return Parent::maxArcId();
+ }
+
+ Node fromId(int id, Node) const {
+ return Parent::nodeFromId(id);
+ }
+
+ Arc fromId(int id, Arc) const {
+ return Parent::arcFromId(id);
+ }
+
+ Node oppositeNode(const Node &n, const Arc &e) const {
+ if (n == Parent::source(e))
+ return Parent::target(e);
+ else if(n==Parent::target(e))
+ return Parent::source(e);
+ else
+ return INVALID;
+ }
+
+ class NodeIt : public Node {
+ const Adaptor* _adaptor;
+ public:
+
+ NodeIt() {}
+
+ NodeIt(Invalid i) : Node(i) { }
+
+ explicit NodeIt(const Adaptor& adaptor) : _adaptor(&adaptor) {
+ _adaptor->first(static_cast<Node&>(*this));
+ }
+
+ NodeIt(const Adaptor& adaptor, const Node& node)
+ : Node(node), _adaptor(&adaptor) {}
+
+ NodeIt& operator++() {
+ _adaptor->next(*this);
+ return *this;
+ }
+
+ };
+
+
+ class ArcIt : public Arc {
+ const Adaptor* _adaptor;
+ public:
+
+ ArcIt() { }
+
+ ArcIt(Invalid i) : Arc(i) { }
+
+ explicit ArcIt(const Adaptor& adaptor) : _adaptor(&adaptor) {
+ _adaptor->first(static_cast<Arc&>(*this));
+ }
+
+ ArcIt(const Adaptor& adaptor, const Arc& e) :
+ Arc(e), _adaptor(&adaptor) { }
+
+ ArcIt& operator++() {
+ _adaptor->next(*this);
+ return *this;
+ }
+
+ };
+
+
+ class OutArcIt : public Arc {
+ const Adaptor* _adaptor;
+ public:
+
+ OutArcIt() { }
+
+ OutArcIt(Invalid i) : Arc(i) { }
+
+ OutArcIt(const Adaptor& adaptor, const Node& node)
+ : _adaptor(&adaptor) {
+ _adaptor->firstOut(*this, node);
+ }
+
+ OutArcIt(const Adaptor& adaptor, const Arc& arc)
+ : Arc(arc), _adaptor(&adaptor) {}
+
+ OutArcIt& operator++() {
+ _adaptor->nextOut(*this);
+ return *this;
+ }
+
+ };
+
+
+ class InArcIt : public Arc {
+ const Adaptor* _adaptor;
+ public:
+
+ InArcIt() { }
+
+ InArcIt(Invalid i) : Arc(i) { }
+
+ InArcIt(const Adaptor& adaptor, const Node& node)
+ : _adaptor(&adaptor) {
+ _adaptor->firstIn(*this, node);
+ }
+
+ InArcIt(const Adaptor& adaptor, const Arc& arc) :
+ Arc(arc), _adaptor(&adaptor) {}
+
+ InArcIt& operator++() {
+ _adaptor->nextIn(*this);
+ return *this;
+ }
+
+ };
+
+ Node baseNode(const OutArcIt &e) const {
+ return Parent::source(e);
+ }
+ Node runningNode(const OutArcIt &e) const {
+ return Parent::target(e);
+ }
+
+ Node baseNode(const InArcIt &e) const {
+ return Parent::target(e);
+ }
+ Node runningNode(const InArcIt &e) const {
+ return Parent::source(e);
+ }
+
+ };
+
+ template <typename _Graph>
+ class GraphAdaptorExtender : public _Graph {
+ typedef _Graph Parent;
+
+ public:
+
+ typedef _Graph Graph;
+ typedef GraphAdaptorExtender Adaptor;
+
+ typedef True UndirectedTag;
+
+ typedef typename Parent::Node Node;
+ typedef typename Parent::Arc Arc;
+ typedef typename Parent::Edge Edge;
+
+ // Graph extension
+
+ int maxId(Node) const {
+ return Parent::maxNodeId();
+ }
+
+ int maxId(Arc) const {
+ return Parent::maxArcId();
+ }
+
+ int maxId(Edge) const {
+ return Parent::maxEdgeId();
+ }
+
+ Node fromId(int id, Node) const {
+ return Parent::nodeFromId(id);
+ }
+
+ Arc fromId(int id, Arc) const {
+ return Parent::arcFromId(id);
+ }
+
+ Edge fromId(int id, Edge) const {
+ return Parent::edgeFromId(id);
+ }
+
+ Node oppositeNode(const Node &n, const Edge &e) const {
+ if( n == Parent::u(e))
+ return Parent::v(e);
+ else if( n == Parent::v(e))
+ return Parent::u(e);
+ else
+ return INVALID;
+ }
+
+ Arc oppositeArc(const Arc &a) const {
+ return Parent::direct(a, !Parent::direction(a));
+ }
+
+ using Parent::direct;
+ Arc direct(const Edge &e, const Node &s) const {
+ return Parent::direct(e, Parent::u(e) == s);
+ }
+
+
+ class NodeIt : public Node {
+ const Adaptor* _adaptor;
+ public:
+
+ NodeIt() {}
+
+ NodeIt(Invalid i) : Node(i) { }
+
+ explicit NodeIt(const Adaptor& adaptor) : _adaptor(&adaptor) {
+ _adaptor->first(static_cast<Node&>(*this));
+ }
+
+ NodeIt(const Adaptor& adaptor, const Node& node)
+ : Node(node), _adaptor(&adaptor) {}
+
+ NodeIt& operator++() {
+ _adaptor->next(*this);
+ return *this;
+ }
+
+ };
+
+
+ class ArcIt : public Arc {
+ const Adaptor* _adaptor;
+ public:
+
+ ArcIt() { }
+
+ ArcIt(Invalid i) : Arc(i) { }
+
+ explicit ArcIt(const Adaptor& adaptor) : _adaptor(&adaptor) {
+ _adaptor->first(static_cast<Arc&>(*this));
+ }
+
+ ArcIt(const Adaptor& adaptor, const Arc& e) :
+ Arc(e), _adaptor(&adaptor) { }
+
+ ArcIt& operator++() {
+ _adaptor->next(*this);
+ return *this;
+ }
+
+ };
+
+
+ class OutArcIt : public Arc {
+ const Adaptor* _adaptor;
+ public:
+
+ OutArcIt() { }
+
+ OutArcIt(Invalid i) : Arc(i) { }
+
+ OutArcIt(const Adaptor& adaptor, const Node& node)
+ : _adaptor(&adaptor) {
+ _adaptor->firstOut(*this, node);
+ }
+
+ OutArcIt(const Adaptor& adaptor, const Arc& arc)
+ : Arc(arc), _adaptor(&adaptor) {}
+
+ OutArcIt& operator++() {
+ _adaptor->nextOut(*this);
+ return *this;
+ }
+
+ };
+
+
+ class InArcIt : public Arc {
+ const Adaptor* _adaptor;
+ public:
+
+ InArcIt() { }
+
+ InArcIt(Invalid i) : Arc(i) { }
+
+ InArcIt(const Adaptor& adaptor, const Node& node)
+ : _adaptor(&adaptor) {
+ _adaptor->firstIn(*this, node);
+ }
+
+ InArcIt(const Adaptor& adaptor, const Arc& arc) :
+ Arc(arc), _adaptor(&adaptor) {}
+
+ InArcIt& operator++() {
+ _adaptor->nextIn(*this);
+ return *this;
+ }
+
+ };
+
+ class EdgeIt : public Parent::Edge {
+ const Adaptor* _adaptor;
+ public:
+
+ EdgeIt() { }
+
+ EdgeIt(Invalid i) : Edge(i) { }
+
+ explicit EdgeIt(const Adaptor& adaptor) : _adaptor(&adaptor) {
+ _adaptor->first(static_cast<Edge&>(*this));
+ }
+
+ EdgeIt(const Adaptor& adaptor, const Edge& e) :
+ Edge(e), _adaptor(&adaptor) { }
+
+ EdgeIt& operator++() {
+ _adaptor->next(*this);
+ return *this;
+ }
+
+ };
+
+ class IncEdgeIt : public Edge {
+ friend class GraphAdaptorExtender;
+ const Adaptor* _adaptor;
+ bool direction;
+ public:
+
+ IncEdgeIt() { }
+
+ IncEdgeIt(Invalid i) : Edge(i), direction(false) { }
+
+ IncEdgeIt(const Adaptor& adaptor, const Node &n) : _adaptor(&adaptor) {
+ _adaptor->firstInc(static_cast<Edge&>(*this), direction, n);
+ }
+
+ IncEdgeIt(const Adaptor& adaptor, const Edge &e, const Node &n)
+ : _adaptor(&adaptor), Edge(e) {
+ direction = (_adaptor->u(e) == n);
+ }
+
+ IncEdgeIt& operator++() {
+ _adaptor->nextInc(*this, direction);
+ return *this;
+ }
+ };
+
+ Node baseNode(const OutArcIt &a) const {
+ return Parent::source(a);
+ }
+ Node runningNode(const OutArcIt &a) const {
+ return Parent::target(a);
+ }
+
+ Node baseNode(const InArcIt &a) const {
+ return Parent::target(a);
+ }
+ Node runningNode(const InArcIt &a) const {
+ return Parent::source(a);
+ }
+
+ Node baseNode(const IncEdgeIt &e) const {
+ return e.direction ? Parent::u(e) : Parent::v(e);
+ }
+ Node runningNode(const IncEdgeIt &e) const {
+ return e.direction ? Parent::v(e) : Parent::u(e);
+ }
+
+ };
+
+}
+
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/graph_extender.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/graph_extender.h
new file mode 100644
index 00000000000..755a8907f50
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/graph_extender.h
@@ -0,0 +1,1332 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_BITS_GRAPH_EXTENDER_H
+#define LEMON_BITS_GRAPH_EXTENDER_H
+
+#include <lemon/core.h>
+
+#include <lemon/bits/map_extender.h>
+#include <lemon/bits/default_map.h>
+
+#include <lemon/concept_check.h>
+#include <lemon/concepts/maps.h>
+
+//\ingroup graphbits
+//\file
+//\brief Extenders for the graph types
+namespace lemon {
+
+ // \ingroup graphbits
+ //
+ // \brief Extender for the digraph implementations
+ template <typename Base>
+ class DigraphExtender : public Base {
+ typedef Base Parent;
+
+ public:
+
+ typedef DigraphExtender Digraph;
+
+ // Base extensions
+
+ typedef typename Parent::Node Node;
+ typedef typename Parent::Arc Arc;
+
+ int maxId(Node) const {
+ return Parent::maxNodeId();
+ }
+
+ int maxId(Arc) const {
+ return Parent::maxArcId();
+ }
+
+ static Node fromId(int id, Node) {
+ return Parent::nodeFromId(id);
+ }
+
+ static Arc fromId(int id, Arc) {
+ return Parent::arcFromId(id);
+ }
+
+ Node oppositeNode(const Node &node, const Arc &arc) const {
+ if (node == Parent::source(arc))
+ return Parent::target(arc);
+ else if(node == Parent::target(arc))
+ return Parent::source(arc);
+ else
+ return INVALID;
+ }
+
+ // Alterable extension
+
+ typedef AlterationNotifier<DigraphExtender, Node> NodeNotifier;
+ typedef AlterationNotifier<DigraphExtender, Arc> ArcNotifier;
+
+
+ protected:
+
+ mutable NodeNotifier node_notifier;
+ mutable ArcNotifier arc_notifier;
+
+ public:
+
+ NodeNotifier& notifier(Node) const {
+ return node_notifier;
+ }
+
+ ArcNotifier& notifier(Arc) const {
+ return arc_notifier;
+ }
+
+ class NodeIt : public Node {
+ const Digraph* _digraph;
+ public:
+
+ NodeIt() {}
+
+ NodeIt(Invalid i) : Node(i) { }
+
+ explicit NodeIt(const Digraph& digraph) : _digraph(&digraph) {
+ _digraph->first(static_cast<Node&>(*this));
+ }
+
+ NodeIt(const Digraph& digraph, const Node& node)
+ : Node(node), _digraph(&digraph) {}
+
+ NodeIt& operator++() {
+ _digraph->next(*this);
+ return *this;
+ }
+
+ };
+
+
+ class ArcIt : public Arc {
+ const Digraph* _digraph;
+ public:
+
+ ArcIt() { }
+
+ ArcIt(Invalid i) : Arc(i) { }
+
+ explicit ArcIt(const Digraph& digraph) : _digraph(&digraph) {
+ _digraph->first(static_cast<Arc&>(*this));
+ }
+
+ ArcIt(const Digraph& digraph, const Arc& arc) :
+ Arc(arc), _digraph(&digraph) { }
+
+ ArcIt& operator++() {
+ _digraph->next(*this);
+ return *this;
+ }
+
+ };
+
+
+ class OutArcIt : public Arc {
+ const Digraph* _digraph;
+ public:
+
+ OutArcIt() { }
+
+ OutArcIt(Invalid i) : Arc(i) { }
+
+ OutArcIt(const Digraph& digraph, const Node& node)
+ : _digraph(&digraph) {
+ _digraph->firstOut(*this, node);
+ }
+
+ OutArcIt(const Digraph& digraph, const Arc& arc)
+ : Arc(arc), _digraph(&digraph) {}
+
+ OutArcIt& operator++() {
+ _digraph->nextOut(*this);
+ return *this;
+ }
+
+ };
+
+
+ class InArcIt : public Arc {
+ const Digraph* _digraph;
+ public:
+
+ InArcIt() { }
+
+ InArcIt(Invalid i) : Arc(i) { }
+
+ InArcIt(const Digraph& digraph, const Node& node)
+ : _digraph(&digraph) {
+ _digraph->firstIn(*this, node);
+ }
+
+ InArcIt(const Digraph& digraph, const Arc& arc) :
+ Arc(arc), _digraph(&digraph) {}
+
+ InArcIt& operator++() {
+ _digraph->nextIn(*this);
+ return *this;
+ }
+
+ };
+
+ // \brief Base node of the iterator
+ //
+ // Returns the base node (i.e. the source in this case) of the iterator
+ Node baseNode(const OutArcIt &arc) const {
+ return Parent::source(arc);
+ }
+ // \brief Running node of the iterator
+ //
+ // Returns the running node (i.e. the target in this case) of the
+ // iterator
+ Node runningNode(const OutArcIt &arc) const {
+ return Parent::target(arc);
+ }
+
+ // \brief Base node of the iterator
+ //
+ // Returns the base node (i.e. the target in this case) of the iterator
+ Node baseNode(const InArcIt &arc) const {
+ return Parent::target(arc);
+ }
+ // \brief Running node of the iterator
+ //
+ // Returns the running node (i.e. the source in this case) of the
+ // iterator
+ Node runningNode(const InArcIt &arc) const {
+ return Parent::source(arc);
+ }
+
+
+ template <typename _Value>
+ class NodeMap
+ : public MapExtender<DefaultMap<Digraph, Node, _Value> > {
+ typedef MapExtender<DefaultMap<Digraph, Node, _Value> > Parent;
+
+ public:
+ explicit NodeMap(const Digraph& digraph)
+ : Parent(digraph) {}
+ NodeMap(const Digraph& digraph, const _Value& value)
+ : Parent(digraph, value) {}
+
+ private:
+ NodeMap& operator=(const NodeMap& cmap) {
+ return operator=<NodeMap>(cmap);
+ }
+
+ template <typename CMap>
+ NodeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+
+ };
+
+ template <typename _Value>
+ class ArcMap
+ : public MapExtender<DefaultMap<Digraph, Arc, _Value> > {
+ typedef MapExtender<DefaultMap<Digraph, Arc, _Value> > Parent;
+
+ public:
+ explicit ArcMap(const Digraph& digraph)
+ : Parent(digraph) {}
+ ArcMap(const Digraph& digraph, const _Value& value)
+ : Parent(digraph, value) {}
+
+ private:
+ ArcMap& operator=(const ArcMap& cmap) {
+ return operator=<ArcMap>(cmap);
+ }
+
+ template <typename CMap>
+ ArcMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+
+ Node addNode() {
+ Node node = Parent::addNode();
+ notifier(Node()).add(node);
+ return node;
+ }
+
+ Arc addArc(const Node& from, const Node& to) {
+ Arc arc = Parent::addArc(from, to);
+ notifier(Arc()).add(arc);
+ return arc;
+ }
+
+ void clear() {
+ notifier(Arc()).clear();
+ notifier(Node()).clear();
+ Parent::clear();
+ }
+
+ template <typename Digraph, typename NodeRefMap, typename ArcRefMap>
+ void build(const Digraph& digraph, NodeRefMap& nodeRef, ArcRefMap& arcRef) {
+ Parent::build(digraph, nodeRef, arcRef);
+ notifier(Node()).build();
+ notifier(Arc()).build();
+ }
+
+ void erase(const Node& node) {
+ Arc arc;
+ Parent::firstOut(arc, node);
+ while (arc != INVALID ) {
+ erase(arc);
+ Parent::firstOut(arc, node);
+ }
+
+ Parent::firstIn(arc, node);
+ while (arc != INVALID ) {
+ erase(arc);
+ Parent::firstIn(arc, node);
+ }
+
+ notifier(Node()).erase(node);
+ Parent::erase(node);
+ }
+
+ void erase(const Arc& arc) {
+ notifier(Arc()).erase(arc);
+ Parent::erase(arc);
+ }
+
+ DigraphExtender() {
+ node_notifier.setContainer(*this);
+ arc_notifier.setContainer(*this);
+ }
+
+
+ ~DigraphExtender() {
+ arc_notifier.clear();
+ node_notifier.clear();
+ }
+ };
+
+ // \ingroup _graphbits
+ //
+ // \brief Extender for the Graphs
+ template <typename Base>
+ class GraphExtender : public Base {
+ typedef Base Parent;
+
+ public:
+
+ typedef GraphExtender Graph;
+
+ typedef True UndirectedTag;
+
+ typedef typename Parent::Node Node;
+ typedef typename Parent::Arc Arc;
+ typedef typename Parent::Edge Edge;
+
+ // Graph extension
+
+ int maxId(Node) const {
+ return Parent::maxNodeId();
+ }
+
+ int maxId(Arc) const {
+ return Parent::maxArcId();
+ }
+
+ int maxId(Edge) const {
+ return Parent::maxEdgeId();
+ }
+
+ static Node fromId(int id, Node) {
+ return Parent::nodeFromId(id);
+ }
+
+ static Arc fromId(int id, Arc) {
+ return Parent::arcFromId(id);
+ }
+
+ static Edge fromId(int id, Edge) {
+ return Parent::edgeFromId(id);
+ }
+
+ Node oppositeNode(const Node &n, const Edge &e) const {
+ if( n == Parent::u(e))
+ return Parent::v(e);
+ else if( n == Parent::v(e))
+ return Parent::u(e);
+ else
+ return INVALID;
+ }
+
+ Arc oppositeArc(const Arc &arc) const {
+ return Parent::direct(arc, !Parent::direction(arc));
+ }
+
+ using Parent::direct;
+ Arc direct(const Edge &edge, const Node &node) const {
+ return Parent::direct(edge, Parent::u(edge) == node);
+ }
+
+ // Alterable extension
+
+ typedef AlterationNotifier<GraphExtender, Node> NodeNotifier;
+ typedef AlterationNotifier<GraphExtender, Arc> ArcNotifier;
+ typedef AlterationNotifier<GraphExtender, Edge> EdgeNotifier;
+
+
+ protected:
+
+ mutable NodeNotifier node_notifier;
+ mutable ArcNotifier arc_notifier;
+ mutable EdgeNotifier edge_notifier;
+
+ public:
+
+ NodeNotifier& notifier(Node) const {
+ return node_notifier;
+ }
+
+ ArcNotifier& notifier(Arc) const {
+ return arc_notifier;
+ }
+
+ EdgeNotifier& notifier(Edge) const {
+ return edge_notifier;
+ }
+
+
+
+ class NodeIt : public Node {
+ const Graph* _graph;
+ public:
+
+ NodeIt() {}
+
+ NodeIt(Invalid i) : Node(i) { }
+
+ explicit NodeIt(const Graph& graph) : _graph(&graph) {
+ _graph->first(static_cast<Node&>(*this));
+ }
+
+ NodeIt(const Graph& graph, const Node& node)
+ : Node(node), _graph(&graph) {}
+
+ NodeIt& operator++() {
+ _graph->next(*this);
+ return *this;
+ }
+
+ };
+
+
+ class ArcIt : public Arc {
+ const Graph* _graph;
+ public:
+
+ ArcIt() { }
+
+ ArcIt(Invalid i) : Arc(i) { }
+
+ explicit ArcIt(const Graph& graph) : _graph(&graph) {
+ _graph->first(static_cast<Arc&>(*this));
+ }
+
+ ArcIt(const Graph& graph, const Arc& arc) :
+ Arc(arc), _graph(&graph) { }
+
+ ArcIt& operator++() {
+ _graph->next(*this);
+ return *this;
+ }
+
+ };
+
+
+ class OutArcIt : public Arc {
+ const Graph* _graph;
+ public:
+
+ OutArcIt() { }
+
+ OutArcIt(Invalid i) : Arc(i) { }
+
+ OutArcIt(const Graph& graph, const Node& node)
+ : _graph(&graph) {
+ _graph->firstOut(*this, node);
+ }
+
+ OutArcIt(const Graph& graph, const Arc& arc)
+ : Arc(arc), _graph(&graph) {}
+
+ OutArcIt& operator++() {
+ _graph->nextOut(*this);
+ return *this;
+ }
+
+ };
+
+
+ class InArcIt : public Arc {
+ const Graph* _graph;
+ public:
+
+ InArcIt() { }
+
+ InArcIt(Invalid i) : Arc(i) { }
+
+ InArcIt(const Graph& graph, const Node& node)
+ : _graph(&graph) {
+ _graph->firstIn(*this, node);
+ }
+
+ InArcIt(const Graph& graph, const Arc& arc) :
+ Arc(arc), _graph(&graph) {}
+
+ InArcIt& operator++() {
+ _graph->nextIn(*this);
+ return *this;
+ }
+
+ };
+
+
+ class EdgeIt : public Parent::Edge {
+ const Graph* _graph;
+ public:
+
+ EdgeIt() { }
+
+ EdgeIt(Invalid i) : Edge(i) { }
+
+ explicit EdgeIt(const Graph& graph) : _graph(&graph) {
+ _graph->first(static_cast<Edge&>(*this));
+ }
+
+ EdgeIt(const Graph& graph, const Edge& edge) :
+ Edge(edge), _graph(&graph) { }
+
+ EdgeIt& operator++() {
+ _graph->next(*this);
+ return *this;
+ }
+
+ };
+
+ class IncEdgeIt : public Parent::Edge {
+ friend class GraphExtender;
+ const Graph* _graph;
+ bool _direction;
+ public:
+
+ IncEdgeIt() { }
+
+ IncEdgeIt(Invalid i) : Edge(i), _direction(false) { }
+
+ IncEdgeIt(const Graph& graph, const Node &node) : _graph(&graph) {
+ _graph->firstInc(*this, _direction, node);
+ }
+
+ IncEdgeIt(const Graph& graph, const Edge &edge, const Node &node)
+ : _graph(&graph), Edge(edge) {
+ _direction = (_graph->source(edge) == node);
+ }
+
+ IncEdgeIt& operator++() {
+ _graph->nextInc(*this, _direction);
+ return *this;
+ }
+ };
+
+ // \brief Base node of the iterator
+ //
+ // Returns the base node (ie. the source in this case) of the iterator
+ Node baseNode(const OutArcIt &arc) const {
+ return Parent::source(static_cast<const Arc&>(arc));
+ }
+ // \brief Running node of the iterator
+ //
+ // Returns the running node (ie. the target in this case) of the
+ // iterator
+ Node runningNode(const OutArcIt &arc) const {
+ return Parent::target(static_cast<const Arc&>(arc));
+ }
+
+ // \brief Base node of the iterator
+ //
+ // Returns the base node (ie. the target in this case) of the iterator
+ Node baseNode(const InArcIt &arc) const {
+ return Parent::target(static_cast<const Arc&>(arc));
+ }
+ // \brief Running node of the iterator
+ //
+ // Returns the running node (ie. the source in this case) of the
+ // iterator
+ Node runningNode(const InArcIt &arc) const {
+ return Parent::source(static_cast<const Arc&>(arc));
+ }
+
+ // Base node of the iterator
+ //
+ // Returns the base node of the iterator
+ Node baseNode(const IncEdgeIt &edge) const {
+ return edge._direction ? this->u(edge) : this->v(edge);
+ }
+ // Running node of the iterator
+ //
+ // Returns the running node of the iterator
+ Node runningNode(const IncEdgeIt &edge) const {
+ return edge._direction ? this->v(edge) : this->u(edge);
+ }
+
+ // Mappable extension
+
+ template <typename _Value>
+ class NodeMap
+ : public MapExtender<DefaultMap<Graph, Node, _Value> > {
+ typedef MapExtender<DefaultMap<Graph, Node, _Value> > Parent;
+
+ public:
+ explicit NodeMap(const Graph& graph)
+ : Parent(graph) {}
+ NodeMap(const Graph& graph, const _Value& value)
+ : Parent(graph, value) {}
+
+ private:
+ NodeMap& operator=(const NodeMap& cmap) {
+ return operator=<NodeMap>(cmap);
+ }
+
+ template <typename CMap>
+ NodeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+
+ };
+
+ template <typename _Value>
+ class ArcMap
+ : public MapExtender<DefaultMap<Graph, Arc, _Value> > {
+ typedef MapExtender<DefaultMap<Graph, Arc, _Value> > Parent;
+
+ public:
+ explicit ArcMap(const Graph& graph)
+ : Parent(graph) {}
+ ArcMap(const Graph& graph, const _Value& value)
+ : Parent(graph, value) {}
+
+ private:
+ ArcMap& operator=(const ArcMap& cmap) {
+ return operator=<ArcMap>(cmap);
+ }
+
+ template <typename CMap>
+ ArcMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+
+ template <typename _Value>
+ class EdgeMap
+ : public MapExtender<DefaultMap<Graph, Edge, _Value> > {
+ typedef MapExtender<DefaultMap<Graph, Edge, _Value> > Parent;
+
+ public:
+ explicit EdgeMap(const Graph& graph)
+ : Parent(graph) {}
+
+ EdgeMap(const Graph& graph, const _Value& value)
+ : Parent(graph, value) {}
+
+ private:
+ EdgeMap& operator=(const EdgeMap& cmap) {
+ return operator=<EdgeMap>(cmap);
+ }
+
+ template <typename CMap>
+ EdgeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+
+ };
+
+ // Alteration extension
+
+ Node addNode() {
+ Node node = Parent::addNode();
+ notifier(Node()).add(node);
+ return node;
+ }
+
+ Edge addEdge(const Node& from, const Node& to) {
+ Edge edge = Parent::addEdge(from, to);
+ notifier(Edge()).add(edge);
+ std::vector<Arc> ev;
+ ev.push_back(Parent::direct(edge, true));
+ ev.push_back(Parent::direct(edge, false));
+ notifier(Arc()).add(ev);
+ return edge;
+ }
+
+ void clear() {
+ notifier(Arc()).clear();
+ notifier(Edge()).clear();
+ notifier(Node()).clear();
+ Parent::clear();
+ }
+
+ template <typename Graph, typename NodeRefMap, typename EdgeRefMap>
+ void build(const Graph& graph, NodeRefMap& nodeRef,
+ EdgeRefMap& edgeRef) {
+ Parent::build(graph, nodeRef, edgeRef);
+ notifier(Node()).build();
+ notifier(Edge()).build();
+ notifier(Arc()).build();
+ }
+
+ void erase(const Node& node) {
+ Arc arc;
+ Parent::firstOut(arc, node);
+ while (arc != INVALID ) {
+ erase(arc);
+ Parent::firstOut(arc, node);
+ }
+
+ Parent::firstIn(arc, node);
+ while (arc != INVALID ) {
+ erase(arc);
+ Parent::firstIn(arc, node);
+ }
+
+ notifier(Node()).erase(node);
+ Parent::erase(node);
+ }
+
+ void erase(const Edge& edge) {
+ std::vector<Arc> av;
+ av.push_back(Parent::direct(edge, true));
+ av.push_back(Parent::direct(edge, false));
+ notifier(Arc()).erase(av);
+ notifier(Edge()).erase(edge);
+ Parent::erase(edge);
+ }
+
+ GraphExtender() {
+ node_notifier.setContainer(*this);
+ arc_notifier.setContainer(*this);
+ edge_notifier.setContainer(*this);
+ }
+
+ ~GraphExtender() {
+ edge_notifier.clear();
+ arc_notifier.clear();
+ node_notifier.clear();
+ }
+
+ };
+
+ // \ingroup _graphbits
+ //
+ // \brief Extender for the BpGraphs
+ template <typename Base>
+ class BpGraphExtender : public Base {
+ typedef Base Parent;
+
+ public:
+
+ typedef BpGraphExtender BpGraph;
+
+ typedef True UndirectedTag;
+
+ typedef typename Parent::Node Node;
+ typedef typename Parent::RedNode RedNode;
+ typedef typename Parent::BlueNode BlueNode;
+ typedef typename Parent::Arc Arc;
+ typedef typename Parent::Edge Edge;
+
+ // BpGraph extension
+
+ using Parent::first;
+ using Parent::next;
+ using Parent::id;
+
+ int maxId(Node) const {
+ return Parent::maxNodeId();
+ }
+
+ int maxId(RedNode) const {
+ return Parent::maxRedId();
+ }
+
+ int maxId(BlueNode) const {
+ return Parent::maxBlueId();
+ }
+
+ int maxId(Arc) const {
+ return Parent::maxArcId();
+ }
+
+ int maxId(Edge) const {
+ return Parent::maxEdgeId();
+ }
+
+ static Node fromId(int id, Node) {
+ return Parent::nodeFromId(id);
+ }
+
+ static Arc fromId(int id, Arc) {
+ return Parent::arcFromId(id);
+ }
+
+ static Edge fromId(int id, Edge) {
+ return Parent::edgeFromId(id);
+ }
+
+ Node u(Edge e) const { return this->redNode(e); }
+ Node v(Edge e) const { return this->blueNode(e); }
+
+ Node oppositeNode(const Node &n, const Edge &e) const {
+ if( n == u(e))
+ return v(e);
+ else if( n == v(e))
+ return u(e);
+ else
+ return INVALID;
+ }
+
+ Arc oppositeArc(const Arc &arc) const {
+ return Parent::direct(arc, !Parent::direction(arc));
+ }
+
+ using Parent::direct;
+ Arc direct(const Edge &edge, const Node &node) const {
+ return Parent::direct(edge, Parent::redNode(edge) == node);
+ }
+
+ RedNode asRedNode(const Node& node) const {
+ if (node == INVALID || Parent::blue(node)) {
+ return INVALID;
+ } else {
+ return Parent::asRedNodeUnsafe(node);
+ }
+ }
+
+ BlueNode asBlueNode(const Node& node) const {
+ if (node == INVALID || Parent::red(node)) {
+ return INVALID;
+ } else {
+ return Parent::asBlueNodeUnsafe(node);
+ }
+ }
+
+ // Alterable extension
+
+ typedef AlterationNotifier<BpGraphExtender, Node> NodeNotifier;
+ typedef AlterationNotifier<BpGraphExtender, RedNode> RedNodeNotifier;
+ typedef AlterationNotifier<BpGraphExtender, BlueNode> BlueNodeNotifier;
+ typedef AlterationNotifier<BpGraphExtender, Arc> ArcNotifier;
+ typedef AlterationNotifier<BpGraphExtender, Edge> EdgeNotifier;
+
+
+ protected:
+
+ mutable NodeNotifier node_notifier;
+ mutable RedNodeNotifier red_node_notifier;
+ mutable BlueNodeNotifier blue_node_notifier;
+ mutable ArcNotifier arc_notifier;
+ mutable EdgeNotifier edge_notifier;
+
+ public:
+
+ NodeNotifier& notifier(Node) const {
+ return node_notifier;
+ }
+
+ RedNodeNotifier& notifier(RedNode) const {
+ return red_node_notifier;
+ }
+
+ BlueNodeNotifier& notifier(BlueNode) const {
+ return blue_node_notifier;
+ }
+
+ ArcNotifier& notifier(Arc) const {
+ return arc_notifier;
+ }
+
+ EdgeNotifier& notifier(Edge) const {
+ return edge_notifier;
+ }
+
+
+
+ class NodeIt : public Node {
+ const BpGraph* _graph;
+ public:
+
+ NodeIt() {}
+
+ NodeIt(Invalid i) : Node(i) { }
+
+ explicit NodeIt(const BpGraph& graph) : _graph(&graph) {
+ _graph->first(static_cast<Node&>(*this));
+ }
+
+ NodeIt(const BpGraph& graph, const Node& node)
+ : Node(node), _graph(&graph) {}
+
+ NodeIt& operator++() {
+ _graph->next(*this);
+ return *this;
+ }
+
+ };
+
+ class RedNodeIt : public RedNode {
+ const BpGraph* _graph;
+ public:
+
+ RedNodeIt() {}
+
+ RedNodeIt(Invalid i) : RedNode(i) { }
+
+ explicit RedNodeIt(const BpGraph& graph) : _graph(&graph) {
+ _graph->first(static_cast<RedNode&>(*this));
+ }
+
+ RedNodeIt(const BpGraph& graph, const RedNode& node)
+ : RedNode(node), _graph(&graph) {}
+
+ RedNodeIt& operator++() {
+ _graph->next(static_cast<RedNode&>(*this));
+ return *this;
+ }
+
+ };
+
+ class BlueNodeIt : public BlueNode {
+ const BpGraph* _graph;
+ public:
+
+ BlueNodeIt() {}
+
+ BlueNodeIt(Invalid i) : BlueNode(i) { }
+
+ explicit BlueNodeIt(const BpGraph& graph) : _graph(&graph) {
+ _graph->first(static_cast<BlueNode&>(*this));
+ }
+
+ BlueNodeIt(const BpGraph& graph, const BlueNode& node)
+ : BlueNode(node), _graph(&graph) {}
+
+ BlueNodeIt& operator++() {
+ _graph->next(static_cast<BlueNode&>(*this));
+ return *this;
+ }
+
+ };
+
+
+ class ArcIt : public Arc {
+ const BpGraph* _graph;
+ public:
+
+ ArcIt() { }
+
+ ArcIt(Invalid i) : Arc(i) { }
+
+ explicit ArcIt(const BpGraph& graph) : _graph(&graph) {
+ _graph->first(static_cast<Arc&>(*this));
+ }
+
+ ArcIt(const BpGraph& graph, const Arc& arc) :
+ Arc(arc), _graph(&graph) { }
+
+ ArcIt& operator++() {
+ _graph->next(*this);
+ return *this;
+ }
+
+ };
+
+
+ class OutArcIt : public Arc {
+ const BpGraph* _graph;
+ public:
+
+ OutArcIt() { }
+
+ OutArcIt(Invalid i) : Arc(i) { }
+
+ OutArcIt(const BpGraph& graph, const Node& node)
+ : _graph(&graph) {
+ _graph->firstOut(*this, node);
+ }
+
+ OutArcIt(const BpGraph& graph, const Arc& arc)
+ : Arc(arc), _graph(&graph) {}
+
+ OutArcIt& operator++() {
+ _graph->nextOut(*this);
+ return *this;
+ }
+
+ };
+
+
+ class InArcIt : public Arc {
+ const BpGraph* _graph;
+ public:
+
+ InArcIt() { }
+
+ InArcIt(Invalid i) : Arc(i) { }
+
+ InArcIt(const BpGraph& graph, const Node& node)
+ : _graph(&graph) {
+ _graph->firstIn(*this, node);
+ }
+
+ InArcIt(const BpGraph& graph, const Arc& arc) :
+ Arc(arc), _graph(&graph) {}
+
+ InArcIt& operator++() {
+ _graph->nextIn(*this);
+ return *this;
+ }
+
+ };
+
+
+ class EdgeIt : public Parent::Edge {
+ const BpGraph* _graph;
+ public:
+
+ EdgeIt() { }
+
+ EdgeIt(Invalid i) : Edge(i) { }
+
+ explicit EdgeIt(const BpGraph& graph) : _graph(&graph) {
+ _graph->first(static_cast<Edge&>(*this));
+ }
+
+ EdgeIt(const BpGraph& graph, const Edge& edge) :
+ Edge(edge), _graph(&graph) { }
+
+ EdgeIt& operator++() {
+ _graph->next(*this);
+ return *this;
+ }
+
+ };
+
+ class IncEdgeIt : public Parent::Edge {
+ friend class BpGraphExtender;
+ const BpGraph* _graph;
+ bool _direction;
+ public:
+
+ IncEdgeIt() { }
+
+ IncEdgeIt(Invalid i) : Edge(i), _direction(false) { }
+
+ IncEdgeIt(const BpGraph& graph, const Node &node) : _graph(&graph) {
+ _graph->firstInc(*this, _direction, node);
+ }
+
+ IncEdgeIt(const BpGraph& graph, const Edge &edge, const Node &node)
+ : _graph(&graph), Edge(edge) {
+ _direction = (_graph->source(edge) == node);
+ }
+
+ IncEdgeIt& operator++() {
+ _graph->nextInc(*this, _direction);
+ return *this;
+ }
+ };
+
+ // \brief Base node of the iterator
+ //
+ // Returns the base node (ie. the source in this case) of the iterator
+ Node baseNode(const OutArcIt &arc) const {
+ return Parent::source(static_cast<const Arc&>(arc));
+ }
+ // \brief Running node of the iterator
+ //
+ // Returns the running node (ie. the target in this case) of the
+ // iterator
+ Node runningNode(const OutArcIt &arc) const {
+ return Parent::target(static_cast<const Arc&>(arc));
+ }
+
+ // \brief Base node of the iterator
+ //
+ // Returns the base node (ie. the target in this case) of the iterator
+ Node baseNode(const InArcIt &arc) const {
+ return Parent::target(static_cast<const Arc&>(arc));
+ }
+ // \brief Running node of the iterator
+ //
+ // Returns the running node (ie. the source in this case) of the
+ // iterator
+ Node runningNode(const InArcIt &arc) const {
+ return Parent::source(static_cast<const Arc&>(arc));
+ }
+
+ // Base node of the iterator
+ //
+ // Returns the base node of the iterator
+ Node baseNode(const IncEdgeIt &edge) const {
+ return edge._direction ? this->u(edge) : this->v(edge);
+ }
+ // Running node of the iterator
+ //
+ // Returns the running node of the iterator
+ Node runningNode(const IncEdgeIt &edge) const {
+ return edge._direction ? this->v(edge) : this->u(edge);
+ }
+
+ // Mappable extension
+
+ template <typename _Value>
+ class NodeMap
+ : public MapExtender<DefaultMap<BpGraph, Node, _Value> > {
+ typedef MapExtender<DefaultMap<BpGraph, Node, _Value> > Parent;
+
+ public:
+ explicit NodeMap(const BpGraph& bpgraph)
+ : Parent(bpgraph) {}
+ NodeMap(const BpGraph& bpgraph, const _Value& value)
+ : Parent(bpgraph, value) {}
+
+ private:
+ NodeMap& operator=(const NodeMap& cmap) {
+ return operator=<NodeMap>(cmap);
+ }
+
+ template <typename CMap>
+ NodeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+
+ };
+
+ template <typename _Value>
+ class RedNodeMap
+ : public MapExtender<DefaultMap<BpGraph, RedNode, _Value> > {
+ typedef MapExtender<DefaultMap<BpGraph, RedNode, _Value> > Parent;
+
+ public:
+ explicit RedNodeMap(const BpGraph& bpgraph)
+ : Parent(bpgraph) {}
+ RedNodeMap(const BpGraph& bpgraph, const _Value& value)
+ : Parent(bpgraph, value) {}
+
+ private:
+ RedNodeMap& operator=(const RedNodeMap& cmap) {
+ return operator=<RedNodeMap>(cmap);
+ }
+
+ template <typename CMap>
+ RedNodeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+
+ };
+
+ template <typename _Value>
+ class BlueNodeMap
+ : public MapExtender<DefaultMap<BpGraph, BlueNode, _Value> > {
+ typedef MapExtender<DefaultMap<BpGraph, BlueNode, _Value> > Parent;
+
+ public:
+ explicit BlueNodeMap(const BpGraph& bpgraph)
+ : Parent(bpgraph) {}
+ BlueNodeMap(const BpGraph& bpgraph, const _Value& value)
+ : Parent(bpgraph, value) {}
+
+ private:
+ BlueNodeMap& operator=(const BlueNodeMap& cmap) {
+ return operator=<BlueNodeMap>(cmap);
+ }
+
+ template <typename CMap>
+ BlueNodeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+
+ };
+
+ template <typename _Value>
+ class ArcMap
+ : public MapExtender<DefaultMap<BpGraph, Arc, _Value> > {
+ typedef MapExtender<DefaultMap<BpGraph, Arc, _Value> > Parent;
+
+ public:
+ explicit ArcMap(const BpGraph& graph)
+ : Parent(graph) {}
+ ArcMap(const BpGraph& graph, const _Value& value)
+ : Parent(graph, value) {}
+
+ private:
+ ArcMap& operator=(const ArcMap& cmap) {
+ return operator=<ArcMap>(cmap);
+ }
+
+ template <typename CMap>
+ ArcMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+
+ template <typename _Value>
+ class EdgeMap
+ : public MapExtender<DefaultMap<BpGraph, Edge, _Value> > {
+ typedef MapExtender<DefaultMap<BpGraph, Edge, _Value> > Parent;
+
+ public:
+ explicit EdgeMap(const BpGraph& graph)
+ : Parent(graph) {}
+
+ EdgeMap(const BpGraph& graph, const _Value& value)
+ : Parent(graph, value) {}
+
+ private:
+ EdgeMap& operator=(const EdgeMap& cmap) {
+ return operator=<EdgeMap>(cmap);
+ }
+
+ template <typename CMap>
+ EdgeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+
+ };
+
+ // Alteration extension
+
+ RedNode addRedNode() {
+ RedNode node = Parent::addRedNode();
+ notifier(RedNode()).add(node);
+ notifier(Node()).add(node);
+ return node;
+ }
+
+ BlueNode addBlueNode() {
+ BlueNode node = Parent::addBlueNode();
+ notifier(BlueNode()).add(node);
+ notifier(Node()).add(node);
+ return node;
+ }
+
+ Edge addEdge(const RedNode& from, const BlueNode& to) {
+ Edge edge = Parent::addEdge(from, to);
+ notifier(Edge()).add(edge);
+ std::vector<Arc> av;
+ av.push_back(Parent::direct(edge, true));
+ av.push_back(Parent::direct(edge, false));
+ notifier(Arc()).add(av);
+ return edge;
+ }
+
+ void clear() {
+ notifier(Arc()).clear();
+ notifier(Edge()).clear();
+ notifier(Node()).clear();
+ notifier(BlueNode()).clear();
+ notifier(RedNode()).clear();
+ Parent::clear();
+ }
+
+ template <typename BpGraph, typename NodeRefMap, typename EdgeRefMap>
+ void build(const BpGraph& graph, NodeRefMap& nodeRef,
+ EdgeRefMap& edgeRef) {
+ Parent::build(graph, nodeRef, edgeRef);
+ notifier(RedNode()).build();
+ notifier(BlueNode()).build();
+ notifier(Node()).build();
+ notifier(Edge()).build();
+ notifier(Arc()).build();
+ }
+
+ void erase(const Node& node) {
+ Arc arc;
+ Parent::firstOut(arc, node);
+ while (arc != INVALID ) {
+ erase(arc);
+ Parent::firstOut(arc, node);
+ }
+
+ Parent::firstIn(arc, node);
+ while (arc != INVALID ) {
+ erase(arc);
+ Parent::firstIn(arc, node);
+ }
+
+ if (Parent::red(node)) {
+ notifier(RedNode()).erase(this->asRedNodeUnsafe(node));
+ } else {
+ notifier(BlueNode()).erase(this->asBlueNodeUnsafe(node));
+ }
+
+ notifier(Node()).erase(node);
+ Parent::erase(node);
+ }
+
+ void erase(const Edge& edge) {
+ std::vector<Arc> av;
+ av.push_back(Parent::direct(edge, true));
+ av.push_back(Parent::direct(edge, false));
+ notifier(Arc()).erase(av);
+ notifier(Edge()).erase(edge);
+ Parent::erase(edge);
+ }
+
+ BpGraphExtender() {
+ red_node_notifier.setContainer(*this);
+ blue_node_notifier.setContainer(*this);
+ node_notifier.setContainer(*this);
+ arc_notifier.setContainer(*this);
+ edge_notifier.setContainer(*this);
+ }
+
+ ~BpGraphExtender() {
+ edge_notifier.clear();
+ arc_notifier.clear();
+ node_notifier.clear();
+ blue_node_notifier.clear();
+ red_node_notifier.clear();
+ }
+
+ };
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/lock.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/lock.h
new file mode 100644
index 00000000000..09069998cdb
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/lock.h
@@ -0,0 +1,65 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_BITS_LOCK_H
+#define LEMON_BITS_LOCK_H
+
+#include <lemon/config.h>
+#if defined(LEMON_USE_PTHREAD)
+#include <pthread.h>
+#elif defined(LEMON_USE_WIN32_THREADS)
+#include <lemon/bits/windows.h>
+#endif
+
+namespace lemon {
+ namespace bits {
+
+#if defined(LEMON_USE_PTHREAD)
+ class Lock {
+ public:
+ Lock() {
+ pthread_mutex_init(&_lock, 0);
+ }
+ ~Lock() {
+ pthread_mutex_destroy(&_lock);
+ }
+ void lock() {
+ pthread_mutex_lock(&_lock);
+ }
+ void unlock() {
+ pthread_mutex_unlock(&_lock);
+ }
+
+ private:
+ pthread_mutex_t _lock;
+ };
+#elif defined(LEMON_USE_WIN32_THREADS)
+ class Lock : public WinLock {};
+#else
+ class Lock {
+ public:
+ Lock() {}
+ ~Lock() {}
+ void lock() {}
+ void unlock() {}
+ };
+#endif
+ }
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/map_extender.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/map_extender.h
new file mode 100644
index 00000000000..f32403e65ae
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/map_extender.h
@@ -0,0 +1,332 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_BITS_MAP_EXTENDER_H
+#define LEMON_BITS_MAP_EXTENDER_H
+
+#include <iterator>
+
+#include <lemon/bits/traits.h>
+
+#include <lemon/concept_check.h>
+#include <lemon/concepts/maps.h>
+
+//\file
+//\brief Extenders for iterable maps.
+
+namespace lemon {
+
+ // \ingroup graphbits
+ //
+ // \brief Extender for maps
+ template <typename _Map>
+ class MapExtender : public _Map {
+ typedef _Map Parent;
+ typedef typename Parent::GraphType GraphType;
+
+ public:
+
+ typedef MapExtender Map;
+ typedef typename Parent::Key Item;
+
+ typedef typename Parent::Key Key;
+ typedef typename Parent::Value Value;
+ typedef typename Parent::Reference Reference;
+ typedef typename Parent::ConstReference ConstReference;
+
+ typedef typename Parent::ReferenceMapTag ReferenceMapTag;
+
+ class MapIt;
+ class ConstMapIt;
+
+ friend class MapIt;
+ friend class ConstMapIt;
+
+ public:
+
+ MapExtender(const GraphType& graph)
+ : Parent(graph) {}
+
+ MapExtender(const GraphType& graph, const Value& value)
+ : Parent(graph, value) {}
+
+ private:
+ MapExtender& operator=(const MapExtender& cmap) {
+ return operator=<MapExtender>(cmap);
+ }
+
+ template <typename CMap>
+ MapExtender& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+
+ public:
+ class MapIt : public Item {
+ typedef Item Parent;
+
+ public:
+
+ typedef typename Map::Value Value;
+
+ MapIt() : map(NULL) {}
+
+ MapIt(Invalid i) : Parent(i), map(NULL) {}
+
+ explicit MapIt(Map& _map) : map(&_map) {
+ map->notifier()->first(*this);
+ }
+
+ MapIt(const Map& _map, const Item& item)
+ : Parent(item), map(&_map) {}
+
+ MapIt& operator++() {
+ map->notifier()->next(*this);
+ return *this;
+ }
+
+ typename MapTraits<Map>::ConstReturnValue operator*() const {
+ return (*map)[*this];
+ }
+
+ typename MapTraits<Map>::ReturnValue operator*() {
+ return (*map)[*this];
+ }
+
+ void set(const Value& value) {
+ map->set(*this, value);
+ }
+
+ protected:
+ Map* map;
+
+ };
+
+ class ConstMapIt : public Item {
+ typedef Item Parent;
+
+ public:
+
+ typedef typename Map::Value Value;
+
+ ConstMapIt() : map(NULL) {}
+
+ ConstMapIt(Invalid i) : Parent(i), map(NULL) {}
+
+ explicit ConstMapIt(Map& _map) : map(&_map) {
+ map->notifier()->first(*this);
+ }
+
+ ConstMapIt(const Map& _map, const Item& item)
+ : Parent(item), map(_map) {}
+
+ ConstMapIt& operator++() {
+ map->notifier()->next(*this);
+ return *this;
+ }
+
+ typename MapTraits<Map>::ConstReturnValue operator*() const {
+ return map[*this];
+ }
+
+ protected:
+ const Map* map;
+ };
+
+ class ItemIt : public Item {
+ typedef Item Parent;
+
+ public:
+ ItemIt() : map(NULL) {}
+
+
+ ItemIt(Invalid i) : Parent(i), map(NULL) {}
+
+ explicit ItemIt(Map& _map) : map(&_map) {
+ map->notifier()->first(*this);
+ }
+
+ ItemIt(const Map& _map, const Item& item)
+ : Parent(item), map(&_map) {}
+
+ ItemIt& operator++() {
+ map->notifier()->next(*this);
+ return *this;
+ }
+
+ protected:
+ const Map* map;
+
+ };
+ };
+
+ // \ingroup graphbits
+ //
+ // \brief Extender for maps which use a subset of the items.
+ template <typename _Graph, typename _Map>
+ class SubMapExtender : public _Map {
+ typedef _Map Parent;
+ typedef _Graph GraphType;
+
+ public:
+
+ typedef SubMapExtender Map;
+ typedef typename Parent::Key Item;
+
+ typedef typename Parent::Key Key;
+ typedef typename Parent::Value Value;
+ typedef typename Parent::Reference Reference;
+ typedef typename Parent::ConstReference ConstReference;
+
+ typedef typename Parent::ReferenceMapTag ReferenceMapTag;
+
+ class MapIt;
+ class ConstMapIt;
+
+ friend class MapIt;
+ friend class ConstMapIt;
+
+ public:
+
+ SubMapExtender(const GraphType& _graph)
+ : Parent(_graph), graph(_graph) {}
+
+ SubMapExtender(const GraphType& _graph, const Value& _value)
+ : Parent(_graph, _value), graph(_graph) {}
+
+ private:
+ SubMapExtender& operator=(const SubMapExtender& cmap) {
+ return operator=<MapExtender>(cmap);
+ }
+
+ template <typename CMap>
+ SubMapExtender& operator=(const CMap& cmap) {
+ checkConcept<concepts::ReadMap<Key, Value>, CMap>();
+ Item it;
+ for (graph.first(it); it != INVALID; graph.next(it)) {
+ Parent::set(it, cmap[it]);
+ }
+ return *this;
+ }
+
+ public:
+ class MapIt : public Item {
+ typedef Item Parent;
+
+ public:
+ typedef typename Map::Value Value;
+
+ MapIt() : map(NULL) {}
+
+ MapIt(Invalid i) : Parent(i), map(NULL) { }
+
+ explicit MapIt(Map& _map) : map(&_map) {
+ map->graph.first(*this);
+ }
+
+ MapIt(const Map& _map, const Item& item)
+ : Parent(item), map(&_map) {}
+
+ MapIt& operator++() {
+ map->graph.next(*this);
+ return *this;
+ }
+
+ typename MapTraits<Map>::ConstReturnValue operator*() const {
+ return (*map)[*this];
+ }
+
+ typename MapTraits<Map>::ReturnValue operator*() {
+ return (*map)[*this];
+ }
+
+ void set(const Value& value) {
+ map->set(*this, value);
+ }
+
+ protected:
+ Map* map;
+
+ };
+
+ class ConstMapIt : public Item {
+ typedef Item Parent;
+
+ public:
+
+ typedef typename Map::Value Value;
+
+ ConstMapIt() : map(NULL) {}
+
+ ConstMapIt(Invalid i) : Parent(i), map(NULL) { }
+
+ explicit ConstMapIt(Map& _map) : map(&_map) {
+ map->graph.first(*this);
+ }
+
+ ConstMapIt(const Map& _map, const Item& item)
+ : Parent(item), map(&_map) {}
+
+ ConstMapIt& operator++() {
+ map->graph.next(*this);
+ return *this;
+ }
+
+ typename MapTraits<Map>::ConstReturnValue operator*() const {
+ return (*map)[*this];
+ }
+
+ protected:
+ const Map* map;
+ };
+
+ class ItemIt : public Item {
+ typedef Item Parent;
+
+ public:
+ ItemIt() : map(NULL) {}
+
+
+ ItemIt(Invalid i) : Parent(i), map(NULL) { }
+
+ explicit ItemIt(Map& _map) : map(&_map) {
+ map->graph.first(*this);
+ }
+
+ ItemIt(const Map& _map, const Item& item)
+ : Parent(item), map(&_map) {}
+
+ ItemIt& operator++() {
+ map->graph.next(*this);
+ return *this;
+ }
+
+ protected:
+ const Map* map;
+
+ };
+
+ private:
+
+ const GraphType& graph;
+
+ };
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/path_dump.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/path_dump.h
new file mode 100644
index 00000000000..3e8cb8dd58c
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/path_dump.h
@@ -0,0 +1,177 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_BITS_PATH_DUMP_H
+#define LEMON_BITS_PATH_DUMP_H
+
+#include <lemon/core.h>
+#include <lemon/concept_check.h>
+
+namespace lemon {
+
+ template <typename _Digraph, typename _PredMap>
+ class PredMapPath {
+ public:
+ typedef True RevPathTag;
+
+ typedef _Digraph Digraph;
+ typedef typename Digraph::Arc Arc;
+ typedef _PredMap PredMap;
+
+ PredMapPath(const Digraph& _digraph, const PredMap& _predMap,
+ typename Digraph::Node _target)
+ : digraph(_digraph), predMap(_predMap), target(_target) {}
+
+ int length() const {
+ int len = 0;
+ typename Digraph::Node node = target;
+ typename Digraph::Arc arc;
+ while ((arc = predMap[node]) != INVALID) {
+ node = digraph.source(arc);
+ ++len;
+ }
+ return len;
+ }
+
+ bool empty() const {
+ return predMap[target] == INVALID;
+ }
+
+ class RevArcIt {
+ public:
+ RevArcIt() {}
+ RevArcIt(Invalid) : path(0), current(INVALID) {}
+ RevArcIt(const PredMapPath& _path)
+ : path(&_path), current(_path.target) {
+ if (path->predMap[current] == INVALID) current = INVALID;
+ }
+
+ operator const typename Digraph::Arc() const {
+ return path->predMap[current];
+ }
+
+ RevArcIt& operator++() {
+ current = path->digraph.source(path->predMap[current]);
+ if (path->predMap[current] == INVALID) current = INVALID;
+ return *this;
+ }
+
+ bool operator==(const RevArcIt& e) const {
+ return current == e.current;
+ }
+
+ bool operator!=(const RevArcIt& e) const {
+ return current != e.current;
+ }
+
+ bool operator<(const RevArcIt& e) const {
+ return current < e.current;
+ }
+
+ private:
+ const PredMapPath* path;
+ typename Digraph::Node current;
+ };
+
+ private:
+ const Digraph& digraph;
+ const PredMap& predMap;
+ typename Digraph::Node target;
+ };
+
+
+ template <typename _Digraph, typename _PredMatrixMap>
+ class PredMatrixMapPath {
+ public:
+ typedef True RevPathTag;
+
+ typedef _Digraph Digraph;
+ typedef typename Digraph::Arc Arc;
+ typedef _PredMatrixMap PredMatrixMap;
+
+ PredMatrixMapPath(const Digraph& _digraph,
+ const PredMatrixMap& _predMatrixMap,
+ typename Digraph::Node _source,
+ typename Digraph::Node _target)
+ : digraph(_digraph), predMatrixMap(_predMatrixMap),
+ source(_source), target(_target) {}
+
+ int length() const {
+ int len = 0;
+ typename Digraph::Node node = target;
+ typename Digraph::Arc arc;
+ while ((arc = predMatrixMap(source, node)) != INVALID) {
+ node = digraph.source(arc);
+ ++len;
+ }
+ return len;
+ }
+
+ bool empty() const {
+ return predMatrixMap(source, target) == INVALID;
+ }
+
+ class RevArcIt {
+ public:
+ RevArcIt() {}
+ RevArcIt(Invalid) : path(0), current(INVALID) {}
+ RevArcIt(const PredMatrixMapPath& _path)
+ : path(&_path), current(_path.target) {
+ if (path->predMatrixMap(path->source, current) == INVALID)
+ current = INVALID;
+ }
+
+ operator const typename Digraph::Arc() const {
+ return path->predMatrixMap(path->source, current);
+ }
+
+ RevArcIt& operator++() {
+ current =
+ path->digraph.source(path->predMatrixMap(path->source, current));
+ if (path->predMatrixMap(path->source, current) == INVALID)
+ current = INVALID;
+ return *this;
+ }
+
+ bool operator==(const RevArcIt& e) const {
+ return current == e.current;
+ }
+
+ bool operator!=(const RevArcIt& e) const {
+ return current != e.current;
+ }
+
+ bool operator<(const RevArcIt& e) const {
+ return current < e.current;
+ }
+
+ private:
+ const PredMatrixMapPath* path;
+ typename Digraph::Node current;
+ };
+
+ private:
+ const Digraph& digraph;
+ const PredMatrixMap& predMatrixMap;
+ typename Digraph::Node source;
+ typename Digraph::Node target;
+ };
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/solver_bits.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/solver_bits.h
new file mode 100644
index 00000000000..c34212be8cd
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/solver_bits.h
@@ -0,0 +1,194 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_BITS_SOLVER_BITS_H
+#define LEMON_BITS_SOLVER_BITS_H
+
+#include <vector>
+
+namespace lemon {
+
+ namespace _solver_bits {
+
+ class VarIndex {
+ private:
+ struct ItemT {
+ int prev, next;
+ int index;
+ };
+ std::vector<ItemT> items;
+ int first_item, last_item, first_free_item;
+
+ std::vector<int> cross;
+
+ public:
+
+ VarIndex()
+ : first_item(-1), last_item(-1), first_free_item(-1) {
+ }
+
+ void clear() {
+ first_item = -1;
+ last_item = -1;
+ first_free_item = -1;
+ items.clear();
+ cross.clear();
+ }
+
+ int addIndex(int idx) {
+ int n;
+ if (first_free_item == -1) {
+ n = items.size();
+ items.push_back(ItemT());
+ } else {
+ n = first_free_item;
+ first_free_item = items[n].next;
+ if (first_free_item != -1) {
+ items[first_free_item].prev = -1;
+ }
+ }
+ items[n].index = idx;
+ if (static_cast<int>(cross.size()) <= idx) {
+ cross.resize(idx + 1, -1);
+ }
+ cross[idx] = n;
+
+ items[n].prev = last_item;
+ items[n].next = -1;
+ if (last_item != -1) {
+ items[last_item].next = n;
+ } else {
+ first_item = n;
+ }
+ last_item = n;
+
+ return n;
+ }
+
+ int addIndex(int idx, int n) {
+ while (n >= static_cast<int>(items.size())) {
+ items.push_back(ItemT());
+ items.back().prev = -1;
+ items.back().next = first_free_item;
+ if (first_free_item != -1) {
+ items[first_free_item].prev = items.size() - 1;
+ }
+ first_free_item = items.size() - 1;
+ }
+ if (items[n].next != -1) {
+ items[items[n].next].prev = items[n].prev;
+ }
+ if (items[n].prev != -1) {
+ items[items[n].prev].next = items[n].next;
+ } else {
+ first_free_item = items[n].next;
+ }
+
+ items[n].index = idx;
+ if (static_cast<int>(cross.size()) <= idx) {
+ cross.resize(idx + 1, -1);
+ }
+ cross[idx] = n;
+
+ items[n].prev = last_item;
+ items[n].next = -1;
+ if (last_item != -1) {
+ items[last_item].next = n;
+ } else {
+ first_item = n;
+ }
+ last_item = n;
+
+ return n;
+ }
+
+ void eraseIndex(int idx) {
+ int n = cross[idx];
+
+ if (items[n].prev != -1) {
+ items[items[n].prev].next = items[n].next;
+ } else {
+ first_item = items[n].next;
+ }
+ if (items[n].next != -1) {
+ items[items[n].next].prev = items[n].prev;
+ } else {
+ last_item = items[n].prev;
+ }
+
+ if (first_free_item != -1) {
+ items[first_free_item].prev = n;
+ }
+ items[n].next = first_free_item;
+ items[n].prev = -1;
+ first_free_item = n;
+
+ while (!cross.empty() && cross.back() == -1) {
+ cross.pop_back();
+ }
+ }
+
+ int maxIndex() const {
+ return cross.size() - 1;
+ }
+
+ void shiftIndices(int idx) {
+ for (int i = idx + 1; i < static_cast<int>(cross.size()); ++i) {
+ cross[i - 1] = cross[i];
+ if (cross[i] != -1) {
+ --items[cross[i]].index;
+ }
+ }
+ cross.back() = -1;
+ cross.pop_back();
+ while (!cross.empty() && cross.back() == -1) {
+ cross.pop_back();
+ }
+ }
+
+ void relocateIndex(int idx, int jdx) {
+ cross[idx] = cross[jdx];
+ items[cross[jdx]].index = idx;
+ cross[jdx] = -1;
+
+ while (!cross.empty() && cross.back() == -1) {
+ cross.pop_back();
+ }
+ }
+
+ int operator[](int idx) const {
+ return cross[idx];
+ }
+
+ int operator()(int fdx) const {
+ return items[fdx].index;
+ }
+
+ void firstItem(int& fdx) const {
+ fdx = first_item;
+ }
+
+ void nextItem(int& fdx) const {
+ fdx = items[fdx].next;
+ }
+
+ };
+ }
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/traits.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/traits.h
new file mode 100644
index 00000000000..53fbd45647a
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/traits.h
@@ -0,0 +1,388 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_BITS_TRAITS_H
+#define LEMON_BITS_TRAITS_H
+
+//\file
+//\brief Traits for graphs and maps
+//
+
+#include <lemon/bits/enable_if.h>
+
+namespace lemon {
+
+ struct InvalidType {};
+
+ template <typename GR, typename _Item>
+ class ItemSetTraits {};
+
+
+ template <typename GR, typename Enable = void>
+ struct NodeNotifierIndicator {
+ typedef InvalidType Type;
+ };
+ template <typename GR>
+ struct NodeNotifierIndicator<
+ GR,
+ typename enable_if<typename GR::NodeNotifier::Notifier, void>::type
+ > {
+ typedef typename GR::NodeNotifier Type;
+ };
+
+ template <typename GR>
+ class ItemSetTraits<GR, typename GR::Node> {
+ public:
+
+ typedef GR Graph;
+ typedef GR Digraph;
+
+ typedef typename GR::Node Item;
+ typedef typename GR::NodeIt ItemIt;
+
+ typedef typename NodeNotifierIndicator<GR>::Type ItemNotifier;
+
+ template <typename V>
+ class Map : public GR::template NodeMap<V> {
+ typedef typename GR::template NodeMap<V> Parent;
+
+ public:
+ typedef typename GR::template NodeMap<V> Type;
+ typedef typename Parent::Value Value;
+
+ Map(const GR& _digraph) : Parent(_digraph) {}
+ Map(const GR& _digraph, const Value& _value)
+ : Parent(_digraph, _value) {}
+
+ };
+
+ };
+
+ template <typename GR, typename Enable = void>
+ struct ArcNotifierIndicator {
+ typedef InvalidType Type;
+ };
+ template <typename GR>
+ struct ArcNotifierIndicator<
+ GR,
+ typename enable_if<typename GR::ArcNotifier::Notifier, void>::type
+ > {
+ typedef typename GR::ArcNotifier Type;
+ };
+
+ template <typename GR>
+ class ItemSetTraits<GR, typename GR::Arc> {
+ public:
+
+ typedef GR Graph;
+ typedef GR Digraph;
+
+ typedef typename GR::Arc Item;
+ typedef typename GR::ArcIt ItemIt;
+
+ typedef typename ArcNotifierIndicator<GR>::Type ItemNotifier;
+
+ template <typename V>
+ class Map : public GR::template ArcMap<V> {
+ typedef typename GR::template ArcMap<V> Parent;
+
+ public:
+ typedef typename GR::template ArcMap<V> Type;
+ typedef typename Parent::Value Value;
+
+ Map(const GR& _digraph) : Parent(_digraph) {}
+ Map(const GR& _digraph, const Value& _value)
+ : Parent(_digraph, _value) {}
+ };
+
+ };
+
+ template <typename GR, typename Enable = void>
+ struct EdgeNotifierIndicator {
+ typedef InvalidType Type;
+ };
+ template <typename GR>
+ struct EdgeNotifierIndicator<
+ GR,
+ typename enable_if<typename GR::EdgeNotifier::Notifier, void>::type
+ > {
+ typedef typename GR::EdgeNotifier Type;
+ };
+
+ template <typename GR>
+ class ItemSetTraits<GR, typename GR::Edge> {
+ public:
+
+ typedef GR Graph;
+ typedef GR Digraph;
+
+ typedef typename GR::Edge Item;
+ typedef typename GR::EdgeIt ItemIt;
+
+ typedef typename EdgeNotifierIndicator<GR>::Type ItemNotifier;
+
+ template <typename V>
+ class Map : public GR::template EdgeMap<V> {
+ typedef typename GR::template EdgeMap<V> Parent;
+
+ public:
+ typedef typename GR::template EdgeMap<V> Type;
+ typedef typename Parent::Value Value;
+
+ Map(const GR& _digraph) : Parent(_digraph) {}
+ Map(const GR& _digraph, const Value& _value)
+ : Parent(_digraph, _value) {}
+ };
+
+ };
+
+ template <typename GR, typename Enable = void>
+ struct RedNodeNotifierIndicator {
+ typedef InvalidType Type;
+ };
+ template <typename GR>
+ struct RedNodeNotifierIndicator<
+ GR,
+ typename enable_if<typename GR::RedNodeNotifier::Notifier, void>::type
+ > {
+ typedef typename GR::RedNodeNotifier Type;
+ };
+
+ template <typename GR>
+ class ItemSetTraits<GR, typename GR::RedNode> {
+ public:
+
+ typedef GR BpGraph;
+ typedef GR Graph;
+ typedef GR Digraph;
+
+ typedef typename GR::RedNode Item;
+ typedef typename GR::RedNodeIt ItemIt;
+
+ typedef typename RedNodeNotifierIndicator<GR>::Type ItemNotifier;
+
+ template <typename V>
+ class Map : public GR::template RedNodeMap<V> {
+ typedef typename GR::template RedNodeMap<V> Parent;
+
+ public:
+ typedef typename GR::template RedNodeMap<V> Type;
+ typedef typename Parent::Value Value;
+
+ Map(const GR& _bpgraph) : Parent(_bpgraph) {}
+ Map(const GR& _bpgraph, const Value& _value)
+ : Parent(_bpgraph, _value) {}
+
+ };
+
+ };
+
+ template <typename GR, typename Enable = void>
+ struct BlueNodeNotifierIndicator {
+ typedef InvalidType Type;
+ };
+ template <typename GR>
+ struct BlueNodeNotifierIndicator<
+ GR,
+ typename enable_if<typename GR::BlueNodeNotifier::Notifier, void>::type
+ > {
+ typedef typename GR::BlueNodeNotifier Type;
+ };
+
+ template <typename GR>
+ class ItemSetTraits<GR, typename GR::BlueNode> {
+ public:
+
+ typedef GR BpGraph;
+ typedef GR Graph;
+ typedef GR Digraph;
+
+ typedef typename GR::BlueNode Item;
+ typedef typename GR::BlueNodeIt ItemIt;
+
+ typedef typename BlueNodeNotifierIndicator<GR>::Type ItemNotifier;
+
+ template <typename V>
+ class Map : public GR::template BlueNodeMap<V> {
+ typedef typename GR::template BlueNodeMap<V> Parent;
+
+ public:
+ typedef typename GR::template BlueNodeMap<V> Type;
+ typedef typename Parent::Value Value;
+
+ Map(const GR& _bpgraph) : Parent(_bpgraph) {}
+ Map(const GR& _bpgraph, const Value& _value)
+ : Parent(_bpgraph, _value) {}
+
+ };
+
+ };
+
+ template <typename Map, typename Enable = void>
+ struct MapTraits {
+ typedef False ReferenceMapTag;
+
+ typedef typename Map::Key Key;
+ typedef typename Map::Value Value;
+
+ typedef Value ConstReturnValue;
+ typedef Value ReturnValue;
+ };
+
+ template <typename Map>
+ struct MapTraits<
+ Map, typename enable_if<typename Map::ReferenceMapTag, void>::type >
+ {
+ typedef True ReferenceMapTag;
+
+ typedef typename Map::Key Key;
+ typedef typename Map::Value Value;
+
+ typedef typename Map::ConstReference ConstReturnValue;
+ typedef typename Map::Reference ReturnValue;
+
+ typedef typename Map::ConstReference ConstReference;
+ typedef typename Map::Reference Reference;
+ };
+
+ template <typename MatrixMap, typename Enable = void>
+ struct MatrixMapTraits {
+ typedef False ReferenceMapTag;
+
+ typedef typename MatrixMap::FirstKey FirstKey;
+ typedef typename MatrixMap::SecondKey SecondKey;
+ typedef typename MatrixMap::Value Value;
+
+ typedef Value ConstReturnValue;
+ typedef Value ReturnValue;
+ };
+
+ template <typename MatrixMap>
+ struct MatrixMapTraits<
+ MatrixMap, typename enable_if<typename MatrixMap::ReferenceMapTag,
+ void>::type >
+ {
+ typedef True ReferenceMapTag;
+
+ typedef typename MatrixMap::FirstKey FirstKey;
+ typedef typename MatrixMap::SecondKey SecondKey;
+ typedef typename MatrixMap::Value Value;
+
+ typedef typename MatrixMap::ConstReference ConstReturnValue;
+ typedef typename MatrixMap::Reference ReturnValue;
+
+ typedef typename MatrixMap::ConstReference ConstReference;
+ typedef typename MatrixMap::Reference Reference;
+ };
+
+ // Indicators for the tags
+
+ template <typename GR, typename Enable = void>
+ struct NodeNumTagIndicator {
+ static const bool value = false;
+ };
+
+ template <typename GR>
+ struct NodeNumTagIndicator<
+ GR,
+ typename enable_if<typename GR::NodeNumTag, void>::type
+ > {
+ static const bool value = true;
+ };
+
+ template <typename GR, typename Enable = void>
+ struct ArcNumTagIndicator {
+ static const bool value = false;
+ };
+
+ template <typename GR>
+ struct ArcNumTagIndicator<
+ GR,
+ typename enable_if<typename GR::ArcNumTag, void>::type
+ > {
+ static const bool value = true;
+ };
+
+ template <typename GR, typename Enable = void>
+ struct EdgeNumTagIndicator {
+ static const bool value = false;
+ };
+
+ template <typename GR>
+ struct EdgeNumTagIndicator<
+ GR,
+ typename enable_if<typename GR::EdgeNumTag, void>::type
+ > {
+ static const bool value = true;
+ };
+
+ template <typename GR, typename Enable = void>
+ struct FindArcTagIndicator {
+ static const bool value = false;
+ };
+
+ template <typename GR>
+ struct FindArcTagIndicator<
+ GR,
+ typename enable_if<typename GR::FindArcTag, void>::type
+ > {
+ static const bool value = true;
+ };
+
+ template <typename GR, typename Enable = void>
+ struct FindEdgeTagIndicator {
+ static const bool value = false;
+ };
+
+ template <typename GR>
+ struct FindEdgeTagIndicator<
+ GR,
+ typename enable_if<typename GR::FindEdgeTag, void>::type
+ > {
+ static const bool value = true;
+ };
+
+ template <typename GR, typename Enable = void>
+ struct UndirectedTagIndicator {
+ static const bool value = false;
+ };
+
+ template <typename GR>
+ struct UndirectedTagIndicator<
+ GR,
+ typename enable_if<typename GR::UndirectedTag, void>::type
+ > {
+ static const bool value = true;
+ };
+
+ template <typename GR, typename Enable = void>
+ struct BuildTagIndicator {
+ static const bool value = false;
+ };
+
+ template <typename GR>
+ struct BuildTagIndicator<
+ GR,
+ typename enable_if<typename GR::BuildTag, void>::type
+ > {
+ static const bool value = true;
+ };
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/variant.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/variant.h
new file mode 100644
index 00000000000..b8301892e61
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/variant.h
@@ -0,0 +1,494 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_BITS_VARIANT_H
+#define LEMON_BITS_VARIANT_H
+
+#include <lemon/assert.h>
+
+// \file
+// \brief Variant types
+
+namespace lemon {
+
+ namespace _variant_bits {
+
+ template <int left, int right>
+ struct CTMax {
+ static const int value = left < right ? right : left;
+ };
+
+ }
+
+
+ // \brief Simple Variant type for two types
+ //
+ // Simple Variant type for two types. The Variant type is a type-safe
+ // union. C++ has strong limitations for using unions, for
+ // example you cannot store a type with non-default constructor or
+ // destructor in a union. This class always knowns the current
+ // state of the variant and it cares for the proper construction
+ // and destruction.
+ template <typename _First, typename _Second>
+ class BiVariant {
+ public:
+
+ // \brief The \c First type.
+ typedef _First First;
+ // \brief The \c Second type.
+ typedef _Second Second;
+
+ // \brief Constructor
+ //
+ // This constructor initalizes to the default value of the \c First
+ // type.
+ BiVariant() {
+ flag = true;
+ new(reinterpret_cast<First*>(data)) First();
+ }
+
+ // \brief Constructor
+ //
+ // This constructor initalizes to the given value of the \c First
+ // type.
+ BiVariant(const First& f) {
+ flag = true;
+ new(reinterpret_cast<First*>(data)) First(f);
+ }
+
+ // \brief Constructor
+ //
+ // This constructor initalizes to the given value of the \c
+ // Second type.
+ BiVariant(const Second& s) {
+ flag = false;
+ new(reinterpret_cast<Second*>(data)) Second(s);
+ }
+
+ // \brief Copy constructor
+ //
+ // Copy constructor
+ BiVariant(const BiVariant& bivariant) {
+ flag = bivariant.flag;
+ if (flag) {
+ new(reinterpret_cast<First*>(data)) First(bivariant.first());
+ } else {
+ new(reinterpret_cast<Second*>(data)) Second(bivariant.second());
+ }
+ }
+
+ // \brief Destrcutor
+ //
+ // Destructor
+ ~BiVariant() {
+ destroy();
+ }
+
+ // \brief Set to the default value of the \c First type.
+ //
+ // This function sets the variant to the default value of the \c
+ // First type.
+ BiVariant& setFirst() {
+ destroy();
+ flag = true;
+ new(reinterpret_cast<First*>(data)) First();
+ return *this;
+ }
+
+ // \brief Set to the given value of the \c First type.
+ //
+ // This function sets the variant to the given value of the \c
+ // First type.
+ BiVariant& setFirst(const First& f) {
+ destroy();
+ flag = true;
+ new(reinterpret_cast<First*>(data)) First(f);
+ return *this;
+ }
+
+ // \brief Set to the default value of the \c Second type.
+ //
+ // This function sets the variant to the default value of the \c
+ // Second type.
+ BiVariant& setSecond() {
+ destroy();
+ flag = false;
+ new(reinterpret_cast<Second*>(data)) Second();
+ return *this;
+ }
+
+ // \brief Set to the given value of the \c Second type.
+ //
+ // This function sets the variant to the given value of the \c
+ // Second type.
+ BiVariant& setSecond(const Second& s) {
+ destroy();
+ flag = false;
+ new(reinterpret_cast<Second*>(data)) Second(s);
+ return *this;
+ }
+
+ // \brief Operator form of the \c setFirst()
+ BiVariant& operator=(const First& f) {
+ return setFirst(f);
+ }
+
+ // \brief Operator form of the \c setSecond()
+ BiVariant& operator=(const Second& s) {
+ return setSecond(s);
+ }
+
+ // \brief Assign operator
+ BiVariant& operator=(const BiVariant& bivariant) {
+ if (this == &bivariant) return *this;
+ destroy();
+ flag = bivariant.flag;
+ if (flag) {
+ new(reinterpret_cast<First*>(data)) First(bivariant.first());
+ } else {
+ new(reinterpret_cast<Second*>(data)) Second(bivariant.second());
+ }
+ return *this;
+ }
+
+ // \brief Reference to the value
+ //
+ // Reference to the value of the \c First type.
+ // \pre The BiVariant should store value of \c First type.
+ First& first() {
+ LEMON_DEBUG(flag, "Variant wrong state");
+ return *reinterpret_cast<First*>(data);
+ }
+
+ // \brief Const reference to the value
+ //
+ // Const reference to the value of the \c First type.
+ // \pre The BiVariant should store value of \c First type.
+ const First& first() const {
+ LEMON_DEBUG(flag, "Variant wrong state");
+ return *reinterpret_cast<const First*>(data);
+ }
+
+ // \brief Operator form of the \c first()
+ operator First&() { return first(); }
+ // \brief Operator form of the const \c first()
+ operator const First&() const { return first(); }
+
+ // \brief Reference to the value
+ //
+ // Reference to the value of the \c Second type.
+ // \pre The BiVariant should store value of \c Second type.
+ Second& second() {
+ LEMON_DEBUG(!flag, "Variant wrong state");
+ return *reinterpret_cast<Second*>(data);
+ }
+
+ // \brief Const reference to the value
+ //
+ // Const reference to the value of the \c Second type.
+ // \pre The BiVariant should store value of \c Second type.
+ const Second& second() const {
+ LEMON_DEBUG(!flag, "Variant wrong state");
+ return *reinterpret_cast<const Second*>(data);
+ }
+
+ // \brief Operator form of the \c second()
+ operator Second&() { return second(); }
+ // \brief Operator form of the const \c second()
+ operator const Second&() const { return second(); }
+
+ // \brief %True when the variant is in the first state
+ //
+ // %True when the variant stores value of the \c First type.
+ bool firstState() const { return flag; }
+
+ // \brief %True when the variant is in the second state
+ //
+ // %True when the variant stores value of the \c Second type.
+ bool secondState() const { return !flag; }
+
+ private:
+
+ void destroy() {
+ if (flag) {
+ reinterpret_cast<First*>(data)->~First();
+ } else {
+ reinterpret_cast<Second*>(data)->~Second();
+ }
+ }
+
+ char data[_variant_bits::CTMax<sizeof(First), sizeof(Second)>::value];
+ bool flag;
+ };
+
+ namespace _variant_bits {
+
+ template <int _idx, typename _TypeMap>
+ struct Memory {
+
+ typedef typename _TypeMap::template Map<_idx>::Type Current;
+
+ static void destroy(int index, char* place) {
+ if (index == _idx) {
+ reinterpret_cast<Current*>(place)->~Current();
+ } else {
+ Memory<_idx - 1, _TypeMap>::destroy(index, place);
+ }
+ }
+
+ static void copy(int index, char* to, const char* from) {
+ if (index == _idx) {
+ new (reinterpret_cast<Current*>(to))
+ Current(reinterpret_cast<const Current*>(from));
+ } else {
+ Memory<_idx - 1, _TypeMap>::copy(index, to, from);
+ }
+ }
+
+ };
+
+ template <typename _TypeMap>
+ struct Memory<-1, _TypeMap> {
+
+ static void destroy(int, char*) {
+ LEMON_DEBUG(false, "Variant wrong index.");
+ }
+
+ static void copy(int, char*, const char*) {
+ LEMON_DEBUG(false, "Variant wrong index.");
+ }
+ };
+
+ template <int _idx, typename _TypeMap>
+ struct Size {
+ static const int value =
+ CTMax<sizeof(typename _TypeMap::template Map<_idx>::Type),
+ Size<_idx - 1, _TypeMap>::value>::value;
+ };
+
+ template <typename _TypeMap>
+ struct Size<0, _TypeMap> {
+ static const int value =
+ sizeof(typename _TypeMap::template Map<0>::Type);
+ };
+
+ }
+
+ // \brief Variant type
+ //
+ // Simple Variant type. The Variant type is a type-safe union.
+ // C++ has strong limitations for using unions, for example you
+ // cannot store type with non-default constructor or destructor in
+ // a union. This class always knowns the current state of the
+ // variant and it cares for the proper construction and
+ // destruction.
+ //
+ // \param _num The number of the types which can be stored in the
+ // variant type.
+ // \param _TypeMap This class describes the types of the Variant. The
+ // _TypeMap::Map<index>::Type should be a valid type for each index
+ // in the range {0, 1, ..., _num - 1}. The \c VariantTypeMap is helper
+ // class to define such type mappings up to 10 types.
+ //
+ // And the usage of the class:
+ //\code
+ // typedef Variant<3, VariantTypeMap<int, std::string, double> > MyVariant;
+ // MyVariant var;
+ // var.set<0>(12);
+ // std::cout << var.get<0>() << std::endl;
+ // var.set<1>("alpha");
+ // std::cout << var.get<1>() << std::endl;
+ // var.set<2>(0.75);
+ // std::cout << var.get<2>() << std::endl;
+ //\endcode
+ //
+ // The result of course:
+ //\code
+ // 12
+ // alpha
+ // 0.75
+ //\endcode
+ template <int _num, typename _TypeMap>
+ class Variant {
+ public:
+
+ static const int num = _num;
+
+ typedef _TypeMap TypeMap;
+
+ // \brief Constructor
+ //
+ // This constructor initalizes to the default value of the \c type
+ // with 0 index.
+ Variant() {
+ flag = 0;
+ new(reinterpret_cast<typename TypeMap::template Map<0>::Type*>(data))
+ typename TypeMap::template Map<0>::Type();
+ }
+
+
+ // \brief Copy constructor
+ //
+ // Copy constructor
+ Variant(const Variant& variant) {
+ flag = variant.flag;
+ _variant_bits::Memory<num - 1, TypeMap>::copy(flag, data, variant.data);
+ }
+
+ // \brief Assign operator
+ //
+ // Assign operator
+ Variant& operator=(const Variant& variant) {
+ if (this == &variant) return *this;
+ _variant_bits::Memory<num - 1, TypeMap>::
+ destroy(flag, data);
+ flag = variant.flag;
+ _variant_bits::Memory<num - 1, TypeMap>::
+ copy(flag, data, variant.data);
+ return *this;
+ }
+
+ // \brief Destrcutor
+ //
+ // Destructor
+ ~Variant() {
+ _variant_bits::Memory<num - 1, TypeMap>::destroy(flag, data);
+ }
+
+ // \brief Set to the default value of the type with \c _idx index.
+ //
+ // This function sets the variant to the default value of the
+ // type with \c _idx index.
+ template <int _idx>
+ Variant& set() {
+ _variant_bits::Memory<num - 1, TypeMap>::destroy(flag, data);
+ flag = _idx;
+ new(reinterpret_cast<typename TypeMap::template Map<_idx>::Type*>(data))
+ typename TypeMap::template Map<_idx>::Type();
+ return *this;
+ }
+
+ // \brief Set to the given value of the type with \c _idx index.
+ //
+ // This function sets the variant to the given value of the type
+ // with \c _idx index.
+ template <int _idx>
+ Variant& set(const typename _TypeMap::template Map<_idx>::Type& init) {
+ _variant_bits::Memory<num - 1, TypeMap>::destroy(flag, data);
+ flag = _idx;
+ new(reinterpret_cast<typename TypeMap::template Map<_idx>::Type*>(data))
+ typename TypeMap::template Map<_idx>::Type(init);
+ return *this;
+ }
+
+ // \brief Gets the current value of the type with \c _idx index.
+ //
+ // Gets the current value of the type with \c _idx index.
+ template <int _idx>
+ const typename TypeMap::template Map<_idx>::Type& get() const {
+ LEMON_DEBUG(_idx == flag, "Variant wrong index");
+ return *reinterpret_cast<const typename TypeMap::
+ template Map<_idx>::Type*>(data);
+ }
+
+ // \brief Gets the current value of the type with \c _idx index.
+ //
+ // Gets the current value of the type with \c _idx index.
+ template <int _idx>
+ typename _TypeMap::template Map<_idx>::Type& get() {
+ LEMON_DEBUG(_idx == flag, "Variant wrong index");
+ return *reinterpret_cast<typename TypeMap::template Map<_idx>::Type*>
+ (data);
+ }
+
+ // \brief Returns the current state of the variant.
+ //
+ // Returns the current state of the variant.
+ int state() const {
+ return flag;
+ }
+
+ private:
+
+ char data[_variant_bits::Size<num - 1, TypeMap>::value];
+ int flag;
+ };
+
+ namespace _variant_bits {
+
+ template <int _index, typename _List>
+ struct Get {
+ typedef typename Get<_index - 1, typename _List::Next>::Type Type;
+ };
+
+ template <typename _List>
+ struct Get<0, _List> {
+ typedef typename _List::Type Type;
+ };
+
+ struct List {};
+
+ template <typename _Type, typename _List>
+ struct Insert {
+ typedef _List Next;
+ typedef _Type Type;
+ };
+
+ template <int _idx, typename _T0, typename _T1, typename _T2,
+ typename _T3, typename _T4, typename _T5, typename _T6,
+ typename _T7, typename _T8, typename _T9>
+ struct Mapper {
+ typedef List L10;
+ typedef Insert<_T9, L10> L9;
+ typedef Insert<_T8, L9> L8;
+ typedef Insert<_T7, L8> L7;
+ typedef Insert<_T6, L7> L6;
+ typedef Insert<_T5, L6> L5;
+ typedef Insert<_T4, L5> L4;
+ typedef Insert<_T3, L4> L3;
+ typedef Insert<_T2, L3> L2;
+ typedef Insert<_T1, L2> L1;
+ typedef Insert<_T0, L1> L0;
+ typedef typename Get<_idx, L0>::Type Type;
+ };
+
+ }
+
+ // \brief Helper class for Variant
+ //
+ // Helper class to define type mappings for Variant. This class
+ // converts the template parameters to be mappable by integer.
+ // \see Variant
+ template <
+ typename _T0,
+ typename _T1 = void, typename _T2 = void, typename _T3 = void,
+ typename _T4 = void, typename _T5 = void, typename _T6 = void,
+ typename _T7 = void, typename _T8 = void, typename _T9 = void>
+ struct VariantTypeMap {
+ template <int _idx>
+ struct Map {
+ typedef typename _variant_bits::
+ Mapper<_idx, _T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9>::Type
+ Type;
+ };
+ };
+
+}
+
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/vector_map.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/vector_map.h
new file mode 100644
index 00000000000..d60841defbd
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/vector_map.h
@@ -0,0 +1,244 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_BITS_VECTOR_MAP_H
+#define LEMON_BITS_VECTOR_MAP_H
+
+#include <vector>
+#include <algorithm>
+
+#include <lemon/core.h>
+#include <lemon/bits/alteration_notifier.h>
+
+#include <lemon/concept_check.h>
+#include <lemon/concepts/maps.h>
+
+//\ingroup graphbits
+//
+//\file
+//\brief Vector based graph maps.
+namespace lemon {
+
+ // \ingroup graphbits
+ //
+ // \brief Graph map based on the std::vector storage.
+ //
+ // The VectorMap template class is graph map structure that automatically
+ // updates the map when a key is added to or erased from the graph.
+ // This map type uses std::vector to store the values.
+ //
+ // \tparam _Graph The graph this map is attached to.
+ // \tparam _Item The item type of the graph items.
+ // \tparam _Value The value type of the map.
+ template <typename _Graph, typename _Item, typename _Value>
+ class VectorMap
+ : public ItemSetTraits<_Graph, _Item>::ItemNotifier::ObserverBase {
+ private:
+
+ // The container type of the map.
+ typedef std::vector<_Value> Container;
+
+ public:
+
+ // The graph type of the map.
+ typedef _Graph GraphType;
+ // The item type of the map.
+ typedef _Item Item;
+ // The reference map tag.
+ typedef True ReferenceMapTag;
+
+ // The key type of the map.
+ typedef _Item Key;
+ // The value type of the map.
+ typedef _Value Value;
+
+ // The notifier type.
+ typedef typename ItemSetTraits<_Graph, _Item>::ItemNotifier Notifier;
+
+ // The map type.
+ typedef VectorMap Map;
+
+ // The reference type of the map;
+ typedef typename Container::reference Reference;
+ // The const reference type of the map;
+ typedef typename Container::const_reference ConstReference;
+
+ private:
+
+ // The base class of the map.
+ typedef typename Notifier::ObserverBase Parent;
+
+ public:
+
+ // \brief Constructor to attach the new map into the notifier.
+ //
+ // It constructs a map and attachs it into the notifier.
+ // It adds all the items of the graph to the map.
+ VectorMap(const GraphType& graph) {
+ Parent::attach(graph.notifier(Item()));
+ container.resize(Parent::notifier()->maxId() + 1);
+ }
+
+ // \brief Constructor uses given value to initialize the map.
+ //
+ // It constructs a map uses a given value to initialize the map.
+ // It adds all the items of the graph to the map.
+ VectorMap(const GraphType& graph, const Value& value) {
+ Parent::attach(graph.notifier(Item()));
+ container.resize(Parent::notifier()->maxId() + 1, value);
+ }
+
+ private:
+ // \brief Copy constructor
+ //
+ // Copy constructor.
+ VectorMap(const VectorMap& _copy) : Parent() {
+ if (_copy.attached()) {
+ Parent::attach(*_copy.notifier());
+ container = _copy.container;
+ }
+ }
+
+ // \brief Assign operator.
+ //
+ // This operator assigns for each item in the map the
+ // value mapped to the same item in the copied map.
+ // The parameter map should be indiced with the same
+ // itemset because this assign operator does not change
+ // the container of the map.
+ VectorMap& operator=(const VectorMap& cmap) {
+ return operator=<VectorMap>(cmap);
+ }
+
+
+ // \brief Template assign operator.
+ //
+ // The given parameter should conform to the ReadMap
+ // concecpt and could be indiced by the current item set of
+ // the NodeMap. In this case the value for each item
+ // is assigned by the value of the given ReadMap.
+ template <typename CMap>
+ VectorMap& operator=(const CMap& cmap) {
+ checkConcept<concepts::ReadMap<Key, _Value>, CMap>();
+ const typename Parent::Notifier* nf = Parent::notifier();
+ Item it;
+ for (nf->first(it); it != INVALID; nf->next(it)) {
+ set(it, cmap[it]);
+ }
+ return *this;
+ }
+
+ public:
+
+ // \brief The subcript operator.
+ //
+ // The subscript operator. The map can be subscripted by the
+ // actual items of the graph.
+ Reference operator[](const Key& key) {
+ return container[Parent::notifier()->id(key)];
+ }
+
+ // \brief The const subcript operator.
+ //
+ // The const subscript operator. The map can be subscripted by the
+ // actual items of the graph.
+ ConstReference operator[](const Key& key) const {
+ return container[Parent::notifier()->id(key)];
+ }
+
+
+ // \brief The setter function of the map.
+ //
+ // It the same as operator[](key) = value expression.
+ void set(const Key& key, const Value& value) {
+ (*this)[key] = value;
+ }
+
+ protected:
+
+ // \brief Adds a new key to the map.
+ //
+ // It adds a new key to the map. It is called by the observer notifier
+ // and it overrides the add() member function of the observer base.
+ virtual void add(const Key& key) {
+ int id = Parent::notifier()->id(key);
+ if (id >= int(container.size())) {
+ container.resize(id + 1);
+ }
+ }
+
+ // \brief Adds more new keys to the map.
+ //
+ // It adds more new keys to the map. It is called by the observer notifier
+ // and it overrides the add() member function of the observer base.
+ virtual void add(const std::vector<Key>& keys) {
+ int max = container.size() - 1;
+ for (int i = 0; i < int(keys.size()); ++i) {
+ int id = Parent::notifier()->id(keys[i]);
+ if (id >= max) {
+ max = id;
+ }
+ }
+ container.resize(max + 1);
+ }
+
+ // \brief Erase a key from the map.
+ //
+ // Erase a key from the map. It is called by the observer notifier
+ // and it overrides the erase() member function of the observer base.
+ virtual void erase(const Key& key) {
+ container[Parent::notifier()->id(key)] = Value();
+ }
+
+ // \brief Erase more keys from the map.
+ //
+ // It erases more keys from the map. It is called by the observer notifier
+ // and it overrides the erase() member function of the observer base.
+ virtual void erase(const std::vector<Key>& keys) {
+ for (int i = 0; i < int(keys.size()); ++i) {
+ container[Parent::notifier()->id(keys[i])] = Value();
+ }
+ }
+
+ // \brief Build the map.
+ //
+ // It builds the map. It is called by the observer notifier
+ // and it overrides the build() member function of the observer base.
+ virtual void build() {
+ int size = Parent::notifier()->maxId() + 1;
+ container.reserve(size);
+ container.resize(size);
+ }
+
+ // \brief Clear the map.
+ //
+ // It erases all items from the map. It is called by the observer notifier
+ // and it overrides the clear() member function of the observer base.
+ virtual void clear() {
+ container.clear();
+ }
+
+ private:
+
+ Container container;
+
+ };
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/windows.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/windows.cc
new file mode 100644
index 00000000000..7ad901c619c
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/windows.cc
@@ -0,0 +1,166 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+///\file
+///\brief Some basic non-inline functions and static global data.
+
+#include<lemon/bits/windows.h>
+
+#ifdef WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#ifdef UNICODE
+#undef UNICODE
+#endif
+#include <windows.h>
+#ifdef LOCALE_INVARIANT
+#define MY_LOCALE LOCALE_INVARIANT
+#else
+#define MY_LOCALE LOCALE_NEUTRAL
+#endif
+#else
+#include <unistd.h>
+#include <ctime>
+#ifndef WIN32
+#include <sys/times.h>
+#endif
+#include <sys/time.h>
+#endif
+
+#include <cmath>
+#include <sstream>
+
+namespace lemon {
+ namespace bits {
+ void getWinProcTimes(double &rtime,
+ double &utime, double &stime,
+ double &cutime, double &cstime)
+ {
+#ifdef WIN32
+ static const double ch = 4294967296.0e-7;
+ static const double cl = 1.0e-7;
+
+ FILETIME system;
+ GetSystemTimeAsFileTime(&system);
+ rtime = ch * system.dwHighDateTime + cl * system.dwLowDateTime;
+
+ FILETIME create, exit, kernel, user;
+ if (GetProcessTimes(GetCurrentProcess(),&create, &exit, &kernel, &user)) {
+ utime = ch * user.dwHighDateTime + cl * user.dwLowDateTime;
+ stime = ch * kernel.dwHighDateTime + cl * kernel.dwLowDateTime;
+ cutime = 0;
+ cstime = 0;
+ } else {
+ rtime = 0;
+ utime = 0;
+ stime = 0;
+ cutime = 0;
+ cstime = 0;
+ }
+#else
+ timeval tv;
+ gettimeofday(&tv, 0);
+ rtime=tv.tv_sec+double(tv.tv_usec)/1e6;
+
+ tms ts;
+ double tck=sysconf(_SC_CLK_TCK);
+ times(&ts);
+ utime=ts.tms_utime/tck;
+ stime=ts.tms_stime/tck;
+ cutime=ts.tms_cutime/tck;
+ cstime=ts.tms_cstime/tck;
+#endif
+ }
+
+ std::string getWinFormattedDate()
+ {
+ std::ostringstream os;
+#ifdef WIN32
+ SYSTEMTIME time;
+ GetSystemTime(&time);
+ char buf1[11], buf2[9], buf3[5];
+ if (GetDateFormat(MY_LOCALE, 0, &time,
+ ("ddd MMM dd"), buf1, 11) &&
+ GetTimeFormat(MY_LOCALE, 0, &time,
+ ("HH':'mm':'ss"), buf2, 9) &&
+ GetDateFormat(MY_LOCALE, 0, &time,
+ ("yyyy"), buf3, 5)) {
+ os << buf1 << ' ' << buf2 << ' ' << buf3;
+ }
+ else os << "unknown";
+#else
+ timeval tv;
+ gettimeofday(&tv, 0);
+
+ char cbuf[26];
+ ctime_r(&tv.tv_sec,cbuf);
+ os << cbuf;
+#endif
+ return os.str();
+ }
+
+ int getWinRndSeed()
+ {
+#ifdef WIN32
+ FILETIME time;
+ GetSystemTimeAsFileTime(&time);
+ return GetCurrentProcessId() + time.dwHighDateTime + time.dwLowDateTime;
+#else
+ timeval tv;
+ gettimeofday(&tv, 0);
+ return getpid() + tv.tv_sec + tv.tv_usec;
+#endif
+ }
+
+ WinLock::WinLock() {
+#ifdef WIN32
+ CRITICAL_SECTION *lock = new CRITICAL_SECTION;
+ InitializeCriticalSection(lock);
+ _repr = lock;
+#else
+ _repr = 0; //Just to avoid 'unused variable' warning with clang
+#endif
+ }
+
+ WinLock::~WinLock() {
+#ifdef WIN32
+ CRITICAL_SECTION *lock = static_cast<CRITICAL_SECTION*>(_repr);
+ DeleteCriticalSection(lock);
+ delete lock;
+#endif
+ }
+
+ void WinLock::lock() {
+#ifdef WIN32
+ CRITICAL_SECTION *lock = static_cast<CRITICAL_SECTION*>(_repr);
+ EnterCriticalSection(lock);
+#endif
+ }
+
+ void WinLock::unlock() {
+#ifdef WIN32
+ CRITICAL_SECTION *lock = static_cast<CRITICAL_SECTION*>(_repr);
+ LeaveCriticalSection(lock);
+#endif
+ }
+ }
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/windows.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/windows.h
new file mode 100644
index 00000000000..c09bb1284c5
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/windows.h
@@ -0,0 +1,44 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_BITS_WINDOWS_H
+#define LEMON_BITS_WINDOWS_H
+
+#include <string>
+
+namespace lemon {
+ namespace bits {
+ void getWinProcTimes(double &rtime,
+ double &utime, double &stime,
+ double &cutime, double &cstime);
+ std::string getWinFormattedDate();
+ int getWinRndSeed();
+
+ class WinLock {
+ public:
+ WinLock();
+ ~WinLock();
+ void lock();
+ void unlock();
+ private:
+ void *_repr;
+ };
+ }
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bucket_heap.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bucket_heap.h
new file mode 100644
index 00000000000..92dbc08f011
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bucket_heap.h
@@ -0,0 +1,594 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2010
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_BUCKET_HEAP_H
+#define LEMON_BUCKET_HEAP_H
+
+///\ingroup heaps
+///\file
+///\brief Bucket heap implementation.
+
+#include <vector>
+#include <utility>
+#include <functional>
+
+namespace lemon {
+
+ namespace _bucket_heap_bits {
+
+ template <bool MIN>
+ struct DirectionTraits {
+ static bool less(int left, int right) {
+ return left < right;
+ }
+ static void increase(int& value) {
+ ++value;
+ }
+ };
+
+ template <>
+ struct DirectionTraits<false> {
+ static bool less(int left, int right) {
+ return left > right;
+ }
+ static void increase(int& value) {
+ --value;
+ }
+ };
+
+ }
+
+ /// \ingroup heaps
+ ///
+ /// \brief Bucket heap data structure.
+ ///
+ /// This class implements the \e bucket \e heap data structure.
+ /// It practically conforms to the \ref concepts::Heap "heap concept",
+ /// but it has some limitations.
+ ///
+ /// The bucket heap is a very simple structure. It can store only
+ /// \c int priorities and it maintains a list of items for each priority
+ /// in the range <tt>[0..C)</tt>. So it should only be used when the
+ /// priorities are small. It is not intended to use as a Dijkstra heap.
+ ///
+ /// \tparam IM A read-writable item map with \c int values, used
+ /// internally to handle the cross references.
+ /// \tparam MIN Indicate if the heap is a \e min-heap or a \e max-heap.
+ /// The default is \e min-heap. If this parameter is set to \c false,
+ /// then the comparison is reversed, so the top(), prio() and pop()
+ /// functions deal with the item having maximum priority instead of the
+ /// minimum.
+ ///
+ /// \sa SimpleBucketHeap
+ template <typename IM, bool MIN = true>
+ class BucketHeap {
+
+ public:
+
+ /// Type of the item-int map.
+ typedef IM ItemIntMap;
+ /// Type of the priorities.
+ typedef int Prio;
+ /// Type of the items stored in the heap.
+ typedef typename ItemIntMap::Key Item;
+ /// Type of the item-priority pairs.
+ typedef std::pair<Item,Prio> Pair;
+
+ private:
+
+ typedef _bucket_heap_bits::DirectionTraits<MIN> Direction;
+
+ public:
+
+ /// \brief Type to represent the states of the items.
+ ///
+ /// Each item has a state associated to it. It can be "in heap",
+ /// "pre-heap" or "post-heap". The latter two are indifferent from the
+ /// heap's point of view, but may be useful to the user.
+ ///
+ /// The item-int map must be initialized in such way that it assigns
+ /// \c PRE_HEAP (<tt>-1</tt>) to any element to be put in the heap.
+ enum State {
+ IN_HEAP = 0, ///< = 0.
+ PRE_HEAP = -1, ///< = -1.
+ POST_HEAP = -2 ///< = -2.
+ };
+
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ /// \param map A map that assigns \c int values to the items.
+ /// It is used internally to handle the cross references.
+ /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
+ explicit BucketHeap(ItemIntMap &map) : _iim(map), _minimum(0) {}
+
+ /// \brief The number of items stored in the heap.
+ ///
+ /// This function returns the number of items stored in the heap.
+ int size() const { return _data.size(); }
+
+ /// \brief Check if the heap is empty.
+ ///
+ /// This function returns \c true if the heap is empty.
+ bool empty() const { return _data.empty(); }
+
+ /// \brief Make the heap empty.
+ ///
+ /// This functon makes the heap empty.
+ /// It does not change the cross reference map. If you want to reuse
+ /// a heap that is not surely empty, you should first clear it and
+ /// then you should set the cross reference map to \c PRE_HEAP
+ /// for each item.
+ void clear() {
+ _data.clear(); _first.clear(); _minimum = 0;
+ }
+
+ private:
+
+ void relocateLast(int idx) {
+ if (idx + 1 < int(_data.size())) {
+ _data[idx] = _data.back();
+ if (_data[idx].prev != -1) {
+ _data[_data[idx].prev].next = idx;
+ } else {
+ _first[_data[idx].value] = idx;
+ }
+ if (_data[idx].next != -1) {
+ _data[_data[idx].next].prev = idx;
+ }
+ _iim[_data[idx].item] = idx;
+ }
+ _data.pop_back();
+ }
+
+ void unlace(int idx) {
+ if (_data[idx].prev != -1) {
+ _data[_data[idx].prev].next = _data[idx].next;
+ } else {
+ _first[_data[idx].value] = _data[idx].next;
+ }
+ if (_data[idx].next != -1) {
+ _data[_data[idx].next].prev = _data[idx].prev;
+ }
+ }
+
+ void lace(int idx) {
+ if (int(_first.size()) <= _data[idx].value) {
+ _first.resize(_data[idx].value + 1, -1);
+ }
+ _data[idx].next = _first[_data[idx].value];
+ if (_data[idx].next != -1) {
+ _data[_data[idx].next].prev = idx;
+ }
+ _first[_data[idx].value] = idx;
+ _data[idx].prev = -1;
+ }
+
+ public:
+
+ /// \brief Insert a pair of item and priority into the heap.
+ ///
+ /// This function inserts \c p.first to the heap with priority
+ /// \c p.second.
+ /// \param p The pair to insert.
+ /// \pre \c p.first must not be stored in the heap.
+ void push(const Pair& p) {
+ push(p.first, p.second);
+ }
+
+ /// \brief Insert an item into the heap with the given priority.
+ ///
+ /// This function inserts the given item into the heap with the
+ /// given priority.
+ /// \param i The item to insert.
+ /// \param p The priority of the item.
+ /// \pre \e i must not be stored in the heap.
+ void push(const Item &i, const Prio &p) {
+ int idx = _data.size();
+ _iim[i] = idx;
+ _data.push_back(BucketItem(i, p));
+ lace(idx);
+ if (Direction::less(p, _minimum)) {
+ _minimum = p;
+ }
+ }
+
+ /// \brief Return the item having minimum priority.
+ ///
+ /// This function returns the item having minimum priority.
+ /// \pre The heap must be non-empty.
+ Item top() const {
+ while (_first[_minimum] == -1) {
+ Direction::increase(_minimum);
+ }
+ return _data[_first[_minimum]].item;
+ }
+
+ /// \brief The minimum priority.
+ ///
+ /// This function returns the minimum priority.
+ /// \pre The heap must be non-empty.
+ Prio prio() const {
+ while (_first[_minimum] == -1) {
+ Direction::increase(_minimum);
+ }
+ return _minimum;
+ }
+
+ /// \brief Remove the item having minimum priority.
+ ///
+ /// This function removes the item having minimum priority.
+ /// \pre The heap must be non-empty.
+ void pop() {
+ while (_first[_minimum] == -1) {
+ Direction::increase(_minimum);
+ }
+ int idx = _first[_minimum];
+ _iim[_data[idx].item] = -2;
+ unlace(idx);
+ relocateLast(idx);
+ }
+
+ /// \brief Remove the given item from the heap.
+ ///
+ /// This function removes the given item from the heap if it is
+ /// already stored.
+ /// \param i The item to delete.
+ /// \pre \e i must be in the heap.
+ void erase(const Item &i) {
+ int idx = _iim[i];
+ _iim[_data[idx].item] = -2;
+ unlace(idx);
+ relocateLast(idx);
+ }
+
+ /// \brief The priority of the given item.
+ ///
+ /// This function returns the priority of the given item.
+ /// \param i The item.
+ /// \pre \e i must be in the heap.
+ Prio operator[](const Item &i) const {
+ int idx = _iim[i];
+ return _data[idx].value;
+ }
+
+ /// \brief Set the priority of an item or insert it, if it is
+ /// not stored in the heap.
+ ///
+ /// This method sets the priority of the given item if it is
+ /// already stored in the heap. Otherwise it inserts the given
+ /// item into the heap with the given priority.
+ /// \param i The item.
+ /// \param p The priority.
+ void set(const Item &i, const Prio &p) {
+ int idx = _iim[i];
+ if (idx < 0) {
+ push(i, p);
+ } else if (Direction::less(p, _data[idx].value)) {
+ decrease(i, p);
+ } else {
+ increase(i, p);
+ }
+ }
+
+ /// \brief Decrease the priority of an item to the given value.
+ ///
+ /// This function decreases the priority of an item to the given value.
+ /// \param i The item.
+ /// \param p The priority.
+ /// \pre \e i must be stored in the heap with priority at least \e p.
+ void decrease(const Item &i, const Prio &p) {
+ int idx = _iim[i];
+ unlace(idx);
+ _data[idx].value = p;
+ if (Direction::less(p, _minimum)) {
+ _minimum = p;
+ }
+ lace(idx);
+ }
+
+ /// \brief Increase the priority of an item to the given value.
+ ///
+ /// This function increases the priority of an item to the given value.
+ /// \param i The item.
+ /// \param p The priority.
+ /// \pre \e i must be stored in the heap with priority at most \e p.
+ void increase(const Item &i, const Prio &p) {
+ int idx = _iim[i];
+ unlace(idx);
+ _data[idx].value = p;
+ lace(idx);
+ }
+
+ /// \brief Return the state of an item.
+ ///
+ /// This method returns \c PRE_HEAP if the given item has never
+ /// been in the heap, \c IN_HEAP if it is in the heap at the moment,
+ /// and \c POST_HEAP otherwise.
+ /// In the latter case it is possible that the item will get back
+ /// to the heap again.
+ /// \param i The item.
+ State state(const Item &i) const {
+ int idx = _iim[i];
+ if (idx >= 0) idx = 0;
+ return State(idx);
+ }
+
+ /// \brief Set the state of an item in the heap.
+ ///
+ /// This function sets the state of the given item in the heap.
+ /// It can be used to manually clear the heap when it is important
+ /// to achive better time complexity.
+ /// \param i The item.
+ /// \param st The state. It should not be \c IN_HEAP.
+ void state(const Item& i, State st) {
+ switch (st) {
+ case POST_HEAP:
+ case PRE_HEAP:
+ if (state(i) == IN_HEAP) {
+ erase(i);
+ }
+ _iim[i] = st;
+ break;
+ case IN_HEAP:
+ break;
+ }
+ }
+
+ private:
+
+ struct BucketItem {
+ BucketItem(const Item& _item, int _value)
+ : item(_item), value(_value) {}
+
+ Item item;
+ int value;
+
+ int prev, next;
+ };
+
+ ItemIntMap& _iim;
+ std::vector<int> _first;
+ std::vector<BucketItem> _data;
+ mutable int _minimum;
+
+ }; // class BucketHeap
+
+ /// \ingroup heaps
+ ///
+ /// \brief Simplified bucket heap data structure.
+ ///
+ /// This class implements a simplified \e bucket \e heap data
+ /// structure. It does not provide some functionality, but it is
+ /// faster and simpler than BucketHeap. The main difference is
+ /// that BucketHeap stores a doubly-linked list for each key while
+ /// this class stores only simply-linked lists. It supports erasing
+ /// only for the item having minimum priority and it does not support
+ /// key increasing and decreasing.
+ ///
+ /// Note that this implementation does not conform to the
+ /// \ref concepts::Heap "heap concept" due to the lack of some
+ /// functionality.
+ ///
+ /// \tparam IM A read-writable item map with \c int values, used
+ /// internally to handle the cross references.
+ /// \tparam MIN Indicate if the heap is a \e min-heap or a \e max-heap.
+ /// The default is \e min-heap. If this parameter is set to \c false,
+ /// then the comparison is reversed, so the top(), prio() and pop()
+ /// functions deal with the item having maximum priority instead of the
+ /// minimum.
+ ///
+ /// \sa BucketHeap
+ template <typename IM, bool MIN = true >
+ class SimpleBucketHeap {
+
+ public:
+
+ /// Type of the item-int map.
+ typedef IM ItemIntMap;
+ /// Type of the priorities.
+ typedef int Prio;
+ /// Type of the items stored in the heap.
+ typedef typename ItemIntMap::Key Item;
+ /// Type of the item-priority pairs.
+ typedef std::pair<Item,Prio> Pair;
+
+ private:
+
+ typedef _bucket_heap_bits::DirectionTraits<MIN> Direction;
+
+ public:
+
+ /// \brief Type to represent the states of the items.
+ ///
+ /// Each item has a state associated to it. It can be "in heap",
+ /// "pre-heap" or "post-heap". The latter two are indifferent from the
+ /// heap's point of view, but may be useful to the user.
+ ///
+ /// The item-int map must be initialized in such way that it assigns
+ /// \c PRE_HEAP (<tt>-1</tt>) to any element to be put in the heap.
+ enum State {
+ IN_HEAP = 0, ///< = 0.
+ PRE_HEAP = -1, ///< = -1.
+ POST_HEAP = -2 ///< = -2.
+ };
+
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ /// \param map A map that assigns \c int values to the items.
+ /// It is used internally to handle the cross references.
+ /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
+ explicit SimpleBucketHeap(ItemIntMap &map)
+ : _iim(map), _free(-1), _num(0), _minimum(0) {}
+
+ /// \brief The number of items stored in the heap.
+ ///
+ /// This function returns the number of items stored in the heap.
+ int size() const { return _num; }
+
+ /// \brief Check if the heap is empty.
+ ///
+ /// This function returns \c true if the heap is empty.
+ bool empty() const { return _num == 0; }
+
+ /// \brief Make the heap empty.
+ ///
+ /// This functon makes the heap empty.
+ /// It does not change the cross reference map. If you want to reuse
+ /// a heap that is not surely empty, you should first clear it and
+ /// then you should set the cross reference map to \c PRE_HEAP
+ /// for each item.
+ void clear() {
+ _data.clear(); _first.clear(); _free = -1; _num = 0; _minimum = 0;
+ }
+
+ /// \brief Insert a pair of item and priority into the heap.
+ ///
+ /// This function inserts \c p.first to the heap with priority
+ /// \c p.second.
+ /// \param p The pair to insert.
+ /// \pre \c p.first must not be stored in the heap.
+ void push(const Pair& p) {
+ push(p.first, p.second);
+ }
+
+ /// \brief Insert an item into the heap with the given priority.
+ ///
+ /// This function inserts the given item into the heap with the
+ /// given priority.
+ /// \param i The item to insert.
+ /// \param p The priority of the item.
+ /// \pre \e i must not be stored in the heap.
+ void push(const Item &i, const Prio &p) {
+ int idx;
+ if (_free == -1) {
+ idx = _data.size();
+ _data.push_back(BucketItem(i));
+ } else {
+ idx = _free;
+ _free = _data[idx].next;
+ _data[idx].item = i;
+ }
+ _iim[i] = idx;
+ if (p >= int(_first.size())) _first.resize(p + 1, -1);
+ _data[idx].next = _first[p];
+ _first[p] = idx;
+ if (Direction::less(p, _minimum)) {
+ _minimum = p;
+ }
+ ++_num;
+ }
+
+ /// \brief Return the item having minimum priority.
+ ///
+ /// This function returns the item having minimum priority.
+ /// \pre The heap must be non-empty.
+ Item top() const {
+ while (_first[_minimum] == -1) {
+ Direction::increase(_minimum);
+ }
+ return _data[_first[_minimum]].item;
+ }
+
+ /// \brief The minimum priority.
+ ///
+ /// This function returns the minimum priority.
+ /// \pre The heap must be non-empty.
+ Prio prio() const {
+ while (_first[_minimum] == -1) {
+ Direction::increase(_minimum);
+ }
+ return _minimum;
+ }
+
+ /// \brief Remove the item having minimum priority.
+ ///
+ /// This function removes the item having minimum priority.
+ /// \pre The heap must be non-empty.
+ void pop() {
+ while (_first[_minimum] == -1) {
+ Direction::increase(_minimum);
+ }
+ int idx = _first[_minimum];
+ _iim[_data[idx].item] = -2;
+ _first[_minimum] = _data[idx].next;
+ _data[idx].next = _free;
+ _free = idx;
+ --_num;
+ }
+
+ /// \brief The priority of the given item.
+ ///
+ /// This function returns the priority of the given item.
+ /// \param i The item.
+ /// \pre \e i must be in the heap.
+ /// \warning This operator is not a constant time function because
+ /// it scans the whole data structure to find the proper value.
+ Prio operator[](const Item &i) const {
+ for (int k = 0; k < int(_first.size()); ++k) {
+ int idx = _first[k];
+ while (idx != -1) {
+ if (_data[idx].item == i) {
+ return k;
+ }
+ idx = _data[idx].next;
+ }
+ }
+ return -1;
+ }
+
+ /// \brief Return the state of an item.
+ ///
+ /// This method returns \c PRE_HEAP if the given item has never
+ /// been in the heap, \c IN_HEAP if it is in the heap at the moment,
+ /// and \c POST_HEAP otherwise.
+ /// In the latter case it is possible that the item will get back
+ /// to the heap again.
+ /// \param i The item.
+ State state(const Item &i) const {
+ int idx = _iim[i];
+ if (idx >= 0) idx = 0;
+ return State(idx);
+ }
+
+ private:
+
+ struct BucketItem {
+ BucketItem(const Item& _item)
+ : item(_item) {}
+
+ Item item;
+ int next;
+ };
+
+ ItemIntMap& _iim;
+ std::vector<int> _first;
+ std::vector<BucketItem> _data;
+ int _free, _num;
+ mutable int _minimum;
+
+ }; // class SimpleBucketHeap
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/capacity_scaling.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/capacity_scaling.h
new file mode 100644
index 00000000000..ca64b56d3b3
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/capacity_scaling.h
@@ -0,0 +1,1014 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_CAPACITY_SCALING_H
+#define LEMON_CAPACITY_SCALING_H
+
+/// \ingroup min_cost_flow_algs
+///
+/// \file
+/// \brief Capacity Scaling algorithm for finding a minimum cost flow.
+
+#include <vector>
+#include <limits>
+#include <lemon/core.h>
+#include <lemon/bin_heap.h>
+
+namespace lemon {
+
+ /// \brief Default traits class of CapacityScaling algorithm.
+ ///
+ /// Default traits class of CapacityScaling algorithm.
+ /// \tparam GR Digraph type.
+ /// \tparam V The number type used for flow amounts, capacity bounds
+ /// and supply values. By default it is \c int.
+ /// \tparam C The number type used for costs and potentials.
+ /// By default it is the same as \c V.
+ template <typename GR, typename V = int, typename C = V>
+ struct CapacityScalingDefaultTraits
+ {
+ /// The type of the digraph
+ typedef GR Digraph;
+ /// The type of the flow amounts, capacity bounds and supply values
+ typedef V Value;
+ /// The type of the arc costs
+ typedef C Cost;
+
+ /// \brief The type of the heap used for internal Dijkstra computations.
+ ///
+ /// The type of the heap used for internal Dijkstra computations.
+ /// It must conform to the \ref lemon::concepts::Heap "Heap" concept,
+ /// its priority type must be \c Cost and its cross reference type
+ /// must be \ref RangeMap "RangeMap<int>".
+ typedef BinHeap<Cost, RangeMap<int> > Heap;
+ };
+
+ /// \addtogroup min_cost_flow_algs
+ /// @{
+
+ /// \brief Implementation of the Capacity Scaling algorithm for
+ /// finding a \ref min_cost_flow "minimum cost flow".
+ ///
+ /// \ref CapacityScaling implements the capacity scaling version
+ /// of the successive shortest path algorithm for finding a
+ /// \ref min_cost_flow "minimum cost flow" \cite amo93networkflows,
+ /// \cite edmondskarp72theoretical. It is an efficient dual
+ /// solution method, which runs in polynomial time
+ /// \f$O(m\log U (n+m)\log n)\f$, where <i>U</i> denotes the maximum
+ /// of node supply and arc capacity values.
+ ///
+ /// This algorithm is typically slower than \ref CostScaling and
+ /// \ref NetworkSimplex, but in special cases, it can be more
+ /// efficient than them.
+ /// (For more information, see \ref min_cost_flow_algs "the module page".)
+ ///
+ /// Most of the parameters of the problem (except for the digraph)
+ /// can be given using separate functions, and the algorithm can be
+ /// executed using the \ref run() function. If some parameters are not
+ /// specified, then default values will be used.
+ ///
+ /// \tparam GR The digraph type the algorithm runs on.
+ /// \tparam V The number type used for flow amounts, capacity bounds
+ /// and supply values in the algorithm. By default, it is \c int.
+ /// \tparam C The number type used for costs and potentials in the
+ /// algorithm. By default, it is the same as \c V.
+ /// \tparam TR The traits class that defines various types used by the
+ /// algorithm. By default, it is \ref CapacityScalingDefaultTraits
+ /// "CapacityScalingDefaultTraits<GR, V, C>".
+ /// In most cases, this parameter should not be set directly,
+ /// consider to use the named template parameters instead.
+ ///
+ /// \warning Both \c V and \c C must be signed number types.
+ /// \warning Capacity bounds and supply values must be integer, but
+ /// arc costs can be arbitrary real numbers.
+ /// \warning This algorithm does not support negative costs for
+ /// arcs having infinite upper bound.
+#ifdef DOXYGEN
+ template <typename GR, typename V, typename C, typename TR>
+#else
+ template < typename GR, typename V = int, typename C = V,
+ typename TR = CapacityScalingDefaultTraits<GR, V, C> >
+#endif
+ class CapacityScaling
+ {
+ public:
+
+ /// The type of the digraph
+ typedef typename TR::Digraph Digraph;
+ /// The type of the flow amounts, capacity bounds and supply values
+ typedef typename TR::Value Value;
+ /// The type of the arc costs
+ typedef typename TR::Cost Cost;
+
+ /// The type of the heap used for internal Dijkstra computations
+ typedef typename TR::Heap Heap;
+
+ /// \brief The \ref lemon::CapacityScalingDefaultTraits "traits class"
+ /// of the algorithm
+ typedef TR Traits;
+
+ public:
+
+ /// \brief Problem type constants for the \c run() function.
+ ///
+ /// Enum type containing the problem type constants that can be
+ /// returned by the \ref run() function of the algorithm.
+ enum ProblemType {
+ /// The problem has no feasible solution (flow).
+ INFEASIBLE,
+ /// The problem has optimal solution (i.e. it is feasible and
+ /// bounded), and the algorithm has found optimal flow and node
+ /// potentials (primal and dual solutions).
+ OPTIMAL,
+ /// The digraph contains an arc of negative cost and infinite
+ /// upper bound. It means that the objective function is unbounded
+ /// on that arc, however, note that it could actually be bounded
+ /// over the feasible flows, but this algroithm cannot handle
+ /// these cases.
+ UNBOUNDED
+ };
+
+ private:
+
+ TEMPLATE_DIGRAPH_TYPEDEFS(GR);
+
+ typedef std::vector<int> IntVector;
+ typedef std::vector<Value> ValueVector;
+ typedef std::vector<Cost> CostVector;
+ typedef std::vector<char> BoolVector;
+ // Note: vector<char> is used instead of vector<bool> for efficiency reasons
+
+ private:
+
+ // Data related to the underlying digraph
+ const GR &_graph;
+ int _node_num;
+ int _arc_num;
+ int _res_arc_num;
+ int _root;
+
+ // Parameters of the problem
+ bool _has_lower;
+ Value _sum_supply;
+
+ // Data structures for storing the digraph
+ IntNodeMap _node_id;
+ IntArcMap _arc_idf;
+ IntArcMap _arc_idb;
+ IntVector _first_out;
+ BoolVector _forward;
+ IntVector _source;
+ IntVector _target;
+ IntVector _reverse;
+
+ // Node and arc data
+ ValueVector _lower;
+ ValueVector _upper;
+ CostVector _cost;
+ ValueVector _supply;
+
+ ValueVector _res_cap;
+ CostVector _pi;
+ ValueVector _excess;
+ IntVector _excess_nodes;
+ IntVector _deficit_nodes;
+
+ Value _delta;
+ int _factor;
+ IntVector _pred;
+
+ public:
+
+ /// \brief Constant for infinite upper bounds (capacities).
+ ///
+ /// Constant for infinite upper bounds (capacities).
+ /// It is \c std::numeric_limits<Value>::infinity() if available,
+ /// \c std::numeric_limits<Value>::max() otherwise.
+ const Value INF;
+
+ private:
+
+ // Special implementation of the Dijkstra algorithm for finding
+ // shortest paths in the residual network of the digraph with
+ // respect to the reduced arc costs and modifying the node
+ // potentials according to the found distance labels.
+ class ResidualDijkstra
+ {
+ private:
+
+ int _node_num;
+ bool _geq;
+ const IntVector &_first_out;
+ const IntVector &_target;
+ const CostVector &_cost;
+ const ValueVector &_res_cap;
+ const ValueVector &_excess;
+ CostVector &_pi;
+ IntVector &_pred;
+
+ IntVector _proc_nodes;
+ CostVector _dist;
+
+ public:
+
+ ResidualDijkstra(CapacityScaling& cs) :
+ _node_num(cs._node_num), _geq(cs._sum_supply < 0),
+ _first_out(cs._first_out), _target(cs._target), _cost(cs._cost),
+ _res_cap(cs._res_cap), _excess(cs._excess), _pi(cs._pi),
+ _pred(cs._pred), _dist(cs._node_num)
+ {}
+
+ int run(int s, Value delta = 1) {
+ RangeMap<int> heap_cross_ref(_node_num, Heap::PRE_HEAP);
+ Heap heap(heap_cross_ref);
+ heap.push(s, 0);
+ _pred[s] = -1;
+ _proc_nodes.clear();
+
+ // Process nodes
+ while (!heap.empty() && _excess[heap.top()] > -delta) {
+ int u = heap.top(), v;
+ Cost d = heap.prio() + _pi[u], dn;
+ _dist[u] = heap.prio();
+ _proc_nodes.push_back(u);
+ heap.pop();
+
+ // Traverse outgoing residual arcs
+ int last_out = _geq ? _first_out[u+1] : _first_out[u+1] - 1;
+ for (int a = _first_out[u]; a != last_out; ++a) {
+ if (_res_cap[a] < delta) continue;
+ v = _target[a];
+ switch (heap.state(v)) {
+ case Heap::PRE_HEAP:
+ heap.push(v, d + _cost[a] - _pi[v]);
+ _pred[v] = a;
+ break;
+ case Heap::IN_HEAP:
+ dn = d + _cost[a] - _pi[v];
+ if (dn < heap[v]) {
+ heap.decrease(v, dn);
+ _pred[v] = a;
+ }
+ break;
+ case Heap::POST_HEAP:
+ break;
+ }
+ }
+ }
+ if (heap.empty()) return -1;
+
+ // Update potentials of processed nodes
+ int t = heap.top();
+ Cost dt = heap.prio();
+ for (int i = 0; i < int(_proc_nodes.size()); ++i) {
+ _pi[_proc_nodes[i]] += _dist[_proc_nodes[i]] - dt;
+ }
+
+ return t;
+ }
+
+ }; //class ResidualDijkstra
+
+ public:
+
+ /// \name Named Template Parameters
+ /// @{
+
+ template <typename T>
+ struct SetHeapTraits : public Traits {
+ typedef T Heap;
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// \c Heap type.
+ ///
+ /// \ref named-templ-param "Named parameter" for setting \c Heap
+ /// type, which is used for internal Dijkstra computations.
+ /// It must conform to the \ref lemon::concepts::Heap "Heap" concept,
+ /// its priority type must be \c Cost and its cross reference type
+ /// must be \ref RangeMap "RangeMap<int>".
+ template <typename T>
+ struct SetHeap
+ : public CapacityScaling<GR, V, C, SetHeapTraits<T> > {
+ typedef CapacityScaling<GR, V, C, SetHeapTraits<T> > Create;
+ };
+
+ /// @}
+
+ protected:
+
+ CapacityScaling() {}
+
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// The constructor of the class.
+ ///
+ /// \param graph The digraph the algorithm runs on.
+ CapacityScaling(const GR& graph) :
+ _graph(graph), _node_id(graph), _arc_idf(graph), _arc_idb(graph),
+ INF(std::numeric_limits<Value>::has_infinity ?
+ std::numeric_limits<Value>::infinity() :
+ std::numeric_limits<Value>::max())
+ {
+ // Check the number types
+ LEMON_ASSERT(std::numeric_limits<Value>::is_signed,
+ "The flow type of CapacityScaling must be signed");
+ LEMON_ASSERT(std::numeric_limits<Cost>::is_signed,
+ "The cost type of CapacityScaling must be signed");
+
+ // Reset data structures
+ reset();
+ }
+
+ /// \name Parameters
+ /// The parameters of the algorithm can be specified using these
+ /// functions.
+
+ /// @{
+
+ /// \brief Set the lower bounds on the arcs.
+ ///
+ /// This function sets the lower bounds on the arcs.
+ /// If it is not used before calling \ref run(), the lower bounds
+ /// will be set to zero on all arcs.
+ ///
+ /// \param map An arc map storing the lower bounds.
+ /// Its \c Value type must be convertible to the \c Value type
+ /// of the algorithm.
+ ///
+ /// \return <tt>(*this)</tt>
+ template <typename LowerMap>
+ CapacityScaling& lowerMap(const LowerMap& map) {
+ _has_lower = true;
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ _lower[_arc_idf[a]] = map[a];
+ }
+ return *this;
+ }
+
+ /// \brief Set the upper bounds (capacities) on the arcs.
+ ///
+ /// This function sets the upper bounds (capacities) on the arcs.
+ /// If it is not used before calling \ref run(), the upper bounds
+ /// will be set to \ref INF on all arcs (i.e. the flow value will be
+ /// unbounded from above).
+ ///
+ /// \param map An arc map storing the upper bounds.
+ /// Its \c Value type must be convertible to the \c Value type
+ /// of the algorithm.
+ ///
+ /// \return <tt>(*this)</tt>
+ template<typename UpperMap>
+ CapacityScaling& upperMap(const UpperMap& map) {
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ _upper[_arc_idf[a]] = map[a];
+ }
+ return *this;
+ }
+
+ /// \brief Set the costs of the arcs.
+ ///
+ /// This function sets the costs of the arcs.
+ /// If it is not used before calling \ref run(), the costs
+ /// will be set to \c 1 on all arcs.
+ ///
+ /// \param map An arc map storing the costs.
+ /// Its \c Value type must be convertible to the \c Cost type
+ /// of the algorithm.
+ ///
+ /// \return <tt>(*this)</tt>
+ template<typename CostMap>
+ CapacityScaling& costMap(const CostMap& map) {
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ _cost[_arc_idf[a]] = map[a];
+ _cost[_arc_idb[a]] = -map[a];
+ }
+ return *this;
+ }
+
+ /// \brief Set the supply values of the nodes.
+ ///
+ /// This function sets the supply values of the nodes.
+ /// If neither this function nor \ref stSupply() is used before
+ /// calling \ref run(), the supply of each node will be set to zero.
+ ///
+ /// \param map A node map storing the supply values.
+ /// Its \c Value type must be convertible to the \c Value type
+ /// of the algorithm.
+ ///
+ /// \return <tt>(*this)</tt>
+ template<typename SupplyMap>
+ CapacityScaling& supplyMap(const SupplyMap& map) {
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ _supply[_node_id[n]] = map[n];
+ }
+ return *this;
+ }
+
+ /// \brief Set single source and target nodes and a supply value.
+ ///
+ /// This function sets a single source node and a single target node
+ /// and the required flow value.
+ /// If neither this function nor \ref supplyMap() is used before
+ /// calling \ref run(), the supply of each node will be set to zero.
+ ///
+ /// Using this function has the same effect as using \ref supplyMap()
+ /// with a map in which \c k is assigned to \c s, \c -k is
+ /// assigned to \c t and all other nodes have zero supply value.
+ ///
+ /// \param s The source node.
+ /// \param t The target node.
+ /// \param k The required amount of flow from node \c s to node \c t
+ /// (i.e. the supply of \c s and the demand of \c t).
+ ///
+ /// \return <tt>(*this)</tt>
+ CapacityScaling& stSupply(const Node& s, const Node& t, Value k) {
+ for (int i = 0; i != _node_num; ++i) {
+ _supply[i] = 0;
+ }
+ _supply[_node_id[s]] = k;
+ _supply[_node_id[t]] = -k;
+ return *this;
+ }
+
+ /// @}
+
+ /// \name Execution control
+ /// The algorithm can be executed using \ref run().
+
+ /// @{
+
+ /// \brief Run the algorithm.
+ ///
+ /// This function runs the algorithm.
+ /// The paramters can be specified using functions \ref lowerMap(),
+ /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply().
+ /// For example,
+ /// \code
+ /// CapacityScaling<ListDigraph> cs(graph);
+ /// cs.lowerMap(lower).upperMap(upper).costMap(cost)
+ /// .supplyMap(sup).run();
+ /// \endcode
+ ///
+ /// This function can be called more than once. All the given parameters
+ /// are kept for the next call, unless \ref resetParams() or \ref reset()
+ /// is used, thus only the modified parameters have to be set again.
+ /// If the underlying digraph was also modified after the construction
+ /// of the class (or the last \ref reset() call), then the \ref reset()
+ /// function must be called.
+ ///
+ /// \param factor The capacity scaling factor. It must be larger than
+ /// one to use scaling. If it is less or equal to one, then scaling
+ /// will be disabled.
+ ///
+ /// \return \c INFEASIBLE if no feasible flow exists,
+ /// \n \c OPTIMAL if the problem has optimal solution
+ /// (i.e. it is feasible and bounded), and the algorithm has found
+ /// optimal flow and node potentials (primal and dual solutions),
+ /// \n \c UNBOUNDED if the digraph contains an arc of negative cost
+ /// and infinite upper bound. It means that the objective function
+ /// is unbounded on that arc, however, note that it could actually be
+ /// bounded over the feasible flows, but this algroithm cannot handle
+ /// these cases.
+ ///
+ /// \see ProblemType
+ /// \see resetParams(), reset()
+ ProblemType run(int factor = 4) {
+ _factor = factor;
+ ProblemType pt = init();
+ if (pt != OPTIMAL) return pt;
+ return start();
+ }
+
+ /// \brief Reset all the parameters that have been given before.
+ ///
+ /// This function resets all the paramaters that have been given
+ /// before using functions \ref lowerMap(), \ref upperMap(),
+ /// \ref costMap(), \ref supplyMap(), \ref stSupply().
+ ///
+ /// It is useful for multiple \ref run() calls. Basically, all the given
+ /// parameters are kept for the next \ref run() call, unless
+ /// \ref resetParams() or \ref reset() is used.
+ /// If the underlying digraph was also modified after the construction
+ /// of the class or the last \ref reset() call, then the \ref reset()
+ /// function must be used, otherwise \ref resetParams() is sufficient.
+ ///
+ /// For example,
+ /// \code
+ /// CapacityScaling<ListDigraph> cs(graph);
+ ///
+ /// // First run
+ /// cs.lowerMap(lower).upperMap(upper).costMap(cost)
+ /// .supplyMap(sup).run();
+ ///
+ /// // Run again with modified cost map (resetParams() is not called,
+ /// // so only the cost map have to be set again)
+ /// cost[e] += 100;
+ /// cs.costMap(cost).run();
+ ///
+ /// // Run again from scratch using resetParams()
+ /// // (the lower bounds will be set to zero on all arcs)
+ /// cs.resetParams();
+ /// cs.upperMap(capacity).costMap(cost)
+ /// .supplyMap(sup).run();
+ /// \endcode
+ ///
+ /// \return <tt>(*this)</tt>
+ ///
+ /// \see reset(), run()
+ CapacityScaling& resetParams() {
+ for (int i = 0; i != _node_num; ++i) {
+ _supply[i] = 0;
+ }
+ for (int j = 0; j != _res_arc_num; ++j) {
+ _lower[j] = 0;
+ _upper[j] = INF;
+ _cost[j] = _forward[j] ? 1 : -1;
+ }
+ _has_lower = false;
+ return *this;
+ }
+
+ /// \brief Reset the internal data structures and all the parameters
+ /// that have been given before.
+ ///
+ /// This function resets the internal data structures and all the
+ /// paramaters that have been given before using functions \ref lowerMap(),
+ /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply().
+ ///
+ /// It is useful for multiple \ref run() calls. Basically, all the given
+ /// parameters are kept for the next \ref run() call, unless
+ /// \ref resetParams() or \ref reset() is used.
+ /// If the underlying digraph was also modified after the construction
+ /// of the class or the last \ref reset() call, then the \ref reset()
+ /// function must be used, otherwise \ref resetParams() is sufficient.
+ ///
+ /// See \ref resetParams() for examples.
+ ///
+ /// \return <tt>(*this)</tt>
+ ///
+ /// \see resetParams(), run()
+ CapacityScaling& reset() {
+ // Resize vectors
+ _node_num = countNodes(_graph);
+ _arc_num = countArcs(_graph);
+ _res_arc_num = 2 * (_arc_num + _node_num);
+ _root = _node_num;
+ ++_node_num;
+
+ _first_out.resize(_node_num + 1);
+ _forward.resize(_res_arc_num);
+ _source.resize(_res_arc_num);
+ _target.resize(_res_arc_num);
+ _reverse.resize(_res_arc_num);
+
+ _lower.resize(_res_arc_num);
+ _upper.resize(_res_arc_num);
+ _cost.resize(_res_arc_num);
+ _supply.resize(_node_num);
+
+ _res_cap.resize(_res_arc_num);
+ _pi.resize(_node_num);
+ _excess.resize(_node_num);
+ _pred.resize(_node_num);
+
+ // Copy the graph
+ int i = 0, j = 0, k = 2 * _arc_num + _node_num - 1;
+ for (NodeIt n(_graph); n != INVALID; ++n, ++i) {
+ _node_id[n] = i;
+ }
+ i = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n, ++i) {
+ _first_out[i] = j;
+ for (OutArcIt a(_graph, n); a != INVALID; ++a, ++j) {
+ _arc_idf[a] = j;
+ _forward[j] = true;
+ _source[j] = i;
+ _target[j] = _node_id[_graph.runningNode(a)];
+ }
+ for (InArcIt a(_graph, n); a != INVALID; ++a, ++j) {
+ _arc_idb[a] = j;
+ _forward[j] = false;
+ _source[j] = i;
+ _target[j] = _node_id[_graph.runningNode(a)];
+ }
+ _forward[j] = false;
+ _source[j] = i;
+ _target[j] = _root;
+ _reverse[j] = k;
+ _forward[k] = true;
+ _source[k] = _root;
+ _target[k] = i;
+ _reverse[k] = j;
+ ++j; ++k;
+ }
+ _first_out[i] = j;
+ _first_out[_node_num] = k;
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ int fi = _arc_idf[a];
+ int bi = _arc_idb[a];
+ _reverse[fi] = bi;
+ _reverse[bi] = fi;
+ }
+
+ // Reset parameters
+ resetParams();
+ return *this;
+ }
+
+ /// @}
+
+ /// \name Query Functions
+ /// The results of the algorithm can be obtained using these
+ /// functions.\n
+ /// The \ref run() function must be called before using them.
+
+ /// @{
+
+ /// \brief Return the total cost of the found flow.
+ ///
+ /// This function returns the total cost of the found flow.
+ /// Its complexity is O(m).
+ ///
+ /// \note The return type of the function can be specified as a
+ /// template parameter. For example,
+ /// \code
+ /// cs.totalCost<double>();
+ /// \endcode
+ /// It is useful if the total cost cannot be stored in the \c Cost
+ /// type of the algorithm, which is the default return type of the
+ /// function.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ template <typename Number>
+ Number totalCost() const {
+ Number c = 0;
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ int i = _arc_idb[a];
+ c += static_cast<Number>(_res_cap[i]) *
+ (-static_cast<Number>(_cost[i]));
+ }
+ return c;
+ }
+
+#ifndef DOXYGEN
+ Cost totalCost() const {
+ return totalCost<Cost>();
+ }
+#endif
+
+ /// \brief Return the flow on the given arc.
+ ///
+ /// This function returns the flow on the given arc.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ Value flow(const Arc& a) const {
+ return _res_cap[_arc_idb[a]];
+ }
+
+ /// \brief Copy the flow values (the primal solution) into the
+ /// given map.
+ ///
+ /// This function copies the flow value on each arc into the given
+ /// map. The \c Value type of the algorithm must be convertible to
+ /// the \c Value type of the map.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ template <typename FlowMap>
+ void flowMap(FlowMap &map) const {
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ map.set(a, _res_cap[_arc_idb[a]]);
+ }
+ }
+
+ /// \brief Return the potential (dual value) of the given node.
+ ///
+ /// This function returns the potential (dual value) of the
+ /// given node.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ Cost potential(const Node& n) const {
+ return _pi[_node_id[n]];
+ }
+
+ /// \brief Copy the potential values (the dual solution) into the
+ /// given map.
+ ///
+ /// This function copies the potential (dual value) of each node
+ /// into the given map.
+ /// The \c Cost type of the algorithm must be convertible to the
+ /// \c Value type of the map.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ template <typename PotentialMap>
+ void potentialMap(PotentialMap &map) const {
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ map.set(n, _pi[_node_id[n]]);
+ }
+ }
+
+ /// @}
+
+ private:
+
+ // Initialize the algorithm
+ ProblemType init() {
+ if (_node_num <= 1) return INFEASIBLE;
+
+ // Check the sum of supply values
+ _sum_supply = 0;
+ for (int i = 0; i != _root; ++i) {
+ _sum_supply += _supply[i];
+ }
+ if (_sum_supply > 0) return INFEASIBLE;
+
+ // Check lower and upper bounds
+ LEMON_DEBUG(checkBoundMaps(),
+ "Upper bounds must be greater or equal to the lower bounds");
+
+
+ // Initialize vectors
+ for (int i = 0; i != _root; ++i) {
+ _pi[i] = 0;
+ _excess[i] = _supply[i];
+ }
+
+ // Remove non-zero lower bounds
+ const Value MAX = std::numeric_limits<Value>::max();
+ int last_out;
+ if (_has_lower) {
+ for (int i = 0; i != _root; ++i) {
+ last_out = _first_out[i+1];
+ for (int j = _first_out[i]; j != last_out; ++j) {
+ if (_forward[j]) {
+ Value c = _lower[j];
+ if (c >= 0) {
+ _res_cap[j] = _upper[j] < MAX ? _upper[j] - c : INF;
+ } else {
+ _res_cap[j] = _upper[j] < MAX + c ? _upper[j] - c : INF;
+ }
+ _excess[i] -= c;
+ _excess[_target[j]] += c;
+ } else {
+ _res_cap[j] = 0;
+ }
+ }
+ }
+ } else {
+ for (int j = 0; j != _res_arc_num; ++j) {
+ _res_cap[j] = _forward[j] ? _upper[j] : 0;
+ }
+ }
+
+ // Handle negative costs
+ for (int i = 0; i != _root; ++i) {
+ last_out = _first_out[i+1] - 1;
+ for (int j = _first_out[i]; j != last_out; ++j) {
+ Value rc = _res_cap[j];
+ if (_cost[j] < 0 && rc > 0) {
+ if (rc >= MAX) return UNBOUNDED;
+ _excess[i] -= rc;
+ _excess[_target[j]] += rc;
+ _res_cap[j] = 0;
+ _res_cap[_reverse[j]] += rc;
+ }
+ }
+ }
+
+ // Handle GEQ supply type
+ if (_sum_supply < 0) {
+ _pi[_root] = 0;
+ _excess[_root] = -_sum_supply;
+ for (int a = _first_out[_root]; a != _res_arc_num; ++a) {
+ int ra = _reverse[a];
+ _res_cap[a] = -_sum_supply + 1;
+ _res_cap[ra] = 0;
+ _cost[a] = 0;
+ _cost[ra] = 0;
+ }
+ } else {
+ _pi[_root] = 0;
+ _excess[_root] = 0;
+ for (int a = _first_out[_root]; a != _res_arc_num; ++a) {
+ int ra = _reverse[a];
+ _res_cap[a] = 1;
+ _res_cap[ra] = 0;
+ _cost[a] = 0;
+ _cost[ra] = 0;
+ }
+ }
+
+ // Initialize delta value
+ if (_factor > 1) {
+ // With scaling
+ Value max_sup = 0, max_dem = 0, max_cap = 0;
+ for (int i = 0; i != _root; ++i) {
+ Value ex = _excess[i];
+ if ( ex > max_sup) max_sup = ex;
+ if (-ex > max_dem) max_dem = -ex;
+ int last_out = _first_out[i+1] - 1;
+ for (int j = _first_out[i]; j != last_out; ++j) {
+ if (_res_cap[j] > max_cap) max_cap = _res_cap[j];
+ }
+ }
+ max_sup = std::min(std::min(max_sup, max_dem), max_cap);
+ for (_delta = 1; 2 * _delta <= max_sup; _delta *= 2) ;
+ } else {
+ // Without scaling
+ _delta = 1;
+ }
+
+ return OPTIMAL;
+ }
+
+ // Check if the upper bound is greater than or equal to the lower bound
+ // on each forward arc.
+ bool checkBoundMaps() {
+ for (int j = 0; j != _res_arc_num; ++j) {
+ if (_forward[j] && _upper[j] < _lower[j]) return false;
+ }
+ return true;
+ }
+
+ ProblemType start() {
+ // Execute the algorithm
+ ProblemType pt;
+ if (_delta > 1)
+ pt = startWithScaling();
+ else
+ pt = startWithoutScaling();
+
+ // Handle non-zero lower bounds
+ if (_has_lower) {
+ int limit = _first_out[_root];
+ for (int j = 0; j != limit; ++j) {
+ if (_forward[j]) _res_cap[_reverse[j]] += _lower[j];
+ }
+ }
+
+ // Shift potentials if necessary
+ Cost pr = _pi[_root];
+ if (_sum_supply < 0 || pr > 0) {
+ for (int i = 0; i != _node_num; ++i) {
+ _pi[i] -= pr;
+ }
+ }
+
+ return pt;
+ }
+
+ // Execute the capacity scaling algorithm
+ ProblemType startWithScaling() {
+ // Perform capacity scaling phases
+ int s, t;
+ ResidualDijkstra _dijkstra(*this);
+ while (true) {
+ // Saturate all arcs not satisfying the optimality condition
+ int last_out;
+ for (int u = 0; u != _node_num; ++u) {
+ last_out = _sum_supply < 0 ?
+ _first_out[u+1] : _first_out[u+1] - 1;
+ for (int a = _first_out[u]; a != last_out; ++a) {
+ int v = _target[a];
+ Cost c = _cost[a] + _pi[u] - _pi[v];
+ Value rc = _res_cap[a];
+ if (c < 0 && rc >= _delta) {
+ _excess[u] -= rc;
+ _excess[v] += rc;
+ _res_cap[a] = 0;
+ _res_cap[_reverse[a]] += rc;
+ }
+ }
+ }
+
+ // Find excess nodes and deficit nodes
+ _excess_nodes.clear();
+ _deficit_nodes.clear();
+ for (int u = 0; u != _node_num; ++u) {
+ Value ex = _excess[u];
+ if (ex >= _delta) _excess_nodes.push_back(u);
+ if (ex <= -_delta) _deficit_nodes.push_back(u);
+ }
+ int next_node = 0, next_def_node = 0;
+
+ // Find augmenting shortest paths
+ while (next_node < int(_excess_nodes.size())) {
+ // Check deficit nodes
+ if (_delta > 1) {
+ bool delta_deficit = false;
+ for ( ; next_def_node < int(_deficit_nodes.size());
+ ++next_def_node ) {
+ if (_excess[_deficit_nodes[next_def_node]] <= -_delta) {
+ delta_deficit = true;
+ break;
+ }
+ }
+ if (!delta_deficit) break;
+ }
+
+ // Run Dijkstra in the residual network
+ s = _excess_nodes[next_node];
+ if ((t = _dijkstra.run(s, _delta)) == -1) {
+ if (_delta > 1) {
+ ++next_node;
+ continue;
+ }
+ return INFEASIBLE;
+ }
+
+ // Augment along a shortest path from s to t
+ Value d = std::min(_excess[s], -_excess[t]);
+ int u = t;
+ int a;
+ if (d > _delta) {
+ while ((a = _pred[u]) != -1) {
+ if (_res_cap[a] < d) d = _res_cap[a];
+ u = _source[a];
+ }
+ }
+ u = t;
+ while ((a = _pred[u]) != -1) {
+ _res_cap[a] -= d;
+ _res_cap[_reverse[a]] += d;
+ u = _source[a];
+ }
+ _excess[s] -= d;
+ _excess[t] += d;
+
+ if (_excess[s] < _delta) ++next_node;
+ }
+
+ if (_delta == 1) break;
+ _delta = _delta <= _factor ? 1 : _delta / _factor;
+ }
+
+ return OPTIMAL;
+ }
+
+ // Execute the successive shortest path algorithm
+ ProblemType startWithoutScaling() {
+ // Find excess nodes
+ _excess_nodes.clear();
+ for (int i = 0; i != _node_num; ++i) {
+ if (_excess[i] > 0) _excess_nodes.push_back(i);
+ }
+ if (_excess_nodes.size() == 0) return OPTIMAL;
+ int next_node = 0;
+
+ // Find shortest paths
+ int s, t;
+ ResidualDijkstra _dijkstra(*this);
+ while ( _excess[_excess_nodes[next_node]] > 0 ||
+ ++next_node < int(_excess_nodes.size()) )
+ {
+ // Run Dijkstra in the residual network
+ s = _excess_nodes[next_node];
+ if ((t = _dijkstra.run(s)) == -1) return INFEASIBLE;
+
+ // Augment along a shortest path from s to t
+ Value d = std::min(_excess[s], -_excess[t]);
+ int u = t;
+ int a;
+ if (d > 1) {
+ while ((a = _pred[u]) != -1) {
+ if (_res_cap[a] < d) d = _res_cap[a];
+ u = _source[a];
+ }
+ }
+ u = t;
+ while ((a = _pred[u]) != -1) {
+ _res_cap[a] -= d;
+ _res_cap[_reverse[a]] += d;
+ u = _source[a];
+ }
+ _excess[s] -= d;
+ _excess[t] += d;
+ }
+
+ return OPTIMAL;
+ }
+
+ }; //class CapacityScaling
+
+ ///@}
+
+} //namespace lemon
+
+#endif //LEMON_CAPACITY_SCALING_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/cbc.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cbc.cc
new file mode 100644
index 00000000000..62331b1e2e1
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cbc.cc
@@ -0,0 +1,460 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+///\file
+///\brief Implementation of the CBC MIP solver interface.
+
+#include "cbc.h"
+
+#include <coin/CoinModel.hpp>
+#include <coin/CbcModel.hpp>
+#include <coin/OsiSolverInterface.hpp>
+
+#include "coin/OsiClpSolverInterface.hpp"
+
+#include "coin/CbcCutGenerator.hpp"
+#include "coin/CbcHeuristicLocal.hpp"
+#include "coin/CbcHeuristicGreedy.hpp"
+#include "coin/CbcHeuristicFPump.hpp"
+#include "coin/CbcHeuristicRINS.hpp"
+
+#include "coin/CglGomory.hpp"
+#include "coin/CglProbing.hpp"
+#include "coin/CglKnapsackCover.hpp"
+#include "coin/CglOddHole.hpp"
+#include "coin/CglClique.hpp"
+#include "coin/CglFlowCover.hpp"
+#include "coin/CglMixedIntegerRounding.hpp"
+
+#include "coin/CbcHeuristic.hpp"
+
+namespace lemon {
+
+ CbcMip::CbcMip() {
+ _prob = new CoinModel();
+ _prob->setProblemName("LEMON");
+ _osi_solver = 0;
+ _cbc_model = 0;
+ messageLevel(MESSAGE_NOTHING);
+ }
+
+ CbcMip::CbcMip(const CbcMip& other) {
+ _prob = new CoinModel(*other._prob);
+ _prob->setProblemName("LEMON");
+ _osi_solver = 0;
+ _cbc_model = 0;
+ messageLevel(MESSAGE_NOTHING);
+ }
+
+ CbcMip::~CbcMip() {
+ delete _prob;
+ if (_osi_solver) delete _osi_solver;
+ if (_cbc_model) delete _cbc_model;
+ }
+
+ const char* CbcMip::_solverName() const { return "CbcMip"; }
+
+ int CbcMip::_addCol() {
+ _prob->addColumn(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX, 0.0, 0, false);
+ return _prob->numberColumns() - 1;
+ }
+
+ CbcMip* CbcMip::newSolver() const {
+ CbcMip* newlp = new CbcMip;
+ return newlp;
+ }
+
+ CbcMip* CbcMip::cloneSolver() const {
+ CbcMip* copylp = new CbcMip(*this);
+ return copylp;
+ }
+
+ int CbcMip::_addRow() {
+ _prob->addRow(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX);
+ return _prob->numberRows() - 1;
+ }
+
+ int CbcMip::_addRow(Value l, ExprIterator b, ExprIterator e, Value u) {
+ std::vector<int> indexes;
+ std::vector<Value> values;
+
+ for(ExprIterator it = b; it != e; ++it) {
+ indexes.push_back(it->first);
+ values.push_back(it->second);
+ }
+
+ _prob->addRow(values.size(), &indexes.front(), &values.front(), l, u);
+ return _prob->numberRows() - 1;
+ }
+
+ void CbcMip::_eraseCol(int i) {
+ _prob->deleteColumn(i);
+ }
+
+ void CbcMip::_eraseRow(int i) {
+ _prob->deleteRow(i);
+ }
+
+ void CbcMip::_eraseColId(int i) {
+ cols.eraseIndex(i);
+ }
+
+ void CbcMip::_eraseRowId(int i) {
+ rows.eraseIndex(i);
+ }
+
+ void CbcMip::_getColName(int c, std::string& name) const {
+ name = _prob->getColumnName(c);
+ }
+
+ void CbcMip::_setColName(int c, const std::string& name) {
+ _prob->setColumnName(c, name.c_str());
+ }
+
+ int CbcMip::_colByName(const std::string& name) const {
+ return _prob->column(name.c_str());
+ }
+
+ void CbcMip::_getRowName(int r, std::string& name) const {
+ name = _prob->getRowName(r);
+ }
+
+ void CbcMip::_setRowName(int r, const std::string& name) {
+ _prob->setRowName(r, name.c_str());
+ }
+
+ int CbcMip::_rowByName(const std::string& name) const {
+ return _prob->row(name.c_str());
+ }
+
+ void CbcMip::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) {
+ for (ExprIterator it = b; it != e; ++it) {
+ _prob->setElement(i, it->first, it->second);
+ }
+ }
+
+ void CbcMip::_getRowCoeffs(int ix, InsertIterator b) const {
+ int length = _prob->numberRows();
+
+ std::vector<int> indices(length);
+ std::vector<Value> values(length);
+
+ length = _prob->getRow(ix, &indices[0], &values[0]);
+
+ for (int i = 0; i < length; ++i) {
+ *b = std::make_pair(indices[i], values[i]);
+ ++b;
+ }
+ }
+
+ void CbcMip::_setColCoeffs(int ix, ExprIterator b, ExprIterator e) {
+ for (ExprIterator it = b; it != e; ++it) {
+ _prob->setElement(it->first, ix, it->second);
+ }
+ }
+
+ void CbcMip::_getColCoeffs(int ix, InsertIterator b) const {
+ int length = _prob->numberColumns();
+
+ std::vector<int> indices(length);
+ std::vector<Value> values(length);
+
+ length = _prob->getColumn(ix, &indices[0], &values[0]);
+
+ for (int i = 0; i < length; ++i) {
+ *b = std::make_pair(indices[i], values[i]);
+ ++b;
+ }
+ }
+
+ void CbcMip::_setCoeff(int ix, int jx, Value value) {
+ _prob->setElement(ix, jx, value);
+ }
+
+ CbcMip::Value CbcMip::_getCoeff(int ix, int jx) const {
+ return _prob->getElement(ix, jx);
+ }
+
+
+ void CbcMip::_setColLowerBound(int i, Value lo) {
+ LEMON_ASSERT(lo != INF, "Invalid bound");
+ _prob->setColumnLower(i, lo == - INF ? - COIN_DBL_MAX : lo);
+ }
+
+ CbcMip::Value CbcMip::_getColLowerBound(int i) const {
+ double val = _prob->getColumnLower(i);
+ return val == - COIN_DBL_MAX ? - INF : val;
+ }
+
+ void CbcMip::_setColUpperBound(int i, Value up) {
+ LEMON_ASSERT(up != -INF, "Invalid bound");
+ _prob->setColumnUpper(i, up == INF ? COIN_DBL_MAX : up);
+ }
+
+ CbcMip::Value CbcMip::_getColUpperBound(int i) const {
+ double val = _prob->getColumnUpper(i);
+ return val == COIN_DBL_MAX ? INF : val;
+ }
+
+ void CbcMip::_setRowLowerBound(int i, Value lo) {
+ LEMON_ASSERT(lo != INF, "Invalid bound");
+ _prob->setRowLower(i, lo == - INF ? - COIN_DBL_MAX : lo);
+ }
+
+ CbcMip::Value CbcMip::_getRowLowerBound(int i) const {
+ double val = _prob->getRowLower(i);
+ return val == - COIN_DBL_MAX ? - INF : val;
+ }
+
+ void CbcMip::_setRowUpperBound(int i, Value up) {
+ LEMON_ASSERT(up != -INF, "Invalid bound");
+ _prob->setRowUpper(i, up == INF ? COIN_DBL_MAX : up);
+ }
+
+ CbcMip::Value CbcMip::_getRowUpperBound(int i) const {
+ double val = _prob->getRowUpper(i);
+ return val == COIN_DBL_MAX ? INF : val;
+ }
+
+ void CbcMip::_setObjCoeffs(ExprIterator b, ExprIterator e) {
+ int num = _prob->numberColumns();
+ for (int i = 0; i < num; ++i) {
+ _prob->setColumnObjective(i, 0.0);
+ }
+ for (ExprIterator it = b; it != e; ++it) {
+ _prob->setColumnObjective(it->first, it->second);
+ }
+ }
+
+ void CbcMip::_getObjCoeffs(InsertIterator b) const {
+ int num = _prob->numberColumns();
+ for (int i = 0; i < num; ++i) {
+ Value coef = _prob->getColumnObjective(i);
+ if (coef != 0.0) {
+ *b = std::make_pair(i, coef);
+ ++b;
+ }
+ }
+ }
+
+ void CbcMip::_setObjCoeff(int i, Value obj_coef) {
+ _prob->setColumnObjective(i, obj_coef);
+ }
+
+ CbcMip::Value CbcMip::_getObjCoeff(int i) const {
+ return _prob->getColumnObjective(i);
+ }
+
+ CbcMip::SolveExitStatus CbcMip::_solve() {
+
+ if (_osi_solver) {
+ delete _osi_solver;
+ }
+ _osi_solver = new OsiClpSolverInterface();
+
+ _osi_solver->loadFromCoinModel(*_prob);
+
+ if (_cbc_model) {
+ delete _cbc_model;
+ }
+ _cbc_model= new CbcModel(*_osi_solver);
+
+ _osi_solver->messageHandler()->setLogLevel(_message_level);
+ _cbc_model->setLogLevel(_message_level);
+
+ _cbc_model->initialSolve();
+ _cbc_model->solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
+
+ if (!_cbc_model->isInitialSolveAbandoned() &&
+ _cbc_model->isInitialSolveProvenOptimal() &&
+ !_cbc_model->isInitialSolveProvenPrimalInfeasible() &&
+ !_cbc_model->isInitialSolveProvenDualInfeasible()) {
+
+ CglProbing generator1;
+ generator1.setUsingObjective(true);
+ generator1.setMaxPass(3);
+ generator1.setMaxProbe(100);
+ generator1.setMaxLook(50);
+ generator1.setRowCuts(3);
+ _cbc_model->addCutGenerator(&generator1, -1, "Probing");
+
+ CglGomory generator2;
+ generator2.setLimit(300);
+ _cbc_model->addCutGenerator(&generator2, -1, "Gomory");
+
+ CglKnapsackCover generator3;
+ _cbc_model->addCutGenerator(&generator3, -1, "Knapsack");
+
+ CglOddHole generator4;
+ generator4.setMinimumViolation(0.005);
+ generator4.setMinimumViolationPer(0.00002);
+ generator4.setMaximumEntries(200);
+ _cbc_model->addCutGenerator(&generator4, -1, "OddHole");
+
+ CglClique generator5;
+ generator5.setStarCliqueReport(false);
+ generator5.setRowCliqueReport(false);
+ _cbc_model->addCutGenerator(&generator5, -1, "Clique");
+
+ CglMixedIntegerRounding mixedGen;
+ _cbc_model->addCutGenerator(&mixedGen, -1, "MixedIntegerRounding");
+
+ CglFlowCover flowGen;
+ _cbc_model->addCutGenerator(&flowGen, -1, "FlowCover");
+
+ OsiClpSolverInterface* osiclp =
+ dynamic_cast<OsiClpSolverInterface*>(_cbc_model->solver());
+ if (osiclp->getNumRows() < 300 && osiclp->getNumCols() < 500) {
+ osiclp->setupForRepeatedUse(2, 0);
+ }
+
+ CbcRounding heuristic1(*_cbc_model);
+ heuristic1.setWhen(3);
+ _cbc_model->addHeuristic(&heuristic1);
+
+ CbcHeuristicLocal heuristic2(*_cbc_model);
+ heuristic2.setWhen(3);
+ _cbc_model->addHeuristic(&heuristic2);
+
+ CbcHeuristicGreedyCover heuristic3(*_cbc_model);
+ heuristic3.setAlgorithm(11);
+ heuristic3.setWhen(3);
+ _cbc_model->addHeuristic(&heuristic3);
+
+ CbcHeuristicFPump heuristic4(*_cbc_model);
+ heuristic4.setWhen(3);
+ _cbc_model->addHeuristic(&heuristic4);
+
+ CbcHeuristicRINS heuristic5(*_cbc_model);
+ heuristic5.setWhen(3);
+ _cbc_model->addHeuristic(&heuristic5);
+
+ if (_cbc_model->getNumCols() < 500) {
+ _cbc_model->setMaximumCutPassesAtRoot(-100);
+ } else if (_cbc_model->getNumCols() < 5000) {
+ _cbc_model->setMaximumCutPassesAtRoot(100);
+ } else {
+ _cbc_model->setMaximumCutPassesAtRoot(20);
+ }
+
+ if (_cbc_model->getNumCols() < 5000) {
+ _cbc_model->setNumberStrong(10);
+ }
+
+ _cbc_model->solver()->setIntParam(OsiMaxNumIterationHotStart, 100);
+ _cbc_model->branchAndBound();
+ }
+
+ if (_cbc_model->isAbandoned()) {
+ return UNSOLVED;
+ } else {
+ return SOLVED;
+ }
+ }
+
+ CbcMip::Value CbcMip::_getSol(int i) const {
+ return _cbc_model->getColSolution()[i];
+ }
+
+ CbcMip::Value CbcMip::_getSolValue() const {
+ return _cbc_model->getObjValue();
+ }
+
+ CbcMip::ProblemType CbcMip::_getType() const {
+ if (_cbc_model->isProvenOptimal()) {
+ return OPTIMAL;
+ } else if (_cbc_model->isContinuousUnbounded()) {
+ return UNBOUNDED;
+ }
+ return FEASIBLE;
+ }
+
+ void CbcMip::_setSense(Sense sense) {
+ switch (sense) {
+ case MIN:
+ _prob->setOptimizationDirection(1.0);
+ break;
+ case MAX:
+ _prob->setOptimizationDirection(- 1.0);
+ break;
+ }
+ }
+
+ CbcMip::Sense CbcMip::_getSense() const {
+ if (_prob->optimizationDirection() > 0.0) {
+ return MIN;
+ } else if (_prob->optimizationDirection() < 0.0) {
+ return MAX;
+ } else {
+ LEMON_ASSERT(false, "Wrong sense");
+ return CbcMip::Sense();
+ }
+ }
+
+ void CbcMip::_setColType(int i, CbcMip::ColTypes col_type) {
+ switch (col_type){
+ case INTEGER:
+ _prob->setInteger(i);
+ break;
+ case REAL:
+ _prob->setContinuous(i);
+ break;
+ default:;
+ LEMON_ASSERT(false, "Wrong sense");
+ }
+ }
+
+ CbcMip::ColTypes CbcMip::_getColType(int i) const {
+ return _prob->getColumnIsInteger(i) ? INTEGER : REAL;
+ }
+
+ void CbcMip::_clear() {
+ delete _prob;
+ if (_osi_solver) {
+ delete _osi_solver;
+ _osi_solver = 0;
+ }
+ if (_cbc_model) {
+ delete _cbc_model;
+ _cbc_model = 0;
+ }
+
+ _prob = new CoinModel();
+ }
+
+ void CbcMip::_messageLevel(MessageLevel level) {
+ switch (level) {
+ case MESSAGE_NOTHING:
+ _message_level = 0;
+ break;
+ case MESSAGE_ERROR:
+ _message_level = 1;
+ break;
+ case MESSAGE_WARNING:
+ _message_level = 1;
+ break;
+ case MESSAGE_NORMAL:
+ _message_level = 2;
+ break;
+ case MESSAGE_VERBOSE:
+ _message_level = 3;
+ break;
+ }
+ }
+
+} //END OF NAMESPACE LEMON
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/cbc.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cbc.h
new file mode 100644
index 00000000000..968e504ac35
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cbc.h
@@ -0,0 +1,129 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_CBC_H
+#define LEMON_CBC_H
+
+///\file
+///\brief Header of the LEMON-CBC mip solver interface.
+///\ingroup lp_group
+
+#include <lemon/lp_base.h>
+
+class CoinModel;
+class OsiSolverInterface;
+class CbcModel;
+
+namespace lemon {
+
+ /// \brief Interface for the CBC MIP solver
+ ///
+ /// This class implements an interface for the CBC MIP solver.
+ ///\ingroup lp_group
+ class CbcMip : public MipSolver {
+ protected:
+
+ CoinModel *_prob;
+ OsiSolverInterface *_osi_solver;
+ CbcModel *_cbc_model;
+
+ public:
+
+ /// \e
+ CbcMip();
+ /// \e
+ CbcMip(const CbcMip&);
+ /// \e
+ ~CbcMip();
+ /// \e
+ virtual CbcMip* newSolver() const;
+ /// \e
+ virtual CbcMip* cloneSolver() const;
+
+ protected:
+
+ virtual const char* _solverName() const;
+
+ virtual int _addCol();
+ virtual int _addRow();
+ virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u);
+
+ virtual void _eraseCol(int i);
+ virtual void _eraseRow(int i);
+
+ virtual void _eraseColId(int i);
+ virtual void _eraseRowId(int i);
+
+ virtual void _getColName(int col, std::string& name) const;
+ virtual void _setColName(int col, const std::string& name);
+ virtual int _colByName(const std::string& name) const;
+
+ virtual void _getRowName(int row, std::string& name) const;
+ virtual void _setRowName(int row, const std::string& name);
+ virtual int _rowByName(const std::string& name) const;
+
+ virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e);
+ virtual void _getRowCoeffs(int i, InsertIterator b) const;
+
+ virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e);
+ virtual void _getColCoeffs(int i, InsertIterator b) const;
+
+ virtual void _setCoeff(int row, int col, Value value);
+ virtual Value _getCoeff(int row, int col) const;
+
+ virtual void _setColLowerBound(int i, Value value);
+ virtual Value _getColLowerBound(int i) const;
+ virtual void _setColUpperBound(int i, Value value);
+ virtual Value _getColUpperBound(int i) const;
+
+ virtual void _setRowLowerBound(int i, Value value);
+ virtual Value _getRowLowerBound(int i) const;
+ virtual void _setRowUpperBound(int i, Value value);
+ virtual Value _getRowUpperBound(int i) const;
+
+ virtual void _setObjCoeffs(ExprIterator b, ExprIterator e);
+ virtual void _getObjCoeffs(InsertIterator b) const;
+
+ virtual void _setObjCoeff(int i, Value obj_coef);
+ virtual Value _getObjCoeff(int i) const;
+
+ virtual void _setSense(Sense sense);
+ virtual Sense _getSense() const;
+
+ virtual ColTypes _getColType(int col) const;
+ virtual void _setColType(int col, ColTypes col_type);
+
+ virtual SolveExitStatus _solve();
+ virtual ProblemType _getType() const;
+ virtual Value _getSol(int i) const;
+ virtual Value _getSolValue() const;
+
+ virtual void _clear();
+
+ virtual void _messageLevel(MessageLevel level);
+ void _applyMessageLevel();
+
+ int _message_level;
+
+
+
+ };
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/christofides_tsp.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/christofides_tsp.h
new file mode 100644
index 00000000000..2997567a689
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/christofides_tsp.h
@@ -0,0 +1,254 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_CHRISTOFIDES_TSP_H
+#define LEMON_CHRISTOFIDES_TSP_H
+
+/// \ingroup tsp
+/// \file
+/// \brief Christofides algorithm for symmetric TSP
+
+#include <lemon/full_graph.h>
+#include <lemon/smart_graph.h>
+#include <lemon/kruskal.h>
+#include <lemon/matching.h>
+#include <lemon/euler.h>
+
+namespace lemon {
+
+ /// \ingroup tsp
+ ///
+ /// \brief Christofides algorithm for symmetric TSP.
+ ///
+ /// ChristofidesTsp implements Christofides' heuristic for solving
+ /// symmetric \ref tsp "TSP".
+ ///
+ /// This a well-known approximation method for the TSP problem with
+ /// metric cost function.
+ /// It has a guaranteed approximation factor of 3/2 (i.e. it finds a tour
+ /// whose total cost is at most 3/2 of the optimum), but it usually
+ /// provides better solutions in practice.
+ /// This implementation runs in O(n<sup>3</sup>log(n)) time.
+ ///
+ /// The algorithm starts with a \ref spantree "minimum cost spanning tree" and
+ /// finds a \ref MaxWeightedPerfectMatching "minimum cost perfect matching"
+ /// in the subgraph induced by the nodes that have odd degree in the
+ /// spanning tree.
+ /// Finally, it constructs the tour from the \ref EulerIt "Euler traversal"
+ /// of the union of the spanning tree and the matching.
+ /// During this last step, the algorithm simply skips the visited nodes
+ /// (i.e. creates shortcuts) assuming that the triangle inequality holds
+ /// for the cost function.
+ ///
+ /// \tparam CM Type of the cost map.
+ ///
+ /// \warning CM::Value must be a signed number type.
+ template <typename CM>
+ class ChristofidesTsp
+ {
+ public:
+
+ /// Type of the cost map
+ typedef CM CostMap;
+ /// Type of the edge costs
+ typedef typename CM::Value Cost;
+
+ private:
+
+ GRAPH_TYPEDEFS(FullGraph);
+
+ const FullGraph &_gr;
+ const CostMap &_cost;
+ std::vector<Node> _path;
+ Cost _sum;
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ /// \param gr The \ref FullGraph "full graph" the algorithm runs on.
+ /// \param cost The cost map.
+ ChristofidesTsp(const FullGraph &gr, const CostMap &cost)
+ : _gr(gr), _cost(cost) {}
+
+ /// \name Execution Control
+ /// @{
+
+ /// \brief Runs the algorithm.
+ ///
+ /// This function runs the algorithm.
+ ///
+ /// \return The total cost of the found tour.
+ Cost run() {
+ _path.clear();
+
+ if (_gr.nodeNum() == 0) return _sum = 0;
+ else if (_gr.nodeNum() == 1) {
+ _path.push_back(_gr(0));
+ return _sum = 0;
+ }
+ else if (_gr.nodeNum() == 2) {
+ _path.push_back(_gr(0));
+ _path.push_back(_gr(1));
+ return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))];
+ }
+
+ // Compute min. cost spanning tree
+ std::vector<Edge> tree;
+ kruskal(_gr, _cost, std::back_inserter(tree));
+
+ FullGraph::NodeMap<int> deg(_gr, 0);
+ for (int i = 0; i != int(tree.size()); ++i) {
+ Edge e = tree[i];
+ ++deg[_gr.u(e)];
+ ++deg[_gr.v(e)];
+ }
+
+ // Copy the induced subgraph of odd nodes
+ std::vector<Node> odd_nodes;
+ for (NodeIt u(_gr); u != INVALID; ++u) {
+ if (deg[u] % 2 == 1) odd_nodes.push_back(u);
+ }
+
+ SmartGraph sgr;
+ SmartGraph::EdgeMap<Cost> scost(sgr);
+ for (int i = 0; i != int(odd_nodes.size()); ++i) {
+ sgr.addNode();
+ }
+ for (int i = 0; i != int(odd_nodes.size()); ++i) {
+ for (int j = 0; j != int(odd_nodes.size()); ++j) {
+ if (j == i) continue;
+ SmartGraph::Edge e =
+ sgr.addEdge(sgr.nodeFromId(i), sgr.nodeFromId(j));
+ scost[e] = -_cost[_gr.edge(odd_nodes[i], odd_nodes[j])];
+ }
+ }
+
+ // Compute min. cost perfect matching
+ MaxWeightedPerfectMatching<SmartGraph, SmartGraph::EdgeMap<Cost> >
+ mwpm(sgr, scost);
+ mwpm.run();
+
+ for (SmartGraph::EdgeIt e(sgr); e != INVALID; ++e) {
+ if (mwpm.matching(e)) {
+ tree.push_back( _gr.edge(odd_nodes[sgr.id(sgr.u(e))],
+ odd_nodes[sgr.id(sgr.v(e))]) );
+ }
+ }
+
+ // Join the spanning tree and the matching
+ sgr.clear();
+ for (int i = 0; i != _gr.nodeNum(); ++i) {
+ sgr.addNode();
+ }
+ for (int i = 0; i != int(tree.size()); ++i) {
+ int ui = _gr.id(_gr.u(tree[i])),
+ vi = _gr.id(_gr.v(tree[i]));
+ sgr.addEdge(sgr.nodeFromId(ui), sgr.nodeFromId(vi));
+ }
+
+ // Compute the tour from the Euler traversal
+ SmartGraph::NodeMap<bool> visited(sgr, false);
+ for (EulerIt<SmartGraph> e(sgr); e != INVALID; ++e) {
+ SmartGraph::Node n = sgr.target(e);
+ if (!visited[n]) {
+ _path.push_back(_gr(sgr.id(n)));
+ visited[n] = true;
+ }
+ }
+
+ _sum = _cost[_gr.edge(_path.back(), _path.front())];
+ for (int i = 0; i < int(_path.size())-1; ++i) {
+ _sum += _cost[_gr.edge(_path[i], _path[i+1])];
+ }
+
+ return _sum;
+ }
+
+ /// @}
+
+ /// \name Query Functions
+ /// @{
+
+ /// \brief The total cost of the found tour.
+ ///
+ /// This function returns the total cost of the found tour.
+ ///
+ /// \pre run() must be called before using this function.
+ Cost tourCost() const {
+ return _sum;
+ }
+
+ /// \brief Returns a const reference to the node sequence of the
+ /// found tour.
+ ///
+ /// This function returns a const reference to a vector
+ /// that stores the node sequence of the found tour.
+ ///
+ /// \pre run() must be called before using this function.
+ const std::vector<Node>& tourNodes() const {
+ return _path;
+ }
+
+ /// \brief Gives back the node sequence of the found tour.
+ ///
+ /// This function copies the node sequence of the found tour into
+ /// an STL container through the given output iterator. The
+ /// <tt>value_type</tt> of the container must be <tt>FullGraph::Node</tt>.
+ /// For example,
+ /// \code
+ /// std::vector<FullGraph::Node> nodes(countNodes(graph));
+ /// tsp.tourNodes(nodes.begin());
+ /// \endcode
+ /// or
+ /// \code
+ /// std::list<FullGraph::Node> nodes;
+ /// tsp.tourNodes(std::back_inserter(nodes));
+ /// \endcode
+ ///
+ /// \pre run() must be called before using this function.
+ template <typename Iterator>
+ void tourNodes(Iterator out) const {
+ std::copy(_path.begin(), _path.end(), out);
+ }
+
+ /// \brief Gives back the found tour as a path.
+ ///
+ /// This function copies the found tour as a list of arcs/edges into
+ /// the given \ref lemon::concepts::Path "path structure".
+ ///
+ /// \pre run() must be called before using this function.
+ template <typename Path>
+ void tour(Path &path) const {
+ path.clear();
+ for (int i = 0; i < int(_path.size()) - 1; ++i) {
+ path.addBack(_gr.arc(_path[i], _path[i+1]));
+ }
+ if (int(_path.size()) >= 2) {
+ path.addBack(_gr.arc(_path.back(), _path.front()));
+ }
+ }
+
+ /// @}
+
+ };
+
+}; // namespace lemon
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/circulation.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/circulation.h
new file mode 100644
index 00000000000..b0f717b2615
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/circulation.h
@@ -0,0 +1,807 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_CIRCULATION_H
+#define LEMON_CIRCULATION_H
+
+#include <lemon/tolerance.h>
+#include <lemon/elevator.h>
+#include <limits>
+
+///\ingroup max_flow
+///\file
+///\brief Push-relabel algorithm for finding a feasible circulation.
+///
+namespace lemon {
+
+ /// \brief Default traits class of Circulation class.
+ ///
+ /// Default traits class of Circulation class.
+ ///
+ /// \tparam GR Type of the digraph the algorithm runs on.
+ /// \tparam LM The type of the lower bound map.
+ /// \tparam UM The type of the upper bound (capacity) map.
+ /// \tparam SM The type of the supply map.
+ template <typename GR, typename LM,
+ typename UM, typename SM>
+ struct CirculationDefaultTraits {
+
+ /// \brief The type of the digraph the algorithm runs on.
+ typedef GR Digraph;
+
+ /// \brief The type of the lower bound map.
+ ///
+ /// The type of the map that stores the lower bounds on the arcs.
+ /// It must conform to the \ref concepts::ReadMap "ReadMap" concept.
+ typedef LM LowerMap;
+
+ /// \brief The type of the upper bound (capacity) map.
+ ///
+ /// The type of the map that stores the upper bounds (capacities)
+ /// on the arcs.
+ /// It must conform to the \ref concepts::ReadMap "ReadMap" concept.
+ typedef UM UpperMap;
+
+ /// \brief The type of supply map.
+ ///
+ /// The type of the map that stores the signed supply values of the
+ /// nodes.
+ /// It must conform to the \ref concepts::ReadMap "ReadMap" concept.
+ typedef SM SupplyMap;
+
+ /// \brief The type of the flow and supply values.
+ typedef typename SupplyMap::Value Value;
+
+ /// \brief The type of the map that stores the flow values.
+ ///
+ /// The type of the map that stores the flow values.
+ /// It must conform to the \ref concepts::ReadWriteMap "ReadWriteMap"
+ /// concept.
+#ifdef DOXYGEN
+ typedef GR::ArcMap<Value> FlowMap;
+#else
+ typedef typename Digraph::template ArcMap<Value> FlowMap;
+#endif
+
+ /// \brief Instantiates a FlowMap.
+ ///
+ /// This function instantiates a \ref FlowMap.
+ /// \param digraph The digraph for which we would like to define
+ /// the flow map.
+ static FlowMap* createFlowMap(const Digraph& digraph) {
+ return new FlowMap(digraph);
+ }
+
+ /// \brief The elevator type used by the algorithm.
+ ///
+ /// The elevator type used by the algorithm.
+ ///
+ /// \sa Elevator, LinkedElevator
+#ifdef DOXYGEN
+ typedef lemon::Elevator<GR, GR::Node> Elevator;
+#else
+ typedef lemon::Elevator<Digraph, typename Digraph::Node> Elevator;
+#endif
+
+ /// \brief Instantiates an Elevator.
+ ///
+ /// This function instantiates an \ref Elevator.
+ /// \param digraph The digraph for which we would like to define
+ /// the elevator.
+ /// \param max_level The maximum level of the elevator.
+ static Elevator* createElevator(const Digraph& digraph, int max_level) {
+ return new Elevator(digraph, max_level);
+ }
+
+ /// \brief The tolerance used by the algorithm
+ ///
+ /// The tolerance used by the algorithm to handle inexact computation.
+ typedef lemon::Tolerance<Value> Tolerance;
+
+ };
+
+ /**
+ \brief Push-relabel algorithm for the network circulation problem.
+
+ \ingroup max_flow
+ This class implements a push-relabel algorithm for the \e network
+ \e circulation problem.
+ It is to find a feasible circulation when lower and upper bounds
+ are given for the flow values on the arcs and lower bounds are
+ given for the difference between the outgoing and incoming flow
+ at the nodes.
+
+ The exact formulation of this problem is the following.
+ Let \f$G=(V,A)\f$ be a digraph, \f$lower: A\rightarrow\mathbf{R}\f$
+ \f$upper: A\rightarrow\mathbf{R}\cup\{\infty\}\f$ denote the lower and
+ upper bounds on the arcs, for which \f$lower(uv) \leq upper(uv)\f$
+ holds for all \f$uv\in A\f$, and \f$sup: V\rightarrow\mathbf{R}\f$
+ denotes the signed supply values of the nodes.
+ If \f$sup(u)>0\f$, then \f$u\f$ is a supply node with \f$sup(u)\f$
+ supply, if \f$sup(u)<0\f$, then \f$u\f$ is a demand node with
+ \f$-sup(u)\f$ demand.
+ A feasible circulation is an \f$f: A\rightarrow\mathbf{R}\f$
+ solution of the following problem.
+
+ \f[ \sum_{uv\in A} f(uv) - \sum_{vu\in A} f(vu)
+ \geq sup(u) \quad \forall u\in V, \f]
+ \f[ lower(uv) \leq f(uv) \leq upper(uv) \quad \forall uv\in A. \f]
+
+ The sum of the supply values, i.e. \f$\sum_{u\in V} sup(u)\f$ must be
+ zero or negative in order to have a feasible solution (since the sum
+ of the expressions on the left-hand side of the inequalities is zero).
+ It means that the total demand must be greater or equal to the total
+ supply and all the supplies have to be carried out from the supply nodes,
+ but there could be demands that are not satisfied.
+ If \f$\sum_{u\in V} sup(u)\f$ is zero, then all the supply/demand
+ constraints have to be satisfied with equality, i.e. all demands
+ have to be satisfied and all supplies have to be used.
+
+ If you need the opposite inequalities in the supply/demand constraints
+ (i.e. the total demand is less than the total supply and all the demands
+ have to be satisfied while there could be supplies that are not used),
+ then you could easily transform the problem to the above form by reversing
+ the direction of the arcs and taking the negative of the supply values
+ (e.g. using \ref ReverseDigraph and \ref NegMap adaptors).
+
+ This algorithm either calculates a feasible circulation, or provides
+ a \ref barrier() "barrier", which prooves that a feasible soultion
+ cannot exist.
+
+ Note that this algorithm also provides a feasible solution for the
+ \ref min_cost_flow "minimum cost flow problem".
+
+ \tparam GR The type of the digraph the algorithm runs on.
+ \tparam LM The type of the lower bound map. The default
+ map type is \ref concepts::Digraph::ArcMap "GR::ArcMap<int>".
+ \tparam UM The type of the upper bound (capacity) map.
+ The default map type is \c LM.
+ \tparam SM The type of the supply map. The default map type is
+ \ref concepts::Digraph::NodeMap "GR::NodeMap<UM::Value>".
+ \tparam TR The traits class that defines various types used by the
+ algorithm. By default, it is \ref CirculationDefaultTraits
+ "CirculationDefaultTraits<GR, LM, UM, SM>".
+ In most cases, this parameter should not be set directly,
+ consider to use the named template parameters instead.
+ */
+#ifdef DOXYGEN
+template< typename GR,
+ typename LM,
+ typename UM,
+ typename SM,
+ typename TR >
+#else
+template< typename GR,
+ typename LM = typename GR::template ArcMap<int>,
+ typename UM = LM,
+ typename SM = typename GR::template NodeMap<typename UM::Value>,
+ typename TR = CirculationDefaultTraits<GR, LM, UM, SM> >
+#endif
+ class Circulation {
+ public:
+
+ /// \brief The \ref lemon::CirculationDefaultTraits "traits class"
+ /// of the algorithm.
+ typedef TR Traits;
+ ///The type of the digraph the algorithm runs on.
+ typedef typename Traits::Digraph Digraph;
+ ///The type of the flow and supply values.
+ typedef typename Traits::Value Value;
+
+ ///The type of the lower bound map.
+ typedef typename Traits::LowerMap LowerMap;
+ ///The type of the upper bound (capacity) map.
+ typedef typename Traits::UpperMap UpperMap;
+ ///The type of the supply map.
+ typedef typename Traits::SupplyMap SupplyMap;
+ ///The type of the flow map.
+ typedef typename Traits::FlowMap FlowMap;
+
+ ///The type of the elevator.
+ typedef typename Traits::Elevator Elevator;
+ ///The type of the tolerance.
+ typedef typename Traits::Tolerance Tolerance;
+
+ private:
+
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+
+ const Digraph &_g;
+ int _node_num;
+
+ const LowerMap *_lo;
+ const UpperMap *_up;
+ const SupplyMap *_supply;
+
+ FlowMap *_flow;
+ bool _local_flow;
+
+ Elevator* _level;
+ bool _local_level;
+
+ typedef typename Digraph::template NodeMap<Value> ExcessMap;
+ ExcessMap* _excess;
+
+ Tolerance _tol;
+ int _el;
+
+ public:
+
+ typedef Circulation Create;
+
+ ///\name Named Template Parameters
+
+ ///@{
+
+ template <typename T>
+ struct SetFlowMapTraits : public Traits {
+ typedef T FlowMap;
+ static FlowMap *createFlowMap(const Digraph&) {
+ LEMON_ASSERT(false, "FlowMap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// FlowMap type
+ ///
+ /// \ref named-templ-param "Named parameter" for setting FlowMap
+ /// type.
+ template <typename T>
+ struct SetFlowMap
+ : public Circulation<Digraph, LowerMap, UpperMap, SupplyMap,
+ SetFlowMapTraits<T> > {
+ typedef Circulation<Digraph, LowerMap, UpperMap, SupplyMap,
+ SetFlowMapTraits<T> > Create;
+ };
+
+ template <typename T>
+ struct SetElevatorTraits : public Traits {
+ typedef T Elevator;
+ static Elevator *createElevator(const Digraph&, int) {
+ LEMON_ASSERT(false, "Elevator is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// Elevator type
+ ///
+ /// \ref named-templ-param "Named parameter" for setting Elevator
+ /// type. If this named parameter is used, then an external
+ /// elevator object must be passed to the algorithm using the
+ /// \ref elevator(Elevator&) "elevator()" function before calling
+ /// \ref run() or \ref init().
+ /// \sa SetStandardElevator
+ template <typename T>
+ struct SetElevator
+ : public Circulation<Digraph, LowerMap, UpperMap, SupplyMap,
+ SetElevatorTraits<T> > {
+ typedef Circulation<Digraph, LowerMap, UpperMap, SupplyMap,
+ SetElevatorTraits<T> > Create;
+ };
+
+ template <typename T>
+ struct SetStandardElevatorTraits : public Traits {
+ typedef T Elevator;
+ static Elevator *createElevator(const Digraph& digraph, int max_level) {
+ return new Elevator(digraph, max_level);
+ }
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// Elevator type with automatic allocation
+ ///
+ /// \ref named-templ-param "Named parameter" for setting Elevator
+ /// type with automatic allocation.
+ /// The Elevator should have standard constructor interface to be
+ /// able to automatically created by the algorithm (i.e. the
+ /// digraph and the maximum level should be passed to it).
+ /// However, an external elevator object could also be passed to the
+ /// algorithm with the \ref elevator(Elevator&) "elevator()" function
+ /// before calling \ref run() or \ref init().
+ /// \sa SetElevator
+ template <typename T>
+ struct SetStandardElevator
+ : public Circulation<Digraph, LowerMap, UpperMap, SupplyMap,
+ SetStandardElevatorTraits<T> > {
+ typedef Circulation<Digraph, LowerMap, UpperMap, SupplyMap,
+ SetStandardElevatorTraits<T> > Create;
+ };
+
+ /// @}
+
+ protected:
+
+ Circulation() {}
+
+ public:
+
+ /// Constructor.
+
+ /// The constructor of the class.
+ ///
+ /// \param graph The digraph the algorithm runs on.
+ /// \param lower The lower bounds for the flow values on the arcs.
+ /// \param upper The upper bounds (capacities) for the flow values
+ /// on the arcs.
+ /// \param supply The signed supply values of the nodes.
+ Circulation(const Digraph &graph, const LowerMap &lower,
+ const UpperMap &upper, const SupplyMap &supply)
+ : _g(graph), _lo(&lower), _up(&upper), _supply(&supply),
+ _flow(NULL), _local_flow(false), _level(NULL), _local_level(false),
+ _excess(NULL) {}
+
+ /// Destructor.
+ ~Circulation() {
+ destroyStructures();
+ }
+
+
+ private:
+
+ bool checkBoundMaps() {
+ for (ArcIt e(_g);e!=INVALID;++e) {
+ if (_tol.less((*_up)[e], (*_lo)[e])) return false;
+ }
+ return true;
+ }
+
+ void createStructures() {
+ _node_num = _el = countNodes(_g);
+
+ if (!_flow) {
+ _flow = Traits::createFlowMap(_g);
+ _local_flow = true;
+ }
+ if (!_level) {
+ _level = Traits::createElevator(_g, _node_num);
+ _local_level = true;
+ }
+ if (!_excess) {
+ _excess = new ExcessMap(_g);
+ }
+ }
+
+ void destroyStructures() {
+ if (_local_flow) {
+ delete _flow;
+ }
+ if (_local_level) {
+ delete _level;
+ }
+ if (_excess) {
+ delete _excess;
+ }
+ }
+
+ public:
+
+ /// Sets the lower bound map.
+
+ /// Sets the lower bound map.
+ /// \return <tt>(*this)</tt>
+ Circulation& lowerMap(const LowerMap& map) {
+ _lo = &map;
+ return *this;
+ }
+
+ /// Sets the upper bound (capacity) map.
+
+ /// Sets the upper bound (capacity) map.
+ /// \return <tt>(*this)</tt>
+ Circulation& upperMap(const UpperMap& map) {
+ _up = &map;
+ return *this;
+ }
+
+ /// Sets the supply map.
+
+ /// Sets the supply map.
+ /// \return <tt>(*this)</tt>
+ Circulation& supplyMap(const SupplyMap& map) {
+ _supply = &map;
+ return *this;
+ }
+
+ /// \brief Sets the flow map.
+ ///
+ /// Sets the flow map.
+ /// If you don't use this function before calling \ref run() or
+ /// \ref init(), an instance will be allocated automatically.
+ /// The destructor deallocates this automatically allocated map,
+ /// of course.
+ /// \return <tt>(*this)</tt>
+ Circulation& flowMap(FlowMap& map) {
+ if (_local_flow) {
+ delete _flow;
+ _local_flow = false;
+ }
+ _flow = &map;
+ return *this;
+ }
+
+ /// \brief Sets the elevator used by algorithm.
+ ///
+ /// Sets the elevator used by algorithm.
+ /// If you don't use this function before calling \ref run() or
+ /// \ref init(), an instance will be allocated automatically.
+ /// The destructor deallocates this automatically allocated elevator,
+ /// of course.
+ /// \return <tt>(*this)</tt>
+ Circulation& elevator(Elevator& elevator) {
+ if (_local_level) {
+ delete _level;
+ _local_level = false;
+ }
+ _level = &elevator;
+ return *this;
+ }
+
+ /// \brief Returns a const reference to the elevator.
+ ///
+ /// Returns a const reference to the elevator.
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ const Elevator& elevator() const {
+ return *_level;
+ }
+
+ /// \brief Sets the tolerance used by the algorithm.
+ ///
+ /// Sets the tolerance object used by the algorithm.
+ /// \return <tt>(*this)</tt>
+ Circulation& tolerance(const Tolerance& tolerance) {
+ _tol = tolerance;
+ return *this;
+ }
+
+ /// \brief Returns a const reference to the tolerance.
+ ///
+ /// Returns a const reference to the tolerance object used by
+ /// the algorithm.
+ const Tolerance& tolerance() const {
+ return _tol;
+ }
+
+ /// \name Execution Control
+ /// The simplest way to execute the algorithm is to call \ref run().\n
+ /// If you need better control on the initial solution or the execution,
+ /// you have to call one of the \ref init() functions first, then
+ /// the \ref start() function.
+
+ ///@{
+
+ /// Initializes the internal data structures.
+
+ /// Initializes the internal data structures and sets all flow values
+ /// to the lower bound.
+ void init()
+ {
+ LEMON_DEBUG(checkBoundMaps(),
+ "Upper bounds must be greater or equal to the lower bounds");
+
+ createStructures();
+
+ for(NodeIt n(_g);n!=INVALID;++n) {
+ (*_excess)[n] = (*_supply)[n];
+ }
+
+ for (ArcIt e(_g);e!=INVALID;++e) {
+ _flow->set(e, (*_lo)[e]);
+ (*_excess)[_g.target(e)] += (*_flow)[e];
+ (*_excess)[_g.source(e)] -= (*_flow)[e];
+ }
+
+ // global relabeling tested, but in general case it provides
+ // worse performance for random digraphs
+ _level->initStart();
+ for(NodeIt n(_g);n!=INVALID;++n)
+ _level->initAddItem(n);
+ _level->initFinish();
+ for(NodeIt n(_g);n!=INVALID;++n)
+ if(_tol.positive((*_excess)[n]))
+ _level->activate(n);
+ }
+
+ /// Initializes the internal data structures using a greedy approach.
+
+ /// Initializes the internal data structures using a greedy approach
+ /// to construct the initial solution.
+ void greedyInit()
+ {
+ LEMON_DEBUG(checkBoundMaps(),
+ "Upper bounds must be greater or equal to the lower bounds");
+
+ createStructures();
+
+ for(NodeIt n(_g);n!=INVALID;++n) {
+ (*_excess)[n] = (*_supply)[n];
+ }
+
+ for (ArcIt e(_g);e!=INVALID;++e) {
+ if (!_tol.less(-(*_excess)[_g.target(e)], (*_up)[e])) {
+ _flow->set(e, (*_up)[e]);
+ (*_excess)[_g.target(e)] += (*_up)[e];
+ (*_excess)[_g.source(e)] -= (*_up)[e];
+ } else if (_tol.less(-(*_excess)[_g.target(e)], (*_lo)[e])) {
+ _flow->set(e, (*_lo)[e]);
+ (*_excess)[_g.target(e)] += (*_lo)[e];
+ (*_excess)[_g.source(e)] -= (*_lo)[e];
+ } else {
+ Value fc = -(*_excess)[_g.target(e)];
+ _flow->set(e, fc);
+ (*_excess)[_g.target(e)] = 0;
+ (*_excess)[_g.source(e)] -= fc;
+ }
+ }
+
+ _level->initStart();
+ for(NodeIt n(_g);n!=INVALID;++n)
+ _level->initAddItem(n);
+ _level->initFinish();
+ for(NodeIt n(_g);n!=INVALID;++n)
+ if(_tol.positive((*_excess)[n]))
+ _level->activate(n);
+ }
+
+ ///Executes the algorithm
+
+ ///This function executes the algorithm.
+ ///
+ ///\return \c true if a feasible circulation is found.
+ ///
+ ///\sa barrier()
+ ///\sa barrierMap()
+ bool start()
+ {
+
+ Node act;
+ while((act=_level->highestActive())!=INVALID) {
+ int actlevel=(*_level)[act];
+ int mlevel=_node_num;
+ Value exc=(*_excess)[act];
+
+ for(OutArcIt e(_g,act);e!=INVALID; ++e) {
+ Node v = _g.target(e);
+ Value fc=(*_up)[e]-(*_flow)[e];
+ if(!_tol.positive(fc)) continue;
+ if((*_level)[v]<actlevel) {
+ if(!_tol.less(fc, exc)) {
+ _flow->set(e, (*_flow)[e] + exc);
+ (*_excess)[v] += exc;
+ if(!_level->active(v) && _tol.positive((*_excess)[v]))
+ _level->activate(v);
+ (*_excess)[act] = 0;
+ _level->deactivate(act);
+ goto next_l;
+ }
+ else {
+ _flow->set(e, (*_up)[e]);
+ (*_excess)[v] += fc;
+ if(!_level->active(v) && _tol.positive((*_excess)[v]))
+ _level->activate(v);
+ exc-=fc;
+ }
+ }
+ else if((*_level)[v]<mlevel) mlevel=(*_level)[v];
+ }
+ for(InArcIt e(_g,act);e!=INVALID; ++e) {
+ Node v = _g.source(e);
+ Value fc=(*_flow)[e]-(*_lo)[e];
+ if(!_tol.positive(fc)) continue;
+ if((*_level)[v]<actlevel) {
+ if(!_tol.less(fc, exc)) {
+ _flow->set(e, (*_flow)[e] - exc);
+ (*_excess)[v] += exc;
+ if(!_level->active(v) && _tol.positive((*_excess)[v]))
+ _level->activate(v);
+ (*_excess)[act] = 0;
+ _level->deactivate(act);
+ goto next_l;
+ }
+ else {
+ _flow->set(e, (*_lo)[e]);
+ (*_excess)[v] += fc;
+ if(!_level->active(v) && _tol.positive((*_excess)[v]))
+ _level->activate(v);
+ exc-=fc;
+ }
+ }
+ else if((*_level)[v]<mlevel) mlevel=(*_level)[v];
+ }
+
+ (*_excess)[act] = exc;
+ if(!_tol.positive(exc)) _level->deactivate(act);
+ else if(mlevel==_node_num) {
+ _level->liftHighestActiveToTop();
+ _el = _node_num;
+ return false;
+ }
+ else {
+ _level->liftHighestActive(mlevel+1);
+ if(_level->onLevel(actlevel)==0) {
+ _el = actlevel;
+ return false;
+ }
+ }
+ next_l:
+ ;
+ }
+ return true;
+ }
+
+ /// Runs the algorithm.
+
+ /// This function runs the algorithm.
+ ///
+ /// \return \c true if a feasible circulation is found.
+ ///
+ /// \note Apart from the return value, c.run() is just a shortcut of
+ /// the following code.
+ /// \code
+ /// c.greedyInit();
+ /// c.start();
+ /// \endcode
+ bool run() {
+ greedyInit();
+ return start();
+ }
+
+ /// @}
+
+ /// \name Query Functions
+ /// The results of the circulation algorithm can be obtained using
+ /// these functions.\n
+ /// Either \ref run() or \ref start() should be called before
+ /// using them.
+
+ ///@{
+
+ /// \brief Returns the flow value on the given arc.
+ ///
+ /// Returns the flow value on the given arc.
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ Value flow(const Arc& arc) const {
+ return (*_flow)[arc];
+ }
+
+ /// \brief Returns a const reference to the flow map.
+ ///
+ /// Returns a const reference to the arc map storing the found flow.
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ const FlowMap& flowMap() const {
+ return *_flow;
+ }
+
+ /**
+ \brief Returns \c true if the given node is in a barrier.
+
+ Barrier is a set \e B of nodes for which
+
+ \f[ \sum_{uv\in A: u\in B} upper(uv) -
+ \sum_{uv\in A: v\in B} lower(uv) < \sum_{v\in B} sup(v) \f]
+
+ holds. The existence of a set with this property prooves that a
+ feasible circualtion cannot exist.
+
+ This function returns \c true if the given node is in the found
+ barrier. If a feasible circulation is found, the function
+ gives back \c false for every node.
+
+ \pre Either \ref run() or \ref init() must be called before
+ using this function.
+
+ \sa barrierMap()
+ \sa checkBarrier()
+ */
+ bool barrier(const Node& node) const
+ {
+ return (*_level)[node] >= _el;
+ }
+
+ /// \brief Gives back a barrier.
+ ///
+ /// This function sets \c bar to the characteristic vector of the
+ /// found barrier. \c bar should be a \ref concepts::WriteMap "writable"
+ /// node map with \c bool (or convertible) value type.
+ ///
+ /// If a feasible circulation is found, the function gives back an
+ /// empty set, so \c bar[v] will be \c false for all nodes \c v.
+ ///
+ /// \note This function calls \ref barrier() for each node,
+ /// so it runs in O(n) time.
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ ///
+ /// \sa barrier()
+ /// \sa checkBarrier()
+ template<class BarrierMap>
+ void barrierMap(BarrierMap &bar) const
+ {
+ for(NodeIt n(_g);n!=INVALID;++n)
+ bar.set(n, (*_level)[n] >= _el);
+ }
+
+ /// @}
+
+ /// \name Checker Functions
+ /// The feasibility of the results can be checked using
+ /// these functions.\n
+ /// Either \ref run() or \ref start() should be called before
+ /// using them.
+
+ ///@{
+
+ ///Check if the found flow is a feasible circulation
+
+ ///Check if the found flow is a feasible circulation,
+ ///
+ bool checkFlow() const {
+ for(ArcIt e(_g);e!=INVALID;++e)
+ if((*_flow)[e]<(*_lo)[e]||(*_flow)[e]>(*_up)[e]) return false;
+ for(NodeIt n(_g);n!=INVALID;++n)
+ {
+ Value dif=-(*_supply)[n];
+ for(InArcIt e(_g,n);e!=INVALID;++e) dif-=(*_flow)[e];
+ for(OutArcIt e(_g,n);e!=INVALID;++e) dif+=(*_flow)[e];
+ if(_tol.negative(dif)) return false;
+ }
+ return true;
+ }
+
+ ///Check whether or not the last execution provides a barrier
+
+ ///Check whether or not the last execution provides a barrier.
+ ///\sa barrier()
+ ///\sa barrierMap()
+ bool checkBarrier() const
+ {
+ Value delta=0;
+ Value inf_cap = std::numeric_limits<Value>::has_infinity ?
+ std::numeric_limits<Value>::infinity() :
+ std::numeric_limits<Value>::max();
+ for(NodeIt n(_g);n!=INVALID;++n)
+ if(barrier(n))
+ delta-=(*_supply)[n];
+ for(ArcIt e(_g);e!=INVALID;++e)
+ {
+ Node s=_g.source(e);
+ Node t=_g.target(e);
+ if(barrier(s)&&!barrier(t)) {
+ if (_tol.less(inf_cap - (*_up)[e], delta)) return false;
+ delta+=(*_up)[e];
+ }
+ else if(barrier(t)&&!barrier(s)) delta-=(*_lo)[e];
+ }
+ return _tol.negative(delta);
+ }
+
+ /// @}
+
+ };
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/clp.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/clp.cc
new file mode 100644
index 00000000000..7c0ea74f22c
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/clp.cc
@@ -0,0 +1,464 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <lemon/clp.h>
+#include <coin/ClpSimplex.hpp>
+
+namespace lemon {
+
+ ClpLp::ClpLp() {
+ _prob = new ClpSimplex();
+ _init_temporals();
+ messageLevel(MESSAGE_NOTHING);
+ }
+
+ ClpLp::ClpLp(const ClpLp& other) {
+ _prob = new ClpSimplex(*other._prob);
+ rows = other.rows;
+ cols = other.cols;
+ _init_temporals();
+ messageLevel(MESSAGE_NOTHING);
+ }
+
+ ClpLp::~ClpLp() {
+ delete _prob;
+ _clear_temporals();
+ }
+
+ void ClpLp::_init_temporals() {
+ _primal_ray = 0;
+ _dual_ray = 0;
+ }
+
+ void ClpLp::_clear_temporals() {
+ if (_primal_ray) {
+ delete[] _primal_ray;
+ _primal_ray = 0;
+ }
+ if (_dual_ray) {
+ delete[] _dual_ray;
+ _dual_ray = 0;
+ }
+ }
+
+ ClpLp* ClpLp::newSolver() const {
+ ClpLp* newlp = new ClpLp;
+ return newlp;
+ }
+
+ ClpLp* ClpLp::cloneSolver() const {
+ ClpLp* copylp = new ClpLp(*this);
+ return copylp;
+ }
+
+ const char* ClpLp::_solverName() const { return "ClpLp"; }
+
+ int ClpLp::_addCol() {
+ _prob->addColumn(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX, 0.0);
+ return _prob->numberColumns() - 1;
+ }
+
+ int ClpLp::_addRow() {
+ _prob->addRow(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX);
+ return _prob->numberRows() - 1;
+ }
+
+ int ClpLp::_addRow(Value l, ExprIterator b, ExprIterator e, Value u) {
+ std::vector<int> indexes;
+ std::vector<Value> values;
+
+ for(ExprIterator it = b; it != e; ++it) {
+ indexes.push_back(it->first);
+ values.push_back(it->second);
+ }
+
+ _prob->addRow(values.size(), &indexes.front(), &values.front(), l, u);
+ return _prob->numberRows() - 1;
+ }
+
+
+ void ClpLp::_eraseCol(int c) {
+ _col_names_ref.erase(_prob->getColumnName(c));
+ _prob->deleteColumns(1, &c);
+ }
+
+ void ClpLp::_eraseRow(int r) {
+ _row_names_ref.erase(_prob->getRowName(r));
+ _prob->deleteRows(1, &r);
+ }
+
+ void ClpLp::_eraseColId(int i) {
+ cols.eraseIndex(i);
+ cols.shiftIndices(i);
+ }
+
+ void ClpLp::_eraseRowId(int i) {
+ rows.eraseIndex(i);
+ rows.shiftIndices(i);
+ }
+
+ void ClpLp::_getColName(int c, std::string& name) const {
+ name = _prob->getColumnName(c);
+ }
+
+ void ClpLp::_setColName(int c, const std::string& name) {
+ _prob->setColumnName(c, const_cast<std::string&>(name));
+ _col_names_ref[name] = c;
+ }
+
+ int ClpLp::_colByName(const std::string& name) const {
+ std::map<std::string, int>::const_iterator it = _col_names_ref.find(name);
+ return it != _col_names_ref.end() ? it->second : -1;
+ }
+
+ void ClpLp::_getRowName(int r, std::string& name) const {
+ name = _prob->getRowName(r);
+ }
+
+ void ClpLp::_setRowName(int r, const std::string& name) {
+ _prob->setRowName(r, const_cast<std::string&>(name));
+ _row_names_ref[name] = r;
+ }
+
+ int ClpLp::_rowByName(const std::string& name) const {
+ std::map<std::string, int>::const_iterator it = _row_names_ref.find(name);
+ return it != _row_names_ref.end() ? it->second : -1;
+ }
+
+
+ void ClpLp::_setRowCoeffs(int ix, ExprIterator b, ExprIterator e) {
+ std::map<int, Value> coeffs;
+
+ int n = _prob->clpMatrix()->getNumCols();
+
+ const int* indices = _prob->clpMatrix()->getIndices();
+ const double* elements = _prob->clpMatrix()->getElements();
+
+ for (int i = 0; i < n; ++i) {
+ CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[i];
+ CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[i];
+
+ const int* it = std::lower_bound(indices + begin, indices + end, ix);
+ if (it != indices + end && *it == ix && elements[it - indices] != 0.0) {
+ coeffs[i] = 0.0;
+ }
+ }
+
+ for (ExprIterator it = b; it != e; ++it) {
+ coeffs[it->first] = it->second;
+ }
+
+ for (std::map<int, Value>::iterator it = coeffs.begin();
+ it != coeffs.end(); ++it) {
+ _prob->modifyCoefficient(ix, it->first, it->second);
+ }
+ }
+
+ void ClpLp::_getRowCoeffs(int ix, InsertIterator b) const {
+ int n = _prob->clpMatrix()->getNumCols();
+
+ const int* indices = _prob->clpMatrix()->getIndices();
+ const double* elements = _prob->clpMatrix()->getElements();
+
+ for (int i = 0; i < n; ++i) {
+ CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[i];
+ CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[i];
+
+ const int* it = std::lower_bound(indices + begin, indices + end, ix);
+ if (it != indices + end && *it == ix) {
+ *b = std::make_pair(i, elements[it - indices]);
+ }
+ }
+ }
+
+ void ClpLp::_setColCoeffs(int ix, ExprIterator b, ExprIterator e) {
+ std::map<int, Value> coeffs;
+
+ CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix];
+ CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix];
+
+ const int* indices = _prob->clpMatrix()->getIndices();
+ const double* elements = _prob->clpMatrix()->getElements();
+
+ for (CoinBigIndex i = begin; i != end; ++i) {
+ if (elements[i] != 0.0) {
+ coeffs[indices[i]] = 0.0;
+ }
+ }
+ for (ExprIterator it = b; it != e; ++it) {
+ coeffs[it->first] = it->second;
+ }
+ for (std::map<int, Value>::iterator it = coeffs.begin();
+ it != coeffs.end(); ++it) {
+ _prob->modifyCoefficient(it->first, ix, it->second);
+ }
+ }
+
+ void ClpLp::_getColCoeffs(int ix, InsertIterator b) const {
+ CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix];
+ CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix];
+
+ const int* indices = _prob->clpMatrix()->getIndices();
+ const double* elements = _prob->clpMatrix()->getElements();
+
+ for (CoinBigIndex i = begin; i != end; ++i) {
+ *b = std::make_pair(indices[i], elements[i]);
+ ++b;
+ }
+ }
+
+ void ClpLp::_setCoeff(int ix, int jx, Value value) {
+ _prob->modifyCoefficient(ix, jx, value);
+ }
+
+ ClpLp::Value ClpLp::_getCoeff(int ix, int jx) const {
+ CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix];
+ CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix];
+
+ const int* indices = _prob->clpMatrix()->getIndices();
+ const double* elements = _prob->clpMatrix()->getElements();
+
+ const int* it = std::lower_bound(indices + begin, indices + end, jx);
+ if (it != indices + end && *it == jx) {
+ return elements[it - indices];
+ } else {
+ return 0.0;
+ }
+ }
+
+ void ClpLp::_setColLowerBound(int i, Value lo) {
+ _prob->setColumnLower(i, lo == - INF ? - COIN_DBL_MAX : lo);
+ }
+
+ ClpLp::Value ClpLp::_getColLowerBound(int i) const {
+ double val = _prob->getColLower()[i];
+ return val == - COIN_DBL_MAX ? - INF : val;
+ }
+
+ void ClpLp::_setColUpperBound(int i, Value up) {
+ _prob->setColumnUpper(i, up == INF ? COIN_DBL_MAX : up);
+ }
+
+ ClpLp::Value ClpLp::_getColUpperBound(int i) const {
+ double val = _prob->getColUpper()[i];
+ return val == COIN_DBL_MAX ? INF : val;
+ }
+
+ void ClpLp::_setRowLowerBound(int i, Value lo) {
+ _prob->setRowLower(i, lo == - INF ? - COIN_DBL_MAX : lo);
+ }
+
+ ClpLp::Value ClpLp::_getRowLowerBound(int i) const {
+ double val = _prob->getRowLower()[i];
+ return val == - COIN_DBL_MAX ? - INF : val;
+ }
+
+ void ClpLp::_setRowUpperBound(int i, Value up) {
+ _prob->setRowUpper(i, up == INF ? COIN_DBL_MAX : up);
+ }
+
+ ClpLp::Value ClpLp::_getRowUpperBound(int i) const {
+ double val = _prob->getRowUpper()[i];
+ return val == COIN_DBL_MAX ? INF : val;
+ }
+
+ void ClpLp::_setObjCoeffs(ExprIterator b, ExprIterator e) {
+ int num = _prob->clpMatrix()->getNumCols();
+ for (int i = 0; i < num; ++i) {
+ _prob->setObjectiveCoefficient(i, 0.0);
+ }
+ for (ExprIterator it = b; it != e; ++it) {
+ _prob->setObjectiveCoefficient(it->first, it->second);
+ }
+ }
+
+ void ClpLp::_getObjCoeffs(InsertIterator b) const {
+ int num = _prob->clpMatrix()->getNumCols();
+ for (int i = 0; i < num; ++i) {
+ Value coef = _prob->getObjCoefficients()[i];
+ if (coef != 0.0) {
+ *b = std::make_pair(i, coef);
+ ++b;
+ }
+ }
+ }
+
+ void ClpLp::_setObjCoeff(int i, Value obj_coef) {
+ _prob->setObjectiveCoefficient(i, obj_coef);
+ }
+
+ ClpLp::Value ClpLp::_getObjCoeff(int i) const {
+ return _prob->getObjCoefficients()[i];
+ }
+
+ ClpLp::SolveExitStatus ClpLp::_solve() {
+ return _prob->primal() >= 0 ? SOLVED : UNSOLVED;
+ }
+
+ ClpLp::SolveExitStatus ClpLp::solvePrimal() {
+ return _prob->primal() >= 0 ? SOLVED : UNSOLVED;
+ }
+
+ ClpLp::SolveExitStatus ClpLp::solveDual() {
+ return _prob->dual() >= 0 ? SOLVED : UNSOLVED;
+ }
+
+ ClpLp::SolveExitStatus ClpLp::solveBarrier() {
+ return _prob->barrier() >= 0 ? SOLVED : UNSOLVED;
+ }
+
+ ClpLp::Value ClpLp::_getPrimal(int i) const {
+ return _prob->primalColumnSolution()[i];
+ }
+ ClpLp::Value ClpLp::_getPrimalValue() const {
+ return _prob->objectiveValue();
+ }
+
+ ClpLp::Value ClpLp::_getDual(int i) const {
+ return _prob->dualRowSolution()[i];
+ }
+
+ ClpLp::Value ClpLp::_getPrimalRay(int i) const {
+ if (!_primal_ray) {
+ _primal_ray = _prob->unboundedRay();
+ LEMON_ASSERT(_primal_ray != 0, "Primal ray is not provided");
+ }
+ return _primal_ray[i];
+ }
+
+ ClpLp::Value ClpLp::_getDualRay(int i) const {
+ if (!_dual_ray) {
+ _dual_ray = _prob->infeasibilityRay();
+ LEMON_ASSERT(_dual_ray != 0, "Dual ray is not provided");
+ }
+ return _dual_ray[i];
+ }
+
+ ClpLp::VarStatus ClpLp::_getColStatus(int i) const {
+ switch (_prob->getColumnStatus(i)) {
+ case ClpSimplex::basic:
+ return BASIC;
+ case ClpSimplex::isFree:
+ return FREE;
+ case ClpSimplex::atUpperBound:
+ return UPPER;
+ case ClpSimplex::atLowerBound:
+ return LOWER;
+ case ClpSimplex::isFixed:
+ return FIXED;
+ case ClpSimplex::superBasic:
+ return FREE;
+ default:
+ LEMON_ASSERT(false, "Wrong column status");
+ return VarStatus();
+ }
+ }
+
+ ClpLp::VarStatus ClpLp::_getRowStatus(int i) const {
+ switch (_prob->getColumnStatus(i)) {
+ case ClpSimplex::basic:
+ return BASIC;
+ case ClpSimplex::isFree:
+ return FREE;
+ case ClpSimplex::atUpperBound:
+ return UPPER;
+ case ClpSimplex::atLowerBound:
+ return LOWER;
+ case ClpSimplex::isFixed:
+ return FIXED;
+ case ClpSimplex::superBasic:
+ return FREE;
+ default:
+ LEMON_ASSERT(false, "Wrong row status");
+ return VarStatus();
+ }
+ }
+
+
+ ClpLp::ProblemType ClpLp::_getPrimalType() const {
+ if (_prob->isProvenOptimal()) {
+ return OPTIMAL;
+ } else if (_prob->isProvenPrimalInfeasible()) {
+ return INFEASIBLE;
+ } else if (_prob->isProvenDualInfeasible()) {
+ return UNBOUNDED;
+ } else {
+ return UNDEFINED;
+ }
+ }
+
+ ClpLp::ProblemType ClpLp::_getDualType() const {
+ if (_prob->isProvenOptimal()) {
+ return OPTIMAL;
+ } else if (_prob->isProvenDualInfeasible()) {
+ return INFEASIBLE;
+ } else if (_prob->isProvenPrimalInfeasible()) {
+ return INFEASIBLE;
+ } else {
+ return UNDEFINED;
+ }
+ }
+
+ void ClpLp::_setSense(ClpLp::Sense sense) {
+ switch (sense) {
+ case MIN:
+ _prob->setOptimizationDirection(1);
+ break;
+ case MAX:
+ _prob->setOptimizationDirection(-1);
+ break;
+ }
+ }
+
+ ClpLp::Sense ClpLp::_getSense() const {
+ double dir = _prob->optimizationDirection();
+ if (dir > 0.0) {
+ return MIN;
+ } else {
+ return MAX;
+ }
+ }
+
+ void ClpLp::_clear() {
+ delete _prob;
+ _prob = new ClpSimplex();
+ _col_names_ref.clear();
+ _clear_temporals();
+ }
+
+ void ClpLp::_messageLevel(MessageLevel level) {
+ switch (level) {
+ case MESSAGE_NOTHING:
+ _prob->setLogLevel(0);
+ break;
+ case MESSAGE_ERROR:
+ _prob->setLogLevel(1);
+ break;
+ case MESSAGE_WARNING:
+ _prob->setLogLevel(2);
+ break;
+ case MESSAGE_NORMAL:
+ _prob->setLogLevel(3);
+ break;
+ case MESSAGE_VERBOSE:
+ _prob->setLogLevel(4);
+ break;
+ }
+ }
+
+} //END OF NAMESPACE LEMON
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/clp.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/clp.h
new file mode 100644
index 00000000000..fd331ac1354
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/clp.h
@@ -0,0 +1,164 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_CLP_H
+#define LEMON_CLP_H
+
+///\file
+///\brief Header of the LEMON-CLP lp solver interface.
+
+#include <vector>
+#include <string>
+
+#include <lemon/lp_base.h>
+
+class ClpSimplex;
+
+namespace lemon {
+
+ /// \ingroup lp_group
+ ///
+ /// \brief Interface for the CLP solver
+ ///
+ /// This class implements an interface for the Clp LP solver. The
+ /// Clp library is an object oriented lp solver library developed at
+ /// the IBM. The CLP is part of the COIN-OR package and it can be
+ /// used with Common Public License.
+ class ClpLp : public LpSolver {
+ protected:
+
+ ClpSimplex* _prob;
+
+ std::map<std::string, int> _col_names_ref;
+ std::map<std::string, int> _row_names_ref;
+
+ public:
+
+ /// \e
+ ClpLp();
+ /// \e
+ ClpLp(const ClpLp&);
+ /// \e
+ ~ClpLp();
+
+ /// \e
+ virtual ClpLp* newSolver() const;
+ /// \e
+ virtual ClpLp* cloneSolver() const;
+
+ protected:
+
+ mutable double* _primal_ray;
+ mutable double* _dual_ray;
+
+ void _init_temporals();
+ void _clear_temporals();
+
+ protected:
+
+ virtual const char* _solverName() const;
+
+ virtual int _addCol();
+ virtual int _addRow();
+ virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u);
+
+ virtual void _eraseCol(int i);
+ virtual void _eraseRow(int i);
+
+ virtual void _eraseColId(int i);
+ virtual void _eraseRowId(int i);
+
+ virtual void _getColName(int col, std::string& name) const;
+ virtual void _setColName(int col, const std::string& name);
+ virtual int _colByName(const std::string& name) const;
+
+ virtual void _getRowName(int row, std::string& name) const;
+ virtual void _setRowName(int row, const std::string& name);
+ virtual int _rowByName(const std::string& name) const;
+
+ virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e);
+ virtual void _getRowCoeffs(int i, InsertIterator b) const;
+
+ virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e);
+ virtual void _getColCoeffs(int i, InsertIterator b) const;
+
+ virtual void _setCoeff(int row, int col, Value value);
+ virtual Value _getCoeff(int row, int col) const;
+
+ virtual void _setColLowerBound(int i, Value value);
+ virtual Value _getColLowerBound(int i) const;
+ virtual void _setColUpperBound(int i, Value value);
+ virtual Value _getColUpperBound(int i) const;
+
+ virtual void _setRowLowerBound(int i, Value value);
+ virtual Value _getRowLowerBound(int i) const;
+ virtual void _setRowUpperBound(int i, Value value);
+ virtual Value _getRowUpperBound(int i) const;
+
+ virtual void _setObjCoeffs(ExprIterator, ExprIterator);
+ virtual void _getObjCoeffs(InsertIterator) const;
+
+ virtual void _setObjCoeff(int i, Value obj_coef);
+ virtual Value _getObjCoeff(int i) const;
+
+ virtual void _setSense(Sense sense);
+ virtual Sense _getSense() const;
+
+ virtual SolveExitStatus _solve();
+
+ virtual Value _getPrimal(int i) const;
+ virtual Value _getDual(int i) const;
+
+ virtual Value _getPrimalValue() const;
+
+ virtual Value _getPrimalRay(int i) const;
+ virtual Value _getDualRay(int i) const;
+
+ virtual VarStatus _getColStatus(int i) const;
+ virtual VarStatus _getRowStatus(int i) const;
+
+ virtual ProblemType _getPrimalType() const;
+ virtual ProblemType _getDualType() const;
+
+ virtual void _clear();
+
+ virtual void _messageLevel(MessageLevel);
+
+ public:
+
+ ///Solves LP with primal simplex method.
+ SolveExitStatus solvePrimal();
+
+ ///Solves LP with dual simplex method.
+ SolveExitStatus solveDual();
+
+ ///Solves LP with barrier method.
+ SolveExitStatus solveBarrier();
+
+ ///Returns the constraint identifier understood by CLP.
+ int clpRow(Row r) const { return rows(id(r)); }
+
+ ///Returns the variable identifier understood by CLP.
+ int clpCol(Col c) const { return cols(id(c)); }
+
+ };
+
+} //END OF NAMESPACE LEMON
+
+#endif //LEMON_CLP_H
+
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/color.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/color.cc
new file mode 100644
index 00000000000..a49167b5cc7
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/color.cc
@@ -0,0 +1,44 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+///\file
+///\brief Color constants
+
+#include<lemon/color.h>
+
+namespace lemon {
+
+ const Color WHITE(1,1,1);
+
+ const Color BLACK(0,0,0);
+ const Color RED(1,0,0);
+ const Color GREEN(0,1,0);
+ const Color BLUE(0,0,1);
+ const Color YELLOW(1,1,0);
+ const Color MAGENTA(1,0,1);
+ const Color CYAN(0,1,1);
+
+ const Color GREY(0,0,0);
+ const Color DARK_RED(.5,0,0);
+ const Color DARK_GREEN(0,.5,0);
+ const Color DARK_BLUE(0,0,.5);
+ const Color DARK_YELLOW(.5,.5,0);
+ const Color DARK_MAGENTA(.5,0,.5);
+ const Color DARK_CYAN(0,.5,.5);
+
+} //namespace lemon
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/color.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/color.h
new file mode 100644
index 00000000000..02357910ff7
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/color.h
@@ -0,0 +1,204 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_COLOR_H
+#define LEMON_COLOR_H
+
+#include<vector>
+#include<lemon/math.h>
+#include<lemon/maps.h>
+
+
+///\ingroup misc
+///\file
+///\brief Tools to manage RGB colors.
+
+namespace lemon {
+
+
+ /// \addtogroup misc
+ /// @{
+
+ ///Data structure representing RGB colors.
+
+ ///Data structure representing RGB colors.
+ class Color
+ {
+ double _r,_g,_b;
+ public:
+ ///Default constructor
+ Color() {}
+ ///Constructor
+ Color(double r,double g,double b) :_r(r),_g(g),_b(b) {};
+ ///Set the red component
+ double & red() {return _r;}
+ ///Return the red component
+ const double & red() const {return _r;}
+ ///Set the green component
+ double & green() {return _g;}
+ ///Return the green component
+ const double & green() const {return _g;}
+ ///Set the blue component
+ double & blue() {return _b;}
+ ///Return the blue component
+ const double & blue() const {return _b;}
+ ///Set the color components
+ void set(double r,double g,double b) { _r=r;_g=g;_b=b; };
+ };
+
+ /// White color constant
+ extern const Color WHITE;
+ /// Black color constant
+ extern const Color BLACK;
+ /// Red color constant
+ extern const Color RED;
+ /// Green color constant
+ extern const Color GREEN;
+ /// Blue color constant
+ extern const Color BLUE;
+ /// Yellow color constant
+ extern const Color YELLOW;
+ /// Magenta color constant
+ extern const Color MAGENTA;
+ /// Cyan color constant
+ extern const Color CYAN;
+ /// Grey color constant
+ extern const Color GREY;
+ /// Dark red color constant
+ extern const Color DARK_RED;
+ /// Dark green color constant
+ extern const Color DARK_GREEN;
+ /// Drak blue color constant
+ extern const Color DARK_BLUE;
+ /// Dark yellow color constant
+ extern const Color DARK_YELLOW;
+ /// Dark magenta color constant
+ extern const Color DARK_MAGENTA;
+ /// Dark cyan color constant
+ extern const Color DARK_CYAN;
+
+ ///Map <tt>int</tt>s to different <tt>Color</tt>s
+
+ ///This map assigns one of the predefined \ref Color "Color"s to
+ ///each <tt>int</tt>. It is possible to change the colors as well as
+ ///their number. The integer range is cyclically mapped to the
+ ///provided set of colors.
+ ///
+ ///This is a true \ref concepts::ReferenceMap "reference map", so
+ ///you can also change the actual colors.
+
+ class Palette : public MapBase<int,Color>
+ {
+ std::vector<Color> colors;
+ public:
+ ///Constructor
+
+ ///Constructor.
+ ///\param have_white Indicates whether white is among the
+ ///provided initial colors (\c true) or not (\c false). If it is true,
+ ///white will be assigned to \c 0.
+ ///\param num The number of the allocated colors. If it is \c -1,
+ ///the default color configuration is set up (26 color plus optionaly the
+ ///white). If \c num is less then 26/27 then the default color
+ ///list is cut. Otherwise the color list is filled repeatedly with
+ ///the default color list. (The colors can be changed later on.)
+ Palette(bool have_white=false,int num=-1)
+ {
+ if (num==0) return;
+ do {
+ if(have_white) colors.push_back(Color(1,1,1));
+
+ colors.push_back(Color(0,0,0));
+ colors.push_back(Color(1,0,0));
+ colors.push_back(Color(0,1,0));
+ colors.push_back(Color(0,0,1));
+ colors.push_back(Color(1,1,0));
+ colors.push_back(Color(1,0,1));
+ colors.push_back(Color(0,1,1));
+
+ colors.push_back(Color(.5,0,0));
+ colors.push_back(Color(0,.5,0));
+ colors.push_back(Color(0,0,.5));
+ colors.push_back(Color(.5,.5,0));
+ colors.push_back(Color(.5,0,.5));
+ colors.push_back(Color(0,.5,.5));
+
+ colors.push_back(Color(.5,.5,.5));
+ colors.push_back(Color(1,.5,.5));
+ colors.push_back(Color(.5,1,.5));
+ colors.push_back(Color(.5,.5,1));
+ colors.push_back(Color(1,1,.5));
+ colors.push_back(Color(1,.5,1));
+ colors.push_back(Color(.5,1,1));
+
+ colors.push_back(Color(1,.5,0));
+ colors.push_back(Color(.5,1,0));
+ colors.push_back(Color(1,0,.5));
+ colors.push_back(Color(0,1,.5));
+ colors.push_back(Color(0,.5,1));
+ colors.push_back(Color(.5,0,1));
+ } while(int(colors.size())<num);
+ if(num>=0) colors.resize(num);
+ }
+ ///\e
+ Color &operator[](int i)
+ {
+ return colors[i%colors.size()];
+ }
+ ///\e
+ const Color &operator[](int i) const
+ {
+ return colors[i%colors.size()];
+ }
+ ///\e
+ void set(int i,const Color &c)
+ {
+ colors[i%colors.size()]=c;
+ }
+ ///Adds a new color to the end of the color list.
+ void add(const Color &c)
+ {
+ colors.push_back(c);
+ }
+
+ ///Sets the number of the existing colors.
+ void resize(int s) { colors.resize(s);}
+ ///Returns the number of the existing colors.
+ int size() const { return int(colors.size());}
+ };
+
+ ///Returns a visibly distinct \ref Color
+
+ ///Returns a \ref Color which is as different from the given parameter
+ ///as it is possible.
+ inline Color distantColor(const Color &c)
+ {
+ return Color(c.red()<.5?1:0,c.green()<.5?1:0,c.blue()<.5?1:0);
+ }
+ ///Returns black for light colors and white for the dark ones.
+
+ ///Returns black for light colors and white for the dark ones.
+ inline Color distantBW(const Color &c){
+ return (.2125*c.red()+.7154*c.green()+.0721*c.blue())<.5 ? WHITE : BLACK;
+ }
+
+ /// @}
+
+} //END OF NAMESPACE LEMON
+
+#endif // LEMON_COLOR_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/concept_check.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concept_check.h
new file mode 100644
index 00000000000..38355b0f228
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concept_check.h
@@ -0,0 +1,77 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+// The contents of this file was inspired by the concept checking
+// utility of the BOOST library (http://www.boost.org).
+
+///\file
+///\brief Basic utilities for concept checking.
+///
+
+#ifndef LEMON_CONCEPT_CHECK_H
+#define LEMON_CONCEPT_CHECK_H
+
+namespace lemon {
+
+ /*
+ "inline" is used for ignore_unused_variable_warning()
+ and function_requires() to make sure there is no
+ overtarget with g++.
+ */
+
+ template <class T> inline void ignore_unused_variable_warning(const T&) { }
+ template <class T1, class T2>
+ inline void ignore_unused_variable_warning(const T1&, const T2&) { }
+ template <class T1, class T2, class T3>
+ inline void ignore_unused_variable_warning(const T1&, const T2&,
+ const T3&) { }
+ template <class T1, class T2, class T3, class T4>
+ inline void ignore_unused_variable_warning(const T1&, const T2&,
+ const T3&, const T4&) { }
+ template <class T1, class T2, class T3, class T4, class T5>
+ inline void ignore_unused_variable_warning(const T1&, const T2&,
+ const T3&, const T4&,
+ const T5&) { }
+ template <class T1, class T2, class T3, class T4, class T5, class T6>
+ inline void ignore_unused_variable_warning(const T1&, const T2&,
+ const T3&, const T4&,
+ const T5&, const T6&) { }
+
+ ///\e
+ template <class Concept>
+ inline void function_requires()
+ {
+#if !defined(NDEBUG)
+ void (Concept::*x)() = & Concept::constraints;
+ ::lemon::ignore_unused_variable_warning(x);
+#endif
+ }
+
+ ///\e
+ template <typename Concept, typename Type>
+ inline void checkConcept() {
+#if !defined(NDEBUG)
+ typedef typename Concept::template Constraints<Type> ConceptCheck;
+ void (ConceptCheck::*x)() = & ConceptCheck::constraints;
+ ::lemon::ignore_unused_variable_warning(x);
+#endif
+ }
+
+} // namespace lemon
+
+#endif // LEMON_CONCEPT_CHECK_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/bpgraph.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/bpgraph.h
new file mode 100644
index 00000000000..2ebdeaf8b2f
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/bpgraph.h
@@ -0,0 +1,1029 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+///\ingroup graph_concepts
+///\file
+///\brief The concept of undirected graphs.
+
+#ifndef LEMON_CONCEPTS_BPGRAPH_H
+#define LEMON_CONCEPTS_BPGRAPH_H
+
+#include <lemon/concepts/graph_components.h>
+#include <lemon/concepts/maps.h>
+#include <lemon/concept_check.h>
+#include <lemon/core.h>
+
+namespace lemon {
+ namespace concepts {
+
+ /// \ingroup graph_concepts
+ ///
+ /// \brief Class describing the concept of undirected bipartite graphs.
+ ///
+ /// This class describes the common interface of all undirected
+ /// bipartite graphs.
+ ///
+ /// Like all concept classes, it only provides an interface
+ /// without any sensible implementation. So any general algorithm for
+ /// undirected bipartite graphs should compile with this class,
+ /// but it will not run properly, of course.
+ /// An actual graph implementation like \ref ListBpGraph or
+ /// \ref SmartBpGraph may have additional functionality.
+ ///
+ /// The bipartite graphs also fulfill the concept of \ref Graph
+ /// "undirected graphs". Bipartite graphs provide a bipartition of
+ /// the node set, namely a red and blue set of the nodes. The
+ /// nodes can be iterated with the RedNodeIt and BlueNodeIt in the
+ /// two node sets. With RedNodeMap and BlueNodeMap values can be
+ /// assigned to the nodes in the two sets.
+ ///
+ /// The edges of the graph cannot connect two nodes of the same
+ /// set. The edges inherent orientation is from the red nodes to
+ /// the blue nodes.
+ ///
+ /// \sa Graph
+ class BpGraph {
+ private:
+ /// BpGraphs are \e not copy constructible. Use bpGraphCopy instead.
+ BpGraph(const BpGraph&) {}
+ /// \brief Assignment of a graph to another one is \e not allowed.
+ /// Use bpGraphCopy instead.
+ void operator=(const BpGraph&) {}
+
+ public:
+ /// Default constructor.
+ BpGraph() {}
+
+ /// \brief Undirected graphs should be tagged with \c UndirectedTag.
+ ///
+ /// Undirected graphs should be tagged with \c UndirectedTag.
+ ///
+ /// This tag helps the \c enable_if technics to make compile time
+ /// specializations for undirected graphs.
+ typedef True UndirectedTag;
+
+ /// The node type of the graph
+
+ /// This class identifies a node of the graph. It also serves
+ /// as a base class of the node iterators,
+ /// thus they convert to this type.
+ class Node {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the object to an undefined value.
+ Node() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ Node(const Node&) { }
+
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the object to be invalid.
+ /// \sa Invalid for more details.
+ Node(Invalid) { }
+ /// Equality operator
+
+ /// Equality operator.
+ ///
+ /// Two iterators are equal if and only if they point to the
+ /// same object or both are \c INVALID.
+ bool operator==(Node) const { return true; }
+
+ /// Inequality operator
+
+ /// Inequality operator.
+ bool operator!=(Node) const { return true; }
+
+ /// Artificial ordering operator.
+
+ /// Artificial ordering operator.
+ ///
+ /// \note This operator only has to define some strict ordering of
+ /// the items; this order has nothing to do with the iteration
+ /// ordering of the items.
+ bool operator<(Node) const { return false; }
+
+ };
+
+ /// Class to represent red nodes.
+
+ /// This class represents the red nodes of the graph. It does
+ /// not supposed to be used directly, because the nodes can be
+ /// represented as Node instances. This class can be used as
+ /// template parameter for special map classes.
+ class RedNode : public Node {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the object to an undefined value.
+ RedNode() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ RedNode(const RedNode&) : Node() { }
+
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the object to be invalid.
+ /// \sa Invalid for more details.
+ RedNode(Invalid) { }
+
+ };
+
+ /// Class to represent blue nodes.
+
+ /// This class represents the blue nodes of the graph. It does
+ /// not supposed to be used directly, because the nodes can be
+ /// represented as Node instances. This class can be used as
+ /// template parameter for special map classes.
+ class BlueNode : public Node {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the object to an undefined value.
+ BlueNode() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ BlueNode(const BlueNode&) : Node() { }
+
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the object to be invalid.
+ /// \sa Invalid for more details.
+ BlueNode(Invalid) { }
+
+ };
+
+ /// Iterator class for the red nodes.
+
+ /// This iterator goes through each red node of the graph.
+ /// Its usage is quite simple, for example, you can count the number
+ /// of red nodes in a graph \c g of type \c %BpGraph like this:
+ ///\code
+ /// int count=0;
+ /// for (BpGraph::RedNodeIt n(g); n!=INVALID; ++n) ++count;
+ ///\endcode
+ class RedNodeIt : public RedNode {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the iterator to an undefined value.
+ RedNodeIt() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ RedNodeIt(const RedNodeIt& n) : RedNode(n) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ RedNodeIt(Invalid) { }
+ /// Sets the iterator to the first red node.
+
+ /// Sets the iterator to the first red node of the given
+ /// digraph.
+ explicit RedNodeIt(const BpGraph&) { }
+ /// Sets the iterator to the given red node.
+
+ /// Sets the iterator to the given red node of the given
+ /// digraph.
+ RedNodeIt(const BpGraph&, const RedNode&) { }
+ /// Next node.
+
+ /// Assign the iterator to the next red node.
+ ///
+ RedNodeIt& operator++() { return *this; }
+ };
+
+ /// Iterator class for the blue nodes.
+
+ /// This iterator goes through each blue node of the graph.
+ /// Its usage is quite simple, for example, you can count the number
+ /// of blue nodes in a graph \c g of type \c %BpGraph like this:
+ ///\code
+ /// int count=0;
+ /// for (BpGraph::BlueNodeIt n(g); n!=INVALID; ++n) ++count;
+ ///\endcode
+ class BlueNodeIt : public BlueNode {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the iterator to an undefined value.
+ BlueNodeIt() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ BlueNodeIt(const BlueNodeIt& n) : BlueNode(n) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ BlueNodeIt(Invalid) { }
+ /// Sets the iterator to the first blue node.
+
+ /// Sets the iterator to the first blue node of the given
+ /// digraph.
+ explicit BlueNodeIt(const BpGraph&) { }
+ /// Sets the iterator to the given blue node.
+
+ /// Sets the iterator to the given blue node of the given
+ /// digraph.
+ BlueNodeIt(const BpGraph&, const BlueNode&) { }
+ /// Next node.
+
+ /// Assign the iterator to the next blue node.
+ ///
+ BlueNodeIt& operator++() { return *this; }
+ };
+
+ /// Iterator class for the nodes.
+
+ /// This iterator goes through each node of the graph.
+ /// Its usage is quite simple, for example, you can count the number
+ /// of nodes in a graph \c g of type \c %BpGraph like this:
+ ///\code
+ /// int count=0;
+ /// for (BpGraph::NodeIt n(g); n!=INVALID; ++n) ++count;
+ ///\endcode
+ class NodeIt : public Node {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the iterator to an undefined value.
+ NodeIt() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ NodeIt(const NodeIt& n) : Node(n) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ NodeIt(Invalid) { }
+ /// Sets the iterator to the first node.
+
+ /// Sets the iterator to the first node of the given digraph.
+ ///
+ explicit NodeIt(const BpGraph&) { }
+ /// Sets the iterator to the given node.
+
+ /// Sets the iterator to the given node of the given digraph.
+ ///
+ NodeIt(const BpGraph&, const Node&) { }
+ /// Next node.
+
+ /// Assign the iterator to the next node.
+ ///
+ NodeIt& operator++() { return *this; }
+ };
+
+
+ /// The edge type of the graph
+
+ /// This class identifies an edge of the graph. It also serves
+ /// as a base class of the edge iterators,
+ /// thus they will convert to this type.
+ class Edge {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the object to an undefined value.
+ Edge() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ Edge(const Edge&) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the object to be invalid.
+ /// \sa Invalid for more details.
+ Edge(Invalid) { }
+ /// Equality operator
+
+ /// Equality operator.
+ ///
+ /// Two iterators are equal if and only if they point to the
+ /// same object or both are \c INVALID.
+ bool operator==(Edge) const { return true; }
+ /// Inequality operator
+
+ /// Inequality operator.
+ bool operator!=(Edge) const { return true; }
+
+ /// Artificial ordering operator.
+
+ /// Artificial ordering operator.
+ ///
+ /// \note This operator only has to define some strict ordering of
+ /// the edges; this order has nothing to do with the iteration
+ /// ordering of the edges.
+ bool operator<(Edge) const { return false; }
+ };
+
+ /// Iterator class for the edges.
+
+ /// This iterator goes through each edge of the graph.
+ /// Its usage is quite simple, for example, you can count the number
+ /// of edges in a graph \c g of type \c %BpGraph as follows:
+ ///\code
+ /// int count=0;
+ /// for(BpGraph::EdgeIt e(g); e!=INVALID; ++e) ++count;
+ ///\endcode
+ class EdgeIt : public Edge {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the iterator to an undefined value.
+ EdgeIt() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ EdgeIt(const EdgeIt& e) : Edge(e) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ EdgeIt(Invalid) { }
+ /// Sets the iterator to the first edge.
+
+ /// Sets the iterator to the first edge of the given graph.
+ ///
+ explicit EdgeIt(const BpGraph&) { }
+ /// Sets the iterator to the given edge.
+
+ /// Sets the iterator to the given edge of the given graph.
+ ///
+ EdgeIt(const BpGraph&, const Edge&) { }
+ /// Next edge
+
+ /// Assign the iterator to the next edge.
+ ///
+ EdgeIt& operator++() { return *this; }
+ };
+
+ /// Iterator class for the incident edges of a node.
+
+ /// This iterator goes trough the incident undirected edges
+ /// of a certain node of a graph.
+ /// Its usage is quite simple, for example, you can compute the
+ /// degree (i.e. the number of incident edges) of a node \c n
+ /// in a graph \c g of type \c %BpGraph as follows.
+ ///
+ ///\code
+ /// int count=0;
+ /// for(BpGraph::IncEdgeIt e(g, n); e!=INVALID; ++e) ++count;
+ ///\endcode
+ ///
+ /// \warning Loop edges will be iterated twice.
+ class IncEdgeIt : public Edge {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the iterator to an undefined value.
+ IncEdgeIt() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ IncEdgeIt(const IncEdgeIt& e) : Edge(e) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ IncEdgeIt(Invalid) { }
+ /// Sets the iterator to the first incident edge.
+
+ /// Sets the iterator to the first incident edge of the given node.
+ ///
+ IncEdgeIt(const BpGraph&, const Node&) { }
+ /// Sets the iterator to the given edge.
+
+ /// Sets the iterator to the given edge of the given graph.
+ ///
+ IncEdgeIt(const BpGraph&, const Edge&) { }
+ /// Next incident edge
+
+ /// Assign the iterator to the next incident edge
+ /// of the corresponding node.
+ IncEdgeIt& operator++() { return *this; }
+ };
+
+ /// The arc type of the graph
+
+ /// This class identifies a directed arc of the graph. It also serves
+ /// as a base class of the arc iterators,
+ /// thus they will convert to this type.
+ class Arc {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the object to an undefined value.
+ Arc() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ Arc(const Arc&) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the object to be invalid.
+ /// \sa Invalid for more details.
+ Arc(Invalid) { }
+ /// Equality operator
+
+ /// Equality operator.
+ ///
+ /// Two iterators are equal if and only if they point to the
+ /// same object or both are \c INVALID.
+ bool operator==(Arc) const { return true; }
+ /// Inequality operator
+
+ /// Inequality operator.
+ bool operator!=(Arc) const { return true; }
+
+ /// Artificial ordering operator.
+
+ /// Artificial ordering operator.
+ ///
+ /// \note This operator only has to define some strict ordering of
+ /// the arcs; this order has nothing to do with the iteration
+ /// ordering of the arcs.
+ bool operator<(Arc) const { return false; }
+
+ /// Converison to \c Edge
+
+ /// Converison to \c Edge.
+ ///
+ operator Edge() const { return Edge(); }
+ };
+
+ /// Iterator class for the arcs.
+
+ /// This iterator goes through each directed arc of the graph.
+ /// Its usage is quite simple, for example, you can count the number
+ /// of arcs in a graph \c g of type \c %BpGraph as follows:
+ ///\code
+ /// int count=0;
+ /// for(BpGraph::ArcIt a(g); a!=INVALID; ++a) ++count;
+ ///\endcode
+ class ArcIt : public Arc {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the iterator to an undefined value.
+ ArcIt() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ ArcIt(const ArcIt& e) : Arc(e) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ ArcIt(Invalid) { }
+ /// Sets the iterator to the first arc.
+
+ /// Sets the iterator to the first arc of the given graph.
+ ///
+ explicit ArcIt(const BpGraph &g)
+ {
+ ::lemon::ignore_unused_variable_warning(g);
+ }
+ /// Sets the iterator to the given arc.
+
+ /// Sets the iterator to the given arc of the given graph.
+ ///
+ ArcIt(const BpGraph&, const Arc&) { }
+ /// Next arc
+
+ /// Assign the iterator to the next arc.
+ ///
+ ArcIt& operator++() { return *this; }
+ };
+
+ /// Iterator class for the outgoing arcs of a node.
+
+ /// This iterator goes trough the \e outgoing directed arcs of a
+ /// certain node of a graph.
+ /// Its usage is quite simple, for example, you can count the number
+ /// of outgoing arcs of a node \c n
+ /// in a graph \c g of type \c %BpGraph as follows.
+ ///\code
+ /// int count=0;
+ /// for (Digraph::OutArcIt a(g, n); a!=INVALID; ++a) ++count;
+ ///\endcode
+ class OutArcIt : public Arc {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the iterator to an undefined value.
+ OutArcIt() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ OutArcIt(const OutArcIt& e) : Arc(e) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ OutArcIt(Invalid) { }
+ /// Sets the iterator to the first outgoing arc.
+
+ /// Sets the iterator to the first outgoing arc of the given node.
+ ///
+ OutArcIt(const BpGraph& n, const Node& g) {
+ ::lemon::ignore_unused_variable_warning(n);
+ ::lemon::ignore_unused_variable_warning(g);
+ }
+ /// Sets the iterator to the given arc.
+
+ /// Sets the iterator to the given arc of the given graph.
+ ///
+ OutArcIt(const BpGraph&, const Arc&) { }
+ /// Next outgoing arc
+
+ /// Assign the iterator to the next
+ /// outgoing arc of the corresponding node.
+ OutArcIt& operator++() { return *this; }
+ };
+
+ /// Iterator class for the incoming arcs of a node.
+
+ /// This iterator goes trough the \e incoming directed arcs of a
+ /// certain node of a graph.
+ /// Its usage is quite simple, for example, you can count the number
+ /// of incoming arcs of a node \c n
+ /// in a graph \c g of type \c %BpGraph as follows.
+ ///\code
+ /// int count=0;
+ /// for (Digraph::InArcIt a(g, n); a!=INVALID; ++a) ++count;
+ ///\endcode
+ class InArcIt : public Arc {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the iterator to an undefined value.
+ InArcIt() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ InArcIt(const InArcIt& e) : Arc(e) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ InArcIt(Invalid) { }
+ /// Sets the iterator to the first incoming arc.
+
+ /// Sets the iterator to the first incoming arc of the given node.
+ ///
+ InArcIt(const BpGraph& g, const Node& n) {
+ ::lemon::ignore_unused_variable_warning(n);
+ ::lemon::ignore_unused_variable_warning(g);
+ }
+ /// Sets the iterator to the given arc.
+
+ /// Sets the iterator to the given arc of the given graph.
+ ///
+ InArcIt(const BpGraph&, const Arc&) { }
+ /// Next incoming arc
+
+ /// Assign the iterator to the next
+ /// incoming arc of the corresponding node.
+ InArcIt& operator++() { return *this; }
+ };
+
+ /// \brief Standard graph map type for the nodes.
+ ///
+ /// Standard graph map type for the nodes.
+ /// It conforms to the ReferenceMap concept.
+ template<class T>
+ class NodeMap : public ReferenceMap<Node, T, T&, const T&>
+ {
+ public:
+
+ /// Constructor
+ explicit NodeMap(const BpGraph&) { }
+ /// Constructor with given initial value
+ NodeMap(const BpGraph&, T) { }
+
+ private:
+ ///Copy constructor
+ NodeMap(const NodeMap& nm) :
+ ReferenceMap<Node, T, T&, const T&>(nm) { }
+ ///Assignment operator
+ template <typename CMap>
+ NodeMap& operator=(const CMap&) {
+ checkConcept<ReadMap<Node, T>, CMap>();
+ return *this;
+ }
+ };
+
+ /// \brief Standard graph map type for the red nodes.
+ ///
+ /// Standard graph map type for the red nodes.
+ /// It conforms to the ReferenceMap concept.
+ template<class T>
+ class RedNodeMap : public ReferenceMap<Node, T, T&, const T&>
+ {
+ public:
+
+ /// Constructor
+ explicit RedNodeMap(const BpGraph&) { }
+ /// Constructor with given initial value
+ RedNodeMap(const BpGraph&, T) { }
+
+ private:
+ ///Copy constructor
+ RedNodeMap(const RedNodeMap& nm) :
+ ReferenceMap<Node, T, T&, const T&>(nm) { }
+ ///Assignment operator
+ template <typename CMap>
+ RedNodeMap& operator=(const CMap&) {
+ checkConcept<ReadMap<Node, T>, CMap>();
+ return *this;
+ }
+ };
+
+ /// \brief Standard graph map type for the blue nodes.
+ ///
+ /// Standard graph map type for the blue nodes.
+ /// It conforms to the ReferenceMap concept.
+ template<class T>
+ class BlueNodeMap : public ReferenceMap<Node, T, T&, const T&>
+ {
+ public:
+
+ /// Constructor
+ explicit BlueNodeMap(const BpGraph&) { }
+ /// Constructor with given initial value
+ BlueNodeMap(const BpGraph&, T) { }
+
+ private:
+ ///Copy constructor
+ BlueNodeMap(const BlueNodeMap& nm) :
+ ReferenceMap<Node, T, T&, const T&>(nm) { }
+ ///Assignment operator
+ template <typename CMap>
+ BlueNodeMap& operator=(const CMap&) {
+ checkConcept<ReadMap<Node, T>, CMap>();
+ return *this;
+ }
+ };
+
+ /// \brief Standard graph map type for the arcs.
+ ///
+ /// Standard graph map type for the arcs.
+ /// It conforms to the ReferenceMap concept.
+ template<class T>
+ class ArcMap : public ReferenceMap<Arc, T, T&, const T&>
+ {
+ public:
+
+ /// Constructor
+ explicit ArcMap(const BpGraph&) { }
+ /// Constructor with given initial value
+ ArcMap(const BpGraph&, T) { }
+
+ private:
+ ///Copy constructor
+ ArcMap(const ArcMap& em) :
+ ReferenceMap<Arc, T, T&, const T&>(em) { }
+ ///Assignment operator
+ template <typename CMap>
+ ArcMap& operator=(const CMap&) {
+ checkConcept<ReadMap<Arc, T>, CMap>();
+ return *this;
+ }
+ };
+
+ /// \brief Standard graph map type for the edges.
+ ///
+ /// Standard graph map type for the edges.
+ /// It conforms to the ReferenceMap concept.
+ template<class T>
+ class EdgeMap : public ReferenceMap<Edge, T, T&, const T&>
+ {
+ public:
+
+ /// Constructor
+ explicit EdgeMap(const BpGraph&) { }
+ /// Constructor with given initial value
+ EdgeMap(const BpGraph&, T) { }
+
+ private:
+ ///Copy constructor
+ EdgeMap(const EdgeMap& em) :
+ ReferenceMap<Edge, T, T&, const T&>(em) {}
+ ///Assignment operator
+ template <typename CMap>
+ EdgeMap& operator=(const CMap&) {
+ checkConcept<ReadMap<Edge, T>, CMap>();
+ return *this;
+ }
+ };
+
+ /// \brief Gives back %true for red nodes.
+ ///
+ /// Gives back %true for red nodes.
+ bool red(const Node&) const { return true; }
+
+ /// \brief Gives back %true for blue nodes.
+ ///
+ /// Gives back %true for blue nodes.
+ bool blue(const Node&) const { return true; }
+
+ /// \brief Converts the node to red node object.
+ ///
+ /// This function converts unsafely the node to red node
+ /// object. It should be called only if the node is from the red
+ /// partition or INVALID.
+ RedNode asRedNodeUnsafe(const Node&) const { return RedNode(); }
+
+ /// \brief Converts the node to blue node object.
+ ///
+ /// This function converts unsafely the node to blue node
+ /// object. It should be called only if the node is from the red
+ /// partition or INVALID.
+ BlueNode asBlueNodeUnsafe(const Node&) const { return BlueNode(); }
+
+ /// \brief Converts the node to red node object.
+ ///
+ /// This function converts safely the node to red node
+ /// object. If the node is not from the red partition, then it
+ /// returns INVALID.
+ RedNode asRedNode(const Node&) const { return RedNode(); }
+
+ /// \brief Converts the node to blue node object.
+ ///
+ /// This function converts unsafely the node to blue node
+ /// object. If the node is not from the blue partition, then it
+ /// returns INVALID.
+ BlueNode asBlueNode(const Node&) const { return BlueNode(); }
+
+ /// \brief Gives back the red end node of the edge.
+ ///
+ /// Gives back the red end node of the edge.
+ RedNode redNode(const Edge&) const { return RedNode(); }
+
+ /// \brief Gives back the blue end node of the edge.
+ ///
+ /// Gives back the blue end node of the edge.
+ BlueNode blueNode(const Edge&) const { return BlueNode(); }
+
+ /// \brief The first node of the edge.
+ ///
+ /// It is a synonim for the \c redNode().
+ Node u(Edge) const { return INVALID; }
+
+ /// \brief The second node of the edge.
+ ///
+ /// It is a synonim for the \c blueNode().
+ Node v(Edge) const { return INVALID; }
+
+ /// \brief The source node of the arc.
+ ///
+ /// Returns the source node of the given arc.
+ Node source(Arc) const { return INVALID; }
+
+ /// \brief The target node of the arc.
+ ///
+ /// Returns the target node of the given arc.
+ Node target(Arc) const { return INVALID; }
+
+ /// \brief The ID of the node.
+ ///
+ /// Returns the ID of the given node.
+ int id(Node) const { return -1; }
+
+ /// \brief The red ID of the node.
+ ///
+ /// Returns the red ID of the given node.
+ int id(RedNode) const { return -1; }
+
+ /// \brief The blue ID of the node.
+ ///
+ /// Returns the blue ID of the given node.
+ int id(BlueNode) const { return -1; }
+
+ /// \brief The ID of the edge.
+ ///
+ /// Returns the ID of the given edge.
+ int id(Edge) const { return -1; }
+
+ /// \brief The ID of the arc.
+ ///
+ /// Returns the ID of the given arc.
+ int id(Arc) const { return -1; }
+
+ /// \brief The node with the given ID.
+ ///
+ /// Returns the node with the given ID.
+ /// \pre The argument should be a valid node ID in the graph.
+ Node nodeFromId(int) const { return INVALID; }
+
+ /// \brief The edge with the given ID.
+ ///
+ /// Returns the edge with the given ID.
+ /// \pre The argument should be a valid edge ID in the graph.
+ Edge edgeFromId(int) const { return INVALID; }
+
+ /// \brief The arc with the given ID.
+ ///
+ /// Returns the arc with the given ID.
+ /// \pre The argument should be a valid arc ID in the graph.
+ Arc arcFromId(int) const { return INVALID; }
+
+ /// \brief An upper bound on the node IDs.
+ ///
+ /// Returns an upper bound on the node IDs.
+ int maxNodeId() const { return -1; }
+
+ /// \brief An upper bound on the red IDs.
+ ///
+ /// Returns an upper bound on the red IDs.
+ int maxRedId() const { return -1; }
+
+ /// \brief An upper bound on the blue IDs.
+ ///
+ /// Returns an upper bound on the blue IDs.
+ int maxBlueId() const { return -1; }
+
+ /// \brief An upper bound on the edge IDs.
+ ///
+ /// Returns an upper bound on the edge IDs.
+ int maxEdgeId() const { return -1; }
+
+ /// \brief An upper bound on the arc IDs.
+ ///
+ /// Returns an upper bound on the arc IDs.
+ int maxArcId() const { return -1; }
+
+ /// \brief The direction of the arc.
+ ///
+ /// Returns \c true if the given arc goes from a red node to a blue node.
+ bool direction(Arc) const { return true; }
+
+ /// \brief Direct the edge.
+ ///
+ /// Direct the given edge. The returned arc
+ /// represents the given edge and its direction comes
+ /// from the bool parameter. If it is \c true, then the source of the node
+ /// will be a red node.
+ Arc direct(Edge, bool) const {
+ return INVALID;
+ }
+
+ /// \brief Direct the edge.
+ ///
+ /// Direct the given edge. The returned arc represents the given
+ /// edge and its source node is the given node.
+ Arc direct(Edge, Node) const {
+ return INVALID;
+ }
+
+ /// \brief The oppositely directed arc.
+ ///
+ /// Returns the oppositely directed arc representing the same edge.
+ Arc oppositeArc(Arc) const { return INVALID; }
+
+ /// \brief The opposite node on the edge.
+ ///
+ /// Returns the opposite node on the given edge.
+ Node oppositeNode(Node, Edge) const { return INVALID; }
+
+ void first(Node&) const {}
+ void next(Node&) const {}
+
+ void firstRed(RedNode&) const {}
+ void nextRed(RedNode&) const {}
+
+ void firstBlue(BlueNode&) const {}
+ void nextBlue(BlueNode&) const {}
+
+ void first(Edge&) const {}
+ void next(Edge&) const {}
+
+ void first(Arc&) const {}
+ void next(Arc&) const {}
+
+ void firstOut(Arc&, Node) const {}
+ void nextOut(Arc&) const {}
+
+ void firstIn(Arc&, Node) const {}
+ void nextIn(Arc&) const {}
+
+ void firstInc(Edge &, bool &, const Node &) const {}
+ void nextInc(Edge &, bool &) const {}
+
+ // The second parameter is dummy.
+ Node fromId(int, Node) const { return INVALID; }
+ // The second parameter is dummy.
+ Edge fromId(int, Edge) const { return INVALID; }
+ // The second parameter is dummy.
+ Arc fromId(int, Arc) const { return INVALID; }
+
+ // Dummy parameter.
+ int maxId(Node) const { return -1; }
+ // Dummy parameter.
+ int maxId(RedNode) const { return -1; }
+ // Dummy parameter.
+ int maxId(BlueNode) const { return -1; }
+ // Dummy parameter.
+ int maxId(Edge) const { return -1; }
+ // Dummy parameter.
+ int maxId(Arc) const { return -1; }
+
+ /// \brief The base node of the iterator.
+ ///
+ /// Returns the base node of the given incident edge iterator.
+ Node baseNode(IncEdgeIt) const { return INVALID; }
+
+ /// \brief The running node of the iterator.
+ ///
+ /// Returns the running node of the given incident edge iterator.
+ Node runningNode(IncEdgeIt) const { return INVALID; }
+
+ /// \brief The base node of the iterator.
+ ///
+ /// Returns the base node of the given outgoing arc iterator
+ /// (i.e. the source node of the corresponding arc).
+ Node baseNode(OutArcIt) const { return INVALID; }
+
+ /// \brief The running node of the iterator.
+ ///
+ /// Returns the running node of the given outgoing arc iterator
+ /// (i.e. the target node of the corresponding arc).
+ Node runningNode(OutArcIt) const { return INVALID; }
+
+ /// \brief The base node of the iterator.
+ ///
+ /// Returns the base node of the given incoming arc iterator
+ /// (i.e. the target node of the corresponding arc).
+ Node baseNode(InArcIt) const { return INVALID; }
+
+ /// \brief The running node of the iterator.
+ ///
+ /// Returns the running node of the given incoming arc iterator
+ /// (i.e. the source node of the corresponding arc).
+ Node runningNode(InArcIt) const { return INVALID; }
+
+ template <typename _BpGraph>
+ struct Constraints {
+ void constraints() {
+ checkConcept<BaseBpGraphComponent, _BpGraph>();
+ checkConcept<IterableBpGraphComponent<>, _BpGraph>();
+ checkConcept<IDableBpGraphComponent<>, _BpGraph>();
+ checkConcept<MappableBpGraphComponent<>, _BpGraph>();
+ }
+ };
+
+ };
+
+ }
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/digraph.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/digraph.h
new file mode 100644
index 00000000000..dc3c36bbbc0
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/digraph.h
@@ -0,0 +1,491 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_CONCEPTS_DIGRAPH_H
+#define LEMON_CONCEPTS_DIGRAPH_H
+
+///\ingroup graph_concepts
+///\file
+///\brief The concept of directed graphs.
+
+#include <lemon/core.h>
+#include <lemon/concepts/maps.h>
+#include <lemon/concept_check.h>
+#include <lemon/concepts/graph_components.h>
+
+namespace lemon {
+ namespace concepts {
+
+ /// \ingroup graph_concepts
+ ///
+ /// \brief Class describing the concept of directed graphs.
+ ///
+ /// This class describes the common interface of all directed
+ /// graphs (digraphs).
+ ///
+ /// Like all concept classes, it only provides an interface
+ /// without any sensible implementation. So any general algorithm for
+ /// directed graphs should compile with this class, but it will not
+ /// run properly, of course.
+ /// An actual digraph implementation like \ref ListDigraph or
+ /// \ref SmartDigraph may have additional functionality.
+ ///
+ /// \sa Graph
+ class Digraph {
+ private:
+ /// Diraphs are \e not copy constructible. Use DigraphCopy instead.
+ Digraph(const Digraph &) {}
+ /// \brief Assignment of a digraph to another one is \e not allowed.
+ /// Use DigraphCopy instead.
+ void operator=(const Digraph &) {}
+
+ public:
+ /// Default constructor.
+ Digraph() { }
+
+ /// The node type of the digraph
+
+ /// This class identifies a node of the digraph. It also serves
+ /// as a base class of the node iterators,
+ /// thus they convert to this type.
+ class Node {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the object to an undefined value.
+ Node() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ Node(const Node&) { }
+
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the object to be invalid.
+ /// \sa Invalid for more details.
+ Node(Invalid) { }
+ /// Equality operator
+
+ /// Equality operator.
+ ///
+ /// Two iterators are equal if and only if they point to the
+ /// same object or both are \c INVALID.
+ bool operator==(Node) const { return true; }
+
+ /// Inequality operator
+
+ /// Inequality operator.
+ bool operator!=(Node) const { return true; }
+
+ /// Artificial ordering operator.
+
+ /// Artificial ordering operator.
+ ///
+ /// \note This operator only has to define some strict ordering of
+ /// the nodes; this order has nothing to do with the iteration
+ /// ordering of the nodes.
+ bool operator<(Node) const { return false; }
+ };
+
+ /// Iterator class for the nodes.
+
+ /// This iterator goes through each node of the digraph.
+ /// Its usage is quite simple, for example, you can count the number
+ /// of nodes in a digraph \c g of type \c %Digraph like this:
+ ///\code
+ /// int count=0;
+ /// for (Digraph::NodeIt n(g); n!=INVALID; ++n) ++count;
+ ///\endcode
+ class NodeIt : public Node {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the iterator to an undefined value.
+ NodeIt() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ NodeIt(const NodeIt& n) : Node(n) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ NodeIt(Invalid) { }
+ /// Sets the iterator to the first node.
+
+ /// Sets the iterator to the first node of the given digraph.
+ ///
+ explicit NodeIt(const Digraph&) { }
+ /// Sets the iterator to the given node.
+
+ /// Sets the iterator to the given node of the given digraph.
+ ///
+ NodeIt(const Digraph&, const Node&) { }
+ /// Next node.
+
+ /// Assign the iterator to the next node.
+ ///
+ NodeIt& operator++() { return *this; }
+ };
+
+
+ /// The arc type of the digraph
+
+ /// This class identifies an arc of the digraph. It also serves
+ /// as a base class of the arc iterators,
+ /// thus they will convert to this type.
+ class Arc {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the object to an undefined value.
+ Arc() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ Arc(const Arc&) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the object to be invalid.
+ /// \sa Invalid for more details.
+ Arc(Invalid) { }
+ /// Equality operator
+
+ /// Equality operator.
+ ///
+ /// Two iterators are equal if and only if they point to the
+ /// same object or both are \c INVALID.
+ bool operator==(Arc) const { return true; }
+ /// Inequality operator
+
+ /// Inequality operator.
+ bool operator!=(Arc) const { return true; }
+
+ /// Artificial ordering operator.
+
+ /// Artificial ordering operator.
+ ///
+ /// \note This operator only has to define some strict ordering of
+ /// the arcs; this order has nothing to do with the iteration
+ /// ordering of the arcs.
+ bool operator<(Arc) const { return false; }
+ };
+
+ /// Iterator class for the outgoing arcs of a node.
+
+ /// This iterator goes trough the \e outgoing arcs of a certain node
+ /// of a digraph.
+ /// Its usage is quite simple, for example, you can count the number
+ /// of outgoing arcs of a node \c n
+ /// in a digraph \c g of type \c %Digraph as follows.
+ ///\code
+ /// int count=0;
+ /// for (Digraph::OutArcIt a(g, n); a!=INVALID; ++a) ++count;
+ ///\endcode
+ class OutArcIt : public Arc {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the iterator to an undefined value.
+ OutArcIt() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ OutArcIt(const OutArcIt& e) : Arc(e) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ OutArcIt(Invalid) { }
+ /// Sets the iterator to the first outgoing arc.
+
+ /// Sets the iterator to the first outgoing arc of the given node.
+ ///
+ OutArcIt(const Digraph&, const Node&) { }
+ /// Sets the iterator to the given arc.
+
+ /// Sets the iterator to the given arc of the given digraph.
+ ///
+ OutArcIt(const Digraph&, const Arc&) { }
+ /// Next outgoing arc
+
+ /// Assign the iterator to the next
+ /// outgoing arc of the corresponding node.
+ OutArcIt& operator++() { return *this; }
+ };
+
+ /// Iterator class for the incoming arcs of a node.
+
+ /// This iterator goes trough the \e incoming arcs of a certain node
+ /// of a digraph.
+ /// Its usage is quite simple, for example, you can count the number
+ /// of incoming arcs of a node \c n
+ /// in a digraph \c g of type \c %Digraph as follows.
+ ///\code
+ /// int count=0;
+ /// for(Digraph::InArcIt a(g, n); a!=INVALID; ++a) ++count;
+ ///\endcode
+ class InArcIt : public Arc {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the iterator to an undefined value.
+ InArcIt() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ InArcIt(const InArcIt& e) : Arc(e) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ InArcIt(Invalid) { }
+ /// Sets the iterator to the first incoming arc.
+
+ /// Sets the iterator to the first incoming arc of the given node.
+ ///
+ InArcIt(const Digraph&, const Node&) { }
+ /// Sets the iterator to the given arc.
+
+ /// Sets the iterator to the given arc of the given digraph.
+ ///
+ InArcIt(const Digraph&, const Arc&) { }
+ /// Next incoming arc
+
+ /// Assign the iterator to the next
+ /// incoming arc of the corresponding node.
+ InArcIt& operator++() { return *this; }
+ };
+
+ /// Iterator class for the arcs.
+
+ /// This iterator goes through each arc of the digraph.
+ /// Its usage is quite simple, for example, you can count the number
+ /// of arcs in a digraph \c g of type \c %Digraph as follows:
+ ///\code
+ /// int count=0;
+ /// for(Digraph::ArcIt a(g); a!=INVALID; ++a) ++count;
+ ///\endcode
+ class ArcIt : public Arc {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the iterator to an undefined value.
+ ArcIt() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ ArcIt(const ArcIt& e) : Arc(e) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ ArcIt(Invalid) { }
+ /// Sets the iterator to the first arc.
+
+ /// Sets the iterator to the first arc of the given digraph.
+ ///
+ explicit ArcIt(const Digraph& g) {
+ ::lemon::ignore_unused_variable_warning(g);
+ }
+ /// Sets the iterator to the given arc.
+
+ /// Sets the iterator to the given arc of the given digraph.
+ ///
+ ArcIt(const Digraph&, const Arc&) { }
+ /// Next arc
+
+ /// Assign the iterator to the next arc.
+ ///
+ ArcIt& operator++() { return *this; }
+ };
+
+ /// \brief The source node of the arc.
+ ///
+ /// Returns the source node of the given arc.
+ Node source(Arc) const { return INVALID; }
+
+ /// \brief The target node of the arc.
+ ///
+ /// Returns the target node of the given arc.
+ Node target(Arc) const { return INVALID; }
+
+ /// \brief The ID of the node.
+ ///
+ /// Returns the ID of the given node.
+ int id(Node) const { return -1; }
+
+ /// \brief The ID of the arc.
+ ///
+ /// Returns the ID of the given arc.
+ int id(Arc) const { return -1; }
+
+ /// \brief The node with the given ID.
+ ///
+ /// Returns the node with the given ID.
+ /// \pre The argument should be a valid node ID in the digraph.
+ Node nodeFromId(int) const { return INVALID; }
+
+ /// \brief The arc with the given ID.
+ ///
+ /// Returns the arc with the given ID.
+ /// \pre The argument should be a valid arc ID in the digraph.
+ Arc arcFromId(int) const { return INVALID; }
+
+ /// \brief An upper bound on the node IDs.
+ ///
+ /// Returns an upper bound on the node IDs.
+ int maxNodeId() const { return -1; }
+
+ /// \brief An upper bound on the arc IDs.
+ ///
+ /// Returns an upper bound on the arc IDs.
+ int maxArcId() const { return -1; }
+
+ void first(Node&) const {}
+ void next(Node&) const {}
+
+ void first(Arc&) const {}
+ void next(Arc&) const {}
+
+
+ void firstIn(Arc&, const Node&) const {}
+ void nextIn(Arc&) const {}
+
+ void firstOut(Arc&, const Node&) const {}
+ void nextOut(Arc&) const {}
+
+ // The second parameter is dummy.
+ Node fromId(int, Node) const { return INVALID; }
+ // The second parameter is dummy.
+ Arc fromId(int, Arc) const { return INVALID; }
+
+ // Dummy parameter.
+ int maxId(Node) const { return -1; }
+ // Dummy parameter.
+ int maxId(Arc) const { return -1; }
+
+ /// \brief The opposite node on the arc.
+ ///
+ /// Returns the opposite node on the given arc.
+ Node oppositeNode(Node, Arc) const { return INVALID; }
+
+ /// \brief The base node of the iterator.
+ ///
+ /// Returns the base node of the given outgoing arc iterator
+ /// (i.e. the source node of the corresponding arc).
+ Node baseNode(OutArcIt) const { return INVALID; }
+
+ /// \brief The running node of the iterator.
+ ///
+ /// Returns the running node of the given outgoing arc iterator
+ /// (i.e. the target node of the corresponding arc).
+ Node runningNode(OutArcIt) const { return INVALID; }
+
+ /// \brief The base node of the iterator.
+ ///
+ /// Returns the base node of the given incoming arc iterator
+ /// (i.e. the target node of the corresponding arc).
+ Node baseNode(InArcIt) const { return INVALID; }
+
+ /// \brief The running node of the iterator.
+ ///
+ /// Returns the running node of the given incoming arc iterator
+ /// (i.e. the source node of the corresponding arc).
+ Node runningNode(InArcIt) const { return INVALID; }
+
+ /// \brief Standard graph map type for the nodes.
+ ///
+ /// Standard graph map type for the nodes.
+ /// It conforms to the ReferenceMap concept.
+ template<class T>
+ class NodeMap : public ReferenceMap<Node, T, T&, const T&> {
+ public:
+
+ /// Constructor
+ explicit NodeMap(const Digraph&) { }
+ /// Constructor with given initial value
+ NodeMap(const Digraph&, T) { }
+
+ private:
+ ///Copy constructor
+ NodeMap(const NodeMap& nm) :
+ ReferenceMap<Node, T, T&, const T&>(nm) { }
+ ///Assignment operator
+ template <typename CMap>
+ NodeMap& operator=(const CMap&) {
+ checkConcept<ReadMap<Node, T>, CMap>();
+ return *this;
+ }
+ };
+
+ /// \brief Standard graph map type for the arcs.
+ ///
+ /// Standard graph map type for the arcs.
+ /// It conforms to the ReferenceMap concept.
+ template<class T>
+ class ArcMap : public ReferenceMap<Arc, T, T&, const T&> {
+ public:
+
+ /// Constructor
+ explicit ArcMap(const Digraph&) { }
+ /// Constructor with given initial value
+ ArcMap(const Digraph&, T) { }
+
+ private:
+ ///Copy constructor
+ ArcMap(const ArcMap& em) :
+ ReferenceMap<Arc, T, T&, const T&>(em) { }
+ ///Assignment operator
+ template <typename CMap>
+ ArcMap& operator=(const CMap&) {
+ checkConcept<ReadMap<Arc, T>, CMap>();
+ return *this;
+ }
+ };
+
+ template <typename _Digraph>
+ struct Constraints {
+ void constraints() {
+ checkConcept<BaseDigraphComponent, _Digraph>();
+ checkConcept<IterableDigraphComponent<>, _Digraph>();
+ checkConcept<IDableDigraphComponent<>, _Digraph>();
+ checkConcept<MappableDigraphComponent<>, _Digraph>();
+ }
+ };
+
+ };
+
+ } //namespace concepts
+} //namespace lemon
+
+
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/graph.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/graph.h
new file mode 100644
index 00000000000..76e43da0680
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/graph.h
@@ -0,0 +1,788 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+///\ingroup graph_concepts
+///\file
+///\brief The concept of undirected graphs.
+
+#ifndef LEMON_CONCEPTS_GRAPH_H
+#define LEMON_CONCEPTS_GRAPH_H
+
+#include <lemon/concepts/graph_components.h>
+#include <lemon/concepts/maps.h>
+#include <lemon/concept_check.h>
+#include <lemon/core.h>
+
+namespace lemon {
+ namespace concepts {
+
+ /// \ingroup graph_concepts
+ ///
+ /// \brief Class describing the concept of undirected graphs.
+ ///
+ /// This class describes the common interface of all undirected
+ /// graphs.
+ ///
+ /// Like all concept classes, it only provides an interface
+ /// without any sensible implementation. So any general algorithm for
+ /// undirected graphs should compile with this class, but it will not
+ /// run properly, of course.
+ /// An actual graph implementation like \ref ListGraph or
+ /// \ref SmartGraph may have additional functionality.
+ ///
+ /// The undirected graphs also fulfill the concept of \ref Digraph
+ /// "directed graphs", since each edge can also be regarded as two
+ /// oppositely directed arcs.
+ /// Undirected graphs provide an Edge type for the undirected edges and
+ /// an Arc type for the directed arcs. The Arc type is convertible to
+ /// Edge or inherited from it, i.e. the corresponding edge can be
+ /// obtained from an arc.
+ /// EdgeIt and EdgeMap classes can be used for the edges, while ArcIt
+ /// and ArcMap classes can be used for the arcs (just like in digraphs).
+ /// Both InArcIt and OutArcIt iterates on the same edges but with
+ /// opposite direction. IncEdgeIt also iterates on the same edges
+ /// as OutArcIt and InArcIt, but it is not convertible to Arc,
+ /// only to Edge.
+ ///
+ /// In LEMON, each undirected edge has an inherent orientation.
+ /// Thus it can defined if an arc is forward or backward oriented in
+ /// an undirected graph with respect to this default oriantation of
+ /// the represented edge.
+ /// With the direction() and direct() functions the direction
+ /// of an arc can be obtained and set, respectively.
+ ///
+ /// Only nodes and edges can be added to or removed from an undirected
+ /// graph and the corresponding arcs are added or removed automatically.
+ ///
+ /// \sa Digraph
+ class Graph {
+ private:
+ /// Graphs are \e not copy constructible. Use GraphCopy instead.
+ Graph(const Graph&) {}
+ /// \brief Assignment of a graph to another one is \e not allowed.
+ /// Use GraphCopy instead.
+ void operator=(const Graph&) {}
+
+ public:
+ /// Default constructor.
+ Graph() {}
+
+ /// \brief Undirected graphs should be tagged with \c UndirectedTag.
+ ///
+ /// Undirected graphs should be tagged with \c UndirectedTag.
+ ///
+ /// This tag helps the \c enable_if technics to make compile time
+ /// specializations for undirected graphs.
+ typedef True UndirectedTag;
+
+ /// The node type of the graph
+
+ /// This class identifies a node of the graph. It also serves
+ /// as a base class of the node iterators,
+ /// thus they convert to this type.
+ class Node {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the object to an undefined value.
+ Node() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ Node(const Node&) { }
+
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the object to be invalid.
+ /// \sa Invalid for more details.
+ Node(Invalid) { }
+ /// Equality operator
+
+ /// Equality operator.
+ ///
+ /// Two iterators are equal if and only if they point to the
+ /// same object or both are \c INVALID.
+ bool operator==(Node) const { return true; }
+
+ /// Inequality operator
+
+ /// Inequality operator.
+ bool operator!=(Node) const { return true; }
+
+ /// Artificial ordering operator.
+
+ /// Artificial ordering operator.
+ ///
+ /// \note This operator only has to define some strict ordering of
+ /// the items; this order has nothing to do with the iteration
+ /// ordering of the items.
+ bool operator<(Node) const { return false; }
+
+ };
+
+ /// Iterator class for the nodes.
+
+ /// This iterator goes through each node of the graph.
+ /// Its usage is quite simple, for example, you can count the number
+ /// of nodes in a graph \c g of type \c %Graph like this:
+ ///\code
+ /// int count=0;
+ /// for (Graph::NodeIt n(g); n!=INVALID; ++n) ++count;
+ ///\endcode
+ class NodeIt : public Node {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the iterator to an undefined value.
+ NodeIt() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ NodeIt(const NodeIt& n) : Node(n) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ NodeIt(Invalid) { }
+ /// Sets the iterator to the first node.
+
+ /// Sets the iterator to the first node of the given digraph.
+ ///
+ explicit NodeIt(const Graph&) { }
+ /// Sets the iterator to the given node.
+
+ /// Sets the iterator to the given node of the given digraph.
+ ///
+ NodeIt(const Graph&, const Node&) { }
+ /// Next node.
+
+ /// Assign the iterator to the next node.
+ ///
+ NodeIt& operator++() { return *this; }
+ };
+
+
+ /// The edge type of the graph
+
+ /// This class identifies an edge of the graph. It also serves
+ /// as a base class of the edge iterators,
+ /// thus they will convert to this type.
+ class Edge {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the object to an undefined value.
+ Edge() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ Edge(const Edge&) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the object to be invalid.
+ /// \sa Invalid for more details.
+ Edge(Invalid) { }
+ /// Equality operator
+
+ /// Equality operator.
+ ///
+ /// Two iterators are equal if and only if they point to the
+ /// same object or both are \c INVALID.
+ bool operator==(Edge) const { return true; }
+ /// Inequality operator
+
+ /// Inequality operator.
+ bool operator!=(Edge) const { return true; }
+
+ /// Artificial ordering operator.
+
+ /// Artificial ordering operator.
+ ///
+ /// \note This operator only has to define some strict ordering of
+ /// the edges; this order has nothing to do with the iteration
+ /// ordering of the edges.
+ bool operator<(Edge) const { return false; }
+ };
+
+ /// Iterator class for the edges.
+
+ /// This iterator goes through each edge of the graph.
+ /// Its usage is quite simple, for example, you can count the number
+ /// of edges in a graph \c g of type \c %Graph as follows:
+ ///\code
+ /// int count=0;
+ /// for(Graph::EdgeIt e(g); e!=INVALID; ++e) ++count;
+ ///\endcode
+ class EdgeIt : public Edge {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the iterator to an undefined value.
+ EdgeIt() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ EdgeIt(const EdgeIt& e) : Edge(e) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ EdgeIt(Invalid) { }
+ /// Sets the iterator to the first edge.
+
+ /// Sets the iterator to the first edge of the given graph.
+ ///
+ explicit EdgeIt(const Graph&) { }
+ /// Sets the iterator to the given edge.
+
+ /// Sets the iterator to the given edge of the given graph.
+ ///
+ EdgeIt(const Graph&, const Edge&) { }
+ /// Next edge
+
+ /// Assign the iterator to the next edge.
+ ///
+ EdgeIt& operator++() { return *this; }
+ };
+
+ /// Iterator class for the incident edges of a node.
+
+ /// This iterator goes trough the incident undirected edges
+ /// of a certain node of a graph.
+ /// Its usage is quite simple, for example, you can compute the
+ /// degree (i.e. the number of incident edges) of a node \c n
+ /// in a graph \c g of type \c %Graph as follows.
+ ///
+ ///\code
+ /// int count=0;
+ /// for(Graph::IncEdgeIt e(g, n); e!=INVALID; ++e) ++count;
+ ///\endcode
+ ///
+ /// \warning Loop edges will be iterated twice.
+ class IncEdgeIt : public Edge {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the iterator to an undefined value.
+ IncEdgeIt() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ IncEdgeIt(const IncEdgeIt& e) : Edge(e) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ IncEdgeIt(Invalid) { }
+ /// Sets the iterator to the first incident edge.
+
+ /// Sets the iterator to the first incident edge of the given node.
+ ///
+ IncEdgeIt(const Graph&, const Node&) { }
+ /// Sets the iterator to the given edge.
+
+ /// Sets the iterator to the given edge of the given graph.
+ ///
+ IncEdgeIt(const Graph&, const Edge&) { }
+ /// Next incident edge
+
+ /// Assign the iterator to the next incident edge
+ /// of the corresponding node.
+ IncEdgeIt& operator++() { return *this; }
+ };
+
+ /// The arc type of the graph
+
+ /// This class identifies a directed arc of the graph. It also serves
+ /// as a base class of the arc iterators,
+ /// thus they will convert to this type.
+ class Arc {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the object to an undefined value.
+ Arc() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ Arc(const Arc&) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the object to be invalid.
+ /// \sa Invalid for more details.
+ Arc(Invalid) { }
+ /// Equality operator
+
+ /// Equality operator.
+ ///
+ /// Two iterators are equal if and only if they point to the
+ /// same object or both are \c INVALID.
+ bool operator==(Arc) const { return true; }
+ /// Inequality operator
+
+ /// Inequality operator.
+ bool operator!=(Arc) const { return true; }
+
+ /// Artificial ordering operator.
+
+ /// Artificial ordering operator.
+ ///
+ /// \note This operator only has to define some strict ordering of
+ /// the arcs; this order has nothing to do with the iteration
+ /// ordering of the arcs.
+ bool operator<(Arc) const { return false; }
+
+ /// Converison to \c Edge
+
+ /// Converison to \c Edge.
+ ///
+ operator Edge() const { return Edge(); }
+ };
+
+ /// Iterator class for the arcs.
+
+ /// This iterator goes through each directed arc of the graph.
+ /// Its usage is quite simple, for example, you can count the number
+ /// of arcs in a graph \c g of type \c %Graph as follows:
+ ///\code
+ /// int count=0;
+ /// for(Graph::ArcIt a(g); a!=INVALID; ++a) ++count;
+ ///\endcode
+ class ArcIt : public Arc {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the iterator to an undefined value.
+ ArcIt() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ ArcIt(const ArcIt& e) : Arc(e) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ ArcIt(Invalid) { }
+ /// Sets the iterator to the first arc.
+
+ /// Sets the iterator to the first arc of the given graph.
+ ///
+ explicit ArcIt(const Graph &g) {
+ ::lemon::ignore_unused_variable_warning(g);
+ }
+ /// Sets the iterator to the given arc.
+
+ /// Sets the iterator to the given arc of the given graph.
+ ///
+ ArcIt(const Graph&, const Arc&) { }
+ /// Next arc
+
+ /// Assign the iterator to the next arc.
+ ///
+ ArcIt& operator++() { return *this; }
+ };
+
+ /// Iterator class for the outgoing arcs of a node.
+
+ /// This iterator goes trough the \e outgoing directed arcs of a
+ /// certain node of a graph.
+ /// Its usage is quite simple, for example, you can count the number
+ /// of outgoing arcs of a node \c n
+ /// in a graph \c g of type \c %Graph as follows.
+ ///\code
+ /// int count=0;
+ /// for (Digraph::OutArcIt a(g, n); a!=INVALID; ++a) ++count;
+ ///\endcode
+ class OutArcIt : public Arc {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the iterator to an undefined value.
+ OutArcIt() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ OutArcIt(const OutArcIt& e) : Arc(e) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ OutArcIt(Invalid) { }
+ /// Sets the iterator to the first outgoing arc.
+
+ /// Sets the iterator to the first outgoing arc of the given node.
+ ///
+ OutArcIt(const Graph& n, const Node& g) {
+ ::lemon::ignore_unused_variable_warning(n);
+ ::lemon::ignore_unused_variable_warning(g);
+ }
+ /// Sets the iterator to the given arc.
+
+ /// Sets the iterator to the given arc of the given graph.
+ ///
+ OutArcIt(const Graph&, const Arc&) { }
+ /// Next outgoing arc
+
+ /// Assign the iterator to the next
+ /// outgoing arc of the corresponding node.
+ OutArcIt& operator++() { return *this; }
+ };
+
+ /// Iterator class for the incoming arcs of a node.
+
+ /// This iterator goes trough the \e incoming directed arcs of a
+ /// certain node of a graph.
+ /// Its usage is quite simple, for example, you can count the number
+ /// of incoming arcs of a node \c n
+ /// in a graph \c g of type \c %Graph as follows.
+ ///\code
+ /// int count=0;
+ /// for (Digraph::InArcIt a(g, n); a!=INVALID; ++a) ++count;
+ ///\endcode
+ class InArcIt : public Arc {
+ public:
+ /// Default constructor
+
+ /// Default constructor.
+ /// \warning It sets the iterator to an undefined value.
+ InArcIt() { }
+ /// Copy constructor.
+
+ /// Copy constructor.
+ ///
+ InArcIt(const InArcIt& e) : Arc(e) { }
+ /// %Invalid constructor \& conversion.
+
+ /// Initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ InArcIt(Invalid) { }
+ /// Sets the iterator to the first incoming arc.
+
+ /// Sets the iterator to the first incoming arc of the given node.
+ ///
+ InArcIt(const Graph& g, const Node& n) {
+ ::lemon::ignore_unused_variable_warning(n);
+ ::lemon::ignore_unused_variable_warning(g);
+ }
+ /// Sets the iterator to the given arc.
+
+ /// Sets the iterator to the given arc of the given graph.
+ ///
+ InArcIt(const Graph&, const Arc&) { }
+ /// Next incoming arc
+
+ /// Assign the iterator to the next
+ /// incoming arc of the corresponding node.
+ InArcIt& operator++() { return *this; }
+ };
+
+ /// \brief Standard graph map type for the nodes.
+ ///
+ /// Standard graph map type for the nodes.
+ /// It conforms to the ReferenceMap concept.
+ template<class T>
+ class NodeMap : public ReferenceMap<Node, T, T&, const T&>
+ {
+ public:
+
+ /// Constructor
+ explicit NodeMap(const Graph&) { }
+ /// Constructor with given initial value
+ NodeMap(const Graph&, T) { }
+
+ private:
+ ///Copy constructor
+ NodeMap(const NodeMap& nm) :
+ ReferenceMap<Node, T, T&, const T&>(nm) { }
+ ///Assignment operator
+ template <typename CMap>
+ NodeMap& operator=(const CMap&) {
+ checkConcept<ReadMap<Node, T>, CMap>();
+ return *this;
+ }
+ };
+
+ /// \brief Standard graph map type for the arcs.
+ ///
+ /// Standard graph map type for the arcs.
+ /// It conforms to the ReferenceMap concept.
+ template<class T>
+ class ArcMap : public ReferenceMap<Arc, T, T&, const T&>
+ {
+ public:
+
+ /// Constructor
+ explicit ArcMap(const Graph&) { }
+ /// Constructor with given initial value
+ ArcMap(const Graph&, T) { }
+
+ private:
+ ///Copy constructor
+ ArcMap(const ArcMap& em) :
+ ReferenceMap<Arc, T, T&, const T&>(em) { }
+ ///Assignment operator
+ template <typename CMap>
+ ArcMap& operator=(const CMap&) {
+ checkConcept<ReadMap<Arc, T>, CMap>();
+ return *this;
+ }
+ };
+
+ /// \brief Standard graph map type for the edges.
+ ///
+ /// Standard graph map type for the edges.
+ /// It conforms to the ReferenceMap concept.
+ template<class T>
+ class EdgeMap : public ReferenceMap<Edge, T, T&, const T&>
+ {
+ public:
+
+ /// Constructor
+ explicit EdgeMap(const Graph&) { }
+ /// Constructor with given initial value
+ EdgeMap(const Graph&, T) { }
+
+ private:
+ ///Copy constructor
+ EdgeMap(const EdgeMap& em) :
+ ReferenceMap<Edge, T, T&, const T&>(em) {}
+ ///Assignment operator
+ template <typename CMap>
+ EdgeMap& operator=(const CMap&) {
+ checkConcept<ReadMap<Edge, T>, CMap>();
+ return *this;
+ }
+ };
+
+ /// \brief The first node of the edge.
+ ///
+ /// Returns the first node of the given edge.
+ ///
+ /// Edges don't have source and target nodes, however, methods
+ /// u() and v() are used to query the two end-nodes of an edge.
+ /// The orientation of an edge that arises this way is called
+ /// the inherent direction, it is used to define the default
+ /// direction for the corresponding arcs.
+ /// \sa v()
+ /// \sa direction()
+ Node u(Edge) const { return INVALID; }
+
+ /// \brief The second node of the edge.
+ ///
+ /// Returns the second node of the given edge.
+ ///
+ /// Edges don't have source and target nodes, however, methods
+ /// u() and v() are used to query the two end-nodes of an edge.
+ /// The orientation of an edge that arises this way is called
+ /// the inherent direction, it is used to define the default
+ /// direction for the corresponding arcs.
+ /// \sa u()
+ /// \sa direction()
+ Node v(Edge) const { return INVALID; }
+
+ /// \brief The source node of the arc.
+ ///
+ /// Returns the source node of the given arc.
+ Node source(Arc) const { return INVALID; }
+
+ /// \brief The target node of the arc.
+ ///
+ /// Returns the target node of the given arc.
+ Node target(Arc) const { return INVALID; }
+
+ /// \brief The ID of the node.
+ ///
+ /// Returns the ID of the given node.
+ int id(Node) const { return -1; }
+
+ /// \brief The ID of the edge.
+ ///
+ /// Returns the ID of the given edge.
+ int id(Edge) const { return -1; }
+
+ /// \brief The ID of the arc.
+ ///
+ /// Returns the ID of the given arc.
+ int id(Arc) const { return -1; }
+
+ /// \brief The node with the given ID.
+ ///
+ /// Returns the node with the given ID.
+ /// \pre The argument should be a valid node ID in the graph.
+ Node nodeFromId(int) const { return INVALID; }
+
+ /// \brief The edge with the given ID.
+ ///
+ /// Returns the edge with the given ID.
+ /// \pre The argument should be a valid edge ID in the graph.
+ Edge edgeFromId(int) const { return INVALID; }
+
+ /// \brief The arc with the given ID.
+ ///
+ /// Returns the arc with the given ID.
+ /// \pre The argument should be a valid arc ID in the graph.
+ Arc arcFromId(int) const { return INVALID; }
+
+ /// \brief An upper bound on the node IDs.
+ ///
+ /// Returns an upper bound on the node IDs.
+ int maxNodeId() const { return -1; }
+
+ /// \brief An upper bound on the edge IDs.
+ ///
+ /// Returns an upper bound on the edge IDs.
+ int maxEdgeId() const { return -1; }
+
+ /// \brief An upper bound on the arc IDs.
+ ///
+ /// Returns an upper bound on the arc IDs.
+ int maxArcId() const { return -1; }
+
+ /// \brief The direction of the arc.
+ ///
+ /// Returns \c true if the direction of the given arc is the same as
+ /// the inherent orientation of the represented edge.
+ bool direction(Arc) const { return true; }
+
+ /// \brief Direct the edge.
+ ///
+ /// Direct the given edge. The returned arc
+ /// represents the given edge and its direction comes
+ /// from the bool parameter. If it is \c true, then the direction
+ /// of the arc is the same as the inherent orientation of the edge.
+ Arc direct(Edge, bool) const {
+ return INVALID;
+ }
+
+ /// \brief Direct the edge.
+ ///
+ /// Direct the given edge. The returned arc represents the given
+ /// edge and its source node is the given node.
+ Arc direct(Edge, Node) const {
+ return INVALID;
+ }
+
+ /// \brief The oppositely directed arc.
+ ///
+ /// Returns the oppositely directed arc representing the same edge.
+ Arc oppositeArc(Arc) const { return INVALID; }
+
+ /// \brief The opposite node on the edge.
+ ///
+ /// Returns the opposite node on the given edge.
+ Node oppositeNode(Node, Edge) const { return INVALID; }
+
+ void first(Node&) const {}
+ void next(Node&) const {}
+
+ void first(Edge&) const {}
+ void next(Edge&) const {}
+
+ void first(Arc&) const {}
+ void next(Arc&) const {}
+
+ void firstOut(Arc&, Node) const {}
+ void nextOut(Arc&) const {}
+
+ void firstIn(Arc&, Node) const {}
+ void nextIn(Arc&) const {}
+
+ void firstInc(Edge &, bool &, const Node &) const {}
+ void nextInc(Edge &, bool &) const {}
+
+ // The second parameter is dummy.
+ Node fromId(int, Node) const { return INVALID; }
+ // The second parameter is dummy.
+ Edge fromId(int, Edge) const { return INVALID; }
+ // The second parameter is dummy.
+ Arc fromId(int, Arc) const { return INVALID; }
+
+ // Dummy parameter.
+ int maxId(Node) const { return -1; }
+ // Dummy parameter.
+ int maxId(Edge) const { return -1; }
+ // Dummy parameter.
+ int maxId(Arc) const { return -1; }
+
+ /// \brief The base node of the iterator.
+ ///
+ /// Returns the base node of the given incident edge iterator.
+ Node baseNode(IncEdgeIt) const { return INVALID; }
+
+ /// \brief The running node of the iterator.
+ ///
+ /// Returns the running node of the given incident edge iterator.
+ Node runningNode(IncEdgeIt) const { return INVALID; }
+
+ /// \brief The base node of the iterator.
+ ///
+ /// Returns the base node of the given outgoing arc iterator
+ /// (i.e. the source node of the corresponding arc).
+ Node baseNode(OutArcIt) const { return INVALID; }
+
+ /// \brief The running node of the iterator.
+ ///
+ /// Returns the running node of the given outgoing arc iterator
+ /// (i.e. the target node of the corresponding arc).
+ Node runningNode(OutArcIt) const { return INVALID; }
+
+ /// \brief The base node of the iterator.
+ ///
+ /// Returns the base node of the given incoming arc iterator
+ /// (i.e. the target node of the corresponding arc).
+ Node baseNode(InArcIt) const { return INVALID; }
+
+ /// \brief The running node of the iterator.
+ ///
+ /// Returns the running node of the given incoming arc iterator
+ /// (i.e. the source node of the corresponding arc).
+ Node runningNode(InArcIt) const { return INVALID; }
+
+ template <typename _Graph>
+ struct Constraints {
+ void constraints() {
+ checkConcept<BaseGraphComponent, _Graph>();
+ checkConcept<IterableGraphComponent<>, _Graph>();
+ checkConcept<IDableGraphComponent<>, _Graph>();
+ checkConcept<MappableGraphComponent<>, _Graph>();
+ }
+ };
+
+ };
+
+ }
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/graph_components.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/graph_components.h
new file mode 100644
index 00000000000..9df28f37e61
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/graph_components.h
@@ -0,0 +1,2134 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+///\ingroup graph_concepts
+///\file
+///\brief The concepts of graph components.
+
+#ifndef LEMON_CONCEPTS_GRAPH_COMPONENTS_H
+#define LEMON_CONCEPTS_GRAPH_COMPONENTS_H
+
+#include <lemon/core.h>
+#include <lemon/concepts/maps.h>
+
+#include <lemon/bits/alteration_notifier.h>
+
+namespace lemon {
+ namespace concepts {
+
+ /// \brief Concept class for \c Node, \c Arc and \c Edge types.
+ ///
+ /// This class describes the concept of \c Node, \c Arc and \c Edge
+ /// subtypes of digraph and graph types.
+ ///
+ /// \note This class is a template class so that we can use it to
+ /// create graph skeleton classes. The reason for this is that \c Node
+ /// and \c Arc (or \c Edge) types should \e not derive from the same
+ /// base class. For \c Node you should instantiate it with character
+ /// \c 'n', for \c Arc with \c 'a' and for \c Edge with \c 'e'.
+#ifndef DOXYGEN
+ template <char sel = '0'>
+#endif
+ class GraphItem {
+ public:
+ /// \brief Default constructor.
+ ///
+ /// Default constructor.
+ /// \warning The default constructor is not required to set
+ /// the item to some well-defined value. So you should consider it
+ /// as uninitialized.
+ GraphItem() {}
+
+ /// \brief Copy constructor.
+ ///
+ /// Copy constructor.
+ GraphItem(const GraphItem &) {}
+
+ /// \brief Constructor for conversion from \c INVALID.
+ ///
+ /// Constructor for conversion from \c INVALID.
+ /// It initializes the item to be invalid.
+ /// \sa Invalid for more details.
+ GraphItem(Invalid) {}
+
+ /// \brief Assignment operator.
+ ///
+ /// Assignment operator for the item.
+ GraphItem& operator=(const GraphItem&) { return *this; }
+
+ /// \brief Assignment operator for INVALID.
+ ///
+ /// This operator makes the item invalid.
+ GraphItem& operator=(Invalid) { return *this; }
+
+ /// \brief Equality operator.
+ ///
+ /// Equality operator.
+ bool operator==(const GraphItem&) const { return false; }
+
+ /// \brief Inequality operator.
+ ///
+ /// Inequality operator.
+ bool operator!=(const GraphItem&) const { return false; }
+
+ /// \brief Ordering operator.
+ ///
+ /// This operator defines an ordering of the items.
+ /// It makes possible to use graph item types as key types in
+ /// associative containers (e.g. \c std::map).
+ ///
+ /// \note This operator only has to define some strict ordering of
+ /// the items; this order has nothing to do with the iteration
+ /// ordering of the items.
+ bool operator<(const GraphItem&) const { return false; }
+
+ template<typename _GraphItem>
+ struct Constraints {
+ void constraints() {
+ _GraphItem i1;
+ i1=INVALID;
+ _GraphItem i2 = i1;
+ _GraphItem i3 = INVALID;
+
+ i1 = i2 = i3;
+
+ bool b;
+ ::lemon::ignore_unused_variable_warning(b);
+
+ b = (ia == ib) && (ia != ib);
+ b = (ia == INVALID) && (ib != INVALID);
+ b = (ia < ib);
+ }
+
+ const _GraphItem &ia;
+ const _GraphItem &ib;
+ Constraints() {}
+ };
+ };
+
+ /// \brief Base skeleton class for directed graphs.
+ ///
+ /// This class describes the base interface of directed graph types.
+ /// All digraph %concepts have to conform to this class.
+ /// It just provides types for nodes and arcs and functions
+ /// to get the source and the target nodes of arcs.
+ class BaseDigraphComponent {
+ public:
+
+ typedef BaseDigraphComponent Digraph;
+
+ /// \brief Node class of the digraph.
+ ///
+ /// This class represents the nodes of the digraph.
+ typedef GraphItem<'n'> Node;
+
+ /// \brief Arc class of the digraph.
+ ///
+ /// This class represents the arcs of the digraph.
+ typedef GraphItem<'a'> Arc;
+
+ /// \brief Return the source node of an arc.
+ ///
+ /// This function returns the source node of an arc.
+ Node source(const Arc&) const { return INVALID; }
+
+ /// \brief Return the target node of an arc.
+ ///
+ /// This function returns the target node of an arc.
+ Node target(const Arc&) const { return INVALID; }
+
+ /// \brief Return the opposite node on the given arc.
+ ///
+ /// This function returns the opposite node on the given arc.
+ Node oppositeNode(const Node&, const Arc&) const {
+ return INVALID;
+ }
+
+ template <typename _Digraph>
+ struct Constraints {
+ typedef typename _Digraph::Node Node;
+ typedef typename _Digraph::Arc Arc;
+
+ void constraints() {
+ checkConcept<GraphItem<'n'>, Node>();
+ checkConcept<GraphItem<'a'>, Arc>();
+ {
+ Node n;
+ Arc e(INVALID);
+ n = digraph.source(e);
+ n = digraph.target(e);
+ n = digraph.oppositeNode(n, e);
+ }
+ }
+
+ const _Digraph& digraph;
+ Constraints() {}
+ };
+ };
+
+ /// \brief Base skeleton class for undirected graphs.
+ ///
+ /// This class describes the base interface of undirected graph types.
+ /// All graph %concepts have to conform to this class.
+ /// It extends the interface of \ref BaseDigraphComponent with an
+ /// \c Edge type and functions to get the end nodes of edges,
+ /// to convert from arcs to edges and to get both direction of edges.
+ class BaseGraphComponent : public BaseDigraphComponent {
+ public:
+
+ typedef BaseGraphComponent Graph;
+
+ typedef BaseDigraphComponent::Node Node;
+ typedef BaseDigraphComponent::Arc Arc;
+
+ /// \brief Undirected edge class of the graph.
+ ///
+ /// This class represents the undirected edges of the graph.
+ /// Undirected graphs can be used as directed graphs, each edge is
+ /// represented by two opposite directed arcs.
+ class Edge : public GraphItem<'e'> {
+ typedef GraphItem<'e'> Parent;
+
+ public:
+ /// \brief Default constructor.
+ ///
+ /// Default constructor.
+ /// \warning The default constructor is not required to set
+ /// the item to some well-defined value. So you should consider it
+ /// as uninitialized.
+ Edge() {}
+
+ /// \brief Copy constructor.
+ ///
+ /// Copy constructor.
+ Edge(const Edge &) : Parent() {}
+
+ /// \brief Constructor for conversion from \c INVALID.
+ ///
+ /// Constructor for conversion from \c INVALID.
+ /// It initializes the item to be invalid.
+ /// \sa Invalid for more details.
+ Edge(Invalid) {}
+
+ /// \brief Constructor for conversion from an arc.
+ ///
+ /// Constructor for conversion from an arc.
+ /// Besides the core graph item functionality each arc should
+ /// be convertible to the represented edge.
+ Edge(const Arc&) {}
+ };
+
+ /// \brief Return one end node of an edge.
+ ///
+ /// This function returns one end node of an edge.
+ Node u(const Edge&) const { return INVALID; }
+
+ /// \brief Return the other end node of an edge.
+ ///
+ /// This function returns the other end node of an edge.
+ Node v(const Edge&) const { return INVALID; }
+
+ /// \brief Return a directed arc related to an edge.
+ ///
+ /// This function returns a directed arc from its direction and the
+ /// represented edge.
+ Arc direct(const Edge&, bool) const { return INVALID; }
+
+ /// \brief Return a directed arc related to an edge.
+ ///
+ /// This function returns a directed arc from its source node and the
+ /// represented edge.
+ Arc direct(const Edge&, const Node&) const { return INVALID; }
+
+ /// \brief Return the direction of the arc.
+ ///
+ /// Returns the direction of the arc. Each arc represents an
+ /// edge with a direction. It gives back the
+ /// direction.
+ bool direction(const Arc&) const { return true; }
+
+ /// \brief Return the opposite arc.
+ ///
+ /// This function returns the opposite arc, i.e. the arc representing
+ /// the same edge and has opposite direction.
+ Arc oppositeArc(const Arc&) const { return INVALID; }
+
+ template <typename _Graph>
+ struct Constraints {
+ typedef typename _Graph::Node Node;
+ typedef typename _Graph::Arc Arc;
+ typedef typename _Graph::Edge Edge;
+
+ void constraints() {
+ checkConcept<BaseDigraphComponent, _Graph>();
+ checkConcept<GraphItem<'e'>, Edge>();
+ {
+ Node n;
+ Edge ue(INVALID);
+ Arc e;
+ n = graph.u(ue);
+ n = graph.v(ue);
+ e = graph.direct(ue, true);
+ e = graph.direct(ue, false);
+ e = graph.direct(ue, n);
+ e = graph.oppositeArc(e);
+ ue = e;
+ bool d = graph.direction(e);
+ ::lemon::ignore_unused_variable_warning(d);
+ }
+ }
+
+ const _Graph& graph;
+ Constraints() {}
+ };
+
+ };
+
+ /// \brief Base skeleton class for undirected bipartite graphs.
+ ///
+ /// This class describes the base interface of undirected
+ /// bipartite graph types. All bipartite graph %concepts have to
+ /// conform to this class. It extends the interface of \ref
+ /// BaseGraphComponent with an \c Edge type and functions to get
+ /// the end nodes of edges, to convert from arcs to edges and to
+ /// get both direction of edges.
+ class BaseBpGraphComponent : public BaseGraphComponent {
+ public:
+
+ typedef BaseBpGraphComponent BpGraph;
+
+ typedef BaseDigraphComponent::Node Node;
+ typedef BaseDigraphComponent::Arc Arc;
+
+ /// \brief Class to represent red nodes.
+ ///
+ /// This class represents the red nodes of the graph. The red
+ /// nodes can also be used as normal nodes.
+ class RedNode : public Node {
+ typedef Node Parent;
+
+ public:
+ /// \brief Default constructor.
+ ///
+ /// Default constructor.
+ /// \warning The default constructor is not required to set
+ /// the item to some well-defined value. So you should consider it
+ /// as uninitialized.
+ RedNode() {}
+
+ /// \brief Copy constructor.
+ ///
+ /// Copy constructor.
+ RedNode(const RedNode &) : Parent() {}
+
+ /// \brief Constructor for conversion from \c INVALID.
+ ///
+ /// Constructor for conversion from \c INVALID.
+ /// It initializes the item to be invalid.
+ /// \sa Invalid for more details.
+ RedNode(Invalid) {}
+ };
+
+ /// \brief Class to represent blue nodes.
+ ///
+ /// This class represents the blue nodes of the graph. The blue
+ /// nodes can also be used as normal nodes.
+ class BlueNode : public Node {
+ typedef Node Parent;
+
+ public:
+ /// \brief Default constructor.
+ ///
+ /// Default constructor.
+ /// \warning The default constructor is not required to set
+ /// the item to some well-defined value. So you should consider it
+ /// as uninitialized.
+ BlueNode() {}
+
+ /// \brief Copy constructor.
+ ///
+ /// Copy constructor.
+ BlueNode(const BlueNode &) : Parent() {}
+
+ /// \brief Constructor for conversion from \c INVALID.
+ ///
+ /// Constructor for conversion from \c INVALID.
+ /// It initializes the item to be invalid.
+ /// \sa Invalid for more details.
+ BlueNode(Invalid) {}
+
+ /// \brief Constructor for conversion from a node.
+ ///
+ /// Constructor for conversion from a node. The conversion can
+ /// be invalid, since the Node can be member of the red
+ /// set.
+ BlueNode(const Node&) {}
+ };
+
+ /// \brief Gives back %true for red nodes.
+ ///
+ /// Gives back %true for red nodes.
+ bool red(const Node&) const { return true; }
+
+ /// \brief Gives back %true for blue nodes.
+ ///
+ /// Gives back %true for blue nodes.
+ bool blue(const Node&) const { return true; }
+
+ /// \brief Gives back the red end node of the edge.
+ ///
+ /// Gives back the red end node of the edge.
+ RedNode redNode(const Edge&) const { return RedNode(); }
+
+ /// \brief Gives back the blue end node of the edge.
+ ///
+ /// Gives back the blue end node of the edge.
+ BlueNode blueNode(const Edge&) const { return BlueNode(); }
+
+ /// \brief Converts the node to red node object.
+ ///
+ /// This function converts unsafely the node to red node
+ /// object. It should be called only if the node is from the red
+ /// partition or INVALID.
+ RedNode asRedNodeUnsafe(const Node&) const { return RedNode(); }
+
+ /// \brief Converts the node to blue node object.
+ ///
+ /// This function converts unsafely the node to blue node
+ /// object. It should be called only if the node is from the red
+ /// partition or INVALID.
+ BlueNode asBlueNodeUnsafe(const Node&) const { return BlueNode(); }
+
+ /// \brief Converts the node to red node object.
+ ///
+ /// This function converts safely the node to red node
+ /// object. If the node is not from the red partition, then it
+ /// returns INVALID.
+ RedNode asRedNode(const Node&) const { return RedNode(); }
+
+ /// \brief Converts the node to blue node object.
+ ///
+ /// This function converts unsafely the node to blue node
+ /// object. If the node is not from the blue partition, then it
+ /// returns INVALID.
+ BlueNode asBlueNode(const Node&) const { return BlueNode(); }
+
+ template <typename _BpGraph>
+ struct Constraints {
+ typedef typename _BpGraph::Node Node;
+ typedef typename _BpGraph::RedNode RedNode;
+ typedef typename _BpGraph::BlueNode BlueNode;
+ typedef typename _BpGraph::Arc Arc;
+ typedef typename _BpGraph::Edge Edge;
+
+ void constraints() {
+ checkConcept<BaseGraphComponent, _BpGraph>();
+ checkConcept<GraphItem<'n'>, RedNode>();
+ checkConcept<GraphItem<'n'>, BlueNode>();
+ {
+ Node n;
+ RedNode rn;
+ BlueNode bn;
+ Node rnan = rn;
+ Node bnan = bn;
+ Edge e;
+ bool b;
+ b = bpgraph.red(rnan);
+ b = bpgraph.blue(bnan);
+ rn = bpgraph.redNode(e);
+ bn = bpgraph.blueNode(e);
+ rn = bpgraph.asRedNodeUnsafe(rnan);
+ bn = bpgraph.asBlueNodeUnsafe(bnan);
+ rn = bpgraph.asRedNode(rnan);
+ bn = bpgraph.asBlueNode(bnan);
+ ::lemon::ignore_unused_variable_warning(b);
+ }
+ }
+
+ const _BpGraph& bpgraph;
+ };
+
+ };
+
+ /// \brief Skeleton class for \e idable directed graphs.
+ ///
+ /// This class describes the interface of \e idable directed graphs.
+ /// It extends \ref BaseDigraphComponent with the core ID functions.
+ /// The ids of the items must be unique and immutable.
+ /// This concept is part of the Digraph concept.
+ template <typename BAS = BaseDigraphComponent>
+ class IDableDigraphComponent : public BAS {
+ public:
+
+ typedef BAS Base;
+ typedef typename Base::Node Node;
+ typedef typename Base::Arc Arc;
+
+ /// \brief Return a unique integer id for the given node.
+ ///
+ /// This function returns a unique integer id for the given node.
+ int id(const Node&) const { return -1; }
+
+ /// \brief Return the node by its unique id.
+ ///
+ /// This function returns the node by its unique id.
+ /// If the digraph does not contain a node with the given id,
+ /// then the result of the function is undefined.
+ Node nodeFromId(int) const { return INVALID; }
+
+ /// \brief Return a unique integer id for the given arc.
+ ///
+ /// This function returns a unique integer id for the given arc.
+ int id(const Arc&) const { return -1; }
+
+ /// \brief Return the arc by its unique id.
+ ///
+ /// This function returns the arc by its unique id.
+ /// If the digraph does not contain an arc with the given id,
+ /// then the result of the function is undefined.
+ Arc arcFromId(int) const { return INVALID; }
+
+ /// \brief Return an integer greater or equal to the maximum
+ /// node id.
+ ///
+ /// This function returns an integer greater or equal to the
+ /// maximum node id.
+ int maxNodeId() const { return -1; }
+
+ /// \brief Return an integer greater or equal to the maximum
+ /// arc id.
+ ///
+ /// This function returns an integer greater or equal to the
+ /// maximum arc id.
+ int maxArcId() const { return -1; }
+
+ template <typename _Digraph>
+ struct Constraints {
+
+ void constraints() {
+ checkConcept<Base, _Digraph >();
+ typename _Digraph::Node node;
+ node=INVALID;
+ int nid = digraph.id(node);
+ nid = digraph.id(node);
+ node = digraph.nodeFromId(nid);
+ typename _Digraph::Arc arc;
+ arc=INVALID;
+ int eid = digraph.id(arc);
+ eid = digraph.id(arc);
+ arc = digraph.arcFromId(eid);
+
+ nid = digraph.maxNodeId();
+ ::lemon::ignore_unused_variable_warning(nid);
+ eid = digraph.maxArcId();
+ ::lemon::ignore_unused_variable_warning(eid);
+ }
+
+ const _Digraph& digraph;
+ Constraints() {}
+ };
+ };
+
+ /// \brief Skeleton class for \e idable undirected graphs.
+ ///
+ /// This class describes the interface of \e idable undirected
+ /// graphs. It extends \ref IDableDigraphComponent with the core ID
+ /// functions of undirected graphs.
+ /// The ids of the items must be unique and immutable.
+ /// This concept is part of the Graph concept.
+ template <typename BAS = BaseGraphComponent>
+ class IDableGraphComponent : public IDableDigraphComponent<BAS> {
+ public:
+
+ typedef BAS Base;
+ typedef typename Base::Edge Edge;
+
+ using IDableDigraphComponent<Base>::id;
+
+ /// \brief Return a unique integer id for the given edge.
+ ///
+ /// This function returns a unique integer id for the given edge.
+ int id(const Edge&) const { return -1; }
+
+ /// \brief Return the edge by its unique id.
+ ///
+ /// This function returns the edge by its unique id.
+ /// If the graph does not contain an edge with the given id,
+ /// then the result of the function is undefined.
+ Edge edgeFromId(int) const { return INVALID; }
+
+ /// \brief Return an integer greater or equal to the maximum
+ /// edge id.
+ ///
+ /// This function returns an integer greater or equal to the
+ /// maximum edge id.
+ int maxEdgeId() const { return -1; }
+
+ template <typename _Graph>
+ struct Constraints {
+
+ void constraints() {
+ checkConcept<IDableDigraphComponent<Base>, _Graph >();
+ typename _Graph::Edge edge;
+ int ueid = graph.id(edge);
+ ueid = graph.id(edge);
+ edge = graph.edgeFromId(ueid);
+ ueid = graph.maxEdgeId();
+ ::lemon::ignore_unused_variable_warning(ueid);
+ }
+
+ const _Graph& graph;
+ Constraints() {}
+ };
+ };
+
+ /// \brief Skeleton class for \e idable undirected bipartite graphs.
+ ///
+ /// This class describes the interface of \e idable undirected
+ /// bipartite graphs. It extends \ref IDableGraphComponent with
+ /// the core ID functions of undirected bipartite graphs. Beside
+ /// the regular node ids, this class also provides ids within the
+ /// the red and blue sets of the nodes. This concept is part of
+ /// the BpGraph concept.
+ template <typename BAS = BaseBpGraphComponent>
+ class IDableBpGraphComponent : public IDableGraphComponent<BAS> {
+ public:
+
+ typedef BAS Base;
+ typedef IDableGraphComponent<BAS> Parent;
+ typedef typename Base::Node Node;
+ typedef typename Base::RedNode RedNode;
+ typedef typename Base::BlueNode BlueNode;
+
+ using Parent::id;
+
+ /// \brief Return a unique integer id for the given node in the red set.
+ ///
+ /// Return a unique integer id for the given node in the red set.
+ int id(const RedNode&) const { return -1; }
+
+ /// \brief Return a unique integer id for the given node in the blue set.
+ ///
+ /// Return a unique integer id for the given node in the blue set.
+ int id(const BlueNode&) const { return -1; }
+
+ /// \brief Return an integer greater or equal to the maximum
+ /// node id in the red set.
+ ///
+ /// Return an integer greater or equal to the maximum
+ /// node id in the red set.
+ int maxRedId() const { return -1; }
+
+ /// \brief Return an integer greater or equal to the maximum
+ /// node id in the blue set.
+ ///
+ /// Return an integer greater or equal to the maximum
+ /// node id in the blue set.
+ int maxBlueId() const { return -1; }
+
+ template <typename _BpGraph>
+ struct Constraints {
+
+ void constraints() {
+ checkConcept<IDableGraphComponent<Base>, _BpGraph>();
+ typename _BpGraph::Node node;
+ typename _BpGraph::RedNode red;
+ typename _BpGraph::BlueNode blue;
+ int rid = bpgraph.id(red);
+ int bid = bpgraph.id(blue);
+ rid = bpgraph.maxRedId();
+ bid = bpgraph.maxBlueId();
+ ::lemon::ignore_unused_variable_warning(rid);
+ ::lemon::ignore_unused_variable_warning(bid);
+ }
+
+ const _BpGraph& bpgraph;
+ };
+ };
+
+ /// \brief Concept class for \c NodeIt, \c ArcIt and \c EdgeIt types.
+ ///
+ /// This class describes the concept of \c NodeIt, \c ArcIt and
+ /// \c EdgeIt subtypes of digraph and graph types.
+ template <typename GR, typename Item>
+ class GraphItemIt : public Item {
+ public:
+ /// \brief Default constructor.
+ ///
+ /// Default constructor.
+ /// \warning The default constructor is not required to set
+ /// the iterator to some well-defined value. So you should consider it
+ /// as uninitialized.
+ GraphItemIt() {}
+
+ /// \brief Copy constructor.
+ ///
+ /// Copy constructor.
+ GraphItemIt(const GraphItemIt& it) : Item(it) {}
+
+ /// \brief Constructor that sets the iterator to the first item.
+ ///
+ /// Constructor that sets the iterator to the first item.
+ explicit GraphItemIt(const GR&) {}
+
+ /// \brief Constructor for conversion from \c INVALID.
+ ///
+ /// Constructor for conversion from \c INVALID.
+ /// It initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ GraphItemIt(Invalid) {}
+
+ /// \brief Assignment operator.
+ ///
+ /// Assignment operator for the iterator.
+ GraphItemIt& operator=(const GraphItemIt&) { return *this; }
+
+ /// \brief Increment the iterator.
+ ///
+ /// This operator increments the iterator, i.e. assigns it to the
+ /// next item.
+ GraphItemIt& operator++() { return *this; }
+
+ /// \brief Equality operator
+ ///
+ /// Equality operator.
+ /// Two iterators are equal if and only if they point to the
+ /// same object or both are invalid.
+ bool operator==(const GraphItemIt&) const { return true;}
+
+ /// \brief Inequality operator
+ ///
+ /// Inequality operator.
+ /// Two iterators are equal if and only if they point to the
+ /// same object or both are invalid.
+ bool operator!=(const GraphItemIt&) const { return true;}
+
+ template<typename _GraphItemIt>
+ struct Constraints {
+ void constraints() {
+ checkConcept<GraphItem<>, _GraphItemIt>();
+ _GraphItemIt it1(g);
+ _GraphItemIt it2;
+ _GraphItemIt it3 = it1;
+ _GraphItemIt it4 = INVALID;
+ ::lemon::ignore_unused_variable_warning(it3);
+ ::lemon::ignore_unused_variable_warning(it4);
+
+ it2 = ++it1;
+ ++it2 = it1;
+ ++(++it1);
+
+ Item bi = it1;
+ bi = it2;
+ }
+ const GR& g;
+ Constraints() {}
+ };
+ };
+
+ /// \brief Concept class for \c InArcIt, \c OutArcIt and
+ /// \c IncEdgeIt types.
+ ///
+ /// This class describes the concept of \c InArcIt, \c OutArcIt
+ /// and \c IncEdgeIt subtypes of digraph and graph types.
+ ///
+ /// \note Since these iterator classes do not inherit from the same
+ /// base class, there is an additional template parameter (selector)
+ /// \c sel. For \c InArcIt you should instantiate it with character
+ /// \c 'i', for \c OutArcIt with \c 'o' and for \c IncEdgeIt with \c 'e'.
+ template <typename GR,
+ typename Item = typename GR::Arc,
+ typename Base = typename GR::Node,
+ char sel = '0'>
+ class GraphIncIt : public Item {
+ public:
+ /// \brief Default constructor.
+ ///
+ /// Default constructor.
+ /// \warning The default constructor is not required to set
+ /// the iterator to some well-defined value. So you should consider it
+ /// as uninitialized.
+ GraphIncIt() {}
+
+ /// \brief Copy constructor.
+ ///
+ /// Copy constructor.
+ GraphIncIt(const GraphIncIt& it) : Item(it) {}
+
+ /// \brief Constructor that sets the iterator to the first
+ /// incoming or outgoing arc.
+ ///
+ /// Constructor that sets the iterator to the first arc
+ /// incoming to or outgoing from the given node.
+ explicit GraphIncIt(const GR&, const Base&) {}
+
+ /// \brief Constructor for conversion from \c INVALID.
+ ///
+ /// Constructor for conversion from \c INVALID.
+ /// It initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ GraphIncIt(Invalid) {}
+
+ /// \brief Assignment operator.
+ ///
+ /// Assignment operator for the iterator.
+ GraphIncIt& operator=(const GraphIncIt&) { return *this; }
+
+ /// \brief Increment the iterator.
+ ///
+ /// This operator increments the iterator, i.e. assigns it to the
+ /// next arc incoming to or outgoing from the given node.
+ GraphIncIt& operator++() { return *this; }
+
+ /// \brief Equality operator
+ ///
+ /// Equality operator.
+ /// Two iterators are equal if and only if they point to the
+ /// same object or both are invalid.
+ bool operator==(const GraphIncIt&) const { return true;}
+
+ /// \brief Inequality operator
+ ///
+ /// Inequality operator.
+ /// Two iterators are equal if and only if they point to the
+ /// same object or both are invalid.
+ bool operator!=(const GraphIncIt&) const { return true;}
+
+ template <typename _GraphIncIt>
+ struct Constraints {
+ void constraints() {
+ checkConcept<GraphItem<sel>, _GraphIncIt>();
+ _GraphIncIt it1(graph, node);
+ _GraphIncIt it2;
+ _GraphIncIt it3 = it1;
+ _GraphIncIt it4 = INVALID;
+ ::lemon::ignore_unused_variable_warning(it3);
+ ::lemon::ignore_unused_variable_warning(it4);
+
+ it2 = ++it1;
+ ++it2 = it1;
+ ++(++it1);
+ Item e = it1;
+ e = it2;
+ }
+ const Base& node;
+ const GR& graph;
+ Constraints() {}
+ };
+ };
+
+ /// \brief Skeleton class for iterable directed graphs.
+ ///
+ /// This class describes the interface of iterable directed
+ /// graphs. It extends \ref BaseDigraphComponent with the core
+ /// iterable interface.
+ /// This concept is part of the Digraph concept.
+ template <typename BAS = BaseDigraphComponent>
+ class IterableDigraphComponent : public BAS {
+
+ public:
+
+ typedef BAS Base;
+ typedef typename Base::Node Node;
+ typedef typename Base::Arc Arc;
+
+ typedef IterableDigraphComponent Digraph;
+
+ /// \name Base Iteration
+ ///
+ /// This interface provides functions for iteration on digraph items.
+ ///
+ /// @{
+
+ /// \brief Return the first node.
+ ///
+ /// This function gives back the first node in the iteration order.
+ void first(Node&) const {}
+
+ /// \brief Return the next node.
+ ///
+ /// This function gives back the next node in the iteration order.
+ void next(Node&) const {}
+
+ /// \brief Return the first arc.
+ ///
+ /// This function gives back the first arc in the iteration order.
+ void first(Arc&) const {}
+
+ /// \brief Return the next arc.
+ ///
+ /// This function gives back the next arc in the iteration order.
+ void next(Arc&) const {}
+
+ /// \brief Return the first arc incoming to the given node.
+ ///
+ /// This function gives back the first arc incoming to the
+ /// given node.
+ void firstIn(Arc&, const Node&) const {}
+
+ /// \brief Return the next arc incoming to the given node.
+ ///
+ /// This function gives back the next arc incoming to the
+ /// given node.
+ void nextIn(Arc&) const {}
+
+ /// \brief Return the first arc outgoing form the given node.
+ ///
+ /// This function gives back the first arc outgoing form the
+ /// given node.
+ void firstOut(Arc&, const Node&) const {}
+
+ /// \brief Return the next arc outgoing form the given node.
+ ///
+ /// This function gives back the next arc outgoing form the
+ /// given node.
+ void nextOut(Arc&) const {}
+
+ /// @}
+
+ /// \name Class Based Iteration
+ ///
+ /// This interface provides iterator classes for digraph items.
+ ///
+ /// @{
+
+ /// \brief This iterator goes through each node.
+ ///
+ /// This iterator goes through each node.
+ ///
+ typedef GraphItemIt<Digraph, Node> NodeIt;
+
+ /// \brief This iterator goes through each arc.
+ ///
+ /// This iterator goes through each arc.
+ ///
+ typedef GraphItemIt<Digraph, Arc> ArcIt;
+
+ /// \brief This iterator goes trough the incoming arcs of a node.
+ ///
+ /// This iterator goes trough the \e incoming arcs of a certain node
+ /// of a digraph.
+ typedef GraphIncIt<Digraph, Arc, Node, 'i'> InArcIt;
+
+ /// \brief This iterator goes trough the outgoing arcs of a node.
+ ///
+ /// This iterator goes trough the \e outgoing arcs of a certain node
+ /// of a digraph.
+ typedef GraphIncIt<Digraph, Arc, Node, 'o'> OutArcIt;
+
+ /// \brief The base node of the iterator.
+ ///
+ /// This function gives back the base node of the iterator.
+ /// It is always the target node of the pointed arc.
+ Node baseNode(const InArcIt&) const { return INVALID; }
+
+ /// \brief The running node of the iterator.
+ ///
+ /// This function gives back the running node of the iterator.
+ /// It is always the source node of the pointed arc.
+ Node runningNode(const InArcIt&) const { return INVALID; }
+
+ /// \brief The base node of the iterator.
+ ///
+ /// This function gives back the base node of the iterator.
+ /// It is always the source node of the pointed arc.
+ Node baseNode(const OutArcIt&) const { return INVALID; }
+
+ /// \brief The running node of the iterator.
+ ///
+ /// This function gives back the running node of the iterator.
+ /// It is always the target node of the pointed arc.
+ Node runningNode(const OutArcIt&) const { return INVALID; }
+
+ /// @}
+
+ template <typename _Digraph>
+ struct Constraints {
+ void constraints() {
+ checkConcept<Base, _Digraph>();
+
+ {
+ typename _Digraph::Node node(INVALID);
+ typename _Digraph::Arc arc(INVALID);
+ {
+ digraph.first(node);
+ digraph.next(node);
+ }
+ {
+ digraph.first(arc);
+ digraph.next(arc);
+ }
+ {
+ digraph.firstIn(arc, node);
+ digraph.nextIn(arc);
+ }
+ {
+ digraph.firstOut(arc, node);
+ digraph.nextOut(arc);
+ }
+ }
+
+ {
+ checkConcept<GraphItemIt<_Digraph, typename _Digraph::Arc>,
+ typename _Digraph::ArcIt >();
+ checkConcept<GraphItemIt<_Digraph, typename _Digraph::Node>,
+ typename _Digraph::NodeIt >();
+ checkConcept<GraphIncIt<_Digraph, typename _Digraph::Arc,
+ typename _Digraph::Node, 'i'>, typename _Digraph::InArcIt>();
+ checkConcept<GraphIncIt<_Digraph, typename _Digraph::Arc,
+ typename _Digraph::Node, 'o'>, typename _Digraph::OutArcIt>();
+
+ typename _Digraph::Node n;
+ const typename _Digraph::InArcIt iait(INVALID);
+ const typename _Digraph::OutArcIt oait(INVALID);
+ n = digraph.baseNode(iait);
+ n = digraph.runningNode(iait);
+ n = digraph.baseNode(oait);
+ n = digraph.runningNode(oait);
+ ::lemon::ignore_unused_variable_warning(n);
+ }
+ }
+
+ const _Digraph& digraph;
+ Constraints() {}
+ };
+ };
+
+ /// \brief Skeleton class for iterable undirected graphs.
+ ///
+ /// This class describes the interface of iterable undirected
+ /// graphs. It extends \ref IterableDigraphComponent with the core
+ /// iterable interface of undirected graphs.
+ /// This concept is part of the Graph concept.
+ template <typename BAS = BaseGraphComponent>
+ class IterableGraphComponent : public IterableDigraphComponent<BAS> {
+ public:
+
+ typedef BAS Base;
+ typedef typename Base::Node Node;
+ typedef typename Base::Arc Arc;
+ typedef typename Base::Edge Edge;
+
+
+ typedef IterableGraphComponent Graph;
+
+ /// \name Base Iteration
+ ///
+ /// This interface provides functions for iteration on edges.
+ ///
+ /// @{
+
+ using IterableDigraphComponent<Base>::first;
+ using IterableDigraphComponent<Base>::next;
+
+ /// \brief Return the first edge.
+ ///
+ /// This function gives back the first edge in the iteration order.
+ void first(Edge&) const {}
+
+ /// \brief Return the next edge.
+ ///
+ /// This function gives back the next edge in the iteration order.
+ void next(Edge&) const {}
+
+ /// \brief Return the first edge incident to the given node.
+ ///
+ /// This function gives back the first edge incident to the given
+ /// node. The bool parameter gives back the direction for which the
+ /// source node of the directed arc representing the edge is the
+ /// given node.
+ void firstInc(Edge&, bool&, const Node&) const {}
+
+ /// \brief Gives back the next of the edges from the
+ /// given node.
+ ///
+ /// This function gives back the next edge incident to the given
+ /// node. The bool parameter should be used as \c firstInc() use it.
+ void nextInc(Edge&, bool&) const {}
+
+ using IterableDigraphComponent<Base>::baseNode;
+ using IterableDigraphComponent<Base>::runningNode;
+
+ /// @}
+
+ /// \name Class Based Iteration
+ ///
+ /// This interface provides iterator classes for edges.
+ ///
+ /// @{
+
+ /// \brief This iterator goes through each edge.
+ ///
+ /// This iterator goes through each edge.
+ typedef GraphItemIt<Graph, Edge> EdgeIt;
+
+ /// \brief This iterator goes trough the incident edges of a
+ /// node.
+ ///
+ /// This iterator goes trough the incident edges of a certain
+ /// node of a graph.
+ typedef GraphIncIt<Graph, Edge, Node, 'e'> IncEdgeIt;
+
+ /// \brief The base node of the iterator.
+ ///
+ /// This function gives back the base node of the iterator.
+ Node baseNode(const IncEdgeIt&) const { return INVALID; }
+
+ /// \brief The running node of the iterator.
+ ///
+ /// This function gives back the running node of the iterator.
+ Node runningNode(const IncEdgeIt&) const { return INVALID; }
+
+ /// @}
+
+ template <typename _Graph>
+ struct Constraints {
+ void constraints() {
+ checkConcept<IterableDigraphComponent<Base>, _Graph>();
+
+ {
+ typename _Graph::Node node(INVALID);
+ typename _Graph::Edge edge(INVALID);
+ bool dir;
+ {
+ graph.first(edge);
+ graph.next(edge);
+ }
+ {
+ graph.firstInc(edge, dir, node);
+ graph.nextInc(edge, dir);
+ }
+
+ }
+
+ {
+ checkConcept<GraphItemIt<_Graph, typename _Graph::Edge>,
+ typename _Graph::EdgeIt >();
+ checkConcept<GraphIncIt<_Graph, typename _Graph::Edge,
+ typename _Graph::Node, 'e'>, typename _Graph::IncEdgeIt>();
+
+ typename _Graph::Node n;
+ const typename _Graph::IncEdgeIt ieit(INVALID);
+ n = graph.baseNode(ieit);
+ n = graph.runningNode(ieit);
+ }
+ }
+
+ const _Graph& graph;
+ Constraints() {}
+ };
+ };
+
+ /// \brief Skeleton class for iterable undirected bipartite graphs.
+ ///
+ /// This class describes the interface of iterable undirected
+ /// bipartite graphs. It extends \ref IterableGraphComponent with
+ /// the core iterable interface of undirected bipartite graphs.
+ /// This concept is part of the BpGraph concept.
+ template <typename BAS = BaseBpGraphComponent>
+ class IterableBpGraphComponent : public IterableGraphComponent<BAS> {
+ public:
+
+ typedef BAS Base;
+ typedef typename Base::Node Node;
+ typedef typename Base::RedNode RedNode;
+ typedef typename Base::BlueNode BlueNode;
+ typedef typename Base::Arc Arc;
+ typedef typename Base::Edge Edge;
+
+ typedef IterableBpGraphComponent BpGraph;
+
+ using IterableGraphComponent<BAS>::first;
+ using IterableGraphComponent<BAS>::next;
+
+ /// \name Base Iteration
+ ///
+ /// This interface provides functions for iteration on red and blue nodes.
+ ///
+ /// @{
+
+ /// \brief Return the first red node.
+ ///
+ /// This function gives back the first red node in the iteration order.
+ void first(RedNode&) const {}
+
+ /// \brief Return the next red node.
+ ///
+ /// This function gives back the next red node in the iteration order.
+ void next(RedNode&) const {}
+
+ /// \brief Return the first blue node.
+ ///
+ /// This function gives back the first blue node in the iteration order.
+ void first(BlueNode&) const {}
+
+ /// \brief Return the next blue node.
+ ///
+ /// This function gives back the next blue node in the iteration order.
+ void next(BlueNode&) const {}
+
+
+ /// @}
+
+ /// \name Class Based Iteration
+ ///
+ /// This interface provides iterator classes for red and blue nodes.
+ ///
+ /// @{
+
+ /// \brief This iterator goes through each red node.
+ ///
+ /// This iterator goes through each red node.
+ typedef GraphItemIt<BpGraph, RedNode> RedNodeIt;
+
+ /// \brief This iterator goes through each blue node.
+ ///
+ /// This iterator goes through each blue node.
+ typedef GraphItemIt<BpGraph, BlueNode> BlueNodeIt;
+
+ /// @}
+
+ template <typename _BpGraph>
+ struct Constraints {
+ void constraints() {
+ checkConcept<IterableGraphComponent<Base>, _BpGraph>();
+
+ typename _BpGraph::RedNode rn(INVALID);
+ bpgraph.first(rn);
+ bpgraph.next(rn);
+ typename _BpGraph::BlueNode bn(INVALID);
+ bpgraph.first(bn);
+ bpgraph.next(bn);
+
+ checkConcept<GraphItemIt<_BpGraph, typename _BpGraph::RedNode>,
+ typename _BpGraph::RedNodeIt>();
+ checkConcept<GraphItemIt<_BpGraph, typename _BpGraph::BlueNode>,
+ typename _BpGraph::BlueNodeIt>();
+ }
+
+ const _BpGraph& bpgraph;
+ };
+ };
+
+ /// \brief Skeleton class for alterable directed graphs.
+ ///
+ /// This class describes the interface of alterable directed
+ /// graphs. It extends \ref BaseDigraphComponent with the alteration
+ /// notifier interface. It implements
+ /// an observer-notifier pattern for each digraph item. More
+ /// obsevers can be registered into the notifier and whenever an
+ /// alteration occured in the digraph all the observers will be
+ /// notified about it.
+ template <typename BAS = BaseDigraphComponent>
+ class AlterableDigraphComponent : public BAS {
+ public:
+
+ typedef BAS Base;
+ typedef typename Base::Node Node;
+ typedef typename Base::Arc Arc;
+
+
+ /// Node alteration notifier class.
+ typedef AlterationNotifier<AlterableDigraphComponent, Node>
+ NodeNotifier;
+ /// Arc alteration notifier class.
+ typedef AlterationNotifier<AlterableDigraphComponent, Arc>
+ ArcNotifier;
+
+ mutable NodeNotifier node_notifier;
+ mutable ArcNotifier arc_notifier;
+
+ /// \brief Return the node alteration notifier.
+ ///
+ /// This function gives back the node alteration notifier.
+ NodeNotifier& notifier(Node) const {
+ return node_notifier;
+ }
+
+ /// \brief Return the arc alteration notifier.
+ ///
+ /// This function gives back the arc alteration notifier.
+ ArcNotifier& notifier(Arc) const {
+ return arc_notifier;
+ }
+
+ template <typename _Digraph>
+ struct Constraints {
+ void constraints() {
+ checkConcept<Base, _Digraph>();
+ typename _Digraph::NodeNotifier& nn
+ = digraph.notifier(typename _Digraph::Node());
+
+ typename _Digraph::ArcNotifier& en
+ = digraph.notifier(typename _Digraph::Arc());
+
+ ::lemon::ignore_unused_variable_warning(nn);
+ ::lemon::ignore_unused_variable_warning(en);
+ }
+
+ const _Digraph& digraph;
+ Constraints() {}
+ };
+ };
+
+ /// \brief Skeleton class for alterable undirected graphs.
+ ///
+ /// This class describes the interface of alterable undirected
+ /// graphs. It extends \ref AlterableDigraphComponent with the alteration
+ /// notifier interface of undirected graphs. It implements
+ /// an observer-notifier pattern for the edges. More
+ /// obsevers can be registered into the notifier and whenever an
+ /// alteration occured in the graph all the observers will be
+ /// notified about it.
+ template <typename BAS = BaseGraphComponent>
+ class AlterableGraphComponent : public AlterableDigraphComponent<BAS> {
+ public:
+
+ typedef BAS Base;
+ typedef AlterableDigraphComponent<Base> Parent;
+ typedef typename Base::Edge Edge;
+
+
+ /// Edge alteration notifier class.
+ typedef AlterationNotifier<AlterableGraphComponent, Edge>
+ EdgeNotifier;
+
+ mutable EdgeNotifier edge_notifier;
+
+ using Parent::notifier;
+
+ /// \brief Return the edge alteration notifier.
+ ///
+ /// This function gives back the edge alteration notifier.
+ EdgeNotifier& notifier(Edge) const {
+ return edge_notifier;
+ }
+
+ template <typename _Graph>
+ struct Constraints {
+ void constraints() {
+ checkConcept<AlterableDigraphComponent<Base>, _Graph>();
+ typename _Graph::EdgeNotifier& uen
+ = graph.notifier(typename _Graph::Edge());
+ ::lemon::ignore_unused_variable_warning(uen);
+ }
+
+ const _Graph& graph;
+ Constraints() {}
+ };
+ };
+
+ /// \brief Skeleton class for alterable undirected bipartite graphs.
+ ///
+ /// This class describes the interface of alterable undirected
+ /// bipartite graphs. It extends \ref AlterableGraphComponent with
+ /// the alteration notifier interface of bipartite graphs. It
+ /// implements an observer-notifier pattern for the red and blue
+ /// nodes. More obsevers can be registered into the notifier and
+ /// whenever an alteration occured in the graph all the observers
+ /// will be notified about it.
+ template <typename BAS = BaseBpGraphComponent>
+ class AlterableBpGraphComponent : public AlterableGraphComponent<BAS> {
+ public:
+
+ typedef BAS Base;
+ typedef AlterableGraphComponent<Base> Parent;
+ typedef typename Base::RedNode RedNode;
+ typedef typename Base::BlueNode BlueNode;
+
+
+ /// Red node alteration notifier class.
+ typedef AlterationNotifier<AlterableBpGraphComponent, RedNode>
+ RedNodeNotifier;
+
+ /// Blue node alteration notifier class.
+ typedef AlterationNotifier<AlterableBpGraphComponent, BlueNode>
+ BlueNodeNotifier;
+
+ mutable RedNodeNotifier red_node_notifier;
+ mutable BlueNodeNotifier blue_node_notifier;
+
+ using Parent::notifier;
+
+ /// \brief Return the red node alteration notifier.
+ ///
+ /// This function gives back the red node alteration notifier.
+ RedNodeNotifier& notifier(RedNode) const {
+ return red_node_notifier;
+ }
+
+ /// \brief Return the blue node alteration notifier.
+ ///
+ /// This function gives back the blue node alteration notifier.
+ BlueNodeNotifier& notifier(BlueNode) const {
+ return blue_node_notifier;
+ }
+
+ template <typename _BpGraph>
+ struct Constraints {
+ void constraints() {
+ checkConcept<AlterableGraphComponent<Base>, _BpGraph>();
+ typename _BpGraph::RedNodeNotifier& rnn
+ = bpgraph.notifier(typename _BpGraph::RedNode());
+ typename _BpGraph::BlueNodeNotifier& bnn
+ = bpgraph.notifier(typename _BpGraph::BlueNode());
+ ::lemon::ignore_unused_variable_warning(rnn);
+ ::lemon::ignore_unused_variable_warning(bnn);
+ }
+
+ const _BpGraph& bpgraph;
+ };
+ };
+
+ /// \brief Concept class for standard graph maps.
+ ///
+ /// This class describes the concept of standard graph maps, i.e.
+ /// the \c NodeMap, \c ArcMap and \c EdgeMap subtypes of digraph and
+ /// graph types, which can be used for associating data to graph items.
+ /// The standard graph maps must conform to the ReferenceMap concept.
+ template <typename GR, typename K, typename V>
+ class GraphMap : public ReferenceMap<K, V, V&, const V&> {
+ typedef ReferenceMap<K, V, V&, const V&> Parent;
+
+ public:
+
+ /// The key type of the map.
+ typedef K Key;
+ /// The value type of the map.
+ typedef V Value;
+ /// The reference type of the map.
+ typedef Value& Reference;
+ /// The const reference type of the map.
+ typedef const Value& ConstReference;
+
+ // The reference map tag.
+ typedef True ReferenceMapTag;
+
+ /// \brief Construct a new map.
+ ///
+ /// Construct a new map for the graph.
+ explicit GraphMap(const GR&) {}
+ /// \brief Construct a new map with default value.
+ ///
+ /// Construct a new map for the graph and initalize the values.
+ GraphMap(const GR&, const Value&) {}
+
+ private:
+ /// \brief Copy constructor.
+ ///
+ /// Copy Constructor.
+ GraphMap(const GraphMap&) : Parent() {}
+
+ /// \brief Assignment operator.
+ ///
+ /// Assignment operator. It does not mofify the underlying graph,
+ /// it just iterates on the current item set and set the map
+ /// with the value returned by the assigned map.
+ template <typename CMap>
+ GraphMap& operator=(const CMap&) {
+ checkConcept<ReadMap<Key, Value>, CMap>();
+ return *this;
+ }
+
+ public:
+ template<typename _Map>
+ struct Constraints {
+ void constraints() {
+ checkConcept
+ <ReferenceMap<Key, Value, Value&, const Value&>, _Map>();
+ _Map m1(g);
+ _Map m2(g,t);
+
+ // Copy constructor
+ // _Map m3(m);
+
+ // Assignment operator
+ // ReadMap<Key, Value> cmap;
+ // m3 = cmap;
+
+ ::lemon::ignore_unused_variable_warning(m1);
+ ::lemon::ignore_unused_variable_warning(m2);
+ // ::lemon::ignore_unused_variable_warning(m3);
+ }
+
+ const _Map &m;
+ const GR &g;
+ const typename GraphMap::Value &t;
+ Constraints() {}
+ };
+
+ };
+
+ /// \brief Skeleton class for mappable directed graphs.
+ ///
+ /// This class describes the interface of mappable directed graphs.
+ /// It extends \ref BaseDigraphComponent with the standard digraph
+ /// map classes, namely \c NodeMap and \c ArcMap.
+ /// This concept is part of the Digraph concept.
+ template <typename BAS = BaseDigraphComponent>
+ class MappableDigraphComponent : public BAS {
+ public:
+
+ typedef BAS Base;
+ typedef typename Base::Node Node;
+ typedef typename Base::Arc Arc;
+
+ typedef MappableDigraphComponent Digraph;
+
+ /// \brief Standard graph map for the nodes.
+ ///
+ /// Standard graph map for the nodes.
+ /// It conforms to the ReferenceMap concept.
+ template <typename V>
+ class NodeMap : public GraphMap<MappableDigraphComponent, Node, V> {
+ typedef GraphMap<MappableDigraphComponent, Node, V> Parent;
+
+ public:
+ /// \brief Construct a new map.
+ ///
+ /// Construct a new map for the digraph.
+ explicit NodeMap(const MappableDigraphComponent& digraph)
+ : Parent(digraph) {}
+
+ /// \brief Construct a new map with default value.
+ ///
+ /// Construct a new map for the digraph and initalize the values.
+ NodeMap(const MappableDigraphComponent& digraph, const V& value)
+ : Parent(digraph, value) {}
+
+ private:
+ /// \brief Copy constructor.
+ ///
+ /// Copy Constructor.
+ NodeMap(const NodeMap& nm) : Parent(nm) {}
+
+ /// \brief Assignment operator.
+ ///
+ /// Assignment operator.
+ template <typename CMap>
+ NodeMap& operator=(const CMap&) {
+ checkConcept<ReadMap<Node, V>, CMap>();
+ return *this;
+ }
+
+ };
+
+ /// \brief Standard graph map for the arcs.
+ ///
+ /// Standard graph map for the arcs.
+ /// It conforms to the ReferenceMap concept.
+ template <typename V>
+ class ArcMap : public GraphMap<MappableDigraphComponent, Arc, V> {
+ typedef GraphMap<MappableDigraphComponent, Arc, V> Parent;
+
+ public:
+ /// \brief Construct a new map.
+ ///
+ /// Construct a new map for the digraph.
+ explicit ArcMap(const MappableDigraphComponent& digraph)
+ : Parent(digraph) {}
+
+ /// \brief Construct a new map with default value.
+ ///
+ /// Construct a new map for the digraph and initalize the values.
+ ArcMap(const MappableDigraphComponent& digraph, const V& value)
+ : Parent(digraph, value) {}
+
+ private:
+ /// \brief Copy constructor.
+ ///
+ /// Copy Constructor.
+ ArcMap(const ArcMap& nm) : Parent(nm) {}
+
+ /// \brief Assignment operator.
+ ///
+ /// Assignment operator.
+ template <typename CMap>
+ ArcMap& operator=(const CMap&) {
+ checkConcept<ReadMap<Arc, V>, CMap>();
+ return *this;
+ }
+
+ };
+
+
+ template <typename _Digraph>
+ struct Constraints {
+
+ struct Dummy {
+ int value;
+ Dummy() : value(0) {}
+ Dummy(int _v) : value(_v) {}
+ };
+
+ void constraints() {
+ checkConcept<Base, _Digraph>();
+ { // int map test
+ typedef typename _Digraph::template NodeMap<int> IntNodeMap;
+ checkConcept<GraphMap<_Digraph, typename _Digraph::Node, int>,
+ IntNodeMap >();
+ } { // bool map test
+ typedef typename _Digraph::template NodeMap<bool> BoolNodeMap;
+ checkConcept<GraphMap<_Digraph, typename _Digraph::Node, bool>,
+ BoolNodeMap >();
+ } { // Dummy map test
+ typedef typename _Digraph::template NodeMap<Dummy> DummyNodeMap;
+ checkConcept<GraphMap<_Digraph, typename _Digraph::Node, Dummy>,
+ DummyNodeMap >();
+ }
+
+ { // int map test
+ typedef typename _Digraph::template ArcMap<int> IntArcMap;
+ checkConcept<GraphMap<_Digraph, typename _Digraph::Arc, int>,
+ IntArcMap >();
+ } { // bool map test
+ typedef typename _Digraph::template ArcMap<bool> BoolArcMap;
+ checkConcept<GraphMap<_Digraph, typename _Digraph::Arc, bool>,
+ BoolArcMap >();
+ } { // Dummy map test
+ typedef typename _Digraph::template ArcMap<Dummy> DummyArcMap;
+ checkConcept<GraphMap<_Digraph, typename _Digraph::Arc, Dummy>,
+ DummyArcMap >();
+ }
+ }
+
+ const _Digraph& digraph;
+ Constraints() {}
+ };
+ };
+
+ /// \brief Skeleton class for mappable undirected graphs.
+ ///
+ /// This class describes the interface of mappable undirected graphs.
+ /// It extends \ref MappableDigraphComponent with the standard graph
+ /// map class for edges (\c EdgeMap).
+ /// This concept is part of the Graph concept.
+ template <typename BAS = BaseGraphComponent>
+ class MappableGraphComponent : public MappableDigraphComponent<BAS> {
+ public:
+
+ typedef BAS Base;
+ typedef typename Base::Edge Edge;
+
+ typedef MappableGraphComponent Graph;
+
+ /// \brief Standard graph map for the edges.
+ ///
+ /// Standard graph map for the edges.
+ /// It conforms to the ReferenceMap concept.
+ template <typename V>
+ class EdgeMap : public GraphMap<MappableGraphComponent, Edge, V> {
+ typedef GraphMap<MappableGraphComponent, Edge, V> Parent;
+
+ public:
+ /// \brief Construct a new map.
+ ///
+ /// Construct a new map for the graph.
+ explicit EdgeMap(const MappableGraphComponent& graph)
+ : Parent(graph) {}
+
+ /// \brief Construct a new map with default value.
+ ///
+ /// Construct a new map for the graph and initalize the values.
+ EdgeMap(const MappableGraphComponent& graph, const V& value)
+ : Parent(graph, value) {}
+
+ private:
+ /// \brief Copy constructor.
+ ///
+ /// Copy Constructor.
+ EdgeMap(const EdgeMap& nm) : Parent(nm) {}
+
+ /// \brief Assignment operator.
+ ///
+ /// Assignment operator.
+ template <typename CMap>
+ EdgeMap& operator=(const CMap&) {
+ checkConcept<ReadMap<Edge, V>, CMap>();
+ return *this;
+ }
+
+ };
+
+
+ template <typename _Graph>
+ struct Constraints {
+
+ struct Dummy {
+ int value;
+ Dummy() : value(0) {}
+ Dummy(int _v) : value(_v) {}
+ };
+
+ void constraints() {
+ checkConcept<MappableDigraphComponent<Base>, _Graph>();
+
+ { // int map test
+ typedef typename _Graph::template EdgeMap<int> IntEdgeMap;
+ checkConcept<GraphMap<_Graph, typename _Graph::Edge, int>,
+ IntEdgeMap >();
+ } { // bool map test
+ typedef typename _Graph::template EdgeMap<bool> BoolEdgeMap;
+ checkConcept<GraphMap<_Graph, typename _Graph::Edge, bool>,
+ BoolEdgeMap >();
+ } { // Dummy map test
+ typedef typename _Graph::template EdgeMap<Dummy> DummyEdgeMap;
+ checkConcept<GraphMap<_Graph, typename _Graph::Edge, Dummy>,
+ DummyEdgeMap >();
+ }
+ }
+
+ const _Graph& graph;
+ Constraints() {}
+ };
+ };
+
+ /// \brief Skeleton class for mappable undirected bipartite graphs.
+ ///
+ /// This class describes the interface of mappable undirected
+ /// bipartite graphs. It extends \ref MappableGraphComponent with
+ /// the standard graph map class for red and blue nodes (\c
+ /// RedNodeMap and BlueNodeMap). This concept is part of the
+ /// BpGraph concept.
+ template <typename BAS = BaseBpGraphComponent>
+ class MappableBpGraphComponent : public MappableGraphComponent<BAS> {
+ public:
+
+ typedef BAS Base;
+ typedef typename Base::Node Node;
+
+ typedef MappableBpGraphComponent BpGraph;
+
+ /// \brief Standard graph map for the red nodes.
+ ///
+ /// Standard graph map for the red nodes.
+ /// It conforms to the ReferenceMap concept.
+ template <typename V>
+ class RedNodeMap : public GraphMap<MappableBpGraphComponent, Node, V> {
+ typedef GraphMap<MappableBpGraphComponent, Node, V> Parent;
+
+ public:
+ /// \brief Construct a new map.
+ ///
+ /// Construct a new map for the graph.
+ explicit RedNodeMap(const MappableBpGraphComponent& graph)
+ : Parent(graph) {}
+
+ /// \brief Construct a new map with default value.
+ ///
+ /// Construct a new map for the graph and initalize the values.
+ RedNodeMap(const MappableBpGraphComponent& graph, const V& value)
+ : Parent(graph, value) {}
+
+ private:
+ /// \brief Copy constructor.
+ ///
+ /// Copy Constructor.
+ RedNodeMap(const RedNodeMap& nm) : Parent(nm) {}
+
+ /// \brief Assignment operator.
+ ///
+ /// Assignment operator.
+ template <typename CMap>
+ RedNodeMap& operator=(const CMap&) {
+ checkConcept<ReadMap<Node, V>, CMap>();
+ return *this;
+ }
+
+ };
+
+ /// \brief Standard graph map for the blue nodes.
+ ///
+ /// Standard graph map for the blue nodes.
+ /// It conforms to the ReferenceMap concept.
+ template <typename V>
+ class BlueNodeMap : public GraphMap<MappableBpGraphComponent, Node, V> {
+ typedef GraphMap<MappableBpGraphComponent, Node, V> Parent;
+
+ public:
+ /// \brief Construct a new map.
+ ///
+ /// Construct a new map for the graph.
+ explicit BlueNodeMap(const MappableBpGraphComponent& graph)
+ : Parent(graph) {}
+
+ /// \brief Construct a new map with default value.
+ ///
+ /// Construct a new map for the graph and initalize the values.
+ BlueNodeMap(const MappableBpGraphComponent& graph, const V& value)
+ : Parent(graph, value) {}
+
+ private:
+ /// \brief Copy constructor.
+ ///
+ /// Copy Constructor.
+ BlueNodeMap(const BlueNodeMap& nm) : Parent(nm) {}
+
+ /// \brief Assignment operator.
+ ///
+ /// Assignment operator.
+ template <typename CMap>
+ BlueNodeMap& operator=(const CMap&) {
+ checkConcept<ReadMap<Node, V>, CMap>();
+ return *this;
+ }
+
+ };
+
+
+ template <typename _BpGraph>
+ struct Constraints {
+
+ struct Dummy {
+ int value;
+ Dummy() : value(0) {}
+ Dummy(int _v) : value(_v) {}
+ };
+
+ void constraints() {
+ checkConcept<MappableGraphComponent<Base>, _BpGraph>();
+
+ { // int map test
+ typedef typename _BpGraph::template RedNodeMap<int>
+ IntRedNodeMap;
+ checkConcept<GraphMap<_BpGraph, typename _BpGraph::RedNode, int>,
+ IntRedNodeMap >();
+ } { // bool map test
+ typedef typename _BpGraph::template RedNodeMap<bool>
+ BoolRedNodeMap;
+ checkConcept<GraphMap<_BpGraph, typename _BpGraph::RedNode, bool>,
+ BoolRedNodeMap >();
+ } { // Dummy map test
+ typedef typename _BpGraph::template RedNodeMap<Dummy>
+ DummyRedNodeMap;
+ checkConcept<GraphMap<_BpGraph, typename _BpGraph::RedNode, Dummy>,
+ DummyRedNodeMap >();
+ }
+
+ { // int map test
+ typedef typename _BpGraph::template BlueNodeMap<int>
+ IntBlueNodeMap;
+ checkConcept<GraphMap<_BpGraph, typename _BpGraph::BlueNode, int>,
+ IntBlueNodeMap >();
+ } { // bool map test
+ typedef typename _BpGraph::template BlueNodeMap<bool>
+ BoolBlueNodeMap;
+ checkConcept<GraphMap<_BpGraph, typename _BpGraph::BlueNode, bool>,
+ BoolBlueNodeMap >();
+ } { // Dummy map test
+ typedef typename _BpGraph::template BlueNodeMap<Dummy>
+ DummyBlueNodeMap;
+ checkConcept<GraphMap<_BpGraph, typename _BpGraph::BlueNode, Dummy>,
+ DummyBlueNodeMap >();
+ }
+ }
+
+ const _BpGraph& bpgraph;
+ };
+ };
+
+ /// \brief Skeleton class for extendable directed graphs.
+ ///
+ /// This class describes the interface of extendable directed graphs.
+ /// It extends \ref BaseDigraphComponent with functions for adding
+ /// nodes and arcs to the digraph.
+ /// This concept requires \ref AlterableDigraphComponent.
+ template <typename BAS = BaseDigraphComponent>
+ class ExtendableDigraphComponent : public BAS {
+ public:
+ typedef BAS Base;
+
+ typedef typename Base::Node Node;
+ typedef typename Base::Arc Arc;
+
+ /// \brief Add a new node to the digraph.
+ ///
+ /// This function adds a new node to the digraph.
+ Node addNode() {
+ return INVALID;
+ }
+
+ /// \brief Add a new arc connecting the given two nodes.
+ ///
+ /// This function adds a new arc connecting the given two nodes
+ /// of the digraph.
+ Arc addArc(const Node&, const Node&) {
+ return INVALID;
+ }
+
+ template <typename _Digraph>
+ struct Constraints {
+ void constraints() {
+ checkConcept<Base, _Digraph>();
+ typename _Digraph::Node node_a, node_b;
+ node_a = digraph.addNode();
+ node_b = digraph.addNode();
+ typename _Digraph::Arc arc;
+ arc = digraph.addArc(node_a, node_b);
+ }
+
+ _Digraph& digraph;
+ Constraints() {}
+ };
+ };
+
+ /// \brief Skeleton class for extendable undirected graphs.
+ ///
+ /// This class describes the interface of extendable undirected graphs.
+ /// It extends \ref BaseGraphComponent with functions for adding
+ /// nodes and edges to the graph.
+ /// This concept requires \ref AlterableGraphComponent.
+ template <typename BAS = BaseGraphComponent>
+ class ExtendableGraphComponent : public BAS {
+ public:
+
+ typedef BAS Base;
+ typedef typename Base::Node Node;
+ typedef typename Base::Edge Edge;
+
+ /// \brief Add a new node to the digraph.
+ ///
+ /// This function adds a new node to the digraph.
+ Node addNode() {
+ return INVALID;
+ }
+
+ /// \brief Add a new edge connecting the given two nodes.
+ ///
+ /// This function adds a new edge connecting the given two nodes
+ /// of the graph.
+ Edge addEdge(const Node&, const Node&) {
+ return INVALID;
+ }
+
+ template <typename _Graph>
+ struct Constraints {
+ void constraints() {
+ checkConcept<Base, _Graph>();
+ typename _Graph::Node node_a, node_b;
+ node_a = graph.addNode();
+ node_b = graph.addNode();
+ typename _Graph::Edge edge;
+ edge = graph.addEdge(node_a, node_b);
+ }
+
+ _Graph& graph;
+ Constraints() {}
+ };
+ };
+
+ /// \brief Skeleton class for extendable undirected bipartite graphs.
+ ///
+ /// This class describes the interface of extendable undirected
+ /// bipartite graphs. It extends \ref BaseGraphComponent with
+ /// functions for adding nodes and edges to the graph. This
+ /// concept requires \ref AlterableBpGraphComponent.
+ template <typename BAS = BaseBpGraphComponent>
+ class ExtendableBpGraphComponent : public BAS {
+ public:
+
+ typedef BAS Base;
+ typedef typename Base::Node Node;
+ typedef typename Base::RedNode RedNode;
+ typedef typename Base::BlueNode BlueNode;
+ typedef typename Base::Edge Edge;
+
+ /// \brief Add a new red node to the digraph.
+ ///
+ /// This function adds a red new node to the digraph.
+ RedNode addRedNode() {
+ return INVALID;
+ }
+
+ /// \brief Add a new blue node to the digraph.
+ ///
+ /// This function adds a blue new node to the digraph.
+ BlueNode addBlueNode() {
+ return INVALID;
+ }
+
+ /// \brief Add a new edge connecting the given two nodes.
+ ///
+ /// This function adds a new edge connecting the given two nodes
+ /// of the graph. The first node has to be a red node, and the
+ /// second one a blue node.
+ Edge addEdge(const RedNode&, const BlueNode&) {
+ return INVALID;
+ }
+ Edge addEdge(const BlueNode&, const RedNode&) {
+ return INVALID;
+ }
+
+ template <typename _BpGraph>
+ struct Constraints {
+ void constraints() {
+ checkConcept<Base, _BpGraph>();
+ typename _BpGraph::RedNode red_node;
+ typename _BpGraph::BlueNode blue_node;
+ red_node = bpgraph.addRedNode();
+ blue_node = bpgraph.addBlueNode();
+ typename _BpGraph::Edge edge;
+ edge = bpgraph.addEdge(red_node, blue_node);
+ edge = bpgraph.addEdge(blue_node, red_node);
+ }
+
+ _BpGraph& bpgraph;
+ };
+ };
+
+ /// \brief Skeleton class for erasable directed graphs.
+ ///
+ /// This class describes the interface of erasable directed graphs.
+ /// It extends \ref BaseDigraphComponent with functions for removing
+ /// nodes and arcs from the digraph.
+ /// This concept requires \ref AlterableDigraphComponent.
+ template <typename BAS = BaseDigraphComponent>
+ class ErasableDigraphComponent : public BAS {
+ public:
+
+ typedef BAS Base;
+ typedef typename Base::Node Node;
+ typedef typename Base::Arc Arc;
+
+ /// \brief Erase a node from the digraph.
+ ///
+ /// This function erases the given node from the digraph and all arcs
+ /// connected to the node.
+ void erase(const Node&) {}
+
+ /// \brief Erase an arc from the digraph.
+ ///
+ /// This function erases the given arc from the digraph.
+ void erase(const Arc&) {}
+
+ template <typename _Digraph>
+ struct Constraints {
+ void constraints() {
+ checkConcept<Base, _Digraph>();
+ const typename _Digraph::Node node(INVALID);
+ digraph.erase(node);
+ const typename _Digraph::Arc arc(INVALID);
+ digraph.erase(arc);
+ }
+
+ _Digraph& digraph;
+ Constraints() {}
+ };
+ };
+
+ /// \brief Skeleton class for erasable undirected graphs.
+ ///
+ /// This class describes the interface of erasable undirected graphs.
+ /// It extends \ref BaseGraphComponent with functions for removing
+ /// nodes and edges from the graph.
+ /// This concept requires \ref AlterableGraphComponent.
+ template <typename BAS = BaseGraphComponent>
+ class ErasableGraphComponent : public BAS {
+ public:
+
+ typedef BAS Base;
+ typedef typename Base::Node Node;
+ typedef typename Base::Edge Edge;
+
+ /// \brief Erase a node from the graph.
+ ///
+ /// This function erases the given node from the graph and all edges
+ /// connected to the node.
+ void erase(const Node&) {}
+
+ /// \brief Erase an edge from the digraph.
+ ///
+ /// This function erases the given edge from the digraph.
+ void erase(const Edge&) {}
+
+ template <typename _Graph>
+ struct Constraints {
+ void constraints() {
+ checkConcept<Base, _Graph>();
+ const typename _Graph::Node node(INVALID);
+ graph.erase(node);
+ const typename _Graph::Edge edge(INVALID);
+ graph.erase(edge);
+ }
+
+ _Graph& graph;
+ Constraints() {}
+ };
+ };
+
+ /// \brief Skeleton class for erasable undirected graphs.
+ ///
+ /// This class describes the interface of erasable undirected
+ /// bipartite graphs. It extends \ref BaseBpGraphComponent with
+ /// functions for removing nodes and edges from the graph. This
+ /// concept requires \ref AlterableBpGraphComponent.
+ template <typename BAS = BaseBpGraphComponent>
+ class ErasableBpGraphComponent : public ErasableGraphComponent<BAS> {};
+
+ /// \brief Skeleton class for clearable directed graphs.
+ ///
+ /// This class describes the interface of clearable directed graphs.
+ /// It extends \ref BaseDigraphComponent with a function for clearing
+ /// the digraph.
+ /// This concept requires \ref AlterableDigraphComponent.
+ template <typename BAS = BaseDigraphComponent>
+ class ClearableDigraphComponent : public BAS {
+ public:
+
+ typedef BAS Base;
+
+ /// \brief Erase all nodes and arcs from the digraph.
+ ///
+ /// This function erases all nodes and arcs from the digraph.
+ void clear() {}
+
+ template <typename _Digraph>
+ struct Constraints {
+ void constraints() {
+ checkConcept<Base, _Digraph>();
+ digraph.clear();
+ }
+
+ _Digraph& digraph;
+ Constraints() {}
+ };
+ };
+
+ /// \brief Skeleton class for clearable undirected graphs.
+ ///
+ /// This class describes the interface of clearable undirected graphs.
+ /// It extends \ref BaseGraphComponent with a function for clearing
+ /// the graph.
+ /// This concept requires \ref AlterableGraphComponent.
+ template <typename BAS = BaseGraphComponent>
+ class ClearableGraphComponent : public ClearableDigraphComponent<BAS> {};
+
+ /// \brief Skeleton class for clearable undirected biparite graphs.
+ ///
+ /// This class describes the interface of clearable undirected
+ /// bipartite graphs. It extends \ref BaseBpGraphComponent with a
+ /// function for clearing the graph. This concept requires \ref
+ /// AlterableBpGraphComponent.
+ template <typename BAS = BaseBpGraphComponent>
+ class ClearableBpGraphComponent : public ClearableGraphComponent<BAS> {};
+
+ }
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/heap.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/heap.h
new file mode 100644
index 00000000000..8c7a2512144
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/heap.h
@@ -0,0 +1,324 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_CONCEPTS_HEAP_H
+#define LEMON_CONCEPTS_HEAP_H
+
+///\ingroup concept
+///\file
+///\brief The concept of heaps.
+
+#include <lemon/core.h>
+#include <lemon/concept_check.h>
+
+namespace lemon {
+
+ namespace concepts {
+
+ /// \addtogroup concept
+ /// @{
+
+ /// \brief The heap concept.
+ ///
+ /// This concept class describes the main interface of heaps.
+ /// The various \ref heaps "heap structures" are efficient
+ /// implementations of the abstract data type \e priority \e queue.
+ /// They store items with specified values called \e priorities
+ /// in such a way that finding and removing the item with minimum
+ /// priority are efficient. The basic operations are adding and
+ /// erasing items, changing the priority of an item, etc.
+ ///
+ /// Heaps are crucial in several algorithms, such as Dijkstra and Prim.
+ /// Any class that conforms to this concept can be used easily in such
+ /// algorithms.
+ ///
+ /// \tparam PR Type of the priorities of the items.
+ /// \tparam IM A read-writable item map with \c int values, used
+ /// internally to handle the cross references.
+ /// \tparam CMP A functor class for comparing the priorities.
+ /// The default is \c std::less<PR>.
+#ifdef DOXYGEN
+ template <typename PR, typename IM, typename CMP>
+#else
+ template <typename PR, typename IM, typename CMP = std::less<PR> >
+#endif
+ class Heap {
+ public:
+
+ /// Type of the item-int map.
+ typedef IM ItemIntMap;
+ /// Type of the priorities.
+ typedef PR Prio;
+ /// Type of the items stored in the heap.
+ typedef typename ItemIntMap::Key Item;
+
+ /// \brief Type to represent the states of the items.
+ ///
+ /// Each item has a state associated to it. It can be "in heap",
+ /// "pre-heap" or "post-heap". The latter two are indifferent from the
+ /// heap's point of view, but may be useful to the user.
+ ///
+ /// The item-int map must be initialized in such way that it assigns
+ /// \c PRE_HEAP (<tt>-1</tt>) to any element to be put in the heap.
+ enum State {
+ IN_HEAP = 0, ///< = 0. The "in heap" state constant.
+ PRE_HEAP = -1, ///< = -1. The "pre-heap" state constant.
+ POST_HEAP = -2 ///< = -2. The "post-heap" state constant.
+ };
+
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ /// \param map A map that assigns \c int values to keys of type
+ /// \c Item. It is used internally by the heap implementations to
+ /// handle the cross references. The assigned value must be
+ /// \c PRE_HEAP (<tt>-1</tt>) for each item.
+#ifdef DOXYGEN
+ explicit Heap(ItemIntMap &map) {}
+#else
+ explicit Heap(ItemIntMap&) {}
+#endif
+
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ /// \param map A map that assigns \c int values to keys of type
+ /// \c Item. It is used internally by the heap implementations to
+ /// handle the cross references. The assigned value must be
+ /// \c PRE_HEAP (<tt>-1</tt>) for each item.
+ /// \param comp The function object used for comparing the priorities.
+#ifdef DOXYGEN
+ explicit Heap(ItemIntMap &map, const CMP &comp) {}
+#else
+ explicit Heap(ItemIntMap&, const CMP&) {}
+#endif
+
+ /// \brief The number of items stored in the heap.
+ ///
+ /// This function returns the number of items stored in the heap.
+ int size() const { return 0; }
+
+ /// \brief Check if the heap is empty.
+ ///
+ /// This function returns \c true if the heap is empty.
+ bool empty() const { return false; }
+
+ /// \brief Make the heap empty.
+ ///
+ /// This functon makes the heap empty.
+ /// It does not change the cross reference map. If you want to reuse
+ /// a heap that is not surely empty, you should first clear it and
+ /// then you should set the cross reference map to \c PRE_HEAP
+ /// for each item.
+ void clear() {}
+
+ /// \brief Insert an item into the heap with the given priority.
+ ///
+ /// This function inserts the given item into the heap with the
+ /// given priority.
+ /// \param i The item to insert.
+ /// \param p The priority of the item.
+ /// \pre \e i must not be stored in the heap.
+#ifdef DOXYGEN
+ void push(const Item &i, const Prio &p) {}
+#else
+ void push(const Item&, const Prio&) {}
+#endif
+
+ /// \brief Return the item having minimum priority.
+ ///
+ /// This function returns the item having minimum priority.
+ /// \pre The heap must be non-empty.
+ Item top() const { return Item(); }
+
+ /// \brief The minimum priority.
+ ///
+ /// This function returns the minimum priority.
+ /// \pre The heap must be non-empty.
+ Prio prio() const { return Prio(); }
+
+ /// \brief Remove the item having minimum priority.
+ ///
+ /// This function removes the item having minimum priority.
+ /// \pre The heap must be non-empty.
+ void pop() {}
+
+ /// \brief Remove the given item from the heap.
+ ///
+ /// This function removes the given item from the heap if it is
+ /// already stored.
+ /// \param i The item to delete.
+ /// \pre \e i must be in the heap.
+#ifdef DOXYGEN
+ void erase(const Item &i) {}
+#else
+ void erase(const Item&) {}
+#endif
+
+ /// \brief The priority of the given item.
+ ///
+ /// This function returns the priority of the given item.
+ /// \param i The item.
+ /// \pre \e i must be in the heap.
+#ifdef DOXYGEN
+ Prio operator[](const Item &i) const {}
+#else
+ Prio operator[](const Item&) const { return Prio(); }
+#endif
+
+ /// \brief Set the priority of an item or insert it, if it is
+ /// not stored in the heap.
+ ///
+ /// This method sets the priority of the given item if it is
+ /// already stored in the heap. Otherwise it inserts the given
+ /// item into the heap with the given priority.
+ ///
+ /// \param i The item.
+ /// \param p The priority.
+#ifdef DOXYGEN
+ void set(const Item &i, const Prio &p) {}
+#else
+ void set(const Item&, const Prio&) {}
+#endif
+
+ /// \brief Decrease the priority of an item to the given value.
+ ///
+ /// This function decreases the priority of an item to the given value.
+ /// \param i The item.
+ /// \param p The priority.
+ /// \pre \e i must be stored in the heap with priority at least \e p.
+#ifdef DOXYGEN
+ void decrease(const Item &i, const Prio &p) {}
+#else
+ void decrease(const Item&, const Prio&) {}
+#endif
+
+ /// \brief Increase the priority of an item to the given value.
+ ///
+ /// This function increases the priority of an item to the given value.
+ /// \param i The item.
+ /// \param p The priority.
+ /// \pre \e i must be stored in the heap with priority at most \e p.
+#ifdef DOXYGEN
+ void increase(const Item &i, const Prio &p) {}
+#else
+ void increase(const Item&, const Prio&) {}
+#endif
+
+ /// \brief Return the state of an item.
+ ///
+ /// This method returns \c PRE_HEAP if the given item has never
+ /// been in the heap, \c IN_HEAP if it is in the heap at the moment,
+ /// and \c POST_HEAP otherwise.
+ /// In the latter case it is possible that the item will get back
+ /// to the heap again.
+ /// \param i The item.
+#ifdef DOXYGEN
+ State state(const Item &i) const {}
+#else
+ State state(const Item&) const { return PRE_HEAP; }
+#endif
+
+ /// \brief Set the state of an item in the heap.
+ ///
+ /// This function sets the state of the given item in the heap.
+ /// It can be used to manually clear the heap when it is important
+ /// to achive better time complexity.
+ /// \param i The item.
+ /// \param st The state. It should not be \c IN_HEAP.
+#ifdef DOXYGEN
+ void state(const Item& i, State st) {}
+#else
+ void state(const Item&, State) {}
+#endif
+
+
+ template <typename _Heap>
+ struct Constraints {
+ public:
+ void constraints() {
+ typedef typename _Heap::Item OwnItem;
+ typedef typename _Heap::Prio OwnPrio;
+ typedef typename _Heap::State OwnState;
+
+ Item item;
+ Prio prio;
+ item=Item();
+ prio=Prio();
+ ::lemon::ignore_unused_variable_warning(item);
+ ::lemon::ignore_unused_variable_warning(prio);
+
+ OwnItem own_item;
+ OwnPrio own_prio;
+ OwnState own_state;
+ own_item=Item();
+ own_prio=Prio();
+ ::lemon::ignore_unused_variable_warning(own_item);
+ ::lemon::ignore_unused_variable_warning(own_prio);
+ ::lemon::ignore_unused_variable_warning(own_state);
+
+ _Heap heap1(map);
+ _Heap heap2 = heap1;
+ ::lemon::ignore_unused_variable_warning(heap1);
+ ::lemon::ignore_unused_variable_warning(heap2);
+
+ int s = heap.size();
+ ::lemon::ignore_unused_variable_warning(s);
+ bool e = heap.empty();
+ ::lemon::ignore_unused_variable_warning(e);
+
+ prio = heap.prio();
+ item = heap.top();
+ prio = heap[item];
+ own_prio = heap.prio();
+ own_item = heap.top();
+ own_prio = heap[own_item];
+
+ heap.push(item, prio);
+ heap.push(own_item, own_prio);
+ heap.pop();
+
+ heap.set(item, prio);
+ heap.decrease(item, prio);
+ heap.increase(item, prio);
+ heap.set(own_item, own_prio);
+ heap.decrease(own_item, own_prio);
+ heap.increase(own_item, own_prio);
+
+ heap.erase(item);
+ heap.erase(own_item);
+ heap.clear();
+
+ own_state = heap.state(own_item);
+ heap.state(own_item, own_state);
+
+ own_state = _Heap::PRE_HEAP;
+ own_state = _Heap::IN_HEAP;
+ own_state = _Heap::POST_HEAP;
+ }
+
+ _Heap& heap;
+ ItemIntMap& map;
+ Constraints() {}
+ };
+ };
+
+ /// @}
+ } // namespace lemon
+}
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/maps.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/maps.h
new file mode 100644
index 00000000000..88b66b51118
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/maps.h
@@ -0,0 +1,223 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_CONCEPTS_MAPS_H
+#define LEMON_CONCEPTS_MAPS_H
+
+#include <lemon/core.h>
+#include <lemon/concept_check.h>
+
+///\ingroup map_concepts
+///\file
+///\brief The concept of maps.
+
+namespace lemon {
+
+ namespace concepts {
+
+ /// \addtogroup map_concepts
+ /// @{
+
+ /// Readable map concept
+
+ /// Readable map concept.
+ ///
+ template<typename K, typename T>
+ class ReadMap
+ {
+ public:
+ /// The key type of the map.
+ typedef K Key;
+ /// \brief The value type of the map.
+ /// (The type of objects associated with the keys).
+ typedef T Value;
+
+ /// Returns the value associated with the given key.
+ Value operator[](const Key &) const {
+ return *(static_cast<Value *>(0)+1);
+ }
+
+ template<typename _ReadMap>
+ struct Constraints {
+ void constraints() {
+ Value val = m[key];
+ val = m[key];
+ typename _ReadMap::Value own_val = m[own_key];
+ own_val = m[own_key];
+
+ ::lemon::ignore_unused_variable_warning(key);
+ ::lemon::ignore_unused_variable_warning(val);
+ ::lemon::ignore_unused_variable_warning(own_key);
+ ::lemon::ignore_unused_variable_warning(own_val);
+ }
+ const Key& key;
+ const typename _ReadMap::Key& own_key;
+ const _ReadMap& m;
+ Constraints() {}
+ };
+
+ };
+
+
+ /// Writable map concept
+
+ /// Writable map concept.
+ ///
+ template<typename K, typename T>
+ class WriteMap
+ {
+ public:
+ /// The key type of the map.
+ typedef K Key;
+ /// \brief The value type of the map.
+ /// (The type of objects associated with the keys).
+ typedef T Value;
+
+ /// Sets the value associated with the given key.
+ void set(const Key &, const Value &) {}
+
+ /// Default constructor.
+ WriteMap() {}
+
+ template <typename _WriteMap>
+ struct Constraints {
+ void constraints() {
+ m.set(key, val);
+ m.set(own_key, own_val);
+
+ ::lemon::ignore_unused_variable_warning(key);
+ ::lemon::ignore_unused_variable_warning(val);
+ ::lemon::ignore_unused_variable_warning(own_key);
+ ::lemon::ignore_unused_variable_warning(own_val);
+ }
+ const Key& key;
+ const Value& val;
+ const typename _WriteMap::Key& own_key;
+ const typename _WriteMap::Value& own_val;
+ _WriteMap& m;
+ Constraints() {}
+ };
+ };
+
+ /// Read/writable map concept
+
+ /// Read/writable map concept.
+ ///
+ template<typename K, typename T>
+ class ReadWriteMap : public ReadMap<K,T>,
+ public WriteMap<K,T>
+ {
+ public:
+ /// The key type of the map.
+ typedef K Key;
+ /// \brief The value type of the map.
+ /// (The type of objects associated with the keys).
+ typedef T Value;
+
+ /// Returns the value associated with the given key.
+ Value operator[](const Key &) const {
+ Value *r = 0;
+ return *r;
+ }
+
+ /// Sets the value associated with the given key.
+ void set(const Key &, const Value &) {}
+
+ template<typename _ReadWriteMap>
+ struct Constraints {
+ void constraints() {
+ checkConcept<ReadMap<K, T>, _ReadWriteMap >();
+ checkConcept<WriteMap<K, T>, _ReadWriteMap >();
+ }
+ };
+ };
+
+
+ /// Dereferable map concept
+
+ /// Dereferable map concept.
+ ///
+ template<typename K, typename T, typename R, typename CR>
+ class ReferenceMap : public ReadWriteMap<K,T>
+ {
+ public:
+ /// Tag for reference maps.
+ typedef True ReferenceMapTag;
+ /// The key type of the map.
+ typedef K Key;
+ /// \brief The value type of the map.
+ /// (The type of objects associated with the keys).
+ typedef T Value;
+ /// The reference type of the map.
+ typedef R Reference;
+ /// The const reference type of the map.
+ typedef CR ConstReference;
+
+ public:
+
+ /// Returns a reference to the value associated with the given key.
+ Reference operator[](const Key &) {
+ Value *r = 0;
+ return *r;
+ }
+
+ /// Returns a const reference to the value associated with the given key.
+ ConstReference operator[](const Key &) const {
+ Value *r = 0;
+ return *r;
+ }
+
+ /// Sets the value associated with the given key.
+ void set(const Key &k,const Value &t) { operator[](k)=t; }
+
+ template<typename _ReferenceMap>
+ struct Constraints {
+ typename enable_if<typename _ReferenceMap::ReferenceMapTag, void>::type
+ constraints() {
+ checkConcept<ReadWriteMap<K, T>, _ReferenceMap >();
+ ref = m[key];
+ m[key] = val;
+ m[key] = ref;
+ m[key] = cref;
+ own_ref = m[own_key];
+ m[own_key] = own_val;
+ m[own_key] = own_ref;
+ m[own_key] = own_cref;
+ m[key] = m[own_key];
+ m[own_key] = m[key];
+ }
+ const Key& key;
+ Value& val;
+ Reference ref;
+ ConstReference cref;
+ const typename _ReferenceMap::Key& own_key;
+ typename _ReferenceMap::Value& own_val;
+ typename _ReferenceMap::Reference own_ref;
+ typename _ReferenceMap::ConstReference own_cref;
+ _ReferenceMap& m;
+ Constraints() {}
+ };
+ };
+
+ // @}
+
+ } //namespace concepts
+
+} //namespace lemon
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/path.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/path.h
new file mode 100644
index 00000000000..18e4b01803d
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/path.h
@@ -0,0 +1,312 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+///\ingroup concept
+///\file
+///\brief The concept of paths
+///
+
+#ifndef LEMON_CONCEPTS_PATH_H
+#define LEMON_CONCEPTS_PATH_H
+
+#include <lemon/core.h>
+#include <lemon/concept_check.h>
+
+namespace lemon {
+ namespace concepts {
+
+ /// \addtogroup concept
+ /// @{
+
+ /// \brief A skeleton structure for representing directed paths in
+ /// a digraph.
+ ///
+ /// A skeleton structure for representing directed paths in a
+ /// digraph.
+ /// In a sense, a path can be treated as a list of arcs.
+ /// LEMON path types just store this list. As a consequence, they cannot
+ /// enumerate the nodes on the path directly and a zero length path
+ /// cannot store its source node.
+ ///
+ /// The arcs of a path should be stored in the order of their directions,
+ /// i.e. the target node of each arc should be the same as the source
+ /// node of the next arc. This consistency could be checked using
+ /// \ref checkPath().
+ /// The source and target nodes of a (consistent) path can be obtained
+ /// using \ref pathSource() and \ref pathTarget().
+ ///
+ /// A path can be constructed from another path of any type using the
+ /// copy constructor or the assignment operator.
+ ///
+ /// \tparam GR The digraph type in which the path is.
+ template <typename GR>
+ class Path {
+ public:
+
+ /// Type of the underlying digraph.
+ typedef GR Digraph;
+ /// Arc type of the underlying digraph.
+ typedef typename Digraph::Arc Arc;
+
+ class ArcIt;
+
+ /// \brief Default constructor
+ Path() {}
+
+ /// \brief Template copy constructor
+ template <typename CPath>
+ Path(const CPath& cpath) {}
+
+ /// \brief Template assigment operator
+ template <typename CPath>
+ Path& operator=(const CPath& cpath) {
+ ::lemon::ignore_unused_variable_warning(cpath);
+ return *this;
+ }
+
+ /// Length of the path, i.e. the number of arcs on the path.
+ int length() const { return 0;}
+
+ /// Returns whether the path is empty.
+ bool empty() const { return true;}
+
+ /// Resets the path to an empty path.
+ void clear() {}
+
+ /// \brief LEMON style iterator for enumerating the arcs of a path.
+ ///
+ /// LEMON style iterator class for enumerating the arcs of a path.
+ class ArcIt {
+ public:
+ /// Default constructor
+ ArcIt() {}
+ /// Invalid constructor
+ ArcIt(Invalid) {}
+ /// Sets the iterator to the first arc of the given path
+ ArcIt(const Path &) {}
+
+ /// Conversion to \c Arc
+ operator Arc() const { return INVALID; }
+
+ /// Next arc
+ ArcIt& operator++() {return *this;}
+
+ /// Comparison operator
+ bool operator==(const ArcIt&) const {return true;}
+ /// Comparison operator
+ bool operator!=(const ArcIt&) const {return true;}
+ /// Comparison operator
+ bool operator<(const ArcIt&) const {return false;}
+
+ };
+
+ template <typename _Path>
+ struct Constraints {
+ void constraints() {
+ Path<Digraph> pc;
+ _Path p, pp(pc);
+ int l = p.length();
+ int e = p.empty();
+ p.clear();
+
+ p = pc;
+
+ typename _Path::ArcIt id, ii(INVALID), i(p);
+
+ ++i;
+ typename Digraph::Arc ed = i;
+
+ e = (i == ii);
+ e = (i != ii);
+ e = (i < ii);
+
+ ::lemon::ignore_unused_variable_warning(l);
+ ::lemon::ignore_unused_variable_warning(pp);
+ ::lemon::ignore_unused_variable_warning(e);
+ ::lemon::ignore_unused_variable_warning(id);
+ ::lemon::ignore_unused_variable_warning(ii);
+ ::lemon::ignore_unused_variable_warning(ed);
+ }
+ };
+
+ };
+
+ namespace _path_bits {
+
+ template <typename _Digraph, typename _Path, typename RevPathTag = void>
+ struct PathDumperConstraints {
+ void constraints() {
+ int l = p.length();
+ int e = p.empty();
+
+ typename _Path::ArcIt id, i(p);
+
+ ++i;
+ typename _Digraph::Arc ed = i;
+
+ e = (i == INVALID);
+ e = (i != INVALID);
+
+ ::lemon::ignore_unused_variable_warning(l);
+ ::lemon::ignore_unused_variable_warning(e);
+ ::lemon::ignore_unused_variable_warning(id);
+ ::lemon::ignore_unused_variable_warning(ed);
+ }
+ _Path& p;
+ PathDumperConstraints() {}
+ };
+
+ template <typename _Digraph, typename _Path>
+ struct PathDumperConstraints<
+ _Digraph, _Path,
+ typename enable_if<typename _Path::RevPathTag, void>::type
+ > {
+ void constraints() {
+ int l = p.length();
+ int e = p.empty();
+
+ typename _Path::RevArcIt id, i(p);
+
+ ++i;
+ typename _Digraph::Arc ed = i;
+
+ e = (i == INVALID);
+ e = (i != INVALID);
+
+ ::lemon::ignore_unused_variable_warning(l);
+ ::lemon::ignore_unused_variable_warning(e);
+ ::lemon::ignore_unused_variable_warning(id);
+ ::lemon::ignore_unused_variable_warning(ed);
+ }
+ _Path& p;
+ PathDumperConstraints() {}
+ };
+
+ }
+
+
+ /// \brief A skeleton structure for path dumpers.
+ ///
+ /// A skeleton structure for path dumpers. The path dumpers are
+ /// the generalization of the paths, they can enumerate the arcs
+ /// of the path either in forward or in backward order.
+ /// These classes are typically not used directly, they are rather
+ /// used to be assigned to a real path type.
+ ///
+ /// The main purpose of this concept is that the shortest path
+ /// algorithms can enumerate the arcs easily in reverse order.
+ /// In LEMON, such algorithms give back a (reverse) path dumper that
+ /// can be assigned to a real path. The dumpers can be implemented as
+ /// an adaptor class to the predecessor map.
+ ///
+ /// \tparam GR The digraph type in which the path is.
+ template <typename GR>
+ class PathDumper {
+ public:
+
+ /// Type of the underlying digraph.
+ typedef GR Digraph;
+ /// Arc type of the underlying digraph.
+ typedef typename Digraph::Arc Arc;
+
+ /// Length of the path, i.e. the number of arcs on the path.
+ int length() const { return 0;}
+
+ /// Returns whether the path is empty.
+ bool empty() const { return true;}
+
+ /// \brief Forward or reverse dumping
+ ///
+ /// If this tag is defined to be \c True, then reverse dumping
+ /// is provided in the path dumper. In this case, \c RevArcIt
+ /// iterator should be implemented instead of \c ArcIt iterator.
+ typedef False RevPathTag;
+
+ /// \brief LEMON style iterator for enumerating the arcs of a path.
+ ///
+ /// LEMON style iterator class for enumerating the arcs of a path.
+ class ArcIt {
+ public:
+ /// Default constructor
+ ArcIt() {}
+ /// Invalid constructor
+ ArcIt(Invalid) {}
+ /// Sets the iterator to the first arc of the given path
+ ArcIt(const PathDumper&) {}
+
+ /// Conversion to \c Arc
+ operator Arc() const { return INVALID; }
+
+ /// Next arc
+ ArcIt& operator++() {return *this;}
+
+ /// Comparison operator
+ bool operator==(const ArcIt&) const {return true;}
+ /// Comparison operator
+ bool operator!=(const ArcIt&) const {return true;}
+ /// Comparison operator
+ bool operator<(const ArcIt&) const {return false;}
+
+ };
+
+ /// \brief LEMON style iterator for enumerating the arcs of a path
+ /// in reverse direction.
+ ///
+ /// LEMON style iterator class for enumerating the arcs of a path
+ /// in reverse direction.
+ class RevArcIt {
+ public:
+ /// Default constructor
+ RevArcIt() {}
+ /// Invalid constructor
+ RevArcIt(Invalid) {}
+ /// Sets the iterator to the last arc of the given path
+ RevArcIt(const PathDumper &) {}
+
+ /// Conversion to \c Arc
+ operator Arc() const { return INVALID; }
+
+ /// Next arc
+ RevArcIt& operator++() {return *this;}
+
+ /// Comparison operator
+ bool operator==(const RevArcIt&) const {return true;}
+ /// Comparison operator
+ bool operator!=(const RevArcIt&) const {return true;}
+ /// Comparison operator
+ bool operator<(const RevArcIt&) const {return false;}
+
+ };
+
+ template <typename _Path>
+ struct Constraints {
+ void constraints() {
+ function_requires<_path_bits::
+ PathDumperConstraints<Digraph, _Path> >();
+ }
+ };
+
+ };
+
+
+ ///@}
+ }
+
+} // namespace lemon
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/config.h.in b/extern/quadriflow/3rd/lemon-1.3.1/lemon/config.h.in
new file mode 100644
index 00000000000..37d8c04d733
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/config.h.in
@@ -0,0 +1,22 @@
+#define LEMON_VERSION "@PROJECT_VERSION@"
+#cmakedefine LEMON_HAVE_LONG_LONG 1
+
+#cmakedefine LEMON_HAVE_LP 1
+#cmakedefine LEMON_HAVE_MIP 1
+#cmakedefine LEMON_HAVE_GLPK 1
+#cmakedefine LEMON_HAVE_CPLEX 1
+#cmakedefine LEMON_HAVE_SOPLEX 1
+#cmakedefine LEMON_HAVE_CLP 1
+#cmakedefine LEMON_HAVE_CBC 1
+
+#define _LEMON_CPLEX 1
+#define _LEMON_CLP 2
+#define _LEMON_GLPK 3
+#define _LEMON_SOPLEX 4
+#define _LEMON_CBC 5
+
+#cmakedefine LEMON_DEFAULT_LP _LEMON_@LEMON_DEFAULT_LP@
+#cmakedefine LEMON_DEFAULT_MIP _LEMON_@LEMON_DEFAULT_MIP@
+
+#cmakedefine LEMON_USE_PTHREAD 1
+#cmakedefine LEMON_USE_WIN32_THREADS 1
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/connectivity.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/connectivity.h
new file mode 100644
index 00000000000..6bd85a18818
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/connectivity.h
@@ -0,0 +1,1688 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_CONNECTIVITY_H
+#define LEMON_CONNECTIVITY_H
+
+#include <lemon/dfs.h>
+#include <lemon/bfs.h>
+#include <lemon/core.h>
+#include <lemon/maps.h>
+#include <lemon/adaptors.h>
+
+#include <lemon/concepts/digraph.h>
+#include <lemon/concepts/graph.h>
+#include <lemon/concept_check.h>
+
+#include <stack>
+#include <functional>
+
+/// \ingroup graph_properties
+/// \file
+/// \brief Connectivity algorithms
+///
+/// Connectivity algorithms
+
+namespace lemon {
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Check whether an undirected graph is connected.
+ ///
+ /// This function checks whether the given undirected graph is connected,
+ /// i.e. there is a path between any two nodes in the graph.
+ ///
+ /// \return \c true if the graph is connected.
+ /// \note By definition, the empty graph is connected.
+ ///
+ /// \see countConnectedComponents(), connectedComponents()
+ /// \see stronglyConnected()
+ template <typename Graph>
+ bool connected(const Graph& graph) {
+ checkConcept<concepts::Graph, Graph>();
+ typedef typename Graph::NodeIt NodeIt;
+ if (NodeIt(graph) == INVALID) return true;
+ Dfs<Graph> dfs(graph);
+ dfs.run(NodeIt(graph));
+ for (NodeIt it(graph); it != INVALID; ++it) {
+ if (!dfs.reached(it)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Count the number of connected components of an undirected graph
+ ///
+ /// This function counts the number of connected components of the given
+ /// undirected graph.
+ ///
+ /// The connected components are the classes of an equivalence relation
+ /// on the nodes of an undirected graph. Two nodes are in the same class
+ /// if they are connected with a path.
+ ///
+ /// \return The number of connected components.
+ /// \note By definition, the empty graph consists
+ /// of zero connected components.
+ ///
+ /// \see connected(), connectedComponents()
+ template <typename Graph>
+ int countConnectedComponents(const Graph &graph) {
+ checkConcept<concepts::Graph, Graph>();
+ typedef typename Graph::Node Node;
+ typedef typename Graph::Arc Arc;
+
+ typedef NullMap<Node, Arc> PredMap;
+ typedef NullMap<Node, int> DistMap;
+
+ int compNum = 0;
+ typename Bfs<Graph>::
+ template SetPredMap<PredMap>::
+ template SetDistMap<DistMap>::
+ Create bfs(graph);
+
+ PredMap predMap;
+ bfs.predMap(predMap);
+
+ DistMap distMap;
+ bfs.distMap(distMap);
+
+ bfs.init();
+ for(typename Graph::NodeIt n(graph); n != INVALID; ++n) {
+ if (!bfs.reached(n)) {
+ bfs.addSource(n);
+ bfs.start();
+ ++compNum;
+ }
+ }
+ return compNum;
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Find the connected components of an undirected graph
+ ///
+ /// This function finds the connected components of the given undirected
+ /// graph.
+ ///
+ /// The connected components are the classes of an equivalence relation
+ /// on the nodes of an undirected graph. Two nodes are in the same class
+ /// if they are connected with a path.
+ ///
+ /// \image html connected_components.png
+ /// \image latex connected_components.eps "Connected components" width=\textwidth
+ ///
+ /// \param graph The undirected graph.
+ /// \retval compMap A writable node map. The values will be set from 0 to
+ /// the number of the connected components minus one. Each value of the map
+ /// will be set exactly once, and the values of a certain component will be
+ /// set continuously.
+ /// \return The number of connected components.
+ /// \note By definition, the empty graph consists
+ /// of zero connected components.
+ ///
+ /// \see connected(), countConnectedComponents()
+ template <class Graph, class NodeMap>
+ int connectedComponents(const Graph &graph, NodeMap &compMap) {
+ checkConcept<concepts::Graph, Graph>();
+ typedef typename Graph::Node Node;
+ typedef typename Graph::Arc Arc;
+ checkConcept<concepts::WriteMap<Node, int>, NodeMap>();
+
+ typedef NullMap<Node, Arc> PredMap;
+ typedef NullMap<Node, int> DistMap;
+
+ int compNum = 0;
+ typename Bfs<Graph>::
+ template SetPredMap<PredMap>::
+ template SetDistMap<DistMap>::
+ Create bfs(graph);
+
+ PredMap predMap;
+ bfs.predMap(predMap);
+
+ DistMap distMap;
+ bfs.distMap(distMap);
+
+ bfs.init();
+ for(typename Graph::NodeIt n(graph); n != INVALID; ++n) {
+ if(!bfs.reached(n)) {
+ bfs.addSource(n);
+ while (!bfs.emptyQueue()) {
+ compMap.set(bfs.nextNode(), compNum);
+ bfs.processNextNode();
+ }
+ ++compNum;
+ }
+ }
+ return compNum;
+ }
+
+ namespace _connectivity_bits {
+
+ template <typename Digraph, typename Iterator >
+ struct LeaveOrderVisitor : public DfsVisitor<Digraph> {
+ public:
+ typedef typename Digraph::Node Node;
+ LeaveOrderVisitor(Iterator it) : _it(it) {}
+
+ void leave(const Node& node) {
+ *(_it++) = node;
+ }
+
+ private:
+ Iterator _it;
+ };
+
+ template <typename Digraph, typename Map>
+ struct FillMapVisitor : public DfsVisitor<Digraph> {
+ public:
+ typedef typename Digraph::Node Node;
+ typedef typename Map::Value Value;
+
+ FillMapVisitor(Map& map, Value& value)
+ : _map(map), _value(value) {}
+
+ void reach(const Node& node) {
+ _map.set(node, _value);
+ }
+ private:
+ Map& _map;
+ Value& _value;
+ };
+
+ template <typename Digraph, typename ArcMap>
+ struct StronglyConnectedCutArcsVisitor : public DfsVisitor<Digraph> {
+ public:
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::Arc Arc;
+
+ StronglyConnectedCutArcsVisitor(const Digraph& digraph,
+ ArcMap& cutMap,
+ int& cutNum)
+ : _digraph(digraph), _cutMap(cutMap), _cutNum(cutNum),
+ _compMap(digraph, -1), _num(-1) {
+ }
+
+ void start(const Node&) {
+ ++_num;
+ }
+
+ void reach(const Node& node) {
+ _compMap.set(node, _num);
+ }
+
+ void examine(const Arc& arc) {
+ if (_compMap[_digraph.source(arc)] !=
+ _compMap[_digraph.target(arc)]) {
+ _cutMap.set(arc, true);
+ ++_cutNum;
+ }
+ }
+ private:
+ const Digraph& _digraph;
+ ArcMap& _cutMap;
+ int& _cutNum;
+
+ typename Digraph::template NodeMap<int> _compMap;
+ int _num;
+ };
+
+ }
+
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Check whether a directed graph is strongly connected.
+ ///
+ /// This function checks whether the given directed graph is strongly
+ /// connected, i.e. any two nodes of the digraph are
+ /// connected with directed paths in both direction.
+ ///
+ /// \return \c true if the digraph is strongly connected.
+ /// \note By definition, the empty digraph is strongly connected.
+ ///
+ /// \see countStronglyConnectedComponents(), stronglyConnectedComponents()
+ /// \see connected()
+ template <typename Digraph>
+ bool stronglyConnected(const Digraph& digraph) {
+ checkConcept<concepts::Digraph, Digraph>();
+
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::NodeIt NodeIt;
+
+ typename Digraph::Node source = NodeIt(digraph);
+ if (source == INVALID) return true;
+
+ using namespace _connectivity_bits;
+
+ typedef DfsVisitor<Digraph> Visitor;
+ Visitor visitor;
+
+ DfsVisit<Digraph, Visitor> dfs(digraph, visitor);
+ dfs.init();
+ dfs.addSource(source);
+ dfs.start();
+
+ for (NodeIt it(digraph); it != INVALID; ++it) {
+ if (!dfs.reached(it)) {
+ return false;
+ }
+ }
+
+ typedef ReverseDigraph<const Digraph> RDigraph;
+ typedef typename RDigraph::NodeIt RNodeIt;
+ RDigraph rdigraph(digraph);
+
+ typedef DfsVisitor<RDigraph> RVisitor;
+ RVisitor rvisitor;
+
+ DfsVisit<RDigraph, RVisitor> rdfs(rdigraph, rvisitor);
+ rdfs.init();
+ rdfs.addSource(source);
+ rdfs.start();
+
+ for (RNodeIt it(rdigraph); it != INVALID; ++it) {
+ if (!rdfs.reached(it)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Count the number of strongly connected components of a
+ /// directed graph
+ ///
+ /// This function counts the number of strongly connected components of
+ /// the given directed graph.
+ ///
+ /// The strongly connected components are the classes of an
+ /// equivalence relation on the nodes of a digraph. Two nodes are in
+ /// the same class if they are connected with directed paths in both
+ /// direction.
+ ///
+ /// \return The number of strongly connected components.
+ /// \note By definition, the empty digraph has zero
+ /// strongly connected components.
+ ///
+ /// \see stronglyConnected(), stronglyConnectedComponents()
+ template <typename Digraph>
+ int countStronglyConnectedComponents(const Digraph& digraph) {
+ checkConcept<concepts::Digraph, Digraph>();
+
+ using namespace _connectivity_bits;
+
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::NodeIt NodeIt;
+ typedef typename Digraph::ArcIt ArcIt;
+
+ typedef std::vector<Node> Container;
+ typedef typename Container::iterator Iterator;
+
+ Container nodes(countNodes(digraph));
+ typedef LeaveOrderVisitor<Digraph, Iterator> Visitor;
+ Visitor visitor(nodes.begin());
+
+ DfsVisit<Digraph, Visitor> dfs(digraph, visitor);
+ dfs.init();
+ for (NodeIt it(digraph); it != INVALID; ++it) {
+ if (!dfs.reached(it)) {
+ dfs.addSource(it);
+ dfs.start();
+ }
+ }
+
+ typedef typename Container::reverse_iterator RIterator;
+ typedef ReverseDigraph<const Digraph> RDigraph;
+
+ RDigraph rdigraph(digraph);
+
+ typedef DfsVisitor<Digraph> RVisitor;
+ RVisitor rvisitor;
+
+ DfsVisit<RDigraph, RVisitor> rdfs(rdigraph, rvisitor);
+
+ int compNum = 0;
+
+ rdfs.init();
+ for (RIterator it = nodes.rbegin(); it != nodes.rend(); ++it) {
+ if (!rdfs.reached(*it)) {
+ rdfs.addSource(*it);
+ rdfs.start();
+ ++compNum;
+ }
+ }
+ return compNum;
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Find the strongly connected components of a directed graph
+ ///
+ /// This function finds the strongly connected components of the given
+ /// directed graph. In addition, the numbering of the components will
+ /// satisfy that there is no arc going from a higher numbered component
+ /// to a lower one (i.e. it provides a topological order of the components).
+ ///
+ /// The strongly connected components are the classes of an
+ /// equivalence relation on the nodes of a digraph. Two nodes are in
+ /// the same class if they are connected with directed paths in both
+ /// direction.
+ ///
+ /// \image html strongly_connected_components.png
+ /// \image latex strongly_connected_components.eps "Strongly connected components" width=\textwidth
+ ///
+ /// \param digraph The digraph.
+ /// \retval compMap A writable node map. The values will be set from 0 to
+ /// the number of the strongly connected components minus one. Each value
+ /// of the map will be set exactly once, and the values of a certain
+ /// component will be set continuously.
+ /// \return The number of strongly connected components.
+ /// \note By definition, the empty digraph has zero
+ /// strongly connected components.
+ ///
+ /// \see stronglyConnected(), countStronglyConnectedComponents()
+ template <typename Digraph, typename NodeMap>
+ int stronglyConnectedComponents(const Digraph& digraph, NodeMap& compMap) {
+ checkConcept<concepts::Digraph, Digraph>();
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::NodeIt NodeIt;
+ checkConcept<concepts::WriteMap<Node, int>, NodeMap>();
+
+ using namespace _connectivity_bits;
+
+ typedef std::vector<Node> Container;
+ typedef typename Container::iterator Iterator;
+
+ Container nodes(countNodes(digraph));
+ typedef LeaveOrderVisitor<Digraph, Iterator> Visitor;
+ Visitor visitor(nodes.begin());
+
+ DfsVisit<Digraph, Visitor> dfs(digraph, visitor);
+ dfs.init();
+ for (NodeIt it(digraph); it != INVALID; ++it) {
+ if (!dfs.reached(it)) {
+ dfs.addSource(it);
+ dfs.start();
+ }
+ }
+
+ typedef typename Container::reverse_iterator RIterator;
+ typedef ReverseDigraph<const Digraph> RDigraph;
+
+ RDigraph rdigraph(digraph);
+
+ int compNum = 0;
+
+ typedef FillMapVisitor<RDigraph, NodeMap> RVisitor;
+ RVisitor rvisitor(compMap, compNum);
+
+ DfsVisit<RDigraph, RVisitor> rdfs(rdigraph, rvisitor);
+
+ rdfs.init();
+ for (RIterator it = nodes.rbegin(); it != nodes.rend(); ++it) {
+ if (!rdfs.reached(*it)) {
+ rdfs.addSource(*it);
+ rdfs.start();
+ ++compNum;
+ }
+ }
+ return compNum;
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Find the cut arcs of the strongly connected components.
+ ///
+ /// This function finds the cut arcs of the strongly connected components
+ /// of the given digraph.
+ ///
+ /// The strongly connected components are the classes of an
+ /// equivalence relation on the nodes of a digraph. Two nodes are in
+ /// the same class if they are connected with directed paths in both
+ /// direction.
+ /// The strongly connected components are separated by the cut arcs.
+ ///
+ /// \param digraph The digraph.
+ /// \retval cutMap A writable arc map. The values will be set to \c true
+ /// for the cut arcs (exactly once for each cut arc), and will not be
+ /// changed for other arcs.
+ /// \return The number of cut arcs.
+ ///
+ /// \see stronglyConnected(), stronglyConnectedComponents()
+ template <typename Digraph, typename ArcMap>
+ int stronglyConnectedCutArcs(const Digraph& digraph, ArcMap& cutMap) {
+ checkConcept<concepts::Digraph, Digraph>();
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::NodeIt NodeIt;
+ checkConcept<concepts::WriteMap<Arc, bool>, ArcMap>();
+
+ using namespace _connectivity_bits;
+
+ typedef std::vector<Node> Container;
+ typedef typename Container::iterator Iterator;
+
+ Container nodes(countNodes(digraph));
+ typedef LeaveOrderVisitor<Digraph, Iterator> Visitor;
+ Visitor visitor(nodes.begin());
+
+ DfsVisit<Digraph, Visitor> dfs(digraph, visitor);
+ dfs.init();
+ for (NodeIt it(digraph); it != INVALID; ++it) {
+ if (!dfs.reached(it)) {
+ dfs.addSource(it);
+ dfs.start();
+ }
+ }
+
+ typedef typename Container::reverse_iterator RIterator;
+ typedef ReverseDigraph<const Digraph> RDigraph;
+
+ RDigraph rdigraph(digraph);
+
+ int cutNum = 0;
+
+ typedef StronglyConnectedCutArcsVisitor<RDigraph, ArcMap> RVisitor;
+ RVisitor rvisitor(rdigraph, cutMap, cutNum);
+
+ DfsVisit<RDigraph, RVisitor> rdfs(rdigraph, rvisitor);
+
+ rdfs.init();
+ for (RIterator it = nodes.rbegin(); it != nodes.rend(); ++it) {
+ if (!rdfs.reached(*it)) {
+ rdfs.addSource(*it);
+ rdfs.start();
+ }
+ }
+ return cutNum;
+ }
+
+ namespace _connectivity_bits {
+
+ template <typename Digraph>
+ class CountBiNodeConnectedComponentsVisitor : public DfsVisitor<Digraph> {
+ public:
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::Edge Edge;
+
+ CountBiNodeConnectedComponentsVisitor(const Digraph& graph, int &compNum)
+ : _graph(graph), _compNum(compNum),
+ _numMap(graph), _retMap(graph), _predMap(graph), _num(0) {}
+
+ void start(const Node& node) {
+ _predMap.set(node, INVALID);
+ }
+
+ void reach(const Node& node) {
+ _numMap.set(node, _num);
+ _retMap.set(node, _num);
+ ++_num;
+ }
+
+ void discover(const Arc& edge) {
+ _predMap.set(_graph.target(edge), _graph.source(edge));
+ }
+
+ void examine(const Arc& edge) {
+ if (_graph.source(edge) == _graph.target(edge) &&
+ _graph.direction(edge)) {
+ ++_compNum;
+ return;
+ }
+ if (_predMap[_graph.source(edge)] == _graph.target(edge)) {
+ return;
+ }
+ if (_retMap[_graph.source(edge)] > _numMap[_graph.target(edge)]) {
+ _retMap.set(_graph.source(edge), _numMap[_graph.target(edge)]);
+ }
+ }
+
+ void backtrack(const Arc& edge) {
+ if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) {
+ _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]);
+ }
+ if (_numMap[_graph.source(edge)] <= _retMap[_graph.target(edge)]) {
+ ++_compNum;
+ }
+ }
+
+ private:
+ const Digraph& _graph;
+ int& _compNum;
+
+ typename Digraph::template NodeMap<int> _numMap;
+ typename Digraph::template NodeMap<int> _retMap;
+ typename Digraph::template NodeMap<Node> _predMap;
+ int _num;
+ };
+
+ template <typename Digraph, typename ArcMap>
+ class BiNodeConnectedComponentsVisitor : public DfsVisitor<Digraph> {
+ public:
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::Edge Edge;
+
+ BiNodeConnectedComponentsVisitor(const Digraph& graph,
+ ArcMap& compMap, int &compNum)
+ : _graph(graph), _compMap(compMap), _compNum(compNum),
+ _numMap(graph), _retMap(graph), _predMap(graph), _num(0) {}
+
+ void start(const Node& node) {
+ _predMap.set(node, INVALID);
+ }
+
+ void reach(const Node& node) {
+ _numMap.set(node, _num);
+ _retMap.set(node, _num);
+ ++_num;
+ }
+
+ void discover(const Arc& edge) {
+ Node target = _graph.target(edge);
+ _predMap.set(target, edge);
+ _edgeStack.push(edge);
+ }
+
+ void examine(const Arc& edge) {
+ Node source = _graph.source(edge);
+ Node target = _graph.target(edge);
+ if (source == target && _graph.direction(edge)) {
+ _compMap.set(edge, _compNum);
+ ++_compNum;
+ return;
+ }
+ if (_numMap[target] < _numMap[source]) {
+ if (_predMap[source] != _graph.oppositeArc(edge)) {
+ _edgeStack.push(edge);
+ }
+ }
+ if (_predMap[source] != INVALID &&
+ target == _graph.source(_predMap[source])) {
+ return;
+ }
+ if (_retMap[source] > _numMap[target]) {
+ _retMap.set(source, _numMap[target]);
+ }
+ }
+
+ void backtrack(const Arc& edge) {
+ Node source = _graph.source(edge);
+ Node target = _graph.target(edge);
+ if (_retMap[source] > _retMap[target]) {
+ _retMap.set(source, _retMap[target]);
+ }
+ if (_numMap[source] <= _retMap[target]) {
+ while (_edgeStack.top() != edge) {
+ _compMap.set(_edgeStack.top(), _compNum);
+ _edgeStack.pop();
+ }
+ _compMap.set(edge, _compNum);
+ _edgeStack.pop();
+ ++_compNum;
+ }
+ }
+
+ private:
+ const Digraph& _graph;
+ ArcMap& _compMap;
+ int& _compNum;
+
+ typename Digraph::template NodeMap<int> _numMap;
+ typename Digraph::template NodeMap<int> _retMap;
+ typename Digraph::template NodeMap<Arc> _predMap;
+ std::stack<Edge> _edgeStack;
+ int _num;
+ };
+
+
+ template <typename Digraph, typename NodeMap>
+ class BiNodeConnectedCutNodesVisitor : public DfsVisitor<Digraph> {
+ public:
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::Edge Edge;
+
+ BiNodeConnectedCutNodesVisitor(const Digraph& graph, NodeMap& cutMap,
+ int& cutNum)
+ : _graph(graph), _cutMap(cutMap), _cutNum(cutNum),
+ _numMap(graph), _retMap(graph), _predMap(graph), _num(0) {}
+
+ void start(const Node& node) {
+ _predMap.set(node, INVALID);
+ rootCut = false;
+ }
+
+ void reach(const Node& node) {
+ _numMap.set(node, _num);
+ _retMap.set(node, _num);
+ ++_num;
+ }
+
+ void discover(const Arc& edge) {
+ _predMap.set(_graph.target(edge), _graph.source(edge));
+ }
+
+ void examine(const Arc& edge) {
+ if (_graph.source(edge) == _graph.target(edge) &&
+ _graph.direction(edge)) {
+ if (!_cutMap[_graph.source(edge)]) {
+ _cutMap.set(_graph.source(edge), true);
+ ++_cutNum;
+ }
+ return;
+ }
+ if (_predMap[_graph.source(edge)] == _graph.target(edge)) return;
+ if (_retMap[_graph.source(edge)] > _numMap[_graph.target(edge)]) {
+ _retMap.set(_graph.source(edge), _numMap[_graph.target(edge)]);
+ }
+ }
+
+ void backtrack(const Arc& edge) {
+ if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) {
+ _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]);
+ }
+ if (_numMap[_graph.source(edge)] <= _retMap[_graph.target(edge)]) {
+ if (_predMap[_graph.source(edge)] != INVALID) {
+ if (!_cutMap[_graph.source(edge)]) {
+ _cutMap.set(_graph.source(edge), true);
+ ++_cutNum;
+ }
+ } else if (rootCut) {
+ if (!_cutMap[_graph.source(edge)]) {
+ _cutMap.set(_graph.source(edge), true);
+ ++_cutNum;
+ }
+ } else {
+ rootCut = true;
+ }
+ }
+ }
+
+ private:
+ const Digraph& _graph;
+ NodeMap& _cutMap;
+ int& _cutNum;
+
+ typename Digraph::template NodeMap<int> _numMap;
+ typename Digraph::template NodeMap<int> _retMap;
+ typename Digraph::template NodeMap<Node> _predMap;
+ std::stack<Edge> _edgeStack;
+ int _num;
+ bool rootCut;
+ };
+
+ }
+
+ template <typename Graph>
+ int countBiNodeConnectedComponents(const Graph& graph);
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Check whether an undirected graph is bi-node-connected.
+ ///
+ /// This function checks whether the given undirected graph is
+ /// bi-node-connected, i.e. a connected graph without articulation
+ /// node.
+ ///
+ /// \return \c true if the graph bi-node-connected.
+ ///
+ /// \note By definition,
+ /// \li a graph consisting of zero or one node is bi-node-connected,
+ /// \li a graph consisting of two isolated nodes
+ /// is \e not bi-node-connected and
+ /// \li a graph consisting of two nodes connected by an edge
+ /// is bi-node-connected.
+ ///
+ /// \see countBiNodeConnectedComponents(), biNodeConnectedComponents()
+ template <typename Graph>
+ bool biNodeConnected(const Graph& graph) {
+ bool hasNonIsolated = false, hasIsolated = false;
+ for (typename Graph::NodeIt n(graph); n != INVALID; ++n) {
+ if (typename Graph::OutArcIt(graph, n) == INVALID) {
+ if (hasIsolated || hasNonIsolated) {
+ return false;
+ } else {
+ hasIsolated = true;
+ }
+ } else {
+ if (hasIsolated) {
+ return false;
+ } else {
+ hasNonIsolated = true;
+ }
+ }
+ }
+ return countBiNodeConnectedComponents(graph) <= 1;
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Count the number of bi-node-connected components of an
+ /// undirected graph.
+ ///
+ /// This function counts the number of bi-node-connected components of
+ /// the given undirected graph.
+ ///
+ /// The bi-node-connected components are the classes of an equivalence
+ /// relation on the edges of a undirected graph. Two edges are in the
+ /// same class if they are on same circle.
+ ///
+ /// \return The number of bi-node-connected components.
+ ///
+ /// \see biNodeConnected(), biNodeConnectedComponents()
+ template <typename Graph>
+ int countBiNodeConnectedComponents(const Graph& graph) {
+ checkConcept<concepts::Graph, Graph>();
+ typedef typename Graph::NodeIt NodeIt;
+
+ using namespace _connectivity_bits;
+
+ typedef CountBiNodeConnectedComponentsVisitor<Graph> Visitor;
+
+ int compNum = 0;
+ Visitor visitor(graph, compNum);
+
+ DfsVisit<Graph, Visitor> dfs(graph, visitor);
+ dfs.init();
+
+ for (NodeIt it(graph); it != INVALID; ++it) {
+ if (!dfs.reached(it)) {
+ dfs.addSource(it);
+ dfs.start();
+ }
+ }
+ return compNum;
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Find the bi-node-connected components of an undirected graph.
+ ///
+ /// This function finds the bi-node-connected components of the given
+ /// undirected graph.
+ ///
+ /// The bi-node-connected components are the classes of an equivalence
+ /// relation on the edges of a undirected graph. Two edges are in the
+ /// same class if they are on same circle.
+ ///
+ /// \image html node_biconnected_components.png
+ /// \image latex node_biconnected_components.eps "bi-node-connected components" width=\textwidth
+ ///
+ /// \param graph The undirected graph.
+ /// \retval compMap A writable edge map. The values will be set from 0
+ /// to the number of the bi-node-connected components minus one. Each
+ /// value of the map will be set exactly once, and the values of a
+ /// certain component will be set continuously.
+ /// \return The number of bi-node-connected components.
+ ///
+ /// \see biNodeConnected(), countBiNodeConnectedComponents()
+ template <typename Graph, typename EdgeMap>
+ int biNodeConnectedComponents(const Graph& graph,
+ EdgeMap& compMap) {
+ checkConcept<concepts::Graph, Graph>();
+ typedef typename Graph::NodeIt NodeIt;
+ typedef typename Graph::Edge Edge;
+ checkConcept<concepts::WriteMap<Edge, int>, EdgeMap>();
+
+ using namespace _connectivity_bits;
+
+ typedef BiNodeConnectedComponentsVisitor<Graph, EdgeMap> Visitor;
+
+ int compNum = 0;
+ Visitor visitor(graph, compMap, compNum);
+
+ DfsVisit<Graph, Visitor> dfs(graph, visitor);
+ dfs.init();
+
+ for (NodeIt it(graph); it != INVALID; ++it) {
+ if (!dfs.reached(it)) {
+ dfs.addSource(it);
+ dfs.start();
+ }
+ }
+ return compNum;
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Find the bi-node-connected cut nodes in an undirected graph.
+ ///
+ /// This function finds the bi-node-connected cut nodes in the given
+ /// undirected graph.
+ ///
+ /// The bi-node-connected components are the classes of an equivalence
+ /// relation on the edges of a undirected graph. Two edges are in the
+ /// same class if they are on same circle.
+ /// The bi-node-connected components are separted by the cut nodes of
+ /// the components.
+ ///
+ /// \param graph The undirected graph.
+ /// \retval cutMap A writable node map. The values will be set to
+ /// \c true for the nodes that separate two or more components
+ /// (exactly once for each cut node), and will not be changed for
+ /// other nodes.
+ /// \return The number of the cut nodes.
+ ///
+ /// \see biNodeConnected(), biNodeConnectedComponents()
+ template <typename Graph, typename NodeMap>
+ int biNodeConnectedCutNodes(const Graph& graph, NodeMap& cutMap) {
+ checkConcept<concepts::Graph, Graph>();
+ typedef typename Graph::Node Node;
+ typedef typename Graph::NodeIt NodeIt;
+ checkConcept<concepts::WriteMap<Node, bool>, NodeMap>();
+
+ using namespace _connectivity_bits;
+
+ typedef BiNodeConnectedCutNodesVisitor<Graph, NodeMap> Visitor;
+
+ int cutNum = 0;
+ Visitor visitor(graph, cutMap, cutNum);
+
+ DfsVisit<Graph, Visitor> dfs(graph, visitor);
+ dfs.init();
+
+ for (NodeIt it(graph); it != INVALID; ++it) {
+ if (!dfs.reached(it)) {
+ dfs.addSource(it);
+ dfs.start();
+ }
+ }
+ return cutNum;
+ }
+
+ namespace _connectivity_bits {
+
+ template <typename Digraph>
+ class CountBiEdgeConnectedComponentsVisitor : public DfsVisitor<Digraph> {
+ public:
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::Edge Edge;
+
+ CountBiEdgeConnectedComponentsVisitor(const Digraph& graph, int &compNum)
+ : _graph(graph), _compNum(compNum),
+ _numMap(graph), _retMap(graph), _predMap(graph), _num(0) {}
+
+ void start(const Node& node) {
+ _predMap.set(node, INVALID);
+ }
+
+ void reach(const Node& node) {
+ _numMap.set(node, _num);
+ _retMap.set(node, _num);
+ ++_num;
+ }
+
+ void leave(const Node& node) {
+ if (_numMap[node] <= _retMap[node]) {
+ ++_compNum;
+ }
+ }
+
+ void discover(const Arc& edge) {
+ _predMap.set(_graph.target(edge), edge);
+ }
+
+ void examine(const Arc& edge) {
+ if (_predMap[_graph.source(edge)] == _graph.oppositeArc(edge)) {
+ return;
+ }
+ if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) {
+ _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]);
+ }
+ }
+
+ void backtrack(const Arc& edge) {
+ if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) {
+ _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]);
+ }
+ }
+
+ private:
+ const Digraph& _graph;
+ int& _compNum;
+
+ typename Digraph::template NodeMap<int> _numMap;
+ typename Digraph::template NodeMap<int> _retMap;
+ typename Digraph::template NodeMap<Arc> _predMap;
+ int _num;
+ };
+
+ template <typename Digraph, typename NodeMap>
+ class BiEdgeConnectedComponentsVisitor : public DfsVisitor<Digraph> {
+ public:
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::Edge Edge;
+
+ BiEdgeConnectedComponentsVisitor(const Digraph& graph,
+ NodeMap& compMap, int &compNum)
+ : _graph(graph), _compMap(compMap), _compNum(compNum),
+ _numMap(graph), _retMap(graph), _predMap(graph), _num(0) {}
+
+ void start(const Node& node) {
+ _predMap.set(node, INVALID);
+ }
+
+ void reach(const Node& node) {
+ _numMap.set(node, _num);
+ _retMap.set(node, _num);
+ _nodeStack.push(node);
+ ++_num;
+ }
+
+ void leave(const Node& node) {
+ if (_numMap[node] <= _retMap[node]) {
+ while (_nodeStack.top() != node) {
+ _compMap.set(_nodeStack.top(), _compNum);
+ _nodeStack.pop();
+ }
+ _compMap.set(node, _compNum);
+ _nodeStack.pop();
+ ++_compNum;
+ }
+ }
+
+ void discover(const Arc& edge) {
+ _predMap.set(_graph.target(edge), edge);
+ }
+
+ void examine(const Arc& edge) {
+ if (_predMap[_graph.source(edge)] == _graph.oppositeArc(edge)) {
+ return;
+ }
+ if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) {
+ _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]);
+ }
+ }
+
+ void backtrack(const Arc& edge) {
+ if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) {
+ _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]);
+ }
+ }
+
+ private:
+ const Digraph& _graph;
+ NodeMap& _compMap;
+ int& _compNum;
+
+ typename Digraph::template NodeMap<int> _numMap;
+ typename Digraph::template NodeMap<int> _retMap;
+ typename Digraph::template NodeMap<Arc> _predMap;
+ std::stack<Node> _nodeStack;
+ int _num;
+ };
+
+
+ template <typename Digraph, typename ArcMap>
+ class BiEdgeConnectedCutEdgesVisitor : public DfsVisitor<Digraph> {
+ public:
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::Edge Edge;
+
+ BiEdgeConnectedCutEdgesVisitor(const Digraph& graph,
+ ArcMap& cutMap, int &cutNum)
+ : _graph(graph), _cutMap(cutMap), _cutNum(cutNum),
+ _numMap(graph), _retMap(graph), _predMap(graph), _num(0) {}
+
+ void start(const Node& node) {
+ _predMap[node] = INVALID;
+ }
+
+ void reach(const Node& node) {
+ _numMap.set(node, _num);
+ _retMap.set(node, _num);
+ ++_num;
+ }
+
+ void leave(const Node& node) {
+ if (_numMap[node] <= _retMap[node]) {
+ if (_predMap[node] != INVALID) {
+ _cutMap.set(_predMap[node], true);
+ ++_cutNum;
+ }
+ }
+ }
+
+ void discover(const Arc& edge) {
+ _predMap.set(_graph.target(edge), edge);
+ }
+
+ void examine(const Arc& edge) {
+ if (_predMap[_graph.source(edge)] == _graph.oppositeArc(edge)) {
+ return;
+ }
+ if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) {
+ _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]);
+ }
+ }
+
+ void backtrack(const Arc& edge) {
+ if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) {
+ _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]);
+ }
+ }
+
+ private:
+ const Digraph& _graph;
+ ArcMap& _cutMap;
+ int& _cutNum;
+
+ typename Digraph::template NodeMap<int> _numMap;
+ typename Digraph::template NodeMap<int> _retMap;
+ typename Digraph::template NodeMap<Arc> _predMap;
+ int _num;
+ };
+ }
+
+ template <typename Graph>
+ int countBiEdgeConnectedComponents(const Graph& graph);
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Check whether an undirected graph is bi-edge-connected.
+ ///
+ /// This function checks whether the given undirected graph is
+ /// bi-edge-connected, i.e. any two nodes are connected with at least
+ /// two edge-disjoint paths.
+ ///
+ /// \return \c true if the graph is bi-edge-connected.
+ /// \note By definition, the empty graph is bi-edge-connected.
+ ///
+ /// \see countBiEdgeConnectedComponents(), biEdgeConnectedComponents()
+ template <typename Graph>
+ bool biEdgeConnected(const Graph& graph) {
+ return countBiEdgeConnectedComponents(graph) <= 1;
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Count the number of bi-edge-connected components of an
+ /// undirected graph.
+ ///
+ /// This function counts the number of bi-edge-connected components of
+ /// the given undirected graph.
+ ///
+ /// The bi-edge-connected components are the classes of an equivalence
+ /// relation on the nodes of an undirected graph. Two nodes are in the
+ /// same class if they are connected with at least two edge-disjoint
+ /// paths.
+ ///
+ /// \return The number of bi-edge-connected components.
+ ///
+ /// \see biEdgeConnected(), biEdgeConnectedComponents()
+ template <typename Graph>
+ int countBiEdgeConnectedComponents(const Graph& graph) {
+ checkConcept<concepts::Graph, Graph>();
+ typedef typename Graph::NodeIt NodeIt;
+
+ using namespace _connectivity_bits;
+
+ typedef CountBiEdgeConnectedComponentsVisitor<Graph> Visitor;
+
+ int compNum = 0;
+ Visitor visitor(graph, compNum);
+
+ DfsVisit<Graph, Visitor> dfs(graph, visitor);
+ dfs.init();
+
+ for (NodeIt it(graph); it != INVALID; ++it) {
+ if (!dfs.reached(it)) {
+ dfs.addSource(it);
+ dfs.start();
+ }
+ }
+ return compNum;
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Find the bi-edge-connected components of an undirected graph.
+ ///
+ /// This function finds the bi-edge-connected components of the given
+ /// undirected graph.
+ ///
+ /// The bi-edge-connected components are the classes of an equivalence
+ /// relation on the nodes of an undirected graph. Two nodes are in the
+ /// same class if they are connected with at least two edge-disjoint
+ /// paths.
+ ///
+ /// \image html edge_biconnected_components.png
+ /// \image latex edge_biconnected_components.eps "bi-edge-connected components" width=\textwidth
+ ///
+ /// \param graph The undirected graph.
+ /// \retval compMap A writable node map. The values will be set from 0 to
+ /// the number of the bi-edge-connected components minus one. Each value
+ /// of the map will be set exactly once, and the values of a certain
+ /// component will be set continuously.
+ /// \return The number of bi-edge-connected components.
+ ///
+ /// \see biEdgeConnected(), countBiEdgeConnectedComponents()
+ template <typename Graph, typename NodeMap>
+ int biEdgeConnectedComponents(const Graph& graph, NodeMap& compMap) {
+ checkConcept<concepts::Graph, Graph>();
+ typedef typename Graph::NodeIt NodeIt;
+ typedef typename Graph::Node Node;
+ checkConcept<concepts::WriteMap<Node, int>, NodeMap>();
+
+ using namespace _connectivity_bits;
+
+ typedef BiEdgeConnectedComponentsVisitor<Graph, NodeMap> Visitor;
+
+ int compNum = 0;
+ Visitor visitor(graph, compMap, compNum);
+
+ DfsVisit<Graph, Visitor> dfs(graph, visitor);
+ dfs.init();
+
+ for (NodeIt it(graph); it != INVALID; ++it) {
+ if (!dfs.reached(it)) {
+ dfs.addSource(it);
+ dfs.start();
+ }
+ }
+ return compNum;
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Find the bi-edge-connected cut edges in an undirected graph.
+ ///
+ /// This function finds the bi-edge-connected cut edges in the given
+ /// undirected graph.
+ ///
+ /// The bi-edge-connected components are the classes of an equivalence
+ /// relation on the nodes of an undirected graph. Two nodes are in the
+ /// same class if they are connected with at least two edge-disjoint
+ /// paths.
+ /// The bi-edge-connected components are separted by the cut edges of
+ /// the components.
+ ///
+ /// \param graph The undirected graph.
+ /// \retval cutMap A writable edge map. The values will be set to \c true
+ /// for the cut edges (exactly once for each cut edge), and will not be
+ /// changed for other edges.
+ /// \return The number of cut edges.
+ ///
+ /// \see biEdgeConnected(), biEdgeConnectedComponents()
+ template <typename Graph, typename EdgeMap>
+ int biEdgeConnectedCutEdges(const Graph& graph, EdgeMap& cutMap) {
+ checkConcept<concepts::Graph, Graph>();
+ typedef typename Graph::NodeIt NodeIt;
+ typedef typename Graph::Edge Edge;
+ checkConcept<concepts::WriteMap<Edge, bool>, EdgeMap>();
+
+ using namespace _connectivity_bits;
+
+ typedef BiEdgeConnectedCutEdgesVisitor<Graph, EdgeMap> Visitor;
+
+ int cutNum = 0;
+ Visitor visitor(graph, cutMap, cutNum);
+
+ DfsVisit<Graph, Visitor> dfs(graph, visitor);
+ dfs.init();
+
+ for (NodeIt it(graph); it != INVALID; ++it) {
+ if (!dfs.reached(it)) {
+ dfs.addSource(it);
+ dfs.start();
+ }
+ }
+ return cutNum;
+ }
+
+
+ namespace _connectivity_bits {
+
+ template <typename Digraph, typename IntNodeMap>
+ class TopologicalSortVisitor : public DfsVisitor<Digraph> {
+ public:
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::Arc edge;
+
+ TopologicalSortVisitor(IntNodeMap& order, int num)
+ : _order(order), _num(num) {}
+
+ void leave(const Node& node) {
+ _order.set(node, --_num);
+ }
+
+ private:
+ IntNodeMap& _order;
+ int _num;
+ };
+
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Check whether a digraph is DAG.
+ ///
+ /// This function checks whether the given digraph is DAG, i.e.
+ /// \e Directed \e Acyclic \e Graph.
+ /// \return \c true if there is no directed cycle in the digraph.
+ /// \see acyclic()
+ template <typename Digraph>
+ bool dag(const Digraph& digraph) {
+
+ checkConcept<concepts::Digraph, Digraph>();
+
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::NodeIt NodeIt;
+ typedef typename Digraph::Arc Arc;
+
+ typedef typename Digraph::template NodeMap<bool> ProcessedMap;
+
+ typename Dfs<Digraph>::template SetProcessedMap<ProcessedMap>::
+ Create dfs(digraph);
+
+ ProcessedMap processed(digraph);
+ dfs.processedMap(processed);
+
+ dfs.init();
+ for (NodeIt it(digraph); it != INVALID; ++it) {
+ if (!dfs.reached(it)) {
+ dfs.addSource(it);
+ while (!dfs.emptyQueue()) {
+ Arc arc = dfs.nextArc();
+ Node target = digraph.target(arc);
+ if (dfs.reached(target) && !processed[target]) {
+ return false;
+ }
+ dfs.processNextArc();
+ }
+ }
+ }
+ return true;
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Sort the nodes of a DAG into topolgical order.
+ ///
+ /// This function sorts the nodes of the given acyclic digraph (DAG)
+ /// into topolgical order.
+ ///
+ /// \param digraph The digraph, which must be DAG.
+ /// \retval order A writable node map. The values will be set from 0 to
+ /// the number of the nodes in the digraph minus one. Each value of the
+ /// map will be set exactly once, and the values will be set descending
+ /// order.
+ ///
+ /// \see dag(), checkedTopologicalSort()
+ template <typename Digraph, typename NodeMap>
+ void topologicalSort(const Digraph& digraph, NodeMap& order) {
+ using namespace _connectivity_bits;
+
+ checkConcept<concepts::Digraph, Digraph>();
+ checkConcept<concepts::WriteMap<typename Digraph::Node, int>, NodeMap>();
+
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::NodeIt NodeIt;
+ typedef typename Digraph::Arc Arc;
+
+ TopologicalSortVisitor<Digraph, NodeMap>
+ visitor(order, countNodes(digraph));
+
+ DfsVisit<Digraph, TopologicalSortVisitor<Digraph, NodeMap> >
+ dfs(digraph, visitor);
+
+ dfs.init();
+ for (NodeIt it(digraph); it != INVALID; ++it) {
+ if (!dfs.reached(it)) {
+ dfs.addSource(it);
+ dfs.start();
+ }
+ }
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Sort the nodes of a DAG into topolgical order.
+ ///
+ /// This function sorts the nodes of the given acyclic digraph (DAG)
+ /// into topolgical order and also checks whether the given digraph
+ /// is DAG.
+ ///
+ /// \param digraph The digraph.
+ /// \retval order A readable and writable node map. The values will be
+ /// set from 0 to the number of the nodes in the digraph minus one.
+ /// Each value of the map will be set exactly once, and the values will
+ /// be set descending order.
+ /// \return \c false if the digraph is not DAG.
+ ///
+ /// \see dag(), topologicalSort()
+ template <typename Digraph, typename NodeMap>
+ bool checkedTopologicalSort(const Digraph& digraph, NodeMap& order) {
+ using namespace _connectivity_bits;
+
+ checkConcept<concepts::Digraph, Digraph>();
+ checkConcept<concepts::ReadWriteMap<typename Digraph::Node, int>,
+ NodeMap>();
+
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::NodeIt NodeIt;
+ typedef typename Digraph::Arc Arc;
+
+ for (NodeIt it(digraph); it != INVALID; ++it) {
+ order.set(it, -1);
+ }
+
+ TopologicalSortVisitor<Digraph, NodeMap>
+ visitor(order, countNodes(digraph));
+
+ DfsVisit<Digraph, TopologicalSortVisitor<Digraph, NodeMap> >
+ dfs(digraph, visitor);
+
+ dfs.init();
+ for (NodeIt it(digraph); it != INVALID; ++it) {
+ if (!dfs.reached(it)) {
+ dfs.addSource(it);
+ while (!dfs.emptyQueue()) {
+ Arc arc = dfs.nextArc();
+ Node target = digraph.target(arc);
+ if (dfs.reached(target) && order[target] == -1) {
+ return false;
+ }
+ dfs.processNextArc();
+ }
+ }
+ }
+ return true;
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Check whether an undirected graph is acyclic.
+ ///
+ /// This function checks whether the given undirected graph is acyclic.
+ /// \return \c true if there is no cycle in the graph.
+ /// \see dag()
+ template <typename Graph>
+ bool acyclic(const Graph& graph) {
+ checkConcept<concepts::Graph, Graph>();
+ typedef typename Graph::Node Node;
+ typedef typename Graph::NodeIt NodeIt;
+ typedef typename Graph::Arc Arc;
+ Dfs<Graph> dfs(graph);
+ dfs.init();
+ for (NodeIt it(graph); it != INVALID; ++it) {
+ if (!dfs.reached(it)) {
+ dfs.addSource(it);
+ while (!dfs.emptyQueue()) {
+ Arc arc = dfs.nextArc();
+ Node source = graph.source(arc);
+ Node target = graph.target(arc);
+ if (dfs.reached(target) &&
+ dfs.predArc(source) != graph.oppositeArc(arc)) {
+ return false;
+ }
+ dfs.processNextArc();
+ }
+ }
+ }
+ return true;
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Check whether an undirected graph is tree.
+ ///
+ /// This function checks whether the given undirected graph is tree.
+ /// \return \c true if the graph is acyclic and connected.
+ /// \see acyclic(), connected()
+ template <typename Graph>
+ bool tree(const Graph& graph) {
+ checkConcept<concepts::Graph, Graph>();
+ typedef typename Graph::Node Node;
+ typedef typename Graph::NodeIt NodeIt;
+ typedef typename Graph::Arc Arc;
+ if (NodeIt(graph) == INVALID) return true;
+ Dfs<Graph> dfs(graph);
+ dfs.init();
+ dfs.addSource(NodeIt(graph));
+ while (!dfs.emptyQueue()) {
+ Arc arc = dfs.nextArc();
+ Node source = graph.source(arc);
+ Node target = graph.target(arc);
+ if (dfs.reached(target) &&
+ dfs.predArc(source) != graph.oppositeArc(arc)) {
+ return false;
+ }
+ dfs.processNextArc();
+ }
+ for (NodeIt it(graph); it != INVALID; ++it) {
+ if (!dfs.reached(it)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ namespace _connectivity_bits {
+
+ template <typename Digraph>
+ class BipartiteVisitor : public BfsVisitor<Digraph> {
+ public:
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::Node Node;
+
+ BipartiteVisitor(const Digraph& graph, bool& bipartite)
+ : _graph(graph), _part(graph), _bipartite(bipartite) {}
+
+ void start(const Node& node) {
+ _part[node] = true;
+ }
+ void discover(const Arc& edge) {
+ _part.set(_graph.target(edge), !_part[_graph.source(edge)]);
+ }
+ void examine(const Arc& edge) {
+ _bipartite = _bipartite &&
+ _part[_graph.target(edge)] != _part[_graph.source(edge)];
+ }
+
+ private:
+
+ const Digraph& _graph;
+ typename Digraph::template NodeMap<bool> _part;
+ bool& _bipartite;
+ };
+
+ template <typename Digraph, typename PartMap>
+ class BipartitePartitionsVisitor : public BfsVisitor<Digraph> {
+ public:
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::Node Node;
+
+ BipartitePartitionsVisitor(const Digraph& graph,
+ PartMap& part, bool& bipartite)
+ : _graph(graph), _part(part), _bipartite(bipartite) {}
+
+ void start(const Node& node) {
+ _part.set(node, true);
+ }
+ void discover(const Arc& edge) {
+ _part.set(_graph.target(edge), !_part[_graph.source(edge)]);
+ }
+ void examine(const Arc& edge) {
+ _bipartite = _bipartite &&
+ _part[_graph.target(edge)] != _part[_graph.source(edge)];
+ }
+
+ private:
+
+ const Digraph& _graph;
+ PartMap& _part;
+ bool& _bipartite;
+ };
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Check whether an undirected graph is bipartite.
+ ///
+ /// The function checks whether the given undirected graph is bipartite.
+ /// \return \c true if the graph is bipartite.
+ ///
+ /// \see bipartitePartitions()
+ template<typename Graph>
+ bool bipartite(const Graph &graph){
+ using namespace _connectivity_bits;
+
+ checkConcept<concepts::Graph, Graph>();
+
+ typedef typename Graph::NodeIt NodeIt;
+ typedef typename Graph::ArcIt ArcIt;
+
+ bool bipartite = true;
+
+ BipartiteVisitor<Graph>
+ visitor(graph, bipartite);
+ BfsVisit<Graph, BipartiteVisitor<Graph> >
+ bfs(graph, visitor);
+ bfs.init();
+ for(NodeIt it(graph); it != INVALID; ++it) {
+ if(!bfs.reached(it)){
+ bfs.addSource(it);
+ while (!bfs.emptyQueue()) {
+ bfs.processNextNode();
+ if (!bipartite) return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Find the bipartite partitions of an undirected graph.
+ ///
+ /// This function checks whether the given undirected graph is bipartite
+ /// and gives back the bipartite partitions.
+ ///
+ /// \image html bipartite_partitions.png
+ /// \image latex bipartite_partitions.eps "Bipartite partititions" width=\textwidth
+ ///
+ /// \param graph The undirected graph.
+ /// \retval partMap A writable node map of \c bool (or convertible) value
+ /// type. The values will be set to \c true for one component and
+ /// \c false for the other one.
+ /// \return \c true if the graph is bipartite, \c false otherwise.
+ ///
+ /// \see bipartite()
+ template<typename Graph, typename NodeMap>
+ bool bipartitePartitions(const Graph &graph, NodeMap &partMap){
+ using namespace _connectivity_bits;
+
+ checkConcept<concepts::Graph, Graph>();
+ checkConcept<concepts::WriteMap<typename Graph::Node, bool>, NodeMap>();
+
+ typedef typename Graph::Node Node;
+ typedef typename Graph::NodeIt NodeIt;
+ typedef typename Graph::ArcIt ArcIt;
+
+ bool bipartite = true;
+
+ BipartitePartitionsVisitor<Graph, NodeMap>
+ visitor(graph, partMap, bipartite);
+ BfsVisit<Graph, BipartitePartitionsVisitor<Graph, NodeMap> >
+ bfs(graph, visitor);
+ bfs.init();
+ for(NodeIt it(graph); it != INVALID; ++it) {
+ if(!bfs.reached(it)){
+ bfs.addSource(it);
+ while (!bfs.emptyQueue()) {
+ bfs.processNextNode();
+ if (!bipartite) return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Check whether the given graph contains no loop arcs/edges.
+ ///
+ /// This function returns \c true if there are no loop arcs/edges in
+ /// the given graph. It works for both directed and undirected graphs.
+ template <typename Graph>
+ bool loopFree(const Graph& graph) {
+ for (typename Graph::ArcIt it(graph); it != INVALID; ++it) {
+ if (graph.source(it) == graph.target(it)) return false;
+ }
+ return true;
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Check whether the given graph contains no parallel arcs/edges.
+ ///
+ /// This function returns \c true if there are no parallel arcs/edges in
+ /// the given graph. It works for both directed and undirected graphs.
+ template <typename Graph>
+ bool parallelFree(const Graph& graph) {
+ typename Graph::template NodeMap<int> reached(graph, 0);
+ int cnt = 1;
+ for (typename Graph::NodeIt n(graph); n != INVALID; ++n) {
+ for (typename Graph::OutArcIt a(graph, n); a != INVALID; ++a) {
+ if (reached[graph.target(a)] == cnt) return false;
+ reached[graph.target(a)] = cnt;
+ }
+ ++cnt;
+ }
+ return true;
+ }
+
+ /// \ingroup graph_properties
+ ///
+ /// \brief Check whether the given graph is simple.
+ ///
+ /// This function returns \c true if the given graph is simple, i.e.
+ /// it contains no loop arcs/edges and no parallel arcs/edges.
+ /// The function works for both directed and undirected graphs.
+ /// \see loopFree(), parallelFree()
+ template <typename Graph>
+ bool simpleGraph(const Graph& graph) {
+ typename Graph::template NodeMap<int> reached(graph, 0);
+ int cnt = 1;
+ for (typename Graph::NodeIt n(graph); n != INVALID; ++n) {
+ reached[n] = cnt;
+ for (typename Graph::OutArcIt a(graph, n); a != INVALID; ++a) {
+ if (reached[graph.target(a)] == cnt) return false;
+ reached[graph.target(a)] = cnt;
+ }
+ ++cnt;
+ }
+ return true;
+ }
+
+} //namespace lemon
+
+#endif //LEMON_CONNECTIVITY_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/core.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/core.h
new file mode 100644
index 00000000000..507943db1c3
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/core.h
@@ -0,0 +1,2506 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_CORE_H
+#define LEMON_CORE_H
+
+#include <vector>
+#include <algorithm>
+
+#include <lemon/config.h>
+#include <lemon/bits/enable_if.h>
+#include <lemon/bits/traits.h>
+#include <lemon/assert.h>
+
+// Disable the following warnings when compiling with MSVC:
+// C4250: 'class1' : inherits 'class2::member' via dominance
+// C4355: 'this' : used in base member initializer list
+// C4503: 'function' : decorated name length exceeded, name was truncated
+// C4800: 'type' : forcing value to bool 'true' or 'false' (performance warning)
+// C4996: 'function': was declared deprecated
+#ifdef _MSC_VER
+#pragma warning( disable : 4250 4355 4503 4800 4996 )
+#endif
+
+#ifdef __GNUC__
+#define GCC_VERSION (__GNUC__ * 10000 \
+ + __GNUC_MINOR__ * 100 \
+ + __GNUC_PATCHLEVEL__)
+#endif
+
+#if GCC_VERSION >= 40800
+// Needed by the [DI]GRAPH_TYPEDEFS marcos for gcc 4.8
+#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
+#endif
+
+///\file
+///\brief LEMON core utilities.
+///
+///This header file contains core utilities for LEMON.
+///It is automatically included by all graph types, therefore it usually
+///do not have to be included directly.
+
+namespace lemon {
+
+ /// \brief Dummy type to make it easier to create invalid iterators.
+ ///
+ /// Dummy type to make it easier to create invalid iterators.
+ /// See \ref INVALID for the usage.
+ struct Invalid {
+ public:
+ bool operator==(Invalid) { return true; }
+ bool operator!=(Invalid) { return false; }
+ bool operator< (Invalid) { return false; }
+ };
+
+ /// \brief Invalid iterators.
+ ///
+ /// \ref Invalid is a global type that converts to each iterator
+ /// in such a way that the value of the target iterator will be invalid.
+#ifdef LEMON_ONLY_TEMPLATES
+ const Invalid INVALID = Invalid();
+#else
+ extern const Invalid INVALID;
+#endif
+
+ /// \addtogroup gutils
+ /// @{
+
+ ///Create convenience typedefs for the digraph types and iterators
+
+ ///This \c \#define creates convenient type definitions for the following
+ ///types of \c Digraph: \c Node, \c NodeIt, \c Arc, \c ArcIt, \c InArcIt,
+ ///\c OutArcIt, \c BoolNodeMap, \c IntNodeMap, \c DoubleNodeMap,
+ ///\c BoolArcMap, \c IntArcMap, \c DoubleArcMap.
+ ///
+ ///\note If the graph type is a dependent type, ie. the graph type depend
+ ///on a template parameter, then use \c TEMPLATE_DIGRAPH_TYPEDEFS()
+ ///macro.
+#define DIGRAPH_TYPEDEFS(Digraph) \
+ typedef Digraph::Node Node; \
+ typedef Digraph::NodeIt NodeIt; \
+ typedef Digraph::Arc Arc; \
+ typedef Digraph::ArcIt ArcIt; \
+ typedef Digraph::InArcIt InArcIt; \
+ typedef Digraph::OutArcIt OutArcIt; \
+ typedef Digraph::NodeMap<bool> BoolNodeMap; \
+ typedef Digraph::NodeMap<int> IntNodeMap; \
+ typedef Digraph::NodeMap<double> DoubleNodeMap; \
+ typedef Digraph::ArcMap<bool> BoolArcMap; \
+ typedef Digraph::ArcMap<int> IntArcMap; \
+ typedef Digraph::ArcMap<double> DoubleArcMap
+
+ ///Create convenience typedefs for the digraph types and iterators
+
+ ///\see DIGRAPH_TYPEDEFS
+ ///
+ ///\note Use this macro, if the graph type is a dependent type,
+ ///ie. the graph type depend on a template parameter.
+#define TEMPLATE_DIGRAPH_TYPEDEFS(Digraph) \
+ typedef typename Digraph::Node Node; \
+ typedef typename Digraph::NodeIt NodeIt; \
+ typedef typename Digraph::Arc Arc; \
+ typedef typename Digraph::ArcIt ArcIt; \
+ typedef typename Digraph::InArcIt InArcIt; \
+ typedef typename Digraph::OutArcIt OutArcIt; \
+ typedef typename Digraph::template NodeMap<bool> BoolNodeMap; \
+ typedef typename Digraph::template NodeMap<int> IntNodeMap; \
+ typedef typename Digraph::template NodeMap<double> DoubleNodeMap; \
+ typedef typename Digraph::template ArcMap<bool> BoolArcMap; \
+ typedef typename Digraph::template ArcMap<int> IntArcMap; \
+ typedef typename Digraph::template ArcMap<double> DoubleArcMap
+
+ ///Create convenience typedefs for the graph types and iterators
+
+ ///This \c \#define creates the same convenient type definitions as defined
+ ///by \ref DIGRAPH_TYPEDEFS(Graph) and six more, namely it creates
+ ///\c Edge, \c EdgeIt, \c IncEdgeIt, \c BoolEdgeMap, \c IntEdgeMap,
+ ///\c DoubleEdgeMap.
+ ///
+ ///\note If the graph type is a dependent type, ie. the graph type depend
+ ///on a template parameter, then use \c TEMPLATE_GRAPH_TYPEDEFS()
+ ///macro.
+#define GRAPH_TYPEDEFS(Graph) \
+ DIGRAPH_TYPEDEFS(Graph); \
+ typedef Graph::Edge Edge; \
+ typedef Graph::EdgeIt EdgeIt; \
+ typedef Graph::IncEdgeIt IncEdgeIt; \
+ typedef Graph::EdgeMap<bool> BoolEdgeMap; \
+ typedef Graph::EdgeMap<int> IntEdgeMap; \
+ typedef Graph::EdgeMap<double> DoubleEdgeMap
+
+ ///Create convenience typedefs for the graph types and iterators
+
+ ///\see GRAPH_TYPEDEFS
+ ///
+ ///\note Use this macro, if the graph type is a dependent type,
+ ///ie. the graph type depend on a template parameter.
+#define TEMPLATE_GRAPH_TYPEDEFS(Graph) \
+ TEMPLATE_DIGRAPH_TYPEDEFS(Graph); \
+ typedef typename Graph::Edge Edge; \
+ typedef typename Graph::EdgeIt EdgeIt; \
+ typedef typename Graph::IncEdgeIt IncEdgeIt; \
+ typedef typename Graph::template EdgeMap<bool> BoolEdgeMap; \
+ typedef typename Graph::template EdgeMap<int> IntEdgeMap; \
+ typedef typename Graph::template EdgeMap<double> DoubleEdgeMap
+
+ ///Create convenience typedefs for the bipartite graph types and iterators
+
+ ///This \c \#define creates the same convenient type definitions as
+ ///defined by \ref GRAPH_TYPEDEFS(BpGraph) and ten more, namely it
+ ///creates \c RedNode, \c RedNodeIt, \c BoolRedNodeMap,
+ ///\c IntRedNodeMap, \c DoubleRedNodeMap, \c BlueNode, \c BlueNodeIt,
+ ///\c BoolBlueNodeMap, \c IntBlueNodeMap, \c DoubleBlueNodeMap.
+ ///
+ ///\note If the graph type is a dependent type, ie. the graph type depend
+ ///on a template parameter, then use \c TEMPLATE_BPGRAPH_TYPEDEFS()
+ ///macro.
+#define BPGRAPH_TYPEDEFS(BpGraph) \
+ GRAPH_TYPEDEFS(BpGraph); \
+ typedef BpGraph::RedNode RedNode; \
+ typedef BpGraph::RedNodeIt RedNodeIt; \
+ typedef BpGraph::RedNodeMap<bool> BoolRedNodeMap; \
+ typedef BpGraph::RedNodeMap<int> IntRedNodeMap; \
+ typedef BpGraph::RedNodeMap<double> DoubleRedNodeMap; \
+ typedef BpGraph::BlueNode BlueNode; \
+ typedef BpGraph::BlueNodeIt BlueNodeIt; \
+ typedef BpGraph::BlueNodeMap<bool> BoolBlueNodeMap; \
+ typedef BpGraph::BlueNodeMap<int> IntBlueNodeMap; \
+ typedef BpGraph::BlueNodeMap<double> DoubleBlueNodeMap
+
+ ///Create convenience typedefs for the bipartite graph types and iterators
+
+ ///\see BPGRAPH_TYPEDEFS
+ ///
+ ///\note Use this macro, if the graph type is a dependent type,
+ ///ie. the graph type depend on a template parameter.
+#define TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph) \
+ TEMPLATE_GRAPH_TYPEDEFS(BpGraph); \
+ typedef typename BpGraph::RedNode RedNode; \
+ typedef typename BpGraph::RedNodeIt RedNodeIt; \
+ typedef typename BpGraph::template RedNodeMap<bool> BoolRedNodeMap; \
+ typedef typename BpGraph::template RedNodeMap<int> IntRedNodeMap; \
+ typedef typename BpGraph::template RedNodeMap<double> DoubleRedNodeMap; \
+ typedef typename BpGraph::BlueNode BlueNode; \
+ typedef typename BpGraph::BlueNodeIt BlueNodeIt; \
+ typedef typename BpGraph::template BlueNodeMap<bool> BoolBlueNodeMap; \
+ typedef typename BpGraph::template BlueNodeMap<int> IntBlueNodeMap; \
+ typedef typename BpGraph::template BlueNodeMap<double> DoubleBlueNodeMap
+
+ /// \brief Function to count the items in a graph.
+ ///
+ /// This function counts the items (nodes, arcs etc.) in a graph.
+ /// The complexity of the function is linear because
+ /// it iterates on all of the items.
+ template <typename Graph, typename Item>
+ inline int countItems(const Graph& g) {
+ typedef typename ItemSetTraits<Graph, Item>::ItemIt ItemIt;
+ int num = 0;
+ for (ItemIt it(g); it != INVALID; ++it) {
+ ++num;
+ }
+ return num;
+ }
+
+ // Node counting:
+
+ namespace _core_bits {
+
+ template <typename Graph, typename Enable = void>
+ struct CountNodesSelector {
+ static int count(const Graph &g) {
+ return countItems<Graph, typename Graph::Node>(g);
+ }
+ };
+
+ template <typename Graph>
+ struct CountNodesSelector<
+ Graph, typename
+ enable_if<typename Graph::NodeNumTag, void>::type>
+ {
+ static int count(const Graph &g) {
+ return g.nodeNum();
+ }
+ };
+ }
+
+ /// \brief Function to count the nodes in the graph.
+ ///
+ /// This function counts the nodes in the graph.
+ /// The complexity of the function is <em>O</em>(<em>n</em>), but for some
+ /// graph structures it is specialized to run in <em>O</em>(1).
+ ///
+ /// \note If the graph contains a \c nodeNum() member function and a
+ /// \c NodeNumTag tag then this function calls directly the member
+ /// function to query the cardinality of the node set.
+ template <typename Graph>
+ inline int countNodes(const Graph& g) {
+ return _core_bits::CountNodesSelector<Graph>::count(g);
+ }
+
+ namespace _graph_utils_bits {
+
+ template <typename Graph, typename Enable = void>
+ struct CountRedNodesSelector {
+ static int count(const Graph &g) {
+ return countItems<Graph, typename Graph::RedNode>(g);
+ }
+ };
+
+ template <typename Graph>
+ struct CountRedNodesSelector<
+ Graph, typename
+ enable_if<typename Graph::NodeNumTag, void>::type>
+ {
+ static int count(const Graph &g) {
+ return g.redNum();
+ }
+ };
+ }
+
+ /// \brief Function to count the red nodes in the graph.
+ ///
+ /// This function counts the red nodes in the graph.
+ /// The complexity of the function is O(n) but for some
+ /// graph structures it is specialized to run in O(1).
+ ///
+ /// If the graph contains a \e redNum() member function and a
+ /// \e NodeNumTag tag then this function calls directly the member
+ /// function to query the cardinality of the node set.
+ template <typename Graph>
+ inline int countRedNodes(const Graph& g) {
+ return _graph_utils_bits::CountRedNodesSelector<Graph>::count(g);
+ }
+
+ namespace _graph_utils_bits {
+
+ template <typename Graph, typename Enable = void>
+ struct CountBlueNodesSelector {
+ static int count(const Graph &g) {
+ return countItems<Graph, typename Graph::BlueNode>(g);
+ }
+ };
+
+ template <typename Graph>
+ struct CountBlueNodesSelector<
+ Graph, typename
+ enable_if<typename Graph::NodeNumTag, void>::type>
+ {
+ static int count(const Graph &g) {
+ return g.blueNum();
+ }
+ };
+ }
+
+ /// \brief Function to count the blue nodes in the graph.
+ ///
+ /// This function counts the blue nodes in the graph.
+ /// The complexity of the function is O(n) but for some
+ /// graph structures it is specialized to run in O(1).
+ ///
+ /// If the graph contains a \e blueNum() member function and a
+ /// \e NodeNumTag tag then this function calls directly the member
+ /// function to query the cardinality of the node set.
+ template <typename Graph>
+ inline int countBlueNodes(const Graph& g) {
+ return _graph_utils_bits::CountBlueNodesSelector<Graph>::count(g);
+ }
+
+ // Arc counting:
+
+ namespace _core_bits {
+
+ template <typename Graph, typename Enable = void>
+ struct CountArcsSelector {
+ static int count(const Graph &g) {
+ return countItems<Graph, typename Graph::Arc>(g);
+ }
+ };
+
+ template <typename Graph>
+ struct CountArcsSelector<
+ Graph,
+ typename enable_if<typename Graph::ArcNumTag, void>::type>
+ {
+ static int count(const Graph &g) {
+ return g.arcNum();
+ }
+ };
+ }
+
+ /// \brief Function to count the arcs in the graph.
+ ///
+ /// This function counts the arcs in the graph.
+ /// The complexity of the function is <em>O</em>(<em>m</em>), but for some
+ /// graph structures it is specialized to run in <em>O</em>(1).
+ ///
+ /// \note If the graph contains a \c arcNum() member function and a
+ /// \c ArcNumTag tag then this function calls directly the member
+ /// function to query the cardinality of the arc set.
+ template <typename Graph>
+ inline int countArcs(const Graph& g) {
+ return _core_bits::CountArcsSelector<Graph>::count(g);
+ }
+
+ // Edge counting:
+
+ namespace _core_bits {
+
+ template <typename Graph, typename Enable = void>
+ struct CountEdgesSelector {
+ static int count(const Graph &g) {
+ return countItems<Graph, typename Graph::Edge>(g);
+ }
+ };
+
+ template <typename Graph>
+ struct CountEdgesSelector<
+ Graph,
+ typename enable_if<typename Graph::EdgeNumTag, void>::type>
+ {
+ static int count(const Graph &g) {
+ return g.edgeNum();
+ }
+ };
+ }
+
+ /// \brief Function to count the edges in the graph.
+ ///
+ /// This function counts the edges in the graph.
+ /// The complexity of the function is <em>O</em>(<em>m</em>), but for some
+ /// graph structures it is specialized to run in <em>O</em>(1).
+ ///
+ /// \note If the graph contains a \c edgeNum() member function and a
+ /// \c EdgeNumTag tag then this function calls directly the member
+ /// function to query the cardinality of the edge set.
+ template <typename Graph>
+ inline int countEdges(const Graph& g) {
+ return _core_bits::CountEdgesSelector<Graph>::count(g);
+
+ }
+
+
+ template <typename Graph, typename DegIt>
+ inline int countNodeDegree(const Graph& _g, const typename Graph::Node& _n) {
+ int num = 0;
+ for (DegIt it(_g, _n); it != INVALID; ++it) {
+ ++num;
+ }
+ return num;
+ }
+
+ /// \brief Function to count the number of the out-arcs from node \c n.
+ ///
+ /// This function counts the number of the out-arcs from node \c n
+ /// in the graph \c g.
+ template <typename Graph>
+ inline int countOutArcs(const Graph& g, const typename Graph::Node& n) {
+ return countNodeDegree<Graph, typename Graph::OutArcIt>(g, n);
+ }
+
+ /// \brief Function to count the number of the in-arcs to node \c n.
+ ///
+ /// This function counts the number of the in-arcs to node \c n
+ /// in the graph \c g.
+ template <typename Graph>
+ inline int countInArcs(const Graph& g, const typename Graph::Node& n) {
+ return countNodeDegree<Graph, typename Graph::InArcIt>(g, n);
+ }
+
+ /// \brief Function to count the number of the inc-edges to node \c n.
+ ///
+ /// This function counts the number of the inc-edges to node \c n
+ /// in the undirected graph \c g.
+ template <typename Graph>
+ inline int countIncEdges(const Graph& g, const typename Graph::Node& n) {
+ return countNodeDegree<Graph, typename Graph::IncEdgeIt>(g, n);
+ }
+
+ namespace _core_bits {
+
+ template <typename Digraph, typename Item, typename RefMap>
+ class MapCopyBase {
+ public:
+ virtual void copy(const Digraph& from, const RefMap& refMap) = 0;
+
+ virtual ~MapCopyBase() {}
+ };
+
+ template <typename Digraph, typename Item, typename RefMap,
+ typename FromMap, typename ToMap>
+ class MapCopy : public MapCopyBase<Digraph, Item, RefMap> {
+ public:
+
+ MapCopy(const FromMap& map, ToMap& tmap)
+ : _map(map), _tmap(tmap) {}
+
+ virtual void copy(const Digraph& digraph, const RefMap& refMap) {
+ typedef typename ItemSetTraits<Digraph, Item>::ItemIt ItemIt;
+ for (ItemIt it(digraph); it != INVALID; ++it) {
+ _tmap.set(refMap[it], _map[it]);
+ }
+ }
+
+ private:
+ const FromMap& _map;
+ ToMap& _tmap;
+ };
+
+ template <typename Digraph, typename Item, typename RefMap, typename It>
+ class ItemCopy : public MapCopyBase<Digraph, Item, RefMap> {
+ public:
+
+ ItemCopy(const Item& item, It& it) : _item(item), _it(it) {}
+
+ virtual void copy(const Digraph&, const RefMap& refMap) {
+ _it = refMap[_item];
+ }
+
+ private:
+ Item _item;
+ It& _it;
+ };
+
+ template <typename Digraph, typename Item, typename RefMap, typename Ref>
+ class RefCopy : public MapCopyBase<Digraph, Item, RefMap> {
+ public:
+
+ RefCopy(Ref& map) : _map(map) {}
+
+ virtual void copy(const Digraph& digraph, const RefMap& refMap) {
+ typedef typename ItemSetTraits<Digraph, Item>::ItemIt ItemIt;
+ for (ItemIt it(digraph); it != INVALID; ++it) {
+ _map.set(it, refMap[it]);
+ }
+ }
+
+ private:
+ Ref& _map;
+ };
+
+ template <typename Digraph, typename Item, typename RefMap,
+ typename CrossRef>
+ class CrossRefCopy : public MapCopyBase<Digraph, Item, RefMap> {
+ public:
+
+ CrossRefCopy(CrossRef& cmap) : _cmap(cmap) {}
+
+ virtual void copy(const Digraph& digraph, const RefMap& refMap) {
+ typedef typename ItemSetTraits<Digraph, Item>::ItemIt ItemIt;
+ for (ItemIt it(digraph); it != INVALID; ++it) {
+ _cmap.set(refMap[it], it);
+ }
+ }
+
+ private:
+ CrossRef& _cmap;
+ };
+
+ template <typename Digraph, typename Enable = void>
+ struct DigraphCopySelector {
+ template <typename From, typename NodeRefMap, typename ArcRefMap>
+ static void copy(const From& from, Digraph &to,
+ NodeRefMap& nodeRefMap, ArcRefMap& arcRefMap) {
+ to.clear();
+ for (typename From::NodeIt it(from); it != INVALID; ++it) {
+ nodeRefMap[it] = to.addNode();
+ }
+ for (typename From::ArcIt it(from); it != INVALID; ++it) {
+ arcRefMap[it] = to.addArc(nodeRefMap[from.source(it)],
+ nodeRefMap[from.target(it)]);
+ }
+ }
+ };
+
+ template <typename Digraph>
+ struct DigraphCopySelector<
+ Digraph,
+ typename enable_if<typename Digraph::BuildTag, void>::type>
+ {
+ template <typename From, typename NodeRefMap, typename ArcRefMap>
+ static void copy(const From& from, Digraph &to,
+ NodeRefMap& nodeRefMap, ArcRefMap& arcRefMap) {
+ to.build(from, nodeRefMap, arcRefMap);
+ }
+ };
+
+ template <typename Graph, typename Enable = void>
+ struct GraphCopySelector {
+ template <typename From, typename NodeRefMap, typename EdgeRefMap>
+ static void copy(const From& from, Graph &to,
+ NodeRefMap& nodeRefMap, EdgeRefMap& edgeRefMap) {
+ to.clear();
+ for (typename From::NodeIt it(from); it != INVALID; ++it) {
+ nodeRefMap[it] = to.addNode();
+ }
+ for (typename From::EdgeIt it(from); it != INVALID; ++it) {
+ edgeRefMap[it] = to.addEdge(nodeRefMap[from.u(it)],
+ nodeRefMap[from.v(it)]);
+ }
+ }
+ };
+
+ template <typename Graph>
+ struct GraphCopySelector<
+ Graph,
+ typename enable_if<typename Graph::BuildTag, void>::type>
+ {
+ template <typename From, typename NodeRefMap, typename EdgeRefMap>
+ static void copy(const From& from, Graph &to,
+ NodeRefMap& nodeRefMap,
+ EdgeRefMap& edgeRefMap) {
+ to.build(from, nodeRefMap, edgeRefMap);
+ }
+ };
+
+ template <typename BpGraph, typename Enable = void>
+ struct BpGraphCopySelector {
+ template <typename From, typename RedNodeRefMap,
+ typename BlueNodeRefMap, typename EdgeRefMap>
+ static void copy(const From& from, BpGraph &to,
+ RedNodeRefMap& redNodeRefMap,
+ BlueNodeRefMap& blueNodeRefMap,
+ EdgeRefMap& edgeRefMap) {
+ to.clear();
+ for (typename From::RedNodeIt it(from); it != INVALID; ++it) {
+ redNodeRefMap[it] = to.addRedNode();
+ }
+ for (typename From::BlueNodeIt it(from); it != INVALID; ++it) {
+ blueNodeRefMap[it] = to.addBlueNode();
+ }
+ for (typename From::EdgeIt it(from); it != INVALID; ++it) {
+ edgeRefMap[it] = to.addEdge(redNodeRefMap[from.redNode(it)],
+ blueNodeRefMap[from.blueNode(it)]);
+ }
+ }
+ };
+
+ template <typename BpGraph>
+ struct BpGraphCopySelector<
+ BpGraph,
+ typename enable_if<typename BpGraph::BuildTag, void>::type>
+ {
+ template <typename From, typename RedNodeRefMap,
+ typename BlueNodeRefMap, typename EdgeRefMap>
+ static void copy(const From& from, BpGraph &to,
+ RedNodeRefMap& redNodeRefMap,
+ BlueNodeRefMap& blueNodeRefMap,
+ EdgeRefMap& edgeRefMap) {
+ to.build(from, redNodeRefMap, blueNodeRefMap, edgeRefMap);
+ }
+ };
+
+ }
+
+ /// \brief Check whether a graph is undirected.
+ ///
+ /// This function returns \c true if the given graph is undirected.
+#ifdef DOXYGEN
+ template <typename GR>
+ bool undirected(const GR& g) { return false; }
+#else
+ template <typename GR>
+ typename enable_if<UndirectedTagIndicator<GR>, bool>::type
+ undirected(const GR&) {
+ return true;
+ }
+ template <typename GR>
+ typename disable_if<UndirectedTagIndicator<GR>, bool>::type
+ undirected(const GR&) {
+ return false;
+ }
+#endif
+
+ /// \brief Class to copy a digraph.
+ ///
+ /// Class to copy a digraph to another digraph (duplicate a digraph). The
+ /// simplest way of using it is through the \c digraphCopy() function.
+ ///
+ /// This class not only make a copy of a digraph, but it can create
+ /// references and cross references between the nodes and arcs of
+ /// the two digraphs, and it can copy maps to use with the newly created
+ /// digraph.
+ ///
+ /// To make a copy from a digraph, first an instance of DigraphCopy
+ /// should be created, then the data belongs to the digraph should
+ /// assigned to copy. In the end, the \c run() member should be
+ /// called.
+ ///
+ /// The next code copies a digraph with several data:
+ ///\code
+ /// DigraphCopy<OrigGraph, NewGraph> cg(orig_graph, new_graph);
+ /// // Create references for the nodes
+ /// OrigGraph::NodeMap<NewGraph::Node> nr(orig_graph);
+ /// cg.nodeRef(nr);
+ /// // Create cross references (inverse) for the arcs
+ /// NewGraph::ArcMap<OrigGraph::Arc> acr(new_graph);
+ /// cg.arcCrossRef(acr);
+ /// // Copy an arc map
+ /// OrigGraph::ArcMap<double> oamap(orig_graph);
+ /// NewGraph::ArcMap<double> namap(new_graph);
+ /// cg.arcMap(oamap, namap);
+ /// // Copy a node
+ /// OrigGraph::Node on;
+ /// NewGraph::Node nn;
+ /// cg.node(on, nn);
+ /// // Execute copying
+ /// cg.run();
+ ///\endcode
+ template <typename From, typename To>
+ class DigraphCopy {
+ private:
+
+ typedef typename From::Node Node;
+ typedef typename From::NodeIt NodeIt;
+ typedef typename From::Arc Arc;
+ typedef typename From::ArcIt ArcIt;
+
+ typedef typename To::Node TNode;
+ typedef typename To::Arc TArc;
+
+ typedef typename From::template NodeMap<TNode> NodeRefMap;
+ typedef typename From::template ArcMap<TArc> ArcRefMap;
+
+ public:
+
+ /// \brief Constructor of DigraphCopy.
+ ///
+ /// Constructor of DigraphCopy for copying the content of the
+ /// \c from digraph into the \c to digraph.
+ DigraphCopy(const From& from, To& to)
+ : _from(from), _to(to) {}
+
+ /// \brief Destructor of DigraphCopy
+ ///
+ /// Destructor of DigraphCopy.
+ ~DigraphCopy() {
+ for (int i = 0; i < int(_node_maps.size()); ++i) {
+ delete _node_maps[i];
+ }
+ for (int i = 0; i < int(_arc_maps.size()); ++i) {
+ delete _arc_maps[i];
+ }
+
+ }
+
+ /// \brief Copy the node references into the given map.
+ ///
+ /// This function copies the node references into the given map.
+ /// The parameter should be a map, whose key type is the Node type of
+ /// the source digraph, while the value type is the Node type of the
+ /// destination digraph.
+ template <typename NodeRef>
+ DigraphCopy& nodeRef(NodeRef& map) {
+ _node_maps.push_back(new _core_bits::RefCopy<From, Node,
+ NodeRefMap, NodeRef>(map));
+ return *this;
+ }
+
+ /// \brief Copy the node cross references into the given map.
+ ///
+ /// This function copies the node cross references (reverse references)
+ /// into the given map. The parameter should be a map, whose key type
+ /// is the Node type of the destination digraph, while the value type is
+ /// the Node type of the source digraph.
+ template <typename NodeCrossRef>
+ DigraphCopy& nodeCrossRef(NodeCrossRef& map) {
+ _node_maps.push_back(new _core_bits::CrossRefCopy<From, Node,
+ NodeRefMap, NodeCrossRef>(map));
+ return *this;
+ }
+
+ /// \brief Make a copy of the given node map.
+ ///
+ /// This function makes a copy of the given node map for the newly
+ /// created digraph.
+ /// The key type of the new map \c tmap should be the Node type of the
+ /// destination digraph, and the key type of the original map \c map
+ /// should be the Node type of the source digraph.
+ template <typename FromMap, typename ToMap>
+ DigraphCopy& nodeMap(const FromMap& map, ToMap& tmap) {
+ _node_maps.push_back(new _core_bits::MapCopy<From, Node,
+ NodeRefMap, FromMap, ToMap>(map, tmap));
+ return *this;
+ }
+
+ /// \brief Make a copy of the given node.
+ ///
+ /// This function makes a copy of the given node.
+ DigraphCopy& node(const Node& node, TNode& tnode) {
+ _node_maps.push_back(new _core_bits::ItemCopy<From, Node,
+ NodeRefMap, TNode>(node, tnode));
+ return *this;
+ }
+
+ /// \brief Copy the arc references into the given map.
+ ///
+ /// This function copies the arc references into the given map.
+ /// The parameter should be a map, whose key type is the Arc type of
+ /// the source digraph, while the value type is the Arc type of the
+ /// destination digraph.
+ template <typename ArcRef>
+ DigraphCopy& arcRef(ArcRef& map) {
+ _arc_maps.push_back(new _core_bits::RefCopy<From, Arc,
+ ArcRefMap, ArcRef>(map));
+ return *this;
+ }
+
+ /// \brief Copy the arc cross references into the given map.
+ ///
+ /// This function copies the arc cross references (reverse references)
+ /// into the given map. The parameter should be a map, whose key type
+ /// is the Arc type of the destination digraph, while the value type is
+ /// the Arc type of the source digraph.
+ template <typename ArcCrossRef>
+ DigraphCopy& arcCrossRef(ArcCrossRef& map) {
+ _arc_maps.push_back(new _core_bits::CrossRefCopy<From, Arc,
+ ArcRefMap, ArcCrossRef>(map));
+ return *this;
+ }
+
+ /// \brief Make a copy of the given arc map.
+ ///
+ /// This function makes a copy of the given arc map for the newly
+ /// created digraph.
+ /// The key type of the new map \c tmap should be the Arc type of the
+ /// destination digraph, and the key type of the original map \c map
+ /// should be the Arc type of the source digraph.
+ template <typename FromMap, typename ToMap>
+ DigraphCopy& arcMap(const FromMap& map, ToMap& tmap) {
+ _arc_maps.push_back(new _core_bits::MapCopy<From, Arc,
+ ArcRefMap, FromMap, ToMap>(map, tmap));
+ return *this;
+ }
+
+ /// \brief Make a copy of the given arc.
+ ///
+ /// This function makes a copy of the given arc.
+ DigraphCopy& arc(const Arc& arc, TArc& tarc) {
+ _arc_maps.push_back(new _core_bits::ItemCopy<From, Arc,
+ ArcRefMap, TArc>(arc, tarc));
+ return *this;
+ }
+
+ /// \brief Execute copying.
+ ///
+ /// This function executes the copying of the digraph along with the
+ /// copying of the assigned data.
+ void run() {
+ NodeRefMap nodeRefMap(_from);
+ ArcRefMap arcRefMap(_from);
+ _core_bits::DigraphCopySelector<To>::
+ copy(_from, _to, nodeRefMap, arcRefMap);
+ for (int i = 0; i < int(_node_maps.size()); ++i) {
+ _node_maps[i]->copy(_from, nodeRefMap);
+ }
+ for (int i = 0; i < int(_arc_maps.size()); ++i) {
+ _arc_maps[i]->copy(_from, arcRefMap);
+ }
+ }
+
+ protected:
+
+ const From& _from;
+ To& _to;
+
+ std::vector<_core_bits::MapCopyBase<From, Node, NodeRefMap>* >
+ _node_maps;
+
+ std::vector<_core_bits::MapCopyBase<From, Arc, ArcRefMap>* >
+ _arc_maps;
+
+ };
+
+ /// \brief Copy a digraph to another digraph.
+ ///
+ /// This function copies a digraph to another digraph.
+ /// The complete usage of it is detailed in the DigraphCopy class, but
+ /// a short example shows a basic work:
+ ///\code
+ /// digraphCopy(src, trg).nodeRef(nr).arcCrossRef(acr).run();
+ ///\endcode
+ ///
+ /// After the copy the \c nr map will contain the mapping from the
+ /// nodes of the \c from digraph to the nodes of the \c to digraph and
+ /// \c acr will contain the mapping from the arcs of the \c to digraph
+ /// to the arcs of the \c from digraph.
+ ///
+ /// \see DigraphCopy
+ template <typename From, typename To>
+ DigraphCopy<From, To> digraphCopy(const From& from, To& to) {
+ return DigraphCopy<From, To>(from, to);
+ }
+
+ /// \brief Class to copy a graph.
+ ///
+ /// Class to copy a graph to another graph (duplicate a graph). The
+ /// simplest way of using it is through the \c graphCopy() function.
+ ///
+ /// This class not only make a copy of a graph, but it can create
+ /// references and cross references between the nodes, edges and arcs of
+ /// the two graphs, and it can copy maps for using with the newly created
+ /// graph.
+ ///
+ /// To make a copy from a graph, first an instance of GraphCopy
+ /// should be created, then the data belongs to the graph should
+ /// assigned to copy. In the end, the \c run() member should be
+ /// called.
+ ///
+ /// The next code copies a graph with several data:
+ ///\code
+ /// GraphCopy<OrigGraph, NewGraph> cg(orig_graph, new_graph);
+ /// // Create references for the nodes
+ /// OrigGraph::NodeMap<NewGraph::Node> nr(orig_graph);
+ /// cg.nodeRef(nr);
+ /// // Create cross references (inverse) for the edges
+ /// NewGraph::EdgeMap<OrigGraph::Edge> ecr(new_graph);
+ /// cg.edgeCrossRef(ecr);
+ /// // Copy an edge map
+ /// OrigGraph::EdgeMap<double> oemap(orig_graph);
+ /// NewGraph::EdgeMap<double> nemap(new_graph);
+ /// cg.edgeMap(oemap, nemap);
+ /// // Copy a node
+ /// OrigGraph::Node on;
+ /// NewGraph::Node nn;
+ /// cg.node(on, nn);
+ /// // Execute copying
+ /// cg.run();
+ ///\endcode
+ template <typename From, typename To>
+ class GraphCopy {
+ private:
+
+ typedef typename From::Node Node;
+ typedef typename From::NodeIt NodeIt;
+ typedef typename From::Arc Arc;
+ typedef typename From::ArcIt ArcIt;
+ typedef typename From::Edge Edge;
+ typedef typename From::EdgeIt EdgeIt;
+
+ typedef typename To::Node TNode;
+ typedef typename To::Arc TArc;
+ typedef typename To::Edge TEdge;
+
+ typedef typename From::template NodeMap<TNode> NodeRefMap;
+ typedef typename From::template EdgeMap<TEdge> EdgeRefMap;
+
+ struct ArcRefMap {
+ ArcRefMap(const From& from, const To& to,
+ const EdgeRefMap& edge_ref, const NodeRefMap& node_ref)
+ : _from(from), _to(to),
+ _edge_ref(edge_ref), _node_ref(node_ref) {}
+
+ typedef typename From::Arc Key;
+ typedef typename To::Arc Value;
+
+ Value operator[](const Key& key) const {
+ bool forward = _from.u(key) != _from.v(key) ?
+ _node_ref[_from.source(key)] ==
+ _to.source(_to.direct(_edge_ref[key], true)) :
+ _from.direction(key);
+ return _to.direct(_edge_ref[key], forward);
+ }
+
+ const From& _from;
+ const To& _to;
+ const EdgeRefMap& _edge_ref;
+ const NodeRefMap& _node_ref;
+ };
+
+ public:
+
+ /// \brief Constructor of GraphCopy.
+ ///
+ /// Constructor of GraphCopy for copying the content of the
+ /// \c from graph into the \c to graph.
+ GraphCopy(const From& from, To& to)
+ : _from(from), _to(to) {}
+
+ /// \brief Destructor of GraphCopy
+ ///
+ /// Destructor of GraphCopy.
+ ~GraphCopy() {
+ for (int i = 0; i < int(_node_maps.size()); ++i) {
+ delete _node_maps[i];
+ }
+ for (int i = 0; i < int(_arc_maps.size()); ++i) {
+ delete _arc_maps[i];
+ }
+ for (int i = 0; i < int(_edge_maps.size()); ++i) {
+ delete _edge_maps[i];
+ }
+ }
+
+ /// \brief Copy the node references into the given map.
+ ///
+ /// This function copies the node references into the given map.
+ /// The parameter should be a map, whose key type is the Node type of
+ /// the source graph, while the value type is the Node type of the
+ /// destination graph.
+ template <typename NodeRef>
+ GraphCopy& nodeRef(NodeRef& map) {
+ _node_maps.push_back(new _core_bits::RefCopy<From, Node,
+ NodeRefMap, NodeRef>(map));
+ return *this;
+ }
+
+ /// \brief Copy the node cross references into the given map.
+ ///
+ /// This function copies the node cross references (reverse references)
+ /// into the given map. The parameter should be a map, whose key type
+ /// is the Node type of the destination graph, while the value type is
+ /// the Node type of the source graph.
+ template <typename NodeCrossRef>
+ GraphCopy& nodeCrossRef(NodeCrossRef& map) {
+ _node_maps.push_back(new _core_bits::CrossRefCopy<From, Node,
+ NodeRefMap, NodeCrossRef>(map));
+ return *this;
+ }
+
+ /// \brief Make a copy of the given node map.
+ ///
+ /// This function makes a copy of the given node map for the newly
+ /// created graph.
+ /// The key type of the new map \c tmap should be the Node type of the
+ /// destination graph, and the key type of the original map \c map
+ /// should be the Node type of the source graph.
+ template <typename FromMap, typename ToMap>
+ GraphCopy& nodeMap(const FromMap& map, ToMap& tmap) {
+ _node_maps.push_back(new _core_bits::MapCopy<From, Node,
+ NodeRefMap, FromMap, ToMap>(map, tmap));
+ return *this;
+ }
+
+ /// \brief Make a copy of the given node.
+ ///
+ /// This function makes a copy of the given node.
+ GraphCopy& node(const Node& node, TNode& tnode) {
+ _node_maps.push_back(new _core_bits::ItemCopy<From, Node,
+ NodeRefMap, TNode>(node, tnode));
+ return *this;
+ }
+
+ /// \brief Copy the arc references into the given map.
+ ///
+ /// This function copies the arc references into the given map.
+ /// The parameter should be a map, whose key type is the Arc type of
+ /// the source graph, while the value type is the Arc type of the
+ /// destination graph.
+ template <typename ArcRef>
+ GraphCopy& arcRef(ArcRef& map) {
+ _arc_maps.push_back(new _core_bits::RefCopy<From, Arc,
+ ArcRefMap, ArcRef>(map));
+ return *this;
+ }
+
+ /// \brief Copy the arc cross references into the given map.
+ ///
+ /// This function copies the arc cross references (reverse references)
+ /// into the given map. The parameter should be a map, whose key type
+ /// is the Arc type of the destination graph, while the value type is
+ /// the Arc type of the source graph.
+ template <typename ArcCrossRef>
+ GraphCopy& arcCrossRef(ArcCrossRef& map) {
+ _arc_maps.push_back(new _core_bits::CrossRefCopy<From, Arc,
+ ArcRefMap, ArcCrossRef>(map));
+ return *this;
+ }
+
+ /// \brief Make a copy of the given arc map.
+ ///
+ /// This function makes a copy of the given arc map for the newly
+ /// created graph.
+ /// The key type of the new map \c tmap should be the Arc type of the
+ /// destination graph, and the key type of the original map \c map
+ /// should be the Arc type of the source graph.
+ template <typename FromMap, typename ToMap>
+ GraphCopy& arcMap(const FromMap& map, ToMap& tmap) {
+ _arc_maps.push_back(new _core_bits::MapCopy<From, Arc,
+ ArcRefMap, FromMap, ToMap>(map, tmap));
+ return *this;
+ }
+
+ /// \brief Make a copy of the given arc.
+ ///
+ /// This function makes a copy of the given arc.
+ GraphCopy& arc(const Arc& arc, TArc& tarc) {
+ _arc_maps.push_back(new _core_bits::ItemCopy<From, Arc,
+ ArcRefMap, TArc>(arc, tarc));
+ return *this;
+ }
+
+ /// \brief Copy the edge references into the given map.
+ ///
+ /// This function copies the edge references into the given map.
+ /// The parameter should be a map, whose key type is the Edge type of
+ /// the source graph, while the value type is the Edge type of the
+ /// destination graph.
+ template <typename EdgeRef>
+ GraphCopy& edgeRef(EdgeRef& map) {
+ _edge_maps.push_back(new _core_bits::RefCopy<From, Edge,
+ EdgeRefMap, EdgeRef>(map));
+ return *this;
+ }
+
+ /// \brief Copy the edge cross references into the given map.
+ ///
+ /// This function copies the edge cross references (reverse references)
+ /// into the given map. The parameter should be a map, whose key type
+ /// is the Edge type of the destination graph, while the value type is
+ /// the Edge type of the source graph.
+ template <typename EdgeCrossRef>
+ GraphCopy& edgeCrossRef(EdgeCrossRef& map) {
+ _edge_maps.push_back(new _core_bits::CrossRefCopy<From,
+ Edge, EdgeRefMap, EdgeCrossRef>(map));
+ return *this;
+ }
+
+ /// \brief Make a copy of the given edge map.
+ ///
+ /// This function makes a copy of the given edge map for the newly
+ /// created graph.
+ /// The key type of the new map \c tmap should be the Edge type of the
+ /// destination graph, and the key type of the original map \c map
+ /// should be the Edge type of the source graph.
+ template <typename FromMap, typename ToMap>
+ GraphCopy& edgeMap(const FromMap& map, ToMap& tmap) {
+ _edge_maps.push_back(new _core_bits::MapCopy<From, Edge,
+ EdgeRefMap, FromMap, ToMap>(map, tmap));
+ return *this;
+ }
+
+ /// \brief Make a copy of the given edge.
+ ///
+ /// This function makes a copy of the given edge.
+ GraphCopy& edge(const Edge& edge, TEdge& tedge) {
+ _edge_maps.push_back(new _core_bits::ItemCopy<From, Edge,
+ EdgeRefMap, TEdge>(edge, tedge));
+ return *this;
+ }
+
+ /// \brief Execute copying.
+ ///
+ /// This function executes the copying of the graph along with the
+ /// copying of the assigned data.
+ void run() {
+ NodeRefMap nodeRefMap(_from);
+ EdgeRefMap edgeRefMap(_from);
+ ArcRefMap arcRefMap(_from, _to, edgeRefMap, nodeRefMap);
+ _core_bits::GraphCopySelector<To>::
+ copy(_from, _to, nodeRefMap, edgeRefMap);
+ for (int i = 0; i < int(_node_maps.size()); ++i) {
+ _node_maps[i]->copy(_from, nodeRefMap);
+ }
+ for (int i = 0; i < int(_edge_maps.size()); ++i) {
+ _edge_maps[i]->copy(_from, edgeRefMap);
+ }
+ for (int i = 0; i < int(_arc_maps.size()); ++i) {
+ _arc_maps[i]->copy(_from, arcRefMap);
+ }
+ }
+
+ private:
+
+ const From& _from;
+ To& _to;
+
+ std::vector<_core_bits::MapCopyBase<From, Node, NodeRefMap>* >
+ _node_maps;
+
+ std::vector<_core_bits::MapCopyBase<From, Arc, ArcRefMap>* >
+ _arc_maps;
+
+ std::vector<_core_bits::MapCopyBase<From, Edge, EdgeRefMap>* >
+ _edge_maps;
+
+ };
+
+ /// \brief Copy a graph to another graph.
+ ///
+ /// This function copies a graph to another graph.
+ /// The complete usage of it is detailed in the GraphCopy class,
+ /// but a short example shows a basic work:
+ ///\code
+ /// graphCopy(src, trg).nodeRef(nr).edgeCrossRef(ecr).run();
+ ///\endcode
+ ///
+ /// After the copy the \c nr map will contain the mapping from the
+ /// nodes of the \c from graph to the nodes of the \c to graph and
+ /// \c ecr will contain the mapping from the edges of the \c to graph
+ /// to the edges of the \c from graph.
+ ///
+ /// \see GraphCopy
+ template <typename From, typename To>
+ GraphCopy<From, To>
+ graphCopy(const From& from, To& to) {
+ return GraphCopy<From, To>(from, to);
+ }
+
+ /// \brief Class to copy a bipartite graph.
+ ///
+ /// Class to copy a bipartite graph to another graph (duplicate a
+ /// graph). The simplest way of using it is through the
+ /// \c bpGraphCopy() function.
+ ///
+ /// This class not only make a copy of a bipartite graph, but it can
+ /// create references and cross references between the nodes, edges
+ /// and arcs of the two graphs, and it can copy maps for using with
+ /// the newly created graph.
+ ///
+ /// To make a copy from a graph, first an instance of BpGraphCopy
+ /// should be created, then the data belongs to the graph should
+ /// assigned to copy. In the end, the \c run() member should be
+ /// called.
+ ///
+ /// The next code copies a graph with several data:
+ ///\code
+ /// BpGraphCopy<OrigBpGraph, NewBpGraph> cg(orig_graph, new_graph);
+ /// // Create references for the nodes
+ /// OrigBpGraph::NodeMap<NewBpGraph::Node> nr(orig_graph);
+ /// cg.nodeRef(nr);
+ /// // Create cross references (inverse) for the edges
+ /// NewBpGraph::EdgeMap<OrigBpGraph::Edge> ecr(new_graph);
+ /// cg.edgeCrossRef(ecr);
+ /// // Copy a red node map
+ /// OrigBpGraph::RedNodeMap<double> ormap(orig_graph);
+ /// NewBpGraph::RedNodeMap<double> nrmap(new_graph);
+ /// cg.redNodeMap(ormap, nrmap);
+ /// // Copy a node
+ /// OrigBpGraph::Node on;
+ /// NewBpGraph::Node nn;
+ /// cg.node(on, nn);
+ /// // Execute copying
+ /// cg.run();
+ ///\endcode
+ template <typename From, typename To>
+ class BpGraphCopy {
+ private:
+
+ typedef typename From::Node Node;
+ typedef typename From::RedNode RedNode;
+ typedef typename From::BlueNode BlueNode;
+ typedef typename From::NodeIt NodeIt;
+ typedef typename From::Arc Arc;
+ typedef typename From::ArcIt ArcIt;
+ typedef typename From::Edge Edge;
+ typedef typename From::EdgeIt EdgeIt;
+
+ typedef typename To::Node TNode;
+ typedef typename To::RedNode TRedNode;
+ typedef typename To::BlueNode TBlueNode;
+ typedef typename To::Arc TArc;
+ typedef typename To::Edge TEdge;
+
+ typedef typename From::template RedNodeMap<TRedNode> RedNodeRefMap;
+ typedef typename From::template BlueNodeMap<TBlueNode> BlueNodeRefMap;
+ typedef typename From::template EdgeMap<TEdge> EdgeRefMap;
+
+ struct NodeRefMap {
+ NodeRefMap(const From& from, const RedNodeRefMap& red_node_ref,
+ const BlueNodeRefMap& blue_node_ref)
+ : _from(from), _red_node_ref(red_node_ref),
+ _blue_node_ref(blue_node_ref) {}
+
+ typedef typename From::Node Key;
+ typedef typename To::Node Value;
+
+ Value operator[](const Key& key) const {
+ if (_from.red(key)) {
+ return _red_node_ref[_from.asRedNodeUnsafe(key)];
+ } else {
+ return _blue_node_ref[_from.asBlueNodeUnsafe(key)];
+ }
+ }
+
+ const From& _from;
+ const RedNodeRefMap& _red_node_ref;
+ const BlueNodeRefMap& _blue_node_ref;
+ };
+
+ struct ArcRefMap {
+ ArcRefMap(const From& from, const To& to, const EdgeRefMap& edge_ref)
+ : _from(from), _to(to), _edge_ref(edge_ref) {}
+
+ typedef typename From::Arc Key;
+ typedef typename To::Arc Value;
+
+ Value operator[](const Key& key) const {
+ return _to.direct(_edge_ref[key], _from.direction(key));
+ }
+
+ const From& _from;
+ const To& _to;
+ const EdgeRefMap& _edge_ref;
+ };
+
+ public:
+
+ /// \brief Constructor of BpGraphCopy.
+ ///
+ /// Constructor of BpGraphCopy for copying the content of the
+ /// \c from graph into the \c to graph.
+ BpGraphCopy(const From& from, To& to)
+ : _from(from), _to(to) {}
+
+ /// \brief Destructor of BpGraphCopy
+ ///
+ /// Destructor of BpGraphCopy.
+ ~BpGraphCopy() {
+ for (int i = 0; i < int(_node_maps.size()); ++i) {
+ delete _node_maps[i];
+ }
+ for (int i = 0; i < int(_red_maps.size()); ++i) {
+ delete _red_maps[i];
+ }
+ for (int i = 0; i < int(_blue_maps.size()); ++i) {
+ delete _blue_maps[i];
+ }
+ for (int i = 0; i < int(_arc_maps.size()); ++i) {
+ delete _arc_maps[i];
+ }
+ for (int i = 0; i < int(_edge_maps.size()); ++i) {
+ delete _edge_maps[i];
+ }
+ }
+
+ /// \brief Copy the node references into the given map.
+ ///
+ /// This function copies the node references into the given map.
+ /// The parameter should be a map, whose key type is the Node type of
+ /// the source graph, while the value type is the Node type of the
+ /// destination graph.
+ template <typename NodeRef>
+ BpGraphCopy& nodeRef(NodeRef& map) {
+ _node_maps.push_back(new _core_bits::RefCopy<From, Node,
+ NodeRefMap, NodeRef>(map));
+ return *this;
+ }
+
+ /// \brief Copy the node cross references into the given map.
+ ///
+ /// This function copies the node cross references (reverse references)
+ /// into the given map. The parameter should be a map, whose key type
+ /// is the Node type of the destination graph, while the value type is
+ /// the Node type of the source graph.
+ template <typename NodeCrossRef>
+ BpGraphCopy& nodeCrossRef(NodeCrossRef& map) {
+ _node_maps.push_back(new _core_bits::CrossRefCopy<From, Node,
+ NodeRefMap, NodeCrossRef>(map));
+ return *this;
+ }
+
+ /// \brief Make a copy of the given node map.
+ ///
+ /// This function makes a copy of the given node map for the newly
+ /// created graph.
+ /// The key type of the new map \c tmap should be the Node type of the
+ /// destination graph, and the key type of the original map \c map
+ /// should be the Node type of the source graph.
+ template <typename FromMap, typename ToMap>
+ BpGraphCopy& nodeMap(const FromMap& map, ToMap& tmap) {
+ _node_maps.push_back(new _core_bits::MapCopy<From, Node,
+ NodeRefMap, FromMap, ToMap>(map, tmap));
+ return *this;
+ }
+
+ /// \brief Make a copy of the given node.
+ ///
+ /// This function makes a copy of the given node.
+ BpGraphCopy& node(const Node& node, TNode& tnode) {
+ _node_maps.push_back(new _core_bits::ItemCopy<From, Node,
+ NodeRefMap, TNode>(node, tnode));
+ return *this;
+ }
+
+ /// \brief Copy the red node references into the given map.
+ ///
+ /// This function copies the red node references into the given
+ /// map. The parameter should be a map, whose key type is the
+ /// Node type of the source graph with the red item set, while the
+ /// value type is the Node type of the destination graph.
+ template <typename RedRef>
+ BpGraphCopy& redRef(RedRef& map) {
+ _red_maps.push_back(new _core_bits::RefCopy<From, RedNode,
+ RedNodeRefMap, RedRef>(map));
+ return *this;
+ }
+
+ /// \brief Copy the red node cross references into the given map.
+ ///
+ /// This function copies the red node cross references (reverse
+ /// references) into the given map. The parameter should be a map,
+ /// whose key type is the Node type of the destination graph with
+ /// the red item set, while the value type is the Node type of the
+ /// source graph.
+ template <typename RedCrossRef>
+ BpGraphCopy& redCrossRef(RedCrossRef& map) {
+ _red_maps.push_back(new _core_bits::CrossRefCopy<From, RedNode,
+ RedNodeRefMap, RedCrossRef>(map));
+ return *this;
+ }
+
+ /// \brief Make a copy of the given red node map.
+ ///
+ /// This function makes a copy of the given red node map for the newly
+ /// created graph.
+ /// The key type of the new map \c tmap should be the Node type of
+ /// the destination graph with the red items, and the key type of
+ /// the original map \c map should be the Node type of the source
+ /// graph.
+ template <typename FromMap, typename ToMap>
+ BpGraphCopy& redNodeMap(const FromMap& map, ToMap& tmap) {
+ _red_maps.push_back(new _core_bits::MapCopy<From, RedNode,
+ RedNodeRefMap, FromMap, ToMap>(map, tmap));
+ return *this;
+ }
+
+ /// \brief Make a copy of the given red node.
+ ///
+ /// This function makes a copy of the given red node.
+ BpGraphCopy& redNode(const RedNode& node, TRedNode& tnode) {
+ _red_maps.push_back(new _core_bits::ItemCopy<From, RedNode,
+ RedNodeRefMap, TRedNode>(node, tnode));
+ return *this;
+ }
+
+ /// \brief Copy the blue node references into the given map.
+ ///
+ /// This function copies the blue node references into the given
+ /// map. The parameter should be a map, whose key type is the
+ /// Node type of the source graph with the blue item set, while the
+ /// value type is the Node type of the destination graph.
+ template <typename BlueRef>
+ BpGraphCopy& blueRef(BlueRef& map) {
+ _blue_maps.push_back(new _core_bits::RefCopy<From, BlueNode,
+ BlueNodeRefMap, BlueRef>(map));
+ return *this;
+ }
+
+ /// \brief Copy the blue node cross references into the given map.
+ ///
+ /// This function copies the blue node cross references (reverse
+ /// references) into the given map. The parameter should be a map,
+ /// whose key type is the Node type of the destination graph with
+ /// the blue item set, while the value type is the Node type of the
+ /// source graph.
+ template <typename BlueCrossRef>
+ BpGraphCopy& blueCrossRef(BlueCrossRef& map) {
+ _blue_maps.push_back(new _core_bits::CrossRefCopy<From, BlueNode,
+ BlueNodeRefMap, BlueCrossRef>(map));
+ return *this;
+ }
+
+ /// \brief Make a copy of the given blue node map.
+ ///
+ /// This function makes a copy of the given blue node map for the newly
+ /// created graph.
+ /// The key type of the new map \c tmap should be the Node type of
+ /// the destination graph with the blue items, and the key type of
+ /// the original map \c map should be the Node type of the source
+ /// graph.
+ template <typename FromMap, typename ToMap>
+ BpGraphCopy& blueNodeMap(const FromMap& map, ToMap& tmap) {
+ _blue_maps.push_back(new _core_bits::MapCopy<From, BlueNode,
+ BlueNodeRefMap, FromMap, ToMap>(map, tmap));
+ return *this;
+ }
+
+ /// \brief Make a copy of the given blue node.
+ ///
+ /// This function makes a copy of the given blue node.
+ BpGraphCopy& blueNode(const BlueNode& node, TBlueNode& tnode) {
+ _blue_maps.push_back(new _core_bits::ItemCopy<From, BlueNode,
+ BlueNodeRefMap, TBlueNode>(node, tnode));
+ return *this;
+ }
+
+ /// \brief Copy the arc references into the given map.
+ ///
+ /// This function copies the arc references into the given map.
+ /// The parameter should be a map, whose key type is the Arc type of
+ /// the source graph, while the value type is the Arc type of the
+ /// destination graph.
+ template <typename ArcRef>
+ BpGraphCopy& arcRef(ArcRef& map) {
+ _arc_maps.push_back(new _core_bits::RefCopy<From, Arc,
+ ArcRefMap, ArcRef>(map));
+ return *this;
+ }
+
+ /// \brief Copy the arc cross references into the given map.
+ ///
+ /// This function copies the arc cross references (reverse references)
+ /// into the given map. The parameter should be a map, whose key type
+ /// is the Arc type of the destination graph, while the value type is
+ /// the Arc type of the source graph.
+ template <typename ArcCrossRef>
+ BpGraphCopy& arcCrossRef(ArcCrossRef& map) {
+ _arc_maps.push_back(new _core_bits::CrossRefCopy<From, Arc,
+ ArcRefMap, ArcCrossRef>(map));
+ return *this;
+ }
+
+ /// \brief Make a copy of the given arc map.
+ ///
+ /// This function makes a copy of the given arc map for the newly
+ /// created graph.
+ /// The key type of the new map \c tmap should be the Arc type of the
+ /// destination graph, and the key type of the original map \c map
+ /// should be the Arc type of the source graph.
+ template <typename FromMap, typename ToMap>
+ BpGraphCopy& arcMap(const FromMap& map, ToMap& tmap) {
+ _arc_maps.push_back(new _core_bits::MapCopy<From, Arc,
+ ArcRefMap, FromMap, ToMap>(map, tmap));
+ return *this;
+ }
+
+ /// \brief Make a copy of the given arc.
+ ///
+ /// This function makes a copy of the given arc.
+ BpGraphCopy& arc(const Arc& arc, TArc& tarc) {
+ _arc_maps.push_back(new _core_bits::ItemCopy<From, Arc,
+ ArcRefMap, TArc>(arc, tarc));
+ return *this;
+ }
+
+ /// \brief Copy the edge references into the given map.
+ ///
+ /// This function copies the edge references into the given map.
+ /// The parameter should be a map, whose key type is the Edge type of
+ /// the source graph, while the value type is the Edge type of the
+ /// destination graph.
+ template <typename EdgeRef>
+ BpGraphCopy& edgeRef(EdgeRef& map) {
+ _edge_maps.push_back(new _core_bits::RefCopy<From, Edge,
+ EdgeRefMap, EdgeRef>(map));
+ return *this;
+ }
+
+ /// \brief Copy the edge cross references into the given map.
+ ///
+ /// This function copies the edge cross references (reverse references)
+ /// into the given map. The parameter should be a map, whose key type
+ /// is the Edge type of the destination graph, while the value type is
+ /// the Edge type of the source graph.
+ template <typename EdgeCrossRef>
+ BpGraphCopy& edgeCrossRef(EdgeCrossRef& map) {
+ _edge_maps.push_back(new _core_bits::CrossRefCopy<From,
+ Edge, EdgeRefMap, EdgeCrossRef>(map));
+ return *this;
+ }
+
+ /// \brief Make a copy of the given edge map.
+ ///
+ /// This function makes a copy of the given edge map for the newly
+ /// created graph.
+ /// The key type of the new map \c tmap should be the Edge type of the
+ /// destination graph, and the key type of the original map \c map
+ /// should be the Edge type of the source graph.
+ template <typename FromMap, typename ToMap>
+ BpGraphCopy& edgeMap(const FromMap& map, ToMap& tmap) {
+ _edge_maps.push_back(new _core_bits::MapCopy<From, Edge,
+ EdgeRefMap, FromMap, ToMap>(map, tmap));
+ return *this;
+ }
+
+ /// \brief Make a copy of the given edge.
+ ///
+ /// This function makes a copy of the given edge.
+ BpGraphCopy& edge(const Edge& edge, TEdge& tedge) {
+ _edge_maps.push_back(new _core_bits::ItemCopy<From, Edge,
+ EdgeRefMap, TEdge>(edge, tedge));
+ return *this;
+ }
+
+ /// \brief Execute copying.
+ ///
+ /// This function executes the copying of the graph along with the
+ /// copying of the assigned data.
+ void run() {
+ RedNodeRefMap redNodeRefMap(_from);
+ BlueNodeRefMap blueNodeRefMap(_from);
+ NodeRefMap nodeRefMap(_from, redNodeRefMap, blueNodeRefMap);
+ EdgeRefMap edgeRefMap(_from);
+ ArcRefMap arcRefMap(_from, _to, edgeRefMap);
+ _core_bits::BpGraphCopySelector<To>::
+ copy(_from, _to, redNodeRefMap, blueNodeRefMap, edgeRefMap);
+ for (int i = 0; i < int(_node_maps.size()); ++i) {
+ _node_maps[i]->copy(_from, nodeRefMap);
+ }
+ for (int i = 0; i < int(_red_maps.size()); ++i) {
+ _red_maps[i]->copy(_from, redNodeRefMap);
+ }
+ for (int i = 0; i < int(_blue_maps.size()); ++i) {
+ _blue_maps[i]->copy(_from, blueNodeRefMap);
+ }
+ for (int i = 0; i < int(_edge_maps.size()); ++i) {
+ _edge_maps[i]->copy(_from, edgeRefMap);
+ }
+ for (int i = 0; i < int(_arc_maps.size()); ++i) {
+ _arc_maps[i]->copy(_from, arcRefMap);
+ }
+ }
+
+ private:
+
+ const From& _from;
+ To& _to;
+
+ std::vector<_core_bits::MapCopyBase<From, Node, NodeRefMap>* >
+ _node_maps;
+
+ std::vector<_core_bits::MapCopyBase<From, RedNode, RedNodeRefMap>* >
+ _red_maps;
+
+ std::vector<_core_bits::MapCopyBase<From, BlueNode, BlueNodeRefMap>* >
+ _blue_maps;
+
+ std::vector<_core_bits::MapCopyBase<From, Arc, ArcRefMap>* >
+ _arc_maps;
+
+ std::vector<_core_bits::MapCopyBase<From, Edge, EdgeRefMap>* >
+ _edge_maps;
+
+ };
+
+ /// \brief Copy a graph to another graph.
+ ///
+ /// This function copies a graph to another graph.
+ /// The complete usage of it is detailed in the BpGraphCopy class,
+ /// but a short example shows a basic work:
+ ///\code
+ /// graphCopy(src, trg).nodeRef(nr).edgeCrossRef(ecr).run();
+ ///\endcode
+ ///
+ /// After the copy the \c nr map will contain the mapping from the
+ /// nodes of the \c from graph to the nodes of the \c to graph and
+ /// \c ecr will contain the mapping from the edges of the \c to graph
+ /// to the edges of the \c from graph.
+ ///
+ /// \see BpGraphCopy
+ template <typename From, typename To>
+ BpGraphCopy<From, To>
+ bpGraphCopy(const From& from, To& to) {
+ return BpGraphCopy<From, To>(from, to);
+ }
+
+ namespace _core_bits {
+
+ template <typename Graph, typename Enable = void>
+ struct FindArcSelector {
+ typedef typename Graph::Node Node;
+ typedef typename Graph::Arc Arc;
+ static Arc find(const Graph &g, Node u, Node v, Arc e) {
+ if (e == INVALID) {
+ g.firstOut(e, u);
+ } else {
+ g.nextOut(e);
+ }
+ while (e != INVALID && g.target(e) != v) {
+ g.nextOut(e);
+ }
+ return e;
+ }
+ };
+
+ template <typename Graph>
+ struct FindArcSelector<
+ Graph,
+ typename enable_if<typename Graph::FindArcTag, void>::type>
+ {
+ typedef typename Graph::Node Node;
+ typedef typename Graph::Arc Arc;
+ static Arc find(const Graph &g, Node u, Node v, Arc prev) {
+ return g.findArc(u, v, prev);
+ }
+ };
+ }
+
+ /// \brief Find an arc between two nodes of a digraph.
+ ///
+ /// This function finds an arc from node \c u to node \c v in the
+ /// digraph \c g.
+ ///
+ /// If \c prev is \ref INVALID (this is the default value), then
+ /// it finds the first arc from \c u to \c v. Otherwise it looks for
+ /// the next arc from \c u to \c v after \c prev.
+ /// \return The found arc or \ref INVALID if there is no such an arc.
+ ///
+ /// Thus you can iterate through each arc from \c u to \c v as it follows.
+ ///\code
+ /// for(Arc e = findArc(g,u,v); e != INVALID; e = findArc(g,u,v,e)) {
+ /// ...
+ /// }
+ ///\endcode
+ ///
+ /// \note \ref ConArcIt provides iterator interface for the same
+ /// functionality.
+ ///
+ ///\sa ConArcIt
+ ///\sa ArcLookUp, AllArcLookUp, DynArcLookUp
+ template <typename Graph>
+ inline typename Graph::Arc
+ findArc(const Graph &g, typename Graph::Node u, typename Graph::Node v,
+ typename Graph::Arc prev = INVALID) {
+ return _core_bits::FindArcSelector<Graph>::find(g, u, v, prev);
+ }
+
+ /// \brief Iterator for iterating on parallel arcs connecting the same nodes.
+ ///
+ /// Iterator for iterating on parallel arcs connecting the same nodes. It is
+ /// a higher level interface for the \ref findArc() function. You can
+ /// use it the following way:
+ ///\code
+ /// for (ConArcIt<Graph> it(g, src, trg); it != INVALID; ++it) {
+ /// ...
+ /// }
+ ///\endcode
+ ///
+ ///\sa findArc()
+ ///\sa ArcLookUp, AllArcLookUp, DynArcLookUp
+ template <typename GR>
+ class ConArcIt : public GR::Arc {
+ typedef typename GR::Arc Parent;
+
+ public:
+
+ typedef typename GR::Arc Arc;
+ typedef typename GR::Node Node;
+
+ /// \brief Constructor.
+ ///
+ /// Construct a new ConArcIt iterating on the arcs that
+ /// connects nodes \c u and \c v.
+ ConArcIt(const GR& g, Node u, Node v) : _graph(g) {
+ Parent::operator=(findArc(_graph, u, v));
+ }
+
+ /// \brief Constructor.
+ ///
+ /// Construct a new ConArcIt that continues the iterating from arc \c a.
+ ConArcIt(const GR& g, Arc a) : Parent(a), _graph(g) {}
+
+ /// \brief Increment operator.
+ ///
+ /// It increments the iterator and gives back the next arc.
+ ConArcIt& operator++() {
+ Parent::operator=(findArc(_graph, _graph.source(*this),
+ _graph.target(*this), *this));
+ return *this;
+ }
+ private:
+ const GR& _graph;
+ };
+
+ namespace _core_bits {
+
+ template <typename Graph, typename Enable = void>
+ struct FindEdgeSelector {
+ typedef typename Graph::Node Node;
+ typedef typename Graph::Edge Edge;
+ static Edge find(const Graph &g, Node u, Node v, Edge e) {
+ bool b;
+ if (u != v) {
+ if (e == INVALID) {
+ g.firstInc(e, b, u);
+ } else {
+ b = g.u(e) == u;
+ g.nextInc(e, b);
+ }
+ while (e != INVALID && (b ? g.v(e) : g.u(e)) != v) {
+ g.nextInc(e, b);
+ }
+ } else {
+ if (e == INVALID) {
+ g.firstInc(e, b, u);
+ } else {
+ b = true;
+ g.nextInc(e, b);
+ }
+ while (e != INVALID && (!b || g.v(e) != v)) {
+ g.nextInc(e, b);
+ }
+ }
+ return e;
+ }
+ };
+
+ template <typename Graph>
+ struct FindEdgeSelector<
+ Graph,
+ typename enable_if<typename Graph::FindEdgeTag, void>::type>
+ {
+ typedef typename Graph::Node Node;
+ typedef typename Graph::Edge Edge;
+ static Edge find(const Graph &g, Node u, Node v, Edge prev) {
+ return g.findEdge(u, v, prev);
+ }
+ };
+ }
+
+ /// \brief Find an edge between two nodes of a graph.
+ ///
+ /// This function finds an edge from node \c u to node \c v in graph \c g.
+ /// If node \c u and node \c v is equal then each loop edge
+ /// will be enumerated once.
+ ///
+ /// If \c prev is \ref INVALID (this is the default value), then
+ /// it finds the first edge from \c u to \c v. Otherwise it looks for
+ /// the next edge from \c u to \c v after \c prev.
+ /// \return The found edge or \ref INVALID if there is no such an edge.
+ ///
+ /// Thus you can iterate through each edge between \c u and \c v
+ /// as it follows.
+ ///\code
+ /// for(Edge e = findEdge(g,u,v); e != INVALID; e = findEdge(g,u,v,e)) {
+ /// ...
+ /// }
+ ///\endcode
+ ///
+ /// \note \ref ConEdgeIt provides iterator interface for the same
+ /// functionality.
+ ///
+ ///\sa ConEdgeIt
+ template <typename Graph>
+ inline typename Graph::Edge
+ findEdge(const Graph &g, typename Graph::Node u, typename Graph::Node v,
+ typename Graph::Edge p = INVALID) {
+ return _core_bits::FindEdgeSelector<Graph>::find(g, u, v, p);
+ }
+
+ /// \brief Iterator for iterating on parallel edges connecting the same nodes.
+ ///
+ /// Iterator for iterating on parallel edges connecting the same nodes.
+ /// It is a higher level interface for the findEdge() function. You can
+ /// use it the following way:
+ ///\code
+ /// for (ConEdgeIt<Graph> it(g, u, v); it != INVALID; ++it) {
+ /// ...
+ /// }
+ ///\endcode
+ ///
+ ///\sa findEdge()
+ template <typename GR>
+ class ConEdgeIt : public GR::Edge {
+ typedef typename GR::Edge Parent;
+
+ public:
+
+ typedef typename GR::Edge Edge;
+ typedef typename GR::Node Node;
+
+ /// \brief Constructor.
+ ///
+ /// Construct a new ConEdgeIt iterating on the edges that
+ /// connects nodes \c u and \c v.
+ ConEdgeIt(const GR& g, Node u, Node v) : _graph(g), _u(u), _v(v) {
+ Parent::operator=(findEdge(_graph, _u, _v));
+ }
+
+ /// \brief Constructor.
+ ///
+ /// Construct a new ConEdgeIt that continues iterating from edge \c e.
+ ConEdgeIt(const GR& g, Edge e) : Parent(e), _graph(g) {}
+
+ /// \brief Increment operator.
+ ///
+ /// It increments the iterator and gives back the next edge.
+ ConEdgeIt& operator++() {
+ Parent::operator=(findEdge(_graph, _u, _v, *this));
+ return *this;
+ }
+ private:
+ const GR& _graph;
+ Node _u, _v;
+ };
+
+
+ ///Dynamic arc look-up between given endpoints.
+
+ ///Using this class, you can find an arc in a digraph from a given
+ ///source to a given target in amortized time <em>O</em>(log<em>d</em>),
+ ///where <em>d</em> is the out-degree of the source node.
+ ///
+ ///It is possible to find \e all parallel arcs between two nodes with
+ ///the \c operator() member.
+ ///
+ ///This is a dynamic data structure. Consider to use \ref ArcLookUp or
+ ///\ref AllArcLookUp if your digraph is not changed so frequently.
+ ///
+ ///This class uses a self-adjusting binary search tree, the Splay tree
+ ///of Sleator and Tarjan to guarantee the logarithmic amortized
+ ///time bound for arc look-ups. This class also guarantees the
+ ///optimal time bound in a constant factor for any distribution of
+ ///queries.
+ ///
+ ///\tparam GR The type of the underlying digraph.
+ ///
+ ///\sa ArcLookUp
+ ///\sa AllArcLookUp
+ template <typename GR>
+ class DynArcLookUp
+ : protected ItemSetTraits<GR, typename GR::Arc>::ItemNotifier::ObserverBase
+ {
+ typedef typename ItemSetTraits<GR, typename GR::Arc>
+ ::ItemNotifier::ObserverBase Parent;
+
+ TEMPLATE_DIGRAPH_TYPEDEFS(GR);
+
+ public:
+
+ /// The Digraph type
+ typedef GR Digraph;
+
+ protected:
+
+ class AutoNodeMap : public ItemSetTraits<GR, Node>::template Map<Arc>::Type
+ {
+ typedef typename ItemSetTraits<GR, Node>::template Map<Arc>::Type Parent;
+
+ public:
+
+ AutoNodeMap(const GR& digraph) : Parent(digraph, INVALID) {}
+
+ virtual void add(const Node& node) {
+ Parent::add(node);
+ Parent::set(node, INVALID);
+ }
+
+ virtual void add(const std::vector<Node>& nodes) {
+ Parent::add(nodes);
+ for (int i = 0; i < int(nodes.size()); ++i) {
+ Parent::set(nodes[i], INVALID);
+ }
+ }
+
+ virtual void build() {
+ Parent::build();
+ Node it;
+ typename Parent::Notifier* nf = Parent::notifier();
+ for (nf->first(it); it != INVALID; nf->next(it)) {
+ Parent::set(it, INVALID);
+ }
+ }
+ };
+
+ class ArcLess {
+ const Digraph &g;
+ public:
+ ArcLess(const Digraph &_g) : g(_g) {}
+ bool operator()(Arc a,Arc b) const
+ {
+ return g.target(a)<g.target(b);
+ }
+ };
+
+ protected:
+
+ const Digraph &_g;
+ AutoNodeMap _head;
+ typename Digraph::template ArcMap<Arc> _parent;
+ typename Digraph::template ArcMap<Arc> _left;
+ typename Digraph::template ArcMap<Arc> _right;
+
+ public:
+
+ ///Constructor
+
+ ///Constructor.
+ ///
+ ///It builds up the search database.
+ DynArcLookUp(const Digraph &g)
+ : _g(g),_head(g),_parent(g),_left(g),_right(g)
+ {
+ Parent::attach(_g.notifier(typename Digraph::Arc()));
+ refresh();
+ }
+
+ protected:
+
+ virtual void add(const Arc& arc) {
+ insert(arc);
+ }
+
+ virtual void add(const std::vector<Arc>& arcs) {
+ for (int i = 0; i < int(arcs.size()); ++i) {
+ insert(arcs[i]);
+ }
+ }
+
+ virtual void erase(const Arc& arc) {
+ remove(arc);
+ }
+
+ virtual void erase(const std::vector<Arc>& arcs) {
+ for (int i = 0; i < int(arcs.size()); ++i) {
+ remove(arcs[i]);
+ }
+ }
+
+ virtual void build() {
+ refresh();
+ }
+
+ virtual void clear() {
+ for(NodeIt n(_g);n!=INVALID;++n) {
+ _head[n] = INVALID;
+ }
+ }
+
+ void insert(Arc arc) {
+ Node s = _g.source(arc);
+ Node t = _g.target(arc);
+ _left[arc] = INVALID;
+ _right[arc] = INVALID;
+
+ Arc e = _head[s];
+ if (e == INVALID) {
+ _head[s] = arc;
+ _parent[arc] = INVALID;
+ return;
+ }
+ while (true) {
+ if (t < _g.target(e)) {
+ if (_left[e] == INVALID) {
+ _left[e] = arc;
+ _parent[arc] = e;
+ splay(arc);
+ return;
+ } else {
+ e = _left[e];
+ }
+ } else {
+ if (_right[e] == INVALID) {
+ _right[e] = arc;
+ _parent[arc] = e;
+ splay(arc);
+ return;
+ } else {
+ e = _right[e];
+ }
+ }
+ }
+ }
+
+ void remove(Arc arc) {
+ if (_left[arc] == INVALID) {
+ if (_right[arc] != INVALID) {
+ _parent[_right[arc]] = _parent[arc];
+ }
+ if (_parent[arc] != INVALID) {
+ if (_left[_parent[arc]] == arc) {
+ _left[_parent[arc]] = _right[arc];
+ } else {
+ _right[_parent[arc]] = _right[arc];
+ }
+ } else {
+ _head[_g.source(arc)] = _right[arc];
+ }
+ } else if (_right[arc] == INVALID) {
+ _parent[_left[arc]] = _parent[arc];
+ if (_parent[arc] != INVALID) {
+ if (_left[_parent[arc]] == arc) {
+ _left[_parent[arc]] = _left[arc];
+ } else {
+ _right[_parent[arc]] = _left[arc];
+ }
+ } else {
+ _head[_g.source(arc)] = _left[arc];
+ }
+ } else {
+ Arc e = _left[arc];
+ if (_right[e] != INVALID) {
+ e = _right[e];
+ while (_right[e] != INVALID) {
+ e = _right[e];
+ }
+ Arc s = _parent[e];
+ _right[_parent[e]] = _left[e];
+ if (_left[e] != INVALID) {
+ _parent[_left[e]] = _parent[e];
+ }
+
+ _left[e] = _left[arc];
+ _parent[_left[arc]] = e;
+ _right[e] = _right[arc];
+ _parent[_right[arc]] = e;
+
+ _parent[e] = _parent[arc];
+ if (_parent[arc] != INVALID) {
+ if (_left[_parent[arc]] == arc) {
+ _left[_parent[arc]] = e;
+ } else {
+ _right[_parent[arc]] = e;
+ }
+ }
+ splay(s);
+ } else {
+ _right[e] = _right[arc];
+ _parent[_right[arc]] = e;
+ _parent[e] = _parent[arc];
+
+ if (_parent[arc] != INVALID) {
+ if (_left[_parent[arc]] == arc) {
+ _left[_parent[arc]] = e;
+ } else {
+ _right[_parent[arc]] = e;
+ }
+ } else {
+ _head[_g.source(arc)] = e;
+ }
+ }
+ }
+ }
+
+ Arc refreshRec(std::vector<Arc> &v,int a,int b)
+ {
+ int m=(a+b)/2;
+ Arc me=v[m];
+ if (a < m) {
+ Arc left = refreshRec(v,a,m-1);
+ _left[me] = left;
+ _parent[left] = me;
+ } else {
+ _left[me] = INVALID;
+ }
+ if (m < b) {
+ Arc right = refreshRec(v,m+1,b);
+ _right[me] = right;
+ _parent[right] = me;
+ } else {
+ _right[me] = INVALID;
+ }
+ return me;
+ }
+
+ void refresh() {
+ for(NodeIt n(_g);n!=INVALID;++n) {
+ std::vector<Arc> v;
+ for(OutArcIt a(_g,n);a!=INVALID;++a) v.push_back(a);
+ if (!v.empty()) {
+ std::sort(v.begin(),v.end(),ArcLess(_g));
+ Arc head = refreshRec(v,0,v.size()-1);
+ _head[n] = head;
+ _parent[head] = INVALID;
+ }
+ else _head[n] = INVALID;
+ }
+ }
+
+ void zig(Arc v) {
+ Arc w = _parent[v];
+ _parent[v] = _parent[w];
+ _parent[w] = v;
+ _left[w] = _right[v];
+ _right[v] = w;
+ if (_parent[v] != INVALID) {
+ if (_right[_parent[v]] == w) {
+ _right[_parent[v]] = v;
+ } else {
+ _left[_parent[v]] = v;
+ }
+ }
+ if (_left[w] != INVALID){
+ _parent[_left[w]] = w;
+ }
+ }
+
+ void zag(Arc v) {
+ Arc w = _parent[v];
+ _parent[v] = _parent[w];
+ _parent[w] = v;
+ _right[w] = _left[v];
+ _left[v] = w;
+ if (_parent[v] != INVALID){
+ if (_left[_parent[v]] == w) {
+ _left[_parent[v]] = v;
+ } else {
+ _right[_parent[v]] = v;
+ }
+ }
+ if (_right[w] != INVALID){
+ _parent[_right[w]] = w;
+ }
+ }
+
+ void splay(Arc v) {
+ while (_parent[v] != INVALID) {
+ if (v == _left[_parent[v]]) {
+ if (_parent[_parent[v]] == INVALID) {
+ zig(v);
+ } else {
+ if (_parent[v] == _left[_parent[_parent[v]]]) {
+ zig(_parent[v]);
+ zig(v);
+ } else {
+ zig(v);
+ zag(v);
+ }
+ }
+ } else {
+ if (_parent[_parent[v]] == INVALID) {
+ zag(v);
+ } else {
+ if (_parent[v] == _left[_parent[_parent[v]]]) {
+ zag(v);
+ zig(v);
+ } else {
+ zag(_parent[v]);
+ zag(v);
+ }
+ }
+ }
+ }
+ _head[_g.source(v)] = v;
+ }
+
+
+ public:
+
+ ///Find an arc between two nodes.
+
+ ///Find an arc between two nodes.
+ ///\param s The source node.
+ ///\param t The target node.
+ ///\param p The previous arc between \c s and \c t. It it is INVALID or
+ ///not given, the operator finds the first appropriate arc.
+ ///\return An arc from \c s to \c t after \c p or
+ ///\ref INVALID if there is no more.
+ ///
+ ///For example, you can count the number of arcs from \c u to \c v in the
+ ///following way.
+ ///\code
+ ///DynArcLookUp<ListDigraph> ae(g);
+ ///...
+ ///int n = 0;
+ ///for(Arc a = ae(u,v); a != INVALID; a = ae(u,v,a)) n++;
+ ///\endcode
+ ///
+ ///Finding the arcs take at most <em>O</em>(log<em>d</em>)
+ ///amortized time, specifically, the time complexity of the lookups
+ ///is equal to the optimal search tree implementation for the
+ ///current query distribution in a constant factor.
+ ///
+ ///\note This is a dynamic data structure, therefore the data
+ ///structure is updated after each graph alteration. Thus although
+ ///this data structure is theoretically faster than \ref ArcLookUp
+ ///and \ref AllArcLookUp, it often provides worse performance than
+ ///them.
+ Arc operator()(Node s, Node t, Arc p = INVALID) const {
+ if (p == INVALID) {
+ Arc a = _head[s];
+ if (a == INVALID) return INVALID;
+ Arc r = INVALID;
+ while (true) {
+ if (_g.target(a) < t) {
+ if (_right[a] == INVALID) {
+ const_cast<DynArcLookUp&>(*this).splay(a);
+ return r;
+ } else {
+ a = _right[a];
+ }
+ } else {
+ if (_g.target(a) == t) {
+ r = a;
+ }
+ if (_left[a] == INVALID) {
+ const_cast<DynArcLookUp&>(*this).splay(a);
+ return r;
+ } else {
+ a = _left[a];
+ }
+ }
+ }
+ } else {
+ Arc a = p;
+ if (_right[a] != INVALID) {
+ a = _right[a];
+ while (_left[a] != INVALID) {
+ a = _left[a];
+ }
+ const_cast<DynArcLookUp&>(*this).splay(a);
+ } else {
+ while (_parent[a] != INVALID && _right[_parent[a]] == a) {
+ a = _parent[a];
+ }
+ if (_parent[a] == INVALID) {
+ return INVALID;
+ } else {
+ a = _parent[a];
+ const_cast<DynArcLookUp&>(*this).splay(a);
+ }
+ }
+ if (_g.target(a) == t) return a;
+ else return INVALID;
+ }
+ }
+
+ };
+
+ ///Fast arc look-up between given endpoints.
+
+ ///Using this class, you can find an arc in a digraph from a given
+ ///source to a given target in time <em>O</em>(log<em>d</em>),
+ ///where <em>d</em> is the out-degree of the source node.
+ ///
+ ///It is not possible to find \e all parallel arcs between two nodes.
+ ///Use \ref AllArcLookUp for this purpose.
+ ///
+ ///\warning This class is static, so you should call refresh() (or at
+ ///least refresh(Node)) to refresh this data structure whenever the
+ ///digraph changes. This is a time consuming (superlinearly proportional
+ ///(<em>O</em>(<em>m</em> log<em>m</em>)) to the number of arcs).
+ ///
+ ///\tparam GR The type of the underlying digraph.
+ ///
+ ///\sa DynArcLookUp
+ ///\sa AllArcLookUp
+ template<class GR>
+ class ArcLookUp
+ {
+ TEMPLATE_DIGRAPH_TYPEDEFS(GR);
+
+ public:
+
+ /// The Digraph type
+ typedef GR Digraph;
+
+ protected:
+ const Digraph &_g;
+ typename Digraph::template NodeMap<Arc> _head;
+ typename Digraph::template ArcMap<Arc> _left;
+ typename Digraph::template ArcMap<Arc> _right;
+
+ class ArcLess {
+ const Digraph &g;
+ public:
+ ArcLess(const Digraph &_g) : g(_g) {}
+ bool operator()(Arc a,Arc b) const
+ {
+ return g.target(a)<g.target(b);
+ }
+ };
+
+ public:
+
+ ///Constructor
+
+ ///Constructor.
+ ///
+ ///It builds up the search database, which remains valid until the digraph
+ ///changes.
+ ArcLookUp(const Digraph &g) :_g(g),_head(g),_left(g),_right(g) {refresh();}
+
+ private:
+ Arc refreshRec(std::vector<Arc> &v,int a,int b)
+ {
+ int m=(a+b)/2;
+ Arc me=v[m];
+ _left[me] = a<m?refreshRec(v,a,m-1):INVALID;
+ _right[me] = m<b?refreshRec(v,m+1,b):INVALID;
+ return me;
+ }
+ public:
+ ///Refresh the search data structure at a node.
+
+ ///Build up the search database of node \c n.
+ ///
+ ///It runs in time <em>O</em>(<em>d</em> log<em>d</em>), where <em>d</em>
+ ///is the number of the outgoing arcs of \c n.
+ void refresh(Node n)
+ {
+ std::vector<Arc> v;
+ for(OutArcIt e(_g,n);e!=INVALID;++e) v.push_back(e);
+ if(v.size()) {
+ std::sort(v.begin(),v.end(),ArcLess(_g));
+ _head[n]=refreshRec(v,0,v.size()-1);
+ }
+ else _head[n]=INVALID;
+ }
+ ///Refresh the full data structure.
+
+ ///Build up the full search database. In fact, it simply calls
+ ///\ref refresh(Node) "refresh(n)" for each node \c n.
+ ///
+ ///It runs in time <em>O</em>(<em>m</em> log<em>D</em>), where <em>m</em> is
+ ///the number of the arcs in the digraph and <em>D</em> is the maximum
+ ///out-degree of the digraph.
+ void refresh()
+ {
+ for(NodeIt n(_g);n!=INVALID;++n) refresh(n);
+ }
+
+ ///Find an arc between two nodes.
+
+ ///Find an arc between two nodes in time <em>O</em>(log<em>d</em>),
+ ///where <em>d</em> is the number of outgoing arcs of \c s.
+ ///\param s The source node.
+ ///\param t The target node.
+ ///\return An arc from \c s to \c t if there exists,
+ ///\ref INVALID otherwise.
+ ///
+ ///\warning If you change the digraph, refresh() must be called before using
+ ///this operator. If you change the outgoing arcs of
+ ///a single node \c n, then \ref refresh(Node) "refresh(n)" is enough.
+ Arc operator()(Node s, Node t) const
+ {
+ Arc e;
+ for(e=_head[s];
+ e!=INVALID&&_g.target(e)!=t;
+ e = t < _g.target(e)?_left[e]:_right[e]) ;
+ return e;
+ }
+
+ };
+
+ ///Fast look-up of all arcs between given endpoints.
+
+ ///This class is the same as \ref ArcLookUp, with the addition
+ ///that it makes it possible to find all parallel arcs between given
+ ///endpoints.
+ ///
+ ///\warning This class is static, so you should call refresh() (or at
+ ///least refresh(Node)) to refresh this data structure whenever the
+ ///digraph changes. This is a time consuming (superlinearly proportional
+ ///(<em>O</em>(<em>m</em> log<em>m</em>)) to the number of arcs).
+ ///
+ ///\tparam GR The type of the underlying digraph.
+ ///
+ ///\sa DynArcLookUp
+ ///\sa ArcLookUp
+ template<class GR>
+ class AllArcLookUp : public ArcLookUp<GR>
+ {
+ using ArcLookUp<GR>::_g;
+ using ArcLookUp<GR>::_right;
+ using ArcLookUp<GR>::_left;
+ using ArcLookUp<GR>::_head;
+
+ TEMPLATE_DIGRAPH_TYPEDEFS(GR);
+
+ typename GR::template ArcMap<Arc> _next;
+
+ Arc refreshNext(Arc head,Arc next=INVALID)
+ {
+ if(head==INVALID) return next;
+ else {
+ next=refreshNext(_right[head],next);
+ _next[head]=( next!=INVALID && _g.target(next)==_g.target(head))
+ ? next : INVALID;
+ return refreshNext(_left[head],head);
+ }
+ }
+
+ void refreshNext()
+ {
+ for(NodeIt n(_g);n!=INVALID;++n) refreshNext(_head[n]);
+ }
+
+ public:
+
+ /// The Digraph type
+ typedef GR Digraph;
+
+ ///Constructor
+
+ ///Constructor.
+ ///
+ ///It builds up the search database, which remains valid until the digraph
+ ///changes.
+ AllArcLookUp(const Digraph &g) : ArcLookUp<GR>(g), _next(g) {refreshNext();}
+
+ ///Refresh the data structure at a node.
+
+ ///Build up the search database of node \c n.
+ ///
+ ///It runs in time <em>O</em>(<em>d</em> log<em>d</em>), where <em>d</em> is
+ ///the number of the outgoing arcs of \c n.
+ void refresh(Node n)
+ {
+ ArcLookUp<GR>::refresh(n);
+ refreshNext(_head[n]);
+ }
+
+ ///Refresh the full data structure.
+
+ ///Build up the full search database. In fact, it simply calls
+ ///\ref refresh(Node) "refresh(n)" for each node \c n.
+ ///
+ ///It runs in time <em>O</em>(<em>m</em> log<em>D</em>), where <em>m</em> is
+ ///the number of the arcs in the digraph and <em>D</em> is the maximum
+ ///out-degree of the digraph.
+ void refresh()
+ {
+ for(NodeIt n(_g);n!=INVALID;++n) refresh(_head[n]);
+ }
+
+ ///Find an arc between two nodes.
+
+ ///Find an arc between two nodes.
+ ///\param s The source node.
+ ///\param t The target node.
+ ///\param prev The previous arc between \c s and \c t. It it is INVALID or
+ ///not given, the operator finds the first appropriate arc.
+ ///\return An arc from \c s to \c t after \c prev or
+ ///\ref INVALID if there is no more.
+ ///
+ ///For example, you can count the number of arcs from \c u to \c v in the
+ ///following way.
+ ///\code
+ ///AllArcLookUp<ListDigraph> ae(g);
+ ///...
+ ///int n = 0;
+ ///for(Arc a = ae(u,v); a != INVALID; a=ae(u,v,a)) n++;
+ ///\endcode
+ ///
+ ///Finding the first arc take <em>O</em>(log<em>d</em>) time,
+ ///where <em>d</em> is the number of outgoing arcs of \c s. Then the
+ ///consecutive arcs are found in constant time.
+ ///
+ ///\warning If you change the digraph, refresh() must be called before using
+ ///this operator. If you change the outgoing arcs of
+ ///a single node \c n, then \ref refresh(Node) "refresh(n)" is enough.
+ ///
+ Arc operator()(Node s, Node t, Arc prev=INVALID) const
+ {
+ if(prev==INVALID)
+ {
+ Arc f=INVALID;
+ Arc e;
+ for(e=_head[s];
+ e!=INVALID&&_g.target(e)!=t;
+ e = t < _g.target(e)?_left[e]:_right[e]) ;
+ while(e!=INVALID)
+ if(_g.target(e)==t)
+ {
+ f = e;
+ e = _left[e];
+ }
+ else e = _right[e];
+ return f;
+ }
+ else return _next[prev];
+ }
+
+ };
+
+ /// @}
+
+} //namespace lemon
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/cost_scaling.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cost_scaling.h
new file mode 100644
index 00000000000..efecdfe77c7
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cost_scaling.h
@@ -0,0 +1,1607 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_COST_SCALING_H
+#define LEMON_COST_SCALING_H
+
+/// \ingroup min_cost_flow_algs
+/// \file
+/// \brief Cost scaling algorithm for finding a minimum cost flow.
+
+#include <vector>
+#include <deque>
+#include <limits>
+
+#include <lemon/core.h>
+#include <lemon/maps.h>
+#include <lemon/math.h>
+#include <lemon/static_graph.h>
+#include <lemon/circulation.h>
+#include <lemon/bellman_ford.h>
+
+namespace lemon {
+
+ /// \brief Default traits class of CostScaling algorithm.
+ ///
+ /// Default traits class of CostScaling algorithm.
+ /// \tparam GR Digraph type.
+ /// \tparam V The number type used for flow amounts, capacity bounds
+ /// and supply values. By default it is \c int.
+ /// \tparam C The number type used for costs and potentials.
+ /// By default it is the same as \c V.
+#ifdef DOXYGEN
+ template <typename GR, typename V = int, typename C = V>
+#else
+ template < typename GR, typename V = int, typename C = V,
+ bool integer = std::numeric_limits<C>::is_integer >
+#endif
+ struct CostScalingDefaultTraits
+ {
+ /// The type of the digraph
+ typedef GR Digraph;
+ /// The type of the flow amounts, capacity bounds and supply values
+ typedef V Value;
+ /// The type of the arc costs
+ typedef C Cost;
+
+ /// \brief The large cost type used for internal computations
+ ///
+ /// The large cost type used for internal computations.
+ /// It is \c long \c long if the \c Cost type is integer,
+ /// otherwise it is \c double.
+ /// \c Cost must be convertible to \c LargeCost.
+ typedef double LargeCost;
+ };
+
+ // Default traits class for integer cost types
+ template <typename GR, typename V, typename C>
+ struct CostScalingDefaultTraits<GR, V, C, true>
+ {
+ typedef GR Digraph;
+ typedef V Value;
+ typedef C Cost;
+#ifdef LEMON_HAVE_LONG_LONG
+ typedef long long LargeCost;
+#else
+ typedef long LargeCost;
+#endif
+ };
+
+
+ /// \addtogroup min_cost_flow_algs
+ /// @{
+
+ /// \brief Implementation of the Cost Scaling algorithm for
+ /// finding a \ref min_cost_flow "minimum cost flow".
+ ///
+ /// \ref CostScaling implements a cost scaling algorithm that performs
+ /// push/augment and relabel operations for finding a \ref min_cost_flow
+ /// "minimum cost flow" \cite amo93networkflows,
+ /// \cite goldberg90approximation,
+ /// \cite goldberg97efficient, \cite bunnagel98efficient.
+ /// It is a highly efficient primal-dual solution method, which
+ /// can be viewed as the generalization of the \ref Preflow
+ /// "preflow push-relabel" algorithm for the maximum flow problem.
+ /// It is a polynomial algorithm, its running time complexity is
+ /// \f$O(n^2m\log(nK))\f$, where <i>K</i> denotes the maximum arc cost.
+ ///
+ /// In general, \ref NetworkSimplex and \ref CostScaling are the fastest
+ /// implementations available in LEMON for solving this problem.
+ /// (For more information, see \ref min_cost_flow_algs "the module page".)
+ ///
+ /// Most of the parameters of the problem (except for the digraph)
+ /// can be given using separate functions, and the algorithm can be
+ /// executed using the \ref run() function. If some parameters are not
+ /// specified, then default values will be used.
+ ///
+ /// \tparam GR The digraph type the algorithm runs on.
+ /// \tparam V The number type used for flow amounts, capacity bounds
+ /// and supply values in the algorithm. By default, it is \c int.
+ /// \tparam C The number type used for costs and potentials in the
+ /// algorithm. By default, it is the same as \c V.
+ /// \tparam TR The traits class that defines various types used by the
+ /// algorithm. By default, it is \ref CostScalingDefaultTraits
+ /// "CostScalingDefaultTraits<GR, V, C>".
+ /// In most cases, this parameter should not be set directly,
+ /// consider to use the named template parameters instead.
+ ///
+ /// \warning Both \c V and \c C must be signed number types.
+ /// \warning All input data (capacities, supply values, and costs) must
+ /// be integer.
+ /// \warning This algorithm does not support negative costs for
+ /// arcs having infinite upper bound.
+ ///
+ /// \note %CostScaling provides three different internal methods,
+ /// from which the most efficient one is used by default.
+ /// For more information, see \ref Method.
+#ifdef DOXYGEN
+ template <typename GR, typename V, typename C, typename TR>
+#else
+ template < typename GR, typename V = int, typename C = V,
+ typename TR = CostScalingDefaultTraits<GR, V, C> >
+#endif
+ class CostScaling
+ {
+ public:
+
+ /// The type of the digraph
+ typedef typename TR::Digraph Digraph;
+ /// The type of the flow amounts, capacity bounds and supply values
+ typedef typename TR::Value Value;
+ /// The type of the arc costs
+ typedef typename TR::Cost Cost;
+
+ /// \brief The large cost type
+ ///
+ /// The large cost type used for internal computations.
+ /// By default, it is \c long \c long if the \c Cost type is integer,
+ /// otherwise it is \c double.
+ typedef typename TR::LargeCost LargeCost;
+
+ /// \brief The \ref lemon::CostScalingDefaultTraits "traits class"
+ /// of the algorithm
+ typedef TR Traits;
+
+ public:
+
+ /// \brief Problem type constants for the \c run() function.
+ ///
+ /// Enum type containing the problem type constants that can be
+ /// returned by the \ref run() function of the algorithm.
+ enum ProblemType {
+ /// The problem has no feasible solution (flow).
+ INFEASIBLE,
+ /// The problem has optimal solution (i.e. it is feasible and
+ /// bounded), and the algorithm has found optimal flow and node
+ /// potentials (primal and dual solutions).
+ OPTIMAL,
+ /// The digraph contains an arc of negative cost and infinite
+ /// upper bound. It means that the objective function is unbounded
+ /// on that arc, however, note that it could actually be bounded
+ /// over the feasible flows, but this algroithm cannot handle
+ /// these cases.
+ UNBOUNDED
+ };
+
+ /// \brief Constants for selecting the internal method.
+ ///
+ /// Enum type containing constants for selecting the internal method
+ /// for the \ref run() function.
+ ///
+ /// \ref CostScaling provides three internal methods that differ mainly
+ /// in their base operations, which are used in conjunction with the
+ /// relabel operation.
+ /// By default, the so called \ref PARTIAL_AUGMENT
+ /// "Partial Augment-Relabel" method is used, which turned out to be
+ /// the most efficient and the most robust on various test inputs.
+ /// However, the other methods can be selected using the \ref run()
+ /// function with the proper parameter.
+ enum Method {
+ /// Local push operations are used, i.e. flow is moved only on one
+ /// admissible arc at once.
+ PUSH,
+ /// Augment operations are used, i.e. flow is moved on admissible
+ /// paths from a node with excess to a node with deficit.
+ AUGMENT,
+ /// Partial augment operations are used, i.e. flow is moved on
+ /// admissible paths started from a node with excess, but the
+ /// lengths of these paths are limited. This method can be viewed
+ /// as a combined version of the previous two operations.
+ PARTIAL_AUGMENT
+ };
+
+ private:
+
+ TEMPLATE_DIGRAPH_TYPEDEFS(GR);
+
+ typedef std::vector<int> IntVector;
+ typedef std::vector<Value> ValueVector;
+ typedef std::vector<Cost> CostVector;
+ typedef std::vector<LargeCost> LargeCostVector;
+ typedef std::vector<char> BoolVector;
+ // Note: vector<char> is used instead of vector<bool>
+ // for efficiency reasons
+
+ private:
+
+ template <typename KT, typename VT>
+ class StaticVectorMap {
+ public:
+ typedef KT Key;
+ typedef VT Value;
+
+ StaticVectorMap(std::vector<Value>& v) : _v(v) {}
+
+ const Value& operator[](const Key& key) const {
+ return _v[StaticDigraph::id(key)];
+ }
+
+ Value& operator[](const Key& key) {
+ return _v[StaticDigraph::id(key)];
+ }
+
+ void set(const Key& key, const Value& val) {
+ _v[StaticDigraph::id(key)] = val;
+ }
+
+ private:
+ std::vector<Value>& _v;
+ };
+
+ typedef StaticVectorMap<StaticDigraph::Arc, LargeCost> LargeCostArcMap;
+
+ private:
+
+ // Data related to the underlying digraph
+ const GR &_graph;
+ int _node_num;
+ int _arc_num;
+ int _res_node_num;
+ int _res_arc_num;
+ int _root;
+
+ // Parameters of the problem
+ bool _has_lower;
+ Value _sum_supply;
+ int _sup_node_num;
+
+ // Data structures for storing the digraph
+ IntNodeMap _node_id;
+ IntArcMap _arc_idf;
+ IntArcMap _arc_idb;
+ IntVector _first_out;
+ BoolVector _forward;
+ IntVector _source;
+ IntVector _target;
+ IntVector _reverse;
+
+ // Node and arc data
+ ValueVector _lower;
+ ValueVector _upper;
+ CostVector _scost;
+ ValueVector _supply;
+
+ ValueVector _res_cap;
+ LargeCostVector _cost;
+ LargeCostVector _pi;
+ ValueVector _excess;
+ IntVector _next_out;
+ std::deque<int> _active_nodes;
+
+ // Data for scaling
+ LargeCost _epsilon;
+ int _alpha;
+
+ IntVector _buckets;
+ IntVector _bucket_next;
+ IntVector _bucket_prev;
+ IntVector _rank;
+ int _max_rank;
+
+ public:
+
+ /// \brief Constant for infinite upper bounds (capacities).
+ ///
+ /// Constant for infinite upper bounds (capacities).
+ /// It is \c std::numeric_limits<Value>::infinity() if available,
+ /// \c std::numeric_limits<Value>::max() otherwise.
+ const Value INF;
+
+ public:
+
+ /// \name Named Template Parameters
+ /// @{
+
+ template <typename T>
+ struct SetLargeCostTraits : public Traits {
+ typedef T LargeCost;
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// \c LargeCost type.
+ ///
+ /// \ref named-templ-param "Named parameter" for setting \c LargeCost
+ /// type, which is used for internal computations in the algorithm.
+ /// \c Cost must be convertible to \c LargeCost.
+ template <typename T>
+ struct SetLargeCost
+ : public CostScaling<GR, V, C, SetLargeCostTraits<T> > {
+ typedef CostScaling<GR, V, C, SetLargeCostTraits<T> > Create;
+ };
+
+ /// @}
+
+ protected:
+
+ CostScaling() {}
+
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// The constructor of the class.
+ ///
+ /// \param graph The digraph the algorithm runs on.
+ CostScaling(const GR& graph) :
+ _graph(graph), _node_id(graph), _arc_idf(graph), _arc_idb(graph),
+ INF(std::numeric_limits<Value>::has_infinity ?
+ std::numeric_limits<Value>::infinity() :
+ std::numeric_limits<Value>::max())
+ {
+ // Check the number types
+ LEMON_ASSERT(std::numeric_limits<Value>::is_signed,
+ "The flow type of CostScaling must be signed");
+ LEMON_ASSERT(std::numeric_limits<Cost>::is_signed,
+ "The cost type of CostScaling must be signed");
+
+ // Reset data structures
+ reset();
+ }
+
+ /// \name Parameters
+ /// The parameters of the algorithm can be specified using these
+ /// functions.
+
+ /// @{
+
+ /// \brief Set the lower bounds on the arcs.
+ ///
+ /// This function sets the lower bounds on the arcs.
+ /// If it is not used before calling \ref run(), the lower bounds
+ /// will be set to zero on all arcs.
+ ///
+ /// \param map An arc map storing the lower bounds.
+ /// Its \c Value type must be convertible to the \c Value type
+ /// of the algorithm.
+ ///
+ /// \return <tt>(*this)</tt>
+ template <typename LowerMap>
+ CostScaling& lowerMap(const LowerMap& map) {
+ _has_lower = true;
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ _lower[_arc_idf[a]] = map[a];
+ }
+ return *this;
+ }
+
+ /// \brief Set the upper bounds (capacities) on the arcs.
+ ///
+ /// This function sets the upper bounds (capacities) on the arcs.
+ /// If it is not used before calling \ref run(), the upper bounds
+ /// will be set to \ref INF on all arcs (i.e. the flow value will be
+ /// unbounded from above).
+ ///
+ /// \param map An arc map storing the upper bounds.
+ /// Its \c Value type must be convertible to the \c Value type
+ /// of the algorithm.
+ ///
+ /// \return <tt>(*this)</tt>
+ template<typename UpperMap>
+ CostScaling& upperMap(const UpperMap& map) {
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ _upper[_arc_idf[a]] = map[a];
+ }
+ return *this;
+ }
+
+ /// \brief Set the costs of the arcs.
+ ///
+ /// This function sets the costs of the arcs.
+ /// If it is not used before calling \ref run(), the costs
+ /// will be set to \c 1 on all arcs.
+ ///
+ /// \param map An arc map storing the costs.
+ /// Its \c Value type must be convertible to the \c Cost type
+ /// of the algorithm.
+ ///
+ /// \return <tt>(*this)</tt>
+ template<typename CostMap>
+ CostScaling& costMap(const CostMap& map) {
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ _scost[_arc_idf[a]] = map[a];
+ _scost[_arc_idb[a]] = -map[a];
+ }
+ return *this;
+ }
+
+ /// \brief Set the supply values of the nodes.
+ ///
+ /// This function sets the supply values of the nodes.
+ /// If neither this function nor \ref stSupply() is used before
+ /// calling \ref run(), the supply of each node will be set to zero.
+ ///
+ /// \param map A node map storing the supply values.
+ /// Its \c Value type must be convertible to the \c Value type
+ /// of the algorithm.
+ ///
+ /// \return <tt>(*this)</tt>
+ template<typename SupplyMap>
+ CostScaling& supplyMap(const SupplyMap& map) {
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ _supply[_node_id[n]] = map[n];
+ }
+ return *this;
+ }
+
+ /// \brief Set single source and target nodes and a supply value.
+ ///
+ /// This function sets a single source node and a single target node
+ /// and the required flow value.
+ /// If neither this function nor \ref supplyMap() is used before
+ /// calling \ref run(), the supply of each node will be set to zero.
+ ///
+ /// Using this function has the same effect as using \ref supplyMap()
+ /// with a map in which \c k is assigned to \c s, \c -k is
+ /// assigned to \c t and all other nodes have zero supply value.
+ ///
+ /// \param s The source node.
+ /// \param t The target node.
+ /// \param k The required amount of flow from node \c s to node \c t
+ /// (i.e. the supply of \c s and the demand of \c t).
+ ///
+ /// \return <tt>(*this)</tt>
+ CostScaling& stSupply(const Node& s, const Node& t, Value k) {
+ for (int i = 0; i != _res_node_num; ++i) {
+ _supply[i] = 0;
+ }
+ _supply[_node_id[s]] = k;
+ _supply[_node_id[t]] = -k;
+ return *this;
+ }
+
+ /// @}
+
+ /// \name Execution control
+ /// The algorithm can be executed using \ref run().
+
+ /// @{
+
+ /// \brief Run the algorithm.
+ ///
+ /// This function runs the algorithm.
+ /// The paramters can be specified using functions \ref lowerMap(),
+ /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply().
+ /// For example,
+ /// \code
+ /// CostScaling<ListDigraph> cs(graph);
+ /// cs.lowerMap(lower).upperMap(upper).costMap(cost)
+ /// .supplyMap(sup).run();
+ /// \endcode
+ ///
+ /// This function can be called more than once. All the given parameters
+ /// are kept for the next call, unless \ref resetParams() or \ref reset()
+ /// is used, thus only the modified parameters have to be set again.
+ /// If the underlying digraph was also modified after the construction
+ /// of the class (or the last \ref reset() call), then the \ref reset()
+ /// function must be called.
+ ///
+ /// \param method The internal method that will be used in the
+ /// algorithm. For more information, see \ref Method.
+ /// \param factor The cost scaling factor. It must be at least two.
+ ///
+ /// \return \c INFEASIBLE if no feasible flow exists,
+ /// \n \c OPTIMAL if the problem has optimal solution
+ /// (i.e. it is feasible and bounded), and the algorithm has found
+ /// optimal flow and node potentials (primal and dual solutions),
+ /// \n \c UNBOUNDED if the digraph contains an arc of negative cost
+ /// and infinite upper bound. It means that the objective function
+ /// is unbounded on that arc, however, note that it could actually be
+ /// bounded over the feasible flows, but this algroithm cannot handle
+ /// these cases.
+ ///
+ /// \see ProblemType, Method
+ /// \see resetParams(), reset()
+ ProblemType run(Method method = PARTIAL_AUGMENT, int factor = 16) {
+ LEMON_ASSERT(factor >= 2, "The scaling factor must be at least 2");
+ _alpha = factor;
+ ProblemType pt = init();
+ if (pt != OPTIMAL) return pt;
+ start(method);
+ return OPTIMAL;
+ }
+
+ /// \brief Reset all the parameters that have been given before.
+ ///
+ /// This function resets all the paramaters that have been given
+ /// before using functions \ref lowerMap(), \ref upperMap(),
+ /// \ref costMap(), \ref supplyMap(), \ref stSupply().
+ ///
+ /// It is useful for multiple \ref run() calls. Basically, all the given
+ /// parameters are kept for the next \ref run() call, unless
+ /// \ref resetParams() or \ref reset() is used.
+ /// If the underlying digraph was also modified after the construction
+ /// of the class or the last \ref reset() call, then the \ref reset()
+ /// function must be used, otherwise \ref resetParams() is sufficient.
+ ///
+ /// For example,
+ /// \code
+ /// CostScaling<ListDigraph> cs(graph);
+ ///
+ /// // First run
+ /// cs.lowerMap(lower).upperMap(upper).costMap(cost)
+ /// .supplyMap(sup).run();
+ ///
+ /// // Run again with modified cost map (resetParams() is not called,
+ /// // so only the cost map have to be set again)
+ /// cost[e] += 100;
+ /// cs.costMap(cost).run();
+ ///
+ /// // Run again from scratch using resetParams()
+ /// // (the lower bounds will be set to zero on all arcs)
+ /// cs.resetParams();
+ /// cs.upperMap(capacity).costMap(cost)
+ /// .supplyMap(sup).run();
+ /// \endcode
+ ///
+ /// \return <tt>(*this)</tt>
+ ///
+ /// \see reset(), run()
+ CostScaling& resetParams() {
+ for (int i = 0; i != _res_node_num; ++i) {
+ _supply[i] = 0;
+ }
+ int limit = _first_out[_root];
+ for (int j = 0; j != limit; ++j) {
+ _lower[j] = 0;
+ _upper[j] = INF;
+ _scost[j] = _forward[j] ? 1 : -1;
+ }
+ for (int j = limit; j != _res_arc_num; ++j) {
+ _lower[j] = 0;
+ _upper[j] = INF;
+ _scost[j] = 0;
+ _scost[_reverse[j]] = 0;
+ }
+ _has_lower = false;
+ return *this;
+ }
+
+ /// \brief Reset the internal data structures and all the parameters
+ /// that have been given before.
+ ///
+ /// This function resets the internal data structures and all the
+ /// paramaters that have been given before using functions \ref lowerMap(),
+ /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply().
+ ///
+ /// It is useful for multiple \ref run() calls. By default, all the given
+ /// parameters are kept for the next \ref run() call, unless
+ /// \ref resetParams() or \ref reset() is used.
+ /// If the underlying digraph was also modified after the construction
+ /// of the class or the last \ref reset() call, then the \ref reset()
+ /// function must be used, otherwise \ref resetParams() is sufficient.
+ ///
+ /// See \ref resetParams() for examples.
+ ///
+ /// \return <tt>(*this)</tt>
+ ///
+ /// \see resetParams(), run()
+ CostScaling& reset() {
+ // Resize vectors
+ _node_num = countNodes(_graph);
+ _arc_num = countArcs(_graph);
+ _res_node_num = _node_num + 1;
+ _res_arc_num = 2 * (_arc_num + _node_num);
+ _root = _node_num;
+
+ _first_out.resize(_res_node_num + 1);
+ _forward.resize(_res_arc_num);
+ _source.resize(_res_arc_num);
+ _target.resize(_res_arc_num);
+ _reverse.resize(_res_arc_num);
+
+ _lower.resize(_res_arc_num);
+ _upper.resize(_res_arc_num);
+ _scost.resize(_res_arc_num);
+ _supply.resize(_res_node_num);
+
+ _res_cap.resize(_res_arc_num);
+ _cost.resize(_res_arc_num);
+ _pi.resize(_res_node_num);
+ _excess.resize(_res_node_num);
+ _next_out.resize(_res_node_num);
+
+ // Copy the graph
+ int i = 0, j = 0, k = 2 * _arc_num + _node_num;
+ for (NodeIt n(_graph); n != INVALID; ++n, ++i) {
+ _node_id[n] = i;
+ }
+ i = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n, ++i) {
+ _first_out[i] = j;
+ for (OutArcIt a(_graph, n); a != INVALID; ++a, ++j) {
+ _arc_idf[a] = j;
+ _forward[j] = true;
+ _source[j] = i;
+ _target[j] = _node_id[_graph.runningNode(a)];
+ }
+ for (InArcIt a(_graph, n); a != INVALID; ++a, ++j) {
+ _arc_idb[a] = j;
+ _forward[j] = false;
+ _source[j] = i;
+ _target[j] = _node_id[_graph.runningNode(a)];
+ }
+ _forward[j] = false;
+ _source[j] = i;
+ _target[j] = _root;
+ _reverse[j] = k;
+ _forward[k] = true;
+ _source[k] = _root;
+ _target[k] = i;
+ _reverse[k] = j;
+ ++j; ++k;
+ }
+ _first_out[i] = j;
+ _first_out[_res_node_num] = k;
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ int fi = _arc_idf[a];
+ int bi = _arc_idb[a];
+ _reverse[fi] = bi;
+ _reverse[bi] = fi;
+ }
+
+ // Reset parameters
+ resetParams();
+ return *this;
+ }
+
+ /// @}
+
+ /// \name Query Functions
+ /// The results of the algorithm can be obtained using these
+ /// functions.\n
+ /// The \ref run() function must be called before using them.
+
+ /// @{
+
+ /// \brief Return the total cost of the found flow.
+ ///
+ /// This function returns the total cost of the found flow.
+ /// Its complexity is O(m).
+ ///
+ /// \note The return type of the function can be specified as a
+ /// template parameter. For example,
+ /// \code
+ /// cs.totalCost<double>();
+ /// \endcode
+ /// It is useful if the total cost cannot be stored in the \c Cost
+ /// type of the algorithm, which is the default return type of the
+ /// function.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ template <typename Number>
+ Number totalCost() const {
+ Number c = 0;
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ int i = _arc_idb[a];
+ c += static_cast<Number>(_res_cap[i]) *
+ (-static_cast<Number>(_scost[i]));
+ }
+ return c;
+ }
+
+#ifndef DOXYGEN
+ Cost totalCost() const {
+ return totalCost<Cost>();
+ }
+#endif
+
+ /// \brief Return the flow on the given arc.
+ ///
+ /// This function returns the flow on the given arc.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ Value flow(const Arc& a) const {
+ return _res_cap[_arc_idb[a]];
+ }
+
+ /// \brief Copy the flow values (the primal solution) into the
+ /// given map.
+ ///
+ /// This function copies the flow value on each arc into the given
+ /// map. The \c Value type of the algorithm must be convertible to
+ /// the \c Value type of the map.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ template <typename FlowMap>
+ void flowMap(FlowMap &map) const {
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ map.set(a, _res_cap[_arc_idb[a]]);
+ }
+ }
+
+ /// \brief Return the potential (dual value) of the given node.
+ ///
+ /// This function returns the potential (dual value) of the
+ /// given node.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ Cost potential(const Node& n) const {
+ return static_cast<Cost>(_pi[_node_id[n]]);
+ }
+
+ /// \brief Copy the potential values (the dual solution) into the
+ /// given map.
+ ///
+ /// This function copies the potential (dual value) of each node
+ /// into the given map.
+ /// The \c Cost type of the algorithm must be convertible to the
+ /// \c Value type of the map.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ template <typename PotentialMap>
+ void potentialMap(PotentialMap &map) const {
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ map.set(n, static_cast<Cost>(_pi[_node_id[n]]));
+ }
+ }
+
+ /// @}
+
+ private:
+
+ // Initialize the algorithm
+ ProblemType init() {
+ if (_res_node_num <= 1) return INFEASIBLE;
+
+ // Check the sum of supply values
+ _sum_supply = 0;
+ for (int i = 0; i != _root; ++i) {
+ _sum_supply += _supply[i];
+ }
+ if (_sum_supply > 0) return INFEASIBLE;
+
+ // Check lower and upper bounds
+ LEMON_DEBUG(checkBoundMaps(),
+ "Upper bounds must be greater or equal to the lower bounds");
+
+
+ // Initialize vectors
+ for (int i = 0; i != _res_node_num; ++i) {
+ _pi[i] = 0;
+ _excess[i] = _supply[i];
+ }
+
+ // Remove infinite upper bounds and check negative arcs
+ const Value MAX = std::numeric_limits<Value>::max();
+ int last_out;
+ if (_has_lower) {
+ for (int i = 0; i != _root; ++i) {
+ last_out = _first_out[i+1];
+ for (int j = _first_out[i]; j != last_out; ++j) {
+ if (_forward[j]) {
+ Value c = _scost[j] < 0 ? _upper[j] : _lower[j];
+ if (c >= MAX) return UNBOUNDED;
+ _excess[i] -= c;
+ _excess[_target[j]] += c;
+ }
+ }
+ }
+ } else {
+ for (int i = 0; i != _root; ++i) {
+ last_out = _first_out[i+1];
+ for (int j = _first_out[i]; j != last_out; ++j) {
+ if (_forward[j] && _scost[j] < 0) {
+ Value c = _upper[j];
+ if (c >= MAX) return UNBOUNDED;
+ _excess[i] -= c;
+ _excess[_target[j]] += c;
+ }
+ }
+ }
+ }
+ Value ex, max_cap = 0;
+ for (int i = 0; i != _res_node_num; ++i) {
+ ex = _excess[i];
+ _excess[i] = 0;
+ if (ex < 0) max_cap -= ex;
+ }
+ for (int j = 0; j != _res_arc_num; ++j) {
+ if (_upper[j] >= MAX) _upper[j] = max_cap;
+ }
+
+ // Initialize the large cost vector and the epsilon parameter
+ _epsilon = 0;
+ LargeCost lc;
+ for (int i = 0; i != _root; ++i) {
+ last_out = _first_out[i+1];
+ for (int j = _first_out[i]; j != last_out; ++j) {
+ lc = static_cast<LargeCost>(_scost[j]) * _res_node_num * _alpha;
+ _cost[j] = lc;
+ if (lc > _epsilon) _epsilon = lc;
+ }
+ }
+ _epsilon /= _alpha;
+
+ // Initialize maps for Circulation and remove non-zero lower bounds
+ ConstMap<Arc, Value> low(0);
+ typedef typename Digraph::template ArcMap<Value> ValueArcMap;
+ typedef typename Digraph::template NodeMap<Value> ValueNodeMap;
+ ValueArcMap cap(_graph), flow(_graph);
+ ValueNodeMap sup(_graph);
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ sup[n] = _supply[_node_id[n]];
+ }
+ if (_has_lower) {
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ int j = _arc_idf[a];
+ Value c = _lower[j];
+ cap[a] = _upper[j] - c;
+ sup[_graph.source(a)] -= c;
+ sup[_graph.target(a)] += c;
+ }
+ } else {
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ cap[a] = _upper[_arc_idf[a]];
+ }
+ }
+
+ _sup_node_num = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ if (sup[n] > 0) ++_sup_node_num;
+ }
+
+ // Find a feasible flow using Circulation
+ Circulation<Digraph, ConstMap<Arc, Value>, ValueArcMap, ValueNodeMap>
+ circ(_graph, low, cap, sup);
+ if (!circ.flowMap(flow).run()) return INFEASIBLE;
+
+ // Set residual capacities and handle GEQ supply type
+ if (_sum_supply < 0) {
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ Value fa = flow[a];
+ _res_cap[_arc_idf[a]] = cap[a] - fa;
+ _res_cap[_arc_idb[a]] = fa;
+ sup[_graph.source(a)] -= fa;
+ sup[_graph.target(a)] += fa;
+ }
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ _excess[_node_id[n]] = sup[n];
+ }
+ for (int a = _first_out[_root]; a != _res_arc_num; ++a) {
+ int u = _target[a];
+ int ra = _reverse[a];
+ _res_cap[a] = -_sum_supply + 1;
+ _res_cap[ra] = -_excess[u];
+ _cost[a] = 0;
+ _cost[ra] = 0;
+ _excess[u] = 0;
+ }
+ } else {
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ Value fa = flow[a];
+ _res_cap[_arc_idf[a]] = cap[a] - fa;
+ _res_cap[_arc_idb[a]] = fa;
+ }
+ for (int a = _first_out[_root]; a != _res_arc_num; ++a) {
+ int ra = _reverse[a];
+ _res_cap[a] = 0;
+ _res_cap[ra] = 0;
+ _cost[a] = 0;
+ _cost[ra] = 0;
+ }
+ }
+
+ // Initialize data structures for buckets
+ _max_rank = _alpha * _res_node_num;
+ _buckets.resize(_max_rank);
+ _bucket_next.resize(_res_node_num + 1);
+ _bucket_prev.resize(_res_node_num + 1);
+ _rank.resize(_res_node_num + 1);
+
+ return OPTIMAL;
+ }
+
+ // Check if the upper bound is greater than or equal to the lower bound
+ // on each forward arc.
+ bool checkBoundMaps() {
+ for (int j = 0; j != _res_arc_num; ++j) {
+ if (_forward[j] && _upper[j] < _lower[j]) return false;
+ }
+ return true;
+ }
+
+ // Execute the algorithm and transform the results
+ void start(Method method) {
+ const int MAX_PARTIAL_PATH_LENGTH = 4;
+
+ switch (method) {
+ case PUSH:
+ startPush();
+ break;
+ case AUGMENT:
+ startAugment(_res_node_num - 1);
+ break;
+ case PARTIAL_AUGMENT:
+ startAugment(MAX_PARTIAL_PATH_LENGTH);
+ break;
+ }
+
+ // Compute node potentials (dual solution)
+ for (int i = 0; i != _res_node_num; ++i) {
+ _pi[i] = static_cast<Cost>(_pi[i] / (_res_node_num * _alpha));
+ }
+ bool optimal = true;
+ for (int i = 0; optimal && i != _res_node_num; ++i) {
+ LargeCost pi_i = _pi[i];
+ int last_out = _first_out[i+1];
+ for (int j = _first_out[i]; j != last_out; ++j) {
+ if (_res_cap[j] > 0 && _scost[j] + pi_i - _pi[_target[j]] < 0) {
+ optimal = false;
+ break;
+ }
+ }
+ }
+
+ if (!optimal) {
+ // Compute node potentials for the original costs with BellmanFord
+ // (if it is necessary)
+ typedef std::pair<int, int> IntPair;
+ StaticDigraph sgr;
+ std::vector<IntPair> arc_vec;
+ std::vector<LargeCost> cost_vec;
+ LargeCostArcMap cost_map(cost_vec);
+
+ arc_vec.clear();
+ cost_vec.clear();
+ for (int j = 0; j != _res_arc_num; ++j) {
+ if (_res_cap[j] > 0) {
+ int u = _source[j], v = _target[j];
+ arc_vec.push_back(IntPair(u, v));
+ cost_vec.push_back(_scost[j] + _pi[u] - _pi[v]);
+ }
+ }
+ sgr.build(_res_node_num, arc_vec.begin(), arc_vec.end());
+
+ typename BellmanFord<StaticDigraph, LargeCostArcMap>::Create
+ bf(sgr, cost_map);
+ bf.init(0);
+ bf.start();
+
+ for (int i = 0; i != _res_node_num; ++i) {
+ _pi[i] += bf.dist(sgr.node(i));
+ }
+ }
+
+ // Shift potentials to meet the requirements of the GEQ type
+ // optimality conditions
+ LargeCost max_pot = _pi[_root];
+ for (int i = 0; i != _res_node_num; ++i) {
+ if (_pi[i] > max_pot) max_pot = _pi[i];
+ }
+ if (max_pot != 0) {
+ for (int i = 0; i != _res_node_num; ++i) {
+ _pi[i] -= max_pot;
+ }
+ }
+
+ // Handle non-zero lower bounds
+ if (_has_lower) {
+ int limit = _first_out[_root];
+ for (int j = 0; j != limit; ++j) {
+ if (_forward[j]) _res_cap[_reverse[j]] += _lower[j];
+ }
+ }
+ }
+
+ // Initialize a cost scaling phase
+ void initPhase() {
+ // Saturate arcs not satisfying the optimality condition
+ for (int u = 0; u != _res_node_num; ++u) {
+ int last_out = _first_out[u+1];
+ LargeCost pi_u = _pi[u];
+ for (int a = _first_out[u]; a != last_out; ++a) {
+ Value delta = _res_cap[a];
+ if (delta > 0) {
+ int v = _target[a];
+ if (_cost[a] + pi_u - _pi[v] < 0) {
+ _excess[u] -= delta;
+ _excess[v] += delta;
+ _res_cap[a] = 0;
+ _res_cap[_reverse[a]] += delta;
+ }
+ }
+ }
+ }
+
+ // Find active nodes (i.e. nodes with positive excess)
+ for (int u = 0; u != _res_node_num; ++u) {
+ if (_excess[u] > 0) _active_nodes.push_back(u);
+ }
+
+ // Initialize the next arcs
+ for (int u = 0; u != _res_node_num; ++u) {
+ _next_out[u] = _first_out[u];
+ }
+ }
+
+ // Price (potential) refinement heuristic
+ bool priceRefinement() {
+
+ // Stack for stroing the topological order
+ IntVector stack(_res_node_num);
+ int stack_top;
+
+ // Perform phases
+ while (topologicalSort(stack, stack_top)) {
+
+ // Compute node ranks in the acyclic admissible network and
+ // store the nodes in buckets
+ for (int i = 0; i != _res_node_num; ++i) {
+ _rank[i] = 0;
+ }
+ const int bucket_end = _root + 1;
+ for (int r = 0; r != _max_rank; ++r) {
+ _buckets[r] = bucket_end;
+ }
+ int top_rank = 0;
+ for ( ; stack_top >= 0; --stack_top) {
+ int u = stack[stack_top], v;
+ int rank_u = _rank[u];
+
+ LargeCost rc, pi_u = _pi[u];
+ int last_out = _first_out[u+1];
+ for (int a = _first_out[u]; a != last_out; ++a) {
+ if (_res_cap[a] > 0) {
+ v = _target[a];
+ rc = _cost[a] + pi_u - _pi[v];
+ if (rc < 0) {
+ LargeCost nrc = static_cast<LargeCost>((-rc - 0.5) / _epsilon);
+ if (nrc < LargeCost(_max_rank)) {
+ int new_rank_v = rank_u + static_cast<int>(nrc);
+ if (new_rank_v > _rank[v]) {
+ _rank[v] = new_rank_v;
+ }
+ }
+ }
+ }
+ }
+
+ if (rank_u > 0) {
+ top_rank = std::max(top_rank, rank_u);
+ int bfirst = _buckets[rank_u];
+ _bucket_next[u] = bfirst;
+ _bucket_prev[bfirst] = u;
+ _buckets[rank_u] = u;
+ }
+ }
+
+ // Check if the current flow is epsilon-optimal
+ if (top_rank == 0) {
+ return true;
+ }
+
+ // Process buckets in top-down order
+ for (int rank = top_rank; rank > 0; --rank) {
+ while (_buckets[rank] != bucket_end) {
+ // Remove the first node from the current bucket
+ int u = _buckets[rank];
+ _buckets[rank] = _bucket_next[u];
+
+ // Search the outgoing arcs of u
+ LargeCost rc, pi_u = _pi[u];
+ int last_out = _first_out[u+1];
+ int v, old_rank_v, new_rank_v;
+ for (int a = _first_out[u]; a != last_out; ++a) {
+ if (_res_cap[a] > 0) {
+ v = _target[a];
+ old_rank_v = _rank[v];
+
+ if (old_rank_v < rank) {
+
+ // Compute the new rank of node v
+ rc = _cost[a] + pi_u - _pi[v];
+ if (rc < 0) {
+ new_rank_v = rank;
+ } else {
+ LargeCost nrc = rc / _epsilon;
+ new_rank_v = 0;
+ if (nrc < LargeCost(_max_rank)) {
+ new_rank_v = rank - 1 - static_cast<int>(nrc);
+ }
+ }
+
+ // Change the rank of node v
+ if (new_rank_v > old_rank_v) {
+ _rank[v] = new_rank_v;
+
+ // Remove v from its old bucket
+ if (old_rank_v > 0) {
+ if (_buckets[old_rank_v] == v) {
+ _buckets[old_rank_v] = _bucket_next[v];
+ } else {
+ int pv = _bucket_prev[v], nv = _bucket_next[v];
+ _bucket_next[pv] = nv;
+ _bucket_prev[nv] = pv;
+ }
+ }
+
+ // Insert v into its new bucket
+ int nv = _buckets[new_rank_v];
+ _bucket_next[v] = nv;
+ _bucket_prev[nv] = v;
+ _buckets[new_rank_v] = v;
+ }
+ }
+ }
+ }
+
+ // Refine potential of node u
+ _pi[u] -= rank * _epsilon;
+ }
+ }
+
+ }
+
+ return false;
+ }
+
+ // Find and cancel cycles in the admissible network and
+ // determine topological order using DFS
+ bool topologicalSort(IntVector &stack, int &stack_top) {
+ const int MAX_CYCLE_CANCEL = 1;
+
+ BoolVector reached(_res_node_num, false);
+ BoolVector processed(_res_node_num, false);
+ IntVector pred(_res_node_num);
+ for (int i = 0; i != _res_node_num; ++i) {
+ _next_out[i] = _first_out[i];
+ }
+ stack_top = -1;
+
+ int cycle_cnt = 0;
+ for (int start = 0; start != _res_node_num; ++start) {
+ if (reached[start]) continue;
+
+ // Start DFS search from this start node
+ pred[start] = -1;
+ int tip = start, v;
+ while (true) {
+ // Check the outgoing arcs of the current tip node
+ reached[tip] = true;
+ LargeCost pi_tip = _pi[tip];
+ int a, last_out = _first_out[tip+1];
+ for (a = _next_out[tip]; a != last_out; ++a) {
+ if (_res_cap[a] > 0) {
+ v = _target[a];
+ if (_cost[a] + pi_tip - _pi[v] < 0) {
+ if (!reached[v]) {
+ // A new node is reached
+ reached[v] = true;
+ pred[v] = tip;
+ _next_out[tip] = a;
+ tip = v;
+ a = _next_out[tip];
+ last_out = _first_out[tip+1];
+ break;
+ }
+ else if (!processed[v]) {
+ // A cycle is found
+ ++cycle_cnt;
+ _next_out[tip] = a;
+
+ // Find the minimum residual capacity along the cycle
+ Value d, delta = _res_cap[a];
+ int u, delta_node = tip;
+ for (u = tip; u != v; ) {
+ u = pred[u];
+ d = _res_cap[_next_out[u]];
+ if (d <= delta) {
+ delta = d;
+ delta_node = u;
+ }
+ }
+
+ // Augment along the cycle
+ _res_cap[a] -= delta;
+ _res_cap[_reverse[a]] += delta;
+ for (u = tip; u != v; ) {
+ u = pred[u];
+ int ca = _next_out[u];
+ _res_cap[ca] -= delta;
+ _res_cap[_reverse[ca]] += delta;
+ }
+
+ // Check the maximum number of cycle canceling
+ if (cycle_cnt >= MAX_CYCLE_CANCEL) {
+ return false;
+ }
+
+ // Roll back search to delta_node
+ if (delta_node != tip) {
+ for (u = tip; u != delta_node; u = pred[u]) {
+ reached[u] = false;
+ }
+ tip = delta_node;
+ a = _next_out[tip] + 1;
+ last_out = _first_out[tip+1];
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Step back to the previous node
+ if (a == last_out) {
+ processed[tip] = true;
+ stack[++stack_top] = tip;
+ tip = pred[tip];
+ if (tip < 0) {
+ // Finish DFS from the current start node
+ break;
+ }
+ ++_next_out[tip];
+ }
+ }
+
+ }
+
+ return (cycle_cnt == 0);
+ }
+
+ // Global potential update heuristic
+ void globalUpdate() {
+ const int bucket_end = _root + 1;
+
+ // Initialize buckets
+ for (int r = 0; r != _max_rank; ++r) {
+ _buckets[r] = bucket_end;
+ }
+ Value total_excess = 0;
+ int b0 = bucket_end;
+ for (int i = 0; i != _res_node_num; ++i) {
+ if (_excess[i] < 0) {
+ _rank[i] = 0;
+ _bucket_next[i] = b0;
+ _bucket_prev[b0] = i;
+ b0 = i;
+ } else {
+ total_excess += _excess[i];
+ _rank[i] = _max_rank;
+ }
+ }
+ if (total_excess == 0) return;
+ _buckets[0] = b0;
+
+ // Search the buckets
+ int r = 0;
+ for ( ; r != _max_rank; ++r) {
+ while (_buckets[r] != bucket_end) {
+ // Remove the first node from the current bucket
+ int u = _buckets[r];
+ _buckets[r] = _bucket_next[u];
+
+ // Search the incoming arcs of u
+ LargeCost pi_u = _pi[u];
+ int last_out = _first_out[u+1];
+ for (int a = _first_out[u]; a != last_out; ++a) {
+ int ra = _reverse[a];
+ if (_res_cap[ra] > 0) {
+ int v = _source[ra];
+ int old_rank_v = _rank[v];
+ if (r < old_rank_v) {
+ // Compute the new rank of v
+ LargeCost nrc = (_cost[ra] + _pi[v] - pi_u) / _epsilon;
+ int new_rank_v = old_rank_v;
+ if (nrc < LargeCost(_max_rank)) {
+ new_rank_v = r + 1 + static_cast<int>(nrc);
+ }
+
+ // Change the rank of v
+ if (new_rank_v < old_rank_v) {
+ _rank[v] = new_rank_v;
+ _next_out[v] = _first_out[v];
+
+ // Remove v from its old bucket
+ if (old_rank_v < _max_rank) {
+ if (_buckets[old_rank_v] == v) {
+ _buckets[old_rank_v] = _bucket_next[v];
+ } else {
+ int pv = _bucket_prev[v], nv = _bucket_next[v];
+ _bucket_next[pv] = nv;
+ _bucket_prev[nv] = pv;
+ }
+ }
+
+ // Insert v into its new bucket
+ int nv = _buckets[new_rank_v];
+ _bucket_next[v] = nv;
+ _bucket_prev[nv] = v;
+ _buckets[new_rank_v] = v;
+ }
+ }
+ }
+ }
+
+ // Finish search if there are no more active nodes
+ if (_excess[u] > 0) {
+ total_excess -= _excess[u];
+ if (total_excess <= 0) break;
+ }
+ }
+ if (total_excess <= 0) break;
+ }
+
+ // Relabel nodes
+ for (int u = 0; u != _res_node_num; ++u) {
+ int k = std::min(_rank[u], r);
+ if (k > 0) {
+ _pi[u] -= _epsilon * k;
+ _next_out[u] = _first_out[u];
+ }
+ }
+ }
+
+ /// Execute the algorithm performing augment and relabel operations
+ void startAugment(int max_length) {
+ // Paramters for heuristics
+ const int PRICE_REFINEMENT_LIMIT = 2;
+ const double GLOBAL_UPDATE_FACTOR = 1.0;
+ const int global_update_skip = static_cast<int>(GLOBAL_UPDATE_FACTOR *
+ (_res_node_num + _sup_node_num * _sup_node_num));
+ int next_global_update_limit = global_update_skip;
+
+ // Perform cost scaling phases
+ IntVector path;
+ BoolVector path_arc(_res_arc_num, false);
+ int relabel_cnt = 0;
+ int eps_phase_cnt = 0;
+ for ( ; _epsilon >= 1; _epsilon = _epsilon < _alpha && _epsilon > 1 ?
+ 1 : _epsilon / _alpha )
+ {
+ ++eps_phase_cnt;
+
+ // Price refinement heuristic
+ if (eps_phase_cnt >= PRICE_REFINEMENT_LIMIT) {
+ if (priceRefinement()) continue;
+ }
+
+ // Initialize current phase
+ initPhase();
+
+ // Perform partial augment and relabel operations
+ while (true) {
+ // Select an active node (FIFO selection)
+ while (_active_nodes.size() > 0 &&
+ _excess[_active_nodes.front()] <= 0) {
+ _active_nodes.pop_front();
+ }
+ if (_active_nodes.size() == 0) break;
+ int start = _active_nodes.front();
+
+ // Find an augmenting path from the start node
+ int tip = start;
+ while (int(path.size()) < max_length && _excess[tip] >= 0) {
+ int u;
+ LargeCost rc, min_red_cost = std::numeric_limits<LargeCost>::max();
+ LargeCost pi_tip = _pi[tip];
+ int last_out = _first_out[tip+1];
+ for (int a = _next_out[tip]; a != last_out; ++a) {
+ if (_res_cap[a] > 0) {
+ u = _target[a];
+ rc = _cost[a] + pi_tip - _pi[u];
+ if (rc < 0) {
+ path.push_back(a);
+ _next_out[tip] = a;
+ if (path_arc[a]) {
+ goto augment; // a cycle is found, stop path search
+ }
+ tip = u;
+ path_arc[a] = true;
+ goto next_step;
+ }
+ else if (rc < min_red_cost) {
+ min_red_cost = rc;
+ }
+ }
+ }
+
+ // Relabel tip node
+ if (tip != start) {
+ int ra = _reverse[path.back()];
+ min_red_cost =
+ std::min(min_red_cost, _cost[ra] + pi_tip - _pi[_target[ra]]);
+ }
+ last_out = _next_out[tip];
+ for (int a = _first_out[tip]; a != last_out; ++a) {
+ if (_res_cap[a] > 0) {
+ rc = _cost[a] + pi_tip - _pi[_target[a]];
+ if (rc < min_red_cost) {
+ min_red_cost = rc;
+ }
+ }
+ }
+ _pi[tip] -= min_red_cost + _epsilon;
+ _next_out[tip] = _first_out[tip];
+ ++relabel_cnt;
+
+ // Step back
+ if (tip != start) {
+ int pa = path.back();
+ path_arc[pa] = false;
+ tip = _source[pa];
+ path.pop_back();
+ }
+
+ next_step: ;
+ }
+
+ // Augment along the found path (as much flow as possible)
+ augment:
+ Value delta;
+ int pa, u, v = start;
+ for (int i = 0; i != int(path.size()); ++i) {
+ pa = path[i];
+ u = v;
+ v = _target[pa];
+ path_arc[pa] = false;
+ delta = std::min(_res_cap[pa], _excess[u]);
+ _res_cap[pa] -= delta;
+ _res_cap[_reverse[pa]] += delta;
+ _excess[u] -= delta;
+ _excess[v] += delta;
+ if (_excess[v] > 0 && _excess[v] <= delta) {
+ _active_nodes.push_back(v);
+ }
+ }
+ path.clear();
+
+ // Global update heuristic
+ if (relabel_cnt >= next_global_update_limit) {
+ globalUpdate();
+ next_global_update_limit += global_update_skip;
+ }
+ }
+
+ }
+
+ }
+
+ /// Execute the algorithm performing push and relabel operations
+ void startPush() {
+ // Paramters for heuristics
+ const int PRICE_REFINEMENT_LIMIT = 2;
+ const double GLOBAL_UPDATE_FACTOR = 2.0;
+
+ const int global_update_skip = static_cast<int>(GLOBAL_UPDATE_FACTOR *
+ (_res_node_num + _sup_node_num * _sup_node_num));
+ int next_global_update_limit = global_update_skip;
+
+ // Perform cost scaling phases
+ BoolVector hyper(_res_node_num, false);
+ LargeCostVector hyper_cost(_res_node_num);
+ int relabel_cnt = 0;
+ int eps_phase_cnt = 0;
+ for ( ; _epsilon >= 1; _epsilon = _epsilon < _alpha && _epsilon > 1 ?
+ 1 : _epsilon / _alpha )
+ {
+ ++eps_phase_cnt;
+
+ // Price refinement heuristic
+ if (eps_phase_cnt >= PRICE_REFINEMENT_LIMIT) {
+ if (priceRefinement()) continue;
+ }
+
+ // Initialize current phase
+ initPhase();
+
+ // Perform push and relabel operations
+ while (_active_nodes.size() > 0) {
+ LargeCost min_red_cost, rc, pi_n;
+ Value delta;
+ int n, t, a, last_out = _res_arc_num;
+
+ next_node:
+ // Select an active node (FIFO selection)
+ n = _active_nodes.front();
+ last_out = _first_out[n+1];
+ pi_n = _pi[n];
+
+ // Perform push operations if there are admissible arcs
+ if (_excess[n] > 0) {
+ for (a = _next_out[n]; a != last_out; ++a) {
+ if (_res_cap[a] > 0 &&
+ _cost[a] + pi_n - _pi[_target[a]] < 0) {
+ delta = std::min(_res_cap[a], _excess[n]);
+ t = _target[a];
+
+ // Push-look-ahead heuristic
+ Value ahead = -_excess[t];
+ int last_out_t = _first_out[t+1];
+ LargeCost pi_t = _pi[t];
+ for (int ta = _next_out[t]; ta != last_out_t; ++ta) {
+ if (_res_cap[ta] > 0 &&
+ _cost[ta] + pi_t - _pi[_target[ta]] < 0)
+ ahead += _res_cap[ta];
+ if (ahead >= delta) break;
+ }
+ if (ahead < 0) ahead = 0;
+
+ // Push flow along the arc
+ if (ahead < delta && !hyper[t]) {
+ _res_cap[a] -= ahead;
+ _res_cap[_reverse[a]] += ahead;
+ _excess[n] -= ahead;
+ _excess[t] += ahead;
+ _active_nodes.push_front(t);
+ hyper[t] = true;
+ hyper_cost[t] = _cost[a] + pi_n - pi_t;
+ _next_out[n] = a;
+ goto next_node;
+ } else {
+ _res_cap[a] -= delta;
+ _res_cap[_reverse[a]] += delta;
+ _excess[n] -= delta;
+ _excess[t] += delta;
+ if (_excess[t] > 0 && _excess[t] <= delta)
+ _active_nodes.push_back(t);
+ }
+
+ if (_excess[n] == 0) {
+ _next_out[n] = a;
+ goto remove_nodes;
+ }
+ }
+ }
+ _next_out[n] = a;
+ }
+
+ // Relabel the node if it is still active (or hyper)
+ if (_excess[n] > 0 || hyper[n]) {
+ min_red_cost = hyper[n] ? -hyper_cost[n] :
+ std::numeric_limits<LargeCost>::max();
+ for (int a = _first_out[n]; a != last_out; ++a) {
+ if (_res_cap[a] > 0) {
+ rc = _cost[a] + pi_n - _pi[_target[a]];
+ if (rc < min_red_cost) {
+ min_red_cost = rc;
+ }
+ }
+ }
+ _pi[n] -= min_red_cost + _epsilon;
+ _next_out[n] = _first_out[n];
+ hyper[n] = false;
+ ++relabel_cnt;
+ }
+
+ // Remove nodes that are not active nor hyper
+ remove_nodes:
+ while ( _active_nodes.size() > 0 &&
+ _excess[_active_nodes.front()] <= 0 &&
+ !hyper[_active_nodes.front()] ) {
+ _active_nodes.pop_front();
+ }
+
+ // Global update heuristic
+ if (relabel_cnt >= next_global_update_limit) {
+ globalUpdate();
+ for (int u = 0; u != _res_node_num; ++u)
+ hyper[u] = false;
+ next_global_update_limit += global_update_skip;
+ }
+ }
+ }
+ }
+
+ }; //class CostScaling
+
+ ///@}
+
+} //namespace lemon
+
+#endif //LEMON_COST_SCALING_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/counter.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/counter.h
new file mode 100644
index 00000000000..a0049918929
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/counter.h
@@ -0,0 +1,249 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_COUNTER_H
+#define LEMON_COUNTER_H
+
+#include <string>
+#include <iostream>
+
+///\ingroup timecount
+///\file
+///\brief Tools for counting steps and events
+
+namespace lemon
+{
+
+ template<class P> class _NoSubCounter;
+
+ template<class P>
+ class _SubCounter
+ {
+ P &_parent;
+ std::string _title;
+ std::ostream &_os;
+ int count;
+ public:
+
+ typedef _SubCounter<_SubCounter<P> > SubCounter;
+ typedef _NoSubCounter<_SubCounter<P> > NoSubCounter;
+
+ _SubCounter(P &parent)
+ : _parent(parent), _title(), _os(std::cerr), count(0) {}
+ _SubCounter(P &parent,std::string title,std::ostream &os=std::cerr)
+ : _parent(parent), _title(title), _os(os), count(0) {}
+ _SubCounter(P &parent,const char *title,std::ostream &os=std::cerr)
+ : _parent(parent), _title(title), _os(os), count(0) {}
+ ~_SubCounter() {
+ _os << _title << count <<std::endl;
+ _parent+=count;
+ }
+ _SubCounter &operator++() { count++; return *this;}
+ int operator++(int) { return count++; }
+ _SubCounter &operator--() { count--; return *this;}
+ int operator--(int) { return count--; }
+ _SubCounter &operator+=(int c) { count+=c; return *this;}
+ _SubCounter &operator-=(int c) { count-=c; return *this;}
+ operator int() {return count;}
+ };
+
+ template<class P>
+ class _NoSubCounter
+ {
+ P &_parent;
+ public:
+ typedef _NoSubCounter<_NoSubCounter<P> > SubCounter;
+ typedef _NoSubCounter<_NoSubCounter<P> > NoSubCounter;
+
+ _NoSubCounter(P &parent) :_parent(parent) {}
+ _NoSubCounter(P &parent,std::string,std::ostream &)
+ :_parent(parent) {}
+ _NoSubCounter(P &parent,std::string)
+ :_parent(parent) {}
+ _NoSubCounter(P &parent,const char *,std::ostream &)
+ :_parent(parent) {}
+ _NoSubCounter(P &parent,const char *)
+ :_parent(parent) {}
+ ~_NoSubCounter() {}
+ _NoSubCounter &operator++() { ++_parent; return *this;}
+ int operator++(int) { _parent++; return 0;}
+ _NoSubCounter &operator--() { --_parent; return *this;}
+ int operator--(int) { _parent--; return 0;}
+ _NoSubCounter &operator+=(int c) { _parent+=c; return *this;}
+ _NoSubCounter &operator-=(int c) { _parent-=c; return *this;}
+ operator int() {return 0;}
+ };
+
+
+ /// \addtogroup timecount
+ /// @{
+
+ /// A counter class
+
+ /// This class makes it easier to count certain events (e.g. for debug
+ /// reasons).
+ /// You can increment or decrement the counter using \c operator++,
+ /// \c operator--, \c operator+= and \c operator-=. You can also
+ /// define subcounters for the different phases of the algorithm or
+ /// for different types of operations.
+ /// A report containing the given title and the value of the counter
+ /// is automatically printed on destruction.
+ ///
+ /// The following example shows the usage of counters and subcounters.
+ /// \code
+ /// // Bubble sort
+ /// std::vector<T> v;
+ /// ...
+ /// Counter op("Operations: ");
+ /// Counter::SubCounter as(op, "Assignments: ");
+ /// Counter::SubCounter co(op, "Comparisons: ");
+ /// for (int i = v.size()-1; i > 0; --i) {
+ /// for (int j = 0; j < i; ++j) {
+ /// if (v[j] > v[j+1]) {
+ /// T tmp = v[j];
+ /// v[j] = v[j+1];
+ /// v[j+1] = tmp;
+ /// as += 3; // three assignments
+ /// }
+ /// ++co; // one comparison
+ /// }
+ /// }
+ /// \endcode
+ ///
+ /// This code prints out something like that:
+ /// \code
+ /// Comparisons: 45
+ /// Assignments: 57
+ /// Operations: 102
+ /// \endcode
+ ///
+ /// \sa NoCounter
+ class Counter
+ {
+ std::string _title;
+ std::ostream &_os;
+ int count;
+ public:
+
+ /// SubCounter class
+
+ /// This class can be used to setup subcounters for a \ref Counter
+ /// to have finer reports. A subcounter provides exactly the same
+ /// operations as the main \ref Counter, but it also increments and
+ /// decrements the value of its parent.
+ /// Subcounters can also have subcounters.
+ ///
+ /// The parent counter must be given as the first parameter of the
+ /// constructor. Apart from that a title and an \c ostream object
+ /// can also be given just like for the main \ref Counter.
+ ///
+ /// A report containing the given title and the value of the
+ /// subcounter is automatically printed on destruction. If you
+ /// would like to turn off this report, use \ref NoSubCounter
+ /// instead.
+ ///
+ /// \sa NoSubCounter
+ typedef _SubCounter<Counter> SubCounter;
+
+ /// SubCounter class without printing report on destruction
+
+ /// This class can be used to setup subcounters for a \ref Counter.
+ /// It is the same as \ref SubCounter but it does not print report
+ /// on destruction. (It modifies the value of its parent, so 'No'
+ /// only means 'do not print'.)
+ ///
+ /// Replacing \ref SubCounter "SubCounter"s with \ref NoSubCounter
+ /// "NoSubCounter"s makes it possible to turn off reporting
+ /// subcounter values without actually removing the definitions
+ /// and the increment or decrement operators.
+ ///
+ /// \sa SubCounter
+ typedef _NoSubCounter<Counter> NoSubCounter;
+
+ /// Constructor.
+ Counter() : _title(), _os(std::cerr), count(0) {}
+ /// Constructor.
+ Counter(std::string title,std::ostream &os=std::cerr)
+ : _title(title), _os(os), count(0) {}
+ /// Constructor.
+ Counter(const char *title,std::ostream &os=std::cerr)
+ : _title(title), _os(os), count(0) {}
+ /// Destructor. Prints the given title and the value of the counter.
+ ~Counter() {
+ _os << _title << count <<std::endl;
+ }
+ ///\e
+ Counter &operator++() { count++; return *this;}
+ ///\e
+ int operator++(int) { return count++;}
+ ///\e
+ Counter &operator--() { count--; return *this;}
+ ///\e
+ int operator--(int) { return count--;}
+ ///\e
+ Counter &operator+=(int c) { count+=c; return *this;}
+ ///\e
+ Counter &operator-=(int c) { count-=c; return *this;}
+ /// Resets the counter to the given value.
+
+ /// Resets the counter to the given value.
+ /// \note This function does not reset the values of
+ /// \ref SubCounter "SubCounter"s but it resets \ref NoSubCounter
+ /// "NoSubCounter"s along with the main counter.
+ void reset(int c=0) {count=c;}
+ /// Returns the value of the counter.
+ operator int() {return count;}
+ };
+
+ /// 'Do nothing' version of Counter.
+
+ /// This class can be used in the same way as \ref Counter, but it
+ /// does not count at all and does not print report on destruction.
+ ///
+ /// Replacing a \ref Counter with a \ref NoCounter makes it possible
+ /// to turn off all counting and reporting (SubCounters should also
+ /// be replaced with NoSubCounters), so it does not affect the
+ /// efficiency of the program at all.
+ ///
+ /// \sa Counter
+ class NoCounter
+ {
+ public:
+ typedef _NoSubCounter<NoCounter> SubCounter;
+ typedef _NoSubCounter<NoCounter> NoSubCounter;
+
+ NoCounter() {}
+ NoCounter(std::string,std::ostream &) {}
+ NoCounter(const char *,std::ostream &) {}
+ NoCounter(std::string) {}
+ NoCounter(const char *) {}
+ NoCounter &operator++() { return *this; }
+ int operator++(int) { return 0; }
+ NoCounter &operator--() { return *this; }
+ int operator--(int) { return 0; }
+ NoCounter &operator+=(int) { return *this;}
+ NoCounter &operator-=(int) { return *this;}
+ void reset(int) {}
+ void reset() {}
+ operator int() {return 0;}
+ };
+
+ ///@}
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/cplex.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cplex.cc
new file mode 100644
index 00000000000..029a3efc500
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cplex.cc
@@ -0,0 +1,994 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <iostream>
+#include <vector>
+#include <cstring>
+
+#include <lemon/cplex.h>
+
+extern "C" {
+#include <ilcplex/cplex.h>
+}
+
+
+///\file
+///\brief Implementation of the LEMON-CPLEX lp solver interface.
+namespace lemon {
+
+ CplexEnv::LicenseError::LicenseError(int status) {
+ if (!CPXgeterrorstring(0, status, _message)) {
+ std::strcpy(_message, "Cplex unknown error");
+ }
+ }
+
+ CplexEnv::CplexEnv() {
+ int status;
+ _cnt = new int;
+ (*_cnt) = 1;
+ _env = CPXopenCPLEX(&status);
+ if (_env == 0) {
+ delete _cnt;
+ _cnt = 0;
+ throw LicenseError(status);
+ }
+ }
+
+ CplexEnv::CplexEnv(const CplexEnv& other) {
+ _env = other._env;
+ _cnt = other._cnt;
+ ++(*_cnt);
+ }
+
+ CplexEnv& CplexEnv::operator=(const CplexEnv& other) {
+ _env = other._env;
+ _cnt = other._cnt;
+ ++(*_cnt);
+ return *this;
+ }
+
+ CplexEnv::~CplexEnv() {
+ --(*_cnt);
+ if (*_cnt == 0) {
+ delete _cnt;
+ CPXcloseCPLEX(&_env);
+ }
+ }
+
+ CplexBase::CplexBase() : LpBase() {
+ int status;
+ _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
+ messageLevel(MESSAGE_NOTHING);
+ }
+
+ CplexBase::CplexBase(const CplexEnv& env)
+ : LpBase(), _env(env) {
+ int status;
+ _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
+ messageLevel(MESSAGE_NOTHING);
+ }
+
+ CplexBase::CplexBase(const CplexBase& cplex)
+ : LpBase() {
+ int status;
+ _prob = CPXcloneprob(cplexEnv(), cplex._prob, &status);
+ rows = cplex.rows;
+ cols = cplex.cols;
+ messageLevel(MESSAGE_NOTHING);
+ }
+
+ CplexBase::~CplexBase() {
+ CPXfreeprob(cplexEnv(),&_prob);
+ }
+
+ int CplexBase::_addCol() {
+ int i = CPXgetnumcols(cplexEnv(), _prob);
+ double lb = -INF, ub = INF;
+ CPXnewcols(cplexEnv(), _prob, 1, 0, &lb, &ub, 0, 0);
+ return i;
+ }
+
+
+ int CplexBase::_addRow() {
+ int i = CPXgetnumrows(cplexEnv(), _prob);
+ const double ub = INF;
+ const char s = 'L';
+ CPXnewrows(cplexEnv(), _prob, 1, &ub, &s, 0, 0);
+ return i;
+ }
+
+ int CplexBase::_addRow(Value lb, ExprIterator b,
+ ExprIterator e, Value ub) {
+ int i = CPXgetnumrows(cplexEnv(), _prob);
+ if (lb == -INF) {
+ const char s = 'L';
+ CPXnewrows(cplexEnv(), _prob, 1, &ub, &s, 0, 0);
+ } else if (ub == INF) {
+ const char s = 'G';
+ CPXnewrows(cplexEnv(), _prob, 1, &lb, &s, 0, 0);
+ } else if (lb == ub){
+ const char s = 'E';
+ CPXnewrows(cplexEnv(), _prob, 1, &lb, &s, 0, 0);
+ } else {
+ const char s = 'R';
+ double len = ub - lb;
+ CPXnewrows(cplexEnv(), _prob, 1, &lb, &s, &len, 0);
+ }
+
+ std::vector<int> indices;
+ std::vector<int> rowlist;
+ std::vector<Value> values;
+
+ for(ExprIterator it=b; it!=e; ++it) {
+ indices.push_back(it->first);
+ values.push_back(it->second);
+ rowlist.push_back(i);
+ }
+
+ CPXchgcoeflist(cplexEnv(), _prob, values.size(),
+ &rowlist.front(), &indices.front(), &values.front());
+
+ return i;
+ }
+
+ void CplexBase::_eraseCol(int i) {
+ CPXdelcols(cplexEnv(), _prob, i, i);
+ }
+
+ void CplexBase::_eraseRow(int i) {
+ CPXdelrows(cplexEnv(), _prob, i, i);
+ }
+
+ void CplexBase::_eraseColId(int i) {
+ cols.eraseIndex(i);
+ cols.shiftIndices(i);
+ }
+ void CplexBase::_eraseRowId(int i) {
+ rows.eraseIndex(i);
+ rows.shiftIndices(i);
+ }
+
+ void CplexBase::_getColName(int col, std::string &name) const {
+ int size;
+ CPXgetcolname(cplexEnv(), _prob, 0, 0, 0, &size, col, col);
+ if (size == 0) {
+ name.clear();
+ return;
+ }
+
+ size *= -1;
+ std::vector<char> buf(size);
+ char *cname;
+ int tmp;
+ CPXgetcolname(cplexEnv(), _prob, &cname, &buf.front(), size,
+ &tmp, col, col);
+ name = cname;
+ }
+
+ void CplexBase::_setColName(int col, const std::string &name) {
+ char *cname;
+ cname = const_cast<char*>(name.c_str());
+ CPXchgcolname(cplexEnv(), _prob, 1, &col, &cname);
+ }
+
+ int CplexBase::_colByName(const std::string& name) const {
+ int index;
+ if (CPXgetcolindex(cplexEnv(), _prob,
+ const_cast<char*>(name.c_str()), &index) == 0) {
+ return index;
+ }
+ return -1;
+ }
+
+ void CplexBase::_getRowName(int row, std::string &name) const {
+ int size;
+ CPXgetrowname(cplexEnv(), _prob, 0, 0, 0, &size, row, row);
+ if (size == 0) {
+ name.clear();
+ return;
+ }
+
+ size *= -1;
+ std::vector<char> buf(size);
+ char *cname;
+ int tmp;
+ CPXgetrowname(cplexEnv(), _prob, &cname, &buf.front(), size,
+ &tmp, row, row);
+ name = cname;
+ }
+
+ void CplexBase::_setRowName(int row, const std::string &name) {
+ char *cname;
+ cname = const_cast<char*>(name.c_str());
+ CPXchgrowname(cplexEnv(), _prob, 1, &row, &cname);
+ }
+
+ int CplexBase::_rowByName(const std::string& name) const {
+ int index;
+ if (CPXgetrowindex(cplexEnv(), _prob,
+ const_cast<char*>(name.c_str()), &index) == 0) {
+ return index;
+ }
+ return -1;
+ }
+
+ void CplexBase::_setRowCoeffs(int i, ExprIterator b,
+ ExprIterator e)
+ {
+ std::vector<int> indices;
+ std::vector<int> rowlist;
+ std::vector<Value> values;
+
+ for(ExprIterator it=b; it!=e; ++it) {
+ indices.push_back(it->first);
+ values.push_back(it->second);
+ rowlist.push_back(i);
+ }
+
+ CPXchgcoeflist(cplexEnv(), _prob, values.size(),
+ &rowlist.front(), &indices.front(), &values.front());
+ }
+
+ void CplexBase::_getRowCoeffs(int i, InsertIterator b) const {
+ int tmp1, tmp2, tmp3, length;
+ CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i);
+
+ length = -length;
+ std::vector<int> indices(length);
+ std::vector<double> values(length);
+
+ CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2,
+ &indices.front(), &values.front(),
+ length, &tmp3, i, i);
+
+ for (int i = 0; i < length; ++i) {
+ *b = std::make_pair(indices[i], values[i]);
+ ++b;
+ }
+ }
+
+ void CplexBase::_setColCoeffs(int i, ExprIterator b, ExprIterator e) {
+ std::vector<int> indices;
+ std::vector<int> collist;
+ std::vector<Value> values;
+
+ for(ExprIterator it=b; it!=e; ++it) {
+ indices.push_back(it->first);
+ values.push_back(it->second);
+ collist.push_back(i);
+ }
+
+ CPXchgcoeflist(cplexEnv(), _prob, values.size(),
+ &indices.front(), &collist.front(), &values.front());
+ }
+
+ void CplexBase::_getColCoeffs(int i, InsertIterator b) const {
+
+ int tmp1, tmp2, tmp3, length;
+ CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i);
+
+ length = -length;
+ std::vector<int> indices(length);
+ std::vector<double> values(length);
+
+ CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2,
+ &indices.front(), &values.front(),
+ length, &tmp3, i, i);
+
+ for (int i = 0; i < length; ++i) {
+ *b = std::make_pair(indices[i], values[i]);
+ ++b;
+ }
+
+ }
+
+ void CplexBase::_setCoeff(int row, int col, Value value) {
+ CPXchgcoef(cplexEnv(), _prob, row, col, value);
+ }
+
+ CplexBase::Value CplexBase::_getCoeff(int row, int col) const {
+ CplexBase::Value value;
+ CPXgetcoef(cplexEnv(), _prob, row, col, &value);
+ return value;
+ }
+
+ void CplexBase::_setColLowerBound(int i, Value value) {
+ const char s = 'L';
+ CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value);
+ }
+
+ CplexBase::Value CplexBase::_getColLowerBound(int i) const {
+ CplexBase::Value res;
+ CPXgetlb(cplexEnv(), _prob, &res, i, i);
+ return res <= -CPX_INFBOUND ? -INF : res;
+ }
+
+ void CplexBase::_setColUpperBound(int i, Value value)
+ {
+ const char s = 'U';
+ CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value);
+ }
+
+ CplexBase::Value CplexBase::_getColUpperBound(int i) const {
+ CplexBase::Value res;
+ CPXgetub(cplexEnv(), _prob, &res, i, i);
+ return res >= CPX_INFBOUND ? INF : res;
+ }
+
+ CplexBase::Value CplexBase::_getRowLowerBound(int i) const {
+ char s;
+ CPXgetsense(cplexEnv(), _prob, &s, i, i);
+ CplexBase::Value res;
+
+ switch (s) {
+ case 'G':
+ case 'R':
+ case 'E':
+ CPXgetrhs(cplexEnv(), _prob, &res, i, i);
+ return res <= -CPX_INFBOUND ? -INF : res;
+ default:
+ return -INF;
+ }
+ }
+
+ CplexBase::Value CplexBase::_getRowUpperBound(int i) const {
+ char s;
+ CPXgetsense(cplexEnv(), _prob, &s, i, i);
+ CplexBase::Value res;
+
+ switch (s) {
+ case 'L':
+ case 'E':
+ CPXgetrhs(cplexEnv(), _prob, &res, i, i);
+ return res >= CPX_INFBOUND ? INF : res;
+ case 'R':
+ CPXgetrhs(cplexEnv(), _prob, &res, i, i);
+ {
+ double rng;
+ CPXgetrngval(cplexEnv(), _prob, &rng, i, i);
+ res += rng;
+ }
+ return res >= CPX_INFBOUND ? INF : res;
+ default:
+ return INF;
+ }
+ }
+
+ //This is easier to implement
+ void CplexBase::_set_row_bounds(int i, Value lb, Value ub) {
+ if (lb == -INF) {
+ const char s = 'L';
+ CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
+ CPXchgrhs(cplexEnv(), _prob, 1, &i, &ub);
+ } else if (ub == INF) {
+ const char s = 'G';
+ CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
+ CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
+ } else if (lb == ub){
+ const char s = 'E';
+ CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
+ CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
+ } else {
+ const char s = 'R';
+ CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
+ CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
+ double len = ub - lb;
+ CPXchgrngval(cplexEnv(), _prob, 1, &i, &len);
+ }
+ }
+
+ void CplexBase::_setRowLowerBound(int i, Value lb)
+ {
+ LEMON_ASSERT(lb != INF, "Invalid bound");
+ _set_row_bounds(i, lb, CplexBase::_getRowUpperBound(i));
+ }
+
+ void CplexBase::_setRowUpperBound(int i, Value ub)
+ {
+
+ LEMON_ASSERT(ub != -INF, "Invalid bound");
+ _set_row_bounds(i, CplexBase::_getRowLowerBound(i), ub);
+ }
+
+ void CplexBase::_setObjCoeffs(ExprIterator b, ExprIterator e)
+ {
+ std::vector<int> indices;
+ std::vector<Value> values;
+ for(ExprIterator it=b; it!=e; ++it) {
+ indices.push_back(it->first);
+ values.push_back(it->second);
+ }
+ CPXchgobj(cplexEnv(), _prob, values.size(),
+ &indices.front(), &values.front());
+
+ }
+
+ void CplexBase::_getObjCoeffs(InsertIterator b) const
+ {
+ int num = CPXgetnumcols(cplexEnv(), _prob);
+ std::vector<Value> x(num);
+
+ CPXgetobj(cplexEnv(), _prob, &x.front(), 0, num - 1);
+ for (int i = 0; i < num; ++i) {
+ if (x[i] != 0.0) {
+ *b = std::make_pair(i, x[i]);
+ ++b;
+ }
+ }
+ }
+
+ void CplexBase::_setObjCoeff(int i, Value obj_coef)
+ {
+ CPXchgobj(cplexEnv(), _prob, 1, &i, &obj_coef);
+ }
+
+ CplexBase::Value CplexBase::_getObjCoeff(int i) const
+ {
+ Value x;
+ CPXgetobj(cplexEnv(), _prob, &x, i, i);
+ return x;
+ }
+
+ void CplexBase::_setSense(CplexBase::Sense sense) {
+ switch (sense) {
+ case MIN:
+ CPXchgobjsen(cplexEnv(), _prob, CPX_MIN);
+ break;
+ case MAX:
+ CPXchgobjsen(cplexEnv(), _prob, CPX_MAX);
+ break;
+ }
+ }
+
+ CplexBase::Sense CplexBase::_getSense() const {
+ switch (CPXgetobjsen(cplexEnv(), _prob)) {
+ case CPX_MIN:
+ return MIN;
+ case CPX_MAX:
+ return MAX;
+ default:
+ LEMON_ASSERT(false, "Invalid sense");
+ return CplexBase::Sense();
+ }
+ }
+
+ void CplexBase::_clear() {
+ CPXfreeprob(cplexEnv(),&_prob);
+ int status;
+ _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
+ }
+
+ void CplexBase::_messageLevel(MessageLevel level) {
+ switch (level) {
+ case MESSAGE_NOTHING:
+ _message_enabled = false;
+ break;
+ case MESSAGE_ERROR:
+ case MESSAGE_WARNING:
+ case MESSAGE_NORMAL:
+ case MESSAGE_VERBOSE:
+ _message_enabled = true;
+ break;
+ }
+ }
+
+ void CplexBase::_applyMessageLevel() {
+ CPXsetintparam(cplexEnv(), CPX_PARAM_SCRIND,
+ _message_enabled ? CPX_ON : CPX_OFF);
+ }
+
+ void CplexBase::_write(std::string file, std::string format) const
+ {
+ if(format == "MPS" || format == "LP")
+ CPXwriteprob(cplexEnv(), cplexLp(), file.c_str(), format.c_str());
+ else if(format == "SOL")
+ CPXsolwrite(cplexEnv(), cplexLp(), file.c_str());
+ else throw UnsupportedFormatError(format);
+ }
+
+
+
+ // CplexLp members
+
+ CplexLp::CplexLp()
+ : LpBase(), LpSolver(), CplexBase() {}
+
+ CplexLp::CplexLp(const CplexEnv& env)
+ : LpBase(), LpSolver(), CplexBase(env) {}
+
+ CplexLp::CplexLp(const CplexLp& other)
+ : LpBase(), LpSolver(), CplexBase(other) {}
+
+ CplexLp::~CplexLp() {}
+
+ CplexLp* CplexLp::newSolver() const { return new CplexLp; }
+ CplexLp* CplexLp::cloneSolver() const {return new CplexLp(*this); }
+
+ const char* CplexLp::_solverName() const { return "CplexLp"; }
+
+ void CplexLp::_clear_temporals() {
+ _col_status.clear();
+ _row_status.clear();
+ _primal_ray.clear();
+ _dual_ray.clear();
+ }
+
+ // The routine returns zero unless an error occurred during the
+ // optimization. Examples of errors include exhausting available
+ // memory (CPXERR_NO_MEMORY) or encountering invalid data in the
+ // CPLEX problem object (CPXERR_NO_PROBLEM). Exceeding a
+ // user-specified CPLEX limit, or proving the model infeasible or
+ // unbounded, are not considered errors. Note that a zero return
+ // value does not necessarily mean that a solution exists. Use query
+ // routines CPXsolninfo, CPXgetstat, and CPXsolution to obtain
+ // further information about the status of the optimization.
+ CplexLp::SolveExitStatus CplexLp::convertStatus(int status) {
+#if CPX_VERSION >= 800
+ if (status == 0) {
+ switch (CPXgetstat(cplexEnv(), _prob)) {
+ case CPX_STAT_OPTIMAL:
+ case CPX_STAT_INFEASIBLE:
+ case CPX_STAT_UNBOUNDED:
+ return SOLVED;
+ default:
+ return UNSOLVED;
+ }
+ } else {
+ return UNSOLVED;
+ }
+#else
+ if (status == 0) {
+ //We want to exclude some cases
+ switch (CPXgetstat(cplexEnv(), _prob)) {
+ case CPX_OBJ_LIM:
+ case CPX_IT_LIM_FEAS:
+ case CPX_IT_LIM_INFEAS:
+ case CPX_TIME_LIM_FEAS:
+ case CPX_TIME_LIM_INFEAS:
+ return UNSOLVED;
+ default:
+ return SOLVED;
+ }
+ } else {
+ return UNSOLVED;
+ }
+#endif
+ }
+
+ CplexLp::SolveExitStatus CplexLp::_solve() {
+ _clear_temporals();
+ _applyMessageLevel();
+ return convertStatus(CPXlpopt(cplexEnv(), _prob));
+ }
+
+ CplexLp::SolveExitStatus CplexLp::solvePrimal() {
+ _clear_temporals();
+ _applyMessageLevel();
+ return convertStatus(CPXprimopt(cplexEnv(), _prob));
+ }
+
+ CplexLp::SolveExitStatus CplexLp::solveDual() {
+ _clear_temporals();
+ _applyMessageLevel();
+ return convertStatus(CPXdualopt(cplexEnv(), _prob));
+ }
+
+ CplexLp::SolveExitStatus CplexLp::solveBarrier() {
+ _clear_temporals();
+ _applyMessageLevel();
+ return convertStatus(CPXbaropt(cplexEnv(), _prob));
+ }
+
+ CplexLp::Value CplexLp::_getPrimal(int i) const {
+ Value x;
+ CPXgetx(cplexEnv(), _prob, &x, i, i);
+ return x;
+ }
+
+ CplexLp::Value CplexLp::_getDual(int i) const {
+ Value y;
+ CPXgetpi(cplexEnv(), _prob, &y, i, i);
+ return y;
+ }
+
+ CplexLp::Value CplexLp::_getPrimalValue() const {
+ Value objval;
+ CPXgetobjval(cplexEnv(), _prob, &objval);
+ return objval;
+ }
+
+ CplexLp::VarStatus CplexLp::_getColStatus(int i) const {
+ if (_col_status.empty()) {
+ _col_status.resize(CPXgetnumcols(cplexEnv(), _prob));
+ CPXgetbase(cplexEnv(), _prob, &_col_status.front(), 0);
+ }
+ switch (_col_status[i]) {
+ case CPX_BASIC:
+ return BASIC;
+ case CPX_FREE_SUPER:
+ return FREE;
+ case CPX_AT_LOWER:
+ return LOWER;
+ case CPX_AT_UPPER:
+ return UPPER;
+ default:
+ LEMON_ASSERT(false, "Wrong column status");
+ return CplexLp::VarStatus();
+ }
+ }
+
+ CplexLp::VarStatus CplexLp::_getRowStatus(int i) const {
+ if (_row_status.empty()) {
+ _row_status.resize(CPXgetnumrows(cplexEnv(), _prob));
+ CPXgetbase(cplexEnv(), _prob, 0, &_row_status.front());
+ }
+ switch (_row_status[i]) {
+ case CPX_BASIC:
+ return BASIC;
+ case CPX_AT_LOWER:
+ {
+ char s;
+ CPXgetsense(cplexEnv(), _prob, &s, i, i);
+ return s != 'L' ? LOWER : UPPER;
+ }
+ case CPX_AT_UPPER:
+ return UPPER;
+ default:
+ LEMON_ASSERT(false, "Wrong row status");
+ return CplexLp::VarStatus();
+ }
+ }
+
+ CplexLp::Value CplexLp::_getPrimalRay(int i) const {
+ if (_primal_ray.empty()) {
+ _primal_ray.resize(CPXgetnumcols(cplexEnv(), _prob));
+ CPXgetray(cplexEnv(), _prob, &_primal_ray.front());
+ }
+ return _primal_ray[i];
+ }
+
+ CplexLp::Value CplexLp::_getDualRay(int i) const {
+ if (_dual_ray.empty()) {
+
+ }
+ return _dual_ray[i];
+ }
+
+ // Cplex 7.0 status values
+ // This table lists the statuses, returned by the CPXgetstat()
+ // routine, for solutions to LP problems or mixed integer problems. If
+ // no solution exists, the return value is zero.
+
+ // For Simplex, Barrier
+ // 1 CPX_OPTIMAL
+ // Optimal solution found
+ // 2 CPX_INFEASIBLE
+ // Problem infeasible
+ // 3 CPX_UNBOUNDED
+ // Problem unbounded
+ // 4 CPX_OBJ_LIM
+ // Objective limit exceeded in Phase II
+ // 5 CPX_IT_LIM_FEAS
+ // Iteration limit exceeded in Phase II
+ // 6 CPX_IT_LIM_INFEAS
+ // Iteration limit exceeded in Phase I
+ // 7 CPX_TIME_LIM_FEAS
+ // Time limit exceeded in Phase II
+ // 8 CPX_TIME_LIM_INFEAS
+ // Time limit exceeded in Phase I
+ // 9 CPX_NUM_BEST_FEAS
+ // Problem non-optimal, singularities in Phase II
+ // 10 CPX_NUM_BEST_INFEAS
+ // Problem non-optimal, singularities in Phase I
+ // 11 CPX_OPTIMAL_INFEAS
+ // Optimal solution found, unscaled infeasibilities
+ // 12 CPX_ABORT_FEAS
+ // Aborted in Phase II
+ // 13 CPX_ABORT_INFEAS
+ // Aborted in Phase I
+ // 14 CPX_ABORT_DUAL_INFEAS
+ // Aborted in barrier, dual infeasible
+ // 15 CPX_ABORT_PRIM_INFEAS
+ // Aborted in barrier, primal infeasible
+ // 16 CPX_ABORT_PRIM_DUAL_INFEAS
+ // Aborted in barrier, primal and dual infeasible
+ // 17 CPX_ABORT_PRIM_DUAL_FEAS
+ // Aborted in barrier, primal and dual feasible
+ // 18 CPX_ABORT_CROSSOVER
+ // Aborted in crossover
+ // 19 CPX_INForUNBD
+ // Infeasible or unbounded
+ // 20 CPX_PIVOT
+ // User pivot used
+ //
+ // Pending return values
+ // ??case CPX_ABORT_DUAL_INFEAS
+ // ??case CPX_ABORT_CROSSOVER
+ // ??case CPX_INForUNBD
+ // ??case CPX_PIVOT
+
+ //Some more interesting stuff:
+
+ // CPX_PARAM_PROBMETHOD 1062 int LPMETHOD
+ // 0 Automatic
+ // 1 Primal Simplex
+ // 2 Dual Simplex
+ // 3 Network Simplex
+ // 4 Standard Barrier
+ // Default: 0
+ // Description: Method for linear optimization.
+ // Determines which algorithm is used when CPXlpopt() (or "optimize"
+ // in the Interactive Optimizer) is called. Currently the behavior of
+ // the "Automatic" setting is that CPLEX simply invokes the dual
+ // simplex method, but this capability may be expanded in the future
+ // so that CPLEX chooses the method based on problem characteristics
+#if CPX_VERSION < 900
+ void statusSwitch(CPXENVptr cplexEnv(),int& stat){
+ int lpmethod;
+ CPXgetintparam (cplexEnv(),CPX_PARAM_PROBMETHOD,&lpmethod);
+ if (lpmethod==2){
+ if (stat==CPX_UNBOUNDED){
+ stat=CPX_INFEASIBLE;
+ }
+ else{
+ if (stat==CPX_INFEASIBLE)
+ stat=CPX_UNBOUNDED;
+ }
+ }
+ }
+#else
+ void statusSwitch(CPXENVptr,int&){}
+#endif
+
+ CplexLp::ProblemType CplexLp::_getPrimalType() const {
+ // Unboundedness not treated well: the following is from cplex 9.0 doc
+ // About Unboundedness
+
+ // The treatment of models that are unbounded involves a few
+ // subtleties. Specifically, a declaration of unboundedness means that
+ // ILOG CPLEX has determined that the model has an unbounded
+ // ray. Given any feasible solution x with objective z, a multiple of
+ // the unbounded ray can be added to x to give a feasible solution
+ // with objective z-1 (or z+1 for maximization models). Thus, if a
+ // feasible solution exists, then the optimal objective is
+ // unbounded. Note that ILOG CPLEX has not necessarily concluded that
+ // a feasible solution exists. Users can call the routine CPXsolninfo
+ // to determine whether ILOG CPLEX has also concluded that the model
+ // has a feasible solution.
+
+ int stat = CPXgetstat(cplexEnv(), _prob);
+#if CPX_VERSION >= 800
+ switch (stat)
+ {
+ case CPX_STAT_OPTIMAL:
+ return OPTIMAL;
+ case CPX_STAT_UNBOUNDED:
+ return UNBOUNDED;
+ case CPX_STAT_INFEASIBLE:
+ return INFEASIBLE;
+ default:
+ return UNDEFINED;
+ }
+#else
+ statusSwitch(cplexEnv(),stat);
+ //CPXgetstat(cplexEnv(), _prob);
+ switch (stat) {
+ case 0:
+ return UNDEFINED; //Undefined
+ case CPX_OPTIMAL://Optimal
+ return OPTIMAL;
+ case CPX_UNBOUNDED://Unbounded
+ return INFEASIBLE;//In case of dual simplex
+ //return UNBOUNDED;
+ case CPX_INFEASIBLE://Infeasible
+ // case CPX_IT_LIM_INFEAS:
+ // case CPX_TIME_LIM_INFEAS:
+ // case CPX_NUM_BEST_INFEAS:
+ // case CPX_OPTIMAL_INFEAS:
+ // case CPX_ABORT_INFEAS:
+ // case CPX_ABORT_PRIM_INFEAS:
+ // case CPX_ABORT_PRIM_DUAL_INFEAS:
+ return UNBOUNDED;//In case of dual simplex
+ //return INFEASIBLE;
+ // case CPX_OBJ_LIM:
+ // case CPX_IT_LIM_FEAS:
+ // case CPX_TIME_LIM_FEAS:
+ // case CPX_NUM_BEST_FEAS:
+ // case CPX_ABORT_FEAS:
+ // case CPX_ABORT_PRIM_DUAL_FEAS:
+ // return FEASIBLE;
+ default:
+ return UNDEFINED; //Everything else comes here
+ //FIXME error
+ }
+#endif
+ }
+
+ // Cplex 9.0 status values
+ // CPX_STAT_ABORT_DUAL_OBJ_LIM
+ // CPX_STAT_ABORT_IT_LIM
+ // CPX_STAT_ABORT_OBJ_LIM
+ // CPX_STAT_ABORT_PRIM_OBJ_LIM
+ // CPX_STAT_ABORT_TIME_LIM
+ // CPX_STAT_ABORT_USER
+ // CPX_STAT_FEASIBLE_RELAXED
+ // CPX_STAT_INFEASIBLE
+ // CPX_STAT_INForUNBD
+ // CPX_STAT_NUM_BEST
+ // CPX_STAT_OPTIMAL
+ // CPX_STAT_OPTIMAL_FACE_UNBOUNDED
+ // CPX_STAT_OPTIMAL_INFEAS
+ // CPX_STAT_OPTIMAL_RELAXED
+ // CPX_STAT_UNBOUNDED
+
+ CplexLp::ProblemType CplexLp::_getDualType() const {
+ int stat = CPXgetstat(cplexEnv(), _prob);
+#if CPX_VERSION >= 800
+ switch (stat) {
+ case CPX_STAT_OPTIMAL:
+ return OPTIMAL;
+ case CPX_STAT_UNBOUNDED:
+ return INFEASIBLE;
+ default:
+ return UNDEFINED;
+ }
+#else
+ statusSwitch(cplexEnv(),stat);
+ switch (stat) {
+ case 0:
+ return UNDEFINED; //Undefined
+ case CPX_OPTIMAL://Optimal
+ return OPTIMAL;
+ case CPX_UNBOUNDED:
+ return INFEASIBLE;
+ default:
+ return UNDEFINED; //Everything else comes here
+ //FIXME error
+ }
+#endif
+ }
+
+ // CplexMip members
+
+ CplexMip::CplexMip()
+ : LpBase(), MipSolver(), CplexBase() {
+
+#if CPX_VERSION < 800
+ CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP);
+#else
+ CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MILP);
+#endif
+ }
+
+ CplexMip::CplexMip(const CplexEnv& env)
+ : LpBase(), MipSolver(), CplexBase(env) {
+
+#if CPX_VERSION < 800
+ CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP);
+#else
+ CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MILP);
+#endif
+
+ }
+
+ CplexMip::CplexMip(const CplexMip& other)
+ : LpBase(), MipSolver(), CplexBase(other) {}
+
+ CplexMip::~CplexMip() {}
+
+ CplexMip* CplexMip::newSolver() const { return new CplexMip; }
+ CplexMip* CplexMip::cloneSolver() const {return new CplexMip(*this); }
+
+ const char* CplexMip::_solverName() const { return "CplexMip"; }
+
+ void CplexMip::_setColType(int i, CplexMip::ColTypes col_type) {
+
+ // Note If a variable is to be changed to binary, a call to CPXchgbds
+ // should also be made to change the bounds to 0 and 1.
+
+ switch (col_type){
+ case INTEGER: {
+ const char t = 'I';
+ CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
+ } break;
+ case REAL: {
+ const char t = 'C';
+ CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
+ } break;
+ default:
+ break;
+ }
+ }
+
+ CplexMip::ColTypes CplexMip::_getColType(int i) const {
+ char t;
+ CPXgetctype (cplexEnv(), _prob, &t, i, i);
+ switch (t) {
+ case 'I':
+ return INTEGER;
+ case 'C':
+ return REAL;
+ default:
+ LEMON_ASSERT(false, "Invalid column type");
+ return ColTypes();
+ }
+
+ }
+
+ CplexMip::SolveExitStatus CplexMip::_solve() {
+ int status;
+ _applyMessageLevel();
+ status = CPXmipopt (cplexEnv(), _prob);
+ if (status==0)
+ return SOLVED;
+ else
+ return UNSOLVED;
+
+ }
+
+
+ CplexMip::ProblemType CplexMip::_getType() const {
+
+ int stat = CPXgetstat(cplexEnv(), _prob);
+
+ //Fortunately, MIP statuses did not change for cplex 8.0
+ switch (stat) {
+ case CPXMIP_OPTIMAL:
+ // Optimal integer solution has been found.
+ case CPXMIP_OPTIMAL_TOL:
+ // Optimal soluton with the tolerance defined by epgap or epagap has
+ // been found.
+ return OPTIMAL;
+ //This also exists in later issues
+ // case CPXMIP_UNBOUNDED:
+ //return UNBOUNDED;
+ case CPXMIP_INFEASIBLE:
+ return INFEASIBLE;
+ default:
+ return UNDEFINED;
+ }
+ //Unboundedness not treated well: the following is from cplex 9.0 doc
+ // About Unboundedness
+
+ // The treatment of models that are unbounded involves a few
+ // subtleties. Specifically, a declaration of unboundedness means that
+ // ILOG CPLEX has determined that the model has an unbounded
+ // ray. Given any feasible solution x with objective z, a multiple of
+ // the unbounded ray can be added to x to give a feasible solution
+ // with objective z-1 (or z+1 for maximization models). Thus, if a
+ // feasible solution exists, then the optimal objective is
+ // unbounded. Note that ILOG CPLEX has not necessarily concluded that
+ // a feasible solution exists. Users can call the routine CPXsolninfo
+ // to determine whether ILOG CPLEX has also concluded that the model
+ // has a feasible solution.
+ }
+
+ CplexMip::Value CplexMip::_getSol(int i) const {
+ Value x;
+ CPXgetmipx(cplexEnv(), _prob, &x, i, i);
+ return x;
+ }
+
+ CplexMip::Value CplexMip::_getSolValue() const {
+ Value objval;
+ CPXgetmipobjval(cplexEnv(), _prob, &objval);
+ return objval;
+ }
+
+} //namespace lemon
+
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/cplex.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cplex.h
new file mode 100644
index 00000000000..c17e7926ad6
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cplex.h
@@ -0,0 +1,292 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_CPLEX_H
+#define LEMON_CPLEX_H
+
+///\file
+///\brief Header of the LEMON-CPLEX lp solver interface.
+
+#include <lemon/lp_base.h>
+
+struct cpxenv;
+struct cpxlp;
+
+namespace lemon {
+
+ /// \brief Reference counted wrapper around cpxenv pointer
+ ///
+ /// The cplex uses environment object which is responsible for
+ /// checking the proper license usage. This class provides a simple
+ /// interface for share the environment object between different
+ /// problems.
+ class CplexEnv {
+ friend class CplexBase;
+ private:
+ cpxenv* _env;
+ mutable int* _cnt;
+
+ public:
+
+ /// \brief This exception is thrown when the license check is not
+ /// sufficient
+ class LicenseError : public Exception {
+ friend class CplexEnv;
+ private:
+
+ LicenseError(int status);
+ char _message[510];
+
+ public:
+
+ /// The short error message
+ virtual const char* what() const throw() {
+ return _message;
+ }
+ };
+
+ /// Constructor
+ CplexEnv();
+ /// Shallow copy constructor
+ CplexEnv(const CplexEnv&);
+ /// Shallow assignement
+ CplexEnv& operator=(const CplexEnv&);
+ /// Destructor
+ virtual ~CplexEnv();
+
+ protected:
+
+ cpxenv* cplexEnv() { return _env; }
+ const cpxenv* cplexEnv() const { return _env; }
+ };
+
+ /// \brief Base interface for the CPLEX LP and MIP solver
+ ///
+ /// This class implements the common interface of the CPLEX LP and
+ /// MIP solvers.
+ /// \ingroup lp_group
+ class CplexBase : virtual public LpBase {
+ protected:
+
+ CplexEnv _env;
+ cpxlp* _prob;
+
+ CplexBase();
+ CplexBase(const CplexEnv&);
+ CplexBase(const CplexBase &);
+ virtual ~CplexBase();
+
+ virtual int _addCol();
+ virtual int _addRow();
+ virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u);
+
+ virtual void _eraseCol(int i);
+ virtual void _eraseRow(int i);
+
+ virtual void _eraseColId(int i);
+ virtual void _eraseRowId(int i);
+
+ virtual void _getColName(int col, std::string& name) const;
+ virtual void _setColName(int col, const std::string& name);
+ virtual int _colByName(const std::string& name) const;
+
+ virtual void _getRowName(int row, std::string& name) const;
+ virtual void _setRowName(int row, const std::string& name);
+ virtual int _rowByName(const std::string& name) const;
+
+ virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e);
+ virtual void _getRowCoeffs(int i, InsertIterator b) const;
+
+ virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e);
+ virtual void _getColCoeffs(int i, InsertIterator b) const;
+
+ virtual void _setCoeff(int row, int col, Value value);
+ virtual Value _getCoeff(int row, int col) const;
+
+ virtual void _setColLowerBound(int i, Value value);
+ virtual Value _getColLowerBound(int i) const;
+
+ virtual void _setColUpperBound(int i, Value value);
+ virtual Value _getColUpperBound(int i) const;
+
+ private:
+ void _set_row_bounds(int i, Value lb, Value ub);
+ protected:
+
+ virtual void _setRowLowerBound(int i, Value value);
+ virtual Value _getRowLowerBound(int i) const;
+
+ virtual void _setRowUpperBound(int i, Value value);
+ virtual Value _getRowUpperBound(int i) const;
+
+ virtual void _setObjCoeffs(ExprIterator b, ExprIterator e);
+ virtual void _getObjCoeffs(InsertIterator b) const;
+
+ virtual void _setObjCoeff(int i, Value obj_coef);
+ virtual Value _getObjCoeff(int i) const;
+
+ virtual void _setSense(Sense sense);
+ virtual Sense _getSense() const;
+
+ virtual void _clear();
+
+ virtual void _messageLevel(MessageLevel level);
+ void _applyMessageLevel();
+
+ bool _message_enabled;
+
+ void _write(std::string file, std::string format) const;
+
+ public:
+
+ /// Returns the used \c CplexEnv instance
+ const CplexEnv& env() const { return _env; }
+
+ /// \brief Returns the const cpxenv pointer
+ ///
+ /// \note The cpxenv might be destructed with the solver.
+ const cpxenv* cplexEnv() const { return _env.cplexEnv(); }
+
+ /// \brief Returns the const cpxenv pointer
+ ///
+ /// \note The cpxenv might be destructed with the solver.
+ cpxenv* cplexEnv() { return _env.cplexEnv(); }
+
+ /// Returns the cplex problem object
+ cpxlp* cplexLp() { return _prob; }
+ /// Returns the cplex problem object
+ const cpxlp* cplexLp() const { return _prob; }
+
+#ifdef DOXYGEN
+ /// Write the problem or the solution to a file in the given format
+
+ /// This function writes the problem or the solution
+ /// to a file in the given format.
+ /// Trying to write in an unsupported format will trigger
+ /// \ref lemon::LpBase::UnsupportedFormatError "UnsupportedFormatError".
+ /// \param file The file path
+ /// \param format The output file format.
+ /// Supportted formats are "MPS", "LP" and "SOL".
+ void write(std::string file, std::string format = "MPS") const {}
+#endif
+
+ };
+
+ /// \brief Interface for the CPLEX LP solver
+ ///
+ /// This class implements an interface for the CPLEX LP solver.
+ ///\ingroup lp_group
+ class CplexLp : public LpSolver, public CplexBase {
+ public:
+ /// \e
+ CplexLp();
+ /// \e
+ CplexLp(const CplexEnv&);
+ /// \e
+ CplexLp(const CplexLp&);
+ /// \e
+ virtual ~CplexLp();
+
+ /// \e
+ virtual CplexLp* cloneSolver() const;
+ /// \e
+ virtual CplexLp* newSolver() const;
+
+ private:
+
+ // these values cannot retrieved element by element
+ mutable std::vector<int> _col_status;
+ mutable std::vector<int> _row_status;
+
+ mutable std::vector<Value> _primal_ray;
+ mutable std::vector<Value> _dual_ray;
+
+ void _clear_temporals();
+
+ SolveExitStatus convertStatus(int status);
+
+ protected:
+
+ virtual const char* _solverName() const;
+
+ virtual SolveExitStatus _solve();
+ virtual Value _getPrimal(int i) const;
+ virtual Value _getDual(int i) const;
+ virtual Value _getPrimalValue() const;
+
+ virtual VarStatus _getColStatus(int i) const;
+ virtual VarStatus _getRowStatus(int i) const;
+
+ virtual Value _getPrimalRay(int i) const;
+ virtual Value _getDualRay(int i) const;
+
+ virtual ProblemType _getPrimalType() const;
+ virtual ProblemType _getDualType() const;
+
+ public:
+
+ /// Solve with primal simplex method
+ SolveExitStatus solvePrimal();
+
+ /// Solve with dual simplex method
+ SolveExitStatus solveDual();
+
+ /// Solve with barrier method
+ SolveExitStatus solveBarrier();
+
+ };
+
+ /// \brief Interface for the CPLEX MIP solver
+ ///
+ /// This class implements an interface for the CPLEX MIP solver.
+ ///\ingroup lp_group
+ class CplexMip : public MipSolver, public CplexBase {
+ public:
+ /// \e
+ CplexMip();
+ /// \e
+ CplexMip(const CplexEnv&);
+ /// \e
+ CplexMip(const CplexMip&);
+ /// \e
+ virtual ~CplexMip();
+
+ /// \e
+ virtual CplexMip* cloneSolver() const;
+ /// \e
+ virtual CplexMip* newSolver() const;
+
+ protected:
+
+
+ virtual const char* _solverName() const;
+
+ virtual ColTypes _getColType(int col) const;
+ virtual void _setColType(int col, ColTypes col_type);
+
+ virtual SolveExitStatus _solve();
+ virtual ProblemType _getType() const;
+ virtual Value _getSol(int i) const;
+ virtual Value _getSolValue() const;
+
+ };
+
+} //END OF NAMESPACE LEMON
+
+#endif //LEMON_CPLEX_H
+
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/cycle_canceling.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cycle_canceling.h
new file mode 100644
index 00000000000..646d299e3ec
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cycle_canceling.h
@@ -0,0 +1,1230 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_CYCLE_CANCELING_H
+#define LEMON_CYCLE_CANCELING_H
+
+/// \ingroup min_cost_flow_algs
+/// \file
+/// \brief Cycle-canceling algorithms for finding a minimum cost flow.
+
+#include <vector>
+#include <limits>
+
+#include <lemon/core.h>
+#include <lemon/maps.h>
+#include <lemon/path.h>
+#include <lemon/math.h>
+#include <lemon/static_graph.h>
+#include <lemon/adaptors.h>
+#include <lemon/circulation.h>
+#include <lemon/bellman_ford.h>
+#include <lemon/howard_mmc.h>
+#include <lemon/hartmann_orlin_mmc.h>
+
+namespace lemon {
+
+ /// \addtogroup min_cost_flow_algs
+ /// @{
+
+ /// \brief Implementation of cycle-canceling algorithms for
+ /// finding a \ref min_cost_flow "minimum cost flow".
+ ///
+ /// \ref CycleCanceling implements three different cycle-canceling
+ /// algorithms for finding a \ref min_cost_flow "minimum cost flow"
+ /// \cite amo93networkflows, \cite klein67primal,
+ /// \cite goldberg89cyclecanceling.
+ /// The most efficent one is the \ref CANCEL_AND_TIGHTEN
+ /// "Cancel-and-Tighten" algorithm, thus it is the default method.
+ /// It runs in strongly polynomial time \f$O(n^2 m^2 \log n)\f$,
+ /// but in practice, it is typically orders of magnitude slower than
+ /// the scaling algorithms and \ref NetworkSimplex.
+ /// (For more information, see \ref min_cost_flow_algs "the module page".)
+ ///
+ /// Most of the parameters of the problem (except for the digraph)
+ /// can be given using separate functions, and the algorithm can be
+ /// executed using the \ref run() function. If some parameters are not
+ /// specified, then default values will be used.
+ ///
+ /// \tparam GR The digraph type the algorithm runs on.
+ /// \tparam V The number type used for flow amounts, capacity bounds
+ /// and supply values in the algorithm. By default, it is \c int.
+ /// \tparam C The number type used for costs and potentials in the
+ /// algorithm. By default, it is the same as \c V.
+ ///
+ /// \warning Both \c V and \c C must be signed number types.
+ /// \warning All input data (capacities, supply values, and costs) must
+ /// be integer.
+ /// \warning This algorithm does not support negative costs for
+ /// arcs having infinite upper bound.
+ ///
+ /// \note For more information about the three available methods,
+ /// see \ref Method.
+#ifdef DOXYGEN
+ template <typename GR, typename V, typename C>
+#else
+ template <typename GR, typename V = int, typename C = V>
+#endif
+ class CycleCanceling
+ {
+ public:
+
+ /// The type of the digraph
+ typedef GR Digraph;
+ /// The type of the flow amounts, capacity bounds and supply values
+ typedef V Value;
+ /// The type of the arc costs
+ typedef C Cost;
+
+ public:
+
+ /// \brief Problem type constants for the \c run() function.
+ ///
+ /// Enum type containing the problem type constants that can be
+ /// returned by the \ref run() function of the algorithm.
+ enum ProblemType {
+ /// The problem has no feasible solution (flow).
+ INFEASIBLE,
+ /// The problem has optimal solution (i.e. it is feasible and
+ /// bounded), and the algorithm has found optimal flow and node
+ /// potentials (primal and dual solutions).
+ OPTIMAL,
+ /// The digraph contains an arc of negative cost and infinite
+ /// upper bound. It means that the objective function is unbounded
+ /// on that arc, however, note that it could actually be bounded
+ /// over the feasible flows, but this algroithm cannot handle
+ /// these cases.
+ UNBOUNDED
+ };
+
+ /// \brief Constants for selecting the used method.
+ ///
+ /// Enum type containing constants for selecting the used method
+ /// for the \ref run() function.
+ ///
+ /// \ref CycleCanceling provides three different cycle-canceling
+ /// methods. By default, \ref CANCEL_AND_TIGHTEN "Cancel-and-Tighten"
+ /// is used, which is by far the most efficient and the most robust.
+ /// However, the other methods can be selected using the \ref run()
+ /// function with the proper parameter.
+ enum Method {
+ /// A simple cycle-canceling method, which uses the
+ /// \ref BellmanFord "Bellman-Ford" algorithm for detecting negative
+ /// cycles in the residual network.
+ /// The number of Bellman-Ford iterations is bounded by a successively
+ /// increased limit.
+ SIMPLE_CYCLE_CANCELING,
+ /// The "Minimum Mean Cycle-Canceling" algorithm, which is a
+ /// well-known strongly polynomial method
+ /// \cite goldberg89cyclecanceling. It improves along a
+ /// \ref min_mean_cycle "minimum mean cycle" in each iteration.
+ /// Its running time complexity is \f$O(n^2 m^3 \log n)\f$.
+ MINIMUM_MEAN_CYCLE_CANCELING,
+ /// The "Cancel-and-Tighten" algorithm, which can be viewed as an
+ /// improved version of the previous method
+ /// \cite goldberg89cyclecanceling.
+ /// It is faster both in theory and in practice, its running time
+ /// complexity is \f$O(n^2 m^2 \log n)\f$.
+ CANCEL_AND_TIGHTEN
+ };
+
+ private:
+
+ TEMPLATE_DIGRAPH_TYPEDEFS(GR);
+
+ typedef std::vector<int> IntVector;
+ typedef std::vector<double> DoubleVector;
+ typedef std::vector<Value> ValueVector;
+ typedef std::vector<Cost> CostVector;
+ typedef std::vector<char> BoolVector;
+ // Note: vector<char> is used instead of vector<bool> for efficiency reasons
+
+ private:
+
+ template <typename KT, typename VT>
+ class StaticVectorMap {
+ public:
+ typedef KT Key;
+ typedef VT Value;
+
+ StaticVectorMap(std::vector<Value>& v) : _v(v) {}
+
+ const Value& operator[](const Key& key) const {
+ return _v[StaticDigraph::id(key)];
+ }
+
+ Value& operator[](const Key& key) {
+ return _v[StaticDigraph::id(key)];
+ }
+
+ void set(const Key& key, const Value& val) {
+ _v[StaticDigraph::id(key)] = val;
+ }
+
+ private:
+ std::vector<Value>& _v;
+ };
+
+ typedef StaticVectorMap<StaticDigraph::Node, Cost> CostNodeMap;
+ typedef StaticVectorMap<StaticDigraph::Arc, Cost> CostArcMap;
+
+ private:
+
+
+ // Data related to the underlying digraph
+ const GR &_graph;
+ int _node_num;
+ int _arc_num;
+ int _res_node_num;
+ int _res_arc_num;
+ int _root;
+
+ // Parameters of the problem
+ bool _has_lower;
+ Value _sum_supply;
+
+ // Data structures for storing the digraph
+ IntNodeMap _node_id;
+ IntArcMap _arc_idf;
+ IntArcMap _arc_idb;
+ IntVector _first_out;
+ BoolVector _forward;
+ IntVector _source;
+ IntVector _target;
+ IntVector _reverse;
+
+ // Node and arc data
+ ValueVector _lower;
+ ValueVector _upper;
+ CostVector _cost;
+ ValueVector _supply;
+
+ ValueVector _res_cap;
+ CostVector _pi;
+
+ // Data for a StaticDigraph structure
+ typedef std::pair<int, int> IntPair;
+ StaticDigraph _sgr;
+ std::vector<IntPair> _arc_vec;
+ std::vector<Cost> _cost_vec;
+ IntVector _id_vec;
+ CostArcMap _cost_map;
+ CostNodeMap _pi_map;
+
+ public:
+
+ /// \brief Constant for infinite upper bounds (capacities).
+ ///
+ /// Constant for infinite upper bounds (capacities).
+ /// It is \c std::numeric_limits<Value>::infinity() if available,
+ /// \c std::numeric_limits<Value>::max() otherwise.
+ const Value INF;
+
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// The constructor of the class.
+ ///
+ /// \param graph The digraph the algorithm runs on.
+ CycleCanceling(const GR& graph) :
+ _graph(graph), _node_id(graph), _arc_idf(graph), _arc_idb(graph),
+ _cost_map(_cost_vec), _pi_map(_pi),
+ INF(std::numeric_limits<Value>::has_infinity ?
+ std::numeric_limits<Value>::infinity() :
+ std::numeric_limits<Value>::max())
+ {
+ // Check the number types
+ LEMON_ASSERT(std::numeric_limits<Value>::is_signed,
+ "The flow type of CycleCanceling must be signed");
+ LEMON_ASSERT(std::numeric_limits<Cost>::is_signed,
+ "The cost type of CycleCanceling must be signed");
+
+ // Reset data structures
+ reset();
+ }
+
+ /// \name Parameters
+ /// The parameters of the algorithm can be specified using these
+ /// functions.
+
+ /// @{
+
+ /// \brief Set the lower bounds on the arcs.
+ ///
+ /// This function sets the lower bounds on the arcs.
+ /// If it is not used before calling \ref run(), the lower bounds
+ /// will be set to zero on all arcs.
+ ///
+ /// \param map An arc map storing the lower bounds.
+ /// Its \c Value type must be convertible to the \c Value type
+ /// of the algorithm.
+ ///
+ /// \return <tt>(*this)</tt>
+ template <typename LowerMap>
+ CycleCanceling& lowerMap(const LowerMap& map) {
+ _has_lower = true;
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ _lower[_arc_idf[a]] = map[a];
+ }
+ return *this;
+ }
+
+ /// \brief Set the upper bounds (capacities) on the arcs.
+ ///
+ /// This function sets the upper bounds (capacities) on the arcs.
+ /// If it is not used before calling \ref run(), the upper bounds
+ /// will be set to \ref INF on all arcs (i.e. the flow value will be
+ /// unbounded from above).
+ ///
+ /// \param map An arc map storing the upper bounds.
+ /// Its \c Value type must be convertible to the \c Value type
+ /// of the algorithm.
+ ///
+ /// \return <tt>(*this)</tt>
+ template<typename UpperMap>
+ CycleCanceling& upperMap(const UpperMap& map) {
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ _upper[_arc_idf[a]] = map[a];
+ }
+ return *this;
+ }
+
+ /// \brief Set the costs of the arcs.
+ ///
+ /// This function sets the costs of the arcs.
+ /// If it is not used before calling \ref run(), the costs
+ /// will be set to \c 1 on all arcs.
+ ///
+ /// \param map An arc map storing the costs.
+ /// Its \c Value type must be convertible to the \c Cost type
+ /// of the algorithm.
+ ///
+ /// \return <tt>(*this)</tt>
+ template<typename CostMap>
+ CycleCanceling& costMap(const CostMap& map) {
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ _cost[_arc_idf[a]] = map[a];
+ _cost[_arc_idb[a]] = -map[a];
+ }
+ return *this;
+ }
+
+ /// \brief Set the supply values of the nodes.
+ ///
+ /// This function sets the supply values of the nodes.
+ /// If neither this function nor \ref stSupply() is used before
+ /// calling \ref run(), the supply of each node will be set to zero.
+ ///
+ /// \param map A node map storing the supply values.
+ /// Its \c Value type must be convertible to the \c Value type
+ /// of the algorithm.
+ ///
+ /// \return <tt>(*this)</tt>
+ template<typename SupplyMap>
+ CycleCanceling& supplyMap(const SupplyMap& map) {
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ _supply[_node_id[n]] = map[n];
+ }
+ return *this;
+ }
+
+ /// \brief Set single source and target nodes and a supply value.
+ ///
+ /// This function sets a single source node and a single target node
+ /// and the required flow value.
+ /// If neither this function nor \ref supplyMap() is used before
+ /// calling \ref run(), the supply of each node will be set to zero.
+ ///
+ /// Using this function has the same effect as using \ref supplyMap()
+ /// with a map in which \c k is assigned to \c s, \c -k is
+ /// assigned to \c t and all other nodes have zero supply value.
+ ///
+ /// \param s The source node.
+ /// \param t The target node.
+ /// \param k The required amount of flow from node \c s to node \c t
+ /// (i.e. the supply of \c s and the demand of \c t).
+ ///
+ /// \return <tt>(*this)</tt>
+ CycleCanceling& stSupply(const Node& s, const Node& t, Value k) {
+ for (int i = 0; i != _res_node_num; ++i) {
+ _supply[i] = 0;
+ }
+ _supply[_node_id[s]] = k;
+ _supply[_node_id[t]] = -k;
+ return *this;
+ }
+
+ /// @}
+
+ /// \name Execution control
+ /// The algorithm can be executed using \ref run().
+
+ /// @{
+
+ /// \brief Run the algorithm.
+ ///
+ /// This function runs the algorithm.
+ /// The paramters can be specified using functions \ref lowerMap(),
+ /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply().
+ /// For example,
+ /// \code
+ /// CycleCanceling<ListDigraph> cc(graph);
+ /// cc.lowerMap(lower).upperMap(upper).costMap(cost)
+ /// .supplyMap(sup).run();
+ /// \endcode
+ ///
+ /// This function can be called more than once. All the given parameters
+ /// are kept for the next call, unless \ref resetParams() or \ref reset()
+ /// is used, thus only the modified parameters have to be set again.
+ /// If the underlying digraph was also modified after the construction
+ /// of the class (or the last \ref reset() call), then the \ref reset()
+ /// function must be called.
+ ///
+ /// \param method The cycle-canceling method that will be used.
+ /// For more information, see \ref Method.
+ ///
+ /// \return \c INFEASIBLE if no feasible flow exists,
+ /// \n \c OPTIMAL if the problem has optimal solution
+ /// (i.e. it is feasible and bounded), and the algorithm has found
+ /// optimal flow and node potentials (primal and dual solutions),
+ /// \n \c UNBOUNDED if the digraph contains an arc of negative cost
+ /// and infinite upper bound. It means that the objective function
+ /// is unbounded on that arc, however, note that it could actually be
+ /// bounded over the feasible flows, but this algroithm cannot handle
+ /// these cases.
+ ///
+ /// \see ProblemType, Method
+ /// \see resetParams(), reset()
+ ProblemType run(Method method = CANCEL_AND_TIGHTEN) {
+ ProblemType pt = init();
+ if (pt != OPTIMAL) return pt;
+ start(method);
+ return OPTIMAL;
+ }
+
+ /// \brief Reset all the parameters that have been given before.
+ ///
+ /// This function resets all the paramaters that have been given
+ /// before using functions \ref lowerMap(), \ref upperMap(),
+ /// \ref costMap(), \ref supplyMap(), \ref stSupply().
+ ///
+ /// It is useful for multiple \ref run() calls. Basically, all the given
+ /// parameters are kept for the next \ref run() call, unless
+ /// \ref resetParams() or \ref reset() is used.
+ /// If the underlying digraph was also modified after the construction
+ /// of the class or the last \ref reset() call, then the \ref reset()
+ /// function must be used, otherwise \ref resetParams() is sufficient.
+ ///
+ /// For example,
+ /// \code
+ /// CycleCanceling<ListDigraph> cs(graph);
+ ///
+ /// // First run
+ /// cc.lowerMap(lower).upperMap(upper).costMap(cost)
+ /// .supplyMap(sup).run();
+ ///
+ /// // Run again with modified cost map (resetParams() is not called,
+ /// // so only the cost map have to be set again)
+ /// cost[e] += 100;
+ /// cc.costMap(cost).run();
+ ///
+ /// // Run again from scratch using resetParams()
+ /// // (the lower bounds will be set to zero on all arcs)
+ /// cc.resetParams();
+ /// cc.upperMap(capacity).costMap(cost)
+ /// .supplyMap(sup).run();
+ /// \endcode
+ ///
+ /// \return <tt>(*this)</tt>
+ ///
+ /// \see reset(), run()
+ CycleCanceling& resetParams() {
+ for (int i = 0; i != _res_node_num; ++i) {
+ _supply[i] = 0;
+ }
+ int limit = _first_out[_root];
+ for (int j = 0; j != limit; ++j) {
+ _lower[j] = 0;
+ _upper[j] = INF;
+ _cost[j] = _forward[j] ? 1 : -1;
+ }
+ for (int j = limit; j != _res_arc_num; ++j) {
+ _lower[j] = 0;
+ _upper[j] = INF;
+ _cost[j] = 0;
+ _cost[_reverse[j]] = 0;
+ }
+ _has_lower = false;
+ return *this;
+ }
+
+ /// \brief Reset the internal data structures and all the parameters
+ /// that have been given before.
+ ///
+ /// This function resets the internal data structures and all the
+ /// paramaters that have been given before using functions \ref lowerMap(),
+ /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply().
+ ///
+ /// It is useful for multiple \ref run() calls. Basically, all the given
+ /// parameters are kept for the next \ref run() call, unless
+ /// \ref resetParams() or \ref reset() is used.
+ /// If the underlying digraph was also modified after the construction
+ /// of the class or the last \ref reset() call, then the \ref reset()
+ /// function must be used, otherwise \ref resetParams() is sufficient.
+ ///
+ /// See \ref resetParams() for examples.
+ ///
+ /// \return <tt>(*this)</tt>
+ ///
+ /// \see resetParams(), run()
+ CycleCanceling& reset() {
+ // Resize vectors
+ _node_num = countNodes(_graph);
+ _arc_num = countArcs(_graph);
+ _res_node_num = _node_num + 1;
+ _res_arc_num = 2 * (_arc_num + _node_num);
+ _root = _node_num;
+
+ _first_out.resize(_res_node_num + 1);
+ _forward.resize(_res_arc_num);
+ _source.resize(_res_arc_num);
+ _target.resize(_res_arc_num);
+ _reverse.resize(_res_arc_num);
+
+ _lower.resize(_res_arc_num);
+ _upper.resize(_res_arc_num);
+ _cost.resize(_res_arc_num);
+ _supply.resize(_res_node_num);
+
+ _res_cap.resize(_res_arc_num);
+ _pi.resize(_res_node_num);
+
+ _arc_vec.reserve(_res_arc_num);
+ _cost_vec.reserve(_res_arc_num);
+ _id_vec.reserve(_res_arc_num);
+
+ // Copy the graph
+ int i = 0, j = 0, k = 2 * _arc_num + _node_num;
+ for (NodeIt n(_graph); n != INVALID; ++n, ++i) {
+ _node_id[n] = i;
+ }
+ i = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n, ++i) {
+ _first_out[i] = j;
+ for (OutArcIt a(_graph, n); a != INVALID; ++a, ++j) {
+ _arc_idf[a] = j;
+ _forward[j] = true;
+ _source[j] = i;
+ _target[j] = _node_id[_graph.runningNode(a)];
+ }
+ for (InArcIt a(_graph, n); a != INVALID; ++a, ++j) {
+ _arc_idb[a] = j;
+ _forward[j] = false;
+ _source[j] = i;
+ _target[j] = _node_id[_graph.runningNode(a)];
+ }
+ _forward[j] = false;
+ _source[j] = i;
+ _target[j] = _root;
+ _reverse[j] = k;
+ _forward[k] = true;
+ _source[k] = _root;
+ _target[k] = i;
+ _reverse[k] = j;
+ ++j; ++k;
+ }
+ _first_out[i] = j;
+ _first_out[_res_node_num] = k;
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ int fi = _arc_idf[a];
+ int bi = _arc_idb[a];
+ _reverse[fi] = bi;
+ _reverse[bi] = fi;
+ }
+
+ // Reset parameters
+ resetParams();
+ return *this;
+ }
+
+ /// @}
+
+ /// \name Query Functions
+ /// The results of the algorithm can be obtained using these
+ /// functions.\n
+ /// The \ref run() function must be called before using them.
+
+ /// @{
+
+ /// \brief Return the total cost of the found flow.
+ ///
+ /// This function returns the total cost of the found flow.
+ /// Its complexity is O(m).
+ ///
+ /// \note The return type of the function can be specified as a
+ /// template parameter. For example,
+ /// \code
+ /// cc.totalCost<double>();
+ /// \endcode
+ /// It is useful if the total cost cannot be stored in the \c Cost
+ /// type of the algorithm, which is the default return type of the
+ /// function.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ template <typename Number>
+ Number totalCost() const {
+ Number c = 0;
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ int i = _arc_idb[a];
+ c += static_cast<Number>(_res_cap[i]) *
+ (-static_cast<Number>(_cost[i]));
+ }
+ return c;
+ }
+
+#ifndef DOXYGEN
+ Cost totalCost() const {
+ return totalCost<Cost>();
+ }
+#endif
+
+ /// \brief Return the flow on the given arc.
+ ///
+ /// This function returns the flow on the given arc.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ Value flow(const Arc& a) const {
+ return _res_cap[_arc_idb[a]];
+ }
+
+ /// \brief Copy the flow values (the primal solution) into the
+ /// given map.
+ ///
+ /// This function copies the flow value on each arc into the given
+ /// map. The \c Value type of the algorithm must be convertible to
+ /// the \c Value type of the map.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ template <typename FlowMap>
+ void flowMap(FlowMap &map) const {
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ map.set(a, _res_cap[_arc_idb[a]]);
+ }
+ }
+
+ /// \brief Return the potential (dual value) of the given node.
+ ///
+ /// This function returns the potential (dual value) of the
+ /// given node.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ Cost potential(const Node& n) const {
+ return static_cast<Cost>(_pi[_node_id[n]]);
+ }
+
+ /// \brief Copy the potential values (the dual solution) into the
+ /// given map.
+ ///
+ /// This function copies the potential (dual value) of each node
+ /// into the given map.
+ /// The \c Cost type of the algorithm must be convertible to the
+ /// \c Value type of the map.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ template <typename PotentialMap>
+ void potentialMap(PotentialMap &map) const {
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ map.set(n, static_cast<Cost>(_pi[_node_id[n]]));
+ }
+ }
+
+ /// @}
+
+ private:
+
+ // Initialize the algorithm
+ ProblemType init() {
+ if (_res_node_num <= 1) return INFEASIBLE;
+
+ // Check the sum of supply values
+ _sum_supply = 0;
+ for (int i = 0; i != _root; ++i) {
+ _sum_supply += _supply[i];
+ }
+ if (_sum_supply > 0) return INFEASIBLE;
+
+ // Check lower and upper bounds
+ LEMON_DEBUG(checkBoundMaps(),
+ "Upper bounds must be greater or equal to the lower bounds");
+
+
+ // Initialize vectors
+ for (int i = 0; i != _res_node_num; ++i) {
+ _pi[i] = 0;
+ }
+ ValueVector excess(_supply);
+
+ // Remove infinite upper bounds and check negative arcs
+ const Value MAX = std::numeric_limits<Value>::max();
+ int last_out;
+ if (_has_lower) {
+ for (int i = 0; i != _root; ++i) {
+ last_out = _first_out[i+1];
+ for (int j = _first_out[i]; j != last_out; ++j) {
+ if (_forward[j]) {
+ Value c = _cost[j] < 0 ? _upper[j] : _lower[j];
+ if (c >= MAX) return UNBOUNDED;
+ excess[i] -= c;
+ excess[_target[j]] += c;
+ }
+ }
+ }
+ } else {
+ for (int i = 0; i != _root; ++i) {
+ last_out = _first_out[i+1];
+ for (int j = _first_out[i]; j != last_out; ++j) {
+ if (_forward[j] && _cost[j] < 0) {
+ Value c = _upper[j];
+ if (c >= MAX) return UNBOUNDED;
+ excess[i] -= c;
+ excess[_target[j]] += c;
+ }
+ }
+ }
+ }
+ Value ex, max_cap = 0;
+ for (int i = 0; i != _res_node_num; ++i) {
+ ex = excess[i];
+ if (ex < 0) max_cap -= ex;
+ }
+ for (int j = 0; j != _res_arc_num; ++j) {
+ if (_upper[j] >= MAX) _upper[j] = max_cap;
+ }
+
+ // Initialize maps for Circulation and remove non-zero lower bounds
+ ConstMap<Arc, Value> low(0);
+ typedef typename Digraph::template ArcMap<Value> ValueArcMap;
+ typedef typename Digraph::template NodeMap<Value> ValueNodeMap;
+ ValueArcMap cap(_graph), flow(_graph);
+ ValueNodeMap sup(_graph);
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ sup[n] = _supply[_node_id[n]];
+ }
+ if (_has_lower) {
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ int j = _arc_idf[a];
+ Value c = _lower[j];
+ cap[a] = _upper[j] - c;
+ sup[_graph.source(a)] -= c;
+ sup[_graph.target(a)] += c;
+ }
+ } else {
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ cap[a] = _upper[_arc_idf[a]];
+ }
+ }
+
+ // Find a feasible flow using Circulation
+ Circulation<Digraph, ConstMap<Arc, Value>, ValueArcMap, ValueNodeMap>
+ circ(_graph, low, cap, sup);
+ if (!circ.flowMap(flow).run()) return INFEASIBLE;
+
+ // Set residual capacities and handle GEQ supply type
+ if (_sum_supply < 0) {
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ Value fa = flow[a];
+ _res_cap[_arc_idf[a]] = cap[a] - fa;
+ _res_cap[_arc_idb[a]] = fa;
+ sup[_graph.source(a)] -= fa;
+ sup[_graph.target(a)] += fa;
+ }
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ excess[_node_id[n]] = sup[n];
+ }
+ for (int a = _first_out[_root]; a != _res_arc_num; ++a) {
+ int u = _target[a];
+ int ra = _reverse[a];
+ _res_cap[a] = -_sum_supply + 1;
+ _res_cap[ra] = -excess[u];
+ _cost[a] = 0;
+ _cost[ra] = 0;
+ }
+ } else {
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ Value fa = flow[a];
+ _res_cap[_arc_idf[a]] = cap[a] - fa;
+ _res_cap[_arc_idb[a]] = fa;
+ }
+ for (int a = _first_out[_root]; a != _res_arc_num; ++a) {
+ int ra = _reverse[a];
+ _res_cap[a] = 1;
+ _res_cap[ra] = 0;
+ _cost[a] = 0;
+ _cost[ra] = 0;
+ }
+ }
+
+ return OPTIMAL;
+ }
+
+ // Check if the upper bound is greater than or equal to the lower bound
+ // on each forward arc.
+ bool checkBoundMaps() {
+ for (int j = 0; j != _res_arc_num; ++j) {
+ if (_forward[j] && _upper[j] < _lower[j]) return false;
+ }
+ return true;
+ }
+
+ // Build a StaticDigraph structure containing the current
+ // residual network
+ void buildResidualNetwork() {
+ _arc_vec.clear();
+ _cost_vec.clear();
+ _id_vec.clear();
+ for (int j = 0; j != _res_arc_num; ++j) {
+ if (_res_cap[j] > 0) {
+ _arc_vec.push_back(IntPair(_source[j], _target[j]));
+ _cost_vec.push_back(_cost[j]);
+ _id_vec.push_back(j);
+ }
+ }
+ _sgr.build(_res_node_num, _arc_vec.begin(), _arc_vec.end());
+ }
+
+ // Execute the algorithm and transform the results
+ void start(Method method) {
+ // Execute the algorithm
+ switch (method) {
+ case SIMPLE_CYCLE_CANCELING:
+ startSimpleCycleCanceling();
+ break;
+ case MINIMUM_MEAN_CYCLE_CANCELING:
+ startMinMeanCycleCanceling();
+ break;
+ case CANCEL_AND_TIGHTEN:
+ startCancelAndTighten();
+ break;
+ }
+
+ // Compute node potentials
+ if (method != SIMPLE_CYCLE_CANCELING) {
+ buildResidualNetwork();
+ typename BellmanFord<StaticDigraph, CostArcMap>
+ ::template SetDistMap<CostNodeMap>::Create bf(_sgr, _cost_map);
+ bf.distMap(_pi_map);
+ bf.init(0);
+ bf.start();
+ }
+
+ // Handle non-zero lower bounds
+ if (_has_lower) {
+ int limit = _first_out[_root];
+ for (int j = 0; j != limit; ++j) {
+ if (_forward[j]) _res_cap[_reverse[j]] += _lower[j];
+ }
+ }
+ }
+
+ // Execute the "Simple Cycle Canceling" method
+ void startSimpleCycleCanceling() {
+ // Constants for computing the iteration limits
+ const int BF_FIRST_LIMIT = 2;
+ const double BF_LIMIT_FACTOR = 1.5;
+
+ typedef StaticVectorMap<StaticDigraph::Arc, Value> FilterMap;
+ typedef FilterArcs<StaticDigraph, FilterMap> ResDigraph;
+ typedef StaticVectorMap<StaticDigraph::Node, StaticDigraph::Arc> PredMap;
+ typedef typename BellmanFord<ResDigraph, CostArcMap>
+ ::template SetDistMap<CostNodeMap>
+ ::template SetPredMap<PredMap>::Create BF;
+
+ // Build the residual network
+ _arc_vec.clear();
+ _cost_vec.clear();
+ for (int j = 0; j != _res_arc_num; ++j) {
+ _arc_vec.push_back(IntPair(_source[j], _target[j]));
+ _cost_vec.push_back(_cost[j]);
+ }
+ _sgr.build(_res_node_num, _arc_vec.begin(), _arc_vec.end());
+
+ FilterMap filter_map(_res_cap);
+ ResDigraph rgr(_sgr, filter_map);
+ std::vector<int> cycle;
+ std::vector<StaticDigraph::Arc> pred(_res_arc_num);
+ PredMap pred_map(pred);
+ BF bf(rgr, _cost_map);
+ bf.distMap(_pi_map).predMap(pred_map);
+
+ int length_bound = BF_FIRST_LIMIT;
+ bool optimal = false;
+ while (!optimal) {
+ bf.init(0);
+ int iter_num = 0;
+ bool cycle_found = false;
+ while (!cycle_found) {
+ // Perform some iterations of the Bellman-Ford algorithm
+ int curr_iter_num = iter_num + length_bound <= _node_num ?
+ length_bound : _node_num - iter_num;
+ iter_num += curr_iter_num;
+ int real_iter_num = curr_iter_num;
+ for (int i = 0; i < curr_iter_num; ++i) {
+ if (bf.processNextWeakRound()) {
+ real_iter_num = i;
+ break;
+ }
+ }
+ if (real_iter_num < curr_iter_num) {
+ // Optimal flow is found
+ optimal = true;
+ break;
+ } else {
+ // Search for node disjoint negative cycles
+ std::vector<int> state(_res_node_num, 0);
+ int id = 0;
+ for (int u = 0; u != _res_node_num; ++u) {
+ if (state[u] != 0) continue;
+ ++id;
+ int v = u;
+ for (; v != -1 && state[v] == 0; v = pred[v] == INVALID ?
+ -1 : rgr.id(rgr.source(pred[v]))) {
+ state[v] = id;
+ }
+ if (v != -1 && state[v] == id) {
+ // A negative cycle is found
+ cycle_found = true;
+ cycle.clear();
+ StaticDigraph::Arc a = pred[v];
+ Value d, delta = _res_cap[rgr.id(a)];
+ cycle.push_back(rgr.id(a));
+ while (rgr.id(rgr.source(a)) != v) {
+ a = pred_map[rgr.source(a)];
+ d = _res_cap[rgr.id(a)];
+ if (d < delta) delta = d;
+ cycle.push_back(rgr.id(a));
+ }
+
+ // Augment along the cycle
+ for (int i = 0; i < int(cycle.size()); ++i) {
+ int j = cycle[i];
+ _res_cap[j] -= delta;
+ _res_cap[_reverse[j]] += delta;
+ }
+ }
+ }
+ }
+
+ // Increase iteration limit if no cycle is found
+ if (!cycle_found) {
+ length_bound = static_cast<int>(length_bound * BF_LIMIT_FACTOR);
+ }
+ }
+ }
+ }
+
+ // Execute the "Minimum Mean Cycle Canceling" method
+ void startMinMeanCycleCanceling() {
+ typedef Path<StaticDigraph> SPath;
+ typedef typename SPath::ArcIt SPathArcIt;
+ typedef typename HowardMmc<StaticDigraph, CostArcMap>
+ ::template SetPath<SPath>::Create HwMmc;
+ typedef typename HartmannOrlinMmc<StaticDigraph, CostArcMap>
+ ::template SetPath<SPath>::Create HoMmc;
+
+ const double HW_ITER_LIMIT_FACTOR = 1.0;
+ const int HW_ITER_LIMIT_MIN_VALUE = 5;
+
+ const int hw_iter_limit =
+ std::max(static_cast<int>(HW_ITER_LIMIT_FACTOR * _node_num),
+ HW_ITER_LIMIT_MIN_VALUE);
+
+ SPath cycle;
+ HwMmc hw_mmc(_sgr, _cost_map);
+ hw_mmc.cycle(cycle);
+ buildResidualNetwork();
+ while (true) {
+
+ typename HwMmc::TerminationCause hw_tc =
+ hw_mmc.findCycleMean(hw_iter_limit);
+ if (hw_tc == HwMmc::ITERATION_LIMIT) {
+ // Howard's algorithm reached the iteration limit, start a
+ // strongly polynomial algorithm instead
+ HoMmc ho_mmc(_sgr, _cost_map);
+ ho_mmc.cycle(cycle);
+ // Find a minimum mean cycle (Hartmann-Orlin algorithm)
+ if (!(ho_mmc.findCycleMean() && ho_mmc.cycleCost() < 0)) break;
+ ho_mmc.findCycle();
+ } else {
+ // Find a minimum mean cycle (Howard algorithm)
+ if (!(hw_tc == HwMmc::OPTIMAL && hw_mmc.cycleCost() < 0)) break;
+ hw_mmc.findCycle();
+ }
+
+ // Compute delta value
+ Value delta = INF;
+ for (SPathArcIt a(cycle); a != INVALID; ++a) {
+ Value d = _res_cap[_id_vec[_sgr.id(a)]];
+ if (d < delta) delta = d;
+ }
+
+ // Augment along the cycle
+ for (SPathArcIt a(cycle); a != INVALID; ++a) {
+ int j = _id_vec[_sgr.id(a)];
+ _res_cap[j] -= delta;
+ _res_cap[_reverse[j]] += delta;
+ }
+
+ // Rebuild the residual network
+ buildResidualNetwork();
+ }
+ }
+
+ // Execute the "Cancel-and-Tighten" method
+ void startCancelAndTighten() {
+ // Constants for the min mean cycle computations
+ const double LIMIT_FACTOR = 1.0;
+ const int MIN_LIMIT = 5;
+ const double HW_ITER_LIMIT_FACTOR = 1.0;
+ const int HW_ITER_LIMIT_MIN_VALUE = 5;
+
+ const int hw_iter_limit =
+ std::max(static_cast<int>(HW_ITER_LIMIT_FACTOR * _node_num),
+ HW_ITER_LIMIT_MIN_VALUE);
+
+ // Contruct auxiliary data vectors
+ DoubleVector pi(_res_node_num, 0.0);
+ IntVector level(_res_node_num);
+ BoolVector reached(_res_node_num);
+ BoolVector processed(_res_node_num);
+ IntVector pred_node(_res_node_num);
+ IntVector pred_arc(_res_node_num);
+ std::vector<int> stack(_res_node_num);
+ std::vector<int> proc_vector(_res_node_num);
+
+ // Initialize epsilon
+ double epsilon = 0;
+ for (int a = 0; a != _res_arc_num; ++a) {
+ if (_res_cap[a] > 0 && -_cost[a] > epsilon)
+ epsilon = -_cost[a];
+ }
+
+ // Start phases
+ Tolerance<double> tol;
+ tol.epsilon(1e-6);
+ int limit = int(LIMIT_FACTOR * std::sqrt(double(_res_node_num)));
+ if (limit < MIN_LIMIT) limit = MIN_LIMIT;
+ int iter = limit;
+ while (epsilon * _res_node_num >= 1) {
+ // Find and cancel cycles in the admissible network using DFS
+ for (int u = 0; u != _res_node_num; ++u) {
+ reached[u] = false;
+ processed[u] = false;
+ }
+ int stack_head = -1;
+ int proc_head = -1;
+ for (int start = 0; start != _res_node_num; ++start) {
+ if (reached[start]) continue;
+
+ // New start node
+ reached[start] = true;
+ pred_arc[start] = -1;
+ pred_node[start] = -1;
+
+ // Find the first admissible outgoing arc
+ double p = pi[start];
+ int a = _first_out[start];
+ int last_out = _first_out[start+1];
+ for (; a != last_out && (_res_cap[a] == 0 ||
+ !tol.negative(_cost[a] + p - pi[_target[a]])); ++a) ;
+ if (a == last_out) {
+ processed[start] = true;
+ proc_vector[++proc_head] = start;
+ continue;
+ }
+ stack[++stack_head] = a;
+
+ while (stack_head >= 0) {
+ int sa = stack[stack_head];
+ int u = _source[sa];
+ int v = _target[sa];
+
+ if (!reached[v]) {
+ // A new node is reached
+ reached[v] = true;
+ pred_node[v] = u;
+ pred_arc[v] = sa;
+ p = pi[v];
+ a = _first_out[v];
+ last_out = _first_out[v+1];
+ for (; a != last_out && (_res_cap[a] == 0 ||
+ !tol.negative(_cost[a] + p - pi[_target[a]])); ++a) ;
+ stack[++stack_head] = a == last_out ? -1 : a;
+ } else {
+ if (!processed[v]) {
+ // A cycle is found
+ int n, w = u;
+ Value d, delta = _res_cap[sa];
+ for (n = u; n != v; n = pred_node[n]) {
+ d = _res_cap[pred_arc[n]];
+ if (d <= delta) {
+ delta = d;
+ w = pred_node[n];
+ }
+ }
+
+ // Augment along the cycle
+ _res_cap[sa] -= delta;
+ _res_cap[_reverse[sa]] += delta;
+ for (n = u; n != v; n = pred_node[n]) {
+ int pa = pred_arc[n];
+ _res_cap[pa] -= delta;
+ _res_cap[_reverse[pa]] += delta;
+ }
+ for (n = u; stack_head > 0 && n != w; n = pred_node[n]) {
+ --stack_head;
+ reached[n] = false;
+ }
+ u = w;
+ }
+ v = u;
+
+ // Find the next admissible outgoing arc
+ p = pi[v];
+ a = stack[stack_head] + 1;
+ last_out = _first_out[v+1];
+ for (; a != last_out && (_res_cap[a] == 0 ||
+ !tol.negative(_cost[a] + p - pi[_target[a]])); ++a) ;
+ stack[stack_head] = a == last_out ? -1 : a;
+ }
+
+ while (stack_head >= 0 && stack[stack_head] == -1) {
+ processed[v] = true;
+ proc_vector[++proc_head] = v;
+ if (--stack_head >= 0) {
+ // Find the next admissible outgoing arc
+ v = _source[stack[stack_head]];
+ p = pi[v];
+ a = stack[stack_head] + 1;
+ last_out = _first_out[v+1];
+ for (; a != last_out && (_res_cap[a] == 0 ||
+ !tol.negative(_cost[a] + p - pi[_target[a]])); ++a) ;
+ stack[stack_head] = a == last_out ? -1 : a;
+ }
+ }
+ }
+ }
+
+ // Tighten potentials and epsilon
+ if (--iter > 0) {
+ for (int u = 0; u != _res_node_num; ++u) {
+ level[u] = 0;
+ }
+ for (int i = proc_head; i > 0; --i) {
+ int u = proc_vector[i];
+ double p = pi[u];
+ int l = level[u] + 1;
+ int last_out = _first_out[u+1];
+ for (int a = _first_out[u]; a != last_out; ++a) {
+ int v = _target[a];
+ if (_res_cap[a] > 0 && tol.negative(_cost[a] + p - pi[v]) &&
+ l > level[v]) level[v] = l;
+ }
+ }
+
+ // Modify potentials
+ double q = std::numeric_limits<double>::max();
+ for (int u = 0; u != _res_node_num; ++u) {
+ int lu = level[u];
+ double p, pu = pi[u];
+ int last_out = _first_out[u+1];
+ for (int a = _first_out[u]; a != last_out; ++a) {
+ if (_res_cap[a] == 0) continue;
+ int v = _target[a];
+ int ld = lu - level[v];
+ if (ld > 0) {
+ p = (_cost[a] + pu - pi[v] + epsilon) / (ld + 1);
+ if (p < q) q = p;
+ }
+ }
+ }
+ for (int u = 0; u != _res_node_num; ++u) {
+ pi[u] -= q * level[u];
+ }
+
+ // Modify epsilon
+ epsilon = 0;
+ for (int u = 0; u != _res_node_num; ++u) {
+ double curr, pu = pi[u];
+ int last_out = _first_out[u+1];
+ for (int a = _first_out[u]; a != last_out; ++a) {
+ if (_res_cap[a] == 0) continue;
+ curr = _cost[a] + pu - pi[_target[a]];
+ if (-curr > epsilon) epsilon = -curr;
+ }
+ }
+ } else {
+ typedef HowardMmc<StaticDigraph, CostArcMap> HwMmc;
+ typedef HartmannOrlinMmc<StaticDigraph, CostArcMap> HoMmc;
+ typedef typename BellmanFord<StaticDigraph, CostArcMap>
+ ::template SetDistMap<CostNodeMap>::Create BF;
+
+ // Set epsilon to the minimum cycle mean
+ Cost cycle_cost = 0;
+ int cycle_size = 1;
+ buildResidualNetwork();
+ HwMmc hw_mmc(_sgr, _cost_map);
+ if (hw_mmc.findCycleMean(hw_iter_limit) == HwMmc::ITERATION_LIMIT) {
+ // Howard's algorithm reached the iteration limit, start a
+ // strongly polynomial algorithm instead
+ HoMmc ho_mmc(_sgr, _cost_map);
+ ho_mmc.findCycleMean();
+ epsilon = -ho_mmc.cycleMean();
+ cycle_cost = ho_mmc.cycleCost();
+ cycle_size = ho_mmc.cycleSize();
+ } else {
+ // Set epsilon
+ epsilon = -hw_mmc.cycleMean();
+ cycle_cost = hw_mmc.cycleCost();
+ cycle_size = hw_mmc.cycleSize();
+ }
+
+ // Compute feasible potentials for the current epsilon
+ for (int i = 0; i != int(_cost_vec.size()); ++i) {
+ _cost_vec[i] = cycle_size * _cost_vec[i] - cycle_cost;
+ }
+ BF bf(_sgr, _cost_map);
+ bf.distMap(_pi_map);
+ bf.init(0);
+ bf.start();
+ for (int u = 0; u != _res_node_num; ++u) {
+ pi[u] = static_cast<double>(_pi[u]) / cycle_size;
+ }
+
+ iter = limit;
+ }
+ }
+ }
+
+ }; //class CycleCanceling
+
+ ///@}
+
+} //namespace lemon
+
+#endif //LEMON_CYCLE_CANCELING_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/dfs.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/dfs.h
new file mode 100644
index 00000000000..6e9e84a4892
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/dfs.h
@@ -0,0 +1,1637 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_DFS_H
+#define LEMON_DFS_H
+
+///\ingroup search
+///\file
+///\brief DFS algorithm.
+
+#include <lemon/list_graph.h>
+#include <lemon/bits/path_dump.h>
+#include <lemon/core.h>
+#include <lemon/error.h>
+#include <lemon/maps.h>
+#include <lemon/path.h>
+
+namespace lemon {
+
+ ///Default traits class of Dfs class.
+
+ ///Default traits class of Dfs class.
+ ///\tparam GR Digraph type.
+ template<class GR>
+ struct DfsDefaultTraits
+ {
+ ///The type of the digraph the algorithm runs on.
+ typedef GR Digraph;
+
+ ///\brief The type of the map that stores the predecessor
+ ///arcs of the %DFS paths.
+ ///
+ ///The type of the map that stores the predecessor
+ ///arcs of the %DFS paths.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ typedef typename Digraph::template NodeMap<typename Digraph::Arc> PredMap;
+ ///Instantiates a \c PredMap.
+
+ ///This function instantiates a \ref PredMap.
+ ///\param g is the digraph, to which we would like to define the
+ ///\ref PredMap.
+ static PredMap *createPredMap(const Digraph &g)
+ {
+ return new PredMap(g);
+ }
+
+ ///The type of the map that indicates which nodes are processed.
+
+ ///The type of the map that indicates which nodes are processed.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ ///By default, it is a NullMap.
+ typedef NullMap<typename Digraph::Node,bool> ProcessedMap;
+ ///Instantiates a \c ProcessedMap.
+
+ ///This function instantiates a \ref ProcessedMap.
+ ///\param g is the digraph, to which
+ ///we would like to define the \ref ProcessedMap.
+#ifdef DOXYGEN
+ static ProcessedMap *createProcessedMap(const Digraph &g)
+#else
+ static ProcessedMap *createProcessedMap(const Digraph &)
+#endif
+ {
+ return new ProcessedMap();
+ }
+
+ ///The type of the map that indicates which nodes are reached.
+
+ ///The type of the map that indicates which nodes are reached.
+ ///It must conform to
+ ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept.
+ typedef typename Digraph::template NodeMap<bool> ReachedMap;
+ ///Instantiates a \c ReachedMap.
+
+ ///This function instantiates a \ref ReachedMap.
+ ///\param g is the digraph, to which
+ ///we would like to define the \ref ReachedMap.
+ static ReachedMap *createReachedMap(const Digraph &g)
+ {
+ return new ReachedMap(g);
+ }
+
+ ///The type of the map that stores the distances of the nodes.
+
+ ///The type of the map that stores the distances of the nodes.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ typedef typename Digraph::template NodeMap<int> DistMap;
+ ///Instantiates a \c DistMap.
+
+ ///This function instantiates a \ref DistMap.
+ ///\param g is the digraph, to which we would like to define the
+ ///\ref DistMap.
+ static DistMap *createDistMap(const Digraph &g)
+ {
+ return new DistMap(g);
+ }
+ };
+
+ ///%DFS algorithm class.
+
+ ///\ingroup search
+ ///This class provides an efficient implementation of the %DFS algorithm.
+ ///
+ ///There is also a \ref dfs() "function-type interface" for the DFS
+ ///algorithm, which is convenient in the simplier cases and it can be
+ ///used easier.
+ ///
+ ///\tparam GR The type of the digraph the algorithm runs on.
+ ///The default type is \ref ListDigraph.
+ ///\tparam TR The traits class that defines various types used by the
+ ///algorithm. By default, it is \ref DfsDefaultTraits
+ ///"DfsDefaultTraits<GR>".
+ ///In most cases, this parameter should not be set directly,
+ ///consider to use the named template parameters instead.
+#ifdef DOXYGEN
+ template <typename GR,
+ typename TR>
+#else
+ template <typename GR=ListDigraph,
+ typename TR=DfsDefaultTraits<GR> >
+#endif
+ class Dfs {
+ public:
+
+ ///The type of the digraph the algorithm runs on.
+ typedef typename TR::Digraph Digraph;
+
+ ///\brief The type of the map that stores the predecessor arcs of the
+ ///DFS paths.
+ typedef typename TR::PredMap PredMap;
+ ///The type of the map that stores the distances of the nodes.
+ typedef typename TR::DistMap DistMap;
+ ///The type of the map that indicates which nodes are reached.
+ typedef typename TR::ReachedMap ReachedMap;
+ ///The type of the map that indicates which nodes are processed.
+ typedef typename TR::ProcessedMap ProcessedMap;
+ ///The type of the paths.
+ typedef PredMapPath<Digraph, PredMap> Path;
+
+ ///The \ref lemon::DfsDefaultTraits "traits class" of the algorithm.
+ typedef TR Traits;
+
+ private:
+
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::NodeIt NodeIt;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::OutArcIt OutArcIt;
+
+ //Pointer to the underlying digraph.
+ const Digraph *G;
+ //Pointer to the map of predecessor arcs.
+ PredMap *_pred;
+ //Indicates if _pred is locally allocated (true) or not.
+ bool local_pred;
+ //Pointer to the map of distances.
+ DistMap *_dist;
+ //Indicates if _dist is locally allocated (true) or not.
+ bool local_dist;
+ //Pointer to the map of reached status of the nodes.
+ ReachedMap *_reached;
+ //Indicates if _reached is locally allocated (true) or not.
+ bool local_reached;
+ //Pointer to the map of processed status of the nodes.
+ ProcessedMap *_processed;
+ //Indicates if _processed is locally allocated (true) or not.
+ bool local_processed;
+
+ std::vector<typename Digraph::OutArcIt> _stack;
+ int _stack_head;
+
+ //Creates the maps if necessary.
+ void create_maps()
+ {
+ if(!_pred) {
+ local_pred = true;
+ _pred = Traits::createPredMap(*G);
+ }
+ if(!_dist) {
+ local_dist = true;
+ _dist = Traits::createDistMap(*G);
+ }
+ if(!_reached) {
+ local_reached = true;
+ _reached = Traits::createReachedMap(*G);
+ }
+ if(!_processed) {
+ local_processed = true;
+ _processed = Traits::createProcessedMap(*G);
+ }
+ }
+
+ protected:
+
+ Dfs() {}
+
+ public:
+
+ typedef Dfs Create;
+
+ ///\name Named Template Parameters
+
+ ///@{
+
+ template <class T>
+ struct SetPredMapTraits : public Traits {
+ typedef T PredMap;
+ static PredMap *createPredMap(const Digraph &)
+ {
+ LEMON_ASSERT(false, "PredMap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///\c PredMap type.
+ ///
+ ///\ref named-templ-param "Named parameter" for setting
+ ///\c PredMap type.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ template <class T>
+ struct SetPredMap : public Dfs<Digraph, SetPredMapTraits<T> > {
+ typedef Dfs<Digraph, SetPredMapTraits<T> > Create;
+ };
+
+ template <class T>
+ struct SetDistMapTraits : public Traits {
+ typedef T DistMap;
+ static DistMap *createDistMap(const Digraph &)
+ {
+ LEMON_ASSERT(false, "DistMap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///\c DistMap type.
+ ///
+ ///\ref named-templ-param "Named parameter" for setting
+ ///\c DistMap type.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ template <class T>
+ struct SetDistMap : public Dfs< Digraph, SetDistMapTraits<T> > {
+ typedef Dfs<Digraph, SetDistMapTraits<T> > Create;
+ };
+
+ template <class T>
+ struct SetReachedMapTraits : public Traits {
+ typedef T ReachedMap;
+ static ReachedMap *createReachedMap(const Digraph &)
+ {
+ LEMON_ASSERT(false, "ReachedMap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///\c ReachedMap type.
+ ///
+ ///\ref named-templ-param "Named parameter" for setting
+ ///\c ReachedMap type.
+ ///It must conform to
+ ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept.
+ template <class T>
+ struct SetReachedMap : public Dfs< Digraph, SetReachedMapTraits<T> > {
+ typedef Dfs< Digraph, SetReachedMapTraits<T> > Create;
+ };
+
+ template <class T>
+ struct SetProcessedMapTraits : public Traits {
+ typedef T ProcessedMap;
+ static ProcessedMap *createProcessedMap(const Digraph &)
+ {
+ LEMON_ASSERT(false, "ProcessedMap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///\c ProcessedMap type.
+ ///
+ ///\ref named-templ-param "Named parameter" for setting
+ ///\c ProcessedMap type.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ template <class T>
+ struct SetProcessedMap : public Dfs< Digraph, SetProcessedMapTraits<T> > {
+ typedef Dfs< Digraph, SetProcessedMapTraits<T> > Create;
+ };
+
+ struct SetStandardProcessedMapTraits : public Traits {
+ typedef typename Digraph::template NodeMap<bool> ProcessedMap;
+ static ProcessedMap *createProcessedMap(const Digraph &g)
+ {
+ return new ProcessedMap(g);
+ }
+ };
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///\c ProcessedMap type to be <tt>Digraph::NodeMap<bool></tt>.
+ ///
+ ///\ref named-templ-param "Named parameter" for setting
+ ///\c ProcessedMap type to be <tt>Digraph::NodeMap<bool></tt>.
+ ///If you don't set it explicitly, it will be automatically allocated.
+ struct SetStandardProcessedMap :
+ public Dfs< Digraph, SetStandardProcessedMapTraits > {
+ typedef Dfs< Digraph, SetStandardProcessedMapTraits > Create;
+ };
+
+ ///@}
+
+ public:
+
+ ///Constructor.
+
+ ///Constructor.
+ ///\param g The digraph the algorithm runs on.
+ Dfs(const Digraph &g) :
+ G(&g),
+ _pred(NULL), local_pred(false),
+ _dist(NULL), local_dist(false),
+ _reached(NULL), local_reached(false),
+ _processed(NULL), local_processed(false)
+ { }
+
+ ///Destructor.
+ ~Dfs()
+ {
+ if(local_pred) delete _pred;
+ if(local_dist) delete _dist;
+ if(local_reached) delete _reached;
+ if(local_processed) delete _processed;
+ }
+
+ ///Sets the map that stores the predecessor arcs.
+
+ ///Sets the map that stores the predecessor arcs.
+ ///If you don't use this function before calling \ref run(Node) "run()"
+ ///or \ref init(), an instance will be allocated automatically.
+ ///The destructor deallocates this automatically allocated map,
+ ///of course.
+ ///\return <tt> (*this) </tt>
+ Dfs &predMap(PredMap &m)
+ {
+ if(local_pred) {
+ delete _pred;
+ local_pred=false;
+ }
+ _pred = &m;
+ return *this;
+ }
+
+ ///Sets the map that indicates which nodes are reached.
+
+ ///Sets the map that indicates which nodes are reached.
+ ///If you don't use this function before calling \ref run(Node) "run()"
+ ///or \ref init(), an instance will be allocated automatically.
+ ///The destructor deallocates this automatically allocated map,
+ ///of course.
+ ///\return <tt> (*this) </tt>
+ Dfs &reachedMap(ReachedMap &m)
+ {
+ if(local_reached) {
+ delete _reached;
+ local_reached=false;
+ }
+ _reached = &m;
+ return *this;
+ }
+
+ ///Sets the map that indicates which nodes are processed.
+
+ ///Sets the map that indicates which nodes are processed.
+ ///If you don't use this function before calling \ref run(Node) "run()"
+ ///or \ref init(), an instance will be allocated automatically.
+ ///The destructor deallocates this automatically allocated map,
+ ///of course.
+ ///\return <tt> (*this) </tt>
+ Dfs &processedMap(ProcessedMap &m)
+ {
+ if(local_processed) {
+ delete _processed;
+ local_processed=false;
+ }
+ _processed = &m;
+ return *this;
+ }
+
+ ///Sets the map that stores the distances of the nodes.
+
+ ///Sets the map that stores the distances of the nodes calculated by
+ ///the algorithm.
+ ///If you don't use this function before calling \ref run(Node) "run()"
+ ///or \ref init(), an instance will be allocated automatically.
+ ///The destructor deallocates this automatically allocated map,
+ ///of course.
+ ///\return <tt> (*this) </tt>
+ Dfs &distMap(DistMap &m)
+ {
+ if(local_dist) {
+ delete _dist;
+ local_dist=false;
+ }
+ _dist = &m;
+ return *this;
+ }
+
+ public:
+
+ ///\name Execution Control
+ ///The simplest way to execute the DFS algorithm is to use one of the
+ ///member functions called \ref run(Node) "run()".\n
+ ///If you need better control on the execution, you have to call
+ ///\ref init() first, then you can add a source node with \ref addSource()
+ ///and perform the actual computation with \ref start().
+ ///This procedure can be repeated if there are nodes that have not
+ ///been reached.
+
+ ///@{
+
+ ///\brief Initializes the internal data structures.
+ ///
+ ///Initializes the internal data structures.
+ void init()
+ {
+ create_maps();
+ _stack.resize(countNodes(*G));
+ _stack_head=-1;
+ for ( NodeIt u(*G) ; u!=INVALID ; ++u ) {
+ _pred->set(u,INVALID);
+ _reached->set(u,false);
+ _processed->set(u,false);
+ }
+ }
+
+ ///Adds a new source node.
+
+ ///Adds a new source node to the set of nodes to be processed.
+ ///
+ ///\pre The stack must be empty. Otherwise the algorithm gives
+ ///wrong results. (One of the outgoing arcs of all the source nodes
+ ///except for the last one will not be visited and distances will
+ ///also be wrong.)
+ void addSource(Node s)
+ {
+ LEMON_DEBUG(emptyQueue(), "The stack is not empty.");
+ if(!(*_reached)[s])
+ {
+ _reached->set(s,true);
+ _pred->set(s,INVALID);
+ OutArcIt e(*G,s);
+ if(e!=INVALID) {
+ _stack[++_stack_head]=e;
+ _dist->set(s,_stack_head);
+ }
+ else {
+ _processed->set(s,true);
+ _dist->set(s,0);
+ }
+ }
+ }
+
+ ///Processes the next arc.
+
+ ///Processes the next arc.
+ ///
+ ///\return The processed arc.
+ ///
+ ///\pre The stack must not be empty.
+ Arc processNextArc()
+ {
+ Node m;
+ Arc e=_stack[_stack_head];
+ if(!(*_reached)[m=G->target(e)]) {
+ _pred->set(m,e);
+ _reached->set(m,true);
+ ++_stack_head;
+ _stack[_stack_head] = OutArcIt(*G, m);
+ _dist->set(m,_stack_head);
+ }
+ else {
+ m=G->source(e);
+ ++_stack[_stack_head];
+ }
+ while(_stack_head>=0 && _stack[_stack_head]==INVALID) {
+ _processed->set(m,true);
+ --_stack_head;
+ if(_stack_head>=0) {
+ m=G->source(_stack[_stack_head]);
+ ++_stack[_stack_head];
+ }
+ }
+ return e;
+ }
+
+ ///Next arc to be processed.
+
+ ///Next arc to be processed.
+ ///
+ ///\return The next arc to be processed or \c INVALID if the stack
+ ///is empty.
+ OutArcIt nextArc() const
+ {
+ return _stack_head>=0?_stack[_stack_head]:INVALID;
+ }
+
+ ///Returns \c false if there are nodes to be processed.
+
+ ///Returns \c false if there are nodes to be processed
+ ///in the queue (stack).
+ bool emptyQueue() const { return _stack_head<0; }
+
+ ///Returns the number of the nodes to be processed.
+
+ ///Returns the number of the nodes to be processed
+ ///in the queue (stack).
+ int queueSize() const { return _stack_head+1; }
+
+ ///Executes the algorithm.
+
+ ///Executes the algorithm.
+ ///
+ ///This method runs the %DFS algorithm from the root node
+ ///in order to compute the DFS path to each node.
+ ///
+ /// The algorithm computes
+ ///- the %DFS tree,
+ ///- the distance of each node from the root in the %DFS tree.
+ ///
+ ///\pre init() must be called and a root node should be
+ ///added with addSource() before using this function.
+ ///
+ ///\note <tt>d.start()</tt> is just a shortcut of the following code.
+ ///\code
+ /// while ( !d.emptyQueue() ) {
+ /// d.processNextArc();
+ /// }
+ ///\endcode
+ void start()
+ {
+ while ( !emptyQueue() ) processNextArc();
+ }
+
+ ///Executes the algorithm until the given target node is reached.
+
+ ///Executes the algorithm until the given target node is reached.
+ ///
+ ///This method runs the %DFS algorithm from the root node
+ ///in order to compute the DFS path to \c t.
+ ///
+ ///The algorithm computes
+ ///- the %DFS path to \c t,
+ ///- the distance of \c t from the root in the %DFS tree.
+ ///
+ ///\pre init() must be called and a root node should be
+ ///added with addSource() before using this function.
+ void start(Node t)
+ {
+ while ( !emptyQueue() && !(*_reached)[t] )
+ processNextArc();
+ }
+
+ ///Executes the algorithm until a condition is met.
+
+ ///Executes the algorithm until a condition is met.
+ ///
+ ///This method runs the %DFS algorithm from the root node
+ ///until an arc \c a with <tt>am[a]</tt> true is found.
+ ///
+ ///\param am A \c bool (or convertible) arc map. The algorithm
+ ///will stop when it reaches an arc \c a with <tt>am[a]</tt> true.
+ ///
+ ///\return The reached arc \c a with <tt>am[a]</tt> true or
+ ///\c INVALID if no such arc was found.
+ ///
+ ///\pre init() must be called and a root node should be
+ ///added with addSource() before using this function.
+ ///
+ ///\warning Contrary to \ref Bfs and \ref Dijkstra, \c am is an arc map,
+ ///not a node map.
+ template<class ArcBoolMap>
+ Arc start(const ArcBoolMap &am)
+ {
+ while ( !emptyQueue() && !am[_stack[_stack_head]] )
+ processNextArc();
+ return emptyQueue() ? INVALID : _stack[_stack_head];
+ }
+
+ ///Runs the algorithm from the given source node.
+
+ ///This method runs the %DFS algorithm from node \c s
+ ///in order to compute the DFS path to each node.
+ ///
+ ///The algorithm computes
+ ///- the %DFS tree,
+ ///- the distance of each node from the root in the %DFS tree.
+ ///
+ ///\note <tt>d.run(s)</tt> is just a shortcut of the following code.
+ ///\code
+ /// d.init();
+ /// d.addSource(s);
+ /// d.start();
+ ///\endcode
+ void run(Node s) {
+ init();
+ addSource(s);
+ start();
+ }
+
+ ///Finds the %DFS path between \c s and \c t.
+
+ ///This method runs the %DFS algorithm from node \c s
+ ///in order to compute the DFS path to node \c t
+ ///(it stops searching when \c t is processed)
+ ///
+ ///\return \c true if \c t is reachable form \c s.
+ ///
+ ///\note Apart from the return value, <tt>d.run(s,t)</tt> is
+ ///just a shortcut of the following code.
+ ///\code
+ /// d.init();
+ /// d.addSource(s);
+ /// d.start(t);
+ ///\endcode
+ bool run(Node s,Node t) {
+ init();
+ addSource(s);
+ start(t);
+ return reached(t);
+ }
+
+ ///Runs the algorithm to visit all nodes in the digraph.
+
+ ///This method runs the %DFS algorithm in order to visit all nodes
+ ///in the digraph.
+ ///
+ ///\note <tt>d.run()</tt> is just a shortcut of the following code.
+ ///\code
+ /// d.init();
+ /// for (NodeIt n(digraph); n != INVALID; ++n) {
+ /// if (!d.reached(n)) {
+ /// d.addSource(n);
+ /// d.start();
+ /// }
+ /// }
+ ///\endcode
+ void run() {
+ init();
+ for (NodeIt it(*G); it != INVALID; ++it) {
+ if (!reached(it)) {
+ addSource(it);
+ start();
+ }
+ }
+ }
+
+ ///@}
+
+ ///\name Query Functions
+ ///The results of the DFS algorithm can be obtained using these
+ ///functions.\n
+ ///Either \ref run(Node) "run()" or \ref start() should be called
+ ///before using them.
+
+ ///@{
+
+ ///The DFS path to the given node.
+
+ ///Returns the DFS path to the given node from the root(s).
+ ///
+ ///\warning \c t should be reached from the root(s).
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ Path path(Node t) const { return Path(*G, *_pred, t); }
+
+ ///The distance of the given node from the root(s).
+
+ ///Returns the distance of the given node from the root(s).
+ ///
+ ///\warning If node \c v is not reached from the root(s), then
+ ///the return value of this function is undefined.
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ int dist(Node v) const { return (*_dist)[v]; }
+
+ ///Returns the 'previous arc' of the %DFS tree for the given node.
+
+ ///This function returns the 'previous arc' of the %DFS tree for the
+ ///node \c v, i.e. it returns the last arc of a %DFS path from a
+ ///root to \c v. It is \c INVALID if \c v is not reached from the
+ ///root(s) or if \c v is a root.
+ ///
+ ///The %DFS tree used here is equal to the %DFS tree used in
+ ///\ref predNode() and \ref predMap().
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ Arc predArc(Node v) const { return (*_pred)[v];}
+
+ ///Returns the 'previous node' of the %DFS tree for the given node.
+
+ ///This function returns the 'previous node' of the %DFS
+ ///tree for the node \c v, i.e. it returns the last but one node
+ ///of a %DFS path from a root to \c v. It is \c INVALID
+ ///if \c v is not reached from the root(s) or if \c v is a root.
+ ///
+ ///The %DFS tree used here is equal to the %DFS tree used in
+ ///\ref predArc() and \ref predMap().
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ Node predNode(Node v) const { return (*_pred)[v]==INVALID ? INVALID:
+ G->source((*_pred)[v]); }
+
+ ///\brief Returns a const reference to the node map that stores the
+ ///distances of the nodes.
+ ///
+ ///Returns a const reference to the node map that stores the
+ ///distances of the nodes calculated by the algorithm.
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ const DistMap &distMap() const { return *_dist;}
+
+ ///\brief Returns a const reference to the node map that stores the
+ ///predecessor arcs.
+ ///
+ ///Returns a const reference to the node map that stores the predecessor
+ ///arcs, which form the DFS tree (forest).
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ const PredMap &predMap() const { return *_pred;}
+
+ ///Checks if the given node. node is reached from the root(s).
+
+ ///Returns \c true if \c v is reached from the root(s).
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ bool reached(Node v) const { return (*_reached)[v]; }
+
+ ///@}
+ };
+
+ ///Default traits class of dfs() function.
+
+ ///Default traits class of dfs() function.
+ ///\tparam GR Digraph type.
+ template<class GR>
+ struct DfsWizardDefaultTraits
+ {
+ ///The type of the digraph the algorithm runs on.
+ typedef GR Digraph;
+
+ ///\brief The type of the map that stores the predecessor
+ ///arcs of the %DFS paths.
+ ///
+ ///The type of the map that stores the predecessor
+ ///arcs of the %DFS paths.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ typedef typename Digraph::template NodeMap<typename Digraph::Arc> PredMap;
+ ///Instantiates a PredMap.
+
+ ///This function instantiates a PredMap.
+ ///\param g is the digraph, to which we would like to define the
+ ///PredMap.
+ static PredMap *createPredMap(const Digraph &g)
+ {
+ return new PredMap(g);
+ }
+
+ ///The type of the map that indicates which nodes are processed.
+
+ ///The type of the map that indicates which nodes are processed.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ ///By default, it is a NullMap.
+ typedef NullMap<typename Digraph::Node,bool> ProcessedMap;
+ ///Instantiates a ProcessedMap.
+
+ ///This function instantiates a ProcessedMap.
+ ///\param g is the digraph, to which
+ ///we would like to define the ProcessedMap.
+#ifdef DOXYGEN
+ static ProcessedMap *createProcessedMap(const Digraph &g)
+#else
+ static ProcessedMap *createProcessedMap(const Digraph &)
+#endif
+ {
+ return new ProcessedMap();
+ }
+
+ ///The type of the map that indicates which nodes are reached.
+
+ ///The type of the map that indicates which nodes are reached.
+ ///It must conform to
+ ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept.
+ typedef typename Digraph::template NodeMap<bool> ReachedMap;
+ ///Instantiates a ReachedMap.
+
+ ///This function instantiates a ReachedMap.
+ ///\param g is the digraph, to which
+ ///we would like to define the ReachedMap.
+ static ReachedMap *createReachedMap(const Digraph &g)
+ {
+ return new ReachedMap(g);
+ }
+
+ ///The type of the map that stores the distances of the nodes.
+
+ ///The type of the map that stores the distances of the nodes.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ typedef typename Digraph::template NodeMap<int> DistMap;
+ ///Instantiates a DistMap.
+
+ ///This function instantiates a DistMap.
+ ///\param g is the digraph, to which we would like to define
+ ///the DistMap
+ static DistMap *createDistMap(const Digraph &g)
+ {
+ return new DistMap(g);
+ }
+
+ ///The type of the DFS paths.
+
+ ///The type of the DFS paths.
+ ///It must conform to the \ref concepts::Path "Path" concept.
+ typedef lemon::Path<Digraph> Path;
+ };
+
+ /// Default traits class used by DfsWizard
+
+ /// Default traits class used by DfsWizard.
+ /// \tparam GR The type of the digraph.
+ template<class GR>
+ class DfsWizardBase : public DfsWizardDefaultTraits<GR>
+ {
+
+ typedef DfsWizardDefaultTraits<GR> Base;
+ protected:
+ //The type of the nodes in the digraph.
+ typedef typename Base::Digraph::Node Node;
+
+ //Pointer to the digraph the algorithm runs on.
+ void *_g;
+ //Pointer to the map of reached nodes.
+ void *_reached;
+ //Pointer to the map of processed nodes.
+ void *_processed;
+ //Pointer to the map of predecessors arcs.
+ void *_pred;
+ //Pointer to the map of distances.
+ void *_dist;
+ //Pointer to the DFS path to the target node.
+ void *_path;
+ //Pointer to the distance of the target node.
+ int *_di;
+
+ public:
+ /// Constructor.
+
+ /// This constructor does not require parameters, it initiates
+ /// all of the attributes to \c 0.
+ DfsWizardBase() : _g(0), _reached(0), _processed(0), _pred(0),
+ _dist(0), _path(0), _di(0) {}
+
+ /// Constructor.
+
+ /// This constructor requires one parameter,
+ /// others are initiated to \c 0.
+ /// \param g The digraph the algorithm runs on.
+ DfsWizardBase(const GR &g) :
+ _g(reinterpret_cast<void*>(const_cast<GR*>(&g))),
+ _reached(0), _processed(0), _pred(0), _dist(0), _path(0), _di(0) {}
+
+ };
+
+ /// Auxiliary class for the function-type interface of DFS algorithm.
+
+ /// This auxiliary class is created to implement the
+ /// \ref dfs() "function-type interface" of \ref Dfs algorithm.
+ /// It does not have own \ref run(Node) "run()" method, it uses the
+ /// functions and features of the plain \ref Dfs.
+ ///
+ /// This class should only be used through the \ref dfs() function,
+ /// which makes it easier to use the algorithm.
+ ///
+ /// \tparam TR The traits class that defines various types used by the
+ /// algorithm.
+ template<class TR>
+ class DfsWizard : public TR
+ {
+ typedef TR Base;
+
+ typedef typename TR::Digraph Digraph;
+
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::NodeIt NodeIt;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::OutArcIt OutArcIt;
+
+ typedef typename TR::PredMap PredMap;
+ typedef typename TR::DistMap DistMap;
+ typedef typename TR::ReachedMap ReachedMap;
+ typedef typename TR::ProcessedMap ProcessedMap;
+ typedef typename TR::Path Path;
+
+ public:
+
+ /// Constructor.
+ DfsWizard() : TR() {}
+
+ /// Constructor that requires parameters.
+
+ /// Constructor that requires parameters.
+ /// These parameters will be the default values for the traits class.
+ /// \param g The digraph the algorithm runs on.
+ DfsWizard(const Digraph &g) :
+ TR(g) {}
+
+ ///Copy constructor
+ DfsWizard(const TR &b) : TR(b) {}
+
+ ~DfsWizard() {}
+
+ ///Runs DFS algorithm from the given source node.
+
+ ///This method runs DFS algorithm from node \c s
+ ///in order to compute the DFS path to each node.
+ void run(Node s)
+ {
+ Dfs<Digraph,TR> alg(*reinterpret_cast<const Digraph*>(Base::_g));
+ if (Base::_pred)
+ alg.predMap(*reinterpret_cast<PredMap*>(Base::_pred));
+ if (Base::_dist)
+ alg.distMap(*reinterpret_cast<DistMap*>(Base::_dist));
+ if (Base::_reached)
+ alg.reachedMap(*reinterpret_cast<ReachedMap*>(Base::_reached));
+ if (Base::_processed)
+ alg.processedMap(*reinterpret_cast<ProcessedMap*>(Base::_processed));
+ if (s!=INVALID)
+ alg.run(s);
+ else
+ alg.run();
+ }
+
+ ///Finds the DFS path between \c s and \c t.
+
+ ///This method runs DFS algorithm from node \c s
+ ///in order to compute the DFS path to node \c t
+ ///(it stops searching when \c t is processed).
+ ///
+ ///\return \c true if \c t is reachable form \c s.
+ bool run(Node s, Node t)
+ {
+ Dfs<Digraph,TR> alg(*reinterpret_cast<const Digraph*>(Base::_g));
+ if (Base::_pred)
+ alg.predMap(*reinterpret_cast<PredMap*>(Base::_pred));
+ if (Base::_dist)
+ alg.distMap(*reinterpret_cast<DistMap*>(Base::_dist));
+ if (Base::_reached)
+ alg.reachedMap(*reinterpret_cast<ReachedMap*>(Base::_reached));
+ if (Base::_processed)
+ alg.processedMap(*reinterpret_cast<ProcessedMap*>(Base::_processed));
+ alg.run(s,t);
+ if (Base::_path)
+ *reinterpret_cast<Path*>(Base::_path) = alg.path(t);
+ if (Base::_di)
+ *Base::_di = alg.dist(t);
+ return alg.reached(t);
+ }
+
+ ///Runs DFS algorithm to visit all nodes in the digraph.
+
+ ///This method runs DFS algorithm in order to visit all nodes
+ ///in the digraph.
+ void run()
+ {
+ run(INVALID);
+ }
+
+ template<class T>
+ struct SetPredMapBase : public Base {
+ typedef T PredMap;
+ static PredMap *createPredMap(const Digraph &) { return 0; };
+ SetPredMapBase(const TR &b) : TR(b) {}
+ };
+
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///the predecessor map.
+ ///
+ ///\ref named-templ-param "Named parameter" function for setting
+ ///the map that stores the predecessor arcs of the nodes.
+ template<class T>
+ DfsWizard<SetPredMapBase<T> > predMap(const T &t)
+ {
+ Base::_pred=reinterpret_cast<void*>(const_cast<T*>(&t));
+ return DfsWizard<SetPredMapBase<T> >(*this);
+ }
+
+ template<class T>
+ struct SetReachedMapBase : public Base {
+ typedef T ReachedMap;
+ static ReachedMap *createReachedMap(const Digraph &) { return 0; };
+ SetReachedMapBase(const TR &b) : TR(b) {}
+ };
+
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///the reached map.
+ ///
+ ///\ref named-templ-param "Named parameter" function for setting
+ ///the map that indicates which nodes are reached.
+ template<class T>
+ DfsWizard<SetReachedMapBase<T> > reachedMap(const T &t)
+ {
+ Base::_reached=reinterpret_cast<void*>(const_cast<T*>(&t));
+ return DfsWizard<SetReachedMapBase<T> >(*this);
+ }
+
+ template<class T>
+ struct SetDistMapBase : public Base {
+ typedef T DistMap;
+ static DistMap *createDistMap(const Digraph &) { return 0; };
+ SetDistMapBase(const TR &b) : TR(b) {}
+ };
+
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///the distance map.
+ ///
+ ///\ref named-templ-param "Named parameter" function for setting
+ ///the map that stores the distances of the nodes calculated
+ ///by the algorithm.
+ template<class T>
+ DfsWizard<SetDistMapBase<T> > distMap(const T &t)
+ {
+ Base::_dist=reinterpret_cast<void*>(const_cast<T*>(&t));
+ return DfsWizard<SetDistMapBase<T> >(*this);
+ }
+
+ template<class T>
+ struct SetProcessedMapBase : public Base {
+ typedef T ProcessedMap;
+ static ProcessedMap *createProcessedMap(const Digraph &) { return 0; };
+ SetProcessedMapBase(const TR &b) : TR(b) {}
+ };
+
+ ///\brief \ref named-func-param "Named parameter" for setting
+ ///the processed map.
+ ///
+ ///\ref named-templ-param "Named parameter" function for setting
+ ///the map that indicates which nodes are processed.
+ template<class T>
+ DfsWizard<SetProcessedMapBase<T> > processedMap(const T &t)
+ {
+ Base::_processed=reinterpret_cast<void*>(const_cast<T*>(&t));
+ return DfsWizard<SetProcessedMapBase<T> >(*this);
+ }
+
+ template<class T>
+ struct SetPathBase : public Base {
+ typedef T Path;
+ SetPathBase(const TR &b) : TR(b) {}
+ };
+ ///\brief \ref named-func-param "Named parameter"
+ ///for getting the DFS path to the target node.
+ ///
+ ///\ref named-func-param "Named parameter"
+ ///for getting the DFS path to the target node.
+ template<class T>
+ DfsWizard<SetPathBase<T> > path(const T &t)
+ {
+ Base::_path=reinterpret_cast<void*>(const_cast<T*>(&t));
+ return DfsWizard<SetPathBase<T> >(*this);
+ }
+
+ ///\brief \ref named-func-param "Named parameter"
+ ///for getting the distance of the target node.
+ ///
+ ///\ref named-func-param "Named parameter"
+ ///for getting the distance of the target node.
+ DfsWizard dist(const int &d)
+ {
+ Base::_di=const_cast<int*>(&d);
+ return *this;
+ }
+
+ };
+
+ ///Function-type interface for DFS algorithm.
+
+ ///\ingroup search
+ ///Function-type interface for DFS algorithm.
+ ///
+ ///This function also has several \ref named-func-param "named parameters",
+ ///they are declared as the members of class \ref DfsWizard.
+ ///The following examples show how to use these parameters.
+ ///\code
+ /// // Compute the DFS tree
+ /// dfs(g).predMap(preds).distMap(dists).run(s);
+ ///
+ /// // Compute the DFS path from s to t
+ /// bool reached = dfs(g).path(p).dist(d).run(s,t);
+ ///\endcode
+ ///\warning Don't forget to put the \ref DfsWizard::run(Node) "run()"
+ ///to the end of the parameter list.
+ ///\sa DfsWizard
+ ///\sa Dfs
+ template<class GR>
+ DfsWizard<DfsWizardBase<GR> >
+ dfs(const GR &digraph)
+ {
+ return DfsWizard<DfsWizardBase<GR> >(digraph);
+ }
+
+#ifdef DOXYGEN
+ /// \brief Visitor class for DFS.
+ ///
+ /// This class defines the interface of the DfsVisit events, and
+ /// it could be the base of a real visitor class.
+ template <typename GR>
+ struct DfsVisitor {
+ typedef GR Digraph;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::Node Node;
+ /// \brief Called for the source node of the DFS.
+ ///
+ /// This function is called for the source node of the DFS.
+ void start(const Node& node) {}
+ /// \brief Called when the source node is leaved.
+ ///
+ /// This function is called when the source node is leaved.
+ void stop(const Node& node) {}
+ /// \brief Called when a node is reached first time.
+ ///
+ /// This function is called when a node is reached first time.
+ void reach(const Node& node) {}
+ /// \brief Called when an arc reaches a new node.
+ ///
+ /// This function is called when the DFS finds an arc whose target node
+ /// is not reached yet.
+ void discover(const Arc& arc) {}
+ /// \brief Called when an arc is examined but its target node is
+ /// already discovered.
+ ///
+ /// This function is called when an arc is examined but its target node is
+ /// already discovered.
+ void examine(const Arc& arc) {}
+ /// \brief Called when the DFS steps back from a node.
+ ///
+ /// This function is called when the DFS steps back from a node.
+ void leave(const Node& node) {}
+ /// \brief Called when the DFS steps back on an arc.
+ ///
+ /// This function is called when the DFS steps back on an arc.
+ void backtrack(const Arc& arc) {}
+ };
+#else
+ template <typename GR>
+ struct DfsVisitor {
+ typedef GR Digraph;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::Node Node;
+ void start(const Node&) {}
+ void stop(const Node&) {}
+ void reach(const Node&) {}
+ void discover(const Arc&) {}
+ void examine(const Arc&) {}
+ void leave(const Node&) {}
+ void backtrack(const Arc&) {}
+
+ template <typename _Visitor>
+ struct Constraints {
+ void constraints() {
+ Arc arc;
+ Node node;
+ visitor.start(node);
+ visitor.stop(arc);
+ visitor.reach(node);
+ visitor.discover(arc);
+ visitor.examine(arc);
+ visitor.leave(node);
+ visitor.backtrack(arc);
+ }
+ _Visitor& visitor;
+ Constraints() {}
+ };
+ };
+#endif
+
+ /// \brief Default traits class of DfsVisit class.
+ ///
+ /// Default traits class of DfsVisit class.
+ /// \tparam _Digraph The type of the digraph the algorithm runs on.
+ template<class GR>
+ struct DfsVisitDefaultTraits {
+
+ /// \brief The type of the digraph the algorithm runs on.
+ typedef GR Digraph;
+
+ /// \brief The type of the map that indicates which nodes are reached.
+ ///
+ /// The type of the map that indicates which nodes are reached.
+ /// It must conform to the
+ /// \ref concepts::ReadWriteMap "ReadWriteMap" concept.
+ typedef typename Digraph::template NodeMap<bool> ReachedMap;
+
+ /// \brief Instantiates a ReachedMap.
+ ///
+ /// This function instantiates a ReachedMap.
+ /// \param digraph is the digraph, to which
+ /// we would like to define the ReachedMap.
+ static ReachedMap *createReachedMap(const Digraph &digraph) {
+ return new ReachedMap(digraph);
+ }
+
+ };
+
+ /// \ingroup search
+ ///
+ /// \brief DFS algorithm class with visitor interface.
+ ///
+ /// This class provides an efficient implementation of the DFS algorithm
+ /// with visitor interface.
+ ///
+ /// The DfsVisit class provides an alternative interface to the Dfs
+ /// class. It works with callback mechanism, the DfsVisit object calls
+ /// the member functions of the \c Visitor class on every DFS event.
+ ///
+ /// This interface of the DFS algorithm should be used in special cases
+ /// when extra actions have to be performed in connection with certain
+ /// events of the DFS algorithm. Otherwise consider to use Dfs or dfs()
+ /// instead.
+ ///
+ /// \tparam GR The type of the digraph the algorithm runs on.
+ /// The default type is \ref ListDigraph.
+ /// The value of GR is not used directly by \ref DfsVisit,
+ /// it is only passed to \ref DfsVisitDefaultTraits.
+ /// \tparam VS The Visitor type that is used by the algorithm.
+ /// \ref DfsVisitor "DfsVisitor<GR>" is an empty visitor, which
+ /// does not observe the DFS events. If you want to observe the DFS
+ /// events, you should implement your own visitor class.
+ /// \tparam TR The traits class that defines various types used by the
+ /// algorithm. By default, it is \ref DfsVisitDefaultTraits
+ /// "DfsVisitDefaultTraits<GR>".
+ /// In most cases, this parameter should not be set directly,
+ /// consider to use the named template parameters instead.
+#ifdef DOXYGEN
+ template <typename GR, typename VS, typename TR>
+#else
+ template <typename GR = ListDigraph,
+ typename VS = DfsVisitor<GR>,
+ typename TR = DfsVisitDefaultTraits<GR> >
+#endif
+ class DfsVisit {
+ public:
+
+ ///The traits class.
+ typedef TR Traits;
+
+ ///The type of the digraph the algorithm runs on.
+ typedef typename Traits::Digraph Digraph;
+
+ ///The visitor type used by the algorithm.
+ typedef VS Visitor;
+
+ ///The type of the map that indicates which nodes are reached.
+ typedef typename Traits::ReachedMap ReachedMap;
+
+ private:
+
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::NodeIt NodeIt;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::OutArcIt OutArcIt;
+
+ //Pointer to the underlying digraph.
+ const Digraph *_digraph;
+ //Pointer to the visitor object.
+ Visitor *_visitor;
+ //Pointer to the map of reached status of the nodes.
+ ReachedMap *_reached;
+ //Indicates if _reached is locally allocated (true) or not.
+ bool local_reached;
+
+ std::vector<typename Digraph::Arc> _stack;
+ int _stack_head;
+
+ //Creates the maps if necessary.
+ void create_maps() {
+ if(!_reached) {
+ local_reached = true;
+ _reached = Traits::createReachedMap(*_digraph);
+ }
+ }
+
+ protected:
+
+ DfsVisit() {}
+
+ public:
+
+ typedef DfsVisit Create;
+
+ /// \name Named Template Parameters
+
+ ///@{
+ template <class T>
+ struct SetReachedMapTraits : public Traits {
+ typedef T ReachedMap;
+ static ReachedMap *createReachedMap(const Digraph &digraph) {
+ LEMON_ASSERT(false, "ReachedMap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// ReachedMap type.
+ ///
+ /// \ref named-templ-param "Named parameter" for setting ReachedMap type.
+ template <class T>
+ struct SetReachedMap : public DfsVisit< Digraph, Visitor,
+ SetReachedMapTraits<T> > {
+ typedef DfsVisit< Digraph, Visitor, SetReachedMapTraits<T> > Create;
+ };
+ ///@}
+
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ ///
+ /// \param digraph The digraph the algorithm runs on.
+ /// \param visitor The visitor object of the algorithm.
+ DfsVisit(const Digraph& digraph, Visitor& visitor)
+ : _digraph(&digraph), _visitor(&visitor),
+ _reached(0), local_reached(false) {}
+
+ /// \brief Destructor.
+ ~DfsVisit() {
+ if(local_reached) delete _reached;
+ }
+
+ /// \brief Sets the map that indicates which nodes are reached.
+ ///
+ /// Sets the map that indicates which nodes are reached.
+ /// If you don't use this function before calling \ref run(Node) "run()"
+ /// or \ref init(), an instance will be allocated automatically.
+ /// The destructor deallocates this automatically allocated map,
+ /// of course.
+ /// \return <tt> (*this) </tt>
+ DfsVisit &reachedMap(ReachedMap &m) {
+ if(local_reached) {
+ delete _reached;
+ local_reached=false;
+ }
+ _reached = &m;
+ return *this;
+ }
+
+ public:
+
+ /// \name Execution Control
+ /// The simplest way to execute the DFS algorithm is to use one of the
+ /// member functions called \ref run(Node) "run()".\n
+ /// If you need better control on the execution, you have to call
+ /// \ref init() first, then you can add a source node with \ref addSource()
+ /// and perform the actual computation with \ref start().
+ /// This procedure can be repeated if there are nodes that have not
+ /// been reached.
+
+ /// @{
+
+ /// \brief Initializes the internal data structures.
+ ///
+ /// Initializes the internal data structures.
+ void init() {
+ create_maps();
+ _stack.resize(countNodes(*_digraph));
+ _stack_head = -1;
+ for (NodeIt u(*_digraph) ; u != INVALID ; ++u) {
+ _reached->set(u, false);
+ }
+ }
+
+ /// \brief Adds a new source node.
+ ///
+ /// Adds a new source node to the set of nodes to be processed.
+ ///
+ /// \pre The stack must be empty. Otherwise the algorithm gives
+ /// wrong results. (One of the outgoing arcs of all the source nodes
+ /// except for the last one will not be visited and distances will
+ /// also be wrong.)
+ void addSource(Node s)
+ {
+ LEMON_DEBUG(emptyQueue(), "The stack is not empty.");
+ if(!(*_reached)[s]) {
+ _reached->set(s,true);
+ _visitor->start(s);
+ _visitor->reach(s);
+ Arc e;
+ _digraph->firstOut(e, s);
+ if (e != INVALID) {
+ _stack[++_stack_head] = e;
+ } else {
+ _visitor->leave(s);
+ _visitor->stop(s);
+ }
+ }
+ }
+
+ /// \brief Processes the next arc.
+ ///
+ /// Processes the next arc.
+ ///
+ /// \return The processed arc.
+ ///
+ /// \pre The stack must not be empty.
+ Arc processNextArc() {
+ Arc e = _stack[_stack_head];
+ Node m = _digraph->target(e);
+ if(!(*_reached)[m]) {
+ _visitor->discover(e);
+ _visitor->reach(m);
+ _reached->set(m, true);
+ _digraph->firstOut(_stack[++_stack_head], m);
+ } else {
+ _visitor->examine(e);
+ m = _digraph->source(e);
+ _digraph->nextOut(_stack[_stack_head]);
+ }
+ while (_stack_head>=0 && _stack[_stack_head] == INVALID) {
+ _visitor->leave(m);
+ --_stack_head;
+ if (_stack_head >= 0) {
+ _visitor->backtrack(_stack[_stack_head]);
+ m = _digraph->source(_stack[_stack_head]);
+ _digraph->nextOut(_stack[_stack_head]);
+ } else {
+ _visitor->stop(m);
+ }
+ }
+ return e;
+ }
+
+ /// \brief Next arc to be processed.
+ ///
+ /// Next arc to be processed.
+ ///
+ /// \return The next arc to be processed or INVALID if the stack is
+ /// empty.
+ Arc nextArc() const {
+ return _stack_head >= 0 ? _stack[_stack_head] : INVALID;
+ }
+
+ /// \brief Returns \c false if there are nodes
+ /// to be processed.
+ ///
+ /// Returns \c false if there are nodes
+ /// to be processed in the queue (stack).
+ bool emptyQueue() const { return _stack_head < 0; }
+
+ /// \brief Returns the number of the nodes to be processed.
+ ///
+ /// Returns the number of the nodes to be processed in the queue (stack).
+ int queueSize() const { return _stack_head + 1; }
+
+ /// \brief Executes the algorithm.
+ ///
+ /// Executes the algorithm.
+ ///
+ /// This method runs the %DFS algorithm from the root node
+ /// in order to compute the %DFS path to each node.
+ ///
+ /// The algorithm computes
+ /// - the %DFS tree,
+ /// - the distance of each node from the root in the %DFS tree.
+ ///
+ /// \pre init() must be called and a root node should be
+ /// added with addSource() before using this function.
+ ///
+ /// \note <tt>d.start()</tt> is just a shortcut of the following code.
+ /// \code
+ /// while ( !d.emptyQueue() ) {
+ /// d.processNextArc();
+ /// }
+ /// \endcode
+ void start() {
+ while ( !emptyQueue() ) processNextArc();
+ }
+
+ /// \brief Executes the algorithm until the given target node is reached.
+ ///
+ /// Executes the algorithm until the given target node is reached.
+ ///
+ /// This method runs the %DFS algorithm from the root node
+ /// in order to compute the DFS path to \c t.
+ ///
+ /// The algorithm computes
+ /// - the %DFS path to \c t,
+ /// - the distance of \c t from the root in the %DFS tree.
+ ///
+ /// \pre init() must be called and a root node should be added
+ /// with addSource() before using this function.
+ void start(Node t) {
+ while ( !emptyQueue() && !(*_reached)[t] )
+ processNextArc();
+ }
+
+ /// \brief Executes the algorithm until a condition is met.
+ ///
+ /// Executes the algorithm until a condition is met.
+ ///
+ /// This method runs the %DFS algorithm from the root node
+ /// until an arc \c a with <tt>am[a]</tt> true is found.
+ ///
+ /// \param am A \c bool (or convertible) arc map. The algorithm
+ /// will stop when it reaches an arc \c a with <tt>am[a]</tt> true.
+ ///
+ /// \return The reached arc \c a with <tt>am[a]</tt> true or
+ /// \c INVALID if no such arc was found.
+ ///
+ /// \pre init() must be called and a root node should be added
+ /// with addSource() before using this function.
+ ///
+ /// \warning Contrary to \ref Bfs and \ref Dijkstra, \c am is an arc map,
+ /// not a node map.
+ template <typename AM>
+ Arc start(const AM &am) {
+ while ( !emptyQueue() && !am[_stack[_stack_head]] )
+ processNextArc();
+ return emptyQueue() ? INVALID : _stack[_stack_head];
+ }
+
+ /// \brief Runs the algorithm from the given source node.
+ ///
+ /// This method runs the %DFS algorithm from node \c s.
+ /// in order to compute the DFS path to each node.
+ ///
+ /// The algorithm computes
+ /// - the %DFS tree,
+ /// - the distance of each node from the root in the %DFS tree.
+ ///
+ /// \note <tt>d.run(s)</tt> is just a shortcut of the following code.
+ ///\code
+ /// d.init();
+ /// d.addSource(s);
+ /// d.start();
+ ///\endcode
+ void run(Node s) {
+ init();
+ addSource(s);
+ start();
+ }
+
+ /// \brief Finds the %DFS path between \c s and \c t.
+
+ /// This method runs the %DFS algorithm from node \c s
+ /// in order to compute the DFS path to node \c t
+ /// (it stops searching when \c t is processed).
+ ///
+ /// \return \c true if \c t is reachable form \c s.
+ ///
+ /// \note Apart from the return value, <tt>d.run(s,t)</tt> is
+ /// just a shortcut of the following code.
+ ///\code
+ /// d.init();
+ /// d.addSource(s);
+ /// d.start(t);
+ ///\endcode
+ bool run(Node s,Node t) {
+ init();
+ addSource(s);
+ start(t);
+ return reached(t);
+ }
+
+ /// \brief Runs the algorithm to visit all nodes in the digraph.
+
+ /// This method runs the %DFS algorithm in order to visit all nodes
+ /// in the digraph.
+ ///
+ /// \note <tt>d.run()</tt> is just a shortcut of the following code.
+ ///\code
+ /// d.init();
+ /// for (NodeIt n(digraph); n != INVALID; ++n) {
+ /// if (!d.reached(n)) {
+ /// d.addSource(n);
+ /// d.start();
+ /// }
+ /// }
+ ///\endcode
+ void run() {
+ init();
+ for (NodeIt it(*_digraph); it != INVALID; ++it) {
+ if (!reached(it)) {
+ addSource(it);
+ start();
+ }
+ }
+ }
+
+ ///@}
+
+ /// \name Query Functions
+ /// The results of the DFS algorithm can be obtained using these
+ /// functions.\n
+ /// Either \ref run(Node) "run()" or \ref start() should be called
+ /// before using them.
+
+ ///@{
+
+ /// \brief Checks if the given node is reached from the root(s).
+ ///
+ /// Returns \c true if \c v is reached from the root(s).
+ ///
+ /// \pre Either \ref run(Node) "run()" or \ref init()
+ /// must be called before using this function.
+ bool reached(Node v) const { return (*_reached)[v]; }
+
+ ///@}
+
+ };
+
+} //END OF NAMESPACE LEMON
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/dheap.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/dheap.h
new file mode 100644
index 00000000000..a3ab62525aa
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/dheap.h
@@ -0,0 +1,352 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_DHEAP_H
+#define LEMON_DHEAP_H
+
+///\ingroup heaps
+///\file
+///\brief D-ary heap implementation.
+
+#include <vector>
+#include <utility>
+#include <functional>
+
+namespace lemon {
+
+ /// \ingroup heaps
+ ///
+ ///\brief D-ary heap data structure.
+ ///
+ /// This class implements the \e D-ary \e heap data structure.
+ /// It fully conforms to the \ref concepts::Heap "heap concept".
+ ///
+ /// The \ref DHeap "D-ary heap" is a generalization of the
+ /// \ref BinHeap "binary heap" structure, its nodes have at most
+ /// \c D children, instead of two.
+ /// \ref BinHeap and \ref QuadHeap are specialized implementations
+ /// of this structure for <tt>D=2</tt> and <tt>D=4</tt>, respectively.
+ ///
+ /// \tparam PR Type of the priorities of the items.
+ /// \tparam IM A read-writable item map with \c int values, used
+ /// internally to handle the cross references.
+ /// \tparam D The degree of the heap, each node have at most \e D
+ /// children. The default is 16. Powers of two are suggested to use
+ /// so that the multiplications and divisions needed to traverse the
+ /// nodes of the heap could be performed faster.
+ /// \tparam CMP A functor class for comparing the priorities.
+ /// The default is \c std::less<PR>.
+ ///
+ ///\sa BinHeap
+ ///\sa FouraryHeap
+#ifdef DOXYGEN
+ template <typename PR, typename IM, int D, typename CMP>
+#else
+ template <typename PR, typename IM, int D = 16,
+ typename CMP = std::less<PR> >
+#endif
+ class DHeap {
+ public:
+ /// Type of the item-int map.
+ typedef IM ItemIntMap;
+ /// Type of the priorities.
+ typedef PR Prio;
+ /// Type of the items stored in the heap.
+ typedef typename ItemIntMap::Key Item;
+ /// Type of the item-priority pairs.
+ typedef std::pair<Item,Prio> Pair;
+ /// Functor type for comparing the priorities.
+ typedef CMP Compare;
+
+ /// \brief Type to represent the states of the items.
+ ///
+ /// Each item has a state associated to it. It can be "in heap",
+ /// "pre-heap" or "post-heap". The latter two are indifferent from the
+ /// heap's point of view, but may be useful to the user.
+ ///
+ /// The item-int map must be initialized in such way that it assigns
+ /// \c PRE_HEAP (<tt>-1</tt>) to any element to be put in the heap.
+ enum State {
+ IN_HEAP = 0, ///< = 0.
+ PRE_HEAP = -1, ///< = -1.
+ POST_HEAP = -2 ///< = -2.
+ };
+
+ private:
+ std::vector<Pair> _data;
+ Compare _comp;
+ ItemIntMap &_iim;
+
+ public:
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ /// \param map A map that assigns \c int values to the items.
+ /// It is used internally to handle the cross references.
+ /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
+ explicit DHeap(ItemIntMap &map) : _iim(map) {}
+
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ /// \param map A map that assigns \c int values to the items.
+ /// It is used internally to handle the cross references.
+ /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
+ /// \param comp The function object used for comparing the priorities.
+ DHeap(ItemIntMap &map, const Compare &comp)
+ : _iim(map), _comp(comp) {}
+
+ /// \brief The number of items stored in the heap.
+ ///
+ /// This function returns the number of items stored in the heap.
+ int size() const { return _data.size(); }
+
+ /// \brief Check if the heap is empty.
+ ///
+ /// This function returns \c true if the heap is empty.
+ bool empty() const { return _data.empty(); }
+
+ /// \brief Make the heap empty.
+ ///
+ /// This functon makes the heap empty.
+ /// It does not change the cross reference map. If you want to reuse
+ /// a heap that is not surely empty, you should first clear it and
+ /// then you should set the cross reference map to \c PRE_HEAP
+ /// for each item.
+ void clear() { _data.clear(); }
+
+ private:
+ int parent(int i) { return (i-1)/D; }
+ int firstChild(int i) { return D*i+1; }
+
+ bool less(const Pair &p1, const Pair &p2) const {
+ return _comp(p1.second, p2.second);
+ }
+
+ void bubbleUp(int hole, Pair p) {
+ int par = parent(hole);
+ while( hole>0 && less(p,_data[par]) ) {
+ move(_data[par],hole);
+ hole = par;
+ par = parent(hole);
+ }
+ move(p, hole);
+ }
+
+ void bubbleDown(int hole, Pair p, int length) {
+ if( length>1 ) {
+ int child = firstChild(hole);
+ while( child+D<=length ) {
+ int min=child;
+ for (int i=1; i<D; ++i) {
+ if( less(_data[child+i], _data[min]) )
+ min=child+i;
+ }
+ if( !less(_data[min], p) )
+ goto ok;
+ move(_data[min], hole);
+ hole = min;
+ child = firstChild(hole);
+ }
+ if ( child<length ) {
+ int min = child;
+ while (++child < length) {
+ if( less(_data[child], _data[min]) )
+ min=child;
+ }
+ if( less(_data[min], p) ) {
+ move(_data[min], hole);
+ hole = min;
+ }
+ }
+ }
+ ok:
+ move(p, hole);
+ }
+
+ void move(const Pair &p, int i) {
+ _data[i] = p;
+ _iim.set(p.first, i);
+ }
+
+ public:
+ /// \brief Insert a pair of item and priority into the heap.
+ ///
+ /// This function inserts \c p.first to the heap with priority
+ /// \c p.second.
+ /// \param p The pair to insert.
+ /// \pre \c p.first must not be stored in the heap.
+ void push(const Pair &p) {
+ int n = _data.size();
+ _data.resize(n+1);
+ bubbleUp(n, p);
+ }
+
+ /// \brief Insert an item into the heap with the given priority.
+ ///
+ /// This function inserts the given item into the heap with the
+ /// given priority.
+ /// \param i The item to insert.
+ /// \param p The priority of the item.
+ /// \pre \e i must not be stored in the heap.
+ void push(const Item &i, const Prio &p) { push(Pair(i,p)); }
+
+ /// \brief Return the item having minimum priority.
+ ///
+ /// This function returns the item having minimum priority.
+ /// \pre The heap must be non-empty.
+ Item top() const { return _data[0].first; }
+
+ /// \brief The minimum priority.
+ ///
+ /// This function returns the minimum priority.
+ /// \pre The heap must be non-empty.
+ Prio prio() const { return _data[0].second; }
+
+ /// \brief Remove the item having minimum priority.
+ ///
+ /// This function removes the item having minimum priority.
+ /// \pre The heap must be non-empty.
+ void pop() {
+ int n = _data.size()-1;
+ _iim.set(_data[0].first, POST_HEAP);
+ if (n>0) bubbleDown(0, _data[n], n);
+ _data.pop_back();
+ }
+
+ /// \brief Remove the given item from the heap.
+ ///
+ /// This function removes the given item from the heap if it is
+ /// already stored.
+ /// \param i The item to delete.
+ /// \pre \e i must be in the heap.
+ void erase(const Item &i) {
+ int h = _iim[i];
+ int n = _data.size()-1;
+ _iim.set(_data[h].first, POST_HEAP);
+ if( h<n ) {
+ if( less(_data[parent(h)], _data[n]) )
+ bubbleDown(h, _data[n], n);
+ else
+ bubbleUp(h, _data[n]);
+ }
+ _data.pop_back();
+ }
+
+ /// \brief The priority of the given item.
+ ///
+ /// This function returns the priority of the given item.
+ /// \param i The item.
+ /// \pre \e i must be in the heap.
+ Prio operator[](const Item &i) const {
+ int idx = _iim[i];
+ return _data[idx].second;
+ }
+
+ /// \brief Set the priority of an item or insert it, if it is
+ /// not stored in the heap.
+ ///
+ /// This method sets the priority of the given item if it is
+ /// already stored in the heap. Otherwise it inserts the given
+ /// item into the heap with the given priority.
+ /// \param i The item.
+ /// \param p The priority.
+ void set(const Item &i, const Prio &p) {
+ int idx = _iim[i];
+ if( idx<0 )
+ push(i,p);
+ else if( _comp(p, _data[idx].second) )
+ bubbleUp(idx, Pair(i,p));
+ else
+ bubbleDown(idx, Pair(i,p), _data.size());
+ }
+
+ /// \brief Decrease the priority of an item to the given value.
+ ///
+ /// This function decreases the priority of an item to the given value.
+ /// \param i The item.
+ /// \param p The priority.
+ /// \pre \e i must be stored in the heap with priority at least \e p.
+ void decrease(const Item &i, const Prio &p) {
+ int idx = _iim[i];
+ bubbleUp(idx, Pair(i,p));
+ }
+
+ /// \brief Increase the priority of an item to the given value.
+ ///
+ /// This function increases the priority of an item to the given value.
+ /// \param i The item.
+ /// \param p The priority.
+ /// \pre \e i must be stored in the heap with priority at most \e p.
+ void increase(const Item &i, const Prio &p) {
+ int idx = _iim[i];
+ bubbleDown(idx, Pair(i,p), _data.size());
+ }
+
+ /// \brief Return the state of an item.
+ ///
+ /// This method returns \c PRE_HEAP if the given item has never
+ /// been in the heap, \c IN_HEAP if it is in the heap at the moment,
+ /// and \c POST_HEAP otherwise.
+ /// In the latter case it is possible that the item will get back
+ /// to the heap again.
+ /// \param i The item.
+ State state(const Item &i) const {
+ int s = _iim[i];
+ if (s>=0) s=0;
+ return State(s);
+ }
+
+ /// \brief Set the state of an item in the heap.
+ ///
+ /// This function sets the state of the given item in the heap.
+ /// It can be used to manually clear the heap when it is important
+ /// to achive better time complexity.
+ /// \param i The item.
+ /// \param st The state. It should not be \c IN_HEAP.
+ void state(const Item& i, State st) {
+ switch (st) {
+ case POST_HEAP:
+ case PRE_HEAP:
+ if (state(i) == IN_HEAP) erase(i);
+ _iim[i] = st;
+ break;
+ case IN_HEAP:
+ break;
+ }
+ }
+
+ /// \brief Replace an item in the heap.
+ ///
+ /// This function replaces item \c i with item \c j.
+ /// Item \c i must be in the heap, while \c j must be out of the heap.
+ /// After calling this method, item \c i will be out of the
+ /// heap and \c j will be in the heap with the same prioriority
+ /// as item \c i had before.
+ void replace(const Item& i, const Item& j) {
+ int idx=_iim[i];
+ _iim.set(i, _iim[j]);
+ _iim.set(j, idx);
+ _data[idx].first=j;
+ }
+
+ }; // class DHeap
+
+} // namespace lemon
+
+#endif // LEMON_DHEAP_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/dijkstra.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/dijkstra.h
new file mode 100644
index 00000000000..1564a03e6ec
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/dijkstra.h
@@ -0,0 +1,1303 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_DIJKSTRA_H
+#define LEMON_DIJKSTRA_H
+
+///\ingroup shortest_path
+///\file
+///\brief Dijkstra algorithm.
+
+#include <limits>
+#include <lemon/list_graph.h>
+#include <lemon/bin_heap.h>
+#include <lemon/bits/path_dump.h>
+#include <lemon/core.h>
+#include <lemon/error.h>
+#include <lemon/maps.h>
+#include <lemon/path.h>
+
+namespace lemon {
+
+ /// \brief Default operation traits for the Dijkstra algorithm class.
+ ///
+ /// This operation traits class defines all computational operations and
+ /// constants which are used in the Dijkstra algorithm.
+ template <typename V>
+ struct DijkstraDefaultOperationTraits {
+ /// \e
+ typedef V Value;
+ /// \brief Gives back the zero value of the type.
+ static Value zero() {
+ return static_cast<Value>(0);
+ }
+ /// \brief Gives back the sum of the given two elements.
+ static Value plus(const Value& left, const Value& right) {
+ return left + right;
+ }
+ /// \brief Gives back true only if the first value is less than the second.
+ static bool less(const Value& left, const Value& right) {
+ return left < right;
+ }
+ };
+
+ ///Default traits class of Dijkstra class.
+
+ ///Default traits class of Dijkstra class.
+ ///\tparam GR The type of the digraph.
+ ///\tparam LEN The type of the length map.
+ template<typename GR, typename LEN>
+ struct DijkstraDefaultTraits
+ {
+ ///The type of the digraph the algorithm runs on.
+ typedef GR Digraph;
+
+ ///The type of the map that stores the arc lengths.
+
+ ///The type of the map that stores the arc lengths.
+ ///It must conform to the \ref concepts::ReadMap "ReadMap" concept.
+ typedef LEN LengthMap;
+ ///The type of the arc lengths.
+ typedef typename LEN::Value Value;
+
+ /// Operation traits for %Dijkstra algorithm.
+
+ /// This class defines the operations that are used in the algorithm.
+ /// \see DijkstraDefaultOperationTraits
+ typedef DijkstraDefaultOperationTraits<Value> OperationTraits;
+
+ /// The cross reference type used by the heap.
+
+ /// The cross reference type used by the heap.
+ /// Usually it is \c Digraph::NodeMap<int>.
+ typedef typename Digraph::template NodeMap<int> HeapCrossRef;
+ ///Instantiates a \c HeapCrossRef.
+
+ ///This function instantiates a \ref HeapCrossRef.
+ /// \param g is the digraph, to which we would like to define the
+ /// \ref HeapCrossRef.
+ static HeapCrossRef *createHeapCrossRef(const Digraph &g)
+ {
+ return new HeapCrossRef(g);
+ }
+
+ ///The heap type used by the %Dijkstra algorithm.
+
+ ///The heap type used by the Dijkstra algorithm.
+ ///
+ ///\sa BinHeap
+ ///\sa Dijkstra
+ typedef BinHeap<typename LEN::Value, HeapCrossRef, std::less<Value> > Heap;
+ ///Instantiates a \c Heap.
+
+ ///This function instantiates a \ref Heap.
+ static Heap *createHeap(HeapCrossRef& r)
+ {
+ return new Heap(r);
+ }
+
+ ///\brief The type of the map that stores the predecessor
+ ///arcs of the shortest paths.
+ ///
+ ///The type of the map that stores the predecessor
+ ///arcs of the shortest paths.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ typedef typename Digraph::template NodeMap<typename Digraph::Arc> PredMap;
+ ///Instantiates a \c PredMap.
+
+ ///This function instantiates a \ref PredMap.
+ ///\param g is the digraph, to which we would like to define the
+ ///\ref PredMap.
+ static PredMap *createPredMap(const Digraph &g)
+ {
+ return new PredMap(g);
+ }
+
+ ///The type of the map that indicates which nodes are processed.
+
+ ///The type of the map that indicates which nodes are processed.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ ///By default, it is a NullMap.
+ typedef NullMap<typename Digraph::Node,bool> ProcessedMap;
+ ///Instantiates a \c ProcessedMap.
+
+ ///This function instantiates a \ref ProcessedMap.
+ ///\param g is the digraph, to which
+ ///we would like to define the \ref ProcessedMap.
+#ifdef DOXYGEN
+ static ProcessedMap *createProcessedMap(const Digraph &g)
+#else
+ static ProcessedMap *createProcessedMap(const Digraph &)
+#endif
+ {
+ return new ProcessedMap();
+ }
+
+ ///The type of the map that stores the distances of the nodes.
+
+ ///The type of the map that stores the distances of the nodes.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ typedef typename Digraph::template NodeMap<typename LEN::Value> DistMap;
+ ///Instantiates a \c DistMap.
+
+ ///This function instantiates a \ref DistMap.
+ ///\param g is the digraph, to which we would like to define
+ ///the \ref DistMap.
+ static DistMap *createDistMap(const Digraph &g)
+ {
+ return new DistMap(g);
+ }
+ };
+
+ ///%Dijkstra algorithm class.
+
+ /// \ingroup shortest_path
+ ///This class provides an efficient implementation of the %Dijkstra algorithm.
+ ///
+ ///The %Dijkstra algorithm solves the single-source shortest path problem
+ ///when all arc lengths are non-negative. If there are negative lengths,
+ ///the BellmanFord algorithm should be used instead.
+ ///
+ ///The arc lengths are passed to the algorithm using a
+ ///\ref concepts::ReadMap "ReadMap",
+ ///so it is easy to change it to any kind of length.
+ ///The type of the length is determined by the
+ ///\ref concepts::ReadMap::Value "Value" of the length map.
+ ///It is also possible to change the underlying priority heap.
+ ///
+ ///There is also a \ref dijkstra() "function-type interface" for the
+ ///%Dijkstra algorithm, which is convenient in the simplier cases and
+ ///it can be used easier.
+ ///
+ ///\tparam GR The type of the digraph the algorithm runs on.
+ ///The default type is \ref ListDigraph.
+ ///\tparam LEN A \ref concepts::ReadMap "readable" arc map that specifies
+ ///the lengths of the arcs.
+ ///It is read once for each arc, so the map may involve in
+ ///relatively time consuming process to compute the arc lengths if
+ ///it is necessary. The default map type is \ref
+ ///concepts::Digraph::ArcMap "GR::ArcMap<int>".
+ ///\tparam TR The traits class that defines various types used by the
+ ///algorithm. By default, it is \ref DijkstraDefaultTraits
+ ///"DijkstraDefaultTraits<GR, LEN>".
+ ///In most cases, this parameter should not be set directly,
+ ///consider to use the named template parameters instead.
+#ifdef DOXYGEN
+ template <typename GR, typename LEN, typename TR>
+#else
+ template <typename GR=ListDigraph,
+ typename LEN=typename GR::template ArcMap<int>,
+ typename TR=DijkstraDefaultTraits<GR,LEN> >
+#endif
+ class Dijkstra {
+ public:
+
+ ///The type of the digraph the algorithm runs on.
+ typedef typename TR::Digraph Digraph;
+
+ ///The type of the arc lengths.
+ typedef typename TR::Value Value;
+ ///The type of the map that stores the arc lengths.
+ typedef typename TR::LengthMap LengthMap;
+ ///\brief The type of the map that stores the predecessor arcs of the
+ ///shortest paths.
+ typedef typename TR::PredMap PredMap;
+ ///The type of the map that stores the distances of the nodes.
+ typedef typename TR::DistMap DistMap;
+ ///The type of the map that indicates which nodes are processed.
+ typedef typename TR::ProcessedMap ProcessedMap;
+ ///The type of the paths.
+ typedef PredMapPath<Digraph, PredMap> Path;
+ ///The cross reference type used for the current heap.
+ typedef typename TR::HeapCrossRef HeapCrossRef;
+ ///The heap type used by the algorithm.
+ typedef typename TR::Heap Heap;
+ /// \brief The \ref lemon::DijkstraDefaultOperationTraits
+ /// "operation traits class" of the algorithm.
+ typedef typename TR::OperationTraits OperationTraits;
+
+ ///The \ref lemon::DijkstraDefaultTraits "traits class" of the algorithm.
+ typedef TR Traits;
+
+ private:
+
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::NodeIt NodeIt;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::OutArcIt OutArcIt;
+
+ //Pointer to the underlying digraph.
+ const Digraph *G;
+ //Pointer to the length map.
+ const LengthMap *_length;
+ //Pointer to the map of predecessors arcs.
+ PredMap *_pred;
+ //Indicates if _pred is locally allocated (true) or not.
+ bool local_pred;
+ //Pointer to the map of distances.
+ DistMap *_dist;
+ //Indicates if _dist is locally allocated (true) or not.
+ bool local_dist;
+ //Pointer to the map of processed status of the nodes.
+ ProcessedMap *_processed;
+ //Indicates if _processed is locally allocated (true) or not.
+ bool local_processed;
+ //Pointer to the heap cross references.
+ HeapCrossRef *_heap_cross_ref;
+ //Indicates if _heap_cross_ref is locally allocated (true) or not.
+ bool local_heap_cross_ref;
+ //Pointer to the heap.
+ Heap *_heap;
+ //Indicates if _heap is locally allocated (true) or not.
+ bool local_heap;
+
+ //Creates the maps if necessary.
+ void create_maps()
+ {
+ if(!_pred) {
+ local_pred = true;
+ _pred = Traits::createPredMap(*G);
+ }
+ if(!_dist) {
+ local_dist = true;
+ _dist = Traits::createDistMap(*G);
+ }
+ if(!_processed) {
+ local_processed = true;
+ _processed = Traits::createProcessedMap(*G);
+ }
+ if (!_heap_cross_ref) {
+ local_heap_cross_ref = true;
+ _heap_cross_ref = Traits::createHeapCrossRef(*G);
+ }
+ if (!_heap) {
+ local_heap = true;
+ _heap = Traits::createHeap(*_heap_cross_ref);
+ }
+ }
+
+ public:
+
+ typedef Dijkstra Create;
+
+ ///\name Named Template Parameters
+
+ ///@{
+
+ template <class T>
+ struct SetPredMapTraits : public Traits {
+ typedef T PredMap;
+ static PredMap *createPredMap(const Digraph &)
+ {
+ LEMON_ASSERT(false, "PredMap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///\c PredMap type.
+ ///
+ ///\ref named-templ-param "Named parameter" for setting
+ ///\c PredMap type.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ template <class T>
+ struct SetPredMap
+ : public Dijkstra< Digraph, LengthMap, SetPredMapTraits<T> > {
+ typedef Dijkstra< Digraph, LengthMap, SetPredMapTraits<T> > Create;
+ };
+
+ template <class T>
+ struct SetDistMapTraits : public Traits {
+ typedef T DistMap;
+ static DistMap *createDistMap(const Digraph &)
+ {
+ LEMON_ASSERT(false, "DistMap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///\c DistMap type.
+ ///
+ ///\ref named-templ-param "Named parameter" for setting
+ ///\c DistMap type.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ template <class T>
+ struct SetDistMap
+ : public Dijkstra< Digraph, LengthMap, SetDistMapTraits<T> > {
+ typedef Dijkstra< Digraph, LengthMap, SetDistMapTraits<T> > Create;
+ };
+
+ template <class T>
+ struct SetProcessedMapTraits : public Traits {
+ typedef T ProcessedMap;
+ static ProcessedMap *createProcessedMap(const Digraph &)
+ {
+ LEMON_ASSERT(false, "ProcessedMap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///\c ProcessedMap type.
+ ///
+ ///\ref named-templ-param "Named parameter" for setting
+ ///\c ProcessedMap type.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ template <class T>
+ struct SetProcessedMap
+ : public Dijkstra< Digraph, LengthMap, SetProcessedMapTraits<T> > {
+ typedef Dijkstra< Digraph, LengthMap, SetProcessedMapTraits<T> > Create;
+ };
+
+ struct SetStandardProcessedMapTraits : public Traits {
+ typedef typename Digraph::template NodeMap<bool> ProcessedMap;
+ static ProcessedMap *createProcessedMap(const Digraph &g)
+ {
+ return new ProcessedMap(g);
+ }
+ };
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///\c ProcessedMap type to be <tt>Digraph::NodeMap<bool></tt>.
+ ///
+ ///\ref named-templ-param "Named parameter" for setting
+ ///\c ProcessedMap type to be <tt>Digraph::NodeMap<bool></tt>.
+ ///If you don't set it explicitly, it will be automatically allocated.
+ struct SetStandardProcessedMap
+ : public Dijkstra< Digraph, LengthMap, SetStandardProcessedMapTraits > {
+ typedef Dijkstra< Digraph, LengthMap, SetStandardProcessedMapTraits >
+ Create;
+ };
+
+ template <class H, class CR>
+ struct SetHeapTraits : public Traits {
+ typedef CR HeapCrossRef;
+ typedef H Heap;
+ static HeapCrossRef *createHeapCrossRef(const Digraph &) {
+ LEMON_ASSERT(false, "HeapCrossRef is not initialized");
+ return 0; // ignore warnings
+ }
+ static Heap *createHeap(HeapCrossRef &)
+ {
+ LEMON_ASSERT(false, "Heap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///heap and cross reference types
+ ///
+ ///\ref named-templ-param "Named parameter" for setting heap and cross
+ ///reference types. If this named parameter is used, then external
+ ///heap and cross reference objects must be passed to the algorithm
+ ///using the \ref heap() function before calling \ref run(Node) "run()"
+ ///or \ref init().
+ ///\sa SetStandardHeap
+ template <class H, class CR = typename Digraph::template NodeMap<int> >
+ struct SetHeap
+ : public Dijkstra< Digraph, LengthMap, SetHeapTraits<H, CR> > {
+ typedef Dijkstra< Digraph, LengthMap, SetHeapTraits<H, CR> > Create;
+ };
+
+ template <class H, class CR>
+ struct SetStandardHeapTraits : public Traits {
+ typedef CR HeapCrossRef;
+ typedef H Heap;
+ static HeapCrossRef *createHeapCrossRef(const Digraph &G) {
+ return new HeapCrossRef(G);
+ }
+ static Heap *createHeap(HeapCrossRef &R)
+ {
+ return new Heap(R);
+ }
+ };
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///heap and cross reference types with automatic allocation
+ ///
+ ///\ref named-templ-param "Named parameter" for setting heap and cross
+ ///reference types with automatic allocation.
+ ///They should have standard constructor interfaces to be able to
+ ///automatically created by the algorithm (i.e. the digraph should be
+ ///passed to the constructor of the cross reference and the cross
+ ///reference should be passed to the constructor of the heap).
+ ///However, external heap and cross reference objects could also be
+ ///passed to the algorithm using the \ref heap() function before
+ ///calling \ref run(Node) "run()" or \ref init().
+ ///\sa SetHeap
+ template <class H, class CR = typename Digraph::template NodeMap<int> >
+ struct SetStandardHeap
+ : public Dijkstra< Digraph, LengthMap, SetStandardHeapTraits<H, CR> > {
+ typedef Dijkstra< Digraph, LengthMap, SetStandardHeapTraits<H, CR> >
+ Create;
+ };
+
+ template <class T>
+ struct SetOperationTraitsTraits : public Traits {
+ typedef T OperationTraits;
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ ///\c OperationTraits type
+ ///
+ ///\ref named-templ-param "Named parameter" for setting
+ ///\c OperationTraits type.
+ /// For more information, see \ref DijkstraDefaultOperationTraits.
+ template <class T>
+ struct SetOperationTraits
+ : public Dijkstra<Digraph, LengthMap, SetOperationTraitsTraits<T> > {
+ typedef Dijkstra<Digraph, LengthMap, SetOperationTraitsTraits<T> >
+ Create;
+ };
+
+ ///@}
+
+ protected:
+
+ Dijkstra() {}
+
+ public:
+
+ ///Constructor.
+
+ ///Constructor.
+ ///\param g The digraph the algorithm runs on.
+ ///\param length The length map used by the algorithm.
+ Dijkstra(const Digraph& g, const LengthMap& length) :
+ G(&g), _length(&length),
+ _pred(NULL), local_pred(false),
+ _dist(NULL), local_dist(false),
+ _processed(NULL), local_processed(false),
+ _heap_cross_ref(NULL), local_heap_cross_ref(false),
+ _heap(NULL), local_heap(false)
+ { }
+
+ ///Destructor.
+ ~Dijkstra()
+ {
+ if(local_pred) delete _pred;
+ if(local_dist) delete _dist;
+ if(local_processed) delete _processed;
+ if(local_heap_cross_ref) delete _heap_cross_ref;
+ if(local_heap) delete _heap;
+ }
+
+ ///Sets the length map.
+
+ ///Sets the length map.
+ ///\return <tt> (*this) </tt>
+ Dijkstra &lengthMap(const LengthMap &m)
+ {
+ _length = &m;
+ return *this;
+ }
+
+ ///Sets the map that stores the predecessor arcs.
+
+ ///Sets the map that stores the predecessor arcs.
+ ///If you don't use this function before calling \ref run(Node) "run()"
+ ///or \ref init(), an instance will be allocated automatically.
+ ///The destructor deallocates this automatically allocated map,
+ ///of course.
+ ///\return <tt> (*this) </tt>
+ Dijkstra &predMap(PredMap &m)
+ {
+ if(local_pred) {
+ delete _pred;
+ local_pred=false;
+ }
+ _pred = &m;
+ return *this;
+ }
+
+ ///Sets the map that indicates which nodes are processed.
+
+ ///Sets the map that indicates which nodes are processed.
+ ///If you don't use this function before calling \ref run(Node) "run()"
+ ///or \ref init(), an instance will be allocated automatically.
+ ///The destructor deallocates this automatically allocated map,
+ ///of course.
+ ///\return <tt> (*this) </tt>
+ Dijkstra &processedMap(ProcessedMap &m)
+ {
+ if(local_processed) {
+ delete _processed;
+ local_processed=false;
+ }
+ _processed = &m;
+ return *this;
+ }
+
+ ///Sets the map that stores the distances of the nodes.
+
+ ///Sets the map that stores the distances of the nodes calculated by the
+ ///algorithm.
+ ///If you don't use this function before calling \ref run(Node) "run()"
+ ///or \ref init(), an instance will be allocated automatically.
+ ///The destructor deallocates this automatically allocated map,
+ ///of course.
+ ///\return <tt> (*this) </tt>
+ Dijkstra &distMap(DistMap &m)
+ {
+ if(local_dist) {
+ delete _dist;
+ local_dist=false;
+ }
+ _dist = &m;
+ return *this;
+ }
+
+ ///Sets the heap and the cross reference used by algorithm.
+
+ ///Sets the heap and the cross reference used by algorithm.
+ ///If you don't use this function before calling \ref run(Node) "run()"
+ ///or \ref init(), heap and cross reference instances will be
+ ///allocated automatically.
+ ///The destructor deallocates these automatically allocated objects,
+ ///of course.
+ ///\return <tt> (*this) </tt>
+ Dijkstra &heap(Heap& hp, HeapCrossRef &cr)
+ {
+ if(local_heap_cross_ref) {
+ delete _heap_cross_ref;
+ local_heap_cross_ref=false;
+ }
+ _heap_cross_ref = &cr;
+ if(local_heap) {
+ delete _heap;
+ local_heap=false;
+ }
+ _heap = &hp;
+ return *this;
+ }
+
+ private:
+
+ void finalizeNodeData(Node v,Value dst)
+ {
+ _processed->set(v,true);
+ _dist->set(v, dst);
+ }
+
+ public:
+
+ ///\name Execution Control
+ ///The simplest way to execute the %Dijkstra algorithm is to use
+ ///one of the member functions called \ref run(Node) "run()".\n
+ ///If you need better control on the execution, you have to call
+ ///\ref init() first, then you can add several source nodes with
+ ///\ref addSource(). Finally the actual path computation can be
+ ///performed with one of the \ref start() functions.
+
+ ///@{
+
+ ///\brief Initializes the internal data structures.
+ ///
+ ///Initializes the internal data structures.
+ void init()
+ {
+ create_maps();
+ _heap->clear();
+ for ( NodeIt u(*G) ; u!=INVALID ; ++u ) {
+ _pred->set(u,INVALID);
+ _processed->set(u,false);
+ _heap_cross_ref->set(u,Heap::PRE_HEAP);
+ }
+ }
+
+ ///Adds a new source node.
+
+ ///Adds a new source node to the priority heap.
+ ///The optional second parameter is the initial distance of the node.
+ ///
+ ///The function checks if the node has already been added to the heap and
+ ///it is pushed to the heap only if either it was not in the heap
+ ///or the shortest path found till then is shorter than \c dst.
+ void addSource(Node s,Value dst=OperationTraits::zero())
+ {
+ if(_heap->state(s) != Heap::IN_HEAP) {
+ _heap->push(s,dst);
+ } else if(OperationTraits::less((*_heap)[s], dst)) {
+ _heap->set(s,dst);
+ _pred->set(s,INVALID);
+ }
+ }
+
+ ///Processes the next node in the priority heap
+
+ ///Processes the next node in the priority heap.
+ ///
+ ///\return The processed node.
+ ///
+ ///\warning The priority heap must not be empty.
+ Node processNextNode()
+ {
+ Node v=_heap->top();
+ Value oldvalue=_heap->prio();
+ _heap->pop();
+ finalizeNodeData(v,oldvalue);
+
+ for(OutArcIt e(*G,v); e!=INVALID; ++e) {
+ Node w=G->target(e);
+ switch(_heap->state(w)) {
+ case Heap::PRE_HEAP:
+ _heap->push(w,OperationTraits::plus(oldvalue, (*_length)[e]));
+ _pred->set(w,e);
+ break;
+ case Heap::IN_HEAP:
+ {
+ Value newvalue = OperationTraits::plus(oldvalue, (*_length)[e]);
+ if ( OperationTraits::less(newvalue, (*_heap)[w]) ) {
+ _heap->decrease(w, newvalue);
+ _pred->set(w,e);
+ }
+ }
+ break;
+ case Heap::POST_HEAP:
+ break;
+ }
+ }
+ return v;
+ }
+
+ ///The next node to be processed.
+
+ ///Returns the next node to be processed or \c INVALID if the
+ ///priority heap is empty.
+ Node nextNode() const
+ {
+ return !_heap->empty()?_heap->top():INVALID;
+ }
+
+ ///Returns \c false if there are nodes to be processed.
+
+ ///Returns \c false if there are nodes to be processed
+ ///in the priority heap.
+ bool emptyQueue() const { return _heap->empty(); }
+
+ ///Returns the number of the nodes to be processed.
+
+ ///Returns the number of the nodes to be processed
+ ///in the priority heap.
+ int queueSize() const { return _heap->size(); }
+
+ ///Executes the algorithm.
+
+ ///Executes the algorithm.
+ ///
+ ///This method runs the %Dijkstra algorithm from the root node(s)
+ ///in order to compute the shortest path to each node.
+ ///
+ ///The algorithm computes
+ ///- the shortest path tree (forest),
+ ///- the distance of each node from the root(s).
+ ///
+ ///\pre init() must be called and at least one root node should be
+ ///added with addSource() before using this function.
+ ///
+ ///\note <tt>d.start()</tt> is just a shortcut of the following code.
+ ///\code
+ /// while ( !d.emptyQueue() ) {
+ /// d.processNextNode();
+ /// }
+ ///\endcode
+ void start()
+ {
+ while ( !emptyQueue() ) processNextNode();
+ }
+
+ ///Executes the algorithm until the given target node is processed.
+
+ ///Executes the algorithm until the given target node is processed.
+ ///
+ ///This method runs the %Dijkstra algorithm from the root node(s)
+ ///in order to compute the shortest path to \c t.
+ ///
+ ///The algorithm computes
+ ///- the shortest path to \c t,
+ ///- the distance of \c t from the root(s).
+ ///
+ ///\pre init() must be called and at least one root node should be
+ ///added with addSource() before using this function.
+ void start(Node t)
+ {
+ while ( !_heap->empty() && _heap->top()!=t ) processNextNode();
+ if ( !_heap->empty() ) {
+ finalizeNodeData(_heap->top(),_heap->prio());
+ _heap->pop();
+ }
+ }
+
+ ///Executes the algorithm until a condition is met.
+
+ ///Executes the algorithm until a condition is met.
+ ///
+ ///This method runs the %Dijkstra algorithm from the root node(s) in
+ ///order to compute the shortest path to a node \c v with
+ /// <tt>nm[v]</tt> true, if such a node can be found.
+ ///
+ ///\param nm A \c bool (or convertible) node map. The algorithm
+ ///will stop when it reaches a node \c v with <tt>nm[v]</tt> true.
+ ///
+ ///\return The reached node \c v with <tt>nm[v]</tt> true or
+ ///\c INVALID if no such node was found.
+ ///
+ ///\pre init() must be called and at least one root node should be
+ ///added with addSource() before using this function.
+ template<class NodeBoolMap>
+ Node start(const NodeBoolMap &nm)
+ {
+ while ( !_heap->empty() && !nm[_heap->top()] ) processNextNode();
+ if ( _heap->empty() ) return INVALID;
+ finalizeNodeData(_heap->top(),_heap->prio());
+ return _heap->top();
+ }
+
+ ///Runs the algorithm from the given source node.
+
+ ///This method runs the %Dijkstra algorithm from node \c s
+ ///in order to compute the shortest path to each node.
+ ///
+ ///The algorithm computes
+ ///- the shortest path tree,
+ ///- the distance of each node from the root.
+ ///
+ ///\note <tt>d.run(s)</tt> is just a shortcut of the following code.
+ ///\code
+ /// d.init();
+ /// d.addSource(s);
+ /// d.start();
+ ///\endcode
+ void run(Node s) {
+ init();
+ addSource(s);
+ start();
+ }
+
+ ///Finds the shortest path between \c s and \c t.
+
+ ///This method runs the %Dijkstra algorithm from node \c s
+ ///in order to compute the shortest path to node \c t
+ ///(it stops searching when \c t is processed).
+ ///
+ ///\return \c true if \c t is reachable form \c s.
+ ///
+ ///\note Apart from the return value, <tt>d.run(s,t)</tt> is just a
+ ///shortcut of the following code.
+ ///\code
+ /// d.init();
+ /// d.addSource(s);
+ /// d.start(t);
+ ///\endcode
+ bool run(Node s,Node t) {
+ init();
+ addSource(s);
+ start(t);
+ return (*_heap_cross_ref)[t] == Heap::POST_HEAP;
+ }
+
+ ///@}
+
+ ///\name Query Functions
+ ///The results of the %Dijkstra algorithm can be obtained using these
+ ///functions.\n
+ ///Either \ref run(Node) "run()" or \ref init() should be called
+ ///before using them.
+
+ ///@{
+
+ ///The shortest path to the given node.
+
+ ///Returns the shortest path to the given node from the root(s).
+ ///
+ ///\warning \c t should be reached from the root(s).
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ Path path(Node t) const { return Path(*G, *_pred, t); }
+
+ ///The distance of the given node from the root(s).
+
+ ///Returns the distance of the given node from the root(s).
+ ///
+ ///\warning If node \c v is not reached from the root(s), then
+ ///the return value of this function is undefined.
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ Value dist(Node v) const { return (*_dist)[v]; }
+
+ ///\brief Returns the 'previous arc' of the shortest path tree for
+ ///the given node.
+ ///
+ ///This function returns the 'previous arc' of the shortest path
+ ///tree for the node \c v, i.e. it returns the last arc of a
+ ///shortest path from a root to \c v. It is \c INVALID if \c v
+ ///is not reached from the root(s) or if \c v is a root.
+ ///
+ ///The shortest path tree used here is equal to the shortest path
+ ///tree used in \ref predNode() and \ref predMap().
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ Arc predArc(Node v) const { return (*_pred)[v]; }
+
+ ///\brief Returns the 'previous node' of the shortest path tree for
+ ///the given node.
+ ///
+ ///This function returns the 'previous node' of the shortest path
+ ///tree for the node \c v, i.e. it returns the last but one node
+ ///of a shortest path from a root to \c v. It is \c INVALID
+ ///if \c v is not reached from the root(s) or if \c v is a root.
+ ///
+ ///The shortest path tree used here is equal to the shortest path
+ ///tree used in \ref predArc() and \ref predMap().
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ Node predNode(Node v) const { return (*_pred)[v]==INVALID ? INVALID:
+ G->source((*_pred)[v]); }
+
+ ///\brief Returns a const reference to the node map that stores the
+ ///distances of the nodes.
+ ///
+ ///Returns a const reference to the node map that stores the distances
+ ///of the nodes calculated by the algorithm.
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ const DistMap &distMap() const { return *_dist;}
+
+ ///\brief Returns a const reference to the node map that stores the
+ ///predecessor arcs.
+ ///
+ ///Returns a const reference to the node map that stores the predecessor
+ ///arcs, which form the shortest path tree (forest).
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ const PredMap &predMap() const { return *_pred;}
+
+ ///Checks if the given node is reached from the root(s).
+
+ ///Returns \c true if \c v is reached from the root(s).
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ bool reached(Node v) const { return (*_heap_cross_ref)[v] !=
+ Heap::PRE_HEAP; }
+
+ ///Checks if a node is processed.
+
+ ///Returns \c true if \c v is processed, i.e. the shortest
+ ///path to \c v has already found.
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function.
+ bool processed(Node v) const { return (*_heap_cross_ref)[v] ==
+ Heap::POST_HEAP; }
+
+ ///The current distance of the given node from the root(s).
+
+ ///Returns the current distance of the given node from the root(s).
+ ///It may be decreased in the following processes.
+ ///
+ ///\pre Either \ref run(Node) "run()" or \ref init()
+ ///must be called before using this function and
+ ///node \c v must be reached but not necessarily processed.
+ Value currentDist(Node v) const {
+ return processed(v) ? (*_dist)[v] : (*_heap)[v];
+ }
+
+ ///@}
+ };
+
+
+ ///Default traits class of dijkstra() function.
+
+ ///Default traits class of dijkstra() function.
+ ///\tparam GR The type of the digraph.
+ ///\tparam LEN The type of the length map.
+ template<class GR, class LEN>
+ struct DijkstraWizardDefaultTraits
+ {
+ ///The type of the digraph the algorithm runs on.
+ typedef GR Digraph;
+ ///The type of the map that stores the arc lengths.
+
+ ///The type of the map that stores the arc lengths.
+ ///It must conform to the \ref concepts::ReadMap "ReadMap" concept.
+ typedef LEN LengthMap;
+ ///The type of the arc lengths.
+ typedef typename LEN::Value Value;
+
+ /// Operation traits for Dijkstra algorithm.
+
+ /// This class defines the operations that are used in the algorithm.
+ /// \see DijkstraDefaultOperationTraits
+ typedef DijkstraDefaultOperationTraits<Value> OperationTraits;
+
+ /// The cross reference type used by the heap.
+
+ /// The cross reference type used by the heap.
+ /// Usually it is \c Digraph::NodeMap<int>.
+ typedef typename Digraph::template NodeMap<int> HeapCrossRef;
+ ///Instantiates a \ref HeapCrossRef.
+
+ ///This function instantiates a \ref HeapCrossRef.
+ /// \param g is the digraph, to which we would like to define the
+ /// HeapCrossRef.
+ static HeapCrossRef *createHeapCrossRef(const Digraph &g)
+ {
+ return new HeapCrossRef(g);
+ }
+
+ ///The heap type used by the Dijkstra algorithm.
+
+ ///The heap type used by the Dijkstra algorithm.
+ ///
+ ///\sa BinHeap
+ ///\sa Dijkstra
+ typedef BinHeap<Value, typename Digraph::template NodeMap<int>,
+ std::less<Value> > Heap;
+
+ ///Instantiates a \ref Heap.
+
+ ///This function instantiates a \ref Heap.
+ /// \param r is the HeapCrossRef which is used.
+ static Heap *createHeap(HeapCrossRef& r)
+ {
+ return new Heap(r);
+ }
+
+ ///\brief The type of the map that stores the predecessor
+ ///arcs of the shortest paths.
+ ///
+ ///The type of the map that stores the predecessor
+ ///arcs of the shortest paths.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ typedef typename Digraph::template NodeMap<typename Digraph::Arc> PredMap;
+ ///Instantiates a PredMap.
+
+ ///This function instantiates a PredMap.
+ ///\param g is the digraph, to which we would like to define the
+ ///PredMap.
+ static PredMap *createPredMap(const Digraph &g)
+ {
+ return new PredMap(g);
+ }
+
+ ///The type of the map that indicates which nodes are processed.
+
+ ///The type of the map that indicates which nodes are processed.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ ///By default, it is a NullMap.
+ typedef NullMap<typename Digraph::Node,bool> ProcessedMap;
+ ///Instantiates a ProcessedMap.
+
+ ///This function instantiates a ProcessedMap.
+ ///\param g is the digraph, to which
+ ///we would like to define the ProcessedMap.
+#ifdef DOXYGEN
+ static ProcessedMap *createProcessedMap(const Digraph &g)
+#else
+ static ProcessedMap *createProcessedMap(const Digraph &)
+#endif
+ {
+ return new ProcessedMap();
+ }
+
+ ///The type of the map that stores the distances of the nodes.
+
+ ///The type of the map that stores the distances of the nodes.
+ ///It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ typedef typename Digraph::template NodeMap<typename LEN::Value> DistMap;
+ ///Instantiates a DistMap.
+
+ ///This function instantiates a DistMap.
+ ///\param g is the digraph, to which we would like to define
+ ///the DistMap
+ static DistMap *createDistMap(const Digraph &g)
+ {
+ return new DistMap(g);
+ }
+
+ ///The type of the shortest paths.
+
+ ///The type of the shortest paths.
+ ///It must conform to the \ref concepts::Path "Path" concept.
+ typedef lemon::Path<Digraph> Path;
+ };
+
+ /// Default traits class used by DijkstraWizard
+
+ /// Default traits class used by DijkstraWizard.
+ /// \tparam GR The type of the digraph.
+ /// \tparam LEN The type of the length map.
+ template<typename GR, typename LEN>
+ class DijkstraWizardBase : public DijkstraWizardDefaultTraits<GR,LEN>
+ {
+ typedef DijkstraWizardDefaultTraits<GR,LEN> Base;
+ protected:
+ //The type of the nodes in the digraph.
+ typedef typename Base::Digraph::Node Node;
+
+ //Pointer to the digraph the algorithm runs on.
+ void *_g;
+ //Pointer to the length map.
+ void *_length;
+ //Pointer to the map of processed nodes.
+ void *_processed;
+ //Pointer to the map of predecessors arcs.
+ void *_pred;
+ //Pointer to the map of distances.
+ void *_dist;
+ //Pointer to the shortest path to the target node.
+ void *_path;
+ //Pointer to the distance of the target node.
+ void *_di;
+
+ public:
+ /// Constructor.
+
+ /// This constructor does not require parameters, therefore it initiates
+ /// all of the attributes to \c 0.
+ DijkstraWizardBase() : _g(0), _length(0), _processed(0), _pred(0),
+ _dist(0), _path(0), _di(0) {}
+
+ /// Constructor.
+
+ /// This constructor requires two parameters,
+ /// others are initiated to \c 0.
+ /// \param g The digraph the algorithm runs on.
+ /// \param l The length map.
+ DijkstraWizardBase(const GR &g,const LEN &l) :
+ _g(reinterpret_cast<void*>(const_cast<GR*>(&g))),
+ _length(reinterpret_cast<void*>(const_cast<LEN*>(&l))),
+ _processed(0), _pred(0), _dist(0), _path(0), _di(0) {}
+
+ };
+
+ /// Auxiliary class for the function-type interface of Dijkstra algorithm.
+
+ /// This auxiliary class is created to implement the
+ /// \ref dijkstra() "function-type interface" of \ref Dijkstra algorithm.
+ /// It does not have own \ref run(Node) "run()" method, it uses the
+ /// functions and features of the plain \ref Dijkstra.
+ ///
+ /// This class should only be used through the \ref dijkstra() function,
+ /// which makes it easier to use the algorithm.
+ ///
+ /// \tparam TR The traits class that defines various types used by the
+ /// algorithm.
+ template<class TR>
+ class DijkstraWizard : public TR
+ {
+ typedef TR Base;
+
+ typedef typename TR::Digraph Digraph;
+
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::NodeIt NodeIt;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::OutArcIt OutArcIt;
+
+ typedef typename TR::LengthMap LengthMap;
+ typedef typename LengthMap::Value Value;
+ typedef typename TR::PredMap PredMap;
+ typedef typename TR::DistMap DistMap;
+ typedef typename TR::ProcessedMap ProcessedMap;
+ typedef typename TR::Path Path;
+ typedef typename TR::Heap Heap;
+
+ public:
+
+ /// Constructor.
+ DijkstraWizard() : TR() {}
+
+ /// Constructor that requires parameters.
+
+ /// Constructor that requires parameters.
+ /// These parameters will be the default values for the traits class.
+ /// \param g The digraph the algorithm runs on.
+ /// \param l The length map.
+ DijkstraWizard(const Digraph &g, const LengthMap &l) :
+ TR(g,l) {}
+
+ ///Copy constructor
+ DijkstraWizard(const TR &b) : TR(b) {}
+
+ ~DijkstraWizard() {}
+
+ ///Runs Dijkstra algorithm from the given source node.
+
+ ///This method runs %Dijkstra algorithm from the given source node
+ ///in order to compute the shortest path to each node.
+ void run(Node s)
+ {
+ Dijkstra<Digraph,LengthMap,TR>
+ dijk(*reinterpret_cast<const Digraph*>(Base::_g),
+ *reinterpret_cast<const LengthMap*>(Base::_length));
+ if (Base::_pred)
+ dijk.predMap(*reinterpret_cast<PredMap*>(Base::_pred));
+ if (Base::_dist)
+ dijk.distMap(*reinterpret_cast<DistMap*>(Base::_dist));
+ if (Base::_processed)
+ dijk.processedMap(*reinterpret_cast<ProcessedMap*>(Base::_processed));
+ dijk.run(s);
+ }
+
+ ///Finds the shortest path between \c s and \c t.
+
+ ///This method runs the %Dijkstra algorithm from node \c s
+ ///in order to compute the shortest path to node \c t
+ ///(it stops searching when \c t is processed).
+ ///
+ ///\return \c true if \c t is reachable form \c s.
+ bool run(Node s, Node t)
+ {
+ Dijkstra<Digraph,LengthMap,TR>
+ dijk(*reinterpret_cast<const Digraph*>(Base::_g),
+ *reinterpret_cast<const LengthMap*>(Base::_length));
+ if (Base::_pred)
+ dijk.predMap(*reinterpret_cast<PredMap*>(Base::_pred));
+ if (Base::_dist)
+ dijk.distMap(*reinterpret_cast<DistMap*>(Base::_dist));
+ if (Base::_processed)
+ dijk.processedMap(*reinterpret_cast<ProcessedMap*>(Base::_processed));
+ dijk.run(s,t);
+ if (Base::_path)
+ *reinterpret_cast<Path*>(Base::_path) = dijk.path(t);
+ if (Base::_di)
+ *reinterpret_cast<Value*>(Base::_di) = dijk.dist(t);
+ return dijk.reached(t);
+ }
+
+ template<class T>
+ struct SetPredMapBase : public Base {
+ typedef T PredMap;
+ static PredMap *createPredMap(const Digraph &) { return 0; };
+ SetPredMapBase(const TR &b) : TR(b) {}
+ };
+
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///the predecessor map.
+ ///
+ ///\ref named-templ-param "Named parameter" function for setting
+ ///the map that stores the predecessor arcs of the nodes.
+ template<class T>
+ DijkstraWizard<SetPredMapBase<T> > predMap(const T &t)
+ {
+ Base::_pred=reinterpret_cast<void*>(const_cast<T*>(&t));
+ return DijkstraWizard<SetPredMapBase<T> >(*this);
+ }
+
+ template<class T>
+ struct SetDistMapBase : public Base {
+ typedef T DistMap;
+ static DistMap *createDistMap(const Digraph &) { return 0; };
+ SetDistMapBase(const TR &b) : TR(b) {}
+ };
+
+ ///\brief \ref named-templ-param "Named parameter" for setting
+ ///the distance map.
+ ///
+ ///\ref named-templ-param "Named parameter" function for setting
+ ///the map that stores the distances of the nodes calculated
+ ///by the algorithm.
+ template<class T>
+ DijkstraWizard<SetDistMapBase<T> > distMap(const T &t)
+ {
+ Base::_dist=reinterpret_cast<void*>(const_cast<T*>(&t));
+ return DijkstraWizard<SetDistMapBase<T> >(*this);
+ }
+
+ template<class T>
+ struct SetProcessedMapBase : public Base {
+ typedef T ProcessedMap;
+ static ProcessedMap *createProcessedMap(const Digraph &) { return 0; };
+ SetProcessedMapBase(const TR &b) : TR(b) {}
+ };
+
+ ///\brief \ref named-func-param "Named parameter" for setting
+ ///the processed map.
+ ///
+ ///\ref named-templ-param "Named parameter" function for setting
+ ///the map that indicates which nodes are processed.
+ template<class T>
+ DijkstraWizard<SetProcessedMapBase<T> > processedMap(const T &t)
+ {
+ Base::_processed=reinterpret_cast<void*>(const_cast<T*>(&t));
+ return DijkstraWizard<SetProcessedMapBase<T> >(*this);
+ }
+
+ template<class T>
+ struct SetPathBase : public Base {
+ typedef T Path;
+ SetPathBase(const TR &b) : TR(b) {}
+ };
+
+ ///\brief \ref named-func-param "Named parameter"
+ ///for getting the shortest path to the target node.
+ ///
+ ///\ref named-func-param "Named parameter"
+ ///for getting the shortest path to the target node.
+ template<class T>
+ DijkstraWizard<SetPathBase<T> > path(const T &t)
+ {
+ Base::_path=reinterpret_cast<void*>(const_cast<T*>(&t));
+ return DijkstraWizard<SetPathBase<T> >(*this);
+ }
+
+ ///\brief \ref named-func-param "Named parameter"
+ ///for getting the distance of the target node.
+ ///
+ ///\ref named-func-param "Named parameter"
+ ///for getting the distance of the target node.
+ DijkstraWizard dist(const Value &d)
+ {
+ Base::_di=reinterpret_cast<void*>(const_cast<Value*>(&d));
+ return *this;
+ }
+
+ };
+
+ ///Function-type interface for Dijkstra algorithm.
+
+ /// \ingroup shortest_path
+ ///Function-type interface for Dijkstra algorithm.
+ ///
+ ///This function also has several \ref named-func-param "named parameters",
+ ///they are declared as the members of class \ref DijkstraWizard.
+ ///The following examples show how to use these parameters.
+ ///\code
+ /// // Compute shortest path from node s to each node
+ /// dijkstra(g,length).predMap(preds).distMap(dists).run(s);
+ ///
+ /// // Compute shortest path from s to t
+ /// bool reached = dijkstra(g,length).path(p).dist(d).run(s,t);
+ ///\endcode
+ ///\warning Don't forget to put the \ref DijkstraWizard::run(Node) "run()"
+ ///to the end of the parameter list.
+ ///\sa DijkstraWizard
+ ///\sa Dijkstra
+ template<typename GR, typename LEN>
+ DijkstraWizard<DijkstraWizardBase<GR,LEN> >
+ dijkstra(const GR &digraph, const LEN &length)
+ {
+ return DijkstraWizard<DijkstraWizardBase<GR,LEN> >(digraph,length);
+ }
+
+} //END OF NAMESPACE LEMON
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/dim2.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/dim2.h
new file mode 100644
index 00000000000..0b14221060f
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/dim2.h
@@ -0,0 +1,726 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_DIM2_H
+#define LEMON_DIM2_H
+
+#include <iostream>
+#include <algorithm>
+
+///\ingroup geomdat
+///\file
+///\brief A simple two dimensional vector and a bounding box implementation
+
+namespace lemon {
+
+ ///Tools for handling two dimensional coordinates
+
+ ///This namespace is a storage of several
+ ///tools for handling two dimensional coordinates
+ namespace dim2 {
+
+ /// \addtogroup geomdat
+ /// @{
+
+ /// Two dimensional vector (plain vector)
+
+ /// A simple two dimensional vector (plain vector) implementation
+ /// with the usual vector operations.
+ template<typename T>
+ class Point {
+
+ public:
+
+ typedef T Value;
+
+ ///First coordinate
+ T x;
+ ///Second coordinate
+ T y;
+
+ ///Default constructor
+ Point() {}
+
+ ///Construct an instance from coordinates
+ Point(T a, T b) : x(a), y(b) { }
+
+ ///Returns the dimension of the vector (i.e. returns 2).
+
+ ///The dimension of the vector.
+ ///This function always returns 2.
+ int size() const { return 2; }
+
+ ///Subscripting operator
+
+ ///\c p[0] is \c p.x and \c p[1] is \c p.y
+ ///
+ T& operator[](int idx) { return idx == 0 ? x : y; }
+
+ ///Const subscripting operator
+
+ ///\c p[0] is \c p.x and \c p[1] is \c p.y
+ ///
+ const T& operator[](int idx) const { return idx == 0 ? x : y; }
+
+ ///Conversion constructor
+ template<class TT> Point(const Point<TT> &p) : x(p.x), y(p.y) {}
+
+ ///Give back the square of the norm of the vector
+ T normSquare() const {
+ return x*x+y*y;
+ }
+
+ ///Increment the left hand side by \c u
+ Point<T>& operator +=(const Point<T>& u) {
+ x += u.x;
+ y += u.y;
+ return *this;
+ }
+
+ ///Decrement the left hand side by \c u
+ Point<T>& operator -=(const Point<T>& u) {
+ x -= u.x;
+ y -= u.y;
+ return *this;
+ }
+
+ ///Multiply the left hand side with a scalar
+ Point<T>& operator *=(const T &u) {
+ x *= u;
+ y *= u;
+ return *this;
+ }
+
+ ///Divide the left hand side by a scalar
+ Point<T>& operator /=(const T &u) {
+ x /= u;
+ y /= u;
+ return *this;
+ }
+
+ ///Return the scalar product of two vectors
+ T operator *(const Point<T>& u) const {
+ return x*u.x+y*u.y;
+ }
+
+ ///Return the sum of two vectors
+ Point<T> operator+(const Point<T> &u) const {
+ Point<T> b=*this;
+ return b+=u;
+ }
+
+ ///Return the negative of the vector
+ Point<T> operator-() const {
+ Point<T> b=*this;
+ b.x=-b.x; b.y=-b.y;
+ return b;
+ }
+
+ ///Return the difference of two vectors
+ Point<T> operator-(const Point<T> &u) const {
+ Point<T> b=*this;
+ return b-=u;
+ }
+
+ ///Return a vector multiplied by a scalar
+ Point<T> operator*(const T &u) const {
+ Point<T> b=*this;
+ return b*=u;
+ }
+
+ ///Return a vector divided by a scalar
+ Point<T> operator/(const T &u) const {
+ Point<T> b=*this;
+ return b/=u;
+ }
+
+ ///Test equality
+ bool operator==(const Point<T> &u) const {
+ return (x==u.x) && (y==u.y);
+ }
+
+ ///Test inequality
+ bool operator!=(Point u) const {
+ return (x!=u.x) || (y!=u.y);
+ }
+
+ };
+
+ ///Return a Point
+
+ ///Return a Point.
+ ///\relates Point
+ template <typename T>
+ inline Point<T> makePoint(const T& x, const T& y) {
+ return Point<T>(x, y);
+ }
+
+ ///Return a vector multiplied by a scalar
+
+ ///Return a vector multiplied by a scalar.
+ ///\relates Point
+ template<typename T> Point<T> operator*(const T &u,const Point<T> &x) {
+ return x*u;
+ }
+
+ ///Read a plain vector from a stream
+
+ ///Read a plain vector from a stream.
+ ///\relates Point
+ ///
+ template<typename T>
+ inline std::istream& operator>>(std::istream &is, Point<T> &z) {
+ char c;
+ if (is >> c) {
+ if (c != '(') is.putback(c);
+ } else {
+ is.clear();
+ }
+ if (!(is >> z.x)) return is;
+ if (is >> c) {
+ if (c != ',') is.putback(c);
+ } else {
+ is.clear();
+ }
+ if (!(is >> z.y)) return is;
+ if (is >> c) {
+ if (c != ')') is.putback(c);
+ } else {
+ is.clear();
+ }
+ return is;
+ }
+
+ ///Write a plain vector to a stream
+
+ ///Write a plain vector to a stream.
+ ///\relates Point
+ ///
+ template<typename T>
+ inline std::ostream& operator<<(std::ostream &os, const Point<T>& z)
+ {
+ os << "(" << z.x << "," << z.y << ")";
+ return os;
+ }
+
+ ///Rotate by 90 degrees
+
+ ///Returns the parameter rotated by 90 degrees in positive direction.
+ ///\relates Point
+ ///
+ template<typename T>
+ inline Point<T> rot90(const Point<T> &z)
+ {
+ return Point<T>(-z.y,z.x);
+ }
+
+ ///Rotate by 180 degrees
+
+ ///Returns the parameter rotated by 180 degrees.
+ ///\relates Point
+ ///
+ template<typename T>
+ inline Point<T> rot180(const Point<T> &z)
+ {
+ return Point<T>(-z.x,-z.y);
+ }
+
+ ///Rotate by 270 degrees
+
+ ///Returns the parameter rotated by 90 degrees in negative direction.
+ ///\relates Point
+ ///
+ template<typename T>
+ inline Point<T> rot270(const Point<T> &z)
+ {
+ return Point<T>(z.y,-z.x);
+ }
+
+
+
+ /// Bounding box of plain vectors (points).
+
+ /// A class to calculate or store the bounding box of plain vectors
+ /// (\ref Point "points").
+ template<typename T>
+ class Box {
+ Point<T> _bottom_left, _top_right;
+ bool _empty;
+ public:
+
+ ///Default constructor: creates an empty box
+ Box() { _empty = true; }
+
+ ///Construct a box from one point
+ Box(Point<T> a) {
+ _bottom_left = _top_right = a;
+ _empty = false;
+ }
+
+ ///Construct a box from two points
+
+ ///Construct a box from two points.
+ ///\param a The bottom left corner.
+ ///\param b The top right corner.
+ ///\warning The coordinates of the bottom left corner must be no more
+ ///than those of the top right one.
+ Box(Point<T> a,Point<T> b)
+ {
+ _bottom_left = a;
+ _top_right = b;
+ _empty = false;
+ }
+
+ ///Construct a box from four numbers
+
+ ///Construct a box from four numbers.
+ ///\param l The left side of the box.
+ ///\param b The bottom of the box.
+ ///\param r The right side of the box.
+ ///\param t The top of the box.
+ ///\warning The left side must be no more than the right side and
+ ///bottom must be no more than the top.
+ Box(T l,T b,T r,T t)
+ {
+ _bottom_left=Point<T>(l,b);
+ _top_right=Point<T>(r,t);
+ _empty = false;
+ }
+
+ ///Return \c true if the box is empty.
+
+ ///Return \c true if the box is empty (i.e. return \c false
+ ///if at least one point was added to the box or the coordinates of
+ ///the box were set).
+ ///
+ ///The coordinates of an empty box are not defined.
+ bool empty() const {
+ return _empty;
+ }
+
+ ///Make the box empty
+ void clear() {
+ _empty = true;
+ }
+
+ ///Give back the bottom left corner of the box
+
+ ///Give back the bottom left corner of the box.
+ ///If the box is empty, then the return value is not defined.
+ Point<T> bottomLeft() const {
+ return _bottom_left;
+ }
+
+ ///Set the bottom left corner of the box
+
+ ///Set the bottom left corner of the box.
+ ///\pre The box must not be empty.
+ void bottomLeft(Point<T> p) {
+ _bottom_left = p;
+ }
+
+ ///Give back the top right corner of the box
+
+ ///Give back the top right corner of the box.
+ ///If the box is empty, then the return value is not defined.
+ Point<T> topRight() const {
+ return _top_right;
+ }
+
+ ///Set the top right corner of the box
+
+ ///Set the top right corner of the box.
+ ///\pre The box must not be empty.
+ void topRight(Point<T> p) {
+ _top_right = p;
+ }
+
+ ///Give back the bottom right corner of the box
+
+ ///Give back the bottom right corner of the box.
+ ///If the box is empty, then the return value is not defined.
+ Point<T> bottomRight() const {
+ return Point<T>(_top_right.x,_bottom_left.y);
+ }
+
+ ///Set the bottom right corner of the box
+
+ ///Set the bottom right corner of the box.
+ ///\pre The box must not be empty.
+ void bottomRight(Point<T> p) {
+ _top_right.x = p.x;
+ _bottom_left.y = p.y;
+ }
+
+ ///Give back the top left corner of the box
+
+ ///Give back the top left corner of the box.
+ ///If the box is empty, then the return value is not defined.
+ Point<T> topLeft() const {
+ return Point<T>(_bottom_left.x,_top_right.y);
+ }
+
+ ///Set the top left corner of the box
+
+ ///Set the top left corner of the box.
+ ///\pre The box must not be empty.
+ void topLeft(Point<T> p) {
+ _top_right.y = p.y;
+ _bottom_left.x = p.x;
+ }
+
+ ///Give back the bottom of the box
+
+ ///Give back the bottom of the box.
+ ///If the box is empty, then the return value is not defined.
+ T bottom() const {
+ return _bottom_left.y;
+ }
+
+ ///Set the bottom of the box
+
+ ///Set the bottom of the box.
+ ///\pre The box must not be empty.
+ void bottom(T t) {
+ _bottom_left.y = t;
+ }
+
+ ///Give back the top of the box
+
+ ///Give back the top of the box.
+ ///If the box is empty, then the return value is not defined.
+ T top() const {
+ return _top_right.y;
+ }
+
+ ///Set the top of the box
+
+ ///Set the top of the box.
+ ///\pre The box must not be empty.
+ void top(T t) {
+ _top_right.y = t;
+ }
+
+ ///Give back the left side of the box
+
+ ///Give back the left side of the box.
+ ///If the box is empty, then the return value is not defined.
+ T left() const {
+ return _bottom_left.x;
+ }
+
+ ///Set the left side of the box
+
+ ///Set the left side of the box.
+ ///\pre The box must not be empty.
+ void left(T t) {
+ _bottom_left.x = t;
+ }
+
+ /// Give back the right side of the box
+
+ /// Give back the right side of the box.
+ ///If the box is empty, then the return value is not defined.
+ T right() const {
+ return _top_right.x;
+ }
+
+ ///Set the right side of the box
+
+ ///Set the right side of the box.
+ ///\pre The box must not be empty.
+ void right(T t) {
+ _top_right.x = t;
+ }
+
+ ///Give back the height of the box
+
+ ///Give back the height of the box.
+ ///If the box is empty, then the return value is not defined.
+ T height() const {
+ return _top_right.y-_bottom_left.y;
+ }
+
+ ///Give back the width of the box
+
+ ///Give back the width of the box.
+ ///If the box is empty, then the return value is not defined.
+ T width() const {
+ return _top_right.x-_bottom_left.x;
+ }
+
+ ///Checks whether a point is inside the box
+ bool inside(const Point<T>& u) const {
+ if (_empty)
+ return false;
+ else {
+ return ( (u.x-_bottom_left.x)*(_top_right.x-u.x) >= 0 &&
+ (u.y-_bottom_left.y)*(_top_right.y-u.y) >= 0 );
+ }
+ }
+
+ ///Increments the box with a point
+
+ ///Increments the box with a point.
+ ///
+ Box& add(const Point<T>& u){
+ if (_empty) {
+ _bottom_left = _top_right = u;
+ _empty = false;
+ }
+ else {
+ if (_bottom_left.x > u.x) _bottom_left.x = u.x;
+ if (_bottom_left.y > u.y) _bottom_left.y = u.y;
+ if (_top_right.x < u.x) _top_right.x = u.x;
+ if (_top_right.y < u.y) _top_right.y = u.y;
+ }
+ return *this;
+ }
+
+ ///Increments the box to contain another box
+
+ ///Increments the box to contain another box.
+ ///
+ Box& add(const Box &u){
+ if ( !u.empty() ){
+ add(u._bottom_left);
+ add(u._top_right);
+ }
+ return *this;
+ }
+
+ ///Intersection of two boxes
+
+ ///Intersection of two boxes.
+ ///
+ Box operator&(const Box& u) const {
+ Box b;
+ if (_empty || u._empty) {
+ b._empty = true;
+ } else {
+ b._bottom_left.x = std::max(_bottom_left.x, u._bottom_left.x);
+ b._bottom_left.y = std::max(_bottom_left.y, u._bottom_left.y);
+ b._top_right.x = std::min(_top_right.x, u._top_right.x);
+ b._top_right.y = std::min(_top_right.y, u._top_right.y);
+ b._empty = b._bottom_left.x > b._top_right.x ||
+ b._bottom_left.y > b._top_right.y;
+ }
+ return b;
+ }
+
+ };//class Box
+
+
+ ///Read a box from a stream
+
+ ///Read a box from a stream.
+ ///\relates Box
+ template<typename T>
+ inline std::istream& operator>>(std::istream &is, Box<T>& b) {
+ char c;
+ Point<T> p;
+ if (is >> c) {
+ if (c != '(') is.putback(c);
+ } else {
+ is.clear();
+ }
+ if (!(is >> p)) return is;
+ b.bottomLeft(p);
+ if (is >> c) {
+ if (c != ',') is.putback(c);
+ } else {
+ is.clear();
+ }
+ if (!(is >> p)) return is;
+ b.topRight(p);
+ if (is >> c) {
+ if (c != ')') is.putback(c);
+ } else {
+ is.clear();
+ }
+ return is;
+ }
+
+ ///Write a box to a stream
+
+ ///Write a box to a stream.
+ ///\relates Box
+ template<typename T>
+ inline std::ostream& operator<<(std::ostream &os, const Box<T>& b)
+ {
+ os << "(" << b.bottomLeft() << "," << b.topRight() << ")";
+ return os;
+ }
+
+ ///Map of x-coordinates of a <tt>Point</tt>-map
+
+ ///Map of x-coordinates of a \ref Point "Point"-map.
+ ///
+ template<class M>
+ class XMap
+ {
+ M& _map;
+ public:
+
+ typedef typename M::Value::Value Value;
+ typedef typename M::Key Key;
+ ///\e
+ XMap(M& map) : _map(map) {}
+ Value operator[](Key k) const {return _map[k].x;}
+ void set(Key k,Value v) {_map.set(k,typename M::Value(v,_map[k].y));}
+ };
+
+ ///Returns an XMap class
+
+ ///This function just returns an XMap class.
+ ///\relates XMap
+ template<class M>
+ inline XMap<M> xMap(M &m)
+ {
+ return XMap<M>(m);
+ }
+
+ template<class M>
+ inline XMap<M> xMap(const M &m)
+ {
+ return XMap<M>(m);
+ }
+
+ ///Constant (read only) version of XMap
+
+ ///Constant (read only) version of XMap.
+ ///
+ template<class M>
+ class ConstXMap
+ {
+ const M& _map;
+ public:
+
+ typedef typename M::Value::Value Value;
+ typedef typename M::Key Key;
+ ///\e
+ ConstXMap(const M &map) : _map(map) {}
+ Value operator[](Key k) const {return _map[k].x;}
+ };
+
+ ///Returns a ConstXMap class
+
+ ///This function just returns a ConstXMap class.
+ ///\relates ConstXMap
+ template<class M>
+ inline ConstXMap<M> xMap(const M &m)
+ {
+ return ConstXMap<M>(m);
+ }
+
+ ///Map of y-coordinates of a <tt>Point</tt>-map
+
+ ///Map of y-coordinates of a \ref Point "Point"-map.
+ ///
+ template<class M>
+ class YMap
+ {
+ M& _map;
+ public:
+
+ typedef typename M::Value::Value Value;
+ typedef typename M::Key Key;
+ ///\e
+ YMap(M& map) : _map(map) {}
+ Value operator[](Key k) const {return _map[k].y;}
+ void set(Key k,Value v) {_map.set(k,typename M::Value(_map[k].x,v));}
+ };
+
+ ///Returns a YMap class
+
+ ///This function just returns a YMap class.
+ ///\relates YMap
+ template<class M>
+ inline YMap<M> yMap(M &m)
+ {
+ return YMap<M>(m);
+ }
+
+ template<class M>
+ inline YMap<M> yMap(const M &m)
+ {
+ return YMap<M>(m);
+ }
+
+ ///Constant (read only) version of YMap
+
+ ///Constant (read only) version of YMap.
+ ///
+ template<class M>
+ class ConstYMap
+ {
+ const M& _map;
+ public:
+
+ typedef typename M::Value::Value Value;
+ typedef typename M::Key Key;
+ ///\e
+ ConstYMap(const M &map) : _map(map) {}
+ Value operator[](Key k) const {return _map[k].y;}
+ };
+
+ ///Returns a ConstYMap class
+
+ ///This function just returns a ConstYMap class.
+ ///\relates ConstYMap
+ template<class M>
+ inline ConstYMap<M> yMap(const M &m)
+ {
+ return ConstYMap<M>(m);
+ }
+
+
+ ///\brief Map of the normSquare() of a <tt>Point</tt>-map
+ ///
+ ///Map of the \ref Point::normSquare() "normSquare()"
+ ///of a \ref Point "Point"-map.
+ template<class M>
+ class NormSquareMap
+ {
+ const M& _map;
+ public:
+
+ typedef typename M::Value::Value Value;
+ typedef typename M::Key Key;
+ ///\e
+ NormSquareMap(const M &map) : _map(map) {}
+ Value operator[](Key k) const {return _map[k].normSquare();}
+ };
+
+ ///Returns a NormSquareMap class
+
+ ///This function just returns a NormSquareMap class.
+ ///\relates NormSquareMap
+ template<class M>
+ inline NormSquareMap<M> normSquareMap(const M &m)
+ {
+ return NormSquareMap<M>(m);
+ }
+
+ /// @}
+
+ } //namespce dim2
+
+} //namespace lemon
+
+#endif //LEMON_DIM2_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/dimacs.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/dimacs.h
new file mode 100644
index 00000000000..616879ffa5e
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/dimacs.h
@@ -0,0 +1,448 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_DIMACS_H
+#define LEMON_DIMACS_H
+
+#include <iostream>
+#include <string>
+#include <vector>
+#include <limits>
+#include <lemon/maps.h>
+#include <lemon/error.h>
+/// \ingroup dimacs_group
+/// \file
+/// \brief DIMACS file format reader.
+
+namespace lemon {
+
+ /// \addtogroup dimacs_group
+ /// @{
+
+ /// DIMACS file type descriptor.
+ struct DimacsDescriptor
+ {
+ ///\brief DIMACS file type enum
+ ///
+ ///DIMACS file type enum.
+ enum Type {
+ NONE, ///< Undefined type.
+ MIN, ///< DIMACS file type for minimum cost flow problems.
+ MAX, ///< DIMACS file type for maximum flow problems.
+ SP, ///< DIMACS file type for shostest path problems.
+ MAT ///< DIMACS file type for plain graphs and matching problems.
+ };
+ ///The file type
+ Type type;
+ ///The number of nodes in the graph
+ int nodeNum;
+ ///The number of edges in the graph
+ int edgeNum;
+ int lineShift;
+ ///Constructor. It sets the type to \c NONE.
+ DimacsDescriptor() : type(NONE) {}
+ };
+
+ ///Discover the type of a DIMACS file
+
+ ///This function starts seeking the beginning of the given file for the
+ ///problem type and size info.
+ ///The found data is returned in a special struct that can be evaluated
+ ///and passed to the appropriate reader function.
+ DimacsDescriptor dimacsType(std::istream& is)
+ {
+ DimacsDescriptor r;
+ std::string problem,str;
+ char c;
+ r.lineShift=0;
+ while (is >> c)
+ switch(c)
+ {
+ case 'p':
+ if(is >> problem >> r.nodeNum >> r.edgeNum)
+ {
+ getline(is, str);
+ r.lineShift++;
+ if(problem=="min") r.type=DimacsDescriptor::MIN;
+ else if(problem=="max") r.type=DimacsDescriptor::MAX;
+ else if(problem=="sp") r.type=DimacsDescriptor::SP;
+ else if(problem=="mat") r.type=DimacsDescriptor::MAT;
+ else throw FormatError("Unknown problem type");
+ return r;
+ }
+ else
+ {
+ throw FormatError("Missing or wrong problem type declaration.");
+ }
+ break;
+ case 'c':
+ getline(is, str);
+ r.lineShift++;
+ break;
+ default:
+ throw FormatError("Unknown DIMACS declaration.");
+ }
+ throw FormatError("Missing problem type declaration.");
+ }
+
+
+ /// \brief DIMACS minimum cost flow reader function.
+ ///
+ /// This function reads a minimum cost flow instance from DIMACS format,
+ /// i.e. from a DIMACS file having a line starting with
+ /// \code
+ /// p min
+ /// \endcode
+ /// At the beginning, \c g is cleared by \c g.clear(). The supply
+ /// amount of the nodes are written to the \c supply node map
+ /// (they are signed values). The lower bounds, capacities and costs
+ /// of the arcs are written to the \c lower, \c capacity and \c cost
+ /// arc maps.
+ ///
+ /// If the capacity of an arc is less than the lower bound, it will
+ /// be set to "infinite" instead. The actual value of "infinite" is
+ /// contolled by the \c infty parameter. If it is 0 (the default value),
+ /// \c std::numeric_limits<Capacity>::infinity() will be used if available,
+ /// \c std::numeric_limits<Capacity>::max() otherwise. If \c infty is set to
+ /// a non-zero value, that value will be used as "infinite".
+ ///
+ /// If the file type was previously evaluated by dimacsType(), then
+ /// the descriptor struct should be given by the \c dest parameter.
+ template <typename Digraph, typename LowerMap,
+ typename CapacityMap, typename CostMap,
+ typename SupplyMap>
+ void readDimacsMin(std::istream& is,
+ Digraph &g,
+ LowerMap& lower,
+ CapacityMap& capacity,
+ CostMap& cost,
+ SupplyMap& supply,
+ typename CapacityMap::Value infty = 0,
+ DimacsDescriptor desc=DimacsDescriptor())
+ {
+ g.clear();
+ std::vector<typename Digraph::Node> nodes;
+ typename Digraph::Arc e;
+ std::string problem, str;
+ char c;
+ int i, j;
+ if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is);
+ if(desc.type!=DimacsDescriptor::MIN)
+ throw FormatError("Problem type mismatch");
+
+ nodes.resize(desc.nodeNum + 1);
+ for (int k = 1; k <= desc.nodeNum; ++k) {
+ nodes[k] = g.addNode();
+ supply.set(nodes[k], 0);
+ }
+
+ typename SupplyMap::Value sup;
+ typename CapacityMap::Value low;
+ typename CapacityMap::Value cap;
+ typename CostMap::Value co;
+ typedef typename CapacityMap::Value Capacity;
+ if(infty==0)
+ infty = std::numeric_limits<Capacity>::has_infinity ?
+ std::numeric_limits<Capacity>::infinity() :
+ std::numeric_limits<Capacity>::max();
+
+ while (is >> c) {
+ switch (c) {
+ case 'c': // comment line
+ getline(is, str);
+ break;
+ case 'n': // node definition line
+ is >> i >> sup;
+ getline(is, str);
+ supply.set(nodes[i], sup);
+ break;
+ case 'a': // arc definition line
+ is >> i >> j >> low >> cap >> co;
+ getline(is, str);
+ e = g.addArc(nodes[i], nodes[j]);
+ lower.set(e, low);
+ if (cap >= low)
+ capacity.set(e, cap);
+ else
+ capacity.set(e, infty);
+ cost.set(e, co);
+ break;
+ }
+ }
+ }
+
+ template<typename Digraph, typename CapacityMap>
+ void _readDimacs(std::istream& is,
+ Digraph &g,
+ CapacityMap& capacity,
+ typename Digraph::Node &s,
+ typename Digraph::Node &t,
+ typename CapacityMap::Value infty = 0,
+ DimacsDescriptor desc=DimacsDescriptor()) {
+ g.clear();
+ s=t=INVALID;
+ std::vector<typename Digraph::Node> nodes;
+ typename Digraph::Arc e;
+ char c, d;
+ int i, j;
+ typename CapacityMap::Value _cap;
+ std::string str;
+ nodes.resize(desc.nodeNum + 1);
+ for (int k = 1; k <= desc.nodeNum; ++k) {
+ nodes[k] = g.addNode();
+ }
+ typedef typename CapacityMap::Value Capacity;
+
+ if(infty==0)
+ infty = std::numeric_limits<Capacity>::has_infinity ?
+ std::numeric_limits<Capacity>::infinity() :
+ std::numeric_limits<Capacity>::max();
+
+ while (is >> c) {
+ switch (c) {
+ case 'c': // comment line
+ getline(is, str);
+ break;
+ case 'n': // node definition line
+ if (desc.type==DimacsDescriptor::SP) { // shortest path problem
+ is >> i;
+ getline(is, str);
+ s = nodes[i];
+ }
+ if (desc.type==DimacsDescriptor::MAX) { // max flow problem
+ is >> i >> d;
+ getline(is, str);
+ if (d == 's') s = nodes[i];
+ if (d == 't') t = nodes[i];
+ }
+ break;
+ case 'a': // arc definition line
+ if (desc.type==DimacsDescriptor::SP) {
+ is >> i >> j >> _cap;
+ getline(is, str);
+ e = g.addArc(nodes[i], nodes[j]);
+ capacity.set(e, _cap);
+ }
+ else if (desc.type==DimacsDescriptor::MAX) {
+ is >> i >> j >> _cap;
+ getline(is, str);
+ e = g.addArc(nodes[i], nodes[j]);
+ if (_cap >= 0)
+ capacity.set(e, _cap);
+ else
+ capacity.set(e, infty);
+ }
+ else {
+ is >> i >> j;
+ getline(is, str);
+ g.addArc(nodes[i], nodes[j]);
+ }
+ break;
+ }
+ }
+ }
+
+ /// \brief DIMACS maximum flow reader function.
+ ///
+ /// This function reads a maximum flow instance from DIMACS format,
+ /// i.e. from a DIMACS file having a line starting with
+ /// \code
+ /// p max
+ /// \endcode
+ /// At the beginning, \c g is cleared by \c g.clear(). The arc
+ /// capacities are written to the \c capacity arc map and \c s and
+ /// \c t are set to the source and the target nodes.
+ ///
+ /// If the capacity of an arc is negative, it will
+ /// be set to "infinite" instead. The actual value of "infinite" is
+ /// contolled by the \c infty parameter. If it is 0 (the default value),
+ /// \c std::numeric_limits<Capacity>::infinity() will be used if available,
+ /// \c std::numeric_limits<Capacity>::max() otherwise. If \c infty is set to
+ /// a non-zero value, that value will be used as "infinite".
+ ///
+ /// If the file type was previously evaluated by dimacsType(), then
+ /// the descriptor struct should be given by the \c dest parameter.
+ template<typename Digraph, typename CapacityMap>
+ void readDimacsMax(std::istream& is,
+ Digraph &g,
+ CapacityMap& capacity,
+ typename Digraph::Node &s,
+ typename Digraph::Node &t,
+ typename CapacityMap::Value infty = 0,
+ DimacsDescriptor desc=DimacsDescriptor()) {
+ if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is);
+ if(desc.type!=DimacsDescriptor::MAX)
+ throw FormatError("Problem type mismatch");
+ _readDimacs(is,g,capacity,s,t,infty,desc);
+ }
+
+ /// \brief DIMACS shortest path reader function.
+ ///
+ /// This function reads a shortest path instance from DIMACS format,
+ /// i.e. from a DIMACS file having a line starting with
+ /// \code
+ /// p sp
+ /// \endcode
+ /// At the beginning, \c g is cleared by \c g.clear(). The arc
+ /// lengths are written to the \c length arc map and \c s is set to the
+ /// source node.
+ ///
+ /// If the file type was previously evaluated by dimacsType(), then
+ /// the descriptor struct should be given by the \c dest parameter.
+ template<typename Digraph, typename LengthMap>
+ void readDimacsSp(std::istream& is,
+ Digraph &g,
+ LengthMap& length,
+ typename Digraph::Node &s,
+ DimacsDescriptor desc=DimacsDescriptor()) {
+ typename Digraph::Node t;
+ if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is);
+ if(desc.type!=DimacsDescriptor::SP)
+ throw FormatError("Problem type mismatch");
+ _readDimacs(is, g, length, s, t, 0, desc);
+ }
+
+ /// \brief DIMACS capacitated digraph reader function.
+ ///
+ /// This function reads an arc capacitated digraph instance from
+ /// DIMACS 'max' or 'sp' format.
+ /// At the beginning, \c g is cleared by \c g.clear()
+ /// and the arc capacities/lengths are written to the \c capacity
+ /// arc map.
+ ///
+ /// In case of the 'max' format, if the capacity of an arc is negative,
+ /// it will
+ /// be set to "infinite" instead. The actual value of "infinite" is
+ /// contolled by the \c infty parameter. If it is 0 (the default value),
+ /// \c std::numeric_limits<Capacity>::infinity() will be used if available,
+ /// \c std::numeric_limits<Capacity>::max() otherwise. If \c infty is set to
+ /// a non-zero value, that value will be used as "infinite".
+ ///
+ /// If the file type was previously evaluated by dimacsType(), then
+ /// the descriptor struct should be given by the \c dest parameter.
+ template<typename Digraph, typename CapacityMap>
+ void readDimacsCap(std::istream& is,
+ Digraph &g,
+ CapacityMap& capacity,
+ typename CapacityMap::Value infty = 0,
+ DimacsDescriptor desc=DimacsDescriptor()) {
+ typename Digraph::Node u,v;
+ if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is);
+ if(desc.type!=DimacsDescriptor::MAX || desc.type!=DimacsDescriptor::SP)
+ throw FormatError("Problem type mismatch");
+ _readDimacs(is, g, capacity, u, v, infty, desc);
+ }
+
+ template<typename Graph>
+ typename enable_if<lemon::UndirectedTagIndicator<Graph>,void>::type
+ _addArcEdge(Graph &g, typename Graph::Node s, typename Graph::Node t,
+ dummy<0> = 0)
+ {
+ g.addEdge(s,t);
+ }
+ template<typename Graph>
+ typename disable_if<lemon::UndirectedTagIndicator<Graph>,void>::type
+ _addArcEdge(Graph &g, typename Graph::Node s, typename Graph::Node t,
+ dummy<1> = 1)
+ {
+ g.addArc(s,t);
+ }
+
+ /// \brief DIMACS plain (di)graph reader function.
+ ///
+ /// This function reads a plain (di)graph without any designated nodes
+ /// and maps (e.g. a matching instance) from DIMACS format, i.e. from
+ /// DIMACS files having a line starting with
+ /// \code
+ /// p mat
+ /// \endcode
+ /// At the beginning, \c g is cleared by \c g.clear().
+ ///
+ /// If the file type was previously evaluated by dimacsType(), then
+ /// the descriptor struct should be given by the \c dest parameter.
+ template<typename Graph>
+ void readDimacsMat(std::istream& is, Graph &g,
+ DimacsDescriptor desc=DimacsDescriptor())
+ {
+ if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is);
+ if(desc.type!=DimacsDescriptor::MAT)
+ throw FormatError("Problem type mismatch");
+
+ g.clear();
+ std::vector<typename Graph::Node> nodes;
+ char c;
+ int i, j;
+ std::string str;
+ nodes.resize(desc.nodeNum + 1);
+ for (int k = 1; k <= desc.nodeNum; ++k) {
+ nodes[k] = g.addNode();
+ }
+
+ while (is >> c) {
+ switch (c) {
+ case 'c': // comment line
+ getline(is, str);
+ break;
+ case 'n': // node definition line
+ break;
+ case 'a': // arc definition line
+ is >> i >> j;
+ getline(is, str);
+ _addArcEdge(g,nodes[i], nodes[j]);
+ break;
+ }
+ }
+ }
+
+ /// DIMACS plain digraph writer function.
+ ///
+ /// This function writes a digraph without any designated nodes and
+ /// maps into DIMACS format, i.e. into DIMACS file having a line
+ /// starting with
+ /// \code
+ /// p mat
+ /// \endcode
+ /// If \c comment is not empty, then it will be printed in the first line
+ /// prefixed by 'c'.
+ template<typename Digraph>
+ void writeDimacsMat(std::ostream& os, const Digraph &g,
+ std::string comment="") {
+ typedef typename Digraph::NodeIt NodeIt;
+ typedef typename Digraph::ArcIt ArcIt;
+
+ if(!comment.empty())
+ os << "c " << comment << std::endl;
+ os << "p mat " << g.nodeNum() << " " << g.arcNum() << std::endl;
+
+ typename Digraph::template NodeMap<int> nodes(g);
+ int i = 1;
+ for(NodeIt v(g); v != INVALID; ++v) {
+ nodes.set(v, i);
+ ++i;
+ }
+ for(ArcIt e(g); e != INVALID; ++e) {
+ os << "a " << nodes[g.source(e)] << " " << nodes[g.target(e)]
+ << std::endl;
+ }
+ }
+
+ /// @}
+
+} //namespace lemon
+
+#endif //LEMON_DIMACS_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/edge_set.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/edge_set.h
new file mode 100644
index 00000000000..399b7a266f0
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/edge_set.h
@@ -0,0 +1,1420 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_EDGE_SET_H
+#define LEMON_EDGE_SET_H
+
+#include <lemon/core.h>
+#include <lemon/bits/edge_set_extender.h>
+
+/// \ingroup graphs
+/// \file
+/// \brief ArcSet and EdgeSet classes.
+///
+/// Graphs which use another graph's node-set as own.
+namespace lemon {
+
+ template <typename GR>
+ class ListArcSetBase {
+ public:
+
+ typedef typename GR::Node Node;
+ typedef typename GR::NodeIt NodeIt;
+
+ protected:
+
+ struct NodeT {
+ int first_out, first_in;
+ NodeT() : first_out(-1), first_in(-1) {}
+ };
+
+ typedef typename ItemSetTraits<GR, Node>::
+ template Map<NodeT>::Type NodesImplBase;
+
+ NodesImplBase* _nodes;
+
+ struct ArcT {
+ Node source, target;
+ int next_out, next_in;
+ int prev_out, prev_in;
+ ArcT() : prev_out(-1), prev_in(-1) {}
+ };
+
+ std::vector<ArcT> arcs;
+
+ int first_arc;
+ int first_free_arc;
+
+ const GR* _graph;
+
+ void initalize(const GR& graph, NodesImplBase& nodes) {
+ _graph = &graph;
+ _nodes = &nodes;
+ }
+
+ public:
+
+ class Arc {
+ friend class ListArcSetBase<GR>;
+ protected:
+ Arc(int _id) : id(_id) {}
+ int id;
+ public:
+ Arc() {}
+ Arc(Invalid) : id(-1) {}
+ bool operator==(const Arc& arc) const { return id == arc.id; }
+ bool operator!=(const Arc& arc) const { return id != arc.id; }
+ bool operator<(const Arc& arc) const { return id < arc.id; }
+ };
+
+ ListArcSetBase() : first_arc(-1), first_free_arc(-1) {}
+
+ Node addNode() {
+ LEMON_ASSERT(false,
+ "This graph structure does not support node insertion");
+ return INVALID; // avoid warning
+ }
+
+ Arc addArc(const Node& u, const Node& v) {
+ int n;
+ if (first_free_arc == -1) {
+ n = arcs.size();
+ arcs.push_back(ArcT());
+ } else {
+ n = first_free_arc;
+ first_free_arc = arcs[first_free_arc].next_in;
+ }
+ arcs[n].next_in = (*_nodes)[v].first_in;
+ if ((*_nodes)[v].first_in != -1) {
+ arcs[(*_nodes)[v].first_in].prev_in = n;
+ }
+ (*_nodes)[v].first_in = n;
+ arcs[n].next_out = (*_nodes)[u].first_out;
+ if ((*_nodes)[u].first_out != -1) {
+ arcs[(*_nodes)[u].first_out].prev_out = n;
+ }
+ (*_nodes)[u].first_out = n;
+ arcs[n].source = u;
+ arcs[n].target = v;
+ return Arc(n);
+ }
+
+ void erase(const Arc& arc) {
+ int n = arc.id;
+ if (arcs[n].prev_in != -1) {
+ arcs[arcs[n].prev_in].next_in = arcs[n].next_in;
+ } else {
+ (*_nodes)[arcs[n].target].first_in = arcs[n].next_in;
+ }
+ if (arcs[n].next_in != -1) {
+ arcs[arcs[n].next_in].prev_in = arcs[n].prev_in;
+ }
+
+ if (arcs[n].prev_out != -1) {
+ arcs[arcs[n].prev_out].next_out = arcs[n].next_out;
+ } else {
+ (*_nodes)[arcs[n].source].first_out = arcs[n].next_out;
+ }
+ if (arcs[n].next_out != -1) {
+ arcs[arcs[n].next_out].prev_out = arcs[n].prev_out;
+ }
+
+ }
+
+ void clear() {
+ Node node;
+ for (first(node); node != INVALID; next(node)) {
+ (*_nodes)[node].first_in = -1;
+ (*_nodes)[node].first_out = -1;
+ }
+ arcs.clear();
+ first_arc = -1;
+ first_free_arc = -1;
+ }
+
+ void first(Node& node) const {
+ _graph->first(node);
+ }
+
+ void next(Node& node) const {
+ _graph->next(node);
+ }
+
+ void first(Arc& arc) const {
+ Node node;
+ first(node);
+ while (node != INVALID && (*_nodes)[node].first_in == -1) {
+ next(node);
+ }
+ arc.id = (node == INVALID) ? -1 : (*_nodes)[node].first_in;
+ }
+
+ void next(Arc& arc) const {
+ if (arcs[arc.id].next_in != -1) {
+ arc.id = arcs[arc.id].next_in;
+ } else {
+ Node node = arcs[arc.id].target;
+ next(node);
+ while (node != INVALID && (*_nodes)[node].first_in == -1) {
+ next(node);
+ }
+ arc.id = (node == INVALID) ? -1 : (*_nodes)[node].first_in;
+ }
+ }
+
+ void firstOut(Arc& arc, const Node& node) const {
+ arc.id = (*_nodes)[node].first_out;
+ }
+
+ void nextOut(Arc& arc) const {
+ arc.id = arcs[arc.id].next_out;
+ }
+
+ void firstIn(Arc& arc, const Node& node) const {
+ arc.id = (*_nodes)[node].first_in;
+ }
+
+ void nextIn(Arc& arc) const {
+ arc.id = arcs[arc.id].next_in;
+ }
+
+ int id(const Node& node) const { return _graph->id(node); }
+ int id(const Arc& arc) const { return arc.id; }
+
+ Node nodeFromId(int ix) const { return _graph->nodeFromId(ix); }
+ Arc arcFromId(int ix) const { return Arc(ix); }
+
+ int maxNodeId() const { return _graph->maxNodeId(); };
+ int maxArcId() const { return arcs.size() - 1; }
+
+ Node source(const Arc& arc) const { return arcs[arc.id].source;}
+ Node target(const Arc& arc) const { return arcs[arc.id].target;}
+
+ typedef typename ItemSetTraits<GR, Node>::ItemNotifier NodeNotifier;
+
+ NodeNotifier& notifier(Node) const {
+ return _graph->notifier(Node());
+ }
+
+ template <typename V>
+ class NodeMap : public GR::template NodeMap<V> {
+ typedef typename GR::template NodeMap<V> Parent;
+
+ public:
+
+ explicit NodeMap(const ListArcSetBase<GR>& arcset)
+ : Parent(*arcset._graph) {}
+
+ NodeMap(const ListArcSetBase<GR>& arcset, const V& value)
+ : Parent(*arcset._graph, value) {}
+
+ NodeMap& operator=(const NodeMap& cmap) {
+ return operator=<NodeMap>(cmap);
+ }
+
+ template <typename CMap>
+ NodeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+ };
+
+ /// \ingroup graphs
+ ///
+ /// \brief Digraph using a node set of another digraph or graph and
+ /// an own arc set.
+ ///
+ /// This structure can be used to establish another directed graph
+ /// over a node set of an existing one. This class uses the same
+ /// Node type as the underlying graph, and each valid node of the
+ /// original graph is valid in this arc set, therefore the node
+ /// objects of the original graph can be used directly with this
+ /// class. The node handling functions (id handling, observing, and
+ /// iterators) works equivalently as in the original graph.
+ ///
+ /// This implementation is based on doubly-linked lists, from each
+ /// node the outgoing and the incoming arcs make up lists, therefore
+ /// one arc can be erased in constant time. It also makes possible,
+ /// that node can be removed from the underlying graph, in this case
+ /// all arcs incident to the given node is erased from the arc set.
+ ///
+ /// This class fully conforms to the \ref concepts::Digraph
+ /// "Digraph" concept.
+ /// It provides only linear time counting for nodes and arcs.
+ ///
+ /// \param GR The type of the graph which shares its node set with
+ /// this class. Its interface must conform to the
+ /// \ref concepts::Digraph "Digraph" or \ref concepts::Graph "Graph"
+ /// concept.
+ template <typename GR>
+ class ListArcSet : public ArcSetExtender<ListArcSetBase<GR> > {
+ typedef ArcSetExtender<ListArcSetBase<GR> > Parent;
+
+ public:
+
+ typedef typename Parent::Node Node;
+ typedef typename Parent::Arc Arc;
+
+ typedef typename Parent::NodesImplBase NodesImplBase;
+
+ void eraseNode(const Node& node) {
+ Arc arc;
+ Parent::firstOut(arc, node);
+ while (arc != INVALID ) {
+ erase(arc);
+ Parent::firstOut(arc, node);
+ }
+
+ Parent::firstIn(arc, node);
+ while (arc != INVALID ) {
+ erase(arc);
+ Parent::firstIn(arc, node);
+ }
+ }
+
+ void clearNodes() {
+ Parent::clear();
+ }
+
+ class NodesImpl : public NodesImplBase {
+ typedef NodesImplBase Parent;
+
+ public:
+ NodesImpl(const GR& graph, ListArcSet& arcset)
+ : Parent(graph), _arcset(arcset) {}
+
+ virtual ~NodesImpl() {}
+
+ protected:
+
+ virtual void erase(const Node& node) {
+ _arcset.eraseNode(node);
+ Parent::erase(node);
+ }
+ virtual void erase(const std::vector<Node>& nodes) {
+ for (int i = 0; i < int(nodes.size()); ++i) {
+ _arcset.eraseNode(nodes[i]);
+ }
+ Parent::erase(nodes);
+ }
+ virtual void clear() {
+ _arcset.clearNodes();
+ Parent::clear();
+ }
+
+ private:
+ ListArcSet& _arcset;
+ };
+
+ NodesImpl _nodes;
+
+ public:
+
+ /// \brief Constructor of the ArcSet.
+ ///
+ /// Constructor of the ArcSet.
+ ListArcSet(const GR& graph) : _nodes(graph, *this) {
+ Parent::initalize(graph, _nodes);
+ }
+
+ /// \brief Add a new arc to the digraph.
+ ///
+ /// Add a new arc to the digraph with source node \c s
+ /// and target node \c t.
+ /// \return The new arc.
+ Arc addArc(const Node& s, const Node& t) {
+ return Parent::addArc(s, t);
+ }
+
+ /// \brief Erase an arc from the digraph.
+ ///
+ /// Erase an arc \c a from the digraph.
+ void erase(const Arc& a) {
+ return Parent::erase(a);
+ }
+
+ };
+
+ template <typename GR>
+ class ListEdgeSetBase {
+ public:
+
+ typedef typename GR::Node Node;
+ typedef typename GR::NodeIt NodeIt;
+
+ protected:
+
+ struct NodeT {
+ int first_out;
+ NodeT() : first_out(-1) {}
+ };
+
+ typedef typename ItemSetTraits<GR, Node>::
+ template Map<NodeT>::Type NodesImplBase;
+
+ NodesImplBase* _nodes;
+
+ struct ArcT {
+ Node target;
+ int prev_out, next_out;
+ ArcT() : prev_out(-1), next_out(-1) {}
+ };
+
+ std::vector<ArcT> arcs;
+
+ int first_arc;
+ int first_free_arc;
+
+ const GR* _graph;
+
+ void initalize(const GR& graph, NodesImplBase& nodes) {
+ _graph = &graph;
+ _nodes = &nodes;
+ }
+
+ public:
+
+ class Edge {
+ friend class ListEdgeSetBase;
+ protected:
+
+ int id;
+ explicit Edge(int _id) { id = _id;}
+
+ public:
+ Edge() {}
+ Edge (Invalid) { id = -1; }
+ bool operator==(const Edge& arc) const {return id == arc.id;}
+ bool operator!=(const Edge& arc) const {return id != arc.id;}
+ bool operator<(const Edge& arc) const {return id < arc.id;}
+ };
+
+ class Arc {
+ friend class ListEdgeSetBase;
+ protected:
+ Arc(int _id) : id(_id) {}
+ int id;
+ public:
+ operator Edge() const { return edgeFromId(id / 2); }
+
+ Arc() {}
+ Arc(Invalid) : id(-1) {}
+ bool operator==(const Arc& arc) const { return id == arc.id; }
+ bool operator!=(const Arc& arc) const { return id != arc.id; }
+ bool operator<(const Arc& arc) const { return id < arc.id; }
+ };
+
+ ListEdgeSetBase() : first_arc(-1), first_free_arc(-1) {}
+
+ Node addNode() {
+ LEMON_ASSERT(false,
+ "This graph structure does not support node insertion");
+ return INVALID; // avoid warning
+ }
+
+ Edge addEdge(const Node& u, const Node& v) {
+ int n;
+
+ if (first_free_arc == -1) {
+ n = arcs.size();
+ arcs.push_back(ArcT());
+ arcs.push_back(ArcT());
+ } else {
+ n = first_free_arc;
+ first_free_arc = arcs[n].next_out;
+ }
+
+ arcs[n].target = u;
+ arcs[n | 1].target = v;
+
+ arcs[n].next_out = (*_nodes)[v].first_out;
+ if ((*_nodes)[v].first_out != -1) {
+ arcs[(*_nodes)[v].first_out].prev_out = n;
+ }
+ (*_nodes)[v].first_out = n;
+ arcs[n].prev_out = -1;
+
+ if ((*_nodes)[u].first_out != -1) {
+ arcs[(*_nodes)[u].first_out].prev_out = (n | 1);
+ }
+ arcs[n | 1].next_out = (*_nodes)[u].first_out;
+ (*_nodes)[u].first_out = (n | 1);
+ arcs[n | 1].prev_out = -1;
+
+ return Edge(n / 2);
+ }
+
+ void erase(const Edge& arc) {
+ int n = arc.id * 2;
+
+ if (arcs[n].next_out != -1) {
+ arcs[arcs[n].next_out].prev_out = arcs[n].prev_out;
+ }
+
+ if (arcs[n].prev_out != -1) {
+ arcs[arcs[n].prev_out].next_out = arcs[n].next_out;
+ } else {
+ (*_nodes)[arcs[n | 1].target].first_out = arcs[n].next_out;
+ }
+
+ if (arcs[n | 1].next_out != -1) {
+ arcs[arcs[n | 1].next_out].prev_out = arcs[n | 1].prev_out;
+ }
+
+ if (arcs[n | 1].prev_out != -1) {
+ arcs[arcs[n | 1].prev_out].next_out = arcs[n | 1].next_out;
+ } else {
+ (*_nodes)[arcs[n].target].first_out = arcs[n | 1].next_out;
+ }
+
+ arcs[n].next_out = first_free_arc;
+ first_free_arc = n;
+
+ }
+
+ void clear() {
+ Node node;
+ for (first(node); node != INVALID; next(node)) {
+ (*_nodes)[node].first_out = -1;
+ }
+ arcs.clear();
+ first_arc = -1;
+ first_free_arc = -1;
+ }
+
+ void first(Node& node) const {
+ _graph->first(node);
+ }
+
+ void next(Node& node) const {
+ _graph->next(node);
+ }
+
+ void first(Arc& arc) const {
+ Node node;
+ first(node);
+ while (node != INVALID && (*_nodes)[node].first_out == -1) {
+ next(node);
+ }
+ arc.id = (node == INVALID) ? -1 : (*_nodes)[node].first_out;
+ }
+
+ void next(Arc& arc) const {
+ if (arcs[arc.id].next_out != -1) {
+ arc.id = arcs[arc.id].next_out;
+ } else {
+ Node node = arcs[arc.id ^ 1].target;
+ next(node);
+ while(node != INVALID && (*_nodes)[node].first_out == -1) {
+ next(node);
+ }
+ arc.id = (node == INVALID) ? -1 : (*_nodes)[node].first_out;
+ }
+ }
+
+ void first(Edge& edge) const {
+ Node node;
+ first(node);
+ while (node != INVALID) {
+ edge.id = (*_nodes)[node].first_out;
+ while ((edge.id & 1) != 1) {
+ edge.id = arcs[edge.id].next_out;
+ }
+ if (edge.id != -1) {
+ edge.id /= 2;
+ return;
+ }
+ next(node);
+ }
+ edge.id = -1;
+ }
+
+ void next(Edge& edge) const {
+ Node node = arcs[edge.id * 2].target;
+ edge.id = arcs[(edge.id * 2) | 1].next_out;
+ while ((edge.id & 1) != 1) {
+ edge.id = arcs[edge.id].next_out;
+ }
+ if (edge.id != -1) {
+ edge.id /= 2;
+ return;
+ }
+ next(node);
+ while (node != INVALID) {
+ edge.id = (*_nodes)[node].first_out;
+ while ((edge.id & 1) != 1) {
+ edge.id = arcs[edge.id].next_out;
+ }
+ if (edge.id != -1) {
+ edge.id /= 2;
+ return;
+ }
+ next(node);
+ }
+ edge.id = -1;
+ }
+
+ void firstOut(Arc& arc, const Node& node) const {
+ arc.id = (*_nodes)[node].first_out;
+ }
+
+ void nextOut(Arc& arc) const {
+ arc.id = arcs[arc.id].next_out;
+ }
+
+ void firstIn(Arc& arc, const Node& node) const {
+ arc.id = (((*_nodes)[node].first_out) ^ 1);
+ if (arc.id == -2) arc.id = -1;
+ }
+
+ void nextIn(Arc& arc) const {
+ arc.id = ((arcs[arc.id ^ 1].next_out) ^ 1);
+ if (arc.id == -2) arc.id = -1;
+ }
+
+ void firstInc(Edge &arc, bool& dir, const Node& node) const {
+ int de = (*_nodes)[node].first_out;
+ if (de != -1 ) {
+ arc.id = de / 2;
+ dir = ((de & 1) == 1);
+ } else {
+ arc.id = -1;
+ dir = true;
+ }
+ }
+ void nextInc(Edge &arc, bool& dir) const {
+ int de = (arcs[(arc.id * 2) | (dir ? 1 : 0)].next_out);
+ if (de != -1 ) {
+ arc.id = de / 2;
+ dir = ((de & 1) == 1);
+ } else {
+ arc.id = -1;
+ dir = true;
+ }
+ }
+
+ static bool direction(Arc arc) {
+ return (arc.id & 1) == 1;
+ }
+
+ static Arc direct(Edge edge, bool dir) {
+ return Arc(edge.id * 2 + (dir ? 1 : 0));
+ }
+
+ int id(const Node& node) const { return _graph->id(node); }
+ static int id(Arc e) { return e.id; }
+ static int id(Edge e) { return e.id; }
+
+ Node nodeFromId(int id) const { return _graph->nodeFromId(id); }
+ static Arc arcFromId(int id) { return Arc(id);}
+ static Edge edgeFromId(int id) { return Edge(id);}
+
+ int maxNodeId() const { return _graph->maxNodeId(); };
+ int maxEdgeId() const { return arcs.size() / 2 - 1; }
+ int maxArcId() const { return arcs.size()-1; }
+
+ Node source(Arc e) const { return arcs[e.id ^ 1].target; }
+ Node target(Arc e) const { return arcs[e.id].target; }
+
+ Node u(Edge e) const { return arcs[2 * e.id].target; }
+ Node v(Edge e) const { return arcs[2 * e.id + 1].target; }
+
+ typedef typename ItemSetTraits<GR, Node>::ItemNotifier NodeNotifier;
+
+ NodeNotifier& notifier(Node) const {
+ return _graph->notifier(Node());
+ }
+
+ template <typename V>
+ class NodeMap : public GR::template NodeMap<V> {
+ typedef typename GR::template NodeMap<V> Parent;
+
+ public:
+
+ explicit NodeMap(const ListEdgeSetBase<GR>& arcset)
+ : Parent(*arcset._graph) {}
+
+ NodeMap(const ListEdgeSetBase<GR>& arcset, const V& value)
+ : Parent(*arcset._graph, value) {}
+
+ NodeMap& operator=(const NodeMap& cmap) {
+ return operator=<NodeMap>(cmap);
+ }
+
+ template <typename CMap>
+ NodeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+ };
+
+ /// \ingroup graphs
+ ///
+ /// \brief Graph using a node set of another digraph or graph and an
+ /// own edge set.
+ ///
+ /// This structure can be used to establish another graph over a
+ /// node set of an existing one. This class uses the same Node type
+ /// as the underlying graph, and each valid node of the original
+ /// graph is valid in this arc set, therefore the node objects of
+ /// the original graph can be used directly with this class. The
+ /// node handling functions (id handling, observing, and iterators)
+ /// works equivalently as in the original graph.
+ ///
+ /// This implementation is based on doubly-linked lists, from each
+ /// node the incident edges make up lists, therefore one edge can be
+ /// erased in constant time. It also makes possible, that node can
+ /// be removed from the underlying graph, in this case all edges
+ /// incident to the given node is erased from the arc set.
+ ///
+ /// This class fully conforms to the \ref concepts::Graph "Graph"
+ /// concept.
+ /// It provides only linear time counting for nodes, edges and arcs.
+ ///
+ /// \param GR The type of the graph which shares its node set
+ /// with this class. Its interface must conform to the
+ /// \ref concepts::Digraph "Digraph" or \ref concepts::Graph "Graph"
+ /// concept.
+ template <typename GR>
+ class ListEdgeSet : public EdgeSetExtender<ListEdgeSetBase<GR> > {
+ typedef EdgeSetExtender<ListEdgeSetBase<GR> > Parent;
+
+ public:
+
+ typedef typename Parent::Node Node;
+ typedef typename Parent::Arc Arc;
+ typedef typename Parent::Edge Edge;
+
+ typedef typename Parent::NodesImplBase NodesImplBase;
+
+ void eraseNode(const Node& node) {
+ Arc arc;
+ Parent::firstOut(arc, node);
+ while (arc != INVALID ) {
+ erase(arc);
+ Parent::firstOut(arc, node);
+ }
+
+ }
+
+ void clearNodes() {
+ Parent::clear();
+ }
+
+ class NodesImpl : public NodesImplBase {
+ typedef NodesImplBase Parent;
+
+ public:
+ NodesImpl(const GR& graph, ListEdgeSet& arcset)
+ : Parent(graph), _arcset(arcset) {}
+
+ virtual ~NodesImpl() {}
+
+ protected:
+
+ virtual void erase(const Node& node) {
+ _arcset.eraseNode(node);
+ Parent::erase(node);
+ }
+ virtual void erase(const std::vector<Node>& nodes) {
+ for (int i = 0; i < int(nodes.size()); ++i) {
+ _arcset.eraseNode(nodes[i]);
+ }
+ Parent::erase(nodes);
+ }
+ virtual void clear() {
+ _arcset.clearNodes();
+ Parent::clear();
+ }
+
+ private:
+ ListEdgeSet& _arcset;
+ };
+
+ NodesImpl _nodes;
+
+ public:
+
+ /// \brief Constructor of the EdgeSet.
+ ///
+ /// Constructor of the EdgeSet.
+ ListEdgeSet(const GR& graph) : _nodes(graph, *this) {
+ Parent::initalize(graph, _nodes);
+ }
+
+ /// \brief Add a new edge to the graph.
+ ///
+ /// Add a new edge to the graph with node \c u
+ /// and node \c v endpoints.
+ /// \return The new edge.
+ Edge addEdge(const Node& u, const Node& v) {
+ return Parent::addEdge(u, v);
+ }
+
+ /// \brief Erase an edge from the graph.
+ ///
+ /// Erase the edge \c e from the graph.
+ void erase(const Edge& e) {
+ return Parent::erase(e);
+ }
+
+ };
+
+ template <typename GR>
+ class SmartArcSetBase {
+ public:
+
+ typedef typename GR::Node Node;
+ typedef typename GR::NodeIt NodeIt;
+
+ protected:
+
+ struct NodeT {
+ int first_out, first_in;
+ NodeT() : first_out(-1), first_in(-1) {}
+ };
+
+ typedef typename ItemSetTraits<GR, Node>::
+ template Map<NodeT>::Type NodesImplBase;
+
+ NodesImplBase* _nodes;
+
+ struct ArcT {
+ Node source, target;
+ int next_out, next_in;
+ ArcT() {}
+ };
+
+ std::vector<ArcT> arcs;
+
+ const GR* _graph;
+
+ void initalize(const GR& graph, NodesImplBase& nodes) {
+ _graph = &graph;
+ _nodes = &nodes;
+ }
+
+ public:
+
+ class Arc {
+ friend class SmartArcSetBase<GR>;
+ protected:
+ Arc(int _id) : id(_id) {}
+ int id;
+ public:
+ Arc() {}
+ Arc(Invalid) : id(-1) {}
+ bool operator==(const Arc& arc) const { return id == arc.id; }
+ bool operator!=(const Arc& arc) const { return id != arc.id; }
+ bool operator<(const Arc& arc) const { return id < arc.id; }
+ };
+
+ SmartArcSetBase() {}
+
+ Node addNode() {
+ LEMON_ASSERT(false,
+ "This graph structure does not support node insertion");
+ return INVALID; // avoid warning
+ }
+
+ Arc addArc(const Node& u, const Node& v) {
+ int n = arcs.size();
+ arcs.push_back(ArcT());
+ arcs[n].next_in = (*_nodes)[v].first_in;
+ (*_nodes)[v].first_in = n;
+ arcs[n].next_out = (*_nodes)[u].first_out;
+ (*_nodes)[u].first_out = n;
+ arcs[n].source = u;
+ arcs[n].target = v;
+ return Arc(n);
+ }
+
+ void clear() {
+ Node node;
+ for (first(node); node != INVALID; next(node)) {
+ (*_nodes)[node].first_in = -1;
+ (*_nodes)[node].first_out = -1;
+ }
+ arcs.clear();
+ }
+
+ void first(Node& node) const {
+ _graph->first(node);
+ }
+
+ void next(Node& node) const {
+ _graph->next(node);
+ }
+
+ void first(Arc& arc) const {
+ arc.id = arcs.size() - 1;
+ }
+
+ static void next(Arc& arc) {
+ --arc.id;
+ }
+
+ void firstOut(Arc& arc, const Node& node) const {
+ arc.id = (*_nodes)[node].first_out;
+ }
+
+ void nextOut(Arc& arc) const {
+ arc.id = arcs[arc.id].next_out;
+ }
+
+ void firstIn(Arc& arc, const Node& node) const {
+ arc.id = (*_nodes)[node].first_in;
+ }
+
+ void nextIn(Arc& arc) const {
+ arc.id = arcs[arc.id].next_in;
+ }
+
+ int id(const Node& node) const { return _graph->id(node); }
+ int id(const Arc& arc) const { return arc.id; }
+
+ Node nodeFromId(int ix) const { return _graph->nodeFromId(ix); }
+ Arc arcFromId(int ix) const { return Arc(ix); }
+
+ int maxNodeId() const { return _graph->maxNodeId(); };
+ int maxArcId() const { return arcs.size() - 1; }
+
+ Node source(const Arc& arc) const { return arcs[arc.id].source;}
+ Node target(const Arc& arc) const { return arcs[arc.id].target;}
+
+ typedef typename ItemSetTraits<GR, Node>::ItemNotifier NodeNotifier;
+
+ NodeNotifier& notifier(Node) const {
+ return _graph->notifier(Node());
+ }
+
+ template <typename V>
+ class NodeMap : public GR::template NodeMap<V> {
+ typedef typename GR::template NodeMap<V> Parent;
+
+ public:
+
+ explicit NodeMap(const SmartArcSetBase<GR>& arcset)
+ : Parent(*arcset._graph) { }
+
+ NodeMap(const SmartArcSetBase<GR>& arcset, const V& value)
+ : Parent(*arcset._graph, value) { }
+
+ NodeMap& operator=(const NodeMap& cmap) {
+ return operator=<NodeMap>(cmap);
+ }
+
+ template <typename CMap>
+ NodeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+ };
+
+
+ /// \ingroup graphs
+ ///
+ /// \brief Digraph using a node set of another digraph or graph and
+ /// an own arc set.
+ ///
+ /// This structure can be used to establish another directed graph
+ /// over a node set of an existing one. This class uses the same
+ /// Node type as the underlying graph, and each valid node of the
+ /// original graph is valid in this arc set, therefore the node
+ /// objects of the original graph can be used directly with this
+ /// class. The node handling functions (id handling, observing, and
+ /// iterators) works equivalently as in the original graph.
+ ///
+ /// \param GR The type of the graph which shares its node set with
+ /// this class. Its interface must conform to the
+ /// \ref concepts::Digraph "Digraph" or \ref concepts::Graph "Graph"
+ /// concept.
+ ///
+ /// This implementation is slightly faster than the \c ListArcSet,
+ /// because it uses continuous storage for arcs and it uses just
+ /// single-linked lists for enumerate outgoing and incoming
+ /// arcs. Therefore the arcs cannot be erased from the arc sets.
+ ///
+ /// This class fully conforms to the \ref concepts::Digraph "Digraph"
+ /// concept.
+ /// It provides only linear time counting for nodes and arcs.
+ ///
+ /// \warning If a node is erased from the underlying graph and this
+ /// node is the source or target of one arc in the arc set, then
+ /// the arc set is invalidated, and it cannot be used anymore. The
+ /// validity can be checked with the \c valid() member function.
+ template <typename GR>
+ class SmartArcSet : public ArcSetExtender<SmartArcSetBase<GR> > {
+ typedef ArcSetExtender<SmartArcSetBase<GR> > Parent;
+
+ public:
+
+ typedef typename Parent::Node Node;
+ typedef typename Parent::Arc Arc;
+
+ protected:
+
+ typedef typename Parent::NodesImplBase NodesImplBase;
+
+ void eraseNode(const Node& node) {
+ if (typename Parent::InArcIt(*this, node) == INVALID &&
+ typename Parent::OutArcIt(*this, node) == INVALID) {
+ return;
+ }
+ throw typename NodesImplBase::Notifier::ImmediateDetach();
+ }
+
+ void clearNodes() {
+ Parent::clear();
+ }
+
+ class NodesImpl : public NodesImplBase {
+ typedef NodesImplBase Parent;
+
+ public:
+ NodesImpl(const GR& graph, SmartArcSet& arcset)
+ : Parent(graph), _arcset(arcset) {}
+
+ virtual ~NodesImpl() {}
+
+ bool attached() const {
+ return Parent::attached();
+ }
+
+ protected:
+
+ virtual void erase(const Node& node) {
+ try {
+ _arcset.eraseNode(node);
+ Parent::erase(node);
+ } catch (const typename NodesImplBase::Notifier::ImmediateDetach&) {
+ Parent::clear();
+ throw;
+ }
+ }
+ virtual void erase(const std::vector<Node>& nodes) {
+ try {
+ for (int i = 0; i < int(nodes.size()); ++i) {
+ _arcset.eraseNode(nodes[i]);
+ }
+ Parent::erase(nodes);
+ } catch (const typename NodesImplBase::Notifier::ImmediateDetach&) {
+ Parent::clear();
+ throw;
+ }
+ }
+ virtual void clear() {
+ _arcset.clearNodes();
+ Parent::clear();
+ }
+
+ private:
+ SmartArcSet& _arcset;
+ };
+
+ NodesImpl _nodes;
+
+ public:
+
+ /// \brief Constructor of the ArcSet.
+ ///
+ /// Constructor of the ArcSet.
+ SmartArcSet(const GR& graph) : _nodes(graph, *this) {
+ Parent::initalize(graph, _nodes);
+ }
+
+ /// \brief Add a new arc to the digraph.
+ ///
+ /// Add a new arc to the digraph with source node \c s
+ /// and target node \c t.
+ /// \return The new arc.
+ Arc addArc(const Node& s, const Node& t) {
+ return Parent::addArc(s, t);
+ }
+
+ /// \brief Validity check
+ ///
+ /// This functions gives back false if the ArcSet is
+ /// invalidated. It occurs when a node in the underlying graph is
+ /// erased and it is not isolated in the ArcSet.
+ bool valid() const {
+ return _nodes.attached();
+ }
+
+ };
+
+
+ template <typename GR>
+ class SmartEdgeSetBase {
+ public:
+
+ typedef typename GR::Node Node;
+ typedef typename GR::NodeIt NodeIt;
+
+ protected:
+
+ struct NodeT {
+ int first_out;
+ NodeT() : first_out(-1) {}
+ };
+
+ typedef typename ItemSetTraits<GR, Node>::
+ template Map<NodeT>::Type NodesImplBase;
+
+ NodesImplBase* _nodes;
+
+ struct ArcT {
+ Node target;
+ int next_out;
+ ArcT() {}
+ };
+
+ std::vector<ArcT> arcs;
+
+ const GR* _graph;
+
+ void initalize(const GR& graph, NodesImplBase& nodes) {
+ _graph = &graph;
+ _nodes = &nodes;
+ }
+
+ public:
+
+ class Edge {
+ friend class SmartEdgeSetBase;
+ protected:
+
+ int id;
+ explicit Edge(int _id) { id = _id;}
+
+ public:
+ Edge() {}
+ Edge (Invalid) { id = -1; }
+ bool operator==(const Edge& arc) const {return id == arc.id;}
+ bool operator!=(const Edge& arc) const {return id != arc.id;}
+ bool operator<(const Edge& arc) const {return id < arc.id;}
+ };
+
+ class Arc {
+ friend class SmartEdgeSetBase;
+ protected:
+ Arc(int _id) : id(_id) {}
+ int id;
+ public:
+ operator Edge() const { return edgeFromId(id / 2); }
+
+ Arc() {}
+ Arc(Invalid) : id(-1) {}
+ bool operator==(const Arc& arc) const { return id == arc.id; }
+ bool operator!=(const Arc& arc) const { return id != arc.id; }
+ bool operator<(const Arc& arc) const { return id < arc.id; }
+ };
+
+ SmartEdgeSetBase() {}
+
+ Node addNode() {
+ LEMON_ASSERT(false,
+ "This graph structure does not support node insertion");
+ return INVALID; // avoid warning
+ }
+
+ Edge addEdge(const Node& u, const Node& v) {
+ int n = arcs.size();
+ arcs.push_back(ArcT());
+ arcs.push_back(ArcT());
+
+ arcs[n].target = u;
+ arcs[n | 1].target = v;
+
+ arcs[n].next_out = (*_nodes)[v].first_out;
+ (*_nodes)[v].first_out = n;
+
+ arcs[n | 1].next_out = (*_nodes)[u].first_out;
+ (*_nodes)[u].first_out = (n | 1);
+
+ return Edge(n / 2);
+ }
+
+ void clear() {
+ Node node;
+ for (first(node); node != INVALID; next(node)) {
+ (*_nodes)[node].first_out = -1;
+ }
+ arcs.clear();
+ }
+
+ void first(Node& node) const {
+ _graph->first(node);
+ }
+
+ void next(Node& node) const {
+ _graph->next(node);
+ }
+
+ void first(Arc& arc) const {
+ arc.id = arcs.size() - 1;
+ }
+
+ static void next(Arc& arc) {
+ --arc.id;
+ }
+
+ void first(Edge& arc) const {
+ arc.id = arcs.size() / 2 - 1;
+ }
+
+ static void next(Edge& arc) {
+ --arc.id;
+ }
+
+ void firstOut(Arc& arc, const Node& node) const {
+ arc.id = (*_nodes)[node].first_out;
+ }
+
+ void nextOut(Arc& arc) const {
+ arc.id = arcs[arc.id].next_out;
+ }
+
+ void firstIn(Arc& arc, const Node& node) const {
+ arc.id = (((*_nodes)[node].first_out) ^ 1);
+ if (arc.id == -2) arc.id = -1;
+ }
+
+ void nextIn(Arc& arc) const {
+ arc.id = ((arcs[arc.id ^ 1].next_out) ^ 1);
+ if (arc.id == -2) arc.id = -1;
+ }
+
+ void firstInc(Edge &arc, bool& dir, const Node& node) const {
+ int de = (*_nodes)[node].first_out;
+ if (de != -1 ) {
+ arc.id = de / 2;
+ dir = ((de & 1) == 1);
+ } else {
+ arc.id = -1;
+ dir = true;
+ }
+ }
+ void nextInc(Edge &arc, bool& dir) const {
+ int de = (arcs[(arc.id * 2) | (dir ? 1 : 0)].next_out);
+ if (de != -1 ) {
+ arc.id = de / 2;
+ dir = ((de & 1) == 1);
+ } else {
+ arc.id = -1;
+ dir = true;
+ }
+ }
+
+ static bool direction(Arc arc) {
+ return (arc.id & 1) == 1;
+ }
+
+ static Arc direct(Edge edge, bool dir) {
+ return Arc(edge.id * 2 + (dir ? 1 : 0));
+ }
+
+ int id(Node node) const { return _graph->id(node); }
+ static int id(Arc arc) { return arc.id; }
+ static int id(Edge arc) { return arc.id; }
+
+ Node nodeFromId(int id) const { return _graph->nodeFromId(id); }
+ static Arc arcFromId(int id) { return Arc(id); }
+ static Edge edgeFromId(int id) { return Edge(id);}
+
+ int maxNodeId() const { return _graph->maxNodeId(); };
+ int maxArcId() const { return arcs.size() - 1; }
+ int maxEdgeId() const { return arcs.size() / 2 - 1; }
+
+ Node source(Arc e) const { return arcs[e.id ^ 1].target; }
+ Node target(Arc e) const { return arcs[e.id].target; }
+
+ Node u(Edge e) const { return arcs[2 * e.id].target; }
+ Node v(Edge e) const { return arcs[2 * e.id + 1].target; }
+
+ typedef typename ItemSetTraits<GR, Node>::ItemNotifier NodeNotifier;
+
+ NodeNotifier& notifier(Node) const {
+ return _graph->notifier(Node());
+ }
+
+ template <typename V>
+ class NodeMap : public GR::template NodeMap<V> {
+ typedef typename GR::template NodeMap<V> Parent;
+
+ public:
+
+ explicit NodeMap(const SmartEdgeSetBase<GR>& arcset)
+ : Parent(*arcset._graph) { }
+
+ NodeMap(const SmartEdgeSetBase<GR>& arcset, const V& value)
+ : Parent(*arcset._graph, value) { }
+
+ NodeMap& operator=(const NodeMap& cmap) {
+ return operator=<NodeMap>(cmap);
+ }
+
+ template <typename CMap>
+ NodeMap& operator=(const CMap& cmap) {
+ Parent::operator=(cmap);
+ return *this;
+ }
+ };
+
+ };
+
+ /// \ingroup graphs
+ ///
+ /// \brief Graph using a node set of another digraph or graph and an
+ /// own edge set.
+ ///
+ /// This structure can be used to establish another graph over a
+ /// node set of an existing one. This class uses the same Node type
+ /// as the underlying graph, and each valid node of the original
+ /// graph is valid in this arc set, therefore the node objects of
+ /// the original graph can be used directly with this class. The
+ /// node handling functions (id handling, observing, and iterators)
+ /// works equivalently as in the original graph.
+ ///
+ /// \param GR The type of the graph which shares its node set
+ /// with this class. Its interface must conform to the
+ /// \ref concepts::Digraph "Digraph" or \ref concepts::Graph "Graph"
+ /// concept.
+ ///
+ /// This implementation is slightly faster than the \c ListEdgeSet,
+ /// because it uses continuous storage for edges and it uses just
+ /// single-linked lists for enumerate incident edges. Therefore the
+ /// edges cannot be erased from the edge sets.
+ ///
+ /// This class fully conforms to the \ref concepts::Graph "Graph"
+ /// concept.
+ /// It provides only linear time counting for nodes, edges and arcs.
+ ///
+ /// \warning If a node is erased from the underlying graph and this
+ /// node is incident to one edge in the edge set, then the edge set
+ /// is invalidated, and it cannot be used anymore. The validity can
+ /// be checked with the \c valid() member function.
+ template <typename GR>
+ class SmartEdgeSet : public EdgeSetExtender<SmartEdgeSetBase<GR> > {
+ typedef EdgeSetExtender<SmartEdgeSetBase<GR> > Parent;
+
+ public:
+
+ typedef typename Parent::Node Node;
+ typedef typename Parent::Arc Arc;
+ typedef typename Parent::Edge Edge;
+
+ protected:
+
+ typedef typename Parent::NodesImplBase NodesImplBase;
+
+ void eraseNode(const Node& node) {
+ if (typename Parent::IncEdgeIt(*this, node) == INVALID) {
+ return;
+ }
+ throw typename NodesImplBase::Notifier::ImmediateDetach();
+ }
+
+ void clearNodes() {
+ Parent::clear();
+ }
+
+ class NodesImpl : public NodesImplBase {
+ typedef NodesImplBase Parent;
+
+ public:
+ NodesImpl(const GR& graph, SmartEdgeSet& arcset)
+ : Parent(graph), _arcset(arcset) {}
+
+ virtual ~NodesImpl() {}
+
+ bool attached() const {
+ return Parent::attached();
+ }
+
+ protected:
+
+ virtual void erase(const Node& node) {
+ try {
+ _arcset.eraseNode(node);
+ Parent::erase(node);
+ } catch (const typename NodesImplBase::Notifier::ImmediateDetach&) {
+ Parent::clear();
+ throw;
+ }
+ }
+ virtual void erase(const std::vector<Node>& nodes) {
+ try {
+ for (int i = 0; i < int(nodes.size()); ++i) {
+ _arcset.eraseNode(nodes[i]);
+ }
+ Parent::erase(nodes);
+ } catch (const typename NodesImplBase::Notifier::ImmediateDetach&) {
+ Parent::clear();
+ throw;
+ }
+ }
+ virtual void clear() {
+ _arcset.clearNodes();
+ Parent::clear();
+ }
+
+ private:
+ SmartEdgeSet& _arcset;
+ };
+
+ NodesImpl _nodes;
+
+ public:
+
+ /// \brief Constructor of the EdgeSet.
+ ///
+ /// Constructor of the EdgeSet.
+ SmartEdgeSet(const GR& graph) : _nodes(graph, *this) {
+ Parent::initalize(graph, _nodes);
+ }
+
+ /// \brief Add a new edge to the graph.
+ ///
+ /// Add a new edge to the graph with node \c u
+ /// and node \c v endpoints.
+ /// \return The new edge.
+ Edge addEdge(const Node& u, const Node& v) {
+ return Parent::addEdge(u, v);
+ }
+
+ /// \brief Validity check
+ ///
+ /// This functions gives back false if the EdgeSet is
+ /// invalidated. It occurs when a node in the underlying graph is
+ /// erased and it is not isolated in the EdgeSet.
+ bool valid() const {
+ return _nodes.attached();
+ }
+
+ };
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/edmonds_karp.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/edmonds_karp.h
new file mode 100644
index 00000000000..92af3cba313
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/edmonds_karp.h
@@ -0,0 +1,556 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_EDMONDS_KARP_H
+#define LEMON_EDMONDS_KARP_H
+
+/// \file
+/// \ingroup max_flow
+/// \brief Implementation of the Edmonds-Karp algorithm.
+
+#include <lemon/tolerance.h>
+#include <vector>
+
+namespace lemon {
+
+ /// \brief Default traits class of EdmondsKarp class.
+ ///
+ /// Default traits class of EdmondsKarp class.
+ /// \param GR Digraph type.
+ /// \param CAP Type of capacity map.
+ template <typename GR, typename CAP>
+ struct EdmondsKarpDefaultTraits {
+
+ /// \brief The digraph type the algorithm runs on.
+ typedef GR Digraph;
+
+ /// \brief The type of the map that stores the arc capacities.
+ ///
+ /// The type of the map that stores the arc capacities.
+ /// It must meet the \ref concepts::ReadMap "ReadMap" concept.
+ typedef CAP CapacityMap;
+
+ /// \brief The type of the flow values.
+ typedef typename CapacityMap::Value Value;
+
+ /// \brief The type of the map that stores the flow values.
+ ///
+ /// The type of the map that stores the flow values.
+ /// It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept.
+#ifdef DOXYGEN
+ typedef GR::ArcMap<Value> FlowMap;
+#else
+ typedef typename Digraph::template ArcMap<Value> FlowMap;
+#endif
+
+ /// \brief Instantiates a FlowMap.
+ ///
+ /// This function instantiates a \ref FlowMap.
+ /// \param digraph The digraph for which we would like to define
+ /// the flow map.
+ static FlowMap* createFlowMap(const Digraph& digraph) {
+ return new FlowMap(digraph);
+ }
+
+ /// \brief The tolerance used by the algorithm
+ ///
+ /// The tolerance used by the algorithm to handle inexact computation.
+ typedef lemon::Tolerance<Value> Tolerance;
+
+ };
+
+ /// \ingroup max_flow
+ ///
+ /// \brief Edmonds-Karp algorithms class.
+ ///
+ /// This class provides an implementation of the \e Edmonds-Karp \e
+ /// algorithm producing a \ref max_flow "flow of maximum value" in a
+ /// digraph \cite clrs01algorithms, \cite amo93networkflows,
+ /// \cite edmondskarp72theoretical.
+ /// The Edmonds-Karp algorithm is slower than the Preflow
+ /// algorithm, but it has an advantage of the step-by-step execution
+ /// control with feasible flow solutions. The \e source node, the \e
+ /// target node, the \e capacity of the arcs and the \e starting \e
+ /// flow value of the arcs should be passed to the algorithm
+ /// through the constructor.
+ ///
+ /// The time complexity of the algorithm is \f$ O(nm^2) \f$ in
+ /// worst case. Always try the Preflow algorithm instead of this if
+ /// you just want to compute the optimal flow.
+ ///
+ /// \tparam GR The type of the digraph the algorithm runs on.
+ /// \tparam CAP The type of the capacity map. The default map
+ /// type is \ref concepts::Digraph::ArcMap "GR::ArcMap<int>".
+ /// \tparam TR The traits class that defines various types used by the
+ /// algorithm. By default, it is \ref EdmondsKarpDefaultTraits
+ /// "EdmondsKarpDefaultTraits<GR, CAP>".
+ /// In most cases, this parameter should not be set directly,
+ /// consider to use the named template parameters instead.
+
+#ifdef DOXYGEN
+ template <typename GR, typename CAP, typename TR>
+#else
+ template <typename GR,
+ typename CAP = typename GR::template ArcMap<int>,
+ typename TR = EdmondsKarpDefaultTraits<GR, CAP> >
+#endif
+ class EdmondsKarp {
+ public:
+
+ /// \brief The \ref lemon::EdmondsKarpDefaultTraits "traits class"
+ /// of the algorithm.
+ typedef TR Traits;
+ /// The type of the digraph the algorithm runs on.
+ typedef typename Traits::Digraph Digraph;
+ /// The type of the capacity map.
+ typedef typename Traits::CapacityMap CapacityMap;
+ /// The type of the flow values.
+ typedef typename Traits::Value Value;
+
+ /// The type of the flow map.
+ typedef typename Traits::FlowMap FlowMap;
+ /// The type of the tolerance.
+ typedef typename Traits::Tolerance Tolerance;
+
+ private:
+
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+ typedef typename Digraph::template NodeMap<Arc> PredMap;
+
+ const Digraph& _graph;
+ const CapacityMap* _capacity;
+
+ Node _source, _target;
+
+ FlowMap* _flow;
+ bool _local_flow;
+
+ PredMap* _pred;
+ std::vector<Node> _queue;
+
+ Tolerance _tolerance;
+ Value _flow_value;
+
+ void createStructures() {
+ if (!_flow) {
+ _flow = Traits::createFlowMap(_graph);
+ _local_flow = true;
+ }
+ if (!_pred) {
+ _pred = new PredMap(_graph);
+ }
+ _queue.resize(countNodes(_graph));
+ }
+
+ void destroyStructures() {
+ if (_local_flow) {
+ delete _flow;
+ }
+ if (_pred) {
+ delete _pred;
+ }
+ }
+
+ public:
+
+ typedef EdmondsKarp Create;
+
+ ///\name Named template parameters
+
+ ///@{
+
+ template <typename T>
+ struct SetFlowMapTraits : public Traits {
+ typedef T FlowMap;
+ static FlowMap *createFlowMap(const Digraph&) {
+ LEMON_ASSERT(false, "FlowMap is not initialized");
+ return 0;
+ }
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// FlowMap type
+ ///
+ /// \ref named-templ-param "Named parameter" for setting FlowMap
+ /// type
+ template <typename T>
+ struct SetFlowMap
+ : public EdmondsKarp<Digraph, CapacityMap, SetFlowMapTraits<T> > {
+ typedef EdmondsKarp<Digraph, CapacityMap, SetFlowMapTraits<T> > Create;
+ };
+
+ /// @}
+
+ protected:
+
+ EdmondsKarp() {}
+
+ public:
+
+ /// \brief The constructor of the class.
+ ///
+ /// The constructor of the class.
+ /// \param digraph The digraph the algorithm runs on.
+ /// \param capacity The capacity of the arcs.
+ /// \param source The source node.
+ /// \param target The target node.
+ EdmondsKarp(const Digraph& digraph, const CapacityMap& capacity,
+ Node source, Node target)
+ : _graph(digraph), _capacity(&capacity), _source(source), _target(target),
+ _flow(0), _local_flow(false), _pred(0), _tolerance(), _flow_value()
+ {
+ LEMON_ASSERT(_source != _target,
+ "Flow source and target are the same nodes.");
+ }
+
+ /// \brief Destructor.
+ ///
+ /// Destructor.
+ ~EdmondsKarp() {
+ destroyStructures();
+ }
+
+ /// \brief Sets the capacity map.
+ ///
+ /// Sets the capacity map.
+ /// \return <tt>(*this)</tt>
+ EdmondsKarp& capacityMap(const CapacityMap& map) {
+ _capacity = &map;
+ return *this;
+ }
+
+ /// \brief Sets the flow map.
+ ///
+ /// Sets the flow map.
+ /// If you don't use this function before calling \ref run() or
+ /// \ref init(), an instance will be allocated automatically.
+ /// The destructor deallocates this automatically allocated map,
+ /// of course.
+ /// \return <tt>(*this)</tt>
+ EdmondsKarp& flowMap(FlowMap& map) {
+ if (_local_flow) {
+ delete _flow;
+ _local_flow = false;
+ }
+ _flow = &map;
+ return *this;
+ }
+
+ /// \brief Sets the source node.
+ ///
+ /// Sets the source node.
+ /// \return <tt>(*this)</tt>
+ EdmondsKarp& source(const Node& node) {
+ _source = node;
+ return *this;
+ }
+
+ /// \brief Sets the target node.
+ ///
+ /// Sets the target node.
+ /// \return <tt>(*this)</tt>
+ EdmondsKarp& target(const Node& node) {
+ _target = node;
+ return *this;
+ }
+
+ /// \brief Sets the tolerance used by algorithm.
+ ///
+ /// Sets the tolerance used by algorithm.
+ /// \return <tt>(*this)</tt>
+ EdmondsKarp& tolerance(const Tolerance& tolerance) {
+ _tolerance = tolerance;
+ return *this;
+ }
+
+ /// \brief Returns a const reference to the tolerance.
+ ///
+ /// Returns a const reference to the tolerance object used by
+ /// the algorithm.
+ const Tolerance& tolerance() const {
+ return _tolerance;
+ }
+
+ /// \name Execution control
+ /// The simplest way to execute the algorithm is to use \ref run().\n
+ /// If you need better control on the initial solution or the execution,
+ /// you have to call one of the \ref init() functions first, then
+ /// \ref start() or multiple times the \ref augment() function.
+
+ ///@{
+
+ /// \brief Initializes the algorithm.
+ ///
+ /// Initializes the internal data structures and sets the initial
+ /// flow to zero on each arc.
+ void init() {
+ createStructures();
+ for (ArcIt it(_graph); it != INVALID; ++it) {
+ _flow->set(it, 0);
+ }
+ _flow_value = 0;
+ }
+
+ /// \brief Initializes the algorithm using the given flow map.
+ ///
+ /// Initializes the internal data structures and sets the initial
+ /// flow to the given \c flowMap. The \c flowMap should
+ /// contain a feasible flow, i.e. at each node excluding the source
+ /// and the target, the incoming flow should be equal to the
+ /// outgoing flow.
+ template <typename FlowMap>
+ void init(const FlowMap& flowMap) {
+ createStructures();
+ for (ArcIt e(_graph); e != INVALID; ++e) {
+ _flow->set(e, flowMap[e]);
+ }
+ _flow_value = 0;
+ for (OutArcIt jt(_graph, _source); jt != INVALID; ++jt) {
+ _flow_value += (*_flow)[jt];
+ }
+ for (InArcIt jt(_graph, _source); jt != INVALID; ++jt) {
+ _flow_value -= (*_flow)[jt];
+ }
+ }
+
+ /// \brief Initializes the algorithm using the given flow map.
+ ///
+ /// Initializes the internal data structures and sets the initial
+ /// flow to the given \c flowMap. The \c flowMap should
+ /// contain a feasible flow, i.e. at each node excluding the source
+ /// and the target, the incoming flow should be equal to the
+ /// outgoing flow.
+ /// \return \c false when the given \c flowMap does not contain a
+ /// feasible flow.
+ template <typename FlowMap>
+ bool checkedInit(const FlowMap& flowMap) {
+ createStructures();
+ for (ArcIt e(_graph); e != INVALID; ++e) {
+ _flow->set(e, flowMap[e]);
+ }
+ for (NodeIt it(_graph); it != INVALID; ++it) {
+ if (it == _source || it == _target) continue;
+ Value outFlow = 0;
+ for (OutArcIt jt(_graph, it); jt != INVALID; ++jt) {
+ outFlow += (*_flow)[jt];
+ }
+ Value inFlow = 0;
+ for (InArcIt jt(_graph, it); jt != INVALID; ++jt) {
+ inFlow += (*_flow)[jt];
+ }
+ if (_tolerance.different(outFlow, inFlow)) {
+ return false;
+ }
+ }
+ for (ArcIt it(_graph); it != INVALID; ++it) {
+ if (_tolerance.less((*_flow)[it], 0)) return false;
+ if (_tolerance.less((*_capacity)[it], (*_flow)[it])) return false;
+ }
+ _flow_value = 0;
+ for (OutArcIt jt(_graph, _source); jt != INVALID; ++jt) {
+ _flow_value += (*_flow)[jt];
+ }
+ for (InArcIt jt(_graph, _source); jt != INVALID; ++jt) {
+ _flow_value -= (*_flow)[jt];
+ }
+ return true;
+ }
+
+ /// \brief Augments the solution along a shortest path.
+ ///
+ /// Augments the solution along a shortest path. This function searches a
+ /// shortest path between the source and the target
+ /// in the residual digraph by the Bfs algoritm.
+ /// Then it increases the flow on this path with the minimal residual
+ /// capacity on the path. If there is no such path, it gives back
+ /// false.
+ /// \return \c false when the augmenting did not success, i.e. the
+ /// current flow is a feasible and optimal solution.
+ bool augment() {
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ _pred->set(n, INVALID);
+ }
+
+ int first = 0, last = 1;
+
+ _queue[0] = _source;
+ _pred->set(_source, OutArcIt(_graph, _source));
+
+ while (first != last && (*_pred)[_target] == INVALID) {
+ Node n = _queue[first++];
+
+ for (OutArcIt e(_graph, n); e != INVALID; ++e) {
+ Value rem = (*_capacity)[e] - (*_flow)[e];
+ Node t = _graph.target(e);
+ if (_tolerance.positive(rem) && (*_pred)[t] == INVALID) {
+ _pred->set(t, e);
+ _queue[last++] = t;
+ }
+ }
+ for (InArcIt e(_graph, n); e != INVALID; ++e) {
+ Value rem = (*_flow)[e];
+ Node t = _graph.source(e);
+ if (_tolerance.positive(rem) && (*_pred)[t] == INVALID) {
+ _pred->set(t, e);
+ _queue[last++] = t;
+ }
+ }
+ }
+
+ if ((*_pred)[_target] != INVALID) {
+ Node n = _target;
+ Arc e = (*_pred)[n];
+
+ Value prem = (*_capacity)[e] - (*_flow)[e];
+ n = _graph.source(e);
+ while (n != _source) {
+ e = (*_pred)[n];
+ if (_graph.target(e) == n) {
+ Value rem = (*_capacity)[e] - (*_flow)[e];
+ if (rem < prem) prem = rem;
+ n = _graph.source(e);
+ } else {
+ Value rem = (*_flow)[e];
+ if (rem < prem) prem = rem;
+ n = _graph.target(e);
+ }
+ }
+
+ n = _target;
+ e = (*_pred)[n];
+
+ _flow->set(e, (*_flow)[e] + prem);
+ n = _graph.source(e);
+ while (n != _source) {
+ e = (*_pred)[n];
+ if (_graph.target(e) == n) {
+ _flow->set(e, (*_flow)[e] + prem);
+ n = _graph.source(e);
+ } else {
+ _flow->set(e, (*_flow)[e] - prem);
+ n = _graph.target(e);
+ }
+ }
+
+ _flow_value += prem;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /// \brief Executes the algorithm
+ ///
+ /// Executes the algorithm by performing augmenting phases until the
+ /// optimal solution is reached.
+ /// \pre One of the \ref init() functions must be called before
+ /// using this function.
+ void start() {
+ while (augment()) {}
+ }
+
+ /// \brief Runs the algorithm.
+ ///
+ /// Runs the Edmonds-Karp algorithm.
+ /// \note ek.run() is just a shortcut of the following code.
+ ///\code
+ /// ek.init();
+ /// ek.start();
+ ///\endcode
+ void run() {
+ init();
+ start();
+ }
+
+ /// @}
+
+ /// \name Query Functions
+ /// The result of the Edmonds-Karp algorithm can be obtained using these
+ /// functions.\n
+ /// Either \ref run() or \ref start() should be called before using them.
+
+ ///@{
+
+ /// \brief Returns the value of the maximum flow.
+ ///
+ /// Returns the value of the maximum flow found by the algorithm.
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ Value flowValue() const {
+ return _flow_value;
+ }
+
+ /// \brief Returns the flow value on the given arc.
+ ///
+ /// Returns the flow value on the given arc.
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ Value flow(const Arc& arc) const {
+ return (*_flow)[arc];
+ }
+
+ /// \brief Returns a const reference to the flow map.
+ ///
+ /// Returns a const reference to the arc map storing the found flow.
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ const FlowMap& flowMap() const {
+ return *_flow;
+ }
+
+ /// \brief Returns \c true when the node is on the source side of the
+ /// minimum cut.
+ ///
+ /// Returns true when the node is on the source side of the found
+ /// minimum cut.
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ bool minCut(const Node& node) const {
+ return ((*_pred)[node] != INVALID) || node == _source;
+ }
+
+ /// \brief Gives back a minimum value cut.
+ ///
+ /// Sets \c cutMap to the characteristic vector of a minimum value
+ /// cut. \c cutMap should be a \ref concepts::WriteMap "writable"
+ /// node map with \c bool (or convertible) value type.
+ ///
+ /// \note This function calls \ref minCut() for each node, so it runs in
+ /// O(n) time.
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ template <typename CutMap>
+ void minCutMap(CutMap& cutMap) const {
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ cutMap.set(n, (*_pred)[n] != INVALID);
+ }
+ cutMap.set(_source, true);
+ }
+
+ /// @}
+
+ };
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/elevator.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/elevator.h
new file mode 100644
index 00000000000..e4adcd59982
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/elevator.h
@@ -0,0 +1,982 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_ELEVATOR_H
+#define LEMON_ELEVATOR_H
+
+///\ingroup auxdat
+///\file
+///\brief Elevator class
+///
+///Elevator class implements an efficient data structure
+///for labeling items in push-relabel type algorithms.
+///
+
+#include <lemon/core.h>
+#include <lemon/bits/traits.h>
+
+namespace lemon {
+
+ ///Class for handling "labels" in push-relabel type algorithms.
+
+ ///A class for handling "labels" in push-relabel type algorithms.
+ ///
+ ///\ingroup auxdat
+ ///Using this class you can assign "labels" (nonnegative integer numbers)
+ ///to the edges or nodes of a graph, manipulate and query them through
+ ///operations typically arising in "push-relabel" type algorithms.
+ ///
+ ///Each item is either \em active or not, and you can also choose a
+ ///highest level active item.
+ ///
+ ///\sa LinkedElevator
+ ///
+ ///\param GR Type of the underlying graph.
+ ///\param Item Type of the items the data is assigned to (\c GR::Node,
+ ///\c GR::Arc or \c GR::Edge).
+ template<class GR, class Item>
+ class Elevator
+ {
+ public:
+
+ typedef Item Key;
+ typedef int Value;
+
+ private:
+
+ typedef Item *Vit;
+ typedef typename ItemSetTraits<GR,Item>::template Map<Vit>::Type VitMap;
+ typedef typename ItemSetTraits<GR,Item>::template Map<int>::Type IntMap;
+
+ const GR &_g;
+ int _max_level;
+ int _item_num;
+ VitMap _where;
+ IntMap _level;
+ std::vector<Item> _items;
+ std::vector<Vit> _first;
+ std::vector<Vit> _last_active;
+
+ int _highest_active;
+
+ void copy(Item i, Vit p)
+ {
+ _where[*p=i] = p;
+ }
+ void copy(Vit s, Vit p)
+ {
+ if(s!=p)
+ {
+ Item i=*s;
+ *p=i;
+ _where[i] = p;
+ }
+ }
+ void swap(Vit i, Vit j)
+ {
+ Item ti=*i;
+ Vit ct = _where[ti];
+ _where[ti] = _where[*i=*j];
+ _where[*j] = ct;
+ *j=ti;
+ }
+
+ public:
+
+ ///Constructor with given maximum level.
+
+ ///Constructor with given maximum level.
+ ///
+ ///\param graph The underlying graph.
+ ///\param max_level The maximum allowed level.
+ ///Set the range of the possible labels to <tt>[0..max_level]</tt>.
+ Elevator(const GR &graph,int max_level) :
+ _g(graph),
+ _max_level(max_level),
+ _item_num(_max_level),
+ _where(graph),
+ _level(graph,0),
+ _items(_max_level),
+ _first(_max_level+2),
+ _last_active(_max_level+2),
+ _highest_active(-1) {}
+ ///Constructor.
+
+ ///Constructor.
+ ///
+ ///\param graph The underlying graph.
+ ///Set the range of the possible labels to <tt>[0..max_level]</tt>,
+ ///where \c max_level is equal to the number of labeled items in the graph.
+ Elevator(const GR &graph) :
+ _g(graph),
+ _max_level(countItems<GR, Item>(graph)),
+ _item_num(_max_level),
+ _where(graph),
+ _level(graph,0),
+ _items(_max_level),
+ _first(_max_level+2),
+ _last_active(_max_level+2),
+ _highest_active(-1)
+ {
+ }
+
+ ///Activate item \c i.
+
+ ///Activate item \c i.
+ ///\pre Item \c i shouldn't be active before.
+ void activate(Item i)
+ {
+ const int l=_level[i];
+ swap(_where[i],++_last_active[l]);
+ if(l>_highest_active) _highest_active=l;
+ }
+
+ ///Deactivate item \c i.
+
+ ///Deactivate item \c i.
+ ///\pre Item \c i must be active before.
+ void deactivate(Item i)
+ {
+ swap(_where[i],_last_active[_level[i]]--);
+ while(_highest_active>=0 &&
+ _last_active[_highest_active]<_first[_highest_active])
+ _highest_active--;
+ }
+
+ ///Query whether item \c i is active
+ bool active(Item i) const { return _where[i]<=_last_active[_level[i]]; }
+
+ ///Return the level of item \c i.
+ int operator[](Item i) const { return _level[i]; }
+
+ ///Return the number of items on level \c l.
+ int onLevel(int l) const
+ {
+ return _first[l+1]-_first[l];
+ }
+ ///Return true if level \c l is empty.
+ bool emptyLevel(int l) const
+ {
+ return _first[l+1]-_first[l]==0;
+ }
+ ///Return the number of items above level \c l.
+ int aboveLevel(int l) const
+ {
+ return _first[_max_level+1]-_first[l+1];
+ }
+ ///Return the number of active items on level \c l.
+ int activesOnLevel(int l) const
+ {
+ return _last_active[l]-_first[l]+1;
+ }
+ ///Return true if there is no active item on level \c l.
+ bool activeFree(int l) const
+ {
+ return _last_active[l]<_first[l];
+ }
+ ///Return the maximum allowed level.
+ int maxLevel() const
+ {
+ return _max_level;
+ }
+
+ ///\name Highest Active Item
+ ///Functions for working with the highest level
+ ///active item.
+
+ ///@{
+
+ ///Return a highest level active item.
+
+ ///Return a highest level active item or INVALID if there is no active
+ ///item.
+ Item highestActive() const
+ {
+ return _highest_active>=0?*_last_active[_highest_active]:INVALID;
+ }
+
+ ///Return the highest active level.
+
+ ///Return the level of the highest active item or -1 if there is no active
+ ///item.
+ int highestActiveLevel() const
+ {
+ return _highest_active;
+ }
+
+ ///Lift the highest active item by one.
+
+ ///Lift the item returned by highestActive() by one.
+ ///
+ void liftHighestActive()
+ {
+ Item it = *_last_active[_highest_active];
+ ++_level[it];
+ swap(_last_active[_highest_active]--,_last_active[_highest_active+1]);
+ --_first[++_highest_active];
+ }
+
+ ///Lift the highest active item to the given level.
+
+ ///Lift the item returned by highestActive() to level \c new_level.
+ ///
+ ///\warning \c new_level must be strictly higher
+ ///than the current level.
+ ///
+ void liftHighestActive(int new_level)
+ {
+ const Item li = *_last_active[_highest_active];
+
+ copy(--_first[_highest_active+1],_last_active[_highest_active]--);
+ for(int l=_highest_active+1;l<new_level;l++)
+ {
+ copy(--_first[l+1],_first[l]);
+ --_last_active[l];
+ }
+ copy(li,_first[new_level]);
+ _level[li] = new_level;
+ _highest_active=new_level;
+ }
+
+ ///Lift the highest active item to the top level.
+
+ ///Lift the item returned by highestActive() to the top level and
+ ///deactivate it.
+ void liftHighestActiveToTop()
+ {
+ const Item li = *_last_active[_highest_active];
+
+ copy(--_first[_highest_active+1],_last_active[_highest_active]--);
+ for(int l=_highest_active+1;l<_max_level;l++)
+ {
+ copy(--_first[l+1],_first[l]);
+ --_last_active[l];
+ }
+ copy(li,_first[_max_level]);
+ --_last_active[_max_level];
+ _level[li] = _max_level;
+
+ while(_highest_active>=0 &&
+ _last_active[_highest_active]<_first[_highest_active])
+ _highest_active--;
+ }
+
+ ///@}
+
+ ///\name Active Item on Certain Level
+ ///Functions for working with the active items.
+
+ ///@{
+
+ ///Return an active item on level \c l.
+
+ ///Return an active item on level \c l or \ref INVALID if there is no such
+ ///an item. (\c l must be from the range [0...\c max_level].
+ Item activeOn(int l) const
+ {
+ return _last_active[l]>=_first[l]?*_last_active[l]:INVALID;
+ }
+
+ ///Lift the active item returned by \c activeOn(level) by one.
+
+ ///Lift the active item returned by \ref activeOn() "activeOn(level)"
+ ///by one.
+ Item liftActiveOn(int level)
+ {
+ Item it =*_last_active[level];
+ ++_level[it];
+ swap(_last_active[level]--, --_first[level+1]);
+ if (level+1>_highest_active) ++_highest_active;
+ }
+
+ ///Lift the active item returned by \c activeOn(level) to the given level.
+
+ ///Lift the active item returned by \ref activeOn() "activeOn(level)"
+ ///to the given level.
+ void liftActiveOn(int level, int new_level)
+ {
+ const Item ai = *_last_active[level];
+
+ copy(--_first[level+1], _last_active[level]--);
+ for(int l=level+1;l<new_level;l++)
+ {
+ copy(_last_active[l],_first[l]);
+ copy(--_first[l+1], _last_active[l]--);
+ }
+ copy(ai,_first[new_level]);
+ _level[ai] = new_level;
+ if (new_level>_highest_active) _highest_active=new_level;
+ }
+
+ ///Lift the active item returned by \c activeOn(level) to the top level.
+
+ ///Lift the active item returned by \ref activeOn() "activeOn(level)"
+ ///to the top level and deactivate it.
+ void liftActiveToTop(int level)
+ {
+ const Item ai = *_last_active[level];
+
+ copy(--_first[level+1],_last_active[level]--);
+ for(int l=level+1;l<_max_level;l++)
+ {
+ copy(_last_active[l],_first[l]);
+ copy(--_first[l+1], _last_active[l]--);
+ }
+ copy(ai,_first[_max_level]);
+ --_last_active[_max_level];
+ _level[ai] = _max_level;
+
+ if (_highest_active==level) {
+ while(_highest_active>=0 &&
+ _last_active[_highest_active]<_first[_highest_active])
+ _highest_active--;
+ }
+ }
+
+ ///@}
+
+ ///Lift an active item to a higher level.
+
+ ///Lift an active item to a higher level.
+ ///\param i The item to be lifted. It must be active.
+ ///\param new_level The new level of \c i. It must be strictly higher
+ ///than the current level.
+ ///
+ void lift(Item i, int new_level)
+ {
+ const int lo = _level[i];
+ const Vit w = _where[i];
+
+ copy(_last_active[lo],w);
+ copy(--_first[lo+1],_last_active[lo]--);
+ for(int l=lo+1;l<new_level;l++)
+ {
+ copy(_last_active[l],_first[l]);
+ copy(--_first[l+1],_last_active[l]--);
+ }
+ copy(i,_first[new_level]);
+ _level[i] = new_level;
+ if(new_level>_highest_active) _highest_active=new_level;
+ }
+
+ ///Move an inactive item to the top but one level (in a dirty way).
+
+ ///This function moves an inactive item from the top level to the top
+ ///but one level (in a dirty way).
+ ///\warning It makes the underlying datastructure corrupt, so use it
+ ///only if you really know what it is for.
+ ///\pre The item is on the top level.
+ void dirtyTopButOne(Item i) {
+ _level[i] = _max_level - 1;
+ }
+
+ ///Lift all items on and above the given level to the top level.
+
+ ///This function lifts all items on and above level \c l to the top
+ ///level and deactivates them.
+ void liftToTop(int l)
+ {
+ const Vit f=_first[l];
+ const Vit tl=_first[_max_level];
+ for(Vit i=f;i!=tl;++i)
+ _level[*i] = _max_level;
+ for(int i=l;i<=_max_level;i++)
+ {
+ _first[i]=f;
+ _last_active[i]=f-1;
+ }
+ for(_highest_active=l-1;
+ _highest_active>=0 &&
+ _last_active[_highest_active]<_first[_highest_active];
+ _highest_active--) ;
+ }
+
+ private:
+ int _init_lev;
+ Vit _init_num;
+
+ public:
+
+ ///\name Initialization
+ ///Using these functions you can initialize the levels of the items.
+ ///\n
+ ///The initialization must be started with calling \c initStart().
+ ///Then the items should be listed level by level starting with the
+ ///lowest one (level 0) using \c initAddItem() and \c initNewLevel().
+ ///Finally \c initFinish() must be called.
+ ///The items not listed are put on the highest level.
+ ///@{
+
+ ///Start the initialization process.
+ void initStart()
+ {
+ _init_lev=0;
+ _init_num=&_items[0];
+ _first[0]=&_items[0];
+ _last_active[0]=&_items[0]-1;
+ Vit n=&_items[0];
+ for(typename ItemSetTraits<GR,Item>::ItemIt i(_g);i!=INVALID;++i)
+ {
+ *n=i;
+ _where[i] = n;
+ _level[i] = _max_level;
+ ++n;
+ }
+ }
+
+ ///Add an item to the current level.
+ void initAddItem(Item i)
+ {
+ swap(_where[i],_init_num);
+ _level[i] = _init_lev;
+ ++_init_num;
+ }
+
+ ///Start a new level.
+
+ ///Start a new level.
+ ///It shouldn't be used before the items on level 0 are listed.
+ void initNewLevel()
+ {
+ _init_lev++;
+ _first[_init_lev]=_init_num;
+ _last_active[_init_lev]=_init_num-1;
+ }
+
+ ///Finalize the initialization process.
+ void initFinish()
+ {
+ for(_init_lev++;_init_lev<=_max_level;_init_lev++)
+ {
+ _first[_init_lev]=_init_num;
+ _last_active[_init_lev]=_init_num-1;
+ }
+ _first[_max_level+1]=&_items[0]+_item_num;
+ _last_active[_max_level+1]=&_items[0]+_item_num-1;
+ _highest_active = -1;
+ }
+
+ ///@}
+
+ };
+
+ ///Class for handling "labels" in push-relabel type algorithms.
+
+ ///A class for handling "labels" in push-relabel type algorithms.
+ ///
+ ///\ingroup auxdat
+ ///Using this class you can assign "labels" (nonnegative integer numbers)
+ ///to the edges or nodes of a graph, manipulate and query them through
+ ///operations typically arising in "push-relabel" type algorithms.
+ ///
+ ///Each item is either \em active or not, and you can also choose a
+ ///highest level active item.
+ ///
+ ///\sa Elevator
+ ///
+ ///\param GR Type of the underlying graph.
+ ///\param Item Type of the items the data is assigned to (\c GR::Node,
+ ///\c GR::Arc or \c GR::Edge).
+ template <class GR, class Item>
+ class LinkedElevator {
+ public:
+
+ typedef Item Key;
+ typedef int Value;
+
+ private:
+
+ typedef typename ItemSetTraits<GR,Item>::
+ template Map<Item>::Type ItemMap;
+ typedef typename ItemSetTraits<GR,Item>::
+ template Map<int>::Type IntMap;
+ typedef typename ItemSetTraits<GR,Item>::
+ template Map<bool>::Type BoolMap;
+
+ const GR &_graph;
+ int _max_level;
+ int _item_num;
+ std::vector<Item> _first, _last;
+ ItemMap _prev, _next;
+ int _highest_active;
+ IntMap _level;
+ BoolMap _active;
+
+ public:
+ ///Constructor with given maximum level.
+
+ ///Constructor with given maximum level.
+ ///
+ ///\param graph The underlying graph.
+ ///\param max_level The maximum allowed level.
+ ///Set the range of the possible labels to <tt>[0..max_level]</tt>.
+ LinkedElevator(const GR& graph, int max_level)
+ : _graph(graph), _max_level(max_level), _item_num(_max_level),
+ _first(_max_level + 1), _last(_max_level + 1),
+ _prev(graph), _next(graph),
+ _highest_active(-1), _level(graph), _active(graph) {}
+
+ ///Constructor.
+
+ ///Constructor.
+ ///
+ ///\param graph The underlying graph.
+ ///Set the range of the possible labels to <tt>[0..max_level]</tt>,
+ ///where \c max_level is equal to the number of labeled items in the graph.
+ LinkedElevator(const GR& graph)
+ : _graph(graph), _max_level(countItems<GR, Item>(graph)),
+ _item_num(_max_level),
+ _first(_max_level + 1), _last(_max_level + 1),
+ _prev(graph, INVALID), _next(graph, INVALID),
+ _highest_active(-1), _level(graph), _active(graph) {}
+
+
+ ///Activate item \c i.
+
+ ///Activate item \c i.
+ ///\pre Item \c i shouldn't be active before.
+ void activate(Item i) {
+ _active[i] = true;
+
+ int level = _level[i];
+ if (level > _highest_active) {
+ _highest_active = level;
+ }
+
+ if (_prev[i] == INVALID || _active[_prev[i]]) return;
+ //unlace
+ _next[_prev[i]] = _next[i];
+ if (_next[i] != INVALID) {
+ _prev[_next[i]] = _prev[i];
+ } else {
+ _last[level] = _prev[i];
+ }
+ //lace
+ _next[i] = _first[level];
+ _prev[_first[level]] = i;
+ _prev[i] = INVALID;
+ _first[level] = i;
+
+ }
+
+ ///Deactivate item \c i.
+
+ ///Deactivate item \c i.
+ ///\pre Item \c i must be active before.
+ void deactivate(Item i) {
+ _active[i] = false;
+ int level = _level[i];
+
+ if (_next[i] == INVALID || !_active[_next[i]])
+ goto find_highest_level;
+
+ //unlace
+ _prev[_next[i]] = _prev[i];
+ if (_prev[i] != INVALID) {
+ _next[_prev[i]] = _next[i];
+ } else {
+ _first[_level[i]] = _next[i];
+ }
+ //lace
+ _prev[i] = _last[level];
+ _next[_last[level]] = i;
+ _next[i] = INVALID;
+ _last[level] = i;
+
+ find_highest_level:
+ if (level == _highest_active) {
+ while (_highest_active >= 0 && activeFree(_highest_active))
+ --_highest_active;
+ }
+ }
+
+ ///Query whether item \c i is active
+ bool active(Item i) const { return _active[i]; }
+
+ ///Return the level of item \c i.
+ int operator[](Item i) const { return _level[i]; }
+
+ ///Return the number of items on level \c l.
+ int onLevel(int l) const {
+ int num = 0;
+ Item n = _first[l];
+ while (n != INVALID) {
+ ++num;
+ n = _next[n];
+ }
+ return num;
+ }
+
+ ///Return true if the level is empty.
+ bool emptyLevel(int l) const {
+ return _first[l] == INVALID;
+ }
+
+ ///Return the number of items above level \c l.
+ int aboveLevel(int l) const {
+ int num = 0;
+ for (int level = l + 1; level < _max_level; ++level)
+ num += onLevel(level);
+ return num;
+ }
+
+ ///Return the number of active items on level \c l.
+ int activesOnLevel(int l) const {
+ int num = 0;
+ Item n = _first[l];
+ while (n != INVALID && _active[n]) {
+ ++num;
+ n = _next[n];
+ }
+ return num;
+ }
+
+ ///Return true if there is no active item on level \c l.
+ bool activeFree(int l) const {
+ return _first[l] == INVALID || !_active[_first[l]];
+ }
+
+ ///Return the maximum allowed level.
+ int maxLevel() const {
+ return _max_level;
+ }
+
+ ///\name Highest Active Item
+ ///Functions for working with the highest level
+ ///active item.
+
+ ///@{
+
+ ///Return a highest level active item.
+
+ ///Return a highest level active item or INVALID if there is no active
+ ///item.
+ Item highestActive() const {
+ return _highest_active >= 0 ? _first[_highest_active] : INVALID;
+ }
+
+ ///Return the highest active level.
+
+ ///Return the level of the highest active item or -1 if there is no active
+ ///item.
+ int highestActiveLevel() const {
+ return _highest_active;
+ }
+
+ ///Lift the highest active item by one.
+
+ ///Lift the item returned by highestActive() by one.
+ ///
+ void liftHighestActive() {
+ Item i = _first[_highest_active];
+ if (_next[i] != INVALID) {
+ _prev[_next[i]] = INVALID;
+ _first[_highest_active] = _next[i];
+ } else {
+ _first[_highest_active] = INVALID;
+ _last[_highest_active] = INVALID;
+ }
+ _level[i] = ++_highest_active;
+ if (_first[_highest_active] == INVALID) {
+ _first[_highest_active] = i;
+ _last[_highest_active] = i;
+ _prev[i] = INVALID;
+ _next[i] = INVALID;
+ } else {
+ _prev[_first[_highest_active]] = i;
+ _next[i] = _first[_highest_active];
+ _first[_highest_active] = i;
+ }
+ }
+
+ ///Lift the highest active item to the given level.
+
+ ///Lift the item returned by highestActive() to level \c new_level.
+ ///
+ ///\warning \c new_level must be strictly higher
+ ///than the current level.
+ ///
+ void liftHighestActive(int new_level) {
+ Item i = _first[_highest_active];
+ if (_next[i] != INVALID) {
+ _prev[_next[i]] = INVALID;
+ _first[_highest_active] = _next[i];
+ } else {
+ _first[_highest_active] = INVALID;
+ _last[_highest_active] = INVALID;
+ }
+ _level[i] = _highest_active = new_level;
+ if (_first[_highest_active] == INVALID) {
+ _first[_highest_active] = _last[_highest_active] = i;
+ _prev[i] = INVALID;
+ _next[i] = INVALID;
+ } else {
+ _prev[_first[_highest_active]] = i;
+ _next[i] = _first[_highest_active];
+ _first[_highest_active] = i;
+ }
+ }
+
+ ///Lift the highest active item to the top level.
+
+ ///Lift the item returned by highestActive() to the top level and
+ ///deactivate it.
+ void liftHighestActiveToTop() {
+ Item i = _first[_highest_active];
+ _level[i] = _max_level;
+ if (_next[i] != INVALID) {
+ _prev[_next[i]] = INVALID;
+ _first[_highest_active] = _next[i];
+ } else {
+ _first[_highest_active] = INVALID;
+ _last[_highest_active] = INVALID;
+ }
+ while (_highest_active >= 0 && activeFree(_highest_active))
+ --_highest_active;
+ }
+
+ ///@}
+
+ ///\name Active Item on Certain Level
+ ///Functions for working with the active items.
+
+ ///@{
+
+ ///Return an active item on level \c l.
+
+ ///Return an active item on level \c l or \ref INVALID if there is no such
+ ///an item. (\c l must be from the range [0...\c max_level].
+ Item activeOn(int l) const
+ {
+ return _active[_first[l]] ? _first[l] : INVALID;
+ }
+
+ ///Lift the active item returned by \c activeOn(l) by one.
+
+ ///Lift the active item returned by \ref activeOn() "activeOn(l)"
+ ///by one.
+ Item liftActiveOn(int l)
+ {
+ Item i = _first[l];
+ if (_next[i] != INVALID) {
+ _prev[_next[i]] = INVALID;
+ _first[l] = _next[i];
+ } else {
+ _first[l] = INVALID;
+ _last[l] = INVALID;
+ }
+ _level[i] = ++l;
+ if (_first[l] == INVALID) {
+ _first[l] = _last[l] = i;
+ _prev[i] = INVALID;
+ _next[i] = INVALID;
+ } else {
+ _prev[_first[l]] = i;
+ _next[i] = _first[l];
+ _first[l] = i;
+ }
+ if (_highest_active < l) {
+ _highest_active = l;
+ }
+ }
+
+ ///Lift the active item returned by \c activeOn(l) to the given level.
+
+ ///Lift the active item returned by \ref activeOn() "activeOn(l)"
+ ///to the given level.
+ void liftActiveOn(int l, int new_level)
+ {
+ Item i = _first[l];
+ if (_next[i] != INVALID) {
+ _prev[_next[i]] = INVALID;
+ _first[l] = _next[i];
+ } else {
+ _first[l] = INVALID;
+ _last[l] = INVALID;
+ }
+ _level[i] = l = new_level;
+ if (_first[l] == INVALID) {
+ _first[l] = _last[l] = i;
+ _prev[i] = INVALID;
+ _next[i] = INVALID;
+ } else {
+ _prev[_first[l]] = i;
+ _next[i] = _first[l];
+ _first[l] = i;
+ }
+ if (_highest_active < l) {
+ _highest_active = l;
+ }
+ }
+
+ ///Lift the active item returned by \c activeOn(l) to the top level.
+
+ ///Lift the active item returned by \ref activeOn() "activeOn(l)"
+ ///to the top level and deactivate it.
+ void liftActiveToTop(int l)
+ {
+ Item i = _first[l];
+ if (_next[i] != INVALID) {
+ _prev[_next[i]] = INVALID;
+ _first[l] = _next[i];
+ } else {
+ _first[l] = INVALID;
+ _last[l] = INVALID;
+ }
+ _level[i] = _max_level;
+ if (l == _highest_active) {
+ while (_highest_active >= 0 && activeFree(_highest_active))
+ --_highest_active;
+ }
+ }
+
+ ///@}
+
+ /// \brief Lift an active item to a higher level.
+ ///
+ /// Lift an active item to a higher level.
+ /// \param i The item to be lifted. It must be active.
+ /// \param new_level The new level of \c i. It must be strictly higher
+ /// than the current level.
+ ///
+ void lift(Item i, int new_level) {
+ if (_next[i] != INVALID) {
+ _prev[_next[i]] = _prev[i];
+ } else {
+ _last[new_level] = _prev[i];
+ }
+ if (_prev[i] != INVALID) {
+ _next[_prev[i]] = _next[i];
+ } else {
+ _first[new_level] = _next[i];
+ }
+ _level[i] = new_level;
+ if (_first[new_level] == INVALID) {
+ _first[new_level] = _last[new_level] = i;
+ _prev[i] = INVALID;
+ _next[i] = INVALID;
+ } else {
+ _prev[_first[new_level]] = i;
+ _next[i] = _first[new_level];
+ _first[new_level] = i;
+ }
+ if (_highest_active < new_level) {
+ _highest_active = new_level;
+ }
+ }
+
+ ///Move an inactive item to the top but one level (in a dirty way).
+
+ ///This function moves an inactive item from the top level to the top
+ ///but one level (in a dirty way).
+ ///\warning It makes the underlying datastructure corrupt, so use it
+ ///only if you really know what it is for.
+ ///\pre The item is on the top level.
+ void dirtyTopButOne(Item i) {
+ _level[i] = _max_level - 1;
+ }
+
+ ///Lift all items on and above the given level to the top level.
+
+ ///This function lifts all items on and above level \c l to the top
+ ///level and deactivates them.
+ void liftToTop(int l) {
+ for (int i = l + 1; _first[i] != INVALID; ++i) {
+ Item n = _first[i];
+ while (n != INVALID) {
+ _level[n] = _max_level;
+ n = _next[n];
+ }
+ _first[i] = INVALID;
+ _last[i] = INVALID;
+ }
+ if (_highest_active > l - 1) {
+ _highest_active = l - 1;
+ while (_highest_active >= 0 && activeFree(_highest_active))
+ --_highest_active;
+ }
+ }
+
+ private:
+
+ int _init_level;
+
+ public:
+
+ ///\name Initialization
+ ///Using these functions you can initialize the levels of the items.
+ ///\n
+ ///The initialization must be started with calling \c initStart().
+ ///Then the items should be listed level by level starting with the
+ ///lowest one (level 0) using \c initAddItem() and \c initNewLevel().
+ ///Finally \c initFinish() must be called.
+ ///The items not listed are put on the highest level.
+ ///@{
+
+ ///Start the initialization process.
+ void initStart() {
+
+ for (int i = 0; i <= _max_level; ++i) {
+ _first[i] = _last[i] = INVALID;
+ }
+ _init_level = 0;
+ for(typename ItemSetTraits<GR,Item>::ItemIt i(_graph);
+ i != INVALID; ++i) {
+ _level[i] = _max_level;
+ _active[i] = false;
+ }
+ }
+
+ ///Add an item to the current level.
+ void initAddItem(Item i) {
+ _level[i] = _init_level;
+ if (_last[_init_level] == INVALID) {
+ _first[_init_level] = i;
+ _last[_init_level] = i;
+ _prev[i] = INVALID;
+ _next[i] = INVALID;
+ } else {
+ _prev[i] = _last[_init_level];
+ _next[i] = INVALID;
+ _next[_last[_init_level]] = i;
+ _last[_init_level] = i;
+ }
+ }
+
+ ///Start a new level.
+
+ ///Start a new level.
+ ///It shouldn't be used before the items on level 0 are listed.
+ void initNewLevel() {
+ ++_init_level;
+ }
+
+ ///Finalize the initialization process.
+ void initFinish() {
+ _highest_active = -1;
+ }
+
+ ///@}
+
+ };
+
+
+} //END OF NAMESPACE LEMON
+
+#endif
+
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/error.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/error.h
new file mode 100644
index 00000000000..f937704541b
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/error.h
@@ -0,0 +1,276 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_ERROR_H
+#define LEMON_ERROR_H
+
+/// \ingroup exceptions
+/// \file
+/// \brief Basic exception classes and error handling.
+
+#include <exception>
+#include <string>
+#include <sstream>
+#include <iostream>
+#include <cstdlib>
+#include <memory>
+
+namespace lemon {
+
+ /// \addtogroup exceptions
+ /// @{
+
+ /// \brief Generic exception class.
+ ///
+ /// Base class for exceptions used in LEMON.
+ ///
+ class Exception : public std::exception {
+ public:
+ ///Constructor
+ Exception() throw() {}
+ ///Virtual destructor
+ virtual ~Exception() throw() {}
+ ///A short description of the exception
+ virtual const char* what() const throw() {
+ return "lemon::Exception";
+ }
+ };
+
+ /// \brief Input-Output error
+ ///
+ /// This exception is thrown when a file operation cannot be
+ /// succeeded.
+ class IoError : public Exception {
+ protected:
+ std::string _message;
+ std::string _file;
+
+ mutable std::string _what;
+ public:
+
+ /// Copy constructor
+ IoError(const IoError &error) throw() : Exception() {
+ message(error._message);
+ file(error._file);
+ }
+
+ /// Constructor
+ explicit IoError(const char *message) throw() {
+ IoError::message(message);
+ }
+
+ /// Constructor
+ explicit IoError(const std::string &message) throw() {
+ IoError::message(message);
+ }
+
+ /// Constructor
+ explicit IoError(const char *message,
+ const std::string &file) throw() {
+ IoError::message(message);
+ IoError::file(file);
+ }
+
+ /// Constructor
+ explicit IoError(const std::string &message,
+ const std::string &file) throw() {
+ IoError::message(message);
+ IoError::file(file);
+ }
+
+ /// Virtual destructor
+ virtual ~IoError() throw() {}
+
+ /// Set the error message
+ void message(const char *message) throw() {
+ try {
+ _message = message;
+ } catch (...) {}
+ }
+
+ /// Set the error message
+ void message(const std::string& message) throw() {
+ try {
+ _message = message;
+ } catch (...) {}
+ }
+
+ /// Set the file name
+ void file(const std::string &file) throw() {
+ try {
+ _file = file;
+ } catch (...) {}
+ }
+
+ /// Returns the error message
+ const std::string& message() const throw() {
+ return _message;
+ }
+
+ /// \brief Returns the filename
+ ///
+ /// Returns the filename or an empty string if it was not specified.
+ const std::string& file() const throw() {
+ return _file;
+ }
+
+ /// \brief Returns a short error message
+ ///
+ /// Returns a short error message which contains the message and the
+ /// file name.
+ virtual const char* what() const throw() {
+ try {
+ _what.clear();
+ std::ostringstream oss;
+ oss << "lemon:IoError" << ": ";
+ oss << _message;
+ if (!_file.empty()) {
+ oss << " ('" << _file << "')";
+ }
+ _what = oss.str();
+ }
+ catch (...) {}
+ if (!_what.empty()) return _what.c_str();
+ else return "lemon:IoError";
+ }
+
+ };
+
+ /// \brief Format error
+ ///
+ /// This exception is thrown when an input file has wrong
+ /// format or a data representation is not legal.
+ class FormatError : public Exception {
+ protected:
+ std::string _message;
+ std::string _file;
+ int _line;
+
+ mutable std::string _what;
+ public:
+
+ /// Copy constructor
+ FormatError(const FormatError &error) throw() : Exception() {
+ message(error._message);
+ file(error._file);
+ line(error._line);
+ }
+
+ /// Constructor
+ explicit FormatError(const char *message) throw() {
+ FormatError::message(message);
+ _line = 0;
+ }
+
+ /// Constructor
+ explicit FormatError(const std::string &message) throw() {
+ FormatError::message(message);
+ _line = 0;
+ }
+
+ /// Constructor
+ explicit FormatError(const char *message,
+ const std::string &file, int line = 0) throw() {
+ FormatError::message(message);
+ FormatError::file(file);
+ FormatError::line(line);
+ }
+
+ /// Constructor
+ explicit FormatError(const std::string &message,
+ const std::string &file, int line = 0) throw() {
+ FormatError::message(message);
+ FormatError::file(file);
+ FormatError::line(line);
+ }
+
+ /// Virtual destructor
+ virtual ~FormatError() throw() {}
+
+ /// Set the line number
+ void line(int line) throw() { _line = line; }
+
+ /// Set the error message
+ void message(const char *message) throw() {
+ try {
+ _message = message;
+ } catch (...) {}
+ }
+
+ /// Set the error message
+ void message(const std::string& message) throw() {
+ try {
+ _message = message;
+ } catch (...) {}
+ }
+
+ /// Set the file name
+ void file(const std::string &file) throw() {
+ try {
+ _file = file;
+ } catch (...) {}
+ }
+
+ /// \brief Returns the line number
+ ///
+ /// Returns the line number or zero if it was not specified.
+ int line() const throw() { return _line; }
+
+ /// Returns the error message
+ const std::string& message() const throw() {
+ return _message;
+ }
+
+ /// \brief Returns the filename
+ ///
+ /// Returns the filename or an empty string if it was not specified.
+ const std::string& file() const throw() {
+ return _file;
+ }
+
+ /// \brief Returns a short error message
+ ///
+ /// Returns a short error message which contains the message, the
+ /// file name and the line number.
+ virtual const char* what() const throw() {
+ try {
+ _what.clear();
+ std::ostringstream oss;
+ oss << "lemon:FormatError" << ": ";
+ oss << _message;
+ if (!_file.empty() || _line != 0) {
+ oss << " (";
+ if (!_file.empty()) oss << "in file '" << _file << "'";
+ if (!_file.empty() && _line != 0) oss << " ";
+ if (_line != 0) oss << "at line " << _line;
+ oss << ")";
+ }
+ _what = oss.str();
+ }
+ catch (...) {}
+ if (!_what.empty()) return _what.c_str();
+ else return "lemon:FormatError";
+ }
+
+ };
+
+ /// @}
+
+}
+
+#endif // LEMON_ERROR_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/euler.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/euler.h
new file mode 100644
index 00000000000..3a3cbd0653d
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/euler.h
@@ -0,0 +1,287 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_EULER_H
+#define LEMON_EULER_H
+
+#include<lemon/core.h>
+#include<lemon/adaptors.h>
+#include<lemon/connectivity.h>
+#include <list>
+
+/// \ingroup graph_properties
+/// \file
+/// \brief Euler tour iterators and a function for checking the \e Eulerian
+/// property.
+///
+///This file provides Euler tour iterators and a function to check
+///if a (di)graph is \e Eulerian.
+
+namespace lemon {
+
+ ///Euler tour iterator for digraphs.
+
+ /// \ingroup graph_properties
+ ///This iterator provides an Euler tour (Eulerian circuit) of a \e directed
+ ///graph (if there exists) and it converts to the \c Arc type of the digraph.
+ ///
+ ///For example, if the given digraph has an Euler tour (i.e it has only one
+ ///non-trivial component and the in-degree is equal to the out-degree
+ ///for all nodes), then the following code will put the arcs of \c g
+ ///to the vector \c et according to an Euler tour of \c g.
+ ///\code
+ /// std::vector<ListDigraph::Arc> et;
+ /// for(DiEulerIt<ListDigraph> e(g); e!=INVALID; ++e)
+ /// et.push_back(e);
+ ///\endcode
+ ///If \c g has no Euler tour, then the resulted walk will not be closed
+ ///or not contain all arcs.
+ ///\sa EulerIt
+ template<typename GR>
+ class DiEulerIt
+ {
+ typedef typename GR::Node Node;
+ typedef typename GR::NodeIt NodeIt;
+ typedef typename GR::Arc Arc;
+ typedef typename GR::ArcIt ArcIt;
+ typedef typename GR::OutArcIt OutArcIt;
+ typedef typename GR::InArcIt InArcIt;
+
+ const GR &g;
+ typename GR::template NodeMap<OutArcIt> narc;
+ std::list<Arc> euler;
+
+ public:
+
+ ///Constructor
+
+ ///Constructor.
+ ///\param gr A digraph.
+ ///\param start The starting point of the tour. If it is not given,
+ ///the tour will start from the first node that has an outgoing arc.
+ DiEulerIt(const GR &gr, typename GR::Node start = INVALID)
+ : g(gr), narc(g)
+ {
+ if (start==INVALID) {
+ NodeIt n(g);
+ while (n!=INVALID && OutArcIt(g,n)==INVALID) ++n;
+ start=n;
+ }
+ if (start!=INVALID) {
+ for (NodeIt n(g); n!=INVALID; ++n) narc[n]=OutArcIt(g,n);
+ while (narc[start]!=INVALID) {
+ euler.push_back(narc[start]);
+ Node next=g.target(narc[start]);
+ ++narc[start];
+ start=next;
+ }
+ }
+ }
+
+ ///Arc conversion
+ operator Arc() { return euler.empty()?INVALID:euler.front(); }
+ ///Compare with \c INVALID
+ bool operator==(Invalid) { return euler.empty(); }
+ ///Compare with \c INVALID
+ bool operator!=(Invalid) { return !euler.empty(); }
+
+ ///Next arc of the tour
+
+ ///Next arc of the tour
+ ///
+ DiEulerIt &operator++() {
+ Node s=g.target(euler.front());
+ euler.pop_front();
+ typename std::list<Arc>::iterator next=euler.begin();
+ while(narc[s]!=INVALID) {
+ euler.insert(next,narc[s]);
+ Node n=g.target(narc[s]);
+ ++narc[s];
+ s=n;
+ }
+ return *this;
+ }
+ ///Postfix incrementation
+
+ /// Postfix incrementation.
+ ///
+ ///\warning This incrementation
+ ///returns an \c Arc, not a \ref DiEulerIt, as one may
+ ///expect.
+ Arc operator++(int)
+ {
+ Arc e=*this;
+ ++(*this);
+ return e;
+ }
+ };
+
+ ///Euler tour iterator for graphs.
+
+ /// \ingroup graph_properties
+ ///This iterator provides an Euler tour (Eulerian circuit) of an
+ ///\e undirected graph (if there exists) and it converts to the \c Arc
+ ///and \c Edge types of the graph.
+ ///
+ ///For example, if the given graph has an Euler tour (i.e it has only one
+ ///non-trivial component and the degree of each node is even),
+ ///the following code will print the arc IDs according to an
+ ///Euler tour of \c g.
+ ///\code
+ /// for(EulerIt<ListGraph> e(g); e!=INVALID; ++e) {
+ /// std::cout << g.id(Edge(e)) << std::eol;
+ /// }
+ ///\endcode
+ ///Although this iterator is for undirected graphs, it still returns
+ ///arcs in order to indicate the direction of the tour.
+ ///(But arcs convert to edges, of course.)
+ ///
+ ///If \c g has no Euler tour, then the resulted walk will not be closed
+ ///or not contain all edges.
+ template<typename GR>
+ class EulerIt
+ {
+ typedef typename GR::Node Node;
+ typedef typename GR::NodeIt NodeIt;
+ typedef typename GR::Arc Arc;
+ typedef typename GR::Edge Edge;
+ typedef typename GR::ArcIt ArcIt;
+ typedef typename GR::OutArcIt OutArcIt;
+ typedef typename GR::InArcIt InArcIt;
+
+ const GR &g;
+ typename GR::template NodeMap<OutArcIt> narc;
+ typename GR::template EdgeMap<bool> visited;
+ std::list<Arc> euler;
+
+ public:
+
+ ///Constructor
+
+ ///Constructor.
+ ///\param gr A graph.
+ ///\param start The starting point of the tour. If it is not given,
+ ///the tour will start from the first node that has an incident edge.
+ EulerIt(const GR &gr, typename GR::Node start = INVALID)
+ : g(gr), narc(g), visited(g, false)
+ {
+ if (start==INVALID) {
+ NodeIt n(g);
+ while (n!=INVALID && OutArcIt(g,n)==INVALID) ++n;
+ start=n;
+ }
+ if (start!=INVALID) {
+ for (NodeIt n(g); n!=INVALID; ++n) narc[n]=OutArcIt(g,n);
+ while(narc[start]!=INVALID) {
+ euler.push_back(narc[start]);
+ visited[narc[start]]=true;
+ Node next=g.target(narc[start]);
+ ++narc[start];
+ start=next;
+ while(narc[start]!=INVALID && visited[narc[start]]) ++narc[start];
+ }
+ }
+ }
+
+ ///Arc conversion
+ operator Arc() const { return euler.empty()?INVALID:euler.front(); }
+ ///Edge conversion
+ operator Edge() const { return euler.empty()?INVALID:euler.front(); }
+ ///Compare with \c INVALID
+ bool operator==(Invalid) const { return euler.empty(); }
+ ///Compare with \c INVALID
+ bool operator!=(Invalid) const { return !euler.empty(); }
+
+ ///Next arc of the tour
+
+ ///Next arc of the tour
+ ///
+ EulerIt &operator++() {
+ Node s=g.target(euler.front());
+ euler.pop_front();
+ typename std::list<Arc>::iterator next=euler.begin();
+ while(narc[s]!=INVALID) {
+ while(narc[s]!=INVALID && visited[narc[s]]) ++narc[s];
+ if(narc[s]==INVALID) break;
+ else {
+ euler.insert(next,narc[s]);
+ visited[narc[s]]=true;
+ Node n=g.target(narc[s]);
+ ++narc[s];
+ s=n;
+ }
+ }
+ return *this;
+ }
+
+ ///Postfix incrementation
+
+ /// Postfix incrementation.
+ ///
+ ///\warning This incrementation returns an \c Arc (which converts to
+ ///an \c Edge), not an \ref EulerIt, as one may expect.
+ Arc operator++(int)
+ {
+ Arc e=*this;
+ ++(*this);
+ return e;
+ }
+ };
+
+
+ ///Check if the given graph is Eulerian
+
+ /// \ingroup graph_properties
+ ///This function checks if the given graph is Eulerian.
+ ///It works for both directed and undirected graphs.
+ ///
+ ///By definition, a digraph is called \e Eulerian if
+ ///and only if it is connected and the number of incoming and outgoing
+ ///arcs are the same for each node.
+ ///Similarly, an undirected graph is called \e Eulerian if
+ ///and only if it is connected and the number of incident edges is even
+ ///for each node.
+ ///
+ ///\note There are (di)graphs that are not Eulerian, but still have an
+ /// Euler tour, since they may contain isolated nodes.
+ ///
+ ///\sa DiEulerIt, EulerIt
+ template<typename GR>
+#ifdef DOXYGEN
+ bool
+#else
+ typename enable_if<UndirectedTagIndicator<GR>,bool>::type
+ eulerian(const GR &g)
+ {
+ for(typename GR::NodeIt n(g);n!=INVALID;++n)
+ if(countIncEdges(g,n)%2) return false;
+ return connected(g);
+ }
+ template<class GR>
+ typename disable_if<UndirectedTagIndicator<GR>,bool>::type
+#endif
+ eulerian(const GR &g)
+ {
+ for(typename GR::NodeIt n(g);n!=INVALID;++n)
+ if(countInArcs(g,n)!=countOutArcs(g,n)) return false;
+ return connected(undirector(g));
+ }
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/fib_heap.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/fib_heap.h
new file mode 100644
index 00000000000..3441722a034
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/fib_heap.h
@@ -0,0 +1,475 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_FIB_HEAP_H
+#define LEMON_FIB_HEAP_H
+
+///\file
+///\ingroup heaps
+///\brief Fibonacci heap implementation.
+
+#include <vector>
+#include <utility>
+#include <functional>
+#include <lemon/math.h>
+
+namespace lemon {
+
+ /// \ingroup heaps
+ ///
+ /// \brief Fibonacci heap data structure.
+ ///
+ /// This class implements the \e Fibonacci \e heap data structure.
+ /// It fully conforms to the \ref concepts::Heap "heap concept".
+ ///
+ /// The methods \ref increase() and \ref erase() are not efficient in a
+ /// Fibonacci heap. In case of many calls of these operations, it is
+ /// better to use other heap structure, e.g. \ref BinHeap "binary heap".
+ ///
+ /// \tparam PR Type of the priorities of the items.
+ /// \tparam IM A read-writable item map with \c int values, used
+ /// internally to handle the cross references.
+ /// \tparam CMP A functor class for comparing the priorities.
+ /// The default is \c std::less<PR>.
+#ifdef DOXYGEN
+ template <typename PR, typename IM, typename CMP>
+#else
+ template <typename PR, typename IM, typename CMP = std::less<PR> >
+#endif
+ class FibHeap {
+ public:
+
+ /// Type of the item-int map.
+ typedef IM ItemIntMap;
+ /// Type of the priorities.
+ typedef PR Prio;
+ /// Type of the items stored in the heap.
+ typedef typename ItemIntMap::Key Item;
+ /// Type of the item-priority pairs.
+ typedef std::pair<Item,Prio> Pair;
+ /// Functor type for comparing the priorities.
+ typedef CMP Compare;
+
+ private:
+ class Store;
+
+ std::vector<Store> _data;
+ int _minimum;
+ ItemIntMap &_iim;
+ Compare _comp;
+ int _num;
+
+ public:
+
+ /// \brief Type to represent the states of the items.
+ ///
+ /// Each item has a state associated to it. It can be "in heap",
+ /// "pre-heap" or "post-heap". The latter two are indifferent from the
+ /// heap's point of view, but may be useful to the user.
+ ///
+ /// The item-int map must be initialized in such way that it assigns
+ /// \c PRE_HEAP (<tt>-1</tt>) to any element to be put in the heap.
+ enum State {
+ IN_HEAP = 0, ///< = 0.
+ PRE_HEAP = -1, ///< = -1.
+ POST_HEAP = -2 ///< = -2.
+ };
+
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ /// \param map A map that assigns \c int values to the items.
+ /// It is used internally to handle the cross references.
+ /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
+ explicit FibHeap(ItemIntMap &map)
+ : _minimum(0), _iim(map), _num() {}
+
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ /// \param map A map that assigns \c int values to the items.
+ /// It is used internally to handle the cross references.
+ /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
+ /// \param comp The function object used for comparing the priorities.
+ FibHeap(ItemIntMap &map, const Compare &comp)
+ : _minimum(0), _iim(map), _comp(comp), _num() {}
+
+ /// \brief The number of items stored in the heap.
+ ///
+ /// This function returns the number of items stored in the heap.
+ int size() const { return _num; }
+
+ /// \brief Check if the heap is empty.
+ ///
+ /// This function returns \c true if the heap is empty.
+ bool empty() const { return _num==0; }
+
+ /// \brief Make the heap empty.
+ ///
+ /// This functon makes the heap empty.
+ /// It does not change the cross reference map. If you want to reuse
+ /// a heap that is not surely empty, you should first clear it and
+ /// then you should set the cross reference map to \c PRE_HEAP
+ /// for each item.
+ void clear() {
+ _data.clear(); _minimum = 0; _num = 0;
+ }
+
+ /// \brief Insert an item into the heap with the given priority.
+ ///
+ /// This function inserts the given item into the heap with the
+ /// given priority.
+ /// \param item The item to insert.
+ /// \param prio The priority of the item.
+ /// \pre \e item must not be stored in the heap.
+ void push (const Item& item, const Prio& prio) {
+ int i=_iim[item];
+ if ( i < 0 ) {
+ int s=_data.size();
+ _iim.set( item, s );
+ Store st;
+ st.name=item;
+ _data.push_back(st);
+ i=s;
+ } else {
+ _data[i].parent=_data[i].child=-1;
+ _data[i].degree=0;
+ _data[i].in=true;
+ _data[i].marked=false;
+ }
+
+ if ( _num ) {
+ _data[_data[_minimum].right_neighbor].left_neighbor=i;
+ _data[i].right_neighbor=_data[_minimum].right_neighbor;
+ _data[_minimum].right_neighbor=i;
+ _data[i].left_neighbor=_minimum;
+ if ( _comp( prio, _data[_minimum].prio) ) _minimum=i;
+ } else {
+ _data[i].right_neighbor=_data[i].left_neighbor=i;
+ _minimum=i;
+ }
+ _data[i].prio=prio;
+ ++_num;
+ }
+
+ /// \brief Return the item having minimum priority.
+ ///
+ /// This function returns the item having minimum priority.
+ /// \pre The heap must be non-empty.
+ Item top() const { return _data[_minimum].name; }
+
+ /// \brief The minimum priority.
+ ///
+ /// This function returns the minimum priority.
+ /// \pre The heap must be non-empty.
+ Prio prio() const { return _data[_minimum].prio; }
+
+ /// \brief Remove the item having minimum priority.
+ ///
+ /// This function removes the item having minimum priority.
+ /// \pre The heap must be non-empty.
+ void pop() {
+ /*The first case is that there are only one root.*/
+ if ( _data[_minimum].left_neighbor==_minimum ) {
+ _data[_minimum].in=false;
+ if ( _data[_minimum].degree!=0 ) {
+ makeRoot(_data[_minimum].child);
+ _minimum=_data[_minimum].child;
+ balance();
+ }
+ } else {
+ int right=_data[_minimum].right_neighbor;
+ unlace(_minimum);
+ _data[_minimum].in=false;
+ if ( _data[_minimum].degree > 0 ) {
+ int left=_data[_minimum].left_neighbor;
+ int child=_data[_minimum].child;
+ int last_child=_data[child].left_neighbor;
+
+ makeRoot(child);
+
+ _data[left].right_neighbor=child;
+ _data[child].left_neighbor=left;
+ _data[right].left_neighbor=last_child;
+ _data[last_child].right_neighbor=right;
+ }
+ _minimum=right;
+ balance();
+ } // the case where there are more roots
+ --_num;
+ }
+
+ /// \brief Remove the given item from the heap.
+ ///
+ /// This function removes the given item from the heap if it is
+ /// already stored.
+ /// \param item The item to delete.
+ /// \pre \e item must be in the heap.
+ void erase (const Item& item) {
+ int i=_iim[item];
+
+ if ( i >= 0 && _data[i].in ) {
+ if ( _data[i].parent!=-1 ) {
+ int p=_data[i].parent;
+ cut(i,p);
+ cascade(p);
+ }
+ _minimum=i; //As if its prio would be -infinity
+ pop();
+ }
+ }
+
+ /// \brief The priority of the given item.
+ ///
+ /// This function returns the priority of the given item.
+ /// \param item The item.
+ /// \pre \e item must be in the heap.
+ Prio operator[](const Item& item) const {
+ return _data[_iim[item]].prio;
+ }
+
+ /// \brief Set the priority of an item or insert it, if it is
+ /// not stored in the heap.
+ ///
+ /// This method sets the priority of the given item if it is
+ /// already stored in the heap. Otherwise it inserts the given
+ /// item into the heap with the given priority.
+ /// \param item The item.
+ /// \param prio The priority.
+ void set (const Item& item, const Prio& prio) {
+ int i=_iim[item];
+ if ( i >= 0 && _data[i].in ) {
+ if ( _comp(prio, _data[i].prio) ) decrease(item, prio);
+ if ( _comp(_data[i].prio, prio) ) increase(item, prio);
+ } else push(item, prio);
+ }
+
+ /// \brief Decrease the priority of an item to the given value.
+ ///
+ /// This function decreases the priority of an item to the given value.
+ /// \param item The item.
+ /// \param prio The priority.
+ /// \pre \e item must be stored in the heap with priority at least \e prio.
+ void decrease (const Item& item, const Prio& prio) {
+ int i=_iim[item];
+ _data[i].prio=prio;
+ int p=_data[i].parent;
+
+ if ( p!=-1 && _comp(prio, _data[p].prio) ) {
+ cut(i,p);
+ cascade(p);
+ }
+ if ( _comp(prio, _data[_minimum].prio) ) _minimum=i;
+ }
+
+ /// \brief Increase the priority of an item to the given value.
+ ///
+ /// This function increases the priority of an item to the given value.
+ /// \param item The item.
+ /// \param prio The priority.
+ /// \pre \e item must be stored in the heap with priority at most \e prio.
+ void increase (const Item& item, const Prio& prio) {
+ erase(item);
+ push(item, prio);
+ }
+
+ /// \brief Return the state of an item.
+ ///
+ /// This method returns \c PRE_HEAP if the given item has never
+ /// been in the heap, \c IN_HEAP if it is in the heap at the moment,
+ /// and \c POST_HEAP otherwise.
+ /// In the latter case it is possible that the item will get back
+ /// to the heap again.
+ /// \param item The item.
+ State state(const Item &item) const {
+ int i=_iim[item];
+ if( i>=0 ) {
+ if ( _data[i].in ) i=0;
+ else i=-2;
+ }
+ return State(i);
+ }
+
+ /// \brief Set the state of an item in the heap.
+ ///
+ /// This function sets the state of the given item in the heap.
+ /// It can be used to manually clear the heap when it is important
+ /// to achive better time complexity.
+ /// \param i The item.
+ /// \param st The state. It should not be \c IN_HEAP.
+ void state(const Item& i, State st) {
+ switch (st) {
+ case POST_HEAP:
+ case PRE_HEAP:
+ if (state(i) == IN_HEAP) {
+ erase(i);
+ }
+ _iim[i] = st;
+ break;
+ case IN_HEAP:
+ break;
+ }
+ }
+
+ private:
+
+ void balance() {
+
+ int maxdeg=int( std::floor( 2.08*log(double(_data.size()))))+1;
+
+ std::vector<int> A(maxdeg,-1);
+
+ /*
+ *Recall that now minimum does not point to the minimum prio element.
+ *We set minimum to this during balance().
+ */
+ int anchor=_data[_minimum].left_neighbor;
+ int next=_minimum;
+ bool end=false;
+
+ do {
+ int active=next;
+ if ( anchor==active ) end=true;
+ int d=_data[active].degree;
+ next=_data[active].right_neighbor;
+
+ while (A[d]!=-1) {
+ if( _comp(_data[active].prio, _data[A[d]].prio) ) {
+ fuse(active,A[d]);
+ } else {
+ fuse(A[d],active);
+ active=A[d];
+ }
+ A[d]=-1;
+ ++d;
+ }
+ A[d]=active;
+ } while ( !end );
+
+
+ while ( _data[_minimum].parent >=0 )
+ _minimum=_data[_minimum].parent;
+ int s=_minimum;
+ int m=_minimum;
+ do {
+ if ( _comp(_data[s].prio, _data[_minimum].prio) ) _minimum=s;
+ s=_data[s].right_neighbor;
+ } while ( s != m );
+ }
+
+ void makeRoot(int c) {
+ int s=c;
+ do {
+ _data[s].parent=-1;
+ s=_data[s].right_neighbor;
+ } while ( s != c );
+ }
+
+ void cut(int a, int b) {
+ /*
+ *Replacing a from the children of b.
+ */
+ --_data[b].degree;
+
+ if ( _data[b].degree !=0 ) {
+ int child=_data[b].child;
+ if ( child==a )
+ _data[b].child=_data[child].right_neighbor;
+ unlace(a);
+ }
+
+
+ /*Lacing a to the roots.*/
+ int right=_data[_minimum].right_neighbor;
+ _data[_minimum].right_neighbor=a;
+ _data[a].left_neighbor=_minimum;
+ _data[a].right_neighbor=right;
+ _data[right].left_neighbor=a;
+
+ _data[a].parent=-1;
+ _data[a].marked=false;
+ }
+
+ void cascade(int a) {
+ if ( _data[a].parent!=-1 ) {
+ int p=_data[a].parent;
+
+ if ( _data[a].marked==false ) _data[a].marked=true;
+ else {
+ cut(a,p);
+ cascade(p);
+ }
+ }
+ }
+
+ void fuse(int a, int b) {
+ unlace(b);
+
+ /*Lacing b under a.*/
+ _data[b].parent=a;
+
+ if (_data[a].degree==0) {
+ _data[b].left_neighbor=b;
+ _data[b].right_neighbor=b;
+ _data[a].child=b;
+ } else {
+ int child=_data[a].child;
+ int last_child=_data[child].left_neighbor;
+ _data[child].left_neighbor=b;
+ _data[b].right_neighbor=child;
+ _data[last_child].right_neighbor=b;
+ _data[b].left_neighbor=last_child;
+ }
+
+ ++_data[a].degree;
+
+ _data[b].marked=false;
+ }
+
+ /*
+ *It is invoked only if a has siblings.
+ */
+ void unlace(int a) {
+ int leftn=_data[a].left_neighbor;
+ int rightn=_data[a].right_neighbor;
+ _data[leftn].right_neighbor=rightn;
+ _data[rightn].left_neighbor=leftn;
+ }
+
+
+ class Store {
+ friend class FibHeap;
+
+ Item name;
+ int parent;
+ int left_neighbor;
+ int right_neighbor;
+ int child;
+ int degree;
+ bool marked;
+ bool in;
+ Prio prio;
+
+ Store() : parent(-1), child(-1), degree(), marked(false), in(true) {}
+ };
+ };
+
+} //namespace lemon
+
+#endif //LEMON_FIB_HEAP_H
+
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/fractional_matching.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/fractional_matching.h
new file mode 100644
index 00000000000..7448f411d93
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/fractional_matching.h
@@ -0,0 +1,2139 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_FRACTIONAL_MATCHING_H
+#define LEMON_FRACTIONAL_MATCHING_H
+
+#include <vector>
+#include <queue>
+#include <set>
+#include <limits>
+
+#include <lemon/core.h>
+#include <lemon/unionfind.h>
+#include <lemon/bin_heap.h>
+#include <lemon/maps.h>
+#include <lemon/assert.h>
+#include <lemon/elevator.h>
+
+///\ingroup matching
+///\file
+///\brief Fractional matching algorithms in general graphs.
+
+namespace lemon {
+
+ /// \brief Default traits class of MaxFractionalMatching class.
+ ///
+ /// Default traits class of MaxFractionalMatching class.
+ /// \tparam GR Graph type.
+ template <typename GR>
+ struct MaxFractionalMatchingDefaultTraits {
+
+ /// \brief The type of the graph the algorithm runs on.
+ typedef GR Graph;
+
+ /// \brief The type of the map that stores the matching.
+ ///
+ /// The type of the map that stores the matching arcs.
+ /// It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept.
+ typedef typename Graph::template NodeMap<typename GR::Arc> MatchingMap;
+
+ /// \brief Instantiates a MatchingMap.
+ ///
+ /// This function instantiates a \ref MatchingMap.
+ /// \param graph The graph for which we would like to define
+ /// the matching map.
+ static MatchingMap* createMatchingMap(const Graph& graph) {
+ return new MatchingMap(graph);
+ }
+
+ /// \brief The elevator type used by MaxFractionalMatching algorithm.
+ ///
+ /// The elevator type used by MaxFractionalMatching algorithm.
+ ///
+ /// \sa Elevator
+ /// \sa LinkedElevator
+ typedef LinkedElevator<Graph, typename Graph::Node> Elevator;
+
+ /// \brief Instantiates an Elevator.
+ ///
+ /// This function instantiates an \ref Elevator.
+ /// \param graph The graph for which we would like to define
+ /// the elevator.
+ /// \param max_level The maximum level of the elevator.
+ static Elevator* createElevator(const Graph& graph, int max_level) {
+ return new Elevator(graph, max_level);
+ }
+ };
+
+ /// \ingroup matching
+ ///
+ /// \brief Max cardinality fractional matching
+ ///
+ /// This class provides an implementation of fractional matching
+ /// algorithm based on push-relabel principle.
+ ///
+ /// The maximum cardinality fractional matching is a relaxation of the
+ /// maximum cardinality matching problem where the odd set constraints
+ /// are omitted.
+ /// It can be formulated with the following linear program.
+ /// \f[ \sum_{e \in \delta(u)}x_e \le 1 \quad \forall u\in V\f]
+ /// \f[x_e \ge 0\quad \forall e\in E\f]
+ /// \f[\max \sum_{e\in E}x_e\f]
+ /// where \f$\delta(X)\f$ is the set of edges incident to a node in
+ /// \f$X\f$. The result can be represented as the union of a
+ /// matching with one value edges and a set of odd length cycles
+ /// with half value edges.
+ ///
+ /// The algorithm calculates an optimal fractional matching and a
+ /// barrier. The number of adjacents of any node set minus the size
+ /// of node set is a lower bound on the uncovered nodes in the
+ /// graph. For maximum matching a barrier is computed which
+ /// maximizes this difference.
+ ///
+ /// The algorithm can be executed with the run() function. After it
+ /// the matching (the primal solution) and the barrier (the dual
+ /// solution) can be obtained using the query functions.
+ ///
+ /// The primal solution is multiplied by
+ /// \ref MaxFractionalMatching::primalScale "2".
+ ///
+ /// \tparam GR The undirected graph type the algorithm runs on.
+#ifdef DOXYGEN
+ template <typename GR, typename TR>
+#else
+ template <typename GR,
+ typename TR = MaxFractionalMatchingDefaultTraits<GR> >
+#endif
+ class MaxFractionalMatching {
+ public:
+
+ /// \brief The \ref lemon::MaxFractionalMatchingDefaultTraits
+ /// "traits class" of the algorithm.
+ typedef TR Traits;
+ /// The type of the graph the algorithm runs on.
+ typedef typename TR::Graph Graph;
+ /// The type of the matching map.
+ typedef typename TR::MatchingMap MatchingMap;
+ /// The type of the elevator.
+ typedef typename TR::Elevator Elevator;
+
+ /// \brief Scaling factor for primal solution
+ ///
+ /// Scaling factor for primal solution.
+ static const int primalScale = 2;
+
+ private:
+
+ const Graph &_graph;
+ int _node_num;
+ bool _allow_loops;
+ int _empty_level;
+
+ TEMPLATE_GRAPH_TYPEDEFS(Graph);
+
+ bool _local_matching;
+ MatchingMap *_matching;
+
+ bool _local_level;
+ Elevator *_level;
+
+ typedef typename Graph::template NodeMap<int> InDegMap;
+ InDegMap *_indeg;
+
+ void createStructures() {
+ _node_num = countNodes(_graph);
+
+ if (!_matching) {
+ _local_matching = true;
+ _matching = Traits::createMatchingMap(_graph);
+ }
+ if (!_level) {
+ _local_level = true;
+ _level = Traits::createElevator(_graph, _node_num);
+ }
+ if (!_indeg) {
+ _indeg = new InDegMap(_graph);
+ }
+ }
+
+ void destroyStructures() {
+ if (_local_matching) {
+ delete _matching;
+ }
+ if (_local_level) {
+ delete _level;
+ }
+ if (_indeg) {
+ delete _indeg;
+ }
+ }
+
+ void postprocessing() {
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ if ((*_indeg)[n] != 0) continue;
+ _indeg->set(n, -1);
+ Node u = n;
+ while ((*_matching)[u] != INVALID) {
+ Node v = _graph.target((*_matching)[u]);
+ _indeg->set(v, -1);
+ Arc a = _graph.oppositeArc((*_matching)[u]);
+ u = _graph.target((*_matching)[v]);
+ _indeg->set(u, -1);
+ _matching->set(v, a);
+ }
+ }
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ if ((*_indeg)[n] != 1) continue;
+ _indeg->set(n, -1);
+
+ int num = 1;
+ Node u = _graph.target((*_matching)[n]);
+ while (u != n) {
+ _indeg->set(u, -1);
+ u = _graph.target((*_matching)[u]);
+ ++num;
+ }
+ if (num % 2 == 0 && num > 2) {
+ Arc prev = _graph.oppositeArc((*_matching)[n]);
+ Node v = _graph.target((*_matching)[n]);
+ u = _graph.target((*_matching)[v]);
+ _matching->set(v, prev);
+ while (u != n) {
+ prev = _graph.oppositeArc((*_matching)[u]);
+ v = _graph.target((*_matching)[u]);
+ u = _graph.target((*_matching)[v]);
+ _matching->set(v, prev);
+ }
+ }
+ }
+ }
+
+ public:
+
+ typedef MaxFractionalMatching Create;
+
+ ///\name Named Template Parameters
+
+ ///@{
+
+ template <typename T>
+ struct SetMatchingMapTraits : public Traits {
+ typedef T MatchingMap;
+ static MatchingMap *createMatchingMap(const Graph&) {
+ LEMON_ASSERT(false, "MatchingMap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// MatchingMap type
+ ///
+ /// \ref named-templ-param "Named parameter" for setting MatchingMap
+ /// type.
+ template <typename T>
+ struct SetMatchingMap
+ : public MaxFractionalMatching<Graph, SetMatchingMapTraits<T> > {
+ typedef MaxFractionalMatching<Graph, SetMatchingMapTraits<T> > Create;
+ };
+
+ template <typename T>
+ struct SetElevatorTraits : public Traits {
+ typedef T Elevator;
+ static Elevator *createElevator(const Graph&, int) {
+ LEMON_ASSERT(false, "Elevator is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// Elevator type
+ ///
+ /// \ref named-templ-param "Named parameter" for setting Elevator
+ /// type. If this named parameter is used, then an external
+ /// elevator object must be passed to the algorithm using the
+ /// \ref elevator(Elevator&) "elevator()" function before calling
+ /// \ref run() or \ref init().
+ /// \sa SetStandardElevator
+ template <typename T>
+ struct SetElevator
+ : public MaxFractionalMatching<Graph, SetElevatorTraits<T> > {
+ typedef MaxFractionalMatching<Graph, SetElevatorTraits<T> > Create;
+ };
+
+ template <typename T>
+ struct SetStandardElevatorTraits : public Traits {
+ typedef T Elevator;
+ static Elevator *createElevator(const Graph& graph, int max_level) {
+ return new Elevator(graph, max_level);
+ }
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// Elevator type with automatic allocation
+ ///
+ /// \ref named-templ-param "Named parameter" for setting Elevator
+ /// type with automatic allocation.
+ /// The Elevator should have standard constructor interface to be
+ /// able to automatically created by the algorithm (i.e. the
+ /// graph and the maximum level should be passed to it).
+ /// However an external elevator object could also be passed to the
+ /// algorithm with the \ref elevator(Elevator&) "elevator()" function
+ /// before calling \ref run() or \ref init().
+ /// \sa SetElevator
+ template <typename T>
+ struct SetStandardElevator
+ : public MaxFractionalMatching<Graph, SetStandardElevatorTraits<T> > {
+ typedef MaxFractionalMatching<Graph,
+ SetStandardElevatorTraits<T> > Create;
+ };
+
+ /// @}
+
+ protected:
+
+ MaxFractionalMatching() {}
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ ///
+ MaxFractionalMatching(const Graph &graph, bool allow_loops = true)
+ : _graph(graph), _allow_loops(allow_loops),
+ _local_matching(false), _matching(0),
+ _local_level(false), _level(0), _indeg(0)
+ {}
+
+ ~MaxFractionalMatching() {
+ destroyStructures();
+ }
+
+ /// \brief Sets the matching map.
+ ///
+ /// Sets the matching map.
+ /// If you don't use this function before calling \ref run() or
+ /// \ref init(), an instance will be allocated automatically.
+ /// The destructor deallocates this automatically allocated map,
+ /// of course.
+ /// \return <tt>(*this)</tt>
+ MaxFractionalMatching& matchingMap(MatchingMap& map) {
+ if (_local_matching) {
+ delete _matching;
+ _local_matching = false;
+ }
+ _matching = &map;
+ return *this;
+ }
+
+ /// \brief Sets the elevator used by algorithm.
+ ///
+ /// Sets the elevator used by algorithm.
+ /// If you don't use this function before calling \ref run() or
+ /// \ref init(), an instance will be allocated automatically.
+ /// The destructor deallocates this automatically allocated elevator,
+ /// of course.
+ /// \return <tt>(*this)</tt>
+ MaxFractionalMatching& elevator(Elevator& elevator) {
+ if (_local_level) {
+ delete _level;
+ _local_level = false;
+ }
+ _level = &elevator;
+ return *this;
+ }
+
+ /// \brief Returns a const reference to the elevator.
+ ///
+ /// Returns a const reference to the elevator.
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ const Elevator& elevator() const {
+ return *_level;
+ }
+
+ /// \name Execution control
+ /// The simplest way to execute the algorithm is to use one of the
+ /// member functions called \c run(). \n
+ /// If you need more control on the execution, first
+ /// you must call \ref init() and then one variant of the start()
+ /// member.
+
+ /// @{
+
+ /// \brief Initializes the internal data structures.
+ ///
+ /// Initializes the internal data structures and sets the initial
+ /// matching.
+ void init() {
+ createStructures();
+
+ _level->initStart();
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ _indeg->set(n, 0);
+ _matching->set(n, INVALID);
+ _level->initAddItem(n);
+ }
+ _level->initFinish();
+
+ _empty_level = _node_num;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ for (OutArcIt a(_graph, n); a != INVALID; ++a) {
+ if (_graph.target(a) == n && !_allow_loops) continue;
+ _matching->set(n, a);
+ Node v = _graph.target((*_matching)[n]);
+ _indeg->set(v, (*_indeg)[v] + 1);
+ break;
+ }
+ }
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ if ((*_indeg)[n] == 0) {
+ _level->activate(n);
+ }
+ }
+ }
+
+ /// \brief Starts the algorithm and computes a fractional matching
+ ///
+ /// The algorithm computes a maximum fractional matching.
+ ///
+ /// \param postprocess The algorithm computes first a matching
+ /// which is a union of a matching with one value edges, cycles
+ /// with half value edges and even length paths with half value
+ /// edges. If the parameter is true, then after the push-relabel
+ /// algorithm it postprocesses the matching to contain only
+ /// matching edges and half value odd cycles.
+ void start(bool postprocess = true) {
+ Node n;
+ while ((n = _level->highestActive()) != INVALID) {
+ int level = _level->highestActiveLevel();
+ int new_level = _level->maxLevel();
+ for (InArcIt a(_graph, n); a != INVALID; ++a) {
+ Node u = _graph.source(a);
+ if (n == u && !_allow_loops) continue;
+ Node v = _graph.target((*_matching)[u]);
+ if ((*_level)[v] < level) {
+ _indeg->set(v, (*_indeg)[v] - 1);
+ if ((*_indeg)[v] == 0) {
+ _level->activate(v);
+ }
+ _matching->set(u, a);
+ _indeg->set(n, (*_indeg)[n] + 1);
+ _level->deactivate(n);
+ goto no_more_push;
+ } else if (new_level > (*_level)[v]) {
+ new_level = (*_level)[v];
+ }
+ }
+
+ if (new_level + 1 < _level->maxLevel()) {
+ _level->liftHighestActive(new_level + 1);
+ } else {
+ _level->liftHighestActiveToTop();
+ }
+ if (_level->emptyLevel(level)) {
+ _level->liftToTop(level);
+ }
+ no_more_push:
+ ;
+ }
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ if ((*_matching)[n] == INVALID) continue;
+ Node u = _graph.target((*_matching)[n]);
+ if ((*_indeg)[u] > 1) {
+ _indeg->set(u, (*_indeg)[u] - 1);
+ _matching->set(n, INVALID);
+ }
+ }
+ if (postprocess) {
+ postprocessing();
+ }
+ }
+
+ /// \brief Starts the algorithm and computes a perfect fractional
+ /// matching
+ ///
+ /// The algorithm computes a perfect fractional matching. If it
+ /// does not exists, then the algorithm returns false and the
+ /// matching is undefined and the barrier.
+ ///
+ /// \param postprocess The algorithm computes first a matching
+ /// which is a union of a matching with one value edges, cycles
+ /// with half value edges and even length paths with half value
+ /// edges. If the parameter is true, then after the push-relabel
+ /// algorithm it postprocesses the matching to contain only
+ /// matching edges and half value odd cycles.
+ bool startPerfect(bool postprocess = true) {
+ Node n;
+ while ((n = _level->highestActive()) != INVALID) {
+ int level = _level->highestActiveLevel();
+ int new_level = _level->maxLevel();
+ for (InArcIt a(_graph, n); a != INVALID; ++a) {
+ Node u = _graph.source(a);
+ if (n == u && !_allow_loops) continue;
+ Node v = _graph.target((*_matching)[u]);
+ if ((*_level)[v] < level) {
+ _indeg->set(v, (*_indeg)[v] - 1);
+ if ((*_indeg)[v] == 0) {
+ _level->activate(v);
+ }
+ _matching->set(u, a);
+ _indeg->set(n, (*_indeg)[n] + 1);
+ _level->deactivate(n);
+ goto no_more_push;
+ } else if (new_level > (*_level)[v]) {
+ new_level = (*_level)[v];
+ }
+ }
+
+ if (new_level + 1 < _level->maxLevel()) {
+ _level->liftHighestActive(new_level + 1);
+ } else {
+ _level->liftHighestActiveToTop();
+ _empty_level = _level->maxLevel() - 1;
+ return false;
+ }
+ if (_level->emptyLevel(level)) {
+ _level->liftToTop(level);
+ _empty_level = level;
+ return false;
+ }
+ no_more_push:
+ ;
+ }
+ if (postprocess) {
+ postprocessing();
+ }
+ return true;
+ }
+
+ /// \brief Runs the algorithm
+ ///
+ /// Just a shortcut for the next code:
+ ///\code
+ /// init();
+ /// start();
+ ///\endcode
+ void run(bool postprocess = true) {
+ init();
+ start(postprocess);
+ }
+
+ /// \brief Runs the algorithm to find a perfect fractional matching
+ ///
+ /// Just a shortcut for the next code:
+ ///\code
+ /// init();
+ /// startPerfect();
+ ///\endcode
+ bool runPerfect(bool postprocess = true) {
+ init();
+ return startPerfect(postprocess);
+ }
+
+ ///@}
+
+ /// \name Query Functions
+ /// The result of the %Matching algorithm can be obtained using these
+ /// functions.\n
+ /// Before the use of these functions,
+ /// either run() or start() must be called.
+ ///@{
+
+
+ /// \brief Return the number of covered nodes in the matching.
+ ///
+ /// This function returns the number of covered nodes in the matching.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ int matchingSize() const {
+ int num = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ if ((*_matching)[n] != INVALID) {
+ ++num;
+ }
+ }
+ return num;
+ }
+
+ /// \brief Returns a const reference to the matching map.
+ ///
+ /// Returns a const reference to the node map storing the found
+ /// fractional matching. This method can be called after
+ /// running the algorithm.
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ const MatchingMap& matchingMap() const {
+ return *_matching;
+ }
+
+ /// \brief Return \c true if the given edge is in the matching.
+ ///
+ /// This function returns \c true if the given edge is in the
+ /// found matching. The result is scaled by \ref primalScale
+ /// "primal scale".
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ int matching(const Edge& edge) const {
+ return (edge == (*_matching)[_graph.u(edge)] ? 1 : 0) +
+ (edge == (*_matching)[_graph.v(edge)] ? 1 : 0);
+ }
+
+ /// \brief Return the fractional matching arc (or edge) incident
+ /// to the given node.
+ ///
+ /// This function returns one of the fractional matching arc (or
+ /// edge) incident to the given node in the found matching or \c
+ /// INVALID if the node is not covered by the matching or if the
+ /// node is on an odd length cycle then it is the successor edge
+ /// on the cycle.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Arc matching(const Node& node) const {
+ return (*_matching)[node];
+ }
+
+ /// \brief Returns true if the node is in the barrier
+ ///
+ /// The barrier is a subset of the nodes. If the nodes in the
+ /// barrier have less adjacent nodes than the size of the barrier,
+ /// then at least as much nodes cannot be covered as the
+ /// difference of the two subsets.
+ bool barrier(const Node& node) const {
+ return (*_level)[node] >= _empty_level;
+ }
+
+ /// @}
+
+ };
+
+ /// \ingroup matching
+ ///
+ /// \brief Weighted fractional matching in general graphs
+ ///
+ /// This class provides an efficient implementation of fractional
+ /// matching algorithm. The implementation uses priority queues and
+ /// provides \f$O(nm\log n)\f$ time complexity.
+ ///
+ /// The maximum weighted fractional matching is a relaxation of the
+ /// maximum weighted matching problem where the odd set constraints
+ /// are omitted.
+ /// It can be formulated with the following linear program.
+ /// \f[ \sum_{e \in \delta(u)}x_e \le 1 \quad \forall u\in V\f]
+ /// \f[x_e \ge 0\quad \forall e\in E\f]
+ /// \f[\max \sum_{e\in E}x_ew_e\f]
+ /// where \f$\delta(X)\f$ is the set of edges incident to a node in
+ /// \f$X\f$. The result must be the union of a matching with one
+ /// value edges and a set of odd length cycles with half value edges.
+ ///
+ /// The algorithm calculates an optimal fractional matching and a
+ /// proof of the optimality. The solution of the dual problem can be
+ /// used to check the result of the algorithm. The dual linear
+ /// problem is the following.
+ /// \f[ y_u + y_v \ge w_{uv} \quad \forall uv\in E\f]
+ /// \f[y_u \ge 0 \quad \forall u \in V\f]
+ /// \f[\min \sum_{u \in V}y_u \f]
+ ///
+ /// The algorithm can be executed with the run() function.
+ /// After it the matching (the primal solution) and the dual solution
+ /// can be obtained using the query functions.
+ ///
+ /// The primal solution is multiplied by
+ /// \ref MaxWeightedFractionalMatching::primalScale "2".
+ /// If the value type is integer, then the dual
+ /// solution is scaled by
+ /// \ref MaxWeightedFractionalMatching::dualScale "4".
+ ///
+ /// \tparam GR The undirected graph type the algorithm runs on.
+ /// \tparam WM The type edge weight map. The default type is
+ /// \ref concepts::Graph::EdgeMap "GR::EdgeMap<int>".
+#ifdef DOXYGEN
+ template <typename GR, typename WM>
+#else
+ template <typename GR,
+ typename WM = typename GR::template EdgeMap<int> >
+#endif
+ class MaxWeightedFractionalMatching {
+ public:
+
+ /// The graph type of the algorithm
+ typedef GR Graph;
+ /// The type of the edge weight map
+ typedef WM WeightMap;
+ /// The value type of the edge weights
+ typedef typename WeightMap::Value Value;
+
+ /// The type of the matching map
+ typedef typename Graph::template NodeMap<typename Graph::Arc>
+ MatchingMap;
+
+ /// \brief Scaling factor for primal solution
+ ///
+ /// Scaling factor for primal solution.
+ static const int primalScale = 2;
+
+ /// \brief Scaling factor for dual solution
+ ///
+ /// Scaling factor for dual solution. It is equal to 4 or 1
+ /// according to the value type.
+ static const int dualScale =
+ std::numeric_limits<Value>::is_integer ? 4 : 1;
+
+ private:
+
+ TEMPLATE_GRAPH_TYPEDEFS(Graph);
+
+ typedef typename Graph::template NodeMap<Value> NodePotential;
+
+ const Graph& _graph;
+ const WeightMap& _weight;
+
+ MatchingMap* _matching;
+ NodePotential* _node_potential;
+
+ int _node_num;
+ bool _allow_loops;
+
+ enum Status {
+ EVEN = -1, MATCHED = 0, ODD = 1
+ };
+
+ typedef typename Graph::template NodeMap<Status> StatusMap;
+ StatusMap* _status;
+
+ typedef typename Graph::template NodeMap<Arc> PredMap;
+ PredMap* _pred;
+
+ typedef ExtendFindEnum<IntNodeMap> TreeSet;
+
+ IntNodeMap *_tree_set_index;
+ TreeSet *_tree_set;
+
+ IntNodeMap *_delta1_index;
+ BinHeap<Value, IntNodeMap> *_delta1;
+
+ IntNodeMap *_delta2_index;
+ BinHeap<Value, IntNodeMap> *_delta2;
+
+ IntEdgeMap *_delta3_index;
+ BinHeap<Value, IntEdgeMap> *_delta3;
+
+ Value _delta_sum;
+
+ void createStructures() {
+ _node_num = countNodes(_graph);
+
+ if (!_matching) {
+ _matching = new MatchingMap(_graph);
+ }
+ if (!_node_potential) {
+ _node_potential = new NodePotential(_graph);
+ }
+ if (!_status) {
+ _status = new StatusMap(_graph);
+ }
+ if (!_pred) {
+ _pred = new PredMap(_graph);
+ }
+ if (!_tree_set) {
+ _tree_set_index = new IntNodeMap(_graph);
+ _tree_set = new TreeSet(*_tree_set_index);
+ }
+ if (!_delta1) {
+ _delta1_index = new IntNodeMap(_graph);
+ _delta1 = new BinHeap<Value, IntNodeMap>(*_delta1_index);
+ }
+ if (!_delta2) {
+ _delta2_index = new IntNodeMap(_graph);
+ _delta2 = new BinHeap<Value, IntNodeMap>(*_delta2_index);
+ }
+ if (!_delta3) {
+ _delta3_index = new IntEdgeMap(_graph);
+ _delta3 = new BinHeap<Value, IntEdgeMap>(*_delta3_index);
+ }
+ }
+
+ void destroyStructures() {
+ if (_matching) {
+ delete _matching;
+ }
+ if (_node_potential) {
+ delete _node_potential;
+ }
+ if (_status) {
+ delete _status;
+ }
+ if (_pred) {
+ delete _pred;
+ }
+ if (_tree_set) {
+ delete _tree_set_index;
+ delete _tree_set;
+ }
+ if (_delta1) {
+ delete _delta1_index;
+ delete _delta1;
+ }
+ if (_delta2) {
+ delete _delta2_index;
+ delete _delta2;
+ }
+ if (_delta3) {
+ delete _delta3_index;
+ delete _delta3;
+ }
+ }
+
+ void matchedToEven(Node node, int tree) {
+ _tree_set->insert(node, tree);
+ _node_potential->set(node, (*_node_potential)[node] + _delta_sum);
+ _delta1->push(node, (*_node_potential)[node]);
+
+ if (_delta2->state(node) == _delta2->IN_HEAP) {
+ _delta2->erase(node);
+ }
+
+ for (InArcIt a(_graph, node); a != INVALID; ++a) {
+ Node v = _graph.source(a);
+ Value rw = (*_node_potential)[node] + (*_node_potential)[v] -
+ dualScale * _weight[a];
+ if (node == v) {
+ if (_allow_loops && _graph.direction(a)) {
+ _delta3->push(a, rw / 2);
+ }
+ } else if ((*_status)[v] == EVEN) {
+ _delta3->push(a, rw / 2);
+ } else if ((*_status)[v] == MATCHED) {
+ if (_delta2->state(v) != _delta2->IN_HEAP) {
+ _pred->set(v, a);
+ _delta2->push(v, rw);
+ } else if ((*_delta2)[v] > rw) {
+ _pred->set(v, a);
+ _delta2->decrease(v, rw);
+ }
+ }
+ }
+ }
+
+ void matchedToOdd(Node node, int tree) {
+ _tree_set->insert(node, tree);
+ _node_potential->set(node, (*_node_potential)[node] - _delta_sum);
+
+ if (_delta2->state(node) == _delta2->IN_HEAP) {
+ _delta2->erase(node);
+ }
+ }
+
+ void evenToMatched(Node node, int tree) {
+ _delta1->erase(node);
+ _node_potential->set(node, (*_node_potential)[node] - _delta_sum);
+ Arc min = INVALID;
+ Value minrw = std::numeric_limits<Value>::max();
+ for (InArcIt a(_graph, node); a != INVALID; ++a) {
+ Node v = _graph.source(a);
+ Value rw = (*_node_potential)[node] + (*_node_potential)[v] -
+ dualScale * _weight[a];
+
+ if (node == v) {
+ if (_allow_loops && _graph.direction(a)) {
+ _delta3->erase(a);
+ }
+ } else if ((*_status)[v] == EVEN) {
+ _delta3->erase(a);
+ if (minrw > rw) {
+ min = _graph.oppositeArc(a);
+ minrw = rw;
+ }
+ } else if ((*_status)[v] == MATCHED) {
+ if ((*_pred)[v] == a) {
+ Arc mina = INVALID;
+ Value minrwa = std::numeric_limits<Value>::max();
+ for (OutArcIt aa(_graph, v); aa != INVALID; ++aa) {
+ Node va = _graph.target(aa);
+ if ((*_status)[va] != EVEN ||
+ _tree_set->find(va) == tree) continue;
+ Value rwa = (*_node_potential)[v] + (*_node_potential)[va] -
+ dualScale * _weight[aa];
+ if (minrwa > rwa) {
+ minrwa = rwa;
+ mina = aa;
+ }
+ }
+ if (mina != INVALID) {
+ _pred->set(v, mina);
+ _delta2->increase(v, minrwa);
+ } else {
+ _pred->set(v, INVALID);
+ _delta2->erase(v);
+ }
+ }
+ }
+ }
+ if (min != INVALID) {
+ _pred->set(node, min);
+ _delta2->push(node, minrw);
+ } else {
+ _pred->set(node, INVALID);
+ }
+ }
+
+ void oddToMatched(Node node) {
+ _node_potential->set(node, (*_node_potential)[node] + _delta_sum);
+ Arc min = INVALID;
+ Value minrw = std::numeric_limits<Value>::max();
+ for (InArcIt a(_graph, node); a != INVALID; ++a) {
+ Node v = _graph.source(a);
+ if ((*_status)[v] != EVEN) continue;
+ Value rw = (*_node_potential)[node] + (*_node_potential)[v] -
+ dualScale * _weight[a];
+
+ if (minrw > rw) {
+ min = _graph.oppositeArc(a);
+ minrw = rw;
+ }
+ }
+ if (min != INVALID) {
+ _pred->set(node, min);
+ _delta2->push(node, minrw);
+ } else {
+ _pred->set(node, INVALID);
+ }
+ }
+
+ void alternatePath(Node even, int tree) {
+ Node odd;
+
+ _status->set(even, MATCHED);
+ evenToMatched(even, tree);
+
+ Arc prev = (*_matching)[even];
+ while (prev != INVALID) {
+ odd = _graph.target(prev);
+ even = _graph.target((*_pred)[odd]);
+ _matching->set(odd, (*_pred)[odd]);
+ _status->set(odd, MATCHED);
+ oddToMatched(odd);
+
+ prev = (*_matching)[even];
+ _status->set(even, MATCHED);
+ _matching->set(even, _graph.oppositeArc((*_matching)[odd]));
+ evenToMatched(even, tree);
+ }
+ }
+
+ void destroyTree(int tree) {
+ for (typename TreeSet::ItemIt n(*_tree_set, tree); n != INVALID; ++n) {
+ if ((*_status)[n] == EVEN) {
+ _status->set(n, MATCHED);
+ evenToMatched(n, tree);
+ } else if ((*_status)[n] == ODD) {
+ _status->set(n, MATCHED);
+ oddToMatched(n);
+ }
+ }
+ _tree_set->eraseClass(tree);
+ }
+
+
+ void unmatchNode(const Node& node) {
+ int tree = _tree_set->find(node);
+
+ alternatePath(node, tree);
+ destroyTree(tree);
+
+ _matching->set(node, INVALID);
+ }
+
+
+ void augmentOnEdge(const Edge& edge) {
+ Node left = _graph.u(edge);
+ int left_tree = _tree_set->find(left);
+
+ alternatePath(left, left_tree);
+ destroyTree(left_tree);
+ _matching->set(left, _graph.direct(edge, true));
+
+ Node right = _graph.v(edge);
+ int right_tree = _tree_set->find(right);
+
+ alternatePath(right, right_tree);
+ destroyTree(right_tree);
+ _matching->set(right, _graph.direct(edge, false));
+ }
+
+ void augmentOnArc(const Arc& arc) {
+ Node left = _graph.source(arc);
+ _status->set(left, MATCHED);
+ _matching->set(left, arc);
+ _pred->set(left, arc);
+
+ Node right = _graph.target(arc);
+ int right_tree = _tree_set->find(right);
+
+ alternatePath(right, right_tree);
+ destroyTree(right_tree);
+ _matching->set(right, _graph.oppositeArc(arc));
+ }
+
+ void extendOnArc(const Arc& arc) {
+ Node base = _graph.target(arc);
+ int tree = _tree_set->find(base);
+
+ Node odd = _graph.source(arc);
+ _tree_set->insert(odd, tree);
+ _status->set(odd, ODD);
+ matchedToOdd(odd, tree);
+ _pred->set(odd, arc);
+
+ Node even = _graph.target((*_matching)[odd]);
+ _tree_set->insert(even, tree);
+ _status->set(even, EVEN);
+ matchedToEven(even, tree);
+ }
+
+ void cycleOnEdge(const Edge& edge, int tree) {
+ Node nca = INVALID;
+ std::vector<Node> left_path, right_path;
+
+ {
+ std::set<Node> left_set, right_set;
+ Node left = _graph.u(edge);
+ left_path.push_back(left);
+ left_set.insert(left);
+
+ Node right = _graph.v(edge);
+ right_path.push_back(right);
+ right_set.insert(right);
+
+ while (true) {
+
+ if (left_set.find(right) != left_set.end()) {
+ nca = right;
+ break;
+ }
+
+ if ((*_matching)[left] == INVALID) break;
+
+ left = _graph.target((*_matching)[left]);
+ left_path.push_back(left);
+ left = _graph.target((*_pred)[left]);
+ left_path.push_back(left);
+
+ left_set.insert(left);
+
+ if (right_set.find(left) != right_set.end()) {
+ nca = left;
+ break;
+ }
+
+ if ((*_matching)[right] == INVALID) break;
+
+ right = _graph.target((*_matching)[right]);
+ right_path.push_back(right);
+ right = _graph.target((*_pred)[right]);
+ right_path.push_back(right);
+
+ right_set.insert(right);
+
+ }
+
+ if (nca == INVALID) {
+ if ((*_matching)[left] == INVALID) {
+ nca = right;
+ while (left_set.find(nca) == left_set.end()) {
+ nca = _graph.target((*_matching)[nca]);
+ right_path.push_back(nca);
+ nca = _graph.target((*_pred)[nca]);
+ right_path.push_back(nca);
+ }
+ } else {
+ nca = left;
+ while (right_set.find(nca) == right_set.end()) {
+ nca = _graph.target((*_matching)[nca]);
+ left_path.push_back(nca);
+ nca = _graph.target((*_pred)[nca]);
+ left_path.push_back(nca);
+ }
+ }
+ }
+ }
+
+ alternatePath(nca, tree);
+ Arc prev;
+
+ prev = _graph.direct(edge, true);
+ for (int i = 0; left_path[i] != nca; i += 2) {
+ _matching->set(left_path[i], prev);
+ _status->set(left_path[i], MATCHED);
+ evenToMatched(left_path[i], tree);
+
+ prev = _graph.oppositeArc((*_pred)[left_path[i + 1]]);
+ _status->set(left_path[i + 1], MATCHED);
+ oddToMatched(left_path[i + 1]);
+ }
+ _matching->set(nca, prev);
+
+ for (int i = 0; right_path[i] != nca; i += 2) {
+ _status->set(right_path[i], MATCHED);
+ evenToMatched(right_path[i], tree);
+
+ _matching->set(right_path[i + 1], (*_pred)[right_path[i + 1]]);
+ _status->set(right_path[i + 1], MATCHED);
+ oddToMatched(right_path[i + 1]);
+ }
+
+ destroyTree(tree);
+ }
+
+ void extractCycle(const Arc &arc) {
+ Node left = _graph.source(arc);
+ Node odd = _graph.target((*_matching)[left]);
+ Arc prev;
+ while (odd != left) {
+ Node even = _graph.target((*_matching)[odd]);
+ prev = (*_matching)[odd];
+ odd = _graph.target((*_matching)[even]);
+ _matching->set(even, _graph.oppositeArc(prev));
+ }
+ _matching->set(left, arc);
+
+ Node right = _graph.target(arc);
+ int right_tree = _tree_set->find(right);
+ alternatePath(right, right_tree);
+ destroyTree(right_tree);
+ _matching->set(right, _graph.oppositeArc(arc));
+ }
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ MaxWeightedFractionalMatching(const Graph& graph, const WeightMap& weight,
+ bool allow_loops = true)
+ : _graph(graph), _weight(weight), _matching(0),
+ _node_potential(0), _node_num(0), _allow_loops(allow_loops),
+ _status(0), _pred(0),
+ _tree_set_index(0), _tree_set(0),
+
+ _delta1_index(0), _delta1(0),
+ _delta2_index(0), _delta2(0),
+ _delta3_index(0), _delta3(0),
+
+ _delta_sum() {}
+
+ ~MaxWeightedFractionalMatching() {
+ destroyStructures();
+ }
+
+ /// \name Execution Control
+ /// The simplest way to execute the algorithm is to use the
+ /// \ref run() member function.
+
+ ///@{
+
+ /// \brief Initialize the algorithm
+ ///
+ /// This function initializes the algorithm.
+ void init() {
+ createStructures();
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ (*_delta1_index)[n] = _delta1->PRE_HEAP;
+ (*_delta2_index)[n] = _delta2->PRE_HEAP;
+ }
+ for (EdgeIt e(_graph); e != INVALID; ++e) {
+ (*_delta3_index)[e] = _delta3->PRE_HEAP;
+ }
+
+ _delta1->clear();
+ _delta2->clear();
+ _delta3->clear();
+ _tree_set->clear();
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ Value max = 0;
+ for (OutArcIt e(_graph, n); e != INVALID; ++e) {
+ if (_graph.target(e) == n && !_allow_loops) continue;
+ if ((dualScale * _weight[e]) / 2 > max) {
+ max = (dualScale * _weight[e]) / 2;
+ }
+ }
+ _node_potential->set(n, max);
+ _delta1->push(n, max);
+
+ _tree_set->insert(n);
+
+ _matching->set(n, INVALID);
+ _status->set(n, EVEN);
+ }
+
+ for (EdgeIt e(_graph); e != INVALID; ++e) {
+ Node left = _graph.u(e);
+ Node right = _graph.v(e);
+ if (left == right && !_allow_loops) continue;
+ _delta3->push(e, ((*_node_potential)[left] +
+ (*_node_potential)[right] -
+ dualScale * _weight[e]) / 2);
+ }
+ }
+
+ /// \brief Start the algorithm
+ ///
+ /// This function starts the algorithm.
+ ///
+ /// \pre \ref init() must be called before using this function.
+ void start() {
+ enum OpType {
+ D1, D2, D3
+ };
+
+ int unmatched = _node_num;
+ while (unmatched > 0) {
+ Value d1 = !_delta1->empty() ?
+ _delta1->prio() : std::numeric_limits<Value>::max();
+
+ Value d2 = !_delta2->empty() ?
+ _delta2->prio() : std::numeric_limits<Value>::max();
+
+ Value d3 = !_delta3->empty() ?
+ _delta3->prio() : std::numeric_limits<Value>::max();
+
+ _delta_sum = d3; OpType ot = D3;
+ if (d1 < _delta_sum) { _delta_sum = d1; ot = D1; }
+ if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; }
+
+ switch (ot) {
+ case D1:
+ {
+ Node n = _delta1->top();
+ unmatchNode(n);
+ --unmatched;
+ }
+ break;
+ case D2:
+ {
+ Node n = _delta2->top();
+ Arc a = (*_pred)[n];
+ if ((*_matching)[n] == INVALID) {
+ augmentOnArc(a);
+ --unmatched;
+ } else {
+ Node v = _graph.target((*_matching)[n]);
+ if ((*_matching)[n] !=
+ _graph.oppositeArc((*_matching)[v])) {
+ extractCycle(a);
+ --unmatched;
+ } else {
+ extendOnArc(a);
+ }
+ }
+ } break;
+ case D3:
+ {
+ Edge e = _delta3->top();
+
+ Node left = _graph.u(e);
+ Node right = _graph.v(e);
+
+ int left_tree = _tree_set->find(left);
+ int right_tree = _tree_set->find(right);
+
+ if (left_tree == right_tree) {
+ cycleOnEdge(e, left_tree);
+ --unmatched;
+ } else {
+ augmentOnEdge(e);
+ unmatched -= 2;
+ }
+ } break;
+ }
+ }
+ }
+
+ /// \brief Run the algorithm.
+ ///
+ /// This method runs the \c %MaxWeightedFractionalMatching algorithm.
+ ///
+ /// \note mwfm.run() is just a shortcut of the following code.
+ /// \code
+ /// mwfm.init();
+ /// mwfm.start();
+ /// \endcode
+ void run() {
+ init();
+ start();
+ }
+
+ /// @}
+
+ /// \name Primal Solution
+ /// Functions to get the primal solution, i.e. the maximum weighted
+ /// matching.\n
+ /// Either \ref run() or \ref start() function should be called before
+ /// using them.
+
+ /// @{
+
+ /// \brief Return the weight of the matching.
+ ///
+ /// This function returns the weight of the found matching. This
+ /// value is scaled by \ref primalScale "primal scale".
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Value matchingWeight() const {
+ Value sum = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ if ((*_matching)[n] != INVALID) {
+ sum += _weight[(*_matching)[n]];
+ }
+ }
+ return sum * primalScale / 2;
+ }
+
+ /// \brief Return the number of covered nodes in the matching.
+ ///
+ /// This function returns the number of covered nodes in the matching.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ int matchingSize() const {
+ int num = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ if ((*_matching)[n] != INVALID) {
+ ++num;
+ }
+ }
+ return num;
+ }
+
+ /// \brief Return \c true if the given edge is in the matching.
+ ///
+ /// This function returns \c true if the given edge is in the
+ /// found matching. The result is scaled by \ref primalScale
+ /// "primal scale".
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ int matching(const Edge& edge) const {
+ return (edge == (*_matching)[_graph.u(edge)] ? 1 : 0)
+ + (edge == (*_matching)[_graph.v(edge)] ? 1 : 0);
+ }
+
+ /// \brief Return the fractional matching arc (or edge) incident
+ /// to the given node.
+ ///
+ /// This function returns one of the fractional matching arc (or
+ /// edge) incident to the given node in the found matching or \c
+ /// INVALID if the node is not covered by the matching or if the
+ /// node is on an odd length cycle then it is the successor edge
+ /// on the cycle.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Arc matching(const Node& node) const {
+ return (*_matching)[node];
+ }
+
+ /// \brief Return a const reference to the matching map.
+ ///
+ /// This function returns a const reference to a node map that stores
+ /// the matching arc (or edge) incident to each node.
+ const MatchingMap& matchingMap() const {
+ return *_matching;
+ }
+
+ /// @}
+
+ /// \name Dual Solution
+ /// Functions to get the dual solution.\n
+ /// Either \ref run() or \ref start() function should be called before
+ /// using them.
+
+ /// @{
+
+ /// \brief Return the value of the dual solution.
+ ///
+ /// This function returns the value of the dual solution.
+ /// It should be equal to the primal value scaled by \ref dualScale
+ /// "dual scale".
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Value dualValue() const {
+ Value sum = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ sum += nodeValue(n);
+ }
+ return sum;
+ }
+
+ /// \brief Return the dual value (potential) of the given node.
+ ///
+ /// This function returns the dual value (potential) of the given node.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Value nodeValue(const Node& n) const {
+ return (*_node_potential)[n];
+ }
+
+ /// @}
+
+ };
+
+ /// \ingroup matching
+ ///
+ /// \brief Weighted fractional perfect matching in general graphs
+ ///
+ /// This class provides an efficient implementation of fractional
+ /// matching algorithm. The implementation uses priority queues and
+ /// provides \f$O(nm\log n)\f$ time complexity.
+ ///
+ /// The maximum weighted fractional perfect matching is a relaxation
+ /// of the maximum weighted perfect matching problem where the odd
+ /// set constraints are omitted.
+ /// It can be formulated with the following linear program.
+ /// \f[ \sum_{e \in \delta(u)}x_e = 1 \quad \forall u\in V\f]
+ /// \f[x_e \ge 0\quad \forall e\in E\f]
+ /// \f[\max \sum_{e\in E}x_ew_e\f]
+ /// where \f$\delta(X)\f$ is the set of edges incident to a node in
+ /// \f$X\f$. The result must be the union of a matching with one
+ /// value edges and a set of odd length cycles with half value edges.
+ ///
+ /// The algorithm calculates an optimal fractional matching and a
+ /// proof of the optimality. The solution of the dual problem can be
+ /// used to check the result of the algorithm. The dual linear
+ /// problem is the following.
+ /// \f[ y_u + y_v \ge w_{uv} \quad \forall uv\in E\f]
+ /// \f[\min \sum_{u \in V}y_u \f]
+ ///
+ /// The algorithm can be executed with the run() function.
+ /// After it the matching (the primal solution) and the dual solution
+ /// can be obtained using the query functions.
+ ///
+ /// The primal solution is multiplied by
+ /// \ref MaxWeightedPerfectFractionalMatching::primalScale "2".
+ /// If the value type is integer, then the dual
+ /// solution is scaled by
+ /// \ref MaxWeightedPerfectFractionalMatching::dualScale "4".
+ ///
+ /// \tparam GR The undirected graph type the algorithm runs on.
+ /// \tparam WM The type edge weight map. The default type is
+ /// \ref concepts::Graph::EdgeMap "GR::EdgeMap<int>".
+#ifdef DOXYGEN
+ template <typename GR, typename WM>
+#else
+ template <typename GR,
+ typename WM = typename GR::template EdgeMap<int> >
+#endif
+ class MaxWeightedPerfectFractionalMatching {
+ public:
+
+ /// The graph type of the algorithm
+ typedef GR Graph;
+ /// The type of the edge weight map
+ typedef WM WeightMap;
+ /// The value type of the edge weights
+ typedef typename WeightMap::Value Value;
+
+ /// The type of the matching map
+ typedef typename Graph::template NodeMap<typename Graph::Arc>
+ MatchingMap;
+
+ /// \brief Scaling factor for primal solution
+ ///
+ /// Scaling factor for primal solution.
+ static const int primalScale = 2;
+
+ /// \brief Scaling factor for dual solution
+ ///
+ /// Scaling factor for dual solution. It is equal to 4 or 1
+ /// according to the value type.
+ static const int dualScale =
+ std::numeric_limits<Value>::is_integer ? 4 : 1;
+
+ private:
+
+ TEMPLATE_GRAPH_TYPEDEFS(Graph);
+
+ typedef typename Graph::template NodeMap<Value> NodePotential;
+
+ const Graph& _graph;
+ const WeightMap& _weight;
+
+ MatchingMap* _matching;
+ NodePotential* _node_potential;
+
+ int _node_num;
+ bool _allow_loops;
+
+ enum Status {
+ EVEN = -1, MATCHED = 0, ODD = 1
+ };
+
+ typedef typename Graph::template NodeMap<Status> StatusMap;
+ StatusMap* _status;
+
+ typedef typename Graph::template NodeMap<Arc> PredMap;
+ PredMap* _pred;
+
+ typedef ExtendFindEnum<IntNodeMap> TreeSet;
+
+ IntNodeMap *_tree_set_index;
+ TreeSet *_tree_set;
+
+ IntNodeMap *_delta2_index;
+ BinHeap<Value, IntNodeMap> *_delta2;
+
+ IntEdgeMap *_delta3_index;
+ BinHeap<Value, IntEdgeMap> *_delta3;
+
+ Value _delta_sum;
+
+ void createStructures() {
+ _node_num = countNodes(_graph);
+
+ if (!_matching) {
+ _matching = new MatchingMap(_graph);
+ }
+ if (!_node_potential) {
+ _node_potential = new NodePotential(_graph);
+ }
+ if (!_status) {
+ _status = new StatusMap(_graph);
+ }
+ if (!_pred) {
+ _pred = new PredMap(_graph);
+ }
+ if (!_tree_set) {
+ _tree_set_index = new IntNodeMap(_graph);
+ _tree_set = new TreeSet(*_tree_set_index);
+ }
+ if (!_delta2) {
+ _delta2_index = new IntNodeMap(_graph);
+ _delta2 = new BinHeap<Value, IntNodeMap>(*_delta2_index);
+ }
+ if (!_delta3) {
+ _delta3_index = new IntEdgeMap(_graph);
+ _delta3 = new BinHeap<Value, IntEdgeMap>(*_delta3_index);
+ }
+ }
+
+ void destroyStructures() {
+ if (_matching) {
+ delete _matching;
+ }
+ if (_node_potential) {
+ delete _node_potential;
+ }
+ if (_status) {
+ delete _status;
+ }
+ if (_pred) {
+ delete _pred;
+ }
+ if (_tree_set) {
+ delete _tree_set_index;
+ delete _tree_set;
+ }
+ if (_delta2) {
+ delete _delta2_index;
+ delete _delta2;
+ }
+ if (_delta3) {
+ delete _delta3_index;
+ delete _delta3;
+ }
+ }
+
+ void matchedToEven(Node node, int tree) {
+ _tree_set->insert(node, tree);
+ _node_potential->set(node, (*_node_potential)[node] + _delta_sum);
+
+ if (_delta2->state(node) == _delta2->IN_HEAP) {
+ _delta2->erase(node);
+ }
+
+ for (InArcIt a(_graph, node); a != INVALID; ++a) {
+ Node v = _graph.source(a);
+ Value rw = (*_node_potential)[node] + (*_node_potential)[v] -
+ dualScale * _weight[a];
+ if (node == v) {
+ if (_allow_loops && _graph.direction(a)) {
+ _delta3->push(a, rw / 2);
+ }
+ } else if ((*_status)[v] == EVEN) {
+ _delta3->push(a, rw / 2);
+ } else if ((*_status)[v] == MATCHED) {
+ if (_delta2->state(v) != _delta2->IN_HEAP) {
+ _pred->set(v, a);
+ _delta2->push(v, rw);
+ } else if ((*_delta2)[v] > rw) {
+ _pred->set(v, a);
+ _delta2->decrease(v, rw);
+ }
+ }
+ }
+ }
+
+ void matchedToOdd(Node node, int tree) {
+ _tree_set->insert(node, tree);
+ _node_potential->set(node, (*_node_potential)[node] - _delta_sum);
+
+ if (_delta2->state(node) == _delta2->IN_HEAP) {
+ _delta2->erase(node);
+ }
+ }
+
+ void evenToMatched(Node node, int tree) {
+ _node_potential->set(node, (*_node_potential)[node] - _delta_sum);
+ Arc min = INVALID;
+ Value minrw = std::numeric_limits<Value>::max();
+ for (InArcIt a(_graph, node); a != INVALID; ++a) {
+ Node v = _graph.source(a);
+ Value rw = (*_node_potential)[node] + (*_node_potential)[v] -
+ dualScale * _weight[a];
+
+ if (node == v) {
+ if (_allow_loops && _graph.direction(a)) {
+ _delta3->erase(a);
+ }
+ } else if ((*_status)[v] == EVEN) {
+ _delta3->erase(a);
+ if (minrw > rw) {
+ min = _graph.oppositeArc(a);
+ minrw = rw;
+ }
+ } else if ((*_status)[v] == MATCHED) {
+ if ((*_pred)[v] == a) {
+ Arc mina = INVALID;
+ Value minrwa = std::numeric_limits<Value>::max();
+ for (OutArcIt aa(_graph, v); aa != INVALID; ++aa) {
+ Node va = _graph.target(aa);
+ if ((*_status)[va] != EVEN ||
+ _tree_set->find(va) == tree) continue;
+ Value rwa = (*_node_potential)[v] + (*_node_potential)[va] -
+ dualScale * _weight[aa];
+ if (minrwa > rwa) {
+ minrwa = rwa;
+ mina = aa;
+ }
+ }
+ if (mina != INVALID) {
+ _pred->set(v, mina);
+ _delta2->increase(v, minrwa);
+ } else {
+ _pred->set(v, INVALID);
+ _delta2->erase(v);
+ }
+ }
+ }
+ }
+ if (min != INVALID) {
+ _pred->set(node, min);
+ _delta2->push(node, minrw);
+ } else {
+ _pred->set(node, INVALID);
+ }
+ }
+
+ void oddToMatched(Node node) {
+ _node_potential->set(node, (*_node_potential)[node] + _delta_sum);
+ Arc min = INVALID;
+ Value minrw = std::numeric_limits<Value>::max();
+ for (InArcIt a(_graph, node); a != INVALID; ++a) {
+ Node v = _graph.source(a);
+ if ((*_status)[v] != EVEN) continue;
+ Value rw = (*_node_potential)[node] + (*_node_potential)[v] -
+ dualScale * _weight[a];
+
+ if (minrw > rw) {
+ min = _graph.oppositeArc(a);
+ minrw = rw;
+ }
+ }
+ if (min != INVALID) {
+ _pred->set(node, min);
+ _delta2->push(node, minrw);
+ } else {
+ _pred->set(node, INVALID);
+ }
+ }
+
+ void alternatePath(Node even, int tree) {
+ Node odd;
+
+ _status->set(even, MATCHED);
+ evenToMatched(even, tree);
+
+ Arc prev = (*_matching)[even];
+ while (prev != INVALID) {
+ odd = _graph.target(prev);
+ even = _graph.target((*_pred)[odd]);
+ _matching->set(odd, (*_pred)[odd]);
+ _status->set(odd, MATCHED);
+ oddToMatched(odd);
+
+ prev = (*_matching)[even];
+ _status->set(even, MATCHED);
+ _matching->set(even, _graph.oppositeArc((*_matching)[odd]));
+ evenToMatched(even, tree);
+ }
+ }
+
+ void destroyTree(int tree) {
+ for (typename TreeSet::ItemIt n(*_tree_set, tree); n != INVALID; ++n) {
+ if ((*_status)[n] == EVEN) {
+ _status->set(n, MATCHED);
+ evenToMatched(n, tree);
+ } else if ((*_status)[n] == ODD) {
+ _status->set(n, MATCHED);
+ oddToMatched(n);
+ }
+ }
+ _tree_set->eraseClass(tree);
+ }
+
+ void augmentOnEdge(const Edge& edge) {
+ Node left = _graph.u(edge);
+ int left_tree = _tree_set->find(left);
+
+ alternatePath(left, left_tree);
+ destroyTree(left_tree);
+ _matching->set(left, _graph.direct(edge, true));
+
+ Node right = _graph.v(edge);
+ int right_tree = _tree_set->find(right);
+
+ alternatePath(right, right_tree);
+ destroyTree(right_tree);
+ _matching->set(right, _graph.direct(edge, false));
+ }
+
+ void augmentOnArc(const Arc& arc) {
+ Node left = _graph.source(arc);
+ _status->set(left, MATCHED);
+ _matching->set(left, arc);
+ _pred->set(left, arc);
+
+ Node right = _graph.target(arc);
+ int right_tree = _tree_set->find(right);
+
+ alternatePath(right, right_tree);
+ destroyTree(right_tree);
+ _matching->set(right, _graph.oppositeArc(arc));
+ }
+
+ void extendOnArc(const Arc& arc) {
+ Node base = _graph.target(arc);
+ int tree = _tree_set->find(base);
+
+ Node odd = _graph.source(arc);
+ _tree_set->insert(odd, tree);
+ _status->set(odd, ODD);
+ matchedToOdd(odd, tree);
+ _pred->set(odd, arc);
+
+ Node even = _graph.target((*_matching)[odd]);
+ _tree_set->insert(even, tree);
+ _status->set(even, EVEN);
+ matchedToEven(even, tree);
+ }
+
+ void cycleOnEdge(const Edge& edge, int tree) {
+ Node nca = INVALID;
+ std::vector<Node> left_path, right_path;
+
+ {
+ std::set<Node> left_set, right_set;
+ Node left = _graph.u(edge);
+ left_path.push_back(left);
+ left_set.insert(left);
+
+ Node right = _graph.v(edge);
+ right_path.push_back(right);
+ right_set.insert(right);
+
+ while (true) {
+
+ if (left_set.find(right) != left_set.end()) {
+ nca = right;
+ break;
+ }
+
+ if ((*_matching)[left] == INVALID) break;
+
+ left = _graph.target((*_matching)[left]);
+ left_path.push_back(left);
+ left = _graph.target((*_pred)[left]);
+ left_path.push_back(left);
+
+ left_set.insert(left);
+
+ if (right_set.find(left) != right_set.end()) {
+ nca = left;
+ break;
+ }
+
+ if ((*_matching)[right] == INVALID) break;
+
+ right = _graph.target((*_matching)[right]);
+ right_path.push_back(right);
+ right = _graph.target((*_pred)[right]);
+ right_path.push_back(right);
+
+ right_set.insert(right);
+
+ }
+
+ if (nca == INVALID) {
+ if ((*_matching)[left] == INVALID) {
+ nca = right;
+ while (left_set.find(nca) == left_set.end()) {
+ nca = _graph.target((*_matching)[nca]);
+ right_path.push_back(nca);
+ nca = _graph.target((*_pred)[nca]);
+ right_path.push_back(nca);
+ }
+ } else {
+ nca = left;
+ while (right_set.find(nca) == right_set.end()) {
+ nca = _graph.target((*_matching)[nca]);
+ left_path.push_back(nca);
+ nca = _graph.target((*_pred)[nca]);
+ left_path.push_back(nca);
+ }
+ }
+ }
+ }
+
+ alternatePath(nca, tree);
+ Arc prev;
+
+ prev = _graph.direct(edge, true);
+ for (int i = 0; left_path[i] != nca; i += 2) {
+ _matching->set(left_path[i], prev);
+ _status->set(left_path[i], MATCHED);
+ evenToMatched(left_path[i], tree);
+
+ prev = _graph.oppositeArc((*_pred)[left_path[i + 1]]);
+ _status->set(left_path[i + 1], MATCHED);
+ oddToMatched(left_path[i + 1]);
+ }
+ _matching->set(nca, prev);
+
+ for (int i = 0; right_path[i] != nca; i += 2) {
+ _status->set(right_path[i], MATCHED);
+ evenToMatched(right_path[i], tree);
+
+ _matching->set(right_path[i + 1], (*_pred)[right_path[i + 1]]);
+ _status->set(right_path[i + 1], MATCHED);
+ oddToMatched(right_path[i + 1]);
+ }
+
+ destroyTree(tree);
+ }
+
+ void extractCycle(const Arc &arc) {
+ Node left = _graph.source(arc);
+ Node odd = _graph.target((*_matching)[left]);
+ Arc prev;
+ while (odd != left) {
+ Node even = _graph.target((*_matching)[odd]);
+ prev = (*_matching)[odd];
+ odd = _graph.target((*_matching)[even]);
+ _matching->set(even, _graph.oppositeArc(prev));
+ }
+ _matching->set(left, arc);
+
+ Node right = _graph.target(arc);
+ int right_tree = _tree_set->find(right);
+ alternatePath(right, right_tree);
+ destroyTree(right_tree);
+ _matching->set(right, _graph.oppositeArc(arc));
+ }
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ MaxWeightedPerfectFractionalMatching(const Graph& graph,
+ const WeightMap& weight,
+ bool allow_loops = true)
+ : _graph(graph), _weight(weight), _matching(0),
+ _node_potential(0), _node_num(0), _allow_loops(allow_loops),
+ _status(0), _pred(0),
+ _tree_set_index(0), _tree_set(0),
+
+ _delta2_index(0), _delta2(0),
+ _delta3_index(0), _delta3(0),
+
+ _delta_sum() {}
+
+ ~MaxWeightedPerfectFractionalMatching() {
+ destroyStructures();
+ }
+
+ /// \name Execution Control
+ /// The simplest way to execute the algorithm is to use the
+ /// \ref run() member function.
+
+ ///@{
+
+ /// \brief Initialize the algorithm
+ ///
+ /// This function initializes the algorithm.
+ void init() {
+ createStructures();
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ (*_delta2_index)[n] = _delta2->PRE_HEAP;
+ }
+ for (EdgeIt e(_graph); e != INVALID; ++e) {
+ (*_delta3_index)[e] = _delta3->PRE_HEAP;
+ }
+
+ _delta2->clear();
+ _delta3->clear();
+ _tree_set->clear();
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ Value max = - std::numeric_limits<Value>::max();
+ for (OutArcIt e(_graph, n); e != INVALID; ++e) {
+ if (_graph.target(e) == n && !_allow_loops) continue;
+ if ((dualScale * _weight[e]) / 2 > max) {
+ max = (dualScale * _weight[e]) / 2;
+ }
+ }
+ _node_potential->set(n, max);
+
+ _tree_set->insert(n);
+
+ _matching->set(n, INVALID);
+ _status->set(n, EVEN);
+ }
+
+ for (EdgeIt e(_graph); e != INVALID; ++e) {
+ Node left = _graph.u(e);
+ Node right = _graph.v(e);
+ if (left == right && !_allow_loops) continue;
+ _delta3->push(e, ((*_node_potential)[left] +
+ (*_node_potential)[right] -
+ dualScale * _weight[e]) / 2);
+ }
+ }
+
+ /// \brief Start the algorithm
+ ///
+ /// This function starts the algorithm.
+ ///
+ /// \pre \ref init() must be called before using this function.
+ bool start() {
+ enum OpType {
+ D2, D3
+ };
+
+ int unmatched = _node_num;
+ while (unmatched > 0) {
+ Value d2 = !_delta2->empty() ?
+ _delta2->prio() : std::numeric_limits<Value>::max();
+
+ Value d3 = !_delta3->empty() ?
+ _delta3->prio() : std::numeric_limits<Value>::max();
+
+ _delta_sum = d3; OpType ot = D3;
+ if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; }
+
+ if (_delta_sum == std::numeric_limits<Value>::max()) {
+ return false;
+ }
+
+ switch (ot) {
+ case D2:
+ {
+ Node n = _delta2->top();
+ Arc a = (*_pred)[n];
+ if ((*_matching)[n] == INVALID) {
+ augmentOnArc(a);
+ --unmatched;
+ } else {
+ Node v = _graph.target((*_matching)[n]);
+ if ((*_matching)[n] !=
+ _graph.oppositeArc((*_matching)[v])) {
+ extractCycle(a);
+ --unmatched;
+ } else {
+ extendOnArc(a);
+ }
+ }
+ } break;
+ case D3:
+ {
+ Edge e = _delta3->top();
+
+ Node left = _graph.u(e);
+ Node right = _graph.v(e);
+
+ int left_tree = _tree_set->find(left);
+ int right_tree = _tree_set->find(right);
+
+ if (left_tree == right_tree) {
+ cycleOnEdge(e, left_tree);
+ --unmatched;
+ } else {
+ augmentOnEdge(e);
+ unmatched -= 2;
+ }
+ } break;
+ }
+ }
+ return true;
+ }
+
+ /// \brief Run the algorithm.
+ ///
+ /// This method runs the \c %MaxWeightedPerfectFractionalMatching
+ /// algorithm.
+ ///
+ /// \note mwfm.run() is just a shortcut of the following code.
+ /// \code
+ /// mwpfm.init();
+ /// mwpfm.start();
+ /// \endcode
+ bool run() {
+ init();
+ return start();
+ }
+
+ /// @}
+
+ /// \name Primal Solution
+ /// Functions to get the primal solution, i.e. the maximum weighted
+ /// matching.\n
+ /// Either \ref run() or \ref start() function should be called before
+ /// using them.
+
+ /// @{
+
+ /// \brief Return the weight of the matching.
+ ///
+ /// This function returns the weight of the found matching. This
+ /// value is scaled by \ref primalScale "primal scale".
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Value matchingWeight() const {
+ Value sum = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ if ((*_matching)[n] != INVALID) {
+ sum += _weight[(*_matching)[n]];
+ }
+ }
+ return sum * primalScale / 2;
+ }
+
+ /// \brief Return the number of covered nodes in the matching.
+ ///
+ /// This function returns the number of covered nodes in the matching.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ int matchingSize() const {
+ int num = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ if ((*_matching)[n] != INVALID) {
+ ++num;
+ }
+ }
+ return num;
+ }
+
+ /// \brief Return \c true if the given edge is in the matching.
+ ///
+ /// This function returns \c true if the given edge is in the
+ /// found matching. The result is scaled by \ref primalScale
+ /// "primal scale".
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ int matching(const Edge& edge) const {
+ return (edge == (*_matching)[_graph.u(edge)] ? 1 : 0)
+ + (edge == (*_matching)[_graph.v(edge)] ? 1 : 0);
+ }
+
+ /// \brief Return the fractional matching arc (or edge) incident
+ /// to the given node.
+ ///
+ /// This function returns one of the fractional matching arc (or
+ /// edge) incident to the given node in the found matching or \c
+ /// INVALID if the node is not covered by the matching or if the
+ /// node is on an odd length cycle then it is the successor edge
+ /// on the cycle.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Arc matching(const Node& node) const {
+ return (*_matching)[node];
+ }
+
+ /// \brief Return a const reference to the matching map.
+ ///
+ /// This function returns a const reference to a node map that stores
+ /// the matching arc (or edge) incident to each node.
+ const MatchingMap& matchingMap() const {
+ return *_matching;
+ }
+
+ /// @}
+
+ /// \name Dual Solution
+ /// Functions to get the dual solution.\n
+ /// Either \ref run() or \ref start() function should be called before
+ /// using them.
+
+ /// @{
+
+ /// \brief Return the value of the dual solution.
+ ///
+ /// This function returns the value of the dual solution.
+ /// It should be equal to the primal value scaled by \ref dualScale
+ /// "dual scale".
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Value dualValue() const {
+ Value sum = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ sum += nodeValue(n);
+ }
+ return sum;
+ }
+
+ /// \brief Return the dual value (potential) of the given node.
+ ///
+ /// This function returns the dual value (potential) of the given node.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Value nodeValue(const Node& n) const {
+ return (*_node_potential)[n];
+ }
+
+ /// @}
+
+ };
+
+} //END OF NAMESPACE LEMON
+
+#endif //LEMON_FRACTIONAL_MATCHING_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/full_graph.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/full_graph.h
new file mode 100644
index 00000000000..b63df2e0746
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/full_graph.h
@@ -0,0 +1,1082 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_FULL_GRAPH_H
+#define LEMON_FULL_GRAPH_H
+
+#include <lemon/core.h>
+#include <lemon/bits/graph_extender.h>
+
+///\ingroup graphs
+///\file
+///\brief FullDigraph and FullGraph classes.
+
+namespace lemon {
+
+ class FullDigraphBase {
+ public:
+
+ typedef FullDigraphBase Digraph;
+
+ class Node;
+ class Arc;
+
+ protected:
+
+ int _node_num;
+ int _arc_num;
+
+ FullDigraphBase() {}
+
+ void construct(int n) { _node_num = n; _arc_num = n * n; }
+
+ public:
+
+ typedef True NodeNumTag;
+ typedef True ArcNumTag;
+
+ Node operator()(int ix) const { return Node(ix); }
+ static int index(const Node& node) { return node._id; }
+
+ Arc arc(const Node& s, const Node& t) const {
+ return Arc(s._id * _node_num + t._id);
+ }
+
+ int nodeNum() const { return _node_num; }
+ int arcNum() const { return _arc_num; }
+
+ int maxNodeId() const { return _node_num - 1; }
+ int maxArcId() const { return _arc_num - 1; }
+
+ Node source(Arc arc) const { return arc._id / _node_num; }
+ Node target(Arc arc) const { return arc._id % _node_num; }
+
+ static int id(Node node) { return node._id; }
+ static int id(Arc arc) { return arc._id; }
+
+ static Node nodeFromId(int id) { return Node(id);}
+ static Arc arcFromId(int id) { return Arc(id);}
+
+ typedef True FindArcTag;
+
+ Arc findArc(Node s, Node t, Arc prev = INVALID) const {
+ return prev == INVALID ? arc(s, t) : INVALID;
+ }
+
+ class Node {
+ friend class FullDigraphBase;
+
+ protected:
+ int _id;
+ Node(int id) : _id(id) {}
+ public:
+ Node() {}
+ Node (Invalid) : _id(-1) {}
+ bool operator==(const Node node) const {return _id == node._id;}
+ bool operator!=(const Node node) const {return _id != node._id;}
+ bool operator<(const Node node) const {return _id < node._id;}
+ };
+
+ class Arc {
+ friend class FullDigraphBase;
+
+ protected:
+ int _id; // _node_num * source + target;
+
+ Arc(int id) : _id(id) {}
+
+ public:
+ Arc() { }
+ Arc (Invalid) { _id = -1; }
+ bool operator==(const Arc arc) const {return _id == arc._id;}
+ bool operator!=(const Arc arc) const {return _id != arc._id;}
+ bool operator<(const Arc arc) const {return _id < arc._id;}
+ };
+
+ void first(Node& node) const {
+ node._id = _node_num - 1;
+ }
+
+ static void next(Node& node) {
+ --node._id;
+ }
+
+ void first(Arc& arc) const {
+ arc._id = _arc_num - 1;
+ }
+
+ static void next(Arc& arc) {
+ --arc._id;
+ }
+
+ void firstOut(Arc& arc, const Node& node) const {
+ arc._id = (node._id + 1) * _node_num - 1;
+ }
+
+ void nextOut(Arc& arc) const {
+ if (arc._id % _node_num == 0) arc._id = 0;
+ --arc._id;
+ }
+
+ void firstIn(Arc& arc, const Node& node) const {
+ arc._id = _arc_num + node._id - _node_num;
+ }
+
+ void nextIn(Arc& arc) const {
+ arc._id -= _node_num;
+ if (arc._id < 0) arc._id = -1;
+ }
+
+ };
+
+ typedef DigraphExtender<FullDigraphBase> ExtendedFullDigraphBase;
+
+ /// \ingroup graphs
+ ///
+ /// \brief A directed full graph class.
+ ///
+ /// FullDigraph is a simple and fast implmenetation of directed full
+ /// (complete) graphs. It contains an arc from each node to each node
+ /// (including a loop for each node), therefore the number of arcs
+ /// is the square of the number of nodes.
+ /// This class is completely static and it needs constant memory space.
+ /// Thus you can neither add nor delete nodes or arcs, however
+ /// the structure can be resized using resize().
+ ///
+ /// This type fully conforms to the \ref concepts::Digraph "Digraph concept".
+ /// Most of its member functions and nested classes are documented
+ /// only in the concept class.
+ ///
+ /// This class provides constant time counting for nodes and arcs.
+ ///
+ /// \note FullDigraph and FullGraph classes are very similar,
+ /// but there are two differences. While this class conforms only
+ /// to the \ref concepts::Digraph "Digraph" concept, FullGraph
+ /// conforms to the \ref concepts::Graph "Graph" concept,
+ /// moreover FullGraph does not contain a loop for each
+ /// node as this class does.
+ ///
+ /// \sa FullGraph
+ class FullDigraph : public ExtendedFullDigraphBase {
+ typedef ExtendedFullDigraphBase Parent;
+
+ public:
+
+ /// \brief Default constructor.
+ ///
+ /// Default constructor. The number of nodes and arcs will be zero.
+ FullDigraph() { construct(0); }
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ /// \param n The number of the nodes.
+ FullDigraph(int n) { construct(n); }
+
+ /// \brief Resizes the digraph
+ ///
+ /// This function resizes the digraph. It fully destroys and
+ /// rebuilds the structure, therefore the maps of the digraph will be
+ /// reallocated automatically and the previous values will be lost.
+ void resize(int n) {
+ Parent::notifier(Arc()).clear();
+ Parent::notifier(Node()).clear();
+ construct(n);
+ Parent::notifier(Node()).build();
+ Parent::notifier(Arc()).build();
+ }
+
+ /// \brief Returns the node with the given index.
+ ///
+ /// Returns the node with the given index. Since this structure is
+ /// completely static, the nodes can be indexed with integers from
+ /// the range <tt>[0..nodeNum()-1]</tt>.
+ /// The index of a node is the same as its ID.
+ /// \sa index()
+ Node operator()(int ix) const { return Parent::operator()(ix); }
+
+ /// \brief Returns the index of the given node.
+ ///
+ /// Returns the index of the given node. Since this structure is
+ /// completely static, the nodes can be indexed with integers from
+ /// the range <tt>[0..nodeNum()-1]</tt>.
+ /// The index of a node is the same as its ID.
+ /// \sa operator()()
+ static int index(const Node& node) { return Parent::index(node); }
+
+ /// \brief Returns the arc connecting the given nodes.
+ ///
+ /// Returns the arc connecting the given nodes.
+ Arc arc(Node u, Node v) const {
+ return Parent::arc(u, v);
+ }
+
+ /// \brief Number of nodes.
+ int nodeNum() const { return Parent::nodeNum(); }
+ /// \brief Number of arcs.
+ int arcNum() const { return Parent::arcNum(); }
+ };
+
+
+ class FullGraphBase {
+ public:
+
+ typedef FullGraphBase Graph;
+
+ class Node;
+ class Arc;
+ class Edge;
+
+ protected:
+
+ int _node_num;
+ int _edge_num;
+
+ FullGraphBase() {}
+
+ void construct(int n) { _node_num = n; _edge_num = n * (n - 1) / 2; }
+
+ int _uid(int e) const {
+ int u = e / _node_num;
+ int v = e % _node_num;
+ return u < v ? u : _node_num - 2 - u;
+ }
+
+ int _vid(int e) const {
+ int u = e / _node_num;
+ int v = e % _node_num;
+ return u < v ? v : _node_num - 1 - v;
+ }
+
+ void _uvid(int e, int& u, int& v) const {
+ u = e / _node_num;
+ v = e % _node_num;
+ if (u >= v) {
+ u = _node_num - 2 - u;
+ v = _node_num - 1 - v;
+ }
+ }
+
+ void _stid(int a, int& s, int& t) const {
+ if ((a & 1) == 1) {
+ _uvid(a >> 1, s, t);
+ } else {
+ _uvid(a >> 1, t, s);
+ }
+ }
+
+ int _eid(int u, int v) const {
+ if (u < (_node_num - 1) / 2) {
+ return u * _node_num + v;
+ } else {
+ return (_node_num - 1 - u) * _node_num - v - 1;
+ }
+ }
+
+ public:
+
+ Node operator()(int ix) const { return Node(ix); }
+ static int index(const Node& node) { return node._id; }
+
+ Edge edge(const Node& u, const Node& v) const {
+ if (u._id < v._id) {
+ return Edge(_eid(u._id, v._id));
+ } else if (u._id != v._id) {
+ return Edge(_eid(v._id, u._id));
+ } else {
+ return INVALID;
+ }
+ }
+
+ Arc arc(const Node& s, const Node& t) const {
+ if (s._id < t._id) {
+ return Arc((_eid(s._id, t._id) << 1) | 1);
+ } else if (s._id != t._id) {
+ return Arc(_eid(t._id, s._id) << 1);
+ } else {
+ return INVALID;
+ }
+ }
+
+ typedef True NodeNumTag;
+ typedef True ArcNumTag;
+ typedef True EdgeNumTag;
+
+ int nodeNum() const { return _node_num; }
+ int arcNum() const { return 2 * _edge_num; }
+ int edgeNum() const { return _edge_num; }
+
+ static int id(Node node) { return node._id; }
+ static int id(Arc arc) { return arc._id; }
+ static int id(Edge edge) { return edge._id; }
+
+ int maxNodeId() const { return _node_num-1; }
+ int maxArcId() const { return 2 * _edge_num-1; }
+ int maxEdgeId() const { return _edge_num-1; }
+
+ static Node nodeFromId(int id) { return Node(id);}
+ static Arc arcFromId(int id) { return Arc(id);}
+ static Edge edgeFromId(int id) { return Edge(id);}
+
+ Node u(Edge edge) const {
+ return Node(_uid(edge._id));
+ }
+
+ Node v(Edge edge) const {
+ return Node(_vid(edge._id));
+ }
+
+ Node source(Arc arc) const {
+ return Node((arc._id & 1) == 1 ?
+ _uid(arc._id >> 1) : _vid(arc._id >> 1));
+ }
+
+ Node target(Arc arc) const {
+ return Node((arc._id & 1) == 1 ?
+ _vid(arc._id >> 1) : _uid(arc._id >> 1));
+ }
+
+ typedef True FindEdgeTag;
+ typedef True FindArcTag;
+
+ Edge findEdge(Node u, Node v, Edge prev = INVALID) const {
+ return prev != INVALID ? INVALID : edge(u, v);
+ }
+
+ Arc findArc(Node s, Node t, Arc prev = INVALID) const {
+ return prev != INVALID ? INVALID : arc(s, t);
+ }
+
+ class Node {
+ friend class FullGraphBase;
+
+ protected:
+ int _id;
+ Node(int id) : _id(id) {}
+ public:
+ Node() {}
+ Node (Invalid) { _id = -1; }
+ bool operator==(const Node node) const {return _id == node._id;}
+ bool operator!=(const Node node) const {return _id != node._id;}
+ bool operator<(const Node node) const {return _id < node._id;}
+ };
+
+ class Edge {
+ friend class FullGraphBase;
+ friend class Arc;
+
+ protected:
+ int _id;
+
+ Edge(int id) : _id(id) {}
+
+ public:
+ Edge() { }
+ Edge (Invalid) { _id = -1; }
+
+ bool operator==(const Edge edge) const {return _id == edge._id;}
+ bool operator!=(const Edge edge) const {return _id != edge._id;}
+ bool operator<(const Edge edge) const {return _id < edge._id;}
+ };
+
+ class Arc {
+ friend class FullGraphBase;
+
+ protected:
+ int _id;
+
+ Arc(int id) : _id(id) {}
+
+ public:
+ Arc() { }
+ Arc (Invalid) { _id = -1; }
+
+ operator Edge() const { return Edge(_id != -1 ? (_id >> 1) : -1); }
+
+ bool operator==(const Arc arc) const {return _id == arc._id;}
+ bool operator!=(const Arc arc) const {return _id != arc._id;}
+ bool operator<(const Arc arc) const {return _id < arc._id;}
+ };
+
+ static bool direction(Arc arc) {
+ return (arc._id & 1) == 1;
+ }
+
+ static Arc direct(Edge edge, bool dir) {
+ return Arc((edge._id << 1) | (dir ? 1 : 0));
+ }
+
+ void first(Node& node) const {
+ node._id = _node_num - 1;
+ }
+
+ static void next(Node& node) {
+ --node._id;
+ }
+
+ void first(Arc& arc) const {
+ arc._id = (_edge_num << 1) - 1;
+ }
+
+ static void next(Arc& arc) {
+ --arc._id;
+ }
+
+ void first(Edge& edge) const {
+ edge._id = _edge_num - 1;
+ }
+
+ static void next(Edge& edge) {
+ --edge._id;
+ }
+
+ void firstOut(Arc& arc, const Node& node) const {
+ int s = node._id, t = _node_num - 1;
+ if (s < t) {
+ arc._id = (_eid(s, t) << 1) | 1;
+ } else {
+ --t;
+ arc._id = (t != -1 ? (_eid(t, s) << 1) : -1);
+ }
+ }
+
+ void nextOut(Arc& arc) const {
+ int s, t;
+ _stid(arc._id, s, t);
+ --t;
+ if (s < t) {
+ arc._id = (_eid(s, t) << 1) | 1;
+ } else {
+ if (s == t) --t;
+ arc._id = (t != -1 ? (_eid(t, s) << 1) : -1);
+ }
+ }
+
+ void firstIn(Arc& arc, const Node& node) const {
+ int s = _node_num - 1, t = node._id;
+ if (s > t) {
+ arc._id = (_eid(t, s) << 1);
+ } else {
+ --s;
+ arc._id = (s != -1 ? (_eid(s, t) << 1) | 1 : -1);
+ }
+ }
+
+ void nextIn(Arc& arc) const {
+ int s, t;
+ _stid(arc._id, s, t);
+ --s;
+ if (s > t) {
+ arc._id = (_eid(t, s) << 1);
+ } else {
+ if (s == t) --s;
+ arc._id = (s != -1 ? (_eid(s, t) << 1) | 1 : -1);
+ }
+ }
+
+ void firstInc(Edge& edge, bool& dir, const Node& node) const {
+ int u = node._id, v = _node_num - 1;
+ if (u < v) {
+ edge._id = _eid(u, v);
+ dir = true;
+ } else {
+ --v;
+ edge._id = (v != -1 ? _eid(v, u) : -1);
+ dir = false;
+ }
+ }
+
+ void nextInc(Edge& edge, bool& dir) const {
+ int u, v;
+ if (dir) {
+ _uvid(edge._id, u, v);
+ --v;
+ if (u < v) {
+ edge._id = _eid(u, v);
+ } else {
+ --v;
+ edge._id = (v != -1 ? _eid(v, u) : -1);
+ dir = false;
+ }
+ } else {
+ _uvid(edge._id, v, u);
+ --v;
+ edge._id = (v != -1 ? _eid(v, u) : -1);
+ }
+ }
+
+ };
+
+ typedef GraphExtender<FullGraphBase> ExtendedFullGraphBase;
+
+ /// \ingroup graphs
+ ///
+ /// \brief An undirected full graph class.
+ ///
+ /// FullGraph is a simple and fast implmenetation of undirected full
+ /// (complete) graphs. It contains an edge between every distinct pair
+ /// of nodes, therefore the number of edges is <tt>n(n-1)/2</tt>.
+ /// This class is completely static and it needs constant memory space.
+ /// Thus you can neither add nor delete nodes or edges, however
+ /// the structure can be resized using resize().
+ ///
+ /// This type fully conforms to the \ref concepts::Graph "Graph concept".
+ /// Most of its member functions and nested classes are documented
+ /// only in the concept class.
+ ///
+ /// This class provides constant time counting for nodes, edges and arcs.
+ ///
+ /// \note FullDigraph and FullGraph classes are very similar,
+ /// but there are two differences. While FullDigraph
+ /// conforms only to the \ref concepts::Digraph "Digraph" concept,
+ /// this class conforms to the \ref concepts::Graph "Graph" concept,
+ /// moreover this class does not contain a loop for each
+ /// node as FullDigraph does.
+ ///
+ /// \sa FullDigraph
+ class FullGraph : public ExtendedFullGraphBase {
+ typedef ExtendedFullGraphBase Parent;
+
+ public:
+
+ /// \brief Default constructor.
+ ///
+ /// Default constructor. The number of nodes and edges will be zero.
+ FullGraph() { construct(0); }
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ /// \param n The number of the nodes.
+ FullGraph(int n) { construct(n); }
+
+ /// \brief Resizes the graph
+ ///
+ /// This function resizes the graph. It fully destroys and
+ /// rebuilds the structure, therefore the maps of the graph will be
+ /// reallocated automatically and the previous values will be lost.
+ void resize(int n) {
+ Parent::notifier(Arc()).clear();
+ Parent::notifier(Edge()).clear();
+ Parent::notifier(Node()).clear();
+ construct(n);
+ Parent::notifier(Node()).build();
+ Parent::notifier(Edge()).build();
+ Parent::notifier(Arc()).build();
+ }
+
+ /// \brief Returns the node with the given index.
+ ///
+ /// Returns the node with the given index. Since this structure is
+ /// completely static, the nodes can be indexed with integers from
+ /// the range <tt>[0..nodeNum()-1]</tt>.
+ /// The index of a node is the same as its ID.
+ /// \sa index()
+ Node operator()(int ix) const { return Parent::operator()(ix); }
+
+ /// \brief Returns the index of the given node.
+ ///
+ /// Returns the index of the given node. Since this structure is
+ /// completely static, the nodes can be indexed with integers from
+ /// the range <tt>[0..nodeNum()-1]</tt>.
+ /// The index of a node is the same as its ID.
+ /// \sa operator()()
+ static int index(const Node& node) { return Parent::index(node); }
+
+ /// \brief Returns the arc connecting the given nodes.
+ ///
+ /// Returns the arc connecting the given nodes.
+ Arc arc(Node s, Node t) const {
+ return Parent::arc(s, t);
+ }
+
+ /// \brief Returns the edge connecting the given nodes.
+ ///
+ /// Returns the edge connecting the given nodes.
+ Edge edge(Node u, Node v) const {
+ return Parent::edge(u, v);
+ }
+
+ /// \brief Number of nodes.
+ int nodeNum() const { return Parent::nodeNum(); }
+ /// \brief Number of arcs.
+ int arcNum() const { return Parent::arcNum(); }
+ /// \brief Number of edges.
+ int edgeNum() const { return Parent::edgeNum(); }
+
+ };
+
+ class FullBpGraphBase {
+
+ protected:
+
+ int _red_num, _blue_num;
+ int _node_num, _edge_num;
+
+ public:
+
+ typedef FullBpGraphBase Graph;
+
+ class Node;
+ class Arc;
+ class Edge;
+
+ class Node {
+ friend class FullBpGraphBase;
+ protected:
+
+ int _id;
+ explicit Node(int id) { _id = id;}
+
+ public:
+ Node() {}
+ Node (Invalid) { _id = -1; }
+ bool operator==(const Node& node) const {return _id == node._id;}
+ bool operator!=(const Node& node) const {return _id != node._id;}
+ bool operator<(const Node& node) const {return _id < node._id;}
+ };
+
+ class RedNode : public Node {
+ friend class FullBpGraphBase;
+ protected:
+
+ explicit RedNode(int pid) : Node(pid) {}
+
+ public:
+ RedNode() {}
+ RedNode(const RedNode& node) : Node(node) {}
+ RedNode(Invalid) : Node(INVALID){}
+ };
+
+ class BlueNode : public Node {
+ friend class FullBpGraphBase;
+ protected:
+
+ explicit BlueNode(int pid) : Node(pid) {}
+
+ public:
+ BlueNode() {}
+ BlueNode(const BlueNode& node) : Node(node) {}
+ BlueNode(Invalid) : Node(INVALID){}
+ };
+
+ class Edge {
+ friend class FullBpGraphBase;
+ protected:
+
+ int _id;
+ explicit Edge(int id) { _id = id;}
+
+ public:
+ Edge() {}
+ Edge (Invalid) { _id = -1; }
+ bool operator==(const Edge& arc) const {return _id == arc._id;}
+ bool operator!=(const Edge& arc) const {return _id != arc._id;}
+ bool operator<(const Edge& arc) const {return _id < arc._id;}
+ };
+
+ class Arc {
+ friend class FullBpGraphBase;
+ protected:
+
+ int _id;
+ explicit Arc(int id) { _id = id;}
+
+ public:
+ operator Edge() const {
+ return _id != -1 ? edgeFromId(_id / 2) : INVALID;
+ }
+
+ Arc() {}
+ Arc (Invalid) { _id = -1; }
+ bool operator==(const Arc& arc) const {return _id == arc._id;}
+ bool operator!=(const Arc& arc) const {return _id != arc._id;}
+ bool operator<(const Arc& arc) const {return _id < arc._id;}
+ };
+
+
+ protected:
+
+ FullBpGraphBase()
+ : _red_num(0), _blue_num(0), _node_num(0), _edge_num(0) {}
+
+ void construct(int redNum, int blueNum) {
+ _red_num = redNum; _blue_num = blueNum;
+ _node_num = redNum + blueNum; _edge_num = redNum * blueNum;
+ }
+
+ public:
+
+ typedef True NodeNumTag;
+ typedef True EdgeNumTag;
+ typedef True ArcNumTag;
+
+ int nodeNum() const { return _node_num; }
+ int redNum() const { return _red_num; }
+ int blueNum() const { return _blue_num; }
+ int edgeNum() const { return _edge_num; }
+ int arcNum() const { return 2 * _edge_num; }
+
+ int maxNodeId() const { return _node_num - 1; }
+ int maxRedId() const { return _red_num - 1; }
+ int maxBlueId() const { return _blue_num - 1; }
+ int maxEdgeId() const { return _edge_num - 1; }
+ int maxArcId() const { return 2 * _edge_num - 1; }
+
+ bool red(Node n) const { return n._id < _red_num; }
+ bool blue(Node n) const { return n._id >= _red_num; }
+
+ static RedNode asRedNodeUnsafe(Node n) { return RedNode(n._id); }
+ static BlueNode asBlueNodeUnsafe(Node n) { return BlueNode(n._id); }
+
+ Node source(Arc a) const {
+ if (a._id & 1) {
+ return Node((a._id >> 1) % _red_num);
+ } else {
+ return Node((a._id >> 1) / _red_num + _red_num);
+ }
+ }
+ Node target(Arc a) const {
+ if (a._id & 1) {
+ return Node((a._id >> 1) / _red_num + _red_num);
+ } else {
+ return Node((a._id >> 1) % _red_num);
+ }
+ }
+
+ RedNode redNode(Edge e) const {
+ return RedNode(e._id % _red_num);
+ }
+ BlueNode blueNode(Edge e) const {
+ return BlueNode(e._id / _red_num + _red_num);
+ }
+
+ static bool direction(Arc a) {
+ return (a._id & 1) == 1;
+ }
+
+ static Arc direct(Edge e, bool d) {
+ return Arc(e._id * 2 + (d ? 1 : 0));
+ }
+
+ void first(Node& node) const {
+ node._id = _node_num - 1;
+ }
+
+ static void next(Node& node) {
+ --node._id;
+ }
+
+ void first(RedNode& node) const {
+ node._id = _red_num - 1;
+ }
+
+ static void next(RedNode& node) {
+ --node._id;
+ }
+
+ void first(BlueNode& node) const {
+ if (_red_num == _node_num) node._id = -1;
+ else node._id = _node_num - 1;
+ }
+
+ void next(BlueNode& node) const {
+ if (node._id == _red_num) node._id = -1;
+ else --node._id;
+ }
+
+ void first(Arc& arc) const {
+ arc._id = 2 * _edge_num - 1;
+ }
+
+ static void next(Arc& arc) {
+ --arc._id;
+ }
+
+ void first(Edge& arc) const {
+ arc._id = _edge_num - 1;
+ }
+
+ static void next(Edge& arc) {
+ --arc._id;
+ }
+
+ void firstOut(Arc &a, const Node& v) const {
+ if (v._id < _red_num) {
+ a._id = 2 * (v._id + _red_num * (_blue_num - 1)) + 1;
+ } else {
+ a._id = 2 * (_red_num - 1 + _red_num * (v._id - _red_num));
+ }
+ }
+ void nextOut(Arc &a) const {
+ if (a._id & 1) {
+ a._id -= 2 * _red_num;
+ if (a._id < 0) a._id = -1;
+ } else {
+ if (a._id % (2 * _red_num) == 0) a._id = -1;
+ else a._id -= 2;
+ }
+ }
+
+ void firstIn(Arc &a, const Node& v) const {
+ if (v._id < _red_num) {
+ a._id = 2 * (v._id + _red_num * (_blue_num - 1));
+ } else {
+ a._id = 2 * (_red_num - 1 + _red_num * (v._id - _red_num)) + 1;
+ }
+ }
+ void nextIn(Arc &a) const {
+ if (a._id & 1) {
+ if (a._id % (2 * _red_num) == 1) a._id = -1;
+ else a._id -= 2;
+ } else {
+ a._id -= 2 * _red_num;
+ if (a._id < 0) a._id = -1;
+ }
+ }
+
+ void firstInc(Edge &e, bool& d, const Node& v) const {
+ if (v._id < _red_num) {
+ d = true;
+ e._id = v._id + _red_num * (_blue_num - 1);
+ } else {
+ d = false;
+ e._id = _red_num - 1 + _red_num * (v._id - _red_num);
+ }
+ }
+ void nextInc(Edge &e, bool& d) const {
+ if (d) {
+ e._id -= _red_num;
+ if (e._id < 0) e._id = -1;
+ } else {
+ if (e._id % _red_num == 0) e._id = -1;
+ else --e._id;
+ }
+ }
+
+ static int id(const Node& v) { return v._id; }
+ int id(const RedNode& v) const { return v._id; }
+ int id(const BlueNode& v) const { return v._id - _red_num; }
+ static int id(Arc e) { return e._id; }
+ static int id(Edge e) { return e._id; }
+
+ static Node nodeFromId(int id) { return Node(id);}
+ static Arc arcFromId(int id) { return Arc(id);}
+ static Edge edgeFromId(int id) { return Edge(id);}
+
+ bool valid(Node n) const {
+ return n._id >= 0 && n._id < _node_num;
+ }
+ bool valid(Arc a) const {
+ return a._id >= 0 && a._id < 2 * _edge_num;
+ }
+ bool valid(Edge e) const {
+ return e._id >= 0 && e._id < _edge_num;
+ }
+
+ RedNode redNode(int index) const {
+ return RedNode(index);
+ }
+
+ int index(RedNode n) const {
+ return n._id;
+ }
+
+ BlueNode blueNode(int index) const {
+ return BlueNode(index + _red_num);
+ }
+
+ int index(BlueNode n) const {
+ return n._id - _red_num;
+ }
+
+ void clear() {
+ _red_num = 0; _blue_num = 0;
+ _node_num = 0; _edge_num = 0;
+ }
+
+ Edge edge(const Node& u, const Node& v) const {
+ if (u._id < _red_num) {
+ if (v._id < _red_num) {
+ return Edge(-1);
+ } else {
+ return Edge(u._id + _red_num * (v._id - _red_num));
+ }
+ } else {
+ if (v._id < _red_num) {
+ return Edge(v._id + _red_num * (u._id - _red_num));
+ } else {
+ return Edge(-1);
+ }
+ }
+ }
+
+ Arc arc(const Node& u, const Node& v) const {
+ if (u._id < _red_num) {
+ if (v._id < _red_num) {
+ return Arc(-1);
+ } else {
+ return Arc(2 * (u._id + _red_num * (v._id - _red_num)) + 1);
+ }
+ } else {
+ if (v._id < _red_num) {
+ return Arc(2 * (v._id + _red_num * (u._id - _red_num)));
+ } else {
+ return Arc(-1);
+ }
+ }
+ }
+
+ typedef True FindEdgeTag;
+ typedef True FindArcTag;
+
+ Edge findEdge(Node u, Node v, Edge prev = INVALID) const {
+ return prev != INVALID ? INVALID : edge(u, v);
+ }
+
+ Arc findArc(Node s, Node t, Arc prev = INVALID) const {
+ return prev != INVALID ? INVALID : arc(s, t);
+ }
+
+ };
+
+ typedef BpGraphExtender<FullBpGraphBase> ExtendedFullBpGraphBase;
+
+ /// \ingroup graphs
+ ///
+ /// \brief An undirected full bipartite graph class.
+ ///
+ /// FullBpGraph is a simple and fast implmenetation of undirected
+ /// full bipartite graphs. It contains an edge between every
+ /// red-blue pairs of nodes, therefore the number of edges is
+ /// <tt>nr*nb</tt>. This class is completely static and it needs
+ /// constant memory space. Thus you can neither add nor delete
+ /// nodes or edges, however the structure can be resized using
+ /// resize().
+ ///
+ /// This type fully conforms to the \ref concepts::BpGraph "BpGraph concept".
+ /// Most of its member functions and nested classes are documented
+ /// only in the concept class.
+ ///
+ /// This class provides constant time counting for nodes, edges and arcs.
+ ///
+ /// \sa FullGraph
+ class FullBpGraph : public ExtendedFullBpGraphBase {
+ public:
+
+ typedef ExtendedFullBpGraphBase Parent;
+
+ /// \brief Default constructor.
+ ///
+ /// Default constructor. The number of nodes and edges will be zero.
+ FullBpGraph() { construct(0, 0); }
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ /// \param redNum The number of the red nodes.
+ /// \param blueNum The number of the blue nodes.
+ FullBpGraph(int redNum, int blueNum) { construct(redNum, blueNum); }
+
+ /// \brief Resizes the graph
+ ///
+ /// This function resizes the graph. It fully destroys and
+ /// rebuilds the structure, therefore the maps of the graph will be
+ /// reallocated automatically and the previous values will be lost.
+ void resize(int redNum, int blueNum) {
+ Parent::notifier(Arc()).clear();
+ Parent::notifier(Edge()).clear();
+ Parent::notifier(Node()).clear();
+ Parent::notifier(BlueNode()).clear();
+ Parent::notifier(RedNode()).clear();
+ construct(redNum, blueNum);
+ Parent::notifier(RedNode()).build();
+ Parent::notifier(BlueNode()).build();
+ Parent::notifier(Node()).build();
+ Parent::notifier(Edge()).build();
+ Parent::notifier(Arc()).build();
+ }
+
+ using Parent::redNode;
+ using Parent::blueNode;
+
+ /// \brief Returns the red node with the given index.
+ ///
+ /// Returns the red node with the given index. Since this
+ /// structure is completely static, the red nodes can be indexed
+ /// with integers from the range <tt>[0..redNum()-1]</tt>.
+ /// \sa redIndex()
+ RedNode redNode(int index) const { return Parent::redNode(index); }
+
+ /// \brief Returns the index of the given red node.
+ ///
+ /// Returns the index of the given red node. Since this structure
+ /// is completely static, the red nodes can be indexed with
+ /// integers from the range <tt>[0..redNum()-1]</tt>.
+ ///
+ /// \sa operator()()
+ int index(RedNode node) const { return Parent::index(node); }
+
+ /// \brief Returns the blue node with the given index.
+ ///
+ /// Returns the blue node with the given index. Since this
+ /// structure is completely static, the blue nodes can be indexed
+ /// with integers from the range <tt>[0..blueNum()-1]</tt>.
+ /// \sa blueIndex()
+ BlueNode blueNode(int index) const { return Parent::blueNode(index); }
+
+ /// \brief Returns the index of the given blue node.
+ ///
+ /// Returns the index of the given blue node. Since this structure
+ /// is completely static, the blue nodes can be indexed with
+ /// integers from the range <tt>[0..blueNum()-1]</tt>.
+ ///
+ /// \sa operator()()
+ int index(BlueNode node) const { return Parent::index(node); }
+
+ /// \brief Returns the edge which connects the given nodes.
+ ///
+ /// Returns the edge which connects the given nodes.
+ Edge edge(const Node& u, const Node& v) const {
+ return Parent::edge(u, v);
+ }
+
+ /// \brief Returns the arc which connects the given nodes.
+ ///
+ /// Returns the arc which connects the given nodes.
+ Arc arc(const Node& u, const Node& v) const {
+ return Parent::arc(u, v);
+ }
+
+ /// \brief Number of nodes.
+ int nodeNum() const { return Parent::nodeNum(); }
+ /// \brief Number of red nodes.
+ int redNum() const { return Parent::redNum(); }
+ /// \brief Number of blue nodes.
+ int blueNum() const { return Parent::blueNum(); }
+ /// \brief Number of arcs.
+ int arcNum() const { return Parent::arcNum(); }
+ /// \brief Number of edges.
+ int edgeNum() const { return Parent::edgeNum(); }
+ };
+
+
+} //namespace lemon
+
+
+#endif //LEMON_FULL_GRAPH_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/glpk.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/glpk.cc
new file mode 100644
index 00000000000..38d81151f2f
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/glpk.cc
@@ -0,0 +1,1012 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+///\file
+///\brief Implementation of the LEMON GLPK LP and MIP solver interface.
+
+#include <lemon/glpk.h>
+#include <glpk.h>
+
+#include <lemon/assert.h>
+
+namespace lemon {
+
+ // GlpkBase members
+
+ GlpkBase::GlpkBase() : LpBase() {
+ lp = glp_create_prob();
+ glp_create_index(lp);
+ messageLevel(MESSAGE_NOTHING);
+ }
+
+ GlpkBase::GlpkBase(const GlpkBase &other) : LpBase() {
+ lp = glp_create_prob();
+ glp_copy_prob(lp, other.lp, GLP_ON);
+ glp_create_index(lp);
+ rows = other.rows;
+ cols = other.cols;
+ messageLevel(MESSAGE_NOTHING);
+ }
+
+ GlpkBase::~GlpkBase() {
+ glp_delete_prob(lp);
+ }
+
+ int GlpkBase::_addCol() {
+ int i = glp_add_cols(lp, 1);
+ glp_set_col_bnds(lp, i, GLP_FR, 0.0, 0.0);
+ return i;
+ }
+
+ int GlpkBase::_addRow() {
+ int i = glp_add_rows(lp, 1);
+ glp_set_row_bnds(lp, i, GLP_FR, 0.0, 0.0);
+ return i;
+ }
+
+ int GlpkBase::_addRow(Value lo, ExprIterator b,
+ ExprIterator e, Value up) {
+ int i = glp_add_rows(lp, 1);
+
+ if (lo == -INF) {
+ if (up == INF) {
+ glp_set_row_bnds(lp, i, GLP_FR, lo, up);
+ } else {
+ glp_set_row_bnds(lp, i, GLP_UP, lo, up);
+ }
+ } else {
+ if (up == INF) {
+ glp_set_row_bnds(lp, i, GLP_LO, lo, up);
+ } else if (lo != up) {
+ glp_set_row_bnds(lp, i, GLP_DB, lo, up);
+ } else {
+ glp_set_row_bnds(lp, i, GLP_FX, lo, up);
+ }
+ }
+
+ std::vector<int> indexes;
+ std::vector<Value> values;
+
+ indexes.push_back(0);
+ values.push_back(0);
+
+ for(ExprIterator it = b; it != e; ++it) {
+ indexes.push_back(it->first);
+ values.push_back(it->second);
+ }
+
+ glp_set_mat_row(lp, i, values.size() - 1,
+ &indexes.front(), &values.front());
+ return i;
+ }
+
+ void GlpkBase::_eraseCol(int i) {
+ int ca[2];
+ ca[1] = i;
+ glp_del_cols(lp, 1, ca);
+ }
+
+ void GlpkBase::_eraseRow(int i) {
+ int ra[2];
+ ra[1] = i;
+ glp_del_rows(lp, 1, ra);
+ }
+
+ void GlpkBase::_eraseColId(int i) {
+ cols.eraseIndex(i);
+ cols.shiftIndices(i);
+ }
+
+ void GlpkBase::_eraseRowId(int i) {
+ rows.eraseIndex(i);
+ rows.shiftIndices(i);
+ }
+
+ void GlpkBase::_getColName(int c, std::string& name) const {
+ const char *str = glp_get_col_name(lp, c);
+ if (str) name = str;
+ else name.clear();
+ }
+
+ void GlpkBase::_setColName(int c, const std::string & name) {
+ glp_set_col_name(lp, c, const_cast<char*>(name.c_str()));
+
+ }
+
+ int GlpkBase::_colByName(const std::string& name) const {
+ int k = glp_find_col(lp, const_cast<char*>(name.c_str()));
+ return k > 0 ? k : -1;
+ }
+
+ void GlpkBase::_getRowName(int r, std::string& name) const {
+ const char *str = glp_get_row_name(lp, r);
+ if (str) name = str;
+ else name.clear();
+ }
+
+ void GlpkBase::_setRowName(int r, const std::string & name) {
+ glp_set_row_name(lp, r, const_cast<char*>(name.c_str()));
+
+ }
+
+ int GlpkBase::_rowByName(const std::string& name) const {
+ int k = glp_find_row(lp, const_cast<char*>(name.c_str()));
+ return k > 0 ? k : -1;
+ }
+
+ void GlpkBase::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) {
+ std::vector<int> indexes;
+ std::vector<Value> values;
+
+ indexes.push_back(0);
+ values.push_back(0);
+
+ for(ExprIterator it = b; it != e; ++it) {
+ indexes.push_back(it->first);
+ values.push_back(it->second);
+ }
+
+ glp_set_mat_row(lp, i, values.size() - 1,
+ &indexes.front(), &values.front());
+ }
+
+ void GlpkBase::_getRowCoeffs(int ix, InsertIterator b) const {
+ int length = glp_get_mat_row(lp, ix, 0, 0);
+
+ std::vector<int> indexes(length + 1);
+ std::vector<Value> values(length + 1);
+
+ glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
+
+ for (int i = 1; i <= length; ++i) {
+ *b = std::make_pair(indexes[i], values[i]);
+ ++b;
+ }
+ }
+
+ void GlpkBase::_setColCoeffs(int ix, ExprIterator b,
+ ExprIterator e) {
+
+ std::vector<int> indexes;
+ std::vector<Value> values;
+
+ indexes.push_back(0);
+ values.push_back(0);
+
+ for(ExprIterator it = b; it != e; ++it) {
+ indexes.push_back(it->first);
+ values.push_back(it->second);
+ }
+
+ glp_set_mat_col(lp, ix, values.size() - 1,
+ &indexes.front(), &values.front());
+ }
+
+ void GlpkBase::_getColCoeffs(int ix, InsertIterator b) const {
+ int length = glp_get_mat_col(lp, ix, 0, 0);
+
+ std::vector<int> indexes(length + 1);
+ std::vector<Value> values(length + 1);
+
+ glp_get_mat_col(lp, ix, &indexes.front(), &values.front());
+
+ for (int i = 1; i <= length; ++i) {
+ *b = std::make_pair(indexes[i], values[i]);
+ ++b;
+ }
+ }
+
+ void GlpkBase::_setCoeff(int ix, int jx, Value value) {
+
+ if (glp_get_num_cols(lp) < glp_get_num_rows(lp)) {
+
+ int length = glp_get_mat_row(lp, ix, 0, 0);
+
+ std::vector<int> indexes(length + 2);
+ std::vector<Value> values(length + 2);
+
+ glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
+
+ //The following code does not suppose that the elements of the
+ //array indexes are sorted
+ bool found = false;
+ for (int i = 1; i <= length; ++i) {
+ if (indexes[i] == jx) {
+ found = true;
+ values[i] = value;
+ break;
+ }
+ }
+ if (!found) {
+ ++length;
+ indexes[length] = jx;
+ values[length] = value;
+ }
+
+ glp_set_mat_row(lp, ix, length, &indexes.front(), &values.front());
+
+ } else {
+
+ int length = glp_get_mat_col(lp, jx, 0, 0);
+
+ std::vector<int> indexes(length + 2);
+ std::vector<Value> values(length + 2);
+
+ glp_get_mat_col(lp, jx, &indexes.front(), &values.front());
+
+ //The following code does not suppose that the elements of the
+ //array indexes are sorted
+ bool found = false;
+ for (int i = 1; i <= length; ++i) {
+ if (indexes[i] == ix) {
+ found = true;
+ values[i] = value;
+ break;
+ }
+ }
+ if (!found) {
+ ++length;
+ indexes[length] = ix;
+ values[length] = value;
+ }
+
+ glp_set_mat_col(lp, jx, length, &indexes.front(), &values.front());
+ }
+
+ }
+
+ GlpkBase::Value GlpkBase::_getCoeff(int ix, int jx) const {
+
+ int length = glp_get_mat_row(lp, ix, 0, 0);
+
+ std::vector<int> indexes(length + 1);
+ std::vector<Value> values(length + 1);
+
+ glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
+
+ for (int i = 1; i <= length; ++i) {
+ if (indexes[i] == jx) {
+ return values[i];
+ }
+ }
+
+ return 0;
+ }
+
+ void GlpkBase::_setColLowerBound(int i, Value lo) {
+ LEMON_ASSERT(lo != INF, "Invalid bound");
+
+ int b = glp_get_col_type(lp, i);
+ double up = glp_get_col_ub(lp, i);
+ if (lo == -INF) {
+ switch (b) {
+ case GLP_FR:
+ case GLP_LO:
+ glp_set_col_bnds(lp, i, GLP_FR, lo, up);
+ break;
+ case GLP_UP:
+ break;
+ case GLP_DB:
+ case GLP_FX:
+ glp_set_col_bnds(lp, i, GLP_UP, lo, up);
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (b) {
+ case GLP_FR:
+ case GLP_LO:
+ glp_set_col_bnds(lp, i, GLP_LO, lo, up);
+ break;
+ case GLP_UP:
+ case GLP_DB:
+ case GLP_FX:
+ if (lo == up)
+ glp_set_col_bnds(lp, i, GLP_FX, lo, up);
+ else
+ glp_set_col_bnds(lp, i, GLP_DB, lo, up);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ GlpkBase::Value GlpkBase::_getColLowerBound(int i) const {
+ int b = glp_get_col_type(lp, i);
+ switch (b) {
+ case GLP_LO:
+ case GLP_DB:
+ case GLP_FX:
+ return glp_get_col_lb(lp, i);
+ default:
+ return -INF;
+ }
+ }
+
+ void GlpkBase::_setColUpperBound(int i, Value up) {
+ LEMON_ASSERT(up != -INF, "Invalid bound");
+
+ int b = glp_get_col_type(lp, i);
+ double lo = glp_get_col_lb(lp, i);
+ if (up == INF) {
+ switch (b) {
+ case GLP_FR:
+ case GLP_LO:
+ break;
+ case GLP_UP:
+ glp_set_col_bnds(lp, i, GLP_FR, lo, up);
+ break;
+ case GLP_DB:
+ case GLP_FX:
+ glp_set_col_bnds(lp, i, GLP_LO, lo, up);
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (b) {
+ case GLP_FR:
+ glp_set_col_bnds(lp, i, GLP_UP, lo, up);
+ break;
+ case GLP_UP:
+ glp_set_col_bnds(lp, i, GLP_UP, lo, up);
+ break;
+ case GLP_LO:
+ case GLP_DB:
+ case GLP_FX:
+ if (lo == up)
+ glp_set_col_bnds(lp, i, GLP_FX, lo, up);
+ else
+ glp_set_col_bnds(lp, i, GLP_DB, lo, up);
+ break;
+ default:
+ break;
+ }
+ }
+
+ }
+
+ GlpkBase::Value GlpkBase::_getColUpperBound(int i) const {
+ int b = glp_get_col_type(lp, i);
+ switch (b) {
+ case GLP_UP:
+ case GLP_DB:
+ case GLP_FX:
+ return glp_get_col_ub(lp, i);
+ default:
+ return INF;
+ }
+ }
+
+ void GlpkBase::_setRowLowerBound(int i, Value lo) {
+ LEMON_ASSERT(lo != INF, "Invalid bound");
+
+ int b = glp_get_row_type(lp, i);
+ double up = glp_get_row_ub(lp, i);
+ if (lo == -INF) {
+ switch (b) {
+ case GLP_FR:
+ case GLP_LO:
+ glp_set_row_bnds(lp, i, GLP_FR, lo, up);
+ break;
+ case GLP_UP:
+ break;
+ case GLP_DB:
+ case GLP_FX:
+ glp_set_row_bnds(lp, i, GLP_UP, lo, up);
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (b) {
+ case GLP_FR:
+ case GLP_LO:
+ glp_set_row_bnds(lp, i, GLP_LO, lo, up);
+ break;
+ case GLP_UP:
+ case GLP_DB:
+ case GLP_FX:
+ if (lo == up)
+ glp_set_row_bnds(lp, i, GLP_FX, lo, up);
+ else
+ glp_set_row_bnds(lp, i, GLP_DB, lo, up);
+ break;
+ default:
+ break;
+ }
+ }
+
+ }
+
+ GlpkBase::Value GlpkBase::_getRowLowerBound(int i) const {
+ int b = glp_get_row_type(lp, i);
+ switch (b) {
+ case GLP_LO:
+ case GLP_DB:
+ case GLP_FX:
+ return glp_get_row_lb(lp, i);
+ default:
+ return -INF;
+ }
+ }
+
+ void GlpkBase::_setRowUpperBound(int i, Value up) {
+ LEMON_ASSERT(up != -INF, "Invalid bound");
+
+ int b = glp_get_row_type(lp, i);
+ double lo = glp_get_row_lb(lp, i);
+ if (up == INF) {
+ switch (b) {
+ case GLP_FR:
+ case GLP_LO:
+ break;
+ case GLP_UP:
+ glp_set_row_bnds(lp, i, GLP_FR, lo, up);
+ break;
+ case GLP_DB:
+ case GLP_FX:
+ glp_set_row_bnds(lp, i, GLP_LO, lo, up);
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (b) {
+ case GLP_FR:
+ glp_set_row_bnds(lp, i, GLP_UP, lo, up);
+ break;
+ case GLP_UP:
+ glp_set_row_bnds(lp, i, GLP_UP, lo, up);
+ break;
+ case GLP_LO:
+ case GLP_DB:
+ case GLP_FX:
+ if (lo == up)
+ glp_set_row_bnds(lp, i, GLP_FX, lo, up);
+ else
+ glp_set_row_bnds(lp, i, GLP_DB, lo, up);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ GlpkBase::Value GlpkBase::_getRowUpperBound(int i) const {
+ int b = glp_get_row_type(lp, i);
+ switch (b) {
+ case GLP_UP:
+ case GLP_DB:
+ case GLP_FX:
+ return glp_get_row_ub(lp, i);
+ default:
+ return INF;
+ }
+ }
+
+ void GlpkBase::_setObjCoeffs(ExprIterator b, ExprIterator e) {
+ for (int i = 1; i <= glp_get_num_cols(lp); ++i) {
+ glp_set_obj_coef(lp, i, 0.0);
+ }
+ for (ExprIterator it = b; it != e; ++it) {
+ glp_set_obj_coef(lp, it->first, it->second);
+ }
+ }
+
+ void GlpkBase::_getObjCoeffs(InsertIterator b) const {
+ for (int i = 1; i <= glp_get_num_cols(lp); ++i) {
+ Value val = glp_get_obj_coef(lp, i);
+ if (val != 0.0) {
+ *b = std::make_pair(i, val);
+ ++b;
+ }
+ }
+ }
+
+ void GlpkBase::_setObjCoeff(int i, Value obj_coef) {
+ //i = 0 means the constant term (shift)
+ glp_set_obj_coef(lp, i, obj_coef);
+ }
+
+ GlpkBase::Value GlpkBase::_getObjCoeff(int i) const {
+ //i = 0 means the constant term (shift)
+ return glp_get_obj_coef(lp, i);
+ }
+
+ void GlpkBase::_setSense(GlpkBase::Sense sense) {
+ switch (sense) {
+ case MIN:
+ glp_set_obj_dir(lp, GLP_MIN);
+ break;
+ case MAX:
+ glp_set_obj_dir(lp, GLP_MAX);
+ break;
+ }
+ }
+
+ GlpkBase::Sense GlpkBase::_getSense() const {
+ switch(glp_get_obj_dir(lp)) {
+ case GLP_MIN:
+ return MIN;
+ case GLP_MAX:
+ return MAX;
+ default:
+ LEMON_ASSERT(false, "Wrong sense");
+ return GlpkBase::Sense();
+ }
+ }
+
+ void GlpkBase::_clear() {
+ glp_erase_prob(lp);
+ }
+
+ void GlpkBase::freeEnv() {
+ glp_free_env();
+ }
+
+ void GlpkBase::_messageLevel(MessageLevel level) {
+ switch (level) {
+ case MESSAGE_NOTHING:
+ _message_level = GLP_MSG_OFF;
+ break;
+ case MESSAGE_ERROR:
+ _message_level = GLP_MSG_ERR;
+ break;
+ case MESSAGE_WARNING:
+ _message_level = GLP_MSG_ERR;
+ break;
+ case MESSAGE_NORMAL:
+ _message_level = GLP_MSG_ON;
+ break;
+ case MESSAGE_VERBOSE:
+ _message_level = GLP_MSG_ALL;
+ break;
+ }
+ }
+
+ void GlpkBase::_write(std::string file, std::string format) const
+ {
+ if(format == "MPS")
+ glp_write_mps(lp, GLP_MPS_FILE, 0, file.c_str());
+ else if(format == "LP")
+ glp_write_lp(lp, 0, file.c_str());
+ else throw UnsupportedFormatError(format);
+ }
+
+ GlpkBase::FreeEnvHelper GlpkBase::freeEnvHelper;
+
+ // GlpkLp members
+
+ GlpkLp::GlpkLp()
+ : LpBase(), LpSolver(), GlpkBase() {
+ presolver(false);
+ }
+
+ GlpkLp::GlpkLp(const GlpkLp& other)
+ : LpBase(other), LpSolver(other), GlpkBase(other) {
+ presolver(false);
+ }
+
+ GlpkLp* GlpkLp::newSolver() const { return new GlpkLp; }
+ GlpkLp* GlpkLp::cloneSolver() const { return new GlpkLp(*this); }
+
+ const char* GlpkLp::_solverName() const { return "GlpkLp"; }
+
+ void GlpkLp::_clear_temporals() {
+ _primal_ray.clear();
+ _dual_ray.clear();
+ }
+
+ GlpkLp::SolveExitStatus GlpkLp::_solve() {
+ return solvePrimal();
+ }
+
+ GlpkLp::SolveExitStatus GlpkLp::solvePrimal() {
+ _clear_temporals();
+
+ glp_smcp smcp;
+ glp_init_smcp(&smcp);
+
+ smcp.msg_lev = _message_level;
+ smcp.presolve = _presolve;
+
+ // If the basis is not valid we get an error return value.
+ // In this case we can try to create a new basis.
+ switch (glp_simplex(lp, &smcp)) {
+ case 0:
+ break;
+ case GLP_EBADB:
+ case GLP_ESING:
+ case GLP_ECOND:
+ glp_term_out(false);
+ glp_adv_basis(lp, 0);
+ glp_term_out(true);
+ if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
+ break;
+ default:
+ return UNSOLVED;
+ }
+
+ return SOLVED;
+ }
+
+ GlpkLp::SolveExitStatus GlpkLp::solveDual() {
+ _clear_temporals();
+
+ glp_smcp smcp;
+ glp_init_smcp(&smcp);
+
+ smcp.msg_lev = _message_level;
+ smcp.meth = GLP_DUAL;
+ smcp.presolve = _presolve;
+
+ // If the basis is not valid we get an error return value.
+ // In this case we can try to create a new basis.
+ switch (glp_simplex(lp, &smcp)) {
+ case 0:
+ break;
+ case GLP_EBADB:
+ case GLP_ESING:
+ case GLP_ECOND:
+ glp_term_out(false);
+ glp_adv_basis(lp, 0);
+ glp_term_out(true);
+ if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
+ break;
+ default:
+ return UNSOLVED;
+ }
+ return SOLVED;
+ }
+
+ GlpkLp::Value GlpkLp::_getPrimal(int i) const {
+ return glp_get_col_prim(lp, i);
+ }
+
+ GlpkLp::Value GlpkLp::_getDual(int i) const {
+ return glp_get_row_dual(lp, i);
+ }
+
+ GlpkLp::Value GlpkLp::_getPrimalValue() const {
+ return glp_get_obj_val(lp);
+ }
+
+ GlpkLp::VarStatus GlpkLp::_getColStatus(int i) const {
+ switch (glp_get_col_stat(lp, i)) {
+ case GLP_BS:
+ return BASIC;
+ case GLP_UP:
+ return UPPER;
+ case GLP_LO:
+ return LOWER;
+ case GLP_NF:
+ return FREE;
+ case GLP_NS:
+ return FIXED;
+ default:
+ LEMON_ASSERT(false, "Wrong column status");
+ return GlpkLp::VarStatus();
+ }
+ }
+
+ GlpkLp::VarStatus GlpkLp::_getRowStatus(int i) const {
+ switch (glp_get_row_stat(lp, i)) {
+ case GLP_BS:
+ return BASIC;
+ case GLP_UP:
+ return UPPER;
+ case GLP_LO:
+ return LOWER;
+ case GLP_NF:
+ return FREE;
+ case GLP_NS:
+ return FIXED;
+ default:
+ LEMON_ASSERT(false, "Wrong row status");
+ return GlpkLp::VarStatus();
+ }
+ }
+
+ GlpkLp::Value GlpkLp::_getPrimalRay(int i) const {
+ if (_primal_ray.empty()) {
+ int row_num = glp_get_num_rows(lp);
+ int col_num = glp_get_num_cols(lp);
+
+ _primal_ray.resize(col_num + 1, 0.0);
+
+ int index = glp_get_unbnd_ray(lp);
+ if (index != 0) {
+ // The primal ray is found in primal simplex second phase
+ LEMON_ASSERT((index <= row_num ? glp_get_row_stat(lp, index) :
+ glp_get_col_stat(lp, index - row_num)) != GLP_BS,
+ "Wrong primal ray");
+
+ bool negate = glp_get_obj_dir(lp) == GLP_MAX;
+
+ if (index > row_num) {
+ _primal_ray[index - row_num] = 1.0;
+ if (glp_get_col_dual(lp, index - row_num) > 0) {
+ negate = !negate;
+ }
+ } else {
+ if (glp_get_row_dual(lp, index) > 0) {
+ negate = !negate;
+ }
+ }
+
+ std::vector<int> ray_indexes(row_num + 1);
+ std::vector<Value> ray_values(row_num + 1);
+ int ray_length = glp_eval_tab_col(lp, index, &ray_indexes.front(),
+ &ray_values.front());
+
+ for (int i = 1; i <= ray_length; ++i) {
+ if (ray_indexes[i] > row_num) {
+ _primal_ray[ray_indexes[i] - row_num] = ray_values[i];
+ }
+ }
+
+ if (negate) {
+ for (int i = 1; i <= col_num; ++i) {
+ _primal_ray[i] = - _primal_ray[i];
+ }
+ }
+ } else {
+ for (int i = 1; i <= col_num; ++i) {
+ _primal_ray[i] = glp_get_col_prim(lp, i);
+ }
+ }
+ }
+ return _primal_ray[i];
+ }
+
+ GlpkLp::Value GlpkLp::_getDualRay(int i) const {
+ if (_dual_ray.empty()) {
+ int row_num = glp_get_num_rows(lp);
+
+ _dual_ray.resize(row_num + 1, 0.0);
+
+ int index = glp_get_unbnd_ray(lp);
+ if (index != 0) {
+ // The dual ray is found in dual simplex second phase
+ LEMON_ASSERT((index <= row_num ? glp_get_row_stat(lp, index) :
+ glp_get_col_stat(lp, index - row_num)) == GLP_BS,
+
+ "Wrong dual ray");
+
+ int idx;
+ bool negate = false;
+
+ if (index > row_num) {
+ idx = glp_get_col_bind(lp, index - row_num);
+ if (glp_get_col_prim(lp, index - row_num) >
+ glp_get_col_ub(lp, index - row_num)) {
+ negate = true;
+ }
+ } else {
+ idx = glp_get_row_bind(lp, index);
+ if (glp_get_row_prim(lp, index) > glp_get_row_ub(lp, index)) {
+ negate = true;
+ }
+ }
+
+ _dual_ray[idx] = negate ? - 1.0 : 1.0;
+
+ glp_btran(lp, &_dual_ray.front());
+ } else {
+ double eps = 1e-7;
+ // The dual ray is found in primal simplex first phase
+ // We assume that the glpk minimizes the slack to get feasible solution
+ for (int i = 1; i <= row_num; ++i) {
+ int index = glp_get_bhead(lp, i);
+ if (index <= row_num) {
+ double res = glp_get_row_prim(lp, index);
+ if (res > glp_get_row_ub(lp, index) + eps) {
+ _dual_ray[i] = -1;
+ } else if (res < glp_get_row_lb(lp, index) - eps) {
+ _dual_ray[i] = 1;
+ } else {
+ _dual_ray[i] = 0;
+ }
+ _dual_ray[i] *= glp_get_rii(lp, index);
+ } else {
+ double res = glp_get_col_prim(lp, index - row_num);
+ if (res > glp_get_col_ub(lp, index - row_num) + eps) {
+ _dual_ray[i] = -1;
+ } else if (res < glp_get_col_lb(lp, index - row_num) - eps) {
+ _dual_ray[i] = 1;
+ } else {
+ _dual_ray[i] = 0;
+ }
+ _dual_ray[i] /= glp_get_sjj(lp, index - row_num);
+ }
+ }
+
+ glp_btran(lp, &_dual_ray.front());
+
+ for (int i = 1; i <= row_num; ++i) {
+ _dual_ray[i] /= glp_get_rii(lp, i);
+ }
+ }
+ }
+ return _dual_ray[i];
+ }
+
+ GlpkLp::ProblemType GlpkLp::_getPrimalType() const {
+ if (glp_get_status(lp) == GLP_OPT)
+ return OPTIMAL;
+ switch (glp_get_prim_stat(lp)) {
+ case GLP_UNDEF:
+ return UNDEFINED;
+ case GLP_FEAS:
+ case GLP_INFEAS:
+ if (glp_get_dual_stat(lp) == GLP_NOFEAS) {
+ return UNBOUNDED;
+ } else {
+ return UNDEFINED;
+ }
+ case GLP_NOFEAS:
+ return INFEASIBLE;
+ default:
+ LEMON_ASSERT(false, "Wrong primal type");
+ return GlpkLp::ProblemType();
+ }
+ }
+
+ GlpkLp::ProblemType GlpkLp::_getDualType() const {
+ if (glp_get_status(lp) == GLP_OPT)
+ return OPTIMAL;
+ switch (glp_get_dual_stat(lp)) {
+ case GLP_UNDEF:
+ return UNDEFINED;
+ case GLP_FEAS:
+ case GLP_INFEAS:
+ if (glp_get_prim_stat(lp) == GLP_NOFEAS) {
+ return UNBOUNDED;
+ } else {
+ return UNDEFINED;
+ }
+ case GLP_NOFEAS:
+ return INFEASIBLE;
+ default:
+ LEMON_ASSERT(false, "Wrong primal type");
+ return GlpkLp::ProblemType();
+ }
+ }
+
+ void GlpkLp::presolver(bool presolve) {
+ _presolve = presolve;
+ }
+
+ // GlpkMip members
+
+ GlpkMip::GlpkMip()
+ : LpBase(), MipSolver(), GlpkBase() {
+ }
+
+ GlpkMip::GlpkMip(const GlpkMip& other)
+ : LpBase(), MipSolver(), GlpkBase(other) {
+ }
+
+ void GlpkMip::_setColType(int i, GlpkMip::ColTypes col_type) {
+ switch (col_type) {
+ case INTEGER:
+ glp_set_col_kind(lp, i, GLP_IV);
+ break;
+ case REAL:
+ glp_set_col_kind(lp, i, GLP_CV);
+ break;
+ }
+ }
+
+ GlpkMip::ColTypes GlpkMip::_getColType(int i) const {
+ switch (glp_get_col_kind(lp, i)) {
+ case GLP_IV:
+ case GLP_BV:
+ return INTEGER;
+ default:
+ return REAL;
+ }
+
+ }
+
+ GlpkMip::SolveExitStatus GlpkMip::_solve() {
+ glp_smcp smcp;
+ glp_init_smcp(&smcp);
+
+ smcp.msg_lev = _message_level;
+ smcp.meth = GLP_DUAL;
+
+ // If the basis is not valid we get an error return value.
+ // In this case we can try to create a new basis.
+ switch (glp_simplex(lp, &smcp)) {
+ case 0:
+ break;
+ case GLP_EBADB:
+ case GLP_ESING:
+ case GLP_ECOND:
+ glp_term_out(false);
+ glp_adv_basis(lp, 0);
+ glp_term_out(true);
+ if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
+ break;
+ default:
+ return UNSOLVED;
+ }
+
+ if (glp_get_status(lp) != GLP_OPT) return SOLVED;
+
+ glp_iocp iocp;
+ glp_init_iocp(&iocp);
+
+ iocp.msg_lev = _message_level;
+
+ if (glp_intopt(lp, &iocp) != 0) return UNSOLVED;
+ return SOLVED;
+ }
+
+
+ GlpkMip::ProblemType GlpkMip::_getType() const {
+ switch (glp_get_status(lp)) {
+ case GLP_OPT:
+ switch (glp_mip_status(lp)) {
+ case GLP_UNDEF:
+ return UNDEFINED;
+ case GLP_NOFEAS:
+ return INFEASIBLE;
+ case GLP_FEAS:
+ return FEASIBLE;
+ case GLP_OPT:
+ return OPTIMAL;
+ default:
+ LEMON_ASSERT(false, "Wrong problem type.");
+ return GlpkMip::ProblemType();
+ }
+ case GLP_NOFEAS:
+ return INFEASIBLE;
+ case GLP_INFEAS:
+ case GLP_FEAS:
+ if (glp_get_dual_stat(lp) == GLP_NOFEAS) {
+ return UNBOUNDED;
+ } else {
+ return UNDEFINED;
+ }
+ default:
+ LEMON_ASSERT(false, "Wrong problem type.");
+ return GlpkMip::ProblemType();
+ }
+ }
+
+ GlpkMip::Value GlpkMip::_getSol(int i) const {
+ return glp_mip_col_val(lp, i);
+ }
+
+ GlpkMip::Value GlpkMip::_getSolValue() const {
+ return glp_mip_obj_val(lp);
+ }
+
+ GlpkMip* GlpkMip::newSolver() const { return new GlpkMip; }
+ GlpkMip* GlpkMip::cloneSolver() const {return new GlpkMip(*this); }
+
+ const char* GlpkMip::_solverName() const { return "GlpkMip"; }
+
+
+
+} //END OF NAMESPACE LEMON
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/glpk.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/glpk.h
new file mode 100644
index 00000000000..ccdc54ac059
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/glpk.h
@@ -0,0 +1,263 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_GLPK_H
+#define LEMON_GLPK_H
+
+///\file
+///\brief Header of the LEMON-GLPK lp solver interface.
+///\ingroup lp_group
+
+#include <lemon/lp_base.h>
+
+namespace lemon {
+
+ namespace _solver_bits {
+ class VoidPtr {
+ private:
+ void *_ptr;
+ public:
+ VoidPtr() : _ptr(0) {}
+
+ template <typename T>
+ VoidPtr(T* ptr) : _ptr(reinterpret_cast<void*>(ptr)) {}
+
+ template <typename T>
+ VoidPtr& operator=(T* ptr) {
+ _ptr = reinterpret_cast<void*>(ptr);
+ return *this;
+ }
+
+ template <typename T>
+ operator T*() const { return reinterpret_cast<T*>(_ptr); }
+ };
+ }
+
+ /// \brief Base interface for the GLPK LP and MIP solver
+ ///
+ /// This class implements the common interface of the GLPK LP and MIP solver.
+ /// \ingroup lp_group
+ class GlpkBase : virtual public LpBase {
+ protected:
+
+ _solver_bits::VoidPtr lp;
+
+ GlpkBase();
+ GlpkBase(const GlpkBase&);
+ virtual ~GlpkBase();
+
+ protected:
+
+ virtual int _addCol();
+ virtual int _addRow();
+ virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u);
+
+ virtual void _eraseCol(int i);
+ virtual void _eraseRow(int i);
+
+ virtual void _eraseColId(int i);
+ virtual void _eraseRowId(int i);
+
+ virtual void _getColName(int col, std::string& name) const;
+ virtual void _setColName(int col, const std::string& name);
+ virtual int _colByName(const std::string& name) const;
+
+ virtual void _getRowName(int row, std::string& name) const;
+ virtual void _setRowName(int row, const std::string& name);
+ virtual int _rowByName(const std::string& name) const;
+
+ virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e);
+ virtual void _getRowCoeffs(int i, InsertIterator b) const;
+
+ virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e);
+ virtual void _getColCoeffs(int i, InsertIterator b) const;
+
+ virtual void _setCoeff(int row, int col, Value value);
+ virtual Value _getCoeff(int row, int col) const;
+
+ virtual void _setColLowerBound(int i, Value value);
+ virtual Value _getColLowerBound(int i) const;
+
+ virtual void _setColUpperBound(int i, Value value);
+ virtual Value _getColUpperBound(int i) const;
+
+ virtual void _setRowLowerBound(int i, Value value);
+ virtual Value _getRowLowerBound(int i) const;
+
+ virtual void _setRowUpperBound(int i, Value value);
+ virtual Value _getRowUpperBound(int i) const;
+
+ virtual void _setObjCoeffs(ExprIterator b, ExprIterator e);
+ virtual void _getObjCoeffs(InsertIterator b) const;
+
+ virtual void _setObjCoeff(int i, Value obj_coef);
+ virtual Value _getObjCoeff(int i) const;
+
+ virtual void _setSense(Sense);
+ virtual Sense _getSense() const;
+
+ virtual void _clear();
+
+ virtual void _messageLevel(MessageLevel level);
+
+ virtual void _write(std::string file, std::string format) const;
+
+ private:
+
+ static void freeEnv();
+
+ struct FreeEnvHelper {
+ ~FreeEnvHelper() {
+ freeEnv();
+ }
+ };
+
+ static FreeEnvHelper freeEnvHelper;
+
+ protected:
+
+ int _message_level;
+
+ public:
+
+ ///Pointer to the underlying GLPK data structure.
+ _solver_bits::VoidPtr lpx() {return lp;}
+ ///Const pointer to the underlying GLPK data structure.
+ _solver_bits::VoidPtr lpx() const {return lp;}
+
+ ///Returns the constraint identifier understood by GLPK.
+ int lpxRow(Row r) const { return rows(id(r)); }
+
+ ///Returns the variable identifier understood by GLPK.
+ int lpxCol(Col c) const { return cols(id(c)); }
+
+#ifdef DOXYGEN
+ /// Write the problem or the solution to a file in the given format
+
+ /// This function writes the problem or the solution
+ /// to a file in the given format.
+ /// Trying to write in an unsupported format will trigger
+ /// \ref LpBase::UnsupportedFormatError.
+ /// \param file The file path
+ /// \param format The output file format.
+ /// Supportted formats are "MPS" and "LP".
+ void write(std::string file, std::string format = "MPS") const {}
+#endif
+
+ };
+
+ /// \brief Interface for the GLPK LP solver
+ ///
+ /// This class implements an interface for the GLPK LP solver.
+ ///\ingroup lp_group
+ class GlpkLp : public LpSolver, public GlpkBase {
+ public:
+
+ ///\e
+ GlpkLp();
+ ///\e
+ GlpkLp(const GlpkLp&);
+
+ ///\e
+ virtual GlpkLp* cloneSolver() const;
+ ///\e
+ virtual GlpkLp* newSolver() const;
+
+ private:
+
+ mutable std::vector<double> _primal_ray;
+ mutable std::vector<double> _dual_ray;
+
+ void _clear_temporals();
+
+ protected:
+
+ virtual const char* _solverName() const;
+
+ virtual SolveExitStatus _solve();
+ virtual Value _getPrimal(int i) const;
+ virtual Value _getDual(int i) const;
+
+ virtual Value _getPrimalValue() const;
+
+ virtual VarStatus _getColStatus(int i) const;
+ virtual VarStatus _getRowStatus(int i) const;
+
+ virtual Value _getPrimalRay(int i) const;
+ virtual Value _getDualRay(int i) const;
+
+ virtual ProblemType _getPrimalType() const;
+ virtual ProblemType _getDualType() const;
+
+ public:
+
+ ///Solve with primal simplex
+ SolveExitStatus solvePrimal();
+
+ ///Solve with dual simplex
+ SolveExitStatus solveDual();
+
+ private:
+
+ bool _presolve;
+
+ public:
+
+ ///Turns on or off the presolver
+
+ ///Turns on (\c b is \c true) or off (\c b is \c false) the presolver
+ ///
+ ///The presolver is off by default.
+ void presolver(bool presolve);
+
+ };
+
+ /// \brief Interface for the GLPK MIP solver
+ ///
+ /// This class implements an interface for the GLPK MIP solver.
+ ///\ingroup lp_group
+ class GlpkMip : public MipSolver, public GlpkBase {
+ public:
+
+ ///\e
+ GlpkMip();
+ ///\e
+ GlpkMip(const GlpkMip&);
+
+ virtual GlpkMip* cloneSolver() const;
+ virtual GlpkMip* newSolver() const;
+
+ protected:
+
+ virtual const char* _solverName() const;
+
+ virtual ColTypes _getColType(int col) const;
+ virtual void _setColType(int col, ColTypes col_type);
+
+ virtual SolveExitStatus _solve();
+ virtual ProblemType _getType() const;
+ virtual Value _getSol(int i) const;
+ virtual Value _getSolValue() const;
+
+ };
+
+
+} //END OF NAMESPACE LEMON
+
+#endif //LEMON_GLPK_H
+
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/gomory_hu.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/gomory_hu.h
new file mode 100644
index 00000000000..c43305f88e1
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/gomory_hu.h
@@ -0,0 +1,568 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_GOMORY_HU_TREE_H
+#define LEMON_GOMORY_HU_TREE_H
+
+#include <limits>
+
+#include <lemon/core.h>
+#include <lemon/preflow.h>
+#include <lemon/concept_check.h>
+#include <lemon/concepts/maps.h>
+
+/// \ingroup min_cut
+/// \file
+/// \brief Gomory-Hu cut tree in graphs.
+
+namespace lemon {
+
+ /// \ingroup min_cut
+ ///
+ /// \brief Gomory-Hu cut tree algorithm
+ ///
+ /// The Gomory-Hu tree is a tree on the node set of a given graph, but it
+ /// may contain edges which are not in the original graph. It has the
+ /// property that the minimum capacity edge of the path between two nodes
+ /// in this tree has the same weight as the minimum cut in the graph
+ /// between these nodes. Moreover the components obtained by removing
+ /// this edge from the tree determine the corresponding minimum cut.
+ /// Therefore once this tree is computed, the minimum cut between any pair
+ /// of nodes can easily be obtained.
+ ///
+ /// The algorithm calculates \e n-1 distinct minimum cuts (currently with
+ /// the \ref Preflow algorithm), thus it has \f$O(n^3\sqrt{m})\f$ overall
+ /// time complexity. It calculates a rooted Gomory-Hu tree.
+ /// The structure of the tree and the edge weights can be
+ /// obtained using \c predNode(), \c predValue() and \c rootDist().
+ /// The functions \c minCutMap() and \c minCutValue() calculate
+ /// the minimum cut and the minimum cut value between any two nodes
+ /// in the graph. You can also list (iterate on) the nodes and the
+ /// edges of the cuts using \c MinCutNodeIt and \c MinCutEdgeIt.
+ ///
+ /// \tparam GR The type of the undirected graph the algorithm runs on.
+ /// \tparam CAP The type of the edge map containing the capacities.
+ /// The default map type is \ref concepts::Graph::EdgeMap "GR::EdgeMap<int>".
+#ifdef DOXYGEN
+ template <typename GR,
+ typename CAP>
+#else
+ template <typename GR,
+ typename CAP = typename GR::template EdgeMap<int> >
+#endif
+ class GomoryHu {
+ public:
+
+ /// The graph type of the algorithm
+ typedef GR Graph;
+ /// The capacity map type of the algorithm
+ typedef CAP Capacity;
+ /// The value type of capacities
+ typedef typename Capacity::Value Value;
+
+ private:
+
+ TEMPLATE_GRAPH_TYPEDEFS(Graph);
+
+ const Graph& _graph;
+ const Capacity& _capacity;
+
+ Node _root;
+ typename Graph::template NodeMap<Node>* _pred;
+ typename Graph::template NodeMap<Value>* _weight;
+ typename Graph::template NodeMap<int>* _order;
+
+ void createStructures() {
+ if (!_pred) {
+ _pred = new typename Graph::template NodeMap<Node>(_graph);
+ }
+ if (!_weight) {
+ _weight = new typename Graph::template NodeMap<Value>(_graph);
+ }
+ if (!_order) {
+ _order = new typename Graph::template NodeMap<int>(_graph);
+ }
+ }
+
+ void destroyStructures() {
+ if (_pred) {
+ delete _pred;
+ }
+ if (_weight) {
+ delete _weight;
+ }
+ if (_order) {
+ delete _order;
+ }
+ }
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ /// \param graph The undirected graph the algorithm runs on.
+ /// \param capacity The edge capacity map.
+ GomoryHu(const Graph& graph, const Capacity& capacity)
+ : _graph(graph), _capacity(capacity),
+ _pred(0), _weight(0), _order(0)
+ {
+ checkConcept<concepts::ReadMap<Edge, Value>, Capacity>();
+ }
+
+
+ /// \brief Destructor
+ ///
+ /// Destructor.
+ ~GomoryHu() {
+ destroyStructures();
+ }
+
+ private:
+
+ // Initialize the internal data structures
+ void init() {
+ createStructures();
+
+ _root = NodeIt(_graph);
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ (*_pred)[n] = _root;
+ (*_order)[n] = -1;
+ }
+ (*_pred)[_root] = INVALID;
+ (*_weight)[_root] = std::numeric_limits<Value>::max();
+ }
+
+
+ // Start the algorithm
+ void start() {
+ Preflow<Graph, Capacity> fa(_graph, _capacity, _root, INVALID);
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ if (n == _root) continue;
+
+ Node pn = (*_pred)[n];
+ fa.source(n);
+ fa.target(pn);
+
+ fa.runMinCut();
+
+ (*_weight)[n] = fa.flowValue();
+
+ for (NodeIt nn(_graph); nn != INVALID; ++nn) {
+ if (nn != n && fa.minCut(nn) && (*_pred)[nn] == pn) {
+ (*_pred)[nn] = n;
+ }
+ }
+ if ((*_pred)[pn] != INVALID && fa.minCut((*_pred)[pn])) {
+ (*_pred)[n] = (*_pred)[pn];
+ (*_pred)[pn] = n;
+ (*_weight)[n] = (*_weight)[pn];
+ (*_weight)[pn] = fa.flowValue();
+ }
+ }
+
+ (*_order)[_root] = 0;
+ int index = 1;
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ std::vector<Node> st;
+ Node nn = n;
+ while ((*_order)[nn] == -1) {
+ st.push_back(nn);
+ nn = (*_pred)[nn];
+ }
+ while (!st.empty()) {
+ (*_order)[st.back()] = index++;
+ st.pop_back();
+ }
+ }
+ }
+
+ public:
+
+ ///\name Execution Control
+
+ ///@{
+
+ /// \brief Run the Gomory-Hu algorithm.
+ ///
+ /// This function runs the Gomory-Hu algorithm.
+ void run() {
+ init();
+ start();
+ }
+
+ /// @}
+
+ ///\name Query Functions
+ ///The results of the algorithm can be obtained using these
+ ///functions.\n
+ ///\ref run() should be called before using them.\n
+ ///See also \ref MinCutNodeIt and \ref MinCutEdgeIt.
+
+ ///@{
+
+ /// \brief Return the predecessor node in the Gomory-Hu tree.
+ ///
+ /// This function returns the predecessor node of the given node
+ /// in the Gomory-Hu tree.
+ /// If \c node is the root of the tree, then it returns \c INVALID.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ Node predNode(const Node& node) const {
+ return (*_pred)[node];
+ }
+
+ /// \brief Return the weight of the predecessor edge in the
+ /// Gomory-Hu tree.
+ ///
+ /// This function returns the weight of the predecessor edge of the
+ /// given node in the Gomory-Hu tree.
+ /// If \c node is the root of the tree, the result is undefined.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ Value predValue(const Node& node) const {
+ return (*_weight)[node];
+ }
+
+ /// \brief Return the distance from the root node in the Gomory-Hu tree.
+ ///
+ /// This function returns the distance of the given node from the root
+ /// node in the Gomory-Hu tree.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ int rootDist(const Node& node) const {
+ return (*_order)[node];
+ }
+
+ /// \brief Return the minimum cut value between two nodes
+ ///
+ /// This function returns the minimum cut value between the nodes
+ /// \c s and \c t.
+ /// It finds the nearest common ancestor of the given nodes in the
+ /// Gomory-Hu tree and calculates the minimum weight edge on the
+ /// paths to the ancestor.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ Value minCutValue(const Node& s, const Node& t) const {
+ Node sn = s, tn = t;
+ Value value = std::numeric_limits<Value>::max();
+
+ while (sn != tn) {
+ if ((*_order)[sn] < (*_order)[tn]) {
+ if ((*_weight)[tn] <= value) value = (*_weight)[tn];
+ tn = (*_pred)[tn];
+ } else {
+ if ((*_weight)[sn] <= value) value = (*_weight)[sn];
+ sn = (*_pred)[sn];
+ }
+ }
+ return value;
+ }
+
+ /// \brief Return the minimum cut between two nodes
+ ///
+ /// This function returns the minimum cut between the nodes \c s and \c t
+ /// in the \c cutMap parameter by setting the nodes in the component of
+ /// \c s to \c true and the other nodes to \c false.
+ ///
+ /// For higher level interfaces see MinCutNodeIt and MinCutEdgeIt.
+ ///
+ /// \param s The base node.
+ /// \param t The node you want to separate from node \c s.
+ /// \param cutMap The cut will be returned in this map.
+ /// It must be a \c bool (or convertible) \ref concepts::ReadWriteMap
+ /// "ReadWriteMap" on the graph nodes.
+ ///
+ /// \return The value of the minimum cut between \c s and \c t.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ template <typename CutMap>
+ Value minCutMap(const Node& s,
+ const Node& t,
+ CutMap& cutMap
+ ) const {
+ Node sn = s, tn = t;
+ bool s_root=false;
+ Node rn = INVALID;
+ Value value = std::numeric_limits<Value>::max();
+
+ while (sn != tn) {
+ if ((*_order)[sn] < (*_order)[tn]) {
+ if ((*_weight)[tn] <= value) {
+ rn = tn;
+ s_root = false;
+ value = (*_weight)[tn];
+ }
+ tn = (*_pred)[tn];
+ } else {
+ if ((*_weight)[sn] <= value) {
+ rn = sn;
+ s_root = true;
+ value = (*_weight)[sn];
+ }
+ sn = (*_pred)[sn];
+ }
+ }
+
+ typename Graph::template NodeMap<bool> reached(_graph, false);
+ reached[_root] = true;
+ cutMap.set(_root, !s_root);
+ reached[rn] = true;
+ cutMap.set(rn, s_root);
+
+ std::vector<Node> st;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ st.clear();
+ Node nn = n;
+ while (!reached[nn]) {
+ st.push_back(nn);
+ nn = (*_pred)[nn];
+ }
+ while (!st.empty()) {
+ cutMap.set(st.back(), cutMap[nn]);
+ st.pop_back();
+ }
+ }
+
+ return value;
+ }
+
+ ///@}
+
+ friend class MinCutNodeIt;
+
+ /// Iterate on the nodes of a minimum cut
+
+ /// This iterator class lists the nodes of a minimum cut found by
+ /// GomoryHu. Before using it, you must allocate a GomoryHu class
+ /// and call its \ref GomoryHu::run() "run()" method.
+ ///
+ /// This example counts the nodes in the minimum cut separating \c s from
+ /// \c t.
+ /// \code
+ /// GomoryHu<Graph> gom(g, capacities);
+ /// gom.run();
+ /// int cnt=0;
+ /// for(GomoryHu<Graph>::MinCutNodeIt n(gom,s,t); n!=INVALID; ++n) ++cnt;
+ /// \endcode
+ class MinCutNodeIt
+ {
+ bool _side;
+ typename Graph::NodeIt _node_it;
+ typename Graph::template NodeMap<bool> _cut;
+ public:
+ /// Constructor
+
+ /// Constructor.
+ ///
+ MinCutNodeIt(GomoryHu const &gomory,
+ ///< The GomoryHu class. You must call its
+ /// run() method
+ /// before initializing this iterator.
+ const Node& s, ///< The base node.
+ const Node& t,
+ ///< The node you want to separate from node \c s.
+ bool side=true
+ ///< If it is \c true (default) then the iterator lists
+ /// the nodes of the component containing \c s,
+ /// otherwise it lists the other component.
+ /// \note As the minimum cut is not always unique,
+ /// \code
+ /// MinCutNodeIt(gomory, s, t, true);
+ /// \endcode
+ /// and
+ /// \code
+ /// MinCutNodeIt(gomory, t, s, false);
+ /// \endcode
+ /// does not necessarily give the same set of nodes.
+ /// However, it is ensured that
+ /// \code
+ /// MinCutNodeIt(gomory, s, t, true);
+ /// \endcode
+ /// and
+ /// \code
+ /// MinCutNodeIt(gomory, s, t, false);
+ /// \endcode
+ /// together list each node exactly once.
+ )
+ : _side(side), _cut(gomory._graph)
+ {
+ gomory.minCutMap(s,t,_cut);
+ for(_node_it=typename Graph::NodeIt(gomory._graph);
+ _node_it!=INVALID && _cut[_node_it]!=_side;
+ ++_node_it) {}
+ }
+ /// Conversion to \c Node
+
+ /// Conversion to \c Node.
+ ///
+ operator typename Graph::Node() const
+ {
+ return _node_it;
+ }
+ bool operator==(Invalid) { return _node_it==INVALID; }
+ bool operator!=(Invalid) { return _node_it!=INVALID; }
+ /// Next node
+
+ /// Next node.
+ ///
+ MinCutNodeIt &operator++()
+ {
+ for(++_node_it;_node_it!=INVALID&&_cut[_node_it]!=_side;++_node_it) {}
+ return *this;
+ }
+ /// Postfix incrementation
+
+ /// Postfix incrementation.
+ ///
+ /// \warning This incrementation
+ /// returns a \c Node, not a \c MinCutNodeIt, as one may
+ /// expect.
+ typename Graph::Node operator++(int)
+ {
+ typename Graph::Node n=*this;
+ ++(*this);
+ return n;
+ }
+ };
+
+ friend class MinCutEdgeIt;
+
+ /// Iterate on the edges of a minimum cut
+
+ /// This iterator class lists the edges of a minimum cut found by
+ /// GomoryHu. Before using it, you must allocate a GomoryHu class
+ /// and call its \ref GomoryHu::run() "run()" method.
+ ///
+ /// This example computes the value of the minimum cut separating \c s from
+ /// \c t.
+ /// \code
+ /// GomoryHu<Graph> gom(g, capacities);
+ /// gom.run();
+ /// int value=0;
+ /// for(GomoryHu<Graph>::MinCutEdgeIt e(gom,s,t); e!=INVALID; ++e)
+ /// value+=capacities[e];
+ /// \endcode
+ /// The result will be the same as the value returned by
+ /// \ref GomoryHu::minCutValue() "gom.minCutValue(s,t)".
+ class MinCutEdgeIt
+ {
+ bool _side;
+ const Graph &_graph;
+ typename Graph::NodeIt _node_it;
+ typename Graph::OutArcIt _arc_it;
+ typename Graph::template NodeMap<bool> _cut;
+ void step()
+ {
+ ++_arc_it;
+ while(_node_it!=INVALID && _arc_it==INVALID)
+ {
+ for(++_node_it;_node_it!=INVALID&&!_cut[_node_it];++_node_it) {}
+ if(_node_it!=INVALID)
+ _arc_it=typename Graph::OutArcIt(_graph,_node_it);
+ }
+ }
+
+ public:
+ /// Constructor
+
+ /// Constructor.
+ ///
+ MinCutEdgeIt(GomoryHu const &gomory,
+ ///< The GomoryHu class. You must call its
+ /// run() method
+ /// before initializing this iterator.
+ const Node& s, ///< The base node.
+ const Node& t,
+ ///< The node you want to separate from node \c s.
+ bool side=true
+ ///< If it is \c true (default) then the listed arcs
+ /// will be oriented from the
+ /// nodes of the component containing \c s,
+ /// otherwise they will be oriented in the opposite
+ /// direction.
+ )
+ : _graph(gomory._graph), _cut(_graph)
+ {
+ gomory.minCutMap(s,t,_cut);
+ if(!side)
+ for(typename Graph::NodeIt n(_graph);n!=INVALID;++n)
+ _cut[n]=!_cut[n];
+
+ for(_node_it=typename Graph::NodeIt(_graph);
+ _node_it!=INVALID && !_cut[_node_it];
+ ++_node_it) {}
+ _arc_it = _node_it!=INVALID ?
+ typename Graph::OutArcIt(_graph,_node_it) : INVALID;
+ while(_node_it!=INVALID && _arc_it == INVALID)
+ {
+ for(++_node_it; _node_it!=INVALID&&!_cut[_node_it]; ++_node_it) {}
+ if(_node_it!=INVALID)
+ _arc_it= typename Graph::OutArcIt(_graph,_node_it);
+ }
+ while(_arc_it!=INVALID && _cut[_graph.target(_arc_it)]) step();
+ }
+ /// Conversion to \c Arc
+
+ /// Conversion to \c Arc.
+ ///
+ operator typename Graph::Arc() const
+ {
+ return _arc_it;
+ }
+ /// Conversion to \c Edge
+
+ /// Conversion to \c Edge.
+ ///
+ operator typename Graph::Edge() const
+ {
+ return _arc_it;
+ }
+ bool operator==(Invalid) { return _node_it==INVALID; }
+ bool operator!=(Invalid) { return _node_it!=INVALID; }
+ /// Next edge
+
+ /// Next edge.
+ ///
+ MinCutEdgeIt &operator++()
+ {
+ step();
+ while(_arc_it!=INVALID && _cut[_graph.target(_arc_it)]) step();
+ return *this;
+ }
+ /// Postfix incrementation
+
+ /// Postfix incrementation.
+ ///
+ /// \warning This incrementation
+ /// returns an \c Arc, not a \c MinCutEdgeIt, as one may expect.
+ typename Graph::Arc operator++(int)
+ {
+ typename Graph::Arc e=*this;
+ ++(*this);
+ return e;
+ }
+ };
+
+ };
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/graph_to_eps.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/graph_to_eps.h
new file mode 100644
index 00000000000..29ba836937d
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/graph_to_eps.h
@@ -0,0 +1,1186 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_GRAPH_TO_EPS_H
+#define LEMON_GRAPH_TO_EPS_H
+
+#include<iostream>
+#include<fstream>
+#include<sstream>
+#include<algorithm>
+#include<vector>
+
+#ifndef WIN32
+#include<sys/time.h>
+#include<ctime>
+#else
+#include<lemon/bits/windows.h>
+#endif
+
+#include<lemon/math.h>
+#include<lemon/core.h>
+#include<lemon/dim2.h>
+#include<lemon/maps.h>
+#include<lemon/color.h>
+#include<lemon/bits/bezier.h>
+#include<lemon/error.h>
+
+
+///\ingroup eps_io
+///\file
+///\brief A well configurable tool for visualizing graphs
+
+namespace lemon {
+
+ namespace _graph_to_eps_bits {
+ template<class MT>
+ class _NegY {
+ public:
+ typedef typename MT::Key Key;
+ typedef typename MT::Value Value;
+ const MT &map;
+ int yscale;
+ _NegY(const MT &m,bool b) : map(m), yscale(1-b*2) {}
+ Value operator[](Key n) { return Value(map[n].x,map[n].y*yscale);}
+ };
+ }
+
+///Default traits class of GraphToEps
+
+///Default traits class of \ref GraphToEps.
+///
+///\param GR is the type of the underlying graph.
+template<class GR>
+struct DefaultGraphToEpsTraits
+{
+ typedef GR Graph;
+ typedef GR Digraph;
+ typedef typename Graph::Node Node;
+ typedef typename Graph::NodeIt NodeIt;
+ typedef typename Graph::Arc Arc;
+ typedef typename Graph::ArcIt ArcIt;
+ typedef typename Graph::InArcIt InArcIt;
+ typedef typename Graph::OutArcIt OutArcIt;
+
+
+ const Graph &g;
+
+ std::ostream& os;
+
+ typedef ConstMap<typename Graph::Node,dim2::Point<double> > CoordsMapType;
+ CoordsMapType _coords;
+ ConstMap<typename Graph::Node,double > _nodeSizes;
+ ConstMap<typename Graph::Node,int > _nodeShapes;
+
+ ConstMap<typename Graph::Node,Color > _nodeColors;
+ ConstMap<typename Graph::Arc,Color > _arcColors;
+
+ ConstMap<typename Graph::Arc,double > _arcWidths;
+
+ double _arcWidthScale;
+
+ double _nodeScale;
+ double _xBorder, _yBorder;
+ double _scale;
+ double _nodeBorderQuotient;
+
+ bool _drawArrows;
+ double _arrowLength, _arrowWidth;
+
+ bool _showNodes, _showArcs;
+
+ bool _enableParallel;
+ double _parArcDist;
+
+ bool _showNodeText;
+ ConstMap<typename Graph::Node,bool > _nodeTexts;
+ double _nodeTextSize;
+
+ bool _showNodePsText;
+ ConstMap<typename Graph::Node,bool > _nodePsTexts;
+ char *_nodePsTextsPreamble;
+
+ bool _undirected;
+
+ bool _pleaseRemoveOsStream;
+
+ bool _scaleToA4;
+
+ std::string _title;
+ std::string _copyright;
+
+ enum NodeTextColorType
+ { DIST_COL=0, DIST_BW=1, CUST_COL=2, SAME_COL=3 } _nodeTextColorType;
+ ConstMap<typename Graph::Node,Color > _nodeTextColors;
+
+ bool _autoNodeScale;
+ bool _autoArcWidthScale;
+
+ bool _absoluteNodeSizes;
+ bool _absoluteArcWidths;
+
+ bool _negY;
+
+ bool _preScale;
+ ///Constructor
+
+ ///Constructor
+ ///\param gr Reference to the graph to be printed.
+ ///\param ost Reference to the output stream.
+ ///By default, it is <tt>std::cout</tt>.
+ ///\param pros If it is \c true, then the \c ostream referenced by \c os
+ ///will be explicitly deallocated by the destructor.
+ DefaultGraphToEpsTraits(const GR &gr, std::ostream& ost = std::cout,
+ bool pros = false) :
+ g(gr), os(ost),
+ _coords(dim2::Point<double>(1,1)), _nodeSizes(1), _nodeShapes(0),
+ _nodeColors(WHITE), _arcColors(BLACK),
+ _arcWidths(1.0), _arcWidthScale(0.003),
+ _nodeScale(.01), _xBorder(10), _yBorder(10), _scale(1.0),
+ _nodeBorderQuotient(.1),
+ _drawArrows(false), _arrowLength(1), _arrowWidth(0.3),
+ _showNodes(true), _showArcs(true),
+ _enableParallel(false), _parArcDist(1),
+ _showNodeText(false), _nodeTexts(false), _nodeTextSize(1),
+ _showNodePsText(false), _nodePsTexts(false), _nodePsTextsPreamble(0),
+ _undirected(lemon::UndirectedTagIndicator<GR>::value),
+ _pleaseRemoveOsStream(pros), _scaleToA4(false),
+ _nodeTextColorType(SAME_COL), _nodeTextColors(BLACK),
+ _autoNodeScale(false),
+ _autoArcWidthScale(false),
+ _absoluteNodeSizes(false),
+ _absoluteArcWidths(false),
+ _negY(false),
+ _preScale(true)
+ {}
+};
+
+///Auxiliary class to implement the named parameters of \ref graphToEps()
+
+///Auxiliary class to implement the named parameters of \ref graphToEps().
+///
+///For detailed examples see the \ref graph_to_eps_demo.cc demo file.
+template<class T> class GraphToEps : public T
+{
+ // Can't believe it is required by the C++ standard
+ using T::g;
+ using T::os;
+
+ using T::_coords;
+ using T::_nodeSizes;
+ using T::_nodeShapes;
+ using T::_nodeColors;
+ using T::_arcColors;
+ using T::_arcWidths;
+
+ using T::_arcWidthScale;
+ using T::_nodeScale;
+ using T::_xBorder;
+ using T::_yBorder;
+ using T::_scale;
+ using T::_nodeBorderQuotient;
+
+ using T::_drawArrows;
+ using T::_arrowLength;
+ using T::_arrowWidth;
+
+ using T::_showNodes;
+ using T::_showArcs;
+
+ using T::_enableParallel;
+ using T::_parArcDist;
+
+ using T::_showNodeText;
+ using T::_nodeTexts;
+ using T::_nodeTextSize;
+
+ using T::_showNodePsText;
+ using T::_nodePsTexts;
+ using T::_nodePsTextsPreamble;
+
+ using T::_undirected;
+
+ using T::_pleaseRemoveOsStream;
+
+ using T::_scaleToA4;
+
+ using T::_title;
+ using T::_copyright;
+
+ using T::CUST_COL;
+ using T::DIST_COL;
+ using T::DIST_BW;
+ using T::_nodeTextColorType;
+ using T::_nodeTextColors;
+
+ using T::_autoNodeScale;
+ using T::_autoArcWidthScale;
+
+ using T::_absoluteNodeSizes;
+ using T::_absoluteArcWidths;
+
+
+ using T::_negY;
+ using T::_preScale;
+
+ // dradnats ++C eht yb deriuqer si ti eveileb t'naC
+
+ typedef typename T::Graph Graph;
+ typedef typename T::Digraph Digraph;
+ typedef typename Graph::Node Node;
+ typedef typename Graph::NodeIt NodeIt;
+ typedef typename Graph::Arc Arc;
+ typedef typename Graph::ArcIt ArcIt;
+ typedef typename Graph::InArcIt InArcIt;
+ typedef typename Graph::OutArcIt OutArcIt;
+
+ static const int INTERPOL_PREC;
+ static const double A4HEIGHT;
+ static const double A4WIDTH;
+ static const double A4BORDER;
+
+ bool dontPrint;
+
+public:
+ ///Node shapes
+
+ ///Node shapes.
+ ///
+ enum NodeShapes {
+ /// = 0
+ ///\image html nodeshape_0.png
+ ///\image latex nodeshape_0.eps "CIRCLE shape (0)" width=2cm
+ CIRCLE=0,
+ /// = 1
+ ///\image html nodeshape_1.png
+ ///\image latex nodeshape_1.eps "SQUARE shape (1)" width=2cm
+ SQUARE=1,
+ /// = 2
+ ///\image html nodeshape_2.png
+ ///\image latex nodeshape_2.eps "DIAMOND shape (2)" width=2cm
+ DIAMOND=2,
+ /// = 3
+ ///\image html nodeshape_3.png
+ ///\image latex nodeshape_3.eps "MALE shape (3)" width=2cm
+ MALE=3,
+ /// = 4
+ ///\image html nodeshape_4.png
+ ///\image latex nodeshape_4.eps "FEMALE shape (4)" width=2cm
+ FEMALE=4
+ };
+
+private:
+ class arcLess {
+ const Graph &g;
+ public:
+ arcLess(const Graph &_g) : g(_g) {}
+ bool operator()(Arc a,Arc b) const
+ {
+ Node ai=std::min(g.source(a),g.target(a));
+ Node aa=std::max(g.source(a),g.target(a));
+ Node bi=std::min(g.source(b),g.target(b));
+ Node ba=std::max(g.source(b),g.target(b));
+ return ai<bi ||
+ (ai==bi && (aa < ba ||
+ (aa==ba && ai==g.source(a) && bi==g.target(b))));
+ }
+ };
+ bool isParallel(Arc e,Arc f) const
+ {
+ return (g.source(e)==g.source(f)&&
+ g.target(e)==g.target(f)) ||
+ (g.source(e)==g.target(f)&&
+ g.target(e)==g.source(f));
+ }
+ template<class TT>
+ static std::string psOut(const dim2::Point<TT> &p)
+ {
+ std::ostringstream os;
+ os << p.x << ' ' << p.y;
+ return os.str();
+ }
+ static std::string psOut(const Color &c)
+ {
+ std::ostringstream os;
+ os << c.red() << ' ' << c.green() << ' ' << c.blue();
+ return os.str();
+ }
+
+public:
+ GraphToEps(const T &t) : T(t), dontPrint(false) {};
+
+ template<class X> struct CoordsTraits : public T {
+ typedef X CoordsMapType;
+ const X &_coords;
+ CoordsTraits(const T &t,const X &x) : T(t), _coords(x) {}
+ };
+ ///Sets the map of the node coordinates
+
+ ///Sets the map of the node coordinates.
+ ///\param x must be a node map with \ref dim2::Point "dim2::Point<double>" or
+ ///\ref dim2::Point "dim2::Point<int>" values.
+ template<class X> GraphToEps<CoordsTraits<X> > coords(const X &x) {
+ dontPrint=true;
+ return GraphToEps<CoordsTraits<X> >(CoordsTraits<X>(*this,x));
+ }
+ template<class X> struct NodeSizesTraits : public T {
+ const X &_nodeSizes;
+ NodeSizesTraits(const T &t,const X &x) : T(t), _nodeSizes(x) {}
+ };
+ ///Sets the map of the node sizes
+
+ ///Sets the map of the node sizes.
+ ///\param x must be a node map with \c double (or convertible) values.
+ template<class X> GraphToEps<NodeSizesTraits<X> > nodeSizes(const X &x)
+ {
+ dontPrint=true;
+ return GraphToEps<NodeSizesTraits<X> >(NodeSizesTraits<X>(*this,x));
+ }
+ template<class X> struct NodeShapesTraits : public T {
+ const X &_nodeShapes;
+ NodeShapesTraits(const T &t,const X &x) : T(t), _nodeShapes(x) {}
+ };
+ ///Sets the map of the node shapes
+
+ ///Sets the map of the node shapes.
+ ///The available shape values
+ ///can be found in \ref NodeShapes "enum NodeShapes".
+ ///\param x must be a node map with \c int (or convertible) values.
+ ///\sa NodeShapes
+ template<class X> GraphToEps<NodeShapesTraits<X> > nodeShapes(const X &x)
+ {
+ dontPrint=true;
+ return GraphToEps<NodeShapesTraits<X> >(NodeShapesTraits<X>(*this,x));
+ }
+ template<class X> struct NodeTextsTraits : public T {
+ const X &_nodeTexts;
+ NodeTextsTraits(const T &t,const X &x) : T(t), _nodeTexts(x) {}
+ };
+ ///Sets the text printed on the nodes
+
+ ///Sets the text printed on the nodes.
+ ///\param x must be a node map with type that can be pushed to a standard
+ ///\c ostream.
+ template<class X> GraphToEps<NodeTextsTraits<X> > nodeTexts(const X &x)
+ {
+ dontPrint=true;
+ _showNodeText=true;
+ return GraphToEps<NodeTextsTraits<X> >(NodeTextsTraits<X>(*this,x));
+ }
+ template<class X> struct NodePsTextsTraits : public T {
+ const X &_nodePsTexts;
+ NodePsTextsTraits(const T &t,const X &x) : T(t), _nodePsTexts(x) {}
+ };
+ ///Inserts a PostScript block to the nodes
+
+ ///With this command it is possible to insert a verbatim PostScript
+ ///block to the nodes.
+ ///The PS current point will be moved to the center of the node before
+ ///the PostScript block inserted.
+ ///
+ ///Before and after the block a newline character is inserted so you
+ ///don't have to bother with the separators.
+ ///
+ ///\param x must be a node map with type that can be pushed to a standard
+ ///\c ostream.
+ ///
+ ///\sa nodePsTextsPreamble()
+ template<class X> GraphToEps<NodePsTextsTraits<X> > nodePsTexts(const X &x)
+ {
+ dontPrint=true;
+ _showNodePsText=true;
+ return GraphToEps<NodePsTextsTraits<X> >(NodePsTextsTraits<X>(*this,x));
+ }
+ template<class X> struct ArcWidthsTraits : public T {
+ const X &_arcWidths;
+ ArcWidthsTraits(const T &t,const X &x) : T(t), _arcWidths(x) {}
+ };
+ ///Sets the map of the arc widths
+
+ ///Sets the map of the arc widths.
+ ///\param x must be an arc map with \c double (or convertible) values.
+ template<class X> GraphToEps<ArcWidthsTraits<X> > arcWidths(const X &x)
+ {
+ dontPrint=true;
+ return GraphToEps<ArcWidthsTraits<X> >(ArcWidthsTraits<X>(*this,x));
+ }
+
+ template<class X> struct NodeColorsTraits : public T {
+ const X &_nodeColors;
+ NodeColorsTraits(const T &t,const X &x) : T(t), _nodeColors(x) {}
+ };
+ ///Sets the map of the node colors
+
+ ///Sets the map of the node colors.
+ ///\param x must be a node map with \ref Color values.
+ ///
+ ///\sa Palette
+ template<class X> GraphToEps<NodeColorsTraits<X> >
+ nodeColors(const X &x)
+ {
+ dontPrint=true;
+ return GraphToEps<NodeColorsTraits<X> >(NodeColorsTraits<X>(*this,x));
+ }
+ template<class X> struct NodeTextColorsTraits : public T {
+ const X &_nodeTextColors;
+ NodeTextColorsTraits(const T &t,const X &x) : T(t), _nodeTextColors(x) {}
+ };
+ ///Sets the map of the node text colors
+
+ ///Sets the map of the node text colors.
+ ///\param x must be a node map with \ref Color values.
+ ///
+ ///\sa Palette
+ template<class X> GraphToEps<NodeTextColorsTraits<X> >
+ nodeTextColors(const X &x)
+ {
+ dontPrint=true;
+ _nodeTextColorType=CUST_COL;
+ return GraphToEps<NodeTextColorsTraits<X> >
+ (NodeTextColorsTraits<X>(*this,x));
+ }
+ template<class X> struct ArcColorsTraits : public T {
+ const X &_arcColors;
+ ArcColorsTraits(const T &t,const X &x) : T(t), _arcColors(x) {}
+ };
+ ///Sets the map of the arc colors
+
+ ///Sets the map of the arc colors.
+ ///\param x must be an arc map with \ref Color values.
+ ///
+ ///\sa Palette
+ template<class X> GraphToEps<ArcColorsTraits<X> >
+ arcColors(const X &x)
+ {
+ dontPrint=true;
+ return GraphToEps<ArcColorsTraits<X> >(ArcColorsTraits<X>(*this,x));
+ }
+ ///Sets a global scale factor for node sizes
+
+ ///Sets a global scale factor for node sizes.
+ ///
+ /// If nodeSizes() is not given, this function simply sets the node
+ /// sizes to \c d. If nodeSizes() is given, but
+ /// autoNodeScale() is not, then the node size given by
+ /// nodeSizes() will be multiplied by the value \c d.
+ /// If both nodeSizes() and autoNodeScale() are used, then the
+ /// node sizes will be scaled in such a way that the greatest size will be
+ /// equal to \c d.
+ /// \sa nodeSizes()
+ /// \sa autoNodeScale()
+ GraphToEps<T> &nodeScale(double d=.01) {_nodeScale=d;return *this;}
+ ///Turns on/off the automatic node size scaling.
+
+ ///Turns on/off the automatic node size scaling.
+ ///
+ ///\sa nodeScale()
+ ///
+ GraphToEps<T> &autoNodeScale(bool b=true) {
+ _autoNodeScale=b;return *this;
+ }
+
+ ///Turns on/off the absolutematic node size scaling.
+
+ ///Turns on/off the absolutematic node size scaling.
+ ///
+ ///\sa nodeScale()
+ ///
+ GraphToEps<T> &absoluteNodeSizes(bool b=true) {
+ _absoluteNodeSizes=b;return *this;
+ }
+
+ ///Negates the Y coordinates.
+ GraphToEps<T> &negateY(bool b=true) {
+ _negY=b;return *this;
+ }
+
+ ///Turn on/off pre-scaling
+
+ ///By default, graphToEps() rescales the whole image in order to avoid
+ ///very big or very small bounding boxes.
+ ///
+ ///This (p)rescaling can be turned off with this function.
+ ///
+ GraphToEps<T> &preScale(bool b=true) {
+ _preScale=b;return *this;
+ }
+
+ ///Sets a global scale factor for arc widths
+
+ /// Sets a global scale factor for arc widths.
+ ///
+ /// If arcWidths() is not given, this function simply sets the arc
+ /// widths to \c d. If arcWidths() is given, but
+ /// autoArcWidthScale() is not, then the arc withs given by
+ /// arcWidths() will be multiplied by the value \c d.
+ /// If both arcWidths() and autoArcWidthScale() are used, then the
+ /// arc withs will be scaled in such a way that the greatest width will be
+ /// equal to \c d.
+ GraphToEps<T> &arcWidthScale(double d=.003) {_arcWidthScale=d;return *this;}
+ ///Turns on/off the automatic arc width scaling.
+
+ ///Turns on/off the automatic arc width scaling.
+ ///
+ ///\sa arcWidthScale()
+ ///
+ GraphToEps<T> &autoArcWidthScale(bool b=true) {
+ _autoArcWidthScale=b;return *this;
+ }
+ ///Turns on/off the absolutematic arc width scaling.
+
+ ///Turns on/off the absolutematic arc width scaling.
+ ///
+ ///\sa arcWidthScale()
+ ///
+ GraphToEps<T> &absoluteArcWidths(bool b=true) {
+ _absoluteArcWidths=b;return *this;
+ }
+ ///Sets a global scale factor for the whole picture
+ GraphToEps<T> &scale(double d) {_scale=d;return *this;}
+ ///Sets the width of the border around the picture
+ GraphToEps<T> &border(double b=10) {_xBorder=_yBorder=b;return *this;}
+ ///Sets the width of the border around the picture
+ GraphToEps<T> &border(double x, double y) {
+ _xBorder=x;_yBorder=y;return *this;
+ }
+ ///Sets whether to draw arrows
+ GraphToEps<T> &drawArrows(bool b=true) {_drawArrows=b;return *this;}
+ ///Sets the length of the arrowheads
+ GraphToEps<T> &arrowLength(double d=1.0) {_arrowLength*=d;return *this;}
+ ///Sets the width of the arrowheads
+ GraphToEps<T> &arrowWidth(double d=.3) {_arrowWidth*=d;return *this;}
+
+ ///Scales the drawing to fit to A4 page
+ GraphToEps<T> &scaleToA4() {_scaleToA4=true;return *this;}
+
+ ///Enables parallel arcs
+ GraphToEps<T> &enableParallel(bool b=true) {_enableParallel=b;return *this;}
+
+ ///Sets the distance between parallel arcs
+ GraphToEps<T> &parArcDist(double d) {_parArcDist*=d;return *this;}
+
+ ///Hides the arcs
+ GraphToEps<T> &hideArcs(bool b=true) {_showArcs=!b;return *this;}
+ ///Hides the nodes
+ GraphToEps<T> &hideNodes(bool b=true) {_showNodes=!b;return *this;}
+
+ ///Sets the size of the node texts
+ GraphToEps<T> &nodeTextSize(double d) {_nodeTextSize=d;return *this;}
+
+ ///Sets the color of the node texts to be different from the node color
+
+ ///Sets the color of the node texts to be as different from the node color
+ ///as it is possible.
+ GraphToEps<T> &distantColorNodeTexts()
+ {_nodeTextColorType=DIST_COL;return *this;}
+ ///Sets the color of the node texts to be black or white and always visible.
+
+ ///Sets the color of the node texts to be black or white according to
+ ///which is more different from the node color.
+ GraphToEps<T> &distantBWNodeTexts()
+ {_nodeTextColorType=DIST_BW;return *this;}
+
+ ///Gives a preamble block for node Postscript block.
+
+ ///Gives a preamble block for node Postscript block.
+ ///
+ ///\sa nodePsTexts()
+ GraphToEps<T> & nodePsTextsPreamble(const char *str) {
+ _nodePsTextsPreamble=str ;return *this;
+ }
+ ///Sets whether the graph is undirected
+
+ ///Sets whether the graph is undirected.
+ ///
+ ///This setting is the default for undirected graphs.
+ ///
+ ///\sa directed()
+ GraphToEps<T> &undirected(bool b=true) {_undirected=b;return *this;}
+
+ ///Sets whether the graph is directed
+
+ ///Sets whether the graph is directed.
+ ///Use it to show the edges as a pair of directed ones.
+ ///
+ ///This setting is the default for digraphs.
+ ///
+ ///\sa undirected()
+ GraphToEps<T> &directed(bool b=true) {_undirected=!b;return *this;}
+
+ ///Sets the title.
+
+ ///Sets the title of the generated image,
+ ///namely it inserts a <tt>%%Title:</tt> DSC field to the header of
+ ///the EPS file.
+ GraphToEps<T> &title(const std::string &t) {_title=t;return *this;}
+ ///Sets the copyright statement.
+
+ ///Sets the copyright statement of the generated image,
+ ///namely it inserts a <tt>%%Copyright:</tt> DSC field to the header of
+ ///the EPS file.
+ GraphToEps<T> &copyright(const std::string &t) {_copyright=t;return *this;}
+
+protected:
+ bool isInsideNode(dim2::Point<double> p, double r,int t)
+ {
+ switch(t) {
+ case CIRCLE:
+ case MALE:
+ case FEMALE:
+ return p.normSquare()<=r*r;
+ case SQUARE:
+ return p.x<=r&&p.x>=-r&&p.y<=r&&p.y>=-r;
+ case DIAMOND:
+ return p.x+p.y<=r && p.x-p.y<=r && -p.x+p.y<=r && -p.x-p.y<=r;
+ }
+ return false;
+ }
+
+public:
+ ~GraphToEps() { }
+
+ ///Draws the graph.
+
+ ///Like other functions using
+ ///\ref named-templ-func-param "named template parameters",
+ ///this function calls the algorithm itself, i.e. in this case
+ ///it draws the graph.
+ void run() {
+ const double EPSILON=1e-9;
+ if(dontPrint) return;
+
+ _graph_to_eps_bits::_NegY<typename T::CoordsMapType>
+ mycoords(_coords,_negY);
+
+ os << "%!PS-Adobe-2.0 EPSF-2.0\n";
+ if(_title.size()>0) os << "%%Title: " << _title << '\n';
+ if(_copyright.size()>0) os << "%%Copyright: " << _copyright << '\n';
+ os << "%%Creator: LEMON, graphToEps()\n";
+
+ {
+ os << "%%CreationDate: ";
+#ifndef WIN32
+ timeval tv;
+ gettimeofday(&tv, 0);
+
+ char cbuf[26];
+ ctime_r(&tv.tv_sec,cbuf);
+ os << cbuf;
+#else
+ os << bits::getWinFormattedDate();
+ os << std::endl;
+#endif
+ }
+
+ if (_autoArcWidthScale) {
+ double max_w=0;
+ for(ArcIt e(g);e!=INVALID;++e)
+ max_w=std::max(double(_arcWidths[e]),max_w);
+ if(max_w>EPSILON) {
+ _arcWidthScale/=max_w;
+ }
+ }
+
+ if (_autoNodeScale) {
+ double max_s=0;
+ for(NodeIt n(g);n!=INVALID;++n)
+ max_s=std::max(double(_nodeSizes[n]),max_s);
+ if(max_s>EPSILON) {
+ _nodeScale/=max_s;
+ }
+ }
+
+ double diag_len = 1;
+ if(!(_absoluteNodeSizes&&_absoluteArcWidths)) {
+ dim2::Box<double> bb;
+ for(NodeIt n(g);n!=INVALID;++n) bb.add(mycoords[n]);
+ if (bb.empty()) {
+ bb = dim2::Box<double>(dim2::Point<double>(0,0));
+ }
+ diag_len = std::sqrt((bb.bottomLeft()-bb.topRight()).normSquare());
+ if(diag_len<EPSILON) diag_len = 1;
+ if(!_absoluteNodeSizes) _nodeScale*=diag_len;
+ if(!_absoluteArcWidths) _arcWidthScale*=diag_len;
+ }
+
+ dim2::Box<double> bb;
+ for(NodeIt n(g);n!=INVALID;++n) {
+ double ns=_nodeSizes[n]*_nodeScale;
+ dim2::Point<double> p(ns,ns);
+ switch(_nodeShapes[n]) {
+ case CIRCLE:
+ case SQUARE:
+ case DIAMOND:
+ bb.add(p+mycoords[n]);
+ bb.add(-p+mycoords[n]);
+ break;
+ case MALE:
+ bb.add(-p+mycoords[n]);
+ bb.add(dim2::Point<double>(1.5*ns,1.5*std::sqrt(3.0)*ns)+mycoords[n]);
+ break;
+ case FEMALE:
+ bb.add(p+mycoords[n]);
+ bb.add(dim2::Point<double>(-ns,-3.01*ns)+mycoords[n]);
+ break;
+ }
+ }
+ if (bb.empty()) {
+ bb = dim2::Box<double>(dim2::Point<double>(0,0));
+ }
+
+ if(_scaleToA4)
+ os <<"%%BoundingBox: 0 0 596 842\n%%DocumentPaperSizes: a4\n";
+ else {
+ if(_preScale) {
+ //Rescale so that BoundingBox won't be neither to big nor too small.
+ while(bb.height()*_scale>1000||bb.width()*_scale>1000) _scale/=10;
+ while(bb.height()*_scale<100||bb.width()*_scale<100) _scale*=10;
+ }
+
+ os << "%%BoundingBox: "
+ << int(floor(bb.left() * _scale - _xBorder)) << ' '
+ << int(floor(bb.bottom() * _scale - _yBorder)) << ' '
+ << int(ceil(bb.right() * _scale + _xBorder)) << ' '
+ << int(ceil(bb.top() * _scale + _yBorder)) << '\n';
+ }
+
+ os << "%%EndComments\n";
+
+ //x1 y1 x2 y2 x3 y3 cr cg cb w
+ os << "/lb { setlinewidth setrgbcolor newpath moveto\n"
+ << " 4 2 roll 1 index 1 index curveto stroke } bind def\n";
+ os << "/l { setlinewidth setrgbcolor newpath moveto lineto stroke }"
+ << " bind def\n";
+ //x y r
+ os << "/c { newpath dup 3 index add 2 index moveto 0 360 arc closepath }"
+ << " bind def\n";
+ //x y r
+ os << "/sq { newpath 2 index 1 index add 2 index 2 index add moveto\n"
+ << " 2 index 1 index sub 2 index 2 index add lineto\n"
+ << " 2 index 1 index sub 2 index 2 index sub lineto\n"
+ << " 2 index 1 index add 2 index 2 index sub lineto\n"
+ << " closepath pop pop pop} bind def\n";
+ //x y r
+ os << "/di { newpath 2 index 1 index add 2 index moveto\n"
+ << " 2 index 2 index 2 index add lineto\n"
+ << " 2 index 1 index sub 2 index lineto\n"
+ << " 2 index 2 index 2 index sub lineto\n"
+ << " closepath pop pop pop} bind def\n";
+ // x y r cr cg cb
+ os << "/nc { 0 0 0 setrgbcolor 5 index 5 index 5 index c fill\n"
+ << " setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n"
+ << " } bind def\n";
+ os << "/nsq { 0 0 0 setrgbcolor 5 index 5 index 5 index sq fill\n"
+ << " setrgbcolor " << 1+_nodeBorderQuotient << " div sq fill\n"
+ << " } bind def\n";
+ os << "/ndi { 0 0 0 setrgbcolor 5 index 5 index 5 index di fill\n"
+ << " setrgbcolor " << 1+_nodeBorderQuotient << " div di fill\n"
+ << " } bind def\n";
+ os << "/nfemale { 0 0 0 setrgbcolor 3 index "
+ << _nodeBorderQuotient/(1+_nodeBorderQuotient)
+ << " 1.5 mul mul setlinewidth\n"
+ << " newpath 5 index 5 index moveto "
+ << "5 index 5 index 5 index 3.01 mul sub\n"
+ << " lineto 5 index 4 index .7 mul sub 5 index 5 index 2.2 mul sub"
+ << " moveto\n"
+ << " 5 index 4 index .7 mul add 5 index 5 index 2.2 mul sub lineto "
+ << "stroke\n"
+ << " 5 index 5 index 5 index c fill\n"
+ << " setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n"
+ << " } bind def\n";
+ os << "/nmale {\n"
+ << " 0 0 0 setrgbcolor 3 index "
+ << _nodeBorderQuotient/(1+_nodeBorderQuotient)
+ <<" 1.5 mul mul setlinewidth\n"
+ << " newpath 5 index 5 index moveto\n"
+ << " 5 index 4 index 1 mul 1.5 mul add\n"
+ << " 5 index 5 index 3 sqrt 1.5 mul mul add\n"
+ << " 1 index 1 index lineto\n"
+ << " 1 index 1 index 7 index sub moveto\n"
+ << " 1 index 1 index lineto\n"
+ << " exch 5 index 3 sqrt .5 mul mul sub exch 5 index .5 mul sub"
+ << " lineto\n"
+ << " stroke\n"
+ << " 5 index 5 index 5 index c fill\n"
+ << " setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n"
+ << " } bind def\n";
+
+
+ os << "/arrl " << _arrowLength << " def\n";
+ os << "/arrw " << _arrowWidth << " def\n";
+ // l dx_norm dy_norm
+ os << "/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def\n";
+ //len w dx_norm dy_norm x1 y1 cr cg cb
+ os << "/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx "
+ << "exch def\n"
+ << " /w exch def /len exch def\n"
+ //<< "0.1 setlinewidth x1 y1 moveto dx len mul dy len mul rlineto stroke"
+ << " newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto\n"
+ << " len w sub arrl sub dx dy lrl\n"
+ << " arrw dy dx neg lrl\n"
+ << " dx arrl w add mul dy w 2 div arrw add mul sub\n"
+ << " dy arrl w add mul dx w 2 div arrw add mul add rlineto\n"
+ << " dx arrl w add mul neg dy w 2 div arrw add mul sub\n"
+ << " dy arrl w add mul neg dx w 2 div arrw add mul add rlineto\n"
+ << " arrw dy dx neg lrl\n"
+ << " len w sub arrl sub neg dx dy lrl\n"
+ << " closepath fill } bind def\n";
+ os << "/cshow { 2 index 2 index moveto dup stringwidth pop\n"
+ << " neg 2 div fosi .35 mul neg rmoveto show pop pop} def\n";
+
+ os << "\ngsave\n";
+ if(_scaleToA4)
+ if(bb.height()>bb.width()) {
+ double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.height(),
+ (A4WIDTH-2*A4BORDER)/bb.width());
+ os << ((A4WIDTH -2*A4BORDER)-sc*bb.width())/2 + A4BORDER << ' '
+ << ((A4HEIGHT-2*A4BORDER)-sc*bb.height())/2 + A4BORDER
+ << " translate\n"
+ << sc << " dup scale\n"
+ << -bb.left() << ' ' << -bb.bottom() << " translate\n";
+ }
+ else {
+ double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.width(),
+ (A4WIDTH-2*A4BORDER)/bb.height());
+ os << ((A4WIDTH -2*A4BORDER)-sc*bb.height())/2 + A4BORDER << ' '
+ << ((A4HEIGHT-2*A4BORDER)-sc*bb.width())/2 + A4BORDER
+ << " translate\n"
+ << sc << " dup scale\n90 rotate\n"
+ << -bb.left() << ' ' << -bb.top() << " translate\n";
+ }
+ else if(_scale!=1.0) os << _scale << " dup scale\n";
+
+ if(_showArcs) {
+ os << "%Arcs:\ngsave\n";
+ if(_enableParallel) {
+ std::vector<Arc> el;
+ for(ArcIt e(g);e!=INVALID;++e)
+ if((!_undirected||g.source(e)<g.target(e))&&_arcWidths[e]>0
+ &&g.source(e)!=g.target(e))
+ el.push_back(e);
+ std::sort(el.begin(),el.end(),arcLess(g));
+
+ typename std::vector<Arc>::iterator j;
+ for(typename std::vector<Arc>::iterator i=el.begin();i!=el.end();i=j) {
+ for(j=i+1;j!=el.end()&&isParallel(*i,*j);++j) ;
+
+ double sw=0;
+ for(typename std::vector<Arc>::iterator e=i;e!=j;++e)
+ sw+=_arcWidths[*e]*_arcWidthScale+_parArcDist;
+ sw-=_parArcDist;
+ sw/=-2.0;
+ dim2::Point<double>
+ dvec(mycoords[g.target(*i)]-mycoords[g.source(*i)]);
+ double l=std::sqrt(dvec.normSquare());
+ dim2::Point<double> d(dvec/std::max(l,EPSILON));
+ dim2::Point<double> m;
+// m=dim2::Point<double>(mycoords[g.target(*i)]+
+// mycoords[g.source(*i)])/2.0;
+
+// m=dim2::Point<double>(mycoords[g.source(*i)])+
+// dvec*(double(_nodeSizes[g.source(*i)])/
+// (_nodeSizes[g.source(*i)]+_nodeSizes[g.target(*i)]));
+
+ m=dim2::Point<double>(mycoords[g.source(*i)])+
+ d*(l+_nodeSizes[g.source(*i)]-_nodeSizes[g.target(*i)])/2.0;
+
+ for(typename std::vector<Arc>::iterator e=i;e!=j;++e) {
+ sw+=_arcWidths[*e]*_arcWidthScale/2.0;
+ dim2::Point<double> mm=m+rot90(d)*sw/.75;
+ if(_drawArrows) {
+ int node_shape;
+ dim2::Point<double> s=mycoords[g.source(*e)];
+ dim2::Point<double> t=mycoords[g.target(*e)];
+ double rn=_nodeSizes[g.target(*e)]*_nodeScale;
+ node_shape=_nodeShapes[g.target(*e)];
+ dim2::Bezier3 bez(s,mm,mm,t);
+ double t1=0,t2=1;
+ for(int ii=0;ii<INTERPOL_PREC;++ii)
+ if(isInsideNode(bez((t1+t2)/2)-t,rn,node_shape)) t2=(t1+t2)/2;
+ else t1=(t1+t2)/2;
+ dim2::Point<double> apoint=bez((t1+t2)/2);
+ rn = _arrowLength+_arcWidths[*e]*_arcWidthScale;
+ rn*=rn;
+ t2=(t1+t2)/2;t1=0;
+ for(int ii=0;ii<INTERPOL_PREC;++ii)
+ if((bez((t1+t2)/2)-apoint).normSquare()>rn) t1=(t1+t2)/2;
+ else t2=(t1+t2)/2;
+ dim2::Point<double> linend=bez((t1+t2)/2);
+ bez=bez.before((t1+t2)/2);
+// rn=_nodeSizes[g.source(*e)]*_nodeScale;
+// node_shape=_nodeShapes[g.source(*e)];
+// t1=0;t2=1;
+// for(int i=0;i<INTERPOL_PREC;++i)
+// if(isInsideNode(bez((t1+t2)/2)-t,rn,node_shape))
+// t1=(t1+t2)/2;
+// else t2=(t1+t2)/2;
+// bez=bez.after((t1+t2)/2);
+ os << _arcWidths[*e]*_arcWidthScale << " setlinewidth "
+ << _arcColors[*e].red() << ' '
+ << _arcColors[*e].green() << ' '
+ << _arcColors[*e].blue() << " setrgbcolor newpath\n"
+ << bez.p1.x << ' ' << bez.p1.y << " moveto\n"
+ << bez.p2.x << ' ' << bez.p2.y << ' '
+ << bez.p3.x << ' ' << bez.p3.y << ' '
+ << bez.p4.x << ' ' << bez.p4.y << " curveto stroke\n";
+ dim2::Point<double> dd(rot90(linend-apoint));
+ dd*=(.5*_arcWidths[*e]*_arcWidthScale+_arrowWidth)/
+ std::sqrt(dd.normSquare());
+ os << "newpath " << psOut(apoint) << " moveto "
+ << psOut(linend+dd) << " lineto "
+ << psOut(linend-dd) << " lineto closepath fill\n";
+ }
+ else {
+ os << mycoords[g.source(*e)].x << ' '
+ << mycoords[g.source(*e)].y << ' '
+ << mm.x << ' ' << mm.y << ' '
+ << mycoords[g.target(*e)].x << ' '
+ << mycoords[g.target(*e)].y << ' '
+ << _arcColors[*e].red() << ' '
+ << _arcColors[*e].green() << ' '
+ << _arcColors[*e].blue() << ' '
+ << _arcWidths[*e]*_arcWidthScale << " lb\n";
+ }
+ sw+=_arcWidths[*e]*_arcWidthScale/2.0+_parArcDist;
+ }
+ }
+ }
+ else for(ArcIt e(g);e!=INVALID;++e)
+ if((!_undirected||g.source(e)<g.target(e))&&_arcWidths[e]>0
+ &&g.source(e)!=g.target(e)) {
+ if(_drawArrows) {
+ dim2::Point<double> d(mycoords[g.target(e)]-mycoords[g.source(e)]);
+ double rn=_nodeSizes[g.target(e)]*_nodeScale;
+ int node_shape=_nodeShapes[g.target(e)];
+ double t1=0,t2=1;
+ for(int i=0;i<INTERPOL_PREC;++i)
+ if(isInsideNode((-(t1+t2)/2)*d,rn,node_shape)) t1=(t1+t2)/2;
+ else t2=(t1+t2)/2;
+ double l=std::sqrt(d.normSquare());
+ d/=l;
+
+ os << l*(1-(t1+t2)/2) << ' '
+ << _arcWidths[e]*_arcWidthScale << ' '
+ << d.x << ' ' << d.y << ' '
+ << mycoords[g.source(e)].x << ' '
+ << mycoords[g.source(e)].y << ' '
+ << _arcColors[e].red() << ' '
+ << _arcColors[e].green() << ' '
+ << _arcColors[e].blue() << " arr\n";
+ }
+ else os << mycoords[g.source(e)].x << ' '
+ << mycoords[g.source(e)].y << ' '
+ << mycoords[g.target(e)].x << ' '
+ << mycoords[g.target(e)].y << ' '
+ << _arcColors[e].red() << ' '
+ << _arcColors[e].green() << ' '
+ << _arcColors[e].blue() << ' '
+ << _arcWidths[e]*_arcWidthScale << " l\n";
+ }
+ os << "grestore\n";
+ }
+ if(_showNodes) {
+ os << "%Nodes:\ngsave\n";
+ for(NodeIt n(g);n!=INVALID;++n) {
+ os << mycoords[n].x << ' ' << mycoords[n].y << ' '
+ << _nodeSizes[n]*_nodeScale << ' '
+ << _nodeColors[n].red() << ' '
+ << _nodeColors[n].green() << ' '
+ << _nodeColors[n].blue() << ' ';
+ switch(_nodeShapes[n]) {
+ case CIRCLE:
+ os<< "nc";break;
+ case SQUARE:
+ os<< "nsq";break;
+ case DIAMOND:
+ os<< "ndi";break;
+ case MALE:
+ os<< "nmale";break;
+ case FEMALE:
+ os<< "nfemale";break;
+ }
+ os<<'\n';
+ }
+ os << "grestore\n";
+ }
+ if(_showNodeText) {
+ os << "%Node texts:\ngsave\n";
+ os << "/fosi " << _nodeTextSize << " def\n";
+ os << "(Helvetica) findfont fosi scalefont setfont\n";
+ for(NodeIt n(g);n!=INVALID;++n) {
+ switch(_nodeTextColorType) {
+ case DIST_COL:
+ os << psOut(distantColor(_nodeColors[n])) << " setrgbcolor\n";
+ break;
+ case DIST_BW:
+ os << psOut(distantBW(_nodeColors[n])) << " setrgbcolor\n";
+ break;
+ case CUST_COL:
+ os << psOut(distantColor(_nodeTextColors[n])) << " setrgbcolor\n";
+ break;
+ default:
+ os << "0 0 0 setrgbcolor\n";
+ }
+ os << mycoords[n].x << ' ' << mycoords[n].y
+ << " (" << _nodeTexts[n] << ") cshow\n";
+ }
+ os << "grestore\n";
+ }
+ if(_showNodePsText) {
+ os << "%Node PS blocks:\ngsave\n";
+ for(NodeIt n(g);n!=INVALID;++n)
+ os << mycoords[n].x << ' ' << mycoords[n].y
+ << " moveto\n" << _nodePsTexts[n] << "\n";
+ os << "grestore\n";
+ }
+
+ os << "grestore\nshowpage\n";
+
+ //CleanUp:
+ if(_pleaseRemoveOsStream) {delete &os;}
+ }
+
+ ///\name Aliases
+ ///These are just some aliases to other parameter setting functions.
+
+ ///@{
+
+ ///An alias for arcWidths()
+ template<class X> GraphToEps<ArcWidthsTraits<X> > edgeWidths(const X &x)
+ {
+ return arcWidths(x);
+ }
+
+ ///An alias for arcColors()
+ template<class X> GraphToEps<ArcColorsTraits<X> >
+ edgeColors(const X &x)
+ {
+ return arcColors(x);
+ }
+
+ ///An alias for arcWidthScale()
+ GraphToEps<T> &edgeWidthScale(double d) {return arcWidthScale(d);}
+
+ ///An alias for autoArcWidthScale()
+ GraphToEps<T> &autoEdgeWidthScale(bool b=true)
+ {
+ return autoArcWidthScale(b);
+ }
+
+ ///An alias for absoluteArcWidths()
+ GraphToEps<T> &absoluteEdgeWidths(bool b=true)
+ {
+ return absoluteArcWidths(b);
+ }
+
+ ///An alias for parArcDist()
+ GraphToEps<T> &parEdgeDist(double d) {return parArcDist(d);}
+
+ ///An alias for hideArcs()
+ GraphToEps<T> &hideEdges(bool b=true) {return hideArcs(b);}
+
+ ///@}
+};
+
+template<class T>
+const int GraphToEps<T>::INTERPOL_PREC = 20;
+template<class T>
+const double GraphToEps<T>::A4HEIGHT = 841.8897637795276;
+template<class T>
+const double GraphToEps<T>::A4WIDTH = 595.275590551181;
+template<class T>
+const double GraphToEps<T>::A4BORDER = 15;
+
+
+///Generates an EPS file from a graph
+
+///\ingroup eps_io
+///Generates an EPS file from a graph.
+///\param g Reference to the graph to be printed.
+///\param os Reference to the output stream.
+///By default, it is <tt>std::cout</tt>.
+///
+///This function also has a lot of
+///\ref named-templ-func-param "named parameters",
+///they are declared as the members of class \ref GraphToEps. The following
+///example shows how to use these parameters.
+///\code
+/// graphToEps(g,os).scale(10).coords(coords)
+/// .nodeScale(2).nodeSizes(sizes)
+/// .arcWidthScale(.4).run();
+///\endcode
+///
+///For more detailed examples, see the \ref graph_to_eps_demo.cc demo file.
+///
+///\warning Don't forget to put the \ref GraphToEps::run() "run()"
+///to the end of the parameter list.
+///\sa GraphToEps
+///\sa graphToEps(GR &g, const char *file_name)
+template<class GR>
+GraphToEps<DefaultGraphToEpsTraits<GR> >
+graphToEps(GR &g, std::ostream& os=std::cout)
+{
+ return
+ GraphToEps<DefaultGraphToEpsTraits<GR> >(DefaultGraphToEpsTraits<GR>(g,os));
+}
+
+///Generates an EPS file from a graph
+
+///\ingroup eps_io
+///This function does the same as
+///\ref graphToEps(GR &g,std::ostream& os)
+///but it writes its output into the file \c file_name
+///instead of a stream.
+///\sa graphToEps(GR &g, std::ostream& os)
+template<class GR>
+GraphToEps<DefaultGraphToEpsTraits<GR> >
+graphToEps(GR &g,const char *file_name)
+{
+ std::ostream* os = new std::ofstream(file_name);
+ if (!(*os)) {
+ delete os;
+ throw IoError("Cannot write file", file_name);
+ }
+ return GraphToEps<DefaultGraphToEpsTraits<GR> >
+ (DefaultGraphToEpsTraits<GR>(g,*os,true));
+}
+
+///Generates an EPS file from a graph
+
+///\ingroup eps_io
+///This function does the same as
+///\ref graphToEps(GR &g,std::ostream& os)
+///but it writes its output into the file \c file_name
+///instead of a stream.
+///\sa graphToEps(GR &g, std::ostream& os)
+template<class GR>
+GraphToEps<DefaultGraphToEpsTraits<GR> >
+graphToEps(GR &g,const std::string& file_name)
+{
+ std::ostream* os = new std::ofstream(file_name.c_str());
+ if (!(*os)) {
+ delete os;
+ throw IoError("Cannot write file", file_name);
+ }
+ return GraphToEps<DefaultGraphToEpsTraits<GR> >
+ (DefaultGraphToEpsTraits<GR>(g,*os,true));
+}
+
+} //END OF NAMESPACE LEMON
+
+#endif // LEMON_GRAPH_TO_EPS_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/greedy_tsp.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/greedy_tsp.h
new file mode 100644
index 00000000000..95461717ae0
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/greedy_tsp.h
@@ -0,0 +1,251 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_GREEDY_TSP_H
+#define LEMON_GREEDY_TSP_H
+
+/// \ingroup tsp
+/// \file
+/// \brief Greedy algorithm for symmetric TSP
+
+#include <vector>
+#include <algorithm>
+#include <lemon/full_graph.h>
+#include <lemon/unionfind.h>
+
+namespace lemon {
+
+ /// \ingroup tsp
+ ///
+ /// \brief Greedy algorithm for symmetric TSP.
+ ///
+ /// GreedyTsp implements the greedy heuristic for solving
+ /// symmetric \ref tsp "TSP".
+ ///
+ /// This algorithm is quite similar to the \ref NearestNeighborTsp
+ /// "nearest neighbor" heuristic, but it maintains a set of disjoint paths.
+ /// At each step, the shortest possible edge is added to these paths
+ /// as long as it does not create a cycle of less than n edges and it does
+ /// not increase the degree of any node above two.
+ ///
+ /// This method runs in O(n<sup>2</sup>) time.
+ /// It quickly finds a relatively short tour for most TSP instances,
+ /// but it could also yield a really bad (or even the worst) solution
+ /// in special cases.
+ ///
+ /// \tparam CM Type of the cost map.
+ template <typename CM>
+ class GreedyTsp
+ {
+ public:
+
+ /// Type of the cost map
+ typedef CM CostMap;
+ /// Type of the edge costs
+ typedef typename CM::Value Cost;
+
+ private:
+
+ GRAPH_TYPEDEFS(FullGraph);
+
+ const FullGraph &_gr;
+ const CostMap &_cost;
+ Cost _sum;
+ std::vector<Node> _path;
+
+ private:
+
+ // Functor class to compare edges by their costs
+ class EdgeComp {
+ private:
+ const CostMap &_cost;
+
+ public:
+ EdgeComp(const CostMap &cost) : _cost(cost) {}
+
+ bool operator()(const Edge &a, const Edge &b) const {
+ return _cost[a] < _cost[b];
+ }
+ };
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ /// \param gr The \ref FullGraph "full graph" the algorithm runs on.
+ /// \param cost The cost map.
+ GreedyTsp(const FullGraph &gr, const CostMap &cost)
+ : _gr(gr), _cost(cost) {}
+
+ /// \name Execution Control
+ /// @{
+
+ /// \brief Runs the algorithm.
+ ///
+ /// This function runs the algorithm.
+ ///
+ /// \return The total cost of the found tour.
+ Cost run() {
+ _path.clear();
+
+ if (_gr.nodeNum() == 0) return _sum = 0;
+ else if (_gr.nodeNum() == 1) {
+ _path.push_back(_gr(0));
+ return _sum = 0;
+ }
+
+ std::vector<int> plist;
+ plist.resize(_gr.nodeNum()*2, -1);
+
+ std::vector<Edge> sorted_edges;
+ sorted_edges.reserve(_gr.edgeNum());
+ for (EdgeIt e(_gr); e != INVALID; ++e)
+ sorted_edges.push_back(e);
+ std::sort(sorted_edges.begin(), sorted_edges.end(), EdgeComp(_cost));
+
+ FullGraph::NodeMap<int> item_int_map(_gr);
+ UnionFind<FullGraph::NodeMap<int> > union_find(item_int_map);
+ for (NodeIt n(_gr); n != INVALID; ++n)
+ union_find.insert(n);
+
+ FullGraph::NodeMap<int> degree(_gr, 0);
+
+ int nodesNum = 0, i = 0;
+ while (nodesNum != _gr.nodeNum()-1) {
+ Edge e = sorted_edges[i++];
+ Node u = _gr.u(e),
+ v = _gr.v(e);
+
+ if (degree[u] <= 1 && degree[v] <= 1) {
+ if (union_find.join(u, v)) {
+ const int uid = _gr.id(u),
+ vid = _gr.id(v);
+
+ plist[uid*2 + degree[u]] = vid;
+ plist[vid*2 + degree[v]] = uid;
+
+ ++degree[u];
+ ++degree[v];
+ ++nodesNum;
+ }
+ }
+ }
+
+ for (int i=0, n=-1; i<_gr.nodeNum()*2; ++i) {
+ if (plist[i] == -1) {
+ if (n==-1) {
+ n = i;
+ } else {
+ plist[n] = i/2;
+ plist[i] = n/2;
+ break;
+ }
+ }
+ }
+
+ for (int i=0, next=0, last=-1; i!=_gr.nodeNum(); ++i) {
+ _path.push_back(_gr.nodeFromId(next));
+ if (plist[2*next] != last) {
+ last = next;
+ next = plist[2*next];
+ } else {
+ last = next;
+ next = plist[2*next+1];
+ }
+ }
+
+ _sum = _cost[_gr.edge(_path.back(), _path.front())];
+ for (int i = 0; i < int(_path.size())-1; ++i) {
+ _sum += _cost[_gr.edge(_path[i], _path[i+1])];
+ }
+
+ return _sum;
+ }
+
+ /// @}
+
+ /// \name Query Functions
+ /// @{
+
+ /// \brief The total cost of the found tour.
+ ///
+ /// This function returns the total cost of the found tour.
+ ///
+ /// \pre run() must be called before using this function.
+ Cost tourCost() const {
+ return _sum;
+ }
+
+ /// \brief Returns a const reference to the node sequence of the
+ /// found tour.
+ ///
+ /// This function returns a const reference to a vector
+ /// that stores the node sequence of the found tour.
+ ///
+ /// \pre run() must be called before using this function.
+ const std::vector<Node>& tourNodes() const {
+ return _path;
+ }
+
+ /// \brief Gives back the node sequence of the found tour.
+ ///
+ /// This function copies the node sequence of the found tour into
+ /// an STL container through the given output iterator. The
+ /// <tt>value_type</tt> of the container must be <tt>FullGraph::Node</tt>.
+ /// For example,
+ /// \code
+ /// std::vector<FullGraph::Node> nodes(countNodes(graph));
+ /// tsp.tourNodes(nodes.begin());
+ /// \endcode
+ /// or
+ /// \code
+ /// std::list<FullGraph::Node> nodes;
+ /// tsp.tourNodes(std::back_inserter(nodes));
+ /// \endcode
+ ///
+ /// \pre run() must be called before using this function.
+ template <typename Iterator>
+ void tourNodes(Iterator out) const {
+ std::copy(_path.begin(), _path.end(), out);
+ }
+
+ /// \brief Gives back the found tour as a path.
+ ///
+ /// This function copies the found tour as a list of arcs/edges into
+ /// the given \ref lemon::concepts::Path "path structure".
+ ///
+ /// \pre run() must be called before using this function.
+ template <typename Path>
+ void tour(Path &path) const {
+ path.clear();
+ for (int i = 0; i < int(_path.size()) - 1; ++i) {
+ path.addBack(_gr.arc(_path[i], _path[i+1]));
+ }
+ if (int(_path.size()) >= 2) {
+ path.addBack(_gr.arc(_path.back(), _path.front()));
+ }
+ }
+
+ /// @}
+
+ };
+
+}; // namespace lemon
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/grid_graph.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/grid_graph.h
new file mode 100644
index 00000000000..a3dff0f612f
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/grid_graph.h
@@ -0,0 +1,699 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef GRID_GRAPH_H
+#define GRID_GRAPH_H
+
+#include <lemon/core.h>
+#include <lemon/bits/graph_extender.h>
+#include <lemon/dim2.h>
+#include <lemon/assert.h>
+
+///\ingroup graphs
+///\file
+///\brief GridGraph class.
+
+namespace lemon {
+
+ class GridGraphBase {
+
+ public:
+
+ typedef GridGraphBase Graph;
+
+ class Node;
+ class Edge;
+ class Arc;
+
+ public:
+
+ GridGraphBase() {}
+
+ protected:
+
+ void construct(int width, int height) {
+ _width = width; _height = height;
+ _node_num = width * height;
+ _edge_num = 2 * _node_num - width - height;
+ _edge_limit = _node_num - _width;
+ }
+
+ public:
+
+ Node operator()(int i, int j) const {
+ LEMON_DEBUG(0 <= i && i < _width &&
+ 0 <= j && j < _height, "Index out of range");
+ return Node(i + j * _width);
+ }
+
+ int col(Node n) const {
+ return n._id % _width;
+ }
+
+ int row(Node n) const {
+ return n._id / _width;
+ }
+
+ dim2::Point<int> pos(Node n) const {
+ return dim2::Point<int>(col(n), row(n));
+ }
+
+ int width() const {
+ return _width;
+ }
+
+ int height() const {
+ return _height;
+ }
+
+ typedef True NodeNumTag;
+ typedef True EdgeNumTag;
+ typedef True ArcNumTag;
+
+ int nodeNum() const { return _node_num; }
+ int edgeNum() const { return _edge_num; }
+ int arcNum() const { return 2 * _edge_num; }
+
+ Node u(Edge edge) const {
+ if (edge._id < _edge_limit) {
+ return edge._id;
+ } else {
+ return (edge._id - _edge_limit) % (_width - 1) +
+ (edge._id - _edge_limit) / (_width - 1) * _width;
+ }
+ }
+
+ Node v(Edge edge) const {
+ if (edge._id < _edge_limit) {
+ return edge._id + _width;
+ } else {
+ return (edge._id - _edge_limit) % (_width - 1) +
+ (edge._id - _edge_limit) / (_width - 1) * _width + 1;
+ }
+ }
+
+ Node source(Arc arc) const {
+ return (arc._id & 1) == 1 ? u(arc) : v(arc);
+ }
+
+ Node target(Arc arc) const {
+ return (arc._id & 1) == 1 ? v(arc) : u(arc);
+ }
+
+ static int id(Node node) { return node._id; }
+ static int id(Edge edge) { return edge._id; }
+ static int id(Arc arc) { return arc._id; }
+
+ int maxNodeId() const { return _node_num - 1; }
+ int maxEdgeId() const { return _edge_num - 1; }
+ int maxArcId() const { return 2 * _edge_num - 1; }
+
+ static Node nodeFromId(int id) { return Node(id);}
+ static Edge edgeFromId(int id) { return Edge(id);}
+ static Arc arcFromId(int id) { return Arc(id);}
+
+ typedef True FindEdgeTag;
+ typedef True FindArcTag;
+
+ Edge findEdge(Node u, Node v, Edge prev = INVALID) const {
+ if (prev != INVALID) return INVALID;
+ if (v._id > u._id) {
+ if (v._id - u._id == _width)
+ return Edge(u._id);
+ if (v._id - u._id == 1 && u._id % _width < _width - 1) {
+ return Edge(u._id / _width * (_width - 1) +
+ u._id % _width + _edge_limit);
+ }
+ } else {
+ if (u._id - v._id == _width)
+ return Edge(v._id);
+ if (u._id - v._id == 1 && v._id % _width < _width - 1) {
+ return Edge(v._id / _width * (_width - 1) +
+ v._id % _width + _edge_limit);
+ }
+ }
+ return INVALID;
+ }
+
+ Arc findArc(Node u, Node v, Arc prev = INVALID) const {
+ if (prev != INVALID) return INVALID;
+ if (v._id > u._id) {
+ if (v._id - u._id == _width)
+ return Arc((u._id << 1) | 1);
+ if (v._id - u._id == 1 && u._id % _width < _width - 1) {
+ return Arc(((u._id / _width * (_width - 1) +
+ u._id % _width + _edge_limit) << 1) | 1);
+ }
+ } else {
+ if (u._id - v._id == _width)
+ return Arc(v._id << 1);
+ if (u._id - v._id == 1 && v._id % _width < _width - 1) {
+ return Arc((v._id / _width * (_width - 1) +
+ v._id % _width + _edge_limit) << 1);
+ }
+ }
+ return INVALID;
+ }
+
+ class Node {
+ friend class GridGraphBase;
+
+ protected:
+ int _id;
+ Node(int id) : _id(id) {}
+ public:
+ Node() {}
+ Node (Invalid) : _id(-1) {}
+ bool operator==(const Node node) const {return _id == node._id;}
+ bool operator!=(const Node node) const {return _id != node._id;}
+ bool operator<(const Node node) const {return _id < node._id;}
+ };
+
+ class Edge {
+ friend class GridGraphBase;
+ friend class Arc;
+
+ protected:
+ int _id;
+
+ Edge(int id) : _id(id) {}
+
+ public:
+ Edge() {}
+ Edge (Invalid) : _id(-1) {}
+ bool operator==(const Edge edge) const {return _id == edge._id;}
+ bool operator!=(const Edge edge) const {return _id != edge._id;}
+ bool operator<(const Edge edge) const {return _id < edge._id;}
+ };
+
+ class Arc {
+ friend class GridGraphBase;
+
+ protected:
+ int _id;
+
+ Arc(int id) : _id(id) {}
+
+ public:
+ Arc() {}
+ Arc (Invalid) : _id(-1) {}
+ operator Edge() const { return _id != -1 ? Edge(_id >> 1) : INVALID; }
+ bool operator==(const Arc arc) const {return _id == arc._id;}
+ bool operator!=(const Arc arc) const {return _id != arc._id;}
+ bool operator<(const Arc arc) const {return _id < arc._id;}
+ };
+
+ static bool direction(Arc arc) {
+ return (arc._id & 1) == 1;
+ }
+
+ static Arc direct(Edge edge, bool dir) {
+ return Arc((edge._id << 1) | (dir ? 1 : 0));
+ }
+
+ void first(Node& node) const {
+ node._id = _node_num - 1;
+ }
+
+ static void next(Node& node) {
+ --node._id;
+ }
+
+ void first(Edge& edge) const {
+ edge._id = _edge_num - 1;
+ }
+
+ static void next(Edge& edge) {
+ --edge._id;
+ }
+
+ void first(Arc& arc) const {
+ arc._id = 2 * _edge_num - 1;
+ }
+
+ static void next(Arc& arc) {
+ --arc._id;
+ }
+
+ void firstOut(Arc& arc, const Node& node) const {
+ if (node._id % _width < _width - 1) {
+ arc._id = (_edge_limit + node._id % _width +
+ (node._id / _width) * (_width - 1)) << 1 | 1;
+ return;
+ }
+ if (node._id < _node_num - _width) {
+ arc._id = node._id << 1 | 1;
+ return;
+ }
+ if (node._id % _width > 0) {
+ arc._id = (_edge_limit + node._id % _width +
+ (node._id / _width) * (_width - 1) - 1) << 1;
+ return;
+ }
+ if (node._id >= _width) {
+ arc._id = (node._id - _width) << 1;
+ return;
+ }
+ arc._id = -1;
+ }
+
+ void nextOut(Arc& arc) const {
+ int nid = arc._id >> 1;
+ if ((arc._id & 1) == 1) {
+ if (nid >= _edge_limit) {
+ nid = (nid - _edge_limit) % (_width - 1) +
+ (nid - _edge_limit) / (_width - 1) * _width;
+ if (nid < _node_num - _width) {
+ arc._id = nid << 1 | 1;
+ return;
+ }
+ }
+ if (nid % _width > 0) {
+ arc._id = (_edge_limit + nid % _width +
+ (nid / _width) * (_width - 1) - 1) << 1;
+ return;
+ }
+ if (nid >= _width) {
+ arc._id = (nid - _width) << 1;
+ return;
+ }
+ } else {
+ if (nid >= _edge_limit) {
+ nid = (nid - _edge_limit) % (_width - 1) +
+ (nid - _edge_limit) / (_width - 1) * _width + 1;
+ if (nid >= _width) {
+ arc._id = (nid - _width) << 1;
+ return;
+ }
+ }
+ }
+ arc._id = -1;
+ }
+
+ void firstIn(Arc& arc, const Node& node) const {
+ if (node._id % _width < _width - 1) {
+ arc._id = (_edge_limit + node._id % _width +
+ (node._id / _width) * (_width - 1)) << 1;
+ return;
+ }
+ if (node._id < _node_num - _width) {
+ arc._id = node._id << 1;
+ return;
+ }
+ if (node._id % _width > 0) {
+ arc._id = (_edge_limit + node._id % _width +
+ (node._id / _width) * (_width - 1) - 1) << 1 | 1;
+ return;
+ }
+ if (node._id >= _width) {
+ arc._id = (node._id - _width) << 1 | 1;
+ return;
+ }
+ arc._id = -1;
+ }
+
+ void nextIn(Arc& arc) const {
+ int nid = arc._id >> 1;
+ if ((arc._id & 1) == 0) {
+ if (nid >= _edge_limit) {
+ nid = (nid - _edge_limit) % (_width - 1) +
+ (nid - _edge_limit) / (_width - 1) * _width;
+ if (nid < _node_num - _width) {
+ arc._id = nid << 1;
+ return;
+ }
+ }
+ if (nid % _width > 0) {
+ arc._id = (_edge_limit + nid % _width +
+ (nid / _width) * (_width - 1) - 1) << 1 | 1;
+ return;
+ }
+ if (nid >= _width) {
+ arc._id = (nid - _width) << 1 | 1;
+ return;
+ }
+ } else {
+ if (nid >= _edge_limit) {
+ nid = (nid - _edge_limit) % (_width - 1) +
+ (nid - _edge_limit) / (_width - 1) * _width + 1;
+ if (nid >= _width) {
+ arc._id = (nid - _width) << 1 | 1;
+ return;
+ }
+ }
+ }
+ arc._id = -1;
+ }
+
+ void firstInc(Edge& edge, bool& dir, const Node& node) const {
+ if (node._id % _width < _width - 1) {
+ edge._id = _edge_limit + node._id % _width +
+ (node._id / _width) * (_width - 1);
+ dir = true;
+ return;
+ }
+ if (node._id < _node_num - _width) {
+ edge._id = node._id;
+ dir = true;
+ return;
+ }
+ if (node._id % _width > 0) {
+ edge._id = _edge_limit + node._id % _width +
+ (node._id / _width) * (_width - 1) - 1;
+ dir = false;
+ return;
+ }
+ if (node._id >= _width) {
+ edge._id = node._id - _width;
+ dir = false;
+ return;
+ }
+ edge._id = -1;
+ dir = true;
+ }
+
+ void nextInc(Edge& edge, bool& dir) const {
+ int nid = edge._id;
+ if (dir) {
+ if (nid >= _edge_limit) {
+ nid = (nid - _edge_limit) % (_width - 1) +
+ (nid - _edge_limit) / (_width - 1) * _width;
+ if (nid < _node_num - _width) {
+ edge._id = nid;
+ return;
+ }
+ }
+ if (nid % _width > 0) {
+ edge._id = _edge_limit + nid % _width +
+ (nid / _width) * (_width - 1) - 1;
+ dir = false;
+ return;
+ }
+ if (nid >= _width) {
+ edge._id = nid - _width;
+ dir = false;
+ return;
+ }
+ } else {
+ if (nid >= _edge_limit) {
+ nid = (nid - _edge_limit) % (_width - 1) +
+ (nid - _edge_limit) / (_width - 1) * _width + 1;
+ if (nid >= _width) {
+ edge._id = nid - _width;
+ return;
+ }
+ }
+ }
+ edge._id = -1;
+ dir = true;
+ }
+
+ Arc right(Node n) const {
+ if (n._id % _width < _width - 1) {
+ return Arc(((_edge_limit + n._id % _width +
+ (n._id / _width) * (_width - 1)) << 1) | 1);
+ } else {
+ return INVALID;
+ }
+ }
+
+ Arc left(Node n) const {
+ if (n._id % _width > 0) {
+ return Arc((_edge_limit + n._id % _width +
+ (n._id / _width) * (_width - 1) - 1) << 1);
+ } else {
+ return INVALID;
+ }
+ }
+
+ Arc up(Node n) const {
+ if (n._id < _edge_limit) {
+ return Arc((n._id << 1) | 1);
+ } else {
+ return INVALID;
+ }
+ }
+
+ Arc down(Node n) const {
+ if (n._id >= _width) {
+ return Arc((n._id - _width) << 1);
+ } else {
+ return INVALID;
+ }
+ }
+
+ private:
+ int _width, _height;
+ int _node_num, _edge_num;
+ int _edge_limit;
+ };
+
+
+ typedef GraphExtender<GridGraphBase> ExtendedGridGraphBase;
+
+ /// \ingroup graphs
+ ///
+ /// \brief Grid graph class
+ ///
+ /// GridGraph implements a special graph type. The nodes of the
+ /// graph can be indexed by two integer values \c (i,j) where \c i is
+ /// in the range <tt>[0..width()-1]</tt> and j is in the range
+ /// <tt>[0..height()-1]</tt>. Two nodes are connected in the graph if
+ /// the indices differ exactly on one position and the difference is
+ /// also exactly one. The nodes of the graph can be obtained by position
+ /// using the \c operator()() function and the indices of the nodes can
+ /// be obtained using \c pos(), \c col() and \c row() members. The outgoing
+ /// arcs can be retrieved with the \c right(), \c up(), \c left()
+ /// and \c down() functions, where the bottom-left corner is the
+ /// origin.
+ ///
+ /// This class is completely static and it needs constant memory space.
+ /// Thus you can neither add nor delete nodes or edges, however
+ /// the structure can be resized using resize().
+ ///
+ /// \image html grid_graph.png
+ /// \image latex grid_graph.eps "Grid graph" width=\textwidth
+ ///
+ /// A short example about the basic usage:
+ ///\code
+ /// GridGraph graph(rows, cols);
+ /// GridGraph::NodeMap<int> val(graph);
+ /// for (int i = 0; i < graph.width(); ++i) {
+ /// for (int j = 0; j < graph.height(); ++j) {
+ /// val[graph(i, j)] = i + j;
+ /// }
+ /// }
+ ///\endcode
+ ///
+ /// This type fully conforms to the \ref concepts::Graph "Graph concept".
+ /// Most of its member functions and nested classes are documented
+ /// only in the concept class.
+ ///
+ /// This class provides constant time counting for nodes, edges and arcs.
+ class GridGraph : public ExtendedGridGraphBase {
+ typedef ExtendedGridGraphBase Parent;
+
+ public:
+
+ /// \brief Map to get the indices of the nodes as \ref dim2::Point
+ /// "dim2::Point<int>".
+ ///
+ /// Map to get the indices of the nodes as \ref dim2::Point
+ /// "dim2::Point<int>".
+ class IndexMap {
+ public:
+ /// \brief The key type of the map
+ typedef GridGraph::Node Key;
+ /// \brief The value type of the map
+ typedef dim2::Point<int> Value;
+
+ /// \brief Constructor
+ IndexMap(const GridGraph& graph) : _graph(graph) {}
+
+ /// \brief The subscript operator
+ Value operator[](Key key) const {
+ return _graph.pos(key);
+ }
+
+ private:
+ const GridGraph& _graph;
+ };
+
+ /// \brief Map to get the column of the nodes.
+ ///
+ /// Map to get the column of the nodes.
+ class ColMap {
+ public:
+ /// \brief The key type of the map
+ typedef GridGraph::Node Key;
+ /// \brief The value type of the map
+ typedef int Value;
+
+ /// \brief Constructor
+ ColMap(const GridGraph& graph) : _graph(graph) {}
+
+ /// \brief The subscript operator
+ Value operator[](Key key) const {
+ return _graph.col(key);
+ }
+
+ private:
+ const GridGraph& _graph;
+ };
+
+ /// \brief Map to get the row of the nodes.
+ ///
+ /// Map to get the row of the nodes.
+ class RowMap {
+ public:
+ /// \brief The key type of the map
+ typedef GridGraph::Node Key;
+ /// \brief The value type of the map
+ typedef int Value;
+
+ /// \brief Constructor
+ RowMap(const GridGraph& graph) : _graph(graph) {}
+
+ /// \brief The subscript operator
+ Value operator[](Key key) const {
+ return _graph.row(key);
+ }
+
+ private:
+ const GridGraph& _graph;
+ };
+
+ /// \brief Constructor
+ ///
+ /// Construct a grid graph with the given size.
+ GridGraph(int width, int height) { construct(width, height); }
+
+ /// \brief Resizes the graph
+ ///
+ /// This function resizes the graph. It fully destroys and
+ /// rebuilds the structure, therefore the maps of the graph will be
+ /// reallocated automatically and the previous values will be lost.
+ void resize(int width, int height) {
+ Parent::notifier(Arc()).clear();
+ Parent::notifier(Edge()).clear();
+ Parent::notifier(Node()).clear();
+ construct(width, height);
+ Parent::notifier(Node()).build();
+ Parent::notifier(Edge()).build();
+ Parent::notifier(Arc()).build();
+ }
+
+ /// \brief The node on the given position.
+ ///
+ /// Gives back the node on the given position.
+ Node operator()(int i, int j) const {
+ return Parent::operator()(i, j);
+ }
+
+ /// \brief The column index of the node.
+ ///
+ /// Gives back the column index of the node.
+ int col(Node n) const {
+ return Parent::col(n);
+ }
+
+ /// \brief The row index of the node.
+ ///
+ /// Gives back the row index of the node.
+ int row(Node n) const {
+ return Parent::row(n);
+ }
+
+ /// \brief The position of the node.
+ ///
+ /// Gives back the position of the node, ie. the <tt>(col,row)</tt> pair.
+ dim2::Point<int> pos(Node n) const {
+ return Parent::pos(n);
+ }
+
+ /// \brief The number of the columns.
+ ///
+ /// Gives back the number of the columns.
+ int width() const {
+ return Parent::width();
+ }
+
+ /// \brief The number of the rows.
+ ///
+ /// Gives back the number of the rows.
+ int height() const {
+ return Parent::height();
+ }
+
+ /// \brief The arc goes right from the node.
+ ///
+ /// Gives back the arc goes right from the node. If there is not
+ /// outgoing arc then it gives back INVALID.
+ Arc right(Node n) const {
+ return Parent::right(n);
+ }
+
+ /// \brief The arc goes left from the node.
+ ///
+ /// Gives back the arc goes left from the node. If there is not
+ /// outgoing arc then it gives back INVALID.
+ Arc left(Node n) const {
+ return Parent::left(n);
+ }
+
+ /// \brief The arc goes up from the node.
+ ///
+ /// Gives back the arc goes up from the node. If there is not
+ /// outgoing arc then it gives back INVALID.
+ Arc up(Node n) const {
+ return Parent::up(n);
+ }
+
+ /// \brief The arc goes down from the node.
+ ///
+ /// Gives back the arc goes down from the node. If there is not
+ /// outgoing arc then it gives back INVALID.
+ Arc down(Node n) const {
+ return Parent::down(n);
+ }
+
+ /// \brief Index map of the grid graph
+ ///
+ /// Just returns an IndexMap for the grid graph.
+ IndexMap indexMap() const {
+ return IndexMap(*this);
+ }
+
+ /// \brief Row map of the grid graph
+ ///
+ /// Just returns a RowMap for the grid graph.
+ RowMap rowMap() const {
+ return RowMap(*this);
+ }
+
+ /// \brief Column map of the grid graph
+ ///
+ /// Just returns a ColMap for the grid graph.
+ ColMap colMap() const {
+ return ColMap(*this);
+ }
+
+ };
+
+}
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/grosso_locatelli_pullan_mc.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/grosso_locatelli_pullan_mc.h
new file mode 100644
index 00000000000..669e1fa3298
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/grosso_locatelli_pullan_mc.h
@@ -0,0 +1,840 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_GROSSO_LOCATELLI_PULLAN_MC_H
+#define LEMON_GROSSO_LOCATELLI_PULLAN_MC_H
+
+/// \ingroup approx_algs
+///
+/// \file
+/// \brief The iterated local search algorithm of Grosso, Locatelli, and Pullan
+/// for the maximum clique problem
+
+#include <vector>
+#include <limits>
+#include <lemon/core.h>
+#include <lemon/random.h>
+
+namespace lemon {
+
+ /// \addtogroup approx_algs
+ /// @{
+
+ /// \brief Implementation of the iterated local search algorithm of Grosso,
+ /// Locatelli, and Pullan for the maximum clique problem
+ ///
+ /// \ref GrossoLocatelliPullanMc implements the iterated local search
+ /// algorithm of Grosso, Locatelli, and Pullan for solving the \e maximum
+ /// \e clique \e problem \cite grosso08maxclique.
+ /// It is to find the largest complete subgraph (\e clique) in an
+ /// undirected graph, i.e., the largest set of nodes where each
+ /// pair of nodes is connected.
+ ///
+ /// This class provides a simple but highly efficient and robust heuristic
+ /// method that quickly finds a quite large clique, but not necessarily the
+ /// largest one.
+ /// The algorithm performs a certain number of iterations to find several
+ /// cliques and selects the largest one among them. Various limits can be
+ /// specified to control the running time and the effectiveness of the
+ /// search process.
+ ///
+ /// \tparam GR The undirected graph type the algorithm runs on.
+ ///
+ /// \note %GrossoLocatelliPullanMc provides three different node selection
+ /// rules, from which the most powerful one is used by default.
+ /// For more information, see \ref SelectionRule.
+ template <typename GR>
+ class GrossoLocatelliPullanMc
+ {
+ public:
+
+ /// \brief Constants for specifying the node selection rule.
+ ///
+ /// Enum type containing constants for specifying the node selection rule
+ /// for the \ref run() function.
+ ///
+ /// During the algorithm, nodes are selected for addition to the current
+ /// clique according to the applied rule.
+ /// In general, the PENALTY_BASED rule turned out to be the most powerful
+ /// and the most robust, thus it is the default option.
+ /// However, another selection rule can be specified using the \ref run()
+ /// function with the proper parameter.
+ enum SelectionRule {
+
+ /// A node is selected randomly without any evaluation at each step.
+ RANDOM,
+
+ /// A node of maximum degree is selected randomly at each step.
+ DEGREE_BASED,
+
+ /// A node of minimum penalty is selected randomly at each step.
+ /// The node penalties are updated adaptively after each stage of the
+ /// search process.
+ PENALTY_BASED
+ };
+
+ /// \brief Constants for the causes of search termination.
+ ///
+ /// Enum type containing constants for the different causes of search
+ /// termination. The \ref run() function returns one of these values.
+ enum TerminationCause {
+
+ /// The iteration count limit is reached.
+ ITERATION_LIMIT,
+
+ /// The step count limit is reached.
+ STEP_LIMIT,
+
+ /// The clique size limit is reached.
+ SIZE_LIMIT
+ };
+
+ private:
+
+ TEMPLATE_GRAPH_TYPEDEFS(GR);
+
+ typedef std::vector<int> IntVector;
+ typedef std::vector<char> BoolVector;
+ typedef std::vector<BoolVector> BoolMatrix;
+ // Note: vector<char> is used instead of vector<bool> for efficiency reasons
+
+ // The underlying graph
+ const GR &_graph;
+ IntNodeMap _id;
+
+ // Internal matrix representation of the graph
+ BoolMatrix _gr;
+ int _n;
+
+ // Search options
+ bool _delta_based_restart;
+ int _restart_delta_limit;
+
+ // Search limits
+ int _iteration_limit;
+ int _step_limit;
+ int _size_limit;
+
+ // The current clique
+ BoolVector _clique;
+ int _size;
+
+ // The best clique found so far
+ BoolVector _best_clique;
+ int _best_size;
+
+ // The "distances" of the nodes from the current clique.
+ // _delta[u] is the number of nodes in the clique that are
+ // not connected with u.
+ IntVector _delta;
+
+ // The current tabu set
+ BoolVector _tabu;
+
+ // Random number generator
+ Random _rnd;
+
+ private:
+
+ // Implementation of the RANDOM node selection rule.
+ class RandomSelectionRule
+ {
+ private:
+
+ // References to the algorithm instance
+ const BoolVector &_clique;
+ const IntVector &_delta;
+ const BoolVector &_tabu;
+ Random &_rnd;
+
+ // Pivot rule data
+ int _n;
+
+ public:
+
+ // Constructor
+ RandomSelectionRule(GrossoLocatelliPullanMc &mc) :
+ _clique(mc._clique), _delta(mc._delta), _tabu(mc._tabu),
+ _rnd(mc._rnd), _n(mc._n)
+ {}
+
+ // Return a node index for a feasible add move or -1 if no one exists
+ int nextFeasibleAddNode() const {
+ int start_node = _rnd[_n];
+ for (int i = start_node; i != _n; i++) {
+ if (_delta[i] == 0 && !_tabu[i]) return i;
+ }
+ for (int i = 0; i != start_node; i++) {
+ if (_delta[i] == 0 && !_tabu[i]) return i;
+ }
+ return -1;
+ }
+
+ // Return a node index for a feasible swap move or -1 if no one exists
+ int nextFeasibleSwapNode() const {
+ int start_node = _rnd[_n];
+ for (int i = start_node; i != _n; i++) {
+ if (!_clique[i] && _delta[i] == 1 && !_tabu[i]) return i;
+ }
+ for (int i = 0; i != start_node; i++) {
+ if (!_clique[i] && _delta[i] == 1 && !_tabu[i]) return i;
+ }
+ return -1;
+ }
+
+ // Return a node index for an add move or -1 if no one exists
+ int nextAddNode() const {
+ int start_node = _rnd[_n];
+ for (int i = start_node; i != _n; i++) {
+ if (_delta[i] == 0) return i;
+ }
+ for (int i = 0; i != start_node; i++) {
+ if (_delta[i] == 0) return i;
+ }
+ return -1;
+ }
+
+ // Update internal data structures between stages (if necessary)
+ void update() {}
+
+ }; //class RandomSelectionRule
+
+
+ // Implementation of the DEGREE_BASED node selection rule.
+ class DegreeBasedSelectionRule
+ {
+ private:
+
+ // References to the algorithm instance
+ const BoolVector &_clique;
+ const IntVector &_delta;
+ const BoolVector &_tabu;
+ Random &_rnd;
+
+ // Pivot rule data
+ int _n;
+ IntVector _deg;
+
+ public:
+
+ // Constructor
+ DegreeBasedSelectionRule(GrossoLocatelliPullanMc &mc) :
+ _clique(mc._clique), _delta(mc._delta), _tabu(mc._tabu),
+ _rnd(mc._rnd), _n(mc._n), _deg(_n)
+ {
+ for (int i = 0; i != _n; i++) {
+ int d = 0;
+ BoolVector &row = mc._gr[i];
+ for (int j = 0; j != _n; j++) {
+ if (row[j]) d++;
+ }
+ _deg[i] = d;
+ }
+ }
+
+ // Return a node index for a feasible add move or -1 if no one exists
+ int nextFeasibleAddNode() const {
+ int start_node = _rnd[_n];
+ int node = -1, max_deg = -1;
+ for (int i = start_node; i != _n; i++) {
+ if (_delta[i] == 0 && !_tabu[i] && _deg[i] > max_deg) {
+ node = i;
+ max_deg = _deg[i];
+ }
+ }
+ for (int i = 0; i != start_node; i++) {
+ if (_delta[i] == 0 && !_tabu[i] && _deg[i] > max_deg) {
+ node = i;
+ max_deg = _deg[i];
+ }
+ }
+ return node;
+ }
+
+ // Return a node index for a feasible swap move or -1 if no one exists
+ int nextFeasibleSwapNode() const {
+ int start_node = _rnd[_n];
+ int node = -1, max_deg = -1;
+ for (int i = start_node; i != _n; i++) {
+ if (!_clique[i] && _delta[i] == 1 && !_tabu[i] &&
+ _deg[i] > max_deg) {
+ node = i;
+ max_deg = _deg[i];
+ }
+ }
+ for (int i = 0; i != start_node; i++) {
+ if (!_clique[i] && _delta[i] == 1 && !_tabu[i] &&
+ _deg[i] > max_deg) {
+ node = i;
+ max_deg = _deg[i];
+ }
+ }
+ return node;
+ }
+
+ // Return a node index for an add move or -1 if no one exists
+ int nextAddNode() const {
+ int start_node = _rnd[_n];
+ int node = -1, max_deg = -1;
+ for (int i = start_node; i != _n; i++) {
+ if (_delta[i] == 0 && _deg[i] > max_deg) {
+ node = i;
+ max_deg = _deg[i];
+ }
+ }
+ for (int i = 0; i != start_node; i++) {
+ if (_delta[i] == 0 && _deg[i] > max_deg) {
+ node = i;
+ max_deg = _deg[i];
+ }
+ }
+ return node;
+ }
+
+ // Update internal data structures between stages (if necessary)
+ void update() {}
+
+ }; //class DegreeBasedSelectionRule
+
+
+ // Implementation of the PENALTY_BASED node selection rule.
+ class PenaltyBasedSelectionRule
+ {
+ private:
+
+ // References to the algorithm instance
+ const BoolVector &_clique;
+ const IntVector &_delta;
+ const BoolVector &_tabu;
+ Random &_rnd;
+
+ // Pivot rule data
+ int _n;
+ IntVector _penalty;
+
+ public:
+
+ // Constructor
+ PenaltyBasedSelectionRule(GrossoLocatelliPullanMc &mc) :
+ _clique(mc._clique), _delta(mc._delta), _tabu(mc._tabu),
+ _rnd(mc._rnd), _n(mc._n), _penalty(_n, 0)
+ {}
+
+ // Return a node index for a feasible add move or -1 if no one exists
+ int nextFeasibleAddNode() const {
+ int start_node = _rnd[_n];
+ int node = -1, min_p = std::numeric_limits<int>::max();
+ for (int i = start_node; i != _n; i++) {
+ if (_delta[i] == 0 && !_tabu[i] && _penalty[i] < min_p) {
+ node = i;
+ min_p = _penalty[i];
+ }
+ }
+ for (int i = 0; i != start_node; i++) {
+ if (_delta[i] == 0 && !_tabu[i] && _penalty[i] < min_p) {
+ node = i;
+ min_p = _penalty[i];
+ }
+ }
+ return node;
+ }
+
+ // Return a node index for a feasible swap move or -1 if no one exists
+ int nextFeasibleSwapNode() const {
+ int start_node = _rnd[_n];
+ int node = -1, min_p = std::numeric_limits<int>::max();
+ for (int i = start_node; i != _n; i++) {
+ if (!_clique[i] && _delta[i] == 1 && !_tabu[i] &&
+ _penalty[i] < min_p) {
+ node = i;
+ min_p = _penalty[i];
+ }
+ }
+ for (int i = 0; i != start_node; i++) {
+ if (!_clique[i] && _delta[i] == 1 && !_tabu[i] &&
+ _penalty[i] < min_p) {
+ node = i;
+ min_p = _penalty[i];
+ }
+ }
+ return node;
+ }
+
+ // Return a node index for an add move or -1 if no one exists
+ int nextAddNode() const {
+ int start_node = _rnd[_n];
+ int node = -1, min_p = std::numeric_limits<int>::max();
+ for (int i = start_node; i != _n; i++) {
+ if (_delta[i] == 0 && _penalty[i] < min_p) {
+ node = i;
+ min_p = _penalty[i];
+ }
+ }
+ for (int i = 0; i != start_node; i++) {
+ if (_delta[i] == 0 && _penalty[i] < min_p) {
+ node = i;
+ min_p = _penalty[i];
+ }
+ }
+ return node;
+ }
+
+ // Update internal data structures between stages (if necessary)
+ void update() {}
+
+ }; //class PenaltyBasedSelectionRule
+
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ /// The global \ref rnd "random number generator instance" is used
+ /// during the algorithm.
+ ///
+ /// \param graph The undirected graph the algorithm runs on.
+ GrossoLocatelliPullanMc(const GR& graph) :
+ _graph(graph), _id(_graph), _rnd(rnd)
+ {
+ initOptions();
+ }
+
+ /// \brief Constructor with random seed.
+ ///
+ /// Constructor with random seed.
+ ///
+ /// \param graph The undirected graph the algorithm runs on.
+ /// \param seed Seed value for the internal random number generator
+ /// that is used during the algorithm.
+ GrossoLocatelliPullanMc(const GR& graph, int seed) :
+ _graph(graph), _id(_graph), _rnd(seed)
+ {
+ initOptions();
+ }
+
+ /// \brief Constructor with random number generator.
+ ///
+ /// Constructor with random number generator.
+ ///
+ /// \param graph The undirected graph the algorithm runs on.
+ /// \param random A random number generator that is used during the
+ /// algorithm.
+ GrossoLocatelliPullanMc(const GR& graph, const Random& random) :
+ _graph(graph), _id(_graph), _rnd(random)
+ {
+ initOptions();
+ }
+
+ /// \name Execution Control
+ /// The \ref run() function can be used to execute the algorithm.\n
+ /// The functions \ref iterationLimit(int), \ref stepLimit(int), and
+ /// \ref sizeLimit(int) can be used to specify various limits for the
+ /// search process.
+
+ /// @{
+
+ /// \brief Sets the maximum number of iterations.
+ ///
+ /// This function sets the maximum number of iterations.
+ /// Each iteration of the algorithm finds a maximal clique (but not
+ /// necessarily the largest one) by performing several search steps
+ /// (node selections).
+ ///
+ /// This limit controls the running time and the success of the
+ /// algorithm. For larger values, the algorithm runs slower, but it more
+ /// likely finds larger cliques. For smaller values, the algorithm is
+ /// faster but probably gives worse results.
+ ///
+ /// The default value is \c 1000.
+ /// \c -1 means that number of iterations is not limited.
+ ///
+ /// \warning You should specify a reasonable limit for the number of
+ /// iterations and/or the number of search steps.
+ ///
+ /// \return <tt>(*this)</tt>
+ ///
+ /// \sa stepLimit(int)
+ /// \sa sizeLimit(int)
+ GrossoLocatelliPullanMc& iterationLimit(int limit) {
+ _iteration_limit = limit;
+ return *this;
+ }
+
+ /// \brief Sets the maximum number of search steps.
+ ///
+ /// This function sets the maximum number of elementary search steps.
+ /// Each iteration of the algorithm finds a maximal clique (but not
+ /// necessarily the largest one) by performing several search steps
+ /// (node selections).
+ ///
+ /// This limit controls the running time and the success of the
+ /// algorithm. For larger values, the algorithm runs slower, but it more
+ /// likely finds larger cliques. For smaller values, the algorithm is
+ /// faster but probably gives worse results.
+ ///
+ /// The default value is \c -1, which means that number of steps
+ /// is not limited explicitly. However, the number of iterations is
+ /// limited and each iteration performs a finite number of search steps.
+ ///
+ /// \warning You should specify a reasonable limit for the number of
+ /// iterations and/or the number of search steps.
+ ///
+ /// \return <tt>(*this)</tt>
+ ///
+ /// \sa iterationLimit(int)
+ /// \sa sizeLimit(int)
+ GrossoLocatelliPullanMc& stepLimit(int limit) {
+ _step_limit = limit;
+ return *this;
+ }
+
+ /// \brief Sets the desired clique size.
+ ///
+ /// This function sets the desired clique size that serves as a search
+ /// limit. If a clique of this size (or a larger one) is found, then the
+ /// algorithm terminates.
+ ///
+ /// This function is especially useful if you know an exact upper bound
+ /// for the size of the cliques in the graph or if any clique above
+ /// a certain size limit is sufficient for your application.
+ ///
+ /// The default value is \c -1, which means that the size limit is set to
+ /// the number of nodes in the graph.
+ ///
+ /// \return <tt>(*this)</tt>
+ ///
+ /// \sa iterationLimit(int)
+ /// \sa stepLimit(int)
+ GrossoLocatelliPullanMc& sizeLimit(int limit) {
+ _size_limit = limit;
+ return *this;
+ }
+
+ /// \brief The maximum number of iterations.
+ ///
+ /// This function gives back the maximum number of iterations.
+ /// \c -1 means that no limit is specified.
+ ///
+ /// \sa iterationLimit(int)
+ int iterationLimit() const {
+ return _iteration_limit;
+ }
+
+ /// \brief The maximum number of search steps.
+ ///
+ /// This function gives back the maximum number of search steps.
+ /// \c -1 means that no limit is specified.
+ ///
+ /// \sa stepLimit(int)
+ int stepLimit() const {
+ return _step_limit;
+ }
+
+ /// \brief The desired clique size.
+ ///
+ /// This function gives back the desired clique size that serves as a
+ /// search limit. \c -1 means that this limit is set to the number of
+ /// nodes in the graph.
+ ///
+ /// \sa sizeLimit(int)
+ int sizeLimit() const {
+ return _size_limit;
+ }
+
+ /// \brief Runs the algorithm.
+ ///
+ /// This function runs the algorithm. If one of the specified limits
+ /// is reached, the search process terminates.
+ ///
+ /// \param rule The node selection rule. For more information, see
+ /// \ref SelectionRule.
+ ///
+ /// \return The termination cause of the search. For more information,
+ /// see \ref TerminationCause.
+ TerminationCause run(SelectionRule rule = PENALTY_BASED)
+ {
+ init();
+ switch (rule) {
+ case RANDOM:
+ return start<RandomSelectionRule>();
+ case DEGREE_BASED:
+ return start<DegreeBasedSelectionRule>();
+ default:
+ return start<PenaltyBasedSelectionRule>();
+ }
+ }
+
+ /// @}
+
+ /// \name Query Functions
+ /// The results of the algorithm can be obtained using these functions.\n
+ /// The run() function must be called before using them.
+
+ /// @{
+
+ /// \brief The size of the found clique
+ ///
+ /// This function returns the size of the found clique.
+ ///
+ /// \pre run() must be called before using this function.
+ int cliqueSize() const {
+ return _best_size;
+ }
+
+ /// \brief Gives back the found clique in a \c bool node map
+ ///
+ /// This function gives back the characteristic vector of the found
+ /// clique in the given node map.
+ /// It must be a \ref concepts::WriteMap "writable" node map with
+ /// \c bool (or convertible) value type.
+ ///
+ /// \pre run() must be called before using this function.
+ template <typename CliqueMap>
+ void cliqueMap(CliqueMap &map) const {
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ map[n] = static_cast<bool>(_best_clique[_id[n]]);
+ }
+ }
+
+ /// \brief Iterator to list the nodes of the found clique
+ ///
+ /// This iterator class lists the nodes of the found clique.
+ /// Before using it, you must allocate a GrossoLocatelliPullanMc instance
+ /// and call its \ref GrossoLocatelliPullanMc::run() "run()" method.
+ ///
+ /// The following example prints out the IDs of the nodes in the found
+ /// clique.
+ /// \code
+ /// GrossoLocatelliPullanMc<Graph> mc(g);
+ /// mc.run();
+ /// for (GrossoLocatelliPullanMc<Graph>::CliqueNodeIt n(mc);
+ /// n != INVALID; ++n)
+ /// {
+ /// std::cout << g.id(n) << std::endl;
+ /// }
+ /// \endcode
+ class CliqueNodeIt
+ {
+ private:
+ NodeIt _it;
+ BoolNodeMap _map;
+
+ public:
+
+ /// Constructor
+
+ /// Constructor.
+ /// \param mc The algorithm instance.
+ CliqueNodeIt(const GrossoLocatelliPullanMc &mc)
+ : _map(mc._graph)
+ {
+ mc.cliqueMap(_map);
+ for (_it = NodeIt(mc._graph); _it != INVALID && !_map[_it]; ++_it) ;
+ }
+
+ /// Conversion to \c Node
+ operator Node() const { return _it; }
+
+ bool operator==(Invalid) const { return _it == INVALID; }
+ bool operator!=(Invalid) const { return _it != INVALID; }
+
+ /// Next node
+ CliqueNodeIt &operator++() {
+ for (++_it; _it != INVALID && !_map[_it]; ++_it) ;
+ return *this;
+ }
+
+ /// Postfix incrementation
+
+ /// Postfix incrementation.
+ ///
+ /// \warning This incrementation returns a \c Node, not a
+ /// \c CliqueNodeIt as one may expect.
+ typename GR::Node operator++(int) {
+ Node n=*this;
+ ++(*this);
+ return n;
+ }
+
+ };
+
+ /// @}
+
+ private:
+
+ // Initialize search options and limits
+ void initOptions() {
+ // Search options
+ _delta_based_restart = true;
+ _restart_delta_limit = 4;
+
+ // Search limits
+ _iteration_limit = 1000;
+ _step_limit = -1; // this is disabled by default
+ _size_limit = -1; // this is disabled by default
+ }
+
+ // Adds a node to the current clique
+ void addCliqueNode(int u) {
+ if (_clique[u]) return;
+ _clique[u] = true;
+ _size++;
+ BoolVector &row = _gr[u];
+ for (int i = 0; i != _n; i++) {
+ if (!row[i]) _delta[i]++;
+ }
+ }
+
+ // Removes a node from the current clique
+ void delCliqueNode(int u) {
+ if (!_clique[u]) return;
+ _clique[u] = false;
+ _size--;
+ BoolVector &row = _gr[u];
+ for (int i = 0; i != _n; i++) {
+ if (!row[i]) _delta[i]--;
+ }
+ }
+
+ // Initialize data structures
+ void init() {
+ _n = countNodes(_graph);
+ int ui = 0;
+ for (NodeIt u(_graph); u != INVALID; ++u) {
+ _id[u] = ui++;
+ }
+ _gr.clear();
+ _gr.resize(_n, BoolVector(_n, false));
+ ui = 0;
+ for (NodeIt u(_graph); u != INVALID; ++u) {
+ for (IncEdgeIt e(_graph, u); e != INVALID; ++e) {
+ int vi = _id[_graph.runningNode(e)];
+ _gr[ui][vi] = true;
+ _gr[vi][ui] = true;
+ }
+ ++ui;
+ }
+
+ _clique.clear();
+ _clique.resize(_n, false);
+ _size = 0;
+ _best_clique.clear();
+ _best_clique.resize(_n, false);
+ _best_size = 0;
+ _delta.clear();
+ _delta.resize(_n, 0);
+ _tabu.clear();
+ _tabu.resize(_n, false);
+ }
+
+ // Executes the algorithm
+ template <typename SelectionRuleImpl>
+ TerminationCause start() {
+ if (_n == 0) return SIZE_LIMIT;
+ if (_n == 1) {
+ _best_clique[0] = true;
+ _best_size = 1;
+ return SIZE_LIMIT;
+ }
+
+ // Iterated local search algorithm
+ const int max_size = _size_limit >= 0 ? _size_limit : _n;
+ const int max_restart = _iteration_limit >= 0 ?
+ _iteration_limit : std::numeric_limits<int>::max();
+ const int max_select = _step_limit >= 0 ?
+ _step_limit : std::numeric_limits<int>::max();
+
+ SelectionRuleImpl sel_method(*this);
+ int select = 0, restart = 0;
+ IntVector restart_nodes;
+ while (select < max_select && restart < max_restart) {
+
+ // Perturbation/restart
+ restart++;
+ if (_delta_based_restart) {
+ restart_nodes.clear();
+ for (int i = 0; i != _n; i++) {
+ if (_delta[i] >= _restart_delta_limit)
+ restart_nodes.push_back(i);
+ }
+ }
+ int rs_node = -1;
+ if (restart_nodes.size() > 0) {
+ rs_node = restart_nodes[_rnd[restart_nodes.size()]];
+ } else {
+ rs_node = _rnd[_n];
+ }
+ BoolVector &row = _gr[rs_node];
+ for (int i = 0; i != _n; i++) {
+ if (_clique[i] && !row[i]) delCliqueNode(i);
+ }
+ addCliqueNode(rs_node);
+
+ // Local search
+ _tabu.clear();
+ _tabu.resize(_n, false);
+ bool tabu_empty = true;
+ int max_swap = _size;
+ while (select < max_select) {
+ select++;
+ int u;
+ if ((u = sel_method.nextFeasibleAddNode()) != -1) {
+ // Feasible add move
+ addCliqueNode(u);
+ if (tabu_empty) max_swap = _size;
+ }
+ else if ((u = sel_method.nextFeasibleSwapNode()) != -1) {
+ // Feasible swap move
+ int v = -1;
+ BoolVector &row = _gr[u];
+ for (int i = 0; i != _n; i++) {
+ if (_clique[i] && !row[i]) {
+ v = i;
+ break;
+ }
+ }
+ addCliqueNode(u);
+ delCliqueNode(v);
+ _tabu[v] = true;
+ tabu_empty = false;
+ if (--max_swap <= 0) break;
+ }
+ else if ((u = sel_method.nextAddNode()) != -1) {
+ // Non-feasible add move
+ addCliqueNode(u);
+ }
+ else break;
+ }
+ if (_size > _best_size) {
+ _best_clique = _clique;
+ _best_size = _size;
+ if (_best_size >= max_size) return SIZE_LIMIT;
+ }
+ sel_method.update();
+ }
+
+ return (restart >= max_restart ? ITERATION_LIMIT : STEP_LIMIT);
+ }
+
+ }; //class GrossoLocatelliPullanMc
+
+ ///@}
+
+} //namespace lemon
+
+#endif //LEMON_GROSSO_LOCATELLI_PULLAN_MC_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/hao_orlin.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/hao_orlin.h
new file mode 100644
index 00000000000..0eeaff95d14
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/hao_orlin.h
@@ -0,0 +1,1015 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_HAO_ORLIN_H
+#define LEMON_HAO_ORLIN_H
+
+#include <vector>
+#include <list>
+#include <limits>
+
+#include <lemon/maps.h>
+#include <lemon/core.h>
+#include <lemon/tolerance.h>
+
+/// \file
+/// \ingroup min_cut
+/// \brief Implementation of the Hao-Orlin algorithm.
+///
+/// Implementation of the Hao-Orlin algorithm for finding a minimum cut
+/// in a digraph.
+
+namespace lemon {
+
+ /// \ingroup min_cut
+ ///
+ /// \brief Hao-Orlin algorithm for finding a minimum cut in a digraph.
+ ///
+ /// This class implements the Hao-Orlin algorithm for finding a minimum
+ /// value cut in a directed graph \f$D=(V,A)\f$.
+ /// It takes a fixed node \f$ source \in V \f$ and
+ /// consists of two phases: in the first phase it determines a
+ /// minimum cut with \f$ source \f$ on the source-side (i.e. a set
+ /// \f$ X\subsetneq V \f$ with \f$ source \in X \f$ and minimal outgoing
+ /// capacity) and in the second phase it determines a minimum cut
+ /// with \f$ source \f$ on the sink-side (i.e. a set
+ /// \f$ X\subsetneq V \f$ with \f$ source \notin X \f$ and minimal outgoing
+ /// capacity). Obviously, the smaller of these two cuts will be a
+ /// minimum cut of \f$ D \f$. The algorithm is a modified
+ /// preflow push-relabel algorithm. Our implementation calculates
+ /// the minimum cut in \f$ O(n^2\sqrt{m}) \f$ time (we use the
+ /// highest-label rule), or in \f$O(nm)\f$ for unit capacities. A notable
+ /// use of this algorithm is testing network reliability.
+ ///
+ /// For an undirected graph you can run just the first phase of the
+ /// algorithm or you can use the algorithm of Nagamochi and Ibaraki,
+ /// which solves the undirected problem in \f$ O(nm + n^2 \log n) \f$
+ /// time. It is implemented in the NagamochiIbaraki algorithm class.
+ ///
+ /// \tparam GR The type of the digraph the algorithm runs on.
+ /// \tparam CAP The type of the arc map containing the capacities,
+ /// which can be any numreric type. The default map type is
+ /// \ref concepts::Digraph::ArcMap "GR::ArcMap<int>".
+ /// \tparam TOL Tolerance class for handling inexact computations. The
+ /// default tolerance type is \ref Tolerance "Tolerance<CAP::Value>".
+#ifdef DOXYGEN
+ template <typename GR, typename CAP, typename TOL>
+#else
+ template <typename GR,
+ typename CAP = typename GR::template ArcMap<int>,
+ typename TOL = Tolerance<typename CAP::Value> >
+#endif
+ class HaoOrlin {
+ public:
+
+ /// The digraph type of the algorithm
+ typedef GR Digraph;
+ /// The capacity map type of the algorithm
+ typedef CAP CapacityMap;
+ /// The tolerance type of the algorithm
+ typedef TOL Tolerance;
+
+ private:
+
+ typedef typename CapacityMap::Value Value;
+
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+
+ const Digraph& _graph;
+ const CapacityMap* _capacity;
+
+ typedef typename Digraph::template ArcMap<Value> FlowMap;
+ FlowMap* _flow;
+
+ Node _source;
+
+ int _node_num;
+
+ // Bucketing structure
+ std::vector<Node> _first, _last;
+ typename Digraph::template NodeMap<Node>* _next;
+ typename Digraph::template NodeMap<Node>* _prev;
+ typename Digraph::template NodeMap<bool>* _active;
+ typename Digraph::template NodeMap<int>* _bucket;
+
+ std::vector<bool> _dormant;
+
+ std::list<std::list<int> > _sets;
+ std::list<int>::iterator _highest;
+
+ typedef typename Digraph::template NodeMap<Value> ExcessMap;
+ ExcessMap* _excess;
+
+ typedef typename Digraph::template NodeMap<bool> SourceSetMap;
+ SourceSetMap* _source_set;
+
+ Value _min_cut;
+
+ typedef typename Digraph::template NodeMap<bool> MinCutMap;
+ MinCutMap* _min_cut_map;
+
+ Tolerance _tolerance;
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Constructor of the algorithm class.
+ HaoOrlin(const Digraph& graph, const CapacityMap& capacity,
+ const Tolerance& tolerance = Tolerance()) :
+ _graph(graph), _capacity(&capacity), _flow(0), _source(),
+ _node_num(), _first(), _last(), _next(0), _prev(0),
+ _active(0), _bucket(0), _dormant(), _sets(), _highest(),
+ _excess(0), _source_set(0), _min_cut(), _min_cut_map(0),
+ _tolerance(tolerance) {}
+
+ ~HaoOrlin() {
+ if (_min_cut_map) {
+ delete _min_cut_map;
+ }
+ if (_source_set) {
+ delete _source_set;
+ }
+ if (_excess) {
+ delete _excess;
+ }
+ if (_next) {
+ delete _next;
+ }
+ if (_prev) {
+ delete _prev;
+ }
+ if (_active) {
+ delete _active;
+ }
+ if (_bucket) {
+ delete _bucket;
+ }
+ if (_flow) {
+ delete _flow;
+ }
+ }
+
+ /// \brief Set the tolerance used by the algorithm.
+ ///
+ /// This function sets the tolerance object used by the algorithm.
+ /// \return <tt>(*this)</tt>
+ HaoOrlin& tolerance(const Tolerance& tolerance) {
+ _tolerance = tolerance;
+ return *this;
+ }
+
+ /// \brief Returns a const reference to the tolerance.
+ ///
+ /// This function returns a const reference to the tolerance object
+ /// used by the algorithm.
+ const Tolerance& tolerance() const {
+ return _tolerance;
+ }
+
+ private:
+
+ void activate(const Node& i) {
+ (*_active)[i] = true;
+
+ int bucket = (*_bucket)[i];
+
+ if ((*_prev)[i] == INVALID || (*_active)[(*_prev)[i]]) return;
+ //unlace
+ (*_next)[(*_prev)[i]] = (*_next)[i];
+ if ((*_next)[i] != INVALID) {
+ (*_prev)[(*_next)[i]] = (*_prev)[i];
+ } else {
+ _last[bucket] = (*_prev)[i];
+ }
+ //lace
+ (*_next)[i] = _first[bucket];
+ (*_prev)[_first[bucket]] = i;
+ (*_prev)[i] = INVALID;
+ _first[bucket] = i;
+ }
+
+ void deactivate(const Node& i) {
+ (*_active)[i] = false;
+ int bucket = (*_bucket)[i];
+
+ if ((*_next)[i] == INVALID || !(*_active)[(*_next)[i]]) return;
+
+ //unlace
+ (*_prev)[(*_next)[i]] = (*_prev)[i];
+ if ((*_prev)[i] != INVALID) {
+ (*_next)[(*_prev)[i]] = (*_next)[i];
+ } else {
+ _first[bucket] = (*_next)[i];
+ }
+ //lace
+ (*_prev)[i] = _last[bucket];
+ (*_next)[_last[bucket]] = i;
+ (*_next)[i] = INVALID;
+ _last[bucket] = i;
+ }
+
+ void addItem(const Node& i, int bucket) {
+ (*_bucket)[i] = bucket;
+ if (_last[bucket] != INVALID) {
+ (*_prev)[i] = _last[bucket];
+ (*_next)[_last[bucket]] = i;
+ (*_next)[i] = INVALID;
+ _last[bucket] = i;
+ } else {
+ (*_prev)[i] = INVALID;
+ _first[bucket] = i;
+ (*_next)[i] = INVALID;
+ _last[bucket] = i;
+ }
+ }
+
+ void findMinCutOut() {
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ (*_excess)[n] = 0;
+ (*_source_set)[n] = false;
+ }
+
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ (*_flow)[a] = 0;
+ }
+
+ int bucket_num = 0;
+ std::vector<Node> queue(_node_num);
+ int qfirst = 0, qlast = 0, qsep = 0;
+
+ {
+ typename Digraph::template NodeMap<bool> reached(_graph, false);
+
+ reached[_source] = true;
+ bool first_set = true;
+
+ for (NodeIt t(_graph); t != INVALID; ++t) {
+ if (reached[t]) continue;
+ _sets.push_front(std::list<int>());
+
+ queue[qlast++] = t;
+ reached[t] = true;
+
+ while (qfirst != qlast) {
+ if (qsep == qfirst) {
+ ++bucket_num;
+ _sets.front().push_front(bucket_num);
+ _dormant[bucket_num] = !first_set;
+ _first[bucket_num] = _last[bucket_num] = INVALID;
+ qsep = qlast;
+ }
+
+ Node n = queue[qfirst++];
+ addItem(n, bucket_num);
+
+ for (InArcIt a(_graph, n); a != INVALID; ++a) {
+ Node u = _graph.source(a);
+ if (!reached[u] && _tolerance.positive((*_capacity)[a])) {
+ reached[u] = true;
+ queue[qlast++] = u;
+ }
+ }
+ }
+ first_set = false;
+ }
+
+ ++bucket_num;
+ (*_bucket)[_source] = 0;
+ _dormant[0] = true;
+ }
+ (*_source_set)[_source] = true;
+
+ Node target = _last[_sets.back().back()];
+ {
+ for (OutArcIt a(_graph, _source); a != INVALID; ++a) {
+ if (_tolerance.positive((*_capacity)[a])) {
+ Node u = _graph.target(a);
+ (*_flow)[a] = (*_capacity)[a];
+ (*_excess)[u] += (*_capacity)[a];
+ if (!(*_active)[u] && u != _source) {
+ activate(u);
+ }
+ }
+ }
+
+ if ((*_active)[target]) {
+ deactivate(target);
+ }
+
+ _highest = _sets.back().begin();
+ while (_highest != _sets.back().end() &&
+ !(*_active)[_first[*_highest]]) {
+ ++_highest;
+ }
+ }
+
+ while (true) {
+ while (_highest != _sets.back().end()) {
+ Node n = _first[*_highest];
+ Value excess = (*_excess)[n];
+ int next_bucket = _node_num;
+
+ int under_bucket;
+ if (++std::list<int>::iterator(_highest) == _sets.back().end()) {
+ under_bucket = -1;
+ } else {
+ under_bucket = *(++std::list<int>::iterator(_highest));
+ }
+
+ for (OutArcIt a(_graph, n); a != INVALID; ++a) {
+ Node v = _graph.target(a);
+ if (_dormant[(*_bucket)[v]]) continue;
+ Value rem = (*_capacity)[a] - (*_flow)[a];
+ if (!_tolerance.positive(rem)) continue;
+ if ((*_bucket)[v] == under_bucket) {
+ if (!(*_active)[v] && v != target) {
+ activate(v);
+ }
+ if (!_tolerance.less(rem, excess)) {
+ (*_flow)[a] += excess;
+ (*_excess)[v] += excess;
+ excess = 0;
+ goto no_more_push;
+ } else {
+ excess -= rem;
+ (*_excess)[v] += rem;
+ (*_flow)[a] = (*_capacity)[a];
+ }
+ } else if (next_bucket > (*_bucket)[v]) {
+ next_bucket = (*_bucket)[v];
+ }
+ }
+
+ for (InArcIt a(_graph, n); a != INVALID; ++a) {
+ Node v = _graph.source(a);
+ if (_dormant[(*_bucket)[v]]) continue;
+ Value rem = (*_flow)[a];
+ if (!_tolerance.positive(rem)) continue;
+ if ((*_bucket)[v] == under_bucket) {
+ if (!(*_active)[v] && v != target) {
+ activate(v);
+ }
+ if (!_tolerance.less(rem, excess)) {
+ (*_flow)[a] -= excess;
+ (*_excess)[v] += excess;
+ excess = 0;
+ goto no_more_push;
+ } else {
+ excess -= rem;
+ (*_excess)[v] += rem;
+ (*_flow)[a] = 0;
+ }
+ } else if (next_bucket > (*_bucket)[v]) {
+ next_bucket = (*_bucket)[v];
+ }
+ }
+
+ no_more_push:
+
+ (*_excess)[n] = excess;
+
+ if (excess != 0) {
+ if ((*_next)[n] == INVALID) {
+ typename std::list<std::list<int> >::iterator new_set =
+ _sets.insert(--_sets.end(), std::list<int>());
+ new_set->splice(new_set->end(), _sets.back(),
+ _sets.back().begin(), ++_highest);
+ for (std::list<int>::iterator it = new_set->begin();
+ it != new_set->end(); ++it) {
+ _dormant[*it] = true;
+ }
+ while (_highest != _sets.back().end() &&
+ !(*_active)[_first[*_highest]]) {
+ ++_highest;
+ }
+ } else if (next_bucket == _node_num) {
+ _first[(*_bucket)[n]] = (*_next)[n];
+ (*_prev)[(*_next)[n]] = INVALID;
+
+ std::list<std::list<int> >::iterator new_set =
+ _sets.insert(--_sets.end(), std::list<int>());
+
+ new_set->push_front(bucket_num);
+ (*_bucket)[n] = bucket_num;
+ _first[bucket_num] = _last[bucket_num] = n;
+ (*_next)[n] = INVALID;
+ (*_prev)[n] = INVALID;
+ _dormant[bucket_num] = true;
+ ++bucket_num;
+
+ while (_highest != _sets.back().end() &&
+ !(*_active)[_first[*_highest]]) {
+ ++_highest;
+ }
+ } else {
+ _first[*_highest] = (*_next)[n];
+ (*_prev)[(*_next)[n]] = INVALID;
+
+ while (next_bucket != *_highest) {
+ --_highest;
+ }
+
+ if (_highest == _sets.back().begin()) {
+ _sets.back().push_front(bucket_num);
+ _dormant[bucket_num] = false;
+ _first[bucket_num] = _last[bucket_num] = INVALID;
+ ++bucket_num;
+ }
+ --_highest;
+
+ (*_bucket)[n] = *_highest;
+ (*_next)[n] = _first[*_highest];
+ if (_first[*_highest] != INVALID) {
+ (*_prev)[_first[*_highest]] = n;
+ } else {
+ _last[*_highest] = n;
+ }
+ _first[*_highest] = n;
+ }
+ } else {
+
+ deactivate(n);
+ if (!(*_active)[_first[*_highest]]) {
+ ++_highest;
+ if (_highest != _sets.back().end() &&
+ !(*_active)[_first[*_highest]]) {
+ _highest = _sets.back().end();
+ }
+ }
+ }
+ }
+
+ if ((*_excess)[target] < _min_cut) {
+ _min_cut = (*_excess)[target];
+ for (NodeIt i(_graph); i != INVALID; ++i) {
+ (*_min_cut_map)[i] = true;
+ }
+ for (std::list<int>::iterator it = _sets.back().begin();
+ it != _sets.back().end(); ++it) {
+ Node n = _first[*it];
+ while (n != INVALID) {
+ (*_min_cut_map)[n] = false;
+ n = (*_next)[n];
+ }
+ }
+ }
+
+ {
+ Node new_target;
+ if ((*_prev)[target] != INVALID || (*_next)[target] != INVALID) {
+ if ((*_next)[target] == INVALID) {
+ _last[(*_bucket)[target]] = (*_prev)[target];
+ new_target = (*_prev)[target];
+ } else {
+ (*_prev)[(*_next)[target]] = (*_prev)[target];
+ new_target = (*_next)[target];
+ }
+ if ((*_prev)[target] == INVALID) {
+ _first[(*_bucket)[target]] = (*_next)[target];
+ } else {
+ (*_next)[(*_prev)[target]] = (*_next)[target];
+ }
+ } else {
+ _sets.back().pop_back();
+ if (_sets.back().empty()) {
+ _sets.pop_back();
+ if (_sets.empty())
+ break;
+ for (std::list<int>::iterator it = _sets.back().begin();
+ it != _sets.back().end(); ++it) {
+ _dormant[*it] = false;
+ }
+ }
+ new_target = _last[_sets.back().back()];
+ }
+
+ (*_bucket)[target] = 0;
+
+ (*_source_set)[target] = true;
+ for (OutArcIt a(_graph, target); a != INVALID; ++a) {
+ Value rem = (*_capacity)[a] - (*_flow)[a];
+ if (!_tolerance.positive(rem)) continue;
+ Node v = _graph.target(a);
+ if (!(*_active)[v] && !(*_source_set)[v]) {
+ activate(v);
+ }
+ (*_excess)[v] += rem;
+ (*_flow)[a] = (*_capacity)[a];
+ }
+
+ for (InArcIt a(_graph, target); a != INVALID; ++a) {
+ Value rem = (*_flow)[a];
+ if (!_tolerance.positive(rem)) continue;
+ Node v = _graph.source(a);
+ if (!(*_active)[v] && !(*_source_set)[v]) {
+ activate(v);
+ }
+ (*_excess)[v] += rem;
+ (*_flow)[a] = 0;
+ }
+
+ target = new_target;
+ if ((*_active)[target]) {
+ deactivate(target);
+ }
+
+ _highest = _sets.back().begin();
+ while (_highest != _sets.back().end() &&
+ !(*_active)[_first[*_highest]]) {
+ ++_highest;
+ }
+ }
+ }
+ }
+
+ void findMinCutIn() {
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ (*_excess)[n] = 0;
+ (*_source_set)[n] = false;
+ }
+
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ (*_flow)[a] = 0;
+ }
+
+ int bucket_num = 0;
+ std::vector<Node> queue(_node_num);
+ int qfirst = 0, qlast = 0, qsep = 0;
+
+ {
+ typename Digraph::template NodeMap<bool> reached(_graph, false);
+
+ reached[_source] = true;
+
+ bool first_set = true;
+
+ for (NodeIt t(_graph); t != INVALID; ++t) {
+ if (reached[t]) continue;
+ _sets.push_front(std::list<int>());
+
+ queue[qlast++] = t;
+ reached[t] = true;
+
+ while (qfirst != qlast) {
+ if (qsep == qfirst) {
+ ++bucket_num;
+ _sets.front().push_front(bucket_num);
+ _dormant[bucket_num] = !first_set;
+ _first[bucket_num] = _last[bucket_num] = INVALID;
+ qsep = qlast;
+ }
+
+ Node n = queue[qfirst++];
+ addItem(n, bucket_num);
+
+ for (OutArcIt a(_graph, n); a != INVALID; ++a) {
+ Node u = _graph.target(a);
+ if (!reached[u] && _tolerance.positive((*_capacity)[a])) {
+ reached[u] = true;
+ queue[qlast++] = u;
+ }
+ }
+ }
+ first_set = false;
+ }
+
+ ++bucket_num;
+ (*_bucket)[_source] = 0;
+ _dormant[0] = true;
+ }
+ (*_source_set)[_source] = true;
+
+ Node target = _last[_sets.back().back()];
+ {
+ for (InArcIt a(_graph, _source); a != INVALID; ++a) {
+ if (_tolerance.positive((*_capacity)[a])) {
+ Node u = _graph.source(a);
+ (*_flow)[a] = (*_capacity)[a];
+ (*_excess)[u] += (*_capacity)[a];
+ if (!(*_active)[u] && u != _source) {
+ activate(u);
+ }
+ }
+ }
+ if ((*_active)[target]) {
+ deactivate(target);
+ }
+
+ _highest = _sets.back().begin();
+ while (_highest != _sets.back().end() &&
+ !(*_active)[_first[*_highest]]) {
+ ++_highest;
+ }
+ }
+
+
+ while (true) {
+ while (_highest != _sets.back().end()) {
+ Node n = _first[*_highest];
+ Value excess = (*_excess)[n];
+ int next_bucket = _node_num;
+
+ int under_bucket;
+ if (++std::list<int>::iterator(_highest) == _sets.back().end()) {
+ under_bucket = -1;
+ } else {
+ under_bucket = *(++std::list<int>::iterator(_highest));
+ }
+
+ for (InArcIt a(_graph, n); a != INVALID; ++a) {
+ Node v = _graph.source(a);
+ if (_dormant[(*_bucket)[v]]) continue;
+ Value rem = (*_capacity)[a] - (*_flow)[a];
+ if (!_tolerance.positive(rem)) continue;
+ if ((*_bucket)[v] == under_bucket) {
+ if (!(*_active)[v] && v != target) {
+ activate(v);
+ }
+ if (!_tolerance.less(rem, excess)) {
+ (*_flow)[a] += excess;
+ (*_excess)[v] += excess;
+ excess = 0;
+ goto no_more_push;
+ } else {
+ excess -= rem;
+ (*_excess)[v] += rem;
+ (*_flow)[a] = (*_capacity)[a];
+ }
+ } else if (next_bucket > (*_bucket)[v]) {
+ next_bucket = (*_bucket)[v];
+ }
+ }
+
+ for (OutArcIt a(_graph, n); a != INVALID; ++a) {
+ Node v = _graph.target(a);
+ if (_dormant[(*_bucket)[v]]) continue;
+ Value rem = (*_flow)[a];
+ if (!_tolerance.positive(rem)) continue;
+ if ((*_bucket)[v] == under_bucket) {
+ if (!(*_active)[v] && v != target) {
+ activate(v);
+ }
+ if (!_tolerance.less(rem, excess)) {
+ (*_flow)[a] -= excess;
+ (*_excess)[v] += excess;
+ excess = 0;
+ goto no_more_push;
+ } else {
+ excess -= rem;
+ (*_excess)[v] += rem;
+ (*_flow)[a] = 0;
+ }
+ } else if (next_bucket > (*_bucket)[v]) {
+ next_bucket = (*_bucket)[v];
+ }
+ }
+
+ no_more_push:
+
+ (*_excess)[n] = excess;
+
+ if (excess != 0) {
+ if ((*_next)[n] == INVALID) {
+ typename std::list<std::list<int> >::iterator new_set =
+ _sets.insert(--_sets.end(), std::list<int>());
+ new_set->splice(new_set->end(), _sets.back(),
+ _sets.back().begin(), ++_highest);
+ for (std::list<int>::iterator it = new_set->begin();
+ it != new_set->end(); ++it) {
+ _dormant[*it] = true;
+ }
+ while (_highest != _sets.back().end() &&
+ !(*_active)[_first[*_highest]]) {
+ ++_highest;
+ }
+ } else if (next_bucket == _node_num) {
+ _first[(*_bucket)[n]] = (*_next)[n];
+ (*_prev)[(*_next)[n]] = INVALID;
+
+ std::list<std::list<int> >::iterator new_set =
+ _sets.insert(--_sets.end(), std::list<int>());
+
+ new_set->push_front(bucket_num);
+ (*_bucket)[n] = bucket_num;
+ _first[bucket_num] = _last[bucket_num] = n;
+ (*_next)[n] = INVALID;
+ (*_prev)[n] = INVALID;
+ _dormant[bucket_num] = true;
+ ++bucket_num;
+
+ while (_highest != _sets.back().end() &&
+ !(*_active)[_first[*_highest]]) {
+ ++_highest;
+ }
+ } else {
+ _first[*_highest] = (*_next)[n];
+ (*_prev)[(*_next)[n]] = INVALID;
+
+ while (next_bucket != *_highest) {
+ --_highest;
+ }
+ if (_highest == _sets.back().begin()) {
+ _sets.back().push_front(bucket_num);
+ _dormant[bucket_num] = false;
+ _first[bucket_num] = _last[bucket_num] = INVALID;
+ ++bucket_num;
+ }
+ --_highest;
+
+ (*_bucket)[n] = *_highest;
+ (*_next)[n] = _first[*_highest];
+ if (_first[*_highest] != INVALID) {
+ (*_prev)[_first[*_highest]] = n;
+ } else {
+ _last[*_highest] = n;
+ }
+ _first[*_highest] = n;
+ }
+ } else {
+
+ deactivate(n);
+ if (!(*_active)[_first[*_highest]]) {
+ ++_highest;
+ if (_highest != _sets.back().end() &&
+ !(*_active)[_first[*_highest]]) {
+ _highest = _sets.back().end();
+ }
+ }
+ }
+ }
+
+ if ((*_excess)[target] < _min_cut) {
+ _min_cut = (*_excess)[target];
+ for (NodeIt i(_graph); i != INVALID; ++i) {
+ (*_min_cut_map)[i] = false;
+ }
+ for (std::list<int>::iterator it = _sets.back().begin();
+ it != _sets.back().end(); ++it) {
+ Node n = _first[*it];
+ while (n != INVALID) {
+ (*_min_cut_map)[n] = true;
+ n = (*_next)[n];
+ }
+ }
+ }
+
+ {
+ Node new_target;
+ if ((*_prev)[target] != INVALID || (*_next)[target] != INVALID) {
+ if ((*_next)[target] == INVALID) {
+ _last[(*_bucket)[target]] = (*_prev)[target];
+ new_target = (*_prev)[target];
+ } else {
+ (*_prev)[(*_next)[target]] = (*_prev)[target];
+ new_target = (*_next)[target];
+ }
+ if ((*_prev)[target] == INVALID) {
+ _first[(*_bucket)[target]] = (*_next)[target];
+ } else {
+ (*_next)[(*_prev)[target]] = (*_next)[target];
+ }
+ } else {
+ _sets.back().pop_back();
+ if (_sets.back().empty()) {
+ _sets.pop_back();
+ if (_sets.empty())
+ break;
+ for (std::list<int>::iterator it = _sets.back().begin();
+ it != _sets.back().end(); ++it) {
+ _dormant[*it] = false;
+ }
+ }
+ new_target = _last[_sets.back().back()];
+ }
+
+ (*_bucket)[target] = 0;
+
+ (*_source_set)[target] = true;
+ for (InArcIt a(_graph, target); a != INVALID; ++a) {
+ Value rem = (*_capacity)[a] - (*_flow)[a];
+ if (!_tolerance.positive(rem)) continue;
+ Node v = _graph.source(a);
+ if (!(*_active)[v] && !(*_source_set)[v]) {
+ activate(v);
+ }
+ (*_excess)[v] += rem;
+ (*_flow)[a] = (*_capacity)[a];
+ }
+
+ for (OutArcIt a(_graph, target); a != INVALID; ++a) {
+ Value rem = (*_flow)[a];
+ if (!_tolerance.positive(rem)) continue;
+ Node v = _graph.target(a);
+ if (!(*_active)[v] && !(*_source_set)[v]) {
+ activate(v);
+ }
+ (*_excess)[v] += rem;
+ (*_flow)[a] = 0;
+ }
+
+ target = new_target;
+ if ((*_active)[target]) {
+ deactivate(target);
+ }
+
+ _highest = _sets.back().begin();
+ while (_highest != _sets.back().end() &&
+ !(*_active)[_first[*_highest]]) {
+ ++_highest;
+ }
+ }
+ }
+ }
+
+ public:
+
+ /// \name Execution Control
+ /// The simplest way to execute the algorithm is to use
+ /// one of the member functions called \ref run().
+ /// \n
+ /// If you need better control on the execution,
+ /// you have to call one of the \ref init() functions first, then
+ /// \ref calculateOut() and/or \ref calculateIn().
+
+ /// @{
+
+ /// \brief Initialize the internal data structures.
+ ///
+ /// This function initializes the internal data structures. It creates
+ /// the maps and some bucket structures for the algorithm.
+ /// The first node is used as the source node for the push-relabel
+ /// algorithm.
+ void init() {
+ init(NodeIt(_graph));
+ }
+
+ /// \brief Initialize the internal data structures.
+ ///
+ /// This function initializes the internal data structures. It creates
+ /// the maps and some bucket structures for the algorithm.
+ /// The given node is used as the source node for the push-relabel
+ /// algorithm.
+ void init(const Node& source) {
+ _source = source;
+
+ _node_num = countNodes(_graph);
+
+ _first.resize(_node_num);
+ _last.resize(_node_num);
+
+ _dormant.resize(_node_num);
+
+ if (!_flow) {
+ _flow = new FlowMap(_graph);
+ }
+ if (!_next) {
+ _next = new typename Digraph::template NodeMap<Node>(_graph);
+ }
+ if (!_prev) {
+ _prev = new typename Digraph::template NodeMap<Node>(_graph);
+ }
+ if (!_active) {
+ _active = new typename Digraph::template NodeMap<bool>(_graph);
+ }
+ if (!_bucket) {
+ _bucket = new typename Digraph::template NodeMap<int>(_graph);
+ }
+ if (!_excess) {
+ _excess = new ExcessMap(_graph);
+ }
+ if (!_source_set) {
+ _source_set = new SourceSetMap(_graph);
+ }
+ if (!_min_cut_map) {
+ _min_cut_map = new MinCutMap(_graph);
+ }
+
+ _min_cut = std::numeric_limits<Value>::max();
+ }
+
+
+ /// \brief Calculate a minimum cut with \f$ source \f$ on the
+ /// source-side.
+ ///
+ /// This function calculates a minimum cut with \f$ source \f$ on the
+ /// source-side (i.e. a set \f$ X\subsetneq V \f$ with
+ /// \f$ source \in X \f$ and minimal outgoing capacity).
+ /// It updates the stored cut if (and only if) the newly found one
+ /// is better.
+ ///
+ /// \pre \ref init() must be called before using this function.
+ void calculateOut() {
+ findMinCutOut();
+ }
+
+ /// \brief Calculate a minimum cut with \f$ source \f$ on the
+ /// sink-side.
+ ///
+ /// This function calculates a minimum cut with \f$ source \f$ on the
+ /// sink-side (i.e. a set \f$ X\subsetneq V \f$ with
+ /// \f$ source \notin X \f$ and minimal outgoing capacity).
+ /// It updates the stored cut if (and only if) the newly found one
+ /// is better.
+ ///
+ /// \pre \ref init() must be called before using this function.
+ void calculateIn() {
+ findMinCutIn();
+ }
+
+
+ /// \brief Run the algorithm.
+ ///
+ /// This function runs the algorithm. It chooses source node,
+ /// then calls \ref init(), \ref calculateOut()
+ /// and \ref calculateIn().
+ void run() {
+ init();
+ calculateOut();
+ calculateIn();
+ }
+
+ /// \brief Run the algorithm.
+ ///
+ /// This function runs the algorithm. It calls \ref init(),
+ /// \ref calculateOut() and \ref calculateIn() with the given
+ /// source node.
+ void run(const Node& s) {
+ init(s);
+ calculateOut();
+ calculateIn();
+ }
+
+ /// @}
+
+ /// \name Query Functions
+ /// The result of the %HaoOrlin algorithm
+ /// can be obtained using these functions.\n
+ /// \ref run(), \ref calculateOut() or \ref calculateIn()
+ /// should be called before using them.
+
+ /// @{
+
+ /// \brief Return the value of the minimum cut.
+ ///
+ /// This function returns the value of the best cut found by the
+ /// previously called \ref run(), \ref calculateOut() or \ref
+ /// calculateIn().
+ ///
+ /// \pre \ref run(), \ref calculateOut() or \ref calculateIn()
+ /// must be called before using this function.
+ Value minCutValue() const {
+ return _min_cut;
+ }
+
+
+ /// \brief Return a minimum cut.
+ ///
+ /// This function gives the best cut found by the
+ /// previously called \ref run(), \ref calculateOut() or \ref
+ /// calculateIn().
+ ///
+ /// It sets \c cutMap to the characteristic vector of the found
+ /// minimum value cut - a non-empty set \f$ X\subsetneq V \f$
+ /// of minimum outgoing capacity (i.e. \c cutMap will be \c true exactly
+ /// for the nodes of \f$ X \f$).
+ ///
+ /// \param cutMap A \ref concepts::WriteMap "writable" node map with
+ /// \c bool (or convertible) value type.
+ ///
+ /// \return The value of the minimum cut.
+ ///
+ /// \pre \ref run(), \ref calculateOut() or \ref calculateIn()
+ /// must be called before using this function.
+ template <typename CutMap>
+ Value minCutMap(CutMap& cutMap) const {
+ for (NodeIt it(_graph); it != INVALID; ++it) {
+ cutMap.set(it, (*_min_cut_map)[it]);
+ }
+ return _min_cut;
+ }
+
+ /// @}
+
+ }; //class HaoOrlin
+
+} //namespace lemon
+
+#endif //LEMON_HAO_ORLIN_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/hartmann_orlin_mmc.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/hartmann_orlin_mmc.h
new file mode 100644
index 00000000000..6b60a85ed7a
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/hartmann_orlin_mmc.h
@@ -0,0 +1,654 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_HARTMANN_ORLIN_MMC_H
+#define LEMON_HARTMANN_ORLIN_MMC_H
+
+/// \ingroup min_mean_cycle
+///
+/// \file
+/// \brief Hartmann-Orlin's algorithm for finding a minimum mean cycle.
+
+#include <vector>
+#include <limits>
+#include <lemon/core.h>
+#include <lemon/path.h>
+#include <lemon/tolerance.h>
+#include <lemon/connectivity.h>
+
+namespace lemon {
+
+ /// \brief Default traits class of HartmannOrlinMmc class.
+ ///
+ /// Default traits class of HartmannOrlinMmc class.
+ /// \tparam GR The type of the digraph.
+ /// \tparam CM The type of the cost map.
+ /// It must conform to the \ref concepts::ReadMap "ReadMap" concept.
+#ifdef DOXYGEN
+ template <typename GR, typename CM>
+#else
+ template <typename GR, typename CM,
+ bool integer = std::numeric_limits<typename CM::Value>::is_integer>
+#endif
+ struct HartmannOrlinMmcDefaultTraits
+ {
+ /// The type of the digraph
+ typedef GR Digraph;
+ /// The type of the cost map
+ typedef CM CostMap;
+ /// The type of the arc costs
+ typedef typename CostMap::Value Cost;
+
+ /// \brief The large cost type used for internal computations
+ ///
+ /// The large cost type used for internal computations.
+ /// It is \c long \c long if the \c Cost type is integer,
+ /// otherwise it is \c double.
+ /// \c Cost must be convertible to \c LargeCost.
+ typedef double LargeCost;
+
+ /// The tolerance type used for internal computations
+ typedef lemon::Tolerance<LargeCost> Tolerance;
+
+ /// \brief The path type of the found cycles
+ ///
+ /// The path type of the found cycles.
+ /// It must conform to the \ref lemon::concepts::Path "Path" concept
+ /// and it must have an \c addFront() function.
+ typedef lemon::Path<Digraph> Path;
+ };
+
+ // Default traits class for integer cost types
+ template <typename GR, typename CM>
+ struct HartmannOrlinMmcDefaultTraits<GR, CM, true>
+ {
+ typedef GR Digraph;
+ typedef CM CostMap;
+ typedef typename CostMap::Value Cost;
+#ifdef LEMON_HAVE_LONG_LONG
+ typedef long long LargeCost;
+#else
+ typedef long LargeCost;
+#endif
+ typedef lemon::Tolerance<LargeCost> Tolerance;
+ typedef lemon::Path<Digraph> Path;
+ };
+
+
+ /// \addtogroup min_mean_cycle
+ /// @{
+
+ /// \brief Implementation of the Hartmann-Orlin algorithm for finding
+ /// a minimum mean cycle.
+ ///
+ /// This class implements the Hartmann-Orlin algorithm for finding
+ /// a directed cycle of minimum mean cost in a digraph
+ /// \cite hartmann93finding, \cite dasdan98minmeancycle.
+ /// This method is based on \ref KarpMmc "Karp"'s original algorithm, but
+ /// applies an early termination scheme. It makes the algorithm
+ /// significantly faster for some problem instances, but slower for others.
+ /// The algorithm runs in time O(nm) and uses space O(n<sup>2</sup>+m).
+ ///
+ /// \tparam GR The type of the digraph the algorithm runs on.
+ /// \tparam CM The type of the cost map. The default
+ /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap<int>".
+ /// \tparam TR The traits class that defines various types used by the
+ /// algorithm. By default, it is \ref HartmannOrlinMmcDefaultTraits
+ /// "HartmannOrlinMmcDefaultTraits<GR, CM>".
+ /// In most cases, this parameter should not be set directly,
+ /// consider to use the named template parameters instead.
+#ifdef DOXYGEN
+ template <typename GR, typename CM, typename TR>
+#else
+ template < typename GR,
+ typename CM = typename GR::template ArcMap<int>,
+ typename TR = HartmannOrlinMmcDefaultTraits<GR, CM> >
+#endif
+ class HartmannOrlinMmc
+ {
+ public:
+
+ /// The type of the digraph
+ typedef typename TR::Digraph Digraph;
+ /// The type of the cost map
+ typedef typename TR::CostMap CostMap;
+ /// The type of the arc costs
+ typedef typename TR::Cost Cost;
+
+ /// \brief The large cost type
+ ///
+ /// The large cost type used for internal computations.
+ /// By default, it is \c long \c long if the \c Cost type is integer,
+ /// otherwise it is \c double.
+ typedef typename TR::LargeCost LargeCost;
+
+ /// The tolerance type
+ typedef typename TR::Tolerance Tolerance;
+
+ /// \brief The path type of the found cycles
+ ///
+ /// The path type of the found cycles.
+ /// Using the \ref lemon::HartmannOrlinMmcDefaultTraits
+ /// "default traits class",
+ /// it is \ref lemon::Path "Path<Digraph>".
+ typedef typename TR::Path Path;
+
+ /// \brief The
+ /// \ref lemon::HartmannOrlinMmcDefaultTraits "traits class"
+ /// of the algorithm
+ typedef TR Traits;
+
+ private:
+
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+
+ // Data sturcture for path data
+ struct PathData
+ {
+ LargeCost dist;
+ Arc pred;
+ PathData(LargeCost d, Arc p = INVALID) :
+ dist(d), pred(p) {}
+ };
+
+ typedef typename Digraph::template NodeMap<std::vector<PathData> >
+ PathDataNodeMap;
+
+ private:
+
+ // The digraph the algorithm runs on
+ const Digraph &_gr;
+ // The cost of the arcs
+ const CostMap &_cost;
+
+ // Data for storing the strongly connected components
+ int _comp_num;
+ typename Digraph::template NodeMap<int> _comp;
+ std::vector<std::vector<Node> > _comp_nodes;
+ std::vector<Node>* _nodes;
+ typename Digraph::template NodeMap<std::vector<Arc> > _out_arcs;
+
+ // Data for the found cycles
+ bool _curr_found, _best_found;
+ LargeCost _curr_cost, _best_cost;
+ int _curr_size, _best_size;
+ Node _curr_node, _best_node;
+ int _curr_level, _best_level;
+
+ Path *_cycle_path;
+ bool _local_path;
+
+ // Node map for storing path data
+ PathDataNodeMap _data;
+ // The processed nodes in the last round
+ std::vector<Node> _process;
+
+ Tolerance _tolerance;
+
+ // Infinite constant
+ const LargeCost INF;
+
+ public:
+
+ /// \name Named Template Parameters
+ /// @{
+
+ template <typename T>
+ struct SetLargeCostTraits : public Traits {
+ typedef T LargeCost;
+ typedef lemon::Tolerance<T> Tolerance;
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// \c LargeCost type.
+ ///
+ /// \ref named-templ-param "Named parameter" for setting \c LargeCost
+ /// type. It is used for internal computations in the algorithm.
+ template <typename T>
+ struct SetLargeCost
+ : public HartmannOrlinMmc<GR, CM, SetLargeCostTraits<T> > {
+ typedef HartmannOrlinMmc<GR, CM, SetLargeCostTraits<T> > Create;
+ };
+
+ template <typename T>
+ struct SetPathTraits : public Traits {
+ typedef T Path;
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// \c %Path type.
+ ///
+ /// \ref named-templ-param "Named parameter" for setting the \c %Path
+ /// type of the found cycles.
+ /// It must conform to the \ref lemon::concepts::Path "Path" concept
+ /// and it must have an \c addFront() function.
+ template <typename T>
+ struct SetPath
+ : public HartmannOrlinMmc<GR, CM, SetPathTraits<T> > {
+ typedef HartmannOrlinMmc<GR, CM, SetPathTraits<T> > Create;
+ };
+
+ /// @}
+
+ protected:
+
+ HartmannOrlinMmc() {}
+
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// The constructor of the class.
+ ///
+ /// \param digraph The digraph the algorithm runs on.
+ /// \param cost The costs of the arcs.
+ HartmannOrlinMmc( const Digraph &digraph,
+ const CostMap &cost ) :
+ _gr(digraph), _cost(cost), _comp(digraph), _out_arcs(digraph),
+ _best_found(false), _best_cost(0), _best_size(1),
+ _cycle_path(NULL), _local_path(false), _data(digraph),
+ INF(std::numeric_limits<LargeCost>::has_infinity ?
+ std::numeric_limits<LargeCost>::infinity() :
+ std::numeric_limits<LargeCost>::max())
+ {}
+
+ /// Destructor.
+ ~HartmannOrlinMmc() {
+ if (_local_path) delete _cycle_path;
+ }
+
+ /// \brief Set the path structure for storing the found cycle.
+ ///
+ /// This function sets an external path structure for storing the
+ /// found cycle.
+ ///
+ /// If you don't call this function before calling \ref run() or
+ /// \ref findCycleMean(), a local \ref Path "path" structure
+ /// will be allocated. The destuctor deallocates this automatically
+ /// allocated object, of course.
+ ///
+ /// \note The algorithm calls only the \ref lemon::Path::addFront()
+ /// "addFront()" function of the given path structure.
+ ///
+ /// \return <tt>(*this)</tt>
+ HartmannOrlinMmc& cycle(Path &path) {
+ if (_local_path) {
+ delete _cycle_path;
+ _local_path = false;
+ }
+ _cycle_path = &path;
+ return *this;
+ }
+
+ /// \brief Set the tolerance used by the algorithm.
+ ///
+ /// This function sets the tolerance object used by the algorithm.
+ ///
+ /// \return <tt>(*this)</tt>
+ HartmannOrlinMmc& tolerance(const Tolerance& tolerance) {
+ _tolerance = tolerance;
+ return *this;
+ }
+
+ /// \brief Return a const reference to the tolerance.
+ ///
+ /// This function returns a const reference to the tolerance object
+ /// used by the algorithm.
+ const Tolerance& tolerance() const {
+ return _tolerance;
+ }
+
+ /// \name Execution control
+ /// The simplest way to execute the algorithm is to call the \ref run()
+ /// function.\n
+ /// If you only need the minimum mean cost, you may call
+ /// \ref findCycleMean().
+
+ /// @{
+
+ /// \brief Run the algorithm.
+ ///
+ /// This function runs the algorithm.
+ /// It can be called more than once (e.g. if the underlying digraph
+ /// and/or the arc costs have been modified).
+ ///
+ /// \return \c true if a directed cycle exists in the digraph.
+ ///
+ /// \note <tt>mmc.run()</tt> is just a shortcut of the following code.
+ /// \code
+ /// return mmc.findCycleMean() && mmc.findCycle();
+ /// \endcode
+ bool run() {
+ return findCycleMean() && findCycle();
+ }
+
+ /// \brief Find the minimum cycle mean.
+ ///
+ /// This function finds the minimum mean cost of the directed
+ /// cycles in the digraph.
+ ///
+ /// \return \c true if a directed cycle exists in the digraph.
+ bool findCycleMean() {
+ // Initialization and find strongly connected components
+ init();
+ findComponents();
+
+ // Find the minimum cycle mean in the components
+ for (int comp = 0; comp < _comp_num; ++comp) {
+ if (!initComponent(comp)) continue;
+ processRounds();
+
+ // Update the best cycle (global minimum mean cycle)
+ if ( _curr_found && (!_best_found ||
+ _curr_cost * _best_size < _best_cost * _curr_size) ) {
+ _best_found = true;
+ _best_cost = _curr_cost;
+ _best_size = _curr_size;
+ _best_node = _curr_node;
+ _best_level = _curr_level;
+ }
+ }
+ return _best_found;
+ }
+
+ /// \brief Find a minimum mean directed cycle.
+ ///
+ /// This function finds a directed cycle of minimum mean cost
+ /// in the digraph using the data computed by findCycleMean().
+ ///
+ /// \return \c true if a directed cycle exists in the digraph.
+ ///
+ /// \pre \ref findCycleMean() must be called before using this function.
+ bool findCycle() {
+ if (!_best_found) return false;
+ IntNodeMap reached(_gr, -1);
+ int r = _best_level + 1;
+ Node u = _best_node;
+ while (reached[u] < 0) {
+ reached[u] = --r;
+ u = _gr.source(_data[u][r].pred);
+ }
+ r = reached[u];
+ Arc e = _data[u][r].pred;
+ _cycle_path->addFront(e);
+ _best_cost = _cost[e];
+ _best_size = 1;
+ Node v;
+ while ((v = _gr.source(e)) != u) {
+ e = _data[v][--r].pred;
+ _cycle_path->addFront(e);
+ _best_cost += _cost[e];
+ ++_best_size;
+ }
+ return true;
+ }
+
+ /// @}
+
+ /// \name Query Functions
+ /// The results of the algorithm can be obtained using these
+ /// functions.\n
+ /// The algorithm should be executed before using them.
+
+ /// @{
+
+ /// \brief Return the total cost of the found cycle.
+ ///
+ /// This function returns the total cost of the found cycle.
+ ///
+ /// \pre \ref run() or \ref findCycleMean() must be called before
+ /// using this function.
+ Cost cycleCost() const {
+ return static_cast<Cost>(_best_cost);
+ }
+
+ /// \brief Return the number of arcs on the found cycle.
+ ///
+ /// This function returns the number of arcs on the found cycle.
+ ///
+ /// \pre \ref run() or \ref findCycleMean() must be called before
+ /// using this function.
+ int cycleSize() const {
+ return _best_size;
+ }
+
+ /// \brief Return the mean cost of the found cycle.
+ ///
+ /// This function returns the mean cost of the found cycle.
+ ///
+ /// \note <tt>alg.cycleMean()</tt> is just a shortcut of the
+ /// following code.
+ /// \code
+ /// return static_cast<double>(alg.cycleCost()) / alg.cycleSize();
+ /// \endcode
+ ///
+ /// \pre \ref run() or \ref findCycleMean() must be called before
+ /// using this function.
+ double cycleMean() const {
+ return static_cast<double>(_best_cost) / _best_size;
+ }
+
+ /// \brief Return the found cycle.
+ ///
+ /// This function returns a const reference to the path structure
+ /// storing the found cycle.
+ ///
+ /// \pre \ref run() or \ref findCycle() must be called before using
+ /// this function.
+ const Path& cycle() const {
+ return *_cycle_path;
+ }
+
+ ///@}
+
+ private:
+
+ // Initialization
+ void init() {
+ if (!_cycle_path) {
+ _local_path = true;
+ _cycle_path = new Path;
+ }
+ _cycle_path->clear();
+ _best_found = false;
+ _best_cost = 0;
+ _best_size = 1;
+ _cycle_path->clear();
+ for (NodeIt u(_gr); u != INVALID; ++u)
+ _data[u].clear();
+ }
+
+ // Find strongly connected components and initialize _comp_nodes
+ // and _out_arcs
+ void findComponents() {
+ _comp_num = stronglyConnectedComponents(_gr, _comp);
+ _comp_nodes.resize(_comp_num);
+ if (_comp_num == 1) {
+ _comp_nodes[0].clear();
+ for (NodeIt n(_gr); n != INVALID; ++n) {
+ _comp_nodes[0].push_back(n);
+ _out_arcs[n].clear();
+ for (OutArcIt a(_gr, n); a != INVALID; ++a) {
+ _out_arcs[n].push_back(a);
+ }
+ }
+ } else {
+ for (int i = 0; i < _comp_num; ++i)
+ _comp_nodes[i].clear();
+ for (NodeIt n(_gr); n != INVALID; ++n) {
+ int k = _comp[n];
+ _comp_nodes[k].push_back(n);
+ _out_arcs[n].clear();
+ for (OutArcIt a(_gr, n); a != INVALID; ++a) {
+ if (_comp[_gr.target(a)] == k) _out_arcs[n].push_back(a);
+ }
+ }
+ }
+ }
+
+ // Initialize path data for the current component
+ bool initComponent(int comp) {
+ _nodes = &(_comp_nodes[comp]);
+ int n = _nodes->size();
+ if (n < 1 || (n == 1 && _out_arcs[(*_nodes)[0]].size() == 0)) {
+ return false;
+ }
+ for (int i = 0; i < n; ++i) {
+ _data[(*_nodes)[i]].resize(n + 1, PathData(INF));
+ }
+ return true;
+ }
+
+ // Process all rounds of computing path data for the current component.
+ // _data[v][k] is the cost of a shortest directed walk from the root
+ // node to node v containing exactly k arcs.
+ void processRounds() {
+ Node start = (*_nodes)[0];
+ _data[start][0] = PathData(0);
+ _process.clear();
+ _process.push_back(start);
+
+ int k, n = _nodes->size();
+ int next_check = 4;
+ bool terminate = false;
+ for (k = 1; k <= n && int(_process.size()) < n && !terminate; ++k) {
+ processNextBuildRound(k);
+ if (k == next_check || k == n) {
+ terminate = checkTermination(k);
+ next_check = next_check * 3 / 2;
+ }
+ }
+ for ( ; k <= n && !terminate; ++k) {
+ processNextFullRound(k);
+ if (k == next_check || k == n) {
+ terminate = checkTermination(k);
+ next_check = next_check * 3 / 2;
+ }
+ }
+ }
+
+ // Process one round and rebuild _process
+ void processNextBuildRound(int k) {
+ std::vector<Node> next;
+ Node u, v;
+ Arc e;
+ LargeCost d;
+ for (int i = 0; i < int(_process.size()); ++i) {
+ u = _process[i];
+ for (int j = 0; j < int(_out_arcs[u].size()); ++j) {
+ e = _out_arcs[u][j];
+ v = _gr.target(e);
+ d = _data[u][k-1].dist + _cost[e];
+ if (_tolerance.less(d, _data[v][k].dist)) {
+ if (_data[v][k].dist == INF) next.push_back(v);
+ _data[v][k] = PathData(d, e);
+ }
+ }
+ }
+ _process.swap(next);
+ }
+
+ // Process one round using _nodes instead of _process
+ void processNextFullRound(int k) {
+ Node u, v;
+ Arc e;
+ LargeCost d;
+ for (int i = 0; i < int(_nodes->size()); ++i) {
+ u = (*_nodes)[i];
+ for (int j = 0; j < int(_out_arcs[u].size()); ++j) {
+ e = _out_arcs[u][j];
+ v = _gr.target(e);
+ d = _data[u][k-1].dist + _cost[e];
+ if (_tolerance.less(d, _data[v][k].dist)) {
+ _data[v][k] = PathData(d, e);
+ }
+ }
+ }
+ }
+
+ // Check early termination
+ bool checkTermination(int k) {
+ typedef std::pair<int, int> Pair;
+ typename GR::template NodeMap<Pair> level(_gr, Pair(-1, 0));
+ typename GR::template NodeMap<LargeCost> pi(_gr);
+ int n = _nodes->size();
+ LargeCost cost;
+ int size;
+ Node u;
+
+ // Search for cycles that are already found
+ _curr_found = false;
+ for (int i = 0; i < n; ++i) {
+ u = (*_nodes)[i];
+ if (_data[u][k].dist == INF) continue;
+ for (int j = k; j >= 0; --j) {
+ if (level[u].first == i && level[u].second > 0) {
+ // A cycle is found
+ cost = _data[u][level[u].second].dist - _data[u][j].dist;
+ size = level[u].second - j;
+ if (!_curr_found || cost * _curr_size < _curr_cost * size) {
+ _curr_cost = cost;
+ _curr_size = size;
+ _curr_node = u;
+ _curr_level = level[u].second;
+ _curr_found = true;
+ }
+ }
+ level[u] = Pair(i, j);
+ if (j != 0) {
+ u = _gr.source(_data[u][j].pred);
+ }
+ }
+ }
+
+ // If at least one cycle is found, check the optimality condition
+ LargeCost d;
+ if (_curr_found && k < n) {
+ // Find node potentials
+ for (int i = 0; i < n; ++i) {
+ u = (*_nodes)[i];
+ pi[u] = INF;
+ for (int j = 0; j <= k; ++j) {
+ if (_data[u][j].dist < INF) {
+ d = _data[u][j].dist * _curr_size - j * _curr_cost;
+ if (_tolerance.less(d, pi[u])) pi[u] = d;
+ }
+ }
+ }
+
+ // Check the optimality condition for all arcs
+ bool done = true;
+ for (ArcIt a(_gr); a != INVALID; ++a) {
+ if (_tolerance.less(_cost[a] * _curr_size - _curr_cost,
+ pi[_gr.target(a)] - pi[_gr.source(a)]) ) {
+ done = false;
+ break;
+ }
+ }
+ return done;
+ }
+ return (k == n);
+ }
+
+ }; //class HartmannOrlinMmc
+
+ ///@}
+
+} //namespace lemon
+
+#endif //LEMON_HARTMANN_ORLIN_MMC_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/howard_mmc.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/howard_mmc.h
new file mode 100644
index 00000000000..690236340ff
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/howard_mmc.h
@@ -0,0 +1,651 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_HOWARD_MMC_H
+#define LEMON_HOWARD_MMC_H
+
+/// \ingroup min_mean_cycle
+///
+/// \file
+/// \brief Howard's algorithm for finding a minimum mean cycle.
+
+#include <vector>
+#include <limits>
+#include <lemon/core.h>
+#include <lemon/path.h>
+#include <lemon/tolerance.h>
+#include <lemon/connectivity.h>
+
+namespace lemon {
+
+ /// \brief Default traits class of HowardMmc class.
+ ///
+ /// Default traits class of HowardMmc class.
+ /// \tparam GR The type of the digraph.
+ /// \tparam CM The type of the cost map.
+ /// It must conform to the \ref concepts::ReadMap "ReadMap" concept.
+#ifdef DOXYGEN
+ template <typename GR, typename CM>
+#else
+ template <typename GR, typename CM,
+ bool integer = std::numeric_limits<typename CM::Value>::is_integer>
+#endif
+ struct HowardMmcDefaultTraits
+ {
+ /// The type of the digraph
+ typedef GR Digraph;
+ /// The type of the cost map
+ typedef CM CostMap;
+ /// The type of the arc costs
+ typedef typename CostMap::Value Cost;
+
+ /// \brief The large cost type used for internal computations
+ ///
+ /// The large cost type used for internal computations.
+ /// It is \c long \c long if the \c Cost type is integer,
+ /// otherwise it is \c double.
+ /// \c Cost must be convertible to \c LargeCost.
+ typedef double LargeCost;
+
+ /// The tolerance type used for internal computations
+ typedef lemon::Tolerance<LargeCost> Tolerance;
+
+ /// \brief The path type of the found cycles
+ ///
+ /// The path type of the found cycles.
+ /// It must conform to the \ref lemon::concepts::Path "Path" concept
+ /// and it must have an \c addBack() function.
+ typedef lemon::Path<Digraph> Path;
+ };
+
+ // Default traits class for integer cost types
+ template <typename GR, typename CM>
+ struct HowardMmcDefaultTraits<GR, CM, true>
+ {
+ typedef GR Digraph;
+ typedef CM CostMap;
+ typedef typename CostMap::Value Cost;
+#ifdef LEMON_HAVE_LONG_LONG
+ typedef long long LargeCost;
+#else
+ typedef long LargeCost;
+#endif
+ typedef lemon::Tolerance<LargeCost> Tolerance;
+ typedef lemon::Path<Digraph> Path;
+ };
+
+
+ /// \addtogroup min_mean_cycle
+ /// @{
+
+ /// \brief Implementation of Howard's algorithm for finding a minimum
+ /// mean cycle.
+ ///
+ /// This class implements Howard's policy iteration algorithm for finding
+ /// a directed cycle of minimum mean cost in a digraph
+ /// \cite dasdan98minmeancycle, \cite dasdan04experimental.
+ /// This class provides the most efficient algorithm for the
+ /// minimum mean cycle problem, though the best known theoretical
+ /// bound on its running time is exponential.
+ ///
+ /// \tparam GR The type of the digraph the algorithm runs on.
+ /// \tparam CM The type of the cost map. The default
+ /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap<int>".
+ /// \tparam TR The traits class that defines various types used by the
+ /// algorithm. By default, it is \ref HowardMmcDefaultTraits
+ /// "HowardMmcDefaultTraits<GR, CM>".
+ /// In most cases, this parameter should not be set directly,
+ /// consider to use the named template parameters instead.
+#ifdef DOXYGEN
+ template <typename GR, typename CM, typename TR>
+#else
+ template < typename GR,
+ typename CM = typename GR::template ArcMap<int>,
+ typename TR = HowardMmcDefaultTraits<GR, CM> >
+#endif
+ class HowardMmc
+ {
+ public:
+
+ /// The type of the digraph
+ typedef typename TR::Digraph Digraph;
+ /// The type of the cost map
+ typedef typename TR::CostMap CostMap;
+ /// The type of the arc costs
+ typedef typename TR::Cost Cost;
+
+ /// \brief The large cost type
+ ///
+ /// The large cost type used for internal computations.
+ /// By default, it is \c long \c long if the \c Cost type is integer,
+ /// otherwise it is \c double.
+ typedef typename TR::LargeCost LargeCost;
+
+ /// The tolerance type
+ typedef typename TR::Tolerance Tolerance;
+
+ /// \brief The path type of the found cycles
+ ///
+ /// The path type of the found cycles.
+ /// Using the \ref lemon::HowardMmcDefaultTraits "default traits class",
+ /// it is \ref lemon::Path "Path<Digraph>".
+ typedef typename TR::Path Path;
+
+ /// The \ref lemon::HowardMmcDefaultTraits "traits class" of the algorithm
+ typedef TR Traits;
+
+ /// \brief Constants for the causes of search termination.
+ ///
+ /// Enum type containing constants for the different causes of search
+ /// termination. The \ref findCycleMean() function returns one of
+ /// these values.
+ enum TerminationCause {
+
+ /// No directed cycle can be found in the digraph.
+ NO_CYCLE = 0,
+
+ /// Optimal solution (minimum cycle mean) is found.
+ OPTIMAL = 1,
+
+ /// The iteration count limit is reached.
+ ITERATION_LIMIT
+ };
+
+ private:
+
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+
+ // The digraph the algorithm runs on
+ const Digraph &_gr;
+ // The cost of the arcs
+ const CostMap &_cost;
+
+ // Data for the found cycles
+ bool _curr_found, _best_found;
+ LargeCost _curr_cost, _best_cost;
+ int _curr_size, _best_size;
+ Node _curr_node, _best_node;
+
+ Path *_cycle_path;
+ bool _local_path;
+
+ // Internal data used by the algorithm
+ typename Digraph::template NodeMap<Arc> _policy;
+ typename Digraph::template NodeMap<bool> _reached;
+ typename Digraph::template NodeMap<int> _level;
+ typename Digraph::template NodeMap<LargeCost> _dist;
+
+ // Data for storing the strongly connected components
+ int _comp_num;
+ typename Digraph::template NodeMap<int> _comp;
+ std::vector<std::vector<Node> > _comp_nodes;
+ std::vector<Node>* _nodes;
+ typename Digraph::template NodeMap<std::vector<Arc> > _in_arcs;
+
+ // Queue used for BFS search
+ std::vector<Node> _queue;
+ int _qfront, _qback;
+
+ Tolerance _tolerance;
+
+ // Infinite constant
+ const LargeCost INF;
+
+ public:
+
+ /// \name Named Template Parameters
+ /// @{
+
+ template <typename T>
+ struct SetLargeCostTraits : public Traits {
+ typedef T LargeCost;
+ typedef lemon::Tolerance<T> Tolerance;
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// \c LargeCost type.
+ ///
+ /// \ref named-templ-param "Named parameter" for setting \c LargeCost
+ /// type. It is used for internal computations in the algorithm.
+ template <typename T>
+ struct SetLargeCost
+ : public HowardMmc<GR, CM, SetLargeCostTraits<T> > {
+ typedef HowardMmc<GR, CM, SetLargeCostTraits<T> > Create;
+ };
+
+ template <typename T>
+ struct SetPathTraits : public Traits {
+ typedef T Path;
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// \c %Path type.
+ ///
+ /// \ref named-templ-param "Named parameter" for setting the \c %Path
+ /// type of the found cycles.
+ /// It must conform to the \ref lemon::concepts::Path "Path" concept
+ /// and it must have an \c addBack() function.
+ template <typename T>
+ struct SetPath
+ : public HowardMmc<GR, CM, SetPathTraits<T> > {
+ typedef HowardMmc<GR, CM, SetPathTraits<T> > Create;
+ };
+
+ /// @}
+
+ protected:
+
+ HowardMmc() {}
+
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// The constructor of the class.
+ ///
+ /// \param digraph The digraph the algorithm runs on.
+ /// \param cost The costs of the arcs.
+ HowardMmc( const Digraph &digraph,
+ const CostMap &cost ) :
+ _gr(digraph), _cost(cost), _best_found(false),
+ _best_cost(0), _best_size(1), _cycle_path(NULL), _local_path(false),
+ _policy(digraph), _reached(digraph), _level(digraph), _dist(digraph),
+ _comp(digraph), _in_arcs(digraph),
+ INF(std::numeric_limits<LargeCost>::has_infinity ?
+ std::numeric_limits<LargeCost>::infinity() :
+ std::numeric_limits<LargeCost>::max())
+ {}
+
+ /// Destructor.
+ ~HowardMmc() {
+ if (_local_path) delete _cycle_path;
+ }
+
+ /// \brief Set the path structure for storing the found cycle.
+ ///
+ /// This function sets an external path structure for storing the
+ /// found cycle.
+ ///
+ /// If you don't call this function before calling \ref run() or
+ /// \ref findCycleMean(), a local \ref Path "path" structure
+ /// will be allocated. The destuctor deallocates this automatically
+ /// allocated object, of course.
+ ///
+ /// \note The algorithm calls only the \ref lemon::Path::addBack()
+ /// "addBack()" function of the given path structure.
+ ///
+ /// \return <tt>(*this)</tt>
+ HowardMmc& cycle(Path &path) {
+ if (_local_path) {
+ delete _cycle_path;
+ _local_path = false;
+ }
+ _cycle_path = &path;
+ return *this;
+ }
+
+ /// \brief Set the tolerance used by the algorithm.
+ ///
+ /// This function sets the tolerance object used by the algorithm.
+ ///
+ /// \return <tt>(*this)</tt>
+ HowardMmc& tolerance(const Tolerance& tolerance) {
+ _tolerance = tolerance;
+ return *this;
+ }
+
+ /// \brief Return a const reference to the tolerance.
+ ///
+ /// This function returns a const reference to the tolerance object
+ /// used by the algorithm.
+ const Tolerance& tolerance() const {
+ return _tolerance;
+ }
+
+ /// \name Execution control
+ /// The simplest way to execute the algorithm is to call the \ref run()
+ /// function.\n
+ /// If you only need the minimum mean cost, you may call
+ /// \ref findCycleMean().
+
+ /// @{
+
+ /// \brief Run the algorithm.
+ ///
+ /// This function runs the algorithm.
+ /// It can be called more than once (e.g. if the underlying digraph
+ /// and/or the arc costs have been modified).
+ ///
+ /// \return \c true if a directed cycle exists in the digraph.
+ ///
+ /// \note <tt>mmc.run()</tt> is just a shortcut of the following code.
+ /// \code
+ /// return mmc.findCycleMean() && mmc.findCycle();
+ /// \endcode
+ bool run() {
+ return findCycleMean() && findCycle();
+ }
+
+ /// \brief Find the minimum cycle mean (or an upper bound).
+ ///
+ /// This function finds the minimum mean cost of the directed
+ /// cycles in the digraph (or an upper bound for it).
+ ///
+ /// By default, the function finds the exact minimum cycle mean,
+ /// but an optional limit can also be specified for the number of
+ /// iterations performed during the search process.
+ /// The return value indicates if the optimal solution is found
+ /// or the iteration limit is reached. In the latter case, an
+ /// approximate solution is provided, which corresponds to a directed
+ /// cycle whose mean cost is relatively small, but not necessarily
+ /// minimal.
+ ///
+ /// \param limit The maximum allowed number of iterations during
+ /// the search process. Its default value implies that the algorithm
+ /// runs until it finds the exact optimal solution.
+ ///
+ /// \return The termination cause of the search process.
+ /// For more information, see \ref TerminationCause.
+ TerminationCause findCycleMean(int limit =
+ std::numeric_limits<int>::max()) {
+ // Initialize and find strongly connected components
+ init();
+ findComponents();
+
+ // Find the minimum cycle mean in the components
+ int iter_count = 0;
+ bool iter_limit_reached = false;
+ for (int comp = 0; comp < _comp_num; ++comp) {
+ // Find the minimum mean cycle in the current component
+ if (!buildPolicyGraph(comp)) continue;
+ while (true) {
+ if (++iter_count > limit) {
+ iter_limit_reached = true;
+ break;
+ }
+ findPolicyCycle();
+ if (!computeNodeDistances()) break;
+ }
+
+ // Update the best cycle (global minimum mean cycle)
+ if ( _curr_found && (!_best_found ||
+ _curr_cost * _best_size < _best_cost * _curr_size) ) {
+ _best_found = true;
+ _best_cost = _curr_cost;
+ _best_size = _curr_size;
+ _best_node = _curr_node;
+ }
+
+ if (iter_limit_reached) break;
+ }
+
+ if (iter_limit_reached) {
+ return ITERATION_LIMIT;
+ } else {
+ return _best_found ? OPTIMAL : NO_CYCLE;
+ }
+ }
+
+ /// \brief Find a minimum mean directed cycle.
+ ///
+ /// This function finds a directed cycle of minimum mean cost
+ /// in the digraph using the data computed by findCycleMean().
+ ///
+ /// \return \c true if a directed cycle exists in the digraph.
+ ///
+ /// \pre \ref findCycleMean() must be called before using this function.
+ bool findCycle() {
+ if (!_best_found) return false;
+ _cycle_path->addBack(_policy[_best_node]);
+ for ( Node v = _best_node;
+ (v = _gr.target(_policy[v])) != _best_node; ) {
+ _cycle_path->addBack(_policy[v]);
+ }
+ return true;
+ }
+
+ /// @}
+
+ /// \name Query Functions
+ /// The results of the algorithm can be obtained using these
+ /// functions.\n
+ /// The algorithm should be executed before using them.
+
+ /// @{
+
+ /// \brief Return the total cost of the found cycle.
+ ///
+ /// This function returns the total cost of the found cycle.
+ ///
+ /// \pre \ref run() or \ref findCycleMean() must be called before
+ /// using this function.
+ Cost cycleCost() const {
+ return static_cast<Cost>(_best_cost);
+ }
+
+ /// \brief Return the number of arcs on the found cycle.
+ ///
+ /// This function returns the number of arcs on the found cycle.
+ ///
+ /// \pre \ref run() or \ref findCycleMean() must be called before
+ /// using this function.
+ int cycleSize() const {
+ return _best_size;
+ }
+
+ /// \brief Return the mean cost of the found cycle.
+ ///
+ /// This function returns the mean cost of the found cycle.
+ ///
+ /// \note <tt>alg.cycleMean()</tt> is just a shortcut of the
+ /// following code.
+ /// \code
+ /// return static_cast<double>(alg.cycleCost()) / alg.cycleSize();
+ /// \endcode
+ ///
+ /// \pre \ref run() or \ref findCycleMean() must be called before
+ /// using this function.
+ double cycleMean() const {
+ return static_cast<double>(_best_cost) / _best_size;
+ }
+
+ /// \brief Return the found cycle.
+ ///
+ /// This function returns a const reference to the path structure
+ /// storing the found cycle.
+ ///
+ /// \pre \ref run() or \ref findCycle() must be called before using
+ /// this function.
+ const Path& cycle() const {
+ return *_cycle_path;
+ }
+
+ ///@}
+
+ private:
+
+ // Initialize
+ void init() {
+ if (!_cycle_path) {
+ _local_path = true;
+ _cycle_path = new Path;
+ }
+ _queue.resize(countNodes(_gr));
+ _best_found = false;
+ _best_cost = 0;
+ _best_size = 1;
+ _cycle_path->clear();
+ }
+
+ // Find strongly connected components and initialize _comp_nodes
+ // and _in_arcs
+ void findComponents() {
+ _comp_num = stronglyConnectedComponents(_gr, _comp);
+ _comp_nodes.resize(_comp_num);
+ if (_comp_num == 1) {
+ _comp_nodes[0].clear();
+ for (NodeIt n(_gr); n != INVALID; ++n) {
+ _comp_nodes[0].push_back(n);
+ _in_arcs[n].clear();
+ for (InArcIt a(_gr, n); a != INVALID; ++a) {
+ _in_arcs[n].push_back(a);
+ }
+ }
+ } else {
+ for (int i = 0; i < _comp_num; ++i)
+ _comp_nodes[i].clear();
+ for (NodeIt n(_gr); n != INVALID; ++n) {
+ int k = _comp[n];
+ _comp_nodes[k].push_back(n);
+ _in_arcs[n].clear();
+ for (InArcIt a(_gr, n); a != INVALID; ++a) {
+ if (_comp[_gr.source(a)] == k) _in_arcs[n].push_back(a);
+ }
+ }
+ }
+ }
+
+ // Build the policy graph in the given strongly connected component
+ // (the out-degree of every node is 1)
+ bool buildPolicyGraph(int comp) {
+ _nodes = &(_comp_nodes[comp]);
+ if (_nodes->size() < 1 ||
+ (_nodes->size() == 1 && _in_arcs[(*_nodes)[0]].size() == 0)) {
+ return false;
+ }
+ for (int i = 0; i < int(_nodes->size()); ++i) {
+ _dist[(*_nodes)[i]] = INF;
+ }
+ Node u, v;
+ Arc e;
+ for (int i = 0; i < int(_nodes->size()); ++i) {
+ v = (*_nodes)[i];
+ for (int j = 0; j < int(_in_arcs[v].size()); ++j) {
+ e = _in_arcs[v][j];
+ u = _gr.source(e);
+ if (_cost[e] < _dist[u]) {
+ _dist[u] = _cost[e];
+ _policy[u] = e;
+ }
+ }
+ }
+ return true;
+ }
+
+ // Find the minimum mean cycle in the policy graph
+ void findPolicyCycle() {
+ for (int i = 0; i < int(_nodes->size()); ++i) {
+ _level[(*_nodes)[i]] = -1;
+ }
+ LargeCost ccost;
+ int csize;
+ Node u, v;
+ _curr_found = false;
+ for (int i = 0; i < int(_nodes->size()); ++i) {
+ u = (*_nodes)[i];
+ if (_level[u] >= 0) continue;
+ for (; _level[u] < 0; u = _gr.target(_policy[u])) {
+ _level[u] = i;
+ }
+ if (_level[u] == i) {
+ // A cycle is found
+ ccost = _cost[_policy[u]];
+ csize = 1;
+ for (v = u; (v = _gr.target(_policy[v])) != u; ) {
+ ccost += _cost[_policy[v]];
+ ++csize;
+ }
+ if ( !_curr_found ||
+ (ccost * _curr_size < _curr_cost * csize) ) {
+ _curr_found = true;
+ _curr_cost = ccost;
+ _curr_size = csize;
+ _curr_node = u;
+ }
+ }
+ }
+ }
+
+ // Contract the policy graph and compute node distances
+ bool computeNodeDistances() {
+ // Find the component of the main cycle and compute node distances
+ // using reverse BFS
+ for (int i = 0; i < int(_nodes->size()); ++i) {
+ _reached[(*_nodes)[i]] = false;
+ }
+ _qfront = _qback = 0;
+ _queue[0] = _curr_node;
+ _reached[_curr_node] = true;
+ _dist[_curr_node] = 0;
+ Node u, v;
+ Arc e;
+ while (_qfront <= _qback) {
+ v = _queue[_qfront++];
+ for (int j = 0; j < int(_in_arcs[v].size()); ++j) {
+ e = _in_arcs[v][j];
+ u = _gr.source(e);
+ if (_policy[u] == e && !_reached[u]) {
+ _reached[u] = true;
+ _dist[u] = _dist[v] + _cost[e] * _curr_size - _curr_cost;
+ _queue[++_qback] = u;
+ }
+ }
+ }
+
+ // Connect all other nodes to this component and compute node
+ // distances using reverse BFS
+ _qfront = 0;
+ while (_qback < int(_nodes->size())-1) {
+ v = _queue[_qfront++];
+ for (int j = 0; j < int(_in_arcs[v].size()); ++j) {
+ e = _in_arcs[v][j];
+ u = _gr.source(e);
+ if (!_reached[u]) {
+ _reached[u] = true;
+ _policy[u] = e;
+ _dist[u] = _dist[v] + _cost[e] * _curr_size - _curr_cost;
+ _queue[++_qback] = u;
+ }
+ }
+ }
+
+ // Improve node distances
+ bool improved = false;
+ for (int i = 0; i < int(_nodes->size()); ++i) {
+ v = (*_nodes)[i];
+ for (int j = 0; j < int(_in_arcs[v].size()); ++j) {
+ e = _in_arcs[v][j];
+ u = _gr.source(e);
+ LargeCost delta = _dist[v] + _cost[e] * _curr_size - _curr_cost;
+ if (_tolerance.less(delta, _dist[u])) {
+ _dist[u] = delta;
+ _policy[u] = e;
+ improved = true;
+ }
+ }
+ }
+ return improved;
+ }
+
+ }; //class HowardMmc
+
+ ///@}
+
+} //namespace lemon
+
+#endif //LEMON_HOWARD_MMC_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/hypercube_graph.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/hypercube_graph.h
new file mode 100644
index 00000000000..2cf37ad49d2
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/hypercube_graph.h
@@ -0,0 +1,459 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef HYPERCUBE_GRAPH_H
+#define HYPERCUBE_GRAPH_H
+
+#include <vector>
+#include <lemon/core.h>
+#include <lemon/assert.h>
+#include <lemon/bits/graph_extender.h>
+
+///\ingroup graphs
+///\file
+///\brief HypercubeGraph class.
+
+namespace lemon {
+
+ class HypercubeGraphBase {
+
+ public:
+
+ typedef HypercubeGraphBase Graph;
+
+ class Node;
+ class Edge;
+ class Arc;
+
+ public:
+
+ HypercubeGraphBase() {}
+
+ protected:
+
+ void construct(int dim) {
+ LEMON_ASSERT(dim >= 1, "The number of dimensions must be at least 1.");
+ _dim = dim;
+ _node_num = 1 << dim;
+ _edge_num = dim * (1 << (dim-1));
+ }
+
+ public:
+
+ typedef True NodeNumTag;
+ typedef True EdgeNumTag;
+ typedef True ArcNumTag;
+
+ int nodeNum() const { return _node_num; }
+ int edgeNum() const { return _edge_num; }
+ int arcNum() const { return 2 * _edge_num; }
+
+ int maxNodeId() const { return _node_num - 1; }
+ int maxEdgeId() const { return _edge_num - 1; }
+ int maxArcId() const { return 2 * _edge_num - 1; }
+
+ static Node nodeFromId(int id) { return Node(id); }
+ static Edge edgeFromId(int id) { return Edge(id); }
+ static Arc arcFromId(int id) { return Arc(id); }
+
+ static int id(Node node) { return node._id; }
+ static int id(Edge edge) { return edge._id; }
+ static int id(Arc arc) { return arc._id; }
+
+ Node u(Edge edge) const {
+ int base = edge._id & ((1 << (_dim-1)) - 1);
+ int k = edge._id >> (_dim-1);
+ return ((base >> k) << (k+1)) | (base & ((1 << k) - 1));
+ }
+
+ Node v(Edge edge) const {
+ int base = edge._id & ((1 << (_dim-1)) - 1);
+ int k = edge._id >> (_dim-1);
+ return ((base >> k) << (k+1)) | (base & ((1 << k) - 1)) | (1 << k);
+ }
+
+ Node source(Arc arc) const {
+ return (arc._id & 1) == 1 ? u(arc) : v(arc);
+ }
+
+ Node target(Arc arc) const {
+ return (arc._id & 1) == 1 ? v(arc) : u(arc);
+ }
+
+ typedef True FindEdgeTag;
+ typedef True FindArcTag;
+
+ Edge findEdge(Node u, Node v, Edge prev = INVALID) const {
+ if (prev != INVALID) return INVALID;
+ int d = u._id ^ v._id;
+ int k = 0;
+ if (d == 0) return INVALID;
+ for ( ; (d & 1) == 0; d >>= 1) ++k;
+ if (d >> 1 != 0) return INVALID;
+ return (k << (_dim-1)) | ((u._id >> (k+1)) << k) |
+ (u._id & ((1 << k) - 1));
+ }
+
+ Arc findArc(Node u, Node v, Arc prev = INVALID) const {
+ Edge edge = findEdge(u, v, prev);
+ if (edge == INVALID) return INVALID;
+ int k = edge._id >> (_dim-1);
+ return ((u._id >> k) & 1) == 1 ? edge._id << 1 : (edge._id << 1) | 1;
+ }
+
+ class Node {
+ friend class HypercubeGraphBase;
+
+ protected:
+ int _id;
+ Node(int id) : _id(id) {}
+ public:
+ Node() {}
+ Node (Invalid) : _id(-1) {}
+ bool operator==(const Node node) const {return _id == node._id;}
+ bool operator!=(const Node node) const {return _id != node._id;}
+ bool operator<(const Node node) const {return _id < node._id;}
+ };
+
+ class Edge {
+ friend class HypercubeGraphBase;
+ friend class Arc;
+
+ protected:
+ int _id;
+
+ Edge(int id) : _id(id) {}
+
+ public:
+ Edge() {}
+ Edge (Invalid) : _id(-1) {}
+ bool operator==(const Edge edge) const {return _id == edge._id;}
+ bool operator!=(const Edge edge) const {return _id != edge._id;}
+ bool operator<(const Edge edge) const {return _id < edge._id;}
+ };
+
+ class Arc {
+ friend class HypercubeGraphBase;
+
+ protected:
+ int _id;
+
+ Arc(int id) : _id(id) {}
+
+ public:
+ Arc() {}
+ Arc (Invalid) : _id(-1) {}
+ operator Edge() const { return _id != -1 ? Edge(_id >> 1) : INVALID; }
+ bool operator==(const Arc arc) const {return _id == arc._id;}
+ bool operator!=(const Arc arc) const {return _id != arc._id;}
+ bool operator<(const Arc arc) const {return _id < arc._id;}
+ };
+
+ void first(Node& node) const {
+ node._id = _node_num - 1;
+ }
+
+ static void next(Node& node) {
+ --node._id;
+ }
+
+ void first(Edge& edge) const {
+ edge._id = _edge_num - 1;
+ }
+
+ static void next(Edge& edge) {
+ --edge._id;
+ }
+
+ void first(Arc& arc) const {
+ arc._id = 2 * _edge_num - 1;
+ }
+
+ static void next(Arc& arc) {
+ --arc._id;
+ }
+
+ void firstInc(Edge& edge, bool& dir, const Node& node) const {
+ edge._id = node._id >> 1;
+ dir = (node._id & 1) == 0;
+ }
+
+ void nextInc(Edge& edge, bool& dir) const {
+ Node n = dir ? u(edge) : v(edge);
+ int k = (edge._id >> (_dim-1)) + 1;
+ if (k < _dim) {
+ edge._id = (k << (_dim-1)) |
+ ((n._id >> (k+1)) << k) | (n._id & ((1 << k) - 1));
+ dir = ((n._id >> k) & 1) == 0;
+ } else {
+ edge._id = -1;
+ dir = true;
+ }
+ }
+
+ void firstOut(Arc& arc, const Node& node) const {
+ arc._id = ((node._id >> 1) << 1) | (~node._id & 1);
+ }
+
+ void nextOut(Arc& arc) const {
+ Node n = (arc._id & 1) == 1 ? u(arc) : v(arc);
+ int k = (arc._id >> _dim) + 1;
+ if (k < _dim) {
+ arc._id = (k << (_dim-1)) |
+ ((n._id >> (k+1)) << k) | (n._id & ((1 << k) - 1));
+ arc._id = (arc._id << 1) | (~(n._id >> k) & 1);
+ } else {
+ arc._id = -1;
+ }
+ }
+
+ void firstIn(Arc& arc, const Node& node) const {
+ arc._id = ((node._id >> 1) << 1) | (node._id & 1);
+ }
+
+ void nextIn(Arc& arc) const {
+ Node n = (arc._id & 1) == 1 ? v(arc) : u(arc);
+ int k = (arc._id >> _dim) + 1;
+ if (k < _dim) {
+ arc._id = (k << (_dim-1)) |
+ ((n._id >> (k+1)) << k) | (n._id & ((1 << k) - 1));
+ arc._id = (arc._id << 1) | ((n._id >> k) & 1);
+ } else {
+ arc._id = -1;
+ }
+ }
+
+ static bool direction(Arc arc) {
+ return (arc._id & 1) == 1;
+ }
+
+ static Arc direct(Edge edge, bool dir) {
+ return Arc((edge._id << 1) | (dir ? 1 : 0));
+ }
+
+ int dimension() const {
+ return _dim;
+ }
+
+ bool projection(Node node, int n) const {
+ return static_cast<bool>(node._id & (1 << n));
+ }
+
+ int dimension(Edge edge) const {
+ return edge._id >> (_dim-1);
+ }
+
+ int dimension(Arc arc) const {
+ return arc._id >> _dim;
+ }
+
+ static int index(Node node) {
+ return node._id;
+ }
+
+ Node operator()(int ix) const {
+ return Node(ix);
+ }
+
+ private:
+ int _dim;
+ int _node_num, _edge_num;
+ };
+
+
+ typedef GraphExtender<HypercubeGraphBase> ExtendedHypercubeGraphBase;
+
+ /// \ingroup graphs
+ ///
+ /// \brief Hypercube graph class
+ ///
+ /// HypercubeGraph implements a special graph type. The nodes of the
+ /// graph are indexed with integers having at most \c dim binary digits.
+ /// Two nodes are connected in the graph if and only if their indices
+ /// differ only on one position in the binary form.
+ /// This class is completely static and it needs constant memory space.
+ /// Thus you can neither add nor delete nodes or edges, however,
+ /// the structure can be resized using resize().
+ ///
+ /// This type fully conforms to the \ref concepts::Graph "Graph concept".
+ /// Most of its member functions and nested classes are documented
+ /// only in the concept class.
+ ///
+ /// This class provides constant time counting for nodes, edges and arcs.
+ ///
+ /// \note The type of the indices is chosen to \c int for efficiency
+ /// reasons. Thus the maximum dimension of this implementation is 26
+ /// (assuming that the size of \c int is 32 bit).
+ class HypercubeGraph : public ExtendedHypercubeGraphBase {
+ typedef ExtendedHypercubeGraphBase Parent;
+
+ public:
+
+ /// \brief Constructs a hypercube graph with \c dim dimensions.
+ ///
+ /// Constructs a hypercube graph with \c dim dimensions.
+ HypercubeGraph(int dim) { construct(dim); }
+
+ /// \brief Resizes the graph
+ ///
+ /// This function resizes the graph. It fully destroys and
+ /// rebuilds the structure, therefore the maps of the graph will be
+ /// reallocated automatically and the previous values will be lost.
+ void resize(int dim) {
+ Parent::notifier(Arc()).clear();
+ Parent::notifier(Edge()).clear();
+ Parent::notifier(Node()).clear();
+ construct(dim);
+ Parent::notifier(Node()).build();
+ Parent::notifier(Edge()).build();
+ Parent::notifier(Arc()).build();
+ }
+
+ /// \brief The number of dimensions.
+ ///
+ /// Gives back the number of dimensions.
+ int dimension() const {
+ return Parent::dimension();
+ }
+
+ /// \brief Returns \c true if the n'th bit of the node is one.
+ ///
+ /// Returns \c true if the n'th bit of the node is one.
+ bool projection(Node node, int n) const {
+ return Parent::projection(node, n);
+ }
+
+ /// \brief The dimension id of an edge.
+ ///
+ /// Gives back the dimension id of the given edge.
+ /// It is in the range <tt>[0..dim-1]</tt>.
+ int dimension(Edge edge) const {
+ return Parent::dimension(edge);
+ }
+
+ /// \brief The dimension id of an arc.
+ ///
+ /// Gives back the dimension id of the given arc.
+ /// It is in the range <tt>[0..dim-1]</tt>.
+ int dimension(Arc arc) const {
+ return Parent::dimension(arc);
+ }
+
+ /// \brief The index of a node.
+ ///
+ /// Gives back the index of the given node.
+ /// The lower bits of the integer describes the node.
+ static int index(Node node) {
+ return Parent::index(node);
+ }
+
+ /// \brief Gives back a node by its index.
+ ///
+ /// Gives back a node by its index.
+ Node operator()(int ix) const {
+ return Parent::operator()(ix);
+ }
+
+ /// \brief Number of nodes.
+ int nodeNum() const { return Parent::nodeNum(); }
+ /// \brief Number of edges.
+ int edgeNum() const { return Parent::edgeNum(); }
+ /// \brief Number of arcs.
+ int arcNum() const { return Parent::arcNum(); }
+
+ /// \brief Linear combination map.
+ ///
+ /// This map makes possible to give back a linear combination
+ /// for each node. It works like the \c std::accumulate function,
+ /// so it accumulates the \c bf binary function with the \c fv first
+ /// value. The map accumulates only on that positions (dimensions)
+ /// where the index of the node is one. The values that have to be
+ /// accumulated should be given by the \c begin and \c end iterators
+ /// and the length of this range should be equal to the dimension
+ /// number of the graph.
+ ///
+ ///\code
+ /// const int DIM = 3;
+ /// HypercubeGraph graph(DIM);
+ /// dim2::Point<double> base[DIM];
+ /// for (int k = 0; k < DIM; ++k) {
+ /// base[k].x = rnd();
+ /// base[k].y = rnd();
+ /// }
+ /// HypercubeGraph::HyperMap<dim2::Point<double> >
+ /// pos(graph, base, base + DIM, dim2::Point<double>(0.0, 0.0));
+ ///\endcode
+ ///
+ /// \see HypercubeGraph
+ template <typename T, typename BF = std::plus<T> >
+ class HyperMap {
+ public:
+
+ /// \brief The key type of the map
+ typedef Node Key;
+ /// \brief The value type of the map
+ typedef T Value;
+
+ /// \brief Constructor for HyperMap.
+ ///
+ /// Construct a HyperMap for the given graph. The values that have
+ /// to be accumulated should be given by the \c begin and \c end
+ /// iterators and the length of this range should be equal to the
+ /// dimension number of the graph.
+ ///
+ /// This map accumulates the \c bf binary function with the \c fv
+ /// first value on that positions (dimensions) where the index of
+ /// the node is one.
+ template <typename It>
+ HyperMap(const Graph& graph, It begin, It end,
+ T fv = 0, const BF& bf = BF())
+ : _graph(graph), _values(begin, end), _first_value(fv), _bin_func(bf)
+ {
+ LEMON_ASSERT(_values.size() == graph.dimension(),
+ "Wrong size of range");
+ }
+
+ /// \brief The partial accumulated value.
+ ///
+ /// Gives back the partial accumulated value.
+ Value operator[](const Key& k) const {
+ Value val = _first_value;
+ int id = _graph.index(k);
+ int n = 0;
+ while (id != 0) {
+ if (id & 1) {
+ val = _bin_func(val, _values[n]);
+ }
+ id >>= 1;
+ ++n;
+ }
+ return val;
+ }
+
+ private:
+ const Graph& _graph;
+ std::vector<T> _values;
+ T _first_value;
+ BF _bin_func;
+ };
+
+ };
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/insertion_tsp.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/insertion_tsp.h
new file mode 100644
index 00000000000..fa16825db52
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/insertion_tsp.h
@@ -0,0 +1,533 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_INSERTION_TSP_H
+#define LEMON_INSERTION_TSP_H
+
+/// \ingroup tsp
+/// \file
+/// \brief Insertion algorithm for symmetric TSP
+
+#include <vector>
+#include <functional>
+#include <lemon/full_graph.h>
+#include <lemon/maps.h>
+#include <lemon/random.h>
+
+namespace lemon {
+
+ /// \ingroup tsp
+ ///
+ /// \brief Insertion algorithm for symmetric TSP.
+ ///
+ /// InsertionTsp implements the insertion heuristic for solving
+ /// symmetric \ref tsp "TSP".
+ ///
+ /// This is a fast and effective tour construction method that has
+ /// many variants.
+ /// It starts with a subtour containing a few nodes of the graph and it
+ /// iteratively inserts the other nodes into this subtour according to a
+ /// certain node selection rule.
+ ///
+ /// This method is among the fastest TSP algorithms, and it typically
+ /// provides quite good solutions (usually much better than
+ /// \ref NearestNeighborTsp and \ref GreedyTsp).
+ ///
+ /// InsertionTsp implements four different node selection rules,
+ /// from which the most effective one (\e farthest \e node \e selection)
+ /// is used by default.
+ /// With this choice, the algorithm runs in O(n<sup>2</sup>) time.
+ /// For more information, see \ref SelectionRule.
+ ///
+ /// \tparam CM Type of the cost map.
+ template <typename CM>
+ class InsertionTsp
+ {
+ public:
+
+ /// Type of the cost map
+ typedef CM CostMap;
+ /// Type of the edge costs
+ typedef typename CM::Value Cost;
+
+ private:
+
+ GRAPH_TYPEDEFS(FullGraph);
+
+ const FullGraph &_gr;
+ const CostMap &_cost;
+ std::vector<Node> _notused;
+ std::vector<Node> _tour;
+ Cost _sum;
+
+ public:
+
+ /// \brief Constants for specifying the node selection rule.
+ ///
+ /// Enum type containing constants for specifying the node selection
+ /// rule for the \ref run() function.
+ ///
+ /// During the algorithm, nodes are selected for addition to the current
+ /// subtour according to the applied rule.
+ /// The FARTHEST method is one of the fastest selection rules, and
+ /// it is typically the most effective, thus it is the default
+ /// option. The RANDOM rule usually gives slightly worse results,
+ /// but it is more robust.
+ ///
+ /// The desired selection rule can be specified as a parameter of the
+ /// \ref run() function.
+ enum SelectionRule {
+
+ /// An unvisited node having minimum distance from the current
+ /// subtour is selected at each step.
+ /// The algorithm runs in O(n<sup>2</sup>) time using this
+ /// selection rule.
+ NEAREST,
+
+ /// An unvisited node having maximum distance from the current
+ /// subtour is selected at each step.
+ /// The algorithm runs in O(n<sup>2</sup>) time using this
+ /// selection rule.
+ FARTHEST,
+
+ /// An unvisited node whose insertion results in the least
+ /// increase of the subtour's total cost is selected at each step.
+ /// The algorithm runs in O(n<sup>3</sup>) time using this
+ /// selection rule, but in most cases, it is almost as fast as
+ /// with other rules.
+ CHEAPEST,
+
+ /// An unvisited node is selected randomly without any evaluation
+ /// at each step.
+ /// The global \ref rnd "random number generator instance" is used.
+ /// You can seed it before executing the algorithm, if you
+ /// would like to.
+ /// The algorithm runs in O(n<sup>2</sup>) time using this
+ /// selection rule.
+ RANDOM
+ };
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ /// \param gr The \ref FullGraph "full graph" the algorithm runs on.
+ /// \param cost The cost map.
+ InsertionTsp(const FullGraph &gr, const CostMap &cost)
+ : _gr(gr), _cost(cost) {}
+
+ /// \name Execution Control
+ /// @{
+
+ /// \brief Runs the algorithm.
+ ///
+ /// This function runs the algorithm.
+ ///
+ /// \param rule The node selection rule. For more information, see
+ /// \ref SelectionRule.
+ ///
+ /// \return The total cost of the found tour.
+ Cost run(SelectionRule rule = FARTHEST) {
+ _tour.clear();
+
+ if (_gr.nodeNum() == 0) return _sum = 0;
+ else if (_gr.nodeNum() == 1) {
+ _tour.push_back(_gr(0));
+ return _sum = 0;
+ }
+
+ switch (rule) {
+ case NEAREST:
+ init(true);
+ start<ComparingSelection<std::less<Cost> >,
+ DefaultInsertion>();
+ break;
+ case FARTHEST:
+ init(false);
+ start<ComparingSelection<std::greater<Cost> >,
+ DefaultInsertion>();
+ break;
+ case CHEAPEST:
+ init(true);
+ start<CheapestSelection, CheapestInsertion>();
+ break;
+ case RANDOM:
+ init(true);
+ start<RandomSelection, DefaultInsertion>();
+ break;
+ }
+ return _sum;
+ }
+
+ /// @}
+
+ /// \name Query Functions
+ /// @{
+
+ /// \brief The total cost of the found tour.
+ ///
+ /// This function returns the total cost of the found tour.
+ ///
+ /// \pre run() must be called before using this function.
+ Cost tourCost() const {
+ return _sum;
+ }
+
+ /// \brief Returns a const reference to the node sequence of the
+ /// found tour.
+ ///
+ /// This function returns a const reference to a vector
+ /// that stores the node sequence of the found tour.
+ ///
+ /// \pre run() must be called before using this function.
+ const std::vector<Node>& tourNodes() const {
+ return _tour;
+ }
+
+ /// \brief Gives back the node sequence of the found tour.
+ ///
+ /// This function copies the node sequence of the found tour into
+ /// an STL container through the given output iterator. The
+ /// <tt>value_type</tt> of the container must be <tt>FullGraph::Node</tt>.
+ /// For example,
+ /// \code
+ /// std::vector<FullGraph::Node> nodes(countNodes(graph));
+ /// tsp.tourNodes(nodes.begin());
+ /// \endcode
+ /// or
+ /// \code
+ /// std::list<FullGraph::Node> nodes;
+ /// tsp.tourNodes(std::back_inserter(nodes));
+ /// \endcode
+ ///
+ /// \pre run() must be called before using this function.
+ template <typename Iterator>
+ void tourNodes(Iterator out) const {
+ std::copy(_tour.begin(), _tour.end(), out);
+ }
+
+ /// \brief Gives back the found tour as a path.
+ ///
+ /// This function copies the found tour as a list of arcs/edges into
+ /// the given \ref lemon::concepts::Path "path structure".
+ ///
+ /// \pre run() must be called before using this function.
+ template <typename Path>
+ void tour(Path &path) const {
+ path.clear();
+ for (int i = 0; i < int(_tour.size()) - 1; ++i) {
+ path.addBack(_gr.arc(_tour[i], _tour[i+1]));
+ }
+ if (int(_tour.size()) >= 2) {
+ path.addBack(_gr.arc(_tour.back(), _tour.front()));
+ }
+ }
+
+ /// @}
+
+ private:
+
+ // Initializes the algorithm
+ void init(bool min) {
+ Edge min_edge = min ? mapMin(_gr, _cost) : mapMax(_gr, _cost);
+
+ _tour.clear();
+ _tour.push_back(_gr.u(min_edge));
+ _tour.push_back(_gr.v(min_edge));
+
+ _notused.clear();
+ for (NodeIt n(_gr); n!=INVALID; ++n) {
+ if (n != _gr.u(min_edge) && n != _gr.v(min_edge)) {
+ _notused.push_back(n);
+ }
+ }
+
+ _sum = _cost[min_edge] * 2;
+ }
+
+ // Executes the algorithm
+ template <class SelectionFunctor, class InsertionFunctor>
+ void start() {
+ SelectionFunctor selectNode(_gr, _cost, _tour, _notused);
+ InsertionFunctor insertNode(_gr, _cost, _tour, _sum);
+
+ for (int i=0; i<_gr.nodeNum()-2; ++i) {
+ insertNode.insert(selectNode.select());
+ }
+
+ _sum = _cost[_gr.edge(_tour.back(), _tour.front())];
+ for (int i = 0; i < int(_tour.size())-1; ++i) {
+ _sum += _cost[_gr.edge(_tour[i], _tour[i+1])];
+ }
+ }
+
+
+ // Implementation of the nearest and farthest selection rule
+ template <typename Comparator>
+ class ComparingSelection {
+ public:
+ ComparingSelection(const FullGraph &gr, const CostMap &cost,
+ std::vector<Node> &tour, std::vector<Node> &notused)
+ : _gr(gr), _cost(cost), _tour(tour), _notused(notused),
+ _dist(gr, 0), _compare()
+ {
+ // Compute initial distances for the unused nodes
+ for (unsigned int i=0; i<_notused.size(); ++i) {
+ Node u = _notused[i];
+ Cost min_dist = _cost[_gr.edge(u, _tour[0])];
+ for (unsigned int j=1; j<_tour.size(); ++j) {
+ Cost curr = _cost[_gr.edge(u, _tour[j])];
+ if (curr < min_dist) {
+ min_dist = curr;
+ }
+ }
+ _dist[u] = min_dist;
+ }
+ }
+
+ Node select() {
+
+ // Select an used node with minimum distance
+ Cost ins_dist = 0;
+ int ins_node = -1;
+ for (unsigned int i=0; i<_notused.size(); ++i) {
+ Cost curr = _dist[_notused[i]];
+ if (_compare(curr, ins_dist) || ins_node == -1) {
+ ins_dist = curr;
+ ins_node = i;
+ }
+ }
+
+ // Remove the selected node from the unused vector
+ Node sn = _notused[ins_node];
+ _notused[ins_node] = _notused.back();
+ _notused.pop_back();
+
+ // Update the distances of the remaining nodes
+ for (unsigned int i=0; i<_notused.size(); ++i) {
+ Node u = _notused[i];
+ Cost nc = _cost[_gr.edge(sn, u)];
+ if (nc < _dist[u]) {
+ _dist[u] = nc;
+ }
+ }
+
+ return sn;
+ }
+
+ private:
+ const FullGraph &_gr;
+ const CostMap &_cost;
+ std::vector<Node> &_tour;
+ std::vector<Node> &_notused;
+ FullGraph::NodeMap<Cost> _dist;
+ Comparator _compare;
+ };
+
+ // Implementation of the cheapest selection rule
+ class CheapestSelection {
+ private:
+ Cost costDiff(Node u, Node v, Node w) const {
+ return
+ _cost[_gr.edge(u, w)] +
+ _cost[_gr.edge(v, w)] -
+ _cost[_gr.edge(u, v)];
+ }
+
+ public:
+ CheapestSelection(const FullGraph &gr, const CostMap &cost,
+ std::vector<Node> &tour, std::vector<Node> &notused)
+ : _gr(gr), _cost(cost), _tour(tour), _notused(notused),
+ _ins_cost(gr, 0), _ins_pos(gr, -1)
+ {
+ // Compute insertion cost and position for the unused nodes
+ for (unsigned int i=0; i<_notused.size(); ++i) {
+ Node u = _notused[i];
+ Cost min_cost = costDiff(_tour.back(), _tour.front(), u);
+ int min_pos = 0;
+ for (unsigned int j=1; j<_tour.size(); ++j) {
+ Cost curr_cost = costDiff(_tour[j-1], _tour[j], u);
+ if (curr_cost < min_cost) {
+ min_cost = curr_cost;
+ min_pos = j;
+ }
+ }
+ _ins_cost[u] = min_cost;
+ _ins_pos[u] = min_pos;
+ }
+ }
+
+ Cost select() {
+
+ // Select an used node with minimum insertion cost
+ Cost min_cost = 0;
+ int min_node = -1;
+ for (unsigned int i=0; i<_notused.size(); ++i) {
+ Cost curr_cost = _ins_cost[_notused[i]];
+ if (curr_cost < min_cost || min_node == -1) {
+ min_cost = curr_cost;
+ min_node = i;
+ }
+ }
+
+ // Remove the selected node from the unused vector
+ Node sn = _notused[min_node];
+ _notused[min_node] = _notused.back();
+ _notused.pop_back();
+
+ // Insert the selected node into the tour
+ const int ipos = _ins_pos[sn];
+ _tour.insert(_tour.begin() + ipos, sn);
+
+ // Update the insertion cost and position of the remaining nodes
+ for (unsigned int i=0; i<_notused.size(); ++i) {
+ Node u = _notused[i];
+ Cost curr_cost = _ins_cost[u];
+ int curr_pos = _ins_pos[u];
+
+ int ipos_prev = ipos == 0 ? _tour.size()-1 : ipos-1;
+ int ipos_next = ipos == int(_tour.size())-1 ? 0 : ipos+1;
+ Cost nc1 = costDiff(_tour[ipos_prev], _tour[ipos], u);
+ Cost nc2 = costDiff(_tour[ipos], _tour[ipos_next], u);
+
+ if (nc1 <= curr_cost || nc2 <= curr_cost) {
+ // A new position is better than the old one
+ if (nc1 <= nc2) {
+ curr_cost = nc1;
+ curr_pos = ipos;
+ } else {
+ curr_cost = nc2;
+ curr_pos = ipos_next;
+ }
+ }
+ else {
+ if (curr_pos == ipos) {
+ // The minimum should be found again
+ curr_cost = costDiff(_tour.back(), _tour.front(), u);
+ curr_pos = 0;
+ for (unsigned int j=1; j<_tour.size(); ++j) {
+ Cost tmp_cost = costDiff(_tour[j-1], _tour[j], u);
+ if (tmp_cost < curr_cost) {
+ curr_cost = tmp_cost;
+ curr_pos = j;
+ }
+ }
+ }
+ else if (curr_pos > ipos) {
+ ++curr_pos;
+ }
+ }
+
+ _ins_cost[u] = curr_cost;
+ _ins_pos[u] = curr_pos;
+ }
+
+ return min_cost;
+ }
+
+ private:
+ const FullGraph &_gr;
+ const CostMap &_cost;
+ std::vector<Node> &_tour;
+ std::vector<Node> &_notused;
+ FullGraph::NodeMap<Cost> _ins_cost;
+ FullGraph::NodeMap<int> _ins_pos;
+ };
+
+ // Implementation of the random selection rule
+ class RandomSelection {
+ public:
+ RandomSelection(const FullGraph &, const CostMap &,
+ std::vector<Node> &, std::vector<Node> &notused)
+ : _notused(notused) {}
+
+ Node select() const {
+ const int index = rnd[_notused.size()];
+ Node n = _notused[index];
+ _notused[index] = _notused.back();
+ _notused.pop_back();
+ return n;
+ }
+
+ private:
+ std::vector<Node> &_notused;
+ };
+
+
+ // Implementation of the default insertion method
+ class DefaultInsertion {
+ private:
+ Cost costDiff(Node u, Node v, Node w) const {
+ return
+ _cost[_gr.edge(u, w)] +
+ _cost[_gr.edge(v, w)] -
+ _cost[_gr.edge(u, v)];
+ }
+
+ public:
+ DefaultInsertion(const FullGraph &gr, const CostMap &cost,
+ std::vector<Node> &tour, Cost &total_cost) :
+ _gr(gr), _cost(cost), _tour(tour), _total(total_cost) {}
+
+ void insert(Node n) const {
+ int min = 0;
+ Cost min_val =
+ costDiff(_tour.front(), _tour.back(), n);
+
+ for (unsigned int i=1; i<_tour.size(); ++i) {
+ Cost tmp = costDiff(_tour[i-1], _tour[i], n);
+ if (tmp < min_val) {
+ min = i;
+ min_val = tmp;
+ }
+ }
+
+ _tour.insert(_tour.begin()+min, n);
+ _total += min_val;
+ }
+
+ private:
+ const FullGraph &_gr;
+ const CostMap &_cost;
+ std::vector<Node> &_tour;
+ Cost &_total;
+ };
+
+ // Implementation of a special insertion method for the cheapest
+ // selection rule
+ class CheapestInsertion {
+ TEMPLATE_GRAPH_TYPEDEFS(FullGraph);
+ public:
+ CheapestInsertion(const FullGraph &, const CostMap &,
+ std::vector<Node> &, Cost &total_cost) :
+ _total(total_cost) {}
+
+ void insert(Cost diff) const {
+ _total += diff;
+ }
+
+ private:
+ Cost &_total;
+ };
+
+ };
+
+}; // namespace lemon
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/karp_mmc.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/karp_mmc.h
new file mode 100644
index 00000000000..1f05d4369c9
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/karp_mmc.h
@@ -0,0 +1,590 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_KARP_MMC_H
+#define LEMON_KARP_MMC_H
+
+/// \ingroup min_mean_cycle
+///
+/// \file
+/// \brief Karp's algorithm for finding a minimum mean cycle.
+
+#include <vector>
+#include <limits>
+#include <lemon/core.h>
+#include <lemon/path.h>
+#include <lemon/tolerance.h>
+#include <lemon/connectivity.h>
+
+namespace lemon {
+
+ /// \brief Default traits class of KarpMmc class.
+ ///
+ /// Default traits class of KarpMmc class.
+ /// \tparam GR The type of the digraph.
+ /// \tparam CM The type of the cost map.
+ /// It must conform to the \ref concepts::ReadMap "ReadMap" concept.
+#ifdef DOXYGEN
+ template <typename GR, typename CM>
+#else
+ template <typename GR, typename CM,
+ bool integer = std::numeric_limits<typename CM::Value>::is_integer>
+#endif
+ struct KarpMmcDefaultTraits
+ {
+ /// The type of the digraph
+ typedef GR Digraph;
+ /// The type of the cost map
+ typedef CM CostMap;
+ /// The type of the arc costs
+ typedef typename CostMap::Value Cost;
+
+ /// \brief The large cost type used for internal computations
+ ///
+ /// The large cost type used for internal computations.
+ /// It is \c long \c long if the \c Cost type is integer,
+ /// otherwise it is \c double.
+ /// \c Cost must be convertible to \c LargeCost.
+ typedef double LargeCost;
+
+ /// The tolerance type used for internal computations
+ typedef lemon::Tolerance<LargeCost> Tolerance;
+
+ /// \brief The path type of the found cycles
+ ///
+ /// The path type of the found cycles.
+ /// It must conform to the \ref lemon::concepts::Path "Path" concept
+ /// and it must have an \c addFront() function.
+ typedef lemon::Path<Digraph> Path;
+ };
+
+ // Default traits class for integer cost types
+ template <typename GR, typename CM>
+ struct KarpMmcDefaultTraits<GR, CM, true>
+ {
+ typedef GR Digraph;
+ typedef CM CostMap;
+ typedef typename CostMap::Value Cost;
+#ifdef LEMON_HAVE_LONG_LONG
+ typedef long long LargeCost;
+#else
+ typedef long LargeCost;
+#endif
+ typedef lemon::Tolerance<LargeCost> Tolerance;
+ typedef lemon::Path<Digraph> Path;
+ };
+
+
+ /// \addtogroup min_mean_cycle
+ /// @{
+
+ /// \brief Implementation of Karp's algorithm for finding a minimum
+ /// mean cycle.
+ ///
+ /// This class implements Karp's algorithm for finding a directed
+ /// cycle of minimum mean cost in a digraph
+ /// \cite karp78characterization, \cite dasdan98minmeancycle.
+ /// It runs in time O(nm) and uses space O(n<sup>2</sup>+m).
+ ///
+ /// \tparam GR The type of the digraph the algorithm runs on.
+ /// \tparam CM The type of the cost map. The default
+ /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap<int>".
+ /// \tparam TR The traits class that defines various types used by the
+ /// algorithm. By default, it is \ref KarpMmcDefaultTraits
+ /// "KarpMmcDefaultTraits<GR, CM>".
+ /// In most cases, this parameter should not be set directly,
+ /// consider to use the named template parameters instead.
+#ifdef DOXYGEN
+ template <typename GR, typename CM, typename TR>
+#else
+ template < typename GR,
+ typename CM = typename GR::template ArcMap<int>,
+ typename TR = KarpMmcDefaultTraits<GR, CM> >
+#endif
+ class KarpMmc
+ {
+ public:
+
+ /// The type of the digraph
+ typedef typename TR::Digraph Digraph;
+ /// The type of the cost map
+ typedef typename TR::CostMap CostMap;
+ /// The type of the arc costs
+ typedef typename TR::Cost Cost;
+
+ /// \brief The large cost type
+ ///
+ /// The large cost type used for internal computations.
+ /// By default, it is \c long \c long if the \c Cost type is integer,
+ /// otherwise it is \c double.
+ typedef typename TR::LargeCost LargeCost;
+
+ /// The tolerance type
+ typedef typename TR::Tolerance Tolerance;
+
+ /// \brief The path type of the found cycles
+ ///
+ /// The path type of the found cycles.
+ /// Using the \ref lemon::KarpMmcDefaultTraits "default traits class",
+ /// it is \ref lemon::Path "Path<Digraph>".
+ typedef typename TR::Path Path;
+
+ /// The \ref lemon::KarpMmcDefaultTraits "traits class" of the algorithm
+ typedef TR Traits;
+
+ private:
+
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+
+ // Data sturcture for path data
+ struct PathData
+ {
+ LargeCost dist;
+ Arc pred;
+ PathData(LargeCost d, Arc p = INVALID) :
+ dist(d), pred(p) {}
+ };
+
+ typedef typename Digraph::template NodeMap<std::vector<PathData> >
+ PathDataNodeMap;
+
+ private:
+
+ // The digraph the algorithm runs on
+ const Digraph &_gr;
+ // The cost of the arcs
+ const CostMap &_cost;
+
+ // Data for storing the strongly connected components
+ int _comp_num;
+ typename Digraph::template NodeMap<int> _comp;
+ std::vector<std::vector<Node> > _comp_nodes;
+ std::vector<Node>* _nodes;
+ typename Digraph::template NodeMap<std::vector<Arc> > _out_arcs;
+
+ // Data for the found cycle
+ LargeCost _cycle_cost;
+ int _cycle_size;
+ Node _cycle_node;
+
+ Path *_cycle_path;
+ bool _local_path;
+
+ // Node map for storing path data
+ PathDataNodeMap _data;
+ // The processed nodes in the last round
+ std::vector<Node> _process;
+
+ Tolerance _tolerance;
+
+ // Infinite constant
+ const LargeCost INF;
+
+ public:
+
+ /// \name Named Template Parameters
+ /// @{
+
+ template <typename T>
+ struct SetLargeCostTraits : public Traits {
+ typedef T LargeCost;
+ typedef lemon::Tolerance<T> Tolerance;
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// \c LargeCost type.
+ ///
+ /// \ref named-templ-param "Named parameter" for setting \c LargeCost
+ /// type. It is used for internal computations in the algorithm.
+ template <typename T>
+ struct SetLargeCost
+ : public KarpMmc<GR, CM, SetLargeCostTraits<T> > {
+ typedef KarpMmc<GR, CM, SetLargeCostTraits<T> > Create;
+ };
+
+ template <typename T>
+ struct SetPathTraits : public Traits {
+ typedef T Path;
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// \c %Path type.
+ ///
+ /// \ref named-templ-param "Named parameter" for setting the \c %Path
+ /// type of the found cycles.
+ /// It must conform to the \ref lemon::concepts::Path "Path" concept
+ /// and it must have an \c addFront() function.
+ template <typename T>
+ struct SetPath
+ : public KarpMmc<GR, CM, SetPathTraits<T> > {
+ typedef KarpMmc<GR, CM, SetPathTraits<T> > Create;
+ };
+
+ /// @}
+
+ protected:
+
+ KarpMmc() {}
+
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// The constructor of the class.
+ ///
+ /// \param digraph The digraph the algorithm runs on.
+ /// \param cost The costs of the arcs.
+ KarpMmc( const Digraph &digraph,
+ const CostMap &cost ) :
+ _gr(digraph), _cost(cost), _comp(digraph), _out_arcs(digraph),
+ _cycle_cost(0), _cycle_size(1), _cycle_node(INVALID),
+ _cycle_path(NULL), _local_path(false), _data(digraph),
+ INF(std::numeric_limits<LargeCost>::has_infinity ?
+ std::numeric_limits<LargeCost>::infinity() :
+ std::numeric_limits<LargeCost>::max())
+ {}
+
+ /// Destructor.
+ ~KarpMmc() {
+ if (_local_path) delete _cycle_path;
+ }
+
+ /// \brief Set the path structure for storing the found cycle.
+ ///
+ /// This function sets an external path structure for storing the
+ /// found cycle.
+ ///
+ /// If you don't call this function before calling \ref run() or
+ /// \ref findCycleMean(), a local \ref Path "path" structure
+ /// will be allocated. The destuctor deallocates this automatically
+ /// allocated object, of course.
+ ///
+ /// \note The algorithm calls only the \ref lemon::Path::addFront()
+ /// "addFront()" function of the given path structure.
+ ///
+ /// \return <tt>(*this)</tt>
+ KarpMmc& cycle(Path &path) {
+ if (_local_path) {
+ delete _cycle_path;
+ _local_path = false;
+ }
+ _cycle_path = &path;
+ return *this;
+ }
+
+ /// \brief Set the tolerance used by the algorithm.
+ ///
+ /// This function sets the tolerance object used by the algorithm.
+ ///
+ /// \return <tt>(*this)</tt>
+ KarpMmc& tolerance(const Tolerance& tolerance) {
+ _tolerance = tolerance;
+ return *this;
+ }
+
+ /// \brief Return a const reference to the tolerance.
+ ///
+ /// This function returns a const reference to the tolerance object
+ /// used by the algorithm.
+ const Tolerance& tolerance() const {
+ return _tolerance;
+ }
+
+ /// \name Execution control
+ /// The simplest way to execute the algorithm is to call the \ref run()
+ /// function.\n
+ /// If you only need the minimum mean cost, you may call
+ /// \ref findCycleMean().
+
+ /// @{
+
+ /// \brief Run the algorithm.
+ ///
+ /// This function runs the algorithm.
+ /// It can be called more than once (e.g. if the underlying digraph
+ /// and/or the arc costs have been modified).
+ ///
+ /// \return \c true if a directed cycle exists in the digraph.
+ ///
+ /// \note <tt>mmc.run()</tt> is just a shortcut of the following code.
+ /// \code
+ /// return mmc.findCycleMean() && mmc.findCycle();
+ /// \endcode
+ bool run() {
+ return findCycleMean() && findCycle();
+ }
+
+ /// \brief Find the minimum cycle mean.
+ ///
+ /// This function finds the minimum mean cost of the directed
+ /// cycles in the digraph.
+ ///
+ /// \return \c true if a directed cycle exists in the digraph.
+ bool findCycleMean() {
+ // Initialization and find strongly connected components
+ init();
+ findComponents();
+
+ // Find the minimum cycle mean in the components
+ for (int comp = 0; comp < _comp_num; ++comp) {
+ if (!initComponent(comp)) continue;
+ processRounds();
+ updateMinMean();
+ }
+ return (_cycle_node != INVALID);
+ }
+
+ /// \brief Find a minimum mean directed cycle.
+ ///
+ /// This function finds a directed cycle of minimum mean cost
+ /// in the digraph using the data computed by findCycleMean().
+ ///
+ /// \return \c true if a directed cycle exists in the digraph.
+ ///
+ /// \pre \ref findCycleMean() must be called before using this function.
+ bool findCycle() {
+ if (_cycle_node == INVALID) return false;
+ IntNodeMap reached(_gr, -1);
+ int r = _data[_cycle_node].size();
+ Node u = _cycle_node;
+ while (reached[u] < 0) {
+ reached[u] = --r;
+ u = _gr.source(_data[u][r].pred);
+ }
+ r = reached[u];
+ Arc e = _data[u][r].pred;
+ _cycle_path->addFront(e);
+ _cycle_cost = _cost[e];
+ _cycle_size = 1;
+ Node v;
+ while ((v = _gr.source(e)) != u) {
+ e = _data[v][--r].pred;
+ _cycle_path->addFront(e);
+ _cycle_cost += _cost[e];
+ ++_cycle_size;
+ }
+ return true;
+ }
+
+ /// @}
+
+ /// \name Query Functions
+ /// The results of the algorithm can be obtained using these
+ /// functions.\n
+ /// The algorithm should be executed before using them.
+
+ /// @{
+
+ /// \brief Return the total cost of the found cycle.
+ ///
+ /// This function returns the total cost of the found cycle.
+ ///
+ /// \pre \ref run() or \ref findCycleMean() must be called before
+ /// using this function.
+ Cost cycleCost() const {
+ return static_cast<Cost>(_cycle_cost);
+ }
+
+ /// \brief Return the number of arcs on the found cycle.
+ ///
+ /// This function returns the number of arcs on the found cycle.
+ ///
+ /// \pre \ref run() or \ref findCycleMean() must be called before
+ /// using this function.
+ int cycleSize() const {
+ return _cycle_size;
+ }
+
+ /// \brief Return the mean cost of the found cycle.
+ ///
+ /// This function returns the mean cost of the found cycle.
+ ///
+ /// \note <tt>alg.cycleMean()</tt> is just a shortcut of the
+ /// following code.
+ /// \code
+ /// return static_cast<double>(alg.cycleCost()) / alg.cycleSize();
+ /// \endcode
+ ///
+ /// \pre \ref run() or \ref findCycleMean() must be called before
+ /// using this function.
+ double cycleMean() const {
+ return static_cast<double>(_cycle_cost) / _cycle_size;
+ }
+
+ /// \brief Return the found cycle.
+ ///
+ /// This function returns a const reference to the path structure
+ /// storing the found cycle.
+ ///
+ /// \pre \ref run() or \ref findCycle() must be called before using
+ /// this function.
+ const Path& cycle() const {
+ return *_cycle_path;
+ }
+
+ ///@}
+
+ private:
+
+ // Initialization
+ void init() {
+ if (!_cycle_path) {
+ _local_path = true;
+ _cycle_path = new Path;
+ }
+ _cycle_path->clear();
+ _cycle_cost = 0;
+ _cycle_size = 1;
+ _cycle_node = INVALID;
+ for (NodeIt u(_gr); u != INVALID; ++u)
+ _data[u].clear();
+ }
+
+ // Find strongly connected components and initialize _comp_nodes
+ // and _out_arcs
+ void findComponents() {
+ _comp_num = stronglyConnectedComponents(_gr, _comp);
+ _comp_nodes.resize(_comp_num);
+ if (_comp_num == 1) {
+ _comp_nodes[0].clear();
+ for (NodeIt n(_gr); n != INVALID; ++n) {
+ _comp_nodes[0].push_back(n);
+ _out_arcs[n].clear();
+ for (OutArcIt a(_gr, n); a != INVALID; ++a) {
+ _out_arcs[n].push_back(a);
+ }
+ }
+ } else {
+ for (int i = 0; i < _comp_num; ++i)
+ _comp_nodes[i].clear();
+ for (NodeIt n(_gr); n != INVALID; ++n) {
+ int k = _comp[n];
+ _comp_nodes[k].push_back(n);
+ _out_arcs[n].clear();
+ for (OutArcIt a(_gr, n); a != INVALID; ++a) {
+ if (_comp[_gr.target(a)] == k) _out_arcs[n].push_back(a);
+ }
+ }
+ }
+ }
+
+ // Initialize path data for the current component
+ bool initComponent(int comp) {
+ _nodes = &(_comp_nodes[comp]);
+ int n = _nodes->size();
+ if (n < 1 || (n == 1 && _out_arcs[(*_nodes)[0]].size() == 0)) {
+ return false;
+ }
+ for (int i = 0; i < n; ++i) {
+ _data[(*_nodes)[i]].resize(n + 1, PathData(INF));
+ }
+ return true;
+ }
+
+ // Process all rounds of computing path data for the current component.
+ // _data[v][k] is the cost of a shortest directed walk from the root
+ // node to node v containing exactly k arcs.
+ void processRounds() {
+ Node start = (*_nodes)[0];
+ _data[start][0] = PathData(0);
+ _process.clear();
+ _process.push_back(start);
+
+ int k, n = _nodes->size();
+ for (k = 1; k <= n && int(_process.size()) < n; ++k) {
+ processNextBuildRound(k);
+ }
+ for ( ; k <= n; ++k) {
+ processNextFullRound(k);
+ }
+ }
+
+ // Process one round and rebuild _process
+ void processNextBuildRound(int k) {
+ std::vector<Node> next;
+ Node u, v;
+ Arc e;
+ LargeCost d;
+ for (int i = 0; i < int(_process.size()); ++i) {
+ u = _process[i];
+ for (int j = 0; j < int(_out_arcs[u].size()); ++j) {
+ e = _out_arcs[u][j];
+ v = _gr.target(e);
+ d = _data[u][k-1].dist + _cost[e];
+ if (_tolerance.less(d, _data[v][k].dist)) {
+ if (_data[v][k].dist == INF) next.push_back(v);
+ _data[v][k] = PathData(d, e);
+ }
+ }
+ }
+ _process.swap(next);
+ }
+
+ // Process one round using _nodes instead of _process
+ void processNextFullRound(int k) {
+ Node u, v;
+ Arc e;
+ LargeCost d;
+ for (int i = 0; i < int(_nodes->size()); ++i) {
+ u = (*_nodes)[i];
+ for (int j = 0; j < int(_out_arcs[u].size()); ++j) {
+ e = _out_arcs[u][j];
+ v = _gr.target(e);
+ d = _data[u][k-1].dist + _cost[e];
+ if (_tolerance.less(d, _data[v][k].dist)) {
+ _data[v][k] = PathData(d, e);
+ }
+ }
+ }
+ }
+
+ // Update the minimum cycle mean
+ void updateMinMean() {
+ int n = _nodes->size();
+ for (int i = 0; i < n; ++i) {
+ Node u = (*_nodes)[i];
+ if (_data[u][n].dist == INF) continue;
+ LargeCost cost, max_cost = 0;
+ int size, max_size = 1;
+ bool found_curr = false;
+ for (int k = 0; k < n; ++k) {
+ if (_data[u][k].dist == INF) continue;
+ cost = _data[u][n].dist - _data[u][k].dist;
+ size = n - k;
+ if (!found_curr || cost * max_size > max_cost * size) {
+ found_curr = true;
+ max_cost = cost;
+ max_size = size;
+ }
+ }
+ if ( found_curr && (_cycle_node == INVALID ||
+ max_cost * _cycle_size < _cycle_cost * max_size) ) {
+ _cycle_cost = max_cost;
+ _cycle_size = max_size;
+ _cycle_node = u;
+ }
+ }
+ }
+
+ }; //class KarpMmc
+
+ ///@}
+
+} //namespace lemon
+
+#endif //LEMON_KARP_MMC_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/kruskal.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/kruskal.h
new file mode 100644
index 00000000000..04c2ddb9384
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/kruskal.h
@@ -0,0 +1,324 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_KRUSKAL_H
+#define LEMON_KRUSKAL_H
+
+#include <algorithm>
+#include <vector>
+#include <lemon/unionfind.h>
+#include <lemon/maps.h>
+
+#include <lemon/core.h>
+#include <lemon/bits/traits.h>
+
+///\ingroup spantree
+///\file
+///\brief Kruskal's algorithm to compute a minimum cost spanning tree
+
+namespace lemon {
+
+ namespace _kruskal_bits {
+
+ // Kruskal for directed graphs.
+
+ template <typename Digraph, typename In, typename Out>
+ typename disable_if<lemon::UndirectedTagIndicator<Digraph>,
+ typename In::value_type::second_type >::type
+ kruskal(const Digraph& digraph, const In& in, Out& out,dummy<0> = 0) {
+ typedef typename In::value_type::second_type Value;
+ typedef typename Digraph::template NodeMap<int> IndexMap;
+ typedef typename Digraph::Node Node;
+
+ IndexMap index(digraph);
+ UnionFind<IndexMap> uf(index);
+ for (typename Digraph::NodeIt it(digraph); it != INVALID; ++it) {
+ uf.insert(it);
+ }
+
+ Value tree_value = 0;
+ for (typename In::const_iterator it = in.begin(); it != in.end(); ++it) {
+ if (uf.join(digraph.target(it->first),digraph.source(it->first))) {
+ out.set(it->first, true);
+ tree_value += it->second;
+ }
+ else {
+ out.set(it->first, false);
+ }
+ }
+ return tree_value;
+ }
+
+ // Kruskal for undirected graphs.
+
+ template <typename Graph, typename In, typename Out>
+ typename enable_if<lemon::UndirectedTagIndicator<Graph>,
+ typename In::value_type::second_type >::type
+ kruskal(const Graph& graph, const In& in, Out& out,dummy<1> = 1) {
+ typedef typename In::value_type::second_type Value;
+ typedef typename Graph::template NodeMap<int> IndexMap;
+ typedef typename Graph::Node Node;
+
+ IndexMap index(graph);
+ UnionFind<IndexMap> uf(index);
+ for (typename Graph::NodeIt it(graph); it != INVALID; ++it) {
+ uf.insert(it);
+ }
+
+ Value tree_value = 0;
+ for (typename In::const_iterator it = in.begin(); it != in.end(); ++it) {
+ if (uf.join(graph.u(it->first),graph.v(it->first))) {
+ out.set(it->first, true);
+ tree_value += it->second;
+ }
+ else {
+ out.set(it->first, false);
+ }
+ }
+ return tree_value;
+ }
+
+
+ template <typename Sequence>
+ struct PairComp {
+ typedef typename Sequence::value_type Value;
+ bool operator()(const Value& left, const Value& right) {
+ return left.second < right.second;
+ }
+ };
+
+ template <typename In, typename Enable = void>
+ struct SequenceInputIndicator {
+ static const bool value = false;
+ };
+
+ template <typename In>
+ struct SequenceInputIndicator<In,
+ typename exists<typename In::value_type::first_type>::type> {
+ static const bool value = true;
+ };
+
+ template <typename In, typename Enable = void>
+ struct MapInputIndicator {
+ static const bool value = false;
+ };
+
+ template <typename In>
+ struct MapInputIndicator<In,
+ typename exists<typename In::Value>::type> {
+ static const bool value = true;
+ };
+
+ template <typename In, typename Enable = void>
+ struct SequenceOutputIndicator {
+ static const bool value = false;
+ };
+
+ template <typename Out>
+ struct SequenceOutputIndicator<Out,
+ typename exists<typename Out::value_type>::type> {
+ static const bool value = true;
+ };
+
+ template <typename Out, typename Enable = void>
+ struct MapOutputIndicator {
+ static const bool value = false;
+ };
+
+ template <typename Out>
+ struct MapOutputIndicator<Out,
+ typename exists<typename Out::Value>::type> {
+ static const bool value = true;
+ };
+
+ template <typename In, typename InEnable = void>
+ struct KruskalValueSelector {};
+
+ template <typename In>
+ struct KruskalValueSelector<In,
+ typename enable_if<SequenceInputIndicator<In>, void>::type>
+ {
+ typedef typename In::value_type::second_type Value;
+ };
+
+ template <typename In>
+ struct KruskalValueSelector<In,
+ typename enable_if<MapInputIndicator<In>, void>::type>
+ {
+ typedef typename In::Value Value;
+ };
+
+ template <typename Graph, typename In, typename Out,
+ typename InEnable = void>
+ struct KruskalInputSelector {};
+
+ template <typename Graph, typename In, typename Out,
+ typename InEnable = void>
+ struct KruskalOutputSelector {};
+
+ template <typename Graph, typename In, typename Out>
+ struct KruskalInputSelector<Graph, In, Out,
+ typename enable_if<SequenceInputIndicator<In>, void>::type >
+ {
+ typedef typename In::value_type::second_type Value;
+
+ static Value kruskal(const Graph& graph, const In& in, Out& out) {
+ return KruskalOutputSelector<Graph, In, Out>::
+ kruskal(graph, in, out);
+ }
+
+ };
+
+ template <typename Graph, typename In, typename Out>
+ struct KruskalInputSelector<Graph, In, Out,
+ typename enable_if<MapInputIndicator<In>, void>::type >
+ {
+ typedef typename In::Value Value;
+ static Value kruskal(const Graph& graph, const In& in, Out& out) {
+ typedef typename In::Key MapArc;
+ typedef typename In::Value Value;
+ typedef typename ItemSetTraits<Graph, MapArc>::ItemIt MapArcIt;
+ typedef std::vector<std::pair<MapArc, Value> > Sequence;
+ Sequence seq;
+
+ for (MapArcIt it(graph); it != INVALID; ++it) {
+ seq.push_back(std::make_pair(it, in[it]));
+ }
+
+ std::sort(seq.begin(), seq.end(), PairComp<Sequence>());
+ return KruskalOutputSelector<Graph, Sequence, Out>::
+ kruskal(graph, seq, out);
+ }
+ };
+
+ template <typename T>
+ struct RemoveConst {
+ typedef T type;
+ };
+
+ template <typename T>
+ struct RemoveConst<const T> {
+ typedef T type;
+ };
+
+ template <typename Graph, typename In, typename Out>
+ struct KruskalOutputSelector<Graph, In, Out,
+ typename enable_if<SequenceOutputIndicator<Out>, void>::type >
+ {
+ typedef typename In::value_type::second_type Value;
+
+ static Value kruskal(const Graph& graph, const In& in, Out& out) {
+ typedef LoggerBoolMap<typename RemoveConst<Out>::type> Map;
+ Map map(out);
+ return _kruskal_bits::kruskal(graph, in, map);
+ }
+
+ };
+
+ template <typename Graph, typename In, typename Out>
+ struct KruskalOutputSelector<Graph, In, Out,
+ typename enable_if<MapOutputIndicator<Out>, void>::type >
+ {
+ typedef typename In::value_type::second_type Value;
+
+ static Value kruskal(const Graph& graph, const In& in, Out& out) {
+ return _kruskal_bits::kruskal(graph, in, out);
+ }
+ };
+
+ }
+
+ /// \ingroup spantree
+ ///
+ /// \brief Kruskal's algorithm for finding a minimum cost spanning tree of
+ /// a graph.
+ ///
+ /// This function runs Kruskal's algorithm to find a minimum cost
+ /// spanning tree of a graph.
+ /// Due to some C++ hacking, it accepts various input and output types.
+ ///
+ /// \param g The graph the algorithm runs on.
+ /// It can be either \ref concepts::Digraph "directed" or
+ /// \ref concepts::Graph "undirected".
+ /// If the graph is directed, the algorithm consider it to be
+ /// undirected by disregarding the direction of the arcs.
+ ///
+ /// \param in This object is used to describe the arc/edge costs.
+ /// It can be one of the following choices.
+ /// - An STL compatible 'Forward Container' with
+ /// <tt>std::pair<GR::Arc,C></tt> or
+ /// <tt>std::pair<GR::Edge,C></tt> as its <tt>value_type</tt>, where
+ /// \c C is the type of the costs. The pairs indicates the arcs/edges
+ /// along with the assigned cost. <em>They must be in a
+ /// cost-ascending order.</em>
+ /// - Any readable arc/edge map. The values of the map indicate the
+ /// arc/edge costs.
+ ///
+ /// \retval out Here we also have a choice.
+ /// - It can be a writable arc/edge map with \c bool value type. After
+ /// running the algorithm it will contain the found minimum cost spanning
+ /// tree: the value of an arc/edge will be set to \c true if it belongs
+ /// to the tree, otherwise it will be set to \c false. The value of
+ /// each arc/edge will be set exactly once.
+ /// - It can also be an iteraror of an STL Container with
+ /// <tt>GR::Arc</tt> or <tt>GR::Edge</tt> as its
+ /// <tt>value_type</tt>. The algorithm copies the elements of the
+ /// found tree into this sequence. For example, if we know that the
+ /// spanning tree of the graph \c g has say 53 arcs, then we can
+ /// put its arcs into an STL vector \c tree with a code like this.
+ ///\code
+ /// std::vector<Arc> tree(53);
+ /// kruskal(g,cost,tree.begin());
+ ///\endcode
+ /// Or if we don't know in advance the size of the tree, we can
+ /// write this.
+ ///\code
+ /// std::vector<Arc> tree;
+ /// kruskal(g,cost,std::back_inserter(tree));
+ ///\endcode
+ ///
+ /// \return The total cost of the found spanning tree.
+ ///
+ /// \note If the input graph is not (weakly) connected, a spanning
+ /// forest is calculated instead of a spanning tree.
+
+#ifdef DOXYGEN
+ template <typename Graph, typename In, typename Out>
+ Value kruskal(const Graph& g, const In& in, Out& out)
+#else
+ template <class Graph, class In, class Out>
+ inline typename _kruskal_bits::KruskalValueSelector<In>::Value
+ kruskal(const Graph& graph, const In& in, Out& out)
+#endif
+ {
+ return _kruskal_bits::KruskalInputSelector<Graph, In, Out>::
+ kruskal(graph, in, out);
+ }
+
+
+ template <class Graph, class In, class Out>
+ inline typename _kruskal_bits::KruskalValueSelector<In>::Value
+ kruskal(const Graph& graph, const In& in, const Out& out)
+ {
+ return _kruskal_bits::KruskalInputSelector<Graph, In, const Out>::
+ kruskal(graph, in, out);
+ }
+
+} //namespace lemon
+
+#endif //LEMON_KRUSKAL_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/lemon.pc.in b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lemon.pc.in
new file mode 100644
index 00000000000..e85bf7652ec
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lemon.pc.in
@@ -0,0 +1,10 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=@CMAKE_INSTALL_PREFIX@/bin
+libdir=@CMAKE_INSTALL_PREFIX@/lib
+includedir=@CMAKE_INSTALL_PREFIX@/include
+
+Name: @PROJECT_NAME@
+Description: Library for Efficient Modeling and Optimization in Networks
+Version: @PROJECT_VERSION@
+Libs: -L${libdir} -lemon @GLPK_LIBS@ @CPLEX_LIBS@ @SOPLEX_LIBS@ @CLP_LIBS@ @CBC_LIBS@
+Cflags: -I${includedir}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_reader.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_reader.h
new file mode 100644
index 00000000000..2f49fa25f21
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_reader.h
@@ -0,0 +1,3854 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+///\ingroup lemon_io
+///\file
+///\brief \ref lgf-format "LEMON Graph Format" reader.
+
+
+#ifndef LEMON_LGF_READER_H
+#define LEMON_LGF_READER_H
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+
+#include <set>
+#include <map>
+
+#include <lemon/core.h>
+
+#include <lemon/lgf_writer.h>
+
+#include <lemon/concept_check.h>
+#include <lemon/concepts/maps.h>
+
+namespace lemon {
+
+ namespace _reader_bits {
+
+ template <typename Value>
+ struct DefaultConverter {
+ Value operator()(const std::string& str) {
+ std::istringstream is(str);
+ Value value;
+ if (!(is >> value)) {
+ throw FormatError("Cannot read token");
+ }
+
+ char c;
+ if (is >> std::ws >> c) {
+ throw FormatError("Remaining characters in token");
+ }
+ return value;
+ }
+ };
+
+ template <>
+ struct DefaultConverter<std::string> {
+ std::string operator()(const std::string& str) {
+ return str;
+ }
+ };
+
+ template <typename _Item>
+ class MapStorageBase {
+ public:
+ typedef _Item Item;
+
+ public:
+ MapStorageBase() {}
+ virtual ~MapStorageBase() {}
+
+ virtual void set(const Item& item, const std::string& value) = 0;
+
+ };
+
+ template <typename _Item, typename _Map,
+ typename _Converter = DefaultConverter<typename _Map::Value> >
+ class MapStorage : public MapStorageBase<_Item> {
+ public:
+ typedef _Map Map;
+ typedef _Converter Converter;
+ typedef _Item Item;
+
+ private:
+ Map& _map;
+ Converter _converter;
+
+ public:
+ MapStorage(Map& map, const Converter& converter = Converter())
+ : _map(map), _converter(converter) {}
+ virtual ~MapStorage() {}
+
+ virtual void set(const Item& item ,const std::string& value) {
+ _map.set(item, _converter(value));
+ }
+ };
+
+ template <typename _GR, bool _dir, typename _Map,
+ typename _Converter = DefaultConverter<typename _Map::Value> >
+ class GraphArcMapStorage : public MapStorageBase<typename _GR::Edge> {
+ public:
+ typedef _Map Map;
+ typedef _Converter Converter;
+ typedef _GR GR;
+ typedef typename GR::Edge Item;
+ static const bool dir = _dir;
+
+ private:
+ const GR& _graph;
+ Map& _map;
+ Converter _converter;
+
+ public:
+ GraphArcMapStorage(const GR& graph, Map& map,
+ const Converter& converter = Converter())
+ : _graph(graph), _map(map), _converter(converter) {}
+ virtual ~GraphArcMapStorage() {}
+
+ virtual void set(const Item& item ,const std::string& value) {
+ _map.set(_graph.direct(item, dir), _converter(value));
+ }
+ };
+
+ class ValueStorageBase {
+ public:
+ ValueStorageBase() {}
+ virtual ~ValueStorageBase() {}
+
+ virtual void set(const std::string&) = 0;
+ };
+
+ template <typename _Value, typename _Converter = DefaultConverter<_Value> >
+ class ValueStorage : public ValueStorageBase {
+ public:
+ typedef _Value Value;
+ typedef _Converter Converter;
+
+ private:
+ Value& _value;
+ Converter _converter;
+
+ public:
+ ValueStorage(Value& value, const Converter& converter = Converter())
+ : _value(value), _converter(converter) {}
+
+ virtual void set(const std::string& value) {
+ _value = _converter(value);
+ }
+ };
+
+ template <typename Value,
+ typename Map = std::map<std::string, Value> >
+ struct MapLookUpConverter {
+ const Map& _map;
+
+ MapLookUpConverter(const Map& map)
+ : _map(map) {}
+
+ Value operator()(const std::string& str) {
+ typename Map::const_iterator it = _map.find(str);
+ if (it == _map.end()) {
+ std::ostringstream msg;
+ msg << "Item not found: " << str;
+ throw FormatError(msg.str());
+ }
+ return it->second;
+ }
+ };
+
+ template <typename Value,
+ typename Map1 = std::map<std::string, Value>,
+ typename Map2 = std::map<std::string, Value> >
+ struct DoubleMapLookUpConverter {
+ const Map1& _map1;
+ const Map2& _map2;
+
+ DoubleMapLookUpConverter(const Map1& map1, const Map2& map2)
+ : _map1(map1), _map2(map2) {}
+
+ Value operator()(const std::string& str) {
+ typename Map1::const_iterator it1 = _map1.find(str);
+ typename Map2::const_iterator it2 = _map2.find(str);
+ if (it1 == _map1.end()) {
+ if (it2 == _map2.end()) {
+ std::ostringstream msg;
+ msg << "Item not found: " << str;
+ throw FormatError(msg.str());
+ } else {
+ return it2->second;
+ }
+ } else {
+ if (it2 == _map2.end()) {
+ return it1->second;
+ } else {
+ std::ostringstream msg;
+ msg << "Item is ambigous: " << str;
+ throw FormatError(msg.str());
+ }
+ }
+ }
+ };
+
+ template <typename GR>
+ struct GraphArcLookUpConverter {
+ const GR& _graph;
+ const std::map<std::string, typename GR::Edge>& _map;
+
+ GraphArcLookUpConverter(const GR& graph,
+ const std::map<std::string,
+ typename GR::Edge>& map)
+ : _graph(graph), _map(map) {}
+
+ typename GR::Arc operator()(const std::string& str) {
+ if (str.empty() || (str[0] != '+' && str[0] != '-')) {
+ throw FormatError("Item must start with '+' or '-'");
+ }
+ typename std::map<std::string, typename GR::Edge>
+ ::const_iterator it = _map.find(str.substr(1));
+ if (it == _map.end()) {
+ throw FormatError("Item not found");
+ }
+ return _graph.direct(it->second, str[0] == '+');
+ }
+ };
+
+ inline bool isWhiteSpace(char c) {
+ return c == ' ' || c == '\t' || c == '\v' ||
+ c == '\n' || c == '\r' || c == '\f';
+ }
+
+ inline bool isOct(char c) {
+ return '0' <= c && c <='7';
+ }
+
+ inline int valueOct(char c) {
+ LEMON_ASSERT(isOct(c), "The character is not octal.");
+ return c - '0';
+ }
+
+ inline bool isHex(char c) {
+ return ('0' <= c && c <= '9') ||
+ ('a' <= c && c <= 'z') ||
+ ('A' <= c && c <= 'Z');
+ }
+
+ inline int valueHex(char c) {
+ LEMON_ASSERT(isHex(c), "The character is not hexadecimal.");
+ if ('0' <= c && c <= '9') return c - '0';
+ if ('a' <= c && c <= 'z') return c - 'a' + 10;
+ return c - 'A' + 10;
+ }
+
+ inline bool isIdentifierFirstChar(char c) {
+ return ('a' <= c && c <= 'z') ||
+ ('A' <= c && c <= 'Z') || c == '_';
+ }
+
+ inline bool isIdentifierChar(char c) {
+ return isIdentifierFirstChar(c) ||
+ ('0' <= c && c <= '9');
+ }
+
+ inline char readEscape(std::istream& is) {
+ char c;
+ if (!is.get(c))
+ throw FormatError("Escape format error");
+
+ switch (c) {
+ case '\\':
+ return '\\';
+ case '\"':
+ return '\"';
+ case '\'':
+ return '\'';
+ case '\?':
+ return '\?';
+ case 'a':
+ return '\a';
+ case 'b':
+ return '\b';
+ case 'f':
+ return '\f';
+ case 'n':
+ return '\n';
+ case 'r':
+ return '\r';
+ case 't':
+ return '\t';
+ case 'v':
+ return '\v';
+ case 'x':
+ {
+ int code;
+ if (!is.get(c) || !isHex(c))
+ throw FormatError("Escape format error");
+ else if (code = valueHex(c), !is.get(c) || !isHex(c)) is.putback(c);
+ else code = code * 16 + valueHex(c);
+ return code;
+ }
+ default:
+ {
+ int code;
+ if (!isOct(c))
+ throw FormatError("Escape format error");
+ else if (code = valueOct(c), !is.get(c) || !isOct(c))
+ is.putback(c);
+ else if (code = code * 8 + valueOct(c), !is.get(c) || !isOct(c))
+ is.putback(c);
+ else code = code * 8 + valueOct(c);
+ return code;
+ }
+ }
+ }
+
+ inline std::istream& readToken(std::istream& is, std::string& str) {
+ std::ostringstream os;
+
+ char c;
+ is >> std::ws;
+
+ if (!is.get(c))
+ return is;
+
+ if (c == '\"') {
+ while (is.get(c) && c != '\"') {
+ if (c == '\\')
+ c = readEscape(is);
+ os << c;
+ }
+ if (!is)
+ throw FormatError("Quoted format error");
+ } else {
+ is.putback(c);
+ while (is.get(c) && !isWhiteSpace(c)) {
+ if (c == '\\')
+ c = readEscape(is);
+ os << c;
+ }
+ if (!is) {
+ is.clear();
+ } else {
+ is.putback(c);
+ }
+ }
+ str = os.str();
+ return is;
+ }
+
+ class Section {
+ public:
+ virtual ~Section() {}
+ virtual void process(std::istream& is, int& line_num) = 0;
+ };
+
+ template <typename Functor>
+ class LineSection : public Section {
+ private:
+
+ Functor _functor;
+
+ public:
+
+ LineSection(const Functor& functor) : _functor(functor) {}
+ virtual ~LineSection() {}
+
+ virtual void process(std::istream& is, int& line_num) {
+ char c;
+ std::string line;
+ while (is.get(c) && c != '@') {
+ if (c == '\n') {
+ ++line_num;
+ } else if (c == '#') {
+ getline(is, line);
+ ++line_num;
+ } else if (!isWhiteSpace(c)) {
+ is.putback(c);
+ getline(is, line);
+ _functor(line);
+ ++line_num;
+ }
+ }
+ if (is) is.putback(c);
+ else if (is.eof()) is.clear();
+ }
+ };
+
+ template <typename Functor>
+ class StreamSection : public Section {
+ private:
+
+ Functor _functor;
+
+ public:
+
+ StreamSection(const Functor& functor) : _functor(functor) {}
+ virtual ~StreamSection() {}
+
+ virtual void process(std::istream& is, int& line_num) {
+ _functor(is, line_num);
+ char c;
+ std::string line;
+ while (is.get(c) && c != '@') {
+ if (c == '\n') {
+ ++line_num;
+ } else if (!isWhiteSpace(c)) {
+ getline(is, line);
+ ++line_num;
+ }
+ }
+ if (is) is.putback(c);
+ else if (is.eof()) is.clear();
+ }
+ };
+
+ }
+
+ template <typename DGR>
+ class DigraphReader;
+
+ template <typename TDGR>
+ DigraphReader<TDGR> digraphReader(TDGR& digraph, std::istream& is = std::cin);
+ template <typename TDGR>
+ DigraphReader<TDGR> digraphReader(TDGR& digraph, const std::string& fn);
+ template <typename TDGR>
+ DigraphReader<TDGR> digraphReader(TDGR& digraph, const char *fn);
+
+ /// \ingroup lemon_io
+ ///
+ /// \brief \ref lgf-format "LGF" reader for directed graphs
+ ///
+ /// This utility reads an \ref lgf-format "LGF" file.
+ ///
+ /// The reading method does a batch processing. The user creates a
+ /// reader object, then various reading rules can be added to the
+ /// reader, and eventually the reading is executed with the \c run()
+ /// member function. A map reading rule can be added to the reader
+ /// with the \c nodeMap() or \c arcMap() members. An optional
+ /// converter parameter can also be added as a standard functor
+ /// converting from \c std::string to the value type of the map. If it
+ /// is set, it will determine how the tokens in the file should be
+ /// converted to the value type of the map. If the functor is not set,
+ /// then a default conversion will be used. One map can be read into
+ /// multiple map objects at the same time. The \c attribute(), \c
+ /// node() and \c arc() functions are used to add attribute reading
+ /// rules.
+ ///
+ ///\code
+ /// DigraphReader<DGR>(digraph, std::cin).
+ /// nodeMap("coordinates", coord_map).
+ /// arcMap("capacity", cap_map).
+ /// node("source", src).
+ /// node("target", trg).
+ /// attribute("caption", caption).
+ /// run();
+ ///\endcode
+ ///
+ /// By default, the reader uses the first section in the file of the
+ /// proper type. If a section has an optional name, then it can be
+ /// selected for reading by giving an optional name parameter to the
+ /// \c nodes(), \c arcs() or \c attributes() functions.
+ ///
+ /// The \c useNodes() and \c useArcs() functions are used to tell the reader
+ /// that the nodes or arcs should not be constructed (added to the
+ /// graph) during the reading, but instead the label map of the items
+ /// are given as a parameter of these functions. An
+ /// application of these functions is multipass reading, which is
+ /// important if two \c \@arcs sections must be read from the
+ /// file. In this case the first phase would read the node set and one
+ /// of the arc sets, while the second phase would read the second arc
+ /// set into an \e ArcSet class (\c SmartArcSet or \c ListArcSet).
+ /// The previously read label node map should be passed to the \c
+ /// useNodes() functions. Another application of multipass reading when
+ /// paths are given as a node map or an arc map.
+ /// It is impossible to read this in
+ /// a single pass, because the arcs are not constructed when the node
+ /// maps are read.
+ template <typename DGR>
+ class DigraphReader {
+ public:
+
+ typedef DGR Digraph;
+
+ private:
+
+ TEMPLATE_DIGRAPH_TYPEDEFS(DGR);
+
+ std::istream* _is;
+ bool local_is;
+ std::string _filename;
+
+ DGR& _digraph;
+
+ std::string _nodes_caption;
+ std::string _arcs_caption;
+ std::string _attributes_caption;
+
+ typedef std::map<std::string, Node> NodeIndex;
+ NodeIndex _node_index;
+ typedef std::map<std::string, Arc> ArcIndex;
+ ArcIndex _arc_index;
+
+ typedef std::vector<std::pair<std::string,
+ _reader_bits::MapStorageBase<Node>*> > NodeMaps;
+ NodeMaps _node_maps;
+
+ typedef std::vector<std::pair<std::string,
+ _reader_bits::MapStorageBase<Arc>*> >ArcMaps;
+ ArcMaps _arc_maps;
+
+ typedef std::multimap<std::string, _reader_bits::ValueStorageBase*>
+ Attributes;
+ Attributes _attributes;
+
+ bool _use_nodes;
+ bool _use_arcs;
+
+ bool _skip_nodes;
+ bool _skip_arcs;
+
+ int line_num;
+ std::istringstream line;
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Construct a directed graph reader, which reads from the given
+ /// input stream.
+ DigraphReader(DGR& digraph, std::istream& is = std::cin)
+ : _is(&is), local_is(false), _digraph(digraph),
+ _use_nodes(false), _use_arcs(false),
+ _skip_nodes(false), _skip_arcs(false) {}
+
+ /// \brief Constructor
+ ///
+ /// Construct a directed graph reader, which reads from the given
+ /// file.
+ DigraphReader(DGR& digraph, const std::string& fn)
+ : _is(new std::ifstream(fn.c_str())), local_is(true),
+ _filename(fn), _digraph(digraph),
+ _use_nodes(false), _use_arcs(false),
+ _skip_nodes(false), _skip_arcs(false) {
+ if (!(*_is)) {
+ delete _is;
+ throw IoError("Cannot open file", fn);
+ }
+ }
+
+ /// \brief Constructor
+ ///
+ /// Construct a directed graph reader, which reads from the given
+ /// file.
+ DigraphReader(DGR& digraph, const char* fn)
+ : _is(new std::ifstream(fn)), local_is(true),
+ _filename(fn), _digraph(digraph),
+ _use_nodes(false), _use_arcs(false),
+ _skip_nodes(false), _skip_arcs(false) {
+ if (!(*_is)) {
+ delete _is;
+ throw IoError("Cannot open file", fn);
+ }
+ }
+
+ /// \brief Destructor
+ ~DigraphReader() {
+ for (typename NodeMaps::iterator it = _node_maps.begin();
+ it != _node_maps.end(); ++it) {
+ delete it->second;
+ }
+
+ for (typename ArcMaps::iterator it = _arc_maps.begin();
+ it != _arc_maps.end(); ++it) {
+ delete it->second;
+ }
+
+ for (typename Attributes::iterator it = _attributes.begin();
+ it != _attributes.end(); ++it) {
+ delete it->second;
+ }
+
+ if (local_is) {
+ delete _is;
+ }
+
+ }
+
+ private:
+
+ template <typename TDGR>
+ friend DigraphReader<TDGR> digraphReader(TDGR& digraph, std::istream& is);
+ template <typename TDGR>
+ friend DigraphReader<TDGR> digraphReader(TDGR& digraph,
+ const std::string& fn);
+ template <typename TDGR>
+ friend DigraphReader<TDGR> digraphReader(TDGR& digraph, const char *fn);
+
+ DigraphReader(DigraphReader& other)
+ : _is(other._is), local_is(other.local_is), _digraph(other._digraph),
+ _use_nodes(other._use_nodes), _use_arcs(other._use_arcs),
+ _skip_nodes(other._skip_nodes), _skip_arcs(other._skip_arcs) {
+
+ other._is = 0;
+ other.local_is = false;
+
+ _node_index.swap(other._node_index);
+ _arc_index.swap(other._arc_index);
+
+ _node_maps.swap(other._node_maps);
+ _arc_maps.swap(other._arc_maps);
+ _attributes.swap(other._attributes);
+
+ _nodes_caption = other._nodes_caption;
+ _arcs_caption = other._arcs_caption;
+ _attributes_caption = other._attributes_caption;
+
+ }
+
+ DigraphReader& operator=(const DigraphReader&);
+
+ public:
+
+ /// \name Reading Rules
+ /// @{
+
+ /// \brief Node map reading rule
+ ///
+ /// Add a node map reading rule to the reader.
+ template <typename Map>
+ DigraphReader& nodeMap(const std::string& caption, Map& map) {
+ checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
+ _reader_bits::MapStorageBase<Node>* storage =
+ new _reader_bits::MapStorage<Node, Map>(map);
+ _node_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Node map reading rule
+ ///
+ /// Add a node map reading rule with specialized converter to the
+ /// reader.
+ template <typename Map, typename Converter>
+ DigraphReader& nodeMap(const std::string& caption, Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
+ _reader_bits::MapStorageBase<Node>* storage =
+ new _reader_bits::MapStorage<Node, Map, Converter>(map, converter);
+ _node_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Arc map reading rule
+ ///
+ /// Add an arc map reading rule to the reader.
+ template <typename Map>
+ DigraphReader& arcMap(const std::string& caption, Map& map) {
+ checkConcept<concepts::WriteMap<Arc, typename Map::Value>, Map>();
+ _reader_bits::MapStorageBase<Arc>* storage =
+ new _reader_bits::MapStorage<Arc, Map>(map);
+ _arc_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Arc map reading rule
+ ///
+ /// Add an arc map reading rule with specialized converter to the
+ /// reader.
+ template <typename Map, typename Converter>
+ DigraphReader& arcMap(const std::string& caption, Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::WriteMap<Arc, typename Map::Value>, Map>();
+ _reader_bits::MapStorageBase<Arc>* storage =
+ new _reader_bits::MapStorage<Arc, Map, Converter>(map, converter);
+ _arc_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Attribute reading rule
+ ///
+ /// Add an attribute reading rule to the reader.
+ template <typename Value>
+ DigraphReader& attribute(const std::string& caption, Value& value) {
+ _reader_bits::ValueStorageBase* storage =
+ new _reader_bits::ValueStorage<Value>(value);
+ _attributes.insert(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Attribute reading rule
+ ///
+ /// Add an attribute reading rule with specialized converter to the
+ /// reader.
+ template <typename Value, typename Converter>
+ DigraphReader& attribute(const std::string& caption, Value& value,
+ const Converter& converter = Converter()) {
+ _reader_bits::ValueStorageBase* storage =
+ new _reader_bits::ValueStorage<Value, Converter>(value, converter);
+ _attributes.insert(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Node reading rule
+ ///
+ /// Add a node reading rule to reader.
+ DigraphReader& node(const std::string& caption, Node& node) {
+ typedef _reader_bits::MapLookUpConverter<Node> Converter;
+ Converter converter(_node_index);
+ _reader_bits::ValueStorageBase* storage =
+ new _reader_bits::ValueStorage<Node, Converter>(node, converter);
+ _attributes.insert(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Arc reading rule
+ ///
+ /// Add an arc reading rule to reader.
+ DigraphReader& arc(const std::string& caption, Arc& arc) {
+ typedef _reader_bits::MapLookUpConverter<Arc> Converter;
+ Converter converter(_arc_index);
+ _reader_bits::ValueStorageBase* storage =
+ new _reader_bits::ValueStorage<Arc, Converter>(arc, converter);
+ _attributes.insert(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// @}
+
+ /// \name Select Section by Name
+ /// @{
+
+ /// \brief Set \c \@nodes section to be read
+ ///
+ /// Set \c \@nodes section to be read
+ DigraphReader& nodes(const std::string& caption) {
+ _nodes_caption = caption;
+ return *this;
+ }
+
+ /// \brief Set \c \@arcs section to be read
+ ///
+ /// Set \c \@arcs section to be read
+ DigraphReader& arcs(const std::string& caption) {
+ _arcs_caption = caption;
+ return *this;
+ }
+
+ /// \brief Set \c \@attributes section to be read
+ ///
+ /// Set \c \@attributes section to be read
+ DigraphReader& attributes(const std::string& caption) {
+ _attributes_caption = caption;
+ return *this;
+ }
+
+ /// @}
+
+ /// \name Using Previously Constructed Node or Arc Set
+ /// @{
+
+ /// \brief Use previously constructed node set
+ ///
+ /// Use previously constructed node set, and specify the node
+ /// label map.
+ template <typename Map>
+ DigraphReader& useNodes(const Map& map) {
+ checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
+ LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member");
+ _use_nodes = true;
+ _writer_bits::DefaultConverter<typename Map::Value> converter;
+ for (NodeIt n(_digraph); n != INVALID; ++n) {
+ _node_index.insert(std::make_pair(converter(map[n]), n));
+ }
+ return *this;
+ }
+
+ /// \brief Use previously constructed node set
+ ///
+ /// Use previously constructed node set, and specify the node
+ /// label map and a functor which converts the label map values to
+ /// \c std::string.
+ template <typename Map, typename Converter>
+ DigraphReader& useNodes(const Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
+ LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member");
+ _use_nodes = true;
+ for (NodeIt n(_digraph); n != INVALID; ++n) {
+ _node_index.insert(std::make_pair(converter(map[n]), n));
+ }
+ return *this;
+ }
+
+ /// \brief Use previously constructed arc set
+ ///
+ /// Use previously constructed arc set, and specify the arc
+ /// label map.
+ template <typename Map>
+ DigraphReader& useArcs(const Map& map) {
+ checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
+ LEMON_ASSERT(!_use_arcs, "Multiple usage of useArcs() member");
+ _use_arcs = true;
+ _writer_bits::DefaultConverter<typename Map::Value> converter;
+ for (ArcIt a(_digraph); a != INVALID; ++a) {
+ _arc_index.insert(std::make_pair(converter(map[a]), a));
+ }
+ return *this;
+ }
+
+ /// \brief Use previously constructed arc set
+ ///
+ /// Use previously constructed arc set, and specify the arc
+ /// label map and a functor which converts the label map values to
+ /// \c std::string.
+ template <typename Map, typename Converter>
+ DigraphReader& useArcs(const Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
+ LEMON_ASSERT(!_use_arcs, "Multiple usage of useArcs() member");
+ _use_arcs = true;
+ for (ArcIt a(_digraph); a != INVALID; ++a) {
+ _arc_index.insert(std::make_pair(converter(map[a]), a));
+ }
+ return *this;
+ }
+
+ /// \brief Skips the reading of node section
+ ///
+ /// Omit the reading of the node section. This implies that each node
+ /// map reading rule will be abandoned, and the nodes of the graph
+ /// will not be constructed, which usually cause that the arc set
+ /// could not be read due to lack of node name resolving.
+ /// Therefore \c skipArcs() function should also be used, or
+ /// \c useNodes() should be used to specify the label of the nodes.
+ DigraphReader& skipNodes() {
+ LEMON_ASSERT(!_skip_nodes, "Skip nodes already set");
+ _skip_nodes = true;
+ return *this;
+ }
+
+ /// \brief Skips the reading of arc section
+ ///
+ /// Omit the reading of the arc section. This implies that each arc
+ /// map reading rule will be abandoned, and the arcs of the graph
+ /// will not be constructed.
+ DigraphReader& skipArcs() {
+ LEMON_ASSERT(!_skip_arcs, "Skip arcs already set");
+ _skip_arcs = true;
+ return *this;
+ }
+
+ /// @}
+
+ private:
+
+ bool readLine() {
+ std::string str;
+ while(++line_num, std::getline(*_is, str)) {
+ line.clear(); line.str(str);
+ char c;
+ if (line >> std::ws >> c && c != '#') {
+ line.putback(c);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool readSuccess() {
+ return static_cast<bool>(*_is);
+ }
+
+ void skipSection() {
+ char c;
+ while (readSuccess() && line >> c && c != '@') {
+ readLine();
+ }
+ if (readSuccess()) {
+ line.putback(c);
+ }
+ }
+
+ void readNodes() {
+
+ std::vector<int> map_index(_node_maps.size());
+ int map_num, label_index;
+
+ char c;
+ if (!readLine() || !(line >> c) || c == '@') {
+ if (readSuccess() && line) line.putback(c);
+ if (!_node_maps.empty())
+ throw FormatError("Cannot find map names");
+ return;
+ }
+ line.putback(c);
+
+ {
+ std::map<std::string, int> maps;
+
+ std::string map;
+ int index = 0;
+ while (_reader_bits::readToken(line, map)) {
+ if (maps.find(map) != maps.end()) {
+ std::ostringstream msg;
+ msg << "Multiple occurence of node map: " << map;
+ throw FormatError(msg.str());
+ }
+ maps.insert(std::make_pair(map, index));
+ ++index;
+ }
+
+ for (int i = 0; i < static_cast<int>(_node_maps.size()); ++i) {
+ std::map<std::string, int>::iterator jt =
+ maps.find(_node_maps[i].first);
+ if (jt == maps.end()) {
+ std::ostringstream msg;
+ msg << "Map not found: " << _node_maps[i].first;
+ throw FormatError(msg.str());
+ }
+ map_index[i] = jt->second;
+ }
+
+ {
+ std::map<std::string, int>::iterator jt = maps.find("label");
+ if (jt != maps.end()) {
+ label_index = jt->second;
+ } else {
+ label_index = -1;
+ }
+ }
+ map_num = maps.size();
+ }
+
+ while (readLine() && line >> c && c != '@') {
+ line.putback(c);
+
+ std::vector<std::string> tokens(map_num);
+ for (int i = 0; i < map_num; ++i) {
+ if (!_reader_bits::readToken(line, tokens[i])) {
+ std::ostringstream msg;
+ msg << "Column not found (" << i + 1 << ")";
+ throw FormatError(msg.str());
+ }
+ }
+ if (line >> std::ws >> c)
+ throw FormatError("Extra character at the end of line");
+
+ Node n;
+ if (!_use_nodes) {
+ n = _digraph.addNode();
+ if (label_index != -1)
+ _node_index.insert(std::make_pair(tokens[label_index], n));
+ } else {
+ if (label_index == -1)
+ throw FormatError("Label map not found");
+ typename std::map<std::string, Node>::iterator it =
+ _node_index.find(tokens[label_index]);
+ if (it == _node_index.end()) {
+ std::ostringstream msg;
+ msg << "Node with label not found: " << tokens[label_index];
+ throw FormatError(msg.str());
+ }
+ n = it->second;
+ }
+
+ for (int i = 0; i < static_cast<int>(_node_maps.size()); ++i) {
+ _node_maps[i].second->set(n, tokens[map_index[i]]);
+ }
+
+ }
+ if (readSuccess()) {
+ line.putback(c);
+ }
+ }
+
+ void readArcs() {
+
+ std::vector<int> map_index(_arc_maps.size());
+ int map_num, label_index;
+
+ char c;
+ if (!readLine() || !(line >> c) || c == '@') {
+ if (readSuccess() && line) line.putback(c);
+ if (!_arc_maps.empty())
+ throw FormatError("Cannot find map names");
+ return;
+ }
+ line.putback(c);
+
+ {
+ std::map<std::string, int> maps;
+
+ std::string map;
+ int index = 0;
+ while (_reader_bits::readToken(line, map)) {
+ if(map == "-") {
+ if(index!=0)
+ throw FormatError("'-' is not allowed as a map name");
+ else if (line >> std::ws >> c)
+ throw FormatError("Extra character at the end of line");
+ else break;
+ }
+ if (maps.find(map) != maps.end()) {
+ std::ostringstream msg;
+ msg << "Multiple occurence of arc map: " << map;
+ throw FormatError(msg.str());
+ }
+ maps.insert(std::make_pair(map, index));
+ ++index;
+ }
+
+ for (int i = 0; i < static_cast<int>(_arc_maps.size()); ++i) {
+ std::map<std::string, int>::iterator jt =
+ maps.find(_arc_maps[i].first);
+ if (jt == maps.end()) {
+ std::ostringstream msg;
+ msg << "Map not found: " << _arc_maps[i].first;
+ throw FormatError(msg.str());
+ }
+ map_index[i] = jt->second;
+ }
+
+ {
+ std::map<std::string, int>::iterator jt = maps.find("label");
+ if (jt != maps.end()) {
+ label_index = jt->second;
+ } else {
+ label_index = -1;
+ }
+ }
+ map_num = maps.size();
+ }
+
+ while (readLine() && line >> c && c != '@') {
+ line.putback(c);
+
+ std::string source_token;
+ std::string target_token;
+
+ if (!_reader_bits::readToken(line, source_token))
+ throw FormatError("Source not found");
+
+ if (!_reader_bits::readToken(line, target_token))
+ throw FormatError("Target not found");
+
+ std::vector<std::string> tokens(map_num);
+ for (int i = 0; i < map_num; ++i) {
+ if (!_reader_bits::readToken(line, tokens[i])) {
+ std::ostringstream msg;
+ msg << "Column not found (" << i + 1 << ")";
+ throw FormatError(msg.str());
+ }
+ }
+ if (line >> std::ws >> c)
+ throw FormatError("Extra character at the end of line");
+
+ Arc a;
+ if (!_use_arcs) {
+
+ typename NodeIndex::iterator it;
+
+ it = _node_index.find(source_token);
+ if (it == _node_index.end()) {
+ std::ostringstream msg;
+ msg << "Item not found: " << source_token;
+ throw FormatError(msg.str());
+ }
+ Node source = it->second;
+
+ it = _node_index.find(target_token);
+ if (it == _node_index.end()) {
+ std::ostringstream msg;
+ msg << "Item not found: " << target_token;
+ throw FormatError(msg.str());
+ }
+ Node target = it->second;
+
+ a = _digraph.addArc(source, target);
+ if (label_index != -1)
+ _arc_index.insert(std::make_pair(tokens[label_index], a));
+ } else {
+ if (label_index == -1)
+ throw FormatError("Label map not found");
+ typename std::map<std::string, Arc>::iterator it =
+ _arc_index.find(tokens[label_index]);
+ if (it == _arc_index.end()) {
+ std::ostringstream msg;
+ msg << "Arc with label not found: " << tokens[label_index];
+ throw FormatError(msg.str());
+ }
+ a = it->second;
+ }
+
+ for (int i = 0; i < static_cast<int>(_arc_maps.size()); ++i) {
+ _arc_maps[i].second->set(a, tokens[map_index[i]]);
+ }
+
+ }
+ if (readSuccess()) {
+ line.putback(c);
+ }
+ }
+
+ void readAttributes() {
+
+ std::set<std::string> read_attr;
+
+ char c;
+ while (readLine() && line >> c && c != '@') {
+ line.putback(c);
+
+ std::string attr, token;
+ if (!_reader_bits::readToken(line, attr))
+ throw FormatError("Attribute name not found");
+ if (!_reader_bits::readToken(line, token))
+ throw FormatError("Attribute value not found");
+ if (line >> c)
+ throw FormatError("Extra character at the end of line");
+
+ {
+ std::set<std::string>::iterator it = read_attr.find(attr);
+ if (it != read_attr.end()) {
+ std::ostringstream msg;
+ msg << "Multiple occurence of attribute: " << attr;
+ throw FormatError(msg.str());
+ }
+ read_attr.insert(attr);
+ }
+
+ {
+ typename Attributes::iterator it = _attributes.lower_bound(attr);
+ while (it != _attributes.end() && it->first == attr) {
+ it->second->set(token);
+ ++it;
+ }
+ }
+
+ }
+ if (readSuccess()) {
+ line.putback(c);
+ }
+ for (typename Attributes::iterator it = _attributes.begin();
+ it != _attributes.end(); ++it) {
+ if (read_attr.find(it->first) == read_attr.end()) {
+ std::ostringstream msg;
+ msg << "Attribute not found: " << it->first;
+ throw FormatError(msg.str());
+ }
+ }
+ }
+
+ public:
+
+ /// \name Execution of the Reader
+ /// @{
+
+ /// \brief Start the batch processing
+ ///
+ /// This function starts the batch processing
+ void run() {
+ LEMON_ASSERT(_is != 0, "This reader assigned to an other reader");
+
+ bool nodes_done = _skip_nodes;
+ bool arcs_done = _skip_arcs;
+ bool attributes_done = false;
+
+ line_num = 0;
+ readLine();
+ skipSection();
+
+ while (readSuccess()) {
+ try {
+ char c;
+ std::string section, caption;
+ line >> c;
+ _reader_bits::readToken(line, section);
+ _reader_bits::readToken(line, caption);
+
+ if (line >> c)
+ throw FormatError("Extra character at the end of line");
+
+ if (section == "nodes" && !nodes_done) {
+ if (_nodes_caption.empty() || _nodes_caption == caption) {
+ readNodes();
+ nodes_done = true;
+ }
+ } else if ((section == "arcs" || section == "edges") &&
+ !arcs_done) {
+ if (_arcs_caption.empty() || _arcs_caption == caption) {
+ readArcs();
+ arcs_done = true;
+ }
+ } else if (section == "attributes" && !attributes_done) {
+ if (_attributes_caption.empty() || _attributes_caption == caption) {
+ readAttributes();
+ attributes_done = true;
+ }
+ } else {
+ readLine();
+ skipSection();
+ }
+ } catch (FormatError& error) {
+ error.line(line_num);
+ error.file(_filename);
+ throw;
+ }
+ }
+
+ if (!nodes_done) {
+ throw FormatError("Section @nodes not found");
+ }
+
+ if (!arcs_done) {
+ throw FormatError("Section @arcs not found");
+ }
+
+ if (!attributes_done && !_attributes.empty()) {
+ throw FormatError("Section @attributes not found");
+ }
+
+ }
+
+ /// @}
+
+ };
+
+ /// \ingroup lemon_io
+ ///
+ /// \brief Return a \ref lemon::DigraphReader "DigraphReader" class
+ ///
+ /// This function just returns a \ref lemon::DigraphReader
+ /// "DigraphReader" class.
+ ///
+ /// With this function a digraph can be read from an
+ /// \ref lgf-format "LGF" file or input stream with several maps and
+ /// attributes. For example, there is network flow problem on a
+ /// digraph, i.e. a digraph with a \e capacity map on the arcs and
+ /// \e source and \e target nodes. This digraph can be read with the
+ /// following code:
+ ///
+ ///\code
+ ///ListDigraph digraph;
+ ///ListDigraph::ArcMap<int> cm(digraph);
+ ///ListDigraph::Node src, trg;
+ ///digraphReader(digraph, std::cin).
+ /// arcMap("capacity", cap).
+ /// node("source", src).
+ /// node("target", trg).
+ /// run();
+ ///\endcode
+ ///
+ /// For a complete documentation, please see the
+ /// \ref lemon::DigraphReader "DigraphReader"
+ /// class documentation.
+ /// \warning Don't forget to put the \ref lemon::DigraphReader::run() "run()"
+ /// to the end of the parameter list.
+ /// \relates DigraphReader
+ /// \sa digraphReader(TDGR& digraph, const std::string& fn)
+ /// \sa digraphReader(TDGR& digraph, const char* fn)
+ template <typename TDGR>
+ DigraphReader<TDGR> digraphReader(TDGR& digraph, std::istream& is) {
+ DigraphReader<TDGR> tmp(digraph, is);
+ return tmp;
+ }
+
+ /// \brief Return a \ref DigraphReader class
+ ///
+ /// This function just returns a \ref DigraphReader class.
+ /// \relates DigraphReader
+ /// \sa digraphReader(TDGR& digraph, std::istream& is)
+ template <typename TDGR>
+ DigraphReader<TDGR> digraphReader(TDGR& digraph, const std::string& fn) {
+ DigraphReader<TDGR> tmp(digraph, fn);
+ return tmp;
+ }
+
+ /// \brief Return a \ref DigraphReader class
+ ///
+ /// This function just returns a \ref DigraphReader class.
+ /// \relates DigraphReader
+ /// \sa digraphReader(TDGR& digraph, std::istream& is)
+ template <typename TDGR>
+ DigraphReader<TDGR> digraphReader(TDGR& digraph, const char* fn) {
+ DigraphReader<TDGR> tmp(digraph, fn);
+ return tmp;
+ }
+
+ template <typename GR>
+ class GraphReader;
+
+ template <typename TGR>
+ GraphReader<TGR> graphReader(TGR& graph, std::istream& is = std::cin);
+ template <typename TGR>
+ GraphReader<TGR> graphReader(TGR& graph, const std::string& fn);
+ template <typename TGR>
+ GraphReader<TGR> graphReader(TGR& graph, const char *fn);
+
+ /// \ingroup lemon_io
+ ///
+ /// \brief \ref lgf-format "LGF" reader for undirected graphs
+ ///
+ /// This utility reads an \ref lgf-format "LGF" file.
+ ///
+ /// It can be used almost the same way as \c DigraphReader.
+ /// The only difference is that this class can handle edges and
+ /// edge maps as well as arcs and arc maps.
+ ///
+ /// The columns in the \c \@edges (or \c \@arcs) section are the
+ /// edge maps. However, if there are two maps with the same name
+ /// prefixed with \c '+' and \c '-', then these can be read into an
+ /// arc map. Similarly, an attribute can be read into an arc, if
+ /// it's value is an edge label prefixed with \c '+' or \c '-'.
+ template <typename GR>
+ class GraphReader {
+ public:
+
+ typedef GR Graph;
+
+ private:
+
+ TEMPLATE_GRAPH_TYPEDEFS(GR);
+
+ std::istream* _is;
+ bool local_is;
+ std::string _filename;
+
+ GR& _graph;
+
+ std::string _nodes_caption;
+ std::string _edges_caption;
+ std::string _attributes_caption;
+
+ typedef std::map<std::string, Node> NodeIndex;
+ NodeIndex _node_index;
+ typedef std::map<std::string, Edge> EdgeIndex;
+ EdgeIndex _edge_index;
+
+ typedef std::vector<std::pair<std::string,
+ _reader_bits::MapStorageBase<Node>*> > NodeMaps;
+ NodeMaps _node_maps;
+
+ typedef std::vector<std::pair<std::string,
+ _reader_bits::MapStorageBase<Edge>*> > EdgeMaps;
+ EdgeMaps _edge_maps;
+
+ typedef std::multimap<std::string, _reader_bits::ValueStorageBase*>
+ Attributes;
+ Attributes _attributes;
+
+ bool _use_nodes;
+ bool _use_edges;
+
+ bool _skip_nodes;
+ bool _skip_edges;
+
+ int line_num;
+ std::istringstream line;
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Construct an undirected graph reader, which reads from the given
+ /// input stream.
+ GraphReader(GR& graph, std::istream& is = std::cin)
+ : _is(&is), local_is(false), _graph(graph),
+ _use_nodes(false), _use_edges(false),
+ _skip_nodes(false), _skip_edges(false) {}
+
+ /// \brief Constructor
+ ///
+ /// Construct an undirected graph reader, which reads from the given
+ /// file.
+ GraphReader(GR& graph, const std::string& fn)
+ : _is(new std::ifstream(fn.c_str())), local_is(true),
+ _filename(fn), _graph(graph),
+ _use_nodes(false), _use_edges(false),
+ _skip_nodes(false), _skip_edges(false) {
+ if (!(*_is)) {
+ delete _is;
+ throw IoError("Cannot open file", fn);
+ }
+ }
+
+ /// \brief Constructor
+ ///
+ /// Construct an undirected graph reader, which reads from the given
+ /// file.
+ GraphReader(GR& graph, const char* fn)
+ : _is(new std::ifstream(fn)), local_is(true),
+ _filename(fn), _graph(graph),
+ _use_nodes(false), _use_edges(false),
+ _skip_nodes(false), _skip_edges(false) {
+ if (!(*_is)) {
+ delete _is;
+ throw IoError("Cannot open file", fn);
+ }
+ }
+
+ /// \brief Destructor
+ ~GraphReader() {
+ for (typename NodeMaps::iterator it = _node_maps.begin();
+ it != _node_maps.end(); ++it) {
+ delete it->second;
+ }
+
+ for (typename EdgeMaps::iterator it = _edge_maps.begin();
+ it != _edge_maps.end(); ++it) {
+ delete it->second;
+ }
+
+ for (typename Attributes::iterator it = _attributes.begin();
+ it != _attributes.end(); ++it) {
+ delete it->second;
+ }
+
+ if (local_is) {
+ delete _is;
+ }
+
+ }
+
+ private:
+ template <typename TGR>
+ friend GraphReader<TGR> graphReader(TGR& graph, std::istream& is);
+ template <typename TGR>
+ friend GraphReader<TGR> graphReader(TGR& graph, const std::string& fn);
+ template <typename TGR>
+ friend GraphReader<TGR> graphReader(TGR& graph, const char *fn);
+
+ GraphReader(GraphReader& other)
+ : _is(other._is), local_is(other.local_is), _graph(other._graph),
+ _use_nodes(other._use_nodes), _use_edges(other._use_edges),
+ _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) {
+
+ other._is = 0;
+ other.local_is = false;
+
+ _node_index.swap(other._node_index);
+ _edge_index.swap(other._edge_index);
+
+ _node_maps.swap(other._node_maps);
+ _edge_maps.swap(other._edge_maps);
+ _attributes.swap(other._attributes);
+
+ _nodes_caption = other._nodes_caption;
+ _edges_caption = other._edges_caption;
+ _attributes_caption = other._attributes_caption;
+
+ }
+
+ GraphReader& operator=(const GraphReader&);
+
+ public:
+
+ /// \name Reading Rules
+ /// @{
+
+ /// \brief Node map reading rule
+ ///
+ /// Add a node map reading rule to the reader.
+ template <typename Map>
+ GraphReader& nodeMap(const std::string& caption, Map& map) {
+ checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
+ _reader_bits::MapStorageBase<Node>* storage =
+ new _reader_bits::MapStorage<Node, Map>(map);
+ _node_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Node map reading rule
+ ///
+ /// Add a node map reading rule with specialized converter to the
+ /// reader.
+ template <typename Map, typename Converter>
+ GraphReader& nodeMap(const std::string& caption, Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
+ _reader_bits::MapStorageBase<Node>* storage =
+ new _reader_bits::MapStorage<Node, Map, Converter>(map, converter);
+ _node_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Edge map reading rule
+ ///
+ /// Add an edge map reading rule to the reader.
+ template <typename Map>
+ GraphReader& edgeMap(const std::string& caption, Map& map) {
+ checkConcept<concepts::WriteMap<Edge, typename Map::Value>, Map>();
+ _reader_bits::MapStorageBase<Edge>* storage =
+ new _reader_bits::MapStorage<Edge, Map>(map);
+ _edge_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Edge map reading rule
+ ///
+ /// Add an edge map reading rule with specialized converter to the
+ /// reader.
+ template <typename Map, typename Converter>
+ GraphReader& edgeMap(const std::string& caption, Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::WriteMap<Edge, typename Map::Value>, Map>();
+ _reader_bits::MapStorageBase<Edge>* storage =
+ new _reader_bits::MapStorage<Edge, Map, Converter>(map, converter);
+ _edge_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Arc map reading rule
+ ///
+ /// Add an arc map reading rule to the reader.
+ template <typename Map>
+ GraphReader& arcMap(const std::string& caption, Map& map) {
+ checkConcept<concepts::WriteMap<Arc, typename Map::Value>, Map>();
+ _reader_bits::MapStorageBase<Edge>* forward_storage =
+ new _reader_bits::GraphArcMapStorage<Graph, true, Map>(_graph, map);
+ _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
+ _reader_bits::MapStorageBase<Edge>* backward_storage =
+ new _reader_bits::GraphArcMapStorage<GR, false, Map>(_graph, map);
+ _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
+ return *this;
+ }
+
+ /// \brief Arc map reading rule
+ ///
+ /// Add an arc map reading rule with specialized converter to the
+ /// reader.
+ template <typename Map, typename Converter>
+ GraphReader& arcMap(const std::string& caption, Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::WriteMap<Arc, typename Map::Value>, Map>();
+ _reader_bits::MapStorageBase<Edge>* forward_storage =
+ new _reader_bits::GraphArcMapStorage<GR, true, Map, Converter>
+ (_graph, map, converter);
+ _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
+ _reader_bits::MapStorageBase<Edge>* backward_storage =
+ new _reader_bits::GraphArcMapStorage<GR, false, Map, Converter>
+ (_graph, map, converter);
+ _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
+ return *this;
+ }
+
+ /// \brief Attribute reading rule
+ ///
+ /// Add an attribute reading rule to the reader.
+ template <typename Value>
+ GraphReader& attribute(const std::string& caption, Value& value) {
+ _reader_bits::ValueStorageBase* storage =
+ new _reader_bits::ValueStorage<Value>(value);
+ _attributes.insert(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Attribute reading rule
+ ///
+ /// Add an attribute reading rule with specialized converter to the
+ /// reader.
+ template <typename Value, typename Converter>
+ GraphReader& attribute(const std::string& caption, Value& value,
+ const Converter& converter = Converter()) {
+ _reader_bits::ValueStorageBase* storage =
+ new _reader_bits::ValueStorage<Value, Converter>(value, converter);
+ _attributes.insert(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Node reading rule
+ ///
+ /// Add a node reading rule to reader.
+ GraphReader& node(const std::string& caption, Node& node) {
+ typedef _reader_bits::MapLookUpConverter<Node> Converter;
+ Converter converter(_node_index);
+ _reader_bits::ValueStorageBase* storage =
+ new _reader_bits::ValueStorage<Node, Converter>(node, converter);
+ _attributes.insert(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Edge reading rule
+ ///
+ /// Add an edge reading rule to reader.
+ GraphReader& edge(const std::string& caption, Edge& edge) {
+ typedef _reader_bits::MapLookUpConverter<Edge> Converter;
+ Converter converter(_edge_index);
+ _reader_bits::ValueStorageBase* storage =
+ new _reader_bits::ValueStorage<Edge, Converter>(edge, converter);
+ _attributes.insert(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Arc reading rule
+ ///
+ /// Add an arc reading rule to reader.
+ GraphReader& arc(const std::string& caption, Arc& arc) {
+ typedef _reader_bits::GraphArcLookUpConverter<GR> Converter;
+ Converter converter(_graph, _edge_index);
+ _reader_bits::ValueStorageBase* storage =
+ new _reader_bits::ValueStorage<Arc, Converter>(arc, converter);
+ _attributes.insert(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// @}
+
+ /// \name Select Section by Name
+ /// @{
+
+ /// \brief Set \c \@nodes section to be read
+ ///
+ /// Set \c \@nodes section to be read.
+ GraphReader& nodes(const std::string& caption) {
+ _nodes_caption = caption;
+ return *this;
+ }
+
+ /// \brief Set \c \@edges section to be read
+ ///
+ /// Set \c \@edges section to be read.
+ GraphReader& edges(const std::string& caption) {
+ _edges_caption = caption;
+ return *this;
+ }
+
+ /// \brief Set \c \@attributes section to be read
+ ///
+ /// Set \c \@attributes section to be read.
+ GraphReader& attributes(const std::string& caption) {
+ _attributes_caption = caption;
+ return *this;
+ }
+
+ /// @}
+
+ /// \name Using Previously Constructed Node or Edge Set
+ /// @{
+
+ /// \brief Use previously constructed node set
+ ///
+ /// Use previously constructed node set, and specify the node
+ /// label map.
+ template <typename Map>
+ GraphReader& useNodes(const Map& map) {
+ checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
+ LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member");
+ _use_nodes = true;
+ _writer_bits::DefaultConverter<typename Map::Value> converter;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ _node_index.insert(std::make_pair(converter(map[n]), n));
+ }
+ return *this;
+ }
+
+ /// \brief Use previously constructed node set
+ ///
+ /// Use previously constructed node set, and specify the node
+ /// label map and a functor which converts the label map values to
+ /// \c std::string.
+ template <typename Map, typename Converter>
+ GraphReader& useNodes(const Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
+ LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member");
+ _use_nodes = true;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ _node_index.insert(std::make_pair(converter(map[n]), n));
+ }
+ return *this;
+ }
+
+ /// \brief Use previously constructed edge set
+ ///
+ /// Use previously constructed edge set, and specify the edge
+ /// label map.
+ template <typename Map>
+ GraphReader& useEdges(const Map& map) {
+ checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
+ LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member");
+ _use_edges = true;
+ _writer_bits::DefaultConverter<typename Map::Value> converter;
+ for (EdgeIt a(_graph); a != INVALID; ++a) {
+ _edge_index.insert(std::make_pair(converter(map[a]), a));
+ }
+ return *this;
+ }
+
+ /// \brief Use previously constructed edge set
+ ///
+ /// Use previously constructed edge set, and specify the edge
+ /// label map and a functor which converts the label map values to
+ /// \c std::string.
+ template <typename Map, typename Converter>
+ GraphReader& useEdges(const Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
+ LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member");
+ _use_edges = true;
+ for (EdgeIt a(_graph); a != INVALID; ++a) {
+ _edge_index.insert(std::make_pair(converter(map[a]), a));
+ }
+ return *this;
+ }
+
+ /// \brief Skip the reading of node section
+ ///
+ /// Omit the reading of the node section. This implies that each node
+ /// map reading rule will be abandoned, and the nodes of the graph
+ /// will not be constructed, which usually cause that the edge set
+ /// could not be read due to lack of node name
+ /// could not be read due to lack of node name resolving.
+ /// Therefore \c skipEdges() function should also be used, or
+ /// \c useNodes() should be used to specify the label of the nodes.
+ GraphReader& skipNodes() {
+ LEMON_ASSERT(!_skip_nodes, "Skip nodes already set");
+ _skip_nodes = true;
+ return *this;
+ }
+
+ /// \brief Skip the reading of edge section
+ ///
+ /// Omit the reading of the edge section. This implies that each edge
+ /// map reading rule will be abandoned, and the edges of the graph
+ /// will not be constructed.
+ GraphReader& skipEdges() {
+ LEMON_ASSERT(!_skip_edges, "Skip edges already set");
+ _skip_edges = true;
+ return *this;
+ }
+
+ /// @}
+
+ private:
+
+ bool readLine() {
+ std::string str;
+ while(++line_num, std::getline(*_is, str)) {
+ line.clear(); line.str(str);
+ char c;
+ if (line >> std::ws >> c && c != '#') {
+ line.putback(c);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool readSuccess() {
+ return static_cast<bool>(*_is);
+ }
+
+ void skipSection() {
+ char c;
+ while (readSuccess() && line >> c && c != '@') {
+ readLine();
+ }
+ if (readSuccess()) {
+ line.putback(c);
+ }
+ }
+
+ void readNodes() {
+
+ std::vector<int> map_index(_node_maps.size());
+ int map_num, label_index;
+
+ char c;
+ if (!readLine() || !(line >> c) || c == '@') {
+ if (readSuccess() && line) line.putback(c);
+ if (!_node_maps.empty())
+ throw FormatError("Cannot find map names");
+ return;
+ }
+ line.putback(c);
+
+ {
+ std::map<std::string, int> maps;
+
+ std::string map;
+ int index = 0;
+ while (_reader_bits::readToken(line, map)) {
+ if (maps.find(map) != maps.end()) {
+ std::ostringstream msg;
+ msg << "Multiple occurence of node map: " << map;
+ throw FormatError(msg.str());
+ }
+ maps.insert(std::make_pair(map, index));
+ ++index;
+ }
+
+ for (int i = 0; i < static_cast<int>(_node_maps.size()); ++i) {
+ std::map<std::string, int>::iterator jt =
+ maps.find(_node_maps[i].first);
+ if (jt == maps.end()) {
+ std::ostringstream msg;
+ msg << "Map not found: " << _node_maps[i].first;
+ throw FormatError(msg.str());
+ }
+ map_index[i] = jt->second;
+ }
+
+ {
+ std::map<std::string, int>::iterator jt = maps.find("label");
+ if (jt != maps.end()) {
+ label_index = jt->second;
+ } else {
+ label_index = -1;
+ }
+ }
+ map_num = maps.size();
+ }
+
+ while (readLine() && line >> c && c != '@') {
+ line.putback(c);
+
+ std::vector<std::string> tokens(map_num);
+ for (int i = 0; i < map_num; ++i) {
+ if (!_reader_bits::readToken(line, tokens[i])) {
+ std::ostringstream msg;
+ msg << "Column not found (" << i + 1 << ")";
+ throw FormatError(msg.str());
+ }
+ }
+ if (line >> std::ws >> c)
+ throw FormatError("Extra character at the end of line");
+
+ Node n;
+ if (!_use_nodes) {
+ n = _graph.addNode();
+ if (label_index != -1)
+ _node_index.insert(std::make_pair(tokens[label_index], n));
+ } else {
+ if (label_index == -1)
+ throw FormatError("Label map not found");
+ typename std::map<std::string, Node>::iterator it =
+ _node_index.find(tokens[label_index]);
+ if (it == _node_index.end()) {
+ std::ostringstream msg;
+ msg << "Node with label not found: " << tokens[label_index];
+ throw FormatError(msg.str());
+ }
+ n = it->second;
+ }
+
+ for (int i = 0; i < static_cast<int>(_node_maps.size()); ++i) {
+ _node_maps[i].second->set(n, tokens[map_index[i]]);
+ }
+
+ }
+ if (readSuccess()) {
+ line.putback(c);
+ }
+ }
+
+ void readEdges() {
+
+ std::vector<int> map_index(_edge_maps.size());
+ int map_num, label_index;
+
+ char c;
+ if (!readLine() || !(line >> c) || c == '@') {
+ if (readSuccess() && line) line.putback(c);
+ if (!_edge_maps.empty())
+ throw FormatError("Cannot find map names");
+ return;
+ }
+ line.putback(c);
+
+ {
+ std::map<std::string, int> maps;
+
+ std::string map;
+ int index = 0;
+ while (_reader_bits::readToken(line, map)) {
+ if(map == "-") {
+ if(index!=0)
+ throw FormatError("'-' is not allowed as a map name");
+ else if (line >> std::ws >> c)
+ throw FormatError("Extra character at the end of line");
+ else break;
+ }
+ if (maps.find(map) != maps.end()) {
+ std::ostringstream msg;
+ msg << "Multiple occurence of edge map: " << map;
+ throw FormatError(msg.str());
+ }
+ maps.insert(std::make_pair(map, index));
+ ++index;
+ }
+
+ for (int i = 0; i < static_cast<int>(_edge_maps.size()); ++i) {
+ std::map<std::string, int>::iterator jt =
+ maps.find(_edge_maps[i].first);
+ if (jt == maps.end()) {
+ std::ostringstream msg;
+ msg << "Map not found: " << _edge_maps[i].first;
+ throw FormatError(msg.str());
+ }
+ map_index[i] = jt->second;
+ }
+
+ {
+ std::map<std::string, int>::iterator jt = maps.find("label");
+ if (jt != maps.end()) {
+ label_index = jt->second;
+ } else {
+ label_index = -1;
+ }
+ }
+ map_num = maps.size();
+ }
+
+ while (readLine() && line >> c && c != '@') {
+ line.putback(c);
+
+ std::string source_token;
+ std::string target_token;
+
+ if (!_reader_bits::readToken(line, source_token))
+ throw FormatError("Node u not found");
+
+ if (!_reader_bits::readToken(line, target_token))
+ throw FormatError("Node v not found");
+
+ std::vector<std::string> tokens(map_num);
+ for (int i = 0; i < map_num; ++i) {
+ if (!_reader_bits::readToken(line, tokens[i])) {
+ std::ostringstream msg;
+ msg << "Column not found (" << i + 1 << ")";
+ throw FormatError(msg.str());
+ }
+ }
+ if (line >> std::ws >> c)
+ throw FormatError("Extra character at the end of line");
+
+ Edge e;
+ if (!_use_edges) {
+
+ typename NodeIndex::iterator it;
+
+ it = _node_index.find(source_token);
+ if (it == _node_index.end()) {
+ std::ostringstream msg;
+ msg << "Item not found: " << source_token;
+ throw FormatError(msg.str());
+ }
+ Node source = it->second;
+
+ it = _node_index.find(target_token);
+ if (it == _node_index.end()) {
+ std::ostringstream msg;
+ msg << "Item not found: " << target_token;
+ throw FormatError(msg.str());
+ }
+ Node target = it->second;
+
+ e = _graph.addEdge(source, target);
+ if (label_index != -1)
+ _edge_index.insert(std::make_pair(tokens[label_index], e));
+ } else {
+ if (label_index == -1)
+ throw FormatError("Label map not found");
+ typename std::map<std::string, Edge>::iterator it =
+ _edge_index.find(tokens[label_index]);
+ if (it == _edge_index.end()) {
+ std::ostringstream msg;
+ msg << "Edge with label not found: " << tokens[label_index];
+ throw FormatError(msg.str());
+ }
+ e = it->second;
+ }
+
+ for (int i = 0; i < static_cast<int>(_edge_maps.size()); ++i) {
+ _edge_maps[i].second->set(e, tokens[map_index[i]]);
+ }
+
+ }
+ if (readSuccess()) {
+ line.putback(c);
+ }
+ }
+
+ void readAttributes() {
+
+ std::set<std::string> read_attr;
+
+ char c;
+ while (readLine() && line >> c && c != '@') {
+ line.putback(c);
+
+ std::string attr, token;
+ if (!_reader_bits::readToken(line, attr))
+ throw FormatError("Attribute name not found");
+ if (!_reader_bits::readToken(line, token))
+ throw FormatError("Attribute value not found");
+ if (line >> c)
+ throw FormatError("Extra character at the end of line");
+
+ {
+ std::set<std::string>::iterator it = read_attr.find(attr);
+ if (it != read_attr.end()) {
+ std::ostringstream msg;
+ msg << "Multiple occurence of attribute: " << attr;
+ throw FormatError(msg.str());
+ }
+ read_attr.insert(attr);
+ }
+
+ {
+ typename Attributes::iterator it = _attributes.lower_bound(attr);
+ while (it != _attributes.end() && it->first == attr) {
+ it->second->set(token);
+ ++it;
+ }
+ }
+
+ }
+ if (readSuccess()) {
+ line.putback(c);
+ }
+ for (typename Attributes::iterator it = _attributes.begin();
+ it != _attributes.end(); ++it) {
+ if (read_attr.find(it->first) == read_attr.end()) {
+ std::ostringstream msg;
+ msg << "Attribute not found: " << it->first;
+ throw FormatError(msg.str());
+ }
+ }
+ }
+
+ public:
+
+ /// \name Execution of the Reader
+ /// @{
+
+ /// \brief Start the batch processing
+ ///
+ /// This function starts the batch processing
+ void run() {
+
+ LEMON_ASSERT(_is != 0, "This reader assigned to an other reader");
+
+ bool nodes_done = _skip_nodes;
+ bool edges_done = _skip_edges;
+ bool attributes_done = false;
+
+ line_num = 0;
+ readLine();
+ skipSection();
+
+ while (readSuccess()) {
+ try {
+ char c;
+ std::string section, caption;
+ line >> c;
+ _reader_bits::readToken(line, section);
+ _reader_bits::readToken(line, caption);
+
+ if (line >> c)
+ throw FormatError("Extra character at the end of line");
+
+ if (section == "nodes" && !nodes_done) {
+ if (_nodes_caption.empty() || _nodes_caption == caption) {
+ readNodes();
+ nodes_done = true;
+ }
+ } else if ((section == "edges" || section == "arcs") &&
+ !edges_done) {
+ if (_edges_caption.empty() || _edges_caption == caption) {
+ readEdges();
+ edges_done = true;
+ }
+ } else if (section == "attributes" && !attributes_done) {
+ if (_attributes_caption.empty() || _attributes_caption == caption) {
+ readAttributes();
+ attributes_done = true;
+ }
+ } else {
+ readLine();
+ skipSection();
+ }
+ } catch (FormatError& error) {
+ error.line(line_num);
+ error.file(_filename);
+ throw;
+ }
+ }
+
+ if (!nodes_done) {
+ throw FormatError("Section @nodes not found");
+ }
+
+ if (!edges_done) {
+ throw FormatError("Section @edges not found");
+ }
+
+ if (!attributes_done && !_attributes.empty()) {
+ throw FormatError("Section @attributes not found");
+ }
+
+ }
+
+ /// @}
+
+ };
+
+ /// \ingroup lemon_io
+ ///
+ /// \brief Return a \ref lemon::GraphReader "GraphReader" class
+ ///
+ /// This function just returns a \ref lemon::GraphReader "GraphReader" class.
+ ///
+ /// With this function a graph can be read from an
+ /// \ref lgf-format "LGF" file or input stream with several maps and
+ /// attributes. For example, there is weighted matching problem on a
+ /// graph, i.e. a graph with a \e weight map on the edges. This
+ /// graph can be read with the following code:
+ ///
+ ///\code
+ ///ListGraph graph;
+ ///ListGraph::EdgeMap<int> weight(graph);
+ ///graphReader(graph, std::cin).
+ /// edgeMap("weight", weight).
+ /// run();
+ ///\endcode
+ ///
+ /// For a complete documentation, please see the
+ /// \ref lemon::GraphReader "GraphReader"
+ /// class documentation.
+ /// \warning Don't forget to put the \ref lemon::GraphReader::run() "run()"
+ /// to the end of the parameter list.
+ /// \relates GraphReader
+ /// \sa graphReader(TGR& graph, const std::string& fn)
+ /// \sa graphReader(TGR& graph, const char* fn)
+ template <typename TGR>
+ GraphReader<TGR> graphReader(TGR& graph, std::istream& is) {
+ GraphReader<TGR> tmp(graph, is);
+ return tmp;
+ }
+
+ /// \brief Return a \ref GraphReader class
+ ///
+ /// This function just returns a \ref GraphReader class.
+ /// \relates GraphReader
+ /// \sa graphReader(TGR& graph, std::istream& is)
+ template <typename TGR>
+ GraphReader<TGR> graphReader(TGR& graph, const std::string& fn) {
+ GraphReader<TGR> tmp(graph, fn);
+ return tmp;
+ }
+
+ /// \brief Return a \ref GraphReader class
+ ///
+ /// This function just returns a \ref GraphReader class.
+ /// \relates GraphReader
+ /// \sa graphReader(TGR& graph, std::istream& is)
+ template <typename TGR>
+ GraphReader<TGR> graphReader(TGR& graph, const char* fn) {
+ GraphReader<TGR> tmp(graph, fn);
+ return tmp;
+ }
+
+ template <typename BGR>
+ class BpGraphReader;
+
+ template <typename TBGR>
+ BpGraphReader<TBGR> bpGraphReader(TBGR& graph, std::istream& is = std::cin);
+ template <typename TBGR>
+ BpGraphReader<TBGR> bpGraphReader(TBGR& graph, const std::string& fn);
+ template <typename TBGR>
+ BpGraphReader<TBGR> bpGraphReader(TBGR& graph, const char *fn);
+
+ /// \ingroup lemon_io
+ ///
+ /// \brief \ref lgf-format "LGF" reader for bipartite graphs
+ ///
+ /// This utility reads an \ref lgf-format "LGF" file.
+ ///
+ /// It can be used almost the same way as \c GraphReader, but it
+ /// reads the red and blue nodes from separate sections, and these
+ /// sections can contain different set of maps.
+ ///
+ /// The red and blue node maps are read from the corresponding
+ /// sections. If a map is defined with the same name in both of
+ /// these sections, then it can be read as a node map.
+ template <typename BGR>
+ class BpGraphReader {
+ public:
+
+ typedef BGR Graph;
+
+ private:
+
+ TEMPLATE_BPGRAPH_TYPEDEFS(BGR);
+
+ std::istream* _is;
+ bool local_is;
+ std::string _filename;
+
+ BGR& _graph;
+
+ std::string _nodes_caption;
+ std::string _edges_caption;
+ std::string _attributes_caption;
+
+ typedef std::map<std::string, RedNode> RedNodeIndex;
+ RedNodeIndex _red_node_index;
+ typedef std::map<std::string, BlueNode> BlueNodeIndex;
+ BlueNodeIndex _blue_node_index;
+ typedef std::map<std::string, Edge> EdgeIndex;
+ EdgeIndex _edge_index;
+
+ typedef std::vector<std::pair<std::string,
+ _reader_bits::MapStorageBase<RedNode>*> > RedNodeMaps;
+ RedNodeMaps _red_node_maps;
+ typedef std::vector<std::pair<std::string,
+ _reader_bits::MapStorageBase<BlueNode>*> > BlueNodeMaps;
+ BlueNodeMaps _blue_node_maps;
+
+ typedef std::vector<std::pair<std::string,
+ _reader_bits::MapStorageBase<Edge>*> > EdgeMaps;
+ EdgeMaps _edge_maps;
+
+ typedef std::multimap<std::string, _reader_bits::ValueStorageBase*>
+ Attributes;
+ Attributes _attributes;
+
+ bool _use_nodes;
+ bool _use_edges;
+
+ bool _skip_nodes;
+ bool _skip_edges;
+
+ int line_num;
+ std::istringstream line;
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Construct an undirected graph reader, which reads from the given
+ /// input stream.
+ BpGraphReader(BGR& graph, std::istream& is = std::cin)
+ : _is(&is), local_is(false), _graph(graph),
+ _use_nodes(false), _use_edges(false),
+ _skip_nodes(false), _skip_edges(false) {}
+
+ /// \brief Constructor
+ ///
+ /// Construct an undirected graph reader, which reads from the given
+ /// file.
+ BpGraphReader(BGR& graph, const std::string& fn)
+ : _is(new std::ifstream(fn.c_str())), local_is(true),
+ _filename(fn), _graph(graph),
+ _use_nodes(false), _use_edges(false),
+ _skip_nodes(false), _skip_edges(false) {
+ if (!(*_is)) {
+ delete _is;
+ throw IoError("Cannot open file", fn);
+ }
+ }
+
+ /// \brief Constructor
+ ///
+ /// Construct an undirected graph reader, which reads from the given
+ /// file.
+ BpGraphReader(BGR& graph, const char* fn)
+ : _is(new std::ifstream(fn)), local_is(true),
+ _filename(fn), _graph(graph),
+ _use_nodes(false), _use_edges(false),
+ _skip_nodes(false), _skip_edges(false) {
+ if (!(*_is)) {
+ delete _is;
+ throw IoError("Cannot open file", fn);
+ }
+ }
+
+ /// \brief Destructor
+ ~BpGraphReader() {
+ for (typename RedNodeMaps::iterator it = _red_node_maps.begin();
+ it != _red_node_maps.end(); ++it) {
+ delete it->second;
+ }
+
+ for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin();
+ it != _blue_node_maps.end(); ++it) {
+ delete it->second;
+ }
+
+ for (typename EdgeMaps::iterator it = _edge_maps.begin();
+ it != _edge_maps.end(); ++it) {
+ delete it->second;
+ }
+
+ for (typename Attributes::iterator it = _attributes.begin();
+ it != _attributes.end(); ++it) {
+ delete it->second;
+ }
+
+ if (local_is) {
+ delete _is;
+ }
+
+ }
+
+ private:
+ template <typename TBGR>
+ friend BpGraphReader<TBGR> bpGraphReader(TBGR& graph, std::istream& is);
+ template <typename TBGR>
+ friend BpGraphReader<TBGR> bpGraphReader(TBGR& graph,
+ const std::string& fn);
+ template <typename TBGR>
+ friend BpGraphReader<TBGR> bpGraphReader(TBGR& graph, const char *fn);
+
+ BpGraphReader(BpGraphReader& other)
+ : _is(other._is), local_is(other.local_is), _graph(other._graph),
+ _use_nodes(other._use_nodes), _use_edges(other._use_edges),
+ _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) {
+
+ other._is = 0;
+ other.local_is = false;
+
+ _red_node_index.swap(other._red_node_index);
+ _blue_node_index.swap(other._blue_node_index);
+ _edge_index.swap(other._edge_index);
+
+ _red_node_maps.swap(other._red_node_maps);
+ _blue_node_maps.swap(other._blue_node_maps);
+ _edge_maps.swap(other._edge_maps);
+ _attributes.swap(other._attributes);
+
+ _nodes_caption = other._nodes_caption;
+ _edges_caption = other._edges_caption;
+ _attributes_caption = other._attributes_caption;
+
+ }
+
+ BpGraphReader& operator=(const BpGraphReader&);
+
+ public:
+
+ /// \name Reading Rules
+ /// @{
+
+ /// \brief Node map reading rule
+ ///
+ /// Add a node map reading rule to the reader.
+ template <typename Map>
+ BpGraphReader& nodeMap(const std::string& caption, Map& map) {
+ checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
+ _reader_bits::MapStorageBase<RedNode>* red_storage =
+ new _reader_bits::MapStorage<RedNode, Map>(map);
+ _red_node_maps.push_back(std::make_pair(caption, red_storage));
+ _reader_bits::MapStorageBase<BlueNode>* blue_storage =
+ new _reader_bits::MapStorage<BlueNode, Map>(map);
+ _blue_node_maps.push_back(std::make_pair(caption, blue_storage));
+ return *this;
+ }
+
+ /// \brief Node map reading rule
+ ///
+ /// Add a node map reading rule with specialized converter to the
+ /// reader.
+ template <typename Map, typename Converter>
+ BpGraphReader& nodeMap(const std::string& caption, Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
+ _reader_bits::MapStorageBase<RedNode>* red_storage =
+ new _reader_bits::MapStorage<RedNode, Map, Converter>(map, converter);
+ _red_node_maps.push_back(std::make_pair(caption, red_storage));
+ _reader_bits::MapStorageBase<BlueNode>* blue_storage =
+ new _reader_bits::MapStorage<BlueNode, Map, Converter>(map, converter);
+ _blue_node_maps.push_back(std::make_pair(caption, blue_storage));
+ return *this;
+ }
+
+ /// Add a red node map reading rule to the reader.
+ template <typename Map>
+ BpGraphReader& redNodeMap(const std::string& caption, Map& map) {
+ checkConcept<concepts::WriteMap<RedNode, typename Map::Value>, Map>();
+ _reader_bits::MapStorageBase<RedNode>* storage =
+ new _reader_bits::MapStorage<RedNode, Map>(map);
+ _red_node_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Red node map reading rule
+ ///
+ /// Add a red node map node reading rule with specialized converter to
+ /// the reader.
+ template <typename Map, typename Converter>
+ BpGraphReader& redNodeMap(const std::string& caption, Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::WriteMap<RedNode, typename Map::Value>, Map>();
+ _reader_bits::MapStorageBase<RedNode>* storage =
+ new _reader_bits::MapStorage<RedNode, Map, Converter>(map, converter);
+ _red_node_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// Add a blue node map reading rule to the reader.
+ template <typename Map>
+ BpGraphReader& blueNodeMap(const std::string& caption, Map& map) {
+ checkConcept<concepts::WriteMap<BlueNode, typename Map::Value>, Map>();
+ _reader_bits::MapStorageBase<BlueNode>* storage =
+ new _reader_bits::MapStorage<BlueNode, Map>(map);
+ _blue_node_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Blue node map reading rule
+ ///
+ /// Add a blue node map reading rule with specialized converter to
+ /// the reader.
+ template <typename Map, typename Converter>
+ BpGraphReader& blueNodeMap(const std::string& caption, Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::WriteMap<BlueNode, typename Map::Value>, Map>();
+ _reader_bits::MapStorageBase<BlueNode>* storage =
+ new _reader_bits::MapStorage<BlueNode, Map, Converter>(map, converter);
+ _blue_node_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Edge map reading rule
+ ///
+ /// Add an edge map reading rule to the reader.
+ template <typename Map>
+ BpGraphReader& edgeMap(const std::string& caption, Map& map) {
+ checkConcept<concepts::WriteMap<Edge, typename Map::Value>, Map>();
+ _reader_bits::MapStorageBase<Edge>* storage =
+ new _reader_bits::MapStorage<Edge, Map>(map);
+ _edge_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Edge map reading rule
+ ///
+ /// Add an edge map reading rule with specialized converter to the
+ /// reader.
+ template <typename Map, typename Converter>
+ BpGraphReader& edgeMap(const std::string& caption, Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::WriteMap<Edge, typename Map::Value>, Map>();
+ _reader_bits::MapStorageBase<Edge>* storage =
+ new _reader_bits::MapStorage<Edge, Map, Converter>(map, converter);
+ _edge_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Arc map reading rule
+ ///
+ /// Add an arc map reading rule to the reader.
+ template <typename Map>
+ BpGraphReader& arcMap(const std::string& caption, Map& map) {
+ checkConcept<concepts::WriteMap<Arc, typename Map::Value>, Map>();
+ _reader_bits::MapStorageBase<Edge>* forward_storage =
+ new _reader_bits::GraphArcMapStorage<Graph, true, Map>(_graph, map);
+ _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
+ _reader_bits::MapStorageBase<Edge>* backward_storage =
+ new _reader_bits::GraphArcMapStorage<BGR, false, Map>(_graph, map);
+ _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
+ return *this;
+ }
+
+ /// \brief Arc map reading rule
+ ///
+ /// Add an arc map reading rule with specialized converter to the
+ /// reader.
+ template <typename Map, typename Converter>
+ BpGraphReader& arcMap(const std::string& caption, Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::WriteMap<Arc, typename Map::Value>, Map>();
+ _reader_bits::MapStorageBase<Edge>* forward_storage =
+ new _reader_bits::GraphArcMapStorage<BGR, true, Map, Converter>
+ (_graph, map, converter);
+ _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
+ _reader_bits::MapStorageBase<Edge>* backward_storage =
+ new _reader_bits::GraphArcMapStorage<BGR, false, Map, Converter>
+ (_graph, map, converter);
+ _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
+ return *this;
+ }
+
+ /// \brief Attribute reading rule
+ ///
+ /// Add an attribute reading rule to the reader.
+ template <typename Value>
+ BpGraphReader& attribute(const std::string& caption, Value& value) {
+ _reader_bits::ValueStorageBase* storage =
+ new _reader_bits::ValueStorage<Value>(value);
+ _attributes.insert(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Attribute reading rule
+ ///
+ /// Add an attribute reading rule with specialized converter to the
+ /// reader.
+ template <typename Value, typename Converter>
+ BpGraphReader& attribute(const std::string& caption, Value& value,
+ const Converter& converter = Converter()) {
+ _reader_bits::ValueStorageBase* storage =
+ new _reader_bits::ValueStorage<Value, Converter>(value, converter);
+ _attributes.insert(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Node reading rule
+ ///
+ /// Add a node reading rule to reader.
+ BpGraphReader& node(const std::string& caption, Node& node) {
+ typedef _reader_bits::DoubleMapLookUpConverter<
+ Node, RedNodeIndex, BlueNodeIndex> Converter;
+ Converter converter(_red_node_index, _blue_node_index);
+ _reader_bits::ValueStorageBase* storage =
+ new _reader_bits::ValueStorage<Node, Converter>(node, converter);
+ _attributes.insert(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Red node reading rule
+ ///
+ /// Add a red node reading rule to reader.
+ BpGraphReader& redNode(const std::string& caption, RedNode& node) {
+ typedef _reader_bits::MapLookUpConverter<RedNode> Converter;
+ Converter converter(_red_node_index);
+ _reader_bits::ValueStorageBase* storage =
+ new _reader_bits::ValueStorage<RedNode, Converter>(node, converter);
+ _attributes.insert(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Blue node reading rule
+ ///
+ /// Add a blue node reading rule to reader.
+ BpGraphReader& blueNode(const std::string& caption, BlueNode& node) {
+ typedef _reader_bits::MapLookUpConverter<BlueNode> Converter;
+ Converter converter(_blue_node_index);
+ _reader_bits::ValueStorageBase* storage =
+ new _reader_bits::ValueStorage<BlueNode, Converter>(node, converter);
+ _attributes.insert(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Edge reading rule
+ ///
+ /// Add an edge reading rule to reader.
+ BpGraphReader& edge(const std::string& caption, Edge& edge) {
+ typedef _reader_bits::MapLookUpConverter<Edge> Converter;
+ Converter converter(_edge_index);
+ _reader_bits::ValueStorageBase* storage =
+ new _reader_bits::ValueStorage<Edge, Converter>(edge, converter);
+ _attributes.insert(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Arc reading rule
+ ///
+ /// Add an arc reading rule to reader.
+ BpGraphReader& arc(const std::string& caption, Arc& arc) {
+ typedef _reader_bits::GraphArcLookUpConverter<BGR> Converter;
+ Converter converter(_graph, _edge_index);
+ _reader_bits::ValueStorageBase* storage =
+ new _reader_bits::ValueStorage<Arc, Converter>(arc, converter);
+ _attributes.insert(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// @}
+
+ /// \name Select Section by Name
+ /// @{
+
+ /// \brief Set \c \@nodes section to be read
+ ///
+ /// Set \c \@nodes section to be read.
+ BpGraphReader& nodes(const std::string& caption) {
+ _nodes_caption = caption;
+ return *this;
+ }
+
+ /// \brief Set \c \@edges section to be read
+ ///
+ /// Set \c \@edges section to be read.
+ BpGraphReader& edges(const std::string& caption) {
+ _edges_caption = caption;
+ return *this;
+ }
+
+ /// \brief Set \c \@attributes section to be read
+ ///
+ /// Set \c \@attributes section to be read.
+ BpGraphReader& attributes(const std::string& caption) {
+ _attributes_caption = caption;
+ return *this;
+ }
+
+ /// @}
+
+ /// \name Using Previously Constructed Node or Edge Set
+ /// @{
+
+ /// \brief Use previously constructed node set
+ ///
+ /// Use previously constructed node set, and specify the node
+ /// label map.
+ template <typename Map>
+ BpGraphReader& useNodes(const Map& map) {
+ checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
+ LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member");
+ _use_nodes = true;
+ _writer_bits::DefaultConverter<typename Map::Value> converter;
+ for (RedNodeIt n(_graph); n != INVALID; ++n) {
+ _red_node_index.insert(std::make_pair(converter(map[n]), n));
+ }
+ for (BlueNodeIt n(_graph); n != INVALID; ++n) {
+ _blue_node_index.insert(std::make_pair(converter(map[n]), n));
+ }
+ return *this;
+ }
+
+ /// \brief Use previously constructed node set
+ ///
+ /// Use previously constructed node set, and specify the node
+ /// label map and a functor which converts the label map values to
+ /// \c std::string.
+ template <typename Map, typename Converter>
+ BpGraphReader& useNodes(const Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
+ LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member");
+ _use_nodes = true;
+ for (RedNodeIt n(_graph); n != INVALID; ++n) {
+ _red_node_index.insert(std::make_pair(converter(map[n]), n));
+ }
+ for (BlueNodeIt n(_graph); n != INVALID; ++n) {
+ _blue_node_index.insert(std::make_pair(converter(map[n]), n));
+ }
+ return *this;
+ }
+
+ /// \brief Use previously constructed edge set
+ ///
+ /// Use previously constructed edge set, and specify the edge
+ /// label map.
+ template <typename Map>
+ BpGraphReader& useEdges(const Map& map) {
+ checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
+ LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member");
+ _use_edges = true;
+ _writer_bits::DefaultConverter<typename Map::Value> converter;
+ for (EdgeIt a(_graph); a != INVALID; ++a) {
+ _edge_index.insert(std::make_pair(converter(map[a]), a));
+ }
+ return *this;
+ }
+
+ /// \brief Use previously constructed edge set
+ ///
+ /// Use previously constructed edge set, and specify the edge
+ /// label map and a functor which converts the label map values to
+ /// \c std::string.
+ template <typename Map, typename Converter>
+ BpGraphReader& useEdges(const Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
+ LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member");
+ _use_edges = true;
+ for (EdgeIt a(_graph); a != INVALID; ++a) {
+ _edge_index.insert(std::make_pair(converter(map[a]), a));
+ }
+ return *this;
+ }
+
+ /// \brief Skip the reading of node section
+ ///
+ /// Omit the reading of the node section. This implies that each node
+ /// map reading rule will be abandoned, and the nodes of the graph
+ /// will not be constructed, which usually cause that the edge set
+ /// could not be read due to lack of node name
+ /// could not be read due to lack of node name resolving.
+ /// Therefore \c skipEdges() function should also be used, or
+ /// \c useNodes() should be used to specify the label of the nodes.
+ BpGraphReader& skipNodes() {
+ LEMON_ASSERT(!_skip_nodes, "Skip nodes already set");
+ _skip_nodes = true;
+ return *this;
+ }
+
+ /// \brief Skip the reading of edge section
+ ///
+ /// Omit the reading of the edge section. This implies that each edge
+ /// map reading rule will be abandoned, and the edges of the graph
+ /// will not be constructed.
+ BpGraphReader& skipEdges() {
+ LEMON_ASSERT(!_skip_edges, "Skip edges already set");
+ _skip_edges = true;
+ return *this;
+ }
+
+ /// @}
+
+ private:
+
+ bool readLine() {
+ std::string str;
+ while(++line_num, std::getline(*_is, str)) {
+ line.clear(); line.str(str);
+ char c;
+ if (line >> std::ws >> c && c != '#') {
+ line.putback(c);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool readSuccess() {
+ return static_cast<bool>(*_is);
+ }
+
+ void skipSection() {
+ char c;
+ while (readSuccess() && line >> c && c != '@') {
+ readLine();
+ }
+ if (readSuccess()) {
+ line.putback(c);
+ }
+ }
+
+ void readRedNodes() {
+
+ std::vector<int> map_index(_red_node_maps.size());
+ int map_num, label_index;
+
+ char c;
+ if (!readLine() || !(line >> c) || c == '@') {
+ if (readSuccess() && line) line.putback(c);
+ if (!_red_node_maps.empty())
+ throw FormatError("Cannot find map names");
+ return;
+ }
+ line.putback(c);
+
+ {
+ std::map<std::string, int> maps;
+
+ std::string map;
+ int index = 0;
+ while (_reader_bits::readToken(line, map)) {
+ if (maps.find(map) != maps.end()) {
+ std::ostringstream msg;
+ msg << "Multiple occurence of red node map: " << map;
+ throw FormatError(msg.str());
+ }
+ maps.insert(std::make_pair(map, index));
+ ++index;
+ }
+
+ for (int i = 0; i < static_cast<int>(_red_node_maps.size()); ++i) {
+ std::map<std::string, int>::iterator jt =
+ maps.find(_red_node_maps[i].first);
+ if (jt == maps.end()) {
+ std::ostringstream msg;
+ msg << "Map not found: " << _red_node_maps[i].first;
+ throw FormatError(msg.str());
+ }
+ map_index[i] = jt->second;
+ }
+
+ {
+ std::map<std::string, int>::iterator jt = maps.find("label");
+ if (jt != maps.end()) {
+ label_index = jt->second;
+ } else {
+ label_index = -1;
+ }
+ }
+ map_num = maps.size();
+ }
+
+ while (readLine() && line >> c && c != '@') {
+ line.putback(c);
+
+ std::vector<std::string> tokens(map_num);
+ for (int i = 0; i < map_num; ++i) {
+ if (!_reader_bits::readToken(line, tokens[i])) {
+ std::ostringstream msg;
+ msg << "Column not found (" << i + 1 << ")";
+ throw FormatError(msg.str());
+ }
+ }
+ if (line >> std::ws >> c)
+ throw FormatError("Extra character at the end of line");
+
+ RedNode n;
+ if (!_use_nodes) {
+ n = _graph.addRedNode();
+ if (label_index != -1)
+ _red_node_index.insert(std::make_pair(tokens[label_index], n));
+ } else {
+ if (label_index == -1)
+ throw FormatError("Label map not found");
+ typename std::map<std::string, RedNode>::iterator it =
+ _red_node_index.find(tokens[label_index]);
+ if (it == _red_node_index.end()) {
+ std::ostringstream msg;
+ msg << "Node with label not found: " << tokens[label_index];
+ throw FormatError(msg.str());
+ }
+ n = it->second;
+ }
+
+ for (int i = 0; i < static_cast<int>(_red_node_maps.size()); ++i) {
+ _red_node_maps[i].second->set(n, tokens[map_index[i]]);
+ }
+
+ }
+ if (readSuccess()) {
+ line.putback(c);
+ }
+ }
+
+ void readBlueNodes() {
+
+ std::vector<int> map_index(_blue_node_maps.size());
+ int map_num, label_index;
+
+ char c;
+ if (!readLine() || !(line >> c) || c == '@') {
+ if (readSuccess() && line) line.putback(c);
+ if (!_blue_node_maps.empty())
+ throw FormatError("Cannot find map names");
+ return;
+ }
+ line.putback(c);
+
+ {
+ std::map<std::string, int> maps;
+
+ std::string map;
+ int index = 0;
+ while (_reader_bits::readToken(line, map)) {
+ if (maps.find(map) != maps.end()) {
+ std::ostringstream msg;
+ msg << "Multiple occurence of blue node map: " << map;
+ throw FormatError(msg.str());
+ }
+ maps.insert(std::make_pair(map, index));
+ ++index;
+ }
+
+ for (int i = 0; i < static_cast<int>(_blue_node_maps.size()); ++i) {
+ std::map<std::string, int>::iterator jt =
+ maps.find(_blue_node_maps[i].first);
+ if (jt == maps.end()) {
+ std::ostringstream msg;
+ msg << "Map not found: " << _blue_node_maps[i].first;
+ throw FormatError(msg.str());
+ }
+ map_index[i] = jt->second;
+ }
+
+ {
+ std::map<std::string, int>::iterator jt = maps.find("label");
+ if (jt != maps.end()) {
+ label_index = jt->second;
+ } else {
+ label_index = -1;
+ }
+ }
+ map_num = maps.size();
+ }
+
+ while (readLine() && line >> c && c != '@') {
+ line.putback(c);
+
+ std::vector<std::string> tokens(map_num);
+ for (int i = 0; i < map_num; ++i) {
+ if (!_reader_bits::readToken(line, tokens[i])) {
+ std::ostringstream msg;
+ msg << "Column not found (" << i + 1 << ")";
+ throw FormatError(msg.str());
+ }
+ }
+ if (line >> std::ws >> c)
+ throw FormatError("Extra character at the end of line");
+
+ BlueNode n;
+ if (!_use_nodes) {
+ n = _graph.addBlueNode();
+ if (label_index != -1)
+ _blue_node_index.insert(std::make_pair(tokens[label_index], n));
+ } else {
+ if (label_index == -1)
+ throw FormatError("Label map not found");
+ typename std::map<std::string, BlueNode>::iterator it =
+ _blue_node_index.find(tokens[label_index]);
+ if (it == _blue_node_index.end()) {
+ std::ostringstream msg;
+ msg << "Node with label not found: " << tokens[label_index];
+ throw FormatError(msg.str());
+ }
+ n = it->second;
+ }
+
+ for (int i = 0; i < static_cast<int>(_blue_node_maps.size()); ++i) {
+ _blue_node_maps[i].second->set(n, tokens[map_index[i]]);
+ }
+
+ }
+ if (readSuccess()) {
+ line.putback(c);
+ }
+ }
+
+ void readEdges() {
+
+ std::vector<int> map_index(_edge_maps.size());
+ int map_num, label_index;
+
+ char c;
+ if (!readLine() || !(line >> c) || c == '@') {
+ if (readSuccess() && line) line.putback(c);
+ if (!_edge_maps.empty())
+ throw FormatError("Cannot find map names");
+ return;
+ }
+ line.putback(c);
+
+ {
+ std::map<std::string, int> maps;
+
+ std::string map;
+ int index = 0;
+ while (_reader_bits::readToken(line, map)) {
+ if (maps.find(map) != maps.end()) {
+ std::ostringstream msg;
+ msg << "Multiple occurence of edge map: " << map;
+ throw FormatError(msg.str());
+ }
+ maps.insert(std::make_pair(map, index));
+ ++index;
+ }
+
+ for (int i = 0; i < static_cast<int>(_edge_maps.size()); ++i) {
+ std::map<std::string, int>::iterator jt =
+ maps.find(_edge_maps[i].first);
+ if (jt == maps.end()) {
+ std::ostringstream msg;
+ msg << "Map not found: " << _edge_maps[i].first;
+ throw FormatError(msg.str());
+ }
+ map_index[i] = jt->second;
+ }
+
+ {
+ std::map<std::string, int>::iterator jt = maps.find("label");
+ if (jt != maps.end()) {
+ label_index = jt->second;
+ } else {
+ label_index = -1;
+ }
+ }
+ map_num = maps.size();
+ }
+
+ while (readLine() && line >> c && c != '@') {
+ line.putback(c);
+
+ std::string source_token;
+ std::string target_token;
+
+ if (!_reader_bits::readToken(line, source_token))
+ throw FormatError("Red node not found");
+
+ if (!_reader_bits::readToken(line, target_token))
+ throw FormatError("Blue node not found");
+
+ std::vector<std::string> tokens(map_num);
+ for (int i = 0; i < map_num; ++i) {
+ if (!_reader_bits::readToken(line, tokens[i])) {
+ std::ostringstream msg;
+ msg << "Column not found (" << i + 1 << ")";
+ throw FormatError(msg.str());
+ }
+ }
+ if (line >> std::ws >> c)
+ throw FormatError("Extra character at the end of line");
+
+ Edge e;
+ if (!_use_edges) {
+ typename RedNodeIndex::iterator rit =
+ _red_node_index.find(source_token);
+ if (rit == _red_node_index.end()) {
+ std::ostringstream msg;
+ msg << "Item not found: " << source_token;
+ throw FormatError(msg.str());
+ }
+ RedNode source = rit->second;
+ typename BlueNodeIndex::iterator it =
+ _blue_node_index.find(target_token);
+ if (it == _blue_node_index.end()) {
+ std::ostringstream msg;
+ msg << "Item not found: " << target_token;
+ throw FormatError(msg.str());
+ }
+ BlueNode target = it->second;
+
+ // It is checked that source is red and
+ // target is blue, so this should be safe:
+ e = _graph.addEdge(source, target);
+ if (label_index != -1)
+ _edge_index.insert(std::make_pair(tokens[label_index], e));
+ } else {
+ if (label_index == -1)
+ throw FormatError("Label map not found");
+ typename std::map<std::string, Edge>::iterator it =
+ _edge_index.find(tokens[label_index]);
+ if (it == _edge_index.end()) {
+ std::ostringstream msg;
+ msg << "Edge with label not found: " << tokens[label_index];
+ throw FormatError(msg.str());
+ }
+ e = it->second;
+ }
+
+ for (int i = 0; i < static_cast<int>(_edge_maps.size()); ++i) {
+ _edge_maps[i].second->set(e, tokens[map_index[i]]);
+ }
+
+ }
+ if (readSuccess()) {
+ line.putback(c);
+ }
+ }
+
+ void readAttributes() {
+
+ std::set<std::string> read_attr;
+
+ char c;
+ while (readLine() && line >> c && c != '@') {
+ line.putback(c);
+
+ std::string attr, token;
+ if (!_reader_bits::readToken(line, attr))
+ throw FormatError("Attribute name not found");
+ if (!_reader_bits::readToken(line, token))
+ throw FormatError("Attribute value not found");
+ if (line >> c)
+ throw FormatError("Extra character at the end of line");
+
+ {
+ std::set<std::string>::iterator it = read_attr.find(attr);
+ if (it != read_attr.end()) {
+ std::ostringstream msg;
+ msg << "Multiple occurence of attribute: " << attr;
+ throw FormatError(msg.str());
+ }
+ read_attr.insert(attr);
+ }
+
+ {
+ typename Attributes::iterator it = _attributes.lower_bound(attr);
+ while (it != _attributes.end() && it->first == attr) {
+ it->second->set(token);
+ ++it;
+ }
+ }
+
+ }
+ if (readSuccess()) {
+ line.putback(c);
+ }
+ for (typename Attributes::iterator it = _attributes.begin();
+ it != _attributes.end(); ++it) {
+ if (read_attr.find(it->first) == read_attr.end()) {
+ std::ostringstream msg;
+ msg << "Attribute not found: " << it->first;
+ throw FormatError(msg.str());
+ }
+ }
+ }
+
+ public:
+
+ /// \name Execution of the Reader
+ /// @{
+
+ /// \brief Start the batch processing
+ ///
+ /// This function starts the batch processing
+ void run() {
+
+ LEMON_ASSERT(_is != 0, "This reader assigned to an other reader");
+
+ bool red_nodes_done = _skip_nodes;
+ bool blue_nodes_done = _skip_nodes;
+ bool edges_done = _skip_edges;
+ bool attributes_done = false;
+
+ line_num = 0;
+ readLine();
+ skipSection();
+
+ while (readSuccess()) {
+ try {
+ char c;
+ std::string section, caption;
+ line >> c;
+ _reader_bits::readToken(line, section);
+ _reader_bits::readToken(line, caption);
+
+ if (line >> c)
+ throw FormatError("Extra character at the end of line");
+
+ if (section == "red_nodes" && !red_nodes_done) {
+ if (_nodes_caption.empty() || _nodes_caption == caption) {
+ readRedNodes();
+ red_nodes_done = true;
+ }
+ } else if (section == "blue_nodes" && !blue_nodes_done) {
+ if (_nodes_caption.empty() || _nodes_caption == caption) {
+ readBlueNodes();
+ blue_nodes_done = true;
+ }
+ } else if ((section == "edges" || section == "arcs") &&
+ !edges_done) {
+ if (_edges_caption.empty() || _edges_caption == caption) {
+ readEdges();
+ edges_done = true;
+ }
+ } else if (section == "attributes" && !attributes_done) {
+ if (_attributes_caption.empty() || _attributes_caption == caption) {
+ readAttributes();
+ attributes_done = true;
+ }
+ } else {
+ readLine();
+ skipSection();
+ }
+ } catch (FormatError& error) {
+ error.line(line_num);
+ error.file(_filename);
+ throw;
+ }
+ }
+
+ if (!red_nodes_done) {
+ throw FormatError("Section @red_nodes not found");
+ }
+
+ if (!blue_nodes_done) {
+ throw FormatError("Section @blue_nodes not found");
+ }
+
+ if (!edges_done) {
+ throw FormatError("Section @edges not found");
+ }
+
+ if (!attributes_done && !_attributes.empty()) {
+ throw FormatError("Section @attributes not found");
+ }
+
+ }
+
+ /// @}
+
+ };
+
+ /// \ingroup lemon_io
+ ///
+ /// \brief Return a \ref lemon::BpGraphReader "BpGraphReader" class
+ ///
+ /// This function just returns a \ref lemon::BpGraphReader
+ /// "BpGraphReader" class.
+ ///
+ /// With this function a graph can be read from an
+ /// \ref lgf-format "LGF" file or input stream with several maps and
+ /// attributes. For example, there is bipartite weighted matching problem
+ /// on a graph, i.e. a graph with a \e weight map on the edges. This
+ /// graph can be read with the following code:
+ ///
+ ///\code
+ ///ListBpGraph graph;
+ ///ListBpGraph::EdgeMap<int> weight(graph);
+ ///bpGraphReader(graph, std::cin).
+ /// edgeMap("weight", weight).
+ /// run();
+ ///\endcode
+ ///
+ /// For a complete documentation, please see the
+ /// \ref lemon::BpGraphReader "BpGraphReader"
+ /// class documentation.
+ /// \warning Don't forget to put the \ref lemon::BpGraphReader::run() "run()"
+ /// to the end of the parameter list.
+ /// \relates BpGraphReader
+ /// \sa bpGraphReader(TBGR& graph, const std::string& fn)
+ /// \sa bpGraphReader(TBGR& graph, const char* fn)
+ template <typename TBGR>
+ BpGraphReader<TBGR> bpGraphReader(TBGR& graph, std::istream& is) {
+ BpGraphReader<TBGR> tmp(graph, is);
+ return tmp;
+ }
+
+ /// \brief Return a \ref BpGraphReader class
+ ///
+ /// This function just returns a \ref BpGraphReader class.
+ /// \relates BpGraphReader
+ /// \sa bpGraphReader(TBGR& graph, std::istream& is)
+ template <typename TBGR>
+ BpGraphReader<TBGR> bpGraphReader(TBGR& graph, const std::string& fn) {
+ BpGraphReader<TBGR> tmp(graph, fn);
+ return tmp;
+ }
+
+ /// \brief Return a \ref BpGraphReader class
+ ///
+ /// This function just returns a \ref BpGraphReader class.
+ /// \relates BpGraphReader
+ /// \sa bpGraphReader(TBGR& graph, std::istream& is)
+ template <typename TBGR>
+ BpGraphReader<TBGR> bpGraphReader(TBGR& graph, const char* fn) {
+ BpGraphReader<TBGR> tmp(graph, fn);
+ return tmp;
+ }
+
+ class SectionReader;
+
+ SectionReader sectionReader(std::istream& is);
+ SectionReader sectionReader(const std::string& fn);
+ SectionReader sectionReader(const char* fn);
+
+ /// \ingroup lemon_io
+ ///
+ /// \brief Section reader class
+ ///
+ /// In the \ref lgf-format "LGF" file extra sections can be placed,
+ /// which contain any data in arbitrary format. Such sections can be
+ /// read with this class. A reading rule can be added to the class
+ /// with two different functions. With the \c sectionLines() function a
+ /// functor can process the section line-by-line, while with the \c
+ /// sectionStream() member the section can be read from an input
+ /// stream.
+ class SectionReader {
+ private:
+
+ std::istream* _is;
+ bool local_is;
+ std::string _filename;
+
+ typedef std::map<std::string, _reader_bits::Section*> Sections;
+ Sections _sections;
+
+ int line_num;
+ std::istringstream line;
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Construct a section reader, which reads from the given input
+ /// stream.
+ SectionReader(std::istream& is)
+ : _is(&is), local_is(false) {}
+
+ /// \brief Constructor
+ ///
+ /// Construct a section reader, which reads from the given file.
+ SectionReader(const std::string& fn)
+ : _is(new std::ifstream(fn.c_str())), local_is(true),
+ _filename(fn) {
+ if (!(*_is)) {
+ delete _is;
+ throw IoError("Cannot open file", fn);
+ }
+ }
+
+ /// \brief Constructor
+ ///
+ /// Construct a section reader, which reads from the given file.
+ SectionReader(const char* fn)
+ : _is(new std::ifstream(fn)), local_is(true),
+ _filename(fn) {
+ if (!(*_is)) {
+ delete _is;
+ throw IoError("Cannot open file", fn);
+ }
+ }
+
+ /// \brief Destructor
+ ~SectionReader() {
+ for (Sections::iterator it = _sections.begin();
+ it != _sections.end(); ++it) {
+ delete it->second;
+ }
+
+ if (local_is) {
+ delete _is;
+ }
+
+ }
+
+ private:
+
+ friend SectionReader sectionReader(std::istream& is);
+ friend SectionReader sectionReader(const std::string& fn);
+ friend SectionReader sectionReader(const char* fn);
+
+ SectionReader(SectionReader& other)
+ : _is(other._is), local_is(other.local_is) {
+
+ other._is = 0;
+ other.local_is = false;
+
+ _sections.swap(other._sections);
+ }
+
+ SectionReader& operator=(const SectionReader&);
+
+ public:
+
+ /// \name Section Readers
+ /// @{
+
+ /// \brief Add a section processor with line oriented reading
+ ///
+ /// The first parameter is the type descriptor of the section, the
+ /// second is a functor, which takes just one \c std::string
+ /// parameter. At the reading process, each line of the section
+ /// will be given to the functor object. However, the empty lines
+ /// and the comment lines are filtered out, and the leading
+ /// whitespaces are trimmed from each processed string.
+ ///
+ /// For example, let's see a section, which contain several
+ /// integers, which should be inserted into a vector.
+ ///\code
+ /// @numbers
+ /// 12 45 23
+ /// 4
+ /// 23 6
+ ///\endcode
+ ///
+ /// The functor is implemented as a struct:
+ ///\code
+ /// struct NumberSection {
+ /// std::vector<int>& _data;
+ /// NumberSection(std::vector<int>& data) : _data(data) {}
+ /// void operator()(const std::string& line) {
+ /// std::istringstream ls(line);
+ /// int value;
+ /// while (ls >> value) _data.push_back(value);
+ /// }
+ /// };
+ ///
+ /// // ...
+ ///
+ /// reader.sectionLines("numbers", NumberSection(vec));
+ ///\endcode
+ template <typename Functor>
+ SectionReader& sectionLines(const std::string& type, Functor functor) {
+ LEMON_ASSERT(!type.empty(), "Type is empty.");
+ LEMON_ASSERT(_sections.find(type) == _sections.end(),
+ "Multiple reading of section.");
+ _sections.insert(std::make_pair(type,
+ new _reader_bits::LineSection<Functor>(functor)));
+ return *this;
+ }
+
+
+ /// \brief Add a section processor with stream oriented reading
+ ///
+ /// The first parameter is the type of the section, the second is
+ /// a functor, which takes an \c std::istream& and an \c int&
+ /// parameter, the latter regard to the line number of stream. The
+ /// functor can read the input while the section go on, and the
+ /// line number should be modified accordingly.
+ template <typename Functor>
+ SectionReader& sectionStream(const std::string& type, Functor functor) {
+ LEMON_ASSERT(!type.empty(), "Type is empty.");
+ LEMON_ASSERT(_sections.find(type) == _sections.end(),
+ "Multiple reading of section.");
+ _sections.insert(std::make_pair(type,
+ new _reader_bits::StreamSection<Functor>(functor)));
+ return *this;
+ }
+
+ /// @}
+
+ private:
+
+ bool readLine() {
+ std::string str;
+ while(++line_num, std::getline(*_is, str)) {
+ line.clear(); line.str(str);
+ char c;
+ if (line >> std::ws >> c && c != '#') {
+ line.putback(c);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool readSuccess() {
+ return static_cast<bool>(*_is);
+ }
+
+ void skipSection() {
+ char c;
+ while (readSuccess() && line >> c && c != '@') {
+ readLine();
+ }
+ if (readSuccess()) {
+ line.putback(c);
+ }
+ }
+
+ public:
+
+
+ /// \name Execution of the Reader
+ /// @{
+
+ /// \brief Start the batch processing
+ ///
+ /// This function starts the batch processing.
+ void run() {
+
+ LEMON_ASSERT(_is != 0, "This reader assigned to an other reader");
+
+ std::set<std::string> extra_sections;
+
+ line_num = 0;
+ readLine();
+ skipSection();
+
+ while (readSuccess()) {
+ try {
+ char c;
+ std::string section, caption;
+ line >> c;
+ _reader_bits::readToken(line, section);
+ _reader_bits::readToken(line, caption);
+
+ if (line >> c)
+ throw FormatError("Extra character at the end of line");
+
+ if (extra_sections.find(section) != extra_sections.end()) {
+ std::ostringstream msg;
+ msg << "Multiple occurence of section: " << section;
+ throw FormatError(msg.str());
+ }
+ Sections::iterator it = _sections.find(section);
+ if (it != _sections.end()) {
+ extra_sections.insert(section);
+ it->second->process(*_is, line_num);
+ }
+ readLine();
+ skipSection();
+ } catch (FormatError& error) {
+ error.line(line_num);
+ error.file(_filename);
+ throw;
+ }
+ }
+ for (Sections::iterator it = _sections.begin();
+ it != _sections.end(); ++it) {
+ if (extra_sections.find(it->first) == extra_sections.end()) {
+ std::ostringstream os;
+ os << "Cannot find section: " << it->first;
+ throw FormatError(os.str());
+ }
+ }
+ }
+
+ /// @}
+
+ };
+
+ /// \ingroup lemon_io
+ ///
+ /// \brief Return a \ref SectionReader class
+ ///
+ /// This function just returns a \ref SectionReader class.
+ ///
+ /// Please see SectionReader documentation about the custom section
+ /// input.
+ ///
+ /// \relates SectionReader
+ /// \sa sectionReader(const std::string& fn)
+ /// \sa sectionReader(const char *fn)
+ inline SectionReader sectionReader(std::istream& is) {
+ SectionReader tmp(is);
+ return tmp;
+ }
+
+ /// \brief Return a \ref SectionReader class
+ ///
+ /// This function just returns a \ref SectionReader class.
+ /// \relates SectionReader
+ /// \sa sectionReader(std::istream& is)
+ inline SectionReader sectionReader(const std::string& fn) {
+ SectionReader tmp(fn);
+ return tmp;
+ }
+
+ /// \brief Return a \ref SectionReader class
+ ///
+ /// This function just returns a \ref SectionReader class.
+ /// \relates SectionReader
+ /// \sa sectionReader(std::istream& is)
+ inline SectionReader sectionReader(const char* fn) {
+ SectionReader tmp(fn);
+ return tmp;
+ }
+
+ /// \ingroup lemon_io
+ ///
+ /// \brief Reader for the contents of the \ref lgf-format "LGF" file
+ ///
+ /// This class can be used to read the sections, the map names and
+ /// the attributes from a file. Usually, the LEMON programs know
+ /// that, which type of graph, which maps and which attributes
+ /// should be read from a file, but in general tools (like glemon)
+ /// the contents of an LGF file should be guessed somehow. This class
+ /// reads the graph and stores the appropriate information for
+ /// reading the graph.
+ ///
+ ///\code
+ /// LgfContents contents("graph.lgf");
+ /// contents.run();
+ ///
+ /// // Does it contain any node section and arc section?
+ /// if (contents.nodeSectionNum() == 0 || contents.arcSectionNum()) {
+ /// std::cerr << "Failure, cannot find graph." << std::endl;
+ /// return -1;
+ /// }
+ /// std::cout << "The name of the default node section: "
+ /// << contents.nodeSection(0) << std::endl;
+ /// std::cout << "The number of the arc maps: "
+ /// << contents.arcMaps(0).size() << std::endl;
+ /// std::cout << "The name of second arc map: "
+ /// << contents.arcMaps(0)[1] << std::endl;
+ ///\endcode
+ class LgfContents {
+ private:
+
+ std::istream* _is;
+ bool local_is;
+
+ std::vector<std::string> _node_sections;
+ std::vector<std::string> _edge_sections;
+ std::vector<std::string> _attribute_sections;
+ std::vector<std::string> _extra_sections;
+
+ std::vector<bool> _arc_sections;
+
+ std::vector<std::vector<std::string> > _node_maps;
+ std::vector<std::vector<std::string> > _edge_maps;
+
+ std::vector<std::vector<std::string> > _attributes;
+
+
+ int line_num;
+ std::istringstream line;
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Construct an \e LGF contents reader, which reads from the given
+ /// input stream.
+ LgfContents(std::istream& is)
+ : _is(&is), local_is(false) {}
+
+ /// \brief Constructor
+ ///
+ /// Construct an \e LGF contents reader, which reads from the given
+ /// file.
+ LgfContents(const std::string& fn)
+ : _is(new std::ifstream(fn.c_str())), local_is(true) {
+ if (!(*_is)) {
+ delete _is;
+ throw IoError("Cannot open file", fn);
+ }
+ }
+
+ /// \brief Constructor
+ ///
+ /// Construct an \e LGF contents reader, which reads from the given
+ /// file.
+ LgfContents(const char* fn)
+ : _is(new std::ifstream(fn)), local_is(true) {
+ if (!(*_is)) {
+ delete _is;
+ throw IoError("Cannot open file", fn);
+ }
+ }
+
+ /// \brief Destructor
+ ~LgfContents() {
+ if (local_is) delete _is;
+ }
+
+ private:
+
+ LgfContents(const LgfContents&);
+ LgfContents& operator=(const LgfContents&);
+
+ public:
+
+
+ /// \name Node Sections
+ /// @{
+
+ /// \brief Gives back the number of node sections in the file.
+ ///
+ /// Gives back the number of node sections in the file.
+ int nodeSectionNum() const {
+ return _node_sections.size();
+ }
+
+ /// \brief Returns the node section name at the given position.
+ ///
+ /// Returns the node section name at the given position.
+ const std::string& nodeSection(int i) const {
+ return _node_sections[i];
+ }
+
+ /// \brief Gives back the node maps for the given section.
+ ///
+ /// Gives back the node maps for the given section.
+ const std::vector<std::string>& nodeMapNames(int i) const {
+ return _node_maps[i];
+ }
+
+ /// @}
+
+ /// \name Arc/Edge Sections
+ /// @{
+
+ /// \brief Gives back the number of arc/edge sections in the file.
+ ///
+ /// Gives back the number of arc/edge sections in the file.
+ /// \note It is synonym of \c edgeSectionNum().
+ int arcSectionNum() const {
+ return _edge_sections.size();
+ }
+
+ /// \brief Returns the arc/edge section name at the given position.
+ ///
+ /// Returns the arc/edge section name at the given position.
+ /// \note It is synonym of \c edgeSection().
+ const std::string& arcSection(int i) const {
+ return _edge_sections[i];
+ }
+
+ /// \brief Gives back the arc/edge maps for the given section.
+ ///
+ /// Gives back the arc/edge maps for the given section.
+ /// \note It is synonym of \c edgeMapNames().
+ const std::vector<std::string>& arcMapNames(int i) const {
+ return _edge_maps[i];
+ }
+
+ /// @}
+
+ /// \name Synonyms
+ /// @{
+
+ /// \brief Gives back the number of arc/edge sections in the file.
+ ///
+ /// Gives back the number of arc/edge sections in the file.
+ /// \note It is synonym of \c arcSectionNum().
+ int edgeSectionNum() const {
+ return _edge_sections.size();
+ }
+
+ /// \brief Returns the section name at the given position.
+ ///
+ /// Returns the section name at the given position.
+ /// \note It is synonym of \c arcSection().
+ const std::string& edgeSection(int i) const {
+ return _edge_sections[i];
+ }
+
+ /// \brief Gives back the edge maps for the given section.
+ ///
+ /// Gives back the edge maps for the given section.
+ /// \note It is synonym of \c arcMapNames().
+ const std::vector<std::string>& edgeMapNames(int i) const {
+ return _edge_maps[i];
+ }
+
+ /// @}
+
+ /// \name Attribute Sections
+ /// @{
+
+ /// \brief Gives back the number of attribute sections in the file.
+ ///
+ /// Gives back the number of attribute sections in the file.
+ int attributeSectionNum() const {
+ return _attribute_sections.size();
+ }
+
+ /// \brief Returns the attribute section name at the given position.
+ ///
+ /// Returns the attribute section name at the given position.
+ const std::string& attributeSectionNames(int i) const {
+ return _attribute_sections[i];
+ }
+
+ /// \brief Gives back the attributes for the given section.
+ ///
+ /// Gives back the attributes for the given section.
+ const std::vector<std::string>& attributes(int i) const {
+ return _attributes[i];
+ }
+
+ /// @}
+
+ /// \name Extra Sections
+ /// @{
+
+ /// \brief Gives back the number of extra sections in the file.
+ ///
+ /// Gives back the number of extra sections in the file.
+ int extraSectionNum() const {
+ return _extra_sections.size();
+ }
+
+ /// \brief Returns the extra section type at the given position.
+ ///
+ /// Returns the section type at the given position.
+ const std::string& extraSection(int i) const {
+ return _extra_sections[i];
+ }
+
+ /// @}
+
+ private:
+
+ bool readLine() {
+ std::string str;
+ while(++line_num, std::getline(*_is, str)) {
+ line.clear(); line.str(str);
+ char c;
+ if (line >> std::ws >> c && c != '#') {
+ line.putback(c);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool readSuccess() {
+ return static_cast<bool>(*_is);
+ }
+
+ void skipSection() {
+ char c;
+ while (readSuccess() && line >> c && c != '@') {
+ readLine();
+ }
+ if (readSuccess()) {
+ line.putback(c);
+ }
+ }
+
+ void readMaps(std::vector<std::string>& maps) {
+ char c;
+ if (!readLine() || !(line >> c) || c == '@') {
+ if (readSuccess() && line) line.putback(c);
+ return;
+ }
+ line.putback(c);
+ std::string map;
+ while (_reader_bits::readToken(line, map)) {
+ maps.push_back(map);
+ }
+ }
+
+ void readAttributes(std::vector<std::string>& attrs) {
+ readLine();
+ char c;
+ while (readSuccess() && line >> c && c != '@') {
+ line.putback(c);
+ std::string attr;
+ _reader_bits::readToken(line, attr);
+ attrs.push_back(attr);
+ readLine();
+ }
+ line.putback(c);
+ }
+
+ public:
+
+ /// \name Execution of the Contents Reader
+ /// @{
+
+ /// \brief Starts the reading
+ ///
+ /// This function starts the reading.
+ void run() {
+
+ readLine();
+ skipSection();
+
+ while (readSuccess()) {
+
+ char c;
+ line >> c;
+
+ std::string section, caption;
+ _reader_bits::readToken(line, section);
+ _reader_bits::readToken(line, caption);
+
+ if (section == "nodes") {
+ _node_sections.push_back(caption);
+ _node_maps.push_back(std::vector<std::string>());
+ readMaps(_node_maps.back());
+ readLine(); skipSection();
+ } else if (section == "arcs" || section == "edges") {
+ _edge_sections.push_back(caption);
+ _arc_sections.push_back(section == "arcs");
+ _edge_maps.push_back(std::vector<std::string>());
+ readMaps(_edge_maps.back());
+ readLine(); skipSection();
+ } else if (section == "attributes") {
+ _attribute_sections.push_back(caption);
+ _attributes.push_back(std::vector<std::string>());
+ readAttributes(_attributes.back());
+ } else {
+ _extra_sections.push_back(section);
+ readLine(); skipSection();
+ }
+ }
+ }
+
+ /// @}
+
+ };
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_writer.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_writer.h
new file mode 100644
index 00000000000..0695287d518
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_writer.h
@@ -0,0 +1,2687 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+///\ingroup lemon_io
+///\file
+///\brief \ref lgf-format "LEMON Graph Format" writer.
+
+
+#ifndef LEMON_LGF_WRITER_H
+#define LEMON_LGF_WRITER_H
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+
+#include <algorithm>
+
+#include <vector>
+#include <functional>
+
+#include <lemon/core.h>
+#include <lemon/maps.h>
+
+#include <lemon/concept_check.h>
+#include <lemon/concepts/maps.h>
+
+namespace lemon {
+
+ namespace _writer_bits {
+
+ template <typename Value>
+ struct DefaultConverter {
+ std::string operator()(const Value& value) {
+ std::ostringstream os;
+ os << value;
+ return os.str();
+ }
+ };
+
+ template <typename T>
+ bool operator<(const T&, const T&) {
+ throw FormatError("Label map is not comparable");
+ }
+
+ template <typename _Map>
+ class MapLess {
+ public:
+ typedef _Map Map;
+ typedef typename Map::Key Item;
+
+ private:
+ const Map& _map;
+
+ public:
+ MapLess(const Map& map) : _map(map) {}
+
+ bool operator()(const Item& left, const Item& right) {
+ return _map[left] < _map[right];
+ }
+ };
+
+ template <typename _Graph, bool _dir, typename _Map>
+ class GraphArcMapLess {
+ public:
+ typedef _Map Map;
+ typedef _Graph Graph;
+ typedef typename Graph::Edge Item;
+
+ private:
+ const Graph& _graph;
+ const Map& _map;
+
+ public:
+ GraphArcMapLess(const Graph& graph, const Map& map)
+ : _graph(graph), _map(map) {}
+
+ bool operator()(const Item& left, const Item& right) {
+ return _map[_graph.direct(left, _dir)] <
+ _map[_graph.direct(right, _dir)];
+ }
+ };
+
+ template <typename _Item>
+ class MapStorageBase {
+ public:
+ typedef _Item Item;
+
+ public:
+ MapStorageBase() {}
+ virtual ~MapStorageBase() {}
+
+ virtual std::string get(const Item& item) = 0;
+ virtual void sort(std::vector<Item>&) = 0;
+ };
+
+ template <typename _Item, typename _Map,
+ typename _Converter = DefaultConverter<typename _Map::Value> >
+ class MapStorage : public MapStorageBase<_Item> {
+ public:
+ typedef _Map Map;
+ typedef _Converter Converter;
+ typedef _Item Item;
+
+ private:
+ const Map& _map;
+ Converter _converter;
+
+ public:
+ MapStorage(const Map& map, const Converter& converter = Converter())
+ : _map(map), _converter(converter) {}
+ virtual ~MapStorage() {}
+
+ virtual std::string get(const Item& item) {
+ return _converter(_map[item]);
+ }
+ virtual void sort(std::vector<Item>& items) {
+ MapLess<Map> less(_map);
+ std::sort(items.begin(), items.end(), less);
+ }
+ };
+
+ template <typename _Graph, bool _dir, typename _Map,
+ typename _Converter = DefaultConverter<typename _Map::Value> >
+ class GraphArcMapStorage : public MapStorageBase<typename _Graph::Edge> {
+ public:
+ typedef _Map Map;
+ typedef _Converter Converter;
+ typedef _Graph Graph;
+ typedef typename Graph::Edge Item;
+ static const bool dir = _dir;
+
+ private:
+ const Graph& _graph;
+ const Map& _map;
+ Converter _converter;
+
+ public:
+ GraphArcMapStorage(const Graph& graph, const Map& map,
+ const Converter& converter = Converter())
+ : _graph(graph), _map(map), _converter(converter) {}
+ virtual ~GraphArcMapStorage() {}
+
+ virtual std::string get(const Item& item) {
+ return _converter(_map[_graph.direct(item, dir)]);
+ }
+ virtual void sort(std::vector<Item>& items) {
+ GraphArcMapLess<Graph, dir, Map> less(_graph, _map);
+ std::sort(items.begin(), items.end(), less);
+ }
+ };
+
+ class ValueStorageBase {
+ public:
+ ValueStorageBase() {}
+ virtual ~ValueStorageBase() {}
+
+ virtual std::string get() = 0;
+ };
+
+ template <typename _Value, typename _Converter = DefaultConverter<_Value> >
+ class ValueStorage : public ValueStorageBase {
+ public:
+ typedef _Value Value;
+ typedef _Converter Converter;
+
+ private:
+ const Value& _value;
+ Converter _converter;
+
+ public:
+ ValueStorage(const Value& value, const Converter& converter = Converter())
+ : _value(value), _converter(converter) {}
+
+ virtual std::string get() {
+ return _converter(_value);
+ }
+ };
+
+ template <typename Value,
+ typename Map = std::map<Value, std::string> >
+ struct MapLookUpConverter {
+ const Map& _map;
+
+ MapLookUpConverter(const Map& map)
+ : _map(map) {}
+
+ std::string operator()(const Value& value) {
+ typename Map::const_iterator it = _map.find(value);
+ if (it == _map.end()) {
+ throw FormatError("Item not found");
+ }
+ return it->second;
+ }
+ };
+
+ template <typename Value,
+ typename Map1 = std::map<Value, std::string>,
+ typename Map2 = std::map<Value, std::string> >
+ struct DoubleMapLookUpConverter {
+ const Map1& _map1;
+ const Map2& _map2;
+
+ DoubleMapLookUpConverter(const Map1& map1, const Map2& map2)
+ : _map1(map1), _map2(map2) {}
+
+ std::string operator()(const Value& value) {
+ typename Map1::const_iterator it1 = _map1.find(value);
+ typename Map1::const_iterator it2 = _map2.find(value);
+ if (it1 == _map1.end()) {
+ if (it2 == _map2.end()) {
+ throw FormatError("Item not found");
+ } else {
+ return it2->second;
+ }
+ } else {
+ if (it2 == _map2.end()) {
+ return it1->second;
+ } else {
+ throw FormatError("Item is ambigous");
+ }
+ }
+ }
+ };
+
+ template <typename Graph>
+ struct GraphArcLookUpConverter {
+ const Graph& _graph;
+ const std::map<typename Graph::Edge, std::string>& _map;
+
+ GraphArcLookUpConverter(const Graph& graph,
+ const std::map<typename Graph::Edge,
+ std::string>& map)
+ : _graph(graph), _map(map) {}
+
+ std::string operator()(const typename Graph::Arc& val) {
+ typename std::map<typename Graph::Edge, std::string>
+ ::const_iterator it = _map.find(val);
+ if (it == _map.end()) {
+ throw FormatError("Item not found");
+ }
+ return (_graph.direction(val) ? '+' : '-') + it->second;
+ }
+ };
+
+ inline bool isWhiteSpace(char c) {
+ return c == ' ' || c == '\t' || c == '\v' ||
+ c == '\n' || c == '\r' || c == '\f';
+ }
+
+ inline bool isEscaped(char c) {
+ return c == '\\' || c == '\"' || c == '\'' ||
+ c == '\a' || c == '\b';
+ }
+
+ inline static void writeEscape(std::ostream& os, char c) {
+ switch (c) {
+ case '\\':
+ os << "\\\\";
+ return;
+ case '\"':
+ os << "\\\"";
+ return;
+ case '\a':
+ os << "\\a";
+ return;
+ case '\b':
+ os << "\\b";
+ return;
+ case '\f':
+ os << "\\f";
+ return;
+ case '\r':
+ os << "\\r";
+ return;
+ case '\n':
+ os << "\\n";
+ return;
+ case '\t':
+ os << "\\t";
+ return;
+ case '\v':
+ os << "\\v";
+ return;
+ default:
+ if (c < 0x20) {
+ std::ios::fmtflags flags = os.flags();
+ os << '\\' << std::oct << static_cast<int>(c);
+ os.flags(flags);
+ } else {
+ os << c;
+ }
+ return;
+ }
+ }
+
+ inline bool requireEscape(const std::string& str) {
+ if (str.empty() || str[0] == '@') return true;
+ std::istringstream is(str);
+ char c;
+ while (is.get(c)) {
+ if (isWhiteSpace(c) || isEscaped(c)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ inline std::ostream& writeToken(std::ostream& os, const std::string& str) {
+
+ if (requireEscape(str)) {
+ os << '\"';
+ for (std::string::const_iterator it = str.begin();
+ it != str.end(); ++it) {
+ writeEscape(os, *it);
+ }
+ os << '\"';
+ } else {
+ os << str;
+ }
+ return os;
+ }
+
+ class Section {
+ public:
+ virtual ~Section() {}
+ virtual void process(std::ostream& os) = 0;
+ };
+
+ template <typename Functor>
+ class LineSection : public Section {
+ private:
+
+ Functor _functor;
+
+ public:
+
+ LineSection(const Functor& functor) : _functor(functor) {}
+ virtual ~LineSection() {}
+
+ virtual void process(std::ostream& os) {
+ std::string line;
+ while (!(line = _functor()).empty()) os << line << std::endl;
+ }
+ };
+
+ template <typename Functor>
+ class StreamSection : public Section {
+ private:
+
+ Functor _functor;
+
+ public:
+
+ StreamSection(const Functor& functor) : _functor(functor) {}
+ virtual ~StreamSection() {}
+
+ virtual void process(std::ostream& os) {
+ _functor(os);
+ }
+ };
+
+ }
+
+ template <typename DGR>
+ class DigraphWriter;
+
+ template <typename TDGR>
+ DigraphWriter<TDGR> digraphWriter(const TDGR& digraph,
+ std::ostream& os = std::cout);
+ template <typename TDGR>
+ DigraphWriter<TDGR> digraphWriter(const TDGR& digraph, const std::string& fn);
+
+ template <typename TDGR>
+ DigraphWriter<TDGR> digraphWriter(const TDGR& digraph, const char* fn);
+
+
+ /// \ingroup lemon_io
+ ///
+ /// \brief \ref lgf-format "LGF" writer for directed graphs
+ ///
+ /// This utility writes an \ref lgf-format "LGF" file.
+ ///
+ /// The writing method does a batch processing. The user creates a
+ /// writer object, then various writing rules can be added to the
+ /// writer, and eventually the writing is executed with the \c run()
+ /// member function. A map writing rule can be added to the writer
+ /// with the \c nodeMap() or \c arcMap() members. An optional
+ /// converter parameter can also be added as a standard functor
+ /// converting from the value type of the map to \c std::string. If it
+ /// is set, it will determine how the value type of the map is written to
+ /// the output stream. If the functor is not set, then a default
+ /// conversion will be used. The \c attribute(), \c node() and \c
+ /// arc() functions are used to add attribute writing rules.
+ ///
+ ///\code
+ /// DigraphWriter<DGR>(digraph, std::cout).
+ /// nodeMap("coordinates", coord_map).
+ /// nodeMap("size", size).
+ /// nodeMap("title", title).
+ /// arcMap("capacity", cap_map).
+ /// node("source", src).
+ /// node("target", trg).
+ /// attribute("caption", caption).
+ /// run();
+ ///\endcode
+ ///
+ ///
+ /// By default, the writer does not write additional captions to the
+ /// sections, but they can be give as an optional parameter of
+ /// the \c nodes(), \c arcs() or \c
+ /// attributes() functions.
+ ///
+ /// The \c skipNodes() and \c skipArcs() functions forbid the
+ /// writing of the sections. If two arc sections should be written
+ /// to the output, it can be done in two passes, the first pass
+ /// writes the node section and the first arc section, then the
+ /// second pass skips the node section and writes just the arc
+ /// section to the stream. The output stream can be retrieved with
+ /// the \c ostream() function, hence the second pass can append its
+ /// output to the output of the first pass.
+ template <typename DGR>
+ class DigraphWriter {
+ public:
+
+ typedef DGR Digraph;
+ TEMPLATE_DIGRAPH_TYPEDEFS(DGR);
+
+ private:
+
+
+ std::ostream* _os;
+ bool local_os;
+
+ const DGR& _digraph;
+
+ std::string _nodes_caption;
+ std::string _arcs_caption;
+ std::string _attributes_caption;
+
+ typedef std::map<Node, std::string> NodeIndex;
+ NodeIndex _node_index;
+ typedef std::map<Arc, std::string> ArcIndex;
+ ArcIndex _arc_index;
+
+ typedef std::vector<std::pair<std::string,
+ _writer_bits::MapStorageBase<Node>* > > NodeMaps;
+ NodeMaps _node_maps;
+
+ typedef std::vector<std::pair<std::string,
+ _writer_bits::MapStorageBase<Arc>* > >ArcMaps;
+ ArcMaps _arc_maps;
+
+ typedef std::vector<std::pair<std::string,
+ _writer_bits::ValueStorageBase*> > Attributes;
+ Attributes _attributes;
+
+ bool _skip_nodes;
+ bool _skip_arcs;
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Construct a directed graph writer, which writes to the given
+ /// output stream.
+ DigraphWriter(const DGR& digraph, std::ostream& os = std::cout)
+ : _os(&os), local_os(false), _digraph(digraph),
+ _skip_nodes(false), _skip_arcs(false) {}
+
+ /// \brief Constructor
+ ///
+ /// Construct a directed graph writer, which writes to the given
+ /// output file.
+ DigraphWriter(const DGR& digraph, const std::string& fn)
+ : _os(new std::ofstream(fn.c_str())), local_os(true), _digraph(digraph),
+ _skip_nodes(false), _skip_arcs(false) {
+ if (!(*_os)) {
+ delete _os;
+ throw IoError("Cannot write file", fn);
+ }
+ }
+
+ /// \brief Constructor
+ ///
+ /// Construct a directed graph writer, which writes to the given
+ /// output file.
+ DigraphWriter(const DGR& digraph, const char* fn)
+ : _os(new std::ofstream(fn)), local_os(true), _digraph(digraph),
+ _skip_nodes(false), _skip_arcs(false) {
+ if (!(*_os)) {
+ delete _os;
+ throw IoError("Cannot write file", fn);
+ }
+ }
+
+ /// \brief Destructor
+ ~DigraphWriter() {
+ for (typename NodeMaps::iterator it = _node_maps.begin();
+ it != _node_maps.end(); ++it) {
+ delete it->second;
+ }
+
+ for (typename ArcMaps::iterator it = _arc_maps.begin();
+ it != _arc_maps.end(); ++it) {
+ delete it->second;
+ }
+
+ for (typename Attributes::iterator it = _attributes.begin();
+ it != _attributes.end(); ++it) {
+ delete it->second;
+ }
+
+ if (local_os) {
+ delete _os;
+ }
+ }
+
+ private:
+
+ template <typename TDGR>
+ friend DigraphWriter<TDGR> digraphWriter(const TDGR& digraph,
+ std::ostream& os);
+ template <typename TDGR>
+ friend DigraphWriter<TDGR> digraphWriter(const TDGR& digraph,
+ const std::string& fn);
+ template <typename TDGR>
+ friend DigraphWriter<TDGR> digraphWriter(const TDGR& digraph,
+ const char *fn);
+
+ DigraphWriter(DigraphWriter& other)
+ : _os(other._os), local_os(other.local_os), _digraph(other._digraph),
+ _skip_nodes(other._skip_nodes), _skip_arcs(other._skip_arcs) {
+
+ other._os = 0;
+ other.local_os = false;
+
+ _node_index.swap(other._node_index);
+ _arc_index.swap(other._arc_index);
+
+ _node_maps.swap(other._node_maps);
+ _arc_maps.swap(other._arc_maps);
+ _attributes.swap(other._attributes);
+
+ _nodes_caption = other._nodes_caption;
+ _arcs_caption = other._arcs_caption;
+ _attributes_caption = other._attributes_caption;
+ }
+
+ DigraphWriter& operator=(const DigraphWriter&);
+
+ public:
+
+ /// \name Writing Rules
+ /// @{
+
+ /// \brief Node map writing rule
+ ///
+ /// Add a node map writing rule to the writer.
+ template <typename Map>
+ DigraphWriter& nodeMap(const std::string& caption, const Map& map) {
+ checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
+ _writer_bits::MapStorageBase<Node>* storage =
+ new _writer_bits::MapStorage<Node, Map>(map);
+ _node_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Node map writing rule
+ ///
+ /// Add a node map writing rule with specialized converter to the
+ /// writer.
+ template <typename Map, typename Converter>
+ DigraphWriter& nodeMap(const std::string& caption, const Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
+ _writer_bits::MapStorageBase<Node>* storage =
+ new _writer_bits::MapStorage<Node, Map, Converter>(map, converter);
+ _node_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Arc map writing rule
+ ///
+ /// Add an arc map writing rule to the writer.
+ template <typename Map>
+ DigraphWriter& arcMap(const std::string& caption, const Map& map) {
+ checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
+ _writer_bits::MapStorageBase<Arc>* storage =
+ new _writer_bits::MapStorage<Arc, Map>(map);
+ _arc_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Arc map writing rule
+ ///
+ /// Add an arc map writing rule with specialized converter to the
+ /// writer.
+ template <typename Map, typename Converter>
+ DigraphWriter& arcMap(const std::string& caption, const Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
+ _writer_bits::MapStorageBase<Arc>* storage =
+ new _writer_bits::MapStorage<Arc, Map, Converter>(map, converter);
+ _arc_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Attribute writing rule
+ ///
+ /// Add an attribute writing rule to the writer.
+ template <typename Value>
+ DigraphWriter& attribute(const std::string& caption, const Value& value) {
+ _writer_bits::ValueStorageBase* storage =
+ new _writer_bits::ValueStorage<Value>(value);
+ _attributes.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Attribute writing rule
+ ///
+ /// Add an attribute writing rule with specialized converter to the
+ /// writer.
+ template <typename Value, typename Converter>
+ DigraphWriter& attribute(const std::string& caption, const Value& value,
+ const Converter& converter = Converter()) {
+ _writer_bits::ValueStorageBase* storage =
+ new _writer_bits::ValueStorage<Value, Converter>(value, converter);
+ _attributes.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Node writing rule
+ ///
+ /// Add a node writing rule to the writer.
+ DigraphWriter& node(const std::string& caption, const Node& node) {
+ typedef _writer_bits::MapLookUpConverter<Node> Converter;
+ Converter converter(_node_index);
+ _writer_bits::ValueStorageBase* storage =
+ new _writer_bits::ValueStorage<Node, Converter>(node, converter);
+ _attributes.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Arc writing rule
+ ///
+ /// Add an arc writing rule to writer.
+ DigraphWriter& arc(const std::string& caption, const Arc& arc) {
+ typedef _writer_bits::MapLookUpConverter<Arc> Converter;
+ Converter converter(_arc_index);
+ _writer_bits::ValueStorageBase* storage =
+ new _writer_bits::ValueStorage<Arc, Converter>(arc, converter);
+ _attributes.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \name Section Captions
+ /// @{
+
+ /// \brief Add an additional caption to the \c \@nodes section
+ ///
+ /// Add an additional caption to the \c \@nodes section.
+ DigraphWriter& nodes(const std::string& caption) {
+ _nodes_caption = caption;
+ return *this;
+ }
+
+ /// \brief Add an additional caption to the \c \@arcs section
+ ///
+ /// Add an additional caption to the \c \@arcs section.
+ DigraphWriter& arcs(const std::string& caption) {
+ _arcs_caption = caption;
+ return *this;
+ }
+
+ /// \brief Add an additional caption to the \c \@attributes section
+ ///
+ /// Add an additional caption to the \c \@attributes section.
+ DigraphWriter& attributes(const std::string& caption) {
+ _attributes_caption = caption;
+ return *this;
+ }
+
+ /// \name Skipping Section
+ /// @{
+
+ /// \brief Skip writing the node set
+ ///
+ /// The \c \@nodes section will not be written to the stream.
+ DigraphWriter& skipNodes() {
+ LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
+ _skip_nodes = true;
+ return *this;
+ }
+
+ /// \brief Skip writing arc set
+ ///
+ /// The \c \@arcs section will not be written to the stream.
+ DigraphWriter& skipArcs() {
+ LEMON_ASSERT(!_skip_arcs, "Multiple usage of skipArcs() member");
+ _skip_arcs = true;
+ return *this;
+ }
+
+ /// @}
+
+ private:
+
+ void writeNodes() {
+ _writer_bits::MapStorageBase<Node>* label = 0;
+ for (typename NodeMaps::iterator it = _node_maps.begin();
+ it != _node_maps.end(); ++it) {
+ if (it->first == "label") {
+ label = it->second;
+ break;
+ }
+ }
+
+ *_os << "@nodes";
+ if (!_nodes_caption.empty()) {
+ _writer_bits::writeToken(*_os << ' ', _nodes_caption);
+ }
+ *_os << std::endl;
+
+ if (label == 0) {
+ *_os << "label" << '\t';
+ }
+ for (typename NodeMaps::iterator it = _node_maps.begin();
+ it != _node_maps.end(); ++it) {
+ _writer_bits::writeToken(*_os, it->first) << '\t';
+ }
+ *_os << std::endl;
+
+ std::vector<Node> nodes;
+ for (NodeIt n(_digraph); n != INVALID; ++n) {
+ nodes.push_back(n);
+ }
+
+ if (label == 0) {
+ IdMap<DGR, Node> id_map(_digraph);
+ _writer_bits::MapLess<IdMap<DGR, Node> > id_less(id_map);
+ std::sort(nodes.begin(), nodes.end(), id_less);
+ } else {
+ label->sort(nodes);
+ }
+
+ for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
+ Node n = nodes[i];
+ if (label == 0) {
+ std::ostringstream os;
+ os << _digraph.id(n);
+ _writer_bits::writeToken(*_os, os.str());
+ *_os << '\t';
+ _node_index.insert(std::make_pair(n, os.str()));
+ }
+ for (typename NodeMaps::iterator it = _node_maps.begin();
+ it != _node_maps.end(); ++it) {
+ std::string value = it->second->get(n);
+ _writer_bits::writeToken(*_os, value);
+ if (it->first == "label") {
+ _node_index.insert(std::make_pair(n, value));
+ }
+ *_os << '\t';
+ }
+ *_os << std::endl;
+ }
+ }
+
+ void createNodeIndex() {
+ _writer_bits::MapStorageBase<Node>* label = 0;
+ for (typename NodeMaps::iterator it = _node_maps.begin();
+ it != _node_maps.end(); ++it) {
+ if (it->first == "label") {
+ label = it->second;
+ break;
+ }
+ }
+
+ if (label == 0) {
+ for (NodeIt n(_digraph); n != INVALID; ++n) {
+ std::ostringstream os;
+ os << _digraph.id(n);
+ _node_index.insert(std::make_pair(n, os.str()));
+ }
+ } else {
+ for (NodeIt n(_digraph); n != INVALID; ++n) {
+ std::string value = label->get(n);
+ _node_index.insert(std::make_pair(n, value));
+ }
+ }
+ }
+
+ void writeArcs() {
+ _writer_bits::MapStorageBase<Arc>* label = 0;
+ for (typename ArcMaps::iterator it = _arc_maps.begin();
+ it != _arc_maps.end(); ++it) {
+ if (it->first == "label") {
+ label = it->second;
+ break;
+ }
+ }
+
+ *_os << "@arcs";
+ if (!_arcs_caption.empty()) {
+ _writer_bits::writeToken(*_os << ' ', _arcs_caption);
+ }
+ *_os << std::endl;
+
+ *_os << '\t' << '\t';
+ if (label == 0) {
+ *_os << "label" << '\t';
+ }
+ for (typename ArcMaps::iterator it = _arc_maps.begin();
+ it != _arc_maps.end(); ++it) {
+ _writer_bits::writeToken(*_os, it->first) << '\t';
+ }
+ *_os << std::endl;
+
+ std::vector<Arc> arcs;
+ for (ArcIt n(_digraph); n != INVALID; ++n) {
+ arcs.push_back(n);
+ }
+
+ if (label == 0) {
+ IdMap<DGR, Arc> id_map(_digraph);
+ _writer_bits::MapLess<IdMap<DGR, Arc> > id_less(id_map);
+ std::sort(arcs.begin(), arcs.end(), id_less);
+ } else {
+ label->sort(arcs);
+ }
+
+ for (int i = 0; i < static_cast<int>(arcs.size()); ++i) {
+ Arc a = arcs[i];
+ _writer_bits::writeToken(*_os, _node_index.
+ find(_digraph.source(a))->second);
+ *_os << '\t';
+ _writer_bits::writeToken(*_os, _node_index.
+ find(_digraph.target(a))->second);
+ *_os << '\t';
+ if (label == 0) {
+ std::ostringstream os;
+ os << _digraph.id(a);
+ _writer_bits::writeToken(*_os, os.str());
+ *_os << '\t';
+ _arc_index.insert(std::make_pair(a, os.str()));
+ }
+ for (typename ArcMaps::iterator it = _arc_maps.begin();
+ it != _arc_maps.end(); ++it) {
+ std::string value = it->second->get(a);
+ _writer_bits::writeToken(*_os, value);
+ if (it->first == "label") {
+ _arc_index.insert(std::make_pair(a, value));
+ }
+ *_os << '\t';
+ }
+ *_os << std::endl;
+ }
+ }
+
+ void createArcIndex() {
+ _writer_bits::MapStorageBase<Arc>* label = 0;
+ for (typename ArcMaps::iterator it = _arc_maps.begin();
+ it != _arc_maps.end(); ++it) {
+ if (it->first == "label") {
+ label = it->second;
+ break;
+ }
+ }
+
+ if (label == 0) {
+ for (ArcIt a(_digraph); a != INVALID; ++a) {
+ std::ostringstream os;
+ os << _digraph.id(a);
+ _arc_index.insert(std::make_pair(a, os.str()));
+ }
+ } else {
+ for (ArcIt a(_digraph); a != INVALID; ++a) {
+ std::string value = label->get(a);
+ _arc_index.insert(std::make_pair(a, value));
+ }
+ }
+ }
+
+ void writeAttributes() {
+ if (_attributes.empty()) return;
+ *_os << "@attributes";
+ if (!_attributes_caption.empty()) {
+ _writer_bits::writeToken(*_os << ' ', _attributes_caption);
+ }
+ *_os << std::endl;
+ for (typename Attributes::iterator it = _attributes.begin();
+ it != _attributes.end(); ++it) {
+ _writer_bits::writeToken(*_os, it->first) << ' ';
+ _writer_bits::writeToken(*_os, it->second->get());
+ *_os << std::endl;
+ }
+ }
+
+ public:
+
+ /// \name Execution of the Writer
+ /// @{
+
+ /// \brief Start the batch processing
+ ///
+ /// This function starts the batch processing.
+ void run() {
+ if (!_skip_nodes) {
+ writeNodes();
+ } else {
+ createNodeIndex();
+ }
+ if (!_skip_arcs) {
+ writeArcs();
+ } else {
+ createArcIndex();
+ }
+ writeAttributes();
+ }
+
+ /// \brief Give back the stream of the writer
+ ///
+ /// Give back the stream of the writer.
+ std::ostream& ostream() {
+ return *_os;
+ }
+
+ /// @}
+ };
+
+ /// \ingroup lemon_io
+ ///
+ /// \brief Return a \ref lemon::DigraphWriter "DigraphWriter" class
+ ///
+ /// This function just returns a \ref lemon::DigraphWriter
+ /// "DigraphWriter" class.
+ ///
+ /// With this function a digraph can be write to a file or output
+ /// stream in \ref lgf-format "LGF" format with several maps and
+ /// attributes. For example, with the following code a network flow
+ /// problem can be written to the standard output, i.e. a digraph
+ /// with a \e capacity map on the arcs and \e source and \e target
+ /// nodes:
+ ///
+ ///\code
+ ///ListDigraph digraph;
+ ///ListDigraph::ArcMap<int> cap(digraph);
+ ///ListDigraph::Node src, trg;
+ /// // Setting the capacity map and source and target nodes
+ ///digraphWriter(digraph, std::cout).
+ /// arcMap("capacity", cap).
+ /// node("source", src).
+ /// node("target", trg).
+ /// run();
+ ///\endcode
+ ///
+ /// For a complete documentation, please see the
+ /// \ref lemon::DigraphWriter "DigraphWriter"
+ /// class documentation.
+ /// \warning Don't forget to put the \ref lemon::DigraphWriter::run() "run()"
+ /// to the end of the parameter list.
+ /// \relates DigraphWriter
+ /// \sa digraphWriter(const TDGR& digraph, const std::string& fn)
+ /// \sa digraphWriter(const TDGR& digraph, const char* fn)
+ template <typename TDGR>
+ DigraphWriter<TDGR> digraphWriter(const TDGR& digraph, std::ostream& os) {
+ DigraphWriter<TDGR> tmp(digraph, os);
+ return tmp;
+ }
+
+ /// \brief Return a \ref DigraphWriter class
+ ///
+ /// This function just returns a \ref DigraphWriter class.
+ /// \relates DigraphWriter
+ /// \sa digraphWriter(const TDGR& digraph, std::ostream& os)
+ template <typename TDGR>
+ DigraphWriter<TDGR> digraphWriter(const TDGR& digraph,
+ const std::string& fn) {
+ DigraphWriter<TDGR> tmp(digraph, fn);
+ return tmp;
+ }
+
+ /// \brief Return a \ref DigraphWriter class
+ ///
+ /// This function just returns a \ref DigraphWriter class.
+ /// \relates DigraphWriter
+ /// \sa digraphWriter(const TDGR& digraph, std::ostream& os)
+ template <typename TDGR>
+ DigraphWriter<TDGR> digraphWriter(const TDGR& digraph, const char* fn) {
+ DigraphWriter<TDGR> tmp(digraph, fn);
+ return tmp;
+ }
+
+ template <typename GR>
+ class GraphWriter;
+
+ template <typename TGR>
+ GraphWriter<TGR> graphWriter(const TGR& graph, std::ostream& os = std::cout);
+ template <typename TGR>
+ GraphWriter<TGR> graphWriter(const TGR& graph, const std::string& fn);
+ template <typename TGR>
+ GraphWriter<TGR> graphWriter(const TGR& graph, const char* fn);
+
+ /// \ingroup lemon_io
+ ///
+ /// \brief \ref lgf-format "LGF" writer for undirected graphs
+ ///
+ /// This utility writes an \ref lgf-format "LGF" file.
+ ///
+ /// It can be used almost the same way as \c DigraphWriter.
+ /// The only difference is that this class can handle edges and
+ /// edge maps as well as arcs and arc maps.
+ ///
+ /// The arc maps are written into the file as two columns, the
+ /// caption of the columns are the name of the map prefixed with \c
+ /// '+' and \c '-'. The arcs are written into the \c \@attributes
+ /// section as a \c '+' or a \c '-' prefix (depends on the direction
+ /// of the arc) and the label of corresponding edge.
+ template <typename GR>
+ class GraphWriter {
+ public:
+
+ typedef GR Graph;
+ TEMPLATE_GRAPH_TYPEDEFS(GR);
+
+ private:
+
+
+ std::ostream* _os;
+ bool local_os;
+
+ const GR& _graph;
+
+ std::string _nodes_caption;
+ std::string _edges_caption;
+ std::string _attributes_caption;
+
+ typedef std::map<Node, std::string> NodeIndex;
+ NodeIndex _node_index;
+ typedef std::map<Edge, std::string> EdgeIndex;
+ EdgeIndex _edge_index;
+
+ typedef std::vector<std::pair<std::string,
+ _writer_bits::MapStorageBase<Node>* > > NodeMaps;
+ NodeMaps _node_maps;
+
+ typedef std::vector<std::pair<std::string,
+ _writer_bits::MapStorageBase<Edge>* > >EdgeMaps;
+ EdgeMaps _edge_maps;
+
+ typedef std::vector<std::pair<std::string,
+ _writer_bits::ValueStorageBase*> > Attributes;
+ Attributes _attributes;
+
+ bool _skip_nodes;
+ bool _skip_edges;
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Construct an undirected graph writer, which writes to the
+ /// given output stream.
+ GraphWriter(const GR& graph, std::ostream& os = std::cout)
+ : _os(&os), local_os(false), _graph(graph),
+ _skip_nodes(false), _skip_edges(false) {}
+
+ /// \brief Constructor
+ ///
+ /// Construct a undirected graph writer, which writes to the given
+ /// output file.
+ GraphWriter(const GR& graph, const std::string& fn)
+ : _os(new std::ofstream(fn.c_str())), local_os(true), _graph(graph),
+ _skip_nodes(false), _skip_edges(false) {
+ if (!(*_os)) {
+ delete _os;
+ throw IoError("Cannot write file", fn);
+ }
+ }
+
+ /// \brief Constructor
+ ///
+ /// Construct a undirected graph writer, which writes to the given
+ /// output file.
+ GraphWriter(const GR& graph, const char* fn)
+ : _os(new std::ofstream(fn)), local_os(true), _graph(graph),
+ _skip_nodes(false), _skip_edges(false) {
+ if (!(*_os)) {
+ delete _os;
+ throw IoError("Cannot write file", fn);
+ }
+ }
+
+ /// \brief Destructor
+ ~GraphWriter() {
+ for (typename NodeMaps::iterator it = _node_maps.begin();
+ it != _node_maps.end(); ++it) {
+ delete it->second;
+ }
+
+ for (typename EdgeMaps::iterator it = _edge_maps.begin();
+ it != _edge_maps.end(); ++it) {
+ delete it->second;
+ }
+
+ for (typename Attributes::iterator it = _attributes.begin();
+ it != _attributes.end(); ++it) {
+ delete it->second;
+ }
+
+ if (local_os) {
+ delete _os;
+ }
+ }
+
+ private:
+
+ template <typename TGR>
+ friend GraphWriter<TGR> graphWriter(const TGR& graph, std::ostream& os);
+ template <typename TGR>
+ friend GraphWriter<TGR> graphWriter(const TGR& graph,
+ const std::string& fn);
+ template <typename TGR>
+ friend GraphWriter<TGR> graphWriter(const TGR& graph, const char *fn);
+
+ GraphWriter(GraphWriter& other)
+ : _os(other._os), local_os(other.local_os), _graph(other._graph),
+ _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) {
+
+ other._os = 0;
+ other.local_os = false;
+
+ _node_index.swap(other._node_index);
+ _edge_index.swap(other._edge_index);
+
+ _node_maps.swap(other._node_maps);
+ _edge_maps.swap(other._edge_maps);
+ _attributes.swap(other._attributes);
+
+ _nodes_caption = other._nodes_caption;
+ _edges_caption = other._edges_caption;
+ _attributes_caption = other._attributes_caption;
+ }
+
+ GraphWriter& operator=(const GraphWriter&);
+
+ public:
+
+ /// \name Writing Rules
+ /// @{
+
+ /// \brief Node map writing rule
+ ///
+ /// Add a node map writing rule to the writer.
+ template <typename Map>
+ GraphWriter& nodeMap(const std::string& caption, const Map& map) {
+ checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
+ _writer_bits::MapStorageBase<Node>* storage =
+ new _writer_bits::MapStorage<Node, Map>(map);
+ _node_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Node map writing rule
+ ///
+ /// Add a node map writing rule with specialized converter to the
+ /// writer.
+ template <typename Map, typename Converter>
+ GraphWriter& nodeMap(const std::string& caption, const Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
+ _writer_bits::MapStorageBase<Node>* storage =
+ new _writer_bits::MapStorage<Node, Map, Converter>(map, converter);
+ _node_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Edge map writing rule
+ ///
+ /// Add an edge map writing rule to the writer.
+ template <typename Map>
+ GraphWriter& edgeMap(const std::string& caption, const Map& map) {
+ checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
+ _writer_bits::MapStorageBase<Edge>* storage =
+ new _writer_bits::MapStorage<Edge, Map>(map);
+ _edge_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Edge map writing rule
+ ///
+ /// Add an edge map writing rule with specialized converter to the
+ /// writer.
+ template <typename Map, typename Converter>
+ GraphWriter& edgeMap(const std::string& caption, const Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
+ _writer_bits::MapStorageBase<Edge>* storage =
+ new _writer_bits::MapStorage<Edge, Map, Converter>(map, converter);
+ _edge_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Arc map writing rule
+ ///
+ /// Add an arc map writing rule to the writer.
+ template <typename Map>
+ GraphWriter& arcMap(const std::string& caption, const Map& map) {
+ checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
+ _writer_bits::MapStorageBase<Edge>* forward_storage =
+ new _writer_bits::GraphArcMapStorage<GR, true, Map>(_graph, map);
+ _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
+ _writer_bits::MapStorageBase<Edge>* backward_storage =
+ new _writer_bits::GraphArcMapStorage<GR, false, Map>(_graph, map);
+ _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
+ return *this;
+ }
+
+ /// \brief Arc map writing rule
+ ///
+ /// Add an arc map writing rule with specialized converter to the
+ /// writer.
+ template <typename Map, typename Converter>
+ GraphWriter& arcMap(const std::string& caption, const Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
+ _writer_bits::MapStorageBase<Edge>* forward_storage =
+ new _writer_bits::GraphArcMapStorage<GR, true, Map, Converter>
+ (_graph, map, converter);
+ _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
+ _writer_bits::MapStorageBase<Edge>* backward_storage =
+ new _writer_bits::GraphArcMapStorage<GR, false, Map, Converter>
+ (_graph, map, converter);
+ _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
+ return *this;
+ }
+
+ /// \brief Attribute writing rule
+ ///
+ /// Add an attribute writing rule to the writer.
+ template <typename Value>
+ GraphWriter& attribute(const std::string& caption, const Value& value) {
+ _writer_bits::ValueStorageBase* storage =
+ new _writer_bits::ValueStorage<Value>(value);
+ _attributes.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Attribute writing rule
+ ///
+ /// Add an attribute writing rule with specialized converter to the
+ /// writer.
+ template <typename Value, typename Converter>
+ GraphWriter& attribute(const std::string& caption, const Value& value,
+ const Converter& converter = Converter()) {
+ _writer_bits::ValueStorageBase* storage =
+ new _writer_bits::ValueStorage<Value, Converter>(value, converter);
+ _attributes.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Node writing rule
+ ///
+ /// Add a node writing rule to the writer.
+ GraphWriter& node(const std::string& caption, const Node& node) {
+ typedef _writer_bits::MapLookUpConverter<Node> Converter;
+ Converter converter(_node_index);
+ _writer_bits::ValueStorageBase* storage =
+ new _writer_bits::ValueStorage<Node, Converter>(node, converter);
+ _attributes.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Edge writing rule
+ ///
+ /// Add an edge writing rule to writer.
+ GraphWriter& edge(const std::string& caption, const Edge& edge) {
+ typedef _writer_bits::MapLookUpConverter<Edge> Converter;
+ Converter converter(_edge_index);
+ _writer_bits::ValueStorageBase* storage =
+ new _writer_bits::ValueStorage<Edge, Converter>(edge, converter);
+ _attributes.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Arc writing rule
+ ///
+ /// Add an arc writing rule to writer.
+ GraphWriter& arc(const std::string& caption, const Arc& arc) {
+ typedef _writer_bits::GraphArcLookUpConverter<GR> Converter;
+ Converter converter(_graph, _edge_index);
+ _writer_bits::ValueStorageBase* storage =
+ new _writer_bits::ValueStorage<Arc, Converter>(arc, converter);
+ _attributes.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \name Section Captions
+ /// @{
+
+ /// \brief Add an additional caption to the \c \@nodes section
+ ///
+ /// Add an additional caption to the \c \@nodes section.
+ GraphWriter& nodes(const std::string& caption) {
+ _nodes_caption = caption;
+ return *this;
+ }
+
+ /// \brief Add an additional caption to the \c \@edges section
+ ///
+ /// Add an additional caption to the \c \@edges section.
+ GraphWriter& edges(const std::string& caption) {
+ _edges_caption = caption;
+ return *this;
+ }
+
+ /// \brief Add an additional caption to the \c \@attributes section
+ ///
+ /// Add an additional caption to the \c \@attributes section.
+ GraphWriter& attributes(const std::string& caption) {
+ _attributes_caption = caption;
+ return *this;
+ }
+
+ /// \name Skipping Section
+ /// @{
+
+ /// \brief Skip writing the node set
+ ///
+ /// The \c \@nodes section will not be written to the stream.
+ GraphWriter& skipNodes() {
+ LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
+ _skip_nodes = true;
+ return *this;
+ }
+
+ /// \brief Skip writing edge set
+ ///
+ /// The \c \@edges section will not be written to the stream.
+ GraphWriter& skipEdges() {
+ LEMON_ASSERT(!_skip_edges, "Multiple usage of skipEdges() member");
+ _skip_edges = true;
+ return *this;
+ }
+
+ /// @}
+
+ private:
+
+ void writeNodes() {
+ _writer_bits::MapStorageBase<Node>* label = 0;
+ for (typename NodeMaps::iterator it = _node_maps.begin();
+ it != _node_maps.end(); ++it) {
+ if (it->first == "label") {
+ label = it->second;
+ break;
+ }
+ }
+
+ *_os << "@nodes";
+ if (!_nodes_caption.empty()) {
+ _writer_bits::writeToken(*_os << ' ', _nodes_caption);
+ }
+ *_os << std::endl;
+
+ if (label == 0) {
+ *_os << "label" << '\t';
+ }
+ for (typename NodeMaps::iterator it = _node_maps.begin();
+ it != _node_maps.end(); ++it) {
+ _writer_bits::writeToken(*_os, it->first) << '\t';
+ }
+ *_os << std::endl;
+
+ std::vector<Node> nodes;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ nodes.push_back(n);
+ }
+
+ if (label == 0) {
+ IdMap<GR, Node> id_map(_graph);
+ _writer_bits::MapLess<IdMap<GR, Node> > id_less(id_map);
+ std::sort(nodes.begin(), nodes.end(), id_less);
+ } else {
+ label->sort(nodes);
+ }
+
+ for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
+ Node n = nodes[i];
+ if (label == 0) {
+ std::ostringstream os;
+ os << _graph.id(n);
+ _writer_bits::writeToken(*_os, os.str());
+ *_os << '\t';
+ _node_index.insert(std::make_pair(n, os.str()));
+ }
+ for (typename NodeMaps::iterator it = _node_maps.begin();
+ it != _node_maps.end(); ++it) {
+ std::string value = it->second->get(n);
+ _writer_bits::writeToken(*_os, value);
+ if (it->first == "label") {
+ _node_index.insert(std::make_pair(n, value));
+ }
+ *_os << '\t';
+ }
+ *_os << std::endl;
+ }
+ }
+
+ void createNodeIndex() {
+ _writer_bits::MapStorageBase<Node>* label = 0;
+ for (typename NodeMaps::iterator it = _node_maps.begin();
+ it != _node_maps.end(); ++it) {
+ if (it->first == "label") {
+ label = it->second;
+ break;
+ }
+ }
+
+ if (label == 0) {
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ std::ostringstream os;
+ os << _graph.id(n);
+ _node_index.insert(std::make_pair(n, os.str()));
+ }
+ } else {
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ std::string value = label->get(n);
+ _node_index.insert(std::make_pair(n, value));
+ }
+ }
+ }
+
+ void writeEdges() {
+ _writer_bits::MapStorageBase<Edge>* label = 0;
+ for (typename EdgeMaps::iterator it = _edge_maps.begin();
+ it != _edge_maps.end(); ++it) {
+ if (it->first == "label") {
+ label = it->second;
+ break;
+ }
+ }
+
+ *_os << "@edges";
+ if (!_edges_caption.empty()) {
+ _writer_bits::writeToken(*_os << ' ', _edges_caption);
+ }
+ *_os << std::endl;
+
+ *_os << '\t' << '\t';
+ if (label == 0) {
+ *_os << "label" << '\t';
+ }
+ for (typename EdgeMaps::iterator it = _edge_maps.begin();
+ it != _edge_maps.end(); ++it) {
+ _writer_bits::writeToken(*_os, it->first) << '\t';
+ }
+ *_os << std::endl;
+
+ std::vector<Edge> edges;
+ for (EdgeIt n(_graph); n != INVALID; ++n) {
+ edges.push_back(n);
+ }
+
+ if (label == 0) {
+ IdMap<GR, Edge> id_map(_graph);
+ _writer_bits::MapLess<IdMap<GR, Edge> > id_less(id_map);
+ std::sort(edges.begin(), edges.end(), id_less);
+ } else {
+ label->sort(edges);
+ }
+
+ for (int i = 0; i < static_cast<int>(edges.size()); ++i) {
+ Edge e = edges[i];
+ _writer_bits::writeToken(*_os, _node_index.
+ find(_graph.u(e))->second);
+ *_os << '\t';
+ _writer_bits::writeToken(*_os, _node_index.
+ find(_graph.v(e))->second);
+ *_os << '\t';
+ if (label == 0) {
+ std::ostringstream os;
+ os << _graph.id(e);
+ _writer_bits::writeToken(*_os, os.str());
+ *_os << '\t';
+ _edge_index.insert(std::make_pair(e, os.str()));
+ }
+ for (typename EdgeMaps::iterator it = _edge_maps.begin();
+ it != _edge_maps.end(); ++it) {
+ std::string value = it->second->get(e);
+ _writer_bits::writeToken(*_os, value);
+ if (it->first == "label") {
+ _edge_index.insert(std::make_pair(e, value));
+ }
+ *_os << '\t';
+ }
+ *_os << std::endl;
+ }
+ }
+
+ void createEdgeIndex() {
+ _writer_bits::MapStorageBase<Edge>* label = 0;
+ for (typename EdgeMaps::iterator it = _edge_maps.begin();
+ it != _edge_maps.end(); ++it) {
+ if (it->first == "label") {
+ label = it->second;
+ break;
+ }
+ }
+
+ if (label == 0) {
+ for (EdgeIt e(_graph); e != INVALID; ++e) {
+ std::ostringstream os;
+ os << _graph.id(e);
+ _edge_index.insert(std::make_pair(e, os.str()));
+ }
+ } else {
+ for (EdgeIt e(_graph); e != INVALID; ++e) {
+ std::string value = label->get(e);
+ _edge_index.insert(std::make_pair(e, value));
+ }
+ }
+ }
+
+ void writeAttributes() {
+ if (_attributes.empty()) return;
+ *_os << "@attributes";
+ if (!_attributes_caption.empty()) {
+ _writer_bits::writeToken(*_os << ' ', _attributes_caption);
+ }
+ *_os << std::endl;
+ for (typename Attributes::iterator it = _attributes.begin();
+ it != _attributes.end(); ++it) {
+ _writer_bits::writeToken(*_os, it->first) << ' ';
+ _writer_bits::writeToken(*_os, it->second->get());
+ *_os << std::endl;
+ }
+ }
+
+ public:
+
+ /// \name Execution of the Writer
+ /// @{
+
+ /// \brief Start the batch processing
+ ///
+ /// This function starts the batch processing.
+ void run() {
+ if (!_skip_nodes) {
+ writeNodes();
+ } else {
+ createNodeIndex();
+ }
+ if (!_skip_edges) {
+ writeEdges();
+ } else {
+ createEdgeIndex();
+ }
+ writeAttributes();
+ }
+
+ /// \brief Give back the stream of the writer
+ ///
+ /// Give back the stream of the writer
+ std::ostream& ostream() {
+ return *_os;
+ }
+
+ /// @}
+ };
+
+ /// \ingroup lemon_io
+ ///
+ /// \brief Return a \ref lemon::GraphWriter "GraphWriter" class
+ ///
+ /// This function just returns a \ref lemon::GraphWriter "GraphWriter" class.
+ ///
+ /// With this function a graph can be write to a file or output
+ /// stream in \ref lgf-format "LGF" format with several maps and
+ /// attributes. For example, with the following code a weighted
+ /// matching problem can be written to the standard output, i.e. a
+ /// graph with a \e weight map on the edges:
+ ///
+ ///\code
+ ///ListGraph graph;
+ ///ListGraph::EdgeMap<int> weight(graph);
+ /// // Setting the weight map
+ ///graphWriter(graph, std::cout).
+ /// edgeMap("weight", weight).
+ /// run();
+ ///\endcode
+ ///
+ /// For a complete documentation, please see the
+ /// \ref lemon::GraphWriter "GraphWriter"
+ /// class documentation.
+ /// \warning Don't forget to put the \ref lemon::GraphWriter::run() "run()"
+ /// to the end of the parameter list.
+ /// \relates GraphWriter
+ /// \sa graphWriter(const TGR& graph, const std::string& fn)
+ /// \sa graphWriter(const TGR& graph, const char* fn)
+ template <typename TGR>
+ GraphWriter<TGR> graphWriter(const TGR& graph, std::ostream& os) {
+ GraphWriter<TGR> tmp(graph, os);
+ return tmp;
+ }
+
+ /// \brief Return a \ref GraphWriter class
+ ///
+ /// This function just returns a \ref GraphWriter class.
+ /// \relates GraphWriter
+ /// \sa graphWriter(const TGR& graph, std::ostream& os)
+ template <typename TGR>
+ GraphWriter<TGR> graphWriter(const TGR& graph, const std::string& fn) {
+ GraphWriter<TGR> tmp(graph, fn);
+ return tmp;
+ }
+
+ /// \brief Return a \ref GraphWriter class
+ ///
+ /// This function just returns a \ref GraphWriter class.
+ /// \relates GraphWriter
+ /// \sa graphWriter(const TGR& graph, std::ostream& os)
+ template <typename TGR>
+ GraphWriter<TGR> graphWriter(const TGR& graph, const char* fn) {
+ GraphWriter<TGR> tmp(graph, fn);
+ return tmp;
+ }
+
+ template <typename BGR>
+ class BpGraphWriter;
+
+ template <typename TBGR>
+ BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph,
+ std::ostream& os = std::cout);
+ template <typename TBGR>
+ BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const std::string& fn);
+ template <typename TBGR>
+ BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const char* fn);
+
+ /// \ingroup lemon_io
+ ///
+ /// \brief \ref lgf-format "LGF" writer for undirected bipartite graphs
+ ///
+ /// This utility writes an \ref lgf-format "LGF" file.
+ ///
+ /// It can be used almost the same way as \c GraphWriter, but it
+ /// reads the red and blue nodes from separate sections, and these
+ /// sections can contain different set of maps.
+ ///
+ /// The red and blue node maps are written to the corresponding
+ /// sections. The node maps are written to both of these sections
+ /// with the same map name.
+ template <typename BGR>
+ class BpGraphWriter {
+ public:
+
+ typedef BGR BpGraph;
+ TEMPLATE_BPGRAPH_TYPEDEFS(BGR);
+
+ private:
+
+
+ std::ostream* _os;
+ bool local_os;
+
+ const BGR& _graph;
+
+ std::string _nodes_caption;
+ std::string _edges_caption;
+ std::string _attributes_caption;
+
+ typedef std::map<Node, std::string> RedNodeIndex;
+ RedNodeIndex _red_node_index;
+ typedef std::map<Node, std::string> BlueNodeIndex;
+ BlueNodeIndex _blue_node_index;
+ typedef std::map<Edge, std::string> EdgeIndex;
+ EdgeIndex _edge_index;
+
+ typedef std::vector<std::pair<std::string,
+ _writer_bits::MapStorageBase<RedNode>* > > RedNodeMaps;
+ RedNodeMaps _red_node_maps;
+ typedef std::vector<std::pair<std::string,
+ _writer_bits::MapStorageBase<BlueNode>* > > BlueNodeMaps;
+ BlueNodeMaps _blue_node_maps;
+
+ typedef std::vector<std::pair<std::string,
+ _writer_bits::MapStorageBase<Edge>* > >EdgeMaps;
+ EdgeMaps _edge_maps;
+
+ typedef std::vector<std::pair<std::string,
+ _writer_bits::ValueStorageBase*> > Attributes;
+ Attributes _attributes;
+
+ bool _skip_nodes;
+ bool _skip_edges;
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Construct a bipartite graph writer, which writes to the given
+ /// output stream.
+ BpGraphWriter(const BGR& graph, std::ostream& os = std::cout)
+ : _os(&os), local_os(false), _graph(graph),
+ _skip_nodes(false), _skip_edges(false) {}
+
+ /// \brief Constructor
+ ///
+ /// Construct a bipartite graph writer, which writes to the given
+ /// output file.
+ BpGraphWriter(const BGR& graph, const std::string& fn)
+ : _os(new std::ofstream(fn.c_str())), local_os(true), _graph(graph),
+ _skip_nodes(false), _skip_edges(false) {
+ if (!(*_os)) {
+ delete _os;
+ throw IoError("Cannot write file", fn);
+ }
+ }
+
+ /// \brief Constructor
+ ///
+ /// Construct a bipartite graph writer, which writes to the given
+ /// output file.
+ BpGraphWriter(const BGR& graph, const char* fn)
+ : _os(new std::ofstream(fn)), local_os(true), _graph(graph),
+ _skip_nodes(false), _skip_edges(false) {
+ if (!(*_os)) {
+ delete _os;
+ throw IoError("Cannot write file", fn);
+ }
+ }
+
+ /// \brief Destructor
+ ~BpGraphWriter() {
+ for (typename RedNodeMaps::iterator it = _red_node_maps.begin();
+ it != _red_node_maps.end(); ++it) {
+ delete it->second;
+ }
+
+ for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin();
+ it != _blue_node_maps.end(); ++it) {
+ delete it->second;
+ }
+
+ for (typename EdgeMaps::iterator it = _edge_maps.begin();
+ it != _edge_maps.end(); ++it) {
+ delete it->second;
+ }
+
+ for (typename Attributes::iterator it = _attributes.begin();
+ it != _attributes.end(); ++it) {
+ delete it->second;
+ }
+
+ if (local_os) {
+ delete _os;
+ }
+ }
+
+ private:
+
+ template <typename TBGR>
+ friend BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph,
+ std::ostream& os);
+ template <typename TBGR>
+ friend BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph,
+ const std::string& fn);
+ template <typename TBGR>
+ friend BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const char *fn);
+
+ BpGraphWriter(BpGraphWriter& other)
+ : _os(other._os), local_os(other.local_os), _graph(other._graph),
+ _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) {
+
+ other._os = 0;
+ other.local_os = false;
+
+ _red_node_index.swap(other._red_node_index);
+ _blue_node_index.swap(other._blue_node_index);
+ _edge_index.swap(other._edge_index);
+
+ _red_node_maps.swap(other._red_node_maps);
+ _blue_node_maps.swap(other._blue_node_maps);
+ _edge_maps.swap(other._edge_maps);
+ _attributes.swap(other._attributes);
+
+ _nodes_caption = other._nodes_caption;
+ _edges_caption = other._edges_caption;
+ _attributes_caption = other._attributes_caption;
+ }
+
+ BpGraphWriter& operator=(const BpGraphWriter&);
+
+ public:
+
+ /// \name Writing Rules
+ /// @{
+
+ /// \brief Node map writing rule
+ ///
+ /// Add a node map writing rule to the writer.
+ template <typename Map>
+ BpGraphWriter& nodeMap(const std::string& caption, const Map& map) {
+ checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
+ _writer_bits::MapStorageBase<RedNode>* red_storage =
+ new _writer_bits::MapStorage<RedNode, Map>(map);
+ _red_node_maps.push_back(std::make_pair(caption, red_storage));
+ _writer_bits::MapStorageBase<BlueNode>* blue_storage =
+ new _writer_bits::MapStorage<BlueNode, Map>(map);
+ _blue_node_maps.push_back(std::make_pair(caption, blue_storage));
+ return *this;
+ }
+
+ /// \brief Node map writing rule
+ ///
+ /// Add a node map writing rule with specialized converter to the
+ /// writer.
+ template <typename Map, typename Converter>
+ BpGraphWriter& nodeMap(const std::string& caption, const Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
+ _writer_bits::MapStorageBase<RedNode>* red_storage =
+ new _writer_bits::MapStorage<RedNode, Map, Converter>(map, converter);
+ _red_node_maps.push_back(std::make_pair(caption, red_storage));
+ _writer_bits::MapStorageBase<BlueNode>* blue_storage =
+ new _writer_bits::MapStorage<BlueNode, Map, Converter>(map, converter);
+ _blue_node_maps.push_back(std::make_pair(caption, blue_storage));
+ return *this;
+ }
+
+ /// \brief Red node map writing rule
+ ///
+ /// Add a red node map writing rule to the writer.
+ template <typename Map>
+ BpGraphWriter& redNodeMap(const std::string& caption, const Map& map) {
+ checkConcept<concepts::ReadMap<RedNode, typename Map::Value>, Map>();
+ _writer_bits::MapStorageBase<RedNode>* storage =
+ new _writer_bits::MapStorage<RedNode, Map>(map);
+ _red_node_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Red node map writing rule
+ ///
+ /// Add a red node map writing rule with specialized converter to the
+ /// writer.
+ template <typename Map, typename Converter>
+ BpGraphWriter& redNodeMap(const std::string& caption, const Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::ReadMap<RedNode, typename Map::Value>, Map>();
+ _writer_bits::MapStorageBase<RedNode>* storage =
+ new _writer_bits::MapStorage<RedNode, Map, Converter>(map, converter);
+ _red_node_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Blue node map writing rule
+ ///
+ /// Add a blue node map writing rule to the writer.
+ template <typename Map>
+ BpGraphWriter& blueNodeMap(const std::string& caption, const Map& map) {
+ checkConcept<concepts::ReadMap<BlueNode, typename Map::Value>, Map>();
+ _writer_bits::MapStorageBase<BlueNode>* storage =
+ new _writer_bits::MapStorage<BlueNode, Map>(map);
+ _blue_node_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Blue node map writing rule
+ ///
+ /// Add a blue node map writing rule with specialized converter to the
+ /// writer.
+ template <typename Map, typename Converter>
+ BpGraphWriter& blueNodeMap(const std::string& caption, const Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::ReadMap<BlueNode, typename Map::Value>, Map>();
+ _writer_bits::MapStorageBase<BlueNode>* storage =
+ new _writer_bits::MapStorage<BlueNode, Map, Converter>(map, converter);
+ _blue_node_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Edge map writing rule
+ ///
+ /// Add an edge map writing rule to the writer.
+ template <typename Map>
+ BpGraphWriter& edgeMap(const std::string& caption, const Map& map) {
+ checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
+ _writer_bits::MapStorageBase<Edge>* storage =
+ new _writer_bits::MapStorage<Edge, Map>(map);
+ _edge_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Edge map writing rule
+ ///
+ /// Add an edge map writing rule with specialized converter to the
+ /// writer.
+ template <typename Map, typename Converter>
+ BpGraphWriter& edgeMap(const std::string& caption, const Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
+ _writer_bits::MapStorageBase<Edge>* storage =
+ new _writer_bits::MapStorage<Edge, Map, Converter>(map, converter);
+ _edge_maps.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Arc map writing rule
+ ///
+ /// Add an arc map writing rule to the writer.
+ template <typename Map>
+ BpGraphWriter& arcMap(const std::string& caption, const Map& map) {
+ checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
+ _writer_bits::MapStorageBase<Edge>* forward_storage =
+ new _writer_bits::GraphArcMapStorage<BGR, true, Map>(_graph, map);
+ _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
+ _writer_bits::MapStorageBase<Edge>* backward_storage =
+ new _writer_bits::GraphArcMapStorage<BGR, false, Map>(_graph, map);
+ _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
+ return *this;
+ }
+
+ /// \brief Arc map writing rule
+ ///
+ /// Add an arc map writing rule with specialized converter to the
+ /// writer.
+ template <typename Map, typename Converter>
+ BpGraphWriter& arcMap(const std::string& caption, const Map& map,
+ const Converter& converter = Converter()) {
+ checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
+ _writer_bits::MapStorageBase<Edge>* forward_storage =
+ new _writer_bits::GraphArcMapStorage<BGR, true, Map, Converter>
+ (_graph, map, converter);
+ _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
+ _writer_bits::MapStorageBase<Edge>* backward_storage =
+ new _writer_bits::GraphArcMapStorage<BGR, false, Map, Converter>
+ (_graph, map, converter);
+ _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
+ return *this;
+ }
+
+ /// \brief Attribute writing rule
+ ///
+ /// Add an attribute writing rule to the writer.
+ template <typename Value>
+ BpGraphWriter& attribute(const std::string& caption, const Value& value) {
+ _writer_bits::ValueStorageBase* storage =
+ new _writer_bits::ValueStorage<Value>(value);
+ _attributes.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Attribute writing rule
+ ///
+ /// Add an attribute writing rule with specialized converter to the
+ /// writer.
+ template <typename Value, typename Converter>
+ BpGraphWriter& attribute(const std::string& caption, const Value& value,
+ const Converter& converter = Converter()) {
+ _writer_bits::ValueStorageBase* storage =
+ new _writer_bits::ValueStorage<Value, Converter>(value, converter);
+ _attributes.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Node writing rule
+ ///
+ /// Add a node writing rule to the writer.
+ BpGraphWriter& node(const std::string& caption, const Node& node) {
+ typedef _writer_bits::DoubleMapLookUpConverter<
+ Node, RedNodeIndex, BlueNodeIndex> Converter;
+ Converter converter(_red_node_index, _blue_node_index);
+ _writer_bits::ValueStorageBase* storage =
+ new _writer_bits::ValueStorage<Node, Converter>(node, converter);
+ _attributes.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Red node writing rule
+ ///
+ /// Add a red node writing rule to the writer.
+ BpGraphWriter& redNode(const std::string& caption, const RedNode& node) {
+ typedef _writer_bits::MapLookUpConverter<Node> Converter;
+ Converter converter(_red_node_index);
+ _writer_bits::ValueStorageBase* storage =
+ new _writer_bits::ValueStorage<Node, Converter>(node, converter);
+ _attributes.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Blue node writing rule
+ ///
+ /// Add a blue node writing rule to the writer.
+ BpGraphWriter& blueNode(const std::string& caption, const BlueNode& node) {
+ typedef _writer_bits::MapLookUpConverter<Node> Converter;
+ Converter converter(_blue_node_index);
+ _writer_bits::ValueStorageBase* storage =
+ new _writer_bits::ValueStorage<Node, Converter>(node, converter);
+ _attributes.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Edge writing rule
+ ///
+ /// Add an edge writing rule to writer.
+ BpGraphWriter& edge(const std::string& caption, const Edge& edge) {
+ typedef _writer_bits::MapLookUpConverter<Edge> Converter;
+ Converter converter(_edge_index);
+ _writer_bits::ValueStorageBase* storage =
+ new _writer_bits::ValueStorage<Edge, Converter>(edge, converter);
+ _attributes.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \brief Arc writing rule
+ ///
+ /// Add an arc writing rule to writer.
+ BpGraphWriter& arc(const std::string& caption, const Arc& arc) {
+ typedef _writer_bits::GraphArcLookUpConverter<BGR> Converter;
+ Converter converter(_graph, _edge_index);
+ _writer_bits::ValueStorageBase* storage =
+ new _writer_bits::ValueStorage<Arc, Converter>(arc, converter);
+ _attributes.push_back(std::make_pair(caption, storage));
+ return *this;
+ }
+
+ /// \name Section Captions
+ /// @{
+
+ /// \brief Add an additional caption to the \c \@red_nodes and
+ /// \c \@blue_nodes section
+ ///
+ /// Add an additional caption to the \c \@red_nodes and \c
+ /// \@blue_nodes section.
+ BpGraphWriter& nodes(const std::string& caption) {
+ _nodes_caption = caption;
+ return *this;
+ }
+
+ /// \brief Add an additional caption to the \c \@edges section
+ ///
+ /// Add an additional caption to the \c \@edges section.
+ BpGraphWriter& edges(const std::string& caption) {
+ _edges_caption = caption;
+ return *this;
+ }
+
+ /// \brief Add an additional caption to the \c \@attributes section
+ ///
+ /// Add an additional caption to the \c \@attributes section.
+ BpGraphWriter& attributes(const std::string& caption) {
+ _attributes_caption = caption;
+ return *this;
+ }
+
+ /// \name Skipping Section
+ /// @{
+
+ /// \brief Skip writing the node set
+ ///
+ /// The \c \@red_nodes and \c \@blue_nodes section will not be
+ /// written to the stream.
+ BpGraphWriter& skipNodes() {
+ LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
+ _skip_nodes = true;
+ return *this;
+ }
+
+ /// \brief Skip writing edge set
+ ///
+ /// The \c \@edges section will not be written to the stream.
+ BpGraphWriter& skipEdges() {
+ LEMON_ASSERT(!_skip_edges, "Multiple usage of skipEdges() member");
+ _skip_edges = true;
+ return *this;
+ }
+
+ /// @}
+
+ private:
+
+ void writeRedNodes() {
+ _writer_bits::MapStorageBase<RedNode>* label = 0;
+ for (typename RedNodeMaps::iterator it = _red_node_maps.begin();
+ it != _red_node_maps.end(); ++it) {
+ if (it->first == "label") {
+ label = it->second;
+ break;
+ }
+ }
+
+ *_os << "@red_nodes";
+ if (!_nodes_caption.empty()) {
+ _writer_bits::writeToken(*_os << ' ', _nodes_caption);
+ }
+ *_os << std::endl;
+
+ if (label == 0) {
+ *_os << "label" << '\t';
+ }
+ for (typename RedNodeMaps::iterator it = _red_node_maps.begin();
+ it != _red_node_maps.end(); ++it) {
+ _writer_bits::writeToken(*_os, it->first) << '\t';
+ }
+ *_os << std::endl;
+
+ std::vector<RedNode> nodes;
+ for (RedNodeIt n(_graph); n != INVALID; ++n) {
+ nodes.push_back(n);
+ }
+
+ if (label == 0) {
+ IdMap<BGR, Node> id_map(_graph);
+ _writer_bits::MapLess<IdMap<BGR, Node> > id_less(id_map);
+ std::sort(nodes.begin(), nodes.end(), id_less);
+ } else {
+ label->sort(nodes);
+ }
+
+ for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
+ RedNode n = nodes[i];
+ if (label == 0) {
+ std::ostringstream os;
+ os << _graph.id(static_cast<Node>(n));
+ _writer_bits::writeToken(*_os, os.str());
+ *_os << '\t';
+ _red_node_index.insert(std::make_pair(n, os.str()));
+ }
+ for (typename RedNodeMaps::iterator it = _red_node_maps.begin();
+ it != _red_node_maps.end(); ++it) {
+ std::string value = it->second->get(n);
+ _writer_bits::writeToken(*_os, value);
+ if (it->first == "label") {
+ _red_node_index.insert(std::make_pair(n, value));
+ }
+ *_os << '\t';
+ }
+ *_os << std::endl;
+ }
+ }
+
+ void writeBlueNodes() {
+ _writer_bits::MapStorageBase<BlueNode>* label = 0;
+ for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin();
+ it != _blue_node_maps.end(); ++it) {
+ if (it->first == "label") {
+ label = it->second;
+ break;
+ }
+ }
+
+ *_os << "@blue_nodes";
+ if (!_nodes_caption.empty()) {
+ _writer_bits::writeToken(*_os << ' ', _nodes_caption);
+ }
+ *_os << std::endl;
+
+ if (label == 0) {
+ *_os << "label" << '\t';
+ }
+ for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin();
+ it != _blue_node_maps.end(); ++it) {
+ _writer_bits::writeToken(*_os, it->first) << '\t';
+ }
+ *_os << std::endl;
+
+ std::vector<BlueNode> nodes;
+ for (BlueNodeIt n(_graph); n != INVALID; ++n) {
+ nodes.push_back(n);
+ }
+
+ if (label == 0) {
+ IdMap<BGR, Node> id_map(_graph);
+ _writer_bits::MapLess<IdMap<BGR, Node> > id_less(id_map);
+ std::sort(nodes.begin(), nodes.end(), id_less);
+ } else {
+ label->sort(nodes);
+ }
+
+ for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
+ BlueNode n = nodes[i];
+ if (label == 0) {
+ std::ostringstream os;
+ os << _graph.id(static_cast<Node>(n));
+ _writer_bits::writeToken(*_os, os.str());
+ *_os << '\t';
+ _blue_node_index.insert(std::make_pair(n, os.str()));
+ }
+ for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin();
+ it != _blue_node_maps.end(); ++it) {
+ std::string value = it->second->get(n);
+ _writer_bits::writeToken(*_os, value);
+ if (it->first == "label") {
+ _blue_node_index.insert(std::make_pair(n, value));
+ }
+ *_os << '\t';
+ }
+ *_os << std::endl;
+ }
+ }
+
+ void createRedNodeIndex() {
+ _writer_bits::MapStorageBase<RedNode>* label = 0;
+ for (typename RedNodeMaps::iterator it = _red_node_maps.begin();
+ it != _red_node_maps.end(); ++it) {
+ if (it->first == "label") {
+ label = it->second;
+ break;
+ }
+ }
+
+ if (label == 0) {
+ for (RedNodeIt n(_graph); n != INVALID; ++n) {
+ std::ostringstream os;
+ os << _graph.id(n);
+ _red_node_index.insert(std::make_pair(n, os.str()));
+ }
+ } else {
+ for (RedNodeIt n(_graph); n != INVALID; ++n) {
+ std::string value = label->get(n);
+ _red_node_index.insert(std::make_pair(n, value));
+ }
+ }
+ }
+
+ void createBlueNodeIndex() {
+ _writer_bits::MapStorageBase<BlueNode>* label = 0;
+ for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin();
+ it != _blue_node_maps.end(); ++it) {
+ if (it->first == "label") {
+ label = it->second;
+ break;
+ }
+ }
+
+ if (label == 0) {
+ for (BlueNodeIt n(_graph); n != INVALID; ++n) {
+ std::ostringstream os;
+ os << _graph.id(n);
+ _blue_node_index.insert(std::make_pair(n, os.str()));
+ }
+ } else {
+ for (BlueNodeIt n(_graph); n != INVALID; ++n) {
+ std::string value = label->get(n);
+ _blue_node_index.insert(std::make_pair(n, value));
+ }
+ }
+ }
+
+ void writeEdges() {
+ _writer_bits::MapStorageBase<Edge>* label = 0;
+ for (typename EdgeMaps::iterator it = _edge_maps.begin();
+ it != _edge_maps.end(); ++it) {
+ if (it->first == "label") {
+ label = it->second;
+ break;
+ }
+ }
+
+ *_os << "@edges";
+ if (!_edges_caption.empty()) {
+ _writer_bits::writeToken(*_os << ' ', _edges_caption);
+ }
+ *_os << std::endl;
+
+ *_os << '\t' << '\t';
+ if (label == 0) {
+ *_os << "label" << '\t';
+ }
+ for (typename EdgeMaps::iterator it = _edge_maps.begin();
+ it != _edge_maps.end(); ++it) {
+ _writer_bits::writeToken(*_os, it->first) << '\t';
+ }
+ *_os << std::endl;
+
+ std::vector<Edge> edges;
+ for (EdgeIt n(_graph); n != INVALID; ++n) {
+ edges.push_back(n);
+ }
+
+ if (label == 0) {
+ IdMap<BGR, Edge> id_map(_graph);
+ _writer_bits::MapLess<IdMap<BGR, Edge> > id_less(id_map);
+ std::sort(edges.begin(), edges.end(), id_less);
+ } else {
+ label->sort(edges);
+ }
+
+ for (int i = 0; i < static_cast<int>(edges.size()); ++i) {
+ Edge e = edges[i];
+ _writer_bits::writeToken(*_os, _red_node_index.
+ find(_graph.redNode(e))->second);
+ *_os << '\t';
+ _writer_bits::writeToken(*_os, _blue_node_index.
+ find(_graph.blueNode(e))->second);
+ *_os << '\t';
+ if (label == 0) {
+ std::ostringstream os;
+ os << _graph.id(e);
+ _writer_bits::writeToken(*_os, os.str());
+ *_os << '\t';
+ _edge_index.insert(std::make_pair(e, os.str()));
+ }
+ for (typename EdgeMaps::iterator it = _edge_maps.begin();
+ it != _edge_maps.end(); ++it) {
+ std::string value = it->second->get(e);
+ _writer_bits::writeToken(*_os, value);
+ if (it->first == "label") {
+ _edge_index.insert(std::make_pair(e, value));
+ }
+ *_os << '\t';
+ }
+ *_os << std::endl;
+ }
+ }
+
+ void createEdgeIndex() {
+ _writer_bits::MapStorageBase<Edge>* label = 0;
+ for (typename EdgeMaps::iterator it = _edge_maps.begin();
+ it != _edge_maps.end(); ++it) {
+ if (it->first == "label") {
+ label = it->second;
+ break;
+ }
+ }
+
+ if (label == 0) {
+ for (EdgeIt e(_graph); e != INVALID; ++e) {
+ std::ostringstream os;
+ os << _graph.id(e);
+ _edge_index.insert(std::make_pair(e, os.str()));
+ }
+ } else {
+ for (EdgeIt e(_graph); e != INVALID; ++e) {
+ std::string value = label->get(e);
+ _edge_index.insert(std::make_pair(e, value));
+ }
+ }
+ }
+
+ void writeAttributes() {
+ if (_attributes.empty()) return;
+ *_os << "@attributes";
+ if (!_attributes_caption.empty()) {
+ _writer_bits::writeToken(*_os << ' ', _attributes_caption);
+ }
+ *_os << std::endl;
+ for (typename Attributes::iterator it = _attributes.begin();
+ it != _attributes.end(); ++it) {
+ _writer_bits::writeToken(*_os, it->first) << ' ';
+ _writer_bits::writeToken(*_os, it->second->get());
+ *_os << std::endl;
+ }
+ }
+
+ public:
+
+ /// \name Execution of the Writer
+ /// @{
+
+ /// \brief Start the batch processing
+ ///
+ /// This function starts the batch processing.
+ void run() {
+ if (!_skip_nodes) {
+ writeRedNodes();
+ writeBlueNodes();
+ } else {
+ createRedNodeIndex();
+ createBlueNodeIndex();
+ }
+ if (!_skip_edges) {
+ writeEdges();
+ } else {
+ createEdgeIndex();
+ }
+ writeAttributes();
+ }
+
+ /// \brief Give back the stream of the writer
+ ///
+ /// Give back the stream of the writer
+ std::ostream& ostream() {
+ return *_os;
+ }
+
+ /// @}
+ };
+
+ /// \ingroup lemon_io
+ ///
+ /// \brief Return a \ref lemon::BpGraphWriter "BpGraphWriter" class
+ ///
+ /// This function just returns a \ref lemon::BpGraphWriter
+ /// "BpGraphWriter" class.
+ ///
+ /// With this function a bipartite graph can be write to a file or output
+ /// stream in \ref lgf-format "LGF" format with several maps and
+ /// attributes. For example, with the following code a bipartite
+ /// weighted matching problem can be written to the standard output,
+ /// i.e. a graph with a \e weight map on the edges:
+ ///
+ ///\code
+ ///ListBpGraph graph;
+ ///ListBpGraph::EdgeMap<int> weight(graph);
+ /// // Setting the weight map
+ ///bpGraphWriter(graph, std::cout).
+ /// edgeMap("weight", weight).
+ /// run();
+ ///\endcode
+ ///
+ /// For a complete documentation, please see the
+ /// \ref lemon::BpGraphWriter "BpGraphWriter"
+ /// class documentation.
+ /// \warning Don't forget to put the \ref lemon::BpGraphWriter::run() "run()"
+ /// to the end of the parameter list.
+ /// \relates BpGraphWriter
+ /// \sa bpGraphWriter(const TBGR& graph, const std::string& fn)
+ /// \sa bpGraphWriter(const TBGR& graph, const char* fn)
+ template <typename TBGR>
+ BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, std::ostream& os) {
+ BpGraphWriter<TBGR> tmp(graph, os);
+ return tmp;
+ }
+
+ /// \brief Return a \ref BpGraphWriter class
+ ///
+ /// This function just returns a \ref BpGraphWriter class.
+ /// \relates BpGraphWriter
+ /// \sa graphWriter(const TBGR& graph, std::ostream& os)
+ template <typename TBGR>
+ BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const std::string& fn) {
+ BpGraphWriter<TBGR> tmp(graph, fn);
+ return tmp;
+ }
+
+ /// \brief Return a \ref BpGraphWriter class
+ ///
+ /// This function just returns a \ref BpGraphWriter class.
+ /// \relates BpGraphWriter
+ /// \sa graphWriter(const TBGR& graph, std::ostream& os)
+ template <typename TBGR>
+ BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const char* fn) {
+ BpGraphWriter<TBGR> tmp(graph, fn);
+ return tmp;
+ }
+
+ class SectionWriter;
+
+ SectionWriter sectionWriter(std::istream& is);
+ SectionWriter sectionWriter(const std::string& fn);
+ SectionWriter sectionWriter(const char* fn);
+
+ /// \ingroup lemon_io
+ ///
+ /// \brief Section writer class
+ ///
+ /// In the \ref lgf-format "LGF" file extra sections can be placed,
+ /// which contain any data in arbitrary format. Such sections can be
+ /// written with this class. A writing rule can be added to the
+ /// class with two different functions. With the \c sectionLines()
+ /// function a generator can write the section line-by-line, while
+ /// with the \c sectionStream() member the section can be written to
+ /// an output stream.
+ class SectionWriter {
+ private:
+
+ std::ostream* _os;
+ bool local_os;
+
+ typedef std::vector<std::pair<std::string, _writer_bits::Section*> >
+ Sections;
+
+ Sections _sections;
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Construct a section writer, which writes to the given output
+ /// stream.
+ SectionWriter(std::ostream& os)
+ : _os(&os), local_os(false) {}
+
+ /// \brief Constructor
+ ///
+ /// Construct a section writer, which writes into the given file.
+ SectionWriter(const std::string& fn)
+ : _os(new std::ofstream(fn.c_str())), local_os(true) {
+ if (!(*_os)) {
+ delete _os;
+ throw IoError("Cannot write file", fn);
+ }
+ }
+
+ /// \brief Constructor
+ ///
+ /// Construct a section writer, which writes into the given file.
+ SectionWriter(const char* fn)
+ : _os(new std::ofstream(fn)), local_os(true) {
+ if (!(*_os)) {
+ delete _os;
+ throw IoError("Cannot write file", fn);
+ }
+ }
+
+ /// \brief Destructor
+ ~SectionWriter() {
+ for (Sections::iterator it = _sections.begin();
+ it != _sections.end(); ++it) {
+ delete it->second;
+ }
+
+ if (local_os) {
+ delete _os;
+ }
+
+ }
+
+ private:
+
+ friend SectionWriter sectionWriter(std::ostream& os);
+ friend SectionWriter sectionWriter(const std::string& fn);
+ friend SectionWriter sectionWriter(const char* fn);
+
+ SectionWriter(SectionWriter& other)
+ : _os(other._os), local_os(other.local_os) {
+
+ other._os = 0;
+ other.local_os = false;
+
+ _sections.swap(other._sections);
+ }
+
+ SectionWriter& operator=(const SectionWriter&);
+
+ public:
+
+ /// \name Section Writers
+ /// @{
+
+ /// \brief Add a section writer with line oriented writing
+ ///
+ /// The first parameter is the type descriptor of the section, the
+ /// second is a generator with std::string values. At the writing
+ /// process, the returned \c std::string will be written into the
+ /// output file until it is an empty string.
+ ///
+ /// For example, an integer vector is written into a section.
+ ///\code
+ /// @numbers
+ /// 12 45 23 78
+ /// 4 28 38 28
+ /// 23 6 16
+ ///\endcode
+ ///
+ /// The generator is implemented as a struct.
+ ///\code
+ /// struct NumberSection {
+ /// std::vector<int>::const_iterator _it, _end;
+ /// NumberSection(const std::vector<int>& data)
+ /// : _it(data.begin()), _end(data.end()) {}
+ /// std::string operator()() {
+ /// int rem_in_line = 4;
+ /// std::ostringstream ls;
+ /// while (rem_in_line > 0 && _it != _end) {
+ /// ls << *(_it++) << ' ';
+ /// --rem_in_line;
+ /// }
+ /// return ls.str();
+ /// }
+ /// };
+ ///
+ /// // ...
+ ///
+ /// writer.sectionLines("numbers", NumberSection(vec));
+ ///\endcode
+ template <typename Functor>
+ SectionWriter& sectionLines(const std::string& type, Functor functor) {
+ LEMON_ASSERT(!type.empty(), "Type is empty.");
+ _sections.push_back(std::make_pair(type,
+ new _writer_bits::LineSection<Functor>(functor)));
+ return *this;
+ }
+
+
+ /// \brief Add a section writer with stream oriented writing
+ ///
+ /// The first parameter is the type of the section, the second is
+ /// a functor, which takes a \c std::ostream& parameter. The
+ /// functor writes the section to the output stream.
+ /// \warning The last line must be closed with end-line character.
+ template <typename Functor>
+ SectionWriter& sectionStream(const std::string& type, Functor functor) {
+ LEMON_ASSERT(!type.empty(), "Type is empty.");
+ _sections.push_back(std::make_pair(type,
+ new _writer_bits::StreamSection<Functor>(functor)));
+ return *this;
+ }
+
+ /// @}
+
+ public:
+
+
+ /// \name Execution of the Writer
+ /// @{
+
+ /// \brief Start the batch processing
+ ///
+ /// This function starts the batch processing.
+ void run() {
+
+ LEMON_ASSERT(_os != 0, "This writer is assigned to an other writer");
+
+ for (Sections::iterator it = _sections.begin();
+ it != _sections.end(); ++it) {
+ (*_os) << '@' << it->first << std::endl;
+ it->second->process(*_os);
+ }
+ }
+
+ /// \brief Give back the stream of the writer
+ ///
+ /// Returns the stream of the writer
+ std::ostream& ostream() {
+ return *_os;
+ }
+
+ /// @}
+
+ };
+
+ /// \ingroup lemon_io
+ ///
+ /// \brief Return a \ref SectionWriter class
+ ///
+ /// This function just returns a \ref SectionWriter class.
+ ///
+ /// Please see SectionWriter documentation about the custom section
+ /// output.
+ ///
+ /// \relates SectionWriter
+ /// \sa sectionWriter(const std::string& fn)
+ /// \sa sectionWriter(const char *fn)
+ inline SectionWriter sectionWriter(std::ostream& os) {
+ SectionWriter tmp(os);
+ return tmp;
+ }
+
+ /// \brief Return a \ref SectionWriter class
+ ///
+ /// This function just returns a \ref SectionWriter class.
+ /// \relates SectionWriter
+ /// \sa sectionWriter(std::ostream& os)
+ inline SectionWriter sectionWriter(const std::string& fn) {
+ SectionWriter tmp(fn);
+ return tmp;
+ }
+
+ /// \brief Return a \ref SectionWriter class
+ ///
+ /// This function just returns a \ref SectionWriter class.
+ /// \relates SectionWriter
+ /// \sa sectionWriter(std::ostream& os)
+ inline SectionWriter sectionWriter(const char* fn) {
+ SectionWriter tmp(fn);
+ return tmp;
+ }
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/list_graph.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/list_graph.h
new file mode 100644
index 00000000000..2a236cf91de
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/list_graph.h
@@ -0,0 +1,2510 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_LIST_GRAPH_H
+#define LEMON_LIST_GRAPH_H
+
+///\ingroup graphs
+///\file
+///\brief ListDigraph and ListGraph classes.
+
+#include <lemon/core.h>
+#include <lemon/error.h>
+#include <lemon/bits/graph_extender.h>
+
+#include <vector>
+#include <list>
+
+namespace lemon {
+
+ class ListDigraph;
+
+ class ListDigraphBase {
+
+ protected:
+ struct NodeT {
+ int first_in, first_out;
+ int prev, next;
+ };
+
+ struct ArcT {
+ int target, source;
+ int prev_in, prev_out;
+ int next_in, next_out;
+ };
+
+ std::vector<NodeT> nodes;
+
+ int first_node;
+
+ int first_free_node;
+
+ std::vector<ArcT> arcs;
+
+ int first_free_arc;
+
+ public:
+
+ typedef ListDigraphBase Digraph;
+
+ class Node {
+ friend class ListDigraphBase;
+ friend class ListDigraph;
+ protected:
+
+ int id;
+ explicit Node(int pid) { id = pid;}
+
+ public:
+ Node() {}
+ Node (Invalid) { id = -1; }
+ bool operator==(const Node& node) const {return id == node.id;}
+ bool operator!=(const Node& node) const {return id != node.id;}
+ bool operator<(const Node& node) const {return id < node.id;}
+ };
+
+ class Arc {
+ friend class ListDigraphBase;
+ friend class ListDigraph;
+ protected:
+
+ int id;
+ explicit Arc(int pid) { id = pid;}
+
+ public:
+ Arc() {}
+ Arc (Invalid) { id = -1; }
+ bool operator==(const Arc& arc) const {return id == arc.id;}
+ bool operator!=(const Arc& arc) const {return id != arc.id;}
+ bool operator<(const Arc& arc) const {return id < arc.id;}
+ };
+
+
+
+ ListDigraphBase()
+ : nodes(), first_node(-1),
+ first_free_node(-1), arcs(), first_free_arc(-1) {}
+
+
+ int maxNodeId() const { return nodes.size()-1; }
+ int maxArcId() const { return arcs.size()-1; }
+
+ Node source(Arc e) const { return Node(arcs[e.id].source); }
+ Node target(Arc e) const { return Node(arcs[e.id].target); }
+
+
+ void first(Node& node) const {
+ node.id = first_node;
+ }
+
+ void next(Node& node) const {
+ node.id = nodes[node.id].next;
+ }
+
+
+ void first(Arc& arc) const {
+ int n;
+ for(n = first_node;
+ n != -1 && nodes[n].first_out == -1;
+ n = nodes[n].next) {}
+ arc.id = (n == -1) ? -1 : nodes[n].first_out;
+ }
+
+ void next(Arc& arc) const {
+ if (arcs[arc.id].next_out != -1) {
+ arc.id = arcs[arc.id].next_out;
+ } else {
+ int n;
+ for(n = nodes[arcs[arc.id].source].next;
+ n != -1 && nodes[n].first_out == -1;
+ n = nodes[n].next) {}
+ arc.id = (n == -1) ? -1 : nodes[n].first_out;
+ }
+ }
+
+ void firstOut(Arc &e, const Node& v) const {
+ e.id = nodes[v.id].first_out;
+ }
+ void nextOut(Arc &e) const {
+ e.id=arcs[e.id].next_out;
+ }
+
+ void firstIn(Arc &e, const Node& v) const {
+ e.id = nodes[v.id].first_in;
+ }
+ void nextIn(Arc &e) const {
+ e.id=arcs[e.id].next_in;
+ }
+
+
+ static int id(Node v) { return v.id; }
+ static int id(Arc e) { return e.id; }
+
+ static Node nodeFromId(int id) { return Node(id);}
+ static Arc arcFromId(int id) { return Arc(id);}
+
+ bool valid(Node n) const {
+ return n.id >= 0 && n.id < static_cast<int>(nodes.size()) &&
+ nodes[n.id].prev != -2;
+ }
+
+ bool valid(Arc a) const {
+ return a.id >= 0 && a.id < static_cast<int>(arcs.size()) &&
+ arcs[a.id].prev_in != -2;
+ }
+
+ Node addNode() {
+ int n;
+
+ if(first_free_node==-1) {
+ n = nodes.size();
+ nodes.push_back(NodeT());
+ } else {
+ n = first_free_node;
+ first_free_node = nodes[n].next;
+ }
+
+ nodes[n].next = first_node;
+ if(first_node != -1) nodes[first_node].prev = n;
+ first_node = n;
+ nodes[n].prev = -1;
+
+ nodes[n].first_in = nodes[n].first_out = -1;
+
+ return Node(n);
+ }
+
+ Arc addArc(Node u, Node v) {
+ int n;
+
+ if (first_free_arc == -1) {
+ n = arcs.size();
+ arcs.push_back(ArcT());
+ } else {
+ n = first_free_arc;
+ first_free_arc = arcs[n].next_in;
+ }
+
+ arcs[n].source = u.id;
+ arcs[n].target = v.id;
+
+ arcs[n].next_out = nodes[u.id].first_out;
+ if(nodes[u.id].first_out != -1) {
+ arcs[nodes[u.id].first_out].prev_out = n;
+ }
+
+ arcs[n].next_in = nodes[v.id].first_in;
+ if(nodes[v.id].first_in != -1) {
+ arcs[nodes[v.id].first_in].prev_in = n;
+ }
+
+ arcs[n].prev_in = arcs[n].prev_out = -1;
+
+ nodes[u.id].first_out = nodes[v.id].first_in = n;
+
+ return Arc(n);
+ }
+
+ void erase(const Node& node) {
+ int n = node.id;
+
+ if(nodes[n].next != -1) {
+ nodes[nodes[n].next].prev = nodes[n].prev;
+ }
+
+ if(nodes[n].prev != -1) {
+ nodes[nodes[n].prev].next = nodes[n].next;
+ } else {
+ first_node = nodes[n].next;
+ }
+
+ nodes[n].next = first_free_node;
+ first_free_node = n;
+ nodes[n].prev = -2;
+
+ }
+
+ void erase(const Arc& arc) {
+ int n = arc.id;
+
+ if(arcs[n].next_in!=-1) {
+ arcs[arcs[n].next_in].prev_in = arcs[n].prev_in;
+ }
+
+ if(arcs[n].prev_in!=-1) {
+ arcs[arcs[n].prev_in].next_in = arcs[n].next_in;
+ } else {
+ nodes[arcs[n].target].first_in = arcs[n].next_in;
+ }
+
+
+ if(arcs[n].next_out!=-1) {
+ arcs[arcs[n].next_out].prev_out = arcs[n].prev_out;
+ }
+
+ if(arcs[n].prev_out!=-1) {
+ arcs[arcs[n].prev_out].next_out = arcs[n].next_out;
+ } else {
+ nodes[arcs[n].source].first_out = arcs[n].next_out;
+ }
+
+ arcs[n].next_in = first_free_arc;
+ first_free_arc = n;
+ arcs[n].prev_in = -2;
+ }
+
+ void clear() {
+ arcs.clear();
+ nodes.clear();
+ first_node = first_free_node = first_free_arc = -1;
+ }
+
+ protected:
+ void changeTarget(Arc e, Node n)
+ {
+ if(arcs[e.id].next_in != -1)
+ arcs[arcs[e.id].next_in].prev_in = arcs[e.id].prev_in;
+ if(arcs[e.id].prev_in != -1)
+ arcs[arcs[e.id].prev_in].next_in = arcs[e.id].next_in;
+ else nodes[arcs[e.id].target].first_in = arcs[e.id].next_in;
+ if (nodes[n.id].first_in != -1) {
+ arcs[nodes[n.id].first_in].prev_in = e.id;
+ }
+ arcs[e.id].target = n.id;
+ arcs[e.id].prev_in = -1;
+ arcs[e.id].next_in = nodes[n.id].first_in;
+ nodes[n.id].first_in = e.id;
+ }
+ void changeSource(Arc e, Node n)
+ {
+ if(arcs[e.id].next_out != -1)
+ arcs[arcs[e.id].next_out].prev_out = arcs[e.id].prev_out;
+ if(arcs[e.id].prev_out != -1)
+ arcs[arcs[e.id].prev_out].next_out = arcs[e.id].next_out;
+ else nodes[arcs[e.id].source].first_out = arcs[e.id].next_out;
+ if (nodes[n.id].first_out != -1) {
+ arcs[nodes[n.id].first_out].prev_out = e.id;
+ }
+ arcs[e.id].source = n.id;
+ arcs[e.id].prev_out = -1;
+ arcs[e.id].next_out = nodes[n.id].first_out;
+ nodes[n.id].first_out = e.id;
+ }
+
+ };
+
+ typedef DigraphExtender<ListDigraphBase> ExtendedListDigraphBase;
+
+ /// \addtogroup graphs
+ /// @{
+
+ ///A general directed graph structure.
+
+ ///\ref ListDigraph is a versatile and fast directed graph
+ ///implementation based on linked lists that are stored in
+ ///\c std::vector structures.
+ ///
+ ///This type fully conforms to the \ref concepts::Digraph "Digraph concept"
+ ///and it also provides several useful additional functionalities.
+ ///Most of its member functions and nested classes are documented
+ ///only in the concept class.
+ ///
+ ///This class provides only linear time counting for nodes and arcs.
+ ///
+ ///\sa concepts::Digraph
+ ///\sa ListGraph
+ class ListDigraph : public ExtendedListDigraphBase {
+ typedef ExtendedListDigraphBase Parent;
+
+ private:
+ /// Digraphs are \e not copy constructible. Use DigraphCopy instead.
+ ListDigraph(const ListDigraph &) :ExtendedListDigraphBase() {};
+ /// \brief Assignment of a digraph to another one is \e not allowed.
+ /// Use DigraphCopy instead.
+ void operator=(const ListDigraph &) {}
+ public:
+
+ /// Constructor
+
+ /// Constructor.
+ ///
+ ListDigraph() {}
+
+ ///Add a new node to the digraph.
+
+ ///This function adds a new node to the digraph.
+ ///\return The new node.
+ Node addNode() { return Parent::addNode(); }
+
+ ///Add a new arc to the digraph.
+
+ ///This function adds a new arc to the digraph with source node \c s
+ ///and target node \c t.
+ ///\return The new arc.
+ Arc addArc(Node s, Node t) {
+ return Parent::addArc(s, t);
+ }
+
+ ///\brief Erase a node from the digraph.
+ ///
+ ///This function erases the given node along with its outgoing and
+ ///incoming arcs from the digraph.
+ ///
+ ///\note All iterators referencing the removed node or the connected
+ ///arcs are invalidated, of course.
+ void erase(Node n) { Parent::erase(n); }
+
+ ///\brief Erase an arc from the digraph.
+ ///
+ ///This function erases the given arc from the digraph.
+ ///
+ ///\note All iterators referencing the removed arc are invalidated,
+ ///of course.
+ void erase(Arc a) { Parent::erase(a); }
+
+ /// Node validity check
+
+ /// This function gives back \c true if the given node is valid,
+ /// i.e. it is a real node of the digraph.
+ ///
+ /// \warning A removed node could become valid again if new nodes are
+ /// added to the digraph.
+ bool valid(Node n) const { return Parent::valid(n); }
+
+ /// Arc validity check
+
+ /// This function gives back \c true if the given arc is valid,
+ /// i.e. it is a real arc of the digraph.
+ ///
+ /// \warning A removed arc could become valid again if new arcs are
+ /// added to the digraph.
+ bool valid(Arc a) const { return Parent::valid(a); }
+
+ /// Change the target node of an arc
+
+ /// This function changes the target node of the given arc \c a to \c n.
+ ///
+ ///\note \c ArcIt and \c OutArcIt iterators referencing the changed
+ ///arc remain valid, but \c InArcIt iterators are invalidated.
+ ///
+ ///\warning This functionality cannot be used together with the Snapshot
+ ///feature.
+ void changeTarget(Arc a, Node n) {
+ Parent::changeTarget(a,n);
+ }
+ /// Change the source node of an arc
+
+ /// This function changes the source node of the given arc \c a to \c n.
+ ///
+ ///\note \c InArcIt iterators referencing the changed arc remain
+ ///valid, but \c ArcIt and \c OutArcIt iterators are invalidated.
+ ///
+ ///\warning This functionality cannot be used together with the Snapshot
+ ///feature.
+ void changeSource(Arc a, Node n) {
+ Parent::changeSource(a,n);
+ }
+
+ /// Reverse the direction of an arc.
+
+ /// This function reverses the direction of the given arc.
+ ///\note \c ArcIt, \c OutArcIt and \c InArcIt iterators referencing
+ ///the changed arc are invalidated.
+ ///
+ ///\warning This functionality cannot be used together with the Snapshot
+ ///feature.
+ void reverseArc(Arc a) {
+ Node t=target(a);
+ changeTarget(a,source(a));
+ changeSource(a,t);
+ }
+
+ ///Contract two nodes.
+
+ ///This function contracts the given two nodes.
+ ///Node \c v is removed, but instead of deleting its
+ ///incident arcs, they are joined to node \c u.
+ ///If the last parameter \c r is \c true (this is the default value),
+ ///then the newly created loops are removed.
+ ///
+ ///\note The moved arcs are joined to node \c u using changeSource()
+ ///or changeTarget(), thus \c ArcIt and \c OutArcIt iterators are
+ ///invalidated for the outgoing arcs of node \c v and \c InArcIt
+ ///iterators are invalidated for the incoming arcs of \c v.
+ ///Moreover all iterators referencing node \c v or the removed
+ ///loops are also invalidated. Other iterators remain valid.
+ ///
+ ///\warning This functionality cannot be used together with the Snapshot
+ ///feature.
+ void contract(Node u, Node v, bool r = true)
+ {
+ for(OutArcIt e(*this,v);e!=INVALID;) {
+ OutArcIt f=e;
+ ++f;
+ if(r && target(e)==u) erase(e);
+ else changeSource(e,u);
+ e=f;
+ }
+ for(InArcIt e(*this,v);e!=INVALID;) {
+ InArcIt f=e;
+ ++f;
+ if(r && source(e)==u) erase(e);
+ else changeTarget(e,u);
+ e=f;
+ }
+ erase(v);
+ }
+
+ ///Split a node.
+
+ ///This function splits the given node. First, a new node is added
+ ///to the digraph, then the source of each outgoing arc of node \c n
+ ///is moved to this new node.
+ ///If the second parameter \c connect is \c true (this is the default
+ ///value), then a new arc from node \c n to the newly created node
+ ///is also added.
+ ///\return The newly created node.
+ ///
+ ///\note All iterators remain valid.
+ ///
+ ///\warning This functionality cannot be used together with the
+ ///Snapshot feature.
+ Node split(Node n, bool connect = true) {
+ Node b = addNode();
+ nodes[b.id].first_out=nodes[n.id].first_out;
+ nodes[n.id].first_out=-1;
+ for(int i=nodes[b.id].first_out; i!=-1; i=arcs[i].next_out) {
+ arcs[i].source=b.id;
+ }
+ if (connect) addArc(n,b);
+ return b;
+ }
+
+ ///Split an arc.
+
+ ///This function splits the given arc. First, a new node \c v is
+ ///added to the digraph, then the target node of the original arc
+ ///is set to \c v. Finally, an arc from \c v to the original target
+ ///is added.
+ ///\return The newly created node.
+ ///
+ ///\note \c InArcIt iterators referencing the original arc are
+ ///invalidated. Other iterators remain valid.
+ ///
+ ///\warning This functionality cannot be used together with the
+ ///Snapshot feature.
+ Node split(Arc a) {
+ Node v = addNode();
+ addArc(v,target(a));
+ changeTarget(a,v);
+ return v;
+ }
+
+ ///Clear the digraph.
+
+ ///This function erases all nodes and arcs from the digraph.
+ ///
+ ///\note All iterators of the digraph are invalidated, of course.
+ void clear() {
+ Parent::clear();
+ }
+
+ /// Reserve memory for nodes.
+
+ /// Using this function, it is possible to avoid superfluous memory
+ /// allocation: if you know that the digraph you want to build will
+ /// be large (e.g. it will contain millions of nodes and/or arcs),
+ /// then it is worth reserving space for this amount before starting
+ /// to build the digraph.
+ /// \sa reserveArc()
+ void reserveNode(int n) { nodes.reserve(n); };
+
+ /// Reserve memory for arcs.
+
+ /// Using this function, it is possible to avoid superfluous memory
+ /// allocation: if you know that the digraph you want to build will
+ /// be large (e.g. it will contain millions of nodes and/or arcs),
+ /// then it is worth reserving space for this amount before starting
+ /// to build the digraph.
+ /// \sa reserveNode()
+ void reserveArc(int m) { arcs.reserve(m); };
+
+ /// \brief Class to make a snapshot of the digraph and restore
+ /// it later.
+ ///
+ /// Class to make a snapshot of the digraph and restore it later.
+ ///
+ /// The newly added nodes and arcs can be removed using the
+ /// restore() function.
+ ///
+ /// \note After a state is restored, you cannot restore a later state,
+ /// i.e. you cannot add the removed nodes and arcs again using
+ /// another Snapshot instance.
+ ///
+ /// \warning Node and arc deletions and other modifications (e.g.
+ /// reversing, contracting, splitting arcs or nodes) cannot be
+ /// restored. These events invalidate the snapshot.
+ /// However, the arcs and nodes that were added to the digraph after
+ /// making the current snapshot can be removed without invalidating it.
+ class Snapshot {
+ protected:
+
+ typedef Parent::NodeNotifier NodeNotifier;
+
+ class NodeObserverProxy : public NodeNotifier::ObserverBase {
+ public:
+
+ NodeObserverProxy(Snapshot& _snapshot)
+ : snapshot(_snapshot) {}
+
+ using NodeNotifier::ObserverBase::attach;
+ using NodeNotifier::ObserverBase::detach;
+ using NodeNotifier::ObserverBase::attached;
+
+ protected:
+
+ virtual void add(const Node& node) {
+ snapshot.addNode(node);
+ }
+ virtual void add(const std::vector<Node>& nodes) {
+ for (int i = nodes.size() - 1; i >= 0; ++i) {
+ snapshot.addNode(nodes[i]);
+ }
+ }
+ virtual void erase(const Node& node) {
+ snapshot.eraseNode(node);
+ }
+ virtual void erase(const std::vector<Node>& nodes) {
+ for (int i = 0; i < int(nodes.size()); ++i) {
+ snapshot.eraseNode(nodes[i]);
+ }
+ }
+ virtual void build() {
+ Node node;
+ std::vector<Node> nodes;
+ for (notifier()->first(node); node != INVALID;
+ notifier()->next(node)) {
+ nodes.push_back(node);
+ }
+ for (int i = nodes.size() - 1; i >= 0; --i) {
+ snapshot.addNode(nodes[i]);
+ }
+ }
+ virtual void clear() {
+ Node node;
+ for (notifier()->first(node); node != INVALID;
+ notifier()->next(node)) {
+ snapshot.eraseNode(node);
+ }
+ }
+
+ Snapshot& snapshot;
+ };
+
+ class ArcObserverProxy : public ArcNotifier::ObserverBase {
+ public:
+
+ ArcObserverProxy(Snapshot& _snapshot)
+ : snapshot(_snapshot) {}
+
+ using ArcNotifier::ObserverBase::attach;
+ using ArcNotifier::ObserverBase::detach;
+ using ArcNotifier::ObserverBase::attached;
+
+ protected:
+
+ virtual void add(const Arc& arc) {
+ snapshot.addArc(arc);
+ }
+ virtual void add(const std::vector<Arc>& arcs) {
+ for (int i = arcs.size() - 1; i >= 0; ++i) {
+ snapshot.addArc(arcs[i]);
+ }
+ }
+ virtual void erase(const Arc& arc) {
+ snapshot.eraseArc(arc);
+ }
+ virtual void erase(const std::vector<Arc>& arcs) {
+ for (int i = 0; i < int(arcs.size()); ++i) {
+ snapshot.eraseArc(arcs[i]);
+ }
+ }
+ virtual void build() {
+ Arc arc;
+ std::vector<Arc> arcs;
+ for (notifier()->first(arc); arc != INVALID;
+ notifier()->next(arc)) {
+ arcs.push_back(arc);
+ }
+ for (int i = arcs.size() - 1; i >= 0; --i) {
+ snapshot.addArc(arcs[i]);
+ }
+ }
+ virtual void clear() {
+ Arc arc;
+ for (notifier()->first(arc); arc != INVALID;
+ notifier()->next(arc)) {
+ snapshot.eraseArc(arc);
+ }
+ }
+
+ Snapshot& snapshot;
+ };
+
+ ListDigraph *digraph;
+
+ NodeObserverProxy node_observer_proxy;
+ ArcObserverProxy arc_observer_proxy;
+
+ std::list<Node> added_nodes;
+ std::list<Arc> added_arcs;
+
+
+ void addNode(const Node& node) {
+ added_nodes.push_front(node);
+ }
+ void eraseNode(const Node& node) {
+ std::list<Node>::iterator it =
+ std::find(added_nodes.begin(), added_nodes.end(), node);
+ if (it == added_nodes.end()) {
+ clear();
+ arc_observer_proxy.detach();
+ throw NodeNotifier::ImmediateDetach();
+ } else {
+ added_nodes.erase(it);
+ }
+ }
+
+ void addArc(const Arc& arc) {
+ added_arcs.push_front(arc);
+ }
+ void eraseArc(const Arc& arc) {
+ std::list<Arc>::iterator it =
+ std::find(added_arcs.begin(), added_arcs.end(), arc);
+ if (it == added_arcs.end()) {
+ clear();
+ node_observer_proxy.detach();
+ throw ArcNotifier::ImmediateDetach();
+ } else {
+ added_arcs.erase(it);
+ }
+ }
+
+ void attach(ListDigraph &_digraph) {
+ digraph = &_digraph;
+ node_observer_proxy.attach(digraph->notifier(Node()));
+ arc_observer_proxy.attach(digraph->notifier(Arc()));
+ }
+
+ void detach() {
+ node_observer_proxy.detach();
+ arc_observer_proxy.detach();
+ }
+
+ bool attached() const {
+ return node_observer_proxy.attached();
+ }
+
+ void clear() {
+ added_nodes.clear();
+ added_arcs.clear();
+ }
+
+ public:
+
+ /// \brief Default constructor.
+ ///
+ /// Default constructor.
+ /// You have to call save() to actually make a snapshot.
+ Snapshot()
+ : digraph(0), node_observer_proxy(*this),
+ arc_observer_proxy(*this) {}
+
+ /// \brief Constructor that immediately makes a snapshot.
+ ///
+ /// This constructor immediately makes a snapshot of the given digraph.
+ Snapshot(ListDigraph &gr)
+ : node_observer_proxy(*this),
+ arc_observer_proxy(*this) {
+ attach(gr);
+ }
+
+ /// \brief Make a snapshot.
+ ///
+ /// This function makes a snapshot of the given digraph.
+ /// It can be called more than once. In case of a repeated
+ /// call, the previous snapshot gets lost.
+ void save(ListDigraph &gr) {
+ if (attached()) {
+ detach();
+ clear();
+ }
+ attach(gr);
+ }
+
+ /// \brief Undo the changes until the last snapshot.
+ ///
+ /// This function undos the changes until the last snapshot
+ /// created by save() or Snapshot(ListDigraph&).
+ ///
+ /// \warning This method invalidates the snapshot, i.e. repeated
+ /// restoring is not supported unless you call save() again.
+ void restore() {
+ detach();
+ for(std::list<Arc>::iterator it = added_arcs.begin();
+ it != added_arcs.end(); ++it) {
+ digraph->erase(*it);
+ }
+ for(std::list<Node>::iterator it = added_nodes.begin();
+ it != added_nodes.end(); ++it) {
+ digraph->erase(*it);
+ }
+ clear();
+ }
+
+ /// \brief Returns \c true if the snapshot is valid.
+ ///
+ /// This function returns \c true if the snapshot is valid.
+ bool valid() const {
+ return attached();
+ }
+ };
+
+ };
+
+ ///@}
+
+ class ListGraphBase {
+
+ protected:
+
+ struct NodeT {
+ int first_out;
+ int prev, next;
+ };
+
+ struct ArcT {
+ int target;
+ int prev_out, next_out;
+ };
+
+ std::vector<NodeT> nodes;
+
+ int first_node;
+
+ int first_free_node;
+
+ std::vector<ArcT> arcs;
+
+ int first_free_arc;
+
+ public:
+
+ typedef ListGraphBase Graph;
+
+ class Node {
+ friend class ListGraphBase;
+ protected:
+
+ int id;
+ explicit Node(int pid) { id = pid;}
+
+ public:
+ Node() {}
+ Node (Invalid) { id = -1; }
+ bool operator==(const Node& node) const {return id == node.id;}
+ bool operator!=(const Node& node) const {return id != node.id;}
+ bool operator<(const Node& node) const {return id < node.id;}
+ };
+
+ class Edge {
+ friend class ListGraphBase;
+ protected:
+
+ int id;
+ explicit Edge(int pid) { id = pid;}
+
+ public:
+ Edge() {}
+ Edge (Invalid) { id = -1; }
+ bool operator==(const Edge& edge) const {return id == edge.id;}
+ bool operator!=(const Edge& edge) const {return id != edge.id;}
+ bool operator<(const Edge& edge) const {return id < edge.id;}
+ };
+
+ class Arc {
+ friend class ListGraphBase;
+ protected:
+
+ int id;
+ explicit Arc(int pid) { id = pid;}
+
+ public:
+ operator Edge() const {
+ return id != -1 ? edgeFromId(id / 2) : INVALID;
+ }
+
+ Arc() {}
+ Arc (Invalid) { id = -1; }
+ bool operator==(const Arc& arc) const {return id == arc.id;}
+ bool operator!=(const Arc& arc) const {return id != arc.id;}
+ bool operator<(const Arc& arc) const {return id < arc.id;}
+ };
+
+ ListGraphBase()
+ : nodes(), first_node(-1),
+ first_free_node(-1), arcs(), first_free_arc(-1) {}
+
+
+ int maxNodeId() const { return nodes.size()-1; }
+ int maxEdgeId() const { return arcs.size() / 2 - 1; }
+ int maxArcId() const { return arcs.size()-1; }
+
+ Node source(Arc e) const { return Node(arcs[e.id ^ 1].target); }
+ Node target(Arc e) const { return Node(arcs[e.id].target); }
+
+ Node u(Edge e) const { return Node(arcs[2 * e.id].target); }
+ Node v(Edge e) const { return Node(arcs[2 * e.id + 1].target); }
+
+ static bool direction(Arc e) {
+ return (e.id & 1) == 1;
+ }
+
+ static Arc direct(Edge e, bool d) {
+ return Arc(e.id * 2 + (d ? 1 : 0));
+ }
+
+ void first(Node& node) const {
+ node.id = first_node;
+ }
+
+ void next(Node& node) const {
+ node.id = nodes[node.id].next;
+ }
+
+ void first(Arc& e) const {
+ int n = first_node;
+ while (n != -1 && nodes[n].first_out == -1) {
+ n = nodes[n].next;
+ }
+ e.id = (n == -1) ? -1 : nodes[n].first_out;
+ }
+
+ void next(Arc& e) const {
+ if (arcs[e.id].next_out != -1) {
+ e.id = arcs[e.id].next_out;
+ } else {
+ int n = nodes[arcs[e.id ^ 1].target].next;
+ while(n != -1 && nodes[n].first_out == -1) {
+ n = nodes[n].next;
+ }
+ e.id = (n == -1) ? -1 : nodes[n].first_out;
+ }
+ }
+
+ void first(Edge& e) const {
+ int n = first_node;
+ while (n != -1) {
+ e.id = nodes[n].first_out;
+ while ((e.id & 1) != 1) {
+ e.id = arcs[e.id].next_out;
+ }
+ if (e.id != -1) {
+ e.id /= 2;
+ return;
+ }
+ n = nodes[n].next;
+ }
+ e.id = -1;
+ }
+
+ void next(Edge& e) const {
+ int n = arcs[e.id * 2].target;
+ e.id = arcs[(e.id * 2) | 1].next_out;
+ while ((e.id & 1) != 1) {
+ e.id = arcs[e.id].next_out;
+ }
+ if (e.id != -1) {
+ e.id /= 2;
+ return;
+ }
+ n = nodes[n].next;
+ while (n != -1) {
+ e.id = nodes[n].first_out;
+ while ((e.id & 1) != 1) {
+ e.id = arcs[e.id].next_out;
+ }
+ if (e.id != -1) {
+ e.id /= 2;
+ return;
+ }
+ n = nodes[n].next;
+ }
+ e.id = -1;
+ }
+
+ void firstOut(Arc &e, const Node& v) const {
+ e.id = nodes[v.id].first_out;
+ }
+ void nextOut(Arc &e) const {
+ e.id = arcs[e.id].next_out;
+ }
+
+ void firstIn(Arc &e, const Node& v) const {
+ e.id = ((nodes[v.id].first_out) ^ 1);
+ if (e.id == -2) e.id = -1;
+ }
+ void nextIn(Arc &e) const {
+ e.id = ((arcs[e.id ^ 1].next_out) ^ 1);
+ if (e.id == -2) e.id = -1;
+ }
+
+ void firstInc(Edge &e, bool& d, const Node& v) const {
+ int a = nodes[v.id].first_out;
+ if (a != -1 ) {
+ e.id = a / 2;
+ d = ((a & 1) == 1);
+ } else {
+ e.id = -1;
+ d = true;
+ }
+ }
+ void nextInc(Edge &e, bool& d) const {
+ int a = (arcs[(e.id * 2) | (d ? 1 : 0)].next_out);
+ if (a != -1 ) {
+ e.id = a / 2;
+ d = ((a & 1) == 1);
+ } else {
+ e.id = -1;
+ d = true;
+ }
+ }
+
+ static int id(Node v) { return v.id; }
+ static int id(Arc e) { return e.id; }
+ static int id(Edge e) { return e.id; }
+
+ static Node nodeFromId(int id) { return Node(id);}
+ static Arc arcFromId(int id) { return Arc(id);}
+ static Edge edgeFromId(int id) { return Edge(id);}
+
+ bool valid(Node n) const {
+ return n.id >= 0 && n.id < static_cast<int>(nodes.size()) &&
+ nodes[n.id].prev != -2;
+ }
+
+ bool valid(Arc a) const {
+ return a.id >= 0 && a.id < static_cast<int>(arcs.size()) &&
+ arcs[a.id].prev_out != -2;
+ }
+
+ bool valid(Edge e) const {
+ return e.id >= 0 && 2 * e.id < static_cast<int>(arcs.size()) &&
+ arcs[2 * e.id].prev_out != -2;
+ }
+
+ Node addNode() {
+ int n;
+
+ if(first_free_node==-1) {
+ n = nodes.size();
+ nodes.push_back(NodeT());
+ } else {
+ n = first_free_node;
+ first_free_node = nodes[n].next;
+ }
+
+ nodes[n].next = first_node;
+ if (first_node != -1) nodes[first_node].prev = n;
+ first_node = n;
+ nodes[n].prev = -1;
+
+ nodes[n].first_out = -1;
+
+ return Node(n);
+ }
+
+ Edge addEdge(Node u, Node v) {
+ int n;
+
+ if (first_free_arc == -1) {
+ n = arcs.size();
+ arcs.push_back(ArcT());
+ arcs.push_back(ArcT());
+ } else {
+ n = first_free_arc;
+ first_free_arc = arcs[n].next_out;
+ }
+
+ arcs[n].target = u.id;
+ arcs[n | 1].target = v.id;
+
+ arcs[n].next_out = nodes[v.id].first_out;
+ if (nodes[v.id].first_out != -1) {
+ arcs[nodes[v.id].first_out].prev_out = n;
+ }
+ arcs[n].prev_out = -1;
+ nodes[v.id].first_out = n;
+
+ arcs[n | 1].next_out = nodes[u.id].first_out;
+ if (nodes[u.id].first_out != -1) {
+ arcs[nodes[u.id].first_out].prev_out = (n | 1);
+ }
+ arcs[n | 1].prev_out = -1;
+ nodes[u.id].first_out = (n | 1);
+
+ return Edge(n / 2);
+ }
+
+ void erase(const Node& node) {
+ int n = node.id;
+
+ if(nodes[n].next != -1) {
+ nodes[nodes[n].next].prev = nodes[n].prev;
+ }
+
+ if(nodes[n].prev != -1) {
+ nodes[nodes[n].prev].next = nodes[n].next;
+ } else {
+ first_node = nodes[n].next;
+ }
+
+ nodes[n].next = first_free_node;
+ first_free_node = n;
+ nodes[n].prev = -2;
+ }
+
+ void erase(const Edge& edge) {
+ int n = edge.id * 2;
+
+ if (arcs[n].next_out != -1) {
+ arcs[arcs[n].next_out].prev_out = arcs[n].prev_out;
+ }
+
+ if (arcs[n].prev_out != -1) {
+ arcs[arcs[n].prev_out].next_out = arcs[n].next_out;
+ } else {
+ nodes[arcs[n | 1].target].first_out = arcs[n].next_out;
+ }
+
+ if (arcs[n | 1].next_out != -1) {
+ arcs[arcs[n | 1].next_out].prev_out = arcs[n | 1].prev_out;
+ }
+
+ if (arcs[n | 1].prev_out != -1) {
+ arcs[arcs[n | 1].prev_out].next_out = arcs[n | 1].next_out;
+ } else {
+ nodes[arcs[n].target].first_out = arcs[n | 1].next_out;
+ }
+
+ arcs[n].next_out = first_free_arc;
+ first_free_arc = n;
+ arcs[n].prev_out = -2;
+ arcs[n | 1].prev_out = -2;
+
+ }
+
+ void clear() {
+ arcs.clear();
+ nodes.clear();
+ first_node = first_free_node = first_free_arc = -1;
+ }
+
+ protected:
+
+ void changeV(Edge e, Node n) {
+ if(arcs[2 * e.id].next_out != -1) {
+ arcs[arcs[2 * e.id].next_out].prev_out = arcs[2 * e.id].prev_out;
+ }
+ if(arcs[2 * e.id].prev_out != -1) {
+ arcs[arcs[2 * e.id].prev_out].next_out =
+ arcs[2 * e.id].next_out;
+ } else {
+ nodes[arcs[(2 * e.id) | 1].target].first_out =
+ arcs[2 * e.id].next_out;
+ }
+
+ if (nodes[n.id].first_out != -1) {
+ arcs[nodes[n.id].first_out].prev_out = 2 * e.id;
+ }
+ arcs[(2 * e.id) | 1].target = n.id;
+ arcs[2 * e.id].prev_out = -1;
+ arcs[2 * e.id].next_out = nodes[n.id].first_out;
+ nodes[n.id].first_out = 2 * e.id;
+ }
+
+ void changeU(Edge e, Node n) {
+ if(arcs[(2 * e.id) | 1].next_out != -1) {
+ arcs[arcs[(2 * e.id) | 1].next_out].prev_out =
+ arcs[(2 * e.id) | 1].prev_out;
+ }
+ if(arcs[(2 * e.id) | 1].prev_out != -1) {
+ arcs[arcs[(2 * e.id) | 1].prev_out].next_out =
+ arcs[(2 * e.id) | 1].next_out;
+ } else {
+ nodes[arcs[2 * e.id].target].first_out =
+ arcs[(2 * e.id) | 1].next_out;
+ }
+
+ if (nodes[n.id].first_out != -1) {
+ arcs[nodes[n.id].first_out].prev_out = ((2 * e.id) | 1);
+ }
+ arcs[2 * e.id].target = n.id;
+ arcs[(2 * e.id) | 1].prev_out = -1;
+ arcs[(2 * e.id) | 1].next_out = nodes[n.id].first_out;
+ nodes[n.id].first_out = ((2 * e.id) | 1);
+ }
+
+ };
+
+ typedef GraphExtender<ListGraphBase> ExtendedListGraphBase;
+
+
+ /// \addtogroup graphs
+ /// @{
+
+ ///A general undirected graph structure.
+
+ ///\ref ListGraph is a versatile and fast undirected graph
+ ///implementation based on linked lists that are stored in
+ ///\c std::vector structures.
+ ///
+ ///This type fully conforms to the \ref concepts::Graph "Graph concept"
+ ///and it also provides several useful additional functionalities.
+ ///Most of its member functions and nested classes are documented
+ ///only in the concept class.
+ ///
+ ///This class provides only linear time counting for nodes, edges and arcs.
+ ///
+ ///\sa concepts::Graph
+ ///\sa ListDigraph
+ class ListGraph : public ExtendedListGraphBase {
+ typedef ExtendedListGraphBase Parent;
+
+ private:
+ /// Graphs are \e not copy constructible. Use GraphCopy instead.
+ ListGraph(const ListGraph &) :ExtendedListGraphBase() {};
+ /// \brief Assignment of a graph to another one is \e not allowed.
+ /// Use GraphCopy instead.
+ void operator=(const ListGraph &) {}
+ public:
+ /// Constructor
+
+ /// Constructor.
+ ///
+ ListGraph() {}
+
+ typedef Parent::OutArcIt IncEdgeIt;
+
+ /// \brief Add a new node to the graph.
+ ///
+ /// This function adds a new node to the graph.
+ /// \return The new node.
+ Node addNode() { return Parent::addNode(); }
+
+ /// \brief Add a new edge to the graph.
+ ///
+ /// This function adds a new edge to the graph between nodes
+ /// \c u and \c v with inherent orientation from node \c u to
+ /// node \c v.
+ /// \return The new edge.
+ Edge addEdge(Node u, Node v) {
+ return Parent::addEdge(u, v);
+ }
+
+ ///\brief Erase a node from the graph.
+ ///
+ /// This function erases the given node along with its incident arcs
+ /// from the graph.
+ ///
+ /// \note All iterators referencing the removed node or the incident
+ /// edges are invalidated, of course.
+ void erase(Node n) { Parent::erase(n); }
+
+ ///\brief Erase an edge from the graph.
+ ///
+ /// This function erases the given edge from the graph.
+ ///
+ /// \note All iterators referencing the removed edge are invalidated,
+ /// of course.
+ void erase(Edge e) { Parent::erase(e); }
+ /// Node validity check
+
+ /// This function gives back \c true if the given node is valid,
+ /// i.e. it is a real node of the graph.
+ ///
+ /// \warning A removed node could become valid again if new nodes are
+ /// added to the graph.
+ bool valid(Node n) const { return Parent::valid(n); }
+ /// Edge validity check
+
+ /// This function gives back \c true if the given edge is valid,
+ /// i.e. it is a real edge of the graph.
+ ///
+ /// \warning A removed edge could become valid again if new edges are
+ /// added to the graph.
+ bool valid(Edge e) const { return Parent::valid(e); }
+ /// Arc validity check
+
+ /// This function gives back \c true if the given arc is valid,
+ /// i.e. it is a real arc of the graph.
+ ///
+ /// \warning A removed arc could become valid again if new edges are
+ /// added to the graph.
+ bool valid(Arc a) const { return Parent::valid(a); }
+
+ /// \brief Change the first node of an edge.
+ ///
+ /// This function changes the first node of the given edge \c e to \c n.
+ ///
+ ///\note \c EdgeIt and \c ArcIt iterators referencing the
+ ///changed edge are invalidated and all other iterators whose
+ ///base node is the changed node are also invalidated.
+ ///
+ ///\warning This functionality cannot be used together with the
+ ///Snapshot feature.
+ void changeU(Edge e, Node n) {
+ Parent::changeU(e,n);
+ }
+ /// \brief Change the second node of an edge.
+ ///
+ /// This function changes the second node of the given edge \c e to \c n.
+ ///
+ ///\note \c EdgeIt iterators referencing the changed edge remain
+ ///valid, but \c ArcIt iterators referencing the changed edge and
+ ///all other iterators whose base node is the changed node are also
+ ///invalidated.
+ ///
+ ///\warning This functionality cannot be used together with the
+ ///Snapshot feature.
+ void changeV(Edge e, Node n) {
+ Parent::changeV(e,n);
+ }
+
+ /// \brief Contract two nodes.
+ ///
+ /// This function contracts the given two nodes.
+ /// Node \c b is removed, but instead of deleting
+ /// its incident edges, they are joined to node \c a.
+ /// If the last parameter \c r is \c true (this is the default value),
+ /// then the newly created loops are removed.
+ ///
+ /// \note The moved edges are joined to node \c a using changeU()
+ /// or changeV(), thus all edge and arc iterators whose base node is
+ /// \c b are invalidated.
+ /// Moreover all iterators referencing node \c b or the removed
+ /// loops are also invalidated. Other iterators remain valid.
+ ///
+ ///\warning This functionality cannot be used together with the
+ ///Snapshot feature.
+ void contract(Node a, Node b, bool r = true) {
+ for(IncEdgeIt e(*this, b); e!=INVALID;) {
+ IncEdgeIt f = e; ++f;
+ if (r && runningNode(e) == a) {
+ erase(e);
+ } else if (u(e) == b) {
+ changeU(e, a);
+ } else {
+ changeV(e, a);
+ }
+ e = f;
+ }
+ erase(b);
+ }
+
+ ///Clear the graph.
+
+ ///This function erases all nodes and arcs from the graph.
+ ///
+ ///\note All iterators of the graph are invalidated, of course.
+ void clear() {
+ Parent::clear();
+ }
+
+ /// Reserve memory for nodes.
+
+ /// Using this function, it is possible to avoid superfluous memory
+ /// allocation: if you know that the graph you want to build will
+ /// be large (e.g. it will contain millions of nodes and/or edges),
+ /// then it is worth reserving space for this amount before starting
+ /// to build the graph.
+ /// \sa reserveEdge()
+ void reserveNode(int n) { nodes.reserve(n); };
+
+ /// Reserve memory for edges.
+
+ /// Using this function, it is possible to avoid superfluous memory
+ /// allocation: if you know that the graph you want to build will
+ /// be large (e.g. it will contain millions of nodes and/or edges),
+ /// then it is worth reserving space for this amount before starting
+ /// to build the graph.
+ /// \sa reserveNode()
+ void reserveEdge(int m) { arcs.reserve(2 * m); };
+
+ /// \brief Class to make a snapshot of the graph and restore
+ /// it later.
+ ///
+ /// Class to make a snapshot of the graph and restore it later.
+ ///
+ /// The newly added nodes and edges can be removed
+ /// using the restore() function.
+ ///
+ /// \note After a state is restored, you cannot restore a later state,
+ /// i.e. you cannot add the removed nodes and edges again using
+ /// another Snapshot instance.
+ ///
+ /// \warning Node and edge deletions and other modifications
+ /// (e.g. changing the end-nodes of edges or contracting nodes)
+ /// cannot be restored. These events invalidate the snapshot.
+ /// However, the edges and nodes that were added to the graph after
+ /// making the current snapshot can be removed without invalidating it.
+ class Snapshot {
+ protected:
+
+ typedef Parent::NodeNotifier NodeNotifier;
+
+ class NodeObserverProxy : public NodeNotifier::ObserverBase {
+ public:
+
+ NodeObserverProxy(Snapshot& _snapshot)
+ : snapshot(_snapshot) {}
+
+ using NodeNotifier::ObserverBase::attach;
+ using NodeNotifier::ObserverBase::detach;
+ using NodeNotifier::ObserverBase::attached;
+
+ protected:
+
+ virtual void add(const Node& node) {
+ snapshot.addNode(node);
+ }
+ virtual void add(const std::vector<Node>& nodes) {
+ for (int i = nodes.size() - 1; i >= 0; ++i) {
+ snapshot.addNode(nodes[i]);
+ }
+ }
+ virtual void erase(const Node& node) {
+ snapshot.eraseNode(node);
+ }
+ virtual void erase(const std::vector<Node>& nodes) {
+ for (int i = 0; i < int(nodes.size()); ++i) {
+ snapshot.eraseNode(nodes[i]);
+ }
+ }
+ virtual void build() {
+ Node node;
+ std::vector<Node> nodes;
+ for (notifier()->first(node); node != INVALID;
+ notifier()->next(node)) {
+ nodes.push_back(node);
+ }
+ for (int i = nodes.size() - 1; i >= 0; --i) {
+ snapshot.addNode(nodes[i]);
+ }
+ }
+ virtual void clear() {
+ Node node;
+ for (notifier()->first(node); node != INVALID;
+ notifier()->next(node)) {
+ snapshot.eraseNode(node);
+ }
+ }
+
+ Snapshot& snapshot;
+ };
+
+ class EdgeObserverProxy : public EdgeNotifier::ObserverBase {
+ public:
+
+ EdgeObserverProxy(Snapshot& _snapshot)
+ : snapshot(_snapshot) {}
+
+ using EdgeNotifier::ObserverBase::attach;
+ using EdgeNotifier::ObserverBase::detach;
+ using EdgeNotifier::ObserverBase::attached;
+
+ protected:
+
+ virtual void add(const Edge& edge) {
+ snapshot.addEdge(edge);
+ }
+ virtual void add(const std::vector<Edge>& edges) {
+ for (int i = edges.size() - 1; i >= 0; ++i) {
+ snapshot.addEdge(edges[i]);
+ }
+ }
+ virtual void erase(const Edge& edge) {
+ snapshot.eraseEdge(edge);
+ }
+ virtual void erase(const std::vector<Edge>& edges) {
+ for (int i = 0; i < int(edges.size()); ++i) {
+ snapshot.eraseEdge(edges[i]);
+ }
+ }
+ virtual void build() {
+ Edge edge;
+ std::vector<Edge> edges;
+ for (notifier()->first(edge); edge != INVALID;
+ notifier()->next(edge)) {
+ edges.push_back(edge);
+ }
+ for (int i = edges.size() - 1; i >= 0; --i) {
+ snapshot.addEdge(edges[i]);
+ }
+ }
+ virtual void clear() {
+ Edge edge;
+ for (notifier()->first(edge); edge != INVALID;
+ notifier()->next(edge)) {
+ snapshot.eraseEdge(edge);
+ }
+ }
+
+ Snapshot& snapshot;
+ };
+
+ ListGraph *graph;
+
+ NodeObserverProxy node_observer_proxy;
+ EdgeObserverProxy edge_observer_proxy;
+
+ std::list<Node> added_nodes;
+ std::list<Edge> added_edges;
+
+
+ void addNode(const Node& node) {
+ added_nodes.push_front(node);
+ }
+ void eraseNode(const Node& node) {
+ std::list<Node>::iterator it =
+ std::find(added_nodes.begin(), added_nodes.end(), node);
+ if (it == added_nodes.end()) {
+ clear();
+ edge_observer_proxy.detach();
+ throw NodeNotifier::ImmediateDetach();
+ } else {
+ added_nodes.erase(it);
+ }
+ }
+
+ void addEdge(const Edge& edge) {
+ added_edges.push_front(edge);
+ }
+ void eraseEdge(const Edge& edge) {
+ std::list<Edge>::iterator it =
+ std::find(added_edges.begin(), added_edges.end(), edge);
+ if (it == added_edges.end()) {
+ clear();
+ node_observer_proxy.detach();
+ throw EdgeNotifier::ImmediateDetach();
+ } else {
+ added_edges.erase(it);
+ }
+ }
+
+ void attach(ListGraph &_graph) {
+ graph = &_graph;
+ node_observer_proxy.attach(graph->notifier(Node()));
+ edge_observer_proxy.attach(graph->notifier(Edge()));
+ }
+
+ void detach() {
+ node_observer_proxy.detach();
+ edge_observer_proxy.detach();
+ }
+
+ bool attached() const {
+ return node_observer_proxy.attached();
+ }
+
+ void clear() {
+ added_nodes.clear();
+ added_edges.clear();
+ }
+
+ public:
+
+ /// \brief Default constructor.
+ ///
+ /// Default constructor.
+ /// You have to call save() to actually make a snapshot.
+ Snapshot()
+ : graph(0), node_observer_proxy(*this),
+ edge_observer_proxy(*this) {}
+
+ /// \brief Constructor that immediately makes a snapshot.
+ ///
+ /// This constructor immediately makes a snapshot of the given graph.
+ Snapshot(ListGraph &gr)
+ : node_observer_proxy(*this),
+ edge_observer_proxy(*this) {
+ attach(gr);
+ }
+
+ /// \brief Make a snapshot.
+ ///
+ /// This function makes a snapshot of the given graph.
+ /// It can be called more than once. In case of a repeated
+ /// call, the previous snapshot gets lost.
+ void save(ListGraph &gr) {
+ if (attached()) {
+ detach();
+ clear();
+ }
+ attach(gr);
+ }
+
+ /// \brief Undo the changes until the last snapshot.
+ ///
+ /// This function undos the changes until the last snapshot
+ /// created by save() or Snapshot(ListGraph&).
+ ///
+ /// \warning This method invalidates the snapshot, i.e. repeated
+ /// restoring is not supported unless you call save() again.
+ void restore() {
+ detach();
+ for(std::list<Edge>::iterator it = added_edges.begin();
+ it != added_edges.end(); ++it) {
+ graph->erase(*it);
+ }
+ for(std::list<Node>::iterator it = added_nodes.begin();
+ it != added_nodes.end(); ++it) {
+ graph->erase(*it);
+ }
+ clear();
+ }
+
+ /// \brief Returns \c true if the snapshot is valid.
+ ///
+ /// This function returns \c true if the snapshot is valid.
+ bool valid() const {
+ return attached();
+ }
+ };
+ };
+
+ /// @}
+
+ class ListBpGraphBase {
+
+ protected:
+
+ struct NodeT {
+ int first_out;
+ int prev, next;
+ int partition_prev, partition_next;
+ int partition_index;
+ bool red;
+ };
+
+ struct ArcT {
+ int target;
+ int prev_out, next_out;
+ };
+
+ std::vector<NodeT> nodes;
+
+ int first_node, first_red, first_blue;
+ int max_red, max_blue;
+
+ int first_free_red, first_free_blue;
+
+ std::vector<ArcT> arcs;
+
+ int first_free_arc;
+
+ public:
+
+ typedef ListBpGraphBase BpGraph;
+
+ class Node {
+ friend class ListBpGraphBase;
+ protected:
+
+ int id;
+ explicit Node(int pid) { id = pid;}
+
+ public:
+ Node() {}
+ Node (Invalid) { id = -1; }
+ bool operator==(const Node& node) const {return id == node.id;}
+ bool operator!=(const Node& node) const {return id != node.id;}
+ bool operator<(const Node& node) const {return id < node.id;}
+ };
+
+ class RedNode : public Node {
+ friend class ListBpGraphBase;
+ protected:
+
+ explicit RedNode(int pid) : Node(pid) {}
+
+ public:
+ RedNode() {}
+ RedNode(const RedNode& node) : Node(node) {}
+ RedNode(Invalid) : Node(INVALID){}
+ };
+
+ class BlueNode : public Node {
+ friend class ListBpGraphBase;
+ protected:
+
+ explicit BlueNode(int pid) : Node(pid) {}
+
+ public:
+ BlueNode() {}
+ BlueNode(const BlueNode& node) : Node(node) {}
+ BlueNode(Invalid) : Node(INVALID){}
+ };
+
+ class Edge {
+ friend class ListBpGraphBase;
+ protected:
+
+ int id;
+ explicit Edge(int pid) { id = pid;}
+
+ public:
+ Edge() {}
+ Edge (Invalid) { id = -1; }
+ bool operator==(const Edge& edge) const {return id == edge.id;}
+ bool operator!=(const Edge& edge) const {return id != edge.id;}
+ bool operator<(const Edge& edge) const {return id < edge.id;}
+ };
+
+ class Arc {
+ friend class ListBpGraphBase;
+ protected:
+
+ int id;
+ explicit Arc(int pid) { id = pid;}
+
+ public:
+ operator Edge() const {
+ return id != -1 ? edgeFromId(id / 2) : INVALID;
+ }
+
+ Arc() {}
+ Arc (Invalid) { id = -1; }
+ bool operator==(const Arc& arc) const {return id == arc.id;}
+ bool operator!=(const Arc& arc) const {return id != arc.id;}
+ bool operator<(const Arc& arc) const {return id < arc.id;}
+ };
+
+ ListBpGraphBase()
+ : nodes(), first_node(-1),
+ first_red(-1), first_blue(-1),
+ max_red(-1), max_blue(-1),
+ first_free_red(-1), first_free_blue(-1),
+ arcs(), first_free_arc(-1) {}
+
+
+ bool red(Node n) const { return nodes[n.id].red; }
+ bool blue(Node n) const { return !nodes[n.id].red; }
+
+ static RedNode asRedNodeUnsafe(Node n) { return RedNode(n.id); }
+ static BlueNode asBlueNodeUnsafe(Node n) { return BlueNode(n.id); }
+
+ int maxNodeId() const { return nodes.size()-1; }
+ int maxRedId() const { return max_red; }
+ int maxBlueId() const { return max_blue; }
+ int maxEdgeId() const { return arcs.size() / 2 - 1; }
+ int maxArcId() const { return arcs.size()-1; }
+
+ Node source(Arc e) const { return Node(arcs[e.id ^ 1].target); }
+ Node target(Arc e) const { return Node(arcs[e.id].target); }
+
+ RedNode redNode(Edge e) const {
+ return RedNode(arcs[2 * e.id].target);
+ }
+ BlueNode blueNode(Edge e) const {
+ return BlueNode(arcs[2 * e.id + 1].target);
+ }
+
+ static bool direction(Arc e) {
+ return (e.id & 1) == 1;
+ }
+
+ static Arc direct(Edge e, bool d) {
+ return Arc(e.id * 2 + (d ? 1 : 0));
+ }
+
+ void first(Node& node) const {
+ node.id = first_node;
+ }
+
+ void next(Node& node) const {
+ node.id = nodes[node.id].next;
+ }
+
+ void first(RedNode& node) const {
+ node.id = first_red;
+ }
+
+ void next(RedNode& node) const {
+ node.id = nodes[node.id].partition_next;
+ }
+
+ void first(BlueNode& node) const {
+ node.id = first_blue;
+ }
+
+ void next(BlueNode& node) const {
+ node.id = nodes[node.id].partition_next;
+ }
+
+ void first(Arc& e) const {
+ int n = first_node;
+ while (n != -1 && nodes[n].first_out == -1) {
+ n = nodes[n].next;
+ }
+ e.id = (n == -1) ? -1 : nodes[n].first_out;
+ }
+
+ void next(Arc& e) const {
+ if (arcs[e.id].next_out != -1) {
+ e.id = arcs[e.id].next_out;
+ } else {
+ int n = nodes[arcs[e.id ^ 1].target].next;
+ while(n != -1 && nodes[n].first_out == -1) {
+ n = nodes[n].next;
+ }
+ e.id = (n == -1) ? -1 : nodes[n].first_out;
+ }
+ }
+
+ void first(Edge& e) const {
+ int n = first_node;
+ while (n != -1) {
+ e.id = nodes[n].first_out;
+ while ((e.id & 1) != 1) {
+ e.id = arcs[e.id].next_out;
+ }
+ if (e.id != -1) {
+ e.id /= 2;
+ return;
+ }
+ n = nodes[n].next;
+ }
+ e.id = -1;
+ }
+
+ void next(Edge& e) const {
+ int n = arcs[e.id * 2].target;
+ e.id = arcs[(e.id * 2) | 1].next_out;
+ while ((e.id & 1) != 1) {
+ e.id = arcs[e.id].next_out;
+ }
+ if (e.id != -1) {
+ e.id /= 2;
+ return;
+ }
+ n = nodes[n].next;
+ while (n != -1) {
+ e.id = nodes[n].first_out;
+ while ((e.id & 1) != 1) {
+ e.id = arcs[e.id].next_out;
+ }
+ if (e.id != -1) {
+ e.id /= 2;
+ return;
+ }
+ n = nodes[n].next;
+ }
+ e.id = -1;
+ }
+
+ void firstOut(Arc &e, const Node& v) const {
+ e.id = nodes[v.id].first_out;
+ }
+ void nextOut(Arc &e) const {
+ e.id = arcs[e.id].next_out;
+ }
+
+ void firstIn(Arc &e, const Node& v) const {
+ e.id = ((nodes[v.id].first_out) ^ 1);
+ if (e.id == -2) e.id = -1;
+ }
+ void nextIn(Arc &e) const {
+ e.id = ((arcs[e.id ^ 1].next_out) ^ 1);
+ if (e.id == -2) e.id = -1;
+ }
+
+ void firstInc(Edge &e, bool& d, const Node& v) const {
+ int a = nodes[v.id].first_out;
+ if (a != -1 ) {
+ e.id = a / 2;
+ d = ((a & 1) == 1);
+ } else {
+ e.id = -1;
+ d = true;
+ }
+ }
+ void nextInc(Edge &e, bool& d) const {
+ int a = (arcs[(e.id * 2) | (d ? 1 : 0)].next_out);
+ if (a != -1 ) {
+ e.id = a / 2;
+ d = ((a & 1) == 1);
+ } else {
+ e.id = -1;
+ d = true;
+ }
+ }
+
+ static int id(Node v) { return v.id; }
+ int id(RedNode v) const { return nodes[v.id].partition_index; }
+ int id(BlueNode v) const { return nodes[v.id].partition_index; }
+ static int id(Arc e) { return e.id; }
+ static int id(Edge e) { return e.id; }
+
+ static Node nodeFromId(int id) { return Node(id);}
+ static Arc arcFromId(int id) { return Arc(id);}
+ static Edge edgeFromId(int id) { return Edge(id);}
+
+ bool valid(Node n) const {
+ return n.id >= 0 && n.id < static_cast<int>(nodes.size()) &&
+ nodes[n.id].prev != -2;
+ }
+
+ bool valid(Arc a) const {
+ return a.id >= 0 && a.id < static_cast<int>(arcs.size()) &&
+ arcs[a.id].prev_out != -2;
+ }
+
+ bool valid(Edge e) const {
+ return e.id >= 0 && 2 * e.id < static_cast<int>(arcs.size()) &&
+ arcs[2 * e.id].prev_out != -2;
+ }
+
+ RedNode addRedNode() {
+ int n;
+
+ if(first_free_red==-1) {
+ n = nodes.size();
+ nodes.push_back(NodeT());
+ nodes[n].partition_index = ++max_red;
+ nodes[n].red = true;
+ } else {
+ n = first_free_red;
+ first_free_red = nodes[n].next;
+ }
+
+ nodes[n].next = first_node;
+ if (first_node != -1) nodes[first_node].prev = n;
+ first_node = n;
+ nodes[n].prev = -1;
+
+ nodes[n].partition_next = first_red;
+ if (first_red != -1) nodes[first_red].partition_prev = n;
+ first_red = n;
+ nodes[n].partition_prev = -1;
+
+ nodes[n].first_out = -1;
+
+ return RedNode(n);
+ }
+
+ BlueNode addBlueNode() {
+ int n;
+
+ if(first_free_blue==-1) {
+ n = nodes.size();
+ nodes.push_back(NodeT());
+ nodes[n].partition_index = ++max_blue;
+ nodes[n].red = false;
+ } else {
+ n = first_free_blue;
+ first_free_blue = nodes[n].next;
+ }
+
+ nodes[n].next = first_node;
+ if (first_node != -1) nodes[first_node].prev = n;
+ first_node = n;
+ nodes[n].prev = -1;
+
+ nodes[n].partition_next = first_blue;
+ if (first_blue != -1) nodes[first_blue].partition_prev = n;
+ first_blue = n;
+ nodes[n].partition_prev = -1;
+
+ nodes[n].first_out = -1;
+
+ return BlueNode(n);
+ }
+
+ Edge addEdge(Node u, Node v) {
+ int n;
+
+ if (first_free_arc == -1) {
+ n = arcs.size();
+ arcs.push_back(ArcT());
+ arcs.push_back(ArcT());
+ } else {
+ n = first_free_arc;
+ first_free_arc = arcs[n].next_out;
+ }
+
+ arcs[n].target = u.id;
+ arcs[n | 1].target = v.id;
+
+ arcs[n].next_out = nodes[v.id].first_out;
+ if (nodes[v.id].first_out != -1) {
+ arcs[nodes[v.id].first_out].prev_out = n;
+ }
+ arcs[n].prev_out = -1;
+ nodes[v.id].first_out = n;
+
+ arcs[n | 1].next_out = nodes[u.id].first_out;
+ if (nodes[u.id].first_out != -1) {
+ arcs[nodes[u.id].first_out].prev_out = (n | 1);
+ }
+ arcs[n | 1].prev_out = -1;
+ nodes[u.id].first_out = (n | 1);
+
+ return Edge(n / 2);
+ }
+
+ void erase(const Node& node) {
+ int n = node.id;
+
+ if(nodes[n].next != -1) {
+ nodes[nodes[n].next].prev = nodes[n].prev;
+ }
+
+ if(nodes[n].prev != -1) {
+ nodes[nodes[n].prev].next = nodes[n].next;
+ } else {
+ first_node = nodes[n].next;
+ }
+
+ if (nodes[n].partition_next != -1) {
+ nodes[nodes[n].partition_next].partition_prev = nodes[n].partition_prev;
+ }
+
+ if (nodes[n].partition_prev != -1) {
+ nodes[nodes[n].partition_prev].partition_next = nodes[n].partition_next;
+ } else {
+ if (nodes[n].red) {
+ first_red = nodes[n].partition_next;
+ } else {
+ first_blue = nodes[n].partition_next;
+ }
+ }
+
+ if (nodes[n].red) {
+ nodes[n].next = first_free_red;
+ first_free_red = n;
+ } else {
+ nodes[n].next = first_free_blue;
+ first_free_blue = n;
+ }
+ nodes[n].prev = -2;
+ }
+
+ void erase(const Edge& edge) {
+ int n = edge.id * 2;
+
+ if (arcs[n].next_out != -1) {
+ arcs[arcs[n].next_out].prev_out = arcs[n].prev_out;
+ }
+
+ if (arcs[n].prev_out != -1) {
+ arcs[arcs[n].prev_out].next_out = arcs[n].next_out;
+ } else {
+ nodes[arcs[n | 1].target].first_out = arcs[n].next_out;
+ }
+
+ if (arcs[n | 1].next_out != -1) {
+ arcs[arcs[n | 1].next_out].prev_out = arcs[n | 1].prev_out;
+ }
+
+ if (arcs[n | 1].prev_out != -1) {
+ arcs[arcs[n | 1].prev_out].next_out = arcs[n | 1].next_out;
+ } else {
+ nodes[arcs[n].target].first_out = arcs[n | 1].next_out;
+ }
+
+ arcs[n].next_out = first_free_arc;
+ first_free_arc = n;
+ arcs[n].prev_out = -2;
+ arcs[n | 1].prev_out = -2;
+
+ }
+
+ void clear() {
+ arcs.clear();
+ nodes.clear();
+ first_node = first_free_arc = first_red = first_blue =
+ max_red = max_blue = first_free_red = first_free_blue = -1;
+ }
+
+ protected:
+
+ void changeRed(Edge e, RedNode n) {
+ if(arcs[(2 * e.id) | 1].next_out != -1) {
+ arcs[arcs[(2 * e.id) | 1].next_out].prev_out =
+ arcs[(2 * e.id) | 1].prev_out;
+ }
+ if(arcs[(2 * e.id) | 1].prev_out != -1) {
+ arcs[arcs[(2 * e.id) | 1].prev_out].next_out =
+ arcs[(2 * e.id) | 1].next_out;
+ } else {
+ nodes[arcs[2 * e.id].target].first_out =
+ arcs[(2 * e.id) | 1].next_out;
+ }
+
+ if (nodes[n.id].first_out != -1) {
+ arcs[nodes[n.id].first_out].prev_out = ((2 * e.id) | 1);
+ }
+ arcs[2 * e.id].target = n.id;
+ arcs[(2 * e.id) | 1].prev_out = -1;
+ arcs[(2 * e.id) | 1].next_out = nodes[n.id].first_out;
+ nodes[n.id].first_out = ((2 * e.id) | 1);
+ }
+
+ void changeBlue(Edge e, BlueNode n) {
+ if(arcs[2 * e.id].next_out != -1) {
+ arcs[arcs[2 * e.id].next_out].prev_out = arcs[2 * e.id].prev_out;
+ }
+ if(arcs[2 * e.id].prev_out != -1) {
+ arcs[arcs[2 * e.id].prev_out].next_out =
+ arcs[2 * e.id].next_out;
+ } else {
+ nodes[arcs[(2 * e.id) | 1].target].first_out =
+ arcs[2 * e.id].next_out;
+ }
+
+ if (nodes[n.id].first_out != -1) {
+ arcs[nodes[n.id].first_out].prev_out = 2 * e.id;
+ }
+ arcs[(2 * e.id) | 1].target = n.id;
+ arcs[2 * e.id].prev_out = -1;
+ arcs[2 * e.id].next_out = nodes[n.id].first_out;
+ nodes[n.id].first_out = 2 * e.id;
+ }
+
+ };
+
+ typedef BpGraphExtender<ListBpGraphBase> ExtendedListBpGraphBase;
+
+
+ /// \addtogroup graphs
+ /// @{
+
+ ///A general undirected graph structure.
+
+ ///\ref ListBpGraph is a versatile and fast undirected graph
+ ///implementation based on linked lists that are stored in
+ ///\c std::vector structures.
+ ///
+ ///This type fully conforms to the \ref concepts::BpGraph "BpGraph concept"
+ ///and it also provides several useful additional functionalities.
+ ///Most of its member functions and nested classes are documented
+ ///only in the concept class.
+ ///
+ ///This class provides only linear time counting for nodes, edges and arcs.
+ ///
+ ///\sa concepts::BpGraph
+ ///\sa ListDigraph
+ class ListBpGraph : public ExtendedListBpGraphBase {
+ typedef ExtendedListBpGraphBase Parent;
+
+ private:
+ /// BpGraphs are \e not copy constructible. Use BpGraphCopy instead.
+ ListBpGraph(const ListBpGraph &) :ExtendedListBpGraphBase() {};
+ /// \brief Assignment of a graph to another one is \e not allowed.
+ /// Use BpGraphCopy instead.
+ void operator=(const ListBpGraph &) {}
+ public:
+ /// Constructor
+
+ /// Constructor.
+ ///
+ ListBpGraph() {}
+
+ typedef Parent::OutArcIt IncEdgeIt;
+
+ /// \brief Add a new red node to the graph.
+ ///
+ /// This function adds a red new node to the graph.
+ /// \return The new node.
+ RedNode addRedNode() { return Parent::addRedNode(); }
+
+ /// \brief Add a new blue node to the graph.
+ ///
+ /// This function adds a blue new node to the graph.
+ /// \return The new node.
+ BlueNode addBlueNode() { return Parent::addBlueNode(); }
+
+ /// \brief Add a new edge to the graph.
+ ///
+ /// This function adds a new edge to the graph between nodes
+ /// \c u and \c v with inherent orientation from node \c u to
+ /// node \c v.
+ /// \return The new edge.
+ Edge addEdge(RedNode u, BlueNode v) {
+ return Parent::addEdge(u, v);
+ }
+ Edge addEdge(BlueNode v, RedNode u) {
+ return Parent::addEdge(u, v);
+ }
+
+ ///\brief Erase a node from the graph.
+ ///
+ /// This function erases the given node along with its incident arcs
+ /// from the graph.
+ ///
+ /// \note All iterators referencing the removed node or the incident
+ /// edges are invalidated, of course.
+ void erase(Node n) { Parent::erase(n); }
+
+ ///\brief Erase an edge from the graph.
+ ///
+ /// This function erases the given edge from the graph.
+ ///
+ /// \note All iterators referencing the removed edge are invalidated,
+ /// of course.
+ void erase(Edge e) { Parent::erase(e); }
+ /// Node validity check
+
+ /// This function gives back \c true if the given node is valid,
+ /// i.e. it is a real node of the graph.
+ ///
+ /// \warning A removed node could become valid again if new nodes are
+ /// added to the graph.
+ bool valid(Node n) const { return Parent::valid(n); }
+ /// Edge validity check
+
+ /// This function gives back \c true if the given edge is valid,
+ /// i.e. it is a real edge of the graph.
+ ///
+ /// \warning A removed edge could become valid again if new edges are
+ /// added to the graph.
+ bool valid(Edge e) const { return Parent::valid(e); }
+ /// Arc validity check
+
+ /// This function gives back \c true if the given arc is valid,
+ /// i.e. it is a real arc of the graph.
+ ///
+ /// \warning A removed arc could become valid again if new edges are
+ /// added to the graph.
+ bool valid(Arc a) const { return Parent::valid(a); }
+
+ /// \brief Change the red node of an edge.
+ ///
+ /// This function changes the red node of the given edge \c e to \c n.
+ ///
+ ///\note \c EdgeIt and \c ArcIt iterators referencing the
+ ///changed edge are invalidated and all other iterators whose
+ ///base node is the changed node are also invalidated.
+ ///
+ ///\warning This functionality cannot be used together with the
+ ///Snapshot feature.
+ void changeRed(Edge e, RedNode n) {
+ Parent::changeRed(e, n);
+ }
+ /// \brief Change the blue node of an edge.
+ ///
+ /// This function changes the blue node of the given edge \c e to \c n.
+ ///
+ ///\note \c EdgeIt iterators referencing the changed edge remain
+ ///valid, but \c ArcIt iterators referencing the changed edge and
+ ///all other iterators whose base node is the changed node are also
+ ///invalidated.
+ ///
+ ///\warning This functionality cannot be used together with the
+ ///Snapshot feature.
+ void changeBlue(Edge e, BlueNode n) {
+ Parent::changeBlue(e, n);
+ }
+
+ ///Clear the graph.
+
+ ///This function erases all nodes and arcs from the graph.
+ ///
+ ///\note All iterators of the graph are invalidated, of course.
+ void clear() {
+ Parent::clear();
+ }
+
+ /// Reserve memory for nodes.
+
+ /// Using this function, it is possible to avoid superfluous memory
+ /// allocation: if you know that the graph you want to build will
+ /// be large (e.g. it will contain millions of nodes and/or edges),
+ /// then it is worth reserving space for this amount before starting
+ /// to build the graph.
+ /// \sa reserveEdge()
+ void reserveNode(int n) { nodes.reserve(n); };
+
+ /// Reserve memory for edges.
+
+ /// Using this function, it is possible to avoid superfluous memory
+ /// allocation: if you know that the graph you want to build will
+ /// be large (e.g. it will contain millions of nodes and/or edges),
+ /// then it is worth reserving space for this amount before starting
+ /// to build the graph.
+ /// \sa reserveNode()
+ void reserveEdge(int m) { arcs.reserve(2 * m); };
+
+ /// \brief Class to make a snapshot of the graph and restore
+ /// it later.
+ ///
+ /// Class to make a snapshot of the graph and restore it later.
+ ///
+ /// The newly added nodes and edges can be removed
+ /// using the restore() function.
+ ///
+ /// \note After a state is restored, you cannot restore a later state,
+ /// i.e. you cannot add the removed nodes and edges again using
+ /// another Snapshot instance.
+ ///
+ /// \warning Node and edge deletions and other modifications
+ /// (e.g. changing the end-nodes of edges or contracting nodes)
+ /// cannot be restored. These events invalidate the snapshot.
+ /// However, the edges and nodes that were added to the graph after
+ /// making the current snapshot can be removed without invalidating it.
+ class Snapshot {
+ protected:
+
+ typedef Parent::NodeNotifier NodeNotifier;
+
+ class NodeObserverProxy : public NodeNotifier::ObserverBase {
+ public:
+
+ NodeObserverProxy(Snapshot& _snapshot)
+ : snapshot(_snapshot) {}
+
+ using NodeNotifier::ObserverBase::attach;
+ using NodeNotifier::ObserverBase::detach;
+ using NodeNotifier::ObserverBase::attached;
+
+ protected:
+
+ virtual void add(const Node& node) {
+ snapshot.addNode(node);
+ }
+ virtual void add(const std::vector<Node>& nodes) {
+ for (int i = nodes.size() - 1; i >= 0; ++i) {
+ snapshot.addNode(nodes[i]);
+ }
+ }
+ virtual void erase(const Node& node) {
+ snapshot.eraseNode(node);
+ }
+ virtual void erase(const std::vector<Node>& nodes) {
+ for (int i = 0; i < int(nodes.size()); ++i) {
+ snapshot.eraseNode(nodes[i]);
+ }
+ }
+ virtual void build() {
+ Node node;
+ std::vector<Node> nodes;
+ for (notifier()->first(node); node != INVALID;
+ notifier()->next(node)) {
+ nodes.push_back(node);
+ }
+ for (int i = nodes.size() - 1; i >= 0; --i) {
+ snapshot.addNode(nodes[i]);
+ }
+ }
+ virtual void clear() {
+ Node node;
+ for (notifier()->first(node); node != INVALID;
+ notifier()->next(node)) {
+ snapshot.eraseNode(node);
+ }
+ }
+
+ Snapshot& snapshot;
+ };
+
+ class EdgeObserverProxy : public EdgeNotifier::ObserverBase {
+ public:
+
+ EdgeObserverProxy(Snapshot& _snapshot)
+ : snapshot(_snapshot) {}
+
+ using EdgeNotifier::ObserverBase::attach;
+ using EdgeNotifier::ObserverBase::detach;
+ using EdgeNotifier::ObserverBase::attached;
+
+ protected:
+
+ virtual void add(const Edge& edge) {
+ snapshot.addEdge(edge);
+ }
+ virtual void add(const std::vector<Edge>& edges) {
+ for (int i = edges.size() - 1; i >= 0; ++i) {
+ snapshot.addEdge(edges[i]);
+ }
+ }
+ virtual void erase(const Edge& edge) {
+ snapshot.eraseEdge(edge);
+ }
+ virtual void erase(const std::vector<Edge>& edges) {
+ for (int i = 0; i < int(edges.size()); ++i) {
+ snapshot.eraseEdge(edges[i]);
+ }
+ }
+ virtual void build() {
+ Edge edge;
+ std::vector<Edge> edges;
+ for (notifier()->first(edge); edge != INVALID;
+ notifier()->next(edge)) {
+ edges.push_back(edge);
+ }
+ for (int i = edges.size() - 1; i >= 0; --i) {
+ snapshot.addEdge(edges[i]);
+ }
+ }
+ virtual void clear() {
+ Edge edge;
+ for (notifier()->first(edge); edge != INVALID;
+ notifier()->next(edge)) {
+ snapshot.eraseEdge(edge);
+ }
+ }
+
+ Snapshot& snapshot;
+ };
+
+ ListBpGraph *graph;
+
+ NodeObserverProxy node_observer_proxy;
+ EdgeObserverProxy edge_observer_proxy;
+
+ std::list<Node> added_nodes;
+ std::list<Edge> added_edges;
+
+
+ void addNode(const Node& node) {
+ added_nodes.push_front(node);
+ }
+ void eraseNode(const Node& node) {
+ std::list<Node>::iterator it =
+ std::find(added_nodes.begin(), added_nodes.end(), node);
+ if (it == added_nodes.end()) {
+ clear();
+ edge_observer_proxy.detach();
+ throw NodeNotifier::ImmediateDetach();
+ } else {
+ added_nodes.erase(it);
+ }
+ }
+
+ void addEdge(const Edge& edge) {
+ added_edges.push_front(edge);
+ }
+ void eraseEdge(const Edge& edge) {
+ std::list<Edge>::iterator it =
+ std::find(added_edges.begin(), added_edges.end(), edge);
+ if (it == added_edges.end()) {
+ clear();
+ node_observer_proxy.detach();
+ throw EdgeNotifier::ImmediateDetach();
+ } else {
+ added_edges.erase(it);
+ }
+ }
+
+ void attach(ListBpGraph &_graph) {
+ graph = &_graph;
+ node_observer_proxy.attach(graph->notifier(Node()));
+ edge_observer_proxy.attach(graph->notifier(Edge()));
+ }
+
+ void detach() {
+ node_observer_proxy.detach();
+ edge_observer_proxy.detach();
+ }
+
+ bool attached() const {
+ return node_observer_proxy.attached();
+ }
+
+ void clear() {
+ added_nodes.clear();
+ added_edges.clear();
+ }
+
+ public:
+
+ /// \brief Default constructor.
+ ///
+ /// Default constructor.
+ /// You have to call save() to actually make a snapshot.
+ Snapshot()
+ : graph(0), node_observer_proxy(*this),
+ edge_observer_proxy(*this) {}
+
+ /// \brief Constructor that immediately makes a snapshot.
+ ///
+ /// This constructor immediately makes a snapshot of the given graph.
+ Snapshot(ListBpGraph &gr)
+ : node_observer_proxy(*this),
+ edge_observer_proxy(*this) {
+ attach(gr);
+ }
+
+ /// \brief Make a snapshot.
+ ///
+ /// This function makes a snapshot of the given graph.
+ /// It can be called more than once. In case of a repeated
+ /// call, the previous snapshot gets lost.
+ void save(ListBpGraph &gr) {
+ if (attached()) {
+ detach();
+ clear();
+ }
+ attach(gr);
+ }
+
+ /// \brief Undo the changes until the last snapshot.
+ ///
+ /// This function undos the changes until the last snapshot
+ /// created by save() or Snapshot(ListBpGraph&).
+ ///
+ /// \warning This method invalidates the snapshot, i.e. repeated
+ /// restoring is not supported unless you call save() again.
+ void restore() {
+ detach();
+ for(std::list<Edge>::iterator it = added_edges.begin();
+ it != added_edges.end(); ++it) {
+ graph->erase(*it);
+ }
+ for(std::list<Node>::iterator it = added_nodes.begin();
+ it != added_nodes.end(); ++it) {
+ graph->erase(*it);
+ }
+ clear();
+ }
+
+ /// \brief Returns \c true if the snapshot is valid.
+ ///
+ /// This function returns \c true if the snapshot is valid.
+ bool valid() const {
+ return attached();
+ }
+ };
+ };
+
+ /// @}
+} //namespace lemon
+
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp.h
new file mode 100644
index 00000000000..567763f0222
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp.h
@@ -0,0 +1,95 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_LP_H
+#define LEMON_LP_H
+
+#include<lemon/config.h>
+
+
+#ifdef LEMON_HAVE_GLPK
+#include <lemon/glpk.h>
+#elif LEMON_HAVE_CPLEX
+#include <lemon/cplex.h>
+#elif LEMON_HAVE_SOPLEX
+#include <lemon/soplex.h>
+#elif LEMON_HAVE_CLP
+#include <lemon/clp.h>
+#elif LEMON_HAVE_CBC
+#include <lemon/cbc.h>
+#endif
+
+///\file
+///\brief Defines a default LP solver
+///\ingroup lp_group
+namespace lemon {
+
+#ifdef DOXYGEN
+ ///The default LP solver identifier
+
+ ///The default LP solver identifier.
+ ///\ingroup lp_group
+ ///
+ ///Currently, the possible values are \c _LEMON_GLPK, \c LEMON__CPLEX,
+ ///\c _LEMON_SOPLEX or \c LEMON__CLP
+#define LEMON_DEFAULT_LP SOLVER
+ ///The default LP solver
+
+ ///The default LP solver.
+ ///\ingroup lp_group
+ ///
+ ///Currently, it is either \c GlpkLp, \c CplexLp, \c SoplexLp or \c ClpLp
+ typedef GlpkLp Lp;
+
+ ///The default MIP solver identifier
+
+ ///The default MIP solver identifier.
+ ///\ingroup lp_group
+ ///
+ ///Currently, the possible values are \c _LEMON_GLPK, \c LEMON__CPLEX
+ ///or \c _LEMON_CBC
+#define LEMON_DEFAULT_MIP SOLVER
+ ///The default MIP solver.
+
+ ///The default MIP solver.
+ ///\ingroup lp_group
+ ///
+ ///Currently, it is either \c GlpkMip, \c CplexMip , \c CbcMip
+ typedef GlpkMip Mip;
+#else
+#if LEMON_DEFAULT_LP == _LEMON_GLPK
+ typedef GlpkLp Lp;
+#elif LEMON_DEFAULT_LP == _LEMON_CPLEX
+ typedef CplexLp Lp;
+#elif LEMON_DEFAULT_LP == _LEMON_SOPLEX
+ typedef SoplexLp Lp;
+#elif LEMON_DEFAULT_LP == _LEMON_CLP
+ typedef ClpLp Lp;
+#endif
+#if LEMON_DEFAULT_MIP == _LEMON_GLPK
+ typedef GlpkMip Mip;
+#elif LEMON_DEFAULT_MIP == _LEMON_CPLEX
+ typedef CplexMip Mip;
+#elif LEMON_DEFAULT_MIP == _LEMON_CBC
+ typedef CbcMip Mip;
+#endif
+#endif
+
+} //namespace lemon
+
+#endif //LEMON_LP_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_base.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_base.cc
new file mode 100644
index 00000000000..312fd631f9a
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_base.cc
@@ -0,0 +1,30 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+///\file
+///\brief The implementation of the LP solver interface.
+
+#include <lemon/lp_base.h>
+namespace lemon {
+
+ const LpBase::Value LpBase::INF =
+ std::numeric_limits<LpBase::Value>::infinity();
+ const LpBase::Value LpBase::NaN =
+ std::numeric_limits<LpBase::Value>::quiet_NaN();
+
+} //namespace lemon
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_base.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_base.h
new file mode 100644
index 00000000000..22d3e4899fe
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_base.h
@@ -0,0 +1,2147 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_LP_BASE_H
+#define LEMON_LP_BASE_H
+
+#include<iostream>
+#include<vector>
+#include<map>
+#include<limits>
+#include<lemon/math.h>
+
+#include<lemon/error.h>
+#include<lemon/assert.h>
+
+#include<lemon/core.h>
+#include<lemon/bits/solver_bits.h>
+
+///\file
+///\brief The interface of the LP solver interface.
+///\ingroup lp_group
+namespace lemon {
+
+ ///Common base class for LP and MIP solvers
+
+ ///Usually this class is not used directly, please use one of the concrete
+ ///implementations of the solver interface.
+ ///\ingroup lp_group
+ class LpBase {
+
+ protected:
+
+ _solver_bits::VarIndex rows;
+ _solver_bits::VarIndex cols;
+
+ public:
+
+ ///Possible outcomes of an LP solving procedure
+ enum SolveExitStatus {
+ /// = 0. It means that the problem has been successfully solved: either
+ ///an optimal solution has been found or infeasibility/unboundedness
+ ///has been proved.
+ SOLVED = 0,
+ /// = 1. Any other case (including the case when some user specified
+ ///limit has been exceeded).
+ UNSOLVED = 1
+ };
+
+ ///Direction of the optimization
+ enum Sense {
+ /// Minimization
+ MIN,
+ /// Maximization
+ MAX
+ };
+
+ ///Enum for \c messageLevel() parameter
+ enum MessageLevel {
+ /// No output (default value).
+ MESSAGE_NOTHING,
+ /// Error messages only.
+ MESSAGE_ERROR,
+ /// Warnings.
+ MESSAGE_WARNING,
+ /// Normal output.
+ MESSAGE_NORMAL,
+ /// Verbose output.
+ MESSAGE_VERBOSE
+ };
+
+
+ ///The floating point type used by the solver
+ typedef double Value;
+ ///The infinity constant
+ static const Value INF;
+ ///The not a number constant
+ static const Value NaN;
+
+ friend class Col;
+ friend class ColIt;
+ friend class Row;
+ friend class RowIt;
+
+ ///Refer to a column of the LP.
+
+ ///This type is used to refer to a column of the LP.
+ ///
+ ///Its value remains valid and correct even after the addition or erase of
+ ///other columns.
+ ///
+ ///\note This class is similar to other Item types in LEMON, like
+ ///Node and Arc types in digraph.
+ class Col {
+ friend class LpBase;
+ protected:
+ int _id;
+ explicit Col(int id) : _id(id) {}
+ public:
+ typedef Value ExprValue;
+ typedef True LpCol;
+ /// Default constructor
+
+ /// \warning The default constructor sets the Col to an
+ /// undefined value.
+ Col() {}
+ /// Invalid constructor \& conversion.
+
+ /// This constructor initializes the Col to be invalid.
+ /// \sa Invalid for more details.
+ Col(const Invalid&) : _id(-1) {}
+ /// Equality operator
+
+ /// Two \ref Col "Col"s are equal if and only if they point to
+ /// the same LP column or both are invalid.
+ bool operator==(Col c) const {return _id == c._id;}
+ /// Inequality operator
+
+ /// \sa operator==(Col c)
+ ///
+ bool operator!=(Col c) const {return _id != c._id;}
+ /// Artificial ordering operator.
+
+ /// To allow the use of this object in std::map or similar
+ /// associative container we require this.
+ ///
+ /// \note This operator only have to define some strict ordering of
+ /// the items; this order has nothing to do with the iteration
+ /// ordering of the items.
+ bool operator<(Col c) const {return _id < c._id;}
+ };
+
+ ///Iterator for iterate over the columns of an LP problem
+
+ /// Its usage is quite simple, for example, you can count the number
+ /// of columns in an LP \c lp:
+ ///\code
+ /// int count=0;
+ /// for (LpBase::ColIt c(lp); c!=INVALID; ++c) ++count;
+ ///\endcode
+ class ColIt : public Col {
+ const LpBase *_solver;
+ public:
+ /// Default constructor
+
+ /// \warning The default constructor sets the iterator
+ /// to an undefined value.
+ ColIt() {}
+ /// Sets the iterator to the first Col
+
+ /// Sets the iterator to the first Col.
+ ///
+ ColIt(const LpBase &solver) : _solver(&solver)
+ {
+ _solver->cols.firstItem(_id);
+ }
+ /// Invalid constructor \& conversion
+
+ /// Initialize the iterator to be invalid.
+ /// \sa Invalid for more details.
+ ColIt(const Invalid&) : Col(INVALID) {}
+ /// Next column
+
+ /// Assign the iterator to the next column.
+ ///
+ ColIt &operator++()
+ {
+ _solver->cols.nextItem(_id);
+ return *this;
+ }
+ };
+
+ /// \brief Returns the ID of the column.
+ static int id(const Col& col) { return col._id; }
+ /// \brief Returns the column with the given ID.
+ ///
+ /// \pre The argument should be a valid column ID in the LP problem.
+ static Col colFromId(int id) { return Col(id); }
+
+ ///Refer to a row of the LP.
+
+ ///This type is used to refer to a row of the LP.
+ ///
+ ///Its value remains valid and correct even after the addition or erase of
+ ///other rows.
+ ///
+ ///\note This class is similar to other Item types in LEMON, like
+ ///Node and Arc types in digraph.
+ class Row {
+ friend class LpBase;
+ protected:
+ int _id;
+ explicit Row(int id) : _id(id) {}
+ public:
+ typedef Value ExprValue;
+ typedef True LpRow;
+ /// Default constructor
+
+ /// \warning The default constructor sets the Row to an
+ /// undefined value.
+ Row() {}
+ /// Invalid constructor \& conversion.
+
+ /// This constructor initializes the Row to be invalid.
+ /// \sa Invalid for more details.
+ Row(const Invalid&) : _id(-1) {}
+ /// Equality operator
+
+ /// Two \ref Row "Row"s are equal if and only if they point to
+ /// the same LP row or both are invalid.
+ bool operator==(Row r) const {return _id == r._id;}
+ /// Inequality operator
+
+ /// \sa operator==(Row r)
+ ///
+ bool operator!=(Row r) const {return _id != r._id;}
+ /// Artificial ordering operator.
+
+ /// To allow the use of this object in std::map or similar
+ /// associative container we require this.
+ ///
+ /// \note This operator only have to define some strict ordering of
+ /// the items; this order has nothing to do with the iteration
+ /// ordering of the items.
+ bool operator<(Row r) const {return _id < r._id;}
+ };
+
+ ///Iterator for iterate over the rows of an LP problem
+
+ /// Its usage is quite simple, for example, you can count the number
+ /// of rows in an LP \c lp:
+ ///\code
+ /// int count=0;
+ /// for (LpBase::RowIt c(lp); c!=INVALID; ++c) ++count;
+ ///\endcode
+ class RowIt : public Row {
+ const LpBase *_solver;
+ public:
+ /// Default constructor
+
+ /// \warning The default constructor sets the iterator
+ /// to an undefined value.
+ RowIt() {}
+ /// Sets the iterator to the first Row
+
+ /// Sets the iterator to the first Row.
+ ///
+ RowIt(const LpBase &solver) : _solver(&solver)
+ {
+ _solver->rows.firstItem(_id);
+ }
+ /// Invalid constructor \& conversion
+
+ /// Initialize the iterator to be invalid.
+ /// \sa Invalid for more details.
+ RowIt(const Invalid&) : Row(INVALID) {}
+ /// Next row
+
+ /// Assign the iterator to the next row.
+ ///
+ RowIt &operator++()
+ {
+ _solver->rows.nextItem(_id);
+ return *this;
+ }
+ };
+
+ /// \brief Returns the ID of the row.
+ static int id(const Row& row) { return row._id; }
+ /// \brief Returns the row with the given ID.
+ ///
+ /// \pre The argument should be a valid row ID in the LP problem.
+ static Row rowFromId(int id) { return Row(id); }
+
+ public:
+
+ ///Linear expression of variables and a constant component
+
+ ///This data structure stores a linear expression of the variables
+ ///(\ref Col "Col"s) and also has a constant component.
+ ///
+ ///There are several ways to access and modify the contents of this
+ ///container.
+ ///\code
+ ///e[v]=5;
+ ///e[v]+=12;
+ ///e.erase(v);
+ ///\endcode
+ ///or you can also iterate through its elements.
+ ///\code
+ ///double s=0;
+ ///for(LpBase::Expr::ConstCoeffIt i(e);i!=INVALID;++i)
+ /// s+=*i * primal(i);
+ ///\endcode
+ ///(This code computes the primal value of the expression).
+ ///- Numbers (<tt>double</tt>'s)
+ ///and variables (\ref Col "Col"s) directly convert to an
+ ///\ref Expr and the usual linear operations are defined, so
+ ///\code
+ ///v+w
+ ///2*v-3.12*(v-w/2)+2
+ ///v*2.1+(3*v+(v*12+w+6)*3)/2
+ ///\endcode
+ ///are valid expressions.
+ ///The usual assignment operations are also defined.
+ ///\code
+ ///e=v+w;
+ ///e+=2*v-3.12*(v-w/2)+2;
+ ///e*=3.4;
+ ///e/=5;
+ ///\endcode
+ ///- The constant member can be set and read by dereference
+ /// operator (unary *)
+ ///
+ ///\code
+ ///*e=12;
+ ///double c=*e;
+ ///\endcode
+ ///
+ ///\sa Constr
+ class Expr {
+ friend class LpBase;
+ public:
+ /// The key type of the expression
+ typedef LpBase::Col Key;
+ /// The value type of the expression
+ typedef LpBase::Value Value;
+
+ protected:
+ Value const_comp;
+ std::map<int, Value> comps;
+
+ public:
+ typedef True SolverExpr;
+ /// Default constructor
+
+ /// Construct an empty expression, the coefficients and
+ /// the constant component are initialized to zero.
+ Expr() : const_comp(0) {}
+ /// Construct an expression from a column
+
+ /// Construct an expression, which has a term with \c c variable
+ /// and 1.0 coefficient.
+ Expr(const Col &c) : const_comp(0) {
+ typedef std::map<int, Value>::value_type pair_type;
+ comps.insert(pair_type(id(c), 1));
+ }
+ /// Construct an expression from a constant
+
+ /// Construct an expression, which's constant component is \c v.
+ ///
+ Expr(const Value &v) : const_comp(v) {}
+ /// Returns the coefficient of the column
+ Value operator[](const Col& c) const {
+ std::map<int, Value>::const_iterator it=comps.find(id(c));
+ if (it != comps.end()) {
+ return it->second;
+ } else {
+ return 0;
+ }
+ }
+ /// Returns the coefficient of the column
+ Value& operator[](const Col& c) {
+ return comps[id(c)];
+ }
+ /// Sets the coefficient of the column
+ void set(const Col &c, const Value &v) {
+ if (v != 0.0) {
+ typedef std::map<int, Value>::value_type pair_type;
+ comps.insert(pair_type(id(c), v));
+ } else {
+ comps.erase(id(c));
+ }
+ }
+ /// Returns the constant component of the expression
+ Value& operator*() { return const_comp; }
+ /// Returns the constant component of the expression
+ const Value& operator*() const { return const_comp; }
+ /// \brief Removes the coefficients which's absolute value does
+ /// not exceed \c epsilon. It also sets to zero the constant
+ /// component, if it does not exceed epsilon in absolute value.
+ void simplify(Value epsilon = 0.0) {
+ std::map<int, Value>::iterator it=comps.begin();
+ while (it != comps.end()) {
+ std::map<int, Value>::iterator jt=it;
+ ++jt;
+ if (std::fabs((*it).second) <= epsilon) comps.erase(it);
+ it=jt;
+ }
+ if (std::fabs(const_comp) <= epsilon) const_comp = 0;
+ }
+
+ void simplify(Value epsilon = 0.0) const {
+ const_cast<Expr*>(this)->simplify(epsilon);
+ }
+
+ ///Sets all coefficients and the constant component to 0.
+ void clear() {
+ comps.clear();
+ const_comp=0;
+ }
+
+ ///Compound assignment
+ Expr &operator+=(const Expr &e) {
+ for (std::map<int, Value>::const_iterator it=e.comps.begin();
+ it!=e.comps.end(); ++it)
+ comps[it->first]+=it->second;
+ const_comp+=e.const_comp;
+ return *this;
+ }
+ ///Compound assignment
+ Expr &operator-=(const Expr &e) {
+ for (std::map<int, Value>::const_iterator it=e.comps.begin();
+ it!=e.comps.end(); ++it)
+ comps[it->first]-=it->second;
+ const_comp-=e.const_comp;
+ return *this;
+ }
+ ///Multiply with a constant
+ Expr &operator*=(const Value &v) {
+ for (std::map<int, Value>::iterator it=comps.begin();
+ it!=comps.end(); ++it)
+ it->second*=v;
+ const_comp*=v;
+ return *this;
+ }
+ ///Division with a constant
+ Expr &operator/=(const Value &c) {
+ for (std::map<int, Value>::iterator it=comps.begin();
+ it!=comps.end(); ++it)
+ it->second/=c;
+ const_comp/=c;
+ return *this;
+ }
+
+ ///Iterator over the expression
+
+ ///The iterator iterates over the terms of the expression.
+ ///
+ ///\code
+ ///double s=0;
+ ///for(LpBase::Expr::CoeffIt i(e);i!=INVALID;++i)
+ /// s+= *i * primal(i);
+ ///\endcode
+ class CoeffIt {
+ private:
+
+ std::map<int, Value>::iterator _it, _end;
+
+ public:
+
+ /// Sets the iterator to the first term
+
+ /// Sets the iterator to the first term of the expression.
+ ///
+ CoeffIt(Expr& e)
+ : _it(e.comps.begin()), _end(e.comps.end()){}
+
+ /// Convert the iterator to the column of the term
+ operator Col() const {
+ return colFromId(_it->first);
+ }
+
+ /// Returns the coefficient of the term
+ Value& operator*() { return _it->second; }
+
+ /// Returns the coefficient of the term
+ const Value& operator*() const { return _it->second; }
+ /// Next term
+
+ /// Assign the iterator to the next term.
+ ///
+ CoeffIt& operator++() { ++_it; return *this; }
+
+ /// Equality operator
+ bool operator==(Invalid) const { return _it == _end; }
+ /// Inequality operator
+ bool operator!=(Invalid) const { return _it != _end; }
+ };
+
+ /// Const iterator over the expression
+
+ ///The iterator iterates over the terms of the expression.
+ ///
+ ///\code
+ ///double s=0;
+ ///for(LpBase::Expr::ConstCoeffIt i(e);i!=INVALID;++i)
+ /// s+=*i * primal(i);
+ ///\endcode
+ class ConstCoeffIt {
+ private:
+
+ std::map<int, Value>::const_iterator _it, _end;
+
+ public:
+
+ /// Sets the iterator to the first term
+
+ /// Sets the iterator to the first term of the expression.
+ ///
+ ConstCoeffIt(const Expr& e)
+ : _it(e.comps.begin()), _end(e.comps.end()){}
+
+ /// Convert the iterator to the column of the term
+ operator Col() const {
+ return colFromId(_it->first);
+ }
+
+ /// Returns the coefficient of the term
+ const Value& operator*() const { return _it->second; }
+
+ /// Next term
+
+ /// Assign the iterator to the next term.
+ ///
+ ConstCoeffIt& operator++() { ++_it; return *this; }
+
+ /// Equality operator
+ bool operator==(Invalid) const { return _it == _end; }
+ /// Inequality operator
+ bool operator!=(Invalid) const { return _it != _end; }
+ };
+
+ };
+
+ ///Linear constraint
+
+ ///This data stucture represents a linear constraint in the LP.
+ ///Basically it is a linear expression with a lower or an upper bound
+ ///(or both). These parts of the constraint can be obtained by the member
+ ///functions \ref expr(), \ref lowerBound() and \ref upperBound(),
+ ///respectively.
+ ///There are two ways to construct a constraint.
+ ///- You can set the linear expression and the bounds directly
+ /// by the functions above.
+ ///- The operators <tt>\<=</tt>, <tt>==</tt> and <tt>\>=</tt>
+ /// are defined between expressions, or even between constraints whenever
+ /// it makes sense. Therefore if \c e and \c f are linear expressions and
+ /// \c s and \c t are numbers, then the followings are valid expressions
+ /// and thus they can be used directly e.g. in \ref addRow() whenever
+ /// it makes sense.
+ ///\code
+ /// e<=s
+ /// e<=f
+ /// e==f
+ /// s<=e<=t
+ /// e>=t
+ ///\endcode
+ ///\warning The validity of a constraint is checked only at run
+ ///time, so e.g. \ref addRow(<tt>x[1]\<=x[2]<=5</tt>) will
+ ///compile, but will fail an assertion.
+ class Constr
+ {
+ public:
+ typedef LpBase::Expr Expr;
+ typedef Expr::Key Key;
+ typedef Expr::Value Value;
+
+ protected:
+ Expr _expr;
+ Value _lb,_ub;
+ public:
+ ///\e
+ Constr() : _expr(), _lb(NaN), _ub(NaN) {}
+ ///\e
+ Constr(Value lb, const Expr &e, Value ub) :
+ _expr(e), _lb(lb), _ub(ub) {}
+ Constr(const Expr &e) :
+ _expr(e), _lb(NaN), _ub(NaN) {}
+ ///\e
+ void clear()
+ {
+ _expr.clear();
+ _lb=_ub=NaN;
+ }
+
+ ///Reference to the linear expression
+ Expr &expr() { return _expr; }
+ ///Cont reference to the linear expression
+ const Expr &expr() const { return _expr; }
+ ///Reference to the lower bound.
+
+ ///\return
+ ///- \ref INF "INF": the constraint is lower unbounded.
+ ///- \ref NaN "NaN": lower bound has not been set.
+ ///- finite number: the lower bound
+ Value &lowerBound() { return _lb; }
+ ///The const version of \ref lowerBound()
+ const Value &lowerBound() const { return _lb; }
+ ///Reference to the upper bound.
+
+ ///\return
+ ///- \ref INF "INF": the constraint is upper unbounded.
+ ///- \ref NaN "NaN": upper bound has not been set.
+ ///- finite number: the upper bound
+ Value &upperBound() { return _ub; }
+ ///The const version of \ref upperBound()
+ const Value &upperBound() const { return _ub; }
+ ///Is the constraint lower bounded?
+ bool lowerBounded() const {
+ return _lb != -INF && !isNaN(_lb);
+ }
+ ///Is the constraint upper bounded?
+ bool upperBounded() const {
+ return _ub != INF && !isNaN(_ub);
+ }
+
+ };
+
+ ///Linear expression of rows
+
+ ///This data structure represents a column of the matrix,
+ ///thas is it strores a linear expression of the dual variables
+ ///(\ref Row "Row"s).
+ ///
+ ///There are several ways to access and modify the contents of this
+ ///container.
+ ///\code
+ ///e[v]=5;
+ ///e[v]+=12;
+ ///e.erase(v);
+ ///\endcode
+ ///or you can also iterate through its elements.
+ ///\code
+ ///double s=0;
+ ///for(LpBase::DualExpr::ConstCoeffIt i(e);i!=INVALID;++i)
+ /// s+=*i;
+ ///\endcode
+ ///(This code computes the sum of all coefficients).
+ ///- Numbers (<tt>double</tt>'s)
+ ///and variables (\ref Row "Row"s) directly convert to an
+ ///\ref DualExpr and the usual linear operations are defined, so
+ ///\code
+ ///v+w
+ ///2*v-3.12*(v-w/2)
+ ///v*2.1+(3*v+(v*12+w)*3)/2
+ ///\endcode
+ ///are valid \ref DualExpr dual expressions.
+ ///The usual assignment operations are also defined.
+ ///\code
+ ///e=v+w;
+ ///e+=2*v-3.12*(v-w/2);
+ ///e*=3.4;
+ ///e/=5;
+ ///\endcode
+ ///
+ ///\sa Expr
+ class DualExpr {
+ friend class LpBase;
+ public:
+ /// The key type of the expression
+ typedef LpBase::Row Key;
+ /// The value type of the expression
+ typedef LpBase::Value Value;
+
+ protected:
+ std::map<int, Value> comps;
+
+ public:
+ typedef True SolverExpr;
+ /// Default constructor
+
+ /// Construct an empty expression, the coefficients are
+ /// initialized to zero.
+ DualExpr() {}
+ /// Construct an expression from a row
+
+ /// Construct an expression, which has a term with \c r dual
+ /// variable and 1.0 coefficient.
+ DualExpr(const Row &r) {
+ typedef std::map<int, Value>::value_type pair_type;
+ comps.insert(pair_type(id(r), 1));
+ }
+ /// Returns the coefficient of the row
+ Value operator[](const Row& r) const {
+ std::map<int, Value>::const_iterator it = comps.find(id(r));
+ if (it != comps.end()) {
+ return it->second;
+ } else {
+ return 0;
+ }
+ }
+ /// Returns the coefficient of the row
+ Value& operator[](const Row& r) {
+ return comps[id(r)];
+ }
+ /// Sets the coefficient of the row
+ void set(const Row &r, const Value &v) {
+ if (v != 0.0) {
+ typedef std::map<int, Value>::value_type pair_type;
+ comps.insert(pair_type(id(r), v));
+ } else {
+ comps.erase(id(r));
+ }
+ }
+ /// \brief Removes the coefficients which's absolute value does
+ /// not exceed \c epsilon.
+ void simplify(Value epsilon = 0.0) {
+ std::map<int, Value>::iterator it=comps.begin();
+ while (it != comps.end()) {
+ std::map<int, Value>::iterator jt=it;
+ ++jt;
+ if (std::fabs((*it).second) <= epsilon) comps.erase(it);
+ it=jt;
+ }
+ }
+
+ void simplify(Value epsilon = 0.0) const {
+ const_cast<DualExpr*>(this)->simplify(epsilon);
+ }
+
+ ///Sets all coefficients to 0.
+ void clear() {
+ comps.clear();
+ }
+ ///Compound assignment
+ DualExpr &operator+=(const DualExpr &e) {
+ for (std::map<int, Value>::const_iterator it=e.comps.begin();
+ it!=e.comps.end(); ++it)
+ comps[it->first]+=it->second;
+ return *this;
+ }
+ ///Compound assignment
+ DualExpr &operator-=(const DualExpr &e) {
+ for (std::map<int, Value>::const_iterator it=e.comps.begin();
+ it!=e.comps.end(); ++it)
+ comps[it->first]-=it->second;
+ return *this;
+ }
+ ///Multiply with a constant
+ DualExpr &operator*=(const Value &v) {
+ for (std::map<int, Value>::iterator it=comps.begin();
+ it!=comps.end(); ++it)
+ it->second*=v;
+ return *this;
+ }
+ ///Division with a constant
+ DualExpr &operator/=(const Value &v) {
+ for (std::map<int, Value>::iterator it=comps.begin();
+ it!=comps.end(); ++it)
+ it->second/=v;
+ return *this;
+ }
+
+ ///Iterator over the expression
+
+ ///The iterator iterates over the terms of the expression.
+ ///
+ ///\code
+ ///double s=0;
+ ///for(LpBase::DualExpr::CoeffIt i(e);i!=INVALID;++i)
+ /// s+= *i * dual(i);
+ ///\endcode
+ class CoeffIt {
+ private:
+
+ std::map<int, Value>::iterator _it, _end;
+
+ public:
+
+ /// Sets the iterator to the first term
+
+ /// Sets the iterator to the first term of the expression.
+ ///
+ CoeffIt(DualExpr& e)
+ : _it(e.comps.begin()), _end(e.comps.end()){}
+
+ /// Convert the iterator to the row of the term
+ operator Row() const {
+ return rowFromId(_it->first);
+ }
+
+ /// Returns the coefficient of the term
+ Value& operator*() { return _it->second; }
+
+ /// Returns the coefficient of the term
+ const Value& operator*() const { return _it->second; }
+
+ /// Next term
+
+ /// Assign the iterator to the next term.
+ ///
+ CoeffIt& operator++() { ++_it; return *this; }
+
+ /// Equality operator
+ bool operator==(Invalid) const { return _it == _end; }
+ /// Inequality operator
+ bool operator!=(Invalid) const { return _it != _end; }
+ };
+
+ ///Iterator over the expression
+
+ ///The iterator iterates over the terms of the expression.
+ ///
+ ///\code
+ ///double s=0;
+ ///for(LpBase::DualExpr::ConstCoeffIt i(e);i!=INVALID;++i)
+ /// s+= *i * dual(i);
+ ///\endcode
+ class ConstCoeffIt {
+ private:
+
+ std::map<int, Value>::const_iterator _it, _end;
+
+ public:
+
+ /// Sets the iterator to the first term
+
+ /// Sets the iterator to the first term of the expression.
+ ///
+ ConstCoeffIt(const DualExpr& e)
+ : _it(e.comps.begin()), _end(e.comps.end()){}
+
+ /// Convert the iterator to the row of the term
+ operator Row() const {
+ return rowFromId(_it->first);
+ }
+
+ /// Returns the coefficient of the term
+ const Value& operator*() const { return _it->second; }
+
+ /// Next term
+
+ /// Assign the iterator to the next term.
+ ///
+ ConstCoeffIt& operator++() { ++_it; return *this; }
+
+ /// Equality operator
+ bool operator==(Invalid) const { return _it == _end; }
+ /// Inequality operator
+ bool operator!=(Invalid) const { return _it != _end; }
+ };
+ };
+
+
+ protected:
+
+ class InsertIterator {
+ private:
+
+ std::map<int, Value>& _host;
+ const _solver_bits::VarIndex& _index;
+
+ public:
+
+ typedef std::output_iterator_tag iterator_category;
+ typedef void difference_type;
+ typedef void value_type;
+ typedef void reference;
+ typedef void pointer;
+
+ InsertIterator(std::map<int, Value>& host,
+ const _solver_bits::VarIndex& index)
+ : _host(host), _index(index) {}
+
+ InsertIterator& operator=(const std::pair<int, Value>& value) {
+ typedef std::map<int, Value>::value_type pair_type;
+ _host.insert(pair_type(_index[value.first], value.second));
+ return *this;
+ }
+
+ InsertIterator& operator*() { return *this; }
+ InsertIterator& operator++() { return *this; }
+ InsertIterator operator++(int) { return *this; }
+
+ };
+
+ class ExprIterator {
+ private:
+ std::map<int, Value>::const_iterator _host_it;
+ const _solver_bits::VarIndex& _index;
+ public:
+
+ typedef std::bidirectional_iterator_tag iterator_category;
+ typedef std::ptrdiff_t difference_type;
+ typedef const std::pair<int, Value> value_type;
+ typedef value_type reference;
+
+ class pointer {
+ public:
+ pointer(value_type& _value) : value(_value) {}
+ value_type* operator->() { return &value; }
+ private:
+ value_type value;
+ };
+
+ ExprIterator(const std::map<int, Value>::const_iterator& host_it,
+ const _solver_bits::VarIndex& index)
+ : _host_it(host_it), _index(index) {}
+
+ reference operator*() {
+ return std::make_pair(_index(_host_it->first), _host_it->second);
+ }
+
+ pointer operator->() {
+ return pointer(operator*());
+ }
+
+ ExprIterator& operator++() { ++_host_it; return *this; }
+ ExprIterator operator++(int) {
+ ExprIterator tmp(*this); ++_host_it; return tmp;
+ }
+
+ ExprIterator& operator--() { --_host_it; return *this; }
+ ExprIterator operator--(int) {
+ ExprIterator tmp(*this); --_host_it; return tmp;
+ }
+
+ bool operator==(const ExprIterator& it) const {
+ return _host_it == it._host_it;
+ }
+
+ bool operator!=(const ExprIterator& it) const {
+ return _host_it != it._host_it;
+ }
+
+ };
+
+ protected:
+
+ //Abstract virtual functions
+
+ virtual int _addColId(int col) { return cols.addIndex(col); }
+ virtual int _addRowId(int row) { return rows.addIndex(row); }
+
+ virtual void _eraseColId(int col) { cols.eraseIndex(col); }
+ virtual void _eraseRowId(int row) { rows.eraseIndex(row); }
+
+ virtual int _addCol() = 0;
+ virtual int _addRow() = 0;
+
+ virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u) {
+ int row = _addRow();
+ _setRowCoeffs(row, b, e);
+ _setRowLowerBound(row, l);
+ _setRowUpperBound(row, u);
+ return row;
+ }
+
+ virtual void _eraseCol(int col) = 0;
+ virtual void _eraseRow(int row) = 0;
+
+ virtual void _getColName(int col, std::string& name) const = 0;
+ virtual void _setColName(int col, const std::string& name) = 0;
+ virtual int _colByName(const std::string& name) const = 0;
+
+ virtual void _getRowName(int row, std::string& name) const = 0;
+ virtual void _setRowName(int row, const std::string& name) = 0;
+ virtual int _rowByName(const std::string& name) const = 0;
+
+ virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e) = 0;
+ virtual void _getRowCoeffs(int i, InsertIterator b) const = 0;
+
+ virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e) = 0;
+ virtual void _getColCoeffs(int i, InsertIterator b) const = 0;
+
+ virtual void _setCoeff(int row, int col, Value value) = 0;
+ virtual Value _getCoeff(int row, int col) const = 0;
+
+ virtual void _setColLowerBound(int i, Value value) = 0;
+ virtual Value _getColLowerBound(int i) const = 0;
+
+ virtual void _setColUpperBound(int i, Value value) = 0;
+ virtual Value _getColUpperBound(int i) const = 0;
+
+ virtual void _setRowLowerBound(int i, Value value) = 0;
+ virtual Value _getRowLowerBound(int i) const = 0;
+
+ virtual void _setRowUpperBound(int i, Value value) = 0;
+ virtual Value _getRowUpperBound(int i) const = 0;
+
+ virtual void _setObjCoeffs(ExprIterator b, ExprIterator e) = 0;
+ virtual void _getObjCoeffs(InsertIterator b) const = 0;
+
+ virtual void _setObjCoeff(int i, Value obj_coef) = 0;
+ virtual Value _getObjCoeff(int i) const = 0;
+
+ virtual void _setSense(Sense) = 0;
+ virtual Sense _getSense() const = 0;
+
+ virtual void _clear() = 0;
+
+ virtual const char* _solverName() const = 0;
+
+ virtual void _messageLevel(MessageLevel level) = 0;
+
+ //Own protected stuff
+
+ //Constant component of the objective function
+ Value obj_const_comp;
+
+ LpBase() : rows(), cols(), obj_const_comp(0) {}
+
+ public:
+
+ ///Unsupported file format exception
+ class UnsupportedFormatError : public Exception
+ {
+ std::string _format;
+ mutable std::string _what;
+ public:
+ explicit UnsupportedFormatError(std::string format) throw()
+ : _format(format) { }
+ virtual ~UnsupportedFormatError() throw() {}
+ virtual const char* what() const throw() {
+ try {
+ _what.clear();
+ std::ostringstream oss;
+ oss << "lemon::UnsupportedFormatError: " << _format;
+ _what = oss.str();
+ }
+ catch (...) {}
+ if (!_what.empty()) return _what.c_str();
+ else return "lemon::UnsupportedFormatError";
+ }
+ };
+
+ protected:
+ virtual void _write(std::string, std::string format) const
+ {
+ throw UnsupportedFormatError(format);
+ }
+
+ public:
+
+ /// Virtual destructor
+ virtual ~LpBase() {}
+
+ ///Gives back the name of the solver.
+ const char* solverName() const {return _solverName();}
+
+ ///\name Build Up and Modify the LP
+
+ ///@{
+
+ ///Add a new empty column (i.e a new variable) to the LP
+ Col addCol() { Col c; c._id = _addColId(_addCol()); return c;}
+
+ ///\brief Adds several new columns (i.e variables) at once
+ ///
+ ///This magic function takes a container as its argument and fills
+ ///its elements with new columns (i.e. variables)
+ ///\param t can be
+ ///- a standard STL compatible iterable container with
+ ///\ref Col as its \c values_type like
+ ///\code
+ ///std::vector<LpBase::Col>
+ ///std::list<LpBase::Col>
+ ///\endcode
+ ///- a standard STL compatible iterable container with
+ ///\ref Col as its \c mapped_type like
+ ///\code
+ ///std::map<AnyType,LpBase::Col>
+ ///\endcode
+ ///- an iterable lemon \ref concepts::WriteMap "write map" like
+ ///\code
+ ///ListGraph::NodeMap<LpBase::Col>
+ ///ListGraph::ArcMap<LpBase::Col>
+ ///\endcode
+ ///\return The number of the created column.
+#ifdef DOXYGEN
+ template<class T>
+ int addColSet(T &t) { return 0;}
+#else
+ template<class T>
+ typename enable_if<typename T::value_type::LpCol,int>::type
+ addColSet(T &t,dummy<0> = 0) {
+ int s=0;
+ for(typename T::iterator i=t.begin();i!=t.end();++i) {*i=addCol();s++;}
+ return s;
+ }
+ template<class T>
+ typename enable_if<typename T::value_type::second_type::LpCol,
+ int>::type
+ addColSet(T &t,dummy<1> = 1) {
+ int s=0;
+ for(typename T::iterator i=t.begin();i!=t.end();++i) {
+ i->second=addCol();
+ s++;
+ }
+ return s;
+ }
+ template<class T>
+ typename enable_if<typename T::MapIt::Value::LpCol,
+ int>::type
+ addColSet(T &t,dummy<2> = 2) {
+ int s=0;
+ for(typename T::MapIt i(t); i!=INVALID; ++i)
+ {
+ i.set(addCol());
+ s++;
+ }
+ return s;
+ }
+#endif
+
+ ///Set a column (i.e a dual constraint) of the LP
+
+ ///\param c is the column to be modified
+ ///\param e is a dual linear expression (see \ref DualExpr)
+ ///a better one.
+ void col(Col c, const DualExpr &e) {
+ e.simplify();
+ _setColCoeffs(cols(id(c)), ExprIterator(e.comps.begin(), rows),
+ ExprIterator(e.comps.end(), rows));
+ }
+
+ ///Get a column (i.e a dual constraint) of the LP
+
+ ///\param c is the column to get
+ ///\return the dual expression associated to the column
+ DualExpr col(Col c) const {
+ DualExpr e;
+ _getColCoeffs(cols(id(c)), InsertIterator(e.comps, rows));
+ return e;
+ }
+
+ ///Add a new column to the LP
+
+ ///\param e is a dual linear expression (see \ref DualExpr)
+ ///\param o is the corresponding component of the objective
+ ///function. It is 0 by default.
+ ///\return The created column.
+ Col addCol(const DualExpr &e, Value o = 0) {
+ Col c=addCol();
+ col(c,e);
+ objCoeff(c,o);
+ return c;
+ }
+
+ ///Add a new empty row (i.e a new constraint) to the LP
+
+ ///This function adds a new empty row (i.e a new constraint) to the LP.
+ ///\return The created row
+ Row addRow() { Row r; r._id = _addRowId(_addRow()); return r;}
+
+ ///\brief Add several new rows (i.e constraints) at once
+ ///
+ ///This magic function takes a container as its argument and fills
+ ///its elements with new row (i.e. variables)
+ ///\param t can be
+ ///- a standard STL compatible iterable container with
+ ///\ref Row as its \c values_type like
+ ///\code
+ ///std::vector<LpBase::Row>
+ ///std::list<LpBase::Row>
+ ///\endcode
+ ///- a standard STL compatible iterable container with
+ ///\ref Row as its \c mapped_type like
+ ///\code
+ ///std::map<AnyType,LpBase::Row>
+ ///\endcode
+ ///- an iterable lemon \ref concepts::WriteMap "write map" like
+ ///\code
+ ///ListGraph::NodeMap<LpBase::Row>
+ ///ListGraph::ArcMap<LpBase::Row>
+ ///\endcode
+ ///\return The number of rows created.
+#ifdef DOXYGEN
+ template<class T>
+ int addRowSet(T &t) { return 0;}
+#else
+ template<class T>
+ typename enable_if<typename T::value_type::LpRow,int>::type
+ addRowSet(T &t, dummy<0> = 0) {
+ int s=0;
+ for(typename T::iterator i=t.begin();i!=t.end();++i) {*i=addRow();s++;}
+ return s;
+ }
+ template<class T>
+ typename enable_if<typename T::value_type::second_type::LpRow, int>::type
+ addRowSet(T &t, dummy<1> = 1) {
+ int s=0;
+ for(typename T::iterator i=t.begin();i!=t.end();++i) {
+ i->second=addRow();
+ s++;
+ }
+ return s;
+ }
+ template<class T>
+ typename enable_if<typename T::MapIt::Value::LpRow, int>::type
+ addRowSet(T &t, dummy<2> = 2) {
+ int s=0;
+ for(typename T::MapIt i(t); i!=INVALID; ++i)
+ {
+ i.set(addRow());
+ s++;
+ }
+ return s;
+ }
+#endif
+
+ ///Set a row (i.e a constraint) of the LP
+
+ ///\param r is the row to be modified
+ ///\param l is lower bound (-\ref INF means no bound)
+ ///\param e is a linear expression (see \ref Expr)
+ ///\param u is the upper bound (\ref INF means no bound)
+ void row(Row r, Value l, const Expr &e, Value u) {
+ e.simplify();
+ _setRowCoeffs(rows(id(r)), ExprIterator(e.comps.begin(), cols),
+ ExprIterator(e.comps.end(), cols));
+ _setRowLowerBound(rows(id(r)),l - *e);
+ _setRowUpperBound(rows(id(r)),u - *e);
+ }
+
+ ///Set a row (i.e a constraint) of the LP
+
+ ///\param r is the row to be modified
+ ///\param c is a linear expression (see \ref Constr)
+ void row(Row r, const Constr &c) {
+ row(r, c.lowerBounded()?c.lowerBound():-INF,
+ c.expr(), c.upperBounded()?c.upperBound():INF);
+ }
+
+
+ ///Get a row (i.e a constraint) of the LP
+
+ ///\param r is the row to get
+ ///\return the expression associated to the row
+ Expr row(Row r) const {
+ Expr e;
+ _getRowCoeffs(rows(id(r)), InsertIterator(e.comps, cols));
+ return e;
+ }
+
+ ///Add a new row (i.e a new constraint) to the LP
+
+ ///\param l is the lower bound (-\ref INF means no bound)
+ ///\param e is a linear expression (see \ref Expr)
+ ///\param u is the upper bound (\ref INF means no bound)
+ ///\return The created row.
+ Row addRow(Value l,const Expr &e, Value u) {
+ Row r;
+ e.simplify();
+ r._id = _addRowId(_addRow(l - *e, ExprIterator(e.comps.begin(), cols),
+ ExprIterator(e.comps.end(), cols), u - *e));
+ return r;
+ }
+
+ ///Add a new row (i.e a new constraint) to the LP
+
+ ///\param c is a linear expression (see \ref Constr)
+ ///\return The created row.
+ Row addRow(const Constr &c) {
+ Row r;
+ c.expr().simplify();
+ r._id = _addRowId(_addRow(c.lowerBounded()?c.lowerBound()-*c.expr():-INF,
+ ExprIterator(c.expr().comps.begin(), cols),
+ ExprIterator(c.expr().comps.end(), cols),
+ c.upperBounded()?c.upperBound()-*c.expr():INF));
+ return r;
+ }
+ ///Erase a column (i.e a variable) from the LP
+
+ ///\param c is the column to be deleted
+ void erase(Col c) {
+ _eraseCol(cols(id(c)));
+ _eraseColId(cols(id(c)));
+ }
+ ///Erase a row (i.e a constraint) from the LP
+
+ ///\param r is the row to be deleted
+ void erase(Row r) {
+ _eraseRow(rows(id(r)));
+ _eraseRowId(rows(id(r)));
+ }
+
+ /// Get the name of a column
+
+ ///\param c is the coresponding column
+ ///\return The name of the colunm
+ std::string colName(Col c) const {
+ std::string name;
+ _getColName(cols(id(c)), name);
+ return name;
+ }
+
+ /// Set the name of a column
+
+ ///\param c is the coresponding column
+ ///\param name The name to be given
+ void colName(Col c, const std::string& name) {
+ _setColName(cols(id(c)), name);
+ }
+
+ /// Get the column by its name
+
+ ///\param name The name of the column
+ ///\return the proper column or \c INVALID
+ Col colByName(const std::string& name) const {
+ int k = _colByName(name);
+ return k != -1 ? Col(cols[k]) : Col(INVALID);
+ }
+
+ /// Get the name of a row
+
+ ///\param r is the coresponding row
+ ///\return The name of the row
+ std::string rowName(Row r) const {
+ std::string name;
+ _getRowName(rows(id(r)), name);
+ return name;
+ }
+
+ /// Set the name of a row
+
+ ///\param r is the coresponding row
+ ///\param name The name to be given
+ void rowName(Row r, const std::string& name) {
+ _setRowName(rows(id(r)), name);
+ }
+
+ /// Get the row by its name
+
+ ///\param name The name of the row
+ ///\return the proper row or \c INVALID
+ Row rowByName(const std::string& name) const {
+ int k = _rowByName(name);
+ return k != -1 ? Row(rows[k]) : Row(INVALID);
+ }
+
+ /// Set an element of the coefficient matrix of the LP
+
+ ///\param r is the row of the element to be modified
+ ///\param c is the column of the element to be modified
+ ///\param val is the new value of the coefficient
+ void coeff(Row r, Col c, Value val) {
+ _setCoeff(rows(id(r)),cols(id(c)), val);
+ }
+
+ /// Get an element of the coefficient matrix of the LP
+
+ ///\param r is the row of the element
+ ///\param c is the column of the element
+ ///\return the corresponding coefficient
+ Value coeff(Row r, Col c) const {
+ return _getCoeff(rows(id(r)),cols(id(c)));
+ }
+
+ /// Set the lower bound of a column (i.e a variable)
+
+ /// The lower bound of a variable (column) has to be given by an
+ /// extended number of type Value, i.e. a finite number of type
+ /// Value or -\ref INF.
+ void colLowerBound(Col c, Value value) {
+ _setColLowerBound(cols(id(c)),value);
+ }
+
+ /// Get the lower bound of a column (i.e a variable)
+
+ /// This function returns the lower bound for column (variable) \c c
+ /// (this might be -\ref INF as well).
+ ///\return The lower bound for column \c c
+ Value colLowerBound(Col c) const {
+ return _getColLowerBound(cols(id(c)));
+ }
+
+ ///\brief Set the lower bound of several columns
+ ///(i.e variables) at once
+ ///
+ ///This magic function takes a container as its argument
+ ///and applies the function on all of its elements.
+ ///The lower bound of a variable (column) has to be given by an
+ ///extended number of type Value, i.e. a finite number of type
+ ///Value or -\ref INF.
+#ifdef DOXYGEN
+ template<class T>
+ void colLowerBound(T &t, Value value) { return 0;}
+#else
+ template<class T>
+ typename enable_if<typename T::value_type::LpCol,void>::type
+ colLowerBound(T &t, Value value,dummy<0> = 0) {
+ for(typename T::iterator i=t.begin();i!=t.end();++i) {
+ colLowerBound(*i, value);
+ }
+ }
+ template<class T>
+ typename enable_if<typename T::value_type::second_type::LpCol,
+ void>::type
+ colLowerBound(T &t, Value value,dummy<1> = 1) {
+ for(typename T::iterator i=t.begin();i!=t.end();++i) {
+ colLowerBound(i->second, value);
+ }
+ }
+ template<class T>
+ typename enable_if<typename T::MapIt::Value::LpCol,
+ void>::type
+ colLowerBound(T &t, Value value,dummy<2> = 2) {
+ for(typename T::MapIt i(t); i!=INVALID; ++i){
+ colLowerBound(*i, value);
+ }
+ }
+#endif
+
+ /// Set the upper bound of a column (i.e a variable)
+
+ /// The upper bound of a variable (column) has to be given by an
+ /// extended number of type Value, i.e. a finite number of type
+ /// Value or \ref INF.
+ void colUpperBound(Col c, Value value) {
+ _setColUpperBound(cols(id(c)),value);
+ };
+
+ /// Get the upper bound of a column (i.e a variable)
+
+ /// This function returns the upper bound for column (variable) \c c
+ /// (this might be \ref INF as well).
+ /// \return The upper bound for column \c c
+ Value colUpperBound(Col c) const {
+ return _getColUpperBound(cols(id(c)));
+ }
+
+ ///\brief Set the upper bound of several columns
+ ///(i.e variables) at once
+ ///
+ ///This magic function takes a container as its argument
+ ///and applies the function on all of its elements.
+ ///The upper bound of a variable (column) has to be given by an
+ ///extended number of type Value, i.e. a finite number of type
+ ///Value or \ref INF.
+#ifdef DOXYGEN
+ template<class T>
+ void colUpperBound(T &t, Value value) { return 0;}
+#else
+ template<class T1>
+ typename enable_if<typename T1::value_type::LpCol,void>::type
+ colUpperBound(T1 &t, Value value,dummy<0> = 0) {
+ for(typename T1::iterator i=t.begin();i!=t.end();++i) {
+ colUpperBound(*i, value);
+ }
+ }
+ template<class T1>
+ typename enable_if<typename T1::value_type::second_type::LpCol,
+ void>::type
+ colUpperBound(T1 &t, Value value,dummy<1> = 1) {
+ for(typename T1::iterator i=t.begin();i!=t.end();++i) {
+ colUpperBound(i->second, value);
+ }
+ }
+ template<class T1>
+ typename enable_if<typename T1::MapIt::Value::LpCol,
+ void>::type
+ colUpperBound(T1 &t, Value value,dummy<2> = 2) {
+ for(typename T1::MapIt i(t); i!=INVALID; ++i){
+ colUpperBound(*i, value);
+ }
+ }
+#endif
+
+ /// Set the lower and the upper bounds of a column (i.e a variable)
+
+ /// The lower and the upper bounds of
+ /// a variable (column) have to be given by an
+ /// extended number of type Value, i.e. a finite number of type
+ /// Value, -\ref INF or \ref INF.
+ void colBounds(Col c, Value lower, Value upper) {
+ _setColLowerBound(cols(id(c)),lower);
+ _setColUpperBound(cols(id(c)),upper);
+ }
+
+ ///\brief Set the lower and the upper bound of several columns
+ ///(i.e variables) at once
+ ///
+ ///This magic function takes a container as its argument
+ ///and applies the function on all of its elements.
+ /// The lower and the upper bounds of
+ /// a variable (column) have to be given by an
+ /// extended number of type Value, i.e. a finite number of type
+ /// Value, -\ref INF or \ref INF.
+#ifdef DOXYGEN
+ template<class T>
+ void colBounds(T &t, Value lower, Value upper) { return 0;}
+#else
+ template<class T2>
+ typename enable_if<typename T2::value_type::LpCol,void>::type
+ colBounds(T2 &t, Value lower, Value upper,dummy<0> = 0) {
+ for(typename T2::iterator i=t.begin();i!=t.end();++i) {
+ colBounds(*i, lower, upper);
+ }
+ }
+ template<class T2>
+ typename enable_if<typename T2::value_type::second_type::LpCol, void>::type
+ colBounds(T2 &t, Value lower, Value upper,dummy<1> = 1) {
+ for(typename T2::iterator i=t.begin();i!=t.end();++i) {
+ colBounds(i->second, lower, upper);
+ }
+ }
+ template<class T2>
+ typename enable_if<typename T2::MapIt::Value::LpCol, void>::type
+ colBounds(T2 &t, Value lower, Value upper,dummy<2> = 2) {
+ for(typename T2::MapIt i(t); i!=INVALID; ++i){
+ colBounds(*i, lower, upper);
+ }
+ }
+#endif
+
+ /// Set the lower bound of a row (i.e a constraint)
+
+ /// The lower bound of a constraint (row) has to be given by an
+ /// extended number of type Value, i.e. a finite number of type
+ /// Value or -\ref INF.
+ void rowLowerBound(Row r, Value value) {
+ _setRowLowerBound(rows(id(r)),value);
+ }
+
+ /// Get the lower bound of a row (i.e a constraint)
+
+ /// This function returns the lower bound for row (constraint) \c c
+ /// (this might be -\ref INF as well).
+ ///\return The lower bound for row \c r
+ Value rowLowerBound(Row r) const {
+ return _getRowLowerBound(rows(id(r)));
+ }
+
+ /// Set the upper bound of a row (i.e a constraint)
+
+ /// The upper bound of a constraint (row) has to be given by an
+ /// extended number of type Value, i.e. a finite number of type
+ /// Value or -\ref INF.
+ void rowUpperBound(Row r, Value value) {
+ _setRowUpperBound(rows(id(r)),value);
+ }
+
+ /// Get the upper bound of a row (i.e a constraint)
+
+ /// This function returns the upper bound for row (constraint) \c c
+ /// (this might be -\ref INF as well).
+ ///\return The upper bound for row \c r
+ Value rowUpperBound(Row r) const {
+ return _getRowUpperBound(rows(id(r)));
+ }
+
+ ///Set an element of the objective function
+ void objCoeff(Col c, Value v) {_setObjCoeff(cols(id(c)),v); };
+
+ ///Get an element of the objective function
+ Value objCoeff(Col c) const { return _getObjCoeff(cols(id(c))); };
+
+ ///Set the objective function
+
+ ///\param e is a linear expression of type \ref Expr.
+ ///
+ void obj(const Expr& e) {
+ _setObjCoeffs(ExprIterator(e.comps.begin(), cols),
+ ExprIterator(e.comps.end(), cols));
+ obj_const_comp = *e;
+ }
+
+ ///Get the objective function
+
+ ///\return the objective function as a linear expression of type
+ ///Expr.
+ Expr obj() const {
+ Expr e;
+ _getObjCoeffs(InsertIterator(e.comps, cols));
+ *e = obj_const_comp;
+ return e;
+ }
+
+
+ ///Set the direction of optimization
+ void sense(Sense sense) { _setSense(sense); }
+
+ ///Query the direction of the optimization
+ Sense sense() const {return _getSense(); }
+
+ ///Set the sense to maximization
+ void max() { _setSense(MAX); }
+
+ ///Set the sense to maximization
+ void min() { _setSense(MIN); }
+
+ ///Clear the problem
+ void clear() { _clear(); rows.clear(); cols.clear(); }
+
+ /// Set the message level of the solver
+ void messageLevel(MessageLevel level) { _messageLevel(level); }
+
+ /// Write the problem to a file in the given format
+
+ /// This function writes the problem to a file in the given format.
+ /// Different solver backends may support different formats.
+ /// Trying to write in an unsupported format will trigger
+ /// \ref UnsupportedFormatError. For the supported formats,
+ /// visit the documentation of the base class of the related backends
+ /// (\ref CplexBase, \ref GlpkBase etc.)
+ /// \param file The file path
+ /// \param format The output file format.
+ void write(std::string file, std::string format = "MPS") const
+ {
+ _write(file.c_str(),format.c_str());
+ }
+
+ ///@}
+
+ };
+
+ /// Addition
+
+ ///\relates LpBase::Expr
+ ///
+ inline LpBase::Expr operator+(const LpBase::Expr &a, const LpBase::Expr &b) {
+ LpBase::Expr tmp(a);
+ tmp+=b;
+ return tmp;
+ }
+ ///Substraction
+
+ ///\relates LpBase::Expr
+ ///
+ inline LpBase::Expr operator-(const LpBase::Expr &a, const LpBase::Expr &b) {
+ LpBase::Expr tmp(a);
+ tmp-=b;
+ return tmp;
+ }
+ ///Multiply with constant
+
+ ///\relates LpBase::Expr
+ ///
+ inline LpBase::Expr operator*(const LpBase::Expr &a, const LpBase::Value &b) {
+ LpBase::Expr tmp(a);
+ tmp*=b;
+ return tmp;
+ }
+
+ ///Multiply with constant
+
+ ///\relates LpBase::Expr
+ ///
+ inline LpBase::Expr operator*(const LpBase::Value &a, const LpBase::Expr &b) {
+ LpBase::Expr tmp(b);
+ tmp*=a;
+ return tmp;
+ }
+ ///Divide with constant
+
+ ///\relates LpBase::Expr
+ ///
+ inline LpBase::Expr operator/(const LpBase::Expr &a, const LpBase::Value &b) {
+ LpBase::Expr tmp(a);
+ tmp/=b;
+ return tmp;
+ }
+
+ ///Create constraint
+
+ ///\relates LpBase::Constr
+ ///
+ inline LpBase::Constr operator<=(const LpBase::Expr &e,
+ const LpBase::Expr &f) {
+ return LpBase::Constr(0, f - e, LpBase::NaN);
+ }
+
+ ///Create constraint
+
+ ///\relates LpBase::Constr
+ ///
+ inline LpBase::Constr operator<=(const LpBase::Value &e,
+ const LpBase::Expr &f) {
+ return LpBase::Constr(e, f, LpBase::NaN);
+ }
+
+ ///Create constraint
+
+ ///\relates LpBase::Constr
+ ///
+ inline LpBase::Constr operator<=(const LpBase::Expr &e,
+ const LpBase::Value &f) {
+ return LpBase::Constr(LpBase::NaN, e, f);
+ }
+
+ ///Create constraint
+
+ ///\relates LpBase::Constr
+ ///
+ inline LpBase::Constr operator>=(const LpBase::Expr &e,
+ const LpBase::Expr &f) {
+ return LpBase::Constr(0, e - f, LpBase::NaN);
+ }
+
+
+ ///Create constraint
+
+ ///\relates LpBase::Constr
+ ///
+ inline LpBase::Constr operator>=(const LpBase::Value &e,
+ const LpBase::Expr &f) {
+ return LpBase::Constr(LpBase::NaN, f, e);
+ }
+
+
+ ///Create constraint
+
+ ///\relates LpBase::Constr
+ ///
+ inline LpBase::Constr operator>=(const LpBase::Expr &e,
+ const LpBase::Value &f) {
+ return LpBase::Constr(f, e, LpBase::NaN);
+ }
+
+ ///Create constraint
+
+ ///\relates LpBase::Constr
+ ///
+ inline LpBase::Constr operator==(const LpBase::Expr &e,
+ const LpBase::Value &f) {
+ return LpBase::Constr(f, e, f);
+ }
+
+ ///Create constraint
+
+ ///\relates LpBase::Constr
+ ///
+ inline LpBase::Constr operator==(const LpBase::Expr &e,
+ const LpBase::Expr &f) {
+ return LpBase::Constr(0, f - e, 0);
+ }
+
+ ///Create constraint
+
+ ///\relates LpBase::Constr
+ ///
+ inline LpBase::Constr operator<=(const LpBase::Value &n,
+ const LpBase::Constr &c) {
+ LpBase::Constr tmp(c);
+ LEMON_ASSERT(isNaN(tmp.lowerBound()), "Wrong LP constraint");
+ tmp.lowerBound()=n;
+ return tmp;
+ }
+ ///Create constraint
+
+ ///\relates LpBase::Constr
+ ///
+ inline LpBase::Constr operator<=(const LpBase::Constr &c,
+ const LpBase::Value &n)
+ {
+ LpBase::Constr tmp(c);
+ LEMON_ASSERT(isNaN(tmp.upperBound()), "Wrong LP constraint");
+ tmp.upperBound()=n;
+ return tmp;
+ }
+
+ ///Create constraint
+
+ ///\relates LpBase::Constr
+ ///
+ inline LpBase::Constr operator>=(const LpBase::Value &n,
+ const LpBase::Constr &c) {
+ LpBase::Constr tmp(c);
+ LEMON_ASSERT(isNaN(tmp.upperBound()), "Wrong LP constraint");
+ tmp.upperBound()=n;
+ return tmp;
+ }
+ ///Create constraint
+
+ ///\relates LpBase::Constr
+ ///
+ inline LpBase::Constr operator>=(const LpBase::Constr &c,
+ const LpBase::Value &n)
+ {
+ LpBase::Constr tmp(c);
+ LEMON_ASSERT(isNaN(tmp.lowerBound()), "Wrong LP constraint");
+ tmp.lowerBound()=n;
+ return tmp;
+ }
+
+ ///Addition
+
+ ///\relates LpBase::DualExpr
+ ///
+ inline LpBase::DualExpr operator+(const LpBase::DualExpr &a,
+ const LpBase::DualExpr &b) {
+ LpBase::DualExpr tmp(a);
+ tmp+=b;
+ return tmp;
+ }
+ ///Substraction
+
+ ///\relates LpBase::DualExpr
+ ///
+ inline LpBase::DualExpr operator-(const LpBase::DualExpr &a,
+ const LpBase::DualExpr &b) {
+ LpBase::DualExpr tmp(a);
+ tmp-=b;
+ return tmp;
+ }
+ ///Multiply with constant
+
+ ///\relates LpBase::DualExpr
+ ///
+ inline LpBase::DualExpr operator*(const LpBase::DualExpr &a,
+ const LpBase::Value &b) {
+ LpBase::DualExpr tmp(a);
+ tmp*=b;
+ return tmp;
+ }
+
+ ///Multiply with constant
+
+ ///\relates LpBase::DualExpr
+ ///
+ inline LpBase::DualExpr operator*(const LpBase::Value &a,
+ const LpBase::DualExpr &b) {
+ LpBase::DualExpr tmp(b);
+ tmp*=a;
+ return tmp;
+ }
+ ///Divide with constant
+
+ ///\relates LpBase::DualExpr
+ ///
+ inline LpBase::DualExpr operator/(const LpBase::DualExpr &a,
+ const LpBase::Value &b) {
+ LpBase::DualExpr tmp(a);
+ tmp/=b;
+ return tmp;
+ }
+
+ /// \ingroup lp_group
+ ///
+ /// \brief Common base class for LP solvers
+ ///
+ /// This class is an abstract base class for LP solvers. This class
+ /// provides a full interface for set and modify an LP problem,
+ /// solve it and retrieve the solution. You can use one of the
+ /// descendants as a concrete implementation, or the \c Lp
+ /// default LP solver. However, if you would like to handle LP
+ /// solvers as reference or pointer in a generic way, you can use
+ /// this class directly.
+ class LpSolver : virtual public LpBase {
+ public:
+
+ /// The problem types for primal and dual problems
+ enum ProblemType {
+ /// = 0. Feasible solution hasn't been found (but may exist).
+ UNDEFINED = 0,
+ /// = 1. The problem has no feasible solution.
+ INFEASIBLE = 1,
+ /// = 2. Feasible solution found.
+ FEASIBLE = 2,
+ /// = 3. Optimal solution exists and found.
+ OPTIMAL = 3,
+ /// = 4. The cost function is unbounded.
+ UNBOUNDED = 4
+ };
+
+ ///The basis status of variables
+ enum VarStatus {
+ /// The variable is in the basis
+ BASIC,
+ /// The variable is free, but not basic
+ FREE,
+ /// The variable has active lower bound
+ LOWER,
+ /// The variable has active upper bound
+ UPPER,
+ /// The variable is non-basic and fixed
+ FIXED
+ };
+
+ protected:
+
+ virtual SolveExitStatus _solve() = 0;
+
+ virtual Value _getPrimal(int i) const = 0;
+ virtual Value _getDual(int i) const = 0;
+
+ virtual Value _getPrimalRay(int i) const = 0;
+ virtual Value _getDualRay(int i) const = 0;
+
+ virtual Value _getPrimalValue() const = 0;
+
+ virtual VarStatus _getColStatus(int i) const = 0;
+ virtual VarStatus _getRowStatus(int i) const = 0;
+
+ virtual ProblemType _getPrimalType() const = 0;
+ virtual ProblemType _getDualType() const = 0;
+
+ public:
+
+ ///Allocate a new LP problem instance
+ virtual LpSolver* newSolver() const = 0;
+ ///Make a copy of the LP problem
+ virtual LpSolver* cloneSolver() const = 0;
+
+ ///\name Solve the LP
+
+ ///@{
+
+ ///\e Solve the LP problem at hand
+ ///
+ ///\return The result of the optimization procedure. Possible
+ ///values and their meanings can be found in the documentation of
+ ///\ref SolveExitStatus.
+ SolveExitStatus solve() { return _solve(); }
+
+ ///@}
+
+ ///\name Obtain the Solution
+
+ ///@{
+
+ /// The type of the primal problem
+ ProblemType primalType() const {
+ return _getPrimalType();
+ }
+
+ /// The type of the dual problem
+ ProblemType dualType() const {
+ return _getDualType();
+ }
+
+ /// Return the primal value of the column
+
+ /// Return the primal value of the column.
+ /// \pre The problem is solved.
+ Value primal(Col c) const { return _getPrimal(cols(id(c))); }
+
+ /// Return the primal value of the expression
+
+ /// Return the primal value of the expression, i.e. the dot
+ /// product of the primal solution and the expression.
+ /// \pre The problem is solved.
+ Value primal(const Expr& e) const {
+ double res = *e;
+ for (Expr::ConstCoeffIt c(e); c != INVALID; ++c) {
+ res += *c * primal(c);
+ }
+ return res;
+ }
+ /// Returns a component of the primal ray
+
+ /// The primal ray is solution of the modified primal problem,
+ /// where we change each finite bound to 0, and we looking for a
+ /// negative objective value in case of minimization, and positive
+ /// objective value for maximization. If there is such solution,
+ /// that proofs the unsolvability of the dual problem, and if a
+ /// feasible primal solution exists, then the unboundness of
+ /// primal problem.
+ ///
+ /// \pre The problem is solved and the dual problem is infeasible.
+ /// \note Some solvers does not provide primal ray calculation
+ /// functions.
+ Value primalRay(Col c) const { return _getPrimalRay(cols(id(c))); }
+
+ /// Return the dual value of the row
+
+ /// Return the dual value of the row.
+ /// \pre The problem is solved.
+ Value dual(Row r) const { return _getDual(rows(id(r))); }
+
+ /// Return the dual value of the dual expression
+
+ /// Return the dual value of the dual expression, i.e. the dot
+ /// product of the dual solution and the dual expression.
+ /// \pre The problem is solved.
+ Value dual(const DualExpr& e) const {
+ double res = 0.0;
+ for (DualExpr::ConstCoeffIt r(e); r != INVALID; ++r) {
+ res += *r * dual(r);
+ }
+ return res;
+ }
+
+ /// Returns a component of the dual ray
+
+ /// The dual ray is solution of the modified primal problem, where
+ /// we change each finite bound to 0 (i.e. the objective function
+ /// coefficients in the primal problem), and we looking for a
+ /// ositive objective value. If there is such solution, that
+ /// proofs the unsolvability of the primal problem, and if a
+ /// feasible dual solution exists, then the unboundness of
+ /// dual problem.
+ ///
+ /// \pre The problem is solved and the primal problem is infeasible.
+ /// \note Some solvers does not provide dual ray calculation
+ /// functions.
+ Value dualRay(Row r) const { return _getDualRay(rows(id(r))); }
+
+ /// Return the basis status of the column
+
+ /// \see VarStatus
+ VarStatus colStatus(Col c) const { return _getColStatus(cols(id(c))); }
+
+ /// Return the basis status of the row
+
+ /// \see VarStatus
+ VarStatus rowStatus(Row r) const { return _getRowStatus(rows(id(r))); }
+
+ ///The value of the objective function
+
+ ///\return
+ ///- \ref INF or -\ref INF means either infeasibility or unboundedness
+ /// of the primal problem, depending on whether we minimize or maximize.
+ ///- \ref NaN if no primal solution is found.
+ ///- The (finite) objective value if an optimal solution is found.
+ Value primal() const { return _getPrimalValue()+obj_const_comp;}
+ ///@}
+
+ protected:
+
+ };
+
+
+ /// \ingroup lp_group
+ ///
+ /// \brief Common base class for MIP solvers
+ ///
+ /// This class is an abstract base class for MIP solvers. This class
+ /// provides a full interface for set and modify an MIP problem,
+ /// solve it and retrieve the solution. You can use one of the
+ /// descendants as a concrete implementation, or the \c Lp
+ /// default MIP solver. However, if you would like to handle MIP
+ /// solvers as reference or pointer in a generic way, you can use
+ /// this class directly.
+ class MipSolver : virtual public LpBase {
+ public:
+
+ /// The problem types for MIP problems
+ enum ProblemType {
+ /// = 0. Feasible solution hasn't been found (but may exist).
+ UNDEFINED = 0,
+ /// = 1. The problem has no feasible solution.
+ INFEASIBLE = 1,
+ /// = 2. Feasible solution found.
+ FEASIBLE = 2,
+ /// = 3. Optimal solution exists and found.
+ OPTIMAL = 3,
+ /// = 4. The cost function is unbounded.
+ ///The Mip or at least the relaxed problem is unbounded.
+ UNBOUNDED = 4
+ };
+
+ ///Allocate a new MIP problem instance
+ virtual MipSolver* newSolver() const = 0;
+ ///Make a copy of the MIP problem
+ virtual MipSolver* cloneSolver() const = 0;
+
+ ///\name Solve the MIP
+
+ ///@{
+
+ /// Solve the MIP problem at hand
+ ///
+ ///\return The result of the optimization procedure. Possible
+ ///values and their meanings can be found in the documentation of
+ ///\ref SolveExitStatus.
+ SolveExitStatus solve() { return _solve(); }
+
+ ///@}
+
+ ///\name Set Column Type
+ ///@{
+
+ ///Possible variable (column) types (e.g. real, integer, binary etc.)
+ enum ColTypes {
+ /// = 0. Continuous variable (default).
+ REAL = 0,
+ /// = 1. Integer variable.
+ INTEGER = 1
+ };
+
+ ///Sets the type of the given column to the given type
+
+ ///Sets the type of the given column to the given type.
+ ///
+ void colType(Col c, ColTypes col_type) {
+ _setColType(cols(id(c)),col_type);
+ }
+
+ ///Gives back the type of the column.
+
+ ///Gives back the type of the column.
+ ///
+ ColTypes colType(Col c) const {
+ return _getColType(cols(id(c)));
+ }
+ ///@}
+
+ ///\name Obtain the Solution
+
+ ///@{
+
+ /// The type of the MIP problem
+ ProblemType type() const {
+ return _getType();
+ }
+
+ /// Return the value of the row in the solution
+
+ /// Return the value of the row in the solution.
+ /// \pre The problem is solved.
+ Value sol(Col c) const { return _getSol(cols(id(c))); }
+
+ /// Return the value of the expression in the solution
+
+ /// Return the value of the expression in the solution, i.e. the
+ /// dot product of the solution and the expression.
+ /// \pre The problem is solved.
+ Value sol(const Expr& e) const {
+ double res = *e;
+ for (Expr::ConstCoeffIt c(e); c != INVALID; ++c) {
+ res += *c * sol(c);
+ }
+ return res;
+ }
+ ///The value of the objective function
+
+ ///\return
+ ///- \ref INF or -\ref INF means either infeasibility or unboundedness
+ /// of the problem, depending on whether we minimize or maximize.
+ ///- \ref NaN if no primal solution is found.
+ ///- The (finite) objective value if an optimal solution is found.
+ Value solValue() const { return _getSolValue()+obj_const_comp;}
+ ///@}
+
+ protected:
+
+ virtual SolveExitStatus _solve() = 0;
+ virtual ColTypes _getColType(int col) const = 0;
+ virtual void _setColType(int col, ColTypes col_type) = 0;
+ virtual ProblemType _getType() const = 0;
+ virtual Value _getSol(int i) const = 0;
+ virtual Value _getSolValue() const = 0;
+
+ };
+
+
+
+} //namespace lemon
+
+#endif //LEMON_LP_BASE_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_skeleton.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_skeleton.cc
new file mode 100644
index 00000000000..fc1c143f3ca
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_skeleton.cc
@@ -0,0 +1,143 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <lemon/lp_skeleton.h>
+
+///\file
+///\brief A skeleton file to implement LP solver interfaces
+namespace lemon {
+
+ int SkeletonSolverBase::_addCol()
+ {
+ return ++col_num;
+ }
+
+ int SkeletonSolverBase::_addRow()
+ {
+ return ++row_num;
+ }
+
+ int SkeletonSolverBase::_addRow(Value, ExprIterator, ExprIterator, Value)
+ {
+ return ++row_num;
+ }
+
+ void SkeletonSolverBase::_eraseCol(int) {}
+ void SkeletonSolverBase::_eraseRow(int) {}
+
+ void SkeletonSolverBase::_getColName(int, std::string &) const {}
+ void SkeletonSolverBase::_setColName(int, const std::string &) {}
+ int SkeletonSolverBase::_colByName(const std::string&) const { return -1; }
+
+ void SkeletonSolverBase::_getRowName(int, std::string &) const {}
+ void SkeletonSolverBase::_setRowName(int, const std::string &) {}
+ int SkeletonSolverBase::_rowByName(const std::string&) const { return -1; }
+
+ void SkeletonSolverBase::_setRowCoeffs(int, ExprIterator, ExprIterator) {}
+ void SkeletonSolverBase::_getRowCoeffs(int, InsertIterator) const {}
+
+ void SkeletonSolverBase::_setColCoeffs(int, ExprIterator, ExprIterator) {}
+ void SkeletonSolverBase::_getColCoeffs(int, InsertIterator) const {}
+
+ void SkeletonSolverBase::_setCoeff(int, int, Value) {}
+ SkeletonSolverBase::Value SkeletonSolverBase::_getCoeff(int, int) const
+ { return 0; }
+
+ void SkeletonSolverBase::_setColLowerBound(int, Value) {}
+ SkeletonSolverBase::Value SkeletonSolverBase::_getColLowerBound(int) const
+ { return 0; }
+
+ void SkeletonSolverBase::_setColUpperBound(int, Value) {}
+ SkeletonSolverBase::Value SkeletonSolverBase::_getColUpperBound(int) const
+ { return 0; }
+
+ void SkeletonSolverBase::_setRowLowerBound(int, Value) {}
+ SkeletonSolverBase::Value SkeletonSolverBase::_getRowLowerBound(int) const
+ { return 0; }
+
+ void SkeletonSolverBase::_setRowUpperBound(int, Value) {}
+ SkeletonSolverBase::Value SkeletonSolverBase::_getRowUpperBound(int) const
+ { return 0; }
+
+ void SkeletonSolverBase::_setObjCoeffs(ExprIterator, ExprIterator) {}
+ void SkeletonSolverBase::_getObjCoeffs(InsertIterator) const {};
+
+ void SkeletonSolverBase::_setObjCoeff(int, Value) {}
+ SkeletonSolverBase::Value SkeletonSolverBase::_getObjCoeff(int) const
+ { return 0; }
+
+ void SkeletonSolverBase::_setSense(Sense) {}
+ SkeletonSolverBase::Sense SkeletonSolverBase::_getSense() const
+ { return MIN; }
+
+ void SkeletonSolverBase::_clear() {
+ row_num = col_num = 0;
+ }
+
+ void SkeletonSolverBase::_messageLevel(MessageLevel) {}
+
+ void SkeletonSolverBase::_write(std::string, std::string) const {}
+
+ LpSkeleton::SolveExitStatus LpSkeleton::_solve() { return SOLVED; }
+
+ LpSkeleton::Value LpSkeleton::_getPrimal(int) const { return 0; }
+ LpSkeleton::Value LpSkeleton::_getDual(int) const { return 0; }
+ LpSkeleton::Value LpSkeleton::_getPrimalValue() const { return 0; }
+
+ LpSkeleton::Value LpSkeleton::_getPrimalRay(int) const { return 0; }
+ LpSkeleton::Value LpSkeleton::_getDualRay(int) const { return 0; }
+
+ LpSkeleton::ProblemType LpSkeleton::_getPrimalType() const
+ { return UNDEFINED; }
+
+ LpSkeleton::ProblemType LpSkeleton::_getDualType() const
+ { return UNDEFINED; }
+
+ LpSkeleton::VarStatus LpSkeleton::_getColStatus(int) const
+ { return BASIC; }
+
+ LpSkeleton::VarStatus LpSkeleton::_getRowStatus(int) const
+ { return BASIC; }
+
+ LpSkeleton* LpSkeleton::newSolver() const
+ { return static_cast<LpSkeleton*>(0); }
+
+ LpSkeleton* LpSkeleton::cloneSolver() const
+ { return static_cast<LpSkeleton*>(0); }
+
+ const char* LpSkeleton::_solverName() const { return "LpSkeleton"; }
+
+ MipSkeleton::SolveExitStatus MipSkeleton::_solve()
+ { return SOLVED; }
+
+ MipSkeleton::Value MipSkeleton::_getSol(int) const { return 0; }
+ MipSkeleton::Value MipSkeleton::_getSolValue() const { return 0; }
+
+ MipSkeleton::ProblemType MipSkeleton::_getType() const
+ { return UNDEFINED; }
+
+ MipSkeleton* MipSkeleton::newSolver() const
+ { return static_cast<MipSkeleton*>(0); }
+
+ MipSkeleton* MipSkeleton::cloneSolver() const
+ { return static_cast<MipSkeleton*>(0); }
+
+ const char* MipSkeleton::_solverName() const { return "MipSkeleton"; }
+
+} //namespace lemon
+
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_skeleton.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_skeleton.h
new file mode 100644
index 00000000000..27285a4982a
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_skeleton.h
@@ -0,0 +1,234 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_LP_SKELETON_H
+#define LEMON_LP_SKELETON_H
+
+#include <lemon/lp_base.h>
+
+///\file
+///\brief Skeleton file to implement LP/MIP solver interfaces
+///
+///The classes in this file do nothing, but they can serve as skeletons when
+///implementing an interface to new solvers.
+namespace lemon {
+
+ ///A skeleton class to implement LP/MIP solver base interface
+
+ ///This class does nothing, but it can serve as a skeleton when
+ ///implementing an interface to new solvers.
+ class SkeletonSolverBase : public virtual LpBase {
+ int col_num,row_num;
+
+ protected:
+
+ SkeletonSolverBase()
+ : col_num(-1), row_num(-1) {}
+
+ /// \e
+ virtual int _addCol();
+ /// \e
+ virtual int _addRow();
+ /// \e
+ virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u);
+ /// \e
+ virtual void _eraseCol(int i);
+ /// \e
+ virtual void _eraseRow(int i);
+
+ /// \e
+ virtual void _getColName(int col, std::string& name) const;
+ /// \e
+ virtual void _setColName(int col, const std::string& name);
+ /// \e
+ virtual int _colByName(const std::string& name) const;
+
+ /// \e
+ virtual void _getRowName(int row, std::string& name) const;
+ /// \e
+ virtual void _setRowName(int row, const std::string& name);
+ /// \e
+ virtual int _rowByName(const std::string& name) const;
+
+ /// \e
+ virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e);
+ /// \e
+ virtual void _getRowCoeffs(int i, InsertIterator b) const;
+ /// \e
+ virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e);
+ /// \e
+ virtual void _getColCoeffs(int i, InsertIterator b) const;
+
+ /// Set one element of the coefficient matrix
+ virtual void _setCoeff(int row, int col, Value value);
+
+ /// Get one element of the coefficient matrix
+ virtual Value _getCoeff(int row, int col) const;
+
+ /// The lower bound of a variable (column) have to be given by an
+ /// extended number of type Value, i.e. a finite number of type
+ /// Value or -\ref INF.
+ virtual void _setColLowerBound(int i, Value value);
+ /// \e
+
+ /// The lower bound of a variable (column) is an
+ /// extended number of type Value, i.e. a finite number of type
+ /// Value or -\ref INF.
+ virtual Value _getColLowerBound(int i) const;
+
+ /// The upper bound of a variable (column) have to be given by an
+ /// extended number of type Value, i.e. a finite number of type
+ /// Value or \ref INF.
+ virtual void _setColUpperBound(int i, Value value);
+ /// \e
+
+ /// The upper bound of a variable (column) is an
+ /// extended number of type Value, i.e. a finite number of type
+ /// Value or \ref INF.
+ virtual Value _getColUpperBound(int i) const;
+
+ /// The lower bound of a constraint (row) have to be given by an
+ /// extended number of type Value, i.e. a finite number of type
+ /// Value or -\ref INF.
+ virtual void _setRowLowerBound(int i, Value value);
+ /// \e
+
+ /// The lower bound of a constraint (row) is an
+ /// extended number of type Value, i.e. a finite number of type
+ /// Value or -\ref INF.
+ virtual Value _getRowLowerBound(int i) const;
+
+ /// The upper bound of a constraint (row) have to be given by an
+ /// extended number of type Value, i.e. a finite number of type
+ /// Value or \ref INF.
+ virtual void _setRowUpperBound(int i, Value value);
+ /// \e
+
+ /// The upper bound of a constraint (row) is an
+ /// extended number of type Value, i.e. a finite number of type
+ /// Value or \ref INF.
+ virtual Value _getRowUpperBound(int i) const;
+
+ /// \e
+ virtual void _setObjCoeffs(ExprIterator b, ExprIterator e);
+ /// \e
+ virtual void _getObjCoeffs(InsertIterator b) const;
+
+ /// \e
+ virtual void _setObjCoeff(int i, Value obj_coef);
+ /// \e
+ virtual Value _getObjCoeff(int i) const;
+
+ ///\e
+ virtual void _setSense(Sense);
+ ///\e
+ virtual Sense _getSense() const;
+
+ ///\e
+ virtual void _clear();
+
+ ///\e
+ virtual void _messageLevel(MessageLevel);
+
+ ///\e
+ virtual void _write(std::string file, std::string format) const;
+
+ };
+
+ /// \brief Skeleton class for an LP solver interface
+ ///
+ ///This class does nothing, but it can serve as a skeleton when
+ ///implementing an interface to new solvers.
+
+ ///\ingroup lp_group
+ class LpSkeleton : public LpSolver, public SkeletonSolverBase {
+ public:
+ ///\e
+ LpSkeleton() : LpSolver(), SkeletonSolverBase() {}
+ ///\e
+ virtual LpSkeleton* newSolver() const;
+ ///\e
+ virtual LpSkeleton* cloneSolver() const;
+ protected:
+
+ ///\e
+ virtual SolveExitStatus _solve();
+
+ ///\e
+ virtual Value _getPrimal(int i) const;
+ ///\e
+ virtual Value _getDual(int i) const;
+
+ ///\e
+ virtual Value _getPrimalValue() const;
+
+ ///\e
+ virtual Value _getPrimalRay(int i) const;
+ ///\e
+ virtual Value _getDualRay(int i) const;
+
+ ///\e
+ virtual ProblemType _getPrimalType() const;
+ ///\e
+ virtual ProblemType _getDualType() const;
+
+ ///\e
+ virtual VarStatus _getColStatus(int i) const;
+ ///\e
+ virtual VarStatus _getRowStatus(int i) const;
+
+ ///\e
+ virtual const char* _solverName() const;
+
+ };
+
+ /// \brief Skeleton class for a MIP solver interface
+ ///
+ ///This class does nothing, but it can serve as a skeleton when
+ ///implementing an interface to new solvers.
+ ///\ingroup lp_group
+ class MipSkeleton : public MipSolver, public SkeletonSolverBase {
+ public:
+ ///\e
+ MipSkeleton() : MipSolver(), SkeletonSolverBase() {}
+ ///\e
+ virtual MipSkeleton* newSolver() const;
+ ///\e
+ virtual MipSkeleton* cloneSolver() const;
+
+ protected:
+ ///\e
+ virtual SolveExitStatus _solve();
+
+ ///\e
+ virtual Value _getSol(int i) const;
+
+ ///\e
+ virtual Value _getSolValue() const;
+
+ ///\e
+ virtual ProblemType _getType() const;
+
+ ///\e
+ virtual const char* _solverName() const;
+
+ };
+
+} //namespace lemon
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/maps.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/maps.h
new file mode 100644
index 00000000000..1bc49e911ca
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/maps.h
@@ -0,0 +1,4057 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_MAPS_H
+#define LEMON_MAPS_H
+
+#include <iterator>
+#include <functional>
+#include <vector>
+#include <map>
+
+#include <lemon/core.h>
+
+///\file
+///\ingroup maps
+///\brief Miscellaneous property maps
+
+namespace lemon {
+
+ /// \addtogroup maps
+ /// @{
+
+ /// Base class of maps.
+
+ /// Base class of maps. It provides the necessary type definitions
+ /// required by the map %concepts.
+ template<typename K, typename V>
+ class MapBase {
+ public:
+ /// \brief The key type of the map.
+ typedef K Key;
+ /// \brief The value type of the map.
+ /// (The type of objects associated with the keys).
+ typedef V Value;
+ };
+
+
+ /// Null map. (a.k.a. DoNothingMap)
+
+ /// This map can be used if you have to provide a map only for
+ /// its type definitions, or if you have to provide a writable map,
+ /// but data written to it is not required (i.e. it will be sent to
+ /// <tt>/dev/null</tt>).
+ /// It conforms to the \ref concepts::ReadWriteMap "ReadWriteMap" concept.
+ ///
+ /// \sa ConstMap
+ template<typename K, typename V>
+ class NullMap : public MapBase<K, V> {
+ public:
+ ///\e
+ typedef K Key;
+ ///\e
+ typedef V Value;
+
+ /// Gives back a default constructed element.
+ Value operator[](const Key&) const { return Value(); }
+ /// Absorbs the value.
+ void set(const Key&, const Value&) {}
+ };
+
+ /// Returns a \c NullMap class
+
+ /// This function just returns a \c NullMap class.
+ /// \relates NullMap
+ template <typename K, typename V>
+ NullMap<K, V> nullMap() {
+ return NullMap<K, V>();
+ }
+
+
+ /// Constant map.
+
+ /// This \ref concepts::ReadMap "readable map" assigns a specified
+ /// value to each key.
+ ///
+ /// In other aspects it is equivalent to \c NullMap.
+ /// So it conforms to the \ref concepts::ReadWriteMap "ReadWriteMap"
+ /// concept, but it absorbs the data written to it.
+ ///
+ /// The simplest way of using this map is through the constMap()
+ /// function.
+ ///
+ /// \sa NullMap
+ /// \sa IdentityMap
+ template<typename K, typename V>
+ class ConstMap : public MapBase<K, V> {
+ private:
+ V _value;
+ public:
+ ///\e
+ typedef K Key;
+ ///\e
+ typedef V Value;
+
+ /// Default constructor
+
+ /// Default constructor.
+ /// The value of the map will be default constructed.
+ ConstMap() {}
+
+ /// Constructor with specified initial value
+
+ /// Constructor with specified initial value.
+ /// \param v The initial value of the map.
+ ConstMap(const Value &v) : _value(v) {}
+
+ /// Gives back the specified value.
+ Value operator[](const Key&) const { return _value; }
+
+ /// Absorbs the value.
+ void set(const Key&, const Value&) {}
+
+ /// Sets the value that is assigned to each key.
+ void setAll(const Value &v) {
+ _value = v;
+ }
+
+ template<typename V1>
+ ConstMap(const ConstMap<K, V1> &, const Value &v) : _value(v) {}
+ };
+
+ /// Returns a \c ConstMap class
+
+ /// This function just returns a \c ConstMap class.
+ /// \relates ConstMap
+ template<typename K, typename V>
+ inline ConstMap<K, V> constMap(const V &v) {
+ return ConstMap<K, V>(v);
+ }
+
+ template<typename K, typename V>
+ inline ConstMap<K, V> constMap() {
+ return ConstMap<K, V>();
+ }
+
+
+ template<typename T, T v>
+ struct Const {};
+
+ /// Constant map with inlined constant value.
+
+ /// This \ref concepts::ReadMap "readable map" assigns a specified
+ /// value to each key.
+ ///
+ /// In other aspects it is equivalent to \c NullMap.
+ /// So it conforms to the \ref concepts::ReadWriteMap "ReadWriteMap"
+ /// concept, but it absorbs the data written to it.
+ ///
+ /// The simplest way of using this map is through the constMap()
+ /// function.
+ ///
+ /// \sa NullMap
+ /// \sa IdentityMap
+ template<typename K, typename V, V v>
+ class ConstMap<K, Const<V, v> > : public MapBase<K, V> {
+ public:
+ ///\e
+ typedef K Key;
+ ///\e
+ typedef V Value;
+
+ /// Constructor.
+ ConstMap() {}
+
+ /// Gives back the specified value.
+ Value operator[](const Key&) const { return v; }
+
+ /// Absorbs the value.
+ void set(const Key&, const Value&) {}
+ };
+
+ /// Returns a \c ConstMap class with inlined constant value
+
+ /// This function just returns a \c ConstMap class with inlined
+ /// constant value.
+ /// \relates ConstMap
+ template<typename K, typename V, V v>
+ inline ConstMap<K, Const<V, v> > constMap() {
+ return ConstMap<K, Const<V, v> >();
+ }
+
+
+ /// Identity map.
+
+ /// This \ref concepts::ReadMap "read-only map" gives back the given
+ /// key as value without any modification.
+ ///
+ /// \sa ConstMap
+ template <typename T>
+ class IdentityMap : public MapBase<T, T> {
+ public:
+ ///\e
+ typedef T Key;
+ ///\e
+ typedef T Value;
+
+ /// Gives back the given value without any modification.
+ Value operator[](const Key &k) const {
+ return k;
+ }
+ };
+
+ /// Returns an \c IdentityMap class
+
+ /// This function just returns an \c IdentityMap class.
+ /// \relates IdentityMap
+ template<typename T>
+ inline IdentityMap<T> identityMap() {
+ return IdentityMap<T>();
+ }
+
+
+ /// \brief Map for storing values for integer keys from the range
+ /// <tt>[0..size-1]</tt>.
+ ///
+ /// This map is essentially a wrapper for \c std::vector. It assigns
+ /// values to integer keys from the range <tt>[0..size-1]</tt>.
+ /// It can be used together with some data structures, e.g.
+ /// heap types and \c UnionFind, when the used items are small
+ /// integers. This map conforms to the \ref concepts::ReferenceMap
+ /// "ReferenceMap" concept.
+ ///
+ /// The simplest way of using this map is through the rangeMap()
+ /// function.
+ template <typename V>
+ class RangeMap : public MapBase<int, V> {
+ template <typename V1>
+ friend class RangeMap;
+ private:
+
+ typedef std::vector<V> Vector;
+ Vector _vector;
+
+ public:
+
+ /// Key type
+ typedef int Key;
+ /// Value type
+ typedef V Value;
+ /// Reference type
+ typedef typename Vector::reference Reference;
+ /// Const reference type
+ typedef typename Vector::const_reference ConstReference;
+
+ typedef True ReferenceMapTag;
+
+ public:
+
+ /// Constructor with specified default value.
+ RangeMap(int size = 0, const Value &value = Value())
+ : _vector(size, value) {}
+
+ /// Constructs the map from an appropriate \c std::vector.
+ template <typename V1>
+ RangeMap(const std::vector<V1>& vector)
+ : _vector(vector.begin(), vector.end()) {}
+
+ /// Constructs the map from another \c RangeMap.
+ template <typename V1>
+ RangeMap(const RangeMap<V1> &c)
+ : _vector(c._vector.begin(), c._vector.end()) {}
+
+ /// Returns the size of the map.
+ int size() {
+ return _vector.size();
+ }
+
+ /// Resizes the map.
+
+ /// Resizes the underlying \c std::vector container, so changes the
+ /// keyset of the map.
+ /// \param size The new size of the map. The new keyset will be the
+ /// range <tt>[0..size-1]</tt>.
+ /// \param value The default value to assign to the new keys.
+ void resize(int size, const Value &value = Value()) {
+ _vector.resize(size, value);
+ }
+
+ private:
+
+ RangeMap& operator=(const RangeMap&);
+
+ public:
+
+ ///\e
+ Reference operator[](const Key &k) {
+ return _vector[k];
+ }
+
+ ///\e
+ ConstReference operator[](const Key &k) const {
+ return _vector[k];
+ }
+
+ ///\e
+ void set(const Key &k, const Value &v) {
+ _vector[k] = v;
+ }
+ };
+
+ /// Returns a \c RangeMap class
+
+ /// This function just returns a \c RangeMap class.
+ /// \relates RangeMap
+ template<typename V>
+ inline RangeMap<V> rangeMap(int size = 0, const V &value = V()) {
+ return RangeMap<V>(size, value);
+ }
+
+ /// \brief Returns a \c RangeMap class created from an appropriate
+ /// \c std::vector
+
+ /// This function just returns a \c RangeMap class created from an
+ /// appropriate \c std::vector.
+ /// \relates RangeMap
+ template<typename V>
+ inline RangeMap<V> rangeMap(const std::vector<V> &vector) {
+ return RangeMap<V>(vector);
+ }
+
+
+ /// Map type based on \c std::map
+
+ /// This map is essentially a wrapper for \c std::map with addition
+ /// that you can specify a default value for the keys that are not
+ /// stored actually. This value can be different from the default
+ /// contructed value (i.e. \c %Value()).
+ /// This type conforms to the \ref concepts::ReferenceMap "ReferenceMap"
+ /// concept.
+ ///
+ /// This map is useful if a default value should be assigned to most of
+ /// the keys and different values should be assigned only to a few
+ /// keys (i.e. the map is "sparse").
+ /// The name of this type also refers to this important usage.
+ ///
+ /// Apart form that, this map can be used in many other cases since it
+ /// is based on \c std::map, which is a general associative container.
+ /// However, keep in mind that it is usually not as efficient as other
+ /// maps.
+ ///
+ /// The simplest way of using this map is through the sparseMap()
+ /// function.
+ template <typename K, typename V, typename Comp = std::less<K> >
+ class SparseMap : public MapBase<K, V> {
+ template <typename K1, typename V1, typename C1>
+ friend class SparseMap;
+ public:
+
+ /// Key type
+ typedef K Key;
+ /// Value type
+ typedef V Value;
+ /// Reference type
+ typedef Value& Reference;
+ /// Const reference type
+ typedef const Value& ConstReference;
+
+ typedef True ReferenceMapTag;
+
+ private:
+
+ typedef std::map<K, V, Comp> Map;
+ Map _map;
+ Value _value;
+
+ public:
+
+ /// \brief Constructor with specified default value.
+ SparseMap(const Value &value = Value()) : _value(value) {}
+ /// \brief Constructs the map from an appropriate \c std::map, and
+ /// explicitly specifies a default value.
+ template <typename V1, typename Comp1>
+ SparseMap(const std::map<Key, V1, Comp1> &map,
+ const Value &value = Value())
+ : _map(map.begin(), map.end()), _value(value) {}
+
+ /// \brief Constructs the map from another \c SparseMap.
+ template<typename V1, typename Comp1>
+ SparseMap(const SparseMap<Key, V1, Comp1> &c)
+ : _map(c._map.begin(), c._map.end()), _value(c._value) {}
+
+ private:
+
+ SparseMap& operator=(const SparseMap&);
+
+ public:
+
+ ///\e
+ Reference operator[](const Key &k) {
+ typename Map::iterator it = _map.lower_bound(k);
+ if (it != _map.end() && !_map.key_comp()(k, it->first))
+ return it->second;
+ else
+ return _map.insert(it, std::make_pair(k, _value))->second;
+ }
+
+ ///\e
+ ConstReference operator[](const Key &k) const {
+ typename Map::const_iterator it = _map.find(k);
+ if (it != _map.end())
+ return it->second;
+ else
+ return _value;
+ }
+
+ ///\e
+ void set(const Key &k, const Value &v) {
+ typename Map::iterator it = _map.lower_bound(k);
+ if (it != _map.end() && !_map.key_comp()(k, it->first))
+ it->second = v;
+ else
+ _map.insert(it, std::make_pair(k, v));
+ }
+
+ ///\e
+ void setAll(const Value &v) {
+ _value = v;
+ _map.clear();
+ }
+ };
+
+ /// Returns a \c SparseMap class
+
+ /// This function just returns a \c SparseMap class with specified
+ /// default value.
+ /// \relates SparseMap
+ template<typename K, typename V, typename Compare>
+ inline SparseMap<K, V, Compare> sparseMap(const V& value = V()) {
+ return SparseMap<K, V, Compare>(value);
+ }
+
+ template<typename K, typename V>
+ inline SparseMap<K, V, std::less<K> > sparseMap(const V& value = V()) {
+ return SparseMap<K, V, std::less<K> >(value);
+ }
+
+ /// \brief Returns a \c SparseMap class created from an appropriate
+ /// \c std::map
+
+ /// This function just returns a \c SparseMap class created from an
+ /// appropriate \c std::map.
+ /// \relates SparseMap
+ template<typename K, typename V, typename Compare>
+ inline SparseMap<K, V, Compare>
+ sparseMap(const std::map<K, V, Compare> &map, const V& value = V())
+ {
+ return SparseMap<K, V, Compare>(map, value);
+ }
+
+ /// @}
+
+ /// \addtogroup map_adaptors
+ /// @{
+
+ /// Composition of two maps
+
+ /// This \ref concepts::ReadMap "read-only map" returns the
+ /// composition of two given maps. That is to say, if \c m1 is of
+ /// type \c M1 and \c m2 is of \c M2, then for
+ /// \code
+ /// ComposeMap<M1, M2> cm(m1,m2);
+ /// \endcode
+ /// <tt>cm[x]</tt> will be equal to <tt>m1[m2[x]]</tt>.
+ ///
+ /// The \c Key type of the map is inherited from \c M2 and the
+ /// \c Value type is from \c M1.
+ /// \c M2::Value must be convertible to \c M1::Key.
+ ///
+ /// The simplest way of using this map is through the composeMap()
+ /// function.
+ ///
+ /// \sa CombineMap
+ template <typename M1, typename M2>
+ class ComposeMap : public MapBase<typename M2::Key, typename M1::Value> {
+ const M1 &_m1;
+ const M2 &_m2;
+ public:
+ ///\e
+ typedef typename M2::Key Key;
+ ///\e
+ typedef typename M1::Value Value;
+
+ /// Constructor
+ ComposeMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {}
+
+ ///\e
+ typename MapTraits<M1>::ConstReturnValue
+ operator[](const Key &k) const { return _m1[_m2[k]]; }
+ };
+
+ /// Returns a \c ComposeMap class
+
+ /// This function just returns a \c ComposeMap class.
+ ///
+ /// If \c m1 and \c m2 are maps and the \c Value type of \c m2 is
+ /// convertible to the \c Key of \c m1, then <tt>composeMap(m1,m2)[x]</tt>
+ /// will be equal to <tt>m1[m2[x]]</tt>.
+ ///
+ /// \relates ComposeMap
+ template <typename M1, typename M2>
+ inline ComposeMap<M1, M2> composeMap(const M1 &m1, const M2 &m2) {
+ return ComposeMap<M1, M2>(m1, m2);
+ }
+
+
+ /// Combination of two maps using an STL (binary) functor.
+
+ /// This \ref concepts::ReadMap "read-only map" takes two maps and a
+ /// binary functor and returns the combination of the two given maps
+ /// using the functor.
+ /// That is to say, if \c m1 is of type \c M1 and \c m2 is of \c M2
+ /// and \c f is of \c F, then for
+ /// \code
+ /// CombineMap<M1,M2,F,V> cm(m1,m2,f);
+ /// \endcode
+ /// <tt>cm[x]</tt> will be equal to <tt>f(m1[x],m2[x])</tt>.
+ ///
+ /// The \c Key type of the map is inherited from \c M1 (\c M1::Key
+ /// must be convertible to \c M2::Key) and the \c Value type is \c V.
+ /// \c M2::Value and \c M1::Value must be convertible to the
+ /// corresponding input parameter of \c F and the return type of \c F
+ /// must be convertible to \c V.
+ ///
+ /// The simplest way of using this map is through the combineMap()
+ /// function.
+ ///
+ /// \sa ComposeMap
+ template<typename M1, typename M2, typename F,
+ typename V = typename F::result_type>
+ class CombineMap : public MapBase<typename M1::Key, V> {
+ const M1 &_m1;
+ const M2 &_m2;
+ F _f;
+ public:
+ ///\e
+ typedef typename M1::Key Key;
+ ///\e
+ typedef V Value;
+
+ /// Constructor
+ CombineMap(const M1 &m1, const M2 &m2, const F &f = F())
+ : _m1(m1), _m2(m2), _f(f) {}
+ ///\e
+ Value operator[](const Key &k) const { return _f(_m1[k],_m2[k]); }
+ };
+
+ /// Returns a \c CombineMap class
+
+ /// This function just returns a \c CombineMap class.
+ ///
+ /// For example, if \c m1 and \c m2 are both maps with \c double
+ /// values, then
+ /// \code
+ /// combineMap(m1,m2,std::plus<double>())
+ /// \endcode
+ /// is equivalent to
+ /// \code
+ /// addMap(m1,m2)
+ /// \endcode
+ ///
+ /// This function is specialized for adaptable binary function
+ /// classes and C++ functions.
+ ///
+ /// \relates CombineMap
+ template<typename M1, typename M2, typename F, typename V>
+ inline CombineMap<M1, M2, F, V>
+ combineMap(const M1 &m1, const M2 &m2, const F &f) {
+ return CombineMap<M1, M2, F, V>(m1,m2,f);
+ }
+
+ template<typename M1, typename M2, typename F>
+ inline CombineMap<M1, M2, F, typename F::result_type>
+ combineMap(const M1 &m1, const M2 &m2, const F &f) {
+ return combineMap<M1, M2, F, typename F::result_type>(m1,m2,f);
+ }
+
+ template<typename M1, typename M2, typename K1, typename K2, typename V>
+ inline CombineMap<M1, M2, V (*)(K1, K2), V>
+ combineMap(const M1 &m1, const M2 &m2, V (*f)(K1, K2)) {
+ return combineMap<M1, M2, V (*)(K1, K2), V>(m1,m2,f);
+ }
+
+
+ /// Converts an STL style (unary) functor to a map
+
+ /// This \ref concepts::ReadMap "read-only map" returns the value
+ /// of a given functor. Actually, it just wraps the functor and
+ /// provides the \c Key and \c Value typedefs.
+ ///
+ /// Template parameters \c K and \c V will become its \c Key and
+ /// \c Value. In most cases they have to be given explicitly because
+ /// a functor typically does not provide \c argument_type and
+ /// \c result_type typedefs.
+ /// Parameter \c F is the type of the used functor.
+ ///
+ /// The simplest way of using this map is through the functorToMap()
+ /// function.
+ ///
+ /// \sa MapToFunctor
+ template<typename F,
+ typename K = typename F::argument_type,
+ typename V = typename F::result_type>
+ class FunctorToMap : public MapBase<K, V> {
+ F _f;
+ public:
+ ///\e
+ typedef K Key;
+ ///\e
+ typedef V Value;
+
+ /// Constructor
+ FunctorToMap(const F &f = F()) : _f(f) {}
+ ///\e
+ Value operator[](const Key &k) const { return _f(k); }
+ };
+
+ /// Returns a \c FunctorToMap class
+
+ /// This function just returns a \c FunctorToMap class.
+ ///
+ /// This function is specialized for adaptable binary function
+ /// classes and C++ functions.
+ ///
+ /// \relates FunctorToMap
+ template<typename K, typename V, typename F>
+ inline FunctorToMap<F, K, V> functorToMap(const F &f) {
+ return FunctorToMap<F, K, V>(f);
+ }
+
+ template <typename F>
+ inline FunctorToMap<F, typename F::argument_type, typename F::result_type>
+ functorToMap(const F &f)
+ {
+ return FunctorToMap<F, typename F::argument_type,
+ typename F::result_type>(f);
+ }
+
+ template <typename K, typename V>
+ inline FunctorToMap<V (*)(K), K, V> functorToMap(V (*f)(K)) {
+ return FunctorToMap<V (*)(K), K, V>(f);
+ }
+
+
+ /// Converts a map to an STL style (unary) functor
+
+ /// This class converts a map to an STL style (unary) functor.
+ /// That is it provides an <tt>operator()</tt> to read its values.
+ ///
+ /// For the sake of convenience it also works as a usual
+ /// \ref concepts::ReadMap "readable map", i.e. <tt>operator[]</tt>
+ /// and the \c Key and \c Value typedefs also exist.
+ ///
+ /// The simplest way of using this map is through the mapToFunctor()
+ /// function.
+ ///
+ ///\sa FunctorToMap
+ template <typename M>
+ class MapToFunctor : public MapBase<typename M::Key, typename M::Value> {
+ const M &_m;
+ public:
+ ///\e
+ typedef typename M::Key Key;
+ ///\e
+ typedef typename M::Value Value;
+
+ typedef typename M::Key argument_type;
+ typedef typename M::Value result_type;
+
+ /// Constructor
+ MapToFunctor(const M &m) : _m(m) {}
+ ///\e
+ Value operator()(const Key &k) const { return _m[k]; }
+ ///\e
+ Value operator[](const Key &k) const { return _m[k]; }
+ };
+
+ /// Returns a \c MapToFunctor class
+
+ /// This function just returns a \c MapToFunctor class.
+ /// \relates MapToFunctor
+ template<typename M>
+ inline MapToFunctor<M> mapToFunctor(const M &m) {
+ return MapToFunctor<M>(m);
+ }
+
+
+ /// \brief Map adaptor to convert the \c Value type of a map to
+ /// another type using the default conversion.
+
+ /// Map adaptor to convert the \c Value type of a \ref concepts::ReadMap
+ /// "readable map" to another type using the default conversion.
+ /// The \c Key type of it is inherited from \c M and the \c Value
+ /// type is \c V.
+ /// This type conforms to the \ref concepts::ReadMap "ReadMap" concept.
+ ///
+ /// The simplest way of using this map is through the convertMap()
+ /// function.
+ template <typename M, typename V>
+ class ConvertMap : public MapBase<typename M::Key, V> {
+ const M &_m;
+ public:
+ ///\e
+ typedef typename M::Key Key;
+ ///\e
+ typedef V Value;
+
+ /// Constructor
+
+ /// Constructor.
+ /// \param m The underlying map.
+ ConvertMap(const M &m) : _m(m) {}
+
+ ///\e
+ Value operator[](const Key &k) const { return _m[k]; }
+ };
+
+ /// Returns a \c ConvertMap class
+
+ /// This function just returns a \c ConvertMap class.
+ /// \relates ConvertMap
+ template<typename V, typename M>
+ inline ConvertMap<M, V> convertMap(const M &map) {
+ return ConvertMap<M, V>(map);
+ }
+
+
+ /// Applies all map setting operations to two maps
+
+ /// This map has two \ref concepts::WriteMap "writable map" parameters
+ /// and each write request will be passed to both of them.
+ /// If \c M1 is also \ref concepts::ReadMap "readable", then the read
+ /// operations will return the corresponding values of \c M1.
+ ///
+ /// The \c Key and \c Value types are inherited from \c M1.
+ /// The \c Key and \c Value of \c M2 must be convertible from those
+ /// of \c M1.
+ ///
+ /// The simplest way of using this map is through the forkMap()
+ /// function.
+ template<typename M1, typename M2>
+ class ForkMap : public MapBase<typename M1::Key, typename M1::Value> {
+ M1 &_m1;
+ M2 &_m2;
+ public:
+ ///\e
+ typedef typename M1::Key Key;
+ ///\e
+ typedef typename M1::Value Value;
+
+ /// Constructor
+ ForkMap(M1 &m1, M2 &m2) : _m1(m1), _m2(m2) {}
+ /// Returns the value associated with the given key in the first map.
+ Value operator[](const Key &k) const { return _m1[k]; }
+ /// Sets the value associated with the given key in both maps.
+ void set(const Key &k, const Value &v) { _m1.set(k,v); _m2.set(k,v); }
+ };
+
+ /// Returns a \c ForkMap class
+
+ /// This function just returns a \c ForkMap class.
+ /// \relates ForkMap
+ template <typename M1, typename M2>
+ inline ForkMap<M1,M2> forkMap(M1 &m1, M2 &m2) {
+ return ForkMap<M1,M2>(m1,m2);
+ }
+
+
+ /// Sum of two maps
+
+ /// This \ref concepts::ReadMap "read-only map" returns the sum
+ /// of the values of the two given maps.
+ /// Its \c Key and \c Value types are inherited from \c M1.
+ /// The \c Key and \c Value of \c M2 must be convertible to those of
+ /// \c M1.
+ ///
+ /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for
+ /// \code
+ /// AddMap<M1,M2> am(m1,m2);
+ /// \endcode
+ /// <tt>am[x]</tt> will be equal to <tt>m1[x]+m2[x]</tt>.
+ ///
+ /// The simplest way of using this map is through the addMap()
+ /// function.
+ ///
+ /// \sa SubMap, MulMap, DivMap
+ /// \sa ShiftMap, ShiftWriteMap
+ template<typename M1, typename M2>
+ class AddMap : public MapBase<typename M1::Key, typename M1::Value> {
+ const M1 &_m1;
+ const M2 &_m2;
+ public:
+ ///\e
+ typedef typename M1::Key Key;
+ ///\e
+ typedef typename M1::Value Value;
+
+ /// Constructor
+ AddMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {}
+ ///\e
+ Value operator[](const Key &k) const { return _m1[k]+_m2[k]; }
+ };
+
+ /// Returns an \c AddMap class
+
+ /// This function just returns an \c AddMap class.
+ ///
+ /// For example, if \c m1 and \c m2 are both maps with \c double
+ /// values, then <tt>addMap(m1,m2)[x]</tt> will be equal to
+ /// <tt>m1[x]+m2[x]</tt>.
+ ///
+ /// \relates AddMap
+ template<typename M1, typename M2>
+ inline AddMap<M1, M2> addMap(const M1 &m1, const M2 &m2) {
+ return AddMap<M1, M2>(m1,m2);
+ }
+
+
+ /// Difference of two maps
+
+ /// This \ref concepts::ReadMap "read-only map" returns the difference
+ /// of the values of the two given maps.
+ /// Its \c Key and \c Value types are inherited from \c M1.
+ /// The \c Key and \c Value of \c M2 must be convertible to those of
+ /// \c M1.
+ ///
+ /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for
+ /// \code
+ /// SubMap<M1,M2> sm(m1,m2);
+ /// \endcode
+ /// <tt>sm[x]</tt> will be equal to <tt>m1[x]-m2[x]</tt>.
+ ///
+ /// The simplest way of using this map is through the subMap()
+ /// function.
+ ///
+ /// \sa AddMap, MulMap, DivMap
+ template<typename M1, typename M2>
+ class SubMap : public MapBase<typename M1::Key, typename M1::Value> {
+ const M1 &_m1;
+ const M2 &_m2;
+ public:
+ ///\e
+ typedef typename M1::Key Key;
+ ///\e
+ typedef typename M1::Value Value;
+
+ /// Constructor
+ SubMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {}
+ ///\e
+ Value operator[](const Key &k) const { return _m1[k]-_m2[k]; }
+ };
+
+ /// Returns a \c SubMap class
+
+ /// This function just returns a \c SubMap class.
+ ///
+ /// For example, if \c m1 and \c m2 are both maps with \c double
+ /// values, then <tt>subMap(m1,m2)[x]</tt> will be equal to
+ /// <tt>m1[x]-m2[x]</tt>.
+ ///
+ /// \relates SubMap
+ template<typename M1, typename M2>
+ inline SubMap<M1, M2> subMap(const M1 &m1, const M2 &m2) {
+ return SubMap<M1, M2>(m1,m2);
+ }
+
+
+ /// Product of two maps
+
+ /// This \ref concepts::ReadMap "read-only map" returns the product
+ /// of the values of the two given maps.
+ /// Its \c Key and \c Value types are inherited from \c M1.
+ /// The \c Key and \c Value of \c M2 must be convertible to those of
+ /// \c M1.
+ ///
+ /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for
+ /// \code
+ /// MulMap<M1,M2> mm(m1,m2);
+ /// \endcode
+ /// <tt>mm[x]</tt> will be equal to <tt>m1[x]*m2[x]</tt>.
+ ///
+ /// The simplest way of using this map is through the mulMap()
+ /// function.
+ ///
+ /// \sa AddMap, SubMap, DivMap
+ /// \sa ScaleMap, ScaleWriteMap
+ template<typename M1, typename M2>
+ class MulMap : public MapBase<typename M1::Key, typename M1::Value> {
+ const M1 &_m1;
+ const M2 &_m2;
+ public:
+ ///\e
+ typedef typename M1::Key Key;
+ ///\e
+ typedef typename M1::Value Value;
+
+ /// Constructor
+ MulMap(const M1 &m1,const M2 &m2) : _m1(m1), _m2(m2) {}
+ ///\e
+ Value operator[](const Key &k) const { return _m1[k]*_m2[k]; }
+ };
+
+ /// Returns a \c MulMap class
+
+ /// This function just returns a \c MulMap class.
+ ///
+ /// For example, if \c m1 and \c m2 are both maps with \c double
+ /// values, then <tt>mulMap(m1,m2)[x]</tt> will be equal to
+ /// <tt>m1[x]*m2[x]</tt>.
+ ///
+ /// \relates MulMap
+ template<typename M1, typename M2>
+ inline MulMap<M1, M2> mulMap(const M1 &m1,const M2 &m2) {
+ return MulMap<M1, M2>(m1,m2);
+ }
+
+
+ /// Quotient of two maps
+
+ /// This \ref concepts::ReadMap "read-only map" returns the quotient
+ /// of the values of the two given maps.
+ /// Its \c Key and \c Value types are inherited from \c M1.
+ /// The \c Key and \c Value of \c M2 must be convertible to those of
+ /// \c M1.
+ ///
+ /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for
+ /// \code
+ /// DivMap<M1,M2> dm(m1,m2);
+ /// \endcode
+ /// <tt>dm[x]</tt> will be equal to <tt>m1[x]/m2[x]</tt>.
+ ///
+ /// The simplest way of using this map is through the divMap()
+ /// function.
+ ///
+ /// \sa AddMap, SubMap, MulMap
+ template<typename M1, typename M2>
+ class DivMap : public MapBase<typename M1::Key, typename M1::Value> {
+ const M1 &_m1;
+ const M2 &_m2;
+ public:
+ ///\e
+ typedef typename M1::Key Key;
+ ///\e
+ typedef typename M1::Value Value;
+
+ /// Constructor
+ DivMap(const M1 &m1,const M2 &m2) : _m1(m1), _m2(m2) {}
+ ///\e
+ Value operator[](const Key &k) const { return _m1[k]/_m2[k]; }
+ };
+
+ /// Returns a \c DivMap class
+
+ /// This function just returns a \c DivMap class.
+ ///
+ /// For example, if \c m1 and \c m2 are both maps with \c double
+ /// values, then <tt>divMap(m1,m2)[x]</tt> will be equal to
+ /// <tt>m1[x]/m2[x]</tt>.
+ ///
+ /// \relates DivMap
+ template<typename M1, typename M2>
+ inline DivMap<M1, M2> divMap(const M1 &m1,const M2 &m2) {
+ return DivMap<M1, M2>(m1,m2);
+ }
+
+
+ /// Shifts a map with a constant.
+
+ /// This \ref concepts::ReadMap "read-only map" returns the sum of
+ /// the given map and a constant value (i.e. it shifts the map with
+ /// the constant). Its \c Key and \c Value are inherited from \c M.
+ ///
+ /// Actually,
+ /// \code
+ /// ShiftMap<M> sh(m,v);
+ /// \endcode
+ /// is equivalent to
+ /// \code
+ /// ConstMap<M::Key, M::Value> cm(v);
+ /// AddMap<M, ConstMap<M::Key, M::Value> > sh(m,cm);
+ /// \endcode
+ ///
+ /// The simplest way of using this map is through the shiftMap()
+ /// function.
+ ///
+ /// \sa ShiftWriteMap
+ template<typename M, typename C = typename M::Value>
+ class ShiftMap : public MapBase<typename M::Key, typename M::Value> {
+ const M &_m;
+ C _v;
+ public:
+ ///\e
+ typedef typename M::Key Key;
+ ///\e
+ typedef typename M::Value Value;
+
+ /// Constructor
+
+ /// Constructor.
+ /// \param m The undelying map.
+ /// \param v The constant value.
+ ShiftMap(const M &m, const C &v) : _m(m), _v(v) {}
+ ///\e
+ Value operator[](const Key &k) const { return _m[k]+_v; }
+ };
+
+ /// Shifts a map with a constant (read-write version).
+
+ /// This \ref concepts::ReadWriteMap "read-write map" returns the sum
+ /// of the given map and a constant value (i.e. it shifts the map with
+ /// the constant). Its \c Key and \c Value are inherited from \c M.
+ /// It makes also possible to write the map.
+ ///
+ /// The simplest way of using this map is through the shiftWriteMap()
+ /// function.
+ ///
+ /// \sa ShiftMap
+ template<typename M, typename C = typename M::Value>
+ class ShiftWriteMap : public MapBase<typename M::Key, typename M::Value> {
+ M &_m;
+ C _v;
+ public:
+ ///\e
+ typedef typename M::Key Key;
+ ///\e
+ typedef typename M::Value Value;
+
+ /// Constructor
+
+ /// Constructor.
+ /// \param m The undelying map.
+ /// \param v The constant value.
+ ShiftWriteMap(M &m, const C &v) : _m(m), _v(v) {}
+ ///\e
+ Value operator[](const Key &k) const { return _m[k]+_v; }
+ ///\e
+ void set(const Key &k, const Value &v) { _m.set(k, v-_v); }
+ };
+
+ /// Returns a \c ShiftMap class
+
+ /// This function just returns a \c ShiftMap class.
+ ///
+ /// For example, if \c m is a map with \c double values and \c v is
+ /// \c double, then <tt>shiftMap(m,v)[x]</tt> will be equal to
+ /// <tt>m[x]+v</tt>.
+ ///
+ /// \relates ShiftMap
+ template<typename M, typename C>
+ inline ShiftMap<M, C> shiftMap(const M &m, const C &v) {
+ return ShiftMap<M, C>(m,v);
+ }
+
+ /// Returns a \c ShiftWriteMap class
+
+ /// This function just returns a \c ShiftWriteMap class.
+ ///
+ /// For example, if \c m is a map with \c double values and \c v is
+ /// \c double, then <tt>shiftWriteMap(m,v)[x]</tt> will be equal to
+ /// <tt>m[x]+v</tt>.
+ /// Moreover it makes also possible to write the map.
+ ///
+ /// \relates ShiftWriteMap
+ template<typename M, typename C>
+ inline ShiftWriteMap<M, C> shiftWriteMap(M &m, const C &v) {
+ return ShiftWriteMap<M, C>(m,v);
+ }
+
+
+ /// Scales a map with a constant.
+
+ /// This \ref concepts::ReadMap "read-only map" returns the value of
+ /// the given map multiplied from the left side with a constant value.
+ /// Its \c Key and \c Value are inherited from \c M.
+ ///
+ /// Actually,
+ /// \code
+ /// ScaleMap<M> sc(m,v);
+ /// \endcode
+ /// is equivalent to
+ /// \code
+ /// ConstMap<M::Key, M::Value> cm(v);
+ /// MulMap<ConstMap<M::Key, M::Value>, M> sc(cm,m);
+ /// \endcode
+ ///
+ /// The simplest way of using this map is through the scaleMap()
+ /// function.
+ ///
+ /// \sa ScaleWriteMap
+ template<typename M, typename C = typename M::Value>
+ class ScaleMap : public MapBase<typename M::Key, typename M::Value> {
+ const M &_m;
+ C _v;
+ public:
+ ///\e
+ typedef typename M::Key Key;
+ ///\e
+ typedef typename M::Value Value;
+
+ /// Constructor
+
+ /// Constructor.
+ /// \param m The undelying map.
+ /// \param v The constant value.
+ ScaleMap(const M &m, const C &v) : _m(m), _v(v) {}
+ ///\e
+ Value operator[](const Key &k) const { return _v*_m[k]; }
+ };
+
+ /// Scales a map with a constant (read-write version).
+
+ /// This \ref concepts::ReadWriteMap "read-write map" returns the value of
+ /// the given map multiplied from the left side with a constant value.
+ /// Its \c Key and \c Value are inherited from \c M.
+ /// It can also be used as write map if the \c / operator is defined
+ /// between \c Value and \c C and the given multiplier is not zero.
+ ///
+ /// The simplest way of using this map is through the scaleWriteMap()
+ /// function.
+ ///
+ /// \sa ScaleMap
+ template<typename M, typename C = typename M::Value>
+ class ScaleWriteMap : public MapBase<typename M::Key, typename M::Value> {
+ M &_m;
+ C _v;
+ public:
+ ///\e
+ typedef typename M::Key Key;
+ ///\e
+ typedef typename M::Value Value;
+
+ /// Constructor
+
+ /// Constructor.
+ /// \param m The undelying map.
+ /// \param v The constant value.
+ ScaleWriteMap(M &m, const C &v) : _m(m), _v(v) {}
+ ///\e
+ Value operator[](const Key &k) const { return _v*_m[k]; }
+ ///\e
+ void set(const Key &k, const Value &v) { _m.set(k, v/_v); }
+ };
+
+ /// Returns a \c ScaleMap class
+
+ /// This function just returns a \c ScaleMap class.
+ ///
+ /// For example, if \c m is a map with \c double values and \c v is
+ /// \c double, then <tt>scaleMap(m,v)[x]</tt> will be equal to
+ /// <tt>v*m[x]</tt>.
+ ///
+ /// \relates ScaleMap
+ template<typename M, typename C>
+ inline ScaleMap<M, C> scaleMap(const M &m, const C &v) {
+ return ScaleMap<M, C>(m,v);
+ }
+
+ /// Returns a \c ScaleWriteMap class
+
+ /// This function just returns a \c ScaleWriteMap class.
+ ///
+ /// For example, if \c m is a map with \c double values and \c v is
+ /// \c double, then <tt>scaleWriteMap(m,v)[x]</tt> will be equal to
+ /// <tt>v*m[x]</tt>.
+ /// Moreover it makes also possible to write the map.
+ ///
+ /// \relates ScaleWriteMap
+ template<typename M, typename C>
+ inline ScaleWriteMap<M, C> scaleWriteMap(M &m, const C &v) {
+ return ScaleWriteMap<M, C>(m,v);
+ }
+
+
+ /// Negative of a map
+
+ /// This \ref concepts::ReadMap "read-only map" returns the negative
+ /// of the values of the given map (using the unary \c - operator).
+ /// Its \c Key and \c Value are inherited from \c M.
+ ///
+ /// If M::Value is \c int, \c double etc., then
+ /// \code
+ /// NegMap<M> neg(m);
+ /// \endcode
+ /// is equivalent to
+ /// \code
+ /// ScaleMap<M> neg(m,-1);
+ /// \endcode
+ ///
+ /// The simplest way of using this map is through the negMap()
+ /// function.
+ ///
+ /// \sa NegWriteMap
+ template<typename M>
+ class NegMap : public MapBase<typename M::Key, typename M::Value> {
+ const M& _m;
+ public:
+ ///\e
+ typedef typename M::Key Key;
+ ///\e
+ typedef typename M::Value Value;
+
+ /// Constructor
+ NegMap(const M &m) : _m(m) {}
+ ///\e
+ Value operator[](const Key &k) const { return -_m[k]; }
+ };
+
+ /// Negative of a map (read-write version)
+
+ /// This \ref concepts::ReadWriteMap "read-write map" returns the
+ /// negative of the values of the given map (using the unary \c -
+ /// operator).
+ /// Its \c Key and \c Value are inherited from \c M.
+ /// It makes also possible to write the map.
+ ///
+ /// If M::Value is \c int, \c double etc., then
+ /// \code
+ /// NegWriteMap<M> neg(m);
+ /// \endcode
+ /// is equivalent to
+ /// \code
+ /// ScaleWriteMap<M> neg(m,-1);
+ /// \endcode
+ ///
+ /// The simplest way of using this map is through the negWriteMap()
+ /// function.
+ ///
+ /// \sa NegMap
+ template<typename M>
+ class NegWriteMap : public MapBase<typename M::Key, typename M::Value> {
+ M &_m;
+ public:
+ ///\e
+ typedef typename M::Key Key;
+ ///\e
+ typedef typename M::Value Value;
+
+ /// Constructor
+ NegWriteMap(M &m) : _m(m) {}
+ ///\e
+ Value operator[](const Key &k) const { return -_m[k]; }
+ ///\e
+ void set(const Key &k, const Value &v) { _m.set(k, -v); }
+ };
+
+ /// Returns a \c NegMap class
+
+ /// This function just returns a \c NegMap class.
+ ///
+ /// For example, if \c m is a map with \c double values, then
+ /// <tt>negMap(m)[x]</tt> will be equal to <tt>-m[x]</tt>.
+ ///
+ /// \relates NegMap
+ template <typename M>
+ inline NegMap<M> negMap(const M &m) {
+ return NegMap<M>(m);
+ }
+
+ /// Returns a \c NegWriteMap class
+
+ /// This function just returns a \c NegWriteMap class.
+ ///
+ /// For example, if \c m is a map with \c double values, then
+ /// <tt>negWriteMap(m)[x]</tt> will be equal to <tt>-m[x]</tt>.
+ /// Moreover it makes also possible to write the map.
+ ///
+ /// \relates NegWriteMap
+ template <typename M>
+ inline NegWriteMap<M> negWriteMap(M &m) {
+ return NegWriteMap<M>(m);
+ }
+
+
+ /// Absolute value of a map
+
+ /// This \ref concepts::ReadMap "read-only map" returns the absolute
+ /// value of the values of the given map.
+ /// Its \c Key and \c Value are inherited from \c M.
+ /// \c Value must be comparable to \c 0 and the unary \c -
+ /// operator must be defined for it, of course.
+ ///
+ /// The simplest way of using this map is through the absMap()
+ /// function.
+ template<typename M>
+ class AbsMap : public MapBase<typename M::Key, typename M::Value> {
+ const M &_m;
+ public:
+ ///\e
+ typedef typename M::Key Key;
+ ///\e
+ typedef typename M::Value Value;
+
+ /// Constructor
+ AbsMap(const M &m) : _m(m) {}
+ ///\e
+ Value operator[](const Key &k) const {
+ Value tmp = _m[k];
+ return tmp >= 0 ? tmp : -tmp;
+ }
+
+ };
+
+ /// Returns an \c AbsMap class
+
+ /// This function just returns an \c AbsMap class.
+ ///
+ /// For example, if \c m is a map with \c double values, then
+ /// <tt>absMap(m)[x]</tt> will be equal to <tt>m[x]</tt> if
+ /// it is positive or zero and <tt>-m[x]</tt> if <tt>m[x]</tt> is
+ /// negative.
+ ///
+ /// \relates AbsMap
+ template<typename M>
+ inline AbsMap<M> absMap(const M &m) {
+ return AbsMap<M>(m);
+ }
+
+ /// @}
+
+ // Logical maps and map adaptors:
+
+ /// \addtogroup maps
+ /// @{
+
+ /// Constant \c true map.
+
+ /// This \ref concepts::ReadMap "read-only map" assigns \c true to
+ /// each key.
+ ///
+ /// Note that
+ /// \code
+ /// TrueMap<K> tm;
+ /// \endcode
+ /// is equivalent to
+ /// \code
+ /// ConstMap<K,bool> tm(true);
+ /// \endcode
+ ///
+ /// \sa FalseMap
+ /// \sa ConstMap
+ template <typename K>
+ class TrueMap : public MapBase<K, bool> {
+ public:
+ ///\e
+ typedef K Key;
+ ///\e
+ typedef bool Value;
+
+ /// Gives back \c true.
+ Value operator[](const Key&) const { return true; }
+ };
+
+ /// Returns a \c TrueMap class
+
+ /// This function just returns a \c TrueMap class.
+ /// \relates TrueMap
+ template<typename K>
+ inline TrueMap<K> trueMap() {
+ return TrueMap<K>();
+ }
+
+
+ /// Constant \c false map.
+
+ /// This \ref concepts::ReadMap "read-only map" assigns \c false to
+ /// each key.
+ ///
+ /// Note that
+ /// \code
+ /// FalseMap<K> fm;
+ /// \endcode
+ /// is equivalent to
+ /// \code
+ /// ConstMap<K,bool> fm(false);
+ /// \endcode
+ ///
+ /// \sa TrueMap
+ /// \sa ConstMap
+ template <typename K>
+ class FalseMap : public MapBase<K, bool> {
+ public:
+ ///\e
+ typedef K Key;
+ ///\e
+ typedef bool Value;
+
+ /// Gives back \c false.
+ Value operator[](const Key&) const { return false; }
+ };
+
+ /// Returns a \c FalseMap class
+
+ /// This function just returns a \c FalseMap class.
+ /// \relates FalseMap
+ template<typename K>
+ inline FalseMap<K> falseMap() {
+ return FalseMap<K>();
+ }
+
+ /// @}
+
+ /// \addtogroup map_adaptors
+ /// @{
+
+ /// Logical 'and' of two maps
+
+ /// This \ref concepts::ReadMap "read-only map" returns the logical
+ /// 'and' of the values of the two given maps.
+ /// Its \c Key type is inherited from \c M1 and its \c Value type is
+ /// \c bool. \c M2::Key must be convertible to \c M1::Key.
+ ///
+ /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for
+ /// \code
+ /// AndMap<M1,M2> am(m1,m2);
+ /// \endcode
+ /// <tt>am[x]</tt> will be equal to <tt>m1[x]&&m2[x]</tt>.
+ ///
+ /// The simplest way of using this map is through the andMap()
+ /// function.
+ ///
+ /// \sa OrMap
+ /// \sa NotMap, NotWriteMap
+ template<typename M1, typename M2>
+ class AndMap : public MapBase<typename M1::Key, bool> {
+ const M1 &_m1;
+ const M2 &_m2;
+ public:
+ ///\e
+ typedef typename M1::Key Key;
+ ///\e
+ typedef bool Value;
+
+ /// Constructor
+ AndMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {}
+ ///\e
+ Value operator[](const Key &k) const { return _m1[k]&&_m2[k]; }
+ };
+
+ /// Returns an \c AndMap class
+
+ /// This function just returns an \c AndMap class.
+ ///
+ /// For example, if \c m1 and \c m2 are both maps with \c bool values,
+ /// then <tt>andMap(m1,m2)[x]</tt> will be equal to
+ /// <tt>m1[x]&&m2[x]</tt>.
+ ///
+ /// \relates AndMap
+ template<typename M1, typename M2>
+ inline AndMap<M1, M2> andMap(const M1 &m1, const M2 &m2) {
+ return AndMap<M1, M2>(m1,m2);
+ }
+
+
+ /// Logical 'or' of two maps
+
+ /// This \ref concepts::ReadMap "read-only map" returns the logical
+ /// 'or' of the values of the two given maps.
+ /// Its \c Key type is inherited from \c M1 and its \c Value type is
+ /// \c bool. \c M2::Key must be convertible to \c M1::Key.
+ ///
+ /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for
+ /// \code
+ /// OrMap<M1,M2> om(m1,m2);
+ /// \endcode
+ /// <tt>om[x]</tt> will be equal to <tt>m1[x]||m2[x]</tt>.
+ ///
+ /// The simplest way of using this map is through the orMap()
+ /// function.
+ ///
+ /// \sa AndMap
+ /// \sa NotMap, NotWriteMap
+ template<typename M1, typename M2>
+ class OrMap : public MapBase<typename M1::Key, bool> {
+ const M1 &_m1;
+ const M2 &_m2;
+ public:
+ ///\e
+ typedef typename M1::Key Key;
+ ///\e
+ typedef bool Value;
+
+ /// Constructor
+ OrMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {}
+ ///\e
+ Value operator[](const Key &k) const { return _m1[k]||_m2[k]; }
+ };
+
+ /// Returns an \c OrMap class
+
+ /// This function just returns an \c OrMap class.
+ ///
+ /// For example, if \c m1 and \c m2 are both maps with \c bool values,
+ /// then <tt>orMap(m1,m2)[x]</tt> will be equal to
+ /// <tt>m1[x]||m2[x]</tt>.
+ ///
+ /// \relates OrMap
+ template<typename M1, typename M2>
+ inline OrMap<M1, M2> orMap(const M1 &m1, const M2 &m2) {
+ return OrMap<M1, M2>(m1,m2);
+ }
+
+
+ /// Logical 'not' of a map
+
+ /// This \ref concepts::ReadMap "read-only map" returns the logical
+ /// negation of the values of the given map.
+ /// Its \c Key is inherited from \c M and its \c Value is \c bool.
+ ///
+ /// The simplest way of using this map is through the notMap()
+ /// function.
+ ///
+ /// \sa NotWriteMap
+ template <typename M>
+ class NotMap : public MapBase<typename M::Key, bool> {
+ const M &_m;
+ public:
+ ///\e
+ typedef typename M::Key Key;
+ ///\e
+ typedef bool Value;
+
+ /// Constructor
+ NotMap(const M &m) : _m(m) {}
+ ///\e
+ Value operator[](const Key &k) const { return !_m[k]; }
+ };
+
+ /// Logical 'not' of a map (read-write version)
+
+ /// This \ref concepts::ReadWriteMap "read-write map" returns the
+ /// logical negation of the values of the given map.
+ /// Its \c Key is inherited from \c M and its \c Value is \c bool.
+ /// It makes also possible to write the map. When a value is set,
+ /// the opposite value is set to the original map.
+ ///
+ /// The simplest way of using this map is through the notWriteMap()
+ /// function.
+ ///
+ /// \sa NotMap
+ template <typename M>
+ class NotWriteMap : public MapBase<typename M::Key, bool> {
+ M &_m;
+ public:
+ ///\e
+ typedef typename M::Key Key;
+ ///\e
+ typedef bool Value;
+
+ /// Constructor
+ NotWriteMap(M &m) : _m(m) {}
+ ///\e
+ Value operator[](const Key &k) const { return !_m[k]; }
+ ///\e
+ void set(const Key &k, bool v) { _m.set(k, !v); }
+ };
+
+ /// Returns a \c NotMap class
+
+ /// This function just returns a \c NotMap class.
+ ///
+ /// For example, if \c m is a map with \c bool values, then
+ /// <tt>notMap(m)[x]</tt> will be equal to <tt>!m[x]</tt>.
+ ///
+ /// \relates NotMap
+ template <typename M>
+ inline NotMap<M> notMap(const M &m) {
+ return NotMap<M>(m);
+ }
+
+ /// Returns a \c NotWriteMap class
+
+ /// This function just returns a \c NotWriteMap class.
+ ///
+ /// For example, if \c m is a map with \c bool values, then
+ /// <tt>notWriteMap(m)[x]</tt> will be equal to <tt>!m[x]</tt>.
+ /// Moreover it makes also possible to write the map.
+ ///
+ /// \relates NotWriteMap
+ template <typename M>
+ inline NotWriteMap<M> notWriteMap(M &m) {
+ return NotWriteMap<M>(m);
+ }
+
+
+ /// Combination of two maps using the \c == operator
+
+ /// This \ref concepts::ReadMap "read-only map" assigns \c true to
+ /// the keys for which the corresponding values of the two maps are
+ /// equal.
+ /// Its \c Key type is inherited from \c M1 and its \c Value type is
+ /// \c bool. \c M2::Key must be convertible to \c M1::Key.
+ ///
+ /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for
+ /// \code
+ /// EqualMap<M1,M2> em(m1,m2);
+ /// \endcode
+ /// <tt>em[x]</tt> will be equal to <tt>m1[x]==m2[x]</tt>.
+ ///
+ /// The simplest way of using this map is through the equalMap()
+ /// function.
+ ///
+ /// \sa LessMap
+ template<typename M1, typename M2>
+ class EqualMap : public MapBase<typename M1::Key, bool> {
+ const M1 &_m1;
+ const M2 &_m2;
+ public:
+ ///\e
+ typedef typename M1::Key Key;
+ ///\e
+ typedef bool Value;
+
+ /// Constructor
+ EqualMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {}
+ ///\e
+ Value operator[](const Key &k) const { return _m1[k]==_m2[k]; }
+ };
+
+ /// Returns an \c EqualMap class
+
+ /// This function just returns an \c EqualMap class.
+ ///
+ /// For example, if \c m1 and \c m2 are maps with keys and values of
+ /// the same type, then <tt>equalMap(m1,m2)[x]</tt> will be equal to
+ /// <tt>m1[x]==m2[x]</tt>.
+ ///
+ /// \relates EqualMap
+ template<typename M1, typename M2>
+ inline EqualMap<M1, M2> equalMap(const M1 &m1, const M2 &m2) {
+ return EqualMap<M1, M2>(m1,m2);
+ }
+
+
+ /// Combination of two maps using the \c < operator
+
+ /// This \ref concepts::ReadMap "read-only map" assigns \c true to
+ /// the keys for which the corresponding value of the first map is
+ /// less then the value of the second map.
+ /// Its \c Key type is inherited from \c M1 and its \c Value type is
+ /// \c bool. \c M2::Key must be convertible to \c M1::Key.
+ ///
+ /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for
+ /// \code
+ /// LessMap<M1,M2> lm(m1,m2);
+ /// \endcode
+ /// <tt>lm[x]</tt> will be equal to <tt>m1[x]<m2[x]</tt>.
+ ///
+ /// The simplest way of using this map is through the lessMap()
+ /// function.
+ ///
+ /// \sa EqualMap
+ template<typename M1, typename M2>
+ class LessMap : public MapBase<typename M1::Key, bool> {
+ const M1 &_m1;
+ const M2 &_m2;
+ public:
+ ///\e
+ typedef typename M1::Key Key;
+ ///\e
+ typedef bool Value;
+
+ /// Constructor
+ LessMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {}
+ ///\e
+ Value operator[](const Key &k) const { return _m1[k]<_m2[k]; }
+ };
+
+ /// Returns an \c LessMap class
+
+ /// This function just returns an \c LessMap class.
+ ///
+ /// For example, if \c m1 and \c m2 are maps with keys and values of
+ /// the same type, then <tt>lessMap(m1,m2)[x]</tt> will be equal to
+ /// <tt>m1[x]<m2[x]</tt>.
+ ///
+ /// \relates LessMap
+ template<typename M1, typename M2>
+ inline LessMap<M1, M2> lessMap(const M1 &m1, const M2 &m2) {
+ return LessMap<M1, M2>(m1,m2);
+ }
+
+ namespace _maps_bits {
+
+ template <typename _Iterator, typename Enable = void>
+ struct IteratorTraits {
+ typedef typename std::iterator_traits<_Iterator>::value_type Value;
+ };
+
+ template <typename _Iterator>
+ struct IteratorTraits<_Iterator,
+ typename exists<typename _Iterator::container_type>::type>
+ {
+ typedef typename _Iterator::container_type::value_type Value;
+ };
+
+ }
+
+ /// @}
+
+ /// \addtogroup maps
+ /// @{
+
+ /// \brief Writable bool map for logging each \c true assigned element
+ ///
+ /// A \ref concepts::WriteMap "writable" bool map for logging
+ /// each \c true assigned element, i.e it copies subsequently each
+ /// keys set to \c true to the given iterator.
+ /// The most important usage of it is storing certain nodes or arcs
+ /// that were marked \c true by an algorithm.
+ ///
+ /// There are several algorithms that provide solutions through bool
+ /// maps and most of them assign \c true at most once for each key.
+ /// In these cases it is a natural request to store each \c true
+ /// assigned elements (in order of the assignment), which can be
+ /// easily done with LoggerBoolMap.
+ ///
+ /// The simplest way of using this map is through the loggerBoolMap()
+ /// function.
+ ///
+ /// \tparam IT The type of the iterator.
+ /// \tparam KEY The key type of the map. The default value set
+ /// according to the iterator type should work in most cases.
+ ///
+ /// \note The container of the iterator must contain enough space
+ /// for the elements or the iterator should be an inserter iterator.
+#ifdef DOXYGEN
+ template <typename IT, typename KEY>
+#else
+ template <typename IT,
+ typename KEY = typename _maps_bits::IteratorTraits<IT>::Value>
+#endif
+ class LoggerBoolMap : public MapBase<KEY, bool> {
+ public:
+
+ ///\e
+ typedef KEY Key;
+ ///\e
+ typedef bool Value;
+ ///\e
+ typedef IT Iterator;
+
+ /// Constructor
+ LoggerBoolMap(Iterator it)
+ : _begin(it), _end(it) {}
+
+ /// Gives back the given iterator set for the first key
+ Iterator begin() const {
+ return _begin;
+ }
+
+ /// Gives back the the 'after the last' iterator
+ Iterator end() const {
+ return _end;
+ }
+
+ /// The set function of the map
+ void set(const Key& key, Value value) {
+ if (value) {
+ *_end++ = key;
+ }
+ }
+
+ private:
+ Iterator _begin;
+ Iterator _end;
+ };
+
+ /// Returns a \c LoggerBoolMap class
+
+ /// This function just returns a \c LoggerBoolMap class.
+ ///
+ /// The most important usage of it is storing certain nodes or arcs
+ /// that were marked \c true by an algorithm.
+ /// For example, it makes easier to store the nodes in the processing
+ /// order of Dfs algorithm, as the following examples show.
+ /// \code
+ /// std::vector<Node> v;
+ /// dfs(g).processedMap(loggerBoolMap(std::back_inserter(v))).run(s);
+ /// \endcode
+ /// \code
+ /// std::vector<Node> v(countNodes(g));
+ /// dfs(g).processedMap(loggerBoolMap(v.begin())).run(s);
+ /// \endcode
+ ///
+ /// \note The container of the iterator must contain enough space
+ /// for the elements or the iterator should be an inserter iterator.
+ ///
+ /// \note LoggerBoolMap is just \ref concepts::WriteMap "writable", so
+ /// it cannot be used when a readable map is needed, for example, as
+ /// \c ReachedMap for \c Bfs, \c Dfs and \c Dijkstra algorithms.
+ ///
+ /// \relates LoggerBoolMap
+ template<typename Iterator>
+ inline LoggerBoolMap<Iterator> loggerBoolMap(Iterator it) {
+ return LoggerBoolMap<Iterator>(it);
+ }
+
+ /// @}
+
+ /// \addtogroup graph_maps
+ /// @{
+
+ /// \brief Provides an immutable and unique id for each item in a graph.
+ ///
+ /// IdMap provides a unique and immutable id for each item of the
+ /// same type (\c Node, \c Arc or \c Edge) in a graph. This id is
+ /// - \b unique: different items get different ids,
+ /// - \b immutable: the id of an item does not change (even if you
+ /// delete other nodes).
+ ///
+ /// Using this map you get access (i.e. can read) the inner id values of
+ /// the items stored in the graph, which is returned by the \c id()
+ /// function of the graph. This map can be inverted with its member
+ /// class \c InverseMap or with the \c operator()() member.
+ ///
+ /// \tparam GR The graph type.
+ /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or
+ /// \c GR::Edge).
+ ///
+ /// \see RangeIdMap
+ template <typename GR, typename K>
+ class IdMap : public MapBase<K, int> {
+ public:
+ /// The graph type of IdMap.
+ typedef GR Graph;
+ typedef GR Digraph;
+ /// The key type of IdMap (\c Node, \c Arc or \c Edge).
+ typedef K Item;
+ /// The key type of IdMap (\c Node, \c Arc or \c Edge).
+ typedef K Key;
+ /// The value type of IdMap.
+ typedef int Value;
+
+ /// \brief Constructor.
+ ///
+ /// Constructor of the map.
+ explicit IdMap(const Graph& graph) : _graph(&graph) {}
+
+ /// \brief Gives back the \e id of the item.
+ ///
+ /// Gives back the immutable and unique \e id of the item.
+ int operator[](const Item& item) const { return _graph->id(item);}
+
+ /// \brief Gives back the \e item by its id.
+ ///
+ /// Gives back the \e item by its id.
+ Item operator()(int id) { return _graph->fromId(id, Item()); }
+
+ private:
+ const Graph* _graph;
+
+ public:
+
+ /// \brief The inverse map type of IdMap.
+ ///
+ /// The inverse map type of IdMap. The subscript operator gives back
+ /// an item by its id.
+ /// This type conforms to the \ref concepts::ReadMap "ReadMap" concept.
+ /// \see inverse()
+ class InverseMap {
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// Constructor for creating an id-to-item map.
+ explicit InverseMap(const Graph& graph) : _graph(&graph) {}
+
+ /// \brief Constructor.
+ ///
+ /// Constructor for creating an id-to-item map.
+ explicit InverseMap(const IdMap& map) : _graph(map._graph) {}
+
+ /// \brief Gives back an item by its id.
+ ///
+ /// Gives back an item by its id.
+ Item operator[](int id) const { return _graph->fromId(id, Item());}
+
+ private:
+ const Graph* _graph;
+ };
+
+ /// \brief Gives back the inverse of the map.
+ ///
+ /// Gives back the inverse of the IdMap.
+ InverseMap inverse() const { return InverseMap(*_graph);}
+ };
+
+ /// \brief Returns an \c IdMap class.
+ ///
+ /// This function just returns an \c IdMap class.
+ /// \relates IdMap
+ template <typename K, typename GR>
+ inline IdMap<GR, K> idMap(const GR& graph) {
+ return IdMap<GR, K>(graph);
+ }
+
+ /// \brief General cross reference graph map type.
+
+ /// This class provides simple invertable graph maps.
+ /// It wraps a standard graph map (\c NodeMap, \c ArcMap or \c EdgeMap)
+ /// and if a key is set to a new value, then stores it in the inverse map.
+ /// The graph items can be accessed by their values either using
+ /// \c InverseMap or \c operator()(), and the values of the map can be
+ /// accessed with an STL compatible forward iterator (\c ValueIt).
+ ///
+ /// This map is intended to be used when all associated values are
+ /// different (the map is actually invertable) or there are only a few
+ /// items with the same value.
+ /// Otherwise consider to use \c IterableValueMap, which is more
+ /// suitable and more efficient for such cases. It provides iterators
+ /// to traverse the items with the same associated value, but
+ /// it does not have \c InverseMap.
+ ///
+ /// This type is not reference map, so it cannot be modified with
+ /// the subscript operator.
+ ///
+ /// \tparam GR The graph type.
+ /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or
+ /// \c GR::Edge).
+ /// \tparam V The value type of the map.
+ ///
+ /// \see IterableValueMap
+ template <typename GR, typename K, typename V>
+ class CrossRefMap
+ : protected ItemSetTraits<GR, K>::template Map<V>::Type {
+ private:
+
+ typedef typename ItemSetTraits<GR, K>::
+ template Map<V>::Type Map;
+
+ typedef std::multimap<V, K> Container;
+ Container _inv_map;
+
+ public:
+
+ /// The graph type of CrossRefMap.
+ typedef GR Graph;
+ typedef GR Digraph;
+ /// The key type of CrossRefMap (\c Node, \c Arc or \c Edge).
+ typedef K Item;
+ /// The key type of CrossRefMap (\c Node, \c Arc or \c Edge).
+ typedef K Key;
+ /// The value type of CrossRefMap.
+ typedef V Value;
+
+ /// \brief Constructor.
+ ///
+ /// Construct a new CrossRefMap for the given graph.
+ explicit CrossRefMap(const Graph& graph) : Map(graph) {}
+
+ /// \brief Forward iterator for values.
+ ///
+ /// This iterator is an STL compatible forward
+ /// iterator on the values of the map. The values can
+ /// be accessed in the <tt>[beginValue, endValue)</tt> range.
+ /// They are considered with multiplicity, so each value is
+ /// traversed for each item it is assigned to.
+ class ValueIt
+ : public std::iterator<std::forward_iterator_tag, Value> {
+ friend class CrossRefMap;
+ private:
+ ValueIt(typename Container::const_iterator _it)
+ : it(_it) {}
+ public:
+
+ /// Constructor
+ ValueIt() {}
+
+ /// \e
+ ValueIt& operator++() { ++it; return *this; }
+ /// \e
+ ValueIt operator++(int) {
+ ValueIt tmp(*this);
+ operator++();
+ return tmp;
+ }
+
+ /// \e
+ const Value& operator*() const { return it->first; }
+ /// \e
+ const Value* operator->() const { return &(it->first); }
+
+ /// \e
+ bool operator==(ValueIt jt) const { return it == jt.it; }
+ /// \e
+ bool operator!=(ValueIt jt) const { return it != jt.it; }
+
+ private:
+ typename Container::const_iterator it;
+ };
+
+ /// Alias for \c ValueIt
+ typedef ValueIt ValueIterator;
+
+ /// \brief Returns an iterator to the first value.
+ ///
+ /// Returns an STL compatible iterator to the
+ /// first value of the map. The values of the
+ /// map can be accessed in the <tt>[beginValue, endValue)</tt>
+ /// range.
+ ValueIt beginValue() const {
+ return ValueIt(_inv_map.begin());
+ }
+
+ /// \brief Returns an iterator after the last value.
+ ///
+ /// Returns an STL compatible iterator after the
+ /// last value of the map. The values of the
+ /// map can be accessed in the <tt>[beginValue, endValue)</tt>
+ /// range.
+ ValueIt endValue() const {
+ return ValueIt(_inv_map.end());
+ }
+
+ /// \brief Sets the value associated with the given key.
+ ///
+ /// Sets the value associated with the given key.
+ void set(const Key& key, const Value& val) {
+ Value oldval = Map::operator[](key);
+ typename Container::iterator it;
+ for (it = _inv_map.equal_range(oldval).first;
+ it != _inv_map.equal_range(oldval).second; ++it) {
+ if (it->second == key) {
+ _inv_map.erase(it);
+ break;
+ }
+ }
+ _inv_map.insert(std::make_pair(val, key));
+ Map::set(key, val);
+ }
+
+ /// \brief Returns the value associated with the given key.
+ ///
+ /// Returns the value associated with the given key.
+ typename MapTraits<Map>::ConstReturnValue
+ operator[](const Key& key) const {
+ return Map::operator[](key);
+ }
+
+ /// \brief Gives back an item by its value.
+ ///
+ /// This function gives back an item that is assigned to
+ /// the given value or \c INVALID if no such item exists.
+ /// If there are more items with the same associated value,
+ /// only one of them is returned.
+ Key operator()(const Value& val) const {
+ typename Container::const_iterator it = _inv_map.find(val);
+ return it != _inv_map.end() ? it->second : INVALID;
+ }
+
+ /// \brief Returns the number of items with the given value.
+ ///
+ /// This function returns the number of items with the given value
+ /// associated with it.
+ int count(const Value &val) const {
+ return _inv_map.count(val);
+ }
+
+ protected:
+
+ /// \brief Erase the key from the map and the inverse map.
+ ///
+ /// Erase the key from the map and the inverse map. It is called by the
+ /// \c AlterationNotifier.
+ virtual void erase(const Key& key) {
+ Value val = Map::operator[](key);
+ typename Container::iterator it;
+ for (it = _inv_map.equal_range(val).first;
+ it != _inv_map.equal_range(val).second; ++it) {
+ if (it->second == key) {
+ _inv_map.erase(it);
+ break;
+ }
+ }
+ Map::erase(key);
+ }
+
+ /// \brief Erase more keys from the map and the inverse map.
+ ///
+ /// Erase more keys from the map and the inverse map. It is called by the
+ /// \c AlterationNotifier.
+ virtual void erase(const std::vector<Key>& keys) {
+ for (int i = 0; i < int(keys.size()); ++i) {
+ Value val = Map::operator[](keys[i]);
+ typename Container::iterator it;
+ for (it = _inv_map.equal_range(val).first;
+ it != _inv_map.equal_range(val).second; ++it) {
+ if (it->second == keys[i]) {
+ _inv_map.erase(it);
+ break;
+ }
+ }
+ }
+ Map::erase(keys);
+ }
+
+ /// \brief Clear the keys from the map and the inverse map.
+ ///
+ /// Clear the keys from the map and the inverse map. It is called by the
+ /// \c AlterationNotifier.
+ virtual void clear() {
+ _inv_map.clear();
+ Map::clear();
+ }
+
+ public:
+
+ /// \brief The inverse map type of CrossRefMap.
+ ///
+ /// The inverse map type of CrossRefMap. The subscript operator gives
+ /// back an item by its value.
+ /// This type conforms to the \ref concepts::ReadMap "ReadMap" concept.
+ /// \see inverse()
+ class InverseMap {
+ public:
+ /// \brief Constructor
+ ///
+ /// Constructor of the InverseMap.
+ explicit InverseMap(const CrossRefMap& inverted)
+ : _inverted(inverted) {}
+
+ /// The value type of the InverseMap.
+ typedef typename CrossRefMap::Key Value;
+ /// The key type of the InverseMap.
+ typedef typename CrossRefMap::Value Key;
+
+ /// \brief Subscript operator.
+ ///
+ /// Subscript operator. It gives back an item
+ /// that is assigned to the given value or \c INVALID
+ /// if no such item exists.
+ Value operator[](const Key& key) const {
+ return _inverted(key);
+ }
+
+ private:
+ const CrossRefMap& _inverted;
+ };
+
+ /// \brief Gives back the inverse of the map.
+ ///
+ /// Gives back the inverse of the CrossRefMap.
+ InverseMap inverse() const {
+ return InverseMap(*this);
+ }
+
+ };
+
+ /// \brief Provides continuous and unique id for the
+ /// items of a graph.
+ ///
+ /// RangeIdMap provides a unique and continuous
+ /// id for each item of a given type (\c Node, \c Arc or
+ /// \c Edge) in a graph. This id is
+ /// - \b unique: different items get different ids,
+ /// - \b continuous: the range of the ids is the set of integers
+ /// between 0 and \c n-1, where \c n is the number of the items of
+ /// this type (\c Node, \c Arc or \c Edge).
+ /// - So, the ids can change when deleting an item of the same type.
+ ///
+ /// Thus this id is not (necessarily) the same as what can get using
+ /// the \c id() function of the graph or \ref IdMap.
+ /// This map can be inverted with its member class \c InverseMap,
+ /// or with the \c operator()() member.
+ ///
+ /// \tparam GR The graph type.
+ /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or
+ /// \c GR::Edge).
+ ///
+ /// \see IdMap
+ template <typename GR, typename K>
+ class RangeIdMap
+ : protected ItemSetTraits<GR, K>::template Map<int>::Type {
+
+ typedef typename ItemSetTraits<GR, K>::template Map<int>::Type Map;
+
+ public:
+ /// The graph type of RangeIdMap.
+ typedef GR Graph;
+ typedef GR Digraph;
+ /// The key type of RangeIdMap (\c Node, \c Arc or \c Edge).
+ typedef K Item;
+ /// The key type of RangeIdMap (\c Node, \c Arc or \c Edge).
+ typedef K Key;
+ /// The value type of RangeIdMap.
+ typedef int Value;
+
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ explicit RangeIdMap(const Graph& gr) : Map(gr) {
+ Item it;
+ const typename Map::Notifier* nf = Map::notifier();
+ for (nf->first(it); it != INVALID; nf->next(it)) {
+ Map::set(it, _inv_map.size());
+ _inv_map.push_back(it);
+ }
+ }
+
+ protected:
+
+ /// \brief Adds a new key to the map.
+ ///
+ /// Add a new key to the map. It is called by the
+ /// \c AlterationNotifier.
+ virtual void add(const Item& item) {
+ Map::add(item);
+ Map::set(item, _inv_map.size());
+ _inv_map.push_back(item);
+ }
+
+ /// \brief Add more new keys to the map.
+ ///
+ /// Add more new keys to the map. It is called by the
+ /// \c AlterationNotifier.
+ virtual void add(const std::vector<Item>& items) {
+ Map::add(items);
+ for (int i = 0; i < int(items.size()); ++i) {
+ Map::set(items[i], _inv_map.size());
+ _inv_map.push_back(items[i]);
+ }
+ }
+
+ /// \brief Erase the key from the map.
+ ///
+ /// Erase the key from the map. It is called by the
+ /// \c AlterationNotifier.
+ virtual void erase(const Item& item) {
+ Map::set(_inv_map.back(), Map::operator[](item));
+ _inv_map[Map::operator[](item)] = _inv_map.back();
+ _inv_map.pop_back();
+ Map::erase(item);
+ }
+
+ /// \brief Erase more keys from the map.
+ ///
+ /// Erase more keys from the map. It is called by the
+ /// \c AlterationNotifier.
+ virtual void erase(const std::vector<Item>& items) {
+ for (int i = 0; i < int(items.size()); ++i) {
+ Map::set(_inv_map.back(), Map::operator[](items[i]));
+ _inv_map[Map::operator[](items[i])] = _inv_map.back();
+ _inv_map.pop_back();
+ }
+ Map::erase(items);
+ }
+
+ /// \brief Build the unique map.
+ ///
+ /// Build the unique map. It is called by the
+ /// \c AlterationNotifier.
+ virtual void build() {
+ Map::build();
+ Item it;
+ const typename Map::Notifier* nf = Map::notifier();
+ for (nf->first(it); it != INVALID; nf->next(it)) {
+ Map::set(it, _inv_map.size());
+ _inv_map.push_back(it);
+ }
+ }
+
+ /// \brief Clear the keys from the map.
+ ///
+ /// Clear the keys from the map. It is called by the
+ /// \c AlterationNotifier.
+ virtual void clear() {
+ _inv_map.clear();
+ Map::clear();
+ }
+
+ public:
+
+ /// \brief Returns the maximal value plus one.
+ ///
+ /// Returns the maximal value plus one in the map.
+ unsigned int size() const {
+ return _inv_map.size();
+ }
+
+ /// \brief Swaps the position of the two items in the map.
+ ///
+ /// Swaps the position of the two items in the map.
+ void swap(const Item& p, const Item& q) {
+ int pi = Map::operator[](p);
+ int qi = Map::operator[](q);
+ Map::set(p, qi);
+ _inv_map[qi] = p;
+ Map::set(q, pi);
+ _inv_map[pi] = q;
+ }
+
+ /// \brief Gives back the \e range \e id of the item
+ ///
+ /// Gives back the \e range \e id of the item.
+ int operator[](const Item& item) const {
+ return Map::operator[](item);
+ }
+
+ /// \brief Gives back the item belonging to a \e range \e id
+ ///
+ /// Gives back the item belonging to the given \e range \e id.
+ Item operator()(int id) const {
+ return _inv_map[id];
+ }
+
+ private:
+
+ typedef std::vector<Item> Container;
+ Container _inv_map;
+
+ public:
+
+ /// \brief The inverse map type of RangeIdMap.
+ ///
+ /// The inverse map type of RangeIdMap. The subscript operator gives
+ /// back an item by its \e range \e id.
+ /// This type conforms to the \ref concepts::ReadMap "ReadMap" concept.
+ class InverseMap {
+ public:
+ /// \brief Constructor
+ ///
+ /// Constructor of the InverseMap.
+ explicit InverseMap(const RangeIdMap& inverted)
+ : _inverted(inverted) {}
+
+
+ /// The value type of the InverseMap.
+ typedef typename RangeIdMap::Key Value;
+ /// The key type of the InverseMap.
+ typedef typename RangeIdMap::Value Key;
+
+ /// \brief Subscript operator.
+ ///
+ /// Subscript operator. It gives back the item
+ /// that the given \e range \e id currently belongs to.
+ Value operator[](const Key& key) const {
+ return _inverted(key);
+ }
+
+ /// \brief Size of the map.
+ ///
+ /// Returns the size of the map.
+ unsigned int size() const {
+ return _inverted.size();
+ }
+
+ private:
+ const RangeIdMap& _inverted;
+ };
+
+ /// \brief Gives back the inverse of the map.
+ ///
+ /// Gives back the inverse of the RangeIdMap.
+ const InverseMap inverse() const {
+ return InverseMap(*this);
+ }
+ };
+
+ /// \brief Returns a \c RangeIdMap class.
+ ///
+ /// This function just returns an \c RangeIdMap class.
+ /// \relates RangeIdMap
+ template <typename K, typename GR>
+ inline RangeIdMap<GR, K> rangeIdMap(const GR& graph) {
+ return RangeIdMap<GR, K>(graph);
+ }
+
+ /// \brief Dynamic iterable \c bool map.
+ ///
+ /// This class provides a special graph map type which can store a
+ /// \c bool value for graph items (\c Node, \c Arc or \c Edge).
+ /// For both \c true and \c false values it is possible to iterate on
+ /// the keys mapped to the value.
+ ///
+ /// This type is a reference map, so it can be modified with the
+ /// subscript operator.
+ ///
+ /// \tparam GR The graph type.
+ /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or
+ /// \c GR::Edge).
+ ///
+ /// \see IterableIntMap, IterableValueMap
+ /// \see CrossRefMap
+ template <typename GR, typename K>
+ class IterableBoolMap
+ : protected ItemSetTraits<GR, K>::template Map<int>::Type {
+ private:
+ typedef GR Graph;
+
+ typedef typename ItemSetTraits<GR, K>::ItemIt KeyIt;
+ typedef typename ItemSetTraits<GR, K>::template Map<int>::Type Parent;
+
+ std::vector<K> _array;
+ int _sep;
+
+ public:
+
+ /// Indicates that the map is reference map.
+ typedef True ReferenceMapTag;
+
+ /// The key type
+ typedef K Key;
+ /// The value type
+ typedef bool Value;
+ /// The const reference type.
+ typedef const Value& ConstReference;
+
+ private:
+
+ int position(const Key& key) const {
+ return Parent::operator[](key);
+ }
+
+ public:
+
+ /// \brief Reference to the value of the map.
+ ///
+ /// This class is similar to the \c bool type. It can be converted to
+ /// \c bool and it provides the same operators.
+ class Reference {
+ friend class IterableBoolMap;
+ private:
+ Reference(IterableBoolMap& map, const Key& key)
+ : _key(key), _map(map) {}
+ public:
+
+ Reference& operator=(const Reference& value) {
+ _map.set(_key, static_cast<bool>(value));
+ return *this;
+ }
+
+ operator bool() const {
+ return static_cast<const IterableBoolMap&>(_map)[_key];
+ }
+
+ Reference& operator=(bool value) {
+ _map.set(_key, value);
+ return *this;
+ }
+ Reference& operator&=(bool value) {
+ _map.set(_key, _map[_key] & value);
+ return *this;
+ }
+ Reference& operator|=(bool value) {
+ _map.set(_key, _map[_key] | value);
+ return *this;
+ }
+ Reference& operator^=(bool value) {
+ _map.set(_key, _map[_key] ^ value);
+ return *this;
+ }
+ private:
+ Key _key;
+ IterableBoolMap& _map;
+ };
+
+ /// \brief Constructor of the map with a default value.
+ ///
+ /// Constructor of the map with a default value.
+ explicit IterableBoolMap(const Graph& graph, bool def = false)
+ : Parent(graph) {
+ typename Parent::Notifier* nf = Parent::notifier();
+ Key it;
+ for (nf->first(it); it != INVALID; nf->next(it)) {
+ Parent::set(it, _array.size());
+ _array.push_back(it);
+ }
+ _sep = (def ? _array.size() : 0);
+ }
+
+ /// \brief Const subscript operator of the map.
+ ///
+ /// Const subscript operator of the map.
+ bool operator[](const Key& key) const {
+ return position(key) < _sep;
+ }
+
+ /// \brief Subscript operator of the map.
+ ///
+ /// Subscript operator of the map.
+ Reference operator[](const Key& key) {
+ return Reference(*this, key);
+ }
+
+ /// \brief Set operation of the map.
+ ///
+ /// Set operation of the map.
+ void set(const Key& key, bool value) {
+ int pos = position(key);
+ if (value) {
+ if (pos < _sep) return;
+ Key tmp = _array[_sep];
+ _array[_sep] = key;
+ Parent::set(key, _sep);
+ _array[pos] = tmp;
+ Parent::set(tmp, pos);
+ ++_sep;
+ } else {
+ if (pos >= _sep) return;
+ --_sep;
+ Key tmp = _array[_sep];
+ _array[_sep] = key;
+ Parent::set(key, _sep);
+ _array[pos] = tmp;
+ Parent::set(tmp, pos);
+ }
+ }
+
+ /// \brief Set all items.
+ ///
+ /// Set all items in the map.
+ /// \note Constant time operation.
+ void setAll(bool value) {
+ _sep = (value ? _array.size() : 0);
+ }
+
+ /// \brief Returns the number of the keys mapped to \c true.
+ ///
+ /// Returns the number of the keys mapped to \c true.
+ int trueNum() const {
+ return _sep;
+ }
+
+ /// \brief Returns the number of the keys mapped to \c false.
+ ///
+ /// Returns the number of the keys mapped to \c false.
+ int falseNum() const {
+ return _array.size() - _sep;
+ }
+
+ /// \brief Iterator for the keys mapped to \c true.
+ ///
+ /// Iterator for the keys mapped to \c true. It works
+ /// like a graph item iterator, it can be converted to
+ /// the key type of the map, incremented with \c ++ operator, and
+ /// if the iterator leaves the last valid key, it will be equal to
+ /// \c INVALID.
+ class TrueIt : public Key {
+ public:
+ typedef Key Parent;
+
+ /// \brief Creates an iterator.
+ ///
+ /// Creates an iterator. It iterates on the
+ /// keys mapped to \c true.
+ /// \param map The IterableBoolMap.
+ explicit TrueIt(const IterableBoolMap& map)
+ : Parent(map._sep > 0 ? map._array[map._sep - 1] : INVALID),
+ _map(&map) {}
+
+ /// \brief Invalid constructor \& conversion.
+ ///
+ /// This constructor initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ TrueIt(Invalid) : Parent(INVALID), _map(0) {}
+
+ /// \brief Increment operator.
+ ///
+ /// Increment operator.
+ TrueIt& operator++() {
+ int pos = _map->position(*this);
+ Parent::operator=(pos > 0 ? _map->_array[pos - 1] : INVALID);
+ return *this;
+ }
+
+ private:
+ const IterableBoolMap* _map;
+ };
+
+ /// \brief Iterator for the keys mapped to \c false.
+ ///
+ /// Iterator for the keys mapped to \c false. It works
+ /// like a graph item iterator, it can be converted to
+ /// the key type of the map, incremented with \c ++ operator, and
+ /// if the iterator leaves the last valid key, it will be equal to
+ /// \c INVALID.
+ class FalseIt : public Key {
+ public:
+ typedef Key Parent;
+
+ /// \brief Creates an iterator.
+ ///
+ /// Creates an iterator. It iterates on the
+ /// keys mapped to \c false.
+ /// \param map The IterableBoolMap.
+ explicit FalseIt(const IterableBoolMap& map)
+ : Parent(map._sep < int(map._array.size()) ?
+ map._array.back() : INVALID), _map(&map) {}
+
+ /// \brief Invalid constructor \& conversion.
+ ///
+ /// This constructor initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ FalseIt(Invalid) : Parent(INVALID), _map(0) {}
+
+ /// \brief Increment operator.
+ ///
+ /// Increment operator.
+ FalseIt& operator++() {
+ int pos = _map->position(*this);
+ Parent::operator=(pos > _map->_sep ? _map->_array[pos - 1] : INVALID);
+ return *this;
+ }
+
+ private:
+ const IterableBoolMap* _map;
+ };
+
+ /// \brief Iterator for the keys mapped to a given value.
+ ///
+ /// Iterator for the keys mapped to a given value. It works
+ /// like a graph item iterator, it can be converted to
+ /// the key type of the map, incremented with \c ++ operator, and
+ /// if the iterator leaves the last valid key, it will be equal to
+ /// \c INVALID.
+ class ItemIt : public Key {
+ public:
+ typedef Key Parent;
+
+ /// \brief Creates an iterator with a value.
+ ///
+ /// Creates an iterator with a value. It iterates on the
+ /// keys mapped to the given value.
+ /// \param map The IterableBoolMap.
+ /// \param value The value.
+ ItemIt(const IterableBoolMap& map, bool value)
+ : Parent(value ?
+ (map._sep > 0 ?
+ map._array[map._sep - 1] : INVALID) :
+ (map._sep < int(map._array.size()) ?
+ map._array.back() : INVALID)), _map(&map) {}
+
+ /// \brief Invalid constructor \& conversion.
+ ///
+ /// This constructor initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ ItemIt(Invalid) : Parent(INVALID), _map(0) {}
+
+ /// \brief Increment operator.
+ ///
+ /// Increment operator.
+ ItemIt& operator++() {
+ int pos = _map->position(*this);
+ int _sep = pos >= _map->_sep ? _map->_sep : 0;
+ Parent::operator=(pos > _sep ? _map->_array[pos - 1] : INVALID);
+ return *this;
+ }
+
+ private:
+ const IterableBoolMap* _map;
+ };
+
+ protected:
+
+ virtual void add(const Key& key) {
+ Parent::add(key);
+ Parent::set(key, _array.size());
+ _array.push_back(key);
+ }
+
+ virtual void add(const std::vector<Key>& keys) {
+ Parent::add(keys);
+ for (int i = 0; i < int(keys.size()); ++i) {
+ Parent::set(keys[i], _array.size());
+ _array.push_back(keys[i]);
+ }
+ }
+
+ virtual void erase(const Key& key) {
+ int pos = position(key);
+ if (pos < _sep) {
+ --_sep;
+ Parent::set(_array[_sep], pos);
+ _array[pos] = _array[_sep];
+ Parent::set(_array.back(), _sep);
+ _array[_sep] = _array.back();
+ _array.pop_back();
+ } else {
+ Parent::set(_array.back(), pos);
+ _array[pos] = _array.back();
+ _array.pop_back();
+ }
+ Parent::erase(key);
+ }
+
+ virtual void erase(const std::vector<Key>& keys) {
+ for (int i = 0; i < int(keys.size()); ++i) {
+ int pos = position(keys[i]);
+ if (pos < _sep) {
+ --_sep;
+ Parent::set(_array[_sep], pos);
+ _array[pos] = _array[_sep];
+ Parent::set(_array.back(), _sep);
+ _array[_sep] = _array.back();
+ _array.pop_back();
+ } else {
+ Parent::set(_array.back(), pos);
+ _array[pos] = _array.back();
+ _array.pop_back();
+ }
+ }
+ Parent::erase(keys);
+ }
+
+ virtual void build() {
+ Parent::build();
+ typename Parent::Notifier* nf = Parent::notifier();
+ Key it;
+ for (nf->first(it); it != INVALID; nf->next(it)) {
+ Parent::set(it, _array.size());
+ _array.push_back(it);
+ }
+ _sep = 0;
+ }
+
+ virtual void clear() {
+ _array.clear();
+ _sep = 0;
+ Parent::clear();
+ }
+
+ };
+
+
+ namespace _maps_bits {
+ template <typename Item>
+ struct IterableIntMapNode {
+ IterableIntMapNode() : value(-1) {}
+ IterableIntMapNode(int _value) : value(_value) {}
+ Item prev, next;
+ int value;
+ };
+ }
+
+ /// \brief Dynamic iterable integer map.
+ ///
+ /// This class provides a special graph map type which can store an
+ /// integer value for graph items (\c Node, \c Arc or \c Edge).
+ /// For each non-negative value it is possible to iterate on the keys
+ /// mapped to the value.
+ ///
+ /// This map is intended to be used with small integer values, for which
+ /// it is efficient, and supports iteration only for non-negative values.
+ /// If you need large values and/or iteration for negative integers,
+ /// consider to use \ref IterableValueMap instead.
+ ///
+ /// This type is a reference map, so it can be modified with the
+ /// subscript operator.
+ ///
+ /// \note The size of the data structure depends on the largest
+ /// value in the map.
+ ///
+ /// \tparam GR The graph type.
+ /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or
+ /// \c GR::Edge).
+ ///
+ /// \see IterableBoolMap, IterableValueMap
+ /// \see CrossRefMap
+ template <typename GR, typename K>
+ class IterableIntMap
+ : protected ItemSetTraits<GR, K>::
+ template Map<_maps_bits::IterableIntMapNode<K> >::Type {
+ public:
+ typedef typename ItemSetTraits<GR, K>::
+ template Map<_maps_bits::IterableIntMapNode<K> >::Type Parent;
+
+ /// The key type
+ typedef K Key;
+ /// The value type
+ typedef int Value;
+ /// The graph type
+ typedef GR Graph;
+
+ /// \brief Constructor of the map.
+ ///
+ /// Constructor of the map. It sets all values to -1.
+ explicit IterableIntMap(const Graph& graph)
+ : Parent(graph) {}
+
+ /// \brief Constructor of the map with a given value.
+ ///
+ /// Constructor of the map with a given value.
+ explicit IterableIntMap(const Graph& graph, int value)
+ : Parent(graph, _maps_bits::IterableIntMapNode<K>(value)) {
+ if (value >= 0) {
+ for (typename Parent::ItemIt it(*this); it != INVALID; ++it) {
+ lace(it);
+ }
+ }
+ }
+
+ private:
+
+ void unlace(const Key& key) {
+ typename Parent::Value& node = Parent::operator[](key);
+ if (node.value < 0) return;
+ if (node.prev != INVALID) {
+ Parent::operator[](node.prev).next = node.next;
+ } else {
+ _first[node.value] = node.next;
+ }
+ if (node.next != INVALID) {
+ Parent::operator[](node.next).prev = node.prev;
+ }
+ while (!_first.empty() && _first.back() == INVALID) {
+ _first.pop_back();
+ }
+ }
+
+ void lace(const Key& key) {
+ typename Parent::Value& node = Parent::operator[](key);
+ if (node.value < 0) return;
+ if (node.value >= int(_first.size())) {
+ _first.resize(node.value + 1, INVALID);
+ }
+ node.prev = INVALID;
+ node.next = _first[node.value];
+ if (node.next != INVALID) {
+ Parent::operator[](node.next).prev = key;
+ }
+ _first[node.value] = key;
+ }
+
+ public:
+
+ /// Indicates that the map is reference map.
+ typedef True ReferenceMapTag;
+
+ /// \brief Reference to the value of the map.
+ ///
+ /// This class is similar to the \c int type. It can
+ /// be converted to \c int and it has the same operators.
+ class Reference {
+ friend class IterableIntMap;
+ private:
+ Reference(IterableIntMap& map, const Key& key)
+ : _key(key), _map(map) {}
+ public:
+
+ Reference& operator=(const Reference& value) {
+ _map.set(_key, static_cast<const int&>(value));
+ return *this;
+ }
+
+ operator const int&() const {
+ return static_cast<const IterableIntMap&>(_map)[_key];
+ }
+
+ Reference& operator=(int value) {
+ _map.set(_key, value);
+ return *this;
+ }
+ Reference& operator++() {
+ _map.set(_key, _map[_key] + 1);
+ return *this;
+ }
+ int operator++(int) {
+ int value = _map[_key];
+ _map.set(_key, value + 1);
+ return value;
+ }
+ Reference& operator--() {
+ _map.set(_key, _map[_key] - 1);
+ return *this;
+ }
+ int operator--(int) {
+ int value = _map[_key];
+ _map.set(_key, value - 1);
+ return value;
+ }
+ Reference& operator+=(int value) {
+ _map.set(_key, _map[_key] + value);
+ return *this;
+ }
+ Reference& operator-=(int value) {
+ _map.set(_key, _map[_key] - value);
+ return *this;
+ }
+ Reference& operator*=(int value) {
+ _map.set(_key, _map[_key] * value);
+ return *this;
+ }
+ Reference& operator/=(int value) {
+ _map.set(_key, _map[_key] / value);
+ return *this;
+ }
+ Reference& operator%=(int value) {
+ _map.set(_key, _map[_key] % value);
+ return *this;
+ }
+ Reference& operator&=(int value) {
+ _map.set(_key, _map[_key] & value);
+ return *this;
+ }
+ Reference& operator|=(int value) {
+ _map.set(_key, _map[_key] | value);
+ return *this;
+ }
+ Reference& operator^=(int value) {
+ _map.set(_key, _map[_key] ^ value);
+ return *this;
+ }
+ Reference& operator<<=(int value) {
+ _map.set(_key, _map[_key] << value);
+ return *this;
+ }
+ Reference& operator>>=(int value) {
+ _map.set(_key, _map[_key] >> value);
+ return *this;
+ }
+
+ private:
+ Key _key;
+ IterableIntMap& _map;
+ };
+
+ /// The const reference type.
+ typedef const Value& ConstReference;
+
+ /// \brief Gives back the maximal value plus one.
+ ///
+ /// Gives back the maximal value plus one.
+ int size() const {
+ return _first.size();
+ }
+
+ /// \brief Set operation of the map.
+ ///
+ /// Set operation of the map.
+ void set(const Key& key, const Value& value) {
+ unlace(key);
+ Parent::operator[](key).value = value;
+ lace(key);
+ }
+
+ /// \brief Const subscript operator of the map.
+ ///
+ /// Const subscript operator of the map.
+ const Value& operator[](const Key& key) const {
+ return Parent::operator[](key).value;
+ }
+
+ /// \brief Subscript operator of the map.
+ ///
+ /// Subscript operator of the map.
+ Reference operator[](const Key& key) {
+ return Reference(*this, key);
+ }
+
+ /// \brief Iterator for the keys with the same value.
+ ///
+ /// Iterator for the keys with the same value. It works
+ /// like a graph item iterator, it can be converted to
+ /// the item type of the map, incremented with \c ++ operator, and
+ /// if the iterator leaves the last valid item, it will be equal to
+ /// \c INVALID.
+ class ItemIt : public Key {
+ public:
+ typedef Key Parent;
+
+ /// \brief Invalid constructor \& conversion.
+ ///
+ /// This constructor initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ ItemIt(Invalid) : Parent(INVALID), _map(0) {}
+
+ /// \brief Creates an iterator with a value.
+ ///
+ /// Creates an iterator with a value. It iterates on the
+ /// keys mapped to the given value.
+ /// \param map The IterableIntMap.
+ /// \param value The value.
+ ItemIt(const IterableIntMap& map, int value) : _map(&map) {
+ if (value < 0 || value >= int(_map->_first.size())) {
+ Parent::operator=(INVALID);
+ } else {
+ Parent::operator=(_map->_first[value]);
+ }
+ }
+
+ /// \brief Increment operator.
+ ///
+ /// Increment operator.
+ ItemIt& operator++() {
+ Parent::operator=(_map->IterableIntMap::Parent::
+ operator[](static_cast<Parent&>(*this)).next);
+ return *this;
+ }
+
+ private:
+ const IterableIntMap* _map;
+ };
+
+ protected:
+
+ virtual void erase(const Key& key) {
+ unlace(key);
+ Parent::erase(key);
+ }
+
+ virtual void erase(const std::vector<Key>& keys) {
+ for (int i = 0; i < int(keys.size()); ++i) {
+ unlace(keys[i]);
+ }
+ Parent::erase(keys);
+ }
+
+ virtual void clear() {
+ _first.clear();
+ Parent::clear();
+ }
+
+ private:
+ std::vector<Key> _first;
+ };
+
+ namespace _maps_bits {
+ template <typename Item, typename Value>
+ struct IterableValueMapNode {
+ IterableValueMapNode(Value _value = Value()) : value(_value) {}
+ Item prev, next;
+ Value value;
+ };
+ }
+
+ /// \brief Dynamic iterable map for comparable values.
+ ///
+ /// This class provides a special graph map type which can store a
+ /// comparable value for graph items (\c Node, \c Arc or \c Edge).
+ /// For each value it is possible to iterate on the keys mapped to
+ /// the value (\c ItemIt), and the values of the map can be accessed
+ /// with an STL compatible forward iterator (\c ValueIt).
+ /// The map stores a linked list for each value, which contains
+ /// the items mapped to the value, and the used values are stored
+ /// in balanced binary tree (\c std::map).
+ ///
+ /// \ref IterableBoolMap and \ref IterableIntMap are similar classes
+ /// specialized for \c bool and \c int values, respectively.
+ ///
+ /// This type is not reference map, so it cannot be modified with
+ /// the subscript operator.
+ ///
+ /// \tparam GR The graph type.
+ /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or
+ /// \c GR::Edge).
+ /// \tparam V The value type of the map. It can be any comparable
+ /// value type.
+ ///
+ /// \see IterableBoolMap, IterableIntMap
+ /// \see CrossRefMap
+ template <typename GR, typename K, typename V>
+ class IterableValueMap
+ : protected ItemSetTraits<GR, K>::
+ template Map<_maps_bits::IterableValueMapNode<K, V> >::Type {
+ public:
+ typedef typename ItemSetTraits<GR, K>::
+ template Map<_maps_bits::IterableValueMapNode<K, V> >::Type Parent;
+
+ /// The key type
+ typedef K Key;
+ /// The value type
+ typedef V Value;
+ /// The graph type
+ typedef GR Graph;
+
+ public:
+
+ /// \brief Constructor of the map with a given value.
+ ///
+ /// Constructor of the map with a given value.
+ explicit IterableValueMap(const Graph& graph,
+ const Value& value = Value())
+ : Parent(graph, _maps_bits::IterableValueMapNode<K, V>(value)) {
+ for (typename Parent::ItemIt it(*this); it != INVALID; ++it) {
+ lace(it);
+ }
+ }
+
+ protected:
+
+ void unlace(const Key& key) {
+ typename Parent::Value& node = Parent::operator[](key);
+ if (node.prev != INVALID) {
+ Parent::operator[](node.prev).next = node.next;
+ } else {
+ if (node.next != INVALID) {
+ _first[node.value] = node.next;
+ } else {
+ _first.erase(node.value);
+ }
+ }
+ if (node.next != INVALID) {
+ Parent::operator[](node.next).prev = node.prev;
+ }
+ }
+
+ void lace(const Key& key) {
+ typename Parent::Value& node = Parent::operator[](key);
+ typename std::map<Value, Key>::iterator it = _first.find(node.value);
+ if (it == _first.end()) {
+ node.prev = node.next = INVALID;
+ _first.insert(std::make_pair(node.value, key));
+ } else {
+ node.prev = INVALID;
+ node.next = it->second;
+ if (node.next != INVALID) {
+ Parent::operator[](node.next).prev = key;
+ }
+ it->second = key;
+ }
+ }
+
+ public:
+
+ /// \brief Forward iterator for values.
+ ///
+ /// This iterator is an STL compatible forward
+ /// iterator on the values of the map. The values can
+ /// be accessed in the <tt>[beginValue, endValue)</tt> range.
+ class ValueIt
+ : public std::iterator<std::forward_iterator_tag, Value> {
+ friend class IterableValueMap;
+ private:
+ ValueIt(typename std::map<Value, Key>::const_iterator _it)
+ : it(_it) {}
+ public:
+
+ /// Constructor
+ ValueIt() {}
+
+ /// \e
+ ValueIt& operator++() { ++it; return *this; }
+ /// \e
+ ValueIt operator++(int) {
+ ValueIt tmp(*this);
+ operator++();
+ return tmp;
+ }
+
+ /// \e
+ const Value& operator*() const { return it->first; }
+ /// \e
+ const Value* operator->() const { return &(it->first); }
+
+ /// \e
+ bool operator==(ValueIt jt) const { return it == jt.it; }
+ /// \e
+ bool operator!=(ValueIt jt) const { return it != jt.it; }
+
+ private:
+ typename std::map<Value, Key>::const_iterator it;
+ };
+
+ /// \brief Returns an iterator to the first value.
+ ///
+ /// Returns an STL compatible iterator to the
+ /// first value of the map. The values of the
+ /// map can be accessed in the <tt>[beginValue, endValue)</tt>
+ /// range.
+ ValueIt beginValue() const {
+ return ValueIt(_first.begin());
+ }
+
+ /// \brief Returns an iterator after the last value.
+ ///
+ /// Returns an STL compatible iterator after the
+ /// last value of the map. The values of the
+ /// map can be accessed in the <tt>[beginValue, endValue)</tt>
+ /// range.
+ ValueIt endValue() const {
+ return ValueIt(_first.end());
+ }
+
+ /// \brief Set operation of the map.
+ ///
+ /// Set operation of the map.
+ void set(const Key& key, const Value& value) {
+ unlace(key);
+ Parent::operator[](key).value = value;
+ lace(key);
+ }
+
+ /// \brief Const subscript operator of the map.
+ ///
+ /// Const subscript operator of the map.
+ const Value& operator[](const Key& key) const {
+ return Parent::operator[](key).value;
+ }
+
+ /// \brief Iterator for the keys with the same value.
+ ///
+ /// Iterator for the keys with the same value. It works
+ /// like a graph item iterator, it can be converted to
+ /// the item type of the map, incremented with \c ++ operator, and
+ /// if the iterator leaves the last valid item, it will be equal to
+ /// \c INVALID.
+ class ItemIt : public Key {
+ public:
+ typedef Key Parent;
+
+ /// \brief Invalid constructor \& conversion.
+ ///
+ /// This constructor initializes the iterator to be invalid.
+ /// \sa Invalid for more details.
+ ItemIt(Invalid) : Parent(INVALID), _map(0) {}
+
+ /// \brief Creates an iterator with a value.
+ ///
+ /// Creates an iterator with a value. It iterates on the
+ /// keys which have the given value.
+ /// \param map The IterableValueMap
+ /// \param value The value
+ ItemIt(const IterableValueMap& map, const Value& value) : _map(&map) {
+ typename std::map<Value, Key>::const_iterator it =
+ map._first.find(value);
+ if (it == map._first.end()) {
+ Parent::operator=(INVALID);
+ } else {
+ Parent::operator=(it->second);
+ }
+ }
+
+ /// \brief Increment operator.
+ ///
+ /// Increment Operator.
+ ItemIt& operator++() {
+ Parent::operator=(_map->IterableValueMap::Parent::
+ operator[](static_cast<Parent&>(*this)).next);
+ return *this;
+ }
+
+
+ private:
+ const IterableValueMap* _map;
+ };
+
+ protected:
+
+ virtual void add(const Key& key) {
+ Parent::add(key);
+ lace(key);
+ }
+
+ virtual void add(const std::vector<Key>& keys) {
+ Parent::add(keys);
+ for (int i = 0; i < int(keys.size()); ++i) {
+ lace(keys[i]);
+ }
+ }
+
+ virtual void erase(const Key& key) {
+ unlace(key);
+ Parent::erase(key);
+ }
+
+ virtual void erase(const std::vector<Key>& keys) {
+ for (int i = 0; i < int(keys.size()); ++i) {
+ unlace(keys[i]);
+ }
+ Parent::erase(keys);
+ }
+
+ virtual void build() {
+ Parent::build();
+ for (typename Parent::ItemIt it(*this); it != INVALID; ++it) {
+ lace(it);
+ }
+ }
+
+ virtual void clear() {
+ _first.clear();
+ Parent::clear();
+ }
+
+ private:
+ std::map<Value, Key> _first;
+ };
+
+ /// \brief Map of the source nodes of arcs in a digraph.
+ ///
+ /// SourceMap provides access for the source node of each arc in a digraph,
+ /// which is returned by the \c source() function of the digraph.
+ /// \tparam GR The digraph type.
+ /// \see TargetMap
+ template <typename GR>
+ class SourceMap {
+ public:
+
+ /// The key type (the \c Arc type of the digraph).
+ typedef typename GR::Arc Key;
+ /// The value type (the \c Node type of the digraph).
+ typedef typename GR::Node Value;
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ /// \param digraph The digraph that the map belongs to.
+ explicit SourceMap(const GR& digraph) : _graph(digraph) {}
+
+ /// \brief Returns the source node of the given arc.
+ ///
+ /// Returns the source node of the given arc.
+ Value operator[](const Key& arc) const {
+ return _graph.source(arc);
+ }
+
+ private:
+ const GR& _graph;
+ };
+
+ /// \brief Returns a \c SourceMap class.
+ ///
+ /// This function just returns an \c SourceMap class.
+ /// \relates SourceMap
+ template <typename GR>
+ inline SourceMap<GR> sourceMap(const GR& graph) {
+ return SourceMap<GR>(graph);
+ }
+
+ /// \brief Map of the target nodes of arcs in a digraph.
+ ///
+ /// TargetMap provides access for the target node of each arc in a digraph,
+ /// which is returned by the \c target() function of the digraph.
+ /// \tparam GR The digraph type.
+ /// \see SourceMap
+ template <typename GR>
+ class TargetMap {
+ public:
+
+ /// The key type (the \c Arc type of the digraph).
+ typedef typename GR::Arc Key;
+ /// The value type (the \c Node type of the digraph).
+ typedef typename GR::Node Value;
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ /// \param digraph The digraph that the map belongs to.
+ explicit TargetMap(const GR& digraph) : _graph(digraph) {}
+
+ /// \brief Returns the target node of the given arc.
+ ///
+ /// Returns the target node of the given arc.
+ Value operator[](const Key& e) const {
+ return _graph.target(e);
+ }
+
+ private:
+ const GR& _graph;
+ };
+
+ /// \brief Returns a \c TargetMap class.
+ ///
+ /// This function just returns a \c TargetMap class.
+ /// \relates TargetMap
+ template <typename GR>
+ inline TargetMap<GR> targetMap(const GR& graph) {
+ return TargetMap<GR>(graph);
+ }
+
+ /// \brief Map of the "forward" directed arc view of edges in a graph.
+ ///
+ /// ForwardMap provides access for the "forward" directed arc view of
+ /// each edge in a graph, which is returned by the \c direct() function
+ /// of the graph with \c true parameter.
+ /// \tparam GR The graph type.
+ /// \see BackwardMap
+ template <typename GR>
+ class ForwardMap {
+ public:
+
+ /// The key type (the \c Edge type of the digraph).
+ typedef typename GR::Edge Key;
+ /// The value type (the \c Arc type of the digraph).
+ typedef typename GR::Arc Value;
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ /// \param graph The graph that the map belongs to.
+ explicit ForwardMap(const GR& graph) : _graph(graph) {}
+
+ /// \brief Returns the "forward" directed arc view of the given edge.
+ ///
+ /// Returns the "forward" directed arc view of the given edge.
+ Value operator[](const Key& key) const {
+ return _graph.direct(key, true);
+ }
+
+ private:
+ const GR& _graph;
+ };
+
+ /// \brief Returns a \c ForwardMap class.
+ ///
+ /// This function just returns an \c ForwardMap class.
+ /// \relates ForwardMap
+ template <typename GR>
+ inline ForwardMap<GR> forwardMap(const GR& graph) {
+ return ForwardMap<GR>(graph);
+ }
+
+ /// \brief Map of the "backward" directed arc view of edges in a graph.
+ ///
+ /// BackwardMap provides access for the "backward" directed arc view of
+ /// each edge in a graph, which is returned by the \c direct() function
+ /// of the graph with \c false parameter.
+ /// \tparam GR The graph type.
+ /// \see ForwardMap
+ template <typename GR>
+ class BackwardMap {
+ public:
+
+ /// The key type (the \c Edge type of the digraph).
+ typedef typename GR::Edge Key;
+ /// The value type (the \c Arc type of the digraph).
+ typedef typename GR::Arc Value;
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ /// \param graph The graph that the map belongs to.
+ explicit BackwardMap(const GR& graph) : _graph(graph) {}
+
+ /// \brief Returns the "backward" directed arc view of the given edge.
+ ///
+ /// Returns the "backward" directed arc view of the given edge.
+ Value operator[](const Key& key) const {
+ return _graph.direct(key, false);
+ }
+
+ private:
+ const GR& _graph;
+ };
+
+ /// \brief Returns a \c BackwardMap class
+
+ /// This function just returns a \c BackwardMap class.
+ /// \relates BackwardMap
+ template <typename GR>
+ inline BackwardMap<GR> backwardMap(const GR& graph) {
+ return BackwardMap<GR>(graph);
+ }
+
+ /// \brief Map of the in-degrees of nodes in a digraph.
+ ///
+ /// This map returns the in-degree of a node. Once it is constructed,
+ /// the degrees are stored in a standard \c NodeMap, so each query is done
+ /// in constant time. On the other hand, the values are updated automatically
+ /// whenever the digraph changes.
+ ///
+ /// \warning Besides \c addNode() and \c addArc(), a digraph structure
+ /// may provide alternative ways to modify the digraph.
+ /// The correct behavior of InDegMap is not guarantied if these additional
+ /// features are used. For example, the functions
+ /// \ref ListDigraph::changeSource() "changeSource()",
+ /// \ref ListDigraph::changeTarget() "changeTarget()" and
+ /// \ref ListDigraph::reverseArc() "reverseArc()"
+ /// of \ref ListDigraph will \e not update the degree values correctly.
+ ///
+ /// \sa OutDegMap
+ template <typename GR>
+ class InDegMap
+ : protected ItemSetTraits<GR, typename GR::Arc>
+ ::ItemNotifier::ObserverBase {
+
+ public:
+
+ /// The graph type of InDegMap
+ typedef GR Graph;
+ typedef GR Digraph;
+ /// The key type
+ typedef typename Digraph::Node Key;
+ /// The value type
+ typedef int Value;
+
+ typedef typename ItemSetTraits<Digraph, typename Digraph::Arc>
+ ::ItemNotifier::ObserverBase Parent;
+
+ private:
+
+ class AutoNodeMap
+ : public ItemSetTraits<Digraph, Key>::template Map<int>::Type {
+ public:
+
+ typedef typename ItemSetTraits<Digraph, Key>::
+ template Map<int>::Type Parent;
+
+ AutoNodeMap(const Digraph& digraph) : Parent(digraph, 0) {}
+
+ virtual void add(const Key& key) {
+ Parent::add(key);
+ Parent::set(key, 0);
+ }
+
+ virtual void add(const std::vector<Key>& keys) {
+ Parent::add(keys);
+ for (int i = 0; i < int(keys.size()); ++i) {
+ Parent::set(keys[i], 0);
+ }
+ }
+
+ virtual void build() {
+ Parent::build();
+ Key it;
+ typename Parent::Notifier* nf = Parent::notifier();
+ for (nf->first(it); it != INVALID; nf->next(it)) {
+ Parent::set(it, 0);
+ }
+ }
+ };
+
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// Constructor for creating an in-degree map.
+ explicit InDegMap(const Digraph& graph)
+ : _digraph(graph), _deg(graph) {
+ Parent::attach(_digraph.notifier(typename Digraph::Arc()));
+
+ for(typename Digraph::NodeIt it(_digraph); it != INVALID; ++it) {
+ _deg[it] = countInArcs(_digraph, it);
+ }
+ }
+
+ /// \brief Gives back the in-degree of a Node.
+ ///
+ /// Gives back the in-degree of a Node.
+ int operator[](const Key& key) const {
+ return _deg[key];
+ }
+
+ protected:
+
+ typedef typename Digraph::Arc Arc;
+
+ virtual void add(const Arc& arc) {
+ ++_deg[_digraph.target(arc)];
+ }
+
+ virtual void add(const std::vector<Arc>& arcs) {
+ for (int i = 0; i < int(arcs.size()); ++i) {
+ ++_deg[_digraph.target(arcs[i])];
+ }
+ }
+
+ virtual void erase(const Arc& arc) {
+ --_deg[_digraph.target(arc)];
+ }
+
+ virtual void erase(const std::vector<Arc>& arcs) {
+ for (int i = 0; i < int(arcs.size()); ++i) {
+ --_deg[_digraph.target(arcs[i])];
+ }
+ }
+
+ virtual void build() {
+ for(typename Digraph::NodeIt it(_digraph); it != INVALID; ++it) {
+ _deg[it] = countInArcs(_digraph, it);
+ }
+ }
+
+ virtual void clear() {
+ for(typename Digraph::NodeIt it(_digraph); it != INVALID; ++it) {
+ _deg[it] = 0;
+ }
+ }
+ private:
+
+ const Digraph& _digraph;
+ AutoNodeMap _deg;
+ };
+
+ /// \brief Map of the out-degrees of nodes in a digraph.
+ ///
+ /// This map returns the out-degree of a node. Once it is constructed,
+ /// the degrees are stored in a standard \c NodeMap, so each query is done
+ /// in constant time. On the other hand, the values are updated automatically
+ /// whenever the digraph changes.
+ ///
+ /// \warning Besides \c addNode() and \c addArc(), a digraph structure
+ /// may provide alternative ways to modify the digraph.
+ /// The correct behavior of OutDegMap is not guarantied if these additional
+ /// features are used. For example, the functions
+ /// \ref ListDigraph::changeSource() "changeSource()",
+ /// \ref ListDigraph::changeTarget() "changeTarget()" and
+ /// \ref ListDigraph::reverseArc() "reverseArc()"
+ /// of \ref ListDigraph will \e not update the degree values correctly.
+ ///
+ /// \sa InDegMap
+ template <typename GR>
+ class OutDegMap
+ : protected ItemSetTraits<GR, typename GR::Arc>
+ ::ItemNotifier::ObserverBase {
+
+ public:
+
+ /// The graph type of OutDegMap
+ typedef GR Graph;
+ typedef GR Digraph;
+ /// The key type
+ typedef typename Digraph::Node Key;
+ /// The value type
+ typedef int Value;
+
+ typedef typename ItemSetTraits<Digraph, typename Digraph::Arc>
+ ::ItemNotifier::ObserverBase Parent;
+
+ private:
+
+ class AutoNodeMap
+ : public ItemSetTraits<Digraph, Key>::template Map<int>::Type {
+ public:
+
+ typedef typename ItemSetTraits<Digraph, Key>::
+ template Map<int>::Type Parent;
+
+ AutoNodeMap(const Digraph& digraph) : Parent(digraph, 0) {}
+
+ virtual void add(const Key& key) {
+ Parent::add(key);
+ Parent::set(key, 0);
+ }
+ virtual void add(const std::vector<Key>& keys) {
+ Parent::add(keys);
+ for (int i = 0; i < int(keys.size()); ++i) {
+ Parent::set(keys[i], 0);
+ }
+ }
+ virtual void build() {
+ Parent::build();
+ Key it;
+ typename Parent::Notifier* nf = Parent::notifier();
+ for (nf->first(it); it != INVALID; nf->next(it)) {
+ Parent::set(it, 0);
+ }
+ }
+ };
+
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// Constructor for creating an out-degree map.
+ explicit OutDegMap(const Digraph& graph)
+ : _digraph(graph), _deg(graph) {
+ Parent::attach(_digraph.notifier(typename Digraph::Arc()));
+
+ for(typename Digraph::NodeIt it(_digraph); it != INVALID; ++it) {
+ _deg[it] = countOutArcs(_digraph, it);
+ }
+ }
+
+ /// \brief Gives back the out-degree of a Node.
+ ///
+ /// Gives back the out-degree of a Node.
+ int operator[](const Key& key) const {
+ return _deg[key];
+ }
+
+ protected:
+
+ typedef typename Digraph::Arc Arc;
+
+ virtual void add(const Arc& arc) {
+ ++_deg[_digraph.source(arc)];
+ }
+
+ virtual void add(const std::vector<Arc>& arcs) {
+ for (int i = 0; i < int(arcs.size()); ++i) {
+ ++_deg[_digraph.source(arcs[i])];
+ }
+ }
+
+ virtual void erase(const Arc& arc) {
+ --_deg[_digraph.source(arc)];
+ }
+
+ virtual void erase(const std::vector<Arc>& arcs) {
+ for (int i = 0; i < int(arcs.size()); ++i) {
+ --_deg[_digraph.source(arcs[i])];
+ }
+ }
+
+ virtual void build() {
+ for(typename Digraph::NodeIt it(_digraph); it != INVALID; ++it) {
+ _deg[it] = countOutArcs(_digraph, it);
+ }
+ }
+
+ virtual void clear() {
+ for(typename Digraph::NodeIt it(_digraph); it != INVALID; ++it) {
+ _deg[it] = 0;
+ }
+ }
+ private:
+
+ const Digraph& _digraph;
+ AutoNodeMap _deg;
+ };
+
+ /// \brief Potential difference map
+ ///
+ /// PotentialDifferenceMap returns the difference between the potentials of
+ /// the source and target nodes of each arc in a digraph, i.e. it returns
+ /// \code
+ /// potential[gr.target(arc)] - potential[gr.source(arc)].
+ /// \endcode
+ /// \tparam GR The digraph type.
+ /// \tparam POT A node map storing the potentials.
+ template <typename GR, typename POT>
+ class PotentialDifferenceMap {
+ public:
+ /// Key type
+ typedef typename GR::Arc Key;
+ /// Value type
+ typedef typename POT::Value Value;
+
+ /// \brief Constructor
+ ///
+ /// Contructor of the map.
+ explicit PotentialDifferenceMap(const GR& gr,
+ const POT& potential)
+ : _digraph(gr), _potential(potential) {}
+
+ /// \brief Returns the potential difference for the given arc.
+ ///
+ /// Returns the potential difference for the given arc, i.e.
+ /// \code
+ /// potential[gr.target(arc)] - potential[gr.source(arc)].
+ /// \endcode
+ Value operator[](const Key& arc) const {
+ return _potential[_digraph.target(arc)] -
+ _potential[_digraph.source(arc)];
+ }
+
+ private:
+ const GR& _digraph;
+ const POT& _potential;
+ };
+
+ /// \brief Returns a PotentialDifferenceMap.
+ ///
+ /// This function just returns a PotentialDifferenceMap.
+ /// \relates PotentialDifferenceMap
+ template <typename GR, typename POT>
+ PotentialDifferenceMap<GR, POT>
+ potentialDifferenceMap(const GR& gr, const POT& potential) {
+ return PotentialDifferenceMap<GR, POT>(gr, potential);
+ }
+
+
+ /// \brief Copy the values of a graph map to another map.
+ ///
+ /// This function copies the values of a graph map to another graph map.
+ /// \c To::Key must be equal or convertible to \c From::Key and
+ /// \c From::Value must be equal or convertible to \c To::Value.
+ ///
+ /// For example, an edge map of \c int value type can be copied to
+ /// an arc map of \c double value type in an undirected graph, but
+ /// an arc map cannot be copied to an edge map.
+ /// Note that even a \ref ConstMap can be copied to a standard graph map,
+ /// but \ref mapFill() can also be used for this purpose.
+ ///
+ /// \param gr The graph for which the maps are defined.
+ /// \param from The map from which the values have to be copied.
+ /// It must conform to the \ref concepts::ReadMap "ReadMap" concept.
+ /// \param to The map to which the values have to be copied.
+ /// It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ template <typename GR, typename From, typename To>
+ void mapCopy(const GR& gr, const From& from, To& to) {
+ typedef typename To::Key Item;
+ typedef typename ItemSetTraits<GR, Item>::ItemIt ItemIt;
+
+ for (ItemIt it(gr); it != INVALID; ++it) {
+ to.set(it, from[it]);
+ }
+ }
+
+ /// \brief Compare two graph maps.
+ ///
+ /// This function compares the values of two graph maps. It returns
+ /// \c true if the maps assign the same value for all items in the graph.
+ /// The \c Key type of the maps (\c Node, \c Arc or \c Edge) must be equal
+ /// and their \c Value types must be comparable using \c %operator==().
+ ///
+ /// \param gr The graph for which the maps are defined.
+ /// \param map1 The first map.
+ /// \param map2 The second map.
+ template <typename GR, typename Map1, typename Map2>
+ bool mapCompare(const GR& gr, const Map1& map1, const Map2& map2) {
+ typedef typename Map2::Key Item;
+ typedef typename ItemSetTraits<GR, Item>::ItemIt ItemIt;
+
+ for (ItemIt it(gr); it != INVALID; ++it) {
+ if (!(map1[it] == map2[it])) return false;
+ }
+ return true;
+ }
+
+ /// \brief Return an item having minimum value of a graph map.
+ ///
+ /// This function returns an item (\c Node, \c Arc or \c Edge) having
+ /// minimum value of the given graph map.
+ /// If the item set is empty, it returns \c INVALID.
+ ///
+ /// \param gr The graph for which the map is defined.
+ /// \param map The graph map.
+ template <typename GR, typename Map>
+ typename Map::Key mapMin(const GR& gr, const Map& map) {
+ return mapMin(gr, map, std::less<typename Map::Value>());
+ }
+
+ /// \brief Return an item having minimum value of a graph map.
+ ///
+ /// This function returns an item (\c Node, \c Arc or \c Edge) having
+ /// minimum value of the given graph map.
+ /// If the item set is empty, it returns \c INVALID.
+ ///
+ /// \param gr The graph for which the map is defined.
+ /// \param map The graph map.
+ /// \param comp Comparison function object.
+ template <typename GR, typename Map, typename Comp>
+ typename Map::Key mapMin(const GR& gr, const Map& map, const Comp& comp) {
+ typedef typename Map::Key Item;
+ typedef typename Map::Value Value;
+ typedef typename ItemSetTraits<GR, Item>::ItemIt ItemIt;
+
+ ItemIt min_item(gr);
+ if (min_item == INVALID) return INVALID;
+ Value min = map[min_item];
+ for (ItemIt it(gr); it != INVALID; ++it) {
+ if (comp(map[it], min)) {
+ min = map[it];
+ min_item = it;
+ }
+ }
+ return min_item;
+ }
+
+ /// \brief Return an item having maximum value of a graph map.
+ ///
+ /// This function returns an item (\c Node, \c Arc or \c Edge) having
+ /// maximum value of the given graph map.
+ /// If the item set is empty, it returns \c INVALID.
+ ///
+ /// \param gr The graph for which the map is defined.
+ /// \param map The graph map.
+ template <typename GR, typename Map>
+ typename Map::Key mapMax(const GR& gr, const Map& map) {
+ return mapMax(gr, map, std::less<typename Map::Value>());
+ }
+
+ /// \brief Return an item having maximum value of a graph map.
+ ///
+ /// This function returns an item (\c Node, \c Arc or \c Edge) having
+ /// maximum value of the given graph map.
+ /// If the item set is empty, it returns \c INVALID.
+ ///
+ /// \param gr The graph for which the map is defined.
+ /// \param map The graph map.
+ /// \param comp Comparison function object.
+ template <typename GR, typename Map, typename Comp>
+ typename Map::Key mapMax(const GR& gr, const Map& map, const Comp& comp) {
+ typedef typename Map::Key Item;
+ typedef typename Map::Value Value;
+ typedef typename ItemSetTraits<GR, Item>::ItemIt ItemIt;
+
+ ItemIt max_item(gr);
+ if (max_item == INVALID) return INVALID;
+ Value max = map[max_item];
+ for (ItemIt it(gr); it != INVALID; ++it) {
+ if (comp(max, map[it])) {
+ max = map[it];
+ max_item = it;
+ }
+ }
+ return max_item;
+ }
+
+ /// \brief Return the minimum value of a graph map.
+ ///
+ /// This function returns the minimum value of the given graph map.
+ /// The corresponding item set of the graph must not be empty.
+ ///
+ /// \param gr The graph for which the map is defined.
+ /// \param map The graph map.
+ template <typename GR, typename Map>
+ typename Map::Value mapMinValue(const GR& gr, const Map& map) {
+ return map[mapMin(gr, map, std::less<typename Map::Value>())];
+ }
+
+ /// \brief Return the minimum value of a graph map.
+ ///
+ /// This function returns the minimum value of the given graph map.
+ /// The corresponding item set of the graph must not be empty.
+ ///
+ /// \param gr The graph for which the map is defined.
+ /// \param map The graph map.
+ /// \param comp Comparison function object.
+ template <typename GR, typename Map, typename Comp>
+ typename Map::Value
+ mapMinValue(const GR& gr, const Map& map, const Comp& comp) {
+ return map[mapMin(gr, map, comp)];
+ }
+
+ /// \brief Return the maximum value of a graph map.
+ ///
+ /// This function returns the maximum value of the given graph map.
+ /// The corresponding item set of the graph must not be empty.
+ ///
+ /// \param gr The graph for which the map is defined.
+ /// \param map The graph map.
+ template <typename GR, typename Map>
+ typename Map::Value mapMaxValue(const GR& gr, const Map& map) {
+ return map[mapMax(gr, map, std::less<typename Map::Value>())];
+ }
+
+ /// \brief Return the maximum value of a graph map.
+ ///
+ /// This function returns the maximum value of the given graph map.
+ /// The corresponding item set of the graph must not be empty.
+ ///
+ /// \param gr The graph for which the map is defined.
+ /// \param map The graph map.
+ /// \param comp Comparison function object.
+ template <typename GR, typename Map, typename Comp>
+ typename Map::Value
+ mapMaxValue(const GR& gr, const Map& map, const Comp& comp) {
+ return map[mapMax(gr, map, comp)];
+ }
+
+ /// \brief Return an item having a specified value in a graph map.
+ ///
+ /// This function returns an item (\c Node, \c Arc or \c Edge) having
+ /// the specified assigned value in the given graph map.
+ /// If no such item exists, it returns \c INVALID.
+ ///
+ /// \param gr The graph for which the map is defined.
+ /// \param map The graph map.
+ /// \param val The value that have to be found.
+ template <typename GR, typename Map>
+ typename Map::Key
+ mapFind(const GR& gr, const Map& map, const typename Map::Value& val) {
+ typedef typename Map::Key Item;
+ typedef typename ItemSetTraits<GR, Item>::ItemIt ItemIt;
+
+ for (ItemIt it(gr); it != INVALID; ++it) {
+ if (map[it] == val) return it;
+ }
+ return INVALID;
+ }
+
+ /// \brief Return an item having value for which a certain predicate is
+ /// true in a graph map.
+ ///
+ /// This function returns an item (\c Node, \c Arc or \c Edge) having
+ /// such assigned value for which the specified predicate is true
+ /// in the given graph map.
+ /// If no such item exists, it returns \c INVALID.
+ ///
+ /// \param gr The graph for which the map is defined.
+ /// \param map The graph map.
+ /// \param pred The predicate function object.
+ template <typename GR, typename Map, typename Pred>
+ typename Map::Key
+ mapFindIf(const GR& gr, const Map& map, const Pred& pred) {
+ typedef typename Map::Key Item;
+ typedef typename ItemSetTraits<GR, Item>::ItemIt ItemIt;
+
+ for (ItemIt it(gr); it != INVALID; ++it) {
+ if (pred(map[it])) return it;
+ }
+ return INVALID;
+ }
+
+ /// \brief Return the number of items having a specified value in a
+ /// graph map.
+ ///
+ /// This function returns the number of items (\c Node, \c Arc or \c Edge)
+ /// having the specified assigned value in the given graph map.
+ ///
+ /// \param gr The graph for which the map is defined.
+ /// \param map The graph map.
+ /// \param val The value that have to be counted.
+ template <typename GR, typename Map>
+ int mapCount(const GR& gr, const Map& map, const typename Map::Value& val) {
+ typedef typename Map::Key Item;
+ typedef typename ItemSetTraits<GR, Item>::ItemIt ItemIt;
+
+ int cnt = 0;
+ for (ItemIt it(gr); it != INVALID; ++it) {
+ if (map[it] == val) ++cnt;
+ }
+ return cnt;
+ }
+
+ /// \brief Return the number of items having values for which a certain
+ /// predicate is true in a graph map.
+ ///
+ /// This function returns the number of items (\c Node, \c Arc or \c Edge)
+ /// having such assigned values for which the specified predicate is true
+ /// in the given graph map.
+ ///
+ /// \param gr The graph for which the map is defined.
+ /// \param map The graph map.
+ /// \param pred The predicate function object.
+ template <typename GR, typename Map, typename Pred>
+ int mapCountIf(const GR& gr, const Map& map, const Pred& pred) {
+ typedef typename Map::Key Item;
+ typedef typename ItemSetTraits<GR, Item>::ItemIt ItemIt;
+
+ int cnt = 0;
+ for (ItemIt it(gr); it != INVALID; ++it) {
+ if (pred(map[it])) ++cnt;
+ }
+ return cnt;
+ }
+
+ /// \brief Fill a graph map with a certain value.
+ ///
+ /// This function sets the specified value for all items (\c Node,
+ /// \c Arc or \c Edge) in the given graph map.
+ ///
+ /// \param gr The graph for which the map is defined.
+ /// \param map The graph map. It must conform to the
+ /// \ref concepts::WriteMap "WriteMap" concept.
+ /// \param val The value.
+ template <typename GR, typename Map>
+ void mapFill(const GR& gr, Map& map, const typename Map::Value& val) {
+ typedef typename Map::Key Item;
+ typedef typename ItemSetTraits<GR, Item>::ItemIt ItemIt;
+
+ for (ItemIt it(gr); it != INVALID; ++it) {
+ map.set(it, val);
+ }
+ }
+
+ /// @}
+}
+
+#endif // LEMON_MAPS_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/matching.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/matching.h
new file mode 100644
index 00000000000..5ee23412835
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/matching.h
@@ -0,0 +1,3505 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_MATCHING_H
+#define LEMON_MATCHING_H
+
+#include <vector>
+#include <queue>
+#include <set>
+#include <limits>
+
+#include <lemon/core.h>
+#include <lemon/unionfind.h>
+#include <lemon/bin_heap.h>
+#include <lemon/maps.h>
+#include <lemon/fractional_matching.h>
+
+///\ingroup matching
+///\file
+///\brief Maximum matching algorithms in general graphs.
+
+namespace lemon {
+
+ /// \ingroup matching
+ ///
+ /// \brief Maximum cardinality matching in general graphs
+ ///
+ /// This class implements Edmonds' alternating forest matching algorithm
+ /// for finding a maximum cardinality matching in a general undirected graph.
+ /// It can be started from an arbitrary initial matching
+ /// (the default is the empty one).
+ ///
+ /// The dual solution of the problem is a map of the nodes to
+ /// \ref MaxMatching::Status "Status", having values \c EVEN (or \c D),
+ /// \c ODD (or \c A) and \c MATCHED (or \c C) defining the Gallai-Edmonds
+ /// decomposition of the graph. The nodes in \c EVEN/D induce a subgraph
+ /// with factor-critical components, the nodes in \c ODD/A form the
+ /// canonical barrier, and the nodes in \c MATCHED/C induce a graph having
+ /// a perfect matching. The number of the factor-critical components
+ /// minus the number of barrier nodes is a lower bound on the
+ /// unmatched nodes, and the matching is optimal if and only if this bound is
+ /// tight. This decomposition can be obtained using \ref status() or
+ /// \ref statusMap() after running the algorithm.
+ ///
+ /// \tparam GR The undirected graph type the algorithm runs on.
+ template <typename GR>
+ class MaxMatching {
+ public:
+
+ /// The graph type of the algorithm
+ typedef GR Graph;
+ /// The type of the matching map
+ typedef typename Graph::template NodeMap<typename Graph::Arc>
+ MatchingMap;
+
+ ///\brief Status constants for Gallai-Edmonds decomposition.
+ ///
+ ///These constants are used for indicating the Gallai-Edmonds
+ ///decomposition of a graph. The nodes with status \c EVEN (or \c D)
+ ///induce a subgraph with factor-critical components, the nodes with
+ ///status \c ODD (or \c A) form the canonical barrier, and the nodes
+ ///with status \c MATCHED (or \c C) induce a subgraph having a
+ ///perfect matching.
+ enum Status {
+ EVEN = 1, ///< = 1. (\c D is an alias for \c EVEN.)
+ D = 1,
+ MATCHED = 0, ///< = 0. (\c C is an alias for \c MATCHED.)
+ C = 0,
+ ODD = -1, ///< = -1. (\c A is an alias for \c ODD.)
+ A = -1,
+ UNMATCHED = -2 ///< = -2.
+ };
+
+ /// The type of the status map
+ typedef typename Graph::template NodeMap<Status> StatusMap;
+
+ private:
+
+ TEMPLATE_GRAPH_TYPEDEFS(Graph);
+
+ typedef UnionFindEnum<IntNodeMap> BlossomSet;
+ typedef ExtendFindEnum<IntNodeMap> TreeSet;
+ typedef RangeMap<Node> NodeIntMap;
+ typedef MatchingMap EarMap;
+ typedef std::vector<Node> NodeQueue;
+
+ const Graph& _graph;
+ MatchingMap* _matching;
+ StatusMap* _status;
+
+ EarMap* _ear;
+
+ IntNodeMap* _blossom_set_index;
+ BlossomSet* _blossom_set;
+ NodeIntMap* _blossom_rep;
+
+ IntNodeMap* _tree_set_index;
+ TreeSet* _tree_set;
+
+ NodeQueue _node_queue;
+ int _process, _postpone, _last;
+
+ int _node_num;
+
+ private:
+
+ void createStructures() {
+ _node_num = countNodes(_graph);
+ if (!_matching) {
+ _matching = new MatchingMap(_graph);
+ }
+ if (!_status) {
+ _status = new StatusMap(_graph);
+ }
+ if (!_ear) {
+ _ear = new EarMap(_graph);
+ }
+ if (!_blossom_set) {
+ _blossom_set_index = new IntNodeMap(_graph);
+ _blossom_set = new BlossomSet(*_blossom_set_index);
+ }
+ if (!_blossom_rep) {
+ _blossom_rep = new NodeIntMap(_node_num);
+ }
+ if (!_tree_set) {
+ _tree_set_index = new IntNodeMap(_graph);
+ _tree_set = new TreeSet(*_tree_set_index);
+ }
+ _node_queue.resize(_node_num);
+ }
+
+ void destroyStructures() {
+ if (_matching) {
+ delete _matching;
+ }
+ if (_status) {
+ delete _status;
+ }
+ if (_ear) {
+ delete _ear;
+ }
+ if (_blossom_set) {
+ delete _blossom_set;
+ delete _blossom_set_index;
+ }
+ if (_blossom_rep) {
+ delete _blossom_rep;
+ }
+ if (_tree_set) {
+ delete _tree_set_index;
+ delete _tree_set;
+ }
+ }
+
+ void processDense(const Node& n) {
+ _process = _postpone = _last = 0;
+ _node_queue[_last++] = n;
+
+ while (_process != _last) {
+ Node u = _node_queue[_process++];
+ for (OutArcIt a(_graph, u); a != INVALID; ++a) {
+ Node v = _graph.target(a);
+ if ((*_status)[v] == MATCHED) {
+ extendOnArc(a);
+ } else if ((*_status)[v] == UNMATCHED) {
+ augmentOnArc(a);
+ return;
+ }
+ }
+ }
+
+ while (_postpone != _last) {
+ Node u = _node_queue[_postpone++];
+
+ for (OutArcIt a(_graph, u); a != INVALID ; ++a) {
+ Node v = _graph.target(a);
+
+ if ((*_status)[v] == EVEN) {
+ if (_blossom_set->find(u) != _blossom_set->find(v)) {
+ shrinkOnEdge(a);
+ }
+ }
+
+ while (_process != _last) {
+ Node w = _node_queue[_process++];
+ for (OutArcIt b(_graph, w); b != INVALID; ++b) {
+ Node x = _graph.target(b);
+ if ((*_status)[x] == MATCHED) {
+ extendOnArc(b);
+ } else if ((*_status)[x] == UNMATCHED) {
+ augmentOnArc(b);
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void processSparse(const Node& n) {
+ _process = _last = 0;
+ _node_queue[_last++] = n;
+ while (_process != _last) {
+ Node u = _node_queue[_process++];
+ for (OutArcIt a(_graph, u); a != INVALID; ++a) {
+ Node v = _graph.target(a);
+
+ if ((*_status)[v] == EVEN) {
+ if (_blossom_set->find(u) != _blossom_set->find(v)) {
+ shrinkOnEdge(a);
+ }
+ } else if ((*_status)[v] == MATCHED) {
+ extendOnArc(a);
+ } else if ((*_status)[v] == UNMATCHED) {
+ augmentOnArc(a);
+ return;
+ }
+ }
+ }
+ }
+
+ void shrinkOnEdge(const Edge& e) {
+ Node nca = INVALID;
+
+ {
+ std::set<Node> left_set, right_set;
+
+ Node left = (*_blossom_rep)[_blossom_set->find(_graph.u(e))];
+ left_set.insert(left);
+
+ Node right = (*_blossom_rep)[_blossom_set->find(_graph.v(e))];
+ right_set.insert(right);
+
+ while (true) {
+ if ((*_matching)[left] == INVALID) break;
+ left = _graph.target((*_matching)[left]);
+ left = (*_blossom_rep)[_blossom_set->
+ find(_graph.target((*_ear)[left]))];
+ if (right_set.find(left) != right_set.end()) {
+ nca = left;
+ break;
+ }
+ left_set.insert(left);
+
+ if ((*_matching)[right] == INVALID) break;
+ right = _graph.target((*_matching)[right]);
+ right = (*_blossom_rep)[_blossom_set->
+ find(_graph.target((*_ear)[right]))];
+ if (left_set.find(right) != left_set.end()) {
+ nca = right;
+ break;
+ }
+ right_set.insert(right);
+ }
+
+ if (nca == INVALID) {
+ if ((*_matching)[left] == INVALID) {
+ nca = right;
+ while (left_set.find(nca) == left_set.end()) {
+ nca = _graph.target((*_matching)[nca]);
+ nca =(*_blossom_rep)[_blossom_set->
+ find(_graph.target((*_ear)[nca]))];
+ }
+ } else {
+ nca = left;
+ while (right_set.find(nca) == right_set.end()) {
+ nca = _graph.target((*_matching)[nca]);
+ nca = (*_blossom_rep)[_blossom_set->
+ find(_graph.target((*_ear)[nca]))];
+ }
+ }
+ }
+ }
+
+ {
+
+ Node node = _graph.u(e);
+ Arc arc = _graph.direct(e, true);
+ Node base = (*_blossom_rep)[_blossom_set->find(node)];
+
+ while (base != nca) {
+ (*_ear)[node] = arc;
+
+ Node n = node;
+ while (n != base) {
+ n = _graph.target((*_matching)[n]);
+ Arc a = (*_ear)[n];
+ n = _graph.target(a);
+ (*_ear)[n] = _graph.oppositeArc(a);
+ }
+ node = _graph.target((*_matching)[base]);
+ _tree_set->erase(base);
+ _tree_set->erase(node);
+ _blossom_set->insert(node, _blossom_set->find(base));
+ (*_status)[node] = EVEN;
+ _node_queue[_last++] = node;
+ arc = _graph.oppositeArc((*_ear)[node]);
+ node = _graph.target((*_ear)[node]);
+ base = (*_blossom_rep)[_blossom_set->find(node)];
+ _blossom_set->join(_graph.target(arc), base);
+ }
+ }
+
+ (*_blossom_rep)[_blossom_set->find(nca)] = nca;
+
+ {
+
+ Node node = _graph.v(e);
+ Arc arc = _graph.direct(e, false);
+ Node base = (*_blossom_rep)[_blossom_set->find(node)];
+
+ while (base != nca) {
+ (*_ear)[node] = arc;
+
+ Node n = node;
+ while (n != base) {
+ n = _graph.target((*_matching)[n]);
+ Arc a = (*_ear)[n];
+ n = _graph.target(a);
+ (*_ear)[n] = _graph.oppositeArc(a);
+ }
+ node = _graph.target((*_matching)[base]);
+ _tree_set->erase(base);
+ _tree_set->erase(node);
+ _blossom_set->insert(node, _blossom_set->find(base));
+ (*_status)[node] = EVEN;
+ _node_queue[_last++] = node;
+ arc = _graph.oppositeArc((*_ear)[node]);
+ node = _graph.target((*_ear)[node]);
+ base = (*_blossom_rep)[_blossom_set->find(node)];
+ _blossom_set->join(_graph.target(arc), base);
+ }
+ }
+
+ (*_blossom_rep)[_blossom_set->find(nca)] = nca;
+ }
+
+ void extendOnArc(const Arc& a) {
+ Node base = _graph.source(a);
+ Node odd = _graph.target(a);
+
+ (*_ear)[odd] = _graph.oppositeArc(a);
+ Node even = _graph.target((*_matching)[odd]);
+ (*_blossom_rep)[_blossom_set->insert(even)] = even;
+ (*_status)[odd] = ODD;
+ (*_status)[even] = EVEN;
+ int tree = _tree_set->find((*_blossom_rep)[_blossom_set->find(base)]);
+ _tree_set->insert(odd, tree);
+ _tree_set->insert(even, tree);
+ _node_queue[_last++] = even;
+
+ }
+
+ void augmentOnArc(const Arc& a) {
+ Node even = _graph.source(a);
+ Node odd = _graph.target(a);
+
+ int tree = _tree_set->find((*_blossom_rep)[_blossom_set->find(even)]);
+
+ (*_matching)[odd] = _graph.oppositeArc(a);
+ (*_status)[odd] = MATCHED;
+
+ Arc arc = (*_matching)[even];
+ (*_matching)[even] = a;
+
+ while (arc != INVALID) {
+ odd = _graph.target(arc);
+ arc = (*_ear)[odd];
+ even = _graph.target(arc);
+ (*_matching)[odd] = arc;
+ arc = (*_matching)[even];
+ (*_matching)[even] = _graph.oppositeArc((*_matching)[odd]);
+ }
+
+ for (typename TreeSet::ItemIt it(*_tree_set, tree);
+ it != INVALID; ++it) {
+ if ((*_status)[it] == ODD) {
+ (*_status)[it] = MATCHED;
+ } else {
+ int blossom = _blossom_set->find(it);
+ for (typename BlossomSet::ItemIt jt(*_blossom_set, blossom);
+ jt != INVALID; ++jt) {
+ (*_status)[jt] = MATCHED;
+ }
+ _blossom_set->eraseClass(blossom);
+ }
+ }
+ _tree_set->eraseClass(tree);
+
+ }
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ MaxMatching(const Graph& graph)
+ : _graph(graph), _matching(0), _status(0), _ear(0),
+ _blossom_set_index(0), _blossom_set(0), _blossom_rep(0),
+ _tree_set_index(0), _tree_set(0) {}
+
+ ~MaxMatching() {
+ destroyStructures();
+ }
+
+ /// \name Execution Control
+ /// The simplest way to execute the algorithm is to use the
+ /// \c run() member function.\n
+ /// If you need better control on the execution, you have to call
+ /// one of the functions \ref init(), \ref greedyInit() or
+ /// \ref matchingInit() first, then you can start the algorithm with
+ /// \ref startSparse() or \ref startDense().
+
+ ///@{
+
+ /// \brief Set the initial matching to the empty matching.
+ ///
+ /// This function sets the initial matching to the empty matching.
+ void init() {
+ createStructures();
+ for(NodeIt n(_graph); n != INVALID; ++n) {
+ (*_matching)[n] = INVALID;
+ (*_status)[n] = UNMATCHED;
+ }
+ }
+
+ /// \brief Find an initial matching in a greedy way.
+ ///
+ /// This function finds an initial matching in a greedy way.
+ void greedyInit() {
+ createStructures();
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ (*_matching)[n] = INVALID;
+ (*_status)[n] = UNMATCHED;
+ }
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ if ((*_matching)[n] == INVALID) {
+ for (OutArcIt a(_graph, n); a != INVALID ; ++a) {
+ Node v = _graph.target(a);
+ if ((*_matching)[v] == INVALID && v != n) {
+ (*_matching)[n] = a;
+ (*_status)[n] = MATCHED;
+ (*_matching)[v] = _graph.oppositeArc(a);
+ (*_status)[v] = MATCHED;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+
+ /// \brief Initialize the matching from a map.
+ ///
+ /// This function initializes the matching from a \c bool valued edge
+ /// map. This map should have the property that there are no two incident
+ /// edges with \c true value, i.e. it really contains a matching.
+ /// \return \c true if the map contains a matching.
+ template <typename MatchingMap>
+ bool matchingInit(const MatchingMap& matching) {
+ createStructures();
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ (*_matching)[n] = INVALID;
+ (*_status)[n] = UNMATCHED;
+ }
+ for(EdgeIt e(_graph); e!=INVALID; ++e) {
+ if (matching[e]) {
+
+ Node u = _graph.u(e);
+ if ((*_matching)[u] != INVALID) return false;
+ (*_matching)[u] = _graph.direct(e, true);
+ (*_status)[u] = MATCHED;
+
+ Node v = _graph.v(e);
+ if ((*_matching)[v] != INVALID) return false;
+ (*_matching)[v] = _graph.direct(e, false);
+ (*_status)[v] = MATCHED;
+ }
+ }
+ return true;
+ }
+
+ /// \brief Start Edmonds' algorithm
+ ///
+ /// This function runs the original Edmonds' algorithm.
+ ///
+ /// \pre \ref init(), \ref greedyInit() or \ref matchingInit() must be
+ /// called before using this function.
+ void startSparse() {
+ for(NodeIt n(_graph); n != INVALID; ++n) {
+ if ((*_status)[n] == UNMATCHED) {
+ (*_blossom_rep)[_blossom_set->insert(n)] = n;
+ _tree_set->insert(n);
+ (*_status)[n] = EVEN;
+ processSparse(n);
+ }
+ }
+ }
+
+ /// \brief Start Edmonds' algorithm with a heuristic improvement
+ /// for dense graphs
+ ///
+ /// This function runs Edmonds' algorithm with a heuristic of postponing
+ /// shrinks, therefore resulting in a faster algorithm for dense graphs.
+ ///
+ /// \pre \ref init(), \ref greedyInit() or \ref matchingInit() must be
+ /// called before using this function.
+ void startDense() {
+ for(NodeIt n(_graph); n != INVALID; ++n) {
+ if ((*_status)[n] == UNMATCHED) {
+ (*_blossom_rep)[_blossom_set->insert(n)] = n;
+ _tree_set->insert(n);
+ (*_status)[n] = EVEN;
+ processDense(n);
+ }
+ }
+ }
+
+
+ /// \brief Run Edmonds' algorithm
+ ///
+ /// This function runs Edmonds' algorithm. An additional heuristic of
+ /// postponing shrinks is used for relatively dense graphs
+ /// (for which <tt>m>=2*n</tt> holds).
+ void run() {
+ if (countEdges(_graph) < 2 * countNodes(_graph)) {
+ greedyInit();
+ startSparse();
+ } else {
+ init();
+ startDense();
+ }
+ }
+
+ /// @}
+
+ /// \name Primal Solution
+ /// Functions to get the primal solution, i.e. the maximum matching.
+
+ /// @{
+
+ /// \brief Return the size (cardinality) of the matching.
+ ///
+ /// This function returns the size (cardinality) of the current matching.
+ /// After run() it returns the size of the maximum matching in the graph.
+ int matchingSize() const {
+ int size = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ if ((*_matching)[n] != INVALID) {
+ ++size;
+ }
+ }
+ return size / 2;
+ }
+
+ /// \brief Return \c true if the given edge is in the matching.
+ ///
+ /// This function returns \c true if the given edge is in the current
+ /// matching.
+ bool matching(const Edge& edge) const {
+ return edge == (*_matching)[_graph.u(edge)];
+ }
+
+ /// \brief Return the matching arc (or edge) incident to the given node.
+ ///
+ /// This function returns the matching arc (or edge) incident to the
+ /// given node in the current matching or \c INVALID if the node is
+ /// not covered by the matching.
+ Arc matching(const Node& n) const {
+ return (*_matching)[n];
+ }
+
+ /// \brief Return a const reference to the matching map.
+ ///
+ /// This function returns a const reference to a node map that stores
+ /// the matching arc (or edge) incident to each node.
+ const MatchingMap& matchingMap() const {
+ return *_matching;
+ }
+
+ /// \brief Return the mate of the given node.
+ ///
+ /// This function returns the mate of the given node in the current
+ /// matching or \c INVALID if the node is not covered by the matching.
+ Node mate(const Node& n) const {
+ return (*_matching)[n] != INVALID ?
+ _graph.target((*_matching)[n]) : INVALID;
+ }
+
+ /// @}
+
+ /// \name Dual Solution
+ /// Functions to get the dual solution, i.e. the Gallai-Edmonds
+ /// decomposition.
+
+ /// @{
+
+ /// \brief Return the status of the given node in the Edmonds-Gallai
+ /// decomposition.
+ ///
+ /// This function returns the \ref Status "status" of the given node
+ /// in the Edmonds-Gallai decomposition.
+ Status status(const Node& n) const {
+ return (*_status)[n];
+ }
+
+ /// \brief Return a const reference to the status map, which stores
+ /// the Edmonds-Gallai decomposition.
+ ///
+ /// This function returns a const reference to a node map that stores the
+ /// \ref Status "status" of each node in the Edmonds-Gallai decomposition.
+ const StatusMap& statusMap() const {
+ return *_status;
+ }
+
+ /// \brief Return \c true if the given node is in the barrier.
+ ///
+ /// This function returns \c true if the given node is in the barrier.
+ bool barrier(const Node& n) const {
+ return (*_status)[n] == ODD;
+ }
+
+ /// @}
+
+ };
+
+ /// \ingroup matching
+ ///
+ /// \brief Weighted matching in general graphs
+ ///
+ /// This class provides an efficient implementation of Edmond's
+ /// maximum weighted matching algorithm. The implementation is based
+ /// on extensive use of priority queues and provides
+ /// \f$O(nm\log n)\f$ time complexity.
+ ///
+ /// The maximum weighted matching problem is to find a subset of the
+ /// edges in an undirected graph with maximum overall weight for which
+ /// each node has at most one incident edge.
+ /// It can be formulated with the following linear program.
+ /// \f[ \sum_{e \in \delta(u)}x_e \le 1 \quad \forall u\in V\f]
+ /** \f[ \sum_{e \in \gamma(B)}x_e \le \frac{\vert B \vert - 1}{2}
+ \quad \forall B\in\mathcal{O}\f] */
+ /// \f[x_e \ge 0\quad \forall e\in E\f]
+ /// \f[\max \sum_{e\in E}x_ew_e\f]
+ /// where \f$\delta(X)\f$ is the set of edges incident to a node in
+ /// \f$X\f$, \f$\gamma(X)\f$ is the set of edges with both ends in
+ /// \f$X\f$ and \f$\mathcal{O}\f$ is the set of odd cardinality
+ /// subsets of the nodes.
+ ///
+ /// The algorithm calculates an optimal matching and a proof of the
+ /// optimality. The solution of the dual problem can be used to check
+ /// the result of the algorithm. The dual linear problem is the
+ /// following.
+ /** \f[ y_u + y_v + \sum_{B \in \mathcal{O}, uv \in \gamma(B)}
+ z_B \ge w_{uv} \quad \forall uv\in E\f] */
+ /// \f[y_u \ge 0 \quad \forall u \in V\f]
+ /// \f[z_B \ge 0 \quad \forall B \in \mathcal{O}\f]
+ /** \f[\min \sum_{u \in V}y_u + \sum_{B \in \mathcal{O}}
+ \frac{\vert B \vert - 1}{2}z_B\f] */
+ ///
+ /// The algorithm can be executed with the run() function.
+ /// After it the matching (the primal solution) and the dual solution
+ /// can be obtained using the query functions and the
+ /// \ref MaxWeightedMatching::BlossomIt "BlossomIt" nested class,
+ /// which is able to iterate on the nodes of a blossom.
+ /// If the value type is integer, then the dual solution is multiplied
+ /// by \ref MaxWeightedMatching::dualScale "4".
+ ///
+ /// \tparam GR The undirected graph type the algorithm runs on.
+ /// \tparam WM The type edge weight map. The default type is
+ /// \ref concepts::Graph::EdgeMap "GR::EdgeMap<int>".
+#ifdef DOXYGEN
+ template <typename GR, typename WM>
+#else
+ template <typename GR,
+ typename WM = typename GR::template EdgeMap<int> >
+#endif
+ class MaxWeightedMatching {
+ public:
+
+ /// The graph type of the algorithm
+ typedef GR Graph;
+ /// The type of the edge weight map
+ typedef WM WeightMap;
+ /// The value type of the edge weights
+ typedef typename WeightMap::Value Value;
+
+ /// The type of the matching map
+ typedef typename Graph::template NodeMap<typename Graph::Arc>
+ MatchingMap;
+
+ /// \brief Scaling factor for dual solution
+ ///
+ /// Scaling factor for dual solution. It is equal to 4 or 1
+ /// according to the value type.
+ static const int dualScale =
+ std::numeric_limits<Value>::is_integer ? 4 : 1;
+
+ private:
+
+ TEMPLATE_GRAPH_TYPEDEFS(Graph);
+
+ typedef typename Graph::template NodeMap<Value> NodePotential;
+ typedef std::vector<Node> BlossomNodeList;
+
+ struct BlossomVariable {
+ int begin, end;
+ Value value;
+
+ BlossomVariable(int _begin, int _end, Value _value)
+ : begin(_begin), end(_end), value(_value) {}
+
+ };
+
+ typedef std::vector<BlossomVariable> BlossomPotential;
+
+ const Graph& _graph;
+ const WeightMap& _weight;
+
+ MatchingMap* _matching;
+
+ NodePotential* _node_potential;
+
+ BlossomPotential _blossom_potential;
+ BlossomNodeList _blossom_node_list;
+
+ int _node_num;
+ int _blossom_num;
+
+ typedef RangeMap<int> IntIntMap;
+
+ enum Status {
+ EVEN = -1, MATCHED = 0, ODD = 1
+ };
+
+ typedef HeapUnionFind<Value, IntNodeMap> BlossomSet;
+ struct BlossomData {
+ int tree;
+ Status status;
+ Arc pred, next;
+ Value pot, offset;
+ Node base;
+ };
+
+ IntNodeMap *_blossom_index;
+ BlossomSet *_blossom_set;
+ RangeMap<BlossomData>* _blossom_data;
+
+ IntNodeMap *_node_index;
+ IntArcMap *_node_heap_index;
+
+ struct NodeData {
+
+ NodeData(IntArcMap& node_heap_index)
+ : heap(node_heap_index) {}
+
+ int blossom;
+ Value pot;
+ BinHeap<Value, IntArcMap> heap;
+ std::map<int, Arc> heap_index;
+
+ int tree;
+ };
+
+ RangeMap<NodeData>* _node_data;
+
+ typedef ExtendFindEnum<IntIntMap> TreeSet;
+
+ IntIntMap *_tree_set_index;
+ TreeSet *_tree_set;
+
+ IntNodeMap *_delta1_index;
+ BinHeap<Value, IntNodeMap> *_delta1;
+
+ IntIntMap *_delta2_index;
+ BinHeap<Value, IntIntMap> *_delta2;
+
+ IntEdgeMap *_delta3_index;
+ BinHeap<Value, IntEdgeMap> *_delta3;
+
+ IntIntMap *_delta4_index;
+ BinHeap<Value, IntIntMap> *_delta4;
+
+ Value _delta_sum;
+ int _unmatched;
+
+ typedef MaxWeightedFractionalMatching<Graph, WeightMap> FractionalMatching;
+ FractionalMatching *_fractional;
+
+ void createStructures() {
+ _node_num = countNodes(_graph);
+ _blossom_num = _node_num * 3 / 2;
+
+ if (!_matching) {
+ _matching = new MatchingMap(_graph);
+ }
+
+ if (!_node_potential) {
+ _node_potential = new NodePotential(_graph);
+ }
+
+ if (!_blossom_set) {
+ _blossom_index = new IntNodeMap(_graph);
+ _blossom_set = new BlossomSet(*_blossom_index);
+ _blossom_data = new RangeMap<BlossomData>(_blossom_num);
+ } else if (_blossom_data->size() != _blossom_num) {
+ delete _blossom_data;
+ _blossom_data = new RangeMap<BlossomData>(_blossom_num);
+ }
+
+ if (!_node_index) {
+ _node_index = new IntNodeMap(_graph);
+ _node_heap_index = new IntArcMap(_graph);
+ _node_data = new RangeMap<NodeData>(_node_num,
+ NodeData(*_node_heap_index));
+ } else {
+ delete _node_data;
+ _node_data = new RangeMap<NodeData>(_node_num,
+ NodeData(*_node_heap_index));
+ }
+
+ if (!_tree_set) {
+ _tree_set_index = new IntIntMap(_blossom_num);
+ _tree_set = new TreeSet(*_tree_set_index);
+ } else {
+ _tree_set_index->resize(_blossom_num);
+ }
+
+ if (!_delta1) {
+ _delta1_index = new IntNodeMap(_graph);
+ _delta1 = new BinHeap<Value, IntNodeMap>(*_delta1_index);
+ }
+
+ if (!_delta2) {
+ _delta2_index = new IntIntMap(_blossom_num);
+ _delta2 = new BinHeap<Value, IntIntMap>(*_delta2_index);
+ } else {
+ _delta2_index->resize(_blossom_num);
+ }
+
+ if (!_delta3) {
+ _delta3_index = new IntEdgeMap(_graph);
+ _delta3 = new BinHeap<Value, IntEdgeMap>(*_delta3_index);
+ }
+
+ if (!_delta4) {
+ _delta4_index = new IntIntMap(_blossom_num);
+ _delta4 = new BinHeap<Value, IntIntMap>(*_delta4_index);
+ } else {
+ _delta4_index->resize(_blossom_num);
+ }
+ }
+
+ void destroyStructures() {
+ if (_matching) {
+ delete _matching;
+ }
+ if (_node_potential) {
+ delete _node_potential;
+ }
+ if (_blossom_set) {
+ delete _blossom_index;
+ delete _blossom_set;
+ delete _blossom_data;
+ }
+
+ if (_node_index) {
+ delete _node_index;
+ delete _node_heap_index;
+ delete _node_data;
+ }
+
+ if (_tree_set) {
+ delete _tree_set_index;
+ delete _tree_set;
+ }
+ if (_delta1) {
+ delete _delta1_index;
+ delete _delta1;
+ }
+ if (_delta2) {
+ delete _delta2_index;
+ delete _delta2;
+ }
+ if (_delta3) {
+ delete _delta3_index;
+ delete _delta3;
+ }
+ if (_delta4) {
+ delete _delta4_index;
+ delete _delta4;
+ }
+ }
+
+ void matchedToEven(int blossom, int tree) {
+ if (_delta2->state(blossom) == _delta2->IN_HEAP) {
+ _delta2->erase(blossom);
+ }
+
+ if (!_blossom_set->trivial(blossom)) {
+ (*_blossom_data)[blossom].pot -=
+ 2 * (_delta_sum - (*_blossom_data)[blossom].offset);
+ }
+
+ for (typename BlossomSet::ItemIt n(*_blossom_set, blossom);
+ n != INVALID; ++n) {
+
+ _blossom_set->increase(n, std::numeric_limits<Value>::max());
+ int ni = (*_node_index)[n];
+
+ (*_node_data)[ni].heap.clear();
+ (*_node_data)[ni].heap_index.clear();
+
+ (*_node_data)[ni].pot += _delta_sum - (*_blossom_data)[blossom].offset;
+
+ _delta1->push(n, (*_node_data)[ni].pot);
+
+ for (InArcIt e(_graph, n); e != INVALID; ++e) {
+ Node v = _graph.source(e);
+ int vb = _blossom_set->find(v);
+ int vi = (*_node_index)[v];
+
+ Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot -
+ dualScale * _weight[e];
+
+ if ((*_blossom_data)[vb].status == EVEN) {
+ if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) {
+ _delta3->push(e, rw / 2);
+ }
+ } else {
+ typename std::map<int, Arc>::iterator it =
+ (*_node_data)[vi].heap_index.find(tree);
+
+ if (it != (*_node_data)[vi].heap_index.end()) {
+ if ((*_node_data)[vi].heap[it->second] > rw) {
+ (*_node_data)[vi].heap.replace(it->second, e);
+ (*_node_data)[vi].heap.decrease(e, rw);
+ it->second = e;
+ }
+ } else {
+ (*_node_data)[vi].heap.push(e, rw);
+ (*_node_data)[vi].heap_index.insert(std::make_pair(tree, e));
+ }
+
+ if ((*_blossom_set)[v] > (*_node_data)[vi].heap.prio()) {
+ _blossom_set->decrease(v, (*_node_data)[vi].heap.prio());
+
+ if ((*_blossom_data)[vb].status == MATCHED) {
+ if (_delta2->state(vb) != _delta2->IN_HEAP) {
+ _delta2->push(vb, _blossom_set->classPrio(vb) -
+ (*_blossom_data)[vb].offset);
+ } else if ((*_delta2)[vb] > _blossom_set->classPrio(vb) -
+ (*_blossom_data)[vb].offset) {
+ _delta2->decrease(vb, _blossom_set->classPrio(vb) -
+ (*_blossom_data)[vb].offset);
+ }
+ }
+ }
+ }
+ }
+ }
+ (*_blossom_data)[blossom].offset = 0;
+ }
+
+ void matchedToOdd(int blossom) {
+ if (_delta2->state(blossom) == _delta2->IN_HEAP) {
+ _delta2->erase(blossom);
+ }
+ (*_blossom_data)[blossom].offset += _delta_sum;
+ if (!_blossom_set->trivial(blossom)) {
+ _delta4->push(blossom, (*_blossom_data)[blossom].pot / 2 +
+ (*_blossom_data)[blossom].offset);
+ }
+ }
+
+ void evenToMatched(int blossom, int tree) {
+ if (!_blossom_set->trivial(blossom)) {
+ (*_blossom_data)[blossom].pot += 2 * _delta_sum;
+ }
+
+ for (typename BlossomSet::ItemIt n(*_blossom_set, blossom);
+ n != INVALID; ++n) {
+ int ni = (*_node_index)[n];
+ (*_node_data)[ni].pot -= _delta_sum;
+
+ _delta1->erase(n);
+
+ for (InArcIt e(_graph, n); e != INVALID; ++e) {
+ Node v = _graph.source(e);
+ int vb = _blossom_set->find(v);
+ int vi = (*_node_index)[v];
+
+ Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot -
+ dualScale * _weight[e];
+
+ if (vb == blossom) {
+ if (_delta3->state(e) == _delta3->IN_HEAP) {
+ _delta3->erase(e);
+ }
+ } else if ((*_blossom_data)[vb].status == EVEN) {
+
+ if (_delta3->state(e) == _delta3->IN_HEAP) {
+ _delta3->erase(e);
+ }
+
+ int vt = _tree_set->find(vb);
+
+ if (vt != tree) {
+
+ Arc r = _graph.oppositeArc(e);
+
+ typename std::map<int, Arc>::iterator it =
+ (*_node_data)[ni].heap_index.find(vt);
+
+ if (it != (*_node_data)[ni].heap_index.end()) {
+ if ((*_node_data)[ni].heap[it->second] > rw) {
+ (*_node_data)[ni].heap.replace(it->second, r);
+ (*_node_data)[ni].heap.decrease(r, rw);
+ it->second = r;
+ }
+ } else {
+ (*_node_data)[ni].heap.push(r, rw);
+ (*_node_data)[ni].heap_index.insert(std::make_pair(vt, r));
+ }
+
+ if ((*_blossom_set)[n] > (*_node_data)[ni].heap.prio()) {
+ _blossom_set->decrease(n, (*_node_data)[ni].heap.prio());
+
+ if (_delta2->state(blossom) != _delta2->IN_HEAP) {
+ _delta2->push(blossom, _blossom_set->classPrio(blossom) -
+ (*_blossom_data)[blossom].offset);
+ } else if ((*_delta2)[blossom] >
+ _blossom_set->classPrio(blossom) -
+ (*_blossom_data)[blossom].offset){
+ _delta2->decrease(blossom, _blossom_set->classPrio(blossom) -
+ (*_blossom_data)[blossom].offset);
+ }
+ }
+ }
+ } else {
+
+ typename std::map<int, Arc>::iterator it =
+ (*_node_data)[vi].heap_index.find(tree);
+
+ if (it != (*_node_data)[vi].heap_index.end()) {
+ (*_node_data)[vi].heap.erase(it->second);
+ (*_node_data)[vi].heap_index.erase(it);
+ if ((*_node_data)[vi].heap.empty()) {
+ _blossom_set->increase(v, std::numeric_limits<Value>::max());
+ } else if ((*_blossom_set)[v] < (*_node_data)[vi].heap.prio()) {
+ _blossom_set->increase(v, (*_node_data)[vi].heap.prio());
+ }
+
+ if ((*_blossom_data)[vb].status == MATCHED) {
+ if (_blossom_set->classPrio(vb) ==
+ std::numeric_limits<Value>::max()) {
+ _delta2->erase(vb);
+ } else if ((*_delta2)[vb] < _blossom_set->classPrio(vb) -
+ (*_blossom_data)[vb].offset) {
+ _delta2->increase(vb, _blossom_set->classPrio(vb) -
+ (*_blossom_data)[vb].offset);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void oddToMatched(int blossom) {
+ (*_blossom_data)[blossom].offset -= _delta_sum;
+
+ if (_blossom_set->classPrio(blossom) !=
+ std::numeric_limits<Value>::max()) {
+ _delta2->push(blossom, _blossom_set->classPrio(blossom) -
+ (*_blossom_data)[blossom].offset);
+ }
+
+ if (!_blossom_set->trivial(blossom)) {
+ _delta4->erase(blossom);
+ }
+ }
+
+ void oddToEven(int blossom, int tree) {
+ if (!_blossom_set->trivial(blossom)) {
+ _delta4->erase(blossom);
+ (*_blossom_data)[blossom].pot -=
+ 2 * (2 * _delta_sum - (*_blossom_data)[blossom].offset);
+ }
+
+ for (typename BlossomSet::ItemIt n(*_blossom_set, blossom);
+ n != INVALID; ++n) {
+ int ni = (*_node_index)[n];
+
+ _blossom_set->increase(n, std::numeric_limits<Value>::max());
+
+ (*_node_data)[ni].heap.clear();
+ (*_node_data)[ni].heap_index.clear();
+ (*_node_data)[ni].pot +=
+ 2 * _delta_sum - (*_blossom_data)[blossom].offset;
+
+ _delta1->push(n, (*_node_data)[ni].pot);
+
+ for (InArcIt e(_graph, n); e != INVALID; ++e) {
+ Node v = _graph.source(e);
+ int vb = _blossom_set->find(v);
+ int vi = (*_node_index)[v];
+
+ Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot -
+ dualScale * _weight[e];
+
+ if ((*_blossom_data)[vb].status == EVEN) {
+ if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) {
+ _delta3->push(e, rw / 2);
+ }
+ } else {
+
+ typename std::map<int, Arc>::iterator it =
+ (*_node_data)[vi].heap_index.find(tree);
+
+ if (it != (*_node_data)[vi].heap_index.end()) {
+ if ((*_node_data)[vi].heap[it->second] > rw) {
+ (*_node_data)[vi].heap.replace(it->second, e);
+ (*_node_data)[vi].heap.decrease(e, rw);
+ it->second = e;
+ }
+ } else {
+ (*_node_data)[vi].heap.push(e, rw);
+ (*_node_data)[vi].heap_index.insert(std::make_pair(tree, e));
+ }
+
+ if ((*_blossom_set)[v] > (*_node_data)[vi].heap.prio()) {
+ _blossom_set->decrease(v, (*_node_data)[vi].heap.prio());
+
+ if ((*_blossom_data)[vb].status == MATCHED) {
+ if (_delta2->state(vb) != _delta2->IN_HEAP) {
+ _delta2->push(vb, _blossom_set->classPrio(vb) -
+ (*_blossom_data)[vb].offset);
+ } else if ((*_delta2)[vb] > _blossom_set->classPrio(vb) -
+ (*_blossom_data)[vb].offset) {
+ _delta2->decrease(vb, _blossom_set->classPrio(vb) -
+ (*_blossom_data)[vb].offset);
+ }
+ }
+ }
+ }
+ }
+ }
+ (*_blossom_data)[blossom].offset = 0;
+ }
+
+ void alternatePath(int even, int tree) {
+ int odd;
+
+ evenToMatched(even, tree);
+ (*_blossom_data)[even].status = MATCHED;
+
+ while ((*_blossom_data)[even].pred != INVALID) {
+ odd = _blossom_set->find(_graph.target((*_blossom_data)[even].pred));
+ (*_blossom_data)[odd].status = MATCHED;
+ oddToMatched(odd);
+ (*_blossom_data)[odd].next = (*_blossom_data)[odd].pred;
+
+ even = _blossom_set->find(_graph.target((*_blossom_data)[odd].pred));
+ (*_blossom_data)[even].status = MATCHED;
+ evenToMatched(even, tree);
+ (*_blossom_data)[even].next =
+ _graph.oppositeArc((*_blossom_data)[odd].pred);
+ }
+
+ }
+
+ void destroyTree(int tree) {
+ for (TreeSet::ItemIt b(*_tree_set, tree); b != INVALID; ++b) {
+ if ((*_blossom_data)[b].status == EVEN) {
+ (*_blossom_data)[b].status = MATCHED;
+ evenToMatched(b, tree);
+ } else if ((*_blossom_data)[b].status == ODD) {
+ (*_blossom_data)[b].status = MATCHED;
+ oddToMatched(b);
+ }
+ }
+ _tree_set->eraseClass(tree);
+ }
+
+
+ void unmatchNode(const Node& node) {
+ int blossom = _blossom_set->find(node);
+ int tree = _tree_set->find(blossom);
+
+ alternatePath(blossom, tree);
+ destroyTree(tree);
+
+ (*_blossom_data)[blossom].base = node;
+ (*_blossom_data)[blossom].next = INVALID;
+ }
+
+ void augmentOnEdge(const Edge& edge) {
+
+ int left = _blossom_set->find(_graph.u(edge));
+ int right = _blossom_set->find(_graph.v(edge));
+
+ int left_tree = _tree_set->find(left);
+ alternatePath(left, left_tree);
+ destroyTree(left_tree);
+
+ int right_tree = _tree_set->find(right);
+ alternatePath(right, right_tree);
+ destroyTree(right_tree);
+
+ (*_blossom_data)[left].next = _graph.direct(edge, true);
+ (*_blossom_data)[right].next = _graph.direct(edge, false);
+ }
+
+ void augmentOnArc(const Arc& arc) {
+
+ int left = _blossom_set->find(_graph.source(arc));
+ int right = _blossom_set->find(_graph.target(arc));
+
+ (*_blossom_data)[left].status = MATCHED;
+
+ int right_tree = _tree_set->find(right);
+ alternatePath(right, right_tree);
+ destroyTree(right_tree);
+
+ (*_blossom_data)[left].next = arc;
+ (*_blossom_data)[right].next = _graph.oppositeArc(arc);
+ }
+
+ void extendOnArc(const Arc& arc) {
+ int base = _blossom_set->find(_graph.target(arc));
+ int tree = _tree_set->find(base);
+
+ int odd = _blossom_set->find(_graph.source(arc));
+ _tree_set->insert(odd, tree);
+ (*_blossom_data)[odd].status = ODD;
+ matchedToOdd(odd);
+ (*_blossom_data)[odd].pred = arc;
+
+ int even = _blossom_set->find(_graph.target((*_blossom_data)[odd].next));
+ (*_blossom_data)[even].pred = (*_blossom_data)[even].next;
+ _tree_set->insert(even, tree);
+ (*_blossom_data)[even].status = EVEN;
+ matchedToEven(even, tree);
+ }
+
+ void shrinkOnEdge(const Edge& edge, int tree) {
+ int nca = -1;
+ std::vector<int> left_path, right_path;
+
+ {
+ std::set<int> left_set, right_set;
+ int left = _blossom_set->find(_graph.u(edge));
+ left_path.push_back(left);
+ left_set.insert(left);
+
+ int right = _blossom_set->find(_graph.v(edge));
+ right_path.push_back(right);
+ right_set.insert(right);
+
+ while (true) {
+
+ if ((*_blossom_data)[left].pred == INVALID) break;
+
+ left =
+ _blossom_set->find(_graph.target((*_blossom_data)[left].pred));
+ left_path.push_back(left);
+ left =
+ _blossom_set->find(_graph.target((*_blossom_data)[left].pred));
+ left_path.push_back(left);
+
+ left_set.insert(left);
+
+ if (right_set.find(left) != right_set.end()) {
+ nca = left;
+ break;
+ }
+
+ if ((*_blossom_data)[right].pred == INVALID) break;
+
+ right =
+ _blossom_set->find(_graph.target((*_blossom_data)[right].pred));
+ right_path.push_back(right);
+ right =
+ _blossom_set->find(_graph.target((*_blossom_data)[right].pred));
+ right_path.push_back(right);
+
+ right_set.insert(right);
+
+ if (left_set.find(right) != left_set.end()) {
+ nca = right;
+ break;
+ }
+
+ }
+
+ if (nca == -1) {
+ if ((*_blossom_data)[left].pred == INVALID) {
+ nca = right;
+ while (left_set.find(nca) == left_set.end()) {
+ nca =
+ _blossom_set->find(_graph.target((*_blossom_data)[nca].pred));
+ right_path.push_back(nca);
+ nca =
+ _blossom_set->find(_graph.target((*_blossom_data)[nca].pred));
+ right_path.push_back(nca);
+ }
+ } else {
+ nca = left;
+ while (right_set.find(nca) == right_set.end()) {
+ nca =
+ _blossom_set->find(_graph.target((*_blossom_data)[nca].pred));
+ left_path.push_back(nca);
+ nca =
+ _blossom_set->find(_graph.target((*_blossom_data)[nca].pred));
+ left_path.push_back(nca);
+ }
+ }
+ }
+ }
+
+ std::vector<int> subblossoms;
+ Arc prev;
+
+ prev = _graph.direct(edge, true);
+ for (int i = 0; left_path[i] != nca; i += 2) {
+ subblossoms.push_back(left_path[i]);
+ (*_blossom_data)[left_path[i]].next = prev;
+ _tree_set->erase(left_path[i]);
+
+ subblossoms.push_back(left_path[i + 1]);
+ (*_blossom_data)[left_path[i + 1]].status = EVEN;
+ oddToEven(left_path[i + 1], tree);
+ _tree_set->erase(left_path[i + 1]);
+ prev = _graph.oppositeArc((*_blossom_data)[left_path[i + 1]].pred);
+ }
+
+ int k = 0;
+ while (right_path[k] != nca) ++k;
+
+ subblossoms.push_back(nca);
+ (*_blossom_data)[nca].next = prev;
+
+ for (int i = k - 2; i >= 0; i -= 2) {
+ subblossoms.push_back(right_path[i + 1]);
+ (*_blossom_data)[right_path[i + 1]].status = EVEN;
+ oddToEven(right_path[i + 1], tree);
+ _tree_set->erase(right_path[i + 1]);
+
+ (*_blossom_data)[right_path[i + 1]].next =
+ (*_blossom_data)[right_path[i + 1]].pred;
+
+ subblossoms.push_back(right_path[i]);
+ _tree_set->erase(right_path[i]);
+ }
+
+ int surface =
+ _blossom_set->join(subblossoms.begin(), subblossoms.end());
+
+ for (int i = 0; i < int(subblossoms.size()); ++i) {
+ if (!_blossom_set->trivial(subblossoms[i])) {
+ (*_blossom_data)[subblossoms[i]].pot += 2 * _delta_sum;
+ }
+ (*_blossom_data)[subblossoms[i]].status = MATCHED;
+ }
+
+ (*_blossom_data)[surface].pot = -2 * _delta_sum;
+ (*_blossom_data)[surface].offset = 0;
+ (*_blossom_data)[surface].status = EVEN;
+ (*_blossom_data)[surface].pred = (*_blossom_data)[nca].pred;
+ (*_blossom_data)[surface].next = (*_blossom_data)[nca].pred;
+
+ _tree_set->insert(surface, tree);
+ _tree_set->erase(nca);
+ }
+
+ void splitBlossom(int blossom) {
+ Arc next = (*_blossom_data)[blossom].next;
+ Arc pred = (*_blossom_data)[blossom].pred;
+
+ int tree = _tree_set->find(blossom);
+
+ (*_blossom_data)[blossom].status = MATCHED;
+ oddToMatched(blossom);
+ if (_delta2->state(blossom) == _delta2->IN_HEAP) {
+ _delta2->erase(blossom);
+ }
+
+ std::vector<int> subblossoms;
+ _blossom_set->split(blossom, std::back_inserter(subblossoms));
+
+ Value offset = (*_blossom_data)[blossom].offset;
+ int b = _blossom_set->find(_graph.source(pred));
+ int d = _blossom_set->find(_graph.source(next));
+
+ int ib = -1, id = -1;
+ for (int i = 0; i < int(subblossoms.size()); ++i) {
+ if (subblossoms[i] == b) ib = i;
+ if (subblossoms[i] == d) id = i;
+
+ (*_blossom_data)[subblossoms[i]].offset = offset;
+ if (!_blossom_set->trivial(subblossoms[i])) {
+ (*_blossom_data)[subblossoms[i]].pot -= 2 * offset;
+ }
+ if (_blossom_set->classPrio(subblossoms[i]) !=
+ std::numeric_limits<Value>::max()) {
+ _delta2->push(subblossoms[i],
+ _blossom_set->classPrio(subblossoms[i]) -
+ (*_blossom_data)[subblossoms[i]].offset);
+ }
+ }
+
+ if (id > ib ? ((id - ib) % 2 == 0) : ((ib - id) % 2 == 1)) {
+ for (int i = (id + 1) % subblossoms.size();
+ i != ib; i = (i + 2) % subblossoms.size()) {
+ int sb = subblossoms[i];
+ int tb = subblossoms[(i + 1) % subblossoms.size()];
+ (*_blossom_data)[sb].next =
+ _graph.oppositeArc((*_blossom_data)[tb].next);
+ }
+
+ for (int i = ib; i != id; i = (i + 2) % subblossoms.size()) {
+ int sb = subblossoms[i];
+ int tb = subblossoms[(i + 1) % subblossoms.size()];
+ int ub = subblossoms[(i + 2) % subblossoms.size()];
+
+ (*_blossom_data)[sb].status = ODD;
+ matchedToOdd(sb);
+ _tree_set->insert(sb, tree);
+ (*_blossom_data)[sb].pred = pred;
+ (*_blossom_data)[sb].next =
+ _graph.oppositeArc((*_blossom_data)[tb].next);
+
+ pred = (*_blossom_data)[ub].next;
+
+ (*_blossom_data)[tb].status = EVEN;
+ matchedToEven(tb, tree);
+ _tree_set->insert(tb, tree);
+ (*_blossom_data)[tb].pred = (*_blossom_data)[tb].next;
+ }
+
+ (*_blossom_data)[subblossoms[id]].status = ODD;
+ matchedToOdd(subblossoms[id]);
+ _tree_set->insert(subblossoms[id], tree);
+ (*_blossom_data)[subblossoms[id]].next = next;
+ (*_blossom_data)[subblossoms[id]].pred = pred;
+
+ } else {
+
+ for (int i = (ib + 1) % subblossoms.size();
+ i != id; i = (i + 2) % subblossoms.size()) {
+ int sb = subblossoms[i];
+ int tb = subblossoms[(i + 1) % subblossoms.size()];
+ (*_blossom_data)[sb].next =
+ _graph.oppositeArc((*_blossom_data)[tb].next);
+ }
+
+ for (int i = id; i != ib; i = (i + 2) % subblossoms.size()) {
+ int sb = subblossoms[i];
+ int tb = subblossoms[(i + 1) % subblossoms.size()];
+ int ub = subblossoms[(i + 2) % subblossoms.size()];
+
+ (*_blossom_data)[sb].status = ODD;
+ matchedToOdd(sb);
+ _tree_set->insert(sb, tree);
+ (*_blossom_data)[sb].next = next;
+ (*_blossom_data)[sb].pred =
+ _graph.oppositeArc((*_blossom_data)[tb].next);
+
+ (*_blossom_data)[tb].status = EVEN;
+ matchedToEven(tb, tree);
+ _tree_set->insert(tb, tree);
+ (*_blossom_data)[tb].pred =
+ (*_blossom_data)[tb].next =
+ _graph.oppositeArc((*_blossom_data)[ub].next);
+ next = (*_blossom_data)[ub].next;
+ }
+
+ (*_blossom_data)[subblossoms[ib]].status = ODD;
+ matchedToOdd(subblossoms[ib]);
+ _tree_set->insert(subblossoms[ib], tree);
+ (*_blossom_data)[subblossoms[ib]].next = next;
+ (*_blossom_data)[subblossoms[ib]].pred = pred;
+ }
+ _tree_set->erase(blossom);
+ }
+
+ void extractBlossom(int blossom, const Node& base, const Arc& matching) {
+ if (_blossom_set->trivial(blossom)) {
+ int bi = (*_node_index)[base];
+ Value pot = (*_node_data)[bi].pot;
+
+ (*_matching)[base] = matching;
+ _blossom_node_list.push_back(base);
+ (*_node_potential)[base] = pot;
+ } else {
+
+ Value pot = (*_blossom_data)[blossom].pot;
+ int bn = _blossom_node_list.size();
+
+ std::vector<int> subblossoms;
+ _blossom_set->split(blossom, std::back_inserter(subblossoms));
+ int b = _blossom_set->find(base);
+ int ib = -1;
+ for (int i = 0; i < int(subblossoms.size()); ++i) {
+ if (subblossoms[i] == b) { ib = i; break; }
+ }
+
+ for (int i = 1; i < int(subblossoms.size()); i += 2) {
+ int sb = subblossoms[(ib + i) % subblossoms.size()];
+ int tb = subblossoms[(ib + i + 1) % subblossoms.size()];
+
+ Arc m = (*_blossom_data)[tb].next;
+ extractBlossom(sb, _graph.target(m), _graph.oppositeArc(m));
+ extractBlossom(tb, _graph.source(m), m);
+ }
+ extractBlossom(subblossoms[ib], base, matching);
+
+ int en = _blossom_node_list.size();
+
+ _blossom_potential.push_back(BlossomVariable(bn, en, pot));
+ }
+ }
+
+ void extractMatching() {
+ std::vector<int> blossoms;
+ for (typename BlossomSet::ClassIt c(*_blossom_set); c != INVALID; ++c) {
+ blossoms.push_back(c);
+ }
+
+ for (int i = 0; i < int(blossoms.size()); ++i) {
+ if ((*_blossom_data)[blossoms[i]].next != INVALID) {
+
+ Value offset = (*_blossom_data)[blossoms[i]].offset;
+ (*_blossom_data)[blossoms[i]].pot += 2 * offset;
+ for (typename BlossomSet::ItemIt n(*_blossom_set, blossoms[i]);
+ n != INVALID; ++n) {
+ (*_node_data)[(*_node_index)[n]].pot -= offset;
+ }
+
+ Arc matching = (*_blossom_data)[blossoms[i]].next;
+ Node base = _graph.source(matching);
+ extractBlossom(blossoms[i], base, matching);
+ } else {
+ Node base = (*_blossom_data)[blossoms[i]].base;
+ extractBlossom(blossoms[i], base, INVALID);
+ }
+ }
+ }
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ MaxWeightedMatching(const Graph& graph, const WeightMap& weight)
+ : _graph(graph), _weight(weight), _matching(0),
+ _node_potential(0), _blossom_potential(), _blossom_node_list(),
+ _node_num(0), _blossom_num(0),
+
+ _blossom_index(0), _blossom_set(0), _blossom_data(0),
+ _node_index(0), _node_heap_index(0), _node_data(0),
+ _tree_set_index(0), _tree_set(0),
+
+ _delta1_index(0), _delta1(0),
+ _delta2_index(0), _delta2(0),
+ _delta3_index(0), _delta3(0),
+ _delta4_index(0), _delta4(0),
+
+ _delta_sum(), _unmatched(0),
+
+ _fractional(0)
+ {}
+
+ ~MaxWeightedMatching() {
+ destroyStructures();
+ if (_fractional) {
+ delete _fractional;
+ }
+ }
+
+ /// \name Execution Control
+ /// The simplest way to execute the algorithm is to use the
+ /// \ref run() member function.
+
+ ///@{
+
+ /// \brief Initialize the algorithm
+ ///
+ /// This function initializes the algorithm.
+ void init() {
+ createStructures();
+
+ _blossom_node_list.clear();
+ _blossom_potential.clear();
+
+ for (ArcIt e(_graph); e != INVALID; ++e) {
+ (*_node_heap_index)[e] = BinHeap<Value, IntArcMap>::PRE_HEAP;
+ }
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ (*_delta1_index)[n] = _delta1->PRE_HEAP;
+ }
+ for (EdgeIt e(_graph); e != INVALID; ++e) {
+ (*_delta3_index)[e] = _delta3->PRE_HEAP;
+ }
+ for (int i = 0; i < _blossom_num; ++i) {
+ (*_delta2_index)[i] = _delta2->PRE_HEAP;
+ (*_delta4_index)[i] = _delta4->PRE_HEAP;
+ }
+
+ _unmatched = _node_num;
+
+ _delta1->clear();
+ _delta2->clear();
+ _delta3->clear();
+ _delta4->clear();
+ _blossom_set->clear();
+ _tree_set->clear();
+
+ int index = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ Value max = 0;
+ for (OutArcIt e(_graph, n); e != INVALID; ++e) {
+ if (_graph.target(e) == n) continue;
+ if ((dualScale * _weight[e]) / 2 > max) {
+ max = (dualScale * _weight[e]) / 2;
+ }
+ }
+ (*_node_index)[n] = index;
+ (*_node_data)[index].heap_index.clear();
+ (*_node_data)[index].heap.clear();
+ (*_node_data)[index].pot = max;
+ _delta1->push(n, max);
+ int blossom =
+ _blossom_set->insert(n, std::numeric_limits<Value>::max());
+
+ _tree_set->insert(blossom);
+
+ (*_blossom_data)[blossom].status = EVEN;
+ (*_blossom_data)[blossom].pred = INVALID;
+ (*_blossom_data)[blossom].next = INVALID;
+ (*_blossom_data)[blossom].pot = 0;
+ (*_blossom_data)[blossom].offset = 0;
+ ++index;
+ }
+ for (EdgeIt e(_graph); e != INVALID; ++e) {
+ int si = (*_node_index)[_graph.u(e)];
+ int ti = (*_node_index)[_graph.v(e)];
+ if (_graph.u(e) != _graph.v(e)) {
+ _delta3->push(e, ((*_node_data)[si].pot + (*_node_data)[ti].pot -
+ dualScale * _weight[e]) / 2);
+ }
+ }
+ }
+
+ /// \brief Initialize the algorithm with fractional matching
+ ///
+ /// This function initializes the algorithm with a fractional
+ /// matching. This initialization is also called jumpstart heuristic.
+ void fractionalInit() {
+ createStructures();
+
+ _blossom_node_list.clear();
+ _blossom_potential.clear();
+
+ if (_fractional == 0) {
+ _fractional = new FractionalMatching(_graph, _weight, false);
+ }
+ _fractional->run();
+
+ for (ArcIt e(_graph); e != INVALID; ++e) {
+ (*_node_heap_index)[e] = BinHeap<Value, IntArcMap>::PRE_HEAP;
+ }
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ (*_delta1_index)[n] = _delta1->PRE_HEAP;
+ }
+ for (EdgeIt e(_graph); e != INVALID; ++e) {
+ (*_delta3_index)[e] = _delta3->PRE_HEAP;
+ }
+ for (int i = 0; i < _blossom_num; ++i) {
+ (*_delta2_index)[i] = _delta2->PRE_HEAP;
+ (*_delta4_index)[i] = _delta4->PRE_HEAP;
+ }
+
+ _unmatched = 0;
+
+ _delta1->clear();
+ _delta2->clear();
+ _delta3->clear();
+ _delta4->clear();
+ _blossom_set->clear();
+ _tree_set->clear();
+
+ int index = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ Value pot = _fractional->nodeValue(n);
+ (*_node_index)[n] = index;
+ (*_node_data)[index].pot = pot;
+ (*_node_data)[index].heap_index.clear();
+ (*_node_data)[index].heap.clear();
+ int blossom =
+ _blossom_set->insert(n, std::numeric_limits<Value>::max());
+
+ (*_blossom_data)[blossom].status = MATCHED;
+ (*_blossom_data)[blossom].pred = INVALID;
+ (*_blossom_data)[blossom].next = _fractional->matching(n);
+ if (_fractional->matching(n) == INVALID) {
+ (*_blossom_data)[blossom].base = n;
+ }
+ (*_blossom_data)[blossom].pot = 0;
+ (*_blossom_data)[blossom].offset = 0;
+ ++index;
+ }
+
+ typename Graph::template NodeMap<bool> processed(_graph, false);
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ if (processed[n]) continue;
+ processed[n] = true;
+ if (_fractional->matching(n) == INVALID) continue;
+ int num = 1;
+ Node v = _graph.target(_fractional->matching(n));
+ while (n != v) {
+ processed[v] = true;
+ v = _graph.target(_fractional->matching(v));
+ ++num;
+ }
+
+ if (num % 2 == 1) {
+ std::vector<int> subblossoms(num);
+
+ subblossoms[--num] = _blossom_set->find(n);
+ _delta1->push(n, _fractional->nodeValue(n));
+ v = _graph.target(_fractional->matching(n));
+ while (n != v) {
+ subblossoms[--num] = _blossom_set->find(v);
+ _delta1->push(v, _fractional->nodeValue(v));
+ v = _graph.target(_fractional->matching(v));
+ }
+
+ int surface =
+ _blossom_set->join(subblossoms.begin(), subblossoms.end());
+ (*_blossom_data)[surface].status = EVEN;
+ (*_blossom_data)[surface].pred = INVALID;
+ (*_blossom_data)[surface].next = INVALID;
+ (*_blossom_data)[surface].pot = 0;
+ (*_blossom_data)[surface].offset = 0;
+
+ _tree_set->insert(surface);
+ ++_unmatched;
+ }
+ }
+
+ for (EdgeIt e(_graph); e != INVALID; ++e) {
+ int si = (*_node_index)[_graph.u(e)];
+ int sb = _blossom_set->find(_graph.u(e));
+ int ti = (*_node_index)[_graph.v(e)];
+ int tb = _blossom_set->find(_graph.v(e));
+ if ((*_blossom_data)[sb].status == EVEN &&
+ (*_blossom_data)[tb].status == EVEN && sb != tb) {
+ _delta3->push(e, ((*_node_data)[si].pot + (*_node_data)[ti].pot -
+ dualScale * _weight[e]) / 2);
+ }
+ }
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ int nb = _blossom_set->find(n);
+ if ((*_blossom_data)[nb].status != MATCHED) continue;
+ int ni = (*_node_index)[n];
+
+ for (OutArcIt e(_graph, n); e != INVALID; ++e) {
+ Node v = _graph.target(e);
+ int vb = _blossom_set->find(v);
+ int vi = (*_node_index)[v];
+
+ Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot -
+ dualScale * _weight[e];
+
+ if ((*_blossom_data)[vb].status == EVEN) {
+
+ int vt = _tree_set->find(vb);
+
+ typename std::map<int, Arc>::iterator it =
+ (*_node_data)[ni].heap_index.find(vt);
+
+ if (it != (*_node_data)[ni].heap_index.end()) {
+ if ((*_node_data)[ni].heap[it->second] > rw) {
+ (*_node_data)[ni].heap.replace(it->second, e);
+ (*_node_data)[ni].heap.decrease(e, rw);
+ it->second = e;
+ }
+ } else {
+ (*_node_data)[ni].heap.push(e, rw);
+ (*_node_data)[ni].heap_index.insert(std::make_pair(vt, e));
+ }
+ }
+ }
+
+ if (!(*_node_data)[ni].heap.empty()) {
+ _blossom_set->decrease(n, (*_node_data)[ni].heap.prio());
+ _delta2->push(nb, _blossom_set->classPrio(nb));
+ }
+ }
+ }
+
+ /// \brief Start the algorithm
+ ///
+ /// This function starts the algorithm.
+ ///
+ /// \pre \ref init() or \ref fractionalInit() must be called
+ /// before using this function.
+ void start() {
+ enum OpType {
+ D1, D2, D3, D4
+ };
+
+ while (_unmatched > 0) {
+ Value d1 = !_delta1->empty() ?
+ _delta1->prio() : std::numeric_limits<Value>::max();
+
+ Value d2 = !_delta2->empty() ?
+ _delta2->prio() : std::numeric_limits<Value>::max();
+
+ Value d3 = !_delta3->empty() ?
+ _delta3->prio() : std::numeric_limits<Value>::max();
+
+ Value d4 = !_delta4->empty() ?
+ _delta4->prio() : std::numeric_limits<Value>::max();
+
+ _delta_sum = d3; OpType ot = D3;
+ if (d1 < _delta_sum) { _delta_sum = d1; ot = D1; }
+ if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; }
+ if (d4 < _delta_sum) { _delta_sum = d4; ot = D4; }
+
+ switch (ot) {
+ case D1:
+ {
+ Node n = _delta1->top();
+ unmatchNode(n);
+ --_unmatched;
+ }
+ break;
+ case D2:
+ {
+ int blossom = _delta2->top();
+ Node n = _blossom_set->classTop(blossom);
+ Arc a = (*_node_data)[(*_node_index)[n]].heap.top();
+ if ((*_blossom_data)[blossom].next == INVALID) {
+ augmentOnArc(a);
+ --_unmatched;
+ } else {
+ extendOnArc(a);
+ }
+ }
+ break;
+ case D3:
+ {
+ Edge e = _delta3->top();
+
+ int left_blossom = _blossom_set->find(_graph.u(e));
+ int right_blossom = _blossom_set->find(_graph.v(e));
+
+ if (left_blossom == right_blossom) {
+ _delta3->pop();
+ } else {
+ int left_tree = _tree_set->find(left_blossom);
+ int right_tree = _tree_set->find(right_blossom);
+
+ if (left_tree == right_tree) {
+ shrinkOnEdge(e, left_tree);
+ } else {
+ augmentOnEdge(e);
+ _unmatched -= 2;
+ }
+ }
+ } break;
+ case D4:
+ splitBlossom(_delta4->top());
+ break;
+ }
+ }
+ extractMatching();
+ }
+
+ /// \brief Run the algorithm.
+ ///
+ /// This method runs the \c %MaxWeightedMatching algorithm.
+ ///
+ /// \note mwm.run() is just a shortcut of the following code.
+ /// \code
+ /// mwm.fractionalInit();
+ /// mwm.start();
+ /// \endcode
+ void run() {
+ fractionalInit();
+ start();
+ }
+
+ /// @}
+
+ /// \name Primal Solution
+ /// Functions to get the primal solution, i.e. the maximum weighted
+ /// matching.\n
+ /// Either \ref run() or \ref start() function should be called before
+ /// using them.
+
+ /// @{
+
+ /// \brief Return the weight of the matching.
+ ///
+ /// This function returns the weight of the found matching.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Value matchingWeight() const {
+ Value sum = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ if ((*_matching)[n] != INVALID) {
+ sum += _weight[(*_matching)[n]];
+ }
+ }
+ return sum / 2;
+ }
+
+ /// \brief Return the size (cardinality) of the matching.
+ ///
+ /// This function returns the size (cardinality) of the found matching.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ int matchingSize() const {
+ int num = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ if ((*_matching)[n] != INVALID) {
+ ++num;
+ }
+ }
+ return num /= 2;
+ }
+
+ /// \brief Return \c true if the given edge is in the matching.
+ ///
+ /// This function returns \c true if the given edge is in the found
+ /// matching.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ bool matching(const Edge& edge) const {
+ return edge == (*_matching)[_graph.u(edge)];
+ }
+
+ /// \brief Return the matching arc (or edge) incident to the given node.
+ ///
+ /// This function returns the matching arc (or edge) incident to the
+ /// given node in the found matching or \c INVALID if the node is
+ /// not covered by the matching.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Arc matching(const Node& node) const {
+ return (*_matching)[node];
+ }
+
+ /// \brief Return a const reference to the matching map.
+ ///
+ /// This function returns a const reference to a node map that stores
+ /// the matching arc (or edge) incident to each node.
+ const MatchingMap& matchingMap() const {
+ return *_matching;
+ }
+
+ /// \brief Return the mate of the given node.
+ ///
+ /// This function returns the mate of the given node in the found
+ /// matching or \c INVALID if the node is not covered by the matching.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Node mate(const Node& node) const {
+ return (*_matching)[node] != INVALID ?
+ _graph.target((*_matching)[node]) : INVALID;
+ }
+
+ /// @}
+
+ /// \name Dual Solution
+ /// Functions to get the dual solution.\n
+ /// Either \ref run() or \ref start() function should be called before
+ /// using them.
+
+ /// @{
+
+ /// \brief Return the value of the dual solution.
+ ///
+ /// This function returns the value of the dual solution.
+ /// It should be equal to the primal value scaled by \ref dualScale
+ /// "dual scale".
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Value dualValue() const {
+ Value sum = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ sum += nodeValue(n);
+ }
+ for (int i = 0; i < blossomNum(); ++i) {
+ sum += blossomValue(i) * (blossomSize(i) / 2);
+ }
+ return sum;
+ }
+
+ /// \brief Return the dual value (potential) of the given node.
+ ///
+ /// This function returns the dual value (potential) of the given node.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Value nodeValue(const Node& n) const {
+ return (*_node_potential)[n];
+ }
+
+ /// \brief Return the number of the blossoms in the basis.
+ ///
+ /// This function returns the number of the blossoms in the basis.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ /// \see BlossomIt
+ int blossomNum() const {
+ return _blossom_potential.size();
+ }
+
+ /// \brief Return the number of the nodes in the given blossom.
+ ///
+ /// This function returns the number of the nodes in the given blossom.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ /// \see BlossomIt
+ int blossomSize(int k) const {
+ return _blossom_potential[k].end - _blossom_potential[k].begin;
+ }
+
+ /// \brief Return the dual value (ptential) of the given blossom.
+ ///
+ /// This function returns the dual value (ptential) of the given blossom.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Value blossomValue(int k) const {
+ return _blossom_potential[k].value;
+ }
+
+ /// \brief Iterator for obtaining the nodes of a blossom.
+ ///
+ /// This class provides an iterator for obtaining the nodes of the
+ /// given blossom. It lists a subset of the nodes.
+ /// Before using this iterator, you must allocate a
+ /// MaxWeightedMatching class and execute it.
+ class BlossomIt {
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// Constructor to get the nodes of the given variable.
+ ///
+ /// \pre Either \ref MaxWeightedMatching::run() "algorithm.run()" or
+ /// \ref MaxWeightedMatching::start() "algorithm.start()" must be
+ /// called before initializing this iterator.
+ BlossomIt(const MaxWeightedMatching& algorithm, int variable)
+ : _algorithm(&algorithm)
+ {
+ _index = _algorithm->_blossom_potential[variable].begin;
+ _last = _algorithm->_blossom_potential[variable].end;
+ }
+
+ /// \brief Conversion to \c Node.
+ ///
+ /// Conversion to \c Node.
+ operator Node() const {
+ return _algorithm->_blossom_node_list[_index];
+ }
+
+ /// \brief Increment operator.
+ ///
+ /// Increment operator.
+ BlossomIt& operator++() {
+ ++_index;
+ return *this;
+ }
+
+ /// \brief Validity checking
+ ///
+ /// Checks whether the iterator is invalid.
+ bool operator==(Invalid) const { return _index == _last; }
+
+ /// \brief Validity checking
+ ///
+ /// Checks whether the iterator is valid.
+ bool operator!=(Invalid) const { return _index != _last; }
+
+ private:
+ const MaxWeightedMatching* _algorithm;
+ int _last;
+ int _index;
+ };
+
+ /// @}
+
+ };
+
+ /// \ingroup matching
+ ///
+ /// \brief Weighted perfect matching in general graphs
+ ///
+ /// This class provides an efficient implementation of Edmond's
+ /// maximum weighted perfect matching algorithm. The implementation
+ /// is based on extensive use of priority queues and provides
+ /// \f$O(nm\log n)\f$ time complexity.
+ ///
+ /// The maximum weighted perfect matching problem is to find a subset of
+ /// the edges in an undirected graph with maximum overall weight for which
+ /// each node has exactly one incident edge.
+ /// It can be formulated with the following linear program.
+ /// \f[ \sum_{e \in \delta(u)}x_e = 1 \quad \forall u\in V\f]
+ /** \f[ \sum_{e \in \gamma(B)}x_e \le \frac{\vert B \vert - 1}{2}
+ \quad \forall B\in\mathcal{O}\f] */
+ /// \f[x_e \ge 0\quad \forall e\in E\f]
+ /// \f[\max \sum_{e\in E}x_ew_e\f]
+ /// where \f$\delta(X)\f$ is the set of edges incident to a node in
+ /// \f$X\f$, \f$\gamma(X)\f$ is the set of edges with both ends in
+ /// \f$X\f$ and \f$\mathcal{O}\f$ is the set of odd cardinality
+ /// subsets of the nodes.
+ ///
+ /// The algorithm calculates an optimal matching and a proof of the
+ /// optimality. The solution of the dual problem can be used to check
+ /// the result of the algorithm. The dual linear problem is the
+ /// following.
+ /** \f[ y_u + y_v + \sum_{B \in \mathcal{O}, uv \in \gamma(B)}z_B \ge
+ w_{uv} \quad \forall uv\in E\f] */
+ /// \f[z_B \ge 0 \quad \forall B \in \mathcal{O}\f]
+ /** \f[\min \sum_{u \in V}y_u + \sum_{B \in \mathcal{O}}
+ \frac{\vert B \vert - 1}{2}z_B\f] */
+ ///
+ /// The algorithm can be executed with the run() function.
+ /// After it the matching (the primal solution) and the dual solution
+ /// can be obtained using the query functions and the
+ /// \ref MaxWeightedPerfectMatching::BlossomIt "BlossomIt" nested class,
+ /// which is able to iterate on the nodes of a blossom.
+ /// If the value type is integer, then the dual solution is multiplied
+ /// by \ref MaxWeightedMatching::dualScale "4".
+ ///
+ /// \tparam GR The undirected graph type the algorithm runs on.
+ /// \tparam WM The type edge weight map. The default type is
+ /// \ref concepts::Graph::EdgeMap "GR::EdgeMap<int>".
+#ifdef DOXYGEN
+ template <typename GR, typename WM>
+#else
+ template <typename GR,
+ typename WM = typename GR::template EdgeMap<int> >
+#endif
+ class MaxWeightedPerfectMatching {
+ public:
+
+ /// The graph type of the algorithm
+ typedef GR Graph;
+ /// The type of the edge weight map
+ typedef WM WeightMap;
+ /// The value type of the edge weights
+ typedef typename WeightMap::Value Value;
+
+ /// \brief Scaling factor for dual solution
+ ///
+ /// Scaling factor for dual solution, it is equal to 4 or 1
+ /// according to the value type.
+ static const int dualScale =
+ std::numeric_limits<Value>::is_integer ? 4 : 1;
+
+ /// The type of the matching map
+ typedef typename Graph::template NodeMap<typename Graph::Arc>
+ MatchingMap;
+
+ private:
+
+ TEMPLATE_GRAPH_TYPEDEFS(Graph);
+
+ typedef typename Graph::template NodeMap<Value> NodePotential;
+ typedef std::vector<Node> BlossomNodeList;
+
+ struct BlossomVariable {
+ int begin, end;
+ Value value;
+
+ BlossomVariable(int _begin, int _end, Value _value)
+ : begin(_begin), end(_end), value(_value) {}
+
+ };
+
+ typedef std::vector<BlossomVariable> BlossomPotential;
+
+ const Graph& _graph;
+ const WeightMap& _weight;
+
+ MatchingMap* _matching;
+
+ NodePotential* _node_potential;
+
+ BlossomPotential _blossom_potential;
+ BlossomNodeList _blossom_node_list;
+
+ int _node_num;
+ int _blossom_num;
+
+ typedef RangeMap<int> IntIntMap;
+
+ enum Status {
+ EVEN = -1, MATCHED = 0, ODD = 1
+ };
+
+ typedef HeapUnionFind<Value, IntNodeMap> BlossomSet;
+ struct BlossomData {
+ int tree;
+ Status status;
+ Arc pred, next;
+ Value pot, offset;
+ };
+
+ IntNodeMap *_blossom_index;
+ BlossomSet *_blossom_set;
+ RangeMap<BlossomData>* _blossom_data;
+
+ IntNodeMap *_node_index;
+ IntArcMap *_node_heap_index;
+
+ struct NodeData {
+
+ NodeData(IntArcMap& node_heap_index)
+ : heap(node_heap_index) {}
+
+ int blossom;
+ Value pot;
+ BinHeap<Value, IntArcMap> heap;
+ std::map<int, Arc> heap_index;
+
+ int tree;
+ };
+
+ RangeMap<NodeData>* _node_data;
+
+ typedef ExtendFindEnum<IntIntMap> TreeSet;
+
+ IntIntMap *_tree_set_index;
+ TreeSet *_tree_set;
+
+ IntIntMap *_delta2_index;
+ BinHeap<Value, IntIntMap> *_delta2;
+
+ IntEdgeMap *_delta3_index;
+ BinHeap<Value, IntEdgeMap> *_delta3;
+
+ IntIntMap *_delta4_index;
+ BinHeap<Value, IntIntMap> *_delta4;
+
+ Value _delta_sum;
+ int _unmatched;
+
+ typedef MaxWeightedPerfectFractionalMatching<Graph, WeightMap>
+ FractionalMatching;
+ FractionalMatching *_fractional;
+
+ void createStructures() {
+ _node_num = countNodes(_graph);
+ _blossom_num = _node_num * 3 / 2;
+
+ if (!_matching) {
+ _matching = new MatchingMap(_graph);
+ }
+
+ if (!_node_potential) {
+ _node_potential = new NodePotential(_graph);
+ }
+
+ if (!_blossom_set) {
+ _blossom_index = new IntNodeMap(_graph);
+ _blossom_set = new BlossomSet(*_blossom_index);
+ _blossom_data = new RangeMap<BlossomData>(_blossom_num);
+ } else if (_blossom_data->size() != _blossom_num) {
+ delete _blossom_data;
+ _blossom_data = new RangeMap<BlossomData>(_blossom_num);
+ }
+
+ if (!_node_index) {
+ _node_index = new IntNodeMap(_graph);
+ _node_heap_index = new IntArcMap(_graph);
+ _node_data = new RangeMap<NodeData>(_node_num,
+ NodeData(*_node_heap_index));
+ } else if (_node_data->size() != _node_num) {
+ delete _node_data;
+ _node_data = new RangeMap<NodeData>(_node_num,
+ NodeData(*_node_heap_index));
+ }
+
+ if (!_tree_set) {
+ _tree_set_index = new IntIntMap(_blossom_num);
+ _tree_set = new TreeSet(*_tree_set_index);
+ } else {
+ _tree_set_index->resize(_blossom_num);
+ }
+
+ if (!_delta2) {
+ _delta2_index = new IntIntMap(_blossom_num);
+ _delta2 = new BinHeap<Value, IntIntMap>(*_delta2_index);
+ } else {
+ _delta2_index->resize(_blossom_num);
+ }
+
+ if (!_delta3) {
+ _delta3_index = new IntEdgeMap(_graph);
+ _delta3 = new BinHeap<Value, IntEdgeMap>(*_delta3_index);
+ }
+
+ if (!_delta4) {
+ _delta4_index = new IntIntMap(_blossom_num);
+ _delta4 = new BinHeap<Value, IntIntMap>(*_delta4_index);
+ } else {
+ _delta4_index->resize(_blossom_num);
+ }
+ }
+
+ void destroyStructures() {
+ if (_matching) {
+ delete _matching;
+ }
+ if (_node_potential) {
+ delete _node_potential;
+ }
+ if (_blossom_set) {
+ delete _blossom_index;
+ delete _blossom_set;
+ delete _blossom_data;
+ }
+
+ if (_node_index) {
+ delete _node_index;
+ delete _node_heap_index;
+ delete _node_data;
+ }
+
+ if (_tree_set) {
+ delete _tree_set_index;
+ delete _tree_set;
+ }
+ if (_delta2) {
+ delete _delta2_index;
+ delete _delta2;
+ }
+ if (_delta3) {
+ delete _delta3_index;
+ delete _delta3;
+ }
+ if (_delta4) {
+ delete _delta4_index;
+ delete _delta4;
+ }
+ }
+
+ void matchedToEven(int blossom, int tree) {
+ if (_delta2->state(blossom) == _delta2->IN_HEAP) {
+ _delta2->erase(blossom);
+ }
+
+ if (!_blossom_set->trivial(blossom)) {
+ (*_blossom_data)[blossom].pot -=
+ 2 * (_delta_sum - (*_blossom_data)[blossom].offset);
+ }
+
+ for (typename BlossomSet::ItemIt n(*_blossom_set, blossom);
+ n != INVALID; ++n) {
+
+ _blossom_set->increase(n, std::numeric_limits<Value>::max());
+ int ni = (*_node_index)[n];
+
+ (*_node_data)[ni].heap.clear();
+ (*_node_data)[ni].heap_index.clear();
+
+ (*_node_data)[ni].pot += _delta_sum - (*_blossom_data)[blossom].offset;
+
+ for (InArcIt e(_graph, n); e != INVALID; ++e) {
+ Node v = _graph.source(e);
+ int vb = _blossom_set->find(v);
+ int vi = (*_node_index)[v];
+
+ Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot -
+ dualScale * _weight[e];
+
+ if ((*_blossom_data)[vb].status == EVEN) {
+ if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) {
+ _delta3->push(e, rw / 2);
+ }
+ } else {
+ typename std::map<int, Arc>::iterator it =
+ (*_node_data)[vi].heap_index.find(tree);
+
+ if (it != (*_node_data)[vi].heap_index.end()) {
+ if ((*_node_data)[vi].heap[it->second] > rw) {
+ (*_node_data)[vi].heap.replace(it->second, e);
+ (*_node_data)[vi].heap.decrease(e, rw);
+ it->second = e;
+ }
+ } else {
+ (*_node_data)[vi].heap.push(e, rw);
+ (*_node_data)[vi].heap_index.insert(std::make_pair(tree, e));
+ }
+
+ if ((*_blossom_set)[v] > (*_node_data)[vi].heap.prio()) {
+ _blossom_set->decrease(v, (*_node_data)[vi].heap.prio());
+
+ if ((*_blossom_data)[vb].status == MATCHED) {
+ if (_delta2->state(vb) != _delta2->IN_HEAP) {
+ _delta2->push(vb, _blossom_set->classPrio(vb) -
+ (*_blossom_data)[vb].offset);
+ } else if ((*_delta2)[vb] > _blossom_set->classPrio(vb) -
+ (*_blossom_data)[vb].offset){
+ _delta2->decrease(vb, _blossom_set->classPrio(vb) -
+ (*_blossom_data)[vb].offset);
+ }
+ }
+ }
+ }
+ }
+ }
+ (*_blossom_data)[blossom].offset = 0;
+ }
+
+ void matchedToOdd(int blossom) {
+ if (_delta2->state(blossom) == _delta2->IN_HEAP) {
+ _delta2->erase(blossom);
+ }
+ (*_blossom_data)[blossom].offset += _delta_sum;
+ if (!_blossom_set->trivial(blossom)) {
+ _delta4->push(blossom, (*_blossom_data)[blossom].pot / 2 +
+ (*_blossom_data)[blossom].offset);
+ }
+ }
+
+ void evenToMatched(int blossom, int tree) {
+ if (!_blossom_set->trivial(blossom)) {
+ (*_blossom_data)[blossom].pot += 2 * _delta_sum;
+ }
+
+ for (typename BlossomSet::ItemIt n(*_blossom_set, blossom);
+ n != INVALID; ++n) {
+ int ni = (*_node_index)[n];
+ (*_node_data)[ni].pot -= _delta_sum;
+
+ for (InArcIt e(_graph, n); e != INVALID; ++e) {
+ Node v = _graph.source(e);
+ int vb = _blossom_set->find(v);
+ int vi = (*_node_index)[v];
+
+ Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot -
+ dualScale * _weight[e];
+
+ if (vb == blossom) {
+ if (_delta3->state(e) == _delta3->IN_HEAP) {
+ _delta3->erase(e);
+ }
+ } else if ((*_blossom_data)[vb].status == EVEN) {
+
+ if (_delta3->state(e) == _delta3->IN_HEAP) {
+ _delta3->erase(e);
+ }
+
+ int vt = _tree_set->find(vb);
+
+ if (vt != tree) {
+
+ Arc r = _graph.oppositeArc(e);
+
+ typename std::map<int, Arc>::iterator it =
+ (*_node_data)[ni].heap_index.find(vt);
+
+ if (it != (*_node_data)[ni].heap_index.end()) {
+ if ((*_node_data)[ni].heap[it->second] > rw) {
+ (*_node_data)[ni].heap.replace(it->second, r);
+ (*_node_data)[ni].heap.decrease(r, rw);
+ it->second = r;
+ }
+ } else {
+ (*_node_data)[ni].heap.push(r, rw);
+ (*_node_data)[ni].heap_index.insert(std::make_pair(vt, r));
+ }
+
+ if ((*_blossom_set)[n] > (*_node_data)[ni].heap.prio()) {
+ _blossom_set->decrease(n, (*_node_data)[ni].heap.prio());
+
+ if (_delta2->state(blossom) != _delta2->IN_HEAP) {
+ _delta2->push(blossom, _blossom_set->classPrio(blossom) -
+ (*_blossom_data)[blossom].offset);
+ } else if ((*_delta2)[blossom] >
+ _blossom_set->classPrio(blossom) -
+ (*_blossom_data)[blossom].offset){
+ _delta2->decrease(blossom, _blossom_set->classPrio(blossom) -
+ (*_blossom_data)[blossom].offset);
+ }
+ }
+ }
+ } else {
+
+ typename std::map<int, Arc>::iterator it =
+ (*_node_data)[vi].heap_index.find(tree);
+
+ if (it != (*_node_data)[vi].heap_index.end()) {
+ (*_node_data)[vi].heap.erase(it->second);
+ (*_node_data)[vi].heap_index.erase(it);
+ if ((*_node_data)[vi].heap.empty()) {
+ _blossom_set->increase(v, std::numeric_limits<Value>::max());
+ } else if ((*_blossom_set)[v] < (*_node_data)[vi].heap.prio()) {
+ _blossom_set->increase(v, (*_node_data)[vi].heap.prio());
+ }
+
+ if ((*_blossom_data)[vb].status == MATCHED) {
+ if (_blossom_set->classPrio(vb) ==
+ std::numeric_limits<Value>::max()) {
+ _delta2->erase(vb);
+ } else if ((*_delta2)[vb] < _blossom_set->classPrio(vb) -
+ (*_blossom_data)[vb].offset) {
+ _delta2->increase(vb, _blossom_set->classPrio(vb) -
+ (*_blossom_data)[vb].offset);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void oddToMatched(int blossom) {
+ (*_blossom_data)[blossom].offset -= _delta_sum;
+
+ if (_blossom_set->classPrio(blossom) !=
+ std::numeric_limits<Value>::max()) {
+ _delta2->push(blossom, _blossom_set->classPrio(blossom) -
+ (*_blossom_data)[blossom].offset);
+ }
+
+ if (!_blossom_set->trivial(blossom)) {
+ _delta4->erase(blossom);
+ }
+ }
+
+ void oddToEven(int blossom, int tree) {
+ if (!_blossom_set->trivial(blossom)) {
+ _delta4->erase(blossom);
+ (*_blossom_data)[blossom].pot -=
+ 2 * (2 * _delta_sum - (*_blossom_data)[blossom].offset);
+ }
+
+ for (typename BlossomSet::ItemIt n(*_blossom_set, blossom);
+ n != INVALID; ++n) {
+ int ni = (*_node_index)[n];
+
+ _blossom_set->increase(n, std::numeric_limits<Value>::max());
+
+ (*_node_data)[ni].heap.clear();
+ (*_node_data)[ni].heap_index.clear();
+ (*_node_data)[ni].pot +=
+ 2 * _delta_sum - (*_blossom_data)[blossom].offset;
+
+ for (InArcIt e(_graph, n); e != INVALID; ++e) {
+ Node v = _graph.source(e);
+ int vb = _blossom_set->find(v);
+ int vi = (*_node_index)[v];
+
+ Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot -
+ dualScale * _weight[e];
+
+ if ((*_blossom_data)[vb].status == EVEN) {
+ if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) {
+ _delta3->push(e, rw / 2);
+ }
+ } else {
+
+ typename std::map<int, Arc>::iterator it =
+ (*_node_data)[vi].heap_index.find(tree);
+
+ if (it != (*_node_data)[vi].heap_index.end()) {
+ if ((*_node_data)[vi].heap[it->second] > rw) {
+ (*_node_data)[vi].heap.replace(it->second, e);
+ (*_node_data)[vi].heap.decrease(e, rw);
+ it->second = e;
+ }
+ } else {
+ (*_node_data)[vi].heap.push(e, rw);
+ (*_node_data)[vi].heap_index.insert(std::make_pair(tree, e));
+ }
+
+ if ((*_blossom_set)[v] > (*_node_data)[vi].heap.prio()) {
+ _blossom_set->decrease(v, (*_node_data)[vi].heap.prio());
+
+ if ((*_blossom_data)[vb].status == MATCHED) {
+ if (_delta2->state(vb) != _delta2->IN_HEAP) {
+ _delta2->push(vb, _blossom_set->classPrio(vb) -
+ (*_blossom_data)[vb].offset);
+ } else if ((*_delta2)[vb] > _blossom_set->classPrio(vb) -
+ (*_blossom_data)[vb].offset) {
+ _delta2->decrease(vb, _blossom_set->classPrio(vb) -
+ (*_blossom_data)[vb].offset);
+ }
+ }
+ }
+ }
+ }
+ }
+ (*_blossom_data)[blossom].offset = 0;
+ }
+
+ void alternatePath(int even, int tree) {
+ int odd;
+
+ evenToMatched(even, tree);
+ (*_blossom_data)[even].status = MATCHED;
+
+ while ((*_blossom_data)[even].pred != INVALID) {
+ odd = _blossom_set->find(_graph.target((*_blossom_data)[even].pred));
+ (*_blossom_data)[odd].status = MATCHED;
+ oddToMatched(odd);
+ (*_blossom_data)[odd].next = (*_blossom_data)[odd].pred;
+
+ even = _blossom_set->find(_graph.target((*_blossom_data)[odd].pred));
+ (*_blossom_data)[even].status = MATCHED;
+ evenToMatched(even, tree);
+ (*_blossom_data)[even].next =
+ _graph.oppositeArc((*_blossom_data)[odd].pred);
+ }
+
+ }
+
+ void destroyTree(int tree) {
+ for (TreeSet::ItemIt b(*_tree_set, tree); b != INVALID; ++b) {
+ if ((*_blossom_data)[b].status == EVEN) {
+ (*_blossom_data)[b].status = MATCHED;
+ evenToMatched(b, tree);
+ } else if ((*_blossom_data)[b].status == ODD) {
+ (*_blossom_data)[b].status = MATCHED;
+ oddToMatched(b);
+ }
+ }
+ _tree_set->eraseClass(tree);
+ }
+
+ void augmentOnEdge(const Edge& edge) {
+
+ int left = _blossom_set->find(_graph.u(edge));
+ int right = _blossom_set->find(_graph.v(edge));
+
+ int left_tree = _tree_set->find(left);
+ alternatePath(left, left_tree);
+ destroyTree(left_tree);
+
+ int right_tree = _tree_set->find(right);
+ alternatePath(right, right_tree);
+ destroyTree(right_tree);
+
+ (*_blossom_data)[left].next = _graph.direct(edge, true);
+ (*_blossom_data)[right].next = _graph.direct(edge, false);
+ }
+
+ void extendOnArc(const Arc& arc) {
+ int base = _blossom_set->find(_graph.target(arc));
+ int tree = _tree_set->find(base);
+
+ int odd = _blossom_set->find(_graph.source(arc));
+ _tree_set->insert(odd, tree);
+ (*_blossom_data)[odd].status = ODD;
+ matchedToOdd(odd);
+ (*_blossom_data)[odd].pred = arc;
+
+ int even = _blossom_set->find(_graph.target((*_blossom_data)[odd].next));
+ (*_blossom_data)[even].pred = (*_blossom_data)[even].next;
+ _tree_set->insert(even, tree);
+ (*_blossom_data)[even].status = EVEN;
+ matchedToEven(even, tree);
+ }
+
+ void shrinkOnEdge(const Edge& edge, int tree) {
+ int nca = -1;
+ std::vector<int> left_path, right_path;
+
+ {
+ std::set<int> left_set, right_set;
+ int left = _blossom_set->find(_graph.u(edge));
+ left_path.push_back(left);
+ left_set.insert(left);
+
+ int right = _blossom_set->find(_graph.v(edge));
+ right_path.push_back(right);
+ right_set.insert(right);
+
+ while (true) {
+
+ if ((*_blossom_data)[left].pred == INVALID) break;
+
+ left =
+ _blossom_set->find(_graph.target((*_blossom_data)[left].pred));
+ left_path.push_back(left);
+ left =
+ _blossom_set->find(_graph.target((*_blossom_data)[left].pred));
+ left_path.push_back(left);
+
+ left_set.insert(left);
+
+ if (right_set.find(left) != right_set.end()) {
+ nca = left;
+ break;
+ }
+
+ if ((*_blossom_data)[right].pred == INVALID) break;
+
+ right =
+ _blossom_set->find(_graph.target((*_blossom_data)[right].pred));
+ right_path.push_back(right);
+ right =
+ _blossom_set->find(_graph.target((*_blossom_data)[right].pred));
+ right_path.push_back(right);
+
+ right_set.insert(right);
+
+ if (left_set.find(right) != left_set.end()) {
+ nca = right;
+ break;
+ }
+
+ }
+
+ if (nca == -1) {
+ if ((*_blossom_data)[left].pred == INVALID) {
+ nca = right;
+ while (left_set.find(nca) == left_set.end()) {
+ nca =
+ _blossom_set->find(_graph.target((*_blossom_data)[nca].pred));
+ right_path.push_back(nca);
+ nca =
+ _blossom_set->find(_graph.target((*_blossom_data)[nca].pred));
+ right_path.push_back(nca);
+ }
+ } else {
+ nca = left;
+ while (right_set.find(nca) == right_set.end()) {
+ nca =
+ _blossom_set->find(_graph.target((*_blossom_data)[nca].pred));
+ left_path.push_back(nca);
+ nca =
+ _blossom_set->find(_graph.target((*_blossom_data)[nca].pred));
+ left_path.push_back(nca);
+ }
+ }
+ }
+ }
+
+ std::vector<int> subblossoms;
+ Arc prev;
+
+ prev = _graph.direct(edge, true);
+ for (int i = 0; left_path[i] != nca; i += 2) {
+ subblossoms.push_back(left_path[i]);
+ (*_blossom_data)[left_path[i]].next = prev;
+ _tree_set->erase(left_path[i]);
+
+ subblossoms.push_back(left_path[i + 1]);
+ (*_blossom_data)[left_path[i + 1]].status = EVEN;
+ oddToEven(left_path[i + 1], tree);
+ _tree_set->erase(left_path[i + 1]);
+ prev = _graph.oppositeArc((*_blossom_data)[left_path[i + 1]].pred);
+ }
+
+ int k = 0;
+ while (right_path[k] != nca) ++k;
+
+ subblossoms.push_back(nca);
+ (*_blossom_data)[nca].next = prev;
+
+ for (int i = k - 2; i >= 0; i -= 2) {
+ subblossoms.push_back(right_path[i + 1]);
+ (*_blossom_data)[right_path[i + 1]].status = EVEN;
+ oddToEven(right_path[i + 1], tree);
+ _tree_set->erase(right_path[i + 1]);
+
+ (*_blossom_data)[right_path[i + 1]].next =
+ (*_blossom_data)[right_path[i + 1]].pred;
+
+ subblossoms.push_back(right_path[i]);
+ _tree_set->erase(right_path[i]);
+ }
+
+ int surface =
+ _blossom_set->join(subblossoms.begin(), subblossoms.end());
+
+ for (int i = 0; i < int(subblossoms.size()); ++i) {
+ if (!_blossom_set->trivial(subblossoms[i])) {
+ (*_blossom_data)[subblossoms[i]].pot += 2 * _delta_sum;
+ }
+ (*_blossom_data)[subblossoms[i]].status = MATCHED;
+ }
+
+ (*_blossom_data)[surface].pot = -2 * _delta_sum;
+ (*_blossom_data)[surface].offset = 0;
+ (*_blossom_data)[surface].status = EVEN;
+ (*_blossom_data)[surface].pred = (*_blossom_data)[nca].pred;
+ (*_blossom_data)[surface].next = (*_blossom_data)[nca].pred;
+
+ _tree_set->insert(surface, tree);
+ _tree_set->erase(nca);
+ }
+
+ void splitBlossom(int blossom) {
+ Arc next = (*_blossom_data)[blossom].next;
+ Arc pred = (*_blossom_data)[blossom].pred;
+
+ int tree = _tree_set->find(blossom);
+
+ (*_blossom_data)[blossom].status = MATCHED;
+ oddToMatched(blossom);
+ if (_delta2->state(blossom) == _delta2->IN_HEAP) {
+ _delta2->erase(blossom);
+ }
+
+ std::vector<int> subblossoms;
+ _blossom_set->split(blossom, std::back_inserter(subblossoms));
+
+ Value offset = (*_blossom_data)[blossom].offset;
+ int b = _blossom_set->find(_graph.source(pred));
+ int d = _blossom_set->find(_graph.source(next));
+
+ int ib = -1, id = -1;
+ for (int i = 0; i < int(subblossoms.size()); ++i) {
+ if (subblossoms[i] == b) ib = i;
+ if (subblossoms[i] == d) id = i;
+
+ (*_blossom_data)[subblossoms[i]].offset = offset;
+ if (!_blossom_set->trivial(subblossoms[i])) {
+ (*_blossom_data)[subblossoms[i]].pot -= 2 * offset;
+ }
+ if (_blossom_set->classPrio(subblossoms[i]) !=
+ std::numeric_limits<Value>::max()) {
+ _delta2->push(subblossoms[i],
+ _blossom_set->classPrio(subblossoms[i]) -
+ (*_blossom_data)[subblossoms[i]].offset);
+ }
+ }
+
+ if (id > ib ? ((id - ib) % 2 == 0) : ((ib - id) % 2 == 1)) {
+ for (int i = (id + 1) % subblossoms.size();
+ i != ib; i = (i + 2) % subblossoms.size()) {
+ int sb = subblossoms[i];
+ int tb = subblossoms[(i + 1) % subblossoms.size()];
+ (*_blossom_data)[sb].next =
+ _graph.oppositeArc((*_blossom_data)[tb].next);
+ }
+
+ for (int i = ib; i != id; i = (i + 2) % subblossoms.size()) {
+ int sb = subblossoms[i];
+ int tb = subblossoms[(i + 1) % subblossoms.size()];
+ int ub = subblossoms[(i + 2) % subblossoms.size()];
+
+ (*_blossom_data)[sb].status = ODD;
+ matchedToOdd(sb);
+ _tree_set->insert(sb, tree);
+ (*_blossom_data)[sb].pred = pred;
+ (*_blossom_data)[sb].next =
+ _graph.oppositeArc((*_blossom_data)[tb].next);
+
+ pred = (*_blossom_data)[ub].next;
+
+ (*_blossom_data)[tb].status = EVEN;
+ matchedToEven(tb, tree);
+ _tree_set->insert(tb, tree);
+ (*_blossom_data)[tb].pred = (*_blossom_data)[tb].next;
+ }
+
+ (*_blossom_data)[subblossoms[id]].status = ODD;
+ matchedToOdd(subblossoms[id]);
+ _tree_set->insert(subblossoms[id], tree);
+ (*_blossom_data)[subblossoms[id]].next = next;
+ (*_blossom_data)[subblossoms[id]].pred = pred;
+
+ } else {
+
+ for (int i = (ib + 1) % subblossoms.size();
+ i != id; i = (i + 2) % subblossoms.size()) {
+ int sb = subblossoms[i];
+ int tb = subblossoms[(i + 1) % subblossoms.size()];
+ (*_blossom_data)[sb].next =
+ _graph.oppositeArc((*_blossom_data)[tb].next);
+ }
+
+ for (int i = id; i != ib; i = (i + 2) % subblossoms.size()) {
+ int sb = subblossoms[i];
+ int tb = subblossoms[(i + 1) % subblossoms.size()];
+ int ub = subblossoms[(i + 2) % subblossoms.size()];
+
+ (*_blossom_data)[sb].status = ODD;
+ matchedToOdd(sb);
+ _tree_set->insert(sb, tree);
+ (*_blossom_data)[sb].next = next;
+ (*_blossom_data)[sb].pred =
+ _graph.oppositeArc((*_blossom_data)[tb].next);
+
+ (*_blossom_data)[tb].status = EVEN;
+ matchedToEven(tb, tree);
+ _tree_set->insert(tb, tree);
+ (*_blossom_data)[tb].pred =
+ (*_blossom_data)[tb].next =
+ _graph.oppositeArc((*_blossom_data)[ub].next);
+ next = (*_blossom_data)[ub].next;
+ }
+
+ (*_blossom_data)[subblossoms[ib]].status = ODD;
+ matchedToOdd(subblossoms[ib]);
+ _tree_set->insert(subblossoms[ib], tree);
+ (*_blossom_data)[subblossoms[ib]].next = next;
+ (*_blossom_data)[subblossoms[ib]].pred = pred;
+ }
+ _tree_set->erase(blossom);
+ }
+
+ void extractBlossom(int blossom, const Node& base, const Arc& matching) {
+ if (_blossom_set->trivial(blossom)) {
+ int bi = (*_node_index)[base];
+ Value pot = (*_node_data)[bi].pot;
+
+ (*_matching)[base] = matching;
+ _blossom_node_list.push_back(base);
+ (*_node_potential)[base] = pot;
+ } else {
+
+ Value pot = (*_blossom_data)[blossom].pot;
+ int bn = _blossom_node_list.size();
+
+ std::vector<int> subblossoms;
+ _blossom_set->split(blossom, std::back_inserter(subblossoms));
+ int b = _blossom_set->find(base);
+ int ib = -1;
+ for (int i = 0; i < int(subblossoms.size()); ++i) {
+ if (subblossoms[i] == b) { ib = i; break; }
+ }
+
+ for (int i = 1; i < int(subblossoms.size()); i += 2) {
+ int sb = subblossoms[(ib + i) % subblossoms.size()];
+ int tb = subblossoms[(ib + i + 1) % subblossoms.size()];
+
+ Arc m = (*_blossom_data)[tb].next;
+ extractBlossom(sb, _graph.target(m), _graph.oppositeArc(m));
+ extractBlossom(tb, _graph.source(m), m);
+ }
+ extractBlossom(subblossoms[ib], base, matching);
+
+ int en = _blossom_node_list.size();
+
+ _blossom_potential.push_back(BlossomVariable(bn, en, pot));
+ }
+ }
+
+ void extractMatching() {
+ std::vector<int> blossoms;
+ for (typename BlossomSet::ClassIt c(*_blossom_set); c != INVALID; ++c) {
+ blossoms.push_back(c);
+ }
+
+ for (int i = 0; i < int(blossoms.size()); ++i) {
+
+ Value offset = (*_blossom_data)[blossoms[i]].offset;
+ (*_blossom_data)[blossoms[i]].pot += 2 * offset;
+ for (typename BlossomSet::ItemIt n(*_blossom_set, blossoms[i]);
+ n != INVALID; ++n) {
+ (*_node_data)[(*_node_index)[n]].pot -= offset;
+ }
+
+ Arc matching = (*_blossom_data)[blossoms[i]].next;
+ Node base = _graph.source(matching);
+ extractBlossom(blossoms[i], base, matching);
+ }
+ }
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ MaxWeightedPerfectMatching(const Graph& graph, const WeightMap& weight)
+ : _graph(graph), _weight(weight), _matching(0),
+ _node_potential(0), _blossom_potential(), _blossom_node_list(),
+ _node_num(0), _blossom_num(0),
+
+ _blossom_index(0), _blossom_set(0), _blossom_data(0),
+ _node_index(0), _node_heap_index(0), _node_data(0),
+ _tree_set_index(0), _tree_set(0),
+
+ _delta2_index(0), _delta2(0),
+ _delta3_index(0), _delta3(0),
+ _delta4_index(0), _delta4(0),
+
+ _delta_sum(), _unmatched(0),
+
+ _fractional(0)
+ {}
+
+ ~MaxWeightedPerfectMatching() {
+ destroyStructures();
+ if (_fractional) {
+ delete _fractional;
+ }
+ }
+
+ /// \name Execution Control
+ /// The simplest way to execute the algorithm is to use the
+ /// \ref run() member function.
+
+ ///@{
+
+ /// \brief Initialize the algorithm
+ ///
+ /// This function initializes the algorithm.
+ void init() {
+ createStructures();
+
+ _blossom_node_list.clear();
+ _blossom_potential.clear();
+
+ for (ArcIt e(_graph); e != INVALID; ++e) {
+ (*_node_heap_index)[e] = BinHeap<Value, IntArcMap>::PRE_HEAP;
+ }
+ for (EdgeIt e(_graph); e != INVALID; ++e) {
+ (*_delta3_index)[e] = _delta3->PRE_HEAP;
+ }
+ for (int i = 0; i < _blossom_num; ++i) {
+ (*_delta2_index)[i] = _delta2->PRE_HEAP;
+ (*_delta4_index)[i] = _delta4->PRE_HEAP;
+ }
+
+ _unmatched = _node_num;
+
+ _delta2->clear();
+ _delta3->clear();
+ _delta4->clear();
+ _blossom_set->clear();
+ _tree_set->clear();
+
+ int index = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ Value max = - std::numeric_limits<Value>::max();
+ for (OutArcIt e(_graph, n); e != INVALID; ++e) {
+ if (_graph.target(e) == n) continue;
+ if ((dualScale * _weight[e]) / 2 > max) {
+ max = (dualScale * _weight[e]) / 2;
+ }
+ }
+ (*_node_index)[n] = index;
+ (*_node_data)[index].heap_index.clear();
+ (*_node_data)[index].heap.clear();
+ (*_node_data)[index].pot = max;
+ int blossom =
+ _blossom_set->insert(n, std::numeric_limits<Value>::max());
+
+ _tree_set->insert(blossom);
+
+ (*_blossom_data)[blossom].status = EVEN;
+ (*_blossom_data)[blossom].pred = INVALID;
+ (*_blossom_data)[blossom].next = INVALID;
+ (*_blossom_data)[blossom].pot = 0;
+ (*_blossom_data)[blossom].offset = 0;
+ ++index;
+ }
+ for (EdgeIt e(_graph); e != INVALID; ++e) {
+ int si = (*_node_index)[_graph.u(e)];
+ int ti = (*_node_index)[_graph.v(e)];
+ if (_graph.u(e) != _graph.v(e)) {
+ _delta3->push(e, ((*_node_data)[si].pot + (*_node_data)[ti].pot -
+ dualScale * _weight[e]) / 2);
+ }
+ }
+ }
+
+ /// \brief Initialize the algorithm with fractional matching
+ ///
+ /// This function initializes the algorithm with a fractional
+ /// matching. This initialization is also called jumpstart heuristic.
+ void fractionalInit() {
+ createStructures();
+
+ _blossom_node_list.clear();
+ _blossom_potential.clear();
+
+ if (_fractional == 0) {
+ _fractional = new FractionalMatching(_graph, _weight, false);
+ }
+ if (!_fractional->run()) {
+ _unmatched = -1;
+ return;
+ }
+
+ for (ArcIt e(_graph); e != INVALID; ++e) {
+ (*_node_heap_index)[e] = BinHeap<Value, IntArcMap>::PRE_HEAP;
+ }
+ for (EdgeIt e(_graph); e != INVALID; ++e) {
+ (*_delta3_index)[e] = _delta3->PRE_HEAP;
+ }
+ for (int i = 0; i < _blossom_num; ++i) {
+ (*_delta2_index)[i] = _delta2->PRE_HEAP;
+ (*_delta4_index)[i] = _delta4->PRE_HEAP;
+ }
+
+ _unmatched = 0;
+
+ _delta2->clear();
+ _delta3->clear();
+ _delta4->clear();
+ _blossom_set->clear();
+ _tree_set->clear();
+
+ int index = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ Value pot = _fractional->nodeValue(n);
+ (*_node_index)[n] = index;
+ (*_node_data)[index].pot = pot;
+ (*_node_data)[index].heap_index.clear();
+ (*_node_data)[index].heap.clear();
+ int blossom =
+ _blossom_set->insert(n, std::numeric_limits<Value>::max());
+
+ (*_blossom_data)[blossom].status = MATCHED;
+ (*_blossom_data)[blossom].pred = INVALID;
+ (*_blossom_data)[blossom].next = _fractional->matching(n);
+ (*_blossom_data)[blossom].pot = 0;
+ (*_blossom_data)[blossom].offset = 0;
+ ++index;
+ }
+
+ typename Graph::template NodeMap<bool> processed(_graph, false);
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ if (processed[n]) continue;
+ processed[n] = true;
+ if (_fractional->matching(n) == INVALID) continue;
+ int num = 1;
+ Node v = _graph.target(_fractional->matching(n));
+ while (n != v) {
+ processed[v] = true;
+ v = _graph.target(_fractional->matching(v));
+ ++num;
+ }
+
+ if (num % 2 == 1) {
+ std::vector<int> subblossoms(num);
+
+ subblossoms[--num] = _blossom_set->find(n);
+ v = _graph.target(_fractional->matching(n));
+ while (n != v) {
+ subblossoms[--num] = _blossom_set->find(v);
+ v = _graph.target(_fractional->matching(v));
+ }
+
+ int surface =
+ _blossom_set->join(subblossoms.begin(), subblossoms.end());
+ (*_blossom_data)[surface].status = EVEN;
+ (*_blossom_data)[surface].pred = INVALID;
+ (*_blossom_data)[surface].next = INVALID;
+ (*_blossom_data)[surface].pot = 0;
+ (*_blossom_data)[surface].offset = 0;
+
+ _tree_set->insert(surface);
+ ++_unmatched;
+ }
+ }
+
+ for (EdgeIt e(_graph); e != INVALID; ++e) {
+ int si = (*_node_index)[_graph.u(e)];
+ int sb = _blossom_set->find(_graph.u(e));
+ int ti = (*_node_index)[_graph.v(e)];
+ int tb = _blossom_set->find(_graph.v(e));
+ if ((*_blossom_data)[sb].status == EVEN &&
+ (*_blossom_data)[tb].status == EVEN && sb != tb) {
+ _delta3->push(e, ((*_node_data)[si].pot + (*_node_data)[ti].pot -
+ dualScale * _weight[e]) / 2);
+ }
+ }
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ int nb = _blossom_set->find(n);
+ if ((*_blossom_data)[nb].status != MATCHED) continue;
+ int ni = (*_node_index)[n];
+
+ for (OutArcIt e(_graph, n); e != INVALID; ++e) {
+ Node v = _graph.target(e);
+ int vb = _blossom_set->find(v);
+ int vi = (*_node_index)[v];
+
+ Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot -
+ dualScale * _weight[e];
+
+ if ((*_blossom_data)[vb].status == EVEN) {
+
+ int vt = _tree_set->find(vb);
+
+ typename std::map<int, Arc>::iterator it =
+ (*_node_data)[ni].heap_index.find(vt);
+
+ if (it != (*_node_data)[ni].heap_index.end()) {
+ if ((*_node_data)[ni].heap[it->second] > rw) {
+ (*_node_data)[ni].heap.replace(it->second, e);
+ (*_node_data)[ni].heap.decrease(e, rw);
+ it->second = e;
+ }
+ } else {
+ (*_node_data)[ni].heap.push(e, rw);
+ (*_node_data)[ni].heap_index.insert(std::make_pair(vt, e));
+ }
+ }
+ }
+
+ if (!(*_node_data)[ni].heap.empty()) {
+ _blossom_set->decrease(n, (*_node_data)[ni].heap.prio());
+ _delta2->push(nb, _blossom_set->classPrio(nb));
+ }
+ }
+ }
+
+ /// \brief Start the algorithm
+ ///
+ /// This function starts the algorithm.
+ ///
+ /// \pre \ref init() or \ref fractionalInit() must be called before
+ /// using this function.
+ bool start() {
+ enum OpType {
+ D2, D3, D4
+ };
+
+ if (_unmatched == -1) return false;
+
+ while (_unmatched > 0) {
+ Value d2 = !_delta2->empty() ?
+ _delta2->prio() : std::numeric_limits<Value>::max();
+
+ Value d3 = !_delta3->empty() ?
+ _delta3->prio() : std::numeric_limits<Value>::max();
+
+ Value d4 = !_delta4->empty() ?
+ _delta4->prio() : std::numeric_limits<Value>::max();
+
+ _delta_sum = d3; OpType ot = D3;
+ if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; }
+ if (d4 < _delta_sum) { _delta_sum = d4; ot = D4; }
+
+ if (_delta_sum == std::numeric_limits<Value>::max()) {
+ return false;
+ }
+
+ switch (ot) {
+ case D2:
+ {
+ int blossom = _delta2->top();
+ Node n = _blossom_set->classTop(blossom);
+ Arc e = (*_node_data)[(*_node_index)[n]].heap.top();
+ extendOnArc(e);
+ }
+ break;
+ case D3:
+ {
+ Edge e = _delta3->top();
+
+ int left_blossom = _blossom_set->find(_graph.u(e));
+ int right_blossom = _blossom_set->find(_graph.v(e));
+
+ if (left_blossom == right_blossom) {
+ _delta3->pop();
+ } else {
+ int left_tree = _tree_set->find(left_blossom);
+ int right_tree = _tree_set->find(right_blossom);
+
+ if (left_tree == right_tree) {
+ shrinkOnEdge(e, left_tree);
+ } else {
+ augmentOnEdge(e);
+ _unmatched -= 2;
+ }
+ }
+ } break;
+ case D4:
+ splitBlossom(_delta4->top());
+ break;
+ }
+ }
+ extractMatching();
+ return true;
+ }
+
+ /// \brief Run the algorithm.
+ ///
+ /// This method runs the \c %MaxWeightedPerfectMatching algorithm.
+ ///
+ /// \note mwpm.run() is just a shortcut of the following code.
+ /// \code
+ /// mwpm.fractionalInit();
+ /// mwpm.start();
+ /// \endcode
+ bool run() {
+ fractionalInit();
+ return start();
+ }
+
+ /// @}
+
+ /// \name Primal Solution
+ /// Functions to get the primal solution, i.e. the maximum weighted
+ /// perfect matching.\n
+ /// Either \ref run() or \ref start() function should be called before
+ /// using them.
+
+ /// @{
+
+ /// \brief Return the weight of the matching.
+ ///
+ /// This function returns the weight of the found matching.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Value matchingWeight() const {
+ Value sum = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ if ((*_matching)[n] != INVALID) {
+ sum += _weight[(*_matching)[n]];
+ }
+ }
+ return sum / 2;
+ }
+
+ /// \brief Return \c true if the given edge is in the matching.
+ ///
+ /// This function returns \c true if the given edge is in the found
+ /// matching.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ bool matching(const Edge& edge) const {
+ return static_cast<const Edge&>((*_matching)[_graph.u(edge)]) == edge;
+ }
+
+ /// \brief Return the matching arc (or edge) incident to the given node.
+ ///
+ /// This function returns the matching arc (or edge) incident to the
+ /// given node in the found matching or \c INVALID if the node is
+ /// not covered by the matching.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Arc matching(const Node& node) const {
+ return (*_matching)[node];
+ }
+
+ /// \brief Return a const reference to the matching map.
+ ///
+ /// This function returns a const reference to a node map that stores
+ /// the matching arc (or edge) incident to each node.
+ const MatchingMap& matchingMap() const {
+ return *_matching;
+ }
+
+ /// \brief Return the mate of the given node.
+ ///
+ /// This function returns the mate of the given node in the found
+ /// matching or \c INVALID if the node is not covered by the matching.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Node mate(const Node& node) const {
+ return _graph.target((*_matching)[node]);
+ }
+
+ /// @}
+
+ /// \name Dual Solution
+ /// Functions to get the dual solution.\n
+ /// Either \ref run() or \ref start() function should be called before
+ /// using them.
+
+ /// @{
+
+ /// \brief Return the value of the dual solution.
+ ///
+ /// This function returns the value of the dual solution.
+ /// It should be equal to the primal value scaled by \ref dualScale
+ /// "dual scale".
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Value dualValue() const {
+ Value sum = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ sum += nodeValue(n);
+ }
+ for (int i = 0; i < blossomNum(); ++i) {
+ sum += blossomValue(i) * (blossomSize(i) / 2);
+ }
+ return sum;
+ }
+
+ /// \brief Return the dual value (potential) of the given node.
+ ///
+ /// This function returns the dual value (potential) of the given node.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Value nodeValue(const Node& n) const {
+ return (*_node_potential)[n];
+ }
+
+ /// \brief Return the number of the blossoms in the basis.
+ ///
+ /// This function returns the number of the blossoms in the basis.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ /// \see BlossomIt
+ int blossomNum() const {
+ return _blossom_potential.size();
+ }
+
+ /// \brief Return the number of the nodes in the given blossom.
+ ///
+ /// This function returns the number of the nodes in the given blossom.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ /// \see BlossomIt
+ int blossomSize(int k) const {
+ return _blossom_potential[k].end - _blossom_potential[k].begin;
+ }
+
+ /// \brief Return the dual value (ptential) of the given blossom.
+ ///
+ /// This function returns the dual value (ptential) of the given blossom.
+ ///
+ /// \pre Either run() or start() must be called before using this function.
+ Value blossomValue(int k) const {
+ return _blossom_potential[k].value;
+ }
+
+ /// \brief Iterator for obtaining the nodes of a blossom.
+ ///
+ /// This class provides an iterator for obtaining the nodes of the
+ /// given blossom. It lists a subset of the nodes.
+ /// Before using this iterator, you must allocate a
+ /// MaxWeightedPerfectMatching class and execute it.
+ class BlossomIt {
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// Constructor to get the nodes of the given variable.
+ ///
+ /// \pre Either \ref MaxWeightedPerfectMatching::run() "algorithm.run()"
+ /// or \ref MaxWeightedPerfectMatching::start() "algorithm.start()"
+ /// must be called before initializing this iterator.
+ BlossomIt(const MaxWeightedPerfectMatching& algorithm, int variable)
+ : _algorithm(&algorithm)
+ {
+ _index = _algorithm->_blossom_potential[variable].begin;
+ _last = _algorithm->_blossom_potential[variable].end;
+ }
+
+ /// \brief Conversion to \c Node.
+ ///
+ /// Conversion to \c Node.
+ operator Node() const {
+ return _algorithm->_blossom_node_list[_index];
+ }
+
+ /// \brief Increment operator.
+ ///
+ /// Increment operator.
+ BlossomIt& operator++() {
+ ++_index;
+ return *this;
+ }
+
+ /// \brief Validity checking
+ ///
+ /// This function checks whether the iterator is invalid.
+ bool operator==(Invalid) const { return _index == _last; }
+
+ /// \brief Validity checking
+ ///
+ /// This function checks whether the iterator is valid.
+ bool operator!=(Invalid) const { return _index != _last; }
+
+ private:
+ const MaxWeightedPerfectMatching* _algorithm;
+ int _last;
+ int _index;
+ };
+
+ /// @}
+
+ };
+
+} //END OF NAMESPACE LEMON
+
+#endif //LEMON_MATCHING_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/math.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/math.h
new file mode 100644
index 00000000000..5da50b07a9d
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/math.h
@@ -0,0 +1,77 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_MATH_H
+#define LEMON_MATH_H
+
+///\ingroup misc
+///\file
+///\brief Some extensions to the standard \c cmath library.
+///
+///Some extensions to the standard \c cmath library.
+///
+///This file includes the standard math library (cmath).
+
+#include<cmath>
+
+namespace lemon {
+
+ /// \addtogroup misc
+ /// @{
+
+ /// The Euler constant
+ const long double E = 2.7182818284590452353602874713526625L;
+ /// log_2(e)
+ const long double LOG2E = 1.4426950408889634073599246810018921L;
+ /// log_10(e)
+ const long double LOG10E = 0.4342944819032518276511289189166051L;
+ /// ln(2)
+ const long double LN2 = 0.6931471805599453094172321214581766L;
+ /// ln(10)
+ const long double LN10 = 2.3025850929940456840179914546843642L;
+ /// pi
+ const long double PI = 3.1415926535897932384626433832795029L;
+ /// pi/2
+ const long double PI_2 = 1.5707963267948966192313216916397514L;
+ /// pi/4
+ const long double PI_4 = 0.7853981633974483096156608458198757L;
+ /// sqrt(2)
+ const long double SQRT2 = 1.4142135623730950488016887242096981L;
+ /// 1/sqrt(2)
+ const long double SQRT1_2 = 0.7071067811865475244008443621048490L;
+
+ ///Check whether the parameter is NaN or not
+
+ ///This function checks whether the parameter is NaN or not.
+ ///Is should be equivalent with std::isnan(), but it is not
+ ///provided by all compilers.
+ inline bool isNaN(double v)
+ {
+ return v!=v;
+ }
+
+ ///Round a value to its closest integer
+ inline double round(double r) {
+ return (r > 0.0) ? std::floor(r + 0.5) : std::ceil(r - 0.5);
+ }
+
+ /// @}
+
+} //namespace lemon
+
+#endif //LEMON_MATH_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/max_cardinality_search.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/max_cardinality_search.h
new file mode 100644
index 00000000000..bfa9edb7734
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/max_cardinality_search.h
@@ -0,0 +1,794 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_MAX_CARDINALITY_SEARCH_H
+#define LEMON_MAX_CARDINALITY_SEARCH_H
+
+
+/// \ingroup search
+/// \file
+/// \brief Maximum cardinality search in undirected digraphs.
+
+#include <lemon/bin_heap.h>
+#include <lemon/bucket_heap.h>
+
+#include <lemon/error.h>
+#include <lemon/maps.h>
+
+#include <functional>
+
+namespace lemon {
+
+ /// \brief Default traits class of MaxCardinalitySearch class.
+ ///
+ /// Default traits class of MaxCardinalitySearch class.
+ /// \param Digraph Digraph type.
+ /// \param CapacityMap Type of capacity map.
+ template <typename GR, typename CAP>
+ struct MaxCardinalitySearchDefaultTraits {
+ /// The digraph type the algorithm runs on.
+ typedef GR Digraph;
+
+ template <typename CM>
+ struct CapMapSelector {
+
+ typedef CM CapacityMap;
+
+ static CapacityMap *createCapacityMap(const Digraph& g) {
+ return new CapacityMap(g);
+ }
+ };
+
+ template <typename CM>
+ struct CapMapSelector<ConstMap<CM, Const<int, 1> > > {
+
+ typedef ConstMap<CM, Const<int, 1> > CapacityMap;
+
+ static CapacityMap *createCapacityMap(const Digraph&) {
+ return new CapacityMap;
+ }
+ };
+
+ /// \brief The type of the map that stores the arc capacities.
+ ///
+ /// The type of the map that stores the arc capacities.
+ /// It must meet the \ref concepts::ReadMap "ReadMap" concept.
+ typedef typename CapMapSelector<CAP>::CapacityMap CapacityMap;
+
+ /// \brief The type of the capacity of the arcs.
+ typedef typename CapacityMap::Value Value;
+
+ /// \brief Instantiates a CapacityMap.
+ ///
+ /// This function instantiates a \ref CapacityMap.
+ /// \param digraph is the digraph, to which we would like to define
+ /// the CapacityMap.
+ static CapacityMap *createCapacityMap(const Digraph& digraph) {
+ return CapMapSelector<CapacityMap>::createCapacityMap(digraph);
+ }
+
+ /// \brief The cross reference type used by heap.
+ ///
+ /// The cross reference type used by heap.
+ /// Usually it is \c Digraph::NodeMap<int>.
+ typedef typename Digraph::template NodeMap<int> HeapCrossRef;
+
+ /// \brief Instantiates a HeapCrossRef.
+ ///
+ /// This function instantiates a \ref HeapCrossRef.
+ /// \param digraph is the digraph, to which we would like to define the
+ /// HeapCrossRef.
+ static HeapCrossRef *createHeapCrossRef(const Digraph &digraph) {
+ return new HeapCrossRef(digraph);
+ }
+
+ template <typename CapacityMap>
+ struct HeapSelector {
+ template <typename Value, typename Ref>
+ struct Selector {
+ typedef BinHeap<Value, Ref, std::greater<Value> > Heap;
+ };
+ };
+
+ template <typename CapacityKey>
+ struct HeapSelector<ConstMap<CapacityKey, Const<int, 1> > > {
+ template <typename Value, typename Ref>
+ struct Selector {
+ typedef BucketHeap<Ref, false > Heap;
+ };
+ };
+
+ /// \brief The heap type used by MaxCardinalitySearch algorithm.
+ ///
+ /// The heap type used by MaxCardinalitySearch algorithm. It should
+ /// maximalize the priorities. The default heap type is
+ /// the \ref BinHeap, but it is specialized when the
+ /// CapacityMap is ConstMap<Digraph::Node, Const<int, 1> >
+ /// to BucketHeap.
+ ///
+ /// \sa MaxCardinalitySearch
+ typedef typename HeapSelector<CapacityMap>
+ ::template Selector<Value, HeapCrossRef>
+ ::Heap Heap;
+
+ /// \brief Instantiates a Heap.
+ ///
+ /// This function instantiates a \ref Heap.
+ /// \param crossref The cross reference of the heap.
+ static Heap *createHeap(HeapCrossRef& crossref) {
+ return new Heap(crossref);
+ }
+
+ /// \brief The type of the map that stores whether a node is processed.
+ ///
+ /// The type of the map that stores whether a node is processed.
+ /// It must meet the \ref concepts::WriteMap "WriteMap" concept.
+ /// By default it is a NullMap.
+ typedef NullMap<typename Digraph::Node, bool> ProcessedMap;
+
+ /// \brief Instantiates a ProcessedMap.
+ ///
+ /// This function instantiates a \ref ProcessedMap.
+ /// \param digraph is the digraph, to which
+ /// we would like to define the \ref ProcessedMap
+#ifdef DOXYGEN
+ static ProcessedMap *createProcessedMap(const Digraph &digraph)
+#else
+ static ProcessedMap *createProcessedMap(const Digraph &)
+#endif
+ {
+ return new ProcessedMap();
+ }
+
+ /// \brief The type of the map that stores the cardinalities of the nodes.
+ ///
+ /// The type of the map that stores the cardinalities of the nodes.
+ /// It must meet the \ref concepts::WriteMap "WriteMap" concept.
+ typedef typename Digraph::template NodeMap<Value> CardinalityMap;
+
+ /// \brief Instantiates a CardinalityMap.
+ ///
+ /// This function instantiates a \ref CardinalityMap.
+ /// \param digraph is the digraph, to which we would like to
+ /// define the \ref CardinalityMap
+ static CardinalityMap *createCardinalityMap(const Digraph &digraph) {
+ return new CardinalityMap(digraph);
+ }
+
+
+ };
+
+ /// \ingroup search
+ ///
+ /// \brief Maximum Cardinality Search algorithm class.
+ ///
+ /// This class provides an efficient implementation of Maximum Cardinality
+ /// Search algorithm. The maximum cardinality search first chooses any
+ /// node of the digraph. Then every time it chooses one unprocessed node
+ /// with maximum cardinality, i.e the sum of capacities on out arcs
+ /// to the nodes
+ /// which were previusly processed.
+ /// If there is a cut in the digraph the algorithm should choose
+ /// again any unprocessed node of the digraph.
+
+ /// The arc capacities are passed to the algorithm using a
+ /// \ref concepts::ReadMap "ReadMap", so it is easy to change it to any
+ /// kind of capacity.
+ ///
+ /// The type of the capacity is determined by the \ref
+ /// concepts::ReadMap::Value "Value" of the capacity map.
+ ///
+ /// It is also possible to change the underlying priority heap.
+ ///
+ ///
+ /// \param GR The digraph type the algorithm runs on. The value of
+ /// Digraph is not used directly by the search algorithm, it
+ /// is only passed to \ref MaxCardinalitySearchDefaultTraits.
+ /// \param CAP This read-only ArcMap determines the capacities of
+ /// the arcs. It is read once for each arc, so the map may involve in
+ /// relatively time consuming process to compute the arc capacity if
+ /// it is necessary. The default map type is \ref
+ /// ConstMap "ConstMap<concepts::Digraph::Arc, Const<int,1> >". The value
+ /// of CapacityMap is not used directly by search algorithm, it is only
+ /// passed to \ref MaxCardinalitySearchDefaultTraits.
+ /// \param TR Traits class to set various data types used by the
+ /// algorithm. The default traits class is
+ /// \ref MaxCardinalitySearchDefaultTraits
+ /// "MaxCardinalitySearchDefaultTraits<GR, CAP>".
+ /// See \ref MaxCardinalitySearchDefaultTraits
+ /// for the documentation of a MaxCardinalitySearch traits class.
+
+#ifdef DOXYGEN
+ template <typename GR, typename CAP, typename TR>
+#else
+ template <typename GR, typename CAP =
+ ConstMap<typename GR::Arc, Const<int,1> >,
+ typename TR =
+ MaxCardinalitySearchDefaultTraits<GR, CAP> >
+#endif
+ class MaxCardinalitySearch {
+ public:
+
+ typedef TR Traits;
+ ///The type of the underlying digraph.
+ typedef typename Traits::Digraph Digraph;
+
+ ///The type of the capacity of the arcs.
+ typedef typename Traits::CapacityMap::Value Value;
+ ///The type of the map that stores the arc capacities.
+ typedef typename Traits::CapacityMap CapacityMap;
+ ///The type of the map indicating if a node is processed.
+ typedef typename Traits::ProcessedMap ProcessedMap;
+ ///The type of the map that stores the cardinalities of the nodes.
+ typedef typename Traits::CardinalityMap CardinalityMap;
+ ///The cross reference type used for the current heap.
+ typedef typename Traits::HeapCrossRef HeapCrossRef;
+ ///The heap type used by the algorithm. It maximizes the priorities.
+ typedef typename Traits::Heap Heap;
+ private:
+ // Pointer to the underlying digraph.
+ const Digraph *_graph;
+ // Pointer to the capacity map
+ const CapacityMap *_capacity;
+ // Indicates if \ref _capacity is locally allocated (\c true) or not.
+ bool local_capacity;
+ // Pointer to the map of cardinality.
+ CardinalityMap *_cardinality;
+ // Indicates if \ref _cardinality is locally allocated (\c true) or not.
+ bool local_cardinality;
+ // Pointer to the map of processed status of the nodes.
+ ProcessedMap *_processed;
+ // Indicates if \ref _processed is locally allocated (\c true) or not.
+ bool local_processed;
+ // Pointer to the heap cross references.
+ HeapCrossRef *_heap_cross_ref;
+ // Indicates if \ref _heap_cross_ref is locally allocated (\c true) or not.
+ bool local_heap_cross_ref;
+ // Pointer to the heap.
+ Heap *_heap;
+ // Indicates if \ref _heap is locally allocated (\c true) or not.
+ bool local_heap;
+
+ public :
+
+ typedef MaxCardinalitySearch Create;
+
+ ///\name Named template parameters
+
+ ///@{
+
+ template <class T>
+ struct DefCapacityMapTraits : public Traits {
+ typedef T CapacityMap;
+ static CapacityMap *createCapacityMap(const Digraph &) {
+ LEMON_ASSERT(false,"Uninitialized parameter.");
+ return 0;
+ }
+ };
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// CapacityMap type
+ ///
+ /// \ref named-templ-param "Named parameter" for setting CapacityMap type
+ /// for the algorithm.
+ template <class T>
+ struct SetCapacityMap
+ : public MaxCardinalitySearch<Digraph, CapacityMap,
+ DefCapacityMapTraits<T> > {
+ typedef MaxCardinalitySearch<Digraph, CapacityMap,
+ DefCapacityMapTraits<T> > Create;
+ };
+
+ template <class T>
+ struct DefCardinalityMapTraits : public Traits {
+ typedef T CardinalityMap;
+ static CardinalityMap *createCardinalityMap(const Digraph &)
+ {
+ LEMON_ASSERT(false,"Uninitialized parameter.");
+ return 0;
+ }
+ };
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// CardinalityMap type
+ ///
+ /// \ref named-templ-param "Named parameter" for setting CardinalityMap
+ /// type for the algorithm.
+ template <class T>
+ struct SetCardinalityMap
+ : public MaxCardinalitySearch<Digraph, CapacityMap,
+ DefCardinalityMapTraits<T> > {
+ typedef MaxCardinalitySearch<Digraph, CapacityMap,
+ DefCardinalityMapTraits<T> > Create;
+ };
+
+ template <class T>
+ struct DefProcessedMapTraits : public Traits {
+ typedef T ProcessedMap;
+ static ProcessedMap *createProcessedMap(const Digraph &) {
+ LEMON_ASSERT(false,"Uninitialized parameter.");
+ return 0;
+ }
+ };
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// ProcessedMap type
+ ///
+ /// \ref named-templ-param "Named parameter" for setting ProcessedMap type
+ /// for the algorithm.
+ template <class T>
+ struct SetProcessedMap
+ : public MaxCardinalitySearch<Digraph, CapacityMap,
+ DefProcessedMapTraits<T> > {
+ typedef MaxCardinalitySearch<Digraph, CapacityMap,
+ DefProcessedMapTraits<T> > Create;
+ };
+
+ template <class H, class CR>
+ struct DefHeapTraits : public Traits {
+ typedef CR HeapCrossRef;
+ typedef H Heap;
+ static HeapCrossRef *createHeapCrossRef(const Digraph &) {
+ LEMON_ASSERT(false,"Uninitialized parameter.");
+ return 0;
+ }
+ static Heap *createHeap(HeapCrossRef &) {
+ LEMON_ASSERT(false,"Uninitialized parameter.");
+ return 0;
+ }
+ };
+ /// \brief \ref named-templ-param "Named parameter" for setting heap
+ /// and cross reference type
+ ///
+ /// \ref named-templ-param "Named parameter" for setting heap and cross
+ /// reference type for the algorithm.
+ template <class H, class CR = typename Digraph::template NodeMap<int> >
+ struct SetHeap
+ : public MaxCardinalitySearch<Digraph, CapacityMap,
+ DefHeapTraits<H, CR> > {
+ typedef MaxCardinalitySearch< Digraph, CapacityMap,
+ DefHeapTraits<H, CR> > Create;
+ };
+
+ template <class H, class CR>
+ struct DefStandardHeapTraits : public Traits {
+ typedef CR HeapCrossRef;
+ typedef H Heap;
+ static HeapCrossRef *createHeapCrossRef(const Digraph &digraph) {
+ return new HeapCrossRef(digraph);
+ }
+ static Heap *createHeap(HeapCrossRef &crossref) {
+ return new Heap(crossref);
+ }
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting heap and
+ /// cross reference type with automatic allocation
+ ///
+ /// \ref named-templ-param "Named parameter" for setting heap and cross
+ /// reference type. It can allocate the heap and the cross reference
+ /// object if the cross reference's constructor waits for the digraph as
+ /// parameter and the heap's constructor waits for the cross reference.
+ template <class H, class CR = typename Digraph::template NodeMap<int> >
+ struct SetStandardHeap
+ : public MaxCardinalitySearch<Digraph, CapacityMap,
+ DefStandardHeapTraits<H, CR> > {
+ typedef MaxCardinalitySearch<Digraph, CapacityMap,
+ DefStandardHeapTraits<H, CR> >
+ Create;
+ };
+
+ ///@}
+
+
+ protected:
+
+ MaxCardinalitySearch() {}
+
+ public:
+
+ /// \brief Constructor.
+ ///
+ ///\param digraph the digraph the algorithm will run on.
+ ///\param capacity the capacity map used by the algorithm.
+ MaxCardinalitySearch(const Digraph& digraph,
+ const CapacityMap& capacity) :
+ _graph(&digraph),
+ _capacity(&capacity), local_capacity(false),
+ _cardinality(0), local_cardinality(false),
+ _processed(0), local_processed(false),
+ _heap_cross_ref(0), local_heap_cross_ref(false),
+ _heap(0), local_heap(false)
+ { }
+
+ /// \brief Constructor.
+ ///
+ ///\param digraph the digraph the algorithm will run on.
+ ///
+ ///A constant 1 capacity map will be allocated.
+ MaxCardinalitySearch(const Digraph& digraph) :
+ _graph(&digraph),
+ _capacity(0), local_capacity(false),
+ _cardinality(0), local_cardinality(false),
+ _processed(0), local_processed(false),
+ _heap_cross_ref(0), local_heap_cross_ref(false),
+ _heap(0), local_heap(false)
+ { }
+
+ /// \brief Destructor.
+ ~MaxCardinalitySearch() {
+ if(local_capacity) delete _capacity;
+ if(local_cardinality) delete _cardinality;
+ if(local_processed) delete _processed;
+ if(local_heap_cross_ref) delete _heap_cross_ref;
+ if(local_heap) delete _heap;
+ }
+
+ /// \brief Sets the capacity map.
+ ///
+ /// Sets the capacity map.
+ /// \return <tt> (*this) </tt>
+ MaxCardinalitySearch &capacityMap(const CapacityMap &m) {
+ if (local_capacity) {
+ delete _capacity;
+ local_capacity=false;
+ }
+ _capacity=&m;
+ return *this;
+ }
+
+ /// \brief Returns a const reference to the capacity map.
+ ///
+ /// Returns a const reference to the capacity map used by
+ /// the algorithm.
+ const CapacityMap &capacityMap() const {
+ return *_capacity;
+ }
+
+ /// \brief Sets the map storing the cardinalities calculated by the
+ /// algorithm.
+ ///
+ /// Sets the map storing the cardinalities calculated by the algorithm.
+ /// If you don't use this function before calling \ref run(),
+ /// it will allocate one. The destuctor deallocates this
+ /// automatically allocated map, of course.
+ /// \return <tt> (*this) </tt>
+ MaxCardinalitySearch &cardinalityMap(CardinalityMap &m) {
+ if(local_cardinality) {
+ delete _cardinality;
+ local_cardinality=false;
+ }
+ _cardinality = &m;
+ return *this;
+ }
+
+ /// \brief Sets the map storing the processed nodes.
+ ///
+ /// Sets the map storing the processed nodes.
+ /// If you don't use this function before calling \ref run(),
+ /// it will allocate one. The destuctor deallocates this
+ /// automatically allocated map, of course.
+ /// \return <tt> (*this) </tt>
+ MaxCardinalitySearch &processedMap(ProcessedMap &m)
+ {
+ if(local_processed) {
+ delete _processed;
+ local_processed=false;
+ }
+ _processed = &m;
+ return *this;
+ }
+
+ /// \brief Returns a const reference to the cardinality map.
+ ///
+ /// Returns a const reference to the cardinality map used by
+ /// the algorithm.
+ const ProcessedMap &processedMap() const {
+ return *_processed;
+ }
+
+ /// \brief Sets the heap and the cross reference used by algorithm.
+ ///
+ /// Sets the heap and the cross reference used by algorithm.
+ /// If you don't use this function before calling \ref run(),
+ /// it will allocate one. The destuctor deallocates this
+ /// automatically allocated map, of course.
+ /// \return <tt> (*this) </tt>
+ MaxCardinalitySearch &heap(Heap& hp, HeapCrossRef &cr) {
+ if(local_heap_cross_ref) {
+ delete _heap_cross_ref;
+ local_heap_cross_ref = false;
+ }
+ _heap_cross_ref = &cr;
+ if(local_heap) {
+ delete _heap;
+ local_heap = false;
+ }
+ _heap = &hp;
+ return *this;
+ }
+
+ /// \brief Returns a const reference to the heap.
+ ///
+ /// Returns a const reference to the heap used by
+ /// the algorithm.
+ const Heap &heap() const {
+ return *_heap;
+ }
+
+ /// \brief Returns a const reference to the cross reference.
+ ///
+ /// Returns a const reference to the cross reference
+ /// of the heap.
+ const HeapCrossRef &heapCrossRef() const {
+ return *_heap_cross_ref;
+ }
+
+ private:
+
+ typedef typename Digraph::Node Node;
+ typedef typename Digraph::NodeIt NodeIt;
+ typedef typename Digraph::Arc Arc;
+ typedef typename Digraph::InArcIt InArcIt;
+
+ void create_maps() {
+ if(!_capacity) {
+ local_capacity = true;
+ _capacity = Traits::createCapacityMap(*_graph);
+ }
+ if(!_cardinality) {
+ local_cardinality = true;
+ _cardinality = Traits::createCardinalityMap(*_graph);
+ }
+ if(!_processed) {
+ local_processed = true;
+ _processed = Traits::createProcessedMap(*_graph);
+ }
+ if (!_heap_cross_ref) {
+ local_heap_cross_ref = true;
+ _heap_cross_ref = Traits::createHeapCrossRef(*_graph);
+ }
+ if (!_heap) {
+ local_heap = true;
+ _heap = Traits::createHeap(*_heap_cross_ref);
+ }
+ }
+
+ void finalizeNodeData(Node node, Value capacity) {
+ _processed->set(node, true);
+ _cardinality->set(node, capacity);
+ }
+
+ public:
+ /// \name Execution control
+ /// The simplest way to execute the algorithm is to use
+ /// one of the member functions called \ref run().
+ /// \n
+ /// If you need more control on the execution,
+ /// first you must call \ref init(), then you can add several source nodes
+ /// with \ref addSource().
+ /// Finally \ref start() will perform the computation.
+
+ ///@{
+
+ /// \brief Initializes the internal data structures.
+ ///
+ /// Initializes the internal data structures, and clears the heap.
+ void init() {
+ create_maps();
+ _heap->clear();
+ for (NodeIt it(*_graph) ; it != INVALID ; ++it) {
+ _processed->set(it, false);
+ _heap_cross_ref->set(it, Heap::PRE_HEAP);
+ }
+ }
+
+ /// \brief Adds a new source node.
+ ///
+ /// Adds a new source node to the priority heap.
+ ///
+ /// It checks if the node has not yet been added to the heap.
+ void addSource(Node source, Value capacity = 0) {
+ if(_heap->state(source) == Heap::PRE_HEAP) {
+ _heap->push(source, capacity);
+ }
+ }
+
+ /// \brief Processes the next node in the priority heap
+ ///
+ /// Processes the next node in the priority heap.
+ ///
+ /// \return The processed node.
+ ///
+ /// \warning The priority heap must not be empty!
+ Node processNextNode() {
+ Node node = _heap->top();
+ finalizeNodeData(node, _heap->prio());
+ _heap->pop();
+
+ for (InArcIt it(*_graph, node); it != INVALID; ++it) {
+ Node source = _graph->source(it);
+ switch (_heap->state(source)) {
+ case Heap::PRE_HEAP:
+ _heap->push(source, (*_capacity)[it]);
+ break;
+ case Heap::IN_HEAP:
+ _heap->decrease(source, (*_heap)[source] + (*_capacity)[it]);
+ break;
+ case Heap::POST_HEAP:
+ break;
+ }
+ }
+ return node;
+ }
+
+ /// \brief Next node to be processed.
+ ///
+ /// Next node to be processed.
+ ///
+ /// \return The next node to be processed or INVALID if the
+ /// priority heap is empty.
+ Node nextNode() {
+ return !_heap->empty() ? _heap->top() : INVALID;
+ }
+
+ /// \brief Returns \c false if there are nodes
+ /// to be processed in the priority heap
+ ///
+ /// Returns \c false if there are nodes
+ /// to be processed in the priority heap
+ bool emptyQueue() { return _heap->empty(); }
+ /// \brief Returns the number of the nodes to be processed
+ /// in the priority heap
+ ///
+ /// Returns the number of the nodes to be processed in the priority heap
+ int emptySize() { return _heap->size(); }
+
+ /// \brief Executes the algorithm.
+ ///
+ /// Executes the algorithm.
+ ///
+ ///\pre init() must be called and at least one node should be added
+ /// with addSource() before using this function.
+ ///
+ /// This method runs the Maximum Cardinality Search algorithm from the
+ /// source node(s).
+ void start() {
+ while ( !_heap->empty() ) processNextNode();
+ }
+
+ /// \brief Executes the algorithm until \c dest is reached.
+ ///
+ /// Executes the algorithm until \c dest is reached.
+ ///
+ /// \pre init() must be called and at least one node should be added
+ /// with addSource() before using this function.
+ ///
+ /// This method runs the %MaxCardinalitySearch algorithm from the source
+ /// nodes.
+ void start(Node dest) {
+ while ( !_heap->empty() && _heap->top()!=dest ) processNextNode();
+ if ( !_heap->empty() ) finalizeNodeData(_heap->top(), _heap->prio());
+ }
+
+ /// \brief Executes the algorithm until a condition is met.
+ ///
+ /// Executes the algorithm until a condition is met.
+ ///
+ /// \pre init() must be called and at least one node should be added
+ /// with addSource() before using this function.
+ ///
+ /// \param nm must be a bool (or convertible) node map. The algorithm
+ /// will stop when it reaches a node \c v with <tt>nm[v]==true</tt>.
+ template <typename NodeBoolMap>
+ void start(const NodeBoolMap &nm) {
+ while ( !_heap->empty() && !nm[_heap->top()] ) processNextNode();
+ if ( !_heap->empty() ) finalizeNodeData(_heap->top(),_heap->prio());
+ }
+
+ /// \brief Runs the maximum cardinality search algorithm from node \c s.
+ ///
+ /// This method runs the %MaxCardinalitySearch algorithm from a root
+ /// node \c s.
+ ///
+ ///\note d.run(s) is just a shortcut of the following code.
+ ///\code
+ /// d.init();
+ /// d.addSource(s);
+ /// d.start();
+ ///\endcode
+ void run(Node s) {
+ init();
+ addSource(s);
+ start();
+ }
+
+ /// \brief Runs the maximum cardinality search algorithm for the
+ /// whole digraph.
+ ///
+ /// This method runs the %MaxCardinalitySearch algorithm from all
+ /// unprocessed node of the digraph.
+ ///
+ ///\note d.run(s) is just a shortcut of the following code.
+ ///\code
+ /// d.init();
+ /// for (NodeIt it(digraph); it != INVALID; ++it) {
+ /// if (!d.reached(it)) {
+ /// d.addSource(s);
+ /// d.start();
+ /// }
+ /// }
+ ///\endcode
+ void run() {
+ init();
+ for (NodeIt it(*_graph); it != INVALID; ++it) {
+ if (!reached(it)) {
+ addSource(it);
+ start();
+ }
+ }
+ }
+
+ ///@}
+
+ /// \name Query Functions
+ /// The results of the maximum cardinality search algorithm can be
+ /// obtained using these functions.
+ /// \n
+ /// Before the use of these functions, either run() or start() must be
+ /// called.
+
+ ///@{
+
+ /// \brief The cardinality of a node.
+ ///
+ /// Returns the cardinality of a node.
+ /// \pre \ref run() must be called before using this function.
+ /// \warning If node \c v in unreachable from the root the return value
+ /// of this funcion is undefined.
+ Value cardinality(Node node) const { return (*_cardinality)[node]; }
+
+ /// \brief The current cardinality of a node.
+ ///
+ /// Returns the current cardinality of a node.
+ /// \pre the given node should be reached but not processed
+ Value currentCardinality(Node node) const { return (*_heap)[node]; }
+
+ /// \brief Returns a reference to the NodeMap of cardinalities.
+ ///
+ /// Returns a reference to the NodeMap of cardinalities. \pre \ref run()
+ /// must be called before using this function.
+ const CardinalityMap &cardinalityMap() const { return *_cardinality;}
+
+ /// \brief Checks if a node is reachable from the root.
+ ///
+ /// Returns \c true if \c v is reachable from the root.
+ /// \warning The source nodes are initated as unreached.
+ /// \pre \ref run() must be called before using this function.
+ bool reached(Node v) { return (*_heap_cross_ref)[v] != Heap::PRE_HEAP; }
+
+ /// \brief Checks if a node is processed.
+ ///
+ /// Returns \c true if \c v is processed, i.e. the shortest
+ /// path to \c v has already found.
+ /// \pre \ref run() must be called before using this function.
+ bool processed(Node v) { return (*_heap_cross_ref)[v] == Heap::POST_HEAP; }
+
+ ///@}
+ };
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/min_cost_arborescence.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/min_cost_arborescence.h
new file mode 100644
index 00000000000..1d0a2b19d81
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/min_cost_arborescence.h
@@ -0,0 +1,808 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_MIN_COST_ARBORESCENCE_H
+#define LEMON_MIN_COST_ARBORESCENCE_H
+
+///\ingroup spantree
+///\file
+///\brief Minimum Cost Arborescence algorithm.
+
+#include <vector>
+
+#include <lemon/list_graph.h>
+#include <lemon/bin_heap.h>
+#include <lemon/assert.h>
+
+namespace lemon {
+
+
+ /// \brief Default traits class for MinCostArborescence class.
+ ///
+ /// Default traits class for MinCostArborescence class.
+ /// \param GR Digraph type.
+ /// \param CM Type of the cost map.
+ template <class GR, class CM>
+ struct MinCostArborescenceDefaultTraits{
+
+ /// \brief The digraph type the algorithm runs on.
+ typedef GR Digraph;
+
+ /// \brief The type of the map that stores the arc costs.
+ ///
+ /// The type of the map that stores the arc costs.
+ /// It must conform to the \ref concepts::ReadMap "ReadMap" concept.
+ typedef CM CostMap;
+
+ /// \brief The value type of the costs.
+ ///
+ /// The value type of the costs.
+ typedef typename CostMap::Value Value;
+
+ /// \brief The type of the map that stores which arcs are in the
+ /// arborescence.
+ ///
+ /// The type of the map that stores which arcs are in the
+ /// arborescence. It must conform to the \ref concepts::WriteMap
+ /// "WriteMap" concept, and its value type must be \c bool
+ /// (or convertible). Initially it will be set to \c false on each
+ /// arc, then it will be set on each arborescence arc once.
+ typedef typename Digraph::template ArcMap<bool> ArborescenceMap;
+
+ /// \brief Instantiates a \c ArborescenceMap.
+ ///
+ /// This function instantiates a \c ArborescenceMap.
+ /// \param digraph The digraph to which we would like to calculate
+ /// the \c ArborescenceMap.
+ static ArborescenceMap *createArborescenceMap(const Digraph &digraph){
+ return new ArborescenceMap(digraph);
+ }
+
+ /// \brief The type of the \c PredMap
+ ///
+ /// The type of the \c PredMap. It must confrom to the
+ /// \ref concepts::WriteMap "WriteMap" concept, and its value type
+ /// must be the \c Arc type of the digraph.
+ typedef typename Digraph::template NodeMap<typename Digraph::Arc> PredMap;
+
+ /// \brief Instantiates a \c PredMap.
+ ///
+ /// This function instantiates a \c PredMap.
+ /// \param digraph The digraph to which we would like to define the
+ /// \c PredMap.
+ static PredMap *createPredMap(const Digraph &digraph){
+ return new PredMap(digraph);
+ }
+
+ };
+
+ /// \ingroup spantree
+ ///
+ /// \brief Minimum Cost Arborescence algorithm class.
+ ///
+ /// This class provides an efficient implementation of the
+ /// Minimum Cost Arborescence algorithm. The arborescence is a tree
+ /// which is directed from a given source node of the digraph. One or
+ /// more sources should be given to the algorithm and it will calculate
+ /// the minimum cost subgraph that is the union of arborescences with the
+ /// given sources and spans all the nodes which are reachable from the
+ /// sources. The time complexity of the algorithm is O(n<sup>2</sup>+m).
+ ///
+ /// The algorithm also provides an optimal dual solution, therefore
+ /// the optimality of the solution can be checked.
+ ///
+ /// \param GR The digraph type the algorithm runs on.
+ /// \param CM A read-only arc map storing the costs of the
+ /// arcs. It is read once for each arc, so the map may involve in
+ /// relatively time consuming process to compute the arc costs if
+ /// it is necessary. The default map type is \ref
+ /// concepts::Digraph::ArcMap "Digraph::ArcMap<int>".
+ /// \tparam TR The traits class that defines various types used by the
+ /// algorithm. By default, it is \ref MinCostArborescenceDefaultTraits
+ /// "MinCostArborescenceDefaultTraits<GR, CM>".
+ /// In most cases, this parameter should not be set directly,
+ /// consider to use the named template parameters instead.
+#ifndef DOXYGEN
+ template <typename GR,
+ typename CM = typename GR::template ArcMap<int>,
+ typename TR =
+ MinCostArborescenceDefaultTraits<GR, CM> >
+#else
+ template <typename GR, typename CM, typename TR>
+#endif
+ class MinCostArborescence {
+ public:
+
+ /// \brief The \ref lemon::MinCostArborescenceDefaultTraits "traits class"
+ /// of the algorithm.
+ typedef TR Traits;
+ /// The type of the underlying digraph.
+ typedef typename Traits::Digraph Digraph;
+ /// The type of the map that stores the arc costs.
+ typedef typename Traits::CostMap CostMap;
+ ///The type of the costs of the arcs.
+ typedef typename Traits::Value Value;
+ ///The type of the predecessor map.
+ typedef typename Traits::PredMap PredMap;
+ ///The type of the map that stores which arcs are in the arborescence.
+ typedef typename Traits::ArborescenceMap ArborescenceMap;
+
+ typedef MinCostArborescence Create;
+
+ private:
+
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+
+ struct CostArc {
+
+ Arc arc;
+ Value value;
+
+ CostArc() {}
+ CostArc(Arc _arc, Value _value) : arc(_arc), value(_value) {}
+
+ };
+
+ const Digraph *_digraph;
+ const CostMap *_cost;
+
+ PredMap *_pred;
+ bool local_pred;
+
+ ArborescenceMap *_arborescence;
+ bool local_arborescence;
+
+ typedef typename Digraph::template ArcMap<int> ArcOrder;
+ ArcOrder *_arc_order;
+
+ typedef typename Digraph::template NodeMap<int> NodeOrder;
+ NodeOrder *_node_order;
+
+ typedef typename Digraph::template NodeMap<CostArc> CostArcMap;
+ CostArcMap *_cost_arcs;
+
+ struct StackLevel {
+
+ std::vector<CostArc> arcs;
+ int node_level;
+
+ };
+
+ std::vector<StackLevel> level_stack;
+ std::vector<Node> queue;
+
+ typedef std::vector<typename Digraph::Node> DualNodeList;
+
+ DualNodeList _dual_node_list;
+
+ struct DualVariable {
+ int begin, end;
+ Value value;
+
+ DualVariable(int _begin, int _end, Value _value)
+ : begin(_begin), end(_end), value(_value) {}
+
+ };
+
+ typedef std::vector<DualVariable> DualVariables;
+
+ DualVariables _dual_variables;
+
+ typedef typename Digraph::template NodeMap<int> HeapCrossRef;
+
+ HeapCrossRef *_heap_cross_ref;
+
+ typedef BinHeap<int, HeapCrossRef> Heap;
+
+ Heap *_heap;
+
+ protected:
+
+ MinCostArborescence() {}
+
+ private:
+
+ void createStructures() {
+ if (!_pred) {
+ local_pred = true;
+ _pred = Traits::createPredMap(*_digraph);
+ }
+ if (!_arborescence) {
+ local_arborescence = true;
+ _arborescence = Traits::createArborescenceMap(*_digraph);
+ }
+ if (!_arc_order) {
+ _arc_order = new ArcOrder(*_digraph);
+ }
+ if (!_node_order) {
+ _node_order = new NodeOrder(*_digraph);
+ }
+ if (!_cost_arcs) {
+ _cost_arcs = new CostArcMap(*_digraph);
+ }
+ if (!_heap_cross_ref) {
+ _heap_cross_ref = new HeapCrossRef(*_digraph, -1);
+ }
+ if (!_heap) {
+ _heap = new Heap(*_heap_cross_ref);
+ }
+ }
+
+ void destroyStructures() {
+ if (local_arborescence) {
+ delete _arborescence;
+ }
+ if (local_pred) {
+ delete _pred;
+ }
+ if (_arc_order) {
+ delete _arc_order;
+ }
+ if (_node_order) {
+ delete _node_order;
+ }
+ if (_cost_arcs) {
+ delete _cost_arcs;
+ }
+ if (_heap) {
+ delete _heap;
+ }
+ if (_heap_cross_ref) {
+ delete _heap_cross_ref;
+ }
+ }
+
+ Arc prepare(Node node) {
+ std::vector<Node> nodes;
+ (*_node_order)[node] = _dual_node_list.size();
+ StackLevel level;
+ level.node_level = _dual_node_list.size();
+ _dual_node_list.push_back(node);
+ for (InArcIt it(*_digraph, node); it != INVALID; ++it) {
+ Arc arc = it;
+ Node source = _digraph->source(arc);
+ Value value = (*_cost)[it];
+ if (source == node || (*_node_order)[source] == -3) continue;
+ if ((*_cost_arcs)[source].arc == INVALID) {
+ (*_cost_arcs)[source].arc = arc;
+ (*_cost_arcs)[source].value = value;
+ nodes.push_back(source);
+ } else {
+ if ((*_cost_arcs)[source].value > value) {
+ (*_cost_arcs)[source].arc = arc;
+ (*_cost_arcs)[source].value = value;
+ }
+ }
+ }
+ CostArc minimum = (*_cost_arcs)[nodes[0]];
+ for (int i = 1; i < int(nodes.size()); ++i) {
+ if ((*_cost_arcs)[nodes[i]].value < minimum.value) {
+ minimum = (*_cost_arcs)[nodes[i]];
+ }
+ }
+ (*_arc_order)[minimum.arc] = _dual_variables.size();
+ DualVariable var(_dual_node_list.size() - 1,
+ _dual_node_list.size(), minimum.value);
+ _dual_variables.push_back(var);
+ for (int i = 0; i < int(nodes.size()); ++i) {
+ (*_cost_arcs)[nodes[i]].value -= minimum.value;
+ level.arcs.push_back((*_cost_arcs)[nodes[i]]);
+ (*_cost_arcs)[nodes[i]].arc = INVALID;
+ }
+ level_stack.push_back(level);
+ return minimum.arc;
+ }
+
+ Arc contract(Node node) {
+ int node_bottom = bottom(node);
+ std::vector<Node> nodes;
+ while (!level_stack.empty() &&
+ level_stack.back().node_level >= node_bottom) {
+ for (int i = 0; i < int(level_stack.back().arcs.size()); ++i) {
+ Arc arc = level_stack.back().arcs[i].arc;
+ Node source = _digraph->source(arc);
+ Value value = level_stack.back().arcs[i].value;
+ if ((*_node_order)[source] >= node_bottom) continue;
+ if ((*_cost_arcs)[source].arc == INVALID) {
+ (*_cost_arcs)[source].arc = arc;
+ (*_cost_arcs)[source].value = value;
+ nodes.push_back(source);
+ } else {
+ if ((*_cost_arcs)[source].value > value) {
+ (*_cost_arcs)[source].arc = arc;
+ (*_cost_arcs)[source].value = value;
+ }
+ }
+ }
+ level_stack.pop_back();
+ }
+ CostArc minimum = (*_cost_arcs)[nodes[0]];
+ for (int i = 1; i < int(nodes.size()); ++i) {
+ if ((*_cost_arcs)[nodes[i]].value < minimum.value) {
+ minimum = (*_cost_arcs)[nodes[i]];
+ }
+ }
+ (*_arc_order)[minimum.arc] = _dual_variables.size();
+ DualVariable var(node_bottom, _dual_node_list.size(), minimum.value);
+ _dual_variables.push_back(var);
+ StackLevel level;
+ level.node_level = node_bottom;
+ for (int i = 0; i < int(nodes.size()); ++i) {
+ (*_cost_arcs)[nodes[i]].value -= minimum.value;
+ level.arcs.push_back((*_cost_arcs)[nodes[i]]);
+ (*_cost_arcs)[nodes[i]].arc = INVALID;
+ }
+ level_stack.push_back(level);
+ return minimum.arc;
+ }
+
+ int bottom(Node node) {
+ int k = level_stack.size() - 1;
+ while (level_stack[k].node_level > (*_node_order)[node]) {
+ --k;
+ }
+ return level_stack[k].node_level;
+ }
+
+ void finalize(Arc arc) {
+ Node node = _digraph->target(arc);
+ _heap->push(node, (*_arc_order)[arc]);
+ _pred->set(node, arc);
+ while (!_heap->empty()) {
+ Node source = _heap->top();
+ _heap->pop();
+ (*_node_order)[source] = -1;
+ for (OutArcIt it(*_digraph, source); it != INVALID; ++it) {
+ if ((*_arc_order)[it] < 0) continue;
+ Node target = _digraph->target(it);
+ switch(_heap->state(target)) {
+ case Heap::PRE_HEAP:
+ _heap->push(target, (*_arc_order)[it]);
+ _pred->set(target, it);
+ break;
+ case Heap::IN_HEAP:
+ if ((*_arc_order)[it] < (*_heap)[target]) {
+ _heap->decrease(target, (*_arc_order)[it]);
+ _pred->set(target, it);
+ }
+ break;
+ case Heap::POST_HEAP:
+ break;
+ }
+ }
+ _arborescence->set((*_pred)[source], true);
+ }
+ }
+
+
+ public:
+
+ /// \name Named Template Parameters
+
+ /// @{
+
+ template <class T>
+ struct SetArborescenceMapTraits : public Traits {
+ typedef T ArborescenceMap;
+ static ArborescenceMap *createArborescenceMap(const Digraph &)
+ {
+ LEMON_ASSERT(false, "ArborescenceMap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for
+ /// setting \c ArborescenceMap type
+ ///
+ /// \ref named-templ-param "Named parameter" for setting
+ /// \c ArborescenceMap type.
+ /// It must conform to the \ref concepts::WriteMap "WriteMap" concept,
+ /// and its value type must be \c bool (or convertible).
+ /// Initially it will be set to \c false on each arc,
+ /// then it will be set on each arborescence arc once.
+ template <class T>
+ struct SetArborescenceMap
+ : public MinCostArborescence<Digraph, CostMap,
+ SetArborescenceMapTraits<T> > {
+ };
+
+ template <class T>
+ struct SetPredMapTraits : public Traits {
+ typedef T PredMap;
+ static PredMap *createPredMap(const Digraph &)
+ {
+ LEMON_ASSERT(false, "PredMap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for
+ /// setting \c PredMap type
+ ///
+ /// \ref named-templ-param "Named parameter" for setting
+ /// \c PredMap type.
+ /// It must meet the \ref concepts::WriteMap "WriteMap" concept,
+ /// and its value type must be the \c Arc type of the digraph.
+ template <class T>
+ struct SetPredMap
+ : public MinCostArborescence<Digraph, CostMap, SetPredMapTraits<T> > {
+ };
+
+ /// @}
+
+ /// \brief Constructor.
+ ///
+ /// \param digraph The digraph the algorithm will run on.
+ /// \param cost The cost map used by the algorithm.
+ MinCostArborescence(const Digraph& digraph, const CostMap& cost)
+ : _digraph(&digraph), _cost(&cost), _pred(0), local_pred(false),
+ _arborescence(0), local_arborescence(false),
+ _arc_order(0), _node_order(0), _cost_arcs(0),
+ _heap_cross_ref(0), _heap(0) {}
+
+ /// \brief Destructor.
+ ~MinCostArborescence() {
+ destroyStructures();
+ }
+
+ /// \brief Sets the arborescence map.
+ ///
+ /// Sets the arborescence map.
+ /// \return <tt>(*this)</tt>
+ MinCostArborescence& arborescenceMap(ArborescenceMap& m) {
+ if (local_arborescence) {
+ delete _arborescence;
+ }
+ local_arborescence = false;
+ _arborescence = &m;
+ return *this;
+ }
+
+ /// \brief Sets the predecessor map.
+ ///
+ /// Sets the predecessor map.
+ /// \return <tt>(*this)</tt>
+ MinCostArborescence& predMap(PredMap& m) {
+ if (local_pred) {
+ delete _pred;
+ }
+ local_pred = false;
+ _pred = &m;
+ return *this;
+ }
+
+ /// \name Execution Control
+ /// The simplest way to execute the algorithm is to use
+ /// one of the member functions called \c run(...). \n
+ /// If you need better control on the execution,
+ /// you have to call \ref init() first, then you can add several
+ /// source nodes with \ref addSource().
+ /// Finally \ref start() will perform the arborescence
+ /// computation.
+
+ ///@{
+
+ /// \brief Initializes the internal data structures.
+ ///
+ /// Initializes the internal data structures.
+ ///
+ void init() {
+ createStructures();
+ _heap->clear();
+ for (NodeIt it(*_digraph); it != INVALID; ++it) {
+ (*_cost_arcs)[it].arc = INVALID;
+ (*_node_order)[it] = -3;
+ (*_heap_cross_ref)[it] = Heap::PRE_HEAP;
+ _pred->set(it, INVALID);
+ }
+ for (ArcIt it(*_digraph); it != INVALID; ++it) {
+ _arborescence->set(it, false);
+ (*_arc_order)[it] = -1;
+ }
+ _dual_node_list.clear();
+ _dual_variables.clear();
+ }
+
+ /// \brief Adds a new source node.
+ ///
+ /// Adds a new source node to the algorithm.
+ void addSource(Node source) {
+ std::vector<Node> nodes;
+ nodes.push_back(source);
+ while (!nodes.empty()) {
+ Node node = nodes.back();
+ nodes.pop_back();
+ for (OutArcIt it(*_digraph, node); it != INVALID; ++it) {
+ Node target = _digraph->target(it);
+ if ((*_node_order)[target] == -3) {
+ (*_node_order)[target] = -2;
+ nodes.push_back(target);
+ queue.push_back(target);
+ }
+ }
+ }
+ (*_node_order)[source] = -1;
+ }
+
+ /// \brief Processes the next node in the priority queue.
+ ///
+ /// Processes the next node in the priority queue.
+ ///
+ /// \return The processed node.
+ ///
+ /// \warning The queue must not be empty.
+ Node processNextNode() {
+ Node node = queue.back();
+ queue.pop_back();
+ if ((*_node_order)[node] == -2) {
+ Arc arc = prepare(node);
+ Node source = _digraph->source(arc);
+ while ((*_node_order)[source] != -1) {
+ if ((*_node_order)[source] >= 0) {
+ arc = contract(source);
+ } else {
+ arc = prepare(source);
+ }
+ source = _digraph->source(arc);
+ }
+ finalize(arc);
+ level_stack.clear();
+ }
+ return node;
+ }
+
+ /// \brief Returns the number of the nodes to be processed.
+ ///
+ /// Returns the number of the nodes to be processed in the priority
+ /// queue.
+ int queueSize() const {
+ return queue.size();
+ }
+
+ /// \brief Returns \c false if there are nodes to be processed.
+ ///
+ /// Returns \c false if there are nodes to be processed.
+ bool emptyQueue() const {
+ return queue.empty();
+ }
+
+ /// \brief Executes the algorithm.
+ ///
+ /// Executes the algorithm.
+ ///
+ /// \pre init() must be called and at least one node should be added
+ /// with addSource() before using this function.
+ ///
+ ///\note mca.start() is just a shortcut of the following code.
+ ///\code
+ ///while (!mca.emptyQueue()) {
+ /// mca.processNextNode();
+ ///}
+ ///\endcode
+ void start() {
+ while (!emptyQueue()) {
+ processNextNode();
+ }
+ }
+
+ /// \brief Runs %MinCostArborescence algorithm from node \c s.
+ ///
+ /// This method runs the %MinCostArborescence algorithm from
+ /// a root node \c s.
+ ///
+ /// \note mca.run(s) is just a shortcut of the following code.
+ /// \code
+ /// mca.init();
+ /// mca.addSource(s);
+ /// mca.start();
+ /// \endcode
+ void run(Node s) {
+ init();
+ addSource(s);
+ start();
+ }
+
+ ///@}
+
+ /// \name Query Functions
+ /// The result of the %MinCostArborescence algorithm can be obtained
+ /// using these functions.\n
+ /// Either run() or start() must be called before using them.
+
+ /// @{
+
+ /// \brief Returns the cost of the arborescence.
+ ///
+ /// Returns the cost of the arborescence.
+ Value arborescenceCost() const {
+ Value sum = 0;
+ for (ArcIt it(*_digraph); it != INVALID; ++it) {
+ if (arborescence(it)) {
+ sum += (*_cost)[it];
+ }
+ }
+ return sum;
+ }
+
+ /// \brief Returns \c true if the arc is in the arborescence.
+ ///
+ /// Returns \c true if the given arc is in the arborescence.
+ /// \param arc An arc of the digraph.
+ /// \pre \ref run() must be called before using this function.
+ bool arborescence(Arc arc) const {
+ return (*_pred)[_digraph->target(arc)] == arc;
+ }
+
+ /// \brief Returns a const reference to the arborescence map.
+ ///
+ /// Returns a const reference to the arborescence map.
+ /// \pre \ref run() must be called before using this function.
+ const ArborescenceMap& arborescenceMap() const {
+ return *_arborescence;
+ }
+
+ /// \brief Returns the predecessor arc of the given node.
+ ///
+ /// Returns the predecessor arc of the given node.
+ /// \pre \ref run() must be called before using this function.
+ Arc pred(Node node) const {
+ return (*_pred)[node];
+ }
+
+ /// \brief Returns a const reference to the pred map.
+ ///
+ /// Returns a const reference to the pred map.
+ /// \pre \ref run() must be called before using this function.
+ const PredMap& predMap() const {
+ return *_pred;
+ }
+
+ /// \brief Indicates that a node is reachable from the sources.
+ ///
+ /// Indicates that a node is reachable from the sources.
+ bool reached(Node node) const {
+ return (*_node_order)[node] != -3;
+ }
+
+ /// \brief Indicates that a node is processed.
+ ///
+ /// Indicates that a node is processed. The arborescence path exists
+ /// from the source to the given node.
+ bool processed(Node node) const {
+ return (*_node_order)[node] == -1;
+ }
+
+ /// \brief Returns the number of the dual variables in basis.
+ ///
+ /// Returns the number of the dual variables in basis.
+ int dualNum() const {
+ return _dual_variables.size();
+ }
+
+ /// \brief Returns the value of the dual solution.
+ ///
+ /// Returns the value of the dual solution. It should be
+ /// equal to the arborescence value.
+ Value dualValue() const {
+ Value sum = 0;
+ for (int i = 0; i < int(_dual_variables.size()); ++i) {
+ sum += _dual_variables[i].value;
+ }
+ return sum;
+ }
+
+ /// \brief Returns the number of the nodes in the dual variable.
+ ///
+ /// Returns the number of the nodes in the dual variable.
+ int dualSize(int k) const {
+ return _dual_variables[k].end - _dual_variables[k].begin;
+ }
+
+ /// \brief Returns the value of the dual variable.
+ ///
+ /// Returns the the value of the dual variable.
+ Value dualValue(int k) const {
+ return _dual_variables[k].value;
+ }
+
+ /// \brief LEMON iterator for getting a dual variable.
+ ///
+ /// This class provides a common style LEMON iterator for getting a
+ /// dual variable of \ref MinCostArborescence algorithm.
+ /// It iterates over a subset of the nodes.
+ class DualIt {
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// Constructor for getting the nodeset of the dual variable
+ /// of \ref MinCostArborescence algorithm.
+ DualIt(const MinCostArborescence& algorithm, int variable)
+ : _algorithm(&algorithm)
+ {
+ _index = _algorithm->_dual_variables[variable].begin;
+ _last = _algorithm->_dual_variables[variable].end;
+ }
+
+ /// \brief Conversion to \c Node.
+ ///
+ /// Conversion to \c Node.
+ operator Node() const {
+ return _algorithm->_dual_node_list[_index];
+ }
+
+ /// \brief Increment operator.
+ ///
+ /// Increment operator.
+ DualIt& operator++() {
+ ++_index;
+ return *this;
+ }
+
+ /// \brief Validity checking
+ ///
+ /// Checks whether the iterator is invalid.
+ bool operator==(Invalid) const {
+ return _index == _last;
+ }
+
+ /// \brief Validity checking
+ ///
+ /// Checks whether the iterator is valid.
+ bool operator!=(Invalid) const {
+ return _index != _last;
+ }
+
+ private:
+ const MinCostArborescence* _algorithm;
+ int _index, _last;
+ };
+
+ /// @}
+
+ };
+
+ /// \ingroup spantree
+ ///
+ /// \brief Function type interface for MinCostArborescence algorithm.
+ ///
+ /// Function type interface for MinCostArborescence algorithm.
+ /// \param digraph The digraph the algorithm runs on.
+ /// \param cost An arc map storing the costs.
+ /// \param source The source node of the arborescence.
+ /// \retval arborescence An arc map with \c bool (or convertible) value
+ /// type that stores the arborescence.
+ /// \return The total cost of the arborescence.
+ ///
+ /// \sa MinCostArborescence
+ template <typename Digraph, typename CostMap, typename ArborescenceMap>
+ typename CostMap::Value minCostArborescence(const Digraph& digraph,
+ const CostMap& cost,
+ typename Digraph::Node source,
+ ArborescenceMap& arborescence) {
+ typename MinCostArborescence<Digraph, CostMap>
+ ::template SetArborescenceMap<ArborescenceMap>
+ ::Create mca(digraph, cost);
+ mca.arborescenceMap(arborescence);
+ mca.run(source);
+ return mca.arborescenceCost();
+ }
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/nagamochi_ibaraki.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/nagamochi_ibaraki.h
new file mode 100644
index 00000000000..57a6ba64d2b
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/nagamochi_ibaraki.h
@@ -0,0 +1,702 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_NAGAMOCHI_IBARAKI_H
+#define LEMON_NAGAMOCHI_IBARAKI_H
+
+
+/// \ingroup min_cut
+/// \file
+/// \brief Implementation of the Nagamochi-Ibaraki algorithm.
+
+#include <lemon/core.h>
+#include <lemon/bin_heap.h>
+#include <lemon/bucket_heap.h>
+#include <lemon/maps.h>
+#include <lemon/radix_sort.h>
+#include <lemon/unionfind.h>
+
+#include <cassert>
+
+namespace lemon {
+
+ /// \brief Default traits class for NagamochiIbaraki class.
+ ///
+ /// Default traits class for NagamochiIbaraki class.
+ /// \param GR The undirected graph type.
+ /// \param CM Type of capacity map.
+ template <typename GR, typename CM>
+ struct NagamochiIbarakiDefaultTraits {
+ /// The type of the capacity map.
+ typedef typename CM::Value Value;
+
+ /// The undirected graph type the algorithm runs on.
+ typedef GR Graph;
+
+ /// \brief The type of the map that stores the edge capacities.
+ ///
+ /// The type of the map that stores the edge capacities.
+ /// It must meet the \ref concepts::ReadMap "ReadMap" concept.
+ typedef CM CapacityMap;
+
+ /// \brief Instantiates a CapacityMap.
+ ///
+ /// This function instantiates a \ref CapacityMap.
+#ifdef DOXYGEN
+ static CapacityMap *createCapacityMap(const Graph& graph)
+#else
+ static CapacityMap *createCapacityMap(const Graph&)
+#endif
+ {
+ LEMON_ASSERT(false, "CapacityMap is not initialized");
+ return 0; // ignore warnings
+ }
+
+ /// \brief The cross reference type used by heap.
+ ///
+ /// The cross reference type used by heap.
+ /// Usually \c Graph::NodeMap<int>.
+ typedef typename Graph::template NodeMap<int> HeapCrossRef;
+
+ /// \brief Instantiates a HeapCrossRef.
+ ///
+ /// This function instantiates a \ref HeapCrossRef.
+ /// \param g is the graph, to which we would like to define the
+ /// \ref HeapCrossRef.
+ static HeapCrossRef *createHeapCrossRef(const Graph& g) {
+ return new HeapCrossRef(g);
+ }
+
+ /// \brief The heap type used by NagamochiIbaraki algorithm.
+ ///
+ /// The heap type used by NagamochiIbaraki algorithm. It has to
+ /// maximize the priorities.
+ ///
+ /// \sa BinHeap
+ /// \sa NagamochiIbaraki
+ typedef BinHeap<Value, HeapCrossRef, std::greater<Value> > Heap;
+
+ /// \brief Instantiates a Heap.
+ ///
+ /// This function instantiates a \ref Heap.
+ /// \param r is the cross reference of the heap.
+ static Heap *createHeap(HeapCrossRef& r) {
+ return new Heap(r);
+ }
+ };
+
+ /// \ingroup min_cut
+ ///
+ /// \brief Calculates the minimum cut in an undirected graph.
+ ///
+ /// Calculates the minimum cut in an undirected graph with the
+ /// Nagamochi-Ibaraki algorithm. The algorithm separates the graph's
+ /// nodes into two partitions with the minimum sum of edge capacities
+ /// between the two partitions. The algorithm can be used to test
+ /// the network reliability, especially to test how many links have
+ /// to be destroyed in the network to split it to at least two
+ /// distinict subnetworks.
+ ///
+ /// The complexity of the algorithm is \f$ O(nm\log(n)) \f$ but with
+ /// \ref FibHeap "Fibonacci heap" it can be decreased to
+ /// \f$ O(nm+n^2\log(n)) \f$. When the edges have unit capacities,
+ /// \c BucketHeap can be used which yields \f$ O(nm) \f$ time
+ /// complexity.
+ ///
+ /// \warning The value type of the capacity map should be able to
+ /// hold any cut value of the graph, otherwise the result can
+ /// overflow.
+ /// \note This capacity is supposed to be integer type.
+#ifdef DOXYGEN
+ template <typename GR, typename CM, typename TR>
+#else
+ template <typename GR,
+ typename CM = typename GR::template EdgeMap<int>,
+ typename TR = NagamochiIbarakiDefaultTraits<GR, CM> >
+#endif
+ class NagamochiIbaraki {
+ public:
+
+ typedef TR Traits;
+ /// The type of the underlying graph.
+ typedef typename Traits::Graph Graph;
+
+ /// The type of the capacity map.
+ typedef typename Traits::CapacityMap CapacityMap;
+ /// The value type of the capacity map.
+ typedef typename Traits::CapacityMap::Value Value;
+
+ /// The heap type used by the algorithm.
+ typedef typename Traits::Heap Heap;
+ /// The cross reference type used for the heap.
+ typedef typename Traits::HeapCrossRef HeapCrossRef;
+
+ ///\name Named template parameters
+
+ ///@{
+
+ struct SetUnitCapacityTraits : public Traits {
+ typedef ConstMap<typename Graph::Edge, Const<int, 1> > CapacityMap;
+ static CapacityMap *createCapacityMap(const Graph&) {
+ return new CapacityMap();
+ }
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// the capacity map to a constMap<Edge, int, 1>() instance
+ ///
+ /// \ref named-templ-param "Named parameter" for setting
+ /// the capacity map to a constMap<Edge, int, 1>() instance
+ struct SetUnitCapacity
+ : public NagamochiIbaraki<Graph, CapacityMap,
+ SetUnitCapacityTraits> {
+ typedef NagamochiIbaraki<Graph, CapacityMap,
+ SetUnitCapacityTraits> Create;
+ };
+
+
+ template <class H, class CR>
+ struct SetHeapTraits : public Traits {
+ typedef CR HeapCrossRef;
+ typedef H Heap;
+ static HeapCrossRef *createHeapCrossRef(int num) {
+ LEMON_ASSERT(false, "HeapCrossRef is not initialized");
+ return 0; // ignore warnings
+ }
+ static Heap *createHeap(HeapCrossRef &) {
+ LEMON_ASSERT(false, "Heap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// heap and cross reference type
+ ///
+ /// \ref named-templ-param "Named parameter" for setting heap and
+ /// cross reference type. The heap has to maximize the priorities.
+ template <class H, class CR = RangeMap<int> >
+ struct SetHeap
+ : public NagamochiIbaraki<Graph, CapacityMap, SetHeapTraits<H, CR> > {
+ typedef NagamochiIbaraki< Graph, CapacityMap, SetHeapTraits<H, CR> >
+ Create;
+ };
+
+ template <class H, class CR>
+ struct SetStandardHeapTraits : public Traits {
+ typedef CR HeapCrossRef;
+ typedef H Heap;
+ static HeapCrossRef *createHeapCrossRef(int size) {
+ return new HeapCrossRef(size);
+ }
+ static Heap *createHeap(HeapCrossRef &crossref) {
+ return new Heap(crossref);
+ }
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// heap and cross reference type with automatic allocation
+ ///
+ /// \ref named-templ-param "Named parameter" for setting heap and
+ /// cross reference type with automatic allocation. They should
+ /// have standard constructor interfaces to be able to
+ /// automatically created by the algorithm (i.e. the graph should
+ /// be passed to the constructor of the cross reference and the
+ /// cross reference should be passed to the constructor of the
+ /// heap). However, external heap and cross reference objects
+ /// could also be passed to the algorithm using the \ref heap()
+ /// function before calling \ref run() or \ref init(). The heap
+ /// has to maximize the priorities.
+ /// \sa SetHeap
+ template <class H, class CR = RangeMap<int> >
+ struct SetStandardHeap
+ : public NagamochiIbaraki<Graph, CapacityMap,
+ SetStandardHeapTraits<H, CR> > {
+ typedef NagamochiIbaraki<Graph, CapacityMap,
+ SetStandardHeapTraits<H, CR> > Create;
+ };
+
+ ///@}
+
+
+ private:
+
+ const Graph &_graph;
+ const CapacityMap *_capacity;
+ bool _local_capacity; // unit capacity
+
+ struct ArcData {
+ typename Graph::Node target;
+ int prev, next;
+ };
+ struct EdgeData {
+ Value capacity;
+ Value cut;
+ };
+
+ struct NodeData {
+ int first_arc;
+ typename Graph::Node prev, next;
+ int curr_arc;
+ typename Graph::Node last_rep;
+ Value sum;
+ };
+
+ typename Graph::template NodeMap<NodeData> *_nodes;
+ std::vector<ArcData> _arcs;
+ std::vector<EdgeData> _edges;
+
+ typename Graph::Node _first_node;
+ int _node_num;
+
+ Value _min_cut;
+
+ HeapCrossRef *_heap_cross_ref;
+ bool _local_heap_cross_ref;
+ Heap *_heap;
+ bool _local_heap;
+
+ typedef typename Graph::template NodeMap<typename Graph::Node> NodeList;
+ NodeList *_next_rep;
+
+ typedef typename Graph::template NodeMap<bool> MinCutMap;
+ MinCutMap *_cut_map;
+
+ void createStructures() {
+ if (!_nodes) {
+ _nodes = new (typename Graph::template NodeMap<NodeData>)(_graph);
+ }
+ if (!_capacity) {
+ _local_capacity = true;
+ _capacity = Traits::createCapacityMap(_graph);
+ }
+ if (!_heap_cross_ref) {
+ _local_heap_cross_ref = true;
+ _heap_cross_ref = Traits::createHeapCrossRef(_graph);
+ }
+ if (!_heap) {
+ _local_heap = true;
+ _heap = Traits::createHeap(*_heap_cross_ref);
+ }
+ if (!_next_rep) {
+ _next_rep = new NodeList(_graph);
+ }
+ if (!_cut_map) {
+ _cut_map = new MinCutMap(_graph);
+ }
+ }
+
+ protected:
+ //This is here to avoid a gcc-3.3 compilation error.
+ //It should never be called.
+ NagamochiIbaraki() {}
+
+ public:
+
+ typedef NagamochiIbaraki Create;
+
+
+ /// \brief Constructor.
+ ///
+ /// \param graph The graph the algorithm runs on.
+ /// \param capacity The capacity map used by the algorithm.
+ NagamochiIbaraki(const Graph& graph, const CapacityMap& capacity)
+ : _graph(graph), _capacity(&capacity), _local_capacity(false),
+ _nodes(0), _arcs(), _edges(), _min_cut(),
+ _heap_cross_ref(0), _local_heap_cross_ref(false),
+ _heap(0), _local_heap(false),
+ _next_rep(0), _cut_map(0) {}
+
+ /// \brief Constructor.
+ ///
+ /// This constructor can be used only when the Traits class
+ /// defines how can the local capacity map be instantiated.
+ /// If the SetUnitCapacity used the algorithm automatically
+ /// constructs the capacity map.
+ ///
+ ///\param graph The graph the algorithm runs on.
+ NagamochiIbaraki(const Graph& graph)
+ : _graph(graph), _capacity(0), _local_capacity(false),
+ _nodes(0), _arcs(), _edges(), _min_cut(),
+ _heap_cross_ref(0), _local_heap_cross_ref(false),
+ _heap(0), _local_heap(false),
+ _next_rep(0), _cut_map(0) {}
+
+ /// \brief Destructor.
+ ///
+ /// Destructor.
+ ~NagamochiIbaraki() {
+ if (_local_capacity) delete _capacity;
+ if (_nodes) delete _nodes;
+ if (_local_heap) delete _heap;
+ if (_local_heap_cross_ref) delete _heap_cross_ref;
+ if (_next_rep) delete _next_rep;
+ if (_cut_map) delete _cut_map;
+ }
+
+ /// \brief Sets the heap and the cross reference used by algorithm.
+ ///
+ /// Sets the heap and the cross reference used by algorithm.
+ /// If you don't use this function before calling \ref run(),
+ /// it will allocate one. The destuctor deallocates this
+ /// automatically allocated heap and cross reference, of course.
+ /// \return <tt> (*this) </tt>
+ NagamochiIbaraki &heap(Heap& hp, HeapCrossRef &cr)
+ {
+ if (_local_heap_cross_ref) {
+ delete _heap_cross_ref;
+ _local_heap_cross_ref = false;
+ }
+ _heap_cross_ref = &cr;
+ if (_local_heap) {
+ delete _heap;
+ _local_heap = false;
+ }
+ _heap = &hp;
+ return *this;
+ }
+
+ /// \name Execution control
+ /// The simplest way to execute the algorithm is to use
+ /// one of the member functions called \c run().
+ /// \n
+ /// If you need more control on the execution,
+ /// first you must call \ref init() and then call the start()
+ /// or proper times the processNextPhase() member functions.
+
+ ///@{
+
+ /// \brief Initializes the internal data structures.
+ ///
+ /// Initializes the internal data structures.
+ void init() {
+ createStructures();
+
+ int edge_num = countEdges(_graph);
+ _edges.resize(edge_num);
+ _arcs.resize(2 * edge_num);
+
+ typename Graph::Node prev = INVALID;
+ _node_num = 0;
+ for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) {
+ (*_cut_map)[n] = false;
+ (*_next_rep)[n] = INVALID;
+ (*_nodes)[n].last_rep = n;
+ (*_nodes)[n].first_arc = -1;
+ (*_nodes)[n].curr_arc = -1;
+ (*_nodes)[n].prev = prev;
+ if (prev != INVALID) {
+ (*_nodes)[prev].next = n;
+ }
+ (*_nodes)[n].next = INVALID;
+ (*_nodes)[n].sum = 0;
+ prev = n;
+ ++_node_num;
+ }
+
+ _first_node = typename Graph::NodeIt(_graph);
+
+ int index = 0;
+ for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) {
+ for (typename Graph::OutArcIt a(_graph, n); a != INVALID; ++a) {
+ typename Graph::Node m = _graph.target(a);
+
+ if (!(n < m)) continue;
+
+ (*_nodes)[n].sum += (*_capacity)[a];
+ (*_nodes)[m].sum += (*_capacity)[a];
+
+ int c = (*_nodes)[m].curr_arc;
+ if (c != -1 && _arcs[c ^ 1].target == n) {
+ _edges[c >> 1].capacity += (*_capacity)[a];
+ } else {
+ _edges[index].capacity = (*_capacity)[a];
+
+ _arcs[index << 1].prev = -1;
+ if ((*_nodes)[n].first_arc != -1) {
+ _arcs[(*_nodes)[n].first_arc].prev = (index << 1);
+ }
+ _arcs[index << 1].next = (*_nodes)[n].first_arc;
+ (*_nodes)[n].first_arc = (index << 1);
+ _arcs[index << 1].target = m;
+
+ (*_nodes)[m].curr_arc = (index << 1);
+
+ _arcs[(index << 1) | 1].prev = -1;
+ if ((*_nodes)[m].first_arc != -1) {
+ _arcs[(*_nodes)[m].first_arc].prev = ((index << 1) | 1);
+ }
+ _arcs[(index << 1) | 1].next = (*_nodes)[m].first_arc;
+ (*_nodes)[m].first_arc = ((index << 1) | 1);
+ _arcs[(index << 1) | 1].target = n;
+
+ ++index;
+ }
+ }
+ }
+
+ typename Graph::Node cut_node = INVALID;
+ _min_cut = std::numeric_limits<Value>::max();
+
+ for (typename Graph::Node n = _first_node;
+ n != INVALID; n = (*_nodes)[n].next) {
+ if ((*_nodes)[n].sum < _min_cut) {
+ cut_node = n;
+ _min_cut = (*_nodes)[n].sum;
+ }
+ }
+ (*_cut_map)[cut_node] = true;
+ if (_min_cut == 0) {
+ _first_node = INVALID;
+ }
+ }
+
+ public:
+
+ /// \brief Processes the next phase
+ ///
+ /// Processes the next phase in the algorithm. It must be called
+ /// at most one less the number of the nodes in the graph.
+ ///
+ ///\return %True when the algorithm finished.
+ bool processNextPhase() {
+ if (_first_node == INVALID) return true;
+
+ _heap->clear();
+ for (typename Graph::Node n = _first_node;
+ n != INVALID; n = (*_nodes)[n].next) {
+ (*_heap_cross_ref)[n] = Heap::PRE_HEAP;
+ }
+
+ std::vector<typename Graph::Node> order;
+ order.reserve(_node_num);
+ int sep = 0;
+
+ Value alpha = 0;
+ Value pmc = std::numeric_limits<Value>::max();
+
+ _heap->push(_first_node, static_cast<Value>(0));
+ while (!_heap->empty()) {
+ typename Graph::Node n = _heap->top();
+ Value v = _heap->prio();
+
+ _heap->pop();
+ for (int a = (*_nodes)[n].first_arc; a != -1; a = _arcs[a].next) {
+ switch (_heap->state(_arcs[a].target)) {
+ case Heap::PRE_HEAP:
+ {
+ Value nv = _edges[a >> 1].capacity;
+ _heap->push(_arcs[a].target, nv);
+ _edges[a >> 1].cut = nv;
+ } break;
+ case Heap::IN_HEAP:
+ {
+ Value nv = _edges[a >> 1].capacity + (*_heap)[_arcs[a].target];
+ _heap->decrease(_arcs[a].target, nv);
+ _edges[a >> 1].cut = nv;
+ } break;
+ case Heap::POST_HEAP:
+ break;
+ }
+ }
+
+ alpha += (*_nodes)[n].sum;
+ alpha -= 2 * v;
+
+ order.push_back(n);
+ if (!_heap->empty()) {
+ if (alpha < pmc) {
+ pmc = alpha;
+ sep = order.size();
+ }
+ }
+ }
+
+ if (static_cast<int>(order.size()) < _node_num) {
+ _first_node = INVALID;
+ for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) {
+ (*_cut_map)[n] = false;
+ }
+ for (int i = 0; i < static_cast<int>(order.size()); ++i) {
+ typename Graph::Node n = order[i];
+ while (n != INVALID) {
+ (*_cut_map)[n] = true;
+ n = (*_next_rep)[n];
+ }
+ }
+ _min_cut = 0;
+ return true;
+ }
+
+ if (pmc < _min_cut) {
+ for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) {
+ (*_cut_map)[n] = false;
+ }
+ for (int i = 0; i < sep; ++i) {
+ typename Graph::Node n = order[i];
+ while (n != INVALID) {
+ (*_cut_map)[n] = true;
+ n = (*_next_rep)[n];
+ }
+ }
+ _min_cut = pmc;
+ }
+
+ for (typename Graph::Node n = _first_node;
+ n != INVALID; n = (*_nodes)[n].next) {
+ bool merged = false;
+ for (int a = (*_nodes)[n].first_arc; a != -1; a = _arcs[a].next) {
+ if (!(_edges[a >> 1].cut < pmc)) {
+ if (!merged) {
+ for (int b = (*_nodes)[n].first_arc; b != -1; b = _arcs[b].next) {
+ (*_nodes)[_arcs[b].target].curr_arc = b;
+ }
+ merged = true;
+ }
+ typename Graph::Node m = _arcs[a].target;
+ int nb = 0;
+ for (int b = (*_nodes)[m].first_arc; b != -1; b = nb) {
+ nb = _arcs[b].next;
+ if ((b ^ a) == 1) continue;
+ typename Graph::Node o = _arcs[b].target;
+ int c = (*_nodes)[o].curr_arc;
+ if (c != -1 && _arcs[c ^ 1].target == n) {
+ _edges[c >> 1].capacity += _edges[b >> 1].capacity;
+ (*_nodes)[n].sum += _edges[b >> 1].capacity;
+ if (_edges[b >> 1].cut < _edges[c >> 1].cut) {
+ _edges[b >> 1].cut = _edges[c >> 1].cut;
+ }
+ if (_arcs[b ^ 1].prev != -1) {
+ _arcs[_arcs[b ^ 1].prev].next = _arcs[b ^ 1].next;
+ } else {
+ (*_nodes)[o].first_arc = _arcs[b ^ 1].next;
+ }
+ if (_arcs[b ^ 1].next != -1) {
+ _arcs[_arcs[b ^ 1].next].prev = _arcs[b ^ 1].prev;
+ }
+ } else {
+ if (_arcs[a].next != -1) {
+ _arcs[_arcs[a].next].prev = b;
+ }
+ _arcs[b].next = _arcs[a].next;
+ _arcs[b].prev = a;
+ _arcs[a].next = b;
+ _arcs[b ^ 1].target = n;
+
+ (*_nodes)[n].sum += _edges[b >> 1].capacity;
+ (*_nodes)[o].curr_arc = b;
+ }
+ }
+
+ if (_arcs[a].prev != -1) {
+ _arcs[_arcs[a].prev].next = _arcs[a].next;
+ } else {
+ (*_nodes)[n].first_arc = _arcs[a].next;
+ }
+ if (_arcs[a].next != -1) {
+ _arcs[_arcs[a].next].prev = _arcs[a].prev;
+ }
+
+ (*_nodes)[n].sum -= _edges[a >> 1].capacity;
+ (*_next_rep)[(*_nodes)[n].last_rep] = m;
+ (*_nodes)[n].last_rep = (*_nodes)[m].last_rep;
+
+ if ((*_nodes)[m].prev != INVALID) {
+ (*_nodes)[(*_nodes)[m].prev].next = (*_nodes)[m].next;
+ } else{
+ _first_node = (*_nodes)[m].next;
+ }
+ if ((*_nodes)[m].next != INVALID) {
+ (*_nodes)[(*_nodes)[m].next].prev = (*_nodes)[m].prev;
+ }
+ --_node_num;
+ }
+ }
+ }
+
+ if (_node_num == 1) {
+ _first_node = INVALID;
+ return true;
+ }
+
+ return false;
+ }
+
+ /// \brief Executes the algorithm.
+ ///
+ /// Executes the algorithm.
+ ///
+ /// \pre init() must be called
+ void start() {
+ while (!processNextPhase()) {}
+ }
+
+
+ /// \brief Runs %NagamochiIbaraki algorithm.
+ ///
+ /// This method runs the %Min cut algorithm
+ ///
+ /// \note mc.run(s) is just a shortcut of the following code.
+ ///\code
+ /// mc.init();
+ /// mc.start();
+ ///\endcode
+ void run() {
+ init();
+ start();
+ }
+
+ ///@}
+
+ /// \name Query Functions
+ ///
+ /// The result of the %NagamochiIbaraki
+ /// algorithm can be obtained using these functions.\n
+ /// Before the use of these functions, either run() or start()
+ /// must be called.
+
+ ///@{
+
+ /// \brief Returns the min cut value.
+ ///
+ /// Returns the min cut value if the algorithm finished.
+ /// After the first processNextPhase() it is a value of a
+ /// valid cut in the graph.
+ Value minCutValue() const {
+ return _min_cut;
+ }
+
+ /// \brief Returns a min cut in a NodeMap.
+ ///
+ /// It sets the nodes of one of the two partitions to true and
+ /// the other partition to false.
+ /// \param cutMap A \ref concepts::WriteMap "writable" node map with
+ /// \c bool (or convertible) value type.
+ template <typename CutMap>
+ Value minCutMap(CutMap& cutMap) const {
+ for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) {
+ cutMap.set(n, (*_cut_map)[n]);
+ }
+ return minCutValue();
+ }
+
+ ///@}
+
+ };
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/nauty_reader.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/nauty_reader.h
new file mode 100644
index 00000000000..896f2a606bb
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/nauty_reader.h
@@ -0,0 +1,113 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_NAUTY_READER_H
+#define LEMON_NAUTY_READER_H
+
+#include <vector>
+#include <iostream>
+#include <string>
+
+/// \ingroup nauty_group
+/// \file
+/// \brief Nauty file reader.
+
+namespace lemon {
+
+ /// \ingroup nauty_group
+ ///
+ /// \brief Nauty file reader
+ ///
+ /// The \e geng program is in the \e gtools suite of the nauty
+ /// package. This tool can generate all non-isomorphic undirected
+ /// graphs of several classes with given node number (e.g.
+ /// general, connected, biconnected, triangle-free, 4-cycle-free,
+ /// bipartite and graphs with given edge number and degree
+ /// constraints). This function reads a \e nauty \e graph6 \e format
+ /// line from the given stream and builds it in the given graph.
+ ///
+ /// The site of nauty package: http://cs.anu.edu.au/~bdm/nauty/
+ ///
+ /// For example, the number of all non-isomorphic planar graphs
+ /// can be computed with the following code.
+ ///\code
+ /// int num = 0;
+ /// SmartGraph graph;
+ /// while (readNautyGraph(graph, std::cin)) {
+ /// PlanarityChecking<SmartGraph> pc(graph);
+ /// if (pc.run()) ++num;
+ /// }
+ /// std::cout << "Number of planar graphs: " << num << std::endl;
+ ///\endcode
+ ///
+ /// The nauty files are quite huge, therefore instead of the direct
+ /// file generation pipelining is recommended. For example,
+ ///\code
+ /// ./geng -c 10 | ./num_of_planar_graphs
+ ///\endcode
+ template <typename Graph>
+ std::istream& readNautyGraph(Graph& graph, std::istream& is = std::cin) {
+ graph.clear();
+
+ std::string line;
+ if (getline(is, line)) {
+ int index = 0;
+
+ int n;
+
+ if (line[index] == '>') {
+ index += 10;
+ }
+
+ char c = line[index++]; c -= 63;
+ if (c != 63) {
+ n = int(c);
+ } else {
+ c = line[index++]; c -= 63;
+ n = (int(c) << 12);
+ c = line[index++]; c -= 63;
+ n |= (int(c) << 6);
+ c = line[index++]; c -= 63;
+ n |= int(c);
+ }
+
+ std::vector<typename Graph::Node> nodes;
+ for (int i = 0; i < n; ++i) {
+ nodes.push_back(graph.addNode());
+ }
+
+ int bit = -1;
+ for (int j = 0; j < n; ++j) {
+ for (int i = 0; i < j; ++i) {
+ if (bit == -1) {
+ c = line[index++]; c -= 63;
+ bit = 5;
+ }
+ bool b = (c & (1 << (bit--))) != 0;
+
+ if (b) {
+ graph.addEdge(nodes[i], nodes[j]);
+ }
+ }
+ }
+ }
+ return is;
+ }
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/nearest_neighbor_tsp.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/nearest_neighbor_tsp.h
new file mode 100644
index 00000000000..065e145df08
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/nearest_neighbor_tsp.h
@@ -0,0 +1,238 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_NEAREST_NEIGHBOUR_TSP_H
+#define LEMON_NEAREST_NEIGHBOUR_TSP_H
+
+/// \ingroup tsp
+/// \file
+/// \brief Nearest neighbor algorithm for symmetric TSP
+
+#include <deque>
+#include <vector>
+#include <limits>
+#include <lemon/full_graph.h>
+#include <lemon/maps.h>
+
+namespace lemon {
+
+ /// \ingroup tsp
+ ///
+ /// \brief Nearest neighbor algorithm for symmetric TSP.
+ ///
+ /// NearestNeighborTsp implements the nearest neighbor heuristic for solving
+ /// symmetric \ref tsp "TSP".
+ ///
+ /// This is probably the simplest TSP heuristic.
+ /// It starts with a minimum cost edge and at each step, it connects the
+ /// nearest unvisited node to the current path.
+ /// Finally, it connects the two end points of the path to form a tour.
+ ///
+ /// This method runs in O(n<sup>2</sup>) time.
+ /// It quickly finds a relatively short tour for most TSP instances,
+ /// but it could also yield a really bad (or even the worst) solution
+ /// in special cases.
+ ///
+ /// \tparam CM Type of the cost map.
+ template <typename CM>
+ class NearestNeighborTsp
+ {
+ public:
+
+ /// Type of the cost map
+ typedef CM CostMap;
+ /// Type of the edge costs
+ typedef typename CM::Value Cost;
+
+ private:
+
+ GRAPH_TYPEDEFS(FullGraph);
+
+ const FullGraph &_gr;
+ const CostMap &_cost;
+ Cost _sum;
+ std::vector<Node> _path;
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ /// \param gr The \ref FullGraph "full graph" the algorithm runs on.
+ /// \param cost The cost map.
+ NearestNeighborTsp(const FullGraph &gr, const CostMap &cost)
+ : _gr(gr), _cost(cost) {}
+
+ /// \name Execution Control
+ /// @{
+
+ /// \brief Runs the algorithm.
+ ///
+ /// This function runs the algorithm.
+ ///
+ /// \return The total cost of the found tour.
+ Cost run() {
+ _path.clear();
+ if (_gr.nodeNum() == 0) {
+ return _sum = 0;
+ }
+ else if (_gr.nodeNum() == 1) {
+ _path.push_back(_gr(0));
+ return _sum = 0;
+ }
+
+ std::deque<Node> path_dq;
+ Edge min_edge1 = INVALID,
+ min_edge2 = INVALID;
+
+ min_edge1 = mapMin(_gr, _cost);
+ Node n1 = _gr.u(min_edge1),
+ n2 = _gr.v(min_edge1);
+ path_dq.push_back(n1);
+ path_dq.push_back(n2);
+
+ FullGraph::NodeMap<bool> used(_gr, false);
+ used[n1] = true;
+ used[n2] = true;
+
+ min_edge1 = INVALID;
+ while (int(path_dq.size()) != _gr.nodeNum()) {
+ if (min_edge1 == INVALID) {
+ for (IncEdgeIt e(_gr, n1); e != INVALID; ++e) {
+ if (!used[_gr.runningNode(e)] &&
+ (min_edge1 == INVALID || _cost[e] < _cost[min_edge1])) {
+ min_edge1 = e;
+ }
+ }
+ }
+
+ if (min_edge2 == INVALID) {
+ for (IncEdgeIt e(_gr, n2); e != INVALID; ++e) {
+ if (!used[_gr.runningNode(e)] &&
+ (min_edge2 == INVALID||_cost[e] < _cost[min_edge2])) {
+ min_edge2 = e;
+ }
+ }
+ }
+
+ if (_cost[min_edge1] < _cost[min_edge2]) {
+ n1 = _gr.oppositeNode(n1, min_edge1);
+ path_dq.push_front(n1);
+
+ used[n1] = true;
+ min_edge1 = INVALID;
+
+ if (_gr.u(min_edge2) == n1 || _gr.v(min_edge2) == n1)
+ min_edge2 = INVALID;
+ } else {
+ n2 = _gr.oppositeNode(n2, min_edge2);
+ path_dq.push_back(n2);
+
+ used[n2] = true;
+ min_edge2 = INVALID;
+
+ if (_gr.u(min_edge1) == n2 || _gr.v(min_edge1) == n2)
+ min_edge1 = INVALID;
+ }
+ }
+
+ n1 = path_dq.back();
+ n2 = path_dq.front();
+ _path.push_back(n2);
+ _sum = _cost[_gr.edge(n1, n2)];
+ for (int i = 1; i < int(path_dq.size()); ++i) {
+ n1 = n2;
+ n2 = path_dq[i];
+ _path.push_back(n2);
+ _sum += _cost[_gr.edge(n1, n2)];
+ }
+
+ return _sum;
+ }
+
+ /// @}
+
+ /// \name Query Functions
+ /// @{
+
+ /// \brief The total cost of the found tour.
+ ///
+ /// This function returns the total cost of the found tour.
+ ///
+ /// \pre run() must be called before using this function.
+ Cost tourCost() const {
+ return _sum;
+ }
+
+ /// \brief Returns a const reference to the node sequence of the
+ /// found tour.
+ ///
+ /// This function returns a const reference to a vector
+ /// that stores the node sequence of the found tour.
+ ///
+ /// \pre run() must be called before using this function.
+ const std::vector<Node>& tourNodes() const {
+ return _path;
+ }
+
+ /// \brief Gives back the node sequence of the found tour.
+ ///
+ /// This function copies the node sequence of the found tour into
+ /// an STL container through the given output iterator. The
+ /// <tt>value_type</tt> of the container must be <tt>FullGraph::Node</tt>.
+ /// For example,
+ /// \code
+ /// std::vector<FullGraph::Node> nodes(countNodes(graph));
+ /// tsp.tourNodes(nodes.begin());
+ /// \endcode
+ /// or
+ /// \code
+ /// std::list<FullGraph::Node> nodes;
+ /// tsp.tourNodes(std::back_inserter(nodes));
+ /// \endcode
+ ///
+ /// \pre run() must be called before using this function.
+ template <typename Iterator>
+ void tourNodes(Iterator out) const {
+ std::copy(_path.begin(), _path.end(), out);
+ }
+
+ /// \brief Gives back the found tour as a path.
+ ///
+ /// This function copies the found tour as a list of arcs/edges into
+ /// the given \ref lemon::concepts::Path "path structure".
+ ///
+ /// \pre run() must be called before using this function.
+ template <typename Path>
+ void tour(Path &path) const {
+ path.clear();
+ for (int i = 0; i < int(_path.size()) - 1; ++i) {
+ path.addBack(_gr.arc(_path[i], _path[i+1]));
+ }
+ if (int(_path.size()) >= 2) {
+ path.addBack(_gr.arc(_path.back(), _path.front()));
+ }
+ }
+
+ /// @}
+
+ };
+
+}; // namespace lemon
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h
new file mode 100644
index 00000000000..388e990ec3b
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h
@@ -0,0 +1,1659 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_NETWORK_SIMPLEX_H
+#define LEMON_NETWORK_SIMPLEX_H
+
+/// \ingroup min_cost_flow_algs
+///
+/// \file
+/// \brief Network Simplex algorithm for finding a minimum cost flow.
+
+#include <vector>
+#include <limits>
+#include <algorithm>
+
+#include <lemon/core.h>
+#include <lemon/math.h>
+
+namespace lemon {
+
+ /// \addtogroup min_cost_flow_algs
+ /// @{
+
+ /// \brief Implementation of the primal Network Simplex algorithm
+ /// for finding a \ref min_cost_flow "minimum cost flow".
+ ///
+ /// \ref NetworkSimplex implements the primal Network Simplex algorithm
+ /// for finding a \ref min_cost_flow "minimum cost flow"
+ /// \cite amo93networkflows, \cite dantzig63linearprog,
+ /// \cite kellyoneill91netsimplex.
+ /// This algorithm is a highly efficient specialized version of the
+ /// linear programming simplex method directly for the minimum cost
+ /// flow problem.
+ ///
+ /// In general, \ref NetworkSimplex and \ref CostScaling are the fastest
+ /// implementations available in LEMON for solving this problem.
+ /// (For more information, see \ref min_cost_flow_algs "the module page".)
+ /// Furthermore, this class supports both directions of the supply/demand
+ /// inequality constraints. For more information, see \ref SupplyType.
+ ///
+ /// Most of the parameters of the problem (except for the digraph)
+ /// can be given using separate functions, and the algorithm can be
+ /// executed using the \ref run() function. If some parameters are not
+ /// specified, then default values will be used.
+ ///
+ /// \tparam GR The digraph type the algorithm runs on.
+ /// \tparam V The number type used for flow amounts, capacity bounds
+ /// and supply values in the algorithm. By default, it is \c int.
+ /// \tparam C The number type used for costs and potentials in the
+ /// algorithm. By default, it is the same as \c V.
+ ///
+ /// \warning Both \c V and \c C must be signed number types.
+ /// \warning All input data (capacities, supply values, and costs) must
+ /// be integer.
+ ///
+ /// \note %NetworkSimplex provides five different pivot rule
+ /// implementations, from which the most efficient one is used
+ /// by default. For more information, see \ref PivotRule.
+ template <typename GR, typename V = int, typename C = V>
+ class NetworkSimplex
+ {
+ public:
+
+ /// The type of the flow amounts, capacity bounds and supply values
+ typedef V Value;
+ /// The type of the arc costs
+ typedef C Cost;
+
+ public:
+
+ /// \brief Problem type constants for the \c run() function.
+ ///
+ /// Enum type containing the problem type constants that can be
+ /// returned by the \ref run() function of the algorithm.
+ enum ProblemType {
+ /// The problem has no feasible solution (flow).
+ INFEASIBLE,
+ /// The problem has optimal solution (i.e. it is feasible and
+ /// bounded), and the algorithm has found optimal flow and node
+ /// potentials (primal and dual solutions).
+ OPTIMAL,
+ /// The objective function of the problem is unbounded, i.e.
+ /// there is a directed cycle having negative total cost and
+ /// infinite upper bound.
+ UNBOUNDED
+ };
+
+ /// \brief Constants for selecting the type of the supply constraints.
+ ///
+ /// Enum type containing constants for selecting the supply type,
+ /// i.e. the direction of the inequalities in the supply/demand
+ /// constraints of the \ref min_cost_flow "minimum cost flow problem".
+ ///
+ /// The default supply type is \c GEQ, the \c LEQ type can be
+ /// selected using \ref supplyType().
+ /// The equality form is a special case of both supply types.
+ enum SupplyType {
+ /// This option means that there are <em>"greater or equal"</em>
+ /// supply/demand constraints in the definition of the problem.
+ GEQ,
+ /// This option means that there are <em>"less or equal"</em>
+ /// supply/demand constraints in the definition of the problem.
+ LEQ
+ };
+
+ /// \brief Constants for selecting the pivot rule.
+ ///
+ /// Enum type containing constants for selecting the pivot rule for
+ /// the \ref run() function.
+ ///
+ /// \ref NetworkSimplex provides five different implementations for
+ /// the pivot strategy that significantly affects the running time
+ /// of the algorithm.
+ /// According to experimental tests conducted on various problem
+ /// instances, \ref BLOCK_SEARCH "Block Search" and
+ /// \ref ALTERING_LIST "Altering Candidate List" rules turned out
+ /// to be the most efficient.
+ /// Since \ref BLOCK_SEARCH "Block Search" is a simpler strategy that
+ /// seemed to be slightly more robust, it is used by default.
+ /// However, another pivot rule can easily be selected using the
+ /// \ref run() function with the proper parameter.
+ enum PivotRule {
+
+ /// The \e First \e Eligible pivot rule.
+ /// The next eligible arc is selected in a wraparound fashion
+ /// in every iteration.
+ FIRST_ELIGIBLE,
+
+ /// The \e Best \e Eligible pivot rule.
+ /// The best eligible arc is selected in every iteration.
+ BEST_ELIGIBLE,
+
+ /// The \e Block \e Search pivot rule.
+ /// A specified number of arcs are examined in every iteration
+ /// in a wraparound fashion and the best eligible arc is selected
+ /// from this block.
+ BLOCK_SEARCH,
+
+ /// The \e Candidate \e List pivot rule.
+ /// In a major iteration a candidate list is built from eligible arcs
+ /// in a wraparound fashion and in the following minor iterations
+ /// the best eligible arc is selected from this list.
+ CANDIDATE_LIST,
+
+ /// The \e Altering \e Candidate \e List pivot rule.
+ /// It is a modified version of the Candidate List method.
+ /// It keeps only a few of the best eligible arcs from the former
+ /// candidate list and extends this list in every iteration.
+ ALTERING_LIST
+ };
+
+ private:
+
+ TEMPLATE_DIGRAPH_TYPEDEFS(GR);
+
+ typedef std::vector<int> IntVector;
+ typedef std::vector<Value> ValueVector;
+ typedef std::vector<Cost> CostVector;
+ typedef std::vector<signed char> CharVector;
+ // Note: vector<signed char> is used instead of vector<ArcState> and
+ // vector<ArcDirection> for efficiency reasons
+
+ // State constants for arcs
+ enum ArcState {
+ STATE_UPPER = -1,
+ STATE_TREE = 0,
+ STATE_LOWER = 1
+ };
+
+ // Direction constants for tree arcs
+ enum ArcDirection {
+ DIR_DOWN = -1,
+ DIR_UP = 1
+ };
+
+ private:
+
+ // Data related to the underlying digraph
+ const GR &_graph;
+ int _node_num;
+ int _arc_num;
+ int _all_arc_num;
+ int _search_arc_num;
+
+ // Parameters of the problem
+ bool _has_lower;
+ SupplyType _stype;
+ Value _sum_supply;
+
+ // Data structures for storing the digraph
+ IntNodeMap _node_id;
+ IntArcMap _arc_id;
+ IntVector _source;
+ IntVector _target;
+ bool _arc_mixing;
+
+ // Node and arc data
+ ValueVector _lower;
+ ValueVector _upper;
+ ValueVector _cap;
+ CostVector _cost;
+ ValueVector _supply;
+ ValueVector _flow;
+ CostVector _pi;
+
+ // Data for storing the spanning tree structure
+ IntVector _parent;
+ IntVector _pred;
+ IntVector _thread;
+ IntVector _rev_thread;
+ IntVector _succ_num;
+ IntVector _last_succ;
+ CharVector _pred_dir;
+ CharVector _state;
+ IntVector _dirty_revs;
+ int _root;
+
+ // Temporary data used in the current pivot iteration
+ int in_arc, join, u_in, v_in, u_out, v_out;
+ Value delta;
+
+ const Value MAX_VALUE;
+
+ public:
+
+ /// \brief Constant for infinite upper bounds (capacities).
+ ///
+ /// Constant for infinite upper bounds (capacities).
+ /// It is \c std::numeric_limits<Value>::infinity() if available,
+ /// \c std::numeric_limits<Value>::max() otherwise.
+ const Value INF;
+
+ private:
+
+ // Implementation of the First Eligible pivot rule
+ class FirstEligiblePivotRule
+ {
+ private:
+
+ // References to the NetworkSimplex class
+ const IntVector &_source;
+ const IntVector &_target;
+ const CostVector &_cost;
+ const CharVector &_state;
+ const CostVector &_pi;
+ int &_in_arc;
+ int _search_arc_num;
+
+ // Pivot rule data
+ int _next_arc;
+
+ public:
+
+ // Constructor
+ FirstEligiblePivotRule(NetworkSimplex &ns) :
+ _source(ns._source), _target(ns._target),
+ _cost(ns._cost), _state(ns._state), _pi(ns._pi),
+ _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num),
+ _next_arc(0)
+ {}
+
+ // Find next entering arc
+ bool findEnteringArc() {
+ Cost c;
+ for (int e = _next_arc; e != _search_arc_num; ++e) {
+ c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
+ if (c < 0) {
+ _in_arc = e;
+ _next_arc = e + 1;
+ return true;
+ }
+ }
+ for (int e = 0; e != _next_arc; ++e) {
+ c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
+ if (c < 0) {
+ _in_arc = e;
+ _next_arc = e + 1;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ }; //class FirstEligiblePivotRule
+
+
+ // Implementation of the Best Eligible pivot rule
+ class BestEligiblePivotRule
+ {
+ private:
+
+ // References to the NetworkSimplex class
+ const IntVector &_source;
+ const IntVector &_target;
+ const CostVector &_cost;
+ const CharVector &_state;
+ const CostVector &_pi;
+ int &_in_arc;
+ int _search_arc_num;
+
+ public:
+
+ // Constructor
+ BestEligiblePivotRule(NetworkSimplex &ns) :
+ _source(ns._source), _target(ns._target),
+ _cost(ns._cost), _state(ns._state), _pi(ns._pi),
+ _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num)
+ {}
+
+ // Find next entering arc
+ bool findEnteringArc() {
+ Cost c, min = 0;
+ for (int e = 0; e != _search_arc_num; ++e) {
+ c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
+ if (c < min) {
+ min = c;
+ _in_arc = e;
+ }
+ }
+ return min < 0;
+ }
+
+ }; //class BestEligiblePivotRule
+
+
+ // Implementation of the Block Search pivot rule
+ class BlockSearchPivotRule
+ {
+ private:
+
+ // References to the NetworkSimplex class
+ const IntVector &_source;
+ const IntVector &_target;
+ const CostVector &_cost;
+ const CharVector &_state;
+ const CostVector &_pi;
+ int &_in_arc;
+ int _search_arc_num;
+
+ // Pivot rule data
+ int _block_size;
+ int _next_arc;
+
+ public:
+
+ // Constructor
+ BlockSearchPivotRule(NetworkSimplex &ns) :
+ _source(ns._source), _target(ns._target),
+ _cost(ns._cost), _state(ns._state), _pi(ns._pi),
+ _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num),
+ _next_arc(0)
+ {
+ // The main parameters of the pivot rule
+ const double BLOCK_SIZE_FACTOR = 1.0;
+ const int MIN_BLOCK_SIZE = 10;
+
+ _block_size = std::max( int(BLOCK_SIZE_FACTOR *
+ std::sqrt(double(_search_arc_num))),
+ MIN_BLOCK_SIZE );
+ }
+
+ // Find next entering arc
+ bool findEnteringArc() {
+ Cost c, min = 0;
+ int cnt = _block_size;
+ int e;
+ for (e = _next_arc; e != _search_arc_num; ++e) {
+ c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
+ if (c < min) {
+ min = c;
+ _in_arc = e;
+ }
+ if (--cnt == 0) {
+ if (min < 0) goto search_end;
+ cnt = _block_size;
+ }
+ }
+ for (e = 0; e != _next_arc; ++e) {
+ c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
+ if (c < min) {
+ min = c;
+ _in_arc = e;
+ }
+ if (--cnt == 0) {
+ if (min < 0) goto search_end;
+ cnt = _block_size;
+ }
+ }
+ if (min >= 0) return false;
+
+ search_end:
+ _next_arc = e;
+ return true;
+ }
+
+ }; //class BlockSearchPivotRule
+
+
+ // Implementation of the Candidate List pivot rule
+ class CandidateListPivotRule
+ {
+ private:
+
+ // References to the NetworkSimplex class
+ const IntVector &_source;
+ const IntVector &_target;
+ const CostVector &_cost;
+ const CharVector &_state;
+ const CostVector &_pi;
+ int &_in_arc;
+ int _search_arc_num;
+
+ // Pivot rule data
+ IntVector _candidates;
+ int _list_length, _minor_limit;
+ int _curr_length, _minor_count;
+ int _next_arc;
+
+ public:
+
+ /// Constructor
+ CandidateListPivotRule(NetworkSimplex &ns) :
+ _source(ns._source), _target(ns._target),
+ _cost(ns._cost), _state(ns._state), _pi(ns._pi),
+ _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num),
+ _next_arc(0)
+ {
+ // The main parameters of the pivot rule
+ const double LIST_LENGTH_FACTOR = 0.25;
+ const int MIN_LIST_LENGTH = 10;
+ const double MINOR_LIMIT_FACTOR = 0.1;
+ const int MIN_MINOR_LIMIT = 3;
+
+ _list_length = std::max( int(LIST_LENGTH_FACTOR *
+ std::sqrt(double(_search_arc_num))),
+ MIN_LIST_LENGTH );
+ _minor_limit = std::max( int(MINOR_LIMIT_FACTOR * _list_length),
+ MIN_MINOR_LIMIT );
+ _curr_length = _minor_count = 0;
+ _candidates.resize(_list_length);
+ }
+
+ /// Find next entering arc
+ bool findEnteringArc() {
+ Cost min, c;
+ int e;
+ if (_curr_length > 0 && _minor_count < _minor_limit) {
+ // Minor iteration: select the best eligible arc from the
+ // current candidate list
+ ++_minor_count;
+ min = 0;
+ for (int i = 0; i < _curr_length; ++i) {
+ e = _candidates[i];
+ c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
+ if (c < min) {
+ min = c;
+ _in_arc = e;
+ }
+ else if (c >= 0) {
+ _candidates[i--] = _candidates[--_curr_length];
+ }
+ }
+ if (min < 0) return true;
+ }
+
+ // Major iteration: build a new candidate list
+ min = 0;
+ _curr_length = 0;
+ for (e = _next_arc; e != _search_arc_num; ++e) {
+ c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
+ if (c < 0) {
+ _candidates[_curr_length++] = e;
+ if (c < min) {
+ min = c;
+ _in_arc = e;
+ }
+ if (_curr_length == _list_length) goto search_end;
+ }
+ }
+ for (e = 0; e != _next_arc; ++e) {
+ c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
+ if (c < 0) {
+ _candidates[_curr_length++] = e;
+ if (c < min) {
+ min = c;
+ _in_arc = e;
+ }
+ if (_curr_length == _list_length) goto search_end;
+ }
+ }
+ if (_curr_length == 0) return false;
+
+ search_end:
+ _minor_count = 1;
+ _next_arc = e;
+ return true;
+ }
+
+ }; //class CandidateListPivotRule
+
+
+ // Implementation of the Altering Candidate List pivot rule
+ class AlteringListPivotRule
+ {
+ private:
+
+ // References to the NetworkSimplex class
+ const IntVector &_source;
+ const IntVector &_target;
+ const CostVector &_cost;
+ const CharVector &_state;
+ const CostVector &_pi;
+ int &_in_arc;
+ int _search_arc_num;
+
+ // Pivot rule data
+ int _block_size, _head_length, _curr_length;
+ int _next_arc;
+ IntVector _candidates;
+ CostVector _cand_cost;
+
+ // Functor class to compare arcs during sort of the candidate list
+ class SortFunc
+ {
+ private:
+ const CostVector &_map;
+ public:
+ SortFunc(const CostVector &map) : _map(map) {}
+ bool operator()(int left, int right) {
+ return _map[left] < _map[right];
+ }
+ };
+
+ SortFunc _sort_func;
+
+ public:
+
+ // Constructor
+ AlteringListPivotRule(NetworkSimplex &ns) :
+ _source(ns._source), _target(ns._target),
+ _cost(ns._cost), _state(ns._state), _pi(ns._pi),
+ _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num),
+ _next_arc(0), _cand_cost(ns._search_arc_num), _sort_func(_cand_cost)
+ {
+ // The main parameters of the pivot rule
+ const double BLOCK_SIZE_FACTOR = 1.0;
+ const int MIN_BLOCK_SIZE = 10;
+ const double HEAD_LENGTH_FACTOR = 0.01;
+ const int MIN_HEAD_LENGTH = 3;
+
+ _block_size = std::max( int(BLOCK_SIZE_FACTOR *
+ std::sqrt(double(_search_arc_num))),
+ MIN_BLOCK_SIZE );
+ _head_length = std::max( int(HEAD_LENGTH_FACTOR * _block_size),
+ MIN_HEAD_LENGTH );
+ _candidates.resize(_head_length + _block_size);
+ _curr_length = 0;
+ }
+
+ // Find next entering arc
+ bool findEnteringArc() {
+ // Check the current candidate list
+ int e;
+ Cost c;
+ for (int i = 0; i != _curr_length; ++i) {
+ e = _candidates[i];
+ c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
+ if (c < 0) {
+ _cand_cost[e] = c;
+ } else {
+ _candidates[i--] = _candidates[--_curr_length];
+ }
+ }
+
+ // Extend the list
+ int cnt = _block_size;
+ int limit = _head_length;
+
+ for (e = _next_arc; e != _search_arc_num; ++e) {
+ c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
+ if (c < 0) {
+ _cand_cost[e] = c;
+ _candidates[_curr_length++] = e;
+ }
+ if (--cnt == 0) {
+ if (_curr_length > limit) goto search_end;
+ limit = 0;
+ cnt = _block_size;
+ }
+ }
+ for (e = 0; e != _next_arc; ++e) {
+ c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
+ if (c < 0) {
+ _cand_cost[e] = c;
+ _candidates[_curr_length++] = e;
+ }
+ if (--cnt == 0) {
+ if (_curr_length > limit) goto search_end;
+ limit = 0;
+ cnt = _block_size;
+ }
+ }
+ if (_curr_length == 0) return false;
+
+ search_end:
+
+ // Perform partial sort operation on the candidate list
+ int new_length = std::min(_head_length + 1, _curr_length);
+ std::partial_sort(_candidates.begin(), _candidates.begin() + new_length,
+ _candidates.begin() + _curr_length, _sort_func);
+
+ // Select the entering arc and remove it from the list
+ _in_arc = _candidates[0];
+ _next_arc = e;
+ _candidates[0] = _candidates[new_length - 1];
+ _curr_length = new_length - 1;
+ return true;
+ }
+
+ }; //class AlteringListPivotRule
+
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// The constructor of the class.
+ ///
+ /// \param graph The digraph the algorithm runs on.
+ /// \param arc_mixing Indicate if the arcs will be stored in a
+ /// mixed order in the internal data structure.
+ /// In general, it leads to similar performance as using the original
+ /// arc order, but it makes the algorithm more robust and in special
+ /// cases, even significantly faster. Therefore, it is enabled by default.
+ NetworkSimplex(const GR& graph, bool arc_mixing = true) :
+ _graph(graph), _node_id(graph), _arc_id(graph),
+ _arc_mixing(arc_mixing),
+ MAX_VALUE(std::numeric_limits<Value>::max()),
+ INF(std::numeric_limits<Value>::has_infinity ?
+ std::numeric_limits<Value>::infinity() : MAX_VALUE)
+ {
+ // Check the number types
+ LEMON_ASSERT(std::numeric_limits<Value>::is_signed,
+ "The flow type of NetworkSimplex must be signed");
+ LEMON_ASSERT(std::numeric_limits<Cost>::is_signed,
+ "The cost type of NetworkSimplex must be signed");
+
+ // Reset data structures
+ reset();
+ }
+
+ /// \name Parameters
+ /// The parameters of the algorithm can be specified using these
+ /// functions.
+
+ /// @{
+
+ /// \brief Set the lower bounds on the arcs.
+ ///
+ /// This function sets the lower bounds on the arcs.
+ /// If it is not used before calling \ref run(), the lower bounds
+ /// will be set to zero on all arcs.
+ ///
+ /// \param map An arc map storing the lower bounds.
+ /// Its \c Value type must be convertible to the \c Value type
+ /// of the algorithm.
+ ///
+ /// \return <tt>(*this)</tt>
+ template <typename LowerMap>
+ NetworkSimplex& lowerMap(const LowerMap& map) {
+ _has_lower = true;
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ _lower[_arc_id[a]] = map[a];
+ }
+ return *this;
+ }
+
+ /// \brief Set the upper bounds (capacities) on the arcs.
+ ///
+ /// This function sets the upper bounds (capacities) on the arcs.
+ /// If it is not used before calling \ref run(), the upper bounds
+ /// will be set to \ref INF on all arcs (i.e. the flow value will be
+ /// unbounded from above).
+ ///
+ /// \param map An arc map storing the upper bounds.
+ /// Its \c Value type must be convertible to the \c Value type
+ /// of the algorithm.
+ ///
+ /// \return <tt>(*this)</tt>
+ template<typename UpperMap>
+ NetworkSimplex& upperMap(const UpperMap& map) {
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ _upper[_arc_id[a]] = map[a];
+ }
+ return *this;
+ }
+
+ /// \brief Set the costs of the arcs.
+ ///
+ /// This function sets the costs of the arcs.
+ /// If it is not used before calling \ref run(), the costs
+ /// will be set to \c 1 on all arcs.
+ ///
+ /// \param map An arc map storing the costs.
+ /// Its \c Value type must be convertible to the \c Cost type
+ /// of the algorithm.
+ ///
+ /// \return <tt>(*this)</tt>
+ template<typename CostMap>
+ NetworkSimplex& costMap(const CostMap& map) {
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ _cost[_arc_id[a]] = map[a];
+ }
+ return *this;
+ }
+
+ /// \brief Set the supply values of the nodes.
+ ///
+ /// This function sets the supply values of the nodes.
+ /// If neither this function nor \ref stSupply() is used before
+ /// calling \ref run(), the supply of each node will be set to zero.
+ ///
+ /// \param map A node map storing the supply values.
+ /// Its \c Value type must be convertible to the \c Value type
+ /// of the algorithm.
+ ///
+ /// \return <tt>(*this)</tt>
+ ///
+ /// \sa supplyType()
+ template<typename SupplyMap>
+ NetworkSimplex& supplyMap(const SupplyMap& map) {
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ _supply[_node_id[n]] = map[n];
+ }
+ return *this;
+ }
+
+ /// \brief Set single source and target nodes and a supply value.
+ ///
+ /// This function sets a single source node and a single target node
+ /// and the required flow value.
+ /// If neither this function nor \ref supplyMap() is used before
+ /// calling \ref run(), the supply of each node will be set to zero.
+ ///
+ /// Using this function has the same effect as using \ref supplyMap()
+ /// with a map in which \c k is assigned to \c s, \c -k is
+ /// assigned to \c t and all other nodes have zero supply value.
+ ///
+ /// \param s The source node.
+ /// \param t The target node.
+ /// \param k The required amount of flow from node \c s to node \c t
+ /// (i.e. the supply of \c s and the demand of \c t).
+ ///
+ /// \return <tt>(*this)</tt>
+ NetworkSimplex& stSupply(const Node& s, const Node& t, Value k) {
+ for (int i = 0; i != _node_num; ++i) {
+ _supply[i] = 0;
+ }
+ _supply[_node_id[s]] = k;
+ _supply[_node_id[t]] = -k;
+ return *this;
+ }
+
+ /// \brief Set the type of the supply constraints.
+ ///
+ /// This function sets the type of the supply/demand constraints.
+ /// If it is not used before calling \ref run(), the \ref GEQ supply
+ /// type will be used.
+ ///
+ /// For more information, see \ref SupplyType.
+ ///
+ /// \return <tt>(*this)</tt>
+ NetworkSimplex& supplyType(SupplyType supply_type) {
+ _stype = supply_type;
+ return *this;
+ }
+
+ /// @}
+
+ /// \name Execution Control
+ /// The algorithm can be executed using \ref run().
+
+ /// @{
+
+ /// \brief Run the algorithm.
+ ///
+ /// This function runs the algorithm.
+ /// The paramters can be specified using functions \ref lowerMap(),
+ /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(),
+ /// \ref supplyType().
+ /// For example,
+ /// \code
+ /// NetworkSimplex<ListDigraph> ns(graph);
+ /// ns.lowerMap(lower).upperMap(upper).costMap(cost)
+ /// .supplyMap(sup).run();
+ /// \endcode
+ ///
+ /// This function can be called more than once. All the given parameters
+ /// are kept for the next call, unless \ref resetParams() or \ref reset()
+ /// is used, thus only the modified parameters have to be set again.
+ /// If the underlying digraph was also modified after the construction
+ /// of the class (or the last \ref reset() call), then the \ref reset()
+ /// function must be called.
+ ///
+ /// \param pivot_rule The pivot rule that will be used during the
+ /// algorithm. For more information, see \ref PivotRule.
+ ///
+ /// \return \c INFEASIBLE if no feasible flow exists,
+ /// \n \c OPTIMAL if the problem has optimal solution
+ /// (i.e. it is feasible and bounded), and the algorithm has found
+ /// optimal flow and node potentials (primal and dual solutions),
+ /// \n \c UNBOUNDED if the objective function of the problem is
+ /// unbounded, i.e. there is a directed cycle having negative total
+ /// cost and infinite upper bound.
+ ///
+ /// \see ProblemType, PivotRule
+ /// \see resetParams(), reset()
+ ProblemType run(PivotRule pivot_rule = BLOCK_SEARCH) {
+ if (!init()) return INFEASIBLE;
+ return start(pivot_rule);
+ }
+
+ /// \brief Reset all the parameters that have been given before.
+ ///
+ /// This function resets all the paramaters that have been given
+ /// before using functions \ref lowerMap(), \ref upperMap(),
+ /// \ref costMap(), \ref supplyMap(), \ref stSupply(), \ref supplyType().
+ ///
+ /// It is useful for multiple \ref run() calls. Basically, all the given
+ /// parameters are kept for the next \ref run() call, unless
+ /// \ref resetParams() or \ref reset() is used.
+ /// If the underlying digraph was also modified after the construction
+ /// of the class or the last \ref reset() call, then the \ref reset()
+ /// function must be used, otherwise \ref resetParams() is sufficient.
+ ///
+ /// For example,
+ /// \code
+ /// NetworkSimplex<ListDigraph> ns(graph);
+ ///
+ /// // First run
+ /// ns.lowerMap(lower).upperMap(upper).costMap(cost)
+ /// .supplyMap(sup).run();
+ ///
+ /// // Run again with modified cost map (resetParams() is not called,
+ /// // so only the cost map have to be set again)
+ /// cost[e] += 100;
+ /// ns.costMap(cost).run();
+ ///
+ /// // Run again from scratch using resetParams()
+ /// // (the lower bounds will be set to zero on all arcs)
+ /// ns.resetParams();
+ /// ns.upperMap(capacity).costMap(cost)
+ /// .supplyMap(sup).run();
+ /// \endcode
+ ///
+ /// \return <tt>(*this)</tt>
+ ///
+ /// \see reset(), run()
+ NetworkSimplex& resetParams() {
+ for (int i = 0; i != _node_num; ++i) {
+ _supply[i] = 0;
+ }
+ for (int i = 0; i != _arc_num; ++i) {
+ _lower[i] = 0;
+ _upper[i] = INF;
+ _cost[i] = 1;
+ }
+ _has_lower = false;
+ _stype = GEQ;
+ return *this;
+ }
+
+ /// \brief Reset the internal data structures and all the parameters
+ /// that have been given before.
+ ///
+ /// This function resets the internal data structures and all the
+ /// paramaters that have been given before using functions \ref lowerMap(),
+ /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(),
+ /// \ref supplyType().
+ ///
+ /// It is useful for multiple \ref run() calls. Basically, all the given
+ /// parameters are kept for the next \ref run() call, unless
+ /// \ref resetParams() or \ref reset() is used.
+ /// If the underlying digraph was also modified after the construction
+ /// of the class or the last \ref reset() call, then the \ref reset()
+ /// function must be used, otherwise \ref resetParams() is sufficient.
+ ///
+ /// See \ref resetParams() for examples.
+ ///
+ /// \return <tt>(*this)</tt>
+ ///
+ /// \see resetParams(), run()
+ NetworkSimplex& reset() {
+ // Resize vectors
+ _node_num = countNodes(_graph);
+ _arc_num = countArcs(_graph);
+ int all_node_num = _node_num + 1;
+ int max_arc_num = _arc_num + 2 * _node_num;
+
+ _source.resize(max_arc_num);
+ _target.resize(max_arc_num);
+
+ _lower.resize(_arc_num);
+ _upper.resize(_arc_num);
+ _cap.resize(max_arc_num);
+ _cost.resize(max_arc_num);
+ _supply.resize(all_node_num);
+ _flow.resize(max_arc_num);
+ _pi.resize(all_node_num);
+
+ _parent.resize(all_node_num);
+ _pred.resize(all_node_num);
+ _pred_dir.resize(all_node_num);
+ _thread.resize(all_node_num);
+ _rev_thread.resize(all_node_num);
+ _succ_num.resize(all_node_num);
+ _last_succ.resize(all_node_num);
+ _state.resize(max_arc_num);
+
+ // Copy the graph
+ int i = 0;
+ for (NodeIt n(_graph); n != INVALID; ++n, ++i) {
+ _node_id[n] = i;
+ }
+ if (_arc_mixing && _node_num > 1) {
+ // Store the arcs in a mixed order
+ const int skip = std::max(_arc_num / _node_num, 3);
+ int i = 0, j = 0;
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ _arc_id[a] = i;
+ _source[i] = _node_id[_graph.source(a)];
+ _target[i] = _node_id[_graph.target(a)];
+ if ((i += skip) >= _arc_num) i = ++j;
+ }
+ } else {
+ // Store the arcs in the original order
+ int i = 0;
+ for (ArcIt a(_graph); a != INVALID; ++a, ++i) {
+ _arc_id[a] = i;
+ _source[i] = _node_id[_graph.source(a)];
+ _target[i] = _node_id[_graph.target(a)];
+ }
+ }
+
+ // Reset parameters
+ resetParams();
+ return *this;
+ }
+
+ /// @}
+
+ /// \name Query Functions
+ /// The results of the algorithm can be obtained using these
+ /// functions.\n
+ /// The \ref run() function must be called before using them.
+
+ /// @{
+
+ /// \brief Return the total cost of the found flow.
+ ///
+ /// This function returns the total cost of the found flow.
+ /// Its complexity is O(m).
+ ///
+ /// \note The return type of the function can be specified as a
+ /// template parameter. For example,
+ /// \code
+ /// ns.totalCost<double>();
+ /// \endcode
+ /// It is useful if the total cost cannot be stored in the \c Cost
+ /// type of the algorithm, which is the default return type of the
+ /// function.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ template <typename Number>
+ Number totalCost() const {
+ Number c = 0;
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ int i = _arc_id[a];
+ c += Number(_flow[i]) * Number(_cost[i]);
+ }
+ return c;
+ }
+
+#ifndef DOXYGEN
+ Cost totalCost() const {
+ return totalCost<Cost>();
+ }
+#endif
+
+ /// \brief Return the flow on the given arc.
+ ///
+ /// This function returns the flow on the given arc.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ Value flow(const Arc& a) const {
+ return _flow[_arc_id[a]];
+ }
+
+ /// \brief Copy the flow values (the primal solution) into the
+ /// given map.
+ ///
+ /// This function copies the flow value on each arc into the given
+ /// map. The \c Value type of the algorithm must be convertible to
+ /// the \c Value type of the map.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ template <typename FlowMap>
+ void flowMap(FlowMap &map) const {
+ for (ArcIt a(_graph); a != INVALID; ++a) {
+ map.set(a, _flow[_arc_id[a]]);
+ }
+ }
+
+ /// \brief Return the potential (dual value) of the given node.
+ ///
+ /// This function returns the potential (dual value) of the
+ /// given node.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ Cost potential(const Node& n) const {
+ return _pi[_node_id[n]];
+ }
+
+ /// \brief Copy the potential values (the dual solution) into the
+ /// given map.
+ ///
+ /// This function copies the potential (dual value) of each node
+ /// into the given map.
+ /// The \c Cost type of the algorithm must be convertible to the
+ /// \c Value type of the map.
+ ///
+ /// \pre \ref run() must be called before using this function.
+ template <typename PotentialMap>
+ void potentialMap(PotentialMap &map) const {
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ map.set(n, _pi[_node_id[n]]);
+ }
+ }
+
+ /// @}
+
+ private:
+
+ // Initialize internal data structures
+ bool init() {
+ if (_node_num == 0) return false;
+
+ // Check the sum of supply values
+ _sum_supply = 0;
+ for (int i = 0; i != _node_num; ++i) {
+ _sum_supply += _supply[i];
+ }
+ if ( !((_stype == GEQ && _sum_supply <= 0) ||
+ (_stype == LEQ && _sum_supply >= 0)) ) return false;
+
+ // Check lower and upper bounds
+ LEMON_DEBUG(checkBoundMaps(),
+ "Upper bounds must be greater or equal to the lower bounds");
+
+ // Remove non-zero lower bounds
+ if (_has_lower) {
+ for (int i = 0; i != _arc_num; ++i) {
+ Value c = _lower[i];
+ if (c >= 0) {
+ _cap[i] = _upper[i] < MAX_VALUE ? _upper[i] - c : INF;
+ } else {
+ _cap[i] = _upper[i] < MAX_VALUE + c ? _upper[i] - c : INF;
+ }
+ _supply[_source[i]] -= c;
+ _supply[_target[i]] += c;
+ }
+ } else {
+ for (int i = 0; i != _arc_num; ++i) {
+ _cap[i] = _upper[i];
+ }
+ }
+
+ // Initialize artifical cost
+ Cost ART_COST;
+ if (std::numeric_limits<Cost>::is_exact) {
+ ART_COST = std::numeric_limits<Cost>::max() / 2 + 1;
+ } else {
+ ART_COST = 0;
+ for (int i = 0; i != _arc_num; ++i) {
+ if (_cost[i] > ART_COST) ART_COST = _cost[i];
+ }
+ ART_COST = (ART_COST + 1) * _node_num;
+ }
+
+ // Initialize arc maps
+ for (int i = 0; i != _arc_num; ++i) {
+ _flow[i] = 0;
+ _state[i] = STATE_LOWER;
+ }
+
+ // Set data for the artificial root node
+ _root = _node_num;
+ _parent[_root] = -1;
+ _pred[_root] = -1;
+ _thread[_root] = 0;
+ _rev_thread[0] = _root;
+ _succ_num[_root] = _node_num + 1;
+ _last_succ[_root] = _root - 1;
+ _supply[_root] = -_sum_supply;
+ _pi[_root] = 0;
+
+ // Add artificial arcs and initialize the spanning tree data structure
+ if (_sum_supply == 0) {
+ // EQ supply constraints
+ _search_arc_num = _arc_num;
+ _all_arc_num = _arc_num + _node_num;
+ for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) {
+ _parent[u] = _root;
+ _pred[u] = e;
+ _thread[u] = u + 1;
+ _rev_thread[u + 1] = u;
+ _succ_num[u] = 1;
+ _last_succ[u] = u;
+ _cap[e] = INF;
+ _state[e] = STATE_TREE;
+ if (_supply[u] >= 0) {
+ _pred_dir[u] = DIR_UP;
+ _pi[u] = 0;
+ _source[e] = u;
+ _target[e] = _root;
+ _flow[e] = _supply[u];
+ _cost[e] = 0;
+ } else {
+ _pred_dir[u] = DIR_DOWN;
+ _pi[u] = ART_COST;
+ _source[e] = _root;
+ _target[e] = u;
+ _flow[e] = -_supply[u];
+ _cost[e] = ART_COST;
+ }
+ }
+ }
+ else if (_sum_supply > 0) {
+ // LEQ supply constraints
+ _search_arc_num = _arc_num + _node_num;
+ int f = _arc_num + _node_num;
+ for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) {
+ _parent[u] = _root;
+ _thread[u] = u + 1;
+ _rev_thread[u + 1] = u;
+ _succ_num[u] = 1;
+ _last_succ[u] = u;
+ if (_supply[u] >= 0) {
+ _pred_dir[u] = DIR_UP;
+ _pi[u] = 0;
+ _pred[u] = e;
+ _source[e] = u;
+ _target[e] = _root;
+ _cap[e] = INF;
+ _flow[e] = _supply[u];
+ _cost[e] = 0;
+ _state[e] = STATE_TREE;
+ } else {
+ _pred_dir[u] = DIR_DOWN;
+ _pi[u] = ART_COST;
+ _pred[u] = f;
+ _source[f] = _root;
+ _target[f] = u;
+ _cap[f] = INF;
+ _flow[f] = -_supply[u];
+ _cost[f] = ART_COST;
+ _state[f] = STATE_TREE;
+ _source[e] = u;
+ _target[e] = _root;
+ _cap[e] = INF;
+ _flow[e] = 0;
+ _cost[e] = 0;
+ _state[e] = STATE_LOWER;
+ ++f;
+ }
+ }
+ _all_arc_num = f;
+ }
+ else {
+ // GEQ supply constraints
+ _search_arc_num = _arc_num + _node_num;
+ int f = _arc_num + _node_num;
+ for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) {
+ _parent[u] = _root;
+ _thread[u] = u + 1;
+ _rev_thread[u + 1] = u;
+ _succ_num[u] = 1;
+ _last_succ[u] = u;
+ if (_supply[u] <= 0) {
+ _pred_dir[u] = DIR_DOWN;
+ _pi[u] = 0;
+ _pred[u] = e;
+ _source[e] = _root;
+ _target[e] = u;
+ _cap[e] = INF;
+ _flow[e] = -_supply[u];
+ _cost[e] = 0;
+ _state[e] = STATE_TREE;
+ } else {
+ _pred_dir[u] = DIR_UP;
+ _pi[u] = -ART_COST;
+ _pred[u] = f;
+ _source[f] = u;
+ _target[f] = _root;
+ _cap[f] = INF;
+ _flow[f] = _supply[u];
+ _state[f] = STATE_TREE;
+ _cost[f] = ART_COST;
+ _source[e] = _root;
+ _target[e] = u;
+ _cap[e] = INF;
+ _flow[e] = 0;
+ _cost[e] = 0;
+ _state[e] = STATE_LOWER;
+ ++f;
+ }
+ }
+ _all_arc_num = f;
+ }
+
+ return true;
+ }
+
+ // Check if the upper bound is greater than or equal to the lower bound
+ // on each arc.
+ bool checkBoundMaps() {
+ for (int j = 0; j != _arc_num; ++j) {
+ if (_upper[j] < _lower[j]) return false;
+ }
+ return true;
+ }
+
+ // Find the join node
+ void findJoinNode() {
+ int u = _source[in_arc];
+ int v = _target[in_arc];
+ while (u != v) {
+ if (_succ_num[u] < _succ_num[v]) {
+ u = _parent[u];
+ } else {
+ v = _parent[v];
+ }
+ }
+ join = u;
+ }
+
+ // Find the leaving arc of the cycle and returns true if the
+ // leaving arc is not the same as the entering arc
+ bool findLeavingArc() {
+ // Initialize first and second nodes according to the direction
+ // of the cycle
+ int first, second;
+ if (_state[in_arc] == STATE_LOWER) {
+ first = _source[in_arc];
+ second = _target[in_arc];
+ } else {
+ first = _target[in_arc];
+ second = _source[in_arc];
+ }
+ delta = _cap[in_arc];
+ int result = 0;
+ Value c, d;
+ int e;
+
+ // Search the cycle form the first node to the join node
+ for (int u = first; u != join; u = _parent[u]) {
+ e = _pred[u];
+ d = _flow[e];
+ if (_pred_dir[u] == DIR_DOWN) {
+ c = _cap[e];
+ d = c >= MAX_VALUE ? INF : c - d;
+ }
+ if (d < delta) {
+ delta = d;
+ u_out = u;
+ result = 1;
+ }
+ }
+
+ // Search the cycle form the second node to the join node
+ for (int u = second; u != join; u = _parent[u]) {
+ e = _pred[u];
+ d = _flow[e];
+ if (_pred_dir[u] == DIR_UP) {
+ c = _cap[e];
+ d = c >= MAX_VALUE ? INF : c - d;
+ }
+ if (d <= delta) {
+ delta = d;
+ u_out = u;
+ result = 2;
+ }
+ }
+
+ if (result == 1) {
+ u_in = first;
+ v_in = second;
+ } else {
+ u_in = second;
+ v_in = first;
+ }
+ return result != 0;
+ }
+
+ // Change _flow and _state vectors
+ void changeFlow(bool change) {
+ // Augment along the cycle
+ if (delta > 0) {
+ Value val = _state[in_arc] * delta;
+ _flow[in_arc] += val;
+ for (int u = _source[in_arc]; u != join; u = _parent[u]) {
+ _flow[_pred[u]] -= _pred_dir[u] * val;
+ }
+ for (int u = _target[in_arc]; u != join; u = _parent[u]) {
+ _flow[_pred[u]] += _pred_dir[u] * val;
+ }
+ }
+ // Update the state of the entering and leaving arcs
+ if (change) {
+ _state[in_arc] = STATE_TREE;
+ _state[_pred[u_out]] =
+ (_flow[_pred[u_out]] == 0) ? STATE_LOWER : STATE_UPPER;
+ } else {
+ _state[in_arc] = -_state[in_arc];
+ }
+ }
+
+ // Update the tree structure
+ void updateTreeStructure() {
+ int old_rev_thread = _rev_thread[u_out];
+ int old_succ_num = _succ_num[u_out];
+ int old_last_succ = _last_succ[u_out];
+ v_out = _parent[u_out];
+
+ // Check if u_in and u_out coincide
+ if (u_in == u_out) {
+ // Update _parent, _pred, _pred_dir
+ _parent[u_in] = v_in;
+ _pred[u_in] = in_arc;
+ _pred_dir[u_in] = u_in == _source[in_arc] ? DIR_UP : DIR_DOWN;
+
+ // Update _thread and _rev_thread
+ if (_thread[v_in] != u_out) {
+ int after = _thread[old_last_succ];
+ _thread[old_rev_thread] = after;
+ _rev_thread[after] = old_rev_thread;
+ after = _thread[v_in];
+ _thread[v_in] = u_out;
+ _rev_thread[u_out] = v_in;
+ _thread[old_last_succ] = after;
+ _rev_thread[after] = old_last_succ;
+ }
+ } else {
+ // Handle the case when old_rev_thread equals to v_in
+ // (it also means that join and v_out coincide)
+ int thread_continue = old_rev_thread == v_in ?
+ _thread[old_last_succ] : _thread[v_in];
+
+ // Update _thread and _parent along the stem nodes (i.e. the nodes
+ // between u_in and u_out, whose parent have to be changed)
+ int stem = u_in; // the current stem node
+ int par_stem = v_in; // the new parent of stem
+ int next_stem; // the next stem node
+ int last = _last_succ[u_in]; // the last successor of stem
+ int before, after = _thread[last];
+ _thread[v_in] = u_in;
+ _dirty_revs.clear();
+ _dirty_revs.push_back(v_in);
+ while (stem != u_out) {
+ // Insert the next stem node into the thread list
+ next_stem = _parent[stem];
+ _thread[last] = next_stem;
+ _dirty_revs.push_back(last);
+
+ // Remove the subtree of stem from the thread list
+ before = _rev_thread[stem];
+ _thread[before] = after;
+ _rev_thread[after] = before;
+
+ // Change the parent node and shift stem nodes
+ _parent[stem] = par_stem;
+ par_stem = stem;
+ stem = next_stem;
+
+ // Update last and after
+ last = _last_succ[stem] == _last_succ[par_stem] ?
+ _rev_thread[par_stem] : _last_succ[stem];
+ after = _thread[last];
+ }
+ _parent[u_out] = par_stem;
+ _thread[last] = thread_continue;
+ _rev_thread[thread_continue] = last;
+ _last_succ[u_out] = last;
+
+ // Remove the subtree of u_out from the thread list except for
+ // the case when old_rev_thread equals to v_in
+ if (old_rev_thread != v_in) {
+ _thread[old_rev_thread] = after;
+ _rev_thread[after] = old_rev_thread;
+ }
+
+ // Update _rev_thread using the new _thread values
+ for (int i = 0; i != int(_dirty_revs.size()); ++i) {
+ int u = _dirty_revs[i];
+ _rev_thread[_thread[u]] = u;
+ }
+
+ // Update _pred, _pred_dir, _last_succ and _succ_num for the
+ // stem nodes from u_out to u_in
+ int tmp_sc = 0, tmp_ls = _last_succ[u_out];
+ for (int u = u_out, p = _parent[u]; u != u_in; u = p, p = _parent[u]) {
+ _pred[u] = _pred[p];
+ _pred_dir[u] = -_pred_dir[p];
+ tmp_sc += _succ_num[u] - _succ_num[p];
+ _succ_num[u] = tmp_sc;
+ _last_succ[p] = tmp_ls;
+ }
+ _pred[u_in] = in_arc;
+ _pred_dir[u_in] = u_in == _source[in_arc] ? DIR_UP : DIR_DOWN;
+ _succ_num[u_in] = old_succ_num;
+ }
+
+ // Update _last_succ from v_in towards the root
+ int up_limit_out = _last_succ[join] == v_in ? join : -1;
+ int last_succ_out = _last_succ[u_out];
+ for (int u = v_in; u != -1 && _last_succ[u] == v_in; u = _parent[u]) {
+ _last_succ[u] = last_succ_out;
+ }
+
+ // Update _last_succ from v_out towards the root
+ if (join != old_rev_thread && v_in != old_rev_thread) {
+ for (int u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ;
+ u = _parent[u]) {
+ _last_succ[u] = old_rev_thread;
+ }
+ }
+ else if (last_succ_out != old_last_succ) {
+ for (int u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ;
+ u = _parent[u]) {
+ _last_succ[u] = last_succ_out;
+ }
+ }
+
+ // Update _succ_num from v_in to join
+ for (int u = v_in; u != join; u = _parent[u]) {
+ _succ_num[u] += old_succ_num;
+ }
+ // Update _succ_num from v_out to join
+ for (int u = v_out; u != join; u = _parent[u]) {
+ _succ_num[u] -= old_succ_num;
+ }
+ }
+
+ // Update potentials in the subtree that has been moved
+ void updatePotential() {
+ Cost sigma = _pi[v_in] - _pi[u_in] -
+ _pred_dir[u_in] * _cost[in_arc];
+ int end = _thread[_last_succ[u_in]];
+ for (int u = u_in; u != end; u = _thread[u]) {
+ _pi[u] += sigma;
+ }
+ }
+
+ // Heuristic initial pivots
+ bool initialPivots() {
+ Value curr, total = 0;
+ std::vector<Node> supply_nodes, demand_nodes;
+ for (NodeIt u(_graph); u != INVALID; ++u) {
+ curr = _supply[_node_id[u]];
+ if (curr > 0) {
+ total += curr;
+ supply_nodes.push_back(u);
+ }
+ else if (curr < 0) {
+ demand_nodes.push_back(u);
+ }
+ }
+ if (_sum_supply > 0) total -= _sum_supply;
+ if (total <= 0) return true;
+
+ IntVector arc_vector;
+ if (_sum_supply >= 0) {
+ if (supply_nodes.size() == 1 && demand_nodes.size() == 1) {
+ // Perform a reverse graph search from the sink to the source
+ typename GR::template NodeMap<bool> reached(_graph, false);
+ Node s = supply_nodes[0], t = demand_nodes[0];
+ std::vector<Node> stack;
+ reached[t] = true;
+ stack.push_back(t);
+ while (!stack.empty()) {
+ Node u, v = stack.back();
+ stack.pop_back();
+ if (v == s) break;
+ for (InArcIt a(_graph, v); a != INVALID; ++a) {
+ if (reached[u = _graph.source(a)]) continue;
+ int j = _arc_id[a];
+ if (_cap[j] >= total) {
+ arc_vector.push_back(j);
+ reached[u] = true;
+ stack.push_back(u);
+ }
+ }
+ }
+ } else {
+ // Find the min. cost incoming arc for each demand node
+ for (int i = 0; i != int(demand_nodes.size()); ++i) {
+ Node v = demand_nodes[i];
+ Cost c, min_cost = std::numeric_limits<Cost>::max();
+ Arc min_arc = INVALID;
+ for (InArcIt a(_graph, v); a != INVALID; ++a) {
+ c = _cost[_arc_id[a]];
+ if (c < min_cost) {
+ min_cost = c;
+ min_arc = a;
+ }
+ }
+ if (min_arc != INVALID) {
+ arc_vector.push_back(_arc_id[min_arc]);
+ }
+ }
+ }
+ } else {
+ // Find the min. cost outgoing arc for each supply node
+ for (int i = 0; i != int(supply_nodes.size()); ++i) {
+ Node u = supply_nodes[i];
+ Cost c, min_cost = std::numeric_limits<Cost>::max();
+ Arc min_arc = INVALID;
+ for (OutArcIt a(_graph, u); a != INVALID; ++a) {
+ c = _cost[_arc_id[a]];
+ if (c < min_cost) {
+ min_cost = c;
+ min_arc = a;
+ }
+ }
+ if (min_arc != INVALID) {
+ arc_vector.push_back(_arc_id[min_arc]);
+ }
+ }
+ }
+
+ // Perform heuristic initial pivots
+ for (int i = 0; i != int(arc_vector.size()); ++i) {
+ in_arc = arc_vector[i];
+ if (_state[in_arc] * (_cost[in_arc] + _pi[_source[in_arc]] -
+ _pi[_target[in_arc]]) >= 0) continue;
+ findJoinNode();
+ bool change = findLeavingArc();
+ if (delta >= MAX_VALUE) return false;
+ changeFlow(change);
+ if (change) {
+ updateTreeStructure();
+ updatePotential();
+ }
+ }
+ return true;
+ }
+
+ // Execute the algorithm
+ ProblemType start(PivotRule pivot_rule) {
+ // Select the pivot rule implementation
+ switch (pivot_rule) {
+ case FIRST_ELIGIBLE:
+ return start<FirstEligiblePivotRule>();
+ case BEST_ELIGIBLE:
+ return start<BestEligiblePivotRule>();
+ case BLOCK_SEARCH:
+ return start<BlockSearchPivotRule>();
+ case CANDIDATE_LIST:
+ return start<CandidateListPivotRule>();
+ case ALTERING_LIST:
+ return start<AlteringListPivotRule>();
+ }
+ return INFEASIBLE; // avoid warning
+ }
+
+ template <typename PivotRuleImpl>
+ ProblemType start() {
+ PivotRuleImpl pivot(*this);
+
+ // Perform heuristic initial pivots
+ if (!initialPivots()) return UNBOUNDED;
+
+ // Execute the Network Simplex algorithm
+ while (pivot.findEnteringArc()) {
+ findJoinNode();
+ bool change = findLeavingArc();
+ if (delta >= MAX_VALUE) return UNBOUNDED;
+ changeFlow(change);
+ if (change) {
+ updateTreeStructure();
+ updatePotential();
+ }
+ }
+
+ // Check feasibility
+ for (int e = _search_arc_num; e != _all_arc_num; ++e) {
+ if (_flow[e] != 0) return INFEASIBLE;
+ }
+
+ // Transform the solution and the supply map to the original form
+ if (_has_lower) {
+ for (int i = 0; i != _arc_num; ++i) {
+ Value c = _lower[i];
+ if (c != 0) {
+ _flow[i] += c;
+ _supply[_source[i]] += c;
+ _supply[_target[i]] -= c;
+ }
+ }
+ }
+
+ // Shift potentials to meet the requirements of the GEQ/LEQ type
+ // optimality conditions
+ if (_sum_supply == 0) {
+ if (_stype == GEQ) {
+ Cost max_pot = -std::numeric_limits<Cost>::max();
+ for (int i = 0; i != _node_num; ++i) {
+ if (_pi[i] > max_pot) max_pot = _pi[i];
+ }
+ if (max_pot > 0) {
+ for (int i = 0; i != _node_num; ++i)
+ _pi[i] -= max_pot;
+ }
+ } else {
+ Cost min_pot = std::numeric_limits<Cost>::max();
+ for (int i = 0; i != _node_num; ++i) {
+ if (_pi[i] < min_pot) min_pot = _pi[i];
+ }
+ if (min_pot < 0) {
+ for (int i = 0; i != _node_num; ++i)
+ _pi[i] -= min_pot;
+ }
+ }
+ }
+
+ return OPTIMAL;
+ }
+
+ }; //class NetworkSimplex
+
+ ///@}
+
+} //namespace lemon
+
+#endif //LEMON_NETWORK_SIMPLEX_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/opt2_tsp.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/opt2_tsp.h
new file mode 100644
index 00000000000..686cc9cb89d
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/opt2_tsp.h
@@ -0,0 +1,367 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_OPT2_TSP_H
+#define LEMON_OPT2_TSP_H
+
+/// \ingroup tsp
+/// \file
+/// \brief 2-opt algorithm for symmetric TSP.
+
+#include <vector>
+#include <lemon/full_graph.h>
+
+namespace lemon {
+
+ /// \ingroup tsp
+ ///
+ /// \brief 2-opt algorithm for symmetric TSP.
+ ///
+ /// Opt2Tsp implements the 2-opt heuristic for solving
+ /// symmetric \ref tsp "TSP".
+ ///
+ /// This algorithm starts with an initial tour and iteratively improves it.
+ /// At each step, it removes two edges and the reconnects the created two
+ /// paths in the other way if the resulting tour is shorter.
+ /// The algorithm finishes when no such 2-opt move can be applied, and so
+ /// the tour is 2-optimal.
+ ///
+ /// If no starting tour is given to the \ref run() function, then the
+ /// algorithm uses the node sequence determined by the node IDs.
+ /// Oherwise, it starts with the given tour.
+ ///
+ /// This is a rather slow but effective method.
+ /// Its typical usage is the improvement of the result of a fast tour
+ /// construction heuristic (e.g. the InsertionTsp algorithm).
+ ///
+ /// \tparam CM Type of the cost map.
+ template <typename CM>
+ class Opt2Tsp
+ {
+ public:
+
+ /// Type of the cost map
+ typedef CM CostMap;
+ /// Type of the edge costs
+ typedef typename CM::Value Cost;
+
+ private:
+
+ GRAPH_TYPEDEFS(FullGraph);
+
+ const FullGraph &_gr;
+ const CostMap &_cost;
+ Cost _sum;
+ std::vector<int> _plist;
+ std::vector<Node> _path;
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ /// \param gr The \ref FullGraph "full graph" the algorithm runs on.
+ /// \param cost The cost map.
+ Opt2Tsp(const FullGraph &gr, const CostMap &cost)
+ : _gr(gr), _cost(cost) {}
+
+ /// \name Execution Control
+ /// @{
+
+ /// \brief Runs the algorithm from scratch.
+ ///
+ /// This function runs the algorithm starting from the tour that is
+ /// determined by the node ID sequence.
+ ///
+ /// \return The total cost of the found tour.
+ Cost run() {
+ _path.clear();
+
+ if (_gr.nodeNum() == 0) return _sum = 0;
+ else if (_gr.nodeNum() == 1) {
+ _path.push_back(_gr(0));
+ return _sum = 0;
+ }
+ else if (_gr.nodeNum() == 2) {
+ _path.push_back(_gr(0));
+ _path.push_back(_gr(1));
+ return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))];
+ }
+
+ _plist.resize(2*_gr.nodeNum());
+ for (int i = 1; i < _gr.nodeNum()-1; ++i) {
+ _plist[2*i] = i-1;
+ _plist[2*i+1] = i+1;
+ }
+ _plist[0] = _gr.nodeNum()-1;
+ _plist[1] = 1;
+ _plist[2*_gr.nodeNum()-2] = _gr.nodeNum()-2;
+ _plist[2*_gr.nodeNum()-1] = 0;
+
+ return start();
+ }
+
+ /// \brief Runs the algorithm starting from the given tour.
+ ///
+ /// This function runs the algorithm starting from the given tour.
+ ///
+ /// \param tour The tour as a path structure. It must be a
+ /// \ref checkPath() "valid path" containing excactly n arcs.
+ ///
+ /// \return The total cost of the found tour.
+ template <typename Path>
+ Cost run(const Path& tour) {
+ _path.clear();
+
+ if (_gr.nodeNum() == 0) return _sum = 0;
+ else if (_gr.nodeNum() == 1) {
+ _path.push_back(_gr(0));
+ return _sum = 0;
+ }
+ else if (_gr.nodeNum() == 2) {
+ _path.push_back(_gr(0));
+ _path.push_back(_gr(1));
+ return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))];
+ }
+
+ _plist.resize(2*_gr.nodeNum());
+ typename Path::ArcIt it(tour);
+ int first = _gr.id(_gr.source(it)),
+ prev = first,
+ curr = _gr.id(_gr.target(it)),
+ next = -1;
+ _plist[2*first+1] = curr;
+ for (++it; it != INVALID; ++it) {
+ next = _gr.id(_gr.target(it));
+ _plist[2*curr] = prev;
+ _plist[2*curr+1] = next;
+ prev = curr;
+ curr = next;
+ }
+ _plist[2*first] = prev;
+
+ return start();
+ }
+
+ /// \brief Runs the algorithm starting from the given tour.
+ ///
+ /// This function runs the algorithm starting from the given tour
+ /// (node sequence).
+ ///
+ /// \param tour A vector that stores all <tt>Node</tt>s of the graph
+ /// in the desired order.
+ ///
+ /// \return The total cost of the found tour.
+ Cost run(const std::vector<Node>& tour) {
+ _path.clear();
+
+ if (_gr.nodeNum() == 0) return _sum = 0;
+ else if (_gr.nodeNum() == 1) {
+ _path.push_back(_gr(0));
+ return _sum = 0;
+ }
+ else if (_gr.nodeNum() == 2) {
+ _path.push_back(_gr(0));
+ _path.push_back(_gr(1));
+ return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))];
+ }
+
+ _plist.resize(2*_gr.nodeNum());
+ typename std::vector<Node>::const_iterator it = tour.begin();
+ int first = _gr.id(*it),
+ prev = first,
+ curr = _gr.id(*(++it)),
+ next = -1;
+ _plist[2*first+1] = curr;
+ for (++it; it != tour.end(); ++it) {
+ next = _gr.id(*it);
+ _plist[2*curr] = prev;
+ _plist[2*curr+1] = next;
+ prev = curr;
+ curr = next;
+ }
+ _plist[2*first] = curr;
+ _plist[2*curr] = prev;
+ _plist[2*curr+1] = first;
+
+ return start();
+ }
+
+ /// @}
+
+ /// \name Query Functions
+ /// @{
+
+ /// \brief The total cost of the found tour.
+ ///
+ /// This function returns the total cost of the found tour.
+ ///
+ /// \pre run() must be called before using this function.
+ Cost tourCost() const {
+ return _sum;
+ }
+
+ /// \brief Returns a const reference to the node sequence of the
+ /// found tour.
+ ///
+ /// This function returns a const reference to a vector
+ /// that stores the node sequence of the found tour.
+ ///
+ /// \pre run() must be called before using this function.
+ const std::vector<Node>& tourNodes() const {
+ return _path;
+ }
+
+ /// \brief Gives back the node sequence of the found tour.
+ ///
+ /// This function copies the node sequence of the found tour into
+ /// an STL container through the given output iterator. The
+ /// <tt>value_type</tt> of the container must be <tt>FullGraph::Node</tt>.
+ /// For example,
+ /// \code
+ /// std::vector<FullGraph::Node> nodes(countNodes(graph));
+ /// tsp.tourNodes(nodes.begin());
+ /// \endcode
+ /// or
+ /// \code
+ /// std::list<FullGraph::Node> nodes;
+ /// tsp.tourNodes(std::back_inserter(nodes));
+ /// \endcode
+ ///
+ /// \pre run() must be called before using this function.
+ template <typename Iterator>
+ void tourNodes(Iterator out) const {
+ std::copy(_path.begin(), _path.end(), out);
+ }
+
+ /// \brief Gives back the found tour as a path.
+ ///
+ /// This function copies the found tour as a list of arcs/edges into
+ /// the given \ref lemon::concepts::Path "path structure".
+ ///
+ /// \pre run() must be called before using this function.
+ template <typename Path>
+ void tour(Path &path) const {
+ path.clear();
+ for (int i = 0; i < int(_path.size()) - 1; ++i) {
+ path.addBack(_gr.arc(_path[i], _path[i+1]));
+ }
+ if (int(_path.size()) >= 2) {
+ path.addBack(_gr.arc(_path.back(), _path.front()));
+ }
+ }
+
+ /// @}
+
+ private:
+
+ // Iterator class for the linked list storage of the tour
+ class PathListIt {
+ public:
+ PathListIt(const std::vector<int> &pl, int i=0)
+ : plist(&pl), act(i), last(pl[2*act]) {}
+ PathListIt(const std::vector<int> &pl, int i, int l)
+ : plist(&pl), act(i), last(l) {}
+
+ int nextIndex() const {
+ return (*plist)[2*act] == last ? 2*act+1 : 2*act;
+ }
+
+ int prevIndex() const {
+ return (*plist)[2*act] == last ? 2*act : 2*act+1;
+ }
+
+ int next() const {
+ int x = (*plist)[2*act];
+ return x == last ? (*plist)[2*act+1] : x;
+ }
+
+ int prev() const {
+ return last;
+ }
+
+ PathListIt& operator++() {
+ int tmp = act;
+ act = next();
+ last = tmp;
+ return *this;
+ }
+
+ operator int() const {
+ return act;
+ }
+
+ private:
+ const std::vector<int> *plist;
+ int act;
+ int last;
+ };
+
+ // Checks and applies 2-opt move (if it improves the tour)
+ bool checkOpt2(const PathListIt& i, const PathListIt& j) {
+ Node u = _gr.nodeFromId(i),
+ un = _gr.nodeFromId(i.next()),
+ v = _gr.nodeFromId(j),
+ vn = _gr.nodeFromId(j.next());
+
+ if (_cost[_gr.edge(u, un)] + _cost[_gr.edge(v, vn)] >
+ _cost[_gr.edge(u, v)] + _cost[_gr.edge(un, vn)])
+ {
+ _plist[PathListIt(_plist, i.next(), i).prevIndex()] = j.next();
+ _plist[PathListIt(_plist, j.next(), j).prevIndex()] = i.next();
+
+ _plist[i.nextIndex()] = j;
+ _plist[j.nextIndex()] = i;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ // Executes the algorithm from the initial tour
+ Cost start() {
+
+ restart_search:
+ for (PathListIt i(_plist); true; ++i) {
+ PathListIt j = i;
+ if (++j == 0 || ++j == 0) break;
+ for (; j != 0 && j != i.prev(); ++j) {
+ if (checkOpt2(i, j))
+ goto restart_search;
+ }
+ }
+
+ PathListIt i(_plist);
+ _path.push_back(_gr.nodeFromId(i));
+ for (++i; i != 0; ++i)
+ _path.push_back(_gr.nodeFromId(i));
+
+ _sum = _cost[_gr.edge(_path.back(), _path.front())];
+ for (int i = 0; i < int(_path.size())-1; ++i) {
+ _sum += _cost[_gr.edge(_path[i], _path[i+1])];
+ }
+
+ return _sum;
+ }
+
+ };
+
+}; // namespace lemon
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/pairing_heap.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/pairing_heap.h
new file mode 100644
index 00000000000..da6ebcb1552
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/pairing_heap.h
@@ -0,0 +1,474 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_PAIRING_HEAP_H
+#define LEMON_PAIRING_HEAP_H
+
+///\file
+///\ingroup heaps
+///\brief Pairing heap implementation.
+
+#include <vector>
+#include <utility>
+#include <functional>
+#include <lemon/math.h>
+
+namespace lemon {
+
+ /// \ingroup heaps
+ ///
+ ///\brief Pairing Heap.
+ ///
+ /// This class implements the \e pairing \e heap data structure.
+ /// It fully conforms to the \ref concepts::Heap "heap concept".
+ ///
+ /// The methods \ref increase() and \ref erase() are not efficient
+ /// in a pairing heap. In case of many calls of these operations,
+ /// it is better to use other heap structure, e.g. \ref BinHeap
+ /// "binary heap".
+ ///
+ /// \tparam PR Type of the priorities of the items.
+ /// \tparam IM A read-writable item map with \c int values, used
+ /// internally to handle the cross references.
+ /// \tparam CMP A functor class for comparing the priorities.
+ /// The default is \c std::less<PR>.
+#ifdef DOXYGEN
+ template <typename PR, typename IM, typename CMP>
+#else
+ template <typename PR, typename IM, typename CMP = std::less<PR> >
+#endif
+ class PairingHeap {
+ public:
+ /// Type of the item-int map.
+ typedef IM ItemIntMap;
+ /// Type of the priorities.
+ typedef PR Prio;
+ /// Type of the items stored in the heap.
+ typedef typename ItemIntMap::Key Item;
+ /// Functor type for comparing the priorities.
+ typedef CMP Compare;
+
+ /// \brief Type to represent the states of the items.
+ ///
+ /// Each item has a state associated to it. It can be "in heap",
+ /// "pre-heap" or "post-heap". The latter two are indifferent from the
+ /// heap's point of view, but may be useful to the user.
+ ///
+ /// The item-int map must be initialized in such way that it assigns
+ /// \c PRE_HEAP (<tt>-1</tt>) to any element to be put in the heap.
+ enum State {
+ IN_HEAP = 0, ///< = 0.
+ PRE_HEAP = -1, ///< = -1.
+ POST_HEAP = -2 ///< = -2.
+ };
+
+ private:
+ class store;
+
+ std::vector<store> _data;
+ int _min;
+ ItemIntMap &_iim;
+ Compare _comp;
+ int _num_items;
+
+ public:
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ /// \param map A map that assigns \c int values to the items.
+ /// It is used internally to handle the cross references.
+ /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
+ explicit PairingHeap(ItemIntMap &map)
+ : _min(0), _iim(map), _num_items(0) {}
+
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ /// \param map A map that assigns \c int values to the items.
+ /// It is used internally to handle the cross references.
+ /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
+ /// \param comp The function object used for comparing the priorities.
+ PairingHeap(ItemIntMap &map, const Compare &comp)
+ : _min(0), _iim(map), _comp(comp), _num_items(0) {}
+
+ /// \brief The number of items stored in the heap.
+ ///
+ /// This function returns the number of items stored in the heap.
+ int size() const { return _num_items; }
+
+ /// \brief Check if the heap is empty.
+ ///
+ /// This function returns \c true if the heap is empty.
+ bool empty() const { return _num_items==0; }
+
+ /// \brief Make the heap empty.
+ ///
+ /// This functon makes the heap empty.
+ /// It does not change the cross reference map. If you want to reuse
+ /// a heap that is not surely empty, you should first clear it and
+ /// then you should set the cross reference map to \c PRE_HEAP
+ /// for each item.
+ void clear() {
+ _data.clear();
+ _min = 0;
+ _num_items = 0;
+ }
+
+ /// \brief Set the priority of an item or insert it, if it is
+ /// not stored in the heap.
+ ///
+ /// This method sets the priority of the given item if it is
+ /// already stored in the heap. Otherwise it inserts the given
+ /// item into the heap with the given priority.
+ /// \param item The item.
+ /// \param value The priority.
+ void set (const Item& item, const Prio& value) {
+ int i=_iim[item];
+ if ( i>=0 && _data[i].in ) {
+ if ( _comp(value, _data[i].prio) ) decrease(item, value);
+ if ( _comp(_data[i].prio, value) ) increase(item, value);
+ } else push(item, value);
+ }
+
+ /// \brief Insert an item into the heap with the given priority.
+ ///
+ /// This function inserts the given item into the heap with the
+ /// given priority.
+ /// \param item The item to insert.
+ /// \param value The priority of the item.
+ /// \pre \e item must not be stored in the heap.
+ void push (const Item& item, const Prio& value) {
+ int i=_iim[item];
+ if( i<0 ) {
+ int s=_data.size();
+ _iim.set(item, s);
+ store st;
+ st.name=item;
+ _data.push_back(st);
+ i=s;
+ } else {
+ _data[i].parent=_data[i].child=-1;
+ _data[i].left_child=false;
+ _data[i].degree=0;
+ _data[i].in=true;
+ }
+
+ _data[i].prio=value;
+
+ if ( _num_items!=0 ) {
+ if ( _comp( value, _data[_min].prio) ) {
+ fuse(i,_min);
+ _min=i;
+ }
+ else fuse(_min,i);
+ }
+ else _min=i;
+
+ ++_num_items;
+ }
+
+ /// \brief Return the item having minimum priority.
+ ///
+ /// This function returns the item having minimum priority.
+ /// \pre The heap must be non-empty.
+ Item top() const { return _data[_min].name; }
+
+ /// \brief The minimum priority.
+ ///
+ /// This function returns the minimum priority.
+ /// \pre The heap must be non-empty.
+ const Prio& prio() const { return _data[_min].prio; }
+
+ /// \brief The priority of the given item.
+ ///
+ /// This function returns the priority of the given item.
+ /// \param item The item.
+ /// \pre \e item must be in the heap.
+ const Prio& operator[](const Item& item) const {
+ return _data[_iim[item]].prio;
+ }
+
+ /// \brief Remove the item having minimum priority.
+ ///
+ /// This function removes the item having minimum priority.
+ /// \pre The heap must be non-empty.
+ void pop() {
+ std::vector<int> trees;
+ int i=0, child_right = 0;
+ _data[_min].in=false;
+
+ if( -1!=_data[_min].child ) {
+ i=_data[_min].child;
+ trees.push_back(i);
+ _data[i].parent = -1;
+ _data[_min].child = -1;
+
+ int ch=-1;
+ while( _data[i].child!=-1 ) {
+ ch=_data[i].child;
+ if( _data[ch].left_child && i==_data[ch].parent ) {
+ break;
+ } else {
+ if( _data[ch].left_child ) {
+ child_right=_data[ch].parent;
+ _data[ch].parent = i;
+ --_data[i].degree;
+ }
+ else {
+ child_right=ch;
+ _data[i].child=-1;
+ _data[i].degree=0;
+ }
+ _data[child_right].parent = -1;
+ trees.push_back(child_right);
+ i = child_right;
+ }
+ }
+
+ int num_child = trees.size();
+ int other;
+ for( i=0; i<num_child-1; i+=2 ) {
+ if ( !_comp(_data[trees[i]].prio, _data[trees[i+1]].prio) ) {
+ other=trees[i];
+ trees[i]=trees[i+1];
+ trees[i+1]=other;
+ }
+ fuse( trees[i], trees[i+1] );
+ }
+
+ i = (0==(num_child % 2)) ? num_child-2 : num_child-1;
+ while(i>=2) {
+ if ( _comp(_data[trees[i]].prio, _data[trees[i-2]].prio) ) {
+ other=trees[i];
+ trees[i]=trees[i-2];
+ trees[i-2]=other;
+ }
+ fuse( trees[i-2], trees[i] );
+ i-=2;
+ }
+ _min = trees[0];
+ }
+ else {
+ _min = _data[_min].child;
+ }
+
+ if (_min >= 0) _data[_min].left_child = false;
+ --_num_items;
+ }
+
+ /// \brief Remove the given item from the heap.
+ ///
+ /// This function removes the given item from the heap if it is
+ /// already stored.
+ /// \param item The item to delete.
+ /// \pre \e item must be in the heap.
+ void erase (const Item& item) {
+ int i=_iim[item];
+ if ( i>=0 && _data[i].in ) {
+ decrease( item, _data[_min].prio-1 );
+ pop();
+ }
+ }
+
+ /// \brief Decrease the priority of an item to the given value.
+ ///
+ /// This function decreases the priority of an item to the given value.
+ /// \param item The item.
+ /// \param value The priority.
+ /// \pre \e item must be stored in the heap with priority at least \e value.
+ void decrease (Item item, const Prio& value) {
+ int i=_iim[item];
+ _data[i].prio=value;
+ int p=_data[i].parent;
+
+ if( _data[i].left_child && i!=_data[p].child ) {
+ p=_data[p].parent;
+ }
+
+ if ( p!=-1 && _comp(value,_data[p].prio) ) {
+ cut(i,p);
+ if ( _comp(_data[_min].prio,value) ) {
+ fuse(_min,i);
+ } else {
+ fuse(i,_min);
+ _min=i;
+ }
+ }
+ }
+
+ /// \brief Increase the priority of an item to the given value.
+ ///
+ /// This function increases the priority of an item to the given value.
+ /// \param item The item.
+ /// \param value The priority.
+ /// \pre \e item must be stored in the heap with priority at most \e value.
+ void increase (Item item, const Prio& value) {
+ erase(item);
+ push(item,value);
+ }
+
+ /// \brief Return the state of an item.
+ ///
+ /// This method returns \c PRE_HEAP if the given item has never
+ /// been in the heap, \c IN_HEAP if it is in the heap at the moment,
+ /// and \c POST_HEAP otherwise.
+ /// In the latter case it is possible that the item will get back
+ /// to the heap again.
+ /// \param item The item.
+ State state(const Item &item) const {
+ int i=_iim[item];
+ if( i>=0 ) {
+ if( _data[i].in ) i=0;
+ else i=-2;
+ }
+ return State(i);
+ }
+
+ /// \brief Set the state of an item in the heap.
+ ///
+ /// This function sets the state of the given item in the heap.
+ /// It can be used to manually clear the heap when it is important
+ /// to achive better time complexity.
+ /// \param i The item.
+ /// \param st The state. It should not be \c IN_HEAP.
+ void state(const Item& i, State st) {
+ switch (st) {
+ case POST_HEAP:
+ case PRE_HEAP:
+ if (state(i) == IN_HEAP) erase(i);
+ _iim[i]=st;
+ break;
+ case IN_HEAP:
+ break;
+ }
+ }
+
+ private:
+
+ void cut(int a, int b) {
+ int child_a;
+ switch (_data[a].degree) {
+ case 2:
+ child_a = _data[_data[a].child].parent;
+ if( _data[a].left_child ) {
+ _data[child_a].left_child=true;
+ _data[b].child=child_a;
+ _data[child_a].parent=_data[a].parent;
+ }
+ else {
+ _data[child_a].left_child=false;
+ _data[child_a].parent=b;
+ if( a!=_data[b].child )
+ _data[_data[b].child].parent=child_a;
+ else
+ _data[b].child=child_a;
+ }
+ --_data[a].degree;
+ _data[_data[a].child].parent=a;
+ break;
+
+ case 1:
+ child_a = _data[a].child;
+ if( !_data[child_a].left_child ) {
+ --_data[a].degree;
+ if( _data[a].left_child ) {
+ _data[child_a].left_child=true;
+ _data[child_a].parent=_data[a].parent;
+ _data[b].child=child_a;
+ }
+ else {
+ _data[child_a].left_child=false;
+ _data[child_a].parent=b;
+ if( a!=_data[b].child )
+ _data[_data[b].child].parent=child_a;
+ else
+ _data[b].child=child_a;
+ }
+ _data[a].child=-1;
+ }
+ else {
+ --_data[b].degree;
+ if( _data[a].left_child ) {
+ _data[b].child =
+ (1==_data[b].degree) ? _data[a].parent : -1;
+ } else {
+ if (1==_data[b].degree)
+ _data[_data[b].child].parent=b;
+ else
+ _data[b].child=-1;
+ }
+ }
+ break;
+
+ case 0:
+ --_data[b].degree;
+ if( _data[a].left_child ) {
+ _data[b].child =
+ (0!=_data[b].degree) ? _data[a].parent : -1;
+ } else {
+ if( 0!=_data[b].degree )
+ _data[_data[b].child].parent=b;
+ else
+ _data[b].child=-1;
+ }
+ break;
+ }
+ _data[a].parent=-1;
+ _data[a].left_child=false;
+ }
+
+ void fuse(int a, int b) {
+ int child_a = _data[a].child;
+ int child_b = _data[b].child;
+ _data[a].child=b;
+ _data[b].parent=a;
+ _data[b].left_child=true;
+
+ if( -1!=child_a ) {
+ _data[b].child=child_a;
+ _data[child_a].parent=b;
+ _data[child_a].left_child=false;
+ ++_data[b].degree;
+
+ if( -1!=child_b ) {
+ _data[b].child=child_b;
+ _data[child_b].parent=child_a;
+ }
+ }
+ else { ++_data[a].degree; }
+ }
+
+ class store {
+ friend class PairingHeap;
+
+ Item name;
+ int parent;
+ int child;
+ bool left_child;
+ int degree;
+ bool in;
+ Prio prio;
+
+ store() : parent(-1), child(-1), left_child(false), degree(0), in(true) {}
+ };
+ };
+
+} //namespace lemon
+
+#endif //LEMON_PAIRING_HEAP_H
+
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/path.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/path.h
new file mode 100644
index 00000000000..baa92c48baa
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/path.h
@@ -0,0 +1,1164 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+///\ingroup paths
+///\file
+///\brief Classes for representing paths in digraphs.
+///
+
+#ifndef LEMON_PATH_H
+#define LEMON_PATH_H
+
+#include <vector>
+#include <algorithm>
+
+#include <lemon/error.h>
+#include <lemon/core.h>
+#include <lemon/concepts/path.h>
+
+namespace lemon {
+
+ /// \addtogroup paths
+ /// @{
+
+
+ /// \brief A structure for representing directed paths in a digraph.
+ ///
+ /// A structure for representing directed path in a digraph.
+ /// \tparam GR The digraph type in which the path is.
+ ///
+ /// In a sense, the path can be treated as a list of arcs. The
+ /// LEMON path type stores just this list. As a consequence, it
+ /// cannot enumerate the nodes of the path and the source node of
+ /// a zero length path is undefined.
+ ///
+ /// This implementation is a back and front insertable and erasable
+ /// path type. It can be indexed in O(1) time. The front and back
+ /// insertion and erase is done in O(1) (amortized) time. The
+ /// implementation uses two vectors for storing the front and back
+ /// insertions.
+ template <typename GR>
+ class Path {
+ public:
+
+ typedef GR Digraph;
+ typedef typename Digraph::Arc Arc;
+
+ /// \brief Default constructor
+ ///
+ /// Default constructor
+ Path() {}
+
+ /// \brief Copy constructor
+ ///
+ Path(const Path& cpath) {
+ pathCopy(cpath, *this);
+ }
+
+ /// \brief Template copy constructor
+ ///
+ /// This constuctor initializes the path from any other path type.
+ /// It simply makes a copy of the given path.
+ template <typename CPath>
+ Path(const CPath& cpath) {
+ pathCopy(cpath, *this);
+ }
+
+ /// \brief Copy assignment
+ ///
+ Path& operator=(const Path& cpath) {
+ pathCopy(cpath, *this);
+ return *this;
+ }
+
+ /// \brief Template copy assignment
+ ///
+ /// This operator makes a copy of a path of any other type.
+ template <typename CPath>
+ Path& operator=(const CPath& cpath) {
+ pathCopy(cpath, *this);
+ return *this;
+ }
+
+ /// \brief LEMON style iterator for path arcs
+ ///
+ /// This class is used to iterate on the arcs of the paths.
+ class ArcIt {
+ friend class Path;
+ public:
+ /// \brief Default constructor
+ ArcIt() {}
+ /// \brief Invalid constructor
+ ArcIt(Invalid) : path(0), idx(-1) {}
+ /// \brief Initializate the iterator to the first arc of path
+ ArcIt(const Path &_path)
+ : path(&_path), idx(_path.empty() ? -1 : 0) {}
+
+ private:
+
+ ArcIt(const Path &_path, int _idx)
+ : path(&_path), idx(_idx) {}
+
+ public:
+
+ /// \brief Conversion to Arc
+ operator const Arc&() const {
+ return path->nth(idx);
+ }
+
+ /// \brief Next arc
+ ArcIt& operator++() {
+ ++idx;
+ if (idx >= path->length()) idx = -1;
+ return *this;
+ }
+
+ /// \brief Comparison operator
+ bool operator==(const ArcIt& e) const { return idx==e.idx; }
+ /// \brief Comparison operator
+ bool operator!=(const ArcIt& e) const { return idx!=e.idx; }
+ /// \brief Comparison operator
+ bool operator<(const ArcIt& e) const { return idx<e.idx; }
+
+ private:
+ const Path *path;
+ int idx;
+ };
+
+ /// \brief Length of the path.
+ int length() const { return head.size() + tail.size(); }
+ /// \brief Return whether the path is empty.
+ bool empty() const { return head.empty() && tail.empty(); }
+
+ /// \brief Reset the path to an empty one.
+ void clear() { head.clear(); tail.clear(); }
+
+ /// \brief The n-th arc.
+ ///
+ /// \pre \c n is in the <tt>[0..length() - 1]</tt> range.
+ const Arc& nth(int n) const {
+ return n < int(head.size()) ? *(head.rbegin() + n) :
+ *(tail.begin() + (n - head.size()));
+ }
+
+ /// \brief Initialize arc iterator to point to the n-th arc
+ ///
+ /// \pre \c n is in the <tt>[0..length() - 1]</tt> range.
+ ArcIt nthIt(int n) const {
+ return ArcIt(*this, n);
+ }
+
+ /// \brief The first arc of the path
+ const Arc& front() const {
+ return head.empty() ? tail.front() : head.back();
+ }
+
+ /// \brief Add a new arc before the current path
+ void addFront(const Arc& arc) {
+ head.push_back(arc);
+ }
+
+ /// \brief Erase the first arc of the path
+ void eraseFront() {
+ if (!head.empty()) {
+ head.pop_back();
+ } else {
+ head.clear();
+ int halfsize = tail.size() / 2;
+ head.resize(halfsize);
+ std::copy(tail.begin() + 1, tail.begin() + halfsize + 1,
+ head.rbegin());
+ std::copy(tail.begin() + halfsize + 1, tail.end(), tail.begin());
+ tail.resize(tail.size() - halfsize - 1);
+ }
+ }
+
+ /// \brief The last arc of the path
+ const Arc& back() const {
+ return tail.empty() ? head.front() : tail.back();
+ }
+
+ /// \brief Add a new arc behind the current path
+ void addBack(const Arc& arc) {
+ tail.push_back(arc);
+ }
+
+ /// \brief Erase the last arc of the path
+ void eraseBack() {
+ if (!tail.empty()) {
+ tail.pop_back();
+ } else {
+ int halfsize = head.size() / 2;
+ tail.resize(halfsize);
+ std::copy(head.begin() + 1, head.begin() + halfsize + 1,
+ tail.rbegin());
+ std::copy(head.begin() + halfsize + 1, head.end(), head.begin());
+ head.resize(head.size() - halfsize - 1);
+ }
+ }
+
+ typedef True BuildTag;
+
+ template <typename CPath>
+ void build(const CPath& path) {
+ int len = path.length();
+ tail.reserve(len);
+ for (typename CPath::ArcIt it(path); it != INVALID; ++it) {
+ tail.push_back(it);
+ }
+ }
+
+ template <typename CPath>
+ void buildRev(const CPath& path) {
+ int len = path.length();
+ head.reserve(len);
+ for (typename CPath::RevArcIt it(path); it != INVALID; ++it) {
+ head.push_back(it);
+ }
+ }
+
+ protected:
+ typedef std::vector<Arc> Container;
+ Container head, tail;
+
+ };
+
+ /// \brief A structure for representing directed paths in a digraph.
+ ///
+ /// A structure for representing directed path in a digraph.
+ /// \tparam GR The digraph type in which the path is.
+ ///
+ /// In a sense, the path can be treated as a list of arcs. The
+ /// LEMON path type stores just this list. As a consequence it
+ /// cannot enumerate the nodes in the path and the zero length paths
+ /// cannot store the source.
+ ///
+ /// This implementation is a just back insertable and erasable path
+ /// type. It can be indexed in O(1) time. The back insertion and
+ /// erasure is amortized O(1) time. This implementation is faster
+ /// then the \c Path type because it use just one vector for the
+ /// arcs.
+ template <typename GR>
+ class SimplePath {
+ public:
+
+ typedef GR Digraph;
+ typedef typename Digraph::Arc Arc;
+
+ /// \brief Default constructor
+ ///
+ /// Default constructor
+ SimplePath() {}
+
+ /// \brief Copy constructor
+ ///
+ SimplePath(const SimplePath& cpath) {
+ pathCopy(cpath, *this);
+ }
+
+ /// \brief Template copy constructor
+ ///
+ /// This path can be initialized with any other path type. It just
+ /// makes a copy of the given path.
+ template <typename CPath>
+ SimplePath(const CPath& cpath) {
+ pathCopy(cpath, *this);
+ }
+
+ /// \brief Copy assignment
+ ///
+ SimplePath& operator=(const SimplePath& cpath) {
+ pathCopy(cpath, *this);
+ return *this;
+ }
+
+ /// \brief Template copy assignment
+ ///
+ /// This path can be initialized with any other path type. It just
+ /// makes a copy of the given path.
+ template <typename CPath>
+ SimplePath& operator=(const CPath& cpath) {
+ pathCopy(cpath, *this);
+ return *this;
+ }
+
+ /// \brief Iterator class to iterate on the arcs of the paths
+ ///
+ /// This class is used to iterate on the arcs of the paths
+ ///
+ /// Of course it converts to Digraph::Arc
+ class ArcIt {
+ friend class SimplePath;
+ public:
+ /// Default constructor
+ ArcIt() {}
+ /// Invalid constructor
+ ArcIt(Invalid) : path(0), idx(-1) {}
+ /// \brief Initializate the constructor to the first arc of path
+ ArcIt(const SimplePath &_path)
+ : path(&_path), idx(_path.empty() ? -1 : 0) {}
+
+ private:
+
+ /// Constructor with starting point
+ ArcIt(const SimplePath &_path, int _idx)
+ : path(&_path), idx(_idx) {}
+
+ public:
+
+ ///Conversion to Digraph::Arc
+ operator const Arc&() const {
+ return path->nth(idx);
+ }
+
+ /// Next arc
+ ArcIt& operator++() {
+ ++idx;
+ if (idx >= path->length()) idx = -1;
+ return *this;
+ }
+
+ /// Comparison operator
+ bool operator==(const ArcIt& e) const { return idx==e.idx; }
+ /// Comparison operator
+ bool operator!=(const ArcIt& e) const { return idx!=e.idx; }
+ /// Comparison operator
+ bool operator<(const ArcIt& e) const { return idx<e.idx; }
+
+ private:
+ const SimplePath *path;
+ int idx;
+ };
+
+ /// \brief Length of the path.
+ int length() const { return data.size(); }
+ /// \brief Return true if the path is empty.
+ bool empty() const { return data.empty(); }
+
+ /// \brief Reset the path to an empty one.
+ void clear() { data.clear(); }
+
+ /// \brief The n-th arc.
+ ///
+ /// \pre \c n is in the <tt>[0..length() - 1]</tt> range.
+ const Arc& nth(int n) const {
+ return data[n];
+ }
+
+ /// \brief Initializes arc iterator to point to the n-th arc.
+ ArcIt nthIt(int n) const {
+ return ArcIt(*this, n);
+ }
+
+ /// \brief The first arc of the path.
+ const Arc& front() const {
+ return data.front();
+ }
+
+ /// \brief The last arc of the path.
+ const Arc& back() const {
+ return data.back();
+ }
+
+ /// \brief Add a new arc behind the current path.
+ void addBack(const Arc& arc) {
+ data.push_back(arc);
+ }
+
+ /// \brief Erase the last arc of the path
+ void eraseBack() {
+ data.pop_back();
+ }
+
+ typedef True BuildTag;
+
+ template <typename CPath>
+ void build(const CPath& path) {
+ int len = path.length();
+ data.resize(len);
+ int index = 0;
+ for (typename CPath::ArcIt it(path); it != INVALID; ++it) {
+ data[index] = it;;
+ ++index;
+ }
+ }
+
+ template <typename CPath>
+ void buildRev(const CPath& path) {
+ int len = path.length();
+ data.resize(len);
+ int index = len;
+ for (typename CPath::RevArcIt it(path); it != INVALID; ++it) {
+ --index;
+ data[index] = it;;
+ }
+ }
+
+ protected:
+ typedef std::vector<Arc> Container;
+ Container data;
+
+ };
+
+ /// \brief A structure for representing directed paths in a digraph.
+ ///
+ /// A structure for representing directed path in a digraph.
+ /// \tparam GR The digraph type in which the path is.
+ ///
+ /// In a sense, the path can be treated as a list of arcs. The
+ /// LEMON path type stores just this list. As a consequence it
+ /// cannot enumerate the nodes in the path and the zero length paths
+ /// cannot store the source.
+ ///
+ /// This implementation is a back and front insertable and erasable
+ /// path type. It can be indexed in O(k) time, where k is the rank
+ /// of the arc in the path. The length can be computed in O(n)
+ /// time. The front and back insertion and erasure is O(1) time
+ /// and it can be splited and spliced in O(1) time.
+ template <typename GR>
+ class ListPath {
+ public:
+
+ typedef GR Digraph;
+ typedef typename Digraph::Arc Arc;
+
+ protected:
+
+ // the std::list<> is incompatible
+ // hard to create invalid iterator
+ struct Node {
+ Arc arc;
+ Node *next, *prev;
+ };
+
+ Node *first, *last;
+
+ std::allocator<Node> alloc;
+
+ public:
+
+ /// \brief Default constructor
+ ///
+ /// Default constructor
+ ListPath() : first(0), last(0) {}
+
+ /// \brief Copy constructor
+ ///
+ ListPath(const ListPath& cpath) : first(0), last(0) {
+ pathCopy(cpath, *this);
+ }
+
+ /// \brief Template copy constructor
+ ///
+ /// This path can be initialized with any other path type. It just
+ /// makes a copy of the given path.
+ template <typename CPath>
+ ListPath(const CPath& cpath) : first(0), last(0) {
+ pathCopy(cpath, *this);
+ }
+
+ /// \brief Destructor of the path
+ ///
+ /// Destructor of the path
+ ~ListPath() {
+ clear();
+ }
+
+ /// \brief Copy assignment
+ ///
+ ListPath& operator=(const ListPath& cpath) {
+ pathCopy(cpath, *this);
+ return *this;
+ }
+
+ /// \brief Template copy assignment
+ ///
+ /// This path can be initialized with any other path type. It just
+ /// makes a copy of the given path.
+ template <typename CPath>
+ ListPath& operator=(const CPath& cpath) {
+ pathCopy(cpath, *this);
+ return *this;
+ }
+
+ /// \brief Iterator class to iterate on the arcs of the paths
+ ///
+ /// This class is used to iterate on the arcs of the paths
+ ///
+ /// Of course it converts to Digraph::Arc
+ class ArcIt {
+ friend class ListPath;
+ public:
+ /// Default constructor
+ ArcIt() {}
+ /// Invalid constructor
+ ArcIt(Invalid) : path(0), node(0) {}
+ /// \brief Initializate the constructor to the first arc of path
+ ArcIt(const ListPath &_path)
+ : path(&_path), node(_path.first) {}
+
+ protected:
+
+ ArcIt(const ListPath &_path, Node *_node)
+ : path(&_path), node(_node) {}
+
+
+ public:
+
+ ///Conversion to Digraph::Arc
+ operator const Arc&() const {
+ return node->arc;
+ }
+
+ /// Next arc
+ ArcIt& operator++() {
+ node = node->next;
+ return *this;
+ }
+
+ /// Comparison operator
+ bool operator==(const ArcIt& e) const { return node==e.node; }
+ /// Comparison operator
+ bool operator!=(const ArcIt& e) const { return node!=e.node; }
+ /// Comparison operator
+ bool operator<(const ArcIt& e) const { return node<e.node; }
+
+ private:
+ const ListPath *path;
+ Node *node;
+ };
+
+ /// \brief The n-th arc.
+ ///
+ /// This function looks for the n-th arc in O(n) time.
+ /// \pre \c n is in the <tt>[0..length() - 1]</tt> range.
+ const Arc& nth(int n) const {
+ Node *node = first;
+ for (int i = 0; i < n; ++i) {
+ node = node->next;
+ }
+ return node->arc;
+ }
+
+ /// \brief Initializes arc iterator to point to the n-th arc.
+ ArcIt nthIt(int n) const {
+ Node *node = first;
+ for (int i = 0; i < n; ++i) {
+ node = node->next;
+ }
+ return ArcIt(*this, node);
+ }
+
+ /// \brief Length of the path.
+ int length() const {
+ int len = 0;
+ Node *node = first;
+ while (node != 0) {
+ node = node->next;
+ ++len;
+ }
+ return len;
+ }
+
+ /// \brief Return true if the path is empty.
+ bool empty() const { return first == 0; }
+
+ /// \brief Reset the path to an empty one.
+ void clear() {
+ while (first != 0) {
+ last = first->next;
+ alloc.destroy(first);
+ alloc.deallocate(first, 1);
+ first = last;
+ }
+ }
+
+ /// \brief The first arc of the path
+ const Arc& front() const {
+ return first->arc;
+ }
+
+ /// \brief Add a new arc before the current path
+ void addFront(const Arc& arc) {
+ Node *node = alloc.allocate(1);
+ alloc.construct(node, Node());
+ node->prev = 0;
+ node->next = first;
+ node->arc = arc;
+ if (first) {
+ first->prev = node;
+ first = node;
+ } else {
+ first = last = node;
+ }
+ }
+
+ /// \brief Erase the first arc of the path
+ void eraseFront() {
+ Node *node = first;
+ first = first->next;
+ if (first) {
+ first->prev = 0;
+ } else {
+ last = 0;
+ }
+ alloc.destroy(node);
+ alloc.deallocate(node, 1);
+ }
+
+ /// \brief The last arc of the path.
+ const Arc& back() const {
+ return last->arc;
+ }
+
+ /// \brief Add a new arc behind the current path.
+ void addBack(const Arc& arc) {
+ Node *node = alloc.allocate(1);
+ alloc.construct(node, Node());
+ node->next = 0;
+ node->prev = last;
+ node->arc = arc;
+ if (last) {
+ last->next = node;
+ last = node;
+ } else {
+ last = first = node;
+ }
+ }
+
+ /// \brief Erase the last arc of the path
+ void eraseBack() {
+ Node *node = last;
+ last = last->prev;
+ if (last) {
+ last->next = 0;
+ } else {
+ first = 0;
+ }
+ alloc.destroy(node);
+ alloc.deallocate(node, 1);
+ }
+
+ /// \brief Splice a path to the back of the current path.
+ ///
+ /// It splices \c tpath to the back of the current path and \c
+ /// tpath becomes empty. The time complexity of this function is
+ /// O(1).
+ void spliceBack(ListPath& tpath) {
+ if (first) {
+ if (tpath.first) {
+ last->next = tpath.first;
+ tpath.first->prev = last;
+ last = tpath.last;
+ }
+ } else {
+ first = tpath.first;
+ last = tpath.last;
+ }
+ tpath.first = tpath.last = 0;
+ }
+
+ /// \brief Splice a path to the front of the current path.
+ ///
+ /// It splices \c tpath before the current path and \c tpath
+ /// becomes empty. The time complexity of this function
+ /// is O(1).
+ void spliceFront(ListPath& tpath) {
+ if (first) {
+ if (tpath.first) {
+ first->prev = tpath.last;
+ tpath.last->next = first;
+ first = tpath.first;
+ }
+ } else {
+ first = tpath.first;
+ last = tpath.last;
+ }
+ tpath.first = tpath.last = 0;
+ }
+
+ /// \brief Splice a path into the current path.
+ ///
+ /// It splices the \c tpath into the current path before the
+ /// position of \c it iterator and \c tpath becomes empty. The
+ /// time complexity of this function is O(1). If the \c it is
+ /// \c INVALID then it will splice behind the current path.
+ void splice(ArcIt it, ListPath& tpath) {
+ if (it.node) {
+ if (tpath.first) {
+ tpath.first->prev = it.node->prev;
+ if (it.node->prev) {
+ it.node->prev->next = tpath.first;
+ } else {
+ first = tpath.first;
+ }
+ it.node->prev = tpath.last;
+ tpath.last->next = it.node;
+ }
+ } else {
+ if (first) {
+ if (tpath.first) {
+ last->next = tpath.first;
+ tpath.first->prev = last;
+ last = tpath.last;
+ }
+ } else {
+ first = tpath.first;
+ last = tpath.last;
+ }
+ }
+ tpath.first = tpath.last = 0;
+ }
+
+ /// \brief Split the current path.
+ ///
+ /// It splits the current path into two parts. The part before
+ /// the iterator \c it will remain in the current path and the part
+ /// starting with
+ /// \c it will put into \c tpath. If \c tpath have arcs
+ /// before the operation they are removed first. The time
+ /// complexity of this function is O(1) plus the the time of emtying
+ /// \c tpath. If \c it is \c INVALID then it just clears \c tpath
+ void split(ArcIt it, ListPath& tpath) {
+ tpath.clear();
+ if (it.node) {
+ tpath.first = it.node;
+ tpath.last = last;
+ if (it.node->prev) {
+ last = it.node->prev;
+ last->next = 0;
+ } else {
+ first = last = 0;
+ }
+ it.node->prev = 0;
+ }
+ }
+
+
+ typedef True BuildTag;
+
+ template <typename CPath>
+ void build(const CPath& path) {
+ for (typename CPath::ArcIt it(path); it != INVALID; ++it) {
+ addBack(it);
+ }
+ }
+
+ template <typename CPath>
+ void buildRev(const CPath& path) {
+ for (typename CPath::RevArcIt it(path); it != INVALID; ++it) {
+ addFront(it);
+ }
+ }
+
+ };
+
+ /// \brief A structure for representing directed paths in a digraph.
+ ///
+ /// A structure for representing directed path in a digraph.
+ /// \tparam GR The digraph type in which the path is.
+ ///
+ /// In a sense, the path can be treated as a list of arcs. The
+ /// LEMON path type stores just this list. As a consequence it
+ /// cannot enumerate the nodes in the path and the source node of
+ /// a zero length path is undefined.
+ ///
+ /// This implementation is completly static, i.e. it can be copy constucted
+ /// or copy assigned from another path, but otherwise it cannot be
+ /// modified.
+ ///
+ /// Being the the most memory efficient path type in LEMON,
+ /// it is intented to be
+ /// used when you want to store a large number of paths.
+ template <typename GR>
+ class StaticPath {
+ public:
+
+ typedef GR Digraph;
+ typedef typename Digraph::Arc Arc;
+
+ /// \brief Default constructor
+ ///
+ /// Default constructor
+ StaticPath() : len(0), arcs(0) {}
+
+ /// \brief Copy constructor
+ ///
+ StaticPath(const StaticPath& cpath) : arcs(0) {
+ pathCopy(cpath, *this);
+ }
+
+ /// \brief Template copy constructor
+ ///
+ /// This path can be initialized from any other path type.
+ template <typename CPath>
+ StaticPath(const CPath& cpath) : arcs(0) {
+ pathCopy(cpath, *this);
+ }
+
+ /// \brief Destructor of the path
+ ///
+ /// Destructor of the path
+ ~StaticPath() {
+ if (arcs) delete[] arcs;
+ }
+
+ /// \brief Copy assignment
+ ///
+ StaticPath& operator=(const StaticPath& cpath) {
+ pathCopy(cpath, *this);
+ return *this;
+ }
+
+ /// \brief Template copy assignment
+ ///
+ /// This path can be made equal to any other path type. It simply
+ /// makes a copy of the given path.
+ template <typename CPath>
+ StaticPath& operator=(const CPath& cpath) {
+ pathCopy(cpath, *this);
+ return *this;
+ }
+
+ /// \brief Iterator class to iterate on the arcs of the paths
+ ///
+ /// This class is used to iterate on the arcs of the paths
+ ///
+ /// Of course it converts to Digraph::Arc
+ class ArcIt {
+ friend class StaticPath;
+ public:
+ /// Default constructor
+ ArcIt() {}
+ /// Invalid constructor
+ ArcIt(Invalid) : path(0), idx(-1) {}
+ /// Initializate the constructor to the first arc of path
+ ArcIt(const StaticPath &_path)
+ : path(&_path), idx(_path.empty() ? -1 : 0) {}
+
+ private:
+
+ /// Constructor with starting point
+ ArcIt(const StaticPath &_path, int _idx)
+ : idx(_idx), path(&_path) {}
+
+ public:
+
+ ///Conversion to Digraph::Arc
+ operator const Arc&() const {
+ return path->nth(idx);
+ }
+
+ /// Next arc
+ ArcIt& operator++() {
+ ++idx;
+ if (idx >= path->length()) idx = -1;
+ return *this;
+ }
+
+ /// Comparison operator
+ bool operator==(const ArcIt& e) const { return idx==e.idx; }
+ /// Comparison operator
+ bool operator!=(const ArcIt& e) const { return idx!=e.idx; }
+ /// Comparison operator
+ bool operator<(const ArcIt& e) const { return idx<e.idx; }
+
+ private:
+ const StaticPath *path;
+ int idx;
+ };
+
+ /// \brief The n-th arc.
+ ///
+ /// \pre \c n is in the <tt>[0..length() - 1]</tt> range.
+ const Arc& nth(int n) const {
+ return arcs[n];
+ }
+
+ /// \brief The arc iterator pointing to the n-th arc.
+ ArcIt nthIt(int n) const {
+ return ArcIt(*this, n);
+ }
+
+ /// \brief The length of the path.
+ int length() const { return len; }
+
+ /// \brief Return true when the path is empty.
+ int empty() const { return len == 0; }
+
+ /// \brief Erase all arcs in the digraph.
+ void clear() {
+ len = 0;
+ if (arcs) delete[] arcs;
+ arcs = 0;
+ }
+
+ /// \brief The first arc of the path.
+ const Arc& front() const {
+ return arcs[0];
+ }
+
+ /// \brief The last arc of the path.
+ const Arc& back() const {
+ return arcs[len - 1];
+ }
+
+
+ typedef True BuildTag;
+
+ template <typename CPath>
+ void build(const CPath& path) {
+ len = path.length();
+ arcs = new Arc[len];
+ int index = 0;
+ for (typename CPath::ArcIt it(path); it != INVALID; ++it) {
+ arcs[index] = it;
+ ++index;
+ }
+ }
+
+ template <typename CPath>
+ void buildRev(const CPath& path) {
+ len = path.length();
+ arcs = new Arc[len];
+ int index = len;
+ for (typename CPath::RevArcIt it(path); it != INVALID; ++it) {
+ --index;
+ arcs[index] = it;
+ }
+ }
+
+ private:
+ int len;
+ Arc* arcs;
+ };
+
+ ///////////////////////////////////////////////////////////////////////
+ // Additional utilities
+ ///////////////////////////////////////////////////////////////////////
+
+ namespace _path_bits {
+
+ template <typename Path, typename Enable = void>
+ struct RevPathTagIndicator {
+ static const bool value = false;
+ };
+
+ template <typename Path>
+ struct RevPathTagIndicator<
+ Path,
+ typename enable_if<typename Path::RevPathTag, void>::type
+ > {
+ static const bool value = true;
+ };
+
+ template <typename Path, typename Enable = void>
+ struct BuildTagIndicator {
+ static const bool value = false;
+ };
+
+ template <typename Path>
+ struct BuildTagIndicator<
+ Path,
+ typename enable_if<typename Path::BuildTag, void>::type
+ > {
+ static const bool value = true;
+ };
+
+ template <typename From, typename To,
+ bool buildEnable = BuildTagIndicator<To>::value>
+ struct PathCopySelectorForward {
+ static void copy(const From& from, To& to) {
+ to.clear();
+ for (typename From::ArcIt it(from); it != INVALID; ++it) {
+ to.addBack(it);
+ }
+ }
+ };
+
+ template <typename From, typename To>
+ struct PathCopySelectorForward<From, To, true> {
+ static void copy(const From& from, To& to) {
+ to.clear();
+ to.build(from);
+ }
+ };
+
+ template <typename From, typename To,
+ bool buildEnable = BuildTagIndicator<To>::value>
+ struct PathCopySelectorBackward {
+ static void copy(const From& from, To& to) {
+ to.clear();
+ for (typename From::RevArcIt it(from); it != INVALID; ++it) {
+ to.addFront(it);
+ }
+ }
+ };
+
+ template <typename From, typename To>
+ struct PathCopySelectorBackward<From, To, true> {
+ static void copy(const From& from, To& to) {
+ to.clear();
+ to.buildRev(from);
+ }
+ };
+
+
+ template <typename From, typename To,
+ bool revEnable = RevPathTagIndicator<From>::value>
+ struct PathCopySelector {
+ static void copy(const From& from, To& to) {
+ PathCopySelectorForward<From, To>::copy(from, to);
+ }
+ };
+
+ template <typename From, typename To>
+ struct PathCopySelector<From, To, true> {
+ static void copy(const From& from, To& to) {
+ PathCopySelectorBackward<From, To>::copy(from, to);
+ }
+ };
+
+ }
+
+
+ /// \brief Make a copy of a path.
+ ///
+ /// This function makes a copy of a path.
+ template <typename From, typename To>
+ void pathCopy(const From& from, To& to) {
+ checkConcept<concepts::PathDumper<typename From::Digraph>, From>();
+ _path_bits::PathCopySelector<From, To>::copy(from, to);
+ }
+
+ /// \brief Deprecated version of \ref pathCopy().
+ ///
+ /// Deprecated version of \ref pathCopy() (only for reverse compatibility).
+ template <typename To, typename From>
+ void copyPath(To& to, const From& from) {
+ pathCopy(from, to);
+ }
+
+ /// \brief Check the consistency of a path.
+ ///
+ /// This function checks that the target of each arc is the same
+ /// as the source of the next one.
+ ///
+ template <typename Digraph, typename Path>
+ bool checkPath(const Digraph& digraph, const Path& path) {
+ typename Path::ArcIt it(path);
+ if (it == INVALID) return true;
+ typename Digraph::Node node = digraph.target(it);
+ ++it;
+ while (it != INVALID) {
+ if (digraph.source(it) != node) return false;
+ node = digraph.target(it);
+ ++it;
+ }
+ return true;
+ }
+
+ /// \brief The source of a path
+ ///
+ /// This function returns the source node of the given path.
+ /// If the path is empty, then it returns \c INVALID.
+ template <typename Digraph, typename Path>
+ typename Digraph::Node pathSource(const Digraph& digraph, const Path& path) {
+ return path.empty() ? INVALID : digraph.source(path.front());
+ }
+
+ /// \brief The target of a path
+ ///
+ /// This function returns the target node of the given path.
+ /// If the path is empty, then it returns \c INVALID.
+ template <typename Digraph, typename Path>
+ typename Digraph::Node pathTarget(const Digraph& digraph, const Path& path) {
+ return path.empty() ? INVALID : digraph.target(path.back());
+ }
+
+ /// \brief Class which helps to iterate through the nodes of a path
+ ///
+ /// In a sense, the path can be treated as a list of arcs. The
+ /// LEMON path type stores only this list. As a consequence, it
+ /// cannot enumerate the nodes in the path and the zero length paths
+ /// cannot have a source node.
+ ///
+ /// This class implements the node iterator of a path structure. To
+ /// provide this feature, the underlying digraph should be passed to
+ /// the constructor of the iterator.
+ template <typename Path>
+ class PathNodeIt {
+ private:
+ const typename Path::Digraph *_digraph;
+ typename Path::ArcIt _it;
+ typename Path::Digraph::Node _nd;
+
+ public:
+
+ typedef typename Path::Digraph Digraph;
+ typedef typename Digraph::Node Node;
+
+ /// Default constructor
+ PathNodeIt() {}
+ /// Invalid constructor
+ PathNodeIt(Invalid)
+ : _digraph(0), _it(INVALID), _nd(INVALID) {}
+ /// Constructor
+ PathNodeIt(const Digraph& digraph, const Path& path)
+ : _digraph(&digraph), _it(path) {
+ _nd = (_it != INVALID ? _digraph->source(_it) : INVALID);
+ }
+ /// Constructor
+ PathNodeIt(const Digraph& digraph, const Path& path, const Node& src)
+ : _digraph(&digraph), _it(path), _nd(src) {}
+
+ ///Conversion to Digraph::Node
+ operator Node() const {
+ return _nd;
+ }
+
+ /// Next node
+ PathNodeIt& operator++() {
+ if (_it == INVALID) _nd = INVALID;
+ else {
+ _nd = _digraph->target(_it);
+ ++_it;
+ }
+ return *this;
+ }
+
+ /// Comparison operator
+ bool operator==(const PathNodeIt& n) const {
+ return _it == n._it && _nd == n._nd;
+ }
+ /// Comparison operator
+ bool operator!=(const PathNodeIt& n) const {
+ return _it != n._it || _nd != n._nd;
+ }
+ /// Comparison operator
+ bool operator<(const PathNodeIt& n) const {
+ return (_it < n._it && _nd != INVALID);
+ }
+
+ };
+
+ ///@}
+
+} // namespace lemon
+
+#endif // LEMON_PATH_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/planarity.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/planarity.h
new file mode 100644
index 00000000000..bfe8e85dc4d
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/planarity.h
@@ -0,0 +1,2754 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_PLANARITY_H
+#define LEMON_PLANARITY_H
+
+/// \ingroup planar
+/// \file
+/// \brief Planarity checking, embedding, drawing and coloring
+
+#include <vector>
+#include <list>
+
+#include <lemon/dfs.h>
+#include <lemon/bfs.h>
+#include <lemon/radix_sort.h>
+#include <lemon/maps.h>
+#include <lemon/path.h>
+#include <lemon/bucket_heap.h>
+#include <lemon/adaptors.h>
+#include <lemon/edge_set.h>
+#include <lemon/color.h>
+#include <lemon/dim2.h>
+
+namespace lemon {
+
+ namespace _planarity_bits {
+
+ template <typename Graph>
+ struct PlanarityVisitor : DfsVisitor<Graph> {
+
+ TEMPLATE_GRAPH_TYPEDEFS(Graph);
+
+ typedef typename Graph::template NodeMap<Arc> PredMap;
+
+ typedef typename Graph::template EdgeMap<bool> TreeMap;
+
+ typedef typename Graph::template NodeMap<int> OrderMap;
+ typedef std::vector<Node> OrderList;
+
+ typedef typename Graph::template NodeMap<int> LowMap;
+ typedef typename Graph::template NodeMap<int> AncestorMap;
+
+ PlanarityVisitor(const Graph& graph,
+ PredMap& pred_map, TreeMap& tree_map,
+ OrderMap& order_map, OrderList& order_list,
+ AncestorMap& ancestor_map, LowMap& low_map)
+ : _graph(graph), _pred_map(pred_map), _tree_map(tree_map),
+ _order_map(order_map), _order_list(order_list),
+ _ancestor_map(ancestor_map), _low_map(low_map) {}
+
+ void reach(const Node& node) {
+ _order_map[node] = _order_list.size();
+ _low_map[node] = _order_list.size();
+ _ancestor_map[node] = _order_list.size();
+ _order_list.push_back(node);
+ }
+
+ void discover(const Arc& arc) {
+ Node target = _graph.target(arc);
+
+ _tree_map[arc] = true;
+ _pred_map[target] = arc;
+ }
+
+ void examine(const Arc& arc) {
+ Node source = _graph.source(arc);
+ Node target = _graph.target(arc);
+
+ if (_order_map[target] < _order_map[source] && !_tree_map[arc]) {
+ if (_low_map[source] > _order_map[target]) {
+ _low_map[source] = _order_map[target];
+ }
+ if (_ancestor_map[source] > _order_map[target]) {
+ _ancestor_map[source] = _order_map[target];
+ }
+ }
+ }
+
+ void backtrack(const Arc& arc) {
+ Node source = _graph.source(arc);
+ Node target = _graph.target(arc);
+
+ if (_low_map[source] > _low_map[target]) {
+ _low_map[source] = _low_map[target];
+ }
+ }
+
+ const Graph& _graph;
+ PredMap& _pred_map;
+ TreeMap& _tree_map;
+ OrderMap& _order_map;
+ OrderList& _order_list;
+ AncestorMap& _ancestor_map;
+ LowMap& _low_map;
+ };
+
+ template <typename Graph, bool embedding = true>
+ struct NodeDataNode {
+ int prev, next;
+ int visited;
+ typename Graph::Arc first;
+ bool inverted;
+ };
+
+ template <typename Graph>
+ struct NodeDataNode<Graph, false> {
+ int prev, next;
+ int visited;
+ };
+
+ template <typename Graph>
+ struct ChildListNode {
+ typedef typename Graph::Node Node;
+ Node first;
+ Node prev, next;
+ };
+
+ template <typename Graph>
+ struct ArcListNode {
+ typename Graph::Arc prev, next;
+ };
+
+ template <typename Graph>
+ class PlanarityChecking {
+ private:
+
+ TEMPLATE_GRAPH_TYPEDEFS(Graph);
+
+ const Graph& _graph;
+
+ private:
+
+ typedef typename Graph::template NodeMap<Arc> PredMap;
+
+ typedef typename Graph::template EdgeMap<bool> TreeMap;
+
+ typedef typename Graph::template NodeMap<int> OrderMap;
+ typedef std::vector<Node> OrderList;
+
+ typedef typename Graph::template NodeMap<int> LowMap;
+ typedef typename Graph::template NodeMap<int> AncestorMap;
+
+ typedef _planarity_bits::NodeDataNode<Graph> NodeDataNode;
+ typedef std::vector<NodeDataNode> NodeData;
+
+ typedef _planarity_bits::ChildListNode<Graph> ChildListNode;
+ typedef typename Graph::template NodeMap<ChildListNode> ChildLists;
+
+ typedef typename Graph::template NodeMap<std::list<int> > MergeRoots;
+
+ typedef typename Graph::template NodeMap<bool> EmbedArc;
+
+ public:
+
+ PlanarityChecking(const Graph& graph) : _graph(graph) {}
+
+ bool run() {
+ typedef _planarity_bits::PlanarityVisitor<Graph> Visitor;
+
+ PredMap pred_map(_graph, INVALID);
+ TreeMap tree_map(_graph, false);
+
+ OrderMap order_map(_graph, -1);
+ OrderList order_list;
+
+ AncestorMap ancestor_map(_graph, -1);
+ LowMap low_map(_graph, -1);
+
+ Visitor visitor(_graph, pred_map, tree_map,
+ order_map, order_list, ancestor_map, low_map);
+ DfsVisit<Graph, Visitor> visit(_graph, visitor);
+ visit.run();
+
+ ChildLists child_lists(_graph);
+ createChildLists(tree_map, order_map, low_map, child_lists);
+
+ NodeData node_data(2 * order_list.size());
+
+ EmbedArc embed_arc(_graph, false);
+
+ MergeRoots merge_roots(_graph);
+
+ for (int i = order_list.size() - 1; i >= 0; --i) {
+
+ Node node = order_list[i];
+
+ Node source = node;
+ for (OutArcIt e(_graph, node); e != INVALID; ++e) {
+ Node target = _graph.target(e);
+
+ if (order_map[source] < order_map[target] && tree_map[e]) {
+ initFace(target, node_data, order_map, order_list);
+ }
+ }
+
+ for (OutArcIt e(_graph, node); e != INVALID; ++e) {
+ Node target = _graph.target(e);
+
+ if (order_map[source] < order_map[target] && !tree_map[e]) {
+ embed_arc[target] = true;
+ walkUp(target, source, i, pred_map, low_map,
+ order_map, order_list, node_data, merge_roots);
+ }
+ }
+
+ for (typename MergeRoots::Value::iterator it =
+ merge_roots[node].begin();
+ it != merge_roots[node].end(); ++it) {
+ int rn = *it;
+ walkDown(rn, i, node_data, order_list, child_lists,
+ ancestor_map, low_map, embed_arc, merge_roots);
+ }
+ merge_roots[node].clear();
+
+ for (OutArcIt e(_graph, node); e != INVALID; ++e) {
+ Node target = _graph.target(e);
+
+ if (order_map[source] < order_map[target] && !tree_map[e]) {
+ if (embed_arc[target]) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private:
+
+ void createChildLists(const TreeMap& tree_map, const OrderMap& order_map,
+ const LowMap& low_map, ChildLists& child_lists) {
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ Node source = n;
+
+ std::vector<Node> targets;
+ for (OutArcIt e(_graph, n); e != INVALID; ++e) {
+ Node target = _graph.target(e);
+
+ if (order_map[source] < order_map[target] && tree_map[e]) {
+ targets.push_back(target);
+ }
+ }
+
+ if (targets.size() == 0) {
+ child_lists[source].first = INVALID;
+ } else if (targets.size() == 1) {
+ child_lists[source].first = targets[0];
+ child_lists[targets[0]].prev = INVALID;
+ child_lists[targets[0]].next = INVALID;
+ } else {
+ radixSort(targets.begin(), targets.end(), mapToFunctor(low_map));
+ for (int i = 1; i < int(targets.size()); ++i) {
+ child_lists[targets[i]].prev = targets[i - 1];
+ child_lists[targets[i - 1]].next = targets[i];
+ }
+ child_lists[targets.back()].next = INVALID;
+ child_lists[targets.front()].prev = INVALID;
+ child_lists[source].first = targets.front();
+ }
+ }
+ }
+
+ void walkUp(const Node& node, Node root, int rorder,
+ const PredMap& pred_map, const LowMap& low_map,
+ const OrderMap& order_map, const OrderList& order_list,
+ NodeData& node_data, MergeRoots& merge_roots) {
+
+ int na, nb;
+ bool da, db;
+
+ na = nb = order_map[node];
+ da = true; db = false;
+
+ while (true) {
+
+ if (node_data[na].visited == rorder) break;
+ if (node_data[nb].visited == rorder) break;
+
+ node_data[na].visited = rorder;
+ node_data[nb].visited = rorder;
+
+ int rn = -1;
+
+ if (na >= int(order_list.size())) {
+ rn = na;
+ } else if (nb >= int(order_list.size())) {
+ rn = nb;
+ }
+
+ if (rn == -1) {
+ int nn;
+
+ nn = da ? node_data[na].prev : node_data[na].next;
+ da = node_data[nn].prev != na;
+ na = nn;
+
+ nn = db ? node_data[nb].prev : node_data[nb].next;
+ db = node_data[nn].prev != nb;
+ nb = nn;
+
+ } else {
+
+ Node rep = order_list[rn - order_list.size()];
+ Node parent = _graph.source(pred_map[rep]);
+
+ if (low_map[rep] < rorder) {
+ merge_roots[parent].push_back(rn);
+ } else {
+ merge_roots[parent].push_front(rn);
+ }
+
+ if (parent != root) {
+ na = nb = order_map[parent];
+ da = true; db = false;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+
+ void walkDown(int rn, int rorder, NodeData& node_data,
+ OrderList& order_list, ChildLists& child_lists,
+ AncestorMap& ancestor_map, LowMap& low_map,
+ EmbedArc& embed_arc, MergeRoots& merge_roots) {
+
+ std::vector<std::pair<int, bool> > merge_stack;
+
+ for (int di = 0; di < 2; ++di) {
+ bool rd = di == 0;
+ int pn = rn;
+ int n = rd ? node_data[rn].next : node_data[rn].prev;
+
+ while (n != rn) {
+
+ Node node = order_list[n];
+
+ if (embed_arc[node]) {
+
+ // Merging components on the critical path
+ while (!merge_stack.empty()) {
+
+ // Component root
+ int cn = merge_stack.back().first;
+ bool cd = merge_stack.back().second;
+ merge_stack.pop_back();
+
+ // Parent of component
+ int dn = merge_stack.back().first;
+ bool dd = merge_stack.back().second;
+ merge_stack.pop_back();
+
+ Node parent = order_list[dn];
+
+ // Erasing from merge_roots
+ merge_roots[parent].pop_front();
+
+ Node child = order_list[cn - order_list.size()];
+
+ // Erasing from child_lists
+ if (child_lists[child].prev != INVALID) {
+ child_lists[child_lists[child].prev].next =
+ child_lists[child].next;
+ } else {
+ child_lists[parent].first = child_lists[child].next;
+ }
+
+ if (child_lists[child].next != INVALID) {
+ child_lists[child_lists[child].next].prev =
+ child_lists[child].prev;
+ }
+
+ // Merging external faces
+ {
+ int en = cn;
+ cn = cd ? node_data[cn].prev : node_data[cn].next;
+ cd = node_data[cn].next == en;
+
+ }
+
+ if (cd) node_data[cn].next = dn; else node_data[cn].prev = dn;
+ if (dd) node_data[dn].prev = cn; else node_data[dn].next = cn;
+
+ }
+
+ bool d = pn == node_data[n].prev;
+
+ if (node_data[n].prev == node_data[n].next &&
+ node_data[n].inverted) {
+ d = !d;
+ }
+
+ // Embedding arc into external face
+ if (rd) node_data[rn].next = n; else node_data[rn].prev = n;
+ if (d) node_data[n].prev = rn; else node_data[n].next = rn;
+ pn = rn;
+
+ embed_arc[order_list[n]] = false;
+ }
+
+ if (!merge_roots[node].empty()) {
+
+ bool d = pn == node_data[n].prev;
+
+ merge_stack.push_back(std::make_pair(n, d));
+
+ int rn = merge_roots[node].front();
+
+ int xn = node_data[rn].next;
+ Node xnode = order_list[xn];
+
+ int yn = node_data[rn].prev;
+ Node ynode = order_list[yn];
+
+ bool rd;
+ if (!external(xnode, rorder, child_lists,
+ ancestor_map, low_map)) {
+ rd = true;
+ } else if (!external(ynode, rorder, child_lists,
+ ancestor_map, low_map)) {
+ rd = false;
+ } else if (pertinent(xnode, embed_arc, merge_roots)) {
+ rd = true;
+ } else {
+ rd = false;
+ }
+
+ merge_stack.push_back(std::make_pair(rn, rd));
+
+ pn = rn;
+ n = rd ? xn : yn;
+
+ } else if (!external(node, rorder, child_lists,
+ ancestor_map, low_map)) {
+ int nn = (node_data[n].next != pn ?
+ node_data[n].next : node_data[n].prev);
+
+ bool nd = n == node_data[nn].prev;
+
+ if (nd) node_data[nn].prev = pn;
+ else node_data[nn].next = pn;
+
+ if (n == node_data[pn].prev) node_data[pn].prev = nn;
+ else node_data[pn].next = nn;
+
+ node_data[nn].inverted =
+ (node_data[nn].prev == node_data[nn].next && nd != rd);
+
+ n = nn;
+ }
+ else break;
+
+ }
+
+ if (!merge_stack.empty() || n == rn) {
+ break;
+ }
+ }
+ }
+
+ void initFace(const Node& node, NodeData& node_data,
+ const OrderMap& order_map, const OrderList& order_list) {
+ int n = order_map[node];
+ int rn = n + order_list.size();
+
+ node_data[n].next = node_data[n].prev = rn;
+ node_data[rn].next = node_data[rn].prev = n;
+
+ node_data[n].visited = order_list.size();
+ node_data[rn].visited = order_list.size();
+
+ }
+
+ bool external(const Node& node, int rorder,
+ ChildLists& child_lists, AncestorMap& ancestor_map,
+ LowMap& low_map) {
+ Node child = child_lists[node].first;
+
+ if (child != INVALID) {
+ if (low_map[child] < rorder) return true;
+ }
+
+ if (ancestor_map[node] < rorder) return true;
+
+ return false;
+ }
+
+ bool pertinent(const Node& node, const EmbedArc& embed_arc,
+ const MergeRoots& merge_roots) {
+ return !merge_roots[node].empty() || embed_arc[node];
+ }
+
+ };
+
+ }
+
+ /// \ingroup planar
+ ///
+ /// \brief Planarity checking of an undirected simple graph
+ ///
+ /// This function implements the Boyer-Myrvold algorithm for
+ /// planarity checking of an undirected simple graph. It is a simplified
+ /// version of the PlanarEmbedding algorithm class because neither
+ /// the embedding nor the Kuratowski subdivisons are computed.
+ template <typename GR>
+ bool checkPlanarity(const GR& graph) {
+ _planarity_bits::PlanarityChecking<GR> pc(graph);
+ return pc.run();
+ }
+
+ /// \ingroup planar
+ ///
+ /// \brief Planar embedding of an undirected simple graph
+ ///
+ /// This class implements the Boyer-Myrvold algorithm for planar
+ /// embedding of an undirected simple graph. The planar embedding is an
+ /// ordering of the outgoing edges of the nodes, which is a possible
+ /// configuration to draw the graph in the plane. If there is not
+ /// such ordering then the graph contains a K<sub>5</sub> (full graph
+ /// with 5 nodes) or a K<sub>3,3</sub> (complete bipartite graph on
+ /// 3 Red and 3 Blue nodes) subdivision.
+ ///
+ /// The current implementation calculates either an embedding or a
+ /// Kuratowski subdivision. The running time of the algorithm is O(n).
+ ///
+ /// \see PlanarDrawing, checkPlanarity()
+ template <typename Graph>
+ class PlanarEmbedding {
+ private:
+
+ TEMPLATE_GRAPH_TYPEDEFS(Graph);
+
+ const Graph& _graph;
+ typename Graph::template ArcMap<Arc> _embedding;
+
+ typename Graph::template EdgeMap<bool> _kuratowski;
+
+ private:
+
+ typedef typename Graph::template NodeMap<Arc> PredMap;
+
+ typedef typename Graph::template EdgeMap<bool> TreeMap;
+
+ typedef typename Graph::template NodeMap<int> OrderMap;
+ typedef std::vector<Node> OrderList;
+
+ typedef typename Graph::template NodeMap<int> LowMap;
+ typedef typename Graph::template NodeMap<int> AncestorMap;
+
+ typedef _planarity_bits::NodeDataNode<Graph> NodeDataNode;
+ typedef std::vector<NodeDataNode> NodeData;
+
+ typedef _planarity_bits::ChildListNode<Graph> ChildListNode;
+ typedef typename Graph::template NodeMap<ChildListNode> ChildLists;
+
+ typedef typename Graph::template NodeMap<std::list<int> > MergeRoots;
+
+ typedef typename Graph::template NodeMap<Arc> EmbedArc;
+
+ typedef _planarity_bits::ArcListNode<Graph> ArcListNode;
+ typedef typename Graph::template ArcMap<ArcListNode> ArcLists;
+
+ typedef typename Graph::template NodeMap<bool> FlipMap;
+
+ typedef typename Graph::template NodeMap<int> TypeMap;
+
+ enum IsolatorNodeType {
+ HIGHX = 6, LOWX = 7,
+ HIGHY = 8, LOWY = 9,
+ ROOT = 10, PERTINENT = 11,
+ INTERNAL = 12
+ };
+
+ public:
+
+ /// \brief The map type for storing the embedding
+ ///
+ /// The map type for storing the embedding.
+ /// \see embeddingMap()
+ typedef typename Graph::template ArcMap<Arc> EmbeddingMap;
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ /// \pre The graph must be simple, i.e. it should not
+ /// contain parallel or loop arcs.
+ PlanarEmbedding(const Graph& graph)
+ : _graph(graph), _embedding(_graph), _kuratowski(graph, false) {}
+
+ /// \brief Run the algorithm.
+ ///
+ /// This function runs the algorithm.
+ /// \param kuratowski If this parameter is set to \c false, then the
+ /// algorithm does not compute a Kuratowski subdivision.
+ /// \return \c true if the graph is planar.
+ bool run(bool kuratowski = true) {
+ typedef _planarity_bits::PlanarityVisitor<Graph> Visitor;
+
+ PredMap pred_map(_graph, INVALID);
+ TreeMap tree_map(_graph, false);
+
+ OrderMap order_map(_graph, -1);
+ OrderList order_list;
+
+ AncestorMap ancestor_map(_graph, -1);
+ LowMap low_map(_graph, -1);
+
+ Visitor visitor(_graph, pred_map, tree_map,
+ order_map, order_list, ancestor_map, low_map);
+ DfsVisit<Graph, Visitor> visit(_graph, visitor);
+ visit.run();
+
+ ChildLists child_lists(_graph);
+ createChildLists(tree_map, order_map, low_map, child_lists);
+
+ NodeData node_data(2 * order_list.size());
+
+ EmbedArc embed_arc(_graph, INVALID);
+
+ MergeRoots merge_roots(_graph);
+
+ ArcLists arc_lists(_graph);
+
+ FlipMap flip_map(_graph, false);
+
+ for (int i = order_list.size() - 1; i >= 0; --i) {
+
+ Node node = order_list[i];
+
+ node_data[i].first = INVALID;
+
+ Node source = node;
+ for (OutArcIt e(_graph, node); e != INVALID; ++e) {
+ Node target = _graph.target(e);
+
+ if (order_map[source] < order_map[target] && tree_map[e]) {
+ initFace(target, arc_lists, node_data,
+ pred_map, order_map, order_list);
+ }
+ }
+
+ for (OutArcIt e(_graph, node); e != INVALID; ++e) {
+ Node target = _graph.target(e);
+
+ if (order_map[source] < order_map[target] && !tree_map[e]) {
+ embed_arc[target] = e;
+ walkUp(target, source, i, pred_map, low_map,
+ order_map, order_list, node_data, merge_roots);
+ }
+ }
+
+ for (typename MergeRoots::Value::iterator it =
+ merge_roots[node].begin(); it != merge_roots[node].end(); ++it) {
+ int rn = *it;
+ walkDown(rn, i, node_data, arc_lists, flip_map, order_list,
+ child_lists, ancestor_map, low_map, embed_arc, merge_roots);
+ }
+ merge_roots[node].clear();
+
+ for (OutArcIt e(_graph, node); e != INVALID; ++e) {
+ Node target = _graph.target(e);
+
+ if (order_map[source] < order_map[target] && !tree_map[e]) {
+ if (embed_arc[target] != INVALID) {
+ if (kuratowski) {
+ isolateKuratowski(e, node_data, arc_lists, flip_map,
+ order_map, order_list, pred_map, child_lists,
+ ancestor_map, low_map,
+ embed_arc, merge_roots);
+ }
+ return false;
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < int(order_list.size()); ++i) {
+
+ mergeRemainingFaces(order_list[i], node_data, order_list, order_map,
+ child_lists, arc_lists);
+ storeEmbedding(order_list[i], node_data, order_map, pred_map,
+ arc_lists, flip_map);
+ }
+
+ return true;
+ }
+
+ /// \brief Give back the successor of an arc
+ ///
+ /// This function gives back the successor of an arc. It makes
+ /// possible to query the cyclic order of the outgoing arcs from
+ /// a node.
+ Arc next(const Arc& arc) const {
+ return _embedding[arc];
+ }
+
+ /// \brief Give back the calculated embedding map
+ ///
+ /// This function gives back the calculated embedding map, which
+ /// contains the successor of each arc in the cyclic order of the
+ /// outgoing arcs of its source node.
+ const EmbeddingMap& embeddingMap() const {
+ return _embedding;
+ }
+
+ /// \brief Give back \c true if the given edge is in the Kuratowski
+ /// subdivision
+ ///
+ /// This function gives back \c true if the given edge is in the found
+ /// Kuratowski subdivision.
+ /// \pre The \c run() function must be called with \c true parameter
+ /// before using this function.
+ bool kuratowski(const Edge& edge) const {
+ return _kuratowski[edge];
+ }
+
+ private:
+
+ void createChildLists(const TreeMap& tree_map, const OrderMap& order_map,
+ const LowMap& low_map, ChildLists& child_lists) {
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ Node source = n;
+
+ std::vector<Node> targets;
+ for (OutArcIt e(_graph, n); e != INVALID; ++e) {
+ Node target = _graph.target(e);
+
+ if (order_map[source] < order_map[target] && tree_map[e]) {
+ targets.push_back(target);
+ }
+ }
+
+ if (targets.size() == 0) {
+ child_lists[source].first = INVALID;
+ } else if (targets.size() == 1) {
+ child_lists[source].first = targets[0];
+ child_lists[targets[0]].prev = INVALID;
+ child_lists[targets[0]].next = INVALID;
+ } else {
+ radixSort(targets.begin(), targets.end(), mapToFunctor(low_map));
+ for (int i = 1; i < int(targets.size()); ++i) {
+ child_lists[targets[i]].prev = targets[i - 1];
+ child_lists[targets[i - 1]].next = targets[i];
+ }
+ child_lists[targets.back()].next = INVALID;
+ child_lists[targets.front()].prev = INVALID;
+ child_lists[source].first = targets.front();
+ }
+ }
+ }
+
+ void walkUp(const Node& node, Node root, int rorder,
+ const PredMap& pred_map, const LowMap& low_map,
+ const OrderMap& order_map, const OrderList& order_list,
+ NodeData& node_data, MergeRoots& merge_roots) {
+
+ int na, nb;
+ bool da, db;
+
+ na = nb = order_map[node];
+ da = true; db = false;
+
+ while (true) {
+
+ if (node_data[na].visited == rorder) break;
+ if (node_data[nb].visited == rorder) break;
+
+ node_data[na].visited = rorder;
+ node_data[nb].visited = rorder;
+
+ int rn = -1;
+
+ if (na >= int(order_list.size())) {
+ rn = na;
+ } else if (nb >= int(order_list.size())) {
+ rn = nb;
+ }
+
+ if (rn == -1) {
+ int nn;
+
+ nn = da ? node_data[na].prev : node_data[na].next;
+ da = node_data[nn].prev != na;
+ na = nn;
+
+ nn = db ? node_data[nb].prev : node_data[nb].next;
+ db = node_data[nn].prev != nb;
+ nb = nn;
+
+ } else {
+
+ Node rep = order_list[rn - order_list.size()];
+ Node parent = _graph.source(pred_map[rep]);
+
+ if (low_map[rep] < rorder) {
+ merge_roots[parent].push_back(rn);
+ } else {
+ merge_roots[parent].push_front(rn);
+ }
+
+ if (parent != root) {
+ na = nb = order_map[parent];
+ da = true; db = false;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+
+ void walkDown(int rn, int rorder, NodeData& node_data,
+ ArcLists& arc_lists, FlipMap& flip_map,
+ OrderList& order_list, ChildLists& child_lists,
+ AncestorMap& ancestor_map, LowMap& low_map,
+ EmbedArc& embed_arc, MergeRoots& merge_roots) {
+
+ std::vector<std::pair<int, bool> > merge_stack;
+
+ for (int di = 0; di < 2; ++di) {
+ bool rd = di == 0;
+ int pn = rn;
+ int n = rd ? node_data[rn].next : node_data[rn].prev;
+
+ while (n != rn) {
+
+ Node node = order_list[n];
+
+ if (embed_arc[node] != INVALID) {
+
+ // Merging components on the critical path
+ while (!merge_stack.empty()) {
+
+ // Component root
+ int cn = merge_stack.back().first;
+ bool cd = merge_stack.back().second;
+ merge_stack.pop_back();
+
+ // Parent of component
+ int dn = merge_stack.back().first;
+ bool dd = merge_stack.back().second;
+ merge_stack.pop_back();
+
+ Node parent = order_list[dn];
+
+ // Erasing from merge_roots
+ merge_roots[parent].pop_front();
+
+ Node child = order_list[cn - order_list.size()];
+
+ // Erasing from child_lists
+ if (child_lists[child].prev != INVALID) {
+ child_lists[child_lists[child].prev].next =
+ child_lists[child].next;
+ } else {
+ child_lists[parent].first = child_lists[child].next;
+ }
+
+ if (child_lists[child].next != INVALID) {
+ child_lists[child_lists[child].next].prev =
+ child_lists[child].prev;
+ }
+
+ // Merging arcs + flipping
+ Arc de = node_data[dn].first;
+ Arc ce = node_data[cn].first;
+
+ flip_map[order_list[cn - order_list.size()]] = cd != dd;
+ if (cd != dd) {
+ std::swap(arc_lists[ce].prev, arc_lists[ce].next);
+ ce = arc_lists[ce].prev;
+ std::swap(arc_lists[ce].prev, arc_lists[ce].next);
+ }
+
+ {
+ Arc dne = arc_lists[de].next;
+ Arc cne = arc_lists[ce].next;
+
+ arc_lists[de].next = cne;
+ arc_lists[ce].next = dne;
+
+ arc_lists[dne].prev = ce;
+ arc_lists[cne].prev = de;
+ }
+
+ if (dd) {
+ node_data[dn].first = ce;
+ }
+
+ // Merging external faces
+ {
+ int en = cn;
+ cn = cd ? node_data[cn].prev : node_data[cn].next;
+ cd = node_data[cn].next == en;
+
+ if (node_data[cn].prev == node_data[cn].next &&
+ node_data[cn].inverted) {
+ cd = !cd;
+ }
+ }
+
+ if (cd) node_data[cn].next = dn; else node_data[cn].prev = dn;
+ if (dd) node_data[dn].prev = cn; else node_data[dn].next = cn;
+
+ }
+
+ bool d = pn == node_data[n].prev;
+
+ if (node_data[n].prev == node_data[n].next &&
+ node_data[n].inverted) {
+ d = !d;
+ }
+
+ // Add new arc
+ {
+ Arc arc = embed_arc[node];
+ Arc re = node_data[rn].first;
+
+ arc_lists[arc_lists[re].next].prev = arc;
+ arc_lists[arc].next = arc_lists[re].next;
+ arc_lists[arc].prev = re;
+ arc_lists[re].next = arc;
+
+ if (!rd) {
+ node_data[rn].first = arc;
+ }
+
+ Arc rev = _graph.oppositeArc(arc);
+ Arc e = node_data[n].first;
+
+ arc_lists[arc_lists[e].next].prev = rev;
+ arc_lists[rev].next = arc_lists[e].next;
+ arc_lists[rev].prev = e;
+ arc_lists[e].next = rev;
+
+ if (d) {
+ node_data[n].first = rev;
+ }
+
+ }
+
+ // Embedding arc into external face
+ if (rd) node_data[rn].next = n; else node_data[rn].prev = n;
+ if (d) node_data[n].prev = rn; else node_data[n].next = rn;
+ pn = rn;
+
+ embed_arc[order_list[n]] = INVALID;
+ }
+
+ if (!merge_roots[node].empty()) {
+
+ bool d = pn == node_data[n].prev;
+ if (node_data[n].prev == node_data[n].next &&
+ node_data[n].inverted) {
+ d = !d;
+ }
+
+ merge_stack.push_back(std::make_pair(n, d));
+
+ int rn = merge_roots[node].front();
+
+ int xn = node_data[rn].next;
+ Node xnode = order_list[xn];
+
+ int yn = node_data[rn].prev;
+ Node ynode = order_list[yn];
+
+ bool rd;
+ if (!external(xnode, rorder, child_lists, ancestor_map, low_map)) {
+ rd = true;
+ } else if (!external(ynode, rorder, child_lists,
+ ancestor_map, low_map)) {
+ rd = false;
+ } else if (pertinent(xnode, embed_arc, merge_roots)) {
+ rd = true;
+ } else {
+ rd = false;
+ }
+
+ merge_stack.push_back(std::make_pair(rn, rd));
+
+ pn = rn;
+ n = rd ? xn : yn;
+
+ } else if (!external(node, rorder, child_lists,
+ ancestor_map, low_map)) {
+ int nn = (node_data[n].next != pn ?
+ node_data[n].next : node_data[n].prev);
+
+ bool nd = n == node_data[nn].prev;
+
+ if (nd) node_data[nn].prev = pn;
+ else node_data[nn].next = pn;
+
+ if (n == node_data[pn].prev) node_data[pn].prev = nn;
+ else node_data[pn].next = nn;
+
+ node_data[nn].inverted =
+ (node_data[nn].prev == node_data[nn].next && nd != rd);
+
+ n = nn;
+ }
+ else break;
+
+ }
+
+ if (!merge_stack.empty() || n == rn) {
+ break;
+ }
+ }
+ }
+
+ void initFace(const Node& node, ArcLists& arc_lists,
+ NodeData& node_data, const PredMap& pred_map,
+ const OrderMap& order_map, const OrderList& order_list) {
+ int n = order_map[node];
+ int rn = n + order_list.size();
+
+ node_data[n].next = node_data[n].prev = rn;
+ node_data[rn].next = node_data[rn].prev = n;
+
+ node_data[n].visited = order_list.size();
+ node_data[rn].visited = order_list.size();
+
+ node_data[n].inverted = false;
+ node_data[rn].inverted = false;
+
+ Arc arc = pred_map[node];
+ Arc rev = _graph.oppositeArc(arc);
+
+ node_data[rn].first = arc;
+ node_data[n].first = rev;
+
+ arc_lists[arc].prev = arc;
+ arc_lists[arc].next = arc;
+
+ arc_lists[rev].prev = rev;
+ arc_lists[rev].next = rev;
+
+ }
+
+ void mergeRemainingFaces(const Node& node, NodeData& node_data,
+ OrderList& order_list, OrderMap& order_map,
+ ChildLists& child_lists, ArcLists& arc_lists) {
+ while (child_lists[node].first != INVALID) {
+ int dd = order_map[node];
+ Node child = child_lists[node].first;
+ int cd = order_map[child] + order_list.size();
+ child_lists[node].first = child_lists[child].next;
+
+ Arc de = node_data[dd].first;
+ Arc ce = node_data[cd].first;
+
+ if (de != INVALID) {
+ Arc dne = arc_lists[de].next;
+ Arc cne = arc_lists[ce].next;
+
+ arc_lists[de].next = cne;
+ arc_lists[ce].next = dne;
+
+ arc_lists[dne].prev = ce;
+ arc_lists[cne].prev = de;
+ }
+
+ node_data[dd].first = ce;
+
+ }
+ }
+
+ void storeEmbedding(const Node& node, NodeData& node_data,
+ OrderMap& order_map, PredMap& pred_map,
+ ArcLists& arc_lists, FlipMap& flip_map) {
+
+ if (node_data[order_map[node]].first == INVALID) return;
+
+ if (pred_map[node] != INVALID) {
+ Node source = _graph.source(pred_map[node]);
+ flip_map[node] = flip_map[node] != flip_map[source];
+ }
+
+ Arc first = node_data[order_map[node]].first;
+ Arc prev = first;
+
+ Arc arc = flip_map[node] ?
+ arc_lists[prev].prev : arc_lists[prev].next;
+
+ _embedding[prev] = arc;
+
+ while (arc != first) {
+ Arc next = arc_lists[arc].prev == prev ?
+ arc_lists[arc].next : arc_lists[arc].prev;
+ prev = arc; arc = next;
+ _embedding[prev] = arc;
+ }
+ }
+
+
+ bool external(const Node& node, int rorder,
+ ChildLists& child_lists, AncestorMap& ancestor_map,
+ LowMap& low_map) {
+ Node child = child_lists[node].first;
+
+ if (child != INVALID) {
+ if (low_map[child] < rorder) return true;
+ }
+
+ if (ancestor_map[node] < rorder) return true;
+
+ return false;
+ }
+
+ bool pertinent(const Node& node, const EmbedArc& embed_arc,
+ const MergeRoots& merge_roots) {
+ return !merge_roots[node].empty() || embed_arc[node] != INVALID;
+ }
+
+ int lowPoint(const Node& node, OrderMap& order_map, ChildLists& child_lists,
+ AncestorMap& ancestor_map, LowMap& low_map) {
+ int low_point;
+
+ Node child = child_lists[node].first;
+
+ if (child != INVALID) {
+ low_point = low_map[child];
+ } else {
+ low_point = order_map[node];
+ }
+
+ if (low_point > ancestor_map[node]) {
+ low_point = ancestor_map[node];
+ }
+
+ return low_point;
+ }
+
+ int findComponentRoot(Node root, Node node, ChildLists& child_lists,
+ OrderMap& order_map, OrderList& order_list) {
+
+ int order = order_map[root];
+ int norder = order_map[node];
+
+ Node child = child_lists[root].first;
+ while (child != INVALID) {
+ int corder = order_map[child];
+ if (corder > order && corder < norder) {
+ order = corder;
+ }
+ child = child_lists[child].next;
+ }
+ return order + order_list.size();
+ }
+
+ Node findPertinent(Node node, OrderMap& order_map, NodeData& node_data,
+ EmbedArc& embed_arc, MergeRoots& merge_roots) {
+ Node wnode =_graph.target(node_data[order_map[node]].first);
+ while (!pertinent(wnode, embed_arc, merge_roots)) {
+ wnode = _graph.target(node_data[order_map[wnode]].first);
+ }
+ return wnode;
+ }
+
+
+ Node findExternal(Node node, int rorder, OrderMap& order_map,
+ ChildLists& child_lists, AncestorMap& ancestor_map,
+ LowMap& low_map, NodeData& node_data) {
+ Node wnode =_graph.target(node_data[order_map[node]].first);
+ while (!external(wnode, rorder, child_lists, ancestor_map, low_map)) {
+ wnode = _graph.target(node_data[order_map[wnode]].first);
+ }
+ return wnode;
+ }
+
+ void markCommonPath(Node node, int rorder, Node& wnode, Node& znode,
+ OrderList& order_list, OrderMap& order_map,
+ NodeData& node_data, ArcLists& arc_lists,
+ EmbedArc& embed_arc, MergeRoots& merge_roots,
+ ChildLists& child_lists, AncestorMap& ancestor_map,
+ LowMap& low_map) {
+
+ Node cnode = node;
+ Node pred = INVALID;
+
+ while (true) {
+
+ bool pert = pertinent(cnode, embed_arc, merge_roots);
+ bool ext = external(cnode, rorder, child_lists, ancestor_map, low_map);
+
+ if (pert && ext) {
+ if (!merge_roots[cnode].empty()) {
+ int cn = merge_roots[cnode].back();
+
+ if (low_map[order_list[cn - order_list.size()]] < rorder) {
+ Arc arc = node_data[cn].first;
+ _kuratowski.set(arc, true);
+
+ pred = cnode;
+ cnode = _graph.target(arc);
+
+ continue;
+ }
+ }
+ wnode = znode = cnode;
+ return;
+
+ } else if (pert) {
+ wnode = cnode;
+
+ while (!external(cnode, rorder, child_lists, ancestor_map, low_map)) {
+ Arc arc = node_data[order_map[cnode]].first;
+
+ if (_graph.target(arc) == pred) {
+ arc = arc_lists[arc].next;
+ }
+ _kuratowski.set(arc, true);
+
+ Node next = _graph.target(arc);
+ pred = cnode; cnode = next;
+ }
+
+ znode = cnode;
+ return;
+
+ } else if (ext) {
+ znode = cnode;
+
+ while (!pertinent(cnode, embed_arc, merge_roots)) {
+ Arc arc = node_data[order_map[cnode]].first;
+
+ if (_graph.target(arc) == pred) {
+ arc = arc_lists[arc].next;
+ }
+ _kuratowski.set(arc, true);
+
+ Node next = _graph.target(arc);
+ pred = cnode; cnode = next;
+ }
+
+ wnode = cnode;
+ return;
+
+ } else {
+ Arc arc = node_data[order_map[cnode]].first;
+
+ if (_graph.target(arc) == pred) {
+ arc = arc_lists[arc].next;
+ }
+ _kuratowski.set(arc, true);
+
+ Node next = _graph.target(arc);
+ pred = cnode; cnode = next;
+ }
+
+ }
+
+ }
+
+ void orientComponent(Node root, int rn, OrderMap& order_map,
+ PredMap& pred_map, NodeData& node_data,
+ ArcLists& arc_lists, FlipMap& flip_map,
+ TypeMap& type_map) {
+ node_data[order_map[root]].first = node_data[rn].first;
+ type_map[root] = 1;
+
+ std::vector<Node> st, qu;
+
+ st.push_back(root);
+ while (!st.empty()) {
+ Node node = st.back();
+ st.pop_back();
+ qu.push_back(node);
+
+ Arc arc = node_data[order_map[node]].first;
+
+ if (type_map[_graph.target(arc)] == 0) {
+ st.push_back(_graph.target(arc));
+ type_map[_graph.target(arc)] = 1;
+ }
+
+ Arc last = arc, pred = arc;
+ arc = arc_lists[arc].next;
+ while (arc != last) {
+
+ if (type_map[_graph.target(arc)] == 0) {
+ st.push_back(_graph.target(arc));
+ type_map[_graph.target(arc)] = 1;
+ }
+
+ Arc next = arc_lists[arc].next != pred ?
+ arc_lists[arc].next : arc_lists[arc].prev;
+ pred = arc; arc = next;
+ }
+
+ }
+
+ type_map[root] = 2;
+ flip_map[root] = false;
+
+ for (int i = 1; i < int(qu.size()); ++i) {
+
+ Node node = qu[i];
+
+ while (type_map[node] != 2) {
+ st.push_back(node);
+ type_map[node] = 2;
+ node = _graph.source(pred_map[node]);
+ }
+
+ bool flip = flip_map[node];
+
+ while (!st.empty()) {
+ node = st.back();
+ st.pop_back();
+
+ flip_map[node] = flip != flip_map[node];
+ flip = flip_map[node];
+
+ if (flip) {
+ Arc arc = node_data[order_map[node]].first;
+ std::swap(arc_lists[arc].prev, arc_lists[arc].next);
+ arc = arc_lists[arc].prev;
+ std::swap(arc_lists[arc].prev, arc_lists[arc].next);
+ node_data[order_map[node]].first = arc;
+ }
+ }
+ }
+
+ for (int i = 0; i < int(qu.size()); ++i) {
+
+ Arc arc = node_data[order_map[qu[i]]].first;
+ Arc last = arc, pred = arc;
+
+ arc = arc_lists[arc].next;
+ while (arc != last) {
+
+ if (arc_lists[arc].next == pred) {
+ std::swap(arc_lists[arc].next, arc_lists[arc].prev);
+ }
+ pred = arc; arc = arc_lists[arc].next;
+ }
+
+ }
+ }
+
+ void setFaceFlags(Node root, Node wnode, Node ynode, Node xnode,
+ OrderMap& order_map, NodeData& node_data,
+ TypeMap& type_map) {
+ Node node = _graph.target(node_data[order_map[root]].first);
+
+ while (node != ynode) {
+ type_map[node] = HIGHY;
+ node = _graph.target(node_data[order_map[node]].first);
+ }
+
+ while (node != wnode) {
+ type_map[node] = LOWY;
+ node = _graph.target(node_data[order_map[node]].first);
+ }
+
+ node = _graph.target(node_data[order_map[wnode]].first);
+
+ while (node != xnode) {
+ type_map[node] = LOWX;
+ node = _graph.target(node_data[order_map[node]].first);
+ }
+ type_map[node] = LOWX;
+
+ node = _graph.target(node_data[order_map[xnode]].first);
+ while (node != root) {
+ type_map[node] = HIGHX;
+ node = _graph.target(node_data[order_map[node]].first);
+ }
+
+ type_map[wnode] = PERTINENT;
+ type_map[root] = ROOT;
+ }
+
+ void findInternalPath(std::vector<Arc>& ipath,
+ Node wnode, Node root, TypeMap& type_map,
+ OrderMap& order_map, NodeData& node_data,
+ ArcLists& arc_lists) {
+ std::vector<Arc> st;
+
+ Node node = wnode;
+
+ while (node != root) {
+ Arc arc = arc_lists[node_data[order_map[node]].first].next;
+ st.push_back(arc);
+ node = _graph.target(arc);
+ }
+
+ while (true) {
+ Arc arc = st.back();
+ if (type_map[_graph.target(arc)] == LOWX ||
+ type_map[_graph.target(arc)] == HIGHX) {
+ break;
+ }
+ if (type_map[_graph.target(arc)] == 2) {
+ type_map[_graph.target(arc)] = 3;
+
+ arc = arc_lists[_graph.oppositeArc(arc)].next;
+ st.push_back(arc);
+ } else {
+ st.pop_back();
+ arc = arc_lists[arc].next;
+
+ while (_graph.oppositeArc(arc) == st.back()) {
+ arc = st.back();
+ st.pop_back();
+ arc = arc_lists[arc].next;
+ }
+ st.push_back(arc);
+ }
+ }
+
+ for (int i = 0; i < int(st.size()); ++i) {
+ if (type_map[_graph.target(st[i])] != LOWY &&
+ type_map[_graph.target(st[i])] != HIGHY) {
+ for (; i < int(st.size()); ++i) {
+ ipath.push_back(st[i]);
+ }
+ }
+ }
+ }
+
+ void setInternalFlags(std::vector<Arc>& ipath, TypeMap& type_map) {
+ for (int i = 1; i < int(ipath.size()); ++i) {
+ type_map[_graph.source(ipath[i])] = INTERNAL;
+ }
+ }
+
+ void findPilePath(std::vector<Arc>& ppath,
+ Node root, TypeMap& type_map, OrderMap& order_map,
+ NodeData& node_data, ArcLists& arc_lists) {
+ std::vector<Arc> st;
+
+ st.push_back(_graph.oppositeArc(node_data[order_map[root]].first));
+ st.push_back(node_data[order_map[root]].first);
+
+ while (st.size() > 1) {
+ Arc arc = st.back();
+ if (type_map[_graph.target(arc)] == INTERNAL) {
+ break;
+ }
+ if (type_map[_graph.target(arc)] == 3) {
+ type_map[_graph.target(arc)] = 4;
+
+ arc = arc_lists[_graph.oppositeArc(arc)].next;
+ st.push_back(arc);
+ } else {
+ st.pop_back();
+ arc = arc_lists[arc].next;
+
+ while (!st.empty() && _graph.oppositeArc(arc) == st.back()) {
+ arc = st.back();
+ st.pop_back();
+ arc = arc_lists[arc].next;
+ }
+ st.push_back(arc);
+ }
+ }
+
+ for (int i = 1; i < int(st.size()); ++i) {
+ ppath.push_back(st[i]);
+ }
+ }
+
+
+ int markExternalPath(Node node, OrderMap& order_map,
+ ChildLists& child_lists, PredMap& pred_map,
+ AncestorMap& ancestor_map, LowMap& low_map) {
+ int lp = lowPoint(node, order_map, child_lists,
+ ancestor_map, low_map);
+
+ if (ancestor_map[node] != lp) {
+ node = child_lists[node].first;
+ _kuratowski[pred_map[node]] = true;
+
+ while (ancestor_map[node] != lp) {
+ for (OutArcIt e(_graph, node); e != INVALID; ++e) {
+ Node tnode = _graph.target(e);
+ if (order_map[tnode] > order_map[node] && low_map[tnode] == lp) {
+ node = tnode;
+ _kuratowski[e] = true;
+ break;
+ }
+ }
+ }
+ }
+
+ for (OutArcIt e(_graph, node); e != INVALID; ++e) {
+ if (order_map[_graph.target(e)] == lp) {
+ _kuratowski[e] = true;
+ break;
+ }
+ }
+
+ return lp;
+ }
+
+ void markPertinentPath(Node node, OrderMap& order_map,
+ NodeData& node_data, ArcLists& arc_lists,
+ EmbedArc& embed_arc, MergeRoots& merge_roots) {
+ while (embed_arc[node] == INVALID) {
+ int n = merge_roots[node].front();
+ Arc arc = node_data[n].first;
+
+ _kuratowski.set(arc, true);
+
+ Node pred = node;
+ node = _graph.target(arc);
+ while (!pertinent(node, embed_arc, merge_roots)) {
+ arc = node_data[order_map[node]].first;
+ if (_graph.target(arc) == pred) {
+ arc = arc_lists[arc].next;
+ }
+ _kuratowski.set(arc, true);
+ pred = node;
+ node = _graph.target(arc);
+ }
+ }
+ _kuratowski.set(embed_arc[node], true);
+ }
+
+ void markPredPath(Node node, Node snode, PredMap& pred_map) {
+ while (node != snode) {
+ _kuratowski.set(pred_map[node], true);
+ node = _graph.source(pred_map[node]);
+ }
+ }
+
+ void markFacePath(Node ynode, Node xnode,
+ OrderMap& order_map, NodeData& node_data) {
+ Arc arc = node_data[order_map[ynode]].first;
+ Node node = _graph.target(arc);
+ _kuratowski.set(arc, true);
+
+ while (node != xnode) {
+ arc = node_data[order_map[node]].first;
+ _kuratowski.set(arc, true);
+ node = _graph.target(arc);
+ }
+ }
+
+ void markInternalPath(std::vector<Arc>& path) {
+ for (int i = 0; i < int(path.size()); ++i) {
+ _kuratowski.set(path[i], true);
+ }
+ }
+
+ void markPilePath(std::vector<Arc>& path) {
+ for (int i = 0; i < int(path.size()); ++i) {
+ _kuratowski.set(path[i], true);
+ }
+ }
+
+ void isolateKuratowski(Arc arc, NodeData& node_data,
+ ArcLists& arc_lists, FlipMap& flip_map,
+ OrderMap& order_map, OrderList& order_list,
+ PredMap& pred_map, ChildLists& child_lists,
+ AncestorMap& ancestor_map, LowMap& low_map,
+ EmbedArc& embed_arc, MergeRoots& merge_roots) {
+
+ Node root = _graph.source(arc);
+ Node enode = _graph.target(arc);
+
+ int rorder = order_map[root];
+
+ TypeMap type_map(_graph, 0);
+
+ int rn = findComponentRoot(root, enode, child_lists,
+ order_map, order_list);
+
+ Node xnode = order_list[node_data[rn].next];
+ Node ynode = order_list[node_data[rn].prev];
+
+ // Minor-A
+ {
+ while (!merge_roots[xnode].empty() || !merge_roots[ynode].empty()) {
+
+ if (!merge_roots[xnode].empty()) {
+ root = xnode;
+ rn = merge_roots[xnode].front();
+ } else {
+ root = ynode;
+ rn = merge_roots[ynode].front();
+ }
+
+ xnode = order_list[node_data[rn].next];
+ ynode = order_list[node_data[rn].prev];
+ }
+
+ if (root != _graph.source(arc)) {
+ orientComponent(root, rn, order_map, pred_map,
+ node_data, arc_lists, flip_map, type_map);
+ markFacePath(root, root, order_map, node_data);
+ int xlp = markExternalPath(xnode, order_map, child_lists,
+ pred_map, ancestor_map, low_map);
+ int ylp = markExternalPath(ynode, order_map, child_lists,
+ pred_map, ancestor_map, low_map);
+ markPredPath(root, order_list[xlp < ylp ? xlp : ylp], pred_map);
+ Node lwnode = findPertinent(ynode, order_map, node_data,
+ embed_arc, merge_roots);
+
+ markPertinentPath(lwnode, order_map, node_data, arc_lists,
+ embed_arc, merge_roots);
+
+ return;
+ }
+ }
+
+ orientComponent(root, rn, order_map, pred_map,
+ node_data, arc_lists, flip_map, type_map);
+
+ Node wnode = findPertinent(ynode, order_map, node_data,
+ embed_arc, merge_roots);
+ setFaceFlags(root, wnode, ynode, xnode, order_map, node_data, type_map);
+
+
+ //Minor-B
+ if (!merge_roots[wnode].empty()) {
+ int cn = merge_roots[wnode].back();
+ Node rep = order_list[cn - order_list.size()];
+ if (low_map[rep] < rorder) {
+ markFacePath(root, root, order_map, node_data);
+ int xlp = markExternalPath(xnode, order_map, child_lists,
+ pred_map, ancestor_map, low_map);
+ int ylp = markExternalPath(ynode, order_map, child_lists,
+ pred_map, ancestor_map, low_map);
+
+ Node lwnode, lznode;
+ markCommonPath(wnode, rorder, lwnode, lznode, order_list,
+ order_map, node_data, arc_lists, embed_arc,
+ merge_roots, child_lists, ancestor_map, low_map);
+
+ markPertinentPath(lwnode, order_map, node_data, arc_lists,
+ embed_arc, merge_roots);
+ int zlp = markExternalPath(lznode, order_map, child_lists,
+ pred_map, ancestor_map, low_map);
+
+ int minlp = xlp < ylp ? xlp : ylp;
+ if (zlp < minlp) minlp = zlp;
+
+ int maxlp = xlp > ylp ? xlp : ylp;
+ if (zlp > maxlp) maxlp = zlp;
+
+ markPredPath(order_list[maxlp], order_list[minlp], pred_map);
+
+ return;
+ }
+ }
+
+ Node pxnode, pynode;
+ std::vector<Arc> ipath;
+ findInternalPath(ipath, wnode, root, type_map, order_map,
+ node_data, arc_lists);
+ setInternalFlags(ipath, type_map);
+ pynode = _graph.source(ipath.front());
+ pxnode = _graph.target(ipath.back());
+
+ wnode = findPertinent(pynode, order_map, node_data,
+ embed_arc, merge_roots);
+
+ // Minor-C
+ {
+ if (type_map[_graph.source(ipath.front())] == HIGHY) {
+ if (type_map[_graph.target(ipath.back())] == HIGHX) {
+ markFacePath(xnode, pxnode, order_map, node_data);
+ }
+ markFacePath(root, xnode, order_map, node_data);
+ markPertinentPath(wnode, order_map, node_data, arc_lists,
+ embed_arc, merge_roots);
+ markInternalPath(ipath);
+ int xlp = markExternalPath(xnode, order_map, child_lists,
+ pred_map, ancestor_map, low_map);
+ int ylp = markExternalPath(ynode, order_map, child_lists,
+ pred_map, ancestor_map, low_map);
+ markPredPath(root, order_list[xlp < ylp ? xlp : ylp], pred_map);
+ return;
+ }
+
+ if (type_map[_graph.target(ipath.back())] == HIGHX) {
+ markFacePath(ynode, root, order_map, node_data);
+ markPertinentPath(wnode, order_map, node_data, arc_lists,
+ embed_arc, merge_roots);
+ markInternalPath(ipath);
+ int xlp = markExternalPath(xnode, order_map, child_lists,
+ pred_map, ancestor_map, low_map);
+ int ylp = markExternalPath(ynode, order_map, child_lists,
+ pred_map, ancestor_map, low_map);
+ markPredPath(root, order_list[xlp < ylp ? xlp : ylp], pred_map);
+ return;
+ }
+ }
+
+ std::vector<Arc> ppath;
+ findPilePath(ppath, root, type_map, order_map, node_data, arc_lists);
+
+ // Minor-D
+ if (!ppath.empty()) {
+ markFacePath(ynode, xnode, order_map, node_data);
+ markPertinentPath(wnode, order_map, node_data, arc_lists,
+ embed_arc, merge_roots);
+ markPilePath(ppath);
+ markInternalPath(ipath);
+ int xlp = markExternalPath(xnode, order_map, child_lists,
+ pred_map, ancestor_map, low_map);
+ int ylp = markExternalPath(ynode, order_map, child_lists,
+ pred_map, ancestor_map, low_map);
+ markPredPath(root, order_list[xlp < ylp ? xlp : ylp], pred_map);
+ return;
+ }
+
+ // Minor-E*
+ {
+
+ if (!external(wnode, rorder, child_lists, ancestor_map, low_map)) {
+ Node znode = findExternal(pynode, rorder, order_map,
+ child_lists, ancestor_map,
+ low_map, node_data);
+
+ if (type_map[znode] == LOWY) {
+ markFacePath(root, xnode, order_map, node_data);
+ markPertinentPath(wnode, order_map, node_data, arc_lists,
+ embed_arc, merge_roots);
+ markInternalPath(ipath);
+ int xlp = markExternalPath(xnode, order_map, child_lists,
+ pred_map, ancestor_map, low_map);
+ int zlp = markExternalPath(znode, order_map, child_lists,
+ pred_map, ancestor_map, low_map);
+ markPredPath(root, order_list[xlp < zlp ? xlp : zlp], pred_map);
+ } else {
+ markFacePath(ynode, root, order_map, node_data);
+ markPertinentPath(wnode, order_map, node_data, arc_lists,
+ embed_arc, merge_roots);
+ markInternalPath(ipath);
+ int ylp = markExternalPath(ynode, order_map, child_lists,
+ pred_map, ancestor_map, low_map);
+ int zlp = markExternalPath(znode, order_map, child_lists,
+ pred_map, ancestor_map, low_map);
+ markPredPath(root, order_list[ylp < zlp ? ylp : zlp], pred_map);
+ }
+ return;
+ }
+
+ int xlp = markExternalPath(xnode, order_map, child_lists,
+ pred_map, ancestor_map, low_map);
+ int ylp = markExternalPath(ynode, order_map, child_lists,
+ pred_map, ancestor_map, low_map);
+ int wlp = markExternalPath(wnode, order_map, child_lists,
+ pred_map, ancestor_map, low_map);
+
+ if (wlp > xlp && wlp > ylp) {
+ markFacePath(root, root, order_map, node_data);
+ markPredPath(root, order_list[xlp < ylp ? xlp : ylp], pred_map);
+ return;
+ }
+
+ markInternalPath(ipath);
+ markPertinentPath(wnode, order_map, node_data, arc_lists,
+ embed_arc, merge_roots);
+
+ if (xlp > ylp && xlp > wlp) {
+ markFacePath(root, pynode, order_map, node_data);
+ markFacePath(wnode, xnode, order_map, node_data);
+ markPredPath(root, order_list[ylp < wlp ? ylp : wlp], pred_map);
+ return;
+ }
+
+ if (ylp > xlp && ylp > wlp) {
+ markFacePath(pxnode, root, order_map, node_data);
+ markFacePath(ynode, wnode, order_map, node_data);
+ markPredPath(root, order_list[xlp < wlp ? xlp : wlp], pred_map);
+ return;
+ }
+
+ if (pynode != ynode) {
+ markFacePath(pxnode, wnode, order_map, node_data);
+
+ int minlp = xlp < ylp ? xlp : ylp;
+ if (wlp < minlp) minlp = wlp;
+
+ int maxlp = xlp > ylp ? xlp : ylp;
+ if (wlp > maxlp) maxlp = wlp;
+
+ markPredPath(order_list[maxlp], order_list[minlp], pred_map);
+ return;
+ }
+
+ if (pxnode != xnode) {
+ markFacePath(wnode, pynode, order_map, node_data);
+
+ int minlp = xlp < ylp ? xlp : ylp;
+ if (wlp < minlp) minlp = wlp;
+
+ int maxlp = xlp > ylp ? xlp : ylp;
+ if (wlp > maxlp) maxlp = wlp;
+
+ markPredPath(order_list[maxlp], order_list[minlp], pred_map);
+ return;
+ }
+
+ markFacePath(root, root, order_map, node_data);
+ int minlp = xlp < ylp ? xlp : ylp;
+ if (wlp < minlp) minlp = wlp;
+ markPredPath(root, order_list[minlp], pred_map);
+ return;
+ }
+
+ }
+
+ };
+
+ namespace _planarity_bits {
+
+ template <typename Graph, typename EmbeddingMap>
+ void makeConnected(Graph& graph, EmbeddingMap& embedding) {
+ DfsVisitor<Graph> null_visitor;
+ DfsVisit<Graph, DfsVisitor<Graph> > dfs(graph, null_visitor);
+ dfs.init();
+
+ typename Graph::Node u = INVALID;
+ for (typename Graph::NodeIt n(graph); n != INVALID; ++n) {
+ if (!dfs.reached(n)) {
+ dfs.addSource(n);
+ dfs.start();
+ if (u == INVALID) {
+ u = n;
+ } else {
+ typename Graph::Node v = n;
+
+ typename Graph::Arc ue = typename Graph::OutArcIt(graph, u);
+ typename Graph::Arc ve = typename Graph::OutArcIt(graph, v);
+
+ typename Graph::Arc e = graph.direct(graph.addEdge(u, v), true);
+
+ if (ue != INVALID) {
+ embedding[e] = embedding[ue];
+ embedding[ue] = e;
+ } else {
+ embedding[e] = e;
+ }
+
+ if (ve != INVALID) {
+ embedding[graph.oppositeArc(e)] = embedding[ve];
+ embedding[ve] = graph.oppositeArc(e);
+ } else {
+ embedding[graph.oppositeArc(e)] = graph.oppositeArc(e);
+ }
+ }
+ }
+ }
+ }
+
+ template <typename Graph, typename EmbeddingMap>
+ void makeBiNodeConnected(Graph& graph, EmbeddingMap& embedding) {
+ typename Graph::template ArcMap<bool> processed(graph);
+
+ std::vector<typename Graph::Arc> arcs;
+ for (typename Graph::ArcIt e(graph); e != INVALID; ++e) {
+ arcs.push_back(e);
+ }
+
+ IterableBoolMap<Graph, typename Graph::Node> visited(graph, false);
+
+ for (int i = 0; i < int(arcs.size()); ++i) {
+ typename Graph::Arc pp = arcs[i];
+ if (processed[pp]) continue;
+
+ typename Graph::Arc e = embedding[graph.oppositeArc(pp)];
+ processed[e] = true;
+ visited.set(graph.source(e), true);
+
+ typename Graph::Arc p = e, l = e;
+ e = embedding[graph.oppositeArc(e)];
+
+ while (e != l) {
+ processed[e] = true;
+
+ if (visited[graph.source(e)]) {
+
+ typename Graph::Arc n =
+ graph.direct(graph.addEdge(graph.source(p),
+ graph.target(e)), true);
+ embedding[n] = p;
+ embedding[graph.oppositeArc(pp)] = n;
+
+ embedding[graph.oppositeArc(n)] =
+ embedding[graph.oppositeArc(e)];
+ embedding[graph.oppositeArc(e)] =
+ graph.oppositeArc(n);
+
+ p = n;
+ e = embedding[graph.oppositeArc(n)];
+ } else {
+ visited.set(graph.source(e), true);
+ pp = p;
+ p = e;
+ e = embedding[graph.oppositeArc(e)];
+ }
+ }
+ visited.setAll(false);
+ }
+ }
+
+
+ template <typename Graph, typename EmbeddingMap>
+ void makeMaxPlanar(Graph& graph, EmbeddingMap& embedding) {
+
+ typename Graph::template NodeMap<int> degree(graph);
+
+ for (typename Graph::NodeIt n(graph); n != INVALID; ++n) {
+ degree[n] = countIncEdges(graph, n);
+ }
+
+ typename Graph::template ArcMap<bool> processed(graph);
+ IterableBoolMap<Graph, typename Graph::Node> visited(graph, false);
+
+ std::vector<typename Graph::Arc> arcs;
+ for (typename Graph::ArcIt e(graph); e != INVALID; ++e) {
+ arcs.push_back(e);
+ }
+
+ for (int i = 0; i < int(arcs.size()); ++i) {
+ typename Graph::Arc e = arcs[i];
+
+ if (processed[e]) continue;
+ processed[e] = true;
+
+ typename Graph::Arc mine = e;
+ int mind = degree[graph.source(e)];
+
+ int face_size = 1;
+
+ typename Graph::Arc l = e;
+ e = embedding[graph.oppositeArc(e)];
+ while (l != e) {
+ processed[e] = true;
+
+ ++face_size;
+
+ if (degree[graph.source(e)] < mind) {
+ mine = e;
+ mind = degree[graph.source(e)];
+ }
+
+ e = embedding[graph.oppositeArc(e)];
+ }
+
+ if (face_size < 4) {
+ continue;
+ }
+
+ typename Graph::Node s = graph.source(mine);
+ for (typename Graph::OutArcIt e(graph, s); e != INVALID; ++e) {
+ visited.set(graph.target(e), true);
+ }
+
+ typename Graph::Arc oppe = INVALID;
+
+ e = embedding[graph.oppositeArc(mine)];
+ e = embedding[graph.oppositeArc(e)];
+ while (graph.target(e) != s) {
+ if (visited[graph.source(e)]) {
+ oppe = e;
+ break;
+ }
+ e = embedding[graph.oppositeArc(e)];
+ }
+ visited.setAll(false);
+
+ if (oppe == INVALID) {
+
+ e = embedding[graph.oppositeArc(mine)];
+ typename Graph::Arc pn = mine, p = e;
+
+ e = embedding[graph.oppositeArc(e)];
+ while (graph.target(e) != s) {
+ typename Graph::Arc n =
+ graph.direct(graph.addEdge(s, graph.source(e)), true);
+
+ embedding[n] = pn;
+ embedding[graph.oppositeArc(n)] = e;
+ embedding[graph.oppositeArc(p)] = graph.oppositeArc(n);
+
+ pn = n;
+
+ p = e;
+ e = embedding[graph.oppositeArc(e)];
+ }
+
+ embedding[graph.oppositeArc(e)] = pn;
+
+ } else {
+
+ mine = embedding[graph.oppositeArc(mine)];
+ s = graph.source(mine);
+ oppe = embedding[graph.oppositeArc(oppe)];
+ typename Graph::Node t = graph.source(oppe);
+
+ typename Graph::Arc ce = graph.direct(graph.addEdge(s, t), true);
+ embedding[ce] = mine;
+ embedding[graph.oppositeArc(ce)] = oppe;
+
+ typename Graph::Arc pn = ce, p = oppe;
+ e = embedding[graph.oppositeArc(oppe)];
+ while (graph.target(e) != s) {
+ typename Graph::Arc n =
+ graph.direct(graph.addEdge(s, graph.source(e)), true);
+
+ embedding[n] = pn;
+ embedding[graph.oppositeArc(n)] = e;
+ embedding[graph.oppositeArc(p)] = graph.oppositeArc(n);
+
+ pn = n;
+
+ p = e;
+ e = embedding[graph.oppositeArc(e)];
+
+ }
+ embedding[graph.oppositeArc(e)] = pn;
+
+ pn = graph.oppositeArc(ce), p = mine;
+ e = embedding[graph.oppositeArc(mine)];
+ while (graph.target(e) != t) {
+ typename Graph::Arc n =
+ graph.direct(graph.addEdge(t, graph.source(e)), true);
+
+ embedding[n] = pn;
+ embedding[graph.oppositeArc(n)] = e;
+ embedding[graph.oppositeArc(p)] = graph.oppositeArc(n);
+
+ pn = n;
+
+ p = e;
+ e = embedding[graph.oppositeArc(e)];
+
+ }
+ embedding[graph.oppositeArc(e)] = pn;
+ }
+ }
+ }
+
+ }
+
+ /// \ingroup planar
+ ///
+ /// \brief Schnyder's planar drawing algorithm
+ ///
+ /// The planar drawing algorithm calculates positions for the nodes
+ /// in the plane. These coordinates satisfy that if the edges are
+ /// represented with straight lines, then they will not intersect
+ /// each other.
+ ///
+ /// Scnyder's algorithm embeds the graph on an \c (n-2)x(n-2) size grid,
+ /// i.e. each node will be located in the \c [0..n-2]x[0..n-2] square.
+ /// The time complexity of the algorithm is O(n).
+ ///
+ /// \see PlanarEmbedding
+ template <typename Graph>
+ class PlanarDrawing {
+ public:
+
+ TEMPLATE_GRAPH_TYPEDEFS(Graph);
+
+ /// \brief The point type for storing coordinates
+ typedef dim2::Point<int> Point;
+ /// \brief The map type for storing the coordinates of the nodes
+ typedef typename Graph::template NodeMap<Point> PointMap;
+
+
+ /// \brief Constructor
+ ///
+ /// Constructor
+ /// \pre The graph must be simple, i.e. it should not
+ /// contain parallel or loop arcs.
+ PlanarDrawing(const Graph& graph)
+ : _graph(graph), _point_map(graph) {}
+
+ private:
+
+ template <typename AuxGraph, typename AuxEmbeddingMap>
+ void drawing(const AuxGraph& graph,
+ const AuxEmbeddingMap& next,
+ PointMap& point_map) {
+ TEMPLATE_GRAPH_TYPEDEFS(AuxGraph);
+
+ typename AuxGraph::template ArcMap<Arc> prev(graph);
+
+ for (NodeIt n(graph); n != INVALID; ++n) {
+ Arc e = OutArcIt(graph, n);
+
+ Arc p = e, l = e;
+
+ e = next[e];
+ while (e != l) {
+ prev[e] = p;
+ p = e;
+ e = next[e];
+ }
+ prev[e] = p;
+ }
+
+ Node anode, bnode, cnode;
+
+ {
+ Arc e = ArcIt(graph);
+ anode = graph.source(e);
+ bnode = graph.target(e);
+ cnode = graph.target(next[graph.oppositeArc(e)]);
+ }
+
+ IterableBoolMap<AuxGraph, Node> proper(graph, false);
+ typename AuxGraph::template NodeMap<int> conn(graph, -1);
+
+ conn[anode] = conn[bnode] = -2;
+ {
+ for (OutArcIt e(graph, anode); e != INVALID; ++e) {
+ Node m = graph.target(e);
+ if (conn[m] == -1) {
+ conn[m] = 1;
+ }
+ }
+ conn[cnode] = 2;
+
+ for (OutArcIt e(graph, bnode); e != INVALID; ++e) {
+ Node m = graph.target(e);
+ if (conn[m] == -1) {
+ conn[m] = 1;
+ } else if (conn[m] != -2) {
+ conn[m] += 1;
+ Arc pe = graph.oppositeArc(e);
+ if (conn[graph.target(next[pe])] == -2) {
+ conn[m] -= 1;
+ }
+ if (conn[graph.target(prev[pe])] == -2) {
+ conn[m] -= 1;
+ }
+
+ proper.set(m, conn[m] == 1);
+ }
+ }
+ }
+
+
+ typename AuxGraph::template ArcMap<int> angle(graph, -1);
+
+ while (proper.trueNum() != 0) {
+ Node n = typename IterableBoolMap<AuxGraph, Node>::TrueIt(proper);
+ proper.set(n, false);
+ conn[n] = -2;
+
+ for (OutArcIt e(graph, n); e != INVALID; ++e) {
+ Node m = graph.target(e);
+ if (conn[m] == -1) {
+ conn[m] = 1;
+ } else if (conn[m] != -2) {
+ conn[m] += 1;
+ Arc pe = graph.oppositeArc(e);
+ if (conn[graph.target(next[pe])] == -2) {
+ conn[m] -= 1;
+ }
+ if (conn[graph.target(prev[pe])] == -2) {
+ conn[m] -= 1;
+ }
+
+ proper.set(m, conn[m] == 1);
+ }
+ }
+
+ {
+ Arc e = OutArcIt(graph, n);
+ Arc p = e, l = e;
+
+ e = next[e];
+ while (e != l) {
+
+ if (conn[graph.target(e)] == -2 && conn[graph.target(p)] == -2) {
+ Arc f = e;
+ angle[f] = 0;
+ f = next[graph.oppositeArc(f)];
+ angle[f] = 1;
+ f = next[graph.oppositeArc(f)];
+ angle[f] = 2;
+ }
+
+ p = e;
+ e = next[e];
+ }
+
+ if (conn[graph.target(e)] == -2 && conn[graph.target(p)] == -2) {
+ Arc f = e;
+ angle[f] = 0;
+ f = next[graph.oppositeArc(f)];
+ angle[f] = 1;
+ f = next[graph.oppositeArc(f)];
+ angle[f] = 2;
+ }
+ }
+ }
+
+ typename AuxGraph::template NodeMap<Node> apred(graph, INVALID);
+ typename AuxGraph::template NodeMap<Node> bpred(graph, INVALID);
+ typename AuxGraph::template NodeMap<Node> cpred(graph, INVALID);
+
+ typename AuxGraph::template NodeMap<int> apredid(graph, -1);
+ typename AuxGraph::template NodeMap<int> bpredid(graph, -1);
+ typename AuxGraph::template NodeMap<int> cpredid(graph, -1);
+
+ for (ArcIt e(graph); e != INVALID; ++e) {
+ if (angle[e] == angle[next[e]]) {
+ switch (angle[e]) {
+ case 2:
+ apred[graph.target(e)] = graph.source(e);
+ apredid[graph.target(e)] = graph.id(graph.source(e));
+ break;
+ case 1:
+ bpred[graph.target(e)] = graph.source(e);
+ bpredid[graph.target(e)] = graph.id(graph.source(e));
+ break;
+ case 0:
+ cpred[graph.target(e)] = graph.source(e);
+ cpredid[graph.target(e)] = graph.id(graph.source(e));
+ break;
+ }
+ }
+ }
+
+ cpred[anode] = INVALID;
+ cpred[bnode] = INVALID;
+
+ std::vector<Node> aorder, border, corder;
+
+ {
+ typename AuxGraph::template NodeMap<bool> processed(graph, false);
+ std::vector<Node> st;
+ for (NodeIt n(graph); n != INVALID; ++n) {
+ if (!processed[n] && n != bnode && n != cnode) {
+ st.push_back(n);
+ processed[n] = true;
+ Node m = apred[n];
+ while (m != INVALID && !processed[m]) {
+ st.push_back(m);
+ processed[m] = true;
+ m = apred[m];
+ }
+ while (!st.empty()) {
+ aorder.push_back(st.back());
+ st.pop_back();
+ }
+ }
+ }
+ }
+
+ {
+ typename AuxGraph::template NodeMap<bool> processed(graph, false);
+ std::vector<Node> st;
+ for (NodeIt n(graph); n != INVALID; ++n) {
+ if (!processed[n] && n != cnode && n != anode) {
+ st.push_back(n);
+ processed[n] = true;
+ Node m = bpred[n];
+ while (m != INVALID && !processed[m]) {
+ st.push_back(m);
+ processed[m] = true;
+ m = bpred[m];
+ }
+ while (!st.empty()) {
+ border.push_back(st.back());
+ st.pop_back();
+ }
+ }
+ }
+ }
+
+ {
+ typename AuxGraph::template NodeMap<bool> processed(graph, false);
+ std::vector<Node> st;
+ for (NodeIt n(graph); n != INVALID; ++n) {
+ if (!processed[n] && n != anode && n != bnode) {
+ st.push_back(n);
+ processed[n] = true;
+ Node m = cpred[n];
+ while (m != INVALID && !processed[m]) {
+ st.push_back(m);
+ processed[m] = true;
+ m = cpred[m];
+ }
+ while (!st.empty()) {
+ corder.push_back(st.back());
+ st.pop_back();
+ }
+ }
+ }
+ }
+
+ typename AuxGraph::template NodeMap<int> atree(graph, 0);
+ for (int i = aorder.size() - 1; i >= 0; --i) {
+ Node n = aorder[i];
+ atree[n] = 1;
+ for (OutArcIt e(graph, n); e != INVALID; ++e) {
+ if (apred[graph.target(e)] == n) {
+ atree[n] += atree[graph.target(e)];
+ }
+ }
+ }
+
+ typename AuxGraph::template NodeMap<int> btree(graph, 0);
+ for (int i = border.size() - 1; i >= 0; --i) {
+ Node n = border[i];
+ btree[n] = 1;
+ for (OutArcIt e(graph, n); e != INVALID; ++e) {
+ if (bpred[graph.target(e)] == n) {
+ btree[n] += btree[graph.target(e)];
+ }
+ }
+ }
+
+ typename AuxGraph::template NodeMap<int> apath(graph, 0);
+ apath[bnode] = apath[cnode] = 1;
+ typename AuxGraph::template NodeMap<int> apath_btree(graph, 0);
+ apath_btree[bnode] = btree[bnode];
+ for (int i = 1; i < int(aorder.size()); ++i) {
+ Node n = aorder[i];
+ apath[n] = apath[apred[n]] + 1;
+ apath_btree[n] = btree[n] + apath_btree[apred[n]];
+ }
+
+ typename AuxGraph::template NodeMap<int> bpath_atree(graph, 0);
+ bpath_atree[anode] = atree[anode];
+ for (int i = 1; i < int(border.size()); ++i) {
+ Node n = border[i];
+ bpath_atree[n] = atree[n] + bpath_atree[bpred[n]];
+ }
+
+ typename AuxGraph::template NodeMap<int> cpath(graph, 0);
+ cpath[anode] = cpath[bnode] = 1;
+ typename AuxGraph::template NodeMap<int> cpath_atree(graph, 0);
+ cpath_atree[anode] = atree[anode];
+ typename AuxGraph::template NodeMap<int> cpath_btree(graph, 0);
+ cpath_btree[bnode] = btree[bnode];
+ for (int i = 1; i < int(corder.size()); ++i) {
+ Node n = corder[i];
+ cpath[n] = cpath[cpred[n]] + 1;
+ cpath_atree[n] = atree[n] + cpath_atree[cpred[n]];
+ cpath_btree[n] = btree[n] + cpath_btree[cpred[n]];
+ }
+
+ typename AuxGraph::template NodeMap<int> third(graph);
+ for (NodeIt n(graph); n != INVALID; ++n) {
+ point_map[n].x =
+ bpath_atree[n] + cpath_atree[n] - atree[n] - cpath[n] + 1;
+ point_map[n].y =
+ cpath_btree[n] + apath_btree[n] - btree[n] - apath[n] + 1;
+ }
+
+ }
+
+ public:
+
+ /// \brief Calculate the node positions
+ ///
+ /// This function calculates the node positions on the plane.
+ /// \return \c true if the graph is planar.
+ bool run() {
+ PlanarEmbedding<Graph> pe(_graph);
+ if (!pe.run()) return false;
+
+ run(pe);
+ return true;
+ }
+
+ /// \brief Calculate the node positions according to a
+ /// combinatorical embedding
+ ///
+ /// This function calculates the node positions on the plane.
+ /// The given \c embedding map should contain a valid combinatorical
+ /// embedding, i.e. a valid cyclic order of the arcs.
+ /// It can be computed using PlanarEmbedding.
+ template <typename EmbeddingMap>
+ void run(const EmbeddingMap& embedding) {
+ typedef SmartEdgeSet<Graph> AuxGraph;
+
+ if (3 * countNodes(_graph) - 6 == countEdges(_graph)) {
+ drawing(_graph, embedding, _point_map);
+ return;
+ }
+
+ AuxGraph aux_graph(_graph);
+ typename AuxGraph::template ArcMap<typename AuxGraph::Arc>
+ aux_embedding(aux_graph);
+
+ {
+
+ typename Graph::template EdgeMap<typename AuxGraph::Edge>
+ ref(_graph);
+
+ for (EdgeIt e(_graph); e != INVALID; ++e) {
+ ref[e] = aux_graph.addEdge(_graph.u(e), _graph.v(e));
+ }
+
+ for (EdgeIt e(_graph); e != INVALID; ++e) {
+ Arc ee = embedding[_graph.direct(e, true)];
+ aux_embedding[aux_graph.direct(ref[e], true)] =
+ aux_graph.direct(ref[ee], _graph.direction(ee));
+ ee = embedding[_graph.direct(e, false)];
+ aux_embedding[aux_graph.direct(ref[e], false)] =
+ aux_graph.direct(ref[ee], _graph.direction(ee));
+ }
+ }
+ _planarity_bits::makeConnected(aux_graph, aux_embedding);
+ _planarity_bits::makeBiNodeConnected(aux_graph, aux_embedding);
+ _planarity_bits::makeMaxPlanar(aux_graph, aux_embedding);
+ drawing(aux_graph, aux_embedding, _point_map);
+ }
+
+ /// \brief The coordinate of the given node
+ ///
+ /// This function returns the coordinate of the given node.
+ Point operator[](const Node& node) const {
+ return _point_map[node];
+ }
+
+ /// \brief Return the grid embedding in a node map
+ ///
+ /// This function returns the grid embedding in a node map of
+ /// \c dim2::Point<int> coordinates.
+ const PointMap& coords() const {
+ return _point_map;
+ }
+
+ private:
+
+ const Graph& _graph;
+ PointMap _point_map;
+
+ };
+
+ namespace _planarity_bits {
+
+ template <typename ColorMap>
+ class KempeFilter {
+ public:
+ typedef typename ColorMap::Key Key;
+ typedef bool Value;
+
+ KempeFilter(const ColorMap& color_map,
+ const typename ColorMap::Value& first,
+ const typename ColorMap::Value& second)
+ : _color_map(color_map), _first(first), _second(second) {}
+
+ Value operator[](const Key& key) const {
+ return _color_map[key] == _first || _color_map[key] == _second;
+ }
+
+ private:
+ const ColorMap& _color_map;
+ typename ColorMap::Value _first, _second;
+ };
+ }
+
+ /// \ingroup planar
+ ///
+ /// \brief Coloring planar graphs
+ ///
+ /// The graph coloring problem is the coloring of the graph nodes
+ /// so that there are no adjacent nodes with the same color. The
+ /// planar graphs can always be colored with four colors, which is
+ /// proved by Appel and Haken. Their proofs provide a quadratic
+ /// time algorithm for four coloring, but it could not be used to
+ /// implement an efficient algorithm. The five and six coloring can be
+ /// made in linear time, but in this class, the five coloring has
+ /// quadratic worst case time complexity. The two coloring (if
+ /// possible) is solvable with a graph search algorithm and it is
+ /// implemented in \ref bipartitePartitions() function in LEMON. To
+ /// decide whether a planar graph is three colorable is NP-complete.
+ ///
+ /// This class contains member functions for calculate colorings
+ /// with five and six colors. The six coloring algorithm is a simple
+ /// greedy coloring on the backward minimum outgoing order of nodes.
+ /// This order can be computed by selecting the node with least
+ /// outgoing arcs to unprocessed nodes in each phase. This order
+ /// guarantees that when a node is chosen for coloring it has at
+ /// most five already colored adjacents. The five coloring algorithm
+ /// use the same method, but if the greedy approach fails to color
+ /// with five colors, i.e. the node has five already different
+ /// colored neighbours, it swaps the colors in one of the connected
+ /// two colored sets with the Kempe recoloring method.
+ template <typename Graph>
+ class PlanarColoring {
+ public:
+
+ TEMPLATE_GRAPH_TYPEDEFS(Graph);
+
+ /// \brief The map type for storing color indices
+ typedef typename Graph::template NodeMap<int> IndexMap;
+ /// \brief The map type for storing colors
+ ///
+ /// The map type for storing colors.
+ /// \see Palette, Color
+ typedef ComposeMap<Palette, IndexMap> ColorMap;
+
+ /// \brief Constructor
+ ///
+ /// Constructor.
+ /// \pre The graph must be simple, i.e. it should not
+ /// contain parallel or loop arcs.
+ PlanarColoring(const Graph& graph)
+ : _graph(graph), _color_map(graph), _palette(0) {
+ _palette.add(Color(1,0,0));
+ _palette.add(Color(0,1,0));
+ _palette.add(Color(0,0,1));
+ _palette.add(Color(1,1,0));
+ _palette.add(Color(1,0,1));
+ _palette.add(Color(0,1,1));
+ }
+
+ /// \brief Return the node map of color indices
+ ///
+ /// This function returns the node map of color indices. The values are
+ /// in the range \c [0..4] or \c [0..5] according to the coloring method.
+ IndexMap colorIndexMap() const {
+ return _color_map;
+ }
+
+ /// \brief Return the node map of colors
+ ///
+ /// This function returns the node map of colors. The values are among
+ /// five or six distinct \ref lemon::Color "colors".
+ ColorMap colorMap() const {
+ return composeMap(_palette, _color_map);
+ }
+
+ /// \brief Return the color index of the node
+ ///
+ /// This function returns the color index of the given node. The value is
+ /// in the range \c [0..4] or \c [0..5] according to the coloring method.
+ int colorIndex(const Node& node) const {
+ return _color_map[node];
+ }
+
+ /// \brief Return the color of the node
+ ///
+ /// This function returns the color of the given node. The value is among
+ /// five or six distinct \ref lemon::Color "colors".
+ Color color(const Node& node) const {
+ return _palette[_color_map[node]];
+ }
+
+
+ /// \brief Calculate a coloring with at most six colors
+ ///
+ /// This function calculates a coloring with at most six colors. The time
+ /// complexity of this variant is linear in the size of the graph.
+ /// \return \c true if the algorithm could color the graph with six colors.
+ /// If the algorithm fails, then the graph is not planar.
+ /// \note This function can return \c true if the graph is not
+ /// planar, but it can be colored with at most six colors.
+ bool runSixColoring() {
+
+ typename Graph::template NodeMap<int> heap_index(_graph, -1);
+ BucketHeap<typename Graph::template NodeMap<int> > heap(heap_index);
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ _color_map[n] = -2;
+ heap.push(n, countOutArcs(_graph, n));
+ }
+
+ std::vector<Node> order;
+
+ while (!heap.empty()) {
+ Node n = heap.top();
+ heap.pop();
+ _color_map[n] = -1;
+ order.push_back(n);
+ for (OutArcIt e(_graph, n); e != INVALID; ++e) {
+ Node t = _graph.runningNode(e);
+ if (_color_map[t] == -2) {
+ heap.decrease(t, heap[t] - 1);
+ }
+ }
+ }
+
+ for (int i = order.size() - 1; i >= 0; --i) {
+ std::vector<bool> forbidden(6, false);
+ for (OutArcIt e(_graph, order[i]); e != INVALID; ++e) {
+ Node t = _graph.runningNode(e);
+ if (_color_map[t] != -1) {
+ forbidden[_color_map[t]] = true;
+ }
+ }
+ for (int k = 0; k < 6; ++k) {
+ if (!forbidden[k]) {
+ _color_map[order[i]] = k;
+ break;
+ }
+ }
+ if (_color_map[order[i]] == -1) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private:
+
+ bool recolor(const Node& u, const Node& v) {
+ int ucolor = _color_map[u];
+ int vcolor = _color_map[v];
+ typedef _planarity_bits::KempeFilter<IndexMap> KempeFilter;
+ KempeFilter filter(_color_map, ucolor, vcolor);
+
+ typedef FilterNodes<const Graph, const KempeFilter> KempeGraph;
+ KempeGraph kempe_graph(_graph, filter);
+
+ std::vector<Node> comp;
+ Bfs<KempeGraph> bfs(kempe_graph);
+ bfs.init();
+ bfs.addSource(u);
+ while (!bfs.emptyQueue()) {
+ Node n = bfs.nextNode();
+ if (n == v) return false;
+ comp.push_back(n);
+ bfs.processNextNode();
+ }
+
+ int scolor = ucolor + vcolor;
+ for (int i = 0; i < static_cast<int>(comp.size()); ++i) {
+ _color_map[comp[i]] = scolor - _color_map[comp[i]];
+ }
+
+ return true;
+ }
+
+ template <typename EmbeddingMap>
+ void kempeRecoloring(const Node& node, const EmbeddingMap& embedding) {
+ std::vector<Node> nodes;
+ nodes.reserve(4);
+
+ for (Arc e = OutArcIt(_graph, node); e != INVALID; e = embedding[e]) {
+ Node t = _graph.target(e);
+ if (_color_map[t] != -1) {
+ nodes.push_back(t);
+ if (nodes.size() == 4) break;
+ }
+ }
+
+ int color = _color_map[nodes[0]];
+ if (recolor(nodes[0], nodes[2])) {
+ _color_map[node] = color;
+ } else {
+ color = _color_map[nodes[1]];
+ recolor(nodes[1], nodes[3]);
+ _color_map[node] = color;
+ }
+ }
+
+ public:
+
+ /// \brief Calculate a coloring with at most five colors
+ ///
+ /// This function calculates a coloring with at most five
+ /// colors. The worst case time complexity of this variant is
+ /// quadratic in the size of the graph.
+ /// \param embedding This map should contain a valid combinatorical
+ /// embedding, i.e. a valid cyclic order of the arcs.
+ /// It can be computed using PlanarEmbedding.
+ template <typename EmbeddingMap>
+ void runFiveColoring(const EmbeddingMap& embedding) {
+
+ typename Graph::template NodeMap<int> heap_index(_graph, -1);
+ BucketHeap<typename Graph::template NodeMap<int> > heap(heap_index);
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ _color_map[n] = -2;
+ heap.push(n, countOutArcs(_graph, n));
+ }
+
+ std::vector<Node> order;
+
+ while (!heap.empty()) {
+ Node n = heap.top();
+ heap.pop();
+ _color_map[n] = -1;
+ order.push_back(n);
+ for (OutArcIt e(_graph, n); e != INVALID; ++e) {
+ Node t = _graph.runningNode(e);
+ if (_color_map[t] == -2) {
+ heap.decrease(t, heap[t] - 1);
+ }
+ }
+ }
+
+ for (int i = order.size() - 1; i >= 0; --i) {
+ std::vector<bool> forbidden(5, false);
+ for (OutArcIt e(_graph, order[i]); e != INVALID; ++e) {
+ Node t = _graph.runningNode(e);
+ if (_color_map[t] != -1) {
+ forbidden[_color_map[t]] = true;
+ }
+ }
+ for (int k = 0; k < 5; ++k) {
+ if (!forbidden[k]) {
+ _color_map[order[i]] = k;
+ break;
+ }
+ }
+ if (_color_map[order[i]] == -1) {
+ kempeRecoloring(order[i], embedding);
+ }
+ }
+ }
+
+ /// \brief Calculate a coloring with at most five colors
+ ///
+ /// This function calculates a coloring with at most five
+ /// colors. The worst case time complexity of this variant is
+ /// quadratic in the size of the graph.
+ /// \return \c true if the graph is planar.
+ bool runFiveColoring() {
+ PlanarEmbedding<Graph> pe(_graph);
+ if (!pe.run()) return false;
+
+ runFiveColoring(pe.embeddingMap());
+ return true;
+ }
+
+ private:
+
+ const Graph& _graph;
+ IndexMap _color_map;
+ Palette _palette;
+ };
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/preflow.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/preflow.h
new file mode 100644
index 00000000000..28ccd67dcf1
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/preflow.h
@@ -0,0 +1,985 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_PREFLOW_H
+#define LEMON_PREFLOW_H
+
+#include <lemon/tolerance.h>
+#include <lemon/elevator.h>
+
+/// \file
+/// \ingroup max_flow
+/// \brief Implementation of the preflow algorithm.
+
+namespace lemon {
+
+ /// \brief Default traits class of Preflow class.
+ ///
+ /// Default traits class of Preflow class.
+ /// \tparam GR Digraph type.
+ /// \tparam CAP Capacity map type.
+ template <typename GR, typename CAP>
+ struct PreflowDefaultTraits {
+
+ /// \brief The type of the digraph the algorithm runs on.
+ typedef GR Digraph;
+
+ /// \brief The type of the map that stores the arc capacities.
+ ///
+ /// The type of the map that stores the arc capacities.
+ /// It must meet the \ref concepts::ReadMap "ReadMap" concept.
+ typedef CAP CapacityMap;
+
+ /// \brief The type of the flow values.
+ typedef typename CapacityMap::Value Value;
+
+ /// \brief The type of the map that stores the flow values.
+ ///
+ /// The type of the map that stores the flow values.
+ /// It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept.
+#ifdef DOXYGEN
+ typedef GR::ArcMap<Value> FlowMap;
+#else
+ typedef typename Digraph::template ArcMap<Value> FlowMap;
+#endif
+
+ /// \brief Instantiates a FlowMap.
+ ///
+ /// This function instantiates a \ref FlowMap.
+ /// \param digraph The digraph for which we would like to define
+ /// the flow map.
+ static FlowMap* createFlowMap(const Digraph& digraph) {
+ return new FlowMap(digraph);
+ }
+
+ /// \brief The elevator type used by Preflow algorithm.
+ ///
+ /// The elevator type used by Preflow algorithm.
+ ///
+ /// \sa Elevator, LinkedElevator
+#ifdef DOXYGEN
+ typedef lemon::Elevator<GR, GR::Node> Elevator;
+#else
+ typedef lemon::Elevator<Digraph, typename Digraph::Node> Elevator;
+#endif
+
+ /// \brief Instantiates an Elevator.
+ ///
+ /// This function instantiates an \ref Elevator.
+ /// \param digraph The digraph for which we would like to define
+ /// the elevator.
+ /// \param max_level The maximum level of the elevator.
+ static Elevator* createElevator(const Digraph& digraph, int max_level) {
+ return new Elevator(digraph, max_level);
+ }
+
+ /// \brief The tolerance used by the algorithm
+ ///
+ /// The tolerance used by the algorithm to handle inexact computation.
+ typedef lemon::Tolerance<Value> Tolerance;
+
+ };
+
+
+ /// \ingroup max_flow
+ ///
+ /// \brief %Preflow algorithm class.
+ ///
+ /// This class provides an implementation of Goldberg-Tarjan's \e preflow
+ /// \e push-relabel algorithm producing a \ref max_flow
+ /// "flow of maximum value" in a digraph \cite clrs01algorithms,
+ /// \cite amo93networkflows, \cite goldberg88newapproach.
+ /// The preflow algorithms are the fastest known maximum
+ /// flow algorithms. The current implementation uses a mixture of the
+ /// \e "highest label" and the \e "bound decrease" heuristics.
+ /// The worst case time complexity of the algorithm is \f$O(n^2\sqrt{m})\f$.
+ ///
+ /// The algorithm consists of two phases. After the first phase
+ /// the maximum flow value and the minimum cut is obtained. The
+ /// second phase constructs a feasible maximum flow on each arc.
+ ///
+ /// \warning This implementation cannot handle infinite or very large
+ /// capacities (e.g. the maximum value of \c CAP::Value).
+ ///
+ /// \tparam GR The type of the digraph the algorithm runs on.
+ /// \tparam CAP The type of the capacity map. The default map
+ /// type is \ref concepts::Digraph::ArcMap "GR::ArcMap<int>".
+ /// \tparam TR The traits class that defines various types used by the
+ /// algorithm. By default, it is \ref PreflowDefaultTraits
+ /// "PreflowDefaultTraits<GR, CAP>".
+ /// In most cases, this parameter should not be set directly,
+ /// consider to use the named template parameters instead.
+#ifdef DOXYGEN
+ template <typename GR, typename CAP, typename TR>
+#else
+ template <typename GR,
+ typename CAP = typename GR::template ArcMap<int>,
+ typename TR = PreflowDefaultTraits<GR, CAP> >
+#endif
+ class Preflow {
+ public:
+
+ ///The \ref lemon::PreflowDefaultTraits "traits class" of the algorithm.
+ typedef TR Traits;
+ ///The type of the digraph the algorithm runs on.
+ typedef typename Traits::Digraph Digraph;
+ ///The type of the capacity map.
+ typedef typename Traits::CapacityMap CapacityMap;
+ ///The type of the flow values.
+ typedef typename Traits::Value Value;
+
+ ///The type of the flow map.
+ typedef typename Traits::FlowMap FlowMap;
+ ///The type of the elevator.
+ typedef typename Traits::Elevator Elevator;
+ ///The type of the tolerance.
+ typedef typename Traits::Tolerance Tolerance;
+
+ private:
+
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+
+ const Digraph& _graph;
+ const CapacityMap* _capacity;
+
+ int _node_num;
+
+ Node _source, _target;
+
+ FlowMap* _flow;
+ bool _local_flow;
+
+ Elevator* _level;
+ bool _local_level;
+
+ typedef typename Digraph::template NodeMap<Value> ExcessMap;
+ ExcessMap* _excess;
+
+ Tolerance _tolerance;
+
+ bool _phase;
+
+
+ void createStructures() {
+ _node_num = countNodes(_graph);
+
+ if (!_flow) {
+ _flow = Traits::createFlowMap(_graph);
+ _local_flow = true;
+ }
+ if (!_level) {
+ _level = Traits::createElevator(_graph, _node_num);
+ _local_level = true;
+ }
+ if (!_excess) {
+ _excess = new ExcessMap(_graph);
+ }
+ }
+
+ void destroyStructures() {
+ if (_local_flow) {
+ delete _flow;
+ }
+ if (_local_level) {
+ delete _level;
+ }
+ if (_excess) {
+ delete _excess;
+ }
+ }
+
+ public:
+
+ typedef Preflow Create;
+
+ ///\name Named Template Parameters
+
+ ///@{
+
+ template <typename T>
+ struct SetFlowMapTraits : public Traits {
+ typedef T FlowMap;
+ static FlowMap *createFlowMap(const Digraph&) {
+ LEMON_ASSERT(false, "FlowMap is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// FlowMap type
+ ///
+ /// \ref named-templ-param "Named parameter" for setting FlowMap
+ /// type.
+ template <typename T>
+ struct SetFlowMap
+ : public Preflow<Digraph, CapacityMap, SetFlowMapTraits<T> > {
+ typedef Preflow<Digraph, CapacityMap,
+ SetFlowMapTraits<T> > Create;
+ };
+
+ template <typename T>
+ struct SetElevatorTraits : public Traits {
+ typedef T Elevator;
+ static Elevator *createElevator(const Digraph&, int) {
+ LEMON_ASSERT(false, "Elevator is not initialized");
+ return 0; // ignore warnings
+ }
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// Elevator type
+ ///
+ /// \ref named-templ-param "Named parameter" for setting Elevator
+ /// type. If this named parameter is used, then an external
+ /// elevator object must be passed to the algorithm using the
+ /// \ref elevator(Elevator&) "elevator()" function before calling
+ /// \ref run() or \ref init().
+ /// \sa SetStandardElevator
+ template <typename T>
+ struct SetElevator
+ : public Preflow<Digraph, CapacityMap, SetElevatorTraits<T> > {
+ typedef Preflow<Digraph, CapacityMap,
+ SetElevatorTraits<T> > Create;
+ };
+
+ template <typename T>
+ struct SetStandardElevatorTraits : public Traits {
+ typedef T Elevator;
+ static Elevator *createElevator(const Digraph& digraph, int max_level) {
+ return new Elevator(digraph, max_level);
+ }
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// Elevator type with automatic allocation
+ ///
+ /// \ref named-templ-param "Named parameter" for setting Elevator
+ /// type with automatic allocation.
+ /// The Elevator should have standard constructor interface to be
+ /// able to automatically created by the algorithm (i.e. the
+ /// digraph and the maximum level should be passed to it).
+ /// However, an external elevator object could also be passed to the
+ /// algorithm with the \ref elevator(Elevator&) "elevator()" function
+ /// before calling \ref run() or \ref init().
+ /// \sa SetElevator
+ template <typename T>
+ struct SetStandardElevator
+ : public Preflow<Digraph, CapacityMap,
+ SetStandardElevatorTraits<T> > {
+ typedef Preflow<Digraph, CapacityMap,
+ SetStandardElevatorTraits<T> > Create;
+ };
+
+ /// @}
+
+ protected:
+
+ Preflow() {}
+
+ public:
+
+
+ /// \brief The constructor of the class.
+ ///
+ /// The constructor of the class.
+ /// \param digraph The digraph the algorithm runs on.
+ /// \param capacity The capacity of the arcs.
+ /// \param source The source node.
+ /// \param target The target node.
+ Preflow(const Digraph& digraph, const CapacityMap& capacity,
+ Node source, Node target)
+ : _graph(digraph), _capacity(&capacity),
+ _node_num(0), _source(source), _target(target),
+ _flow(0), _local_flow(false),
+ _level(0), _local_level(false),
+ _excess(0), _tolerance(), _phase() {}
+
+ /// \brief Destructor.
+ ///
+ /// Destructor.
+ ~Preflow() {
+ destroyStructures();
+ }
+
+ /// \brief Sets the capacity map.
+ ///
+ /// Sets the capacity map.
+ /// \return <tt>(*this)</tt>
+ Preflow& capacityMap(const CapacityMap& map) {
+ _capacity = &map;
+ return *this;
+ }
+
+ /// \brief Sets the flow map.
+ ///
+ /// Sets the flow map.
+ /// If you don't use this function before calling \ref run() or
+ /// \ref init(), an instance will be allocated automatically.
+ /// The destructor deallocates this automatically allocated map,
+ /// of course.
+ /// \return <tt>(*this)</tt>
+ Preflow& flowMap(FlowMap& map) {
+ if (_local_flow) {
+ delete _flow;
+ _local_flow = false;
+ }
+ _flow = &map;
+ return *this;
+ }
+
+ /// \brief Sets the source node.
+ ///
+ /// Sets the source node.
+ /// \return <tt>(*this)</tt>
+ Preflow& source(const Node& node) {
+ _source = node;
+ return *this;
+ }
+
+ /// \brief Sets the target node.
+ ///
+ /// Sets the target node.
+ /// \return <tt>(*this)</tt>
+ Preflow& target(const Node& node) {
+ _target = node;
+ return *this;
+ }
+
+ /// \brief Sets the elevator used by algorithm.
+ ///
+ /// Sets the elevator used by algorithm.
+ /// If you don't use this function before calling \ref run() or
+ /// \ref init(), an instance will be allocated automatically.
+ /// The destructor deallocates this automatically allocated elevator,
+ /// of course.
+ /// \return <tt>(*this)</tt>
+ Preflow& elevator(Elevator& elevator) {
+ if (_local_level) {
+ delete _level;
+ _local_level = false;
+ }
+ _level = &elevator;
+ return *this;
+ }
+
+ /// \brief Returns a const reference to the elevator.
+ ///
+ /// Returns a const reference to the elevator.
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ const Elevator& elevator() const {
+ return *_level;
+ }
+
+ /// \brief Sets the tolerance used by the algorithm.
+ ///
+ /// Sets the tolerance object used by the algorithm.
+ /// \return <tt>(*this)</tt>
+ Preflow& tolerance(const Tolerance& tolerance) {
+ _tolerance = tolerance;
+ return *this;
+ }
+
+ /// \brief Returns a const reference to the tolerance.
+ ///
+ /// Returns a const reference to the tolerance object used by
+ /// the algorithm.
+ const Tolerance& tolerance() const {
+ return _tolerance;
+ }
+
+ /// \name Execution Control
+ /// The simplest way to execute the preflow algorithm is to use
+ /// \ref run() or \ref runMinCut().\n
+ /// If you need better control on the initial solution or the execution,
+ /// you have to call one of the \ref init() functions first, then
+ /// \ref startFirstPhase() and if you need it \ref startSecondPhase().
+
+ ///@{
+
+ /// \brief Initializes the internal data structures.
+ ///
+ /// Initializes the internal data structures and sets the initial
+ /// flow to zero on each arc.
+ void init() {
+ createStructures();
+
+ _phase = true;
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ (*_excess)[n] = 0;
+ }
+
+ for (ArcIt e(_graph); e != INVALID; ++e) {
+ _flow->set(e, 0);
+ }
+
+ typename Digraph::template NodeMap<bool> reached(_graph, false);
+
+ _level->initStart();
+ _level->initAddItem(_target);
+
+ std::vector<Node> queue;
+ reached[_source] = true;
+
+ queue.push_back(_target);
+ reached[_target] = true;
+ while (!queue.empty()) {
+ _level->initNewLevel();
+ std::vector<Node> nqueue;
+ for (int i = 0; i < int(queue.size()); ++i) {
+ Node n = queue[i];
+ for (InArcIt e(_graph, n); e != INVALID; ++e) {
+ Node u = _graph.source(e);
+ if (!reached[u] && _tolerance.positive((*_capacity)[e])) {
+ reached[u] = true;
+ _level->initAddItem(u);
+ nqueue.push_back(u);
+ }
+ }
+ }
+ queue.swap(nqueue);
+ }
+ _level->initFinish();
+
+ for (OutArcIt e(_graph, _source); e != INVALID; ++e) {
+ if (_tolerance.positive((*_capacity)[e])) {
+ Node u = _graph.target(e);
+ if ((*_level)[u] == _level->maxLevel()) continue;
+ _flow->set(e, (*_capacity)[e]);
+ (*_excess)[u] += (*_capacity)[e];
+ if (u != _target && !_level->active(u)) {
+ _level->activate(u);
+ }
+ }
+ }
+ }
+
+ /// \brief Initializes the internal data structures using the
+ /// given flow map.
+ ///
+ /// Initializes the internal data structures and sets the initial
+ /// flow to the given \c flowMap. The \c flowMap should contain a
+ /// flow or at least a preflow, i.e. at each node excluding the
+ /// source node the incoming flow should greater or equal to the
+ /// outgoing flow.
+ /// \return \c false if the given \c flowMap is not a preflow.
+ template <typename FlowMap>
+ bool init(const FlowMap& flowMap) {
+ createStructures();
+
+ for (ArcIt e(_graph); e != INVALID; ++e) {
+ _flow->set(e, flowMap[e]);
+ }
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ Value excess = 0;
+ for (InArcIt e(_graph, n); e != INVALID; ++e) {
+ excess += (*_flow)[e];
+ }
+ for (OutArcIt e(_graph, n); e != INVALID; ++e) {
+ excess -= (*_flow)[e];
+ }
+ if (excess < 0 && n != _source) return false;
+ (*_excess)[n] = excess;
+ }
+
+ typename Digraph::template NodeMap<bool> reached(_graph, false);
+
+ _level->initStart();
+ _level->initAddItem(_target);
+
+ std::vector<Node> queue;
+ reached[_source] = true;
+
+ queue.push_back(_target);
+ reached[_target] = true;
+ while (!queue.empty()) {
+ _level->initNewLevel();
+ std::vector<Node> nqueue;
+ for (int i = 0; i < int(queue.size()); ++i) {
+ Node n = queue[i];
+ for (InArcIt e(_graph, n); e != INVALID; ++e) {
+ Node u = _graph.source(e);
+ if (!reached[u] &&
+ _tolerance.positive((*_capacity)[e] - (*_flow)[e])) {
+ reached[u] = true;
+ _level->initAddItem(u);
+ nqueue.push_back(u);
+ }
+ }
+ for (OutArcIt e(_graph, n); e != INVALID; ++e) {
+ Node v = _graph.target(e);
+ if (!reached[v] && _tolerance.positive((*_flow)[e])) {
+ reached[v] = true;
+ _level->initAddItem(v);
+ nqueue.push_back(v);
+ }
+ }
+ }
+ queue.swap(nqueue);
+ }
+ _level->initFinish();
+
+ for (OutArcIt e(_graph, _source); e != INVALID; ++e) {
+ Value rem = (*_capacity)[e] - (*_flow)[e];
+ if (_tolerance.positive(rem)) {
+ Node u = _graph.target(e);
+ if ((*_level)[u] == _level->maxLevel()) continue;
+ _flow->set(e, (*_capacity)[e]);
+ (*_excess)[u] += rem;
+ }
+ }
+ for (InArcIt e(_graph, _source); e != INVALID; ++e) {
+ Value rem = (*_flow)[e];
+ if (_tolerance.positive(rem)) {
+ Node v = _graph.source(e);
+ if ((*_level)[v] == _level->maxLevel()) continue;
+ _flow->set(e, 0);
+ (*_excess)[v] += rem;
+ }
+ }
+ for (NodeIt n(_graph); n != INVALID; ++n)
+ if(n!=_source && n!=_target && _tolerance.positive((*_excess)[n]))
+ _level->activate(n);
+
+ return true;
+ }
+
+ /// \brief Starts the first phase of the preflow algorithm.
+ ///
+ /// The preflow algorithm consists of two phases, this method runs
+ /// the first phase. After the first phase the maximum flow value
+ /// and a minimum value cut can already be computed, although a
+ /// maximum flow is not yet obtained. So after calling this method
+ /// \ref flowValue() returns the value of a maximum flow and \ref
+ /// minCut() returns a minimum cut.
+ /// \pre One of the \ref init() functions must be called before
+ /// using this function.
+ void startFirstPhase() {
+ _phase = true;
+
+ while (true) {
+ int num = _node_num;
+
+ Node n = INVALID;
+ int level = -1;
+
+ while (num > 0) {
+ n = _level->highestActive();
+ if (n == INVALID) goto first_phase_done;
+ level = _level->highestActiveLevel();
+ --num;
+
+ Value excess = (*_excess)[n];
+ int new_level = _level->maxLevel();
+
+ for (OutArcIt e(_graph, n); e != INVALID; ++e) {
+ Value rem = (*_capacity)[e] - (*_flow)[e];
+ if (!_tolerance.positive(rem)) continue;
+ Node v = _graph.target(e);
+ if ((*_level)[v] < level) {
+ if (!_level->active(v) && v != _target) {
+ _level->activate(v);
+ }
+ if (!_tolerance.less(rem, excess)) {
+ _flow->set(e, (*_flow)[e] + excess);
+ (*_excess)[v] += excess;
+ excess = 0;
+ goto no_more_push_1;
+ } else {
+ excess -= rem;
+ (*_excess)[v] += rem;
+ _flow->set(e, (*_capacity)[e]);
+ }
+ } else if (new_level > (*_level)[v]) {
+ new_level = (*_level)[v];
+ }
+ }
+
+ for (InArcIt e(_graph, n); e != INVALID; ++e) {
+ Value rem = (*_flow)[e];
+ if (!_tolerance.positive(rem)) continue;
+ Node v = _graph.source(e);
+ if ((*_level)[v] < level) {
+ if (!_level->active(v) && v != _target) {
+ _level->activate(v);
+ }
+ if (!_tolerance.less(rem, excess)) {
+ _flow->set(e, (*_flow)[e] - excess);
+ (*_excess)[v] += excess;
+ excess = 0;
+ goto no_more_push_1;
+ } else {
+ excess -= rem;
+ (*_excess)[v] += rem;
+ _flow->set(e, 0);
+ }
+ } else if (new_level > (*_level)[v]) {
+ new_level = (*_level)[v];
+ }
+ }
+
+ no_more_push_1:
+
+ (*_excess)[n] = excess;
+
+ if (excess != 0) {
+ if (new_level + 1 < _level->maxLevel()) {
+ _level->liftHighestActive(new_level + 1);
+ } else {
+ _level->liftHighestActiveToTop();
+ }
+ if (_level->emptyLevel(level)) {
+ _level->liftToTop(level);
+ }
+ } else {
+ _level->deactivate(n);
+ }
+ }
+
+ num = _node_num * 20;
+ while (num > 0) {
+ while (level >= 0 && _level->activeFree(level)) {
+ --level;
+ }
+ if (level == -1) {
+ n = _level->highestActive();
+ level = _level->highestActiveLevel();
+ if (n == INVALID) goto first_phase_done;
+ } else {
+ n = _level->activeOn(level);
+ }
+ --num;
+
+ Value excess = (*_excess)[n];
+ int new_level = _level->maxLevel();
+
+ for (OutArcIt e(_graph, n); e != INVALID; ++e) {
+ Value rem = (*_capacity)[e] - (*_flow)[e];
+ if (!_tolerance.positive(rem)) continue;
+ Node v = _graph.target(e);
+ if ((*_level)[v] < level) {
+ if (!_level->active(v) && v != _target) {
+ _level->activate(v);
+ }
+ if (!_tolerance.less(rem, excess)) {
+ _flow->set(e, (*_flow)[e] + excess);
+ (*_excess)[v] += excess;
+ excess = 0;
+ goto no_more_push_2;
+ } else {
+ excess -= rem;
+ (*_excess)[v] += rem;
+ _flow->set(e, (*_capacity)[e]);
+ }
+ } else if (new_level > (*_level)[v]) {
+ new_level = (*_level)[v];
+ }
+ }
+
+ for (InArcIt e(_graph, n); e != INVALID; ++e) {
+ Value rem = (*_flow)[e];
+ if (!_tolerance.positive(rem)) continue;
+ Node v = _graph.source(e);
+ if ((*_level)[v] < level) {
+ if (!_level->active(v) && v != _target) {
+ _level->activate(v);
+ }
+ if (!_tolerance.less(rem, excess)) {
+ _flow->set(e, (*_flow)[e] - excess);
+ (*_excess)[v] += excess;
+ excess = 0;
+ goto no_more_push_2;
+ } else {
+ excess -= rem;
+ (*_excess)[v] += rem;
+ _flow->set(e, 0);
+ }
+ } else if (new_level > (*_level)[v]) {
+ new_level = (*_level)[v];
+ }
+ }
+
+ no_more_push_2:
+
+ (*_excess)[n] = excess;
+
+ if (excess != 0) {
+ if (new_level + 1 < _level->maxLevel()) {
+ _level->liftActiveOn(level, new_level + 1);
+ } else {
+ _level->liftActiveToTop(level);
+ }
+ if (_level->emptyLevel(level)) {
+ _level->liftToTop(level);
+ }
+ } else {
+ _level->deactivate(n);
+ }
+ }
+ }
+ first_phase_done:;
+ }
+
+ /// \brief Starts the second phase of the preflow algorithm.
+ ///
+ /// The preflow algorithm consists of two phases, this method runs
+ /// the second phase. After calling one of the \ref init() functions
+ /// and \ref startFirstPhase() and then \ref startSecondPhase(),
+ /// \ref flowMap() returns a maximum flow, \ref flowValue() returns the
+ /// value of a maximum flow, \ref minCut() returns a minimum cut
+ /// \pre One of the \ref init() functions and \ref startFirstPhase()
+ /// must be called before using this function.
+ void startSecondPhase() {
+ _phase = false;
+
+ typename Digraph::template NodeMap<bool> reached(_graph);
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ reached[n] = (*_level)[n] < _level->maxLevel();
+ }
+
+ _level->initStart();
+ _level->initAddItem(_source);
+
+ std::vector<Node> queue;
+ queue.push_back(_source);
+ reached[_source] = true;
+
+ while (!queue.empty()) {
+ _level->initNewLevel();
+ std::vector<Node> nqueue;
+ for (int i = 0; i < int(queue.size()); ++i) {
+ Node n = queue[i];
+ for (OutArcIt e(_graph, n); e != INVALID; ++e) {
+ Node v = _graph.target(e);
+ if (!reached[v] && _tolerance.positive((*_flow)[e])) {
+ reached[v] = true;
+ _level->initAddItem(v);
+ nqueue.push_back(v);
+ }
+ }
+ for (InArcIt e(_graph, n); e != INVALID; ++e) {
+ Node u = _graph.source(e);
+ if (!reached[u] &&
+ _tolerance.positive((*_capacity)[e] - (*_flow)[e])) {
+ reached[u] = true;
+ _level->initAddItem(u);
+ nqueue.push_back(u);
+ }
+ }
+ }
+ queue.swap(nqueue);
+ }
+ _level->initFinish();
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ if (!reached[n]) {
+ _level->dirtyTopButOne(n);
+ } else if ((*_excess)[n] > 0 && _target != n) {
+ _level->activate(n);
+ }
+ }
+
+ Node n;
+ while ((n = _level->highestActive()) != INVALID) {
+ Value excess = (*_excess)[n];
+ int level = _level->highestActiveLevel();
+ int new_level = _level->maxLevel();
+
+ for (OutArcIt e(_graph, n); e != INVALID; ++e) {
+ Value rem = (*_capacity)[e] - (*_flow)[e];
+ if (!_tolerance.positive(rem)) continue;
+ Node v = _graph.target(e);
+ if ((*_level)[v] < level) {
+ if (!_level->active(v) && v != _source) {
+ _level->activate(v);
+ }
+ if (!_tolerance.less(rem, excess)) {
+ _flow->set(e, (*_flow)[e] + excess);
+ (*_excess)[v] += excess;
+ excess = 0;
+ goto no_more_push;
+ } else {
+ excess -= rem;
+ (*_excess)[v] += rem;
+ _flow->set(e, (*_capacity)[e]);
+ }
+ } else if (new_level > (*_level)[v]) {
+ new_level = (*_level)[v];
+ }
+ }
+
+ for (InArcIt e(_graph, n); e != INVALID; ++e) {
+ Value rem = (*_flow)[e];
+ if (!_tolerance.positive(rem)) continue;
+ Node v = _graph.source(e);
+ if ((*_level)[v] < level) {
+ if (!_level->active(v) && v != _source) {
+ _level->activate(v);
+ }
+ if (!_tolerance.less(rem, excess)) {
+ _flow->set(e, (*_flow)[e] - excess);
+ (*_excess)[v] += excess;
+ excess = 0;
+ goto no_more_push;
+ } else {
+ excess -= rem;
+ (*_excess)[v] += rem;
+ _flow->set(e, 0);
+ }
+ } else if (new_level > (*_level)[v]) {
+ new_level = (*_level)[v];
+ }
+ }
+
+ no_more_push:
+
+ (*_excess)[n] = excess;
+
+ if (excess != 0) {
+ if (new_level + 1 < _level->maxLevel()) {
+ _level->liftHighestActive(new_level + 1);
+ } else {
+ // Calculation error
+ _level->liftHighestActiveToTop();
+ }
+ if (_level->emptyLevel(level)) {
+ // Calculation error
+ _level->liftToTop(level);
+ }
+ } else {
+ _level->deactivate(n);
+ }
+
+ }
+ }
+
+ /// \brief Runs the preflow algorithm.
+ ///
+ /// Runs the preflow algorithm.
+ /// \note pf.run() is just a shortcut of the following code.
+ /// \code
+ /// pf.init();
+ /// pf.startFirstPhase();
+ /// pf.startSecondPhase();
+ /// \endcode
+ void run() {
+ init();
+ startFirstPhase();
+ startSecondPhase();
+ }
+
+ /// \brief Runs the preflow algorithm to compute the minimum cut.
+ ///
+ /// Runs the preflow algorithm to compute the minimum cut.
+ /// \note pf.runMinCut() is just a shortcut of the following code.
+ /// \code
+ /// pf.init();
+ /// pf.startFirstPhase();
+ /// \endcode
+ void runMinCut() {
+ init();
+ startFirstPhase();
+ }
+
+ /// @}
+
+ /// \name Query Functions
+ /// The results of the preflow algorithm can be obtained using these
+ /// functions.\n
+ /// Either one of the \ref run() "run*()" functions or one of the
+ /// \ref startFirstPhase() "start*()" functions should be called
+ /// before using them.
+
+ ///@{
+
+ /// \brief Returns the value of the maximum flow.
+ ///
+ /// Returns the value of the maximum flow by returning the excess
+ /// of the target node. This value equals to the value of
+ /// the maximum flow already after the first phase of the algorithm.
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ Value flowValue() const {
+ return (*_excess)[_target];
+ }
+
+ /// \brief Returns the flow value on the given arc.
+ ///
+ /// Returns the flow value on the given arc. This method can
+ /// be called after the second phase of the algorithm.
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ Value flow(const Arc& arc) const {
+ return (*_flow)[arc];
+ }
+
+ /// \brief Returns a const reference to the flow map.
+ ///
+ /// Returns a const reference to the arc map storing the found flow.
+ /// This method can be called after the second phase of the algorithm.
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ const FlowMap& flowMap() const {
+ return *_flow;
+ }
+
+ /// \brief Returns \c true when the node is on the source side of the
+ /// minimum cut.
+ ///
+ /// Returns true when the node is on the source side of the found
+ /// minimum cut. This method can be called both after running \ref
+ /// startFirstPhase() and \ref startSecondPhase().
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ bool minCut(const Node& node) const {
+ return ((*_level)[node] == _level->maxLevel()) == _phase;
+ }
+
+ /// \brief Gives back a minimum value cut.
+ ///
+ /// Sets \c cutMap to the characteristic vector of a minimum value
+ /// cut. \c cutMap should be a \ref concepts::WriteMap "writable"
+ /// node map with \c bool (or convertible) value type.
+ ///
+ /// This method can be called both after running \ref startFirstPhase()
+ /// and \ref startSecondPhase(). The result after the second phase
+ /// could be slightly different if inexact computation is used.
+ ///
+ /// \note This function calls \ref minCut() for each node, so it runs in
+ /// O(n) time.
+ ///
+ /// \pre Either \ref run() or \ref init() must be called before
+ /// using this function.
+ template <typename CutMap>
+ void minCutMap(CutMap& cutMap) const {
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ cutMap.set(n, minCut(n));
+ }
+ }
+
+ /// @}
+ };
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/quad_heap.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/quad_heap.h
new file mode 100644
index 00000000000..27c50fd3f60
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/quad_heap.h
@@ -0,0 +1,343 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_QUAD_HEAP_H
+#define LEMON_QUAD_HEAP_H
+
+///\ingroup heaps
+///\file
+///\brief Fourary (quaternary) heap implementation.
+
+#include <vector>
+#include <utility>
+#include <functional>
+
+namespace lemon {
+
+ /// \ingroup heaps
+ ///
+ ///\brief Fourary (quaternary) heap data structure.
+ ///
+ /// This class implements the \e Fourary (\e quaternary) \e heap
+ /// data structure.
+ /// It fully conforms to the \ref concepts::Heap "heap concept".
+ ///
+ /// The fourary heap is a specialization of the \ref DHeap "D-ary heap"
+ /// for <tt>D=4</tt>. It is similar to the \ref BinHeap "binary heap",
+ /// but its nodes have at most four children, instead of two.
+ ///
+ /// \tparam PR Type of the priorities of the items.
+ /// \tparam IM A read-writable item map with \c int values, used
+ /// internally to handle the cross references.
+ /// \tparam CMP A functor class for comparing the priorities.
+ /// The default is \c std::less<PR>.
+ ///
+ ///\sa BinHeap
+ ///\sa DHeap
+#ifdef DOXYGEN
+ template <typename PR, typename IM, typename CMP>
+#else
+ template <typename PR, typename IM, typename CMP = std::less<PR> >
+#endif
+ class QuadHeap {
+ public:
+ /// Type of the item-int map.
+ typedef IM ItemIntMap;
+ /// Type of the priorities.
+ typedef PR Prio;
+ /// Type of the items stored in the heap.
+ typedef typename ItemIntMap::Key Item;
+ /// Type of the item-priority pairs.
+ typedef std::pair<Item,Prio> Pair;
+ /// Functor type for comparing the priorities.
+ typedef CMP Compare;
+
+ /// \brief Type to represent the states of the items.
+ ///
+ /// Each item has a state associated to it. It can be "in heap",
+ /// "pre-heap" or "post-heap". The latter two are indifferent from the
+ /// heap's point of view, but may be useful to the user.
+ ///
+ /// The item-int map must be initialized in such way that it assigns
+ /// \c PRE_HEAP (<tt>-1</tt>) to any element to be put in the heap.
+ enum State {
+ IN_HEAP = 0, ///< = 0.
+ PRE_HEAP = -1, ///< = -1.
+ POST_HEAP = -2 ///< = -2.
+ };
+
+ private:
+ std::vector<Pair> _data;
+ Compare _comp;
+ ItemIntMap &_iim;
+
+ public:
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ /// \param map A map that assigns \c int values to the items.
+ /// It is used internally to handle the cross references.
+ /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
+ explicit QuadHeap(ItemIntMap &map) : _iim(map) {}
+
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ /// \param map A map that assigns \c int values to the items.
+ /// It is used internally to handle the cross references.
+ /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
+ /// \param comp The function object used for comparing the priorities.
+ QuadHeap(ItemIntMap &map, const Compare &comp)
+ : _iim(map), _comp(comp) {}
+
+ /// \brief The number of items stored in the heap.
+ ///
+ /// This function returns the number of items stored in the heap.
+ int size() const { return _data.size(); }
+
+ /// \brief Check if the heap is empty.
+ ///
+ /// This function returns \c true if the heap is empty.
+ bool empty() const { return _data.empty(); }
+
+ /// \brief Make the heap empty.
+ ///
+ /// This functon makes the heap empty.
+ /// It does not change the cross reference map. If you want to reuse
+ /// a heap that is not surely empty, you should first clear it and
+ /// then you should set the cross reference map to \c PRE_HEAP
+ /// for each item.
+ void clear() { _data.clear(); }
+
+ private:
+ static int parent(int i) { return (i-1)/4; }
+ static int firstChild(int i) { return 4*i+1; }
+
+ bool less(const Pair &p1, const Pair &p2) const {
+ return _comp(p1.second, p2.second);
+ }
+
+ void bubbleUp(int hole, Pair p) {
+ int par = parent(hole);
+ while( hole>0 && less(p,_data[par]) ) {
+ move(_data[par],hole);
+ hole = par;
+ par = parent(hole);
+ }
+ move(p, hole);
+ }
+
+ void bubbleDown(int hole, Pair p, int length) {
+ if( length>1 ) {
+ int child = firstChild(hole);
+ while( child+3<length ) {
+ int min=child;
+ if( less(_data[++child], _data[min]) ) min=child;
+ if( less(_data[++child], _data[min]) ) min=child;
+ if( less(_data[++child], _data[min]) ) min=child;
+ if( !less(_data[min], p) )
+ goto ok;
+ move(_data[min], hole);
+ hole = min;
+ child = firstChild(hole);
+ }
+ if ( child<length ) {
+ int min = child;
+ if( ++child<length && less(_data[child], _data[min]) ) min=child;
+ if( ++child<length && less(_data[child], _data[min]) ) min=child;
+ if( less(_data[min], p) ) {
+ move(_data[min], hole);
+ hole = min;
+ }
+ }
+ }
+ ok:
+ move(p, hole);
+ }
+
+ void move(const Pair &p, int i) {
+ _data[i] = p;
+ _iim.set(p.first, i);
+ }
+
+ public:
+ /// \brief Insert a pair of item and priority into the heap.
+ ///
+ /// This function inserts \c p.first to the heap with priority
+ /// \c p.second.
+ /// \param p The pair to insert.
+ /// \pre \c p.first must not be stored in the heap.
+ void push(const Pair &p) {
+ int n = _data.size();
+ _data.resize(n+1);
+ bubbleUp(n, p);
+ }
+
+ /// \brief Insert an item into the heap with the given priority.
+ ///
+ /// This function inserts the given item into the heap with the
+ /// given priority.
+ /// \param i The item to insert.
+ /// \param p The priority of the item.
+ /// \pre \e i must not be stored in the heap.
+ void push(const Item &i, const Prio &p) { push(Pair(i,p)); }
+
+ /// \brief Return the item having minimum priority.
+ ///
+ /// This function returns the item having minimum priority.
+ /// \pre The heap must be non-empty.
+ Item top() const { return _data[0].first; }
+
+ /// \brief The minimum priority.
+ ///
+ /// This function returns the minimum priority.
+ /// \pre The heap must be non-empty.
+ Prio prio() const { return _data[0].second; }
+
+ /// \brief Remove the item having minimum priority.
+ ///
+ /// This function removes the item having minimum priority.
+ /// \pre The heap must be non-empty.
+ void pop() {
+ int n = _data.size()-1;
+ _iim.set(_data[0].first, POST_HEAP);
+ if (n>0) bubbleDown(0, _data[n], n);
+ _data.pop_back();
+ }
+
+ /// \brief Remove the given item from the heap.
+ ///
+ /// This function removes the given item from the heap if it is
+ /// already stored.
+ /// \param i The item to delete.
+ /// \pre \e i must be in the heap.
+ void erase(const Item &i) {
+ int h = _iim[i];
+ int n = _data.size()-1;
+ _iim.set(_data[h].first, POST_HEAP);
+ if( h<n ) {
+ if( less(_data[parent(h)], _data[n]) )
+ bubbleDown(h, _data[n], n);
+ else
+ bubbleUp(h, _data[n]);
+ }
+ _data.pop_back();
+ }
+
+ /// \brief The priority of the given item.
+ ///
+ /// This function returns the priority of the given item.
+ /// \param i The item.
+ /// \pre \e i must be in the heap.
+ Prio operator[](const Item &i) const {
+ int idx = _iim[i];
+ return _data[idx].second;
+ }
+
+ /// \brief Set the priority of an item or insert it, if it is
+ /// not stored in the heap.
+ ///
+ /// This method sets the priority of the given item if it is
+ /// already stored in the heap. Otherwise it inserts the given
+ /// item into the heap with the given priority.
+ /// \param i The item.
+ /// \param p The priority.
+ void set(const Item &i, const Prio &p) {
+ int idx = _iim[i];
+ if( idx < 0 )
+ push(i,p);
+ else if( _comp(p, _data[idx].second) )
+ bubbleUp(idx, Pair(i,p));
+ else
+ bubbleDown(idx, Pair(i,p), _data.size());
+ }
+
+ /// \brief Decrease the priority of an item to the given value.
+ ///
+ /// This function decreases the priority of an item to the given value.
+ /// \param i The item.
+ /// \param p The priority.
+ /// \pre \e i must be stored in the heap with priority at least \e p.
+ void decrease(const Item &i, const Prio &p) {
+ int idx = _iim[i];
+ bubbleUp(idx, Pair(i,p));
+ }
+
+ /// \brief Increase the priority of an item to the given value.
+ ///
+ /// This function increases the priority of an item to the given value.
+ /// \param i The item.
+ /// \param p The priority.
+ /// \pre \e i must be stored in the heap with priority at most \e p.
+ void increase(const Item &i, const Prio &p) {
+ int idx = _iim[i];
+ bubbleDown(idx, Pair(i,p), _data.size());
+ }
+
+ /// \brief Return the state of an item.
+ ///
+ /// This method returns \c PRE_HEAP if the given item has never
+ /// been in the heap, \c IN_HEAP if it is in the heap at the moment,
+ /// and \c POST_HEAP otherwise.
+ /// In the latter case it is possible that the item will get back
+ /// to the heap again.
+ /// \param i The item.
+ State state(const Item &i) const {
+ int s = _iim[i];
+ if (s>=0) s=0;
+ return State(s);
+ }
+
+ /// \brief Set the state of an item in the heap.
+ ///
+ /// This function sets the state of the given item in the heap.
+ /// It can be used to manually clear the heap when it is important
+ /// to achive better time complexity.
+ /// \param i The item.
+ /// \param st The state. It should not be \c IN_HEAP.
+ void state(const Item& i, State st) {
+ switch (st) {
+ case POST_HEAP:
+ case PRE_HEAP:
+ if (state(i) == IN_HEAP) erase(i);
+ _iim[i] = st;
+ break;
+ case IN_HEAP:
+ break;
+ }
+ }
+
+ /// \brief Replace an item in the heap.
+ ///
+ /// This function replaces item \c i with item \c j.
+ /// Item \c i must be in the heap, while \c j must be out of the heap.
+ /// After calling this method, item \c i will be out of the
+ /// heap and \c j will be in the heap with the same prioriority
+ /// as item \c i had before.
+ void replace(const Item& i, const Item& j) {
+ int idx = _iim[i];
+ _iim.set(i, _iim[j]);
+ _iim.set(j, idx);
+ _data[idx].first = j;
+ }
+
+ }; // class QuadHeap
+
+} // namespace lemon
+
+#endif // LEMON_FOURARY_HEAP_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/radix_heap.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/radix_heap.h
new file mode 100644
index 00000000000..8701ce7474a
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/radix_heap.h
@@ -0,0 +1,438 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_RADIX_HEAP_H
+#define LEMON_RADIX_HEAP_H
+
+///\ingroup heaps
+///\file
+///\brief Radix heap implementation.
+
+#include <vector>
+#include <lemon/error.h>
+
+namespace lemon {
+
+
+ /// \ingroup heaps
+ ///
+ /// \brief Radix heap data structure.
+ ///
+ /// This class implements the \e radix \e heap data structure.
+ /// It practically conforms to the \ref concepts::Heap "heap concept",
+ /// but it has some limitations due its special implementation.
+ /// The type of the priorities must be \c int and the priority of an
+ /// item cannot be decreased under the priority of the last removed item.
+ ///
+ /// \tparam IM A read-writable item map with \c int values, used
+ /// internally to handle the cross references.
+ template <typename IM>
+ class RadixHeap {
+
+ public:
+
+ /// Type of the item-int map.
+ typedef IM ItemIntMap;
+ /// Type of the priorities.
+ typedef int Prio;
+ /// Type of the items stored in the heap.
+ typedef typename ItemIntMap::Key Item;
+
+ /// \brief Exception thrown by RadixHeap.
+ ///
+ /// This exception is thrown when an item is inserted into a
+ /// RadixHeap with a priority smaller than the last erased one.
+ /// \see RadixHeap
+ class PriorityUnderflowError : public Exception {
+ public:
+ virtual const char* what() const throw() {
+ return "lemon::RadixHeap::PriorityUnderflowError";
+ }
+ };
+
+ /// \brief Type to represent the states of the items.
+ ///
+ /// Each item has a state associated to it. It can be "in heap",
+ /// "pre-heap" or "post-heap". The latter two are indifferent from the
+ /// heap's point of view, but may be useful to the user.
+ ///
+ /// The item-int map must be initialized in such way that it assigns
+ /// \c PRE_HEAP (<tt>-1</tt>) to any element to be put in the heap.
+ enum State {
+ IN_HEAP = 0, ///< = 0.
+ PRE_HEAP = -1, ///< = -1.
+ POST_HEAP = -2 ///< = -2.
+ };
+
+ private:
+
+ struct RadixItem {
+ int prev, next, box;
+ Item item;
+ int prio;
+ RadixItem(Item _item, int _prio) : item(_item), prio(_prio) {}
+ };
+
+ struct RadixBox {
+ int first;
+ int min, size;
+ RadixBox(int _min, int _size) : first(-1), min(_min), size(_size) {}
+ };
+
+ std::vector<RadixItem> _data;
+ std::vector<RadixBox> _boxes;
+
+ ItemIntMap &_iim;
+
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ /// \param map A map that assigns \c int values to the items.
+ /// It is used internally to handle the cross references.
+ /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
+ /// \param minimum The initial minimum value of the heap.
+ /// \param capacity The initial capacity of the heap.
+ RadixHeap(ItemIntMap &map, int minimum = 0, int capacity = 0)
+ : _iim(map)
+ {
+ _boxes.push_back(RadixBox(minimum, 1));
+ _boxes.push_back(RadixBox(minimum + 1, 1));
+ while (lower(_boxes.size() - 1, capacity + minimum - 1)) {
+ extend();
+ }
+ }
+
+ /// \brief The number of items stored in the heap.
+ ///
+ /// This function returns the number of items stored in the heap.
+ int size() const { return _data.size(); }
+
+ /// \brief Check if the heap is empty.
+ ///
+ /// This function returns \c true if the heap is empty.
+ bool empty() const { return _data.empty(); }
+
+ /// \brief Make the heap empty.
+ ///
+ /// This functon makes the heap empty.
+ /// It does not change the cross reference map. If you want to reuse
+ /// a heap that is not surely empty, you should first clear it and
+ /// then you should set the cross reference map to \c PRE_HEAP
+ /// for each item.
+ /// \param minimum The minimum value of the heap.
+ /// \param capacity The capacity of the heap.
+ void clear(int minimum = 0, int capacity = 0) {
+ _data.clear(); _boxes.clear();
+ _boxes.push_back(RadixBox(minimum, 1));
+ _boxes.push_back(RadixBox(minimum + 1, 1));
+ while (lower(_boxes.size() - 1, capacity + minimum - 1)) {
+ extend();
+ }
+ }
+
+ private:
+
+ bool upper(int box, Prio pr) {
+ return pr < _boxes[box].min;
+ }
+
+ bool lower(int box, Prio pr) {
+ return pr >= _boxes[box].min + _boxes[box].size;
+ }
+
+ // Remove item from the box list
+ void remove(int index) {
+ if (_data[index].prev >= 0) {
+ _data[_data[index].prev].next = _data[index].next;
+ } else {
+ _boxes[_data[index].box].first = _data[index].next;
+ }
+ if (_data[index].next >= 0) {
+ _data[_data[index].next].prev = _data[index].prev;
+ }
+ }
+
+ // Insert item into the box list
+ void insert(int box, int index) {
+ if (_boxes[box].first == -1) {
+ _boxes[box].first = index;
+ _data[index].next = _data[index].prev = -1;
+ } else {
+ _data[index].next = _boxes[box].first;
+ _data[_boxes[box].first].prev = index;
+ _data[index].prev = -1;
+ _boxes[box].first = index;
+ }
+ _data[index].box = box;
+ }
+
+ // Add a new box to the box list
+ void extend() {
+ int min = _boxes.back().min + _boxes.back().size;
+ int bs = 2 * _boxes.back().size;
+ _boxes.push_back(RadixBox(min, bs));
+ }
+
+ // Move an item up into the proper box.
+ void bubbleUp(int index) {
+ if (!lower(_data[index].box, _data[index].prio)) return;
+ remove(index);
+ int box = findUp(_data[index].box, _data[index].prio);
+ insert(box, index);
+ }
+
+ // Find up the proper box for the item with the given priority
+ int findUp(int start, int pr) {
+ while (lower(start, pr)) {
+ if (++start == int(_boxes.size())) {
+ extend();
+ }
+ }
+ return start;
+ }
+
+ // Move an item down into the proper box
+ void bubbleDown(int index) {
+ if (!upper(_data[index].box, _data[index].prio)) return;
+ remove(index);
+ int box = findDown(_data[index].box, _data[index].prio);
+ insert(box, index);
+ }
+
+ // Find down the proper box for the item with the given priority
+ int findDown(int start, int pr) {
+ while (upper(start, pr)) {
+ if (--start < 0) throw PriorityUnderflowError();
+ }
+ return start;
+ }
+
+ // Find the first non-empty box
+ int findFirst() {
+ int first = 0;
+ while (_boxes[first].first == -1) ++first;
+ return first;
+ }
+
+ // Gives back the minimum priority of the given box
+ int minValue(int box) {
+ int min = _data[_boxes[box].first].prio;
+ for (int k = _boxes[box].first; k != -1; k = _data[k].next) {
+ if (_data[k].prio < min) min = _data[k].prio;
+ }
+ return min;
+ }
+
+ // Rearrange the items of the heap and make the first box non-empty
+ void moveDown() {
+ int box = findFirst();
+ if (box == 0) return;
+ int min = minValue(box);
+ for (int i = 0; i <= box; ++i) {
+ _boxes[i].min = min;
+ min += _boxes[i].size;
+ }
+ int curr = _boxes[box].first, next;
+ while (curr != -1) {
+ next = _data[curr].next;
+ bubbleDown(curr);
+ curr = next;
+ }
+ }
+
+ void relocateLast(int index) {
+ if (index != int(_data.size()) - 1) {
+ _data[index] = _data.back();
+ if (_data[index].prev != -1) {
+ _data[_data[index].prev].next = index;
+ } else {
+ _boxes[_data[index].box].first = index;
+ }
+ if (_data[index].next != -1) {
+ _data[_data[index].next].prev = index;
+ }
+ _iim[_data[index].item] = index;
+ }
+ _data.pop_back();
+ }
+
+ public:
+
+ /// \brief Insert an item into the heap with the given priority.
+ ///
+ /// This function inserts the given item into the heap with the
+ /// given priority.
+ /// \param i The item to insert.
+ /// \param p The priority of the item.
+ /// \pre \e i must not be stored in the heap.
+ /// \warning This method may throw an \c UnderFlowPriorityException.
+ void push(const Item &i, const Prio &p) {
+ int n = _data.size();
+ _iim.set(i, n);
+ _data.push_back(RadixItem(i, p));
+ while (lower(_boxes.size() - 1, p)) {
+ extend();
+ }
+ int box = findDown(_boxes.size() - 1, p);
+ insert(box, n);
+ }
+
+ /// \brief Return the item having minimum priority.
+ ///
+ /// This function returns the item having minimum priority.
+ /// \pre The heap must be non-empty.
+ Item top() const {
+ const_cast<RadixHeap<ItemIntMap>&>(*this).moveDown();
+ return _data[_boxes[0].first].item;
+ }
+
+ /// \brief The minimum priority.
+ ///
+ /// This function returns the minimum priority.
+ /// \pre The heap must be non-empty.
+ Prio prio() const {
+ const_cast<RadixHeap<ItemIntMap>&>(*this).moveDown();
+ return _data[_boxes[0].first].prio;
+ }
+
+ /// \brief Remove the item having minimum priority.
+ ///
+ /// This function removes the item having minimum priority.
+ /// \pre The heap must be non-empty.
+ void pop() {
+ moveDown();
+ int index = _boxes[0].first;
+ _iim[_data[index].item] = POST_HEAP;
+ remove(index);
+ relocateLast(index);
+ }
+
+ /// \brief Remove the given item from the heap.
+ ///
+ /// This function removes the given item from the heap if it is
+ /// already stored.
+ /// \param i The item to delete.
+ /// \pre \e i must be in the heap.
+ void erase(const Item &i) {
+ int index = _iim[i];
+ _iim[i] = POST_HEAP;
+ remove(index);
+ relocateLast(index);
+ }
+
+ /// \brief The priority of the given item.
+ ///
+ /// This function returns the priority of the given item.
+ /// \param i The item.
+ /// \pre \e i must be in the heap.
+ Prio operator[](const Item &i) const {
+ int idx = _iim[i];
+ return _data[idx].prio;
+ }
+
+ /// \brief Set the priority of an item or insert it, if it is
+ /// not stored in the heap.
+ ///
+ /// This method sets the priority of the given item if it is
+ /// already stored in the heap. Otherwise it inserts the given
+ /// item into the heap with the given priority.
+ /// \param i The item.
+ /// \param p The priority.
+ /// \pre \e i must be in the heap.
+ /// \warning This method may throw an \c UnderFlowPriorityException.
+ void set(const Item &i, const Prio &p) {
+ int idx = _iim[i];
+ if( idx < 0 ) {
+ push(i, p);
+ }
+ else if( p >= _data[idx].prio ) {
+ _data[idx].prio = p;
+ bubbleUp(idx);
+ } else {
+ _data[idx].prio = p;
+ bubbleDown(idx);
+ }
+ }
+
+ /// \brief Decrease the priority of an item to the given value.
+ ///
+ /// This function decreases the priority of an item to the given value.
+ /// \param i The item.
+ /// \param p The priority.
+ /// \pre \e i must be stored in the heap with priority at least \e p.
+ /// \warning This method may throw an \c UnderFlowPriorityException.
+ void decrease(const Item &i, const Prio &p) {
+ int idx = _iim[i];
+ _data[idx].prio = p;
+ bubbleDown(idx);
+ }
+
+ /// \brief Increase the priority of an item to the given value.
+ ///
+ /// This function increases the priority of an item to the given value.
+ /// \param i The item.
+ /// \param p The priority.
+ /// \pre \e i must be stored in the heap with priority at most \e p.
+ void increase(const Item &i, const Prio &p) {
+ int idx = _iim[i];
+ _data[idx].prio = p;
+ bubbleUp(idx);
+ }
+
+ /// \brief Return the state of an item.
+ ///
+ /// This method returns \c PRE_HEAP if the given item has never
+ /// been in the heap, \c IN_HEAP if it is in the heap at the moment,
+ /// and \c POST_HEAP otherwise.
+ /// In the latter case it is possible that the item will get back
+ /// to the heap again.
+ /// \param i The item.
+ State state(const Item &i) const {
+ int s = _iim[i];
+ if( s >= 0 ) s = 0;
+ return State(s);
+ }
+
+ /// \brief Set the state of an item in the heap.
+ ///
+ /// This function sets the state of the given item in the heap.
+ /// It can be used to manually clear the heap when it is important
+ /// to achive better time complexity.
+ /// \param i The item.
+ /// \param st The state. It should not be \c IN_HEAP.
+ void state(const Item& i, State st) {
+ switch (st) {
+ case POST_HEAP:
+ case PRE_HEAP:
+ if (state(i) == IN_HEAP) {
+ erase(i);
+ }
+ _iim[i] = st;
+ break;
+ case IN_HEAP:
+ break;
+ }
+ }
+
+ }; // class RadixHeap
+
+} // namespace lemon
+
+#endif // LEMON_RADIX_HEAP_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/radix_sort.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/radix_sort.h
new file mode 100644
index 00000000000..d80875663b0
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/radix_sort.h
@@ -0,0 +1,487 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef RADIX_SORT_H
+#define RADIX_SORT_H
+
+/// \ingroup auxalg
+/// \file
+/// \brief Radix sort
+///
+/// Linear time sorting algorithms
+
+#include <vector>
+#include <limits>
+#include <iterator>
+#include <algorithm>
+
+namespace lemon {
+
+ namespace _radix_sort_bits {
+
+ template <typename Iterator>
+ bool unitRange(Iterator first, Iterator last) {
+ ++first;
+ return first == last;
+ }
+
+ template <typename Value>
+ struct Identity {
+ const Value& operator()(const Value& val) {
+ return val;
+ }
+ };
+
+
+ template <typename Value, typename Iterator, typename Functor>
+ Iterator radixSortPartition(Iterator first, Iterator last,
+ Functor functor, Value mask) {
+ while (first != last && !(functor(*first) & mask)) {
+ ++first;
+ }
+ if (first == last) {
+ return first;
+ }
+ --last;
+ while (first != last && (functor(*last) & mask)) {
+ --last;
+ }
+ if (first == last) {
+ return first;
+ }
+ std::iter_swap(first, last);
+ ++first;
+ while (true) {
+ while (!(functor(*first) & mask)) {
+ ++first;
+ }
+ --last;
+ while (functor(*last) & mask) {
+ --last;
+ }
+ if (unitRange(last, first)) {
+ return first;
+ }
+ std::iter_swap(first, last);
+ ++first;
+ }
+ }
+
+ template <typename Iterator, typename Functor>
+ Iterator radixSortSignPartition(Iterator first, Iterator last,
+ Functor functor) {
+ while (first != last && functor(*first) < 0) {
+ ++first;
+ }
+ if (first == last) {
+ return first;
+ }
+ --last;
+ while (first != last && functor(*last) >= 0) {
+ --last;
+ }
+ if (first == last) {
+ return first;
+ }
+ std::iter_swap(first, last);
+ ++first;
+ while (true) {
+ while (functor(*first) < 0) {
+ ++first;
+ }
+ --last;
+ while (functor(*last) >= 0) {
+ --last;
+ }
+ if (unitRange(last, first)) {
+ return first;
+ }
+ std::iter_swap(first, last);
+ ++first;
+ }
+ }
+
+ template <typename Value, typename Iterator, typename Functor>
+ void radixIntroSort(Iterator first, Iterator last,
+ Functor functor, Value mask) {
+ while (mask != 0 && first != last && !unitRange(first, last)) {
+ Iterator cut = radixSortPartition(first, last, functor, mask);
+ mask >>= 1;
+ radixIntroSort(first, cut, functor, mask);
+ first = cut;
+ }
+ }
+
+ template <typename Value, typename Iterator, typename Functor>
+ void radixSignedSort(Iterator first, Iterator last, Functor functor) {
+
+ Iterator cut = radixSortSignPartition(first, last, functor);
+
+ Value mask;
+ int max_digit;
+ Iterator it;
+
+ mask = ~0; max_digit = 0;
+ for (it = first; it != cut; ++it) {
+ while ((mask & functor(*it)) != mask) {
+ ++max_digit;
+ mask <<= 1;
+ }
+ }
+ radixIntroSort(first, cut, functor, 1 << max_digit);
+
+ mask = 0; max_digit = 0;
+ for (it = cut; it != last; ++it) {
+ while ((mask | functor(*it)) != mask) {
+ ++max_digit;
+ mask <<= 1; mask |= 1;
+ }
+ }
+ radixIntroSort(cut, last, functor, 1 << max_digit);
+ }
+
+ template <typename Value, typename Iterator, typename Functor>
+ void radixUnsignedSort(Iterator first, Iterator last, Functor functor) {
+
+ Value mask = 0;
+ int max_digit = 0;
+
+ Iterator it;
+ for (it = first; it != last; ++it) {
+ while ((mask | functor(*it)) != mask) {
+ ++max_digit;
+ mask <<= 1; mask |= 1;
+ }
+ }
+ radixIntroSort(first, last, functor, 1 << max_digit);
+ }
+
+
+ template <typename Value,
+ bool sign = std::numeric_limits<Value>::is_signed >
+ struct RadixSortSelector {
+ template <typename Iterator, typename Functor>
+ static void sort(Iterator first, Iterator last, Functor functor) {
+ radixSignedSort<Value>(first, last, functor);
+ }
+ };
+
+ template <typename Value>
+ struct RadixSortSelector<Value, false> {
+ template <typename Iterator, typename Functor>
+ static void sort(Iterator first, Iterator last, Functor functor) {
+ radixUnsignedSort<Value>(first, last, functor);
+ }
+ };
+
+ }
+
+ /// \ingroup auxalg
+ ///
+ /// \brief Sorts the STL compatible range into ascending order.
+ ///
+ /// The \c radixSort sorts an STL compatible range into ascending
+ /// order. The radix sort algorithm can sort items which are mapped
+ /// to integers with an adaptable unary function \c functor and the
+ /// order will be ascending according to these mapped values.
+ ///
+ /// It is also possible to use a normal function instead
+ /// of the functor object. If the functor is not given it will use
+ /// the identity function instead.
+ ///
+ /// This is a special quick sort algorithm where the pivot
+ /// values to split the items are choosen to be 2<sup>k</sup>
+ /// for each \c k.
+ /// Therefore, the time complexity of the algorithm is O(log(c)*n) and
+ /// it uses O(log(c)) additional space, where \c c is the maximal value
+ /// and \c n is the number of the items in the container.
+ ///
+ /// \param first The begin of the given range.
+ /// \param last The end of the given range.
+ /// \param functor An adaptible unary function or a normal function
+ /// which maps the items to any integer type which can be either
+ /// signed or unsigned.
+ ///
+ /// \sa stableRadixSort()
+ template <typename Iterator, typename Functor>
+ void radixSort(Iterator first, Iterator last, Functor functor) {
+ using namespace _radix_sort_bits;
+ typedef typename Functor::result_type Value;
+ RadixSortSelector<Value>::sort(first, last, functor);
+ }
+
+ template <typename Iterator, typename Value, typename Key>
+ void radixSort(Iterator first, Iterator last, Value (*functor)(Key)) {
+ using namespace _radix_sort_bits;
+ RadixSortSelector<Value>::sort(first, last, functor);
+ }
+
+ template <typename Iterator, typename Value, typename Key>
+ void radixSort(Iterator first, Iterator last, Value& (*functor)(Key)) {
+ using namespace _radix_sort_bits;
+ RadixSortSelector<Value>::sort(first, last, functor);
+ }
+
+ template <typename Iterator, typename Value, typename Key>
+ void radixSort(Iterator first, Iterator last, Value (*functor)(Key&)) {
+ using namespace _radix_sort_bits;
+ RadixSortSelector<Value>::sort(first, last, functor);
+ }
+
+ template <typename Iterator, typename Value, typename Key>
+ void radixSort(Iterator first, Iterator last, Value& (*functor)(Key&)) {
+ using namespace _radix_sort_bits;
+ RadixSortSelector<Value>::sort(first, last, functor);
+ }
+
+ template <typename Iterator>
+ void radixSort(Iterator first, Iterator last) {
+ using namespace _radix_sort_bits;
+ typedef typename std::iterator_traits<Iterator>::value_type Value;
+ RadixSortSelector<Value>::sort(first, last, Identity<Value>());
+ }
+
+ namespace _radix_sort_bits {
+
+ template <typename Value>
+ unsigned char valueByte(Value value, int byte) {
+ return value >> (std::numeric_limits<unsigned char>::digits * byte);
+ }
+
+ template <typename Functor, typename Key>
+ void stableRadixIntroSort(Key *first, Key *last, Key *target,
+ int byte, Functor functor) {
+ const int size =
+ unsigned(std::numeric_limits<unsigned char>::max()) + 1;
+ std::vector<int> counter(size);
+ for (int i = 0; i < size; ++i) {
+ counter[i] = 0;
+ }
+ Key *it = first;
+ while (first != last) {
+ ++counter[valueByte(functor(*first), byte)];
+ ++first;
+ }
+ int prev, num = 0;
+ for (int i = 0; i < size; ++i) {
+ prev = num;
+ num += counter[i];
+ counter[i] = prev;
+ }
+ while (it != last) {
+ target[counter[valueByte(functor(*it), byte)]++] = *it;
+ ++it;
+ }
+ }
+
+ template <typename Functor, typename Key>
+ void signedStableRadixIntroSort(Key *first, Key *last, Key *target,
+ int byte, Functor functor) {
+ const int size =
+ unsigned(std::numeric_limits<unsigned char>::max()) + 1;
+ std::vector<int> counter(size);
+ for (int i = 0; i < size; ++i) {
+ counter[i] = 0;
+ }
+ Key *it = first;
+ while (first != last) {
+ counter[valueByte(functor(*first), byte)]++;
+ ++first;
+ }
+ int prev, num = 0;
+ for (int i = size / 2; i < size; ++i) {
+ prev = num;
+ num += counter[i];
+ counter[i] = prev;
+ }
+ for (int i = 0; i < size / 2; ++i) {
+ prev = num;
+ num += counter[i];
+ counter[i] = prev;
+ }
+ while (it != last) {
+ target[counter[valueByte(functor(*it), byte)]++] = *it;
+ ++it;
+ }
+ }
+
+
+ template <typename Value, typename Iterator, typename Functor>
+ void stableRadixSignedSort(Iterator first, Iterator last, Functor functor) {
+ if (first == last) return;
+ typedef typename std::iterator_traits<Iterator>::value_type Key;
+ typedef std::allocator<Key> Allocator;
+ Allocator allocator;
+
+ int length = std::distance(first, last);
+ Key* buffer = allocator.allocate(2 * length);
+ try {
+ bool dir = true;
+ std::copy(first, last, buffer);
+ for (int i = 0; i < int(sizeof(Value)) - 1; ++i) {
+ if (dir) {
+ stableRadixIntroSort(buffer, buffer + length, buffer + length,
+ i, functor);
+ } else {
+ stableRadixIntroSort(buffer + length, buffer + 2 * length, buffer,
+ i, functor);
+ }
+ dir = !dir;
+ }
+ if (dir) {
+ signedStableRadixIntroSort(buffer, buffer + length, buffer + length,
+ sizeof(Value) - 1, functor);
+ std::copy(buffer + length, buffer + 2 * length, first);
+ } else {
+ signedStableRadixIntroSort(buffer + length, buffer + 2 * length,
+ buffer, sizeof(Value) - 1, functor);
+ std::copy(buffer, buffer + length, first);
+ }
+ } catch (...) {
+ allocator.deallocate(buffer, 2 * length);
+ throw;
+ }
+ allocator.deallocate(buffer, 2 * length);
+ }
+
+ template <typename Value, typename Iterator, typename Functor>
+ void stableRadixUnsignedSort(Iterator first, Iterator last,
+ Functor functor) {
+ if (first == last) return;
+ typedef typename std::iterator_traits<Iterator>::value_type Key;
+ typedef std::allocator<Key> Allocator;
+ Allocator allocator;
+
+ int length = std::distance(first, last);
+ Key *buffer = allocator.allocate(2 * length);
+ try {
+ bool dir = true;
+ std::copy(first, last, buffer);
+ for (int i = 0; i < int(sizeof(Value)); ++i) {
+ if (dir) {
+ stableRadixIntroSort(buffer, buffer + length,
+ buffer + length, i, functor);
+ } else {
+ stableRadixIntroSort(buffer + length, buffer + 2 * length,
+ buffer, i, functor);
+ }
+ dir = !dir;
+ }
+ if (dir) {
+ std::copy(buffer, buffer + length, first);
+ } else {
+ std::copy(buffer + length, buffer + 2 * length, first);
+ }
+ } catch (...) {
+ allocator.deallocate(buffer, 2 * length);
+ throw;
+ }
+ allocator.deallocate(buffer, 2 * length);
+ }
+
+
+
+ template <typename Value,
+ bool sign = std::numeric_limits<Value>::is_signed >
+ struct StableRadixSortSelector {
+ template <typename Iterator, typename Functor>
+ static void sort(Iterator first, Iterator last, Functor functor) {
+ stableRadixSignedSort<Value>(first, last, functor);
+ }
+ };
+
+ template <typename Value>
+ struct StableRadixSortSelector<Value, false> {
+ template <typename Iterator, typename Functor>
+ static void sort(Iterator first, Iterator last, Functor functor) {
+ stableRadixUnsignedSort<Value>(first, last, functor);
+ }
+ };
+
+ }
+
+ /// \ingroup auxalg
+ ///
+ /// \brief Sorts the STL compatible range into ascending order in a stable
+ /// way.
+ ///
+ /// This function sorts an STL compatible range into ascending
+ /// order according to an integer mapping in the same as radixSort() does.
+ ///
+ /// This sorting algorithm is stable, i.e. the order of two equal
+ /// elements remains the same after the sorting.
+ ///
+ /// This sort algorithm use a radix forward sort on the
+ /// bytes of the integer number. The algorithm sorts the items
+ /// byte-by-byte. First, it counts how many times a byte value occurs
+ /// in the container, then it copies the corresponding items to
+ /// another container in asceding order in O(n) time.
+ ///
+ /// The time complexity of the algorithm is O(log(c)*n) and
+ /// it uses O(n) additional space, where \c c is the
+ /// maximal value and \c n is the number of the items in the
+ /// container.
+ ///
+
+ /// \param first The begin of the given range.
+ /// \param last The end of the given range.
+ /// \param functor An adaptible unary function or a normal function
+ /// which maps the items to any integer type which can be either
+ /// signed or unsigned.
+ /// \sa radixSort()
+ template <typename Iterator, typename Functor>
+ void stableRadixSort(Iterator first, Iterator last, Functor functor) {
+ using namespace _radix_sort_bits;
+ typedef typename Functor::result_type Value;
+ StableRadixSortSelector<Value>::sort(first, last, functor);
+ }
+
+ template <typename Iterator, typename Value, typename Key>
+ void stableRadixSort(Iterator first, Iterator last, Value (*functor)(Key)) {
+ using namespace _radix_sort_bits;
+ StableRadixSortSelector<Value>::sort(first, last, functor);
+ }
+
+ template <typename Iterator, typename Value, typename Key>
+ void stableRadixSort(Iterator first, Iterator last, Value& (*functor)(Key)) {
+ using namespace _radix_sort_bits;
+ StableRadixSortSelector<Value>::sort(first, last, functor);
+ }
+
+ template <typename Iterator, typename Value, typename Key>
+ void stableRadixSort(Iterator first, Iterator last, Value (*functor)(Key&)) {
+ using namespace _radix_sort_bits;
+ StableRadixSortSelector<Value>::sort(first, last, functor);
+ }
+
+ template <typename Iterator, typename Value, typename Key>
+ void stableRadixSort(Iterator first, Iterator last, Value& (*functor)(Key&)) {
+ using namespace _radix_sort_bits;
+ StableRadixSortSelector<Value>::sort(first, last, functor);
+ }
+
+ template <typename Iterator>
+ void stableRadixSort(Iterator first, Iterator last) {
+ using namespace _radix_sort_bits;
+ typedef typename std::iterator_traits<Iterator>::value_type Value;
+ StableRadixSortSelector<Value>::sort(first, last, Identity<Value>());
+ }
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/random.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/random.cc
new file mode 100644
index 00000000000..02951210bdf
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/random.cc
@@ -0,0 +1,29 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+///\file
+///\brief Instantiation of the Random class.
+
+#include <lemon/random.h>
+
+namespace lemon {
+ /// \brief Global random number generator instance
+ ///
+ /// A global Mersenne Twister random number generator instance.
+ Random rnd;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/random.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/random.h
new file mode 100644
index 00000000000..8de74ede8a9
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/random.h
@@ -0,0 +1,1005 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+/*
+ * This file contains the reimplemented version of the Mersenne Twister
+ * Generator of Matsumoto and Nishimura.
+ *
+ * See the appropriate copyright notice below.
+ *
+ * Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. The names of its contributors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * Any feedback is very welcome.
+ * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+ * email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
+ */
+
+#ifndef LEMON_RANDOM_H
+#define LEMON_RANDOM_H
+
+#include <algorithm>
+#include <iterator>
+#include <vector>
+#include <limits>
+#include <fstream>
+
+#include <lemon/math.h>
+#include <lemon/dim2.h>
+
+#ifndef WIN32
+#include <sys/time.h>
+#include <ctime>
+#include <sys/types.h>
+#include <unistd.h>
+#else
+#include <lemon/bits/windows.h>
+#endif
+
+///\ingroup misc
+///\file
+///\brief Mersenne Twister random number generator
+
+namespace lemon {
+
+ namespace _random_bits {
+
+ template <typename _Word, int _bits = std::numeric_limits<_Word>::digits>
+ struct RandomTraits {};
+
+ template <typename _Word>
+ struct RandomTraits<_Word, 32> {
+
+ typedef _Word Word;
+ static const int bits = 32;
+
+ static const int length = 624;
+ static const int shift = 397;
+
+ static const Word mul = 0x6c078965u;
+ static const Word arrayInit = 0x012BD6AAu;
+ static const Word arrayMul1 = 0x0019660Du;
+ static const Word arrayMul2 = 0x5D588B65u;
+
+ static const Word mask = 0x9908B0DFu;
+ static const Word loMask = (1u << 31) - 1;
+ static const Word hiMask = ~loMask;
+
+
+ static Word tempering(Word rnd) {
+ rnd ^= (rnd >> 11);
+ rnd ^= (rnd << 7) & 0x9D2C5680u;
+ rnd ^= (rnd << 15) & 0xEFC60000u;
+ rnd ^= (rnd >> 18);
+ return rnd;
+ }
+
+ };
+
+ template <typename _Word>
+ struct RandomTraits<_Word, 64> {
+
+ typedef _Word Word;
+ static const int bits = 64;
+
+ static const int length = 312;
+ static const int shift = 156;
+
+ static const Word mul = Word(0x5851F42Du) << 32 | Word(0x4C957F2Du);
+ static const Word arrayInit = Word(0x00000000u) << 32 |Word(0x012BD6AAu);
+ static const Word arrayMul1 = Word(0x369DEA0Fu) << 32 |Word(0x31A53F85u);
+ static const Word arrayMul2 = Word(0x27BB2EE6u) << 32 |Word(0x87B0B0FDu);
+
+ static const Word mask = Word(0xB5026F5Au) << 32 | Word(0xA96619E9u);
+ static const Word loMask = (Word(1u) << 31) - 1;
+ static const Word hiMask = ~loMask;
+
+ static Word tempering(Word rnd) {
+ rnd ^= (rnd >> 29) & (Word(0x55555555u) << 32 | Word(0x55555555u));
+ rnd ^= (rnd << 17) & (Word(0x71D67FFFu) << 32 | Word(0xEDA60000u));
+ rnd ^= (rnd << 37) & (Word(0xFFF7EEE0u) << 32 | Word(0x00000000u));
+ rnd ^= (rnd >> 43);
+ return rnd;
+ }
+
+ };
+
+ template <typename _Word>
+ class RandomCore {
+ public:
+
+ typedef _Word Word;
+
+ private:
+
+ static const int bits = RandomTraits<Word>::bits;
+
+ static const int length = RandomTraits<Word>::length;
+ static const int shift = RandomTraits<Word>::shift;
+
+ public:
+
+ void initState() {
+ static const Word seedArray[4] = {
+ 0x12345u, 0x23456u, 0x34567u, 0x45678u
+ };
+
+ initState(seedArray, seedArray + 4);
+ }
+
+ void initState(Word seed) {
+
+ static const Word mul = RandomTraits<Word>::mul;
+
+ current = state;
+
+ Word *curr = state + length - 1;
+ curr[0] = seed; --curr;
+ for (int i = 1; i < length; ++i) {
+ curr[0] = (mul * ( curr[1] ^ (curr[1] >> (bits - 2)) ) + i);
+ --curr;
+ }
+ }
+
+ template <typename Iterator>
+ void initState(Iterator begin, Iterator end) {
+
+ static const Word init = RandomTraits<Word>::arrayInit;
+ static const Word mul1 = RandomTraits<Word>::arrayMul1;
+ static const Word mul2 = RandomTraits<Word>::arrayMul2;
+
+
+ Word *curr = state + length - 1; --curr;
+ Iterator it = begin; int cnt = 0;
+ int num;
+
+ initState(init);
+
+ num = length > end - begin ? length : end - begin;
+ while (num--) {
+ curr[0] = (curr[0] ^ ((curr[1] ^ (curr[1] >> (bits - 2))) * mul1))
+ + *it + cnt;
+ ++it; ++cnt;
+ if (it == end) {
+ it = begin; cnt = 0;
+ }
+ if (curr == state) {
+ curr = state + length - 1; curr[0] = state[0];
+ }
+ --curr;
+ }
+
+ num = length - 1; cnt = length - (curr - state) - 1;
+ while (num--) {
+ curr[0] = (curr[0] ^ ((curr[1] ^ (curr[1] >> (bits - 2))) * mul2))
+ - cnt;
+ --curr; ++cnt;
+ if (curr == state) {
+ curr = state + length - 1; curr[0] = state[0]; --curr;
+ cnt = 1;
+ }
+ }
+
+ state[length - 1] = Word(1) << (bits - 1);
+ }
+
+ void copyState(const RandomCore& other) {
+ std::copy(other.state, other.state + length, state);
+ current = state + (other.current - other.state);
+ }
+
+ Word operator()() {
+ if (current == state) fillState();
+ --current;
+ Word rnd = *current;
+ return RandomTraits<Word>::tempering(rnd);
+ }
+
+ private:
+
+
+ void fillState() {
+ static const Word mask[2] = { 0x0ul, RandomTraits<Word>::mask };
+ static const Word loMask = RandomTraits<Word>::loMask;
+ static const Word hiMask = RandomTraits<Word>::hiMask;
+
+ current = state + length;
+
+ register Word *curr = state + length - 1;
+ register long num;
+
+ num = length - shift;
+ while (num--) {
+ curr[0] = (((curr[0] & hiMask) | (curr[-1] & loMask)) >> 1) ^
+ curr[- shift] ^ mask[curr[-1] & 1ul];
+ --curr;
+ }
+ num = shift - 1;
+ while (num--) {
+ curr[0] = (((curr[0] & hiMask) | (curr[-1] & loMask)) >> 1) ^
+ curr[length - shift] ^ mask[curr[-1] & 1ul];
+ --curr;
+ }
+ state[0] = (((state[0] & hiMask) | (curr[length - 1] & loMask)) >> 1) ^
+ curr[length - shift] ^ mask[curr[length - 1] & 1ul];
+
+ }
+
+
+ Word *current;
+ Word state[length];
+
+ };
+
+
+ template <typename Result,
+ int shift = (std::numeric_limits<Result>::digits + 1) / 2>
+ struct Masker {
+ static Result mask(const Result& result) {
+ return Masker<Result, (shift + 1) / 2>::
+ mask(static_cast<Result>(result | (result >> shift)));
+ }
+ };
+
+ template <typename Result>
+ struct Masker<Result, 1> {
+ static Result mask(const Result& result) {
+ return static_cast<Result>(result | (result >> 1));
+ }
+ };
+
+ template <typename Result, typename Word,
+ int rest = std::numeric_limits<Result>::digits, int shift = 0,
+ bool last = rest <= std::numeric_limits<Word>::digits>
+ struct IntConversion {
+ static const int bits = std::numeric_limits<Word>::digits;
+
+ static Result convert(RandomCore<Word>& rnd) {
+ return static_cast<Result>(rnd() >> (bits - rest)) << shift;
+ }
+
+ };
+
+ template <typename Result, typename Word, int rest, int shift>
+ struct IntConversion<Result, Word, rest, shift, false> {
+ static const int bits = std::numeric_limits<Word>::digits;
+
+ static Result convert(RandomCore<Word>& rnd) {
+ return (static_cast<Result>(rnd()) << shift) |
+ IntConversion<Result, Word, rest - bits, shift + bits>::convert(rnd);
+ }
+ };
+
+
+ template <typename Result, typename Word,
+ bool one_word = (std::numeric_limits<Word>::digits <
+ std::numeric_limits<Result>::digits) >
+ struct Mapping {
+ static Result map(RandomCore<Word>& rnd, const Result& bound) {
+ Word max = Word(bound - 1);
+ Result mask = Masker<Result>::mask(bound - 1);
+ Result num;
+ do {
+ num = IntConversion<Result, Word>::convert(rnd) & mask;
+ } while (num > max);
+ return num;
+ }
+ };
+
+ template <typename Result, typename Word>
+ struct Mapping<Result, Word, false> {
+ static Result map(RandomCore<Word>& rnd, const Result& bound) {
+ Word max = Word(bound - 1);
+ Word mask = Masker<Word, (std::numeric_limits<Result>::digits + 1) / 2>
+ ::mask(max);
+ Word num;
+ do {
+ num = rnd() & mask;
+ } while (num > max);
+ return num;
+ }
+ };
+
+ template <typename Result, int exp>
+ struct ShiftMultiplier {
+ static const Result multiplier() {
+ Result res = ShiftMultiplier<Result, exp / 2>::multiplier();
+ res *= res;
+ if ((exp & 1) == 1) res *= static_cast<Result>(0.5);
+ return res;
+ }
+ };
+
+ template <typename Result>
+ struct ShiftMultiplier<Result, 0> {
+ static const Result multiplier() {
+ return static_cast<Result>(1.0);
+ }
+ };
+
+ template <typename Result>
+ struct ShiftMultiplier<Result, 20> {
+ static const Result multiplier() {
+ return static_cast<Result>(1.0/1048576.0);
+ }
+ };
+
+ template <typename Result>
+ struct ShiftMultiplier<Result, 32> {
+ static const Result multiplier() {
+ return static_cast<Result>(1.0/4294967296.0);
+ }
+ };
+
+ template <typename Result>
+ struct ShiftMultiplier<Result, 53> {
+ static const Result multiplier() {
+ return static_cast<Result>(1.0/9007199254740992.0);
+ }
+ };
+
+ template <typename Result>
+ struct ShiftMultiplier<Result, 64> {
+ static const Result multiplier() {
+ return static_cast<Result>(1.0/18446744073709551616.0);
+ }
+ };
+
+ template <typename Result, int exp>
+ struct Shifting {
+ static Result shift(const Result& result) {
+ return result * ShiftMultiplier<Result, exp>::multiplier();
+ }
+ };
+
+ template <typename Result, typename Word,
+ int rest = std::numeric_limits<Result>::digits, int shift = 0,
+ bool last = rest <= std::numeric_limits<Word>::digits>
+ struct RealConversion{
+ static const int bits = std::numeric_limits<Word>::digits;
+
+ static Result convert(RandomCore<Word>& rnd) {
+ return Shifting<Result, shift + rest>::
+ shift(static_cast<Result>(rnd() >> (bits - rest)));
+ }
+ };
+
+ template <typename Result, typename Word, int rest, int shift>
+ struct RealConversion<Result, Word, rest, shift, false> {
+ static const int bits = std::numeric_limits<Word>::digits;
+
+ static Result convert(RandomCore<Word>& rnd) {
+ return Shifting<Result, shift + bits>::
+ shift(static_cast<Result>(rnd())) +
+ RealConversion<Result, Word, rest-bits, shift + bits>::
+ convert(rnd);
+ }
+ };
+
+ template <typename Result, typename Word>
+ struct Initializer {
+
+ template <typename Iterator>
+ static void init(RandomCore<Word>& rnd, Iterator begin, Iterator end) {
+ std::vector<Word> ws;
+ for (Iterator it = begin; it != end; ++it) {
+ ws.push_back(Word(*it));
+ }
+ rnd.initState(ws.begin(), ws.end());
+ }
+
+ static void init(RandomCore<Word>& rnd, Result seed) {
+ rnd.initState(seed);
+ }
+ };
+
+ template <typename Word>
+ struct BoolConversion {
+ static bool convert(RandomCore<Word>& rnd) {
+ return (rnd() & 1) == 1;
+ }
+ };
+
+ template <typename Word>
+ struct BoolProducer {
+ Word buffer;
+ int num;
+
+ BoolProducer() : num(0) {}
+
+ bool convert(RandomCore<Word>& rnd) {
+ if (num == 0) {
+ buffer = rnd();
+ num = RandomTraits<Word>::bits;
+ }
+ bool r = (buffer & 1);
+ buffer >>= 1;
+ --num;
+ return r;
+ }
+ };
+
+ }
+
+ /// \ingroup misc
+ ///
+ /// \brief Mersenne Twister random number generator
+ ///
+ /// The Mersenne Twister is a twisted generalized feedback
+ /// shift-register generator of Matsumoto and Nishimura. The period
+ /// of this generator is \f$ 2^{19937} - 1 \f$ and it is
+ /// equi-distributed in 623 dimensions for 32-bit numbers. The time
+ /// performance of this generator is comparable to the commonly used
+ /// generators.
+ ///
+ /// This implementation is specialized for both 32-bit and 64-bit
+ /// architectures. The generators differ sligthly in the
+ /// initialization and generation phase so they produce two
+ /// completly different sequences.
+ ///
+ /// The generator gives back random numbers of serveral types. To
+ /// get a random number from a range of a floating point type you
+ /// can use one form of the \c operator() or the \c real() member
+ /// function. If you want to get random number from the {0, 1, ...,
+ /// n-1} integer range use the \c operator[] or the \c integer()
+ /// method. And to get random number from the whole range of an
+ /// integer type you can use the argumentless \c integer() or \c
+ /// uinteger() functions. After all you can get random bool with
+ /// equal chance of true and false or given probability of true
+ /// result with the \c boolean() member functions.
+ ///
+ ///\code
+ /// // The commented code is identical to the other
+ /// double a = rnd(); // [0.0, 1.0)
+ /// // double a = rnd.real(); // [0.0, 1.0)
+ /// double b = rnd(100.0); // [0.0, 100.0)
+ /// // double b = rnd.real(100.0); // [0.0, 100.0)
+ /// double c = rnd(1.0, 2.0); // [1.0, 2.0)
+ /// // double c = rnd.real(1.0, 2.0); // [1.0, 2.0)
+ /// int d = rnd[100000]; // 0..99999
+ /// // int d = rnd.integer(100000); // 0..99999
+ /// int e = rnd[6] + 1; // 1..6
+ /// // int e = rnd.integer(1, 1 + 6); // 1..6
+ /// int b = rnd.uinteger<int>(); // 0 .. 2^31 - 1
+ /// int c = rnd.integer<int>(); // - 2^31 .. 2^31 - 1
+ /// bool g = rnd.boolean(); // P(g = true) = 0.5
+ /// bool h = rnd.boolean(0.8); // P(h = true) = 0.8
+ ///\endcode
+ ///
+ /// LEMON provides a global instance of the random number
+ /// generator which name is \ref lemon::rnd "rnd". Usually it is a
+ /// good programming convenience to use this global generator to get
+ /// random numbers.
+ class Random {
+ private:
+
+ // Architecture word
+ typedef unsigned long Word;
+
+ _random_bits::RandomCore<Word> core;
+ _random_bits::BoolProducer<Word> bool_producer;
+
+
+ public:
+
+ ///\name Initialization
+ ///
+ /// @{
+
+ /// \brief Default constructor
+ ///
+ /// Constructor with constant seeding.
+ Random() { core.initState(); }
+
+ /// \brief Constructor with seed
+ ///
+ /// Constructor with seed. The current number type will be converted
+ /// to the architecture word type.
+ template <typename Number>
+ Random(Number seed) {
+ _random_bits::Initializer<Number, Word>::init(core, seed);
+ }
+
+ /// \brief Constructor with array seeding
+ ///
+ /// Constructor with array seeding. The given range should contain
+ /// any number type and the numbers will be converted to the
+ /// architecture word type.
+ template <typename Iterator>
+ Random(Iterator begin, Iterator end) {
+ typedef typename std::iterator_traits<Iterator>::value_type Number;
+ _random_bits::Initializer<Number, Word>::init(core, begin, end);
+ }
+
+ /// \brief Copy constructor
+ ///
+ /// Copy constructor. The generated sequence will be identical to
+ /// the other sequence. It can be used to save the current state
+ /// of the generator and later use it to generate the same
+ /// sequence.
+ Random(const Random& other) {
+ core.copyState(other.core);
+ }
+
+ /// \brief Assign operator
+ ///
+ /// Assign operator. The generated sequence will be identical to
+ /// the other sequence. It can be used to save the current state
+ /// of the generator and later use it to generate the same
+ /// sequence.
+ Random& operator=(const Random& other) {
+ if (&other != this) {
+ core.copyState(other.core);
+ }
+ return *this;
+ }
+
+ /// \brief Seeding random sequence
+ ///
+ /// Seeding the random sequence. The current number type will be
+ /// converted to the architecture word type.
+ template <typename Number>
+ void seed(Number seed) {
+ _random_bits::Initializer<Number, Word>::init(core, seed);
+ }
+
+ /// \brief Seeding random sequence
+ ///
+ /// Seeding the random sequence. The given range should contain
+ /// any number type and the numbers will be converted to the
+ /// architecture word type.
+ template <typename Iterator>
+ void seed(Iterator begin, Iterator end) {
+ typedef typename std::iterator_traits<Iterator>::value_type Number;
+ _random_bits::Initializer<Number, Word>::init(core, begin, end);
+ }
+
+ /// \brief Seeding from file or from process id and time
+ ///
+ /// By default, this function calls the \c seedFromFile() member
+ /// function with the <tt>/dev/urandom</tt> file. If it does not success,
+ /// it uses the \c seedFromTime().
+ /// \return Currently always \c true.
+ bool seed() {
+#ifndef WIN32
+ if (seedFromFile("/dev/urandom", 0)) return true;
+#endif
+ if (seedFromTime()) return true;
+ return false;
+ }
+
+ /// \brief Seeding from file
+ ///
+ /// Seeding the random sequence from file. The linux kernel has two
+ /// devices, <tt>/dev/random</tt> and <tt>/dev/urandom</tt> which
+ /// could give good seed values for pseudo random generators (The
+ /// difference between two devices is that the <tt>random</tt> may
+ /// block the reading operation while the kernel can give good
+ /// source of randomness, while the <tt>urandom</tt> does not
+ /// block the input, but it could give back bytes with worse
+ /// entropy).
+ /// \param file The source file
+ /// \param offset The offset, from the file read.
+ /// \return \c true when the seeding successes.
+#ifndef WIN32
+ bool seedFromFile(const std::string& file = "/dev/urandom", int offset = 0)
+#else
+ bool seedFromFile(const std::string& file = "", int offset = 0)
+#endif
+ {
+ std::ifstream rs(file.c_str());
+ const int size = 4;
+ Word buf[size];
+ if (offset != 0 && !rs.seekg(offset)) return false;
+ if (!rs.read(reinterpret_cast<char*>(buf), sizeof(buf))) return false;
+ seed(buf, buf + size);
+ return true;
+ }
+
+ /// \brief Seding from process id and time
+ ///
+ /// Seding from process id and time. This function uses the
+ /// current process id and the current time for initialize the
+ /// random sequence.
+ /// \return Currently always \c true.
+ bool seedFromTime() {
+#ifndef WIN32
+ timeval tv;
+ gettimeofday(&tv, 0);
+ seed(getpid() + tv.tv_sec + tv.tv_usec);
+#else
+ seed(bits::getWinRndSeed());
+#endif
+ return true;
+ }
+
+ /// @}
+
+ ///\name Uniform Distributions
+ ///
+ /// @{
+
+ /// \brief Returns a random real number from the range [0, 1)
+ ///
+ /// It returns a random real number from the range [0, 1). The
+ /// default Number type is \c double.
+ template <typename Number>
+ Number real() {
+ return _random_bits::RealConversion<Number, Word>::convert(core);
+ }
+
+ double real() {
+ return real<double>();
+ }
+
+ /// \brief Returns a random real number from the range [0, 1)
+ ///
+ /// It returns a random double from the range [0, 1).
+ double operator()() {
+ return real<double>();
+ }
+
+ /// \brief Returns a random real number from the range [0, b)
+ ///
+ /// It returns a random real number from the range [0, b).
+ double operator()(double b) {
+ return real<double>() * b;
+ }
+
+ /// \brief Returns a random real number from the range [a, b)
+ ///
+ /// It returns a random real number from the range [a, b).
+ double operator()(double a, double b) {
+ return real<double>() * (b - a) + a;
+ }
+
+ /// \brief Returns a random integer from a range
+ ///
+ /// It returns a random integer from the range {0, 1, ..., b - 1}.
+ template <typename Number>
+ Number integer(Number b) {
+ return _random_bits::Mapping<Number, Word>::map(core, b);
+ }
+
+ /// \brief Returns a random integer from a range
+ ///
+ /// It returns a random integer from the range {a, a + 1, ..., b - 1}.
+ template <typename Number>
+ Number integer(Number a, Number b) {
+ return _random_bits::Mapping<Number, Word>::map(core, b - a) + a;
+ }
+
+ /// \brief Returns a random integer from a range
+ ///
+ /// It returns a random integer from the range {0, 1, ..., b - 1}.
+ template <typename Number>
+ Number operator[](Number b) {
+ return _random_bits::Mapping<Number, Word>::map(core, b);
+ }
+
+ /// \brief Returns a random non-negative integer
+ ///
+ /// It returns a random non-negative integer uniformly from the
+ /// whole range of the current \c Number type. The default result
+ /// type of this function is <tt>unsigned int</tt>.
+ template <typename Number>
+ Number uinteger() {
+ return _random_bits::IntConversion<Number, Word>::convert(core);
+ }
+
+ unsigned int uinteger() {
+ return uinteger<unsigned int>();
+ }
+
+ /// \brief Returns a random integer
+ ///
+ /// It returns a random integer uniformly from the whole range of
+ /// the current \c Number type. The default result type of this
+ /// function is \c int.
+ template <typename Number>
+ Number integer() {
+ static const int nb = std::numeric_limits<Number>::digits +
+ (std::numeric_limits<Number>::is_signed ? 1 : 0);
+ return _random_bits::IntConversion<Number, Word, nb>::convert(core);
+ }
+
+ int integer() {
+ return integer<int>();
+ }
+
+ /// \brief Returns a random bool
+ ///
+ /// It returns a random bool. The generator holds a buffer for
+ /// random bits. Every time when it become empty the generator makes
+ /// a new random word and fill the buffer up.
+ bool boolean() {
+ return bool_producer.convert(core);
+ }
+
+ /// @}
+
+ ///\name Non-uniform Distributions
+ ///
+ ///@{
+
+ /// \brief Returns a random bool with given probability of true result.
+ ///
+ /// It returns a random bool with given probability of true result.
+ bool boolean(double p) {
+ return operator()() < p;
+ }
+
+ /// Standard normal (Gauss) distribution
+
+ /// Standard normal (Gauss) distribution.
+ /// \note The Cartesian form of the Box-Muller
+ /// transformation is used to generate a random normal distribution.
+ double gauss()
+ {
+ double V1,V2,S;
+ do {
+ V1=2*real<double>()-1;
+ V2=2*real<double>()-1;
+ S=V1*V1+V2*V2;
+ } while(S>=1);
+ return std::sqrt(-2*std::log(S)/S)*V1;
+ }
+ /// Normal (Gauss) distribution with given mean and standard deviation
+
+ /// Normal (Gauss) distribution with given mean and standard deviation.
+ /// \sa gauss()
+ double gauss(double mean,double std_dev)
+ {
+ return gauss()*std_dev+mean;
+ }
+
+ /// Lognormal distribution
+
+ /// Lognormal distribution. The parameters are the mean and the standard
+ /// deviation of <tt>exp(X)</tt>.
+ ///
+ double lognormal(double n_mean,double n_std_dev)
+ {
+ return std::exp(gauss(n_mean,n_std_dev));
+ }
+ /// Lognormal distribution
+
+ /// Lognormal distribution. The parameter is an <tt>std::pair</tt> of
+ /// the mean and the standard deviation of <tt>exp(X)</tt>.
+ ///
+ double lognormal(const std::pair<double,double> &params)
+ {
+ return std::exp(gauss(params.first,params.second));
+ }
+ /// Compute the lognormal parameters from mean and standard deviation
+
+ /// This function computes the lognormal parameters from mean and
+ /// standard deviation. The return value can direcly be passed to
+ /// lognormal().
+ std::pair<double,double> lognormalParamsFromMD(double mean,
+ double std_dev)
+ {
+ double fr=std_dev/mean;
+ fr*=fr;
+ double lg=std::log(1+fr);
+ return std::pair<double,double>(std::log(mean)-lg/2.0,std::sqrt(lg));
+ }
+ /// Lognormal distribution with given mean and standard deviation
+
+ /// Lognormal distribution with given mean and standard deviation.
+ ///
+ double lognormalMD(double mean,double std_dev)
+ {
+ return lognormal(lognormalParamsFromMD(mean,std_dev));
+ }
+
+ /// Exponential distribution with given mean
+
+ /// This function generates an exponential distribution random number
+ /// with mean <tt>1/lambda</tt>.
+ ///
+ double exponential(double lambda=1.0)
+ {
+ return -std::log(1.0-real<double>())/lambda;
+ }
+
+ /// Gamma distribution with given integer shape
+
+ /// This function generates a gamma distribution random number.
+ ///
+ ///\param k shape parameter (<tt>k>0</tt> integer)
+ double gamma(int k)
+ {
+ double s = 0;
+ for(int i=0;i<k;i++) s-=std::log(1.0-real<double>());
+ return s;
+ }
+
+ /// Gamma distribution with given shape and scale parameter
+
+ /// This function generates a gamma distribution random number.
+ ///
+ ///\param k shape parameter (<tt>k>0</tt>)
+ ///\param theta scale parameter
+ ///
+ double gamma(double k,double theta=1.0)
+ {
+ double xi,nu;
+ const double delta = k-std::floor(k);
+ const double v0=E/(E-delta);
+ do {
+ double V0=1.0-real<double>();
+ double V1=1.0-real<double>();
+ double V2=1.0-real<double>();
+ if(V2<=v0)
+ {
+ xi=std::pow(V1,1.0/delta);
+ nu=V0*std::pow(xi,delta-1.0);
+ }
+ else
+ {
+ xi=1.0-std::log(V1);
+ nu=V0*std::exp(-xi);
+ }
+ } while(nu>std::pow(xi,delta-1.0)*std::exp(-xi));
+ return theta*(xi+gamma(int(std::floor(k))));
+ }
+
+ /// Weibull distribution
+
+ /// This function generates a Weibull distribution random number.
+ ///
+ ///\param k shape parameter (<tt>k>0</tt>)
+ ///\param lambda scale parameter (<tt>lambda>0</tt>)
+ ///
+ double weibull(double k,double lambda)
+ {
+ return lambda*pow(-std::log(1.0-real<double>()),1.0/k);
+ }
+
+ /// Pareto distribution
+
+ /// This function generates a Pareto distribution random number.
+ ///
+ ///\param k shape parameter (<tt>k>0</tt>)
+ ///\param x_min location parameter (<tt>x_min>0</tt>)
+ ///
+ double pareto(double k,double x_min)
+ {
+ return exponential(gamma(k,1.0/x_min))+x_min;
+ }
+
+ /// Poisson distribution
+
+ /// This function generates a Poisson distribution random number with
+ /// parameter \c lambda.
+ ///
+ /// The probability mass function of this distribusion is
+ /// \f[ \frac{e^{-\lambda}\lambda^k}{k!} \f]
+ /// \note The algorithm is taken from the book of Donald E. Knuth titled
+ /// ''Seminumerical Algorithms'' (1969). Its running time is linear in the
+ /// return value.
+
+ int poisson(double lambda)
+ {
+ const double l = std::exp(-lambda);
+ int k=0;
+ double p = 1.0;
+ do {
+ k++;
+ p*=real<double>();
+ } while (p>=l);
+ return k-1;
+ }
+
+ ///@}
+
+ ///\name Two Dimensional Distributions
+ ///
+ ///@{
+
+ /// Uniform distribution on the full unit circle
+
+ /// Uniform distribution on the full unit circle.
+ ///
+ dim2::Point<double> disc()
+ {
+ double V1,V2;
+ do {
+ V1=2*real<double>()-1;
+ V2=2*real<double>()-1;
+
+ } while(V1*V1+V2*V2>=1);
+ return dim2::Point<double>(V1,V2);
+ }
+ /// A kind of two dimensional normal (Gauss) distribution
+
+ /// This function provides a turning symmetric two-dimensional distribution.
+ /// Both coordinates are of standard normal distribution, but they are not
+ /// independent.
+ ///
+ /// \note The coordinates are the two random variables provided by
+ /// the Box-Muller method.
+ dim2::Point<double> gauss2()
+ {
+ double V1,V2,S;
+ do {
+ V1=2*real<double>()-1;
+ V2=2*real<double>()-1;
+ S=V1*V1+V2*V2;
+ } while(S>=1);
+ double W=std::sqrt(-2*std::log(S)/S);
+ return dim2::Point<double>(W*V1,W*V2);
+ }
+ /// A kind of two dimensional exponential distribution
+
+ /// This function provides a turning symmetric two-dimensional distribution.
+ /// The x-coordinate is of conditionally exponential distribution
+ /// with the condition that x is positive and y=0. If x is negative and
+ /// y=0 then, -x is of exponential distribution. The same is true for the
+ /// y-coordinate.
+ dim2::Point<double> exponential2()
+ {
+ double V1,V2,S;
+ do {
+ V1=2*real<double>()-1;
+ V2=2*real<double>()-1;
+ S=V1*V1+V2*V2;
+ } while(S>=1);
+ double W=-std::log(S)/S;
+ return dim2::Point<double>(W*V1,W*V2);
+ }
+
+ ///@}
+ };
+
+
+ extern Random rnd;
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/smart_graph.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/smart_graph.h
new file mode 100644
index 00000000000..bdbe369a4df
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/smart_graph.h
@@ -0,0 +1,1344 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_SMART_GRAPH_H
+#define LEMON_SMART_GRAPH_H
+
+///\ingroup graphs
+///\file
+///\brief SmartDigraph and SmartGraph classes.
+
+#include <vector>
+
+#include <lemon/core.h>
+#include <lemon/error.h>
+#include <lemon/bits/graph_extender.h>
+
+namespace lemon {
+
+ class SmartDigraph;
+
+ class SmartDigraphBase {
+ protected:
+
+ struct NodeT
+ {
+ int first_in, first_out;
+ NodeT() {}
+ };
+ struct ArcT
+ {
+ int target, source, next_in, next_out;
+ ArcT() {}
+ };
+
+ std::vector<NodeT> nodes;
+ std::vector<ArcT> arcs;
+
+ public:
+
+ typedef SmartDigraphBase Digraph;
+
+ class Node;
+ class Arc;
+
+ public:
+
+ SmartDigraphBase() : nodes(), arcs() { }
+ SmartDigraphBase(const SmartDigraphBase &_g)
+ : nodes(_g.nodes), arcs(_g.arcs) { }
+
+ typedef True NodeNumTag;
+ typedef True ArcNumTag;
+
+ int nodeNum() const { return nodes.size(); }
+ int arcNum() const { return arcs.size(); }
+
+ int maxNodeId() const { return nodes.size()-1; }
+ int maxArcId() const { return arcs.size()-1; }
+
+ Node addNode() {
+ int n = nodes.size();
+ nodes.push_back(NodeT());
+ nodes[n].first_in = -1;
+ nodes[n].first_out = -1;
+ return Node(n);
+ }
+
+ Arc addArc(Node u, Node v) {
+ int n = arcs.size();
+ arcs.push_back(ArcT());
+ arcs[n].source = u._id;
+ arcs[n].target = v._id;
+ arcs[n].next_out = nodes[u._id].first_out;
+ arcs[n].next_in = nodes[v._id].first_in;
+ nodes[u._id].first_out = nodes[v._id].first_in = n;
+
+ return Arc(n);
+ }
+
+ void clear() {
+ arcs.clear();
+ nodes.clear();
+ }
+
+ Node source(Arc a) const { return Node(arcs[a._id].source); }
+ Node target(Arc a) const { return Node(arcs[a._id].target); }
+
+ static int id(Node v) { return v._id; }
+ static int id(Arc a) { return a._id; }
+
+ static Node nodeFromId(int id) { return Node(id);}
+ static Arc arcFromId(int id) { return Arc(id);}
+
+ bool valid(Node n) const {
+ return n._id >= 0 && n._id < static_cast<int>(nodes.size());
+ }
+ bool valid(Arc a) const {
+ return a._id >= 0 && a._id < static_cast<int>(arcs.size());
+ }
+
+ class Node {
+ friend class SmartDigraphBase;
+ friend class SmartDigraph;
+
+ protected:
+ int _id;
+ explicit Node(int id) : _id(id) {}
+ public:
+ Node() {}
+ Node (Invalid) : _id(-1) {}
+ bool operator==(const Node i) const {return _id == i._id;}
+ bool operator!=(const Node i) const {return _id != i._id;}
+ bool operator<(const Node i) const {return _id < i._id;}
+ };
+
+
+ class Arc {
+ friend class SmartDigraphBase;
+ friend class SmartDigraph;
+
+ protected:
+ int _id;
+ explicit Arc(int id) : _id(id) {}
+ public:
+ Arc() { }
+ Arc (Invalid) : _id(-1) {}
+ bool operator==(const Arc i) const {return _id == i._id;}
+ bool operator!=(const Arc i) const {return _id != i._id;}
+ bool operator<(const Arc i) const {return _id < i._id;}
+ };
+
+ void first(Node& node) const {
+ node._id = nodes.size() - 1;
+ }
+
+ static void next(Node& node) {
+ --node._id;
+ }
+
+ void first(Arc& arc) const {
+ arc._id = arcs.size() - 1;
+ }
+
+ static void next(Arc& arc) {
+ --arc._id;
+ }
+
+ void firstOut(Arc& arc, const Node& node) const {
+ arc._id = nodes[node._id].first_out;
+ }
+
+ void nextOut(Arc& arc) const {
+ arc._id = arcs[arc._id].next_out;
+ }
+
+ void firstIn(Arc& arc, const Node& node) const {
+ arc._id = nodes[node._id].first_in;
+ }
+
+ void nextIn(Arc& arc) const {
+ arc._id = arcs[arc._id].next_in;
+ }
+
+ };
+
+ typedef DigraphExtender<SmartDigraphBase> ExtendedSmartDigraphBase;
+
+ ///\ingroup graphs
+ ///
+ ///\brief A smart directed graph class.
+ ///
+ ///\ref SmartDigraph is a simple and fast digraph implementation.
+ ///It is also quite memory efficient but at the price
+ ///that it does not support node and arc deletion
+ ///(except for the Snapshot feature).
+ ///
+ ///This type fully conforms to the \ref concepts::Digraph "Digraph concept"
+ ///and it also provides some additional functionalities.
+ ///Most of its member functions and nested classes are documented
+ ///only in the concept class.
+ ///
+ ///This class provides constant time counting for nodes and arcs.
+ ///
+ ///\sa concepts::Digraph
+ ///\sa SmartGraph
+ class SmartDigraph : public ExtendedSmartDigraphBase {
+ typedef ExtendedSmartDigraphBase Parent;
+
+ private:
+ /// Digraphs are \e not copy constructible. Use DigraphCopy instead.
+ SmartDigraph(const SmartDigraph &) : ExtendedSmartDigraphBase() {};
+ /// \brief Assignment of a digraph to another one is \e not allowed.
+ /// Use DigraphCopy instead.
+ void operator=(const SmartDigraph &) {}
+
+ public:
+
+ /// Constructor
+
+ /// Constructor.
+ ///
+ SmartDigraph() {};
+
+ ///Add a new node to the digraph.
+
+ ///This function adds a new node to the digraph.
+ ///\return The new node.
+ Node addNode() { return Parent::addNode(); }
+
+ ///Add a new arc to the digraph.
+
+ ///This function adds a new arc to the digraph with source node \c s
+ ///and target node \c t.
+ ///\return The new arc.
+ Arc addArc(Node s, Node t) {
+ return Parent::addArc(s, t);
+ }
+
+ /// \brief Node validity check
+ ///
+ /// This function gives back \c true if the given node is valid,
+ /// i.e. it is a real node of the digraph.
+ ///
+ /// \warning A removed node (using Snapshot) could become valid again
+ /// if new nodes are added to the digraph.
+ bool valid(Node n) const { return Parent::valid(n); }
+
+ /// \brief Arc validity check
+ ///
+ /// This function gives back \c true if the given arc is valid,
+ /// i.e. it is a real arc of the digraph.
+ ///
+ /// \warning A removed arc (using Snapshot) could become valid again
+ /// if new arcs are added to the graph.
+ bool valid(Arc a) const { return Parent::valid(a); }
+
+ ///Split a node.
+
+ ///This function splits the given node. First, a new node is added
+ ///to the digraph, then the source of each outgoing arc of node \c n
+ ///is moved to this new node.
+ ///If the second parameter \c connect is \c true (this is the default
+ ///value), then a new arc from node \c n to the newly created node
+ ///is also added.
+ ///\return The newly created node.
+ ///
+ ///\note All iterators remain valid.
+ ///
+ ///\warning This functionality cannot be used together with the Snapshot
+ ///feature.
+ Node split(Node n, bool connect = true)
+ {
+ Node b = addNode();
+ nodes[b._id].first_out=nodes[n._id].first_out;
+ nodes[n._id].first_out=-1;
+ for(int i=nodes[b._id].first_out; i!=-1; i=arcs[i].next_out) {
+ arcs[i].source=b._id;
+ }
+ if(connect) addArc(n,b);
+ return b;
+ }
+
+ ///Clear the digraph.
+
+ ///This function erases all nodes and arcs from the digraph.
+ ///
+ void clear() {
+ Parent::clear();
+ }
+
+ /// Reserve memory for nodes.
+
+ /// Using this function, it is possible to avoid superfluous memory
+ /// allocation: if you know that the digraph you want to build will
+ /// be large (e.g. it will contain millions of nodes and/or arcs),
+ /// then it is worth reserving space for this amount before starting
+ /// to build the digraph.
+ /// \sa reserveArc()
+ void reserveNode(int n) { nodes.reserve(n); };
+
+ /// Reserve memory for arcs.
+
+ /// Using this function, it is possible to avoid superfluous memory
+ /// allocation: if you know that the digraph you want to build will
+ /// be large (e.g. it will contain millions of nodes and/or arcs),
+ /// then it is worth reserving space for this amount before starting
+ /// to build the digraph.
+ /// \sa reserveNode()
+ void reserveArc(int m) { arcs.reserve(m); };
+
+ public:
+
+ class Snapshot;
+
+ protected:
+
+ void restoreSnapshot(const Snapshot &s)
+ {
+ while(s.arc_num<arcs.size()) {
+ Arc arc = arcFromId(arcs.size()-1);
+ Parent::notifier(Arc()).erase(arc);
+ nodes[arcs.back().source].first_out=arcs.back().next_out;
+ nodes[arcs.back().target].first_in=arcs.back().next_in;
+ arcs.pop_back();
+ }
+ while(s.node_num<nodes.size()) {
+ Node node = nodeFromId(nodes.size()-1);
+ Parent::notifier(Node()).erase(node);
+ nodes.pop_back();
+ }
+ }
+
+ public:
+
+ ///Class to make a snapshot of the digraph and to restore it later.
+
+ ///Class to make a snapshot of the digraph and to restore it later.
+ ///
+ ///The newly added nodes and arcs can be removed using the
+ ///restore() function. This is the only way for deleting nodes and/or
+ ///arcs from a SmartDigraph structure.
+ ///
+ ///\note After a state is restored, you cannot restore a later state,
+ ///i.e. you cannot add the removed nodes and arcs again using
+ ///another Snapshot instance.
+ ///
+ ///\warning Node splitting cannot be restored.
+ ///\warning The validity of the snapshot is not stored due to
+ ///performance reasons. If you do not use the snapshot correctly,
+ ///it can cause broken program, invalid or not restored state of
+ ///the digraph or no change.
+ class Snapshot
+ {
+ SmartDigraph *_graph;
+ protected:
+ friend class SmartDigraph;
+ unsigned int node_num;
+ unsigned int arc_num;
+ public:
+ ///Default constructor.
+
+ ///Default constructor.
+ ///You have to call save() to actually make a snapshot.
+ Snapshot() : _graph(0) {}
+ ///Constructor that immediately makes a snapshot
+
+ ///This constructor immediately makes a snapshot of the given digraph.
+ ///
+ Snapshot(SmartDigraph &gr) : _graph(&gr) {
+ node_num=_graph->nodes.size();
+ arc_num=_graph->arcs.size();
+ }
+
+ ///Make a snapshot.
+
+ ///This function makes a snapshot of the given digraph.
+ ///It can be called more than once. In case of a repeated
+ ///call, the previous snapshot gets lost.
+ void save(SmartDigraph &gr) {
+ _graph=&gr;
+ node_num=_graph->nodes.size();
+ arc_num=_graph->arcs.size();
+ }
+
+ ///Undo the changes until a snapshot.
+
+ ///This function undos the changes until the last snapshot
+ ///created by save() or Snapshot(SmartDigraph&).
+ void restore()
+ {
+ _graph->restoreSnapshot(*this);
+ }
+ };
+ };
+
+
+ class SmartGraphBase {
+
+ protected:
+
+ struct NodeT {
+ int first_out;
+ };
+
+ struct ArcT {
+ int target;
+ int next_out;
+ };
+
+ std::vector<NodeT> nodes;
+ std::vector<ArcT> arcs;
+
+ public:
+
+ typedef SmartGraphBase Graph;
+
+ class Node;
+ class Arc;
+ class Edge;
+
+ class Node {
+ friend class SmartGraphBase;
+ protected:
+
+ int _id;
+ explicit Node(int id) { _id = id;}
+
+ public:
+ Node() {}
+ Node (Invalid) { _id = -1; }
+ bool operator==(const Node& node) const {return _id == node._id;}
+ bool operator!=(const Node& node) const {return _id != node._id;}
+ bool operator<(const Node& node) const {return _id < node._id;}
+ };
+
+ class Edge {
+ friend class SmartGraphBase;
+ protected:
+
+ int _id;
+ explicit Edge(int id) { _id = id;}
+
+ public:
+ Edge() {}
+ Edge (Invalid) { _id = -1; }
+ bool operator==(const Edge& arc) const {return _id == arc._id;}
+ bool operator!=(const Edge& arc) const {return _id != arc._id;}
+ bool operator<(const Edge& arc) const {return _id < arc._id;}
+ };
+
+ class Arc {
+ friend class SmartGraphBase;
+ protected:
+
+ int _id;
+ explicit Arc(int id) { _id = id;}
+
+ public:
+ operator Edge() const {
+ return _id != -1 ? edgeFromId(_id / 2) : INVALID;
+ }
+
+ Arc() {}
+ Arc (Invalid) { _id = -1; }
+ bool operator==(const Arc& arc) const {return _id == arc._id;}
+ bool operator!=(const Arc& arc) const {return _id != arc._id;}
+ bool operator<(const Arc& arc) const {return _id < arc._id;}
+ };
+
+
+
+ SmartGraphBase()
+ : nodes(), arcs() {}
+
+ typedef True NodeNumTag;
+ typedef True EdgeNumTag;
+ typedef True ArcNumTag;
+
+ int nodeNum() const { return nodes.size(); }
+ int edgeNum() const { return arcs.size() / 2; }
+ int arcNum() const { return arcs.size(); }
+
+ int maxNodeId() const { return nodes.size()-1; }
+ int maxEdgeId() const { return arcs.size() / 2 - 1; }
+ int maxArcId() const { return arcs.size()-1; }
+
+ Node source(Arc e) const { return Node(arcs[e._id ^ 1].target); }
+ Node target(Arc e) const { return Node(arcs[e._id].target); }
+
+ Node u(Edge e) const { return Node(arcs[2 * e._id].target); }
+ Node v(Edge e) const { return Node(arcs[2 * e._id + 1].target); }
+
+ static bool direction(Arc e) {
+ return (e._id & 1) == 1;
+ }
+
+ static Arc direct(Edge e, bool d) {
+ return Arc(e._id * 2 + (d ? 1 : 0));
+ }
+
+ void first(Node& node) const {
+ node._id = nodes.size() - 1;
+ }
+
+ static void next(Node& node) {
+ --node._id;
+ }
+
+ void first(Arc& arc) const {
+ arc._id = arcs.size() - 1;
+ }
+
+ static void next(Arc& arc) {
+ --arc._id;
+ }
+
+ void first(Edge& arc) const {
+ arc._id = arcs.size() / 2 - 1;
+ }
+
+ static void next(Edge& arc) {
+ --arc._id;
+ }
+
+ void firstOut(Arc &arc, const Node& v) const {
+ arc._id = nodes[v._id].first_out;
+ }
+ void nextOut(Arc &arc) const {
+ arc._id = arcs[arc._id].next_out;
+ }
+
+ void firstIn(Arc &arc, const Node& v) const {
+ arc._id = ((nodes[v._id].first_out) ^ 1);
+ if (arc._id == -2) arc._id = -1;
+ }
+ void nextIn(Arc &arc) const {
+ arc._id = ((arcs[arc._id ^ 1].next_out) ^ 1);
+ if (arc._id == -2) arc._id = -1;
+ }
+
+ void firstInc(Edge &arc, bool& d, const Node& v) const {
+ int de = nodes[v._id].first_out;
+ if (de != -1) {
+ arc._id = de / 2;
+ d = ((de & 1) == 1);
+ } else {
+ arc._id = -1;
+ d = true;
+ }
+ }
+ void nextInc(Edge &arc, bool& d) const {
+ int de = (arcs[(arc._id * 2) | (d ? 1 : 0)].next_out);
+ if (de != -1) {
+ arc._id = de / 2;
+ d = ((de & 1) == 1);
+ } else {
+ arc._id = -1;
+ d = true;
+ }
+ }
+
+ static int id(Node v) { return v._id; }
+ static int id(Arc e) { return e._id; }
+ static int id(Edge e) { return e._id; }
+
+ static Node nodeFromId(int id) { return Node(id);}
+ static Arc arcFromId(int id) { return Arc(id);}
+ static Edge edgeFromId(int id) { return Edge(id);}
+
+ bool valid(Node n) const {
+ return n._id >= 0 && n._id < static_cast<int>(nodes.size());
+ }
+ bool valid(Arc a) const {
+ return a._id >= 0 && a._id < static_cast<int>(arcs.size());
+ }
+ bool valid(Edge e) const {
+ return e._id >= 0 && 2 * e._id < static_cast<int>(arcs.size());
+ }
+
+ Node addNode() {
+ int n = nodes.size();
+ nodes.push_back(NodeT());
+ nodes[n].first_out = -1;
+
+ return Node(n);
+ }
+
+ Edge addEdge(Node u, Node v) {
+ int n = arcs.size();
+ arcs.push_back(ArcT());
+ arcs.push_back(ArcT());
+
+ arcs[n].target = u._id;
+ arcs[n | 1].target = v._id;
+
+ arcs[n].next_out = nodes[v._id].first_out;
+ nodes[v._id].first_out = n;
+
+ arcs[n | 1].next_out = nodes[u._id].first_out;
+ nodes[u._id].first_out = (n | 1);
+
+ return Edge(n / 2);
+ }
+
+ void clear() {
+ arcs.clear();
+ nodes.clear();
+ }
+
+ };
+
+ typedef GraphExtender<SmartGraphBase> ExtendedSmartGraphBase;
+
+ /// \ingroup graphs
+ ///
+ /// \brief A smart undirected graph class.
+ ///
+ /// \ref SmartGraph is a simple and fast graph implementation.
+ /// It is also quite memory efficient but at the price
+ /// that it does not support node and edge deletion
+ /// (except for the Snapshot feature).
+ ///
+ /// This type fully conforms to the \ref concepts::Graph "Graph concept"
+ /// and it also provides some additional functionalities.
+ /// Most of its member functions and nested classes are documented
+ /// only in the concept class.
+ ///
+ /// This class provides constant time counting for nodes, edges and arcs.
+ ///
+ /// \sa concepts::Graph
+ /// \sa SmartDigraph
+ class SmartGraph : public ExtendedSmartGraphBase {
+ typedef ExtendedSmartGraphBase Parent;
+
+ private:
+ /// Graphs are \e not copy constructible. Use GraphCopy instead.
+ SmartGraph(const SmartGraph &) : ExtendedSmartGraphBase() {};
+ /// \brief Assignment of a graph to another one is \e not allowed.
+ /// Use GraphCopy instead.
+ void operator=(const SmartGraph &) {}
+
+ public:
+
+ /// Constructor
+
+ /// Constructor.
+ ///
+ SmartGraph() {}
+
+ /// \brief Add a new node to the graph.
+ ///
+ /// This function adds a new node to the graph.
+ /// \return The new node.
+ Node addNode() { return Parent::addNode(); }
+
+ /// \brief Add a new edge to the graph.
+ ///
+ /// This function adds a new edge to the graph between nodes
+ /// \c u and \c v with inherent orientation from node \c u to
+ /// node \c v.
+ /// \return The new edge.
+ Edge addEdge(Node u, Node v) {
+ return Parent::addEdge(u, v);
+ }
+
+ /// \brief Node validity check
+ ///
+ /// This function gives back \c true if the given node is valid,
+ /// i.e. it is a real node of the graph.
+ ///
+ /// \warning A removed node (using Snapshot) could become valid again
+ /// if new nodes are added to the graph.
+ bool valid(Node n) const { return Parent::valid(n); }
+
+ /// \brief Edge validity check
+ ///
+ /// This function gives back \c true if the given edge is valid,
+ /// i.e. it is a real edge of the graph.
+ ///
+ /// \warning A removed edge (using Snapshot) could become valid again
+ /// if new edges are added to the graph.
+ bool valid(Edge e) const { return Parent::valid(e); }
+
+ /// \brief Arc validity check
+ ///
+ /// This function gives back \c true if the given arc is valid,
+ /// i.e. it is a real arc of the graph.
+ ///
+ /// \warning A removed arc (using Snapshot) could become valid again
+ /// if new edges are added to the graph.
+ bool valid(Arc a) const { return Parent::valid(a); }
+
+ ///Clear the graph.
+
+ ///This function erases all nodes and arcs from the graph.
+ ///
+ void clear() {
+ Parent::clear();
+ }
+
+ /// Reserve memory for nodes.
+
+ /// Using this function, it is possible to avoid superfluous memory
+ /// allocation: if you know that the graph you want to build will
+ /// be large (e.g. it will contain millions of nodes and/or edges),
+ /// then it is worth reserving space for this amount before starting
+ /// to build the graph.
+ /// \sa reserveEdge()
+ void reserveNode(int n) { nodes.reserve(n); };
+
+ /// Reserve memory for edges.
+
+ /// Using this function, it is possible to avoid superfluous memory
+ /// allocation: if you know that the graph you want to build will
+ /// be large (e.g. it will contain millions of nodes and/or edges),
+ /// then it is worth reserving space for this amount before starting
+ /// to build the graph.
+ /// \sa reserveNode()
+ void reserveEdge(int m) { arcs.reserve(2 * m); };
+
+ public:
+
+ class Snapshot;
+
+ protected:
+
+ void saveSnapshot(Snapshot &s)
+ {
+ s._graph = this;
+ s.node_num = nodes.size();
+ s.arc_num = arcs.size();
+ }
+
+ void restoreSnapshot(const Snapshot &s)
+ {
+ while(s.arc_num<arcs.size()) {
+ int n=arcs.size()-1;
+ Edge arc=edgeFromId(n/2);
+ Parent::notifier(Edge()).erase(arc);
+ std::vector<Arc> dir;
+ dir.push_back(arcFromId(n));
+ dir.push_back(arcFromId(n-1));
+ Parent::notifier(Arc()).erase(dir);
+ nodes[arcs[n-1].target].first_out=arcs[n].next_out;
+ nodes[arcs[n].target].first_out=arcs[n-1].next_out;
+ arcs.pop_back();
+ arcs.pop_back();
+ }
+ while(s.node_num<nodes.size()) {
+ int n=nodes.size()-1;
+ Node node = nodeFromId(n);
+ Parent::notifier(Node()).erase(node);
+ nodes.pop_back();
+ }
+ }
+
+ public:
+
+ ///Class to make a snapshot of the graph and to restore it later.
+
+ ///Class to make a snapshot of the graph and to restore it later.
+ ///
+ ///The newly added nodes and edges can be removed using the
+ ///restore() function. This is the only way for deleting nodes and/or
+ ///edges from a SmartGraph structure.
+ ///
+ ///\note After a state is restored, you cannot restore a later state,
+ ///i.e. you cannot add the removed nodes and edges again using
+ ///another Snapshot instance.
+ ///
+ ///\warning The validity of the snapshot is not stored due to
+ ///performance reasons. If you do not use the snapshot correctly,
+ ///it can cause broken program, invalid or not restored state of
+ ///the graph or no change.
+ class Snapshot
+ {
+ SmartGraph *_graph;
+ protected:
+ friend class SmartGraph;
+ unsigned int node_num;
+ unsigned int arc_num;
+ public:
+ ///Default constructor.
+
+ ///Default constructor.
+ ///You have to call save() to actually make a snapshot.
+ Snapshot() : _graph(0) {}
+ ///Constructor that immediately makes a snapshot
+
+ /// This constructor immediately makes a snapshot of the given graph.
+ ///
+ Snapshot(SmartGraph &gr) {
+ gr.saveSnapshot(*this);
+ }
+
+ ///Make a snapshot.
+
+ ///This function makes a snapshot of the given graph.
+ ///It can be called more than once. In case of a repeated
+ ///call, the previous snapshot gets lost.
+ void save(SmartGraph &gr)
+ {
+ gr.saveSnapshot(*this);
+ }
+
+ ///Undo the changes until the last snapshot.
+
+ ///This function undos the changes until the last snapshot
+ ///created by save() or Snapshot(SmartGraph&).
+ void restore()
+ {
+ _graph->restoreSnapshot(*this);
+ }
+ };
+ };
+
+ class SmartBpGraphBase {
+
+ protected:
+
+ struct NodeT {
+ int first_out;
+ int partition_next;
+ int partition_index;
+ bool red;
+ };
+
+ struct ArcT {
+ int target;
+ int next_out;
+ };
+
+ std::vector<NodeT> nodes;
+ std::vector<ArcT> arcs;
+
+ int first_red, first_blue;
+ int max_red, max_blue;
+
+ public:
+
+ typedef SmartBpGraphBase Graph;
+
+ class Node;
+ class Arc;
+ class Edge;
+
+ class Node {
+ friend class SmartBpGraphBase;
+ protected:
+
+ int _id;
+ explicit Node(int id) { _id = id;}
+
+ public:
+ Node() {}
+ Node (Invalid) { _id = -1; }
+ bool operator==(const Node& node) const {return _id == node._id;}
+ bool operator!=(const Node& node) const {return _id != node._id;}
+ bool operator<(const Node& node) const {return _id < node._id;}
+ };
+
+ class RedNode : public Node {
+ friend class SmartBpGraphBase;
+ protected:
+
+ explicit RedNode(int pid) : Node(pid) {}
+
+ public:
+ RedNode() {}
+ RedNode(const RedNode& node) : Node(node) {}
+ RedNode(Invalid) : Node(INVALID){}
+ };
+
+ class BlueNode : public Node {
+ friend class SmartBpGraphBase;
+ protected:
+
+ explicit BlueNode(int pid) : Node(pid) {}
+
+ public:
+ BlueNode() {}
+ BlueNode(const BlueNode& node) : Node(node) {}
+ BlueNode(Invalid) : Node(INVALID){}
+ };
+
+ class Edge {
+ friend class SmartBpGraphBase;
+ protected:
+
+ int _id;
+ explicit Edge(int id) { _id = id;}
+
+ public:
+ Edge() {}
+ Edge (Invalid) { _id = -1; }
+ bool operator==(const Edge& arc) const {return _id == arc._id;}
+ bool operator!=(const Edge& arc) const {return _id != arc._id;}
+ bool operator<(const Edge& arc) const {return _id < arc._id;}
+ };
+
+ class Arc {
+ friend class SmartBpGraphBase;
+ protected:
+
+ int _id;
+ explicit Arc(int id) { _id = id;}
+
+ public:
+ operator Edge() const {
+ return _id != -1 ? edgeFromId(_id / 2) : INVALID;
+ }
+
+ Arc() {}
+ Arc (Invalid) { _id = -1; }
+ bool operator==(const Arc& arc) const {return _id == arc._id;}
+ bool operator!=(const Arc& arc) const {return _id != arc._id;}
+ bool operator<(const Arc& arc) const {return _id < arc._id;}
+ };
+
+
+
+ SmartBpGraphBase()
+ : nodes(), arcs(), first_red(-1), first_blue(-1),
+ max_red(-1), max_blue(-1) {}
+
+ typedef True NodeNumTag;
+ typedef True EdgeNumTag;
+ typedef True ArcNumTag;
+
+ int nodeNum() const { return nodes.size(); }
+ int redNum() const { return max_red + 1; }
+ int blueNum() const { return max_blue + 1; }
+ int edgeNum() const { return arcs.size() / 2; }
+ int arcNum() const { return arcs.size(); }
+
+ int maxNodeId() const { return nodes.size()-1; }
+ int maxRedId() const { return max_red; }
+ int maxBlueId() const { return max_blue; }
+ int maxEdgeId() const { return arcs.size() / 2 - 1; }
+ int maxArcId() const { return arcs.size()-1; }
+
+ bool red(Node n) const { return nodes[n._id].red; }
+ bool blue(Node n) const { return !nodes[n._id].red; }
+
+ static RedNode asRedNodeUnsafe(Node n) { return RedNode(n._id); }
+ static BlueNode asBlueNodeUnsafe(Node n) { return BlueNode(n._id); }
+
+ Node source(Arc a) const { return Node(arcs[a._id ^ 1].target); }
+ Node target(Arc a) const { return Node(arcs[a._id].target); }
+
+ RedNode redNode(Edge e) const {
+ return RedNode(arcs[2 * e._id].target);
+ }
+ BlueNode blueNode(Edge e) const {
+ return BlueNode(arcs[2 * e._id + 1].target);
+ }
+
+ static bool direction(Arc a) {
+ return (a._id & 1) == 1;
+ }
+
+ static Arc direct(Edge e, bool d) {
+ return Arc(e._id * 2 + (d ? 1 : 0));
+ }
+
+ void first(Node& node) const {
+ node._id = nodes.size() - 1;
+ }
+
+ static void next(Node& node) {
+ --node._id;
+ }
+
+ void first(RedNode& node) const {
+ node._id = first_red;
+ }
+
+ void next(RedNode& node) const {
+ node._id = nodes[node._id].partition_next;
+ }
+
+ void first(BlueNode& node) const {
+ node._id = first_blue;
+ }
+
+ void next(BlueNode& node) const {
+ node._id = nodes[node._id].partition_next;
+ }
+
+ void first(Arc& arc) const {
+ arc._id = arcs.size() - 1;
+ }
+
+ static void next(Arc& arc) {
+ --arc._id;
+ }
+
+ void first(Edge& arc) const {
+ arc._id = arcs.size() / 2 - 1;
+ }
+
+ static void next(Edge& arc) {
+ --arc._id;
+ }
+
+ void firstOut(Arc &arc, const Node& v) const {
+ arc._id = nodes[v._id].first_out;
+ }
+ void nextOut(Arc &arc) const {
+ arc._id = arcs[arc._id].next_out;
+ }
+
+ void firstIn(Arc &arc, const Node& v) const {
+ arc._id = ((nodes[v._id].first_out) ^ 1);
+ if (arc._id == -2) arc._id = -1;
+ }
+ void nextIn(Arc &arc) const {
+ arc._id = ((arcs[arc._id ^ 1].next_out) ^ 1);
+ if (arc._id == -2) arc._id = -1;
+ }
+
+ void firstInc(Edge &arc, bool& d, const Node& v) const {
+ int de = nodes[v._id].first_out;
+ if (de != -1) {
+ arc._id = de / 2;
+ d = ((de & 1) == 1);
+ } else {
+ arc._id = -1;
+ d = true;
+ }
+ }
+ void nextInc(Edge &arc, bool& d) const {
+ int de = (arcs[(arc._id * 2) | (d ? 1 : 0)].next_out);
+ if (de != -1) {
+ arc._id = de / 2;
+ d = ((de & 1) == 1);
+ } else {
+ arc._id = -1;
+ d = true;
+ }
+ }
+
+ static int id(Node v) { return v._id; }
+ int id(RedNode v) const { return nodes[v._id].partition_index; }
+ int id(BlueNode v) const { return nodes[v._id].partition_index; }
+ static int id(Arc e) { return e._id; }
+ static int id(Edge e) { return e._id; }
+
+ static Node nodeFromId(int id) { return Node(id);}
+ static Arc arcFromId(int id) { return Arc(id);}
+ static Edge edgeFromId(int id) { return Edge(id);}
+
+ bool valid(Node n) const {
+ return n._id >= 0 && n._id < static_cast<int>(nodes.size());
+ }
+ bool valid(Arc a) const {
+ return a._id >= 0 && a._id < static_cast<int>(arcs.size());
+ }
+ bool valid(Edge e) const {
+ return e._id >= 0 && 2 * e._id < static_cast<int>(arcs.size());
+ }
+
+ RedNode addRedNode() {
+ int n = nodes.size();
+ nodes.push_back(NodeT());
+ nodes[n].first_out = -1;
+ nodes[n].red = true;
+ nodes[n].partition_index = ++max_red;
+ nodes[n].partition_next = first_red;
+ first_red = n;
+
+ return RedNode(n);
+ }
+
+ BlueNode addBlueNode() {
+ int n = nodes.size();
+ nodes.push_back(NodeT());
+ nodes[n].first_out = -1;
+ nodes[n].red = false;
+ nodes[n].partition_index = ++max_blue;
+ nodes[n].partition_next = first_blue;
+ first_blue = n;
+
+ return BlueNode(n);
+ }
+
+ Edge addEdge(RedNode u, BlueNode v) {
+ int n = arcs.size();
+ arcs.push_back(ArcT());
+ arcs.push_back(ArcT());
+
+ arcs[n].target = u._id;
+ arcs[n | 1].target = v._id;
+
+ arcs[n].next_out = nodes[v._id].first_out;
+ nodes[v._id].first_out = n;
+
+ arcs[n | 1].next_out = nodes[u._id].first_out;
+ nodes[u._id].first_out = (n | 1);
+
+ return Edge(n / 2);
+ }
+
+ void clear() {
+ arcs.clear();
+ nodes.clear();
+ first_red = -1;
+ first_blue = -1;
+ max_blue = -1;
+ max_red = -1;
+ }
+
+ };
+
+ typedef BpGraphExtender<SmartBpGraphBase> ExtendedSmartBpGraphBase;
+
+ /// \ingroup graphs
+ ///
+ /// \brief A smart undirected bipartite graph class.
+ ///
+ /// \ref SmartBpGraph is a simple and fast bipartite graph implementation.
+ /// It is also quite memory efficient but at the price
+ /// that it does not support node and edge deletion
+ /// (except for the Snapshot feature).
+ ///
+ /// This type fully conforms to the \ref concepts::BpGraph "BpGraph concept"
+ /// and it also provides some additional functionalities.
+ /// Most of its member functions and nested classes are documented
+ /// only in the concept class.
+ ///
+ /// This class provides constant time counting for nodes, edges and arcs.
+ ///
+ /// \sa concepts::BpGraph
+ /// \sa SmartGraph
+ class SmartBpGraph : public ExtendedSmartBpGraphBase {
+ typedef ExtendedSmartBpGraphBase Parent;
+
+ private:
+ /// Graphs are \e not copy constructible. Use GraphCopy instead.
+ SmartBpGraph(const SmartBpGraph &) : ExtendedSmartBpGraphBase() {};
+ /// \brief Assignment of a graph to another one is \e not allowed.
+ /// Use GraphCopy instead.
+ void operator=(const SmartBpGraph &) {}
+
+ public:
+
+ /// Constructor
+
+ /// Constructor.
+ ///
+ SmartBpGraph() {}
+
+ /// \brief Add a new red node to the graph.
+ ///
+ /// This function adds a red new node to the graph.
+ /// \return The new node.
+ RedNode addRedNode() { return Parent::addRedNode(); }
+
+ /// \brief Add a new blue node to the graph.
+ ///
+ /// This function adds a blue new node to the graph.
+ /// \return The new node.
+ BlueNode addBlueNode() { return Parent::addBlueNode(); }
+
+ /// \brief Add a new edge to the graph.
+ ///
+ /// This function adds a new edge to the graph between nodes
+ /// \c u and \c v with inherent orientation from node \c u to
+ /// node \c v.
+ /// \return The new edge.
+ Edge addEdge(RedNode u, BlueNode v) {
+ return Parent::addEdge(u, v);
+ }
+ Edge addEdge(BlueNode v, RedNode u) {
+ return Parent::addEdge(u, v);
+ }
+
+ /// \brief Node validity check
+ ///
+ /// This function gives back \c true if the given node is valid,
+ /// i.e. it is a real node of the graph.
+ ///
+ /// \warning A removed node (using Snapshot) could become valid again
+ /// if new nodes are added to the graph.
+ bool valid(Node n) const { return Parent::valid(n); }
+
+ /// \brief Edge validity check
+ ///
+ /// This function gives back \c true if the given edge is valid,
+ /// i.e. it is a real edge of the graph.
+ ///
+ /// \warning A removed edge (using Snapshot) could become valid again
+ /// if new edges are added to the graph.
+ bool valid(Edge e) const { return Parent::valid(e); }
+
+ /// \brief Arc validity check
+ ///
+ /// This function gives back \c true if the given arc is valid,
+ /// i.e. it is a real arc of the graph.
+ ///
+ /// \warning A removed arc (using Snapshot) could become valid again
+ /// if new edges are added to the graph.
+ bool valid(Arc a) const { return Parent::valid(a); }
+
+ ///Clear the graph.
+
+ ///This function erases all nodes and arcs from the graph.
+ ///
+ void clear() {
+ Parent::clear();
+ }
+
+ /// Reserve memory for nodes.
+
+ /// Using this function, it is possible to avoid superfluous memory
+ /// allocation: if you know that the graph you want to build will
+ /// be large (e.g. it will contain millions of nodes and/or edges),
+ /// then it is worth reserving space for this amount before starting
+ /// to build the graph.
+ /// \sa reserveEdge()
+ void reserveNode(int n) { nodes.reserve(n); };
+
+ /// Reserve memory for edges.
+
+ /// Using this function, it is possible to avoid superfluous memory
+ /// allocation: if you know that the graph you want to build will
+ /// be large (e.g. it will contain millions of nodes and/or edges),
+ /// then it is worth reserving space for this amount before starting
+ /// to build the graph.
+ /// \sa reserveNode()
+ void reserveEdge(int m) { arcs.reserve(2 * m); };
+
+ public:
+
+ class Snapshot;
+
+ protected:
+
+ void saveSnapshot(Snapshot &s)
+ {
+ s._graph = this;
+ s.node_num = nodes.size();
+ s.arc_num = arcs.size();
+ }
+
+ void restoreSnapshot(const Snapshot &s)
+ {
+ while(s.arc_num<arcs.size()) {
+ int n=arcs.size()-1;
+ Edge arc=edgeFromId(n/2);
+ Parent::notifier(Edge()).erase(arc);
+ std::vector<Arc> dir;
+ dir.push_back(arcFromId(n));
+ dir.push_back(arcFromId(n-1));
+ Parent::notifier(Arc()).erase(dir);
+ nodes[arcs[n-1].target].first_out=arcs[n].next_out;
+ nodes[arcs[n].target].first_out=arcs[n-1].next_out;
+ arcs.pop_back();
+ arcs.pop_back();
+ }
+ while(s.node_num<nodes.size()) {
+ int n=nodes.size()-1;
+ Node node = nodeFromId(n);
+ if (Parent::red(node)) {
+ first_red = nodes[n].partition_next;
+ if (first_red != -1) {
+ max_red = nodes[first_red].partition_index;
+ } else {
+ max_red = -1;
+ }
+ Parent::notifier(RedNode()).erase(asRedNodeUnsafe(node));
+ } else {
+ first_blue = nodes[n].partition_next;
+ if (first_blue != -1) {
+ max_blue = nodes[first_blue].partition_index;
+ } else {
+ max_blue = -1;
+ }
+ Parent::notifier(BlueNode()).erase(asBlueNodeUnsafe(node));
+ }
+ Parent::notifier(Node()).erase(node);
+ nodes.pop_back();
+ }
+ }
+
+ public:
+
+ ///Class to make a snapshot of the graph and to restore it later.
+
+ ///Class to make a snapshot of the graph and to restore it later.
+ ///
+ ///The newly added nodes and edges can be removed using the
+ ///restore() function. This is the only way for deleting nodes and/or
+ ///edges from a SmartBpGraph structure.
+ ///
+ ///\note After a state is restored, you cannot restore a later state,
+ ///i.e. you cannot add the removed nodes and edges again using
+ ///another Snapshot instance.
+ ///
+ ///\warning The validity of the snapshot is not stored due to
+ ///performance reasons. If you do not use the snapshot correctly,
+ ///it can cause broken program, invalid or not restored state of
+ ///the graph or no change.
+ class Snapshot
+ {
+ SmartBpGraph *_graph;
+ protected:
+ friend class SmartBpGraph;
+ unsigned int node_num;
+ unsigned int arc_num;
+ public:
+ ///Default constructor.
+
+ ///Default constructor.
+ ///You have to call save() to actually make a snapshot.
+ Snapshot() : _graph(0) {}
+ ///Constructor that immediately makes a snapshot
+
+ /// This constructor immediately makes a snapshot of the given graph.
+ ///
+ Snapshot(SmartBpGraph &gr) {
+ gr.saveSnapshot(*this);
+ }
+
+ ///Make a snapshot.
+
+ ///This function makes a snapshot of the given graph.
+ ///It can be called more than once. In case of a repeated
+ ///call, the previous snapshot gets lost.
+ void save(SmartBpGraph &gr)
+ {
+ gr.saveSnapshot(*this);
+ }
+
+ ///Undo the changes until the last snapshot.
+
+ ///This function undos the changes until the last snapshot
+ ///created by save() or Snapshot(SmartBpGraph&).
+ void restore()
+ {
+ _graph->restoreSnapshot(*this);
+ }
+ };
+ };
+
+} //namespace lemon
+
+
+#endif //LEMON_SMART_GRAPH_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/soplex.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/soplex.cc
new file mode 100644
index 00000000000..d7517231ce2
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/soplex.cc
@@ -0,0 +1,465 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <iostream>
+#include <lemon/soplex.h>
+
+#include <soplex.h>
+#include <spxout.h>
+
+
+///\file
+///\brief Implementation of the LEMON-SOPLEX lp solver interface.
+namespace lemon {
+
+ SoplexLp::SoplexLp() {
+ soplex = new soplex::SoPlex;
+ messageLevel(MESSAGE_NOTHING);
+ }
+
+ SoplexLp::~SoplexLp() {
+ delete soplex;
+ }
+
+ SoplexLp::SoplexLp(const SoplexLp& lp) {
+ rows = lp.rows;
+ cols = lp.cols;
+
+ soplex = new soplex::SoPlex;
+ (*static_cast<soplex::SPxLP*>(soplex)) = *(lp.soplex);
+
+ _col_names = lp._col_names;
+ _col_names_ref = lp._col_names_ref;
+
+ _row_names = lp._row_names;
+ _row_names_ref = lp._row_names_ref;
+
+ messageLevel(MESSAGE_NOTHING);
+ }
+
+ void SoplexLp::_clear_temporals() {
+ _primal_values.clear();
+ _dual_values.clear();
+ }
+
+ SoplexLp* SoplexLp::newSolver() const {
+ SoplexLp* newlp = new SoplexLp();
+ return newlp;
+ }
+
+ SoplexLp* SoplexLp::cloneSolver() const {
+ SoplexLp* newlp = new SoplexLp(*this);
+ return newlp;
+ }
+
+ const char* SoplexLp::_solverName() const { return "SoplexLp"; }
+
+ int SoplexLp::_addCol() {
+ soplex::LPCol c;
+ c.setLower(-soplex::infinity);
+ c.setUpper(soplex::infinity);
+ soplex->addCol(c);
+
+ _col_names.push_back(std::string());
+
+ return soplex->nCols() - 1;
+ }
+
+ int SoplexLp::_addRow() {
+ soplex::LPRow r;
+ r.setLhs(-soplex::infinity);
+ r.setRhs(soplex::infinity);
+ soplex->addRow(r);
+
+ _row_names.push_back(std::string());
+
+ return soplex->nRows() - 1;
+ }
+
+ int SoplexLp::_addRow(Value l, ExprIterator b, ExprIterator e, Value u) {
+ soplex::DSVector v;
+ for (ExprIterator it = b; it != e; ++it) {
+ v.add(it->first, it->second);
+ }
+ soplex::LPRow r(l, v, u);
+ soplex->addRow(r);
+
+ _row_names.push_back(std::string());
+
+ return soplex->nRows() - 1;
+ }
+
+
+ void SoplexLp::_eraseCol(int i) {
+ soplex->removeCol(i);
+ _col_names_ref.erase(_col_names[i]);
+ _col_names[i] = _col_names.back();
+ _col_names_ref[_col_names.back()] = i;
+ _col_names.pop_back();
+ }
+
+ void SoplexLp::_eraseRow(int i) {
+ soplex->removeRow(i);
+ _row_names_ref.erase(_row_names[i]);
+ _row_names[i] = _row_names.back();
+ _row_names_ref[_row_names.back()] = i;
+ _row_names.pop_back();
+ }
+
+ void SoplexLp::_eraseColId(int i) {
+ cols.eraseIndex(i);
+ cols.relocateIndex(i, cols.maxIndex());
+ }
+ void SoplexLp::_eraseRowId(int i) {
+ rows.eraseIndex(i);
+ rows.relocateIndex(i, rows.maxIndex());
+ }
+
+ void SoplexLp::_getColName(int c, std::string &name) const {
+ name = _col_names[c];
+ }
+
+ void SoplexLp::_setColName(int c, const std::string &name) {
+ _col_names_ref.erase(_col_names[c]);
+ _col_names[c] = name;
+ if (!name.empty()) {
+ _col_names_ref.insert(std::make_pair(name, c));
+ }
+ }
+
+ int SoplexLp::_colByName(const std::string& name) const {
+ std::map<std::string, int>::const_iterator it =
+ _col_names_ref.find(name);
+ if (it != _col_names_ref.end()) {
+ return it->second;
+ } else {
+ return -1;
+ }
+ }
+
+ void SoplexLp::_getRowName(int r, std::string &name) const {
+ name = _row_names[r];
+ }
+
+ void SoplexLp::_setRowName(int r, const std::string &name) {
+ _row_names_ref.erase(_row_names[r]);
+ _row_names[r] = name;
+ if (!name.empty()) {
+ _row_names_ref.insert(std::make_pair(name, r));
+ }
+ }
+
+ int SoplexLp::_rowByName(const std::string& name) const {
+ std::map<std::string, int>::const_iterator it =
+ _row_names_ref.find(name);
+ if (it != _row_names_ref.end()) {
+ return it->second;
+ } else {
+ return -1;
+ }
+ }
+
+
+ void SoplexLp::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) {
+ for (int j = 0; j < soplex->nCols(); ++j) {
+ soplex->changeElement(i, j, 0.0);
+ }
+ for(ExprIterator it = b; it != e; ++it) {
+ soplex->changeElement(i, it->first, it->second);
+ }
+ }
+
+ void SoplexLp::_getRowCoeffs(int i, InsertIterator b) const {
+ const soplex::SVector& vec = soplex->rowVector(i);
+ for (int k = 0; k < vec.size(); ++k) {
+ *b = std::make_pair(vec.index(k), vec.value(k));
+ ++b;
+ }
+ }
+
+ void SoplexLp::_setColCoeffs(int j, ExprIterator b, ExprIterator e) {
+ for (int i = 0; i < soplex->nRows(); ++i) {
+ soplex->changeElement(i, j, 0.0);
+ }
+ for(ExprIterator it = b; it != e; ++it) {
+ soplex->changeElement(it->first, j, it->second);
+ }
+ }
+
+ void SoplexLp::_getColCoeffs(int i, InsertIterator b) const {
+ const soplex::SVector& vec = soplex->colVector(i);
+ for (int k = 0; k < vec.size(); ++k) {
+ *b = std::make_pair(vec.index(k), vec.value(k));
+ ++b;
+ }
+ }
+
+ void SoplexLp::_setCoeff(int i, int j, Value value) {
+ soplex->changeElement(i, j, value);
+ }
+
+ SoplexLp::Value SoplexLp::_getCoeff(int i, int j) const {
+ return soplex->rowVector(i)[j];
+ }
+
+ void SoplexLp::_setColLowerBound(int i, Value value) {
+ LEMON_ASSERT(value != INF, "Invalid bound");
+ soplex->changeLower(i, value != -INF ? value : -soplex::infinity);
+ }
+
+ SoplexLp::Value SoplexLp::_getColLowerBound(int i) const {
+ double value = soplex->lower(i);
+ return value != -soplex::infinity ? value : -INF;
+ }
+
+ void SoplexLp::_setColUpperBound(int i, Value value) {
+ LEMON_ASSERT(value != -INF, "Invalid bound");
+ soplex->changeUpper(i, value != INF ? value : soplex::infinity);
+ }
+
+ SoplexLp::Value SoplexLp::_getColUpperBound(int i) const {
+ double value = soplex->upper(i);
+ return value != soplex::infinity ? value : INF;
+ }
+
+ void SoplexLp::_setRowLowerBound(int i, Value lb) {
+ LEMON_ASSERT(lb != INF, "Invalid bound");
+ soplex->changeRange(i, lb != -INF ? lb : -soplex::infinity, soplex->rhs(i));
+ }
+
+ SoplexLp::Value SoplexLp::_getRowLowerBound(int i) const {
+ double res = soplex->lhs(i);
+ return res == -soplex::infinity ? -INF : res;
+ }
+
+ void SoplexLp::_setRowUpperBound(int i, Value ub) {
+ LEMON_ASSERT(ub != -INF, "Invalid bound");
+ soplex->changeRange(i, soplex->lhs(i), ub != INF ? ub : soplex::infinity);
+ }
+
+ SoplexLp::Value SoplexLp::_getRowUpperBound(int i) const {
+ double res = soplex->rhs(i);
+ return res == soplex::infinity ? INF : res;
+ }
+
+ void SoplexLp::_setObjCoeffs(ExprIterator b, ExprIterator e) {
+ for (int j = 0; j < soplex->nCols(); ++j) {
+ soplex->changeObj(j, 0.0);
+ }
+ for (ExprIterator it = b; it != e; ++it) {
+ soplex->changeObj(it->first, it->second);
+ }
+ }
+
+ void SoplexLp::_getObjCoeffs(InsertIterator b) const {
+ for (int j = 0; j < soplex->nCols(); ++j) {
+ Value coef = soplex->obj(j);
+ if (coef != 0.0) {
+ *b = std::make_pair(j, coef);
+ ++b;
+ }
+ }
+ }
+
+ void SoplexLp::_setObjCoeff(int i, Value obj_coef) {
+ soplex->changeObj(i, obj_coef);
+ }
+
+ SoplexLp::Value SoplexLp::_getObjCoeff(int i) const {
+ return soplex->obj(i);
+ }
+
+ SoplexLp::SolveExitStatus SoplexLp::_solve() {
+
+ _clear_temporals();
+
+ _applyMessageLevel();
+
+ soplex::SPxSolver::Status status = soplex->solve();
+
+ switch (status) {
+ case soplex::SPxSolver::OPTIMAL:
+ case soplex::SPxSolver::INFEASIBLE:
+ case soplex::SPxSolver::UNBOUNDED:
+ return SOLVED;
+ default:
+ return UNSOLVED;
+ }
+ }
+
+ SoplexLp::Value SoplexLp::_getPrimal(int i) const {
+ if (_primal_values.empty()) {
+ _primal_values.resize(soplex->nCols());
+ soplex::Vector pv(_primal_values.size(), &_primal_values.front());
+ soplex->getPrimal(pv);
+ }
+ return _primal_values[i];
+ }
+
+ SoplexLp::Value SoplexLp::_getDual(int i) const {
+ if (_dual_values.empty()) {
+ _dual_values.resize(soplex->nRows());
+ soplex::Vector dv(_dual_values.size(), &_dual_values.front());
+ soplex->getDual(dv);
+ }
+ return _dual_values[i];
+ }
+
+ SoplexLp::Value SoplexLp::_getPrimalValue() const {
+ return soplex->objValue();
+ }
+
+ SoplexLp::VarStatus SoplexLp::_getColStatus(int i) const {
+ switch (soplex->getBasisColStatus(i)) {
+ case soplex::SPxSolver::BASIC:
+ return BASIC;
+ case soplex::SPxSolver::ON_UPPER:
+ return UPPER;
+ case soplex::SPxSolver::ON_LOWER:
+ return LOWER;
+ case soplex::SPxSolver::FIXED:
+ return FIXED;
+ case soplex::SPxSolver::ZERO:
+ return FREE;
+ default:
+ LEMON_ASSERT(false, "Wrong column status");
+ return VarStatus();
+ }
+ }
+
+ SoplexLp::VarStatus SoplexLp::_getRowStatus(int i) const {
+ switch (soplex->getBasisRowStatus(i)) {
+ case soplex::SPxSolver::BASIC:
+ return BASIC;
+ case soplex::SPxSolver::ON_UPPER:
+ return UPPER;
+ case soplex::SPxSolver::ON_LOWER:
+ return LOWER;
+ case soplex::SPxSolver::FIXED:
+ return FIXED;
+ case soplex::SPxSolver::ZERO:
+ return FREE;
+ default:
+ LEMON_ASSERT(false, "Wrong row status");
+ return VarStatus();
+ }
+ }
+
+ SoplexLp::Value SoplexLp::_getPrimalRay(int i) const {
+ if (_primal_ray.empty()) {
+ _primal_ray.resize(soplex->nCols());
+ soplex::Vector pv(_primal_ray.size(), &_primal_ray.front());
+ soplex->getDualfarkas(pv);
+ }
+ return _primal_ray[i];
+ }
+
+ SoplexLp::Value SoplexLp::_getDualRay(int i) const {
+ if (_dual_ray.empty()) {
+ _dual_ray.resize(soplex->nRows());
+ soplex::Vector dv(_dual_ray.size(), &_dual_ray.front());
+ soplex->getDualfarkas(dv);
+ }
+ return _dual_ray[i];
+ }
+
+ SoplexLp::ProblemType SoplexLp::_getPrimalType() const {
+ switch (soplex->status()) {
+ case soplex::SPxSolver::OPTIMAL:
+ return OPTIMAL;
+ case soplex::SPxSolver::UNBOUNDED:
+ return UNBOUNDED;
+ case soplex::SPxSolver::INFEASIBLE:
+ return INFEASIBLE;
+ default:
+ return UNDEFINED;
+ }
+ }
+
+ SoplexLp::ProblemType SoplexLp::_getDualType() const {
+ switch (soplex->status()) {
+ case soplex::SPxSolver::OPTIMAL:
+ return OPTIMAL;
+ case soplex::SPxSolver::UNBOUNDED:
+ return UNBOUNDED;
+ case soplex::SPxSolver::INFEASIBLE:
+ return INFEASIBLE;
+ default:
+ return UNDEFINED;
+ }
+ }
+
+ void SoplexLp::_setSense(Sense sense) {
+ switch (sense) {
+ case MIN:
+ soplex->changeSense(soplex::SPxSolver::MINIMIZE);
+ break;
+ case MAX:
+ soplex->changeSense(soplex::SPxSolver::MAXIMIZE);
+ }
+ }
+
+ SoplexLp::Sense SoplexLp::_getSense() const {
+ switch (soplex->spxSense()) {
+ case soplex::SPxSolver::MAXIMIZE:
+ return MAX;
+ case soplex::SPxSolver::MINIMIZE:
+ return MIN;
+ default:
+ LEMON_ASSERT(false, "Wrong sense.");
+ return SoplexLp::Sense();
+ }
+ }
+
+ void SoplexLp::_clear() {
+ soplex->clear();
+ _col_names.clear();
+ _col_names_ref.clear();
+ _row_names.clear();
+ _row_names_ref.clear();
+ cols.clear();
+ rows.clear();
+ _clear_temporals();
+ }
+
+ void SoplexLp::_messageLevel(MessageLevel level) {
+ switch (level) {
+ case MESSAGE_NOTHING:
+ _message_level = -1;
+ break;
+ case MESSAGE_ERROR:
+ _message_level = soplex::SPxOut::ERROR;
+ break;
+ case MESSAGE_WARNING:
+ _message_level = soplex::SPxOut::WARNING;
+ break;
+ case MESSAGE_NORMAL:
+ _message_level = soplex::SPxOut::INFO2;
+ break;
+ case MESSAGE_VERBOSE:
+ _message_level = soplex::SPxOut::DEBUG;
+ break;
+ }
+ }
+
+ void SoplexLp::_applyMessageLevel() {
+ soplex::Param::setVerbose(_message_level);
+ }
+
+} //namespace lemon
+
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/soplex.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/soplex.h
new file mode 100644
index 00000000000..be73f3abecd
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/soplex.h
@@ -0,0 +1,158 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_SOPLEX_H
+#define LEMON_SOPLEX_H
+
+///\file
+///\brief Header of the LEMON-SOPLEX lp solver interface.
+
+#include <vector>
+#include <string>
+
+#include <lemon/lp_base.h>
+
+// Forward declaration
+namespace soplex {
+ class SoPlex;
+}
+
+namespace lemon {
+
+ /// \ingroup lp_group
+ ///
+ /// \brief Interface for the SOPLEX solver
+ ///
+ /// This class implements an interface for the SoPlex LP solver.
+ /// The SoPlex library is an object oriented lp solver library
+ /// developed at the Konrad-Zuse-Zentrum für Informationstechnik
+ /// Berlin (ZIB). You can find detailed information about it at the
+ /// <tt>http://soplex.zib.de</tt> address.
+ class SoplexLp : public LpSolver {
+ private:
+
+ soplex::SoPlex* soplex;
+
+ std::vector<std::string> _col_names;
+ std::map<std::string, int> _col_names_ref;
+
+ std::vector<std::string> _row_names;
+ std::map<std::string, int> _row_names_ref;
+
+ private:
+
+ // these values cannot be retrieved element by element
+ mutable std::vector<Value> _primal_values;
+ mutable std::vector<Value> _dual_values;
+
+ mutable std::vector<Value> _primal_ray;
+ mutable std::vector<Value> _dual_ray;
+
+ void _clear_temporals();
+
+ public:
+
+ /// \e
+ SoplexLp();
+ /// \e
+ SoplexLp(const SoplexLp&);
+ /// \e
+ ~SoplexLp();
+ /// \e
+ virtual SoplexLp* newSolver() const;
+ /// \e
+ virtual SoplexLp* cloneSolver() const;
+
+ protected:
+
+ virtual const char* _solverName() const;
+
+ virtual int _addCol();
+ virtual int _addRow();
+ virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u);
+
+ virtual void _eraseCol(int i);
+ virtual void _eraseRow(int i);
+
+ virtual void _eraseColId(int i);
+ virtual void _eraseRowId(int i);
+
+ virtual void _getColName(int col, std::string& name) const;
+ virtual void _setColName(int col, const std::string& name);
+ virtual int _colByName(const std::string& name) const;
+
+ virtual void _getRowName(int row, std::string& name) const;
+ virtual void _setRowName(int row, const std::string& name);
+ virtual int _rowByName(const std::string& name) const;
+
+ virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e);
+ virtual void _getRowCoeffs(int i, InsertIterator b) const;
+
+ virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e);
+ virtual void _getColCoeffs(int i, InsertIterator b) const;
+
+ virtual void _setCoeff(int row, int col, Value value);
+ virtual Value _getCoeff(int row, int col) const;
+
+ virtual void _setColLowerBound(int i, Value value);
+ virtual Value _getColLowerBound(int i) const;
+ virtual void _setColUpperBound(int i, Value value);
+ virtual Value _getColUpperBound(int i) const;
+
+ virtual void _setRowLowerBound(int i, Value value);
+ virtual Value _getRowLowerBound(int i) const;
+ virtual void _setRowUpperBound(int i, Value value);
+ virtual Value _getRowUpperBound(int i) const;
+
+ virtual void _setObjCoeffs(ExprIterator b, ExprIterator e);
+ virtual void _getObjCoeffs(InsertIterator b) const;
+
+ virtual void _setObjCoeff(int i, Value obj_coef);
+ virtual Value _getObjCoeff(int i) const;
+
+ virtual void _setSense(Sense sense);
+ virtual Sense _getSense() const;
+
+ virtual SolveExitStatus _solve();
+ virtual Value _getPrimal(int i) const;
+ virtual Value _getDual(int i) const;
+
+ virtual Value _getPrimalValue() const;
+
+ virtual Value _getPrimalRay(int i) const;
+ virtual Value _getDualRay(int i) const;
+
+ virtual VarStatus _getColStatus(int i) const;
+ virtual VarStatus _getRowStatus(int i) const;
+
+ virtual ProblemType _getPrimalType() const;
+ virtual ProblemType _getDualType() const;
+
+ virtual void _clear();
+
+ void _messageLevel(MessageLevel m);
+ void _applyMessageLevel();
+
+ int _message_level;
+
+ };
+
+} //END OF NAMESPACE LEMON
+
+#endif //LEMON_SOPLEX_H
+
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/static_graph.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/static_graph.h
new file mode 100644
index 00000000000..1f04e40841c
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/static_graph.h
@@ -0,0 +1,476 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2010
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_STATIC_GRAPH_H
+#define LEMON_STATIC_GRAPH_H
+
+///\ingroup graphs
+///\file
+///\brief StaticDigraph class.
+
+#include <lemon/core.h>
+#include <lemon/bits/graph_extender.h>
+
+namespace lemon {
+
+ class StaticDigraphBase {
+ public:
+
+ StaticDigraphBase()
+ : built(false), node_num(0), arc_num(0),
+ node_first_out(NULL), node_first_in(NULL),
+ arc_source(NULL), arc_target(NULL),
+ arc_next_in(NULL), arc_next_out(NULL) {}
+
+ ~StaticDigraphBase() {
+ if (built) {
+ delete[] node_first_out;
+ delete[] node_first_in;
+ delete[] arc_source;
+ delete[] arc_target;
+ delete[] arc_next_out;
+ delete[] arc_next_in;
+ }
+ }
+
+ class Node {
+ friend class StaticDigraphBase;
+ protected:
+ int id;
+ Node(int _id) : id(_id) {}
+ public:
+ Node() {}
+ Node (Invalid) : id(-1) {}
+ bool operator==(const Node& node) const { return id == node.id; }
+ bool operator!=(const Node& node) const { return id != node.id; }
+ bool operator<(const Node& node) const { return id < node.id; }
+ };
+
+ class Arc {
+ friend class StaticDigraphBase;
+ protected:
+ int id;
+ Arc(int _id) : id(_id) {}
+ public:
+ Arc() { }
+ Arc (Invalid) : id(-1) {}
+ bool operator==(const Arc& arc) const { return id == arc.id; }
+ bool operator!=(const Arc& arc) const { return id != arc.id; }
+ bool operator<(const Arc& arc) const { return id < arc.id; }
+ };
+
+ Node source(const Arc& e) const { return Node(arc_source[e.id]); }
+ Node target(const Arc& e) const { return Node(arc_target[e.id]); }
+
+ void first(Node& n) const { n.id = node_num - 1; }
+ static void next(Node& n) { --n.id; }
+
+ void first(Arc& e) const { e.id = arc_num - 1; }
+ static void next(Arc& e) { --e.id; }
+
+ void firstOut(Arc& e, const Node& n) const {
+ e.id = node_first_out[n.id] != node_first_out[n.id + 1] ?
+ node_first_out[n.id] : -1;
+ }
+ void nextOut(Arc& e) const { e.id = arc_next_out[e.id]; }
+
+ void firstIn(Arc& e, const Node& n) const { e.id = node_first_in[n.id]; }
+ void nextIn(Arc& e) const { e.id = arc_next_in[e.id]; }
+
+ static int id(const Node& n) { return n.id; }
+ static Node nodeFromId(int id) { return Node(id); }
+ int maxNodeId() const { return node_num - 1; }
+
+ static int id(const Arc& e) { return e.id; }
+ static Arc arcFromId(int id) { return Arc(id); }
+ int maxArcId() const { return arc_num - 1; }
+
+ typedef True NodeNumTag;
+ typedef True ArcNumTag;
+
+ int nodeNum() const { return node_num; }
+ int arcNum() const { return arc_num; }
+
+ private:
+
+ template <typename Digraph, typename NodeRefMap>
+ class ArcLess {
+ public:
+ typedef typename Digraph::Arc Arc;
+
+ ArcLess(const Digraph &_graph, const NodeRefMap& _nodeRef)
+ : digraph(_graph), nodeRef(_nodeRef) {}
+
+ bool operator()(const Arc& left, const Arc& right) const {
+ return nodeRef[digraph.target(left)] < nodeRef[digraph.target(right)];
+ }
+ private:
+ const Digraph& digraph;
+ const NodeRefMap& nodeRef;
+ };
+
+ public:
+
+ typedef True BuildTag;
+
+ void clear() {
+ if (built) {
+ delete[] node_first_out;
+ delete[] node_first_in;
+ delete[] arc_source;
+ delete[] arc_target;
+ delete[] arc_next_out;
+ delete[] arc_next_in;
+ }
+ built = false;
+ node_num = 0;
+ arc_num = 0;
+ }
+
+ template <typename Digraph, typename NodeRefMap, typename ArcRefMap>
+ void build(const Digraph& digraph, NodeRefMap& nodeRef, ArcRefMap& arcRef) {
+ typedef typename Digraph::Node GNode;
+ typedef typename Digraph::Arc GArc;
+
+ built = true;
+
+ node_num = countNodes(digraph);
+ arc_num = countArcs(digraph);
+
+ node_first_out = new int[node_num + 1];
+ node_first_in = new int[node_num];
+
+ arc_source = new int[arc_num];
+ arc_target = new int[arc_num];
+ arc_next_out = new int[arc_num];
+ arc_next_in = new int[arc_num];
+
+ int node_index = 0;
+ for (typename Digraph::NodeIt n(digraph); n != INVALID; ++n) {
+ nodeRef[n] = Node(node_index);
+ node_first_in[node_index] = -1;
+ ++node_index;
+ }
+
+ ArcLess<Digraph, NodeRefMap> arcLess(digraph, nodeRef);
+
+ int arc_index = 0;
+ for (typename Digraph::NodeIt n(digraph); n != INVALID; ++n) {
+ int source = nodeRef[n].id;
+ std::vector<GArc> arcs;
+ for (typename Digraph::OutArcIt e(digraph, n); e != INVALID; ++e) {
+ arcs.push_back(e);
+ }
+ if (!arcs.empty()) {
+ node_first_out[source] = arc_index;
+ std::sort(arcs.begin(), arcs.end(), arcLess);
+ for (typename std::vector<GArc>::iterator it = arcs.begin();
+ it != arcs.end(); ++it) {
+ int target = nodeRef[digraph.target(*it)].id;
+ arcRef[*it] = Arc(arc_index);
+ arc_source[arc_index] = source;
+ arc_target[arc_index] = target;
+ arc_next_in[arc_index] = node_first_in[target];
+ node_first_in[target] = arc_index;
+ arc_next_out[arc_index] = arc_index + 1;
+ ++arc_index;
+ }
+ arc_next_out[arc_index - 1] = -1;
+ } else {
+ node_first_out[source] = arc_index;
+ }
+ }
+ node_first_out[node_num] = arc_num;
+ }
+
+ template <typename ArcListIterator>
+ void build(int n, ArcListIterator first, ArcListIterator last) {
+ built = true;
+
+ node_num = n;
+ arc_num = std::distance(first, last);
+
+ node_first_out = new int[node_num + 1];
+ node_first_in = new int[node_num];
+
+ arc_source = new int[arc_num];
+ arc_target = new int[arc_num];
+ arc_next_out = new int[arc_num];
+ arc_next_in = new int[arc_num];
+
+ for (int i = 0; i != node_num; ++i) {
+ node_first_in[i] = -1;
+ }
+
+ int arc_index = 0;
+ for (int i = 0; i != node_num; ++i) {
+ node_first_out[i] = arc_index;
+ for ( ; first != last && (*first).first == i; ++first) {
+ int j = (*first).second;
+ LEMON_ASSERT(j >= 0 && j < node_num,
+ "Wrong arc list for StaticDigraph::build()");
+ arc_source[arc_index] = i;
+ arc_target[arc_index] = j;
+ arc_next_in[arc_index] = node_first_in[j];
+ node_first_in[j] = arc_index;
+ arc_next_out[arc_index] = arc_index + 1;
+ ++arc_index;
+ }
+ if (arc_index > node_first_out[i])
+ arc_next_out[arc_index - 1] = -1;
+ }
+ LEMON_ASSERT(first == last,
+ "Wrong arc list for StaticDigraph::build()");
+ node_first_out[node_num] = arc_num;
+ }
+
+ protected:
+
+ void fastFirstOut(Arc& e, const Node& n) const {
+ e.id = node_first_out[n.id];
+ }
+
+ static void fastNextOut(Arc& e) {
+ ++e.id;
+ }
+ void fastLastOut(Arc& e, const Node& n) const {
+ e.id = node_first_out[n.id + 1];
+ }
+
+ protected:
+ bool built;
+ int node_num;
+ int arc_num;
+ int *node_first_out;
+ int *node_first_in;
+ int *arc_source;
+ int *arc_target;
+ int *arc_next_in;
+ int *arc_next_out;
+ };
+
+ typedef DigraphExtender<StaticDigraphBase> ExtendedStaticDigraphBase;
+
+
+ /// \ingroup graphs
+ ///
+ /// \brief A static directed graph class.
+ ///
+ /// \ref StaticDigraph is a highly efficient digraph implementation,
+ /// but it is fully static.
+ /// It stores only two \c int values for each node and only four \c int
+ /// values for each arc. Moreover it provides faster item iteration than
+ /// \ref ListDigraph and \ref SmartDigraph, especially using \c OutArcIt
+ /// iterators, since its arcs are stored in an appropriate order.
+ /// However it only provides build() and clear() functions and does not
+ /// support any other modification of the digraph.
+ ///
+ /// Since this digraph structure is completely static, its nodes and arcs
+ /// can be indexed with integers from the ranges <tt>[0..nodeNum()-1]</tt>
+ /// and <tt>[0..arcNum()-1]</tt>, respectively.
+ /// The index of an item is the same as its ID, it can be obtained
+ /// using the corresponding \ref index() or \ref concepts::Digraph::id()
+ /// "id()" function. A node or arc with a certain index can be obtained
+ /// using node() or arc().
+ ///
+ /// This type fully conforms to the \ref concepts::Digraph "Digraph concept".
+ /// Most of its member functions and nested classes are documented
+ /// only in the concept class.
+ ///
+ /// This class provides constant time counting for nodes and arcs.
+ ///
+ /// \sa concepts::Digraph
+ class StaticDigraph : public ExtendedStaticDigraphBase {
+ public:
+
+ typedef ExtendedStaticDigraphBase Parent;
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Default constructor.
+ StaticDigraph() : Parent() {}
+
+ /// \brief The node with the given index.
+ ///
+ /// This function returns the node with the given index.
+ /// \sa index()
+ static Node node(int ix) { return Parent::nodeFromId(ix); }
+
+ /// \brief The arc with the given index.
+ ///
+ /// This function returns the arc with the given index.
+ /// \sa index()
+ static Arc arc(int ix) { return Parent::arcFromId(ix); }
+
+ /// \brief The index of the given node.
+ ///
+ /// This function returns the index of the the given node.
+ /// \sa node()
+ static int index(Node node) { return Parent::id(node); }
+
+ /// \brief The index of the given arc.
+ ///
+ /// This function returns the index of the the given arc.
+ /// \sa arc()
+ static int index(Arc arc) { return Parent::id(arc); }
+
+ /// \brief Number of nodes.
+ ///
+ /// This function returns the number of nodes.
+ int nodeNum() const { return node_num; }
+
+ /// \brief Number of arcs.
+ ///
+ /// This function returns the number of arcs.
+ int arcNum() const { return arc_num; }
+
+ /// \brief Build the digraph copying another digraph.
+ ///
+ /// This function builds the digraph copying another digraph of any
+ /// kind. It can be called more than once, but in such case, the whole
+ /// structure and all maps will be cleared and rebuilt.
+ ///
+ /// This method also makes possible to copy a digraph to a StaticDigraph
+ /// structure using \ref DigraphCopy.
+ ///
+ /// \param digraph An existing digraph to be copied.
+ /// \param nodeRef The node references will be copied into this map.
+ /// Its key type must be \c Digraph::Node and its value type must be
+ /// \c StaticDigraph::Node.
+ /// It must conform to the \ref concepts::ReadWriteMap "ReadWriteMap"
+ /// concept.
+ /// \param arcRef The arc references will be copied into this map.
+ /// Its key type must be \c Digraph::Arc and its value type must be
+ /// \c StaticDigraph::Arc.
+ /// It must conform to the \ref concepts::WriteMap "WriteMap" concept.
+ ///
+ /// \note If you do not need the arc references, then you could use
+ /// \ref NullMap for the last parameter. However the node references
+ /// are required by the function itself, thus they must be readable
+ /// from the map.
+ template <typename Digraph, typename NodeRefMap, typename ArcRefMap>
+ void build(const Digraph& digraph, NodeRefMap& nodeRef, ArcRefMap& arcRef) {
+ if (built) Parent::clear();
+ Parent::build(digraph, nodeRef, arcRef);
+ }
+
+ /// \brief Build the digraph from an arc list.
+ ///
+ /// This function builds the digraph from the given arc list.
+ /// It can be called more than once, but in such case, the whole
+ /// structure and all maps will be cleared and rebuilt.
+ ///
+ /// The list of the arcs must be given in the range <tt>[begin, end)</tt>
+ /// specified by STL compatible itartors whose \c value_type must be
+ /// <tt>std::pair<int,int></tt>.
+ /// Each arc must be specified by a pair of integer indices
+ /// from the range <tt>[0..n-1]</tt>. <i>The pairs must be in a
+ /// non-decreasing order with respect to their first values.</i>
+ /// If the k-th pair in the list is <tt>(i,j)</tt>, then
+ /// <tt>arc(k-1)</tt> will connect <tt>node(i)</tt> to <tt>node(j)</tt>.
+ ///
+ /// \param n The number of nodes.
+ /// \param begin An iterator pointing to the beginning of the arc list.
+ /// \param end An iterator pointing to the end of the arc list.
+ ///
+ /// For example, a simple digraph can be constructed like this.
+ /// \code
+ /// std::vector<std::pair<int,int> > arcs;
+ /// arcs.push_back(std::make_pair(0,1));
+ /// arcs.push_back(std::make_pair(0,2));
+ /// arcs.push_back(std::make_pair(1,3));
+ /// arcs.push_back(std::make_pair(1,2));
+ /// arcs.push_back(std::make_pair(3,0));
+ /// StaticDigraph gr;
+ /// gr.build(4, arcs.begin(), arcs.end());
+ /// \endcode
+ template <typename ArcListIterator>
+ void build(int n, ArcListIterator begin, ArcListIterator end) {
+ if (built) Parent::clear();
+ StaticDigraphBase::build(n, begin, end);
+ notifier(Node()).build();
+ notifier(Arc()).build();
+ }
+
+ /// \brief Clear the digraph.
+ ///
+ /// This function erases all nodes and arcs from the digraph.
+ void clear() {
+ Parent::clear();
+ }
+
+ protected:
+
+ using Parent::fastFirstOut;
+ using Parent::fastNextOut;
+ using Parent::fastLastOut;
+
+ public:
+
+ class OutArcIt : public Arc {
+ public:
+
+ OutArcIt() { }
+
+ OutArcIt(Invalid i) : Arc(i) { }
+
+ OutArcIt(const StaticDigraph& digraph, const Node& node) {
+ digraph.fastFirstOut(*this, node);
+ digraph.fastLastOut(last, node);
+ if (last == *this) *this = INVALID;
+ }
+
+ OutArcIt(const StaticDigraph& digraph, const Arc& arc) : Arc(arc) {
+ if (arc != INVALID) {
+ digraph.fastLastOut(last, digraph.source(arc));
+ }
+ }
+
+ OutArcIt& operator++() {
+ StaticDigraph::fastNextOut(*this);
+ if (last == *this) *this = INVALID;
+ return *this;
+ }
+
+ private:
+ Arc last;
+ };
+
+ Node baseNode(const OutArcIt &arc) const {
+ return Parent::source(static_cast<const Arc&>(arc));
+ }
+
+ Node runningNode(const OutArcIt &arc) const {
+ return Parent::target(static_cast<const Arc&>(arc));
+ }
+
+ Node baseNode(const InArcIt &arc) const {
+ return Parent::target(static_cast<const Arc&>(arc));
+ }
+
+ Node runningNode(const InArcIt &arc) const {
+ return Parent::source(static_cast<const Arc&>(arc));
+ }
+
+ };
+
+}
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/suurballe.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/suurballe.h
new file mode 100644
index 00000000000..f1338a2948f
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/suurballe.h
@@ -0,0 +1,776 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_SUURBALLE_H
+#define LEMON_SUURBALLE_H
+
+///\ingroup shortest_path
+///\file
+///\brief An algorithm for finding arc-disjoint paths between two
+/// nodes having minimum total length.
+
+#include <vector>
+#include <limits>
+#include <lemon/bin_heap.h>
+#include <lemon/path.h>
+#include <lemon/list_graph.h>
+#include <lemon/dijkstra.h>
+#include <lemon/maps.h>
+
+namespace lemon {
+
+ /// \brief Default traits class of Suurballe algorithm.
+ ///
+ /// Default traits class of Suurballe algorithm.
+ /// \tparam GR The digraph type the algorithm runs on.
+ /// \tparam LEN The type of the length map.
+ /// The default value is <tt>GR::ArcMap<int></tt>.
+#ifdef DOXYGEN
+ template <typename GR, typename LEN>
+#else
+ template < typename GR,
+ typename LEN = typename GR::template ArcMap<int> >
+#endif
+ struct SuurballeDefaultTraits
+ {
+ /// The type of the digraph.
+ typedef GR Digraph;
+ /// The type of the length map.
+ typedef LEN LengthMap;
+ /// The type of the lengths.
+ typedef typename LEN::Value Length;
+ /// The type of the flow map.
+ typedef typename GR::template ArcMap<int> FlowMap;
+ /// The type of the potential map.
+ typedef typename GR::template NodeMap<Length> PotentialMap;
+
+ /// \brief The path type
+ ///
+ /// The type used for storing the found arc-disjoint paths.
+ /// It must conform to the \ref lemon::concepts::Path "Path" concept
+ /// and it must have an \c addBack() function.
+ typedef lemon::Path<Digraph> Path;
+
+ /// The cross reference type used for the heap.
+ typedef typename GR::template NodeMap<int> HeapCrossRef;
+
+ /// \brief The heap type used for internal Dijkstra computations.
+ ///
+ /// The type of the heap used for internal Dijkstra computations.
+ /// It must conform to the \ref lemon::concepts::Heap "Heap" concept
+ /// and its priority type must be \c Length.
+ typedef BinHeap<Length, HeapCrossRef> Heap;
+ };
+
+ /// \addtogroup shortest_path
+ /// @{
+
+ /// \brief Algorithm for finding arc-disjoint paths between two nodes
+ /// having minimum total length.
+ ///
+ /// \ref lemon::Suurballe "Suurballe" implements an algorithm for
+ /// finding arc-disjoint paths having minimum total length (cost)
+ /// from a given source node to a given target node in a digraph.
+ ///
+ /// Note that this problem is a special case of the \ref min_cost_flow
+ /// "minimum cost flow problem". This implementation is actually an
+ /// efficient specialized version of the \ref CapacityScaling
+ /// "successive shortest path" algorithm directly for this problem.
+ /// Therefore this class provides query functions for flow values and
+ /// node potentials (the dual solution) just like the minimum cost flow
+ /// algorithms.
+ ///
+ /// \tparam GR The digraph type the algorithm runs on.
+ /// \tparam LEN The type of the length map.
+ /// The default value is <tt>GR::ArcMap<int></tt>.
+ ///
+ /// \warning Length values should be \e non-negative.
+ ///
+ /// \note For finding \e node-disjoint paths, this algorithm can be used
+ /// along with the \ref SplitNodes adaptor.
+#ifdef DOXYGEN
+ template <typename GR, typename LEN, typename TR>
+#else
+ template < typename GR,
+ typename LEN = typename GR::template ArcMap<int>,
+ typename TR = SuurballeDefaultTraits<GR, LEN> >
+#endif
+ class Suurballe
+ {
+ TEMPLATE_DIGRAPH_TYPEDEFS(GR);
+
+ typedef ConstMap<Arc, int> ConstArcMap;
+ typedef typename GR::template NodeMap<Arc> PredMap;
+
+ public:
+
+ /// The type of the digraph.
+ typedef typename TR::Digraph Digraph;
+ /// The type of the length map.
+ typedef typename TR::LengthMap LengthMap;
+ /// The type of the lengths.
+ typedef typename TR::Length Length;
+
+ /// The type of the flow map.
+ typedef typename TR::FlowMap FlowMap;
+ /// The type of the potential map.
+ typedef typename TR::PotentialMap PotentialMap;
+ /// The type of the path structures.
+ typedef typename TR::Path Path;
+ /// The cross reference type used for the heap.
+ typedef typename TR::HeapCrossRef HeapCrossRef;
+ /// The heap type used for internal Dijkstra computations.
+ typedef typename TR::Heap Heap;
+
+ /// The \ref lemon::SuurballeDefaultTraits "traits class" of the algorithm.
+ typedef TR Traits;
+
+ private:
+
+ // ResidualDijkstra is a special implementation of the
+ // Dijkstra algorithm for finding shortest paths in the
+ // residual network with respect to the reduced arc lengths
+ // and modifying the node potentials according to the
+ // distance of the nodes.
+ class ResidualDijkstra
+ {
+ private:
+
+ const Digraph &_graph;
+ const LengthMap &_length;
+ const FlowMap &_flow;
+ PotentialMap &_pi;
+ PredMap &_pred;
+ Node _s;
+ Node _t;
+
+ PotentialMap _dist;
+ std::vector<Node> _proc_nodes;
+
+ public:
+
+ // Constructor
+ ResidualDijkstra(Suurballe &srb) :
+ _graph(srb._graph), _length(srb._length),
+ _flow(*srb._flow), _pi(*srb._potential), _pred(srb._pred),
+ _s(srb._s), _t(srb._t), _dist(_graph) {}
+
+ // Run the algorithm and return true if a path is found
+ // from the source node to the target node.
+ bool run(int cnt) {
+ return cnt == 0 ? startFirst() : start();
+ }
+
+ private:
+
+ // Execute the algorithm for the first time (the flow and potential
+ // functions have to be identically zero).
+ bool startFirst() {
+ HeapCrossRef heap_cross_ref(_graph, Heap::PRE_HEAP);
+ Heap heap(heap_cross_ref);
+ heap.push(_s, 0);
+ _pred[_s] = INVALID;
+ _proc_nodes.clear();
+
+ // Process nodes
+ while (!heap.empty() && heap.top() != _t) {
+ Node u = heap.top(), v;
+ Length d = heap.prio(), dn;
+ _dist[u] = heap.prio();
+ _proc_nodes.push_back(u);
+ heap.pop();
+
+ // Traverse outgoing arcs
+ for (OutArcIt e(_graph, u); e != INVALID; ++e) {
+ v = _graph.target(e);
+ switch(heap.state(v)) {
+ case Heap::PRE_HEAP:
+ heap.push(v, d + _length[e]);
+ _pred[v] = e;
+ break;
+ case Heap::IN_HEAP:
+ dn = d + _length[e];
+ if (dn < heap[v]) {
+ heap.decrease(v, dn);
+ _pred[v] = e;
+ }
+ break;
+ case Heap::POST_HEAP:
+ break;
+ }
+ }
+ }
+ if (heap.empty()) return false;
+
+ // Update potentials of processed nodes
+ Length t_dist = heap.prio();
+ for (int i = 0; i < int(_proc_nodes.size()); ++i)
+ _pi[_proc_nodes[i]] = _dist[_proc_nodes[i]] - t_dist;
+ return true;
+ }
+
+ // Execute the algorithm.
+ bool start() {
+ HeapCrossRef heap_cross_ref(_graph, Heap::PRE_HEAP);
+ Heap heap(heap_cross_ref);
+ heap.push(_s, 0);
+ _pred[_s] = INVALID;
+ _proc_nodes.clear();
+
+ // Process nodes
+ while (!heap.empty() && heap.top() != _t) {
+ Node u = heap.top(), v;
+ Length d = heap.prio() + _pi[u], dn;
+ _dist[u] = heap.prio();
+ _proc_nodes.push_back(u);
+ heap.pop();
+
+ // Traverse outgoing arcs
+ for (OutArcIt e(_graph, u); e != INVALID; ++e) {
+ if (_flow[e] == 0) {
+ v = _graph.target(e);
+ switch(heap.state(v)) {
+ case Heap::PRE_HEAP:
+ heap.push(v, d + _length[e] - _pi[v]);
+ _pred[v] = e;
+ break;
+ case Heap::IN_HEAP:
+ dn = d + _length[e] - _pi[v];
+ if (dn < heap[v]) {
+ heap.decrease(v, dn);
+ _pred[v] = e;
+ }
+ break;
+ case Heap::POST_HEAP:
+ break;
+ }
+ }
+ }
+
+ // Traverse incoming arcs
+ for (InArcIt e(_graph, u); e != INVALID; ++e) {
+ if (_flow[e] == 1) {
+ v = _graph.source(e);
+ switch(heap.state(v)) {
+ case Heap::PRE_HEAP:
+ heap.push(v, d - _length[e] - _pi[v]);
+ _pred[v] = e;
+ break;
+ case Heap::IN_HEAP:
+ dn = d - _length[e] - _pi[v];
+ if (dn < heap[v]) {
+ heap.decrease(v, dn);
+ _pred[v] = e;
+ }
+ break;
+ case Heap::POST_HEAP:
+ break;
+ }
+ }
+ }
+ }
+ if (heap.empty()) return false;
+
+ // Update potentials of processed nodes
+ Length t_dist = heap.prio();
+ for (int i = 0; i < int(_proc_nodes.size()); ++i)
+ _pi[_proc_nodes[i]] += _dist[_proc_nodes[i]] - t_dist;
+ return true;
+ }
+
+ }; //class ResidualDijkstra
+
+ public:
+
+ /// \name Named Template Parameters
+ /// @{
+
+ template <typename T>
+ struct SetFlowMapTraits : public Traits {
+ typedef T FlowMap;
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// \c FlowMap type.
+ ///
+ /// \ref named-templ-param "Named parameter" for setting
+ /// \c FlowMap type.
+ template <typename T>
+ struct SetFlowMap
+ : public Suurballe<GR, LEN, SetFlowMapTraits<T> > {
+ typedef Suurballe<GR, LEN, SetFlowMapTraits<T> > Create;
+ };
+
+ template <typename T>
+ struct SetPotentialMapTraits : public Traits {
+ typedef T PotentialMap;
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// \c PotentialMap type.
+ ///
+ /// \ref named-templ-param "Named parameter" for setting
+ /// \c PotentialMap type.
+ template <typename T>
+ struct SetPotentialMap
+ : public Suurballe<GR, LEN, SetPotentialMapTraits<T> > {
+ typedef Suurballe<GR, LEN, SetPotentialMapTraits<T> > Create;
+ };
+
+ template <typename T>
+ struct SetPathTraits : public Traits {
+ typedef T Path;
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// \c %Path type.
+ ///
+ /// \ref named-templ-param "Named parameter" for setting \c %Path type.
+ /// It must conform to the \ref lemon::concepts::Path "Path" concept
+ /// and it must have an \c addBack() function.
+ template <typename T>
+ struct SetPath
+ : public Suurballe<GR, LEN, SetPathTraits<T> > {
+ typedef Suurballe<GR, LEN, SetPathTraits<T> > Create;
+ };
+
+ template <typename H, typename CR>
+ struct SetHeapTraits : public Traits {
+ typedef H Heap;
+ typedef CR HeapCrossRef;
+ };
+
+ /// \brief \ref named-templ-param "Named parameter" for setting
+ /// \c Heap and \c HeapCrossRef types.
+ ///
+ /// \ref named-templ-param "Named parameter" for setting \c Heap
+ /// and \c HeapCrossRef types with automatic allocation.
+ /// They will be used for internal Dijkstra computations.
+ /// The heap type must conform to the \ref lemon::concepts::Heap "Heap"
+ /// concept and its priority type must be \c Length.
+ template <typename H,
+ typename CR = typename Digraph::template NodeMap<int> >
+ struct SetHeap
+ : public Suurballe<GR, LEN, SetHeapTraits<H, CR> > {
+ typedef Suurballe<GR, LEN, SetHeapTraits<H, CR> > Create;
+ };
+
+ /// @}
+
+ private:
+
+ // The digraph the algorithm runs on
+ const Digraph &_graph;
+ // The length map
+ const LengthMap &_length;
+
+ // Arc map of the current flow
+ FlowMap *_flow;
+ bool _local_flow;
+ // Node map of the current potentials
+ PotentialMap *_potential;
+ bool _local_potential;
+
+ // The source node
+ Node _s;
+ // The target node
+ Node _t;
+
+ // Container to store the found paths
+ std::vector<Path> _paths;
+ int _path_num;
+
+ // The pred arc map
+ PredMap _pred;
+
+ // Data for full init
+ PotentialMap *_init_dist;
+ PredMap *_init_pred;
+ bool _full_init;
+
+ protected:
+
+ Suurballe() {}
+
+ public:
+
+ /// \brief Constructor.
+ ///
+ /// Constructor.
+ ///
+ /// \param graph The digraph the algorithm runs on.
+ /// \param length The length (cost) values of the arcs.
+ Suurballe( const Digraph &graph,
+ const LengthMap &length ) :
+ _graph(graph), _length(length), _flow(0), _local_flow(false),
+ _potential(0), _local_potential(false), _pred(graph),
+ _init_dist(0), _init_pred(0)
+ {}
+
+ /// Destructor.
+ ~Suurballe() {
+ if (_local_flow) delete _flow;
+ if (_local_potential) delete _potential;
+ delete _init_dist;
+ delete _init_pred;
+ }
+
+ /// \brief Set the flow map.
+ ///
+ /// This function sets the flow map.
+ /// If it is not used before calling \ref run() or \ref init(),
+ /// an instance will be allocated automatically. The destructor
+ /// deallocates this automatically allocated map, of course.
+ ///
+ /// The found flow contains only 0 and 1 values, since it is the
+ /// union of the found arc-disjoint paths.
+ ///
+ /// \return <tt>(*this)</tt>
+ Suurballe& flowMap(FlowMap &map) {
+ if (_local_flow) {
+ delete _flow;
+ _local_flow = false;
+ }
+ _flow = &map;
+ return *this;
+ }
+
+ /// \brief Set the potential map.
+ ///
+ /// This function sets the potential map.
+ /// If it is not used before calling \ref run() or \ref init(),
+ /// an instance will be allocated automatically. The destructor
+ /// deallocates this automatically allocated map, of course.
+ ///
+ /// The node potentials provide the dual solution of the underlying
+ /// \ref min_cost_flow "minimum cost flow problem".
+ ///
+ /// \return <tt>(*this)</tt>
+ Suurballe& potentialMap(PotentialMap &map) {
+ if (_local_potential) {
+ delete _potential;
+ _local_potential = false;
+ }
+ _potential = &map;
+ return *this;
+ }
+
+ /// \name Execution Control
+ /// The simplest way to execute the algorithm is to call the run()
+ /// function.\n
+ /// If you need to execute the algorithm many times using the same
+ /// source node, then you may call fullInit() once and start()
+ /// for each target node.\n
+ /// If you only need the flow that is the union of the found
+ /// arc-disjoint paths, then you may call findFlow() instead of
+ /// start().
+
+ /// @{
+
+ /// \brief Run the algorithm.
+ ///
+ /// This function runs the algorithm.
+ ///
+ /// \param s The source node.
+ /// \param t The target node.
+ /// \param k The number of paths to be found.
+ ///
+ /// \return \c k if there are at least \c k arc-disjoint paths from
+ /// \c s to \c t in the digraph. Otherwise it returns the number of
+ /// arc-disjoint paths found.
+ ///
+ /// \note Apart from the return value, <tt>s.run(s, t, k)</tt> is
+ /// just a shortcut of the following code.
+ /// \code
+ /// s.init(s);
+ /// s.start(t, k);
+ /// \endcode
+ int run(const Node& s, const Node& t, int k = 2) {
+ init(s);
+ start(t, k);
+ return _path_num;
+ }
+
+ /// \brief Initialize the algorithm.
+ ///
+ /// This function initializes the algorithm with the given source node.
+ ///
+ /// \param s The source node.
+ void init(const Node& s) {
+ _s = s;
+
+ // Initialize maps
+ if (!_flow) {
+ _flow = new FlowMap(_graph);
+ _local_flow = true;
+ }
+ if (!_potential) {
+ _potential = new PotentialMap(_graph);
+ _local_potential = true;
+ }
+ _full_init = false;
+ }
+
+ /// \brief Initialize the algorithm and perform Dijkstra.
+ ///
+ /// This function initializes the algorithm and performs a full
+ /// Dijkstra search from the given source node. It makes consecutive
+ /// executions of \ref start() "start(t, k)" faster, since they
+ /// have to perform %Dijkstra only k-1 times.
+ ///
+ /// This initialization is usually worth using instead of \ref init()
+ /// if the algorithm is executed many times using the same source node.
+ ///
+ /// \param s The source node.
+ void fullInit(const Node& s) {
+ // Initialize maps
+ init(s);
+ if (!_init_dist) {
+ _init_dist = new PotentialMap(_graph);
+ }
+ if (!_init_pred) {
+ _init_pred = new PredMap(_graph);
+ }
+
+ // Run a full Dijkstra
+ typename Dijkstra<Digraph, LengthMap>
+ ::template SetStandardHeap<Heap>
+ ::template SetDistMap<PotentialMap>
+ ::template SetPredMap<PredMap>
+ ::Create dijk(_graph, _length);
+ dijk.distMap(*_init_dist).predMap(*_init_pred);
+ dijk.run(s);
+
+ _full_init = true;
+ }
+
+ /// \brief Execute the algorithm.
+ ///
+ /// This function executes the algorithm.
+ ///
+ /// \param t The target node.
+ /// \param k The number of paths to be found.
+ ///
+ /// \return \c k if there are at least \c k arc-disjoint paths from
+ /// \c s to \c t in the digraph. Otherwise it returns the number of
+ /// arc-disjoint paths found.
+ ///
+ /// \note Apart from the return value, <tt>s.start(t, k)</tt> is
+ /// just a shortcut of the following code.
+ /// \code
+ /// s.findFlow(t, k);
+ /// s.findPaths();
+ /// \endcode
+ int start(const Node& t, int k = 2) {
+ findFlow(t, k);
+ findPaths();
+ return _path_num;
+ }
+
+ /// \brief Execute the algorithm to find an optimal flow.
+ ///
+ /// This function executes the successive shortest path algorithm to
+ /// find a minimum cost flow, which is the union of \c k (or less)
+ /// arc-disjoint paths.
+ ///
+ /// \param t The target node.
+ /// \param k The number of paths to be found.
+ ///
+ /// \return \c k if there are at least \c k arc-disjoint paths from
+ /// the source node to the given node \c t in the digraph.
+ /// Otherwise it returns the number of arc-disjoint paths found.
+ ///
+ /// \pre \ref init() must be called before using this function.
+ int findFlow(const Node& t, int k = 2) {
+ _t = t;
+ ResidualDijkstra dijkstra(*this);
+
+ // Initialization
+ for (ArcIt e(_graph); e != INVALID; ++e) {
+ (*_flow)[e] = 0;
+ }
+ if (_full_init) {
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ (*_potential)[n] = (*_init_dist)[n];
+ }
+ Node u = _t;
+ Arc e;
+ while ((e = (*_init_pred)[u]) != INVALID) {
+ (*_flow)[e] = 1;
+ u = _graph.source(e);
+ }
+ _path_num = 1;
+ } else {
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ (*_potential)[n] = 0;
+ }
+ _path_num = 0;
+ }
+
+ // Find shortest paths
+ while (_path_num < k) {
+ // Run Dijkstra
+ if (!dijkstra.run(_path_num)) break;
+ ++_path_num;
+
+ // Set the flow along the found shortest path
+ Node u = _t;
+ Arc e;
+ while ((e = _pred[u]) != INVALID) {
+ if (u == _graph.target(e)) {
+ (*_flow)[e] = 1;
+ u = _graph.source(e);
+ } else {
+ (*_flow)[e] = 0;
+ u = _graph.target(e);
+ }
+ }
+ }
+ return _path_num;
+ }
+
+ /// \brief Compute the paths from the flow.
+ ///
+ /// This function computes arc-disjoint paths from the found minimum
+ /// cost flow, which is the union of them.
+ ///
+ /// \pre \ref init() and \ref findFlow() must be called before using
+ /// this function.
+ void findPaths() {
+ FlowMap res_flow(_graph);
+ for(ArcIt a(_graph); a != INVALID; ++a) res_flow[a] = (*_flow)[a];
+
+ _paths.clear();
+ _paths.resize(_path_num);
+ for (int i = 0; i < _path_num; ++i) {
+ Node n = _s;
+ while (n != _t) {
+ OutArcIt e(_graph, n);
+ for ( ; res_flow[e] == 0; ++e) ;
+ n = _graph.target(e);
+ _paths[i].addBack(e);
+ res_flow[e] = 0;
+ }
+ }
+ }
+
+ /// @}
+
+ /// \name Query Functions
+ /// The results of the algorithm can be obtained using these
+ /// functions.
+ /// \n The algorithm should be executed before using them.
+
+ /// @{
+
+ /// \brief Return the total length of the found paths.
+ ///
+ /// This function returns the total length of the found paths, i.e.
+ /// the total cost of the found flow.
+ /// The complexity of the function is O(m).
+ ///
+ /// \pre \ref run() or \ref findFlow() must be called before using
+ /// this function.
+ Length totalLength() const {
+ Length c = 0;
+ for (ArcIt e(_graph); e != INVALID; ++e)
+ c += (*_flow)[e] * _length[e];
+ return c;
+ }
+
+ /// \brief Return the flow value on the given arc.
+ ///
+ /// This function returns the flow value on the given arc.
+ /// It is \c 1 if the arc is involved in one of the found arc-disjoint
+ /// paths, otherwise it is \c 0.
+ ///
+ /// \pre \ref run() or \ref findFlow() must be called before using
+ /// this function.
+ int flow(const Arc& arc) const {
+ return (*_flow)[arc];
+ }
+
+ /// \brief Return a const reference to an arc map storing the
+ /// found flow.
+ ///
+ /// This function returns a const reference to an arc map storing
+ /// the flow that is the union of the found arc-disjoint paths.
+ ///
+ /// \pre \ref run() or \ref findFlow() must be called before using
+ /// this function.
+ const FlowMap& flowMap() const {
+ return *_flow;
+ }
+
+ /// \brief Return the potential of the given node.
+ ///
+ /// This function returns the potential of the given node.
+ /// The node potentials provide the dual solution of the
+ /// underlying \ref min_cost_flow "minimum cost flow problem".
+ ///
+ /// \pre \ref run() or \ref findFlow() must be called before using
+ /// this function.
+ Length potential(const Node& node) const {
+ return (*_potential)[node];
+ }
+
+ /// \brief Return a const reference to a node map storing the
+ /// found potentials (the dual solution).
+ ///
+ /// This function returns a const reference to a node map storing
+ /// the found potentials that provide the dual solution of the
+ /// underlying \ref min_cost_flow "minimum cost flow problem".
+ ///
+ /// \pre \ref run() or \ref findFlow() must be called before using
+ /// this function.
+ const PotentialMap& potentialMap() const {
+ return *_potential;
+ }
+
+ /// \brief Return the number of the found paths.
+ ///
+ /// This function returns the number of the found paths.
+ ///
+ /// \pre \ref run() or \ref findFlow() must be called before using
+ /// this function.
+ int pathNum() const {
+ return _path_num;
+ }
+
+ /// \brief Return a const reference to the specified path.
+ ///
+ /// This function returns a const reference to the specified path.
+ ///
+ /// \param i The function returns the <tt>i</tt>-th path.
+ /// \c i must be between \c 0 and <tt>%pathNum()-1</tt>.
+ ///
+ /// \pre \ref run() or \ref findPaths() must be called before using
+ /// this function.
+ const Path& path(int i) const {
+ return _paths[i];
+ }
+
+ /// @}
+
+ }; //class Suurballe
+
+ ///@}
+
+} //namespace lemon
+
+#endif //LEMON_SUURBALLE_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/time_measure.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/time_measure.h
new file mode 100644
index 00000000000..3f7f0778999
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/time_measure.h
@@ -0,0 +1,610 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_TIME_MEASURE_H
+#define LEMON_TIME_MEASURE_H
+
+///\ingroup timecount
+///\file
+///\brief Tools for measuring cpu usage
+
+#ifdef WIN32
+#include <lemon/bits/windows.h>
+#else
+#include <unistd.h>
+#include <sys/times.h>
+#include <sys/time.h>
+#endif
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <lemon/math.h>
+
+namespace lemon {
+
+ /// \addtogroup timecount
+ /// @{
+
+ /// A class to store (cpu)time instances.
+
+ /// This class stores five time values.
+ /// - a real time
+ /// - a user cpu time
+ /// - a system cpu time
+ /// - a user cpu time of children
+ /// - a system cpu time of children
+ ///
+ /// TimeStamp's can be added to or substracted from each other and
+ /// they can be pushed to a stream.
+ ///
+ /// In most cases, perhaps the \ref Timer or the \ref TimeReport
+ /// class is what you want to use instead.
+
+ class TimeStamp
+ {
+ double utime;
+ double stime;
+ double cutime;
+ double cstime;
+ double rtime;
+
+ public:
+ ///Display format specifier
+
+ ///\e
+ ///
+ enum Format {
+ /// Reports all measured values
+ NORMAL = 0,
+ /// Only real time and an error indicator is displayed
+ SHORT = 1
+ };
+
+ private:
+ static Format _format;
+
+ void _reset() {
+ utime = stime = cutime = cstime = rtime = 0;
+ }
+
+ public:
+
+ ///Set output format
+
+ ///Set output format.
+ ///
+ ///The output format is global for all timestamp instances.
+ static void format(Format f) { _format = f; }
+ ///Retrieve the current output format
+
+ ///Retrieve the current output format
+ ///
+ ///The output format is global for all timestamp instances.
+ static Format format() { return _format; }
+
+
+ ///Read the current time values of the process
+ void stamp()
+ {
+#ifndef WIN32
+ timeval tv;
+ gettimeofday(&tv, 0);
+ rtime=tv.tv_sec+double(tv.tv_usec)/1e6;
+
+ tms ts;
+ double tck=sysconf(_SC_CLK_TCK);
+ times(&ts);
+ utime=ts.tms_utime/tck;
+ stime=ts.tms_stime/tck;
+ cutime=ts.tms_cutime/tck;
+ cstime=ts.tms_cstime/tck;
+#else
+ bits::getWinProcTimes(rtime, utime, stime, cutime, cstime);
+#endif
+ }
+
+ /// Constructor initializing with zero
+ TimeStamp()
+ { _reset(); }
+ ///Constructor initializing with the current time values of the process
+ TimeStamp(void *) { stamp();}
+
+ ///Set every time value to zero
+ TimeStamp &reset() {_reset();return *this;}
+
+ ///\e
+ TimeStamp &operator+=(const TimeStamp &b)
+ {
+ utime+=b.utime;
+ stime+=b.stime;
+ cutime+=b.cutime;
+ cstime+=b.cstime;
+ rtime+=b.rtime;
+ return *this;
+ }
+ ///\e
+ TimeStamp operator+(const TimeStamp &b) const
+ {
+ TimeStamp t(*this);
+ return t+=b;
+ }
+ ///\e
+ TimeStamp &operator-=(const TimeStamp &b)
+ {
+ utime-=b.utime;
+ stime-=b.stime;
+ cutime-=b.cutime;
+ cstime-=b.cstime;
+ rtime-=b.rtime;
+ return *this;
+ }
+ ///\e
+ TimeStamp operator-(const TimeStamp &b) const
+ {
+ TimeStamp t(*this);
+ return t-=b;
+ }
+ ///\e
+ TimeStamp &operator*=(double b)
+ {
+ utime*=b;
+ stime*=b;
+ cutime*=b;
+ cstime*=b;
+ rtime*=b;
+ return *this;
+ }
+ ///\e
+ TimeStamp operator*(double b) const
+ {
+ TimeStamp t(*this);
+ return t*=b;
+ }
+ friend TimeStamp operator*(double b,const TimeStamp &t);
+ ///\e
+ TimeStamp &operator/=(double b)
+ {
+ utime/=b;
+ stime/=b;
+ cutime/=b;
+ cstime/=b;
+ rtime/=b;
+ return *this;
+ }
+ ///\e
+ TimeStamp operator/(double b) const
+ {
+ TimeStamp t(*this);
+ return t/=b;
+ }
+ ///The time ellapsed since the last call of stamp()
+ TimeStamp ellapsed() const
+ {
+ TimeStamp t(NULL);
+ return t-*this;
+ }
+
+ friend std::ostream& operator<<(std::ostream& os,const TimeStamp &t);
+
+ ///Gives back the user time of the process
+ double userTime() const
+ {
+ return utime;
+ }
+ ///Gives back the system time of the process
+ double systemTime() const
+ {
+ return stime;
+ }
+ ///Gives back the user time of the process' children
+
+ ///\note On <tt>WIN32</tt> platform this value is not calculated.
+ ///
+ double cUserTime() const
+ {
+ return cutime;
+ }
+ ///Gives back the user time of the process' children
+
+ ///\note On <tt>WIN32</tt> platform this value is not calculated.
+ ///
+ double cSystemTime() const
+ {
+ return cstime;
+ }
+ ///Gives back the real time
+ double realTime() const {return rtime;}
+ };
+
+ inline TimeStamp operator*(double b,const TimeStamp &t)
+ {
+ return t*b;
+ }
+
+ ///Prints the time counters
+
+ ///Prints the time counters in the following form:
+ ///
+ /// <tt>u: XX.XXs s: XX.XXs cu: XX.XXs cs: XX.XXs real: XX.XXs</tt>
+ ///
+ /// where the values are the
+ /// \li \c u: user cpu time,
+ /// \li \c s: system cpu time,
+ /// \li \c cu: user cpu time of children,
+ /// \li \c cs: system cpu time of children,
+ /// \li \c real: real time.
+ /// \relates TimeStamp
+ /// \note On <tt>WIN32</tt> platform the cummulative values are not
+ /// calculated.
+ inline std::ostream& operator<<(std::ostream& os,const TimeStamp &t)
+ {
+ switch(t._format)
+ {
+ case TimeStamp::NORMAL:
+ os << "u: " << t.userTime() <<
+ "s, s: " << t.systemTime() <<
+ "s, cu: " << t.cUserTime() <<
+ "s, cs: " << t.cSystemTime() <<
+ "s, real: " << t.realTime() << "s";
+ break;
+ case TimeStamp::SHORT:
+ double total = t.userTime()+t.systemTime()+
+ t.cUserTime()+t.cSystemTime();
+ os << t.realTime()
+ << "s (err: " << round((t.realTime()-total)/
+ t.realTime()*10000)/100
+ << "%)";
+ break;
+ }
+ return os;
+ }
+
+ ///Class for measuring the cpu time and real time usage of the process
+
+ ///Class for measuring the cpu time and real time usage of the process.
+ ///It is quite easy-to-use, here is a short example.
+ ///\code
+ /// #include<lemon/time_measure.h>
+ /// #include<iostream>
+ ///
+ /// int main()
+ /// {
+ ///
+ /// ...
+ ///
+ /// Timer t;
+ /// doSomething();
+ /// std::cout << t << '\n';
+ /// t.restart();
+ /// doSomethingElse();
+ /// std::cout << t << '\n';
+ ///
+ /// ...
+ ///
+ /// }
+ ///\endcode
+ ///
+ ///The \ref Timer can also be \ref stop() "stopped" and
+ ///\ref start() "started" again, so it is possible to compute collected
+ ///running times.
+ ///
+ ///\warning Depending on the operation system and its actual configuration
+ ///the time counters have a certain (10ms on a typical Linux system)
+ ///granularity.
+ ///Therefore this tool is not appropriate to measure very short times.
+ ///Also, if you start and stop the timer very frequently, it could lead to
+ ///distorted results.
+ ///
+ ///\note If you want to measure the running time of the execution of a certain
+ ///function, consider the usage of \ref TimeReport instead.
+ ///
+ ///\sa TimeReport
+ class Timer
+ {
+ int _running; //Timer is running iff _running>0; (_running>=0 always holds)
+ TimeStamp start_time; //This is the relativ start-time if the timer
+ //is _running, the collected _running time otherwise.
+
+ void _reset() {if(_running) start_time.stamp(); else start_time.reset();}
+
+ public:
+ ///Constructor.
+
+ ///\param run indicates whether or not the timer starts immediately.
+ ///
+ Timer(bool run=true) :_running(run) {_reset();}
+
+ ///\name Control the State of the Timer
+ ///Basically a Timer can be either running or stopped,
+ ///but it provides a bit finer control on the execution.
+ ///The \ref lemon::Timer "Timer" also counts the number of
+ ///\ref lemon::Timer::start() "start()" executions, and it stops
+ ///only after the same amount (or more) \ref lemon::Timer::stop()
+ ///"stop()"s. This can be useful e.g. to compute the running time
+ ///of recursive functions.
+
+ ///@{
+
+ ///Reset and stop the time counters
+
+ ///This function resets and stops the time counters
+ ///\sa restart()
+ void reset()
+ {
+ _running=0;
+ _reset();
+ }
+
+ ///Start the time counters
+
+ ///This function starts the time counters.
+ ///
+ ///If the timer is started more than ones, it will remain running
+ ///until the same amount of \ref stop() is called.
+ ///\sa stop()
+ void start()
+ {
+ if(_running) _running++;
+ else {
+ _running=1;
+ TimeStamp t;
+ t.stamp();
+ start_time=t-start_time;
+ }
+ }
+
+
+ ///Stop the time counters
+
+ ///This function stops the time counters. If start() was executed more than
+ ///once, then the same number of stop() execution is necessary the really
+ ///stop the timer.
+ ///
+ ///\sa halt()
+ ///\sa start()
+ ///\sa restart()
+ ///\sa reset()
+
+ void stop()
+ {
+ if(_running && !--_running) {
+ TimeStamp t;
+ t.stamp();
+ start_time=t-start_time;
+ }
+ }
+
+ ///Halt (i.e stop immediately) the time counters
+
+ ///This function stops immediately the time counters, i.e. <tt>t.halt()</tt>
+ ///is a faster
+ ///equivalent of the following.
+ ///\code
+ /// while(t.running()) t.stop()
+ ///\endcode
+ ///
+ ///
+ ///\sa stop()
+ ///\sa restart()
+ ///\sa reset()
+
+ void halt()
+ {
+ if(_running) {
+ _running=0;
+ TimeStamp t;
+ t.stamp();
+ start_time=t-start_time;
+ }
+ }
+
+ ///Returns the running state of the timer
+
+ ///This function returns the number of stop() exections that is
+ ///necessary to really stop the timer.
+ ///For example, the timer
+ ///is running if and only if the return value is \c true
+ ///(i.e. greater than
+ ///zero).
+ int running() { return _running; }
+
+
+ ///Restart the time counters
+
+ ///This function is a shorthand for
+ ///a reset() and a start() calls.
+ ///
+ void restart()
+ {
+ reset();
+ start();
+ }
+
+ ///@}
+
+ ///\name Query Functions for the Ellapsed Time
+
+ ///@{
+
+ ///Gives back the ellapsed user time of the process
+ double userTime() const
+ {
+ return operator TimeStamp().userTime();
+ }
+ ///Gives back the ellapsed system time of the process
+ double systemTime() const
+ {
+ return operator TimeStamp().systemTime();
+ }
+ ///Gives back the ellapsed user time of the process' children
+
+ ///\note On <tt>WIN32</tt> platform this value is not calculated.
+ ///
+ double cUserTime() const
+ {
+ return operator TimeStamp().cUserTime();
+ }
+ ///Gives back the ellapsed user time of the process' children
+
+ ///\note On <tt>WIN32</tt> platform this value is not calculated.
+ ///
+ double cSystemTime() const
+ {
+ return operator TimeStamp().cSystemTime();
+ }
+ ///Gives back the ellapsed real time
+ double realTime() const
+ {
+ return operator TimeStamp().realTime();
+ }
+ ///Computes the ellapsed time
+
+ ///This conversion computes the ellapsed time, therefore you can print
+ ///the ellapsed time like this.
+ ///\code
+ /// Timer t;
+ /// doSomething();
+ /// std::cout << t << '\n';
+ ///\endcode
+ operator TimeStamp () const
+ {
+ TimeStamp t;
+ t.stamp();
+ return _running?t-start_time:start_time;
+ }
+
+
+ ///@}
+ };
+
+ ///Same as Timer but prints a report on destruction.
+
+ ///Same as \ref Timer but prints a report on destruction.
+ ///This example shows its usage.
+ ///\code
+ /// void myAlg(ListGraph &g,int n)
+ /// {
+ /// TimeReport tr("Running time of myAlg: ");
+ /// ... //Here comes the algorithm
+ /// }
+ ///\endcode
+ ///
+ ///\sa Timer
+ ///\sa NoTimeReport
+ class TimeReport : public Timer
+ {
+ std::string _title;
+ std::ostream &_os;
+ bool _active;
+ public:
+ ///Constructor
+
+ ///Constructor.
+ ///\param title This text will be printed before the ellapsed time.
+ ///\param os The stream to print the report to.
+ ///\param run Sets whether the timer should start immediately.
+ ///\param active Sets whether the report should actually be printed
+ /// on destruction.
+ TimeReport(std::string title,std::ostream &os=std::cerr,bool run=true,
+ bool active=true)
+ : Timer(run), _title(title), _os(os), _active(active) {}
+ ///Destructor that prints the ellapsed time
+ ~TimeReport()
+ {
+ if(_active) _os << _title << *this << std::endl;
+ }
+
+ ///Retrieve the activity status
+
+ ///\e
+ ///
+ bool active() const { return _active; }
+ ///Set the activity status
+
+ /// This function set whether the time report should actually be printed
+ /// on destruction.
+ void active(bool a) { _active=a; }
+ };
+
+ ///'Do nothing' version of TimeReport
+
+ ///\sa TimeReport
+ ///
+ class NoTimeReport
+ {
+ public:
+ ///\e
+ NoTimeReport(std::string,std::ostream &,bool) {}
+ ///\e
+ NoTimeReport(std::string,std::ostream &) {}
+ ///\e
+ NoTimeReport(std::string) {}
+ ///\e Do nothing.
+ ~NoTimeReport() {}
+
+ operator TimeStamp () const { return TimeStamp(); }
+ void reset() {}
+ void start() {}
+ void stop() {}
+ void halt() {}
+ int running() { return 0; }
+ void restart() {}
+ double userTime() const { return 0; }
+ double systemTime() const { return 0; }
+ double cUserTime() const { return 0; }
+ double cSystemTime() const { return 0; }
+ double realTime() const { return 0; }
+ };
+
+ ///Tool to measure the running time more exactly.
+
+ ///This function calls \c f several times and returns the average
+ ///running time. The number of the executions will be choosen in such a way
+ ///that the full real running time will be roughly between \c min_time
+ ///and <tt>2*min_time</tt>.
+ ///\param f the function object to be measured.
+ ///\param min_time the minimum total running time.
+ ///\retval num if it is not \c NULL, then the actual
+ /// number of execution of \c f will be written into <tt>*num</tt>.
+ ///\retval full_time if it is not \c NULL, then the actual
+ /// total running time will be written into <tt>*full_time</tt>.
+ ///\return The average running time of \c f.
+
+ template<class F>
+ TimeStamp runningTimeTest(F f,double min_time=10,unsigned int *num = NULL,
+ TimeStamp *full_time=NULL)
+ {
+ TimeStamp full;
+ unsigned int total=0;
+ Timer t;
+ for(unsigned int tn=1;tn <= 1U<<31 && full.realTime()<=min_time; tn*=2) {
+ for(;total<tn;total++) f();
+ full=t;
+ }
+ if(num) *num=total;
+ if(full_time) *full_time=full;
+ return full/total;
+ }
+
+ /// @}
+
+
+} //namespace lemon
+
+#endif //LEMON_TIME_MEASURE_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/tolerance.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/tolerance.h
new file mode 100644
index 00000000000..36a7512872e
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/tolerance.h
@@ -0,0 +1,242 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_TOLERANCE_H
+#define LEMON_TOLERANCE_H
+
+///\ingroup misc
+///\file
+///\brief A basic tool to handle the anomalies of calculation with
+///floating point numbers.
+///
+
+namespace lemon {
+
+ /// \addtogroup misc
+ /// @{
+
+ ///\brief A class to provide a basic way to
+ ///handle the comparison of numbers that are obtained
+ ///as a result of a probably inexact computation.
+ ///
+ ///\ref Tolerance is a class to provide a basic way to
+ ///handle the comparison of numbers that are obtained
+ ///as a result of a probably inexact computation.
+ ///
+ ///The general implementation is suitable only if the data type is exact,
+ ///like the integer types, otherwise a specialized version must be
+ ///implemented. These specialized classes like
+ ///Tolerance<double> may offer additional tuning parameters.
+ ///
+ ///\sa Tolerance<float>
+ ///\sa Tolerance<double>
+ ///\sa Tolerance<long double>
+
+ template<class T>
+ class Tolerance
+ {
+ public:
+ typedef T Value;
+
+ ///\name Comparisons
+ ///The concept is that these bool functions return \c true only if
+ ///the related comparisons hold even if some numerical error appeared
+ ///during the computations.
+
+ ///@{
+
+ ///Returns \c true if \c a is \e surely strictly less than \c b
+ static bool less(Value a,Value b) {return a<b;}
+ ///Returns \c true if \c a is \e surely different from \c b
+ static bool different(Value a,Value b) {return a!=b;}
+ ///Returns \c true if \c a is \e surely positive
+ static bool positive(Value a) {return static_cast<Value>(0) < a;}
+ ///Returns \c true if \c a is \e surely negative
+ static bool negative(Value a) {return a < static_cast<Value>(0);}
+ ///Returns \c true if \c a is \e surely non-zero
+ static bool nonZero(Value a) {return a != static_cast<Value>(0);}
+
+ ///@}
+
+ ///Returns the zero value.
+ static Value zero() {return static_cast<Value>(0);}
+
+ // static bool finite(Value a) {}
+ // static Value big() {}
+ // static Value negativeBig() {}
+ };
+
+
+ ///Float specialization of Tolerance.
+
+ ///Float specialization of Tolerance.
+ ///\sa Tolerance
+ ///\relates Tolerance
+ template<>
+ class Tolerance<float>
+ {
+ static float def_epsilon;
+ float _epsilon;
+ public:
+ ///\e
+ typedef float Value;
+
+ ///Constructor setting the epsilon tolerance to the default value.
+ Tolerance() : _epsilon(def_epsilon) {}
+ ///Constructor setting the epsilon tolerance to the given value.
+ Tolerance(float e) : _epsilon(e) {}
+
+ ///Returns the epsilon value.
+ Value epsilon() const {return _epsilon;}
+ ///Sets the epsilon value.
+ void epsilon(Value e) {_epsilon=e;}
+
+ ///Returns the default epsilon value.
+ static Value defaultEpsilon() {return def_epsilon;}
+ ///Sets the default epsilon value.
+ static void defaultEpsilon(Value e) {def_epsilon=e;}
+
+ ///\name Comparisons
+ ///See \ref lemon::Tolerance "Tolerance" for more details.
+
+ ///@{
+
+ ///Returns \c true if \c a is \e surely strictly less than \c b
+ bool less(Value a,Value b) const {return a+_epsilon<b;}
+ ///Returns \c true if \c a is \e surely different from \c b
+ bool different(Value a,Value b) const { return less(a,b)||less(b,a); }
+ ///Returns \c true if \c a is \e surely positive
+ bool positive(Value a) const { return _epsilon<a; }
+ ///Returns \c true if \c a is \e surely negative
+ bool negative(Value a) const { return -_epsilon>a; }
+ ///Returns \c true if \c a is \e surely non-zero
+ bool nonZero(Value a) const { return positive(a)||negative(a); }
+
+ ///@}
+
+ ///Returns zero
+ static Value zero() {return 0;}
+ };
+
+ ///Double specialization of Tolerance.
+
+ ///Double specialization of Tolerance.
+ ///\sa Tolerance
+ ///\relates Tolerance
+ template<>
+ class Tolerance<double>
+ {
+ static double def_epsilon;
+ double _epsilon;
+ public:
+ ///\e
+ typedef double Value;
+
+ ///Constructor setting the epsilon tolerance to the default value.
+ Tolerance() : _epsilon(def_epsilon) {}
+ ///Constructor setting the epsilon tolerance to the given value.
+ Tolerance(double e) : _epsilon(e) {}
+
+ ///Returns the epsilon value.
+ Value epsilon() const {return _epsilon;}
+ ///Sets the epsilon value.
+ void epsilon(Value e) {_epsilon=e;}
+
+ ///Returns the default epsilon value.
+ static Value defaultEpsilon() {return def_epsilon;}
+ ///Sets the default epsilon value.
+ static void defaultEpsilon(Value e) {def_epsilon=e;}
+
+ ///\name Comparisons
+ ///See \ref lemon::Tolerance "Tolerance" for more details.
+
+ ///@{
+
+ ///Returns \c true if \c a is \e surely strictly less than \c b
+ bool less(Value a,Value b) const {return a+_epsilon<b;}
+ ///Returns \c true if \c a is \e surely different from \c b
+ bool different(Value a,Value b) const { return less(a,b)||less(b,a); }
+ ///Returns \c true if \c a is \e surely positive
+ bool positive(Value a) const { return _epsilon<a; }
+ ///Returns \c true if \c a is \e surely negative
+ bool negative(Value a) const { return -_epsilon>a; }
+ ///Returns \c true if \c a is \e surely non-zero
+ bool nonZero(Value a) const { return positive(a)||negative(a); }
+
+ ///@}
+
+ ///Returns zero
+ static Value zero() {return 0;}
+ };
+
+ ///Long double specialization of Tolerance.
+
+ ///Long double specialization of Tolerance.
+ ///\sa Tolerance
+ ///\relates Tolerance
+ template<>
+ class Tolerance<long double>
+ {
+ static long double def_epsilon;
+ long double _epsilon;
+ public:
+ ///\e
+ typedef long double Value;
+
+ ///Constructor setting the epsilon tolerance to the default value.
+ Tolerance() : _epsilon(def_epsilon) {}
+ ///Constructor setting the epsilon tolerance to the given value.
+ Tolerance(long double e) : _epsilon(e) {}
+
+ ///Returns the epsilon value.
+ Value epsilon() const {return _epsilon;}
+ ///Sets the epsilon value.
+ void epsilon(Value e) {_epsilon=e;}
+
+ ///Returns the default epsilon value.
+ static Value defaultEpsilon() {return def_epsilon;}
+ ///Sets the default epsilon value.
+ static void defaultEpsilon(Value e) {def_epsilon=e;}
+
+ ///\name Comparisons
+ ///See \ref lemon::Tolerance "Tolerance" for more details.
+
+ ///@{
+
+ ///Returns \c true if \c a is \e surely strictly less than \c b
+ bool less(Value a,Value b) const {return a+_epsilon<b;}
+ ///Returns \c true if \c a is \e surely different from \c b
+ bool different(Value a,Value b) const { return less(a,b)||less(b,a); }
+ ///Returns \c true if \c a is \e surely positive
+ bool positive(Value a) const { return _epsilon<a; }
+ ///Returns \c true if \c a is \e surely negative
+ bool negative(Value a) const { return -_epsilon>a; }
+ ///Returns \c true if \c a is \e surely non-zero
+ bool nonZero(Value a) const { return positive(a)||negative(a); }
+
+ ///@}
+
+ ///Returns zero
+ static Value zero() {return 0;}
+ };
+
+ /// @}
+
+} //namespace lemon
+
+#endif //LEMON_TOLERANCE_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/unionfind.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/unionfind.h
new file mode 100644
index 00000000000..3d96b372b2d
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/unionfind.h
@@ -0,0 +1,1824 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_UNION_FIND_H
+#define LEMON_UNION_FIND_H
+
+//!\ingroup auxdat
+//!\file
+//!\brief Union-Find data structures.
+//!
+
+#include <vector>
+#include <list>
+#include <utility>
+#include <algorithm>
+#include <functional>
+
+#include <lemon/core.h>
+
+namespace lemon {
+
+ /// \ingroup auxdat
+ ///
+ /// \brief A \e Union-Find data structure implementation
+ ///
+ /// The class implements the \e Union-Find data structure.
+ /// The union operation uses rank heuristic, while
+ /// the find operation uses path compression.
+ /// This is a very simple but efficient implementation, providing
+ /// only four methods: join (union), find, insert and size.
+ /// For more features, see the \ref UnionFindEnum class.
+ ///
+ /// It is primarily used in Kruskal algorithm for finding minimal
+ /// cost spanning tree in a graph.
+ /// \sa kruskal()
+ ///
+ /// \pre You need to add all the elements by the \ref insert()
+ /// method.
+ template <typename IM>
+ class UnionFind {
+ public:
+
+ ///\e
+ typedef IM ItemIntMap;
+ ///\e
+ typedef typename ItemIntMap::Key Item;
+
+ private:
+ // If the items vector stores negative value for an item then
+ // that item is root item and it has -items[it] component size.
+ // Else the items[it] contains the index of the parent.
+ std::vector<int> items;
+ ItemIntMap& index;
+
+ bool rep(int idx) const {
+ return items[idx] < 0;
+ }
+
+ int repIndex(int idx) const {
+ int k = idx;
+ while (!rep(k)) {
+ k = items[k] ;
+ }
+ while (idx != k) {
+ int next = items[idx];
+ const_cast<int&>(items[idx]) = k;
+ idx = next;
+ }
+ return k;
+ }
+
+ public:
+
+ /// \brief Constructor
+ ///
+ /// Constructor of the UnionFind class. You should give an item to
+ /// integer map which will be used from the data structure. If you
+ /// modify directly this map that may cause segmentation fault,
+ /// invalid data structure, or infinite loop when you use again
+ /// the union-find.
+ UnionFind(ItemIntMap& m) : index(m) {}
+
+ /// \brief Returns the index of the element's component.
+ ///
+ /// The method returns the index of the element's component.
+ /// This is an integer between zero and the number of inserted elements.
+ ///
+ int find(const Item& a) {
+ return repIndex(index[a]);
+ }
+
+ /// \brief Clears the union-find data structure
+ ///
+ /// Erase each item from the data structure.
+ void clear() {
+ items.clear();
+ }
+
+ /// \brief Inserts a new element into the structure.
+ ///
+ /// This method inserts a new element into the data structure.
+ ///
+ /// The method returns the index of the new component.
+ int insert(const Item& a) {
+ int n = items.size();
+ items.push_back(-1);
+ index.set(a,n);
+ return n;
+ }
+
+ /// \brief Joining the components of element \e a and element \e b.
+ ///
+ /// This is the \e union operation of the Union-Find structure.
+ /// Joins the component of element \e a and component of
+ /// element \e b. If \e a and \e b are in the same component then
+ /// it returns false otherwise it returns true.
+ bool join(const Item& a, const Item& b) {
+ int ka = repIndex(index[a]);
+ int kb = repIndex(index[b]);
+
+ if ( ka == kb )
+ return false;
+
+ if (items[ka] < items[kb]) {
+ items[ka] += items[kb];
+ items[kb] = ka;
+ } else {
+ items[kb] += items[ka];
+ items[ka] = kb;
+ }
+ return true;
+ }
+
+ /// \brief Returns the size of the component of element \e a.
+ ///
+ /// Returns the size of the component of element \e a.
+ int size(const Item& a) {
+ int k = repIndex(index[a]);
+ return - items[k];
+ }
+
+ };
+
+ /// \ingroup auxdat
+ ///
+ /// \brief A \e Union-Find data structure implementation which
+ /// is able to enumerate the components.
+ ///
+ /// The class implements a \e Union-Find data structure
+ /// which is able to enumerate the components and the items in
+ /// a component. If you don't need this feature then perhaps it's
+ /// better to use the \ref UnionFind class which is more efficient.
+ ///
+ /// The union operation uses rank heuristic, while
+ /// the find operation uses path compression.
+ ///
+ /// \pre You need to add all the elements by the \ref insert()
+ /// method.
+ ///
+ template <typename IM>
+ class UnionFindEnum {
+ public:
+
+ ///\e
+ typedef IM ItemIntMap;
+ ///\e
+ typedef typename ItemIntMap::Key Item;
+
+ private:
+
+ ItemIntMap& index;
+
+ // If the parent stores negative value for an item then that item
+ // is root item and it has ~(items[it].parent) component id. Else
+ // the items[it].parent contains the index of the parent.
+ //
+ // The \c next and \c prev provides the double-linked
+ // cyclic list of one component's items.
+ struct ItemT {
+ int parent;
+ Item item;
+
+ int next, prev;
+ };
+
+ std::vector<ItemT> items;
+ int firstFreeItem;
+
+ struct ClassT {
+ int size;
+ int firstItem;
+ int next, prev;
+ };
+
+ std::vector<ClassT> classes;
+ int firstClass, firstFreeClass;
+
+ int newClass() {
+ if (firstFreeClass == -1) {
+ int cdx = classes.size();
+ classes.push_back(ClassT());
+ return cdx;
+ } else {
+ int cdx = firstFreeClass;
+ firstFreeClass = classes[firstFreeClass].next;
+ return cdx;
+ }
+ }
+
+ int newItem() {
+ if (firstFreeItem == -1) {
+ int idx = items.size();
+ items.push_back(ItemT());
+ return idx;
+ } else {
+ int idx = firstFreeItem;
+ firstFreeItem = items[firstFreeItem].next;
+ return idx;
+ }
+ }
+
+
+ bool rep(int idx) const {
+ return items[idx].parent < 0;
+ }
+
+ int repIndex(int idx) const {
+ int k = idx;
+ while (!rep(k)) {
+ k = items[k].parent;
+ }
+ while (idx != k) {
+ int next = items[idx].parent;
+ const_cast<int&>(items[idx].parent) = k;
+ idx = next;
+ }
+ return k;
+ }
+
+ int classIndex(int idx) const {
+ return ~(items[repIndex(idx)].parent);
+ }
+
+ void singletonItem(int idx) {
+ items[idx].next = idx;
+ items[idx].prev = idx;
+ }
+
+ void laceItem(int idx, int rdx) {
+ items[idx].prev = rdx;
+ items[idx].next = items[rdx].next;
+ items[items[rdx].next].prev = idx;
+ items[rdx].next = idx;
+ }
+
+ void unlaceItem(int idx) {
+ items[items[idx].prev].next = items[idx].next;
+ items[items[idx].next].prev = items[idx].prev;
+
+ items[idx].next = firstFreeItem;
+ firstFreeItem = idx;
+ }
+
+ void spliceItems(int ak, int bk) {
+ items[items[ak].prev].next = bk;
+ items[items[bk].prev].next = ak;
+ int tmp = items[ak].prev;
+ items[ak].prev = items[bk].prev;
+ items[bk].prev = tmp;
+
+ }
+
+ void laceClass(int cls) {
+ if (firstClass != -1) {
+ classes[firstClass].prev = cls;
+ }
+ classes[cls].next = firstClass;
+ classes[cls].prev = -1;
+ firstClass = cls;
+ }
+
+ void unlaceClass(int cls) {
+ if (classes[cls].prev != -1) {
+ classes[classes[cls].prev].next = classes[cls].next;
+ } else {
+ firstClass = classes[cls].next;
+ }
+ if (classes[cls].next != -1) {
+ classes[classes[cls].next].prev = classes[cls].prev;
+ }
+
+ classes[cls].next = firstFreeClass;
+ firstFreeClass = cls;
+ }
+
+ public:
+
+ UnionFindEnum(ItemIntMap& _index)
+ : index(_index), items(), firstFreeItem(-1),
+ firstClass(-1), firstFreeClass(-1) {}
+
+ /// \brief Inserts the given element into a new component.
+ ///
+ /// This method creates a new component consisting only of the
+ /// given element.
+ ///
+ int insert(const Item& item) {
+ int idx = newItem();
+
+ index.set(item, idx);
+
+ singletonItem(idx);
+ items[idx].item = item;
+
+ int cdx = newClass();
+
+ items[idx].parent = ~cdx;
+
+ laceClass(cdx);
+ classes[cdx].size = 1;
+ classes[cdx].firstItem = idx;
+
+ firstClass = cdx;
+
+ return cdx;
+ }
+
+ /// \brief Inserts the given element into the component of the others.
+ ///
+ /// This methods inserts the element \e a into the component of the
+ /// element \e comp.
+ void insert(const Item& item, int cls) {
+ int rdx = classes[cls].firstItem;
+ int idx = newItem();
+
+ index.set(item, idx);
+
+ laceItem(idx, rdx);
+
+ items[idx].item = item;
+ items[idx].parent = rdx;
+
+ ++classes[~(items[rdx].parent)].size;
+ }
+
+ /// \brief Clears the union-find data structure
+ ///
+ /// Erase each item from the data structure.
+ void clear() {
+ items.clear();
+ firstClass = -1;
+ firstFreeItem = -1;
+ }
+
+ /// \brief Finds the component of the given element.
+ ///
+ /// The method returns the component id of the given element.
+ int find(const Item &item) const {
+ return ~(items[repIndex(index[item])].parent);
+ }
+
+ /// \brief Joining the component of element \e a and element \e b.
+ ///
+ /// This is the \e union operation of the Union-Find structure.
+ /// Joins the component of element \e a and component of
+ /// element \e b. If \e a and \e b are in the same component then
+ /// returns -1 else returns the remaining class.
+ int join(const Item& a, const Item& b) {
+
+ int ak = repIndex(index[a]);
+ int bk = repIndex(index[b]);
+
+ if (ak == bk) {
+ return -1;
+ }
+
+ int acx = ~(items[ak].parent);
+ int bcx = ~(items[bk].parent);
+
+ int rcx;
+
+ if (classes[acx].size > classes[bcx].size) {
+ classes[acx].size += classes[bcx].size;
+ items[bk].parent = ak;
+ unlaceClass(bcx);
+ rcx = acx;
+ } else {
+ classes[bcx].size += classes[acx].size;
+ items[ak].parent = bk;
+ unlaceClass(acx);
+ rcx = bcx;
+ }
+ spliceItems(ak, bk);
+
+ return rcx;
+ }
+
+ /// \brief Returns the size of the class.
+ ///
+ /// Returns the size of the class.
+ int size(int cls) const {
+ return classes[cls].size;
+ }
+
+ /// \brief Splits up the component.
+ ///
+ /// Splitting the component into singleton components (component
+ /// of size one).
+ void split(int cls) {
+ int fdx = classes[cls].firstItem;
+ int idx = items[fdx].next;
+ while (idx != fdx) {
+ int next = items[idx].next;
+
+ singletonItem(idx);
+
+ int cdx = newClass();
+ items[idx].parent = ~cdx;
+
+ laceClass(cdx);
+ classes[cdx].size = 1;
+ classes[cdx].firstItem = idx;
+
+ idx = next;
+ }
+
+ items[idx].prev = idx;
+ items[idx].next = idx;
+
+ classes[~(items[idx].parent)].size = 1;
+
+ }
+
+ /// \brief Removes the given element from the structure.
+ ///
+ /// Removes the element from its component and if the component becomes
+ /// empty then removes that component from the component list.
+ ///
+ /// \warning It is an error to remove an element which is not in
+ /// the structure.
+ /// \warning This running time of this operation is proportional to the
+ /// number of the items in this class.
+ void erase(const Item& item) {
+ int idx = index[item];
+ int fdx = items[idx].next;
+
+ int cdx = classIndex(idx);
+ if (idx == fdx) {
+ unlaceClass(cdx);
+ items[idx].next = firstFreeItem;
+ firstFreeItem = idx;
+ return;
+ } else {
+ classes[cdx].firstItem = fdx;
+ --classes[cdx].size;
+ items[fdx].parent = ~cdx;
+
+ unlaceItem(idx);
+ idx = items[fdx].next;
+ while (idx != fdx) {
+ items[idx].parent = fdx;
+ idx = items[idx].next;
+ }
+
+ }
+
+ }
+
+ /// \brief Gives back a representant item of the component.
+ ///
+ /// Gives back a representant item of the component.
+ Item item(int cls) const {
+ return items[classes[cls].firstItem].item;
+ }
+
+ /// \brief Removes the component of the given element from the structure.
+ ///
+ /// Removes the component of the given element from the structure.
+ ///
+ /// \warning It is an error to give an element which is not in the
+ /// structure.
+ void eraseClass(int cls) {
+ int fdx = classes[cls].firstItem;
+ unlaceClass(cls);
+ items[items[fdx].prev].next = firstFreeItem;
+ firstFreeItem = fdx;
+ }
+
+ /// \brief LEMON style iterator for the representant items.
+ ///
+ /// ClassIt is a lemon style iterator for the components. It iterates
+ /// on the ids of the classes.
+ class ClassIt {
+ public:
+ /// \brief Constructor of the iterator
+ ///
+ /// Constructor of the iterator
+ ClassIt(const UnionFindEnum& ufe) : unionFind(&ufe) {
+ cdx = unionFind->firstClass;
+ }
+
+ /// \brief Constructor to get invalid iterator
+ ///
+ /// Constructor to get invalid iterator
+ ClassIt(Invalid) : unionFind(0), cdx(-1) {}
+
+ /// \brief Increment operator
+ ///
+ /// It steps to the next representant item.
+ ClassIt& operator++() {
+ cdx = unionFind->classes[cdx].next;
+ return *this;
+ }
+
+ /// \brief Conversion operator
+ ///
+ /// It converts the iterator to the current representant item.
+ operator int() const {
+ return cdx;
+ }
+
+ /// \brief Equality operator
+ ///
+ /// Equality operator
+ bool operator==(const ClassIt& i) {
+ return i.cdx == cdx;
+ }
+
+ /// \brief Inequality operator
+ ///
+ /// Inequality operator
+ bool operator!=(const ClassIt& i) {
+ return i.cdx != cdx;
+ }
+
+ private:
+ const UnionFindEnum* unionFind;
+ int cdx;
+ };
+
+ /// \brief LEMON style iterator for the items of a component.
+ ///
+ /// ClassIt is a lemon style iterator for the components. It iterates
+ /// on the items of a class. By example if you want to iterate on
+ /// each items of each classes then you may write the next code.
+ ///\code
+ /// for (ClassIt cit(ufe); cit != INVALID; ++cit) {
+ /// std::cout << "Class: ";
+ /// for (ItemIt iit(ufe, cit); iit != INVALID; ++iit) {
+ /// std::cout << toString(iit) << ' ' << std::endl;
+ /// }
+ /// std::cout << std::endl;
+ /// }
+ ///\endcode
+ class ItemIt {
+ public:
+ /// \brief Constructor of the iterator
+ ///
+ /// Constructor of the iterator. The iterator iterates
+ /// on the class of the \c item.
+ ItemIt(const UnionFindEnum& ufe, int cls) : unionFind(&ufe) {
+ fdx = idx = unionFind->classes[cls].firstItem;
+ }
+
+ /// \brief Constructor to get invalid iterator
+ ///
+ /// Constructor to get invalid iterator
+ ItemIt(Invalid) : unionFind(0), idx(-1) {}
+
+ /// \brief Increment operator
+ ///
+ /// It steps to the next item in the class.
+ ItemIt& operator++() {
+ idx = unionFind->items[idx].next;
+ if (idx == fdx) idx = -1;
+ return *this;
+ }
+
+ /// \brief Conversion operator
+ ///
+ /// It converts the iterator to the current item.
+ operator const Item&() const {
+ return unionFind->items[idx].item;
+ }
+
+ /// \brief Equality operator
+ ///
+ /// Equality operator
+ bool operator==(const ItemIt& i) {
+ return i.idx == idx;
+ }
+
+ /// \brief Inequality operator
+ ///
+ /// Inequality operator
+ bool operator!=(const ItemIt& i) {
+ return i.idx != idx;
+ }
+
+ private:
+ const UnionFindEnum* unionFind;
+ int idx, fdx;
+ };
+
+ };
+
+ /// \ingroup auxdat
+ ///
+ /// \brief A \e Extend-Find data structure implementation which
+ /// is able to enumerate the components.
+ ///
+ /// The class implements an \e Extend-Find data structure which is
+ /// able to enumerate the components and the items in a
+ /// component. The data structure is a simplification of the
+ /// Union-Find structure, and it does not allow to merge two components.
+ ///
+ /// \pre You need to add all the elements by the \ref insert()
+ /// method.
+ template <typename IM>
+ class ExtendFindEnum {
+ public:
+
+ ///\e
+ typedef IM ItemIntMap;
+ ///\e
+ typedef typename ItemIntMap::Key Item;
+
+ private:
+
+ ItemIntMap& index;
+
+ struct ItemT {
+ int cls;
+ Item item;
+ int next, prev;
+ };
+
+ std::vector<ItemT> items;
+ int firstFreeItem;
+
+ struct ClassT {
+ int firstItem;
+ int next, prev;
+ };
+
+ std::vector<ClassT> classes;
+
+ int firstClass, firstFreeClass;
+
+ int newClass() {
+ if (firstFreeClass != -1) {
+ int cdx = firstFreeClass;
+ firstFreeClass = classes[cdx].next;
+ return cdx;
+ } else {
+ classes.push_back(ClassT());
+ return classes.size() - 1;
+ }
+ }
+
+ int newItem() {
+ if (firstFreeItem != -1) {
+ int idx = firstFreeItem;
+ firstFreeItem = items[idx].next;
+ return idx;
+ } else {
+ items.push_back(ItemT());
+ return items.size() - 1;
+ }
+ }
+
+ public:
+
+ /// \brief Constructor
+ ExtendFindEnum(ItemIntMap& _index)
+ : index(_index), items(), firstFreeItem(-1),
+ classes(), firstClass(-1), firstFreeClass(-1) {}
+
+ /// \brief Inserts the given element into a new component.
+ ///
+ /// This method creates a new component consisting only of the
+ /// given element.
+ int insert(const Item& item) {
+ int cdx = newClass();
+ classes[cdx].prev = -1;
+ classes[cdx].next = firstClass;
+ if (firstClass != -1) {
+ classes[firstClass].prev = cdx;
+ }
+ firstClass = cdx;
+
+ int idx = newItem();
+ items[idx].item = item;
+ items[idx].cls = cdx;
+ items[idx].prev = idx;
+ items[idx].next = idx;
+
+ classes[cdx].firstItem = idx;
+
+ index.set(item, idx);
+
+ return cdx;
+ }
+
+ /// \brief Inserts the given element into the given component.
+ ///
+ /// This methods inserts the element \e item a into the \e cls class.
+ void insert(const Item& item, int cls) {
+ int idx = newItem();
+ int rdx = classes[cls].firstItem;
+ items[idx].item = item;
+ items[idx].cls = cls;
+
+ items[idx].prev = rdx;
+ items[idx].next = items[rdx].next;
+ items[items[rdx].next].prev = idx;
+ items[rdx].next = idx;
+
+ index.set(item, idx);
+ }
+
+ /// \brief Clears the union-find data structure
+ ///
+ /// Erase each item from the data structure.
+ void clear() {
+ items.clear();
+ classes.clear();
+ firstClass = firstFreeClass = firstFreeItem = -1;
+ }
+
+ /// \brief Gives back the class of the \e item.
+ ///
+ /// Gives back the class of the \e item.
+ int find(const Item &item) const {
+ return items[index[item]].cls;
+ }
+
+ /// \brief Gives back a representant item of the component.
+ ///
+ /// Gives back a representant item of the component.
+ Item item(int cls) const {
+ return items[classes[cls].firstItem].item;
+ }
+
+ /// \brief Removes the given element from the structure.
+ ///
+ /// Removes the element from its component and if the component becomes
+ /// empty then removes that component from the component list.
+ ///
+ /// \warning It is an error to remove an element which is not in
+ /// the structure.
+ void erase(const Item &item) {
+ int idx = index[item];
+ int cdx = items[idx].cls;
+
+ if (idx == items[idx].next) {
+ if (classes[cdx].prev != -1) {
+ classes[classes[cdx].prev].next = classes[cdx].next;
+ } else {
+ firstClass = classes[cdx].next;
+ }
+ if (classes[cdx].next != -1) {
+ classes[classes[cdx].next].prev = classes[cdx].prev;
+ }
+ classes[cdx].next = firstFreeClass;
+ firstFreeClass = cdx;
+ } else {
+ classes[cdx].firstItem = items[idx].next;
+ items[items[idx].next].prev = items[idx].prev;
+ items[items[idx].prev].next = items[idx].next;
+ }
+ items[idx].next = firstFreeItem;
+ firstFreeItem = idx;
+
+ }
+
+
+ /// \brief Removes the component of the given element from the structure.
+ ///
+ /// Removes the component of the given element from the structure.
+ ///
+ /// \warning It is an error to give an element which is not in the
+ /// structure.
+ void eraseClass(int cdx) {
+ int idx = classes[cdx].firstItem;
+ items[items[idx].prev].next = firstFreeItem;
+ firstFreeItem = idx;
+
+ if (classes[cdx].prev != -1) {
+ classes[classes[cdx].prev].next = classes[cdx].next;
+ } else {
+ firstClass = classes[cdx].next;
+ }
+ if (classes[cdx].next != -1) {
+ classes[classes[cdx].next].prev = classes[cdx].prev;
+ }
+ classes[cdx].next = firstFreeClass;
+ firstFreeClass = cdx;
+ }
+
+ /// \brief LEMON style iterator for the classes.
+ ///
+ /// ClassIt is a lemon style iterator for the components. It iterates
+ /// on the ids of classes.
+ class ClassIt {
+ public:
+ /// \brief Constructor of the iterator
+ ///
+ /// Constructor of the iterator
+ ClassIt(const ExtendFindEnum& ufe) : extendFind(&ufe) {
+ cdx = extendFind->firstClass;
+ }
+
+ /// \brief Constructor to get invalid iterator
+ ///
+ /// Constructor to get invalid iterator
+ ClassIt(Invalid) : extendFind(0), cdx(-1) {}
+
+ /// \brief Increment operator
+ ///
+ /// It steps to the next representant item.
+ ClassIt& operator++() {
+ cdx = extendFind->classes[cdx].next;
+ return *this;
+ }
+
+ /// \brief Conversion operator
+ ///
+ /// It converts the iterator to the current class id.
+ operator int() const {
+ return cdx;
+ }
+
+ /// \brief Equality operator
+ ///
+ /// Equality operator
+ bool operator==(const ClassIt& i) {
+ return i.cdx == cdx;
+ }
+
+ /// \brief Inequality operator
+ ///
+ /// Inequality operator
+ bool operator!=(const ClassIt& i) {
+ return i.cdx != cdx;
+ }
+
+ private:
+ const ExtendFindEnum* extendFind;
+ int cdx;
+ };
+
+ /// \brief LEMON style iterator for the items of a component.
+ ///
+ /// ClassIt is a lemon style iterator for the components. It iterates
+ /// on the items of a class. By example if you want to iterate on
+ /// each items of each classes then you may write the next code.
+ ///\code
+ /// for (ClassIt cit(ufe); cit != INVALID; ++cit) {
+ /// std::cout << "Class: ";
+ /// for (ItemIt iit(ufe, cit); iit != INVALID; ++iit) {
+ /// std::cout << toString(iit) << ' ' << std::endl;
+ /// }
+ /// std::cout << std::endl;
+ /// }
+ ///\endcode
+ class ItemIt {
+ public:
+ /// \brief Constructor of the iterator
+ ///
+ /// Constructor of the iterator. The iterator iterates
+ /// on the class of the \c item.
+ ItemIt(const ExtendFindEnum& ufe, int cls) : extendFind(&ufe) {
+ fdx = idx = extendFind->classes[cls].firstItem;
+ }
+
+ /// \brief Constructor to get invalid iterator
+ ///
+ /// Constructor to get invalid iterator
+ ItemIt(Invalid) : extendFind(0), idx(-1) {}
+
+ /// \brief Increment operator
+ ///
+ /// It steps to the next item in the class.
+ ItemIt& operator++() {
+ idx = extendFind->items[idx].next;
+ if (fdx == idx) idx = -1;
+ return *this;
+ }
+
+ /// \brief Conversion operator
+ ///
+ /// It converts the iterator to the current item.
+ operator const Item&() const {
+ return extendFind->items[idx].item;
+ }
+
+ /// \brief Equality operator
+ ///
+ /// Equality operator
+ bool operator==(const ItemIt& i) {
+ return i.idx == idx;
+ }
+
+ /// \brief Inequality operator
+ ///
+ /// Inequality operator
+ bool operator!=(const ItemIt& i) {
+ return i.idx != idx;
+ }
+
+ private:
+ const ExtendFindEnum* extendFind;
+ int idx, fdx;
+ };
+
+ };
+
+ /// \ingroup auxdat
+ ///
+ /// \brief A \e Union-Find data structure implementation which
+ /// is able to store a priority for each item and retrieve the minimum of
+ /// each class.
+ ///
+ /// A \e Union-Find data structure implementation which is able to
+ /// store a priority for each item and retrieve the minimum of each
+ /// class. In addition, it supports the joining and splitting the
+ /// components. If you don't need this feature then you makes
+ /// better to use the \ref UnionFind class which is more efficient.
+ ///
+ /// The union-find data strcuture based on a (2, 16)-tree with a
+ /// tournament minimum selection on the internal nodes. The insert
+ /// operation takes O(1), the find, set, decrease and increase takes
+ /// O(log(n)), where n is the number of nodes in the current
+ /// component. The complexity of join and split is O(log(n)*k),
+ /// where n is the sum of the number of the nodes and k is the
+ /// number of joined components or the number of the components
+ /// after the split.
+ ///
+ /// \pre You need to add all the elements by the \ref insert()
+ /// method.
+ template <typename V, typename IM, typename Comp = std::less<V> >
+ class HeapUnionFind {
+ public:
+
+ ///\e
+ typedef V Value;
+ ///\e
+ typedef typename IM::Key Item;
+ ///\e
+ typedef IM ItemIntMap;
+ ///\e
+ typedef Comp Compare;
+
+ private:
+
+ static const int cmax = 16;
+
+ ItemIntMap& index;
+
+ struct ClassNode {
+ int parent;
+ int depth;
+
+ int left, right;
+ int next, prev;
+ };
+
+ int first_class;
+ int first_free_class;
+ std::vector<ClassNode> classes;
+
+ int newClass() {
+ if (first_free_class < 0) {
+ int id = classes.size();
+ classes.push_back(ClassNode());
+ return id;
+ } else {
+ int id = first_free_class;
+ first_free_class = classes[id].next;
+ return id;
+ }
+ }
+
+ void deleteClass(int id) {
+ classes[id].next = first_free_class;
+ first_free_class = id;
+ }
+
+ struct ItemNode {
+ int parent;
+ Item item;
+ Value prio;
+ int next, prev;
+ int left, right;
+ int size;
+ };
+
+ int first_free_node;
+ std::vector<ItemNode> nodes;
+
+ int newNode() {
+ if (first_free_node < 0) {
+ int id = nodes.size();
+ nodes.push_back(ItemNode());
+ return id;
+ } else {
+ int id = first_free_node;
+ first_free_node = nodes[id].next;
+ return id;
+ }
+ }
+
+ void deleteNode(int id) {
+ nodes[id].next = first_free_node;
+ first_free_node = id;
+ }
+
+ Comp comp;
+
+ int findClass(int id) const {
+ int kd = id;
+ while (kd >= 0) {
+ kd = nodes[kd].parent;
+ }
+ return ~kd;
+ }
+
+ int leftNode(int id) const {
+ int kd = ~(classes[id].parent);
+ for (int i = 0; i < classes[id].depth; ++i) {
+ kd = nodes[kd].left;
+ }
+ return kd;
+ }
+
+ int nextNode(int id) const {
+ int depth = 0;
+ while (id >= 0 && nodes[id].next == -1) {
+ id = nodes[id].parent;
+ ++depth;
+ }
+ if (id < 0) {
+ return -1;
+ }
+ id = nodes[id].next;
+ while (depth--) {
+ id = nodes[id].left;
+ }
+ return id;
+ }
+
+
+ void setPrio(int id) {
+ int jd = nodes[id].left;
+ nodes[id].prio = nodes[jd].prio;
+ nodes[id].item = nodes[jd].item;
+ jd = nodes[jd].next;
+ while (jd != -1) {
+ if (comp(nodes[jd].prio, nodes[id].prio)) {
+ nodes[id].prio = nodes[jd].prio;
+ nodes[id].item = nodes[jd].item;
+ }
+ jd = nodes[jd].next;
+ }
+ }
+
+ void push(int id, int jd) {
+ nodes[id].size = 1;
+ nodes[id].left = nodes[id].right = jd;
+ nodes[jd].next = nodes[jd].prev = -1;
+ nodes[jd].parent = id;
+ }
+
+ void pushAfter(int id, int jd) {
+ int kd = nodes[id].parent;
+ if (nodes[id].next != -1) {
+ nodes[nodes[id].next].prev = jd;
+ if (kd >= 0) {
+ nodes[kd].size += 1;
+ }
+ } else {
+ if (kd >= 0) {
+ nodes[kd].right = jd;
+ nodes[kd].size += 1;
+ }
+ }
+ nodes[jd].next = nodes[id].next;
+ nodes[jd].prev = id;
+ nodes[id].next = jd;
+ nodes[jd].parent = kd;
+ }
+
+ void pushRight(int id, int jd) {
+ nodes[id].size += 1;
+ nodes[jd].prev = nodes[id].right;
+ nodes[jd].next = -1;
+ nodes[nodes[id].right].next = jd;
+ nodes[id].right = jd;
+ nodes[jd].parent = id;
+ }
+
+ void popRight(int id) {
+ nodes[id].size -= 1;
+ int jd = nodes[id].right;
+ nodes[nodes[jd].prev].next = -1;
+ nodes[id].right = nodes[jd].prev;
+ }
+
+ void splice(int id, int jd) {
+ nodes[id].size += nodes[jd].size;
+ nodes[nodes[id].right].next = nodes[jd].left;
+ nodes[nodes[jd].left].prev = nodes[id].right;
+ int kd = nodes[jd].left;
+ while (kd != -1) {
+ nodes[kd].parent = id;
+ kd = nodes[kd].next;
+ }
+ nodes[id].right = nodes[jd].right;
+ }
+
+ void split(int id, int jd) {
+ int kd = nodes[id].parent;
+ nodes[kd].right = nodes[id].prev;
+ nodes[nodes[id].prev].next = -1;
+
+ nodes[jd].left = id;
+ nodes[id].prev = -1;
+ int num = 0;
+ while (id != -1) {
+ nodes[id].parent = jd;
+ nodes[jd].right = id;
+ id = nodes[id].next;
+ ++num;
+ }
+ nodes[kd].size -= num;
+ nodes[jd].size = num;
+ }
+
+ void pushLeft(int id, int jd) {
+ nodes[id].size += 1;
+ nodes[jd].next = nodes[id].left;
+ nodes[jd].prev = -1;
+ nodes[nodes[id].left].prev = jd;
+ nodes[id].left = jd;
+ nodes[jd].parent = id;
+ }
+
+ void popLeft(int id) {
+ nodes[id].size -= 1;
+ int jd = nodes[id].left;
+ nodes[nodes[jd].next].prev = -1;
+ nodes[id].left = nodes[jd].next;
+ }
+
+ void repairLeft(int id) {
+ int jd = ~(classes[id].parent);
+ while (nodes[jd].left != -1) {
+ int kd = nodes[jd].left;
+ if (nodes[jd].size == 1) {
+ if (nodes[jd].parent < 0) {
+ classes[id].parent = ~kd;
+ classes[id].depth -= 1;
+ nodes[kd].parent = ~id;
+ deleteNode(jd);
+ jd = kd;
+ } else {
+ int pd = nodes[jd].parent;
+ if (nodes[nodes[jd].next].size < cmax) {
+ pushLeft(nodes[jd].next, nodes[jd].left);
+ if (less(jd, nodes[jd].next) ||
+ nodes[jd].item == nodes[pd].item) {
+ nodes[nodes[jd].next].prio = nodes[jd].prio;
+ nodes[nodes[jd].next].item = nodes[jd].item;
+ }
+ popLeft(pd);
+ deleteNode(jd);
+ jd = pd;
+ } else {
+ int ld = nodes[nodes[jd].next].left;
+ popLeft(nodes[jd].next);
+ pushRight(jd, ld);
+ if (less(ld, nodes[jd].left) ||
+ nodes[ld].item == nodes[pd].item) {
+ nodes[jd].item = nodes[ld].item;
+ nodes[jd].prio = nodes[ld].prio;
+ }
+ if (nodes[nodes[jd].next].item == nodes[ld].item) {
+ setPrio(nodes[jd].next);
+ }
+ jd = nodes[jd].left;
+ }
+ }
+ } else {
+ jd = nodes[jd].left;
+ }
+ }
+ }
+
+ void repairRight(int id) {
+ int jd = ~(classes[id].parent);
+ while (nodes[jd].right != -1) {
+ int kd = nodes[jd].right;
+ if (nodes[jd].size == 1) {
+ if (nodes[jd].parent < 0) {
+ classes[id].parent = ~kd;
+ classes[id].depth -= 1;
+ nodes[kd].parent = ~id;
+ deleteNode(jd);
+ jd = kd;
+ } else {
+ int pd = nodes[jd].parent;
+ if (nodes[nodes[jd].prev].size < cmax) {
+ pushRight(nodes[jd].prev, nodes[jd].right);
+ if (less(jd, nodes[jd].prev) ||
+ nodes[jd].item == nodes[pd].item) {
+ nodes[nodes[jd].prev].prio = nodes[jd].prio;
+ nodes[nodes[jd].prev].item = nodes[jd].item;
+ }
+ popRight(pd);
+ deleteNode(jd);
+ jd = pd;
+ } else {
+ int ld = nodes[nodes[jd].prev].right;
+ popRight(nodes[jd].prev);
+ pushLeft(jd, ld);
+ if (less(ld, nodes[jd].right) ||
+ nodes[ld].item == nodes[pd].item) {
+ nodes[jd].item = nodes[ld].item;
+ nodes[jd].prio = nodes[ld].prio;
+ }
+ if (nodes[nodes[jd].prev].item == nodes[ld].item) {
+ setPrio(nodes[jd].prev);
+ }
+ jd = nodes[jd].right;
+ }
+ }
+ } else {
+ jd = nodes[jd].right;
+ }
+ }
+ }
+
+
+ bool less(int id, int jd) const {
+ return comp(nodes[id].prio, nodes[jd].prio);
+ }
+
+ public:
+
+ /// \brief Returns true when the given class is alive.
+ ///
+ /// Returns true when the given class is alive, ie. the class is
+ /// not nested into other class.
+ bool alive(int cls) const {
+ return classes[cls].parent < 0;
+ }
+
+ /// \brief Returns true when the given class is trivial.
+ ///
+ /// Returns true when the given class is trivial, ie. the class
+ /// contains just one item directly.
+ bool trivial(int cls) const {
+ return classes[cls].left == -1;
+ }
+
+ /// \brief Constructs the union-find.
+ ///
+ /// Constructs the union-find.
+ /// \brief _index The index map of the union-find. The data
+ /// structure uses internally for store references.
+ HeapUnionFind(ItemIntMap& _index)
+ : index(_index), first_class(-1),
+ first_free_class(-1), first_free_node(-1) {}
+
+ /// \brief Clears the union-find data structure
+ ///
+ /// Erase each item from the data structure.
+ void clear() {
+ nodes.clear();
+ classes.clear();
+ first_free_node = first_free_class = first_class = -1;
+ }
+
+ /// \brief Insert a new node into a new component.
+ ///
+ /// Insert a new node into a new component.
+ /// \param item The item of the new node.
+ /// \param prio The priority of the new node.
+ /// \return The class id of the one-item-heap.
+ int insert(const Item& item, const Value& prio) {
+ int id = newNode();
+ nodes[id].item = item;
+ nodes[id].prio = prio;
+ nodes[id].size = 0;
+
+ nodes[id].prev = -1;
+ nodes[id].next = -1;
+
+ nodes[id].left = -1;
+ nodes[id].right = -1;
+
+ nodes[id].item = item;
+ index[item] = id;
+
+ int class_id = newClass();
+ classes[class_id].parent = ~id;
+ classes[class_id].depth = 0;
+
+ classes[class_id].left = -1;
+ classes[class_id].right = -1;
+
+ if (first_class != -1) {
+ classes[first_class].prev = class_id;
+ }
+ classes[class_id].next = first_class;
+ classes[class_id].prev = -1;
+ first_class = class_id;
+
+ nodes[id].parent = ~class_id;
+
+ return class_id;
+ }
+
+ /// \brief The class of the item.
+ ///
+ /// \return The alive class id of the item, which is not nested into
+ /// other classes.
+ ///
+ /// The time complexity is O(log(n)).
+ int find(const Item& item) const {
+ return findClass(index[item]);
+ }
+
+ /// \brief Joins the classes.
+ ///
+ /// The current function joins the given classes. The parameter is
+ /// an STL range which should be contains valid class ids. The
+ /// time complexity is O(log(n)*k) where n is the overall number
+ /// of the joined nodes and k is the number of classes.
+ /// \return The class of the joined classes.
+ /// \pre The range should contain at least two class ids.
+ template <typename Iterator>
+ int join(Iterator begin, Iterator end) {
+ std::vector<int> cs;
+ for (Iterator it = begin; it != end; ++it) {
+ cs.push_back(*it);
+ }
+
+ int class_id = newClass();
+ { // creation union-find
+
+ if (first_class != -1) {
+ classes[first_class].prev = class_id;
+ }
+ classes[class_id].next = first_class;
+ classes[class_id].prev = -1;
+ first_class = class_id;
+
+ classes[class_id].depth = classes[cs[0]].depth;
+ classes[class_id].parent = classes[cs[0]].parent;
+ nodes[~(classes[class_id].parent)].parent = ~class_id;
+
+ int l = cs[0];
+
+ classes[class_id].left = l;
+ classes[class_id].right = l;
+
+ if (classes[l].next != -1) {
+ classes[classes[l].next].prev = classes[l].prev;
+ }
+ classes[classes[l].prev].next = classes[l].next;
+
+ classes[l].prev = -1;
+ classes[l].next = -1;
+
+ classes[l].depth = leftNode(l);
+ classes[l].parent = class_id;
+
+ }
+
+ { // merging of heap
+ int l = class_id;
+ for (int ci = 1; ci < int(cs.size()); ++ci) {
+ int r = cs[ci];
+ int rln = leftNode(r);
+ if (classes[l].depth > classes[r].depth) {
+ int id = ~(classes[l].parent);
+ for (int i = classes[r].depth + 1; i < classes[l].depth; ++i) {
+ id = nodes[id].right;
+ }
+ while (id >= 0 && nodes[id].size == cmax) {
+ int new_id = newNode();
+ int right_id = nodes[id].right;
+
+ popRight(id);
+ if (nodes[id].item == nodes[right_id].item) {
+ setPrio(id);
+ }
+ push(new_id, right_id);
+ pushRight(new_id, ~(classes[r].parent));
+
+ if (less(~classes[r].parent, right_id)) {
+ nodes[new_id].item = nodes[~classes[r].parent].item;
+ nodes[new_id].prio = nodes[~classes[r].parent].prio;
+ } else {
+ nodes[new_id].item = nodes[right_id].item;
+ nodes[new_id].prio = nodes[right_id].prio;
+ }
+
+ id = nodes[id].parent;
+ classes[r].parent = ~new_id;
+ }
+ if (id < 0) {
+ int new_parent = newNode();
+ nodes[new_parent].next = -1;
+ nodes[new_parent].prev = -1;
+ nodes[new_parent].parent = ~l;
+
+ push(new_parent, ~(classes[l].parent));
+ pushRight(new_parent, ~(classes[r].parent));
+ setPrio(new_parent);
+
+ classes[l].parent = ~new_parent;
+ classes[l].depth += 1;
+ } else {
+ pushRight(id, ~(classes[r].parent));
+ while (id >= 0 && less(~(classes[r].parent), id)) {
+ nodes[id].prio = nodes[~(classes[r].parent)].prio;
+ nodes[id].item = nodes[~(classes[r].parent)].item;
+ id = nodes[id].parent;
+ }
+ }
+ } else if (classes[r].depth > classes[l].depth) {
+ int id = ~(classes[r].parent);
+ for (int i = classes[l].depth + 1; i < classes[r].depth; ++i) {
+ id = nodes[id].left;
+ }
+ while (id >= 0 && nodes[id].size == cmax) {
+ int new_id = newNode();
+ int left_id = nodes[id].left;
+
+ popLeft(id);
+ if (nodes[id].prio == nodes[left_id].prio) {
+ setPrio(id);
+ }
+ push(new_id, left_id);
+ pushLeft(new_id, ~(classes[l].parent));
+
+ if (less(~classes[l].parent, left_id)) {
+ nodes[new_id].item = nodes[~classes[l].parent].item;
+ nodes[new_id].prio = nodes[~classes[l].parent].prio;
+ } else {
+ nodes[new_id].item = nodes[left_id].item;
+ nodes[new_id].prio = nodes[left_id].prio;
+ }
+
+ id = nodes[id].parent;
+ classes[l].parent = ~new_id;
+
+ }
+ if (id < 0) {
+ int new_parent = newNode();
+ nodes[new_parent].next = -1;
+ nodes[new_parent].prev = -1;
+ nodes[new_parent].parent = ~l;
+
+ push(new_parent, ~(classes[r].parent));
+ pushLeft(new_parent, ~(classes[l].parent));
+ setPrio(new_parent);
+
+ classes[r].parent = ~new_parent;
+ classes[r].depth += 1;
+ } else {
+ pushLeft(id, ~(classes[l].parent));
+ while (id >= 0 && less(~(classes[l].parent), id)) {
+ nodes[id].prio = nodes[~(classes[l].parent)].prio;
+ nodes[id].item = nodes[~(classes[l].parent)].item;
+ id = nodes[id].parent;
+ }
+ }
+ nodes[~(classes[r].parent)].parent = ~l;
+ classes[l].parent = classes[r].parent;
+ classes[l].depth = classes[r].depth;
+ } else {
+ if (classes[l].depth != 0 &&
+ nodes[~(classes[l].parent)].size +
+ nodes[~(classes[r].parent)].size <= cmax) {
+ splice(~(classes[l].parent), ~(classes[r].parent));
+ deleteNode(~(classes[r].parent));
+ if (less(~(classes[r].parent), ~(classes[l].parent))) {
+ nodes[~(classes[l].parent)].prio =
+ nodes[~(classes[r].parent)].prio;
+ nodes[~(classes[l].parent)].item =
+ nodes[~(classes[r].parent)].item;
+ }
+ } else {
+ int new_parent = newNode();
+ nodes[new_parent].next = nodes[new_parent].prev = -1;
+ push(new_parent, ~(classes[l].parent));
+ pushRight(new_parent, ~(classes[r].parent));
+ setPrio(new_parent);
+
+ classes[l].parent = ~new_parent;
+ classes[l].depth += 1;
+ nodes[new_parent].parent = ~l;
+ }
+ }
+ if (classes[r].next != -1) {
+ classes[classes[r].next].prev = classes[r].prev;
+ }
+ classes[classes[r].prev].next = classes[r].next;
+
+ classes[r].prev = classes[l].right;
+ classes[classes[l].right].next = r;
+ classes[l].right = r;
+ classes[r].parent = l;
+
+ classes[r].next = -1;
+ classes[r].depth = rln;
+ }
+ }
+ return class_id;
+ }
+
+ /// \brief Split the class to subclasses.
+ ///
+ /// The current function splits the given class. The join, which
+ /// made the current class, stored a reference to the
+ /// subclasses. The \c splitClass() member restores the classes
+ /// and creates the heaps. The parameter is an STL output iterator
+ /// which will be filled with the subclass ids. The time
+ /// complexity is O(log(n)*k) where n is the overall number of
+ /// nodes in the splitted classes and k is the number of the
+ /// classes.
+ template <typename Iterator>
+ void split(int cls, Iterator out) {
+ std::vector<int> cs;
+ { // splitting union-find
+ int id = cls;
+ int l = classes[id].left;
+
+ classes[l].parent = classes[id].parent;
+ classes[l].depth = classes[id].depth;
+
+ nodes[~(classes[l].parent)].parent = ~l;
+
+ *out++ = l;
+
+ while (l != -1) {
+ cs.push_back(l);
+ l = classes[l].next;
+ }
+
+ classes[classes[id].right].next = first_class;
+ classes[first_class].prev = classes[id].right;
+ first_class = classes[id].left;
+
+ if (classes[id].next != -1) {
+ classes[classes[id].next].prev = classes[id].prev;
+ }
+ classes[classes[id].prev].next = classes[id].next;
+
+ deleteClass(id);
+ }
+
+ {
+ for (int i = 1; i < int(cs.size()); ++i) {
+ int l = classes[cs[i]].depth;
+ while (nodes[nodes[l].parent].left == l) {
+ l = nodes[l].parent;
+ }
+ int r = l;
+ while (nodes[l].parent >= 0) {
+ l = nodes[l].parent;
+ int new_node = newNode();
+
+ nodes[new_node].prev = -1;
+ nodes[new_node].next = -1;
+
+ split(r, new_node);
+ pushAfter(l, new_node);
+ setPrio(l);
+ setPrio(new_node);
+ r = new_node;
+ }
+ classes[cs[i]].parent = ~r;
+ classes[cs[i]].depth = classes[~(nodes[l].parent)].depth;
+ nodes[r].parent = ~cs[i];
+
+ nodes[l].next = -1;
+ nodes[r].prev = -1;
+
+ repairRight(~(nodes[l].parent));
+ repairLeft(cs[i]);
+
+ *out++ = cs[i];
+ }
+ }
+ }
+
+ /// \brief Gives back the priority of the current item.
+ ///
+ /// Gives back the priority of the current item.
+ const Value& operator[](const Item& item) const {
+ return nodes[index[item]].prio;
+ }
+
+ /// \brief Sets the priority of the current item.
+ ///
+ /// Sets the priority of the current item.
+ void set(const Item& item, const Value& prio) {
+ if (comp(prio, nodes[index[item]].prio)) {
+ decrease(item, prio);
+ } else if (!comp(prio, nodes[index[item]].prio)) {
+ increase(item, prio);
+ }
+ }
+
+ /// \brief Increase the priority of the current item.
+ ///
+ /// Increase the priority of the current item.
+ void increase(const Item& item, const Value& prio) {
+ int id = index[item];
+ int kd = nodes[id].parent;
+ nodes[id].prio = prio;
+ while (kd >= 0 && nodes[kd].item == item) {
+ setPrio(kd);
+ kd = nodes[kd].parent;
+ }
+ }
+
+ /// \brief Increase the priority of the current item.
+ ///
+ /// Increase the priority of the current item.
+ void decrease(const Item& item, const Value& prio) {
+ int id = index[item];
+ int kd = nodes[id].parent;
+ nodes[id].prio = prio;
+ while (kd >= 0 && less(id, kd)) {
+ nodes[kd].prio = prio;
+ nodes[kd].item = item;
+ kd = nodes[kd].parent;
+ }
+ }
+
+ /// \brief Gives back the minimum priority of the class.
+ ///
+ /// Gives back the minimum priority of the class.
+ const Value& classPrio(int cls) const {
+ return nodes[~(classes[cls].parent)].prio;
+ }
+
+ /// \brief Gives back the minimum priority item of the class.
+ ///
+ /// \return Gives back the minimum priority item of the class.
+ const Item& classTop(int cls) const {
+ return nodes[~(classes[cls].parent)].item;
+ }
+
+ /// \brief Gives back a representant item of the class.
+ ///
+ /// Gives back a representant item of the class.
+ /// The representant is indpendent from the priorities of the
+ /// items.
+ const Item& classRep(int id) const {
+ int parent = classes[id].parent;
+ return nodes[parent >= 0 ? classes[id].depth : leftNode(id)].item;
+ }
+
+ /// \brief LEMON style iterator for the items of a class.
+ ///
+ /// ClassIt is a lemon style iterator for the components. It iterates
+ /// on the items of a class. By example if you want to iterate on
+ /// each items of each classes then you may write the next code.
+ ///\code
+ /// for (ClassIt cit(huf); cit != INVALID; ++cit) {
+ /// std::cout << "Class: ";
+ /// for (ItemIt iit(huf, cit); iit != INVALID; ++iit) {
+ /// std::cout << toString(iit) << ' ' << std::endl;
+ /// }
+ /// std::cout << std::endl;
+ /// }
+ ///\endcode
+ class ItemIt {
+ private:
+
+ const HeapUnionFind* _huf;
+ int _id, _lid;
+
+ public:
+
+ /// \brief Default constructor
+ ///
+ /// Default constructor
+ ItemIt() {}
+
+ ItemIt(const HeapUnionFind& huf, int cls) : _huf(&huf) {
+ int id = cls;
+ int parent = _huf->classes[id].parent;
+ if (parent >= 0) {
+ _id = _huf->classes[id].depth;
+ if (_huf->classes[id].next != -1) {
+ _lid = _huf->classes[_huf->classes[id].next].depth;
+ } else {
+ _lid = -1;
+ }
+ } else {
+ _id = _huf->leftNode(id);
+ _lid = -1;
+ }
+ }
+
+ /// \brief Increment operator
+ ///
+ /// It steps to the next item in the class.
+ ItemIt& operator++() {
+ _id = _huf->nextNode(_id);
+ return *this;
+ }
+
+ /// \brief Conversion operator
+ ///
+ /// It converts the iterator to the current item.
+ operator const Item&() const {
+ return _huf->nodes[_id].item;
+ }
+
+ /// \brief Equality operator
+ ///
+ /// Equality operator
+ bool operator==(const ItemIt& i) {
+ return i._id == _id;
+ }
+
+ /// \brief Inequality operator
+ ///
+ /// Inequality operator
+ bool operator!=(const ItemIt& i) {
+ return i._id != _id;
+ }
+
+ /// \brief Equality operator
+ ///
+ /// Equality operator
+ bool operator==(Invalid) {
+ return _id == _lid;
+ }
+
+ /// \brief Inequality operator
+ ///
+ /// Inequality operator
+ bool operator!=(Invalid) {
+ return _id != _lid;
+ }
+
+ };
+
+ /// \brief Class iterator
+ ///
+ /// The iterator stores
+ class ClassIt {
+ private:
+
+ const HeapUnionFind* _huf;
+ int _id;
+
+ public:
+
+ ClassIt(const HeapUnionFind& huf)
+ : _huf(&huf), _id(huf.first_class) {}
+
+ ClassIt(const HeapUnionFind& huf, int cls)
+ : _huf(&huf), _id(huf.classes[cls].left) {}
+
+ ClassIt(Invalid) : _huf(0), _id(-1) {}
+
+ const ClassIt& operator++() {
+ _id = _huf->classes[_id].next;
+ return *this;
+ }
+
+ /// \brief Equality operator
+ ///
+ /// Equality operator
+ bool operator==(const ClassIt& i) {
+ return i._id == _id;
+ }
+
+ /// \brief Inequality operator
+ ///
+ /// Inequality operator
+ bool operator!=(const ClassIt& i) {
+ return i._id != _id;
+ }
+
+ operator int() const {
+ return _id;
+ }
+
+ };
+
+ };
+
+ //! @}
+
+} //namespace lemon
+
+#endif //LEMON_UNION_FIND_H
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/scripts/unify-sources.sh b/extern/quadriflow/3rd/lemon-1.3.1/scripts/unify-sources.sh
new file mode 100755
index 00000000000..6aae63ab641
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/scripts/unify-sources.sh
@@ -0,0 +1,390 @@
+#!/bin/bash
+#
+# This file is a part of LEMON, a generic C++ optimization library.
+#
+# Copyright (C) 2003-2009
+# Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+# (Egervary Research Group on Combinatorial Optimization, EGRES).
+#
+# Permission to use, modify and distribute this software is granted
+# provided that this copyright notice appears in all copies. For
+# precise terms see the accompanying LICENSE file.
+#
+# This software is provided "AS IS" with no warranty of any kind,
+# express or implied, and with no claim as to its suitability for any
+# purpose.
+
+YEAR=`date +%Y`
+HGROOT=`hg root`
+
+function hg_year() {
+ if [ -n "$(hg st $1)" ]; then
+ echo $YEAR
+ else
+ hg log -l 1 --template='{date|isodate}\n' $1 |
+ cut -d '-' -f 1
+ fi
+}
+
+# file enumaration modes
+
+function all_files() {
+ hg status -a -m -c |
+ cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' |
+ while read file; do echo $HGROOT/$file; done
+}
+
+function modified_files() {
+ hg status -a -m |
+ cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' |
+ while read file; do echo $HGROOT/$file; done
+}
+
+function changed_files() {
+ {
+ if [ -n "$HG_PARENT1" ]
+ then
+ hg status --rev $HG_PARENT1:$HG_NODE -a -m
+ fi
+ if [ -n "$HG_PARENT2" ]
+ then
+ hg status --rev $HG_PARENT2:$HG_NODE -a -m
+ fi
+ } | cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' |
+ sort | uniq |
+ while read file; do echo $HGROOT/$file; done
+}
+
+function given_files() {
+ for file in $GIVEN_FILES
+ do
+ echo $file
+ done
+}
+
+# actions
+
+function update_action() {
+ if ! diff -q $1 $2 >/dev/null
+ then
+ echo -n " [$3 updated]"
+ rm $2
+ mv $1 $2
+ CHANGED=YES
+ fi
+}
+
+function update_warning() {
+ echo -n " [$2 warning]"
+ WARNED=YES
+}
+
+function update_init() {
+ echo Update source files...
+ TOTAL_FILES=0
+ CHANGED_FILES=0
+ WARNED_FILES=0
+}
+
+function update_done() {
+ echo $CHANGED_FILES out of $TOTAL_FILES files has been changed.
+ echo $WARNED_FILES out of $TOTAL_FILES files triggered warnings.
+}
+
+function update_begin() {
+ ((TOTAL_FILES++))
+ CHANGED=NO
+ WARNED=NO
+}
+
+function update_end() {
+ if [ $CHANGED == YES ]
+ then
+ ((++CHANGED_FILES))
+ fi
+ if [ $WARNED == YES ]
+ then
+ ((++WARNED_FILES))
+ fi
+}
+
+function check_action() {
+ if [ "$3" == 'tabs' ]
+ then
+ if echo $2 | grep -q -v -E 'Makefile\.am$'
+ then
+ PATTERN=$(echo -e '\t')
+ else
+ PATTERN=' '
+ fi
+ elif [ "$3" == 'trailing spaces' ]
+ then
+ PATTERN='\ +$'
+ else
+ PATTERN='*'
+ fi
+
+ if ! diff -q $1 $2 >/dev/null
+ then
+ if [ "$PATTERN" == '*' ]
+ then
+ diff $1 $2 | grep '^[0-9]' | sed "s|^\(.*\)c.*$|$2:\1: check failed: $3|g" |
+ sed "s/:\([0-9]*\),\([0-9]*\):\(.*\)$/:\1:\3 (until line \2)/g"
+ else
+ grep -n -E "$PATTERN" $2 | sed "s|^\([0-9]*\):.*$|$2:\1: check failed: $3|g"
+ fi
+ FAILED=YES
+ fi
+}
+
+function check_warning() {
+ if [ "$2" == 'long lines' ]
+ then
+ grep -n -E '.{81,}' $1 | sed "s|^\([0-9]*\):.*$|$1:\1: warning: $2|g"
+ else
+ echo "$1: warning: $2"
+ fi
+ WARNED=YES
+}
+
+function check_init() {
+ echo Check source files...
+ FAILED_FILES=0
+ WARNED_FILES=0
+ TOTAL_FILES=0
+}
+
+function check_done() {
+ echo $FAILED_FILES out of $TOTAL_FILES files has been failed.
+ echo $WARNED_FILES out of $TOTAL_FILES files triggered warnings.
+
+ if [ $WARNED_FILES -gt 0 -o $FAILED_FILES -gt 0 ]
+ then
+ if [ "$WARNING" == 'INTERACTIVE' ]
+ then
+ echo -n "Are the files with errors/warnings acceptable? (yes/no) "
+ while read answer
+ do
+ if [ "$answer" == 'yes' ]
+ then
+ return 0
+ elif [ "$answer" == 'no' ]
+ then
+ return 1
+ fi
+ echo -n "Are the files with errors/warnings acceptable? (yes/no) "
+ done
+ elif [ "$WARNING" == 'WERROR' ]
+ then
+ return 1
+ fi
+ fi
+}
+
+function check_begin() {
+ ((TOTAL_FILES++))
+ FAILED=NO
+ WARNED=NO
+}
+
+function check_end() {
+ if [ $FAILED == YES ]
+ then
+ ((++FAILED_FILES))
+ fi
+ if [ $WARNED == YES ]
+ then
+ ((++WARNED_FILES))
+ fi
+}
+
+
+
+# checks
+
+function header_check() {
+ if echo $1 | grep -q -E 'Makefile\.am$'
+ then
+ return
+ fi
+
+ TMP_FILE=`mktemp`
+
+ (echo "/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-"$(hg_year $1)"
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided \"AS IS\" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+"
+ awk 'BEGIN { pm=0; }
+ pm==3 { print }
+ /\/\* / && pm==0 { pm=1;}
+ /[^:blank:]/ && (pm==0 || pm==2) { pm=3; print;}
+ /\*\// && pm==1 { pm=2;}
+ ' $1
+ ) >$TMP_FILE
+
+ "$ACTION"_action "$TMP_FILE" "$1" header
+}
+
+function tabs_check() {
+ if echo $1 | grep -q -v -E 'Makefile\.am$'
+ then
+ OLD_PATTERN=$(echo -e '\t')
+ NEW_PATTERN=' '
+ else
+ OLD_PATTERN=' '
+ NEW_PATTERN=$(echo -e '\t')
+ fi
+ TMP_FILE=`mktemp`
+ cat $1 | sed -e "s/$OLD_PATTERN/$NEW_PATTERN/g" >$TMP_FILE
+
+ "$ACTION"_action "$TMP_FILE" "$1" 'tabs'
+}
+
+function spaces_check() {
+ TMP_FILE=`mktemp`
+ cat $1 | sed -e 's/ \+$//g' >$TMP_FILE
+
+ "$ACTION"_action "$TMP_FILE" "$1" 'trailing spaces'
+}
+
+function long_lines_check() {
+ if cat $1 | grep -q -E '.{81,}'
+ then
+ "$ACTION"_warning $1 'long lines'
+ fi
+}
+
+# process the file
+
+function process_file() {
+ if [ "$ACTION" == 'update' ]
+ then
+ echo -n " $ACTION $1..."
+ else
+ echo " $ACTION $1..."
+ fi
+
+ CHECKING="header tabs spaces long_lines"
+
+ "$ACTION"_begin $1
+ for check in $CHECKING
+ do
+ "$check"_check $1
+ done
+ "$ACTION"_end $1
+ if [ "$ACTION" == 'update' ]
+ then
+ echo
+ fi
+}
+
+function process_all {
+ "$ACTION"_init
+ while read file
+ do
+ process_file $file
+ done < <($FILES)
+ "$ACTION"_done
+}
+
+while [ $# -gt 0 ]
+do
+
+ if [ "$1" == '--help' ] || [ "$1" == '-h' ]
+ then
+ echo -n \
+"Usage:
+ $0 [OPTIONS] [files]
+Options:
+ --dry-run|-n
+ Check the files, but do not modify them.
+ --interactive|-i
+ If --dry-run is specified and the checker emits warnings,
+ then the user is asked if the warnings should be considered
+ errors.
+ --werror|-w
+ Make all warnings into errors.
+ --all|-a
+ Check all source files in the repository.
+ --modified|-m
+ Check only the modified (and new) source files. This option is
+ useful to check the modification before making a commit.
+ --changed|-c
+ Check only the changed source files compared to the parent(s) of
+ the current hg node. This option is useful as hg hook script.
+ To automatically check all your changes before making a commit,
+ add the following section to the appropriate .hg/hgrc file.
+
+ [hooks]
+ pretxncommit.checksources = scripts/unify-sources.sh -c -n -i
+
+ --help|-h
+ Print this help message.
+ files
+ The files to check/unify. If no file names are given, the modified
+ source files will be checked/unified (just like using the
+ --modified|-m option).
+"
+ exit 0
+ elif [ "$1" == '--dry-run' ] || [ "$1" == '-n' ]
+ then
+ [ -n "$ACTION" ] && echo "Conflicting action options" >&2 && exit 1
+ ACTION=check
+ elif [ "$1" == "--all" ] || [ "$1" == '-a' ]
+ then
+ [ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1
+ FILES=all_files
+ elif [ "$1" == "--changed" ] || [ "$1" == '-c' ]
+ then
+ [ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1
+ FILES=changed_files
+ elif [ "$1" == "--modified" ] || [ "$1" == '-m' ]
+ then
+ [ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1
+ FILES=modified_files
+ elif [ "$1" == "--interactive" ] || [ "$1" == "-i" ]
+ then
+ [ -n "$WARNING" ] && echo "Conflicting warning options" >&2 && exit 1
+ WARNING='INTERACTIVE'
+ elif [ "$1" == "--werror" ] || [ "$1" == "-w" ]
+ then
+ [ -n "$WARNING" ] && echo "Conflicting warning options" >&2 && exit 1
+ WARNING='WERROR'
+ elif [ $(echo x$1 | cut -c 2) == '-' ]
+ then
+ echo "Invalid option $1" >&2 && exit 1
+ else
+ [ -n "$FILES" ] && echo "Invalid option $1" >&2 && exit 1
+ GIVEN_FILES=$@
+ FILES=given_files
+ break
+ fi
+
+ shift
+done
+
+if [ -z $FILES ]
+then
+ FILES=modified_files
+fi
+
+if [ -z $ACTION ]
+then
+ ACTION=update
+fi
+
+process_all
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/scripts/valgrind-wrapper.sh b/extern/quadriflow/3rd/lemon-1.3.1/scripts/valgrind-wrapper.sh
new file mode 100755
index 00000000000..bbb12229066
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/scripts/valgrind-wrapper.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# Run in valgrind, with leak checking enabled
+
+valgrind -q --leak-check=full "$@" 2> .valgrind-log
+
+# Save the test result
+
+result="$?"
+
+# Valgrind should generate no error messages
+
+log_contents="`cat .valgrind-log`"
+
+if [ "$log_contents" != "" ]; then
+ cat .valgrind-log >&2
+ result=1
+fi
+
+rm -f .valgrind-log
+
+exit $result
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/CMakeLists.txt b/extern/quadriflow/3rd/lemon-1.3.1/test/CMakeLists.txt
new file mode 100644
index 00000000000..96fc5dd486c
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/CMakeLists.txt
@@ -0,0 +1,161 @@
+INCLUDE_DIRECTORIES(
+ ${PROJECT_SOURCE_DIR}
+ ${PROJECT_BINARY_DIR}
+)
+
+LINK_DIRECTORIES(
+ ${PROJECT_BINARY_DIR}/lemon
+)
+
+SET(TEST_WITH_VALGRIND "NO" CACHE STRING
+ "Run the test with valgrind (YES/NO).")
+SET(VALGRIND_FLAGS "" CACHE STRING "Valgrind flags used by the tests.")
+
+SET(TESTS
+ adaptors_test
+ arc_look_up_test
+ bellman_ford_test
+ bfs_test
+ bpgraph_test
+ circulation_test
+ connectivity_test
+ counter_test
+ dfs_test
+ digraph_test
+ dijkstra_test
+ dim_test
+ edge_set_test
+ error_test
+ euler_test
+ fractional_matching_test
+ gomory_hu_test
+ graph_copy_test
+ graph_test
+ graph_utils_test
+ hao_orlin_test
+ heap_test
+ kruskal_test
+ lgf_reader_writer_test
+ lgf_test
+ maps_test
+ matching_test
+ max_cardinality_search_test
+ max_clique_test
+ max_flow_test
+ min_cost_arborescence_test
+ min_cost_flow_test
+ min_mean_cycle_test
+ nagamochi_ibaraki_test
+ path_test
+ planarity_test
+ radix_sort_test
+ random_test
+ suurballe_test
+ time_measure_test
+ tsp_test
+ unionfind_test
+)
+
+IF(LEMON_HAVE_LP)
+ IF(${CMAKE_BUILD_TYPE} STREQUAL "Maintainer")
+ ADD_EXECUTABLE(lp_test lp_test.cc)
+ ELSE()
+ ADD_EXECUTABLE(lp_test EXCLUDE_FROM_ALL lp_test.cc)
+ ENDIF()
+
+ SET(LP_TEST_LIBS lemon)
+
+ IF(LEMON_HAVE_GLPK)
+ SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${GLPK_LIBRARIES})
+ ENDIF()
+ IF(LEMON_HAVE_CPLEX)
+ SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${ILOG_LIBRARIES})
+ ENDIF()
+ IF(LEMON_HAVE_CLP)
+ SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${COIN_CLP_LIBRARIES})
+ ENDIF()
+ IF(LEMON_HAVE_SOPLEX)
+ SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${SOPLEX_LIBRARIES})
+ ENDIF()
+
+ TARGET_LINK_LIBRARIES(lp_test ${LP_TEST_LIBS})
+ ADD_TEST(lp_test lp_test)
+ ADD_DEPENDENCIES(check lp_test)
+
+ IF(WIN32 AND LEMON_HAVE_GLPK)
+ GET_TARGET_PROPERTY(TARGET_LOC lp_test LOCATION)
+ GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH)
+ ADD_CUSTOM_COMMAND(TARGET lp_test POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/glpk.dll ${TARGET_PATH}
+ COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/libltdl3.dll ${TARGET_PATH}
+ COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/zlib1.dll ${TARGET_PATH}
+ )
+ ENDIF()
+
+ IF(WIN32 AND LEMON_HAVE_CPLEX)
+ GET_TARGET_PROPERTY(TARGET_LOC lp_test LOCATION)
+ GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH)
+ ADD_CUSTOM_COMMAND(TARGET lp_test POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy ${ILOG_CPLEX_DLL} ${TARGET_PATH}
+ )
+ ENDIF()
+ENDIF()
+
+IF(LEMON_HAVE_MIP)
+ IF(${CMAKE_BUILD_TYPE} STREQUAL "Maintainer")
+ ADD_EXECUTABLE(mip_test mip_test.cc)
+ ELSE()
+ ADD_EXECUTABLE(mip_test EXCLUDE_FROM_ALL mip_test.cc)
+ ENDIF()
+
+ SET(MIP_TEST_LIBS lemon)
+
+ IF(LEMON_HAVE_GLPK)
+ SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${GLPK_LIBRARIES})
+ ENDIF()
+ IF(LEMON_HAVE_CPLEX)
+ SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${ILOG_LIBRARIES})
+ ENDIF()
+ IF(LEMON_HAVE_CBC)
+ SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${COIN_CBC_LIBRARIES})
+ ENDIF()
+
+ TARGET_LINK_LIBRARIES(mip_test ${MIP_TEST_LIBS})
+ ADD_TEST(mip_test mip_test)
+ ADD_DEPENDENCIES(check mip_test)
+
+ IF(WIN32 AND LEMON_HAVE_GLPK)
+ GET_TARGET_PROPERTY(TARGET_LOC mip_test LOCATION)
+ GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH)
+ ADD_CUSTOM_COMMAND(TARGET mip_test POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/glpk.dll ${TARGET_PATH}
+ COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/libltdl3.dll ${TARGET_PATH}
+ COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/zlib1.dll ${TARGET_PATH}
+ )
+ ENDIF()
+
+ IF(WIN32 AND LEMON_HAVE_CPLEX)
+ GET_TARGET_PROPERTY(TARGET_LOC mip_test LOCATION)
+ GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH)
+ ADD_CUSTOM_COMMAND(TARGET mip_test POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy ${ILOG_CPLEX_DLL} ${TARGET_PATH}
+ )
+ ENDIF()
+ENDIF()
+
+FOREACH(TEST_NAME ${TESTS})
+ IF(${CMAKE_BUILD_TYPE} STREQUAL "Maintainer")
+ ADD_EXECUTABLE(${TEST_NAME} ${TEST_NAME}.cc)
+ ELSE()
+ ADD_EXECUTABLE(${TEST_NAME} EXCLUDE_FROM_ALL ${TEST_NAME}.cc)
+ ENDIF()
+ TARGET_LINK_LIBRARIES(${TEST_NAME} lemon)
+ IF(TEST_WITH_VALGRIND)
+ ADD_TEST(${TEST_NAME}
+ valgrind --error-exitcode=1 ${VALGRIND_FLAGS}
+ ${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME} )
+ ELSE()
+ ADD_TEST(${TEST_NAME} ${TEST_NAME})
+ ENDIF()
+ ADD_DEPENDENCIES(check ${TEST_NAME})
+ENDFOREACH()
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/adaptors_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/adaptors_test.cc
new file mode 100644
index 00000000000..9077db96eff
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/adaptors_test.cc
@@ -0,0 +1,1468 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <iostream>
+#include <limits>
+
+#include <lemon/list_graph.h>
+#include <lemon/grid_graph.h>
+#include <lemon/bfs.h>
+#include <lemon/path.h>
+
+#include <lemon/concepts/digraph.h>
+#include <lemon/concepts/graph.h>
+#include <lemon/concepts/graph_components.h>
+#include <lemon/concepts/maps.h>
+#include <lemon/concept_check.h>
+
+#include <lemon/adaptors.h>
+
+#include "test/test_tools.h"
+#include "test/graph_test.h"
+
+using namespace lemon;
+
+void checkReverseDigraph() {
+ // Check concepts
+ checkConcept<concepts::Digraph, ReverseDigraph<concepts::Digraph> >();
+ checkConcept<concepts::Digraph, ReverseDigraph<ListDigraph> >();
+ checkConcept<concepts::AlterableDigraphComponent<>,
+ ReverseDigraph<ListDigraph> >();
+ checkConcept<concepts::ExtendableDigraphComponent<>,
+ ReverseDigraph<ListDigraph> >();
+ checkConcept<concepts::ErasableDigraphComponent<>,
+ ReverseDigraph<ListDigraph> >();
+ checkConcept<concepts::ClearableDigraphComponent<>,
+ ReverseDigraph<ListDigraph> >();
+
+ // Create a digraph and an adaptor
+ typedef ListDigraph Digraph;
+ typedef ReverseDigraph<Digraph> Adaptor;
+
+ Digraph digraph;
+ Adaptor adaptor(digraph);
+
+ // Add nodes and arcs to the original digraph
+ Digraph::Node n1 = digraph.addNode();
+ Digraph::Node n2 = digraph.addNode();
+ Digraph::Node n3 = digraph.addNode();
+
+ Digraph::Arc a1 = digraph.addArc(n1, n2);
+ Digraph::Arc a2 = digraph.addArc(n1, n3);
+ Digraph::Arc a3 = digraph.addArc(n2, n3);
+ ::lemon::ignore_unused_variable_warning(a3);
+
+ // Check the adaptor
+ checkGraphNodeList(adaptor, 3);
+ checkGraphArcList(adaptor, 3);
+ checkGraphConArcList(adaptor, 3);
+
+ checkGraphOutArcList(adaptor, n1, 0);
+ checkGraphOutArcList(adaptor, n2, 1);
+ checkGraphOutArcList(adaptor, n3, 2);
+
+ checkGraphInArcList(adaptor, n1, 2);
+ checkGraphInArcList(adaptor, n2, 1);
+ checkGraphInArcList(adaptor, n3, 0);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+
+ // Check the orientation of the arcs
+ for (Adaptor::ArcIt a(adaptor); a != INVALID; ++a) {
+ check(adaptor.source(a) == digraph.target(a), "Wrong reverse");
+ check(adaptor.target(a) == digraph.source(a), "Wrong reverse");
+ }
+
+ // Add and erase nodes and arcs in the digraph through the adaptor
+ Adaptor::Node n4 = adaptor.addNode();
+
+ Adaptor::Arc a4 = adaptor.addArc(n4, n3);
+ Adaptor::Arc a5 = adaptor.addArc(n2, n4);
+ Adaptor::Arc a6 = adaptor.addArc(n2, n4);
+ Adaptor::Arc a7 = adaptor.addArc(n1, n4);
+ Adaptor::Arc a8 = adaptor.addArc(n1, n2);
+ ::lemon::ignore_unused_variable_warning(a6,a7,a8);
+
+ adaptor.erase(a1);
+ adaptor.erase(n3);
+
+ // Check the adaptor
+ checkGraphNodeList(adaptor, 3);
+ checkGraphArcList(adaptor, 4);
+ checkGraphConArcList(adaptor, 4);
+
+ checkGraphOutArcList(adaptor, n1, 2);
+ checkGraphOutArcList(adaptor, n2, 2);
+ checkGraphOutArcList(adaptor, n4, 0);
+
+ checkGraphInArcList(adaptor, n1, 0);
+ checkGraphInArcList(adaptor, n2, 1);
+ checkGraphInArcList(adaptor, n4, 3);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+
+ // Check the digraph
+ checkGraphNodeList(digraph, 3);
+ checkGraphArcList(digraph, 4);
+ checkGraphConArcList(digraph, 4);
+
+ checkGraphOutArcList(digraph, n1, 0);
+ checkGraphOutArcList(digraph, n2, 1);
+ checkGraphOutArcList(digraph, n4, 3);
+
+ checkGraphInArcList(digraph, n1, 2);
+ checkGraphInArcList(digraph, n2, 2);
+ checkGraphInArcList(digraph, n4, 0);
+
+ checkNodeIds(digraph);
+ checkArcIds(digraph);
+
+ checkGraphNodeMap(digraph);
+ checkGraphArcMap(digraph);
+
+ // Check the conversion of nodes and arcs
+ Digraph::Node nd = n4;
+ nd = n4;
+ Adaptor::Node na = n1;
+ na = n2;
+ Digraph::Arc ad = a4;
+ ad = a5;
+ Adaptor::Arc aa = a1;
+ aa = a2;
+}
+
+void checkSubDigraph() {
+ // Check concepts
+ checkConcept<concepts::Digraph, SubDigraph<concepts::Digraph> >();
+ checkConcept<concepts::Digraph, SubDigraph<ListDigraph> >();
+ checkConcept<concepts::AlterableDigraphComponent<>,
+ SubDigraph<ListDigraph> >();
+ checkConcept<concepts::ExtendableDigraphComponent<>,
+ SubDigraph<ListDigraph> >();
+ checkConcept<concepts::ErasableDigraphComponent<>,
+ SubDigraph<ListDigraph> >();
+ checkConcept<concepts::ClearableDigraphComponent<>,
+ SubDigraph<ListDigraph> >();
+
+ // Create a digraph and an adaptor
+ typedef ListDigraph Digraph;
+ typedef Digraph::NodeMap<bool> NodeFilter;
+ typedef Digraph::ArcMap<bool> ArcFilter;
+ typedef SubDigraph<Digraph, NodeFilter, ArcFilter> Adaptor;
+
+ Digraph digraph;
+ NodeFilter node_filter(digraph);
+ ArcFilter arc_filter(digraph);
+ Adaptor adaptor(digraph, node_filter, arc_filter);
+
+ // Add nodes and arcs to the original digraph and the adaptor
+ Digraph::Node n1 = digraph.addNode();
+ Digraph::Node n2 = digraph.addNode();
+ Adaptor::Node n3 = adaptor.addNode();
+
+ node_filter[n1] = node_filter[n2] = node_filter[n3] = true;
+
+ Digraph::Arc a1 = digraph.addArc(n1, n2);
+ Digraph::Arc a2 = digraph.addArc(n1, n3);
+ Adaptor::Arc a3 = adaptor.addArc(n2, n3);
+
+ arc_filter[a1] = arc_filter[a2] = arc_filter[a3] = true;
+
+ checkGraphNodeList(adaptor, 3);
+ checkGraphArcList(adaptor, 3);
+ checkGraphConArcList(adaptor, 3);
+
+ checkGraphOutArcList(adaptor, n1, 2);
+ checkGraphOutArcList(adaptor, n2, 1);
+ checkGraphOutArcList(adaptor, n3, 0);
+
+ checkGraphInArcList(adaptor, n1, 0);
+ checkGraphInArcList(adaptor, n2, 1);
+ checkGraphInArcList(adaptor, n3, 2);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+
+ // Hide an arc
+ adaptor.status(a2, false);
+ adaptor.disable(a3);
+ if (!adaptor.status(a3)) adaptor.enable(a3);
+
+ checkGraphNodeList(adaptor, 3);
+ checkGraphArcList(adaptor, 2);
+ checkGraphConArcList(adaptor, 2);
+
+ checkGraphOutArcList(adaptor, n1, 1);
+ checkGraphOutArcList(adaptor, n2, 1);
+ checkGraphOutArcList(adaptor, n3, 0);
+
+ checkGraphInArcList(adaptor, n1, 0);
+ checkGraphInArcList(adaptor, n2, 1);
+ checkGraphInArcList(adaptor, n3, 1);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+
+ // Hide a node
+ adaptor.status(n1, false);
+ adaptor.disable(n3);
+ if (!adaptor.status(n3)) adaptor.enable(n3);
+
+ checkGraphNodeList(adaptor, 2);
+ checkGraphArcList(adaptor, 1);
+ checkGraphConArcList(adaptor, 1);
+
+ checkGraphOutArcList(adaptor, n2, 1);
+ checkGraphOutArcList(adaptor, n3, 0);
+
+ checkGraphInArcList(adaptor, n2, 0);
+ checkGraphInArcList(adaptor, n3, 1);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+
+ // Hide all nodes and arcs
+ node_filter[n1] = node_filter[n2] = node_filter[n3] = false;
+ arc_filter[a1] = arc_filter[a2] = arc_filter[a3] = false;
+
+ checkGraphNodeList(adaptor, 0);
+ checkGraphArcList(adaptor, 0);
+ checkGraphConArcList(adaptor, 0);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+
+ // Check the conversion of nodes and arcs
+ Digraph::Node nd = n3;
+ nd = n3;
+ Adaptor::Node na = n1;
+ na = n2;
+ Digraph::Arc ad = a3;
+ ad = a3;
+ Adaptor::Arc aa = a1;
+ aa = a2;
+}
+
+void checkFilterNodes1() {
+ // Check concepts
+ checkConcept<concepts::Digraph, FilterNodes<concepts::Digraph> >();
+ checkConcept<concepts::Digraph, FilterNodes<ListDigraph> >();
+ checkConcept<concepts::AlterableDigraphComponent<>,
+ FilterNodes<ListDigraph> >();
+ checkConcept<concepts::ExtendableDigraphComponent<>,
+ FilterNodes<ListDigraph> >();
+ checkConcept<concepts::ErasableDigraphComponent<>,
+ FilterNodes<ListDigraph> >();
+ checkConcept<concepts::ClearableDigraphComponent<>,
+ FilterNodes<ListDigraph> >();
+
+ // Create a digraph and an adaptor
+ typedef ListDigraph Digraph;
+ typedef Digraph::NodeMap<bool> NodeFilter;
+ typedef FilterNodes<Digraph, NodeFilter> Adaptor;
+
+ Digraph digraph;
+ NodeFilter node_filter(digraph);
+ Adaptor adaptor(digraph, node_filter);
+
+ // Add nodes and arcs to the original digraph and the adaptor
+ Digraph::Node n1 = digraph.addNode();
+ Digraph::Node n2 = digraph.addNode();
+ Adaptor::Node n3 = adaptor.addNode();
+
+ node_filter[n1] = node_filter[n2] = node_filter[n3] = true;
+
+ Digraph::Arc a1 = digraph.addArc(n1, n2);
+ Digraph::Arc a2 = digraph.addArc(n1, n3);
+ Adaptor::Arc a3 = adaptor.addArc(n2, n3);
+
+ checkGraphNodeList(adaptor, 3);
+ checkGraphArcList(adaptor, 3);
+ checkGraphConArcList(adaptor, 3);
+
+ checkGraphOutArcList(adaptor, n1, 2);
+ checkGraphOutArcList(adaptor, n2, 1);
+ checkGraphOutArcList(adaptor, n3, 0);
+
+ checkGraphInArcList(adaptor, n1, 0);
+ checkGraphInArcList(adaptor, n2, 1);
+ checkGraphInArcList(adaptor, n3, 2);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+
+ // Hide a node
+ adaptor.status(n1, false);
+ adaptor.disable(n3);
+ if (!adaptor.status(n3)) adaptor.enable(n3);
+
+ checkGraphNodeList(adaptor, 2);
+ checkGraphArcList(adaptor, 1);
+ checkGraphConArcList(adaptor, 1);
+
+ checkGraphOutArcList(adaptor, n2, 1);
+ checkGraphOutArcList(adaptor, n3, 0);
+
+ checkGraphInArcList(adaptor, n2, 0);
+ checkGraphInArcList(adaptor, n3, 1);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+
+ // Hide all nodes
+ node_filter[n1] = node_filter[n2] = node_filter[n3] = false;
+
+ checkGraphNodeList(adaptor, 0);
+ checkGraphArcList(adaptor, 0);
+ checkGraphConArcList(adaptor, 0);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+
+ // Check the conversion of nodes and arcs
+ Digraph::Node nd = n3;
+ nd = n3;
+ Adaptor::Node na = n1;
+ na = n2;
+ Digraph::Arc ad = a3;
+ ad = a3;
+ Adaptor::Arc aa = a1;
+ aa = a2;
+}
+
+void checkFilterArcs() {
+ // Check concepts
+ checkConcept<concepts::Digraph, FilterArcs<concepts::Digraph> >();
+ checkConcept<concepts::Digraph, FilterArcs<ListDigraph> >();
+ checkConcept<concepts::AlterableDigraphComponent<>,
+ FilterArcs<ListDigraph> >();
+ checkConcept<concepts::ExtendableDigraphComponent<>,
+ FilterArcs<ListDigraph> >();
+ checkConcept<concepts::ErasableDigraphComponent<>,
+ FilterArcs<ListDigraph> >();
+ checkConcept<concepts::ClearableDigraphComponent<>,
+ FilterArcs<ListDigraph> >();
+
+ // Create a digraph and an adaptor
+ typedef ListDigraph Digraph;
+ typedef Digraph::ArcMap<bool> ArcFilter;
+ typedef FilterArcs<Digraph, ArcFilter> Adaptor;
+
+ Digraph digraph;
+ ArcFilter arc_filter(digraph);
+ Adaptor adaptor(digraph, arc_filter);
+
+ // Add nodes and arcs to the original digraph and the adaptor
+ Digraph::Node n1 = digraph.addNode();
+ Digraph::Node n2 = digraph.addNode();
+ Adaptor::Node n3 = adaptor.addNode();
+
+ Digraph::Arc a1 = digraph.addArc(n1, n2);
+ Digraph::Arc a2 = digraph.addArc(n1, n3);
+ Adaptor::Arc a3 = adaptor.addArc(n2, n3);
+
+ arc_filter[a1] = arc_filter[a2] = arc_filter[a3] = true;
+
+ checkGraphNodeList(adaptor, 3);
+ checkGraphArcList(adaptor, 3);
+ checkGraphConArcList(adaptor, 3);
+
+ checkGraphOutArcList(adaptor, n1, 2);
+ checkGraphOutArcList(adaptor, n2, 1);
+ checkGraphOutArcList(adaptor, n3, 0);
+
+ checkGraphInArcList(adaptor, n1, 0);
+ checkGraphInArcList(adaptor, n2, 1);
+ checkGraphInArcList(adaptor, n3, 2);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+
+ // Hide an arc
+ adaptor.status(a2, false);
+ adaptor.disable(a3);
+ if (!adaptor.status(a3)) adaptor.enable(a3);
+
+ checkGraphNodeList(adaptor, 3);
+ checkGraphArcList(adaptor, 2);
+ checkGraphConArcList(adaptor, 2);
+
+ checkGraphOutArcList(adaptor, n1, 1);
+ checkGraphOutArcList(adaptor, n2, 1);
+ checkGraphOutArcList(adaptor, n3, 0);
+
+ checkGraphInArcList(adaptor, n1, 0);
+ checkGraphInArcList(adaptor, n2, 1);
+ checkGraphInArcList(adaptor, n3, 1);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+
+ // Hide all arcs
+ arc_filter[a1] = arc_filter[a2] = arc_filter[a3] = false;
+
+ checkGraphNodeList(adaptor, 3);
+ checkGraphArcList(adaptor, 0);
+ checkGraphConArcList(adaptor, 0);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+
+ // Check the conversion of nodes and arcs
+ Digraph::Node nd = n3;
+ nd = n3;
+ Adaptor::Node na = n1;
+ na = n2;
+ Digraph::Arc ad = a3;
+ ad = a3;
+ Adaptor::Arc aa = a1;
+ aa = a2;
+}
+
+void checkUndirector() {
+ // Check concepts
+ checkConcept<concepts::Graph, Undirector<concepts::Digraph> >();
+ checkConcept<concepts::Graph, Undirector<ListDigraph> >();
+ checkConcept<concepts::AlterableGraphComponent<>,
+ Undirector<ListDigraph> >();
+ checkConcept<concepts::ExtendableGraphComponent<>,
+ Undirector<ListDigraph> >();
+ checkConcept<concepts::ErasableGraphComponent<>,
+ Undirector<ListDigraph> >();
+ checkConcept<concepts::ClearableGraphComponent<>,
+ Undirector<ListDigraph> >();
+
+
+ // Create a digraph and an adaptor
+ typedef ListDigraph Digraph;
+ typedef Undirector<Digraph> Adaptor;
+
+ Digraph digraph;
+ Adaptor adaptor(digraph);
+
+ // Add nodes and arcs/edges to the original digraph and the adaptor
+ Digraph::Node n1 = digraph.addNode();
+ Digraph::Node n2 = digraph.addNode();
+ Adaptor::Node n3 = adaptor.addNode();
+
+ Digraph::Arc a1 = digraph.addArc(n1, n2);
+ Digraph::Arc a2 = digraph.addArc(n1, n3);
+ Adaptor::Edge e3 = adaptor.addEdge(n2, n3);
+
+ // Check the original digraph
+ checkGraphNodeList(digraph, 3);
+ checkGraphArcList(digraph, 3);
+ checkGraphConArcList(digraph, 3);
+
+ checkGraphOutArcList(digraph, n1, 2);
+ checkGraphOutArcList(digraph, n2, 1);
+ checkGraphOutArcList(digraph, n3, 0);
+
+ checkGraphInArcList(digraph, n1, 0);
+ checkGraphInArcList(digraph, n2, 1);
+ checkGraphInArcList(digraph, n3, 2);
+
+ checkNodeIds(digraph);
+ checkArcIds(digraph);
+
+ checkGraphNodeMap(digraph);
+ checkGraphArcMap(digraph);
+
+ // Check the adaptor
+ checkGraphNodeList(adaptor, 3);
+ checkGraphArcList(adaptor, 6);
+ checkGraphEdgeList(adaptor, 3);
+ checkGraphConArcList(adaptor, 6);
+ checkGraphConEdgeList(adaptor, 3);
+
+ checkGraphIncEdgeArcLists(adaptor, n1, 2);
+ checkGraphIncEdgeArcLists(adaptor, n2, 2);
+ checkGraphIncEdgeArcLists(adaptor, n3, 2);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+ checkEdgeIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+ checkGraphEdgeMap(adaptor);
+
+ // Check the edges of the adaptor
+ for (Adaptor::EdgeIt e(adaptor); e != INVALID; ++e) {
+ check(adaptor.u(e) == digraph.source(e), "Wrong undir");
+ check(adaptor.v(e) == digraph.target(e), "Wrong undir");
+ }
+
+ // Check CombinedArcMap
+ typedef Adaptor::CombinedArcMap
+ <Digraph::ArcMap<int>, Digraph::ArcMap<int> > IntCombinedMap;
+ typedef Adaptor::CombinedArcMap
+ <Digraph::ArcMap<bool>, Digraph::ArcMap<bool> > BoolCombinedMap;
+ checkConcept<concepts::ReferenceMap<Adaptor::Arc, int, int&, const int&>,
+ IntCombinedMap>();
+ checkConcept<concepts::ReferenceMap<Adaptor::Arc, bool, bool&, const bool&>,
+ BoolCombinedMap>();
+
+ Digraph::ArcMap<int> fw_map(digraph), bk_map(digraph);
+ for (Digraph::ArcIt a(digraph); a != INVALID; ++a) {
+ fw_map[a] = digraph.id(a);
+ bk_map[a] = -digraph.id(a);
+ }
+
+ Adaptor::CombinedArcMap<Digraph::ArcMap<int>, Digraph::ArcMap<int> >
+ comb_map(fw_map, bk_map);
+ for (Adaptor::ArcIt a(adaptor); a != INVALID; ++a) {
+ if (adaptor.source(a) == digraph.source(a)) {
+ check(comb_map[a] == fw_map[a], "Wrong combined map");
+ } else {
+ check(comb_map[a] == bk_map[a], "Wrong combined map");
+ }
+ }
+
+ // Check the conversion of nodes and arcs/edges
+ Digraph::Node nd = n3;
+ nd = n3;
+ Adaptor::Node na = n1;
+ na = n2;
+ Digraph::Arc ad = e3;
+ ad = e3;
+ Adaptor::Edge ea = a1;
+ ea = a2;
+}
+
+void checkResidualDigraph() {
+ // Check concepts
+ checkConcept<concepts::Digraph, ResidualDigraph<concepts::Digraph> >();
+ checkConcept<concepts::Digraph, ResidualDigraph<ListDigraph> >();
+
+ // Create a digraph and an adaptor
+ typedef ListDigraph Digraph;
+ typedef Digraph::ArcMap<int> IntArcMap;
+ typedef ResidualDigraph<Digraph, IntArcMap> Adaptor;
+
+ Digraph digraph;
+ IntArcMap capacity(digraph), flow(digraph);
+ Adaptor adaptor(digraph, capacity, flow);
+
+ Digraph::Node n1 = digraph.addNode();
+ Digraph::Node n2 = digraph.addNode();
+ Digraph::Node n3 = digraph.addNode();
+ Digraph::Node n4 = digraph.addNode();
+
+ Digraph::Arc a1 = digraph.addArc(n1, n2);
+ Digraph::Arc a2 = digraph.addArc(n1, n3);
+ Digraph::Arc a3 = digraph.addArc(n1, n4);
+ Digraph::Arc a4 = digraph.addArc(n2, n3);
+ Digraph::Arc a5 = digraph.addArc(n2, n4);
+ Digraph::Arc a6 = digraph.addArc(n3, n4);
+
+ capacity[a1] = 8;
+ capacity[a2] = 6;
+ capacity[a3] = 4;
+ capacity[a4] = 4;
+ capacity[a5] = 6;
+ capacity[a6] = 10;
+
+ // Check the adaptor with various flow values
+ for (Digraph::ArcIt a(digraph); a != INVALID; ++a) {
+ flow[a] = 0;
+ }
+
+ checkGraphNodeList(adaptor, 4);
+ checkGraphArcList(adaptor, 6);
+ checkGraphConArcList(adaptor, 6);
+
+ checkGraphOutArcList(adaptor, n1, 3);
+ checkGraphOutArcList(adaptor, n2, 2);
+ checkGraphOutArcList(adaptor, n3, 1);
+ checkGraphOutArcList(adaptor, n4, 0);
+
+ checkGraphInArcList(adaptor, n1, 0);
+ checkGraphInArcList(adaptor, n2, 1);
+ checkGraphInArcList(adaptor, n3, 2);
+ checkGraphInArcList(adaptor, n4, 3);
+
+ for (Digraph::ArcIt a(digraph); a != INVALID; ++a) {
+ flow[a] = capacity[a] / 2;
+ }
+
+ checkGraphNodeList(adaptor, 4);
+ checkGraphArcList(adaptor, 12);
+ checkGraphConArcList(adaptor, 12);
+
+ checkGraphOutArcList(adaptor, n1, 3);
+ checkGraphOutArcList(adaptor, n2, 3);
+ checkGraphOutArcList(adaptor, n3, 3);
+ checkGraphOutArcList(adaptor, n4, 3);
+
+ checkGraphInArcList(adaptor, n1, 3);
+ checkGraphInArcList(adaptor, n2, 3);
+ checkGraphInArcList(adaptor, n3, 3);
+ checkGraphInArcList(adaptor, n4, 3);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+
+ for (Digraph::ArcIt a(digraph); a != INVALID; ++a) {
+ flow[a] = capacity[a];
+ }
+
+ checkGraphNodeList(adaptor, 4);
+ checkGraphArcList(adaptor, 6);
+ checkGraphConArcList(adaptor, 6);
+
+ checkGraphOutArcList(adaptor, n1, 0);
+ checkGraphOutArcList(adaptor, n2, 1);
+ checkGraphOutArcList(adaptor, n3, 2);
+ checkGraphOutArcList(adaptor, n4, 3);
+
+ checkGraphInArcList(adaptor, n1, 3);
+ checkGraphInArcList(adaptor, n2, 2);
+ checkGraphInArcList(adaptor, n3, 1);
+ checkGraphInArcList(adaptor, n4, 0);
+
+ // Saturate all backward arcs
+ // (set the flow to zero on all forward arcs)
+ for (Adaptor::ArcIt a(adaptor); a != INVALID; ++a) {
+ if (adaptor.backward(a))
+ adaptor.augment(a, adaptor.residualCapacity(a));
+ }
+
+ checkGraphNodeList(adaptor, 4);
+ checkGraphArcList(adaptor, 6);
+ checkGraphConArcList(adaptor, 6);
+
+ checkGraphOutArcList(adaptor, n1, 3);
+ checkGraphOutArcList(adaptor, n2, 2);
+ checkGraphOutArcList(adaptor, n3, 1);
+ checkGraphOutArcList(adaptor, n4, 0);
+
+ checkGraphInArcList(adaptor, n1, 0);
+ checkGraphInArcList(adaptor, n2, 1);
+ checkGraphInArcList(adaptor, n3, 2);
+ checkGraphInArcList(adaptor, n4, 3);
+
+ // Find maximum flow by augmenting along shortest paths
+ int flow_value = 0;
+ Adaptor::ResidualCapacity res_cap(adaptor);
+ while (true) {
+
+ Bfs<Adaptor> bfs(adaptor);
+ bfs.run(n1, n4);
+
+ if (!bfs.reached(n4)) break;
+
+ Path<Adaptor> p = bfs.path(n4);
+
+ int min = std::numeric_limits<int>::max();
+ for (Path<Adaptor>::ArcIt a(p); a != INVALID; ++a) {
+ if (res_cap[a] < min) min = res_cap[a];
+ }
+
+ for (Path<Adaptor>::ArcIt a(p); a != INVALID; ++a) {
+ adaptor.augment(a, min);
+ }
+ flow_value += min;
+ }
+
+ check(flow_value == 18, "Wrong flow with res graph adaptor");
+
+ // Check forward() and backward()
+ for (Adaptor::ArcIt a(adaptor); a != INVALID; ++a) {
+ check(adaptor.forward(a) != adaptor.backward(a),
+ "Wrong forward() or backward()");
+ check((adaptor.forward(a) && adaptor.forward(Digraph::Arc(a)) == a) ||
+ (adaptor.backward(a) && adaptor.backward(Digraph::Arc(a)) == a),
+ "Wrong forward() or backward()");
+ }
+
+ // Check the conversion of nodes and arcs
+ Digraph::Node nd = Adaptor::NodeIt(adaptor);
+ nd = ++Adaptor::NodeIt(adaptor);
+ Adaptor::Node na = n1;
+ na = n2;
+ Digraph::Arc ad = Adaptor::ArcIt(adaptor);
+ ad = ++Adaptor::ArcIt(adaptor);
+}
+
+void checkSplitNodes() {
+ // Check concepts
+ checkConcept<concepts::Digraph, SplitNodes<concepts::Digraph> >();
+ checkConcept<concepts::Digraph, SplitNodes<ListDigraph> >();
+
+ // Create a digraph and an adaptor
+ typedef ListDigraph Digraph;
+ typedef SplitNodes<Digraph> Adaptor;
+
+ Digraph digraph;
+ Adaptor adaptor(digraph);
+
+ Digraph::Node n1 = digraph.addNode();
+ Digraph::Node n2 = digraph.addNode();
+ Digraph::Node n3 = digraph.addNode();
+
+ Digraph::Arc a1 = digraph.addArc(n1, n2);
+ Digraph::Arc a2 = digraph.addArc(n1, n3);
+ Digraph::Arc a3 = digraph.addArc(n2, n3);
+ ::lemon::ignore_unused_variable_warning(a1,a2,a3);
+
+ checkGraphNodeList(adaptor, 6);
+ checkGraphArcList(adaptor, 6);
+ checkGraphConArcList(adaptor, 6);
+
+ checkGraphOutArcList(adaptor, adaptor.inNode(n1), 1);
+ checkGraphOutArcList(adaptor, adaptor.outNode(n1), 2);
+ checkGraphOutArcList(adaptor, adaptor.inNode(n2), 1);
+ checkGraphOutArcList(adaptor, adaptor.outNode(n2), 1);
+ checkGraphOutArcList(adaptor, adaptor.inNode(n3), 1);
+ checkGraphOutArcList(adaptor, adaptor.outNode(n3), 0);
+
+ checkGraphInArcList(adaptor, adaptor.inNode(n1), 0);
+ checkGraphInArcList(adaptor, adaptor.outNode(n1), 1);
+ checkGraphInArcList(adaptor, adaptor.inNode(n2), 1);
+ checkGraphInArcList(adaptor, adaptor.outNode(n2), 1);
+ checkGraphInArcList(adaptor, adaptor.inNode(n3), 2);
+ checkGraphInArcList(adaptor, adaptor.outNode(n3), 1);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+
+ // Check split
+ for (Adaptor::ArcIt a(adaptor); a != INVALID; ++a) {
+ if (adaptor.origArc(a)) {
+ Digraph::Arc oa = a;
+ check(adaptor.source(a) == adaptor.outNode(digraph.source(oa)),
+ "Wrong split");
+ check(adaptor.target(a) == adaptor.inNode(digraph.target(oa)),
+ "Wrong split");
+ } else {
+ Digraph::Node on = a;
+ check(adaptor.source(a) == adaptor.inNode(on), "Wrong split");
+ check(adaptor.target(a) == adaptor.outNode(on), "Wrong split");
+ }
+ }
+
+ // Check combined node map
+ typedef Adaptor::CombinedNodeMap
+ <Digraph::NodeMap<int>, Digraph::NodeMap<int> > IntCombinedNodeMap;
+ typedef Adaptor::CombinedNodeMap
+ <Digraph::NodeMap<bool>, Digraph::NodeMap<bool> > BoolCombinedNodeMap;
+ checkConcept<concepts::ReferenceMap<Adaptor::Node, int, int&, const int&>,
+ IntCombinedNodeMap>();
+//checkConcept<concepts::ReferenceMap<Adaptor::Node, bool, bool&, const bool&>,
+// BoolCombinedNodeMap>();
+ checkConcept<concepts::ReadWriteMap<Adaptor::Node, bool>,
+ BoolCombinedNodeMap>();
+
+ Digraph::NodeMap<int> in_map(digraph), out_map(digraph);
+ for (Digraph::NodeIt n(digraph); n != INVALID; ++n) {
+ in_map[n] = digraph.id(n);
+ out_map[n] = -digraph.id(n);
+ }
+
+ Adaptor::CombinedNodeMap<Digraph::NodeMap<int>, Digraph::NodeMap<int> >
+ node_map(in_map, out_map);
+ for (Adaptor::NodeIt n(adaptor); n != INVALID; ++n) {
+ if (adaptor.inNode(n)) {
+ check(node_map[n] == in_map[n], "Wrong combined node map");
+ } else {
+ check(node_map[n] == out_map[n], "Wrong combined node map");
+ }
+ }
+
+ // Check combined arc map
+ typedef Adaptor::CombinedArcMap
+ <Digraph::ArcMap<int>, Digraph::NodeMap<int> > IntCombinedArcMap;
+ typedef Adaptor::CombinedArcMap
+ <Digraph::ArcMap<bool>, Digraph::NodeMap<bool> > BoolCombinedArcMap;
+ checkConcept<concepts::ReferenceMap<Adaptor::Arc, int, int&, const int&>,
+ IntCombinedArcMap>();
+//checkConcept<concepts::ReferenceMap<Adaptor::Arc, bool, bool&, const bool&>,
+// BoolCombinedArcMap>();
+ checkConcept<concepts::ReadWriteMap<Adaptor::Arc, bool>,
+ BoolCombinedArcMap>();
+
+ Digraph::ArcMap<int> a_map(digraph);
+ for (Digraph::ArcIt a(digraph); a != INVALID; ++a) {
+ a_map[a] = digraph.id(a);
+ }
+
+ Adaptor::CombinedArcMap<Digraph::ArcMap<int>, Digraph::NodeMap<int> >
+ arc_map(a_map, out_map);
+ for (Digraph::ArcIt a(digraph); a != INVALID; ++a) {
+ check(arc_map[adaptor.arc(a)] == a_map[a], "Wrong combined arc map");
+ }
+ for (Digraph::NodeIt n(digraph); n != INVALID; ++n) {
+ check(arc_map[adaptor.arc(n)] == out_map[n], "Wrong combined arc map");
+ }
+
+ // Check the conversion of nodes
+ Digraph::Node nd = adaptor.inNode(n1);
+ check (nd == n1, "Wrong node conversion");
+ nd = adaptor.outNode(n2);
+ check (nd == n2, "Wrong node conversion");
+}
+
+void checkSubGraph() {
+ // Check concepts
+ checkConcept<concepts::Graph, SubGraph<concepts::Graph> >();
+ checkConcept<concepts::Graph, SubGraph<ListGraph> >();
+ checkConcept<concepts::AlterableGraphComponent<>,
+ SubGraph<ListGraph> >();
+ checkConcept<concepts::ExtendableGraphComponent<>,
+ SubGraph<ListGraph> >();
+ checkConcept<concepts::ErasableGraphComponent<>,
+ SubGraph<ListGraph> >();
+ checkConcept<concepts::ClearableGraphComponent<>,
+ SubGraph<ListGraph> >();
+
+ // Create a graph and an adaptor
+ typedef ListGraph Graph;
+ typedef Graph::NodeMap<bool> NodeFilter;
+ typedef Graph::EdgeMap<bool> EdgeFilter;
+ typedef SubGraph<Graph, NodeFilter, EdgeFilter> Adaptor;
+
+ Graph graph;
+ NodeFilter node_filter(graph);
+ EdgeFilter edge_filter(graph);
+ Adaptor adaptor(graph, node_filter, edge_filter);
+
+ // Add nodes and edges to the original graph and the adaptor
+ Graph::Node n1 = graph.addNode();
+ Graph::Node n2 = graph.addNode();
+ Adaptor::Node n3 = adaptor.addNode();
+ Adaptor::Node n4 = adaptor.addNode();
+
+ node_filter[n1] = node_filter[n2] = node_filter[n3] = node_filter[n4] = true;
+
+ Graph::Edge e1 = graph.addEdge(n1, n2);
+ Graph::Edge e2 = graph.addEdge(n1, n3);
+ Adaptor::Edge e3 = adaptor.addEdge(n2, n3);
+ Adaptor::Edge e4 = adaptor.addEdge(n3, n4);
+
+ edge_filter[e1] = edge_filter[e2] = edge_filter[e3] = edge_filter[e4] = true;
+
+ checkGraphNodeList(adaptor, 4);
+ checkGraphArcList(adaptor, 8);
+ checkGraphEdgeList(adaptor, 4);
+ checkGraphConArcList(adaptor, 8);
+ checkGraphConEdgeList(adaptor, 4);
+
+ checkGraphIncEdgeArcLists(adaptor, n1, 2);
+ checkGraphIncEdgeArcLists(adaptor, n2, 2);
+ checkGraphIncEdgeArcLists(adaptor, n3, 3);
+ checkGraphIncEdgeArcLists(adaptor, n4, 1);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+ checkEdgeIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+ checkGraphEdgeMap(adaptor);
+
+ // Hide an edge
+ adaptor.status(e2, false);
+ adaptor.disable(e3);
+ if (!adaptor.status(e3)) adaptor.enable(e3);
+
+ checkGraphNodeList(adaptor, 4);
+ checkGraphArcList(adaptor, 6);
+ checkGraphEdgeList(adaptor, 3);
+ checkGraphConArcList(adaptor, 6);
+ checkGraphConEdgeList(adaptor, 3);
+
+ checkGraphIncEdgeArcLists(adaptor, n1, 1);
+ checkGraphIncEdgeArcLists(adaptor, n2, 2);
+ checkGraphIncEdgeArcLists(adaptor, n3, 2);
+ checkGraphIncEdgeArcLists(adaptor, n4, 1);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+ checkEdgeIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+ checkGraphEdgeMap(adaptor);
+
+ // Hide a node
+ adaptor.status(n1, false);
+ adaptor.disable(n3);
+ if (!adaptor.status(n3)) adaptor.enable(n3);
+
+ checkGraphNodeList(adaptor, 3);
+ checkGraphArcList(adaptor, 4);
+ checkGraphEdgeList(adaptor, 2);
+ checkGraphConArcList(adaptor, 4);
+ checkGraphConEdgeList(adaptor, 2);
+
+ checkGraphIncEdgeArcLists(adaptor, n2, 1);
+ checkGraphIncEdgeArcLists(adaptor, n3, 2);
+ checkGraphIncEdgeArcLists(adaptor, n4, 1);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+ checkEdgeIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+ checkGraphEdgeMap(adaptor);
+
+ // Hide all nodes and edges
+ node_filter[n1] = node_filter[n2] = node_filter[n3] = node_filter[n4] = false;
+ edge_filter[e1] = edge_filter[e2] = edge_filter[e3] = edge_filter[e4] = false;
+
+ checkGraphNodeList(adaptor, 0);
+ checkGraphArcList(adaptor, 0);
+ checkGraphEdgeList(adaptor, 0);
+ checkGraphConArcList(adaptor, 0);
+ checkGraphConEdgeList(adaptor, 0);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+ checkEdgeIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+ checkGraphEdgeMap(adaptor);
+
+ // Check the conversion of nodes and edges
+ Graph::Node ng = n3;
+ ng = n4;
+ Adaptor::Node na = n1;
+ na = n2;
+ Graph::Edge eg = e3;
+ eg = e4;
+ Adaptor::Edge ea = e1;
+ ea = e2;
+}
+
+void checkFilterNodes2() {
+ // Check concepts
+ checkConcept<concepts::Graph, FilterNodes<concepts::Graph> >();
+ checkConcept<concepts::Graph, FilterNodes<ListGraph> >();
+ checkConcept<concepts::AlterableGraphComponent<>,
+ FilterNodes<ListGraph> >();
+ checkConcept<concepts::ExtendableGraphComponent<>,
+ FilterNodes<ListGraph> >();
+ checkConcept<concepts::ErasableGraphComponent<>,
+ FilterNodes<ListGraph> >();
+ checkConcept<concepts::ClearableGraphComponent<>,
+ FilterNodes<ListGraph> >();
+
+ // Create a graph and an adaptor
+ typedef ListGraph Graph;
+ typedef Graph::NodeMap<bool> NodeFilter;
+ typedef FilterNodes<Graph, NodeFilter> Adaptor;
+
+ // Add nodes and edges to the original graph and the adaptor
+ Graph graph;
+ NodeFilter node_filter(graph);
+ Adaptor adaptor(graph, node_filter);
+
+ Graph::Node n1 = graph.addNode();
+ Graph::Node n2 = graph.addNode();
+ Adaptor::Node n3 = adaptor.addNode();
+ Adaptor::Node n4 = adaptor.addNode();
+
+ node_filter[n1] = node_filter[n2] = node_filter[n3] = node_filter[n4] = true;
+
+ Graph::Edge e1 = graph.addEdge(n1, n2);
+ Graph::Edge e2 = graph.addEdge(n1, n3);
+ Adaptor::Edge e3 = adaptor.addEdge(n2, n3);
+ Adaptor::Edge e4 = adaptor.addEdge(n3, n4);
+
+ checkGraphNodeList(adaptor, 4);
+ checkGraphArcList(adaptor, 8);
+ checkGraphEdgeList(adaptor, 4);
+ checkGraphConArcList(adaptor, 8);
+ checkGraphConEdgeList(adaptor, 4);
+
+ checkGraphIncEdgeArcLists(adaptor, n1, 2);
+ checkGraphIncEdgeArcLists(adaptor, n2, 2);
+ checkGraphIncEdgeArcLists(adaptor, n3, 3);
+ checkGraphIncEdgeArcLists(adaptor, n4, 1);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+ checkEdgeIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+ checkGraphEdgeMap(adaptor);
+
+ // Hide a node
+ adaptor.status(n1, false);
+ adaptor.disable(n3);
+ if (!adaptor.status(n3)) adaptor.enable(n3);
+
+ checkGraphNodeList(adaptor, 3);
+ checkGraphArcList(adaptor, 4);
+ checkGraphEdgeList(adaptor, 2);
+ checkGraphConArcList(adaptor, 4);
+ checkGraphConEdgeList(adaptor, 2);
+
+ checkGraphIncEdgeArcLists(adaptor, n2, 1);
+ checkGraphIncEdgeArcLists(adaptor, n3, 2);
+ checkGraphIncEdgeArcLists(adaptor, n4, 1);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+ checkEdgeIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+ checkGraphEdgeMap(adaptor);
+
+ // Hide all nodes
+ node_filter[n1] = node_filter[n2] = node_filter[n3] = node_filter[n4] = false;
+
+ checkGraphNodeList(adaptor, 0);
+ checkGraphArcList(adaptor, 0);
+ checkGraphEdgeList(adaptor, 0);
+ checkGraphConArcList(adaptor, 0);
+ checkGraphConEdgeList(adaptor, 0);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+ checkEdgeIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+ checkGraphEdgeMap(adaptor);
+
+ // Check the conversion of nodes and edges
+ Graph::Node ng = n3;
+ ng = n4;
+ Adaptor::Node na = n1;
+ na = n2;
+ Graph::Edge eg = e3;
+ eg = e4;
+ Adaptor::Edge ea = e1;
+ ea = e2;
+}
+
+void checkFilterEdges() {
+ // Check concepts
+ checkConcept<concepts::Graph, FilterEdges<concepts::Graph> >();
+ checkConcept<concepts::Graph, FilterEdges<ListGraph> >();
+ checkConcept<concepts::AlterableGraphComponent<>,
+ FilterEdges<ListGraph> >();
+ checkConcept<concepts::ExtendableGraphComponent<>,
+ FilterEdges<ListGraph> >();
+ checkConcept<concepts::ErasableGraphComponent<>,
+ FilterEdges<ListGraph> >();
+ checkConcept<concepts::ClearableGraphComponent<>,
+ FilterEdges<ListGraph> >();
+
+ // Create a graph and an adaptor
+ typedef ListGraph Graph;
+ typedef Graph::EdgeMap<bool> EdgeFilter;
+ typedef FilterEdges<Graph, EdgeFilter> Adaptor;
+
+ Graph graph;
+ EdgeFilter edge_filter(graph);
+ Adaptor adaptor(graph, edge_filter);
+
+ // Add nodes and edges to the original graph and the adaptor
+ Graph::Node n1 = graph.addNode();
+ Graph::Node n2 = graph.addNode();
+ Adaptor::Node n3 = adaptor.addNode();
+ Adaptor::Node n4 = adaptor.addNode();
+
+ Graph::Edge e1 = graph.addEdge(n1, n2);
+ Graph::Edge e2 = graph.addEdge(n1, n3);
+ Adaptor::Edge e3 = adaptor.addEdge(n2, n3);
+ Adaptor::Edge e4 = adaptor.addEdge(n3, n4);
+
+ edge_filter[e1] = edge_filter[e2] = edge_filter[e3] = edge_filter[e4] = true;
+
+ checkGraphNodeList(adaptor, 4);
+ checkGraphArcList(adaptor, 8);
+ checkGraphEdgeList(adaptor, 4);
+ checkGraphConArcList(adaptor, 8);
+ checkGraphConEdgeList(adaptor, 4);
+
+ checkGraphIncEdgeArcLists(adaptor, n1, 2);
+ checkGraphIncEdgeArcLists(adaptor, n2, 2);
+ checkGraphIncEdgeArcLists(adaptor, n3, 3);
+ checkGraphIncEdgeArcLists(adaptor, n4, 1);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+ checkEdgeIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+ checkGraphEdgeMap(adaptor);
+
+ // Hide an edge
+ adaptor.status(e2, false);
+ adaptor.disable(e3);
+ if (!adaptor.status(e3)) adaptor.enable(e3);
+
+ checkGraphNodeList(adaptor, 4);
+ checkGraphArcList(adaptor, 6);
+ checkGraphEdgeList(adaptor, 3);
+ checkGraphConArcList(adaptor, 6);
+ checkGraphConEdgeList(adaptor, 3);
+
+ checkGraphIncEdgeArcLists(adaptor, n1, 1);
+ checkGraphIncEdgeArcLists(adaptor, n2, 2);
+ checkGraphIncEdgeArcLists(adaptor, n3, 2);
+ checkGraphIncEdgeArcLists(adaptor, n4, 1);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+ checkEdgeIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+ checkGraphEdgeMap(adaptor);
+
+ // Hide all edges
+ edge_filter[e1] = edge_filter[e2] = edge_filter[e3] = edge_filter[e4] = false;
+
+ checkGraphNodeList(adaptor, 4);
+ checkGraphArcList(adaptor, 0);
+ checkGraphEdgeList(adaptor, 0);
+ checkGraphConArcList(adaptor, 0);
+ checkGraphConEdgeList(adaptor, 0);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+ checkEdgeIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+ checkGraphEdgeMap(adaptor);
+
+ // Check the conversion of nodes and edges
+ Graph::Node ng = n3;
+ ng = n4;
+ Adaptor::Node na = n1;
+ na = n2;
+ Graph::Edge eg = e3;
+ eg = e4;
+ Adaptor::Edge ea = e1;
+ ea = e2;
+}
+
+void checkOrienter() {
+ // Check concepts
+ checkConcept<concepts::Digraph, Orienter<concepts::Graph> >();
+ checkConcept<concepts::Digraph, Orienter<ListGraph> >();
+ checkConcept<concepts::AlterableDigraphComponent<>,
+ Orienter<ListGraph> >();
+ checkConcept<concepts::ExtendableDigraphComponent<>,
+ Orienter<ListGraph> >();
+ checkConcept<concepts::ErasableDigraphComponent<>,
+ Orienter<ListGraph> >();
+ checkConcept<concepts::ClearableDigraphComponent<>,
+ Orienter<ListGraph> >();
+
+ // Create a graph and an adaptor
+ typedef ListGraph Graph;
+ typedef ListGraph::EdgeMap<bool> DirMap;
+ typedef Orienter<Graph> Adaptor;
+
+ Graph graph;
+ DirMap dir(graph);
+ Adaptor adaptor(graph, dir);
+
+ // Add nodes and edges to the original graph and the adaptor
+ Graph::Node n1 = graph.addNode();
+ Graph::Node n2 = graph.addNode();
+ Adaptor::Node n3 = adaptor.addNode();
+
+ Graph::Edge e1 = graph.addEdge(n1, n2);
+ Graph::Edge e2 = graph.addEdge(n1, n3);
+ Adaptor::Arc e3 = adaptor.addArc(n2, n3);
+
+ dir[e1] = dir[e2] = dir[e3] = true;
+
+ // Check the original graph
+ checkGraphNodeList(graph, 3);
+ checkGraphArcList(graph, 6);
+ checkGraphConArcList(graph, 6);
+ checkGraphEdgeList(graph, 3);
+ checkGraphConEdgeList(graph, 3);
+
+ checkGraphIncEdgeArcLists(graph, n1, 2);
+ checkGraphIncEdgeArcLists(graph, n2, 2);
+ checkGraphIncEdgeArcLists(graph, n3, 2);
+
+ checkNodeIds(graph);
+ checkArcIds(graph);
+ checkEdgeIds(graph);
+
+ checkGraphNodeMap(graph);
+ checkGraphArcMap(graph);
+ checkGraphEdgeMap(graph);
+
+ // Check the adaptor
+ checkGraphNodeList(adaptor, 3);
+ checkGraphArcList(adaptor, 3);
+ checkGraphConArcList(adaptor, 3);
+
+ checkGraphOutArcList(adaptor, n1, 2);
+ checkGraphOutArcList(adaptor, n2, 1);
+ checkGraphOutArcList(adaptor, n3, 0);
+
+ checkGraphInArcList(adaptor, n1, 0);
+ checkGraphInArcList(adaptor, n2, 1);
+ checkGraphInArcList(adaptor, n3, 2);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+
+ // Check direction changing
+ {
+ dir[e1] = true;
+ Adaptor::Node u = adaptor.source(e1);
+ Adaptor::Node v = adaptor.target(e1);
+
+ dir[e1] = false;
+ check (u == adaptor.target(e1), "Wrong dir");
+ check (v == adaptor.source(e1), "Wrong dir");
+
+ check ((u == n1 && v == n2) || (u == n2 && v == n1), "Wrong dir");
+ dir[e1] = n1 == u;
+ }
+
+ {
+ dir[e2] = true;
+ Adaptor::Node u = adaptor.source(e2);
+ Adaptor::Node v = adaptor.target(e2);
+
+ dir[e2] = false;
+ check (u == adaptor.target(e2), "Wrong dir");
+ check (v == adaptor.source(e2), "Wrong dir");
+
+ check ((u == n1 && v == n3) || (u == n3 && v == n1), "Wrong dir");
+ dir[e2] = n3 == u;
+ }
+
+ {
+ dir[e3] = true;
+ Adaptor::Node u = adaptor.source(e3);
+ Adaptor::Node v = adaptor.target(e3);
+
+ dir[e3] = false;
+ check (u == adaptor.target(e3), "Wrong dir");
+ check (v == adaptor.source(e3), "Wrong dir");
+
+ check ((u == n2 && v == n3) || (u == n3 && v == n2), "Wrong dir");
+ dir[e3] = n2 == u;
+ }
+
+ // Check the adaptor again
+ checkGraphNodeList(adaptor, 3);
+ checkGraphArcList(adaptor, 3);
+ checkGraphConArcList(adaptor, 3);
+
+ checkGraphOutArcList(adaptor, n1, 1);
+ checkGraphOutArcList(adaptor, n2, 1);
+ checkGraphOutArcList(adaptor, n3, 1);
+
+ checkGraphInArcList(adaptor, n1, 1);
+ checkGraphInArcList(adaptor, n2, 1);
+ checkGraphInArcList(adaptor, n3, 1);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+
+ // Check reverseArc()
+ adaptor.reverseArc(e2);
+ adaptor.reverseArc(e3);
+ adaptor.reverseArc(e2);
+
+ checkGraphNodeList(adaptor, 3);
+ checkGraphArcList(adaptor, 3);
+ checkGraphConArcList(adaptor, 3);
+
+ checkGraphOutArcList(adaptor, n1, 1);
+ checkGraphOutArcList(adaptor, n2, 0);
+ checkGraphOutArcList(adaptor, n3, 2);
+
+ checkGraphInArcList(adaptor, n1, 1);
+ checkGraphInArcList(adaptor, n2, 2);
+ checkGraphInArcList(adaptor, n3, 0);
+
+ // Check the conversion of nodes and arcs/edges
+ Graph::Node ng = n3;
+ ng = n3;
+ Adaptor::Node na = n1;
+ na = n2;
+ Graph::Edge eg = e3;
+ eg = e3;
+ Adaptor::Arc aa = e1;
+ aa = e2;
+}
+
+void checkCombiningAdaptors() {
+ // Create a grid graph
+ GridGraph graph(2,2);
+ GridGraph::Node n1 = graph(0,0);
+ GridGraph::Node n2 = graph(0,1);
+ GridGraph::Node n3 = graph(1,0);
+ GridGraph::Node n4 = graph(1,1);
+
+ GridGraph::EdgeMap<bool> dir_map(graph);
+ dir_map[graph.right(n1)] = graph.u(graph.right(n1)) != n1;
+ dir_map[graph.up(n1)] = graph.u(graph.up(n1)) == n1;
+ dir_map[graph.left(n4)] = graph.u(graph.left(n4)) == n4;
+ dir_map[graph.down(n4)] = graph.u(graph.down(n4)) == n4;
+
+ // Apply several adaptors on the grid graph
+ typedef Orienter< const GridGraph, GridGraph::EdgeMap<bool> >
+ OrientedGridGraph;
+ typedef SplitNodes<OrientedGridGraph> SplitGridGraph;
+ typedef Undirector<const SplitGridGraph> USplitGridGraph;
+ checkConcept<concepts::Digraph, SplitGridGraph>();
+ checkConcept<concepts::Graph, USplitGridGraph>();
+
+ OrientedGridGraph oadaptor = orienter(graph, dir_map);
+ SplitGridGraph adaptor = splitNodes(oadaptor);
+ USplitGridGraph uadaptor = undirector(adaptor);
+
+ // Check adaptor
+ checkGraphNodeList(adaptor, 8);
+ checkGraphArcList(adaptor, 8);
+ checkGraphConArcList(adaptor, 8);
+
+ checkGraphOutArcList(adaptor, adaptor.inNode(n1), 1);
+ checkGraphOutArcList(adaptor, adaptor.outNode(n1), 1);
+ checkGraphOutArcList(adaptor, adaptor.inNode(n2), 1);
+ checkGraphOutArcList(adaptor, adaptor.outNode(n2), 0);
+ checkGraphOutArcList(adaptor, adaptor.inNode(n3), 1);
+ checkGraphOutArcList(adaptor, adaptor.outNode(n3), 1);
+ checkGraphOutArcList(adaptor, adaptor.inNode(n4), 1);
+ checkGraphOutArcList(adaptor, adaptor.outNode(n4), 2);
+
+ checkGraphInArcList(adaptor, adaptor.inNode(n1), 1);
+ checkGraphInArcList(adaptor, adaptor.outNode(n1), 1);
+ checkGraphInArcList(adaptor, adaptor.inNode(n2), 2);
+ checkGraphInArcList(adaptor, adaptor.outNode(n2), 1);
+ checkGraphInArcList(adaptor, adaptor.inNode(n3), 1);
+ checkGraphInArcList(adaptor, adaptor.outNode(n3), 1);
+ checkGraphInArcList(adaptor, adaptor.inNode(n4), 0);
+ checkGraphInArcList(adaptor, adaptor.outNode(n4), 1);
+
+ checkNodeIds(adaptor);
+ checkArcIds(adaptor);
+
+ checkGraphNodeMap(adaptor);
+ checkGraphArcMap(adaptor);
+
+ // Check uadaptor
+ checkGraphNodeList(uadaptor, 8);
+ checkGraphEdgeList(uadaptor, 8);
+ checkGraphArcList(uadaptor, 16);
+ checkGraphConEdgeList(uadaptor, 8);
+ checkGraphConArcList(uadaptor, 16);
+
+ checkNodeIds(uadaptor);
+ checkEdgeIds(uadaptor);
+ checkArcIds(uadaptor);
+
+ checkGraphNodeMap(uadaptor);
+ checkGraphEdgeMap(uadaptor);
+ checkGraphArcMap(uadaptor);
+
+ checkGraphIncEdgeArcLists(uadaptor, adaptor.inNode(n1), 2);
+ checkGraphIncEdgeArcLists(uadaptor, adaptor.outNode(n1), 2);
+ checkGraphIncEdgeArcLists(uadaptor, adaptor.inNode(n2), 3);
+ checkGraphIncEdgeArcLists(uadaptor, adaptor.outNode(n2), 1);
+ checkGraphIncEdgeArcLists(uadaptor, adaptor.inNode(n3), 2);
+ checkGraphIncEdgeArcLists(uadaptor, adaptor.outNode(n3), 2);
+ checkGraphIncEdgeArcLists(uadaptor, adaptor.inNode(n4), 1);
+ checkGraphIncEdgeArcLists(uadaptor, adaptor.outNode(n4), 3);
+}
+
+int main(int, const char **) {
+ // Check the digraph adaptors (using ListDigraph)
+ checkReverseDigraph();
+ checkSubDigraph();
+ checkFilterNodes1();
+ checkFilterArcs();
+ checkUndirector();
+ checkResidualDigraph();
+ checkSplitNodes();
+
+ // Check the graph adaptors (using ListGraph)
+ checkSubGraph();
+ checkFilterNodes2();
+ checkFilterEdges();
+ checkOrienter();
+
+ // Combine adaptors (using GridGraph)
+ checkCombiningAdaptors();
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/arc_look_up_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/arc_look_up_test.cc
new file mode 100644
index 00000000000..2f4edf52d66
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/arc_look_up_test.cc
@@ -0,0 +1,84 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <iostream>
+#include "lemon/list_graph.h"
+#include "lemon/lgf_reader.h"
+
+#include "test_tools.h"
+
+using namespace lemon;
+
+const std::string lgf =
+ "@nodes\n"
+"label\n"
+"0\n"
+"1\n"
+"2\n"
+"3\n"
+"4\n"
+"5\n"
+"6\n"
+"@arcs\n"
+"label\n"
+"5 6 0\n"
+"5 4 1\n"
+"4 6 2\n"
+"3 4 3\n"
+"3 4 4\n"
+"3 2 5\n"
+"3 5 6\n"
+"3 5 7\n"
+"3 5 8\n"
+"3 5 9\n"
+"2 4 10\n"
+"2 4 11\n"
+"2 4 12\n"
+"2 4 13\n"
+"1 2 14\n"
+"1 2 15\n"
+"1 0 16\n"
+"1 3 17\n"
+"1 3 18\n"
+"1 3 19\n"
+"1 3 20\n"
+"0 2 21\n"
+"0 2 22\n"
+"0 2 23\n"
+"0 2 24\n";
+
+
+int main() {
+ ListDigraph graph;
+ std::istringstream lgfs(lgf);
+ DigraphReader<ListDigraph>(graph, lgfs).run();
+
+ AllArcLookUp<ListDigraph> lookup(graph);
+
+ int numArcs = countArcs(graph);
+
+ int arcCnt = 0;
+ for(ListDigraph::NodeIt n1(graph); n1 != INVALID; ++n1)
+ for(ListDigraph::NodeIt n2(graph); n2 != INVALID; ++n2)
+ for(ListDigraph::Arc a = lookup(n1, n2); a != INVALID;
+ a = lookup(n1, n2, a))
+ ++arcCnt;
+ check(arcCnt==numArcs, "Wrong total number of arcs");
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/bellman_ford_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/bellman_ford_test.cc
new file mode 100644
index 00000000000..14faa07c961
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/bellman_ford_test.cc
@@ -0,0 +1,289 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <lemon/concepts/digraph.h>
+#include <lemon/smart_graph.h>
+#include <lemon/list_graph.h>
+#include <lemon/lgf_reader.h>
+#include <lemon/bellman_ford.h>
+#include <lemon/path.h>
+
+#include "graph_test.h"
+#include "test_tools.h"
+
+using namespace lemon;
+
+char test_lgf[] =
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "@arcs\n"
+ " length\n"
+ "0 1 3\n"
+ "1 2 -3\n"
+ "1 2 -5\n"
+ "1 3 -2\n"
+ "0 2 -1\n"
+ "1 2 -4\n"
+ "0 3 2\n"
+ "4 2 -5\n"
+ "2 3 1\n"
+ "@attributes\n"
+ "source 0\n"
+ "target 3\n";
+
+
+void checkBellmanFordCompile()
+{
+ typedef int Value;
+ typedef concepts::Digraph Digraph;
+ typedef concepts::ReadMap<Digraph::Arc,Value> LengthMap;
+ typedef BellmanFord<Digraph, LengthMap> BF;
+ typedef Digraph::Node Node;
+ typedef Digraph::Arc Arc;
+
+ Digraph gr;
+ Node s, t, n;
+ Arc e;
+ Value l;
+ ::lemon::ignore_unused_variable_warning(l);
+ int k=3;
+ bool b;
+ ::lemon::ignore_unused_variable_warning(b);
+ BF::DistMap d(gr);
+ BF::PredMap p(gr);
+ LengthMap length;
+ concepts::Path<Digraph> pp;
+
+ {
+ BF bf_test(gr,length);
+ const BF& const_bf_test = bf_test;
+
+ bf_test.run(s);
+ bf_test.run(s,k);
+
+ bf_test.init();
+ bf_test.addSource(s);
+ bf_test.addSource(s, 1);
+ b = bf_test.processNextRound();
+ b = bf_test.processNextWeakRound();
+
+ bf_test.start();
+ bf_test.checkedStart();
+ bf_test.limitedStart(k);
+
+ l = const_bf_test.dist(t);
+ e = const_bf_test.predArc(t);
+ s = const_bf_test.predNode(t);
+ b = const_bf_test.reached(t);
+ d = const_bf_test.distMap();
+ p = const_bf_test.predMap();
+ pp = const_bf_test.path(t);
+ pp = const_bf_test.negativeCycle();
+
+ for (BF::ActiveIt it(const_bf_test); it != INVALID; ++it) {}
+ }
+ {
+ BF::SetPredMap<concepts::ReadWriteMap<Node,Arc> >
+ ::SetDistMap<concepts::ReadWriteMap<Node,Value> >
+ ::SetOperationTraits<BellmanFordDefaultOperationTraits<Value> >
+ ::Create bf_test(gr,length);
+
+ LengthMap length_map;
+ concepts::ReadWriteMap<Node,Arc> pred_map;
+ concepts::ReadWriteMap<Node,Value> dist_map;
+
+ bf_test
+ .lengthMap(length_map)
+ .predMap(pred_map)
+ .distMap(dist_map);
+
+ bf_test.run(s);
+ bf_test.run(s,k);
+
+ bf_test.init();
+ bf_test.addSource(s);
+ bf_test.addSource(s, 1);
+ b = bf_test.processNextRound();
+ b = bf_test.processNextWeakRound();
+
+ bf_test.start();
+ bf_test.checkedStart();
+ bf_test.limitedStart(k);
+
+ l = bf_test.dist(t);
+ e = bf_test.predArc(t);
+ s = bf_test.predNode(t);
+ b = bf_test.reached(t);
+ pp = bf_test.path(t);
+ pp = bf_test.negativeCycle();
+ }
+}
+
+void checkBellmanFordFunctionCompile()
+{
+ typedef int Value;
+ typedef concepts::Digraph Digraph;
+ typedef Digraph::Arc Arc;
+ typedef Digraph::Node Node;
+ typedef concepts::ReadMap<Digraph::Arc,Value> LengthMap;
+
+ Digraph g;
+ bool b;
+ ::lemon::ignore_unused_variable_warning(b);
+
+ bellmanFord(g,LengthMap()).run(Node());
+ b = bellmanFord(g,LengthMap()).run(Node(),Node());
+ bellmanFord(g,LengthMap())
+ .predMap(concepts::ReadWriteMap<Node,Arc>())
+ .distMap(concepts::ReadWriteMap<Node,Value>())
+ .run(Node());
+ b=bellmanFord(g,LengthMap())
+ .predMap(concepts::ReadWriteMap<Node,Arc>())
+ .distMap(concepts::ReadWriteMap<Node,Value>())
+ .path(concepts::Path<Digraph>())
+ .dist(Value())
+ .run(Node(),Node());
+}
+
+
+template <typename Digraph, typename Value>
+void checkBellmanFord() {
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+ typedef typename Digraph::template ArcMap<Value> LengthMap;
+
+ Digraph gr;
+ Node s, t;
+ LengthMap length(gr);
+
+ std::istringstream input(test_lgf);
+ digraphReader(gr, input).
+ arcMap("length", length).
+ node("source", s).
+ node("target", t).
+ run();
+
+ BellmanFord<Digraph, LengthMap>
+ bf(gr, length);
+ bf.run(s);
+ Path<Digraph> p = bf.path(t);
+
+ check(bf.reached(t) && bf.dist(t) == -1, "Bellman-Ford found a wrong path.");
+ check(p.length() == 3, "path() found a wrong path.");
+ check(checkPath(gr, p), "path() found a wrong path.");
+ check(pathSource(gr, p) == s, "path() found a wrong path.");
+ check(pathTarget(gr, p) == t, "path() found a wrong path.");
+
+ ListPath<Digraph> path;
+ Value dist = 0;
+ bool reached = bellmanFord(gr,length).path(path).dist(dist).run(s,t);
+
+ check(reached && dist == -1, "Bellman-Ford found a wrong path.");
+ check(path.length() == 3, "path() found a wrong path.");
+ check(checkPath(gr, path), "path() found a wrong path.");
+ check(pathSource(gr, path) == s, "path() found a wrong path.");
+ check(pathTarget(gr, path) == t, "path() found a wrong path.");
+
+ for(ArcIt e(gr); e!=INVALID; ++e) {
+ Node u=gr.source(e);
+ Node v=gr.target(e);
+ check(!bf.reached(u) || (bf.dist(v) - bf.dist(u) <= length[e]),
+ "Wrong output. dist(target)-dist(source)-arc_length=" <<
+ bf.dist(v) - bf.dist(u) - length[e]);
+ }
+
+ for(NodeIt v(gr); v!=INVALID; ++v) {
+ if (bf.reached(v)) {
+ check(v==s || bf.predArc(v)!=INVALID, "Wrong tree.");
+ if (bf.predArc(v)!=INVALID ) {
+ Arc e=bf.predArc(v);
+ Node u=gr.source(e);
+ check(u==bf.predNode(v),"Wrong tree.");
+ check(bf.dist(v) - bf.dist(u) == length[e],
+ "Wrong distance! Difference: " <<
+ bf.dist(v) - bf.dist(u) - length[e]);
+ }
+ }
+ }
+}
+
+void checkBellmanFordNegativeCycle() {
+ DIGRAPH_TYPEDEFS(SmartDigraph);
+
+ SmartDigraph gr;
+ IntArcMap length(gr);
+
+ Node n1 = gr.addNode();
+ Node n2 = gr.addNode();
+ Node n3 = gr.addNode();
+ Node n4 = gr.addNode();
+
+ Arc a1 = gr.addArc(n1, n2);
+ Arc a2 = gr.addArc(n2, n2);
+
+ length[a1] = 2;
+ length[a2] = -1;
+
+ {
+ BellmanFord<SmartDigraph, IntArcMap> bf(gr, length);
+ bf.run(n1);
+ StaticPath<SmartDigraph> p = bf.negativeCycle();
+ check(p.length() == 1 && p.front() == p.back() && p.front() == a2,
+ "Wrong negative cycle.");
+ }
+
+ length[a2] = 0;
+
+ {
+ BellmanFord<SmartDigraph, IntArcMap> bf(gr, length);
+ bf.run(n1);
+ check(bf.negativeCycle().empty(),
+ "Negative cycle should not be found.");
+ }
+
+ length[gr.addArc(n1, n3)] = 5;
+ length[gr.addArc(n4, n3)] = 1;
+ length[gr.addArc(n2, n4)] = 2;
+ length[gr.addArc(n3, n2)] = -4;
+
+ {
+ BellmanFord<SmartDigraph, IntArcMap> bf(gr, length);
+ bf.init();
+ bf.addSource(n1);
+ for (int i = 0; i < 4; ++i) {
+ check(bf.negativeCycle().empty(),
+ "Negative cycle should not be found.");
+ bf.processNextRound();
+ }
+ StaticPath<SmartDigraph> p = bf.negativeCycle();
+ check(p.length() == 3, "Wrong negative cycle.");
+ check(length[p.nth(0)] + length[p.nth(1)] + length[p.nth(2)] == -1,
+ "Wrong negative cycle.");
+ }
+}
+
+int main() {
+ checkBellmanFord<ListDigraph, int>();
+ checkBellmanFord<SmartDigraph, double>();
+ checkBellmanFordNegativeCycle();
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/bfs_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/bfs_test.cc
new file mode 100644
index 00000000000..976fa88b637
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/bfs_test.cc
@@ -0,0 +1,239 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <lemon/concepts/digraph.h>
+#include <lemon/smart_graph.h>
+#include <lemon/list_graph.h>
+#include <lemon/lgf_reader.h>
+#include <lemon/bfs.h>
+#include <lemon/path.h>
+
+#include "graph_test.h"
+#include "test_tools.h"
+
+using namespace lemon;
+
+char test_lgf[] =
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "5\n"
+ "@arcs\n"
+ " label\n"
+ "0 1 0\n"
+ "1 2 1\n"
+ "2 3 2\n"
+ "3 4 3\n"
+ "0 3 4\n"
+ "0 3 5\n"
+ "5 2 6\n"
+ "@attributes\n"
+ "source 0\n"
+ "target 4\n";
+
+void checkBfsCompile()
+{
+ typedef concepts::Digraph Digraph;
+ typedef Bfs<Digraph> BType;
+ typedef Digraph::Node Node;
+ typedef Digraph::Arc Arc;
+
+ Digraph G;
+ Node s, t, n;
+ Arc e;
+ int l, i;
+ ::lemon::ignore_unused_variable_warning(l,i);
+ bool b;
+ BType::DistMap d(G);
+ BType::PredMap p(G);
+ Path<Digraph> pp;
+ concepts::ReadMap<Node,bool> nm;
+
+ {
+ BType bfs_test(G);
+ const BType& const_bfs_test = bfs_test;
+
+ bfs_test.run(s);
+ bfs_test.run(s,t);
+ bfs_test.run();
+
+ bfs_test.init();
+ bfs_test.addSource(s);
+ n = bfs_test.processNextNode();
+ n = bfs_test.processNextNode(t, b);
+ n = bfs_test.processNextNode(nm, n);
+ n = const_bfs_test.nextNode();
+ b = const_bfs_test.emptyQueue();
+ i = const_bfs_test.queueSize();
+
+ bfs_test.start();
+ bfs_test.start(t);
+ bfs_test.start(nm);
+
+ l = const_bfs_test.dist(t);
+ e = const_bfs_test.predArc(t);
+ s = const_bfs_test.predNode(t);
+ b = const_bfs_test.reached(t);
+ d = const_bfs_test.distMap();
+ p = const_bfs_test.predMap();
+ pp = const_bfs_test.path(t);
+ }
+ {
+ BType
+ ::SetPredMap<concepts::ReadWriteMap<Node,Arc> >
+ ::SetDistMap<concepts::ReadWriteMap<Node,int> >
+ ::SetReachedMap<concepts::ReadWriteMap<Node,bool> >
+ ::SetStandardProcessedMap
+ ::SetProcessedMap<concepts::WriteMap<Node,bool> >
+ ::Create bfs_test(G);
+
+ concepts::ReadWriteMap<Node,Arc> pred_map;
+ concepts::ReadWriteMap<Node,int> dist_map;
+ concepts::ReadWriteMap<Node,bool> reached_map;
+ concepts::WriteMap<Node,bool> processed_map;
+
+ bfs_test
+ .predMap(pred_map)
+ .distMap(dist_map)
+ .reachedMap(reached_map)
+ .processedMap(processed_map);
+
+ bfs_test.run(s);
+ bfs_test.run(s,t);
+ bfs_test.run();
+
+ bfs_test.init();
+ bfs_test.addSource(s);
+ n = bfs_test.processNextNode();
+ n = bfs_test.processNextNode(t, b);
+ n = bfs_test.processNextNode(nm, n);
+ n = bfs_test.nextNode();
+ b = bfs_test.emptyQueue();
+ i = bfs_test.queueSize();
+
+ bfs_test.start();
+ bfs_test.start(t);
+ bfs_test.start(nm);
+
+ l = bfs_test.dist(t);
+ e = bfs_test.predArc(t);
+ s = bfs_test.predNode(t);
+ b = bfs_test.reached(t);
+ pp = bfs_test.path(t);
+ }
+}
+
+void checkBfsFunctionCompile()
+{
+ typedef int VType;
+ typedef concepts::Digraph Digraph;
+ typedef Digraph::Arc Arc;
+ typedef Digraph::Node Node;
+
+ Digraph g;
+ bool b;
+ ::lemon::ignore_unused_variable_warning(b);
+
+ bfs(g).run(Node());
+ b=bfs(g).run(Node(),Node());
+ bfs(g).run();
+ bfs(g)
+ .predMap(concepts::ReadWriteMap<Node,Arc>())
+ .distMap(concepts::ReadWriteMap<Node,VType>())
+ .reachedMap(concepts::ReadWriteMap<Node,bool>())
+ .processedMap(concepts::WriteMap<Node,bool>())
+ .run(Node());
+ b=bfs(g)
+ .predMap(concepts::ReadWriteMap<Node,Arc>())
+ .distMap(concepts::ReadWriteMap<Node,VType>())
+ .reachedMap(concepts::ReadWriteMap<Node,bool>())
+ .processedMap(concepts::WriteMap<Node,bool>())
+ .path(concepts::Path<Digraph>())
+ .dist(VType())
+ .run(Node(),Node());
+ bfs(g)
+ .predMap(concepts::ReadWriteMap<Node,Arc>())
+ .distMap(concepts::ReadWriteMap<Node,VType>())
+ .reachedMap(concepts::ReadWriteMap<Node,bool>())
+ .processedMap(concepts::WriteMap<Node,bool>())
+ .run();
+}
+
+template <class Digraph>
+void checkBfs() {
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+
+ Digraph G;
+ Node s, t;
+
+ std::istringstream input(test_lgf);
+ digraphReader(G, input).
+ node("source", s).
+ node("target", t).
+ run();
+
+ Bfs<Digraph> bfs_test(G);
+ bfs_test.run(s);
+
+ check(bfs_test.dist(t)==2,"Bfs found a wrong path.");
+
+ Path<Digraph> p = bfs_test.path(t);
+ check(p.length()==2,"path() found a wrong path.");
+ check(checkPath(G, p),"path() found a wrong path.");
+ check(pathSource(G, p) == s,"path() found a wrong path.");
+ check(pathTarget(G, p) == t,"path() found a wrong path.");
+
+
+ for(ArcIt a(G); a!=INVALID; ++a) {
+ Node u=G.source(a);
+ Node v=G.target(a);
+ check( !bfs_test.reached(u) ||
+ (bfs_test.dist(v) <= bfs_test.dist(u)+1),
+ "Wrong output. " << G.id(u) << "->" << G.id(v));
+ }
+
+ for(NodeIt v(G); v!=INVALID; ++v) {
+ if (bfs_test.reached(v)) {
+ check(v==s || bfs_test.predArc(v)!=INVALID, "Wrong tree.");
+ if (bfs_test.predArc(v)!=INVALID ) {
+ Arc a=bfs_test.predArc(v);
+ Node u=G.source(a);
+ check(u==bfs_test.predNode(v),"Wrong tree.");
+ check(bfs_test.dist(v) - bfs_test.dist(u) == 1,
+ "Wrong distance. Difference: "
+ << std::abs(bfs_test.dist(v) - bfs_test.dist(u) - 1));
+ }
+ }
+ }
+
+ {
+ NullMap<Node,Arc> myPredMap;
+ bfs(G).predMap(myPredMap).run(s);
+ }
+}
+
+int main()
+{
+ checkBfs<ListDigraph>();
+ checkBfs<SmartDigraph>();
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/bpgraph_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/bpgraph_test.cc
new file mode 100644
index 00000000000..45fc5b855d4
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/bpgraph_test.cc
@@ -0,0 +1,456 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <lemon/concepts/bpgraph.h>
+#include <lemon/list_graph.h>
+#include <lemon/smart_graph.h>
+#include <lemon/full_graph.h>
+
+#include "test_tools.h"
+#include "graph_test.h"
+
+using namespace lemon;
+using namespace lemon::concepts;
+
+template <class BpGraph>
+void checkBpGraphBuild() {
+ TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph);
+
+ BpGraph G;
+ checkGraphNodeList(G, 0);
+ checkGraphRedNodeList(G, 0);
+ checkGraphBlueNodeList(G, 0);
+ checkGraphEdgeList(G, 0);
+ checkGraphArcList(G, 0);
+
+ G.reserveNode(3);
+ G.reserveEdge(3);
+
+ RedNode
+ rn1 = G.addRedNode();
+ checkGraphNodeList(G, 1);
+ checkGraphRedNodeList(G, 1);
+ checkGraphBlueNodeList(G, 0);
+ checkGraphEdgeList(G, 0);
+ checkGraphArcList(G, 0);
+
+ BlueNode
+ bn1 = G.addBlueNode(),
+ bn2 = G.addBlueNode();
+ checkGraphNodeList(G, 3);
+ checkGraphRedNodeList(G, 1);
+ checkGraphBlueNodeList(G, 2);
+ checkGraphEdgeList(G, 0);
+ checkGraphArcList(G, 0);
+
+ Edge e1 = G.addEdge(rn1, bn2);
+ check(G.redNode(e1) == rn1 && G.blueNode(e1) == bn2, "Wrong edge");
+ check(G.u(e1) == rn1 && G.v(e1) == bn2, "Wrong edge");
+
+ checkGraphNodeList(G, 3);
+ checkGraphRedNodeList(G, 1);
+ checkGraphBlueNodeList(G, 2);
+ checkGraphEdgeList(G, 1);
+ checkGraphArcList(G, 2);
+
+ checkGraphIncEdgeArcLists(G, rn1, 1);
+ checkGraphIncEdgeArcLists(G, bn1, 0);
+ checkGraphIncEdgeArcLists(G, bn2, 1);
+
+ checkGraphConEdgeList(G, 1);
+ checkGraphConArcList(G, 2);
+
+ Edge
+ e2 = G.addEdge(bn1, rn1),
+ e3 = G.addEdge(rn1, bn2);
+ ::lemon::ignore_unused_variable_warning(e2,e3);
+
+ checkGraphNodeList(G, 3);
+ checkGraphRedNodeList(G, 1);
+ checkGraphBlueNodeList(G, 2);
+ checkGraphEdgeList(G, 3);
+ checkGraphArcList(G, 6);
+
+ checkGraphIncEdgeArcLists(G, rn1, 3);
+ checkGraphIncEdgeArcLists(G, bn1, 1);
+ checkGraphIncEdgeArcLists(G, bn2, 2);
+
+ checkGraphConEdgeList(G, 3);
+ checkGraphConArcList(G, 6);
+
+ checkArcDirections(G);
+
+ checkNodeIds(G);
+ checkRedNodeIds(G);
+ checkBlueNodeIds(G);
+ checkArcIds(G);
+ checkEdgeIds(G);
+
+ checkGraphNodeMap(G);
+ checkGraphRedNodeMap(G);
+ checkGraphBlueNodeMap(G);
+ checkGraphArcMap(G);
+ checkGraphEdgeMap(G);
+}
+
+template <class BpGraph>
+void checkBpGraphErase() {
+ TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph);
+
+ BpGraph G;
+ RedNode
+ n1 = G.addRedNode(), n4 = G.addRedNode();
+ BlueNode
+ n2 = G.addBlueNode(), n3 = G.addBlueNode();
+ Edge
+ e1 = G.addEdge(n1, n2), e2 = G.addEdge(n1, n3),
+ e3 = G.addEdge(n4, n2), e4 = G.addEdge(n4, n3);
+ ::lemon::ignore_unused_variable_warning(e1,e3,e4);
+
+ // Check edge deletion
+ G.erase(e2);
+
+ checkGraphNodeList(G, 4);
+ checkGraphRedNodeList(G, 2);
+ checkGraphBlueNodeList(G, 2);
+ checkGraphEdgeList(G, 3);
+ checkGraphArcList(G, 6);
+
+ checkGraphIncEdgeArcLists(G, n1, 1);
+ checkGraphIncEdgeArcLists(G, n2, 2);
+ checkGraphIncEdgeArcLists(G, n3, 1);
+ checkGraphIncEdgeArcLists(G, n4, 2);
+
+ checkGraphConEdgeList(G, 3);
+ checkGraphConArcList(G, 6);
+
+ // Check node deletion
+ G.erase(n3);
+
+ checkGraphNodeList(G, 3);
+ checkGraphRedNodeList(G, 2);
+ checkGraphBlueNodeList(G, 1);
+ checkGraphEdgeList(G, 2);
+ checkGraphArcList(G, 4);
+
+ checkGraphIncEdgeArcLists(G, n1, 1);
+ checkGraphIncEdgeArcLists(G, n2, 2);
+ checkGraphIncEdgeArcLists(G, n4, 1);
+
+ checkGraphConEdgeList(G, 2);
+ checkGraphConArcList(G, 4);
+
+}
+
+template <class BpGraph>
+void checkBpGraphAlter() {
+ TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph);
+
+ BpGraph G;
+ RedNode
+ n1 = G.addRedNode(), n4 = G.addRedNode();
+ BlueNode
+ n2 = G.addBlueNode(), n3 = G.addBlueNode();
+ Edge
+ e1 = G.addEdge(n1, n2), e2 = G.addEdge(n1, n3),
+ e3 = G.addEdge(n4, n2), e4 = G.addEdge(n4, n3);
+ ::lemon::ignore_unused_variable_warning(e1,e3,e4);
+
+ G.changeRed(e2, n4);
+ check(G.redNode(e2) == n4, "Wrong red node");
+ check(G.blueNode(e2) == n3, "Wrong blue node");
+
+ checkGraphNodeList(G, 4);
+ checkGraphRedNodeList(G, 2);
+ checkGraphBlueNodeList(G, 2);
+ checkGraphEdgeList(G, 4);
+ checkGraphArcList(G, 8);
+
+ checkGraphIncEdgeArcLists(G, n1, 1);
+ checkGraphIncEdgeArcLists(G, n2, 2);
+ checkGraphIncEdgeArcLists(G, n3, 2);
+ checkGraphIncEdgeArcLists(G, n4, 3);
+
+ checkGraphConEdgeList(G, 4);
+ checkGraphConArcList(G, 8);
+
+ G.changeBlue(e2, n2);
+ check(G.redNode(e2) == n4, "Wrong red node");
+ check(G.blueNode(e2) == n2, "Wrong blue node");
+
+ checkGraphNodeList(G, 4);
+ checkGraphRedNodeList(G, 2);
+ checkGraphBlueNodeList(G, 2);
+ checkGraphEdgeList(G, 4);
+ checkGraphArcList(G, 8);
+
+ checkGraphIncEdgeArcLists(G, n1, 1);
+ checkGraphIncEdgeArcLists(G, n2, 3);
+ checkGraphIncEdgeArcLists(G, n3, 1);
+ checkGraphIncEdgeArcLists(G, n4, 3);
+
+ checkGraphConEdgeList(G, 4);
+ checkGraphConArcList(G, 8);
+}
+
+
+template <class BpGraph>
+void checkBpGraphSnapshot() {
+ TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph);
+
+ BpGraph G;
+ RedNode
+ n1 = G.addRedNode();
+ BlueNode
+ n2 = G.addBlueNode(),
+ n3 = G.addBlueNode();
+ Edge
+ e1 = G.addEdge(n1, n2),
+ e2 = G.addEdge(n1, n3);
+ ::lemon::ignore_unused_variable_warning(e1,e2);
+
+ checkGraphNodeList(G, 3);
+ checkGraphRedNodeList(G, 1);
+ checkGraphBlueNodeList(G, 2);
+ checkGraphEdgeList(G, 2);
+ checkGraphArcList(G, 4);
+
+ typename BpGraph::Snapshot snapshot(G);
+
+ RedNode n4 = G.addRedNode();
+ G.addEdge(n4, n2);
+ G.addEdge(n4, n3);
+
+ checkGraphNodeList(G, 4);
+ checkGraphRedNodeList(G, 2);
+ checkGraphBlueNodeList(G, 2);
+ checkGraphEdgeList(G, 4);
+ checkGraphArcList(G, 8);
+
+ snapshot.restore();
+
+ checkGraphNodeList(G, 3);
+ checkGraphRedNodeList(G, 1);
+ checkGraphBlueNodeList(G, 2);
+ checkGraphEdgeList(G, 2);
+ checkGraphArcList(G, 4);
+
+ checkGraphIncEdgeArcLists(G, n1, 2);
+ checkGraphIncEdgeArcLists(G, n2, 1);
+ checkGraphIncEdgeArcLists(G, n3, 1);
+
+ checkGraphConEdgeList(G, 2);
+ checkGraphConArcList(G, 4);
+
+ checkNodeIds(G);
+ checkRedNodeIds(G);
+ checkBlueNodeIds(G);
+ checkArcIds(G);
+ checkEdgeIds(G);
+
+ checkGraphNodeMap(G);
+ checkGraphRedNodeMap(G);
+ checkGraphBlueNodeMap(G);
+ checkGraphArcMap(G);
+ checkGraphEdgeMap(G);
+
+ G.addRedNode();
+ snapshot.save(G);
+
+ G.addEdge(G.addRedNode(), G.addBlueNode());
+
+ snapshot.restore();
+ snapshot.save(G);
+
+ checkGraphNodeList(G, 4);
+ checkGraphRedNodeList(G, 2);
+ checkGraphBlueNodeList(G, 2);
+ checkGraphEdgeList(G, 2);
+ checkGraphArcList(G, 4);
+
+ G.addEdge(G.addRedNode(), G.addBlueNode());
+
+ snapshot.restore();
+
+ checkGraphNodeList(G, 4);
+ checkGraphRedNodeList(G, 2);
+ checkGraphBlueNodeList(G, 2);
+ checkGraphEdgeList(G, 2);
+ checkGraphArcList(G, 4);
+}
+
+template <typename BpGraph>
+void checkBpGraphValidity() {
+ TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph);
+ BpGraph g;
+
+ RedNode
+ n1 = g.addRedNode();
+ BlueNode
+ n2 = g.addBlueNode(),
+ n3 = g.addBlueNode();
+
+ Edge
+ e1 = g.addEdge(n1, n2),
+ e2 = g.addEdge(n1, n3);
+ ::lemon::ignore_unused_variable_warning(e2);
+
+ check(g.valid(n1), "Wrong validity check");
+ check(g.valid(e1), "Wrong validity check");
+ check(g.valid(g.direct(e1, true)), "Wrong validity check");
+
+ check(!g.valid(g.nodeFromId(-1)), "Wrong validity check");
+ check(!g.valid(g.edgeFromId(-1)), "Wrong validity check");
+ check(!g.valid(g.arcFromId(-1)), "Wrong validity check");
+}
+
+void checkConcepts() {
+ { // Checking graph components
+ checkConcept<BaseBpGraphComponent, BaseBpGraphComponent >();
+
+ checkConcept<IDableBpGraphComponent<>,
+ IDableBpGraphComponent<> >();
+
+ checkConcept<IterableBpGraphComponent<>,
+ IterableBpGraphComponent<> >();
+
+ checkConcept<AlterableBpGraphComponent<>,
+ AlterableBpGraphComponent<> >();
+
+ checkConcept<MappableBpGraphComponent<>,
+ MappableBpGraphComponent<> >();
+
+ checkConcept<ExtendableBpGraphComponent<>,
+ ExtendableBpGraphComponent<> >();
+
+ checkConcept<ErasableBpGraphComponent<>,
+ ErasableBpGraphComponent<> >();
+
+ checkConcept<ClearableBpGraphComponent<>,
+ ClearableBpGraphComponent<> >();
+
+ }
+ { // Checking skeleton graph
+ checkConcept<BpGraph, BpGraph>();
+ }
+ { // Checking SmartBpGraph
+ checkConcept<BpGraph, SmartBpGraph>();
+ checkConcept<AlterableBpGraphComponent<>, SmartBpGraph>();
+ checkConcept<ExtendableBpGraphComponent<>, SmartBpGraph>();
+ checkConcept<ClearableBpGraphComponent<>, SmartBpGraph>();
+ }
+}
+
+void checkFullBpGraph(int redNum, int blueNum) {
+ typedef FullBpGraph BpGraph;
+ BPGRAPH_TYPEDEFS(BpGraph);
+
+ BpGraph G(redNum, blueNum);
+ checkGraphNodeList(G, redNum + blueNum);
+ checkGraphRedNodeList(G, redNum);
+ checkGraphBlueNodeList(G, blueNum);
+ checkGraphEdgeList(G, redNum * blueNum);
+ checkGraphArcList(G, 2 * redNum * blueNum);
+
+ G.resize(redNum, blueNum);
+ checkGraphNodeList(G, redNum + blueNum);
+ checkGraphRedNodeList(G, redNum);
+ checkGraphBlueNodeList(G, blueNum);
+ checkGraphEdgeList(G, redNum * blueNum);
+ checkGraphArcList(G, 2 * redNum * blueNum);
+
+ for (RedNodeIt n(G); n != INVALID; ++n) {
+ checkGraphOutArcList(G, n, blueNum);
+ checkGraphInArcList(G, n, blueNum);
+ checkGraphIncEdgeList(G, n, blueNum);
+ }
+
+ for (BlueNodeIt n(G); n != INVALID; ++n) {
+ checkGraphOutArcList(G, n, redNum);
+ checkGraphInArcList(G, n, redNum);
+ checkGraphIncEdgeList(G, n, redNum);
+ }
+
+ checkGraphConArcList(G, 2 * redNum * blueNum);
+ checkGraphConEdgeList(G, redNum * blueNum);
+
+ checkArcDirections(G);
+
+ checkNodeIds(G);
+ checkRedNodeIds(G);
+ checkBlueNodeIds(G);
+ checkArcIds(G);
+ checkEdgeIds(G);
+
+ checkGraphNodeMap(G);
+ checkGraphRedNodeMap(G);
+ checkGraphBlueNodeMap(G);
+ checkGraphArcMap(G);
+ checkGraphEdgeMap(G);
+
+ for (int i = 0; i < G.redNum(); ++i) {
+ check(G.red(G.redNode(i)), "Wrong node");
+ check(G.index(G.redNode(i)) == i, "Wrong index");
+ }
+
+ for (int i = 0; i < G.blueNum(); ++i) {
+ check(G.blue(G.blueNode(i)), "Wrong node");
+ check(G.index(G.blueNode(i)) == i, "Wrong index");
+ }
+
+ for (NodeIt u(G); u != INVALID; ++u) {
+ for (NodeIt v(G); v != INVALID; ++v) {
+ Edge e = G.edge(u, v);
+ Arc a = G.arc(u, v);
+ if (G.red(u) == G.red(v)) {
+ check(e == INVALID, "Wrong edge lookup");
+ check(a == INVALID, "Wrong arc lookup");
+ } else {
+ check((G.u(e) == u && G.v(e) == v) ||
+ (G.u(e) == v && G.v(e) == u), "Wrong edge lookup");
+ check(G.source(a) == u && G.target(a) == v, "Wrong arc lookup");
+ }
+ }
+ }
+
+}
+
+void checkGraphs() {
+ { // Checking ListGraph
+ checkBpGraphBuild<ListBpGraph>();
+ checkBpGraphErase<ListBpGraph>();
+ checkBpGraphAlter<ListBpGraph>();
+ checkBpGraphSnapshot<ListBpGraph>();
+ checkBpGraphValidity<ListBpGraph>();
+ }
+ { // Checking SmartGraph
+ checkBpGraphBuild<SmartBpGraph>();
+ checkBpGraphSnapshot<SmartBpGraph>();
+ checkBpGraphValidity<SmartBpGraph>();
+ }
+ { // Checking FullBpGraph
+ checkFullBpGraph(6, 8);
+ checkFullBpGraph(7, 4);
+ }
+}
+
+int main() {
+ checkConcepts();
+ checkGraphs();
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/circulation_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/circulation_test.cc
new file mode 100644
index 00000000000..3b3a4a97216
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/circulation_test.cc
@@ -0,0 +1,169 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <iostream>
+
+#include "test_tools.h"
+#include <lemon/list_graph.h>
+#include <lemon/circulation.h>
+#include <lemon/lgf_reader.h>
+#include <lemon/concepts/digraph.h>
+#include <lemon/concepts/maps.h>
+
+using namespace lemon;
+
+char test_lgf[] =
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "5\n"
+ "@arcs\n"
+ " lcap ucap\n"
+ "0 1 2 10\n"
+ "0 2 2 6\n"
+ "1 3 4 7\n"
+ "1 4 0 5\n"
+ "2 4 1 3\n"
+ "3 5 3 8\n"
+ "4 5 3 7\n"
+ "@attributes\n"
+ "source 0\n"
+ "sink 5\n";
+
+void checkCirculationCompile()
+{
+ typedef int VType;
+ typedef concepts::Digraph Digraph;
+
+ typedef Digraph::Node Node;
+ typedef Digraph::Arc Arc;
+ typedef concepts::ReadMap<Arc,VType> CapMap;
+ typedef concepts::ReadMap<Node,VType> SupplyMap;
+ typedef concepts::ReadWriteMap<Arc,VType> FlowMap;
+ typedef concepts::WriteMap<Node,bool> BarrierMap;
+
+ typedef Elevator<Digraph, Digraph::Node> Elev;
+ typedef LinkedElevator<Digraph, Digraph::Node> LinkedElev;
+
+ Digraph g;
+ Node n;
+ Arc a;
+ CapMap lcap, ucap;
+ SupplyMap supply;
+ FlowMap flow;
+ BarrierMap bar;
+ VType v;
+ bool b;
+ ::lemon::ignore_unused_variable_warning(v,b);
+
+ typedef Circulation<Digraph, CapMap, CapMap, SupplyMap>
+ ::SetFlowMap<FlowMap>
+ ::SetElevator<Elev>
+ ::SetStandardElevator<LinkedElev>
+ ::Create CirculationType;
+ CirculationType circ_test(g, lcap, ucap, supply);
+ const CirculationType& const_circ_test = circ_test;
+
+ circ_test
+ .lowerMap(lcap)
+ .upperMap(ucap)
+ .supplyMap(supply)
+ .flowMap(flow);
+
+ const CirculationType::Elevator& elev = const_circ_test.elevator();
+ circ_test.elevator(const_cast<CirculationType::Elevator&>(elev));
+ CirculationType::Tolerance tol = const_circ_test.tolerance();
+ circ_test.tolerance(tol);
+
+ circ_test.init();
+ circ_test.greedyInit();
+ circ_test.start();
+ circ_test.run();
+
+ v = const_circ_test.flow(a);
+ const FlowMap& fm = const_circ_test.flowMap();
+ b = const_circ_test.barrier(n);
+ const_circ_test.barrierMap(bar);
+
+ ::lemon::ignore_unused_variable_warning(fm);
+}
+
+template <class G, class LM, class UM, class DM>
+void checkCirculation(const G& g, const LM& lm, const UM& um,
+ const DM& dm, bool find)
+{
+ Circulation<G, LM, UM, DM> circ(g, lm, um, dm);
+ bool ret = circ.run();
+ if (find) {
+ check(ret, "A feasible solution should have been found.");
+ check(circ.checkFlow(), "The found flow is corrupt.");
+ check(!circ.checkBarrier(), "A barrier should not have been found.");
+ } else {
+ check(!ret, "A feasible solution should not have been found.");
+ check(circ.checkBarrier(), "The found barrier is corrupt.");
+ }
+}
+
+int main (int, char*[])
+{
+ typedef ListDigraph Digraph;
+ DIGRAPH_TYPEDEFS(Digraph);
+
+ Digraph g;
+ IntArcMap lo(g), up(g);
+ IntNodeMap delta(g, 0);
+ Node s, t;
+
+ std::istringstream input(test_lgf);
+ DigraphReader<Digraph>(g,input).
+ arcMap("lcap", lo).
+ arcMap("ucap", up).
+ node("source",s).
+ node("sink",t).
+ run();
+
+ delta[s] = 7; delta[t] = -7;
+ checkCirculation(g, lo, up, delta, true);
+
+ delta[s] = 13; delta[t] = -13;
+ checkCirculation(g, lo, up, delta, true);
+
+ delta[s] = 6; delta[t] = -6;
+ checkCirculation(g, lo, up, delta, false);
+
+ delta[s] = 14; delta[t] = -14;
+ checkCirculation(g, lo, up, delta, false);
+
+ delta[s] = 7; delta[t] = -13;
+ checkCirculation(g, lo, up, delta, true);
+
+ delta[s] = 5; delta[t] = -15;
+ checkCirculation(g, lo, up, delta, true);
+
+ delta[s] = 10; delta[t] = -11;
+ checkCirculation(g, lo, up, delta, true);
+
+ delta[s] = 11; delta[t] = -10;
+ checkCirculation(g, lo, up, delta, false);
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/connectivity_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/connectivity_test.cc
new file mode 100644
index 00000000000..4ab343ee0fd
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/connectivity_test.cc
@@ -0,0 +1,316 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <lemon/connectivity.h>
+#include <lemon/list_graph.h>
+#include <lemon/adaptors.h>
+
+#include "test_tools.h"
+
+using namespace lemon;
+
+
+int main()
+{
+ typedef ListDigraph Digraph;
+ typedef Undirector<Digraph> Graph;
+
+ {
+ Digraph d;
+ Digraph::NodeMap<int> order(d);
+ Graph g(d);
+
+ check(stronglyConnected(d), "The empty digraph is strongly connected");
+ check(countStronglyConnectedComponents(d) == 0,
+ "The empty digraph has 0 strongly connected component");
+ check(connected(g), "The empty graph is connected");
+ check(countConnectedComponents(g) == 0,
+ "The empty graph has 0 connected component");
+
+ check(biNodeConnected(g), "The empty graph is bi-node-connected");
+ check(countBiNodeConnectedComponents(g) == 0,
+ "The empty graph has 0 bi-node-connected component");
+ check(biEdgeConnected(g), "The empty graph is bi-edge-connected");
+ check(countBiEdgeConnectedComponents(g) == 0,
+ "The empty graph has 0 bi-edge-connected component");
+
+ check(dag(d), "The empty digraph is DAG.");
+ check(checkedTopologicalSort(d, order), "The empty digraph is DAG.");
+ check(loopFree(d), "The empty digraph is loop-free.");
+ check(parallelFree(d), "The empty digraph is parallel-free.");
+ check(simpleGraph(d), "The empty digraph is simple.");
+
+ check(acyclic(g), "The empty graph is acyclic.");
+ check(tree(g), "The empty graph is tree.");
+ check(bipartite(g), "The empty graph is bipartite.");
+ check(loopFree(g), "The empty graph is loop-free.");
+ check(parallelFree(g), "The empty graph is parallel-free.");
+ check(simpleGraph(g), "The empty graph is simple.");
+ }
+
+ {
+ Digraph d;
+ Digraph::NodeMap<int> order(d);
+ Graph g(d);
+ Digraph::Node n = d.addNode();
+ ::lemon::ignore_unused_variable_warning(n);
+
+ check(stronglyConnected(d), "This digraph is strongly connected");
+ check(countStronglyConnectedComponents(d) == 1,
+ "This digraph has 1 strongly connected component");
+ check(connected(g), "This graph is connected");
+ check(countConnectedComponents(g) == 1,
+ "This graph has 1 connected component");
+
+ check(biNodeConnected(g), "This graph is bi-node-connected");
+ check(countBiNodeConnectedComponents(g) == 0,
+ "This graph has 0 bi-node-connected component");
+ check(biEdgeConnected(g), "This graph is bi-edge-connected");
+ check(countBiEdgeConnectedComponents(g) == 1,
+ "This graph has 1 bi-edge-connected component");
+
+ check(dag(d), "This digraph is DAG.");
+ check(checkedTopologicalSort(d, order), "This digraph is DAG.");
+ check(loopFree(d), "This digraph is loop-free.");
+ check(parallelFree(d), "This digraph is parallel-free.");
+ check(simpleGraph(d), "This digraph is simple.");
+
+ check(acyclic(g), "This graph is acyclic.");
+ check(tree(g), "This graph is tree.");
+ check(bipartite(g), "This graph is bipartite.");
+ check(loopFree(g), "This graph is loop-free.");
+ check(parallelFree(g), "This graph is parallel-free.");
+ check(simpleGraph(g), "This graph is simple.");
+ }
+
+ {
+ ListGraph g;
+ ListGraph::NodeMap<bool> map(g);
+
+ ListGraph::Node n1 = g.addNode();
+ ListGraph::Node n2 = g.addNode();
+
+ ListGraph::Edge e1 = g.addEdge(n1, n2);
+ ::lemon::ignore_unused_variable_warning(e1);
+ check(biNodeConnected(g), "Graph is bi-node-connected");
+
+ ListGraph::Node n3 = g.addNode();
+ ::lemon::ignore_unused_variable_warning(n3);
+ check(!biNodeConnected(g), "Graph is not bi-node-connected");
+ }
+
+
+ {
+ Digraph d;
+ Digraph::NodeMap<int> order(d);
+ Graph g(d);
+
+ Digraph::Node n1 = d.addNode();
+ Digraph::Node n2 = d.addNode();
+ Digraph::Node n3 = d.addNode();
+ Digraph::Node n4 = d.addNode();
+ Digraph::Node n5 = d.addNode();
+ Digraph::Node n6 = d.addNode();
+
+ d.addArc(n1, n3);
+ d.addArc(n3, n2);
+ d.addArc(n2, n1);
+ d.addArc(n4, n2);
+ d.addArc(n4, n3);
+ d.addArc(n5, n6);
+ d.addArc(n6, n5);
+
+ check(!stronglyConnected(d), "This digraph is not strongly connected");
+ check(countStronglyConnectedComponents(d) == 3,
+ "This digraph has 3 strongly connected components");
+ check(!connected(g), "This graph is not connected");
+ check(countConnectedComponents(g) == 2,
+ "This graph has 2 connected components");
+
+ check(!dag(d), "This digraph is not DAG.");
+ check(!checkedTopologicalSort(d, order), "This digraph is not DAG.");
+ check(loopFree(d), "This digraph is loop-free.");
+ check(parallelFree(d), "This digraph is parallel-free.");
+ check(simpleGraph(d), "This digraph is simple.");
+
+ check(!acyclic(g), "This graph is not acyclic.");
+ check(!tree(g), "This graph is not tree.");
+ check(!bipartite(g), "This graph is not bipartite.");
+ check(loopFree(g), "This graph is loop-free.");
+ check(!parallelFree(g), "This graph is not parallel-free.");
+ check(!simpleGraph(g), "This graph is not simple.");
+
+ d.addArc(n3, n3);
+
+ check(!loopFree(d), "This digraph is not loop-free.");
+ check(!loopFree(g), "This graph is not loop-free.");
+ check(!simpleGraph(d), "This digraph is not simple.");
+
+ d.addArc(n3, n2);
+
+ check(!parallelFree(d), "This digraph is not parallel-free.");
+ }
+
+ {
+ Digraph d;
+ Digraph::ArcMap<bool> cutarcs(d, false);
+ Graph g(d);
+
+ Digraph::Node n1 = d.addNode();
+ Digraph::Node n2 = d.addNode();
+ Digraph::Node n3 = d.addNode();
+ Digraph::Node n4 = d.addNode();
+ Digraph::Node n5 = d.addNode();
+ Digraph::Node n6 = d.addNode();
+ Digraph::Node n7 = d.addNode();
+ Digraph::Node n8 = d.addNode();
+
+ d.addArc(n1, n2);
+ d.addArc(n5, n1);
+ d.addArc(n2, n8);
+ d.addArc(n8, n5);
+ d.addArc(n6, n4);
+ d.addArc(n4, n6);
+ d.addArc(n2, n5);
+ d.addArc(n1, n8);
+ d.addArc(n6, n7);
+ d.addArc(n7, n6);
+
+ check(!stronglyConnected(d), "This digraph is not strongly connected");
+ check(countStronglyConnectedComponents(d) == 3,
+ "This digraph has 3 strongly connected components");
+ Digraph::NodeMap<int> scomp1(d);
+ check(stronglyConnectedComponents(d, scomp1) == 3,
+ "This digraph has 3 strongly connected components");
+ check(scomp1[n1] != scomp1[n3] && scomp1[n1] != scomp1[n4] &&
+ scomp1[n3] != scomp1[n4], "Wrong stronglyConnectedComponents()");
+ check(scomp1[n1] == scomp1[n2] && scomp1[n1] == scomp1[n5] &&
+ scomp1[n1] == scomp1[n8], "Wrong stronglyConnectedComponents()");
+ check(scomp1[n4] == scomp1[n6] && scomp1[n4] == scomp1[n7],
+ "Wrong stronglyConnectedComponents()");
+ Digraph::ArcMap<bool> scut1(d, false);
+ check(stronglyConnectedCutArcs(d, scut1) == 0,
+ "This digraph has 0 strongly connected cut arc.");
+ for (Digraph::ArcIt a(d); a != INVALID; ++a) {
+ check(!scut1[a], "Wrong stronglyConnectedCutArcs()");
+ }
+
+ check(!connected(g), "This graph is not connected");
+ check(countConnectedComponents(g) == 3,
+ "This graph has 3 connected components");
+ Graph::NodeMap<int> comp(g);
+ check(connectedComponents(g, comp) == 3,
+ "This graph has 3 connected components");
+ check(comp[n1] != comp[n3] && comp[n1] != comp[n4] &&
+ comp[n3] != comp[n4], "Wrong connectedComponents()");
+ check(comp[n1] == comp[n2] && comp[n1] == comp[n5] &&
+ comp[n1] == comp[n8], "Wrong connectedComponents()");
+ check(comp[n4] == comp[n6] && comp[n4] == comp[n7],
+ "Wrong connectedComponents()");
+
+ cutarcs[d.addArc(n3, n1)] = true;
+ cutarcs[d.addArc(n3, n5)] = true;
+ cutarcs[d.addArc(n3, n8)] = true;
+ cutarcs[d.addArc(n8, n6)] = true;
+ cutarcs[d.addArc(n8, n7)] = true;
+
+ check(!stronglyConnected(d), "This digraph is not strongly connected");
+ check(countStronglyConnectedComponents(d) == 3,
+ "This digraph has 3 strongly connected components");
+ Digraph::NodeMap<int> scomp2(d);
+ check(stronglyConnectedComponents(d, scomp2) == 3,
+ "This digraph has 3 strongly connected components");
+ check(scomp2[n3] == 0, "Wrong stronglyConnectedComponents()");
+ check(scomp2[n1] == 1 && scomp2[n2] == 1 && scomp2[n5] == 1 &&
+ scomp2[n8] == 1, "Wrong stronglyConnectedComponents()");
+ check(scomp2[n4] == 2 && scomp2[n6] == 2 && scomp2[n7] == 2,
+ "Wrong stronglyConnectedComponents()");
+ Digraph::ArcMap<bool> scut2(d, false);
+ check(stronglyConnectedCutArcs(d, scut2) == 5,
+ "This digraph has 5 strongly connected cut arcs.");
+ for (Digraph::ArcIt a(d); a != INVALID; ++a) {
+ check(scut2[a] == cutarcs[a], "Wrong stronglyConnectedCutArcs()");
+ }
+ }
+
+ {
+ // DAG example for topological sort from the book New Algorithms
+ // (T. H. Cormen, C. E. Leiserson, R. L. Rivest, C. Stein)
+ Digraph d;
+ Digraph::NodeMap<int> order(d);
+
+ Digraph::Node belt = d.addNode();
+ Digraph::Node trousers = d.addNode();
+ Digraph::Node necktie = d.addNode();
+ Digraph::Node coat = d.addNode();
+ Digraph::Node socks = d.addNode();
+ Digraph::Node shirt = d.addNode();
+ Digraph::Node shoe = d.addNode();
+ Digraph::Node watch = d.addNode();
+ Digraph::Node pants = d.addNode();
+ ::lemon::ignore_unused_variable_warning(watch);
+
+ d.addArc(socks, shoe);
+ d.addArc(pants, shoe);
+ d.addArc(pants, trousers);
+ d.addArc(trousers, shoe);
+ d.addArc(trousers, belt);
+ d.addArc(belt, coat);
+ d.addArc(shirt, belt);
+ d.addArc(shirt, necktie);
+ d.addArc(necktie, coat);
+
+ check(dag(d), "This digraph is DAG.");
+ topologicalSort(d, order);
+ for (Digraph::ArcIt a(d); a != INVALID; ++a) {
+ check(order[d.source(a)] < order[d.target(a)],
+ "Wrong topologicalSort()");
+ }
+ }
+
+ {
+ ListGraph g;
+ ListGraph::NodeMap<bool> map(g);
+
+ ListGraph::Node n1 = g.addNode();
+ ListGraph::Node n2 = g.addNode();
+ ListGraph::Node n3 = g.addNode();
+ ListGraph::Node n4 = g.addNode();
+ ListGraph::Node n5 = g.addNode();
+ ListGraph::Node n6 = g.addNode();
+ ListGraph::Node n7 = g.addNode();
+
+ g.addEdge(n1, n3);
+ g.addEdge(n1, n4);
+ g.addEdge(n2, n5);
+ g.addEdge(n3, n6);
+ g.addEdge(n4, n6);
+ g.addEdge(n4, n7);
+ g.addEdge(n5, n7);
+
+ check(bipartite(g), "This graph is bipartite");
+ check(bipartitePartitions(g, map), "This graph is bipartite");
+
+ check(map[n1] == map[n2] && map[n1] == map[n6] && map[n1] == map[n7],
+ "Wrong bipartitePartitions()");
+ check(map[n3] == map[n4] && map[n3] == map[n5],
+ "Wrong bipartitePartitions()");
+ }
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/counter_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/counter_test.cc
new file mode 100644
index 00000000000..df31dd4d39e
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/counter_test.cc
@@ -0,0 +1,118 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <lemon/counter.h>
+#include <vector>
+#include <sstream>
+
+#include "test/test_tools.h"
+
+using namespace lemon;
+
+template <typename T>
+void bubbleSort(std::vector<T>& v) {
+ std::stringstream s1, s2, s3;
+ {
+ Counter op("Bubble Sort - Operations: ", s1);
+ Counter::SubCounter as(op, "Assignments: ", s2);
+ Counter::SubCounter co(op, "Comparisons: ", s3);
+ for (int i = v.size()-1; i > 0; --i) {
+ for (int j = 0; j < i; ++j) {
+ if (v[j] > v[j+1]) {
+ T tmp = v[j];
+ v[j] = v[j+1];
+ v[j+1] = tmp;
+ as += 3;
+ }
+ ++co;
+ }
+ }
+ }
+ check(s1.str() == "Bubble Sort - Operations: 102\n", "Wrong counter");
+ check(s2.str() == "Assignments: 57\n", "Wrong subcounter");
+ check(s3.str() == "Comparisons: 45\n", "Wrong subcounter");
+}
+
+template <typename T>
+void insertionSort(std::vector<T>& v) {
+ std::stringstream s1, s2, s3;
+ {
+ Counter op("Insertion Sort - Operations: ", s1);
+ Counter::SubCounter as(op, "Assignments: ", s2);
+ Counter::SubCounter co(op, "Comparisons: ", s3);
+ for (int i = 1; i < int(v.size()); ++i) {
+ T value = v[i];
+ ++as;
+ int j = i;
+ while (j > 0 && v[j-1] > value) {
+ v[j] = v[j-1];
+ --j;
+ ++co; ++as;
+ }
+ v[j] = value;
+ ++as;
+ }
+ }
+ check(s1.str() == "Insertion Sort - Operations: 56\n", "Wrong counter");
+ check(s2.str() == "Assignments: 37\n", "Wrong subcounter");
+ check(s3.str() == "Comparisons: 19\n", "Wrong subcounter");
+}
+
+template <typename MyCounter>
+void counterTest(bool output) {
+ std::stringstream s1, s2, s3;
+ {
+ MyCounter c("Main Counter: ", s1);
+ c++;
+ typename MyCounter::SubCounter d(c, "SubCounter: ", s2);
+ d++;
+ typename MyCounter::SubCounter::NoSubCounter e(d, "SubSubCounter: ", s3);
+ e++;
+ d+=3;
+ c-=4;
+ e-=2;
+ c.reset(2);
+ c.reset();
+ }
+ if (output) {
+ check(s1.str() == "Main Counter: 3\n", "Wrong Counter");
+ check(s2.str() == "SubCounter: 3\n", "Wrong SubCounter");
+ check(s3.str() == "", "Wrong NoSubCounter");
+ } else {
+ check(s1.str() == "", "Wrong NoCounter");
+ check(s2.str() == "", "Wrong SubCounter");
+ check(s3.str() == "", "Wrong NoSubCounter");
+ }
+}
+
+void init(std::vector<int>& v) {
+ v[0] = 10; v[1] = 60; v[2] = 20; v[3] = 90; v[4] = 100;
+ v[5] = 80; v[6] = 40; v[7] = 30; v[8] = 50; v[9] = 70;
+}
+
+int main()
+{
+ counterTest<Counter>(true);
+ counterTest<NoCounter>(false);
+
+ std::vector<int> x(10);
+ init(x); bubbleSort(x);
+ init(x); insertionSort(x);
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/dfs_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/dfs_test.cc
new file mode 100644
index 00000000000..ef5049a000a
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/dfs_test.cc
@@ -0,0 +1,238 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <lemon/concepts/digraph.h>
+#include <lemon/smart_graph.h>
+#include <lemon/list_graph.h>
+#include <lemon/lgf_reader.h>
+#include <lemon/dfs.h>
+#include <lemon/path.h>
+
+#include "graph_test.h"
+#include "test_tools.h"
+
+using namespace lemon;
+
+char test_lgf[] =
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "5\n"
+ "6\n"
+ "@arcs\n"
+ " label\n"
+ "0 1 0\n"
+ "1 2 1\n"
+ "2 3 2\n"
+ "1 4 3\n"
+ "4 2 4\n"
+ "4 5 5\n"
+ "5 0 6\n"
+ "6 3 7\n"
+ "@attributes\n"
+ "source 0\n"
+ "target 5\n"
+ "source1 6\n"
+ "target1 3\n";
+
+
+void checkDfsCompile()
+{
+ typedef concepts::Digraph Digraph;
+ typedef Dfs<Digraph> DType;
+ typedef Digraph::Node Node;
+ typedef Digraph::Arc Arc;
+
+ Digraph G;
+ Node s, t;
+ Arc e;
+ int l, i;
+ bool b;
+ ::lemon::ignore_unused_variable_warning(l,i,b);
+
+ DType::DistMap d(G);
+ DType::PredMap p(G);
+ Path<Digraph> pp;
+ concepts::ReadMap<Arc,bool> am;
+
+ {
+ DType dfs_test(G);
+ const DType& const_dfs_test = dfs_test;
+
+ dfs_test.run(s);
+ dfs_test.run(s,t);
+ dfs_test.run();
+
+ dfs_test.init();
+ dfs_test.addSource(s);
+ e = dfs_test.processNextArc();
+ e = const_dfs_test.nextArc();
+ b = const_dfs_test.emptyQueue();
+ i = const_dfs_test.queueSize();
+
+ dfs_test.start();
+ dfs_test.start(t);
+ dfs_test.start(am);
+
+ l = const_dfs_test.dist(t);
+ e = const_dfs_test.predArc(t);
+ s = const_dfs_test.predNode(t);
+ b = const_dfs_test.reached(t);
+ d = const_dfs_test.distMap();
+ p = const_dfs_test.predMap();
+ pp = const_dfs_test.path(t);
+ }
+ {
+ DType
+ ::SetPredMap<concepts::ReadWriteMap<Node,Arc> >
+ ::SetDistMap<concepts::ReadWriteMap<Node,int> >
+ ::SetReachedMap<concepts::ReadWriteMap<Node,bool> >
+ ::SetStandardProcessedMap
+ ::SetProcessedMap<concepts::WriteMap<Node,bool> >
+ ::Create dfs_test(G);
+
+ concepts::ReadWriteMap<Node,Arc> pred_map;
+ concepts::ReadWriteMap<Node,int> dist_map;
+ concepts::ReadWriteMap<Node,bool> reached_map;
+ concepts::WriteMap<Node,bool> processed_map;
+
+ dfs_test
+ .predMap(pred_map)
+ .distMap(dist_map)
+ .reachedMap(reached_map)
+ .processedMap(processed_map);
+
+ dfs_test.run(s);
+ dfs_test.run(s,t);
+ dfs_test.run();
+ dfs_test.init();
+
+ dfs_test.addSource(s);
+ e = dfs_test.processNextArc();
+ e = dfs_test.nextArc();
+ b = dfs_test.emptyQueue();
+ i = dfs_test.queueSize();
+
+ dfs_test.start();
+ dfs_test.start(t);
+ dfs_test.start(am);
+
+ l = dfs_test.dist(t);
+ e = dfs_test.predArc(t);
+ s = dfs_test.predNode(t);
+ b = dfs_test.reached(t);
+ pp = dfs_test.path(t);
+ }
+}
+
+void checkDfsFunctionCompile()
+{
+ typedef int VType;
+ typedef concepts::Digraph Digraph;
+ typedef Digraph::Arc Arc;
+ typedef Digraph::Node Node;
+
+ Digraph g;
+ bool b;
+ ::lemon::ignore_unused_variable_warning(b);
+
+ dfs(g).run(Node());
+ b=dfs(g).run(Node(),Node());
+ dfs(g).run();
+ dfs(g)
+ .predMap(concepts::ReadWriteMap<Node,Arc>())
+ .distMap(concepts::ReadWriteMap<Node,VType>())
+ .reachedMap(concepts::ReadWriteMap<Node,bool>())
+ .processedMap(concepts::WriteMap<Node,bool>())
+ .run(Node());
+ b=dfs(g)
+ .predMap(concepts::ReadWriteMap<Node,Arc>())
+ .distMap(concepts::ReadWriteMap<Node,VType>())
+ .reachedMap(concepts::ReadWriteMap<Node,bool>())
+ .processedMap(concepts::WriteMap<Node,bool>())
+ .path(concepts::Path<Digraph>())
+ .dist(VType())
+ .run(Node(),Node());
+ dfs(g)
+ .predMap(concepts::ReadWriteMap<Node,Arc>())
+ .distMap(concepts::ReadWriteMap<Node,VType>())
+ .reachedMap(concepts::ReadWriteMap<Node,bool>())
+ .processedMap(concepts::WriteMap<Node,bool>())
+ .run();
+}
+
+template <class Digraph>
+void checkDfs() {
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+
+ Digraph G;
+ Node s, t;
+ Node s1, t1;
+
+ std::istringstream input(test_lgf);
+ digraphReader(G, input).
+ node("source", s).
+ node("target", t).
+ node("source1", s1).
+ node("target1", t1).
+ run();
+
+ Dfs<Digraph> dfs_test(G);
+ dfs_test.run(s);
+
+ Path<Digraph> p = dfs_test.path(t);
+ check(p.length() == dfs_test.dist(t),"path() found a wrong path.");
+ check(checkPath(G, p),"path() found a wrong path.");
+ check(pathSource(G, p) == s,"path() found a wrong path.");
+ check(pathTarget(G, p) == t,"path() found a wrong path.");
+
+ for(NodeIt v(G); v!=INVALID; ++v) {
+ if (dfs_test.reached(v)) {
+ check(v==s || dfs_test.predArc(v)!=INVALID, "Wrong tree.");
+ if (dfs_test.predArc(v)!=INVALID ) {
+ Arc e=dfs_test.predArc(v);
+ Node u=G.source(e);
+ check(u==dfs_test.predNode(v),"Wrong tree.");
+ check(dfs_test.dist(v) - dfs_test.dist(u) == 1,
+ "Wrong distance. (" << dfs_test.dist(u) << "->"
+ << dfs_test.dist(v) << ")");
+ }
+ }
+ }
+
+ {
+ Dfs<Digraph> dfs(G);
+ check(dfs.run(s1,t1) && dfs.reached(t1),"Node 3 is reachable from Node 6.");
+ }
+
+ {
+ NullMap<Node,Arc> myPredMap;
+ dfs(G).predMap(myPredMap).run(s);
+ }
+}
+
+int main()
+{
+ checkDfs<ListDigraph>();
+ checkDfs<SmartDigraph>();
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/digraph_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/digraph_test.cc
new file mode 100644
index 00000000000..e3ff54577ea
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/digraph_test.cc
@@ -0,0 +1,569 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <lemon/concepts/digraph.h>
+#include <lemon/list_graph.h>
+#include <lemon/smart_graph.h>
+#include <lemon/static_graph.h>
+#include <lemon/full_graph.h>
+
+#include "test_tools.h"
+#include "graph_test.h"
+
+using namespace lemon;
+using namespace lemon::concepts;
+
+template <class Digraph>
+void checkDigraphBuild() {
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+ Digraph G;
+
+ checkGraphNodeList(G, 0);
+ checkGraphArcList(G, 0);
+
+ G.reserveNode(3);
+ G.reserveArc(4);
+
+ Node
+ n1 = G.addNode(),
+ n2 = G.addNode(),
+ n3 = G.addNode();
+ checkGraphNodeList(G, 3);
+ checkGraphArcList(G, 0);
+
+ Arc a1 = G.addArc(n1, n2);
+ check(G.source(a1) == n1 && G.target(a1) == n2, "Wrong arc");
+ checkGraphNodeList(G, 3);
+ checkGraphArcList(G, 1);
+
+ checkGraphOutArcList(G, n1, 1);
+ checkGraphOutArcList(G, n2, 0);
+ checkGraphOutArcList(G, n3, 0);
+
+ checkGraphInArcList(G, n1, 0);
+ checkGraphInArcList(G, n2, 1);
+ checkGraphInArcList(G, n3, 0);
+
+ checkGraphConArcList(G, 1);
+
+ Arc a2 = G.addArc(n2, n1),
+ a3 = G.addArc(n2, n3),
+ a4 = G.addArc(n2, n3);
+ ::lemon::ignore_unused_variable_warning(a2,a3,a4);
+
+ checkGraphNodeList(G, 3);
+ checkGraphArcList(G, 4);
+
+ checkGraphOutArcList(G, n1, 1);
+ checkGraphOutArcList(G, n2, 3);
+ checkGraphOutArcList(G, n3, 0);
+
+ checkGraphInArcList(G, n1, 1);
+ checkGraphInArcList(G, n2, 1);
+ checkGraphInArcList(G, n3, 2);
+
+ checkGraphConArcList(G, 4);
+
+ checkNodeIds(G);
+ checkArcIds(G);
+ checkGraphNodeMap(G);
+ checkGraphArcMap(G);
+}
+
+template <class Digraph>
+void checkDigraphSplit() {
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+
+ Digraph G;
+ Node n1 = G.addNode(), n2 = G.addNode(), n3 = G.addNode();
+ Arc a1 = G.addArc(n1, n2), a2 = G.addArc(n2, n1),
+ a3 = G.addArc(n2, n3), a4 = G.addArc(n2, n3);
+ ::lemon::ignore_unused_variable_warning(a1,a2,a3,a4);
+
+ Node n4 = G.split(n2);
+
+ check(G.target(OutArcIt(G, n2)) == n4 &&
+ G.source(InArcIt(G, n4)) == n2,
+ "Wrong split.");
+
+ checkGraphNodeList(G, 4);
+ checkGraphArcList(G, 5);
+
+ checkGraphOutArcList(G, n1, 1);
+ checkGraphOutArcList(G, n2, 1);
+ checkGraphOutArcList(G, n3, 0);
+ checkGraphOutArcList(G, n4, 3);
+
+ checkGraphInArcList(G, n1, 1);
+ checkGraphInArcList(G, n2, 1);
+ checkGraphInArcList(G, n3, 2);
+ checkGraphInArcList(G, n4, 1);
+
+ checkGraphConArcList(G, 5);
+}
+
+template <class Digraph>
+void checkDigraphAlter() {
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+
+ Digraph G;
+ Node n1 = G.addNode(), n2 = G.addNode(),
+ n3 = G.addNode(), n4 = G.addNode();
+ Arc a1 = G.addArc(n1, n2), a2 = G.addArc(n4, n1),
+ a3 = G.addArc(n4, n3), a4 = G.addArc(n4, n3),
+ a5 = G.addArc(n2, n4);
+ ::lemon::ignore_unused_variable_warning(a1,a2,a3,a5);
+
+ checkGraphNodeList(G, 4);
+ checkGraphArcList(G, 5);
+
+ // Check changeSource() and changeTarget()
+ G.changeTarget(a4, n1);
+
+ checkGraphNodeList(G, 4);
+ checkGraphArcList(G, 5);
+
+ checkGraphOutArcList(G, n1, 1);
+ checkGraphOutArcList(G, n2, 1);
+ checkGraphOutArcList(G, n3, 0);
+ checkGraphOutArcList(G, n4, 3);
+
+ checkGraphInArcList(G, n1, 2);
+ checkGraphInArcList(G, n2, 1);
+ checkGraphInArcList(G, n3, 1);
+ checkGraphInArcList(G, n4, 1);
+
+ checkGraphConArcList(G, 5);
+
+ G.changeSource(a4, n3);
+
+ checkGraphNodeList(G, 4);
+ checkGraphArcList(G, 5);
+
+ checkGraphOutArcList(G, n1, 1);
+ checkGraphOutArcList(G, n2, 1);
+ checkGraphOutArcList(G, n3, 1);
+ checkGraphOutArcList(G, n4, 2);
+
+ checkGraphInArcList(G, n1, 2);
+ checkGraphInArcList(G, n2, 1);
+ checkGraphInArcList(G, n3, 1);
+ checkGraphInArcList(G, n4, 1);
+
+ checkGraphConArcList(G, 5);
+
+ // Check contract()
+ G.contract(n2, n4, false);
+
+ checkGraphNodeList(G, 3);
+ checkGraphArcList(G, 5);
+
+ checkGraphOutArcList(G, n1, 1);
+ checkGraphOutArcList(G, n2, 3);
+ checkGraphOutArcList(G, n3, 1);
+
+ checkGraphInArcList(G, n1, 2);
+ checkGraphInArcList(G, n2, 2);
+ checkGraphInArcList(G, n3, 1);
+
+ checkGraphConArcList(G, 5);
+
+ G.contract(n2, n1);
+
+ checkGraphNodeList(G, 2);
+ checkGraphArcList(G, 3);
+
+ checkGraphOutArcList(G, n2, 2);
+ checkGraphOutArcList(G, n3, 1);
+
+ checkGraphInArcList(G, n2, 2);
+ checkGraphInArcList(G, n3, 1);
+
+ checkGraphConArcList(G, 3);
+}
+
+template <class Digraph>
+void checkDigraphErase() {
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+
+ Digraph G;
+ Node n1 = G.addNode(), n2 = G.addNode(),
+ n3 = G.addNode(), n4 = G.addNode();
+ Arc a1 = G.addArc(n1, n2), a2 = G.addArc(n4, n1),
+ a3 = G.addArc(n4, n3), a4 = G.addArc(n3, n1),
+ a5 = G.addArc(n2, n4);
+ ::lemon::ignore_unused_variable_warning(a2,a3,a4,a5);
+
+ // Check arc deletion
+ G.erase(a1);
+
+ checkGraphNodeList(G, 4);
+ checkGraphArcList(G, 4);
+
+ checkGraphOutArcList(G, n1, 0);
+ checkGraphOutArcList(G, n2, 1);
+ checkGraphOutArcList(G, n3, 1);
+ checkGraphOutArcList(G, n4, 2);
+
+ checkGraphInArcList(G, n1, 2);
+ checkGraphInArcList(G, n2, 0);
+ checkGraphInArcList(G, n3, 1);
+ checkGraphInArcList(G, n4, 1);
+
+ checkGraphConArcList(G, 4);
+
+ // Check node deletion
+ G.erase(n4);
+
+ checkGraphNodeList(G, 3);
+ checkGraphArcList(G, 1);
+
+ checkGraphOutArcList(G, n1, 0);
+ checkGraphOutArcList(G, n2, 0);
+ checkGraphOutArcList(G, n3, 1);
+ checkGraphOutArcList(G, n4, 0);
+
+ checkGraphInArcList(G, n1, 1);
+ checkGraphInArcList(G, n2, 0);
+ checkGraphInArcList(G, n3, 0);
+ checkGraphInArcList(G, n4, 0);
+
+ checkGraphConArcList(G, 1);
+}
+
+
+template <class Digraph>
+void checkDigraphSnapshot() {
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+
+ Digraph G;
+ Node n1 = G.addNode(), n2 = G.addNode(), n3 = G.addNode();
+ Arc a1 = G.addArc(n1, n2), a2 = G.addArc(n2, n1),
+ a3 = G.addArc(n2, n3), a4 = G.addArc(n2, n3);
+ ::lemon::ignore_unused_variable_warning(a1,a2,a3,a4);
+
+ typename Digraph::Snapshot snapshot(G);
+
+ Node n = G.addNode();
+ G.addArc(n3, n);
+ G.addArc(n, n3);
+
+ checkGraphNodeList(G, 4);
+ checkGraphArcList(G, 6);
+
+ snapshot.restore();
+
+ checkGraphNodeList(G, 3);
+ checkGraphArcList(G, 4);
+
+ checkGraphOutArcList(G, n1, 1);
+ checkGraphOutArcList(G, n2, 3);
+ checkGraphOutArcList(G, n3, 0);
+
+ checkGraphInArcList(G, n1, 1);
+ checkGraphInArcList(G, n2, 1);
+ checkGraphInArcList(G, n3, 2);
+
+ checkGraphConArcList(G, 4);
+
+ checkNodeIds(G);
+ checkArcIds(G);
+ checkGraphNodeMap(G);
+ checkGraphArcMap(G);
+
+ G.addNode();
+ snapshot.save(G);
+
+ G.addArc(G.addNode(), G.addNode());
+
+ snapshot.restore();
+ snapshot.save(G);
+
+ checkGraphNodeList(G, 4);
+ checkGraphArcList(G, 4);
+
+ G.addArc(G.addNode(), G.addNode());
+
+ snapshot.restore();
+
+ checkGraphNodeList(G, 4);
+ checkGraphArcList(G, 4);
+}
+
+void checkConcepts() {
+ { // Checking digraph components
+ checkConcept<BaseDigraphComponent, BaseDigraphComponent >();
+
+ checkConcept<IDableDigraphComponent<>,
+ IDableDigraphComponent<> >();
+
+ checkConcept<IterableDigraphComponent<>,
+ IterableDigraphComponent<> >();
+
+ checkConcept<MappableDigraphComponent<>,
+ MappableDigraphComponent<> >();
+ }
+ { // Checking skeleton digraph
+ checkConcept<Digraph, Digraph>();
+ }
+ { // Checking ListDigraph
+ checkConcept<Digraph, ListDigraph>();
+ checkConcept<AlterableDigraphComponent<>, ListDigraph>();
+ checkConcept<ExtendableDigraphComponent<>, ListDigraph>();
+ checkConcept<ClearableDigraphComponent<>, ListDigraph>();
+ checkConcept<ErasableDigraphComponent<>, ListDigraph>();
+ }
+ { // Checking SmartDigraph
+ checkConcept<Digraph, SmartDigraph>();
+ checkConcept<AlterableDigraphComponent<>, SmartDigraph>();
+ checkConcept<ExtendableDigraphComponent<>, SmartDigraph>();
+ checkConcept<ClearableDigraphComponent<>, SmartDigraph>();
+ }
+ { // Checking StaticDigraph
+ checkConcept<Digraph, StaticDigraph>();
+ checkConcept<ClearableDigraphComponent<>, StaticDigraph>();
+ }
+ { // Checking FullDigraph
+ checkConcept<Digraph, FullDigraph>();
+ }
+}
+
+template <typename Digraph>
+void checkDigraphValidity() {
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+ Digraph g;
+
+ Node
+ n1 = g.addNode(),
+ n2 = g.addNode(),
+ n3 = g.addNode();
+
+ Arc
+ e1 = g.addArc(n1, n2),
+ e2 = g.addArc(n2, n3);
+ ::lemon::ignore_unused_variable_warning(e2);
+
+ check(g.valid(n1), "Wrong validity check");
+ check(g.valid(e1), "Wrong validity check");
+
+ check(!g.valid(g.nodeFromId(-1)), "Wrong validity check");
+ check(!g.valid(g.arcFromId(-1)), "Wrong validity check");
+}
+
+template <typename Digraph>
+void checkDigraphValidityErase() {
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+ Digraph g;
+
+ Node
+ n1 = g.addNode(),
+ n2 = g.addNode(),
+ n3 = g.addNode();
+
+ Arc
+ e1 = g.addArc(n1, n2),
+ e2 = g.addArc(n2, n3);
+
+ check(g.valid(n1), "Wrong validity check");
+ check(g.valid(e1), "Wrong validity check");
+
+ g.erase(n1);
+
+ check(!g.valid(n1), "Wrong validity check");
+ check(g.valid(n2), "Wrong validity check");
+ check(g.valid(n3), "Wrong validity check");
+ check(!g.valid(e1), "Wrong validity check");
+ check(g.valid(e2), "Wrong validity check");
+
+ check(!g.valid(g.nodeFromId(-1)), "Wrong validity check");
+ check(!g.valid(g.arcFromId(-1)), "Wrong validity check");
+}
+
+void checkStaticDigraph() {
+ SmartDigraph g;
+ SmartDigraph::NodeMap<StaticDigraph::Node> nref(g);
+ SmartDigraph::ArcMap<StaticDigraph::Arc> aref(g);
+
+ StaticDigraph G;
+
+ checkGraphNodeList(G, 0);
+ checkGraphArcList(G, 0);
+
+ G.build(g, nref, aref);
+
+ checkGraphNodeList(G, 0);
+ checkGraphArcList(G, 0);
+
+ SmartDigraph::Node
+ n1 = g.addNode(),
+ n2 = g.addNode(),
+ n3 = g.addNode();
+
+ G.build(g, nref, aref);
+
+ checkGraphNodeList(G, 3);
+ checkGraphArcList(G, 0);
+
+ SmartDigraph::Arc a1 = g.addArc(n1, n2);
+
+ G.build(g, nref, aref);
+
+ check(G.source(aref[a1]) == nref[n1] && G.target(aref[a1]) == nref[n2],
+ "Wrong arc or wrong references");
+ checkGraphNodeList(G, 3);
+ checkGraphArcList(G, 1);
+
+ checkGraphOutArcList(G, nref[n1], 1);
+ checkGraphOutArcList(G, nref[n2], 0);
+ checkGraphOutArcList(G, nref[n3], 0);
+
+ checkGraphInArcList(G, nref[n1], 0);
+ checkGraphInArcList(G, nref[n2], 1);
+ checkGraphInArcList(G, nref[n3], 0);
+
+ checkGraphConArcList(G, 1);
+
+ SmartDigraph::Arc
+ a2 = g.addArc(n2, n1),
+ a3 = g.addArc(n2, n3),
+ a4 = g.addArc(n2, n3);
+ ::lemon::ignore_unused_variable_warning(a2,a3,a4);
+
+ digraphCopy(g, G).nodeRef(nref).run();
+
+ checkGraphNodeList(G, 3);
+ checkGraphArcList(G, 4);
+
+ checkGraphOutArcList(G, nref[n1], 1);
+ checkGraphOutArcList(G, nref[n2], 3);
+ checkGraphOutArcList(G, nref[n3], 0);
+
+ checkGraphInArcList(G, nref[n1], 1);
+ checkGraphInArcList(G, nref[n2], 1);
+ checkGraphInArcList(G, nref[n3], 2);
+
+ checkGraphConArcList(G, 4);
+
+ std::vector<std::pair<int,int> > arcs;
+ arcs.push_back(std::make_pair(0,1));
+ arcs.push_back(std::make_pair(0,2));
+ arcs.push_back(std::make_pair(1,3));
+ arcs.push_back(std::make_pair(1,2));
+ arcs.push_back(std::make_pair(3,0));
+ arcs.push_back(std::make_pair(3,3));
+ arcs.push_back(std::make_pair(4,2));
+ arcs.push_back(std::make_pair(4,3));
+ arcs.push_back(std::make_pair(4,1));
+
+ G.build(6, arcs.begin(), arcs.end());
+
+ checkGraphNodeList(G, 6);
+ checkGraphArcList(G, 9);
+
+ checkGraphOutArcList(G, G.node(0), 2);
+ checkGraphOutArcList(G, G.node(1), 2);
+ checkGraphOutArcList(G, G.node(2), 0);
+ checkGraphOutArcList(G, G.node(3), 2);
+ checkGraphOutArcList(G, G.node(4), 3);
+ checkGraphOutArcList(G, G.node(5), 0);
+
+ checkGraphInArcList(G, G.node(0), 1);
+ checkGraphInArcList(G, G.node(1), 2);
+ checkGraphInArcList(G, G.node(2), 3);
+ checkGraphInArcList(G, G.node(3), 3);
+ checkGraphInArcList(G, G.node(4), 0);
+ checkGraphInArcList(G, G.node(5), 0);
+
+ checkGraphConArcList(G, 9);
+
+ checkNodeIds(G);
+ checkArcIds(G);
+ checkGraphNodeMap(G);
+ checkGraphArcMap(G);
+
+ int n = G.nodeNum();
+ int m = G.arcNum();
+ check(G.index(G.node(n-1)) == n-1, "Wrong index.");
+ check(G.index(G.arc(m-1)) == m-1, "Wrong index.");
+}
+
+void checkFullDigraph(int num) {
+ typedef FullDigraph Digraph;
+ DIGRAPH_TYPEDEFS(Digraph);
+
+ Digraph G(num);
+ check(G.nodeNum() == num && G.arcNum() == num * num, "Wrong size");
+
+ G.resize(num);
+ check(G.nodeNum() == num && G.arcNum() == num * num, "Wrong size");
+
+ checkGraphNodeList(G, num);
+ checkGraphArcList(G, num * num);
+
+ for (NodeIt n(G); n != INVALID; ++n) {
+ checkGraphOutArcList(G, n, num);
+ checkGraphInArcList(G, n, num);
+ }
+
+ checkGraphConArcList(G, num * num);
+
+ checkNodeIds(G);
+ checkArcIds(G);
+ checkGraphNodeMap(G);
+ checkGraphArcMap(G);
+
+ for (int i = 0; i < G.nodeNum(); ++i) {
+ check(G.index(G(i)) == i, "Wrong index");
+ }
+
+ for (NodeIt s(G); s != INVALID; ++s) {
+ for (NodeIt t(G); t != INVALID; ++t) {
+ Arc a = G.arc(s, t);
+ check(G.source(a) == s && G.target(a) == t, "Wrong arc lookup");
+ }
+ }
+}
+
+void checkDigraphs() {
+ { // Checking ListDigraph
+ checkDigraphBuild<ListDigraph>();
+ checkDigraphSplit<ListDigraph>();
+ checkDigraphAlter<ListDigraph>();
+ checkDigraphErase<ListDigraph>();
+ checkDigraphSnapshot<ListDigraph>();
+ checkDigraphValidityErase<ListDigraph>();
+ }
+ { // Checking SmartDigraph
+ checkDigraphBuild<SmartDigraph>();
+ checkDigraphSplit<SmartDigraph>();
+ checkDigraphSnapshot<SmartDigraph>();
+ checkDigraphValidity<SmartDigraph>();
+ }
+ { // Checking StaticDigraph
+ checkStaticDigraph();
+ }
+ { // Checking FullDigraph
+ checkFullDigraph(8);
+ }
+}
+
+int main() {
+ checkDigraphs();
+ checkConcepts();
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/dijkstra_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/dijkstra_test.cc
new file mode 100644
index 00000000000..20cc76b36a8
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/dijkstra_test.cc
@@ -0,0 +1,246 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <lemon/concepts/digraph.h>
+#include <lemon/smart_graph.h>
+#include <lemon/list_graph.h>
+#include <lemon/lgf_reader.h>
+#include <lemon/dijkstra.h>
+#include <lemon/path.h>
+#include <lemon/bin_heap.h>
+
+#include "graph_test.h"
+#include "test_tools.h"
+
+using namespace lemon;
+
+char test_lgf[] =
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "@arcs\n"
+ " label length\n"
+ "0 1 0 1\n"
+ "1 2 1 1\n"
+ "2 3 2 1\n"
+ "0 3 4 5\n"
+ "0 3 5 10\n"
+ "0 3 6 7\n"
+ "4 2 7 1\n"
+ "@attributes\n"
+ "source 0\n"
+ "target 3\n";
+
+void checkDijkstraCompile()
+{
+ typedef int VType;
+ typedef concepts::Digraph Digraph;
+ typedef concepts::ReadMap<Digraph::Arc,VType> LengthMap;
+ typedef Dijkstra<Digraph, LengthMap> DType;
+ typedef Digraph::Node Node;
+ typedef Digraph::Arc Arc;
+
+ Digraph G;
+ Node s, t, n;
+ Arc e;
+ VType l;
+ int i;
+ bool b;
+ ::lemon::ignore_unused_variable_warning(l,i,b);
+
+ DType::DistMap d(G);
+ DType::PredMap p(G);
+ LengthMap length;
+ Path<Digraph> pp;
+ concepts::ReadMap<Node,bool> nm;
+
+ {
+ DType dijkstra_test(G,length);
+ const DType& const_dijkstra_test = dijkstra_test;
+
+ dijkstra_test.run(s);
+ dijkstra_test.run(s,t);
+
+ dijkstra_test.init();
+ dijkstra_test.addSource(s);
+ dijkstra_test.addSource(s, 1);
+ n = dijkstra_test.processNextNode();
+ n = const_dijkstra_test.nextNode();
+ b = const_dijkstra_test.emptyQueue();
+ i = const_dijkstra_test.queueSize();
+
+ dijkstra_test.start();
+ dijkstra_test.start(t);
+ dijkstra_test.start(nm);
+
+ l = const_dijkstra_test.dist(t);
+ e = const_dijkstra_test.predArc(t);
+ s = const_dijkstra_test.predNode(t);
+ b = const_dijkstra_test.reached(t);
+ b = const_dijkstra_test.processed(t);
+ d = const_dijkstra_test.distMap();
+ p = const_dijkstra_test.predMap();
+ pp = const_dijkstra_test.path(t);
+ l = const_dijkstra_test.currentDist(t);
+ }
+ {
+ DType
+ ::SetPredMap<concepts::ReadWriteMap<Node,Arc> >
+ ::SetDistMap<concepts::ReadWriteMap<Node,VType> >
+ ::SetStandardProcessedMap
+ ::SetProcessedMap<concepts::WriteMap<Node,bool> >
+ ::SetOperationTraits<DijkstraDefaultOperationTraits<VType> >
+ ::SetHeap<BinHeap<VType, concepts::ReadWriteMap<Node,int> > >
+ ::SetStandardHeap<BinHeap<VType, concepts::ReadWriteMap<Node,int> > >
+ ::SetHeap<BinHeap<VType, concepts::ReadWriteMap<Node,int> >,
+ concepts::ReadWriteMap<Node,int> >
+ ::Create dijkstra_test(G,length);
+
+ LengthMap length_map;
+ concepts::ReadWriteMap<Node,Arc> pred_map;
+ concepts::ReadWriteMap<Node,VType> dist_map;
+ concepts::WriteMap<Node,bool> processed_map;
+ concepts::ReadWriteMap<Node,int> heap_cross_ref;
+ BinHeap<VType, concepts::ReadWriteMap<Node,int> > heap(heap_cross_ref);
+
+ dijkstra_test
+ .lengthMap(length_map)
+ .predMap(pred_map)
+ .distMap(dist_map)
+ .processedMap(processed_map)
+ .heap(heap, heap_cross_ref);
+
+ dijkstra_test.run(s);
+ dijkstra_test.run(s,t);
+
+ dijkstra_test.addSource(s);
+ dijkstra_test.addSource(s, 1);
+ n = dijkstra_test.processNextNode();
+ n = dijkstra_test.nextNode();
+ b = dijkstra_test.emptyQueue();
+ i = dijkstra_test.queueSize();
+
+ dijkstra_test.start();
+ dijkstra_test.start(t);
+ dijkstra_test.start(nm);
+
+ l = dijkstra_test.dist(t);
+ e = dijkstra_test.predArc(t);
+ s = dijkstra_test.predNode(t);
+ b = dijkstra_test.reached(t);
+ b = dijkstra_test.processed(t);
+ pp = dijkstra_test.path(t);
+ l = dijkstra_test.currentDist(t);
+ }
+
+}
+
+void checkDijkstraFunctionCompile()
+{
+ typedef int VType;
+ typedef concepts::Digraph Digraph;
+ typedef Digraph::Arc Arc;
+ typedef Digraph::Node Node;
+ typedef concepts::ReadMap<Digraph::Arc,VType> LengthMap;
+
+ Digraph g;
+ bool b;
+ ::lemon::ignore_unused_variable_warning(b);
+
+ dijkstra(g,LengthMap()).run(Node());
+ b=dijkstra(g,LengthMap()).run(Node(),Node());
+ dijkstra(g,LengthMap())
+ .predMap(concepts::ReadWriteMap<Node,Arc>())
+ .distMap(concepts::ReadWriteMap<Node,VType>())
+ .processedMap(concepts::WriteMap<Node,bool>())
+ .run(Node());
+ b=dijkstra(g,LengthMap())
+ .predMap(concepts::ReadWriteMap<Node,Arc>())
+ .distMap(concepts::ReadWriteMap<Node,VType>())
+ .processedMap(concepts::WriteMap<Node,bool>())
+ .path(concepts::Path<Digraph>())
+ .dist(VType())
+ .run(Node(),Node());
+}
+
+template <class Digraph>
+void checkDijkstra() {
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+ typedef typename Digraph::template ArcMap<int> LengthMap;
+
+ Digraph G;
+ Node s, t;
+ LengthMap length(G);
+
+ std::istringstream input(test_lgf);
+ digraphReader(G, input).
+ arcMap("length", length).
+ node("source", s).
+ node("target", t).
+ run();
+
+ Dijkstra<Digraph, LengthMap>
+ dijkstra_test(G, length);
+ dijkstra_test.run(s);
+
+ check(dijkstra_test.dist(t)==3,"Dijkstra found a wrong path.");
+
+ Path<Digraph> p = dijkstra_test.path(t);
+ check(p.length()==3,"path() found a wrong path.");
+ check(checkPath(G, p),"path() found a wrong path.");
+ check(pathSource(G, p) == s,"path() found a wrong path.");
+ check(pathTarget(G, p) == t,"path() found a wrong path.");
+
+ for(ArcIt e(G); e!=INVALID; ++e) {
+ Node u=G.source(e);
+ Node v=G.target(e);
+ check( !dijkstra_test.reached(u) ||
+ (dijkstra_test.dist(v) - dijkstra_test.dist(u) <= length[e]),
+ "Wrong output. dist(target)-dist(source)-arc_length=" <<
+ dijkstra_test.dist(v) - dijkstra_test.dist(u) - length[e]);
+ }
+
+ for(NodeIt v(G); v!=INVALID; ++v) {
+ if (dijkstra_test.reached(v)) {
+ check(v==s || dijkstra_test.predArc(v)!=INVALID, "Wrong tree.");
+ if (dijkstra_test.predArc(v)!=INVALID ) {
+ Arc e=dijkstra_test.predArc(v);
+ Node u=G.source(e);
+ check(u==dijkstra_test.predNode(v),"Wrong tree.");
+ check(dijkstra_test.dist(v) - dijkstra_test.dist(u) == length[e],
+ "Wrong distance! Difference: " <<
+ std::abs(dijkstra_test.dist(v)-dijkstra_test.dist(u)-length[e]));
+ }
+ }
+ }
+
+ {
+ NullMap<Node,Arc> myPredMap;
+ dijkstra(G,length).predMap(myPredMap).run(s);
+ }
+}
+
+int main() {
+ checkDijkstra<ListDigraph>();
+ checkDijkstra<SmartDigraph>();
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/dim_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/dim_test.cc
new file mode 100644
index 00000000000..0b2b9250feb
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/dim_test.cc
@@ -0,0 +1,87 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <lemon/dim2.h>
+#include <iostream>
+#include "test_tools.h"
+
+using namespace std;
+using namespace lemon;
+
+int main()
+{
+ typedef dim2::Point<int> Point;
+
+ Point p;
+ check(p.size()==2, "Wrong dim2::Point initialization.");
+
+ Point a(1,2);
+ Point b(3,4);
+ check(a[0]==1 && a[1]==2, "Wrong dim2::Point initialization.");
+
+ p = a+b;
+ check(p.x==4 && p.y==6, "Wrong dim2::Point addition.");
+
+ p = a-b;
+ check(p.x==-2 && p.y==-2, "Wrong dim2::Point subtraction.");
+
+ check(a.normSquare()==5,"Wrong dim2::Point norm calculation.");
+ check(a*b==11, "Wrong dim2::Point scalar product.");
+
+ int l=2;
+ p = a*l;
+ check(p.x==2 && p.y==4, "Wrong dim2::Point multiplication by a scalar.");
+
+ p = b/l;
+ check(p.x==1 && p.y==2, "Wrong dim2::Point division by a scalar.");
+
+ typedef dim2::Box<int> Box;
+ Box box1;
+ check(box1.empty(), "Wrong empty() in dim2::Box.");
+
+ box1.add(a);
+ check(!box1.empty(), "Wrong empty() in dim2::Box.");
+ box1.add(b);
+
+ check(box1.left()==1 && box1.bottom()==2 &&
+ box1.right()==3 && box1.top()==4,
+ "Wrong addition of points to dim2::Box.");
+
+ check(box1.inside(Point(2,3)), "Wrong inside() in dim2::Box.");
+ check(box1.inside(Point(1,3)), "Wrong inside() in dim2::Box.");
+ check(!box1.inside(Point(0,3)), "Wrong inside() in dim2::Box.");
+
+ Box box2(Point(2,2));
+ check(!box2.empty(), "Wrong empty() in dim2::Box.");
+
+ box2.bottomLeft(Point(2,0));
+ box2.topRight(Point(5,3));
+ Box box3 = box1 & box2;
+ check(!box3.empty() &&
+ box3.left()==2 && box3.bottom()==2 &&
+ box3.right()==3 && box3.top()==3,
+ "Wrong intersection of two dim2::Box objects.");
+
+ box1.add(box2);
+ check(!box1.empty() &&
+ box1.left()==1 && box1.bottom()==0 &&
+ box1.right()==5 && box1.top()==4,
+ "Wrong addition of two dim2::Box objects.");
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/edge_set_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/edge_set_test.cc
new file mode 100644
index 00000000000..dbe74a9fcb5
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/edge_set_test.cc
@@ -0,0 +1,396 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <iostream>
+#include <vector>
+
+#include <lemon/concepts/digraph.h>
+#include <lemon/concepts/graph.h>
+#include <lemon/concept_check.h>
+
+#include <lemon/list_graph.h>
+
+#include <lemon/edge_set.h>
+
+#include "graph_test.h"
+#include "test_tools.h"
+
+using namespace lemon;
+
+void checkSmartArcSet() {
+ checkConcept<concepts::Digraph, SmartArcSet<ListDigraph> >();
+
+ typedef ListDigraph Digraph;
+ typedef SmartArcSet<Digraph> ArcSet;
+
+ Digraph digraph;
+ Digraph::Node
+ n1 = digraph.addNode(),
+ n2 = digraph.addNode();
+
+ Digraph::Arc ga1 = digraph.addArc(n1, n2);
+ ::lemon::ignore_unused_variable_warning(ga1);
+
+ ArcSet arc_set(digraph);
+
+ Digraph::Arc ga2 = digraph.addArc(n2, n1);
+ ::lemon::ignore_unused_variable_warning(ga2);
+
+ checkGraphNodeList(arc_set, 2);
+ checkGraphArcList(arc_set, 0);
+
+ Digraph::Node
+ n3 = digraph.addNode();
+ checkGraphNodeList(arc_set, 3);
+ checkGraphArcList(arc_set, 0);
+
+ ArcSet::Arc a1 = arc_set.addArc(n1, n2);
+ check(arc_set.source(a1) == n1 && arc_set.target(a1) == n2, "Wrong arc");
+ checkGraphNodeList(arc_set, 3);
+ checkGraphArcList(arc_set, 1);
+
+ checkGraphOutArcList(arc_set, n1, 1);
+ checkGraphOutArcList(arc_set, n2, 0);
+ checkGraphOutArcList(arc_set, n3, 0);
+
+ checkGraphInArcList(arc_set, n1, 0);
+ checkGraphInArcList(arc_set, n2, 1);
+ checkGraphInArcList(arc_set, n3, 0);
+
+ checkGraphConArcList(arc_set, 1);
+
+ ArcSet::Arc a2 = arc_set.addArc(n2, n1),
+ a3 = arc_set.addArc(n2, n3),
+ a4 = arc_set.addArc(n2, n3);
+ ::lemon::ignore_unused_variable_warning(a2,a3,a4);
+
+ checkGraphNodeList(arc_set, 3);
+ checkGraphArcList(arc_set, 4);
+
+ checkGraphOutArcList(arc_set, n1, 1);
+ checkGraphOutArcList(arc_set, n2, 3);
+ checkGraphOutArcList(arc_set, n3, 0);
+
+ checkGraphInArcList(arc_set, n1, 1);
+ checkGraphInArcList(arc_set, n2, 1);
+ checkGraphInArcList(arc_set, n3, 2);
+
+ checkGraphConArcList(arc_set, 4);
+
+ checkNodeIds(arc_set);
+ checkArcIds(arc_set);
+ checkGraphNodeMap(arc_set);
+ checkGraphArcMap(arc_set);
+
+ check(arc_set.valid(), "Wrong validity");
+ digraph.erase(n1);
+ check(!arc_set.valid(), "Wrong validity");
+}
+
+void checkListArcSet() {
+ checkConcept<concepts::Digraph, SmartArcSet<ListDigraph> >();
+
+ typedef ListDigraph Digraph;
+ typedef ListArcSet<Digraph> ArcSet;
+
+ Digraph digraph;
+ Digraph::Node
+ n1 = digraph.addNode(),
+ n2 = digraph.addNode();
+
+ Digraph::Arc ga1 = digraph.addArc(n1, n2);
+ ::lemon::ignore_unused_variable_warning(ga1);
+
+ ArcSet arc_set(digraph);
+
+ Digraph::Arc ga2 = digraph.addArc(n2, n1);
+ ::lemon::ignore_unused_variable_warning(ga2);
+
+ checkGraphNodeList(arc_set, 2);
+ checkGraphArcList(arc_set, 0);
+
+ Digraph::Node
+ n3 = digraph.addNode();
+ checkGraphNodeList(arc_set, 3);
+ checkGraphArcList(arc_set, 0);
+
+ ArcSet::Arc a1 = arc_set.addArc(n1, n2);
+ check(arc_set.source(a1) == n1 && arc_set.target(a1) == n2, "Wrong arc");
+ checkGraphNodeList(arc_set, 3);
+ checkGraphArcList(arc_set, 1);
+
+ checkGraphOutArcList(arc_set, n1, 1);
+ checkGraphOutArcList(arc_set, n2, 0);
+ checkGraphOutArcList(arc_set, n3, 0);
+
+ checkGraphInArcList(arc_set, n1, 0);
+ checkGraphInArcList(arc_set, n2, 1);
+ checkGraphInArcList(arc_set, n3, 0);
+
+ checkGraphConArcList(arc_set, 1);
+
+ ArcSet::Arc a2 = arc_set.addArc(n2, n1),
+ a3 = arc_set.addArc(n2, n3),
+ a4 = arc_set.addArc(n2, n3);
+ ::lemon::ignore_unused_variable_warning(a2,a3,a4);
+
+ checkGraphNodeList(arc_set, 3);
+ checkGraphArcList(arc_set, 4);
+
+ checkGraphOutArcList(arc_set, n1, 1);
+ checkGraphOutArcList(arc_set, n2, 3);
+ checkGraphOutArcList(arc_set, n3, 0);
+
+ checkGraphInArcList(arc_set, n1, 1);
+ checkGraphInArcList(arc_set, n2, 1);
+ checkGraphInArcList(arc_set, n3, 2);
+
+ checkGraphConArcList(arc_set, 4);
+
+ checkNodeIds(arc_set);
+ checkArcIds(arc_set);
+ checkGraphNodeMap(arc_set);
+ checkGraphArcMap(arc_set);
+
+ digraph.erase(n1);
+
+ checkGraphNodeList(arc_set, 2);
+ checkGraphArcList(arc_set, 2);
+
+ checkGraphOutArcList(arc_set, n2, 2);
+ checkGraphOutArcList(arc_set, n3, 0);
+
+ checkGraphInArcList(arc_set, n2, 0);
+ checkGraphInArcList(arc_set, n3, 2);
+
+ checkNodeIds(arc_set);
+ checkArcIds(arc_set);
+ checkGraphNodeMap(arc_set);
+ checkGraphArcMap(arc_set);
+
+ checkGraphConArcList(arc_set, 2);
+}
+
+void checkSmartEdgeSet() {
+ checkConcept<concepts::Digraph, SmartEdgeSet<ListDigraph> >();
+
+ typedef ListDigraph Digraph;
+ typedef SmartEdgeSet<Digraph> EdgeSet;
+
+ Digraph digraph;
+ Digraph::Node
+ n1 = digraph.addNode(),
+ n2 = digraph.addNode();
+
+ Digraph::Arc ga1 = digraph.addArc(n1, n2);
+ ::lemon::ignore_unused_variable_warning(ga1);
+
+ EdgeSet edge_set(digraph);
+
+ Digraph::Arc ga2 = digraph.addArc(n2, n1);
+ ::lemon::ignore_unused_variable_warning(ga2);
+
+ checkGraphNodeList(edge_set, 2);
+ checkGraphArcList(edge_set, 0);
+ checkGraphEdgeList(edge_set, 0);
+
+ Digraph::Node
+ n3 = digraph.addNode();
+ checkGraphNodeList(edge_set, 3);
+ checkGraphArcList(edge_set, 0);
+ checkGraphEdgeList(edge_set, 0);
+
+ EdgeSet::Edge e1 = edge_set.addEdge(n1, n2);
+ check((edge_set.u(e1) == n1 && edge_set.v(e1) == n2) ||
+ (edge_set.v(e1) == n1 && edge_set.u(e1) == n2), "Wrong edge");
+ checkGraphNodeList(edge_set, 3);
+ checkGraphArcList(edge_set, 2);
+ checkGraphEdgeList(edge_set, 1);
+
+ checkGraphOutArcList(edge_set, n1, 1);
+ checkGraphOutArcList(edge_set, n2, 1);
+ checkGraphOutArcList(edge_set, n3, 0);
+
+ checkGraphInArcList(edge_set, n1, 1);
+ checkGraphInArcList(edge_set, n2, 1);
+ checkGraphInArcList(edge_set, n3, 0);
+
+ checkGraphIncEdgeList(edge_set, n1, 1);
+ checkGraphIncEdgeList(edge_set, n2, 1);
+ checkGraphIncEdgeList(edge_set, n3, 0);
+
+ checkGraphConEdgeList(edge_set, 1);
+ checkGraphConArcList(edge_set, 2);
+
+ EdgeSet::Edge e2 = edge_set.addEdge(n2, n1),
+ e3 = edge_set.addEdge(n2, n3),
+ e4 = edge_set.addEdge(n2, n3);
+ ::lemon::ignore_unused_variable_warning(e2,e3,e4);
+
+ checkGraphNodeList(edge_set, 3);
+ checkGraphEdgeList(edge_set, 4);
+
+ checkGraphOutArcList(edge_set, n1, 2);
+ checkGraphOutArcList(edge_set, n2, 4);
+ checkGraphOutArcList(edge_set, n3, 2);
+
+ checkGraphInArcList(edge_set, n1, 2);
+ checkGraphInArcList(edge_set, n2, 4);
+ checkGraphInArcList(edge_set, n3, 2);
+
+ checkGraphIncEdgeList(edge_set, n1, 2);
+ checkGraphIncEdgeList(edge_set, n2, 4);
+ checkGraphIncEdgeList(edge_set, n3, 2);
+
+ checkGraphConEdgeList(edge_set, 4);
+ checkGraphConArcList(edge_set, 8);
+
+ checkArcDirections(edge_set);
+
+ checkNodeIds(edge_set);
+ checkArcIds(edge_set);
+ checkEdgeIds(edge_set);
+ checkGraphNodeMap(edge_set);
+ checkGraphArcMap(edge_set);
+ checkGraphEdgeMap(edge_set);
+
+ check(edge_set.valid(), "Wrong validity");
+ digraph.erase(n1);
+ check(!edge_set.valid(), "Wrong validity");
+}
+
+void checkListEdgeSet() {
+ checkConcept<concepts::Digraph, ListEdgeSet<ListDigraph> >();
+
+ typedef ListDigraph Digraph;
+ typedef ListEdgeSet<Digraph> EdgeSet;
+
+ Digraph digraph;
+ Digraph::Node
+ n1 = digraph.addNode(),
+ n2 = digraph.addNode();
+
+ Digraph::Arc ga1 = digraph.addArc(n1, n2);
+ ::lemon::ignore_unused_variable_warning(ga1);
+
+ EdgeSet edge_set(digraph);
+
+ Digraph::Arc ga2 = digraph.addArc(n2, n1);
+ ::lemon::ignore_unused_variable_warning(ga2);
+
+ checkGraphNodeList(edge_set, 2);
+ checkGraphArcList(edge_set, 0);
+ checkGraphEdgeList(edge_set, 0);
+
+ Digraph::Node
+ n3 = digraph.addNode();
+ checkGraphNodeList(edge_set, 3);
+ checkGraphArcList(edge_set, 0);
+ checkGraphEdgeList(edge_set, 0);
+
+ EdgeSet::Edge e1 = edge_set.addEdge(n1, n2);
+ check((edge_set.u(e1) == n1 && edge_set.v(e1) == n2) ||
+ (edge_set.v(e1) == n1 && edge_set.u(e1) == n2), "Wrong edge");
+ checkGraphNodeList(edge_set, 3);
+ checkGraphArcList(edge_set, 2);
+ checkGraphEdgeList(edge_set, 1);
+
+ checkGraphOutArcList(edge_set, n1, 1);
+ checkGraphOutArcList(edge_set, n2, 1);
+ checkGraphOutArcList(edge_set, n3, 0);
+
+ checkGraphInArcList(edge_set, n1, 1);
+ checkGraphInArcList(edge_set, n2, 1);
+ checkGraphInArcList(edge_set, n3, 0);
+
+ checkGraphIncEdgeList(edge_set, n1, 1);
+ checkGraphIncEdgeList(edge_set, n2, 1);
+ checkGraphIncEdgeList(edge_set, n3, 0);
+
+ checkGraphConEdgeList(edge_set, 1);
+ checkGraphConArcList(edge_set, 2);
+
+ EdgeSet::Edge e2 = edge_set.addEdge(n2, n1),
+ e3 = edge_set.addEdge(n2, n3),
+ e4 = edge_set.addEdge(n2, n3);
+ ::lemon::ignore_unused_variable_warning(e2,e3,e4);
+
+ checkGraphNodeList(edge_set, 3);
+ checkGraphEdgeList(edge_set, 4);
+
+ checkGraphOutArcList(edge_set, n1, 2);
+ checkGraphOutArcList(edge_set, n2, 4);
+ checkGraphOutArcList(edge_set, n3, 2);
+
+ checkGraphInArcList(edge_set, n1, 2);
+ checkGraphInArcList(edge_set, n2, 4);
+ checkGraphInArcList(edge_set, n3, 2);
+
+ checkGraphIncEdgeList(edge_set, n1, 2);
+ checkGraphIncEdgeList(edge_set, n2, 4);
+ checkGraphIncEdgeList(edge_set, n3, 2);
+
+ checkGraphConEdgeList(edge_set, 4);
+ checkGraphConArcList(edge_set, 8);
+
+ checkArcDirections(edge_set);
+
+ checkNodeIds(edge_set);
+ checkArcIds(edge_set);
+ checkEdgeIds(edge_set);
+ checkGraphNodeMap(edge_set);
+ checkGraphArcMap(edge_set);
+ checkGraphEdgeMap(edge_set);
+
+ digraph.erase(n1);
+
+ checkGraphNodeList(edge_set, 2);
+ checkGraphArcList(edge_set, 4);
+ checkGraphEdgeList(edge_set, 2);
+
+ checkGraphOutArcList(edge_set, n2, 2);
+ checkGraphOutArcList(edge_set, n3, 2);
+
+ checkGraphInArcList(edge_set, n2, 2);
+ checkGraphInArcList(edge_set, n3, 2);
+
+ checkGraphIncEdgeList(edge_set, n2, 2);
+ checkGraphIncEdgeList(edge_set, n3, 2);
+
+ checkNodeIds(edge_set);
+ checkArcIds(edge_set);
+ checkEdgeIds(edge_set);
+ checkGraphNodeMap(edge_set);
+ checkGraphArcMap(edge_set);
+ checkGraphEdgeMap(edge_set);
+
+ checkGraphConEdgeList(edge_set, 2);
+ checkGraphConArcList(edge_set, 4);
+
+}
+
+
+int main() {
+
+ checkSmartArcSet();
+ checkListArcSet();
+ checkSmartEdgeSet();
+ checkListEdgeSet();
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/error_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/error_test.cc
new file mode 100644
index 00000000000..1527519812b
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/error_test.cc
@@ -0,0 +1,90 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <iostream>
+
+#include <lemon/error.h>
+#include "test_tools.h"
+
+using namespace lemon;
+
+#ifdef LEMON_ENABLE_ASSERTS
+#undef LEMON_ENABLE_ASSERTS
+#endif
+
+#ifdef LEMON_DISABLE_ASSERTS
+#undef LEMON_DISABLE_ASSERTS
+#endif
+
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+//checking disabled asserts
+#define LEMON_DISABLE_ASSERTS
+#include <lemon/assert.h>
+
+void no_assertion_text_disable() {
+ LEMON_ASSERT(true, "This is a fault message");
+}
+
+void assertion_text_disable() {
+ LEMON_ASSERT(false, "This is a fault message");
+}
+
+void check_assertion_disable() {
+ no_assertion_text_disable();
+ assertion_text_disable();
+}
+#undef LEMON_DISABLE_ASSERTS
+
+//checking custom assert handler
+#define LEMON_ASSERT_CUSTOM
+
+static int cnt = 0;
+void my_assert_handler(const char*, int, const char*,
+ const char*, const char*) {
+ ++cnt;
+}
+
+#define LEMON_CUSTOM_ASSERT_HANDLER my_assert_handler
+#include <lemon/assert.h>
+
+void no_assertion_text_custom() {
+ LEMON_ASSERT(true, "This is a fault message");
+}
+
+void assertion_text_custom() {
+ LEMON_ASSERT(false, "This is a fault message");
+}
+
+void check_assertion_custom() {
+ no_assertion_text_custom();
+ assertion_text_custom();
+ check(cnt == 1, "The custom assert handler does not work");
+}
+
+#undef LEMON_ASSERT_CUSTOM
+
+
+int main() {
+ check_assertion_disable();
+ check_assertion_custom();
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/euler_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/euler_test.cc
new file mode 100644
index 00000000000..11a39e47081
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/euler_test.cc
@@ -0,0 +1,225 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <lemon/euler.h>
+#include <lemon/list_graph.h>
+#include <lemon/adaptors.h>
+#include "test_tools.h"
+
+using namespace lemon;
+
+template <typename Digraph>
+void checkDiEulerIt(const Digraph& g,
+ const typename Digraph::Node& start = INVALID)
+{
+ typename Digraph::template ArcMap<int> visitationNumber(g, 0);
+
+ DiEulerIt<Digraph> e(g, start);
+ if (e == INVALID) return;
+ typename Digraph::Node firstNode = g.source(e);
+ typename Digraph::Node lastNode = g.target(e);
+ if (start != INVALID) {
+ check(firstNode == start, "checkDiEulerIt: Wrong first node");
+ }
+
+ for (; e != INVALID; ++e) {
+ if (e != INVALID) lastNode = g.target(e);
+ ++visitationNumber[e];
+ }
+
+ check(firstNode == lastNode,
+ "checkDiEulerIt: First and last nodes are not the same");
+
+ for (typename Digraph::ArcIt a(g); a != INVALID; ++a)
+ {
+ check(visitationNumber[a] == 1,
+ "checkDiEulerIt: Not visited or multiple times visited arc found");
+ }
+}
+
+template <typename Graph>
+void checkEulerIt(const Graph& g,
+ const typename Graph::Node& start = INVALID)
+{
+ typename Graph::template EdgeMap<int> visitationNumber(g, 0);
+
+ EulerIt<Graph> e(g, start);
+ if (e == INVALID) return;
+ typename Graph::Node firstNode = g.source(typename Graph::Arc(e));
+ typename Graph::Node lastNode = g.target(typename Graph::Arc(e));
+ if (start != INVALID) {
+ check(firstNode == start, "checkEulerIt: Wrong first node");
+ }
+
+ for (; e != INVALID; ++e) {
+ if (e != INVALID) lastNode = g.target(typename Graph::Arc(e));
+ ++visitationNumber[e];
+ }
+
+ check(firstNode == lastNode,
+ "checkEulerIt: First and last nodes are not the same");
+
+ for (typename Graph::EdgeIt e(g); e != INVALID; ++e)
+ {
+ check(visitationNumber[e] == 1,
+ "checkEulerIt: Not visited or multiple times visited edge found");
+ }
+}
+
+int main()
+{
+ typedef ListDigraph Digraph;
+ typedef Undirector<Digraph> Graph;
+
+ {
+ Digraph d;
+ Graph g(d);
+
+ checkDiEulerIt(d);
+ checkDiEulerIt(g);
+ checkEulerIt(g);
+
+ check(eulerian(d), "This graph is Eulerian");
+ check(eulerian(g), "This graph is Eulerian");
+ }
+ {
+ Digraph d;
+ Graph g(d);
+ Digraph::Node n = d.addNode();
+ ::lemon::ignore_unused_variable_warning(n);
+
+ checkDiEulerIt(d);
+ checkDiEulerIt(g);
+ checkEulerIt(g);
+
+ check(eulerian(d), "This graph is Eulerian");
+ check(eulerian(g), "This graph is Eulerian");
+ }
+ {
+ Digraph d;
+ Graph g(d);
+ Digraph::Node n = d.addNode();
+ d.addArc(n, n);
+
+ checkDiEulerIt(d);
+ checkDiEulerIt(g);
+ checkEulerIt(g);
+
+ check(eulerian(d), "This graph is Eulerian");
+ check(eulerian(g), "This graph is Eulerian");
+ }
+ {
+ Digraph d;
+ Graph g(d);
+ Digraph::Node n1 = d.addNode();
+ Digraph::Node n2 = d.addNode();
+ Digraph::Node n3 = d.addNode();
+
+ d.addArc(n1, n2);
+ d.addArc(n2, n1);
+ d.addArc(n2, n3);
+ d.addArc(n3, n2);
+
+ checkDiEulerIt(d);
+ checkDiEulerIt(d, n2);
+ checkDiEulerIt(g);
+ checkDiEulerIt(g, n2);
+ checkEulerIt(g);
+ checkEulerIt(g, n2);
+
+ check(eulerian(d), "This graph is Eulerian");
+ check(eulerian(g), "This graph is Eulerian");
+ }
+ {
+ Digraph d;
+ Graph g(d);
+ Digraph::Node n1 = d.addNode();
+ Digraph::Node n2 = d.addNode();
+ Digraph::Node n3 = d.addNode();
+ Digraph::Node n4 = d.addNode();
+ Digraph::Node n5 = d.addNode();
+ Digraph::Node n6 = d.addNode();
+
+ d.addArc(n1, n2);
+ d.addArc(n2, n4);
+ d.addArc(n1, n3);
+ d.addArc(n3, n4);
+ d.addArc(n4, n1);
+ d.addArc(n3, n5);
+ d.addArc(n5, n2);
+ d.addArc(n4, n6);
+ d.addArc(n2, n6);
+ d.addArc(n6, n1);
+ d.addArc(n6, n3);
+
+ checkDiEulerIt(d);
+ checkDiEulerIt(d, n1);
+ checkDiEulerIt(d, n5);
+
+ checkDiEulerIt(g);
+ checkDiEulerIt(g, n1);
+ checkDiEulerIt(g, n5);
+ checkEulerIt(g);
+ checkEulerIt(g, n1);
+ checkEulerIt(g, n5);
+
+ check(eulerian(d), "This graph is Eulerian");
+ check(eulerian(g), "This graph is Eulerian");
+ }
+ {
+ Digraph d;
+ Graph g(d);
+ Digraph::Node n0 = d.addNode();
+ Digraph::Node n1 = d.addNode();
+ Digraph::Node n2 = d.addNode();
+ Digraph::Node n3 = d.addNode();
+ Digraph::Node n4 = d.addNode();
+ Digraph::Node n5 = d.addNode();
+ ::lemon::ignore_unused_variable_warning(n0,n4,n5);
+
+ d.addArc(n1, n2);
+ d.addArc(n2, n3);
+ d.addArc(n3, n1);
+
+ checkDiEulerIt(d);
+ checkDiEulerIt(d, n2);
+
+ checkDiEulerIt(g);
+ checkDiEulerIt(g, n2);
+ checkEulerIt(g);
+ checkEulerIt(g, n2);
+
+ check(!eulerian(d), "This graph is not Eulerian");
+ check(!eulerian(g), "This graph is not Eulerian");
+ }
+ {
+ Digraph d;
+ Graph g(d);
+ Digraph::Node n1 = d.addNode();
+ Digraph::Node n2 = d.addNode();
+ Digraph::Node n3 = d.addNode();
+
+ d.addArc(n1, n2);
+ d.addArc(n2, n3);
+
+ check(!eulerian(d), "This graph is not Eulerian");
+ check(!eulerian(g), "This graph is not Eulerian");
+ }
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/fractional_matching_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/fractional_matching_test.cc
new file mode 100644
index 00000000000..bee866c0149
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/fractional_matching_test.cc
@@ -0,0 +1,527 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <iostream>
+#include <sstream>
+#include <vector>
+#include <queue>
+#include <cstdlib>
+
+#include <lemon/fractional_matching.h>
+#include <lemon/smart_graph.h>
+#include <lemon/concepts/graph.h>
+#include <lemon/concepts/maps.h>
+#include <lemon/lgf_reader.h>
+#include <lemon/math.h>
+
+#include "test_tools.h"
+
+using namespace std;
+using namespace lemon;
+
+GRAPH_TYPEDEFS(SmartGraph);
+
+
+const int lgfn = 4;
+const std::string lgf[lgfn] = {
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "5\n"
+ "6\n"
+ "7\n"
+ "@edges\n"
+ " label weight\n"
+ "7 4 0 984\n"
+ "0 7 1 73\n"
+ "7 1 2 204\n"
+ "2 3 3 583\n"
+ "2 7 4 565\n"
+ "2 1 5 582\n"
+ "0 4 6 551\n"
+ "2 5 7 385\n"
+ "1 5 8 561\n"
+ "5 3 9 484\n"
+ "7 5 10 904\n"
+ "3 6 11 47\n"
+ "7 6 12 888\n"
+ "3 0 13 747\n"
+ "6 1 14 310\n",
+
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "5\n"
+ "6\n"
+ "7\n"
+ "@edges\n"
+ " label weight\n"
+ "2 5 0 710\n"
+ "0 5 1 241\n"
+ "2 4 2 856\n"
+ "2 6 3 762\n"
+ "4 1 4 747\n"
+ "6 1 5 962\n"
+ "4 7 6 723\n"
+ "1 7 7 661\n"
+ "2 3 8 376\n"
+ "1 0 9 416\n"
+ "6 7 10 391\n",
+
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "5\n"
+ "6\n"
+ "7\n"
+ "@edges\n"
+ " label weight\n"
+ "6 2 0 553\n"
+ "0 7 1 653\n"
+ "6 3 2 22\n"
+ "4 7 3 846\n"
+ "7 2 4 981\n"
+ "7 6 5 250\n"
+ "5 2 6 539\n",
+
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "@edges\n"
+ " label weight\n"
+ "0 0 0 100\n"
+};
+
+void checkMaxFractionalMatchingCompile()
+{
+ typedef concepts::Graph Graph;
+ typedef Graph::Node Node;
+ typedef Graph::Edge Edge;
+
+ Graph g;
+ Node n;
+ Edge e;
+
+ MaxFractionalMatching<Graph> mat_test(g);
+ const MaxFractionalMatching<Graph>&
+ const_mat_test = mat_test;
+
+ mat_test.init();
+ mat_test.start();
+ mat_test.start(true);
+ mat_test.startPerfect();
+ mat_test.startPerfect(true);
+ mat_test.run();
+ mat_test.run(true);
+ mat_test.runPerfect();
+ mat_test.runPerfect(true);
+
+ const_mat_test.matchingSize();
+ const_mat_test.matching(e);
+ const_mat_test.matching(n);
+ const MaxFractionalMatching<Graph>::MatchingMap& mmap =
+ const_mat_test.matchingMap();
+ e = mmap[n];
+
+ const_mat_test.barrier(n);
+}
+
+void checkMaxWeightedFractionalMatchingCompile()
+{
+ typedef concepts::Graph Graph;
+ typedef Graph::Node Node;
+ typedef Graph::Edge Edge;
+ typedef Graph::EdgeMap<int> WeightMap;
+
+ Graph g;
+ Node n;
+ Edge e;
+ WeightMap w(g);
+
+ MaxWeightedFractionalMatching<Graph> mat_test(g, w);
+ const MaxWeightedFractionalMatching<Graph>&
+ const_mat_test = mat_test;
+
+ mat_test.init();
+ mat_test.start();
+ mat_test.run();
+
+ const_mat_test.matchingWeight();
+ const_mat_test.matchingSize();
+ const_mat_test.matching(e);
+ const_mat_test.matching(n);
+ const MaxWeightedFractionalMatching<Graph>::MatchingMap& mmap =
+ const_mat_test.matchingMap();
+ e = mmap[n];
+
+ const_mat_test.dualValue();
+ const_mat_test.nodeValue(n);
+}
+
+void checkMaxWeightedPerfectFractionalMatchingCompile()
+{
+ typedef concepts::Graph Graph;
+ typedef Graph::Node Node;
+ typedef Graph::Edge Edge;
+ typedef Graph::EdgeMap<int> WeightMap;
+
+ Graph g;
+ Node n;
+ Edge e;
+ WeightMap w(g);
+
+ MaxWeightedPerfectFractionalMatching<Graph> mat_test(g, w);
+ const MaxWeightedPerfectFractionalMatching<Graph>&
+ const_mat_test = mat_test;
+
+ mat_test.init();
+ mat_test.start();
+ mat_test.run();
+
+ const_mat_test.matchingWeight();
+ const_mat_test.matching(e);
+ const_mat_test.matching(n);
+ const MaxWeightedPerfectFractionalMatching<Graph>::MatchingMap& mmap =
+ const_mat_test.matchingMap();
+ e = mmap[n];
+
+ const_mat_test.dualValue();
+ const_mat_test.nodeValue(n);
+}
+
+void checkFractionalMatching(const SmartGraph& graph,
+ const MaxFractionalMatching<SmartGraph>& mfm,
+ bool allow_loops = true) {
+ int pv = 0;
+ for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
+ int indeg = 0;
+ for (InArcIt a(graph, n); a != INVALID; ++a) {
+ if (mfm.matching(graph.source(a)) == a) {
+ ++indeg;
+ }
+ }
+ if (mfm.matching(n) != INVALID) {
+ check(indeg == 1, "Invalid matching");
+ ++pv;
+ } else {
+ check(indeg == 0, "Invalid matching");
+ }
+ }
+ check(pv == mfm.matchingSize(), "Wrong matching size");
+
+ for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
+ check((e == mfm.matching(graph.u(e)) ? 1 : 0) +
+ (e == mfm.matching(graph.v(e)) ? 1 : 0) ==
+ mfm.matching(e), "Invalid matching");
+ }
+
+ SmartGraph::NodeMap<bool> processed(graph, false);
+ for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
+ if (processed[n]) continue;
+ processed[n] = true;
+ if (mfm.matching(n) == INVALID) continue;
+ int num = 1;
+ Node v = graph.target(mfm.matching(n));
+ while (v != n) {
+ processed[v] = true;
+ ++num;
+ v = graph.target(mfm.matching(v));
+ }
+ check(num == 2 || num % 2 == 1, "Wrong cycle size");
+ check(allow_loops || num != 1, "Wrong cycle size");
+ }
+
+ int anum = 0, bnum = 0;
+ SmartGraph::NodeMap<bool> neighbours(graph, false);
+ for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
+ if (!mfm.barrier(n)) continue;
+ ++anum;
+ for (SmartGraph::InArcIt a(graph, n); a != INVALID; ++a) {
+ Node u = graph.source(a);
+ if (!allow_loops && u == n) continue;
+ if (!neighbours[u]) {
+ neighbours[u] = true;
+ ++bnum;
+ }
+ }
+ }
+ check(anum - bnum + mfm.matchingSize() == countNodes(graph),
+ "Wrong barrier");
+}
+
+void checkPerfectFractionalMatching(const SmartGraph& graph,
+ const MaxFractionalMatching<SmartGraph>& mfm,
+ bool perfect, bool allow_loops = true) {
+ if (perfect) {
+ for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
+ int indeg = 0;
+ for (InArcIt a(graph, n); a != INVALID; ++a) {
+ if (mfm.matching(graph.source(a)) == a) {
+ ++indeg;
+ }
+ }
+ check(mfm.matching(n) != INVALID, "Invalid matching");
+ check(indeg == 1, "Invalid matching");
+ }
+ for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
+ check((e == mfm.matching(graph.u(e)) ? 1 : 0) +
+ (e == mfm.matching(graph.v(e)) ? 1 : 0) ==
+ mfm.matching(e), "Invalid matching");
+ }
+ } else {
+ int anum = 0, bnum = 0;
+ SmartGraph::NodeMap<bool> neighbours(graph, false);
+ for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
+ if (!mfm.barrier(n)) continue;
+ ++anum;
+ for (SmartGraph::InArcIt a(graph, n); a != INVALID; ++a) {
+ Node u = graph.source(a);
+ if (!allow_loops && u == n) continue;
+ if (!neighbours[u]) {
+ neighbours[u] = true;
+ ++bnum;
+ }
+ }
+ }
+ check(anum - bnum > 0, "Wrong barrier");
+ }
+}
+
+void checkWeightedFractionalMatching(const SmartGraph& graph,
+ const SmartGraph::EdgeMap<int>& weight,
+ const MaxWeightedFractionalMatching<SmartGraph>& mwfm,
+ bool allow_loops = true) {
+ for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
+ if (graph.u(e) == graph.v(e) && !allow_loops) continue;
+ int rw = mwfm.nodeValue(graph.u(e)) + mwfm.nodeValue(graph.v(e))
+ - weight[e] * mwfm.dualScale;
+
+ check(rw >= 0, "Negative reduced weight");
+ check(rw == 0 || !mwfm.matching(e),
+ "Non-zero reduced weight on matching edge");
+ }
+
+ int pv = 0;
+ for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
+ int indeg = 0;
+ for (InArcIt a(graph, n); a != INVALID; ++a) {
+ if (mwfm.matching(graph.source(a)) == a) {
+ ++indeg;
+ }
+ }
+ check(indeg <= 1, "Invalid matching");
+ if (mwfm.matching(n) != INVALID) {
+ check(mwfm.nodeValue(n) >= 0, "Invalid node value");
+ check(indeg == 1, "Invalid matching");
+ pv += weight[mwfm.matching(n)];
+ SmartGraph::Node o = graph.target(mwfm.matching(n));
+ ::lemon::ignore_unused_variable_warning(o);
+ } else {
+ check(mwfm.nodeValue(n) == 0, "Invalid matching");
+ check(indeg == 0, "Invalid matching");
+ }
+ }
+
+ for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
+ check((e == mwfm.matching(graph.u(e)) ? 1 : 0) +
+ (e == mwfm.matching(graph.v(e)) ? 1 : 0) ==
+ mwfm.matching(e), "Invalid matching");
+ }
+
+ int dv = 0;
+ for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
+ dv += mwfm.nodeValue(n);
+ }
+
+ check(pv * mwfm.dualScale == dv * 2, "Wrong duality");
+
+ SmartGraph::NodeMap<bool> processed(graph, false);
+ for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
+ if (processed[n]) continue;
+ processed[n] = true;
+ if (mwfm.matching(n) == INVALID) continue;
+ int num = 1;
+ Node v = graph.target(mwfm.matching(n));
+ while (v != n) {
+ processed[v] = true;
+ ++num;
+ v = graph.target(mwfm.matching(v));
+ }
+ check(num == 2 || num % 2 == 1, "Wrong cycle size");
+ check(allow_loops || num != 1, "Wrong cycle size");
+ }
+
+ return;
+}
+
+void checkWeightedPerfectFractionalMatching(const SmartGraph& graph,
+ const SmartGraph::EdgeMap<int>& weight,
+ const MaxWeightedPerfectFractionalMatching<SmartGraph>& mwpfm,
+ bool allow_loops = true) {
+ for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
+ if (graph.u(e) == graph.v(e) && !allow_loops) continue;
+ int rw = mwpfm.nodeValue(graph.u(e)) + mwpfm.nodeValue(graph.v(e))
+ - weight[e] * mwpfm.dualScale;
+
+ check(rw >= 0, "Negative reduced weight");
+ check(rw == 0 || !mwpfm.matching(e),
+ "Non-zero reduced weight on matching edge");
+ }
+
+ int pv = 0;
+ for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
+ int indeg = 0;
+ for (InArcIt a(graph, n); a != INVALID; ++a) {
+ if (mwpfm.matching(graph.source(a)) == a) {
+ ++indeg;
+ }
+ }
+ check(mwpfm.matching(n) != INVALID, "Invalid perfect matching");
+ check(indeg == 1, "Invalid perfect matching");
+ pv += weight[mwpfm.matching(n)];
+ SmartGraph::Node o = graph.target(mwpfm.matching(n));
+ ::lemon::ignore_unused_variable_warning(o);
+ }
+
+ for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
+ check((e == mwpfm.matching(graph.u(e)) ? 1 : 0) +
+ (e == mwpfm.matching(graph.v(e)) ? 1 : 0) ==
+ mwpfm.matching(e), "Invalid matching");
+ }
+
+ int dv = 0;
+ for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
+ dv += mwpfm.nodeValue(n);
+ }
+
+ check(pv * mwpfm.dualScale == dv * 2, "Wrong duality");
+
+ SmartGraph::NodeMap<bool> processed(graph, false);
+ for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
+ if (processed[n]) continue;
+ processed[n] = true;
+ if (mwpfm.matching(n) == INVALID) continue;
+ int num = 1;
+ Node v = graph.target(mwpfm.matching(n));
+ while (v != n) {
+ processed[v] = true;
+ ++num;
+ v = graph.target(mwpfm.matching(v));
+ }
+ check(num == 2 || num % 2 == 1, "Wrong cycle size");
+ check(allow_loops || num != 1, "Wrong cycle size");
+ }
+
+ return;
+}
+
+
+int main() {
+
+ for (int i = 0; i < lgfn; ++i) {
+ SmartGraph graph;
+ SmartGraph::EdgeMap<int> weight(graph);
+
+ istringstream lgfs(lgf[i]);
+ graphReader(graph, lgfs).
+ edgeMap("weight", weight).run();
+
+ bool perfect_with_loops;
+ {
+ MaxFractionalMatching<SmartGraph> mfm(graph, true);
+ mfm.run();
+ checkFractionalMatching(graph, mfm, true);
+ perfect_with_loops = mfm.matchingSize() == countNodes(graph);
+ }
+
+ bool perfect_without_loops;
+ {
+ MaxFractionalMatching<SmartGraph> mfm(graph, false);
+ mfm.run();
+ checkFractionalMatching(graph, mfm, false);
+ perfect_without_loops = mfm.matchingSize() == countNodes(graph);
+ }
+
+ {
+ MaxFractionalMatching<SmartGraph> mfm(graph, true);
+ bool result = mfm.runPerfect();
+ checkPerfectFractionalMatching(graph, mfm, result, true);
+ check(result == perfect_with_loops, "Wrong perfect matching");
+ }
+
+ {
+ MaxFractionalMatching<SmartGraph> mfm(graph, false);
+ bool result = mfm.runPerfect();
+ checkPerfectFractionalMatching(graph, mfm, result, false);
+ check(result == perfect_without_loops, "Wrong perfect matching");
+ }
+
+ {
+ MaxWeightedFractionalMatching<SmartGraph> mwfm(graph, weight, true);
+ mwfm.run();
+ checkWeightedFractionalMatching(graph, weight, mwfm, true);
+ }
+
+ {
+ MaxWeightedFractionalMatching<SmartGraph> mwfm(graph, weight, false);
+ mwfm.run();
+ checkWeightedFractionalMatching(graph, weight, mwfm, false);
+ }
+
+ {
+ MaxWeightedPerfectFractionalMatching<SmartGraph> mwpfm(graph, weight,
+ true);
+ bool perfect = mwpfm.run();
+ check(perfect == (mwpfm.matchingSize() == countNodes(graph)),
+ "Perfect matching found");
+ check(perfect == perfect_with_loops, "Wrong perfect matching");
+
+ if (perfect) {
+ checkWeightedPerfectFractionalMatching(graph, weight, mwpfm, true);
+ }
+ }
+
+ {
+ MaxWeightedPerfectFractionalMatching<SmartGraph> mwpfm(graph, weight,
+ false);
+ bool perfect = mwpfm.run();
+ check(perfect == (mwpfm.matchingSize() == countNodes(graph)),
+ "Perfect matching found");
+ check(perfect == perfect_without_loops, "Wrong perfect matching");
+
+ if (perfect) {
+ checkWeightedPerfectFractionalMatching(graph, weight, mwpfm, false);
+ }
+ }
+
+ }
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/gomory_hu_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/gomory_hu_test.cc
new file mode 100644
index 00000000000..178f21fec6f
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/gomory_hu_test.cc
@@ -0,0 +1,142 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <iostream>
+
+#include "test_tools.h"
+#include <lemon/smart_graph.h>
+#include <lemon/concepts/graph.h>
+#include <lemon/concepts/maps.h>
+#include <lemon/lgf_reader.h>
+#include <lemon/gomory_hu.h>
+#include <cstdlib>
+
+using namespace std;
+using namespace lemon;
+
+typedef SmartGraph Graph;
+
+char test_lgf[] =
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "@arcs\n"
+ " label capacity\n"
+ "0 1 0 1\n"
+ "1 2 1 1\n"
+ "2 3 2 1\n"
+ "0 3 4 5\n"
+ "0 3 5 10\n"
+ "0 3 6 7\n"
+ "4 2 7 1\n"
+ "@attributes\n"
+ "source 0\n"
+ "target 3\n";
+
+void checkGomoryHuCompile()
+{
+ typedef int Value;
+ typedef concepts::Graph Graph;
+
+ typedef Graph::Node Node;
+ typedef Graph::Edge Edge;
+ typedef concepts::ReadMap<Edge, Value> CapMap;
+ typedef concepts::ReadWriteMap<Node, bool> CutMap;
+
+ Graph g;
+ Node n;
+ CapMap cap;
+ CutMap cut;
+ Value v;
+ int d;
+ ::lemon::ignore_unused_variable_warning(v,d);
+
+ GomoryHu<Graph, CapMap> gh_test(g, cap);
+ const GomoryHu<Graph, CapMap>&
+ const_gh_test = gh_test;
+
+ gh_test.run();
+
+ n = const_gh_test.predNode(n);
+ v = const_gh_test.predValue(n);
+ d = const_gh_test.rootDist(n);
+ v = const_gh_test.minCutValue(n, n);
+ v = const_gh_test.minCutMap(n, n, cut);
+}
+
+GRAPH_TYPEDEFS(Graph);
+typedef Graph::EdgeMap<int> IntEdgeMap;
+typedef Graph::NodeMap<bool> BoolNodeMap;
+
+int cutValue(const Graph& graph, const BoolNodeMap& cut,
+ const IntEdgeMap& capacity) {
+
+ int sum = 0;
+ for (EdgeIt e(graph); e != INVALID; ++e) {
+ Node s = graph.u(e);
+ Node t = graph.v(e);
+
+ if (cut[s] != cut[t]) {
+ sum += capacity[e];
+ }
+ }
+ return sum;
+}
+
+
+int main() {
+ Graph graph;
+ IntEdgeMap capacity(graph);
+
+ std::istringstream input(test_lgf);
+ GraphReader<Graph>(graph, input).
+ edgeMap("capacity", capacity).run();
+
+ GomoryHu<Graph> ght(graph, capacity);
+ ght.run();
+
+ for (NodeIt u(graph); u != INVALID; ++u) {
+ for (NodeIt v(graph); v != u; ++v) {
+ Preflow<Graph, IntEdgeMap> pf(graph, capacity, u, v);
+ pf.runMinCut();
+ BoolNodeMap cm(graph);
+ ght.minCutMap(u, v, cm);
+ check(pf.flowValue() == ght.minCutValue(u, v), "Wrong cut 1");
+ check(cm[u] != cm[v], "Wrong cut 2");
+ check(pf.flowValue() == cutValue(graph, cm, capacity), "Wrong cut 3");
+
+ int sum=0;
+ for(GomoryHu<Graph>::MinCutEdgeIt a(ght, u, v);a!=INVALID;++a)
+ sum+=capacity[a];
+ check(sum == ght.minCutValue(u, v), "Problem with MinCutEdgeIt");
+
+ sum=0;
+ for(GomoryHu<Graph>::MinCutNodeIt n(ght, u, v,true);n!=INVALID;++n)
+ sum++;
+ for(GomoryHu<Graph>::MinCutNodeIt n(ght, u, v,false);n!=INVALID;++n)
+ sum++;
+ check(sum == countNodes(graph), "Problem with MinCutNodeIt");
+ }
+ }
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/graph_copy_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/graph_copy_test.cc
new file mode 100644
index 00000000000..9a7d8155e0f
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/graph_copy_test.cc
@@ -0,0 +1,388 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <lemon/smart_graph.h>
+#include <lemon/list_graph.h>
+#include <lemon/static_graph.h>
+#include <lemon/lgf_reader.h>
+#include <lemon/error.h>
+
+#include "test_tools.h"
+
+using namespace std;
+using namespace lemon;
+
+template <typename GR>
+void digraph_copy_test() {
+ const int nn = 10;
+
+ // Build a digraph
+ SmartDigraph from;
+ SmartDigraph::NodeMap<int> fnm(from);
+ SmartDigraph::ArcMap<int> fam(from);
+ SmartDigraph::Node fn = INVALID;
+ SmartDigraph::Arc fa = INVALID;
+
+ std::vector<SmartDigraph::Node> fnv;
+ for (int i = 0; i < nn; ++i) {
+ SmartDigraph::Node node = from.addNode();
+ fnv.push_back(node);
+ fnm[node] = i * i;
+ if (i == 0) fn = node;
+ }
+
+ for (int i = 0; i < nn; ++i) {
+ for (int j = 0; j < nn; ++j) {
+ SmartDigraph::Arc arc = from.addArc(fnv[i], fnv[j]);
+ fam[arc] = i + j * j;
+ if (i == 0 && j == 0) fa = arc;
+ }
+ }
+
+ // Test digraph copy
+ GR to;
+ typename GR::template NodeMap<int> tnm(to);
+ typename GR::template ArcMap<int> tam(to);
+ typename GR::Node tn;
+ typename GR::Arc ta;
+
+ SmartDigraph::NodeMap<typename GR::Node> nr(from);
+ SmartDigraph::ArcMap<typename GR::Arc> er(from);
+
+ typename GR::template NodeMap<SmartDigraph::Node> ncr(to);
+ typename GR::template ArcMap<SmartDigraph::Arc> ecr(to);
+
+ digraphCopy(from, to).
+ nodeMap(fnm, tnm).arcMap(fam, tam).
+ nodeRef(nr).arcRef(er).
+ nodeCrossRef(ncr).arcCrossRef(ecr).
+ node(fn, tn).arc(fa, ta).run();
+
+ check(countNodes(from) == countNodes(to), "Wrong copy.");
+ check(countArcs(from) == countArcs(to), "Wrong copy.");
+
+ for (SmartDigraph::NodeIt it(from); it != INVALID; ++it) {
+ check(ncr[nr[it]] == it, "Wrong copy.");
+ check(fnm[it] == tnm[nr[it]], "Wrong copy.");
+ }
+
+ for (SmartDigraph::ArcIt it(from); it != INVALID; ++it) {
+ check(ecr[er[it]] == it, "Wrong copy.");
+ check(fam[it] == tam[er[it]], "Wrong copy.");
+ check(nr[from.source(it)] == to.source(er[it]), "Wrong copy.");
+ check(nr[from.target(it)] == to.target(er[it]), "Wrong copy.");
+ }
+
+ for (typename GR::NodeIt it(to); it != INVALID; ++it) {
+ check(nr[ncr[it]] == it, "Wrong copy.");
+ }
+
+ for (typename GR::ArcIt it(to); it != INVALID; ++it) {
+ check(er[ecr[it]] == it, "Wrong copy.");
+ }
+ check(tn == nr[fn], "Wrong copy.");
+ check(ta == er[fa], "Wrong copy.");
+
+ // Test repeated copy
+ digraphCopy(from, to).run();
+
+ check(countNodes(from) == countNodes(to), "Wrong copy.");
+ check(countArcs(from) == countArcs(to), "Wrong copy.");
+}
+
+template <typename GR>
+void graph_copy_test() {
+ const int nn = 10;
+
+ // Build a graph
+ SmartGraph from;
+ SmartGraph::NodeMap<int> fnm(from);
+ SmartGraph::ArcMap<int> fam(from);
+ SmartGraph::EdgeMap<int> fem(from);
+ SmartGraph::Node fn = INVALID;
+ SmartGraph::Arc fa = INVALID;
+ SmartGraph::Edge fe = INVALID;
+
+ std::vector<SmartGraph::Node> fnv;
+ for (int i = 0; i < nn; ++i) {
+ SmartGraph::Node node = from.addNode();
+ fnv.push_back(node);
+ fnm[node] = i * i;
+ if (i == 0) fn = node;
+ }
+
+ for (int i = 0; i < nn; ++i) {
+ for (int j = 0; j < nn; ++j) {
+ SmartGraph::Edge edge = from.addEdge(fnv[i], fnv[j]);
+ fem[edge] = i * i + j * j;
+ fam[from.direct(edge, true)] = i + j * j;
+ fam[from.direct(edge, false)] = i * i + j;
+ if (i == 0 && j == 0) fa = from.direct(edge, true);
+ if (i == 0 && j == 0) fe = edge;
+ }
+ }
+
+ // Test graph copy
+ GR to;
+ typename GR::template NodeMap<int> tnm(to);
+ typename GR::template ArcMap<int> tam(to);
+ typename GR::template EdgeMap<int> tem(to);
+ typename GR::Node tn;
+ typename GR::Arc ta;
+ typename GR::Edge te;
+
+ SmartGraph::NodeMap<typename GR::Node> nr(from);
+ SmartGraph::ArcMap<typename GR::Arc> ar(from);
+ SmartGraph::EdgeMap<typename GR::Edge> er(from);
+
+ typename GR::template NodeMap<SmartGraph::Node> ncr(to);
+ typename GR::template ArcMap<SmartGraph::Arc> acr(to);
+ typename GR::template EdgeMap<SmartGraph::Edge> ecr(to);
+
+ graphCopy(from, to).
+ nodeMap(fnm, tnm).arcMap(fam, tam).edgeMap(fem, tem).
+ nodeRef(nr).arcRef(ar).edgeRef(er).
+ nodeCrossRef(ncr).arcCrossRef(acr).edgeCrossRef(ecr).
+ node(fn, tn).arc(fa, ta).edge(fe, te).run();
+
+ check(countNodes(from) == countNodes(to), "Wrong copy.");
+ check(countEdges(from) == countEdges(to), "Wrong copy.");
+ check(countArcs(from) == countArcs(to), "Wrong copy.");
+
+ for (SmartGraph::NodeIt it(from); it != INVALID; ++it) {
+ check(ncr[nr[it]] == it, "Wrong copy.");
+ check(fnm[it] == tnm[nr[it]], "Wrong copy.");
+ }
+
+ for (SmartGraph::ArcIt it(from); it != INVALID; ++it) {
+ check(acr[ar[it]] == it, "Wrong copy.");
+ check(fam[it] == tam[ar[it]], "Wrong copy.");
+ check(nr[from.source(it)] == to.source(ar[it]), "Wrong copy.");
+ check(nr[from.target(it)] == to.target(ar[it]), "Wrong copy.");
+ }
+
+ for (SmartGraph::EdgeIt it(from); it != INVALID; ++it) {
+ check(ecr[er[it]] == it, "Wrong copy.");
+ check(fem[it] == tem[er[it]], "Wrong copy.");
+ check(nr[from.u(it)] == to.u(er[it]) || nr[from.u(it)] == to.v(er[it]),
+ "Wrong copy.");
+ check(nr[from.v(it)] == to.u(er[it]) || nr[from.v(it)] == to.v(er[it]),
+ "Wrong copy.");
+ check((from.u(it) != from.v(it)) == (to.u(er[it]) != to.v(er[it])),
+ "Wrong copy.");
+ }
+
+ for (typename GR::NodeIt it(to); it != INVALID; ++it) {
+ check(nr[ncr[it]] == it, "Wrong copy.");
+ }
+
+ for (typename GR::ArcIt it(to); it != INVALID; ++it) {
+ check(ar[acr[it]] == it, "Wrong copy.");
+ }
+ for (typename GR::EdgeIt it(to); it != INVALID; ++it) {
+ check(er[ecr[it]] == it, "Wrong copy.");
+ }
+ check(tn == nr[fn], "Wrong copy.");
+ check(ta == ar[fa], "Wrong copy.");
+ check(te == er[fe], "Wrong copy.");
+
+ // Test repeated copy
+ graphCopy(from, to).run();
+
+ check(countNodes(from) == countNodes(to), "Wrong copy.");
+ check(countEdges(from) == countEdges(to), "Wrong copy.");
+ check(countArcs(from) == countArcs(to), "Wrong copy.");
+}
+
+template <typename GR>
+void bpgraph_copy_test() {
+ const int nn = 10;
+
+ // Build a graph
+ SmartBpGraph from;
+ SmartBpGraph::NodeMap<int> fnm(from);
+ SmartBpGraph::RedNodeMap<int> frnm(from);
+ SmartBpGraph::BlueNodeMap<int> fbnm(from);
+ SmartBpGraph::ArcMap<int> fam(from);
+ SmartBpGraph::EdgeMap<int> fem(from);
+ SmartBpGraph::Node fn = INVALID;
+ SmartBpGraph::RedNode frn = INVALID;
+ SmartBpGraph::BlueNode fbn = INVALID;
+ SmartBpGraph::Arc fa = INVALID;
+ SmartBpGraph::Edge fe = INVALID;
+
+ std::vector<SmartBpGraph::RedNode> frnv;
+ for (int i = 0; i < nn; ++i) {
+ SmartBpGraph::RedNode node = from.addRedNode();
+ frnv.push_back(node);
+ fnm[node] = i * i;
+ frnm[node] = i + i;
+ if (i == 0) {
+ fn = node;
+ frn = node;
+ }
+ }
+
+ std::vector<SmartBpGraph::BlueNode> fbnv;
+ for (int i = 0; i < nn; ++i) {
+ SmartBpGraph::BlueNode node = from.addBlueNode();
+ fbnv.push_back(node);
+ fnm[node] = i * i;
+ fbnm[node] = i + i;
+ if (i == 0) fbn = node;
+ }
+
+ for (int i = 0; i < nn; ++i) {
+ for (int j = 0; j < nn; ++j) {
+ SmartBpGraph::Edge edge = from.addEdge(frnv[i], fbnv[j]);
+ fem[edge] = i * i + j * j;
+ fam[from.direct(edge, true)] = i + j * j;
+ fam[from.direct(edge, false)] = i * i + j;
+ if (i == 0 && j == 0) fa = from.direct(edge, true);
+ if (i == 0 && j == 0) fe = edge;
+ }
+ }
+
+ // Test graph copy
+ GR to;
+ typename GR::template NodeMap<int> tnm(to);
+ typename GR::template RedNodeMap<int> trnm(to);
+ typename GR::template BlueNodeMap<int> tbnm(to);
+ typename GR::template ArcMap<int> tam(to);
+ typename GR::template EdgeMap<int> tem(to);
+ typename GR::Node tn;
+ typename GR::RedNode trn;
+ typename GR::BlueNode tbn;
+ typename GR::Arc ta;
+ typename GR::Edge te;
+
+ SmartBpGraph::NodeMap<typename GR::Node> nr(from);
+ SmartBpGraph::RedNodeMap<typename GR::RedNode> rnr(from);
+ SmartBpGraph::BlueNodeMap<typename GR::BlueNode> bnr(from);
+ SmartBpGraph::ArcMap<typename GR::Arc> ar(from);
+ SmartBpGraph::EdgeMap<typename GR::Edge> er(from);
+
+ typename GR::template NodeMap<SmartBpGraph::Node> ncr(to);
+ typename GR::template RedNodeMap<SmartBpGraph::RedNode> rncr(to);
+ typename GR::template BlueNodeMap<SmartBpGraph::BlueNode> bncr(to);
+ typename GR::template ArcMap<SmartBpGraph::Arc> acr(to);
+ typename GR::template EdgeMap<SmartBpGraph::Edge> ecr(to);
+
+ bpGraphCopy(from, to).
+ nodeMap(fnm, tnm).
+ redNodeMap(frnm, trnm).blueNodeMap(fbnm, tbnm).
+ arcMap(fam, tam).edgeMap(fem, tem).
+ nodeRef(nr).redRef(rnr).blueRef(bnr).
+ arcRef(ar).edgeRef(er).
+ nodeCrossRef(ncr).redCrossRef(rncr).blueCrossRef(bncr).
+ arcCrossRef(acr).edgeCrossRef(ecr).
+ node(fn, tn).redNode(frn, trn).blueNode(fbn, tbn).
+ arc(fa, ta).edge(fe, te).run();
+
+ check(countNodes(from) == countNodes(to), "Wrong copy.");
+ check(countRedNodes(from) == countRedNodes(to), "Wrong copy.");
+ check(countBlueNodes(from) == countBlueNodes(to), "Wrong copy.");
+ check(countEdges(from) == countEdges(to), "Wrong copy.");
+ check(countArcs(from) == countArcs(to), "Wrong copy.");
+
+ for (SmartBpGraph::NodeIt it(from); it != INVALID; ++it) {
+ check(ncr[nr[it]] == it, "Wrong copy.");
+ check(fnm[it] == tnm[nr[it]], "Wrong copy.");
+ }
+
+ for (SmartBpGraph::RedNodeIt it(from); it != INVALID; ++it) {
+ check(ncr[nr[it]] == it, "Wrong copy.");
+ check(fnm[it] == tnm[nr[it]], "Wrong copy.");
+ check(rnr[it] == nr[it], "Wrong copy.");
+ check(rncr[rnr[it]] == it, "Wrong copy.");
+ check(frnm[it] == trnm[rnr[it]], "Wrong copy.");
+ check(to.red(rnr[it]), "Wrong copy.");
+ }
+
+ for (SmartBpGraph::BlueNodeIt it(from); it != INVALID; ++it) {
+ check(ncr[nr[it]] == it, "Wrong copy.");
+ check(fnm[it] == tnm[nr[it]], "Wrong copy.");
+ check(bnr[it] == nr[it], "Wrong copy.");
+ check(bncr[bnr[it]] == it, "Wrong copy.");
+ check(fbnm[it] == tbnm[bnr[it]], "Wrong copy.");
+ check(to.blue(bnr[it]), "Wrong copy.");
+ }
+
+ for (SmartBpGraph::ArcIt it(from); it != INVALID; ++it) {
+ check(acr[ar[it]] == it, "Wrong copy.");
+ check(fam[it] == tam[ar[it]], "Wrong copy.");
+ check(nr[from.source(it)] == to.source(ar[it]), "Wrong copy.");
+ check(nr[from.target(it)] == to.target(ar[it]), "Wrong copy.");
+ }
+
+ for (SmartBpGraph::EdgeIt it(from); it != INVALID; ++it) {
+ check(ecr[er[it]] == it, "Wrong copy.");
+ check(fem[it] == tem[er[it]], "Wrong copy.");
+ check(nr[from.u(it)] == to.u(er[it]) || nr[from.u(it)] == to.v(er[it]),
+ "Wrong copy.");
+ check(nr[from.v(it)] == to.u(er[it]) || nr[from.v(it)] == to.v(er[it]),
+ "Wrong copy.");
+ check((from.u(it) != from.v(it)) == (to.u(er[it]) != to.v(er[it])),
+ "Wrong copy.");
+ }
+
+ for (typename GR::NodeIt it(to); it != INVALID; ++it) {
+ check(nr[ncr[it]] == it, "Wrong copy.");
+ }
+ for (typename GR::RedNodeIt it(to); it != INVALID; ++it) {
+ check(rncr[it] == ncr[it], "Wrong copy.");
+ check(rnr[rncr[it]] == it, "Wrong copy.");
+ }
+ for (typename GR::BlueNodeIt it(to); it != INVALID; ++it) {
+ check(bncr[it] == ncr[it], "Wrong copy.");
+ check(bnr[bncr[it]] == it, "Wrong copy.");
+ }
+ for (typename GR::ArcIt it(to); it != INVALID; ++it) {
+ check(ar[acr[it]] == it, "Wrong copy.");
+ }
+ for (typename GR::EdgeIt it(to); it != INVALID; ++it) {
+ check(er[ecr[it]] == it, "Wrong copy.");
+ }
+ check(tn == nr[fn], "Wrong copy.");
+ check(trn == rnr[frn], "Wrong copy.");
+ check(tbn == bnr[fbn], "Wrong copy.");
+ check(ta == ar[fa], "Wrong copy.");
+ check(te == er[fe], "Wrong copy.");
+
+ // Test repeated copy
+ bpGraphCopy(from, to).run();
+
+ check(countNodes(from) == countNodes(to), "Wrong copy.");
+ check(countRedNodes(from) == countRedNodes(to), "Wrong copy.");
+ check(countBlueNodes(from) == countBlueNodes(to), "Wrong copy.");
+ check(countEdges(from) == countEdges(to), "Wrong copy.");
+ check(countArcs(from) == countArcs(to), "Wrong copy.");
+}
+
+
+int main() {
+ digraph_copy_test<SmartDigraph>();
+ digraph_copy_test<ListDigraph>();
+ digraph_copy_test<StaticDigraph>();
+ graph_copy_test<SmartGraph>();
+ graph_copy_test<ListGraph>();
+ bpgraph_copy_test<SmartBpGraph>();
+ bpgraph_copy_test<ListBpGraph>();
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/graph_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/graph_test.cc
new file mode 100644
index 00000000000..283b02ef58a
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/graph_test.cc
@@ -0,0 +1,603 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <lemon/concepts/graph.h>
+#include <lemon/list_graph.h>
+#include <lemon/smart_graph.h>
+#include <lemon/full_graph.h>
+#include <lemon/grid_graph.h>
+#include <lemon/hypercube_graph.h>
+
+#include "test_tools.h"
+#include "graph_test.h"
+
+using namespace lemon;
+using namespace lemon::concepts;
+
+template <class Graph>
+void checkGraphBuild() {
+ TEMPLATE_GRAPH_TYPEDEFS(Graph);
+
+ Graph G;
+ checkGraphNodeList(G, 0);
+ checkGraphEdgeList(G, 0);
+ checkGraphArcList(G, 0);
+
+ G.reserveNode(3);
+ G.reserveEdge(3);
+
+ Node
+ n1 = G.addNode(),
+ n2 = G.addNode(),
+ n3 = G.addNode();
+ checkGraphNodeList(G, 3);
+ checkGraphEdgeList(G, 0);
+ checkGraphArcList(G, 0);
+
+ Edge e1 = G.addEdge(n1, n2);
+ check((G.u(e1) == n1 && G.v(e1) == n2) || (G.u(e1) == n2 && G.v(e1) == n1),
+ "Wrong edge");
+
+ checkGraphNodeList(G, 3);
+ checkGraphEdgeList(G, 1);
+ checkGraphArcList(G, 2);
+
+ checkGraphIncEdgeArcLists(G, n1, 1);
+ checkGraphIncEdgeArcLists(G, n2, 1);
+ checkGraphIncEdgeArcLists(G, n3, 0);
+
+ checkGraphConEdgeList(G, 1);
+ checkGraphConArcList(G, 2);
+
+ Edge e2 = G.addEdge(n2, n1),
+ e3 = G.addEdge(n2, n3);
+ ::lemon::ignore_unused_variable_warning(e2,e3);
+
+ checkGraphNodeList(G, 3);
+ checkGraphEdgeList(G, 3);
+ checkGraphArcList(G, 6);
+
+ checkGraphIncEdgeArcLists(G, n1, 2);
+ checkGraphIncEdgeArcLists(G, n2, 3);
+ checkGraphIncEdgeArcLists(G, n3, 1);
+
+ checkGraphConEdgeList(G, 3);
+ checkGraphConArcList(G, 6);
+
+ checkArcDirections(G);
+
+ checkNodeIds(G);
+ checkArcIds(G);
+ checkEdgeIds(G);
+ checkGraphNodeMap(G);
+ checkGraphArcMap(G);
+ checkGraphEdgeMap(G);
+}
+
+template <class Graph>
+void checkGraphAlter() {
+ TEMPLATE_GRAPH_TYPEDEFS(Graph);
+
+ Graph G;
+ Node n1 = G.addNode(), n2 = G.addNode(),
+ n3 = G.addNode(), n4 = G.addNode();
+ Edge e1 = G.addEdge(n1, n2), e2 = G.addEdge(n2, n1),
+ e3 = G.addEdge(n2, n3), e4 = G.addEdge(n1, n4),
+ e5 = G.addEdge(n4, n3);
+ ::lemon::ignore_unused_variable_warning(e1,e3,e4,e5);
+
+ checkGraphNodeList(G, 4);
+ checkGraphEdgeList(G, 5);
+ checkGraphArcList(G, 10);
+
+ // Check changeU() and changeV()
+ if (G.u(e2) == n2) {
+ G.changeU(e2, n3);
+ } else {
+ G.changeV(e2, n3);
+ }
+
+ checkGraphNodeList(G, 4);
+ checkGraphEdgeList(G, 5);
+ checkGraphArcList(G, 10);
+
+ checkGraphIncEdgeArcLists(G, n1, 3);
+ checkGraphIncEdgeArcLists(G, n2, 2);
+ checkGraphIncEdgeArcLists(G, n3, 3);
+ checkGraphIncEdgeArcLists(G, n4, 2);
+
+ checkGraphConEdgeList(G, 5);
+ checkGraphConArcList(G, 10);
+
+ if (G.u(e2) == n1) {
+ G.changeU(e2, n2);
+ } else {
+ G.changeV(e2, n2);
+ }
+
+ checkGraphNodeList(G, 4);
+ checkGraphEdgeList(G, 5);
+ checkGraphArcList(G, 10);
+
+ checkGraphIncEdgeArcLists(G, n1, 2);
+ checkGraphIncEdgeArcLists(G, n2, 3);
+ checkGraphIncEdgeArcLists(G, n3, 3);
+ checkGraphIncEdgeArcLists(G, n4, 2);
+
+ checkGraphConEdgeList(G, 5);
+ checkGraphConArcList(G, 10);
+
+ // Check contract()
+ G.contract(n1, n4, false);
+
+ checkGraphNodeList(G, 3);
+ checkGraphEdgeList(G, 5);
+ checkGraphArcList(G, 10);
+
+ checkGraphIncEdgeArcLists(G, n1, 4);
+ checkGraphIncEdgeArcLists(G, n2, 3);
+ checkGraphIncEdgeArcLists(G, n3, 3);
+
+ checkGraphConEdgeList(G, 5);
+ checkGraphConArcList(G, 10);
+
+ G.contract(n2, n3);
+
+ checkGraphNodeList(G, 2);
+ checkGraphEdgeList(G, 3);
+ checkGraphArcList(G, 6);
+
+ checkGraphIncEdgeArcLists(G, n1, 4);
+ checkGraphIncEdgeArcLists(G, n2, 2);
+
+ checkGraphConEdgeList(G, 3);
+ checkGraphConArcList(G, 6);
+}
+
+template <class Graph>
+void checkGraphErase() {
+ TEMPLATE_GRAPH_TYPEDEFS(Graph);
+
+ Graph G;
+ Node n1 = G.addNode(), n2 = G.addNode(),
+ n3 = G.addNode(), n4 = G.addNode();
+ Edge e1 = G.addEdge(n1, n2), e2 = G.addEdge(n2, n1),
+ e3 = G.addEdge(n2, n3), e4 = G.addEdge(n1, n4),
+ e5 = G.addEdge(n4, n3);
+ ::lemon::ignore_unused_variable_warning(e1,e3,e4,e5);
+
+ // Check edge deletion
+ G.erase(e2);
+
+ checkGraphNodeList(G, 4);
+ checkGraphEdgeList(G, 4);
+ checkGraphArcList(G, 8);
+
+ checkGraphIncEdgeArcLists(G, n1, 2);
+ checkGraphIncEdgeArcLists(G, n2, 2);
+ checkGraphIncEdgeArcLists(G, n3, 2);
+ checkGraphIncEdgeArcLists(G, n4, 2);
+
+ checkGraphConEdgeList(G, 4);
+ checkGraphConArcList(G, 8);
+
+ // Check node deletion
+ G.erase(n3);
+
+ checkGraphNodeList(G, 3);
+ checkGraphEdgeList(G, 2);
+ checkGraphArcList(G, 4);
+
+ checkGraphIncEdgeArcLists(G, n1, 2);
+ checkGraphIncEdgeArcLists(G, n2, 1);
+ checkGraphIncEdgeArcLists(G, n4, 1);
+
+ checkGraphConEdgeList(G, 2);
+ checkGraphConArcList(G, 4);
+}
+
+
+template <class Graph>
+void checkGraphSnapshot() {
+ TEMPLATE_GRAPH_TYPEDEFS(Graph);
+
+ Graph G;
+ Node n1 = G.addNode(), n2 = G.addNode(), n3 = G.addNode();
+ Edge e1 = G.addEdge(n1, n2), e2 = G.addEdge(n2, n1),
+ e3 = G.addEdge(n2, n3);
+ ::lemon::ignore_unused_variable_warning(e1,e2,e3);
+
+ checkGraphNodeList(G, 3);
+ checkGraphEdgeList(G, 3);
+ checkGraphArcList(G, 6);
+
+ typename Graph::Snapshot snapshot(G);
+
+ Node n = G.addNode();
+ G.addEdge(n3, n);
+ G.addEdge(n, n3);
+ G.addEdge(n3, n2);
+
+ checkGraphNodeList(G, 4);
+ checkGraphEdgeList(G, 6);
+ checkGraphArcList(G, 12);
+
+ snapshot.restore();
+
+ checkGraphNodeList(G, 3);
+ checkGraphEdgeList(G, 3);
+ checkGraphArcList(G, 6);
+
+ checkGraphIncEdgeArcLists(G, n1, 2);
+ checkGraphIncEdgeArcLists(G, n2, 3);
+ checkGraphIncEdgeArcLists(G, n3, 1);
+
+ checkGraphConEdgeList(G, 3);
+ checkGraphConArcList(G, 6);
+
+ checkNodeIds(G);
+ checkEdgeIds(G);
+ checkArcIds(G);
+ checkGraphNodeMap(G);
+ checkGraphEdgeMap(G);
+ checkGraphArcMap(G);
+
+ G.addNode();
+ snapshot.save(G);
+
+ G.addEdge(G.addNode(), G.addNode());
+
+ snapshot.restore();
+ snapshot.save(G);
+
+ checkGraphNodeList(G, 4);
+ checkGraphEdgeList(G, 3);
+ checkGraphArcList(G, 6);
+
+ G.addEdge(G.addNode(), G.addNode());
+
+ snapshot.restore();
+
+ checkGraphNodeList(G, 4);
+ checkGraphEdgeList(G, 3);
+ checkGraphArcList(G, 6);
+}
+
+void checkFullGraph(int num) {
+ typedef FullGraph Graph;
+ GRAPH_TYPEDEFS(Graph);
+
+ Graph G(num);
+ check(G.nodeNum() == num && G.edgeNum() == num * (num - 1) / 2,
+ "Wrong size");
+
+ G.resize(num);
+ check(G.nodeNum() == num && G.edgeNum() == num * (num - 1) / 2,
+ "Wrong size");
+
+ checkGraphNodeList(G, num);
+ checkGraphEdgeList(G, num * (num - 1) / 2);
+
+ for (NodeIt n(G); n != INVALID; ++n) {
+ checkGraphOutArcList(G, n, num - 1);
+ checkGraphInArcList(G, n, num - 1);
+ checkGraphIncEdgeList(G, n, num - 1);
+ }
+
+ checkGraphConArcList(G, num * (num - 1));
+ checkGraphConEdgeList(G, num * (num - 1) / 2);
+
+ checkArcDirections(G);
+
+ checkNodeIds(G);
+ checkArcIds(G);
+ checkEdgeIds(G);
+ checkGraphNodeMap(G);
+ checkGraphArcMap(G);
+ checkGraphEdgeMap(G);
+
+
+ for (int i = 0; i < G.nodeNum(); ++i) {
+ check(G.index(G(i)) == i, "Wrong index");
+ }
+
+ for (NodeIt u(G); u != INVALID; ++u) {
+ for (NodeIt v(G); v != INVALID; ++v) {
+ Edge e = G.edge(u, v);
+ Arc a = G.arc(u, v);
+ if (u == v) {
+ check(e == INVALID, "Wrong edge lookup");
+ check(a == INVALID, "Wrong arc lookup");
+ } else {
+ check((G.u(e) == u && G.v(e) == v) ||
+ (G.u(e) == v && G.v(e) == u), "Wrong edge lookup");
+ check(G.source(a) == u && G.target(a) == v, "Wrong arc lookup");
+ }
+ }
+ }
+}
+
+void checkConcepts() {
+ { // Checking graph components
+ checkConcept<BaseGraphComponent, BaseGraphComponent >();
+
+ checkConcept<IDableGraphComponent<>,
+ IDableGraphComponent<> >();
+
+ checkConcept<IterableGraphComponent<>,
+ IterableGraphComponent<> >();
+
+ checkConcept<MappableGraphComponent<>,
+ MappableGraphComponent<> >();
+ }
+ { // Checking skeleton graph
+ checkConcept<Graph, Graph>();
+ }
+ { // Checking ListGraph
+ checkConcept<Graph, ListGraph>();
+ checkConcept<AlterableGraphComponent<>, ListGraph>();
+ checkConcept<ExtendableGraphComponent<>, ListGraph>();
+ checkConcept<ClearableGraphComponent<>, ListGraph>();
+ checkConcept<ErasableGraphComponent<>, ListGraph>();
+ }
+ { // Checking SmartGraph
+ checkConcept<Graph, SmartGraph>();
+ checkConcept<AlterableGraphComponent<>, SmartGraph>();
+ checkConcept<ExtendableGraphComponent<>, SmartGraph>();
+ checkConcept<ClearableGraphComponent<>, SmartGraph>();
+ }
+ { // Checking FullGraph
+ checkConcept<Graph, FullGraph>();
+ }
+ { // Checking GridGraph
+ checkConcept<Graph, GridGraph>();
+ }
+ { // Checking HypercubeGraph
+ checkConcept<Graph, HypercubeGraph>();
+ }
+}
+
+template <typename Graph>
+void checkGraphValidity() {
+ TEMPLATE_GRAPH_TYPEDEFS(Graph);
+ Graph g;
+
+ Node
+ n1 = g.addNode(),
+ n2 = g.addNode(),
+ n3 = g.addNode();
+
+ Edge
+ e1 = g.addEdge(n1, n2),
+ e2 = g.addEdge(n2, n3);
+ ::lemon::ignore_unused_variable_warning(e2);
+
+ check(g.valid(n1), "Wrong validity check");
+ check(g.valid(e1), "Wrong validity check");
+ check(g.valid(g.direct(e1, true)), "Wrong validity check");
+
+ check(!g.valid(g.nodeFromId(-1)), "Wrong validity check");
+ check(!g.valid(g.edgeFromId(-1)), "Wrong validity check");
+ check(!g.valid(g.arcFromId(-1)), "Wrong validity check");
+}
+
+template <typename Graph>
+void checkGraphValidityErase() {
+ TEMPLATE_GRAPH_TYPEDEFS(Graph);
+ Graph g;
+
+ Node
+ n1 = g.addNode(),
+ n2 = g.addNode(),
+ n3 = g.addNode();
+
+ Edge
+ e1 = g.addEdge(n1, n2),
+ e2 = g.addEdge(n2, n3);
+
+ check(g.valid(n1), "Wrong validity check");
+ check(g.valid(e1), "Wrong validity check");
+ check(g.valid(g.direct(e1, true)), "Wrong validity check");
+
+ g.erase(n1);
+
+ check(!g.valid(n1), "Wrong validity check");
+ check(g.valid(n2), "Wrong validity check");
+ check(g.valid(n3), "Wrong validity check");
+ check(!g.valid(e1), "Wrong validity check");
+ check(g.valid(e2), "Wrong validity check");
+
+ check(!g.valid(g.nodeFromId(-1)), "Wrong validity check");
+ check(!g.valid(g.edgeFromId(-1)), "Wrong validity check");
+ check(!g.valid(g.arcFromId(-1)), "Wrong validity check");
+}
+
+void checkGridGraph(int width, int height) {
+ typedef GridGraph Graph;
+ GRAPH_TYPEDEFS(Graph);
+ Graph G(width, height);
+
+ check(G.width() == width, "Wrong column number");
+ check(G.height() == height, "Wrong row number");
+
+ G.resize(width, height);
+ check(G.width() == width, "Wrong column number");
+ check(G.height() == height, "Wrong row number");
+
+ for (int i = 0; i < width; ++i) {
+ for (int j = 0; j < height; ++j) {
+ check(G.col(G(i, j)) == i, "Wrong column");
+ check(G.row(G(i, j)) == j, "Wrong row");
+ check(G.pos(G(i, j)).x == i, "Wrong column");
+ check(G.pos(G(i, j)).y == j, "Wrong row");
+ }
+ }
+
+ for (int j = 0; j < height; ++j) {
+ for (int i = 0; i < width - 1; ++i) {
+ check(G.source(G.right(G(i, j))) == G(i, j), "Wrong right");
+ check(G.target(G.right(G(i, j))) == G(i + 1, j), "Wrong right");
+ }
+ check(G.right(G(width - 1, j)) == INVALID, "Wrong right");
+ }
+
+ for (int j = 0; j < height; ++j) {
+ for (int i = 1; i < width; ++i) {
+ check(G.source(G.left(G(i, j))) == G(i, j), "Wrong left");
+ check(G.target(G.left(G(i, j))) == G(i - 1, j), "Wrong left");
+ }
+ check(G.left(G(0, j)) == INVALID, "Wrong left");
+ }
+
+ for (int i = 0; i < width; ++i) {
+ for (int j = 0; j < height - 1; ++j) {
+ check(G.source(G.up(G(i, j))) == G(i, j), "Wrong up");
+ check(G.target(G.up(G(i, j))) == G(i, j + 1), "Wrong up");
+ }
+ check(G.up(G(i, height - 1)) == INVALID, "Wrong up");
+ }
+
+ for (int i = 0; i < width; ++i) {
+ for (int j = 1; j < height; ++j) {
+ check(G.source(G.down(G(i, j))) == G(i, j), "Wrong down");
+ check(G.target(G.down(G(i, j))) == G(i, j - 1), "Wrong down");
+ }
+ check(G.down(G(i, 0)) == INVALID, "Wrong down");
+ }
+
+ checkGraphNodeList(G, width * height);
+ checkGraphEdgeList(G, width * (height - 1) + (width - 1) * height);
+ checkGraphArcList(G, 2 * (width * (height - 1) + (width - 1) * height));
+
+ for (NodeIt n(G); n != INVALID; ++n) {
+ int nb = 4;
+ if (G.col(n) == 0) --nb;
+ if (G.col(n) == width - 1) --nb;
+ if (G.row(n) == 0) --nb;
+ if (G.row(n) == height - 1) --nb;
+
+ checkGraphOutArcList(G, n, nb);
+ checkGraphInArcList(G, n, nb);
+ checkGraphIncEdgeList(G, n, nb);
+ }
+
+ checkArcDirections(G);
+
+ checkGraphConArcList(G, 2 * (width * (height - 1) + (width - 1) * height));
+ checkGraphConEdgeList(G, width * (height - 1) + (width - 1) * height);
+
+ checkNodeIds(G);
+ checkArcIds(G);
+ checkEdgeIds(G);
+ checkGraphNodeMap(G);
+ checkGraphArcMap(G);
+ checkGraphEdgeMap(G);
+
+}
+
+void checkHypercubeGraph(int dim) {
+ GRAPH_TYPEDEFS(HypercubeGraph);
+
+ HypercubeGraph G(dim);
+ check(G.dimension() == dim, "Wrong dimension");
+
+ G.resize(dim);
+ check(G.dimension() == dim, "Wrong dimension");
+
+ checkGraphNodeList(G, 1 << dim);
+ checkGraphEdgeList(G, dim * (1 << (dim-1)));
+ checkGraphArcList(G, dim * (1 << dim));
+
+ Node n = G.nodeFromId(dim);
+ ::lemon::ignore_unused_variable_warning(n);
+
+ for (NodeIt n(G); n != INVALID; ++n) {
+ checkGraphIncEdgeList(G, n, dim);
+ for (IncEdgeIt e(G, n); e != INVALID; ++e) {
+ check( (G.u(e) == n &&
+ G.id(G.v(e)) == (G.id(n) ^ (1 << G.dimension(e)))) ||
+ (G.v(e) == n &&
+ G.id(G.u(e)) == (G.id(n) ^ (1 << G.dimension(e)))),
+ "Wrong edge or wrong dimension");
+ }
+
+ checkGraphOutArcList(G, n, dim);
+ for (OutArcIt a(G, n); a != INVALID; ++a) {
+ check(G.source(a) == n &&
+ G.id(G.target(a)) == (G.id(n) ^ (1 << G.dimension(a))),
+ "Wrong arc or wrong dimension");
+ }
+
+ checkGraphInArcList(G, n, dim);
+ for (InArcIt a(G, n); a != INVALID; ++a) {
+ check(G.target(a) == n &&
+ G.id(G.source(a)) == (G.id(n) ^ (1 << G.dimension(a))),
+ "Wrong arc or wrong dimension");
+ }
+ }
+
+ checkGraphConArcList(G, (1 << dim) * dim);
+ checkGraphConEdgeList(G, dim * (1 << (dim-1)));
+
+ checkArcDirections(G);
+
+ checkNodeIds(G);
+ checkArcIds(G);
+ checkEdgeIds(G);
+ checkGraphNodeMap(G);
+ checkGraphArcMap(G);
+ checkGraphEdgeMap(G);
+}
+
+void checkGraphs() {
+ { // Checking ListGraph
+ checkGraphBuild<ListGraph>();
+ checkGraphAlter<ListGraph>();
+ checkGraphErase<ListGraph>();
+ checkGraphSnapshot<ListGraph>();
+ checkGraphValidityErase<ListGraph>();
+ }
+ { // Checking SmartGraph
+ checkGraphBuild<SmartGraph>();
+ checkGraphSnapshot<SmartGraph>();
+ checkGraphValidity<SmartGraph>();
+ }
+ { // Checking FullGraph
+ checkFullGraph(7);
+ checkFullGraph(8);
+ }
+ { // Checking GridGraph
+ checkGridGraph(5, 8);
+ checkGridGraph(8, 5);
+ checkGridGraph(5, 5);
+ checkGridGraph(0, 0);
+ checkGridGraph(1, 1);
+ }
+ { // Checking HypercubeGraph
+ checkHypercubeGraph(1);
+ checkHypercubeGraph(2);
+ checkHypercubeGraph(3);
+ checkHypercubeGraph(4);
+ }
+}
+
+int main() {
+ checkConcepts();
+ checkGraphs();
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/graph_test.h b/extern/quadriflow/3rd/lemon-1.3.1/test/graph_test.h
new file mode 100644
index 00000000000..70558b768e8
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/graph_test.h
@@ -0,0 +1,421 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_TEST_GRAPH_TEST_H
+#define LEMON_TEST_GRAPH_TEST_H
+
+#include <set>
+
+#include <lemon/core.h>
+#include <lemon/maps.h>
+
+#include "test_tools.h"
+
+namespace lemon {
+
+ template<class Graph>
+ void checkGraphNodeList(const Graph &G, int cnt)
+ {
+ typename Graph::NodeIt n(G);
+ for(int i=0;i<cnt;i++) {
+ check(n!=INVALID,"Wrong Node list linking.");
+ ++n;
+ }
+ check(n==INVALID,"Wrong Node list linking.");
+ check(countNodes(G)==cnt,"Wrong Node number.");
+ }
+
+ template<class Graph>
+ void checkGraphRedNodeList(const Graph &G, int cnt)
+ {
+ typename Graph::RedNodeIt n(G);
+ for(int i=0;i<cnt;i++) {
+ check(n!=INVALID,"Wrong red Node list linking.");
+ check(G.red(n),"Wrong node set check.");
+ check(!G.blue(n),"Wrong node set check.");
+ typename Graph::Node nn = n;
+ check(G.asRedNodeUnsafe(nn) == n,"Wrong node conversion.");
+ check(G.asRedNode(nn) == n,"Wrong node conversion.");
+ check(G.asBlueNode(nn) == INVALID,"Wrong node conversion.");
+ ++n;
+ }
+ check(n==INVALID,"Wrong red Node list linking.");
+ check(countRedNodes(G)==cnt,"Wrong red Node number.");
+ }
+
+ template<class Graph>
+ void checkGraphBlueNodeList(const Graph &G, int cnt)
+ {
+ typename Graph::BlueNodeIt n(G);
+ for(int i=0;i<cnt;i++) {
+ check(n!=INVALID,"Wrong blue Node list linking.");
+ check(G.blue(n),"Wrong node set check.");
+ check(!G.red(n),"Wrong node set check.");
+ typename Graph::Node nn = n;
+ check(G.asBlueNodeUnsafe(nn) == n,"Wrong node conversion.");
+ check(G.asBlueNode(nn) == n,"Wrong node conversion.");
+ check(G.asRedNode(nn) == INVALID,"Wrong node conversion.");
+ ++n;
+ }
+ check(n==INVALID,"Wrong blue Node list linking.");
+ check(countBlueNodes(G)==cnt,"Wrong blue Node number.");
+ }
+
+ template<class Graph>
+ void checkGraphArcList(const Graph &G, int cnt)
+ {
+ typename Graph::ArcIt e(G);
+ for(int i=0;i<cnt;i++) {
+ check(e!=INVALID,"Wrong Arc list linking.");
+ check(G.oppositeNode(G.source(e), e) == G.target(e),
+ "Wrong opposite node");
+ check(G.oppositeNode(G.target(e), e) == G.source(e),
+ "Wrong opposite node");
+ ++e;
+ }
+ check(e==INVALID,"Wrong Arc list linking.");
+ check(countArcs(G)==cnt,"Wrong Arc number.");
+ }
+
+ template<class Graph>
+ void checkGraphOutArcList(const Graph &G, typename Graph::Node n, int cnt)
+ {
+ typename Graph::OutArcIt e(G,n);
+ for(int i=0;i<cnt;i++) {
+ check(e!=INVALID,"Wrong OutArc list linking.");
+ check(n==G.source(e),"Wrong OutArc list linking.");
+ check(n==G.baseNode(e),"Wrong OutArc list linking.");
+ check(G.target(e)==G.runningNode(e),"Wrong OutArc list linking.");
+ ++e;
+ }
+ check(e==INVALID,"Wrong OutArc list linking.");
+ check(countOutArcs(G,n)==cnt,"Wrong OutArc number.");
+ }
+
+ template<class Graph>
+ void checkGraphInArcList(const Graph &G, typename Graph::Node n, int cnt)
+ {
+ typename Graph::InArcIt e(G,n);
+ for(int i=0;i<cnt;i++) {
+ check(e!=INVALID,"Wrong InArc list linking.");
+ check(n==G.target(e),"Wrong InArc list linking.");
+ check(n==G.baseNode(e),"Wrong OutArc list linking.");
+ check(G.source(e)==G.runningNode(e),"Wrong OutArc list linking.");
+ ++e;
+ }
+ check(e==INVALID,"Wrong InArc list linking.");
+ check(countInArcs(G,n)==cnt,"Wrong InArc number.");
+ }
+
+ template<class Graph>
+ void checkGraphEdgeList(const Graph &G, int cnt)
+ {
+ typename Graph::EdgeIt e(G);
+ for(int i=0;i<cnt;i++) {
+ check(e!=INVALID,"Wrong Edge list linking.");
+ check(G.oppositeNode(G.u(e), e) == G.v(e), "Wrong opposite node");
+ check(G.oppositeNode(G.v(e), e) == G.u(e), "Wrong opposite node");
+ ++e;
+ }
+ check(e==INVALID,"Wrong Edge list linking.");
+ check(countEdges(G)==cnt,"Wrong Edge number.");
+ }
+
+ template<class Graph>
+ void checkGraphIncEdgeList(const Graph &G, typename Graph::Node n, int cnt)
+ {
+ typename Graph::IncEdgeIt e(G,n);
+ for(int i=0;i<cnt;i++) {
+ check(e!=INVALID,"Wrong IncEdge list linking.");
+ check(n==G.u(e) || n==G.v(e),"Wrong IncEdge list linking.");
+ check(n==G.baseNode(e),"Wrong OutArc list linking.");
+ check(G.u(e)==G.runningNode(e) || G.v(e)==G.runningNode(e),
+ "Wrong OutArc list linking.");
+ ++e;
+ }
+ check(e==INVALID,"Wrong IncEdge list linking.");
+ check(countIncEdges(G,n)==cnt,"Wrong IncEdge number.");
+ }
+
+ template <class Graph>
+ void checkGraphIncEdgeArcLists(const Graph &G, typename Graph::Node n,
+ int cnt)
+ {
+ checkGraphIncEdgeList(G, n, cnt);
+ checkGraphOutArcList(G, n, cnt);
+ checkGraphInArcList(G, n, cnt);
+ }
+
+ template <class Graph>
+ void checkGraphConArcList(const Graph &G, int cnt) {
+ int i = 0;
+ for (typename Graph::NodeIt u(G); u != INVALID; ++u) {
+ for (typename Graph::NodeIt v(G); v != INVALID; ++v) {
+ for (ConArcIt<Graph> a(G, u, v); a != INVALID; ++a) {
+ check(G.source(a) == u, "Wrong iterator.");
+ check(G.target(a) == v, "Wrong iterator.");
+ ++i;
+ }
+ }
+ }
+ check(cnt == i, "Wrong iterator.");
+ }
+
+ template <class Graph>
+ void checkGraphConEdgeList(const Graph &G, int cnt) {
+ int i = 0;
+ for (typename Graph::NodeIt u(G); u != INVALID; ++u) {
+ for (typename Graph::NodeIt v(G); v != INVALID; ++v) {
+ for (ConEdgeIt<Graph> e(G, u, v); e != INVALID; ++e) {
+ check((G.u(e) == u && G.v(e) == v) ||
+ (G.u(e) == v && G.v(e) == u), "Wrong iterator.");
+ i += u == v ? 2 : 1;
+ }
+ }
+ }
+ check(2 * cnt == i, "Wrong iterator.");
+ }
+
+ template <typename Graph>
+ void checkArcDirections(const Graph& G) {
+ for (typename Graph::ArcIt a(G); a != INVALID; ++a) {
+ check(G.source(a) == G.target(G.oppositeArc(a)), "Wrong direction");
+ check(G.target(a) == G.source(G.oppositeArc(a)), "Wrong direction");
+ check(G.direct(a, G.direction(a)) == a, "Wrong direction");
+ }
+ }
+
+ template <typename Graph>
+ void checkNodeIds(const Graph& G) {
+ typedef typename Graph::Node Node;
+ std::set<int> values;
+ for (typename Graph::NodeIt n(G); n != INVALID; ++n) {
+ check(G.nodeFromId(G.id(n)) == n, "Wrong id");
+ check(values.find(G.id(n)) == values.end(), "Wrong id");
+ check(G.id(n) <= G.maxNodeId(), "Wrong maximum id");
+ values.insert(G.id(n));
+ }
+ check(G.maxId(Node()) <= G.maxNodeId(), "Wrong maximum id");
+ }
+
+ template <typename Graph>
+ void checkRedNodeIds(const Graph& G) {
+ typedef typename Graph::RedNode RedNode;
+ std::set<int> values;
+ for (typename Graph::RedNodeIt n(G); n != INVALID; ++n) {
+ check(G.red(n), "Wrong partition");
+ check(values.find(G.id(n)) == values.end(), "Wrong id");
+ check(G.id(n) <= G.maxRedId(), "Wrong maximum id");
+ values.insert(G.id(n));
+ }
+ check(G.maxId(RedNode()) == G.maxRedId(), "Wrong maximum id");
+ }
+
+ template <typename Graph>
+ void checkBlueNodeIds(const Graph& G) {
+ typedef typename Graph::BlueNode BlueNode;
+ std::set<int> values;
+ for (typename Graph::BlueNodeIt n(G); n != INVALID; ++n) {
+ check(G.blue(n), "Wrong partition");
+ check(values.find(G.id(n)) == values.end(), "Wrong id");
+ check(G.id(n) <= G.maxBlueId(), "Wrong maximum id");
+ values.insert(G.id(n));
+ }
+ check(G.maxId(BlueNode()) == G.maxBlueId(), "Wrong maximum id");
+ }
+
+ template <typename Graph>
+ void checkArcIds(const Graph& G) {
+ typedef typename Graph::Arc Arc;
+ std::set<int> values;
+ for (typename Graph::ArcIt a(G); a != INVALID; ++a) {
+ check(G.arcFromId(G.id(a)) == a, "Wrong id");
+ check(values.find(G.id(a)) == values.end(), "Wrong id");
+ check(G.id(a) <= G.maxArcId(), "Wrong maximum id");
+ values.insert(G.id(a));
+ }
+ check(G.maxId(Arc()) <= G.maxArcId(), "Wrong maximum id");
+ }
+
+ template <typename Graph>
+ void checkEdgeIds(const Graph& G) {
+ typedef typename Graph::Edge Edge;
+ std::set<int> values;
+ for (typename Graph::EdgeIt e(G); e != INVALID; ++e) {
+ check(G.edgeFromId(G.id(e)) == e, "Wrong id");
+ check(values.find(G.id(e)) == values.end(), "Wrong id");
+ check(G.id(e) <= G.maxEdgeId(), "Wrong maximum id");
+ values.insert(G.id(e));
+ }
+ check(G.maxId(Edge()) <= G.maxEdgeId(), "Wrong maximum id");
+ }
+
+ template <typename Graph>
+ void checkGraphNodeMap(const Graph& G) {
+ typedef typename Graph::Node Node;
+ typedef typename Graph::NodeIt NodeIt;
+
+ typedef typename Graph::template NodeMap<int> IntNodeMap;
+ IntNodeMap map(G, 42);
+ for (NodeIt it(G); it != INVALID; ++it) {
+ check(map[it] == 42, "Wrong map constructor.");
+ }
+ int s = 0;
+ for (NodeIt it(G); it != INVALID; ++it) {
+ map[it] = 0;
+ check(map[it] == 0, "Wrong operator[].");
+ map.set(it, s);
+ check(map[it] == s, "Wrong set.");
+ ++s;
+ }
+ s = s * (s - 1) / 2;
+ for (NodeIt it(G); it != INVALID; ++it) {
+ s -= map[it];
+ }
+ check(s == 0, "Wrong sum.");
+
+ // map = constMap<Node>(12);
+ // for (NodeIt it(G); it != INVALID; ++it) {
+ // check(map[it] == 12, "Wrong operator[].");
+ // }
+ }
+
+ template <typename Graph>
+ void checkGraphRedNodeMap(const Graph& G) {
+ typedef typename Graph::Node Node;
+ typedef typename Graph::RedNodeIt RedNodeIt;
+
+ typedef typename Graph::template RedNodeMap<int> IntRedNodeMap;
+ IntRedNodeMap map(G, 42);
+ for (RedNodeIt it(G); it != INVALID; ++it) {
+ check(map[it] == 42, "Wrong map constructor.");
+ }
+ int s = 0;
+ for (RedNodeIt it(G); it != INVALID; ++it) {
+ map[it] = 0;
+ check(map[it] == 0, "Wrong operator[].");
+ map.set(it, s);
+ check(map[it] == s, "Wrong set.");
+ ++s;
+ }
+ s = s * (s - 1) / 2;
+ for (RedNodeIt it(G); it != INVALID; ++it) {
+ s -= map[it];
+ }
+ check(s == 0, "Wrong sum.");
+
+ // map = constMap<Node>(12);
+ // for (NodeIt it(G); it != INVALID; ++it) {
+ // check(map[it] == 12, "Wrong operator[].");
+ // }
+ }
+
+ template <typename Graph>
+ void checkGraphBlueNodeMap(const Graph& G) {
+ typedef typename Graph::Node Node;
+ typedef typename Graph::BlueNodeIt BlueNodeIt;
+
+ typedef typename Graph::template BlueNodeMap<int> IntBlueNodeMap;
+ IntBlueNodeMap map(G, 42);
+ for (BlueNodeIt it(G); it != INVALID; ++it) {
+ check(map[it] == 42, "Wrong map constructor.");
+ }
+ int s = 0;
+ for (BlueNodeIt it(G); it != INVALID; ++it) {
+ map[it] = 0;
+ check(map[it] == 0, "Wrong operator[].");
+ map.set(it, s);
+ check(map[it] == s, "Wrong set.");
+ ++s;
+ }
+ s = s * (s - 1) / 2;
+ for (BlueNodeIt it(G); it != INVALID; ++it) {
+ s -= map[it];
+ }
+ check(s == 0, "Wrong sum.");
+
+ // map = constMap<Node>(12);
+ // for (NodeIt it(G); it != INVALID; ++it) {
+ // check(map[it] == 12, "Wrong operator[].");
+ // }
+ }
+
+ template <typename Graph>
+ void checkGraphArcMap(const Graph& G) {
+ typedef typename Graph::Arc Arc;
+ typedef typename Graph::ArcIt ArcIt;
+
+ typedef typename Graph::template ArcMap<int> IntArcMap;
+ IntArcMap map(G, 42);
+ for (ArcIt it(G); it != INVALID; ++it) {
+ check(map[it] == 42, "Wrong map constructor.");
+ }
+ int s = 0;
+ for (ArcIt it(G); it != INVALID; ++it) {
+ map[it] = 0;
+ check(map[it] == 0, "Wrong operator[].");
+ map.set(it, s);
+ check(map[it] == s, "Wrong set.");
+ ++s;
+ }
+ s = s * (s - 1) / 2;
+ for (ArcIt it(G); it != INVALID; ++it) {
+ s -= map[it];
+ }
+ check(s == 0, "Wrong sum.");
+
+ // map = constMap<Arc>(12);
+ // for (ArcIt it(G); it != INVALID; ++it) {
+ // check(map[it] == 12, "Wrong operator[].");
+ // }
+ }
+
+ template <typename Graph>
+ void checkGraphEdgeMap(const Graph& G) {
+ typedef typename Graph::Edge Edge;
+ typedef typename Graph::EdgeIt EdgeIt;
+
+ typedef typename Graph::template EdgeMap<int> IntEdgeMap;
+ IntEdgeMap map(G, 42);
+ for (EdgeIt it(G); it != INVALID; ++it) {
+ check(map[it] == 42, "Wrong map constructor.");
+ }
+ int s = 0;
+ for (EdgeIt it(G); it != INVALID; ++it) {
+ map[it] = 0;
+ check(map[it] == 0, "Wrong operator[].");
+ map.set(it, s);
+ check(map[it] == s, "Wrong set.");
+ ++s;
+ }
+ s = s * (s - 1) / 2;
+ for (EdgeIt it(G); it != INVALID; ++it) {
+ s -= map[it];
+ }
+ check(s == 0, "Wrong sum.");
+
+ // map = constMap<Edge>(12);
+ // for (EdgeIt it(G); it != INVALID; ++it) {
+ // check(map[it] == 12, "Wrong operator[].");
+ // }
+ }
+
+
+} //namespace lemon
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/graph_utils_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/graph_utils_test.cc
new file mode 100644
index 00000000000..19a934a235a
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/graph_utils_test.cc
@@ -0,0 +1,217 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <cstdlib>
+#include <ctime>
+
+#include <lemon/random.h>
+#include <lemon/list_graph.h>
+#include <lemon/smart_graph.h>
+#include <lemon/maps.h>
+
+#include "graph_test.h"
+#include "test_tools.h"
+
+using namespace lemon;
+
+template <typename Digraph>
+void checkFindArcs() {
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+
+ {
+ Digraph digraph;
+ for (int i = 0; i < 10; ++i) {
+ digraph.addNode();
+ }
+ RangeIdMap<Digraph, Node> nodes(digraph);
+ typename RangeIdMap<Digraph, Node>::InverseMap invNodes(nodes);
+ for (int i = 0; i < 100; ++i) {
+ int src = rnd[invNodes.size()];
+ int trg = rnd[invNodes.size()];
+ digraph.addArc(invNodes[src], invNodes[trg]);
+ }
+ typename Digraph::template ArcMap<bool> found(digraph, false);
+ RangeIdMap<Digraph, Arc> arcs(digraph);
+ for (NodeIt src(digraph); src != INVALID; ++src) {
+ for (NodeIt trg(digraph); trg != INVALID; ++trg) {
+ for (ConArcIt<Digraph> con(digraph, src, trg); con != INVALID; ++con) {
+ check(digraph.source(con) == src, "Wrong source.");
+ check(digraph.target(con) == trg, "Wrong target.");
+ check(found[con] == false, "The arc found already.");
+ found[con] = true;
+ }
+ }
+ }
+ for (ArcIt it(digraph); it != INVALID; ++it) {
+ check(found[it] == true, "The arc is not found.");
+ }
+ }
+
+ {
+ int num = 5;
+ Digraph fg;
+ std::vector<Node> nodes;
+ for (int i = 0; i < num; ++i) {
+ nodes.push_back(fg.addNode());
+ }
+ for (int i = 0; i < num * num; ++i) {
+ fg.addArc(nodes[i / num], nodes[i % num]);
+ }
+ check(countNodes(fg) == num, "Wrong node number.");
+ check(countArcs(fg) == num*num, "Wrong arc number.");
+ for (NodeIt src(fg); src != INVALID; ++src) {
+ for (NodeIt trg(fg); trg != INVALID; ++trg) {
+ ConArcIt<Digraph> con(fg, src, trg);
+ check(con != INVALID, "There is no connecting arc.");
+ check(fg.source(con) == src, "Wrong source.");
+ check(fg.target(con) == trg, "Wrong target.");
+ check(++con == INVALID, "There is more connecting arc.");
+ }
+ }
+ ArcLookUp<Digraph> al1(fg);
+ DynArcLookUp<Digraph> al2(fg);
+ AllArcLookUp<Digraph> al3(fg);
+ for (NodeIt src(fg); src != INVALID; ++src) {
+ for (NodeIt trg(fg); trg != INVALID; ++trg) {
+ Arc con1 = al1(src, trg);
+ Arc con2 = al2(src, trg);
+ Arc con3 = al3(src, trg);
+ Arc con4 = findArc(fg, src, trg);
+ check(con1 == con2 && con2 == con3 && con3 == con4,
+ "Different results.")
+ check(con1 != INVALID, "There is no connecting arc.");
+ check(fg.source(con1) == src, "Wrong source.");
+ check(fg.target(con1) == trg, "Wrong target.");
+ check(al3(src, trg, con3) == INVALID,
+ "There is more connecting arc.");
+ check(findArc(fg, src, trg, con4) == INVALID,
+ "There is more connecting arc.");
+ }
+ }
+ }
+}
+
+template <typename Graph>
+void checkFindEdges() {
+ TEMPLATE_GRAPH_TYPEDEFS(Graph);
+ Graph graph;
+ for (int i = 0; i < 10; ++i) {
+ graph.addNode();
+ }
+ RangeIdMap<Graph, Node> nodes(graph);
+ typename RangeIdMap<Graph, Node>::InverseMap invNodes(nodes);
+ for (int i = 0; i < 100; ++i) {
+ int src = rnd[invNodes.size()];
+ int trg = rnd[invNodes.size()];
+ graph.addEdge(invNodes[src], invNodes[trg]);
+ }
+ typename Graph::template EdgeMap<int> found(graph, 0);
+ RangeIdMap<Graph, Edge> edges(graph);
+ for (NodeIt src(graph); src != INVALID; ++src) {
+ for (NodeIt trg(graph); trg != INVALID; ++trg) {
+ for (ConEdgeIt<Graph> con(graph, src, trg); con != INVALID; ++con) {
+ check( (graph.u(con) == src && graph.v(con) == trg) ||
+ (graph.v(con) == src && graph.u(con) == trg),
+ "Wrong end nodes.");
+ ++found[con];
+ check(found[con] <= 2, "The edge found more than twice.");
+ }
+ }
+ }
+ for (EdgeIt it(graph); it != INVALID; ++it) {
+ check( (graph.u(it) != graph.v(it) && found[it] == 2) ||
+ (graph.u(it) == graph.v(it) && found[it] == 1),
+ "The edge is not found correctly.");
+ }
+}
+
+template <class Digraph>
+void checkDeg()
+{
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+
+ const int nodeNum = 10;
+ const int arcNum = 100;
+ Digraph digraph;
+ InDegMap<Digraph> inDeg(digraph);
+ OutDegMap<Digraph> outDeg(digraph);
+ std::vector<Node> nodes(nodeNum);
+ for (int i = 0; i < nodeNum; ++i) {
+ nodes[i] = digraph.addNode();
+ }
+ std::vector<Arc> arcs(arcNum);
+ for (int i = 0; i < arcNum; ++i) {
+ arcs[i] = digraph.addArc(nodes[rnd[nodeNum]], nodes[rnd[nodeNum]]);
+ }
+ for (int i = 0; i < nodeNum; ++i) {
+ check(inDeg[nodes[i]] == countInArcs(digraph, nodes[i]),
+ "Wrong in degree map");
+ }
+ for (int i = 0; i < nodeNum; ++i) {
+ check(outDeg[nodes[i]] == countOutArcs(digraph, nodes[i]),
+ "Wrong out degree map");
+ }
+}
+
+template <class Digraph>
+void checkSnapDeg()
+{
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+
+ Digraph g;
+ Node n1=g.addNode();
+ Node n2=g.addNode();
+
+ InDegMap<Digraph> ind(g);
+
+ g.addArc(n1,n2);
+
+ typename Digraph::Snapshot snap(g);
+
+ OutDegMap<Digraph> outd(g);
+
+ check(ind[n1]==0 && ind[n2]==1, "Wrong InDegMap value.");
+ check(outd[n1]==1 && outd[n2]==0, "Wrong OutDegMap value.");
+
+ g.addArc(n1,n2);
+ g.addArc(n2,n1);
+
+ check(ind[n1]==1 && ind[n2]==2, "Wrong InDegMap value.");
+ check(outd[n1]==2 && outd[n2]==1, "Wrong OutDegMap value.");
+
+ snap.restore();
+
+ check(ind[n1]==0 && ind[n2]==1, "Wrong InDegMap value.");
+ check(outd[n1]==1 && outd[n2]==0, "Wrong OutDegMap value.");
+}
+
+int main() {
+ // Checking ConArcIt, ConEdgeIt, ArcLookUp, AllArcLookUp, and DynArcLookUp
+ checkFindArcs<ListDigraph>();
+ checkFindArcs<SmartDigraph>();
+ checkFindEdges<ListGraph>();
+ checkFindEdges<SmartGraph>();
+
+ // Checking In/OutDegMap (and Snapshot feature)
+ checkDeg<ListDigraph>();
+ checkDeg<SmartDigraph>();
+ checkSnapDeg<ListDigraph>();
+ checkSnapDeg<SmartDigraph>();
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/hao_orlin_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/hao_orlin_test.cc
new file mode 100644
index 00000000000..c245cb7a727
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/hao_orlin_test.cc
@@ -0,0 +1,164 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <sstream>
+
+#include <lemon/smart_graph.h>
+#include <lemon/adaptors.h>
+#include <lemon/concepts/digraph.h>
+#include <lemon/concepts/maps.h>
+#include <lemon/lgf_reader.h>
+#include <lemon/hao_orlin.h>
+
+#include "test_tools.h"
+
+using namespace lemon;
+using namespace std;
+
+const std::string lgf =
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "5\n"
+ "@edges\n"
+ " cap1 cap2 cap3\n"
+ "0 1 1 1 1 \n"
+ "0 2 2 2 4 \n"
+ "1 2 4 4 4 \n"
+ "3 4 1 1 1 \n"
+ "3 5 2 2 4 \n"
+ "4 5 4 4 4 \n"
+ "5 4 4 4 4 \n"
+ "2 3 1 6 6 \n"
+ "4 0 1 6 6 \n";
+
+void checkHaoOrlinCompile()
+{
+ typedef int Value;
+ typedef concepts::Digraph Digraph;
+
+ typedef Digraph::Node Node;
+ typedef Digraph::Arc Arc;
+ typedef concepts::ReadMap<Arc, Value> CapMap;
+ typedef concepts::WriteMap<Node, bool> CutMap;
+
+ Digraph g;
+ Node n;
+ CapMap cap;
+ CutMap cut;
+ Value v;
+ ::lemon::ignore_unused_variable_warning(v);
+
+ HaoOrlin<Digraph, CapMap> ho_test(g, cap);
+ const HaoOrlin<Digraph, CapMap>&
+ const_ho_test = ho_test;
+
+ ho_test.init();
+ ho_test.init(n);
+ ho_test.calculateOut();
+ ho_test.calculateIn();
+ ho_test.run();
+ ho_test.run(n);
+
+ v = const_ho_test.minCutValue();
+ v = const_ho_test.minCutMap(cut);
+}
+
+template <typename Graph, typename CapMap, typename CutMap>
+typename CapMap::Value
+ cutValue(const Graph& graph, const CapMap& cap, const CutMap& cut)
+{
+ typename CapMap::Value sum = 0;
+ for (typename Graph::ArcIt a(graph); a != INVALID; ++a) {
+ if (cut[graph.source(a)] && !cut[graph.target(a)])
+ sum += cap[a];
+ }
+ return sum;
+}
+
+int main() {
+ SmartDigraph graph;
+ SmartDigraph::ArcMap<int> cap1(graph), cap2(graph), cap3(graph);
+ SmartDigraph::NodeMap<bool> cut(graph);
+
+ istringstream input(lgf);
+ digraphReader(graph, input)
+ .arcMap("cap1", cap1)
+ .arcMap("cap2", cap2)
+ .arcMap("cap3", cap3)
+ .run();
+
+ {
+ HaoOrlin<SmartDigraph> ho(graph, cap1);
+ ho.run();
+ ho.minCutMap(cut);
+
+ check(ho.minCutValue() == 1, "Wrong cut value");
+ check(ho.minCutValue() == cutValue(graph, cap1, cut), "Wrong cut value");
+ }
+ {
+ HaoOrlin<SmartDigraph> ho(graph, cap2);
+ ho.run();
+ ho.minCutMap(cut);
+
+ check(ho.minCutValue() == 1, "Wrong cut value");
+ check(ho.minCutValue() == cutValue(graph, cap2, cut), "Wrong cut value");
+ }
+ {
+ HaoOrlin<SmartDigraph> ho(graph, cap3);
+ ho.run();
+ ho.minCutMap(cut);
+
+ check(ho.minCutValue() == 1, "Wrong cut value");
+ check(ho.minCutValue() == cutValue(graph, cap3, cut), "Wrong cut value");
+ }
+
+ typedef Undirector<SmartDigraph> UGraph;
+ UGraph ugraph(graph);
+
+ {
+ HaoOrlin<UGraph, SmartDigraph::ArcMap<int> > ho(ugraph, cap1);
+ ho.run();
+ ho.minCutMap(cut);
+
+ check(ho.minCutValue() == 2, "Wrong cut value");
+ check(ho.minCutValue() == cutValue(ugraph, cap1, cut), "Wrong cut value");
+ }
+ {
+ HaoOrlin<UGraph, SmartDigraph::ArcMap<int> > ho(ugraph, cap2);
+ ho.run();
+ ho.minCutMap(cut);
+
+ check(ho.minCutValue() == 5, "Wrong cut value");
+ check(ho.minCutValue() == cutValue(ugraph, cap2, cut), "Wrong cut value");
+ }
+ {
+ HaoOrlin<UGraph, SmartDigraph::ArcMap<int> > ho(ugraph, cap3);
+ ho.run();
+ ho.minCutMap(cut);
+
+ check(ho.minCutValue() == 5, "Wrong cut value");
+ check(ho.minCutValue() == cutValue(ugraph, cap3, cut), "Wrong cut value");
+ }
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/heap_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/heap_test.cc
new file mode 100644
index 00000000000..38e15771a8a
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/heap_test.cc
@@ -0,0 +1,310 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include <lemon/concept_check.h>
+#include <lemon/concepts/heap.h>
+
+#include <lemon/smart_graph.h>
+#include <lemon/lgf_reader.h>
+#include <lemon/dijkstra.h>
+#include <lemon/maps.h>
+
+#include <lemon/bin_heap.h>
+#include <lemon/quad_heap.h>
+#include <lemon/dheap.h>
+#include <lemon/fib_heap.h>
+#include <lemon/pairing_heap.h>
+#include <lemon/radix_heap.h>
+#include <lemon/binomial_heap.h>
+#include <lemon/bucket_heap.h>
+
+#include "test_tools.h"
+
+using namespace lemon;
+using namespace lemon::concepts;
+
+typedef ListDigraph Digraph;
+DIGRAPH_TYPEDEFS(Digraph);
+
+char test_lgf[] =
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "5\n"
+ "6\n"
+ "7\n"
+ "8\n"
+ "9\n"
+ "@arcs\n"
+ " label capacity\n"
+ "0 5 0 94\n"
+ "3 9 1 11\n"
+ "8 7 2 83\n"
+ "1 2 3 94\n"
+ "5 7 4 35\n"
+ "7 4 5 84\n"
+ "9 5 6 38\n"
+ "0 4 7 96\n"
+ "6 7 8 6\n"
+ "3 1 9 27\n"
+ "5 2 10 77\n"
+ "5 6 11 69\n"
+ "6 5 12 41\n"
+ "4 6 13 70\n"
+ "3 2 14 45\n"
+ "7 9 15 93\n"
+ "5 9 16 50\n"
+ "9 0 17 94\n"
+ "9 6 18 67\n"
+ "0 9 19 86\n"
+ "@attributes\n"
+ "source 3\n";
+
+int test_seq[] = { 2, 28, 19, 27, 33, 25, 13, 41, 10, 26, 1, 9, 4, 34};
+int test_inc[] = {20, 28, 34, 16, 0, 46, 44, 0, 42, 32, 14, 8, 6, 37};
+
+int test_len = sizeof(test_seq) / sizeof(test_seq[0]);
+
+template <typename Heap>
+void heapSortTest() {
+ RangeMap<int> map(test_len, -1);
+ Heap heap(map);
+
+ std::vector<int> v(test_len);
+ for (int i = 0; i < test_len; ++i) {
+ v[i] = test_seq[i];
+ heap.push(i, v[i]);
+ }
+ std::sort(v.begin(), v.end());
+ for (int i = 0; i < test_len; ++i) {
+ check(v[i] == heap.prio(), "Wrong order in heap sort.");
+ heap.pop();
+ }
+}
+
+template <typename Heap>
+void heapIncreaseTest() {
+ RangeMap<int> map(test_len, -1);
+
+ Heap heap(map);
+
+ std::vector<int> v(test_len);
+ for (int i = 0; i < test_len; ++i) {
+ v[i] = test_seq[i];
+ heap.push(i, v[i]);
+ }
+ for (int i = 0; i < test_len; ++i) {
+ v[i] += test_inc[i];
+ heap.increase(i, v[i]);
+ }
+ std::sort(v.begin(), v.end());
+ for (int i = 0; i < test_len; ++i) {
+ check(v[i] == heap.prio(), "Wrong order in heap increase test.");
+ heap.pop();
+ }
+}
+
+template <typename Heap>
+void dijkstraHeapTest(const Digraph& digraph, const IntArcMap& length,
+ Node source) {
+
+ typename Dijkstra<Digraph, IntArcMap>::template SetStandardHeap<Heap>::
+ Create dijkstra(digraph, length);
+
+ dijkstra.run(source);
+
+ for(ArcIt a(digraph); a != INVALID; ++a) {
+ Node s = digraph.source(a);
+ Node t = digraph.target(a);
+ if (dijkstra.reached(s)) {
+ check( dijkstra.dist(t) - dijkstra.dist(s) <= length[a],
+ "Error in shortest path tree.");
+ }
+ }
+
+ for(NodeIt n(digraph); n != INVALID; ++n) {
+ if ( dijkstra.reached(n) && dijkstra.predArc(n) != INVALID ) {
+ Arc a = dijkstra.predArc(n);
+ Node s = digraph.source(a);
+ check( dijkstra.dist(n) - dijkstra.dist(s) == length[a],
+ "Error in shortest path tree.");
+ }
+ }
+
+}
+
+int main() {
+
+ typedef int Item;
+ typedef int Prio;
+ typedef RangeMap<int> ItemIntMap;
+
+ Digraph digraph;
+ IntArcMap length(digraph);
+ Node source;
+
+ std::istringstream input(test_lgf);
+ digraphReader(digraph, input).
+ arcMap("capacity", length).
+ node("source", source).
+ run();
+
+ // BinHeap
+ {
+ typedef BinHeap<Prio, ItemIntMap> IntHeap;
+ checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
+ heapSortTest<IntHeap>();
+ heapIncreaseTest<IntHeap>();
+
+ typedef BinHeap<Prio, IntNodeMap > NodeHeap;
+ checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
+ dijkstraHeapTest<NodeHeap>(digraph, length, source);
+ }
+
+ // QuadHeap
+ {
+ typedef QuadHeap<Prio, ItemIntMap> IntHeap;
+ checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
+ heapSortTest<IntHeap>();
+ heapIncreaseTest<IntHeap>();
+
+ typedef QuadHeap<Prio, IntNodeMap > NodeHeap;
+ checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
+ dijkstraHeapTest<NodeHeap>(digraph, length, source);
+ }
+
+ // DHeap
+ {
+ typedef DHeap<Prio, ItemIntMap> IntHeap;
+ checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
+ heapSortTest<IntHeap>();
+ heapIncreaseTest<IntHeap>();
+
+ typedef DHeap<Prio, IntNodeMap > NodeHeap;
+ checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
+ dijkstraHeapTest<NodeHeap>(digraph, length, source);
+ }
+
+ // FibHeap
+ {
+ typedef FibHeap<Prio, ItemIntMap> IntHeap;
+ checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
+ heapSortTest<IntHeap>();
+ heapIncreaseTest<IntHeap>();
+
+ typedef FibHeap<Prio, IntNodeMap > NodeHeap;
+ checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
+ dijkstraHeapTest<NodeHeap>(digraph, length, source);
+ }
+
+ // PairingHeap
+ {
+ typedef PairingHeap<Prio, ItemIntMap> IntHeap;
+ checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
+ heapSortTest<IntHeap>();
+ heapIncreaseTest<IntHeap>();
+
+ typedef PairingHeap<Prio, IntNodeMap > NodeHeap;
+ checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
+ dijkstraHeapTest<NodeHeap>(digraph, length, source);
+ }
+
+ // RadixHeap
+ {
+ typedef RadixHeap<ItemIntMap> IntHeap;
+ checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
+ heapSortTest<IntHeap>();
+ heapIncreaseTest<IntHeap>();
+
+ typedef RadixHeap<IntNodeMap > NodeHeap;
+ checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
+ dijkstraHeapTest<NodeHeap>(digraph, length, source);
+ }
+
+ // BinomialHeap
+ {
+ typedef BinomialHeap<Prio, ItemIntMap> IntHeap;
+ checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
+ heapSortTest<IntHeap>();
+ heapIncreaseTest<IntHeap>();
+
+ typedef BinomialHeap<Prio, IntNodeMap > NodeHeap;
+ checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
+ dijkstraHeapTest<NodeHeap>(digraph, length, source);
+ }
+
+ // BucketHeap, SimpleBucketHeap
+ {
+ typedef BucketHeap<ItemIntMap> IntHeap;
+ checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
+ heapSortTest<IntHeap>();
+ heapIncreaseTest<IntHeap>();
+
+ typedef BucketHeap<IntNodeMap > NodeHeap;
+ checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
+ dijkstraHeapTest<NodeHeap>(digraph, length, source);
+
+ typedef SimpleBucketHeap<ItemIntMap> SimpleIntHeap;
+ heapSortTest<SimpleIntHeap>();
+ }
+
+ {
+ typedef FibHeap<Prio, ItemIntMap> IntHeap;
+ checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
+ heapSortTest<IntHeap>();
+ heapIncreaseTest<IntHeap>();
+
+ typedef FibHeap<Prio, IntNodeMap > NodeHeap;
+ checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
+ dijkstraHeapTest<NodeHeap>(digraph, length, source);
+ }
+
+ {
+ typedef RadixHeap<ItemIntMap> IntHeap;
+ checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
+ heapSortTest<IntHeap>();
+ heapIncreaseTest<IntHeap>();
+
+ typedef RadixHeap<IntNodeMap > NodeHeap;
+ checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
+ dijkstraHeapTest<NodeHeap>(digraph, length, source);
+ }
+
+ {
+ typedef BucketHeap<ItemIntMap> IntHeap;
+ checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
+ heapSortTest<IntHeap>();
+ heapIncreaseTest<IntHeap>();
+
+ typedef BucketHeap<IntNodeMap > NodeHeap;
+ checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
+ dijkstraHeapTest<NodeHeap>(digraph, length, source);
+ }
+
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/kruskal_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/kruskal_test.cc
new file mode 100644
index 00000000000..af36c72fd7c
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/kruskal_test.cc
@@ -0,0 +1,147 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <iostream>
+#include <vector>
+
+#include "test_tools.h"
+#include <lemon/maps.h>
+#include <lemon/kruskal.h>
+#include <lemon/list_graph.h>
+
+#include <lemon/concepts/maps.h>
+#include <lemon/concepts/digraph.h>
+#include <lemon/concepts/graph.h>
+
+using namespace std;
+using namespace lemon;
+
+void checkCompileKruskal()
+{
+ concepts::WriteMap<concepts::Digraph::Arc,bool> w;
+ concepts::WriteMap<concepts::Graph::Edge,bool> uw;
+
+ concepts::ReadMap<concepts::Digraph::Arc,int> r;
+ concepts::ReadMap<concepts::Graph::Edge,int> ur;
+
+ concepts::Digraph g;
+ concepts::Graph ug;
+
+ kruskal(g, r, w);
+ kruskal(ug, ur, uw);
+
+ std::vector<std::pair<concepts::Digraph::Arc, int> > rs;
+ std::vector<std::pair<concepts::Graph::Edge, int> > urs;
+
+ kruskal(g, rs, w);
+ kruskal(ug, urs, uw);
+
+ std::vector<concepts::Digraph::Arc> ws;
+ std::vector<concepts::Graph::Edge> uws;
+
+ kruskal(g, r, ws.begin());
+ kruskal(ug, ur, uws.begin());
+}
+
+int main() {
+
+ typedef ListGraph::Node Node;
+ typedef ListGraph::Edge Edge;
+ typedef ListGraph::NodeIt NodeIt;
+ typedef ListGraph::ArcIt ArcIt;
+
+ ListGraph G;
+
+ Node s=G.addNode();
+ Node v1=G.addNode();
+ Node v2=G.addNode();
+ Node v3=G.addNode();
+ Node v4=G.addNode();
+ Node t=G.addNode();
+
+ Edge e1 = G.addEdge(s, v1);
+ Edge e2 = G.addEdge(s, v2);
+ Edge e3 = G.addEdge(v1, v2);
+ Edge e4 = G.addEdge(v2, v1);
+ Edge e5 = G.addEdge(v1, v3);
+ Edge e6 = G.addEdge(v3, v2);
+ Edge e7 = G.addEdge(v2, v4);
+ Edge e8 = G.addEdge(v4, v3);
+ Edge e9 = G.addEdge(v3, t);
+ Edge e10 = G.addEdge(v4, t);
+
+ typedef ListGraph::EdgeMap<int> ECostMap;
+ typedef ListGraph::EdgeMap<bool> EBoolMap;
+
+ ECostMap edge_cost_map(G, 2);
+ EBoolMap tree_map(G);
+
+
+ //Test with const map.
+ check(kruskal(G, ConstMap<ListGraph::Edge,int>(2), tree_map)==10,
+ "Total cost should be 10");
+ //Test with an edge map (filled with uniform costs).
+ check(kruskal(G, edge_cost_map, tree_map)==10,
+ "Total cost should be 10");
+
+ edge_cost_map[e1] = -10;
+ edge_cost_map[e2] = -9;
+ edge_cost_map[e3] = -8;
+ edge_cost_map[e4] = -7;
+ edge_cost_map[e5] = -6;
+ edge_cost_map[e6] = -5;
+ edge_cost_map[e7] = -4;
+ edge_cost_map[e8] = -3;
+ edge_cost_map[e9] = -2;
+ edge_cost_map[e10] = -1;
+
+ vector<Edge> tree_edge_vec(5);
+
+ //Test with a edge map and inserter.
+ check(kruskal(G, edge_cost_map,
+ tree_edge_vec.begin())
+ ==-31,
+ "Total cost should be -31.");
+
+ tree_edge_vec.clear();
+
+ check(kruskal(G, edge_cost_map,
+ back_inserter(tree_edge_vec))
+ ==-31,
+ "Total cost should be -31.");
+
+// tree_edge_vec.clear();
+
+// //The above test could also be coded like this:
+// check(kruskal(G,
+// makeKruskalMapInput(G, edge_cost_map),
+// makeKruskalSequenceOutput(back_inserter(tree_edge_vec)))
+// ==-31,
+// "Total cost should be -31.");
+
+ check(tree_edge_vec.size()==5,"The tree should have 5 edges.");
+
+ check(tree_edge_vec[0]==e1 &&
+ tree_edge_vec[1]==e2 &&
+ tree_edge_vec[2]==e5 &&
+ tree_edge_vec[3]==e7 &&
+ tree_edge_vec[4]==e9,
+ "Wrong tree.");
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/lgf_reader_writer_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/lgf_reader_writer_test.cc
new file mode 100644
index 00000000000..25d9423ac0c
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/lgf_reader_writer_test.cc
@@ -0,0 +1,578 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <string>
+
+#include <lemon/concepts/digraph.h>
+#include <lemon/concepts/graph.h>
+#include <lemon/concepts/bpgraph.h>
+
+#include <lemon/list_graph.h>
+#include <lemon/smart_graph.h>
+#include <lemon/lgf_reader.h>
+
+#include "test_tools.h"
+
+struct ReaderConverter {
+ int operator()(const std::string& str) const {
+ return str.length();
+ }
+};
+
+struct WriterConverter {
+ std::string operator()(int value) const {
+ return std::string(value, '*');
+ }
+};
+
+void checkDigraphReaderCompile() {
+ typedef lemon::concepts::ExtendableDigraphComponent<
+ lemon::concepts::Digraph> Digraph;
+ Digraph digraph;
+ Digraph::NodeMap<int> node_map(digraph);
+ Digraph::ArcMap<int> arc_map(digraph);
+ Digraph::Node node;
+ Digraph::Arc arc;
+ int attr;
+
+ lemon::DigraphReader<Digraph> reader(digraph, "filename");
+ reader.nodeMap("node_map", node_map);
+ reader.nodeMap("node_map", node_map, ReaderConverter());
+ reader.arcMap("arc_map", arc_map);
+ reader.arcMap("arc_map", arc_map, ReaderConverter());
+ reader.attribute("attr", attr);
+ reader.attribute("attr", attr, ReaderConverter());
+ reader.node("node", node);
+ reader.arc("arc", arc);
+
+ reader.nodes("alt_nodes_caption");
+ reader.arcs("alt_arcs_caption");
+ reader.attributes("alt_attrs_caption");
+
+ reader.useNodes(node_map);
+ reader.useNodes(node_map, WriterConverter());
+ reader.useArcs(arc_map);
+ reader.useArcs(arc_map, WriterConverter());
+
+ reader.skipNodes();
+ reader.skipArcs();
+
+ reader.run();
+
+ lemon::DigraphReader<Digraph> reader2(digraph, std::cin);
+}
+
+void checkDigraphWriterCompile() {
+ typedef lemon::concepts::Digraph Digraph;
+ Digraph digraph;
+ Digraph::NodeMap<int> node_map(digraph);
+ Digraph::ArcMap<int> arc_map(digraph);
+ Digraph::Node node;
+ Digraph::Arc arc;
+ int attr;
+
+ lemon::DigraphWriter<Digraph> writer(digraph, "filename");
+ writer.nodeMap("node_map", node_map);
+ writer.nodeMap("node_map", node_map, WriterConverter());
+ writer.arcMap("arc_map", arc_map);
+ writer.arcMap("arc_map", arc_map, WriterConverter());
+ writer.attribute("attr", attr);
+ writer.attribute("attr", attr, WriterConverter());
+ writer.node("node", node);
+ writer.arc("arc", arc);
+
+ writer.nodes("alt_nodes_caption");
+ writer.arcs("alt_arcs_caption");
+ writer.attributes("alt_attrs_caption");
+
+ writer.skipNodes();
+ writer.skipArcs();
+
+ writer.run();
+}
+
+void checkGraphReaderCompile() {
+ typedef lemon::concepts::ExtendableGraphComponent<
+ lemon::concepts::Graph> Graph;
+ Graph graph;
+ Graph::NodeMap<int> node_map(graph);
+ Graph::ArcMap<int> arc_map(graph);
+ Graph::EdgeMap<int> edge_map(graph);
+ Graph::Node node;
+ Graph::Arc arc;
+ Graph::Edge edge;
+ int attr;
+
+ lemon::GraphReader<Graph> reader(graph, "filename");
+ reader.nodeMap("node_map", node_map);
+ reader.nodeMap("node_map", node_map, ReaderConverter());
+ reader.arcMap("arc_map", arc_map);
+ reader.arcMap("arc_map", arc_map, ReaderConverter());
+ reader.edgeMap("edge_map", edge_map);
+ reader.edgeMap("edge_map", edge_map, ReaderConverter());
+ reader.attribute("attr", attr);
+ reader.attribute("attr", attr, ReaderConverter());
+ reader.node("node", node);
+ reader.arc("arc", arc);
+
+ reader.nodes("alt_nodes_caption");
+ reader.edges("alt_edges_caption");
+ reader.attributes("alt_attrs_caption");
+
+ reader.useNodes(node_map);
+ reader.useNodes(node_map, WriterConverter());
+ reader.useEdges(edge_map);
+ reader.useEdges(edge_map, WriterConverter());
+
+ reader.skipNodes();
+ reader.skipEdges();
+
+ reader.run();
+
+ lemon::GraphReader<Graph> reader2(graph, std::cin);
+}
+
+void checkGraphWriterCompile() {
+ typedef lemon::concepts::Graph Graph;
+ Graph graph;
+ Graph::NodeMap<int> node_map(graph);
+ Graph::ArcMap<int> arc_map(graph);
+ Graph::EdgeMap<int> edge_map(graph);
+ Graph::Node node;
+ Graph::Arc arc;
+ Graph::Edge edge;
+ int attr;
+
+ lemon::GraphWriter<Graph> writer(graph, "filename");
+ writer.nodeMap("node_map", node_map);
+ writer.nodeMap("node_map", node_map, WriterConverter());
+ writer.arcMap("arc_map", arc_map);
+ writer.arcMap("arc_map", arc_map, WriterConverter());
+ writer.edgeMap("edge_map", edge_map);
+ writer.edgeMap("edge_map", edge_map, WriterConverter());
+ writer.attribute("attr", attr);
+ writer.attribute("attr", attr, WriterConverter());
+ writer.node("node", node);
+ writer.arc("arc", arc);
+ writer.edge("edge", edge);
+
+ writer.nodes("alt_nodes_caption");
+ writer.edges("alt_edges_caption");
+ writer.attributes("alt_attrs_caption");
+
+ writer.skipNodes();
+ writer.skipEdges();
+
+ writer.run();
+
+ lemon::GraphWriter<Graph> writer2(graph, std::cout);
+}
+
+void checkBpGraphReaderCompile() {
+ typedef lemon::concepts::ExtendableBpGraphComponent<
+ lemon::concepts::BpGraph> BpGraph;
+ BpGraph graph;
+ BpGraph::NodeMap<int> node_map(graph);
+ BpGraph::RedNodeMap<int> red_node_map(graph);
+ BpGraph::BlueNodeMap<int> blue_node_map(graph);
+ BpGraph::ArcMap<int> arc_map(graph);
+ BpGraph::EdgeMap<int> edge_map(graph);
+ BpGraph::Node node;
+ BpGraph::RedNode red_node;
+ BpGraph::BlueNode blue_node;
+ BpGraph::Arc arc;
+ BpGraph::Edge edge;
+ int attr;
+
+ lemon::BpGraphReader<BpGraph> reader(graph, "filename");
+ reader.nodeMap("node_map", node_map);
+ reader.nodeMap("node_map", node_map, ReaderConverter());
+ reader.redNodeMap("red_node_map", red_node_map);
+ reader.redNodeMap("red_node_map", red_node_map, ReaderConverter());
+ reader.blueNodeMap("blue_node_map", blue_node_map);
+ reader.blueNodeMap("blue_node_map", blue_node_map, ReaderConverter());
+ reader.arcMap("arc_map", arc_map);
+ reader.arcMap("arc_map", arc_map, ReaderConverter());
+ reader.edgeMap("edge_map", edge_map);
+ reader.edgeMap("edge_map", edge_map, ReaderConverter());
+ reader.attribute("attr", attr);
+ reader.attribute("attr", attr, ReaderConverter());
+ reader.node("node", node);
+ reader.redNode("red_node", red_node);
+ reader.blueNode("blue_node", blue_node);
+ reader.arc("arc", arc);
+
+ reader.nodes("alt_nodes_caption");
+ reader.edges("alt_edges_caption");
+ reader.attributes("alt_attrs_caption");
+
+ reader.useNodes(node_map);
+ reader.useNodes(node_map, WriterConverter());
+ reader.useEdges(edge_map);
+ reader.useEdges(edge_map, WriterConverter());
+
+ reader.skipNodes();
+ reader.skipEdges();
+
+ reader.run();
+
+ lemon::BpGraphReader<BpGraph> reader2(graph, std::cin);
+}
+
+void checkBpGraphWriterCompile() {
+ typedef lemon::concepts::BpGraph BpGraph;
+ BpGraph graph;
+ BpGraph::NodeMap<int> node_map(graph);
+ BpGraph::RedNodeMap<int> red_node_map(graph);
+ BpGraph::BlueNodeMap<int> blue_node_map(graph);
+ BpGraph::ArcMap<int> arc_map(graph);
+ BpGraph::EdgeMap<int> edge_map(graph);
+ BpGraph::Node node;
+ BpGraph::RedNode red_node;
+ BpGraph::BlueNode blue_node;
+ BpGraph::Arc arc;
+ BpGraph::Edge edge;
+ int attr;
+
+ lemon::BpGraphWriter<BpGraph> writer(graph, "filename");
+ writer.nodeMap("node_map", node_map);
+ writer.nodeMap("node_map", node_map, WriterConverter());
+ writer.redNodeMap("red_node_map", red_node_map);
+ writer.redNodeMap("red_node_map", red_node_map, WriterConverter());
+ writer.blueNodeMap("blue_node_map", blue_node_map);
+ writer.blueNodeMap("blue_node_map", blue_node_map, WriterConverter());
+ writer.arcMap("arc_map", arc_map);
+ writer.arcMap("arc_map", arc_map, WriterConverter());
+ writer.edgeMap("edge_map", edge_map);
+ writer.edgeMap("edge_map", edge_map, WriterConverter());
+ writer.attribute("attr", attr);
+ writer.attribute("attr", attr, WriterConverter());
+ writer.node("node", node);
+ writer.redNode("red_node", red_node);
+ writer.blueNode("blue_node", blue_node);
+ writer.arc("arc", arc);
+
+ writer.nodes("alt_nodes_caption");
+ writer.edges("alt_edges_caption");
+ writer.attributes("alt_attrs_caption");
+
+ writer.skipNodes();
+ writer.skipEdges();
+
+ writer.run();
+
+ lemon::BpGraphWriter<BpGraph> writer2(graph, std::cout);
+}
+
+void checkDigraphReaderWriter() {
+ typedef lemon::SmartDigraph Digraph;
+ Digraph digraph;
+ Digraph::Node n1 = digraph.addNode();
+ Digraph::Node n2 = digraph.addNode();
+ Digraph::Node n3 = digraph.addNode();
+
+ Digraph::Arc a1 = digraph.addArc(n1, n2);
+ Digraph::Arc a2 = digraph.addArc(n2, n3);
+
+ Digraph::NodeMap<int> node_map(digraph);
+ node_map[n1] = 11;
+ node_map[n2] = 12;
+ node_map[n3] = 13;
+
+ Digraph::ArcMap<int> arc_map(digraph);
+ arc_map[a1] = 21;
+ arc_map[a2] = 22;
+
+ int attr = 100;
+
+ std::ostringstream os;
+ lemon::DigraphWriter<Digraph> writer(digraph, os);
+
+ writer.nodeMap("node_map1", node_map);
+ writer.nodeMap("node_map2", node_map, WriterConverter());
+ writer.arcMap("arc_map1", arc_map);
+ writer.arcMap("arc_map2", arc_map, WriterConverter());
+ writer.node("node", n2);
+ writer.arc("arc", a1);
+ writer.attribute("attr1", attr);
+ writer.attribute("attr2", attr, WriterConverter());
+
+ writer.run();
+
+ typedef lemon::ListDigraph ExpDigraph;
+ ExpDigraph exp_digraph;
+ ExpDigraph::NodeMap<int> exp_node_map1(exp_digraph);
+ ExpDigraph::NodeMap<int> exp_node_map2(exp_digraph);
+ ExpDigraph::ArcMap<int> exp_arc_map1(exp_digraph);
+ ExpDigraph::ArcMap<int> exp_arc_map2(exp_digraph);
+ ExpDigraph::Node exp_n2;
+ ExpDigraph::Arc exp_a1;
+ int exp_attr1;
+ int exp_attr2;
+
+ std::istringstream is(os.str());
+ lemon::DigraphReader<ExpDigraph> reader(exp_digraph, is);
+
+ reader.nodeMap("node_map1", exp_node_map1);
+ reader.nodeMap("node_map2", exp_node_map2, ReaderConverter());
+ reader.arcMap("arc_map1", exp_arc_map1);
+ reader.arcMap("arc_map2", exp_arc_map2, ReaderConverter());
+ reader.node("node", exp_n2);
+ reader.arc("arc", exp_a1);
+ reader.attribute("attr1", exp_attr1);
+ reader.attribute("attr2", exp_attr2, ReaderConverter());
+
+ reader.run();
+
+ check(lemon::countNodes(exp_digraph) == 3, "Wrong number of nodes");
+ check(lemon::countArcs(exp_digraph) == 2, "Wrong number of arcs");
+ check(exp_node_map1[exp_n2] == 12, "Wrong map value");
+ check(exp_node_map2[exp_n2] == 12, "Wrong map value");
+ check(exp_arc_map1[exp_a1] == 21, "Wrong map value");
+ check(exp_arc_map2[exp_a1] == 21, "Wrong map value");
+ check(exp_attr1 == 100, "Wrong attr value");
+ check(exp_attr2 == 100, "Wrong attr value");
+}
+
+void checkGraphReaderWriter() {
+ typedef lemon::SmartGraph Graph;
+ Graph graph;
+ Graph::Node n1 = graph.addNode();
+ Graph::Node n2 = graph.addNode();
+ Graph::Node n3 = graph.addNode();
+
+ Graph::Edge e1 = graph.addEdge(n1, n2);
+ Graph::Edge e2 = graph.addEdge(n2, n3);
+
+ Graph::NodeMap<int> node_map(graph);
+ node_map[n1] = 11;
+ node_map[n2] = 12;
+ node_map[n3] = 13;
+
+ Graph::EdgeMap<int> edge_map(graph);
+ edge_map[e1] = 21;
+ edge_map[e2] = 22;
+
+ Graph::ArcMap<int> arc_map(graph);
+ arc_map[graph.direct(e1, true)] = 211;
+ arc_map[graph.direct(e1, false)] = 212;
+ arc_map[graph.direct(e2, true)] = 221;
+ arc_map[graph.direct(e2, false)] = 222;
+
+ int attr = 100;
+
+ std::ostringstream os;
+ lemon::GraphWriter<Graph> writer(graph, os);
+
+ writer.nodeMap("node_map1", node_map);
+ writer.nodeMap("node_map2", node_map, WriterConverter());
+ writer.edgeMap("edge_map1", edge_map);
+ writer.edgeMap("edge_map2", edge_map, WriterConverter());
+ writer.arcMap("arc_map1", arc_map);
+ writer.arcMap("arc_map2", arc_map, WriterConverter());
+ writer.node("node", n2);
+ writer.edge("edge", e1);
+ writer.arc("arc", graph.direct(e1, false));
+ writer.attribute("attr1", attr);
+ writer.attribute("attr2", attr, WriterConverter());
+
+ writer.run();
+
+ typedef lemon::ListGraph ExpGraph;
+ ExpGraph exp_graph;
+ ExpGraph::NodeMap<int> exp_node_map1(exp_graph);
+ ExpGraph::NodeMap<int> exp_node_map2(exp_graph);
+ ExpGraph::EdgeMap<int> exp_edge_map1(exp_graph);
+ ExpGraph::EdgeMap<int> exp_edge_map2(exp_graph);
+ ExpGraph::ArcMap<int> exp_arc_map1(exp_graph);
+ ExpGraph::ArcMap<int> exp_arc_map2(exp_graph);
+ ExpGraph::Node exp_n2;
+ ExpGraph::Edge exp_e1;
+ ExpGraph::Arc exp_a1;
+ int exp_attr1;
+ int exp_attr2;
+
+ std::istringstream is(os.str());
+ lemon::GraphReader<ExpGraph> reader(exp_graph, is);
+
+ reader.nodeMap("node_map1", exp_node_map1);
+ reader.nodeMap("node_map2", exp_node_map2, ReaderConverter());
+ reader.edgeMap("edge_map1", exp_edge_map1);
+ reader.edgeMap("edge_map2", exp_edge_map2, ReaderConverter());
+ reader.arcMap("arc_map1", exp_arc_map1);
+ reader.arcMap("arc_map2", exp_arc_map2, ReaderConverter());
+ reader.node("node", exp_n2);
+ reader.edge("edge", exp_e1);
+ reader.arc("arc", exp_a1);
+ reader.attribute("attr1", exp_attr1);
+ reader.attribute("attr2", exp_attr2, ReaderConverter());
+
+ reader.run();
+
+ check(lemon::countNodes(exp_graph) == 3, "Wrong number of nodes");
+ check(lemon::countEdges(exp_graph) == 2, "Wrong number of edges");
+ check(lemon::countArcs(exp_graph) == 4, "Wrong number of arcs");
+ check(exp_node_map1[exp_n2] == 12, "Wrong map value");
+ check(exp_node_map2[exp_n2] == 12, "Wrong map value");
+ check(exp_edge_map1[exp_e1] == 21, "Wrong map value");
+ check(exp_edge_map2[exp_e1] == 21, "Wrong map value");
+ check(exp_arc_map1[exp_a1] == 212, "Wrong map value");
+ check(exp_arc_map2[exp_a1] == 212, "Wrong map value");
+ check(exp_attr1 == 100, "Wrong attr value");
+ check(exp_attr2 == 100, "Wrong attr value");
+}
+
+void checkBpGraphReaderWriter() {
+ typedef lemon::SmartBpGraph Graph;
+ Graph graph;
+ Graph::RedNode rn1 = graph.addRedNode();
+ Graph::RedNode rn2 = graph.addRedNode();
+ Graph::RedNode rn3 = graph.addRedNode();
+ Graph::BlueNode bn1 = graph.addBlueNode();
+ Graph::BlueNode bn2 = graph.addBlueNode();
+ Graph::Node n = bn1;
+
+ Graph::Edge e1 = graph.addEdge(rn1, bn1);
+ Graph::Edge e2 = graph.addEdge(rn2, bn1);
+
+ Graph::NodeMap<int> node_map(graph);
+ node_map[rn1] = 11;
+ node_map[rn2] = 12;
+ node_map[rn3] = 13;
+ node_map[bn1] = 14;
+ node_map[bn2] = 15;
+
+ Graph::NodeMap<int> red_node_map(graph);
+ red_node_map[rn1] = 411;
+ red_node_map[rn2] = 412;
+ red_node_map[rn3] = 413;
+
+ Graph::NodeMap<int> blue_node_map(graph);
+ blue_node_map[bn1] = 414;
+ blue_node_map[bn2] = 415;
+
+ Graph::EdgeMap<int> edge_map(graph);
+ edge_map[e1] = 21;
+ edge_map[e2] = 22;
+
+ Graph::ArcMap<int> arc_map(graph);
+ arc_map[graph.direct(e1, true)] = 211;
+ arc_map[graph.direct(e1, false)] = 212;
+ arc_map[graph.direct(e2, true)] = 221;
+ arc_map[graph.direct(e2, false)] = 222;
+
+ int attr = 100;
+
+ std::ostringstream os;
+ lemon::BpGraphWriter<Graph> writer(graph, os);
+
+ writer.nodeMap("node_map1", node_map);
+ writer.nodeMap("node_map2", node_map, WriterConverter());
+ writer.nodeMap("red_node_map1", red_node_map);
+ writer.nodeMap("red_node_map2", red_node_map, WriterConverter());
+ writer.nodeMap("blue_node_map1", blue_node_map);
+ writer.nodeMap("blue_node_map2", blue_node_map, WriterConverter());
+ writer.edgeMap("edge_map1", edge_map);
+ writer.edgeMap("edge_map2", edge_map, WriterConverter());
+ writer.arcMap("arc_map1", arc_map);
+ writer.arcMap("arc_map2", arc_map, WriterConverter());
+ writer.node("node", n);
+ writer.redNode("red_node", rn1);
+ writer.blueNode("blue_node", bn2);
+ writer.edge("edge", e1);
+ writer.arc("arc", graph.direct(e1, false));
+ writer.attribute("attr1", attr);
+ writer.attribute("attr2", attr, WriterConverter());
+
+ writer.run();
+
+ typedef lemon::ListBpGraph ExpGraph;
+ ExpGraph exp_graph;
+ ExpGraph::NodeMap<int> exp_node_map1(exp_graph);
+ ExpGraph::NodeMap<int> exp_node_map2(exp_graph);
+ ExpGraph::RedNodeMap<int> exp_red_node_map1(exp_graph);
+ ExpGraph::RedNodeMap<int> exp_red_node_map2(exp_graph);
+ ExpGraph::BlueNodeMap<int> exp_blue_node_map1(exp_graph);
+ ExpGraph::BlueNodeMap<int> exp_blue_node_map2(exp_graph);
+ ExpGraph::EdgeMap<int> exp_edge_map1(exp_graph);
+ ExpGraph::EdgeMap<int> exp_edge_map2(exp_graph);
+ ExpGraph::ArcMap<int> exp_arc_map1(exp_graph);
+ ExpGraph::ArcMap<int> exp_arc_map2(exp_graph);
+ ExpGraph::Node exp_n;
+ ExpGraph::RedNode exp_rn1;
+ ExpGraph::BlueNode exp_bn2;
+ ExpGraph::Edge exp_e1;
+ ExpGraph::Arc exp_a1;
+ int exp_attr1;
+ int exp_attr2;
+
+ std::istringstream is(os.str());
+ lemon::BpGraphReader<ExpGraph> reader(exp_graph, is);
+
+ reader.nodeMap("node_map1", exp_node_map1);
+ reader.nodeMap("node_map2", exp_node_map2, ReaderConverter());
+ reader.redNodeMap("red_node_map1", exp_red_node_map1);
+ reader.redNodeMap("red_node_map2", exp_red_node_map2, ReaderConverter());
+ reader.blueNodeMap("blue_node_map1", exp_blue_node_map1);
+ reader.blueNodeMap("blue_node_map2", exp_blue_node_map2, ReaderConverter());
+ reader.edgeMap("edge_map1", exp_edge_map1);
+ reader.edgeMap("edge_map2", exp_edge_map2, ReaderConverter());
+ reader.arcMap("arc_map1", exp_arc_map1);
+ reader.arcMap("arc_map2", exp_arc_map2, ReaderConverter());
+ reader.node("node", exp_n);
+ reader.redNode("red_node", exp_rn1);
+ reader.blueNode("blue_node", exp_bn2);
+ reader.edge("edge", exp_e1);
+ reader.arc("arc", exp_a1);
+ reader.attribute("attr1", exp_attr1);
+ reader.attribute("attr2", exp_attr2, ReaderConverter());
+
+ reader.run();
+
+ check(lemon::countNodes(exp_graph) == 5, "Wrong number of nodes");
+ check(lemon::countRedNodes(exp_graph) == 3, "Wrong number of red nodes");
+ check(lemon::countBlueNodes(exp_graph) == 2, "Wrong number of blue nodes");
+ check(lemon::countEdges(exp_graph) == 2, "Wrong number of edges");
+ check(lemon::countArcs(exp_graph) == 4, "Wrong number of arcs");
+ check(exp_node_map1[exp_n] == 14, "Wrong map value");
+ check(exp_node_map2[exp_n] == 14, "Wrong map value");
+ check(exp_red_node_map1[exp_rn1] == 411, "Wrong map value");
+ check(exp_red_node_map2[exp_rn1] == 411, "Wrong map value");
+ check(exp_blue_node_map1[exp_bn2] == 415, "Wrong map value");
+ check(exp_blue_node_map2[exp_bn2] == 415, "Wrong map value");
+ check(exp_edge_map1[exp_e1] == 21, "Wrong map value");
+ check(exp_edge_map2[exp_e1] == 21, "Wrong map value");
+ check(exp_arc_map1[exp_a1] == 212, "Wrong map value");
+ check(exp_arc_map2[exp_a1] == 212, "Wrong map value");
+ check(exp_attr1 == 100, "Wrong attr value");
+ check(exp_attr2 == 100, "Wrong attr value");
+}
+
+
+int main() {
+ { // Check digrpah
+ checkDigraphReaderWriter();
+ }
+ { // Check graph
+ checkGraphReaderWriter();
+ }
+ { // Check bipartite graph
+ checkBpGraphReaderWriter();
+ }
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/lgf_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/lgf_test.cc
new file mode 100644
index 00000000000..839afb15242
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/lgf_test.cc
@@ -0,0 +1,169 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <lemon/list_graph.h>
+#include <lemon/lgf_reader.h>
+#include "test_tools.h"
+
+using namespace lemon;
+
+char test_lgf[] =
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "@arcs\n"
+ " label\n"
+ "0 1 0\n"
+ "1 0 1\n"
+ "@attributes\n"
+ "source 0\n"
+ "target 1\n";
+
+char test_lgf_nomap[] =
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "@arcs\n"
+ " -\n"
+ "0 1\n";
+
+char test_lgf_bad1[] =
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "@arcs\n"
+ " - another\n"
+ "0 1\n";
+
+char test_lgf_bad2[] =
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "@arcs\n"
+ " label -\n"
+ "0 1\n";
+
+
+int main()
+{
+ {
+ ListDigraph d;
+ ListDigraph::Node s,t;
+ ListDigraph::ArcMap<int> label(d);
+ std::istringstream input(test_lgf);
+ digraphReader(d, input).
+ node("source", s).
+ node("target", t).
+ arcMap("label", label).
+ run();
+ check(countNodes(d) == 2,"There should be 2 nodes");
+ check(countArcs(d) == 2,"There should be 2 arcs");
+ }
+ {
+ ListGraph g;
+ ListGraph::Node s,t;
+ ListGraph::EdgeMap<int> label(g);
+ std::istringstream input(test_lgf);
+ graphReader(g, input).
+ node("source", s).
+ node("target", t).
+ edgeMap("label", label).
+ run();
+ check(countNodes(g) == 2,"There should be 2 nodes");
+ check(countEdges(g) == 2,"There should be 2 arcs");
+ }
+
+ {
+ ListDigraph d;
+ std::istringstream input(test_lgf_nomap);
+ digraphReader(d, input).
+ run();
+ check(countNodes(d) == 2,"There should be 2 nodes");
+ check(countArcs(d) == 1,"There should be 1 arc");
+ }
+ {
+ ListGraph g;
+ std::istringstream input(test_lgf_nomap);
+ graphReader(g, input).
+ run();
+ check(countNodes(g) == 2,"There should be 2 nodes");
+ check(countEdges(g) == 1,"There should be 1 edge");
+ }
+
+ {
+ ListDigraph d;
+ std::istringstream input(test_lgf_bad1);
+ bool ok=false;
+ try {
+ digraphReader(d, input).
+ run();
+ }
+ catch (FormatError&)
+ {
+ ok = true;
+ }
+ check(ok,"FormatError exception should have occured");
+ }
+ {
+ ListGraph g;
+ std::istringstream input(test_lgf_bad1);
+ bool ok=false;
+ try {
+ graphReader(g, input).
+ run();
+ }
+ catch (FormatError&)
+ {
+ ok = true;
+ }
+ check(ok,"FormatError exception should have occured");
+ }
+
+ {
+ ListDigraph d;
+ std::istringstream input(test_lgf_bad2);
+ bool ok=false;
+ try {
+ digraphReader(d, input).
+ run();
+ }
+ catch (FormatError&)
+ {
+ ok = true;
+ }
+ check(ok,"FormatError exception should have occured");
+ }
+ {
+ ListGraph g;
+ std::istringstream input(test_lgf_bad2);
+ bool ok=false;
+ try {
+ graphReader(g, input).
+ run();
+ }
+ catch (FormatError&)
+ {
+ ok = true;
+ }
+ check(ok,"FormatError exception should have occured");
+ }
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/lp_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/lp_test.cc
new file mode 100644
index 00000000000..914a37643df
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/lp_test.cc
@@ -0,0 +1,470 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <sstream>
+#include <lemon/lp_skeleton.h>
+#include "test_tools.h"
+#include <lemon/tolerance.h>
+
+#include <lemon/config.h>
+
+#ifdef LEMON_HAVE_GLPK
+#include <lemon/glpk.h>
+#endif
+
+#ifdef LEMON_HAVE_CPLEX
+#include <lemon/cplex.h>
+#endif
+
+#ifdef LEMON_HAVE_SOPLEX
+#include <lemon/soplex.h>
+#endif
+
+#ifdef LEMON_HAVE_CLP
+#include <lemon/clp.h>
+#endif
+
+#ifdef LEMON_HAVE_LP
+#include <lemon/lp.h>
+#endif
+using namespace lemon;
+
+int countCols(LpBase & lp) {
+ int count=0;
+ for (LpBase::ColIt c(lp); c!=INVALID; ++c) ++count;
+ return count;
+}
+
+int countRows(LpBase & lp) {
+ int count=0;
+ for (LpBase::RowIt r(lp); r!=INVALID; ++r) ++count;
+ return count;
+}
+
+
+void lpTest(LpSolver& lp)
+{
+
+ typedef LpSolver LP;
+
+ // Test LpBase::clear()
+ check(countRows(lp)==0, "Wrong number of rows");
+ check(countCols(lp)==0, "Wrong number of cols");
+ lp.addCol(); lp.addRow(); lp.addRow();
+ check(countRows(lp)==2, "Wrong number of rows");
+ check(countCols(lp)==1, "Wrong number of cols");
+ lp.clear();
+ check(countRows(lp)==0, "Wrong number of rows");
+ check(countCols(lp)==0, "Wrong number of cols");
+ lp.addCol(); lp.addCol(); lp.addCol(); lp.addRow();
+ check(countRows(lp)==1, "Wrong number of rows");
+ check(countCols(lp)==3, "Wrong number of cols");
+ lp.clear();
+
+ std::vector<LP::Col> x(10);
+ // for(int i=0;i<10;i++) x.push_back(lp.addCol());
+ lp.addColSet(x);
+ lp.colLowerBound(x,1);
+ lp.colUpperBound(x,1);
+ lp.colBounds(x,1,2);
+
+ std::vector<LP::Col> y(10);
+ lp.addColSet(y);
+
+ lp.colLowerBound(y,1);
+ lp.colUpperBound(y,1);
+ lp.colBounds(y,1,2);
+
+ std::map<int,LP::Col> z;
+
+ z.insert(std::make_pair(12,INVALID));
+ z.insert(std::make_pair(2,INVALID));
+ z.insert(std::make_pair(7,INVALID));
+ z.insert(std::make_pair(5,INVALID));
+
+ lp.addColSet(z);
+
+ lp.colLowerBound(z,1);
+ lp.colUpperBound(z,1);
+ lp.colBounds(z,1,2);
+
+ {
+ LP::Expr e,f,g;
+ LP::Col p1,p2,p3,p4,p5;
+ LP::Constr c;
+
+ p1=lp.addCol();
+ p2=lp.addCol();
+ p3=lp.addCol();
+ p4=lp.addCol();
+ p5=lp.addCol();
+
+ e[p1]=2;
+ *e=12;
+ e[p1]+=2;
+ *e+=12;
+ e[p1]-=2;
+ *e-=12;
+
+ e=2;
+ e=2.2;
+ e=p1;
+ e=f;
+
+ e+=2;
+ e+=2.2;
+ e+=p1;
+ e+=f;
+
+ e-=2;
+ e-=2.2;
+ e-=p1;
+ e-=f;
+
+ e*=2;
+ e*=2.2;
+ e/=2;
+ e/=2.2;
+
+ e=((p1+p2)+(p1-p2)+(p1+12)+(12+p1)+(p1-12)+(12-p1)+
+ (f+12)+(12+f)+(p1+f)+(f+p1)+(f+g)+
+ (f-12)+(12-f)+(p1-f)+(f-p1)+(f-g)+
+ 2.2*f+f*2.2+f/2.2+
+ 2*f+f*2+f/2+
+ 2.2*p1+p1*2.2+p1/2.2+
+ 2*p1+p1*2+p1/2
+ );
+
+
+ c = (e <= f );
+ c = (e <= 2.2);
+ c = (e <= 2 );
+ c = (e <= p1 );
+ c = (2.2<= f );
+ c = (2 <= f );
+ c = (p1 <= f );
+ c = (p1 <= p2 );
+ c = (p1 <= 2.2);
+ c = (p1 <= 2 );
+ c = (2.2<= p2 );
+ c = (2 <= p2 );
+
+ c = (e >= f );
+ c = (e >= 2.2);
+ c = (e >= 2 );
+ c = (e >= p1 );
+ c = (2.2>= f );
+ c = (2 >= f );
+ c = (p1 >= f );
+ c = (p1 >= p2 );
+ c = (p1 >= 2.2);
+ c = (p1 >= 2 );
+ c = (2.2>= p2 );
+ c = (2 >= p2 );
+
+ c = (e == f );
+ c = (e == 2.2);
+ c = (e == 2 );
+ c = (e == p1 );
+ c = (2.2== f );
+ c = (2 == f );
+ c = (p1 == f );
+ //c = (p1 == p2 );
+ c = (p1 == 2.2);
+ c = (p1 == 2 );
+ c = (2.2== p2 );
+ c = (2 == p2 );
+
+ c = ((2 <= e) <= 3);
+ c = ((2 <= p1) <= 3);
+
+ c = ((2 >= e) >= 3);
+ c = ((2 >= p1) >= 3);
+
+ { //Tests for #430
+ LP::Col v=lp.addCol();
+ LP::Constr c = v >= -3;
+ c = c <= 4;
+ LP::Constr c2;
+#if ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 3 )
+ c2 = ( -3 <= v ) <= 4;
+#else
+ c2 = -3 <= v <= 4;
+#endif
+
+ }
+
+ e[x[3]]=2;
+ e[x[3]]=4;
+ e[x[3]]=1;
+ *e=12;
+
+ lp.addRow(-LP::INF,e,23);
+ lp.addRow(-LP::INF,3.0*(x[1]+x[2]/2)-x[3],23);
+ lp.addRow(-LP::INF,3.0*(x[1]+x[2]*2-5*x[3]+12-x[4]/3)+2*x[4]-4,23);
+
+ lp.addRow(x[1]+x[3]<=x[5]-3);
+ lp.addRow((-7<=x[1]+x[3]-12)<=3);
+ lp.addRow(x[1]<=x[5]);
+
+ std::ostringstream buf;
+
+
+ e=((p1+p2)+(p1-0.99*p2));
+ //e.prettyPrint(std::cout);
+ //(e<=2).prettyPrint(std::cout);
+ double tolerance=0.001;
+ e.simplify(tolerance);
+ buf << "Coeff. of p2 should be 0.01";
+ check(e[p2]>0, buf.str());
+
+ tolerance=0.02;
+ e.simplify(tolerance);
+ buf << "Coeff. of p2 should be 0";
+ check(const_cast<const LpSolver::Expr&>(e)[p2]==0, buf.str());
+
+ //Test for clone/new
+ LP* lpnew = lp.newSolver();
+ LP* lpclone = lp.cloneSolver();
+ delete lpnew;
+ delete lpclone;
+
+ }
+
+ {
+ LP::DualExpr e,f,g;
+ LP::Row p1 = INVALID, p2 = INVALID;
+
+ e[p1]=2;
+ e[p1]+=2;
+ e[p1]-=2;
+
+ e=p1;
+ e=f;
+
+ e+=p1;
+ e+=f;
+
+ e-=p1;
+ e-=f;
+
+ e*=2;
+ e*=2.2;
+ e/=2;
+ e/=2.2;
+
+ e=((p1+p2)+(p1-p2)+
+ (p1+f)+(f+p1)+(f+g)+
+ (p1-f)+(f-p1)+(f-g)+
+ 2.2*f+f*2.2+f/2.2+
+ 2*f+f*2+f/2+
+ 2.2*p1+p1*2.2+p1/2.2+
+ 2*p1+p1*2+p1/2
+ );
+ }
+
+}
+
+void solveAndCheck(LpSolver& lp, LpSolver::ProblemType stat,
+ double exp_opt) {
+ using std::string;
+ lp.solve();
+
+ std::ostringstream buf;
+ buf << "PrimalType should be: " << int(stat) << int(lp.primalType());
+
+ check(lp.primalType()==stat, buf.str());
+
+ if (stat == LpSolver::OPTIMAL) {
+ std::ostringstream sbuf;
+ sbuf << "Wrong optimal value (" << lp.primal() <<") with "
+ << lp.solverName() <<"\n the right optimum is " << exp_opt;
+ check(std::abs(lp.primal()-exp_opt) < 1e-3, sbuf.str());
+ }
+}
+
+void aTest(LpSolver & lp)
+{
+ typedef LpSolver LP;
+
+ //The following example is very simple
+
+ typedef LpSolver::Row Row;
+ typedef LpSolver::Col Col;
+
+
+ Col x1 = lp.addCol();
+ Col x2 = lp.addCol();
+
+
+ //Constraints
+ Row upright=lp.addRow(x1+2*x2 <=1);
+ lp.addRow(x1+x2 >=-1);
+ lp.addRow(x1-x2 <=1);
+ lp.addRow(x1-x2 >=-1);
+ //Nonnegativity of the variables
+ lp.colLowerBound(x1, 0);
+ lp.colLowerBound(x2, 0);
+ //Objective function
+ lp.obj(x1+x2);
+
+ lp.sense(lp.MAX);
+
+ //Testing the problem retrieving routines
+ check(lp.objCoeff(x1)==1,"First term should be 1 in the obj function!");
+ check(lp.sense() == lp.MAX,"This is a maximization!");
+ check(lp.coeff(upright,x1)==1,"The coefficient in question is 1!");
+ check(lp.colLowerBound(x1)==0,
+ "The lower bound for variable x1 should be 0.");
+ check(lp.colUpperBound(x1)==LpSolver::INF,
+ "The upper bound for variable x1 should be infty.");
+ check(lp.rowLowerBound(upright) == -LpSolver::INF,
+ "The lower bound for the first row should be -infty.");
+ check(lp.rowUpperBound(upright)==1,
+ "The upper bound for the first row should be 1.");
+ LpSolver::Expr e = lp.row(upright);
+ check(e[x1] == 1, "The first coefficient should 1.");
+ check(e[x2] == 2, "The second coefficient should 1.");
+
+ lp.row(upright, x1+x2 <=1);
+ e = lp.row(upright);
+ check(e[x1] == 1, "The first coefficient should 1.");
+ check(e[x2] == 1, "The second coefficient should 1.");
+
+ LpSolver::DualExpr de = lp.col(x1);
+ check( de[upright] == 1, "The first coefficient should 1.");
+
+ LpSolver* clp = lp.cloneSolver();
+
+ //Testing the problem retrieving routines
+ check(clp->objCoeff(x1)==1,"First term should be 1 in the obj function!");
+ check(clp->sense() == clp->MAX,"This is a maximization!");
+ check(clp->coeff(upright,x1)==1,"The coefficient in question is 1!");
+ // std::cout<<lp.colLowerBound(x1)<<std::endl;
+ check(clp->colLowerBound(x1)==0,
+ "The lower bound for variable x1 should be 0.");
+ check(clp->colUpperBound(x1)==LpSolver::INF,
+ "The upper bound for variable x1 should be infty.");
+
+ check(lp.rowLowerBound(upright)==-LpSolver::INF,
+ "The lower bound for the first row should be -infty.");
+ check(lp.rowUpperBound(upright)==1,
+ "The upper bound for the first row should be 1.");
+ e = clp->row(upright);
+ check(e[x1] == 1, "The first coefficient should 1.");
+ check(e[x2] == 1, "The second coefficient should 1.");
+
+ de = clp->col(x1);
+ check(de[upright] == 1, "The first coefficient should 1.");
+
+ delete clp;
+
+ //Maximization of x1+x2
+ //over the triangle with vertices (0,0) (0,1) (1,0)
+ double expected_opt=1;
+ solveAndCheck(lp, LpSolver::OPTIMAL, expected_opt);
+
+ //Minimization
+ lp.sense(lp.MIN);
+ expected_opt=0;
+ solveAndCheck(lp, LpSolver::OPTIMAL, expected_opt);
+
+ //Vertex (-1,0) instead of (0,0)
+ lp.colLowerBound(x1, -LpSolver::INF);
+ expected_opt=-1;
+ solveAndCheck(lp, LpSolver::OPTIMAL, expected_opt);
+
+ //Erase one constraint and return to maximization
+ lp.erase(upright);
+ lp.sense(lp.MAX);
+ expected_opt=LpSolver::INF;
+ solveAndCheck(lp, LpSolver::UNBOUNDED, expected_opt);
+
+ //Infeasibilty
+ lp.addRow(x1+x2 <=-2);
+ solveAndCheck(lp, LpSolver::INFEASIBLE, expected_opt);
+
+}
+
+template<class LP>
+void cloneTest()
+{
+ //Test for clone/new
+
+ LP* lp = new LP();
+ LP* lpnew = lp->newSolver();
+ LP* lpclone = lp->cloneSolver();
+ delete lp;
+ delete lpnew;
+ delete lpclone;
+}
+
+int main()
+{
+ LpSkeleton lp_skel;
+ lpTest(lp_skel);
+
+#ifdef LEMON_HAVE_LP
+ {
+ Lp lp,lp2;
+ lpTest(lp);
+ aTest(lp2);
+ cloneTest<Lp>();
+ }
+#endif
+
+#ifdef LEMON_HAVE_GLPK
+ {
+ GlpkLp lp_glpk1,lp_glpk2;
+ lpTest(lp_glpk1);
+ aTest(lp_glpk2);
+ cloneTest<GlpkLp>();
+ }
+#endif
+
+#ifdef LEMON_HAVE_CPLEX
+ try {
+ CplexLp lp_cplex1,lp_cplex2;
+ lpTest(lp_cplex1);
+ aTest(lp_cplex2);
+ cloneTest<CplexLp>();
+ } catch (CplexEnv::LicenseError& error) {
+ check(false, error.what());
+ }
+#endif
+
+#ifdef LEMON_HAVE_SOPLEX
+ {
+ SoplexLp lp_soplex1,lp_soplex2;
+ lpTest(lp_soplex1);
+ aTest(lp_soplex2);
+ cloneTest<SoplexLp>();
+ }
+#endif
+
+#ifdef LEMON_HAVE_CLP
+ {
+ ClpLp lp_clp1,lp_clp2;
+ lpTest(lp_clp1);
+ aTest(lp_clp2);
+ cloneTest<ClpLp>();
+ }
+#endif
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/maps_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/maps_test.cc
new file mode 100644
index 00000000000..5502e046fde
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/maps_test.cc
@@ -0,0 +1,1022 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <deque>
+#include <set>
+
+#include <lemon/concept_check.h>
+#include <lemon/concepts/maps.h>
+#include <lemon/maps.h>
+#include <lemon/list_graph.h>
+#include <lemon/smart_graph.h>
+#include <lemon/adaptors.h>
+#include <lemon/dfs.h>
+#include <algorithm>
+
+#include "test_tools.h"
+
+using namespace lemon;
+using namespace lemon::concepts;
+
+struct A {};
+inline bool operator<(A, A) { return true; }
+struct B {};
+
+class C {
+ int _x;
+public:
+ C(int x) : _x(x) {}
+ int get() const { return _x; }
+};
+inline bool operator<(C c1, C c2) { return c1.get() < c2.get(); }
+inline bool operator==(C c1, C c2) { return c1.get() == c2.get(); }
+
+C createC(int x) { return C(x); }
+
+template <typename T>
+class Less {
+ T _t;
+public:
+ Less(T t): _t(t) {}
+ bool operator()(const T& t) const { return t < _t; }
+};
+
+class F {
+public:
+ typedef A argument_type;
+ typedef B result_type;
+
+ B operator()(const A&) const { return B(); }
+private:
+ F& operator=(const F&);
+};
+
+int func(A) { return 3; }
+
+int binc(int a, B) { return a+1; }
+
+template <typename T>
+class Sum {
+ T& _sum;
+public:
+ Sum(T& sum) : _sum(sum) {}
+ void operator()(const T& t) { _sum += t; }
+};
+
+typedef ReadMap<A, double> DoubleMap;
+typedef ReadWriteMap<A, double> DoubleWriteMap;
+typedef ReferenceMap<A, double, double&, const double&> DoubleRefMap;
+
+typedef ReadMap<A, bool> BoolMap;
+typedef ReadWriteMap<A, bool> BoolWriteMap;
+typedef ReferenceMap<A, bool, bool&, const bool&> BoolRefMap;
+
+int main()
+{
+ // Map concepts
+ checkConcept<ReadMap<A,B>, ReadMap<A,B> >();
+ checkConcept<ReadMap<A,C>, ReadMap<A,C> >();
+ checkConcept<WriteMap<A,B>, WriteMap<A,B> >();
+ checkConcept<WriteMap<A,C>, WriteMap<A,C> >();
+ checkConcept<ReadWriteMap<A,B>, ReadWriteMap<A,B> >();
+ checkConcept<ReadWriteMap<A,C>, ReadWriteMap<A,C> >();
+ checkConcept<ReferenceMap<A,B,B&,const B&>, ReferenceMap<A,B,B&,const B&> >();
+ checkConcept<ReferenceMap<A,C,C&,const C&>, ReferenceMap<A,C,C&,const C&> >();
+
+ // NullMap
+ {
+ checkConcept<ReadWriteMap<A,B>, NullMap<A,B> >();
+ NullMap<A,B> map1;
+ NullMap<A,B> map2 = map1;
+ ::lemon::ignore_unused_variable_warning(map2);
+ map1 = nullMap<A,B>();
+ }
+
+ // ConstMap
+ {
+ checkConcept<ReadWriteMap<A,B>, ConstMap<A,B> >();
+ checkConcept<ReadWriteMap<A,C>, ConstMap<A,C> >();
+ ConstMap<A,B> map1;
+ ConstMap<A,B> map2 = B();
+ ConstMap<A,B> map3 = map1;
+ ::lemon::ignore_unused_variable_warning(map2,map3);
+
+ map1 = constMap<A>(B());
+ map1 = constMap<A,B>();
+ map1.setAll(B());
+ ConstMap<A,C> map4(C(1));
+ ConstMap<A,C> map5 = map4;
+ ::lemon::ignore_unused_variable_warning(map5);
+
+ map4 = constMap<A>(C(2));
+ map4.setAll(C(3));
+
+ checkConcept<ReadWriteMap<A,int>, ConstMap<A,int> >();
+ check(constMap<A>(10)[A()] == 10, "Something is wrong with ConstMap");
+
+ checkConcept<ReadWriteMap<A,int>, ConstMap<A,Const<int,10> > >();
+ ConstMap<A,Const<int,10> > map6;
+ ConstMap<A,Const<int,10> > map7 = map6;
+ map6 = constMap<A,int,10>();
+ map7 = constMap<A,Const<int,10> >();
+ check(map6[A()] == 10 && map7[A()] == 10,
+ "Something is wrong with ConstMap");
+ }
+
+ // IdentityMap
+ {
+ checkConcept<ReadMap<A,A>, IdentityMap<A> >();
+ IdentityMap<A> map1;
+ IdentityMap<A> map2 = map1;
+ ::lemon::ignore_unused_variable_warning(map2);
+
+ map1 = identityMap<A>();
+
+ checkConcept<ReadMap<double,double>, IdentityMap<double> >();
+ check(identityMap<double>()[1.0] == 1.0 &&
+ identityMap<double>()[3.14] == 3.14,
+ "Something is wrong with IdentityMap");
+ }
+
+ // RangeMap
+ {
+ checkConcept<ReferenceMap<int,B,B&,const B&>, RangeMap<B> >();
+ RangeMap<B> map1;
+ RangeMap<B> map2(10);
+ RangeMap<B> map3(10,B());
+ RangeMap<B> map4 = map1;
+ RangeMap<B> map5 = rangeMap<B>();
+ RangeMap<B> map6 = rangeMap<B>(10);
+ RangeMap<B> map7 = rangeMap(10,B());
+
+ checkConcept< ReferenceMap<int, double, double&, const double&>,
+ RangeMap<double> >();
+ std::vector<double> v(10, 0);
+ v[5] = 100;
+ RangeMap<double> map8(v);
+ RangeMap<double> map9 = rangeMap(v);
+ check(map9.size() == 10 && map9[2] == 0 && map9[5] == 100,
+ "Something is wrong with RangeMap");
+ }
+
+ // SparseMap
+ {
+ checkConcept<ReferenceMap<A,B,B&,const B&>, SparseMap<A,B> >();
+ SparseMap<A,B> map1;
+ SparseMap<A,B> map2 = B();
+ SparseMap<A,B> map3 = sparseMap<A,B>();
+ SparseMap<A,B> map4 = sparseMap<A>(B());
+
+ checkConcept< ReferenceMap<double, int, int&, const int&>,
+ SparseMap<double, int> >();
+ std::map<double, int> m;
+ SparseMap<double, int> map5(m);
+ SparseMap<double, int> map6(m,10);
+ SparseMap<double, int> map7 = sparseMap(m);
+ SparseMap<double, int> map8 = sparseMap(m,10);
+
+ check(map5[1.0] == 0 && map5[3.14] == 0 &&
+ map6[1.0] == 10 && map6[3.14] == 10,
+ "Something is wrong with SparseMap");
+ map5[1.0] = map6[3.14] = 100;
+ check(map5[1.0] == 100 && map5[3.14] == 0 &&
+ map6[1.0] == 10 && map6[3.14] == 100,
+ "Something is wrong with SparseMap");
+ }
+
+ // ComposeMap
+ {
+ typedef ComposeMap<DoubleMap, ReadMap<B,A> > CompMap;
+ checkConcept<ReadMap<B,double>, CompMap>();
+ CompMap map1 = CompMap(DoubleMap(),ReadMap<B,A>());
+ ::lemon::ignore_unused_variable_warning(map1);
+ CompMap map2 = composeMap(DoubleMap(), ReadMap<B,A>());
+ ::lemon::ignore_unused_variable_warning(map2);
+
+ SparseMap<double, bool> m1(false); m1[3.14] = true;
+ RangeMap<double> m2(2); m2[0] = 3.0; m2[1] = 3.14;
+ check(!composeMap(m1,m2)[0] && composeMap(m1,m2)[1],
+ "Something is wrong with ComposeMap")
+ }
+
+ // CombineMap
+ {
+ typedef CombineMap<DoubleMap, DoubleMap, std::plus<double> > CombMap;
+ checkConcept<ReadMap<A,double>, CombMap>();
+ CombMap map1 = CombMap(DoubleMap(), DoubleMap());
+ ::lemon::ignore_unused_variable_warning(map1);
+ CombMap map2 = combineMap(DoubleMap(), DoubleMap(), std::plus<double>());
+ ::lemon::ignore_unused_variable_warning(map2);
+
+ check(combineMap(constMap<B,int,2>(), identityMap<B>(), &binc)[B()] == 3,
+ "Something is wrong with CombineMap");
+ }
+
+ // FunctorToMap, MapToFunctor
+ {
+ checkConcept<ReadMap<A,B>, FunctorToMap<F,A,B> >();
+ checkConcept<ReadMap<A,B>, FunctorToMap<F> >();
+ FunctorToMap<F> map1;
+ FunctorToMap<F> map2 = FunctorToMap<F>(F());
+ ::lemon::ignore_unused_variable_warning(map2);
+
+ B b = functorToMap(F())[A()];
+ ::lemon::ignore_unused_variable_warning(b);
+
+ checkConcept<ReadMap<A,B>, MapToFunctor<ReadMap<A,B> > >();
+ MapToFunctor<ReadMap<A,B> > map =
+ MapToFunctor<ReadMap<A,B> >(ReadMap<A,B>());
+ ::lemon::ignore_unused_variable_warning(map);
+
+ check(functorToMap(&func)[A()] == 3,
+ "Something is wrong with FunctorToMap");
+ check(mapToFunctor(constMap<A,int>(2))(A()) == 2,
+ "Something is wrong with MapToFunctor");
+ check(mapToFunctor(functorToMap(&func))(A()) == 3 &&
+ mapToFunctor(functorToMap(&func))[A()] == 3,
+ "Something is wrong with FunctorToMap or MapToFunctor");
+ check(functorToMap(mapToFunctor(constMap<A,int>(2)))[A()] == 2,
+ "Something is wrong with FunctorToMap or MapToFunctor");
+ }
+
+ // ConvertMap
+ {
+ checkConcept<ReadMap<double,double>,
+ ConvertMap<ReadMap<double, int>, double> >();
+ ConvertMap<RangeMap<bool>, int> map1(rangeMap(1, true));
+ ::lemon::ignore_unused_variable_warning(map1);
+ ConvertMap<RangeMap<bool>, int> map2 = convertMap<int>(rangeMap(2, false));
+ ::lemon::ignore_unused_variable_warning(map2);
+
+ }
+
+ // ForkMap
+ {
+ checkConcept<DoubleWriteMap, ForkMap<DoubleWriteMap, DoubleWriteMap> >();
+
+ typedef RangeMap<double> RM;
+ typedef SparseMap<int, double> SM;
+ RM m1(10, -1);
+ SM m2(-1);
+ checkConcept<ReadWriteMap<int, double>, ForkMap<RM, SM> >();
+ checkConcept<ReadWriteMap<int, double>, ForkMap<SM, RM> >();
+ ForkMap<RM, SM> map1(m1,m2);
+ ForkMap<SM, RM> map2 = forkMap(m2,m1);
+ map2.set(5, 10);
+ check(m1[1] == -1 && m1[5] == 10 && m2[1] == -1 &&
+ m2[5] == 10 && map2[1] == -1 && map2[5] == 10,
+ "Something is wrong with ForkMap");
+ }
+
+ // Arithmetic maps:
+ // - AddMap, SubMap, MulMap, DivMap
+ // - ShiftMap, ShiftWriteMap, ScaleMap, ScaleWriteMap
+ // - NegMap, NegWriteMap, AbsMap
+ {
+ checkConcept<DoubleMap, AddMap<DoubleMap,DoubleMap> >();
+ checkConcept<DoubleMap, SubMap<DoubleMap,DoubleMap> >();
+ checkConcept<DoubleMap, MulMap<DoubleMap,DoubleMap> >();
+ checkConcept<DoubleMap, DivMap<DoubleMap,DoubleMap> >();
+
+ ConstMap<int, double> c1(1.0), c2(3.14);
+ IdentityMap<int> im;
+ ConvertMap<IdentityMap<int>, double> id(im);
+ check(addMap(c1,id)[0] == 1.0 && addMap(c1,id)[10] == 11.0,
+ "Something is wrong with AddMap");
+ check(subMap(id,c1)[0] == -1.0 && subMap(id,c1)[10] == 9.0,
+ "Something is wrong with SubMap");
+ check(mulMap(id,c2)[0] == 0 && mulMap(id,c2)[2] == 6.28,
+ "Something is wrong with MulMap");
+ check(divMap(c2,id)[1] == 3.14 && divMap(c2,id)[2] == 1.57,
+ "Something is wrong with DivMap");
+
+ checkConcept<DoubleMap, ShiftMap<DoubleMap> >();
+ checkConcept<DoubleWriteMap, ShiftWriteMap<DoubleWriteMap> >();
+ checkConcept<DoubleMap, ScaleMap<DoubleMap> >();
+ checkConcept<DoubleWriteMap, ScaleWriteMap<DoubleWriteMap> >();
+ checkConcept<DoubleMap, NegMap<DoubleMap> >();
+ checkConcept<DoubleWriteMap, NegWriteMap<DoubleWriteMap> >();
+ checkConcept<DoubleMap, AbsMap<DoubleMap> >();
+
+ check(shiftMap(id, 2.0)[1] == 3.0 && shiftMap(id, 2.0)[10] == 12.0,
+ "Something is wrong with ShiftMap");
+ check(shiftWriteMap(id, 2.0)[1] == 3.0 &&
+ shiftWriteMap(id, 2.0)[10] == 12.0,
+ "Something is wrong with ShiftWriteMap");
+ check(scaleMap(id, 2.0)[1] == 2.0 && scaleMap(id, 2.0)[10] == 20.0,
+ "Something is wrong with ScaleMap");
+ check(scaleWriteMap(id, 2.0)[1] == 2.0 &&
+ scaleWriteMap(id, 2.0)[10] == 20.0,
+ "Something is wrong with ScaleWriteMap");
+ check(negMap(id)[1] == -1.0 && negMap(id)[-10] == 10.0,
+ "Something is wrong with NegMap");
+ check(negWriteMap(id)[1] == -1.0 && negWriteMap(id)[-10] == 10.0,
+ "Something is wrong with NegWriteMap");
+ check(absMap(id)[1] == 1.0 && absMap(id)[-10] == 10.0,
+ "Something is wrong with AbsMap");
+ }
+
+ // Logical maps:
+ // - TrueMap, FalseMap
+ // - AndMap, OrMap
+ // - NotMap, NotWriteMap
+ // - EqualMap, LessMap
+ {
+ checkConcept<BoolMap, TrueMap<A> >();
+ checkConcept<BoolMap, FalseMap<A> >();
+ checkConcept<BoolMap, AndMap<BoolMap,BoolMap> >();
+ checkConcept<BoolMap, OrMap<BoolMap,BoolMap> >();
+ checkConcept<BoolMap, NotMap<BoolMap> >();
+ checkConcept<BoolWriteMap, NotWriteMap<BoolWriteMap> >();
+ checkConcept<BoolMap, EqualMap<DoubleMap,DoubleMap> >();
+ checkConcept<BoolMap, LessMap<DoubleMap,DoubleMap> >();
+
+ TrueMap<int> tm;
+ FalseMap<int> fm;
+ RangeMap<bool> rm(2);
+ rm[0] = true; rm[1] = false;
+ check(andMap(tm,rm)[0] && !andMap(tm,rm)[1] &&
+ !andMap(fm,rm)[0] && !andMap(fm,rm)[1],
+ "Something is wrong with AndMap");
+ check(orMap(tm,rm)[0] && orMap(tm,rm)[1] &&
+ orMap(fm,rm)[0] && !orMap(fm,rm)[1],
+ "Something is wrong with OrMap");
+ check(!notMap(rm)[0] && notMap(rm)[1],
+ "Something is wrong with NotMap");
+ check(!notWriteMap(rm)[0] && notWriteMap(rm)[1],
+ "Something is wrong with NotWriteMap");
+
+ ConstMap<int, double> cm(2.0);
+ IdentityMap<int> im;
+ ConvertMap<IdentityMap<int>, double> id(im);
+ check(lessMap(id,cm)[1] && !lessMap(id,cm)[2] && !lessMap(id,cm)[3],
+ "Something is wrong with LessMap");
+ check(!equalMap(id,cm)[1] && equalMap(id,cm)[2] && !equalMap(id,cm)[3],
+ "Something is wrong with EqualMap");
+ }
+
+ // LoggerBoolMap
+ {
+ typedef std::vector<int> vec;
+ checkConcept<WriteMap<int, bool>, LoggerBoolMap<vec::iterator> >();
+ checkConcept<WriteMap<int, bool>,
+ LoggerBoolMap<std::back_insert_iterator<vec> > >();
+
+ vec v1;
+ vec v2(10);
+ LoggerBoolMap<std::back_insert_iterator<vec> >
+ map1(std::back_inserter(v1));
+ LoggerBoolMap<vec::iterator> map2(v2.begin());
+ map1.set(10, false);
+ map1.set(20, true); map2.set(20, true);
+ map1.set(30, false); map2.set(40, false);
+ map1.set(50, true); map2.set(50, true);
+ map1.set(60, true); map2.set(60, true);
+ check(v1.size() == 3 && v2.size() == 10 &&
+ v1[0]==20 && v1[1]==50 && v1[2]==60 &&
+ v2[0]==20 && v2[1]==50 && v2[2]==60,
+ "Something is wrong with LoggerBoolMap");
+
+ int i = 0;
+ for ( LoggerBoolMap<vec::iterator>::Iterator it = map2.begin();
+ it != map2.end(); ++it )
+ check(v1[i++] == *it, "Something is wrong with LoggerBoolMap");
+
+ typedef ListDigraph Graph;
+ DIGRAPH_TYPEDEFS(Graph);
+ Graph gr;
+
+ Node n0 = gr.addNode();
+ Node n1 = gr.addNode();
+ Node n2 = gr.addNode();
+ Node n3 = gr.addNode();
+
+ gr.addArc(n3, n0);
+ gr.addArc(n3, n2);
+ gr.addArc(n0, n2);
+ gr.addArc(n2, n1);
+ gr.addArc(n0, n1);
+
+ {
+ std::vector<Node> v;
+ dfs(gr).processedMap(loggerBoolMap(std::back_inserter(v))).run();
+
+ check(v.size()==4 && v[0]==n1 && v[1]==n2 && v[2]==n0 && v[3]==n3,
+ "Something is wrong with LoggerBoolMap");
+ }
+ {
+ std::vector<Node> v(countNodes(gr));
+ dfs(gr).processedMap(loggerBoolMap(v.begin())).run();
+
+ check(v.size()==4 && v[0]==n1 && v[1]==n2 && v[2]==n0 && v[3]==n3,
+ "Something is wrong with LoggerBoolMap");
+ }
+ }
+
+ // IdMap, RangeIdMap
+ {
+ typedef ListDigraph Graph;
+ DIGRAPH_TYPEDEFS(Graph);
+
+ checkConcept<ReadMap<Node, int>, IdMap<Graph, Node> >();
+ checkConcept<ReadMap<Arc, int>, IdMap<Graph, Arc> >();
+ checkConcept<ReadMap<Node, int>, RangeIdMap<Graph, Node> >();
+ checkConcept<ReadMap<Arc, int>, RangeIdMap<Graph, Arc> >();
+
+ Graph gr;
+ IdMap<Graph, Node> nmap(gr);
+ IdMap<Graph, Arc> amap(gr);
+ RangeIdMap<Graph, Node> nrmap(gr);
+ RangeIdMap<Graph, Arc> armap(gr);
+
+ Node n0 = gr.addNode();
+ Node n1 = gr.addNode();
+ Node n2 = gr.addNode();
+
+ Arc a0 = gr.addArc(n0, n1);
+ Arc a1 = gr.addArc(n0, n2);
+ Arc a2 = gr.addArc(n2, n1);
+ Arc a3 = gr.addArc(n2, n0);
+
+ check(nmap[n0] == gr.id(n0) && nmap(gr.id(n0)) == n0, "Wrong IdMap");
+ check(nmap[n1] == gr.id(n1) && nmap(gr.id(n1)) == n1, "Wrong IdMap");
+ check(nmap[n2] == gr.id(n2) && nmap(gr.id(n2)) == n2, "Wrong IdMap");
+
+ check(amap[a0] == gr.id(a0) && amap(gr.id(a0)) == a0, "Wrong IdMap");
+ check(amap[a1] == gr.id(a1) && amap(gr.id(a1)) == a1, "Wrong IdMap");
+ check(amap[a2] == gr.id(a2) && amap(gr.id(a2)) == a2, "Wrong IdMap");
+ check(amap[a3] == gr.id(a3) && amap(gr.id(a3)) == a3, "Wrong IdMap");
+
+ check(nmap.inverse()[gr.id(n0)] == n0, "Wrong IdMap::InverseMap");
+ check(amap.inverse()[gr.id(a0)] == a0, "Wrong IdMap::InverseMap");
+
+ check(nrmap.size() == 3 && armap.size() == 4,
+ "Wrong RangeIdMap::size()");
+
+ check(nrmap[n0] == 0 && nrmap(0) == n0, "Wrong RangeIdMap");
+ check(nrmap[n1] == 1 && nrmap(1) == n1, "Wrong RangeIdMap");
+ check(nrmap[n2] == 2 && nrmap(2) == n2, "Wrong RangeIdMap");
+
+ check(armap[a0] == 0 && armap(0) == a0, "Wrong RangeIdMap");
+ check(armap[a1] == 1 && armap(1) == a1, "Wrong RangeIdMap");
+ check(armap[a2] == 2 && armap(2) == a2, "Wrong RangeIdMap");
+ check(armap[a3] == 3 && armap(3) == a3, "Wrong RangeIdMap");
+
+ check(nrmap.inverse()[0] == n0, "Wrong RangeIdMap::InverseMap");
+ check(armap.inverse()[0] == a0, "Wrong RangeIdMap::InverseMap");
+
+ gr.erase(n1);
+
+ if (nrmap[n0] == 1) nrmap.swap(n0, n2);
+ nrmap.swap(n2, n0);
+ if (armap[a1] == 1) armap.swap(a1, a3);
+ armap.swap(a3, a1);
+
+ check(nrmap.size() == 2 && armap.size() == 2,
+ "Wrong RangeIdMap::size()");
+
+ check(nrmap[n0] == 1 && nrmap(1) == n0, "Wrong RangeIdMap");
+ check(nrmap[n2] == 0 && nrmap(0) == n2, "Wrong RangeIdMap");
+
+ check(armap[a1] == 1 && armap(1) == a1, "Wrong RangeIdMap");
+ check(armap[a3] == 0 && armap(0) == a3, "Wrong RangeIdMap");
+
+ check(nrmap.inverse()[0] == n2, "Wrong RangeIdMap::InverseMap");
+ check(armap.inverse()[0] == a3, "Wrong RangeIdMap::InverseMap");
+ }
+
+ // SourceMap, TargetMap, ForwardMap, BackwardMap, InDegMap, OutDegMap
+ {
+ typedef ListGraph Graph;
+ GRAPH_TYPEDEFS(Graph);
+
+ checkConcept<ReadMap<Arc, Node>, SourceMap<Graph> >();
+ checkConcept<ReadMap<Arc, Node>, TargetMap<Graph> >();
+ checkConcept<ReadMap<Edge, Arc>, ForwardMap<Graph> >();
+ checkConcept<ReadMap<Edge, Arc>, BackwardMap<Graph> >();
+ checkConcept<ReadMap<Node, int>, InDegMap<Graph> >();
+ checkConcept<ReadMap<Node, int>, OutDegMap<Graph> >();
+
+ Graph gr;
+ Node n0 = gr.addNode();
+ Node n1 = gr.addNode();
+ Node n2 = gr.addNode();
+
+ gr.addEdge(n0,n1);
+ gr.addEdge(n1,n2);
+ gr.addEdge(n0,n2);
+ gr.addEdge(n2,n1);
+ gr.addEdge(n1,n2);
+ gr.addEdge(n0,n1);
+
+ for (EdgeIt e(gr); e != INVALID; ++e) {
+ check(forwardMap(gr)[e] == gr.direct(e, true), "Wrong ForwardMap");
+ check(backwardMap(gr)[e] == gr.direct(e, false), "Wrong BackwardMap");
+ }
+
+ check(mapCompare(gr,
+ sourceMap(orienter(gr, constMap<Edge, bool>(true))),
+ targetMap(orienter(gr, constMap<Edge, bool>(false)))),
+ "Wrong SourceMap or TargetMap");
+
+ typedef Orienter<Graph, const ConstMap<Edge, bool> > Digraph;
+ ConstMap<Edge, bool> true_edge_map(true);
+ Digraph dgr(gr, true_edge_map);
+ OutDegMap<Digraph> odm(dgr);
+ InDegMap<Digraph> idm(dgr);
+
+ check(odm[n0] == 3 && odm[n1] == 2 && odm[n2] == 1, "Wrong OutDegMap");
+ check(idm[n0] == 0 && idm[n1] == 3 && idm[n2] == 3, "Wrong InDegMap");
+
+ gr.addEdge(n2, n0);
+
+ check(odm[n0] == 3 && odm[n1] == 2 && odm[n2] == 2, "Wrong OutDegMap");
+ check(idm[n0] == 1 && idm[n1] == 3 && idm[n2] == 3, "Wrong InDegMap");
+ }
+
+ // CrossRefMap
+ {
+ typedef ListDigraph Graph;
+ DIGRAPH_TYPEDEFS(Graph);
+
+ checkConcept<ReadWriteMap<Node, int>,
+ CrossRefMap<Graph, Node, int> >();
+ checkConcept<ReadWriteMap<Node, bool>,
+ CrossRefMap<Graph, Node, bool> >();
+ checkConcept<ReadWriteMap<Node, double>,
+ CrossRefMap<Graph, Node, double> >();
+
+ Graph gr;
+ typedef CrossRefMap<Graph, Node, char> CRMap;
+ CRMap map(gr);
+
+ Node n0 = gr.addNode();
+ Node n1 = gr.addNode();
+ Node n2 = gr.addNode();
+
+ map.set(n0, 'A');
+ map.set(n1, 'B');
+ map.set(n2, 'C');
+
+ check(map[n0] == 'A' && map('A') == n0 && map.inverse()['A'] == n0,
+ "Wrong CrossRefMap");
+ check(map[n1] == 'B' && map('B') == n1 && map.inverse()['B'] == n1,
+ "Wrong CrossRefMap");
+ check(map[n2] == 'C' && map('C') == n2 && map.inverse()['C'] == n2,
+ "Wrong CrossRefMap");
+ check(map.count('A') == 1 && map.count('B') == 1 && map.count('C') == 1,
+ "Wrong CrossRefMap::count()");
+
+ CRMap::ValueIt it = map.beginValue();
+ check(*it++ == 'A' && *it++ == 'B' && *it++ == 'C' &&
+ it == map.endValue(), "Wrong value iterator");
+
+ map.set(n2, 'A');
+
+ check(map[n0] == 'A' && map[n1] == 'B' && map[n2] == 'A',
+ "Wrong CrossRefMap");
+ check(map('A') == n0 && map.inverse()['A'] == n0, "Wrong CrossRefMap");
+ check(map('B') == n1 && map.inverse()['B'] == n1, "Wrong CrossRefMap");
+ check(map('C') == INVALID && map.inverse()['C'] == INVALID,
+ "Wrong CrossRefMap");
+ check(map.count('A') == 2 && map.count('B') == 1 && map.count('C') == 0,
+ "Wrong CrossRefMap::count()");
+
+ it = map.beginValue();
+ check(*it++ == 'A' && *it++ == 'A' && *it++ == 'B' &&
+ it == map.endValue(), "Wrong value iterator");
+
+ map.set(n0, 'C');
+
+ check(map[n0] == 'C' && map[n1] == 'B' && map[n2] == 'A',
+ "Wrong CrossRefMap");
+ check(map('A') == n2 && map.inverse()['A'] == n2, "Wrong CrossRefMap");
+ check(map('B') == n1 && map.inverse()['B'] == n1, "Wrong CrossRefMap");
+ check(map('C') == n0 && map.inverse()['C'] == n0, "Wrong CrossRefMap");
+ check(map.count('A') == 1 && map.count('B') == 1 && map.count('C') == 1,
+ "Wrong CrossRefMap::count()");
+
+ it = map.beginValue();
+ check(*it++ == 'A' && *it++ == 'B' && *it++ == 'C' &&
+ it == map.endValue(), "Wrong value iterator");
+ }
+
+ // CrossRefMap
+ {
+ typedef SmartDigraph Graph;
+ DIGRAPH_TYPEDEFS(Graph);
+
+ checkConcept<ReadWriteMap<Node, int>,
+ CrossRefMap<Graph, Node, int> >();
+
+ Graph gr;
+ typedef CrossRefMap<Graph, Node, char> CRMap;
+ typedef CRMap::ValueIterator ValueIt;
+ CRMap map(gr);
+
+ Node n0 = gr.addNode();
+ Node n1 = gr.addNode();
+ Node n2 = gr.addNode();
+
+ map.set(n0, 'A');
+ map.set(n1, 'B');
+ map.set(n2, 'C');
+ map.set(n2, 'A');
+ map.set(n0, 'C');
+
+ check(map[n0] == 'C' && map[n1] == 'B' && map[n2] == 'A',
+ "Wrong CrossRefMap");
+ check(map('A') == n2 && map.inverse()['A'] == n2, "Wrong CrossRefMap");
+ check(map('B') == n1 && map.inverse()['B'] == n1, "Wrong CrossRefMap");
+ check(map('C') == n0 && map.inverse()['C'] == n0, "Wrong CrossRefMap");
+
+ ValueIt it = map.beginValue();
+ check(*it++ == 'A' && *it++ == 'B' && *it++ == 'C' &&
+ it == map.endValue(), "Wrong value iterator");
+ }
+
+ // Iterable bool map
+ {
+ typedef SmartGraph Graph;
+ typedef SmartGraph::Node Item;
+
+ typedef IterableBoolMap<SmartGraph, SmartGraph::Node> Ibm;
+ checkConcept<ReferenceMap<Item, bool, bool&, const bool&>, Ibm>();
+
+ const int num = 10;
+ Graph g;
+ Ibm map0(g, true);
+ std::vector<Item> items;
+ for (int i = 0; i < num; ++i) {
+ items.push_back(g.addNode());
+ }
+
+ Ibm map1(g, true);
+ int n = 0;
+ for (Ibm::TrueIt it(map1); it != INVALID; ++it) {
+ check(map1[static_cast<Item>(it)], "Wrong TrueIt");
+ ++n;
+ }
+ check(n == num, "Wrong number");
+
+ n = 0;
+ for (Ibm::ItemIt it(map1, true); it != INVALID; ++it) {
+ check(map1[static_cast<Item>(it)], "Wrong ItemIt for true");
+ ++n;
+ }
+ check(n == num, "Wrong number");
+ check(Ibm::FalseIt(map1) == INVALID, "Wrong FalseIt");
+ check(Ibm::ItemIt(map1, false) == INVALID, "Wrong ItemIt for false");
+
+ map1[items[5]] = true;
+
+ n = 0;
+ for (Ibm::ItemIt it(map1, true); it != INVALID; ++it) {
+ check(map1[static_cast<Item>(it)], "Wrong ItemIt for true");
+ ++n;
+ }
+ check(n == num, "Wrong number");
+
+ map1[items[num / 2]] = false;
+ check(map1[items[num / 2]] == false, "Wrong map value");
+
+ n = 0;
+ for (Ibm::TrueIt it(map1); it != INVALID; ++it) {
+ check(map1[static_cast<Item>(it)], "Wrong TrueIt for true");
+ ++n;
+ }
+ check(n == num - 1, "Wrong number");
+
+ n = 0;
+ for (Ibm::FalseIt it(map1); it != INVALID; ++it) {
+ check(!map1[static_cast<Item>(it)], "Wrong FalseIt for true");
+ ++n;
+ }
+ check(n == 1, "Wrong number");
+
+ map1[items[0]] = false;
+ check(map1[items[0]] == false, "Wrong map value");
+
+ map1[items[num - 1]] = false;
+ check(map1[items[num - 1]] == false, "Wrong map value");
+
+ n = 0;
+ for (Ibm::TrueIt it(map1); it != INVALID; ++it) {
+ check(map1[static_cast<Item>(it)], "Wrong TrueIt for true");
+ ++n;
+ }
+ check(n == num - 3, "Wrong number");
+ check(map1.trueNum() == num - 3, "Wrong number");
+
+ n = 0;
+ for (Ibm::FalseIt it(map1); it != INVALID; ++it) {
+ check(!map1[static_cast<Item>(it)], "Wrong FalseIt for true");
+ ++n;
+ }
+ check(n == 3, "Wrong number");
+ check(map1.falseNum() == 3, "Wrong number");
+ }
+
+ // Iterable int map
+ {
+ typedef SmartGraph Graph;
+ typedef SmartGraph::Node Item;
+ typedef IterableIntMap<SmartGraph, SmartGraph::Node> Iim;
+
+ checkConcept<ReferenceMap<Item, int, int&, const int&>, Iim>();
+
+ const int num = 10;
+ Graph g;
+ Iim map0(g, 0);
+ std::vector<Item> items;
+ for (int i = 0; i < num; ++i) {
+ items.push_back(g.addNode());
+ }
+
+ Iim map1(g);
+ check(map1.size() == 0, "Wrong size");
+
+ for (int i = 0; i < num; ++i) {
+ map1[items[i]] = i;
+ }
+ check(map1.size() == num, "Wrong size");
+
+ for (int i = 0; i < num; ++i) {
+ Iim::ItemIt it(map1, i);
+ check(static_cast<Item>(it) == items[i], "Wrong value");
+ ++it;
+ check(static_cast<Item>(it) == INVALID, "Wrong value");
+ }
+
+ for (int i = 0; i < num; ++i) {
+ map1[items[i]] = i % 2;
+ }
+ check(map1.size() == 2, "Wrong size");
+
+ int n = 0;
+ for (Iim::ItemIt it(map1, 0); it != INVALID; ++it) {
+ check(map1[static_cast<Item>(it)] == 0, "Wrong value");
+ ++n;
+ }
+ check(n == (num + 1) / 2, "Wrong number");
+
+ for (Iim::ItemIt it(map1, 1); it != INVALID; ++it) {
+ check(map1[static_cast<Item>(it)] == 1, "Wrong value");
+ ++n;
+ }
+ check(n == num, "Wrong number");
+
+ }
+
+ // Iterable value map
+ {
+ typedef SmartGraph Graph;
+ typedef SmartGraph::Node Item;
+ typedef IterableValueMap<SmartGraph, SmartGraph::Node, double> Ivm;
+
+ checkConcept<ReadWriteMap<Item, double>, Ivm>();
+
+ const int num = 10;
+ Graph g;
+ Ivm map0(g, 0.0);
+ std::vector<Item> items;
+ for (int i = 0; i < num; ++i) {
+ items.push_back(g.addNode());
+ }
+
+ Ivm map1(g, 0.0);
+ check(distance(map1.beginValue(), map1.endValue()) == 1, "Wrong size");
+ check(*map1.beginValue() == 0.0, "Wrong value");
+
+ for (int i = 0; i < num; ++i) {
+ map1.set(items[i], static_cast<double>(i));
+ }
+ check(distance(map1.beginValue(), map1.endValue()) == num, "Wrong size");
+
+ for (int i = 0; i < num; ++i) {
+ Ivm::ItemIt it(map1, static_cast<double>(i));
+ check(static_cast<Item>(it) == items[i], "Wrong value");
+ ++it;
+ check(static_cast<Item>(it) == INVALID, "Wrong value");
+ }
+
+ for (Ivm::ValueIt vit = map1.beginValue();
+ vit != map1.endValue(); ++vit) {
+ check(map1[static_cast<Item>(Ivm::ItemIt(map1, *vit))] == *vit,
+ "Wrong ValueIt");
+ }
+
+ for (int i = 0; i < num; ++i) {
+ map1.set(items[i], static_cast<double>(i % 2));
+ }
+ check(distance(map1.beginValue(), map1.endValue()) == 2, "Wrong size");
+
+ int n = 0;
+ for (Ivm::ItemIt it(map1, 0.0); it != INVALID; ++it) {
+ check(map1[static_cast<Item>(it)] == 0.0, "Wrong value");
+ ++n;
+ }
+ check(n == (num + 1) / 2, "Wrong number");
+
+ for (Ivm::ItemIt it(map1, 1.0); it != INVALID; ++it) {
+ check(map1[static_cast<Item>(it)] == 1.0, "Wrong value");
+ ++n;
+ }
+ check(n == num, "Wrong number");
+
+ }
+
+ // Graph map utilities:
+ // mapMin(), mapMax(), mapMinValue(), mapMaxValue()
+ // mapFind(), mapFindIf(), mapCount(), mapCountIf()
+ // mapCopy(), mapCompare(), mapFill()
+ {
+ DIGRAPH_TYPEDEFS(SmartDigraph);
+
+ SmartDigraph g;
+ Node n1 = g.addNode();
+ Node n2 = g.addNode();
+ Node n3 = g.addNode();
+
+ SmartDigraph::NodeMap<int> map1(g);
+ SmartDigraph::ArcMap<char> map2(g);
+ ConstMap<Node, A> cmap1 = A();
+ ConstMap<Arc, C> cmap2 = C(0);
+
+ map1[n1] = 10;
+ map1[n2] = 5;
+ map1[n3] = 12;
+
+ // mapMin(), mapMax(), mapMinValue(), mapMaxValue()
+ check(mapMin(g, map1) == n2, "Wrong mapMin()");
+ check(mapMax(g, map1) == n3, "Wrong mapMax()");
+ check(mapMin(g, map1, std::greater<int>()) == n3, "Wrong mapMin()");
+ check(mapMax(g, map1, std::greater<int>()) == n2, "Wrong mapMax()");
+ check(mapMinValue(g, map1) == 5, "Wrong mapMinValue()");
+ check(mapMaxValue(g, map1) == 12, "Wrong mapMaxValue()");
+
+ check(mapMin(g, map2) == INVALID, "Wrong mapMin()");
+ check(mapMax(g, map2) == INVALID, "Wrong mapMax()");
+
+ check(mapMin(g, cmap1) != INVALID, "Wrong mapMin()");
+ check(mapMax(g, cmap2) == INVALID, "Wrong mapMax()");
+
+ Arc a1 = g.addArc(n1, n2);
+ Arc a2 = g.addArc(n1, n3);
+ Arc a3 = g.addArc(n2, n3);
+ Arc a4 = g.addArc(n3, n1);
+
+ map2[a1] = 'b';
+ map2[a2] = 'a';
+ map2[a3] = 'b';
+ map2[a4] = 'c';
+
+ // mapMin(), mapMax(), mapMinValue(), mapMaxValue()
+ check(mapMin(g, map2) == a2, "Wrong mapMin()");
+ check(mapMax(g, map2) == a4, "Wrong mapMax()");
+ check(mapMin(g, map2, std::greater<int>()) == a4, "Wrong mapMin()");
+ check(mapMax(g, map2, std::greater<int>()) == a2, "Wrong mapMax()");
+ check(mapMinValue(g, map2, std::greater<int>()) == 'c',
+ "Wrong mapMinValue()");
+ check(mapMaxValue(g, map2, std::greater<int>()) == 'a',
+ "Wrong mapMaxValue()");
+
+ check(mapMin(g, cmap1) != INVALID, "Wrong mapMin()");
+ check(mapMax(g, cmap2) != INVALID, "Wrong mapMax()");
+ check(mapMaxValue(g, cmap2) == C(0), "Wrong mapMaxValue()");
+
+ check(mapMin(g, composeMap(functorToMap(&createC), map2)) == a2,
+ "Wrong mapMin()");
+ check(mapMax(g, composeMap(functorToMap(&createC), map2)) == a4,
+ "Wrong mapMax()");
+ check(mapMinValue(g, composeMap(functorToMap(&createC), map2)) == C('a'),
+ "Wrong mapMinValue()");
+ check(mapMaxValue(g, composeMap(functorToMap(&createC), map2)) == C('c'),
+ "Wrong mapMaxValue()");
+
+ // mapFind(), mapFindIf()
+ check(mapFind(g, map1, 5) == n2, "Wrong mapFind()");
+ check(mapFind(g, map1, 6) == INVALID, "Wrong mapFind()");
+ check(mapFind(g, map2, 'a') == a2, "Wrong mapFind()");
+ check(mapFind(g, map2, 'e') == INVALID, "Wrong mapFind()");
+ check(mapFind(g, cmap2, C(0)) == ArcIt(g), "Wrong mapFind()");
+ check(mapFind(g, cmap2, C(1)) == INVALID, "Wrong mapFind()");
+
+ check(mapFindIf(g, map1, Less<int>(7)) == n2,
+ "Wrong mapFindIf()");
+ check(mapFindIf(g, map1, Less<int>(5)) == INVALID,
+ "Wrong mapFindIf()");
+ check(mapFindIf(g, map2, Less<char>('d')) == ArcIt(g),
+ "Wrong mapFindIf()");
+ check(mapFindIf(g, map2, Less<char>('a')) == INVALID,
+ "Wrong mapFindIf()");
+
+ // mapCount(), mapCountIf()
+ check(mapCount(g, map1, 5) == 1, "Wrong mapCount()");
+ check(mapCount(g, map1, 6) == 0, "Wrong mapCount()");
+ check(mapCount(g, map2, 'a') == 1, "Wrong mapCount()");
+ check(mapCount(g, map2, 'b') == 2, "Wrong mapCount()");
+ check(mapCount(g, map2, 'e') == 0, "Wrong mapCount()");
+ check(mapCount(g, cmap2, C(0)) == 4, "Wrong mapCount()");
+ check(mapCount(g, cmap2, C(1)) == 0, "Wrong mapCount()");
+
+ check(mapCountIf(g, map1, Less<int>(11)) == 2,
+ "Wrong mapCountIf()");
+ check(mapCountIf(g, map1, Less<int>(13)) == 3,
+ "Wrong mapCountIf()");
+ check(mapCountIf(g, map1, Less<int>(5)) == 0,
+ "Wrong mapCountIf()");
+ check(mapCountIf(g, map2, Less<char>('d')) == 4,
+ "Wrong mapCountIf()");
+ check(mapCountIf(g, map2, Less<char>('c')) == 3,
+ "Wrong mapCountIf()");
+ check(mapCountIf(g, map2, Less<char>('a')) == 0,
+ "Wrong mapCountIf()");
+
+ // MapIt, ConstMapIt
+/*
+These tests can be used after applying bugfix #330
+ typedef SmartDigraph::NodeMap<int>::MapIt MapIt;
+ typedef SmartDigraph::NodeMap<int>::ConstMapIt ConstMapIt;
+ check(*std::min_element(MapIt(map1), MapIt(INVALID)) == 5,
+ "Wrong NodeMap<>::MapIt");
+ check(*std::max_element(ConstMapIt(map1), ConstMapIt(INVALID)) == 12,
+ "Wrong NodeMap<>::MapIt");
+
+ int sum = 0;
+ std::for_each(MapIt(map1), MapIt(INVALID), Sum<int>(sum));
+ check(sum == 27, "Wrong NodeMap<>::MapIt");
+ std::for_each(ConstMapIt(map1), ConstMapIt(INVALID), Sum<int>(sum));
+ check(sum == 54, "Wrong NodeMap<>::ConstMapIt");
+*/
+
+ // mapCopy(), mapCompare(), mapFill()
+ check(mapCompare(g, map1, map1), "Wrong mapCompare()");
+ check(mapCompare(g, cmap2, cmap2), "Wrong mapCompare()");
+ check(mapCompare(g, map1, shiftMap(map1, 0)), "Wrong mapCompare()");
+ check(mapCompare(g, map2, scaleMap(map2, 1)), "Wrong mapCompare()");
+ check(!mapCompare(g, map1, shiftMap(map1, 1)), "Wrong mapCompare()");
+
+ SmartDigraph::NodeMap<int> map3(g, 0);
+ SmartDigraph::ArcMap<char> map4(g, 'a');
+
+ check(!mapCompare(g, map1, map3), "Wrong mapCompare()");
+ check(!mapCompare(g, map2, map4), "Wrong mapCompare()");
+
+ mapCopy(g, map1, map3);
+ mapCopy(g, map2, map4);
+
+ check(mapCompare(g, map1, map3), "Wrong mapCompare() or mapCopy()");
+ check(mapCompare(g, map2, map4), "Wrong mapCompare() or mapCopy()");
+
+ Undirector<SmartDigraph> ug(g);
+ Undirector<SmartDigraph>::EdgeMap<char> umap1(ug, 'x');
+ Undirector<SmartDigraph>::ArcMap<double> umap2(ug, 3.14);
+
+ check(!mapCompare(g, map2, umap1), "Wrong mapCompare() or mapCopy()");
+ check(!mapCompare(g, umap1, map2), "Wrong mapCompare() or mapCopy()");
+ check(!mapCompare(ug, map2, umap1), "Wrong mapCompare() or mapCopy()");
+ check(!mapCompare(ug, umap1, map2), "Wrong mapCompare() or mapCopy()");
+
+ mapCopy(g, map2, umap1);
+
+ check(mapCompare(g, map2, umap1), "Wrong mapCompare() or mapCopy()");
+ check(mapCompare(g, umap1, map2), "Wrong mapCompare() or mapCopy()");
+ check(mapCompare(ug, map2, umap1), "Wrong mapCompare() or mapCopy()");
+ check(mapCompare(ug, umap1, map2), "Wrong mapCompare() or mapCopy()");
+
+ mapCopy(g, map2, umap1);
+ mapCopy(g, umap1, map2);
+ mapCopy(ug, map2, umap1);
+ mapCopy(ug, umap1, map2);
+
+ check(!mapCompare(ug, umap1, umap2), "Wrong mapCompare() or mapCopy()");
+ mapCopy(ug, umap1, umap2);
+ check(mapCompare(ug, umap1, umap2), "Wrong mapCompare() or mapCopy()");
+
+ check(!mapCompare(g, map1, constMap<Node>(2)), "Wrong mapCompare()");
+ mapFill(g, map1, 2);
+ check(mapCompare(g, constMap<Node>(2), map1), "Wrong mapFill()");
+
+ check(!mapCompare(g, map2, constMap<Arc>('z')), "Wrong mapCompare()");
+ mapCopy(g, constMap<Arc>('z'), map2);
+ check(mapCompare(g, constMap<Arc>('z'), map2), "Wrong mapCopy()");
+ }
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/matching_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/matching_test.cc
new file mode 100644
index 00000000000..dcb1d3b5752
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/matching_test.cc
@@ -0,0 +1,449 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <iostream>
+#include <sstream>
+#include <vector>
+#include <queue>
+#include <cstdlib>
+
+#include <lemon/matching.h>
+#include <lemon/smart_graph.h>
+#include <lemon/concepts/graph.h>
+#include <lemon/concepts/maps.h>
+#include <lemon/lgf_reader.h>
+#include <lemon/math.h>
+
+#include "test_tools.h"
+
+using namespace std;
+using namespace lemon;
+
+GRAPH_TYPEDEFS(SmartGraph);
+
+
+const int lgfn = 3;
+const std::string lgf[lgfn] = {
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "5\n"
+ "6\n"
+ "7\n"
+ "@edges\n"
+ " label weight\n"
+ "7 4 0 984\n"
+ "0 7 1 73\n"
+ "7 1 2 204\n"
+ "2 3 3 583\n"
+ "2 7 4 565\n"
+ "2 1 5 582\n"
+ "0 4 6 551\n"
+ "2 5 7 385\n"
+ "1 5 8 561\n"
+ "5 3 9 484\n"
+ "7 5 10 904\n"
+ "3 6 11 47\n"
+ "7 6 12 888\n"
+ "3 0 13 747\n"
+ "6 1 14 310\n",
+
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "5\n"
+ "6\n"
+ "7\n"
+ "@edges\n"
+ " label weight\n"
+ "2 5 0 710\n"
+ "0 5 1 241\n"
+ "2 4 2 856\n"
+ "2 6 3 762\n"
+ "4 1 4 747\n"
+ "6 1 5 962\n"
+ "4 7 6 723\n"
+ "1 7 7 661\n"
+ "2 3 8 376\n"
+ "1 0 9 416\n"
+ "6 7 10 391\n",
+
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "5\n"
+ "6\n"
+ "7\n"
+ "@edges\n"
+ " label weight\n"
+ "6 2 0 553\n"
+ "0 7 1 653\n"
+ "6 3 2 22\n"
+ "4 7 3 846\n"
+ "7 2 4 981\n"
+ "7 6 5 250\n"
+ "5 2 6 539\n",
+};
+
+void checkMaxMatchingCompile()
+{
+ typedef concepts::Graph Graph;
+ typedef Graph::Node Node;
+ typedef Graph::Edge Edge;
+ typedef Graph::EdgeMap<bool> MatMap;
+
+ Graph g;
+ Node n;
+ Edge e;
+ MatMap mat(g);
+
+ MaxMatching<Graph> mat_test(g);
+ const MaxMatching<Graph>&
+ const_mat_test = mat_test;
+
+ mat_test.init();
+ mat_test.greedyInit();
+ mat_test.matchingInit(mat);
+ mat_test.startSparse();
+ mat_test.startDense();
+ mat_test.run();
+
+ const_mat_test.matchingSize();
+ const_mat_test.matching(e);
+ const_mat_test.matching(n);
+ const MaxMatching<Graph>::MatchingMap& mmap =
+ const_mat_test.matchingMap();
+ e = mmap[n];
+ const_mat_test.mate(n);
+
+ MaxMatching<Graph>::Status stat =
+ const_mat_test.status(n);
+ ::lemon::ignore_unused_variable_warning(stat);
+ const MaxMatching<Graph>::StatusMap& smap =
+ const_mat_test.statusMap();
+ stat = smap[n];
+ const_mat_test.barrier(n);
+}
+
+void checkMaxWeightedMatchingCompile()
+{
+ typedef concepts::Graph Graph;
+ typedef Graph::Node Node;
+ typedef Graph::Edge Edge;
+ typedef Graph::EdgeMap<int> WeightMap;
+
+ Graph g;
+ Node n;
+ Edge e;
+ WeightMap w(g);
+
+ MaxWeightedMatching<Graph> mat_test(g, w);
+ const MaxWeightedMatching<Graph>&
+ const_mat_test = mat_test;
+
+ mat_test.init();
+ mat_test.start();
+ mat_test.run();
+
+ const_mat_test.matchingWeight();
+ const_mat_test.matchingSize();
+ const_mat_test.matching(e);
+ const_mat_test.matching(n);
+ const MaxWeightedMatching<Graph>::MatchingMap& mmap =
+ const_mat_test.matchingMap();
+ e = mmap[n];
+ const_mat_test.mate(n);
+
+ int k = 0;
+ const_mat_test.dualValue();
+ const_mat_test.nodeValue(n);
+ const_mat_test.blossomNum();
+ const_mat_test.blossomSize(k);
+ const_mat_test.blossomValue(k);
+}
+
+void checkMaxWeightedPerfectMatchingCompile()
+{
+ typedef concepts::Graph Graph;
+ typedef Graph::Node Node;
+ typedef Graph::Edge Edge;
+ typedef Graph::EdgeMap<int> WeightMap;
+
+ Graph g;
+ Node n;
+ Edge e;
+ WeightMap w(g);
+
+ MaxWeightedPerfectMatching<Graph> mat_test(g, w);
+ const MaxWeightedPerfectMatching<Graph>&
+ const_mat_test = mat_test;
+
+ mat_test.init();
+ mat_test.start();
+ mat_test.run();
+
+ const_mat_test.matchingWeight();
+ const_mat_test.matching(e);
+ const_mat_test.matching(n);
+ const MaxWeightedPerfectMatching<Graph>::MatchingMap& mmap =
+ const_mat_test.matchingMap();
+ e = mmap[n];
+ const_mat_test.mate(n);
+
+ int k = 0;
+ const_mat_test.dualValue();
+ const_mat_test.nodeValue(n);
+ const_mat_test.blossomNum();
+ const_mat_test.blossomSize(k);
+ const_mat_test.blossomValue(k);
+}
+
+void checkMatching(const SmartGraph& graph,
+ const MaxMatching<SmartGraph>& mm) {
+ int num = 0;
+
+ IntNodeMap comp_index(graph);
+ UnionFind<IntNodeMap> comp(comp_index);
+
+ int barrier_num = 0;
+
+ for (NodeIt n(graph); n != INVALID; ++n) {
+ check(mm.status(n) == MaxMatching<SmartGraph>::EVEN ||
+ mm.matching(n) != INVALID, "Wrong Gallai-Edmonds decomposition");
+ if (mm.status(n) == MaxMatching<SmartGraph>::ODD) {
+ ++barrier_num;
+ } else {
+ comp.insert(n);
+ }
+ }
+
+ for (EdgeIt e(graph); e != INVALID; ++e) {
+ if (mm.matching(e)) {
+ check(e == mm.matching(graph.u(e)), "Wrong matching");
+ check(e == mm.matching(graph.v(e)), "Wrong matching");
+ ++num;
+ }
+ check(mm.status(graph.u(e)) != MaxMatching<SmartGraph>::EVEN ||
+ mm.status(graph.v(e)) != MaxMatching<SmartGraph>::MATCHED,
+ "Wrong Gallai-Edmonds decomposition");
+
+ check(mm.status(graph.v(e)) != MaxMatching<SmartGraph>::EVEN ||
+ mm.status(graph.u(e)) != MaxMatching<SmartGraph>::MATCHED,
+ "Wrong Gallai-Edmonds decomposition");
+
+ if (mm.status(graph.u(e)) != MaxMatching<SmartGraph>::ODD &&
+ mm.status(graph.v(e)) != MaxMatching<SmartGraph>::ODD) {
+ comp.join(graph.u(e), graph.v(e));
+ }
+ }
+
+ std::set<int> comp_root;
+ int odd_comp_num = 0;
+ for (NodeIt n(graph); n != INVALID; ++n) {
+ if (mm.status(n) != MaxMatching<SmartGraph>::ODD) {
+ int root = comp.find(n);
+ if (comp_root.find(root) == comp_root.end()) {
+ comp_root.insert(root);
+ if (comp.size(n) % 2 == 1) {
+ ++odd_comp_num;
+ }
+ }
+ }
+ }
+
+ check(mm.matchingSize() == num, "Wrong matching");
+ check(2 * num == countNodes(graph) - (odd_comp_num - barrier_num),
+ "Wrong matching");
+ return;
+}
+
+void checkWeightedMatching(const SmartGraph& graph,
+ const SmartGraph::EdgeMap<int>& weight,
+ const MaxWeightedMatching<SmartGraph>& mwm) {
+ for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
+ if (graph.u(e) == graph.v(e)) continue;
+ int rw = mwm.nodeValue(graph.u(e)) + mwm.nodeValue(graph.v(e));
+
+ for (int i = 0; i < mwm.blossomNum(); ++i) {
+ bool s = false, t = false;
+ for (MaxWeightedMatching<SmartGraph>::BlossomIt n(mwm, i);
+ n != INVALID; ++n) {
+ if (graph.u(e) == n) s = true;
+ if (graph.v(e) == n) t = true;
+ }
+ if (s == true && t == true) {
+ rw += mwm.blossomValue(i);
+ }
+ }
+ rw -= weight[e] * mwm.dualScale;
+
+ check(rw >= 0, "Negative reduced weight");
+ check(rw == 0 || !mwm.matching(e),
+ "Non-zero reduced weight on matching edge");
+ }
+
+ int pv = 0;
+ for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
+ if (mwm.matching(n) != INVALID) {
+ check(mwm.nodeValue(n) >= 0, "Invalid node value");
+ pv += weight[mwm.matching(n)];
+ SmartGraph::Node o = graph.target(mwm.matching(n));
+ check(mwm.mate(n) == o, "Invalid matching");
+ check(mwm.matching(n) == graph.oppositeArc(mwm.matching(o)),
+ "Invalid matching");
+ } else {
+ check(mwm.mate(n) == INVALID, "Invalid matching");
+ check(mwm.nodeValue(n) == 0, "Invalid matching");
+ }
+ }
+
+ int dv = 0;
+ for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
+ dv += mwm.nodeValue(n);
+ }
+
+ for (int i = 0; i < mwm.blossomNum(); ++i) {
+ check(mwm.blossomValue(i) >= 0, "Invalid blossom value");
+ check(mwm.blossomSize(i) % 2 == 1, "Even blossom size");
+ dv += mwm.blossomValue(i) * ((mwm.blossomSize(i) - 1) / 2);
+ }
+
+ check(pv * mwm.dualScale == dv * 2, "Wrong duality");
+
+ return;
+}
+
+void checkWeightedPerfectMatching(const SmartGraph& graph,
+ const SmartGraph::EdgeMap<int>& weight,
+ const MaxWeightedPerfectMatching<SmartGraph>& mwpm) {
+ for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
+ if (graph.u(e) == graph.v(e)) continue;
+ int rw = mwpm.nodeValue(graph.u(e)) + mwpm.nodeValue(graph.v(e));
+
+ for (int i = 0; i < mwpm.blossomNum(); ++i) {
+ bool s = false, t = false;
+ for (MaxWeightedPerfectMatching<SmartGraph>::BlossomIt n(mwpm, i);
+ n != INVALID; ++n) {
+ if (graph.u(e) == n) s = true;
+ if (graph.v(e) == n) t = true;
+ }
+ if (s == true && t == true) {
+ rw += mwpm.blossomValue(i);
+ }
+ }
+ rw -= weight[e] * mwpm.dualScale;
+
+ check(rw >= 0, "Negative reduced weight");
+ check(rw == 0 || !mwpm.matching(e),
+ "Non-zero reduced weight on matching edge");
+ }
+
+ int pv = 0;
+ for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
+ check(mwpm.matching(n) != INVALID, "Non perfect");
+ pv += weight[mwpm.matching(n)];
+ SmartGraph::Node o = graph.target(mwpm.matching(n));
+ check(mwpm.mate(n) == o, "Invalid matching");
+ check(mwpm.matching(n) == graph.oppositeArc(mwpm.matching(o)),
+ "Invalid matching");
+ }
+
+ int dv = 0;
+ for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
+ dv += mwpm.nodeValue(n);
+ }
+
+ for (int i = 0; i < mwpm.blossomNum(); ++i) {
+ check(mwpm.blossomValue(i) >= 0, "Invalid blossom value");
+ check(mwpm.blossomSize(i) % 2 == 1, "Even blossom size");
+ dv += mwpm.blossomValue(i) * ((mwpm.blossomSize(i) - 1) / 2);
+ }
+
+ check(pv * mwpm.dualScale == dv * 2, "Wrong duality");
+
+ return;
+}
+
+
+int main() {
+
+ for (int i = 0; i < lgfn; ++i) {
+ SmartGraph graph;
+ SmartGraph::EdgeMap<int> weight(graph);
+
+ istringstream lgfs(lgf[i]);
+ graphReader(graph, lgfs).
+ edgeMap("weight", weight).run();
+
+ bool perfect;
+ {
+ MaxMatching<SmartGraph> mm(graph);
+ mm.run();
+ checkMatching(graph, mm);
+ perfect = 2 * mm.matchingSize() == countNodes(graph);
+ }
+
+ {
+ MaxWeightedMatching<SmartGraph> mwm(graph, weight);
+ mwm.run();
+ checkWeightedMatching(graph, weight, mwm);
+ }
+
+ {
+ MaxWeightedMatching<SmartGraph> mwm(graph, weight);
+ mwm.init();
+ mwm.start();
+ checkWeightedMatching(graph, weight, mwm);
+ }
+
+ {
+ MaxWeightedPerfectMatching<SmartGraph> mwpm(graph, weight);
+ bool result = mwpm.run();
+
+ check(result == perfect, "Perfect matching found");
+ if (perfect) {
+ checkWeightedPerfectMatching(graph, weight, mwpm);
+ }
+ }
+
+ {
+ MaxWeightedPerfectMatching<SmartGraph> mwpm(graph, weight);
+ mwpm.init();
+ bool result = mwpm.start();
+
+ check(result == perfect, "Perfect matching found");
+ if (perfect) {
+ checkWeightedPerfectMatching(graph, weight, mwpm);
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/max_cardinality_search_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/max_cardinality_search_test.cc
new file mode 100644
index 00000000000..c01066f36e7
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/max_cardinality_search_test.cc
@@ -0,0 +1,162 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <iostream>
+
+#include "test_tools.h"
+#include <lemon/smart_graph.h>
+#include <lemon/max_cardinality_search.h>
+#include <lemon/concepts/digraph.h>
+#include <lemon/concepts/maps.h>
+#include <lemon/concepts/heap.h>
+#include <lemon/lgf_reader.h>
+
+using namespace lemon;
+using namespace std;
+
+char test_lgf[] =
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "@arcs\n"
+ " label capacity\n"
+ "0 1 0 2\n"
+ "1 0 1 2\n"
+ "2 1 2 1\n"
+ "2 3 3 3\n"
+ "3 2 4 3\n"
+ "3 1 5 5\n"
+ "@attributes\n"
+ "s 0\n"
+ "x 1\n"
+ "y 2\n"
+ "z 3\n";
+
+void checkMaxCardSearchCompile() {
+
+ typedef concepts::Digraph Digraph;
+ typedef int Value;
+ typedef Digraph::Node Node;
+ typedef Digraph::Arc Arc;
+ typedef concepts::ReadMap<Arc,Value> CapMap;
+ typedef concepts::ReadWriteMap<Node,Value> CardMap;
+ typedef concepts::ReadWriteMap<Node,bool> ProcMap;
+ typedef Digraph::NodeMap<int> HeapCrossRef;
+
+ Digraph g;
+ Node n,s;
+ CapMap cap;
+ CardMap card;
+ ProcMap proc;
+ HeapCrossRef crossref(g);
+
+ typedef MaxCardinalitySearch<Digraph,CapMap>
+ ::SetCapacityMap<CapMap>
+ ::SetCardinalityMap<CardMap>
+ ::SetProcessedMap<ProcMap>
+ ::SetStandardHeap<BinHeap<Value,HeapCrossRef> >
+ ::Create MaxCardType;
+
+ MaxCardType maxcard(g,cap);
+ const MaxCardType& const_maxcard = maxcard;
+
+ const MaxCardType::Heap& heap_const = const_maxcard.heap();
+ MaxCardType::Heap& heap = const_cast<MaxCardType::Heap&>(heap_const);
+ maxcard.heap(heap,crossref);
+
+ maxcard.capacityMap(cap).cardinalityMap(card).processedMap(proc);
+
+ maxcard.init();
+ maxcard.addSource(s);
+ n = maxcard.nextNode();
+ maxcard.processNextNode();
+ maxcard.start();
+ maxcard.run(s);
+ maxcard.run();
+ }
+
+ void checkWithIntMap( std::istringstream& input)
+ {
+ typedef SmartDigraph Digraph;
+ typedef Digraph::Node Node;
+ typedef Digraph::ArcMap<int> CapMap;
+
+ Digraph g;
+ Node s,x,y,z,a;
+ CapMap cap(g);
+
+ DigraphReader<Digraph>(g,input).
+ arcMap("capacity", cap).
+ node("s",s).
+ node("x",x).
+ node("y",y).
+ node("z",z).
+ run();
+
+ MaxCardinalitySearch<Digraph,CapMap> maxcard(g,cap);
+
+ maxcard.init();
+ maxcard.addSource(s);
+ maxcard.start(x);
+
+ check(maxcard.processed(s) && !maxcard.processed(x) &&
+ !maxcard.processed(y), "Wrong processed()!");
+
+ a=maxcard.nextNode();
+ check(maxcard.processNextNode()==a,
+ "Wrong nextNode() or processNextNode() return value!");
+
+ check(maxcard.processed(a), "Wrong processNextNode()!");
+
+ maxcard.start();
+ check(maxcard.cardinality(x)==2 && maxcard.cardinality(y)>=4,
+ "Wrong cardinalities!");
+ }
+
+ void checkWithConst1Map(std::istringstream &input) {
+ typedef SmartDigraph Digraph;
+ typedef Digraph::Node Node;
+
+ Digraph g;
+ Node s,x,y,z;
+
+ DigraphReader<Digraph>(g,input).
+ node("s",s).
+ node("x",x).
+ node("y",y).
+ node("z",z).
+ run();
+
+ MaxCardinalitySearch<Digraph> maxcard(g);
+ maxcard.run(s);
+ check(maxcard.cardinality(x)==1 &&
+ maxcard.cardinality(y)+maxcard.cardinality(z)==3,
+ "Wrong cardinalities!");
+}
+
+int main() {
+
+ std::istringstream input1(test_lgf);
+ checkWithIntMap(input1);
+
+ std::istringstream input2(test_lgf);
+ checkWithConst1Map(input2);
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/max_clique_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/max_clique_test.cc
new file mode 100644
index 00000000000..d16f0f99072
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/max_clique_test.cc
@@ -0,0 +1,188 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <sstream>
+#include <lemon/list_graph.h>
+#include <lemon/full_graph.h>
+#include <lemon/grid_graph.h>
+#include <lemon/lgf_reader.h>
+#include <lemon/grosso_locatelli_pullan_mc.h>
+
+#include "test_tools.h"
+
+using namespace lemon;
+
+char test_lgf[] =
+ "@nodes\n"
+ "label max_clique\n"
+ "1 0\n"
+ "2 0\n"
+ "3 0\n"
+ "4 1\n"
+ "5 1\n"
+ "6 1\n"
+ "7 1\n"
+ "@edges\n"
+ " label\n"
+ "1 2 1\n"
+ "1 3 2\n"
+ "1 4 3\n"
+ "1 6 4\n"
+ "2 3 5\n"
+ "2 5 6\n"
+ "2 7 7\n"
+ "3 4 8\n"
+ "3 5 9\n"
+ "4 5 10\n"
+ "4 6 11\n"
+ "4 7 12\n"
+ "5 6 13\n"
+ "5 7 14\n"
+ "6 7 15\n";
+
+
+// Check with general graphs
+template <typename Param>
+void checkMaxCliqueGeneral(Param rule) {
+ typedef ListGraph GR;
+ typedef GrossoLocatelliPullanMc<GR> McAlg;
+ typedef McAlg::CliqueNodeIt CliqueIt;
+
+ // Basic tests
+ {
+ GR g;
+ GR::NodeMap<bool> map(g);
+ McAlg mc(g);
+ mc.iterationLimit(50);
+ check(mc.run(rule) == McAlg::SIZE_LIMIT, "Wrong termination cause");
+ check(mc.cliqueSize() == 0, "Wrong clique size");
+ check(CliqueIt(mc) == INVALID, "Wrong CliqueNodeIt");
+
+ GR::Node u = g.addNode();
+ check(mc.run(rule) == McAlg::SIZE_LIMIT, "Wrong termination cause");
+ check(mc.cliqueSize() == 1, "Wrong clique size");
+ mc.cliqueMap(map);
+ check(map[u], "Wrong clique map");
+ CliqueIt it1(mc);
+ check(static_cast<GR::Node>(it1) == u && ++it1 == INVALID,
+ "Wrong CliqueNodeIt");
+
+ GR::Node v = g.addNode();
+ check(mc.run(rule) == McAlg::ITERATION_LIMIT, "Wrong termination cause");
+ check(mc.cliqueSize() == 1, "Wrong clique size");
+ mc.cliqueMap(map);
+ check((map[u] && !map[v]) || (map[v] && !map[u]), "Wrong clique map");
+ CliqueIt it2(mc);
+ check(it2 != INVALID && ++it2 == INVALID, "Wrong CliqueNodeIt");
+
+ g.addEdge(u, v);
+ check(mc.run(rule) == McAlg::SIZE_LIMIT, "Wrong termination cause");
+ check(mc.cliqueSize() == 2, "Wrong clique size");
+ mc.cliqueMap(map);
+ check(map[u] && map[v], "Wrong clique map");
+ CliqueIt it3(mc);
+ check(it3 != INVALID && ++it3 != INVALID && ++it3 == INVALID,
+ "Wrong CliqueNodeIt");
+ }
+
+ // Test graph
+ {
+ GR g;
+ GR::NodeMap<bool> max_clique(g);
+ GR::NodeMap<bool> map(g);
+ std::istringstream input(test_lgf);
+ graphReader(g, input)
+ .nodeMap("max_clique", max_clique)
+ .run();
+
+ McAlg mc(g);
+ mc.iterationLimit(50);
+ check(mc.run(rule) == McAlg::ITERATION_LIMIT, "Wrong termination cause");
+ check(mc.cliqueSize() == 4, "Wrong clique size");
+ mc.cliqueMap(map);
+ for (GR::NodeIt n(g); n != INVALID; ++n) {
+ check(map[n] == max_clique[n], "Wrong clique map");
+ }
+ int cnt = 0;
+ for (CliqueIt n(mc); n != INVALID; ++n) {
+ cnt++;
+ check(map[n] && max_clique[n], "Wrong CliqueNodeIt");
+ }
+ check(cnt == 4, "Wrong CliqueNodeIt");
+ }
+}
+
+// Check with full graphs
+template <typename Param>
+void checkMaxCliqueFullGraph(Param rule) {
+ typedef FullGraph GR;
+ typedef GrossoLocatelliPullanMc<FullGraph> McAlg;
+ typedef McAlg::CliqueNodeIt CliqueIt;
+
+ for (int size = 0; size <= 40; size = size * 3 + 1) {
+ GR g(size);
+ GR::NodeMap<bool> map(g);
+ McAlg mc(g);
+ check(mc.run(rule) == McAlg::SIZE_LIMIT, "Wrong termination cause");
+ check(mc.cliqueSize() == size, "Wrong clique size");
+ mc.cliqueMap(map);
+ for (GR::NodeIt n(g); n != INVALID; ++n) {
+ check(map[n], "Wrong clique map");
+ }
+ int cnt = 0;
+ for (CliqueIt n(mc); n != INVALID; ++n) cnt++;
+ check(cnt == size, "Wrong CliqueNodeIt");
+ }
+}
+
+// Check with grid graphs
+template <typename Param>
+void checkMaxCliqueGridGraph(Param rule) {
+ GridGraph g(5, 7);
+ GridGraph::NodeMap<char> map(g);
+ GrossoLocatelliPullanMc<GridGraph> mc(g);
+
+ mc.iterationLimit(100);
+ check(mc.run(rule) == mc.ITERATION_LIMIT, "Wrong termination cause");
+ check(mc.cliqueSize() == 2, "Wrong clique size");
+
+ mc.stepLimit(100);
+ check(mc.run(rule) == mc.STEP_LIMIT, "Wrong termination cause");
+ check(mc.cliqueSize() == 2, "Wrong clique size");
+
+ mc.sizeLimit(2);
+ check(mc.run(rule) == mc.SIZE_LIMIT, "Wrong termination cause");
+ check(mc.cliqueSize() == 2, "Wrong clique size");
+}
+
+
+int main() {
+ checkMaxCliqueGeneral(GrossoLocatelliPullanMc<ListGraph>::RANDOM);
+ checkMaxCliqueGeneral(GrossoLocatelliPullanMc<ListGraph>::DEGREE_BASED);
+ checkMaxCliqueGeneral(GrossoLocatelliPullanMc<ListGraph>::PENALTY_BASED);
+
+ checkMaxCliqueFullGraph(GrossoLocatelliPullanMc<FullGraph>::RANDOM);
+ checkMaxCliqueFullGraph(GrossoLocatelliPullanMc<FullGraph>::DEGREE_BASED);
+ checkMaxCliqueFullGraph(GrossoLocatelliPullanMc<FullGraph>::PENALTY_BASED);
+
+ checkMaxCliqueGridGraph(GrossoLocatelliPullanMc<GridGraph>::RANDOM);
+ checkMaxCliqueGridGraph(GrossoLocatelliPullanMc<GridGraph>::DEGREE_BASED);
+ checkMaxCliqueGridGraph(GrossoLocatelliPullanMc<GridGraph>::PENALTY_BASED);
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/max_flow_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/max_flow_test.cc
new file mode 100644
index 00000000000..f63874a615a
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/max_flow_test.cc
@@ -0,0 +1,395 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <iostream>
+
+#include "test_tools.h"
+#include <lemon/smart_graph.h>
+#include <lemon/preflow.h>
+#include <lemon/edmonds_karp.h>
+#include <lemon/concepts/digraph.h>
+#include <lemon/concepts/maps.h>
+#include <lemon/lgf_reader.h>
+#include <lemon/elevator.h>
+
+using namespace lemon;
+
+char test_lgf[] =
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "5\n"
+ "6\n"
+ "7\n"
+ "8\n"
+ "9\n"
+ "@arcs\n"
+ " label capacity\n"
+ "0 1 0 20\n"
+ "0 2 1 0\n"
+ "1 1 2 3\n"
+ "1 2 3 8\n"
+ "1 3 4 8\n"
+ "2 5 5 5\n"
+ "3 2 6 5\n"
+ "3 5 7 5\n"
+ "3 6 8 5\n"
+ "4 3 9 3\n"
+ "5 7 10 3\n"
+ "5 6 11 10\n"
+ "5 8 12 10\n"
+ "6 8 13 8\n"
+ "8 9 14 20\n"
+ "8 1 15 5\n"
+ "9 5 16 5\n"
+ "@attributes\n"
+ "source 1\n"
+ "target 8\n";
+
+
+// Checks the general interface of a max flow algorithm
+template <typename GR, typename CAP>
+struct MaxFlowClassConcept
+{
+
+ template <typename MF>
+ struct Constraints {
+
+ typedef typename GR::Node Node;
+ typedef typename GR::Arc Arc;
+ typedef typename CAP::Value Value;
+ typedef concepts::ReadWriteMap<Arc, Value> FlowMap;
+ typedef concepts::WriteMap<Node, bool> CutMap;
+
+ GR g;
+ Node n;
+ Arc e;
+ CAP cap;
+ FlowMap flow;
+ CutMap cut;
+ Value v;
+ bool b;
+
+ void constraints() {
+ checkConcept<concepts::Digraph, GR>();
+
+ const Constraints& me = *this;
+
+ typedef typename MF
+ ::template SetFlowMap<FlowMap>
+ ::Create MaxFlowType;
+ typedef typename MF::Create MaxFlowType2;
+ MaxFlowType max_flow(me.g, me.cap, me.n, me.n);
+ const MaxFlowType& const_max_flow = max_flow;
+
+ max_flow
+ .capacityMap(cap)
+ .flowMap(flow)
+ .source(n)
+ .target(n);
+
+ typename MaxFlowType::Tolerance tol = const_max_flow.tolerance();
+ max_flow.tolerance(tol);
+
+ max_flow.init();
+ max_flow.init(cap);
+ max_flow.run();
+
+ v = const_max_flow.flowValue();
+ v = const_max_flow.flow(e);
+ const FlowMap& fm = const_max_flow.flowMap();
+
+ b = const_max_flow.minCut(n);
+ const_max_flow.minCutMap(cut);
+
+ ::lemon::ignore_unused_variable_warning(fm);
+ }
+
+ };
+
+};
+
+// Checks the specific parts of Preflow's interface
+void checkPreflowCompile()
+{
+ typedef int Value;
+ typedef concepts::Digraph Digraph;
+ typedef concepts::ReadMap<Digraph::Arc, Value> CapMap;
+ typedef Elevator<Digraph, Digraph::Node> Elev;
+ typedef LinkedElevator<Digraph, Digraph::Node> LinkedElev;
+
+ Digraph g;
+ Digraph::Node n;
+ CapMap cap;
+
+ typedef Preflow<Digraph, CapMap>
+ ::SetElevator<Elev>
+ ::SetStandardElevator<LinkedElev>
+ ::Create PreflowType;
+ PreflowType preflow_test(g, cap, n, n);
+ const PreflowType& const_preflow_test = preflow_test;
+
+ const PreflowType::Elevator& elev = const_preflow_test.elevator();
+ preflow_test.elevator(const_cast<PreflowType::Elevator&>(elev));
+
+ bool b = preflow_test.init(cap);
+ preflow_test.startFirstPhase();
+ preflow_test.startSecondPhase();
+ preflow_test.runMinCut();
+
+ ::lemon::ignore_unused_variable_warning(b);
+}
+
+// Checks the specific parts of EdmondsKarp's interface
+void checkEdmondsKarpCompile()
+{
+ typedef int Value;
+ typedef concepts::Digraph Digraph;
+ typedef concepts::ReadMap<Digraph::Arc, Value> CapMap;
+ typedef Elevator<Digraph, Digraph::Node> Elev;
+ typedef LinkedElevator<Digraph, Digraph::Node> LinkedElev;
+
+ Digraph g;
+ Digraph::Node n;
+ CapMap cap;
+
+ EdmondsKarp<Digraph, CapMap> ek_test(g, cap, n, n);
+
+ ek_test.init(cap);
+ bool b = ek_test.checkedInit(cap);
+ b = ek_test.augment();
+ ek_test.start();
+
+ ::lemon::ignore_unused_variable_warning(b);
+}
+
+
+template <typename T>
+T cutValue (const SmartDigraph& g,
+ const SmartDigraph::NodeMap<bool>& cut,
+ const SmartDigraph::ArcMap<T>& cap) {
+
+ T c=0;
+ for(SmartDigraph::ArcIt e(g); e!=INVALID; ++e) {
+ if (cut[g.source(e)] && !cut[g.target(e)]) c+=cap[e];
+ }
+ return c;
+}
+
+template <typename T>
+bool checkFlow(const SmartDigraph& g,
+ const SmartDigraph::ArcMap<T>& flow,
+ const SmartDigraph::ArcMap<T>& cap,
+ SmartDigraph::Node s, SmartDigraph::Node t) {
+
+ for (SmartDigraph::ArcIt e(g); e != INVALID; ++e) {
+ if (flow[e] < 0 || flow[e] > cap[e]) return false;
+ }
+
+ for (SmartDigraph::NodeIt n(g); n != INVALID; ++n) {
+ if (n == s || n == t) continue;
+ T sum = 0;
+ for (SmartDigraph::OutArcIt e(g, n); e != INVALID; ++e) {
+ sum += flow[e];
+ }
+ for (SmartDigraph::InArcIt e(g, n); e != INVALID; ++e) {
+ sum -= flow[e];
+ }
+ if (sum != 0) return false;
+ }
+ return true;
+}
+
+void initFlowTest()
+{
+ DIGRAPH_TYPEDEFS(SmartDigraph);
+
+ SmartDigraph g;
+ SmartDigraph::ArcMap<int> cap(g),iflow(g);
+ Node s=g.addNode(); Node t=g.addNode();
+ Node n1=g.addNode(); Node n2=g.addNode();
+ Arc a;
+ a=g.addArc(s,n1); cap[a]=20; iflow[a]=20;
+ a=g.addArc(n1,n2); cap[a]=10; iflow[a]=0;
+ a=g.addArc(n2,t); cap[a]=20; iflow[a]=0;
+
+ Preflow<SmartDigraph> pre(g,cap,s,t);
+ pre.init(iflow);
+ pre.startFirstPhase();
+ check(pre.flowValue() == 10, "The incorrect max flow value.");
+ check(pre.minCut(s), "Wrong min cut (Node s).");
+ check(pre.minCut(n1), "Wrong min cut (Node n1).");
+ check(!pre.minCut(n2), "Wrong min cut (Node n2).");
+ check(!pre.minCut(t), "Wrong min cut (Node t).");
+}
+
+template <typename MF, typename SF>
+void checkMaxFlowAlg() {
+ typedef SmartDigraph Digraph;
+ DIGRAPH_TYPEDEFS(Digraph);
+
+ typedef typename MF::Value Value;
+ typedef Digraph::ArcMap<Value> CapMap;
+ typedef CapMap FlowMap;
+ typedef BoolNodeMap CutMap;
+
+ Digraph g;
+ Node s, t;
+ CapMap cap(g);
+ std::istringstream input(test_lgf);
+ DigraphReader<Digraph>(g,input)
+ .arcMap("capacity", cap)
+ .node("source",s)
+ .node("target",t)
+ .run();
+
+ MF max_flow(g, cap, s, t);
+ max_flow.run();
+
+ check(checkFlow(g, max_flow.flowMap(), cap, s, t),
+ "The flow is not feasible.");
+
+ CutMap min_cut(g);
+ max_flow.minCutMap(min_cut);
+ Value min_cut_value = cutValue(g, min_cut, cap);
+
+ check(max_flow.flowValue() == min_cut_value,
+ "The max flow value is not equal to the min cut value.");
+
+ FlowMap flow(g);
+ for (ArcIt e(g); e != INVALID; ++e) flow[e] = max_flow.flowMap()[e];
+
+ Value flow_value = max_flow.flowValue();
+
+ for (ArcIt e(g); e != INVALID; ++e) cap[e] = 2 * cap[e];
+ max_flow.init(flow);
+
+ SF::startFirstPhase(max_flow); // start first phase of the algorithm
+
+ CutMap min_cut1(g);
+ max_flow.minCutMap(min_cut1);
+ min_cut_value = cutValue(g, min_cut1, cap);
+
+ check(max_flow.flowValue() == min_cut_value &&
+ min_cut_value == 2 * flow_value,
+ "The max flow value or the min cut value is wrong.");
+
+ SF::startSecondPhase(max_flow); // start second phase of the algorithm
+
+ check(checkFlow(g, max_flow.flowMap(), cap, s, t),
+ "The flow is not feasible.");
+
+ CutMap min_cut2(g);
+ max_flow.minCutMap(min_cut2);
+ min_cut_value = cutValue(g, min_cut2, cap);
+
+ check(max_flow.flowValue() == min_cut_value &&
+ min_cut_value == 2 * flow_value,
+ "The max flow value or the min cut value was not doubled");
+
+
+ max_flow.flowMap(flow);
+
+ NodeIt tmp1(g, s);
+ ++tmp1;
+ if (tmp1 != INVALID) s = tmp1;
+
+ NodeIt tmp2(g, t);
+ ++tmp2;
+ if (tmp2 != INVALID) t = tmp2;
+
+ max_flow.source(s);
+ max_flow.target(t);
+
+ max_flow.run();
+
+ CutMap min_cut3(g);
+ max_flow.minCutMap(min_cut3);
+ min_cut_value=cutValue(g, min_cut3, cap);
+
+ check(max_flow.flowValue() == min_cut_value,
+ "The max flow value or the min cut value is wrong.");
+}
+
+// Struct for calling start functions of a general max flow algorithm
+template <typename MF>
+struct GeneralStartFunctions {
+
+ static void startFirstPhase(MF& mf) {
+ mf.start();
+ }
+
+ static void startSecondPhase(MF& mf) {
+ ::lemon::ignore_unused_variable_warning(mf);
+ }
+
+};
+
+// Struct for calling start functions of Preflow
+template <typename MF>
+struct PreflowStartFunctions {
+
+ static void startFirstPhase(MF& mf) {
+ mf.startFirstPhase();
+ }
+
+ static void startSecondPhase(MF& mf) {
+ mf.startSecondPhase();
+ }
+
+};
+
+int main() {
+
+ typedef concepts::Digraph GR;
+ typedef concepts::ReadMap<GR::Arc, int> CM1;
+ typedef concepts::ReadMap<GR::Arc, double> CM2;
+
+ // Check the interface of Preflow
+ checkConcept< MaxFlowClassConcept<GR, CM1>,
+ Preflow<GR, CM1> >();
+ checkConcept< MaxFlowClassConcept<GR, CM2>,
+ Preflow<GR, CM2> >();
+
+ // Check the interface of EdmondsKarp
+ checkConcept< MaxFlowClassConcept<GR, CM1>,
+ EdmondsKarp<GR, CM1> >();
+ checkConcept< MaxFlowClassConcept<GR, CM2>,
+ EdmondsKarp<GR, CM2> >();
+
+ // Check Preflow
+ typedef Preflow<SmartDigraph, SmartDigraph::ArcMap<int> > PType1;
+ typedef Preflow<SmartDigraph, SmartDigraph::ArcMap<float> > PType2;
+ checkMaxFlowAlg<PType1, PreflowStartFunctions<PType1> >();
+ checkMaxFlowAlg<PType2, PreflowStartFunctions<PType2> >();
+ initFlowTest();
+
+ // Check EdmondsKarp
+ typedef EdmondsKarp<SmartDigraph, SmartDigraph::ArcMap<int> > EKType1;
+ typedef EdmondsKarp<SmartDigraph, SmartDigraph::ArcMap<float> > EKType2;
+ checkMaxFlowAlg<EKType1, GeneralStartFunctions<EKType1> >();
+ checkMaxFlowAlg<EKType2, GeneralStartFunctions<EKType2> >();
+
+ initFlowTest();
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/min_cost_arborescence_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/min_cost_arborescence_test.cc
new file mode 100644
index 00000000000..3a5ea36f1ea
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/min_cost_arborescence_test.cc
@@ -0,0 +1,207 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <iostream>
+#include <set>
+#include <vector>
+#include <iterator>
+
+#include <lemon/smart_graph.h>
+#include <lemon/min_cost_arborescence.h>
+#include <lemon/lgf_reader.h>
+#include <lemon/concepts/digraph.h>
+
+#include "test_tools.h"
+
+using namespace lemon;
+using namespace std;
+
+const char test_lgf[] =
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "5\n"
+ "6\n"
+ "7\n"
+ "8\n"
+ "9\n"
+ "@arcs\n"
+ " label cost\n"
+ "1 8 0 107\n"
+ "0 3 1 70\n"
+ "2 1 2 46\n"
+ "4 1 3 28\n"
+ "4 4 4 91\n"
+ "3 9 5 76\n"
+ "9 8 6 61\n"
+ "8 1 7 39\n"
+ "9 8 8 74\n"
+ "8 0 9 39\n"
+ "4 3 10 45\n"
+ "2 2 11 34\n"
+ "0 1 12 100\n"
+ "6 3 13 95\n"
+ "4 1 14 22\n"
+ "1 1 15 31\n"
+ "7 2 16 51\n"
+ "2 6 17 29\n"
+ "8 3 18 115\n"
+ "6 9 19 32\n"
+ "1 1 20 60\n"
+ "0 3 21 40\n"
+ "@attributes\n"
+ "source 0\n";
+
+
+void checkMinCostArborescenceCompile()
+{
+ typedef double VType;
+ typedef concepts::Digraph Digraph;
+ typedef concepts::ReadMap<Digraph::Arc, VType> CostMap;
+ typedef Digraph::Node Node;
+ typedef Digraph::Arc Arc;
+ typedef concepts::WriteMap<Digraph::Arc, bool> ArbMap;
+ typedef concepts::ReadWriteMap<Digraph::Node, Digraph::Arc> PredMap;
+
+ typedef MinCostArborescence<Digraph, CostMap>::
+ SetArborescenceMap<ArbMap>::
+ SetPredMap<PredMap>::Create MinCostArbType;
+
+ Digraph g;
+ Node s, n;
+ Arc e;
+ VType c;
+ bool b;
+ ::lemon::ignore_unused_variable_warning(c,b);
+ int i;
+ CostMap cost;
+ ArbMap arb;
+ PredMap pred;
+
+ MinCostArbType mcarb_test(g, cost);
+ const MinCostArbType& const_mcarb_test = mcarb_test;
+
+ mcarb_test
+ .arborescenceMap(arb)
+ .predMap(pred)
+ .run(s);
+
+ mcarb_test.init();
+ mcarb_test.addSource(s);
+ mcarb_test.start();
+ n = mcarb_test.processNextNode();
+ b = const_mcarb_test.emptyQueue();
+ i = const_mcarb_test.queueSize();
+
+ c = const_mcarb_test.arborescenceCost();
+ b = const_mcarb_test.arborescence(e);
+ e = const_mcarb_test.pred(n);
+ const MinCostArbType::ArborescenceMap &am =
+ const_mcarb_test.arborescenceMap();
+ const MinCostArbType::PredMap &pm =
+ const_mcarb_test.predMap();
+ b = const_mcarb_test.reached(n);
+ b = const_mcarb_test.processed(n);
+
+ i = const_mcarb_test.dualNum();
+ c = const_mcarb_test.dualValue();
+ i = const_mcarb_test.dualSize(i);
+ c = const_mcarb_test.dualValue(i);
+
+ ::lemon::ignore_unused_variable_warning(am);
+ ::lemon::ignore_unused_variable_warning(pm);
+}
+
+int main() {
+ typedef SmartDigraph Digraph;
+ DIGRAPH_TYPEDEFS(Digraph);
+
+ typedef Digraph::ArcMap<double> CostMap;
+
+ Digraph digraph;
+ CostMap cost(digraph);
+ Node source;
+
+ std::istringstream is(test_lgf);
+ digraphReader(digraph, is).
+ arcMap("cost", cost).
+ node("source", source).run();
+
+ MinCostArborescence<Digraph, CostMap> mca(digraph, cost);
+ mca.run(source);
+
+ vector<pair<double, set<Node> > > dualSolution(mca.dualNum());
+
+ for (int i = 0; i < mca.dualNum(); ++i) {
+ dualSolution[i].first = mca.dualValue(i);
+ for (MinCostArborescence<Digraph, CostMap>::DualIt it(mca, i);
+ it != INVALID; ++it) {
+ dualSolution[i].second.insert(it);
+ }
+ }
+
+ for (ArcIt it(digraph); it != INVALID; ++it) {
+ if (mca.reached(digraph.source(it))) {
+ double sum = 0.0;
+ for (int i = 0; i < int(dualSolution.size()); ++i) {
+ if (dualSolution[i].second.find(digraph.target(it))
+ != dualSolution[i].second.end() &&
+ dualSolution[i].second.find(digraph.source(it))
+ == dualSolution[i].second.end()) {
+ sum += dualSolution[i].first;
+ }
+ }
+ if (mca.arborescence(it)) {
+ check(sum == cost[it], "Invalid dual solution");
+ }
+ check(sum <= cost[it], "Invalid dual solution");
+ }
+ }
+
+
+ check(mca.dualValue() == mca.arborescenceCost(), "Invalid dual solution");
+
+ check(mca.reached(source), "Invalid arborescence");
+ for (ArcIt a(digraph); a != INVALID; ++a) {
+ check(!mca.reached(digraph.source(a)) ||
+ mca.reached(digraph.target(a)), "Invalid arborescence");
+ }
+
+ for (NodeIt n(digraph); n != INVALID; ++n) {
+ if (!mca.reached(n)) continue;
+ int cnt = 0;
+ for (InArcIt a(digraph, n); a != INVALID; ++a) {
+ if (mca.arborescence(a)) {
+ check(mca.pred(n) == a, "Invalid arborescence");
+ ++cnt;
+ }
+ }
+ check((n == source ? cnt == 0 : cnt == 1), "Invalid arborescence");
+ }
+
+ Digraph::ArcMap<bool> arborescence(digraph);
+ check(mca.arborescenceCost() ==
+ minCostArborescence(digraph, cost, source, arborescence),
+ "Wrong result of the function interface");
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/min_cost_flow_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/min_cost_flow_test.cc
new file mode 100644
index 00000000000..15dcf542d36
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/min_cost_flow_test.cc
@@ -0,0 +1,548 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <iostream>
+#include <fstream>
+#include <limits>
+
+#include <lemon/list_graph.h>
+#include <lemon/lgf_reader.h>
+
+#include <lemon/network_simplex.h>
+#include <lemon/capacity_scaling.h>
+#include <lemon/cost_scaling.h>
+#include <lemon/cycle_canceling.h>
+
+#include <lemon/concepts/digraph.h>
+#include <lemon/concepts/heap.h>
+#include <lemon/concept_check.h>
+
+#include "test_tools.h"
+
+using namespace lemon;
+
+// Test networks
+char test_lgf[] =
+ "@nodes\n"
+ "label sup1 sup2 sup3 sup4 sup5 sup6\n"
+ " 1 20 27 0 30 20 30\n"
+ " 2 -4 0 0 0 -8 -3\n"
+ " 3 0 0 0 0 0 0\n"
+ " 4 0 0 0 0 0 0\n"
+ " 5 9 0 0 0 6 11\n"
+ " 6 -6 0 0 0 -5 -6\n"
+ " 7 0 0 0 0 0 0\n"
+ " 8 0 0 0 0 0 3\n"
+ " 9 3 0 0 0 0 0\n"
+ " 10 -2 0 0 0 -7 -2\n"
+ " 11 0 0 0 0 -10 0\n"
+ " 12 -20 -27 0 -30 -30 -20\n"
+ "\n"
+ "@arcs\n"
+ " cost cap low1 low2 low3\n"
+ " 1 2 70 11 0 8 8\n"
+ " 1 3 150 3 0 1 0\n"
+ " 1 4 80 15 0 2 2\n"
+ " 2 8 80 12 0 0 0\n"
+ " 3 5 140 5 0 3 1\n"
+ " 4 6 60 10 0 1 0\n"
+ " 4 7 80 2 0 0 0\n"
+ " 4 8 110 3 0 0 0\n"
+ " 5 7 60 14 0 0 0\n"
+ " 5 11 120 12 0 0 0\n"
+ " 6 3 0 3 0 0 0\n"
+ " 6 9 140 4 0 0 0\n"
+ " 6 10 90 8 0 0 0\n"
+ " 7 1 30 5 0 0 -5\n"
+ " 8 12 60 16 0 4 3\n"
+ " 9 12 50 6 0 0 0\n"
+ "10 12 70 13 0 5 2\n"
+ "10 2 100 7 0 0 0\n"
+ "10 7 60 10 0 0 -3\n"
+ "11 10 20 14 0 6 -20\n"
+ "12 11 30 10 0 0 -10\n"
+ "\n"
+ "@attributes\n"
+ "source 1\n"
+ "target 12\n";
+
+char test_neg1_lgf[] =
+ "@nodes\n"
+ "label sup\n"
+ " 1 100\n"
+ " 2 0\n"
+ " 3 0\n"
+ " 4 -100\n"
+ " 5 0\n"
+ " 6 0\n"
+ " 7 0\n"
+ "@arcs\n"
+ " cost low1 low2\n"
+ "1 2 100 0 0\n"
+ "1 3 30 0 0\n"
+ "2 4 20 0 0\n"
+ "3 4 80 0 0\n"
+ "3 2 50 0 0\n"
+ "5 3 10 0 0\n"
+ "5 6 80 0 1000\n"
+ "6 7 30 0 -1000\n"
+ "7 5 -120 0 0\n";
+
+char test_neg2_lgf[] =
+ "@nodes\n"
+ "label sup\n"
+ " 1 100\n"
+ " 2 -300\n"
+ "@arcs\n"
+ " cost\n"
+ "1 2 -1\n";
+
+
+// Test data
+typedef ListDigraph Digraph;
+DIGRAPH_TYPEDEFS(ListDigraph);
+
+Digraph gr;
+Digraph::ArcMap<int> c(gr), l1(gr), l2(gr), l3(gr), u(gr);
+Digraph::NodeMap<int> s1(gr), s2(gr), s3(gr), s4(gr), s5(gr), s6(gr);
+ConstMap<Arc, int> cc(1), cu(std::numeric_limits<int>::max());
+Node v, w;
+
+Digraph neg1_gr;
+Digraph::ArcMap<int> neg1_c(neg1_gr), neg1_l1(neg1_gr), neg1_l2(neg1_gr);
+ConstMap<Arc, int> neg1_u1(std::numeric_limits<int>::max()), neg1_u2(5000);
+Digraph::NodeMap<int> neg1_s(neg1_gr);
+
+Digraph neg2_gr;
+Digraph::ArcMap<int> neg2_c(neg2_gr);
+ConstMap<Arc, int> neg2_l(0), neg2_u(1000);
+Digraph::NodeMap<int> neg2_s(neg2_gr);
+
+
+enum SupplyType {
+ EQ,
+ GEQ,
+ LEQ
+};
+
+
+// Check the interface of an MCF algorithm
+template <typename GR, typename Value, typename Cost>
+class McfClassConcept
+{
+public:
+
+ template <typename MCF>
+ struct Constraints {
+ void constraints() {
+ checkConcept<concepts::Digraph, GR>();
+
+ const Constraints& me = *this;
+
+ MCF mcf(me.g);
+ const MCF& const_mcf = mcf;
+
+ b = mcf.reset().resetParams()
+ .lowerMap(me.lower)
+ .upperMap(me.upper)
+ .costMap(me.cost)
+ .supplyMap(me.sup)
+ .stSupply(me.n, me.n, me.k)
+ .run();
+
+ c = const_mcf.totalCost();
+ x = const_mcf.template totalCost<double>();
+ v = const_mcf.flow(me.a);
+ c = const_mcf.potential(me.n);
+ const_mcf.flowMap(fm);
+ const_mcf.potentialMap(pm);
+ }
+
+ typedef typename GR::Node Node;
+ typedef typename GR::Arc Arc;
+ typedef concepts::ReadMap<Node, Value> NM;
+ typedef concepts::ReadMap<Arc, Value> VAM;
+ typedef concepts::ReadMap<Arc, Cost> CAM;
+ typedef concepts::WriteMap<Arc, Value> FlowMap;
+ typedef concepts::WriteMap<Node, Cost> PotMap;
+
+ GR g;
+ VAM lower;
+ VAM upper;
+ CAM cost;
+ NM sup;
+ Node n;
+ Arc a;
+ Value k;
+
+ FlowMap fm;
+ PotMap pm;
+ bool b;
+ double x;
+ typename MCF::Value v;
+ typename MCF::Cost c;
+ };
+
+};
+
+
+// Check the feasibility of the given flow (primal soluiton)
+template < typename GR, typename LM, typename UM,
+ typename SM, typename FM >
+bool checkFlow( const GR& gr, const LM& lower, const UM& upper,
+ const SM& supply, const FM& flow,
+ SupplyType type = EQ )
+{
+ TEMPLATE_DIGRAPH_TYPEDEFS(GR);
+
+ for (ArcIt e(gr); e != INVALID; ++e) {
+ if (flow[e] < lower[e] || flow[e] > upper[e]) return false;
+ }
+
+ for (NodeIt n(gr); n != INVALID; ++n) {
+ typename SM::Value sum = 0;
+ for (OutArcIt e(gr, n); e != INVALID; ++e)
+ sum += flow[e];
+ for (InArcIt e(gr, n); e != INVALID; ++e)
+ sum -= flow[e];
+ bool b = (type == EQ && sum == supply[n]) ||
+ (type == GEQ && sum >= supply[n]) ||
+ (type == LEQ && sum <= supply[n]);
+ if (!b) return false;
+ }
+
+ return true;
+}
+
+// Check the feasibility of the given potentials (dual soluiton)
+// using the "Complementary Slackness" optimality condition
+template < typename GR, typename LM, typename UM,
+ typename CM, typename SM, typename FM, typename PM >
+bool checkPotential( const GR& gr, const LM& lower, const UM& upper,
+ const CM& cost, const SM& supply, const FM& flow,
+ const PM& pi, SupplyType type )
+{
+ TEMPLATE_DIGRAPH_TYPEDEFS(GR);
+
+ bool opt = true;
+ for (ArcIt e(gr); opt && e != INVALID; ++e) {
+ typename CM::Value red_cost =
+ cost[e] + pi[gr.source(e)] - pi[gr.target(e)];
+ opt = red_cost == 0 ||
+ (red_cost > 0 && flow[e] == lower[e]) ||
+ (red_cost < 0 && flow[e] == upper[e]);
+ }
+
+ for (NodeIt n(gr); opt && n != INVALID; ++n) {
+ typename SM::Value sum = 0;
+ for (OutArcIt e(gr, n); e != INVALID; ++e)
+ sum += flow[e];
+ for (InArcIt e(gr, n); e != INVALID; ++e)
+ sum -= flow[e];
+ if (type != LEQ) {
+ opt = (pi[n] <= 0) && (sum == supply[n] || pi[n] == 0);
+ } else {
+ opt = (pi[n] >= 0) && (sum == supply[n] || pi[n] == 0);
+ }
+ }
+
+ return opt;
+}
+
+// Check whether the dual cost is equal to the primal cost
+template < typename GR, typename LM, typename UM,
+ typename CM, typename SM, typename PM >
+bool checkDualCost( const GR& gr, const LM& lower, const UM& upper,
+ const CM& cost, const SM& supply, const PM& pi,
+ typename CM::Value total )
+{
+ TEMPLATE_DIGRAPH_TYPEDEFS(GR);
+
+ typename CM::Value dual_cost = 0;
+ SM red_supply(gr);
+ for (NodeIt n(gr); n != INVALID; ++n) {
+ red_supply[n] = supply[n];
+ }
+ for (ArcIt a(gr); a != INVALID; ++a) {
+ if (lower[a] != 0) {
+ dual_cost += lower[a] * cost[a];
+ red_supply[gr.source(a)] -= lower[a];
+ red_supply[gr.target(a)] += lower[a];
+ }
+ }
+
+ for (NodeIt n(gr); n != INVALID; ++n) {
+ dual_cost -= red_supply[n] * pi[n];
+ }
+ for (ArcIt a(gr); a != INVALID; ++a) {
+ typename CM::Value red_cost =
+ cost[a] + pi[gr.source(a)] - pi[gr.target(a)];
+ dual_cost -= (upper[a] - lower[a]) * std::max(-red_cost, 0);
+ }
+
+ return dual_cost == total;
+}
+
+// Run a minimum cost flow algorithm and check the results
+template < typename MCF, typename GR,
+ typename LM, typename UM,
+ typename CM, typename SM,
+ typename PT >
+void checkMcf( const MCF& mcf, PT mcf_result,
+ const GR& gr, const LM& lower, const UM& upper,
+ const CM& cost, const SM& supply,
+ PT result, bool optimal, typename CM::Value total,
+ const std::string &test_id = "",
+ SupplyType type = EQ )
+{
+ check(mcf_result == result, "Wrong result " + test_id);
+ if (optimal) {
+ typename GR::template ArcMap<typename SM::Value> flow(gr);
+ typename GR::template NodeMap<typename CM::Value> pi(gr);
+ mcf.flowMap(flow);
+ mcf.potentialMap(pi);
+ check(checkFlow(gr, lower, upper, supply, flow, type),
+ "The flow is not feasible " + test_id);
+ check(mcf.totalCost() == total, "The flow is not optimal " + test_id);
+ check(checkPotential(gr, lower, upper, cost, supply, flow, pi, type),
+ "Wrong potentials " + test_id);
+ check(checkDualCost(gr, lower, upper, cost, supply, pi, total),
+ "Wrong dual cost " + test_id);
+ }
+}
+
+template < typename MCF, typename Param >
+void runMcfGeqTests( Param param,
+ const std::string &test_str = "",
+ bool full_neg_cost_support = false )
+{
+ MCF mcf1(gr), mcf2(neg1_gr), mcf3(neg2_gr);
+
+ // Basic tests
+ mcf1.upperMap(u).costMap(c).supplyMap(s1);
+ checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s1,
+ mcf1.OPTIMAL, true, 5240, test_str + "-1");
+ mcf1.stSupply(v, w, 27);
+ checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s2,
+ mcf1.OPTIMAL, true, 7620, test_str + "-2");
+ mcf1.lowerMap(l2).supplyMap(s1);
+ checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s1,
+ mcf1.OPTIMAL, true, 5970, test_str + "-3");
+ mcf1.stSupply(v, w, 27);
+ checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s2,
+ mcf1.OPTIMAL, true, 8010, test_str + "-4");
+ mcf1.resetParams().supplyMap(s1);
+ checkMcf(mcf1, mcf1.run(param), gr, l1, cu, cc, s1,
+ mcf1.OPTIMAL, true, 74, test_str + "-5");
+ mcf1.lowerMap(l2).stSupply(v, w, 27);
+ checkMcf(mcf1, mcf1.run(param), gr, l2, cu, cc, s2,
+ mcf1.OPTIMAL, true, 94, test_str + "-6");
+ mcf1.reset();
+ checkMcf(mcf1, mcf1.run(param), gr, l1, cu, cc, s3,
+ mcf1.OPTIMAL, true, 0, test_str + "-7");
+ mcf1.lowerMap(l2).upperMap(u);
+ checkMcf(mcf1, mcf1.run(param), gr, l2, u, cc, s3,
+ mcf1.INFEASIBLE, false, 0, test_str + "-8");
+ mcf1.lowerMap(l3).upperMap(u).costMap(c).supplyMap(s4);
+ checkMcf(mcf1, mcf1.run(param), gr, l3, u, c, s4,
+ mcf1.OPTIMAL, true, 6360, test_str + "-9");
+
+ // Tests for the GEQ form
+ mcf1.resetParams().upperMap(u).costMap(c).supplyMap(s5);
+ checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s5,
+ mcf1.OPTIMAL, true, 3530, test_str + "-10", GEQ);
+ mcf1.lowerMap(l2);
+ checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s5,
+ mcf1.OPTIMAL, true, 4540, test_str + "-11", GEQ);
+ mcf1.supplyMap(s6);
+ checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s6,
+ mcf1.INFEASIBLE, false, 0, test_str + "-12", GEQ);
+
+ // Tests with negative costs
+ mcf2.lowerMap(neg1_l1).costMap(neg1_c).supplyMap(neg1_s);
+ checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l1, neg1_u1, neg1_c, neg1_s,
+ mcf2.UNBOUNDED, false, 0, test_str + "-13");
+ mcf2.upperMap(neg1_u2);
+ checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l1, neg1_u2, neg1_c, neg1_s,
+ mcf2.OPTIMAL, true, -40000, test_str + "-14");
+ mcf2.resetParams().lowerMap(neg1_l2).costMap(neg1_c).supplyMap(neg1_s);
+ checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l2, neg1_u1, neg1_c, neg1_s,
+ mcf2.UNBOUNDED, false, 0, test_str + "-15");
+
+ mcf3.costMap(neg2_c).supplyMap(neg2_s);
+ if (full_neg_cost_support) {
+ checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s,
+ mcf3.OPTIMAL, true, -300, test_str + "-16", GEQ);
+ } else {
+ checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s,
+ mcf3.UNBOUNDED, false, 0, test_str + "-17", GEQ);
+ }
+ mcf3.upperMap(neg2_u);
+ checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s,
+ mcf3.OPTIMAL, true, -300, test_str + "-18", GEQ);
+
+ // Tests for empty graph
+ Digraph gr0;
+ MCF mcf0(gr0);
+ mcf0.run(param);
+ check(mcf0.totalCost() == 0, "Wrong total cost");
+}
+
+template < typename MCF, typename Param >
+void runMcfLeqTests( Param param,
+ const std::string &test_str = "" )
+{
+ // Tests for the LEQ form
+ MCF mcf1(gr);
+ mcf1.supplyType(mcf1.LEQ);
+ mcf1.upperMap(u).costMap(c).supplyMap(s6);
+ checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s6,
+ mcf1.OPTIMAL, true, 5080, test_str + "-19", LEQ);
+ mcf1.lowerMap(l2);
+ checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s6,
+ mcf1.OPTIMAL, true, 5930, test_str + "-20", LEQ);
+ mcf1.supplyMap(s5);
+ checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s5,
+ mcf1.INFEASIBLE, false, 0, test_str + "-21", LEQ);
+}
+
+
+int main()
+{
+ // Read the test networks
+ std::istringstream input(test_lgf);
+ DigraphReader<Digraph>(gr, input)
+ .arcMap("cost", c)
+ .arcMap("cap", u)
+ .arcMap("low1", l1)
+ .arcMap("low2", l2)
+ .arcMap("low3", l3)
+ .nodeMap("sup1", s1)
+ .nodeMap("sup2", s2)
+ .nodeMap("sup3", s3)
+ .nodeMap("sup4", s4)
+ .nodeMap("sup5", s5)
+ .nodeMap("sup6", s6)
+ .node("source", v)
+ .node("target", w)
+ .run();
+
+ std::istringstream neg_inp1(test_neg1_lgf);
+ DigraphReader<Digraph>(neg1_gr, neg_inp1)
+ .arcMap("cost", neg1_c)
+ .arcMap("low1", neg1_l1)
+ .arcMap("low2", neg1_l2)
+ .nodeMap("sup", neg1_s)
+ .run();
+
+ std::istringstream neg_inp2(test_neg2_lgf);
+ DigraphReader<Digraph>(neg2_gr, neg_inp2)
+ .arcMap("cost", neg2_c)
+ .nodeMap("sup", neg2_s)
+ .run();
+
+ // Check the interface of NetworkSimplex
+ {
+ typedef concepts::Digraph GR;
+ checkConcept< McfClassConcept<GR, int, int>,
+ NetworkSimplex<GR> >();
+ checkConcept< McfClassConcept<GR, double, double>,
+ NetworkSimplex<GR, double> >();
+ checkConcept< McfClassConcept<GR, int, double>,
+ NetworkSimplex<GR, int, double> >();
+ }
+
+ // Check the interface of CapacityScaling
+ {
+ typedef concepts::Digraph GR;
+ checkConcept< McfClassConcept<GR, int, int>,
+ CapacityScaling<GR> >();
+ checkConcept< McfClassConcept<GR, double, double>,
+ CapacityScaling<GR, double> >();
+ checkConcept< McfClassConcept<GR, int, double>,
+ CapacityScaling<GR, int, double> >();
+ typedef CapacityScaling<GR>::
+ SetHeap<concepts::Heap<int, RangeMap<int> > >::Create CAS;
+ checkConcept< McfClassConcept<GR, int, int>, CAS >();
+ }
+
+ // Check the interface of CostScaling
+ {
+ typedef concepts::Digraph GR;
+ checkConcept< McfClassConcept<GR, int, int>,
+ CostScaling<GR> >();
+ checkConcept< McfClassConcept<GR, double, double>,
+ CostScaling<GR, double> >();
+ checkConcept< McfClassConcept<GR, int, double>,
+ CostScaling<GR, int, double> >();
+ typedef CostScaling<GR>::
+ SetLargeCost<double>::Create COS;
+ checkConcept< McfClassConcept<GR, int, int>, COS >();
+ }
+
+ // Check the interface of CycleCanceling
+ {
+ typedef concepts::Digraph GR;
+ checkConcept< McfClassConcept<GR, int, int>,
+ CycleCanceling<GR> >();
+ checkConcept< McfClassConcept<GR, double, double>,
+ CycleCanceling<GR, double> >();
+ checkConcept< McfClassConcept<GR, int, double>,
+ CycleCanceling<GR, int, double> >();
+ }
+
+ // Test NetworkSimplex
+ {
+ typedef NetworkSimplex<Digraph> MCF;
+ runMcfGeqTests<MCF>(MCF::FIRST_ELIGIBLE, "NS-FE", true);
+ runMcfLeqTests<MCF>(MCF::FIRST_ELIGIBLE, "NS-FE");
+ runMcfGeqTests<MCF>(MCF::BEST_ELIGIBLE, "NS-BE", true);
+ runMcfLeqTests<MCF>(MCF::BEST_ELIGIBLE, "NS-BE");
+ runMcfGeqTests<MCF>(MCF::BLOCK_SEARCH, "NS-BS", true);
+ runMcfLeqTests<MCF>(MCF::BLOCK_SEARCH, "NS-BS");
+ runMcfGeqTests<MCF>(MCF::CANDIDATE_LIST, "NS-CL", true);
+ runMcfLeqTests<MCF>(MCF::CANDIDATE_LIST, "NS-CL");
+ runMcfGeqTests<MCF>(MCF::ALTERING_LIST, "NS-AL", true);
+ runMcfLeqTests<MCF>(MCF::ALTERING_LIST, "NS-AL");
+ }
+
+ // Test CapacityScaling
+ {
+ typedef CapacityScaling<Digraph> MCF;
+ runMcfGeqTests<MCF>(0, "SSP");
+ runMcfGeqTests<MCF>(2, "CAS");
+ }
+
+ // Test CostScaling
+ {
+ typedef CostScaling<Digraph> MCF;
+ runMcfGeqTests<MCF>(MCF::PUSH, "COS-PR");
+ runMcfGeqTests<MCF>(MCF::AUGMENT, "COS-AR");
+ runMcfGeqTests<MCF>(MCF::PARTIAL_AUGMENT, "COS-PAR");
+ }
+
+ // Test CycleCanceling
+ {
+ typedef CycleCanceling<Digraph> MCF;
+ runMcfGeqTests<MCF>(MCF::SIMPLE_CYCLE_CANCELING, "SCC");
+ runMcfGeqTests<MCF>(MCF::MINIMUM_MEAN_CYCLE_CANCELING, "MMCC");
+ runMcfGeqTests<MCF>(MCF::CANCEL_AND_TIGHTEN, "CAT");
+ }
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/min_mean_cycle_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/min_mean_cycle_test.cc
new file mode 100644
index 00000000000..e7524546e54
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/min_mean_cycle_test.cc
@@ -0,0 +1,223 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <iostream>
+#include <sstream>
+
+#include <lemon/smart_graph.h>
+#include <lemon/lgf_reader.h>
+#include <lemon/path.h>
+#include <lemon/concepts/digraph.h>
+#include <lemon/concept_check.h>
+
+#include <lemon/karp_mmc.h>
+#include <lemon/hartmann_orlin_mmc.h>
+#include <lemon/howard_mmc.h>
+
+#include "test_tools.h"
+
+using namespace lemon;
+
+char test_lgf[] =
+ "@nodes\n"
+ "label\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "5\n"
+ "6\n"
+ "7\n"
+ "@arcs\n"
+ " len1 len2 len3 len4 c1 c2 c3 c4\n"
+ "1 2 1 1 1 1 0 0 0 0\n"
+ "2 4 5 5 5 5 1 0 0 0\n"
+ "2 3 8 8 8 8 0 0 0 0\n"
+ "3 2 -2 0 0 0 1 0 0 0\n"
+ "3 4 4 4 4 4 0 0 0 0\n"
+ "3 7 -4 -4 -4 -4 0 0 0 0\n"
+ "4 1 2 2 2 2 0 0 0 0\n"
+ "4 3 3 3 3 3 1 0 0 0\n"
+ "4 4 3 3 0 0 0 0 1 0\n"
+ "5 2 4 4 4 4 0 0 0 0\n"
+ "5 6 3 3 3 3 0 1 0 0\n"
+ "6 5 2 2 2 2 0 1 0 0\n"
+ "6 4 -1 -1 -1 -1 0 0 0 0\n"
+ "6 7 1 1 1 1 0 0 0 0\n"
+ "7 7 4 4 4 -1 0 0 0 1\n";
+
+
+// Check the interface of an MMC algorithm
+template <typename GR, typename Cost>
+struct MmcClassConcept
+{
+ template <typename MMC>
+ struct Constraints {
+ void constraints() {
+ const Constraints& me = *this;
+
+ typedef typename MMC
+ ::template SetPath<ListPath<GR> >
+ ::template SetLargeCost<Cost>
+ ::Create MmcAlg;
+ MmcAlg mmc(me.g, me.cost);
+ const MmcAlg& const_mmc = mmc;
+
+ typename MmcAlg::Tolerance tol = const_mmc.tolerance();
+ mmc.tolerance(tol);
+
+ b = mmc.cycle(p).run();
+ b = mmc.findCycleMean();
+ b = mmc.findCycle();
+
+ v = const_mmc.cycleCost();
+ i = const_mmc.cycleSize();
+ d = const_mmc.cycleMean();
+ p = const_mmc.cycle();
+ }
+
+ typedef concepts::ReadMap<typename GR::Arc, Cost> CM;
+
+ GR g;
+ CM cost;
+ ListPath<GR> p;
+ Cost v;
+ int i;
+ double d;
+ bool b;
+ };
+};
+
+// Perform a test with the given parameters
+template <typename MMC>
+void checkMmcAlg(const SmartDigraph& gr,
+ const SmartDigraph::ArcMap<int>& lm,
+ const SmartDigraph::ArcMap<int>& cm,
+ int cost, int size) {
+ MMC alg(gr, lm);
+ check(alg.findCycleMean(), "Wrong result");
+ check(alg.cycleMean() == static_cast<double>(cost) / size,
+ "Wrong cycle mean");
+ alg.findCycle();
+ check(alg.cycleCost() == cost && alg.cycleSize() == size,
+ "Wrong path");
+ SmartDigraph::ArcMap<int> cycle(gr, 0);
+ for (typename MMC::Path::ArcIt a(alg.cycle()); a != INVALID; ++a) {
+ ++cycle[a];
+ }
+ for (SmartDigraph::ArcIt a(gr); a != INVALID; ++a) {
+ check(cm[a] == cycle[a], "Wrong path");
+ }
+}
+
+// Class for comparing types
+template <typename T1, typename T2>
+struct IsSameType {
+ static const int result = 0;
+};
+
+template <typename T>
+struct IsSameType<T,T> {
+ static const int result = 1;
+};
+
+
+int main() {
+ #ifdef LEMON_HAVE_LONG_LONG
+ typedef long long long_int;
+ #else
+ typedef long long_int;
+ #endif
+
+ // Check the interface
+ {
+ typedef concepts::Digraph GR;
+
+ // KarpMmc
+ checkConcept< MmcClassConcept<GR, int>,
+ KarpMmc<GR, concepts::ReadMap<GR::Arc, int> > >();
+ checkConcept< MmcClassConcept<GR, float>,
+ KarpMmc<GR, concepts::ReadMap<GR::Arc, float> > >();
+
+ // HartmannOrlinMmc
+ checkConcept< MmcClassConcept<GR, int>,
+ HartmannOrlinMmc<GR, concepts::ReadMap<GR::Arc, int> > >();
+ checkConcept< MmcClassConcept<GR, float>,
+ HartmannOrlinMmc<GR, concepts::ReadMap<GR::Arc, float> > >();
+
+ // HowardMmc
+ checkConcept< MmcClassConcept<GR, int>,
+ HowardMmc<GR, concepts::ReadMap<GR::Arc, int> > >();
+ checkConcept< MmcClassConcept<GR, float>,
+ HowardMmc<GR, concepts::ReadMap<GR::Arc, float> > >();
+
+ check((IsSameType<HowardMmc<GR, concepts::ReadMap<GR::Arc, int> >
+ ::LargeCost, long_int>::result == 1), "Wrong LargeCost type");
+ check((IsSameType<HowardMmc<GR, concepts::ReadMap<GR::Arc, float> >
+ ::LargeCost, double>::result == 1), "Wrong LargeCost type");
+ }
+
+ // Run various tests
+ {
+ typedef SmartDigraph GR;
+ DIGRAPH_TYPEDEFS(GR);
+
+ GR gr;
+ IntArcMap l1(gr), l2(gr), l3(gr), l4(gr);
+ IntArcMap c1(gr), c2(gr), c3(gr), c4(gr);
+
+ std::istringstream input(test_lgf);
+ digraphReader(gr, input).
+ arcMap("len1", l1).
+ arcMap("len2", l2).
+ arcMap("len3", l3).
+ arcMap("len4", l4).
+ arcMap("c1", c1).
+ arcMap("c2", c2).
+ arcMap("c3", c3).
+ arcMap("c4", c4).
+ run();
+
+ // Karp
+ checkMmcAlg<KarpMmc<GR, IntArcMap> >(gr, l1, c1, 6, 3);
+ checkMmcAlg<KarpMmc<GR, IntArcMap> >(gr, l2, c2, 5, 2);
+ checkMmcAlg<KarpMmc<GR, IntArcMap> >(gr, l3, c3, 0, 1);
+ checkMmcAlg<KarpMmc<GR, IntArcMap> >(gr, l4, c4, -1, 1);
+
+ // HartmannOrlin
+ checkMmcAlg<HartmannOrlinMmc<GR, IntArcMap> >(gr, l1, c1, 6, 3);
+ checkMmcAlg<HartmannOrlinMmc<GR, IntArcMap> >(gr, l2, c2, 5, 2);
+ checkMmcAlg<HartmannOrlinMmc<GR, IntArcMap> >(gr, l3, c3, 0, 1);
+ checkMmcAlg<HartmannOrlinMmc<GR, IntArcMap> >(gr, l4, c4, -1, 1);
+
+ // Howard
+ checkMmcAlg<HowardMmc<GR, IntArcMap> >(gr, l1, c1, 6, 3);
+ checkMmcAlg<HowardMmc<GR, IntArcMap> >(gr, l2, c2, 5, 2);
+ checkMmcAlg<HowardMmc<GR, IntArcMap> >(gr, l3, c3, 0, 1);
+ checkMmcAlg<HowardMmc<GR, IntArcMap> >(gr, l4, c4, -1, 1);
+
+ // Howard with iteration limit
+ HowardMmc<GR, IntArcMap> mmc(gr, l1);
+ check((mmc.findCycleMean(2) == HowardMmc<GR, IntArcMap>::ITERATION_LIMIT),
+ "Wrong termination cause");
+ check((mmc.findCycleMean(4) == HowardMmc<GR, IntArcMap>::OPTIMAL),
+ "Wrong termination cause");
+ }
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/mip_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/mip_test.cc
new file mode 100644
index 00000000000..641ceb5fe77
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/mip_test.cc
@@ -0,0 +1,171 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include "test_tools.h"
+
+#include <lemon/config.h>
+
+#ifdef LEMON_HAVE_CPLEX
+#include <lemon/cplex.h>
+#endif
+
+#ifdef LEMON_HAVE_GLPK
+#include <lemon/glpk.h>
+#endif
+
+#ifdef LEMON_HAVE_CBC
+#include <lemon/cbc.h>
+#endif
+
+#ifdef LEMON_HAVE_MIP
+#include <lemon/lp.h>
+#endif
+
+
+using namespace lemon;
+
+void solveAndCheck(MipSolver& mip, MipSolver::ProblemType stat,
+ double exp_opt) {
+ using std::string;
+
+ mip.solve();
+ //int decimal,sign;
+ std::ostringstream buf;
+ buf << "Type should be: " << int(stat)<<" and it is "<<int(mip.type());
+
+
+ // itoa(stat,buf1, 10);
+ check(mip.type()==stat, buf.str());
+
+ if (stat == MipSolver::OPTIMAL) {
+ std::ostringstream sbuf;
+ sbuf << "Wrong optimal value ("<< mip.solValue()
+ <<" instead of " << exp_opt << ")";
+ check(std::abs(mip.solValue()-exp_opt) < 1e-3, sbuf.str());
+ //+ecvt(exp_opt,2)
+ }
+}
+
+void aTest(MipSolver& mip)
+{
+ //The following example is very simple
+
+
+ typedef MipSolver::Row Row;
+ typedef MipSolver::Col Col;
+
+
+ Col x1 = mip.addCol();
+ Col x2 = mip.addCol();
+
+
+ //Objective function
+ mip.obj(x1);
+
+ mip.max();
+
+ //Unconstrained optimization
+ mip.solve();
+ //Check it out!
+
+ //Constraints
+ mip.addRow(2 * x1 + x2 <= 2);
+ Row y2 = mip.addRow(x1 - 2 * x2 <= 0);
+
+ //Nonnegativity of the variable x1
+ mip.colLowerBound(x1, 0);
+
+
+ //Maximization of x1
+ //over the triangle with vertices (0,0),(4/5,2/5),(0,2)
+ double expected_opt=4.0/5.0;
+ solveAndCheck(mip, MipSolver::OPTIMAL, expected_opt);
+
+
+ //Restrict x2 to integer
+ mip.colType(x2,MipSolver::INTEGER);
+ expected_opt=1.0/2.0;
+ solveAndCheck(mip, MipSolver::OPTIMAL, expected_opt);
+
+
+ //Restrict both to integer
+ mip.colType(x1,MipSolver::INTEGER);
+ expected_opt=0;
+ solveAndCheck(mip, MipSolver::OPTIMAL, expected_opt);
+
+ //Erase a variable
+ mip.erase(x2);
+ mip.rowUpperBound(y2, 8);
+ expected_opt=1;
+ solveAndCheck(mip, MipSolver::OPTIMAL, expected_opt);
+
+}
+
+
+template<class MIP>
+void cloneTest()
+{
+
+ MIP* mip = new MIP();
+ MIP* mipnew = mip->newSolver();
+ MIP* mipclone = mip->cloneSolver();
+ delete mip;
+ delete mipnew;
+ delete mipclone;
+}
+
+int main()
+{
+
+#ifdef LEMON_HAVE_MIP
+ {
+ Mip mip1;
+ aTest(mip1);
+ cloneTest<Mip>();
+ }
+#endif
+
+#ifdef LEMON_HAVE_GLPK
+ {
+ GlpkMip mip1;
+ aTest(mip1);
+ cloneTest<GlpkMip>();
+ }
+#endif
+
+#ifdef LEMON_HAVE_CPLEX
+ try {
+ CplexMip mip2;
+ aTest(mip2);
+ cloneTest<CplexMip>();
+ } catch (CplexEnv::LicenseError& error) {
+ check(false, error.what());
+ }
+#endif
+
+#ifdef LEMON_HAVE_CBC
+ {
+ CbcMip mip1;
+ aTest(mip1);
+ cloneTest<CbcMip>();
+ }
+#endif
+
+ return 0;
+
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/nagamochi_ibaraki_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/nagamochi_ibaraki_test.cc
new file mode 100644
index 00000000000..94ec29d933b
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/nagamochi_ibaraki_test.cc
@@ -0,0 +1,142 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <sstream>
+
+#include <lemon/smart_graph.h>
+#include <lemon/adaptors.h>
+#include <lemon/concepts/graph.h>
+#include <lemon/concepts/maps.h>
+#include <lemon/lgf_reader.h>
+#include <lemon/nagamochi_ibaraki.h>
+
+#include "test_tools.h"
+
+using namespace lemon;
+using namespace std;
+
+const std::string lgf =
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "5\n"
+ "@edges\n"
+ " cap1 cap2 cap3\n"
+ "0 1 1 1 1 \n"
+ "0 2 2 2 4 \n"
+ "1 2 4 4 4 \n"
+ "3 4 1 1 1 \n"
+ "3 5 2 2 4 \n"
+ "4 5 4 4 4 \n"
+ "2 3 1 6 6 \n";
+
+void checkNagamochiIbarakiCompile()
+{
+ typedef int Value;
+ typedef concepts::Graph Graph;
+
+ typedef Graph::Node Node;
+ typedef Graph::Edge Edge;
+ typedef concepts::ReadMap<Edge, Value> CapMap;
+ typedef concepts::WriteMap<Node, bool> CutMap;
+
+ Graph g;
+ Node n;
+ CapMap cap;
+ CutMap cut;
+ Value v;
+ bool b;
+ ::lemon::ignore_unused_variable_warning(v,b);
+
+ NagamochiIbaraki<Graph, CapMap> ni_test(g, cap);
+ const NagamochiIbaraki<Graph, CapMap>& const_ni_test = ni_test;
+
+ ni_test.init();
+ ni_test.start();
+ b = ni_test.processNextPhase();
+ ni_test.run();
+
+ v = const_ni_test.minCutValue();
+ v = const_ni_test.minCutMap(cut);
+}
+
+template <typename Graph, typename CapMap, typename CutMap>
+typename CapMap::Value
+ cutValue(const Graph& graph, const CapMap& cap, const CutMap& cut)
+{
+ typename CapMap::Value sum = 0;
+ for (typename Graph::EdgeIt e(graph); e != INVALID; ++e) {
+ if (cut[graph.u(e)] != cut[graph.v(e)]) {
+ sum += cap[e];
+ }
+ }
+ return sum;
+}
+
+int main() {
+ SmartGraph graph;
+ SmartGraph::EdgeMap<int> cap1(graph), cap2(graph), cap3(graph);
+ SmartGraph::NodeMap<bool> cut(graph);
+
+ istringstream input(lgf);
+ graphReader(graph, input)
+ .edgeMap("cap1", cap1)
+ .edgeMap("cap2", cap2)
+ .edgeMap("cap3", cap3)
+ .run();
+
+ {
+ NagamochiIbaraki<SmartGraph> ni(graph, cap1);
+ ni.run();
+ ni.minCutMap(cut);
+
+ check(ni.minCutValue() == 1, "Wrong cut value");
+ check(ni.minCutValue() == cutValue(graph, cap1, cut), "Wrong cut value");
+ }
+ {
+ NagamochiIbaraki<SmartGraph> ni(graph, cap2);
+ ni.run();
+ ni.minCutMap(cut);
+
+ check(ni.minCutValue() == 3, "Wrong cut value");
+ check(ni.minCutValue() == cutValue(graph, cap2, cut), "Wrong cut value");
+ }
+ {
+ NagamochiIbaraki<SmartGraph> ni(graph, cap3);
+ ni.run();
+ ni.minCutMap(cut);
+
+ check(ni.minCutValue() == 5, "Wrong cut value");
+ check(ni.minCutValue() == cutValue(graph, cap3, cut), "Wrong cut value");
+ }
+ {
+ NagamochiIbaraki<SmartGraph>::SetUnitCapacity::Create ni(graph);
+ ni.run();
+ ni.minCutMap(cut);
+
+ ConstMap<SmartGraph::Edge, int> cap4(1);
+ check(ni.minCutValue() == 1, "Wrong cut value");
+ check(ni.minCutValue() == cutValue(graph, cap4, cut), "Wrong cut value");
+ }
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/path_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/path_test.cc
new file mode 100644
index 00000000000..f2d96038135
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/path_test.cc
@@ -0,0 +1,339 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <string>
+#include <iostream>
+
+#include <lemon/concepts/path.h>
+#include <lemon/concepts/digraph.h>
+#include <lemon/concept_check.h>
+
+#include <lemon/path.h>
+#include <lemon/list_graph.h>
+
+#include "test_tools.h"
+
+using namespace std;
+using namespace lemon;
+
+template <typename GR>
+void checkConcepts() {
+ checkConcept<concepts::Path<GR>, concepts::Path<GR> >();
+ checkConcept<concepts::Path<GR>, Path<GR> >();
+ checkConcept<concepts::Path<GR>, SimplePath<GR> >();
+ checkConcept<concepts::Path<GR>, StaticPath<GR> >();
+ checkConcept<concepts::Path<GR>, ListPath<GR> >();
+}
+
+// Conecpt checking for path structures
+void checkPathConcepts() {
+ checkConcepts<concepts::Digraph>();
+ checkConcepts<ListDigraph>();
+}
+
+// Check if proper copy consructor is called (use valgrind for testing)
+template <typename GR, typename P1, typename P2>
+void checkCopy(typename GR::Arc a) {
+ P1 p;
+ p.addBack(a);
+ P1 q;
+ q = p;
+ P1 r(p);
+ P2 q2;
+ q2 = p;
+ P2 r2(p);
+}
+
+// Tests for copy constructors and assignment operators of paths
+void checkPathCopy() {
+ ListDigraph g;
+ ListDigraph::Arc a = g.addArc(g.addNode(), g.addNode());
+
+ typedef Path<ListDigraph> Path1;
+ typedef SimplePath<ListDigraph> Path2;
+ typedef ListPath<ListDigraph> Path3;
+ typedef StaticPath<ListDigraph> Path4;
+ checkCopy<ListDigraph, Path1, Path2>(a);
+ checkCopy<ListDigraph, Path1, Path3>(a);
+ checkCopy<ListDigraph, Path1, Path4>(a);
+ checkCopy<ListDigraph, Path2, Path1>(a);
+ checkCopy<ListDigraph, Path2, Path3>(a);
+ checkCopy<ListDigraph, Path2, Path4>(a);
+ checkCopy<ListDigraph, Path3, Path1>(a);
+ checkCopy<ListDigraph, Path3, Path2>(a);
+ checkCopy<ListDigraph, Path3, Path4>(a);
+}
+
+// Class for testing path functions
+class CheckPathFunctions {
+ typedef ListDigraph GR;
+ DIGRAPH_TYPEDEFS(GR);
+ GR gr;
+ const GR& cgr;
+ Node n1, n2, n3, n4;
+ Node tmp_n;
+ Arc a1, a2, a3, a4;
+ Arc tmp_a;
+
+public:
+
+ CheckPathFunctions() : cgr(gr) {
+ n1 = gr.addNode();
+ n2 = gr.addNode();
+ n3 = gr.addNode();
+ n4 = gr.addNode();
+ a1 = gr.addArc(n1, n2);
+ a2 = gr.addArc(n2, n3);
+ a3 = gr.addArc(n3, n4);
+ a4 = gr.addArc(n4, n1);
+ }
+
+ void run() {
+ checkBackAndFrontInsertablePath<Path<GR> >();
+ checkBackAndFrontInsertablePath<ListPath<GR> >();
+ checkBackInsertablePath<SimplePath<GR> >();
+
+ checkListPathSplitAndSplice();
+ }
+
+private:
+
+ template <typename P>
+ void checkBackInsertablePath() {
+
+ // Create and check empty path
+ P p;
+ const P& cp = p;
+ check(cp.empty(), "The path is not empty");
+ check(cp.length() == 0, "The path is not empty");
+// check(cp.front() == INVALID, "Wrong front()");
+// check(cp.back() == INVALID, "Wrong back()");
+ typename P::ArcIt ai(cp);
+ check(ai == INVALID, "Wrong ArcIt");
+ check(pathSource(cgr, cp) == INVALID, "Wrong pathSource()");
+ check(pathTarget(cgr, cp) == INVALID, "Wrong pathTarget()");
+ check(checkPath(cgr, cp), "Wrong checkPath()");
+ PathNodeIt<P> ni(cgr, cp);
+ check(ni == INVALID, "Wrong PathNodeIt");
+
+ // Check single-arc path
+ p.addBack(a1);
+ check(!cp.empty(), "Wrong empty()");
+ check(cp.length() == 1, "Wrong length");
+ check(cp.front() == a1, "Wrong front()");
+ check(cp.back() == a1, "Wrong back()");
+ check(cp.nth(0) == a1, "Wrong nth()");
+ ai = cp.nthIt(0);
+ check((tmp_a = ai) == a1, "Wrong nthIt()");
+ check(++ai == INVALID, "Wrong nthIt()");
+ typename P::ArcIt ai2(cp);
+ check((tmp_a = ai2) == a1, "Wrong ArcIt");
+ check(++ai2 == INVALID, "Wrong ArcIt");
+ check(pathSource(cgr, cp) == n1, "Wrong pathSource()");
+ check(pathTarget(cgr, cp) == n2, "Wrong pathTarget()");
+ check(checkPath(cgr, cp), "Wrong checkPath()");
+ PathNodeIt<P> ni2(cgr, cp);
+ check((tmp_n = ni2) == n1, "Wrong PathNodeIt");
+ check((tmp_n = ++ni2) == n2, "Wrong PathNodeIt");
+ check(++ni2 == INVALID, "Wrong PathNodeIt");
+
+ // Check adding more arcs
+ p.addBack(a2);
+ p.addBack(a3);
+ check(!cp.empty(), "Wrong empty()");
+ check(cp.length() == 3, "Wrong length");
+ check(cp.front() == a1, "Wrong front()");
+ check(cp.back() == a3, "Wrong back()");
+ check(cp.nth(0) == a1, "Wrong nth()");
+ check(cp.nth(1) == a2, "Wrong nth()");
+ check(cp.nth(2) == a3, "Wrong nth()");
+ typename P::ArcIt ai3(cp);
+ check((tmp_a = ai3) == a1, "Wrong ArcIt");
+ check((tmp_a = ++ai3) == a2, "Wrong nthIt()");
+ check((tmp_a = ++ai3) == a3, "Wrong nthIt()");
+ check(++ai3 == INVALID, "Wrong nthIt()");
+ ai = cp.nthIt(0);
+ check((tmp_a = ai) == a1, "Wrong nthIt()");
+ check((tmp_a = ++ai) == a2, "Wrong nthIt()");
+ ai = cp.nthIt(2);
+ check((tmp_a = ai) == a3, "Wrong nthIt()");
+ check(++ai == INVALID, "Wrong nthIt()");
+ check(pathSource(cgr, cp) == n1, "Wrong pathSource()");
+ check(pathTarget(cgr, cp) == n4, "Wrong pathTarget()");
+ check(checkPath(cgr, cp), "Wrong checkPath()");
+ PathNodeIt<P> ni3(cgr, cp);
+ check((tmp_n = ni3) == n1, "Wrong PathNodeIt");
+ check((tmp_n = ++ni3) == n2, "Wrong PathNodeIt");
+ check((tmp_n = ++ni3) == n3, "Wrong PathNodeIt");
+ check((tmp_n = ++ni3) == n4, "Wrong PathNodeIt");
+ check(++ni3 == INVALID, "Wrong PathNodeIt");
+
+ // Check arc removal and addition
+ p.eraseBack();
+ p.eraseBack();
+ p.addBack(a2);
+ check(!cp.empty(), "Wrong empty()");
+ check(cp.length() == 2, "Wrong length");
+ check(cp.front() == a1, "Wrong front()");
+ check(cp.back() == a2, "Wrong back()");
+ check(pathSource(cgr, cp) == n1, "Wrong pathSource()");
+ check(pathTarget(cgr, cp) == n3, "Wrong pathTarget()");
+ check(checkPath(cgr, cp), "Wrong checkPath()");
+
+ // Check clear()
+ p.clear();
+ check(cp.empty(), "The path is not empty");
+ check(cp.length() == 0, "The path is not empty");
+
+ // Check inconsistent path
+ p.addBack(a4);
+ p.addBack(a2);
+ p.addBack(a1);
+ check(!cp.empty(), "Wrong empty()");
+ check(cp.length() == 3, "Wrong length");
+ check(cp.front() == a4, "Wrong front()");
+ check(cp.back() == a1, "Wrong back()");
+ check(pathSource(cgr, cp) == n4, "Wrong pathSource()");
+ check(pathTarget(cgr, cp) == n2, "Wrong pathTarget()");
+ check(!checkPath(cgr, cp), "Wrong checkPath()");
+ }
+
+ template <typename P>
+ void checkBackAndFrontInsertablePath() {
+
+ // Include back insertable test cases
+ checkBackInsertablePath<P>();
+
+ // Check front and back insertion
+ P p;
+ const P& cp = p;
+ p.addFront(a4);
+ p.addBack(a1);
+ p.addFront(a3);
+ check(!cp.empty(), "Wrong empty()");
+ check(cp.length() == 3, "Wrong length");
+ check(cp.front() == a3, "Wrong front()");
+ check(cp.back() == a1, "Wrong back()");
+ check(cp.nth(0) == a3, "Wrong nth()");
+ check(cp.nth(1) == a4, "Wrong nth()");
+ check(cp.nth(2) == a1, "Wrong nth()");
+ typename P::ArcIt ai(cp);
+ check((tmp_a = ai) == a3, "Wrong ArcIt");
+ check((tmp_a = ++ai) == a4, "Wrong nthIt()");
+ check((tmp_a = ++ai) == a1, "Wrong nthIt()");
+ check(++ai == INVALID, "Wrong nthIt()");
+ ai = cp.nthIt(0);
+ check((tmp_a = ai) == a3, "Wrong nthIt()");
+ check((tmp_a = ++ai) == a4, "Wrong nthIt()");
+ ai = cp.nthIt(2);
+ check((tmp_a = ai) == a1, "Wrong nthIt()");
+ check(++ai == INVALID, "Wrong nthIt()");
+ check(pathSource(cgr, cp) == n3, "Wrong pathSource()");
+ check(pathTarget(cgr, cp) == n2, "Wrong pathTarget()");
+ check(checkPath(cgr, cp), "Wrong checkPath()");
+
+ // Check eraseFront()
+ p.eraseFront();
+ p.addBack(a2);
+ check(!cp.empty(), "Wrong empty()");
+ check(cp.length() == 3, "Wrong length");
+ check(cp.front() == a4, "Wrong front()");
+ check(cp.back() == a2, "Wrong back()");
+ check(cp.nth(0) == a4, "Wrong nth()");
+ check(cp.nth(1) == a1, "Wrong nth()");
+ check(cp.nth(2) == a2, "Wrong nth()");
+ typename P::ArcIt ai2(cp);
+ check((tmp_a = ai2) == a4, "Wrong ArcIt");
+ check((tmp_a = ++ai2) == a1, "Wrong nthIt()");
+ check((tmp_a = ++ai2) == a2, "Wrong nthIt()");
+ check(++ai2 == INVALID, "Wrong nthIt()");
+ ai = cp.nthIt(0);
+ check((tmp_a = ai) == a4, "Wrong nthIt()");
+ check((tmp_a = ++ai) == a1, "Wrong nthIt()");
+ ai = cp.nthIt(2);
+ check((tmp_a = ai) == a2, "Wrong nthIt()");
+ check(++ai == INVALID, "Wrong nthIt()");
+ check(pathSource(cgr, cp) == n4, "Wrong pathSource()");
+ check(pathTarget(cgr, cp) == n3, "Wrong pathTarget()");
+ check(checkPath(cgr, cp), "Wrong checkPath()");
+ }
+
+ void checkListPathSplitAndSplice() {
+
+ // Build a path with spliceFront() and spliceBack()
+ ListPath<GR> p1, p2, p3, p4;
+ p1.addBack(a3);
+ p1.addFront(a2);
+ p2.addBack(a1);
+ p1.spliceFront(p2);
+ p3.addFront(a4);
+ p1.spliceBack(p3);
+ check(p1.length() == 4, "Wrong length");
+ check(p1.front() == a1, "Wrong front()");
+ check(p1.back() == a4, "Wrong back()");
+ ListPath<GR>::ArcIt ai(p1);
+ check((tmp_a = ai) == a1, "Wrong ArcIt");
+ check((tmp_a = ++ai) == a2, "Wrong nthIt()");
+ check((tmp_a = ++ai) == a3, "Wrong nthIt()");
+ check((tmp_a = ++ai) == a4, "Wrong nthIt()");
+ check(++ai == INVALID, "Wrong nthIt()");
+ check(checkPath(cgr, p1), "Wrong checkPath()");
+
+ // Check split()
+ p1.split(p1.nthIt(2), p2);
+ check(p1.length() == 2, "Wrong length");
+ ai = p1.nthIt(0);
+ check((tmp_a = ai) == a1, "Wrong ArcIt");
+ check((tmp_a = ++ai) == a2, "Wrong nthIt()");
+ check(++ai == INVALID, "Wrong nthIt()");
+ check(checkPath(cgr, p1), "Wrong checkPath()");
+ check(p2.length() == 2, "Wrong length");
+ ai = p2.nthIt(0);
+ check((tmp_a = ai) == a3, "Wrong ArcIt");
+ check((tmp_a = ++ai) == a4, "Wrong nthIt()");
+ check(++ai == INVALID, "Wrong nthIt()");
+ check(checkPath(cgr, p2), "Wrong checkPath()");
+
+ // Check split() and splice()
+ p1.spliceFront(p2);
+ p1.split(p1.nthIt(2), p2);
+ p2.split(p2.nthIt(1), p3);
+ p2.spliceBack(p1);
+ p2.splice(p2.nthIt(1), p3);
+ check(p2.length() == 4, "Wrong length");
+ check(p2.front() == a1, "Wrong front()");
+ check(p2.back() == a4, "Wrong back()");
+ ai = p2.nthIt(0);
+ check((tmp_a = ai) == a1, "Wrong ArcIt");
+ check((tmp_a = ++ai) == a2, "Wrong nthIt()");
+ check((tmp_a = ++ai) == a3, "Wrong nthIt()");
+ check((tmp_a = ++ai) == a4, "Wrong nthIt()");
+ check(++ai == INVALID, "Wrong nthIt()");
+ check(checkPath(cgr, p2), "Wrong checkPath()");
+ }
+
+};
+
+int main() {
+ checkPathConcepts();
+ checkPathCopy();
+ CheckPathFunctions cpf;
+ cpf.run();
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/planarity_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/planarity_test.cc
new file mode 100644
index 00000000000..0ac11eebba1
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/planarity_test.cc
@@ -0,0 +1,262 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <iostream>
+
+#include <lemon/planarity.h>
+
+#include <lemon/smart_graph.h>
+#include <lemon/lgf_reader.h>
+#include <lemon/connectivity.h>
+#include <lemon/dim2.h>
+
+#include "test_tools.h"
+
+using namespace lemon;
+using namespace lemon::dim2;
+
+const int lgfn = 4;
+const std::string lgf[lgfn] = {
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "@edges\n"
+ " label\n"
+ "0 1 0\n"
+ "0 2 0\n"
+ "0 3 0\n"
+ "0 4 0\n"
+ "1 2 0\n"
+ "1 3 0\n"
+ "1 4 0\n"
+ "2 3 0\n"
+ "2 4 0\n"
+ "3 4 0\n",
+
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "@edges\n"
+ " label\n"
+ "0 1 0\n"
+ "0 2 0\n"
+ "0 3 0\n"
+ "0 4 0\n"
+ "1 2 0\n"
+ "1 3 0\n"
+ "2 3 0\n"
+ "2 4 0\n"
+ "3 4 0\n",
+
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "5\n"
+ "@edges\n"
+ " label\n"
+ "0 3 0\n"
+ "0 4 0\n"
+ "0 5 0\n"
+ "1 3 0\n"
+ "1 4 0\n"
+ "1 5 0\n"
+ "2 3 0\n"
+ "2 4 0\n"
+ "2 5 0\n",
+
+ "@nodes\n"
+ "label\n"
+ "0\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "5\n"
+ "@edges\n"
+ " label\n"
+ "0 3 0\n"
+ "0 4 0\n"
+ "0 5 0\n"
+ "1 3 0\n"
+ "1 4 0\n"
+ "1 5 0\n"
+ "2 3 0\n"
+ "2 5 0\n"
+};
+
+
+
+typedef SmartGraph Graph;
+GRAPH_TYPEDEFS(Graph);
+
+typedef PlanarEmbedding<SmartGraph> PE;
+typedef PlanarDrawing<SmartGraph> PD;
+typedef PlanarColoring<SmartGraph> PC;
+
+void checkEmbedding(const Graph& graph, PE& pe) {
+ int face_num = 0;
+
+ Graph::ArcMap<int> face(graph, -1);
+
+ for (ArcIt a(graph); a != INVALID; ++a) {
+ if (face[a] == -1) {
+ Arc b = a;
+ while (face[b] == -1) {
+ face[b] = face_num;
+ b = pe.next(graph.oppositeArc(b));
+ }
+ check(face[b] == face_num, "Wrong face");
+ ++face_num;
+ }
+ }
+ check(face_num + countNodes(graph) - countConnectedComponents(graph) ==
+ countEdges(graph) + 1, "Euler test does not passed");
+}
+
+void checkKuratowski(const Graph& graph, PE& pe) {
+ std::map<int, int> degs;
+ for (NodeIt n(graph); n != INVALID; ++n) {
+ int deg = 0;
+ for (IncEdgeIt e(graph, n); e != INVALID; ++e) {
+ if (pe.kuratowski(e)) {
+ ++deg;
+ }
+ }
+ ++degs[deg];
+ }
+ for (std::map<int, int>::iterator it = degs.begin(); it != degs.end(); ++it) {
+ check(it->first == 0 || it->first == 2 ||
+ (it->first == 3 && it->second == 6) ||
+ (it->first == 4 && it->second == 5),
+ "Wrong degree in Kuratowski graph");
+ }
+
+ // Not full test
+ check((degs[3] == 0) != (degs[4] == 0), "Wrong Kuratowski graph");
+}
+
+bool intersect(Point<int> e1, Point<int> e2, Point<int> f1, Point<int> f2) {
+ int l, r;
+ if (std::min(e1.x, e2.x) > std::max(f1.x, f2.x)) return false;
+ if (std::max(e1.x, e2.x) < std::min(f1.x, f2.x)) return false;
+ if (std::min(e1.y, e2.y) > std::max(f1.y, f2.y)) return false;
+ if (std::max(e1.y, e2.y) < std::min(f1.y, f2.y)) return false;
+
+ l = (e2.x - e1.x) * (f1.y - e1.y) - (e2.y - e1.y) * (f1.x - e1.x);
+ r = (e2.x - e1.x) * (f2.y - e1.y) - (e2.y - e1.y) * (f2.x - e1.x);
+ if (!((l >= 0 && r <= 0) || (l <= 0 && r >= 0))) return false;
+ l = (f2.x - f1.x) * (e1.y - f1.y) - (f2.y - f1.y) * (e1.x - f1.x);
+ r = (f2.x - f1.x) * (e2.y - f1.y) - (f2.y - f1.y) * (e2.x - f1.x);
+ if (!((l >= 0 && r <= 0) || (l <= 0 && r >= 0))) return false;
+ return true;
+}
+
+bool collinear(Point<int> p, Point<int> q, Point<int> r) {
+ int v;
+ v = (q.x - p.x) * (r.y - p.y) - (q.y - p.y) * (r.x - p.x);
+ if (v != 0) return false;
+ v = (q.x - p.x) * (r.x - p.x) + (q.y - p.y) * (r.y - p.y);
+ if (v < 0) return false;
+ return true;
+}
+
+void checkDrawing(const Graph& graph, PD& pd) {
+ for (Graph::NodeIt n(graph); n != INVALID; ++n) {
+ Graph::NodeIt m(n);
+ for (++m; m != INVALID; ++m) {
+ check(pd[m] != pd[n], "Two nodes with identical coordinates");
+ }
+ }
+
+ for (Graph::EdgeIt e(graph); e != INVALID; ++e) {
+ for (Graph::EdgeIt f(e); f != e; ++f) {
+ Point<int> e1 = pd[graph.u(e)];
+ Point<int> e2 = pd[graph.v(e)];
+ Point<int> f1 = pd[graph.u(f)];
+ Point<int> f2 = pd[graph.v(f)];
+
+ if (graph.u(e) == graph.u(f)) {
+ check(!collinear(e1, e2, f2), "Wrong drawing");
+ } else if (graph.u(e) == graph.v(f)) {
+ check(!collinear(e1, e2, f1), "Wrong drawing");
+ } else if (graph.v(e) == graph.u(f)) {
+ check(!collinear(e2, e1, f2), "Wrong drawing");
+ } else if (graph.v(e) == graph.v(f)) {
+ check(!collinear(e2, e1, f1), "Wrong drawing");
+ } else {
+ check(!intersect(e1, e2, f1, f2), "Wrong drawing");
+ }
+ }
+ }
+}
+
+void checkColoring(const Graph& graph, PC& pc, int num) {
+ for (NodeIt n(graph); n != INVALID; ++n) {
+ check(pc.colorIndex(n) >= 0 && pc.colorIndex(n) < num,
+ "Wrong coloring");
+ }
+ for (EdgeIt e(graph); e != INVALID; ++e) {
+ check(pc.colorIndex(graph.u(e)) != pc.colorIndex(graph.v(e)),
+ "Wrong coloring");
+ }
+}
+
+int main() {
+
+ for (int i = 0; i < lgfn; ++i) {
+ std::istringstream lgfs(lgf[i]);
+
+ SmartGraph graph;
+ graphReader(graph, lgfs).run();
+
+ check(simpleGraph(graph), "Test graphs must be simple");
+
+ PE pe(graph);
+ bool planar = pe.run();
+ check(checkPlanarity(graph) == planar, "Planarity checking failed");
+
+ if (planar) {
+ checkEmbedding(graph, pe);
+
+ PlanarDrawing<Graph> pd(graph);
+ pd.run(pe.embeddingMap());
+ checkDrawing(graph, pd);
+
+ PlanarColoring<Graph> pc(graph);
+ pc.runFiveColoring(pe.embeddingMap());
+ checkColoring(graph, pc, 5);
+
+ } else {
+ checkKuratowski(graph, pe);
+ }
+ }
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/radix_sort_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/radix_sort_test.cc
new file mode 100644
index 00000000000..6ae2debfa84
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/radix_sort_test.cc
@@ -0,0 +1,266 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <lemon/time_measure.h>
+#include <lemon/smart_graph.h>
+#include <lemon/maps.h>
+#include <lemon/radix_sort.h>
+#include <lemon/math.h>
+
+#include "test_tools.h"
+
+#include <vector>
+#include <list>
+#include <algorithm>
+
+using namespace lemon;
+
+static const int n = 10000;
+
+struct Negate {
+ typedef int argument_type;
+ typedef int result_type;
+ int operator()(int a) { return - a; }
+};
+
+int negate(int a) { return - a; }
+
+template<class T>
+bool isTheSame(T &a, T&b)
+{
+ typename T::iterator ai=a.begin();
+ typename T::iterator bi=b.begin();
+ for(;ai!=a.end()||bi!=b.end();++ai,++bi)
+ if(*ai!=*bi) return false;
+ return ai==a.end()&&bi==b.end();
+}
+
+template<class T>
+T listsort(typename T::iterator b, typename T::iterator e)
+{
+ if(b==e) return T();
+ typename T::iterator bn=b;
+ if(++bn==e) {
+ T l;
+ l.push_back(*b);
+ return l;
+ }
+ typename T::iterator m=b;
+ bool x=false;
+ for(typename T::iterator i=b;i!=e;++i,x=!x)
+ if(x) ++m;
+ T l1(listsort<T>(b,m));
+ T l2(listsort<T>(m,e));
+ T l;
+ while((!l1.empty())&&(!l2.empty()))
+ if(l1.front()<=l2.front())
+ {
+ l.push_back(l1.front());
+ l1.pop_front();
+ }
+ else {
+ l.push_back(l2.front());
+ l2.pop_front();
+ }
+ while(!l1.empty())
+ {
+ l.push_back(l1.front());
+ l1.pop_front();
+ }
+ while(!l2.empty())
+ {
+ l.push_back(l2.front());
+ l2.pop_front();
+ }
+ return l;
+}
+
+template<class T>
+void generateIntSequence(int n, T & data) {
+ int prime = 9973;
+ int root = 136, value = 1;
+ for (int i = 0; i < n; ++i) {
+ data.push_back(value - prime / 2);
+ value = (value * root) % prime;
+ }
+}
+
+template<class T>
+void generateCharSequence(int n, T & data) {
+ int prime = 251;
+ int root = 3, value = root;
+ for (int i = 0; i < n; ++i) {
+ data.push_back(static_cast<unsigned char>(value));
+ value = (value * root) % prime;
+ }
+}
+
+void checkRadixSort() {
+ {
+ std::vector<int> data1;
+ generateIntSequence(n, data1);
+
+ std::vector<int> data2(data1);
+ std::sort(data1.begin(), data1.end());
+
+ radixSort(data2.begin(), data2.end());
+ for (int i = 0; i < n; ++i) {
+ check(data1[i] == data2[i], "Test failed");
+ }
+
+ // radixSort(data2.begin(), data2.end(), Negate());
+ // for (int i = 0; i < n; ++i) {
+ // check(data1[i] == data2[n - 1 - i], "Test failed");
+ // }
+
+ // radixSort(data2.begin(), data2.end(), negate);
+ // for (int i = 0; i < n; ++i) {
+ // check(data1[i] == data2[n - 1 - i], "Test failed");
+ // }
+
+ }
+
+ {
+ std::vector<unsigned char> data1(n);
+ generateCharSequence(n, data1);
+
+ std::vector<unsigned char> data2(data1);
+ std::sort(data1.begin(), data1.end());
+
+ radixSort(data2.begin(), data2.end());
+ for (int i = 0; i < n; ++i) {
+ check(data1[i] == data2[i], "Test failed");
+ }
+
+ }
+ {
+ std::list<int> data1;
+ generateIntSequence(n, data1);
+
+ std::list<int> data2(listsort<std::list<int> >(data1.begin(), data1.end()));
+
+ radixSort(data1.begin(), data1.end());
+
+ check(isTheSame(data1,data2), "Test failed");
+
+
+ // radixSort(data2.begin(), data2.end(), Negate());
+ // check(isTheSame(data1,data2), "Test failed");
+ // for (int i = 0; i < n; ++i) {
+ // check(data1[i] == data2[n - 1 - i], "Test failed");
+ // }
+
+ // radixSort(data2.begin(), data2.end(), negate);
+ // for (int i = 0; i < n; ++i) {
+ // check(data1[i] == data2[n - 1 - i], "Test failed");
+ // }
+
+ }
+
+ {
+ std::list<unsigned char> data1(n);
+ generateCharSequence(n, data1);
+
+ std::list<unsigned char> data2(listsort<std::list<unsigned char> >
+ (data1.begin(),
+ data1.end()));
+
+ radixSort(data1.begin(), data1.end());
+ check(isTheSame(data1,data2), "Test failed");
+
+ }
+}
+
+
+void checkStableRadixSort() {
+ {
+ std::vector<int> data1;
+ generateIntSequence(n, data1);
+
+ std::vector<int> data2(data1);
+ std::sort(data1.begin(), data1.end());
+
+ stableRadixSort(data2.begin(), data2.end());
+ for (int i = 0; i < n; ++i) {
+ check(data1[i] == data2[i], "Test failed");
+ }
+
+ stableRadixSort(data2.begin(), data2.end(), Negate());
+ for (int i = 0; i < n; ++i) {
+ check(data1[i] == data2[n - 1 - i], "Test failed");
+ }
+
+ stableRadixSort(data2.begin(), data2.end(), negate);
+ for (int i = 0; i < n; ++i) {
+ check(data1[i] == data2[n - 1 - i], "Test failed");
+ }
+ }
+
+ {
+ std::vector<unsigned char> data1(n);
+ generateCharSequence(n, data1);
+
+ std::vector<unsigned char> data2(data1);
+ std::sort(data1.begin(), data1.end());
+
+ radixSort(data2.begin(), data2.end());
+ for (int i = 0; i < n; ++i) {
+ check(data1[i] == data2[i], "Test failed");
+ }
+
+ }
+ {
+ std::list<int> data1;
+ generateIntSequence(n, data1);
+
+ std::list<int> data2(listsort<std::list<int> >(data1.begin(),
+ data1.end()));
+ stableRadixSort(data1.begin(), data1.end());
+ check(isTheSame(data1,data2), "Test failed");
+
+ // stableRadixSort(data2.begin(), data2.end(), Negate());
+ // for (int i = 0; i < n; ++i) {
+ // check(data1[i] == data2[n - 1 - i], "Test failed");
+ // }
+
+ // stableRadixSort(data2.begin(), data2.end(), negate);
+ // for (int i = 0; i < n; ++i) {
+ // check(data1[i] == data2[n - 1 - i], "Test failed");
+ // }
+ }
+
+ {
+ std::list<unsigned char> data1(n);
+ generateCharSequence(n, data1);
+
+ std::list<unsigned char> data2(listsort<std::list<unsigned char> >
+ (data1.begin(),
+ data1.end()));
+ radixSort(data1.begin(), data1.end());
+ check(isTheSame(data1,data2), "Test failed");
+
+ }
+}
+
+int main() {
+
+ checkRadixSort();
+ checkStableRadixSort();
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/random_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/random_test.cc
new file mode 100644
index 00000000000..49dd8b60398
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/random_test.cc
@@ -0,0 +1,40 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <lemon/random.h>
+#include "test_tools.h"
+
+int seed_array[] = {1, 2};
+
+int main()
+{
+ double a=lemon::rnd();
+ check(a<1.0&&a>0.0,"This should be in [0,1)");
+ a=lemon::rnd.gauss();
+ a=lemon::rnd.gamma(3.45,0);
+ a=lemon::rnd.gamma(4);
+ //Does gamma work with integer k?
+ a=lemon::rnd.gamma(4.0,0);
+ a=lemon::rnd.poisson(.5);
+
+ lemon::rnd.seed(100);
+ lemon::rnd.seed(seed_array, seed_array +
+ (sizeof(seed_array) / sizeof(seed_array[0])));
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/suurballe_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/suurballe_test.cc
new file mode 100644
index 00000000000..7c00f212ac0
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/suurballe_test.cc
@@ -0,0 +1,267 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <iostream>
+
+#include <lemon/list_graph.h>
+#include <lemon/lgf_reader.h>
+#include <lemon/path.h>
+#include <lemon/suurballe.h>
+#include <lemon/concepts/digraph.h>
+#include <lemon/concepts/heap.h>
+
+#include "test_tools.h"
+
+using namespace lemon;
+
+char test_lgf[] =
+ "@nodes\n"
+ "label\n"
+ "1\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "5\n"
+ "6\n"
+ "7\n"
+ "8\n"
+ "9\n"
+ "10\n"
+ "11\n"
+ "12\n"
+ "@arcs\n"
+ " length\n"
+ " 1 2 70\n"
+ " 1 3 150\n"
+ " 1 4 80\n"
+ " 2 8 80\n"
+ " 3 5 140\n"
+ " 4 6 60\n"
+ " 4 7 80\n"
+ " 4 8 110\n"
+ " 5 7 60\n"
+ " 5 11 120\n"
+ " 6 3 0\n"
+ " 6 9 140\n"
+ " 6 10 90\n"
+ " 7 1 30\n"
+ " 8 12 60\n"
+ " 9 12 50\n"
+ "10 12 70\n"
+ "10 2 100\n"
+ "10 7 60\n"
+ "11 10 20\n"
+ "12 11 30\n"
+ "@attributes\n"
+ "source 1\n"
+ "target 12\n"
+ "@end\n";
+
+// Check the interface of Suurballe
+void checkSuurballeCompile()
+{
+ typedef int VType;
+ typedef concepts::Digraph Digraph;
+
+ typedef Digraph::Node Node;
+ typedef Digraph::Arc Arc;
+ typedef concepts::ReadMap<Arc, VType> LengthMap;
+
+ typedef Suurballe<Digraph, LengthMap> ST;
+ typedef Suurballe<Digraph, LengthMap>
+ ::SetFlowMap<ST::FlowMap>
+ ::SetPotentialMap<ST::PotentialMap>
+ ::SetPath<SimplePath<Digraph> >
+ ::SetHeap<concepts::Heap<VType, Digraph::NodeMap<int> > >
+ ::Create SuurballeType;
+
+ Digraph g;
+ Node n;
+ Arc e;
+ LengthMap len;
+ SuurballeType::FlowMap flow(g);
+ SuurballeType::PotentialMap pi(g);
+
+ SuurballeType suurb_test(g, len);
+ const SuurballeType& const_suurb_test = suurb_test;
+
+ suurb_test
+ .flowMap(flow)
+ .potentialMap(pi);
+
+ int k;
+ k = suurb_test.run(n, n);
+ k = suurb_test.run(n, n, k);
+ suurb_test.init(n);
+ suurb_test.fullInit(n);
+ suurb_test.start(n);
+ suurb_test.start(n, k);
+ k = suurb_test.findFlow(n);
+ k = suurb_test.findFlow(n, k);
+ suurb_test.findPaths();
+
+ int f;
+ VType c;
+ ::lemon::ignore_unused_variable_warning(f,c);
+
+ c = const_suurb_test.totalLength();
+ f = const_suurb_test.flow(e);
+ const SuurballeType::FlowMap& fm =
+ const_suurb_test.flowMap();
+ c = const_suurb_test.potential(n);
+ const SuurballeType::PotentialMap& pm =
+ const_suurb_test.potentialMap();
+ k = const_suurb_test.pathNum();
+ Path<Digraph> p = const_suurb_test.path(k);
+
+ ::lemon::ignore_unused_variable_warning(fm);
+ ::lemon::ignore_unused_variable_warning(pm);
+}
+
+// Check the feasibility of the flow
+template <typename Digraph, typename FlowMap>
+bool checkFlow( const Digraph& gr, const FlowMap& flow,
+ typename Digraph::Node s, typename Digraph::Node t,
+ int value )
+{
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+ for (ArcIt e(gr); e != INVALID; ++e)
+ if (!(flow[e] == 0 || flow[e] == 1)) return false;
+
+ for (NodeIt n(gr); n != INVALID; ++n) {
+ int sum = 0;
+ for (OutArcIt e(gr, n); e != INVALID; ++e)
+ sum += flow[e];
+ for (InArcIt e(gr, n); e != INVALID; ++e)
+ sum -= flow[e];
+ if (n == s && sum != value) return false;
+ if (n == t && sum != -value) return false;
+ if (n != s && n != t && sum != 0) return false;
+ }
+
+ return true;
+}
+
+// Check the optimalitiy of the flow
+template < typename Digraph, typename CostMap,
+ typename FlowMap, typename PotentialMap >
+bool checkOptimality( const Digraph& gr, const CostMap& cost,
+ const FlowMap& flow, const PotentialMap& pi )
+{
+ // Check the "Complementary Slackness" optimality condition
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+ bool opt = true;
+ for (ArcIt e(gr); e != INVALID; ++e) {
+ typename CostMap::Value red_cost =
+ cost[e] + pi[gr.source(e)] - pi[gr.target(e)];
+ opt = (flow[e] == 0 && red_cost >= 0) ||
+ (flow[e] == 1 && red_cost <= 0);
+ if (!opt) break;
+ }
+ return opt;
+}
+
+// Check a path
+template <typename Digraph, typename Path>
+bool checkPath( const Digraph& gr, const Path& path,
+ typename Digraph::Node s, typename Digraph::Node t)
+{
+ TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
+ Node n = s;
+ for (int i = 0; i < path.length(); ++i) {
+ if (gr.source(path.nth(i)) != n) return false;
+ n = gr.target(path.nth(i));
+ }
+ return n == t;
+}
+
+
+int main()
+{
+ DIGRAPH_TYPEDEFS(ListDigraph);
+
+ // Read the test digraph
+ ListDigraph digraph;
+ ListDigraph::ArcMap<int> length(digraph);
+ Node s, t;
+
+ std::istringstream input(test_lgf);
+ DigraphReader<ListDigraph>(digraph, input).
+ arcMap("length", length).
+ node("source", s).
+ node("target", t).
+ run();
+
+ // Check run()
+ {
+ Suurballe<ListDigraph> suurballe(digraph, length);
+
+ // Find 2 paths
+ check(suurballe.run(s, t) == 2, "Wrong number of paths");
+ check(checkFlow(digraph, suurballe.flowMap(), s, t, 2),
+ "The flow is not feasible");
+ check(suurballe.totalLength() == 510, "The flow is not optimal");
+ check(checkOptimality(digraph, length, suurballe.flowMap(),
+ suurballe.potentialMap()),
+ "Wrong potentials");
+ for (int i = 0; i < suurballe.pathNum(); ++i)
+ check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path");
+
+ // Find 3 paths
+ check(suurballe.run(s, t, 3) == 3, "Wrong number of paths");
+ check(checkFlow(digraph, suurballe.flowMap(), s, t, 3),
+ "The flow is not feasible");
+ check(suurballe.totalLength() == 1040, "The flow is not optimal");
+ check(checkOptimality(digraph, length, suurballe.flowMap(),
+ suurballe.potentialMap()),
+ "Wrong potentials");
+ for (int i = 0; i < suurballe.pathNum(); ++i)
+ check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path");
+
+ // Find 5 paths (only 3 can be found)
+ check(suurballe.run(s, t, 5) == 3, "Wrong number of paths");
+ check(checkFlow(digraph, suurballe.flowMap(), s, t, 3),
+ "The flow is not feasible");
+ check(suurballe.totalLength() == 1040, "The flow is not optimal");
+ check(checkOptimality(digraph, length, suurballe.flowMap(),
+ suurballe.potentialMap()),
+ "Wrong potentials");
+ for (int i = 0; i < suurballe.pathNum(); ++i)
+ check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path");
+ }
+
+ // Check fullInit() + start()
+ {
+ Suurballe<ListDigraph> suurballe(digraph, length);
+ suurballe.fullInit(s);
+
+ // Find 2 paths
+ check(suurballe.start(t) == 2, "Wrong number of paths");
+ check(suurballe.totalLength() == 510, "The flow is not optimal");
+
+ // Find 3 paths
+ check(suurballe.start(t, 3) == 3, "Wrong number of paths");
+ check(suurballe.totalLength() == 1040, "The flow is not optimal");
+
+ // Find 5 paths (only 3 can be found)
+ check(suurballe.start(t, 5) == 3, "Wrong number of paths");
+ check(suurballe.totalLength() == 1040, "The flow is not optimal");
+ }
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/test_tools.h b/extern/quadriflow/3rd/lemon-1.3.1/test/test_tools.h
new file mode 100644
index 00000000000..33003566791
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/test_tools.h
@@ -0,0 +1,50 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2010
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_TEST_TEST_TOOLS_H
+#define LEMON_TEST_TEST_TOOLS_H
+
+///\ingroup misc
+///\file
+///\brief Some utilities to write test programs.
+
+#include <iostream>
+#include <stdlib.h>
+
+///If \c rc is fail, writes an error message and exits.
+
+///If \c rc is fail, writes an error message and exits.
+///The error message contains the file name and the line number of the
+///source code in a standard from, which makes it possible to go there
+///using good source browsers like e.g. \c emacs.
+///
+///For example
+///\code check(0==1,"This is obviously false.");\endcode will
+///print something like this (and then exits).
+///\verbatim file_name.cc:123: error: This is obviously false. \endverbatim
+#define check(rc, msg) \
+ { \
+ if(!(rc)) { \
+ std::cerr << __FILE__ ":" << __LINE__ << ": error: " \
+ << msg << std::endl; \
+ abort(); \
+ } else { } \
+ } \
+
+
+#endif
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/test_tools_fail.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/test_tools_fail.cc
new file mode 100644
index 00000000000..6407cd15b04
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/test_tools_fail.cc
@@ -0,0 +1,25 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include "test_tools.h"
+
+int main()
+{
+ check(false, "Don't panic. Failing is the right behaviour here.");
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/test_tools_pass.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/test_tools_pass.cc
new file mode 100644
index 00000000000..b590c15a614
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/test_tools_pass.cc
@@ -0,0 +1,25 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include "test_tools.h"
+
+int main()
+{
+ check(true, "It should pass.");
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/time_measure_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/time_measure_test.cc
new file mode 100644
index 00000000000..4e7155a91ba
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/time_measure_test.cc
@@ -0,0 +1,60 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <lemon/time_measure.h>
+#include <lemon/concept_check.h>
+
+using namespace lemon;
+
+void f()
+{
+ double d=0;
+ for(int i=0;i<1000;i++)
+ d+=0.1;
+}
+
+void g()
+{
+ static Timer T;
+
+ for(int i=0;i<1000;i++)
+ {
+ TimeStamp x(T);
+ ::lemon::ignore_unused_variable_warning(x);
+ }
+}
+
+int main()
+{
+ Timer T;
+ unsigned int n;
+ for(n=0;T.realTime()<0.1;n++) ;
+ std::cout << T << " (" << n << " time queries)\n";
+
+ TimeStamp full;
+ TimeStamp t;
+ t=runningTimeTest(f,0.1,&n,&full);
+ std::cout << t << " (" << n << " tests)\n";
+ std::cout << "Total: " << full << "\n";
+
+ t=runningTimeTest(g,0.1,&n,&full);
+ std::cout << t << " (" << n << " tests)\n";
+ std::cout << "Total: " << full << "\n";
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/tsp_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/tsp_test.cc
new file mode 100644
index 00000000000..398a812e090
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/tsp_test.cc
@@ -0,0 +1,287 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <iostream>
+
+#include <lemon/full_graph.h>
+#include <lemon/math.h>
+#include <lemon/maps.h>
+#include <lemon/random.h>
+#include <lemon/dim2.h>
+
+#include <lemon/nearest_neighbor_tsp.h>
+#include <lemon/greedy_tsp.h>
+#include <lemon/insertion_tsp.h>
+#include <lemon/christofides_tsp.h>
+#include <lemon/opt2_tsp.h>
+
+#include "test_tools.h"
+
+using namespace lemon;
+
+// // Tests checkMetricCost() function
+// void metricCostTest() {
+// GRAPH_TYPEDEFS(FullGraph);
+// FullGraph g(10);
+// check(checkMetricCost(g, constMap<Edge>(0)), "Wrong checkMetricCost()");
+// check(checkMetricCost(g, constMap<Edge>(1)), "Wrong checkMetricCost()");
+// check(!checkMetricCost(g, constMap<Edge>(-1)), "Wrong checkMetricCost()");
+//
+// FullGraph::EdgeMap<float> cost(g);
+// for (NodeIt u(g); u != INVALID; ++u) {
+// for (NodeIt v(g); v != INVALID; ++v) {
+// if (u == v) continue;
+// float x1 = g.id(u), x2 = g.id(v);
+// float y1 = x1 * x1, y2 = x2 * x2;
+// cost[g.edge(u, v)] = std::sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
+// }
+// }
+// check(checkMetricCost(g, cost), "Wrong checkMetricCost()");
+// float eps = Tolerance<float>::defaultEpsilon();
+// cost[g.edge(g(0), g(9))] =
+// cost[g.edge(g(0), g(8))] + cost[g.edge(g(8), g(9))] + eps * 2;
+// check(!checkMetricCost(g, cost), "Wrong checkMetricCost()");
+// check(checkMetricCost(g, cost, Tolerance<float>(eps * 4)),
+// "Wrong checkMetricCost()");
+// }
+
+// Checks tour validity
+template <typename Container>
+bool checkTour(const FullGraph &gr, const Container &p) {
+ FullGraph::NodeMap<bool> used(gr, false);
+
+ int node_cnt = 0;
+ for (typename Container::const_iterator it = p.begin(); it != p.end(); ++it)
+ {
+ FullGraph::Node node = *it;
+ if (used[node]) return false;
+ used[node] = true;
+ ++node_cnt;
+ }
+
+ return (node_cnt == gr.nodeNum());
+}
+
+// Checks tour validity
+bool checkTourPath(const FullGraph &gr, const Path<FullGraph> &p) {
+ FullGraph::NodeMap<bool> used(gr, false);
+
+ if (!checkPath(gr, p)) return false;
+ if (gr.nodeNum() <= 1 && p.length() != 0) return false;
+ if (gr.nodeNum() > 1 && p.length() != gr.nodeNum()) return false;
+
+ for (int i = 0; i < p.length(); ++i) {
+ if (used[gr.target(p.nth(i))]) return false;
+ used[gr.target(p.nth(i))] = true;
+ }
+ return true;
+}
+
+// Checks tour cost
+template <typename CostMap>
+bool checkCost(const FullGraph &gr, const std::vector<FullGraph::Node> &p,
+ const CostMap &cost, typename CostMap::Value total)
+{
+ typedef typename CostMap::Value Cost;
+
+ Cost s = 0;
+ for (int i = 0; i < int(p.size()) - 1; ++i)
+ s += cost[gr.edge(p[i], p[i+1])];
+ if (int(p.size()) >= 2)
+ s += cost[gr.edge(p.back(), p.front())];
+
+ return !Tolerance<Cost>().different(s, total);
+}
+
+// Checks tour cost
+template <typename CostMap>
+bool checkCost(const FullGraph &, const Path<FullGraph> &p,
+ const CostMap &cost, typename CostMap::Value total)
+{
+ typedef typename CostMap::Value Cost;
+
+ Cost s = 0;
+ for (int i = 0; i < p.length(); ++i)
+ s += cost[p.nth(i)];
+
+ return !Tolerance<Cost>().different(s, total);
+}
+
+// Tests a TSP algorithm on small graphs
+template <typename TSP>
+void tspTestSmall(const std::string &alg_name) {
+ GRAPH_TYPEDEFS(FullGraph);
+
+ for (int n = 0; n <= 5; ++n) {
+ FullGraph g(n);
+ unsigned nsize = n;
+ int esize = n <= 1 ? 0 : n;
+
+ ConstMap<Edge, int> cost_map(1);
+ TSP alg(g, cost_map);
+
+ check(alg.run() == esize, alg_name + ": Wrong total cost");
+ check(alg.tourCost() == esize, alg_name + ": Wrong total cost");
+
+ std::list<Node> list1(nsize), list2;
+ std::vector<Node> vec1(nsize), vec2;
+ alg.tourNodes(list1.begin());
+ alg.tourNodes(vec1.begin());
+ alg.tourNodes(std::front_inserter(list2));
+ alg.tourNodes(std::back_inserter(vec2));
+ check(checkTour(g, alg.tourNodes()), alg_name + ": Wrong node sequence");
+ check(checkTour(g, list1), alg_name + ": Wrong node sequence");
+ check(checkTour(g, vec1), alg_name + ": Wrong node sequence");
+ check(checkTour(g, list2), alg_name + ": Wrong node sequence");
+ check(checkTour(g, vec2), alg_name + ": Wrong node sequence");
+ check(checkCost(g, vec1, constMap<Edge, int>(1), esize),
+ alg_name + ": Wrong tour cost");
+
+ SimplePath<FullGraph> path;
+ alg.tour(path);
+ check(path.length() == esize, alg_name + ": Wrong tour");
+ check(checkTourPath(g, path), alg_name + ": Wrong tour");
+ check(checkCost(g, path, constMap<Edge, int>(1), esize),
+ alg_name + ": Wrong tour cost");
+ }
+}
+
+// Tests a TSP algorithm on random graphs
+template <typename TSP>
+void tspTestRandom(const std::string &alg_name) {
+ GRAPH_TYPEDEFS(FullGraph);
+
+ FullGraph g(20);
+ FullGraph::NodeMap<dim2::Point<double> > pos(g);
+ DoubleEdgeMap cost(g);
+
+ TSP alg(g, cost);
+ Opt2Tsp<DoubleEdgeMap > opt2(g, cost);
+
+ for (int i = 1; i <= 3; i++) {
+ for (NodeIt u(g); u != INVALID; ++u) {
+ pos[u] = dim2::Point<double>(rnd(), rnd());
+ }
+ for (NodeIt u(g); u != INVALID; ++u) {
+ for (NodeIt v(g); v != INVALID; ++v) {
+ if (u == v) continue;
+ cost[g.edge(u, v)] = (pos[u] - pos[v]).normSquare();
+ }
+ }
+
+ check(alg.run() > 0, alg_name + ": Wrong total cost");
+
+ std::vector<Node> vec;
+ alg.tourNodes(std::back_inserter(vec));
+ check(checkTour(g, vec), alg_name + ": Wrong node sequence");
+ check(checkCost(g, vec, cost, alg.tourCost()),
+ alg_name + ": Wrong tour cost");
+
+ SimplePath<FullGraph> path;
+ alg.tour(path);
+ check(checkTourPath(g, path), alg_name + ": Wrong tour");
+ check(checkCost(g, path, cost, alg.tourCost()),
+ alg_name + ": Wrong tour cost");
+
+ check(!Tolerance<double>().less(alg.tourCost(), opt2.run(alg.tourNodes())),
+ "2-opt improvement: Wrong total cost");
+ check(checkTour(g, opt2.tourNodes()),
+ "2-opt improvement: Wrong node sequence");
+ check(checkCost(g, opt2.tourNodes(), cost, opt2.tourCost()),
+ "2-opt improvement: Wrong tour cost");
+
+ check(!Tolerance<double>().less(alg.tourCost(), opt2.run(path)),
+ "2-opt improvement: Wrong total cost");
+ check(checkTour(g, opt2.tourNodes()),
+ "2-opt improvement: Wrong node sequence");
+ check(checkCost(g, opt2.tourNodes(), cost, opt2.tourCost()),
+ "2-opt improvement: Wrong tour cost");
+ }
+}
+
+// Algorithm class for Nearest Insertion
+template <typename CM>
+class NearestInsertionTsp : public InsertionTsp<CM> {
+public:
+ NearestInsertionTsp(const FullGraph &gr, const CM &cost)
+ : InsertionTsp<CM>(gr, cost) {}
+ typename CM::Value run() {
+ return InsertionTsp<CM>::run(InsertionTsp<CM>::NEAREST);
+ }
+};
+
+// Algorithm class for Farthest Insertion
+template <typename CM>
+class FarthestInsertionTsp : public InsertionTsp<CM> {
+public:
+ FarthestInsertionTsp(const FullGraph &gr, const CM &cost)
+ : InsertionTsp<CM>(gr, cost) {}
+ typename CM::Value run() {
+ return InsertionTsp<CM>::run(InsertionTsp<CM>::FARTHEST);
+ }
+};
+
+// Algorithm class for Cheapest Insertion
+template <typename CM>
+class CheapestInsertionTsp : public InsertionTsp<CM> {
+public:
+ CheapestInsertionTsp(const FullGraph &gr, const CM &cost)
+ : InsertionTsp<CM>(gr, cost) {}
+ typename CM::Value run() {
+ return InsertionTsp<CM>::run(InsertionTsp<CM>::CHEAPEST);
+ }
+};
+
+// Algorithm class for Random Insertion
+template <typename CM>
+class RandomInsertionTsp : public InsertionTsp<CM> {
+public:
+ RandomInsertionTsp(const FullGraph &gr, const CM &cost)
+ : InsertionTsp<CM>(gr, cost) {}
+ typename CM::Value run() {
+ return InsertionTsp<CM>::run(InsertionTsp<CM>::RANDOM);
+ }
+};
+
+int main() {
+ GRAPH_TYPEDEFS(FullGraph);
+
+ // metricCostTest();
+
+ tspTestSmall<NearestNeighborTsp<ConstMap<Edge, int> > >("Nearest Neighbor");
+ tspTestSmall<GreedyTsp<ConstMap<Edge, int> > >("Greedy");
+ tspTestSmall<NearestInsertionTsp<ConstMap<Edge, int> > >("Nearest Insertion");
+ tspTestSmall<FarthestInsertionTsp<ConstMap<Edge, int> > >
+ ("Farthest Insertion");
+ tspTestSmall<CheapestInsertionTsp<ConstMap<Edge, int> > >
+ ("Cheapest Insertion");
+ tspTestSmall<RandomInsertionTsp<ConstMap<Edge, int> > >("Random Insertion");
+ tspTestSmall<ChristofidesTsp<ConstMap<Edge, int> > >("Christofides");
+ tspTestSmall<Opt2Tsp<ConstMap<Edge, int> > >("2-opt");
+
+ tspTestRandom<NearestNeighborTsp<DoubleEdgeMap > >("Nearest Neighbor");
+ tspTestRandom<GreedyTsp<DoubleEdgeMap > >("Greedy");
+ tspTestRandom<NearestInsertionTsp<DoubleEdgeMap > >("Nearest Insertion");
+ tspTestRandom<FarthestInsertionTsp<DoubleEdgeMap > >("Farthest Insertion");
+ tspTestRandom<CheapestInsertionTsp<DoubleEdgeMap > >("Cheapest Insertion");
+ tspTestRandom<RandomInsertionTsp<DoubleEdgeMap > >("Random Insertion");
+ tspTestRandom<ChristofidesTsp<DoubleEdgeMap > >("Christofides");
+ tspTestRandom<Opt2Tsp<DoubleEdgeMap > >("2-opt");
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/unionfind_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/unionfind_test.cc
new file mode 100644
index 00000000000..e82d8e64ae7
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/test/unionfind_test.cc
@@ -0,0 +1,102 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#include <lemon/list_graph.h>
+#include <lemon/maps.h>
+#include <lemon/unionfind.h>
+#include "test_tools.h"
+
+using namespace lemon;
+using namespace std;
+
+typedef UnionFindEnum<ListGraph::NodeMap<int> > UFE;
+
+int main() {
+ ListGraph g;
+ ListGraph::NodeMap<int> base(g);
+ UFE U(base);
+ vector<ListGraph::Node> n;
+
+ for(int i=0;i<20;i++) n.push_back(g.addNode());
+
+ U.insert(n[1]);
+ U.insert(n[2]);
+
+ check(U.join(n[1],n[2]) != -1, "Something is wrong with UnionFindEnum");
+
+ U.insert(n[3]);
+ U.insert(n[4]);
+ U.insert(n[5]);
+ U.insert(n[6]);
+ U.insert(n[7]);
+
+
+ check(U.join(n[1],n[4]) != -1, "Something is wrong with UnionFindEnum");
+ check(U.join(n[2],n[4]) == -1, "Something is wrong with UnionFindEnum");
+ check(U.join(n[3],n[5]) != -1, "Something is wrong with UnionFindEnum");
+
+
+ U.insert(n[8],U.find(n[5]));
+
+
+ check(U.size(U.find(n[4])) == 3, "Something is wrong with UnionFindEnum");
+ check(U.size(U.find(n[5])) == 3, "Something is wrong with UnionFindEnum");
+ check(U.size(U.find(n[6])) == 1, "Something is wrong with UnionFindEnum");
+ check(U.size(U.find(n[2])) == 3, "Something is wrong with UnionFindEnum");
+
+
+ U.insert(n[9]);
+ U.insert(n[10],U.find(n[9]));
+
+
+ check(U.join(n[8],n[10]) != -1, "Something is wrong with UnionFindEnum");
+
+
+ check(U.size(U.find(n[4])) == 3, "Something is wrong with UnionFindEnum");
+ check(U.size(U.find(n[9])) == 5, "Something is wrong with UnionFindEnum");
+
+ check(U.size(U.find(n[8])) == 5, "Something is wrong with UnionFindEnum");
+
+ U.erase(n[9]);
+ U.erase(n[1]);
+
+ check(U.size(U.find(n[10])) == 4, "Something is wrong with UnionFindEnum");
+ check(U.size(U.find(n[2])) == 2, "Something is wrong with UnionFindEnum");
+
+ U.erase(n[6]);
+ U.split(U.find(n[8]));
+
+
+ check(U.size(U.find(n[4])) == 2, "Something is wrong with UnionFindEnum");
+ check(U.size(U.find(n[3])) == 1, "Something is wrong with UnionFindEnum");
+ check(U.size(U.find(n[2])) == 2, "Something is wrong with UnionFindEnum");
+
+
+ check(U.join(n[3],n[4]) != -1, "Something is wrong with UnionFindEnum");
+ check(U.join(n[2],n[4]) == -1, "Something is wrong with UnionFindEnum");
+
+
+ check(U.size(U.find(n[4])) == 3, "Something is wrong with UnionFindEnum");
+ check(U.size(U.find(n[3])) == 3, "Something is wrong with UnionFindEnum");
+ check(U.size(U.find(n[2])) == 3, "Something is wrong with UnionFindEnum");
+
+ U.eraseClass(U.find(n[4]));
+ U.eraseClass(U.find(n[7]));
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/tools/CMakeLists.txt b/extern/quadriflow/3rd/lemon-1.3.1/tools/CMakeLists.txt
new file mode 100644
index 00000000000..64b7df77f65
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/tools/CMakeLists.txt
@@ -0,0 +1,31 @@
+INCLUDE_DIRECTORIES(
+ ${PROJECT_SOURCE_DIR}
+ ${PROJECT_BINARY_DIR}
+)
+
+LINK_DIRECTORIES(
+ ${PROJECT_BINARY_DIR}/lemon
+)
+
+ADD_EXECUTABLE(lgf-gen lgf-gen.cc)
+TARGET_LINK_LIBRARIES(lgf-gen lemon)
+
+ADD_EXECUTABLE(dimacs-to-lgf dimacs-to-lgf.cc)
+TARGET_LINK_LIBRARIES(dimacs-to-lgf lemon)
+
+ADD_EXECUTABLE(dimacs-solver dimacs-solver.cc)
+TARGET_LINK_LIBRARIES(dimacs-solver lemon)
+
+INSTALL(
+ TARGETS lgf-gen dimacs-to-lgf dimacs-solver
+ RUNTIME DESTINATION bin
+ COMPONENT bin
+)
+
+IF(NOT WIN32)
+ INSTALL(
+ PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/lemon-0.x-to-1.x.sh
+ DESTINATION bin
+ COMPONENT bin
+ )
+ENDIF()
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/tools/dimacs-solver.cc b/extern/quadriflow/3rd/lemon-1.3.1/tools/dimacs-solver.cc
new file mode 100644
index 00000000000..60da2330e50
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/tools/dimacs-solver.cc
@@ -0,0 +1,279 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2013
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+///\ingroup tools
+///\file
+///\brief DIMACS problem solver.
+///
+/// This program solves various problems given in DIMACS format.
+///
+/// See
+/// \code
+/// dimacs-solver --help
+/// \endcode
+/// for more info on usage.
+
+#include <iostream>
+#include <fstream>
+#include <cstring>
+
+#include <lemon/smart_graph.h>
+#include <lemon/dimacs.h>
+#include <lemon/lgf_writer.h>
+#include <lemon/time_measure.h>
+
+#include <lemon/arg_parser.h>
+#include <lemon/error.h>
+
+#include <lemon/dijkstra.h>
+#include <lemon/preflow.h>
+#include <lemon/matching.h>
+#include <lemon/network_simplex.h>
+
+using namespace lemon;
+typedef SmartDigraph Digraph;
+DIGRAPH_TYPEDEFS(Digraph);
+typedef SmartGraph Graph;
+
+template<class Value>
+void solve_sp(ArgParser &ap, std::istream &is, std::ostream &,
+ DimacsDescriptor &desc)
+{
+ bool report = !ap.given("q");
+ Digraph g;
+ Node s;
+ Digraph::ArcMap<Value> len(g);
+ Timer t;
+ t.restart();
+ readDimacsSp(is, g, len, s, desc);
+ if(report) std::cerr << "Read the file: " << t << '\n';
+ t.restart();
+ Dijkstra<Digraph, Digraph::ArcMap<Value> > dij(g,len);
+ if(report) std::cerr << "Setup Dijkstra class: " << t << '\n';
+ t.restart();
+ dij.run(s);
+ if(report) std::cerr << "Run Dijkstra: " << t << '\n';
+}
+
+template<class Value>
+void solve_max(ArgParser &ap, std::istream &is, std::ostream &,
+ Value infty, DimacsDescriptor &desc)
+{
+ bool report = !ap.given("q");
+ Digraph g;
+ Node s,t;
+ Digraph::ArcMap<Value> cap(g);
+ Timer ti;
+ ti.restart();
+ readDimacsMax(is, g, cap, s, t, infty, desc);
+ if(report) std::cerr << "Read the file: " << ti << '\n';
+ ti.restart();
+ Preflow<Digraph, Digraph::ArcMap<Value> > pre(g,cap,s,t);
+ if(report) std::cerr << "Setup Preflow class: " << ti << '\n';
+ ti.restart();
+ pre.run();
+ if(report) std::cerr << "Run Preflow: " << ti << '\n';
+ if(report) std::cerr << "\nMax flow value: " << pre.flowValue() << '\n';
+}
+
+template<class Value, class LargeValue>
+void solve_min(ArgParser &ap, std::istream &is, std::ostream &,
+ Value infty, DimacsDescriptor &desc)
+{
+ bool report = !ap.given("q");
+ Digraph g;
+ Digraph::ArcMap<Value> lower(g), cap(g), cost(g);
+ Digraph::NodeMap<Value> sup(g);
+ Timer ti;
+
+ ti.restart();
+ readDimacsMin(is, g, lower, cap, cost, sup, infty, desc);
+ ti.stop();
+ Value sum_sup = 0;
+ for (Digraph::NodeIt n(g); n != INVALID; ++n) {
+ sum_sup += sup[n];
+ }
+ if (report) {
+ std::cerr << "Sum of supply values: " << sum_sup << "\n";
+ if (sum_sup <= 0)
+ std::cerr << "GEQ supply contraints are used for NetworkSimplex\n\n";
+ else
+ std::cerr << "LEQ supply contraints are used for NetworkSimplex\n\n";
+ }
+ if (report) std::cerr << "Read the file: " << ti << '\n';
+
+ typedef NetworkSimplex<Digraph, Value> MCF;
+ ti.restart();
+ MCF ns(g);
+ ns.lowerMap(lower).upperMap(cap).costMap(cost).supplyMap(sup);
+ if (sum_sup > 0) ns.supplyType(ns.LEQ);
+ if (report) std::cerr << "Setup NetworkSimplex class: " << ti << '\n';
+ ti.restart();
+ typename MCF::ProblemType res = ns.run();
+ if (report) {
+ std::cerr << "Run NetworkSimplex: " << ti << "\n\n";
+ std::cerr << "Feasible flow: " << (res == MCF::OPTIMAL ? "found" :
+ "not found") << '\n';
+ if (res) std::cerr << "Min flow cost: "
+ << ns.template totalCost<LargeValue>() << '\n';
+ }
+}
+
+void solve_mat(ArgParser &ap, std::istream &is, std::ostream &,
+ DimacsDescriptor &desc)
+{
+ bool report = !ap.given("q");
+ Graph g;
+ Timer ti;
+ ti.restart();
+ readDimacsMat(is, g, desc);
+ if(report) std::cerr << "Read the file: " << ti << '\n';
+ ti.restart();
+ MaxMatching<Graph> mat(g);
+ if(report) std::cerr << "Setup MaxMatching class: " << ti << '\n';
+ ti.restart();
+ mat.run();
+ if(report) std::cerr << "Run MaxMatching: " << ti << '\n';
+ if(report) std::cerr << "\nCardinality of max matching: "
+ << mat.matchingSize() << '\n';
+}
+
+
+template<class Value, class LargeValue>
+void solve(ArgParser &ap, std::istream &is, std::ostream &os,
+ DimacsDescriptor &desc)
+{
+ std::stringstream iss(static_cast<std::string>(ap["infcap"]));
+ Value infty;
+ iss >> infty;
+ if(iss.fail())
+ {
+ std::cerr << "Cannot interpret '"
+ << static_cast<std::string>(ap["infcap"]) << "' as infinite"
+ << std::endl;
+ exit(1);
+ }
+
+ switch(desc.type)
+ {
+ case DimacsDescriptor::MIN:
+ solve_min<Value, LargeValue>(ap,is,os,infty,desc);
+ break;
+ case DimacsDescriptor::MAX:
+ solve_max<Value>(ap,is,os,infty,desc);
+ break;
+ case DimacsDescriptor::SP:
+ solve_sp<Value>(ap,is,os,desc);
+ break;
+ case DimacsDescriptor::MAT:
+ solve_mat(ap,is,os,desc);
+ break;
+ default:
+ break;
+ }
+}
+
+int main(int argc, const char *argv[]) {
+
+ std::string inputName;
+ std::string outputName;
+
+ ArgParser ap(argc, argv);
+ ap.other("[INFILE [OUTFILE]]",
+ "If either the INFILE or OUTFILE file is missing the standard\n"
+ " input/output will be used instead.")
+ .boolOption("q", "Do not print any report")
+ .boolOption("int","Use 'int' for capacities, costs etc. (default)")
+ .optionGroup("datatype","int")
+#ifdef LEMON_HAVE_LONG_LONG
+ .boolOption("long","Use 'long long' for capacities, costs etc.")
+ .optionGroup("datatype","long")
+#endif
+ .boolOption("double","Use 'double' for capacities, costs etc.")
+ .optionGroup("datatype","double")
+ .boolOption("ldouble","Use 'long double' for capacities, costs etc.")
+ .optionGroup("datatype","ldouble")
+ .onlyOneGroup("datatype")
+ .stringOption("infcap","Value used for 'very high' capacities","0")
+ .run();
+
+ std::ifstream input;
+ std::ofstream output;
+
+ switch(ap.files().size())
+ {
+ case 2:
+ output.open(ap.files()[1].c_str());
+ if (!output) {
+ throw IoError("Cannot open the file for writing", ap.files()[1]);
+ }
+ case 1:
+ input.open(ap.files()[0].c_str());
+ if (!input) {
+ throw IoError("File cannot be found", ap.files()[0]);
+ }
+ case 0:
+ break;
+ default:
+ std::cerr << ap.commandName() << ": too many arguments\n";
+ return 1;
+ }
+ std::istream& is = (ap.files().size()<1 ? std::cin : input);
+ std::ostream& os = (ap.files().size()<2 ? std::cout : output);
+
+ DimacsDescriptor desc = dimacsType(is);
+
+ if(!ap.given("q"))
+ {
+ std::cout << "Problem type: ";
+ switch(desc.type)
+ {
+ case DimacsDescriptor::MIN:
+ std::cout << "min";
+ break;
+ case DimacsDescriptor::MAX:
+ std::cout << "max";
+ break;
+ case DimacsDescriptor::SP:
+ std::cout << "sp";
+ case DimacsDescriptor::MAT:
+ std::cout << "mat";
+ break;
+ default:
+ exit(1);
+ break;
+ }
+ std::cout << "\nNum of nodes: " << desc.nodeNum;
+ std::cout << "\nNum of arcs: " << desc.edgeNum;
+ std::cout << "\n\n";
+ }
+
+ if(ap.given("double"))
+ solve<double, double>(ap,is,os,desc);
+ else if(ap.given("ldouble"))
+ solve<long double, long double>(ap,is,os,desc);
+#ifdef LEMON_HAVE_LONG_LONG
+ else if(ap.given("long"))
+ solve<long long, long long>(ap,is,os,desc);
+ else solve<int, long long>(ap,is,os,desc);
+#else
+ else solve<int, long>(ap,is,os,desc);
+#endif
+
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/tools/dimacs-to-lgf.cc b/extern/quadriflow/3rd/lemon-1.3.1/tools/dimacs-to-lgf.cc
new file mode 100644
index 00000000000..3968645dd90
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/tools/dimacs-to-lgf.cc
@@ -0,0 +1,148 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+///\ingroup tools
+///\file
+///\brief DIMACS to LGF converter.
+///
+/// This program converts various DIMACS formats to the LEMON Digraph Format
+/// (LGF).
+///
+/// See
+/// \code
+/// dimacs-to-lgf --help
+/// \endcode
+/// for more info on the usage.
+
+#include <iostream>
+#include <fstream>
+#include <cstring>
+
+#include <lemon/smart_graph.h>
+#include <lemon/dimacs.h>
+#include <lemon/lgf_writer.h>
+
+#include <lemon/arg_parser.h>
+#include <lemon/error.h>
+
+using namespace std;
+using namespace lemon;
+
+
+int main(int argc, const char *argv[]) {
+ typedef SmartDigraph Digraph;
+
+ typedef Digraph::Arc Arc;
+ typedef Digraph::Node Node;
+ typedef Digraph::ArcIt ArcIt;
+ typedef Digraph::NodeIt NodeIt;
+ typedef Digraph::ArcMap<double> DoubleArcMap;
+ typedef Digraph::NodeMap<double> DoubleNodeMap;
+
+ std::string inputName;
+ std::string outputName;
+
+ ArgParser ap(argc, argv);
+ ap.other("[INFILE [OUTFILE]]",
+ "If either the INFILE or OUTFILE file is missing the standard\n"
+ " input/output will be used instead.")
+ .run();
+
+ ifstream input;
+ ofstream output;
+
+ switch(ap.files().size())
+ {
+ case 2:
+ output.open(ap.files()[1].c_str());
+ if (!output) {
+ throw IoError("Cannot open the file for writing", ap.files()[1]);
+ }
+ case 1:
+ input.open(ap.files()[0].c_str());
+ if (!input) {
+ throw IoError("File cannot be found", ap.files()[0]);
+ }
+ case 0:
+ break;
+ default:
+ cerr << ap.commandName() << ": too many arguments\n";
+ return 1;
+ }
+ istream& is = (ap.files().size()<1 ? cin : input);
+ ostream& os = (ap.files().size()<2 ? cout : output);
+
+ DimacsDescriptor desc = dimacsType(is);
+ switch(desc.type)
+ {
+ case DimacsDescriptor::MIN:
+ {
+ Digraph digraph;
+ DoubleArcMap lower(digraph), capacity(digraph), cost(digraph);
+ DoubleNodeMap supply(digraph);
+ readDimacsMin(is, digraph, lower, capacity, cost, supply, 0, desc);
+ DigraphWriter<Digraph>(digraph, os).
+ nodeMap("supply", supply).
+ arcMap("lower", lower).
+ arcMap("capacity", capacity).
+ arcMap("cost", cost).
+ attribute("problem","min").
+ run();
+ }
+ break;
+ case DimacsDescriptor::MAX:
+ {
+ Digraph digraph;
+ Node s, t;
+ DoubleArcMap capacity(digraph);
+ readDimacsMax(is, digraph, capacity, s, t, 0, desc);
+ DigraphWriter<Digraph>(digraph, os).
+ arcMap("capacity", capacity).
+ node("source", s).
+ node("target", t).
+ attribute("problem","max").
+ run();
+ }
+ break;
+ case DimacsDescriptor::SP:
+ {
+ Digraph digraph;
+ Node s;
+ DoubleArcMap capacity(digraph);
+ readDimacsSp(is, digraph, capacity, s, desc);
+ DigraphWriter<Digraph>(digraph, os).
+ arcMap("capacity", capacity).
+ node("source", s).
+ attribute("problem","sp").
+ run();
+ }
+ break;
+ case DimacsDescriptor::MAT:
+ {
+ Digraph digraph;
+ readDimacsMat(is, digraph,desc);
+ DigraphWriter<Digraph>(digraph, os).
+ attribute("problem","mat").
+ run();
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/tools/lemon-0.x-to-1.x.sh b/extern/quadriflow/3rd/lemon-1.3.1/tools/lemon-0.x-to-1.x.sh
new file mode 100755
index 00000000000..1dac1be653a
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/tools/lemon-0.x-to-1.x.sh
@@ -0,0 +1,134 @@
+#!/bin/bash
+
+set -e
+
+if [ $# -eq 0 -o x$1 = "x-h" -o x$1 = "x-help" -o x$1 = "x--help" ]; then
+ echo "Usage:"
+ echo " $0 source-file(s)"
+ exit
+fi
+
+for i in $@
+do
+ echo Update $i...
+ TMP=`mktemp`
+ sed -e "s/\<undirected graph\>/_gr_aph_label_/g"\
+ -e "s/\<undirected graphs\>/_gr_aph_label_s/g"\
+ -e "s/\<undirected edge\>/_ed_ge_label_/g"\
+ -e "s/\<undirected edges\>/_ed_ge_label_s/g"\
+ -e "s/\<directed graph\>/_digr_aph_label_/g"\
+ -e "s/\<directed graphs\>/_digr_aph_label_s/g"\
+ -e "s/\<directed edge\>/_ar_c_label_/g"\
+ -e "s/\<directed edges\>/_ar_c_label_s/g"\
+ -e "s/UGraph/_Gr_aph_label_/g"\
+ -e "s/u[Gg]raph/_gr_aph_label_/g"\
+ -e "s/Graph\>/_Digr_aph_label_/g"\
+ -e "s/\<graph\>/_digr_aph_label_/g"\
+ -e "s/Graphs\>/_Digr_aph_label_s/g"\
+ -e "s/\<graphs\>/_digr_aph_label_s/g"\
+ -e "s/\([Gg]\)raph\([a-z]\)/_\1r_aph_label_\2/g"\
+ -e "s/\([a-z_]\)graph/\1_gr_aph_label_/g"\
+ -e "s/Graph/_Digr_aph_label_/g"\
+ -e "s/graph/_digr_aph_label_/g"\
+ -e "s/UEdge/_Ed_ge_label_/g"\
+ -e "s/u[Ee]dge/_ed_ge_label_/g"\
+ -e "s/IncEdgeIt/_In_cEd_geIt_label_/g"\
+ -e "s/Edge\>/_Ar_c_label_/g"\
+ -e "s/\<edge\>/_ar_c_label_/g"\
+ -e "s/_edge\>/__ar_c_label_/g"\
+ -e "s/Edges\>/_Ar_c_label_s/g"\
+ -e "s/\<edges\>/_ar_c_label_s/g"\
+ -e "s/_edges\>/__ar_c_label_s/g"\
+ -e "s/\([Ee]\)dge\([a-z]\)/_\1d_ge_label_\2/g"\
+ -e "s/\([a-z]\)edge/\1_ed_ge_label_/g"\
+ -e "s/Edge/_Ar_c_label_/g"\
+ -e "s/edge/_ar_c_label_/g"\
+ -e "s/A[Nn]ode/_Re_d_label_/g"\
+ -e "s/B[Nn]ode/_Blu_e_label_/g"\
+ -e "s/A-[Nn]ode/_Re_d_label_/g"\
+ -e "s/B-[Nn]ode/_Blu_e_label_/g"\
+ -e "s/a[Nn]ode/_re_d_label_/g"\
+ -e "s/b[Nn]ode/_blu_e_label_/g"\
+ -e "s/\<UGRAPH_TYPEDEFS\([ \t]*([ \t]*\)typename[ \t]/TEMPLATE__GR_APH_TY_PEDE_FS_label_\1/g"\
+ -e "s/\<GRAPH_TYPEDEFS\([ \t]*([ \t]*\)typename[ \t]/TEMPLATE__DIGR_APH_TY_PEDE_FS_label_\1/g"\
+ -e "s/\<UGRAPH_TYPEDEFS\>/_GR_APH_TY_PEDE_FS_label_/g"\
+ -e "s/\<GRAPH_TYPEDEFS\>/_DIGR_APH_TY_PEDE_FS_label_/g"\
+ -e "s/_Digr_aph_label_/Digraph/g"\
+ -e "s/_digr_aph_label_/digraph/g"\
+ -e "s/_Gr_aph_label_/Graph/g"\
+ -e "s/_gr_aph_label_/graph/g"\
+ -e "s/_Ar_c_label_/Arc/g"\
+ -e "s/_ar_c_label_/arc/g"\
+ -e "s/_Ed_ge_label_/Edge/g"\
+ -e "s/_ed_ge_label_/edge/g"\
+ -e "s/_In_cEd_geIt_label_/IncEdgeIt/g"\
+ -e "s/_Re_d_label_/Red/g"\
+ -e "s/_Blu_e_label_/Blue/g"\
+ -e "s/_re_d_label_/red/g"\
+ -e "s/_blu_e_label_/blue/g"\
+ -e "s/_GR_APH_TY_PEDE_FS_label_/GRAPH_TYPEDEFS/g"\
+ -e "s/_DIGR_APH_TY_PEDE_FS_label_/DIGRAPH_TYPEDEFS/g"\
+ -e "s/\<digraph_adaptor\.h\>/adaptors.h/g"\
+ -e "s/\<digraph_utils\.h\>/core.h/g"\
+ -e "s/\<digraph_reader\.h\>/lgf_reader.h/g"\
+ -e "s/\<digraph_writer\.h\>/lgf_writer.h/g"\
+ -e "s/\<topology\.h\>/connectivity.h/g"\
+ -e "s/DigraphToEps/GraphToEps/g"\
+ -e "s/digraphToEps/graphToEps/g"\
+ -e "s/\<DefPredMap\>/SetPredMap/g"\
+ -e "s/\<DefDistMap\>/SetDistMap/g"\
+ -e "s/\<DefReachedMap\>/SetReachedMap/g"\
+ -e "s/\<DefProcessedMap\>/SetProcessedMap/g"\
+ -e "s/\<DefHeap\>/SetHeap/g"\
+ -e "s/\<DefStandardHeap\>/SetStandradHeap/g"\
+ -e "s/\<DefOperationTraits\>/SetOperationTraits/g"\
+ -e "s/\<DefProcessedMapToBeDefaultMap\>/SetStandardProcessedMap/g"\
+ -e "s/\<copyGraph\>/graphCopy/g"\
+ -e "s/\<copyDigraph\>/digraphCopy/g"\
+ -e "s/\<HyperCubeDigraph\>/HypercubeGraph/g"\
+ -e "s/\<IntegerMap\>/RangeMap/g"\
+ -e "s/\<integerMap\>/rangeMap/g"\
+ -e "s/\<\([sS]\)tdMap\>/\1parseMap/g"\
+ -e "s/\<\([Ff]\)unctorMap\>/\1unctorToMap/g"\
+ -e "s/\<\([Mm]\)apFunctor\>/\1apToFunctor/g"\
+ -e "s/\<\([Ff]\)orkWriteMap\>/\1orkMap/g"\
+ -e "s/\<StoreBoolMap\>/LoggerBoolMap/g"\
+ -e "s/\<storeBoolMap\>/loggerBoolMap/g"\
+ -e "s/\<InvertableMap\>/CrossRefMap/g"\
+ -e "s/\<invertableMap\>/crossRefMap/g"\
+ -e "s/\<DescriptorMap\>/RangeIdMap/g"\
+ -e "s/\<descriptorMap\>/rangeIdMap/g"\
+ -e "s/\<BoundingBox\>/Box/g"\
+ -e "s/\<readNauty\>/readNautyGraph/g"\
+ -e "s/\<RevDigraphAdaptor\>/ReverseDigraph/g"\
+ -e "s/\<revDigraphAdaptor\>/reverseDigraph/g"\
+ -e "s/\<SubDigraphAdaptor\>/SubDigraph/g"\
+ -e "s/\<subDigraphAdaptor\>/subDigraph/g"\
+ -e "s/\<SubGraphAdaptor\>/SubGraph/g"\
+ -e "s/\<subGraphAdaptor\>/subGraph/g"\
+ -e "s/\<NodeSubDigraphAdaptor\>/FilterNodes/g"\
+ -e "s/\<nodeSubDigraphAdaptor\>/filterNodes/g"\
+ -e "s/\<ArcSubDigraphAdaptor\>/FilterArcs/g"\
+ -e "s/\<arcSubDigraphAdaptor\>/filterArcs/g"\
+ -e "s/\<UndirDigraphAdaptor\>/Undirector/g"\
+ -e "s/\<undirDigraphAdaptor\>/undirector/g"\
+ -e "s/\<ResDigraphAdaptor\>/ResidualDigraph/g"\
+ -e "s/\<resDigraphAdaptor\>/residualDigraph/g"\
+ -e "s/\<SplitDigraphAdaptor\>/SplitNodes/g"\
+ -e "s/\<splitDigraphAdaptor\>/splitNodes/g"\
+ -e "s/\<SubGraphAdaptor\>/SubGraph/g"\
+ -e "s/\<subGraphAdaptor\>/subGraph/g"\
+ -e "s/\<NodeSubGraphAdaptor\>/FilterNodes/g"\
+ -e "s/\<nodeSubGraphAdaptor\>/filterNodes/g"\
+ -e "s/\<ArcSubGraphAdaptor\>/FilterEdges/g"\
+ -e "s/\<arcSubGraphAdaptor\>/filterEdges/g"\
+ -e "s/\<DirGraphAdaptor\>/Orienter/g"\
+ -e "s/\<dirGraphAdaptor\>/orienter/g"\
+ -e "s/\<LpCplex\>/CplexLp/g"\
+ -e "s/\<MipCplex\>/CplexMip/g"\
+ -e "s/\<LpGlpk\>/GlpkLp/g"\
+ -e "s/\<MipGlpk\>/GlpkMip/g"\
+ -e "s/\<LpSoplex\>/SoplexLp/g"\
+ <$i > $TMP
+ mv $TMP $i
+done
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/tools/lgf-gen.cc b/extern/quadriflow/3rd/lemon-1.3.1/tools/lgf-gen.cc
new file mode 100644
index 00000000000..390c8ae5972
--- /dev/null
+++ b/extern/quadriflow/3rd/lemon-1.3.1/tools/lgf-gen.cc
@@ -0,0 +1,847 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2009
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+/// \ingroup tools
+/// \file
+/// \brief Special plane graph generator.
+///
+/// Graph generator application for various types of plane graphs.
+///
+/// See
+/// \code
+/// lgf-gen --help
+/// \endcode
+/// for more information on the usage.
+
+#include <algorithm>
+#include <set>
+#include <ctime>
+#include <lemon/list_graph.h>
+#include <lemon/random.h>
+#include <lemon/dim2.h>
+#include <lemon/bfs.h>
+#include <lemon/counter.h>
+#include <lemon/suurballe.h>
+#include <lemon/graph_to_eps.h>
+#include <lemon/lgf_writer.h>
+#include <lemon/arg_parser.h>
+#include <lemon/euler.h>
+#include <lemon/math.h>
+#include <lemon/kruskal.h>
+#include <lemon/time_measure.h>
+
+using namespace lemon;
+
+typedef dim2::Point<double> Point;
+
+GRAPH_TYPEDEFS(ListGraph);
+
+bool progress=true;
+
+int N;
+// int girth;
+
+ListGraph g;
+
+std::vector<Node> nodes;
+ListGraph::NodeMap<Point> coords(g);
+
+
+double totalLen(){
+ double tlen=0;
+ for(EdgeIt e(g);e!=INVALID;++e)
+ tlen+=std::sqrt((coords[g.v(e)]-coords[g.u(e)]).normSquare());
+ return tlen;
+}
+
+int tsp_impr_num=0;
+
+const double EPSILON=1e-8;
+bool tsp_improve(Node u, Node v)
+{
+ double luv=std::sqrt((coords[v]-coords[u]).normSquare());
+ Node u2=u;
+ Node v2=v;
+ do {
+ Node n;
+ for(IncEdgeIt e(g,v2);(n=g.runningNode(e))==u2;++e) { }
+ u2=v2;
+ v2=n;
+ if(luv+std::sqrt((coords[v2]-coords[u2]).normSquare())-EPSILON>
+ std::sqrt((coords[u]-coords[u2]).normSquare())+
+ std::sqrt((coords[v]-coords[v2]).normSquare()))
+ {
+ g.erase(findEdge(g,u,v));
+ g.erase(findEdge(g,u2,v2));
+ g.addEdge(u2,u);
+ g.addEdge(v,v2);
+ tsp_impr_num++;
+ return true;
+ }
+ } while(v2!=u);
+ return false;
+}
+
+bool tsp_improve(Node u)
+{
+ for(IncEdgeIt e(g,u);e!=INVALID;++e)
+ if(tsp_improve(u,g.runningNode(e))) return true;
+ return false;
+}
+
+void tsp_improve()
+{
+ bool b;
+ do {
+ b=false;
+ for(NodeIt n(g);n!=INVALID;++n)
+ if(tsp_improve(n)) b=true;
+ } while(b);
+}
+
+void tsp()
+{
+ for(int i=0;i<N;i++) g.addEdge(nodes[i],nodes[(i+1)%N]);
+ tsp_improve();
+}
+
+class Line
+{
+public:
+ Point a;
+ Point b;
+ Line(Point _a,Point _b) :a(_a),b(_b) {}
+ Line(Node _a,Node _b) : a(coords[_a]),b(coords[_b]) {}
+ Line(const Arc &e) : a(coords[g.source(e)]),b(coords[g.target(e)]) {}
+ Line(const Edge &e) : a(coords[g.u(e)]),b(coords[g.v(e)]) {}
+};
+
+inline std::ostream& operator<<(std::ostream &os, const Line &l)
+{
+ os << l.a << "->" << l.b;
+ return os;
+}
+
+bool cross(Line a, Line b)
+{
+ Point ao=rot90(a.b-a.a);
+ Point bo=rot90(b.b-b.a);
+ return (ao*(b.a-a.a))*(ao*(b.b-a.a))<0 &&
+ (bo*(a.a-b.a))*(bo*(a.b-b.a))<0;
+}
+
+struct Parc
+{
+ Node a;
+ Node b;
+ double len;
+};
+
+bool pedgeLess(Parc a,Parc b)
+{
+ return a.len<b.len;
+}
+
+std::vector<Edge> arcs;
+
+namespace _delaunay_bits {
+
+ struct Part {
+ int prev, curr, next;
+
+ Part(int p, int c, int n) : prev(p), curr(c), next(n) {}
+ };
+
+ inline std::ostream& operator<<(std::ostream& os, const Part& part) {
+ os << '(' << part.prev << ',' << part.curr << ',' << part.next << ')';
+ return os;
+ }
+
+ inline double circle_point(const Point& p, const Point& q, const Point& r) {
+ double a = p.x * (q.y - r.y) + q.x * (r.y - p.y) + r.x * (p.y - q.y);
+ if (a == 0) return std::numeric_limits<double>::quiet_NaN();
+
+ double d = (p.x * p.x + p.y * p.y) * (q.y - r.y) +
+ (q.x * q.x + q.y * q.y) * (r.y - p.y) +
+ (r.x * r.x + r.y * r.y) * (p.y - q.y);
+
+ double e = (p.x * p.x + p.y * p.y) * (q.x - r.x) +
+ (q.x * q.x + q.y * q.y) * (r.x - p.x) +
+ (r.x * r.x + r.y * r.y) * (p.x - q.x);
+
+ double f = (p.x * p.x + p.y * p.y) * (q.x * r.y - r.x * q.y) +
+ (q.x * q.x + q.y * q.y) * (r.x * p.y - p.x * r.y) +
+ (r.x * r.x + r.y * r.y) * (p.x * q.y - q.x * p.y);
+
+ return d / (2 * a) + std::sqrt((d * d + e * e) / (4 * a * a) + f / a);
+ }
+
+ inline bool circle_form(const Point& p, const Point& q, const Point& r) {
+ return rot90(q - p) * (r - q) < 0.0;
+ }
+
+ inline double intersection(const Point& p, const Point& q, double sx) {
+ const double epsilon = 1e-8;
+
+ if (p.x == q.x) return (p.y + q.y) / 2.0;
+
+ if (sx < p.x + epsilon) return p.y;
+ if (sx < q.x + epsilon) return q.y;
+
+ double a = q.x - p.x;
+ double b = (q.x - sx) * p.y - (p.x - sx) * q.y;
+ double d = (q.x - sx) * (p.x - sx) * (p - q).normSquare();
+ return (b - std::sqrt(d)) / a;
+ }
+
+ struct YLess {
+
+
+ YLess(const std::vector<Point>& points, double& sweep)
+ : _points(points), _sweep(sweep) {}
+
+ bool operator()(const Part& l, const Part& r) const {
+ const double epsilon = 1e-8;
+
+ // std::cerr << l << " vs " << r << std::endl;
+ double lbx = l.prev != -1 ?
+ intersection(_points[l.prev], _points[l.curr], _sweep) :
+ - std::numeric_limits<double>::infinity();
+ double rbx = r.prev != -1 ?
+ intersection(_points[r.prev], _points[r.curr], _sweep) :
+ - std::numeric_limits<double>::infinity();
+ double lex = l.next != -1 ?
+ intersection(_points[l.curr], _points[l.next], _sweep) :
+ std::numeric_limits<double>::infinity();
+ double rex = r.next != -1 ?
+ intersection(_points[r.curr], _points[r.next], _sweep) :
+ std::numeric_limits<double>::infinity();
+
+ if (lbx > lex) std::swap(lbx, lex);
+ if (rbx > rex) std::swap(rbx, rex);
+
+ if (lex < epsilon + rex && lbx + epsilon < rex) return true;
+ if (rex < epsilon + lex && rbx + epsilon < lex) return false;
+ return lex < rex;
+ }
+
+ const std::vector<Point>& _points;
+ double& _sweep;
+ };
+
+ struct BeachIt;
+
+ typedef std::multimap<double, BeachIt*> SpikeHeap;
+
+ typedef std::multimap<Part, SpikeHeap::iterator, YLess> Beach;
+
+ struct BeachIt {
+ Beach::iterator it;
+
+ BeachIt(Beach::iterator iter) : it(iter) {}
+ };
+
+}
+
+inline void delaunay() {
+ Counter cnt("Number of arcs added: ");
+
+ using namespace _delaunay_bits;
+
+ typedef _delaunay_bits::Part Part;
+ typedef std::vector<std::pair<double, int> > SiteHeap;
+
+
+ std::vector<Point> points;
+ std::vector<Node> nodes;
+
+ for (NodeIt it(g); it != INVALID; ++it) {
+ nodes.push_back(it);
+ points.push_back(coords[it]);
+ }
+
+ SiteHeap siteheap(points.size());
+
+ double sweep;
+
+
+ for (int i = 0; i < int(siteheap.size()); ++i) {
+ siteheap[i] = std::make_pair(points[i].x, i);
+ }
+
+ std::sort(siteheap.begin(), siteheap.end());
+ sweep = siteheap.front().first;
+
+ YLess yless(points, sweep);
+ Beach beach(yless);
+
+ SpikeHeap spikeheap;
+
+ std::set<std::pair<int, int> > arcs;
+
+ int siteindex = 0;
+ {
+ SiteHeap front;
+
+ while (siteindex < int(siteheap.size()) &&
+ siteheap[0].first == siteheap[siteindex].first) {
+ front.push_back(std::make_pair(points[siteheap[siteindex].second].y,
+ siteheap[siteindex].second));
+ ++siteindex;
+ }
+
+ std::sort(front.begin(), front.end());
+
+ for (int i = 0; i < int(front.size()); ++i) {
+ int prev = (i == 0 ? -1 : front[i - 1].second);
+ int curr = front[i].second;
+ int next = (i + 1 == int(front.size()) ? -1 : front[i + 1].second);
+
+ beach.insert(std::make_pair(Part(prev, curr, next),
+ spikeheap.end()));
+ }
+ }
+
+ while (siteindex < int(points.size()) || !spikeheap.empty()) {
+
+ SpikeHeap::iterator spit = spikeheap.begin();
+
+ if (siteindex < int(points.size()) &&
+ (spit == spikeheap.end() || siteheap[siteindex].first < spit->first)) {
+ int site = siteheap[siteindex].second;
+ sweep = siteheap[siteindex].first;
+
+ Beach::iterator bit = beach.upper_bound(Part(site, site, site));
+
+ if (bit->second != spikeheap.end()) {
+ delete bit->second->second;
+ spikeheap.erase(bit->second);
+ }
+
+ int prev = bit->first.prev;
+ int curr = bit->first.curr;
+ int next = bit->first.next;
+
+ beach.erase(bit);
+
+ SpikeHeap::iterator pit = spikeheap.end();
+ if (prev != -1 &&
+ circle_form(points[prev], points[curr], points[site])) {
+ double x = circle_point(points[prev], points[curr], points[site]);
+ pit = spikeheap.insert(std::make_pair(x, new BeachIt(beach.end())));
+ pit->second->it =
+ beach.insert(std::make_pair(Part(prev, curr, site), pit));
+ } else {
+ beach.insert(std::make_pair(Part(prev, curr, site), pit));
+ }
+
+ beach.insert(std::make_pair(Part(curr, site, curr), spikeheap.end()));
+
+ SpikeHeap::iterator nit = spikeheap.end();
+ if (next != -1 &&
+ circle_form(points[site], points[curr],points[next])) {
+ double x = circle_point(points[site], points[curr], points[next]);
+ nit = spikeheap.insert(std::make_pair(x, new BeachIt(beach.end())));
+ nit->second->it =
+ beach.insert(std::make_pair(Part(site, curr, next), nit));
+ } else {
+ beach.insert(std::make_pair(Part(site, curr, next), nit));
+ }
+
+ ++siteindex;
+ } else {
+ sweep = spit->first;
+
+ Beach::iterator bit = spit->second->it;
+
+ int prev = bit->first.prev;
+ int curr = bit->first.curr;
+ int next = bit->first.next;
+
+ {
+ std::pair<int, int> arc;
+
+ arc = prev < curr ?
+ std::make_pair(prev, curr) : std::make_pair(curr, prev);
+
+ if (arcs.find(arc) == arcs.end()) {
+ arcs.insert(arc);
+ g.addEdge(nodes[prev], nodes[curr]);
+ ++cnt;
+ }
+
+ arc = curr < next ?
+ std::make_pair(curr, next) : std::make_pair(next, curr);
+
+ if (arcs.find(arc) == arcs.end()) {
+ arcs.insert(arc);
+ g.addEdge(nodes[curr], nodes[next]);
+ ++cnt;
+ }
+ }
+
+ Beach::iterator pbit = bit; --pbit;
+ int ppv = pbit->first.prev;
+ Beach::iterator nbit = bit; ++nbit;
+ int nnt = nbit->first.next;
+
+ if (bit->second != spikeheap.end())
+ {
+ delete bit->second->second;
+ spikeheap.erase(bit->second);
+ }
+ if (pbit->second != spikeheap.end())
+ {
+ delete pbit->second->second;
+ spikeheap.erase(pbit->second);
+ }
+ if (nbit->second != spikeheap.end())
+ {
+ delete nbit->second->second;
+ spikeheap.erase(nbit->second);
+ }
+
+ beach.erase(nbit);
+ beach.erase(bit);
+ beach.erase(pbit);
+
+ SpikeHeap::iterator pit = spikeheap.end();
+ if (ppv != -1 && ppv != next &&
+ circle_form(points[ppv], points[prev], points[next])) {
+ double x = circle_point(points[ppv], points[prev], points[next]);
+ if (x < sweep) x = sweep;
+ pit = spikeheap.insert(std::make_pair(x, new BeachIt(beach.end())));
+ pit->second->it =
+ beach.insert(std::make_pair(Part(ppv, prev, next), pit));
+ } else {
+ beach.insert(std::make_pair(Part(ppv, prev, next), pit));
+ }
+
+ SpikeHeap::iterator nit = spikeheap.end();
+ if (nnt != -1 && prev != nnt &&
+ circle_form(points[prev], points[next], points[nnt])) {
+ double x = circle_point(points[prev], points[next], points[nnt]);
+ if (x < sweep) x = sweep;
+ nit = spikeheap.insert(std::make_pair(x, new BeachIt(beach.end())));
+ nit->second->it =
+ beach.insert(std::make_pair(Part(prev, next, nnt), nit));
+ } else {
+ beach.insert(std::make_pair(Part(prev, next, nnt), nit));
+ }
+
+ }
+ }
+
+ for (Beach::iterator it = beach.begin(); it != beach.end(); ++it) {
+ int curr = it->first.curr;
+ int next = it->first.next;
+
+ if (next == -1) continue;
+
+ std::pair<int, int> arc;
+
+ arc = curr < next ?
+ std::make_pair(curr, next) : std::make_pair(next, curr);
+
+ if (arcs.find(arc) == arcs.end()) {
+ arcs.insert(arc);
+ g.addEdge(nodes[curr], nodes[next]);
+ ++cnt;
+ }
+ }
+}
+
+void sparse(int d)
+{
+ Counter cnt("Number of arcs removed: ");
+ Bfs<ListGraph> bfs(g);
+ for(std::vector<Edge>::reverse_iterator ei=arcs.rbegin();
+ ei!=arcs.rend();++ei)
+ {
+ Node a=g.u(*ei);
+ Node b=g.v(*ei);
+ g.erase(*ei);
+ bfs.run(a,b);
+ if(bfs.predArc(b)==INVALID || bfs.dist(b)>d)
+ g.addEdge(a,b);
+ else cnt++;
+ }
+}
+
+void sparse2(int d)
+{
+ Counter cnt("Number of arcs removed: ");
+ for(std::vector<Edge>::reverse_iterator ei=arcs.rbegin();
+ ei!=arcs.rend();++ei)
+ {
+ Node a=g.u(*ei);
+ Node b=g.v(*ei);
+ g.erase(*ei);
+ ConstMap<Arc,int> cegy(1);
+ Suurballe<ListGraph,ConstMap<Arc,int> > sur(g,cegy);
+ int k=sur.run(a,b,2);
+ if(k<2 || sur.totalLength()>d)
+ g.addEdge(a,b);
+ else cnt++;
+// else std::cout << "Remove arc " << g.id(a) << "-" << g.id(b) << '\n';
+ }
+}
+
+void sparseTriangle(int d)
+{
+ Counter cnt("Number of arcs added: ");
+ std::vector<Parc> pedges;
+ for(NodeIt n(g);n!=INVALID;++n)
+ for(NodeIt m=++(NodeIt(n));m!=INVALID;++m)
+ {
+ Parc p;
+ p.a=n;
+ p.b=m;
+ p.len=(coords[m]-coords[n]).normSquare();
+ pedges.push_back(p);
+ }
+ std::sort(pedges.begin(),pedges.end(),pedgeLess);
+ for(std::vector<Parc>::iterator pi=pedges.begin();pi!=pedges.end();++pi)
+ {
+ Line li(pi->a,pi->b);
+ EdgeIt e(g);
+ for(;e!=INVALID && !cross(e,li);++e) ;
+ Edge ne;
+ if(e==INVALID) {
+ ConstMap<Arc,int> cegy(1);
+ Suurballe<ListGraph,ConstMap<Arc,int> > sur(g,cegy);
+ int k=sur.run(pi->a,pi->b,2);
+ if(k<2 || sur.totalLength()>d)
+ {
+ ne=g.addEdge(pi->a,pi->b);
+ arcs.push_back(ne);
+ cnt++;
+ }
+ }
+ }
+}
+
+template <typename Graph, typename CoordMap>
+class LengthSquareMap {
+public:
+ typedef typename Graph::Edge Key;
+ typedef typename CoordMap::Value::Value Value;
+
+ LengthSquareMap(const Graph& graph, const CoordMap& coords)
+ : _graph(graph), _coords(coords) {}
+
+ Value operator[](const Key& key) const {
+ return (_coords[_graph.v(key)] -
+ _coords[_graph.u(key)]).normSquare();
+ }
+
+private:
+
+ const Graph& _graph;
+ const CoordMap& _coords;
+};
+
+void minTree() {
+ std::vector<Parc> pedges;
+ Timer T;
+ std::cout << T.realTime() << "s: Creating delaunay triangulation...\n";
+ delaunay();
+ std::cout << T.realTime() << "s: Calculating spanning tree...\n";
+ LengthSquareMap<ListGraph, ListGraph::NodeMap<Point> > ls(g, coords);
+ ListGraph::EdgeMap<bool> tree(g);
+ kruskal(g, ls, tree);
+ std::cout << T.realTime() << "s: Removing non tree arcs...\n";
+ std::vector<Edge> remove;
+ for (EdgeIt e(g); e != INVALID; ++e) {
+ if (!tree[e]) remove.push_back(e);
+ }
+ for(int i = 0; i < int(remove.size()); ++i) {
+ g.erase(remove[i]);
+ }
+ std::cout << T.realTime() << "s: Done\n";
+}
+
+void tsp2()
+{
+ std::cout << "Find a tree..." << std::endl;
+
+ minTree();
+
+ std::cout << "Total arc length (tree) : " << totalLen() << std::endl;
+
+ std::cout << "Make it Euler..." << std::endl;
+
+ {
+ std::vector<Node> leafs;
+ for(NodeIt n(g);n!=INVALID;++n)
+ if(countIncEdges(g,n)%2==1) leafs.push_back(n);
+
+// for(unsigned int i=0;i<leafs.size();i+=2)
+// g.addArc(leafs[i],leafs[i+1]);
+
+ std::vector<Parc> pedges;
+ for(unsigned int i=0;i<leafs.size()-1;i++)
+ for(unsigned int j=i+1;j<leafs.size();j++)
+ {
+ Node n=leafs[i];
+ Node m=leafs[j];
+ Parc p;
+ p.a=n;
+ p.b=m;
+ p.len=(coords[m]-coords[n]).normSquare();
+ pedges.push_back(p);
+ }
+ std::sort(pedges.begin(),pedges.end(),pedgeLess);
+ for(unsigned int i=0;i<pedges.size();i++)
+ if(countIncEdges(g,pedges[i].a)%2 &&
+ countIncEdges(g,pedges[i].b)%2)
+ g.addEdge(pedges[i].a,pedges[i].b);
+ }
+
+ for(NodeIt n(g);n!=INVALID;++n)
+ if(countIncEdges(g,n)%2 || countIncEdges(g,n)==0 )
+ std::cout << "GEBASZ!!!" << std::endl;
+
+ for(EdgeIt e(g);e!=INVALID;++e)
+ if(g.u(e)==g.v(e))
+ std::cout << "LOOP GEBASZ!!!" << std::endl;
+
+ std::cout << "Number of arcs : " << countEdges(g) << std::endl;
+
+ std::cout << "Total arc length (euler) : " << totalLen() << std::endl;
+
+ ListGraph::EdgeMap<Arc> enext(g);
+ {
+ EulerIt<ListGraph> e(g);
+ Arc eo=e;
+ Arc ef=e;
+// std::cout << "Tour arc: " << g.id(Edge(e)) << std::endl;
+ for(++e;e!=INVALID;++e)
+ {
+// std::cout << "Tour arc: " << g.id(Edge(e)) << std::endl;
+ enext[eo]=e;
+ eo=e;
+ }
+ enext[eo]=ef;
+ }
+
+ std::cout << "Creating a tour from that..." << std::endl;
+
+ int nnum = countNodes(g);
+ int ednum = countEdges(g);
+
+ for(Arc p=enext[EdgeIt(g)];ednum>nnum;p=enext[p])
+ {
+// std::cout << "Checking arc " << g.id(p) << std::endl;
+ Arc e=enext[p];
+ Arc f=enext[e];
+ Node n2=g.source(f);
+ Node n1=g.oppositeNode(n2,e);
+ Node n3=g.oppositeNode(n2,f);
+ if(countIncEdges(g,n2)>2)
+ {
+// std::cout << "Remove an Arc" << std::endl;
+ Arc ff=enext[f];
+ g.erase(e);
+ g.erase(f);
+ if(n1!=n3)
+ {
+ Arc ne=g.direct(g.addEdge(n1,n3),n1);
+ enext[p]=ne;
+ enext[ne]=ff;
+ ednum--;
+ }
+ else {
+ enext[p]=ff;
+ ednum-=2;
+ }
+ }
+ }
+
+ std::cout << "Total arc length (tour) : " << totalLen() << std::endl;
+
+ std::cout << "2-opt the tour..." << std::endl;
+
+ tsp_improve();
+
+ std::cout << "Total arc length (2-opt tour) : " << totalLen() << std::endl;
+}
+
+
+int main(int argc,const char **argv)
+{
+ ArgParser ap(argc,argv);
+
+// bool eps;
+ bool disc_d, square_d, gauss_d;
+// bool tsp_a,two_a,tree_a;
+ int num_of_cities=1;
+ double area=1;
+ N=100;
+// girth=10;
+ std::string ndist("disc");
+ ap.refOption("n", "Number of nodes (default is 100)", N)
+ .intOption("g", "Girth parameter (default is 10)", 10)
+ .refOption("cities", "Number of cities (default is 1)", num_of_cities)
+ .refOption("area", "Full relative area of the cities (default is 1)", area)
+ .refOption("disc", "Nodes are evenly distributed on a unit disc (default)",
+ disc_d)
+ .optionGroup("dist", "disc")
+ .refOption("square", "Nodes are evenly distributed on a unit square",
+ square_d)
+ .optionGroup("dist", "square")
+ .refOption("gauss", "Nodes are located according to a two-dim Gauss "
+ "distribution", gauss_d)
+ .optionGroup("dist", "gauss")
+ .onlyOneGroup("dist")
+ .boolOption("eps", "Also generate .eps output (<prefix>.eps)")
+ .boolOption("nonodes", "Draw only the edges in the generated .eps output")
+ .boolOption("dir", "Directed graph is generated (each edge is replaced by "
+ "two directed arcs)")
+ .boolOption("2con", "Create a two connected planar graph")
+ .optionGroup("alg","2con")
+ .boolOption("tree", "Create a min. cost spanning tree")
+ .optionGroup("alg","tree")
+ .boolOption("tsp", "Create a TSP tour")
+ .optionGroup("alg","tsp")
+ .boolOption("tsp2", "Create a TSP tour (tree based)")
+ .optionGroup("alg","tsp2")
+ .boolOption("dela", "Delaunay triangulation graph")
+ .optionGroup("alg","dela")
+ .onlyOneGroup("alg")
+ .boolOption("rand", "Use time seed for random number generator")
+ .optionGroup("rand", "rand")
+ .intOption("seed", "Random seed", -1)
+ .optionGroup("rand", "seed")
+ .onlyOneGroup("rand")
+ .other("[prefix]","Prefix of the output files. Default is 'lgf-gen-out'")
+ .run();
+
+ if (ap["rand"]) {
+ int seed = int(time(0));
+ std::cout << "Random number seed: " << seed << std::endl;
+ rnd = Random(seed);
+ }
+ if (ap.given("seed")) {
+ int seed = ap["seed"];
+ std::cout << "Random number seed: " << seed << std::endl;
+ rnd = Random(seed);
+ }
+
+ std::string prefix;
+ switch(ap.files().size())
+ {
+ case 0:
+ prefix="lgf-gen-out";
+ break;
+ case 1:
+ prefix=ap.files()[0];
+ break;
+ default:
+ std::cerr << "\nAt most one prefix can be given\n\n";
+ exit(1);
+ }
+
+ double sum_sizes=0;
+ std::vector<double> sizes;
+ std::vector<double> cum_sizes;
+ for(int s=0;s<num_of_cities;s++)
+ {
+ // sum_sizes+=rnd.exponential();
+ double d=rnd();
+ sum_sizes+=d;
+ sizes.push_back(d);
+ cum_sizes.push_back(sum_sizes);
+ }
+ int i=0;
+ for(int s=0;s<num_of_cities;s++)
+ {
+ Point center=(num_of_cities==1?Point(0,0):rnd.disc());
+ if(gauss_d)
+ for(;i<N*(cum_sizes[s]/sum_sizes);i++) {
+ Node n=g.addNode();
+ nodes.push_back(n);
+ coords[n]=center+rnd.gauss2()*area*
+ std::sqrt(sizes[s]/sum_sizes);
+ }
+ else if(square_d)
+ for(;i<N*(cum_sizes[s]/sum_sizes);i++) {
+ Node n=g.addNode();
+ nodes.push_back(n);
+ coords[n]=center+Point(rnd()*2-1,rnd()*2-1)*area*
+ std::sqrt(sizes[s]/sum_sizes);
+ }
+ else if(disc_d || true)
+ for(;i<N*(cum_sizes[s]/sum_sizes);i++) {
+ Node n=g.addNode();
+ nodes.push_back(n);
+ coords[n]=center+rnd.disc()*area*
+ std::sqrt(sizes[s]/sum_sizes);
+ }
+ }
+
+// for (ListGraph::NodeIt n(g); n != INVALID; ++n) {
+// std::cerr << coords[n] << std::endl;
+// }
+
+ if(ap["tsp"]) {
+ tsp();
+ std::cout << "#2-opt improvements: " << tsp_impr_num << std::endl;
+ }
+ if(ap["tsp2"]) {
+ tsp2();
+ std::cout << "#2-opt improvements: " << tsp_impr_num << std::endl;
+ }
+ else if(ap["2con"]) {
+ std::cout << "Make triangles\n";
+ // triangle();
+ sparseTriangle(ap["g"]);
+ std::cout << "Make it sparser\n";
+ sparse2(ap["g"]);
+ }
+ else if(ap["tree"]) {
+ minTree();
+ }
+ else if(ap["dela"]) {
+ delaunay();
+ }
+
+
+ std::cout << "Number of nodes : " << countNodes(g) << std::endl;
+ std::cout << "Number of arcs : " << countEdges(g) << std::endl;
+ double tlen=0;
+ for(EdgeIt e(g);e!=INVALID;++e)
+ tlen+=std::sqrt((coords[g.v(e)]-coords[g.u(e)]).normSquare());
+ std::cout << "Total arc length : " << tlen << std::endl;
+
+ if(ap["eps"])
+ graphToEps(g,prefix+".eps").scaleToA4().
+ scale(600).nodeScale(.005).arcWidthScale(.001).preScale(false).
+ coords(coords).hideNodes(ap.given("nonodes")).run();
+
+ if(ap["dir"])
+ DigraphWriter<ListGraph>(g,prefix+".lgf").
+ nodeMap("coordinates_x",scaleMap(xMap(coords),600)).
+ nodeMap("coordinates_y",scaleMap(yMap(coords),600)).
+ run();
+ else GraphWriter<ListGraph>(g,prefix+".lgf").
+ nodeMap("coordinates_x",scaleMap(xMap(coords),600)).
+ nodeMap("coordinates_y",scaleMap(yMap(coords),600)).
+ run();
+}
+
diff --git a/extern/quadriflow/3rd/pcg32/pcg32/pcg32.h b/extern/quadriflow/3rd/pcg32/pcg32/pcg32.h
new file mode 100644
index 00000000000..aa06f28a845
--- /dev/null
+++ b/extern/quadriflow/3rd/pcg32/pcg32/pcg32.h
@@ -0,0 +1,209 @@
+/*
+ * Tiny self-contained version of the PCG Random Number Generation for C++
+ * put together from pieces of the much larger C/C++ codebase.
+ * Wenzel Jakob, February 2015
+ *
+ * The PCG random number generator was developed by Melissa O'Neill <oneill@pcg-random.org>
+ *
+ * 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.
+ *
+ * For additional information about the PCG random number generation scheme,
+ * including its license and other licensing options, visit
+ *
+ * http://www.pcg-random.org
+ */
+
+#ifndef __PCG32_H
+#define __PCG32_H 1
+
+#define PCG32_DEFAULT_STATE 0x853c49e6748fea9bULL
+#define PCG32_DEFAULT_STREAM 0xda3e39cb94b95bdbULL
+#define PCG32_MULT 0x5851f42d4c957f2dULL
+
+#include <inttypes.h>
+#include <cmath>
+#include <cassert>
+#include <algorithm>
+
+/// PCG32 Pseudorandom number generator
+struct pcg32 {
+ /// Initialize the pseudorandom number generator with default seed
+ pcg32() : state(PCG32_DEFAULT_STATE), inc(PCG32_DEFAULT_STREAM) {}
+
+ /// Initialize the pseudorandom number generator with the \ref seed() function
+ pcg32(uint64_t initstate, uint64_t initseq = 1u) { seed(initstate, initseq); }
+
+ /**
+ * \brief Seed the pseudorandom number generator
+ *
+ * Specified in two parts: a state initializer and a sequence selection
+ * constant (a.k.a. stream id)
+ */
+ void seed(uint64_t initstate, uint64_t initseq = 1) {
+ state = 0U;
+ inc = (initseq << 1u) | 1u;
+ nextUInt();
+ state += initstate;
+ nextUInt();
+ }
+
+ /// Generate a uniformly distributed unsigned 32-bit random number
+ uint32_t nextUInt() {
+ uint64_t oldstate = state;
+ state = oldstate * PCG32_MULT + inc;
+ uint32_t xorshifted = (uint32_t) (((oldstate >> 18u) ^ oldstate) >> 27u);
+ uint32_t rot = (uint32_t) (oldstate >> 59u);
+ return (xorshifted >> rot) | (xorshifted << ((~rot + 1u) & 31));
+ }
+
+ /// Generate a uniformly distributed number, r, where 0 <= r < bound
+ uint32_t nextUInt(uint32_t bound) {
+ // To avoid bias, we need to make the range of the RNG a multiple of
+ // bound, which we do by dropping output less than a threshold.
+ // A naive scheme to calculate the threshold would be to do
+ //
+ // uint32_t threshold = 0x100000000ull % bound;
+ //
+ // but 64-bit div/mod is slower than 32-bit div/mod (especially on
+ // 32-bit platforms). In essence, we do
+ //
+ // uint32_t threshold = (0x100000000ull-bound) % bound;
+ //
+ // because this version will calculate the same modulus, but the LHS
+ // value is less than 2^32.
+
+ uint32_t threshold = (~bound+1u) % bound;
+
+ // Uniformity guarantees that this loop will terminate. In practice, it
+ // should usually terminate quickly; on average (assuming all bounds are
+ // equally likely), 82.25% of the time, we can expect it to require just
+ // one iteration. In the worst case, someone passes a bound of 2^31 + 1
+ // (i.e., 2147483649), which invalidates almost 50% of the range. In
+ // practice, bounds are typically small and only a tiny amount of the range
+ // is eliminated.
+ for (;;) {
+ uint32_t r = nextUInt();
+ if (r >= threshold)
+ return r % bound;
+ }
+ }
+
+ /// Generate a single precision floating point value on the interval [0, 1)
+ float nextFloat() {
+ /* Trick from MTGP: generate an uniformly distributed
+ single precision number in [1,2) and subtract 1. */
+ union {
+ uint32_t u;
+ float f;
+ } x;
+ x.u = (nextUInt() >> 9) | 0x3f800000UL;
+ return x.f - 1.0f;
+ }
+
+ /**
+ * \brief Generate a double precision floating point value on the interval [0, 1)
+ *
+ * \remark Since the underlying random number generator produces 32 bit output,
+ * only the first 32 mantissa bits will be filled (however, the resolution is still
+ * finer than in \ref nextFloat(), which only uses 23 mantissa bits)
+ */
+ double nextDouble() {
+ /* Trick from MTGP: generate an uniformly distributed
+ double precision number in [1,2) and subtract 1. */
+ union {
+ uint64_t u;
+ double d;
+ } x;
+ x.u = ((uint64_t) nextUInt() << 20) | 0x3ff0000000000000ULL;
+ return x.d - 1.0;
+ }
+
+ /**
+ * \brief Multi-step advance function (jump-ahead, jump-back)
+ *
+ * The method used here is based on Brown, "Random Number Generation
+ * with Arbitrary Stride", Transactions of the American Nuclear
+ * Society (Nov. 1994). The algorithm is very similar to fast
+ * exponentiation.
+ */
+ void advance(int64_t delta_) {
+ uint64_t
+ cur_mult = PCG32_MULT,
+ cur_plus = inc,
+ acc_mult = 1u,
+ acc_plus = 0u;
+
+ /* Even though delta is an unsigned integer, we can pass a signed
+ integer to go backwards, it just goes "the long way round". */
+ uint64_t delta = (uint64_t) delta_;
+
+ while (delta > 0) {
+ if (delta & 1) {
+ acc_mult *= cur_mult;
+ acc_plus = acc_plus * cur_mult + cur_plus;
+ }
+ cur_plus = (cur_mult + 1) * cur_plus;
+ cur_mult *= cur_mult;
+ delta /= 2;
+ }
+ state = acc_mult * state + acc_plus;
+ }
+
+ /**
+ * \brief Draw uniformly distributed permutation and permute the
+ * given STL container
+ *
+ * From: Knuth, TAoCP Vol. 2 (3rd 3d), Section 3.4.2
+ */
+ template <typename Iterator> void shuffle(Iterator begin, Iterator end) {
+ if (begin <= end) return;
+ for (Iterator it = end - 1; it > begin; --it)
+ std::iter_swap(it, begin + nextUInt((uint32_t) (it - begin + 1)));
+ }
+
+ /// Compute the distance between two PCG32 pseudorandom number generators
+ int64_t operator-(const pcg32 &other) const {
+ assert(inc == other.inc);
+
+ uint64_t
+ cur_mult = PCG32_MULT,
+ cur_plus = inc,
+ cur_state = other.state,
+ the_bit = 1u,
+ distance = 0u;
+
+ while (state != cur_state) {
+ if ((state & the_bit) != (cur_state & the_bit)) {
+ cur_state = cur_state * cur_mult + cur_plus;
+ distance |= the_bit;
+ }
+ assert((state & the_bit) == (cur_state & the_bit));
+ the_bit <<= 1;
+ cur_plus = (cur_mult + 1ULL) * cur_plus;
+ cur_mult *= cur_mult;
+ }
+
+ return (int64_t) distance;
+ }
+
+ /// Equality operator
+ bool operator==(const pcg32 &other) const { return state == other.state && inc == other.inc; }
+
+ /// Inequality operator
+ bool operator!=(const pcg32 &other) const { return state != other.state || inc != other.inc; }
+
+ uint64_t state; // RNG state. All values are possible.
+ uint64_t inc; // Controls which RNG sequence (stream) is selected. Must *always* be odd.
+};
+
+#endif // __PCG32_H
diff --git a/extern/quadriflow/3rd/pss/pss/parallel_stable_sort.h b/extern/quadriflow/3rd/pss/pss/parallel_stable_sort.h
new file mode 100644
index 00000000000..3d8854f92ca
--- /dev/null
+++ b/extern/quadriflow/3rd/pss/pss/parallel_stable_sort.h
@@ -0,0 +1,140 @@
+/*
+ Copyright (C) 2014 Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+ WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <iterator>
+#include <algorithm>
+#include <tbb/task.h>
+
+#include "pss_common.h"
+
+namespace pss {
+
+namespace internal {
+
+template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename RandomAccessIterator3, typename Compare>
+class merge_task: public tbb::task {
+ tbb::task* execute();
+ RandomAccessIterator1 xs, xe;
+ RandomAccessIterator2 ys, ye;
+ RandomAccessIterator3 zs;
+ Compare comp;
+ bool destroy;
+public:
+ merge_task( RandomAccessIterator1 xs_, RandomAccessIterator1 xe_, RandomAccessIterator2 ys_, RandomAccessIterator2 ye_, RandomAccessIterator3 zs_, bool destroy_, Compare comp_ ) :
+ xs(xs_), xe(xe_), ys(ys_), ye(ye_), zs(zs_), comp(comp_), destroy(destroy_)
+ {}
+};
+
+template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename RandomAccessIterator3, typename Compare>
+tbb::task* merge_task<RandomAccessIterator1,RandomAccessIterator2,RandomAccessIterator3,Compare>::execute() {
+ const size_t MERGE_CUT_OFF = 2000;
+ auto n = (xe-xs) + (ye-ys);
+ if( (size_t) n <= MERGE_CUT_OFF ) {
+ serial_move_merge( xs, xe, ys, ye, zs, comp );
+ if( destroy ) {
+ serial_destroy(xs,xe);
+ serial_destroy(ys,ye);
+ }
+ return NULL;
+ } else {
+ RandomAccessIterator1 xm;
+ RandomAccessIterator2 ym;
+ if( xe-xs < ye-ys ) {
+ ym = ys+(ye-ys)/2;
+ xm = std::upper_bound(xs,xe,*ym,comp);
+ } else {
+ xm = xs+(xe-xs)/2;
+ ym = std::lower_bound(ys,ye,*xm,comp);
+ }
+ RandomAccessIterator3 zm = zs + ((xm-xs) + (ym-ys));
+ tbb::task* right = new( allocate_additional_child_of(*parent()) ) merge_task( xm, xe, ym, ye, zm, destroy, comp );
+ spawn(*right);
+ recycle_as_continuation();
+ xe = xm;
+ ye = ym;
+ return this;
+ }
+}
+
+template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename Compare>
+class stable_sort_task: public tbb::task {
+ tbb::task* execute();
+ RandomAccessIterator1 xs, xe;
+ RandomAccessIterator2 zs;
+ Compare comp;
+ signed char inplace;
+public:
+ stable_sort_task(RandomAccessIterator1 xs_, RandomAccessIterator1 xe_, RandomAccessIterator2 zs_, int inplace_, Compare comp_ ) :
+ xs(xs_), xe(xe_), zs(zs_), comp(comp_), inplace(inplace_)
+ {}
+};
+
+template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename Compare>
+tbb::task* stable_sort_task<RandomAccessIterator1, RandomAccessIterator2, Compare>::execute() {
+ const size_t SORT_CUT_OFF = 500;
+ if ((size_t) (xe - xs) <= SORT_CUT_OFF) {
+ stable_sort_base_case(xs, xe, zs, inplace, comp);
+ return NULL;
+ } else {
+ RandomAccessIterator1 xm = xs + (xe - xs) / 2;
+ RandomAccessIterator2 zm = zs + (xm - xs);
+ RandomAccessIterator2 ze = zs + (xe - xs);
+ task* m;
+ if (inplace)
+ m = new (allocate_continuation()) merge_task<RandomAccessIterator2,RandomAccessIterator2,RandomAccessIterator1,Compare>(zs, zm, zm, ze, xs, inplace==2, comp);
+ else
+ m = new (allocate_continuation()) merge_task<RandomAccessIterator1,RandomAccessIterator1,RandomAccessIterator2,Compare>(xs, xm, xm, xe, zs, false, comp);
+ m->set_ref_count(2);
+ task* right = new(m->allocate_child()) stable_sort_task(xm,xe,zm,!inplace, comp);
+ spawn(*right);
+ recycle_as_child_of(*m);
+ xe=xm;
+ inplace=!inplace;
+ return this;
+ }
+}
+
+} // namespace internal
+
+template<typename RandomAccessIterator, typename Compare>
+void parallel_stable_sort( RandomAccessIterator xs, RandomAccessIterator xe, Compare comp ) {
+ typedef typename std::iterator_traits<RandomAccessIterator>::value_type T;
+ if( internal::raw_buffer z = internal::raw_buffer( sizeof(T)*(xe-xs) ) ) {
+ using tbb::task;
+ typedef typename std::iterator_traits<RandomAccessIterator>::value_type T;
+ internal::raw_buffer buf( sizeof(T)*(xe-xs) );
+ task::spawn_root_and_wait(*new( task::allocate_root() ) internal::stable_sort_task<RandomAccessIterator,T*,Compare>( xs, xe, (T*)buf.get(), 2, comp ));
+ } else
+ // Not enough memory available - fall back on serial sort
+ std::stable_sort( xs, xe, comp );
+}
+
+} // namespace pss
diff --git a/extern/quadriflow/3rd/pss/pss/pss_common.h b/extern/quadriflow/3rd/pss/pss/pss_common.h
new file mode 100644
index 00000000000..628c0f9830a
--- /dev/null
+++ b/extern/quadriflow/3rd/pss/pss/pss_common.h
@@ -0,0 +1,106 @@
+/*
+ Copyright (C) 2014 Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+ WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <utility>
+#include <iterator>
+
+namespace pss {
+
+namespace internal {
+
+//! Destroy sequence [xs,xe)
+template<class RandomAccessIterator>
+void serial_destroy( RandomAccessIterator zs, RandomAccessIterator ze ) {
+ typedef typename std::iterator_traits<RandomAccessIterator>::value_type T;
+ while( zs!=ze ) {
+ --ze;
+ (*ze).~T();
+ }
+}
+
+//! Merge sequences [xs,xe) and [ys,ye) to output sequence [zs,(xe-xs)+(ye-ys)), using std::move
+template<class RandomAccessIterator1, class RandomAccessIterator2, class RandomAccessIterator3, class Compare>
+void serial_move_merge( RandomAccessIterator1 xs, RandomAccessIterator1 xe, RandomAccessIterator2 ys, RandomAccessIterator2 ye, RandomAccessIterator3 zs, Compare comp ) {
+ if( xs!=xe ) {
+ if( ys!=ye ) {
+ for(;;) {
+ if( comp(*ys,*xs) ) {
+ *zs = std::move(*ys);
+ ++zs;
+ if( ++ys==ye ) { break; }
+ } else {
+ *zs = std::move(*xs);
+ ++zs;
+ if( ++xs==xe ) { goto movey; }
+ }
+ }
+ }
+ ys = xs;
+ ye = xe;
+ }
+movey:
+ std::move( ys, ye, zs );
+}
+
+template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename Compare>
+void stable_sort_base_case( RandomAccessIterator1 xs, RandomAccessIterator1 xe, RandomAccessIterator2 zs, int inplace, Compare comp) {
+ std::stable_sort( xs, xe, comp );
+ if( inplace!=2 ) {
+ RandomAccessIterator2 ze = zs + (xe-xs);
+ typedef typename std::iterator_traits<RandomAccessIterator2>::value_type T;
+ if( inplace )
+ // Initialize the temporary buffer
+ for( ; zs<ze; ++zs )
+ new(&*zs) T;
+ else
+ // Initialize the temporary buffer and move keys to it.
+ for( ; zs<ze; ++xs, ++zs )
+ new(&*zs) T(std::move(*xs));
+ }
+}
+
+//! Raw memory buffer with automatic cleanup.
+class raw_buffer {
+ void* ptr;
+public:
+ //! Try to obtain buffer of given size.
+ raw_buffer( size_t bytes ) : ptr( operator new(bytes,std::nothrow) ) {}
+ //! True if buffer was successfully obtained, zero otherwise.
+ operator bool() const {return ptr;}
+ //! Return pointer to buffer, or NULL if buffer could not be obtained.
+ void* get() const {return ptr;}
+ //! Destroy buffer
+ ~raw_buffer() {operator delete(ptr);}
+};
+
+} // namespace internal
+
+} // namespace pss
diff --git a/extern/quadriflow/CMakeLists.txt b/extern/quadriflow/CMakeLists.txt
new file mode 100644
index 00000000000..3891079073e
--- /dev/null
+++ b/extern/quadriflow/CMakeLists.txt
@@ -0,0 +1,107 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2019, Blender Foundation
+# All rights reserved.
+# ***** END GPL LICENSE BLOCK *****
+
+# avoid noisy warnings
+if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
+ add_c_flag(
+ "-Wno-unused-result"
+ )
+endif()
+
+set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+if (WIN32)
+ add_definitions(-D_USE_MATH_DEFINES)
+endif()
+
+set(LEMON_3RD_PATH 3rd/lemon-1.3.1)
+
+set(LEMON_SOURCE_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${LEMON_3RD_PATH})
+
+set(LEMON_SRC ${LEMON_SOURCE_ROOT_DIR}/lemon)
+set(LEMON_INCLUDE_DIRS ${LEMON_SOURCE_ROOT_DIR})
+
+set(LEMON_GEN_DIR ${CMAKE_BINARY_DIR}/extern/quadriflow/${LEMON_3RD_PATH})
+configure_file(
+ ${LEMON_SRC}/config.h.in
+ ${LEMON_GEN_DIR}/lemon/config.h
+ )
+set(LEMON_SOURCES
+ ${LEMON_SRC}/arg_parser.cc
+ ${LEMON_SRC}/base.cc
+ ${LEMON_SRC}/color.cc
+ ${LEMON_SRC}/lp_base.cc
+ ${LEMON_SRC}/lp_skeleton.cc
+ ${LEMON_SRC}/random.cc
+ ${LEMON_SRC}/bits/windows.cc
+ )
+
+set(INC
+ src
+ 3rd/pcg32
+ 3rd/pss
+ ${LEMON_INCLUDE_DIRS}
+ ${LEMON_GEN_DIR}
+)
+
+set(INC_SYS
+ ${BOOST_INCLUDE_DIR}
+ ${EIGEN3_INCLUDE_DIRS}
+)
+
+set(SRC
+ src/adjacent-matrix.cpp
+ src/adjacent-matrix.hpp
+ src/compare-key.hpp
+ src/config.hpp
+ src/dedge.cpp
+ src/dedge.hpp
+ src/disajoint-tree.hpp
+ src/dset.hpp
+ src/field-math.hpp
+ src/flow.hpp
+ src/hierarchy.cpp
+ src/hierarchy.hpp
+ src/loader.cpp
+ src/loader.hpp
+ src/localsat.cpp
+ src/localsat.hpp
+ src/merge-vertex.cpp
+ src/merge-vertex.hpp
+ src/optimizer.cpp
+ src/optimizer.hpp
+ src/parametrizer.cpp
+ src/parametrizer-flip.cpp
+ src/parametrizer-int.cpp
+ src/parametrizer-mesh.cpp
+ src/parametrizer-scale.cpp
+ src/parametrizer-sing.cpp
+ src/parametrizer.hpp
+ src/serialize.hpp
+ src/subdivide.cpp
+ src/subdivide.hpp
+ ${LEMON_SOURCES}
+)
+
+set(LIB
+)
+
+blender_add_lib(extern_quadriflow "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/extern/quadriflow/LICENSE.txt b/extern/quadriflow/LICENSE.txt
new file mode 100644
index 00000000000..5e963f42ca7
--- /dev/null
+++ b/extern/quadriflow/LICENSE.txt
@@ -0,0 +1,37 @@
+Copyright (c) 2018 Jingwei Huang, Yichao Zhou, Matthias Niessner,
+Jonathan Shewchuk and Leonidas Guibas. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+("Enhancements") to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to the authors of this software, without
+imposing a separate written license agreement for such Enhancements, then you
+hereby grant the following license: a non-exclusive, royalty-free perpetual
+license to install, use, modify, prepare derivative works, incorporate into
+other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form. \ No newline at end of file
diff --git a/extern/quadriflow/README.blender b/extern/quadriflow/README.blender
new file mode 100644
index 00000000000..c88a6d43353
--- /dev/null
+++ b/extern/quadriflow/README.blender
@@ -0,0 +1,5 @@
+Project: QuadriFlow
+URL: https://github.com/hjwdzh/QuadriFlow
+License: MIT and Boost Software License
+Upstream version: 27a6867
+Local modifications: Apply patches/blender.patch
diff --git a/extern/quadriflow/README.md b/extern/quadriflow/README.md
new file mode 100644
index 00000000000..dae22414184
--- /dev/null
+++ b/extern/quadriflow/README.md
@@ -0,0 +1,134 @@
+# QuadriFlow: A Scalable and Robust Method for Quadrangulation
+
+Source code for the paper:
+
+Jingwei Huang, Yichao Zhou, Matthias Niessner, Jonathan Shewchuk and Leonidas Guibas. [**QuadriFlow: A Scalable and Robust Method for Quadrangulation**](http://stanford.edu/~jingweih/papers/quadriflow/quadriflow.pdf), The Eurographics Symposium on Geometry Processing (SGP) 2018.
+
+<!-- ## Processing Result -->
+![QuadriFlow Results](https://github.com/hjwdzh/quadriflow/raw/master/img/result.jpg)
+
+## WebGL Application
+Our 3D WebGL Apps for QuadriFlow are online! Without any installation, you are able to
+* [**Compare**](https://yichaozhou.com/publication/1805quadriflow/#demo) QuadriFlow with previous methods;
+* [**Quadrangulate**](https://yichaozhou.com/publication/1805quadriflow/#tool) your own meshes and
+ download the result!
+
+## Desktop Software
+The software supports cmake build for Linux/Mac/Windows systems. For linux and mac users, run **`sh demo.sh`** to build and try the QuadriFlow example, which converts `examples/Gargoyle_input.obj` to `examples/Gargoyle_quadriflow.obj`.
+
+### Install
+
+```
+git clone git://github.com/hjwdzh/quadriflow
+cd quadriflow
+mkdir build
+cd build
+cmake .. -DCMAKE_BUILD_TYPE=release
+make -j
+```
+
+### QuadriFlow Software
+
+We take a manifold triangle mesh `input.obj` and generate a manifold quad mesh `output.obj`. The face number increases linearly with the resolution controled by the user.
+
+```
+./quadriflow -i input.obj -o output.obj -f [resolution]
+```
+
+Here, the resolution is the desired number of faces in the quad mesh.
+
+## Advanced Functions
+
+### Min-cost Flow
+By default, `quadriflow` uses the Boykov maximum flow solver from boost becuase it is faster. To
+enable the adaptive network simplex minimum-cost flow solver, you can enable the `-mcf` option:
+
+```
+./quadriflow -mcf -i input.obj -o output.obj -f [resolution]
+```
+
+### Sharp Preserving
+By default, `quadriflow` does not explicitly detect and perserve the sharp edges in the model. To
+enable this feature, uses
+
+```
+./quadriflow -sharp -i input.obj -o output.obj -f [resolution]
+```
+
+### SAT Flip Removal (Unix Only)
+By default, `quadriflow` does not use the SAT solver to remove the flips in the integer offsets
+map. To remove the flips and guarantee a watertight result mesh, you can enable the SAT solver.
+First, make sure that `minisat` and `timeout` is properly installed under your `${PATH}`. The
+former can be done by building `3rd/MapleCOMSPS_LRB/CMakeLists.txt` and copying `minisat` to `/usr/bin`.
+In addition, `timeout` is included in coreutils. If you are using Mac, you can install it using
+homebrew:
+```
+brew install coreutils
+export PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH"
+```
+
+You can verify if those binaries are properly installed by executing
+```
+which minisat
+which timeout
+```
+
+After that, you can enable SAT flip removal procedure by executing
+```
+./quadriflow -sat -i input.obj -o output.obj -f [resolution]
+```
+
+When using the SAT flip removal, we also suggest you enabling the verbose logging to understand
+what is going on. You can build quadriflow with the following options:
+```
+cmake .. -DCMAKE_BUILD_TYPE=release -DBUILD_LOG=ON
+```
+
+### GUROBI Support (For Benchmark Purpose)
+
+To use the Gurobi integer programming to solve the integer offset problem, you can build QuadriFlow with
+```
+cmake .. -DCMAKE_BUILD_TYPE=release -DBUILD_GUROBI=ON -DBUILD_LOG=ON
+```
+This override other solvers and should only be used for benchmark purpose.
+
+## External Dependencies
+* Boost
+* Eigen
+* OpenMP (optional in CMake)
+* TBB (optional in CMake)
+* GUROBI (for benchmark purpose only)
+
+## Licenses
+
+QuadriFlow is released under [MIT License](LICENSE.txt).
+For 3rd dependencies,
+* Boost and Lemon are released under [Boost Software License](https://lemon.cs.elte.hu/trac/lemon/wiki/License)
+* Most part of Eigen is released under [MPL2](https://www.mozilla.org/en-US/MPL/2.0/FAQ/)
+ * Sparse Cholesky Decomposition algorithms are released under LGPL
+ * To replace it using Sparse LU decomposition with a more permissive MPL2 license (a little slower), enable `BUILD_FREE_LICENSE` in CMake (e.g., `-DBUILD_FREE_LICENSE=ON`).
+* `pcg32.h` is released under the Apache License, Version 2.0
+* `parallel_stable_sort.h` is released under the MIT License
+
+## Authors
+- [Jingwei Huang](mailto:jingweih@stanford.edu)
+- [Yichao Zhou](mailto:zyc@berkeley.edu)
+
+&copy; 2018 Jingwei Huang and Yichao Zhou All Rights Reserved
+
+**IMPORTANT**: If you use this software please cite the following in any resulting publication:
+```
+@article {10.1111:cgf.13498,
+ journal = {Computer Graphics Forum},
+ title = {{QuadriFlow: A Scalable and Robust Method for Quadrangulation}},
+ author = {Huang, Jingwei and Zhou, Yichao and Niessner, Matthias and Shewchuk, Jonathan Richard and Guibas, Leonidas J.},
+ year = {2018},
+ publisher = {The Eurographics Association and John Wiley & Sons Ltd.},
+ ISSN = {1467-8659},
+ DOI = {10.1111/cgf.13498}
+}
+```
+
+## Triangle Manifold
+
+In case you are dealing with a triangle mesh that is not a manifold, we implemented the software that converts any triangle mesh to watertight manifold. Please visit https://github.com/hjwdzh/Manifold for details.
diff --git a/extern/quadriflow/patches/blender.patch b/extern/quadriflow/patches/blender.patch
new file mode 100644
index 00000000000..d131abc52e2
--- /dev/null
+++ b/extern/quadriflow/patches/blender.patch
@@ -0,0 +1,102 @@
+diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc
+index 35a73d9..0eeba8a 100644
+--- a/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc
++++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc
+@@ -221,9 +221,8 @@ namespace lemon {
+ const std::string &opt)
+ {
+ Opts::iterator o = _opts.find(opt);
+- Opts::iterator s = _opts.find(syn);
+ LEMON_ASSERT(o!=_opts.end(), "Unknown option: '"+opt+"'");
+- LEMON_ASSERT(s==_opts.end(), "Option already used: '"+syn+"'");
++ LEMON_ASSERT(_opts.find(syn)==_opts.end(), "Option already used: '"+syn+"'");
+ ParData p;
+ p.help=opt;
+ p.mandatory=false;
+diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h
+index 6ccad33..388e990 100644
+--- a/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h
++++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h
+@@ -234,7 +234,7 @@ namespace lemon {
+ int in_arc, join, u_in, v_in, u_out, v_out;
+ Value delta;
+
+- const Value MAX;
++ const Value MAX_VALUE;
+
+ public:
+
+@@ -649,9 +649,9 @@ namespace lemon {
+ NetworkSimplex(const GR& graph, bool arc_mixing = true) :
+ _graph(graph), _node_id(graph), _arc_id(graph),
+ _arc_mixing(arc_mixing),
+- MAX(std::numeric_limits<Value>::max()),
++ MAX_VALUE(std::numeric_limits<Value>::max()),
+ INF(std::numeric_limits<Value>::has_infinity ?
+- std::numeric_limits<Value>::infinity() : MAX)
++ std::numeric_limits<Value>::infinity() : MAX_VALUE)
+ {
+ // Check the number types
+ LEMON_ASSERT(std::numeric_limits<Value>::is_signed,
+@@ -1076,9 +1076,9 @@ namespace lemon {
+ for (int i = 0; i != _arc_num; ++i) {
+ Value c = _lower[i];
+ if (c >= 0) {
+- _cap[i] = _upper[i] < MAX ? _upper[i] - c : INF;
++ _cap[i] = _upper[i] < MAX_VALUE ? _upper[i] - c : INF;
+ } else {
+- _cap[i] = _upper[i] < MAX + c ? _upper[i] - c : INF;
++ _cap[i] = _upper[i] < MAX_VALUE + c ? _upper[i] - c : INF;
+ }
+ _supply[_source[i]] -= c;
+ _supply[_target[i]] += c;
+@@ -1282,7 +1282,7 @@ namespace lemon {
+ d = _flow[e];
+ if (_pred_dir[u] == DIR_DOWN) {
+ c = _cap[e];
+- d = c >= MAX ? INF : c - d;
++ d = c >= MAX_VALUE ? INF : c - d;
+ }
+ if (d < delta) {
+ delta = d;
+@@ -1297,7 +1297,7 @@ namespace lemon {
+ d = _flow[e];
+ if (_pred_dir[u] == DIR_UP) {
+ c = _cap[e];
+- d = c >= MAX ? INF : c - d;
++ d = c >= MAX_VALUE ? INF : c - d;
+ }
+ if (d <= delta) {
+ delta = d;
+@@ -1559,7 +1559,7 @@ namespace lemon {
+ _pi[_target[in_arc]]) >= 0) continue;
+ findJoinNode();
+ bool change = findLeavingArc();
+- if (delta >= MAX) return false;
++ if (delta >= MAX_VALUE) return false;
+ changeFlow(change);
+ if (change) {
+ updateTreeStructure();
+@@ -1598,7 +1598,7 @@ namespace lemon {
+ while (pivot.findEnteringArc()) {
+ findJoinNode();
+ bool change = findLeavingArc();
+- if (delta >= MAX) return UNBOUNDED;
++ if (delta >= MAX_VALUE) return UNBOUNDED;
+ changeFlow(change);
+ if (change) {
+ updateTreeStructure();
+diff --git a/extern/quadriflow/src/hierarchy.cpp b/extern/quadriflow/src/hierarchy.cpp
+index c333256..8cc41da 100644
+--- a/extern/quadriflow/src/hierarchy.cpp
++++ b/extern/quadriflow/src/hierarchy.cpp
+@@ -1133,7 +1133,8 @@ void Hierarchy::propagateConstraints() {
+ auto& COw = mCOw[l];
+ auto& COw_next = mCOw[l + 1];
+ auto& toUpper = mToUpper[l];
+- MatrixXd& S = mS[l];
++ // FIXME
++ // MatrixXd& S = mS[l];
+
+ for (uint32_t i = 0; i != mV[l + 1].cols(); ++i) {
+ Vector2i upper = toUpper.col(i);
diff --git a/extern/quadriflow/src/Optimizer.cu b/extern/quadriflow/src/Optimizer.cu
new file mode 100644
index 00000000000..8520c3f90a8
--- /dev/null
+++ b/extern/quadriflow/src/Optimizer.cu
@@ -0,0 +1,281 @@
+#include <glm/glm.hpp>
+#include <cuda_runtime.h>
+#include "AdjacentMatrix.h"
+
+__device__ __host__ glm::dvec3
+middle_point(const glm::dvec3 &p0, const glm::dvec3 &n0, const glm::dvec3 &p1, const glm::dvec3 &n1) {
+ /* How was this derived?
+ *
+ * Minimize \|x-p0\|^2 + \|x-p1\|^2, where
+ * dot(n0, x) == dot(n0, p0)
+ * dot(n1, x) == dot(n1, p1)
+ *
+ * -> Lagrange multipliers, set derivative = 0
+ * Use first 3 equalities to write x in terms of
+ * lambda_1 and lambda_2. Substitute that into the last
+ * two equations and solve for the lambdas. Finally,
+ * add a small epsilon term to avoid issues when n1=n2.
+ */
+ double n0p0 = glm::dot(n0, p0), n0p1 = glm::dot(n0, p1),
+ n1p0 = glm::dot(n1, p0), n1p1 = glm::dot(n1, p1),
+ n0n1 = glm::dot(n0, n1),
+ denom = 1.0f / (1.0f - n0n1*n0n1 + 1e-4f),
+ lambda_0 = 2.0f*(n0p1 - n0p0 - n0n1*(n1p0 - n1p1))*denom,
+ lambda_1 = 2.0f*(n1p0 - n1p1 - n0n1*(n0p1 - n0p0))*denom;
+
+ return 0.5 * (p0 + p1) - 0.25 * (n0 * lambda_0 + n1 * lambda_1);
+}
+
+__device__ __host__ glm::dvec3
+position_round_4(const glm::dvec3 &o, const glm::dvec3 &q,
+const glm::dvec3 &n, const glm::dvec3 &p,
+double scale) {
+ double inv_scale = 1.0 / scale;
+ glm::dvec3 t = glm::cross(n, q);
+ glm::dvec3 d = p - o;
+ return o +
+ q * std::round(glm::dot(q, d) * inv_scale) * scale +
+ t * std::round(glm::dot(t, d) * inv_scale) * scale;
+}
+
+__device__ __host__ glm::dvec3
+position_floor_4(const glm::dvec3 &o, const glm::dvec3 &q,
+const glm::dvec3 &n, const glm::dvec3 &p,
+double scale) {
+ double inv_scale = 1.0 / scale;
+ glm::dvec3 t = glm::cross(n,q);
+ glm::dvec3 d = p - o;
+ return o +
+ q * std::floor(glm::dot(q, d) * inv_scale) * scale +
+ t * std::floor(glm::dot(t, d) * inv_scale) * scale;
+}
+
+
+__device__ __host__ double cudaSignum(double value) {
+ return std::copysign((double)1, value);
+}
+
+__device__ __host__ void
+compat_orientation_extrinsic_4(const glm::dvec3 &q0, const glm::dvec3 &n0,
+const glm::dvec3 &q1, const glm::dvec3 &n1, glm::dvec3& value1, glm::dvec3& value2) {
+ const glm::dvec3 A[2] = { q0, glm::cross(n0, q0) };
+ const glm::dvec3 B[2] = { q1, glm::cross(n1, q1) };
+
+ double best_score = -1e10;
+ int best_a = 0, best_b = 0;
+
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j < 2; ++j) {
+ double score = std::abs(glm::dot(A[i], B[j]));
+ if (score > best_score + 1e-6) {
+ best_a = i;
+ best_b = j;
+ best_score = score;
+ }
+ }
+ }
+ const double dp = glm::dot(A[best_a], B[best_b]);
+ value1 = A[best_a];
+ value2 = B[best_b] * cudaSignum(dp);
+}
+
+__device__ __host__ void
+compat_position_extrinsic_4(
+const glm::dvec3 &p0, const glm::dvec3 &n0, const glm::dvec3 &q0, const glm::dvec3 &o0,
+const glm::dvec3 &p1, const glm::dvec3 &n1, const glm::dvec3 &q1, const glm::dvec3 &o1,
+double scale, glm::dvec3& v1, glm::dvec3& v2) {
+
+ glm::dvec3 t0 = glm::cross(n0, q0), t1 = glm::cross(n1, q1);
+ glm::dvec3 middle = middle_point(p0, n0, p1, n1);
+ glm::dvec3 o0p = position_floor_4(o0, q0, n0, middle, scale);
+ glm::dvec3 o1p = position_floor_4(o1, q1, n1, middle, scale);
+
+ double best_cost = 1e10;
+ int best_i = -1, best_j = -1;
+
+ for (int i = 0; i<4; ++i) {
+ glm::dvec3 o0t = o0p + (q0 * ((i & 1) * scale) + t0 * (((i & 2) >> 1) * scale));
+ for (int j = 0; j<4; ++j) {
+ glm::dvec3 o1t = o1p + (q1 * ((j & 1) * scale) + t1 * (((j & 2) >> 1) * scale));
+ glm::dvec3 t = o0t - o1t;
+ double cost = glm::dot(t, t);
+
+ if (cost < best_cost) {
+ best_i = i;
+ best_j = j;
+ best_cost = cost;
+ }
+ }
+ }
+
+ v1 = o0p + (q0 * ((best_i & 1) * scale) + t0 * (((best_i & 2) >> 1) * scale)),
+ v2 = o1p + (q1 * ((best_j & 1) * scale) + t1 * (((best_j & 2) >> 1) * scale));
+}
+
+__global__
+void cudaUpdateOrientation(int* phase, int num_phases, glm::dvec3* N, glm::dvec3* Q, Link* adj, int* adjOffset, int num_adj) {
+ int pi = blockIdx.x * blockDim.x + threadIdx.x;
+
+// for (int pi = 0; pi < num_phases; ++pi) {
+ if (pi >= num_phases)
+ return;
+ int i = phase[pi];
+ glm::dvec3 n_i = N[i];
+ double weight_sum = 0.0f;
+ glm::dvec3 sum = Q[i];
+
+ for (int l = adjOffset[i]; l < adjOffset[i + 1]; ++l) {
+ Link link = adj[l];
+ const int j = link.id;
+ const double weight = link.weight;
+ if (weight == 0)
+ continue;
+ glm::dvec3 n_j = N[j];
+ glm::dvec3 q_j = Q[j];
+ glm::dvec3 value1, value2;
+ compat_orientation_extrinsic_4(sum, n_i, q_j, n_j, value1, value2);
+ sum = value1 * weight_sum + value2 * weight;
+ sum -= n_i*glm::dot(n_i, sum);
+ weight_sum += weight;
+
+ double norm = glm::length(sum);
+ if (norm > 2.93873587705571876e-39f)
+ sum /= norm;
+ }
+
+ if (weight_sum > 0) {
+ Q[i] = sum;
+ }
+// }
+}
+
+__global__
+void cudaPropagateOrientationUpper(glm::dvec3* srcField, glm::ivec2* toUpper, glm::dvec3* N, glm::dvec3* destField, int num_orientation) {
+ int i = blockIdx.x * blockDim.x + threadIdx.x;
+// for (int i = 0; i < num_orientation; ++i) {
+ if (i >= num_orientation)
+ return;
+ for (int k = 0; k < 2; ++k) {
+ int dest = toUpper[i][k];
+ if (dest == -1)
+ continue;
+ glm::dvec3 q = srcField[i];
+ glm::dvec3 n = N[dest];
+ destField[dest] = q - n * glm::dot(n, q);
+ }
+// }
+}
+
+__global__
+void cudaPropagateOrientationLower(glm::ivec2* toUpper, glm::dvec3* Q, glm::dvec3* N, glm::dvec3* Q_next, glm::dvec3* N_next, int num_toUpper) {
+ int i = blockIdx.x * blockDim.x + threadIdx.x;
+// for (int i = 0; i < num_toUpper; ++i) {
+ if (i >= num_toUpper)
+ return;
+ glm::ivec2 upper = toUpper[i];
+ glm::dvec3 q0 = Q[upper[0]];
+ glm::dvec3 n0 = N[upper[0]];
+
+ glm::dvec3 q, q1, n1, value1, value2;
+ if (upper[1] != -1) {
+ q1 = Q[upper[1]];
+ n1 = N[upper[1]];
+ compat_orientation_extrinsic_4(q0, n0, q1, n1, value1, value2);
+ q = value1 + value2;
+ }
+ else {
+ q = q0;
+ }
+ glm::dvec3 n = N_next[i];
+ q -= glm::dot(n, q) * n;
+
+ double len = q.x * q.x + q.y * q.y + q.z * q.z;
+ if (len > 2.93873587705571876e-39f)
+ q /= sqrt(len);
+ Q_next[i] = q;
+// }
+}
+
+
+__global__
+void cudaUpdatePosition(int* phase, int num_phases, glm::dvec3* N, glm::dvec3* Q, Link* adj, int* adjOffset, int num_adj, glm::dvec3* V, glm::dvec3* O, double scale) {
+ int pi = blockIdx.x * blockDim.x + threadIdx.x;
+
+// for (int pi = 0; pi < num_phases; ++pi) {
+ if (pi >= num_phases)
+ return;
+ int i = phase[pi];
+ glm::dvec3 n_i = N[i], v_i = V[i];
+ glm::dvec3 q_i = Q[i];
+ glm::dvec3 sum = O[i];
+ double weight_sum = 0.0f;
+
+ for (int l = adjOffset[i]; l < adjOffset[i + 1]; ++l) {
+ Link link = adj[l];
+ int j = link.id;
+ const double weight = link.weight;
+ if (weight == 0)
+ continue;
+
+ glm::dvec3 n_j = N[j], v_j = V[j];
+ glm::dvec3 q_j = Q[j], o_j = O[j];
+ glm::dvec3 v1, v2;
+ compat_position_extrinsic_4(
+ v_i, n_i, q_i, sum, v_j, n_j, q_j, o_j, scale, v1, v2);
+
+ sum = v1*weight_sum +v2*weight;
+ weight_sum += weight;
+ if (weight_sum > 2.93873587705571876e-39f)
+ sum /= weight_sum;
+ sum -= glm::dot(n_i, sum - v_i)*n_i;
+ }
+
+ if (weight_sum > 0) {
+ O[i] = position_round_4(sum, q_i, n_i, v_i, scale);
+ }
+// }
+}
+
+__global__
+void cudaPropagatePositionUpper(glm::dvec3* srcField, glm::ivec2* toUpper, glm::dvec3* N, glm::dvec3* V, glm::dvec3* destField, int num_position) {
+ int i = blockIdx.x * blockDim.x + threadIdx.x;
+// for (int i = 0; i < num_position; ++i) {
+ if (i >= num_position)
+ return;
+ for (int k = 0; k < 2; ++k) {
+ int dest = toUpper[i][k];
+ if (dest == -1)
+ continue;
+ glm::dvec3 o = srcField[i], n = N[dest], v = V[dest];
+ o -= n * glm::dot(n, o - v);
+ destField[dest] = o;
+ }
+// }
+}
+
+
+void UpdateOrientation(int* phase, int num_phases, glm::dvec3* N, glm::dvec3* Q, Link* adj, int* adjOffset, int num_adj) {
+ cudaUpdateOrientation << <(num_phases + 255) / 256, 256 >> >(phase, num_phases, N, Q, adj, adjOffset, num_adj);
+// cudaUpdateOrientation(phase, num_phases, N, Q, adj, adjOffset, num_adj);
+}
+
+void PropagateOrientationUpper(glm::dvec3* srcField, int num_orientation, glm::ivec2* toUpper, glm::dvec3* N, glm::dvec3* destField) {
+ cudaPropagateOrientationUpper << <(num_orientation + 255) / 256, 256 >> >(srcField, toUpper, N, destField, num_orientation);
+// cudaPropagateOrientationUpper(srcField, toUpper, N, destField, num_orientation);
+}
+
+void PropagateOrientationLower(glm::ivec2* toUpper, glm::dvec3* Q, glm::dvec3* N, glm::dvec3* Q_next, glm::dvec3* N_next, int num_toUpper) {
+ cudaPropagateOrientationLower << <(num_toUpper + 255) / 256, 256 >> >(toUpper, Q, N, Q_next, N_next, num_toUpper);
+// cudaPropagateOrientationLower(toUpper, Q, N, Q_next, N_next, num_toUpper);
+}
+
+
+void UpdatePosition(int* phase, int num_phases, glm::dvec3* N, glm::dvec3* Q, Link* adj, int* adjOffset, int num_adj, glm::dvec3* V, glm::dvec3* O, double scale) {
+ cudaUpdatePosition << <(num_phases + 255) / 256, 256 >> >(phase, num_phases, N, Q, adj, adjOffset, num_adj, V, O, scale);
+// cudaUpdatePosition(phase, num_phases, N, Q, adj, adjOffset, num_adj, V, O, scale);
+}
+
+void PropagatePositionUpper(glm::dvec3* srcField, int num_position, glm::ivec2* toUpper, glm::dvec3* N, glm::dvec3* V, glm::dvec3* destField) {
+ cudaPropagatePositionUpper << <(num_position + 255) / 256, 256 >> >(srcField, toUpper, N, V, destField, num_position);
+// cudaPropagatePositionUpper(srcField, toUpper, N, V, destField, num_position);
+}
diff --git a/extern/quadriflow/src/adjacent-matrix.cpp b/extern/quadriflow/src/adjacent-matrix.cpp
new file mode 100644
index 00000000000..e20ffb05f6d
--- /dev/null
+++ b/extern/quadriflow/src/adjacent-matrix.cpp
@@ -0,0 +1,35 @@
+#include "config.hpp"
+#include "adjacent-matrix.hpp"
+#include "dedge.hpp"
+#include <fstream>
+
+namespace qflow {
+
+void generate_adjacency_matrix_uniform(
+ const MatrixXi &F, const VectorXi &V2E, const VectorXi &E2E,
+ const VectorXi &nonManifold, AdjacentMatrix& adj) {
+ adj.resize(V2E.size());
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int i = 0; i < adj.size(); ++i) {
+ int start = V2E[i];
+ int edge = start;
+ if (start == -1)
+ continue;
+ do {
+ int base = edge % 3, f = edge / 3;
+ int opp = E2E[edge], next = dedge_next_3(opp);
+ if (adj[i].empty())
+ adj[i].push_back(Link(F((base + 2) % 3, f)));
+ if (opp == -1 || next != start) {
+ adj[i].push_back(Link(F((base + 1) % 3, f)));
+ if (opp == -1)
+ break;
+ }
+ edge = next;
+ } while (edge != start);
+ }
+}
+
+} // namespace qflow
diff --git a/extern/quadriflow/src/adjacent-matrix.hpp b/extern/quadriflow/src/adjacent-matrix.hpp
new file mode 100644
index 00000000000..e3eb2e12a47
--- /dev/null
+++ b/extern/quadriflow/src/adjacent-matrix.hpp
@@ -0,0 +1,37 @@
+#ifndef ADJACENT_MATRIX_H_
+#define ADJACENT_MATRIX_H_
+
+#include <vector>
+
+namespace qflow {
+
+struct Link
+{
+ Link(){}
+ Link(int _id, double _w = 1)
+ : id(_id), weight(_w)
+ {}
+ inline bool operator<(const Link &link) const { return id < link.id; }
+ int id;
+ double weight;
+};
+
+struct TaggedLink {
+ int id;
+ unsigned char flag;
+ TaggedLink(){}
+ TaggedLink(int id) : id(id), flag(0) { }
+ bool used() const { return flag & 1; }
+ void markUsed() { flag |= 1; }
+ TaggedLink& operator=(const Link& l) {
+ flag = 0;
+ id = l.id;
+ return *this;
+ }
+};
+
+typedef std::vector<std::vector<Link> > AdjacentMatrix;
+
+} // namespace qflow
+
+#endif \ No newline at end of file
diff --git a/extern/quadriflow/src/compare-key.hpp b/extern/quadriflow/src/compare-key.hpp
new file mode 100644
index 00000000000..df9109d62e0
--- /dev/null
+++ b/extern/quadriflow/src/compare-key.hpp
@@ -0,0 +1,102 @@
+#ifndef COMPARE_KEY_H_
+#define COMPARE_KEY_H_
+
+#include <iostream>
+#include <map>
+
+namespace qflow {
+
+struct Key2i
+{
+ Key2i(int x, int y)
+ : key(std::make_pair(x, y))
+ {}
+ bool operator==(const Key2i& other) const
+ {
+ return key == other.key;
+ }
+ bool operator<(const Key2i& other) const
+ {
+ return key < other.key;
+ }
+ std::pair<int, int> key;
+};
+
+struct Key3i
+{
+ Key3i(int x, int y, int z)
+ : key(std::make_pair(x, std::make_pair(y, z)))
+ {}
+ bool operator==(const Key3i& other) const
+ {
+ return key == other.key;
+ }
+ bool operator<(const Key3i& other) const
+ {
+ return key < other.key;
+ }
+ std::pair<int, std::pair<int, int> > key;
+};
+
+struct Key3f
+{
+ Key3f(double x, double y, double z, double threshold)
+ : key(std::make_pair(x / threshold, std::make_pair(y / threshold, z / threshold)))
+ {}
+ bool operator==(const Key3f& other) const
+ {
+ return key == other.key;
+ }
+ bool operator<(const Key3f& other) const
+ {
+ return key < other.key;
+ }
+ std::pair<int, std::pair<int, int> > key;
+};
+
+struct KeySorted2i
+{
+ KeySorted2i(int x, int y)
+ : key(std::make_pair(x, y))
+ {
+ if (x > y)
+ std::swap(key.first, key.second);
+ }
+ bool operator==(const KeySorted2i& other) const
+ {
+ return key == other.key;
+ }
+ bool operator<(const KeySorted2i& other) const
+ {
+ return key < other.key;
+ }
+ std::pair<int, int> key;
+};
+
+struct KeySorted3i
+{
+ KeySorted3i(int x, int y, int z)
+ : key(std::make_pair(x, std::make_pair(y, z)))
+ {
+ if (key.first > key.second.first)
+ std::swap(key.first, key.second.first);
+ if (key.first > key.second.second)
+ std::swap(key.first, key.second.second);
+ if (key.second.first > key.second.second)
+ std::swap(key.second.first, key.second.second);
+ }
+ bool operator==(const Key3i& other) const
+ {
+ return key == other.key;
+ }
+ bool operator<(const Key3i& other) const
+ {
+ return key < other.key;
+ }
+ std::pair<int, std::pair<int, int> > key;
+};
+
+
+} // namespace qflow
+
+#endif
diff --git a/extern/quadriflow/src/config.hpp b/extern/quadriflow/src/config.hpp
new file mode 100644
index 00000000000..842b885a209
--- /dev/null
+++ b/extern/quadriflow/src/config.hpp
@@ -0,0 +1,34 @@
+#ifndef CONFIG_H_
+#define CONFIG_H_
+
+// Move settings to cmake to make CMake happy :)
+
+// #define WITH_SCALE
+// #define WITH_CUDA
+
+const int GRAIN_SIZE = 1024;
+
+#ifdef LOG_OUTPUT
+
+#define lprintf(...) printf(__VA_ARGS__)
+#define lputs(...) puts(__VA_ARGS__)
+
+#else
+
+#define lprintf(...) void(0)
+#define lputs(...) void(0)
+
+#endif
+
+#include <chrono>
+
+namespace qflow {
+
+// simulation of Windows GetTickCount()
+unsigned long long inline GetCurrentTime64() {
+ using namespace std::chrono;
+ return duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
+}
+} // namespace qflow
+
+#endif
diff --git a/extern/quadriflow/src/dedge.cpp b/extern/quadriflow/src/dedge.cpp
new file mode 100644
index 00000000000..b030e20d6a1
--- /dev/null
+++ b/extern/quadriflow/src/dedge.cpp
@@ -0,0 +1,487 @@
+#include "dedge.hpp"
+#include "config.hpp"
+
+#include <atomic>
+#include <fstream>
+#include <iostream>
+#include <set>
+#include <vector>
+#include "compare-key.hpp"
+#ifdef WITH_TBB
+#include "tbb/tbb.h"
+#endif
+namespace qflow {
+
+inline int dedge_prev(int e, int deg) { return (e % deg == 0u) ? e + (deg - 1) : e - 1; }
+
+inline bool atomicCompareAndExchange(volatile int* v, uint32_t newValue, int oldValue) {
+#if defined(_WIN32)
+ return _InterlockedCompareExchange(reinterpret_cast<volatile long*>(v), (long)newValue,
+ (long)oldValue) == (long)oldValue;
+#else
+ return __sync_bool_compare_and_swap(v, oldValue, newValue);
+#endif
+}
+
+const int INVALID = -1;
+
+#undef max
+#undef min
+bool compute_direct_graph(MatrixXd& V, MatrixXi& F, VectorXi& V2E, VectorXi& E2E,
+ VectorXi& boundary, VectorXi& nonManifold) {
+ V2E.resize(V.cols());
+ V2E.setConstant(INVALID);
+
+ uint32_t deg = F.rows();
+ std::vector<std::pair<uint32_t, uint32_t>> tmp(F.size());
+
+#ifdef WITH_TBB
+ tbb::parallel_for(
+ tbb::blocked_range<uint32_t>(0u, (uint32_t)F.cols(), GRAIN_SIZE),
+ [&](const tbb::blocked_range<uint32_t>& range) {
+ for (uint32_t f = range.begin(); f != range.end(); ++f) {
+ for (uint32_t i = 0; i < deg; ++i) {
+ uint32_t idx_cur = F(i, f), idx_next = F((i + 1) % deg, f),
+ edge_id = deg * f + i;
+ if (idx_cur >= V.cols() || idx_next >= V.cols())
+ throw std::runtime_error(
+ "Mesh data contains an out-of-bounds vertex reference!");
+ if (idx_cur == idx_next) continue;
+
+ tmp[edge_id] = std::make_pair(idx_next, INVALID);
+ if (!atomicCompareAndExchange(&V2E[idx_cur], edge_id, INVALID)) {
+ uint32_t idx = V2E[idx_cur];
+ while (!atomicCompareAndExchange((int*)&tmp[idx].second, edge_id, INVALID))
+ idx = tmp[idx].second;
+ }
+ }
+ }
+ });
+#else
+ for (int f = 0; f < F.cols(); ++f) {
+ for (unsigned int i = 0; i < deg; ++i) {
+ unsigned int idx_cur = F(i, f), idx_next = F((i + 1) % deg, f), edge_id = deg * f + i;
+ if (idx_cur >= V.cols() || idx_next >= V.cols())
+ throw std::runtime_error("Mesh data contains an out-of-bounds vertex reference!");
+ if (idx_cur == idx_next) continue;
+
+ tmp[edge_id] = std::make_pair(idx_next, -1);
+ if (V2E[idx_cur] == -1)
+ V2E[idx_cur] = edge_id;
+ else {
+ unsigned int idx = V2E[idx_cur];
+ while (tmp[idx].second != -1) {
+ idx = tmp[idx].second;
+ }
+ tmp[idx].second = edge_id;
+ }
+ }
+ }
+#endif
+
+ nonManifold.resize(V.cols());
+ nonManifold.setConstant(false);
+
+ E2E.resize(F.cols() * deg);
+ E2E.setConstant(INVALID);
+
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int f = 0; f < F.cols(); ++f) {
+ for (uint32_t i = 0; i < deg; ++i) {
+ uint32_t idx_cur = F(i, f), idx_next = F((i + 1) % deg, f), edge_id_cur = deg * f + i;
+
+ if (idx_cur == idx_next) continue;
+
+ uint32_t it = V2E[idx_next], edge_id_opp = INVALID;
+ while (it != INVALID) {
+ if (tmp[it].first == idx_cur) {
+ if (edge_id_opp == INVALID) {
+ edge_id_opp = it;
+ } else {
+ nonManifold[idx_cur] = true;
+ nonManifold[idx_next] = true;
+ edge_id_opp = INVALID;
+ break;
+ }
+ }
+ it = tmp[it].second;
+ }
+
+ if (edge_id_opp != INVALID && edge_id_cur < edge_id_opp) {
+ E2E[edge_id_cur] = edge_id_opp;
+ E2E[edge_id_opp] = edge_id_cur;
+ }
+ }
+ }
+ std::atomic<uint32_t> nonManifoldCounter(0), boundaryCounter(0), isolatedCounter(0);
+
+ boundary.resize(V.cols());
+ boundary.setConstant(false);
+
+ /* Detect boundary regions of the mesh and adjust vertex->edge pointers*/
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int i = 0; i < V.cols(); ++i) {
+ uint32_t edge = V2E[i];
+ if (edge == INVALID) {
+ isolatedCounter++;
+ continue;
+ }
+ if (nonManifold[i]) {
+ nonManifoldCounter++;
+ V2E[i] = INVALID;
+ continue;
+ }
+
+ /* Walk backwards to the first boundary edge (if any) */
+ uint32_t start = edge, v2e = INVALID;
+ do {
+ v2e = std::min(v2e, edge);
+ uint32_t prevEdge = E2E[dedge_prev(edge, deg)];
+ if (prevEdge == INVALID) {
+ /* Reached boundary -- update the vertex->edge link */
+ v2e = edge;
+ boundary[i] = true;
+ boundaryCounter++;
+ break;
+ }
+ edge = prevEdge;
+ } while (edge != start);
+ V2E[i] = v2e;
+ }
+#ifdef LOG_OUTPUT
+ printf("counter triangle %d %d\n", (int)boundaryCounter, (int)nonManifoldCounter);
+#endif
+ return true;
+ std::vector<std::vector<int>> vert_to_edges(V2E.size());
+ for (int i = 0; i < F.cols(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ int v = F(j, i);
+ vert_to_edges[v].push_back(i * 3 + j);
+ }
+ }
+ std::vector<int> colors(F.cols() * 3, -1);
+ bool update = false;
+ int num_v = V.cols();
+ std::map<int, int> new_vertices;
+ for (int i = 0; i < vert_to_edges.size(); ++i) {
+ int num_color = 0;
+ for (int j = 0; j < vert_to_edges[i].size(); ++j) {
+ int deid0 = vert_to_edges[i][j];
+ if (colors[deid0] == -1) {
+ int deid = deid0;
+ do {
+ colors[deid] = num_color;
+ if (num_color != 0) F(deid % 3, deid / 3) = num_v;
+ deid = deid / 3 * 3 + (deid + 2) % 3;
+ deid = E2E[deid];
+ } while (deid != deid0);
+ num_color += 1;
+ if (num_color > 1) {
+ update = true;
+ new_vertices[num_v] = i;
+ num_v += 1;
+ }
+ }
+ }
+ }
+ if (update) {
+ V.conservativeResize(3, num_v);
+ for (auto& p : new_vertices) {
+ V.col(p.first) = V.col(p.second);
+ }
+ return false;
+ }
+ return true;
+}
+
+void compute_direct_graph_quad(std::vector<Vector3d>& V, std::vector<Vector4i>& F, std::vector<int>& V2E, std::vector<int>& E2E, VectorXi& boundary, VectorXi& nonManifold) {
+ V2E.clear();
+ E2E.clear();
+ boundary = VectorXi();
+ nonManifold = VectorXi();
+ V2E.resize(V.size(), INVALID);
+
+ uint32_t deg = 4;
+ std::vector<std::pair<uint32_t, uint32_t>> tmp(F.size() * deg);
+
+#ifdef WITH_TBB
+ tbb::parallel_for(
+ tbb::blocked_range<uint32_t>(0u, (uint32_t)F.size(), GRAIN_SIZE),
+ [&](const tbb::blocked_range<uint32_t>& range) {
+ for (uint32_t f = range.begin(); f != range.end(); ++f) {
+ for (uint32_t i = 0; i < deg; ++i) {
+ uint32_t idx_cur = F[f][i], idx_next = F[f][(i + 1) % deg],
+ edge_id = deg * f + i;
+ if (idx_cur >= V.size() || idx_next >= V.size())
+ throw std::runtime_error(
+ "Mesh data contains an out-of-bounds vertex reference!");
+ if (idx_cur == idx_next) continue;
+
+ tmp[edge_id] = std::make_pair(idx_next, INVALID);
+ if (!atomicCompareAndExchange(&V2E[idx_cur], edge_id, INVALID)) {
+ uint32_t idx = V2E[idx_cur];
+ while (!atomicCompareAndExchange((int*)&tmp[idx].second, edge_id, INVALID))
+ idx = tmp[idx].second;
+ }
+ }
+ }
+ });
+#else
+ for (int f = 0; f < F.size(); ++f) {
+ for (unsigned int i = 0; i < deg; ++i) {
+ unsigned int idx_cur = F[f][i], idx_next = F[f][(i + 1) % deg], edge_id = deg * f + i;
+ if (idx_cur >= V.size() || idx_next >= V.size())
+ throw std::runtime_error("Mesh data contains an out-of-bounds vertex reference!");
+ if (idx_cur == idx_next) continue;
+ tmp[edge_id] = std::make_pair(idx_next, -1);
+ if (V2E[idx_cur] == -1) {
+ V2E[idx_cur] = edge_id;
+ }
+ else {
+ unsigned int idx = V2E[idx_cur];
+ while (tmp[idx].second != -1) {
+ idx = tmp[idx].second;
+ }
+ tmp[idx].second = edge_id;
+ }
+ }
+ }
+#endif
+ nonManifold.resize(V.size());
+ nonManifold.setConstant(false);
+
+ E2E.resize(F.size() * deg, INVALID);
+
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int f = 0; f < F.size(); ++f) {
+ for (uint32_t i = 0; i < deg; ++i) {
+ uint32_t idx_cur = F[f][i], idx_next = F[f][(i + 1) % deg], edge_id_cur = deg * f + i;
+
+ if (idx_cur == idx_next) continue;
+
+ uint32_t it = V2E[idx_next], edge_id_opp = INVALID;
+ while (it != INVALID) {
+ if (tmp[it].first == idx_cur) {
+ if (edge_id_opp == INVALID) {
+ edge_id_opp = it;
+ } else {
+ nonManifold[idx_cur] = true;
+ nonManifold[idx_next] = true;
+ edge_id_opp = INVALID;
+ break;
+ }
+ }
+ it = tmp[it].second;
+ }
+
+ if (edge_id_opp != INVALID && edge_id_cur < edge_id_opp) {
+ E2E[edge_id_cur] = edge_id_opp;
+ E2E[edge_id_opp] = edge_id_cur;
+ }
+ }
+ }
+ std::atomic<uint32_t> nonManifoldCounter(0), boundaryCounter(0), isolatedCounter(0);
+
+ boundary.resize(V.size());
+ boundary.setConstant(false);
+
+ /* Detect boundary regions of the mesh and adjust vertex->edge pointers*/
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int i = 0; i < V.size(); ++i) {
+ uint32_t edge = V2E[i];
+ if (edge == INVALID) {
+ isolatedCounter++;
+ continue;
+ }
+ if (nonManifold[i]) {
+ nonManifoldCounter++;
+ V2E[i] = INVALID;
+ continue;
+ }
+
+ /* Walk backwards to the first boundary edge (if any) */
+ uint32_t start = edge, v2e = INVALID;
+ do {
+ v2e = std::min(v2e, edge);
+ uint32_t prevEdge = E2E[dedge_prev(edge, deg)];
+ if (prevEdge == INVALID) {
+ /* Reached boundary -- update the vertex->edge link */
+ v2e = edge;
+ boundary[i] = true;
+ boundaryCounter++;
+ break;
+ }
+ edge = prevEdge;
+ } while (edge != start);
+ V2E[i] = v2e;
+ }
+#ifdef LOG_OUTPUT
+ printf("counter %d %d\n", (int)boundaryCounter, (int)nonManifoldCounter);
+#endif
+}
+
+void remove_nonmanifold(std::vector<Vector4i>& F, std::vector<Vector3d>& V) {
+ typedef std::pair<uint32_t, uint32_t> Edge;
+
+ int degree = 4;
+ std::map<uint32_t, std::map<uint32_t, std::pair<uint32_t, uint32_t>>> irregular;
+ std::vector<std::set<int>> E(V.size());
+ std::vector<std::set<int>> VF(V.size());
+
+ auto kill_face_single = [&](uint32_t f) {
+ if (F[f][0] == INVALID) return;
+ for (int i = 0; i < degree; ++i) E[F[f][i]].erase(F[f][(i + 1) % degree]);
+ F[f].setConstant(INVALID);
+ };
+
+ auto kill_face = [&](uint32_t f) {
+ if (degree == 4 && F[f][2] == F[f][3]) {
+ auto it = irregular.find(F[f][2]);
+ if (it != irregular.end()) {
+ for (auto& item : it->second) {
+ kill_face_single(item.second.second);
+ }
+ }
+ }
+ kill_face_single(f);
+ };
+
+ uint32_t nm_edge = 0, nm_vert = 0;
+
+ for (uint32_t f = 0; f < (uint32_t)F.size(); ++f) {
+ if (F[f][0] == INVALID) continue;
+ if (degree == 4 && F[f][2] == F[f][3]) {
+ /* Special handling of irregular faces */
+ irregular[F[f][2]][F[f][0]] = std::make_pair(F[f][1], f);
+ continue;
+ }
+
+ bool nonmanifold = false;
+ for (uint32_t e = 0; e < degree; ++e) {
+ uint32_t v0 = F[f][e], v1 = F[f][(e + 1) % degree], v2 = F[f][(e + 2) % degree];
+ if (E[v0].find(v1) != E[v0].end() || (degree == 4 && E[v0].find(v2) != E[v0].end()))
+ nonmanifold = true;
+ }
+
+ if (nonmanifold) {
+ nm_edge++;
+ F[f].setConstant(INVALID);
+ continue;
+ }
+
+ for (uint32_t e = 0; e < degree; ++e) {
+ uint32_t v0 = F[f][e], v1 = F[f][(e + 1) % degree], v2 = F[f][(e + 2) % degree];
+
+ E[v0].insert(v1);
+ if (degree == 4) E[v0].insert(v2);
+ VF[v0].insert(f);
+ }
+ }
+
+ std::vector<Edge> edges;
+ for (auto item : irregular) {
+ bool nonmanifold = false;
+ auto face = item.second;
+ edges.clear();
+
+ uint32_t cur = face.begin()->first, stop = cur;
+ while (true) {
+ uint32_t pred = cur;
+ cur = face[cur].first;
+ uint32_t next = face[cur].first, it = 0;
+ while (true) {
+ ++it;
+ if (next == pred) break;
+ if (E[cur].find(next) != E[cur].end() && it == 1) nonmanifold = true;
+ edges.push_back(Edge(cur, next));
+ next = face[next].first;
+ }
+ if (cur == stop) break;
+ }
+
+ if (nonmanifold) {
+ nm_edge++;
+ for (auto& i : item.second) F[i.second.second].setConstant(INVALID);
+ continue;
+ } else {
+ for (auto e : edges) {
+ E[e.first].insert(e.second);
+
+ for (auto e2 : face) VF[e.first].insert(e2.second.second);
+ }
+ }
+ }
+
+ /* Check vertices */
+ std::set<uint32_t> v_marked, v_unmarked, f_adjacent;
+
+ std::function<void(uint32_t)> dfs = [&](uint32_t i) {
+ v_marked.insert(i);
+ v_unmarked.erase(i);
+
+ for (uint32_t f : VF[i]) {
+ if (f_adjacent.find(f) == f_adjacent.end()) /* if not part of adjacent face */
+ continue;
+ for (uint32_t j = 0; j < degree; ++j) {
+ uint32_t k = F[f][j];
+ if (v_unmarked.find(k) == v_unmarked.end() || /* if not unmarked OR */
+ v_marked.find(k) != v_marked.end()) /* if already marked */
+ continue;
+ dfs(k);
+ }
+ }
+ };
+
+ for (uint32_t i = 0; i < (uint32_t)V.size(); ++i) {
+ v_marked.clear();
+ v_unmarked.clear();
+ f_adjacent.clear();
+
+ for (uint32_t f : VF[i]) {
+ if (F[f][0] == INVALID) continue;
+
+ for (uint32_t k = 0; k < degree; ++k) v_unmarked.insert(F[f][k]);
+
+ f_adjacent.insert(f);
+ }
+
+ if (v_unmarked.empty()) continue;
+ v_marked.insert(i);
+ v_unmarked.erase(i);
+
+ dfs(*v_unmarked.begin());
+
+ if (v_unmarked.size() > 0) {
+ nm_vert++;
+ for (uint32_t f : f_adjacent) kill_face(f);
+ }
+ }
+
+ if (nm_vert > 0 || nm_edge > 0) {
+ std::cout << "Non-manifold elements: vertices=" << nm_vert << ", edges=" << nm_edge
+ << std::endl;
+ }
+ uint32_t nFaces = 0, nFacesOrig = F.size();
+ for (uint32_t f = 0; f < (uint32_t)F.size(); ++f) {
+ if (F[f][0] == INVALID) continue;
+ if (nFaces != f) {
+ F[nFaces] = F[f];
+ }
+ ++nFaces;
+ }
+
+ if (nFacesOrig != nFaces) {
+ F.resize(nFaces);
+ std::cout << "Faces reduced from " << nFacesOrig << " -> " << nFaces << std::endl;
+ }
+}
+
+} // namespace qflow
diff --git a/extern/quadriflow/src/dedge.hpp b/extern/quadriflow/src/dedge.hpp
new file mode 100644
index 00000000000..e8ee372f012
--- /dev/null
+++ b/extern/quadriflow/src/dedge.hpp
@@ -0,0 +1,25 @@
+#ifndef DEDGE_H_
+#define DEDGE_H_
+
+#include <Eigen/Core>
+#include <Eigen/Dense>
+#include <vector>
+
+namespace qflow {
+
+using namespace Eigen;
+
+inline int dedge_prev_3(int e) { return (e % 3 == 0) ? e + 2 : e - 1; }
+inline int dedge_next_3(int e) { return (e % 3 == 2) ? e - 2 : e + 1; }
+
+bool compute_direct_graph(MatrixXd& V, MatrixXi& F, VectorXi& V2E,
+ VectorXi& E2E, VectorXi& boundary, VectorXi& nonManifold);
+
+void compute_direct_graph_quad(std::vector<Vector3d>& V, std::vector<Vector4i>& F, std::vector<int>& V2E,
+ std::vector<int>& E2E, VectorXi& boundary, VectorXi& nonManifold);
+
+void remove_nonmanifold(std::vector<Vector4i> &F, std::vector<Vector3d> &V);
+
+} // namespace qflow
+
+#endif
diff --git a/extern/quadriflow/src/disajoint-tree.hpp b/extern/quadriflow/src/disajoint-tree.hpp
new file mode 100644
index 00000000000..1822b83a208
--- /dev/null
+++ b/extern/quadriflow/src/disajoint-tree.hpp
@@ -0,0 +1,151 @@
+#ifndef DISAJOINT_TREE_H_
+#define DISAJOINT_TREE_H_
+
+#include <vector>
+
+namespace qflow {
+
+class DisajointTree {
+ public:
+ DisajointTree() {}
+ DisajointTree(int n) {
+ parent.resize(n);
+ rank.resize(n, 1);
+ for (int i = 0; i < n; ++i) parent[i] = i;
+ }
+ int Parent(int x) {
+ if (x == parent[x]) return x;
+ int y = Parent(parent[x]);
+ parent[x] = y;
+ return y;
+ }
+ int Index(int x) { return indices[x]; }
+ int IndexToParent(int x) {return indices_to_parent[x]; };
+ void MergeFromTo(int x, int y) {
+ int px = Parent(x);
+ int py = Parent(y);
+ if (px == py) return;
+ rank[py] += rank[px];
+ parent[px] = py;
+ }
+ void Merge(int x, int y) {
+ int px = Parent(x);
+ int py = Parent(y);
+ if (px == py) return;
+ if (rank[px] < rank[py]) {
+ rank[py] += rank[px];
+ parent[px] = py;
+ } else {
+ rank[px] += rank[py];
+ parent[py] = px;
+ }
+ }
+
+ // renumber the root so that it is consecutive.
+ void BuildCompactParent() {
+ std::vector<int> compact_parent;
+ compact_parent.resize(parent.size());
+ compact_num = 0;
+ for (int i = 0; i < parent.size(); ++i) {
+ if (parent[i] == i) {
+ compact_parent[i] = compact_num++;
+ indices_to_parent.push_back(i);
+ }
+ }
+ indices.resize(parent.size());
+ for (int i = 0; i < parent.size(); ++i) {
+ indices[i] = compact_parent[Parent(i)];
+ }
+ }
+
+ int CompactNum() { return compact_num; }
+
+ int compact_num;
+ std::vector<int> parent;
+ std::vector<int> indices, indices_to_parent;
+ std::vector<int> rank;
+};
+
+class DisajointOrientTree {
+ public:
+ DisajointOrientTree() {}
+ DisajointOrientTree(int n) {
+ parent.resize(n);
+ rank.resize(n, 1);
+ for (int i = 0; i < n; ++i) parent[i] = std::make_pair(i, 0);
+ }
+ int Parent(int j) {
+ if (j == parent[j].first) return j;
+ int k = Parent(parent[j].first);
+ parent[j].second = (parent[j].second + parent[parent[j].first].second) % 4;
+ parent[j].first = k;
+ return k;
+ }
+ int Orient(int j) {
+ if (j == parent[j].first) return parent[j].second;
+ return (parent[j].second + Orient(parent[j].first)) % 4;
+ }
+ int Index(int x) { return indices[x]; }
+ void MergeFromTo(int v0, int v1, int orient0, int orient1) {
+ int p0 = Parent(v0);
+ int p1 = Parent(v1);
+ if (p0 == p1) return;
+ int orientp0 = Orient(v0);
+ int orientp1 = Orient(v1);
+
+ if (p0 == p1) {
+ return;
+ }
+ rank[p1] += rank[p0];
+ parent[p0].first = p1;
+ parent[p0].second = (orient0 - orient1 + orientp1 - orientp0 + 8) % 4;
+ }
+
+ void Merge(int v0, int v1, int orient0, int orient1) {
+ int p0 = Parent(v0);
+ int p1 = Parent(v1);
+ if (p0 == p1) {
+ return;
+ }
+ int orientp0 = Orient(v0);
+ int orientp1 = Orient(v1);
+
+ if (p0 == p1) {
+ return;
+ }
+ if (rank[p1] < rank[p0]) {
+ rank[p0] += rank[p1];
+ parent[p1].first = p0;
+ parent[p1].second = (orient1 - orient0 + orientp0 - orientp1 + 8) % 4;
+ } else {
+ rank[p1] += rank[p0];
+ parent[p0].first = p1;
+ parent[p0].second = (orient0 - orient1 + orientp1 - orientp0 + 8) % 4;
+ }
+ }
+ void BuildCompactParent() {
+ std::vector<int> compact_parent;
+ compact_parent.resize(parent.size());
+ compact_num = 0;
+ for (int i = 0; i < parent.size(); ++i) {
+ if (parent[i].first == i) {
+ compact_parent[i] = compact_num++;
+ }
+ }
+ indices.resize(parent.size());
+ for (int i = 0; i < parent.size(); ++i) {
+ indices[i] = compact_parent[Parent(i)];
+ }
+ }
+
+ int CompactNum() { return compact_num; }
+
+ int compact_num;
+ std::vector<std::pair<int, int>> parent;
+ std::vector<int> indices;
+ std::vector<int> rank;
+};
+
+} // namespace qflow
+
+#endif
diff --git a/extern/quadriflow/src/dset.hpp b/extern/quadriflow/src/dset.hpp
new file mode 100644
index 00000000000..f8e6f6da6b6
--- /dev/null
+++ b/extern/quadriflow/src/dset.hpp
@@ -0,0 +1,163 @@
+#if !defined(__UNIONFIND_H)
+#define __UNIONFIND_H
+
+#include <vector>
+#include <atomic>
+#include <iostream>
+
+namespace qflow {
+
+/**
+* Lock-free parallel disjoint set data structure (aka UNION-FIND)
+* with path compression and union by rank
+*
+* Supports concurrent find(), same() and unite() calls as described
+* in the paper
+*
+* "Wait-free Parallel Algorithms for the Union-Find Problem"
+* by Richard J. Anderson and Heather Woll
+*
+* In addition, this class supports optimistic locking (try_lock/unlock)
+* of disjoint sets and a combined unite+unlock operation.
+*
+* \author Wenzel Jakob
+*/
+class DisjointSets {
+public:
+ DisjointSets(uint32_t size) : mData(size) {
+ for (uint32_t i = 0; i<size; ++i)
+ mData[i] = (uint32_t)i;
+ }
+
+ uint32_t find(uint32_t id) const {
+ while (id != parent(id)) {
+ uint64_t value = mData[id];
+ uint32_t new_parent = parent((uint32_t)value);
+ uint64_t new_value =
+ (value & 0xFFFFFFFF00000000ULL) | new_parent;
+ /* Try to update parent (may fail, that's ok) */
+ if (value != new_value)
+ mData[id].compare_exchange_weak(value, new_value);
+ id = new_parent;
+ }
+ return id;
+ }
+
+ bool same(uint32_t id1, uint32_t id2) const {
+ for (;;) {
+ id1 = find(id1);
+ id2 = find(id2);
+ if (id1 == id2)
+ return true;
+ if (parent(id1) == id1)
+ return false;
+ }
+ }
+
+ uint32_t unite(uint32_t id1, uint32_t id2) {
+ for (;;) {
+ id1 = find(id1);
+ id2 = find(id2);
+
+ if (id1 == id2)
+ return id1;
+
+ uint32_t r1 = rank(id1), r2 = rank(id2);
+
+ if (r1 > r2 || (r1 == r2 && id1 < id2)) {
+ std::swap(r1, r2);
+ std::swap(id1, id2);
+ }
+
+ uint64_t oldEntry = ((uint64_t)r1 << 32) | id1;
+ uint64_t newEntry = ((uint64_t)r1 << 32) | id2;
+
+ if (!mData[id1].compare_exchange_strong(oldEntry, newEntry))
+ continue;
+
+ if (r1 == r2) {
+ oldEntry = ((uint64_t)r2 << 32) | id2;
+ newEntry = ((uint64_t)(r2 + 1) << 32) | id2;
+ /* Try to update the rank (may fail, that's ok) */
+ mData[id2].compare_exchange_weak(oldEntry, newEntry);
+ }
+
+ break;
+ }
+ return id2;
+ }
+
+ /**
+ * Try to lock the a disjoint union identified by one
+ * of its elements (this can occasionally fail when there
+ * are concurrent operations). The parameter 'id' will be
+ * updated to store the current representative ID of the
+ * union
+ */
+ bool try_lock(uint32_t &id) {
+ const uint64_t lock_flag = 1ULL << 63;
+ id = find(id);
+ uint64_t value = mData[id];
+ if ((value & lock_flag) || (uint32_t)value != id)
+ return false;
+ // On IA32/x64, a PAUSE instruction is recommended for CAS busy loops
+#if defined(__i386__) || defined(__amd64__)
+ __asm__ __volatile__("pause\n");
+#endif
+ return mData[id].compare_exchange_strong(value, value | lock_flag);
+ }
+
+ void unlock(uint32_t id) {
+ const uint64_t lock_flag = 1ULL << 63;
+ mData[id] &= ~lock_flag;
+ }
+
+ /**
+ * Return the representative index of the set that results from merging
+ * locked disjoint sets 'id1' and 'id2'
+ */
+ uint32_t unite_index_locked(uint32_t id1, uint32_t id2) const {
+ uint32_t r1 = rank(id1), r2 = rank(id2);
+ return (r1 > r2 || (r1 == r2 && id1 < id2)) ? id1 : id2;
+ }
+
+ /**
+ * Atomically unite two locked disjoint sets and unlock them. Assumes
+ * that here are no other concurrent unite() involving the same sets
+ */
+ uint32_t unite_unlock(uint32_t id1, uint32_t id2) {
+ uint32_t r1 = rank(id1), r2 = rank(id2);
+
+ if (r1 > r2 || (r1 == r2 && id1 < id2)) {
+ std::swap(r1, r2);
+ std::swap(id1, id2);
+ }
+
+ mData[id1] = ((uint64_t)r1 << 32) | id2;
+ mData[id2] = ((uint64_t)(r2 + ((r1 == r2) ? 1 : 0)) << 32) | id2;
+
+ return id2;
+ }
+
+ uint32_t size() const { return (uint32_t)mData.size(); }
+
+ uint32_t rank(uint32_t id) const {
+ return ((uint32_t)(mData[id] >> 32)) & 0x7FFFFFFFu;
+ }
+
+ uint32_t parent(uint32_t id) const {
+ return (uint32_t)mData[id];
+ }
+
+ friend std::ostream &operator<<(std::ostream &os, const DisjointSets &f) {
+ for (size_t i = 0; i<f.mData.size(); ++i)
+ os << i << ": parent=" << f.parent(i) << ", rank=" << f.rank(i) << std::endl;
+ return os;
+ }
+
+ mutable std::vector<std::atomic<uint64_t>> mData;
+};
+
+} // namespace qflow
+
+#endif /* __UNIONFIND_H */
diff --git a/extern/quadriflow/src/field-math.hpp b/extern/quadriflow/src/field-math.hpp
new file mode 100644
index 00000000000..86ed4b2b1f4
--- /dev/null
+++ b/extern/quadriflow/src/field-math.hpp
@@ -0,0 +1,483 @@
+#ifndef FIELD_MATH_H_
+#define FIELD_MATH_H_
+
+#ifdef WITH_CUDA
+# include <glm/glm.hpp>
+#endif
+#include <Eigen/Core>
+#include <Eigen/Dense>
+#include <algorithm>
+#include <vector>
+
+namespace qflow {
+
+using namespace Eigen;
+
+struct DEdge
+{
+ DEdge()
+ : x(0), y(0)
+ {}
+ DEdge(int _x, int _y) {
+ if (_x > _y)
+ x = _y, y = _x;
+ else
+ x = _x, y = _y;
+ }
+ bool operator<(const DEdge& e) const {
+ return (x < e.x) || (x == e.x && y < e.y);
+ }
+ bool operator==(const DEdge& e) const {
+ return x == e.x && y == e.y;
+ }
+ bool operator!=(const DEdge& e) const {
+ return x != e.x || y != e.y;
+ }
+ int x, y;
+};
+
+inline int get_parents(std::vector<std::pair<int, int>>& parents, int j) {
+ if (j == parents[j].first) return j;
+ int k = get_parents(parents, parents[j].first);
+ parents[j].second = (parents[j].second + parents[parents[j].first].second) % 4;
+ parents[j].first = k;
+ return k;
+}
+
+inline int get_parents_orient(std::vector<std::pair<int, int>>& parents, int j) {
+ if (j == parents[j].first) return parents[j].second;
+ return (parents[j].second + get_parents_orient(parents, parents[j].first)) % 4;
+}
+
+inline double fast_acos(double x) {
+ double negate = double(x < 0.0f);
+ x = std::abs(x);
+ double ret = -0.0187293f;
+ ret *= x;
+ ret = ret + 0.0742610f;
+ ret *= x;
+ ret = ret - 0.2121144f;
+ ret *= x;
+ ret = ret + 1.5707288f;
+ ret = ret * std::sqrt(1.0f - x);
+ ret = ret - 2.0f * negate * ret;
+ return negate * (double)M_PI + ret;
+}
+
+inline double signum(double value) { return std::copysign((double)1, value); }
+
+/// Always-positive modulo function (assumes b > 0)
+inline int modulo(int a, int b) {
+ int r = a % b;
+ return (r < 0) ? r + b : r;
+}
+
+inline Vector3d rotate90_by(const Vector3d &q, const Vector3d &n, int amount) {
+ return ((amount & 1) ? (n.cross(q)) : q) * (amount < 2 ? 1.0f : -1.0f);
+}
+
+inline Vector2i rshift90(Vector2i shift, int amount) {
+ if (amount & 1) shift = Vector2i(-shift.y(), shift.x());
+ if (amount >= 2) shift = -shift;
+ return shift;
+}
+
+inline std::pair<int, int> compat_orientation_extrinsic_index_4(const Vector3d &q0,
+ const Vector3d &n0,
+ const Vector3d &q1,
+ const Vector3d &n1) {
+ const Vector3d A[2] = {q0, n0.cross(q0)};
+ const Vector3d B[2] = {q1, n1.cross(q1)};
+
+ double best_score = -std::numeric_limits<double>::infinity();
+ int best_a = 0, best_b = 0;
+
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j < 2; ++j) {
+ double score = std::abs(A[i].dot(B[j]));
+ if (score > best_score) {
+ best_a = i;
+ best_b = j;
+ best_score = score;
+ }
+ }
+ }
+
+ if (A[best_a].dot(B[best_b]) < 0) best_b += 2;
+
+ return std::make_pair(best_a, best_b);
+}
+
+inline std::pair<Vector3d, Vector3d> compat_orientation_extrinsic_4(const Vector3d &q0,
+ const Vector3d &n0,
+ const Vector3d &q1,
+ const Vector3d &n1) {
+ const Vector3d A[2] = {q0, n0.cross(q0)};
+ const Vector3d B[2] = {q1, n1.cross(q1)};
+
+ double best_score = -std::numeric_limits<double>::infinity();
+ int best_a = 0, best_b = 0;
+
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j < 2; ++j) {
+ double score = std::abs(A[i].dot(B[j]));
+ if (score > best_score + 1e-6) {
+ best_a = i;
+ best_b = j;
+ best_score = score;
+ }
+ }
+ }
+
+ const double dp = A[best_a].dot(B[best_b]);
+ return std::make_pair(A[best_a], B[best_b] * signum(dp));
+}
+
+inline Vector3d middle_point(const Vector3d &p0, const Vector3d &n0, const Vector3d &p1,
+ const Vector3d &n1) {
+ /* How was this derived?
+ *
+ * Minimize \|x-p0\|^2 + \|x-p1\|^2, where
+ * dot(n0, x) == dot(n0, p0)
+ * dot(n1, x) == dot(n1, p1)
+ *
+ * -> Lagrange multipliers, set derivative = 0
+ * Use first 3 equalities to write x in terms of
+ * lambda_1 and lambda_2. Substitute that into the last
+ * two equations and solve for the lambdas. Finally,
+ * add a small epsilon term to avoid issues when n1=n2.
+ */
+ double n0p0 = n0.dot(p0), n0p1 = n0.dot(p1), n1p0 = n1.dot(p0), n1p1 = n1.dot(p1),
+ n0n1 = n0.dot(n1), denom = 1.0f / (1.0f - n0n1 * n0n1 + 1e-4f),
+ lambda_0 = 2.0f * (n0p1 - n0p0 - n0n1 * (n1p0 - n1p1)) * denom,
+ lambda_1 = 2.0f * (n1p0 - n1p1 - n0n1 * (n0p1 - n0p0)) * denom;
+
+ return 0.5f * (p0 + p1) - 0.25f * (n0 * lambda_0 + n1 * lambda_1);
+}
+
+inline Vector3d position_floor_4(const Vector3d &o, const Vector3d &q, const Vector3d &n,
+ const Vector3d &p, double scale_x, double scale_y,
+ double inv_scale_x, double inv_scale_y) {
+ Vector3d t = n.cross(q);
+ Vector3d d = p - o;
+ return o + q * std::floor(q.dot(d) * inv_scale_x) * scale_x +
+ t * std::floor(t.dot(d) * inv_scale_y) * scale_y;
+}
+
+inline std::pair<Vector3d, Vector3d> compat_position_extrinsic_4(
+ const Vector3d &p0, const Vector3d &n0, const Vector3d &q0, const Vector3d &o0,
+ const Vector3d &p1, const Vector3d &n1, const Vector3d &q1, const Vector3d &o1, double scale_x,
+ double scale_y, double inv_scale_x, double inv_scale_y, double scale_x_1, double scale_y_1,
+ double inv_scale_x_1, double inv_scale_y_1) {
+ Vector3d t0 = n0.cross(q0), t1 = n1.cross(q1);
+ Vector3d middle = middle_point(p0, n0, p1, n1);
+ Vector3d o0p =
+ position_floor_4(o0, q0, n0, middle, scale_x, scale_y, inv_scale_x, inv_scale_y);
+ Vector3d o1p =
+ position_floor_4(o1, q1, n1, middle, scale_x_1, scale_y_1, inv_scale_x_1, inv_scale_y_1);
+
+ double best_cost = std::numeric_limits<double>::infinity();
+ int best_i = -1, best_j = -1;
+
+ for (int i = 0; i < 4; ++i) {
+ Vector3d o0t = o0p + (q0 * (i & 1) * scale_x + t0 * ((i & 2) >> 1) * scale_y);
+ for (int j = 0; j < 4; ++j) {
+ Vector3d o1t = o1p + (q1 * (j & 1) * scale_x_1 + t1 * ((j & 2) >> 1) * scale_y_1);
+ double cost = (o0t - o1t).squaredNorm();
+
+ if (cost < best_cost) {
+ best_i = i;
+ best_j = j;
+ best_cost = cost;
+ }
+ }
+ }
+
+ return std::make_pair(
+ o0p + (q0 * (best_i & 1) * scale_x + t0 * ((best_i & 2) >> 1) * scale_y),
+ o1p + (q1 * (best_j & 1) * scale_x_1 + t1 * ((best_j & 2) >> 1) * scale_y_1));
+}
+
+inline Vector3d position_round_4(const Vector3d &o, const Vector3d &q, const Vector3d &n,
+ const Vector3d &p, double scale_x, double scale_y,
+ double inv_scale_x, double inv_scale_y) {
+ Vector3d t = n.cross(q);
+ Vector3d d = p - o;
+ return o + q * std::round(q.dot(d) * inv_scale_x) * scale_x +
+ t * std::round(t.dot(d) * inv_scale_y) * scale_y;
+}
+
+inline Vector2i position_floor_index_4(const Vector3d &o, const Vector3d &q, const Vector3d &n,
+ const Vector3d &p, double /* unused */, double /* unused */,
+ double inv_scale_x, double inv_scale_y) {
+ Vector3d t = n.cross(q);
+ Vector3d d = p - o;
+ return Vector2i((int)std::floor(q.dot(d) * inv_scale_x),
+ (int)std::floor(t.dot(d) * inv_scale_y));
+}
+
+inline std::pair<Vector2i, Vector2i> compat_position_extrinsic_index_4(
+ const Vector3d &p0, const Vector3d &n0, const Vector3d &q0, const Vector3d &o0,
+ const Vector3d &p1, const Vector3d &n1, const Vector3d &q1, const Vector3d &o1, double scale_x,
+ double scale_y, double inv_scale_x, double inv_scale_y, double scale_x_1, double scale_y_1,
+ double inv_scale_x_1, double inv_scale_y_1, double *error) {
+ Vector3d t0 = n0.cross(q0), t1 = n1.cross(q1);
+ Vector3d middle = middle_point(p0, n0, p1, n1);
+ Vector2i o0p =
+ position_floor_index_4(o0, q0, n0, middle, scale_x, scale_y, inv_scale_x, inv_scale_y);
+ Vector2i o1p = position_floor_index_4(o1, q1, n1, middle, scale_x_1, scale_y_1, inv_scale_x_1,
+ inv_scale_y_1);
+
+ double best_cost = std::numeric_limits<double>::infinity();
+ int best_i = -1, best_j = -1;
+
+ for (int i = 0; i < 4; ++i) {
+ Vector3d o0t =
+ o0 + (q0 * ((i & 1) + o0p[0]) * scale_x + t0 * (((i & 2) >> 1) + o0p[1]) * scale_y);
+ for (int j = 0; j < 4; ++j) {
+ Vector3d o1t = o1 + (q1 * ((j & 1) + o1p[0]) * scale_x_1 +
+ t1 * (((j & 2) >> 1) + o1p[1]) * scale_y_1);
+ double cost = (o0t - o1t).squaredNorm();
+
+ if (cost < best_cost) {
+ best_i = i;
+ best_j = j;
+ best_cost = cost;
+ }
+ }
+ }
+ if (error) *error = best_cost;
+
+ return std::make_pair(Vector2i((best_i & 1) + o0p[0], ((best_i & 2) >> 1) + o0p[1]),
+ Vector2i((best_j & 1) + o1p[0], ((best_j & 2) >> 1) + o1p[1]));
+}
+
+inline void coordinate_system(const Vector3d &a, Vector3d &b, Vector3d &c) {
+ if (std::abs(a.x()) > std::abs(a.y())) {
+ double invLen = 1.0f / std::sqrt(a.x() * a.x() + a.z() * a.z());
+ c = Vector3d(a.z() * invLen, 0.0f, -a.x() * invLen);
+ } else {
+ double invLen = 1.0f / std::sqrt(a.y() * a.y() + a.z() * a.z());
+ c = Vector3d(0.0f, a.z() * invLen, -a.y() * invLen);
+ }
+ b = c.cross(a);
+}
+
+inline Vector3d rotate_vector_into_plane(Vector3d q, const Vector3d &source_normal,
+ const Vector3d &target_normal) {
+ const double cosTheta = source_normal.dot(target_normal);
+ if (cosTheta < 0.9999f) {
+ if (cosTheta < -0.9999f) return -q;
+ Vector3d axis = source_normal.cross(target_normal);
+ q = q * cosTheta + axis.cross(q) +
+ axis * (axis.dot(q) * (1.0 - cosTheta) / axis.dot(axis));
+ }
+ return q;
+}
+
+inline Vector3d Travel(Vector3d p, const Vector3d &dir, double &len, int &f, VectorXi &E2E,
+ MatrixXd &V, MatrixXi &F, MatrixXd &NF,
+ std::vector<MatrixXd> &triangle_space, double *tx = 0, double *ty = 0) {
+ Vector3d N = NF.col(f);
+ Vector3d pt = (dir - dir.dot(N) * N).normalized();
+ int prev_id = -1;
+ int count = 0;
+ while (len > 0) {
+ count += 1;
+ Vector3d t1 = V.col(F(1, f)) - V.col(F(0, f));
+ Vector3d t2 = V.col(F(2, f)) - V.col(F(0, f));
+ Vector3d N = NF.col(f);
+ // printf("point dis: %f\n", (p - V.col(F(1, f))).dot(N));
+ int edge_id = f * 3;
+ double max_len = 1e30;
+ bool found = false;
+ int next_id, next_f;
+ Vector3d next_q;
+ Matrix3d m, n;
+ m.col(0) = t1;
+ m.col(1) = t2;
+ m.col(2) = N;
+ n = m.inverse();
+ MatrixXd &T = triangle_space[f];
+ VectorXd coord = T * Vector3d(p - V.col(F(0, f)));
+ VectorXd dirs = (T * pt);
+
+ double lens[3];
+ lens[0] = -coord.y() / dirs.y();
+ lens[1] = (1 - coord.x() - coord.y()) / (dirs.x() + dirs.y());
+ lens[2] = -coord.x() / dirs.x();
+ for (int fid = 0; fid < 3; ++fid) {
+ if (fid + edge_id == prev_id) continue;
+
+ if (lens[fid] >= 0 && lens[fid] < max_len) {
+ max_len = lens[fid];
+ next_id = E2E[edge_id + fid];
+ next_f = next_id;
+ if (next_f != -1) next_f /= 3;
+ found = true;
+ }
+ }
+ if (!found) {
+ printf("error...\n");
+ exit(0);
+ }
+ // printf("status: %f %f %d\n", len, max_len, f);
+ if (max_len >= len) {
+ if (tx && ty) {
+ *tx = coord.x() + dirs.x() * len;
+ *ty = coord.y() + dirs.y() * len;
+ }
+ p = p + len * pt;
+ len = 0;
+ return p;
+ }
+ p = V.col(F(0, f)) + t1 * (coord.x() + dirs.x() * max_len) +
+ t2 * (coord.y() + dirs.y() * max_len);
+ len -= max_len;
+ if (next_f == -1) {
+ if (tx && ty) {
+ *tx = coord.x() + dirs.x() * max_len;
+ *ty = coord.y() + dirs.y() * max_len;
+ }
+ return p;
+ }
+ pt = rotate_vector_into_plane(pt, NF.col(f), NF.col(next_f));
+ f = next_f;
+ prev_id = next_id;
+ }
+ return p;
+}
+inline Vector3d TravelField(Vector3d p, Vector3d &pt, double &len, int &f, VectorXi &E2E,
+ MatrixXd &V, MatrixXi &F, MatrixXd &NF, MatrixXd &QF, MatrixXd &QV,
+ MatrixXd &NV, std::vector<MatrixXd> &triangle_space, double *tx = 0,
+ double *ty = 0, Vector3d *dir_unfold = 0) {
+ Vector3d N = NF.col(f);
+ pt = (pt - pt.dot(N) * N).normalized();
+ int prev_id = -1;
+ int count = 0;
+ std::vector<Vector3d> Ns;
+
+ auto FaceQFromVertices = [&](int f, double tx, double ty) {
+ const Vector3d &n = NF.col(f);
+ const Vector3d &q_1 = QV.col(F(0, f)), &q_2 = QV.col(F(1, f)), &q_3 = QV.col(F(2, f));
+ const Vector3d &n_1 = NV.col(F(0, f)), &n_2 = NV.col(F(1, f)), &n_3 = NV.col(F(2, f));
+ Vector3d q_1n = rotate_vector_into_plane(q_1, n_1, n);
+ Vector3d q_2n = rotate_vector_into_plane(q_2, n_2, n);
+ Vector3d q_3n = rotate_vector_into_plane(q_3, n_3, n);
+ auto orient = compat_orientation_extrinsic_4(q_1n, n, q_2n, n);
+ Vector3d q = (orient.first * tx + orient.second * ty).normalized();
+ orient = compat_orientation_extrinsic_4(q, n, q_3n, n);
+ q = (orient.first * (tx + ty) + orient.second * (1 - tx - ty)).normalized();
+ return q;
+ };
+
+ auto BestQFromGivenQ = [&](const Vector3d &n, const Vector3d &q, const Vector3d &given_q) {
+ Vector3d q_1 = n.cross(q);
+ double t1 = q.dot(given_q);
+ double t2 = q_1.dot(given_q);
+ if (fabs(t1) > fabs(t2)) {
+ if (t1 > 0.0)
+ return Vector3d(q);
+ else
+ return Vector3d(-q);
+ } else {
+ if (t2 > 0.0)
+ return Vector3d(q_1);
+ else
+ return Vector3d(-q_1);
+ }
+ };
+
+ while (len > 0) {
+ count += 1;
+ Vector3d t1 = V.col(F(1, f)) - V.col(F(0, f));
+ Vector3d t2 = V.col(F(2, f)) - V.col(F(0, f));
+ Vector3d N = NF.col(f);
+ Ns.push_back(N);
+ // printf("point dis: %f\n", (p - V.col(F(1, f))).dot(N));
+ int edge_id = f * 3;
+ double max_len = 1e30;
+ bool found = false;
+ int next_id = -1, next_f = -1;
+ Vector3d next_q;
+ Matrix3d m, n;
+ m.col(0) = t1;
+ m.col(1) = t2;
+ m.col(2) = N;
+ n = m.inverse();
+ MatrixXd &T = triangle_space[f];
+ VectorXd coord = T * Vector3d(p - V.col(F(0, f)));
+ VectorXd dirs = (T * pt);
+ double lens[3];
+ lens[0] = -coord.y() / dirs.y();
+ lens[1] = (1 - coord.x() - coord.y()) / (dirs.x() + dirs.y());
+ lens[2] = -coord.x() / dirs.x();
+ for (int fid = 0; fid < 3; ++fid) {
+ if (fid + edge_id == prev_id) continue;
+
+ if (lens[fid] >= 0 && lens[fid] < max_len) {
+ max_len = lens[fid];
+ next_id = E2E[edge_id + fid];
+ next_f = next_id;
+ if (next_f != -1) next_f /= 3;
+ found = true;
+ }
+ }
+ double w1 = (coord.x() + dirs.x() * max_len);
+ double w2 = (coord.y() + dirs.y() * max_len);
+ if (w1 < 0) w1 = 0.0f;
+ if (w2 < 0) w2 = 0.0f;
+ if (w1 + w2 > 1) {
+ double w = w1 + w2;
+ w1 /= w;
+ w2 /= w;
+ }
+
+ if (!found) {
+ printf("error...\n");
+ exit(0);
+ }
+ // printf("status: %f %f %d\n", len, max_len, f);
+ if (max_len >= len) {
+ if (tx && ty) {
+ *tx = w1;
+ *ty = w2;
+ }
+ Vector3d ideal_q = FaceQFromVertices(f, *tx, *ty);
+ *dir_unfold = BestQFromGivenQ(NF.col(f), ideal_q, *dir_unfold);
+ for (int i = Ns.size() - 1; i > 0; --i) {
+ *dir_unfold = rotate_vector_into_plane(*dir_unfold, Ns[i], Ns[i - 1]);
+ }
+ p = p + len * pt;
+ len = 0;
+ return p;
+ }
+ p = V.col(F(0, f)) + t1 * w1 + t2 * w2;
+ len -= max_len;
+ if (next_f == -1) {
+ if (tx && ty) {
+ *tx = w1;
+ *ty = w2;
+ }
+ Vector3d ideal_q = FaceQFromVertices(f, *tx, *ty);
+ *dir_unfold = BestQFromGivenQ(NF.col(f), ideal_q, *dir_unfold);
+ for (int i = Ns.size() - 1; i > 0; --i) {
+ *dir_unfold = rotate_vector_into_plane(*dir_unfold, Ns[i], Ns[i - 1]);
+ }
+ return p;
+ }
+ pt = rotate_vector_into_plane(pt, NF.col(f), NF.col(next_f));
+ // pt = BestQFromGivenQ(NF.col(next_f), QF.col(next_f), pt);
+ if (dir_unfold) {
+ *dir_unfold = BestQFromGivenQ(NF.col(next_f), QF.col(next_f), *dir_unfold);
+ }
+ f = next_f;
+ prev_id = next_id;
+ }
+
+ return p;
+}
+
+} // namespace qflow
+
+#endif
diff --git a/extern/quadriflow/src/flow.hpp b/extern/quadriflow/src/flow.hpp
new file mode 100644
index 00000000000..ab4a01cb4ed
--- /dev/null
+++ b/extern/quadriflow/src/flow.hpp
@@ -0,0 +1,375 @@
+#ifndef FLOW_H_
+#define FLOW_H_
+
+#include <Eigen/Core>
+#include <list>
+#include <map>
+#include <vector>
+
+#include "config.hpp"
+
+#include <boost/graph/adjacency_list.hpp>
+#include <boost/graph/boykov_kolmogorov_max_flow.hpp>
+#include <boost/graph/edmonds_karp_max_flow.hpp>
+#include <boost/graph/push_relabel_max_flow.hpp>
+
+#include <lemon/network_simplex.h>
+#include <lemon/preflow.h>
+#include <lemon/smart_graph.h>
+
+using namespace boost;
+using namespace Eigen;
+
+namespace qflow {
+
+class MaxFlowHelper {
+ public:
+ MaxFlowHelper() {}
+ virtual ~MaxFlowHelper(){};
+ virtual void resize(int n, int m) = 0;
+ virtual void addEdge(int x, int y, int c, int rc, int v, int cost = 1) = 0;
+ virtual int compute() = 0;
+ virtual void applyTo(std::vector<Vector2i>& edge_diff) = 0;
+};
+
+class BoykovMaxFlowHelper : public MaxFlowHelper {
+ public:
+ typedef int EdgeWeightType;
+ typedef adjacency_list_traits<vecS, vecS, directedS> Traits;
+ // clang-format off
+ typedef adjacency_list < vecS, vecS, directedS,
+ property < vertex_name_t, std::string,
+ property < vertex_index_t, long,
+ property < vertex_color_t, boost::default_color_type,
+ property < vertex_distance_t, long,
+ property < vertex_predecessor_t, Traits::edge_descriptor > > > > >,
+
+ property < edge_capacity_t, EdgeWeightType,
+ property < edge_residual_capacity_t, EdgeWeightType,
+ property < edge_reverse_t, Traits::edge_descriptor > > > > Graph;
+ // clang-format on
+
+ public:
+ BoykovMaxFlowHelper() { rev = get(edge_reverse, g); }
+ void resize(int n, int m) {
+ vertex_descriptors.resize(n);
+ for (int i = 0; i < n; ++i) vertex_descriptors[i] = add_vertex(g);
+ }
+ int compute() {
+ EdgeWeightType flow =
+ boykov_kolmogorov_max_flow(g, vertex_descriptors.front(), vertex_descriptors.back());
+ return flow;
+ }
+ void addDirectEdge(Traits::vertex_descriptor& v1, Traits::vertex_descriptor& v2,
+ property_map<Graph, edge_reverse_t>::type& rev, const int capacity,
+ const int inv_capacity, Graph& g, Traits::edge_descriptor& e1,
+ Traits::edge_descriptor& e2) {
+ e1 = add_edge(v1, v2, g).first;
+ e2 = add_edge(v2, v1, g).first;
+ put(edge_capacity, g, e1, capacity);
+ put(edge_capacity, g, e2, inv_capacity);
+
+ rev[e1] = e2;
+ rev[e2] = e1;
+ }
+ void addEdge(int x, int y, int c, int rc, int v, int cost = 1) {
+ Traits::edge_descriptor e1, e2;
+ addDirectEdge(vertex_descriptors[x], vertex_descriptors[y], rev, c, rc, g, e1, e2);
+ if (v != -1) {
+ edge_to_variables[e1] = std::make_pair(v, -1);
+ edge_to_variables[e2] = std::make_pair(v, 1);
+ }
+ }
+ void applyTo(std::vector<Vector2i>& edge_diff) {
+ property_map<Graph, edge_capacity_t>::type capacity = get(edge_capacity, g);
+ property_map<Graph, edge_residual_capacity_t>::type residual_capacity =
+ get(edge_residual_capacity, g);
+
+ graph_traits<Graph>::vertex_iterator u_iter, u_end;
+ graph_traits<Graph>::out_edge_iterator ei, e_end;
+ for (tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter)
+ for (tie(ei, e_end) = out_edges(*u_iter, g); ei != e_end; ++ei)
+ if (capacity[*ei] > 0) {
+ int flow = (capacity[*ei] - residual_capacity[*ei]);
+ if (flow > 0) {
+ auto it = edge_to_variables.find(*ei);
+ if (it != edge_to_variables.end()) {
+ edge_diff[it->second.first / 2][it->second.first % 2] +=
+ it->second.second * flow;
+ }
+ }
+ }
+ }
+
+ private:
+ Graph g;
+ property_map<Graph, edge_reverse_t>::type rev;
+ std::vector<Traits::vertex_descriptor> vertex_descriptors;
+ std::map<Traits::edge_descriptor, std::pair<int, int>> edge_to_variables;
+};
+
+class NetworkSimplexFlowHelper : public MaxFlowHelper {
+ public:
+ using Weight = int;
+ using Capacity = int;
+ using Graph = lemon::SmartDigraph;
+ using Node = Graph::Node;
+ using Arc = Graph::Arc;
+ template <typename ValueType>
+ using ArcMap = lemon::SmartDigraph::ArcMap<ValueType>;
+ using Preflow = lemon::Preflow<lemon::SmartDigraph, ArcMap<Capacity>>;
+ using NetworkSimplex = lemon::NetworkSimplex<lemon::SmartDigraph, Capacity, Weight>;
+
+ public:
+ NetworkSimplexFlowHelper() : cost(graph), capacity(graph), flow(graph), variable(graph) {}
+ ~NetworkSimplexFlowHelper(){};
+ void resize(int n, int m) {
+ nodes.reserve(n);
+ for (int i = 0; i < n; ++i) nodes.push_back(graph.addNode());
+ }
+ void addEdge(int x, int y, int c, int rc, int v, int cst = 1) {
+ assert(x >= 0);
+ assert(v >= -1);
+ if (c) {
+ auto e1 = graph.addArc(nodes[x], nodes[y]);
+ cost[e1] = cst;
+ capacity[e1] = c;
+ variable[e1] = std::make_pair(v, 1);
+ }
+
+ if (rc) {
+ auto e2 = graph.addArc(nodes[y], nodes[x]);
+ cost[e2] = cst;
+ capacity[e2] = rc;
+ variable[e2] = std::make_pair(v, -1);
+ }
+ }
+ int compute() {
+ Preflow pf(graph, capacity, nodes.front(), nodes.back());
+ NetworkSimplex ns(graph);
+
+ // Run preflow to find maximum flow
+ lprintf("push-relabel flow... ");
+ pf.runMinCut();
+ int maxflow = pf.flowValue();
+
+ // Run network simplex to find minimum cost maximum flow
+ ns.costMap(cost).upperMap(capacity).stSupply(nodes.front(), nodes.back(), maxflow);
+ auto status = ns.run();
+ switch (status) {
+ case NetworkSimplex::OPTIMAL:
+ ns.flowMap(flow);
+ break;
+ case NetworkSimplex::INFEASIBLE:
+ lputs("NetworkSimplex::INFEASIBLE");
+ assert(0);
+ break;
+ default:
+ lputs("Unknown: NetworkSimplex::Default");
+ assert(0);
+ break;
+ }
+
+ return maxflow;
+ }
+ void applyTo(std::vector<Vector2i>& edge_diff) {
+ for (Graph::ArcIt e(graph); e != lemon::INVALID; ++e) {
+ int var = variable[e].first;
+ if (var == -1) continue;
+ int sgn = variable[e].second;
+ edge_diff[var / 2][var % 2] -= sgn * flow[e];
+ }
+ }
+
+ private:
+ Graph graph;
+ ArcMap<Weight> cost;
+ ArcMap<Capacity> capacity;
+ ArcMap<Capacity> flow;
+ ArcMap<std::pair<int, int>> variable;
+ std::vector<Node> nodes;
+ std::vector<Arc> edges;
+};
+
+#ifdef WITH_GUROBI
+
+#include <gurobi_c++.h>
+
+class GurobiFlowHelper : public MaxFlowHelper {
+ public:
+ GurobiFlowHelper() {}
+ virtual ~GurobiFlowHelper(){};
+ virtual void resize(int n, int m) {
+ nodes.resize(n * 2);
+ edges.resize(m);
+ }
+ virtual void addEdge(int x, int y, int c, int rc, int v, int cost = 1) {
+ nodes[x * 2 + 0].push_back(vars.size());
+ nodes[y * 2 + 1].push_back(vars.size());
+ vars.push_back(model.addVar(0, c, 0, GRB_INTEGER));
+ edges.push_back(std::make_pair(v, 1));
+
+ nodes[y * 2 + 0].push_back(vars.size());
+ nodes[x * 2 + 1].push_back(vars.size());
+ vars.push_back(model.addVar(0, rc, 0, GRB_INTEGER));
+ edges.push_back(std::make_pair(v, -1));
+ }
+ virtual int compute() {
+ std::cerr << "compute" << std::endl;
+ int ns = nodes.size() / 2;
+
+ int flow;
+ for (int i = 1; i < ns - 1; ++i) {
+ GRBLinExpr cons = 0;
+ for (auto n : nodes[2 * i + 0]) cons += vars[n];
+ for (auto n : nodes[2 * i + 1]) cons -= vars[n];
+ model.addConstr(cons == 0);
+ }
+
+ // first pass, maximum flow
+ GRBLinExpr outbound = 0;
+ {
+ lprintf("first pass\n");
+ for (auto& n : nodes[0]) outbound += vars[n];
+ for (auto& n : nodes[1]) outbound -= vars[n];
+ model.setObjective(outbound, GRB_MAXIMIZE);
+ model.optimize();
+
+ flow = (int)model.get(GRB_DoubleAttr_ObjVal);
+ lprintf("Gurobi result: %d\n", flow);
+ }
+
+ // second pass, minimum cost flow
+ {
+ lprintf("second pass\n");
+ model.addConstr(outbound == flow);
+ GRBLinExpr cost = 0;
+ for (auto& v : vars) cost += v;
+ model.setObjective(cost, GRB_MINIMIZE);
+ model.optimize();
+
+ double optimal_cost = (int)model.get(GRB_DoubleAttr_ObjVal);
+ lprintf("Gurobi result: %.3f\n", optimal_cost);
+ }
+ return flow;
+ }
+ virtual void applyTo(std::vector<Vector2i>& edge_diff) { assert(0); };
+
+ private:
+ GRBEnv env = GRBEnv();
+ GRBModel model = GRBModel(env);
+ std::vector<GRBVar> vars;
+ std::vector<std::pair<int, int>> edges;
+ std::vector<std::vector<int>> nodes;
+};
+
+#endif
+
+class ECMaxFlowHelper : public MaxFlowHelper {
+ public:
+ struct FlowInfo {
+ int id;
+ int capacity, flow;
+ int v, d;
+ FlowInfo* rev;
+ };
+ struct SearchInfo {
+ SearchInfo(int _id, int _prev_id, FlowInfo* _info)
+ : id(_id), prev_id(_prev_id), info(_info) {}
+ int id;
+ int prev_id;
+ FlowInfo* info;
+ };
+ ECMaxFlowHelper() { num = 0; }
+ int num;
+ std::vector<FlowInfo*> variable_to_edge;
+ void resize(int n, int m) {
+ graph.resize(n);
+ variable_to_edge.resize(m, 0);
+ num = n;
+ }
+ void addEdge(int x, int y, int c, int rc, int v, int cost = 0) {
+ FlowInfo flow;
+ flow.id = y;
+ flow.capacity = c;
+ flow.flow = 0;
+ flow.v = v;
+ flow.d = -1;
+ graph[x].push_back(flow);
+ auto& f1 = graph[x].back();
+ flow.id = x;
+ flow.capacity = rc;
+ flow.flow = 0;
+ flow.v = v;
+ flow.d = 1;
+ graph[y].push_back(flow);
+ auto& f2 = graph[y].back();
+ f2.rev = &f1;
+ f1.rev = &f2;
+ }
+ int compute() {
+ int total_flow = 0;
+ int count = 0;
+ while (true) {
+ count += 1;
+ std::vector<int> vhash(num, 0);
+ std::vector<SearchInfo> q;
+ q.push_back(SearchInfo(0, -1, 0));
+ vhash[0] = 1;
+ int q_front = 0;
+ bool found = false;
+ while (q_front < q.size()) {
+ int vert = q[q_front].id;
+ for (auto& l : graph[vert]) {
+ if (vhash[l.id] || l.capacity <= l.flow) continue;
+ q.push_back(SearchInfo(l.id, q_front, &l));
+ vhash[l.id] = 1;
+ if (l.id == num - 1) {
+ found = true;
+ break;
+ }
+ }
+ if (found) break;
+ q_front += 1;
+ }
+ if (q_front == q.size()) break;
+ int loc = q.size() - 1;
+ while (q[loc].prev_id != -1) {
+ q[loc].info->flow += 1;
+ q[loc].info->rev->flow -= 1;
+ loc = q[loc].prev_id;
+ // int prev_v = q[loc].id;
+ // applyFlow(prev_v, current_v, 1);
+ // applyFlow(current_v, prev_v, -1);
+ }
+ total_flow += 1;
+ }
+ return total_flow;
+ }
+ void applyTo(std::vector<Vector2i>& edge_diff) {
+ for (int i = 0; i < graph.size(); ++i) {
+ for (auto& flow : graph[i]) {
+ if (flow.flow > 0 && flow.v != -1) {
+ if (flow.flow > 0) {
+ edge_diff[flow.v / 2][flow.v % 2] += flow.d * flow.flow;
+ if (abs(edge_diff[flow.v / 2][flow.v % 2]) > 2) {
+ }
+ }
+ }
+ }
+ }
+ }
+ void applyFlow(int v1, int v2, int flow) {
+ for (auto& it : graph[v1]) {
+ if (it.id == v2) {
+ it.flow += flow;
+ break;
+ }
+ }
+ }
+ std::vector<std::list<FlowInfo>> graph;
+};
+
+} // namespace qflow
+
+#endif
diff --git a/extern/quadriflow/src/hierarchy.cpp b/extern/quadriflow/src/hierarchy.cpp
new file mode 100644
index 00000000000..8cc41da23d0
--- /dev/null
+++ b/extern/quadriflow/src/hierarchy.cpp
@@ -0,0 +1,1344 @@
+#include "hierarchy.hpp"
+#include <fstream>
+#include <algorithm>
+#include <unordered_map>
+#include "config.hpp"
+#include "field-math.hpp"
+#include <queue>
+#include "localsat.hpp"
+#include "pcg32/pcg32.h"
+#ifdef WITH_TBB
+# include "tbb/tbb.h"
+# include "pss/parallel_stable_sort.h"
+#endif
+
+namespace qflow {
+
+Hierarchy::Hierarchy() {
+ mAdj.resize(MAX_DEPTH + 1);
+ mV.resize(MAX_DEPTH + 1);
+ mN.resize(MAX_DEPTH + 1);
+ mA.resize(MAX_DEPTH + 1);
+ mPhases.resize(MAX_DEPTH + 1);
+ mToLower.resize(MAX_DEPTH);
+ mToUpper.resize(MAX_DEPTH);
+ rng_seed = 0;
+
+ mCQ.reserve(MAX_DEPTH + 1);
+ mCQw.reserve(MAX_DEPTH + 1);
+ mCO.reserve(MAX_DEPTH + 1);
+ mCOw.reserve(MAX_DEPTH + 1);
+}
+
+#undef max
+
+void Hierarchy::Initialize(double scale, int with_scale) {
+ this->with_scale = with_scale;
+ generate_graph_coloring_deterministic(mAdj[0], mV[0].cols(), mPhases[0]);
+
+ for (int i = 0; i < MAX_DEPTH; ++i) {
+ DownsampleGraph(mAdj[i], mV[i], mN[i], mA[i], mV[i + 1], mN[i + 1], mA[i + 1], mToUpper[i],
+ mToLower[i], mAdj[i + 1]);
+ generate_graph_coloring_deterministic(mAdj[i + 1], mV[i + 1].cols(), mPhases[i + 1]);
+ if (mV[i + 1].cols() == 1) {
+ mAdj.resize(i + 2);
+ mV.resize(i + 2);
+ mN.resize(i + 2);
+ mA.resize(i + 2);
+ mToUpper.resize(i + 1);
+ mToLower.resize(i + 1);
+ break;
+ }
+ }
+ mQ.resize(mV.size());
+ mO.resize(mV.size());
+ mS.resize(mV.size());
+ mK.resize(mV.size());
+
+ mCO.resize(mV.size());
+ mCOw.resize(mV.size());
+ mCQ.resize(mV.size());
+ mCQw.resize(mV.size());
+
+ //Set random seed
+ srand(rng_seed);
+
+ mScale = scale;
+ for (int i = 0; i < mV.size(); ++i) {
+ mQ[i].resize(mN[i].rows(), mN[i].cols());
+ mO[i].resize(mN[i].rows(), mN[i].cols());
+ mS[i].resize(2, mN[i].cols());
+ mK[i].resize(2, mN[i].cols());
+ for (int j = 0; j < mN[i].cols(); ++j) {
+ Vector3d s, t;
+ coordinate_system(mN[i].col(j), s, t);
+ //rand() is not thread safe!
+ double angle = ((double)rand()) / RAND_MAX * 2 * M_PI;
+ double x = ((double)rand()) / RAND_MAX * 2 - 1.f;
+ double y = ((double)rand()) / RAND_MAX * 2 - 1.f;
+ mQ[i].col(j) = s * std::cos(angle) + t * std::sin(angle);
+ mO[i].col(j) = mV[i].col(j) + (s * x + t * y) * scale;
+ if (with_scale) {
+ mS[i].col(j) = Vector2d(1.0f, 1.0f);
+ mK[i].col(j) = Vector2d(0.0, 0.0);
+ }
+ }
+ }
+#ifdef WITH_CUDA
+ printf("copy to device...\n");
+ CopyToDevice();
+ printf("copy to device finish...\n");
+#endif
+}
+
+#ifdef WITH_TBB
+void Hierarchy::generate_graph_coloring_deterministic(const AdjacentMatrix& adj, int size,
+ std::vector<std::vector<int>>& phases) {
+ struct ColorData {
+ uint8_t nColors;
+ uint32_t nNodes[256];
+ ColorData() : nColors(0) {}
+ };
+
+ const uint8_t INVALID_COLOR = 0xFF;
+ phases.clear();
+
+ /* Generate a permutation */
+ std::vector<uint32_t> perm(size);
+ std::vector<tbb::spin_mutex> mutex(size);
+ for (uint32_t i = 0; i < size; ++i) perm[i] = i;
+
+ tbb::parallel_for(tbb::blocked_range<uint32_t>(0u, size, GRAIN_SIZE),
+ [&](const tbb::blocked_range<uint32_t>& range) {
+ pcg32 rng;
+ rng.advance(range.begin());
+ for (uint32_t i = range.begin(); i != range.end(); ++i) {
+ uint32_t j = i, k = rng.nextUInt(size - i) + i;
+ if (j == k) continue;
+ if (j > k) std::swap(j, k);
+ tbb::spin_mutex::scoped_lock l0(mutex[j]);
+ tbb::spin_mutex::scoped_lock l1(mutex[k]);
+ std::swap(perm[j], perm[k]);
+ }
+ });
+
+ std::vector<uint8_t> color(size, INVALID_COLOR);
+ ColorData colorData = tbb::parallel_reduce(
+ tbb::blocked_range<uint32_t>(0u, size, GRAIN_SIZE), ColorData(),
+ [&](const tbb::blocked_range<uint32_t>& range, ColorData colorData) -> ColorData {
+ std::vector<uint32_t> neighborhood;
+ bool possible_colors[256];
+
+ for (uint32_t pidx = range.begin(); pidx != range.end(); ++pidx) {
+ uint32_t i = perm[pidx];
+
+ neighborhood.clear();
+ neighborhood.push_back(i);
+ // for (const Link *link = adj[i]; link != adj[i + 1]; ++link)
+ for (auto& link : adj[i]) neighborhood.push_back(link.id);
+ std::sort(neighborhood.begin(), neighborhood.end());
+ for (uint32_t j : neighborhood) mutex[j].lock();
+
+ std::fill(possible_colors, possible_colors + colorData.nColors, true);
+
+ // for (const Link *link = adj[i]; link != adj[i + 1]; ++link) {
+ for (auto& link : adj[i]) {
+ uint8_t c = color[link.id];
+ if (c != INVALID_COLOR) {
+ while (c >= colorData.nColors) {
+ possible_colors[colorData.nColors] = true;
+ colorData.nNodes[colorData.nColors] = 0;
+ colorData.nColors++;
+ }
+ possible_colors[c] = false;
+ }
+ }
+
+ uint8_t chosen_color = INVALID_COLOR;
+ for (uint8_t j = 0; j < colorData.nColors; ++j) {
+ if (possible_colors[j]) {
+ chosen_color = j;
+ break;
+ }
+ }
+ if (chosen_color == INVALID_COLOR) {
+ if (colorData.nColors == INVALID_COLOR - 1)
+ throw std::runtime_error(
+ "Ran out of colors during graph coloring! "
+ "The input mesh is very likely corrupt.");
+ colorData.nNodes[colorData.nColors] = 1;
+ color[i] = colorData.nColors++;
+ } else {
+ colorData.nNodes[chosen_color]++;
+ color[i] = chosen_color;
+ }
+
+ for (uint32_t j : neighborhood) mutex[j].unlock();
+ }
+ return colorData;
+ },
+ [](ColorData c1, ColorData c2) -> ColorData {
+ ColorData result;
+ result.nColors = std::max(c1.nColors, c2.nColors);
+ memset(result.nNodes, 0, sizeof(uint32_t) * result.nColors);
+ for (uint8_t i = 0; i < c1.nColors; ++i) result.nNodes[i] += c1.nNodes[i];
+ for (uint8_t i = 0; i < c2.nColors; ++i) result.nNodes[i] += c2.nNodes[i];
+ return result;
+ });
+
+ phases.resize(colorData.nColors);
+ for (int i = 0; i < colorData.nColors; ++i) phases[i].reserve(colorData.nNodes[i]);
+
+ for (uint32_t i = 0; i < size; ++i) phases[color[i]].push_back(i);
+}
+#else
+void Hierarchy::generate_graph_coloring_deterministic(const AdjacentMatrix& adj, int size,
+ std::vector<std::vector<int>>& phases) {
+ phases.clear();
+
+ std::vector<uint32_t> perm(size);
+ for (uint32_t i = 0; i < size; ++i) perm[i] = i;
+ pcg32 rng;
+ rng.shuffle(perm.begin(), perm.end());
+
+ std::vector<int> color(size, -1);
+ std::vector<uint8_t> possible_colors;
+ std::vector<int> size_per_color;
+ int ncolors = 0;
+
+ for (uint32_t i = 0; i < size; ++i) {
+ uint32_t ip = perm[i];
+
+ std::fill(possible_colors.begin(), possible_colors.end(), 1);
+
+ for (auto& link : adj[ip]) {
+ int c = color[link.id];
+ if (c >= 0) possible_colors[c] = 0;
+ }
+
+ int chosen_color = -1;
+ for (uint32_t j = 0; j < possible_colors.size(); ++j) {
+ if (possible_colors[j]) {
+ chosen_color = j;
+ break;
+ }
+ }
+
+ if (chosen_color < 0) {
+ chosen_color = ncolors++;
+ possible_colors.resize(ncolors);
+ size_per_color.push_back(0);
+ }
+
+ color[ip] = chosen_color;
+ size_per_color[chosen_color]++;
+ }
+ phases.resize(ncolors);
+ for (int i = 0; i < ncolors; ++i) phases[i].reserve(size_per_color[i]);
+ for (uint32_t i = 0; i < size; ++i) phases[color[i]].push_back(i);
+}
+#endif
+
+void Hierarchy::DownsampleGraph(const AdjacentMatrix adj, const MatrixXd& V, const MatrixXd& N,
+ const VectorXd& A, MatrixXd& V_p, MatrixXd& N_p, VectorXd& A_p,
+ MatrixXi& to_upper, VectorXi& to_lower, AdjacentMatrix& adj_p) {
+ struct Entry {
+ int i, j;
+ double order;
+ inline Entry() { i = j = -1; };
+ inline Entry(int i, int j, double order) : i(i), j(j), order(order) {}
+ inline bool operator<(const Entry& e) const { return order > e.order; }
+ inline bool operator==(const Entry& e) const { return order == e.order; }
+ };
+
+ int nLinks = 0;
+ for (auto& adj_i : adj) nLinks += adj_i.size();
+ std::vector<Entry> entries(nLinks);
+ std::vector<int> bases(adj.size());
+ for (int i = 1; i < bases.size(); ++i) {
+ bases[i] = bases[i - 1] + adj[i - 1].size();
+ }
+
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int i = 0; i < V.cols(); ++i) {
+ int base = bases[i];
+ auto& ad = adj[i];
+ auto entry_it = entries.begin() + base;
+ for (auto it = ad.begin(); it != ad.end(); ++it, ++entry_it) {
+ int k = it->id;
+ double dp = N.col(i).dot(N.col(k));
+ double ratio = A[i] > A[k] ? (A[i] / A[k]) : (A[k] / A[i]);
+ *entry_it = Entry(i, k, dp * ratio);
+ }
+ }
+
+#ifdef WITH_TBB
+ pss::parallel_stable_sort(entries.begin(), entries.end(), std::less<Entry>());
+#else
+ std::stable_sort(entries.begin(), entries.end(), std::less<Entry>());
+#endif
+
+ std::vector<bool> mergeFlag(V.cols(), false);
+
+ int nCollapsed = 0;
+ for (int i = 0; i < nLinks; ++i) {
+ const Entry& e = entries[i];
+ if (mergeFlag[e.i] || mergeFlag[e.j]) continue;
+ mergeFlag[e.i] = mergeFlag[e.j] = true;
+ entries[nCollapsed++] = entries[i];
+ }
+ int vertexCount = V.cols() - nCollapsed;
+
+ // Allocate memory for coarsened graph
+ V_p.resize(3, vertexCount);
+ N_p.resize(3, vertexCount);
+ A_p.resize(vertexCount);
+ to_upper.resize(2, vertexCount);
+ to_lower.resize(V.cols());
+
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int i = 0; i < nCollapsed; ++i) {
+ const Entry& e = entries[i];
+ const double area1 = A[e.i], area2 = A[e.j], surfaceArea = area1 + area2;
+ if (surfaceArea > RCPOVERFLOW)
+ V_p.col(i) = (V.col(e.i) * area1 + V.col(e.j) * area2) / surfaceArea;
+ else
+ V_p.col(i) = (V.col(e.i) + V.col(e.j)) * 0.5f;
+ Vector3d normal = N.col(e.i) * area1 + N.col(e.j) * area2;
+ double norm = normal.norm();
+ N_p.col(i) = norm > RCPOVERFLOW ? Vector3d(normal / norm) : Vector3d::UnitX();
+ A_p[i] = surfaceArea;
+ to_upper.col(i) << e.i, e.j;
+ to_lower[e.i] = i;
+ to_lower[e.j] = i;
+ }
+
+ int offset = nCollapsed;
+
+ for (int i = 0; i < V.cols(); ++i) {
+ if (!mergeFlag[i]) {
+ int idx = offset++;
+ V_p.col(idx) = V.col(i);
+ N_p.col(idx) = N.col(i);
+ A_p[idx] = A[i];
+ to_upper.col(idx) << i, -1;
+ to_lower[i] = idx;
+ }
+ }
+
+ adj_p.resize(V_p.cols());
+ std::vector<int> capacity(V_p.cols());
+ std::vector<std::vector<Link>> scratches(V_p.cols());
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int i = 0; i < V_p.cols(); ++i) {
+ int t = 0;
+ for (int j = 0; j < 2; ++j) {
+ int upper = to_upper(j, i);
+ if (upper == -1) continue;
+ t += adj[upper].size();
+ }
+ scratches[i].reserve(t);
+ adj_p[i].reserve(t);
+ }
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int i = 0; i < V_p.cols(); ++i) {
+ auto& scratch = scratches[i];
+ for (int j = 0; j < 2; ++j) {
+ int upper = to_upper(j, i);
+ if (upper == -1) continue;
+ auto& ad = adj[upper];
+ for (auto& link : ad) scratch.push_back(Link(to_lower[link.id], link.weight));
+ }
+ std::sort(scratch.begin(), scratch.end());
+ int id = -1;
+ auto& ad = adj_p[i];
+ for (auto& link : scratch) {
+ if (link.id != i) {
+ if (id != link.id) {
+ ad.push_back(link);
+ id = link.id;
+ } else {
+ ad.back().weight += link.weight;
+ }
+ }
+ }
+ }
+}
+
+void Hierarchy::SaveToFile(FILE* fp) {
+ Save(fp, mScale);
+ Save(fp, mF);
+ Save(fp, mE2E);
+ Save(fp, mAdj);
+ Save(fp, mV);
+ Save(fp, mN);
+ Save(fp, mA);
+ Save(fp, mToLower);
+ Save(fp, mToUpper);
+ Save(fp, mQ);
+ Save(fp, mO);
+ Save(fp, mS);
+ Save(fp, mK);
+ Save(fp, this->mPhases);
+}
+
+void Hierarchy::LoadFromFile(FILE* fp) {
+ Read(fp, mScale);
+ Read(fp, mF);
+ Read(fp, mE2E);
+ Read(fp, mAdj);
+ Read(fp, mV);
+ Read(fp, mN);
+ Read(fp, mA);
+ Read(fp, mToLower);
+ Read(fp, mToUpper);
+ Read(fp, mQ);
+ Read(fp, mO);
+ Read(fp, mS);
+ Read(fp, mK);
+ Read(fp, this->mPhases);
+}
+
+void Hierarchy::UpdateGraphValue(std::vector<Vector3i>& FQ, std::vector<Vector3i>& F2E,
+ std::vector<Vector2i>& edge_diff) {
+ FQ = std::move(mFQ[0]);
+ F2E = std::move(mF2E[0]);
+ edge_diff = std::move(mEdgeDiff[0]);
+}
+
+void Hierarchy::DownsampleEdgeGraph(std::vector<Vector3i>& FQ, std::vector<Vector3i>& F2E,
+ std::vector<Vector2i>& edge_diff,
+ std::vector<int>& allow_changes, int level) {
+ std::vector<Vector2i> E2F(edge_diff.size(), Vector2i(-1, -1));
+ for (int i = 0; i < F2E.size(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ int e = F2E[i][j];
+ if (E2F[e][0] == -1)
+ E2F[e][0] = i;
+ else
+ E2F[e][1] = i;
+ }
+ }
+ int levels = (level == -1) ? 100 : level;
+ mFQ.resize(levels);
+ mF2E.resize(levels);
+ mE2F.resize(levels);
+ mEdgeDiff.resize(levels);
+ mAllowChanges.resize(levels);
+ mSing.resize(levels);
+ mToUpperEdges.resize(levels - 1);
+ mToUpperOrients.resize(levels - 1);
+ for (int i = 0; i < FQ.size(); ++i) {
+ Vector2i diff(0, 0);
+ for (int j = 0; j < 3; ++j) {
+ diff += rshift90(edge_diff[F2E[i][j]], FQ[i][j]);
+ }
+ if (diff != Vector2i::Zero()) {
+ mSing[0].push_back(i);
+ }
+ }
+ mAllowChanges[0] = allow_changes;
+ mFQ[0] = std::move(FQ);
+ mF2E[0] = std::move(F2E);
+ mE2F[0] = std::move(E2F);
+ mEdgeDiff[0] = std::move(edge_diff);
+ for (int l = 0; l < levels - 1; ++l) {
+ auto& FQ = mFQ[l];
+ auto& E2F = mE2F[l];
+ auto& F2E = mF2E[l];
+ auto& Allow = mAllowChanges[l];
+ auto& EdgeDiff = mEdgeDiff[l];
+ auto& Sing = mSing[l];
+ std::vector<int> fixed_faces(F2E.size(), 0);
+ for (auto& s : Sing) {
+ fixed_faces[s] = 1;
+ }
+
+ auto& toUpper = mToUpperEdges[l];
+ auto& toUpperOrients = mToUpperOrients[l];
+ toUpper.resize(E2F.size(), -1);
+ toUpperOrients.resize(E2F.size(), 0);
+
+ auto& nFQ = mFQ[l + 1];
+ auto& nE2F = mE2F[l + 1];
+ auto& nF2E = mF2E[l + 1];
+ auto& nAllow = mAllowChanges[l + 1];
+ auto& nEdgeDiff = mEdgeDiff[l + 1];
+ auto& nSing = mSing[l + 1];
+
+ for (int i = 0; i < E2F.size(); ++i) {
+ if (EdgeDiff[i] != Vector2i::Zero()) continue;
+ if ((E2F[i][0] >= 0 && fixed_faces[E2F[i][0]]) ||
+ (E2F[i][1] >= 0 && fixed_faces[E2F[i][1]])) {
+ continue;
+ }
+ for (int j = 0; j < 2; ++j) {
+ int f = E2F[i][j];
+ if (f < 0)
+ continue;
+ for (int k = 0; k < 3; ++k) {
+ int neighbor_e = F2E[f][k];
+ for (int m = 0; m < 2; ++m) {
+ int neighbor_f = E2F[neighbor_e][m];
+ if (neighbor_f < 0)
+ continue;
+ if (fixed_faces[neighbor_f] == 0) fixed_faces[neighbor_f] = 1;
+ }
+ }
+ }
+ if (E2F[i][0] >= 0)
+ fixed_faces[E2F[i][0]] = 2;
+ if (E2F[i][1] >= 0)
+ fixed_faces[E2F[i][1]] = 2;
+ toUpper[i] = -2;
+ }
+ for (int i = 0; i < E2F.size(); ++i) {
+ if (toUpper[i] == -2) continue;
+ if ((E2F[i][0] < 0 || fixed_faces[E2F[i][0]] == 2) && (E2F[i][1] < 0 || fixed_faces[E2F[i][1]] == 2)) {
+ toUpper[i] = -3;
+ continue;
+ }
+ }
+ int numE = 0;
+ for (int i = 0; i < toUpper.size(); ++i) {
+ if (toUpper[i] == -1) {
+ if ((E2F[i][0] < 0 || fixed_faces[E2F[i][0]] < 2) && (E2F[i][1] < 0 || fixed_faces[E2F[i][1]] < 2)) {
+ nE2F.push_back(E2F[i]);
+ toUpperOrients[i] = 0;
+ toUpper[i] = numE++;
+ continue;
+ }
+ int f0 = (E2F[i][1] < 0 || fixed_faces[E2F[i][0]] < 2) ? E2F[i][0] : E2F[i][1];
+ int e = i;
+ int f = f0;
+ std::vector<std::pair<int, int>> paths;
+ paths.push_back(std::make_pair(i, 0));
+ while (true) {
+ if (E2F[e][0] == f)
+ f = E2F[e][1];
+ else if (E2F[e][1] == f)
+ f = E2F[e][0];
+ if (f < 0 || fixed_faces[f] < 2) {
+ for (int j = 0; j < paths.size(); ++j) {
+ auto& p = paths[j];
+ toUpper[p.first] = numE;
+ int orient = p.second;
+ if (j > 0) orient = (orient + toUpperOrients[paths[j - 1].first]) % 4;
+ toUpperOrients[p.first] = orient;
+ }
+ nE2F.push_back(Vector2i(f0, f));
+ numE += 1;
+ break;
+ }
+ int ind0 = -1, ind1 = -1;
+ int e0 = e;
+ for (int j = 0; j < 3; ++j) {
+ if (F2E[f][j] == e) {
+ ind0 = j;
+ break;
+ }
+ }
+ for (int j = 0; j < 3; ++j) {
+ int e1 = F2E[f][j];
+ if (e1 != e && toUpper[e1] != -2) {
+ e = e1;
+ ind1 = j;
+ break;
+ }
+ }
+
+ if (ind1 != -1) {
+ paths.push_back(std::make_pair(e, (FQ[f][ind1] - FQ[f][ind0] + 6) % 4));
+ } else {
+ if (EdgeDiff[e] != Vector2i::Zero()) {
+ printf("Unsatisfied !!!...\n");
+ printf("%d %d %d: %d %d\n", F2E[f][0], F2E[f][1], F2E[f][2], e0, e);
+ exit(0);
+ }
+ for (auto& p : paths) {
+ toUpper[p.first] = numE;
+ toUpperOrients[p.first] = 0;
+ }
+ numE += 1;
+ nE2F.push_back(Vector2i(f0, f0));
+ break;
+ }
+ }
+ }
+ }
+ nEdgeDiff.resize(numE);
+ nAllow.resize(numE * 2, 1);
+ for (int i = 0; i < toUpper.size(); ++i) {
+ if (toUpper[i] >= 0 && toUpperOrients[i] == 0) {
+ nEdgeDiff[toUpper[i]] = EdgeDiff[i];
+ }
+ if (toUpper[i] >= 0) {
+ int dimension = toUpperOrients[i] % 2;
+ if (Allow[i * 2 + dimension] == 0)
+ nAllow[toUpper[i] * 2] = 0;
+ else if (Allow[i * 2 + dimension] == 2)
+ nAllow[toUpper[i] * 2] = 2;
+ if (Allow[i * 2 + 1 - dimension] == 0)
+ nAllow[toUpper[i] * 2 + 1] = 0;
+ else if (Allow[i * 2 + 1 - dimension] == 2)
+ nAllow[toUpper[i] * 2 + 1] = 2;
+ }
+ }
+ std::vector<int> upperface(F2E.size(), -1);
+
+ for (int i = 0; i < F2E.size(); ++i) {
+ Vector3i eid;
+ for (int j = 0; j < 3; ++j) {
+ eid[j] = toUpper[F2E[i][j]];
+ }
+ if (eid[0] >= 0 && eid[1] >= 0 && eid[2] >= 0) {
+ Vector3i eid_orient;
+ for (int j = 0; j < 3; ++j) {
+ eid_orient[j] = (FQ[i][j] + 4 - toUpperOrients[F2E[i][j]]) % 4;
+ }
+ upperface[i] = nF2E.size();
+ nF2E.push_back(eid);
+ nFQ.push_back(eid_orient);
+ }
+ }
+ for (int i = 0; i < nE2F.size(); ++i) {
+ for (int j = 0; j < 2; ++j) {
+ if (nE2F[i][j] >= 0)
+ nE2F[i][j] = upperface[nE2F[i][j]];
+ }
+ }
+
+ for (auto& s : Sing) {
+ if (upperface[s] >= 0) nSing.push_back(upperface[s]);
+ }
+ mToUpperFaces.push_back(std::move(upperface));
+
+ if (nEdgeDiff.size() == EdgeDiff.size()) {
+ levels = l + 1;
+ break;
+ }
+ }
+
+ mFQ.resize(levels);
+ mF2E.resize(levels);
+ mAllowChanges.resize(levels);
+ mE2F.resize(levels);
+ mEdgeDiff.resize(levels);
+ mSing.resize(levels);
+ mToUpperEdges.resize(levels - 1);
+ mToUpperOrients.resize(levels - 1);
+}
+
+int Hierarchy::FixFlipSat(int depth, int threshold) {
+ if (system("which minisat > /dev/null 2>&1")) {
+ printf("minisat not found, \"-sat\" will not be used!\n");
+ return 0;
+ }
+ if (system("which timeout > /dev/null 2>&1")) {
+ printf("timeout not found, \"-sat\" will not be used!\n");
+ return 0;
+ }
+
+ auto& F2E = mF2E[depth];
+ auto& E2F = mE2F[depth];
+ auto& FQ = mFQ[depth];
+ auto& EdgeDiff = mEdgeDiff[depth];
+ auto& AllowChanges = mAllowChanges[depth];
+
+ // build E2E
+ std::vector<int> E2E(F2E.size() * 3, -1);
+ for (int i = 0; i < E2F.size(); ++i) {
+ int f1 = E2F[i][0];
+ int f2 = E2F[i][1];
+ int t1 = 0;
+ int t2 = 2;
+ if (f1 != -1) while (F2E[f1][t1] != i) t1 += 1;
+ if (f2 != -1) while (F2E[f2][t2] != i) t2 -= 1;
+ t1 += f1 * 3;
+ t2 += f2 * 3;
+ if (f1 != -1) E2E[t1] = (f2 == -1) ? -1 : t2;
+ if (f2 != -1) E2E[t2] = (f1 == -1) ? -1 : t1;
+ }
+
+ auto IntegerArea = [&](int f) {
+ Vector2i diff1 = rshift90(EdgeDiff[F2E[f][0]], FQ[f][0]);
+ Vector2i diff2 = rshift90(EdgeDiff[F2E[f][1]], FQ[f][1]);
+ return diff1[0] * diff2[1] - diff1[1] * diff2[0];
+ };
+
+ std::deque<std::pair<int, int>> Q;
+ std::vector<bool> mark_dedges(F2E.size() * 3, false);
+ for (int f = 0; f < F2E.size(); ++f) {
+ if (IntegerArea(f) < 0) {
+ for (int j = 0; j < 3; ++j) {
+ if (mark_dedges[f * 3 + j]) continue;
+ Q.push_back(std::make_pair(f * 3 + j, 0));
+ mark_dedges[f * 3 + j] = true;
+ }
+ }
+ }
+
+ int mark_count = 0;
+ while (!Q.empty()) {
+ int e0 = Q.front().first;
+ int depth = Q.front().second;
+ Q.pop_front();
+ mark_count++;
+
+ int e = e0, e1;
+ do {
+ e1 = E2E[e];
+ if (e1 == -1) break;
+ int length = EdgeDiff[F2E[e1 / 3][e1 % 3]].array().abs().sum();
+ if (length == 0 && !mark_dedges[e1]) {
+ mark_dedges[e1] = true;
+ Q.push_front(std::make_pair(e1, depth));
+ }
+ e = (e1 / 3) * 3 + (e1 + 1) % 3;
+ mark_dedges[e] = true;
+ } while (e != e0);
+ if (e1 == -1) {
+ do {
+ e1 = E2E[e];
+ if (e1 == -1) break;
+ int length = EdgeDiff[F2E[e1 / 3][e1 % 3]].array().abs().sum();
+ if (length == 0 && !mark_dedges[e1]) {
+ mark_dedges[e1] = true;
+ Q.push_front(std::make_pair(e1, depth));
+ }
+ e = (e1 / 3) * 3 + (e1 + 2) % 3;
+ mark_dedges[e] = true;
+ } while (e != e0);
+ }
+
+ do {
+ e1 = E2E[e];
+ if (e1 == -1) break;
+ int length = EdgeDiff[F2E[e1 / 3][e1 % 3]].array().abs().sum();
+ if (length > 0 && depth + length <= threshold && !mark_dedges[e1]) {
+ mark_dedges[e1] = true;
+ Q.push_back(std::make_pair(e1, depth + length));
+ }
+ e = e1 / 3 * 3 + (e1 + 1) % 3;
+ mark_dedges[e] = true;
+ } while (e != e0);
+ if (e1 == -1) {
+ do {
+ e1 = E2E[e];
+ if (e1 == -1) break;
+ int length = EdgeDiff[F2E[e1 / 3][e1 % 3]].array().abs().sum();
+ if (length > 0 && depth + length <= threshold && !mark_dedges[e1]) {
+ mark_dedges[e1] = true;
+ Q.push_back(std::make_pair(e1, depth + length));
+ }
+ e = e1 / 3 * 3 + (e1 + 2) % 3;
+ mark_dedges[e] = true;
+ } while (e != e0);
+ }
+ }
+ lprintf("[FlipH] Depth %2d: marked = %d\n", depth, mark_count);
+
+ std::vector<bool> flexible(EdgeDiff.size(), false);
+ for (int i = 0; i < F2E.size(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ int dedge = i * 3 + j;
+ int edgeid = F2E[i][j];
+ if (mark_dedges[dedge]) {
+ flexible[edgeid] = true;
+ }
+ }
+ }
+ for (int i = 0; i < flexible.size(); ++i) {
+ if (E2F[i][0] == E2F[i][1]) flexible[i] = false;
+ if (AllowChanges[i] == 0) flexible[i] = false;
+ }
+
+ // Reindexing and solve
+ int num_group = 0;
+ std::vector<int> groups(EdgeDiff.size(), -1);
+ std::vector<int> indices(EdgeDiff.size(), -1);
+ for (int i = 0; i < EdgeDiff.size(); ++i) {
+ if (groups[i] == -1 && flexible[i]) {
+ // group it
+ std::queue<int> q;
+ q.push(i);
+ groups[i] = num_group;
+ while (!q.empty()) {
+ int e = q.front();
+ q.pop();
+ int f[] = {E2F[e][0], E2F[e][1]};
+ for (int j = 0; j < 2; ++j) {
+ if (f[j] == -1) continue;
+ for (int k = 0; k < 3; ++k) {
+ int e1 = F2E[f[j]][k];
+ if (flexible[e1] && groups[e1] == -1) {
+ groups[e1] = num_group;
+ q.push(e1);
+ }
+ }
+ }
+ }
+ num_group += 1;
+ }
+ }
+
+ std::vector<int> num_edges(num_group);
+ std::vector<int> num_flips(num_group);
+ std::vector<std::vector<int>> values(num_group);
+ std::vector<std::vector<Vector3i>> variable_eq(num_group);
+ std::vector<std::vector<Vector3i>> constant_eq(num_group);
+ std::vector<std::vector<Vector4i>> variable_ge(num_group);
+ std::vector<std::vector<Vector2i>> constant_ge(num_group);
+ for (int i = 0; i < groups.size(); ++i) {
+ if (groups[i] != -1) {
+ indices[i] = num_edges[groups[i]]++;
+ values[groups[i]].push_back(EdgeDiff[i][0]);
+ values[groups[i]].push_back(EdgeDiff[i][1]);
+ }
+ }
+ std::vector<int> num_edges_flexible = num_edges;
+ std::map<std::pair<int, int>, int> fixed_variables;
+ for (int i = 0; i < F2E.size(); ++i) {
+ Vector2i var[3];
+ Vector2i cst[3];
+ int gind = 0;
+ while (gind < 3 && groups[F2E[i][gind]] == -1) gind += 1;
+ if (gind == 3) continue;
+ int group = groups[F2E[i][gind]];
+ int ind[3] = {-1, -1, -1};
+ for (int j = 0; j < 3; ++j) {
+ int g = groups[F2E[i][j]];
+ if (g != group) {
+ if (g == -1) {
+ auto key = std::make_pair(F2E[i][j], group);
+ auto it = fixed_variables.find(key);
+ if (it == fixed_variables.end()) {
+ ind[j] = num_edges[group];
+ values[group].push_back(EdgeDiff[F2E[i][j]][0]);
+ values[group].push_back(EdgeDiff[F2E[i][j]][1]);
+ fixed_variables[key] = num_edges[group]++;
+ } else {
+ ind[j] = it->second;
+ }
+ }
+ } else {
+ ind[j] = indices[F2E[i][j]];
+ }
+ }
+ for (int j = 0; j < 3; ++j) assert(ind[j] != -1);
+ for (int j = 0; j < 3; ++j) {
+ var[j] = rshift90(Vector2i(ind[j] * 2 + 1, ind[j] * 2 + 2), FQ[i][j]);
+ cst[j] = var[j].array().sign();
+ var[j] = var[j].array().abs() - 1;
+ }
+
+ num_flips[group] += IntegerArea(i) < 0;
+ variable_eq[group].push_back(Vector3i(var[0][0], var[1][0], var[2][0]));
+ constant_eq[group].push_back(Vector3i(cst[0][0], cst[1][0], cst[2][0]));
+ variable_eq[group].push_back(Vector3i(var[0][1], var[1][1], var[2][1]));
+ constant_eq[group].push_back(Vector3i(cst[0][1], cst[1][1], cst[2][1]));
+
+ variable_ge[group].push_back(Vector4i(var[0][0], var[1][1], var[0][1], var[1][0]));
+ constant_ge[group].push_back(Vector2i(cst[0][0] * cst[1][1], cst[0][1] * cst[1][0]));
+ }
+ int flip_before = 0, flip_after = 0;
+ for (int i = 0; i < F2E.size(); ++i) {
+ int area = IntegerArea(i);
+ if (area < 0) flip_before++;
+ }
+
+ for (int i = 0; i < num_group; ++i) {
+ std::vector<bool> flexible(values[i].size(), true);
+ for (int j = num_edges_flexible[i] * 2; j < flexible.size(); ++j) {
+ flexible[j] = false;
+ }
+ SolveSatProblem(values[i].size(), values[i], flexible, variable_eq[i], constant_eq[i],
+ variable_ge[i], constant_ge[i]);
+ }
+
+ for (int i = 0; i < EdgeDiff.size(); ++i) {
+ int group = groups[i];
+ if (group == -1) continue;
+ EdgeDiff[i][0] = values[group][2 * indices[i] + 0];
+ EdgeDiff[i][1] = values[group][2 * indices[i] + 1];
+ }
+ for (int i = 0; i < F2E.size(); ++i) {
+ Vector2i diff(0, 0);
+ for (int j = 0; j < 3; ++j) {
+ diff += rshift90(EdgeDiff[F2E[i][j]], FQ[i][j]);
+ }
+ assert(diff == Vector2i::Zero());
+
+ int area = IntegerArea(i);
+ if (area < 0) flip_after++;
+ }
+
+ lprintf("[FlipH] FlipArea, Before: %d After %d\n", flip_before, flip_after);
+ return flip_after;
+}
+
+void Hierarchy::PushDownwardFlip(int depth) {
+ auto& EdgeDiff = mEdgeDiff[depth];
+ auto& nEdgeDiff = mEdgeDiff[depth - 1];
+ auto& toUpper = mToUpperEdges[depth - 1];
+ auto& toUpperOrients = mToUpperOrients[depth - 1];
+ auto& toUpperFaces = mToUpperFaces[depth - 1];
+ for (int i = 0; i < toUpper.size(); ++i) {
+ if (toUpper[i] >= 0) {
+ int orient = (4 - toUpperOrients[i]) % 4;
+ nEdgeDiff[i] = rshift90(EdgeDiff[toUpper[i]], orient);
+ } else {
+ nEdgeDiff[i] = Vector2i(0, 0);
+ }
+ }
+ auto& nF2E = mF2E[depth - 1];
+ auto& nFQ = mFQ[depth - 1];
+ for (int i = 0; i < nF2E.size(); ++i) {
+ Vector2i diff(0, 0);
+ for (int j = 0; j < 3; ++j) {
+ diff += rshift90(nEdgeDiff[nF2E[i][j]], nFQ[i][j]);
+ }
+ if (diff != Vector2i::Zero()) {
+ printf("Fail!!!!!!! %d\n", i);
+ for (int j = 0; j < 3; ++j) {
+ Vector2i d = rshift90(nEdgeDiff[nF2E[i][j]], nFQ[i][j]);
+ printf("<%d %d %d>\n", nF2E[i][j], nFQ[i][j], toUpperOrients[nF2E[i][j]]);
+ printf("%d %d\n", d[0], d[1]);
+ printf("%d -> %d\n", nF2E[i][j], toUpper[nF2E[i][j]]);
+ }
+ printf("%d -> %d\n", i, toUpperFaces[i]);
+ exit(1);
+ }
+ }
+}
+
+void Hierarchy::FixFlip() {
+ int l = mF2E.size() - 1;
+ auto& F2E = mF2E[l];
+ auto& E2F = mE2F[l];
+ auto& FQ = mFQ[l];
+ auto& EdgeDiff = mEdgeDiff[l];
+ auto& AllowChange = mAllowChanges[l];
+
+ // build E2E
+ std::vector<int> E2E(F2E.size() * 3, -1);
+ for (int i = 0; i < E2F.size(); ++i) {
+ int v1 = E2F[i][0];
+ int v2 = E2F[i][1];
+ int t1 = 0;
+ int t2 = 2;
+ if (v1 != -1)
+ while (F2E[v1][t1] != i) t1 += 1;
+ if (v2 != -1)
+ while (F2E[v2][t2] != i) t2 -= 1;
+ t1 += v1 * 3;
+ t2 += v2 * 3;
+ if (v1 != -1)
+ E2E[t1] = (v2 == -1) ? -1 : t2;
+ if (v2 != -1)
+ E2E[t2] = (v1 == -1) ? -1 : t1;
+ }
+
+ auto Area = [&](int f) {
+ Vector2i diff1 = rshift90(EdgeDiff[F2E[f][0]], FQ[f][0]);
+ Vector2i diff2 = rshift90(EdgeDiff[F2E[f][1]], FQ[f][1]);
+ return diff1[0] * diff2[1] - diff1[1] * diff2[0];
+ };
+ std::vector<int> valences(F2E.size() * 3, -10000); // comment this line
+ auto CheckShrink = [&](int deid, int allowed_edge_length) {
+ // Check if we want shrink direct edge deid so that all edge length is smaller than
+ // allowed_edge_length
+ if (deid == -1) {
+ return false;
+ }
+ std::vector<int> corresponding_faces;
+ std::vector<int> corresponding_edges;
+ std::vector<Vector2i> corresponding_diff;
+ int deid0 = deid;
+ while (deid != -1) {
+ deid = deid / 3 * 3 + (deid + 2) % 3;
+ if (E2E[deid] == -1)
+ break;
+ deid = E2E[deid];
+ if (deid == deid0)
+ break;
+ }
+ Vector2i diff = EdgeDiff[F2E[deid / 3][deid % 3]];
+ do {
+ corresponding_diff.push_back(diff);
+ corresponding_edges.push_back(deid);
+ corresponding_faces.push_back(deid / 3);
+
+ // transform to the next face
+ deid = E2E[deid];
+ if (deid == -1) {
+ return false;
+ }
+ // transform for the target incremental diff
+ diff = -rshift90(diff, FQ[deid / 3][deid % 3]);
+ deid = deid / 3 * 3 + (deid + 1) % 3;
+ // transform to local
+ diff = rshift90(diff, (4 - FQ[deid / 3][deid % 3]) % 4);
+ } while (deid != corresponding_edges.front());
+ // check diff
+ if (deid != -1 && diff != corresponding_diff.front()) {
+ return false;
+ }
+ std::unordered_map<int, Vector2i> new_values;
+ for (int i = 0; i < corresponding_diff.size(); ++i) {
+ int deid = corresponding_edges[i];
+ int eid = F2E[deid / 3][deid % 3];
+ new_values[eid] = EdgeDiff[eid];
+ }
+ for (int i = 0; i < corresponding_diff.size(); ++i) {
+ int deid = corresponding_edges[i];
+ int eid = F2E[deid / 3][deid % 3];
+ for (int j = 0; j < 2; ++j) {
+ if (corresponding_diff[i][j] != 0 && AllowChange[eid * 2 + j] == 0) return false;
+ }
+ auto& res = new_values[eid];
+ res -= corresponding_diff[i];
+ int edge_thres = allowed_edge_length;
+ if (abs(res[0]) > edge_thres || abs(res[1]) > edge_thres) {
+ return false;
+ }
+ if ((abs(res[0]) > 1 && abs(res[1]) != 0) || (abs(res[1]) > 1 && abs(res[0]) != 0))
+ return false;
+ }
+ int prev_area = 0, current_area = 0;
+ for (int f = 0; f < corresponding_faces.size(); ++f) {
+ int area = Area(corresponding_faces[f]);
+ if (area < 0) prev_area += 1;
+ }
+ for (auto& p : new_values) {
+ std::swap(EdgeDiff[p.first], p.second);
+ }
+ for (int f = 0; f < corresponding_faces.size(); ++f) {
+ int area = Area(corresponding_faces[f]);
+ if (area < 0) {
+ current_area += 1;
+ }
+ }
+ if (current_area < prev_area) {
+ return true;
+ }
+ for (auto& p : new_values) {
+ std::swap(EdgeDiff[p.first], p.second);
+ }
+ return false;
+ };
+
+ std::queue<int> flipped;
+ for (int i = 0; i < F2E.size(); ++i) {
+ int area = Area(i);
+ if (area < 0) {
+ flipped.push(i);
+ }
+ }
+
+ bool update = false;
+ int max_len = 1;
+ while (!update && max_len <= 2) {
+ while (!flipped.empty()) {
+ int f = flipped.front();
+ if (Area(f) >= 0) {
+ flipped.pop();
+ continue;
+ }
+ for (int i = 0; i < 3; ++i) {
+ if (CheckShrink(f * 3 + i, max_len) || CheckShrink(E2E[f * 3 + i], max_len)) {
+ update = true;
+ break;
+ }
+ }
+ flipped.pop();
+ }
+ max_len += 1;
+ }
+ if (update) {
+ Hierarchy flip_hierarchy;
+ flip_hierarchy.DownsampleEdgeGraph(mFQ.back(), mF2E.back(), mEdgeDiff.back(),
+ mAllowChanges.back(), -1);
+ flip_hierarchy.FixFlip();
+ flip_hierarchy.UpdateGraphValue(mFQ.back(), mF2E.back(), mEdgeDiff.back());
+ }
+ PropagateEdge();
+}
+
+void Hierarchy::PropagateEdge() {
+ for (int level = mToUpperEdges.size(); level > 0; --level) {
+ auto& EdgeDiff = mEdgeDiff[level];
+ auto& nEdgeDiff = mEdgeDiff[level - 1];
+ auto& FQ = mFQ[level];
+ auto& nFQ = mFQ[level - 1];
+ auto& F2E = mF2E[level - 1];
+ auto& toUpper = mToUpperEdges[level - 1];
+ auto& toUpperFace = mToUpperFaces[level - 1];
+ auto& toUpperOrients = mToUpperOrients[level - 1];
+ for (int i = 0; i < toUpper.size(); ++i) {
+ if (toUpper[i] >= 0) {
+ int orient = (4 - toUpperOrients[i]) % 4;
+ nEdgeDiff[i] = rshift90(EdgeDiff[toUpper[i]], orient);
+ } else {
+ nEdgeDiff[i] = Vector2i(0, 0);
+ }
+ }
+ for (int i = 0; i < toUpperFace.size(); ++i) {
+ if (toUpperFace[i] == -1) continue;
+ Vector3i eid_orient = FQ[toUpperFace[i]];
+ for (int j = 0; j < 3; ++j) {
+ nFQ[i][j] = (eid_orient[j] + toUpperOrients[F2E[i][j]]) % 4;
+ }
+ }
+ }
+}
+
+void Hierarchy::clearConstraints() {
+ int levels = mV.size();
+ if (levels == 0) return;
+ for (int i = 0; i < levels; ++i) {
+ int size = mV[i].cols();
+ mCQ[i].resize(3, size);
+ mCO[i].resize(3, size);
+ mCQw[i].resize(size);
+ mCOw[i].resize(size);
+ mCQw[i].setZero();
+ mCOw[i].setZero();
+ }
+}
+
+void Hierarchy::propagateConstraints() {
+ int levels = mV.size();
+ if (levels == 0) return;
+
+ for (int l = 0; l < levels - 1; ++l) {
+ auto& N = mN[l];
+ auto& N_next = mN[l + 1];
+ auto& V = mV[l];
+ auto& V_next = mV[l + 1];
+ auto& CQ = mCQ[l];
+ auto& CQ_next = mCQ[l + 1];
+ auto& CQw = mCQw[l];
+ auto& CQw_next = mCQw[l + 1];
+ auto& CO = mCO[l];
+ auto& CO_next = mCO[l + 1];
+ auto& COw = mCOw[l];
+ auto& COw_next = mCOw[l + 1];
+ auto& toUpper = mToUpper[l];
+ // FIXME
+ // MatrixXd& S = mS[l];
+
+ for (uint32_t i = 0; i != mV[l + 1].cols(); ++i) {
+ Vector2i upper = toUpper.col(i);
+ Vector3d cq = Vector3d::Zero(), co = Vector3d::Zero();
+ float cqw = 0.0f, cow = 0.0f;
+
+ bool has_cq0 = CQw[upper[0]] != 0;
+ bool has_cq1 = upper[1] != -1 && CQw[upper[1]] != 0;
+ bool has_co0 = COw[upper[0]] != 0;
+ bool has_co1 = upper[1] != -1 && COw[upper[1]] != 0;
+
+ if (has_cq0 && !has_cq1) {
+ cq = CQ.col(upper[0]);
+ cqw = CQw[upper[0]];
+ } else if (has_cq1 && !has_cq0) {
+ cq = CQ.col(upper[1]);
+ cqw = CQw[upper[1]];
+ } else if (has_cq1 && has_cq0) {
+ Vector3d q_i = CQ.col(upper[0]);
+ Vector3d n_i = CQ.col(upper[0]);
+ Vector3d q_j = CQ.col(upper[1]);
+ Vector3d n_j = CQ.col(upper[1]);
+ auto result = compat_orientation_extrinsic_4(q_i, n_i, q_j, n_j);
+ cq = result.first * CQw[upper[0]] + result.second * CQw[upper[1]];
+ cqw = (CQw[upper[0]] + CQw[upper[1]]);
+ }
+ if (cq != Vector3d::Zero()) {
+ Vector3d n = N_next.col(i);
+ cq -= n.dot(cq) * n;
+ if (cq.squaredNorm() > RCPOVERFLOW) cq.normalize();
+ }
+
+ if (has_co0 && !has_co1) {
+ co = CO.col(upper[0]);
+ cow = COw[upper[0]];
+ } else if (has_co1 && !has_co0) {
+ co = CO.col(upper[1]);
+ cow = COw[upper[1]];
+ } else if (has_co1 && has_co0) {
+ double scale_x = mScale;
+ double scale_y = mScale;
+ if (with_scale) {
+ // FIXME
+ // scale_x *= S(0, i);
+ // scale_y *= S(1, i);
+ }
+ double inv_scale_x = 1.0f / scale_x;
+ double inv_scale_y = 1.0f / scale_y;
+
+ double scale_x_1 = mScale;
+ double scale_y_1 = mScale;
+ if (with_scale) {
+ // FIXME
+ // scale_x_1 *= S(0, j);
+ // scale_y_1 *= S(1, j);
+ }
+ double inv_scale_x_1 = 1.0f / scale_x_1;
+ double inv_scale_y_1 = 1.0f / scale_y_1;
+ auto result = compat_position_extrinsic_4(
+ V.col(upper[0]), N.col(upper[0]), CQ.col(upper[0]), CO.col(upper[0]),
+ V.col(upper[1]), N.col(upper[1]), CQ.col(upper[1]), CO.col(upper[1]), scale_x,
+ scale_y, inv_scale_x, inv_scale_y, scale_x_1, scale_y_1, inv_scale_x_1,
+ inv_scale_y_1);
+ cow = COw[upper[0]] + COw[upper[1]];
+ co = (result.first * COw[upper[0]] + result.second * COw[upper[1]]) / cow;
+ }
+ if (co != Vector3d::Zero()) {
+ Vector3d n = N_next.col(i), v = V_next.col(i);
+ co -= n.dot(cq - v) * n;
+ }
+#if 0
+ cqw *= 0.5f;
+ cow *= 0.5f;
+#else
+ if (cqw > 0) cqw = 1;
+ if (cow > 0) cow = 1;
+#endif
+
+ CQw_next[i] = cqw;
+ COw_next[i] = cow;
+ CQ_next.col(i) = cq;
+ CO_next.col(i) = co;
+ }
+ }
+}
+#ifdef WITH_CUDA
+#include <cuda_runtime.h>
+
+void Hierarchy::CopyToDevice() {
+ if (cudaAdj.empty()) {
+ cudaAdj.resize(mAdj.size());
+ cudaAdjOffset.resize(mAdj.size());
+ for (int i = 0; i < mAdj.size(); ++i) {
+ std::vector<int> offset(mAdj[i].size() + 1, 0);
+ for (int j = 0; j < mAdj[i].size(); ++j) {
+ offset[j + 1] = offset[j] + mAdj[i][j].size();
+ }
+ cudaMalloc(&cudaAdjOffset[i], sizeof(int) * (mAdj[i].size() + 1));
+ cudaMemcpy(cudaAdjOffset[i], offset.data(), sizeof(int) * (mAdj[i].size() + 1),
+ cudaMemcpyHostToDevice);
+ // cudaAdjOffset[i] = (int*)malloc(sizeof(int) * (mAdj[i].size() + 1));
+ // memcpy(cudaAdjOffset[i], offset.data(), sizeof(int) * (mAdj[i].size() +
+ // 1));
+
+ cudaMalloc(&cudaAdj[i], sizeof(Link) * offset.back());
+ // cudaAdj[i] = (Link*)malloc(sizeof(Link) * offset.back());
+ std::vector<Link> plainlink(offset.back());
+ for (int j = 0; j < mAdj[i].size(); ++j) {
+ memcpy(plainlink.data() + offset[j], mAdj[i][j].data(),
+ mAdj[i][j].size() * sizeof(Link));
+ }
+ cudaMemcpy(cudaAdj[i], plainlink.data(), plainlink.size() * sizeof(Link),
+ cudaMemcpyHostToDevice);
+ }
+ }
+
+ if (cudaN.empty()) {
+ cudaN.resize(mN.size());
+ for (int i = 0; i < mN.size(); ++i) {
+ cudaMalloc(&cudaN[i], sizeof(glm::dvec3) * mN[i].cols());
+ // cudaN[i] = (glm::dvec3*)malloc(sizeof(glm::dvec3) * mN[i].cols());
+ }
+ }
+ for (int i = 0; i < mN.size(); ++i) {
+ cudaMemcpy(cudaN[i], mN[i].data(), sizeof(glm::dvec3) * mN[i].cols(),
+ cudaMemcpyHostToDevice);
+ // memcpy(cudaN[i], mN[i].data(), sizeof(glm::dvec3) * mN[i].cols());
+ }
+
+ if (cudaV.empty()) {
+ cudaV.resize(mV.size());
+ for (int i = 0; i < mV.size(); ++i) {
+ cudaMalloc(&cudaV[i], sizeof(glm::dvec3) * mV[i].cols());
+ // cudaV[i] = (glm::dvec3*)malloc(sizeof(glm::dvec3) * mV[i].cols());
+ }
+ }
+ for (int i = 0; i < mV.size(); ++i) {
+ cudaMemcpy(cudaV[i], mV[i].data(), sizeof(glm::dvec3) * mV[i].cols(),
+ cudaMemcpyHostToDevice);
+ // memcpy(cudaV[i], mV[i].data(), sizeof(glm::dvec3) * mV[i].cols());
+ }
+
+ if (cudaQ.empty()) {
+ cudaQ.resize(mQ.size());
+ for (int i = 0; i < mQ.size(); ++i) {
+ cudaMalloc(&cudaQ[i], sizeof(glm::dvec3) * mQ[i].cols());
+ // cudaQ[i] = (glm::dvec3*)malloc(sizeof(glm::dvec3) * mQ[i].cols());
+ }
+ }
+ for (int i = 0; i < mQ.size(); ++i) {
+ cudaMemcpy(cudaQ[i], mQ[i].data(), sizeof(glm::dvec3) * mQ[i].cols(),
+ cudaMemcpyHostToDevice);
+ // memcpy(cudaQ[i], mQ[i].data(), sizeof(glm::dvec3) * mQ[i].cols());
+ }
+ if (cudaO.empty()) {
+ cudaO.resize(mO.size());
+ for (int i = 0; i < mO.size(); ++i) {
+ cudaMalloc(&cudaO[i], sizeof(glm::dvec3) * mO[i].cols());
+ // cudaO[i] = (glm::dvec3*)malloc(sizeof(glm::dvec3) * mO[i].cols());
+ }
+ }
+ for (int i = 0; i < mO.size(); ++i) {
+ cudaMemcpy(cudaO[i], mO[i].data(), sizeof(glm::dvec3) * mO[i].cols(),
+ cudaMemcpyHostToDevice);
+ // memcpy(cudaO[i], mO[i].data(), sizeof(glm::dvec3) * mO[i].cols());
+ }
+ if (cudaPhases.empty()) {
+ cudaPhases.resize(mPhases.size());
+ for (int i = 0; i < mPhases.size(); ++i) {
+ cudaPhases[i].resize(mPhases[i].size());
+ for (int j = 0; j < mPhases[i].size(); ++j) {
+ cudaMalloc(&cudaPhases[i][j], sizeof(int) * mPhases[i][j].size());
+ // cudaPhases[i][j] = (int*)malloc(sizeof(int) *
+ // mPhases[i][j].size());
+ }
+ }
+ }
+ for (int i = 0; i < mPhases.size(); ++i) {
+ for (int j = 0; j < mPhases[i].size(); ++j) {
+ cudaMemcpy(cudaPhases[i][j], mPhases[i][j].data(), sizeof(int) * mPhases[i][j].size(),
+ cudaMemcpyHostToDevice);
+ // memcpy(cudaPhases[i][j], mPhases[i][j].data(), sizeof(int) *
+ // mPhases[i][j].size());
+ }
+ }
+ if (cudaToUpper.empty()) {
+ cudaToUpper.resize(mToUpper.size());
+ for (int i = 0; i < mToUpper.size(); ++i) {
+ cudaMalloc(&cudaToUpper[i], mToUpper[i].cols() * sizeof(glm::ivec2));
+ // cudaToUpper[i] = (glm::ivec2*)malloc(mToUpper[i].cols() *
+ // sizeof(glm::ivec2));
+ }
+ }
+ for (int i = 0; i < mToUpper.size(); ++i) {
+ cudaMemcpy(cudaToUpper[i], mToUpper[i].data(), sizeof(glm::ivec2) * mToUpper[i].cols(),
+ cudaMemcpyHostToDevice);
+ // memcpy(cudaToUpper[i], mToUpper[i].data(), sizeof(glm::ivec2) *
+ // mToUpper[i].cols());
+ }
+ cudaDeviceSynchronize();
+}
+
+void Hierarchy::CopyToHost() {}
+
+#endif
+
+} // namespace qflow
diff --git a/extern/quadriflow/src/hierarchy.hpp b/extern/quadriflow/src/hierarchy.hpp
new file mode 100644
index 00000000000..8403038de4f
--- /dev/null
+++ b/extern/quadriflow/src/hierarchy.hpp
@@ -0,0 +1,99 @@
+#ifndef HIERARCHY_H_
+#define HIERARCHY_H_
+
+#ifdef WITH_CUDA
+# include <glm/glm.hpp>
+#endif
+
+#include <map>
+#include <vector>
+#include "adjacent-matrix.hpp"
+#include "config.hpp"
+#include "serialize.hpp"
+#define RCPOVERFLOW 2.93873587705571876e-39f
+
+using namespace Eigen;
+
+namespace qflow {
+
+class Hierarchy {
+ public:
+ Hierarchy();
+ void Initialize(double scale, int with_scale = 0);
+ void DownsampleGraph(const AdjacentMatrix adj, const MatrixXd& V, const MatrixXd& N,
+ const VectorXd& A, MatrixXd& V_p, MatrixXd& N_p, VectorXd& A_p,
+ MatrixXi& to_upper, VectorXi& to_lower, AdjacentMatrix& adj_p);
+ void generate_graph_coloring_deterministic(const AdjacentMatrix& adj, int size,
+ std::vector<std::vector<int>>& phases);
+ void FixFlip();
+ int FixFlipSat(int depth, int threshold = 0);
+ void PushDownwardFlip(int depth);
+ void PropagateEdge();
+ void DownsampleEdgeGraph(std::vector<Vector3i>& FQ, std::vector<Vector3i>& F2E,
+ std::vector<Vector2i>& edge_diff,
+ std::vector<int>& allow_changes, int level);
+ void UpdateGraphValue(std::vector<Vector3i>& FQ, std::vector<Vector3i>& F2E,
+ std::vector<Vector2i>& edge_diff);
+
+ enum { MAX_DEPTH = 25 };
+
+ void SaveToFile(FILE* fp);
+ void LoadFromFile(FILE* fp);
+
+ void clearConstraints();
+ void propagateConstraints();
+
+ double mScale;
+ int rng_seed;
+
+ MatrixXi mF; // mF(i, j) i \in [0, 3) ith index in face j
+ VectorXi mE2E; // inverse edge
+ std::vector<AdjacentMatrix> mAdj;
+ std::vector<MatrixXd> mV;
+ std::vector<MatrixXd> mN;
+ std::vector<VectorXd> mA;
+ std::vector<std::vector<std::vector<int>>> mPhases;
+ // parameters
+ std::vector<MatrixXd> mQ;
+ std::vector<MatrixXd> mO;
+ std::vector<VectorXi> mToLower;
+ std::vector<MatrixXi> mToUpper; // mToUpper[h](i, j) \in V; i \in [0, 2); j \in V
+ std::vector<MatrixXd> mS;
+ std::vector<MatrixXd> mK;
+
+ // constraints
+ std::vector<MatrixXd> mCQ;
+ std::vector<MatrixXd> mCO;
+ std::vector<VectorXd> mCQw;
+ std::vector<VectorXd> mCOw;
+
+ int with_scale;
+
+ // upper: fine to coarse
+ std::vector<std::vector<int>> mToUpperFaces; // face correspondance
+ std::vector<std::vector<int>> mSing;
+ std::vector<std::vector<int>> mToUpperEdges; // edge correspondance
+ std::vector<std::vector<int>> mToUpperOrients; // rotation of edges from fine to coarse
+ std::vector<std::vector<Vector3i>> mFQ; // face_edgeOrients
+ std::vector<std::vector<Vector3i>> mF2E; // face_edgeIds
+ std::vector<std::vector<Vector2i>> mE2F; // undirect edges to face ID
+ std::vector<std::vector<int> > mAllowChanges;
+ std::vector<std::vector<Vector2i>> mEdgeDiff; // face_edgeDiff
+
+#ifdef WITH_CUDA
+ std::vector<Link*> cudaAdj;
+ std::vector<int*> cudaAdjOffset;
+ std::vector<glm::dvec3*> cudaN;
+ std::vector<glm::dvec3*> cudaV;
+ std::vector<glm::dvec3*> cudaQ;
+ std::vector<glm::dvec3*> cudaO;
+ std::vector<std::vector<int*>> cudaPhases;
+ std::vector<glm::ivec2*> cudaToUpper;
+ void CopyToDevice();
+ void CopyToHost();
+#endif
+};
+
+} // namespace qflow
+
+#endif
diff --git a/extern/quadriflow/src/loader.cpp b/extern/quadriflow/src/loader.cpp
new file mode 100644
index 00000000000..aa27066e6e4
--- /dev/null
+++ b/extern/quadriflow/src/loader.cpp
@@ -0,0 +1,159 @@
+//
+// loader.cpp
+// Loop
+//
+// Created by Jingwei on 10/22/17.
+// Copyright © 2017 Jingwei. All rights reserved.
+//
+
+#include "loader.hpp"
+
+#include <fstream>
+#include <unordered_map>
+
+namespace qflow {
+
+inline std::vector<std::string> &str_tokenize(const std::string &s, char delim, std::vector<std::string> &elems, bool include_empty = false) {
+ std::stringstream ss(s);
+ std::string item;
+ while (std::getline(ss, item, delim))
+ if (!item.empty() || include_empty)
+ elems.push_back(item);
+ return elems;
+}
+
+inline std::vector<std::string> str_tokenize(const std::string &s, char delim, bool include_empty) {
+ std::vector<std::string> elems;
+ str_tokenize(s, delim, elems, include_empty);
+ return elems;
+}
+
+inline uint32_t str_to_uint32_t(const std::string &str) {
+ char *end_ptr = nullptr;
+ uint32_t result = (uint32_t)strtoul(str.c_str(), &end_ptr, 10);
+ if (*end_ptr != '\0')
+ throw std::runtime_error("Could not parse unsigned integer \"" + str + "\"");
+ return result;
+}
+
+void load(const char* filename, MatrixXd& V, MatrixXi& F)
+{
+ /// Vertex indices used by the OBJ format
+ struct obj_vertex {
+ uint32_t p = (uint32_t)-1;
+ uint32_t n = (uint32_t)-1;
+ uint32_t uv = (uint32_t)-1;
+
+ inline obj_vertex() { }
+
+ inline obj_vertex(const std::string &string) {
+ std::vector<std::string> tokens = str_tokenize(string, '/', true);
+
+ if (tokens.size() < 1 || tokens.size() > 3)
+ throw std::runtime_error("Invalid vertex data: \"" + string + "\"");
+
+ p = str_to_uint32_t(tokens[0]);
+
+#if 0
+ if (tokens.size() >= 2 && !tokens[1].empty())
+ uv = str_to_uint32_t(tokens[1]);
+
+ if (tokens.size() >= 3 && !tokens[2].empty())
+ n = str_to_uint32_t(tokens[2]);
+#endif
+ }
+
+ inline bool operator==(const obj_vertex &v) const {
+ return v.p == p && v.n == n && v.uv == uv;
+ }
+ };
+
+ /// Hash function for obj_vertex
+ struct obj_vertexHash : std::unary_function<obj_vertex, size_t> {
+ std::size_t operator()(const obj_vertex &v) const {
+ size_t hash = std::hash<uint32_t>()(v.p);
+ hash = hash * 37 + std::hash<uint32_t>()(v.uv);
+ hash = hash * 37 + std::hash<uint32_t>()(v.n);
+ return hash;
+ }
+ };
+
+ typedef std::unordered_map<obj_vertex, uint32_t, obj_vertexHash> VertexMap;
+
+ std::ifstream is(filename);
+
+ std::vector<Vector3d> positions;
+ //std::vector<Vector2d> texcoords;
+ //std::vector<Vector3d> normals;
+ std::vector<uint32_t> indices;
+ std::vector<obj_vertex> vertices;
+ VertexMap vertexMap;
+
+ std::string line_str;
+ while (std::getline(is, line_str)) {
+ std::istringstream line(line_str);
+
+ std::string prefix;
+ line >> prefix;
+
+ if (prefix == "v") {
+ Vector3d p;
+ line >> p.x() >> p.y() >> p.z();
+ positions.push_back(p);
+ }
+ else if (prefix == "vt") {
+ /*
+ Vector2d tc;
+ line >> tc.x() >> tc.y();
+ texcoords.push_back(tc);
+ */
+ }
+ else if (prefix == "vn") {
+ /*
+ Vector3d n;
+ line >> n.x() >> n.y() >> n.z();
+ normals.push_back(n);
+ */
+ }
+ else if (prefix == "f") {
+ std::string v1, v2, v3, v4;
+ line >> v1 >> v2 >> v3 >> v4;
+ obj_vertex tri[6];
+ int nVertices = 3;
+
+ tri[0] = obj_vertex(v1);
+ tri[1] = obj_vertex(v2);
+ tri[2] = obj_vertex(v3);
+
+ if (!v4.empty()) {
+ /* This is a quad, split into two triangles */
+ tri[3] = obj_vertex(v4);
+ tri[4] = tri[0];
+ tri[5] = tri[2];
+ nVertices = 6;
+ }
+ /* Convert to an indexed vertex list */
+ for (int i = 0; i<nVertices; ++i) {
+ const obj_vertex &v = tri[i];
+ VertexMap::const_iterator it = vertexMap.find(v);
+ if (it == vertexMap.end()) {
+ vertexMap[v] = (uint32_t)vertices.size();
+ indices.push_back((uint32_t)vertices.size());
+ vertices.push_back(v);
+ }
+ else {
+ indices.push_back(it->second);
+ }
+ }
+ }
+ }
+
+ F.resize(3, indices.size() / 3);
+ memcpy(F.data(), indices.data(), sizeof(uint32_t)*indices.size());
+
+ V.resize(3, vertices.size());
+ for (uint32_t i = 0; i<vertices.size(); ++i)
+ V.col(i) = positions.at(vertices[i].p - 1);
+}
+
+} // namespace qflow
diff --git a/extern/quadriflow/src/loader.hpp b/extern/quadriflow/src/loader.hpp
new file mode 100644
index 00000000000..33b5e55b5e5
--- /dev/null
+++ b/extern/quadriflow/src/loader.hpp
@@ -0,0 +1,15 @@
+#ifndef __LOADER_H
+#define __LOADER_H
+
+#include <Eigen/Core>
+#include <vector>
+
+namespace qflow {
+
+using namespace Eigen;
+
+void load(const char* filename, MatrixXd& V, MatrixXi& F);
+
+} // namespace qflow
+
+#endif
diff --git a/extern/quadriflow/src/localsat.cpp b/extern/quadriflow/src/localsat.cpp
new file mode 100644
index 00000000000..1ab665175da
--- /dev/null
+++ b/extern/quadriflow/src/localsat.cpp
@@ -0,0 +1,295 @@
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+#include "localsat.hpp"
+#include "config.hpp"
+#include "dedge.hpp"
+#include "field-math.hpp"
+
+#include <Eigen/Core>
+
+#include <deque>
+#include <memory>
+#include <utility>
+#include <vector>
+
+namespace qflow {
+
+const int max_depth = 0;
+
+using namespace Eigen;
+
+SolverStatus RunCNF(const std::string &fin_name, int n_variable, int timeout,
+ const std::vector<std::vector<int>> &sat_clause, std::vector<int> &value) {
+ int n_sat_variable = 3 * n_variable;
+ auto fout_name = fin_name + ".result.txt";
+
+ FILE *fout = fopen(fin_name.c_str(), "w");
+ fprintf(fout, "p cnf %d %d\n", n_sat_variable, (int)sat_clause.size());
+ for (auto &c : sat_clause) {
+ for (auto e : c) fprintf(fout, "%d ", e);
+ fputs("0\n", fout);
+ }
+ fclose(fout);
+
+ char cmd[100];
+ snprintf(cmd, 99, "rm %s > /dev/null 2>&1", fout_name.c_str());
+ system(cmd);
+ snprintf(cmd, 99, "timeout %d minisat %s %s > /dev/null 2>&1", timeout, fin_name.c_str(),
+ fout_name.c_str());
+ int exit_code = system(cmd);
+
+ FILE *fin = fopen(fout_name.c_str(), "r");
+ char buf[16] = {0};
+ fscanf(fin, "%15s", buf);
+ lprintf(" MiniSAT:");
+ if (strcmp(buf, "SAT") != 0) {
+ fclose(fin);
+
+ if (exit_code == 124) {
+ lprintf(" Timeout! ");
+ return SolverStatus::Timeout;
+ }
+ lprintf(" Unsatisfiable! ");
+ return SolverStatus::Unsat;
+ };
+
+ lprintf(" Satisfiable! ");
+ for (int i = 0; i < n_variable; ++i) {
+ int sign[3];
+ fscanf(fin, "%d %d %d", sign + 0, sign + 1, sign + 2);
+
+ int nvalue = -2;
+ for (int j = 0; j < 3; ++j) {
+ assert(abs(sign[j]) == 3 * i + j + 1);
+ if ((sign[j] > 0) == (value[i] != j - 1)) {
+ assert(nvalue == -2);
+ nvalue = j - 1;
+ }
+ }
+ value[i] = nvalue;
+ }
+ fclose(fin);
+
+ return SolverStatus::Sat;
+}
+
+SolverStatus SolveSatProblem(int n_variable, std::vector<int> &value,
+ const std::vector<bool> flexible, // NOQA
+ const std::vector<Vector3i> &variable_eq,
+ const std::vector<Vector3i> &constant_eq,
+ const std::vector<Vector4i> &variable_ge,
+ const std::vector<Vector2i> &constant_ge,
+ int timeout) {
+ for (int v : value) assert(-1 <= v && v <= +1);
+
+ auto VAR = [&](int i, int v) {
+ int index = 1 + 3 * i + v + 1;
+ // We initialize the SAT problem by setting all the variable to false.
+ // This is because minisat by default will try false first.
+ if (v == value[i]) index = -index;
+ return index;
+ };
+
+ int n_flexible = 0;
+ std::vector<std::vector<int>> sat_clause;
+ std::vector<bool> sat_ishard;
+
+ auto add_clause = [&](const std::vector<int> &clause, bool hard) {
+ sat_clause.push_back(clause);
+ sat_ishard.push_back(hard);
+ };
+
+ for (int i = 0; i < n_variable; ++i) {
+ add_clause({-VAR(i, -1), -VAR(i, 0)}, true);
+ add_clause({-VAR(i, +1), -VAR(i, 0)}, true);
+ add_clause({-VAR(i, -1), -VAR(i, +1)}, true);
+ add_clause({VAR(i, -1), VAR(i, 0), VAR(i, +1)}, true);
+ if (!flexible[i]) {
+ add_clause({VAR(i, value[i])}, true);
+ } else {
+ ++n_flexible;
+ }
+ }
+
+ for (int i = 0; i < (int)variable_eq.size(); ++i) {
+ auto &var = variable_eq[i];
+ auto &cst = constant_eq[i];
+ for (int v0 = -1; v0 <= 1; ++v0)
+ for (int v1 = -1; v1 <= 1; ++v1)
+ for (int v2 = -1; v2 <= 1; ++v2)
+ if (cst[0] * v0 + cst[1] * v1 + cst[2] * v2 != 0) {
+ add_clause({-VAR(var[0], v0), -VAR(var[1], v1), -VAR(var[2], v2)}, true);
+ }
+ }
+
+ for (int i = 0; i < (int)variable_ge.size(); ++i) {
+ auto &var = variable_ge[i];
+ auto &cst = constant_ge[i];
+ for (int v0 = -1; v0 <= 1; ++v0)
+ for (int v1 = -1; v1 <= 1; ++v1)
+ for (int v2 = -1; v2 <= 1; ++v2)
+ for (int v3 = -1; v3 <= 1; ++v3)
+ if (cst[0] * v0 * v1 - cst[1] * v2 * v3 < 0) {
+ add_clause({-VAR(var[0], v0), -VAR(var[1], v1), -VAR(var[2], v2),
+ -VAR(var[3], v3)},
+ false);
+ }
+ }
+
+ int nflip_before = 0, nflip_after = 0;
+ for (int i = 0; i < (int)variable_ge.size(); ++i) {
+ auto &var = variable_ge[i];
+ auto &cst = constant_ge[i];
+ if (value[var[0]] * value[var[1]] * cst[0] - value[var[2]] * value[var[3]] * cst[1] < 0)
+ nflip_before++;
+ }
+
+ lprintf(" [SAT] nvar: %6d nflip: %3d ", n_flexible * 2, nflip_before);
+ auto rcnf = RunCNF("test.out", n_variable, timeout, sat_clause, value);
+
+ for (int i = 0; i < (int)variable_eq.size(); ++i) {
+ auto &var = variable_eq[i];
+ auto &cst = constant_eq[i];
+ assert(cst[0] * value[var[0]] + cst[1] * value[var[1]] + cst[2] * value[var[2]] == 0);
+ }
+ for (int i = 0; i < (int)variable_ge.size(); ++i) {
+ auto &var = variable_ge[i];
+ auto &cst = constant_ge[i];
+ int area = value[var[0]] * value[var[1]] * cst[0] - value[var[2]] * value[var[3]] * cst[1];
+ if (area < 0) ++nflip_after;
+ }
+ lprintf("nflip: %3d\n", nflip_after);
+ return rcnf;
+}
+
+void ExportLocalSat(std::vector<Vector2i> &edge_diff, const std::vector<Vector3i> &face_edgeIds,
+ const std::vector<Vector3i> &face_edgeOrients, const MatrixXi &F,
+ const VectorXi &V2E, const VectorXi &E2E) {
+ int flip_count = 0;
+ int flip_count1 = 0;
+
+ std::vector<int> value(2 * edge_diff.size());
+ for (int i = 0; i < (int)edge_diff.size(); ++i) {
+ value[2 * i + 0] = edge_diff[i][0];
+ value[2 * i + 1] = edge_diff[i][1];
+ }
+
+ std::deque<std::pair<int, int>> Q;
+ std::vector<bool> mark_vertex(V2E.size(), false);
+
+ assert(F.cols() == (int)face_edgeIds.size());
+ std::vector<Vector3i> variable_eq(face_edgeIds.size() * 2);
+ std::vector<Vector3i> constant_eq(face_edgeIds.size() * 2);
+ std::vector<Vector4i> variable_ge(face_edgeIds.size());
+ std::vector<Vector2i> constant_ge(face_edgeIds.size());
+
+ VectorXd face_area(F.cols());
+
+ for (int i = 0; i < (int)face_edgeIds.size(); ++i) {
+ Vector2i diff[3];
+ Vector2i var[3];
+ Vector2i cst[3];
+ for (int j = 0; j < 3; ++j) {
+ int edgeid = face_edgeIds[i][j];
+ diff[j] = rshift90(edge_diff[edgeid], face_edgeOrients[i][j]);
+ var[j] = rshift90(Vector2i(edgeid * 2 + 1, edgeid * 2 + 2), face_edgeOrients[i][j]);
+ cst[j] = var[j].array().sign();
+ var[j] = var[j].array().abs() - 1;
+ }
+
+ assert(diff[0] + diff[1] + diff[2] == Vector2i::Zero());
+ variable_eq[2 * i + 0] = Vector3i(var[0][0], var[1][0], var[2][0]);
+ constant_eq[2 * i + 0] = Vector3i(cst[0][0], cst[1][0], cst[2][0]);
+ variable_eq[2 * i + 1] = Vector3i(var[0][1], var[1][1], var[2][1]);
+ constant_eq[2 * i + 1] = Vector3i(cst[0][1], cst[1][1], cst[2][1]);
+
+ face_area[i] = diff[0][0] * diff[1][1] - diff[0][1] * diff[1][0];
+ if (face_area[i] < 0) {
+ printf("[SAT] Face %d's area < 0\n", i);
+ for (int j = 0; j < 3; ++j) {
+ int v = F(j, i);
+ if (mark_vertex[v]) continue;
+ Q.push_back(std::make_pair(v, 0));
+ mark_vertex[v] = true;
+ }
+ flip_count += 1;
+ }
+ variable_ge[i] = Vector4i(var[0][0], var[1][1], var[0][1], var[1][0]);
+ constant_ge[i] = Vector2i(cst[0][0] * cst[1][1], cst[0][1] * cst[1][0]);
+ }
+ for (int i = 0; i < (int)variable_eq.size(); ++i) {
+ auto &var = variable_eq[i];
+ auto &cst = constant_eq[i];
+ assert((0 <= var.array()).all());
+ assert((var.array() < value.size()).all());
+ assert(cst[0] * value[var[0]] + cst[1] * value[var[1]] + cst[2] * value[var[2]] == 0);
+ }
+
+ for (int i = 0; i < (int)variable_ge.size(); ++i) {
+ auto &var = variable_ge[i];
+ auto &cst = constant_ge[i];
+ assert((0 <= variable_ge[i].array()).all());
+ assert((variable_ge[i].array() < value.size()).all());
+ if (value[var[0]] * value[var[1]] * cst[0] - value[var[2]] * value[var[3]] * cst[1] < 0) {
+ assert(face_area[i] < 0);
+ flip_count1++;
+ }
+ }
+ assert(flip_count == flip_count1);
+
+ // BFS
+ printf("[SAT] Start BFS: Q.size() = %d\n", (int)Q.size());
+
+ int mark_count = Q.size();
+ while (!Q.empty()) {
+ int vertex = Q.front().first;
+ int depth = Q.front().second;
+ Q.pop_front();
+ mark_count++;
+ int e0 = V2E(vertex);
+
+ for (int e = e0;;) {
+ int v = F((e + 1) % 3, e / 3);
+ if (!mark_vertex[v]) {
+ int undirected_edge_id = face_edgeIds[e / 3][e % 3];
+ int undirected_edge_length = edge_diff[undirected_edge_id].array().abs().sum() > 0;
+ int ndepth = depth + undirected_edge_length;
+ if (ndepth <= max_depth) {
+ if (undirected_edge_length == 0)
+ Q.push_front(std::make_pair(v, ndepth));
+ else
+ Q.push_back(std::make_pair(v, ndepth));
+ mark_vertex[v] = true;
+ }
+ }
+ e = dedge_next_3(E2E(e));
+ if (e == e0) break;
+ }
+ }
+ printf("[SAT] Mark %d vertices out of %d\n", mark_count, (int)V2E.size());
+
+ std::vector<bool> flexible(value.size(), false);
+ for (int i = 0; i < (int)face_edgeIds.size(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ int edgeid = face_edgeIds[i][j];
+ if (mark_vertex[F(j, i)] || mark_vertex[F((j + 1) % 3, i)]) {
+ flexible[edgeid * 2 + 0] = true;
+ flexible[edgeid * 2 + 1] = true;
+ } else {
+ assert(face_area[i] >= 0);
+ }
+ }
+ }
+
+ SolveSatProblem(value.size(), value, flexible, variable_eq, constant_eq, variable_ge,
+ constant_ge);
+
+ for (int i = 0; i < edge_diff.size(); ++i) {
+ edge_diff[i][0] = value[2 * i + 0];
+ edge_diff[i][1] = value[2 * i + 1];
+ }
+}
+
+} // namespace qflow
diff --git a/extern/quadriflow/src/localsat.hpp b/extern/quadriflow/src/localsat.hpp
new file mode 100644
index 00000000000..af952320ebb
--- /dev/null
+++ b/extern/quadriflow/src/localsat.hpp
@@ -0,0 +1,31 @@
+#ifndef __LOCAL_SAT_H
+#define __LOCAL_SAT_H
+
+#include <Eigen/Core>
+#include <vector>
+
+namespace qflow {
+
+using namespace Eigen;
+
+enum class SolverStatus {
+ Sat,
+ Unsat,
+ Timeout,
+};
+
+SolverStatus SolveSatProblem(int n_variable, std::vector<int> &value,
+ const std::vector<bool> flexible, // NOQA
+ const std::vector<Vector3i> &variable_eq,
+ const std::vector<Vector3i> &constant_eq,
+ const std::vector<Vector4i> &variable_ge,
+ const std::vector<Vector2i> &constant_ge,
+ int timeout = 8);
+
+void ExportLocalSat(std::vector<Vector2i> &edge_diff, const std::vector<Vector3i> &face_edgeIds,
+ const std::vector<Vector3i> &face_edgeOrients, const MatrixXi &F,
+ const VectorXi &V2E, const VectorXi &E2E);
+
+} // namespace qflow
+
+#endif
diff --git a/extern/quadriflow/src/main.cpp b/extern/quadriflow/src/main.cpp
new file mode 100644
index 00000000000..18bc4063c42
--- /dev/null
+++ b/extern/quadriflow/src/main.cpp
@@ -0,0 +1,127 @@
+#include "config.hpp"
+#include "field-math.hpp"
+#include "optimizer.hpp"
+#include "parametrizer.hpp"
+#include <stdlib.h>
+
+#ifdef WITH_CUDA
+#include <cuda_runtime.h>
+#endif
+
+using namespace qflow;
+
+Parametrizer field;
+
+int main(int argc, char** argv) {
+ setbuf(stdout, NULL);
+
+#ifdef WITH_CUDA
+ cudaFree(0);
+#endif
+ int t1, t2;
+ std::string input_obj, output_obj;
+ int faces = -1;
+ for (int i = 0; i < argc; ++i) {
+ if (strcmp(argv[i], "-f") == 0) {
+ sscanf(argv[i + 1], "%d", &faces);
+ } else if (strcmp(argv[i], "-i") == 0) {
+ input_obj = argv[i + 1];
+ } else if (strcmp(argv[i], "-o") == 0) {
+ output_obj = argv[i + 1];
+ } else if (strcmp(argv[i], "-sharp") == 0) {
+ field.flag_preserve_sharp = 1;
+ } else if (strcmp(argv[i], "-boundary") == 0) {
+ field.flag_preserve_boundary = 1;
+ } else if (strcmp(argv[i], "-adaptive") == 0) {
+ field.flag_adaptive_scale = 1;
+ } else if (strcmp(argv[i], "-mcf") == 0) {
+ field.flag_minimum_cost_flow = 1;
+ } else if (strcmp(argv[i], "-sat") == 0) {
+ field.flag_aggresive_sat = 1;
+ } else if (strcmp(argv[i], "-seed") == 0) {
+ field.hierarchy.rng_seed = atoi(argv[i + 1]);
+ }
+ }
+ printf("%d %s %s\n", faces, input_obj.c_str(), output_obj.c_str());
+ if (input_obj.size() >= 1) {
+ field.Load(input_obj.c_str());
+ } else {
+ assert(0);
+ // field.Load((std::string(DATA_PATH) + "/fertility.obj").c_str());
+ }
+
+ printf("Initialize...\n");
+ t1 = GetCurrentTime64();
+ field.Initialize(faces);
+ t2 = GetCurrentTime64();
+ printf("Use %lf seconds\n", (t2 - t1) * 1e-3);
+
+ if (field.flag_preserve_boundary) {
+ printf("Add boundary constrains...\n");
+ Hierarchy& mRes = field.hierarchy;
+ mRes.clearConstraints();
+ for (uint32_t i = 0; i < 3 * mRes.mF.cols(); ++i) {
+ if (mRes.mE2E[i] == -1) {
+ uint32_t i0 = mRes.mF(i % 3, i / 3);
+ uint32_t i1 = mRes.mF((i + 1) % 3, i / 3);
+ Vector3d p0 = mRes.mV[0].col(i0), p1 = mRes.mV[0].col(i1);
+ Vector3d edge = p1 - p0;
+ if (edge.squaredNorm() > 0) {
+ edge.normalize();
+ mRes.mCO[0].col(i0) = p0;
+ mRes.mCO[0].col(i1) = p1;
+ mRes.mCQ[0].col(i0) = mRes.mCQ[0].col(i1) = edge;
+ mRes.mCQw[0][i0] = mRes.mCQw[0][i1] = mRes.mCOw[0][i0] = mRes.mCOw[0][i1] =
+ 1.0;
+ }
+ }
+ }
+ mRes.propagateConstraints();
+ }
+
+ printf("Solve Orientation Field...\n");
+ t1 = GetCurrentTime64();
+
+ Optimizer::optimize_orientations(field.hierarchy);
+ field.ComputeOrientationSingularities();
+ t2 = GetCurrentTime64();
+ printf("Use %lf seconds\n", (t2 - t1) * 1e-3);
+
+ if (field.flag_adaptive_scale == 1) {
+ printf("Estimate Slop...\n");
+ t1 = GetCurrentTime64();
+ field.EstimateSlope();
+ t2 = GetCurrentTime64();
+ printf("Use %lf seconds\n", (t2 - t1) * 1e-3);
+ }
+ printf("Solve for scale...\n");
+ t1 = GetCurrentTime64();
+ Optimizer::optimize_scale(field.hierarchy, field.rho, field.flag_adaptive_scale);
+ field.flag_adaptive_scale = 1;
+ t2 = GetCurrentTime64();
+ printf("Use %lf seconds\n", (t2 - t1) * 1e-3);
+
+ printf("Solve for position field...\n");
+ t1 = GetCurrentTime64();
+ Optimizer::optimize_positions(field.hierarchy, field.flag_adaptive_scale);
+
+ field.ComputePositionSingularities();
+ t2 = GetCurrentTime64();
+ printf("Use %lf seconds\n", (t2 - t1) * 1e-3);
+ t1 = GetCurrentTime64();
+ printf("Solve index map...\n");
+ field.ComputeIndexMap();
+ t2 = GetCurrentTime64();
+ printf("Indexmap Use %lf seconds\n", (t2 - t1) * 1e-3);
+ printf("Writing the file...\n");
+
+ if (output_obj.size() < 1) {
+ assert(0);
+ // field.OutputMesh((std::string(DATA_PATH) + "/result.obj").c_str());
+ } else {
+ field.OutputMesh(output_obj.c_str());
+ }
+ printf("finish...\n");
+ // field.LoopFace(2);
+ return 0;
+}
diff --git a/extern/quadriflow/src/merge-vertex.cpp b/extern/quadriflow/src/merge-vertex.cpp
new file mode 100644
index 00000000000..4c7b0a2bb9b
--- /dev/null
+++ b/extern/quadriflow/src/merge-vertex.cpp
@@ -0,0 +1,44 @@
+#include "merge-vertex.hpp"
+
+#include "compare-key.hpp"
+
+#include <map>
+#include <vector>
+
+namespace qflow {
+
+void merge_close(MatrixXd& V, MatrixXi& F, double threshold)
+{
+ std::map<Key3f, int> vid_maps;
+ std::vector<int> vid_compress(V.cols());
+ for (int i = 0; i < V.cols(); ++i) {
+ Key3f key(V(0, i), V(1, i), V(2, i), threshold);
+ if (vid_maps.count(key)) {
+ vid_compress[i] = vid_maps[key];
+ }
+ else {
+ V.col(vid_maps.size()) = V.col(i);
+ vid_compress[i] = vid_maps.size();
+ vid_maps[key] = vid_compress[i];
+ }
+ }
+ printf("Compress Vertex from %d to %d...\n", (int)V.cols(), (int)vid_maps.size());
+ MatrixXd newV(3, vid_maps.size());
+ memcpy(newV.data(), V.data(), sizeof(double) * 3 * vid_maps.size());
+ V = std::move(newV);
+ int f_num = 0;
+ for (int i = 0; i < F.cols(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ F(j, f_num) = vid_compress[F(j, i)];
+ }
+ if (F(0, f_num) != F(1, f_num) && F(0, f_num) != F(2, f_num) && F(1, f_num) != F(2, f_num)) {
+ f_num++;
+ }
+ }
+ printf("Compress Face from %d to %d...\n", (int)F.cols(), f_num);
+ MatrixXi newF(3, f_num);
+ memcpy(newF.data(), F.data(), sizeof(int) * 3 * f_num);
+ F = std::move(newF);
+}
+
+} // namespace qflow
diff --git a/extern/quadriflow/src/merge-vertex.hpp b/extern/quadriflow/src/merge-vertex.hpp
new file mode 100644
index 00000000000..8bcea3d8e4d
--- /dev/null
+++ b/extern/quadriflow/src/merge-vertex.hpp
@@ -0,0 +1,14 @@
+#ifndef MERGE_VERTEX_H_
+#define MERGE_VERTEX_H_
+
+#include <Eigen/Core>
+
+namespace qflow {
+
+using namespace Eigen;
+
+void merge_close(MatrixXd& V, MatrixXi& F, double threshold);
+
+} // namespace qflow
+
+#endif \ No newline at end of file
diff --git a/extern/quadriflow/src/optimizer.cpp b/extern/quadriflow/src/optimizer.cpp
new file mode 100644
index 00000000000..1c59ad0f70c
--- /dev/null
+++ b/extern/quadriflow/src/optimizer.cpp
@@ -0,0 +1,1419 @@
+#include "optimizer.hpp"
+
+#include <Eigen/Sparse>
+#include <cmath>
+#include <fstream>
+#include <iostream>
+#include <memory>
+#include <queue>
+#include <unordered_map>
+
+#include "config.hpp"
+#include "field-math.hpp"
+#include "flow.hpp"
+#include "parametrizer.hpp"
+
+namespace qflow {
+
+#ifdef WITH_CUDA
+# include <cuda_runtime.h>
+#endif
+
+#ifndef EIGEN_MPL2_ONLY
+template<class T>
+using LinearSolver = Eigen::SimplicialLLT<T>;
+#else
+template<class T>
+using LinearSolver = Eigen::SparseLU<T>;
+#endif
+
+Optimizer::Optimizer() {}
+
+void Optimizer::optimize_orientations(Hierarchy& mRes) {
+#ifdef WITH_CUDA
+ optimize_orientations_cuda(mRes);
+ printf("%s\n", cudaGetErrorString(cudaDeviceSynchronize()));
+ cudaMemcpy(mRes.mQ[0].data(), mRes.cudaQ[0], sizeof(glm::dvec3) * mRes.mQ[0].cols(),
+ cudaMemcpyDeviceToHost);
+
+#else
+
+ int levelIterations = 6;
+ for (int level = mRes.mN.size() - 1; level >= 0; --level) {
+ AdjacentMatrix& adj = mRes.mAdj[level];
+ const MatrixXd& N = mRes.mN[level];
+ const MatrixXd& CQ = mRes.mCQ[level];
+ const VectorXd& CQw = mRes.mCQw[level];
+ MatrixXd& Q = mRes.mQ[level];
+ auto& phases = mRes.mPhases[level];
+ for (int iter = 0; iter < levelIterations; ++iter) {
+ for (int phase = 0; phase < phases.size(); ++phase) {
+ auto& p = phases[phase];
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int pi = 0; pi < p.size(); ++pi) {
+ int i = p[pi];
+ const Vector3d n_i = N.col(i);
+ double weight_sum = 0.0f;
+ Vector3d sum = Q.col(i);
+ for (auto& link : adj[i]) {
+ const int j = link.id;
+ const double weight = link.weight;
+ if (weight == 0) continue;
+ const Vector3d n_j = N.col(j);
+ Vector3d q_j = Q.col(j);
+ std::pair<Vector3d, Vector3d> value =
+ compat_orientation_extrinsic_4(sum, n_i, q_j, n_j);
+ sum = value.first * weight_sum + value.second * weight;
+ sum -= n_i * n_i.dot(sum);
+ weight_sum += weight;
+ double norm = sum.norm();
+ if (norm > RCPOVERFLOW) sum /= norm;
+ }
+
+ if (CQw.size() > 0) {
+ float cw = CQw[i];
+ if (cw != 0) {
+ std::pair<Vector3d, Vector3d> value =
+ compat_orientation_extrinsic_4(sum, n_i, CQ.col(i), n_i);
+ sum = value.first * (1 - cw) + value.second * cw;
+ sum -= n_i * n_i.dot(sum);
+
+ float norm = sum.norm();
+ if (norm > RCPOVERFLOW) sum /= norm;
+ }
+ }
+
+ if (weight_sum > 0) {
+ Q.col(i) = sum;
+ }
+ }
+ }
+ }
+ if (level > 0) {
+ const MatrixXd& srcField = mRes.mQ[level];
+ const MatrixXi& toUpper = mRes.mToUpper[level - 1];
+ MatrixXd& destField = mRes.mQ[level - 1];
+ const MatrixXd& N = mRes.mN[level - 1];
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int i = 0; i < srcField.cols(); ++i) {
+ for (int k = 0; k < 2; ++k) {
+ int dest = toUpper(k, i);
+ if (dest == -1) continue;
+ Vector3d q = srcField.col(i), n = N.col(dest);
+ destField.col(dest) = q - n * n.dot(q);
+ }
+ }
+ }
+ }
+
+ for (int l = 0; l < mRes.mN.size() - 1; ++l) {
+ const MatrixXd& N = mRes.mN[l];
+ const MatrixXd& N_next = mRes.mN[l + 1];
+ const MatrixXd& Q = mRes.mQ[l];
+ MatrixXd& Q_next = mRes.mQ[l + 1];
+ auto& toUpper = mRes.mToUpper[l];
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int i = 0; i < toUpper.cols(); ++i) {
+ Vector2i upper = toUpper.col(i);
+ Vector3d q0 = Q.col(upper[0]);
+ Vector3d n0 = N.col(upper[0]);
+ Vector3d q;
+
+ if (upper[1] != -1) {
+ Vector3d q1 = Q.col(upper[1]);
+ Vector3d n1 = N.col(upper[1]);
+ auto result = compat_orientation_extrinsic_4(q0, n0, q1, n1);
+ q = result.first + result.second;
+ } else {
+ q = q0;
+ }
+ Vector3d n = N_next.col(i);
+ q -= n.dot(q) * n;
+ if (q.squaredNorm() > RCPOVERFLOW) q.normalize();
+
+ Q_next.col(i) = q;
+ }
+ }
+
+#endif
+}
+
+void Optimizer::optimize_scale(Hierarchy& mRes, VectorXd& rho, int adaptive) {
+ const MatrixXd& N = mRes.mN[0];
+ MatrixXd& Q = mRes.mQ[0];
+ MatrixXd& V = mRes.mV[0];
+ MatrixXd& S = mRes.mS[0];
+ MatrixXd& K = mRes.mK[0];
+ MatrixXi& F = mRes.mF;
+
+ if (adaptive) {
+ std::vector<Eigen::Triplet<double>> lhsTriplets;
+
+ lhsTriplets.reserve(F.cols() * 6);
+ for (int i = 0; i < V.cols(); ++i) {
+ for (int j = 0; j < 2; ++j) {
+ S(j, i) = 1.0;
+ double sc1 = std::max(0.75 * S(j, i), rho[i] * 1.0 / mRes.mScale);
+ S(j, i) = std::min(S(j, i), sc1);
+ }
+ }
+
+ std::vector<std::map<int, double>> entries(V.cols() * 2);
+ double lambda = 1;
+ for (int i = 0; i < entries.size(); ++i) {
+ entries[i][i] = lambda;
+ }
+ for (int i = 0; i < F.cols(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ int v1 = F(j, i);
+ int v2 = F((j + 1) % 3, i);
+ Vector3d diff = V.col(v2) - V.col(v1);
+ Vector3d q_1 = Q.col(v1);
+ Vector3d q_2 = Q.col(v2);
+ Vector3d n_1 = N.col(v1);
+ Vector3d n_2 = N.col(v2);
+ Vector3d q_1_y = n_1.cross(q_1);
+ auto index = compat_orientation_extrinsic_index_4(q_1, n_1, q_2, n_2);
+ int v1_x = v1 * 2, v1_y = v1 * 2 + 1, v2_x = v2 * 2, v2_y = v2 * 2 + 1;
+
+ double dx = diff.dot(q_1);
+ double dy = diff.dot(q_1_y);
+
+ double kx_g = K(0, v1);
+ double ky_g = K(1, v1);
+
+ if (index.first % 2 != index.second % 2) {
+ std::swap(v2_x, v2_y);
+ }
+ double scale_x = (fmin(fmax(1 + kx_g * dy, 0.3), 3));
+ double scale_y = (fmin(fmax(1 + ky_g * dx, 0.3), 3));
+ // (v2_x - scale_x * v1_x)^2 = 0
+ // x^2 - 2s xy + s^2 y^2
+ entries[v2_x][v2_x] += 1;
+ entries[v1_x][v1_x] += scale_x * scale_x;
+ entries[v2_y][v2_y] += 1;
+ entries[v1_y][v1_y] += scale_y * scale_y;
+ auto it = entries[v1_x].find(v2_x);
+ if (it == entries[v1_x].end()) {
+ entries[v1_x][v2_x] = -scale_x;
+ entries[v2_x][v1_x] = -scale_x;
+ entries[v1_y][v2_y] = -scale_y;
+ entries[v2_y][v1_y] = -scale_y;
+ } else {
+ it->second -= scale_x;
+ entries[v2_x][v1_x] -= scale_x;
+ entries[v1_y][v2_y] -= scale_y;
+ entries[v2_y][v1_y] -= scale_y;
+ }
+ }
+ }
+
+ Eigen::SparseMatrix<double> A(V.cols() * 2, V.cols() * 2);
+ VectorXd rhs(V.cols() * 2);
+ rhs.setZero();
+ for (int i = 0; i < entries.size(); ++i) {
+ rhs(i) = lambda * S(i % 2, i / 2);
+ for (auto& rec : entries[i]) {
+ lhsTriplets.push_back(Eigen::Triplet<double>(i, rec.first, rec.second));
+ }
+ }
+ A.setFromTriplets(lhsTriplets.begin(), lhsTriplets.end());
+ LinearSolver<Eigen::SparseMatrix<double>> solver;
+ solver.analyzePattern(A);
+
+ solver.factorize(A);
+
+ VectorXd result = solver.solve(rhs);
+
+ double total_area = 0;
+ for (int i = 0; i < V.cols(); ++i) {
+ S(0, i) = (result(i * 2));
+ S(1, i) = (result(i * 2 + 1));
+ total_area += S(0, i) * S(1, i);
+ }
+ total_area = sqrt(V.cols() / total_area);
+ for (int i = 0; i < V.cols(); ++i) {
+ // S(0, i) *= total_area;
+ // S(1, i) *= total_area;
+ }
+ } else {
+ for (int i = 0; i < V.cols(); ++i) {
+ S(0, i) = 1;
+ S(1, i) = 1;
+ }
+ }
+
+ for (int l = 0; l < mRes.mS.size() - 1; ++l) {
+ const MatrixXd& S = mRes.mS[l];
+ MatrixXd& S_next = mRes.mS[l + 1];
+ auto& toUpper = mRes.mToUpper[l];
+ for (int i = 0; i < toUpper.cols(); ++i) {
+ Vector2i upper = toUpper.col(i);
+ Vector2d q0 = S.col(upper[0]);
+
+ if (upper[1] != -1) {
+ q0 = (q0 + S.col(upper[1])) * 0.5;
+ }
+ S_next.col(i) = q0;
+ }
+ }
+}
+
+void Optimizer::optimize_positions(Hierarchy& mRes, int with_scale) {
+ int levelIterations = 6;
+#ifdef WITH_CUDA
+ optimize_positions_cuda(mRes);
+ cudaMemcpy(mRes.mO[0].data(), mRes.cudaO[0], sizeof(glm::dvec3) * mRes.mO[0].cols(),
+ cudaMemcpyDeviceToHost);
+#else
+ for (int level = mRes.mAdj.size() - 1; level >= 0; --level) {
+ for (int iter = 0; iter < levelIterations; ++iter) {
+ AdjacentMatrix& adj = mRes.mAdj[level];
+ const MatrixXd &N = mRes.mN[level], &Q = mRes.mQ[level], &V = mRes.mV[level];
+ const MatrixXd& CQ = mRes.mCQ[level];
+ const MatrixXd& CO = mRes.mCO[level];
+ const VectorXd& COw = mRes.mCOw[level];
+ MatrixXd& O = mRes.mO[level];
+ MatrixXd& S = mRes.mS[level];
+ auto& phases = mRes.mPhases[level];
+ for (int phase = 0; phase < phases.size(); ++phase) {
+ auto& p = phases[phase];
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int pi = 0; pi < p.size(); ++pi) {
+ int i = p[pi];
+ double scale_x = mRes.mScale;
+ double scale_y = mRes.mScale;
+ if (with_scale) {
+ scale_x *= S(0, i);
+ scale_y *= S(1, i);
+ }
+ double inv_scale_x = 1.0f / scale_x;
+ double inv_scale_y = 1.0f / scale_y;
+ const Vector3d n_i = N.col(i), v_i = V.col(i);
+ Vector3d q_i = Q.col(i);
+
+ Vector3d sum = O.col(i);
+ double weight_sum = 0.0f;
+
+ q_i.normalize();
+ for (auto& link : adj[i]) {
+ const int j = link.id;
+ const double weight = link.weight;
+ if (weight == 0) continue;
+ double scale_x_1 = mRes.mScale;
+ double scale_y_1 = mRes.mScale;
+ if (with_scale) {
+ scale_x_1 *= S(0, j);
+ scale_y_1 *= S(1, j);
+ }
+ double inv_scale_x_1 = 1.0f / scale_x_1;
+ double inv_scale_y_1 = 1.0f / scale_y_1;
+
+ const Vector3d n_j = N.col(j), v_j = V.col(j);
+ Vector3d q_j = Q.col(j), o_j = O.col(j);
+
+ q_j.normalize();
+
+ std::pair<Vector3d, Vector3d> value = compat_position_extrinsic_4(
+ v_i, n_i, q_i, sum, v_j, n_j, q_j, o_j, scale_x, scale_y, inv_scale_x,
+ inv_scale_y, scale_x_1, scale_y_1, inv_scale_x_1, inv_scale_y_1);
+
+ sum = value.first * weight_sum + value.second * weight;
+ weight_sum += weight;
+ if (weight_sum > RCPOVERFLOW) sum /= weight_sum;
+ sum -= n_i.dot(sum - v_i) * n_i;
+ }
+
+ if (COw.size() > 0) {
+ float cw = COw[i];
+ if (cw != 0) {
+ Vector3d co = CO.col(i), cq = CQ.col(i);
+ Vector3d d = co - sum;
+ d -= cq.dot(d) * cq;
+ sum += cw * d;
+ sum -= n_i.dot(sum - v_i) * n_i;
+ }
+ }
+
+ if (weight_sum > 0) {
+ O.col(i) = position_round_4(sum, q_i, n_i, v_i, scale_x, scale_y,
+ inv_scale_x, inv_scale_y);
+ }
+ }
+ }
+ }
+ if (level > 0) {
+ const MatrixXd& srcField = mRes.mO[level];
+ const MatrixXi& toUpper = mRes.mToUpper[level - 1];
+ MatrixXd& destField = mRes.mO[level - 1];
+ const MatrixXd& N = mRes.mN[level - 1];
+ const MatrixXd& V = mRes.mV[level - 1];
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int i = 0; i < srcField.cols(); ++i) {
+ for (int k = 0; k < 2; ++k) {
+ int dest = toUpper(k, i);
+ if (dest == -1) continue;
+ Vector3d o = srcField.col(i), n = N.col(dest), v = V.col(dest);
+ o -= n * n.dot(o - v);
+ destField.col(dest) = o;
+ }
+ }
+ }
+ }
+#endif
+}
+
+void Optimizer::optimize_positions_dynamic(
+ MatrixXi& F, MatrixXd& V, MatrixXd& N, MatrixXd& Q, std::vector<std::vector<int>>& Vset,
+ std::vector<Vector3d>& O_compact, std::vector<Vector4i>& F_compact,
+ std::vector<int>& V2E_compact, std::vector<int>& E2E_compact, double mScale,
+ std::vector<Vector3d>& diffs, std::vector<int>& diff_count,
+ std::map<std::pair<int, int>, int>& o2e, std::vector<int>& sharp_o,
+ std::map<int, std::pair<Vector3d, Vector3d>>& compact_sharp_constraints, int with_scale) {
+ std::set<int> uncertain;
+ for (auto& info : o2e) {
+ if (diff_count[info.second] == 0) {
+ uncertain.insert(info.first.first);
+ uncertain.insert(info.first.second);
+ }
+ }
+ std::vector<int> Vind(O_compact.size(), -1);
+ std::vector<std::list<int>> links(O_compact.size());
+ std::vector<std::list<int>> dedges(O_compact.size());
+ std::vector<std::vector<int>> adj(V.cols());
+ for (int i = 0; i < F.cols(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ int v1 = F(j, i);
+ int v2 = F((j + 1) % 3, i);
+ adj[v1].push_back(v2);
+ }
+ }
+ auto FindNearest = [&]() {
+ for (int i = 0; i < O_compact.size(); ++i) {
+ if (Vind[i] == -1) {
+ double min_dis = 1e30;
+ int min_ind = -1;
+ for (auto v : Vset[i]) {
+ double dis = (V.col(v) - O_compact[i]).squaredNorm();
+ if (dis < min_dis) {
+ min_dis = dis;
+ min_ind = v;
+ }
+ }
+ if (min_ind > -1) {
+ Vind[i] = min_ind;
+ double x = (O_compact[i] - V.col(min_ind)).dot(N.col(min_ind));
+ O_compact[i] -= x * N.col(min_ind);
+ }
+ } else {
+ int current_v = Vind[i];
+ Vector3d n = N.col(current_v);
+ double current_dis = (O_compact[i] - V.col(current_v)).squaredNorm();
+ while (true) {
+ int next_v = -1;
+ for (auto& v : adj[current_v]) {
+ if (N.col(v).dot(n) < cos(10.0 / 180.0 * 3.141592654)) continue;
+ double dis = (O_compact[i] - V.col(v)).squaredNorm();
+ if (dis < current_dis) {
+ current_dis = dis;
+ next_v = v;
+ }
+ }
+ if (next_v == -1) break;
+ // rotate ideal distance
+ Vector3d n1 = N.col(current_v);
+ Vector3d n2 = N.col(next_v);
+ Vector3d axis = n1.cross(n2);
+ double len = axis.norm();
+ double angle = atan2(len, n1.dot(n2));
+ axis.normalized();
+ Matrix3d m = AngleAxisd(angle, axis).toRotationMatrix();
+ for (auto e : dedges[i]) {
+ Vector3d& d = diffs[e];
+ d = m * d;
+ }
+ current_v = next_v;
+ }
+ Vind[i] = current_v;
+ }
+ }
+ };
+
+ auto BuildConnection = [&]() {
+ for (int i = 0; i < links.size(); ++i) {
+ int deid0 = V2E_compact[i];
+ if (deid0 != -1) {
+ std::list<int>& connection = links[i];
+ std::list<int>& dedge = dedges[i];
+ int deid = deid0;
+ do {
+ connection.push_back(F_compact[deid / 4][(deid + 1) % 4]);
+ dedge.push_back(deid);
+ deid = E2E_compact[deid / 4 * 4 + (deid + 3) % 4];
+ } while (deid != -1 && deid != deid0);
+ if (deid == -1) {
+ deid = deid0;
+ do {
+ deid = E2E_compact[deid];
+ if (deid == -1) break;
+ deid = deid / 4 * 4 + (deid + 1) % 4;
+ connection.push_front(F_compact[deid / 4][(deid + 1) % 4]);
+ dedge.push_front(deid);
+ } while (true);
+ }
+ }
+ }
+ };
+
+ std::vector<Vector3d> lines;
+ auto ComputeDistance = [&]() {
+ std::set<int> unobserved;
+ for (auto& info : o2e) {
+ if (diff_count[info.second] == 0) {
+ unobserved.insert(info.first.first);
+ }
+ }
+ while (true) {
+ bool update = false;
+ std::set<int> observed;
+ for (auto& p : unobserved) {
+ std::vector<int> observations, edges;
+ int count = 0;
+ for (auto& e : dedges[p]) {
+ edges.push_back(e);
+ if (diff_count[e]) {
+ count += 1;
+ observations.push_back(1);
+ } else {
+ observations.push_back(0);
+ }
+ }
+ if (count <= 1) continue;
+ update = true;
+ observed.insert(p);
+ for (int i = 0; i < observations.size(); ++i) {
+ if (observations[i] == 1) continue;
+ int j = i;
+ std::list<int> interp;
+ while (observations[j] == 0) {
+ interp.push_front(j);
+ j -= 1;
+ if (j < 0) j = edges.size() - 1;
+ }
+ j = (i + 1) % edges.size();
+ while (observations[j] == 0) {
+ interp.push_back(j);
+ j += 1;
+ if (j == edges.size()) j = 0;
+ }
+ Vector3d dl = diffs[edges[(interp.front() + edges.size() - 1) % edges.size()]];
+ double lenl = dl.norm();
+ Vector3d dr = diffs[edges[(interp.back() + 1) % edges.size()]];
+ double lenr = dr.norm();
+ dl /= lenl;
+ dr /= lenr;
+ Vector3d n = dl.cross(dr).normalized();
+ double angle = atan2(dl.cross(dr).norm(), dl.dot(dr));
+ if (angle < 0) angle += 2 * 3.141592654;
+ Vector3d nc = N.col(Vind[p]);
+ if (n.dot(nc) < 0) {
+ n = -n;
+ angle = 2 * 3.141592654 - angle;
+ }
+ double step = (lenr - lenl) / (interp.size() + 1);
+ angle /= interp.size() + 1;
+ Vector3d dlp = nc.cross(dl).normalized();
+ int t = 0;
+ for (auto q : interp) {
+ t += 1;
+ observations[q] = 1;
+ double ad = angle * t;
+ int e = edges[q];
+ int re = E2E_compact[e];
+ diff_count[e] = 2;
+ diffs[e] = (cos(ad) * dl + sin(ad) * dlp) * (lenl + step * t);
+ if (re != -1) {
+ diff_count[re] = 2;
+ diffs[re] = -diffs[e];
+ }
+ }
+ for (int i = 0; i < edges.size(); ++i) {
+ lines.push_back(O_compact[p]);
+ lines.push_back(O_compact[p] + diffs[edges[i]]);
+ }
+ }
+ }
+ if (!update) break;
+ for (auto& p : observed) unobserved.erase(p);
+ }
+ };
+
+ BuildConnection();
+ int max_iter = 10;
+ for (int iter = 0; iter < max_iter; ++iter) {
+ FindNearest();
+ ComputeDistance();
+
+ std::vector<std::unordered_map<int, double>> entries(O_compact.size() * 2);
+ std::vector<int> fixed_dim(O_compact.size() * 2, 0);
+ for (auto& info : compact_sharp_constraints) {
+ fixed_dim[info.first * 2 + 1] = 1;
+ if (info.second.second.norm() < 0.5) fixed_dim[info.first * 2] = 1;
+ }
+ std::vector<double> b(O_compact.size() * 2);
+ std::vector<double> x(O_compact.size() * 2);
+ std::vector<Vector3d> Q_compact(O_compact.size());
+ std::vector<Vector3d> N_compact(O_compact.size());
+ std::vector<Vector3d> V_compact(O_compact.size());
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int i = 0; i < O_compact.size(); ++i) {
+ Q_compact[i] = Q.col(Vind[i]);
+ N_compact[i] = N.col(Vind[i]);
+ V_compact[i] = V.col(Vind[i]);
+ if (fixed_dim[i * 2 + 1] && !fixed_dim[i * 2]) {
+ Q_compact[i] = compact_sharp_constraints[i].second;
+ V_compact[i] = compact_sharp_constraints[i].first;
+ }
+ }
+ for (int i = 0; i < O_compact.size(); ++i) {
+ Vector3d q = Q_compact[i];
+ Vector3d n = N_compact[i];
+ Vector3d q_y = n.cross(q);
+ auto Vi = V_compact[i];
+ x[i * 2] = (O_compact[i] - Vi).dot(q);
+ x[i * 2 + 1] = (O_compact[i] - Vi).dot(q_y);
+ }
+ for (int i = 0; i < O_compact.size(); ++i) {
+ Vector3d qx = Q_compact[i];
+ Vector3d qy = N_compact[i];
+ qy = qy.cross(qx);
+ auto dedge_it = dedges[i].begin();
+ for (auto it = links[i].begin(); it != links[i].end(); ++it, ++dedge_it) {
+ int j = *it;
+ Vector3d qx2 = Q_compact[j];
+ Vector3d qy2 = N_compact[j];
+ qy2 = qy2.cross(qx2);
+
+ int de = o2e[std::make_pair(i, j)];
+ double lambda = (diff_count[de] == 1) ? 1 : 1;
+ Vector3d target_offset = diffs[de];
+
+ auto Vi = V_compact[i];
+ auto Vj = V_compact[j];
+
+ Vector3d offset = Vj - Vi;
+
+ // target_offset.normalize();
+ // target_offset *= mScale;
+ Vector3d C = target_offset - offset;
+ int vid[] = {j * 2, j * 2 + 1, i * 2, i * 2 + 1};
+ Vector3d weights[] = {qx2, qy2, -qx, -qy};
+ for (int ii = 0; ii < 4; ++ii) {
+ for (int jj = 0; jj < 4; ++jj) {
+ auto it = entries[vid[ii]].find(vid[jj]);
+ if (it == entries[vid[ii]].end()) {
+ entries[vid[ii]][vid[jj]] = lambda * weights[ii].dot(weights[jj]);
+ } else {
+ entries[vid[ii]][vid[jj]] += lambda * weights[ii].dot(weights[jj]);
+ }
+ }
+ b[vid[ii]] += lambda * weights[ii].dot(C);
+ }
+ }
+ }
+
+ // fix sharp edges
+ for (int i = 0; i < entries.size(); ++i) {
+ if (entries[i].size() == 0) {
+ entries[i][i] = 1;
+ b[i] = x[i];
+ }
+ if (fixed_dim[i]) {
+ b[i] = x[i];
+ entries[i].clear();
+ entries[i][i] = 1;
+ } else {
+ std::unordered_map<int, double> newmap;
+ for (auto& rec : entries[i]) {
+ if (fixed_dim[rec.first]) {
+ b[i] -= rec.second * x[rec.first];
+ } else {
+ newmap[rec.first] = rec.second;
+ }
+ }
+ std::swap(entries[i], newmap);
+ }
+ }
+ std::vector<Eigen::Triplet<double>> lhsTriplets;
+ lhsTriplets.reserve(F_compact.size() * 8);
+ Eigen::SparseMatrix<double> A(O_compact.size() * 2, O_compact.size() * 2);
+ VectorXd rhs(O_compact.size() * 2);
+ rhs.setZero();
+ for (int i = 0; i < entries.size(); ++i) {
+ rhs(i) = b[i];
+ for (auto& rec : entries[i]) {
+ lhsTriplets.push_back(Eigen::Triplet<double>(i, rec.first, rec.second));
+ }
+ }
+
+ A.setFromTriplets(lhsTriplets.begin(), lhsTriplets.end());
+
+#ifdef LOG_OUTPUT
+ int t1 = GetCurrentTime64();
+#endif
+
+ // FIXME: IncompleteCholesky Preconditioner will fail here so I fallback to Diagonal one.
+ // I suspected either there is a implementation bug in IncompleteCholesky Preconditioner
+ // or there is a memory corruption somewhere. However, g++'s address sanitizer does not
+ // report anything useful.
+ LinearSolver<Eigen::SparseMatrix<double>> solver;
+ solver.analyzePattern(A);
+ solver.factorize(A);
+ // Eigen::setNbThreads(1);
+ // ConjugateGradient<SparseMatrix<double>, Lower | Upper> solver;
+ // VectorXd x0 = VectorXd::Map(x.data(), x.size());
+ // solver.setMaxIterations(40);
+
+ // solver.compute(A);
+ VectorXd x_new = solver.solve(rhs); // solver.solveWithGuess(rhs, x0);
+
+#ifdef LOG_OUTPUT
+ // std::cout << "[LSQ] n_iteration:" << solver.iterations() << std::endl;
+ // std::cout << "[LSQ] estimated error:" << solver.error() << std::endl;
+ int t2 = GetCurrentTime64();
+ printf("[LSQ] Linear solver uses %lf seconds.\n", (t2 - t1) * 1e-3);
+#endif
+ for (int i = 0; i < O_compact.size(); ++i) {
+ // Vector3d q = Q.col(Vind[i]);
+ Vector3d q = Q_compact[i];
+ // Vector3d n = N.col(Vind[i]);
+ Vector3d n = N_compact[i];
+ Vector3d q_y = n.cross(q);
+ auto Vi = V_compact[i];
+ O_compact[i] = Vi + q * x_new[i * 2] + q_y * x_new[i * 2 + 1];
+ }
+
+ // forgive my hack...
+ if (iter + 1 == max_iter) {
+ for (int iter = 0; iter < 5; ++iter) {
+ for (int i = 0; i < O_compact.size(); ++i) {
+ if (sharp_o[i]) continue;
+ if (dedges[i].size() != 4 || uncertain.count(i)) {
+ Vector3d n(0, 0, 0), v(0, 0, 0);
+ Vector3d v0 = O_compact[i];
+ for (auto e : dedges[i]) {
+ Vector3d v1 = O_compact[F_compact[e / 4][(e + 1) % 4]];
+ Vector3d v2 = O_compact[F_compact[e / 4][(e + 3) % 4]];
+ n += (v1 - v0).cross(v2 - v0);
+ v += v1;
+ }
+ n.normalize();
+ Vector3d offset = v / dedges[i].size() - v0;
+ offset -= offset.dot(n) * n;
+ O_compact[i] += offset;
+ }
+ }
+ }
+ }
+ }
+}
+
+void Optimizer::optimize_positions_sharp(
+ Hierarchy& mRes, std::vector<DEdge>& edge_values, std::vector<Vector2i>& edge_diff,
+ std::vector<int>& sharp_edges, std::set<int>& sharp_vertices,
+ std::map<int, std::pair<Vector3d, Vector3d>>& sharp_constraints, int with_scale) {
+ auto& V = mRes.mV[0];
+ auto& F = mRes.mF;
+ auto& Q = mRes.mQ[0];
+ auto& N = mRes.mN[0];
+ auto& O = mRes.mO[0];
+ auto& S = mRes.mS[0];
+
+ DisajointTree tree(V.cols());
+ for (int i = 0; i < edge_diff.size(); ++i) {
+ if (edge_diff[i].array().abs().sum() == 0) {
+ tree.Merge(edge_values[i].x, edge_values[i].y);
+ }
+ }
+ tree.BuildCompactParent();
+ std::map<int, int> compact_sharp_indices;
+ std::set<DEdge> compact_sharp_edges;
+ for (int i = 0; i < sharp_edges.size(); ++i) {
+ if (sharp_edges[i] == 1) {
+ int v1 = tree.Index(F(i % 3, i / 3));
+ int v2 = tree.Index(F((i + 1) % 3, i / 3));
+ compact_sharp_edges.insert(DEdge(v1, v2));
+ }
+ }
+ for (auto& v : sharp_vertices) {
+ int p = tree.Index(v);
+ if (compact_sharp_indices.count(p) == 0) {
+ int s = compact_sharp_indices.size();
+ compact_sharp_indices[p] = s;
+ }
+ }
+ std::map<int, std::set<int>> sharp_vertices_links;
+ std::set<DEdge> sharp_dedges;
+ for (int i = 0; i < sharp_edges.size(); ++i) {
+ if (sharp_edges[i]) {
+ int v1 = F(i % 3, i / 3);
+ int v2 = F((i + 1) % 3, i / 3);
+ if (sharp_vertices_links.count(v1) == 0) sharp_vertices_links[v1] = std::set<int>();
+ sharp_vertices_links[v1].insert(v2);
+ sharp_dedges.insert(DEdge(v1, v2));
+ }
+ }
+ std::vector<std::vector<int>> sharp_to_original_indices(compact_sharp_indices.size());
+ for (auto& v : sharp_vertices_links) {
+ if (v.second.size() == 2) continue;
+ int p = tree.Index(v.first);
+ sharp_to_original_indices[compact_sharp_indices[p]].push_back(v.first);
+ }
+ for (auto& v : sharp_vertices_links) {
+ if (v.second.size() != 2) continue;
+ int p = tree.Index(v.first);
+ sharp_to_original_indices[compact_sharp_indices[p]].push_back(v.first);
+ }
+
+ for (int i = 0; i < V.cols(); ++i) {
+ if (sharp_vertices.count(i)) continue;
+ int p = tree.Index(i);
+ if (compact_sharp_indices.count(p))
+ sharp_to_original_indices[compact_sharp_indices[p]].push_back(i);
+ }
+
+ int num = sharp_to_original_indices.size();
+ std::vector<std::set<int>> links(sharp_to_original_indices.size());
+ for (int e = 0; e < edge_diff.size(); ++e) {
+ int v1 = edge_values[e].x;
+ int v2 = edge_values[e].y;
+ int p1 = tree.Index(v1);
+ int p2 = tree.Index(v2);
+ if (p1 == p2 || compact_sharp_edges.count(DEdge(p1, p2)) == 0) continue;
+ p1 = compact_sharp_indices[p1];
+ p2 = compact_sharp_indices[p2];
+
+ links[p1].insert(p2);
+ links[p2].insert(p1);
+ }
+
+ std::vector<int> hash(links.size(), 0);
+ std::vector<std::vector<Vector3d>> loops;
+ for (int i = 0; i < num; ++i) {
+ if (hash[i] == 1) continue;
+ if (links[i].size() == 2) {
+ std::vector<int> q;
+ q.push_back(i);
+ hash[i] = 1;
+ int v = i;
+ int prev_v = -1;
+ bool is_loop = false;
+ while (links[v].size() == 2) {
+ int next_v = -1;
+ for (auto nv : links[v])
+ if (nv != prev_v) next_v = nv;
+ if (hash[next_v]) {
+ is_loop = true;
+ break;
+ }
+ if (links[next_v].size() == 2) hash[next_v] = true;
+ q.push_back(next_v);
+ prev_v = v;
+ v = next_v;
+ }
+ if (!is_loop && q.size() >= 2) {
+ std::vector<int> q1;
+ int v = i;
+ int prev_v = q[1];
+ while (links[v].size() == 2) {
+ int next_v = -1;
+ for (auto nv : links[v])
+ if (nv != prev_v) next_v = nv;
+ if (hash[next_v]) {
+ is_loop = true;
+ break;
+ }
+ if (links[next_v].size() == 2) hash[next_v] = true;
+ q1.push_back(next_v);
+ prev_v = v;
+ v = next_v;
+ }
+ std::reverse(q1.begin(), q1.end());
+ q1.insert(q1.end(), q.begin(), q.end());
+ std::swap(q1, q);
+ }
+ if (q.size() < 3) continue;
+ if (is_loop) q.push_back(q.front());
+ double len = 0, scale = 0;
+ std::vector<Vector3d> o(q.size()), new_o(q.size());
+ std::vector<double> sc(q.size());
+
+ for (int i = 0; i < q.size() - 1; ++i) {
+ int v1 = q[i];
+ int v2 = q[i + 1];
+ auto it = links[v1].find(v2);
+ if (it == links[v1].end()) {
+ printf("Non exist!\n");
+ exit(0);
+ }
+ }
+
+ for (int i = 0; i < q.size(); ++i) {
+ if (sharp_to_original_indices[q[i]].size() == 0) {
+ continue;
+ }
+ o[i] = O.col(sharp_to_original_indices[q[i]][0]);
+ Vector3d qx = Q.col(sharp_to_original_indices[q[i]][0]);
+ Vector3d qy = Vector3d(N.col(sharp_to_original_indices[q[i]][0])).cross(qx);
+ int fst = sharp_to_original_indices[q[1]][0];
+ Vector3d dis = (i == 0) ? (Vector3d(O.col(fst)) - o[i]) : o[i] - o[i - 1];
+ if (with_scale)
+ sc[i] = (abs(qx.dot(dis)) > abs(qy.dot(dis)))
+ ? S(0, sharp_to_original_indices[q[i]][0])
+ : S(1, sharp_to_original_indices[q[i]][0]);
+ else
+ sc[i] = 1;
+ new_o[i] = o[i];
+ }
+
+ if (is_loop) {
+ for (int i = 0; i < q.size(); ++i) {
+ Vector3d dir =
+ (o[(i + 1) % q.size()] - o[(i + q.size() - 1) % q.size()]).normalized();
+ for (auto& ind : sharp_to_original_indices[q[i]]) {
+ sharp_constraints[ind] = std::make_pair(o[i], dir);
+ }
+ }
+ } else {
+ for (int i = 0; i < q.size(); ++i) {
+ Vector3d dir(0, 0, 0);
+ if (i != 0 && i + 1 != q.size())
+ dir = (o[i + 1] - o[i - 1]).normalized();
+ else if (links[q[i]].size() == 1) {
+ if (i == 0)
+ dir = (o[i + 1] - o[i]).normalized();
+ else
+ dir = (o[i] - o[i - 1]).normalized();
+ }
+ for (auto& ind : sharp_to_original_indices[q[i]]) {
+ sharp_constraints[ind] = std::make_pair(o[i], dir);
+ }
+ }
+ }
+
+ for (int i = 0; i < q.size() - 1; ++i) {
+ len += (o[i + 1] - o[i]).norm();
+ scale += sc[i];
+ }
+
+ int next_m = q.size() - 1;
+
+ double left_norm = len * sc[0] / scale;
+ int current_v = 0;
+ double current_norm = (o[1] - o[0]).norm();
+ for (int i = 1; i < next_m; ++i) {
+ while (left_norm >= current_norm) {
+ left_norm -= current_norm;
+ current_v += 1;
+ current_norm = (o[current_v + 1] - o[current_v]).norm();
+ }
+ new_o[i] =
+ (o[current_v + 1] * left_norm + o[current_v] * (current_norm - left_norm)) /
+ current_norm;
+ o[current_v] = new_o[i];
+ current_norm -= left_norm;
+ left_norm = len * sc[current_v] / scale;
+ }
+
+ for (int i = 0; i < q.size(); ++i) {
+ for (auto v : sharp_to_original_indices[q[i]]) {
+ O.col(v) = new_o[i];
+ }
+ }
+
+ loops.push_back(new_o);
+ }
+ }
+ return;
+ std::ofstream os("/Users/jingwei/Desktop/sharp.obj");
+ for (int i = 0; i < loops.size(); ++i) {
+ for (auto& v : loops[i]) {
+ os << "v " << v[0] << " " << v[1] << " " << v[2] << "\n";
+ }
+ }
+ int offset = 1;
+ for (int i = 0; i < loops.size(); ++i) {
+ for (int j = 0; j < loops[i].size() - 1; ++j) {
+ os << "l " << offset + j << " " << offset + j + 1 << "\n";
+ }
+ offset += loops[i].size();
+ }
+ os.close();
+ exit(0);
+}
+
+void Optimizer::optimize_positions_fixed(
+ Hierarchy& mRes, std::vector<DEdge>& edge_values, std::vector<Vector2i>& edge_diff,
+ std::set<int>& sharp_vertices, std::map<int, std::pair<Vector3d, Vector3d>>& sharp_constraints,
+ int with_scale) {
+ auto& V = mRes.mV[0];
+ auto& F = mRes.mF;
+ auto& Q = mRes.mQ[0];
+ auto& N = mRes.mN[0];
+ auto& O = mRes.mO[0];
+ auto& S = mRes.mS[0];
+
+ DisajointTree tree(V.cols());
+ for (int i = 0; i < edge_diff.size(); ++i) {
+ if (edge_diff[i].array().abs().sum() == 0) {
+ tree.Merge(edge_values[i].x, edge_values[i].y);
+ }
+ }
+ tree.BuildCompactParent();
+ int num = tree.CompactNum();
+
+ // Find the most descriptive vertex
+ std::vector<Vector3d> v_positions(num, Vector3d(0, 0, 0));
+ std::vector<int> v_count(num);
+ std::vector<double> v_distance(num, 1e30);
+ std::vector<int> v_index(num, -1);
+
+ for (int i = 0; i < V.cols(); ++i) {
+ v_positions[tree.Index(i)] += O.col(i);
+ v_count[tree.Index(i)] += 1;
+ }
+ for (int i = 0; i < num; ++i) {
+ if (v_count[i] > 0) v_positions[i] /= v_count[i];
+ }
+ for (int i = 0; i < V.cols(); ++i) {
+ int p = tree.Index(i);
+ double dis = (v_positions[p] - V.col(i)).squaredNorm();
+ if (dis < v_distance[p]) {
+ v_distance[p] = dis;
+ v_index[p] = i;
+ }
+ }
+
+ std::set<int> compact_sharp_vertices;
+ for (auto& v : sharp_vertices) {
+ v_positions[tree.Index(v)] = O.col(v);
+ v_index[tree.Index(v)] = v;
+ V.col(v) = O.col(v);
+ compact_sharp_vertices.insert(tree.Index(v));
+ }
+ std::vector<std::map<int, std::pair<int, Vector3d>>> ideal_distances(tree.CompactNum());
+ for (int e = 0; e < edge_diff.size(); ++e) {
+ int v1 = edge_values[e].x;
+ int v2 = edge_values[e].y;
+
+ int p1 = tree.Index(v1);
+ int p2 = tree.Index(v2);
+ int q1 = v_index[p1];
+ int q2 = v_index[p2];
+
+ Vector3d q_1 = Q.col(v1);
+ Vector3d q_2 = Q.col(v2);
+
+ Vector3d n_1 = N.col(v1);
+ Vector3d n_2 = N.col(v2);
+ Vector3d q_1_y = n_1.cross(q_1);
+ Vector3d q_2_y = n_2.cross(q_2);
+ auto index = compat_orientation_extrinsic_index_4(q_1, n_1, q_2, n_2);
+ double s_x1 = S(0, v1), s_y1 = S(1, v1);
+ double s_x2 = S(0, v2), s_y2 = S(1, v2);
+ int rank_diff = (index.second + 4 - index.first) % 4;
+ if (rank_diff % 2 == 1) std::swap(s_x2, s_y2);
+ Vector3d qd_x = 0.5 * (rotate90_by(q_2, n_2, rank_diff) + q_1);
+ Vector3d qd_y = 0.5 * (rotate90_by(q_2_y, n_2, rank_diff) + q_1_y);
+ double scale_x = (with_scale ? 0.5 * (s_x1 + s_x2) : 1) * mRes.mScale;
+ double scale_y = (with_scale ? 0.5 * (s_y1 + s_y2) : 1) * mRes.mScale;
+ Vector2i diff = edge_diff[e];
+
+ Vector3d origin1 =
+ /*(sharp_constraints.count(q1)) ? sharp_constraints[q1].first : */ V.col(q1);
+ Vector3d origin2 =
+ /*(sharp_constraints.count(q2)) ? sharp_constraints[q2].first : */ V.col(q2);
+ Vector3d C = diff[0] * scale_x * qd_x + diff[1] * scale_y * qd_y + origin1 - origin2;
+ auto it = ideal_distances[p1].find(p2);
+ if (it == ideal_distances[p1].end()) {
+ ideal_distances[p1][p2] = std::make_pair(1, C);
+ } else {
+ it->second.first += 1;
+ it->second.second += C;
+ }
+ }
+
+ std::vector<std::unordered_map<int, double>> entries(num * 2);
+ std::vector<double> b(num * 2);
+
+ for (int m = 0; m < num; ++m) {
+ int v1 = v_index[m];
+ for (auto& info : ideal_distances[m]) {
+ int v2 = v_index[info.first];
+ Vector3d q_1 = Q.col(v1);
+ Vector3d q_2 = Q.col(v2);
+ if (sharp_constraints.count(v1)) {
+ Vector3d d = sharp_constraints[v1].second;
+ if (d != Vector3d::Zero()) q_1 = d;
+ }
+ if (sharp_constraints.count(v2)) {
+ Vector3d d = sharp_constraints[v2].second;
+ if (d != Vector3d::Zero()) q_2 = d;
+ }
+
+ Vector3d n_1 = N.col(v1);
+ Vector3d n_2 = N.col(v2);
+ Vector3d q_1_y = n_1.cross(q_1);
+ Vector3d q_2_y = n_2.cross(q_2);
+ Vector3d weights[] = {q_2, q_2_y, -q_1, -q_1_y};
+ int vid[] = {info.first * 2, info.first * 2 + 1, m * 2, m * 2 + 1};
+ Vector3d dis = info.second.second / info.second.first;
+ double lambda = 1;
+ if (sharp_vertices.count(v1) && sharp_vertices.count(v2)) lambda = 1;
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ auto it = entries[vid[i]].find(vid[j]);
+ if (it == entries[vid[i]].end()) {
+ entries[vid[i]][vid[j]] = weights[i].dot(weights[j]) * lambda;
+ } else {
+ entries[vid[i]][vid[j]] += weights[i].dot(weights[j]) * lambda;
+ }
+ }
+ b[vid[i]] += weights[i].dot(dis) * lambda;
+ }
+ }
+ }
+
+ std::vector<int> fixed_dim(num * 2, 0);
+ std::vector<double> x(num * 2);
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int i = 0; i < num; ++i) {
+ int p = v_index[i];
+ Vector3d q = Q.col(p);
+
+ if (sharp_constraints.count(p)) {
+ Vector3d dir = sharp_constraints[p].second;
+ fixed_dim[i * 2 + 1] = 1;
+ if (dir != Vector3d::Zero()) {
+ q = dir;
+ } else
+ fixed_dim[i * 2] = 1;
+ }
+ Vector3d n = N.col(p);
+ Vector3d q_y = n.cross(q);
+ x[i * 2] = (v_positions[i] - V.col(p)).dot(q);
+ x[i * 2 + 1] = (v_positions[i] - V.col(p)).dot(q_y);
+ }
+
+ // fix sharp edges
+ for (int i = 0; i < entries.size(); ++i) {
+ if (fixed_dim[i]) {
+ b[i] = x[i];
+ entries[i].clear();
+ entries[i][i] = 1;
+ } else {
+ std::unordered_map<int, double> newmap;
+ for (auto& rec : entries[i]) {
+ if (fixed_dim[rec.first]) {
+ b[i] -= rec.second * x[rec.first];
+ } else {
+ newmap[rec.first] = rec.second;
+ }
+ }
+ std::swap(entries[i], newmap);
+ }
+ }
+ for (int i = 0; i < entries.size(); ++i) {
+ if (entries[i].size() == 0) {
+ entries[i][i] = 1;
+ }
+ }
+
+ std::vector<Eigen::Triplet<double>> lhsTriplets;
+ lhsTriplets.reserve(F.cols() * 6);
+ Eigen::SparseMatrix<double> A(num * 2, num * 2);
+ VectorXd rhs(num * 2);
+ rhs.setZero();
+ for (int i = 0; i < entries.size(); ++i) {
+ rhs(i) = b[i];
+ if (std::isnan(b[i])) {
+ printf("Equation has nan!\n");
+ exit(0);
+ }
+ for (auto& rec : entries[i]) {
+ lhsTriplets.push_back(Eigen::Triplet<double>(i, rec.first, rec.second));
+ if (std::isnan(rec.second)) {
+ printf("Equation has nan!\n");
+ exit(0);
+ }
+ }
+ }
+ A.setFromTriplets(lhsTriplets.begin(), lhsTriplets.end());
+
+#ifdef LOG_OUTPUT
+ int t1 = GetCurrentTime64();
+#endif
+ /*
+ Eigen::setNbThreads(1);
+ ConjugateGradient<SparseMatrix<double>, Lower | Upper> solver;
+ VectorXd x0 = VectorXd::Map(x.data(), x.size());
+ solver.setMaxIterations(40);
+
+ solver.compute(A);
+ */
+ LinearSolver<Eigen::SparseMatrix<double>> solver;
+ solver.analyzePattern(A);
+ solver.factorize(A);
+
+ VectorXd x_new = solver.solve(rhs);
+#ifdef LOG_OUTPUT
+ // std::cout << "[LSQ] n_iteration:" << solver.iterations() << std::endl;
+ // std::cout << "[LSQ] estimated error:" << solver.error() << std::endl;
+ int t2 = GetCurrentTime64();
+ printf("[LSQ] Linear solver uses %lf seconds.\n", (t2 - t1) * 1e-3);
+#endif
+
+ for (int i = 0; i < x.size(); ++i) {
+ if (!std::isnan(x_new[i])) {
+ if (!fixed_dim[i / 2 * 2 + 1]) {
+ double total = 0;
+ for (auto& res : entries[i]) {
+ double t = x_new[res.first];
+ if (std::isnan(t)) t = 0;
+ total += t * res.second;
+ }
+ }
+ x[i] = x_new[i];
+ }
+ }
+
+ for (int i = 0; i < O.cols(); ++i) {
+ int p = tree.Index(i);
+ int c = v_index[p];
+ Vector3d q = Q.col(c);
+ if (fixed_dim[p * 2 + 1]) {
+ Vector3d dir = sharp_constraints[c].second;
+ if (dir != Vector3d::Zero()) q = dir;
+ }
+ Vector3d n = N.col(c);
+ Vector3d q_y = n.cross(q);
+ O.col(i) = V.col(c) + q * x[p * 2] + q_y * x[p * 2 + 1];
+ }
+}
+
+void Optimizer::optimize_integer_constraints(Hierarchy& mRes, std::map<int, int>& singularities,
+ bool use_minimum_cost_flow) {
+ int edge_capacity = 2;
+ bool fullFlow = false;
+ std::vector<std::vector<int>>& AllowChange = mRes.mAllowChanges;
+ for (int level = mRes.mToUpperEdges.size(); level >= 0; --level) {
+ auto& EdgeDiff = mRes.mEdgeDiff[level];
+ auto& FQ = mRes.mFQ[level];
+ auto& F2E = mRes.mF2E[level];
+ auto& E2F = mRes.mE2F[level];
+
+ int iter = 0;
+ while (!fullFlow) {
+ std::vector<Vector4i> edge_to_constraints(E2F.size() * 2, Vector4i(-1, 0, -1, 0));
+ std::vector<int> initial(F2E.size() * 2, 0);
+ for (int i = 0; i < F2E.size(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ int e = F2E[i][j];
+ Vector2i index = rshift90(Vector2i(e * 2 + 1, e * 2 + 2), FQ[i][j]);
+ for (int k = 0; k < 2; ++k) {
+ int l = abs(index[k]);
+ int s = index[k] / l;
+ int ind = l - 1;
+ int equationID = i * 2 + k;
+ if (edge_to_constraints[ind][0] == -1) {
+ edge_to_constraints[ind][0] = equationID;
+ edge_to_constraints[ind][1] = s;
+ } else {
+ edge_to_constraints[ind][2] = equationID;
+ edge_to_constraints[ind][3] = s;
+ }
+ initial[equationID] += s * EdgeDiff[ind / 2][ind % 2];
+ }
+ }
+ }
+ std::vector<std::pair<Vector2i, int>> arcs;
+ std::vector<int> arc_ids;
+ for (int i = 0; i < edge_to_constraints.size(); ++i) {
+ if (AllowChange[level][i] == 0) continue;
+ if (edge_to_constraints[i][0] == -1 || edge_to_constraints[i][2] == -1) continue;
+ if (edge_to_constraints[i][1] == -edge_to_constraints[i][3]) {
+ int v1 = edge_to_constraints[i][0];
+ int v2 = edge_to_constraints[i][2];
+ if (edge_to_constraints[i][1] < 0) std::swap(v1, v2);
+ int current_v = EdgeDiff[i / 2][i % 2];
+ arcs.push_back(std::make_pair(Vector2i(v1, v2), current_v));
+ if (AllowChange[level][i] == 1)
+ arc_ids.push_back(i + 1);
+ else {
+ arc_ids.push_back(-(i + 1));
+ }
+ }
+ }
+ int supply = 0;
+ int demand = 0;
+ for (int i = 0; i < initial.size(); ++i) {
+ int init_val = initial[i];
+ if (init_val > 0) {
+ arcs.push_back(std::make_pair(Vector2i(-1, i), initial[i]));
+ supply += init_val;
+ } else if (init_val < 0) {
+ demand -= init_val;
+ arcs.push_back(std::make_pair(Vector2i(i, initial.size()), -init_val));
+ }
+ }
+
+ std::unique_ptr<MaxFlowHelper> solver = nullptr;
+ if (use_minimum_cost_flow && level == mRes.mToUpperEdges.size()) {
+ lprintf("network simplex MCF is used\n");
+ solver = std::make_unique<NetworkSimplexFlowHelper>();
+ } else if (supply < 20) {
+ solver = std::make_unique<ECMaxFlowHelper>();
+ } else {
+ solver = std::make_unique<BoykovMaxFlowHelper>();
+ }
+
+#ifdef WITH_GUROBI
+ if (use_minimum_cost_flow && level == mRes.mToUpperEdges.size()) {
+ solver = std::make_unique<GurobiFlowHelper>();
+ }
+#endif
+ solver->resize(initial.size() + 2, arc_ids.size());
+
+ std::set<int> ids;
+ for (int i = 0; i < arcs.size(); ++i) {
+ int v1 = arcs[i].first[0] + 1;
+ int v2 = arcs[i].first[1] + 1;
+ int c = arcs[i].second;
+ if (v1 == 0 || v2 == initial.size() + 1) {
+ solver->addEdge(v1, v2, c, 0, -1);
+ } else {
+ if (arc_ids[i] > 0)
+ solver->addEdge(v1, v2, std::max(0, c + edge_capacity),
+ std::max(0, -c + edge_capacity), arc_ids[i] - 1);
+ else {
+ if (c > 0)
+ solver->addEdge(v1, v2, std::max(0, c - 1),
+ std::max(0, -c + edge_capacity), -1 - arc_ids[i]);
+ else
+ solver->addEdge(v1, v2, std::max(0, c + edge_capacity),
+ std::max(0, -c - 1), -1 - arc_ids[i]);
+ }
+ }
+ }
+ int flow_count = solver->compute();
+
+ solver->applyTo(EdgeDiff);
+
+ lprintf("flow_count = %d, supply = %d\n", flow_count, supply);
+ if (flow_count == supply) fullFlow = true;
+ if (level != 0 || fullFlow) break;
+ edge_capacity += 1;
+ iter++;
+ if (iter == 10) {
+ /* Probably won't converge. */
+ break;
+ }
+ lprintf("Not full flow, edge_capacity += 1\n");
+ }
+
+ if (level != 0) {
+ auto& nEdgeDiff = mRes.mEdgeDiff[level - 1];
+ auto& toUpper = mRes.mToUpperEdges[level - 1];
+ auto& toUpperOrients = mRes.mToUpperOrients[level - 1];
+ for (int i = 0; i < toUpper.size(); ++i) {
+ if (toUpper[i] >= 0) {
+ int orient = (4 - toUpperOrients[i]) % 4;
+ nEdgeDiff[i] = rshift90(EdgeDiff[toUpper[i]], orient);
+ }
+ }
+ }
+ }
+}
+
+#ifdef WITH_CUDA
+
+void Optimizer::optimize_orientations_cuda(Hierarchy& mRes) {
+ int levelIterations = 6;
+ for (int level = mRes.mN.size() - 1; level >= 0; --level) {
+ Link* adj = mRes.cudaAdj[level];
+ int* adjOffset = mRes.cudaAdjOffset[level];
+ glm::dvec3* N = mRes.cudaN[level];
+ glm::dvec3* Q = mRes.cudaQ[level];
+ auto& phases = mRes.cudaPhases[level];
+ for (int iter = 0; iter < levelIterations; ++iter) {
+ for (int phase = 0; phase < phases.size(); ++phase) {
+ int* p = phases[phase];
+ UpdateOrientation(p, mRes.mPhases[level][phase].size(), N, Q, adj, adjOffset,
+ mRes.mAdj[level][phase].size());
+ }
+ }
+ if (level > 0) {
+ glm::dvec3* srcField = mRes.cudaQ[level];
+ glm::ivec2* toUpper = mRes.cudaToUpper[level - 1];
+ glm::dvec3* destField = mRes.cudaQ[level - 1];
+ glm::dvec3* N = mRes.cudaN[level - 1];
+ PropagateOrientationUpper(srcField, mRes.mQ[level].cols(), toUpper, N, destField);
+ }
+ }
+
+ for (int l = 0; l < mRes.mN.size() - 1; ++l) {
+ glm::dvec3* N = mRes.cudaN[l];
+ glm::dvec3* N_next = mRes.cudaN[l + 1];
+ glm::dvec3* Q = mRes.cudaQ[l];
+ glm::dvec3* Q_next = mRes.cudaQ[l + 1];
+ glm::ivec2* toUpper = mRes.cudaToUpper[l];
+
+ PropagateOrientationLower(toUpper, Q, N, Q_next, N_next, mRes.mToUpper[l].cols());
+ }
+}
+
+void Optimizer::optimize_positions_cuda(Hierarchy& mRes) {
+ int levelIterations = 6;
+ for (int level = mRes.mAdj.size() - 1; level >= 0; --level) {
+ Link* adj = mRes.cudaAdj[level];
+ int* adjOffset = mRes.cudaAdjOffset[level];
+ glm::dvec3* N = mRes.cudaN[level];
+ glm::dvec3* Q = mRes.cudaQ[level];
+ glm::dvec3* V = mRes.cudaV[level];
+ glm::dvec3* O = mRes.cudaO[level];
+ std::vector<int*> phases = mRes.cudaPhases[level];
+ for (int iter = 0; iter < levelIterations; ++iter) {
+ for (int phase = 0; phase < phases.size(); ++phase) {
+ int* p = phases[phase];
+ UpdatePosition(p, mRes.mPhases[level][phase].size(), N, Q, adj, adjOffset,
+ mRes.mAdj[level][phase].size(), V, O, mRes.mScale);
+ }
+ }
+ if (level > 0) {
+ glm::dvec3* srcField = mRes.cudaO[level];
+ glm::ivec2* toUpper = mRes.cudaToUpper[level - 1];
+ glm::dvec3* destField = mRes.cudaO[level - 1];
+ glm::dvec3* N = mRes.cudaN[level - 1];
+ glm::dvec3* V = mRes.cudaV[level - 1];
+ PropagatePositionUpper(srcField, mRes.mO[level].cols(), toUpper, N, V, destField);
+ }
+ }
+}
+
+#endif
+
+} // namespace qflow
diff --git a/extern/quadriflow/src/optimizer.hpp b/extern/quadriflow/src/optimizer.hpp
new file mode 100644
index 00000000000..ad6fa720a6e
--- /dev/null
+++ b/extern/quadriflow/src/optimizer.hpp
@@ -0,0 +1,56 @@
+#ifndef OPTIMIZER_H_
+#define OPTIMIZER_H_
+#include "config.hpp"
+#include "field-math.hpp"
+#include "hierarchy.hpp"
+
+namespace qflow {
+
+class Optimizer {
+ public:
+ Optimizer();
+ static void optimize_orientations(Hierarchy& mRes);
+ static void optimize_scale(Hierarchy& mRes, VectorXd& rho, int adaptive);
+ static void optimize_positions(Hierarchy& mRes, int with_scale = 0);
+ static void optimize_integer_constraints(Hierarchy& mRes, std::map<int, int>& singularities,
+ bool use_minimum_cost_flow);
+ static void optimize_positions_fixed(
+ Hierarchy& mRes, std::vector<DEdge>& edge_values, std::vector<Vector2i>& edge_diff,
+ std::set<int>& sharp_vertices,
+ std::map<int, std::pair<Vector3d, Vector3d>>& sharp_constraints, int with_scale = 0);
+ static void optimize_positions_sharp(
+ Hierarchy& mRes, std::vector<DEdge>& edge_values, std::vector<Vector2i>& edge_diff,
+ std::vector<int>& sharp_edges, std::set<int>& sharp_vertices,
+ std::map<int, std::pair<Vector3d, Vector3d>>& sharp_constraints, int with_scale = 0);
+ static void optimize_positions_dynamic(
+ MatrixXi& F, MatrixXd& V, MatrixXd& N, MatrixXd& Q, std::vector<std::vector<int>>& Vset,
+ std::vector<Vector3d>& O_compact, std::vector<Vector4i>& F_compact,
+ std::vector<int>& V2E_compact, std::vector<int>& E2E_compact, double mScale,
+ std::vector<Vector3d>& diffs, std::vector<int>& diff_count,
+ std::map<std::pair<int, int>, int>& o2e, std::vector<int>& sharp_o,
+ std::map<int, std::pair<Vector3d, Vector3d>>& compact_sharp_constraints, int with_scale);
+#ifdef WITH_CUDA
+ static void optimize_orientations_cuda(Hierarchy& mRes);
+ static void optimize_positions_cuda(Hierarchy& mRes);
+#endif
+};
+
+#ifdef WITH_CUDA
+extern void UpdateOrientation(int* phase, int num_phases, glm::dvec3* N, glm::dvec3* Q, Link* adj,
+ int* adjOffset, int num_adj);
+extern void PropagateOrientationUpper(glm::dvec3* srcField, int num_orientation,
+ glm::ivec2* toUpper, glm::dvec3* N, glm::dvec3* destField);
+extern void PropagateOrientationLower(glm::ivec2* toUpper, glm::dvec3* Q, glm::dvec3* N,
+ glm::dvec3* Q_next, glm::dvec3* N_next, int num_toUpper);
+
+extern void UpdatePosition(int* phase, int num_phases, glm::dvec3* N, glm::dvec3* Q, Link* adj,
+ int* adjOffset, int num_adj, glm::dvec3* V, glm::dvec3* O,
+ double scale);
+extern void PropagatePositionUpper(glm::dvec3* srcField, int num_position, glm::ivec2* toUpper,
+ glm::dvec3* N, glm::dvec3* V, glm::dvec3* destField);
+
+#endif
+
+} // namespace qflow
+
+#endif
diff --git a/extern/quadriflow/src/parametrizer-flip.cpp b/extern/quadriflow/src/parametrizer-flip.cpp
new file mode 100644
index 00000000000..67b6ebbb8e2
--- /dev/null
+++ b/extern/quadriflow/src/parametrizer-flip.cpp
@@ -0,0 +1,583 @@
+#include "dedge.hpp"
+#include "parametrizer.hpp"
+
+#include <algorithm>
+#include <queue>
+#include <unordered_map>
+#include <vector>
+
+namespace qflow {
+
+double Parametrizer::QuadEnergy(std::vector<int>& loop_vertices, std::vector<Vector4i>& res_quads,
+ int level) {
+ if (loop_vertices.size() < 4) return 0;
+ if (loop_vertices.size() == 4) {
+ double energy = 0;
+ for (int j = 0; j < 4; ++j) {
+ int v0 = loop_vertices[j];
+ int v2 = loop_vertices[(j + 1) % 4];
+ int v1 = loop_vertices[(j + 3) % 4];
+ Vector3d pt1 = (O_compact[v1] - O_compact[v0]).normalized();
+ Vector3d pt2 = (O_compact[v2] - O_compact[v0]).normalized();
+ Vector3d n = pt1.cross(pt2);
+ double sina = n.norm();
+ if (n.dot(N_compact[v0]) < 0) sina = -sina;
+ double cosa = pt1.dot(pt2);
+ double angle = atan2(sina, cosa) / 3.141592654 * 180.0;
+ if (angle < 0) angle = 360 + angle;
+ energy += angle * angle;
+ }
+ res_quads.push_back(
+ Vector4i(loop_vertices[0], loop_vertices[3], loop_vertices[2], loop_vertices[1]));
+ return energy;
+ }
+ double max_energy = 1e30;
+ for (int seg1 = 2; seg1 < loop_vertices.size(); seg1 += 2) {
+ for (int seg2 = seg1 + 1; seg2 < loop_vertices.size(); seg2 += 2) {
+ std::vector<Vector4i> quads[4];
+ std::vector<int> vertices = {loop_vertices[0], loop_vertices[1], loop_vertices[seg1],
+ loop_vertices[seg2]};
+ double energy = 0;
+ energy += QuadEnergy(vertices, quads[0], level + 1);
+ if (seg1 > 2) {
+ std::vector<int> vertices(loop_vertices.begin() + 1, loop_vertices.begin() + seg1);
+ vertices.push_back(loop_vertices[seg1]);
+ energy += QuadEnergy(vertices, quads[1], level + 1);
+ }
+ if (seg2 != seg1 + 1) {
+ std::vector<int> vertices(loop_vertices.begin() + seg1,
+ loop_vertices.begin() + seg2);
+ vertices.push_back(loop_vertices[seg2]);
+ energy += QuadEnergy(vertices, quads[2], level + 2);
+ }
+ if (seg2 + 1 != loop_vertices.size()) {
+ std::vector<int> vertices(loop_vertices.begin() + seg2, loop_vertices.end());
+ vertices.push_back(loop_vertices[0]);
+ energy += QuadEnergy(vertices, quads[3], level + 1);
+ }
+ if (max_energy > energy) {
+ max_energy = energy;
+ res_quads.clear();
+ for (int i = 0; i < 4; ++i) {
+ for (auto& v : quads[i]) {
+ res_quads.push_back(v);
+ }
+ }
+ }
+ }
+ }
+ return max_energy;
+}
+
+void Parametrizer::FixHoles(std::vector<int>& loop_vertices) {
+ std::vector<std::vector<int>> loop_vertices_array;
+ std::unordered_map<int, int> map_loops;
+ for (int i = 0; i < loop_vertices.size(); ++i) {
+ if (map_loops.count(loop_vertices[i])) {
+ int j = map_loops[loop_vertices[i]];
+ loop_vertices_array.push_back(std::vector<int>());
+ if (i - j > 3 && (i - j) % 2 == 0) {
+ for (int k = j; k < i; ++k) {
+ if (map_loops.count(loop_vertices[k])) {
+ loop_vertices_array.back().push_back(loop_vertices[k]);
+ map_loops.erase(loop_vertices[k]);
+ }
+ }
+ }
+ }
+ map_loops[loop_vertices[i]] = i;
+ }
+ if (map_loops.size() >= 3) {
+ loop_vertices_array.push_back(std::vector<int>());
+ for (int k = 0; k < loop_vertices.size(); ++k) {
+ if (map_loops.count(loop_vertices[k])) {
+ if (map_loops.count(loop_vertices[k])) {
+ loop_vertices_array.back().push_back(loop_vertices[k]);
+ map_loops.erase(loop_vertices[k]);
+ }
+ }
+ }
+ }
+ for (int i = 0; i < loop_vertices_array.size(); ++i) {
+ auto& loop_vertices = loop_vertices_array[i];
+ if (loop_vertices.size() == 0) return;
+ std::vector<Vector4i> quads;
+#ifdef LOG_OUTPUT
+// printf("Compute energy for loop: %d\n", (int)loop_vertices.size());
+#endif
+ QuadEnergy(loop_vertices, quads, 0);
+#ifdef LOG_OUTPUT
+// printf("quads: %d\n", quads.size());
+#endif
+ for (auto& p : quads) {
+ bool flag = false;
+ for (int j = 0; j < 4; ++j) {
+ int v1 = p[j];
+ int v2 = p[(j + 1) % 4];
+ auto key = std::make_pair(v1, v2);
+ if (Quad_edges.count(key)) {
+ flag = true;
+ break;
+ }
+ }
+ if (!flag) {
+ for (int j = 0; j < 4; ++j) {
+ int v1 = p[j];
+ int v2 = p[(j + 1) % 4];
+ auto key = std::make_pair(v1, v2);
+ Quad_edges.insert(key);
+ }
+ F_compact.push_back(p);
+ }
+ }
+ }
+}
+
+void Parametrizer::FixHoles() {
+ for (int i = 0; i < F_compact.size(); ++i) {
+ for (int j = 0; j < 4; ++j) {
+ int v1 = F_compact[i][j];
+ int v2 = F_compact[i][(j + 1) % 4];
+ auto key = std::make_pair(v1, v2);
+ Quad_edges.insert(key);
+ }
+ }
+ std::vector<int> detected_boundary(E2E_compact.size(), 0);
+ for (int i = 0; i < E2E_compact.size(); ++i) {
+ if (detected_boundary[i] != 0 || E2E_compact[i] != -1) continue;
+ std::vector<int> loop_edges;
+ int current_e = i;
+
+ while (detected_boundary[current_e] == 0) {
+ detected_boundary[current_e] = 1;
+ loop_edges.push_back(current_e);
+ current_e = current_e / 4 * 4 + (current_e + 1) % 4;
+ while (E2E_compact[current_e] != -1) {
+ current_e = E2E_compact[current_e];
+ current_e = current_e / 4 * 4 + (current_e + 1) % 4;
+ }
+ }
+ std::vector<int> loop_vertices(loop_edges.size());
+ for (int j = 0; j < loop_edges.size(); ++j) {
+ loop_vertices[j] = F_compact[loop_edges[j] / 4][loop_edges[j] % 4];
+ }
+ if (loop_vertices.size() < 25) FixHoles(loop_vertices);
+ }
+}
+
+void Parametrizer::FixFlipHierarchy() {
+ Hierarchy fh;
+ fh.DownsampleEdgeGraph(face_edgeOrients, face_edgeIds, edge_diff, allow_changes, -1);
+ fh.FixFlip();
+ fh.UpdateGraphValue(face_edgeOrients, face_edgeIds, edge_diff);
+}
+
+void Parametrizer::FixFlipSat() {
+#ifdef LOG_OUTPUT
+ printf("Solving SAT!\n");
+#endif
+
+ if (!this->flag_aggresive_sat) return;
+
+ for (int threshold = 1; threshold <= 4; ++threshold) {
+ lprintf("[FixFlipSat] threshold = %d\n", threshold);
+
+ Hierarchy fh;
+ fh.DownsampleEdgeGraph(face_edgeOrients, face_edgeIds, edge_diff, allow_changes, -1);
+ int nflip = 0;
+ for (int depth = std::min(5, (int)fh.mFQ.size() - 1); depth >= 0; --depth) {
+ nflip = fh.FixFlipSat(depth, threshold);
+ if (depth > 0) fh.PushDownwardFlip(depth);
+ if (nflip == 0) break;
+ }
+ fh.UpdateGraphValue(face_edgeOrients, face_edgeIds, edge_diff);
+ if (nflip == 0) break;
+ }
+}
+
+void Parametrizer::AdvancedExtractQuad() {
+ Hierarchy fh;
+ fh.DownsampleEdgeGraph(face_edgeOrients, face_edgeIds, edge_diff, allow_changes, -1);
+ auto& V = hierarchy.mV[0];
+ auto& F = hierarchy.mF;
+ disajoint_tree = DisajointTree(V.cols());
+ auto& diffs = fh.mEdgeDiff.front();
+ for (int i = 0; i < diffs.size(); ++i) {
+ if (diffs[i] == Vector2i::Zero()) {
+ disajoint_tree.Merge(edge_values[i].x, edge_values[i].y);
+ }
+ }
+ disajoint_tree.BuildCompactParent();
+ auto& F2E = fh.mF2E.back();
+ auto& E2F = fh.mE2F.back();
+ auto& EdgeDiff = fh.mEdgeDiff.back();
+ auto& FQ = fh.mFQ.back();
+
+ std::vector<int> edge(E2F.size());
+ std::vector<int> face(F2E.size());
+ for (int i = 0; i < diffs.size(); ++i) {
+ int t = i;
+ for (int j = 0; j < fh.mToUpperEdges.size(); ++j) {
+ t = fh.mToUpperEdges[j][t];
+ if (t < 0) break;
+ }
+ if (t >= 0) edge[t] = i;
+ }
+ for (int i = 0; i < F.cols(); ++i) {
+ int t = i;
+ for (int j = 0; j < fh.mToUpperFaces.size(); ++j) {
+ t = fh.mToUpperFaces[j][t];
+ if (t < 0) break;
+ }
+ if (t >= 0) face[t] = i;
+ }
+ fh.UpdateGraphValue(face_edgeOrients, face_edgeIds, edge_diff);
+
+ auto& O = hierarchy.mO[0];
+ auto& Q = hierarchy.mQ[0];
+ auto& N = hierarchy.mN[0];
+ int num_v = disajoint_tree.CompactNum();
+ Vset.resize(num_v);
+ O_compact.resize(num_v, Vector3d::Zero());
+ Q_compact.resize(num_v, Vector3d::Zero());
+ N_compact.resize(num_v, Vector3d::Zero());
+ counter.resize(num_v, 0);
+ for (int i = 0; i < O.cols(); ++i) {
+ int compact_v = disajoint_tree.Index(i);
+ Vset[compact_v].push_back(i);
+ O_compact[compact_v] += O.col(i);
+ N_compact[compact_v] = N_compact[compact_v] * counter[compact_v] + N.col(i);
+ N_compact[compact_v].normalize();
+ if (counter[compact_v] == 0)
+ Q_compact[compact_v] = Q.col(i);
+ else {
+ auto pairs = compat_orientation_extrinsic_4(Q_compact[compact_v], N_compact[compact_v],
+ Q.col(i), N.col(i));
+ Q_compact[compact_v] = (pairs.first * counter[compact_v] + pairs.second).normalized();
+ }
+ counter[compact_v] += 1;
+ }
+ for (int i = 0; i < O_compact.size(); ++i) {
+ O_compact[i] /= counter[i];
+ }
+
+ BuildTriangleManifold(disajoint_tree, edge, face, edge_values, F2E, E2F, EdgeDiff, FQ);
+}
+
+void Parametrizer::BuildTriangleManifold(DisajointTree& disajoint_tree, std::vector<int>& edge,
+ std::vector<int>& face, std::vector<DEdge>& edge_values,
+ std::vector<Vector3i>& F2E, std::vector<Vector2i>& E2F,
+ std::vector<Vector2i>& EdgeDiff,
+ std::vector<Vector3i>& FQ) {
+ auto& F = hierarchy.mF;
+ std::vector<int> E2E(F2E.size() * 3, -1);
+ for (int i = 0; i < E2F.size(); ++i) {
+ int v1 = E2F[i][0];
+ int v2 = E2F[i][1];
+ int t1 = 0;
+ int t2 = 2;
+ if (v1 != -1)
+ while (F2E[v1][t1] != i) t1 += 1;
+ if (v2 != -1)
+ while (F2E[v2][t2] != i) t2 -= 1;
+ t1 += v1 * 3;
+ t2 += v2 * 3;
+ if (v1 != -1)
+ E2E[t1] = (v2 == -1) ? -1 : t2;
+ if (v2 != -1)
+ E2E[t2] = (v1 == -1) ? -1 : t1;
+ }
+
+ std::vector<Vector3i> triangle_vertices(F2E.size(), Vector3i(-1, -1, -1));
+ int num_v = 0;
+ std::vector<Vector3d> N, Q, O;
+ std::vector<std::vector<int>> Vs;
+ for (int i = 0; i < F2E.size(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ if (triangle_vertices[i][j] != -1) continue;
+ int f = face[i];
+ int v = disajoint_tree.Index(F(j, f));
+ Vs.push_back(Vset[v]);
+ Q.push_back(Q_compact[v]);
+ N.push_back(N_compact[v]);
+ O.push_back(O_compact[v]);
+ int deid0 = i * 3 + j;
+ int deid = deid0;
+ do {
+ triangle_vertices[deid / 3][deid % 3] = num_v;
+ deid = E2E[deid / 3 * 3 + (deid + 2) % 3];
+ } while (deid != deid0 && deid != -1);
+ if (deid == -1) {
+ deid = deid0;
+ do {
+ deid = E2E[deid];
+ if (deid == -1)
+ break;
+ deid = deid / 3 * 3 + (deid + 1) % 3;
+ triangle_vertices[deid/3][deid%3] = num_v;
+ } while (deid != -1);
+ }
+ num_v += 1;
+ }
+ }
+
+ int num_v0 = num_v;
+ do {
+ num_v0 = num_v;
+ std::vector<std::vector<int>> vert_to_dedge(num_v);
+ for (int i = 0; i < triangle_vertices.size(); ++i) {
+ Vector3i pt = triangle_vertices[i];
+ if (pt[0] == pt[1] || pt[1] == pt[2] || pt[2] == pt[0]) {
+ for (int j = 0; j < 3; ++j) {
+ int t = E2E[i * 3 + j];
+ if (t != -1) E2E[t] = -1;
+ }
+ for (int j = 0; j < 3; ++j) {
+ E2E[i * 3 + j] = -1;
+ }
+ } else {
+ for (int j = 0; j < 3; ++j)
+ vert_to_dedge[triangle_vertices[i][j]].push_back(i * 3 + j);
+ }
+ }
+ std::vector<int> colors(triangle_vertices.size() * 3, -1),
+ reverse_colors(triangle_vertices.size() * 3, -1);
+ for (int i = 0; i < vert_to_dedge.size(); ++i) {
+ int num_color = 0;
+ for (int j = 0; j < vert_to_dedge[i].size(); ++j) {
+ int deid = vert_to_dedge[i][j];
+ if (colors[deid] != -1) continue;
+ std::list<int> l;
+ int deid0 = deid;
+ do {
+ l.push_back(deid);
+ deid = deid / 3 * 3 + (deid + 2) % 3;
+ deid = E2E[deid];
+ } while (deid != -1 && deid != deid0);
+ if (deid == -1) {
+ deid = deid0;
+ do {
+ deid = E2E[deid];
+ if (deid == -1) break;
+ deid = deid / 3 * 3 + (deid + 1) % 3;
+ if (deid == deid0) break;
+ l.push_front(deid);
+ } while (true);
+ }
+ std::vector<int> dedges;
+ for (auto& e : l) dedges.push_back(e);
+ std::map<std::pair<int, int>, int> loc;
+ std::vector<int> deid_colors(dedges.size(), num_color);
+ num_color += 1;
+ for (int jj = 0; jj < dedges.size(); ++jj) {
+ int deid = dedges[jj];
+ colors[deid] = 0;
+ int v1 = triangle_vertices[deid / 3][deid % 3];
+ int v2 = triangle_vertices[deid / 3][(deid + 1) % 3];
+ std::pair<int, int> pt(v1, v2);
+ if (loc.count(pt)) {
+ int s = loc[pt];
+ for (int k = s; k < jj; ++k) {
+ int deid1 = dedges[k];
+ int v11 = triangle_vertices[deid1 / 3][deid1 % 3];
+ int v12 = triangle_vertices[deid1 / 3][(deid1 + 1) % 3];
+ std::pair<int, int> pt1(v11, v12);
+ loc.erase(pt1);
+ deid_colors[k] = num_color;
+ }
+ num_color += 1;
+ }
+ loc[pt] = jj;
+ }
+ for (int j = 0; j < dedges.size(); ++j) {
+ int deid = dedges[j];
+ int color = deid_colors[j];
+ if (color > 0) {
+ triangle_vertices[deid / 3][deid % 3] = num_v + color - 1;
+ }
+ }
+ }
+ if (num_color > 1) {
+ for (int j = 0; j < num_color - 1; ++j) {
+ Vs.push_back(Vs[i]);
+ O.push_back(O[i]);
+ N.push_back(N[i]);
+ Q.push_back(Q[i]);
+ }
+ num_v += num_color - 1;
+ }
+ }
+ } while (num_v != num_v0);
+ int offset = 0;
+ std::vector<Vector3i> triangle_edges, triangle_orients;
+ for (int i = 0; i < triangle_vertices.size(); ++i) {
+ Vector3i pt = triangle_vertices[i];
+ if (pt[0] == pt[1] || pt[1] == pt[2] || pt[2] == pt[0]) continue;
+ triangle_vertices[offset++] = triangle_vertices[i];
+ triangle_edges.push_back(F2E[i]);
+ triangle_orients.push_back(FQ[i]);
+ }
+ triangle_vertices.resize(offset);
+ std::set<int> flip_vertices;
+ for (int i = 0; i < triangle_vertices.size(); ++i) {
+ Vector2i d1 = rshift90(EdgeDiff[triangle_edges[i][0]], triangle_orients[i][0]);
+ Vector2i d2 = rshift90(EdgeDiff[triangle_edges[i][1]], triangle_orients[i][1]);
+ int area = d1[0] * d2[1] - d1[1] * d2[0];
+ if (area < 0) {
+ for (int j = 0; j < 3; ++j) {
+ flip_vertices.insert(triangle_vertices[i][j]);
+ }
+ }
+ }
+ MatrixXd NV(3, num_v);
+ MatrixXi NF(3, triangle_vertices.size());
+ memcpy(NF.data(), triangle_vertices.data(), sizeof(int) * 3 * triangle_vertices.size());
+ VectorXi NV2E, NE2E, NB, NN;
+ compute_direct_graph(NV, NF, NV2E, NE2E, NB, NN);
+
+ std::map<DEdge, std::pair<Vector3i, Vector3i>> quads;
+ for (int i = 0; i < triangle_vertices.size(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ int e = triangle_edges[i][j];
+ int v1 = triangle_vertices[i][j];
+ int v2 = triangle_vertices[i][(j + 1) % 3];
+ int v3 = triangle_vertices[i][(j + 2) % 3];
+ if (abs(EdgeDiff[e][0]) == 1 && abs(EdgeDiff[e][1]) == 1) {
+ DEdge edge(v1, v2);
+ if (quads.count(edge))
+ quads[edge].second = Vector3i(v1, v2, v3);
+ else
+ quads[edge] = std::make_pair(Vector3i(v1, v2, v3), Vector3i(-1, -1, -1));
+ }
+ }
+ }
+
+ for (auto& p : quads) {
+ if (p.second.second[0] != -1 && p.second.first[2] != p.second.second[2]) {
+ F_compact.push_back(Vector4i(p.second.first[1], p.second.first[2], p.second.first[0],
+ p.second.second[2]));
+ }
+ }
+ std::swap(Vs, Vset);
+ std::swap(O_compact, O);
+ std::swap(N_compact, N);
+ std::swap(Q_compact, Q);
+ compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact,
+ nonManifold_compact);
+
+ while (true) {
+ std::vector<int> erasedF(F_compact.size(), 0);
+ for (int i = 0; i < F_compact.size(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ for (int k = j + 1; k < 4; ++k) {
+ if (F_compact[i][j] == F_compact[i][k]) {
+ erasedF[i] = 1;
+ }
+ }
+ }
+ }
+ for (int i = 0; i < O_compact.size(); ++i) {
+ int v = 0;
+ int e0 = V2E_compact[i];
+ if (e0 == -1) continue;
+ std::vector<int> dedges;
+ int e = e0;
+ do {
+ dedges.push_back(e);
+ v += 1;
+ e = e / 4 * 4 + (e + 3) % 4;
+ e = E2E_compact[e];
+ } while (e != e0 && e != -1);
+ if (e == -1) {
+ int e = e0;
+ while (true) {
+ e = E2E_compact[e];
+ if (e == -1) break;
+ e = e / 4 * 4 + (e + 1) % 4;
+ v += 1;
+ dedges.push_back(e);
+ }
+ }
+ if (v == 2) {
+ // erasedF[dedges[1] / 4] = 1;
+ // F_compact[dedges[0]/4][dedges[0]%4] =
+ // F_compact[dedges[1]/4][(dedges[1]+2)%4];
+ }
+ }
+ offset = 0;
+ for (int i = 0; i < F_compact.size(); ++i) {
+ if (erasedF[i] == 0) F_compact[offset++] = F_compact[i];
+ }
+ if (offset == F_compact.size()) break;
+ F_compact.resize(offset);
+ compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact,
+ nonManifold_compact);
+ }
+ FixHoles();
+ compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact,
+ nonManifold_compact);
+
+ /*
+ for (auto& p : flip_vertices) {
+ int deid0 = V2E_compact[p];
+ int deid = deid0;
+ std::list<int> dedges;
+ if (deid0 != -1) {
+ do {
+ dedges.push_back(deid);
+ deid = E2E_compact[deid/4*4 + (deid+3) % 4];
+ } while (deid != -1 && deid != deid0);
+ if (deid == -1) {
+ deid = deid0;
+ do {
+ deid = E2E_compact[deid];
+ if (deid == -1)
+ break;
+ deid = deid/4*4 + (deid +1) % 4;
+ dedges.push_front(deid);
+ } while (deid != -1 && deid != deid0);
+ }
+ std::set<int> eraseF;
+ std::set<int> valid_dedges;
+ std::set<int> boundaries;
+ std::vector<int> loop_vertices;
+ for (auto& dedge : dedges) {
+ int f = dedge / 4;
+ eraseF.insert(f);
+ valid_dedges.insert(E2E_compact[f * 4 + (dedge+1)%4]);
+ valid_dedges.insert(E2E_compact[f * 4 + (dedge+2)%4]);
+ loop_vertices.push_back(F_compact[f][(dedge+1)%4]);
+ loop_vertices.push_back(F_compact[f][(dedge+2)%4]);
+ boundaries.insert(F_compact[f][(dedge+1)%4]);
+ boundaries.insert(F_compact[f][(dedge+2)%4]);
+ }
+ int offset = 0;
+ auto it = eraseF.begin();
+ for (int i = 0; i < F_compact.size(); ++i) {
+ if (it == eraseF.end() || i != *it) {
+ bool need_erase = false;
+ for (int j = 0; j < 4; ++j) {
+ if (valid_dedges.count(i * 4 + j) == 0 && boundaries.count(F_compact[i][j])
+ && boundaries.count(F_compact[i][(j + 1) % 4])) { need_erase = true;
+ }
+ }
+ if (!need_erase)
+ F_compact[offset++] = F_compact[i];
+ } else {
+ it++;
+ }
+ }
+ F_compact.resize(offset);
+ compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact,
+ boundary_compact, nonManifold_compact); std::reverse(loop_vertices.begin(),
+ loop_vertices.end()); FixHoles(loop_vertices); compute_direct_graph_quad(O_compact, F_compact,
+ V2E_compact, E2E_compact, boundary_compact, nonManifold_compact);
+ }
+ }
+ FixHoles();
+ compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact,
+ nonManifold_compact);
+ */
+}
+
+} // namespace qflow
diff --git a/extern/quadriflow/src/parametrizer-int.cpp b/extern/quadriflow/src/parametrizer-int.cpp
new file mode 100644
index 00000000000..08fa36c1baa
--- /dev/null
+++ b/extern/quadriflow/src/parametrizer-int.cpp
@@ -0,0 +1,425 @@
+#include "parametrizer.hpp"
+
+#include <queue>
+#include <unordered_map>
+#include <vector>
+#include <random>
+#include "optimizer.hpp"
+
+namespace qflow {
+
+
+void Parametrizer::BuildEdgeInfo() {
+ auto& F = hierarchy.mF;
+ auto& E2E = hierarchy.mE2E;
+
+ edge_diff.clear();
+ edge_values.clear();
+ face_edgeIds.resize(F.cols(), Vector3i(-1, -1, -1));
+ for (int i = 0; i < F.cols(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ int k1 = j, k2 = (j + 1) % 3;
+ int v1 = F(k1, i);
+ int v2 = F(k2, i);
+ DEdge e2(v1, v2);
+ Vector2i diff2;
+ int rank2;
+ if (v1 > v2) {
+ rank2 = pos_rank(k2, i);
+ diff2 =
+ rshift90(Vector2i(-pos_index(k1 * 2, i), -pos_index(k1 * 2 + 1, i)), rank2);
+ } else {
+ rank2 = pos_rank(k1, i);
+ diff2 = rshift90(Vector2i(pos_index(k1 * 2, i), pos_index(k1 * 2 + 1, i)), rank2);
+ }
+ int current_eid = i * 3 + k1;
+ int eid = E2E[current_eid];
+ int eID1 = face_edgeIds[current_eid / 3][current_eid % 3];
+ int eID2 = -1;
+ if (eID1 == -1) {
+ eID2 = edge_values.size();
+ edge_values.push_back(e2);
+ edge_diff.push_back(diff2);
+ face_edgeIds[i][k1] = eID2;
+ if (eid != -1) face_edgeIds[eid / 3][eid % 3] = eID2;
+ } else if (!singularities.count(i)) {
+ eID2 = face_edgeIds[eid / 3][eid % 3];
+ edge_diff[eID2] = diff2;
+ }
+ }
+ }
+}
+
+void Parametrizer::BuildIntegerConstraints() {
+ auto& F = hierarchy.mF;
+ auto& Q = hierarchy.mQ[0];
+ auto& N = hierarchy.mN[0];
+ face_edgeOrients.resize(F.cols());
+
+ //Random number generator (for shuffling)
+ std::random_device rd;
+ std::mt19937 g(rd());
+ g.seed(hierarchy.rng_seed);
+
+ // undirected edge to direct edge
+ std::vector<std::pair<int, int>> E2D(edge_diff.size(), std::make_pair(-1, -1));
+ for (int i = 0; i < F.cols(); ++i) {
+ int v0 = F(0, i);
+ int v1 = F(1, i);
+ int v2 = F(2, i);
+ DEdge e0(v0, v1), e1(v1, v2), e2(v2, v0);
+ const Vector3i& eid = face_edgeIds[i];
+ Vector2i variable_id[3];
+ for (int i = 0; i < 3; ++i) {
+ variable_id[i] = Vector2i(eid[i] * 2 + 1, eid[i] * 2 + 2);
+ }
+ auto index1 =
+ compat_orientation_extrinsic_index_4(Q.col(v0), N.col(v0), Q.col(v1), N.col(v1));
+ auto index2 =
+ compat_orientation_extrinsic_index_4(Q.col(v0), N.col(v0), Q.col(v2), N.col(v2));
+
+ int rank1 = (index1.first - index1.second + 4) % 4; // v1 -> v0
+ int rank2 = (index2.first - index2.second + 4) % 4; // v2 -> v0
+ int orients[3] = {0}; // == {0, 0, 0}
+ if (v1 < v0) {
+ variable_id[0] = -rshift90(variable_id[0], rank1);
+ orients[0] = (rank1 + 2) % 4;
+ } else {
+ orients[0] = 0;
+ }
+ if (v2 < v1) {
+ variable_id[1] = -rshift90(variable_id[1], rank2);
+ orients[1] = (rank2 + 2) % 4;
+ } else {
+ variable_id[1] = rshift90(variable_id[1], rank1);
+ orients[1] = rank1;
+ }
+ if (v2 < v0) {
+ variable_id[2] = rshift90(variable_id[2], rank2);
+ orients[2] = rank2;
+ } else {
+ variable_id[2] = -variable_id[2];
+ orients[2] = 2;
+ }
+ face_edgeOrients[i] = Vector3i(orients[0], orients[1], orients[2]);
+ for (int j = 0; j < 3; ++j) {
+ int eid = face_edgeIds[i][j];
+ if (E2D[eid].first == -1)
+ E2D[eid].first = i * 3 + j;
+ else
+ E2D[eid].second = i * 3 + j;
+ }
+ }
+
+ // a face disajoint tree
+ DisajointOrientTree disajoint_orient_tree = DisajointOrientTree(F.cols());
+ // merge the whole face graph except for the singularity in which there exists a spanning tree
+ // which contains consistent orientation
+ std::vector<int> sharpUE(E2D.size());
+ for (int i = 0; i < sharp_edges.size(); ++i) {
+ if (sharp_edges[i]) {
+ sharpUE[face_edgeIds[i / 3][i % 3]] = 1;
+ }
+ }
+
+ for (int i = 0; i < E2D.size(); ++i) {
+ auto& edge_c = E2D[i];
+ int f0 = edge_c.first / 3;
+ int f1 = edge_c.second / 3;
+ if (edge_c.first == -1 || edge_c.second == -1) continue;
+ if (singularities.count(f0) || singularities.count(f1) || sharpUE[i]) continue;
+ int orient1 = face_edgeOrients[f0][edge_c.first % 3];
+ int orient0 = (face_edgeOrients[f1][edge_c.second % 3] + 2) % 4;
+ disajoint_orient_tree.Merge(f0, f1, orient0, orient1);
+ }
+
+ // merge singularity later
+ for (auto& f : singularities) {
+ for (int i = 0; i < 3; ++i) {
+ if (sharpUE[face_edgeIds[f.first][i]]) continue;
+ auto& edge_c = E2D[face_edgeIds[f.first][i]];
+ if (edge_c.first == -1 || edge_c.second == -1) continue;
+ int v0 = edge_c.first / 3;
+ int v1 = edge_c.second / 3;
+ int orient1 = face_edgeOrients[v0][edge_c.first % 3];
+ int orient0 = (face_edgeOrients[v1][edge_c.second % 3] + 2) % 4;
+ disajoint_orient_tree.Merge(v0, v1, orient0, orient1);
+ }
+ }
+
+ for (int i = 0; i < sharpUE.size(); ++i) {
+ if (sharpUE[i] == 0) continue;
+ auto& edge_c = E2D[i];
+ if (edge_c.first == -1 || edge_c.second == -1) continue;
+ int f0 = edge_c.first / 3;
+ int f1 = edge_c.second / 3;
+ int orient1 = face_edgeOrients[f0][edge_c.first % 3];
+ int orient0 = (face_edgeOrients[f1][edge_c.second % 3] + 2) % 4;
+ disajoint_orient_tree.Merge(f0, f1, orient0, orient1);
+ }
+
+ // all the face has the same parent. we rotate every face to the space of that parent.
+ for (int i = 0; i < face_edgeOrients.size(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ face_edgeOrients[i][j] =
+ (face_edgeOrients[i][j] + disajoint_orient_tree.Orient(i)) % 4;
+ }
+ }
+
+ std::vector<int> sharp_colors(face_edgeIds.size(), -1);
+ int num_sharp_component = 0;
+ // label the connected component connected by non-fixed edges
+ // we need this because we need sink flow (demand) == source flow (supply) for each component
+ // rather than global
+ for (int i = 0; i < sharp_colors.size(); ++i) {
+ if (sharp_colors[i] != -1) continue;
+ sharp_colors[i] = num_sharp_component;
+ std::queue<int> q;
+ q.push(i);
+ int counter = 0;
+ while (!q.empty()) {
+ int v = q.front();
+ q.pop();
+ for (int i = 0; i < 3; ++i) {
+ int e = face_edgeIds[v][i];
+ int deid1 = E2D[e].first;
+ int deid2 = E2D[e].second;
+ if (deid1 == -1 || deid2 == -1) continue;
+ if (abs(face_edgeOrients[deid1 / 3][deid1 % 3] -
+ face_edgeOrients[deid2 / 3][deid2 % 3] + 4) %
+ 4 !=
+ 2 ||
+ sharpUE[e]) {
+ continue;
+ }
+ for (int k = 0; k < 2; ++k) {
+ int f = (k == 0) ? E2D[e].first / 3 : E2D[e].second / 3;
+ if (sharp_colors[f] == -1) {
+ sharp_colors[f] = num_sharp_component;
+ q.push(f);
+ }
+ }
+ }
+ counter += 1;
+ }
+ num_sharp_component += 1;
+ }
+ {
+ std::vector<int> total_flows(num_sharp_component);
+ // check if each component is full-flow
+ for (int i = 0; i < face_edgeIds.size(); ++i) {
+ Vector2i diff(0, 0);
+ for (int j = 0; j < 3; ++j) {
+ int orient = face_edgeOrients[i][j];
+ diff += rshift90(edge_diff[face_edgeIds[i][j]], orient);
+ }
+ total_flows[sharp_colors[i]] += diff[0] + diff[1];
+ }
+
+ // build "variable"
+ variables.resize(edge_diff.size() * 2, std::make_pair(Vector2i(-1, -1), 0));
+ for (int i = 0; i < face_edgeIds.size(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ Vector2i sign = rshift90(Vector2i(1, 1), face_edgeOrients[i][j]);
+ int eid = face_edgeIds[i][j];
+ Vector2i index = rshift90(Vector2i(eid * 2, eid * 2 + 1), face_edgeOrients[i][j]);
+ for (int k = 0; k < 2; ++k) {
+ auto& p = variables[abs(index[k])];
+ if (p.first[0] == -1)
+ p.first[0] = i * 2 + k;
+ else
+ p.first[1] = i * 2 + k;
+ p.second += sign[k];
+ }
+ }
+ }
+
+ // fixed variable that might be manually modified.
+ // modified_variables[component_od][].first = fixed_variable_id
+ // modified_variables[component_od][].second = 1 if two positive signs -1 if two negative
+ // signs
+ std::vector<std::vector<std::pair<int, int>>> modified_variables[2];
+ for (int i = 0; i < 2; ++i) modified_variables[i].resize(total_flows.size());
+ for (int i = 0; i < variables.size(); ++i) {
+ if ((variables[i].first[1] == -1 || variables[i].second != 0) &&
+ allow_changes[i] == 1) {
+ int find = sharp_colors[variables[i].first[0] / 2];
+ int step = std::abs(variables[i].second) % 2;
+ if (total_flows[find] > 0) {
+ if (variables[i].second > 0 && edge_diff[i / 2][i % 2] > -1) {
+ modified_variables[step][find].push_back(std::make_pair(i, -1));
+ }
+ if (variables[i].second < 0 && edge_diff[i / 2][i % 2] < 1) {
+ modified_variables[step][find].push_back(std::make_pair(i, 1));
+ }
+ } else if (total_flows[find] < 0) {
+ if (variables[i].second < 0 && edge_diff[i / 2][i % 2] > -1) {
+ modified_variables[step][find].push_back(std::make_pair(i, -1));
+ }
+ if (variables[i].second > 0 && edge_diff[i / 2][i % 2] < 1) {
+ modified_variables[step][find].push_back(std::make_pair(i, 1));
+ }
+ }
+ }
+ }
+
+ // uniformly random manually modify variables so that the network has full flow.
+ for (int i = 0; i < 2; ++i)
+ for (auto& modified_var : modified_variables[i])
+ std::shuffle(modified_var.begin(), modified_var.end(), g);
+
+ for (int j = 0; j < total_flows.size(); ++j) {
+ for (int ii = 0; ii < 2; ++ii) {
+ if (total_flows[j] == 0) continue;
+ int max_num;
+ if (ii == 0)
+ max_num =
+ std::min(abs(total_flows[j]) / 2, (int)modified_variables[ii][j].size());
+ else
+ max_num = std::min(abs(total_flows[j]), (int)modified_variables[ii][j].size());
+ int dir = (total_flows[j] > 0) ? -1 : 1;
+ for (int i = 0; i < max_num; ++i) {
+ auto& info = modified_variables[ii][j][i];
+ edge_diff[info.first / 2][info.first % 2] += info.second;
+ if (ii == 0)
+ total_flows[j] += 2 * dir;
+ else
+ total_flows[j] += dir;
+ }
+ }
+ }
+ }
+
+ std::vector<Vector4i> edge_to_constraints(E2D.size() * 2, Vector4i(-1, 0, -1, 0));
+ for (int i = 0; i < face_edgeIds.size(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ int e = face_edgeIds[i][j];
+ Vector2i index = rshift90(Vector2i(e * 2 + 1, e * 2 + 2), face_edgeOrients[i][j]);
+ for (int k = 0; k < 2; ++k) {
+ int l = abs(index[k]);
+ int s = index[k] / l;
+ int ind = l - 1;
+ int equationID = i * 2 + k;
+ if (edge_to_constraints[ind][0] == -1) {
+ edge_to_constraints[ind][0] = equationID;
+ edge_to_constraints[ind][1] = s;
+ } else {
+ edge_to_constraints[ind][2] = equationID;
+ edge_to_constraints[ind][3] = s;
+ }
+ }
+ }
+ }
+ std::vector<std::pair<Vector2i, int>> arcs;
+ std::vector<int> arc_ids;
+ DisajointTree tree(face_edgeIds.size() * 2);
+ for (int i = 0; i < edge_to_constraints.size(); ++i) {
+ if (allow_changes[i] == 0) continue;
+ if (edge_to_constraints[i][0] == -1 || edge_to_constraints[i][2] == -1) continue;
+ if (edge_to_constraints[i][1] == -edge_to_constraints[i][3]) {
+ int v1 = edge_to_constraints[i][0];
+ int v2 = edge_to_constraints[i][2];
+ tree.Merge(v1, v2);
+ if (edge_to_constraints[i][1] < 0) std::swap(v1, v2);
+ int current_v = edge_diff[i / 2][i % 2];
+ arcs.push_back(std::make_pair(Vector2i(v1, v2), current_v));
+ }
+ }
+ tree.BuildCompactParent();
+ std::vector<int> total_flows(tree.CompactNum());
+ // check if each component is full-flow
+ for (int i = 0; i < face_edgeIds.size(); ++i) {
+ Vector2i diff(0, 0);
+ for (int j = 0; j < 3; ++j) {
+ int orient = face_edgeOrients[i][j];
+ diff += rshift90(edge_diff[face_edgeIds[i][j]], orient);
+ }
+ for (int j = 0; j < 2; ++j) {
+ total_flows[tree.Index(i * 2 + j)] += diff[j];
+ }
+ }
+
+ // build "variable"
+ variables.resize(edge_diff.size() * 2);
+ for (int i = 0; i < variables.size(); ++i) {
+ variables[i].first = Vector2i(-1, -1);
+ variables[i].second = 0;
+ }
+ for (int i = 0; i < face_edgeIds.size(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ Vector2i sign = rshift90(Vector2i(1, 1), face_edgeOrients[i][j]);
+ int eid = face_edgeIds[i][j];
+ Vector2i index = rshift90(Vector2i(eid * 2, eid * 2 + 1), face_edgeOrients[i][j]);
+ for (int k = 0; k < 2; ++k) {
+ auto& p = variables[abs(index[k])];
+ if (p.first[0] == -1)
+ p.first[0] = i * 2 + k;
+ else
+ p.first[1] = i * 2 + k;
+ p.second += sign[k];
+ }
+ }
+ }
+
+ // fixed variable that might be manually modified.
+ // modified_variables[component_od][].first = fixed_variable_id
+ // modified_variables[component_od][].second = 1 if two positive signs -1 if two negative signs
+ std::vector<std::vector<std::pair<int, int>>> modified_variables[2];
+ for (int i = 0; i < 2; ++i) {
+ modified_variables[i].resize(total_flows.size());
+ }
+ for (int i = 0; i < variables.size(); ++i) {
+ if ((variables[i].first[1] == -1 || variables[i].second != 0) && allow_changes[i] == 1) {
+ int find = tree.Index(variables[i].first[0]);
+ int step = abs(variables[i].second) % 2;
+ if (total_flows[find] > 0) {
+ if (variables[i].second > 0 && edge_diff[i / 2][i % 2] > -1) {
+ modified_variables[step][find].push_back(std::make_pair(i, -1));
+ }
+ if (variables[i].second < 0 && edge_diff[i / 2][i % 2] < 1) {
+ modified_variables[step][find].push_back(std::make_pair(i, 1));
+ }
+ } else if (total_flows[find] < 0) {
+ if (variables[i].second < 0 && edge_diff[i / 2][i % 2] > -1) {
+ modified_variables[step][find].push_back(std::make_pair(i, -1));
+ }
+ if (variables[i].second > 0 && edge_diff[i / 2][i % 2] < 1) {
+ modified_variables[step][find].push_back(std::make_pair(i, 1));
+ }
+ }
+ }
+ }
+
+ // uniformly random manually modify variables so that the network has full flow.
+ for (int j = 0; j < 2; ++j) {
+ for (auto& modified_var : modified_variables[j])
+ std::shuffle(modified_var.begin(), modified_var.end(), g);
+ }
+ for (int j = 0; j < total_flows.size(); ++j) {
+ for (int ii = 0; ii < 2; ++ii) {
+ if (total_flows[j] == 0) continue;
+ int max_num;
+ if (ii == 0)
+ max_num = std::min(abs(total_flows[j]) / 2, (int)modified_variables[ii][j].size());
+ else
+ max_num = std::min(abs(total_flows[j]), (int)modified_variables[ii][j].size());
+ int dir = (total_flows[j] > 0) ? -1 : 1;
+ for (int i = 0; i < max_num; ++i) {
+ auto& info = modified_variables[ii][j][i];
+ edge_diff[info.first / 2][info.first % 2] += info.second;
+ if (ii == 0)
+ total_flows[j] += 2 * dir;
+ else
+ total_flows[j] += dir;
+ }
+ }
+ }
+}
+
+void Parametrizer::ComputeMaxFlow() {
+ hierarchy.DownsampleEdgeGraph(face_edgeOrients, face_edgeIds, edge_diff, allow_changes, 1);
+ Optimizer::optimize_integer_constraints(hierarchy, singularities, flag_minimum_cost_flow);
+ hierarchy.UpdateGraphValue(face_edgeOrients, face_edgeIds, edge_diff);
+}
+
+} // namespace qflow
diff --git a/extern/quadriflow/src/parametrizer-mesh.cpp b/extern/quadriflow/src/parametrizer-mesh.cpp
new file mode 100644
index 00000000000..19effe92390
--- /dev/null
+++ b/extern/quadriflow/src/parametrizer-mesh.cpp
@@ -0,0 +1,615 @@
+#include "config.hpp"
+#include "dedge.hpp"
+#include "field-math.hpp"
+#include "loader.hpp"
+#include "merge-vertex.hpp"
+#include "parametrizer.hpp"
+#include "subdivide.hpp"
+#include "dedge.hpp"
+#include <queue>
+
+namespace qflow {
+
+void Parametrizer::NormalizeMesh() {
+ double maxV[3] = {-1e30, -1e30, -1e30};
+ double minV[3] = {1e30, 1e30, 1e30};
+
+ for (int i = 0; i < V.cols(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ maxV[j] = std::max(maxV[j], V(j, i));
+ minV[j] = std::min(minV[j], V(j, i));
+ }
+ }
+ double scale =
+ std::max(std::max(maxV[0] - minV[0], maxV[1] - minV[1]), maxV[2] - minV[2]) * 0.5;
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int i = 0; i < V.cols(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ V(j, i) = (V(j, i) - (maxV[j] + minV[j]) * 0.5) / scale;
+ }
+ }
+#ifdef LOG_OUTPUT
+ printf("vertices size: %d\n", (int)V.cols());
+ printf("faces size: %d\n", (int)F.cols());
+#endif
+ this->normalize_scale = scale;
+ this->normalize_offset = Vector3d(0.5 * (maxV[0] + minV[0]), 0.5 * (maxV[1] + minV[1]), 0.5 * (maxV[2] + minV[2]));
+ // merge_close(V, F, 1e-6);
+}
+
+void Parametrizer::Load(const char* filename) {
+ load(filename, V, F);
+ NormalizeMesh();
+}
+
+void Parametrizer::Initialize(int faces) {
+ ComputeMeshStatus();
+ //ComputeCurvature(V, F, rho);
+ rho.resize(V.cols(), 1);
+ for (int i = 0; i < V.cols(); ++i) {
+ rho[i] = 1;
+ }
+#ifdef PERFORMANCE_TEST
+ scale = sqrt(surface_area / (V.cols() * 10));
+#else
+ if (faces <= 0) {
+ scale = sqrt(surface_area / V.cols());
+ } else {
+ scale = std::sqrt(surface_area / faces);
+ }
+#endif
+ double target_len = std::min(scale / 2, average_edge_length * 2);
+#ifdef PERFORMANCE_TEST
+ scale = sqrt(surface_area / V.cols());
+#endif
+
+ if (target_len < max_edge_length) {
+ while (!compute_direct_graph(V, F, V2E, E2E, boundary, nonManifold))
+ ;
+ subdivide(F, V, rho, V2E, E2E, boundary, nonManifold, target_len);
+ }
+
+ while (!compute_direct_graph(V, F, V2E, E2E, boundary, nonManifold))
+ ;
+ generate_adjacency_matrix_uniform(F, V2E, E2E, nonManifold, adj);
+
+ for (int iter = 0; iter < 5; ++iter) {
+ VectorXd r(rho.size());
+ for (int i = 0; i < rho.size(); ++i) {
+ r[i] = rho[i];
+ for (auto& id : adj[i]) {
+ r[i] = std::min(r[i], rho[id.id]);
+ }
+ }
+ rho = r;
+ }
+ ComputeSharpEdges();
+ ComputeSmoothNormal();
+ ComputeVertexArea();
+
+ if (flag_adaptive_scale)
+ ComputeInverseAffine();
+
+#ifdef LOG_OUTPUT
+ printf("V: %d F: %d\n", (int)V.cols(), (int)F.cols());
+#endif
+ hierarchy.mA[0] = std::move(A);
+ hierarchy.mAdj[0] = std::move(adj);
+ hierarchy.mN[0] = std::move(N);
+ hierarchy.mV[0] = std::move(V);
+ hierarchy.mE2E = std::move(E2E);
+ hierarchy.mF = std::move(F);
+ hierarchy.Initialize(scale, flag_adaptive_scale);
+}
+
+void Parametrizer::ComputeMeshStatus() {
+ surface_area = 0;
+ average_edge_length = 0;
+ max_edge_length = 0;
+ for (int f = 0; f < F.cols(); ++f) {
+ Vector3d v[3] = {V.col(F(0, f)), V.col(F(1, f)), V.col(F(2, f))};
+ double area = 0.5f * (v[1] - v[0]).cross(v[2] - v[0]).norm();
+ surface_area += area;
+ for (int i = 0; i < 3; ++i) {
+ double len = (v[(i + 1) % 3] - v[i]).norm();
+ average_edge_length += len;
+ if (len > max_edge_length) max_edge_length = len;
+ }
+ }
+ average_edge_length /= (F.cols() * 3);
+}
+
+void Parametrizer::ComputeSharpEdges() {
+ sharp_edges.resize(F.cols() * 3, 0);
+
+ if (flag_preserve_boundary) {
+ for (int i = 0; i < sharp_edges.size(); ++i) {
+ int re = E2E[i];
+ if (re == -1) {
+ sharp_edges[i] = 1;
+ }
+ }
+ }
+
+ if (flag_preserve_sharp == 0)
+ return;
+
+ std::vector<Vector3d> face_normals(F.cols());
+ for (int i = 0; i < F.cols(); ++i) {
+ Vector3d p1 = V.col(F(0, i));
+ Vector3d p2 = V.col(F(1, i));
+ Vector3d p3 = V.col(F(2, i));
+ face_normals[i] = (p2 - p1).cross(p3 - p1).normalized();
+ }
+
+ double cos_thres = cos(60.0/180.0*3.141592654);
+ for (int i = 0; i < sharp_edges.size(); ++i) {
+ int e = i;
+ int re = E2E[e];
+ Vector3d& n1 = face_normals[e/3];
+ Vector3d& n2 = face_normals[re/3];
+ if (n1.dot(n2) < cos_thres) {
+ sharp_edges[i] = 1;
+ }
+ }
+}
+
+void Parametrizer::ComputeSharpO() {
+ auto& F = hierarchy.mF;
+ auto& V = hierarchy.mV[0];
+ auto& O = hierarchy.mO[0];
+ auto& E2E = hierarchy.mE2E;
+ DisajointTree tree(V.cols());
+ for (int i = 0; i < edge_diff.size(); ++i) {
+ if (edge_diff[i][0] == 0 && edge_diff[i][1] == 0) {
+ tree.Merge(edge_values[i].x, edge_values[i].y);
+ }
+ }
+ std::map<DEdge, std::vector<Vector3d> > edge_normals;
+ for (int i = 0; i < F.cols(); ++i) {
+ int pv[] = {tree.Parent(F(0, i)), tree.Parent(F(1, i)), tree.Parent(F(2, i))};
+ if (pv[0] == pv[1] || pv[1] == pv[2] || pv[2] == pv[0])
+ continue;
+ DEdge e[] = {DEdge(pv[0], pv[1]), DEdge(pv[1], pv[2]), DEdge(pv[2], pv[0])};
+ Vector3d d1 = O.col(F(1, i)) - O.col(F(0, i));
+ Vector3d d2 = O.col(F(2, i)) - O.col(F(0, i));
+ Vector3d n = d1.cross(d2).normalized();
+ for (int j = 0; j < 3; ++j) {
+ if (edge_normals.count(e[j]) == 0)
+ edge_normals[e[j]] = std::vector<Vector3d>();
+ edge_normals[e[j]].push_back(n);
+ }
+ }
+ std::map<DEdge, int> sharps;
+ for (auto& info : edge_normals) {
+ auto& normals = info.second;
+ bool sharp = false;
+ for (int i = 0; i < normals.size(); ++i) {
+ for (int j = i + 1; j < normals.size(); ++j) {
+ if (normals[i].dot(normals[j]) < cos(60.0 / 180.0 * 3.141592654)) {
+ sharp = true;
+ break;
+ }
+ }
+ if (sharp)
+ break;
+ }
+ if (sharp) {
+ int s = sharps.size();
+ sharps[info.first] = s;
+ }
+ }
+ for (auto& s : sharp_edges)
+ s = 0;
+ std::vector<int> sharp_hash(sharps.size(), 0);
+ for (int i = 0; i < F.cols(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ int v1 = tree.Parent(F(j, i));
+ int v2 = tree.Parent(F((j + 1) % 3, i));
+ DEdge e(v1, v2);
+ if (sharps.count(e) == 0)
+ continue;
+ int id = sharps[e];
+ if (sharp_hash[id])
+ continue;
+ sharp_hash[id] = 1;
+ sharp_edges[i * 3 + j] = 1;
+ sharp_edges[E2E[i * 3 + j]] = 1;
+ }
+ }
+
+}
+
+void Parametrizer::ComputeSmoothNormal() {
+ /* Compute face normals */
+ Nf.resize(3, F.cols());
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int f = 0; f < F.cols(); ++f) {
+ Vector3d v0 = V.col(F(0, f)), v1 = V.col(F(1, f)), v2 = V.col(F(2, f)),
+ n = (v1 - v0).cross(v2 - v0);
+ double norm = n.norm();
+ if (norm < RCPOVERFLOW) {
+ n = Vector3d::UnitX();
+ } else {
+ n /= norm;
+ }
+ Nf.col(f) = n;
+ }
+
+ N.resize(3, V.cols());
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int i = 0; i < V2E.rows(); ++i) {
+ int edge = V2E[i];
+ if (nonManifold[i] || edge == -1) {
+ N.col(i) = Vector3d::UnitX();
+ continue;
+ }
+
+
+ int stop = edge;
+ do {
+ if (sharp_edges[edge])
+ break;
+ edge = E2E[edge];
+ if (edge != -1)
+ edge = dedge_next_3(edge);
+ } while (edge != stop && edge != -1);
+ if (edge == -1)
+ edge = stop;
+ else
+ stop = edge;
+ Vector3d normal = Vector3d::Zero();
+ do {
+ int idx = edge % 3;
+
+ Vector3d d0 = V.col(F((idx + 1) % 3, edge / 3)) - V.col(i);
+ Vector3d d1 = V.col(F((idx + 2) % 3, edge / 3)) - V.col(i);
+ double angle = fast_acos(d0.dot(d1) / std::sqrt(d0.squaredNorm() * d1.squaredNorm()));
+
+ /* "Computing Vertex Normals from Polygonal Facets"
+ by Grit Thuermer and Charles A. Wuethrich, JGT 1998, Vol 3 */
+ if (std::isfinite(angle)) normal += Nf.col(edge / 3) * angle;
+
+ int opp = E2E[edge];
+ if (opp == -1) break;
+
+ edge = dedge_next_3(opp);
+ if (sharp_edges[edge])
+ break;
+ } while (edge != stop);
+ double norm = normal.norm();
+ N.col(i) = norm > RCPOVERFLOW ? Vector3d(normal / norm) : Vector3d::UnitX();
+ }
+}
+
+void Parametrizer::ComputeVertexArea() {
+ A.resize(V.cols());
+ A.setZero();
+
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int i = 0; i < V2E.size(); ++i) {
+ int edge = V2E[i], stop = edge;
+ if (nonManifold[i] || edge == -1) continue;
+ double vertex_area = 0;
+ do {
+ int ep = dedge_prev_3(edge), en = dedge_next_3(edge);
+
+ Vector3d v = V.col(F(edge % 3, edge / 3));
+ Vector3d vn = V.col(F(en % 3, en / 3));
+ Vector3d vp = V.col(F(ep % 3, ep / 3));
+
+ Vector3d face_center = (v + vp + vn) * (1.0f / 3.0f);
+ Vector3d prev = (v + vp) * 0.5f;
+ Vector3d next = (v + vn) * 0.5f;
+
+ vertex_area += 0.5f * ((v - prev).cross(v - face_center).norm() +
+ (v - next).cross(v - face_center).norm());
+
+ int opp = E2E[edge];
+ if (opp == -1) break;
+ edge = dedge_next_3(opp);
+ } while (edge != stop);
+
+ A[i] = vertex_area;
+ }
+}
+
+void Parametrizer::FixValence()
+{
+ // Remove Valence 2
+ while (true) {
+ bool update = false;
+ std::vector<int> marks(V2E_compact.size(), 0);
+ std::vector<int> erasedF(F_compact.size(), 0);
+ for (int i = 0; i < V2E_compact.size(); ++i) {
+ int deid0 = V2E_compact[i];
+ if (marks[i] || deid0 == -1)
+ continue;
+ int deid = deid0;
+ std::vector<int> dedges;
+ do {
+ dedges.push_back(deid);
+ int deid1 = deid / 4 * 4 + (deid + 3) % 4;
+ deid = E2E_compact[deid1];
+ } while (deid != deid0 && deid != -1);
+ if (dedges.size() == 2) {
+ int v1 = F_compact[dedges[0]/4][(dedges[0] + 1)%4];
+ int v2 = F_compact[dedges[0]/4][(dedges[0] + 2)%4];
+ int v3 = F_compact[dedges[1]/4][(dedges[1] + 1)%4];
+ int v4 = F_compact[dedges[1]/4][(dedges[1] + 2)%4];
+ if (marks[v1] || marks[v2] || marks[v3] || marks[v4])
+ continue;
+ marks[v1] = true;
+ marks[v2] = true;
+ marks[v3] = true;
+ marks[v4] = true;
+ if (v1 == v2 || v1 == v3 || v1 == v4 || v2 == v3 || v2 == v4 || v3 == v4) {
+ erasedF[dedges[0]/4] = 1;
+ } else {
+ F_compact[dedges[0]/4] = Vector4i(v1, v2, v3, v4);
+ }
+ erasedF[dedges[1]/4] = 1;
+ update = true;
+ }
+ }
+ if (update) {
+ int top = 0;
+ for (int i = 0; i < erasedF.size(); ++i) {
+ if (erasedF[i] == 0) {
+ F_compact[top++] = F_compact[i];
+ }
+ }
+ F_compact.resize(top);
+ compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact,
+ nonManifold_compact);
+ } else {
+ break;
+ }
+ }
+ std::vector<std::vector<int> > v_dedges(V2E_compact.size());
+ for (int i = 0; i < F_compact.size(); ++i) {
+ for (int j = 0; j < 4; ++j) {
+ v_dedges[F_compact[i][j]].push_back(i * 4 + j);
+ }
+ }
+ int top = V2E_compact.size();
+ for (int i = 0; i < v_dedges.size(); ++i) {
+ std::map<int, int> groups;
+ int group_id = 0;
+ for (int j = 0; j < v_dedges[i].size(); ++j) {
+ int deid = v_dedges[i][j];
+ if (groups.count(deid))
+ continue;
+ int deid0 = deid;
+ do {
+ groups[deid] = group_id;
+ deid = deid / 4 * 4 + (deid + 3) % 4;
+ deid = E2E_compact[deid];
+ } while (deid != deid0 && deid != -1);
+ if (deid == -1) {
+ deid = deid0;
+ while (E2E_compact[deid] != -1) {
+ deid = E2E_compact[deid];
+ deid = deid / 4 * 4 + (deid + 1) % 4;
+ groups[deid] = group_id;
+ }
+ }
+ group_id += 1;
+ }
+ if (group_id > 1) {
+ for (auto& g : groups) {
+ if (g.second >= 1)
+ F_compact[g.first/4][g.first%4] = top - 1 + g.second;
+ }
+ for (int j = 1; j < group_id; ++j) {
+ Vset.push_back(Vset[i]);
+ N_compact.push_back(N_compact[i]);
+ Q_compact.push_back(Q_compact[i]);
+ O_compact.push_back(O_compact[i]);
+ }
+ top = O_compact.size();
+ }
+ }
+ compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact,
+ nonManifold_compact);
+
+ // Decrease Valence
+ while (true) {
+ bool update = false;
+ std::vector<int> marks(V2E_compact.size(), 0);
+ std::vector<int> valences(V2E_compact.size(), 0);
+ for (int i = 0; i < V2E_compact.size(); ++i) {
+ int deid0 = V2E_compact[i];
+ if (deid0 == -1)
+ continue;
+ int deid = deid0;
+ int count = 0;
+ do {
+ count += 1;
+ int deid1 = E2E_compact[deid];
+ if (deid1 == -1) {
+ count += 1;
+ break;
+ }
+ deid = deid1 / 4 * 4 + (deid1 + 1) % 4;
+ } while (deid != deid0 && deid != -1);
+ if (deid == -1)
+ count += 1;
+ valences[i] = count;
+ }
+ std::priority_queue<std::pair<int, int> > prior_queue;
+ for (int i = 0; i < valences.size(); ++i) {
+ if (valences[i] > 5)
+ prior_queue.push(std::make_pair(valences[i], i));
+ }
+ while (!prior_queue.empty()) {
+ auto info = prior_queue.top();
+ prior_queue.pop();
+ if (marks[info.second])
+ continue;
+ int deid0 = V2E_compact[info.second];
+ if (deid0 == -1)
+ continue;
+ int deid = deid0;
+ std::vector<int> loop_vertices, loop_dedges;;
+ bool marked = false;
+ do {
+ int v = F_compact[deid/4][(deid+1)%4];
+ loop_dedges.push_back(deid);
+ loop_vertices.push_back(v);
+ if (marks[v])
+ marked = true;
+ int deid1 = E2E_compact[deid];
+ if (deid1 == -1)
+ break;
+ deid = deid1 / 4 * 4 + (deid1 + 1) % 4;
+ } while (deid != deid0 && deid != -1);
+ if (marked)
+ continue;
+
+ if (deid != -1) {
+ int step = (info.first + 1) / 2;
+ std::pair<int, int> min_val(0x7fffffff, 0x7fffffff);
+ int split_idx = -1;
+ for (int i = 0; i < loop_vertices.size(); ++i) {
+ if (i + step >= loop_vertices.size())
+ continue;
+ int v1 = valences[loop_vertices[i]];
+ int v2 = valences[loop_vertices[i + step]];
+ if (v1 < v2)
+ std::swap(v1, v2);
+ auto key = std::make_pair(v1, v2);
+ if (key < min_val) {
+ min_val = key;
+ split_idx = i + 1;
+ }
+ }
+ if (min_val.first >= info.first)
+ continue;
+ update = true;
+ for (int id = split_idx; id < split_idx + step; ++id) {
+ F_compact[loop_dedges[id]/4][loop_dedges[id]%4] = O_compact.size();
+ }
+ F_compact.push_back(Vector4i(O_compact.size(), loop_vertices[(split_idx+loop_vertices.size()-1)%loop_vertices.size()],info.second, loop_vertices[(split_idx + step - 1 + loop_vertices.size()) % loop_vertices.size()]));
+ } else {
+ for (int id = loop_vertices.size() / 2; id < loop_vertices.size(); ++id) {
+ F_compact[loop_dedges[id]/4][loop_dedges[id]%4] = O_compact.size();
+ }
+ update = true;
+ }
+ marks[info.second] = 1;
+ for (int i = 0; i < loop_vertices.size(); ++i) {
+ marks[loop_vertices[i]] = 1;
+ }
+ Vset.push_back(Vset[info.second]);
+ O_compact.push_back(O_compact[info.second]);
+ N_compact.push_back(N_compact[info.second]);
+ Q_compact.push_back(Q_compact[info.second]);
+ }
+ if (!update) {
+ break;
+ } else {
+ compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact,
+ nonManifold_compact);
+ }
+ }
+ // Remove Zero Valence
+ std::vector<int> valences(V2E_compact.size(), 0);
+ for (int i = 0; i < F_compact.size(); ++i) {
+ for (int j = 0; j < 4; ++j) {
+ valences[F_compact[i][j]] = 1;
+ }
+ }
+ top = 0;
+ std::vector<int> compact_indices(valences.size());
+ for (int i = 0; i < valences.size(); ++i) {
+ if (valences[i] == 0)
+ continue;
+ N_compact[top] = N_compact[i];
+ O_compact[top] = O_compact[i];
+ Q_compact[top] = Q_compact[i];
+ Vset[top] = Vset[i];
+ compact_indices[i] = top;
+ top += 1;
+ }
+ for (int i = 0; i < F_compact.size(); ++i) {
+ for (int j = 0; j < 4; ++j) {
+ F_compact[i][j] = compact_indices[F_compact[i][j]];
+ }
+ }
+ N_compact.resize(top);
+ O_compact.resize(top);
+ Q_compact.resize(top);
+ Vset.resize(top);
+ compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact,
+ nonManifold_compact);
+ {
+ compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact,
+ nonManifold_compact);
+ std::vector<int> masks(F_compact.size() * 4, 0);
+ for (int i = 0; i < V2E_compact.size(); ++i) {
+ int deid0 = V2E_compact[i];
+ if (deid0 == -1)
+ continue;
+ int deid = deid0;
+ do {
+ masks[deid] = 1;
+ deid = E2E_compact[deid];
+ if (deid == -1) {
+ break;
+ }
+ deid = deid / 4 * 4 + (deid + 1) % 4;
+ } while (deid != deid0 && deid != -1);
+ }
+ std::vector<std::vector<int> > v_dedges(V2E_compact.size());
+ for (int i = 0; i < F_compact.size(); ++i) {
+ for (int j = 0; j < 4; ++j) {
+ v_dedges[F_compact[i][j]].push_back(i * 4 + j);
+ }
+ }
+ }
+ std::map<int, int> pts;
+ for (int i = 0; i < V2E_compact.size(); ++i) {
+ int deid0 = V2E_compact[i];
+ if (deid0 == -1)
+ continue;
+ int deid = deid0;
+ int count = 0;
+ do {
+ count += 1;
+ int deid1 = E2E_compact[deid];
+ if (deid1 == -1)
+ break;
+ deid = deid1 / 4 * 4 + (deid1 + 1) % 4;
+ } while (deid != deid0 && deid != -1);
+ if (pts.count(count) == 0)
+ pts[count] = 1;
+ else
+ pts[count] += 1;
+ }
+ return;
+}
+
+void Parametrizer::OutputMesh(const char* obj_name) {
+ std::ofstream os(obj_name);
+ for (int i = 0; i < O_compact.size(); ++i) {
+ auto t = O_compact[i] * this->normalize_scale + this->normalize_offset;
+ os << "v " << t[0] << " " << t[1] << " " << t[2] << "\n";
+ }
+ for (int i = 0; i < F_compact.size(); ++i) {
+ os << "f " << F_compact[i][0]+1 << " " << F_compact[i][1]+1
+ << " " << F_compact[i][2]+1 << " " << F_compact[i][3]+1
+ << "\n";
+ }
+ os.close();
+}
+
+} // namespace qflow
diff --git a/extern/quadriflow/src/parametrizer-scale.cpp b/extern/quadriflow/src/parametrizer-scale.cpp
new file mode 100644
index 00000000000..bbd901d08c9
--- /dev/null
+++ b/extern/quadriflow/src/parametrizer-scale.cpp
@@ -0,0 +1,119 @@
+#include "parametrizer.hpp"
+
+namespace qflow {
+
+void Parametrizer::ComputeInverseAffine()
+{
+ if (flag_adaptive_scale == 0)
+ return;
+ triangle_space.resize(F.cols());
+#ifdef WITH_OMP
+#pragma omp parallel for
+#endif
+ for (int i = 0; i < F.cols(); ++i) {
+ Matrix3d p, q;
+ p.col(0) = V.col(F(1, i)) - V.col(F(0, i));
+ p.col(1) = V.col(F(2, i)) - V.col(F(0, i));
+ p.col(2) = Nf.col(i);
+ q = p.inverse();
+ triangle_space[i].resize(2, 3);
+ for (int j = 0; j < 2; ++j) {
+ for (int k = 0; k < 3; ++k) {
+ triangle_space[i](j, k) = q(j, k);
+ }
+ }
+ }
+}
+
+void Parametrizer::EstimateSlope() {
+ auto& mF = hierarchy.mF;
+ auto& mQ = hierarchy.mQ[0];
+ auto& mN = hierarchy.mN[0];
+ auto& mV = hierarchy.mV[0];
+ FS.resize(2, mF.cols());
+ FQ.resize(3, mF.cols());
+ for (int i = 0; i < mF.cols(); ++i) {
+ const Vector3d& n = Nf.col(i);
+ const Vector3d &q_1 = mQ.col(mF(0, i)), &q_2 = mQ.col(mF(1, i)), &q_3 = mQ.col(mF(2, i));
+ const Vector3d &n_1 = mN.col(mF(0, i)), &n_2 = mN.col(mF(1, i)), &n_3 = mN.col(mF(2, i));
+ Vector3d q_1n = rotate_vector_into_plane(q_1, n_1, n);
+ Vector3d q_2n = rotate_vector_into_plane(q_2, n_2, n);
+ Vector3d q_3n = rotate_vector_into_plane(q_3, n_3, n);
+
+ auto p = compat_orientation_extrinsic_4(q_1n, n, q_2n, n);
+ Vector3d q = (p.first + p.second).normalized();
+ p = compat_orientation_extrinsic_4(q, n, q_3n, n);
+ q = (p.first * 2 + p.second);
+ q = q - n * q.dot(n);
+ FQ.col(i) = q.normalized();
+ }
+ for (int i = 0; i < mF.cols(); ++i) {
+ double step = hierarchy.mScale * 1.f;
+
+ const Vector3d &n = Nf.col(i);
+ Vector3d p = (mV.col(mF(0, i)) + mV.col(mF(1, i)) + mV.col(mF(2, i))) * (1.0 / 3.0);
+ Vector3d q_x = FQ.col(i), q_y = n.cross(q_x);
+ Vector3d q_xl = -q_x, q_xr = q_x;
+ Vector3d q_yl = -q_y, q_yr = q_y;
+ Vector3d q_yl_unfold = q_y, q_yr_unfold = q_y, q_xl_unfold = q_x, q_xr_unfold = q_x;
+ int f;
+ double tx, ty, len;
+
+ f = i; len = step;
+ TravelField(p, q_xl, len, f, hierarchy.mE2E, mV, mF, Nf, FQ, mQ, mN, triangle_space, &tx, &ty, &q_yl_unfold);
+
+ f = i; len = step;
+ TravelField(p, q_xr, len, f, hierarchy.mE2E, mV, mF, Nf, FQ, mQ, mN, triangle_space, &tx, &ty, &q_yr_unfold);
+
+ f = i; len = step;
+ TravelField(p, q_yl, len, f, hierarchy.mE2E, mV, mF, Nf, FQ, mQ, mN, triangle_space, &tx, &ty, &q_xl_unfold);
+
+ f = i; len = step;
+ TravelField(p, q_yr, len, f, hierarchy.mE2E, mV, mF, Nf, FQ, mQ, mN, triangle_space, &tx, &ty, &q_xr_unfold);
+ double dSx = (q_yr_unfold - q_yl_unfold).dot(q_x) / (2.0f * step);
+ double dSy = (q_xr_unfold - q_xl_unfold).dot(q_y) / (2.0f * step);
+ FS.col(i) = Vector2d(dSx, dSy);
+ }
+
+ std::vector<double> areas(mV.cols(), 0.0);
+ for (int i = 0; i < mF.cols(); ++i) {
+ Vector3d p1 = mV.col(mF(1, i)) - mV.col(mF(0, i));
+ Vector3d p2 = mV.col(mF(2, i)) - mV.col(mF(0, i));
+ double area = p1.cross(p2).norm();
+ for (int j = 0; j < 3; ++j) {
+ auto index = compat_orientation_extrinsic_index_4(FQ.col(i), Nf.col(i), mQ.col(mF(j, i)), mN.col(mF(j, i)));
+ double scaleX = FS.col(i).x(), scaleY = FS.col(i).y();
+ if (index.first != index.second % 2) {
+ std::swap(scaleX, scaleY);
+ }
+ if (index.second >= 2) {
+ scaleX = -scaleX;
+ scaleY = -scaleY;
+ }
+ hierarchy.mK[0].col(mF(j, i)) += area * Vector2d(scaleX, scaleY);
+ areas[mF(j, i)] += area;
+ }
+ }
+ for (int i = 0; i < mV.cols(); ++i) {
+ if (areas[i] != 0)
+ hierarchy.mK[0].col(i) /= areas[i];
+ }
+ for (int l = 0; l< hierarchy.mK.size() - 1; ++l) {
+ const MatrixXd &K = hierarchy.mK[l];
+ MatrixXd &K_next = hierarchy.mK[l + 1];
+ auto& toUpper = hierarchy.mToUpper[l];
+ for (int i = 0; i < toUpper.cols(); ++i) {
+ Vector2i upper = toUpper.col(i);
+ Vector2d k0 = K.col(upper[0]);
+
+ if (upper[1] != -1) {
+ Vector2d k1 = K.col(upper[1]);
+ k0 = 0.5 * (k0 + k1);
+ }
+
+ K_next.col(i) = k0;
+ }
+ }
+}
+
+} // namespace qflow
diff --git a/extern/quadriflow/src/parametrizer-sing.cpp b/extern/quadriflow/src/parametrizer-sing.cpp
new file mode 100644
index 00000000000..2d600e3cda4
--- /dev/null
+++ b/extern/quadriflow/src/parametrizer-sing.cpp
@@ -0,0 +1,142 @@
+#include "config.hpp"
+#include "field-math.hpp"
+#include "parametrizer.hpp"
+
+namespace qflow {
+
+void Parametrizer::ComputeOrientationSingularities() {
+ MatrixXd &N = hierarchy.mN[0], &Q = hierarchy.mQ[0];
+ const MatrixXi& F = hierarchy.mF;
+ singularities.clear();
+ for (int f = 0; f < F.cols(); ++f) {
+ int index = 0;
+ int abs_index = 0;
+ for (int k = 0; k < 3; ++k) {
+ int i = F(k, f), j = F(k == 2 ? 0 : (k + 1), f);
+ auto value =
+ compat_orientation_extrinsic_index_4(Q.col(i), N.col(i), Q.col(j), N.col(j));
+ index += value.second - value.first;
+ abs_index += std::abs(value.second - value.first);
+ }
+ int index_mod = modulo(index, 4);
+ if (index_mod == 1 || index_mod == 3) {
+ if (index >= 4 || index < 0) {
+ Q.col(F(0, f)) = -Q.col(F(0, f));
+ }
+ singularities[f] = index_mod;
+ }
+ }
+}
+
+void Parametrizer::ComputePositionSingularities() {
+ const MatrixXd &V = hierarchy.mV[0], &N = hierarchy.mN[0], &Q = hierarchy.mQ[0],
+ &O = hierarchy.mO[0];
+ const MatrixXi& F = hierarchy.mF;
+
+ pos_sing.clear();
+ pos_rank.resize(F.rows(), F.cols());
+ pos_index.resize(6, F.cols());
+ for (int f = 0; f < F.cols(); ++f) {
+ Vector2i index = Vector2i::Zero();
+ uint32_t i0 = F(0, f), i1 = F(1, f), i2 = F(2, f);
+
+ Vector3d q[3] = {Q.col(i0).normalized(), Q.col(i1).normalized(), Q.col(i2).normalized()};
+ Vector3d n[3] = {N.col(i0), N.col(i1), N.col(i2)};
+ Vector3d o[3] = {O.col(i0), O.col(i1), O.col(i2)};
+ Vector3d v[3] = {V.col(i0), V.col(i1), V.col(i2)};
+
+ int best[3];
+ double best_dp = -std::numeric_limits<double>::infinity();
+ for (int i = 0; i < 4; ++i) {
+ Vector3d v0 = rotate90_by(q[0], n[0], i);
+ for (int j = 0; j < 4; ++j) {
+ Vector3d v1 = rotate90_by(q[1], n[1], j);
+ for (int k = 0; k < 4; ++k) {
+ Vector3d v2 = rotate90_by(q[2], n[2], k);
+ double dp = std::min(std::min(v0.dot(v1), v1.dot(v2)), v2.dot(v0));
+ if (dp > best_dp) {
+ best_dp = dp;
+ best[0] = i;
+ best[1] = j;
+ best[2] = k;
+ }
+ }
+ }
+ }
+ pos_rank(0, f) = best[0];
+ pos_rank(1, f) = best[1];
+ pos_rank(2, f) = best[2];
+ for (int k = 0; k < 3; ++k) q[k] = rotate90_by(q[k], n[k], best[k]);
+
+ for (int k = 0; k < 3; ++k) {
+ int kn = k == 2 ? 0 : (k + 1);
+ double scale_x = hierarchy.mScale, scale_y = hierarchy.mScale,
+ scale_x_1 = hierarchy.mScale, scale_y_1 = hierarchy.mScale;
+ if (flag_adaptive_scale) {
+ scale_x *= hierarchy.mS[0](0, F(k, f));
+ scale_y *= hierarchy.mS[0](1, F(k, f));
+ scale_x_1 *= hierarchy.mS[0](0, F(kn, f));
+ scale_y_1 *= hierarchy.mS[0](1, F(kn, f));
+ if (best[k] % 2 != 0) std::swap(scale_x, scale_y);
+ if (best[kn] % 2 != 0) std::swap(scale_x_1, scale_y_1);
+ }
+ double inv_scale_x = 1.0 / scale_x, inv_scale_y = 1.0 / scale_y,
+ inv_scale_x_1 = 1.0 / scale_x_1, inv_scale_y_1 = 1.0 / scale_y_1;
+ std::pair<Vector2i, Vector2i> value = compat_position_extrinsic_index_4(
+ v[k], n[k], q[k], o[k], v[kn], n[kn], q[kn], o[kn], scale_x, scale_y, inv_scale_x,
+ inv_scale_y, scale_x_1, scale_y_1, inv_scale_x_1, inv_scale_y_1, nullptr);
+ auto diff = value.first - value.second;
+ index += diff;
+ pos_index(k * 2, f) = diff[0];
+ pos_index(k * 2 + 1, f) = diff[1];
+ }
+
+ if (index != Vector2i::Zero()) {
+ pos_sing[f] = rshift90(index, best[0]);
+ }
+ }
+}
+
+void Parametrizer::AnalyzeValence() {
+ auto& F = hierarchy.mF;
+ std::map<int, int> sing;
+ for (auto& f : singularities) {
+ for (int i = 0; i < 3; ++i) {
+ sing[F(i, f.first)] = f.second;
+ }
+ }
+ auto& F2E = face_edgeIds;
+ auto& E2E = hierarchy.mE2E;
+ auto& FQ = face_edgeOrients;
+ std::set<int> sing1, sing2;
+ for (int i = 0; i < F2E.size(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ int deid = i * 3 + j;
+ int sum_int = 0;
+ std::vector<int> edges;
+ std::vector<double> angles;
+ do {
+ int deid1 = deid / 3 * 3 + (deid + 2) % 3;
+ deid = E2E[deid1];
+ sum_int += (FQ[deid / 3][deid % 3] + 6 - FQ[deid1 / 3][deid1 % 3]) % 4;
+ } while (deid != i * 3 + j);
+ if (sum_int % 4 == 2) {
+ printf("OMG! valence = 2\n");
+ exit(0);
+ }
+ if (sum_int % 4 == 1) sing1.insert(F(j, i));
+ if (sum_int % 4 == 3) sing2.insert(F(j, i));
+ }
+ }
+ int count3 = 0, count4 = 0;
+ for (auto& s : singularities) {
+ if (s.second == 1)
+ count3 += 1;
+ else
+ count4 += 1;
+ }
+ printf("singularity: <%d %d> <%d %d>\n", (int)sing1.size(), (int)sing2.size(), count3, count4);
+}
+
+
+} // namespace qflow
diff --git a/extern/quadriflow/src/parametrizer.cpp b/extern/quadriflow/src/parametrizer.cpp
new file mode 100644
index 00000000000..b85383566c9
--- /dev/null
+++ b/extern/quadriflow/src/parametrizer.cpp
@@ -0,0 +1,247 @@
+#include "parametrizer.hpp"
+#include "config.hpp"
+#include "dedge.hpp"
+#include "field-math.hpp"
+#include "flow.hpp"
+#include "localsat.hpp"
+#include "optimizer.hpp"
+#include "subdivide.hpp"
+
+#include "dset.hpp"
+
+#include <Eigen/Sparse>
+#include <fstream>
+#include <list>
+#include <map>
+#include <queue>
+#include <set>
+
+namespace qflow {
+
+void Parametrizer::ComputeIndexMap(int with_scale) {
+ // build edge info
+ auto& V = hierarchy.mV[0];
+ auto& F = hierarchy.mF;
+ auto& Q = hierarchy.mQ[0];
+ auto& N = hierarchy.mN[0];
+ auto& O = hierarchy.mO[0];
+ auto& S = hierarchy.mS[0];
+ // ComputeOrientationSingularities();
+
+ BuildEdgeInfo();
+
+ if (flag_preserve_sharp) {
+ // ComputeSharpO();
+ }
+ for (int i = 0; i < sharp_edges.size(); ++i) {
+ if (sharp_edges[i]) {
+ int e = face_edgeIds[i / 3][i % 3];
+ if (edge_diff[e][0] * edge_diff[e][1] != 0) {
+ Vector3d d = O.col(edge_values[e].y) - O.col(edge_values[e].x);
+ Vector3d q = Q.col(edge_values[e].x);
+ Vector3d n = N.col(edge_values[e].x);
+ Vector3d qy = n.cross(q);
+ if (abs(q.dot(d)) > qy.dot(d))
+ edge_diff[e][1] = 0;
+ else
+ edge_diff[e][0] = 0;
+ }
+ }
+ }
+ std::map<int, std::pair<Vector3d, Vector3d>> sharp_constraints;
+ std::set<int> sharpvert;
+ for (int i = 0; i < sharp_edges.size(); ++i) {
+ if (sharp_edges[i]) {
+ sharpvert.insert(F(i % 3, i / 3));
+ sharpvert.insert(F((i + 1) % 3, i / 3));
+ }
+ }
+
+ allow_changes.resize(edge_diff.size() * 2, 1);
+ for (int i = 0; i < sharp_edges.size(); ++i) {
+ int e = face_edgeIds[i / 3][i % 3];
+ if (sharpvert.count(edge_values[e].x) && sharpvert.count(edge_values[e].y)) {
+ if (sharp_edges[i] != 0) {
+ for (int k = 0; k < 2; ++k) {
+ if (edge_diff[e][k] == 0) {
+ allow_changes[e * 2 + k] = 0;
+ }
+ }
+ }
+ }
+ }
+#ifdef LOG_OUTPUT
+ printf("Build Integer Constraints...\n");
+#endif
+ BuildIntegerConstraints();
+
+ ComputeMaxFlow();
+ // potential bug
+#ifdef LOG_OUTPUT
+ printf("subdivide...\n");
+#endif
+ subdivide_edgeDiff(F, V, N, Q, O, &hierarchy.mS[0], V2E, hierarchy.mE2E, boundary, nonManifold,
+ edge_diff, edge_values, face_edgeOrients, face_edgeIds, sharp_edges,
+ singularities, 1);
+
+ allow_changes.clear();
+ allow_changes.resize(edge_diff.size() * 2, 1);
+ for (int i = 0; i < sharp_edges.size(); ++i) {
+ if (sharp_edges[i] == 0) continue;
+ int e = face_edgeIds[i / 3][i % 3];
+ for (int k = 0; k < 2; ++k) {
+ if (edge_diff[e][k] == 0) allow_changes[e * 2 + k] = 0;
+ }
+ }
+
+#ifdef LOG_OUTPUT
+ printf("Fix flip advance...\n");
+ int t1 = GetCurrentTime64();
+#endif
+ FixFlipHierarchy();
+ subdivide_edgeDiff(F, V, N, Q, O, &hierarchy.mS[0], V2E, hierarchy.mE2E, boundary, nonManifold,
+ edge_diff, edge_values, face_edgeOrients, face_edgeIds, sharp_edges,
+ singularities, 1);
+ FixFlipSat();
+
+#ifdef LOG_OUTPUT
+ int t2 = GetCurrentTime64();
+ printf("Flip use %lf\n", (t2 - t1) * 1e-3);
+ printf("Post Linear Solver...\n");
+#endif
+ std::set<int> sharp_vertices;
+ for (int i = 0; i < sharp_edges.size(); ++i) {
+ if (sharp_edges[i] == 1) {
+ sharp_vertices.insert(F(i % 3, i / 3));
+ sharp_vertices.insert(F((i + 1) % 3, i / 3));
+ }
+ }
+
+ Optimizer::optimize_positions_sharp(hierarchy, edge_values, edge_diff, sharp_edges,
+ sharp_vertices, sharp_constraints, with_scale);
+
+ Optimizer::optimize_positions_fixed(hierarchy, edge_values, edge_diff, sharp_vertices,
+ sharp_constraints, flag_adaptive_scale);
+
+ AdvancedExtractQuad();
+
+ FixValence();
+
+ std::vector<int> sharp_o(O_compact.size(), 0);
+ std::map<int, std::pair<Vector3d, Vector3d>> compact_sharp_constraints;
+ for (int i = 0; i < Vset.size(); ++i) {
+ int sharpv = -1;
+ for (auto& p : Vset[i]) {
+ if (sharp_constraints.count(p)) {
+ sharpv = p;
+ sharp_o[i] = 1;
+ if (compact_sharp_constraints.count(i) == 0 ||
+ compact_sharp_constraints[i].second != Vector3d::Zero()) {
+ compact_sharp_constraints[i] = sharp_constraints[sharpv];
+ O_compact[i] = O.col(sharpv);
+ compact_sharp_constraints[i].first = O_compact[i];
+ }
+ }
+ }
+ }
+
+ std::map<std::pair<int, int>, int> o2e;
+ for (int i = 0; i < F_compact.size(); ++i) {
+ for (int j = 0; j < 4; ++j) {
+ int v1 = F_compact[i][j];
+ int v2 = F_compact[i][(j + 1) % 4];
+ o2e[std::make_pair(v1, v2)] = i * 4 + j;
+ }
+ }
+ std::vector<std::vector<int>> v2o(V.cols());
+ for (int i = 0; i < Vset.size(); ++i) {
+ for (auto v : Vset[i]) {
+ v2o[v].push_back(i);
+ }
+ }
+ std::vector<Vector3d> diffs(F_compact.size() * 4, Vector3d(0, 0, 0));
+ std::vector<int> diff_count(F_compact.size() * 4, 0);
+ for (int i = 0; i < F.cols(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ int v1 = F(j, i);
+ int v2 = F((j + 1) % 3, i);
+ if (v1 != edge_values[face_edgeIds[i][j]].x) continue;
+ if (edge_diff[face_edgeIds[i][j]].array().abs().sum() != 1) continue;
+ if (v2o[v1].size() > 1 || v2o[v2].size() > 1) continue;
+ for (auto o1 : v2o[v1]) {
+ for (auto o2 : v2o[v2]) {
+ auto key = std::make_pair(o1, o2);
+ if (o2e.count(key)) {
+ int dedge = o2e[key];
+ Vector3d q_1 = Q.col(v1);
+ Vector3d q_2 = Q.col(v2);
+ Vector3d n_1 = N.col(v1);
+ Vector3d n_2 = N.col(v2);
+ Vector3d q_1_y = n_1.cross(q_1);
+ Vector3d q_2_y = n_2.cross(q_2);
+ auto index = compat_orientation_extrinsic_index_4(q_1, n_1, q_2, n_2);
+ double s_x1 = S(0, v1), s_y1 = S(1, v1);
+ double s_x2 = S(0, v2), s_y2 = S(1, v2);
+ int rank_diff = (index.second + 4 - index.first) % 4;
+ if (rank_diff % 2 == 1) std::swap(s_x2, s_y2);
+ Vector3d qd_x = 0.5 * (rotate90_by(q_2, n_2, rank_diff) + q_1);
+ Vector3d qd_y = 0.5 * (rotate90_by(q_2_y, n_2, rank_diff) + q_1_y);
+ double scale_x = (with_scale ? 0.5 * (s_x1 + s_x2) : 1) * hierarchy.mScale;
+ double scale_y = (with_scale ? 0.5 * (s_y1 + s_y2) : 1) * hierarchy.mScale;
+ Vector2i diff = edge_diff[face_edgeIds[i][j]];
+ Vector3d C = diff[0] * scale_x * qd_x + diff[1] * scale_y * qd_y;
+
+ diff_count[dedge] += 1;
+ diffs[dedge] += C;
+ auto key = std::make_pair(o2, o1);
+ if (o2e.count(key)) {
+ int dedge = o2e[key];
+ diff_count[dedge] += 1;
+ diffs[dedge] -= C;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < F.cols(); ++i) {
+ Vector2i d1 = rshift90(edge_diff[face_edgeIds[i][0]], face_edgeOrients[i][0]);
+ Vector2i d2 = rshift90(edge_diff[face_edgeIds[i][1]], face_edgeOrients[i][1]);
+ if (d1[0] * d2[1] - d1[1] * d2[0] < 0) {
+ for (int j = 0; j < 3; ++j) {
+ int v1 = F(j, i);
+ int v2 = F((j + 1) % 3, i);
+ for (auto o1 : v2o[v1]) {
+ for (auto o2 : v2o[v2]) {
+ auto key = std::make_pair(o1, o2);
+ if (o2e.count(key)) {
+ int dedge = o2e[key];
+ diff_count[dedge] = 0;
+ diffs[dedge] = Vector3d(0, 0, 0);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < diff_count.size(); ++i) {
+ if (diff_count[i] != 0) {
+ diffs[i] /= diff_count[i];
+ diff_count[i] = 1;
+ }
+ }
+
+ Optimizer::optimize_positions_dynamic(F, V, N, Q, Vset, O_compact, F_compact, V2E_compact,
+ E2E_compact, sqrt(surface_area / F_compact.size()),
+ diffs, diff_count, o2e, sharp_o,
+ compact_sharp_constraints, flag_adaptive_scale);
+
+ // optimize_quad_positions(O_compact, N_compact, Q_compact, F_compact, V2E_compact,
+ // E2E_compact,
+ // V, N, Q, O, F, V2E, hierarchy.mE2E, disajoint_tree,
+ // hierarchy.mScale, false);
+}
+
+} // namespace qflow
diff --git a/extern/quadriflow/src/parametrizer.hpp b/extern/quadriflow/src/parametrizer.hpp
new file mode 100644
index 00000000000..1f4a02be6c2
--- /dev/null
+++ b/extern/quadriflow/src/parametrizer.hpp
@@ -0,0 +1,177 @@
+#ifndef PARAMETRIZER_H_
+#define PARAMETRIZER_H_
+#include <atomic>
+#include <condition_variable>
+#ifdef WITH_TBB
+#include <tbb/tbb.h>
+#endif
+
+#include <Eigen/Core>
+#include <Eigen/Dense>
+#include <list>
+#include <map>
+#include <set>
+#include <unordered_set>
+#include "adjacent-matrix.hpp"
+#include "disajoint-tree.hpp"
+#include "field-math.hpp"
+#include "hierarchy.hpp"
+#include "post-solver.hpp"
+#include "serialize.hpp"
+
+namespace qflow {
+
+using namespace Eigen;
+
+typedef std::pair<unsigned int, unsigned int> Edge;
+typedef std::map<int, std::pair<int, int>> SingDictionary;
+
+struct ExpandInfo {
+ ExpandInfo() {}
+ int current_v;
+ int singularity;
+ int step;
+ int edge_id;
+ int prev;
+};
+
+class Parametrizer {
+ public:
+ Parametrizer() {}
+ // Mesh Initialization
+ void Load(const char* filename);
+ void NormalizeMesh();
+ void ComputeMeshStatus();
+ void ComputeSmoothNormal();
+ void ComputeSharpEdges();
+ void ComputeSharpO();
+ void ComputeVertexArea();
+ void Initialize(int faces);
+
+ // Singularity and Mesh property
+ void AnalyzeValence();
+ void ComputeOrientationSingularities();
+ void ComputePositionSingularities();
+
+ // Integer Grid Map Pipeline
+ void ComputeIndexMap(int with_scale = 0);
+ void BuildEdgeInfo();
+ void ComputeMaxFlow();
+ void MarkInteger();
+ void BuildIntegerConstraints();
+
+ // Fix Flip
+ void FixFlipHierarchy();
+ void FixFlipSat();
+ void FixHoles();
+ void FixHoles(std::vector<int>& loop_vertices);
+ void FixValence();
+ double QuadEnergy(std::vector<int>& loop_vertices, std::vector<Vector4i>& res_quads,
+ int level);
+
+ // Quadmesh and IO
+ void AdvancedExtractQuad();
+ void BuildTriangleManifold(DisajointTree& disajoint_tree, std::vector<int>& edge,
+ std::vector<int>& face, std::vector<DEdge>& edge_values,
+ std::vector<Vector3i>& F2E, std::vector<Vector2i>& E2F,
+ std::vector<Vector2i>& EdgeDiff, std::vector<Vector3i>& FQ);
+ void OutputMesh(const char* obj_name);
+
+ std::map<int, int> singularities; // map faceid to valence (1 (valence=3) or 3(valence=5))
+ std::map<int, Vector2i> pos_sing;
+ MatrixXi pos_rank; // pos_rank(i, j) i \in [0, 3) jth face ith vertex rotate by its value so
+ // that all thress vertices are in the same orientation
+ MatrixXi pos_index; // pos_index(i x 2 + dim, j) i \in [0, 6) jth face ith vertex's
+ // (t_ij-t_ji)'s dim's dimenstion in the paper
+ // input mesh
+ MatrixXd V;
+ MatrixXd N;
+ MatrixXd Nf;
+ MatrixXd FS;
+ MatrixXd FQ;
+ MatrixXi F;
+
+ double normalize_scale;
+ Vector3d normalize_offset;
+
+ // data structures
+ VectorXd rho;
+ VectorXi V2E;
+ VectorXi E2E;
+ VectorXi boundary;
+ VectorXi nonManifold; // nonManifold vertices, in boolean
+ AdjacentMatrix adj;
+ Hierarchy hierarchy;
+
+ // Mesh Status;
+ double surface_area;
+ double scale;
+ double average_edge_length;
+ double max_edge_length;
+ VectorXd A;
+
+ // just for test
+ DisajointTree disajoint_tree;
+
+ int compact_num_v;
+ std::vector<std::vector<int>> Vset;
+ std::vector<Vector3d> O_compact;
+ std::vector<Vector3d> Q_compact;
+ std::vector<Vector3d> N_compact;
+ std::vector<Vector4i> F_compact;
+ std::set<std::pair<int, int>> Quad_edges;
+ std::vector<int> V2E_compact;
+ std::vector<int> E2E_compact;
+ VectorXi boundary_compact;
+ VectorXi nonManifold_compact;
+
+ std::vector<int> bad_vertices;
+ std::vector<double> counter;
+ std::vector<int>
+ sharp_edges; // sharp_edges[deid]: whether deid is a sharp edge that should be preserved
+ std::vector<int> allow_changes; // allow_changes[variable_id]: whether var can be changed
+ // based on sharp edges
+ std::vector<Vector2i> edge_diff; // edge_diff[edgeIds[i](j)]: t_ij+t_ji under
+ // edge_values[edgeIds[i](j)].x's Q value
+ std::vector<DEdge> edge_values; // see above
+ std::vector<Vector3i>
+ face_edgeIds; // face_edgeIds[i](j): ith face jth edge's "undirected edge ID"
+
+ // face_edgeOrients[i](j): Rotate from edge_diff space
+ // (a) initially, to F(0, i)'s Q space
+ // (b) later on, to a global Q space where some edges are fixed
+ std::vector<Vector3i> face_edgeOrients;
+
+ // variable[i].first: indices of the two equations corresponding to variable i
+ // variable[i].second: number of positive minus negative of variables' occurances
+ std::vector<std::pair<Vector2i, int>> variables;
+
+ struct QuadInfo {
+ QuadInfo() : patchId(-1), coordinate(0x10000000, 0x10000000), singular(0), edge(0) {}
+ int patchId;
+ Vector2i coordinate;
+ int singular;
+ int edge;
+ };
+ std::vector<QuadInfo> quad_info;
+
+ // scale
+ void ComputeInverseAffine();
+ void EstimateSlope();
+ std::vector<MatrixXd> triangle_space;
+
+ // flag
+ int flag_preserve_sharp = 0;
+ int flag_preserve_boundary = 0;
+ int flag_adaptive_scale = 0;
+ int flag_aggresive_sat = 0;
+ int flag_minimum_cost_flow = 0;
+};
+
+extern void generate_adjacency_matrix_uniform(const MatrixXi& F, const VectorXi& V2E,
+ const VectorXi& E2E, const VectorXi& nonManifold,
+ AdjacentMatrix& adj);
+
+} // namespace qflow
+
+#endif
diff --git a/extern/quadriflow/src/post-solver.cpp b/extern/quadriflow/src/post-solver.cpp
new file mode 100644
index 00000000000..6027ddd2eb7
--- /dev/null
+++ b/extern/quadriflow/src/post-solver.cpp
@@ -0,0 +1,427 @@
+//
+// post-solver.cpp
+// parametrize
+//
+// Created by Jingwei on 2/5/18.
+//
+#include <algorithm>
+#include <boost/program_options.hpp>
+#include <cmath>
+#include <cstdio>
+#include <string>
+
+#include "ceres/ceres.h"
+#include "ceres/rotation.h"
+
+#include "post-solver.hpp"
+#include "serialize.hpp"
+
+namespace qflow {
+
+/// Coefficient of area constraint. The magnitude is 1 if area is equal to 0.
+const double COEFF_AREA = 1;
+/// Coefficient of tangent constraint. The magnitude is 0.03 if the bais is reference_length.
+/// This is because current tangent constraint is not very accurate.
+/// This optimization conflicts with COEFF_AREA.
+const double COEFF_TANGENT = 0.02;
+/// Coefficient of normal constraint. The magnitude is the arc angle.
+const double COEFF_NORMAL = 1;
+/// Coefficient of normal constraint. The magnitude is the arc angle.
+const double COEFF_FLOW = 1;
+/// Coefficient of orthogonal edge. The magnitude is the arc angle.
+const double COEFF_ORTH = 1;
+/// Coefficient of edge length. The magnitude is the arc angle.
+const double COEFF_LENGTH = 1;
+/// Number of iterations of the CGNR solver
+const int N_ITER = 100;
+
+template <typename T, typename T2>
+T DotProduct(const T a[3], const T2 b[3]) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+}
+
+template <typename T>
+T Length2(const T a[3]) {
+ return DotProduct(a, a);
+}
+
+namespace ceres {
+inline double min(const double f, const double g) { return std::min(f, g); }
+
+template <typename T, int N>
+inline Jet<T, N> min(const Jet<T, N>& f, const Jet<T, N>& g) {
+ if (f.a < g.a)
+ return f;
+ else
+ return g;
+}
+} // namespace ceres
+
+bool DEBUG = 0;
+struct FaceConstraint {
+ FaceConstraint(double coeff_area, double coeff_normal, double coeff_flow, double coeff_orth,
+ double length, Vector3d normal[4], Vector3d Q0[4], Vector3d Q1[4])
+ : coeff_area(coeff_area),
+ coeff_normal(coeff_normal),
+ coeff_flow(coeff_flow),
+ coeff_orth(coeff_orth),
+ area0(length * length),
+ normal0{
+ normal[0],
+ normal[1],
+ normal[2],
+ normal[3],
+ },
+ Q0{Q0[0], Q0[1], Q0[2], Q0[3]},
+ Q1{Q1[0], Q1[1], Q1[2], Q1[3]} {}
+
+ template <typename T>
+ bool operator()(const T* p0, const T* p1, const T* p2, const T* p3, T* r) const {
+ const T* p[] = {p0, p1, p2, p3};
+ r[12] = T();
+ for (int k = 0; k < 4; ++k) {
+ auto pc = p[k];
+ auto pa = p[(k + 1) % 4];
+ auto pb = p[(k + 3) % 4];
+
+ T a[3]{pa[0] - pc[0], pa[1] - pc[1], pa[2] - pc[2]};
+ T b[3]{pb[0] - pc[0], pb[1] - pc[1], pb[2] - pc[2]};
+
+ T length_a = ceres::sqrt(Length2(a));
+ T length_b = ceres::sqrt(Length2(b));
+ T aa[3]{a[0] / length_a, a[1] / length_a, a[2] / length_a};
+ T bb[3]{b[0] / length_b, b[1] / length_b, b[2] / length_b};
+ r[3 * k + 0] = coeff_orth * DotProduct(aa, bb);
+
+ T degree_edge0 = ceres::abs(DotProduct(aa, &Q0[k][0]));
+ T degree_edge1 = ceres::abs(DotProduct(aa, &Q1[k][0]));
+ T degree_edge = ceres::min(degree_edge0, degree_edge1);
+ r[3 * k + 1] = coeff_flow * degree_edge;
+
+ T normal[3];
+ ceres::CrossProduct(a, b, normal);
+ T area = ceres::sqrt(Length2(normal));
+ r[12] += area;
+
+ assert(area != T());
+ for (int i = 0; i < 3; ++i) normal[i] /= area;
+ T degree_normal = DotProduct(normal, &normal0[k][0]) - T(1);
+ r[3 * k + 2] = coeff_normal * degree_normal * degree_normal;
+ }
+ r[12] = coeff_area * (r[12] / (4.0 * area0) - 1.0);
+ return true;
+ }
+
+ static ceres::CostFunction* create(double coeff_area, double coeff_normal, double coeff_flow,
+ double coeff_orth, double length, Vector3d normal[4],
+ Vector3d Q0[4], Vector3d Q1[4]) {
+ return new ceres::AutoDiffCostFunction<FaceConstraint, 13, 3, 3, 3, 3>(new FaceConstraint(
+ coeff_area, coeff_normal, coeff_flow, coeff_orth, length, normal, Q0, Q1));
+ }
+
+ double coeff_area;
+ double coeff_normal;
+ double coeff_flow;
+ double coeff_orth;
+
+ double area0;
+ Vector3d normal0[4];
+ Vector3d Q0[4], Q1[4];
+};
+
+struct VertexConstraint {
+ VertexConstraint(double coeff_tangent, Vector3d normal, double bias, double length)
+ : coeff{coeff_tangent / length * 10}, bias0{bias}, normal0{normal} {}
+
+ template <typename T>
+ bool operator()(const T* p, T* r) const {
+ r[0] = coeff * (DotProduct(p, &normal0[0]) - bias0);
+ return true;
+ }
+
+ static ceres::CostFunction* create(double coeff_tangent, Vector3d normal, double bias,
+ double length) {
+ return new ceres::AutoDiffCostFunction<VertexConstraint, 1, 3>(
+ new VertexConstraint(coeff_tangent, normal, bias, length));
+ }
+
+ double coeff;
+ double bias0;
+ Vector3d normal0;
+};
+
+void solve(std::vector<Vector3d>& O_quad, std::vector<Vector3d>& N_quad,
+ std::vector<Vector3d>& Q_quad, std::vector<Vector4i>& F_quad,
+ std::vector<double>& B_quad, MatrixXd& V, MatrixXd& N, MatrixXd& Q, MatrixXd& O,
+ MatrixXi& F, double reference_length, double coeff_area, double coeff_tangent,
+ double coeff_normal, double coeff_flow, double coeff_orth) {
+ printf("Parameter: \n");
+ printf(" coeff_area: %.4f\n", coeff_area);
+ printf(" coeff_tangent: %.4f\n", coeff_tangent);
+ printf(" coeff_normal: %.4f\n", coeff_normal);
+ printf(" coeff_flow: %.4f\n", coeff_flow);
+ printf(" coeff_orth: %.4f\n\n", coeff_orth);
+ int n_quad = Q_quad.size();
+
+ ceres::Problem problem;
+ std::vector<double> solution(n_quad * 3);
+ for (int vquad = 0; vquad < n_quad; ++vquad) {
+ solution[3 * vquad + 0] = O_quad[vquad][0];
+ solution[3 * vquad + 1] = O_quad[vquad][1];
+ solution[3 * vquad + 2] = O_quad[vquad][2];
+ }
+
+ // Face constraint (area and normal direction)
+ for (int fquad = 0; fquad < F_quad.size(); ++fquad) {
+ auto v = F_quad[fquad];
+ Vector3d normal[4], Q0[4], Q1[4];
+ for (int k = 0; k < 4; ++k) {
+ normal[k] = N_quad[v[k]];
+ Q0[k] = Q_quad[v[k]];
+ Q1[k] = Q0[k].cross(normal[k]).normalized();
+ }
+ ceres::CostFunction* cost_function = FaceConstraint::create(
+ coeff_area, coeff_normal, coeff_flow, coeff_orth, reference_length, normal, Q0, Q1);
+ problem.AddResidualBlock(cost_function, nullptr, &solution[3 * v[0]], &solution[3 * v[1]],
+ &solution[3 * v[2]], &solution[3 * v[3]]);
+ }
+
+ // Tangent constraint
+ for (int vquad = 0; vquad < O_quad.size(); ++vquad) {
+ ceres::CostFunction* cost_function = VertexConstraint::create(
+ coeff_tangent, N_quad[vquad], B_quad[vquad], reference_length);
+ problem.AddResidualBlock(cost_function, nullptr, &solution[3 * vquad]);
+ }
+
+ // Flow constraint
+
+ ceres::Solver::Options options;
+ options.num_threads = 1;
+ options.max_num_iterations = N_ITER;
+ options.initial_trust_region_radius = 1;
+ options.linear_solver_type = ceres::CGNR;
+ options.minimizer_progress_to_stdout = true;
+ ceres::Solver::Summary summary;
+ ceres::Solve(options, &problem, &summary);
+
+ std::cout << summary.BriefReport() << std::endl;
+
+ for (int vquad = 0; vquad < n_quad; ++vquad) {
+ O_quad[vquad][0] = solution[3 * vquad + 0];
+ O_quad[vquad][1] = solution[3 * vquad + 1];
+ O_quad[vquad][2] = solution[3 * vquad + 2];
+ }
+
+ return;
+}
+
+void optimize_quad_positions(std::vector<Vector3d>& O_quad, std::vector<Vector3d>& N_quad,
+ std::vector<Vector3d>& Q_quad, std::vector<Vector4i>& F_quad,
+ VectorXi& V2E_quad, std::vector<int>& E2E_quad, MatrixXd& V,
+ MatrixXd& N, MatrixXd& Q, MatrixXd& O, MatrixXi& F, VectorXi& V2E,
+ VectorXi& E2E, DisajointTree& disajoint_tree, double reference_length,
+ bool just_serialize) {
+ printf("Quad mesh info:\n");
+ printf("Number of vertices with normals and orientations: %d = %d = %d\n", (int)O_quad.size(),
+ (int)N_quad.size(), (int)Q_quad.size());
+ printf("Number of faces: %d\n", (int)F_quad.size());
+ printf("Number of directed edges: %d\n", (int)E2E_quad.size());
+ // Information for the original mesh
+ printf("Triangle mesh info:\n");
+ printf(
+ "Number of vertices with normals, "
+ "orientations and associated quad positions: "
+ "%d = %d = %d = %d\n",
+ (int)V.cols(), (int)N.cols(), (int)Q.cols(), (int)O.cols());
+ printf("Number of faces: %d\n", (int)F.cols());
+ printf("Number of directed edges: %d\n", (int)E2E.size());
+ printf("Reference length: %.2f\n", reference_length);
+
+ int flip_count = 0;
+ for (int i = 0; i < F_quad.size(); ++i) {
+ bool flipped = false;
+ for (int j = 0; j < 4; ++j) {
+ int v1 = F_quad[i][j];
+ int v2 = F_quad[i][(j + 1) % 4];
+ int v3 = F_quad[i][(j + 3) % 4];
+
+ Vector3d face_norm = (O_quad[v2] - O_quad[v1]).cross(O_quad[v3] - O_quad[v1]);
+ Vector3d vertex_norm = N_quad[v1];
+ if (face_norm.dot(vertex_norm) < 0) {
+ flipped = true;
+ }
+ }
+ if (flipped) {
+ flip_count++;
+ }
+ }
+ printf("Flipped Quads: %d\n", flip_count);
+
+ int n_quad = O_quad.size();
+ int n_trig = O.cols();
+ std::vector<double> B_quad(n_quad); // Average bias for quad vertex
+ std::vector<int> B_weight(n_quad);
+
+ printf("ntrig: %d, disjoint_tree.size: %d\n", n_trig, (int)disajoint_tree.indices.size());
+ for (int vtrig = 0; vtrig < n_trig; ++vtrig) {
+ int vquad = disajoint_tree.Index(vtrig);
+ double b = N_quad[vquad].dot(O.col(vtrig));
+ B_quad[vquad] += b;
+ B_weight[vquad] += 1;
+ }
+ for (int vquad = 0; vquad < n_quad; ++vquad) {
+ assert(B_weight[vquad]);
+ B_quad[vquad] /= B_weight[vquad];
+ }
+
+ puts("Save parameters to post.bin for optimization");
+ FILE* out = fopen("post.bin", "wb");
+ assert(out);
+ Save(out, O_quad);
+ Save(out, N_quad);
+ Save(out, Q_quad);
+ Save(out, F_quad);
+ Save(out, B_quad);
+ Save(out, V);
+ Save(out, N);
+ Save(out, Q);
+ Save(out, O);
+ Save(out, F);
+ Save(out, reference_length);
+ fclose(out);
+
+ if (!just_serialize) {
+ puts("Start post optimization");
+ solve(O_quad, N_quad, Q_quad, F_quad, B_quad, V, N, Q, O, F, reference_length, COEFF_AREA,
+ COEFF_TANGENT, COEFF_NORMAL, COEFF_FLOW, COEFF_ORTH);
+ }
+}
+
+#ifdef POST_SOLVER
+
+void SaveObj(const std::string& fname, std::vector<Vector3d> O_quad,
+ std::vector<Vector4i> F_quad) {
+ std::ofstream os(fname);
+ for (int i = 0; i < (int)O_quad.size(); ++i) {
+ os << "v " << O_quad[i][0] << " " << O_quad[i][1] << " " << O_quad[i][2] << "\n";
+ }
+ for (int i = 0; i < (int)F_quad.size(); ++i) {
+ os << "f " << F_quad[i][0] + 1 << " " << F_quad[i][1] + 1 << " " << F_quad[i][2] + 1 << " "
+ << F_quad[i][3] + 1 << "\n";
+ }
+ os.close();
+}
+
+int main(int argc, char* argv[]) {
+ double coeff_area;
+ double coeff_tangent;
+ double coeff_normal;
+ double coeff_flow;
+ double coeff_orth;
+
+ namespace po = boost::program_options;
+ po::options_description desc("Allowed options");
+ desc.add_options() // clang-format off
+ ("help,h", "produce help message")
+ ("area,a", po::value<double>(&coeff_area)->default_value(COEFF_AREA), "Set the coefficient of area constraint")
+ ("tangent,t", po::value<double>(&coeff_tangent)->default_value(COEFF_TANGENT), "Set the coefficient of tangent constraint")
+ ("normal,n", po::value<double>(&coeff_normal)->default_value(COEFF_NORMAL), "Set the coefficient of normal constraint")
+ ("flow,f", po::value<double>(&coeff_flow)->default_value(COEFF_FLOW), "Set the coefficient of flow (Q) constraint")
+ ("orth,o", po::value<double>(&coeff_orth)->default_value(COEFF_ORTH), "Set the coefficient of orthogonal constraint");
+
+ // clang-format on
+ po::variables_map vm;
+ po::store(po::parse_command_line(argc, argv, desc), vm);
+ po::notify(vm);
+ if (vm.count("help")) {
+ std::cout << desc << std::endl;
+ return 1;
+ }
+
+ std::vector<Vector3d> O_quad;
+ std::vector<Vector3d> N_quad;
+ std::vector<Vector3d> Q_quad;
+ std::vector<Vector4i> F_quad;
+ std::vector<double> B_quad;
+ MatrixXd V;
+ MatrixXd N;
+ MatrixXd Q;
+ MatrixXd O;
+ MatrixXi F;
+ double reference_length;
+
+ puts("Read parameters from post.bin");
+ FILE* in = fopen("post.bin", "rb");
+ assert(in);
+ Read(in, O_quad);
+ Read(in, N_quad);
+ Read(in, Q_quad);
+ Read(in, F_quad);
+ Read(in, B_quad);
+ Read(in, V);
+ Read(in, N);
+ Read(in, Q);
+ Read(in, O);
+ Read(in, F);
+ Read(in, reference_length);
+ fclose(in);
+ printf("reference_length: %.2f\n", reference_length);
+ SaveObj("presolver.obj", O_quad, F_quad);
+
+ int n_flip = 0;
+ double sum_degree = 0;
+ for (int i = 0; i < F_quad.size(); ++i) {
+ bool flipped = false;
+ for (int j = 0; j < 4; ++j) {
+ int v1 = F_quad[i][j];
+ int v2 = F_quad[i][(j + 1) % 4];
+ int v3 = F_quad[i][(j + 3) % 4];
+
+ Vector3d face_norm =
+ (O_quad[v2] - O_quad[v1]).cross(O_quad[v3] - O_quad[v1]).normalized();
+ Vector3d vertex_norm = N_quad[v1];
+ if (face_norm.dot(vertex_norm) < 0) {
+ flipped = true;
+ }
+ double degree = std::acos(face_norm.dot(vertex_norm));
+ assert(degree >= 0);
+ // printf("cos theta = %.2f\n", degree);
+ sum_degree += degree * degree;
+ }
+ n_flip += flipped;
+ }
+ printf("n_flip: %d\nsum_degree: %.3f\n", n_flip, sum_degree);
+
+ puts("Start post optimization");
+ solve(O_quad, N_quad, Q_quad, F_quad, B_quad, V, N, Q, O, F, reference_length, coeff_area,
+ coeff_tangent, coeff_normal, coeff_flow, coeff_orth);
+ SaveObj("postsolver.obj", O_quad, F_quad);
+
+ n_flip = 0;
+ sum_degree = 0;
+ for (int i = 0; i < F_quad.size(); ++i) {
+ bool flipped = false;
+ for (int j = 0; j < 4; ++j) {
+ int v1 = F_quad[i][j];
+ int v2 = F_quad[i][(j + 1) % 4];
+ int v3 = F_quad[i][(j + 3) % 4];
+
+ Vector3d face_norm =
+ (O_quad[v2] - O_quad[v1]).cross(O_quad[v3] - O_quad[v1]).normalized();
+ Vector3d vertex_norm = N_quad[v1];
+ if (face_norm.dot(vertex_norm) < 0) {
+ flipped = true;
+ }
+ double degree = std::acos(face_norm.dot(vertex_norm));
+ assert(degree >= 0);
+ sum_degree += degree * degree;
+ }
+ n_flip += flipped;
+ }
+ printf("n_flip: %d\nsum_degree: %.3f\n", n_flip, sum_degree);
+ return 0;
+}
+
+#endif
+
+} // namespace qflow
diff --git a/extern/quadriflow/src/post-solver.hpp b/extern/quadriflow/src/post-solver.hpp
new file mode 100644
index 00000000000..546245d801e
--- /dev/null
+++ b/extern/quadriflow/src/post-solver.hpp
@@ -0,0 +1,64 @@
+//
+// post-solver.hpp
+// Parametrize
+//
+// Created by Jingwei on 2/5/18.
+//
+
+#ifndef post_solver_h
+#define post_solver_h
+
+#include <Eigen/Core>
+#include <vector>
+#include "disajoint-tree.hpp"
+
+namespace qflow {
+
+using namespace Eigen;
+
+/*
+ * TODO: Optimize O_quad, and possibly N_quad
+ * Input:
+ * O_quad[i]: initialized i-th vertex position of the quad mesh
+ * N_quad[i]: initialized i-th vertex normal of the quad mesh
+ * Q_quad[i]: initialized i-th vertex orientation of the quad mesh, guaranteed to be orthogonal to
+ * N_quad[i]
+ * F_quad[i]: 4 vertex index of the i-th quad face
+ *
+ * Concept: i-th directed edge is the (i%4)-th edge of the (i/4)-th face of the quad mesh
+ * V2E_quad[i]: one directed edge from i-th vertex of the quad mesh
+ * E2E_quad[i]: the reverse directed edge's index of the i-th directed edge of the quad mesh
+ *
+ * V.col(i): i-th vertex position of the triangle mesh
+ * N.col(i): i-th vertex normal of the triangle mesh
+ * Q.col(i): i-th vertex orientation of the triangle mesh, guaranteed to be orthogonal to N.col(i)
+ * O.col(i): "quad position" associated with the i-th vertex in the triangle mesh (see InstantMesh
+ * position field)
+ * F.col(i): i-th triangle of the triangle mesh
+ *
+ * V2E[i]: one directed edge from the i-th vertex of the triangle mesh
+ * E2E[i]: the reverse directed edge's index of the i-th directed edge of the triangle mesh
+ *
+ * j = disajoint_tree.Index(i)
+ * the j-th vertex of the quad mesh is corresponding to the i-th vertex of the triangle mesh
+ * the relation is one-to-multiple
+ * O_quad can be viewed as an average of corresponding O
+ * N_quad can be viewed as an average of corresponding N
+ * Q_quad can be viewed as aggregation of corresponding Q
+ * Method that aggregates qi to qj with weights wi and wj:
+ * value = compat_orientation_extrinsic_4(qj, nj, qi, ni)
+ * result = (value.first * wj + value.second * wi).normalized()
+ *
+ * Output:
+ * Optimized O_quad, (possibly N_quad)
+ */
+void optimize_quad_positions(std::vector<Vector3d>& O_quad, std::vector<Vector3d>& N_quad,
+ std::vector<Vector3d>& Q_quad, std::vector<Vector4i>& F_quad,
+ VectorXi& V2E_quad, std::vector<int>& E2E_quad, MatrixXd& V, MatrixXd& N,
+ MatrixXd& Q, MatrixXd& O, MatrixXi& F, VectorXi& V2E, VectorXi& E2E,
+ DisajointTree& disajoint_tree, double reference_length,
+ bool just_serialize = true);
+
+} // namespace qflow
+
+#endif /* post_solver_h */
diff --git a/extern/quadriflow/src/serialize.hpp b/extern/quadriflow/src/serialize.hpp
new file mode 100644
index 00000000000..3e670e02fa5
--- /dev/null
+++ b/extern/quadriflow/src/serialize.hpp
@@ -0,0 +1,127 @@
+#ifndef SERIALIZE_H_
+#define SERIALIZE_H_
+
+#include <Eigen/Core>
+#include <fstream>
+#include <map>
+#include <set>
+#include <vector>
+#include "adjacent-matrix.hpp"
+
+namespace qflow {
+
+template <typename T, int A, int B>
+inline void Save(FILE* fp, const Eigen::Matrix<T, A, B>& m) {
+ int r = m.rows(), c = m.cols();
+ fwrite(&r, sizeof(int), 1, fp);
+ fwrite(&c, sizeof(int), 1, fp);
+ std::vector<T> buffer(r * c);
+ for (int i = 0; i < r; ++i) {
+ for (int j = 0; j < c; ++j) {
+ buffer[i * c + j] = m(i, j);
+ }
+ }
+ fwrite(buffer.data(), sizeof(T), r * c, fp);
+}
+
+template <typename T, int A, int B>
+inline void Read(FILE* fp, Eigen::Matrix<T, A, B>& m) {
+ int r, c;
+ fread(&r, sizeof(int), 1, fp);
+ fread(&c, sizeof(int), 1, fp);
+ std::vector<T> buffer(r * c);
+ fread(buffer.data(), sizeof(T), r * c, fp);
+ m.resize(r, c);
+ for (int i = 0; i < r; ++i) {
+ for (int j = 0; j < c; ++j) {
+ m(i, j) = buffer[i * c + j];
+ }
+ }
+}
+
+inline void Save(FILE* fp, const Link& p) { fwrite(&p, sizeof(Link), 1, fp); }
+
+inline void Read(FILE* fp, Link& p) { fread(&p, sizeof(Link), 1, fp); }
+
+inline void Save(FILE* fp, const TaggedLink& p) { fwrite(&p, sizeof(TaggedLink), 1, fp); }
+
+inline void Read(FILE* fp, TaggedLink& p) { fread(&p, sizeof(TaggedLink), 1, fp); }
+
+inline void Save(FILE* fp, double p) { fwrite(&p, sizeof(double), 1, fp); }
+
+inline void Read(FILE* fp, double& p) { fread(&p, sizeof(double), 1, fp); }
+
+inline void Save(FILE* fp, int p) { fwrite(&p, sizeof(int), 1, fp); }
+
+inline void Read(FILE* fp, int& p) { fread(&p, sizeof(int), 1, fp); }
+
+template <class T, class F>
+inline void Save(FILE* fp, const std::pair<T, F>& p) {
+ fwrite(&p.first, sizeof(T), 1, fp);
+ fwrite(&p.second, sizeof(F), 1, fp);
+}
+
+template <class T, class F>
+inline void Read(FILE* fp, std::pair<T, F>& p) {
+ fread(&p.first, sizeof(T), 1, fp);
+ fread(&p.second, sizeof(F), 1, fp);
+}
+
+template <class T, class F>
+inline void Save(FILE* fp, const std::map<T, F>& p) {
+ int num = p.size();
+ fwrite(&num, sizeof(int), 1, fp);
+ for (auto& s : p) {
+ fwrite(&s, sizeof(s), 1, fp);
+ }
+}
+
+template <class T, class F>
+inline void Read(FILE* fp, std::map<T, F>& p) {
+ int num;
+ p.clear();
+ fread(&num, sizeof(int), 1, fp);
+ for (int i = 0; i < num; ++i) {
+ std::pair<T, F> m;
+ fread(&m, sizeof(m), 1, fp);
+ p.insert(m);
+ }
+}
+
+template <class T>
+void Save(FILE* fp, const std::vector<T>& p) {
+ int num = p.size();
+ fwrite(&num, sizeof(int), 1, fp);
+ for (auto& q : p) {
+ Save(fp, q);
+ }
+}
+
+template <class T>
+void Read(FILE* fp, std::vector<T>& p) {
+ int num;
+ fread(&num, sizeof(int), 1, fp);
+ p.resize(num);
+ for (auto& q : p) {
+ Read(fp, q);
+ }
+}
+
+template <class T>
+void Save(FILE* fp, const std::set<T>& p) {
+ std::vector<T> buffer;
+ buffer.insert(buffer.end(), p.begin(), p.end());
+ Save(fp, buffer);
+}
+
+template <class T>
+void Read(FILE* fp, std::set<T>& p) {
+ std::vector<T> buffer;
+ Read(fp, buffer);
+ p.clear();
+ for (auto& q : buffer) p.insert(q);
+}
+
+} // namespace qflow
+
+#endif
diff --git a/extern/quadriflow/src/subdivide.cpp b/extern/quadriflow/src/subdivide.cpp
new file mode 100644
index 00000000000..c408bbc6394
--- /dev/null
+++ b/extern/quadriflow/src/subdivide.cpp
@@ -0,0 +1,516 @@
+#include "subdivide.hpp"
+
+#include <fstream>
+#include <queue>
+
+#include "dedge.hpp"
+#include "disajoint-tree.hpp"
+#include "field-math.hpp"
+#include "parametrizer.hpp"
+
+namespace qflow {
+
+void subdivide(MatrixXi &F, MatrixXd &V, VectorXd& rho, VectorXi &V2E, VectorXi &E2E, VectorXi &boundary,
+ VectorXi &nonmanifold, double maxLength) {
+ typedef std::pair<double, int> Edge;
+
+ std::priority_queue<Edge> queue;
+
+ maxLength *= maxLength;
+
+ for (int i = 0; i < E2E.size(); ++i) {
+ int v0 = F(i % 3, i / 3), v1 = F((i + 1) % 3, i / 3);
+ if (nonmanifold[v0] || nonmanifold[v1]) continue;
+ double length = (V.col(v0) - V.col(v1)).squaredNorm();
+ if (length > maxLength || length > std::max(maxLength * 0.75, std::min(rho[v0], rho[v1]) * 1.0)) {
+ int other = E2E[i];
+ if (other == -1 || other > i) queue.push(Edge(length, i));
+ }
+ }
+
+ int nV = V.cols(), nF = F.cols(), nSplit = 0;
+ /*
+ / v0 \
+ v1p 1 | 0 v0p
+ \ v1 /
+
+ / v0 \
+ / 1 | 0 \
+ v1p - vn - v0p
+ \ 2 | 3 /
+ \ v1 /
+
+ f0: vn, v0p, v0
+ f1: vn, v0, v1p
+ f2: vn, v1p, v1
+ f3: vn, v1, v0p
+ */
+ int counter = 0;
+ while (!queue.empty()) {
+ counter += 1;
+ Edge edge = queue.top();
+ queue.pop();
+ int e0 = edge.second, e1 = E2E[e0];
+ bool is_boundary = e1 == -1;
+ int f0 = e0 / 3, f1 = is_boundary ? -1 : (e1 / 3);
+ int v0 = F(e0 % 3, f0), v0p = F((e0 + 2) % 3, f0), v1 = F((e0 + 1) % 3, f0);
+ if ((V.col(v0) - V.col(v1)).squaredNorm() != edge.first) {
+ continue;
+ }
+ int v1p = is_boundary ? -1 : F((e1 + 2) % 3, f1);
+ int vn = nV++;
+ nSplit++;
+ /* Update V */
+ if (nV > V.cols()) {
+ V.conservativeResize(V.rows(), V.cols() * 2);
+ rho.conservativeResize(V.cols() * 2);
+ V2E.conservativeResize(V.cols());
+ boundary.conservativeResize(V.cols());
+ nonmanifold.conservativeResize(V.cols());
+ }
+
+ /* Update V */
+ V.col(vn) = (V.col(v0) + V.col(v1)) * 0.5f;
+ rho[vn] = 0.5f * (rho[v0], rho[v1]);
+ nonmanifold[vn] = false;
+ boundary[vn] = is_boundary;
+
+ /* Update F and E2E */
+ int f2 = is_boundary ? -1 : (nF++);
+ int f3 = nF++;
+ if (nF > F.cols()) {
+ F.conservativeResize(F.rows(), std::max(nF, (int)F.cols() * 2));
+ E2E.conservativeResize(F.cols() * 3);
+ }
+
+ /* Update F */
+ F.col(f0) << vn, v0p, v0;
+ if (!is_boundary) {
+ F.col(f1) << vn, v0, v1p;
+ F.col(f2) << vn, v1p, v1;
+ }
+ F.col(f3) << vn, v1, v0p;
+
+ /* Update E2E */
+ const int e0p = E2E[dedge_prev_3(e0)], e0n = E2E[dedge_next_3(e0)];
+
+#define sE2E(a, b) \
+ E2E[a] = b; \
+ if (b != -1) E2E[b] = a;
+ sE2E(3 * f0 + 0, 3 * f3 + 2);
+ sE2E(3 * f0 + 1, e0p);
+ sE2E(3 * f3 + 1, e0n);
+ if (is_boundary) {
+ sE2E(3 * f0 + 2, -1);
+ sE2E(3 * f3 + 0, -1);
+ } else {
+ const int e1p = E2E[dedge_prev_3(e1)], e1n = E2E[dedge_next_3(e1)];
+ sE2E(3 * f0 + 2, 3 * f1 + 0);
+ sE2E(3 * f1 + 1, e1n);
+ sE2E(3 * f1 + 2, 3 * f2 + 0);
+ sE2E(3 * f2 + 1, e1p);
+ sE2E(3 * f2 + 2, 3 * f3 + 0);
+ }
+#undef sE2E
+
+ /* Update V2E */
+ V2E[v0] = 3 * f0 + 2;
+ V2E[vn] = 3 * f0 + 0;
+ V2E[v1] = 3 * f3 + 1;
+ V2E[v0p] = 3 * f0 + 1;
+ if (!is_boundary) V2E[v1p] = 3 * f1 + 2;
+
+ auto schedule = [&](int f) {
+ for (int i = 0; i < 3; ++i) {
+ double length = (V.col(F(i, f)) - V.col(F((i + 1) % 3, f))).squaredNorm();
+ if (length > maxLength
+ || length > std::max(maxLength * 0.75, std::min(rho[F(i, f)], rho[F((i + 1) % 3, f)]) * 1.0))
+ queue.push(Edge(length, f * 3 + i));
+ }
+ };
+
+ schedule(f0);
+ if (!is_boundary) {
+ schedule(f2);
+ schedule(f1);
+ };
+ schedule(f3);
+ }
+ F.conservativeResize(F.rows(), nF);
+ V.conservativeResize(V.rows(), nV);
+ rho.conservativeResize(nV);
+ V2E.conservativeResize(nV);
+ boundary.conservativeResize(nV);
+ nonmanifold.conservativeResize(nV);
+ E2E.conservativeResize(nF * 3);
+}
+
+void subdivide_edgeDiff(MatrixXi &F, MatrixXd &V, MatrixXd &N, MatrixXd &Q, MatrixXd &O, MatrixXd* S,
+ VectorXi &V2E, VectorXi &E2E, VectorXi &boundary, VectorXi &nonmanifold,
+ std::vector<Vector2i> &edge_diff, std::vector<DEdge> &edge_values,
+ std::vector<Vector3i> &face_edgeOrients, std::vector<Vector3i> &face_edgeIds,
+ std::vector<int>& sharp_edges, std::map<int, int> &singularities, int max_len) {
+ struct EdgeLink {
+ int id;
+ double length;
+ Vector2i diff;
+ int maxlen() const { return std::max(abs(diff[0]), abs(diff[1])); }
+ bool operator<(const EdgeLink &link) const { return maxlen() < link.maxlen(); }
+ };
+
+ struct FaceOrient {
+ int orient;
+ Vector3i d;
+ Vector3d q;
+ Vector3d n;
+ };
+
+ std::vector<FaceOrient> face_spaces(F.cols());
+ std::priority_queue<EdgeLink> queue;
+ std::vector<Vector2i> diffs(E2E.size());
+ for (int i = 0; i < F.cols(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ int eid = i * 3 + j;
+ diffs[eid] = rshift90(edge_diff[face_edgeIds[i][j]], face_edgeOrients[i][j]);
+ }
+ }
+ for (int i = 0; i < F.cols(); ++i) {
+ FaceOrient orient{};
+ orient.q = Q.col(F(0, i));
+ orient.n = N.col(F(0, i));
+ int orient_diff[3];
+ for (int j = 0; j < 3; ++j) {
+ int final_orient = face_edgeOrients[i][j];
+ int eid = face_edgeIds[i][j];
+ auto value = compat_orientation_extrinsic_index_4(
+ Q.col(edge_values[eid].x), N.col(edge_values[eid].x), orient.q, orient.n);
+ int target_orient = (value.second - value.first + 4) % 4;
+ if (F(j, i) == edge_values[eid].y) target_orient = (target_orient + 2) % 4;
+ orient_diff[j] = (final_orient - target_orient + 4) % 4;
+ }
+ if (orient_diff[0] == orient_diff[1])
+ orient.orient = orient_diff[0];
+ else if (orient_diff[0] == orient_diff[2])
+ orient.orient = orient_diff[2];
+ else if (orient_diff[1] == orient_diff[2])
+ orient.orient = orient_diff[1];
+ orient.d = Vector3i((orient_diff[0] - orient.orient + 4) % 4,
+ (orient_diff[1] - orient.orient + 4) % 4,
+ (orient_diff[2] - orient.orient + 4) % 4);
+ face_spaces[i] = (orient);
+ }
+ for (int i = 0; i < E2E.size(); ++i) {
+ int v0 = F(i % 3, i / 3), v1 = F((i + 1) % 3, i / 3);
+ if (nonmanifold[v0] || nonmanifold[v1]) continue;
+ double length = (V.col(v0) - V.col(v1)).squaredNorm();
+ Vector2i diff = diffs[i];
+ if (abs(diff[0]) > max_len || abs(diff[1]) > max_len) {
+ int other = E2E[i];
+ if (other == -1 || other > i) {
+ EdgeLink e;
+ e.id = i;
+ e.length = length;
+ e.diff = diff;
+ queue.push(e);
+ }
+ }
+ }
+ auto AnalyzeOrient = [&](int f0, const Vector3i &d) {
+ for (int j = 0; j < 3; ++j) {
+ int orient = face_spaces[f0].orient + d[j];
+ int v = std::min(F(j, f0), F((j + 1) % 3, f0));
+ auto value = compat_orientation_extrinsic_index_4(
+ Q.col(v), N.col(v), face_spaces[f0].q, face_spaces[f0].n);
+ if (F(j, f0) != v) orient += 2;
+ face_edgeOrients[f0][j] = (orient + value.second - value.first + 4) % 4;
+ }
+ face_spaces[f0].d = d;
+ for (int j = 0; j < 3; ++j) {
+ int eid = face_edgeIds[f0][j];
+ int orient = face_edgeOrients[f0][j];
+ auto diff = rshift90(diffs[f0 * 3 + j], (4 - orient) % 4);
+ edge_diff[eid] = diff;
+ }
+ };
+ auto FixOrient = [&](int f0) {
+ for (int j = 0; j < 3; ++j) {
+ auto diff = edge_diff[face_edgeIds[f0][j]];
+ if (rshift90(diff, face_edgeOrients[f0][j]) != diffs[f0 * 3 + j]) {
+ int orient = 0;
+ while (orient < 4 && rshift90(diff, orient) != diffs[f0 * 3 + j]) orient += 1;
+ face_spaces[f0].d[j] =
+ (face_spaces[f0].d[j] + orient - face_edgeOrients[f0][j]) % 4;
+ face_edgeOrients[f0][j] = orient;
+ }
+ }
+ };
+ /*
+ auto Length = [&](int f0) {
+ int l = 0;
+ for (int j = 0; j < 3; ++j) {
+ for (int k = 0; k < 2; ++k) {
+ l += abs(diffs[f0*3+j][k]);
+ }
+ printf("<%d %d> ", diffs[f0*3+j][0], diffs[f0*3+j][1]);
+ }
+ printf("\n");
+ return l;
+ };
+ */
+ int nV = V.cols(), nF = F.cols(), nSplit = 0;
+ /*
+ / v0 \
+ v1p 1 | 0 v0p
+ \ v1 /
+
+ / v0 \
+ / 1 | 0 \
+ v1p - vn - v0p
+ \ 2 | 3 /
+ \ v1 /
+
+ f0: vn, v0p, v0
+ f1: vn, v0, v1p
+ f2: vn, v1p, v1
+ f3: vn, v1, v0p
+ */
+ int counter = 0;
+ while (!queue.empty()) {
+ counter += 1;
+ EdgeLink edge = queue.top();
+ queue.pop();
+
+ int e0 = edge.id, e1 = E2E[e0];
+ bool is_boundary = e1 == -1;
+ int f0 = e0 / 3, f1 = is_boundary ? -1 : (e1 / 3);
+ int v0 = F(e0 % 3, f0), v0p = F((e0 + 2) % 3, f0), v1 = F((e0 + 1) % 3, f0);
+ if ((V.col(v0) - V.col(v1)).squaredNorm() != edge.length) {
+ continue;
+ }
+ if (abs(diffs[e0][0]) < 2 && abs(diffs[e0][1]) < 2) continue;
+ if (f1 != -1) {
+ face_edgeOrients.push_back(Vector3i());
+ sharp_edges.push_back(0);
+ sharp_edges.push_back(0);
+ sharp_edges.push_back(0);
+ face_edgeIds.push_back(Vector3i());
+ }
+ int v1p = is_boundary ? -1 : F((e1 + 2) % 3, f1);
+ int vn = nV++;
+ nSplit++;
+ if (nV > V.cols()) {
+ V.conservativeResize(V.rows(), V.cols() * 2);
+ N.conservativeResize(N.rows(), N.cols() * 2);
+ Q.conservativeResize(Q.rows(), Q.cols() * 2);
+ O.conservativeResize(O.rows(), O.cols() * 2);
+ if (S)
+ S->conservativeResize(S->rows(), S->cols() * 2);
+ V2E.conservativeResize(V.cols());
+ boundary.conservativeResize(V.cols());
+ nonmanifold.conservativeResize(V.cols());
+ }
+
+ V.col(vn) = (V.col(v0) + V.col(v1)) * 0.5;
+ N.col(vn) = N.col(v0);
+ Q.col(vn) = Q.col(v0);
+ O.col(vn) = (O.col(v0) + O.col(v1)) * 0.5;
+ if (S)
+ S->col(vn) = S->col(v0);
+
+ nonmanifold[vn] = false;
+ boundary[vn] = is_boundary;
+
+ int eid = face_edgeIds[f0][e0 % 3];
+ int sharp_eid = sharp_edges[e0];
+ int eid01 = face_edgeIds[f0][(e0 + 1) % 3];
+ int sharp_eid01 = sharp_edges[f0 * 3 + (e0 + 1) % 3];
+ int eid02 = face_edgeIds[f0][(e0 + 2) % 3];
+ int sharp_eid02 = sharp_edges[f0 * 3 + (e0 + 2) % 3];
+
+ int eid0, eid1, eid0p, eid1p;
+ int sharp_eid0, sharp_eid1, sharp_eid0p, sharp_eid1p;
+
+ eid0 = eid;
+ sharp_eid0 = sharp_eid;
+ edge_values[eid0] = DEdge(v0, vn);
+
+ eid1 = edge_values.size();
+ sharp_eid1 = sharp_eid;
+ edge_values.push_back(DEdge(vn, v1));
+ edge_diff.push_back(Vector2i());
+
+ eid0p = edge_values.size();
+ sharp_eid0p = 0;
+ edge_values.push_back(DEdge(vn, v0p));
+ edge_diff.push_back(Vector2i());
+
+ int f2 = is_boundary ? -1 : (nF++);
+ int f3 = nF++;
+ sharp_edges.push_back(0);
+ sharp_edges.push_back(0);
+ sharp_edges.push_back(0);
+ face_edgeIds.push_back(Vector3i());
+ face_edgeOrients.push_back(Vector3i());
+
+ if (nF > F.cols()) {
+ F.conservativeResize(F.rows(), std::max(nF, (int)F.cols() * 2));
+ face_spaces.resize(F.cols());
+ E2E.conservativeResize(F.cols() * 3);
+ diffs.resize(F.cols() * 3);
+ }
+
+ auto D01 = diffs[e0];
+ auto D1p = diffs[e0 / 3 * 3 + (e0 + 1) % 3];
+ auto Dp0 = diffs[e0 / 3 * 3 + (e0 + 2) % 3];
+
+ Vector2i D0n = D01 / 2;
+
+ auto orients1 = face_spaces[f0];
+ F.col(f0) << vn, v0p, v0;
+ face_edgeIds[f0] = Vector3i(eid0p, eid02, eid0);
+ sharp_edges[f0 * 3] = sharp_eid0p;
+ sharp_edges[f0 * 3 + 1] = sharp_eid02;
+ sharp_edges[f0 * 3 + 2] = sharp_eid0;
+
+ diffs[f0 * 3] = D01 + D1p - D0n;
+ diffs[f0 * 3 + 1] = Dp0;
+ diffs[f0 * 3 + 2] = D0n;
+ int o1 = e0 % 3, o2 = e1 % 3;
+ AnalyzeOrient(f0, Vector3i(0, orients1.d[(o1 + 2) % 3], orients1.d[o1]));
+ if (!is_boundary) {
+ auto orients2 = face_spaces[f1];
+ int eid11 = face_edgeIds[f1][(e1 + 1) % 3];
+ int sharp_eid11 = sharp_edges[f1 * 3 + (e1 + 1) % 3];
+ int eid12 = face_edgeIds[f1][(e1 + 2) % 3];
+ int sharp_eid12 = sharp_edges[f1 * 3 + (e1 + 2) % 3];
+
+ auto Ds10 = diffs[e1];
+ auto Ds0p = diffs[e1 / 3 * 3 + (e1 + 1) % 3];
+
+ auto Dsp1 = diffs[e1 / 3 * 3 + (e1 + 2) % 3];
+ int orient = 0;
+ while (rshift90(D01, orient) != Ds10) orient += 1;
+ Vector2i Dsn0 = rshift90(D0n, orient);
+
+ F.col(f1) << vn, v0, v1p;
+ eid1p = edge_values.size();
+ sharp_eid1p = 0;
+ edge_values.push_back(DEdge(vn, v1p));
+ edge_diff.push_back(Vector2i());
+
+ sharp_edges[f1 * 3] = sharp_eid0;
+ sharp_edges[f1 * 3 + 1] = sharp_eid11;
+ sharp_edges[f1 * 3 + 2] = sharp_eid1p;
+ face_edgeIds[f1] = (Vector3i(eid0, eid11, eid1p));
+ diffs[f1 * 3] = Dsn0;
+ diffs[f1 * 3 + 1] = Ds0p;
+ diffs[f1 * 3 + 2] = Dsp1 + (Ds10 - Dsn0);
+
+ AnalyzeOrient(f1, Vector3i(orients2.d[o2], orients2.d[(o2 + 1) % 3], 0));
+
+ face_spaces[f2] = face_spaces[f1];
+ sharp_edges[f2 * 3] = sharp_eid1p;
+ sharp_edges[f2 * 3 + 1] = sharp_eid12;
+ sharp_edges[f2 * 3 + 2] = sharp_eid1;
+ face_edgeIds[f2] = (Vector3i(eid1p, eid12, eid1));
+ F.col(f2) << vn, v1p, v1;
+ diffs[f2 * 3] = -Dsp1 - (Ds10 - Dsn0);
+ diffs[f2 * 3 + 1] = Dsp1;
+ diffs[f2 * 3 + 2] = Ds10 - Dsn0;
+
+ AnalyzeOrient(f2, Vector3i(0, orients2.d[(o2 + 2) % 3], orients2.d[o2]));
+ }
+ face_spaces[f3] = face_spaces[f0];
+ sharp_edges[f3 * 3] = sharp_eid1;
+ sharp_edges[f3 * 3 + 1] = sharp_eid01;
+ sharp_edges[f3 * 3 + 2] = sharp_eid0p;
+ face_edgeIds[f3] = (Vector3i(eid1, eid01, eid0p));
+ F.col(f3) << vn, v1, v0p;
+ diffs[f3 * 3] = D01 - D0n;
+ diffs[f3 * 3 + 1] = D1p;
+ diffs[f3 * 3 + 2] = D0n - (D01 + D1p);
+
+ AnalyzeOrient(f3, Vector3i(orients1.d[o1], orients1.d[(o1 + 1) % 3], 0));
+
+ FixOrient(f0);
+ if (!is_boundary) {
+ FixOrient(f1);
+ FixOrient(f2);
+ }
+ FixOrient(f3);
+
+ const int e0p = E2E[dedge_prev_3(e0)], e0n = E2E[dedge_next_3(e0)];
+
+#define sE2E(a, b) \
+ E2E[a] = b; \
+ if (b != -1) E2E[b] = a;
+ sE2E(3 * f0 + 0, 3 * f3 + 2);
+ sE2E(3 * f0 + 1, e0p);
+ sE2E(3 * f3 + 1, e0n);
+ if (is_boundary) {
+ sE2E(3 * f0 + 2, -1);
+ sE2E(3 * f3 + 0, -1);
+ } else {
+ const int e1p = E2E[dedge_prev_3(e1)], e1n = E2E[dedge_next_3(e1)];
+ sE2E(3 * f0 + 2, 3 * f1 + 0);
+ sE2E(3 * f1 + 1, e1n);
+ sE2E(3 * f1 + 2, 3 * f2 + 0);
+ sE2E(3 * f2 + 1, e1p);
+ sE2E(3 * f2 + 2, 3 * f3 + 0);
+ }
+#undef sE2E
+
+ V2E[v0] = 3 * f0 + 2;
+ V2E[vn] = 3 * f0 + 0;
+ V2E[v1] = 3 * f3 + 1;
+ V2E[v0p] = 3 * f0 + 1;
+ if (!is_boundary) V2E[v1p] = 3 * f1 + 2;
+
+ auto schedule = [&](int f) {
+ for (int i = 0; i < 3; ++i) {
+ if (abs(diffs[f * 3 + i][0]) > max_len || abs(diffs[f * 3 + i][1]) > max_len) {
+ EdgeLink e;
+ e.id = f * 3 + i;
+ e.length = (V.col(F((i + 1) % 3, f)) - V.col(F(i, f))).squaredNorm();
+ e.diff = diffs[f * 3 + i];
+ queue.push(e);
+ }
+ }
+ };
+
+ schedule(f0);
+ if (!is_boundary) {
+ schedule(f2);
+ schedule(f1);
+ };
+ schedule(f3);
+ }
+ F.conservativeResize(F.rows(), nF);
+ V.conservativeResize(V.rows(), nV);
+ N.conservativeResize(V.rows(), nV);
+ Q.conservativeResize(V.rows(), nV);
+ O.conservativeResize(V.rows(), nV);
+ if (S)
+ S->conservativeResize(S->rows(), nV);
+ V2E.conservativeResize(nV);
+ boundary.conservativeResize(nV);
+ nonmanifold.conservativeResize(nV);
+ E2E.conservativeResize(nF * 3);
+ for (int i = 0; i < F.cols(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ auto diff = edge_diff[face_edgeIds[i][j]];
+ if (abs(diff[0]) > 1 || abs(diff[1]) > 1) {
+ printf("wrong init %d %d!\n", face_edgeIds[i][j], i * 3 + j);
+ exit(0);
+ }
+ }
+ }
+ for (int i = 0; i < edge_diff.size(); ++i) {
+ if (abs(edge_diff[i][0]) > 1 || abs(edge_diff[i][1]) > 1) {
+ printf("wrong...\n");
+ exit(0);
+ }
+ }
+}
+
+} // namespace qflow
diff --git a/extern/quadriflow/src/subdivide.hpp b/extern/quadriflow/src/subdivide.hpp
new file mode 100644
index 00000000000..a93c58ac2a7
--- /dev/null
+++ b/extern/quadriflow/src/subdivide.hpp
@@ -0,0 +1,17 @@
+#include <Eigen/Core>
+#include <Eigen/Dense>
+
+#include "parametrizer.hpp"
+using namespace Eigen;
+
+namespace qflow {
+
+void subdivide(MatrixXi &F, MatrixXd &V, VectorXd& rho, VectorXi &V2E, VectorXi &E2E, VectorXi &boundary,
+ VectorXi &nonmanifold, double maxLength);
+
+void subdivide_edgeDiff(MatrixXi &F, MatrixXd &V, MatrixXd &N, MatrixXd &Q, MatrixXd &O, MatrixXd* S,
+ VectorXi &V2E, VectorXi &E2E, VectorXi &boundary, VectorXi &nonmanifold,
+ std::vector<Vector2i> &edge_diff, std::vector<DEdge> &edge_values,
+ std::vector<Vector3i> &face_edgeOrients, std::vector<Vector3i> &face_edgeIds,
+ std::vector<int>& sharp_edges, std::map<int, int> &singularities, int max_len);
+} // namespace qflow
diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt
index b93f2057b47..4493c68a88d 100644
--- a/intern/CMakeLists.txt
+++ b/intern/CMakeLists.txt
@@ -76,3 +76,8 @@ endif()
if(WITH_OPENVDB)
add_subdirectory(openvdb)
endif()
+
+if(WITH_QUADRIFLOW)
+ add_subdirectory(quadriflow)
+endif()
+
diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt
index 6a3ebd85378..25e8e124885 100644
--- a/intern/cycles/CMakeLists.txt
+++ b/intern/cycles/CMakeLists.txt
@@ -219,6 +219,24 @@ if(WITH_CYCLES_OSL)
)
endif()
+if(WITH_CYCLES_DEVICE_OPTIX)
+ find_package(OptiX)
+
+ if(OPTIX_FOUND)
+ add_definitions(-DWITH_OPTIX)
+ include_directories(
+ SYSTEM
+ ${OPTIX_INCLUDE_DIR}
+ )
+
+ # Need pre-compiled CUDA binaries in the OptiX device
+ set(WITH_CYCLES_CUDA_BINARIES ON)
+ else()
+ message(STATUS "Optix not found, disabling it from Cycles")
+ set(WITH_CYCLES_DEVICE_OPTIX OFF)
+ endif()
+endif()
+
if(WITH_CYCLES_EMBREE)
add_definitions(-DWITH_EMBREE)
add_definitions(-DEMBREE_STATIC_LIB)
diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt
index 7354b1e615e..66d955768a3 100644
--- a/intern/cycles/blender/CMakeLists.txt
+++ b/intern/cycles/blender/CMakeLists.txt
@@ -29,6 +29,7 @@ set(SRC
blender_shader.cpp
blender_sync.cpp
blender_texture.cpp
+ blender_viewport.cpp
CCL_api.h
blender_object_cull.h
@@ -36,6 +37,7 @@ set(SRC
blender_session.h
blender_texture.h
blender_util.h
+ blender_viewport.h
)
set(LIB
@@ -68,7 +70,7 @@ set(ADDON_FILES
add_definitions(${GL_DEFINITIONS})
if(WITH_CYCLES_DEVICE_OPENCL)
- add_definitions(-DWITH_OPENCL)
+ add_definitions(-DWITH_OPENCL)
endif()
if(WITH_CYCLES_NETWORK)
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
index b8bc74f9e35..61ac24f7f07 100644
--- a/intern/cycles/blender/addon/engine.py
+++ b/intern/cycles/blender/addon/engine.py
@@ -139,15 +139,19 @@ def create(engine, data, region=None, v3d=None, rv3d=None, preview_osl=False):
data = data.as_pointer()
prefs = bpy.context.preferences.as_pointer()
+ screen = 0
if region:
+ screen = region.id_data.as_pointer()
region = region.as_pointer()
if v3d:
+ screen = screen or v3d.id_data.as_pointer()
v3d = v3d.as_pointer()
if rv3d:
+ screen = screen or rv3d.id_data.as_pointer()
rv3d = rv3d.as_pointer()
engine.session = _cycles.create(
- engine.as_pointer(), prefs, data, region, v3d, rv3d, preview_osl)
+ engine.as_pointer(), prefs, data, screen, region, v3d, rv3d, preview_osl)
def free(engine):
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 3acdfc391a6..840ab557132 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -137,6 +137,7 @@ enum_world_mis = (
enum_device_type = (
('CPU', "CPU", "CPU", 0),
('CUDA', "CUDA", "CUDA", 1),
+ ('OPTIX', "OptiX", "OptiX", 3),
('OPENCL', "OpenCL", "OpenCL", 2)
)
@@ -151,6 +152,44 @@ enum_texture_limit = (
('8192', "8192", "Limit texture size to 8192 pixels", 7),
)
+enum_view3d_shading_render_pass= (
+ ('', "General", ""),
+
+ ('COMBINED', "Combined", "Show the Combined Render pass", 1),
+ ('EMISSION', "Emission", "Show the Emission render pass", 33),
+ ('BACKGROUND', "Background", "Show the Background render pass", 34),
+ ('AO', "Ambient Occlusion", "Show the Ambient Occlusion render pass", 35),
+
+ ('', "Light", ""),
+
+ ('DIFFUSE_DIRECT', "Diffuse Direct", "Show the Diffuse Direct render pass", 38),
+ ('DIFFUSE_INDIRECT', "Diffuse Indirect", "Show the Diffuse Indirect render pass", 39),
+ ('DIFFUSE_COLOR', "Diffuse Color", "Show the Diffuse Color render pass", 40),
+
+ ('GLOSSY_DIRECT', "Glossy Direct", "Show the Glossy Direct render pass", 41),
+ ('GLOSSY_INDIRECT', "Glossy Indirect", "Show the Glossy Indirect render pass", 42),
+ ('GLOSSY_COLOR', "Glossy Color", "Show the Glossy Color render pass", 43),
+
+ ('', "", ""),
+
+ ('TRANSMISSION_DIRECT', "Transmission Direct", "Show the Transmission Direct render pass", 44),
+ ('TRANSMISSION_INDIRECT', "Transmission Indirect", "Show the Transmission Indirect render pass", 45),
+ ('TRANSMISSION_COLOR', "Transmission Color", "Show the Transmission Color render pass", 46),
+
+ ('SUBSURFACE_DIRECT', "Subsurface Direct", "Show the Subsurface Direct render pass", 47),
+ ('SUBSURFACE_INDIRECT', "Subsurface Indirect", "Show the Subsurface Indirect render pass", 48),
+ ('SUBSURFACE_COLOR', "Subsurface Color", "Show the Subsurface Color render pass", 49),
+
+ ('VOLUME_DIRECT', "Volume Direct", "Show the Volume Direct render pass", 50),
+ ('VOLUME_INDIRECT', "Volume Indirect", "Show the Volume Indirect render pass", 51),
+
+ ('', "Data", ""),
+
+ ('NORMAL', "Normal", "Show the Normal render pass", 3),
+ ('UV', "UV", "Show the UV render pass", 4),
+ ('MIST', "Mist", "Show the Mist render pass", 32),
+)
+
class CyclesRenderSettings(bpy.types.PropertyGroup):
@@ -702,6 +741,8 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
debug_use_cuda_adaptive_compile: BoolProperty(name="Adaptive Compile", default=False)
debug_use_cuda_split_kernel: BoolProperty(name="Split Kernel", default=False)
+ debug_optix_cuda_streams: IntProperty(name="CUDA Streams", default=1, min=1)
+
debug_opencl_kernel_type: EnumProperty(
name="OpenCL Kernel Type",
default='DEFAULT',
@@ -916,7 +957,7 @@ class CyclesLightSettings(bpy.types.PropertyGroup):
class CyclesWorldSettings(bpy.types.PropertyGroup):
sampling_method: EnumProperty(
- name="Sampling method",
+ name="Sampling Method",
description="How to sample the background light",
items=enum_world_mis,
default='AUTOMATIC',
@@ -1290,12 +1331,12 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
subtype="PIXEL",
)
denoising_relative_pca: BoolProperty(
- name="Relative filter",
+ name="Relative Filter",
description="When removing pixels that don't carry information, use a relative threshold instead of an absolute one (can help to reduce artifacts, but might cause detail loss around edges)",
default=False,
)
denoising_store_passes: BoolProperty(
- name="Store denoising passes",
+ name="Store Denoising Passes",
description="Store the denoising feature passes and the noisy image",
default=False,
update=update_render_passes,
@@ -1362,10 +1403,12 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def get_device_types(self, context):
import _cycles
- has_cuda, has_opencl = _cycles.get_device_types()
+ has_cuda, has_optix, has_opencl = _cycles.get_device_types()
list = [('NONE', "None", "Don't use compute device", 0)]
if has_cuda:
list.append(('CUDA', "CUDA", "Use CUDA for GPU acceleration", 1))
+ if has_optix:
+ list.append(('OPTIX', "OptiX", "Use OptiX for GPU acceleration", 3))
if has_opencl:
list.append(('OPENCL', "OpenCL", "Use OpenCL for GPU acceleration", 2))
return list
@@ -1386,7 +1429,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def update_device_entries(self, device_list):
for device in device_list:
- if not device[1] in {'CUDA', 'OPENCL', 'CPU'}:
+ if not device[1] in {'CUDA', 'OPTIX', 'OPENCL', 'CPU'}:
continue
# Try to find existing Device entry
entry = self.find_existing_device_entry(device)
@@ -1401,8 +1444,8 @@ class CyclesPreferences(bpy.types.AddonPreferences):
# Update name in case it changed
entry.name = device[0]
- # Gets all devices types by default.
- def get_devices(self, compute_device_type=''):
+ # Gets all devices types for a compute device type.
+ def get_devices_for_type(self, compute_device_type):
import _cycles
# Layout of the device tuples: (Name, Type, Persistent ID)
device_list = _cycles.available_devices(compute_device_type)
@@ -1411,20 +1454,23 @@ class CyclesPreferences(bpy.types.AddonPreferences):
# hold pointers to a resized array.
self.update_device_entries(device_list)
# Sort entries into lists
- cuda_devices = []
- opencl_devices = []
+ devices = []
cpu_devices = []
for device in device_list:
entry = self.find_existing_device_entry(device)
- if entry.type == 'CUDA':
- cuda_devices.append(entry)
- elif entry.type == 'OPENCL':
- opencl_devices.append(entry)
+ if entry.type == compute_device_type:
+ devices.append(entry)
elif entry.type == 'CPU':
cpu_devices.append(entry)
# Extend all GPU devices with CPU.
- cuda_devices.extend(cpu_devices)
- opencl_devices.extend(cpu_devices)
+ if compute_device_type in ('CUDA', 'OPENCL'):
+ devices.extend(cpu_devices)
+ return devices
+
+ # For backwards compatibility, only has CUDA and OpenCL.
+ def get_devices(self, compute_device_type=''):
+ cuda_devices = self.get_devices_for_type('CUDA')
+ opencl_devices = self.get_devices_for_type('OPENCL')
return cuda_devices, opencl_devices
def get_num_gpu_devices(self):
@@ -1460,21 +1506,38 @@ class CyclesPreferences(bpy.types.AddonPreferences):
for device in devices:
box.prop(device, "use", text=device.name)
+ if device_type == 'OPTIX':
+ col = box.column(align=True)
+ col.label(text="OptiX support is experimental", icon='INFO')
+ col.label(text="Not all Cycles features are supported yet", icon='BLANK1')
+
+
def draw_impl(self, layout, context):
row = layout.row()
row.prop(self, "compute_device_type", expand=True)
- cuda_devices, opencl_devices = self.get_devices(self.compute_device_type)
+ devices = self.get_devices_for_type(self.compute_device_type)
row = layout.row()
if self.compute_device_type == 'CUDA':
- self._draw_devices(row, 'CUDA', cuda_devices)
+ self._draw_devices(row, 'CUDA', devices)
+ elif self.compute_device_type == 'OPTIX':
+ self._draw_devices(row, 'OPTIX', devices)
elif self.compute_device_type == 'OPENCL':
- self._draw_devices(row, 'OPENCL', opencl_devices)
+ self._draw_devices(row, 'OPENCL', devices)
def draw(self, context):
self.draw_impl(self.layout, context)
+class CyclesView3DShadingSettings(bpy.types.PropertyGroup):
+ render_pass: EnumProperty(
+ name="Render Pass",
+ description="Render pass to show in the 3D Viewport",
+ items=enum_view3d_shading_render_pass,
+ default='COMBINED',
+ )
+
+
def register():
bpy.utils.register_class(CyclesRenderSettings)
bpy.utils.register_class(CyclesCameraSettings)
@@ -1488,6 +1551,12 @@ def register():
bpy.utils.register_class(CyclesDeviceSettings)
bpy.utils.register_class(CyclesPreferences)
bpy.utils.register_class(CyclesRenderLayerSettings)
+ bpy.utils.register_class(CyclesView3DShadingSettings)
+
+ bpy.types.View3DShading.cycles = bpy.props.PointerProperty(
+ name="Cycles Settings",
+ type=CyclesView3DShadingSettings,
+ )
def unregister():
@@ -1503,3 +1572,4 @@ def unregister():
bpy.utils.unregister_class(CyclesDeviceSettings)
bpy.utils.unregister_class(CyclesPreferences)
bpy.utils.unregister_class(CyclesRenderLayerSettings)
+ bpy.utils.unregister_class(CyclesView3DShadingSettings)
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index b072d9e583e..b2624b2aa81 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -22,6 +22,8 @@ from bl_ui.utils import PresetPanel
from bpy.types import Panel
+from bl_ui.properties_grease_pencil_common import GreasePencilSimplifyPanel
+
class CYCLES_PT_sampling_presets(PresetPanel, Panel):
bl_label = "Sampling Presets"
@@ -86,10 +88,16 @@ def use_cuda(context):
return (get_device_type(context) == 'CUDA' and cscene.device == 'GPU')
+def use_optix(context):
+ cscene = context.scene.cycles
+
+ return (get_device_type(context) == 'OPTIX' and cscene.device == 'GPU')
+
+
def use_branched_path(context):
cscene = context.scene.cycles
- return (cscene.progressive == 'BRANCHED_PATH')
+ return (cscene.progressive == 'BRANCHED_PATH' and not use_optix(context))
def use_sample_all_lights(context):
@@ -166,7 +174,8 @@ class CYCLES_RENDER_PT_sampling(CyclesButtonsPanel, Panel):
layout.use_property_split = True
layout.use_property_decorate = False
- layout.prop(cscene, "progressive")
+ if not use_optix(context):
+ layout.prop(cscene, "progressive")
if cscene.progressive == 'PATH' or use_branched_path(context) is False:
col = layout.column(align=True)
@@ -1761,6 +1770,10 @@ class CYCLES_RENDER_PT_bake(CyclesButtonsPanel, Panel):
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'CYCLES'}
+ @classmethod
+ def poll(cls, context):
+ return CyclesButtonsPanel.poll(context) and not use_optix(context)
+
def draw(self, context):
layout = self.layout
layout.use_property_split = True
@@ -1945,7 +1958,13 @@ class CYCLES_RENDER_PT_debug(CyclesButtonsPanel, Panel):
col.separator()
col = layout.column()
- col.label(text='OpenCL Flags:')
+ col.label(text="OptiX Flags:")
+ col.prop(cscene, "debug_optix_cuda_streams")
+
+ col.separator()
+
+ col = layout.column()
+ col.label(text="OpenCL Flags:")
col.prop(cscene, "debug_opencl_device_type", text="Device")
col.prop(cscene, "debug_use_opencl_debug", text="Debug")
col.prop(cscene, "debug_opencl_mem_limit")
@@ -2050,6 +2069,70 @@ class CYCLES_RENDER_PT_simplify_culling(CyclesButtonsPanel, Panel):
sub.prop(cscene, "distance_cull_margin", text="Distance")
+class CYCLES_VIEW3D_PT_shading_render_pass(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_label = "Render Pass"
+ bl_parent_id = 'VIEW3D_PT_shading'
+ COMPAT_ENGINES = {'CYCLES'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.engine in cls.COMPAT_ENGINES
+ and context.space_data.shading.type == 'RENDERED')
+
+ def draw(self, context):
+ shading = context.space_data.shading
+
+ layout = self.layout
+ layout.prop(shading.cycles, "render_pass", text="")
+
+
+class CYCLES_VIEW3D_PT_shading_lighting(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_label = "Lighting"
+ bl_parent_id = 'VIEW3D_PT_shading'
+ COMPAT_ENGINES = {'CYCLES'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.engine in cls.COMPAT_ENGINES
+ and context.space_data.shading.type == 'RENDERED')
+
+ def draw(self, context):
+ layout = self.layout
+ col = layout.column()
+ split = col.split(factor=0.9)
+
+ shading = context.space_data.shading
+ col.prop(shading, "use_scene_lights_render")
+ col.prop(shading, "use_scene_world_render")
+
+ if not shading.use_scene_world_render:
+ col = layout.column()
+ split = col.split(factor=0.9)
+
+ col = split.column()
+ sub = col.row()
+ sub.scale_y = 0.6
+ sub.template_icon_view(shading, "studio_light", scale_popup=3)
+
+ col = split.column()
+ col.operator("preferences.studiolight_show", emboss=False, text="", icon='PREFERENCES')
+
+ split = layout.split(factor=0.9)
+ col = split.column()
+ col.prop(shading, "studiolight_rotate_z", text="Rotation")
+ col.prop(shading, "studiolight_intensity")
+ col.prop(shading, "studiolight_background_alpha")
+
+class CYCLES_VIEW3D_PT_simplify_greasepencil(CyclesButtonsPanel, Panel, GreasePencilSimplifyPanel):
+ bl_label = "Grease Pencil"
+ bl_parent_id = "CYCLES_RENDER_PT_simplify"
+ COMPAT_ENGINES = {'CYCLES'}
+ bl_options = {'DEFAULT_CLOSED'}
+
def draw_device(self, context):
scene = context.scene
layout = self.layout
@@ -2131,6 +2214,9 @@ classes = (
CYCLES_RENDER_PT_simplify_viewport,
CYCLES_RENDER_PT_simplify_render,
CYCLES_RENDER_PT_simplify_culling,
+ CYCLES_VIEW3D_PT_simplify_greasepencil,
+ CYCLES_VIEW3D_PT_shading_lighting,
+ CYCLES_VIEW3D_PT_shading_render_pass,
CYCLES_RENDER_PT_motion_blur,
CYCLES_RENDER_PT_motion_blur_curve,
CYCLES_RENDER_PT_film,
diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp
index da43f94708c..c84d6e1572b 100644
--- a/intern/cycles/blender/blender_camera.cpp
+++ b/intern/cycles/blender/blender_camera.cpp
@@ -899,6 +899,8 @@ BufferParams BlenderSync::get_buffer_params(BL::RenderSettings &b_render,
params.height = height;
}
+ update_viewport_display_passes(b_v3d, params.passes);
+
return params;
}
diff --git a/intern/cycles/blender/blender_device.cpp b/intern/cycles/blender/blender_device.cpp
index 98fc0c6dec4..111fc8d5192 100644
--- a/intern/cycles/blender/blender_device.cpp
+++ b/intern/cycles/blender/blender_device.cpp
@@ -61,7 +61,8 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scen
COMPUTE_DEVICE_CPU = 0,
COMPUTE_DEVICE_CUDA = 1,
COMPUTE_DEVICE_OPENCL = 2,
- COMPUTE_DEVICE_NUM = 3,
+ COMPUTE_DEVICE_OPTIX = 3,
+ COMPUTE_DEVICE_NUM = 4,
};
ComputeDevice compute_device = (ComputeDevice)get_enum(
@@ -73,6 +74,10 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scen
if (compute_device == COMPUTE_DEVICE_CUDA) {
mask |= DEVICE_MASK_CUDA;
}
+ else if (compute_device == COMPUTE_DEVICE_OPTIX) {
+ /* Cannot use CPU and OptiX device at the same time right now, so replace mask. */
+ mask = DEVICE_MASK_OPTIX;
+ }
else if (compute_device == COMPUTE_DEVICE_OPENCL) {
mask |= DEVICE_MASK_OPENCL;
}
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index 551866f7fce..30417e85441 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -335,7 +335,7 @@ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh,
continue;
Attribute *attr = mesh->subd_attributes.add(
- ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE);
+ ustring(l->name().c_str()), TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
BL::Mesh::polygons_iterator p;
uchar4 *cdata = attr->data_uchar4();
@@ -343,9 +343,9 @@ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh,
for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
int n = p->loop_total();
for (int i = 0; i < n; i++) {
- float3 color = get_float3(l->data[p->loop_start() + i].color());
+ float4 color = get_float4(l->data[p->loop_start() + i].color());
/* Compress/encode vertex color using the sRGB curve. */
- *(cdata++) = color_float_to_byte(color_srgb_to_linear_v3(color));
+ *(cdata++) = color_float4_to_uchar4(color_srgb_to_linear_v4(color));
}
}
}
@@ -357,21 +357,21 @@ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh,
continue;
Attribute *attr = mesh->attributes.add(
- ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE);
+ ustring(l->name().c_str()), TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
BL::Mesh::loop_triangles_iterator t;
uchar4 *cdata = attr->data_uchar4();
for (b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) {
int3 li = get_int3(t->loops());
- float3 c1 = get_float3(l->data[li[0]].color());
- float3 c2 = get_float3(l->data[li[1]].color());
- float3 c3 = get_float3(l->data[li[2]].color());
+ float4 c1 = get_float4(l->data[li[0]].color());
+ float4 c2 = get_float4(l->data[li[1]].color());
+ float4 c3 = get_float4(l->data[li[2]].color());
/* Compress/encode vertex color using the sRGB curve. */
- cdata[0] = color_float_to_byte(color_srgb_to_linear_v3(c1));
- cdata[1] = color_float_to_byte(color_srgb_to_linear_v3(c2));
- cdata[2] = color_float_to_byte(color_srgb_to_linear_v3(c3));
+ cdata[0] = color_float4_to_uchar4(color_srgb_to_linear_v4(c1));
+ cdata[1] = color_float4_to_uchar4(color_srgb_to_linear_v4(c2));
+ cdata[2] = color_float4_to_uchar4(color_srgb_to_linear_v4(c3));
cdata += 3;
}
}
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index b670922ac88..59509d20fb2 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -239,7 +239,7 @@ void BlenderSync::sync_light(BL::Object &b_parent,
light->tag_update(scene);
}
-void BlenderSync::sync_background_light(bool use_portal)
+void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal)
{
BL::World b_world = b_scene.world();
@@ -283,6 +283,7 @@ void BlenderSync::sync_background_light(bool use_portal)
world_map = b_world.ptr.data;
world_recalc = false;
+ viewport_parameters = BlenderViewportParameters(b_v3d);
}
/* Object */
@@ -293,6 +294,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
float motion_time,
bool show_self,
bool show_particles,
+ bool show_lights,
BlenderObjectCulling &culling,
bool *use_portal)
{
@@ -311,6 +313,10 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
/* light is handled separately */
if (!motion && object_is_light(b_ob)) {
+ if (!show_lights) {
+ return NULL;
+ }
+
/* TODO: don't use lights for excluded layers used as mask layer,
* when dynamic overrides are back. */
#if 0
@@ -507,7 +513,9 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
/* Object Loop */
-void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, float motion_time)
+void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
+ BL::SpaceView3D &b_v3d,
+ float motion_time)
{
/* layer data */
bool motion = motion_time != 0.0f;
@@ -530,8 +538,10 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, float motion_time)
/* object loop */
bool cancel = false;
bool use_portal = false;
+ const bool show_lights = BlenderViewportParameters(b_v3d).use_scene_lights;
BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
+ const bool has_local_view = b_v3d && b_v3d.local_view();
BL::Depsgraph::object_instances_iterator b_instance_iter;
for (b_depsgraph.object_instances.begin(b_instance_iter);
@@ -545,9 +555,10 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, float motion_time)
/* test if object needs to be hidden */
const bool show_self = b_instance.show_self();
+ const bool show_local_view = !has_local_view || b_ob.local_view_get(b_v3d);
const bool show_particles = b_instance.show_particles();
- if (show_self || show_particles) {
+ if (show_local_view && (show_self || show_particles)) {
/* object itself */
sync_object(b_depsgraph,
b_view_layer,
@@ -555,6 +566,7 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, float motion_time)
motion_time,
show_self,
show_particles,
+ show_lights,
culling,
&use_portal);
}
@@ -565,7 +577,7 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, float motion_time)
progress.set_sync_status("");
if (!cancel && !motion) {
- sync_background_light(use_portal);
+ sync_background_light(b_v3d, use_portal);
/* handle removed data and modified pointers */
if (light_map.post_sync())
@@ -584,6 +596,7 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, float motion_time)
void BlenderSync::sync_motion(BL::RenderSettings &b_render,
BL::Depsgraph &b_depsgraph,
+ BL::SpaceView3D &b_v3d,
BL::Object &b_override,
int width,
int height,
@@ -621,7 +634,7 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render,
b_engine.frame_set(frame, subframe);
python_thread_state_save(python_thread_state);
sync_camera_motion(b_render, b_cam, width, height, 0.0f);
- sync_objects(b_depsgraph, 0.0f);
+ sync_objects(b_depsgraph, b_v3d, 0.0f);
}
/* always sample these times for camera motion */
@@ -657,7 +670,7 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render,
}
/* sync object */
- sync_objects(b_depsgraph, relative_time);
+ sync_objects(b_depsgraph, b_v3d, relative_time);
}
/* we need to set the python thread state again because this
diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp
index 80c6fee9723..335d4daf09c 100644
--- a/intern/cycles/blender/blender_python.cpp
+++ b/intern/cycles/blender/blender_python.cpp
@@ -81,6 +81,8 @@ bool debug_flags_sync_from_scene(BL::Scene b_scene)
/* Synchronize CUDA flags. */
flags.cuda.adaptive_compile = get_boolean(cscene, "debug_use_cuda_adaptive_compile");
flags.cuda.split_kernel = get_boolean(cscene, "debug_use_cuda_split_kernel");
+ /* Synchronize OptiX flags. */
+ flags.optix.cuda_streams = get_int(cscene, "debug_optix_cuda_streams");
/* Synchronize OpenCL device type. */
switch (get_enum(cscene, "debug_opencl_device_type")) {
case 0:
@@ -177,6 +179,8 @@ static PyObject *init_func(PyObject * /*self*/, PyObject *args)
BlenderSession::headless = headless;
+ DebugFlags().running_inside_blender = true;
+
VLOG(2) << "Debug flags initialized to:\n" << DebugFlags();
Py_RETURN_NONE;
@@ -192,14 +196,15 @@ static PyObject *exit_func(PyObject * /*self*/, PyObject * /*args*/)
static PyObject *create_func(PyObject * /*self*/, PyObject *args)
{
- PyObject *pyengine, *pypreferences, *pydata, *pyregion, *pyv3d, *pyrv3d;
+ PyObject *pyengine, *pypreferences, *pydata, *pyscreen, *pyregion, *pyv3d, *pyrv3d;
int preview_osl;
if (!PyArg_ParseTuple(args,
- "OOOOOOi",
+ "OOOOOOOi",
&pyengine,
&pypreferences,
&pydata,
+ &pyscreen,
&pyregion,
&pyv3d,
&pyrv3d,
@@ -208,6 +213,8 @@ static PyObject *create_func(PyObject * /*self*/, PyObject *args)
}
/* RNA */
+ ID *bScreen = (ID *)PyLong_AsVoidPtr(pyscreen);
+
PointerRNA engineptr;
RNA_pointer_create(NULL, &RNA_RenderEngine, (void *)PyLong_AsVoidPtr(pyengine), &engineptr);
BL::RenderEngine engine(engineptr);
@@ -222,15 +229,15 @@ static PyObject *create_func(PyObject * /*self*/, PyObject *args)
BL::BlendData data(dataptr);
PointerRNA regionptr;
- RNA_pointer_create(NULL, &RNA_Region, pylong_as_voidptr_typesafe(pyregion), &regionptr);
+ RNA_pointer_create(bScreen, &RNA_Region, pylong_as_voidptr_typesafe(pyregion), &regionptr);
BL::Region region(regionptr);
PointerRNA v3dptr;
- RNA_pointer_create(NULL, &RNA_SpaceView3D, pylong_as_voidptr_typesafe(pyv3d), &v3dptr);
+ RNA_pointer_create(bScreen, &RNA_SpaceView3D, pylong_as_voidptr_typesafe(pyv3d), &v3dptr);
BL::SpaceView3D v3d(v3dptr);
PointerRNA rv3dptr;
- RNA_pointer_create(NULL, &RNA_RegionView3D, pylong_as_voidptr_typesafe(pyrv3d), &rv3dptr);
+ RNA_pointer_create(bScreen, &RNA_RegionView3D, pylong_as_voidptr_typesafe(pyrv3d), &rv3dptr);
BL::RegionView3D rv3d(rv3dptr);
/* create session */
@@ -955,14 +962,16 @@ static PyObject *enable_print_stats_func(PyObject * /*self*/, PyObject * /*args*
static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/)
{
vector<DeviceType> device_types = Device::available_types();
- bool has_cuda = false, has_opencl = false;
+ bool has_cuda = false, has_optix = false, has_opencl = false;
foreach (DeviceType device_type, device_types) {
has_cuda |= (device_type == DEVICE_CUDA);
+ has_optix |= (device_type == DEVICE_OPTIX);
has_opencl |= (device_type == DEVICE_OPENCL);
}
- PyObject *list = PyTuple_New(2);
+ PyObject *list = PyTuple_New(3);
PyTuple_SET_ITEM(list, 0, PyBool_FromLong(has_cuda));
- PyTuple_SET_ITEM(list, 1, PyBool_FromLong(has_opencl));
+ PyTuple_SET_ITEM(list, 1, PyBool_FromLong(has_optix));
+ PyTuple_SET_ITEM(list, 2, PyBool_FromLong(has_opencl));
return list;
}
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index 9a798a4f979..1f0816a6edb 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -114,11 +114,6 @@ BlenderSession::~BlenderSession()
free_session();
}
-void BlenderSession::create()
-{
- create_session();
-}
-
void BlenderSession::create_session()
{
SessionParams session_params = BlenderSync::get_session_params(
@@ -199,8 +194,12 @@ void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsg
height = render_resolution_y(b_render);
}
- if (session == NULL) {
- create();
+ bool is_new_session = (session == NULL);
+ if (is_new_session) {
+ /* Initialize session and remember it was just created so not to
+ * re-create it below.
+ */
+ create_session();
}
if (b_v3d) {
@@ -219,8 +218,10 @@ void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsg
/* if scene or session parameters changed, it's easier to simply re-create
* them rather than trying to distinguish which settings need to be updated
*/
- free_session();
- create_session();
+ if (!is_new_session) {
+ free_session();
+ create_session();
+ }
return;
}
@@ -860,7 +861,7 @@ void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_)
/* copy recalc flags, outside of mutex so we can decide to do the real
* synchronization at a later time to not block on running updates */
- sync->sync_recalc(b_depsgraph_);
+ sync->sync_recalc(b_depsgraph_, b_v3d);
/* don't do synchronization if on pause */
if (session_pause) {
diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h
index d57ebe76b82..7445fb53458 100644
--- a/intern/cycles/blender/blender_session.h
+++ b/intern/cycles/blender/blender_session.h
@@ -49,8 +49,6 @@ class BlenderSession {
~BlenderSession();
- void create();
-
/* session */
void create_session();
void free_session();
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index 720f521c589..362155f22ac 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -208,24 +208,6 @@ static void get_tex_mapping(TextureMapping *mapping, BL::TexMapping &b_mapping)
mapping->z_mapping = (TextureMapping::Mapping)b_mapping.mapping_z();
}
-static void get_tex_mapping(TextureMapping *mapping, BL::ShaderNodeMapping &b_mapping)
-{
- if (!b_mapping)
- return;
-
- mapping->translation = get_float3(b_mapping.translation());
- mapping->rotation = get_float3(b_mapping.rotation());
- mapping->scale = get_float3(b_mapping.scale());
- mapping->type = (TextureMapping::Type)b_mapping.vector_type();
-
- mapping->use_minmax = b_mapping.use_min() || b_mapping.use_max();
-
- if (b_mapping.use_min())
- mapping->min = get_float3(b_mapping.min());
- if (b_mapping.use_max())
- mapping->max = get_float3(b_mapping.max());
-}
-
static ShaderNode *add_node(Scene *scene,
BL::RenderEngine &b_engine,
BL::BlendData &b_data,
@@ -357,9 +339,7 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeMapping)) {
BL::ShaderNodeMapping b_mapping_node(b_node);
MappingNode *mapping = new MappingNode();
-
- get_tex_mapping(&mapping->tex_mapping, b_mapping_node);
-
+ mapping->type = (NodeMappingType)b_mapping_node.vector_type();
node = mapping;
}
else if (b_node.is_a(&RNA_ShaderNodeFresnel)) {
@@ -610,6 +590,12 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeVolumeInfo)) {
node = new VolumeInfoNode();
}
+ else if (b_node.is_a(&RNA_ShaderNodeVertexColor)) {
+ BL::ShaderNodeVertexColor b_vertex_color_node(b_node);
+ VertexColorNode *vertex_color_node = new VertexColorNode();
+ vertex_color_node->layer_name = b_vertex_color_node.layer_name();
+ node = vertex_color_node;
+ }
else if (b_node.is_a(&RNA_ShaderNodeBump)) {
BL::ShaderNodeBump b_bump_node(b_node);
BumpNode *bump = new BumpNode();
@@ -753,9 +739,9 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeTexVoronoi)) {
BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
VoronoiTextureNode *voronoi = new VoronoiTextureNode();
- voronoi->coloring = (NodeVoronoiColoring)b_voronoi_node.coloring();
- voronoi->metric = (NodeVoronoiDistanceMetric)b_voronoi_node.distance();
+ voronoi->dimensions = b_voronoi_node.voronoi_dimensions();
voronoi->feature = (NodeVoronoiFeature)b_voronoi_node.feature();
+ voronoi->metric = (NodeVoronoiDistanceMetric)b_voronoi_node.distance();
BL::TexMapping b_texture_mapping(b_voronoi_node.texture_mapping());
get_tex_mapping(&voronoi->tex_mapping, b_texture_mapping);
node = voronoi;
@@ -798,17 +784,19 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeTexNoise)) {
BL::ShaderNodeTexNoise b_noise_node(b_node);
NoiseTextureNode *noise = new NoiseTextureNode();
+ noise->dimensions = b_noise_node.noise_dimensions();
BL::TexMapping b_texture_mapping(b_noise_node.texture_mapping());
get_tex_mapping(&noise->tex_mapping, b_texture_mapping);
node = noise;
}
else if (b_node.is_a(&RNA_ShaderNodeTexMusgrave)) {
BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
- MusgraveTextureNode *musgrave = new MusgraveTextureNode();
- musgrave->type = (NodeMusgraveType)b_musgrave_node.musgrave_type();
+ MusgraveTextureNode *musgrave_node = new MusgraveTextureNode();
+ musgrave_node->type = (NodeMusgraveType)b_musgrave_node.musgrave_type();
+ musgrave_node->dimensions = b_musgrave_node.musgrave_dimensions();
BL::TexMapping b_texture_mapping(b_musgrave_node.texture_mapping());
- get_tex_mapping(&musgrave->tex_mapping, b_texture_mapping);
- node = musgrave;
+ get_tex_mapping(&musgrave_node->tex_mapping, b_texture_mapping);
+ node = musgrave_node;
}
else if (b_node.is_a(&RNA_ShaderNodeTexCoord)) {
BL::ShaderNodeTexCoord b_tex_coord_node(b_node);
@@ -850,7 +838,7 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeTexWhiteNoise)) {
BL::ShaderNodeTexWhiteNoise b_tex_white_noise_node(b_node);
WhiteNoiseTextureNode *white_noise_node = new WhiteNoiseTextureNode();
- white_noise_node->dimensions = b_tex_white_noise_node.dimensions();
+ white_noise_node->dimensions = b_tex_white_noise_node.noise_dimensions();
node = white_noise_node;
}
else if (b_node.is_a(&RNA_ShaderNodeNormalMap)) {
@@ -1183,8 +1171,10 @@ static void add_nodes(Scene *scene,
BL::NodeTree::links_iterator b_link;
for (b_ntree.links.begin(b_link); b_link != b_ntree.links.end(); ++b_link) {
- /* Ignore invalid links to avoid unwanted cycles created in graph. */
- if (!b_link->is_valid()) {
+ /* Ignore invalid links to avoid unwanted cycles created in graph.
+ * Also ignore links with unavailable sockets. */
+ if (!(b_link->is_valid() && b_link->from_socket().enabled() &&
+ b_link->to_socket().enabled())) {
continue;
}
/* get blender link data */
@@ -1314,19 +1304,23 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
/* Sync World */
-void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, bool update_all)
+void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all)
{
Background *background = scene->background;
Background prevbackground = *background;
BL::World b_world = b_scene.world();
- if (world_recalc || update_all || b_world.ptr.data != world_map) {
+ BlenderViewportParameters new_viewport_parameters(b_v3d);
+
+ if (world_recalc || update_all || b_world.ptr.data != world_map ||
+ viewport_parameters.modified(new_viewport_parameters)) {
Shader *shader = scene->default_background;
ShaderGraph *graph = new ShaderGraph();
/* create nodes */
- if (b_world && b_world.use_nodes() && b_world.node_tree()) {
+ if (new_viewport_parameters.use_scene_world && b_world && b_world.use_nodes() &&
+ b_world.node_tree()) {
BL::ShaderNodeTree b_ntree(b_world.node_tree());
add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree);
@@ -1337,7 +1331,7 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, bool update_all)
shader->volume_sampling_method = get_volume_sampling(cworld);
shader->volume_interpolation_method = get_volume_interpolation(cworld);
}
- else if (b_world) {
+ else if (new_viewport_parameters.use_scene_world && b_world) {
BackgroundNode *background = new BackgroundNode();
background->color = get_float3(b_world.color());
graph->add(background);
@@ -1345,6 +1339,53 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, bool update_all)
ShaderNode *out = graph->output();
graph->connect(background->output("Background"), out->input("Surface"));
}
+ else if (!new_viewport_parameters.use_scene_world) {
+ BackgroundNode *background = new BackgroundNode();
+ graph->add(background);
+
+ LightPathNode *light_path = new LightPathNode();
+ graph->add(light_path);
+
+ MixNode *mix_scene_with_background = new MixNode();
+ mix_scene_with_background->color2 = get_float3(b_world.color());
+ graph->add(mix_scene_with_background);
+
+ EnvironmentTextureNode *texture_environment = new EnvironmentTextureNode();
+ texture_environment->tex_mapping.type = TextureMapping::VECTOR;
+ texture_environment->tex_mapping.rotation[2] = new_viewport_parameters.studiolight_rotate_z;
+ texture_environment->filename = new_viewport_parameters.studiolight_path;
+ graph->add(texture_environment);
+
+ MixNode *mix_intensity = new MixNode();
+ mix_intensity->type = NODE_MIX_MUL;
+ mix_intensity->fac = 1.0f;
+ mix_intensity->color2 = make_float3(new_viewport_parameters.studiolight_intensity,
+ new_viewport_parameters.studiolight_intensity,
+ new_viewport_parameters.studiolight_intensity);
+ graph->add(mix_intensity);
+
+ TextureCoordinateNode *texture_coordinate = new TextureCoordinateNode();
+ graph->add(texture_coordinate);
+
+ MixNode *mix_background_with_environment = new MixNode();
+ mix_background_with_environment->fac = new_viewport_parameters.studiolight_background_alpha;
+ mix_background_with_environment->color1 = get_float3(b_world.color());
+ graph->add(mix_background_with_environment);
+
+ ShaderNode *out = graph->output();
+
+ graph->connect(texture_coordinate->output("Generated"),
+ texture_environment->input("Vector"));
+ graph->connect(texture_environment->output("Color"), mix_intensity->input("Color1"));
+ graph->connect(light_path->output("Is Camera Ray"), mix_scene_with_background->input("Fac"));
+ graph->connect(mix_intensity->output("Color"), mix_scene_with_background->input("Color1"));
+ graph->connect(mix_intensity->output("Color"),
+ mix_background_with_environment->input("Color2"));
+ graph->connect(mix_background_with_environment->output("Color"),
+ mix_scene_with_background->input("Color2"));
+ graph->connect(mix_scene_with_background->output("Color"), background->input("Color"));
+ graph->connect(background->output("Background"), out->input("Surface"));
+ }
if (b_world) {
/* AO */
@@ -1389,7 +1430,8 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, bool update_all)
background->transparent_roughness_threshold = 0.0f;
}
- background->use_shader = view_layer.use_background_shader;
+ background->use_shader = view_layer.use_background_shader |
+ viewport_parameters.custom_viewport_parameters();
background->use_ao = background->use_ao && view_layer.use_background_ao;
if (background->modified(prevbackground))
@@ -1439,7 +1481,7 @@ void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all)
}
}
-void BlenderSync::sync_shaders(BL::Depsgraph &b_depsgraph)
+void BlenderSync::sync_shaders(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d)
{
/* for auto refresh images */
bool auto_refresh_update = false;
@@ -1452,7 +1494,7 @@ void BlenderSync::sync_shaders(BL::Depsgraph &b_depsgraph)
shader_map.pre_sync();
- sync_world(b_depsgraph, auto_refresh_update);
+ sync_world(b_depsgraph, b_v3d, auto_refresh_update);
sync_lights(b_depsgraph, auto_refresh_update);
sync_materials(b_depsgraph, auto_refresh_update);
}
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index aec21887088..f04455ff75e 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -80,7 +80,7 @@ BlenderSync::~BlenderSync()
/* Sync */
-void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph)
+void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d)
{
/* Sync recalc flags from blender to cycles. Actual update is done separate,
* so we can do it later on if doing it immediate is not suitable. */
@@ -175,6 +175,11 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph)
}
}
+ BlenderViewportParameters new_viewport_parameters(b_v3d);
+ if (viewport_parameters.modified(new_viewport_parameters)) {
+ world_recalc = true;
+ }
+
/* Updates shader with object dependency if objects changed. */
if (has_updated_objects) {
if (scene->default_background->has_object_dependency) {
@@ -201,8 +206,8 @@ void BlenderSync::sync_data(BL::RenderSettings &b_render,
sync_view_layer(b_v3d, b_view_layer);
sync_integrator();
- sync_film();
- sync_shaders(b_depsgraph);
+ sync_film(b_v3d);
+ sync_shaders(b_depsgraph, b_v3d);
sync_images();
sync_curve_settings();
@@ -210,9 +215,9 @@ void BlenderSync::sync_data(BL::RenderSettings &b_render,
if (scene->need_motion() == Scene::MOTION_PASS || scene->need_motion() == Scene::MOTION_NONE ||
scene->camera->motion_position == Camera::MOTION_POSITION_CENTER) {
- sync_objects(b_depsgraph);
+ sync_objects(b_depsgraph, b_v3d);
}
- sync_motion(b_render, b_depsgraph, b_override, width, height, python_thread_state);
+ sync_motion(b_render, b_depsgraph, b_v3d, b_override, width, height, python_thread_state);
mesh_synced.clear();
@@ -331,13 +336,17 @@ void BlenderSync::sync_integrator()
/* Film */
-void BlenderSync::sync_film()
+void BlenderSync::sync_film(BL::SpaceView3D &b_v3d)
{
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
Film *film = scene->film;
Film prevfilm = *film;
+ if (b_v3d) {
+ film->display_pass = update_viewport_display_passes(b_v3d, film->passes);
+ }
+
film->exposure = get_float(cscene, "film_exposure");
film->filter_type = (FilterType)get_enum(
cscene, "pixel_filter_type", FILTER_NUM_TYPES, FILTER_BLACKMAN_HARRIS);
@@ -363,8 +372,10 @@ void BlenderSync::sync_film()
}
}
- if (film->modified(prevfilm))
+ if (film->modified(prevfilm)) {
film->tag_update(scene);
+ film->tag_passes_update(scene, prevfilm.passes, false);
+ }
}
/* Render Layer */
@@ -509,7 +520,6 @@ int BlenderSync::get_denoising_pass(BL::RenderPass &b_pass)
vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_view_layer)
{
vector<Pass> passes;
- Pass::add(PASS_COMBINED, passes);
/* loop over passes */
BL::RenderLayer::passes_iterator b_pass_iter;
@@ -747,7 +757,7 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine,
preview_samples = preview_samples * preview_samples;
}
- if (get_enum(cscene, "progressive") == 0) {
+ if (get_enum(cscene, "progressive") == 0 && (params.device.type != DEVICE_OPTIX)) {
if (background) {
params.samples = aa_samples;
}
diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h
index 00afceebde3..a80f484fb92 100644
--- a/intern/cycles/blender/blender_sync.h
+++ b/intern/cycles/blender/blender_sync.h
@@ -23,6 +23,7 @@
#include "RNA_blender_cpp.h"
#include "blender/blender_util.h"
+#include "blender/blender_viewport.h"
#include "render/scene.h"
#include "render/session.h"
@@ -36,6 +37,7 @@ CCL_NAMESPACE_BEGIN
class Background;
class BlenderObjectCulling;
+class BlenderViewportParameters;
class Camera;
class Film;
class Light;
@@ -59,7 +61,7 @@ class BlenderSync {
~BlenderSync();
/* sync */
- void sync_recalc(BL::Depsgraph &b_depsgraph);
+ void sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d);
void sync_data(BL::RenderSettings &b_render,
BL::Depsgraph &b_depsgraph,
BL::SpaceView3D &b_v3d,
@@ -106,17 +108,18 @@ class BlenderSync {
/* sync */
void sync_lights(BL::Depsgraph &b_depsgraph, bool update_all);
void sync_materials(BL::Depsgraph &b_depsgraph, bool update_all);
- void sync_objects(BL::Depsgraph &b_depsgraph, float motion_time = 0.0f);
+ void sync_objects(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, float motion_time = 0.0f);
void sync_motion(BL::RenderSettings &b_render,
BL::Depsgraph &b_depsgraph,
+ BL::SpaceView3D &b_v3d,
BL::Object &b_override,
int width,
int height,
void **python_thread_state);
- void sync_film();
+ void sync_film(BL::SpaceView3D &b_v3d);
void sync_view();
- void sync_world(BL::Depsgraph &b_depsgraph, bool update_all);
- void sync_shaders(BL::Depsgraph &b_depsgraph);
+ void sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all);
+ void sync_shaders(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d);
void sync_curve_settings();
void sync_nodes(Shader *shader, BL::ShaderNodeTree &b_ntree);
@@ -134,6 +137,7 @@ class BlenderSync {
float motion_time,
bool show_self,
bool show_particles,
+ bool show_lights,
BlenderObjectCulling &culling,
bool *use_portal);
void sync_light(BL::Object &b_parent,
@@ -143,7 +147,7 @@ class BlenderSync {
int random_id,
Transform &tfm,
bool *use_portal);
- void sync_background_light(bool use_portal);
+ void sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal);
void sync_mesh_motion(BL::Depsgraph &b_depsgraph,
BL::Object &b_ob,
Object *object,
@@ -183,6 +187,7 @@ class BlenderSync {
set<float> motion_times;
void *world_map;
bool world_recalc;
+ BlenderViewportParameters viewport_parameters;
Scene *scene;
bool preview;
diff --git a/intern/cycles/blender/blender_viewport.cpp b/intern/cycles/blender/blender_viewport.cpp
new file mode 100644
index 00000000000..73ef5f94720
--- /dev/null
+++ b/intern/cycles/blender/blender_viewport.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2019 Blender Foundation
+ *
+ * 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.
+ */
+#include "blender_viewport.h"
+
+#include "blender_util.h"
+
+CCL_NAMESPACE_BEGIN
+
+BlenderViewportParameters::BlenderViewportParameters()
+ : use_scene_world(true),
+ use_scene_lights(true),
+ studiolight_rotate_z(0.0f),
+ studiolight_intensity(1.0f),
+ studiolight_background_alpha(1.0f),
+ studiolight_path(ustring())
+{
+}
+
+BlenderViewportParameters::BlenderViewportParameters(BL::SpaceView3D &b_v3d)
+ : BlenderViewportParameters()
+{
+ /* We only copy the parameters if we are in look dev mode. otherwise
+ * defaults are being used. These defaults mimic normal render settings */
+ if (b_v3d && b_v3d.shading().type() == BL::View3DShading::type_RENDERED) {
+ use_scene_world = b_v3d.shading().use_scene_world_render();
+ use_scene_lights = b_v3d.shading().use_scene_lights_render();
+ if (!use_scene_world) {
+ studiolight_rotate_z = b_v3d.shading().studiolight_rotate_z();
+ studiolight_intensity = b_v3d.shading().studiolight_intensity();
+ studiolight_background_alpha = b_v3d.shading().studiolight_background_alpha();
+ studiolight_path = b_v3d.shading().selected_studio_light().path();
+ }
+ }
+}
+
+/* Check if two instances are different. */
+const bool BlenderViewportParameters::modified(const BlenderViewportParameters &other) const
+{
+ return use_scene_world != other.use_scene_world || use_scene_lights != other.use_scene_lights ||
+ studiolight_rotate_z != other.studiolight_rotate_z ||
+ studiolight_intensity != other.studiolight_intensity ||
+ studiolight_background_alpha != other.studiolight_background_alpha ||
+ studiolight_path != other.studiolight_path;
+}
+
+const bool BlenderViewportParameters::custom_viewport_parameters() const
+{
+ return !(use_scene_world && use_scene_lights);
+}
+
+PassType BlenderViewportParameters::get_viewport_display_render_pass(BL::SpaceView3D &b_v3d)
+{
+ PassType display_pass = PASS_NONE;
+ if (b_v3d) {
+ BL::View3DShading b_view3dshading = b_v3d.shading();
+ PointerRNA cshading = RNA_pointer_get(&b_view3dshading.ptr, "cycles");
+ display_pass = (PassType)get_enum(cshading, "render_pass", -1, -1);
+ }
+ return display_pass;
+}
+
+PassType update_viewport_display_passes(BL::SpaceView3D &b_v3d, vector<Pass> &passes)
+{
+ if (b_v3d) {
+ PassType display_pass = BlenderViewportParameters::get_viewport_display_render_pass(b_v3d);
+
+ passes.clear();
+ Pass::add(display_pass, passes);
+
+ return display_pass;
+ }
+ return PASS_NONE;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_viewport.h b/intern/cycles/blender/blender_viewport.h
new file mode 100644
index 00000000000..f26d0d38115
--- /dev/null
+++ b/intern/cycles/blender/blender_viewport.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2019 Blender Foundation
+ *
+ * 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.
+ */
+
+#ifndef __BLENDER_VIEWPORT_H__
+#define __BLENDER_VIEWPORT_H__
+
+#include "MEM_guardedalloc.h"
+#include "RNA_types.h"
+#include "RNA_access.h"
+#include "RNA_blender_cpp.h"
+
+#include "render/film.h"
+#include "util/util_param.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BlenderViewportParameters {
+ private:
+ bool use_scene_world;
+ bool use_scene_lights;
+ float studiolight_rotate_z;
+ float studiolight_intensity;
+ float studiolight_background_alpha;
+ ustring studiolight_path;
+
+ BlenderViewportParameters();
+ BlenderViewportParameters(BL::SpaceView3D &b_v3d);
+
+ const bool modified(const BlenderViewportParameters &other) const;
+ const bool custom_viewport_parameters() const;
+ friend class BlenderSync;
+
+ public:
+ /* Retrieve the render pass that needs to be displayed on the given `SpaceView3D`
+ * When the `b_v3d` parameter is not given `PASS_NONE` will be returned. */
+ static PassType get_viewport_display_render_pass(BL::SpaceView3D &b_v3d);
+};
+
+PassType update_viewport_display_passes(BL::SpaceView3D &b_v3d, vector<Pass> &passes);
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/bvh/CMakeLists.txt b/intern/cycles/bvh/CMakeLists.txt
index 36bbd937e1a..27a7f604e1c 100644
--- a/intern/cycles/bvh/CMakeLists.txt
+++ b/intern/cycles/bvh/CMakeLists.txt
@@ -15,6 +15,7 @@ set(SRC
bvh_build.cpp
bvh_embree.cpp
bvh_node.cpp
+ bvh_optix.cpp
bvh_sort.cpp
bvh_split.cpp
bvh_unaligned.cpp
@@ -29,6 +30,7 @@ set(SRC_HEADERS
bvh_build.h
bvh_embree.h
bvh_node.h
+ bvh_optix.h
bvh_params.h
bvh_sort.h
bvh_split.h
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp
index 53c66777928..16c721da06a 100644
--- a/intern/cycles/bvh/bvh.cpp
+++ b/intern/cycles/bvh/bvh.cpp
@@ -26,6 +26,9 @@
#include "bvh/bvh_build.h"
#include "bvh/bvh_node.h"
+#ifdef WITH_OPTIX
+# include "bvh/bvh_optix.h"
+#endif
#ifdef WITH_EMBREE
# include "bvh/bvh_embree.h"
#endif
@@ -51,6 +54,8 @@ const char *bvh_layout_name(BVHLayout layout)
return "NONE";
case BVH_LAYOUT_EMBREE:
return "EMBREE";
+ case BVH_LAYOUT_OPTIX:
+ return "OPTIX";
case BVH_LAYOUT_ALL:
return "ALL";
}
@@ -71,7 +76,11 @@ BVHLayout BVHParams::best_bvh_layout(BVHLayout requested_layout, BVHLayoutMask s
/* This is a mask of supported BVH layouts which are narrower than the
* requested one.
*/
- const BVHLayoutMask allowed_layouts_mask = (supported_layouts & (requested_layout_mask - 1));
+ BVHLayoutMask allowed_layouts_mask = (supported_layouts & (requested_layout_mask - 1));
+ /* If the requested layout is not supported, choose from the supported layouts instead. */
+ if (allowed_layouts_mask == 0) {
+ allowed_layouts_mask = supported_layouts;
+ }
/* We get widest from allowed ones and convert mask to actual layout. */
const BVHLayoutMask widest_allowed_layout_mask = __bsr(allowed_layouts_mask);
return (BVHLayout)(1 << widest_allowed_layout_mask);
@@ -90,23 +99,33 @@ int BVHStackEntry::encodeIdx() const
/* BVH */
-BVH::BVH(const BVHParams &params_, const vector<Object *> &objects_)
- : params(params_), objects(objects_)
+BVH::BVH(const BVHParams &params_, const vector<Mesh *> &meshes_, const vector<Object *> &objects_)
+ : params(params_), meshes(meshes_), objects(objects_)
{
}
-BVH *BVH::create(const BVHParams &params, const vector<Object *> &objects)
+BVH *BVH::create(const BVHParams &params,
+ const vector<Mesh *> &meshes,
+ const vector<Object *> &objects)
{
switch (params.bvh_layout) {
case BVH_LAYOUT_BVH2:
- return new BVH2(params, objects);
+ return new BVH2(params, meshes, objects);
case BVH_LAYOUT_BVH4:
- return new BVH4(params, objects);
+ return new BVH4(params, meshes, objects);
case BVH_LAYOUT_BVH8:
- return new BVH8(params, objects);
+ return new BVH8(params, meshes, objects);
case BVH_LAYOUT_EMBREE:
#ifdef WITH_EMBREE
- return new BVHEmbree(params, objects);
+ return new BVHEmbree(params, meshes, objects);
+#else
+ break;
+#endif
+ case BVH_LAYOUT_OPTIX:
+#ifdef WITH_OPTIX
+ return new BVHOptiX(params, meshes, objects);
+#else
+ break;
#endif
case BVH_LAYOUT_NONE:
case BVH_LAYOUT_ALL:
@@ -356,26 +375,17 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
size_t pack_leaf_nodes_offset = leaf_nodes_size;
size_t object_offset = 0;
- map<Mesh *, int> mesh_map;
-
- foreach (Object *ob, objects) {
- Mesh *mesh = ob->mesh;
+ foreach (Mesh *mesh, meshes) {
BVH *bvh = mesh->bvh;
- if (mesh->need_build_bvh()) {
- if (mesh_map.find(mesh) == mesh_map.end()) {
- prim_index_size += bvh->pack.prim_index.size();
- prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
- nodes_size += bvh->pack.nodes.size();
- leaf_nodes_size += bvh->pack.leaf_nodes.size();
-
- mesh_map[mesh] = 1;
- }
+ if (mesh->need_build_bvh(params.bvh_layout)) {
+ prim_index_size += bvh->pack.prim_index.size();
+ prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
+ nodes_size += bvh->pack.nodes.size();
+ leaf_nodes_size += bvh->pack.leaf_nodes.size();
}
}
- mesh_map.clear();
-
pack.prim_index.resize(prim_index_size);
pack.prim_type.resize(prim_index_size);
pack.prim_object.resize(prim_index_size);
@@ -400,6 +410,8 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
int4 *pack_leaf_nodes = (pack.leaf_nodes.size()) ? &pack.leaf_nodes[0] : NULL;
float2 *pack_prim_time = (pack.prim_time.size()) ? &pack.prim_time[0] : NULL;
+ map<Mesh *, int> mesh_map;
+
/* merge */
foreach (Object *ob, objects) {
Mesh *mesh = ob->mesh;
@@ -407,7 +419,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
/* We assume that if mesh doesn't need own BVH it was already included
* into a top-level BVH and no packing here is needed.
*/
- if (!mesh->need_build_bvh()) {
+ if (!mesh->need_build_bvh(params.bvh_layout)) {
pack.object_node[object_offset++] = 0;
continue;
}
diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h
index edce3ca6f2a..92082e4de86 100644
--- a/intern/cycles/bvh/bvh.h
+++ b/intern/cycles/bvh/bvh.h
@@ -26,11 +26,14 @@
CCL_NAMESPACE_BEGIN
class Stats;
+class Device;
+class DeviceScene;
class BVHNode;
struct BVHStackEntry;
class BVHParams;
class BoundBox;
class LeafNode;
+class Mesh;
class Object;
class Progress;
@@ -81,18 +84,25 @@ class BVH {
public:
PackedBVH pack;
BVHParams params;
+ vector<Mesh *> meshes;
vector<Object *> objects;
- static BVH *create(const BVHParams &params, const vector<Object *> &objects);
+ static BVH *create(const BVHParams &params,
+ const vector<Mesh *> &meshes,
+ const vector<Object *> &objects);
virtual ~BVH()
{
}
virtual void build(Progress &progress, Stats *stats = NULL);
+ virtual void copy_to_device(Progress & /*progress*/, DeviceScene * /*dscene*/)
+ {
+ }
+
void refit(Progress &progress);
protected:
- BVH(const BVHParams &params, const vector<Object *> &objects);
+ BVH(const BVHParams &params, const vector<Mesh *> &meshes, const vector<Object *> &objects);
/* Refit range of primitives. */
void refit_primitives(int start, int end, BoundBox &bbox, uint &visibility);
diff --git a/intern/cycles/bvh/bvh2.cpp b/intern/cycles/bvh/bvh2.cpp
index f419d413ef6..b1a9148c297 100644
--- a/intern/cycles/bvh/bvh2.cpp
+++ b/intern/cycles/bvh/bvh2.cpp
@@ -25,7 +25,10 @@
CCL_NAMESPACE_BEGIN
-BVH2::BVH2(const BVHParams &params_, const vector<Object *> &objects_) : BVH(params_, objects_)
+BVH2::BVH2(const BVHParams &params_,
+ const vector<Mesh *> &meshes_,
+ const vector<Object *> &objects_)
+ : BVH(params_, meshes_, objects_)
{
}
diff --git a/intern/cycles/bvh/bvh2.h b/intern/cycles/bvh/bvh2.h
index c6a4e6fa73a..a3eaff9cf65 100644
--- a/intern/cycles/bvh/bvh2.h
+++ b/intern/cycles/bvh/bvh2.h
@@ -46,7 +46,7 @@ class BVH2 : public BVH {
protected:
/* constructor */
friend class BVH;
- BVH2(const BVHParams &params, const vector<Object *> &objects);
+ BVH2(const BVHParams &params, const vector<Mesh *> &meshes, const vector<Object *> &objects);
/* Building process. */
virtual BVHNode *widen_children_nodes(const BVHNode *root) override;
diff --git a/intern/cycles/bvh/bvh4.cpp b/intern/cycles/bvh/bvh4.cpp
index b6df9024ffa..89b42ee1d21 100644
--- a/intern/cycles/bvh/bvh4.cpp
+++ b/intern/cycles/bvh/bvh4.cpp
@@ -31,7 +31,10 @@ CCL_NAMESPACE_BEGIN
* life easier all over the place.
*/
-BVH4::BVH4(const BVHParams &params_, const vector<Object *> &objects_) : BVH(params_, objects_)
+BVH4::BVH4(const BVHParams &params_,
+ const vector<Mesh *> &meshes_,
+ const vector<Object *> &objects_)
+ : BVH(params_, meshes_, objects_)
{
params.bvh_layout = BVH_LAYOUT_BVH4;
}
diff --git a/intern/cycles/bvh/bvh4.h b/intern/cycles/bvh/bvh4.h
index 38b0961d3df..c44f2833c84 100644
--- a/intern/cycles/bvh/bvh4.h
+++ b/intern/cycles/bvh/bvh4.h
@@ -46,7 +46,7 @@ class BVH4 : public BVH {
protected:
/* constructor */
friend class BVH;
- BVH4(const BVHParams &params, const vector<Object *> &objects);
+ BVH4(const BVHParams &params, const vector<Mesh *> &meshes, const vector<Object *> &objects);
/* Building process. */
virtual BVHNode *widen_children_nodes(const BVHNode *root) override;
diff --git a/intern/cycles/bvh/bvh8.cpp b/intern/cycles/bvh/bvh8.cpp
index 10fd01dd8d0..d3516525f78 100644
--- a/intern/cycles/bvh/bvh8.cpp
+++ b/intern/cycles/bvh/bvh8.cpp
@@ -36,7 +36,10 @@
CCL_NAMESPACE_BEGIN
-BVH8::BVH8(const BVHParams &params_, const vector<Object *> &objects_) : BVH(params_, objects_)
+BVH8::BVH8(const BVHParams &params_,
+ const vector<Mesh *> &meshes_,
+ const vector<Object *> &objects_)
+ : BVH(params_, meshes_, objects_)
{
}
diff --git a/intern/cycles/bvh/bvh8.h b/intern/cycles/bvh/bvh8.h
index 6292353c7d4..5f26fd423e1 100644
--- a/intern/cycles/bvh/bvh8.h
+++ b/intern/cycles/bvh/bvh8.h
@@ -57,7 +57,7 @@ class BVH8 : public BVH {
protected:
/* constructor */
friend class BVH;
- BVH8(const BVHParams &params, const vector<Object *> &objects);
+ BVH8(const BVHParams &params, const vector<Mesh *> &meshes, const vector<Object *> &objects);
/* Building process. */
virtual BVHNode *widen_children_nodes(const BVHNode *root) override;
diff --git a/intern/cycles/bvh/bvh_embree.cpp b/intern/cycles/bvh/bvh_embree.cpp
index b011bc63dbd..d12a0c137ea 100644
--- a/intern/cycles/bvh/bvh_embree.cpp
+++ b/intern/cycles/bvh/bvh_embree.cpp
@@ -285,8 +285,10 @@ RTCDevice BVHEmbree::rtc_shared_device = NULL;
int BVHEmbree::rtc_shared_users = 0;
thread_mutex BVHEmbree::rtc_shared_mutex;
-BVHEmbree::BVHEmbree(const BVHParams &params_, const vector<Object *> &objects_)
- : BVH(params_, objects_),
+BVHEmbree::BVHEmbree(const BVHParams &params_,
+ const vector<Mesh *> &meshes_,
+ const vector<Object *> &objects_)
+ : BVH(params_, meshes_, objects_),
scene(NULL),
mem_used(0),
top_level(NULL),
@@ -497,6 +499,11 @@ void BVHEmbree::build(Progress &progress, Stats *stats_)
stats = NULL;
}
+void BVHEmbree::copy_to_device(Progress & /*progress*/, DeviceScene *dscene)
+{
+ dscene->data.bvh.scene = scene;
+}
+
BVHNode *BVHEmbree::widen_children_nodes(const BVHNode * /*root*/)
{
assert(!"Must not be called.");
@@ -840,7 +847,7 @@ void BVHEmbree::pack_nodes(const BVHNode *)
Mesh *mesh = ob->mesh;
BVH *bvh = mesh->bvh;
- if (mesh->need_build_bvh()) {
+ if (mesh->need_build_bvh(BVH_LAYOUT_EMBREE)) {
if (mesh_map.find(mesh) == mesh_map.end()) {
prim_index_size += bvh->pack.prim_index.size();
prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
@@ -872,7 +879,7 @@ void BVHEmbree::pack_nodes(const BVHNode *)
/* We assume that if mesh doesn't need own BVH it was already included
* into a top-level BVH and no packing here is needed.
*/
- if (!mesh->need_build_bvh()) {
+ if (!mesh->need_build_bvh(BVH_LAYOUT_EMBREE)) {
pack.object_node[object_offset++] = prim_offset;
continue;
}
diff --git a/intern/cycles/bvh/bvh_embree.h b/intern/cycles/bvh/bvh_embree.h
index 60702713583..123e87dd9b0 100644
--- a/intern/cycles/bvh/bvh_embree.h
+++ b/intern/cycles/bvh/bvh_embree.h
@@ -36,6 +36,7 @@ class Mesh;
class BVHEmbree : public BVH {
public:
virtual void build(Progress &progress, Stats *stats) override;
+ virtual void copy_to_device(Progress &progress, DeviceScene *dscene) override;
virtual ~BVHEmbree();
RTCScene scene;
static void destroy(RTCScene);
@@ -45,7 +46,9 @@ class BVHEmbree : public BVH {
protected:
friend class BVH;
- BVHEmbree(const BVHParams &params, const vector<Object *> &objects);
+ BVHEmbree(const BVHParams &params,
+ const vector<Mesh *> &meshes,
+ const vector<Object *> &objects);
virtual void pack_nodes(const BVHNode *) override;
virtual void refit_nodes() override;
diff --git a/intern/cycles/bvh/bvh_optix.cpp b/intern/cycles/bvh/bvh_optix.cpp
new file mode 100644
index 00000000000..b3a9aab3266
--- /dev/null
+++ b/intern/cycles/bvh/bvh_optix.cpp
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2019, NVIDIA Corporation.
+ * Copyright 2019, Blender Foundation.
+ *
+ * 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.
+ */
+
+#ifdef WITH_OPTIX
+
+# include "bvh/bvh_optix.h"
+# include "render/mesh.h"
+# include "render/object.h"
+# include "util/util_logging.h"
+# include "util/util_progress.h"
+
+CCL_NAMESPACE_BEGIN
+
+BVHOptiX::BVHOptiX(const BVHParams &params_,
+ const vector<Mesh *> &meshes_,
+ const vector<Object *> &objects_)
+ : BVH(params_, meshes_, objects_)
+{
+}
+
+BVHOptiX::~BVHOptiX()
+{
+}
+
+void BVHOptiX::build(Progress &, Stats *)
+{
+ if (params.top_level)
+ pack_tlas();
+ else
+ pack_blas();
+}
+
+void BVHOptiX::copy_to_device(Progress &progress, DeviceScene *dscene)
+{
+ progress.set_status("Updating Scene BVH", "Building OptiX acceleration structure");
+
+ Device *const device = dscene->bvh_nodes.device;
+ if (!device->build_optix_bvh(this, dscene->bvh_nodes))
+ progress.set_error("Failed to build OptiX acceleration structure");
+}
+
+void BVHOptiX::pack_blas()
+{
+ // Bottom-level BVH can contain multiple primitive types, so merge them:
+ assert(meshes.size() == 1 && objects.size() == 1); // These are build per-mesh
+ Mesh *const mesh = meshes[0];
+
+ if (params.primitive_mask & PRIMITIVE_ALL_CURVE && mesh->num_curves() > 0) {
+ const size_t num_curves = mesh->num_curves();
+ const size_t num_segments = mesh->num_segments();
+ pack.prim_type.reserve(pack.prim_type.size() + num_segments);
+ pack.prim_index.reserve(pack.prim_index.size() + num_segments);
+ pack.prim_object.reserve(pack.prim_object.size() + num_segments);
+ // 'pack.prim_time' is only used in geom_curve_intersect.h
+ // It is not needed because of OPTIX_MOTION_FLAG_[START|END]_VANISH
+
+ uint type = PRIMITIVE_CURVE;
+ if (mesh->use_motion_blur && mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION))
+ type = PRIMITIVE_MOTION_CURVE;
+
+ for (size_t j = 0; j < num_curves; ++j) {
+ const Mesh::Curve curve = mesh->get_curve(j);
+ for (size_t k = 0; k < curve.num_segments(); ++k) {
+ pack.prim_type.push_back_reserved(PRIMITIVE_PACK_SEGMENT(type, k));
+ // Each curve segment points back to its curve index
+ pack.prim_index.push_back_reserved(j);
+ pack.prim_object.push_back_reserved(0);
+ }
+ }
+ }
+
+ if (params.primitive_mask & PRIMITIVE_ALL_TRIANGLE && mesh->num_triangles() > 0) {
+ const size_t num_triangles = mesh->num_triangles();
+ pack.prim_type.reserve(pack.prim_type.size() + num_triangles);
+ pack.prim_index.reserve(pack.prim_index.size() + num_triangles);
+ pack.prim_object.reserve(pack.prim_object.size() + num_triangles);
+
+ uint type = PRIMITIVE_TRIANGLE;
+ if (mesh->use_motion_blur && mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION))
+ type = PRIMITIVE_MOTION_TRIANGLE;
+
+ for (size_t k = 0; k < num_triangles; ++k) {
+ pack.prim_type.push_back_reserved(type);
+ pack.prim_index.push_back_reserved(k);
+ pack.prim_object.push_back_reserved(0);
+ }
+ }
+
+ // Initialize visibility to zero and later update it during top-level build
+ uint prev_visibility = objects[0]->visibility;
+ objects[0]->visibility = 0;
+
+ // Update 'pack.prim_tri_index', 'pack.prim_tri_verts' and 'pack.prim_visibility'
+ pack_primitives();
+
+ // Reset visibility after packing
+ objects[0]->visibility = prev_visibility;
+}
+
+void BVHOptiX::pack_tlas()
+{
+ // Calculate total packed size
+ size_t prim_index_size = 0;
+ size_t prim_tri_verts_size = 0;
+ foreach (Mesh *mesh, meshes) {
+ BVH *const bvh = mesh->bvh;
+ prim_index_size += bvh->pack.prim_index.size();
+ prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
+ }
+
+ if (prim_index_size == 0)
+ return; // Abort right away if this is an empty BVH
+
+ size_t pack_offset = 0;
+ size_t pack_verts_offset = 0;
+
+ pack.prim_type.resize(prim_index_size);
+ int *pack_prim_type = pack.prim_type.data();
+ pack.prim_index.resize(prim_index_size);
+ int *pack_prim_index = pack.prim_index.data();
+ pack.prim_object.resize(prim_index_size);
+ int *pack_prim_object = pack.prim_object.data();
+ pack.prim_visibility.resize(prim_index_size);
+ uint *pack_prim_visibility = pack.prim_visibility.data();
+ pack.prim_tri_index.resize(prim_index_size);
+ uint *pack_prim_tri_index = pack.prim_tri_index.data();
+ pack.prim_tri_verts.resize(prim_tri_verts_size);
+ float4 *pack_prim_tri_verts = pack.prim_tri_verts.data();
+
+ // Top-level BVH should only contain instances, see 'Mesh::need_build_bvh'
+ // Iterate over scene mesh list instead of objects, since the 'prim_offset' is calculated based
+ // on that list, which may be ordered differently from the object list.
+ foreach (Mesh *mesh, meshes) {
+ PackedBVH &bvh_pack = mesh->bvh->pack;
+ int mesh_tri_offset = mesh->tri_offset;
+ int mesh_curve_offset = mesh->curve_offset;
+
+ // Merge primitive, object and triangle indexes
+ if (!bvh_pack.prim_index.empty()) {
+ int *bvh_prim_type = &bvh_pack.prim_type[0];
+ int *bvh_prim_index = &bvh_pack.prim_index[0];
+ uint *bvh_prim_tri_index = &bvh_pack.prim_tri_index[0];
+ uint *bvh_prim_visibility = &bvh_pack.prim_visibility[0];
+
+ for (size_t i = 0; i < bvh_pack.prim_index.size(); i++, pack_offset++) {
+ if (bvh_pack.prim_type[i] & PRIMITIVE_ALL_CURVE) {
+ pack_prim_index[pack_offset] = bvh_prim_index[i] + mesh_curve_offset;
+ pack_prim_tri_index[pack_offset] = -1;
+ }
+ else {
+ pack_prim_index[pack_offset] = bvh_prim_index[i] + mesh_tri_offset;
+ pack_prim_tri_index[pack_offset] = bvh_prim_tri_index[i] + pack_verts_offset;
+ }
+
+ pack_prim_type[pack_offset] = bvh_prim_type[i];
+ pack_prim_object[pack_offset] = 0; // Unused for instanced meshes
+ pack_prim_visibility[pack_offset] = bvh_prim_visibility[i];
+ }
+ }
+
+ // Merge triangle vertex data
+ if (!bvh_pack.prim_tri_verts.empty()) {
+ const size_t prim_tri_size = bvh_pack.prim_tri_verts.size();
+ memcpy(pack_prim_tri_verts + pack_verts_offset,
+ bvh_pack.prim_tri_verts.data(),
+ prim_tri_size * sizeof(float4));
+ pack_verts_offset += prim_tri_size;
+ }
+ }
+
+ // Merge visibility flags of all objects and fix object indices for non-instanced meshes
+ foreach (Object *ob, objects) {
+ Mesh *const mesh = ob->mesh;
+ for (size_t i = 0; i < mesh->num_primitives(); ++i) {
+ if (!ob->mesh->is_instanced()) {
+ assert(pack.prim_object[mesh->prim_offset + i] == 0);
+ pack.prim_object[mesh->prim_offset + i] = ob->get_device_index();
+ }
+ pack.prim_visibility[mesh->prim_offset + i] |= ob->visibility_for_tracing();
+ }
+ }
+}
+
+void BVHOptiX::pack_nodes(const BVHNode *)
+{
+}
+
+void BVHOptiX::refit_nodes()
+{
+ // TODO(pmours): Implement?
+ VLOG(1) << "Refit is not yet implemented for OptiX BVH.";
+}
+
+BVHNode *BVHOptiX::widen_children_nodes(const BVHNode *)
+{
+ return NULL;
+}
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_OPTIX */
diff --git a/intern/cycles/bvh/bvh_optix.h b/intern/cycles/bvh/bvh_optix.h
new file mode 100644
index 00000000000..35033fe635f
--- /dev/null
+++ b/intern/cycles/bvh/bvh_optix.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019, NVIDIA Corporation.
+ * Copyright 2019, Blender Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __BVH_OPTIX_H__
+#define __BVH_OPTIX_H__
+
+#ifdef WITH_OPTIX
+
+# include "bvh/bvh.h"
+# include "bvh/bvh_params.h"
+# include "device/device_memory.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BVHOptiX : public BVH {
+ friend class BVH;
+
+ public:
+ BVHOptiX(const BVHParams &params, const vector<Mesh *> &meshes, const vector<Object *> &objects);
+ virtual ~BVHOptiX();
+
+ virtual void build(Progress &progress, Stats *) override;
+ virtual void copy_to_device(Progress &progress, DeviceScene *dscene) override;
+
+ private:
+ void pack_blas();
+ void pack_tlas();
+
+ virtual void pack_nodes(const BVHNode *) override;
+ virtual void refit_nodes() override;
+
+ virtual BVHNode *widen_children_nodes(const BVHNode *) override;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_OPTIX */
+
+#endif /* __BVH_OPTIX_H__ */
diff --git a/intern/cycles/device/CMakeLists.txt b/intern/cycles/device/CMakeLists.txt
index 3e14480e2ad..a8c4949ad07 100644
--- a/intern/cycles/device/CMakeLists.txt
+++ b/intern/cycles/device/CMakeLists.txt
@@ -29,6 +29,7 @@ set(SRC
device_memory.cpp
device_multi.cpp
device_opencl.cpp
+ device_optix.cpp
device_split_kernel.cpp
device_task.cpp
)
@@ -85,6 +86,9 @@ endif()
if(WITH_CYCLES_DEVICE_CUDA)
add_definitions(-DWITH_CUDA)
endif()
+if(WITH_CYCLES_DEVICE_OPTIX)
+ add_definitions(-DWITH_OPTIX)
+endif()
if(WITH_CYCLES_DEVICE_MULTI)
add_definitions(-DWITH_MULTI)
endif()
diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp
index 47d111802cd..76670351734 100644
--- a/intern/cycles/device/device.cpp
+++ b/intern/cycles/device/device.cpp
@@ -38,6 +38,7 @@ bool Device::need_devices_update = true;
thread_mutex Device::device_mutex;
vector<DeviceInfo> Device::opencl_devices;
vector<DeviceInfo> Device::cuda_devices;
+vector<DeviceInfo> Device::optix_devices;
vector<DeviceInfo> Device::cpu_devices;
vector<DeviceInfo> Device::network_devices;
uint Device::devices_initialized_mask = 0;
@@ -379,6 +380,14 @@ Device *Device::create(DeviceInfo &info, Stats &stats, Profiler &profiler, bool
device = NULL;
break;
#endif
+#ifdef WITH_OPTIX
+ case DEVICE_OPTIX:
+ if (device_optix_init())
+ device = device_optix_create(info, stats, profiler, background);
+ else
+ device = NULL;
+ break;
+#endif
#ifdef WITH_MULTI
case DEVICE_MULTI:
device = device_multi_create(info, stats, profiler, background);
@@ -410,6 +419,8 @@ DeviceType Device::type_from_string(const char *name)
return DEVICE_CPU;
else if (strcmp(name, "CUDA") == 0)
return DEVICE_CUDA;
+ else if (strcmp(name, "OPTIX") == 0)
+ return DEVICE_OPTIX;
else if (strcmp(name, "OPENCL") == 0)
return DEVICE_OPENCL;
else if (strcmp(name, "NETWORK") == 0)
@@ -426,6 +437,8 @@ string Device::string_from_type(DeviceType type)
return "CPU";
else if (type == DEVICE_CUDA)
return "CUDA";
+ else if (type == DEVICE_OPTIX)
+ return "OPTIX";
else if (type == DEVICE_OPENCL)
return "OPENCL";
else if (type == DEVICE_NETWORK)
@@ -443,6 +456,9 @@ vector<DeviceType> Device::available_types()
#ifdef WITH_CUDA
types.push_back(DEVICE_CUDA);
#endif
+#ifdef WITH_OPTIX
+ types.push_back(DEVICE_OPTIX);
+#endif
#ifdef WITH_OPENCL
types.push_back(DEVICE_OPENCL);
#endif
@@ -488,6 +504,20 @@ vector<DeviceInfo> Device::available_devices(uint mask)
}
#endif
+#ifdef WITH_OPTIX
+ if (mask & DEVICE_MASK_OPTIX) {
+ if (!(devices_initialized_mask & DEVICE_MASK_OPTIX)) {
+ if (device_optix_init()) {
+ device_optix_info(optix_devices);
+ }
+ devices_initialized_mask |= DEVICE_MASK_OPTIX;
+ }
+ foreach (DeviceInfo &info, optix_devices) {
+ devices.push_back(info);
+ }
+ }
+#endif
+
if (mask & DEVICE_MASK_CPU) {
if (!(devices_initialized_mask & DEVICE_MASK_CPU)) {
device_cpu_info(cpu_devices);
@@ -613,6 +643,7 @@ void Device::free_memory()
{
devices_initialized_mask = 0;
cuda_devices.free_memory();
+ optix_devices.free_memory();
opencl_devices.free_memory();
cpu_devices.free_memory();
network_devices.free_memory();
diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h
index 15a0ceb4a19..672d93c2581 100644
--- a/intern/cycles/device/device.h
+++ b/intern/cycles/device/device.h
@@ -34,6 +34,7 @@
CCL_NAMESPACE_BEGIN
+class BVH;
class Progress;
class RenderTile;
@@ -45,13 +46,15 @@ enum DeviceType {
DEVICE_OPENCL,
DEVICE_CUDA,
DEVICE_NETWORK,
- DEVICE_MULTI
+ DEVICE_MULTI,
+ DEVICE_OPTIX,
};
enum DeviceTypeMask {
DEVICE_MASK_CPU = (1 << DEVICE_CPU),
DEVICE_MASK_OPENCL = (1 << DEVICE_OPENCL),
DEVICE_MASK_CUDA = (1 << DEVICE_CUDA),
+ DEVICE_MASK_OPTIX = (1 << DEVICE_OPTIX),
DEVICE_MASK_NETWORK = (1 << DEVICE_NETWORK),
DEVICE_MASK_ALL = ~0
};
@@ -380,7 +383,11 @@ class Device {
}
/* tasks */
- virtual int get_split_task_count(DeviceTask &task) = 0;
+ virtual int get_split_task_count(DeviceTask &)
+ {
+ return 1;
+ }
+
virtual void task_add(DeviceTask &task) = 0;
virtual void task_wait() = 0;
virtual void task_cancel() = 0;
@@ -399,6 +406,12 @@ class Device {
bool transparent,
const DeviceDrawParams &draw_params);
+ /* acceleration structure building */
+ virtual bool build_optix_bvh(BVH *, device_memory &)
+ {
+ return false;
+ }
+
#ifdef WITH_NETWORK
/* networking */
void server_run();
@@ -456,6 +469,7 @@ class Device {
static bool need_types_update, need_devices_update;
static thread_mutex device_mutex;
static vector<DeviceInfo> cuda_devices;
+ static vector<DeviceInfo> optix_devices;
static vector<DeviceInfo> opencl_devices;
static vector<DeviceInfo> cpu_devices;
static vector<DeviceInfo> network_devices;
diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp
index b2d923dfdf0..c2843a61e6d 100644
--- a/intern/cycles/device/device_cpu.cpp
+++ b/intern/cycles/device/device_cpu.cpp
@@ -114,6 +114,12 @@ template<typename F> class KernelFunctions {
architecture_name = "SSE2";
kernel = kernel_sse2;
}
+#else
+ {
+ /* Dummy to prevent the architecture if below become
+ * conditional when WITH_CYCLES_OPTIMIZED_KERNEL_SSE2
+ * is not defined. */
+ }
#endif
if (strcmp(architecture_name, logged_architecture) != 0) {
diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp
index 4d7d87828c2..00dd37f089c 100644
--- a/intern/cycles/device/device_cuda.cpp
+++ b/intern/cycles/device/device_cuda.cpp
@@ -2263,11 +2263,6 @@ class CUDADevice : public Device {
}
};
- int get_split_task_count(DeviceTask & /*task*/)
- {
- return 1;
- }
-
void task_add(DeviceTask &task)
{
CUDAContextScope scope(this);
diff --git a/intern/cycles/device/device_intern.h b/intern/cycles/device/device_intern.h
index c393a3f9cda..5b8b86886c4 100644
--- a/intern/cycles/device/device_intern.h
+++ b/intern/cycles/device/device_intern.h
@@ -27,6 +27,9 @@ Device *device_opencl_create(DeviceInfo &info, Stats &stats, Profiler &profiler,
bool device_opencl_compile_kernel(const vector<string> &parameters);
bool device_cuda_init();
Device *device_cuda_create(DeviceInfo &info, Stats &stats, Profiler &profiler, bool background);
+bool device_optix_init();
+Device *device_optix_create(DeviceInfo &info, Stats &stats, Profiler &profiler, bool background);
+
Device *device_network_create(DeviceInfo &info,
Stats &stats,
Profiler &profiler,
@@ -36,6 +39,7 @@ Device *device_multi_create(DeviceInfo &info, Stats &stats, Profiler &profiler,
void device_cpu_info(vector<DeviceInfo> &devices);
void device_opencl_info(vector<DeviceInfo> &devices);
void device_cuda_info(vector<DeviceInfo> &devices);
+void device_optix_info(vector<DeviceInfo> &devices);
void device_network_info(vector<DeviceInfo> &devices);
string device_cpu_capabilities();
diff --git a/intern/cycles/device/device_memory.cpp b/intern/cycles/device/device_memory.cpp
index 859535307f4..c8a71bf4b3b 100644
--- a/intern/cycles/device/device_memory.cpp
+++ b/intern/cycles/device/device_memory.cpp
@@ -44,6 +44,29 @@ device_memory::~device_memory()
{
}
+device_memory::device_memory(device_memory &&other)
+ : data_type(other.data_type),
+ data_elements(other.data_elements),
+ data_size(other.data_size),
+ device_size(other.device_size),
+ data_width(other.data_width),
+ data_height(other.data_height),
+ data_depth(other.data_depth),
+ type(other.type),
+ name(other.name),
+ interpolation(other.interpolation),
+ extension(other.extension),
+ device(other.device),
+ device_pointer(other.device_pointer),
+ host_pointer(other.host_pointer),
+ shared_pointer(other.shared_pointer)
+{
+ other.device_size = 0;
+ other.device_pointer = 0;
+ other.host_pointer = 0;
+ other.shared_pointer = 0;
+}
+
void *device_memory::host_alloc(size_t size)
{
if (!size) {
diff --git a/intern/cycles/device/device_memory.h b/intern/cycles/device/device_memory.h
index f50184efba7..5b43ce8b0bc 100644
--- a/intern/cycles/device/device_memory.h
+++ b/intern/cycles/device/device_memory.h
@@ -229,8 +229,11 @@ class device_memory {
device_memory(Device *device, const char *name, MemoryType type);
/* No copying allowed. */
- device_memory(const device_memory &);
- device_memory &operator=(const device_memory &);
+ device_memory(const device_memory &) = delete;
+ device_memory &operator=(const device_memory &) = delete;
+
+ /* But moving is possible. */
+ device_memory(device_memory &&);
/* Host allocation on the device. All host_pointer memory should be
* allocated with these functions, for devices that support using
@@ -269,6 +272,11 @@ template<typename T> class device_only_memory : public device_memory {
free();
}
+ device_only_memory(device_only_memory &&other)
+ : device_memory(static_cast<device_memory &&>(other))
+ {
+ }
+
void alloc_to_device(size_t num, bool shrink_to_fit = true)
{
size_t new_size = num;
@@ -327,6 +335,10 @@ template<typename T> class device_vector : public device_memory {
free();
}
+ device_vector(device_vector &&other) : device_memory(static_cast<device_memory &&>(other))
+ {
+ }
+
/* Host memory allocation. */
T *alloc(size_t width, size_t height = 0, size_t depth = 0)
{
diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp
index 4a40e106115..ac71be9dbea 100644
--- a/intern/cycles/device/device_multi.cpp
+++ b/intern/cycles/device/device_multi.cpp
@@ -153,6 +153,24 @@ class MultiDevice : public Device {
return result;
}
+ bool build_optix_bvh(BVH *bvh, device_memory &mem)
+ {
+ device_ptr key = unique_key++;
+
+ // Broadcast acceleration structure build to all devices
+ foreach (SubDevice &sub, devices) {
+ mem.device = sub.device;
+ if (!sub.device->build_optix_bvh(bvh, mem))
+ return false;
+ sub.ptr_map[key] = mem.device_pointer;
+ }
+
+ mem.device = this;
+ mem.device_pointer = key;
+ stats.mem_alloc(mem.device_size);
+ return true;
+ }
+
void mem_alloc(device_memory &mem)
{
device_ptr key = unique_key++;
diff --git a/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp
new file mode 100644
index 00000000000..b745235aed5
--- /dev/null
+++ b/intern/cycles/device/device_optix.cpp
@@ -0,0 +1,1970 @@
+/*
+ * Copyright 2019, NVIDIA Corporation.
+ * Copyright 2019, Blender Foundation.
+ *
+ * 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.
+ */
+
+#ifdef WITH_OPTIX
+
+# include "device/device.h"
+# include "device/device_intern.h"
+# include "device/device_denoising.h"
+# include "bvh/bvh.h"
+# include "render/scene.h"
+# include "render/mesh.h"
+# include "render/object.h"
+# include "render/buffers.h"
+# include "util/util_md5.h"
+# include "util/util_path.h"
+# include "util/util_time.h"
+# include "util/util_debug.h"
+# include "util/util_logging.h"
+
+# undef _WIN32_WINNT // Need minimum API support for Windows 7
+# define _WIN32_WINNT _WIN32_WINNT_WIN7
+
+# ifdef WITH_CUDA_DYNLOAD
+# include <cuew.h>
+// Do not use CUDA SDK headers when using CUEW
+# define OPTIX_DONT_INCLUDE_CUDA
+# endif
+# include <optix_stubs.h>
+# include <optix_function_table_definition.h>
+
+CCL_NAMESPACE_BEGIN
+
+/* Make sure this stays in sync with kernel_globals.h */
+struct ShaderParams {
+ uint4 *input;
+ float4 *output;
+ int type;
+ int filter;
+ int sx;
+ int offset;
+ int sample;
+};
+struct KernelParams {
+ WorkTile tile;
+ KernelData data;
+ ShaderParams shader;
+# define KERNEL_TEX(type, name) const type *name;
+# include "kernel/kernel_textures.h"
+# undef KERNEL_TEX
+};
+
+# define check_result_cuda(stmt) \
+ { \
+ CUresult res = stmt; \
+ if (res != CUDA_SUCCESS) { \
+ const char *name; \
+ cuGetErrorName(res, &name); \
+ set_error(string_printf("OptiX CUDA error %s in %s, line %d", name, #stmt, __LINE__)); \
+ return; \
+ } \
+ } \
+ (void)0
+# define check_result_cuda_ret(stmt) \
+ { \
+ CUresult res = stmt; \
+ if (res != CUDA_SUCCESS) { \
+ const char *name; \
+ cuGetErrorName(res, &name); \
+ set_error(string_printf("OptiX CUDA error %s in %s, line %d", name, #stmt, __LINE__)); \
+ return false; \
+ } \
+ } \
+ (void)0
+
+# define check_result_optix(stmt) \
+ { \
+ enum OptixResult res = stmt; \
+ if (res != OPTIX_SUCCESS) { \
+ const char *name = optixGetErrorName(res); \
+ set_error(string_printf("OptiX error %s in %s, line %d", name, #stmt, __LINE__)); \
+ return; \
+ } \
+ } \
+ (void)0
+# define check_result_optix_ret(stmt) \
+ { \
+ enum OptixResult res = stmt; \
+ if (res != OPTIX_SUCCESS) { \
+ const char *name = optixGetErrorName(res); \
+ set_error(string_printf("OptiX error %s in %s, line %d", name, #stmt, __LINE__)); \
+ return false; \
+ } \
+ } \
+ (void)0
+
+class OptiXDevice : public Device {
+
+ // List of OptiX program groups
+ enum {
+ PG_RGEN,
+ PG_MISS,
+ PG_HITD, // Default hit group
+ PG_HITL, // __BVH_LOCAL__ hit group
+ PG_HITS, // __SHADOW_RECORD_ALL__ hit group
+# ifdef WITH_CYCLES_DEBUG
+ PG_EXCP,
+# endif
+ PG_BAKE, // kernel_bake_evaluate
+ PG_DISP, // kernel_displace_evaluate
+ PG_BACK, // kernel_background_evaluate
+ NUM_PROGRAM_GROUPS
+ };
+
+ // List of OptiX pipelines
+ enum { PIP_PATH_TRACE, PIP_SHADER_EVAL, NUM_PIPELINES };
+
+ // A single shader binding table entry
+ struct SbtRecord {
+ char header[OPTIX_SBT_RECORD_HEADER_SIZE];
+ };
+
+ // Information stored about CUDA memory allocations
+ struct CUDAMem {
+ bool free_map_host = false;
+ CUarray array = NULL;
+ CUtexObject texobject = 0;
+ void *map_host_pointer = nullptr;
+ };
+
+ // Helper class to manage current CUDA context
+ struct CUDAContextScope {
+ CUDAContextScope(CUcontext ctx)
+ {
+ cuCtxPushCurrent(ctx);
+ }
+ ~CUDAContextScope()
+ {
+ cuCtxPopCurrent(NULL);
+ }
+ };
+
+ // Use a pool with multiple threads to support launches with multiple CUDA streams
+ TaskPool task_pool;
+
+ // CUDA/OptiX context handles
+ CUdevice cuda_device = 0;
+ CUcontext cuda_context = NULL;
+ vector<CUstream> cuda_stream;
+ OptixDeviceContext context = NULL;
+
+ // Need CUDA kernel module for some utility functions
+ CUmodule cuda_module = NULL;
+ CUmodule cuda_filter_module = NULL;
+ // All necessary OptiX kernels are in one module
+ OptixModule optix_module = NULL;
+ OptixPipeline pipelines[NUM_PIPELINES] = {};
+
+ bool need_texture_info = false;
+ device_vector<SbtRecord> sbt_data;
+ device_vector<TextureInfo> texture_info;
+ device_only_memory<KernelParams> launch_params;
+ vector<device_only_memory<uint8_t>> blas;
+ OptixTraversableHandle tlas_handle = 0;
+
+ map<device_memory *, CUDAMem> cuda_mem_map;
+
+ public:
+ OptiXDevice(DeviceInfo &info_, Stats &stats_, Profiler &profiler_, bool background_)
+ : Device(info_, stats_, profiler_, background_),
+ sbt_data(this, "__sbt", MEM_READ_ONLY),
+ texture_info(this, "__texture_info", MEM_TEXTURE),
+ launch_params(this, "__params")
+ {
+ // Store number of CUDA streams in device info
+ info.cpu_threads = DebugFlags().optix.cuda_streams;
+
+ // Initialize CUDA driver API
+ check_result_cuda(cuInit(0));
+
+ // Retrieve the primary CUDA context for this device
+ check_result_cuda(cuDeviceGet(&cuda_device, info.num));
+ check_result_cuda(cuDevicePrimaryCtxRetain(&cuda_context, cuda_device));
+
+ // Make that CUDA context current
+ const CUDAContextScope scope(cuda_context);
+
+ // Create OptiX context for this device
+ OptixDeviceContextOptions options = {};
+# ifdef WITH_CYCLES_LOGGING
+ options.logCallbackLevel = 4; // Fatal = 1, Error = 2, Warning = 3, Print = 4
+ options.logCallbackFunction =
+ [](unsigned int level, const char *, const char *message, void *) {
+ switch (level) {
+ case 1:
+ LOG_IF(FATAL, VLOG_IS_ON(1)) << message;
+ break;
+ case 2:
+ LOG_IF(ERROR, VLOG_IS_ON(1)) << message;
+ break;
+ case 3:
+ LOG_IF(WARNING, VLOG_IS_ON(1)) << message;
+ break;
+ case 4:
+ LOG_IF(INFO, VLOG_IS_ON(1)) << message;
+ break;
+ }
+ };
+# endif
+ check_result_optix(optixDeviceContextCreate(cuda_context, &options, &context));
+# ifdef WITH_CYCLES_LOGGING
+ check_result_optix(optixDeviceContextSetLogCallback(
+ context, options.logCallbackFunction, options.logCallbackData, options.logCallbackLevel));
+# endif
+
+ // Create launch streams
+ cuda_stream.resize(info.cpu_threads);
+ for (int i = 0; i < info.cpu_threads; ++i)
+ check_result_cuda(cuStreamCreate(&cuda_stream[i], CU_STREAM_NON_BLOCKING));
+
+ // Fix weird compiler bug that assigns wrong size
+ launch_params.data_elements = sizeof(KernelParams);
+ // Allocate launch parameter buffer memory on device
+ launch_params.alloc_to_device(info.cpu_threads);
+ }
+ ~OptiXDevice()
+ {
+ // Stop processing any more tasks
+ task_pool.stop();
+
+ // Clean up all memory before destroying context
+ blas.clear();
+
+ sbt_data.free();
+ texture_info.free();
+ launch_params.free();
+
+ // Make CUDA context current
+ const CUDAContextScope scope(cuda_context);
+
+ // Unload modules
+ if (cuda_module != NULL)
+ cuModuleUnload(cuda_module);
+ if (cuda_filter_module != NULL)
+ cuModuleUnload(cuda_filter_module);
+ if (optix_module != NULL)
+ optixModuleDestroy(optix_module);
+ for (unsigned int i = 0; i < NUM_PIPELINES; ++i)
+ if (pipelines[i] != NULL)
+ optixPipelineDestroy(pipelines[i]);
+
+ // Destroy launch streams
+ for (int i = 0; i < info.cpu_threads; ++i)
+ cuStreamDestroy(cuda_stream[i]);
+
+ // Destroy OptiX and CUDA context
+ optixDeviceContextDestroy(context);
+ cuDevicePrimaryCtxRelease(cuda_device);
+ }
+
+ private:
+ bool show_samples() const override
+ {
+ // Only show samples if not rendering multiple tiles in parallel
+ return info.cpu_threads == 1;
+ }
+
+ BVHLayoutMask get_bvh_layout_mask() const override
+ {
+ // OptiX has its own internal acceleration structure format
+ return BVH_LAYOUT_OPTIX;
+ }
+
+ bool load_kernels(const DeviceRequestedFeatures &requested_features) override
+ {
+ if (have_error())
+ return false; // Abort early if context creation failed already
+
+ // Disable baking for now, since its kernel is not well-suited for inlining and is very slow
+ if (requested_features.use_baking) {
+ set_error("OptiX implementation does not support baking yet");
+ return false;
+ }
+ // Disable shader raytracing support for now, since continuation callables are slow
+ if (requested_features.use_shader_raytrace) {
+ set_error("OptiX implementation does not support shader raytracing yet");
+ return false;
+ }
+
+ const CUDAContextScope scope(cuda_context);
+
+ // Unload any existing modules first
+ if (cuda_module != NULL)
+ cuModuleUnload(cuda_module);
+ if (cuda_filter_module != NULL)
+ cuModuleUnload(cuda_filter_module);
+ if (optix_module != NULL)
+ optixModuleDestroy(optix_module);
+ for (unsigned int i = 0; i < NUM_PIPELINES; ++i)
+ if (pipelines[i] != NULL)
+ optixPipelineDestroy(pipelines[i]);
+
+ OptixModuleCompileOptions module_options;
+ module_options.maxRegisterCount = 0; // Do not set an explicit register limit
+# ifdef WITH_CYCLES_DEBUG
+ module_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0;
+ module_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL;
+# else
+ module_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_3;
+ module_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_LINEINFO;
+# endif
+ OptixPipelineCompileOptions pipeline_options;
+ // Default to no motion blur and two-level graph, since it is the fastest option
+ pipeline_options.usesMotionBlur = false;
+ pipeline_options.traversableGraphFlags =
+ OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_LEVEL_INSTANCING;
+ pipeline_options.numPayloadValues = 6;
+ pipeline_options.numAttributeValues = 2; // u, v
+# ifdef WITH_CYCLES_DEBUG
+ pipeline_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_STACK_OVERFLOW |
+ OPTIX_EXCEPTION_FLAG_TRACE_DEPTH;
+# else
+ pipeline_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE;
+# endif
+ pipeline_options.pipelineLaunchParamsVariableName = "__params"; // See kernel_globals.h
+
+ if (requested_features.use_object_motion) {
+ pipeline_options.usesMotionBlur = true;
+ // Motion blur can insert motion transforms into the traversal graph
+ // It is no longer a two-level graph then, so need to set flags to allow any configuration
+ pipeline_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_ANY;
+ }
+
+ { // Load and compile PTX module with OptiX kernels
+ string ptx_data;
+ const string ptx_filename = "lib/kernel_optix.ptx";
+ if (!path_read_text(path_get(ptx_filename), ptx_data)) {
+ set_error("Failed loading OptiX kernel " + ptx_filename + ".");
+ return false;
+ }
+
+ check_result_optix_ret(optixModuleCreateFromPTX(context,
+ &module_options,
+ &pipeline_options,
+ ptx_data.data(),
+ ptx_data.size(),
+ nullptr,
+ 0,
+ &optix_module));
+ }
+
+ { // Load CUDA modules because we need some of the utility kernels
+ int major, minor;
+ cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, info.num);
+ cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, info.num);
+
+ string cubin_data;
+ const string cubin_filename = string_printf("lib/kernel_sm_%d%d.cubin", major, minor);
+ if (!path_read_text(path_get(cubin_filename), cubin_data)) {
+ set_error("Failed loading pre-compiled CUDA kernel " + cubin_filename + ".");
+ return false;
+ }
+
+ check_result_cuda_ret(cuModuleLoadData(&cuda_module, cubin_data.data()));
+
+ if (requested_features.use_denoising) {
+ string filter_data;
+ const string filter_filename = string_printf("lib/filter_sm_%d%d.cubin", major, minor);
+ if (!path_read_text(path_get(filter_filename), filter_data)) {
+ set_error("Failed loading pre-compiled CUDA filter kernel " + filter_filename + ".");
+ return false;
+ }
+
+ check_result_cuda_ret(cuModuleLoadData(&cuda_filter_module, filter_data.data()));
+ }
+ }
+
+ // Create program groups
+ OptixProgramGroup groups[NUM_PROGRAM_GROUPS] = {};
+ OptixProgramGroupDesc group_descs[NUM_PROGRAM_GROUPS] = {};
+ OptixProgramGroupOptions group_options = {}; // There are no options currently
+ group_descs[PG_RGEN].kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN;
+ group_descs[PG_RGEN].raygen.module = optix_module;
+ // Ignore branched integrator for now (see "requested_features.use_integrator_branched")
+ group_descs[PG_RGEN].raygen.entryFunctionName = "__raygen__kernel_optix_path_trace";
+ group_descs[PG_MISS].kind = OPTIX_PROGRAM_GROUP_KIND_MISS;
+ group_descs[PG_MISS].miss.module = optix_module;
+ group_descs[PG_MISS].miss.entryFunctionName = "__miss__kernel_optix_miss";
+ group_descs[PG_HITD].kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP;
+ group_descs[PG_HITD].hitgroup.moduleCH = optix_module;
+ group_descs[PG_HITD].hitgroup.entryFunctionNameCH = "__closesthit__kernel_optix_hit";
+ group_descs[PG_HITD].hitgroup.moduleAH = optix_module;
+ group_descs[PG_HITD].hitgroup.entryFunctionNameAH = "__anyhit__kernel_optix_visibility_test";
+ group_descs[PG_HITS].kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP;
+ group_descs[PG_HITS].hitgroup.moduleAH = optix_module;
+ group_descs[PG_HITS].hitgroup.entryFunctionNameAH = "__anyhit__kernel_optix_shadow_all_hit";
+
+ if (requested_features.use_hair) {
+ // Add curve intersection programs
+ group_descs[PG_HITD].hitgroup.moduleIS = optix_module;
+ group_descs[PG_HITD].hitgroup.entryFunctionNameIS = "__intersection__curve";
+ group_descs[PG_HITS].hitgroup.moduleIS = optix_module;
+ group_descs[PG_HITS].hitgroup.entryFunctionNameIS = "__intersection__curve";
+ }
+
+ if (requested_features.use_subsurface || requested_features.use_shader_raytrace) {
+ // Add hit group for local intersections
+ group_descs[PG_HITL].kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP;
+ group_descs[PG_HITL].hitgroup.moduleAH = optix_module;
+ group_descs[PG_HITL].hitgroup.entryFunctionNameAH = "__anyhit__kernel_optix_local_hit";
+ }
+
+# ifdef WITH_CYCLES_DEBUG
+ group_descs[PG_EXCP].kind = OPTIX_PROGRAM_GROUP_KIND_EXCEPTION;
+ group_descs[PG_EXCP].exception.module = optix_module;
+ group_descs[PG_EXCP].exception.entryFunctionName = "__exception__kernel_optix_exception";
+# endif
+
+ if (requested_features.use_baking) {
+ group_descs[PG_BAKE].kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN;
+ group_descs[PG_BAKE].raygen.module = optix_module;
+ group_descs[PG_BAKE].raygen.entryFunctionName = "__raygen__kernel_optix_bake";
+ }
+
+ if (requested_features.use_true_displacement) {
+ group_descs[PG_DISP].kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN;
+ group_descs[PG_DISP].raygen.module = optix_module;
+ group_descs[PG_DISP].raygen.entryFunctionName = "__raygen__kernel_optix_displace";
+ }
+
+ if (requested_features.use_background_light) {
+ group_descs[PG_BACK].kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN;
+ group_descs[PG_BACK].raygen.module = optix_module;
+ group_descs[PG_BACK].raygen.entryFunctionName = "__raygen__kernel_optix_background";
+ }
+
+ check_result_optix_ret(optixProgramGroupCreate(
+ context, group_descs, NUM_PROGRAM_GROUPS, &group_options, nullptr, 0, groups));
+
+ // Get program stack sizes
+ OptixStackSizes stack_size[NUM_PROGRAM_GROUPS] = {};
+ // Set up SBT, which in this case is used only to select between different programs
+ sbt_data.alloc(NUM_PROGRAM_GROUPS);
+ memset(sbt_data.host_pointer, 0, sizeof(SbtRecord) * NUM_PROGRAM_GROUPS);
+ for (unsigned int i = 0; i < NUM_PROGRAM_GROUPS; ++i) {
+ check_result_optix_ret(optixSbtRecordPackHeader(groups[i], &sbt_data[i]));
+ check_result_optix_ret(optixProgramGroupGetStackSize(groups[i], &stack_size[i]));
+ }
+ sbt_data.copy_to_device(); // Upload SBT to device
+
+ // Calculate maximum trace continuation stack size
+ unsigned int trace_css = stack_size[PG_HITD].cssCH;
+ // This is based on the maximum of closest-hit and any-hit/intersection programs
+ trace_css = max(trace_css, stack_size[PG_HITD].cssIS + stack_size[PG_HITD].cssAH);
+ trace_css = max(trace_css, stack_size[PG_HITL].cssIS + stack_size[PG_HITL].cssAH);
+ trace_css = max(trace_css, stack_size[PG_HITS].cssIS + stack_size[PG_HITS].cssAH);
+
+ OptixPipelineLinkOptions link_options;
+ link_options.maxTraceDepth = 1;
+# ifdef WITH_CYCLES_DEBUG
+ link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL;
+# else
+ link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_LINEINFO;
+# endif
+ link_options.overrideUsesMotionBlur = pipeline_options.usesMotionBlur;
+
+ { // Create path tracing pipeline
+ OptixProgramGroup pipeline_groups[] = {
+ groups[PG_RGEN],
+ groups[PG_MISS],
+ groups[PG_HITD],
+ groups[PG_HITS],
+ groups[PG_HITL],
+# ifdef WITH_CYCLES_DEBUG
+ groups[PG_EXCP],
+# endif
+ };
+ check_result_optix_ret(
+ optixPipelineCreate(context,
+ &pipeline_options,
+ &link_options,
+ pipeline_groups,
+ (sizeof(pipeline_groups) / sizeof(pipeline_groups[0])),
+ nullptr,
+ 0,
+ &pipelines[PIP_PATH_TRACE]));
+
+ // Combine ray generation and trace continuation stack size
+ const unsigned int css = stack_size[PG_RGEN].cssRG + link_options.maxTraceDepth * trace_css;
+
+ // Set stack size depending on pipeline options
+ check_result_optix_ret(optixPipelineSetStackSize(
+ pipelines[PIP_PATH_TRACE], 0, 0, css, (pipeline_options.usesMotionBlur ? 3 : 2)));
+ }
+
+ // Only need to create shader evaluation pipeline if one of these features is used:
+ const bool use_shader_eval_pipeline = requested_features.use_baking ||
+ requested_features.use_background_light ||
+ requested_features.use_true_displacement;
+
+ if (use_shader_eval_pipeline) { // Create shader evaluation pipeline
+ OptixProgramGroup pipeline_groups[] = {
+ groups[PG_BAKE],
+ groups[PG_DISP],
+ groups[PG_BACK],
+ groups[PG_MISS],
+ groups[PG_HITD],
+ groups[PG_HITS],
+ groups[PG_HITL],
+# ifdef WITH_CYCLES_DEBUG
+ groups[PG_EXCP],
+# endif
+ };
+ check_result_optix_ret(
+ optixPipelineCreate(context,
+ &pipeline_options,
+ &link_options,
+ pipeline_groups,
+ (sizeof(pipeline_groups) / sizeof(pipeline_groups[0])),
+ nullptr,
+ 0,
+ &pipelines[PIP_SHADER_EVAL]));
+
+ // Calculate continuation stack size based on the maximum of all ray generation stack sizes
+ const unsigned int css = max(stack_size[PG_BAKE].cssRG,
+ max(stack_size[PG_DISP].cssRG, stack_size[PG_BACK].cssRG)) +
+ link_options.maxTraceDepth * trace_css;
+
+ check_result_optix_ret(optixPipelineSetStackSize(
+ pipelines[PIP_SHADER_EVAL], 0, 0, css, (pipeline_options.usesMotionBlur ? 3 : 2)));
+ }
+
+ // Clean up program group objects
+ for (unsigned int i = 0; i < NUM_PROGRAM_GROUPS; ++i) {
+ optixProgramGroupDestroy(groups[i]);
+ }
+
+ return true;
+ }
+
+ void thread_run(DeviceTask &task, int thread_index) // Main task entry point
+ {
+ if (have_error())
+ return; // Abort early if there was an error previously
+
+ if (task.type == DeviceTask::RENDER) {
+ RenderTile tile;
+ while (task.acquire_tile(this, tile)) {
+ if (tile.task == RenderTile::PATH_TRACE)
+ launch_render(task, tile, thread_index);
+ else if (tile.task == RenderTile::DENOISE)
+ launch_denoise(task, tile, thread_index);
+ task.release_tile(tile);
+ if (task.get_cancel() && !task.need_finish_queue)
+ break; // User requested cancellation
+ else if (have_error())
+ break; // Abort rendering when encountering an error
+ }
+ }
+ else if (task.type == DeviceTask::SHADER) {
+ launch_shader_eval(task, thread_index);
+ }
+ else if (task.type == DeviceTask::FILM_CONVERT) {
+ launch_film_convert(task, thread_index);
+ }
+ }
+
+ void launch_render(DeviceTask &task, RenderTile &rtile, int thread_index)
+ {
+ assert(thread_index < launch_params.data_size);
+
+ // Keep track of total render time of this tile
+ const scoped_timer timer(&rtile.buffers->render_time);
+
+ WorkTile wtile;
+ wtile.x = rtile.x;
+ wtile.y = rtile.y;
+ wtile.w = rtile.w;
+ wtile.h = rtile.h;
+ wtile.offset = rtile.offset;
+ wtile.stride = rtile.stride;
+ wtile.buffer = (float *)rtile.buffer;
+
+ const int end_sample = rtile.start_sample + rtile.num_samples;
+ // Keep this number reasonable to avoid running into TDRs
+ const int step_samples = (info.display_device ? 8 : 32);
+ // Offset into launch params buffer so that streams use separate data
+ device_ptr launch_params_ptr = launch_params.device_pointer +
+ thread_index * launch_params.data_elements;
+
+ const CUDAContextScope scope(cuda_context);
+
+ for (int sample = rtile.start_sample; sample < end_sample; sample += step_samples) {
+ // Copy work tile information to device
+ wtile.num_samples = min(step_samples, end_sample - sample);
+ wtile.start_sample = sample;
+ check_result_cuda(cuMemcpyHtoDAsync(launch_params_ptr + offsetof(KernelParams, tile),
+ &wtile,
+ sizeof(wtile),
+ cuda_stream[thread_index]));
+
+ OptixShaderBindingTable sbt_params = {};
+ sbt_params.raygenRecord = sbt_data.device_pointer + PG_RGEN * sizeof(SbtRecord);
+# ifdef WITH_CYCLES_DEBUG
+ sbt_params.exceptionRecord = sbt_data.device_pointer + PG_EXCP * sizeof(SbtRecord);
+# endif
+ sbt_params.missRecordBase = sbt_data.device_pointer + PG_MISS * sizeof(SbtRecord);
+ sbt_params.missRecordStrideInBytes = sizeof(SbtRecord);
+ sbt_params.missRecordCount = 1;
+ sbt_params.hitgroupRecordBase = sbt_data.device_pointer + PG_HITD * sizeof(SbtRecord);
+ sbt_params.hitgroupRecordStrideInBytes = sizeof(SbtRecord);
+ sbt_params.hitgroupRecordCount = 3; // PG_HITD, PG_HITL, PG_HITS
+
+ // Launch the ray generation program
+ check_result_optix(optixLaunch(pipelines[PIP_PATH_TRACE],
+ cuda_stream[thread_index],
+ launch_params_ptr,
+ launch_params.data_elements,
+ &sbt_params,
+ // Launch with samples close to each other for better locality
+ wtile.w * wtile.num_samples,
+ wtile.h,
+ 1));
+
+ // Wait for launch to finish
+ check_result_cuda(cuStreamSynchronize(cuda_stream[thread_index]));
+
+ // Update current sample, so it is displayed correctly
+ rtile.sample = wtile.start_sample + wtile.num_samples;
+ // Update task progress after the kernel completed rendering
+ task.update_progress(&rtile, wtile.w * wtile.h * wtile.num_samples);
+
+ if (task.get_cancel() && !task.need_finish_queue)
+ return; // Cancel rendering
+ }
+ }
+
+ void launch_denoise(DeviceTask &task, RenderTile &rtile, int thread_index)
+ {
+ const CUDAContextScope scope(cuda_context);
+
+ // Run CUDA denoising kernels
+ DenoisingTask denoising(this, task);
+ denoising.functions.construct_transform = function_bind(
+ &OptiXDevice::denoising_construct_transform, this, &denoising, thread_index);
+ denoising.functions.accumulate = function_bind(
+ &OptiXDevice::denoising_accumulate, this, _1, _2, _3, _4, &denoising, thread_index);
+ denoising.functions.solve = function_bind(
+ &OptiXDevice::denoising_solve, this, _1, &denoising, thread_index);
+ denoising.functions.divide_shadow = function_bind(
+ &OptiXDevice::denoising_divide_shadow, this, _1, _2, _3, _4, _5, &denoising, thread_index);
+ denoising.functions.non_local_means = function_bind(
+ &OptiXDevice::denoising_non_local_means, this, _1, _2, _3, _4, &denoising, thread_index);
+ denoising.functions.combine_halves = function_bind(&OptiXDevice::denoising_combine_halves,
+ this,
+ _1,
+ _2,
+ _3,
+ _4,
+ _5,
+ _6,
+ &denoising,
+ thread_index);
+ denoising.functions.get_feature = function_bind(
+ &OptiXDevice::denoising_get_feature, this, _1, _2, _3, _4, _5, &denoising, thread_index);
+ denoising.functions.write_feature = function_bind(
+ &OptiXDevice::denoising_write_feature, this, _1, _2, _3, &denoising, thread_index);
+ denoising.functions.detect_outliers = function_bind(
+ &OptiXDevice::denoising_detect_outliers, this, _1, _2, _3, _4, &denoising, thread_index);
+
+ denoising.filter_area = make_int4(rtile.x, rtile.y, rtile.w, rtile.h);
+ denoising.render_buffer.samples = rtile.sample = rtile.start_sample + rtile.num_samples;
+ denoising.buffer.gpu_temporary_mem = true;
+
+ denoising.run_denoising(&rtile);
+
+ task.update_progress(&rtile, rtile.w * rtile.h);
+ }
+
+ void launch_shader_eval(DeviceTask &task, int thread_index)
+ {
+ unsigned int rgen_index = PG_BACK;
+ if (task.shader_eval_type >= SHADER_EVAL_BAKE)
+ rgen_index = PG_BAKE;
+ if (task.shader_eval_type == SHADER_EVAL_DISPLACE)
+ rgen_index = PG_DISP;
+
+ const CUDAContextScope scope(cuda_context);
+
+ device_ptr launch_params_ptr = launch_params.device_pointer +
+ thread_index * launch_params.data_elements;
+
+ for (int sample = 0; sample < task.num_samples; ++sample) {
+ ShaderParams params;
+ params.input = (uint4 *)task.shader_input;
+ params.output = (float4 *)task.shader_output;
+ params.type = task.shader_eval_type;
+ params.filter = task.shader_filter;
+ params.sx = task.shader_x;
+ params.offset = task.offset;
+ params.sample = sample;
+
+ check_result_cuda(cuMemcpyHtoDAsync(launch_params_ptr + offsetof(KernelParams, shader),
+ &params,
+ sizeof(params),
+ cuda_stream[thread_index]));
+
+ OptixShaderBindingTable sbt_params = {};
+ sbt_params.raygenRecord = sbt_data.device_pointer + rgen_index * sizeof(SbtRecord);
+# ifdef WITH_CYCLES_DEBUG
+ sbt_params.exceptionRecord = sbt_data.device_pointer + PG_EXCP * sizeof(SbtRecord);
+# endif
+ sbt_params.missRecordBase = sbt_data.device_pointer + PG_MISS * sizeof(SbtRecord);
+ sbt_params.missRecordStrideInBytes = sizeof(SbtRecord);
+ sbt_params.missRecordCount = 1;
+ sbt_params.hitgroupRecordBase = sbt_data.device_pointer + PG_HITD * sizeof(SbtRecord);
+ sbt_params.hitgroupRecordStrideInBytes = sizeof(SbtRecord);
+ sbt_params.hitgroupRecordCount = 3; // PG_HITD, PG_HITL, PG_HITS
+
+ check_result_optix(optixLaunch(pipelines[PIP_SHADER_EVAL],
+ cuda_stream[thread_index],
+ launch_params_ptr,
+ launch_params.data_elements,
+ &sbt_params,
+ task.shader_w,
+ 1,
+ 1));
+
+ check_result_cuda(cuStreamSynchronize(cuda_stream[thread_index]));
+
+ task.update_progress(NULL);
+ }
+ }
+
+ void launch_film_convert(DeviceTask &task, int thread_index)
+ {
+ const CUDAContextScope scope(cuda_context);
+
+ CUfunction film_convert_func;
+ check_result_cuda(cuModuleGetFunction(&film_convert_func,
+ cuda_module,
+ task.rgba_byte ? "kernel_cuda_convert_to_byte" :
+ "kernel_cuda_convert_to_half_float"));
+
+ float sample_scale = 1.0f / (task.sample + 1);
+ CUdeviceptr rgba = (task.rgba_byte ? task.rgba_byte : task.rgba_half);
+
+ void *args[] = {&rgba,
+ &task.buffer,
+ &sample_scale,
+ &task.x,
+ &task.y,
+ &task.w,
+ &task.h,
+ &task.offset,
+ &task.stride};
+
+ int threads_per_block;
+ check_result_cuda(cuFuncGetAttribute(
+ &threads_per_block, CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, film_convert_func));
+
+ const int num_threads_x = (int)sqrt(threads_per_block);
+ const int num_blocks_x = (task.w + num_threads_x - 1) / num_threads_x;
+ const int num_threads_y = (int)sqrt(threads_per_block);
+ const int num_blocks_y = (task.h + num_threads_y - 1) / num_threads_y;
+
+ check_result_cuda(cuLaunchKernel(film_convert_func,
+ num_blocks_x,
+ num_blocks_y,
+ 1, /* blocks */
+ num_threads_x,
+ num_threads_y,
+ 1, /* threads */
+ 0,
+ cuda_stream[thread_index],
+ args,
+ 0));
+
+ check_result_cuda(cuStreamSynchronize(cuda_stream[thread_index]));
+
+ task.update_progress(NULL);
+ }
+
+ bool build_optix_bvh(const OptixBuildInput &build_input,
+ uint16_t num_motion_steps,
+ device_memory &out_data,
+ OptixTraversableHandle &out_handle)
+ {
+ out_handle = 0;
+
+ const CUDAContextScope scope(cuda_context);
+
+ // Compute memory usage
+ OptixAccelBufferSizes sizes = {};
+ OptixAccelBuildOptions options;
+ options.operation = OPTIX_BUILD_OPERATION_BUILD;
+ options.buildFlags = OPTIX_BUILD_FLAG_PREFER_FAST_TRACE;
+ options.motionOptions.numKeys = num_motion_steps;
+ options.motionOptions.flags = OPTIX_MOTION_FLAG_START_VANISH | OPTIX_MOTION_FLAG_END_VANISH;
+ options.motionOptions.timeBegin = 0.0f;
+ options.motionOptions.timeEnd = 1.0f;
+
+ check_result_optix_ret(
+ optixAccelComputeMemoryUsage(context, &options, &build_input, 1, &sizes));
+
+ // Allocate required output buffers
+ device_only_memory<char> temp_mem(this, "temp_build_mem");
+ temp_mem.alloc_to_device(sizes.tempSizeInBytes);
+
+ out_data.data_type = TYPE_UNKNOWN;
+ out_data.data_elements = 1;
+ out_data.data_size = sizes.outputSizeInBytes;
+ mem_alloc(out_data);
+
+ // Finally build the acceleration structure
+ check_result_optix_ret(optixAccelBuild(context,
+ NULL,
+ &options,
+ &build_input,
+ 1,
+ temp_mem.device_pointer,
+ sizes.tempSizeInBytes,
+ out_data.device_pointer,
+ sizes.outputSizeInBytes,
+ &out_handle,
+ NULL,
+ 0));
+
+ // Wait for all operations to finish
+ check_result_cuda_ret(cuStreamSynchronize(NULL));
+
+ return true;
+ }
+
+ bool build_optix_bvh(BVH *bvh, device_memory &out_data) override
+ {
+ assert(bvh->params.top_level);
+
+ unsigned int num_instances = 0;
+ unordered_map<Mesh *, vector<OptixTraversableHandle>> meshes;
+
+ // Clear all previous AS
+ blas.clear();
+
+ // Build bottom level acceleration structures (BLAS)
+ // Note: Always keep this logic in sync with bvh_optix.cpp!
+ for (Object *ob : bvh->objects) {
+ // Skip meshes for which acceleration structure already exists
+ if (meshes.find(ob->mesh) != meshes.end())
+ continue;
+
+ Mesh *const mesh = ob->mesh;
+ vector<OptixTraversableHandle> handles;
+
+ // Build BLAS for curve primitives
+ if (bvh->params.primitive_mask & PRIMITIVE_ALL_CURVE && mesh->num_curves() > 0) {
+ const size_t num_curves = mesh->num_curves();
+ const size_t num_segments = mesh->num_segments();
+
+ size_t num_motion_steps = 1;
+ Attribute *motion_keys = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (mesh->use_motion_blur && motion_keys) {
+ num_motion_steps = mesh->motion_steps;
+ }
+
+ device_vector<OptixAabb> aabb_data(this, "temp_aabb_data", MEM_READ_ONLY);
+ aabb_data.alloc(num_segments * num_motion_steps);
+
+ // Get AABBs for each motion step
+ for (size_t step = 0; step < num_motion_steps; ++step) {
+ // The center step for motion vertices is not stored in the attribute
+ const float3 *keys = mesh->curve_keys.data();
+ size_t center_step = (num_motion_steps - 1) / 2;
+ if (step != center_step) {
+ size_t attr_offset = (step > center_step) ? step - 1 : step;
+ // Technically this is a float4 array, but sizeof(float3) is the same as sizeof(float4)
+ keys = motion_keys->data_float3() + attr_offset * mesh->curve_keys.size();
+ }
+
+ size_t i = step * num_segments;
+ for (size_t j = 0; j < num_curves; ++j) {
+ const Mesh::Curve c = mesh->get_curve(j);
+
+ for (size_t k = 0; k < c.num_segments(); ++i, ++k) {
+ BoundBox bounds = BoundBox::empty;
+ c.bounds_grow(k, keys, mesh->curve_radius.data(), bounds);
+
+ aabb_data[i].minX = bounds.min.x;
+ aabb_data[i].minY = bounds.min.y;
+ aabb_data[i].minZ = bounds.min.z;
+ aabb_data[i].maxX = bounds.max.x;
+ aabb_data[i].maxY = bounds.max.y;
+ aabb_data[i].maxZ = bounds.max.z;
+ }
+ }
+ }
+
+ // Upload AABB data to GPU
+ aabb_data.copy_to_device();
+
+ vector<device_ptr> aabb_ptrs;
+ aabb_ptrs.reserve(num_motion_steps);
+ for (size_t step = 0; step < num_motion_steps; ++step) {
+ aabb_ptrs.push_back(aabb_data.device_pointer + step * num_segments * sizeof(OptixAabb));
+ }
+
+ // Disable visibility test anyhit program, since it is already checked during intersection
+ // Those trace calls that require anyhit can force it with OPTIX_RAY_FLAG_ENFORCE_ANYHIT
+ unsigned int build_flags = OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT;
+ OptixBuildInput build_input = {};
+ build_input.type = OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES;
+ build_input.aabbArray.aabbBuffers = (CUdeviceptr *)aabb_ptrs.data();
+ build_input.aabbArray.numPrimitives = num_segments;
+ build_input.aabbArray.strideInBytes = sizeof(OptixAabb);
+ build_input.aabbArray.flags = &build_flags;
+ build_input.aabbArray.numSbtRecords = 1;
+ build_input.aabbArray.primitiveIndexOffset = mesh->prim_offset;
+
+ // Allocate memory for new BLAS and build it
+ blas.emplace_back(this, "blas");
+ handles.emplace_back();
+ if (!build_optix_bvh(build_input, num_motion_steps, blas.back(), handles.back()))
+ return false;
+ }
+
+ // Build BLAS for triangle primitives
+ if (bvh->params.primitive_mask & PRIMITIVE_ALL_TRIANGLE && mesh->num_triangles() > 0) {
+ const size_t num_verts = mesh->verts.size();
+
+ size_t num_motion_steps = 1;
+ Attribute *motion_keys = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (mesh->use_motion_blur && motion_keys) {
+ num_motion_steps = mesh->motion_steps;
+ }
+
+ device_vector<int> index_data(this, "temp_index_data", MEM_READ_ONLY);
+ index_data.alloc(mesh->triangles.size());
+ memcpy(index_data.data(), mesh->triangles.data(), mesh->triangles.size() * sizeof(int));
+ device_vector<float3> vertex_data(this, "temp_vertex_data", MEM_READ_ONLY);
+ vertex_data.alloc(num_verts * num_motion_steps);
+
+ for (size_t step = 0; step < num_motion_steps; ++step) {
+ const float3 *verts = mesh->verts.data();
+
+ size_t center_step = (num_motion_steps - 1) / 2;
+ // The center step for motion vertices is not stored in the attribute
+ if (step != center_step) {
+ verts = motion_keys->data_float3() +
+ (step > center_step ? step - 1 : step) * num_verts;
+ }
+
+ memcpy(vertex_data.data() + num_verts * step, verts, num_verts * sizeof(float3));
+ }
+
+ // Upload triangle data to GPU
+ index_data.copy_to_device();
+ vertex_data.copy_to_device();
+
+ vector<device_ptr> vertex_ptrs;
+ vertex_ptrs.reserve(num_motion_steps);
+ for (size_t step = 0; step < num_motion_steps; ++step) {
+ vertex_ptrs.push_back(vertex_data.device_pointer + num_verts * step * sizeof(float3));
+ }
+
+ // No special build flags for triangle primitives
+ unsigned int build_flags = OPTIX_GEOMETRY_FLAG_NONE;
+ OptixBuildInput build_input = {};
+ build_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES;
+ build_input.triangleArray.vertexBuffers = (CUdeviceptr *)vertex_ptrs.data();
+ build_input.triangleArray.numVertices = num_verts;
+ build_input.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3;
+ build_input.triangleArray.vertexStrideInBytes = sizeof(float3);
+ build_input.triangleArray.indexBuffer = index_data.device_pointer;
+ build_input.triangleArray.numIndexTriplets = mesh->num_triangles();
+ build_input.triangleArray.indexFormat = OPTIX_INDICES_FORMAT_UNSIGNED_INT3;
+ build_input.triangleArray.indexStrideInBytes = 3 * sizeof(int);
+ build_input.triangleArray.flags = &build_flags;
+ // The SBT does not store per primitive data since Cycles already allocates separate
+ // buffers for that purpose. OptiX does not allow this to be zero though, so just pass in
+ // one and rely on that having the same meaning in this case.
+ build_input.triangleArray.numSbtRecords = 1;
+ // Triangle primitives are packed right after the curve primitives of this mesh
+ build_input.triangleArray.primitiveIndexOffset = mesh->prim_offset + mesh->num_segments();
+
+ // Allocate memory for new BLAS and build it
+ blas.emplace_back(this, "blas");
+ handles.emplace_back();
+ if (!build_optix_bvh(build_input, num_motion_steps, blas.back(), handles.back()))
+ return false;
+ }
+
+ meshes.insert({mesh, handles});
+ }
+
+ // Fill instance descriptions
+ device_vector<OptixAabb> aabbs(this, "tlas_aabbs", MEM_READ_ONLY);
+ aabbs.alloc(bvh->objects.size() * 2);
+ device_vector<OptixInstance> instances(this, "tlas_instances", MEM_READ_ONLY);
+ instances.alloc(bvh->objects.size() * 2);
+
+ for (Object *ob : bvh->objects) {
+ // Skip non-traceable objects
+ if (!ob->is_traceable())
+ continue;
+ // Create separate instance for triangle/curve meshes of an object
+ for (OptixTraversableHandle handle : meshes[ob->mesh]) {
+ OptixAabb &aabb = aabbs[num_instances];
+ aabb.minX = ob->bounds.min.x;
+ aabb.minY = ob->bounds.min.y;
+ aabb.minZ = ob->bounds.min.z;
+ aabb.maxX = ob->bounds.max.x;
+ aabb.maxY = ob->bounds.max.y;
+ aabb.maxZ = ob->bounds.max.z;
+
+ OptixInstance &instance = instances[num_instances++];
+ memset(&instance, 0, sizeof(instance));
+
+ // Clear transform to identity matrix
+ instance.transform[0] = 1.0f;
+ instance.transform[5] = 1.0f;
+ instance.transform[10] = 1.0f;
+
+ // Set user instance ID to object index
+ instance.instanceId = ob->get_device_index();
+
+ // Volumes have a special bit set in the visibility mask so a trace can mask only volumes
+ // See 'scene_intersect_volume' in bvh.h
+ instance.visibilityMask = (ob->mesh->has_volume ? 3 : 1);
+
+ // Insert motion traversable if object has motion
+ if (ob->use_motion()) {
+ blas.emplace_back(this, "motion_transform");
+ device_only_memory<uint8_t> &motion_transform_gpu = blas.back();
+ motion_transform_gpu.alloc_to_device(sizeof(OptixSRTMotionTransform) +
+ (max(ob->motion.size(), 2) - 2) *
+ sizeof(OptixSRTData));
+
+ // Allocate host side memory for motion transform and fill it with transform data
+ OptixSRTMotionTransform &motion_transform = *reinterpret_cast<OptixSRTMotionTransform *>(
+ motion_transform_gpu.host_pointer = new uint8_t[motion_transform_gpu.memory_size()]);
+ motion_transform.child = handle;
+ motion_transform.motionOptions.numKeys = ob->motion.size();
+ motion_transform.motionOptions.flags = OPTIX_MOTION_FLAG_NONE;
+ motion_transform.motionOptions.timeBegin = 0.0f;
+ motion_transform.motionOptions.timeEnd = 1.0f;
+
+ OptixSRTData *const srt_data = motion_transform.srtData;
+ array<DecomposedTransform> decomp(ob->motion.size());
+ transform_motion_decompose(decomp.data(), ob->motion.data(), ob->motion.size());
+
+ for (size_t i = 0; i < ob->motion.size(); ++i) {
+ // scaling
+ srt_data[i].a = decomp[i].z.x; // scale.x.y
+ srt_data[i].b = decomp[i].z.y; // scale.x.z
+ srt_data[i].c = decomp[i].w.x; // scale.y.z
+ srt_data[i].sx = decomp[i].y.w; // scale.x.x
+ srt_data[i].sy = decomp[i].z.w; // scale.y.y
+ srt_data[i].sz = decomp[i].w.w; // scale.z.z
+ srt_data[i].pvx = 0;
+ srt_data[i].pvy = 0;
+ srt_data[i].pvz = 0;
+ // rotation
+ srt_data[i].qx = decomp[i].x.x;
+ srt_data[i].qy = decomp[i].x.y;
+ srt_data[i].qz = decomp[i].x.z;
+ srt_data[i].qw = decomp[i].x.w;
+ // transform
+ srt_data[i].tx = decomp[i].y.x;
+ srt_data[i].ty = decomp[i].y.y;
+ srt_data[i].tz = decomp[i].y.z;
+ }
+
+ // Upload motion transform to GPU
+ mem_copy_to(motion_transform_gpu);
+ delete[] reinterpret_cast<uint8_t *>(motion_transform_gpu.host_pointer);
+ motion_transform_gpu.host_pointer = 0;
+
+ // Disable instance transform if object uses motion transform already
+ instance.flags = OPTIX_INSTANCE_FLAG_DISABLE_TRANSFORM;
+
+ // Get traversable handle to motion transform
+ optixConvertPointerToTraversableHandle(context,
+ motion_transform_gpu.device_pointer,
+ OPTIX_TRAVERSABLE_TYPE_SRT_MOTION_TRANSFORM,
+ &instance.traversableHandle);
+ }
+ else {
+ instance.traversableHandle = handle;
+
+ if (ob->mesh->is_instanced()) {
+ // Set transform matrix
+ memcpy(instance.transform, &ob->tfm, sizeof(instance.transform));
+ }
+ else {
+ // Disable instance transform if mesh already has it applied to vertex data
+ instance.flags = OPTIX_INSTANCE_FLAG_DISABLE_TRANSFORM;
+ // Non-instanced objects read ID from prim_object, so
+ // distinguish them from instanced objects with high bit set
+ instance.instanceId |= 0x800000;
+ }
+ }
+ }
+ }
+
+ // Upload instance descriptions
+ aabbs.resize(num_instances);
+ aabbs.copy_to_device();
+ instances.resize(num_instances);
+ instances.copy_to_device();
+
+ // Build top-level acceleration structure
+ OptixBuildInput build_input = {};
+ build_input.type = OPTIX_BUILD_INPUT_TYPE_INSTANCES;
+ build_input.instanceArray.instances = instances.device_pointer;
+ build_input.instanceArray.numInstances = num_instances;
+ build_input.instanceArray.aabbs = aabbs.device_pointer;
+ build_input.instanceArray.numAabbs = num_instances;
+
+ return build_optix_bvh(build_input, 0 /* TLAS has no motion itself */, out_data, tlas_handle);
+ }
+
+ void update_texture_info()
+ {
+ if (need_texture_info) {
+ texture_info.copy_to_device();
+ need_texture_info = false;
+ }
+ }
+
+ void update_launch_params(const char *name, size_t offset, void *data, size_t data_size)
+ {
+ const CUDAContextScope scope(cuda_context);
+
+ for (int i = 0; i < info.cpu_threads; ++i)
+ check_result_cuda(
+ cuMemcpyHtoD(launch_params.device_pointer + i * launch_params.data_elements + offset,
+ data,
+ data_size));
+
+ // Set constant memory for CUDA module
+ // TODO(pmours): This is only used for tonemapping (see 'launch_film_convert').
+ // Could be removed by moving those functions to filter CUDA module.
+ size_t bytes = 0;
+ CUdeviceptr mem = 0;
+ check_result_cuda(cuModuleGetGlobal(&mem, &bytes, cuda_module, name));
+ assert(mem != NULL && bytes == data_size);
+ check_result_cuda(cuMemcpyHtoD(mem, data, data_size));
+ }
+
+ void mem_alloc(device_memory &mem) override
+ {
+ const CUDAContextScope scope(cuda_context);
+
+ mem.device_size = mem.memory_size();
+
+ if (mem.type == MEM_TEXTURE && mem.interpolation != INTERPOLATION_NONE) {
+ CUDAMem &cmem = cuda_mem_map[&mem]; // Lock and get associated memory information
+
+ CUDA_TEXTURE_DESC tex_desc = {};
+ tex_desc.flags = CU_TRSF_NORMALIZED_COORDINATES;
+ CUDA_RESOURCE_DESC res_desc = {};
+
+ switch (mem.extension) {
+ default:
+ assert(0);
+ case EXTENSION_REPEAT:
+ tex_desc.addressMode[0] = tex_desc.addressMode[1] = tex_desc.addressMode[2] =
+ CU_TR_ADDRESS_MODE_WRAP;
+ break;
+ case EXTENSION_EXTEND:
+ tex_desc.addressMode[0] = tex_desc.addressMode[1] = tex_desc.addressMode[2] =
+ CU_TR_ADDRESS_MODE_CLAMP;
+ break;
+ case EXTENSION_CLIP:
+ tex_desc.addressMode[0] = tex_desc.addressMode[1] = tex_desc.addressMode[2] =
+ CU_TR_ADDRESS_MODE_BORDER;
+ break;
+ }
+
+ switch (mem.interpolation) {
+ default: // Default to linear for unsupported interpolation types
+ case INTERPOLATION_LINEAR:
+ tex_desc.filterMode = CU_TR_FILTER_MODE_LINEAR;
+ break;
+ case INTERPOLATION_CLOSEST:
+ tex_desc.filterMode = CU_TR_FILTER_MODE_POINT;
+ break;
+ }
+
+ CUarray_format format;
+ switch (mem.data_type) {
+ default:
+ assert(0);
+ case TYPE_UCHAR:
+ format = CU_AD_FORMAT_UNSIGNED_INT8;
+ break;
+ case TYPE_UINT16:
+ format = CU_AD_FORMAT_UNSIGNED_INT16;
+ break;
+ case TYPE_UINT:
+ format = CU_AD_FORMAT_UNSIGNED_INT32;
+ break;
+ case TYPE_INT:
+ format = CU_AD_FORMAT_SIGNED_INT32;
+ break;
+ case TYPE_FLOAT:
+ format = CU_AD_FORMAT_FLOAT;
+ break;
+ case TYPE_HALF:
+ format = CU_AD_FORMAT_HALF;
+ break;
+ }
+
+ if (mem.data_depth > 1) { /* 3D texture using array. */
+ CUDA_ARRAY3D_DESCRIPTOR desc;
+ desc.Width = mem.data_width;
+ desc.Height = mem.data_height;
+ desc.Depth = mem.data_depth;
+ desc.Format = format;
+ desc.NumChannels = mem.data_elements;
+ desc.Flags = 0;
+
+ check_result_cuda(cuArray3DCreate(&cmem.array, &desc));
+ mem.device_pointer = (device_ptr)cmem.array;
+
+ res_desc.resType = CU_RESOURCE_TYPE_ARRAY;
+ res_desc.res.array.hArray = cmem.array;
+ }
+ else if (mem.data_height > 0) { /* 2D texture using array. */
+ CUDA_ARRAY_DESCRIPTOR desc;
+ desc.Width = mem.data_width;
+ desc.Height = mem.data_height;
+ desc.Format = format;
+ desc.NumChannels = mem.data_elements;
+
+ check_result_cuda(cuArrayCreate(&cmem.array, &desc));
+ mem.device_pointer = (device_ptr)cmem.array;
+
+ res_desc.resType = CU_RESOURCE_TYPE_ARRAY;
+ res_desc.res.array.hArray = cmem.array;
+ }
+ else {
+ check_result_cuda(cuMemAlloc((CUdeviceptr *)&mem.device_pointer, mem.device_size));
+
+ res_desc.resType = CU_RESOURCE_TYPE_LINEAR;
+ res_desc.res.linear.devPtr = (CUdeviceptr)mem.device_pointer;
+ res_desc.res.linear.format = format;
+ res_desc.res.linear.numChannels = mem.data_elements;
+ res_desc.res.linear.sizeInBytes = mem.device_size;
+ }
+
+ check_result_cuda(cuTexObjectCreate(&cmem.texobject, &res_desc, &tex_desc, NULL));
+
+ int flat_slot = 0;
+ if (string_startswith(mem.name, "__tex_image")) {
+ flat_slot = atoi(mem.name + string(mem.name).rfind("_") + 1);
+ }
+
+ if (flat_slot >= texture_info.size())
+ texture_info.resize(flat_slot + 128);
+
+ TextureInfo &info = texture_info[flat_slot];
+ info.data = (uint64_t)cmem.texobject;
+ info.cl_buffer = 0;
+ info.interpolation = mem.interpolation;
+ info.extension = mem.extension;
+ info.width = mem.data_width;
+ info.height = mem.data_height;
+ info.depth = mem.data_depth;
+
+ // Texture information has changed and needs an update, delay this to next launch
+ need_texture_info = true;
+ }
+ else {
+ // This is not a texture but simple linear memory
+ check_result_cuda(cuMemAlloc((CUdeviceptr *)&mem.device_pointer, mem.device_size));
+
+ // Update data storage pointers in launch parameters
+# define KERNEL_TEX(data_type, tex_name) \
+ if (strcmp(mem.name, #tex_name) == 0) \
+ update_launch_params( \
+ mem.name, offsetof(KernelParams, tex_name), &mem.device_pointer, sizeof(device_ptr));
+# include "kernel/kernel_textures.h"
+# undef KERNEL_TEX
+ }
+
+ stats.mem_alloc(mem.device_size);
+ }
+
+ void mem_copy_to(device_memory &mem) override
+ {
+ if (!mem.host_pointer || mem.host_pointer == mem.shared_pointer)
+ return;
+ if (!mem.device_pointer)
+ mem_alloc(mem); // Need to allocate memory first if it does not exist yet
+
+ const CUDAContextScope scope(cuda_context);
+
+ if (mem.type == MEM_TEXTURE && mem.interpolation != INTERPOLATION_NONE) {
+ const CUDAMem &cmem = cuda_mem_map[&mem]; // Lock and get associated memory information
+
+ size_t src_pitch = mem.data_width * datatype_size(mem.data_type) * mem.data_elements;
+
+ if (mem.data_depth > 1) {
+ CUDA_MEMCPY3D param;
+ memset(&param, 0, sizeof(param));
+ param.dstMemoryType = CU_MEMORYTYPE_ARRAY;
+ param.dstArray = cmem.array;
+ param.srcMemoryType = CU_MEMORYTYPE_HOST;
+ param.srcHost = mem.host_pointer;
+ param.srcPitch = src_pitch;
+ param.WidthInBytes = param.srcPitch;
+ param.Height = mem.data_height;
+ param.Depth = mem.data_depth;
+
+ check_result_cuda(cuMemcpy3D(&param));
+ }
+ else if (mem.data_height > 0) {
+ CUDA_MEMCPY2D param;
+ memset(&param, 0, sizeof(param));
+ param.dstMemoryType = CU_MEMORYTYPE_ARRAY;
+ param.dstArray = cmem.array;
+ param.srcMemoryType = CU_MEMORYTYPE_HOST;
+ param.srcHost = mem.host_pointer;
+ param.srcPitch = src_pitch;
+ param.WidthInBytes = param.srcPitch;
+ param.Height = mem.data_height;
+
+ check_result_cuda(cuMemcpy2D(&param));
+ }
+ else {
+ check_result_cuda(
+ cuMemcpyHtoD((CUdeviceptr)mem.device_pointer, mem.host_pointer, mem.device_size));
+ }
+ }
+ else {
+ // This is not a texture but simple linear memory
+ check_result_cuda(
+ cuMemcpyHtoD((CUdeviceptr)mem.device_pointer, mem.host_pointer, mem.device_size));
+ }
+ }
+
+ void mem_copy_from(device_memory &mem, int y, int w, int h, int elem) override
+ {
+ // Calculate linear memory offset and size
+ const size_t size = elem * w * h;
+ const size_t offset = elem * y * w;
+
+ if (mem.host_pointer && mem.device_pointer) {
+ const CUDAContextScope scope(cuda_context);
+ check_result_cuda(cuMemcpyDtoH(
+ (char *)mem.host_pointer + offset, (CUdeviceptr)mem.device_pointer + offset, size));
+ }
+ else if (mem.host_pointer) {
+ memset((char *)mem.host_pointer + offset, 0, size);
+ }
+ }
+
+ void mem_zero(device_memory &mem) override
+ {
+ if (mem.host_pointer)
+ memset(mem.host_pointer, 0, mem.memory_size());
+ if (mem.host_pointer && mem.host_pointer == mem.shared_pointer)
+ return; // This is shared host memory, so no device memory to update
+
+ if (!mem.device_pointer)
+ mem_alloc(mem); // Need to allocate memory first if it does not exist yet
+
+ const CUDAContextScope scope(cuda_context);
+ check_result_cuda(cuMemsetD8((CUdeviceptr)mem.device_pointer, 0, mem.memory_size()));
+ }
+
+ void mem_free(device_memory &mem) override
+ {
+ assert(mem.device_pointer);
+
+ const CUDAContextScope scope(cuda_context);
+
+ if (mem.type == MEM_TEXTURE && mem.interpolation != INTERPOLATION_NONE) {
+ CUDAMem &cmem = cuda_mem_map[&mem]; // Lock and get associated memory information
+
+ if (cmem.array)
+ cuArrayDestroy(cmem.array);
+ else
+ cuMemFree((CUdeviceptr)mem.device_pointer);
+
+ if (cmem.texobject)
+ cuTexObjectDestroy(cmem.texobject);
+ }
+ else {
+ // This is not a texture but simple linear memory
+ cuMemFree((CUdeviceptr)mem.device_pointer);
+ }
+
+ stats.mem_free(mem.device_size);
+
+ mem.device_size = 0;
+ mem.device_pointer = 0;
+ }
+
+ void const_copy_to(const char *name, void *host, size_t size) override
+ {
+ if (strcmp(name, "__data") == 0) {
+ assert(size <= sizeof(KernelData));
+
+ // Fix traversable handle on multi devices
+ KernelData *const data = (KernelData *)host;
+ *(OptixTraversableHandle *)&data->bvh.scene = tlas_handle;
+
+ update_launch_params(name, offsetof(KernelParams, data), host, size);
+ }
+ }
+
+ device_ptr mem_alloc_sub_ptr(device_memory &mem, int offset, int /*size*/) override
+ {
+ return (device_ptr)(((char *)mem.device_pointer) + mem.memory_elements_size(offset));
+ }
+
+ void task_add(DeviceTask &task) override
+ {
+ // Upload texture information to device if it has changed since last launch
+ update_texture_info();
+
+ // Split task into smaller ones
+ list<DeviceTask> tasks;
+ task.split(tasks, info.cpu_threads);
+
+ // Queue tasks in internal task pool
+ struct OptiXDeviceTask : public DeviceTask {
+ OptiXDeviceTask(OptiXDevice *device, DeviceTask &task, int task_index) : DeviceTask(task)
+ {
+ // Using task index parameter instead of thread index, since number of CUDA streams may
+ // differ from number of threads
+ run = function_bind(&OptiXDevice::thread_run, device, *this, task_index);
+ }
+ };
+
+ int task_index = 0;
+ for (DeviceTask &task : tasks)
+ task_pool.push(new OptiXDeviceTask(this, task, task_index++));
+ }
+
+ void task_wait() override
+ {
+ // Wait for all queued tasks to finish
+ task_pool.wait_work();
+ }
+
+ void task_cancel() override
+ {
+ // Cancel any remaining tasks in the internal pool
+ task_pool.cancel();
+ }
+
+# define CUDA_GET_BLOCKSIZE(func, w, h) \
+ int threads; \
+ check_result_cuda_ret( \
+ cuFuncGetAttribute(&threads, CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, func)); \
+ threads = (int)sqrt((float)threads); \
+ int xblocks = ((w) + threads - 1) / threads; \
+ int yblocks = ((h) + threads - 1) / threads;
+
+# define CUDA_LAUNCH_KERNEL(func, args) \
+ check_result_cuda_ret(cuLaunchKernel( \
+ func, xblocks, yblocks, 1, threads, threads, 1, 0, cuda_stream[thread_index], args, 0));
+
+ /* Similar as above, but for 1-dimensional blocks. */
+# define CUDA_GET_BLOCKSIZE_1D(func, w, h) \
+ int threads; \
+ check_result_cuda_ret( \
+ cuFuncGetAttribute(&threads, CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, func)); \
+ int xblocks = ((w) + threads - 1) / threads; \
+ int yblocks = h;
+
+# define CUDA_LAUNCH_KERNEL_1D(func, args) \
+ check_result_cuda_ret(cuLaunchKernel( \
+ func, xblocks, yblocks, 1, threads, 1, 1, 0, cuda_stream[thread_index], args, 0));
+
+ bool denoising_non_local_means(device_ptr image_ptr,
+ device_ptr guide_ptr,
+ device_ptr variance_ptr,
+ device_ptr out_ptr,
+ DenoisingTask *task,
+ int thread_index)
+ {
+ if (have_error())
+ return false;
+
+ int stride = task->buffer.stride;
+ int w = task->buffer.width;
+ int h = task->buffer.h;
+ int r = task->nlm_state.r;
+ int f = task->nlm_state.f;
+ float a = task->nlm_state.a;
+ float k_2 = task->nlm_state.k_2;
+
+ int pass_stride = task->buffer.pass_stride;
+ int num_shifts = (2 * r + 1) * (2 * r + 1);
+ int channel_offset = task->nlm_state.is_color ? task->buffer.pass_stride : 0;
+ int frame_offset = 0;
+
+ CUdeviceptr difference = (CUdeviceptr)task->buffer.temporary_mem.device_pointer;
+ CUdeviceptr blurDifference = difference + sizeof(float) * pass_stride * num_shifts;
+ CUdeviceptr weightAccum = difference + 2 * sizeof(float) * pass_stride * num_shifts;
+ CUdeviceptr scale_ptr = 0;
+
+ check_result_cuda_ret(
+ cuMemsetD8Async(weightAccum, 0, sizeof(float) * pass_stride, cuda_stream[thread_index]));
+ check_result_cuda_ret(
+ cuMemsetD8Async(out_ptr, 0, sizeof(float) * pass_stride, cuda_stream[thread_index]));
+
+ {
+ CUfunction cuNLMCalcDifference, cuNLMBlur, cuNLMCalcWeight, cuNLMUpdateOutput;
+ check_result_cuda_ret(cuModuleGetFunction(
+ &cuNLMCalcDifference, cuda_filter_module, "kernel_cuda_filter_nlm_calc_difference"));
+ check_result_cuda_ret(
+ cuModuleGetFunction(&cuNLMBlur, cuda_filter_module, "kernel_cuda_filter_nlm_blur"));
+ check_result_cuda_ret(cuModuleGetFunction(
+ &cuNLMCalcWeight, cuda_filter_module, "kernel_cuda_filter_nlm_calc_weight"));
+ check_result_cuda_ret(cuModuleGetFunction(
+ &cuNLMUpdateOutput, cuda_filter_module, "kernel_cuda_filter_nlm_update_output"));
+
+ check_result_cuda_ret(cuFuncSetCacheConfig(cuNLMCalcDifference, CU_FUNC_CACHE_PREFER_L1));
+ check_result_cuda_ret(cuFuncSetCacheConfig(cuNLMBlur, CU_FUNC_CACHE_PREFER_L1));
+ check_result_cuda_ret(cuFuncSetCacheConfig(cuNLMCalcWeight, CU_FUNC_CACHE_PREFER_L1));
+ check_result_cuda_ret(cuFuncSetCacheConfig(cuNLMUpdateOutput, CU_FUNC_CACHE_PREFER_L1));
+
+ CUDA_GET_BLOCKSIZE_1D(cuNLMCalcDifference, w * h, num_shifts);
+
+ void *calc_difference_args[] = {&guide_ptr,
+ &variance_ptr,
+ &scale_ptr,
+ &difference,
+ &w,
+ &h,
+ &stride,
+ &pass_stride,
+ &r,
+ &channel_offset,
+ &frame_offset,
+ &a,
+ &k_2};
+ void *blur_args[] = {&difference, &blurDifference, &w, &h, &stride, &pass_stride, &r, &f};
+ void *calc_weight_args[] = {
+ &blurDifference, &difference, &w, &h, &stride, &pass_stride, &r, &f};
+ void *update_output_args[] = {&blurDifference,
+ &image_ptr,
+ &out_ptr,
+ &weightAccum,
+ &w,
+ &h,
+ &stride,
+ &pass_stride,
+ &channel_offset,
+ &r,
+ &f};
+
+ CUDA_LAUNCH_KERNEL_1D(cuNLMCalcDifference, calc_difference_args);
+ CUDA_LAUNCH_KERNEL_1D(cuNLMBlur, blur_args);
+ CUDA_LAUNCH_KERNEL_1D(cuNLMCalcWeight, calc_weight_args);
+ CUDA_LAUNCH_KERNEL_1D(cuNLMBlur, blur_args);
+ CUDA_LAUNCH_KERNEL_1D(cuNLMUpdateOutput, update_output_args);
+ }
+
+ {
+ CUfunction cuNLMNormalize;
+ check_result_cuda_ret(cuModuleGetFunction(
+ &cuNLMNormalize, cuda_filter_module, "kernel_cuda_filter_nlm_normalize"));
+ check_result_cuda_ret(cuFuncSetCacheConfig(cuNLMNormalize, CU_FUNC_CACHE_PREFER_L1));
+ void *normalize_args[] = {&out_ptr, &weightAccum, &w, &h, &stride};
+ CUDA_GET_BLOCKSIZE(cuNLMNormalize, w, h);
+ CUDA_LAUNCH_KERNEL(cuNLMNormalize, normalize_args);
+ check_result_cuda_ret(cuStreamSynchronize(cuda_stream[thread_index]));
+ }
+
+ return !have_error();
+ }
+
+ bool denoising_construct_transform(DenoisingTask *task, int thread_index)
+ {
+ if (have_error())
+ return false;
+
+ CUfunction cuFilterConstructTransform;
+ check_result_cuda_ret(cuModuleGetFunction(&cuFilterConstructTransform,
+ cuda_filter_module,
+ "kernel_cuda_filter_construct_transform"));
+ check_result_cuda_ret(
+ cuFuncSetCacheConfig(cuFilterConstructTransform, CU_FUNC_CACHE_PREFER_SHARED));
+ CUDA_GET_BLOCKSIZE(cuFilterConstructTransform, task->storage.w, task->storage.h);
+
+ void *args[] = {&task->buffer.mem.device_pointer,
+ &task->tile_info_mem.device_pointer,
+ &task->storage.transform.device_pointer,
+ &task->storage.rank.device_pointer,
+ &task->filter_area,
+ &task->rect,
+ &task->radius,
+ &task->pca_threshold,
+ &task->buffer.pass_stride,
+ &task->buffer.frame_stride,
+ &task->buffer.use_time};
+ CUDA_LAUNCH_KERNEL(cuFilterConstructTransform, args);
+ check_result_cuda_ret(cuCtxSynchronize());
+
+ return !have_error();
+ }
+
+ bool denoising_accumulate(device_ptr color_ptr,
+ device_ptr color_variance_ptr,
+ device_ptr scale_ptr,
+ int frame,
+ DenoisingTask *task,
+ int thread_index)
+ {
+ if (have_error())
+ return false;
+
+ int r = task->radius;
+ int f = 4;
+ float a = 1.0f;
+ float k_2 = task->nlm_k_2;
+
+ int w = task->reconstruction_state.source_w;
+ int h = task->reconstruction_state.source_h;
+ int stride = task->buffer.stride;
+ int frame_offset = frame * task->buffer.frame_stride;
+ int t = task->tile_info->frames[frame];
+
+ int pass_stride = task->buffer.pass_stride;
+ int num_shifts = (2 * r + 1) * (2 * r + 1);
+
+ CUdeviceptr difference = (CUdeviceptr)task->buffer.temporary_mem.device_pointer;
+ CUdeviceptr blurDifference = difference + sizeof(float) * pass_stride * num_shifts;
+
+ CUfunction cuNLMCalcDifference, cuNLMBlur, cuNLMCalcWeight, cuNLMConstructGramian;
+ check_result_cuda_ret(cuModuleGetFunction(
+ &cuNLMCalcDifference, cuda_filter_module, "kernel_cuda_filter_nlm_calc_difference"));
+ check_result_cuda_ret(
+ cuModuleGetFunction(&cuNLMBlur, cuda_filter_module, "kernel_cuda_filter_nlm_blur"));
+ check_result_cuda_ret(cuModuleGetFunction(
+ &cuNLMCalcWeight, cuda_filter_module, "kernel_cuda_filter_nlm_calc_weight"));
+ check_result_cuda_ret(cuModuleGetFunction(
+ &cuNLMConstructGramian, cuda_filter_module, "kernel_cuda_filter_nlm_construct_gramian"));
+
+ check_result_cuda_ret(cuFuncSetCacheConfig(cuNLMCalcDifference, CU_FUNC_CACHE_PREFER_L1));
+ check_result_cuda_ret(cuFuncSetCacheConfig(cuNLMBlur, CU_FUNC_CACHE_PREFER_L1));
+ check_result_cuda_ret(cuFuncSetCacheConfig(cuNLMCalcWeight, CU_FUNC_CACHE_PREFER_L1));
+ check_result_cuda_ret(
+ cuFuncSetCacheConfig(cuNLMConstructGramian, CU_FUNC_CACHE_PREFER_SHARED));
+
+ CUDA_GET_BLOCKSIZE_1D(cuNLMCalcDifference,
+ task->reconstruction_state.source_w *
+ task->reconstruction_state.source_h,
+ num_shifts);
+
+ void *calc_difference_args[] = {&color_ptr,
+ &color_variance_ptr,
+ &scale_ptr,
+ &difference,
+ &w,
+ &h,
+ &stride,
+ &pass_stride,
+ &r,
+ &pass_stride,
+ &frame_offset,
+ &a,
+ &k_2};
+ void *blur_args[] = {&difference, &blurDifference, &w, &h, &stride, &pass_stride, &r, &f};
+ void *calc_weight_args[] = {
+ &blurDifference, &difference, &w, &h, &stride, &pass_stride, &r, &f};
+ void *construct_gramian_args[] = {&t,
+ &blurDifference,
+ &task->buffer.mem.device_pointer,
+ &task->storage.transform.device_pointer,
+ &task->storage.rank.device_pointer,
+ &task->storage.XtWX.device_pointer,
+ &task->storage.XtWY.device_pointer,
+ &task->reconstruction_state.filter_window,
+ &w,
+ &h,
+ &stride,
+ &pass_stride,
+ &r,
+ &f,
+ &frame_offset,
+ &task->buffer.use_time};
+
+ CUDA_LAUNCH_KERNEL_1D(cuNLMCalcDifference, calc_difference_args);
+ CUDA_LAUNCH_KERNEL_1D(cuNLMBlur, blur_args);
+ CUDA_LAUNCH_KERNEL_1D(cuNLMCalcWeight, calc_weight_args);
+ CUDA_LAUNCH_KERNEL_1D(cuNLMBlur, blur_args);
+ CUDA_LAUNCH_KERNEL_1D(cuNLMConstructGramian, construct_gramian_args);
+ check_result_cuda_ret(cuCtxSynchronize());
+
+ return !have_error();
+ }
+
+ bool denoising_solve(device_ptr output_ptr, DenoisingTask *task, int thread_index)
+ {
+ if (have_error())
+ return false;
+
+ CUfunction cuFinalize;
+ check_result_cuda_ret(
+ cuModuleGetFunction(&cuFinalize, cuda_filter_module, "kernel_cuda_filter_finalize"));
+ check_result_cuda_ret(cuFuncSetCacheConfig(cuFinalize, CU_FUNC_CACHE_PREFER_L1));
+ void *finalize_args[] = {&output_ptr,
+ &task->storage.rank.device_pointer,
+ &task->storage.XtWX.device_pointer,
+ &task->storage.XtWY.device_pointer,
+ &task->filter_area,
+ &task->reconstruction_state.buffer_params.x,
+ &task->render_buffer.samples};
+ CUDA_GET_BLOCKSIZE(
+ cuFinalize, task->reconstruction_state.source_w, task->reconstruction_state.source_h);
+ CUDA_LAUNCH_KERNEL(cuFinalize, finalize_args);
+ check_result_cuda_ret(cuStreamSynchronize(cuda_stream[thread_index]));
+
+ return !have_error();
+ }
+
+ bool denoising_combine_halves(device_ptr a_ptr,
+ device_ptr b_ptr,
+ device_ptr mean_ptr,
+ device_ptr variance_ptr,
+ int r,
+ int4 rect,
+ DenoisingTask *task,
+ int thread_index)
+ {
+ if (have_error())
+ return false;
+
+ CUfunction cuFilterCombineHalves;
+ check_result_cuda_ret(cuModuleGetFunction(
+ &cuFilterCombineHalves, cuda_filter_module, "kernel_cuda_filter_combine_halves"));
+ check_result_cuda_ret(cuFuncSetCacheConfig(cuFilterCombineHalves, CU_FUNC_CACHE_PREFER_L1));
+ CUDA_GET_BLOCKSIZE(
+ cuFilterCombineHalves, task->rect.z - task->rect.x, task->rect.w - task->rect.y);
+
+ void *args[] = {&mean_ptr, &variance_ptr, &a_ptr, &b_ptr, &rect, &r};
+ CUDA_LAUNCH_KERNEL(cuFilterCombineHalves, args);
+ check_result_cuda_ret(cuStreamSynchronize(cuda_stream[thread_index]));
+
+ return !have_error();
+ }
+
+ bool denoising_divide_shadow(device_ptr a_ptr,
+ device_ptr b_ptr,
+ device_ptr sample_variance_ptr,
+ device_ptr sv_variance_ptr,
+ device_ptr buffer_variance_ptr,
+ DenoisingTask *task,
+ int thread_index)
+ {
+ if (have_error())
+ return false;
+
+ CUfunction cuFilterDivideShadow;
+ check_result_cuda_ret(cuModuleGetFunction(
+ &cuFilterDivideShadow, cuda_filter_module, "kernel_cuda_filter_divide_shadow"));
+ check_result_cuda_ret(cuFuncSetCacheConfig(cuFilterDivideShadow, CU_FUNC_CACHE_PREFER_L1));
+ CUDA_GET_BLOCKSIZE(
+ cuFilterDivideShadow, task->rect.z - task->rect.x, task->rect.w - task->rect.y);
+
+ void *args[] = {&task->render_buffer.samples,
+ &task->tile_info_mem.device_pointer,
+ &a_ptr,
+ &b_ptr,
+ &sample_variance_ptr,
+ &sv_variance_ptr,
+ &buffer_variance_ptr,
+ &task->rect,
+ &task->render_buffer.pass_stride,
+ &task->render_buffer.offset};
+ CUDA_LAUNCH_KERNEL(cuFilterDivideShadow, args);
+ check_result_cuda_ret(cuStreamSynchronize(cuda_stream[thread_index]));
+
+ return !have_error();
+ }
+
+ bool denoising_get_feature(int mean_offset,
+ int variance_offset,
+ device_ptr mean_ptr,
+ device_ptr variance_ptr,
+ float scale,
+ DenoisingTask *task,
+ int thread_index)
+ {
+ if (have_error())
+ return false;
+
+ CUfunction cuFilterGetFeature;
+ check_result_cuda_ret(cuModuleGetFunction(
+ &cuFilterGetFeature, cuda_filter_module, "kernel_cuda_filter_get_feature"));
+ check_result_cuda_ret(cuFuncSetCacheConfig(cuFilterGetFeature, CU_FUNC_CACHE_PREFER_L1));
+ CUDA_GET_BLOCKSIZE(
+ cuFilterGetFeature, task->rect.z - task->rect.x, task->rect.w - task->rect.y);
+
+ void *args[] = {&task->render_buffer.samples,
+ &task->tile_info_mem.device_pointer,
+ &mean_offset,
+ &variance_offset,
+ &mean_ptr,
+ &variance_ptr,
+ &scale,
+ &task->rect,
+ &task->render_buffer.pass_stride,
+ &task->render_buffer.offset};
+ CUDA_LAUNCH_KERNEL(cuFilterGetFeature, args);
+ check_result_cuda_ret(cuStreamSynchronize(cuda_stream[thread_index]));
+
+ return !have_error();
+ }
+
+ bool denoising_write_feature(int out_offset,
+ device_ptr from_ptr,
+ device_ptr buffer_ptr,
+ DenoisingTask *task,
+ int thread_index)
+ {
+ if (have_error())
+ return false;
+
+ CUfunction cuFilterWriteFeature;
+ check_result_cuda_ret(cuModuleGetFunction(
+ &cuFilterWriteFeature, cuda_filter_module, "kernel_cuda_filter_write_feature"));
+ check_result_cuda_ret(cuFuncSetCacheConfig(cuFilterWriteFeature, CU_FUNC_CACHE_PREFER_L1));
+ CUDA_GET_BLOCKSIZE(cuFilterWriteFeature, task->filter_area.z, task->filter_area.w);
+
+ void *args[] = {&task->render_buffer.samples,
+ &task->reconstruction_state.buffer_params,
+ &task->filter_area,
+ &from_ptr,
+ &buffer_ptr,
+ &out_offset,
+ &task->rect};
+ CUDA_LAUNCH_KERNEL(cuFilterWriteFeature, args);
+ check_result_cuda_ret(cuStreamSynchronize(cuda_stream[thread_index]));
+
+ return !have_error();
+ }
+
+ bool denoising_detect_outliers(device_ptr image_ptr,
+ device_ptr variance_ptr,
+ device_ptr depth_ptr,
+ device_ptr output_ptr,
+ DenoisingTask *task,
+ int thread_index)
+ {
+ if (have_error())
+ return false;
+
+ CUfunction cuFilterDetectOutliers;
+ check_result_cuda_ret(cuModuleGetFunction(
+ &cuFilterDetectOutliers, cuda_filter_module, "kernel_cuda_filter_detect_outliers"));
+ check_result_cuda_ret(cuFuncSetCacheConfig(cuFilterDetectOutliers, CU_FUNC_CACHE_PREFER_L1));
+ CUDA_GET_BLOCKSIZE(
+ cuFilterDetectOutliers, task->rect.z - task->rect.x, task->rect.w - task->rect.y);
+
+ void *args[] = {&image_ptr,
+ &variance_ptr,
+ &depth_ptr,
+ &output_ptr,
+ &task->rect,
+ &task->buffer.pass_stride};
+
+ CUDA_LAUNCH_KERNEL(cuFilterDetectOutliers, args);
+ check_result_cuda_ret(cuStreamSynchronize(cuda_stream[thread_index]));
+
+ return !have_error();
+ }
+};
+
+bool device_optix_init()
+{
+ if (g_optixFunctionTable.optixDeviceContextCreate != NULL)
+ return true; // Already initialized function table
+
+ // Need to initialize CUDA as well
+ if (!device_cuda_init())
+ return false;
+
+# ifdef WITH_CUDA_DYNLOAD
+ // Load NVRTC function pointers for adaptive kernel compilation
+ if (DebugFlags().cuda.adaptive_compile && cuewInit(CUEW_INIT_NVRTC) != CUEW_SUCCESS) {
+ VLOG(1)
+ << "CUEW initialization failed for NVRTC. Adaptive kernel compilation won't be available.";
+ }
+# endif
+
+ const OptixResult result = optixInit();
+
+ if (result == OPTIX_ERROR_UNSUPPORTED_ABI_VERSION) {
+ VLOG(1)
+ << "OptiX initialization failed because the installed driver does not support ABI version "
+ << OPTIX_ABI_VERSION;
+ return false;
+ }
+ else if (result != OPTIX_SUCCESS) {
+ VLOG(1) << "OptiX initialization failed with error code " << (unsigned int)result;
+ return false;
+ }
+
+ // Loaded OptiX successfully!
+ return true;
+}
+
+void device_optix_info(vector<DeviceInfo> &devices)
+{
+ // Simply add all supported CUDA devices as OptiX devices again
+ vector<DeviceInfo> cuda_devices;
+ device_cuda_info(cuda_devices);
+
+ for (auto it = cuda_devices.begin(); it != cuda_devices.end();) {
+ DeviceInfo &info = *it;
+ assert(info.type == DEVICE_CUDA);
+ info.type = DEVICE_OPTIX;
+ info.id += "_OptiX";
+
+ // Figure out RTX support
+ CUdevice cuda_device = 0;
+ CUcontext cuda_context = NULL;
+ unsigned int rtcore_version = 0;
+ if (cuDeviceGet(&cuda_device, info.num) == CUDA_SUCCESS &&
+ cuDevicePrimaryCtxRetain(&cuda_context, cuda_device) == CUDA_SUCCESS) {
+ OptixDeviceContext optix_context = NULL;
+ if (optixDeviceContextCreate(cuda_context, nullptr, &optix_context) == OPTIX_SUCCESS) {
+ optixDeviceContextGetProperty(optix_context,
+ OPTIX_DEVICE_PROPERTY_RTCORE_VERSION,
+ &rtcore_version,
+ sizeof(rtcore_version));
+ optixDeviceContextDestroy(optix_context);
+ }
+ cuDevicePrimaryCtxRelease(cuda_device);
+ }
+
+ // Only add devices with RTX support
+ if (rtcore_version == 0)
+ it = cuda_devices.erase(it);
+ else
+ ++it;
+ }
+
+ devices.insert(devices.end(), cuda_devices.begin(), cuda_devices.end());
+}
+
+Device *device_optix_create(DeviceInfo &info, Stats &stats, Profiler &profiler, bool background)
+{
+ return new OptiXDevice(info, stats, profiler, background);
+}
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/device/opencl/opencl_split.cpp b/intern/cycles/device/opencl/opencl_split.cpp
index 79474fb0814..eea5cf2fb8a 100644
--- a/intern/cycles/device/opencl/opencl_split.cpp
+++ b/intern/cycles/device/opencl/opencl_split.cpp
@@ -676,7 +676,7 @@ OpenCLDevice::OpenCLDevice(DeviceInfo &info, Stats &stats, Profiler &profiler, b
device_initialized = true;
split_kernel = new OpenCLSplitKernel(this);
- if (!background) {
+ if (use_preview_kernels) {
load_preview_kernels();
}
}
diff --git a/intern/cycles/device/opencl/opencl_util.cpp b/intern/cycles/device/opencl/opencl_util.cpp
index dc9b4072841..3eeff31f8c2 100644
--- a/intern/cycles/device/opencl/opencl_util.cpp
+++ b/intern/cycles/device/opencl/opencl_util.cpp
@@ -619,15 +619,16 @@ void OpenCLDevice::OpenCLProgram::compile()
debug_src = &clsrc;
}
- /* If binary kernel exists already, try use it. */
- if (compile_separate(clbin)) {
+ if (DebugFlags().running_inside_blender && compile_separate(clbin)) {
add_log(string("Built and loaded program from ") + clbin + ".", true);
loaded = true;
}
else {
- add_log(string("Separate-process building of ") + clbin +
- " failed, will fall back to regular building.",
- true);
+ if (DebugFlags().running_inside_blender) {
+ add_log(string("Separate-process building of ") + clbin +
+ " failed, will fall back to regular building.",
+ true);
+ }
/* If does not exist or loading binary failed, compile kernel. */
if (!compile_kernel(debug_src)) {
diff --git a/intern/cycles/graph/node.h b/intern/cycles/graph/node.h
index 226c49b387a..d35a1bb489c 100644
--- a/intern/cycles/graph/node.h
+++ b/intern/cycles/graph/node.h
@@ -33,7 +33,7 @@ struct Transform;
struct Node {
explicit Node(const NodeType *type, ustring name = ustring());
- virtual ~Node();
+ virtual ~Node() = 0;
/* set values */
void set(const SocketType &input, bool value);
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index 48439a8b68f..ea8aa197b6f 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -64,6 +64,10 @@ set(SRC_OPENCL_KERNELS
kernels/opencl/filter.cl
)
+set(SRC_OPTIX_KERNELS
+ kernels/optix/kernel_optix.cu
+)
+
set(SRC_BVH_HEADERS
bvh/bvh.h
bvh/bvh_nodes.h
@@ -95,6 +99,7 @@ set(SRC_HEADERS
kernel_color.h
kernel_compat_cpu.h
kernel_compat_cuda.h
+ kernel_compat_optix.h
kernel_compat_opencl.h
kernel_differential.h
kernel_emission.h
@@ -140,6 +145,9 @@ set(SRC_KERNELS_CUDA_HEADERS
kernels/cuda/kernel_cuda_image.h
)
+set(SRC_KERNELS_OPTIX_HEADERS
+)
+
set(SRC_KERNELS_OPENCL_HEADERS
kernels/opencl/kernel_split_function.h
kernels/opencl/kernel_opencl_image.h
@@ -168,7 +176,7 @@ set(SRC_CLOSURE_HEADERS
closure/volume.h
closure/bsdf_principled_diffuse.h
closure/bsdf_principled_sheen.h
- closure/bsdf_hair_principled.h
+ closure/bsdf_hair_principled.h
)
set(SRC_SVM_HEADERS
@@ -201,6 +209,7 @@ set(SRC_SVM_HEADERS
svm/svm_magic.h
svm/svm_map_range.h
svm/svm_mapping.h
+ svm/svm_mapping_util.h
svm/svm_math.h
svm/svm_math_util.h
svm/svm_mix.h
@@ -214,7 +223,7 @@ set(SRC_SVM_HEADERS
svm/svm_sepcomb_vector.h
svm/svm_sky.h
svm/svm_tex_coord.h
- svm/svm_texture.h
+ svm/svm_fractal_noise.h
svm/svm_types.h
svm/svm_value.h
svm/svm_vector_transform.h
@@ -222,6 +231,7 @@ set(SRC_SVM_HEADERS
svm/svm_voxel.h
svm/svm_wave.h
svm/svm_white_noise.h
+ svm/svm_vertex_color.h
)
set(SRC_GEOM_HEADERS
@@ -474,6 +484,53 @@ if(WITH_CYCLES_CUDA_BINARIES)
cycles_set_solution_folder(cycles_kernel_cuda)
endif()
+# OptiX PTX modules
+
+if(WITH_CYCLES_DEVICE_OPTIX)
+ foreach(input ${SRC_OPTIX_KERNELS})
+ get_filename_component(input_we ${input} NAME_WE)
+
+ set(output "${CMAKE_CURRENT_BINARY_DIR}/${input_we}.ptx")
+ set(cuda_flags
+ -I "${OPTIX_INCLUDE_DIR}"
+ -I "${CMAKE_CURRENT_SOURCE_DIR}/.."
+ -I "${CMAKE_CURRENT_SOURCE_DIR}/kernels/cuda"
+ -arch=sm_30
+ --use_fast_math
+ -o ${output})
+
+ if(WITH_CYCLES_DEBUG)
+ set(cuda_flags ${cuda_flags}
+ -D __KERNEL_DEBUG__)
+ endif()
+
+ add_custom_command(
+ OUTPUT
+ ${output}
+ DEPENDS
+ ${input}
+ ${SRC_HEADERS}
+ ${SRC_KERNELS_CUDA_HEADERS}
+ ${SRC_KERNELS_OPTIX_HEADERS}
+ ${SRC_BVH_HEADERS}
+ ${SRC_SVM_HEADERS}
+ ${SRC_GEOM_HEADERS}
+ ${SRC_CLOSURE_HEADERS}
+ ${SRC_UTIL_HEADERS}
+ COMMAND
+ ${CUDA_NVCC_EXECUTABLE} --ptx ${cuda_flags} ${input}
+ WORKING_DIRECTORY
+ "${CMAKE_CURRENT_SOURCE_DIR}")
+
+ list(APPEND optix_ptx ${output})
+
+ delayed_install("${CMAKE_CURRENT_BINARY_DIR}" "${output}" ${CYCLES_INSTALL_PATH}/lib)
+ endforeach()
+
+ add_custom_target(cycles_kernel_optix ALL DEPENDS ${optix_ptx})
+ cycles_set_solution_folder(cycles_kernel_optix)
+endif()
+
# OSL module
if(WITH_CYCLES_OSL)
@@ -533,10 +590,12 @@ endif()
cycles_add_library(cycles_kernel "${LIB}"
${SRC_CPU_KERNELS}
${SRC_CUDA_KERNELS}
+ ${SRC_OPTIX_KERNELS}
${SRC_OPENCL_KERNELS}
${SRC_HEADERS}
${SRC_KERNELS_CPU_HEADERS}
${SRC_KERNELS_CUDA_HEADERS}
+ ${SRC_KERNELS_OPTIX_HEADERS}
${SRC_KERNELS_OPENCL_HEADERS}
${SRC_BVH_HEADERS}
${SRC_CLOSURE_HEADERS}
@@ -546,9 +605,24 @@ cycles_add_library(cycles_kernel "${LIB}"
${SRC_SPLIT_HEADERS}
)
+source_group("bvh" FILES ${SRC_BVH_HEADERS})
+source_group("closure" FILES ${SRC_CLOSURE_HEADERS})
+source_group("filter" FILES ${SRC_FILTER_HEADERS})
+source_group("geom" FILES ${SRC_GEOM_HEADERS})
+source_group("kernel" FILES ${SRC_HEADERS})
+source_group("kernel\\split" FILES ${SRC_SPLIT_HEADERS})
+source_group("kernels\\cpu" FILES ${SRC_CPU_KERNELS} ${SRC_KERNELS_CPU_HEADERS})
+source_group("kernels\\cuda" FILES ${SRC_CUDA_KERNELS} ${SRC_KERNELS_CUDA_HEADERS})
+source_group("kernels\\opencl" FILES ${SRC_OPENCL_KERNELS} ${SRC_KERNELS_OPENCL_HEADERS})
+source_group("kernels\\optix" FILES ${SRC_OPTIX_KERNELS} ${SRC_KERNELS_OPTIX_HEADERS})
+source_group("svm" FILES ${SRC_SVM_HEADERS})
+
if(WITH_CYCLES_CUDA)
add_dependencies(cycles_kernel cycles_kernel_cuda)
endif()
+if(WITH_CYCLES_DEVICE_OPTIX)
+ add_dependencies(cycles_kernel cycles_kernel_optix)
+endif()
# OpenCL kernel
@@ -562,9 +636,11 @@ endif()
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_OPENCL_KERNELS}" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_CUDA_KERNELS}" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/cuda)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_OPTIX_KERNELS}" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/optix)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNELS_OPENCL_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNELS_CUDA_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/cuda)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNELS_OPTIX_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/optix)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_BVH_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/bvh)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_CLOSURE_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/closure)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_FILTER_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/filter)
diff --git a/intern/cycles/kernel/bvh/bvh.h b/intern/cycles/kernel/bvh/bvh.h
index 162b2fb5cdb..0346f5e09e7 100644
--- a/intern/cycles/kernel/bvh/bvh.h
+++ b/intern/cycles/kernel/bvh/bvh.h
@@ -33,136 +33,140 @@ CCL_NAMESPACE_BEGIN
#include "kernel/bvh/bvh_types.h"
+#ifndef __KERNEL_OPTIX__
+
/* Common QBVH functions. */
-#ifdef __QBVH__
-# include "kernel/bvh/qbvh_nodes.h"
-# ifdef __KERNEL_AVX2__
-# include "kernel/bvh/obvh_nodes.h"
+# ifdef __QBVH__
+# include "kernel/bvh/qbvh_nodes.h"
+# ifdef __KERNEL_AVX2__
+# include "kernel/bvh/obvh_nodes.h"
+# endif
# endif
-#endif
/* Regular BVH traversal */
-#include "kernel/bvh/bvh_nodes.h"
-
-#define BVH_FUNCTION_NAME bvh_intersect
-#define BVH_FUNCTION_FEATURES 0
-#include "kernel/bvh/bvh_traversal.h"
+# include "kernel/bvh/bvh_nodes.h"
-#if defined(__INSTANCING__)
-# define BVH_FUNCTION_NAME bvh_intersect_instancing
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING
+# define BVH_FUNCTION_NAME bvh_intersect
+# define BVH_FUNCTION_FEATURES 0
# include "kernel/bvh/bvh_traversal.h"
-#endif
-#if defined(__HAIR__)
-# define BVH_FUNCTION_NAME bvh_intersect_hair
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING | BVH_HAIR
-# include "kernel/bvh/bvh_traversal.h"
-#endif
+# if defined(__INSTANCING__)
+# define BVH_FUNCTION_NAME bvh_intersect_instancing
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING
+# include "kernel/bvh/bvh_traversal.h"
+# endif
-#if defined(__OBJECT_MOTION__)
-# define BVH_FUNCTION_NAME bvh_intersect_motion
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING | BVH_MOTION
-# include "kernel/bvh/bvh_traversal.h"
-#endif
+# if defined(__HAIR__)
+# define BVH_FUNCTION_NAME bvh_intersect_hair
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING | BVH_HAIR
+# include "kernel/bvh/bvh_traversal.h"
+# endif
-#if defined(__HAIR__) && defined(__OBJECT_MOTION__)
-# define BVH_FUNCTION_NAME bvh_intersect_hair_motion
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING | BVH_HAIR | BVH_MOTION
-# include "kernel/bvh/bvh_traversal.h"
-#endif
+# if defined(__OBJECT_MOTION__)
+# define BVH_FUNCTION_NAME bvh_intersect_motion
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING | BVH_MOTION
+# include "kernel/bvh/bvh_traversal.h"
+# endif
-/* Subsurface scattering BVH traversal */
+# if defined(__HAIR__) && defined(__OBJECT_MOTION__)
+# define BVH_FUNCTION_NAME bvh_intersect_hair_motion
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING | BVH_HAIR | BVH_MOTION
+# include "kernel/bvh/bvh_traversal.h"
+# endif
-#if defined(__BVH_LOCAL__)
-# define BVH_FUNCTION_NAME bvh_intersect_local
-# define BVH_FUNCTION_FEATURES BVH_HAIR
-# include "kernel/bvh/bvh_local.h"
+/* Subsurface scattering BVH traversal */
-# if defined(__OBJECT_MOTION__)
-# define BVH_FUNCTION_NAME bvh_intersect_local_motion
-# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_HAIR
+# if defined(__BVH_LOCAL__)
+# define BVH_FUNCTION_NAME bvh_intersect_local
+# define BVH_FUNCTION_FEATURES BVH_HAIR
# include "kernel/bvh/bvh_local.h"
-# endif
-#endif /* __BVH_LOCAL__ */
-
-/* Volume BVH traversal */
-#if defined(__VOLUME__)
-# define BVH_FUNCTION_NAME bvh_intersect_volume
-# define BVH_FUNCTION_FEATURES BVH_HAIR
-# include "kernel/bvh/bvh_volume.h"
+# if defined(__OBJECT_MOTION__)
+# define BVH_FUNCTION_NAME bvh_intersect_local_motion
+# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_HAIR
+# include "kernel/bvh/bvh_local.h"
+# endif
+# endif /* __BVH_LOCAL__ */
-# if defined(__INSTANCING__)
-# define BVH_FUNCTION_NAME bvh_intersect_volume_instancing
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING | BVH_HAIR
-# include "kernel/bvh/bvh_volume.h"
-# endif
+/* Volume BVH traversal */
-# if defined(__OBJECT_MOTION__)
-# define BVH_FUNCTION_NAME bvh_intersect_volume_motion
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING | BVH_MOTION | BVH_HAIR
+# if defined(__VOLUME__)
+# define BVH_FUNCTION_NAME bvh_intersect_volume
+# define BVH_FUNCTION_FEATURES BVH_HAIR
# include "kernel/bvh/bvh_volume.h"
-# endif
-#endif /* __VOLUME__ */
-/* Record all intersections - Shadow BVH traversal */
-
-#if defined(__SHADOW_RECORD_ALL__)
-# define BVH_FUNCTION_NAME bvh_intersect_shadow_all
-# define BVH_FUNCTION_FEATURES 0
-# include "kernel/bvh/bvh_shadow_all.h"
+# if defined(__INSTANCING__)
+# define BVH_FUNCTION_NAME bvh_intersect_volume_instancing
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING | BVH_HAIR
+# include "kernel/bvh/bvh_volume.h"
+# endif
-# if defined(__INSTANCING__)
-# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_instancing
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING
-# include "kernel/bvh/bvh_shadow_all.h"
-# endif
+# if defined(__OBJECT_MOTION__)
+# define BVH_FUNCTION_NAME bvh_intersect_volume_motion
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING | BVH_MOTION | BVH_HAIR
+# include "kernel/bvh/bvh_volume.h"
+# endif
+# endif /* __VOLUME__ */
-# if defined(__HAIR__)
-# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING | BVH_HAIR
-# include "kernel/bvh/bvh_shadow_all.h"
-# endif
+/* Record all intersections - Shadow BVH traversal */
-# if defined(__OBJECT_MOTION__)
-# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_motion
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING | BVH_MOTION
+# if defined(__SHADOW_RECORD_ALL__)
+# define BVH_FUNCTION_NAME bvh_intersect_shadow_all
+# define BVH_FUNCTION_FEATURES 0
# include "kernel/bvh/bvh_shadow_all.h"
-# endif
-# if defined(__HAIR__) && defined(__OBJECT_MOTION__)
-# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair_motion
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING | BVH_HAIR | BVH_MOTION
-# include "kernel/bvh/bvh_shadow_all.h"
-# endif
-#endif /* __SHADOW_RECORD_ALL__ */
+# if defined(__INSTANCING__)
+# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_instancing
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING
+# include "kernel/bvh/bvh_shadow_all.h"
+# endif
+
+# if defined(__HAIR__)
+# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING | BVH_HAIR
+# include "kernel/bvh/bvh_shadow_all.h"
+# endif
+
+# if defined(__OBJECT_MOTION__)
+# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_motion
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING | BVH_MOTION
+# include "kernel/bvh/bvh_shadow_all.h"
+# endif
+
+# if defined(__HAIR__) && defined(__OBJECT_MOTION__)
+# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair_motion
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING | BVH_HAIR | BVH_MOTION
+# include "kernel/bvh/bvh_shadow_all.h"
+# endif
+# endif /* __SHADOW_RECORD_ALL__ */
/* Record all intersections - Volume BVH traversal */
-#if defined(__VOLUME_RECORD_ALL__)
-# define BVH_FUNCTION_NAME bvh_intersect_volume_all
-# define BVH_FUNCTION_FEATURES BVH_HAIR
-# include "kernel/bvh/bvh_volume_all.h"
-
-# if defined(__INSTANCING__)
-# define BVH_FUNCTION_NAME bvh_intersect_volume_all_instancing
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING | BVH_HAIR
+# if defined(__VOLUME_RECORD_ALL__)
+# define BVH_FUNCTION_NAME bvh_intersect_volume_all
+# define BVH_FUNCTION_FEATURES BVH_HAIR
# include "kernel/bvh/bvh_volume_all.h"
-# endif
-# if defined(__OBJECT_MOTION__)
-# define BVH_FUNCTION_NAME bvh_intersect_volume_all_motion
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING | BVH_MOTION | BVH_HAIR
-# include "kernel/bvh/bvh_volume_all.h"
-# endif
-#endif /* __VOLUME_RECORD_ALL__ */
+# if defined(__INSTANCING__)
+# define BVH_FUNCTION_NAME bvh_intersect_volume_all_instancing
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING | BVH_HAIR
+# include "kernel/bvh/bvh_volume_all.h"
+# endif
+
+# if defined(__OBJECT_MOTION__)
+# define BVH_FUNCTION_NAME bvh_intersect_volume_all_motion
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING | BVH_MOTION | BVH_HAIR
+# include "kernel/bvh/bvh_volume_all.h"
+# endif
+# endif /* __VOLUME_RECORD_ALL__ */
-#undef BVH_FEATURE
-#undef BVH_NAME_JOIN
-#undef BVH_NAME_EVAL
-#undef BVH_FUNCTION_FULL_NAME
+# undef BVH_FEATURE
+# undef BVH_NAME_JOIN
+# undef BVH_NAME_EVAL
+# undef BVH_FUNCTION_FULL_NAME
+
+#endif /* __KERNEL_OPTIX__ */
ccl_device_inline bool scene_intersect_valid(const Ray *ray)
{
@@ -173,8 +177,10 @@ ccl_device_inline bool scene_intersect_valid(const Ray *ray)
* such cases.
* From production scenes so far it seems it's enough to test first element
* only.
+ * Scene intersection may also called with empty rays for conditional trace
+ * calls that evaluate to false, so filter those out.
*/
- return isfinite_safe(ray->P.x) && isfinite_safe(ray->D.x);
+ return isfinite_safe(ray->P.x) && isfinite_safe(ray->D.x) && len_squared(ray->D) != 0.0f;
}
ccl_device_intersect bool scene_intersect(KernelGlobals *kg,
@@ -184,10 +190,46 @@ ccl_device_intersect bool scene_intersect(KernelGlobals *kg,
{
PROFILING_INIT(kg, PROFILING_INTERSECT);
+#ifdef __KERNEL_OPTIX__
+ uint p0 = 0;
+ uint p1 = 0;
+ uint p2 = 0;
+ uint p3 = 0;
+ uint p4 = visibility;
+ uint p5 = PRIMITIVE_NONE;
+
+ optixTrace(scene_intersect_valid(ray) ? kernel_data.bvh.scene : 0,
+ ray->P,
+ ray->D,
+ 0.0f,
+ ray->t,
+ ray->time,
+ 0xFF,
+ OPTIX_RAY_FLAG_NONE,
+ 0,
+ 0,
+ 0, // SBT offset for PG_HITD
+ p0,
+ p1,
+ p2,
+ p3,
+ p4,
+ p5);
+
+ isect->t = __uint_as_float(p0);
+ isect->u = __uint_as_float(p1);
+ isect->v = __uint_as_float(p2);
+ isect->prim = p3;
+ isect->object = p4;
+ isect->type = p5;
+
+ return p5 != PRIMITIVE_NONE;
+#else /* __KERNEL_OPTIX__ */
if (!scene_intersect_valid(ray)) {
return false;
}
-#ifdef __EMBREE__
+
+# ifdef __EMBREE__
if (kernel_data.bvh.scene) {
isect->t = ray->t;
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_REGULAR);
@@ -202,42 +244,41 @@ ccl_device_intersect bool scene_intersect(KernelGlobals *kg,
}
return false;
}
-#endif /* __EMBREE__ */
-#ifdef __OBJECT_MOTION__
+# endif /* __EMBREE__ */
+
+# ifdef __OBJECT_MOTION__
if (kernel_data.bvh.have_motion) {
-# ifdef __HAIR__
+# ifdef __HAIR__
if (kernel_data.bvh.have_curves) {
return bvh_intersect_hair_motion(kg, ray, isect, visibility);
}
-# endif /* __HAIR__ */
+# endif /* __HAIR__ */
return bvh_intersect_motion(kg, ray, isect, visibility);
}
-#endif /* __OBJECT_MOTION__ */
+# endif /* __OBJECT_MOTION__ */
-#ifdef __HAIR__
+# ifdef __HAIR__
if (kernel_data.bvh.have_curves) {
return bvh_intersect_hair(kg, ray, isect, visibility);
}
-#endif /* __HAIR__ */
-
-#ifdef __KERNEL_CPU__
+# endif /* __HAIR__ */
-# ifdef __INSTANCING__
+# ifdef __KERNEL_CPU__
+# ifdef __INSTANCING__
if (kernel_data.bvh.have_instancing) {
return bvh_intersect_instancing(kg, ray, isect, visibility);
}
-# endif /* __INSTANCING__ */
+# endif /* __INSTANCING__ */
return bvh_intersect(kg, ray, isect, visibility);
-#else /* __KERNEL_CPU__ */
-
-# ifdef __INSTANCING__
+# else /* __KERNEL_CPU__ */
+# ifdef __INSTANCING__
return bvh_intersect_instancing(kg, ray, isect, visibility);
-# else
+# else
return bvh_intersect(kg, ray, isect, visibility);
-# endif /* __INSTANCING__ */
-
-#endif /* __KERNEL_CPU__ */
+# endif /* __INSTANCING__ */
+# endif /* __KERNEL_CPU__ */
+#endif /* __KERNEL_OPTIX__ */
}
#ifdef __BVH_LOCAL__
@@ -250,11 +291,43 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals *kg,
{
PROFILING_INIT(kg, PROFILING_INTERSECT_LOCAL);
+# ifdef __KERNEL_OPTIX__
+ uint p0 = ((uint64_t)lcg_state) & 0xFFFFFFFF;
+ uint p1 = (((uint64_t)lcg_state) >> 32) & 0xFFFFFFFF;
+ uint p2 = ((uint64_t)local_isect) & 0xFFFFFFFF;
+ uint p3 = (((uint64_t)local_isect) >> 32) & 0xFFFFFFFF;
+ uint p4 = local_object;
+ // Is set to zero on miss or if ray is aborted, so can be used as return value
+ uint p5 = max_hits;
+
+ local_isect->num_hits = 0; // Initialize hit count to zero
+ optixTrace(scene_intersect_valid(ray) ? kernel_data.bvh.scene : 0,
+ ray->P,
+ ray->D,
+ 0.0f,
+ ray->t,
+ ray->time,
+ // Need to always call into __anyhit__kernel_optix_local_hit
+ 0xFF,
+ OPTIX_RAY_FLAG_ENFORCE_ANYHIT,
+ 1,
+ 0,
+ 0, // SBT offset for PG_HITL
+ p0,
+ p1,
+ p2,
+ p3,
+ p4,
+ p5);
+
+ return p5;
+# else /* __KERNEL_OPTIX__ */
if (!scene_intersect_valid(ray)) {
local_isect->num_hits = 0;
return false;
}
-# ifdef __EMBREE__
+
+# ifdef __EMBREE__
if (kernel_data.bvh.scene) {
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_SSS);
ctx.lcg_state = lcg_state;
@@ -296,13 +369,15 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals *kg,
return local_isect->num_hits > 0;
}
-# endif /* __EMBREE__ */
-# ifdef __OBJECT_MOTION__
+# endif /* __EMBREE__ */
+
+# ifdef __OBJECT_MOTION__
if (kernel_data.bvh.have_motion) {
return bvh_intersect_local_motion(kg, ray, local_isect, local_object, lcg_state, max_hits);
}
-# endif /* __OBJECT_MOTION__ */
+# endif /* __OBJECT_MOTION__ */
return bvh_intersect_local(kg, ray, local_isect, local_object, lcg_state, max_hits);
+# endif /* __KERNEL_OPTIX__ */
}
#endif
@@ -316,11 +391,41 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg,
{
PROFILING_INIT(kg, PROFILING_INTERSECT_SHADOW_ALL);
+# ifdef __KERNEL_OPTIX__
+ uint p0 = ((uint64_t)isect) & 0xFFFFFFFF;
+ uint p1 = (((uint64_t)isect) >> 32) & 0xFFFFFFFF;
+ uint p3 = max_hits;
+ uint p4 = visibility;
+ uint p5 = false;
+
+ *num_hits = 0; // Initialize hit count to zero
+ optixTrace(scene_intersect_valid(ray) ? kernel_data.bvh.scene : 0,
+ ray->P,
+ ray->D,
+ 0.0f,
+ ray->t,
+ ray->time,
+ // Need to always call into __anyhit__kernel_optix_shadow_all_hit
+ 0xFF,
+ OPTIX_RAY_FLAG_ENFORCE_ANYHIT,
+ 2,
+ 0,
+ 0, // SBT offset for PG_HITS
+ p0,
+ p1,
+ *num_hits,
+ p3,
+ p4,
+ p5);
+
+ return p5;
+# else /* __KERNEL_OPTIX__ */
if (!scene_intersect_valid(ray)) {
*num_hits = 0;
return false;
}
-# ifdef __EMBREE__
+
+# ifdef __EMBREE__
if (kernel_data.bvh.scene) {
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_SHADOW_ALL);
ctx.isect_s = isect;
@@ -337,32 +442,41 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg,
*num_hits = ctx.num_hits;
return rtc_ray.tfar == -INFINITY;
}
-# endif
-# ifdef __OBJECT_MOTION__
+# endif /* __EMBREE__ */
+
+# ifdef __OBJECT_MOTION__
if (kernel_data.bvh.have_motion) {
-# ifdef __HAIR__
+# ifdef __HAIR__
if (kernel_data.bvh.have_curves) {
return bvh_intersect_shadow_all_hair_motion(kg, ray, isect, visibility, max_hits, num_hits);
}
-# endif /* __HAIR__ */
+# endif /* __HAIR__ */
return bvh_intersect_shadow_all_motion(kg, ray, isect, visibility, max_hits, num_hits);
}
-# endif /* __OBJECT_MOTION__ */
+# endif /* __OBJECT_MOTION__ */
-# ifdef __HAIR__
+# ifdef __HAIR__
if (kernel_data.bvh.have_curves) {
return bvh_intersect_shadow_all_hair(kg, ray, isect, visibility, max_hits, num_hits);
}
-# endif /* __HAIR__ */
+# endif /* __HAIR__ */
-# ifdef __INSTANCING__
+# ifdef __KERNEL_CPU__
+# ifdef __INSTANCING__
if (kernel_data.bvh.have_instancing) {
return bvh_intersect_shadow_all_instancing(kg, ray, isect, visibility, max_hits, num_hits);
}
-# endif /* __INSTANCING__ */
-
+# endif /* __INSTANCING__ */
+ return bvh_intersect_shadow_all(kg, ray, isect, visibility, max_hits, num_hits);
+# else
+# ifdef __INSTANCING__
+ return bvh_intersect_shadow_all_instancing(kg, ray, isect, visibility, max_hits, num_hits);
+# else
return bvh_intersect_shadow_all(kg, ray, isect, visibility, max_hits, num_hits);
+# endif /* __INSTANCING__ */
+# endif /* __KERNEL_CPU__ */
+# endif /* __KERNEL_OPTIX__ */
}
#endif /* __SHADOW_RECORD_ALL__ */
@@ -374,30 +488,67 @@ ccl_device_intersect bool scene_intersect_volume(KernelGlobals *kg,
{
PROFILING_INIT(kg, PROFILING_INTERSECT_VOLUME);
+# ifdef __KERNEL_OPTIX__
+ uint p0 = 0;
+ uint p1 = 0;
+ uint p2 = 0;
+ uint p3 = 0;
+ uint p4 = visibility;
+ uint p5 = PRIMITIVE_NONE;
+
+ optixTrace(scene_intersect_valid(ray) ? kernel_data.bvh.scene : 0,
+ ray->P,
+ ray->D,
+ 0.0f,
+ ray->t,
+ ray->time,
+ // Visibility mask set to only intersect objects with volumes
+ 0x02,
+ OPTIX_RAY_FLAG_NONE,
+ 0,
+ 0,
+ 0, // SBT offset for PG_HITD
+ p0,
+ p1,
+ p2,
+ p3,
+ p4,
+ p5);
+
+ isect->t = __uint_as_float(p0);
+ isect->u = __uint_as_float(p1);
+ isect->v = __uint_as_float(p2);
+ isect->prim = p3;
+ isect->object = p4;
+ isect->type = p5;
+
+ return p5 != PRIMITIVE_NONE;
+# else /* __KERNEL_OPTIX__ */
if (!scene_intersect_valid(ray)) {
return false;
}
-# ifdef __OBJECT_MOTION__
+# ifdef __OBJECT_MOTION__
if (kernel_data.bvh.have_motion) {
return bvh_intersect_volume_motion(kg, ray, isect, visibility);
}
-# endif /* __OBJECT_MOTION__ */
+# endif /* __OBJECT_MOTION__ */
-# ifdef __KERNEL_CPU__
-# ifdef __INSTANCING__
+# ifdef __KERNEL_CPU__
+# ifdef __INSTANCING__
if (kernel_data.bvh.have_instancing) {
return bvh_intersect_volume_instancing(kg, ray, isect, visibility);
}
-# endif /* __INSTANCING__ */
+# endif /* __INSTANCING__ */
return bvh_intersect_volume(kg, ray, isect, visibility);
-# else /* __KERNEL_CPU__ */
-# ifdef __INSTANCING__
+# else /* __KERNEL_CPU__ */
+# ifdef __INSTANCING__
return bvh_intersect_volume_instancing(kg, ray, isect, visibility);
-# else
+# else
return bvh_intersect_volume(kg, ray, isect, visibility);
-# endif /* __INSTANCING__ */
-# endif /* __KERNEL_CPU__ */
+# endif /* __INSTANCING__ */
+# endif /* __KERNEL_CPU__ */
+# endif /* __KERNEL_OPTIX__ */
}
#endif /* __VOLUME__ */
@@ -413,6 +564,7 @@ ccl_device_intersect uint scene_intersect_volume_all(KernelGlobals *kg,
if (!scene_intersect_valid(ray)) {
return false;
}
+
# ifdef __EMBREE__
if (kernel_data.bvh.scene) {
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_VOLUME_ALL);
@@ -423,7 +575,7 @@ ccl_device_intersect uint scene_intersect_volume_all(KernelGlobals *kg,
RTCRay rtc_ray;
kernel_embree_setup_ray(*ray, rtc_ray, visibility);
rtcOccluded1(kernel_data.bvh.scene, &rtc_ctx.context, &rtc_ray);
- return rtc_ray.tfar == -INFINITY;
+ return ctx.num_hits;
}
# endif /* __EMBREE__ */
diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h
index 5e26f90a878..b282bf5a350 100644
--- a/intern/cycles/kernel/closure/bsdf.h
+++ b/intern/cycles/kernel/closure/bsdf.h
@@ -73,6 +73,28 @@ ccl_device_inline float bsdf_get_roughness_squared(const ShaderClosure *sc)
return bsdf_get_specular_roughness_squared(sc);
}
+/* An additional term to smooth illumination on grazing angles when using bump mapping.
+ * Based on "Taming the Shadow Terminator" by Matt Jen-Yuan Chiang,
+ * Yining Karl Li and Brent Burley. */
+ccl_device_inline float bump_shadowing_term(float3 Ng, float3 N, float3 I)
+{
+ float g = safe_divide(dot(Ng, I), dot(N, I) * dot(Ng, N));
+
+ /* If the incoming light is on the unshadowed side, return full brightness. */
+ if (g >= 1.0f) {
+ return 1.0f;
+ }
+
+ /* If the incoming light points away from the surface, return black. */
+ if (g < 0.0f) {
+ return 0.0f;
+ }
+
+ /* Return smoothed value to avoid discontinuity at perpendicular angle. */
+ float g2 = sqr(g);
+ return -g2 * g + g2 + g;
+}
+
ccl_device_inline int bsdf_sample(KernelGlobals *kg,
ShaderData *sd,
const ShaderClosure *sc,
@@ -424,6 +446,11 @@ ccl_device_inline int bsdf_sample(KernelGlobals *kg,
}
}
}
+ else if (label & LABEL_DIFFUSE) {
+ if (!isequal_float3(sc->N, sd->N)) {
+ *eval *= bump_shadowing_term((label & LABEL_TRANSMIT) ? -sd->N : sd->N, sc->N, *omega_in);
+ }
+ }
return label;
}
@@ -535,6 +562,11 @@ ccl_device_inline
eval = make_float3(0.0f, 0.0f, 0.0f);
break;
}
+ if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
+ if (!isequal_float3(sc->N, sd->N)) {
+ eval *= bump_shadowing_term(sd->N, sc->N, omega_in);
+ }
+ }
}
else {
switch (sc->type) {
@@ -621,6 +653,11 @@ ccl_device_inline
eval = make_float3(0.0f, 0.0f, 0.0f);
break;
}
+ if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
+ if (!isequal_float3(sc->N, sd->N)) {
+ eval *= bump_shadowing_term(-sd->N, sc->N, omega_in);
+ }
+ }
}
return eval;
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h
index 7d7ccfa7774..2f73434706c 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet.h
@@ -303,9 +303,7 @@ ccl_device int bsdf_microfacet_ggx_setup(MicrofacetBsdf *bsdf)
ccl_device int bsdf_microfacet_ggx_fresnel_setup(MicrofacetBsdf *bsdf, const ShaderData *sd)
{
- bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x);
- bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y);
- bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z);
+ bsdf->extra->cspec0 = saturate3(bsdf->extra->cspec0);
float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior);
float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0));
@@ -321,9 +319,7 @@ ccl_device int bsdf_microfacet_ggx_fresnel_setup(MicrofacetBsdf *bsdf, const Sha
ccl_device int bsdf_microfacet_ggx_clearcoat_setup(MicrofacetBsdf *bsdf, const ShaderData *sd)
{
- bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x);
- bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y);
- bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z);
+ bsdf->extra->cspec0 = saturate3(bsdf->extra->cspec0);
float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior);
float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0));
@@ -366,9 +362,7 @@ ccl_device int bsdf_microfacet_ggx_aniso_setup(MicrofacetBsdf *bsdf)
ccl_device int bsdf_microfacet_ggx_aniso_fresnel_setup(MicrofacetBsdf *bsdf, const ShaderData *sd)
{
- bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x);
- bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y);
- bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z);
+ bsdf->extra->cspec0 = saturate3(bsdf->extra->cspec0);
float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior);
float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0));
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
index 07be33ee6b5..9780dd87415 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
@@ -378,12 +378,8 @@ ccl_device int bsdf_microfacet_multi_ggx_common_setup(MicrofacetBsdf *bsdf)
{
bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
bsdf->alpha_y = clamp(bsdf->alpha_y, 1e-4f, 1.0f);
- bsdf->extra->color.x = saturate(bsdf->extra->color.x);
- bsdf->extra->color.y = saturate(bsdf->extra->color.y);
- bsdf->extra->color.z = saturate(bsdf->extra->color.z);
- bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x);
- bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y);
- bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z);
+ bsdf->extra->color = saturate3(bsdf->extra->color);
+ bsdf->extra->cspec0 = saturate3(bsdf->extra->cspec0);
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG;
}
@@ -568,9 +564,7 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_setup(MicrofacetBsdf *bsdf)
bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
bsdf->alpha_y = bsdf->alpha_x;
bsdf->ior = max(0.0f, bsdf->ior);
- bsdf->extra->color.x = saturate(bsdf->extra->color.x);
- bsdf->extra->color.y = saturate(bsdf->extra->color.y);
- bsdf->extra->color.z = saturate(bsdf->extra->color.z);
+ bsdf->extra->color = saturate3(bsdf->extra->color);
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
@@ -583,12 +577,8 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_fresnel_setup(MicrofacetBsdf *bsd
bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
bsdf->alpha_y = bsdf->alpha_x;
bsdf->ior = max(0.0f, bsdf->ior);
- bsdf->extra->color.x = saturate(bsdf->extra->color.x);
- bsdf->extra->color.y = saturate(bsdf->extra->color.y);
- bsdf->extra->color.z = saturate(bsdf->extra->color.z);
- bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x);
- bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y);
- bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z);
+ bsdf->extra->color = saturate3(bsdf->extra->color);
+ bsdf->extra->cspec0 = saturate3(bsdf->extra->cspec0);
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID;
diff --git a/intern/cycles/kernel/closure/bsdf_util.h b/intern/cycles/kernel/closure/bsdf_util.h
index 3bce47caedb..a73dee1b045 100644
--- a/intern/cycles/kernel/closure/bsdf_util.h
+++ b/intern/cycles/kernel/closure/bsdf_util.h
@@ -134,20 +134,6 @@ ccl_device float schlick_fresnel(float u)
return m2 * m2 * m; // pow(m, 5)
}
-ccl_device float smooth_step(float edge0, float edge1, float x)
-{
- float result;
- if (x < edge0)
- result = 0.0f;
- else if (x >= edge1)
- result = 1.0f;
- else {
- float t = (x - edge0) / (edge1 - edge0);
- result = (3.0f - 2.0f * t) * (t * t);
- }
- return result;
-}
-
/* Calculate the fresnel color which is a blend between white and the F0 color (cspec0) */
ccl_device_forceinline float3
interpolate_fresnel_color(float3 L, float3 H, float ior, float F0, float3 cspec0)
diff --git a/intern/cycles/kernel/geom/geom_curve_intersect.h b/intern/cycles/kernel/geom/geom_curve_intersect.h
index 0327ebf8890..7a770470150 100644
--- a/intern/cycles/kernel/geom/geom_curve_intersect.h
+++ b/intern/cycles/kernel/geom/geom_curve_intersect.h
@@ -38,12 +38,14 @@ ccl_device_forceinline bool cardinal_curve_intersect(KernelGlobals *kg,
{
const bool is_curve_primitive = (type & PRIMITIVE_CURVE);
+# ifndef __KERNEL_OPTIX__ /* see OptiX motion flag OPTIX_MOTION_FLAG_[START|END]_VANISH */
if (!is_curve_primitive && kernel_data.bvh.use_bvh_steps) {
const float2 prim_time = kernel_tex_fetch(__prim_time, curveAddr);
if (time < prim_time.x || time > prim_time.y) {
return false;
}
}
+# endif
int segment = PRIMITIVE_UNPACK_SEGMENT(type);
float epsilon = 0.0f;
@@ -505,12 +507,14 @@ ccl_device_forceinline bool curve_intersect(KernelGlobals *kg,
const bool is_curve_primitive = (type & PRIMITIVE_CURVE);
+# ifndef __KERNEL_OPTIX__ /* see OptiX motion flag OPTIX_MOTION_FLAG_[START|END]_VANISH */
if (!is_curve_primitive && kernel_data.bvh.use_bvh_steps) {
const float2 prim_time = kernel_tex_fetch(__prim_time, curveAddr);
if (time < prim_time.x || time > prim_time.y) {
return false;
}
}
+# endif
int segment = PRIMITIVE_UNPACK_SEGMENT(type);
/* curve Intersection check */
diff --git a/intern/cycles/kernel/geom/geom_patch.h b/intern/cycles/kernel/geom/geom_patch.h
index df19199f68e..8b4b91b96c8 100644
--- a/intern/cycles/kernel/geom/geom_patch.h
+++ b/intern/cycles/kernel/geom/geom_patch.h
@@ -380,15 +380,15 @@ ccl_device float3 patch_eval_float3(KernelGlobals *kg,
return val;
}
-ccl_device float3 patch_eval_uchar4(KernelGlobals *kg,
+ccl_device float4 patch_eval_uchar4(KernelGlobals *kg,
const ShaderData *sd,
int offset,
int patch,
float u,
float v,
int channel,
- float3 *du,
- float3 *dv)
+ float4 *du,
+ float4 *dv)
{
int indices[PATCH_MAX_CONTROL_VERTS];
float weights[PATCH_MAX_CONTROL_VERTS];
@@ -398,14 +398,14 @@ ccl_device float3 patch_eval_uchar4(KernelGlobals *kg,
int num_control = patch_eval_control_verts(
kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
- float3 val = make_float3(0.0f, 0.0f, 0.0f);
+ float4 val = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
if (du)
- *du = make_float3(0.0f, 0.0f, 0.0f);
+ *du = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
if (dv)
- *dv = make_float3(0.0f, 0.0f, 0.0f);
+ *dv = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
for (int i = 0; i < num_control; i++) {
- float3 v = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, offset + indices[i]));
+ float4 v = color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, offset + indices[i]));
val += v * weights[i];
if (du)
diff --git a/intern/cycles/kernel/geom/geom_primitive.h b/intern/cycles/kernel/geom/geom_primitive.h
index 7f2b52a24c4..9a91da79f58 100644
--- a/intern/cycles/kernel/geom/geom_primitive.h
+++ b/intern/cycles/kernel/geom/geom_primitive.h
@@ -162,6 +162,27 @@ ccl_device_inline float3 primitive_attribute_float3(KernelGlobals *kg,
}
}
+ccl_device_inline float4 primitive_attribute_float4(KernelGlobals *kg,
+ const ShaderData *sd,
+ const AttributeDescriptor desc,
+ float4 *dx,
+ float4 *dy)
+{
+ if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
+ if (subd_triangle_patch(kg, sd) == ~0)
+ return triangle_attribute_float4(kg, sd, desc, dx, dy);
+ else
+ return subd_triangle_attribute_float4(kg, sd, desc, dx, dy);
+ }
+ else {
+ if (dx)
+ *dx = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ if (dy)
+ *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+}
+
ccl_device_inline float2 primitive_surface_attribute_float2(KernelGlobals *kg,
const ShaderData *sd,
const AttributeDescriptor desc,
diff --git a/intern/cycles/kernel/geom/geom_subd_triangle.h b/intern/cycles/kernel/geom/geom_subd_triangle.h
index 8d5b3c12833..81bac6e6ee1 100644
--- a/intern/cycles/kernel/geom/geom_subd_triangle.h
+++ b/intern/cycles/kernel/geom/geom_subd_triangle.h
@@ -382,13 +382,7 @@ ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals *kg,
float2 p = dpdu * sd->u + dpdv * sd->v + uv[2];
float3 a, dads, dadt;
-
- if (desc.element == ATTR_ELEMENT_CORNER_BYTE) {
- a = patch_eval_uchar4(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
- }
- else {
- a = patch_eval_float3(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
- }
+ a = patch_eval_float3(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
# ifdef __RAY_DIFFERENTIALS__
if (dx || dy) {
@@ -460,7 +454,7 @@ ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals *kg,
return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c;
}
- else if (desc.element == ATTR_ELEMENT_CORNER || desc.element == ATTR_ELEMENT_CORNER_BYTE) {
+ else if (desc.element == ATTR_ELEMENT_CORNER) {
float2 uv[3];
subd_triangle_patch_uv(kg, sd, uv);
@@ -469,18 +463,10 @@ ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals *kg,
float3 f0, f1, f2, f3;
- if (desc.element == ATTR_ELEMENT_CORNER) {
- f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[0] + desc.offset));
- f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[1] + desc.offset));
- f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[2] + desc.offset));
- f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[3] + desc.offset));
- }
- else {
- f0 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[0] + desc.offset));
- f1 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[1] + desc.offset));
- f2 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[2] + desc.offset));
- f3 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[3] + desc.offset));
- }
+ f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[0] + desc.offset));
+ f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[1] + desc.offset));
+ f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[2] + desc.offset));
+ f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[3] + desc.offset));
if (subd_triangle_patch_num_corners(kg, patch) != 4) {
f1 = (f1 + f0) * 0.5f;
@@ -510,4 +496,102 @@ ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals *kg,
}
}
+ccl_device_noinline float4 subd_triangle_attribute_float4(KernelGlobals *kg,
+ const ShaderData *sd,
+ const AttributeDescriptor desc,
+ float4 *dx,
+ float4 *dy)
+{
+ int patch = subd_triangle_patch(kg, sd);
+
+#ifdef __PATCH_EVAL__
+ if (desc.flags & ATTR_SUBDIVIDED) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ float2 dpdu = uv[0] - uv[2];
+ float2 dpdv = uv[1] - uv[2];
+
+ /* p is [s, t] */
+ float2 p = dpdu * sd->u + dpdv * sd->v + uv[2];
+
+ float4 dads, dadt;
+
+ float4 a = patch_eval_uchar4(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
+
+# ifdef __RAY_DIFFERENTIALS__
+ if (dx || dy) {
+ float dsdu = dpdu.x;
+ float dtdu = dpdu.y;
+ float dsdv = dpdv.x;
+ float dtdv = dpdv.y;
+
+ if (dx) {
+ float dudx = sd->du.dx;
+ float dvdx = sd->dv.dx;
+
+ float dsdx = dsdu * dudx + dsdv * dvdx;
+ float dtdx = dtdu * dudx + dtdv * dvdx;
+
+ *dx = dads * dsdx + dadt * dtdx;
+ }
+ if (dy) {
+ float dudy = sd->du.dy;
+ float dvdy = sd->dv.dy;
+
+ float dsdy = dsdu * dudy + dsdv * dvdy;
+ float dtdy = dtdu * dudy + dtdv * dvdy;
+
+ *dy = dads * dsdy + dadt * dtdy;
+ }
+ }
+# endif
+ return a;
+ }
+ else
+#endif /* __PATCH_EVAL__ */
+ if (desc.element == ATTR_ELEMENT_CORNER_BYTE) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ int corners[4];
+ subd_triangle_patch_corners(kg, patch, corners);
+
+ float4 f0 = color_uchar4_to_float4(
+ kernel_tex_fetch(__attributes_uchar4, corners[0] + desc.offset));
+ float4 f1 = color_uchar4_to_float4(
+ kernel_tex_fetch(__attributes_uchar4, corners[1] + desc.offset));
+ float4 f2 = color_uchar4_to_float4(
+ kernel_tex_fetch(__attributes_uchar4, corners[2] + desc.offset));
+ float4 f3 = color_uchar4_to_float4(
+ kernel_tex_fetch(__attributes_uchar4, corners[3] + desc.offset));
+
+ if (subd_triangle_patch_num_corners(kg, patch) != 4) {
+ f1 = (f1 + f0) * 0.5f;
+ f3 = (f3 + f0) * 0.5f;
+ }
+
+ float4 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
+ float4 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
+ float4 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
+
+#ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c;
+ if (dy)
+ *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c;
+#endif
+
+ return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c;
+ }
+ else {
+ if (dx)
+ *dx = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ if (dy)
+ *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom_triangle.h b/intern/cycles/kernel/geom/geom_triangle.h
index 9938c0ba2c3..fdb7f655f64 100644
--- a/intern/cycles/kernel/geom/geom_triangle.h
+++ b/intern/cycles/kernel/geom/geom_triangle.h
@@ -255,20 +255,13 @@ ccl_device float3 triangle_attribute_float3(KernelGlobals *kg,
return sd->u * f0 + sd->v * f1 + (1.0f - sd->u - sd->v) * f2;
}
- else if (desc.element == ATTR_ELEMENT_CORNER || desc.element == ATTR_ELEMENT_CORNER_BYTE) {
+ else if (desc.element == ATTR_ELEMENT_CORNER) {
int tri = desc.offset + sd->prim * 3;
float3 f0, f1, f2;
- if (desc.element == ATTR_ELEMENT_CORNER) {
- f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 0));
- f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 1));
- f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 2));
- }
- else {
- f0 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, tri + 0));
- f1 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, tri + 1));
- f2 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, tri + 2));
- }
+ f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 0));
+ f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 1));
+ f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 2));
#ifdef __RAY_DIFFERENTIALS__
if (dx)
@@ -289,4 +282,36 @@ ccl_device float3 triangle_attribute_float3(KernelGlobals *kg,
}
}
+ccl_device float4 triangle_attribute_float4(KernelGlobals *kg,
+ const ShaderData *sd,
+ const AttributeDescriptor desc,
+ float4 *dx,
+ float4 *dy)
+{
+ if (desc.element == ATTR_ELEMENT_CORNER_BYTE) {
+ int tri = desc.offset + sd->prim * 3;
+
+ float4 f0 = color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, tri + 0));
+ float4 f1 = color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, tri + 1));
+ float4 f2 = color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, tri + 2));
+
+#ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = sd->du.dx * f0 + sd->dv.dx * f1 - (sd->du.dx + sd->dv.dx) * f2;
+ if (dy)
+ *dy = sd->du.dy * f0 + sd->dv.dy * f1 - (sd->du.dy + sd->dv.dy) * f2;
+#endif
+
+ return sd->u * f0 + sd->v * f1 + (1.0f - sd->u - sd->v) * f2;
+ }
+ else {
+ if (dx)
+ *dx = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ if (dy)
+ *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_compat_cuda.h b/intern/cycles/kernel/kernel_compat_cuda.h
index 5075c434b10..4f508d7cdaa 100644
--- a/intern/cycles/kernel/kernel_compat_cuda.h
+++ b/intern/cycles/kernel/kernel_compat_cuda.h
@@ -73,6 +73,7 @@ __device__ half __float2half(const float f)
*/
#define ccl_ref
#define ccl_align(n) __align__(n)
+#define ccl_optional_struct_init
#define ATTR_FALLTHROUGH
diff --git a/intern/cycles/kernel/kernel_compat_opencl.h b/intern/cycles/kernel/kernel_compat_opencl.h
index 1fe52c51ab0..552734cc361 100644
--- a/intern/cycles/kernel/kernel_compat_opencl.h
+++ b/intern/cycles/kernel/kernel_compat_opencl.h
@@ -46,6 +46,7 @@
#define ccl_restrict restrict
#define ccl_ref
#define ccl_align(n) __attribute__((aligned(n)))
+#define ccl_optional_struct_init
#ifdef __SPLIT_KERNEL__
# define ccl_addr_space __global
diff --git a/intern/cycles/kernel/kernel_compat_optix.h b/intern/cycles/kernel/kernel_compat_optix.h
new file mode 100644
index 00000000000..61b9d87a020
--- /dev/null
+++ b/intern/cycles/kernel/kernel_compat_optix.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2019, NVIDIA Corporation.
+ * Copyright 2019, Blender Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __KERNEL_COMPAT_OPTIX_H__
+#define __KERNEL_COMPAT_OPTIX_H__
+
+#define OPTIX_DONT_INCLUDE_CUDA
+#include <optix.h>
+
+#define __KERNEL_GPU__
+#define __KERNEL_CUDA__ // OptiX kernels are implicitly CUDA kernels too
+#define __KERNEL_OPTIX__
+#define CCL_NAMESPACE_BEGIN
+#define CCL_NAMESPACE_END
+
+#ifndef ATTR_FALLTHROUGH
+# define ATTR_FALLTHROUGH
+#endif
+
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+typedef unsigned short half;
+typedef unsigned long long CUtexObject;
+
+#define FLT_MIN 1.175494350822287507969e-38f
+#define FLT_MAX 340282346638528859811704183484516925440.0f
+
+__device__ half __float2half(const float f)
+{
+ half val;
+ asm("{ cvt.rn.f16.f32 %0, %1;}\n" : "=h"(val) : "f"(f));
+ return val;
+}
+
+/* Selective nodes compilation. */
+#ifndef __NODES_MAX_GROUP__
+# define __NODES_MAX_GROUP__ NODE_GROUP_LEVEL_MAX
+#endif
+#ifndef __NODES_FEATURES__
+# define __NODES_FEATURES__ NODE_FEATURE_ALL
+#endif
+
+#define ccl_device \
+ __device__ __forceinline__ // Function calls are bad for OptiX performance, so inline everything
+#define ccl_device_inline ccl_device
+#define ccl_device_forceinline ccl_device
+#define ccl_device_noinline __device__ __noinline__
+#define ccl_device_noinline_cpu ccl_device
+#define ccl_global
+#define ccl_static_constant __constant__
+#define ccl_constant const
+#define ccl_local
+#define ccl_local_param
+#define ccl_private
+#define ccl_may_alias
+#define ccl_addr_space
+#define ccl_restrict __restrict__
+#define ccl_ref
+#define ccl_align(n) __align__(n)
+
+// Zero initialize structs to help the compiler figure out scoping
+#define ccl_optional_struct_init = {}
+
+#define kernel_data __params.data // See kernel_globals.h
+#define kernel_tex_array(t) __params.t
+#define kernel_tex_fetch(t, index) __params.t[(index)]
+
+#define kernel_assert(cond)
+
+/* Types */
+
+#include "util/util_half.h"
+#include "util/util_types.h"
+
+#endif /* __KERNEL_COMPAT_OPTIX_H__ */
diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
index 16d52b0c733..459280cf433 100644
--- a/intern/cycles/kernel/kernel_emission.h
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -242,10 +242,8 @@ ccl_device_noinline_cpu bool indirect_lamp_emission(KernelGlobals *kg,
{
bool hit_lamp = false;
- *emission = make_float3(0.0f, 0.0f, 0.0f);
-
for (int lamp = 0; lamp < kernel_data.integrator.num_all_lights; lamp++) {
- LightSample ls;
+ LightSample ls ccl_optional_struct_init;
if (!lamp_light_eval(kg, lamp, ray->P, ray->D, ray->t, &ls))
continue;
diff --git a/intern/cycles/kernel/kernel_film.h b/intern/cycles/kernel/kernel_film.h
index d20f1adf663..7a974e9d852 100644
--- a/intern/cycles/kernel/kernel_film.h
+++ b/intern/cycles/kernel/kernel_film.h
@@ -16,18 +16,66 @@
CCL_NAMESPACE_BEGIN
-ccl_device float4 film_map(KernelGlobals *kg, float4 irradiance, float scale)
+ccl_device float4 film_get_pass_result(KernelGlobals *kg,
+ ccl_global float *buffer,
+ float sample_scale,
+ int index,
+ bool use_display_sample_scale)
{
- float exposure = kernel_data.film.exposure;
- float4 result = irradiance * scale;
+ float4 pass_result;
+
+ int display_pass_stride = kernel_data.film.display_pass_stride;
+ int display_pass_components = kernel_data.film.display_pass_components;
+
+ if (display_pass_components == 4) {
+ ccl_global float4 *in = (ccl_global float4 *)(buffer + display_pass_stride +
+ index * kernel_data.film.pass_stride);
+ float alpha = use_display_sample_scale ?
+ (kernel_data.film.use_display_pass_alpha ? in->w : 1.0f / sample_scale) :
+ 1.0f;
+
+ pass_result = make_float4(in->x, in->y, in->z, alpha);
+
+ int display_divide_pass_stride = kernel_data.film.display_divide_pass_stride;
+ if (display_divide_pass_stride != -1) {
+ ccl_global float4 *divide_in = (ccl_global float4 *)(buffer + display_divide_pass_stride +
+ index * kernel_data.film.pass_stride);
+ if (divide_in->x != 0.0f) {
+ pass_result.x /= divide_in->x;
+ }
+ if (divide_in->y != 0.0f) {
+ pass_result.y /= divide_in->y;
+ }
+ if (divide_in->z != 0.0f) {
+ pass_result.z /= divide_in->z;
+ }
+ }
+
+ if (kernel_data.film.use_display_exposure) {
+ float exposure = kernel_data.film.exposure;
+ pass_result *= make_float4(exposure, exposure, exposure, alpha);
+ }
+ }
+ else if (display_pass_components == 1) {
+ ccl_global float *in = (ccl_global float *)(buffer + display_pass_stride +
+ index * kernel_data.film.pass_stride);
+ pass_result = make_float4(*in, *in, *in, 1.0f / sample_scale);
+ }
+
+ return pass_result;
+}
+
+ccl_device float4 film_map(KernelGlobals *kg, float4 rgba_in, float scale)
+{
+ float4 result;
/* conversion to srgb */
- result.x = color_linear_to_srgb(result.x * exposure);
- result.y = color_linear_to_srgb(result.y * exposure);
- result.z = color_linear_to_srgb(result.z * exposure);
+ result.x = color_linear_to_srgb(rgba_in.x);
+ result.y = color_linear_to_srgb(rgba_in.y);
+ result.z = color_linear_to_srgb(rgba_in.z);
/* clamp since alpha might be > 1.0 due to russian roulette */
- result.w = saturate(result.w);
+ result.w = saturate(rgba_in.w);
return result;
}
@@ -57,15 +105,22 @@ ccl_device void kernel_film_convert_to_byte(KernelGlobals *kg,
/* buffer offset */
int index = offset + x + y * stride;
+ bool use_display_sample_scale = (kernel_data.film.display_divide_pass_stride == -1);
+ float4 rgba_in = film_get_pass_result(kg, buffer, sample_scale, index, use_display_sample_scale);
+
rgba += index;
- buffer += index * kernel_data.film.pass_stride;
/* map colors */
- float4 irradiance = *((ccl_global float4 *)buffer);
- float4 float_result = film_map(kg, irradiance, sample_scale);
- uchar4 byte_result = film_float_to_byte(float_result);
-
- *rgba = byte_result;
+ if (use_display_sample_scale) {
+ float4 float_result = film_map(kg, rgba_in, sample_scale);
+ uchar4 byte_result = film_float_to_byte(float_result);
+ *rgba = byte_result;
+ }
+ else {
+ float4 float_result = film_map(kg, rgba_in, 1.0);
+ uchar4 byte_result = film_float_to_byte(float_result);
+ *rgba = byte_result;
+ }
}
ccl_device void kernel_film_convert_to_half_float(KernelGlobals *kg,
@@ -79,21 +134,16 @@ ccl_device void kernel_film_convert_to_half_float(KernelGlobals *kg,
{
/* buffer offset */
int index = offset + x + y * stride;
+ bool use_display_sample_scale = (kernel_data.film.display_divide_pass_stride == -1);
+ float4 rgba_in = film_get_pass_result(kg, buffer, sample_scale, index, use_display_sample_scale);
- ccl_global float4 *in = (ccl_global float4 *)(buffer + index * kernel_data.film.pass_stride);
ccl_global half *out = (ccl_global half *)rgba + index * 4;
-
- float exposure = kernel_data.film.exposure;
-
- float4 rgba_in = *in;
-
- if (exposure != 1.0f) {
- rgba_in.x *= exposure;
- rgba_in.y *= exposure;
- rgba_in.z *= exposure;
+ if (use_display_sample_scale) {
+ float4_store_half(out, rgba_in, sample_scale);
+ }
+ else {
+ float4_store_half(out, rgba_in, 1.0f);
}
-
- float4_store_half(out, rgba_in, sample_scale);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_globals.h b/intern/cycles/kernel/kernel_globals.h
index 9dbf3b7ea2e..a440021b6b9 100644
--- a/intern/cycles/kernel/kernel_globals.h
+++ b/intern/cycles/kernel/kernel_globals.h
@@ -90,12 +90,43 @@ typedef struct KernelGlobals {
#endif /* __KERNEL_CPU__ */
+#ifdef __KERNEL_OPTIX__
+
+typedef struct ShaderParams {
+ uint4 *input;
+ float4 *output;
+ int type;
+ int filter;
+ int sx;
+ int offset;
+ int sample;
+} ShaderParams;
+
+typedef struct KernelParams {
+ WorkTile tile;
+ KernelData data;
+ ShaderParams shader;
+# define KERNEL_TEX(type, name) const type *name;
+# include "kernel/kernel_textures.h"
+} KernelParams;
+
+typedef struct KernelGlobals {
+# ifdef __VOLUME__
+ VolumeState volume_state;
+# endif
+ Intersection hits_stack[64];
+} KernelGlobals;
+
+extern "C" __constant__ KernelParams __params;
+
+#else /* __KERNEL_OPTIX__ */
+
/* For CUDA, constant memory textures must be globals, so we can't put them
* into a struct. As a result we don't actually use this struct and use actual
* globals and simply pass along a NULL pointer everywhere, which we hope gets
* optimized out. */
-#ifdef __KERNEL_CUDA__
+# ifdef __KERNEL_CUDA__
__constant__ KernelData __data;
typedef struct KernelGlobals {
@@ -103,10 +134,12 @@ typedef struct KernelGlobals {
Intersection hits_stack[64];
} KernelGlobals;
-# define KERNEL_TEX(type, name) const __constant__ __device__ type *name;
-# include "kernel/kernel_textures.h"
+# define KERNEL_TEX(type, name) const __constant__ __device__ type *name;
+# include "kernel/kernel_textures.h"
+
+# endif /* __KERNEL_CUDA__ */
-#endif /* __KERNEL_CUDA__ */
+#endif /* __KERNEL_OPTIX__ */
/* OpenCL */
diff --git a/intern/cycles/kernel/kernel_jitter.h b/intern/cycles/kernel/kernel_jitter.h
index f7270a14940..e59d8946950 100644
--- a/intern/cycles/kernel/kernel_jitter.h
+++ b/intern/cycles/kernel/kernel_jitter.h
@@ -38,43 +38,13 @@ ccl_device_inline int cmj_fast_mod_pow2(int a, int b)
ccl_device_inline int cmj_fast_div_pow2(int a, int b)
{
kernel_assert(b > 1);
-#if defined(__KERNEL_SSE2__)
-# ifdef _MSC_VER
- unsigned long ctz;
- _BitScanForward(&ctz, b);
- return a >> ctz;
-# else
- return a >> __builtin_ctz(b);
-# endif
-#elif defined(__KERNEL_CUDA__)
- return a >> (__ffs(b) - 1);
-#else
- return a / b;
-#endif
+ return a >> count_trailing_zeros(b);
}
ccl_device_inline uint cmj_w_mask(uint w)
{
kernel_assert(w > 1);
-#if defined(__KERNEL_SSE2__)
-# ifdef _MSC_VER
- unsigned long leading_zero;
- _BitScanReverse(&leading_zero, w);
- return ((1 << (1 + leading_zero)) - 1);
-# else
- return ((1 << (32 - __builtin_clz(w))) - 1);
-# endif
-#elif defined(__KERNEL_CUDA__)
- return ((1 << (32 - __clz(w))) - 1);
-#else
- w |= w >> 1;
- w |= w >> 2;
- w |= w >> 4;
- w |= w >> 8;
- w |= w >> 16;
-
- return w;
-#endif
+ return ((1 << (32 - count_leading_zeros(w))) - 1);
}
ccl_device_inline uint cmj_permute(uint i, uint l, uint p)
diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h
index 4a424866efe..c1d74dddc2a 100644
--- a/intern/cycles/kernel/kernel_passes.h
+++ b/intern/cycles/kernel/kernel_passes.h
@@ -397,7 +397,9 @@ ccl_device_inline void kernel_write_result(KernelGlobals *kg,
float alpha;
float3 L_sum = path_radiance_clamp_and_sum(kg, L, &alpha);
- kernel_write_pass_float4(buffer, make_float4(L_sum.x, L_sum.y, L_sum.z, alpha));
+ if (kernel_data.film.pass_flag & PASSMASK(COMBINED)) {
+ kernel_write_pass_float4(buffer, make_float4(L_sum.x, L_sum.y, L_sum.z, alpha));
+ }
kernel_write_light_passes(kg, buffer, L);
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index 63be0a7f505..d45ffe9c7df 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -92,7 +92,7 @@ ccl_device_forceinline void kernel_path_lamp_emission(KernelGlobals *kg,
#ifdef __LAMP_MIS__
if (kernel_data.integrator.use_lamp_mis && !(state->flag & PATH_RAY_CAMERA)) {
/* ray starting from previous non-transparent bounce */
- Ray light_ray;
+ Ray light_ray ccl_optional_struct_init;
light_ray.P = ray->P - state->ray_t * ray->D;
state->ray_t += isect->t;
@@ -326,13 +326,19 @@ ccl_device_forceinline bool kernel_path_shader_apply(KernelGlobals *kg,
return true;
}
-ccl_device_noinline void kernel_path_ao(KernelGlobals *kg,
- ShaderData *sd,
- ShaderData *emission_sd,
- PathRadiance *L,
- ccl_addr_space PathState *state,
- float3 throughput,
- float3 ao_alpha)
+#ifdef __KERNEL_OPTIX__
+ccl_device_inline /* inline trace calls */
+#else
+ccl_device_noinline
+#endif
+ void
+ kernel_path_ao(KernelGlobals *kg,
+ ShaderData *sd,
+ ShaderData *emission_sd,
+ PathRadiance *L,
+ ccl_addr_space PathState *state,
+ float3 throughput,
+ float3 ao_alpha)
{
PROFILING_INIT(kg, PROFILING_AO);
@@ -655,9 +661,11 @@ ccl_device void kernel_path_trace(
kernel_path_trace_setup(kg, sample, x, y, &rng_hash, &ray);
+# ifndef __KERNEL_OPTIX__
if (ray.t == 0.0f) {
return;
}
+# endif
/* Initialize state. */
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
@@ -671,6 +679,13 @@ ccl_device void kernel_path_trace(
PathState state;
path_state_init(kg, emission_sd, &state, rng_hash, sample, &ray);
+# ifdef __KERNEL_OPTIX__
+ /* Force struct into local memory to avoid costly spilling on trace calls. */
+ if (pass_stride < 0) /* This is never executed and just prevents the compiler from doing SROA. */
+ for (int i = 0; i < sizeof(L); ++i)
+ reinterpret_cast<unsigned char *>(&L)[-pass_stride + i] = 0;
+# endif
+
/* Integrate. */
kernel_path_integrate(kg, &state, throughput, &ray, &L, buffer, emission_sd);
diff --git a/intern/cycles/kernel/kernel_path_surface.h b/intern/cycles/kernel/kernel_path_surface.h
index d299106ea96..a32690d51eb 100644
--- a/intern/cycles/kernel/kernel_path_surface.h
+++ b/intern/cycles/kernel/kernel_path_surface.h
@@ -32,7 +32,7 @@ ccl_device_noinline_cpu void kernel_branched_path_surface_connect_light(
{
# ifdef __EMISSION__
/* sample illumination from lights to find path contribution */
- BsdfEval L_light;
+ BsdfEval L_light ccl_optional_struct_init;
int num_lights = 0;
if (kernel_data.integrator.use_direct_light) {
@@ -79,7 +79,7 @@ ccl_device_noinline_cpu void kernel_branched_path_surface_connect_light(
float num_samples_inv = num_samples_adjust / (num_samples * num_all_lights);
for (int j = 0; j < num_samples; j++) {
- Ray light_ray;
+ Ray light_ray ccl_optional_struct_init;
light_ray.t = 0.0f; /* reset ray */
# ifdef __OBJECT_MOTION__
light_ray.time = sd->time;
@@ -98,7 +98,7 @@ ccl_device_noinline_cpu void kernel_branched_path_surface_connect_light(
light_u = 0.5f * light_u;
}
- LightSample ls;
+ LightSample ls ccl_optional_struct_init;
const int lamp = is_lamp ? i : -1;
if (light_sample(kg, lamp, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
/* The sampling probability returned by lamp_light_sample assumes that all lights were
@@ -147,9 +147,9 @@ ccl_device bool kernel_branched_path_surface_bounce(KernelGlobals *kg,
{
/* sample BSDF */
float bsdf_pdf;
- BsdfEval bsdf_eval;
- float3 bsdf_omega_in;
- differential3 bsdf_domega_in;
+ BsdfEval bsdf_eval ccl_optional_struct_init;
+ float3 bsdf_omega_in ccl_optional_struct_init;
+ differential3 bsdf_domega_in ccl_optional_struct_init;
float bsdf_u, bsdf_v;
path_branched_rng_2D(
kg, state->rng_hash, state, sample, num_samples, PRNG_BSDF_U, &bsdf_u, &bsdf_v);
@@ -220,8 +220,8 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg,
kernel_branched_path_surface_connect_light(kg, sd, emission_sd, state, throughput, 1.0f, L, all);
# else
/* sample illumination from lights to find path contribution */
- Ray light_ray;
- BsdfEval L_light;
+ Ray light_ray ccl_optional_struct_init;
+ BsdfEval L_light ccl_optional_struct_init;
bool is_lamp = false;
bool has_emission = false;
@@ -234,7 +234,7 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg,
float light_u, light_v;
path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v);
- LightSample ls;
+ LightSample ls ccl_optional_struct_init;
if (light_sample(kg, -1, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
float terminate = path_state_rng_light_termination(kg, state);
has_emission = direct_emission(
@@ -274,9 +274,9 @@ ccl_device bool kernel_path_surface_bounce(KernelGlobals *kg,
if (sd->flag & SD_BSDF) {
/* sample BSDF */
float bsdf_pdf;
- BsdfEval bsdf_eval;
- float3 bsdf_omega_in;
- differential3 bsdf_domega_in;
+ BsdfEval bsdf_eval ccl_optional_struct_init;
+ float3 bsdf_omega_in ccl_optional_struct_init;
+ differential3 bsdf_domega_in ccl_optional_struct_init;
float bsdf_u, bsdf_v;
path_state_rng_2D(kg, state, PRNG_BSDF_U, &bsdf_u, &bsdf_v);
int label;
diff --git a/intern/cycles/kernel/kernel_path_volume.h b/intern/cycles/kernel/kernel_path_volume.h
index 6b62005d19a..db10629ee9f 100644
--- a/intern/cycles/kernel/kernel_path_volume.h
+++ b/intern/cycles/kernel/kernel_path_volume.h
@@ -27,8 +27,8 @@ ccl_device_inline void kernel_path_volume_connect_light(KernelGlobals *kg,
{
# ifdef __EMISSION__
/* sample illumination from lights to find path contribution */
- Ray light_ray;
- BsdfEval L_light;
+ Ray light_ray ccl_optional_struct_init;
+ BsdfEval L_light ccl_optional_struct_init;
bool is_lamp = false;
bool has_emission = false;
@@ -42,7 +42,7 @@ ccl_device_inline void kernel_path_volume_connect_light(KernelGlobals *kg,
float light_u, light_v;
path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v);
- LightSample ls;
+ LightSample ls ccl_optional_struct_init;
if (light_sample(kg, -1, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
float terminate = path_state_rng_light_termination(kg, state);
has_emission = direct_emission(
@@ -71,9 +71,9 @@ ccl_device_noinline_cpu bool kernel_path_volume_bounce(KernelGlobals *kg,
{
/* sample phase function */
float phase_pdf;
- BsdfEval phase_eval;
- float3 phase_omega_in;
- differential3 phase_domega_in;
+ BsdfEval phase_eval ccl_optional_struct_init;
+ float3 phase_omega_in ccl_optional_struct_init;
+ differential3 phase_domega_in ccl_optional_struct_init;
float phase_u, phase_v;
path_state_rng_2D(kg, state, PRNG_BSDF_U, &phase_u, &phase_v);
int label;
@@ -139,7 +139,7 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg,
const VolumeSegment *segment)
{
# ifdef __EMISSION__
- BsdfEval L_light;
+ BsdfEval L_light ccl_optional_struct_init;
int num_lights = 1;
if (sample_all_lights) {
@@ -181,7 +181,7 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg,
float num_samples_inv = 1.0f / (num_samples * num_all_lights);
for (int j = 0; j < num_samples; j++) {
- Ray light_ray;
+ Ray light_ray ccl_optional_struct_init;
light_ray.t = 0.0f; /* reset ray */
# ifdef __OBJECT_MOTION__
light_ray.time = sd->time;
@@ -201,7 +201,7 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg,
light_u = 0.5f * light_u;
}
- LightSample ls;
+ LightSample ls ccl_optional_struct_init;
const int lamp = is_lamp ? i : -1;
light_sample(kg, lamp, light_u, light_v, sd->time, ray->P, state->bounce, &ls);
diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h
index a5ae427c2d3..80738213d2a 100644
--- a/intern/cycles/kernel/kernel_random.h
+++ b/intern/cycles/kernel/kernel_random.h
@@ -41,10 +41,9 @@ ccl_device uint sobol_dimension(KernelGlobals *kg, int index, int dimension)
{
uint result = 0;
uint i = index + SOBOL_SKIP;
- for (uint j = 0; i; i >>= 1, j++) {
- if (i & 1) {
- result ^= kernel_tex_fetch(__sobol_directions, 32 * dimension + j);
- }
+ for (int j = 0, x; (x = find_first_set(i)); i >>= x) {
+ j += x;
+ result ^= kernel_tex_fetch(__sobol_directions, 32 * dimension + j - 1);
}
return result;
}
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index 4688857b718..7ccb99cad2a 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -48,10 +48,16 @@ ccl_device void shader_setup_object_transforms(KernelGlobals *kg, ShaderData *sd
}
#endif
-ccl_device_noinline void shader_setup_from_ray(KernelGlobals *kg,
- ShaderData *sd,
- const Intersection *isect,
- const Ray *ray)
+#ifdef __KERNEL_OPTIX__
+ccl_device_inline
+#else
+ccl_device_noinline
+#endif
+ void
+ shader_setup_from_ray(KernelGlobals *kg,
+ ShaderData *sd,
+ const Intersection *isect,
+ const Ray *ray)
{
PROFILING_INIT(kg, PROFILING_SHADER_SETUP);
@@ -1356,7 +1362,7 @@ ccl_device bool shader_transparent_shadow(KernelGlobals *kg, Intersection *isect
int shader = 0;
# ifdef __HAIR__
- if (kernel_tex_fetch(__prim_type, isect->prim) & PRIMITIVE_ALL_TRIANGLE) {
+ if (isect->type & PRIMITIVE_ALL_TRIANGLE) {
# endif
shader = kernel_tex_fetch(__tri_shader, prim);
# ifdef __HAIR__
diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h
index c02d7d77faf..61fcc61264a 100644
--- a/intern/cycles/kernel/kernel_shadow.h
+++ b/intern/cycles/kernel/kernel_shadow.h
@@ -17,13 +17,6 @@
CCL_NAMESPACE_BEGIN
#ifdef __VOLUME__
-typedef struct VolumeState {
-# ifdef __SPLIT_KERNEL__
-# else
- PathState ps;
-# endif
-} VolumeState;
-
/* Get PathState ready for use for volume stack evaluation. */
# ifdef __SPLIT_KERNEL__
ccl_addr_space
@@ -55,16 +48,15 @@ ccl_addr_space
/* Attenuate throughput accordingly to the given intersection event.
* Returns true if the throughput is zero and traversal can be aborted.
*/
-ccl_device_forceinline bool shadow_handle_transparent_isect(
- KernelGlobals *kg,
- ShaderData *shadow_sd,
- ccl_addr_space PathState *state,
+ccl_device_forceinline bool shadow_handle_transparent_isect(KernelGlobals *kg,
+ ShaderData *shadow_sd,
+ ccl_addr_space PathState *state,
#ifdef __VOLUME__
- ccl_addr_space struct PathState *volume_state,
+ ccl_addr_space PathState *volume_state,
#endif
- Intersection *isect,
- Ray *ray,
- float3 *throughput)
+ Intersection *isect,
+ Ray *ray,
+ float3 *throughput)
{
#ifdef __VOLUME__
/* Attenuation between last surface and next surface. */
@@ -163,7 +155,11 @@ ccl_device bool shadow_blocked_transparent_all_loop(KernelGlobals *kg,
uint num_hits;
const bool blocked = scene_intersect_shadow_all(kg, ray, hits, visibility, max_hits, &num_hits);
# ifdef __VOLUME__
+# ifdef __KERNEL_OPTIX__
+ VolumeState &volume_state = kg->volume_state;
+# else
VolumeState volume_state;
+# endif
# endif
/* If no opaque surface found but we did find transparent hits,
* shade them.
@@ -302,7 +298,11 @@ ccl_device bool shadow_blocked_transparent_stepped_loop(KernelGlobals *kg,
float3 *shadow)
{
# ifdef __VOLUME__
+# ifdef __KERNEL_OPTIX__
+ VolumeState &volume_state = kg->volume_state;
+# else
VolumeState volume_state;
+# endif
# endif
if (blocked && is_transparent_isect) {
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
@@ -387,32 +387,38 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg,
ShaderData *sd,
ShaderData *shadow_sd,
ccl_addr_space PathState *state,
- Ray *ray_input,
+ Ray *ray,
float3 *shadow)
{
- Ray *ray = ray_input;
- Intersection isect;
- /* Some common early checks. */
*shadow = make_float3(1.0f, 1.0f, 1.0f);
+#if !defined(__KERNEL_OPTIX__)
+ /* Some common early checks.
+ * Avoid conditional trace call in OptiX though, since those hurt performance there.
+ */
if (ray->t == 0.0f) {
return false;
}
+#endif
#ifdef __SHADOW_TRICKS__
const uint visibility = (state->flag & PATH_RAY_SHADOW_CATCHER) ? PATH_RAY_SHADOW_NON_CATCHER :
PATH_RAY_SHADOW;
#else
const uint visibility = PATH_RAY_SHADOW;
#endif
- /* Do actual shadow shading. */
- /* First of all, we check if integrator requires transparent shadows.
+ /* Do actual shadow shading.
+ * First of all, we check if integrator requires transparent shadows.
* if not, we use simplest and fastest ever way to calculate occlusion.
+ * Do not do this in OptiX to avoid the additional trace call.
*/
-#ifdef __TRANSPARENT_SHADOWS__
+#if !defined(__KERNEL_OPTIX__) || !defined(__TRANSPARENT_SHADOWS__)
+ Intersection isect;
+# ifdef __TRANSPARENT_SHADOWS__
if (!kernel_data.integrator.transparent_shadows)
-#endif
+# endif
{
return shadow_blocked_opaque(kg, shadow_sd, state, visibility, ray, &isect, shadow);
}
+#endif
#ifdef __TRANSPARENT_SHADOWS__
# ifdef __SHADOW_RECORD_ALL__
/* For the transparent shadows we try to use record-all logic on the
@@ -426,7 +432,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg,
return true;
}
const uint max_hits = transparent_max_bounce - state->transparent_bounce - 1;
-# ifdef __KERNEL_GPU__
+# if defined(__KERNEL_GPU__) && !defined(__KERNEL_OPTIX__)
/* On GPU we do tricky with tracing opaque ray first, this avoids speed
* regressions in some files.
*
diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h
index 8dc1904058d..dbe2c12ce81 100644
--- a/intern/cycles/kernel/kernel_subsurface.h
+++ b/intern/cycles/kernel/kernel_subsurface.h
@@ -353,13 +353,19 @@ ccl_device void subsurface_random_walk_coefficients(const ShaderClosure *sc,
*weight = safe_divide_color(bssrdf->weight, A);
}
-ccl_device_noinline bool subsurface_random_walk(KernelGlobals *kg,
- LocalIntersection *ss_isect,
- ShaderData *sd,
- ccl_addr_space PathState *state,
- const ShaderClosure *sc,
- const float bssrdf_u,
- const float bssrdf_v)
+#ifdef __KERNEL_OPTIX__
+ccl_device_inline /* inline trace calls */
+#else
+ccl_device_noinline
+#endif
+ bool
+ subsurface_random_walk(KernelGlobals *kg,
+ LocalIntersection *ss_isect,
+ ShaderData *sd,
+ ccl_addr_space PathState *state,
+ const ShaderClosure *sc,
+ const float bssrdf_u,
+ const float bssrdf_v)
{
/* Sample diffuse surface scatter into the object. */
float3 D;
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index b3cb6ca7c19..1e5534b0c17 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -143,6 +143,13 @@ CCL_NAMESPACE_BEGIN
# endif
#endif /* __KERNEL_CUDA__ */
+#ifdef __KERNEL_OPTIX__
+# undef __BAKING__
+# undef __BRANCHED_PATH__
+/* TODO(pmours): Cannot use optixTrace in non-inlined functions */
+# undef __SHADER_RAYTRACE__
+#endif /* __KERNEL_OPTIX__ */
+
#ifdef __KERNEL_OPENCL__
#endif /* __KERNEL_OPENCL__ */
@@ -918,7 +925,8 @@ enum ShaderDataObjectFlag {
SD_OBJECT_HAS_VOLUME_ATTRIBUTES)
};
-typedef ccl_addr_space struct ShaderData {
+typedef ccl_addr_space struct ccl_align(16) ShaderData
+{
/* position */
float3 P;
/* smooth normal for shading */
@@ -1003,11 +1011,16 @@ typedef ccl_addr_space struct ShaderData {
/* At the end so we can adjust size in ShaderDataTinyStorage. */
struct ShaderClosure closure[MAX_CLOSURE];
-} ShaderData;
+}
+ShaderData;
-typedef ccl_addr_space struct ShaderDataTinyStorage {
+/* ShaderDataTinyStorage needs the same alignment as ShaderData, or else
+ * the pointer cast in AS_SHADER_DATA invokes undefined behavior. */
+typedef ccl_addr_space struct ccl_align(16) ShaderDataTinyStorage
+{
char pad[sizeof(ShaderData) - sizeof(ShaderClosure) * MAX_CLOSURE];
-} ShaderDataTinyStorage;
+}
+ShaderDataTinyStorage;
#define AS_SHADER_DATA(shader_data_tiny_storage) ((ShaderData *)shader_data_tiny_storage)
/* Path State */
@@ -1056,6 +1069,15 @@ typedef struct PathState {
#endif
} PathState;
+#ifdef __VOLUME__
+typedef struct VolumeState {
+# ifdef __SPLIT_KERNEL__
+# else
+ PathState ps;
+# endif
+} VolumeState;
+#endif
+
/* Struct to gather multiple nearby intersections. */
typedef struct LocalIntersection {
Ray ray;
@@ -1168,6 +1190,7 @@ static_assert_align(KernelCamera, 16);
typedef struct KernelFilm {
float exposure;
int pass_flag;
+
int light_pass_flag;
int pass_stride;
int use_light_pass;
@@ -1233,6 +1256,13 @@ typedef struct KernelFilm {
int pass_bvh_intersections;
int pass_ray_bounces;
#endif
+
+ /* viewport rendering options */
+ int display_pass_stride;
+ int display_pass_components;
+ int display_divide_pass_stride;
+ int use_display_exposure;
+ int use_display_pass_alpha;
} KernelFilm;
static_assert_align(KernelFilm, 16);
@@ -1335,9 +1365,12 @@ typedef enum KernelBVHLayout {
BVH_LAYOUT_BVH2 = (1 << 0),
BVH_LAYOUT_BVH4 = (1 << 1),
BVH_LAYOUT_BVH8 = (1 << 2),
+
BVH_LAYOUT_EMBREE = (1 << 3),
+ BVH_LAYOUT_OPTIX = (1 << 4),
+
BVH_LAYOUT_DEFAULT = BVH_LAYOUT_BVH8,
- BVH_LAYOUT_ALL = (unsigned int)(-1),
+ BVH_LAYOUT_ALL = (unsigned int)(~0u),
} KernelBVHLayout;
typedef struct KernelBVH {
@@ -1349,14 +1382,18 @@ typedef struct KernelBVH {
int bvh_layout;
int use_bvh_steps;
- /* Embree */
-#ifdef __EMBREE__
+ /* Custom BVH */
+#ifdef __KERNEL_OPTIX__
+ OptixTraversableHandle scene;
+#else
+# ifdef __EMBREE__
RTCScene scene;
-# ifndef __KERNEL_64_BIT__
- int pad1;
+# ifndef __KERNEL_64_BIT__
+ int pad2;
+# endif
+# else
+ int scene, pad2;
# endif
-#else
- int pad1, pad2;
#endif
} KernelBVH;
static_assert_align(KernelBVH, 16);
diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h
index 2705526abe4..4ddcbec0fef 100644
--- a/intern/cycles/kernel/kernel_volume.h
+++ b/intern/cycles/kernel/kernel_volume.h
@@ -428,7 +428,7 @@ kernel_volume_integrate_homogeneous(KernelGlobals *kg,
ccl_addr_space float3 *throughput,
bool probalistic_scatter)
{
- VolumeShaderCoefficients coeff;
+ VolumeShaderCoefficients coeff ccl_optional_struct_init;
if (!volume_shader_sample(kg, sd, state, ray->P, &coeff))
return VOLUME_PATH_MISSED;
@@ -565,7 +565,7 @@ kernel_volume_integrate_heterogeneous_distance(KernelGlobals *kg,
}
float3 new_P = ray->P + ray->D * (t + step_offset);
- VolumeShaderCoefficients coeff;
+ VolumeShaderCoefficients coeff ccl_optional_struct_init;
/* compute segment */
if (volume_shader_sample(kg, sd, state, new_P, &coeff)) {
@@ -801,7 +801,7 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg,
}
float3 new_P = ray->P + ray->D * (t + step_offset);
- VolumeShaderCoefficients coeff;
+ VolumeShaderCoefficients coeff ccl_optional_struct_init;
/* compute segment */
if (volume_shader_sample(kg, sd, state, new_P, &coeff)) {
diff --git a/intern/cycles/kernel/kernels/optix/kernel_optix.cu b/intern/cycles/kernel/kernels/optix/kernel_optix.cu
new file mode 100644
index 00000000000..c7223a49d79
--- /dev/null
+++ b/intern/cycles/kernel/kernels/optix/kernel_optix.cu
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2019, NVIDIA Corporation.
+ * Copyright 2019, Blender Foundation.
+ *
+ * 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.
+ */
+
+#include "kernel/kernel_compat_optix.h"
+#include "util/util_atomic.h"
+#include "kernel/kernel_types.h"
+#include "kernel/kernel_globals.h"
+#include "../cuda/kernel_cuda_image.h" // Texture lookup uses normal CUDA intrinsics
+
+#include "kernel/kernel_path.h"
+#include "kernel/kernel_bake.h"
+
+template<typename T> ccl_device_forceinline T *get_payload_ptr_0()
+{
+ return (T *)(((uint64_t)optixGetPayload_1() << 32) | optixGetPayload_0());
+}
+template<typename T> ccl_device_forceinline T *get_payload_ptr_2()
+{
+ return (T *)(((uint64_t)optixGetPayload_3() << 32) | optixGetPayload_2());
+}
+
+template<bool always = false> ccl_device_forceinline uint get_object_id()
+{
+#ifdef __OBJECT_MOTION__
+ // Always get the the instance ID from the TLAS
+ // There might be a motion transform node between TLAS and BLAS which does not have one
+ uint object = optixGetInstanceIdFromHandle(optixGetTransformListHandle(0));
+#else
+ uint object = optixGetInstanceId();
+#endif
+ // Choose between always returning object ID or only for instances
+ if (always)
+ // Can just remove the high bit since instace always contains object ID
+ return object & 0x7FFFFF;
+ // Set to OBJECT_NONE if this is not an instanced object
+ else if (object & 0x800000)
+ object = OBJECT_NONE;
+ return object;
+}
+
+extern "C" __global__ void __raygen__kernel_optix_path_trace()
+{
+ KernelGlobals kg; // Allocate stack storage for common data
+
+ const uint3 launch_index = optixGetLaunchIndex();
+ // Keep threads for same pixel together to improve occupancy of warps
+ uint pixel_offset = launch_index.x / __params.tile.num_samples;
+ uint sample_offset = launch_index.x % __params.tile.num_samples;
+
+ kernel_path_trace(&kg,
+ __params.tile.buffer,
+ __params.tile.start_sample + sample_offset,
+ __params.tile.x + pixel_offset,
+ __params.tile.y + launch_index.y,
+ __params.tile.offset,
+ __params.tile.stride);
+}
+
+#ifdef __BAKING__
+extern "C" __global__ void __raygen__kernel_optix_bake()
+{
+ KernelGlobals kg;
+ const ShaderParams &p = __params.shader;
+ kernel_bake_evaluate(&kg,
+ p.input,
+ p.output,
+ (ShaderEvalType)p.type,
+ p.filter,
+ p.sx + optixGetLaunchIndex().x,
+ p.offset,
+ p.sample);
+}
+#endif
+
+extern "C" __global__ void __raygen__kernel_optix_displace()
+{
+ KernelGlobals kg;
+ const ShaderParams &p = __params.shader;
+ kernel_displace_evaluate(&kg, p.input, p.output, p.sx + optixGetLaunchIndex().x);
+}
+
+extern "C" __global__ void __raygen__kernel_optix_background()
+{
+ KernelGlobals kg;
+ const ShaderParams &p = __params.shader;
+ kernel_background_evaluate(&kg, p.input, p.output, p.sx + optixGetLaunchIndex().x);
+}
+
+extern "C" __global__ void __miss__kernel_optix_miss()
+{
+ // 'kernel_path_lamp_emission' checks intersection distance, so need to set it even on a miss
+ optixSetPayload_0(__float_as_uint(optixGetRayTmax()));
+ optixSetPayload_5(PRIMITIVE_NONE);
+}
+
+extern "C" __global__ void __anyhit__kernel_optix_local_hit()
+{
+#ifdef __BVH_LOCAL__
+ const uint object = get_object_id<true>();
+ if (object != optixGetPayload_4() /* local_object */) {
+ // Only intersect with matching object
+ return optixIgnoreIntersection();
+ }
+
+ int hit = 0;
+ uint *const lcg_state = get_payload_ptr_0<uint>();
+ LocalIntersection *const local_isect = get_payload_ptr_2<LocalIntersection>();
+
+ if (lcg_state) {
+ const uint max_hits = optixGetPayload_5();
+ for (int i = min(max_hits, local_isect->num_hits) - 1; i >= 0; --i) {
+ if (optixGetRayTmax() == local_isect->hits[i].t) {
+ return optixIgnoreIntersection();
+ }
+ }
+
+ hit = local_isect->num_hits++;
+
+ if (local_isect->num_hits > max_hits) {
+ hit = lcg_step_uint(lcg_state) % local_isect->num_hits;
+ if (hit >= max_hits) {
+ return optixIgnoreIntersection();
+ }
+ }
+ }
+ else {
+ if (local_isect->num_hits && optixGetRayTmax() > local_isect->hits[0].t) {
+ // Record closest intersection only (do not terminate ray here, since there is no guarantee
+ // about distance ordering in anyhit)
+ return optixIgnoreIntersection();
+ }
+
+ local_isect->num_hits = 1;
+ }
+
+ Intersection *isect = &local_isect->hits[hit];
+ isect->t = optixGetRayTmax();
+ isect->prim = optixGetPrimitiveIndex();
+ isect->object = get_object_id();
+ isect->type = kernel_tex_fetch(__prim_type, isect->prim);
+
+ if (optixIsTriangleHit()) {
+ const float2 barycentrics = optixGetTriangleBarycentrics();
+ isect->u = 1.0f - barycentrics.y - barycentrics.x;
+ isect->v = barycentrics.x;
+ }
+ else {
+ isect->u = __uint_as_float(optixGetAttribute_0());
+ isect->v = __uint_as_float(optixGetAttribute_1());
+ }
+
+ // Record geometric normal
+ const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, isect->prim);
+ const float3 tri_a = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex + 0));
+ const float3 tri_b = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex + 1));
+ const float3 tri_c = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex + 2));
+ local_isect->Ng[hit] = normalize(cross(tri_b - tri_a, tri_c - tri_a));
+
+ // Continue tracing (without this the trace call would return after the first hit)
+ optixIgnoreIntersection();
+#endif
+}
+
+extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit()
+{
+#ifdef __SHADOW_RECORD_ALL__
+ const uint prim = optixGetPrimitiveIndex();
+# ifdef __VISIBILITY_FLAG__
+ const uint visibility = optixGetPayload_4();
+ if ((kernel_tex_fetch(__prim_visibility, prim) & visibility) == 0) {
+ return optixIgnoreIntersection();
+ }
+# endif
+
+ // Offset into array with num_hits
+ Intersection *const isect = get_payload_ptr_0<Intersection>() + optixGetPayload_2();
+ isect->t = optixGetRayTmax();
+ isect->prim = prim;
+ isect->object = get_object_id();
+ isect->type = kernel_tex_fetch(__prim_type, prim);
+
+ if (optixIsTriangleHit()) {
+ const float2 barycentrics = optixGetTriangleBarycentrics();
+ isect->u = 1.0f - barycentrics.y - barycentrics.x;
+ isect->v = barycentrics.x;
+ }
+ else {
+ isect->u = __uint_as_float(optixGetAttribute_0());
+ isect->v = __uint_as_float(optixGetAttribute_1());
+ }
+
+# ifdef __TRANSPARENT_SHADOWS__
+ // Detect if this surface has a shader with transparent shadows
+ if (!shader_transparent_shadow(NULL, isect) || optixGetPayload_2() >= optixGetPayload_3()) {
+# endif
+ // This is an opaque hit or the hit limit has been reached, abort traversal
+ optixSetPayload_5(true);
+ return optixTerminateRay();
+# ifdef __TRANSPARENT_SHADOWS__
+ }
+
+ // TODO(pmours): Do we need REQUIRE_UNIQUE_ANYHIT for this to work?
+ optixSetPayload_2(optixGetPayload_2() + 1); // num_hits++
+
+ // Continue tracing
+ optixIgnoreIntersection();
+# endif
+#endif
+}
+
+extern "C" __global__ void __anyhit__kernel_optix_visibility_test()
+{
+ uint visibility = optixGetPayload_4();
+#ifdef __VISIBILITY_FLAG__
+ const uint prim = optixGetPrimitiveIndex();
+ if ((kernel_tex_fetch(__prim_visibility, prim) & visibility) == 0)
+ return optixIgnoreIntersection();
+#endif
+
+ // Shadow ray early termination
+ if (visibility & PATH_RAY_SHADOW_OPAQUE)
+ return optixTerminateRay();
+}
+
+extern "C" __global__ void __closesthit__kernel_optix_hit()
+{
+ optixSetPayload_0(__float_as_uint(optixGetRayTmax())); // Intersection distance
+ optixSetPayload_3(optixGetPrimitiveIndex());
+ optixSetPayload_4(get_object_id());
+ // Can be PRIMITIVE_TRIANGLE and PRIMITIVE_MOTION_TRIANGLE or curve type and segment index
+ optixSetPayload_5(kernel_tex_fetch(__prim_type, optixGetPrimitiveIndex()));
+
+ if (optixIsTriangleHit()) {
+ const float2 barycentrics = optixGetTriangleBarycentrics();
+ optixSetPayload_1(__float_as_uint(1.0f - barycentrics.y - barycentrics.x));
+ optixSetPayload_2(__float_as_uint(barycentrics.x));
+ }
+ else {
+ optixSetPayload_1(optixGetAttribute_0());
+ optixSetPayload_2(optixGetAttribute_1());
+ }
+}
+
+#ifdef __HAIR__
+extern "C" __global__ void __intersection__curve()
+{
+ const uint prim = optixGetPrimitiveIndex();
+ const uint object = get_object_id<true>();
+ const uint type = kernel_tex_fetch(__prim_type, prim);
+ const uint visibility = optixGetPayload_4();
+
+ const float3 P = optixGetObjectRayOrigin();
+ const float3 dir = optixGetObjectRayDirection();
+
+# ifdef __OBJECT_MOTION__
+ const float time = optixGetRayTime();
+# else
+ const float time = 0.0f;
+# endif
+
+ Intersection isect;
+ isect.t = optixGetRayTmax();
+
+ if (!(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) ?
+ curve_intersect(NULL, &isect, P, dir, visibility, object, prim, time, type) :
+ cardinal_curve_intersect(NULL, &isect, P, dir, visibility, object, prim, time, type)) {
+ optixReportIntersection(isect.t,
+ type & PRIMITIVE_ALL,
+ __float_as_int(isect.u), // Attribute_0
+ __float_as_int(isect.v)); // Attribute_1
+ }
+}
+#endif
+
+#ifdef __KERNEL_DEBUG__
+extern "C" __global__ void __exception__kernel_optix_exception()
+{
+ printf("Unhandled exception occured: code %d!\n", optixGetExceptionCode());
+}
+#endif
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
index 415de9cd66b..1b161fbc8ee 100644
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -483,6 +483,65 @@ static bool set_attribute_float3(float3 f, TypeDesc type, bool derivatives, void
return set_attribute_float3(fv, type, derivatives, val);
}
+/* Attributes with the TypeRGBA type descriptor should be retrieved and stored
+ * in a float array of size 4 (e.g. node_vertex_color.osl), this array have
+ * a type descriptor TypeFloatArray4. If the storage is not a TypeFloatArray4,
+ * we either store the first three components in a vector, store the average of
+ * the components in a float, or fail the retrieval and do nothing. We allow
+ * this for the correct operation of the Attribute node.
+ */
+
+static bool set_attribute_float4(float4 f[3], TypeDesc type, bool derivatives, void *val)
+{
+ float *fval = (float *)val;
+ if (type == TypeFloatArray4) {
+ fval[0] = f[0].x;
+ fval[1] = f[0].y;
+ fval[2] = f[0].z;
+ fval[3] = f[0].w;
+
+ if (derivatives) {
+ fval[4] = f[1].x;
+ fval[5] = f[1].y;
+ fval[6] = f[1].z;
+ fval[7] = f[1].w;
+
+ fval[8] = f[2].x;
+ fval[9] = f[2].y;
+ fval[10] = f[2].z;
+ fval[11] = f[2].w;
+ }
+ return true;
+ }
+ else if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
+ type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor) {
+ fval[0] = f[0].x;
+ fval[1] = f[0].y;
+ fval[2] = f[0].z;
+
+ if (derivatives) {
+ fval[3] = f[1].x;
+ fval[4] = f[1].y;
+ fval[5] = f[1].z;
+
+ fval[6] = f[2].x;
+ fval[7] = f[2].y;
+ fval[8] = f[2].z;
+ }
+ return true;
+ }
+ else if (type == TypeDesc::TypeFloat) {
+ fval[0] = average(float4_to_float3(f[0]));
+
+ if (derivatives) {
+ fval[1] = average(float4_to_float3(f[1]));
+ fval[2] = average(float4_to_float3(f[2]));
+ }
+ return true;
+ }
+ return false;
+}
+
static bool set_attribute_float(float f[3], TypeDesc type, bool derivatives, void *val)
{
if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
@@ -629,6 +688,12 @@ static bool get_primitive_attribute(KernelGlobals *kg,
kg, sd, attr.desc, (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
return set_attribute_float(fval, type, derivatives, val);
}
+ else if (attr.type == TypeRGBA) {
+ float4 fval[3];
+ fval[0] = primitive_attribute_float4(
+ kg, sd, attr.desc, (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
+ return set_attribute_float4(fval, type, derivatives, val);
+ }
else {
return false;
}
diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt
index c50bffe27b2..f4258da70d3 100644
--- a/intern/cycles/kernel/shaders/CMakeLists.txt
+++ b/intern/cycles/kernel/shaders/CMakeLists.txt
@@ -80,6 +80,7 @@ set(SRC_OSL
node_vector_math.osl
node_vector_transform.osl
node_velvet_bsdf.osl
+ node_vertex_color.osl
node_voronoi_texture.osl
node_voxel_texture.osl
node_wavelength.osl
@@ -97,10 +98,13 @@ set(SRC_OSL
set(SRC_OSL_HEADERS
node_color.h
node_fresnel.h
+ node_hash.h
+ node_noise.h
node_ramp_util.h
- node_texture.h
stdosl.h
oslutil.h
+ vector2.h
+ vector4.h
)
set(SRC_OSO
diff --git a/intern/cycles/kernel/shaders/node_brick_texture.osl b/intern/cycles/kernel/shaders/node_brick_texture.osl
index 0abc3574c48..30644ef2ff3 100644
--- a/intern/cycles/kernel/shaders/node_brick_texture.osl
+++ b/intern/cycles/kernel/shaders/node_brick_texture.osl
@@ -15,7 +15,6 @@
*/
#include "stdosl.h"
-#include "node_texture.h"
/* Brick */
diff --git a/intern/cycles/kernel/shaders/node_checker_texture.osl b/intern/cycles/kernel/shaders/node_checker_texture.osl
index e068f7952ed..e05cf20099f 100644
--- a/intern/cycles/kernel/shaders/node_checker_texture.osl
+++ b/intern/cycles/kernel/shaders/node_checker_texture.osl
@@ -15,7 +15,6 @@
*/
#include "stdosl.h"
-#include "node_texture.h"
/* Checker */
diff --git a/intern/cycles/kernel/shaders/node_gradient_texture.osl b/intern/cycles/kernel/shaders/node_gradient_texture.osl
index 52bf466673d..5cc81d367f2 100644
--- a/intern/cycles/kernel/shaders/node_gradient_texture.osl
+++ b/intern/cycles/kernel/shaders/node_gradient_texture.osl
@@ -15,7 +15,6 @@
*/
#include "stdosl.h"
-#include "node_texture.h"
/* Gradient */
diff --git a/intern/cycles/kernel/shaders/node_hash.h b/intern/cycles/kernel/shaders/node_hash.h
new file mode 100644
index 00000000000..7affe432bf2
--- /dev/null
+++ b/intern/cycles/kernel/shaders/node_hash.h
@@ -0,0 +1,81 @@
+#include "stdosl.h"
+#include "vector2.h"
+#include "vector4.h"
+
+#define vector3 point
+
+/* **** Hash a float or vector[234] into a float [0, 1] **** */
+
+float hash_float_to_float(float k)
+{
+ return hashnoise(k);
+}
+
+float hash_vector2_to_float(vector2 k)
+{
+ return hashnoise(k.x, k.y);
+}
+
+float hash_vector3_to_float(vector3 k)
+{
+ return hashnoise(k);
+}
+
+float hash_vector4_to_float(vector4 k)
+{
+ return hashnoise(vector3(k.x, k.y, k.z), k.w);
+}
+
+/* **** Hash a vector[234] into a vector[234] [0, 1] **** */
+
+vector2 hash_vector2_to_vector2(vector2 k)
+{
+ return vector2(hash_vector2_to_float(k), hash_vector3_to_float(vector3(k.x, k.y, 1.0)));
+}
+
+vector3 hash_vector3_to_vector3(vector3 k)
+{
+ return vector3(hash_vector3_to_float(k),
+ hash_vector4_to_float(vector4(k[0], k[1], k[2], 1.0)),
+ hash_vector4_to_float(vector4(k[0], k[1], k[2], 2.0)));
+}
+
+vector4 hash_vector4_to_vector4(vector4 k)
+{
+ return vector4(hash_vector4_to_float(k),
+ hash_vector4_to_float(vector4(k.w, k.x, k.y, k.z)),
+ hash_vector4_to_float(vector4(k.z, k.w, k.x, k.y)),
+ hash_vector4_to_float(vector4(k.y, k.z, k.w, k.x)));
+}
+
+/* **** Hash a float or a vec[234] into a color [0, 1] **** */
+
+color hash_float_to_color(float k)
+{
+ return color(hash_float_to_float(k),
+ hash_vector2_to_float(vector2(k, 1.0)),
+ hash_vector2_to_float(vector2(k, 2.0)));
+}
+
+color hash_vector2_to_color(vector2 k)
+{
+ return color(hash_vector2_to_float(k),
+ hash_vector3_to_float(vector3(k.x, k.y, 1.0)),
+ hash_vector3_to_float(vector3(k.x, k.y, 2.0)));
+}
+
+color hash_vector3_to_color(vector3 k)
+{
+ return color(hash_vector3_to_float(k),
+ hash_vector4_to_float(vector4(k[0], k[1], k[2], 1.0)),
+ hash_vector4_to_float(vector4(k[0], k[1], k[2], 2.0)));
+}
+
+color hash_vector4_to_color(vector4 k)
+{
+ return color(hash_vector4_to_float(k),
+ hash_vector4_to_float(vector4(k.z, k.x, k.w, k.y)),
+ hash_vector4_to_float(vector4(k.w, k.z, k.y, k.x)));
+}
+
+#undef vector3
diff --git a/intern/cycles/kernel/shaders/node_ies_light.osl b/intern/cycles/kernel/shaders/node_ies_light.osl
index ce0173451da..6e9181cde40 100644
--- a/intern/cycles/kernel/shaders/node_ies_light.osl
+++ b/intern/cycles/kernel/shaders/node_ies_light.osl
@@ -15,7 +15,6 @@
*/
#include "stdosl.h"
-#include "node_texture.h"
/* IES Light */
diff --git a/intern/cycles/kernel/shaders/node_magic_texture.osl b/intern/cycles/kernel/shaders/node_magic_texture.osl
index aa700e575ef..26e7d57278b 100644
--- a/intern/cycles/kernel/shaders/node_magic_texture.osl
+++ b/intern/cycles/kernel/shaders/node_magic_texture.osl
@@ -15,7 +15,6 @@
*/
#include "stdosl.h"
-#include "node_texture.h"
/* Magic */
diff --git a/intern/cycles/kernel/shaders/node_mapping.osl b/intern/cycles/kernel/shaders/node_mapping.osl
index f5cc2d1c5dd..8eed0ae9c48 100644
--- a/intern/cycles/kernel/shaders/node_mapping.osl
+++ b/intern/cycles/kernel/shaders/node_mapping.osl
@@ -16,17 +16,58 @@
#include "stdosl.h"
-shader node_mapping(matrix Matrix = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- point mapping_min = point(0.0, 0.0, 0.0),
- point mapping_max = point(0.0, 0.0, 0.0),
- int use_minmax = 0,
- point VectorIn = point(0.0, 0.0, 0.0),
- output point VectorOut = point(0.0, 0.0, 0.0))
+point safe_divide(point a, point b)
+{
+ return point((b[0] != 0.0) ? a[0] / b[0] : 0.0,
+ (b[1] != 0.0) ? a[1] / b[1] : 0.0,
+ (b[2] != 0.0) ? a[2] / b[2] : 0.0);
+}
+
+matrix euler_to_mat(point euler)
{
- point p = transform(Matrix, VectorIn);
+ float cx = cos(euler[0]);
+ float cy = cos(euler[1]);
+ float cz = cos(euler[2]);
+ float sx = sin(euler[0]);
+ float sy = sin(euler[1]);
+ float sz = sin(euler[2]);
+
+ matrix mat = matrix(1.0);
+ mat[0][0] = cy * cz;
+ mat[0][1] = cy * sz;
+ mat[0][2] = -sy;
- if (use_minmax)
- p = min(max(mapping_min, p), mapping_max);
+ mat[1][0] = sy * sx * cz - cx * sz;
+ mat[1][1] = sy * sx * sz + cx * cz;
+ mat[1][2] = cy * sx;
- VectorOut = p;
+ mat[2][0] = sy * cx * cz + sx * sz;
+ mat[2][1] = sy * cx * sz - sx * cz;
+ mat[2][2] = cy * cx;
+ return mat;
+}
+
+shader node_mapping(string type = "point",
+ point VectorIn = point(0.0, 0.0, 0.0),
+ point Location = point(0.0, 0.0, 0.0),
+ point Rotation = point(0.0, 0.0, 0.0),
+ point Scale = point(1.0, 1.0, 1.0),
+ output point VectorOut = point(0.0, 0.0, 0.0))
+{
+ if (type == "point") {
+ VectorOut = transform(euler_to_mat(Rotation), (VectorIn * Scale)) + Location;
+ }
+ else if (type == "texture") {
+ VectorOut = safe_divide(transform(transpose(euler_to_mat(Rotation)), (VectorIn - Location)),
+ Scale);
+ }
+ else if (type == "vector") {
+ VectorOut = transform(euler_to_mat(Rotation), (VectorIn * Scale));
+ }
+ else if (type == "normal") {
+ VectorOut = normalize(transform(euler_to_mat(Rotation), safe_divide(VectorIn, Scale)));
+ }
+ else {
+ warning("%s", "Unknown Mapping vector type!");
+ }
}
diff --git a/intern/cycles/kernel/shaders/node_musgrave_texture.osl b/intern/cycles/kernel/shaders/node_musgrave_texture.osl
index a7877c43d46..8861f9a671a 100644
--- a/intern/cycles/kernel/shaders/node_musgrave_texture.osl
+++ b/intern/cycles/kernel/shaders/node_musgrave_texture.osl
@@ -15,9 +15,343 @@
*/
#include "stdosl.h"
-#include "node_texture.h"
+#include "node_noise.h"
+#include "vector2.h"
+#include "vector4.h"
-/* Musgrave fBm
+#define vector3 point
+
+/* 1D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+float noise_musgrave_fBm_1d(float co, float H, float lacunarity, float octaves)
+{
+ float p = co;
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value += safe_snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * safe_snoise(p) * pwr;
+ }
+
+ return value;
+}
+
+/* 1D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+float noise_musgrave_multi_fractal_1d(float co, float H, float lacunarity, float octaves)
+{
+ float p = co;
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value *= (pwr * safe_snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * safe_snoise(p) + 1.0); /* correct? */
+ }
+
+ return value;
+}
+
+/* 1D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_hetero_terrain_1d(
+ float co, float H, float lacunarity, float octaves, float offset)
+{
+ float p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + safe_snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ float increment = (safe_snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float increment = (safe_snoise(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+/* 1D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_hybrid_multi_fractal_1d(
+ float co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = safe_snoise(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ float signal = (safe_snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * ((safe_snoise(p) + offset) * pwr);
+ }
+
+ return value;
+}
+
+/* 1D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_ridged_multi_fractal_1d(
+ float co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - fabs(safe_snoise(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - fabs(safe_snoise(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return value;
+}
+
+/* 2D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+float noise_musgrave_fBm_2d(vector2 co, float H, float lacunarity, float octaves)
+{
+ vector2 p = co;
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value += safe_snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * safe_snoise(p) * pwr;
+ }
+
+ return value;
+}
+
+/* 2D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+float noise_musgrave_multi_fractal_2d(vector2 co, float H, float lacunarity, float octaves)
+{
+ vector2 p = co;
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value *= (pwr * safe_snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * safe_snoise(p) + 1.0); /* correct? */
+ }
+
+ return value;
+}
+
+/* 2D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_hetero_terrain_2d(
+ vector2 co, float H, float lacunarity, float octaves, float offset)
+{
+ vector2 p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + safe_snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ float increment = (safe_snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float increment = (safe_snoise(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+/* 2D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_hybrid_multi_fractal_2d(
+ vector2 co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ vector2 p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = safe_snoise(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ float signal = (safe_snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * ((safe_snoise(p) + offset) * pwr);
+ }
+
+ return value;
+}
+
+/* 2D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_ridged_multi_fractal_2d(
+ vector2 co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ vector2 p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - fabs(safe_snoise(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - fabs(safe_snoise(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return value;
+}
+
+/* 3D Musgrave fBm
*
* H: fractal increment parameter
* lacunarity: gap between successive frequencies
@@ -26,58 +360,56 @@
* from "Texturing and Modelling: A procedural approach"
*/
-float noise_musgrave_fBm(point ip, float H, float lacunarity, float octaves)
+float noise_musgrave_fBm_3d(vector3 co, float H, float lacunarity, float octaves)
{
- float rmd;
+ vector3 p = co;
float value = 0.0;
float pwr = 1.0;
float pwHL = pow(lacunarity, -H);
- int i;
- point p = ip;
- for (i = 0; i < (int)octaves; i++) {
- value += safe_noise(p, "signed") * pwr;
+ for (int i = 0; i < (int)octaves; i++) {
+ value += safe_snoise(p) * pwr;
pwr *= pwHL;
p *= lacunarity;
}
- rmd = octaves - floor(octaves);
- if (rmd != 0.0)
- value += rmd * safe_noise(p, "signed") * pwr;
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * safe_snoise(p) * pwr;
+ }
return value;
}
-/* Musgrave Multifractal
+/* 3D Musgrave Multifractal
*
* H: highest fractal dimension
* lacunarity: gap between successive frequencies
* octaves: number of frequencies in the fBm
*/
-float noise_musgrave_multi_fractal(point ip, float H, float lacunarity, float octaves)
+float noise_musgrave_multi_fractal_3d(vector3 co, float H, float lacunarity, float octaves)
{
- float rmd;
+ vector3 p = co;
float value = 1.0;
float pwr = 1.0;
float pwHL = pow(lacunarity, -H);
- int i;
- point p = ip;
- for (i = 0; i < (int)octaves; i++) {
- value *= (pwr * safe_noise(p, "signed") + 1.0);
+ for (int i = 0; i < (int)octaves; i++) {
+ value *= (pwr * safe_snoise(p) + 1.0);
pwr *= pwHL;
p *= lacunarity;
}
- rmd = octaves - floor(octaves);
- if (rmd != 0.0)
- value *= (rmd * pwr * safe_noise(p, "signed") + 1.0); /* correct? */
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * safe_snoise(p) + 1.0); /* correct? */
+ }
return value;
}
-/* Musgrave Heterogeneous Terrain
+/* 3D Musgrave Heterogeneous Terrain
*
* H: fractal dimension of the roughest area
* lacunarity: gap between successive frequencies
@@ -85,36 +417,34 @@ float noise_musgrave_multi_fractal(point ip, float H, float lacunarity, float oc
* offset: raises the terrain from `sea level'
*/
-float noise_musgrave_hetero_terrain(
- point ip, float H, float lacunarity, float octaves, float offset)
+float noise_musgrave_hetero_terrain_3d(
+ vector3 co, float H, float lacunarity, float octaves, float offset)
{
- float value, increment, rmd;
+ vector3 p = co;
float pwHL = pow(lacunarity, -H);
float pwr = pwHL;
- int i;
- point p = ip;
/* first unscaled octave of function; later octaves are scaled */
- value = offset + safe_noise(p, "signed");
+ float value = offset + safe_snoise(p);
p *= lacunarity;
- for (i = 1; i < (int)octaves; i++) {
- increment = (safe_noise(p, "signed") + offset) * pwr * value;
+ for (int i = 1; i < (int)octaves; i++) {
+ float increment = (safe_snoise(p) + offset) * pwr * value;
value += increment;
pwr *= pwHL;
p *= lacunarity;
}
- rmd = octaves - floor(octaves);
+ float rmd = octaves - floor(octaves);
if (rmd != 0.0) {
- increment = (safe_noise(p, "signed") + offset) * pwr * value;
+ float increment = (safe_snoise(p) + offset) * pwr * value;
value += rmd * increment;
}
return value;
}
-/* Hybrid Additive/Multiplicative Multifractal Terrain
+/* 3D Hybrid Additive/Multiplicative Multifractal Terrain
*
* H: fractal dimension of the roughest area
* lacunarity: gap between successive frequencies
@@ -122,38 +452,38 @@ float noise_musgrave_hetero_terrain(
* offset: raises the terrain from `sea level'
*/
-float noise_musgrave_hybrid_multi_fractal(
- point ip, float H, float lacunarity, float octaves, float offset, float gain)
+float noise_musgrave_hybrid_multi_fractal_3d(
+ vector3 co, float H, float lacunarity, float octaves, float offset, float gain)
{
- float result, signal, weight, rmd;
+ vector3 p = co;
float pwHL = pow(lacunarity, -H);
float pwr = pwHL;
- int i;
- point p = ip;
- result = safe_noise(p, "signed") + offset;
- weight = gain * result;
+ float value = safe_snoise(p) + offset;
+ float weight = gain * value;
p *= lacunarity;
- for (i = 1; (weight > 0.001) && (i < (int)octaves); i++) {
- if (weight > 1.0)
+ for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) {
+ if (weight > 1.0) {
weight = 1.0;
+ }
- signal = (safe_noise(p, "signed") + offset) * pwr;
+ float signal = (safe_snoise(p) + offset) * pwr;
pwr *= pwHL;
- result += weight * signal;
+ value += weight * signal;
weight *= gain * signal;
p *= lacunarity;
}
- rmd = octaves - floor(octaves);
- if (rmd != 0.0)
- result += rmd * ((safe_noise(p, "signed") + offset) * pwr);
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * ((safe_snoise(p) + offset) * pwr);
+ }
- return result;
+ return value;
}
-/* Ridged Multifractal Terrain
+/* 3D Ridged Multifractal Terrain
*
* H: fractal dimension of the roughest area
* lacunarity: gap between successive frequencies
@@ -161,73 +491,313 @@ float noise_musgrave_hybrid_multi_fractal(
* offset: raises the terrain from `sea level'
*/
-float noise_musgrave_ridged_multi_fractal(
- point ip, float H, float lacunarity, float octaves, float offset, float gain)
+float noise_musgrave_ridged_multi_fractal_3d(
+ vector3 co, float H, float lacunarity, float octaves, float offset, float gain)
{
- float result, signal, weight;
+ vector3 p = co;
float pwHL = pow(lacunarity, -H);
float pwr = pwHL;
- int i;
- point p = ip;
- signal = offset - fabs(safe_noise(p, "signed"));
+ float signal = offset - fabs(safe_snoise(p));
signal *= signal;
- result = signal;
- weight = 1.0;
+ float value = signal;
+ float weight = 1.0;
- for (i = 1; i < (int)octaves; i++) {
+ for (int i = 1; i < (int)octaves; i++) {
p *= lacunarity;
weight = clamp(signal * gain, 0.0, 1.0);
- signal = offset - fabs(safe_noise(p, "signed"));
+ signal = offset - fabs(safe_snoise(p));
signal *= signal;
signal *= weight;
- result += signal * pwr;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return value;
+}
+
+/* 4D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+float noise_musgrave_fBm_4d(vector4 co, float H, float lacunarity, float octaves)
+{
+ vector4 p = co;
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value += safe_snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * safe_snoise(p) * pwr;
+ }
+
+ return value;
+}
+
+/* 4D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+float noise_musgrave_multi_fractal_4d(vector4 co, float H, float lacunarity, float octaves)
+{
+ vector4 p = co;
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value *= (pwr * safe_snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * safe_snoise(p) + 1.0); /* correct? */
+ }
+
+ return value;
+}
+
+/* 4D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_hetero_terrain_4d(
+ vector4 co, float H, float lacunarity, float octaves, float offset)
+{
+ vector4 p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + safe_snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ float increment = (safe_snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float increment = (safe_snoise(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+/* 4D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_hybrid_multi_fractal_4d(
+ vector4 co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ vector4 p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = safe_snoise(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ float signal = (safe_snoise(p) + offset) * pwr;
pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * ((safe_snoise(p) + offset) * pwr);
}
- return result;
+ return value;
}
-/* Shader */
+/* 4D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_ridged_multi_fractal_4d(
+ vector4 co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ vector4 p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - fabs(safe_snoise(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - fabs(safe_snoise(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return value;
+}
shader node_musgrave_texture(
int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
string type = "fBM",
+ string dimensions = "3D",
+ point Vector = P,
+ float W = 0.0,
float Dimension = 2.0,
- float Lacunarity = 1.0,
+ float Scale = 5.0,
float Detail = 2.0,
+ float Lacunarity = 1.0,
float Offset = 0.0,
float Gain = 1.0,
- float Scale = 5.0,
- point Vector = P,
- output float Fac = 0.0,
- output color Color = 0.0)
+ output float Fac = 0.0)
{
float dimension = max(Dimension, 1e-5);
float octaves = clamp(Detail, 0.0, 16.0);
float lacunarity = max(Lacunarity, 1e-5);
- float intensity = 1.0;
- point p = Vector;
+ vector3 s = Vector;
if (use_mapping)
- p = transform(mapping, p);
-
- p = p * Scale;
-
- if (type == "multifractal")
- Fac = intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves);
- else if (type == "fBM")
- Fac = intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves);
- else if (type == "hybrid_multifractal")
- Fac = intensity *
- noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, Offset, Gain);
- else if (type == "ridged_multifractal")
- Fac = intensity *
- noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, Offset, Gain);
- else if (type == "hetero_terrain")
- Fac = intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, Offset);
-
- Color = color(Fac, Fac, Fac);
+ s = transform(mapping, s);
+
+ if (dimensions == "1D") {
+ float p = W * Scale;
+ if (type == "multifractal") {
+ Fac = noise_musgrave_multi_fractal_1d(p, dimension, lacunarity, octaves);
+ }
+ else if (type == "fBM") {
+ Fac = noise_musgrave_fBm_1d(p, dimension, lacunarity, octaves);
+ }
+ else if (type == "hybrid_multifractal") {
+ Fac = noise_musgrave_hybrid_multi_fractal_1d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (type == "ridged_multifractal") {
+ Fac = noise_musgrave_ridged_multi_fractal_1d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (type == "hetero_terrain") {
+ Fac = noise_musgrave_hetero_terrain_1d(p, dimension, lacunarity, octaves, Offset);
+ }
+ else {
+ Fac = 0.0;
+ }
+ }
+ else if (dimensions == "2D") {
+ vector2 p = vector2(s[0], s[1]) * Scale;
+ if (type == "multifractal") {
+ Fac = noise_musgrave_multi_fractal_2d(p, dimension, lacunarity, octaves);
+ }
+ else if (type == "fBM") {
+ Fac = noise_musgrave_fBm_2d(p, dimension, lacunarity, octaves);
+ }
+ else if (type == "hybrid_multifractal") {
+ Fac = noise_musgrave_hybrid_multi_fractal_2d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (type == "ridged_multifractal") {
+ Fac = noise_musgrave_ridged_multi_fractal_2d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (type == "hetero_terrain") {
+ Fac = noise_musgrave_hetero_terrain_2d(p, dimension, lacunarity, octaves, Offset);
+ }
+ else {
+ Fac = 0.0;
+ }
+ }
+ else if (dimensions == "3D") {
+ vector3 p = s * Scale;
+ if (type == "multifractal") {
+ Fac = noise_musgrave_multi_fractal_3d(p, dimension, lacunarity, octaves);
+ }
+ else if (type == "fBM") {
+ Fac = noise_musgrave_fBm_3d(p, dimension, lacunarity, octaves);
+ }
+ else if (type == "hybrid_multifractal") {
+ Fac = noise_musgrave_hybrid_multi_fractal_3d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (type == "ridged_multifractal") {
+ Fac = noise_musgrave_ridged_multi_fractal_3d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (type == "hetero_terrain") {
+ Fac = noise_musgrave_hetero_terrain_3d(p, dimension, lacunarity, octaves, Offset);
+ }
+ else {
+ Fac = 0.0;
+ }
+ }
+ else if (dimensions == "4D") {
+ vector4 p = vector4(s[0], s[1], s[2], W) * Scale;
+ if (type == "multifractal") {
+ Fac = noise_musgrave_multi_fractal_4d(p, dimension, lacunarity, octaves);
+ }
+ else if (type == "fBM") {
+ Fac = noise_musgrave_fBm_4d(p, dimension, lacunarity, octaves);
+ }
+ else if (type == "hybrid_multifractal") {
+ Fac = noise_musgrave_hybrid_multi_fractal_4d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (type == "ridged_multifractal") {
+ Fac = noise_musgrave_ridged_multi_fractal_4d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (type == "hetero_terrain") {
+ Fac = noise_musgrave_hetero_terrain_4d(p, dimension, lacunarity, octaves, Offset);
+ }
+ else {
+ Fac = 0.0;
+ }
+ }
+ else {
+ Fac = 0.0;
+ }
}
diff --git a/intern/cycles/kernel/shaders/node_noise.h b/intern/cycles/kernel/shaders/node_noise.h
new file mode 100644
index 00000000000..23d1987a00e
--- /dev/null
+++ b/intern/cycles/kernel/shaders/node_noise.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * 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.
+ */
+
+#include "vector2.h"
+#include "vector4.h"
+
+#define vector3 point
+
+float safe_noise(float p)
+{
+ float f = noise("noise", p);
+ if (isinf(f))
+ return 0.5;
+ return f;
+}
+
+float safe_noise(vector2 p)
+{
+ float f = noise("noise", p.x, p.y);
+ if (isinf(f))
+ return 0.5;
+ return f;
+}
+
+float safe_noise(vector3 p)
+{
+ float f = noise("noise", p);
+ if (isinf(f))
+ return 0.5;
+ return f;
+}
+
+float safe_noise(vector4 p)
+{
+ float f = noise("noise", vector3(p.x, p.y, p.z), p.w);
+ if (isinf(f))
+ return 0.5;
+ return f;
+}
+
+float safe_snoise(float p)
+{
+ float f = noise("snoise", p);
+ if (isinf(f))
+ return 0.0;
+ return f;
+}
+
+float safe_snoise(vector2 p)
+{
+ float f = noise("snoise", p.x, p.y);
+ if (isinf(f))
+ return 0.0;
+ return f;
+}
+
+float safe_snoise(vector3 p)
+{
+ float f = noise("snoise", p);
+ if (isinf(f))
+ return 0.0;
+ return f;
+}
+
+float safe_snoise(vector4 p)
+{
+ float f = noise("snoise", vector3(p.x, p.y, p.z), p.w);
+ if (isinf(f))
+ return 0.0;
+ return f;
+}
+
+/* The fractal_noise functions are all exactly the same except for the input type. */
+float fractal_noise(float p, float details)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float sum = 0.0;
+ float octaves = clamp(details, 0.0, 16.0);
+ int n = (int)octaves;
+ for (int i = 0; i <= n; i++) {
+ float t = safe_noise(fscale * p);
+ sum += t * amp;
+ amp *= 0.5;
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = safe_noise(fscale * p);
+ float sum2 = sum + t * amp;
+ sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1));
+ sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1));
+ return (1.0 - rmd) * sum + rmd * sum2;
+ }
+ else {
+ sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1));
+ return sum;
+ }
+}
+
+/* The fractal_noise functions are all exactly the same except for the input type. */
+float fractal_noise(vector2 p, float details)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float sum = 0.0;
+ float octaves = clamp(details, 0.0, 16.0);
+ int n = (int)octaves;
+ for (int i = 0; i <= n; i++) {
+ float t = safe_noise(fscale * p);
+ sum += t * amp;
+ amp *= 0.5;
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = safe_noise(fscale * p);
+ float sum2 = sum + t * amp;
+ sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1));
+ sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1));
+ return (1.0 - rmd) * sum + rmd * sum2;
+ }
+ else {
+ sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1));
+ return sum;
+ }
+}
+
+/* The fractal_noise functions are all exactly the same except for the input type. */
+float fractal_noise(vector3 p, float details)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float sum = 0.0;
+ float octaves = clamp(details, 0.0, 16.0);
+ int n = (int)octaves;
+ for (int i = 0; i <= n; i++) {
+ float t = safe_noise(fscale * p);
+ sum += t * amp;
+ amp *= 0.5;
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = safe_noise(fscale * p);
+ float sum2 = sum + t * amp;
+ sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1));
+ sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1));
+ return (1.0 - rmd) * sum + rmd * sum2;
+ }
+ else {
+ sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1));
+ return sum;
+ }
+}
+
+/* The fractal_noise functions are all exactly the same except for the input type. */
+float fractal_noise(vector4 p, float details)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float sum = 0.0;
+ float octaves = clamp(details, 0.0, 16.0);
+ int n = (int)octaves;
+ for (int i = 0; i <= n; i++) {
+ float t = safe_noise(fscale * p);
+ sum += t * amp;
+ amp *= 0.5;
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = safe_noise(fscale * p);
+ float sum2 = sum + t * amp;
+ sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1));
+ sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1));
+ return (1.0 - rmd) * sum + rmd * sum2;
+ }
+ else {
+ sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1));
+ return sum;
+ }
+}
+
+#undef vector3
diff --git a/intern/cycles/kernel/shaders/node_noise_texture.osl b/intern/cycles/kernel/shaders/node_noise_texture.osl
index 2cbd571e206..e3da2d16371 100644
--- a/intern/cycles/kernel/shaders/node_noise_texture.osl
+++ b/intern/cycles/kernel/shaders/node_noise_texture.osl
@@ -15,46 +15,134 @@
*/
#include "stdosl.h"
-#include "node_texture.h"
+#include "vector2.h"
+#include "vector4.h"
+#include "node_noise.h"
-/* Noise */
+#define vector3 point
-float noise(point ip, float distortion, float detail, output color Color)
+/* The following offset functions generate random offsets to be added to texture
+ * coordinates to act as a seed since the noise functions don't have seed values.
+ * A seed value is needed for generating distortion textures and color outputs.
+ * The offset's components are in the range [100, 200], not too high to cause
+ * bad precision and not to small to be noticeable. We use float seed because
+ * OSL only support float hashes.
+ */
+
+float random_float_offset(float seed)
+{
+ return 100.0 + noise("hash", seed) * 100.0;
+}
+
+vector2 random_vector2_offset(float seed)
+{
+ return vector2(100.0 + noise("hash", seed, 0.0) * 100.0,
+ 100.0 + noise("hash", seed, 1.0) * 100.0);
+}
+
+vector3 random_vector3_offset(float seed)
{
- point r;
- point p = ip;
- int hard = 0;
+ return vector3(100.0 + noise("hash", seed, 0.0) * 100.0,
+ 100.0 + noise("hash", seed, 1.0) * 100.0,
+ 100.0 + noise("hash", seed, 2.0) * 100.0);
+}
+
+vector4 random_vector4_offset(float seed)
+{
+ return vector4(100.0 + noise("hash", seed, 0.0) * 100.0,
+ 100.0 + noise("hash", seed, 1.0) * 100.0,
+ 100.0 + noise("hash", seed, 2.0) * 100.0,
+ 100.0 + noise("hash", seed, 3.0) * 100.0);
+}
+
+float noise_texture(float co, float detail, float distortion, output color Color)
+{
+ float p = co;
+ if (distortion != 0.0) {
+ p += safe_noise(p + random_float_offset(0.0)) * distortion;
+ }
+ float value = fractal_noise(p, detail);
+ Color = color(value,
+ fractal_noise(p + random_float_offset(1.0), detail),
+ fractal_noise(p + random_float_offset(2.0), detail));
+ return value;
+}
+
+float noise_texture(vector2 co, float detail, float distortion, output color Color)
+{
+ vector2 p = co;
if (distortion != 0.0) {
- r[0] = safe_noise(p + point(13.5), "unsigned") * distortion;
- r[1] = safe_noise(p, "unsigned") * distortion;
- r[2] = safe_noise(p - point(13.5), "unsigned") * distortion;
+ p += vector2(safe_noise(p + random_vector2_offset(0.0)) * distortion,
+ safe_noise(p + random_vector2_offset(1.0)) * distortion);
+ }
- p += r;
+ float value = fractal_noise(p, detail);
+ Color = color(value,
+ fractal_noise(p + random_vector2_offset(2.0), detail),
+ fractal_noise(p + random_vector2_offset(3.0), detail));
+ return value;
+}
+
+float noise_texture(vector3 co, float detail, float distortion, output color Color)
+{
+ vector3 p = co;
+ if (distortion != 0.0) {
+ p += vector3(safe_noise(p + random_vector3_offset(0.0)) * distortion,
+ safe_noise(p + random_vector3_offset(1.0)) * distortion,
+ safe_noise(p + random_vector3_offset(2.0)) * distortion);
}
- float fac = noise_turbulence(p, detail, hard);
+ float value = fractal_noise(p, detail);
+ Color = color(value,
+ fractal_noise(p + random_vector3_offset(3.0), detail),
+ fractal_noise(p + random_vector3_offset(4.0), detail));
+ return value;
+}
- Color = color(fac,
- noise_turbulence(point(p[1], p[0], p[2]), detail, hard),
- noise_turbulence(point(p[1], p[2], p[0]), detail, hard));
+float noise_texture(vector4 co, float detail, float distortion, output color Color)
+{
+ vector4 p = co;
+ if (distortion != 0.0) {
+ p += vector4(safe_noise(p + random_vector4_offset(0.0)) * distortion,
+ safe_noise(p + random_vector4_offset(1.0)) * distortion,
+ safe_noise(p + random_vector4_offset(2.0)) * distortion,
+ safe_noise(p + random_vector4_offset(3.0)) * distortion);
+ }
- return fac;
+ float value = fractal_noise(p, detail);
+ Color = color(value,
+ fractal_noise(p + random_vector4_offset(4.0), detail),
+ fractal_noise(p + random_vector4_offset(5.0), detail));
+ return value;
}
shader node_noise_texture(int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- float Distortion = 0.0,
+ string dimensions = "3D",
+ vector3 Vector = vector3(0, 0, 0),
+ float W = 0.0,
float Scale = 5.0,
float Detail = 2.0,
- point Vector = P,
+ float Distortion = 0.0,
output float Fac = 0.0,
output color Color = 0.0)
{
- point p = Vector;
-
+ vector3 p = Vector;
if (use_mapping)
p = transform(mapping, p);
- Fac = noise(p * Scale, Distortion, Detail, Color);
+ p *= Scale;
+ float w = W * Scale;
+
+ if (dimensions == "1D")
+ Fac = noise_texture(w, Detail, Distortion, Color);
+ else if (dimensions == "2D")
+ Fac = noise_texture(vector2(p[0], p[1]), Detail, Distortion, Color);
+ else if (dimensions == "3D")
+ Fac = noise_texture(p, Detail, Distortion, Color);
+ else if (dimensions == "4D")
+ Fac = noise_texture(vector4(p[0], p[1], p[2], w), Detail, Distortion, Color);
+ else
+ error("Unknown dimension!");
}
diff --git a/intern/cycles/kernel/shaders/node_texture.h b/intern/cycles/kernel/shaders/node_texture.h
deleted file mode 100644
index e1f3b900ee5..00000000000
--- a/intern/cycles/kernel/shaders/node_texture.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * 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.
- */
-
-/* Voronoi / Worley like */
-
-color cellnoise_color(point p)
-{
- float r = cellnoise(p);
- float g = cellnoise(point(p[1], p[0], p[2]));
- float b = cellnoise(point(p[1], p[2], p[0]));
-
- return color(r, g, b);
-}
-
-void voronoi(point p, float e, float da[4], point pa[4])
-{
- /* returns distances in da and point coords in pa */
- int xx, yy, zz, xi, yi, zi;
-
- xi = (int)floor(p[0]);
- yi = (int)floor(p[1]);
- zi = (int)floor(p[2]);
-
- da[0] = 1e10;
- da[1] = 1e10;
- da[2] = 1e10;
- da[3] = 1e10;
-
- for (xx = xi - 1; xx <= xi + 1; xx++) {
- for (yy = yi - 1; yy <= yi + 1; yy++) {
- for (zz = zi - 1; zz <= zi + 1; zz++) {
- point ip = point(xx, yy, zz);
- point vp = (point)cellnoise_color(ip);
- point pd = p - (vp + ip);
- float d = dot(pd, pd);
-
- vp += point(xx, yy, zz);
-
- if (d < da[0]) {
- da[3] = da[2];
- da[2] = da[1];
- da[1] = da[0];
- da[0] = d;
-
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = pa[0];
- pa[0] = vp;
- }
- else if (d < da[1]) {
- da[3] = da[2];
- da[2] = da[1];
- da[1] = d;
-
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = vp;
- }
- else if (d < da[2]) {
- da[3] = da[2];
- da[2] = d;
-
- pa[3] = pa[2];
- pa[2] = vp;
- }
- else if (d < da[3]) {
- da[3] = d;
- pa[3] = vp;
- }
- }
- }
- }
-}
-
-/* Noise Bases */
-
-float safe_noise(point p, string type)
-{
- float f = 0.0;
-
- /* Perlin noise in range -1..1 */
- if (type == "signed")
- f = noise("perlin", p);
-
- /* Perlin noise in range 0..1 */
- else
- f = noise(p);
-
- /* can happen for big coordinates, things even out to 0.5 then anyway */
- if (!isfinite(f))
- return 0.5;
-
- return f;
-}
-
-/* Turbulence */
-
-float noise_turbulence(point p, float details, int hard)
-{
- float fscale = 1.0;
- float amp = 1.0;
- float sum = 0.0;
- int i, n;
-
- float octaves = clamp(details, 0.0, 16.0);
- n = (int)octaves;
-
- for (i = 0; i <= n; i++) {
- float t = safe_noise(fscale * p, "unsigned");
-
- if (hard)
- t = fabs(2.0 * t - 1.0);
-
- sum += t * amp;
- amp *= 0.5;
- fscale *= 2.0;
- }
-
- float rmd = octaves - floor(octaves);
-
- if (rmd != 0.0) {
- float t = safe_noise(fscale * p, "unsigned");
-
- if (hard)
- t = fabs(2.0 * t - 1.0);
-
- float sum2 = sum + t * amp;
-
- sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1));
- sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1));
-
- return (1.0 - rmd) * sum + rmd * sum2;
- }
- else {
- sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1));
- return sum;
- }
-}
-
-/* Utility */
-
-float nonzero(float f, float eps)
-{
- float r;
-
- if (abs(f) < eps)
- r = sign(f) * eps;
- else
- r = f;
-
- return r;
-}
diff --git a/intern/cycles/kernel/shaders/node_vertex_color.osl b/intern/cycles/kernel/shaders/node_vertex_color.osl
new file mode 100644
index 00000000000..16bf3dd146e
--- /dev/null
+++ b/intern/cycles/kernel/shaders/node_vertex_color.osl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * 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.
+ */
+
+#include "stdosl.h"
+
+shader node_vertex_color(string bump_offset = "center",
+ string layer_name = "",
+ output color Color = 0.0,
+ output float Alpha = 0.0)
+{
+ float vertex_color[4];
+ if (getattribute(layer_name, vertex_color)) {
+ Color = color(vertex_color[0], vertex_color[1], vertex_color[2]);
+ Alpha = vertex_color[3];
+
+ if (bump_offset == "dx") {
+ Color += Dx(Color);
+ Alpha += Dx(Alpha);
+ }
+ else if (bump_offset == "dy") {
+ Color += Dy(Color);
+ Alpha += Dy(Alpha);
+ }
+ }
+ else {
+ warning("%s", "Invalid attribute.");
+ }
+}
diff --git a/intern/cycles/kernel/shaders/node_voronoi_texture.osl b/intern/cycles/kernel/shaders/node_voronoi_texture.osl
index 34c86d5b98d..5de4aeef943 100644
--- a/intern/cycles/kernel/shaders/node_voronoi_texture.osl
+++ b/intern/cycles/kernel/shaders/node_voronoi_texture.osl
@@ -15,150 +15,1013 @@
*/
#include "stdosl.h"
-#include "node_texture.h"
-
-void voronoi_m(point p, string metric, float e, float da[4], point pa[4])
-{
- /* Compute the distance to and the position of the four closest neighbors to p.
- *
- * The neighbors are randomly placed, 1 each in a 3x3x3 grid (Worley pattern).
- * The distances and points are returned in ascending order, i.e. da[0] and pa[0] will
- * contain the distance to the closest point and its coordinates respectively.
- */
- int xx, yy, zz, xi, yi, zi;
-
- xi = (int)floor(p[0]);
- yi = (int)floor(p[1]);
- zi = (int)floor(p[2]);
-
- da[0] = 1e10;
- da[1] = 1e10;
- da[2] = 1e10;
- da[3] = 1e10;
-
- for (xx = xi - 1; xx <= xi + 1; xx++) {
- for (yy = yi - 1; yy <= yi + 1; yy++) {
- for (zz = zi - 1; zz <= zi + 1; zz++) {
- point ip = point(xx, yy, zz);
- point vp = (point)cellnoise_color(ip);
- point pd = p - (vp + ip);
-
- float d = 0.0;
- if (metric == "distance") {
- d = dot(pd, pd);
+#include "vector2.h"
+#include "vector4.h"
+#include "node_hash.h"
+
+#define vector3 point
+
+/* **** Distance Functions **** */
+
+float distance(float a, float b)
+{
+ return abs(a - b);
+}
+
+float distance(vector2 a, vector2 b)
+{
+ return length(a - b);
+}
+
+float distance(vector4 a, vector4 b)
+{
+ return length(a - b);
+}
+
+/* **** Safe Division **** */
+
+vector2 safe_divide(vector2 a, float b)
+{
+ return vector2((b != 0.0) ? a.x / b : 0.0, (b != 0.0) ? a.y / b : 0.0);
+}
+
+vector4 safe_divide(vector4 a, float b)
+{
+ return vector4((b != 0.0) ? a.x / b : 0.0,
+ (b != 0.0) ? a.y / b : 0.0,
+ (b != 0.0) ? a.z / b : 0.0,
+ (b != 0.0) ? a.w / b : 0.0);
+}
+
+/*
+ * Smooth Voronoi:
+ *
+ * - https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi
+ *
+ * Distance To Edge:
+ *
+ * - https://www.shadertoy.com/view/llG3zy
+ *
+ */
+
+/* **** 1D Voronoi **** */
+
+float voronoi_distance(float a, float b, string metric, float exponent)
+{
+ return abs(a - b);
+}
+
+void voronoi_f1_1d(float w,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output float outW)
+{
+ float cellPosition = floor(w);
+ float localPosition = w - cellPosition;
+
+ float minDistance = 8.0;
+ float targetOffset, targetPosition;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ outDistance = minDistance;
+ outColor = hash_float_to_color(cellPosition + targetOffset);
+ outW = targetPosition + cellPosition;
+}
+
+void voronoi_smooth_f1_1d(float w,
+ float smoothness,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output float outW)
+{
+ float cellPosition = floor(w);
+ float localPosition = w - cellPosition;
+
+ float smoothDistance = 8.0;
+ float smoothPosition = 0.0;
+ color smoothColor = color(0.0);
+ for (int i = -2; i <= 2; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0 - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0 + 3.0 * smoothness;
+ color cellColor = hash_float_to_color(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ outDistance = smoothDistance;
+ outColor = smoothColor;
+ outW = cellPosition + smoothPosition;
+}
+
+void voronoi_f2_1d(float w,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output float outW)
+{
+ float cellPosition = floor(w);
+ float localPosition = w - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ float offsetF1 = 0.0;
+ float positionF1 = 0.0;
+ float offsetF2, positionF2;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ outDistance = distanceF2;
+ outColor = hash_float_to_color(cellPosition + offsetF2);
+ outW = positionF2 + cellPosition;
+}
+
+void voronoi_distance_to_edge_1d(float w, float randomness, output float outDistance)
+{
+ float cellPosition = floor(w);
+ float localPosition = w - cellPosition;
+
+ float minDistance = 8.0;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ minDistance = min(distanceToPoint, minDistance);
+ }
+ outDistance = minDistance;
+}
+
+void voronoi_n_sphere_radius_1d(float w, float randomness, output float outRadius)
+{
+ float cellPosition = floor(w);
+ float localPosition = w - cellPosition;
+
+ float closestPoint;
+ float closestPointOffset;
+ float minDistance = 8.0;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+
+ minDistance = 8.0;
+ float closestPointToClosestPoint;
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0) {
+ continue;
+ }
+ float cellOffset = float(i) + closestPointOffset;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
+
+/* **** 2D Voronoi **** */
+
+float voronoi_distance(vector2 a, vector2 b, string metric, float exponent)
+{
+ if (metric == "euclidean") {
+ return distance(a, b);
+ }
+ else if (metric == "manhattan") {
+ return abs(a.x - b.x) + abs(a.y - b.y);
+ }
+ else if (metric == "chebychev") {
+ return max(abs(a.x - b.x), abs(a.y - b.y));
+ }
+ else if (metric == "minkowski") {
+ return pow(pow(abs(a.x - b.x), exponent) + pow(abs(a.y - b.y), exponent), 1.0 / exponent);
+ }
+ else {
+ return 0.0;
+ }
+}
+
+void voronoi_f1_2d(vector2 coord,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector2 outPosition)
+{
+ vector2 cellPosition = floor(coord);
+ vector2 localPosition = coord - cellPosition;
+
+ float minDistance = 8.0;
+ vector2 targetOffset, targetPosition;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector2 cellOffset = vector2(i, j);
+ vector2 pointPosition = cellOffset +
+ hash_vector2_to_vector2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ outDistance = minDistance;
+ outColor = hash_vector2_to_color(cellPosition + targetOffset);
+ outPosition = targetPosition + cellPosition;
+}
+
+void voronoi_smooth_f1_2d(vector2 coord,
+ float smoothness,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector2 outPosition)
+{
+ vector2 cellPosition = floor(coord);
+ vector2 localPosition = coord - cellPosition;
+
+ float smoothDistance = 8.0;
+ color smoothColor = color(0.0);
+ vector2 smoothPosition = vector2(0.0, 0.0);
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vector2 cellOffset = vector2(i, j);
+ vector2 pointPosition = cellOffset +
+ hash_vector2_to_vector2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0 - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0 + 3.0 * smoothness;
+ color cellColor = hash_vector2_to_color(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ outDistance = smoothDistance;
+ outColor = smoothColor;
+ outPosition = cellPosition + smoothPosition;
+}
+
+void voronoi_f2_2d(vector2 coord,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector2 outPosition)
+{
+ vector2 cellPosition = floor(coord);
+ vector2 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vector2 offsetF1 = vector2(0.0, 0.0);
+ vector2 positionF1 = vector2(0.0, 0.0);
+ vector2 offsetF2, positionF2;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector2 cellOffset = vector2(i, j);
+ vector2 pointPosition = cellOffset +
+ hash_vector2_to_vector2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ outDistance = distanceF2;
+ outColor = hash_vector2_to_color(cellPosition + offsetF2);
+ outPosition = positionF2 + cellPosition;
+}
+
+void voronoi_distance_to_edge_2d(vector2 coord, float randomness, output float outDistance)
+{
+ vector2 cellPosition = floor(coord);
+ vector2 localPosition = coord - cellPosition;
+
+ vector2 vectorToClosest;
+ float minDistance = 8.0;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector2 cellOffset = vector2(i, j);
+ vector2 vectorToPoint = cellOffset +
+ hash_vector2_to_vector2(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector2 cellOffset = vector2(i, j);
+ vector2 vectorToPoint = cellOffset +
+ hash_vector2_to_vector2(cellPosition + cellOffset) * randomness -
+ localPosition;
+ vector2 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ outDistance = minDistance;
+}
+
+void voronoi_n_sphere_radius_2d(vector2 coord, float randomness, output float outRadius)
+{
+ vector2 cellPosition = floor(coord);
+ vector2 localPosition = coord - cellPosition;
+
+ vector2 closestPoint;
+ vector2 closestPointOffset;
+ float minDistance = 8.0;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector2 cellOffset = vector2(i, j);
+ vector2 pointPosition = cellOffset +
+ hash_vector2_to_vector2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ vector2 closestPointToClosestPoint;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0) {
+ continue;
+ }
+ vector2 cellOffset = vector2(i, j) + closestPointOffset;
+ vector2 pointPosition = cellOffset +
+ hash_vector2_to_vector2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
+
+/* **** 3D Voronoi **** */
+
+float voronoi_distance(vector3 a, vector3 b, string metric, float exponent)
+{
+ if (metric == "euclidean") {
+ return distance(a, b);
+ }
+ else if (metric == "manhattan") {
+ return abs(a[0] - b[0]) + abs(a[1] - b[1]) + abs(a[2] - b[2]);
+ }
+ else if (metric == "chebychev") {
+ return max(abs(a[0] - b[0]), max(abs(a[1] - b[1]), abs(a[2] - b[2])));
+ }
+ else if (metric == "minkowski") {
+ return pow(pow(abs(a[0] - b[0]), exponent) + pow(abs(a[1] - b[1]), exponent) +
+ pow(abs(a[2] - b[2]), exponent),
+ 1.0 / exponent);
+ }
+ else {
+ return 0.0;
+ }
+}
+
+void voronoi_f1_3d(vector3 coord,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector3 outPosition)
+{
+ vector3 cellPosition = floor(coord);
+ vector3 localPosition = coord - cellPosition;
+
+ float minDistance = 8.0;
+ vector3 targetOffset, targetPosition;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector3 cellOffset = vector3(i, j, k);
+ vector3 pointPosition = cellOffset +
+ hash_vector3_to_vector3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
}
- else if (metric == "manhattan") {
- d = fabs(pd[0]) + fabs(pd[1]) + fabs(pd[2]);
+ }
+ }
+ }
+ outDistance = minDistance;
+ outColor = hash_vector3_to_color(cellPosition + targetOffset);
+ outPosition = targetPosition + cellPosition;
+}
+
+void voronoi_smooth_f1_3d(vector3 coord,
+ float smoothness,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector3 outPosition)
+{
+ vector3 cellPosition = floor(coord);
+ vector3 localPosition = coord - cellPosition;
+
+ float smoothDistance = 8.0;
+ color smoothColor = color(0.0);
+ vector3 smoothPosition = vector3(0.0);
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vector3 cellOffset = vector3(i, j, k);
+ vector3 pointPosition = cellOffset +
+ hash_vector3_to_vector3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(
+ 0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0 - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0 + 3.0 * smoothness;
+ color cellColor = hash_vector3_to_color(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ }
+ outDistance = smoothDistance;
+ outColor = smoothColor;
+ outPosition = cellPosition + smoothPosition;
+}
+
+void voronoi_f2_3d(vector3 coord,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector3 outPosition)
+{
+ vector3 cellPosition = floor(coord);
+ vector3 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vector3 offsetF1 = vector3(0.0);
+ vector3 positionF1 = vector3(0.0);
+ vector3 offsetF2, positionF2;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector3 cellOffset = vector3(i, j, k);
+ vector3 pointPosition = cellOffset +
+ hash_vector3_to_vector3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
}
- else if (metric == "chebychev") {
- d = max(fabs(pd[0]), max(fabs(pd[1]), fabs(pd[2])));
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
}
- else if (metric == "minkowski") {
- d = pow(pow(fabs(pd[0]), e) + pow(fabs(pd[1]), e) + pow(fabs(pd[2]), e), 1.0 / e);
+ }
+ }
+ }
+ outDistance = distanceF2;
+ outColor = hash_vector3_to_color(cellPosition + offsetF2);
+ outPosition = positionF2 + cellPosition;
+}
+
+void voronoi_distance_to_edge_3d(vector3 coord, float randomness, output float outDistance)
+{
+ vector3 cellPosition = floor(coord);
+ vector3 localPosition = coord - cellPosition;
+
+ vector3 vectorToClosest;
+ float minDistance = 8.0;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector3 cellOffset = vector3(i, j, k);
+ vector3 vectorToPoint = cellOffset +
+ hash_vector3_to_vector3(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
}
+ }
+ }
+ }
- vp += point(xx, yy, zz);
+ minDistance = 8.0;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector3 cellOffset = vector3(i, j, k);
+ vector3 vectorToPoint = cellOffset +
+ hash_vector3_to_vector3(cellPosition + cellOffset) * randomness -
+ localPosition;
+ vector3 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ }
+ outDistance = minDistance;
+}
- if (d < da[0]) {
- da[3] = da[2];
- da[2] = da[1];
- da[1] = da[0];
- da[0] = d;
+void voronoi_n_sphere_radius_3d(vector3 coord, float randomness, output float outRadius)
+{
+ vector3 cellPosition = floor(coord);
+ vector3 localPosition = coord - cellPosition;
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = pa[0];
- pa[0] = vp;
+ vector3 closestPoint;
+ vector3 closestPointOffset;
+ float minDistance = 8.0;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector3 cellOffset = vector3(i, j, k);
+ vector3 pointPosition = cellOffset +
+ hash_vector3_to_vector3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
}
- else if (d < da[1]) {
- da[3] = da[2];
- da[2] = da[1];
- da[1] = d;
-
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = vp;
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ vector3 closestPointToClosestPoint;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0 && k == 0) {
+ continue;
}
- else if (d < da[2]) {
- da[3] = da[2];
- da[2] = d;
+ vector3 cellOffset = vector3(i, j, k) + closestPointOffset;
+ vector3 pointPosition = cellOffset +
+ hash_vector3_to_vector3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
- pa[3] = pa[2];
- pa[2] = vp;
+/* **** 4D Voronoi **** */
+
+float voronoi_distance(vector4 a, vector4 b, string metric, float exponent)
+{
+ if (metric == "euclidean") {
+ return distance(a, b);
+ }
+ else if (metric == "manhattan") {
+ return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z) + abs(a.w - b.w);
+ }
+ else if (metric == "chebychev") {
+ return max(abs(a.x - b.x), max(abs(a.y - b.y), max(abs(a.z - b.z), abs(a.w - b.w))));
+ }
+ else if (metric == "minkowski") {
+ return pow(pow(abs(a.x - b.x), exponent) + pow(abs(a.y - b.y), exponent) +
+ pow(abs(a.z - b.z), exponent) + pow(abs(a.w - b.w), exponent),
+ 1.0 / exponent);
+ }
+ else {
+ return 0.0;
+ }
+}
+
+void voronoi_f1_4d(vector4 coord,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector4 outPosition)
+{
+ vector4 cellPosition = floor(coord);
+ vector4 localPosition = coord - cellPosition;
+
+ float minDistance = 8.0;
+ vector4 targetOffset, targetPosition;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector4 cellOffset = vector4(i, j, k, u);
+ vector4 pointPosition = cellOffset +
+ hash_vector4_to_vector4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
}
- else if (d < da[3]) {
- da[3] = d;
- pa[3] = vp;
+ }
+ }
+ }
+ outDistance = minDistance;
+ outColor = hash_vector4_to_color(cellPosition + targetOffset);
+ outPosition = targetPosition + cellPosition;
+}
+
+void voronoi_smooth_f1_4d(vector4 coord,
+ float smoothness,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector4 outPosition)
+{
+ vector4 cellPosition = floor(coord);
+ vector4 localPosition = coord - cellPosition;
+
+ float smoothDistance = 8.0;
+ color smoothColor = color(0.0);
+ vector4 smoothPosition = vector4(0.0, 0.0, 0.0, 0.0);
+ for (int u = -2; u <= 2; u++) {
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vector4 cellOffset = vector4(i, j, k, u);
+ vector4 pointPosition = cellOffset +
+ hash_vector4_to_vector4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(
+ 0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0 - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0 + 3.0 * smoothness;
+ color cellColor = hash_vector4_to_color(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ }
+ }
+ outDistance = smoothDistance;
+ outColor = smoothColor;
+ outPosition = cellPosition + smoothPosition;
+}
+
+void voronoi_f2_4d(vector4 coord,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector4 outPosition)
+{
+ vector4 cellPosition = floor(coord);
+ vector4 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vector4 offsetF1 = vector4(0.0, 0.0, 0.0, 0.0);
+ vector4 positionF1 = vector4(0.0, 0.0, 0.0, 0.0);
+ vector4 offsetF2, positionF2;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector4 cellOffset = vector4(i, j, k, u);
+ vector4 pointPosition = cellOffset +
+ hash_vector4_to_vector4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ outDistance = distanceF2;
+ outColor = hash_vector4_to_color(cellPosition + offsetF2);
+ outPosition = positionF2 + cellPosition;
+}
+
+void voronoi_distance_to_edge_4d(vector4 coord, float randomness, output float outDistance)
+{
+ vector4 cellPosition = floor(coord);
+ vector4 localPosition = coord - cellPosition;
+
+ vector4 vectorToClosest;
+ float minDistance = 8.0;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector4 cellOffset = vector4(i, j, k, u);
+ vector4 vectorToPoint = cellOffset +
+ hash_vector4_to_vector4(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
}
}
}
}
+
+ minDistance = 8.0;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector4 cellOffset = vector4(i, j, k, u);
+ vector4 vectorToPoint = cellOffset +
+ hash_vector4_to_vector4(cellPosition + cellOffset) * randomness -
+ localPosition;
+ vector4 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ }
+ }
+ outDistance = minDistance;
}
-/* Voronoi */
+void voronoi_n_sphere_radius_4d(vector4 coord, float randomness, output float outRadius)
+{
+ vector4 cellPosition = floor(coord);
+ vector4 localPosition = coord - cellPosition;
+
+ vector4 closestPoint;
+ vector4 closestPointOffset;
+ float minDistance = 8.0;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector4 cellOffset = vector4(i, j, k, u);
+ vector4 pointPosition = cellOffset +
+ hash_vector4_to_vector4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ vector4 closestPointToClosestPoint;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0 && k == 0 && u == 0) {
+ continue;
+ }
+ vector4 cellOffset = vector4(i, j, k, u) + closestPointOffset;
+ vector4 pointPosition = cellOffset +
+ hash_vector4_to_vector4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
shader node_voronoi_texture(
int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- string coloring = "intensity",
- string metric = "distance",
- string feature = "F1",
- float Exponent = 1.0,
+ string dimensions = "3D",
+ string feature = "f1",
+ string metric = "euclidean",
+ vector3 Vector = P,
+ float WIn = 0.0,
float Scale = 5.0,
- point Vector = P,
- output float Fac = 0.0,
- output color Color = 0.0)
+ float Smoothness = 5.0,
+ float Exponent = 1.0,
+ float Randomness = 1.0,
+ output float Distance = 0.0,
+ output color Color = 0.0,
+ output vector3 Position = P,
+ output float WOut = 0.0,
+ output float Radius = 0.0)
{
- point p = Vector;
+ float randomness = clamp(Randomness, 0.0, 1.0);
+ float smoothness = clamp(Smoothness / 2.0, 0.0, 0.5);
+ vector3 coord = Vector;
if (use_mapping)
- p = transform(mapping, p);
-
- /* compute distance and point coordinate of 4 nearest neighbours */
- float da[4];
- point pa[4];
+ coord = transform(mapping, coord);
- /* compute distance and point coordinate of 4 nearest neighbours */
- voronoi_m(p * Scale, metric, Exponent, da, pa);
+ float w = WIn * Scale;
+ coord *= Scale;
- if (coloring == "intensity") {
- /* Intensity output */
- if (feature == "F1") {
- Fac = fabs(da[0]);
+ if (dimensions == "1D") {
+ if (feature == "f1") {
+ voronoi_f1_1d(w, Exponent, randomness, metric, Distance, Color, WOut);
}
- else if (feature == "F2") {
- Fac = fabs(da[1]);
+ else if (feature == "smooth_f1") {
+ voronoi_smooth_f1_1d(w, smoothness, Exponent, randomness, metric, Distance, Color, WOut);
}
- else if (feature == "F3") {
- Fac = fabs(da[2]);
+ else if (feature == "f2") {
+ voronoi_f2_1d(w, Exponent, randomness, metric, Distance, Color, WOut);
}
- else if (feature == "F4") {
- Fac = fabs(da[3]);
+ else if (feature == "distance_to_edge") {
+ voronoi_distance_to_edge_1d(w, randomness, Distance);
}
- else if (feature == "F2F1") {
- Fac = fabs(da[1] - da[0]);
+ else if (feature == "n_sphere_radius") {
+ voronoi_n_sphere_radius_1d(w, randomness, Radius);
}
- Color = color(Fac);
+ else {
+ error("Unknown feature!");
+ }
+ WOut = (Scale != 0.0) ? WOut / Scale : 0.0;
}
- else {
- /* Color output */
- if (feature == "F1") {
- Color = pa[0];
+ else if (dimensions == "2D") {
+ vector2 coord2D = vector2(coord[0], coord[1]);
+ vector2 outPosition2D;
+ if (feature == "f1") {
+ voronoi_f1_2d(coord2D, Exponent, randomness, metric, Distance, Color, outPosition2D);
}
- else if (feature == "F2") {
- Color = pa[1];
+ else if (feature == "smooth_f1") {
+ voronoi_smooth_f1_2d(
+ coord2D, smoothness, Exponent, randomness, metric, Distance, Color, outPosition2D);
}
- else if (feature == "F3") {
- Color = pa[2];
+ else if (feature == "f2") {
+ voronoi_f2_2d(coord2D, Exponent, randomness, metric, Distance, Color, outPosition2D);
}
- else if (feature == "F4") {
- Color = pa[3];
+ else if (feature == "distance_to_edge") {
+ voronoi_distance_to_edge_2d(coord2D, randomness, Distance);
}
- else if (feature == "F2F1") {
- Color = fabs(pa[1] - pa[0]);
+ else if (feature == "n_sphere_radius") {
+ voronoi_n_sphere_radius_2d(coord2D, randomness, Radius);
}
-
- Color = cellnoise_color(Color);
- Fac = (Color[0] + Color[1] + Color[2]) * (1.0 / 3.0);
+ else {
+ error("Unknown feature!");
+ }
+ outPosition2D = safe_divide(outPosition2D, Scale);
+ Position = vector3(outPosition2D.x, outPosition2D.y, 0.0);
+ }
+ else if (dimensions == "3D") {
+ if (feature == "f1") {
+ voronoi_f1_3d(coord, Exponent, randomness, metric, Distance, Color, Position);
+ }
+ else if (feature == "smooth_f1") {
+ voronoi_smooth_f1_3d(
+ coord, smoothness, Exponent, randomness, metric, Distance, Color, Position);
+ }
+ else if (feature == "f2") {
+ voronoi_f2_3d(coord, Exponent, randomness, metric, Distance, Color, Position);
+ }
+ else if (feature == "distance_to_edge") {
+ voronoi_distance_to_edge_3d(coord, randomness, Distance);
+ }
+ else if (feature == "n_sphere_radius") {
+ voronoi_n_sphere_radius_3d(coord, randomness, Radius);
+ }
+ else {
+ error("Unknown feature!");
+ }
+ Position = (Scale != 0.0) ? Position / Scale : vector3(0.0);
+ }
+ else if (dimensions == "4D") {
+ vector4 coord4D = vector4(coord[0], coord[1], coord[2], w);
+ vector4 outPosition4D;
+ if (feature == "f1") {
+ voronoi_f1_4d(coord4D, Exponent, randomness, metric, Distance, Color, outPosition4D);
+ }
+ else if (feature == "smooth_f1") {
+ voronoi_smooth_f1_4d(
+ coord4D, smoothness, Exponent, randomness, metric, Distance, Color, outPosition4D);
+ }
+ else if (feature == "f2") {
+ voronoi_f2_4d(coord4D, Exponent, randomness, metric, Distance, Color, outPosition4D);
+ }
+ else if (feature == "distance_to_edge") {
+ voronoi_distance_to_edge_4d(coord4D, randomness, Distance);
+ }
+ else if (feature == "n_sphere_radius") {
+ voronoi_n_sphere_radius_4d(coord4D, randomness, Radius);
+ }
+ else {
+ error("Unknown feature!");
+ }
+ outPosition4D = safe_divide(outPosition4D, Scale);
+ Position = vector3(outPosition4D.x, outPosition4D.y, outPosition4D.z);
+ WOut = outPosition4D.w;
+ }
+ else {
+ error("Unknown dimension!");
}
}
diff --git a/intern/cycles/kernel/shaders/node_wave_texture.osl b/intern/cycles/kernel/shaders/node_wave_texture.osl
index dfc2dbfb800..60591b79b33 100644
--- a/intern/cycles/kernel/shaders/node_wave_texture.osl
+++ b/intern/cycles/kernel/shaders/node_wave_texture.osl
@@ -15,7 +15,7 @@
*/
#include "stdosl.h"
-#include "node_texture.h"
+#include "node_noise.h"
/* Wave */
@@ -31,7 +31,7 @@ float wave(point p, string type, string profile, float detail, float distortion,
}
if (distortion != 0.0) {
- n = n + (distortion * noise_turbulence(p * dscale, detail, 0));
+ n = n + (distortion * fractal_noise(p * dscale, detail));
}
if (profile == "sine") {
diff --git a/intern/cycles/kernel/shaders/vector2.h b/intern/cycles/kernel/shaders/vector2.h
new file mode 100644
index 00000000000..c524735d892
--- /dev/null
+++ b/intern/cycles/kernel/shaders/vector2.h
@@ -0,0 +1,291 @@
+// Open Shading Language : Copyright (c) 2009-2017 Sony Pictures Imageworks Inc., et al.
+// https://github.com/imageworks/OpenShadingLanguage/blob/master/LICENSE
+
+#pragma once
+#define VECTOR2_H
+
+// vector2 is a 2D vector
+struct vector2 {
+ float x;
+ float y;
+};
+
+//
+// For vector2, define math operators to match vector
+//
+
+vector2 __operator__neg__(vector2 a)
+{
+ return vector2(-a.x, -a.y);
+}
+
+vector2 __operator__add__(vector2 a, vector2 b)
+{
+ return vector2(a.x + b.x, a.y + b.y);
+}
+
+vector2 __operator__add__(vector2 a, int b)
+{
+ return a + vector2(b, b);
+}
+
+vector2 __operator__add__(vector2 a, float b)
+{
+ return a + vector2(b, b);
+}
+
+vector2 __operator__add__(int a, vector2 b)
+{
+ return vector2(a, a) + b;
+}
+
+vector2 __operator__add__(float a, vector2 b)
+{
+ return vector2(a, a) + b;
+}
+
+vector2 __operator__sub__(vector2 a, vector2 b)
+{
+ return vector2(a.x - b.x, a.y - b.y);
+}
+
+vector2 __operator__sub__(vector2 a, int b)
+{
+ return a - vector2(b, b);
+}
+
+vector2 __operator__sub__(vector2 a, float b)
+{
+ return a - vector2(b, b);
+}
+
+vector2 __operator__sub__(int a, vector2 b)
+{
+ return vector2(a, a) - b;
+}
+
+vector2 __operator__sub__(float a, vector2 b)
+{
+ return vector2(a, a) - b;
+}
+
+vector2 __operator__mul__(vector2 a, vector2 b)
+{
+ return vector2(a.x * b.x, a.y * b.y);
+}
+
+vector2 __operator__mul__(vector2 a, int b)
+{
+ return a * vector2(b, b);
+}
+
+vector2 __operator__mul__(vector2 a, float b)
+{
+ return a * vector2(b, b);
+}
+
+vector2 __operator__mul__(int a, vector2 b)
+{
+ return b * vector2(a, a);
+}
+
+vector2 __operator__mul__(float a, vector2 b)
+{
+ return b * vector2(a, a);
+}
+
+vector2 __operator__div__(vector2 a, vector2 b)
+{
+ return vector2(a.x / b.x, a.y / b.y);
+}
+
+vector2 __operator__div__(vector2 a, int b)
+{
+ float b_inv = 1 / b;
+ return a * vector2(b_inv, b_inv);
+}
+
+vector2 __operator__div__(vector2 a, float b)
+{
+ float b_inv = 1 / b;
+ return a * vector2(b_inv, b_inv);
+}
+
+vector2 __operator__div__(int a, vector2 b)
+{
+ return vector2(a, a) / b;
+}
+
+vector2 __operator__div__(float a, vector2 b)
+{
+ return vector2(a, a) / b;
+}
+
+int __operator__eq__(vector2 a, vector2 b)
+{
+ return (a.x == b.x) && (a.y == b.y);
+}
+
+int __operator__ne__(vector2 a, vector2 b)
+{
+ return (a.x != b.x) || (a.y != b.y);
+}
+
+//
+// For vector2, define most of the stdosl functions to match vector
+//
+
+vector2 abs(vector2 a)
+{
+ return vector2(abs(a.x), abs(a.y));
+}
+
+vector2 ceil(vector2 a)
+{
+ return vector2(ceil(a.x), ceil(a.y));
+}
+
+vector2 floor(vector2 a)
+{
+ return vector2(floor(a.x), floor(a.y));
+}
+
+vector2 sqrt(vector2 a)
+{
+ return vector2(sqrt(a.x), sqrt(a.y));
+}
+
+vector2 exp(vector2 a)
+{
+ return vector2(exp(a.x), exp(a.y));
+}
+
+vector2 log(vector2 a)
+{
+ return vector2(log(a.x), log(a.y));
+}
+
+vector2 log2(vector2 a)
+{
+ return vector2(log2(a.x), log2(a.y));
+}
+
+vector2 mix(vector2 a, vector2 b, float x)
+{
+ return vector2(mix(a.x, b.x, x), mix(a.y, b.y, x));
+}
+
+float dot(vector2 a, vector2 b)
+{
+ return (a.x * b.x + a.y * b.y);
+}
+
+float length(vector2 a)
+{
+ return hypot(a.x, a.y);
+}
+
+vector2 smoothstep(vector2 low, vector2 high, vector2 in)
+{
+ return vector2(smoothstep(low.x, high.x, in.x), smoothstep(low.y, high.y, in.y));
+}
+
+vector2 smoothstep(float low, float high, vector2 in)
+{
+ return vector2(smoothstep(low, high, in.x), smoothstep(low, high, in.y));
+}
+
+vector2 clamp(vector2 in, vector2 low, vector2 high)
+{
+ return vector2(clamp(in.x, low.x, high.x), clamp(in.y, low.y, high.y));
+}
+
+vector2 clamp(vector2 in, float low, float high)
+{
+ return clamp(in, vector2(low, low), vector2(high, high));
+}
+
+vector2 max(vector2 a, vector2 b)
+{
+ return vector2(max(a.x, b.x), max(a.y, b.y));
+}
+
+vector2 max(vector2 a, float b)
+{
+ return max(a, vector2(b, b));
+}
+
+vector2 normalize(vector2 a)
+{
+ return a / length(a);
+}
+
+vector2 min(vector2 a, vector2 b)
+{
+ return vector2(min(a.x, a.x), min(b.y, b.y));
+}
+
+vector2 min(vector2 a, float b)
+{
+ return min(a, vector2(b, b));
+}
+
+vector2 fmod(vector2 a, vector2 b)
+{
+ return vector2(fmod(a.x, b.x), fmod(a.y, b.y));
+}
+
+vector2 fmod(vector2 a, float b)
+{
+ return fmod(a, vector2(b, b));
+}
+
+vector2 pow(vector2 in, vector2 amount)
+{
+ return vector2(pow(in.x, amount.x), pow(in.y, amount.y));
+}
+
+vector2 pow(vector2 in, float amount)
+{
+ return pow(in, vector2(amount, amount));
+}
+
+vector2 sign(vector2 a)
+{
+ return vector2(sign(a.x), sign(a.y));
+}
+
+vector2 sin(vector2 a)
+{
+ return vector2(sin(a.x), sin(a.y));
+}
+
+vector2 cos(vector2 a)
+{
+ return vector2(cos(a.x), cos(a.y));
+}
+
+vector2 tan(vector2 a)
+{
+ return vector2(tan(a.x), tan(a.y));
+}
+
+vector2 asin(vector2 a)
+{
+ return vector2(asin(a.x), asin(a.y));
+}
+
+vector2 acos(vector2 a)
+{
+ return vector2(acos(a.x), acos(a.y));
+}
+
+vector2 atan2(vector2 a, float f)
+{
+ return vector2(atan2(a.x, f), atan2(a.y, f));
+}
+
+vector2 atan2(vector2 a, vector2 b)
+{
+ return vector2(atan2(a.x, b.x), atan2(a.y, b.y));
+}
diff --git a/intern/cycles/kernel/shaders/vector4.h b/intern/cycles/kernel/shaders/vector4.h
new file mode 100644
index 00000000000..58e1b3c2e23
--- /dev/null
+++ b/intern/cycles/kernel/shaders/vector4.h
@@ -0,0 +1,327 @@
+// Open Shading Language : Copyright (c) 2009-2017 Sony Pictures Imageworks Inc., et al.
+// https://github.com/imageworks/OpenShadingLanguage/blob/master/LICENSE
+
+#pragma once
+#define VECTOR4_H
+
+// vector4 is a 4D vector
+struct vector4 {
+ float x;
+ float y;
+ float z;
+ float w;
+};
+
+//
+// For vector4, define math operators to match vector
+//
+
+vector4 __operator__neg__(vector4 a)
+{
+ return vector4(-a.x, -a.y, -a.z, -a.w);
+}
+
+vector4 __operator__add__(vector4 a, vector4 b)
+{
+ return vector4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
+}
+
+vector4 __operator__add__(vector4 a, int b)
+{
+ return a + vector4(b, b, b, b);
+}
+
+vector4 __operator__add__(vector4 a, float b)
+{
+ return a + vector4(b, b, b, b);
+}
+
+vector4 __operator__add__(int a, vector4 b)
+{
+ return vector4(a, a, a, a) + b;
+}
+
+vector4 __operator__add__(float a, vector4 b)
+{
+ return vector4(a, a, a, a) + b;
+}
+
+vector4 __operator__sub__(vector4 a, vector4 b)
+{
+ return vector4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
+}
+
+vector4 __operator__sub__(vector4 a, int b)
+{
+ return a - vector4(b, b, b, b);
+}
+
+vector4 __operator__sub__(vector4 a, float b)
+{
+ return a - vector4(b, b, b, b);
+}
+
+vector4 __operator__sub__(int a, vector4 b)
+{
+ return vector4(a, a, a, a) - b;
+}
+
+vector4 __operator__sub__(float a, vector4 b)
+{
+ return vector4(a, a, a, a) - b;
+}
+
+vector4 __operator__mul__(vector4 a, vector4 b)
+{
+ return vector4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
+}
+
+vector4 __operator__mul__(vector4 a, int b)
+{
+ return a * vector4(b, b, b, b);
+}
+
+vector4 __operator__mul__(vector4 a, float b)
+{
+ return a * vector4(b, b, b, b);
+}
+
+vector4 __operator__mul__(int a, vector4 b)
+{
+ return vector4(a, a, a, a) * b;
+}
+
+vector4 __operator__mul__(float a, vector4 b)
+{
+ return vector4(a, a, a, a) * b;
+}
+
+vector4 __operator__div__(vector4 a, vector4 b)
+{
+ return vector4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w);
+}
+
+vector4 __operator__div__(vector4 a, int b)
+{
+ float b_inv = 1 / b;
+ return a * vector4(b_inv, b_inv, b_inv, b_inv);
+}
+
+vector4 __operator__div__(vector4 a, float b)
+{
+ float b_inv = 1 / b;
+ return a * vector4(b_inv, b_inv, b_inv, b_inv);
+}
+
+vector4 __operator__div__(int a, vector4 b)
+{
+ return vector4(a, a, a, a) / b;
+}
+
+vector4 __operator__div__(float a, vector4 b)
+{
+ return vector4(a, a, a, a) / b;
+}
+
+int __operator__eq__(vector4 a, vector4 b)
+{
+ return (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w);
+}
+
+int __operator__ne__(vector4 a, vector4 b)
+{
+ return (a.x != b.x) || (a.y != b.y) || (a.z != b.z) || (a.w != b.w);
+}
+
+//
+// For vector4, define most of the stdosl functions to match vector
+//
+
+vector4 abs(vector4 in)
+{
+ return vector4(abs(in.x), abs(in.y), abs(in.z), abs(in.w));
+}
+
+vector4 ceil(vector4 in)
+{
+ return vector4(ceil(in.x), ceil(in.y), ceil(in.z), ceil(in.w));
+}
+
+vector4 floor(vector4 in)
+{
+ return vector4(floor(in.x), floor(in.y), floor(in.z), floor(in.w));
+}
+
+vector4 sqrt(vector4 in)
+{
+ return vector4(sqrt(in.x), sqrt(in.y), sqrt(in.z), sqrt(in.w));
+}
+
+vector4 exp(vector4 in)
+{
+ return vector4(exp(in.x), exp(in.y), exp(in.z), exp(in.w));
+}
+
+vector4 log(vector4 in)
+{
+ return vector4(log(in.x), log(in.y), log(in.z), log(in.w));
+}
+
+vector4 log2(vector4 in)
+{
+ return vector4(log2(in.x), log2(in.y), log2(in.z), log2(in.w));
+}
+
+vector4 mix(vector4 value1, vector4 value2, float x)
+{
+ return vector4(mix(value1.x, value2.x, x),
+ mix(value1.y, value2.y, x),
+ mix(value1.z, value2.z, x),
+ mix(value1.w, value2.w, x));
+}
+
+vector vec4ToVec3(vector4 v)
+{
+ return vector(v.x, v.y, v.z) / v.w;
+}
+
+float dot(vector4 a, vector4 b)
+{
+ return ((a.x * b.x) + (a.y * b.y) + (a.z * b.z) + (a.w * b.w));
+}
+
+float length(vector4 a)
+{
+ return sqrt(a.x * a.x + a.y * a.y + a.z * a.z + a.w * a.w);
+}
+
+vector4 smoothstep(vector4 low, vector4 high, vector4 in)
+{
+ return vector4(smoothstep(low.x, high.x, in.x),
+ smoothstep(low.y, high.y, in.y),
+ smoothstep(low.z, high.z, in.z),
+ smoothstep(low.w, high.w, in.w));
+}
+
+vector4 smoothstep(float low, float high, vector4 in)
+{
+ return vector4(smoothstep(low, high, in.x),
+ smoothstep(low, high, in.y),
+ smoothstep(low, high, in.z),
+ smoothstep(low, high, in.w));
+}
+
+vector4 clamp(vector4 in, vector4 low, vector4 high)
+{
+ return vector4(clamp(in.x, low.x, high.x),
+ clamp(in.y, low.y, high.y),
+ clamp(in.z, low.z, high.z),
+ clamp(in.w, low.w, high.w));
+}
+
+vector4 clamp(vector4 in, float low, float high)
+{
+ return vector4(clamp(in.x, low, high),
+ clamp(in.y, low, high),
+ clamp(in.z, low, high),
+ clamp(in.w, low, high));
+}
+
+vector4 max(vector4 a, vector4 b)
+{
+ return vector4(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z), max(a.w, b.w));
+}
+
+vector4 max(vector4 a, float b)
+{
+ return max(a, vector4(b, b, b, b));
+}
+
+vector4 normalize(vector4 a)
+{
+ return a / length(a);
+}
+
+vector4 min(vector4 a, vector4 b)
+{
+ return vector4(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z), min(a.w, b.w));
+}
+
+vector4 min(vector4 a, float b)
+{
+ return min(a, vector4(b, b, b, b));
+}
+
+vector4 fmod(vector4 a, vector4 b)
+{
+ return vector4(fmod(a.x, b.x), fmod(a.y, b.y), fmod(a.z, b.z), fmod(a.w, b.w));
+}
+
+vector4 fmod(vector4 a, float b)
+{
+ return fmod(a, vector4(b, b, b, b));
+}
+
+vector4 pow(vector4 in, vector4 amount)
+{
+ return vector4(
+ pow(in.x, amount.x), pow(in.y, amount.y), pow(in.z, amount.z), pow(in.w, amount.w));
+}
+
+vector4 pow(vector4 in, float amount)
+{
+ return vector4(pow(in.x, amount), pow(in.y, amount), pow(in.z, amount), pow(in.w, amount));
+}
+
+vector4 sign(vector4 a)
+{
+ return vector4(sign(a.x), sign(a.y), sign(a.z), sign(a.w));
+}
+
+vector4 sin(vector4 a)
+{
+ return vector4(sin(a.x), sin(a.y), sin(a.z), sin(a.w));
+}
+
+vector4 cos(vector4 a)
+{
+ return vector4(cos(a.x), cos(a.y), cos(a.z), cos(a.w));
+}
+
+vector4 tan(vector4 a)
+{
+ return vector4(tan(a.x), tan(a.y), tan(a.z), tan(a.w));
+}
+
+vector4 asin(vector4 a)
+{
+ return vector4(asin(a.x), asin(a.y), asin(a.z), asin(a.w));
+}
+
+vector4 acos(vector4 a)
+{
+ return vector4(acos(a.x), acos(a.y), acos(a.z), acos(a.w));
+}
+
+vector4 atan2(vector4 a, float f)
+{
+ return vector4(atan2(a.x, f), atan2(a.y, f), atan2(a.z, f), atan2(a.w, f));
+}
+
+vector4 atan2(vector4 a, vector4 b)
+{
+ return vector4(atan2(a.x, b.x), atan2(a.y, b.y), atan2(a.z, b.z), atan2(a.w, b.w));
+}
+
+vector4 transform(matrix M, vector4 p)
+{
+ return vector4(M[0][0] * p.x + M[0][1] * p.y + M[0][2] * p.z + M[0][2] * p.w,
+ M[1][0] * p.x + M[1][1] * p.y + M[1][2] * p.z + M[1][2] * p.w,
+ M[2][0] * p.x + M[2][1] * p.y + M[2][2] * p.z + M[2][2] * p.w,
+ M[3][0] * p.x + M[3][1] * p.y + M[3][2] * p.z + M[3][2] * p.w);
+}
+
+vector4 transform(string fromspace, string tospace, vector4 p)
+{
+ return transform(matrix(fromspace, tospace), p);
+}
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h
index ab8570618ab..4fc5e633e3b 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -158,10 +158,11 @@ CCL_NAMESPACE_END
/* Nodes */
#include "kernel/svm/svm_noise.h"
-#include "svm_texture.h"
+#include "svm_fractal_noise.h"
#include "kernel/svm/svm_color_util.h"
#include "kernel/svm/svm_math_util.h"
+#include "kernel/svm/svm_mapping_util.h"
#include "kernel/svm/svm_attribute.h"
#include "kernel/svm/svm_gradient.h"
@@ -204,6 +205,7 @@ CCL_NAMESPACE_END
#include "kernel/svm/svm_map_range.h"
#include "kernel/svm/svm_clamp.h"
#include "kernel/svm/svm_white_noise.h"
+#include "kernel/svm/svm_vertex_color.h"
#ifdef __SHADER_RAYTRACE__
# include "kernel/svm/svm_ao.h"
@@ -288,6 +290,9 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
case NODE_ATTR:
svm_node_attr(kg, sd, stack, node);
break;
+ case NODE_VERTEX_COLOR:
+ svm_node_vertex_color(kg, sd, stack, node.y, node.z, node.w);
+ break;
# if NODES_FEATURE(NODE_FEATURE_BUMP)
case NODE_GEOMETRY_BUMP_DX:
svm_node_geometry_bump_dx(kg, sd, stack, node.y, node.z);
@@ -313,7 +318,7 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
svm_node_tex_image_box(kg, sd, stack, node);
break;
case NODE_TEX_NOISE:
- svm_node_tex_noise(kg, sd, stack, node, &offset);
+ svm_node_tex_noise(kg, sd, stack, node.y, node.z, node.w, &offset);
break;
# endif /* __TEXTURES__ */
# ifdef __EXTRA_NODES__
@@ -327,6 +332,12 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
case NODE_ATTR_BUMP_DY:
svm_node_attr_bump_dy(kg, sd, stack, node);
break;
+ case NODE_VERTEX_COLOR_BUMP_DX:
+ svm_node_vertex_color_bump_dx(kg, sd, stack, node.y, node.z, node.w);
+ break;
+ case NODE_VERTEX_COLOR_BUMP_DY:
+ svm_node_vertex_color_bump_dy(kg, sd, stack, node.y, node.z, node.w);
+ break;
case NODE_TEX_COORD_BUMP_DX:
svm_node_tex_coord_bump_dx(kg, sd, path_flag, stack, node, &offset);
break;
@@ -405,8 +416,11 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
#endif /* NODES_GROUP(NODE_GROUP_LEVEL_1) */
#if NODES_GROUP(NODE_GROUP_LEVEL_2)
+ case NODE_TEXTURE_MAPPING:
+ svm_node_texture_mapping(kg, sd, stack, node.y, node.z, &offset);
+ break;
case NODE_MAPPING:
- svm_node_mapping(kg, sd, stack, node.y, node.z, &offset);
+ svm_node_mapping(kg, sd, stack, node.y, node.z, node.w, &offset);
break;
case NODE_MIN_MAX:
svm_node_min_max(kg, sd, stack, node.y, node.z, &offset);
@@ -425,10 +439,10 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
svm_node_tex_gradient(sd, stack, node);
break;
case NODE_TEX_VORONOI:
- svm_node_tex_voronoi(kg, sd, stack, node, &offset);
+ svm_node_tex_voronoi(kg, sd, stack, node.y, node.z, node.w, &offset);
break;
case NODE_TEX_MUSGRAVE:
- svm_node_tex_musgrave(kg, sd, stack, node, &offset);
+ svm_node_tex_musgrave(kg, sd, stack, node.y, node.z, node.w, &offset);
break;
case NODE_TEX_WAVE:
svm_node_tex_wave(kg, sd, stack, node, &offset);
diff --git a/intern/cycles/kernel/svm/svm_attribute.h b/intern/cycles/kernel/svm/svm_attribute.h
index eaee0f9e4ee..fc7a3ba3f5a 100644
--- a/intern/cycles/kernel/svm/svm_attribute.h
+++ b/intern/cycles/kernel/svm/svm_attribute.h
@@ -69,6 +69,15 @@ ccl_device void svm_node_attr(KernelGlobals *kg, ShaderData *sd, float *stack, u
stack_store_float3(stack, out_offset, make_float3(f.x, f.y, 0.0f));
}
}
+ else if (desc.type == NODE_ATTR_RGBA) {
+ float4 f = primitive_attribute_float4(kg, sd, desc, NULL, NULL);
+ if (type == NODE_ATTR_FLOAT) {
+ stack_store_float(stack, out_offset, average(float4_to_float3(f)));
+ }
+ else {
+ stack_store_float3(stack, out_offset, float4_to_float3(f));
+ }
+ }
else {
float3 f = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
if (type == NODE_ATTR_FLOAT) {
@@ -107,6 +116,16 @@ ccl_device void svm_node_attr_bump_dx(KernelGlobals *kg, ShaderData *sd, float *
stack_store_float3(stack, out_offset, make_float3(f.x + dx.x, f.y + dx.y, 0.0f));
}
}
+ else if (desc.type == NODE_ATTR_RGBA) {
+ float4 dx;
+ float4 f = primitive_attribute_float4(kg, sd, desc, &dx, NULL);
+ if (type == NODE_ATTR_FLOAT) {
+ stack_store_float(stack, out_offset, average(float4_to_float3(f + dx)));
+ }
+ else {
+ stack_store_float3(stack, out_offset, float4_to_float3(f + dx));
+ }
+ }
else {
float3 dx;
float3 f = primitive_surface_attribute_float3(kg, sd, desc, &dx, NULL);
@@ -146,6 +165,16 @@ ccl_device void svm_node_attr_bump_dy(KernelGlobals *kg, ShaderData *sd, float *
stack_store_float3(stack, out_offset, make_float3(f.x + dy.x, f.y + dy.y, 0.0f));
}
}
+ else if (desc.type == NODE_ATTR_RGBA) {
+ float4 dy;
+ float4 f = primitive_attribute_float4(kg, sd, desc, NULL, &dy);
+ if (type == NODE_ATTR_FLOAT) {
+ stack_store_float(stack, out_offset, average(float4_to_float3(f + dy)));
+ }
+ else {
+ stack_store_float3(stack, out_offset, float4_to_float3(f + dy));
+ }
+ }
else {
float3 dy;
float3 f = primitive_surface_attribute_float3(kg, sd, desc, NULL, &dy);
diff --git a/intern/cycles/kernel/svm/svm_color_util.h b/intern/cycles/kernel/svm/svm_color_util.h
index 3a6a5ba782f..0f571eb7253 100644
--- a/intern/cycles/kernel/svm/svm_color_util.h
+++ b/intern/cycles/kernel/svm/svm_color_util.h
@@ -255,13 +255,7 @@ ccl_device float3 svm_mix_linear(float t, float3 col1, float3 col2)
ccl_device float3 svm_mix_clamp(float3 col)
{
- float3 outcol = col;
-
- outcol.x = saturate(col.x);
- outcol.y = saturate(col.y);
- outcol.z = saturate(col.z);
-
- return outcol;
+ return saturate3(col);
}
ccl_device_noinline_cpu float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2)
diff --git a/intern/cycles/kernel/svm/svm_fractal_noise.h b/intern/cycles/kernel/svm/svm_fractal_noise.h
new file mode 100644
index 00000000000..5b2e4a28fce
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_fractal_noise.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * 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.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* The fractal_noise_[1-4] functions are all exactly the same except for the input type. */
+ccl_device_noinline float fractal_noise_1d(float p, float octaves)
+{
+ float fscale = 1.0f;
+ float amp = 1.0f;
+ float sum = 0.0f;
+ octaves = clamp(octaves, 0.0f, 16.0f);
+ int n = float_to_int(octaves);
+ for (int i = 0; i <= n; i++) {
+ float t = noise_1d(fscale * p);
+ sum += t * amp;
+ amp *= 0.5f;
+ fscale *= 2.0f;
+ }
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ float t = noise_1d(fscale * p);
+ float sum2 = sum + t * amp;
+ sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1));
+ sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1));
+ return (1.0f - rmd) * sum + rmd * sum2;
+ }
+ else {
+ sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1));
+ return sum;
+ }
+}
+
+/* The fractal_noise_[1-4] functions are all exactly the same except for the input type. */
+ccl_device_noinline float fractal_noise_2d(float2 p, float octaves)
+{
+ float fscale = 1.0f;
+ float amp = 1.0f;
+ float sum = 0.0f;
+ octaves = clamp(octaves, 0.0f, 16.0f);
+ int n = float_to_int(octaves);
+ for (int i = 0; i <= n; i++) {
+ float t = noise_2d(fscale * p);
+ sum += t * amp;
+ amp *= 0.5f;
+ fscale *= 2.0f;
+ }
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ float t = noise_2d(fscale * p);
+ float sum2 = sum + t * amp;
+ sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1));
+ sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1));
+ return (1.0f - rmd) * sum + rmd * sum2;
+ }
+ else {
+ sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1));
+ return sum;
+ }
+}
+
+/* The fractal_noise_[1-4] functions are all exactly the same except for the input type. */
+ccl_device_noinline float fractal_noise_3d(float3 p, float octaves)
+{
+ float fscale = 1.0f;
+ float amp = 1.0f;
+ float sum = 0.0f;
+ octaves = clamp(octaves, 0.0f, 16.0f);
+ int n = float_to_int(octaves);
+ for (int i = 0; i <= n; i++) {
+ float t = noise_3d(fscale * p);
+ sum += t * amp;
+ amp *= 0.5f;
+ fscale *= 2.0f;
+ }
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ float t = noise_3d(fscale * p);
+ float sum2 = sum + t * amp;
+ sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1));
+ sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1));
+ return (1.0f - rmd) * sum + rmd * sum2;
+ }
+ else {
+ sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1));
+ return sum;
+ }
+}
+
+/* The fractal_noise_[1-4] functions are all exactly the same except for the input type. */
+ccl_device_noinline float fractal_noise_4d(float4 p, float octaves)
+{
+ float fscale = 1.0f;
+ float amp = 1.0f;
+ float sum = 0.0f;
+ octaves = clamp(octaves, 0.0f, 16.0f);
+ int n = float_to_int(octaves);
+ for (int i = 0; i <= n; i++) {
+ float t = noise_4d(fscale * p);
+ sum += t * amp;
+ amp *= 0.5f;
+ fscale *= 2.0f;
+ }
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ float t = noise_4d(fscale * p);
+ float sum2 = sum + t * amp;
+ sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1));
+ sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1));
+ return (1.0f - rmd) * sum + rmd * sum2;
+ }
+ else {
+ sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1));
+ return sum;
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_mapping.h b/intern/cycles/kernel/svm/svm_mapping.h
index 998a29912d4..6e19c859e19 100644
--- a/intern/cycles/kernel/svm/svm_mapping.h
+++ b/intern/cycles/kernel/svm/svm_mapping.h
@@ -18,7 +18,33 @@ CCL_NAMESPACE_BEGIN
/* Mapping Node */
-ccl_device void svm_node_mapping(
+ccl_device void svm_node_mapping(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint type,
+ uint inputs_stack_offsets,
+ uint result_stack_offset,
+ int *offset)
+{
+ uint vector_stack_offset, location_stack_offset, rotation_stack_offset, scale_stack_offset;
+ svm_unpack_node_uchar4(inputs_stack_offsets,
+ &vector_stack_offset,
+ &location_stack_offset,
+ &rotation_stack_offset,
+ &scale_stack_offset);
+
+ float3 vector = stack_load_float3(stack, vector_stack_offset);
+ float3 location = stack_load_float3(stack, location_stack_offset);
+ float3 rotation = stack_load_float3(stack, rotation_stack_offset);
+ float3 scale = stack_load_float3(stack, scale_stack_offset);
+
+ float3 result = svm_mapping((NodeMappingType)type, vector, location, rotation, scale);
+ stack_store_float3(stack, result_stack_offset, result);
+}
+
+/* Texture Mapping */
+
+ccl_device void svm_node_texture_mapping(
KernelGlobals *kg, ShaderData *sd, float *stack, uint vec_offset, uint out_offset, int *offset)
{
float3 v = stack_load_float3(stack, vec_offset);
diff --git a/intern/cycles/kernel/svm/svm_mapping_util.h b/intern/cycles/kernel/svm/svm_mapping_util.h
new file mode 100644
index 00000000000..ec2c84e0791
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_mapping_util.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011-2014 Blender Foundation
+ *
+ * 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.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device float3
+svm_mapping(NodeMappingType type, float3 vector, float3 location, float3 rotation, float3 scale)
+{
+ Transform rotationTransform = euler_to_transform(rotation);
+ switch (type) {
+ case NODE_MAPPING_TYPE_POINT:
+ return transform_direction(&rotationTransform, (vector * scale)) + location;
+ case NODE_MAPPING_TYPE_TEXTURE:
+ return safe_divide_float3_float3(
+ transform_direction_transposed(&rotationTransform, (vector - location)), scale);
+ case NODE_MAPPING_TYPE_VECTOR:
+ return transform_direction(&rotationTransform, (vector * scale));
+ case NODE_MAPPING_TYPE_NORMAL:
+ return safe_normalize(
+ transform_direction(&rotationTransform, safe_divide_float3_float3(vector, scale)));
+ default:
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_musgrave.h b/intern/cycles/kernel/svm/svm_musgrave.h
index 9291c7e7295..571f62fe27f 100644
--- a/intern/cycles/kernel/svm/svm_musgrave.h
+++ b/intern/cycles/kernel/svm/svm_musgrave.h
@@ -16,7 +16,7 @@
CCL_NAMESPACE_BEGIN
-/* Musgrave fBm
+/* 1D Musgrave fBm
*
* H: fractal increment parameter
* lacunarity: gap between successive frequencies
@@ -25,62 +25,404 @@ CCL_NAMESPACE_BEGIN
* from "Texturing and Modelling: A procedural approach"
*/
-ccl_device_noinline_cpu float noise_musgrave_fBm(float3 p,
- float H,
- float lacunarity,
- float octaves)
+ccl_device_noinline_cpu float noise_musgrave_fBm_1d(float co,
+ float H,
+ float lacunarity,
+ float octaves)
{
- float rmd;
+ float p = co;
float value = 0.0f;
float pwr = 1.0f;
float pwHL = powf(lacunarity, -H);
- int i;
- for (i = 0; i < float_to_int(octaves); i++) {
- value += snoise(p) * pwr;
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value += snoise_1d(p) * pwr;
pwr *= pwHL;
p *= lacunarity;
}
- rmd = octaves - floorf(octaves);
- if (rmd != 0.0f)
- value += rmd * snoise(p) * pwr;
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * snoise_1d(p) * pwr;
+ }
+
+ return value;
+}
+
+/* 1D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_multi_fractal_1d(float co,
+ float H,
+ float lacunarity,
+ float octaves)
+{
+ float p = co;
+ float value = 1.0f;
+ float pwr = 1.0f;
+ float pwHL = powf(lacunarity, -H);
+
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value *= (pwr * snoise_1d(p) + 1.0f);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value *= (rmd * pwr * snoise_1d(p) + 1.0f); /* correct? */
+ }
+
+ return value;
+}
+
+/* 1D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_hetero_terrain_1d(
+ float co, float H, float lacunarity, float octaves, float offset)
+{
+ float p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + snoise_1d(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ float increment = (snoise_1d(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ float increment = (snoise_1d(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+/* 1D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_hybrid_multi_fractal_1d(
+ float co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = snoise_1d(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < float_to_int(octaves)); i++) {
+ if (weight > 1.0f) {
+ weight = 1.0f;
+ }
+
+ float signal = (snoise_1d(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * ((snoise_1d(p) + offset) * pwr);
+ }
+
+ return value;
+}
+
+/* 1D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_ridged_multi_fractal_1d(
+ float co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - fabsf(snoise_1d(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0f;
+
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ p *= lacunarity;
+ weight = saturate(signal * gain);
+ signal = offset - fabsf(snoise_1d(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return value;
+}
+
+/* 2D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_fBm_2d(float2 co,
+ float H,
+ float lacunarity,
+ float octaves)
+{
+ float2 p = co;
+ float value = 0.0f;
+ float pwr = 1.0f;
+ float pwHL = powf(lacunarity, -H);
+
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value += snoise_2d(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * snoise_2d(p) * pwr;
+ }
+
+ return value;
+}
+
+/* 2D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_multi_fractal_2d(float2 co,
+ float H,
+ float lacunarity,
+ float octaves)
+{
+ float2 p = co;
+ float value = 1.0f;
+ float pwr = 1.0f;
+ float pwHL = powf(lacunarity, -H);
+
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value *= (pwr * snoise_2d(p) + 1.0f);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value *= (rmd * pwr * snoise_2d(p) + 1.0f); /* correct? */
+ }
+
+ return value;
+}
+
+/* 2D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_hetero_terrain_2d(
+ float2 co, float H, float lacunarity, float octaves, float offset)
+{
+ float2 p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + snoise_2d(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ float increment = (snoise_2d(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ float increment = (snoise_2d(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+/* 2D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_hybrid_multi_fractal_2d(
+ float2 co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float2 p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = snoise_2d(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < float_to_int(octaves)); i++) {
+ if (weight > 1.0f) {
+ weight = 1.0f;
+ }
+
+ float signal = (snoise_2d(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * ((snoise_2d(p) + offset) * pwr);
+ }
+
+ return value;
+}
+
+/* 2D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_ridged_multi_fractal_2d(
+ float2 co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float2 p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - fabsf(snoise_2d(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0f;
+
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ p *= lacunarity;
+ weight = saturate(signal * gain);
+ signal = offset - fabsf(snoise_2d(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return value;
+}
+
+/* 3D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_fBm_3d(float3 co,
+ float H,
+ float lacunarity,
+ float octaves)
+{
+ float3 p = co;
+ float value = 0.0f;
+ float pwr = 1.0f;
+ float pwHL = powf(lacunarity, -H);
+
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value += snoise_3d(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * snoise_3d(p) * pwr;
+ }
return value;
}
-/* Musgrave Multifractal
+/* 3D Musgrave Multifractal
*
* H: highest fractal dimension
* lacunarity: gap between successive frequencies
* octaves: number of frequencies in the fBm
*/
-ccl_device_noinline_cpu float noise_musgrave_multi_fractal(float3 p,
- float H,
- float lacunarity,
- float octaves)
+ccl_device_noinline_cpu float noise_musgrave_multi_fractal_3d(float3 co,
+ float H,
+ float lacunarity,
+ float octaves)
{
- float rmd;
+ float3 p = co;
float value = 1.0f;
float pwr = 1.0f;
float pwHL = powf(lacunarity, -H);
- int i;
- for (i = 0; i < float_to_int(octaves); i++) {
- value *= (pwr * snoise(p) + 1.0f);
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value *= (pwr * snoise_3d(p) + 1.0f);
pwr *= pwHL;
p *= lacunarity;
}
- rmd = octaves - floorf(octaves);
- if (rmd != 0.0f)
- value *= (rmd * pwr * snoise(p) + 1.0f); /* correct? */
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value *= (rmd * pwr * snoise_3d(p) + 1.0f); /* correct? */
+ }
return value;
}
-/* Musgrave Heterogeneous Terrain
+/* 3D Musgrave Heterogeneous Terrain
*
* H: fractal dimension of the roughest area
* lacunarity: gap between successive frequencies
@@ -88,35 +430,34 @@ ccl_device_noinline_cpu float noise_musgrave_multi_fractal(float3 p,
* offset: raises the terrain from `sea level'
*/
-ccl_device_noinline_cpu float noise_musgrave_hetero_terrain(
- float3 p, float H, float lacunarity, float octaves, float offset)
+ccl_device_noinline_cpu float noise_musgrave_hetero_terrain_3d(
+ float3 co, float H, float lacunarity, float octaves, float offset)
{
- float value, increment, rmd;
+ float3 p = co;
float pwHL = powf(lacunarity, -H);
float pwr = pwHL;
- int i;
/* first unscaled octave of function; later octaves are scaled */
- value = offset + snoise(p);
+ float value = offset + snoise_3d(p);
p *= lacunarity;
- for (i = 1; i < float_to_int(octaves); i++) {
- increment = (snoise(p) + offset) * pwr * value;
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ float increment = (snoise_3d(p) + offset) * pwr * value;
value += increment;
pwr *= pwHL;
p *= lacunarity;
}
- rmd = octaves - floorf(octaves);
+ float rmd = octaves - floorf(octaves);
if (rmd != 0.0f) {
- increment = (snoise(p) + offset) * pwr * value;
+ float increment = (snoise_3d(p) + offset) * pwr * value;
value += rmd * increment;
}
return value;
}
-/* Hybrid Additive/Multiplicative Multifractal Terrain
+/* 3D Hybrid Additive/Multiplicative Multifractal Terrain
*
* H: fractal dimension of the roughest area
* lacunarity: gap between successive frequencies
@@ -124,37 +465,38 @@ ccl_device_noinline_cpu float noise_musgrave_hetero_terrain(
* offset: raises the terrain from `sea level'
*/
-ccl_device_noinline_cpu float noise_musgrave_hybrid_multi_fractal(
- float3 p, float H, float lacunarity, float octaves, float offset, float gain)
+ccl_device_noinline_cpu float noise_musgrave_hybrid_multi_fractal_3d(
+ float3 co, float H, float lacunarity, float octaves, float offset, float gain)
{
- float result, signal, weight, rmd;
+ float3 p = co;
float pwHL = powf(lacunarity, -H);
float pwr = pwHL;
- int i;
- result = snoise(p) + offset;
- weight = gain * result;
+ float value = snoise_3d(p) + offset;
+ float weight = gain * value;
p *= lacunarity;
- for (i = 1; (weight > 0.001f) && (i < float_to_int(octaves)); i++) {
- if (weight > 1.0f)
+ for (int i = 1; (weight > 0.001f) && (i < float_to_int(octaves)); i++) {
+ if (weight > 1.0f) {
weight = 1.0f;
+ }
- signal = (snoise(p) + offset) * pwr;
+ float signal = (snoise_3d(p) + offset) * pwr;
pwr *= pwHL;
- result += weight * signal;
+ value += weight * signal;
weight *= gain * signal;
p *= lacunarity;
}
- rmd = octaves - floorf(octaves);
- if (rmd != 0.0f)
- result += rmd * ((snoise(p) + offset) * pwr);
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * ((snoise_3d(p) + offset) * pwr);
+ }
- return result;
+ return value;
}
-/* Ridged Multifractal Terrain
+/* 3D Ridged Multifractal Terrain
*
* H: fractal dimension of the roughest area
* lacunarity: gap between successive frequencies
@@ -162,93 +504,346 @@ ccl_device_noinline_cpu float noise_musgrave_hybrid_multi_fractal(
* offset: raises the terrain from `sea level'
*/
-ccl_device_noinline_cpu float noise_musgrave_ridged_multi_fractal(
- float3 p, float H, float lacunarity, float octaves, float offset, float gain)
+ccl_device_noinline_cpu float noise_musgrave_ridged_multi_fractal_3d(
+ float3 co, float H, float lacunarity, float octaves, float offset, float gain)
{
- float result, signal, weight;
+ float3 p = co;
float pwHL = powf(lacunarity, -H);
float pwr = pwHL;
- int i;
- signal = offset - fabsf(snoise(p));
+ float signal = offset - fabsf(snoise_3d(p));
signal *= signal;
- result = signal;
- weight = 1.0f;
+ float value = signal;
+ float weight = 1.0f;
- for (i = 1; i < float_to_int(octaves); i++) {
+ for (int i = 1; i < float_to_int(octaves); i++) {
p *= lacunarity;
weight = saturate(signal * gain);
- signal = offset - fabsf(snoise(p));
+ signal = offset - fabsf(snoise_3d(p));
signal *= signal;
signal *= weight;
- result += signal * pwr;
+ value += signal * pwr;
pwr *= pwHL;
}
- return result;
+ return value;
}
-/* Shader */
+/* 4D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
-ccl_device float svm_musgrave(NodeMusgraveType type,
- float dimension,
- float lacunarity,
- float octaves,
- float offset,
- float intensity,
- float gain,
- float3 p)
+ccl_device_noinline_cpu float noise_musgrave_fBm_4d(float4 co,
+ float H,
+ float lacunarity,
+ float octaves)
{
- if (type == NODE_MUSGRAVE_MULTIFRACTAL)
- return intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves);
- else if (type == NODE_MUSGRAVE_FBM)
- return intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves);
- else if (type == NODE_MUSGRAVE_HYBRID_MULTIFRACTAL)
- return intensity *
- noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
- else if (type == NODE_MUSGRAVE_RIDGED_MULTIFRACTAL)
- return intensity *
- noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
- else if (type == NODE_MUSGRAVE_HETERO_TERRAIN)
- return intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, offset);
+ float4 p = co;
+ float value = 0.0f;
+ float pwr = 1.0f;
+ float pwHL = powf(lacunarity, -H);
+
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value += snoise_4d(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * snoise_4d(p) * pwr;
+ }
- return 0.0f;
+ return value;
}
-ccl_device void svm_node_tex_musgrave(
- KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
+/* 4D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_multi_fractal_4d(float4 co,
+ float H,
+ float lacunarity,
+ float octaves)
{
- uint4 node2 = read_node(kg, offset);
- uint4 node3 = read_node(kg, offset);
+ float4 p = co;
+ float value = 1.0f;
+ float pwr = 1.0f;
+ float pwHL = powf(lacunarity, -H);
- uint type, co_offset, color_offset, fac_offset;
- uint dimension_offset, lacunarity_offset, detail_offset, offset_offset;
- uint gain_offset, scale_offset;
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value *= (pwr * snoise_4d(p) + 1.0f);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
- svm_unpack_node_uchar4(node.y, &type, &co_offset, &color_offset, &fac_offset);
- svm_unpack_node_uchar4(
- node.z, &dimension_offset, &lacunarity_offset, &detail_offset, &offset_offset);
- svm_unpack_node_uchar2(node.w, &gain_offset, &scale_offset);
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value *= (rmd * pwr * snoise_4d(p) + 1.0f); /* correct? */
+ }
- float3 co = stack_load_float3(stack, co_offset);
- float dimension = stack_load_float_default(stack, dimension_offset, node2.x);
- float lacunarity = stack_load_float_default(stack, lacunarity_offset, node2.y);
- float detail = stack_load_float_default(stack, detail_offset, node2.z);
- float foffset = stack_load_float_default(stack, offset_offset, node2.w);
- float gain = stack_load_float_default(stack, gain_offset, node3.x);
- float scale = stack_load_float_default(stack, scale_offset, node3.y);
+ return value;
+}
+
+/* 4D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_hetero_terrain_4d(
+ float4 co, float H, float lacunarity, float octaves, float offset)
+{
+ float4 p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + snoise_4d(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ float increment = (snoise_4d(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ float increment = (snoise_4d(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+/* 4D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_hybrid_multi_fractal_4d(
+ float4 co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float4 p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = snoise_4d(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < float_to_int(octaves)); i++) {
+ if (weight > 1.0f) {
+ weight = 1.0f;
+ }
+
+ float signal = (snoise_4d(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * ((snoise_4d(p) + offset) * pwr);
+ }
+
+ return value;
+}
+
+/* 4D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline_cpu float noise_musgrave_ridged_multi_fractal_4d(
+ float4 co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float4 p = co;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - fabsf(snoise_4d(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0f;
+
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ p *= lacunarity;
+ weight = saturate(signal * gain);
+ signal = offset - fabsf(snoise_4d(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return value;
+}
+
+ccl_device void svm_node_tex_musgrave(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint offsets1,
+ uint offsets2,
+ uint offsets3,
+ int *offset)
+{
+ uint type, dimensions, co_stack_offset, w_stack_offset;
+ uint scale_stack_offset, detail_stack_offset, dimension_stack_offset, lacunarity_stack_offset;
+ uint offset_stack_offset, gain_stack_offset, fac_stack_offset;
+
+ svm_unpack_node_uchar4(offsets1, &type, &dimensions, &co_stack_offset, &w_stack_offset);
+ svm_unpack_node_uchar4(offsets2,
+ &scale_stack_offset,
+ &detail_stack_offset,
+ &dimension_stack_offset,
+ &lacunarity_stack_offset);
+ svm_unpack_node_uchar3(offsets3, &offset_stack_offset, &gain_stack_offset, &fac_stack_offset);
+
+ uint4 defaults1 = read_node(kg, offset);
+ uint4 defaults2 = read_node(kg, offset);
+
+ float3 co = stack_load_float3(stack, co_stack_offset);
+ float w = stack_load_float_default(stack, w_stack_offset, defaults1.x);
+ float scale = stack_load_float_default(stack, scale_stack_offset, defaults1.y);
+ float detail = stack_load_float_default(stack, detail_stack_offset, defaults1.z);
+ float dimension = stack_load_float_default(stack, dimension_stack_offset, defaults1.w);
+ float lacunarity = stack_load_float_default(stack, lacunarity_stack_offset, defaults2.x);
+ float foffset = stack_load_float_default(stack, offset_stack_offset, defaults2.y);
+ float gain = stack_load_float_default(stack, gain_stack_offset, defaults2.z);
dimension = fmaxf(dimension, 1e-5f);
detail = clamp(detail, 0.0f, 16.0f);
lacunarity = fmaxf(lacunarity, 1e-5f);
- float f = svm_musgrave(
- (NodeMusgraveType)type, dimension, lacunarity, detail, foffset, 1.0f, gain, co * scale);
+ float fac;
+
+ switch (dimensions) {
+ case 1: {
+ float p = w * scale;
+ switch ((NodeMusgraveType)type) {
+ case NODE_MUSGRAVE_MULTIFRACTAL:
+ fac = noise_musgrave_multi_fractal_1d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_FBM:
+ fac = noise_musgrave_fBm_1d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_HYBRID_MULTIFRACTAL:
+ fac = noise_musgrave_hybrid_multi_fractal_1d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_RIDGED_MULTIFRACTAL:
+ fac = noise_musgrave_ridged_multi_fractal_1d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_HETERO_TERRAIN:
+ fac = noise_musgrave_hetero_terrain_1d(p, dimension, lacunarity, detail, foffset);
+ break;
+ default:
+ fac = 0.0f;
+ }
+ break;
+ }
+ case 2: {
+ float2 p = make_float2(co.x, co.y) * scale;
+ switch ((NodeMusgraveType)type) {
+ case NODE_MUSGRAVE_MULTIFRACTAL:
+ fac = noise_musgrave_multi_fractal_2d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_FBM:
+ fac = noise_musgrave_fBm_2d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_HYBRID_MULTIFRACTAL:
+ fac = noise_musgrave_hybrid_multi_fractal_2d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_RIDGED_MULTIFRACTAL:
+ fac = noise_musgrave_ridged_multi_fractal_2d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_HETERO_TERRAIN:
+ fac = noise_musgrave_hetero_terrain_2d(p, dimension, lacunarity, detail, foffset);
+ break;
+ default:
+ fac = 0.0f;
+ }
+ break;
+ }
+ case 3: {
+ float3 p = co * scale;
+ switch ((NodeMusgraveType)type) {
+ case NODE_MUSGRAVE_MULTIFRACTAL:
+ fac = noise_musgrave_multi_fractal_3d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_FBM:
+ fac = noise_musgrave_fBm_3d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_HYBRID_MULTIFRACTAL:
+ fac = noise_musgrave_hybrid_multi_fractal_3d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_RIDGED_MULTIFRACTAL:
+ fac = noise_musgrave_ridged_multi_fractal_3d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_HETERO_TERRAIN:
+ fac = noise_musgrave_hetero_terrain_3d(p, dimension, lacunarity, detail, foffset);
+ break;
+ default:
+ fac = 0.0f;
+ }
+ break;
+ }
+ case 4: {
+ float4 p = make_float4(co.x, co.y, co.z, w) * scale;
+ switch ((NodeMusgraveType)type) {
+ case NODE_MUSGRAVE_MULTIFRACTAL:
+ fac = noise_musgrave_multi_fractal_4d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_FBM:
+ fac = noise_musgrave_fBm_4d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_HYBRID_MULTIFRACTAL:
+ fac = noise_musgrave_hybrid_multi_fractal_4d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_RIDGED_MULTIFRACTAL:
+ fac = noise_musgrave_ridged_multi_fractal_4d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_HETERO_TERRAIN:
+ fac = noise_musgrave_hetero_terrain_4d(p, dimension, lacunarity, detail, foffset);
+ break;
+ default:
+ fac = 0.0f;
+ }
+ break;
+ }
+ default:
+ fac = 0.0f;
+ }
- if (stack_valid(fac_offset))
- stack_store_float(stack, fac_offset, f);
- if (stack_valid(color_offset))
- stack_store_float3(stack, color_offset, make_float3(f, f, f));
+ stack_store_float(stack, fac_stack_offset, fac);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_noise.h b/intern/cycles/kernel/svm/svm_noise.h
index dd375af27e5..a16b226d8de 100644
--- a/intern/cycles/kernel/svm/svm_noise.h
+++ b/intern/cycles/kernel/svm/svm_noise.h
@@ -32,270 +32,562 @@
CCL_NAMESPACE_BEGIN
-#ifdef __KERNEL_SSE2__
-ccl_device_inline ssei quick_floor_sse(const ssef &x)
-{
- ssei b = truncatei(x);
- ssei isneg = cast((x < ssef(0.0f)).m128);
- return b + isneg; // unsaturated add 0xffffffff is the same as subtract -1
-}
-#endif
-
-#ifdef __KERNEL_SSE2__
-ccl_device_inline ssei hash_sse(const ssei &kx, const ssei &ky, const ssei &kz)
-{
-# define rot(x, k) (((x) << (k)) | (srl(x, 32 - (k))))
-# define xor_rot(a, b, c) \
- do { \
- a = a ^ b; \
- a = a - rot(b, c); \
- } while (0)
-
- uint len = 3;
- ssei magic = ssei(0xdeadbeef + (len << 2) + 13);
- ssei a = magic + kx;
- ssei b = magic + ky;
- ssei c = magic + kz;
-
- xor_rot(c, b, 14);
- xor_rot(a, c, 11);
- xor_rot(b, a, 25);
- xor_rot(c, b, 16);
- xor_rot(a, c, 4);
- xor_rot(b, a, 14);
- xor_rot(c, b, 24);
-
- return c;
-# undef rot
-# undef xor_rot
-}
-#endif
+/* **** Perlin Noise **** */
-#if 0 // unused
-ccl_device int imod(int a, int b)
+ccl_device float fade(float t)
{
- a %= b;
- return a < 0 ? a + b : a;
+ return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
}
-ccl_device uint phash(int kx, int ky, int kz, int3 p)
+ccl_device_inline float negate_if(float val, int condition)
{
- return hash(imod(kx, p.x), imod(ky, p.y), imod(kz, p.z));
+ return (condition) ? -val : val;
}
-#endif
-#ifndef __KERNEL_SSE2__
-ccl_device float floorfrac(float x, int *i)
+ccl_device float grad1(int hash, float x)
{
- *i = quick_floor_to_int(x);
- return x - *i;
+ int h = hash & 15;
+ float g = 1 + (h & 7);
+ return negate_if(g, h & 8) * x;
}
-#else
-ccl_device_inline ssef floorfrac_sse(const ssef &x, ssei *i)
+
+ccl_device_noinline_cpu float perlin_1d(float x)
{
- *i = quick_floor_sse(x);
- return x - ssef(*i);
+ int X;
+ float fx = floorfrac(x, &X);
+ float u = fade(fx);
+
+ return mix(grad1(hash_uint(X), fx), grad1(hash_uint(X + 1), fx - 1.0f), u);
}
-#endif
+/* 2D, 3D, and 4D noise can be accelerated using SSE, so we first check if
+ * SSE is supported, that is, if __KERNEL_SSE2__ is defined. If it is not
+ * supported, we do a standard implementation, but if it is supported, we
+ * do an implementation using SSE intrinsics.
+ */
#ifndef __KERNEL_SSE2__
-ccl_device float fade(float t)
+
+/* ** Standard Implementation ** */
+
+/* Bilinear Interpolation:
+ *
+ * v2 v3
+ * @ + + + + @ y
+ * + + ^
+ * + + |
+ * + + |
+ * @ + + + + @ @------> x
+ * v0 v1
+ *
+ */
+ccl_device float bi_mix(float v0, float v1, float v2, float v3, float x, float y)
{
- return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
+ float x1 = 1.0f - x;
+ return (1.0f - y) * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x);
}
-#else
-ccl_device_inline ssef fade_sse(const ssef *t)
+
+/* Trilinear Interpolation:
+ *
+ * v6 v7
+ * @ + + + + + + @
+ * +\ +\
+ * + \ + \
+ * + \ + \
+ * + \ v4 + \ v5
+ * + @ + + + +++ + @ z
+ * + + + + y ^
+ * v2 @ + +++ + + + @ v3 + \ |
+ * \ + \ + \ |
+ * \ + \ + \|
+ * \ + \ + +---------> x
+ * \+ \+
+ * @ + + + + + + @
+ * v0 v1
+ */
+ccl_device float tri_mix(float v0,
+ float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6,
+ float v7,
+ float x,
+ float y,
+ float z)
{
- ssef a = madd(*t, ssef(6.0f), ssef(-15.0f));
- ssef b = madd(*t, a, ssef(10.0f));
- return ((*t) * (*t)) * ((*t) * b);
+ float x1 = 1.0f - x;
+ float y1 = 1.0f - y;
+ float z1 = 1.0f - z;
+ return z1 * (y1 * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x)) +
+ z * (y1 * (v4 * x1 + v5 * x) + y * (v6 * x1 + v7 * x));
}
-#endif
-#ifndef __KERNEL_SSE2__
-ccl_device float nerp(float t, float a, float b)
+ccl_device float quad_mix(float v0,
+ float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6,
+ float v7,
+ float v8,
+ float v9,
+ float v10,
+ float v11,
+ float v12,
+ float v13,
+ float v14,
+ float v15,
+ float x,
+ float y,
+ float z,
+ float w)
{
- return (1.0f - t) * a + t * b;
+ return mix(tri_mix(v0, v1, v2, v3, v4, v5, v6, v7, x, y, z),
+ tri_mix(v8, v9, v10, v11, v12, v13, v14, v15, x, y, z),
+ w);
}
-#else
-ccl_device_inline ssef nerp_sse(const ssef &t, const ssef &a, const ssef &b)
+
+ccl_device float grad2(int hash, float x, float y)
{
- ssef x1 = (ssef(1.0f) - t) * a;
- return madd(t, b, x1);
+ int h = hash & 7;
+ float u = h < 4 ? x : y;
+ float v = 2.0f * (h < 4 ? y : x);
+ return negate_if(u, h & 1) + negate_if(v, h & 2);
}
-#endif
-#ifndef __KERNEL_SSE2__
-ccl_device float grad(int hash, float x, float y, float z)
+ccl_device float grad3(int hash, float x, float y, float z)
{
- // use vectors pointing to the edges of the cube
int h = hash & 15;
float u = h < 8 ? x : y;
- float vt = ((h == 12) | (h == 14)) ? x : z;
+ float vt = ((h == 12) || (h == 14)) ? x : z;
float v = h < 4 ? y : vt;
- return ((h & 1) ? -u : u) + ((h & 2) ? -v : v);
+ return negate_if(u, h & 1) + negate_if(v, h & 2);
}
-#else
-ccl_device_inline ssef grad_sse(const ssei &hash, const ssef &x, const ssef &y, const ssef &z)
-{
- ssei c1 = ssei(1);
- ssei c2 = ssei(2);
- ssei h = hash & ssei(15); // h = hash & 15
+ccl_device float grad4(int hash, float x, float y, float z, float w)
+{
+ int h = hash & 31;
+ float u = h < 24 ? x : y;
+ float v = h < 16 ? y : z;
+ float s = h < 8 ? z : w;
+ return negate_if(u, h & 1) + negate_if(v, h & 2) + negate_if(s, h & 4);
+}
- sseb case_ux = h < ssei(8); // 0xffffffff if h < 8 else 0
+ccl_device_noinline_cpu float perlin_2d(float x, float y)
+{
+ int X;
+ int Y;
- ssef u = select(case_ux, x, y); // u = h<8 ? x : y
+ float fx = floorfrac(x, &X);
+ float fy = floorfrac(y, &Y);
- sseb case_vy = h < ssei(4); // 0xffffffff if h < 4 else 0
+ float u = fade(fx);
+ float v = fade(fy);
- sseb case_h12 = h == ssei(12); // 0xffffffff if h == 12 else 0
- sseb case_h14 = h == ssei(14); // 0xffffffff if h == 14 else 0
+ float r = bi_mix(grad2(hash_uint2(X, Y), fx, fy),
+ grad2(hash_uint2(X + 1, Y), fx - 1.0f, fy),
+ grad2(hash_uint2(X, Y + 1), fx, fy - 1.0f),
+ grad2(hash_uint2(X + 1, Y + 1), fx - 1.0f, fy - 1.0f),
+ u,
+ v);
- sseb case_vx = case_h12 | case_h14; // 0xffffffff if h == 12 or h == 14 else 0
+ return r;
+}
- ssef v = select(case_vy, y, select(case_vx, x, z)); // v = h<4 ? y : h == 12 || h == 14 ? x : z
+ccl_device_noinline_cpu float perlin_3d(float x, float y, float z)
+{
+ int X;
+ int Y;
+ int Z;
- ssei case_uneg = (h & c1) << 31; // 1<<31 if h&1 else 0
- ssef case_uneg_mask = cast(case_uneg); // -0.0 if h&1 else +0.0
- ssef ru = u ^ case_uneg_mask; // -u if h&1 else u (copy float sign)
+ float fx = floorfrac(x, &X);
+ float fy = floorfrac(y, &Y);
+ float fz = floorfrac(z, &Z);
- ssei case_vneg = (h & c2) << 30; // 2<<30 if h&2 else 0
- ssef case_vneg_mask = cast(case_vneg); // -0.0 if h&2 else +0.0
- ssef rv = v ^ case_vneg_mask; // -v if h&2 else v (copy float sign)
+ float u = fade(fx);
+ float v = fade(fy);
+ float w = fade(fz);
- ssef r = ru + rv; // ((h&1) ? -u : u) + ((h&2) ? -v : v)
+ float r = tri_mix(grad3(hash_uint3(X, Y, Z), fx, fy, fz),
+ grad3(hash_uint3(X + 1, Y, Z), fx - 1.0f, fy, fz),
+ grad3(hash_uint3(X, Y + 1, Z), fx, fy - 1.0f, fz),
+ grad3(hash_uint3(X + 1, Y + 1, Z), fx - 1.0f, fy - 1.0f, fz),
+ grad3(hash_uint3(X, Y, Z + 1), fx, fy, fz - 1.0f),
+ grad3(hash_uint3(X + 1, Y, Z + 1), fx - 1.0f, fy, fz - 1.0f),
+ grad3(hash_uint3(X, Y + 1, Z + 1), fx, fy - 1.0f, fz - 1.0f),
+ grad3(hash_uint3(X + 1, Y + 1, Z + 1), fx - 1.0f, fy - 1.0f, fz - 1.0f),
+ u,
+ v,
+ w);
return r;
}
-#endif
-
-#ifndef __KERNEL_SSE2__
-ccl_device float scale3(float result)
-{
- return 0.9820f * result;
-}
-#else
-ccl_device_inline ssef scale3_sse(const ssef &result)
-{
- return ssef(0.9820f) * result;
-}
-#endif
-#ifndef __KERNEL_SSE2__
-ccl_device_noinline_cpu float perlin(float x, float y, float z)
+ccl_device_noinline_cpu float perlin_4d(float x, float y, float z, float w)
{
int X;
- float fx = floorfrac(x, &X);
int Y;
- float fy = floorfrac(y, &Y);
int Z;
+ int W;
+
+ float fx = floorfrac(x, &X);
+ float fy = floorfrac(y, &Y);
float fz = floorfrac(z, &Z);
+ float fw = floorfrac(w, &W);
float u = fade(fx);
float v = fade(fy);
- float w = fade(fz);
+ float t = fade(fz);
+ float s = fade(fw);
+
+ float r = quad_mix(
+ grad4(hash_uint4(X, Y, Z, W), fx, fy, fz, fw),
+ grad4(hash_uint4(X + 1, Y, Z, W), fx - 1.0f, fy, fz, fw),
+ grad4(hash_uint4(X, Y + 1, Z, W), fx, fy - 1.0f, fz, fw),
+ grad4(hash_uint4(X + 1, Y + 1, Z, W), fx - 1.0f, fy - 1.0f, fz, fw),
+ grad4(hash_uint4(X, Y, Z + 1, W), fx, fy, fz - 1.0f, fw),
+ grad4(hash_uint4(X + 1, Y, Z + 1, W), fx - 1.0f, fy, fz - 1.0f, fw),
+ grad4(hash_uint4(X, Y + 1, Z + 1, W), fx, fy - 1.0f, fz - 1.0f, fw),
+ grad4(hash_uint4(X + 1, Y + 1, Z + 1, W), fx - 1.0f, fy - 1.0f, fz - 1.0f, fw),
+ grad4(hash_uint4(X, Y, Z, W + 1), fx, fy, fz, fw - 1.0f),
+ grad4(hash_uint4(X + 1, Y, Z, W + 1), fx - 1.0f, fy, fz, fw - 1.0f),
+ grad4(hash_uint4(X, Y + 1, Z, W + 1), fx, fy - 1.0f, fz, fw - 1.0f),
+ grad4(hash_uint4(X + 1, Y + 1, Z, W + 1), fx - 1.0f, fy - 1.0f, fz, fw - 1.0f),
+ grad4(hash_uint4(X, Y, Z + 1, W + 1), fx, fy, fz - 1.0f, fw - 1.0f),
+ grad4(hash_uint4(X + 1, Y, Z + 1, W + 1), fx - 1.0f, fy, fz - 1.0f, fw - 1.0f),
+ grad4(hash_uint4(X, Y + 1, Z + 1, W + 1), fx, fy - 1.0f, fz - 1.0f, fw - 1.0f),
+ grad4(hash_uint4(X + 1, Y + 1, Z + 1, W + 1), fx - 1.0f, fy - 1.0f, fz - 1.0f, fw - 1.0f),
+ u,
+ v,
+ t,
+ s);
- float result;
-
- result = nerp(
- w,
- nerp(v,
- nerp(u,
- grad(hash_uint3(X, Y, Z), fx, fy, fz),
- grad(hash_uint3(X + 1, Y, Z), fx - 1.0f, fy, fz)),
- nerp(u,
- grad(hash_uint3(X, Y + 1, Z), fx, fy - 1.0f, fz),
- grad(hash_uint3(X + 1, Y + 1, Z), fx - 1.0f, fy - 1.0f, fz))),
- nerp(v,
- nerp(u,
- grad(hash_uint3(X, Y, Z + 1), fx, fy, fz - 1.0f),
- grad(hash_uint3(X + 1, Y, Z + 1), fx - 1.0f, fy, fz - 1.0f)),
- nerp(u,
- grad(hash_uint3(X, Y + 1, Z + 1), fx, fy - 1.0f, fz - 1.0f),
- grad(hash_uint3(X + 1, Y + 1, Z + 1), fx - 1.0f, fy - 1.0f, fz - 1.0f))));
- float r = scale3(result);
-
- /* can happen for big coordinates, things even out to 0.0 then anyway */
- return (isfinite(r)) ? r : 0.0f;
+ return r;
}
+
#else
-ccl_device_noinline float perlin(float x, float y, float z)
+
+/* ** SSE Implementation ** */
+
+/* SSE Bilinear Interpolation:
+ *
+ * The function takes two ssef inputs:
+ * - p : Contains the values at the points (v0, v1, v2, v3).
+ * - f : Contains the values (x, y, _, _). The third and fourth values are unused.
+ *
+ * The interpolation is done in two steps:
+ * 1. Interpolate (v0, v1) and (v2, v3) along the x axis to get g (g0, g1).
+ * (v2, v3) is generated by moving v2 and v3 to the first and second
+ * places of the ssef using the shuffle mask <2, 3, 2, 3>. The third and
+ * fourth values are unused.
+ * 2. Interpolate g0 and g1 along the y axis to get the final value.
+ * g1 is generated by populating an ssef with the second value of g.
+ * Only the first value is important in the final ssef.
+ *
+ * v1 v3 g1
+ * @ + + + + @ @ y
+ * + + (1) + (2) ^
+ * + + ---> + ---> final |
+ * + + + |
+ * @ + + + + @ @ @------> x
+ * v0 v2 g0
+ *
+ */
+ccl_device_inline ssef bi_mix(ssef p, ssef f)
+{
+ ssef g = mix(p, shuffle<2, 3, 2, 3>(p), shuffle<0>(f));
+ return mix(g, shuffle<1>(g), shuffle<1>(f));
+}
+
+/* SSE Trilinear Interpolation:
+ *
+ * The function takes three ssef inputs:
+ * - p : Contains the values at the points (v0, v1, v2, v3).
+ * - q : Contains the values at the points (v4, v5, v6, v7).
+ * - f : Contains the values (x, y, z, _). The fourth value is unused.
+ *
+ * The interpolation is done in three steps:
+ * 1. Interpolate p and q along the x axis to get s (s0, s1, s2, s3).
+ * 2. Interpolate (s0, s1) and (s2, s3) along the y axis to get g (g0, g1).
+ * (s2, s3) is generated by moving v2 and v3 to the first and second
+ * places of the ssef using the shuffle mask <2, 3, 2, 3>. The third and
+ * fourth values are unused.
+ * 3. Interpolate g0 and g1 along the z axis to get the final value.
+ * g1 is generated by populating an ssef with the second value of g.
+ * Only the first value is important in the final ssef.
+ *
+ * v3 v7
+ * @ + + + + + + @ s3 @
+ * +\ +\ +\
+ * + \ + \ + \
+ * + \ + \ + \ g1
+ * + \ v1 + \ v5 + \ s1 @
+ * + @ + + + +++ + @ + @ + z
+ * + + + + (1) + + (2) + (3) y ^
+ * v2 @ + +++ + + + @ v6 + ---> s2 @ + ---> + ---> final \ |
+ * \ + \ + \ + + \ |
+ * \ + \ + \ + + \|
+ * \ + \ + \ + @ +---------> x
+ * \+ \+ \+ g0
+ * @ + + + + + + @ @
+ * v0 v4 s0
+ */
+ccl_device_inline ssef tri_mix(ssef p, ssef q, ssef f)
+{
+ ssef s = mix(p, q, shuffle<0>(f));
+ ssef g = mix(s, shuffle<2, 3, 2, 3>(s), shuffle<1>(f));
+ return mix(g, shuffle<1>(g), shuffle<2>(f));
+}
+
+/* SSE Quadrilinear Interpolation:
+ *
+ * Quadrilinear interpolation is as simple as a linear interpolation
+ * between two trilinear interpolations.
+ *
+ */
+ccl_device_inline ssef quad_mix(ssef p, ssef q, ssef r, ssef s, ssef f)
+{
+ return mix(tri_mix(p, q, f), tri_mix(r, s, f), shuffle<3>(f));
+}
+
+ccl_device_inline ssef fade(const ssef &t)
+{
+ ssef a = madd(t, 6.0f, -15.0f);
+ ssef b = madd(t, a, 10.0f);
+ return (t * t) * (t * b);
+}
+
+/* Negate val if the nth bit of h is 1. */
+# define negate_if_nth_bit(val, h, n) ((val) ^ cast(((h) & (1 << (n))) << (31 - (n))))
+
+ccl_device_inline ssef grad(const ssei &hash, const ssef &x, const ssef &y)
+{
+ ssei h = hash & 7;
+ ssef u = select(h < 4, x, y);
+ ssef v = 2.0f * select(h < 4, y, x);
+ return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1);
+}
+
+ccl_device_inline ssef grad(const ssei &hash, const ssef &x, const ssef &y, const ssef &z)
+{
+ ssei h = hash & 15;
+ ssef u = select(h < 8, x, y);
+ ssef vt = select((h == 12) | (h == 14), x, z);
+ ssef v = select(h < 4, y, vt);
+ return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1);
+}
+
+ccl_device_inline ssef
+grad(const ssei &hash, const ssef &x, const ssef &y, const ssef &z, const ssef &w)
+{
+ ssei h = hash & 31;
+ ssef u = select(h < 24, x, y);
+ ssef v = select(h < 16, y, z);
+ ssef s = select(h < 8, z, w);
+ return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1) + negate_if_nth_bit(s, h, 2);
+}
+
+/* We use SSE to compute and interpolate 4 gradients at once:
+ *
+ * Point Offset from v0
+ * v0 (0, 0)
+ * v1 (0, 1)
+ * v2 (1, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<1, 1, 1, 1>(V, V + 1))
+ * v3 (1, 1) ^
+ * | |__________| (0, 0, 1, 1) = shuffle<0, 0, 0, 0>(V, V + 1)
+ * | ^
+ * |__________________________|
+ *
+ */
+ccl_device_noinline float perlin_2d(float x, float y)
+{
+ ssei XY;
+ ssef fxy = floorfrac(ssef(x, y, 0.0f, 0.0f), &XY);
+ ssef uv = fade(fxy);
+
+ ssei XY1 = XY + 1;
+ ssei X = shuffle<0, 0, 0, 0>(XY, XY1);
+ ssei Y = shuffle<0, 2, 0, 2>(shuffle<1, 1, 1, 1>(XY, XY1));
+
+ ssei h = hash_ssei2(X, Y);
+
+ ssef fxy1 = fxy - 1.0f;
+ ssef fx = shuffle<0, 0, 0, 0>(fxy, fxy1);
+ ssef fy = shuffle<0, 2, 0, 2>(shuffle<1, 1, 1, 1>(fxy, fxy1));
+
+ ssef g = grad(h, fx, fy);
+
+ return extract<0>(bi_mix(g, uv));
+}
+
+/* We use SSE to compute and interpolate 4 gradients at once. Since we have 8
+ * gradients in 3D, we need to compute two sets of gradients at the points:
+ *
+ * Point Offset from v0
+ * v0 (0, 0, 0)
+ * v1 (0, 0, 1)
+ * v2 (0, 1, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(V, V + 1))
+ * v3 (0, 1, 1) ^
+ * | |__________| (0, 0, 1, 1) = shuffle<1, 1, 1, 1>(V, V + 1)
+ * | ^
+ * |__________________________|
+ *
+ * Point Offset from v0
+ * v4 (1, 0, 0)
+ * v5 (1, 0, 1)
+ * v6 (1, 1, 0)
+ * v7 (1, 1, 1)
+ *
+ */
+ccl_device_noinline float perlin_3d(float x, float y, float z)
{
- ssef xyz = ssef(x, y, z, 0.0f);
ssei XYZ;
+ ssef fxyz = floorfrac(ssef(x, y, z, 0.0f), &XYZ);
+ ssef uvw = fade(fxyz);
+
+ ssei XYZ1 = XYZ + 1;
+ ssei Y = shuffle<1, 1, 1, 1>(XYZ, XYZ1);
+ ssei Z = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZ, XYZ1));
+
+ ssei h1 = hash_ssei3(shuffle<0>(XYZ), Y, Z);
+ ssei h2 = hash_ssei3(shuffle<0>(XYZ1), Y, Z);
- ssef fxyz = floorfrac_sse(xyz, &XYZ);
+ ssef fxyz1 = fxyz - 1.0f;
+ ssef fy = shuffle<1, 1, 1, 1>(fxyz, fxyz1);
+ ssef fz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyz, fxyz1));
- ssef uvw = fade_sse(&fxyz);
- ssef u = shuffle<0>(uvw), v = shuffle<1>(uvw), w = shuffle<2>(uvw);
+ ssef g1 = grad(h1, shuffle<0>(fxyz), fy, fz);
+ ssef g2 = grad(h2, shuffle<0>(fxyz1), fy, fz);
- ssei XYZ_ofc = XYZ + ssei(1);
- ssei vdy = shuffle<1, 1, 1, 1>(XYZ, XYZ_ofc); // +0, +0, +1, +1
- ssei vdz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZ, XYZ_ofc)); // +0, +1, +0, +1
+ return extract<0>(tri_mix(g1, g2, uvw));
+}
- ssei h1 = hash_sse(shuffle<0>(XYZ), vdy, vdz); // hash directions 000, 001, 010, 011
- ssei h2 = hash_sse(shuffle<0>(XYZ_ofc), vdy, vdz); // hash directions 100, 101, 110, 111
+/* We use SSE to compute and interpolate 4 gradients at once. Since we have 16
+ * gradients in 4D, we need to compute four sets of gradients at the points:
+ *
+ * Point Offset from v0
+ * v0 (0, 0, 0, 0)
+ * v1 (0, 0, 1, 0)
+ * v2 (0, 1, 0, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(V, V + 1))
+ * v3 (0, 1, 1, 0) ^
+ * | |________| (0, 0, 1, 1) = shuffle<1, 1, 1, 1>(V, V + 1)
+ * | ^
+ * |_______________________|
+ *
+ * Point Offset from v0
+ * v4 (1, 0, 0, 0)
+ * v5 (1, 0, 1, 0)
+ * v6 (1, 1, 0, 0)
+ * v7 (1, 1, 1, 0)
+ *
+ * Point Offset from v0
+ * v8 (0, 0, 0, 1)
+ * v9 (0, 0, 1, 1)
+ * v10 (0, 1, 0, 1)
+ * v11 (0, 1, 1, 1)
+ *
+ * Point Offset from v0
+ * v12 (1, 0, 0, 1)
+ * v13 (1, 0, 1, 1)
+ * v14 (1, 1, 0, 1)
+ * v15 (1, 1, 1, 1)
+ *
+ */
+ccl_device_noinline float perlin_4d(float x, float y, float z, float w)
+{
+ ssei XYZW;
+ ssef fxyzw = floorfrac(ssef(x, y, z, w), &XYZW);
+ ssef uvws = fade(fxyzw);
- ssef fxyz_ofc = fxyz - ssef(1.0f);
- ssef vfy = shuffle<1, 1, 1, 1>(fxyz, fxyz_ofc);
- ssef vfz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyz, fxyz_ofc));
+ ssei XYZW1 = XYZW + 1;
+ ssei Y = shuffle<1, 1, 1, 1>(XYZW, XYZW1);
+ ssei Z = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZW, XYZW1));
- ssef g1 = grad_sse(h1, shuffle<0>(fxyz), vfy, vfz);
- ssef g2 = grad_sse(h2, shuffle<0>(fxyz_ofc), vfy, vfz);
- ssef n1 = nerp_sse(u, g1, g2);
+ ssei h1 = hash_ssei4(shuffle<0>(XYZW), Y, Z, shuffle<3>(XYZW));
+ ssei h2 = hash_ssei4(shuffle<0>(XYZW1), Y, Z, shuffle<3>(XYZW));
- ssef n1_half = shuffle<2, 3, 2, 3>(n1); // extract 2 floats to a separate vector
- ssef n2 = nerp_sse(
- v, n1, n1_half); // process nerp([a, b, _, _], [c, d, _, _]) -> [a', b', _, _]
+ ssei h3 = hash_ssei4(shuffle<0>(XYZW), Y, Z, shuffle<3>(XYZW1));
+ ssei h4 = hash_ssei4(shuffle<0>(XYZW1), Y, Z, shuffle<3>(XYZW1));
- ssef n2_second = shuffle<1>(n2); // extract b to a separate vector
- ssef result = nerp_sse(
- w, n2, n2_second); // process nerp([a', _, _, _], [b', _, _, _]) -> [a'', _, _, _]
+ ssef fxyzw1 = fxyzw - 1.0f;
+ ssef fy = shuffle<1, 1, 1, 1>(fxyzw, fxyzw1);
+ ssef fz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyzw, fxyzw1));
- ssef r = scale3_sse(result);
+ ssef g1 = grad(h1, shuffle<0>(fxyzw), fy, fz, shuffle<3>(fxyzw));
+ ssef g2 = grad(h2, shuffle<0>(fxyzw1), fy, fz, shuffle<3>(fxyzw));
- ssef infmask = cast(ssei(0x7f800000));
- ssef rinfmask = ((r & infmask) == infmask).m128; // 0xffffffff if r is inf/-inf/nan else 0
- ssef rfinite = andnot(rinfmask, r); // 0 if r is inf/-inf/nan else r
- return extract<0>(rfinite);
+ ssef g3 = grad(h3, shuffle<0>(fxyzw), fy, fz, shuffle<3>(fxyzw1));
+ ssef g4 = grad(h4, shuffle<0>(fxyzw1), fy, fz, shuffle<3>(fxyzw1));
+
+ return extract<0>(quad_mix(g1, g2, g3, g4, uvws));
}
#endif
-/* perlin noise in range 0..1 */
-ccl_device float noise(float3 p)
+/* Remap the output of noise to a predictable range [-1, 1].
+ * The scale values were computed experimentally by the OSL developers.
+ */
+
+ccl_device_inline float noise_scale1(float result)
{
- float r = perlin(p.x, p.y, p.z);
- return 0.5f * r + 0.5f;
+ return 0.2500f * result;
}
-/* perlin noise in range -1..1 */
-ccl_device float snoise(float3 p)
+ccl_device_inline float noise_scale2(float result)
{
- return perlin(p.x, p.y, p.z);
+ return 0.6616f * result;
}
-/* cell noise */
-ccl_device float cellnoise(float3 p)
+ccl_device_inline float noise_scale3(float result)
{
- int3 ip = quick_floor_to_int3(p);
- return hash_uint3_to_float(ip.x, ip.y, ip.z);
+ return 0.9820f * result;
}
-ccl_device float3 cellnoise3(float3 p)
+ccl_device_inline float noise_scale4(float result)
{
- int3 ip = quick_floor_to_int3(p);
-#ifndef __KERNEL_SSE__
- float r = hash_uint3_to_float(ip.x, ip.y, ip.z);
- float g = hash_uint3_to_float(ip.y, ip.x, ip.z);
- float b = hash_uint3_to_float(ip.y, ip.z, ip.x);
- return make_float3(r, g, b);
-#else
- ssei ip_yxz = shuffle<1, 0, 2, 3>(ssei(ip.m128));
- ssei ip_xyy = shuffle<0, 1, 1, 3>(ssei(ip.m128));
- ssei ip_zzx = shuffle<2, 2, 0, 3>(ssei(ip.m128));
- ssei bits = hash_sse(ip_xyy, ip_yxz, ip_zzx);
- return float3(uint32_to_float(bits) * ssef(1.0f / (float)0xFFFFFFFF));
-#endif
+ return 0.8344f * result;
+}
+
+/* Safe Signed And Unsigned Noise */
+
+ccl_device_inline float snoise_1d(float p)
+{
+ return noise_scale1(ensure_finite(perlin_1d(p)));
+}
+
+ccl_device_inline float noise_1d(float p)
+{
+ return 0.5f * snoise_1d(p) + 0.5f;
+}
+
+ccl_device_inline float snoise_2d(float2 p)
+{
+ return noise_scale2(ensure_finite(perlin_2d(p.x, p.y)));
+}
+
+ccl_device_inline float noise_2d(float2 p)
+{
+ return 0.5f * snoise_2d(p) + 0.5f;
+}
+
+ccl_device_inline float snoise_3d(float3 p)
+{
+ return noise_scale3(ensure_finite(perlin_3d(p.x, p.y, p.z)));
+}
+
+ccl_device_inline float noise_3d(float3 p)
+{
+ return 0.5f * snoise_3d(p) + 0.5f;
+}
+
+ccl_device_inline float snoise_4d(float4 p)
+{
+ return noise_scale4(ensure_finite(perlin_4d(p.x, p.y, p.z, p.w)));
+}
+
+ccl_device_inline float noise_4d(float4 p)
+{
+ return 0.5f * snoise_4d(p) + 0.5f;
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_noisetex.h b/intern/cycles/kernel/svm/svm_noisetex.h
index 91dc11691e6..c5a1e43a729 100644
--- a/intern/cycles/kernel/svm/svm_noisetex.h
+++ b/intern/cycles/kernel/svm/svm_noisetex.h
@@ -16,44 +16,172 @@
CCL_NAMESPACE_BEGIN
-/* Noise */
+/* The following offset functions generate random offsets to be added to texture
+ * coordinates to act as a seed since the noise functions don't have seed values.
+ * A seed value is needed for generating distortion textures and color outputs.
+ * The offset's components are in the range [100, 200], not too high to cause
+ * bad precision and not to small to be noticeable. We use float seed because
+ * OSL only support float hashes.
+ */
+
+ccl_device_inline float random_float_offset(float seed)
+{
+ return 100.0f + hash_float_to_float(seed) * 100.0f;
+}
+
+ccl_device_inline float2 random_float2_offset(float seed)
+{
+ return make_float2(100.0f + hash_float2_to_float(make_float2(seed, 0.0f)) * 100.0f,
+ 100.0f + hash_float2_to_float(make_float2(seed, 1.0f)) * 100.0f);
+}
-ccl_device void svm_node_tex_noise(
- KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
+ccl_device_inline float3 random_float3_offset(float seed)
{
- uint co_offset, scale_offset, detail_offset, distortion_offset, fac_offset, color_offset;
+ return make_float3(100.0f + hash_float2_to_float(make_float2(seed, 0.0f)) * 100.0f,
+ 100.0f + hash_float2_to_float(make_float2(seed, 1.0f)) * 100.0f,
+ 100.0f + hash_float2_to_float(make_float2(seed, 2.0f)) * 100.0f);
+}
- svm_unpack_node_uchar4(node.y, &co_offset, &scale_offset, &detail_offset, &distortion_offset);
- svm_unpack_node_uchar2(node.z, &color_offset, &fac_offset);
+ccl_device_inline float4 random_float4_offset(float seed)
+{
+ return make_float4(100.0f + hash_float2_to_float(make_float2(seed, 0.0f)) * 100.0f,
+ 100.0f + hash_float2_to_float(make_float2(seed, 1.0f)) * 100.0f,
+ 100.0f + hash_float2_to_float(make_float2(seed, 2.0f)) * 100.0f,
+ 100.0f + hash_float2_to_float(make_float2(seed, 3.0f)) * 100.0f);
+}
- uint4 node2 = read_node(kg, offset);
+ccl_device void noise_texture_1d(
+ float co, float detail, float distortion, bool color_is_needed, float *value, float3 *color)
+{
+ float p = co;
+ if (distortion != 0.0f) {
+ p += noise_1d(p + random_float_offset(0.0f)) * distortion;
+ }
+
+ *value = fractal_noise_1d(p, detail);
+ if (color_is_needed) {
+ *color = make_float3(*value,
+ fractal_noise_1d(p + random_float_offset(1.0f), detail),
+ fractal_noise_1d(p + random_float_offset(2.0f), detail));
+ }
+}
+
+ccl_device void noise_texture_2d(
+ float2 co, float detail, float distortion, bool color_is_needed, float *value, float3 *color)
+{
+ float2 p = co;
+ if (distortion != 0.0f) {
+ p += make_float2(noise_2d(p + random_float2_offset(0.0f)) * distortion,
+ noise_2d(p + random_float2_offset(1.0f)) * distortion);
+ }
- float scale = stack_load_float_default(stack, scale_offset, node2.x);
- float detail = stack_load_float_default(stack, detail_offset, node2.y);
- float distortion = stack_load_float_default(stack, distortion_offset, node2.z);
- float3 p = stack_load_float3(stack, co_offset) * scale;
- int hard = 0;
+ *value = fractal_noise_2d(p, detail);
+ if (color_is_needed) {
+ *color = make_float3(*value,
+ fractal_noise_2d(p + random_float2_offset(2.0f), detail),
+ fractal_noise_2d(p + random_float2_offset(3.0f), detail));
+ }
+}
+ccl_device void noise_texture_3d(
+ float3 co, float detail, float distortion, bool color_is_needed, float *value, float3 *color)
+{
+ float3 p = co;
if (distortion != 0.0f) {
- float3 r, offset = make_float3(13.5f, 13.5f, 13.5f);
+ p += make_float3(noise_3d(p + random_float3_offset(0.0f)) * distortion,
+ noise_3d(p + random_float3_offset(1.0f)) * distortion,
+ noise_3d(p + random_float3_offset(2.0f)) * distortion);
+ }
- r.x = noise(p + offset) * distortion;
- r.y = noise(p) * distortion;
- r.z = noise(p - offset) * distortion;
+ *value = fractal_noise_3d(p, detail);
+ if (color_is_needed) {
+ *color = make_float3(*value,
+ fractal_noise_3d(p + random_float3_offset(3.0f), detail),
+ fractal_noise_3d(p + random_float3_offset(4.0f), detail));
+ }
+}
- p += r;
+ccl_device void noise_texture_4d(
+ float4 co, float detail, float distortion, bool color_is_needed, float *value, float3 *color)
+{
+ float4 p = co;
+ if (distortion != 0.0f) {
+ p += make_float4(noise_4d(p + random_float4_offset(0.0f)) * distortion,
+ noise_4d(p + random_float4_offset(1.0f)) * distortion,
+ noise_4d(p + random_float4_offset(2.0f)) * distortion,
+ noise_4d(p + random_float4_offset(3.0f)) * distortion);
}
- float f = noise_turbulence(p, detail, hard);
+ *value = fractal_noise_4d(p, detail);
+ if (color_is_needed) {
+ *color = make_float3(*value,
+ fractal_noise_4d(p + random_float4_offset(4.0f), detail),
+ fractal_noise_4d(p + random_float4_offset(5.0f), detail));
+ }
+}
+
+ccl_device void svm_node_tex_noise(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint dimensions,
+ uint offsets1,
+ uint offsets2,
+ int *offset)
+{
+ uint vector_stack_offset, w_stack_offset, scale_stack_offset, detail_stack_offset;
+ uint distortion_stack_offset, value_stack_offset, color_stack_offset;
+
+ svm_unpack_node_uchar4(
+ offsets1, &vector_stack_offset, &w_stack_offset, &scale_stack_offset, &detail_stack_offset);
+ svm_unpack_node_uchar3(
+ offsets2, &distortion_stack_offset, &value_stack_offset, &color_stack_offset);
+
+ uint4 defaults = read_node(kg, offset);
+
+ float3 vector = stack_load_float3(stack, vector_stack_offset);
+ float w = stack_load_float_default(stack, w_stack_offset, defaults.x);
+ float scale = stack_load_float_default(stack, scale_stack_offset, defaults.y);
+ float detail = stack_load_float_default(stack, detail_stack_offset, defaults.z);
+ float distortion = stack_load_float_default(stack, distortion_stack_offset, defaults.w);
+
+ vector *= scale;
+ w *= scale;
+
+ float value;
+ float3 color;
+ switch (dimensions) {
+ case 1:
+ noise_texture_1d(w, detail, distortion, stack_valid(color_stack_offset), &value, &color);
+ break;
+ case 2:
+ noise_texture_2d(make_float2(vector.x, vector.y),
+ detail,
+ distortion,
+ stack_valid(color_stack_offset),
+ &value,
+ &color);
+ break;
+ case 3:
+ noise_texture_3d(
+ vector, detail, distortion, stack_valid(color_stack_offset), &value, &color);
+ break;
+ case 4:
+ noise_texture_4d(make_float4(vector.x, vector.y, vector.z, w),
+ detail,
+ distortion,
+ stack_valid(color_stack_offset),
+ &value,
+ &color);
+ break;
+ default:
+ kernel_assert(0);
+ }
- if (stack_valid(fac_offset)) {
- stack_store_float(stack, fac_offset, f);
+ if (stack_valid(value_stack_offset)) {
+ stack_store_float(stack, value_stack_offset, value);
}
- if (stack_valid(color_offset)) {
- float3 color = make_float3(f,
- noise_turbulence(make_float3(p.y, p.x, p.z), detail, hard),
- noise_turbulence(make_float3(p.y, p.z, p.x), detail, hard));
- stack_store_float3(stack, color_offset, color);
+ if (stack_valid(color_stack_offset)) {
+ stack_store_float3(stack, color_stack_offset, color);
}
}
diff --git a/intern/cycles/kernel/svm/svm_texture.h b/intern/cycles/kernel/svm/svm_texture.h
deleted file mode 100644
index 290aa85c831..00000000000
--- a/intern/cycles/kernel/svm/svm_texture.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * 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.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Turbulence */
-
-ccl_device_noinline float noise_turbulence(float3 p, float octaves, int hard)
-{
- float fscale = 1.0f;
- float amp = 1.0f;
- float sum = 0.0f;
- int i, n;
-
- octaves = clamp(octaves, 0.0f, 16.0f);
- n = float_to_int(octaves);
-
- for (i = 0; i <= n; i++) {
- float t = noise(fscale * p);
-
- if (hard)
- t = fabsf(2.0f * t - 1.0f);
-
- sum += t * amp;
- amp *= 0.5f;
- fscale *= 2.0f;
- }
-
- float rmd = octaves - floorf(octaves);
-
- if (rmd != 0.0f) {
- float t = noise(fscale * p);
-
- if (hard)
- t = fabsf(2.0f * t - 1.0f);
-
- float sum2 = sum + t * amp;
-
- sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1));
- sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1));
-
- return (1.0f - rmd) * sum + rmd * sum2;
- }
- else {
- sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1));
- return sum;
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index a3caa1ab68d..a6f2327dada 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -140,13 +140,18 @@ typedef enum ShaderNodeType {
NODE_IES,
NODE_MAP_RANGE,
NODE_CLAMP,
+ NODE_TEXTURE_MAPPING,
NODE_TEX_WHITE_NOISE,
+ NODE_VERTEX_COLOR,
+ NODE_VERTEX_COLOR_BUMP_DX,
+ NODE_VERTEX_COLOR_BUMP_DY,
} ShaderNodeType;
typedef enum NodeAttributeType {
NODE_ATTR_FLOAT = 0,
NODE_ATTR_FLOAT2,
NODE_ATTR_FLOAT3,
+ NODE_ATTR_RGBA,
NODE_ATTR_MATRIX
} NodeAttributeType;
@@ -299,6 +304,13 @@ typedef enum NodeVectorMathType {
NODE_VECTOR_MATH_MAXIMUM,
} NodeVectorMathType;
+typedef enum NodeMappingType {
+ NODE_MAPPING_TYPE_POINT,
+ NODE_MAPPING_TYPE_TEXTURE,
+ NODE_MAPPING_TYPE_VECTOR,
+ NODE_MAPPING_TYPE_NORMAL
+} NodeMappingType;
+
typedef enum NodeVectorTransformType {
NODE_VECTOR_TRANSFORM_TYPE_VECTOR,
NODE_VECTOR_TRANSFORM_TYPE_POINT,
@@ -349,24 +361,19 @@ typedef enum NodeGradientType {
NODE_BLEND_SPHERICAL
} NodeGradientType;
-typedef enum NodeVoronoiColoring {
- NODE_VORONOI_INTENSITY,
- NODE_VORONOI_CELLS
-} NodeVoronoiColoring;
-
typedef enum NodeVoronoiDistanceMetric {
- NODE_VORONOI_DISTANCE,
+ NODE_VORONOI_EUCLIDEAN,
NODE_VORONOI_MANHATTAN,
NODE_VORONOI_CHEBYCHEV,
- NODE_VORONOI_MINKOWSKI
+ NODE_VORONOI_MINKOWSKI,
} NodeVoronoiDistanceMetric;
typedef enum NodeVoronoiFeature {
NODE_VORONOI_F1,
NODE_VORONOI_F2,
- NODE_VORONOI_F3,
- NODE_VORONOI_F4,
- NODE_VORONOI_F2F1
+ NODE_VORONOI_SMOOTH_F1,
+ NODE_VORONOI_DISTANCE_TO_EDGE,
+ NODE_VORONOI_N_SPHERE_RADIUS,
} NodeVoronoiFeature;
typedef enum NodeBlendWeightType {
diff --git a/intern/cycles/kernel/svm/svm_vertex_color.h b/intern/cycles/kernel/svm/svm_vertex_color.h
new file mode 100644
index 00000000000..3c105b1cbfa
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_vertex_color.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * 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.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device void svm_node_vertex_color(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint layer_id,
+ uint color_offset,
+ uint alpha_offset)
+{
+ AttributeDescriptor descriptor = find_attribute(kg, sd, layer_id);
+ if (descriptor.offset != ATTR_STD_NOT_FOUND) {
+ float4 vertex_color = primitive_attribute_float4(kg, sd, descriptor, NULL, NULL);
+ stack_store_float3(stack, color_offset, float4_to_float3(vertex_color));
+ stack_store_float(stack, alpha_offset, vertex_color.w);
+ }
+ else {
+ stack_store_float3(stack, color_offset, make_float3(0.0f, 0.0f, 0.0f));
+ stack_store_float(stack, alpha_offset, 0.0f);
+ }
+}
+
+#ifndef __KERNEL_CUDA__
+ccl_device
+#else
+ccl_device_noinline
+#endif
+ void
+ svm_node_vertex_color_bump_dx(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint layer_id,
+ uint color_offset,
+ uint alpha_offset)
+{
+ AttributeDescriptor descriptor = find_attribute(kg, sd, layer_id);
+ if (descriptor.offset != ATTR_STD_NOT_FOUND) {
+ float4 dx;
+ float4 vertex_color = primitive_attribute_float4(kg, sd, descriptor, &dx, NULL);
+ vertex_color += dx;
+ stack_store_float3(stack, color_offset, float4_to_float3(vertex_color));
+ stack_store_float(stack, alpha_offset, vertex_color.w);
+ }
+ else {
+ stack_store_float3(stack, color_offset, make_float3(0.0f, 0.0f, 0.0f));
+ stack_store_float(stack, alpha_offset, 0.0f);
+ }
+}
+
+#ifndef __KERNEL_CUDA__
+ccl_device
+#else
+ccl_device_noinline
+#endif
+ void
+ svm_node_vertex_color_bump_dy(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint layer_id,
+ uint color_offset,
+ uint alpha_offset)
+{
+ AttributeDescriptor descriptor = find_attribute(kg, sd, layer_id);
+ if (descriptor.offset != ATTR_STD_NOT_FOUND) {
+ float4 dy;
+ float4 vertex_color = primitive_attribute_float4(kg, sd, descriptor, NULL, &dy);
+ vertex_color += dy;
+ stack_store_float3(stack, color_offset, float4_to_float3(vertex_color));
+ stack_store_float(stack, alpha_offset, vertex_color.w);
+ }
+ else {
+ stack_store_float3(stack, color_offset, make_float3(0.0f, 0.0f, 0.0f));
+ stack_store_float(stack, alpha_offset, 0.0f);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_voronoi.h b/intern/cycles/kernel/svm/svm_voronoi.h
index 3d7fa523968..bdfaed8845f 100644
--- a/intern/cycles/kernel/svm/svm_voronoi.h
+++ b/intern/cycles/kernel/svm/svm_voronoi.h
@@ -16,170 +16,1110 @@
CCL_NAMESPACE_BEGIN
-/* Voronoi */
-
-ccl_device void voronoi_neighbors(
- float3 p, NodeVoronoiDistanceMetric distance, float e, float da[4], float3 pa[4])
-{
- /* Compute the distance to and the position of the closest neighbors to p.
- *
- * The neighbors are randomly placed, 1 each in a 3x3x3 grid (Worley pattern).
- * The distances and points are returned in ascending order, i.e. da[0] and pa[0] will
- * contain the distance to the closest point and its coordinates respectively.
- */
-
- da[0] = 1e10f;
- da[1] = 1e10f;
- da[2] = 1e10f;
- da[3] = 1e10f;
-
- pa[0] = make_float3(0.0f, 0.0f, 0.0f);
- pa[1] = make_float3(0.0f, 0.0f, 0.0f);
- pa[2] = make_float3(0.0f, 0.0f, 0.0f);
- pa[3] = make_float3(0.0f, 0.0f, 0.0f);
-
- int3 xyzi = quick_floor_to_int3(p);
-
- for (int xx = -1; xx <= 1; xx++) {
- for (int yy = -1; yy <= 1; yy++) {
- for (int zz = -1; zz <= 1; zz++) {
- int3 ip = xyzi + make_int3(xx, yy, zz);
- float3 fp = make_float3(ip.x, ip.y, ip.z);
- float3 vp = fp + cellnoise3(fp);
-
- float d;
- switch (distance) {
- case NODE_VORONOI_DISTANCE:
- d = len_squared(p - vp);
- break;
- case NODE_VORONOI_MANHATTAN:
- d = reduce_add(fabs(vp - p));
- break;
- case NODE_VORONOI_CHEBYCHEV:
- d = max3(fabs(vp - p));
- break;
- case NODE_VORONOI_MINKOWSKI: {
- float3 n = fabs(vp - p);
- if (e == 0.5f) {
- d = sqr(reduce_add(sqrt(n)));
- }
- else {
- d = powf(reduce_add(pow3(n, e)), 1.0f / e);
- }
- break;
- }
+/*
+ * Smooth Voronoi:
+ *
+ * - https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi
+ *
+ * Distance To Edge:
+ *
+ * - https://www.shadertoy.com/view/llG3zy
+ *
+ */
+
+/* **** 1D Voronoi **** */
+
+ccl_device float voronoi_distance_1d(float a,
+ float b,
+ NodeVoronoiDistanceMetric metric,
+ float exponent)
+{
+ return fabsf(b - a);
+}
+
+ccl_device void voronoi_f1_1d(float w,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float *outW)
+{
+ float cellPosition = floorf(w);
+ float localPosition = w - cellPosition;
+
+ float minDistance = 8.0f;
+ float targetOffset = 0.0f;
+ float targetPosition = 0.0f;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = i;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_1d(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ *outDistance = minDistance;
+ *outColor = hash_float_to_float3(cellPosition + targetOffset);
+ *outW = targetPosition + cellPosition;
+}
+
+ccl_device void voronoi_smooth_f1_1d(float w,
+ float smoothness,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float *outW)
+{
+ float cellPosition = floorf(w);
+ float localPosition = w - cellPosition;
+
+ float smoothDistance = 8.0f;
+ float smoothPosition = 0.0f;
+ float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
+ for (int i = -2; i <= 2; i++) {
+ float cellOffset = i;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_1d(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(
+ 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0f - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0f + 3.0f * smoothness;
+ float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ *outDistance = smoothDistance;
+ *outColor = smoothColor;
+ *outW = cellPosition + smoothPosition;
+}
+
+ccl_device void voronoi_f2_1d(float w,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float *outW)
+{
+ float cellPosition = floorf(w);
+ float localPosition = w - cellPosition;
+
+ float distanceF1 = 8.0f;
+ float distanceF2 = 8.0f;
+ float offsetF1 = 0.0f;
+ float positionF1 = 0.0f;
+ float offsetF2 = 0.0f;
+ float positionF2 = 0.0f;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = i;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_1d(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ *outDistance = distanceF2;
+ *outColor = hash_float_to_float3(cellPosition + offsetF2);
+ *outW = positionF2 + cellPosition;
+}
+
+ccl_device void voronoi_distance_to_edge_1d(float w, float randomness, float *outDistance)
+{
+ float cellPosition = floorf(w);
+ float localPosition = w - cellPosition;
+
+ float minDistance = 8.0f;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = i;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = fabsf(pointPosition - localPosition);
+ minDistance = min(distanceToPoint, minDistance);
+ }
+ *outDistance = minDistance;
+}
+
+ccl_device void voronoi_n_sphere_radius_1d(float w, float randomness, float *outRadius)
+{
+ float cellPosition = floorf(w);
+ float localPosition = w - cellPosition;
+
+ float closestPoint = 0.0f;
+ float closestPointOffset = 0.0f;
+ float minDistance = 8.0f;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = i;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = fabsf(pointPosition - localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+
+ minDistance = 8.0f;
+ float closestPointToClosestPoint = 0.0f;
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0) {
+ continue;
+ }
+ float cellOffset = i + closestPointOffset;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = fabsf(closestPoint - pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ *outRadius = fabsf(closestPointToClosestPoint - closestPoint) / 2.0f;
+}
+
+/* **** 2D Voronoi **** */
+
+ccl_device float voronoi_distance_2d(float2 a,
+ float2 b,
+ NodeVoronoiDistanceMetric metric,
+ float exponent)
+{
+ if (metric == NODE_VORONOI_EUCLIDEAN) {
+ return distance(a, b);
+ }
+ else if (metric == NODE_VORONOI_MANHATTAN) {
+ return fabsf(a.x - b.x) + fabsf(a.y - b.y);
+ }
+ else if (metric == NODE_VORONOI_CHEBYCHEV) {
+ return max(fabsf(a.x - b.x), fabsf(a.y - b.y));
+ }
+ else if (metric == NODE_VORONOI_MINKOWSKI) {
+ return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent),
+ 1.0f / exponent);
+ }
+ else {
+ return 0.0f;
+ }
+}
+
+ccl_device void voronoi_f1_2d(float2 coord,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float2 *outPosition)
+{
+ float2 cellPosition = floor(coord);
+ float2 localPosition = coord - cellPosition;
+
+ float minDistance = 8.0f;
+ float2 targetOffset = make_float2(0.0f, 0.0f);
+ float2 targetPosition = make_float2(0.0f, 0.0f);
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 pointPosition = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_2d(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ *outDistance = minDistance;
+ *outColor = hash_float2_to_float3(cellPosition + targetOffset);
+ *outPosition = targetPosition + cellPosition;
+}
+
+ccl_device void voronoi_smooth_f1_2d(float2 coord,
+ float smoothness,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float2 *outPosition)
+{
+ float2 cellPosition = floor(coord);
+ float2 localPosition = coord - cellPosition;
+
+ float smoothDistance = 8.0f;
+ float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
+ float2 smoothPosition = make_float2(0.0f, 0.0f);
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 pointPosition = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_2d(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(
+ 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0f - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0f + 3.0f * smoothness;
+ float3 cellColor = hash_float2_to_float3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ *outDistance = smoothDistance;
+ *outColor = smoothColor;
+ *outPosition = cellPosition + smoothPosition;
+}
+
+ccl_device void voronoi_f2_2d(float2 coord,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float2 *outPosition)
+{
+ float2 cellPosition = floor(coord);
+ float2 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0f;
+ float distanceF2 = 8.0f;
+ float2 offsetF1 = make_float2(0.0f, 0.0f);
+ float2 positionF1 = make_float2(0.0f, 0.0f);
+ float2 offsetF2 = make_float2(0.0f, 0.0f);
+ float2 positionF2 = make_float2(0.0f, 0.0f);
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 pointPosition = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_2d(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ *outDistance = distanceF2;
+ *outColor = hash_float2_to_float3(cellPosition + offsetF2);
+ *outPosition = positionF2 + cellPosition;
+}
+
+ccl_device void voronoi_distance_to_edge_2d(float2 coord, float randomness, float *outDistance)
+{
+ float2 cellPosition = floor(coord);
+ float2 localPosition = coord - cellPosition;
+
+ float2 vectorToClosest = make_float2(0.0f, 0.0f);
+ float minDistance = 8.0f;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 vectorToPoint = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 vectorToPoint = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float2 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0f,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ *outDistance = minDistance;
+}
+
+ccl_device void voronoi_n_sphere_radius_2d(float2 coord, float randomness, float *outRadius)
+{
+ float2 cellPosition = floor(coord);
+ float2 localPosition = coord - cellPosition;
+
+ float2 closestPoint = make_float2(0.0f, 0.0f);
+ float2 closestPointOffset = make_float2(0.0f, 0.0f);
+ float minDistance = 8.0f;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 pointPosition = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ float2 closestPointToClosestPoint = make_float2(0.0f, 0.0f);
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0) {
+ continue;
+ }
+ float2 cellOffset = make_float2(i, j) + closestPointOffset;
+ float2 pointPosition = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ *outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0f;
+}
+
+/* **** 3D Voronoi **** */
+
+ccl_device float voronoi_distance_3d(float3 a,
+ float3 b,
+ NodeVoronoiDistanceMetric metric,
+ float exponent)
+{
+ if (metric == NODE_VORONOI_EUCLIDEAN) {
+ return distance(a, b);
+ }
+ else if (metric == NODE_VORONOI_MANHATTAN) {
+ return fabsf(a.x - b.x) + fabsf(a.y - b.y) + fabsf(a.z - b.z);
+ }
+ else if (metric == NODE_VORONOI_CHEBYCHEV) {
+ return max(fabsf(a.x - b.x), max(fabsf(a.y - b.y), fabsf(a.z - b.z)));
+ }
+ else if (metric == NODE_VORONOI_MINKOWSKI) {
+ return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent) +
+ powf(fabsf(a.z - b.z), exponent),
+ 1.0f / exponent);
+ }
+ else {
+ return 0.0f;
+ }
+}
+
+ccl_device void voronoi_f1_3d(float3 coord,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float3 *outPosition)
+{
+ float3 cellPosition = floor(coord);
+ float3 localPosition = coord - cellPosition;
+
+ float minDistance = 8.0f;
+ float3 targetOffset = make_float3(0.0f, 0.0f, 0.0f);
+ float3 targetPosition = make_float3(0.0f, 0.0f, 0.0f);
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 pointPosition = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_3d(
+ pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
}
+ }
+ }
+ }
+ *outDistance = minDistance;
+ *outColor = hash_float3_to_float3(cellPosition + targetOffset);
+ *outPosition = targetPosition + cellPosition;
+}
+
+ccl_device void voronoi_smooth_f1_3d(float3 coord,
+ float smoothness,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float3 *outPosition)
+{
+ float3 cellPosition = floor(coord);
+ float3 localPosition = coord - cellPosition;
+
+ float smoothDistance = 8.0f;
+ float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
+ float3 smoothPosition = make_float3(0.0f, 0.0f, 0.0f);
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 pointPosition = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_3d(
+ pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(
+ 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0f - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0f + 3.0f * smoothness;
+ float3 cellColor = hash_float3_to_float3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ }
+ *outDistance = smoothDistance;
+ *outColor = smoothColor;
+ *outPosition = cellPosition + smoothPosition;
+}
- /* To keep the shortest four distances and associated points we have to keep them in sorted
- * order. */
- if (d < da[0]) {
- da[3] = da[2];
- da[2] = da[1];
- da[1] = da[0];
- da[0] = d;
-
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = pa[0];
- pa[0] = vp;
+ccl_device void voronoi_f2_3d(float3 coord,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float3 *outPosition)
+{
+ float3 cellPosition = floor(coord);
+ float3 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0f;
+ float distanceF2 = 8.0f;
+ float3 offsetF1 = make_float3(0.0f, 0.0f, 0.0f);
+ float3 positionF1 = make_float3(0.0f, 0.0f, 0.0f);
+ float3 offsetF2 = make_float3(0.0f, 0.0f, 0.0f);
+ float3 positionF2 = make_float3(0.0f, 0.0f, 0.0f);
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 pointPosition = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_3d(
+ pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
}
- else if (d < da[1]) {
- da[3] = da[2];
- da[2] = da[1];
- da[1] = d;
-
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = vp;
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
}
- else if (d < da[2]) {
- da[3] = da[2];
- da[2] = d;
+ }
+ }
+ }
+ *outDistance = distanceF2;
+ *outColor = hash_float3_to_float3(cellPosition + offsetF2);
+ *outPosition = positionF2 + cellPosition;
+}
- pa[3] = pa[2];
- pa[2] = vp;
+ccl_device void voronoi_distance_to_edge_3d(float3 coord, float randomness, float *outDistance)
+{
+ float3 cellPosition = floor(coord);
+ float3 localPosition = coord - cellPosition;
+
+ float3 vectorToClosest = make_float3(0.0f, 0.0f, 0.0f);
+ float minDistance = 8.0f;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 vectorToPoint = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
}
- else if (d < da[3]) {
- da[3] = d;
- pa[3] = vp;
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 vectorToPoint = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float3 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0f,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
}
}
}
}
+ *outDistance = minDistance;
}
-ccl_device void svm_node_tex_voronoi(
- KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
+ccl_device void voronoi_n_sphere_radius_3d(float3 coord, float randomness, float *outRadius)
{
- uint4 node2 = read_node(kg, offset);
+ float3 cellPosition = floor(coord);
+ float3 localPosition = coord - cellPosition;
- uint co_offset, coloring, distance, feature;
- uint scale_offset, e_offset, fac_offset, color_offset;
+ float3 closestPoint = make_float3(0.0f, 0.0f, 0.0f);
+ float3 closestPointOffset = make_float3(0.0f, 0.0f, 0.0f);
+ float minDistance = 8.0f;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 pointPosition = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+ }
- svm_unpack_node_uchar4(node.y, &co_offset, &coloring, &distance, &feature);
- svm_unpack_node_uchar4(node.z, &scale_offset, &e_offset, &fac_offset, &color_offset);
+ minDistance = 8.0f;
+ float3 closestPointToClosestPoint = make_float3(0.0f, 0.0f, 0.0f);
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0 && k == 0) {
+ continue;
+ }
+ float3 cellOffset = make_float3(i, j, k) + closestPointOffset;
+ float3 pointPosition = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ }
+ *outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0f;
+}
+
+/* **** 4D Voronoi **** */
- float3 co = stack_load_float3(stack, co_offset);
- float scale = stack_load_float_default(stack, scale_offset, node2.x);
- float exponent = stack_load_float_default(stack, e_offset, node2.y);
+ccl_device float voronoi_distance_4d(float4 a,
+ float4 b,
+ NodeVoronoiDistanceMetric metric,
+ float exponent)
+{
+ if (metric == NODE_VORONOI_EUCLIDEAN) {
+ return distance(a, b);
+ }
+ else if (metric == NODE_VORONOI_MANHATTAN) {
+ return fabsf(a.x - b.x) + fabsf(a.y - b.y) + fabsf(a.z - b.z) + fabsf(a.w - b.w);
+ }
+ else if (metric == NODE_VORONOI_CHEBYCHEV) {
+ return max(fabsf(a.x - b.x), max(fabsf(a.y - b.y), max(fabsf(a.z - b.z), fabsf(a.w - b.w))));
+ }
+ else if (metric == NODE_VORONOI_MINKOWSKI) {
+ return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent) +
+ powf(fabsf(a.z - b.z), exponent) + powf(fabsf(a.w - b.w), exponent),
+ 1.0f / exponent);
+ }
+ else {
+ return 0.0f;
+ }
+}
- float dist[4];
- float3 neighbor[4];
- voronoi_neighbors(co * scale, (NodeVoronoiDistanceMetric)distance, exponent, dist, neighbor);
+ccl_device void voronoi_f1_4d(float4 coord,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float4 *outPosition)
+{
+ float4 cellPosition = floor(coord);
+ float4 localPosition = coord - cellPosition;
- float3 color;
- float fac;
- if (coloring == NODE_VORONOI_INTENSITY) {
- switch (feature) {
- case NODE_VORONOI_F1:
- fac = dist[0];
- break;
- case NODE_VORONOI_F2:
- fac = dist[1];
- break;
- case NODE_VORONOI_F3:
- fac = dist[2];
- break;
- case NODE_VORONOI_F4:
- fac = dist[3];
- break;
- case NODE_VORONOI_F2F1:
- fac = dist[1] - dist[0];
- break;
+ float minDistance = 8.0f;
+ float4 targetOffset = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 targetPosition = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 pointPosition = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_4d(
+ pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
}
+ }
+ *outDistance = minDistance;
+ *outColor = hash_float4_to_float3(cellPosition + targetOffset);
+ *outPosition = targetPosition + cellPosition;
+}
+
+ccl_device void voronoi_smooth_f1_4d(float4 coord,
+ float smoothness,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float4 *outPosition)
+{
+ float4 cellPosition = floor(coord);
+ float4 localPosition = coord - cellPosition;
- color = make_float3(fac, fac, fac);
+ float smoothDistance = 8.0f;
+ float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
+ float4 smoothPosition = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ for (int u = -2; u <= 2; u++) {
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 pointPosition = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_4d(
+ pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(
+ 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0f - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0f + 3.0f * smoothness;
+ float3 cellColor = hash_float4_to_float3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ }
}
- else {
- /* NODE_VORONOI_CELLS */
- switch (feature) {
- case NODE_VORONOI_F1:
- color = neighbor[0];
- break;
- case NODE_VORONOI_F2:
- color = neighbor[1];
- break;
- case NODE_VORONOI_F3:
- color = neighbor[2];
- break;
- case NODE_VORONOI_F4:
- color = neighbor[3];
- break;
- /* Usefulness of this vector is questionable. Note F2 >= F1 but the
- * individual vector components might not be. */
- case NODE_VORONOI_F2F1:
- color = fabs(neighbor[1] - neighbor[0]);
- break;
- }
-
- color = cellnoise3(color);
- fac = average(color);
- }
-
- if (stack_valid(fac_offset))
- stack_store_float(stack, fac_offset, fac);
- if (stack_valid(color_offset))
- stack_store_float3(stack, color_offset, color);
+ *outDistance = smoothDistance;
+ *outColor = smoothColor;
+ *outPosition = cellPosition + smoothPosition;
+}
+
+ccl_device void voronoi_f2_4d(float4 coord,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float4 *outPosition)
+{
+ float4 cellPosition = floor(coord);
+ float4 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0f;
+ float distanceF2 = 8.0f;
+ float4 offsetF1 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 positionF1 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 offsetF2 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 positionF2 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 pointPosition = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_4d(
+ pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ *outDistance = distanceF2;
+ *outColor = hash_float4_to_float3(cellPosition + offsetF2);
+ *outPosition = positionF2 + cellPosition;
+}
+
+ccl_device void voronoi_distance_to_edge_4d(float4 coord, float randomness, float *outDistance)
+{
+ float4 cellPosition = floor(coord);
+ float4 localPosition = coord - cellPosition;
+
+ float4 vectorToClosest = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float minDistance = 8.0f;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 vectorToPoint = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 vectorToPoint = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float4 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0f,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ }
+ }
+ *outDistance = minDistance;
+}
+
+ccl_device void voronoi_n_sphere_radius_4d(float4 coord, float randomness, float *outRadius)
+{
+ float4 cellPosition = floor(coord);
+ float4 localPosition = coord - cellPosition;
+
+ float4 closestPoint = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 closestPointOffset = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float minDistance = 8.0f;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 pointPosition = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ float4 closestPointToClosestPoint = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0 && k == 0 && u == 0) {
+ continue;
+ }
+ float4 cellOffset = make_float4(i, j, k, u) + closestPointOffset;
+ float4 pointPosition = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ *outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0f;
+}
+
+ccl_device void svm_node_tex_voronoi(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint dimensions,
+ uint feature,
+ uint metric,
+ int *offset)
+{
+ uint4 stack_offsets = read_node(kg, offset);
+ uint4 defaults = read_node(kg, offset);
+
+ uint coord_stack_offset, w_stack_offset, scale_stack_offset, smoothness_stack_offset;
+ uint exponent_stack_offset, randomness_stack_offset, distance_out_stack_offset,
+ color_out_stack_offset;
+ uint position_out_stack_offset, w_out_stack_offset, radius_out_stack_offset;
+
+ svm_unpack_node_uchar4(stack_offsets.x,
+ &coord_stack_offset,
+ &w_stack_offset,
+ &scale_stack_offset,
+ &smoothness_stack_offset);
+ svm_unpack_node_uchar4(stack_offsets.y,
+ &exponent_stack_offset,
+ &randomness_stack_offset,
+ &distance_out_stack_offset,
+ &color_out_stack_offset);
+ svm_unpack_node_uchar3(
+ stack_offsets.z, &position_out_stack_offset, &w_out_stack_offset, &radius_out_stack_offset);
+
+ float3 coord = stack_load_float3(stack, coord_stack_offset);
+ float w = stack_load_float_default(stack, w_stack_offset, stack_offsets.w);
+ float scale = stack_load_float_default(stack, scale_stack_offset, defaults.x);
+ float smoothness = stack_load_float_default(stack, smoothness_stack_offset, defaults.y);
+ float exponent = stack_load_float_default(stack, exponent_stack_offset, defaults.z);
+ float randomness = stack_load_float_default(stack, randomness_stack_offset, defaults.w);
+
+ NodeVoronoiFeature voronoi_feature = (NodeVoronoiFeature)feature;
+ NodeVoronoiDistanceMetric voronoi_metric = (NodeVoronoiDistanceMetric)metric;
+
+ float distance_out = 0.0f, w_out = 0.0f, radius_out = 0.0f;
+ float3 color_out = make_float3(0.0f, 0.0f, 0.0f);
+ float3 position_out = make_float3(0.0f, 0.0f, 0.0f);
+
+ randomness = clamp(randomness, 0.0f, 1.0f);
+ smoothness = clamp(smoothness / 2.0f, 0.0f, 0.5f);
+
+ w *= scale;
+ coord *= scale;
+
+ switch (dimensions) {
+ case 1: {
+ switch (voronoi_feature) {
+ case NODE_VORONOI_F1:
+ voronoi_f1_1d(
+ w, exponent, randomness, voronoi_metric, &distance_out, &color_out, &w_out);
+ break;
+ case NODE_VORONOI_SMOOTH_F1:
+ voronoi_smooth_f1_1d(w,
+ smoothness,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &w_out);
+ break;
+ case NODE_VORONOI_F2:
+ voronoi_f2_1d(
+ w, exponent, randomness, voronoi_metric, &distance_out, &color_out, &w_out);
+ break;
+ case NODE_VORONOI_DISTANCE_TO_EDGE:
+ voronoi_distance_to_edge_1d(w, randomness, &distance_out);
+ break;
+ case NODE_VORONOI_N_SPHERE_RADIUS:
+ voronoi_n_sphere_radius_1d(w, randomness, &radius_out);
+ break;
+ default:
+ kernel_assert(0);
+ }
+ w_out = safe_divide(w_out, scale);
+ break;
+ }
+ case 2: {
+ float2 coord_2d = make_float2(coord.x, coord.y);
+ float2 position_out_2d;
+ switch (voronoi_feature) {
+ case NODE_VORONOI_F1:
+ voronoi_f1_2d(coord_2d,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_2d);
+ break;
+ case NODE_VORONOI_SMOOTH_F1:
+ voronoi_smooth_f1_2d(coord_2d,
+ smoothness,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_2d);
+ break;
+ case NODE_VORONOI_F2:
+ voronoi_f2_2d(coord_2d,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_2d);
+ break;
+ case NODE_VORONOI_DISTANCE_TO_EDGE:
+ voronoi_distance_to_edge_2d(coord_2d, randomness, &distance_out);
+ break;
+ case NODE_VORONOI_N_SPHERE_RADIUS:
+ voronoi_n_sphere_radius_2d(coord_2d, randomness, &radius_out);
+ break;
+ default:
+ kernel_assert(0);
+ }
+ position_out_2d = safe_divide_float2_float(position_out_2d, scale);
+ position_out = make_float3(position_out_2d.x, position_out_2d.y, 0.0f);
+ break;
+ }
+ case 3: {
+ switch (voronoi_feature) {
+ case NODE_VORONOI_F1:
+ voronoi_f1_3d(coord,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out);
+ break;
+ case NODE_VORONOI_SMOOTH_F1:
+ voronoi_smooth_f1_3d(coord,
+ smoothness,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out);
+ break;
+ case NODE_VORONOI_F2:
+ voronoi_f2_3d(coord,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out);
+ break;
+ case NODE_VORONOI_DISTANCE_TO_EDGE:
+ voronoi_distance_to_edge_3d(coord, randomness, &distance_out);
+ break;
+ case NODE_VORONOI_N_SPHERE_RADIUS:
+ voronoi_n_sphere_radius_3d(coord, randomness, &radius_out);
+ break;
+ default:
+ kernel_assert(0);
+ }
+ position_out = safe_divide_float3_float(position_out, scale);
+ break;
+ }
+ case 4: {
+ float4 coord_4d = make_float4(coord.x, coord.y, coord.z, w);
+ float4 position_out_4d;
+ switch (voronoi_feature) {
+ case NODE_VORONOI_F1:
+ voronoi_f1_4d(coord_4d,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_4d);
+ break;
+ case NODE_VORONOI_SMOOTH_F1:
+ voronoi_smooth_f1_4d(coord_4d,
+ smoothness,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_4d);
+ break;
+ case NODE_VORONOI_F2:
+ voronoi_f2_4d(coord_4d,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_4d);
+ break;
+ case NODE_VORONOI_DISTANCE_TO_EDGE:
+ voronoi_distance_to_edge_4d(coord_4d, randomness, &distance_out);
+ break;
+ case NODE_VORONOI_N_SPHERE_RADIUS:
+ voronoi_n_sphere_radius_4d(coord_4d, randomness, &radius_out);
+ break;
+ default:
+ kernel_assert(0);
+ }
+ position_out_4d = safe_divide_float4_float(position_out_4d, scale);
+ position_out = make_float3(position_out_4d.x, position_out_4d.y, position_out_4d.z);
+ w_out = position_out_4d.w;
+ break;
+ }
+ default:
+ kernel_assert(0);
+ }
+
+ if (stack_valid(distance_out_stack_offset))
+ stack_store_float(stack, distance_out_stack_offset, distance_out);
+ if (stack_valid(color_out_stack_offset))
+ stack_store_float3(stack, color_out_stack_offset, color_out);
+ if (stack_valid(position_out_stack_offset))
+ stack_store_float3(stack, position_out_stack_offset, position_out);
+ if (stack_valid(w_out_stack_offset))
+ stack_store_float(stack, w_out_stack_offset, w_out);
+ if (stack_valid(radius_out_stack_offset))
+ stack_store_float(stack, radius_out_stack_offset, radius_out);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_wave.h b/intern/cycles/kernel/svm/svm_wave.h
index baaa89ab0cb..402c1c87414 100644
--- a/intern/cycles/kernel/svm/svm_wave.h
+++ b/intern/cycles/kernel/svm/svm_wave.h
@@ -33,7 +33,7 @@ ccl_device_noinline_cpu float svm_wave(NodeWaveType type,
n = len(p) * 20.0f;
if (distortion != 0.0f)
- n += distortion * noise_turbulence(p * dscale, detail, 0);
+ n += distortion * fractal_noise_3d(p * dscale, detail);
if (profile == NODE_WAVE_PROFILE_SIN) {
return 0.5f + 0.5f * sinf(n);
diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp
index f1341d50b9d..0fa1142f354 100644
--- a/intern/cycles/render/attribute.cpp
+++ b/intern/cycles/render/attribute.cpp
@@ -48,7 +48,8 @@ void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_)
/* string and matrix not supported! */
assert(type == TypeDesc::TypeFloat || type == TypeDesc::TypeColor ||
type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
- type == TypeDesc::TypeNormal || type == TypeDesc::TypeMatrix || type == TypeFloat2);
+ type == TypeDesc::TypeNormal || type == TypeDesc::TypeMatrix || type == TypeFloat2 ||
+ type == TypeRGBA);
}
void Attribute::resize(Mesh *mesh, AttributePrimitive prim, bool reserve_only)
diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp
index ad3827df7e3..49e15d9eaf1 100644
--- a/intern/cycles/render/buffers.cpp
+++ b/intern/cycles/render/buffers.cpp
@@ -43,8 +43,6 @@ BufferParams::BufferParams()
denoising_data_pass = false;
denoising_clean_pass = false;
denoising_prefiltered_pass = false;
-
- Pass::add(PASS_COMBINED, passes);
}
void BufferParams::get_offset_stride(int &offset, int &stride)
diff --git a/intern/cycles/render/buffers.h b/intern/cycles/render/buffers.h
index 1c49038cd4b..74bb656c5a4 100644
--- a/intern/cycles/render/buffers.h
+++ b/intern/cycles/render/buffers.h
@@ -64,7 +64,6 @@ class BufferParams {
void get_offset_stride(int &offset, int &stride);
bool modified(const BufferParams &params);
- void add_pass(PassType type);
int get_passes_size();
int get_denoising_offset();
int get_denoising_prefiltered_offset();
diff --git a/intern/cycles/render/constant_fold.cpp b/intern/cycles/render/constant_fold.cpp
index 851d4b71df8..f3809ee8d80 100644
--- a/intern/cycles/render/constant_fold.cpp
+++ b/intern/cycles/render/constant_fold.cpp
@@ -429,4 +429,21 @@ void ConstantFolder::fold_vector_math(NodeVectorMathType type) const
}
}
+void ConstantFolder::fold_mapping(NodeMappingType type) const
+{
+ ShaderInput *vector_in = node->input("Vector");
+ ShaderInput *location_in = node->input("Location");
+ ShaderInput *rotation_in = node->input("Rotation");
+ ShaderInput *scale_in = node->input("Scale");
+
+ if (is_zero(scale_in)) {
+ make_zero();
+ }
+ else if ((is_zero(location_in) || type == NODE_MAPPING_TYPE_VECTOR ||
+ type == NODE_MAPPING_TYPE_NORMAL) &&
+ is_zero(rotation_in) && is_one(scale_in)) {
+ try_bypass_or_make_constant(vector_in);
+ }
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/constant_fold.h b/intern/cycles/render/constant_fold.h
index 881636a9fe1..7f622488a88 100644
--- a/intern/cycles/render/constant_fold.h
+++ b/intern/cycles/render/constant_fold.h
@@ -66,6 +66,7 @@ class ConstantFolder {
void fold_mix(NodeMix type, bool clamp) const;
void fold_math(NodeMathType type) const;
void fold_vector_math(NodeVectorMathType type) const;
+ void fold_mapping(NodeMappingType type) const;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/denoising.cpp b/intern/cycles/render/denoising.cpp
index 39bd8ce00c2..4d819d1119e 100644
--- a/intern/cycles/render/denoising.cpp
+++ b/intern/cycles/render/denoising.cpp
@@ -866,8 +866,10 @@ Denoiser::Denoiser(DeviceInfo &device_info)
TaskScheduler::init();
/* Initialize device. */
- DeviceRequestedFeatures req;
device = Device::create(device_info, stats, profiler, true);
+
+ DeviceRequestedFeatures req;
+ req.use_denoising = true;
device->load_kernels(req);
}
diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp
index d6c44b66117..7f5bec2a66e 100644
--- a/intern/cycles/render/film.cpp
+++ b/intern/cycles/render/film.cpp
@@ -267,7 +267,7 @@ NODE_DEFINE(Film)
NodeType *type = NodeType::add("film", create);
SOCKET_FLOAT(exposure, "Exposure", 0.8f);
- SOCKET_FLOAT(pass_alpha_threshold, "Pass Alpha Threshold", 0.5f);
+ SOCKET_FLOAT(pass_alpha_threshold, "Pass Alpha Threshold", 0.0f);
static NodeEnum filter_enum;
filter_enum.insert("box", FILTER_BOX);
@@ -293,8 +293,6 @@ NODE_DEFINE(Film)
Film::Film() : Node(node_type)
{
- Pass::add(PASS_COMBINED, passes);
-
use_light_visibility = false;
filter_table_offset = TABLE_OFFSET_INVALID;
cryptomatte_passes = CRYPT_NONE;
@@ -318,6 +316,13 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
/* update __data */
kfilm->exposure = exposure;
kfilm->pass_flag = 0;
+
+ kfilm->display_pass_stride = -1;
+ kfilm->display_pass_components = 0;
+ kfilm->display_divide_pass_stride = -1;
+ kfilm->use_display_exposure = false;
+ kfilm->use_display_pass_alpha = (display_pass == PASS_COMBINED);
+
kfilm->light_pass_flag = 0;
kfilm->pass_stride = 0;
kfilm->use_light_pass = use_light_visibility || use_sample_clamp;
@@ -464,6 +469,16 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
break;
}
+ if (pass.type == display_pass) {
+ kfilm->display_pass_stride = kfilm->pass_stride;
+ kfilm->display_pass_components = pass.components;
+ kfilm->use_display_exposure = pass.exposure && (kfilm->exposure != 1.0f);
+ }
+ else if (pass.type == PASS_DIFFUSE_COLOR || pass.type == PASS_TRANSMISSION_COLOR ||
+ pass.type == PASS_GLOSSY_COLOR || pass.type == PASS_SUBSURFACE_COLOR) {
+ kfilm->display_divide_pass_stride = kfilm->pass_stride;
+ }
+
kfilm->pass_stride += pass.components;
}
@@ -485,7 +500,18 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
}
kfilm->pass_stride = align_up(kfilm->pass_stride, 4);
- kfilm->pass_alpha_threshold = pass_alpha_threshold;
+
+ /* When displaying the normal/uv pass in the viewport we need to disable
+ * transparency.
+ *
+ * We also don't need to perform light accumulations. Later we want to optimize this to suppress
+ * light calculations. */
+ if (display_pass == PASS_NORMAL || display_pass == PASS_UV) {
+ kfilm->use_light_pass = 0;
+ }
+ else {
+ kfilm->pass_alpha_threshold = pass_alpha_threshold;
+ }
/* update filter table */
vector<float> table = filter_table(filter_type, filter_width);
@@ -518,7 +544,7 @@ bool Film::modified(const Film &film)
return !Node::equals(film) || !Pass::equals(passes, film.passes);
}
-void Film::tag_passes_update(Scene *scene, const vector<Pass> &passes_)
+void Film::tag_passes_update(Scene *scene, const vector<Pass> &passes_, bool update_passes)
{
if (Pass::contains(passes, PASS_UV) != Pass::contains(passes_, PASS_UV)) {
scene->mesh_manager->tag_update(scene);
@@ -526,10 +552,16 @@ void Film::tag_passes_update(Scene *scene, const vector<Pass> &passes_)
foreach (Shader *shader, scene->shaders)
shader->need_update_mesh = true;
}
- else if (Pass::contains(passes, PASS_MOTION) != Pass::contains(passes_, PASS_MOTION))
+ else if (Pass::contains(passes, PASS_MOTION) != Pass::contains(passes_, PASS_MOTION)) {
scene->mesh_manager->tag_update(scene);
+ }
+ else if (Pass::contains(passes, PASS_AO) != Pass::contains(passes_, PASS_AO)) {
+ scene->integrator->tag_update(scene);
+ }
- passes = passes_;
+ if (update_passes) {
+ passes = passes_;
+ }
}
void Film::tag_update(Scene * /*scene*/)
diff --git a/intern/cycles/render/film.h b/intern/cycles/render/film.h
index 1cfa7c3b77d..2c4e07d60ae 100644
--- a/intern/cycles/render/film.h
+++ b/intern/cycles/render/film.h
@@ -64,6 +64,7 @@ class Film : public Node {
int denoising_flags;
float pass_alpha_threshold;
+ PassType display_pass;
int pass_stride;
int denoising_data_offset;
int denoising_clean_offset;
@@ -90,7 +91,7 @@ class Film : public Node {
void device_free(Device *device, DeviceScene *dscene, Scene *scene);
bool modified(const Film &film);
- void tag_passes_update(Scene *scene, const vector<Pass> &passes_);
+ void tag_passes_update(Scene *scene, const vector<Pass> &passes_, bool update_passes = true);
void tag_update(Scene *scene);
};
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index 6ac66661859..cffe2bfa70a 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -433,6 +433,8 @@ Mesh::Mesh() : Node(node_type)
attr_map_offset = 0;
+ prim_offset = 0;
+
num_subd_verts = 0;
attributes.triangle_mesh = this;
@@ -558,6 +560,9 @@ void Mesh::clear(bool preserve_voxel_data)
used_shaders.clear();
+ vert_to_stitching_key_map.clear();
+ vert_stitching_map.clear();
+
if (!preserve_voxel_data) {
geometry_flags = GEOMETRY_NONE;
}
@@ -1013,9 +1018,11 @@ void Mesh::compute_bvh(
compute_bounds();
- if (need_build_bvh()) {
+ const BVHLayout bvh_layout = BVHParams::best_bvh_layout(params->bvh_layout,
+ device->get_bvh_layout_mask());
+ if (need_build_bvh(bvh_layout)) {
string msg = "Updating Mesh BVH ";
- if (name == "")
+ if (name.empty())
msg += string_printf("%u/%u", (uint)(n + 1), (uint)total);
else
msg += string_printf("%s %u/%u", name.c_str(), (uint)(n + 1), (uint)total);
@@ -1023,12 +1030,17 @@ void Mesh::compute_bvh(
Object object;
object.mesh = this;
+ vector<Mesh *> meshes;
+ meshes.push_back(this);
vector<Object *> objects;
objects.push_back(&object);
if (bvh && !need_update_rebuild) {
progress->set_status(msg, "Refitting BVH");
+
+ bvh->meshes = meshes;
bvh->objects = objects;
+
bvh->refit(*progress);
}
else {
@@ -1036,8 +1048,7 @@ void Mesh::compute_bvh(
BVHParams bparams;
bparams.use_spatial_split = params->use_bvh_spatial_split;
- bparams.bvh_layout = BVHParams::best_bvh_layout(params->bvh_layout,
- device->get_bvh_layout_mask());
+ bparams.bvh_layout = bvh_layout;
bparams.use_unaligned_nodes = dscene->data.bvh.have_curves &&
params->use_bvh_unaligned_nodes;
bparams.num_motion_triangle_steps = params->num_bvh_time_steps;
@@ -1047,7 +1058,7 @@ void Mesh::compute_bvh(
bparams.curve_subdivisions = dscene->data.curve.subdivisions;
delete bvh;
- bvh = BVH::create(bparams, objects);
+ bvh = BVH::create(bparams, meshes, objects);
MEM_GUARDED_CALL(progress, bvh->build, *progress);
}
}
@@ -1128,9 +1139,9 @@ int Mesh::motion_step(float time) const
return -1;
}
-bool Mesh::need_build_bvh() const
+bool Mesh::need_build_bvh(BVHLayout layout) const
{
- return !transform_applied || has_surface_bssrdf;
+ return !transform_applied || has_surface_bssrdf || layout == BVH_LAYOUT_OPTIX;
}
bool Mesh::is_instanced() const
@@ -1212,6 +1223,8 @@ void MeshManager::update_osl_attributes(Device *device,
osl_attr.type = TypeDesc::TypeMatrix;
else if (req.triangle_type == TypeFloat2)
osl_attr.type = TypeFloat2;
+ else if (req.triangle_type == TypeRGBA)
+ osl_attr.type = TypeRGBA;
else
osl_attr.type = TypeDesc::TypeColor;
@@ -1235,6 +1248,8 @@ void MeshManager::update_osl_attributes(Device *device,
osl_attr.type = TypeDesc::TypeMatrix;
else if (req.curve_type == TypeFloat2)
osl_attr.type = TypeFloat2;
+ else if (req.curve_type == TypeRGBA)
+ osl_attr.type = TypeRGBA;
else
osl_attr.type = TypeDesc::TypeColor;
@@ -1258,6 +1273,8 @@ void MeshManager::update_osl_attributes(Device *device,
osl_attr.type = TypeDesc::TypeMatrix;
else if (req.subd_type == TypeFloat2)
osl_attr.type = TypeFloat2;
+ else if (req.subd_type == TypeRGBA)
+ osl_attr.type = TypeRGBA;
else
osl_attr.type = TypeDesc::TypeColor;
@@ -1330,6 +1347,8 @@ void MeshManager::update_svm_attributes(Device *,
attr_map[index].w = NODE_ATTR_MATRIX;
else if (req.triangle_type == TypeFloat2)
attr_map[index].w = NODE_ATTR_FLOAT2;
+ else if (req.triangle_type == TypeRGBA)
+ attr_map[index].w = NODE_ATTR_RGBA;
else
attr_map[index].w = NODE_ATTR_FLOAT3;
@@ -1368,6 +1387,8 @@ void MeshManager::update_svm_attributes(Device *,
attr_map[index].w = NODE_ATTR_MATRIX;
else if (req.subd_type == TypeFloat2)
attr_map[index].w = NODE_ATTR_FLOAT2;
+ else if (req.triangle_type == TypeRGBA)
+ attr_map[index].w = NODE_ATTR_RGBA;
else
attr_map[index].w = NODE_ATTR_FLOAT3;
@@ -1722,6 +1743,8 @@ void MeshManager::mesh_calc_offset(Scene *scene)
size_t face_size = 0;
size_t corner_size = 0;
+ size_t prim_size = 0;
+
foreach (Mesh *mesh, scene->meshes) {
mesh->vert_offset = vert_size;
mesh->tri_offset = tri_size;
@@ -1751,6 +1774,9 @@ void MeshManager::mesh_calc_offset(Scene *scene)
}
face_size += mesh->subd_faces.size();
corner_size += mesh->subd_face_corners.size();
+
+ mesh->prim_offset = prim_size;
+ prim_size += mesh->num_primitives();
}
}
@@ -1929,7 +1955,7 @@ void MeshManager::device_update_bvh(Device *device,
}
#endif
- BVH *bvh = BVH::create(bparams, scene->objects);
+ BVH *bvh = BVH::create(bparams, scene->meshes, scene->objects);
bvh->build(progress, &device->stats);
if (progress.get_cancel()) {
@@ -1994,14 +2020,7 @@ void MeshManager::device_update_bvh(Device *device,
dscene->data.bvh.bvh_layout = bparams.bvh_layout;
dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0);
-#ifdef WITH_EMBREE
- if (bparams.bvh_layout == BVH_LAYOUT_EMBREE) {
- dscene->data.bvh.scene = ((BVHEmbree *)bvh)->scene;
- }
- else {
- dscene->data.bvh.scene = NULL;
- }
-#endif
+ bvh->copy_to_device(progress, dscene);
delete bvh;
}
@@ -2213,6 +2232,8 @@ void MeshManager::device_update(Device *device,
/* Update displacement. */
bool displacement_done = false;
size_t num_bvh = 0;
+ BVHLayout bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout,
+ device->get_bvh_layout_mask());
foreach (Mesh *mesh, scene->meshes) {
if (mesh->need_update) {
@@ -2220,7 +2241,7 @@ void MeshManager::device_update(Device *device,
displacement_done = true;
}
- if (mesh->need_build_bvh()) {
+ if (mesh->need_build_bvh(bvh_layout)) {
num_bvh++;
}
}
@@ -2245,7 +2266,7 @@ void MeshManager::device_update(Device *device,
if (mesh->need_update) {
pool.push(function_bind(
&Mesh::compute_bvh, mesh, device, dscene, &scene->params, &progress, i, num_bvh));
- if (mesh->need_build_bvh()) {
+ if (mesh->need_build_bvh(bvh_layout)) {
i++;
}
}
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
index 5bb6ab328b7..4a24a9c2656 100644
--- a/intern/cycles/render/mesh.h
+++ b/intern/cycles/render/mesh.h
@@ -19,6 +19,7 @@
#include "graph/node.h"
+#include "bvh/bvh_params.h"
#include "render/attribute.h"
#include "render/shader.h"
@@ -94,7 +95,7 @@ class Mesh : public Node {
int first_key;
int num_keys;
- int num_segments()
+ int num_segments() const
{
return num_keys - 1;
}
@@ -167,6 +168,16 @@ class Mesh : public Node {
return curve_first_key.size();
}
+ size_t num_segments() const
+ {
+ return curve_keys.size() - curve_first_key.size();
+ }
+
+ size_t num_primitives() const
+ {
+ return num_triangles() + num_segments();
+ }
+
/* Mesh SubdFace */
struct SubdFace {
int start_corner;
@@ -268,8 +279,18 @@ class Mesh : public Node {
size_t attr_map_offset;
+ size_t prim_offset;
+
size_t num_subd_verts;
+ private:
+ unordered_map<int, int> vert_to_stitching_key_map; /* real vert index -> stitching index */
+ unordered_multimap<int, int>
+ vert_stitching_map; /* stitching index -> multiple real vert indices */
+ friend class DiagSplit;
+ friend class MeshManager;
+
+ public:
/* Functions */
Mesh();
~Mesh();
@@ -332,8 +353,9 @@ class Mesh : public Node {
* same BVH tree.
* - Special ray intersection is needed, for example to limit subsurface rays
* to only the mesh itself.
+ * - The BVH layout requires the top level to only contain instances.
*/
- bool need_build_bvh() const;
+ bool need_build_bvh(BVHLayout layout) const;
/* Check if the mesh should be treated as instanced. */
bool is_instanced() const;
diff --git a/intern/cycles/render/mesh_displace.cpp b/intern/cycles/render/mesh_displace.cpp
index 5ae9348d83e..6a6c2fbb3eb 100644
--- a/intern/cycles/render/mesh_displace.cpp
+++ b/intern/cycles/render/mesh_displace.cpp
@@ -22,7 +22,9 @@
#include "render/shader.h"
#include "util/util_foreach.h"
+#include "util/util_map.h"
#include "util/util_progress.h"
+#include "util/util_set.h"
CCL_NAMESPACE_BEGIN
@@ -184,6 +186,38 @@ bool MeshManager::displace(
d_output.free();
+ /* stitch */
+ unordered_set<int> stitch_keys;
+ for (pair<int, int> i : mesh->vert_to_stitching_key_map) {
+ stitch_keys.insert(i.second); /* stitching index */
+ }
+
+ typedef unordered_multimap<int, int>::iterator map_it_t;
+
+ for (int key : stitch_keys) {
+ pair<map_it_t, map_it_t> verts = mesh->vert_stitching_map.equal_range(key);
+
+ float3 pos = make_float3(0.0f, 0.0f, 0.0f);
+ int num = 0;
+
+ for (map_it_t v = verts.first; v != verts.second; ++v) {
+ int vert = v->second;
+
+ pos += mesh->verts[vert];
+ num++;
+ }
+
+ if (num <= 1) {
+ continue;
+ }
+
+ pos *= 1.0f / num;
+
+ for (map_it_t v = verts.first; v != verts.second; ++v) {
+ mesh->verts[v->second] = pos;
+ }
+ }
+
/* for displacement method both, we only need to recompute the face
* normals, as bump mapping in the shader will already alter the
* vertex normal, so we start from the non-displaced vertex normals
@@ -238,7 +272,25 @@ bool MeshManager::displace(
for (size_t i = 0; i < num_triangles; i++) {
if (tri_has_true_disp[i]) {
for (size_t j = 0; j < 3; j++) {
- vN[mesh->get_triangle(i).v[j]] += fN[i];
+ int vert = mesh->get_triangle(i).v[j];
+ vN[vert] += fN[i];
+
+ /* add face normals to stitched vertices */
+ if (stitch_keys.size()) {
+ map_it_t key = mesh->vert_to_stitching_key_map.find(vert);
+
+ if (key != mesh->vert_to_stitching_key_map.end()) {
+ pair<map_it_t, map_it_t> verts = mesh->vert_stitching_map.equal_range(key->second);
+
+ for (map_it_t v = verts.first; v != verts.second; ++v) {
+ if (v->second == vert) {
+ continue;
+ }
+
+ vN[v->second] += fN[i];
+ }
+ }
+ }
}
}
}
@@ -289,8 +341,27 @@ bool MeshManager::displace(
for (size_t i = 0; i < num_triangles; i++) {
if (tri_has_true_disp[i]) {
for (size_t j = 0; j < 3; j++) {
+ int vert = mesh->get_triangle(i).v[j];
float3 fN = compute_face_normal(mesh->get_triangle(i), mP);
- mN[mesh->get_triangle(i).v[j]] += fN;
+ mN[vert] += fN;
+
+ /* add face normals to stitched vertices */
+ if (stitch_keys.size()) {
+ map_it_t key = mesh->vert_to_stitching_key_map.find(vert);
+
+ if (key != mesh->vert_to_stitching_key_map.end()) {
+ pair<map_it_t, map_it_t> verts = mesh->vert_stitching_map.equal_range(
+ key->second);
+
+ for (map_it_t v = verts.first; v != verts.second; ++v) {
+ if (v->second == vert) {
+ continue;
+ }
+
+ mN[v->second] += fN;
+ }
+ }
+ }
}
}
}
diff --git a/intern/cycles/render/mesh_subdivision.cpp b/intern/cycles/render/mesh_subdivision.cpp
index 46c8240fb71..a5a35fc049e 100644
--- a/intern/cycles/render/mesh_subdivision.cpp
+++ b/intern/cycles/render/mesh_subdivision.cpp
@@ -24,6 +24,7 @@
#include "util/util_foreach.h"
#include "util/util_algorithm.h"
+#include "util/util_hash.h"
CCL_NAMESPACE_BEGIN
@@ -318,6 +319,9 @@ class OsdData {
struct OsdPatch : Patch {
OsdData *osd_data;
+ OsdPatch()
+ {
+ }
OsdPatch(OsdData *data) : osd_data(data)
{
}
@@ -358,11 +362,6 @@ struct OsdPatch : Patch {
*N = (t != 0.0f) ? *N / t : make_float3(0.0f, 0.0f, 1.0f);
}
}
-
- BoundBox bound()
- {
- return BoundBox::empty;
- }
};
#endif
@@ -397,29 +396,62 @@ void Mesh::tessellate(DiagSplit *split)
Attribute *attr_vN = subd_attributes.find(ATTR_STD_VERTEX_NORMAL);
float3 *vN = attr_vN->data_float3();
+ /* count patches */
+ int num_patches = 0;
for (int f = 0; f < num_faces; f++) {
SubdFace &face = subd_faces[f];
if (face.is_quad()) {
- /* quad */
- QuadDice::SubPatch subpatch;
+ num_patches++;
+ }
+ else {
+ num_patches += face.num_corners;
+ }
+ }
- LinearQuadPatch quad_patch;
+ /* build patches from faces */
#ifdef WITH_OPENSUBDIV
- OsdPatch osd_patch(&osd_data);
+ if (subdivision_type == SUBDIVISION_CATMULL_CLARK) {
+ vector<OsdPatch> osd_patches(num_patches, &osd_data);
+ OsdPatch *patch = osd_patches.data();
- if (subdivision_type == SUBDIVISION_CATMULL_CLARK) {
- osd_patch.patch_index = face.ptex_offset;
+ for (int f = 0; f < num_faces; f++) {
+ SubdFace &face = subd_faces[f];
- subpatch.patch = &osd_patch;
+ if (face.is_quad()) {
+ patch->patch_index = face.ptex_offset;
+ patch->from_ngon = false;
+ patch->shader = face.shader;
+ patch++;
+ }
+ else {
+ for (int corner = 0; corner < face.num_corners; corner++) {
+ patch->patch_index = face.ptex_offset + corner;
+ patch->from_ngon = true;
+ patch->shader = face.shader;
+ patch++;
+ }
}
- else
+ }
+
+ /* split patches */
+ split->split_patches(osd_patches.data(), sizeof(OsdPatch));
+ }
+ else
#endif
- {
- float3 *hull = quad_patch.hull;
- float3 *normals = quad_patch.normals;
+ {
+ vector<LinearQuadPatch> linear_patches(num_patches);
+ LinearQuadPatch *patch = linear_patches.data();
+
+ for (int f = 0; f < num_faces; f++) {
+ SubdFace &face = subd_faces[f];
- quad_patch.patch_index = face.ptex_offset;
+ if (face.is_quad()) {
+ float3 *hull = patch->hull;
+ float3 *normals = patch->normals;
+
+ patch->patch_index = face.ptex_offset;
+ patch->from_ngon = false;
for (int i = 0; i < 4; i++) {
hull[i] = verts[subd_face_corners[face.start_corner + i]];
@@ -440,55 +472,11 @@ void Mesh::tessellate(DiagSplit *split)
swap(hull[2], hull[3]);
swap(normals[2], normals[3]);
- subpatch.patch = &quad_patch;
+ patch->shader = face.shader;
+ patch++;
}
-
- subpatch.patch->shader = face.shader;
-
- /* Quad faces need to be split at least once to line up with split ngons, we do this
- * here in this manner because if we do it later edge factors may end up slightly off.
- */
- subpatch.P00 = make_float2(0.0f, 0.0f);
- subpatch.P10 = make_float2(0.5f, 0.0f);
- subpatch.P01 = make_float2(0.0f, 0.5f);
- subpatch.P11 = make_float2(0.5f, 0.5f);
- split->split_quad(subpatch.patch, &subpatch);
-
- subpatch.P00 = make_float2(0.5f, 0.0f);
- subpatch.P10 = make_float2(1.0f, 0.0f);
- subpatch.P01 = make_float2(0.5f, 0.5f);
- subpatch.P11 = make_float2(1.0f, 0.5f);
- split->split_quad(subpatch.patch, &subpatch);
-
- subpatch.P00 = make_float2(0.0f, 0.5f);
- subpatch.P10 = make_float2(0.5f, 0.5f);
- subpatch.P01 = make_float2(0.0f, 1.0f);
- subpatch.P11 = make_float2(0.5f, 1.0f);
- split->split_quad(subpatch.patch, &subpatch);
-
- subpatch.P00 = make_float2(0.5f, 0.5f);
- subpatch.P10 = make_float2(1.0f, 0.5f);
- subpatch.P01 = make_float2(0.5f, 1.0f);
- subpatch.P11 = make_float2(1.0f, 1.0f);
- split->split_quad(subpatch.patch, &subpatch);
- }
- else {
- /* ngon */
-#ifdef WITH_OPENSUBDIV
- if (subdivision_type == SUBDIVISION_CATMULL_CLARK) {
- OsdPatch patch(&osd_data);
-
- patch.shader = face.shader;
-
- for (int corner = 0; corner < face.num_corners; corner++) {
- patch.patch_index = face.ptex_offset + corner;
-
- split->split_quad(&patch);
- }
- }
- else
-#endif
- {
+ else {
+ /* ngon */
float3 center_vert = make_float3(0.0f, 0.0f, 0.0f);
float3 center_normal = make_float3(0.0f, 0.0f, 0.0f);
@@ -499,13 +487,13 @@ void Mesh::tessellate(DiagSplit *split)
}
for (int corner = 0; corner < face.num_corners; corner++) {
- LinearQuadPatch patch;
- float3 *hull = patch.hull;
- float3 *normals = patch.normals;
+ float3 *hull = patch->hull;
+ float3 *normals = patch->normals;
- patch.patch_index = face.ptex_offset + corner;
+ patch->patch_index = face.ptex_offset + corner;
+ patch->from_ngon = true;
- patch.shader = face.shader;
+ patch->shader = face.shader;
hull[0] =
verts[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]];
@@ -537,10 +525,13 @@ void Mesh::tessellate(DiagSplit *split)
}
}
- split->split_quad(&patch);
+ patch++;
}
}
}
+
+ /* split patches */
+ split->split_patches(linear_patches.data(), sizeof(LinearQuadPatch));
}
/* interpolate center points for attributes */
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 69c1c06f846..71f1863ea49 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -25,6 +25,7 @@
#include "kernel/svm/svm_color_util.h"
#include "kernel/svm/svm_ramp_util.h"
#include "kernel/svm/svm_math_util.h"
+#include "kernel/svm/svm_mapping_util.h"
#include "render/osl.h"
#include "render/constant_fold.h"
@@ -149,7 +150,7 @@ bool TextureMapping::skip()
void TextureMapping::compile(SVMCompiler &compiler, int offset_in, int offset_out)
{
- compiler.add_node(NODE_MAPPING, offset_in, offset_out);
+ compiler.add_node(NODE_TEXTURE_MAPPING, offset_in, offset_out);
Transform tfm = compute_transform();
compiler.add_node(tfm.x);
@@ -893,14 +894,22 @@ NODE_DEFINE(NoiseTextureNode)
TEXTURE_MAPPING_DEFINE(NoiseTextureNode);
+ static NodeEnum dimensions_enum;
+ dimensions_enum.insert("1D", 1);
+ dimensions_enum.insert("2D", 2);
+ dimensions_enum.insert("3D", 3);
+ dimensions_enum.insert("4D", 4);
+ SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3);
+
+ SOCKET_IN_POINT(
+ vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
+ SOCKET_IN_FLOAT(w, "W", 0.0f);
SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f);
- SOCKET_IN_POINT(
- vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
- SOCKET_OUT_COLOR(color, "Color");
SOCKET_OUT_FLOAT(fac, "Fac");
+ SOCKET_OUT_COLOR(color, "Color");
return type;
}
@@ -911,31 +920,40 @@ NoiseTextureNode::NoiseTextureNode() : TextureNode(node_type)
void NoiseTextureNode::compile(SVMCompiler &compiler)
{
- ShaderInput *distortion_in = input("Distortion");
- ShaderInput *detail_in = input("Detail");
- ShaderInput *scale_in = input("Scale");
ShaderInput *vector_in = input("Vector");
- ShaderOutput *color_out = output("Color");
+ ShaderInput *w_in = input("W");
+ ShaderInput *scale_in = input("Scale");
+ ShaderInput *detail_in = input("Detail");
+ ShaderInput *distortion_in = input("Distortion");
ShaderOutput *fac_out = output("Fac");
+ ShaderOutput *color_out = output("Color");
- int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
+ int vector_stack_offset = tex_mapping.compile_begin(compiler, vector_in);
+ int w_stack_offset = compiler.stack_assign_if_linked(w_in);
+ int scale_stack_offset = compiler.stack_assign_if_linked(scale_in);
+ int detail_stack_offset = compiler.stack_assign_if_linked(detail_in);
+ int distortion_stack_offset = compiler.stack_assign_if_linked(distortion_in);
+ int fac_stack_offset = compiler.stack_assign_if_linked(fac_out);
+ int color_stack_offset = compiler.stack_assign_if_linked(color_out);
- compiler.add_node(NODE_TEX_NOISE,
- compiler.encode_uchar4(vector_offset,
- compiler.stack_assign_if_linked(scale_in),
- compiler.stack_assign_if_linked(detail_in),
- compiler.stack_assign_if_linked(distortion_in)),
- compiler.encode_uchar4(compiler.stack_assign_if_linked(color_out),
- compiler.stack_assign_if_linked(fac_out)));
- compiler.add_node(__float_as_int(scale), __float_as_int(detail), __float_as_int(distortion));
+ compiler.add_node(
+ NODE_TEX_NOISE,
+ dimensions,
+ compiler.encode_uchar4(
+ vector_stack_offset, w_stack_offset, scale_stack_offset, detail_stack_offset),
+ compiler.encode_uchar4(distortion_stack_offset, fac_stack_offset, color_stack_offset));
+ compiler.add_node(__float_as_int(w),
+ __float_as_int(scale),
+ __float_as_int(detail),
+ __float_as_int(distortion));
- tex_mapping.compile_end(compiler, vector_in, vector_offset);
+ tex_mapping.compile_end(compiler, vector_in, vector_stack_offset);
}
void NoiseTextureNode::compile(OSLCompiler &compiler)
{
tex_mapping.compile(compiler);
-
+ compiler.parameter(this, "dimensions");
compiler.add(this, "node_noise_texture");
}
@@ -947,33 +965,41 @@ NODE_DEFINE(VoronoiTextureNode)
TEXTURE_MAPPING_DEFINE(VoronoiTextureNode);
- static NodeEnum coloring_enum;
- coloring_enum.insert("intensity", NODE_VORONOI_INTENSITY);
- coloring_enum.insert("cells", NODE_VORONOI_CELLS);
- SOCKET_ENUM(coloring, "Coloring", coloring_enum, NODE_VORONOI_INTENSITY);
+ static NodeEnum dimensions_enum;
+ dimensions_enum.insert("1D", 1);
+ dimensions_enum.insert("2D", 2);
+ dimensions_enum.insert("3D", 3);
+ dimensions_enum.insert("4D", 4);
+ SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3);
- static NodeEnum metric;
- metric.insert("distance", NODE_VORONOI_DISTANCE);
- metric.insert("manhattan", NODE_VORONOI_MANHATTAN);
- metric.insert("chebychev", NODE_VORONOI_CHEBYCHEV);
- metric.insert("minkowski", NODE_VORONOI_MINKOWSKI);
- SOCKET_ENUM(metric, "Distance Metric", metric, NODE_VORONOI_INTENSITY);
+ static NodeEnum metric_enum;
+ metric_enum.insert("euclidean", NODE_VORONOI_EUCLIDEAN);
+ metric_enum.insert("manhattan", NODE_VORONOI_MANHATTAN);
+ metric_enum.insert("chebychev", NODE_VORONOI_CHEBYCHEV);
+ metric_enum.insert("minkowski", NODE_VORONOI_MINKOWSKI);
+ SOCKET_ENUM(metric, "Distance Metric", metric_enum, NODE_VORONOI_EUCLIDEAN);
static NodeEnum feature_enum;
- feature_enum.insert("F1", NODE_VORONOI_F1);
- feature_enum.insert("F2", NODE_VORONOI_F2);
- feature_enum.insert("F3", NODE_VORONOI_F3);
- feature_enum.insert("F4", NODE_VORONOI_F4);
- feature_enum.insert("F2F1", NODE_VORONOI_F2F1);
- SOCKET_ENUM(feature, "Feature", feature_enum, NODE_VORONOI_INTENSITY);
+ feature_enum.insert("f1", NODE_VORONOI_F1);
+ feature_enum.insert("f2", NODE_VORONOI_F2);
+ feature_enum.insert("smooth_f1", NODE_VORONOI_SMOOTH_F1);
+ feature_enum.insert("distance_to_edge", NODE_VORONOI_DISTANCE_TO_EDGE);
+ feature_enum.insert("n_sphere_radius", NODE_VORONOI_N_SPHERE_RADIUS);
+ SOCKET_ENUM(feature, "Feature", feature_enum, NODE_VORONOI_F1);
- SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
- SOCKET_IN_FLOAT(exponent, "Exponent", 0.5f);
SOCKET_IN_POINT(
vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
+ SOCKET_IN_FLOAT(w, "W", 0.0f);
+ SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
+ SOCKET_IN_FLOAT(smoothness, "Smoothness", 5.0f);
+ SOCKET_IN_FLOAT(exponent, "Exponent", 0.5f);
+ SOCKET_IN_FLOAT(randomness, "Randomness", 1.0f);
+ SOCKET_OUT_FLOAT(distance, "Distance");
SOCKET_OUT_COLOR(color, "Color");
- SOCKET_OUT_FLOAT(fac, "Fac");
+ SOCKET_OUT_POINT(position, "Position");
+ SOCKET_OUT_FLOAT(w, "W");
+ SOCKET_OUT_FLOAT(radius, "Radius");
return type;
}
@@ -984,39 +1010,57 @@ VoronoiTextureNode::VoronoiTextureNode() : TextureNode(node_type)
void VoronoiTextureNode::compile(SVMCompiler &compiler)
{
- ShaderInput *scale_in = input("Scale");
ShaderInput *vector_in = input("Vector");
+ ShaderInput *w_in = input("W");
+ ShaderInput *scale_in = input("Scale");
+ ShaderInput *smoothness_in = input("Smoothness");
ShaderInput *exponent_in = input("Exponent");
- ShaderOutput *color_out = output("Color");
- ShaderOutput *fac_out = output("Fac");
+ ShaderInput *randomness_in = input("Randomness");
- if (vector_in->link)
- compiler.stack_assign(vector_in);
- if (scale_in->link)
- compiler.stack_assign(scale_in);
- if (exponent_in->link)
- compiler.stack_assign(exponent_in);
-
- int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
+ ShaderOutput *distance_out = output("Distance");
+ ShaderOutput *color_out = output("Color");
+ ShaderOutput *position_out = output("Position");
+ ShaderOutput *w_out = output("W");
+ ShaderOutput *radius_out = output("Radius");
+
+ int vector_stack_offset = tex_mapping.compile_begin(compiler, vector_in);
+ int w_in_stack_offset = compiler.stack_assign_if_linked(w_in);
+ int scale_stack_offset = compiler.stack_assign_if_linked(scale_in);
+ int smoothness_stack_offset = compiler.stack_assign_if_linked(smoothness_in);
+ int exponent_stack_offset = compiler.stack_assign_if_linked(exponent_in);
+ int randomness_stack_offset = compiler.stack_assign_if_linked(randomness_in);
+ int distance_stack_offset = compiler.stack_assign_if_linked(distance_out);
+ int color_stack_offset = compiler.stack_assign_if_linked(color_out);
+ int position_stack_offset = compiler.stack_assign_if_linked(position_out);
+ int w_out_stack_offset = compiler.stack_assign_if_linked(w_out);
+ int radius_stack_offset = compiler.stack_assign_if_linked(radius_out);
+
+ compiler.add_node(NODE_TEX_VORONOI, dimensions, feature, metric);
+ compiler.add_node(
+ compiler.encode_uchar4(
+ vector_stack_offset, w_in_stack_offset, scale_stack_offset, smoothness_stack_offset),
+ compiler.encode_uchar4(exponent_stack_offset,
+ randomness_stack_offset,
+ distance_stack_offset,
+ color_stack_offset),
+ compiler.encode_uchar4(position_stack_offset, w_out_stack_offset, radius_stack_offset),
+ __float_as_int(w));
- compiler.add_node(NODE_TEX_VORONOI,
- compiler.encode_uchar4(vector_offset, coloring, metric, feature),
- compiler.encode_uchar4(compiler.stack_assign_if_linked(scale_in),
- compiler.stack_assign_if_linked(exponent_in),
- compiler.stack_assign(fac_out),
- compiler.stack_assign(color_out)));
- compiler.add_node(__float_as_int(scale), __float_as_int(exponent));
+ compiler.add_node(__float_as_int(scale),
+ __float_as_int(smoothness),
+ __float_as_int(exponent),
+ __float_as_int(randomness));
- tex_mapping.compile_end(compiler, vector_in, vector_offset);
+ tex_mapping.compile_end(compiler, vector_in, vector_stack_offset);
}
void VoronoiTextureNode::compile(OSLCompiler &compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter(this, "coloring");
- compiler.parameter(this, "metric");
+ compiler.parameter(this, "dimensions");
compiler.parameter(this, "feature");
+ compiler.parameter(this, "metric");
compiler.add(this, "node_voronoi_texture");
}
@@ -1165,6 +1209,13 @@ NODE_DEFINE(MusgraveTextureNode)
TEXTURE_MAPPING_DEFINE(MusgraveTextureNode);
+ static NodeEnum dimensions_enum;
+ dimensions_enum.insert("1D", 1);
+ dimensions_enum.insert("2D", 2);
+ dimensions_enum.insert("3D", 3);
+ dimensions_enum.insert("4D", 4);
+ SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3);
+
static NodeEnum type_enum;
type_enum.insert("multifractal", NODE_MUSGRAVE_MULTIFRACTAL);
type_enum.insert("fBM", NODE_MUSGRAVE_FBM);
@@ -1173,16 +1224,16 @@ NODE_DEFINE(MusgraveTextureNode)
type_enum.insert("hetero_terrain", NODE_MUSGRAVE_HETERO_TERRAIN);
SOCKET_ENUM(type, "Type", type_enum, NODE_MUSGRAVE_FBM);
+ SOCKET_IN_POINT(
+ vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
+ SOCKET_IN_FLOAT(w, "W", 0.0f);
SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
SOCKET_IN_FLOAT(dimension, "Dimension", 2.0f);
SOCKET_IN_FLOAT(lacunarity, "Lacunarity", 1.0f);
SOCKET_IN_FLOAT(offset, "Offset", 0.0f);
SOCKET_IN_FLOAT(gain, "Gain", 1.0f);
- SOCKET_IN_POINT(
- vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
- SOCKET_OUT_COLOR(color, "Color");
SOCKET_OUT_FLOAT(fac, "Fac");
return type;
@@ -1195,35 +1246,38 @@ MusgraveTextureNode::MusgraveTextureNode() : TextureNode(node_type)
void MusgraveTextureNode::compile(SVMCompiler &compiler)
{
ShaderInput *vector_in = input("Vector");
+ ShaderInput *w_in = input("W");
ShaderInput *scale_in = input("Scale");
+ ShaderInput *detail_in = input("Detail");
ShaderInput *dimension_in = input("Dimension");
ShaderInput *lacunarity_in = input("Lacunarity");
- ShaderInput *detail_in = input("Detail");
ShaderInput *offset_in = input("Offset");
ShaderInput *gain_in = input("Gain");
ShaderOutput *fac_out = output("Fac");
- ShaderOutput *color_out = output("Color");
- int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
+ int vector_stack_offset = tex_mapping.compile_begin(compiler, vector_in);
+ int w_stack_offset = compiler.stack_assign_if_linked(w_in);
+ int scale_stack_offset = compiler.stack_assign_if_linked(scale_in);
+ int detail_stack_offset = compiler.stack_assign_if_linked(detail_in);
+ int dimension_stack_offset = compiler.stack_assign_if_linked(dimension_in);
+ int lacunarity_stack_offset = compiler.stack_assign_if_linked(lacunarity_in);
+ int offset_stack_offset = compiler.stack_assign_if_linked(offset_in);
+ int gain_stack_offset = compiler.stack_assign_if_linked(gain_in);
+ int fac_stack_offset = compiler.stack_assign(fac_out);
- compiler.add_node(NODE_TEX_MUSGRAVE,
- compiler.encode_uchar4(type,
- vector_offset,
- compiler.stack_assign_if_linked(color_out),
- compiler.stack_assign_if_linked(fac_out)),
- compiler.encode_uchar4(compiler.stack_assign_if_linked(dimension_in),
- compiler.stack_assign_if_linked(lacunarity_in),
- compiler.stack_assign_if_linked(detail_in),
- compiler.stack_assign_if_linked(offset_in)),
- compiler.encode_uchar4(compiler.stack_assign_if_linked(gain_in),
- compiler.stack_assign_if_linked(scale_in)));
- compiler.add_node(__float_as_int(dimension),
- __float_as_int(lacunarity),
- __float_as_int(detail),
- __float_as_int(offset));
- compiler.add_node(__float_as_int(gain), __float_as_int(scale));
+ compiler.add_node(
+ NODE_TEX_MUSGRAVE,
+ compiler.encode_uchar4(type, dimensions, vector_stack_offset, w_stack_offset),
+ compiler.encode_uchar4(scale_stack_offset,
+ detail_stack_offset,
+ dimension_stack_offset,
+ lacunarity_stack_offset),
+ compiler.encode_uchar4(offset_stack_offset, gain_stack_offset, fac_stack_offset));
+ compiler.add_node(
+ __float_as_int(w), __float_as_int(scale), __float_as_int(detail), __float_as_int(dimension));
+ compiler.add_node(__float_as_int(lacunarity), __float_as_int(offset), __float_as_int(gain));
- tex_mapping.compile_end(compiler, vector_in, vector_offset);
+ tex_mapping.compile_end(compiler, vector_in, vector_stack_offset);
}
void MusgraveTextureNode::compile(OSLCompiler &compiler)
@@ -1231,6 +1285,7 @@ void MusgraveTextureNode::compile(OSLCompiler &compiler)
tex_mapping.compile(compiler);
compiler.parameter(this, "type");
+ compiler.parameter(this, "dimensions");
compiler.add(this, "node_musgrave_texture");
}
@@ -1710,9 +1765,18 @@ NODE_DEFINE(MappingNode)
{
NodeType *type = NodeType::add("mapping", create, NodeType::SHADER);
- TEXTURE_MAPPING_DEFINE(MappingNode);
+ static NodeEnum type_enum;
+ type_enum.insert("point", NODE_MAPPING_TYPE_POINT);
+ type_enum.insert("texture", NODE_MAPPING_TYPE_TEXTURE);
+ type_enum.insert("vector", NODE_MAPPING_TYPE_VECTOR);
+ type_enum.insert("normal", NODE_MAPPING_TYPE_NORMAL);
+ SOCKET_ENUM(type, "Type", type_enum, NODE_MAPPING_TYPE_POINT);
SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_IN_POINT(location, "Location", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_IN_POINT(rotation, "Rotation", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_IN_POINT(scale, "Scale", make_float3(1.0f, 1.0f, 1.0f));
+
SOCKET_OUT_POINT(vector, "Vector");
return type;
@@ -1722,22 +1786,42 @@ MappingNode::MappingNode() : ShaderNode(node_type)
{
}
+void MappingNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ float3 result = svm_mapping((NodeMappingType)type, vector, location, rotation, scale);
+ folder.make_constant(result);
+ }
+ else {
+ folder.fold_mapping((NodeMappingType)type);
+ }
+}
+
void MappingNode::compile(SVMCompiler &compiler)
{
ShaderInput *vector_in = input("Vector");
+ ShaderInput *location_in = input("Location");
+ ShaderInput *rotation_in = input("Rotation");
+ ShaderInput *scale_in = input("Scale");
ShaderOutput *vector_out = output("Vector");
- tex_mapping.compile(
- compiler, compiler.stack_assign(vector_in), compiler.stack_assign(vector_out));
+ int vector_stack_offset = compiler.stack_assign(vector_in);
+ int location_stack_offset = compiler.stack_assign(location_in);
+ int rotation_stack_offset = compiler.stack_assign(rotation_in);
+ int scale_stack_offset = compiler.stack_assign(scale_in);
+ int result_stack_offset = compiler.stack_assign(vector_out);
+
+ compiler.add_node(
+ NODE_MAPPING,
+ type,
+ compiler.encode_uchar4(
+ vector_stack_offset, location_stack_offset, rotation_stack_offset, scale_stack_offset),
+ result_stack_offset);
}
void MappingNode::compile(OSLCompiler &compiler)
{
- compiler.parameter("Matrix", tex_mapping.compute_transform());
- compiler.parameter_point("mapping_min", tex_mapping.min);
- compiler.parameter_point("mapping_max", tex_mapping.max);
- compiler.parameter("use_minmax", tex_mapping.use_minmax);
-
+ compiler.parameter(this, "type");
compiler.add(this, "node_mapping");
}
@@ -4258,6 +4342,64 @@ void VolumeInfoNode::compile(OSLCompiler &)
{
}
+NODE_DEFINE(VertexColorNode)
+{
+ NodeType *type = NodeType::add("vertex_color", create, NodeType::SHADER);
+
+ SOCKET_STRING(layer_name, "Layer Name", ustring());
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(alpha, "Alpha");
+
+ return type;
+}
+
+VertexColorNode::VertexColorNode() : ShaderNode(node_type)
+{
+}
+
+void VertexColorNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if (!(output("Color")->links.empty() && output("Alpha")->links.empty())) {
+ attributes->add_standard(layer_name);
+ }
+ ShaderNode::attributes(shader, attributes);
+}
+
+void VertexColorNode::compile(SVMCompiler &compiler)
+{
+ ShaderOutput *color_out = output("Color");
+ ShaderOutput *alpha_out = output("Alpha");
+ int layer_id = compiler.attribute(layer_name);
+
+ ShaderNodeType node;
+
+ if (bump == SHADER_BUMP_DX)
+ node = NODE_VERTEX_COLOR_BUMP_DX;
+ else if (bump == SHADER_BUMP_DY)
+ node = NODE_VERTEX_COLOR_BUMP_DY;
+ else {
+ node = NODE_VERTEX_COLOR;
+ }
+
+ compiler.add_node(
+ node, layer_id, compiler.stack_assign(color_out), compiler.stack_assign(alpha_out));
+}
+
+void VertexColorNode::compile(OSLCompiler &compiler)
+{
+ if (bump == SHADER_BUMP_DX) {
+ compiler.parameter("bump_offset", "dx");
+ }
+ else if (bump == SHADER_BUMP_DY) {
+ compiler.parameter("bump_offset", "dy");
+ }
+ else {
+ compiler.parameter("bump_offset", "center");
+ }
+ compiler.parameter("layer_name", layer_name.c_str());
+ compiler.add(this, "node_vertex_color");
+}
+
/* Value */
NODE_DEFINE(ValueNode)
@@ -5674,8 +5816,8 @@ VectorMathNode::VectorMathNode() : ShaderNode(node_type)
void VectorMathNode::constant_fold(const ConstantFolder &folder)
{
- float value;
- float3 vector;
+ float value = 0.0f;
+ float3 vector = make_float3(0.0f, 0.0f, 0.0f);
if (folder.all_inputs_constant()) {
svm_vector_math(&value, &vector, type, vector1, vector2, scale);
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index fbed2ff0ef6..13e9b65fa07 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -206,7 +206,8 @@ class NoiseTextureNode : public TextureNode {
public:
SHADER_NODE_CLASS(NoiseTextureNode)
- float scale, detail, distortion;
+ int dimensions;
+ float w, scale, detail, distortion;
float3 vector;
};
@@ -219,10 +220,10 @@ class VoronoiTextureNode : public TextureNode {
return NODE_GROUP_LEVEL_2;
}
- NodeVoronoiColoring coloring;
+ int dimensions;
NodeVoronoiDistanceMetric metric;
NodeVoronoiFeature feature;
- float scale, exponent;
+ float w, scale, exponent, smoothness, randomness;
float3 vector;
};
@@ -235,8 +236,9 @@ class MusgraveTextureNode : public TextureNode {
return NODE_GROUP_LEVEL_2;
}
+ int dimensions;
NodeMusgraveType type;
- float scale, detail, dimension, lacunarity, offset, gain;
+ float w, scale, detail, dimension, lacunarity, offset, gain;
float3 vector;
};
@@ -390,9 +392,10 @@ class MappingNode : public ShaderNode {
{
return NODE_GROUP_LEVEL_2;
}
+ void constant_fold(const ConstantFolder &folder);
- float3 vector;
- TextureMapping tex_mapping;
+ float3 vector, location, rotation, scale;
+ NodeMappingType type;
};
class RGBToBWNode : public ShaderNode {
@@ -976,6 +979,22 @@ class VolumeInfoNode : public ShaderNode {
void expand(ShaderGraph *graph);
};
+class VertexColorNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(VertexColorNode)
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+
+ ustring layer_name;
+};
+
class ValueNode : public ShaderNode {
public:
SHADER_NODE_CLASS(ValueNode)
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index 157bb6d63d3..7a894c1e98a 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -83,7 +83,7 @@ Session::Session(const SessionParams &params_)
display_outdated = false;
gpu_draw_ready = false;
- gpu_need_tonemap = false;
+ gpu_need_display_buffer_update = false;
pause = false;
kernels_loaded = false;
@@ -97,8 +97,8 @@ Session::~Session()
/* wait for session thread to end */
progress.set_cancel("Exiting");
- gpu_need_tonemap = false;
- gpu_need_tonemap_cond.notify_all();
+ gpu_need_display_buffer_update = false;
+ gpu_need_display_buffer_update_cond.notify_all();
{
thread_scoped_lock pause_lock(pause_mutex);
@@ -110,12 +110,12 @@ Session::~Session()
}
if (params.write_render_cb) {
- /* tonemap and write out image if requested */
+ /* Copy to display buffer and write out image if requested */
delete display;
display = new DisplayBuffer(device, false);
display->reset(buffers->params);
- tonemap(params.samples);
+ copy_to_display_buffer(params.samples);
int w = display->draw_width;
int h = display->draw_height;
@@ -168,8 +168,8 @@ void Session::reset_gpu(BufferParams &buffer_params, int samples)
reset_(buffer_params, samples);
- gpu_need_tonemap = false;
- gpu_need_tonemap_cond.notify_all();
+ gpu_need_display_buffer_update = false;
+ gpu_need_display_buffer_update_cond.notify_all();
pause_cond.notify_all();
}
@@ -186,11 +186,11 @@ bool Session::draw_gpu(BufferParams &buffer_params, DeviceDrawParams &draw_param
if (!buffer_params.modified(display->params)) {
/* for CUDA we need to do tone-mapping still, since we can
* only access GL buffers from the main thread. */
- if (gpu_need_tonemap) {
+ if (gpu_need_display_buffer_update) {
thread_scoped_lock buffers_lock(buffers_mutex);
- tonemap(tile_manager.state.sample);
- gpu_need_tonemap = false;
- gpu_need_tonemap_cond.notify_all();
+ copy_to_display_buffer(tile_manager.state.sample);
+ gpu_need_display_buffer_update = false;
+ gpu_need_display_buffer_update_cond.notify_all();
}
display->draw(device, draw_params);
@@ -232,7 +232,7 @@ void Session::run_gpu()
}
/* Don't go in pause mode when image was rendered with preview kernels
- * When feature kernels become available the session will be resetted. */
+ * When feature kernels become available the session will be reset. */
else if (no_tiles && kernel_state == DEVICE_KERNEL_WAITING_FOR_FEATURE_KERNEL) {
time_sleep(0.1);
}
@@ -307,17 +307,17 @@ void Session::run_gpu()
/* update status and timing */
update_status_time();
- gpu_need_tonemap = true;
+ gpu_need_display_buffer_update = true;
gpu_draw_ready = true;
progress.set_update();
- /* wait for tonemap */
+ /* wait for until display buffer is updated */
if (!params.background) {
- while (gpu_need_tonemap) {
+ while (gpu_need_display_buffer_update) {
if (progress.get_cancel())
break;
- gpu_need_tonemap_cond.wait(buffers_lock);
+ gpu_need_display_buffer_update_cond.wait(buffers_lock);
}
}
@@ -561,7 +561,7 @@ void Session::run_cpu()
while (!progress.get_cancel()) {
/* advance to next tile */
bool no_tiles = !tile_manager.next();
- bool need_tonemap = false;
+ bool need_copy_to_display_buffer = false;
DeviceKernelStatus kernel_state = DEVICE_KERNEL_UNKNOWN;
if (no_tiles) {
@@ -650,7 +650,7 @@ void Session::run_cpu()
update_status_time();
if (!params.background)
- need_tonemap = true;
+ need_copy_to_display_buffer = true;
if (!device->error_message().empty())
progress.set_error(device->error_message());
@@ -668,10 +668,10 @@ void Session::run_cpu()
delayed_reset.do_reset = false;
reset_(delayed_reset.params, delayed_reset.samples);
}
- else if (need_tonemap) {
- /* tonemap only if we do not reset, we don't we don't
+ else if (need_copy_to_display_buffer) {
+ /* Only copy to display_buffer if we do not reset, we don't
* want to show the result of an incomplete sample */
- tonemap(tile_manager.state.sample);
+ copy_to_display_buffer(tile_manager.state.sample);
}
if (!device->error_message().empty())
@@ -1044,9 +1044,9 @@ void Session::render()
device->task_add(task);
}
-void Session::tonemap(int sample)
+void Session::copy_to_display_buffer(int sample)
{
- /* add tonemap task */
+ /* add film conversion task */
DeviceTask task(DeviceTask::FILM_CONVERT);
task.x = tile_manager.state.buffer.full_x;
diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h
index 60d8f7a8b14..9fffc13dd41 100644
--- a/intern/cycles/render/session.h
+++ b/intern/cycles/render/session.h
@@ -176,7 +176,7 @@ class Session {
void update_status_time(bool show_pause = false, bool show_done = false);
- void tonemap(int sample);
+ void copy_to_display_buffer(int sample);
void render();
void reset_(BufferParams &params, int samples);
@@ -202,8 +202,8 @@ class Session {
volatile bool display_outdated;
volatile bool gpu_draw_ready;
- volatile bool gpu_need_tonemap;
- thread_condition_variable gpu_need_tonemap_cond;
+ volatile bool gpu_need_display_buffer_update;
+ thread_condition_variable gpu_need_display_buffer_update_cond;
bool pause;
thread_condition_variable pause_cond;
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
index ec85e516832..00d9cd5e672 100644
--- a/intern/cycles/render/shader.cpp
+++ b/intern/cycles/render/shader.cpp
@@ -703,6 +703,8 @@ void ShaderManager::get_requested_features(Scene *scene,
requested_features->nodes_features |= NODE_FEATURE_BUMP;
if (shader->displacement_method == DISPLACE_BOTH) {
requested_features->nodes_features |= NODE_FEATURE_BUMP_STATE;
+ requested_features->max_nodes_group = max(requested_features->max_nodes_group,
+ NODE_GROUP_LEVEL_1);
}
}
/* On top of volume nodes, also check if we need volume sampling because
diff --git a/intern/cycles/subd/CMakeLists.txt b/intern/cycles/subd/CMakeLists.txt
index f5ceaa0436d..b874c5c3c2d 100644
--- a/intern/cycles/subd/CMakeLists.txt
+++ b/intern/cycles/subd/CMakeLists.txt
@@ -19,6 +19,7 @@ set(SRC_HEADERS
subd_patch.h
subd_patch_table.h
subd_split.h
+ subd_subpatch.h
)
set(LIB
diff --git a/intern/cycles/subd/subd_dice.cpp b/intern/cycles/subd/subd_dice.cpp
index 914b408911e..91c7f4bea05 100644
--- a/intern/cycles/subd/subd_dice.cpp
+++ b/intern/cycles/subd/subd_dice.cpp
@@ -38,107 +38,91 @@ EdgeDice::EdgeDice(const SubdParams &params_) : params(params_)
}
}
-void EdgeDice::reserve(int num_verts)
+void EdgeDice::reserve(int num_verts, int num_triangles)
{
Mesh *mesh = params.mesh;
vert_offset = mesh->verts.size();
tri_offset = mesh->num_triangles();
- /* todo: optimize so we can reserve in advance, this is like push_back_slow() */
- if (vert_offset + num_verts > mesh->verts.capacity()) {
- mesh->reserve_mesh(size_t((vert_offset + num_verts) * 1.2), mesh->num_triangles());
- }
-
- mesh->resize_mesh(vert_offset + num_verts, tri_offset);
+ mesh->resize_mesh(mesh->verts.size() + num_verts, mesh->num_triangles());
+ mesh->reserve_mesh(mesh->verts.size() + num_verts, mesh->num_triangles() + num_triangles);
Attribute *attr_vN = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
- mesh_P = mesh->verts.data();
- mesh_N = attr_vN->data_float3();
+ mesh_P = mesh->verts.data() + vert_offset;
+ mesh_N = attr_vN->data_float3() + vert_offset;
+
+ params.mesh->num_subd_verts += num_verts;
}
-int EdgeDice::add_vert(Patch *patch, float2 uv)
+void EdgeDice::set_vert(Patch *patch, int index, float2 uv)
{
float3 P, N;
patch->eval(&P, NULL, NULL, &N, uv.x, uv.y);
- assert(vert_offset < params.mesh->verts.size());
-
- mesh_P[vert_offset] = P;
- mesh_N[vert_offset] = N;
- params.mesh->vert_patch_uv[vert_offset] = make_float2(uv.x, uv.y);
-
- if (params.ptex) {
- Attribute *attr_ptex_uv = params.mesh->attributes.add(ATTR_STD_PTEX_UV);
- params.mesh->attributes.resize();
+ assert(index < params.mesh->verts.size());
- float3 *ptex_uv = attr_ptex_uv->data_float3();
- ptex_uv[vert_offset] = make_float3(uv.x, uv.y, 0.0f);
- }
-
- params.mesh->num_subd_verts++;
-
- return vert_offset++;
+ mesh_P[index] = P;
+ mesh_N[index] = N;
+ params.mesh->vert_patch_uv[index + vert_offset] = make_float2(uv.x, uv.y);
}
void EdgeDice::add_triangle(Patch *patch, int v0, int v1, int v2)
{
Mesh *mesh = params.mesh;
- /* todo: optimize so we can reserve in advance, this is like push_back_slow() */
- if (mesh->triangles.size() == mesh->triangles.capacity())
- mesh->reserve_mesh(mesh->verts.size(), size_t(max(mesh->num_triangles() + 1, 1) * 1.2));
-
- mesh->add_triangle(v0, v1, v2, patch->shader, true);
+ mesh->add_triangle(v0 + vert_offset, v1 + vert_offset, v2 + vert_offset, patch->shader, true);
params.mesh->triangle_patch[params.mesh->num_triangles() - 1] = patch->patch_index;
- if (params.ptex) {
- Attribute *attr_ptex_face_id = params.mesh->attributes.add(ATTR_STD_PTEX_FACE_ID);
- params.mesh->attributes.resize();
-
- float *ptex_face_id = attr_ptex_face_id->data_float();
- ptex_face_id[tri_offset] = (float)patch->ptex_face_id();
- }
-
tri_offset++;
}
-void EdgeDice::stitch_triangles(Patch *patch, vector<int> &outer, vector<int> &inner)
+void EdgeDice::stitch_triangles(Subpatch &sub, int edge)
{
- if (inner.size() == 0 || outer.size() == 0)
+ int Mu = max(sub.edge_u0.T, sub.edge_u1.T);
+ int Mv = max(sub.edge_v0.T, sub.edge_v1.T);
+ Mu = max(Mu, 2);
+ Mv = max(Mv, 2);
+
+ int outer_T = sub.edges[edge].T;
+ int inner_T = ((edge % 2) == 0) ? Mv - 2 : Mu - 2;
+
+ if (inner_T < 0 || outer_T < 0)
return; // XXX avoid crashes for Mu or Mv == 1, missing polygons
/* stitch together two arrays of verts with triangles. at each step,
* we compare using the next verts on both sides, to find the split
* direction with the smallest diagonal, and use that in order to keep
* the triangle shape reasonable. */
- for (size_t i = 0, j = 0; i + 1 < inner.size() || j + 1 < outer.size();) {
+ for (size_t i = 0, j = 0; i < inner_T || j < outer_T;) {
int v0, v1, v2;
- v0 = inner[i];
- v1 = outer[j];
+ v0 = sub.get_vert_along_grid_edge(edge, i);
+ v1 = sub.get_vert_along_edge(edge, j);
- if (j + 1 == outer.size()) {
- v2 = inner[++i];
+ if (j == outer_T) {
+ v2 = sub.get_vert_along_grid_edge(edge, ++i);
}
- else if (i + 1 == inner.size()) {
- v2 = outer[++j];
+ else if (i == inner_T) {
+ v2 = sub.get_vert_along_edge(edge, ++j);
}
else {
/* length of diagonals */
- float len1 = len_squared(mesh_P[inner[i]] - mesh_P[outer[j + 1]]);
- float len2 = len_squared(mesh_P[outer[j]] - mesh_P[inner[i + 1]]);
+ float len1 = len_squared(mesh_P[sub.get_vert_along_grid_edge(edge, i)] -
+ mesh_P[sub.get_vert_along_edge(edge, j + 1)]);
+ float len2 = len_squared(mesh_P[sub.get_vert_along_edge(edge, j)] -
+ mesh_P[sub.get_vert_along_grid_edge(edge, i + 1)]);
/* use smallest diagonal */
if (len1 < len2)
- v2 = outer[++j];
+ v2 = sub.get_vert_along_edge(edge, ++j);
else
- v2 = inner[++i];
+ v2 = sub.get_vert_along_grid_edge(edge, ++i);
}
- add_triangle(patch, v0, v1, v2);
+ add_triangle(sub.patch, v1, v0, v2);
}
}
@@ -148,22 +132,15 @@ QuadDice::QuadDice(const SubdParams &params_) : EdgeDice(params_)
{
}
-void QuadDice::reserve(EdgeFactors &ef, int Mu, int Mv)
-{
- /* XXX need to make this also work for edge factor 0 and 1 */
- int num_verts = (ef.tu0 + ef.tu1 + ef.tv0 + ef.tv1) + (Mu - 1) * (Mv - 1);
- EdgeDice::reserve(num_verts);
-}
-
-float2 QuadDice::map_uv(SubPatch &sub, float u, float v)
+float2 QuadDice::map_uv(Subpatch &sub, float u, float v)
{
/* map UV from subpatch to patch parametric coordinates */
- float2 d0 = interp(sub.P00, sub.P01, v);
- float2 d1 = interp(sub.P10, sub.P11, v);
+ float2 d0 = interp(sub.c00, sub.c01, v);
+ float2 d1 = interp(sub.c10, sub.c11, v);
return interp(d0, d1, u);
}
-float3 QuadDice::eval_projected(SubPatch &sub, float u, float v)
+float3 QuadDice::eval_projected(Subpatch &sub, float u, float v)
{
float2 uv = map_uv(sub, u, v);
float3 P;
@@ -175,70 +152,41 @@ float3 QuadDice::eval_projected(SubPatch &sub, float u, float v)
return P;
}
-int QuadDice::add_vert(SubPatch &sub, float u, float v)
+void QuadDice::set_vert(Subpatch &sub, int index, float u, float v)
{
- return EdgeDice::add_vert(sub.patch, map_uv(sub, u, v));
+ EdgeDice::set_vert(sub.patch, index, map_uv(sub, u, v));
}
-void QuadDice::add_side_u(SubPatch &sub,
- vector<int> &outer,
- vector<int> &inner,
- int Mu,
- int Mv,
- int tu,
- int side,
- int offset)
+void QuadDice::set_side(Subpatch &sub, int edge)
{
- outer.clear();
- inner.clear();
+ int t = sub.edges[edge].T;
/* set verts on the edge of the patch */
- outer.push_back(offset + ((side) ? 2 : 0));
-
- for (int i = 1; i < tu; i++) {
- float u = i / (float)tu;
- float v = (side) ? 1.0f : 0.0f;
-
- outer.push_back(add_vert(sub, u, v));
- }
-
- outer.push_back(offset + ((side) ? 3 : 1));
-
- /* set verts on the edge of the inner grid */
- for (int i = 0; i < Mu - 1; i++) {
- int j = (side) ? Mv - 1 - 1 : 0;
- inner.push_back(offset + 4 + i + j * (Mu - 1));
- }
-}
-
-void QuadDice::add_side_v(SubPatch &sub,
- vector<int> &outer,
- vector<int> &inner,
- int Mu,
- int Mv,
- int tv,
- int side,
- int offset)
-{
- outer.clear();
- inner.clear();
-
- /* set verts on the edge of the patch */
- outer.push_back(offset + ((side) ? 1 : 0));
-
- for (int j = 1; j < tv; j++) {
- float u = (side) ? 1.0f : 0.0f;
- float v = j / (float)tv;
-
- outer.push_back(add_vert(sub, u, v));
- }
-
- outer.push_back(offset + ((side) ? 3 : 2));
+ for (int i = 0; i < t; i++) {
+ float f = i / (float)t;
+
+ float u, v;
+ switch (edge) {
+ case 0:
+ u = 0;
+ v = f;
+ break;
+ case 1:
+ u = f;
+ v = 1;
+ break;
+ case 2:
+ u = 1;
+ v = 1.0f - f;
+ break;
+ case 3:
+ default:
+ u = 1.0f - f;
+ v = 0;
+ break;
+ }
- /* set verts on the edge of the inner grid */
- for (int j = 0; j < Mv - 1; j++) {
- int i = (side) ? Mu - 1 - 1 : 0;
- inner.push_back(offset + 4 + i + j * (Mu - 1));
+ set_vert(sub, sub.get_vert_along_edge(edge, i), u, v);
}
}
@@ -247,7 +195,7 @@ float QuadDice::quad_area(const float3 &a, const float3 &b, const float3 &c, con
return triangle_area(a, b, d) + triangle_area(a, d, c);
}
-float QuadDice::scale_factor(SubPatch &sub, EdgeFactors &ef, int Mu, int Mv)
+float QuadDice::scale_factor(Subpatch &sub, int Mu, int Mv)
{
/* estimate area as 4x largest of 4 quads */
float3 P[3][3];
@@ -269,23 +217,14 @@ float QuadDice::scale_factor(SubPatch &sub, EdgeFactors &ef, int Mu, int Mv)
// XXX does the -sqrt solution matter
// XXX max(D, 0.0) is highly suspicious, need to test cases
// where D goes negative
- float N = 0.5f * (Ntris - (ef.tu0 + ef.tu1 + ef.tv0 + ef.tv1));
+ float N = 0.5f * (Ntris - (sub.edge_u0.T + sub.edge_u1.T + sub.edge_v0.T + sub.edge_v1.T));
float D = 4.0f * N * Mu * Mv + (Mu + Mv) * (Mu + Mv);
float S = (Mu + Mv + sqrtf(max(D, 0.0f))) / (2 * Mu * Mv);
return S;
}
-void QuadDice::add_corners(SubPatch &sub)
-{
- /* add verts for patch corners */
- add_vert(sub, 0.0f, 0.0f);
- add_vert(sub, 1.0f, 0.0f);
- add_vert(sub, 0.0f, 1.0f);
- add_vert(sub, 1.0f, 1.0f);
-}
-
-void QuadDice::add_grid(SubPatch &sub, int Mu, int Mv, int offset)
+void QuadDice::add_grid(Subpatch &sub, int Mu, int Mv, int offset)
{
/* create inner grid */
float du = 1.0f / (float)Mu;
@@ -296,13 +235,13 @@ void QuadDice::add_grid(SubPatch &sub, int Mu, int Mv, int offset)
float u = i * du;
float v = j * dv;
- add_vert(sub, u, v);
+ set_vert(sub, offset + (i - 1) + (j - 1) * (Mu - 1), u, v);
if (i < Mu - 1 && j < Mv - 1) {
- int i1 = offset + 4 + (i - 1) + (j - 1) * (Mu - 1);
- int i2 = offset + 4 + i + (j - 1) * (Mu - 1);
- int i3 = offset + 4 + i + j * (Mu - 1);
- int i4 = offset + 4 + (i - 1) + j * (Mu - 1);
+ int i1 = offset + (i - 1) + (j - 1) * (Mu - 1);
+ int i2 = offset + i + (j - 1) * (Mu - 1);
+ int i3 = offset + i + j * (Mu - 1);
+ int i4 = offset + (i - 1) + j * (Mu - 1);
add_triangle(sub.patch, i1, i2, i3);
add_triangle(sub.patch, i1, i3, i4);
@@ -311,11 +250,11 @@ void QuadDice::add_grid(SubPatch &sub, int Mu, int Mv, int offset)
}
}
-void QuadDice::dice(SubPatch &sub, EdgeFactors &ef)
+void QuadDice::dice(Subpatch &sub)
{
/* compute inner grid size with scale factor */
- int Mu = max(ef.tu0, ef.tu1);
- int Mv = max(ef.tv0, ef.tv1);
+ int Mu = max(sub.edge_u0.T, sub.edge_u1.T);
+ int Mv = max(sub.edge_v0.T, sub.edge_v1.T);
#if 0 /* Doesn't work very well, especially at grazing angles. */
float S = scale_factor(sub, ef, Mu, Mv);
@@ -326,33 +265,19 @@ void QuadDice::dice(SubPatch &sub, EdgeFactors &ef)
Mu = max((int)ceilf(S * Mu), 2); // XXX handle 0 & 1?
Mv = max((int)ceilf(S * Mv), 2); // XXX handle 0 & 1?
- /* reserve space for new verts */
- int offset = params.mesh->verts.size();
- reserve(ef, Mu, Mv);
-
- /* corners and inner grid */
- add_corners(sub);
- add_grid(sub, Mu, Mv, offset);
-
- /* bottom side */
- vector<int> outer, inner;
-
- add_side_u(sub, outer, inner, Mu, Mv, ef.tu0, 0, offset);
- stitch_triangles(sub.patch, outer, inner);
-
- /* top side */
- add_side_u(sub, outer, inner, Mu, Mv, ef.tu1, 1, offset);
- stitch_triangles(sub.patch, inner, outer);
-
- /* left side */
- add_side_v(sub, outer, inner, Mu, Mv, ef.tv0, 0, offset);
- stitch_triangles(sub.patch, inner, outer);
+ /* inner grid */
+ add_grid(sub, Mu, Mv, sub.inner_grid_vert_offset);
- /* right side */
- add_side_v(sub, outer, inner, Mu, Mv, ef.tv1, 1, offset);
- stitch_triangles(sub.patch, outer, inner);
+ /* sides */
+ set_side(sub, 0);
+ set_side(sub, 1);
+ set_side(sub, 2);
+ set_side(sub, 3);
- assert(vert_offset == params.mesh->verts.size());
+ stitch_triangles(sub, 0);
+ stitch_triangles(sub, 1);
+ stitch_triangles(sub, 2);
+ stitch_triangles(sub, 3);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/subd/subd_dice.h b/intern/cycles/subd/subd_dice.h
index eee54e01861..ee63403d40c 100644
--- a/intern/cycles/subd/subd_dice.h
+++ b/intern/cycles/subd/subd_dice.h
@@ -25,6 +25,8 @@
#include "util/util_types.h"
#include "util/util_vector.h"
+#include "subd/subd_subpatch.h"
+
CCL_NAMESPACE_BEGIN
class Camera;
@@ -67,78 +69,33 @@ class EdgeDice {
explicit EdgeDice(const SubdParams &params);
- void reserve(int num_verts);
+ void reserve(int num_verts, int num_triangles);
- int add_vert(Patch *patch, float2 uv);
+ void set_vert(Patch *patch, int index, float2 uv);
void add_triangle(Patch *patch, int v0, int v1, int v2);
- void stitch_triangles(Patch *patch, vector<int> &outer, vector<int> &inner);
+ void stitch_triangles(Subpatch &sub, int edge);
};
-/* Quad EdgeDice
- *
- * Edge tessellation factors and subpatch coordinates are as follows:
- *
- * tu1
- * P01 --------- P11
- * | |
- * tv0 | | tv1
- * | |
- * P00 --------- P10
- * tu0
- */
+/* Quad EdgeDice */
class QuadDice : public EdgeDice {
public:
- struct SubPatch {
- Patch *patch;
-
- float2 P00;
- float2 P10;
- float2 P01;
- float2 P11;
- };
-
- struct EdgeFactors {
- int tu0;
- int tu1;
- int tv0;
- int tv1;
- };
-
explicit QuadDice(const SubdParams &params);
- void reserve(EdgeFactors &ef, int Mu, int Mv);
- float3 eval_projected(SubPatch &sub, float u, float v);
-
- float2 map_uv(SubPatch &sub, float u, float v);
- int add_vert(SubPatch &sub, float u, float v);
-
- void add_corners(SubPatch &sub);
- void add_grid(SubPatch &sub, int Mu, int Mv, int offset);
-
- void add_side_u(SubPatch &sub,
- vector<int> &outer,
- vector<int> &inner,
- int Mu,
- int Mv,
- int tu,
- int side,
- int offset);
-
- void add_side_v(SubPatch &sub,
- vector<int> &outer,
- vector<int> &inner,
- int Mu,
- int Mv,
- int tv,
- int side,
- int offset);
+ float3 eval_projected(Subpatch &sub, float u, float v);
+
+ float2 map_uv(Subpatch &sub, float u, float v);
+ void set_vert(Subpatch &sub, int index, float u, float v);
+
+ void add_grid(Subpatch &sub, int Mu, int Mv, int offset);
+
+ void set_side(Subpatch &sub, int edge);
float quad_area(const float3 &a, const float3 &b, const float3 &c, const float3 &d);
- float scale_factor(SubPatch &sub, EdgeFactors &ef, int Mu, int Mv);
+ float scale_factor(Subpatch &sub, int Mu, int Mv);
- void dice(SubPatch &sub, EdgeFactors &ef);
+ void dice(Subpatch &sub);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/subd/subd_patch.h b/intern/cycles/subd/subd_patch.h
index 5209d4d0b07..8fe423bc94d 100644
--- a/intern/cycles/subd/subd_patch.h
+++ b/intern/cycles/subd/subd_patch.h
@@ -24,18 +24,17 @@ CCL_NAMESPACE_BEGIN
class Patch {
public:
- virtual ~Patch()
+ Patch() : patch_index(0), shader(0), from_ngon(false)
{
}
+
+ virtual ~Patch() = default;
+
virtual void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v) = 0;
- virtual BoundBox bound() = 0;
- virtual int ptex_face_id()
- {
- return -1;
- }
int patch_index;
int shader;
+ bool from_ngon;
};
/* Linear Quad Patch */
diff --git a/intern/cycles/subd/subd_split.cpp b/intern/cycles/subd/subd_split.cpp
index e5b85fcfd60..1a8c182510c 100644
--- a/intern/cycles/subd/subd_split.cpp
+++ b/intern/cycles/subd/subd_split.cpp
@@ -21,6 +21,9 @@
#include "subd/subd_patch.h"
#include "subd/subd_split.h"
+#include "util/util_algorithm.h"
+#include "util/util_foreach.h"
+#include "util/util_hash.h"
#include "util/util_math.h"
#include "util/util_types.h"
@@ -28,14 +31,12 @@ CCL_NAMESPACE_BEGIN
/* DiagSplit */
-DiagSplit::DiagSplit(const SubdParams &params_) : params(params_)
-{
-}
+#define DSPLIT_NON_UNIFORM -1
+#define STITCH_NGON_CENTER_VERT_INDEX_OFFSET 0x60000000
+#define STITCH_NGON_SPLIT_EDGE_CENTER_VERT_TAG (0x60000000 - 1)
-void DiagSplit::dispatch(QuadDice::SubPatch &sub, QuadDice::EdgeFactors &ef)
+DiagSplit::DiagSplit(const SubdParams &params_) : params(params_)
{
- subpatches_quad.push_back(sub);
- edgefactors_quad.push_back(ef);
}
float3 DiagSplit::to_world(Patch *patch, float2 uv)
@@ -49,45 +50,62 @@ float3 DiagSplit::to_world(Patch *patch, float2 uv)
return P;
}
-int DiagSplit::T(Patch *patch, float2 Pstart, float2 Pend)
+static void order_float2(float2 &a, float2 &b)
{
- float3 Plast = make_float3(0.0f, 0.0f, 0.0f);
+ if (b.x < a.x || b.y < a.y) {
+ swap(a, b);
+ }
+}
+
+int DiagSplit::T(Patch *patch, float2 Pstart, float2 Pend, bool recursive_resolve)
+{
+ order_float2(Pstart, Pend); /* May not be necessary, but better to be safe. */
+
float Lsum = 0.0f;
float Lmax = 0.0f;
- for (int i = 0; i < params.test_steps; i++) {
+ float3 Plast = to_world(patch, Pstart);
+
+ for (int i = 1; i < params.test_steps; i++) {
float t = i / (float)(params.test_steps - 1);
float3 P = to_world(patch, Pstart + t * (Pend - Pstart));
- if (i > 0) {
- float L;
+ float L;
- if (!params.camera) {
- L = len(P - Plast);
- }
- else {
- Camera *cam = params.camera;
-
- float pixel_width = cam->world_to_raster_size((P + Plast) * 0.5f);
- L = len(P - Plast) / pixel_width;
- }
+ if (!params.camera) {
+ L = len(P - Plast);
+ }
+ else {
+ Camera *cam = params.camera;
- Lsum += L;
- Lmax = max(L, Lmax);
+ float pixel_width = cam->world_to_raster_size((P + Plast) * 0.5f);
+ L = len(P - Plast) / pixel_width;
}
+ Lsum += L;
+ Lmax = max(L, Lmax);
+
Plast = P;
}
int tmin = (int)ceilf(Lsum / params.dicing_rate);
int tmax = (int)ceilf((params.test_steps - 1) * Lmax /
params.dicing_rate); // XXX paper says N instead of N-1, seems wrong?
+ int res = max(tmax, 1);
- if (tmax - tmin > params.split_threshold)
- return DSPLIT_NON_UNIFORM;
+ if (tmax - tmin > params.split_threshold) {
+ if (!recursive_resolve) {
+ res = DSPLIT_NON_UNIFORM;
+ }
+ else {
+ float2 P = (Pstart + Pend) * 0.5f;
+ res = T(patch, Pstart, P, true) + T(patch, P, Pend, true);
+ }
+ }
- return tmax;
+ limit_edge_factor(res, patch, Pstart, Pend);
+ return res;
}
void DiagSplit::partition_edge(
@@ -99,159 +117,632 @@ void DiagSplit::partition_edge(
*t1 = T(patch, *P, Pend);
}
else {
+ assert(t >= 2); /* Need at least two segments to partition into. */
+
int I = (int)floorf((float)t * 0.5f);
- *P = interp(Pstart, Pend, (t == 0) ? 0 : I / (float)t); /* XXX is t faces or verts */
+ *P = interp(Pstart, Pend, I / (float)t);
*t0 = I;
*t1 = t - I;
}
}
-static void limit_edge_factors(const QuadDice::SubPatch &sub, QuadDice::EdgeFactors &ef, int max_t)
+void DiagSplit::limit_edge_factor(int &T, Patch *patch, float2 Pstart, float2 Pend)
+{
+ int max_t = 1 << params.max_level;
+ int max_t_for_edge = int(max_t * len(Pstart - Pend));
+
+ if (patch->from_ngon) {
+ max_t_for_edge >>= 1; /* Initial split of ngon causes edges to extend half the distance. */
+ }
+
+ T = (max_t_for_edge <= 1) ? 1 : min(T, max_t_for_edge);
+
+ assert(T >= 1 || T == DSPLIT_NON_UNIFORM);
+}
+
+void DiagSplit::resolve_edge_factors(Subpatch &sub)
{
- float2 P00 = sub.P00;
- float2 P01 = sub.P01;
- float2 P10 = sub.P10;
- float2 P11 = sub.P11;
-
- int tu0 = int(max_t * len(P10 - P00));
- int tu1 = int(max_t * len(P11 - P01));
- int tv0 = int(max_t * len(P01 - P00));
- int tv1 = int(max_t * len(P11 - P10));
-
- ef.tu0 = tu0 <= 1 ? 1 : min(ef.tu0, tu0);
- ef.tu1 = tu1 <= 1 ? 1 : min(ef.tu1, tu1);
- ef.tv0 = tv0 <= 1 ? 1 : min(ef.tv0, tv0);
- ef.tv1 = tv1 <= 1 ? 1 : min(ef.tv1, tv1);
+ /* Resolve DSPLIT_NON_UNIFORM to actual T value if splitting is no longer possible. */
+ if (sub.edge_u0.T == 1 && sub.edge_u1.T == DSPLIT_NON_UNIFORM) {
+ sub.edge_u1.T = T(sub.patch, sub.c01, sub.c11, true);
+ }
+ if (sub.edge_u1.T == 1 && sub.edge_u0.T == DSPLIT_NON_UNIFORM) {
+ sub.edge_u0.T = T(sub.patch, sub.c00, sub.c10, true);
+ }
+ if (sub.edge_v0.T == 1 && sub.edge_v1.T == DSPLIT_NON_UNIFORM) {
+ sub.edge_v1.T = T(sub.patch, sub.c11, sub.c10, true);
+ }
+ if (sub.edge_v1.T == 1 && sub.edge_v0.T == DSPLIT_NON_UNIFORM) {
+ sub.edge_v0.T = T(sub.patch, sub.c01, sub.c00, true);
+ }
}
-void DiagSplit::split(QuadDice::SubPatch &sub, QuadDice::EdgeFactors &ef, int depth)
+void DiagSplit::split(Subpatch &sub, int depth)
{
if (depth > 32) {
/* We should never get here, but just in case end recursion safely. */
- ef.tu0 = 1;
- ef.tu1 = 1;
- ef.tv0 = 1;
- ef.tv1 = 1;
+ assert(!"diagsplit recursion limit reached");
+
+ sub.edge_u0.T = 1;
+ sub.edge_u1.T = 1;
+ sub.edge_v0.T = 1;
+ sub.edge_v1.T = 1;
- dispatch(sub, ef);
+ subpatches.push_back(sub);
return;
}
- bool split_u = (ef.tu0 == DSPLIT_NON_UNIFORM || ef.tu1 == DSPLIT_NON_UNIFORM);
- bool split_v = (ef.tv0 == DSPLIT_NON_UNIFORM || ef.tv1 == DSPLIT_NON_UNIFORM);
+ bool split_u = (sub.edge_u0.T == DSPLIT_NON_UNIFORM || sub.edge_u1.T == DSPLIT_NON_UNIFORM);
+ bool split_v = (sub.edge_v0.T == DSPLIT_NON_UNIFORM || sub.edge_v1.T == DSPLIT_NON_UNIFORM);
/* Split subpatches such that the ratio of T for opposite edges doesn't
* exceed 1.5, this reduces over tessellation for some patches
*/
- bool tmp_split_v = split_v;
- if (!split_u && min(ef.tu0, ef.tu1) > 8 && min(ef.tu0, ef.tu1) * 1.5f < max(ef.tu0, ef.tu1))
+ /* clang-format off */
+ if (min(sub.edge_u0.T, sub.edge_u1.T) > 8 && /* Must be uniform and preferably greater than 8 to split. */
+ min(sub.edge_v0.T, sub.edge_v1.T) >= 2 && /* Must be uniform and at least 2 to split. */
+ max(sub.edge_u0.T, sub.edge_u1.T) / min(sub.edge_u0.T, sub.edge_u1.T) > 1.5f)
+ {
split_v = true;
- if (!tmp_split_v && min(ef.tu0, ef.tu1) > 8 && min(ef.tv0, ef.tv1) * 1.5f < max(ef.tv0, ef.tv1))
+ }
+ if (min(sub.edge_v0.T, sub.edge_v1.T) > 8 &&
+ min(sub.edge_u0.T, sub.edge_u1.T) >= 2 &&
+ max(sub.edge_v0.T, sub.edge_v1.T) / min(sub.edge_v0.T, sub.edge_v1.T) > 1.5f)
+ {
split_u = true;
+ }
+ /* clang-format on */
- /* alternate axis */
+ /* Alternate axis. */
if (split_u && split_v) {
split_u = depth % 2;
}
- if (split_u) {
- /* partition edges */
- QuadDice::EdgeFactors ef0, ef1;
- float2 Pu0, Pu1;
+ if (!split_u && !split_v) {
+ /* Add the unsplit subpatch. */
+ subpatches.push_back(sub);
+ Subpatch &subpatch = subpatches[subpatches.size() - 1];
+
+ /* Update T values and offsets. */
+ for (int i = 0; i < 4; i++) {
+ Subpatch::edge_t &edge = subpatch.edges[i];
+
+ edge.offset = edge.edge->T;
+ edge.edge->T += edge.T;
+ }
+ }
+ else {
+ /* Copy into new subpatches. */
+ Subpatch sub_a = sub;
+ Subpatch sub_b = sub;
+
+ /* Pointers to various subpatch elements. */
+ Subpatch::edge_t *sub_across_0, *sub_across_1;
+ Subpatch::edge_t *sub_a_across_0, *sub_a_across_1;
+ Subpatch::edge_t *sub_b_across_0, *sub_b_across_1;
+
+ Subpatch::edge_t *sub_a_split, *sub_b_split;
+
+ float2 *Pa, *Pb, *Pc, *Pd;
+
+ /* Set pointers based on split axis. */
+ if (split_u) {
+ sub_across_0 = &sub.edge_u0;
+ sub_across_1 = &sub.edge_u1;
+ sub_a_across_0 = &sub_a.edge_u0;
+ sub_a_across_1 = &sub_a.edge_u1;
+ sub_b_across_0 = &sub_b.edge_u0;
+ sub_b_across_1 = &sub_b.edge_u1;
+
+ sub_a_split = &sub_a.edge_v1;
+ sub_b_split = &sub_b.edge_v0;
+
+ Pa = &sub_a.c11;
+ Pb = &sub_a.c10;
+ Pc = &sub_b.c01;
+ Pd = &sub_b.c00;
+ }
+ else {
+ sub_across_0 = &sub.edge_v0;
+ sub_across_1 = &sub.edge_v1;
+ sub_a_across_0 = &sub_a.edge_v0;
+ sub_a_across_1 = &sub_a.edge_v1;
+ sub_b_across_0 = &sub_b.edge_v0;
+ sub_b_across_1 = &sub_b.edge_v1;
+
+ sub_a_split = &sub_a.edge_u0;
+ sub_b_split = &sub_b.edge_u1;
+
+ Pa = &sub_a.c10;
+ Pb = &sub_a.c00;
+ Pc = &sub_b.c11;
+ Pd = &sub_b.c01;
+ }
- partition_edge(sub.patch, &Pu0, &ef0.tu0, &ef1.tu0, sub.P00, sub.P10, ef.tu0);
- partition_edge(sub.patch, &Pu1, &ef0.tu1, &ef1.tu1, sub.P01, sub.P11, ef.tu1);
+ /* Partition edges */
+ float2 P0, P1;
- /* split */
- int tsplit = T(sub.patch, Pu0, Pu1);
- ef0.tv0 = ef.tv0;
- ef0.tv1 = tsplit;
+ partition_edge(
+ sub.patch, &P0, &sub_a_across_0->T, &sub_b_across_0->T, *Pd, *Pb, sub_across_0->T);
+ partition_edge(
+ sub.patch, &P1, &sub_a_across_1->T, &sub_b_across_1->T, *Pc, *Pa, sub_across_1->T);
- ef1.tv0 = tsplit;
- ef1.tv1 = ef.tv1;
+ /* Split */
+ *Pa = P1;
+ *Pb = P0;
- /* create subpatches */
- QuadDice::SubPatch sub0 = {sub.patch, sub.P00, Pu0, sub.P01, Pu1};
- QuadDice::SubPatch sub1 = {sub.patch, Pu0, sub.P10, Pu1, sub.P11};
+ *Pc = P1;
+ *Pd = P0;
- limit_edge_factors(sub0, ef0, 1 << params.max_level);
- limit_edge_factors(sub1, ef1, 1 << params.max_level);
+ int tsplit = T(sub.patch, P0, P1);
- split(sub0, ef0, depth + 1);
- split(sub1, ef1, depth + 1);
+ if (depth == -2 && tsplit == 1) {
+ tsplit = 2; /* Ensure we can always split at depth -1. */
+ }
+
+ sub_a_split->T = tsplit;
+ sub_b_split->T = tsplit;
+
+ resolve_edge_factors(sub_a);
+ resolve_edge_factors(sub_b);
+
+ /* Create new edge */
+ Edge &edge = *alloc_edge();
+
+ sub_a_split->edge = &edge;
+ sub_b_split->edge = &edge;
+
+ sub_a_split->offset = 0;
+ sub_b_split->offset = 0;
+
+ sub_a_split->indices_decrease_along_edge = false;
+ sub_b_split->indices_decrease_along_edge = true;
+
+ sub_a_split->sub_edges_created_in_reverse_order = !split_u;
+ sub_b_split->sub_edges_created_in_reverse_order = !split_u;
+
+ edge.top_indices_decrease = sub_across_1->sub_edges_created_in_reverse_order;
+ edge.bottom_indices_decrease = sub_across_0->sub_edges_created_in_reverse_order;
+
+ /* Recurse */
+ edge.T = 0;
+ split(sub_a, depth + 1);
+
+ int edge_t = edge.T;
+ (void)edge_t;
+
+ edge.top_offset = sub_across_1->edge->T;
+ edge.bottom_offset = sub_across_0->edge->T;
+
+ edge.T = 0; /* We calculate T twice along each edge. :/ */
+ split(sub_b, depth + 1);
+
+ assert(edge.T == edge_t); /* If this fails we will crash at some later point! */
+
+ edge.top = sub_across_1->edge;
+ edge.bottom = sub_across_0->edge;
}
- else if (split_v) {
- /* partition edges */
- QuadDice::EdgeFactors ef0, ef1;
- float2 Pv0, Pv1;
+}
+
+int DiagSplit::alloc_verts(int n)
+{
+ int a = num_alloced_verts;
+ num_alloced_verts += n;
+ return a;
+}
- partition_edge(sub.patch, &Pv0, &ef0.tv0, &ef1.tv0, sub.P00, sub.P01, ef.tv0);
- partition_edge(sub.patch, &Pv1, &ef0.tv1, &ef1.tv1, sub.P10, sub.P11, ef.tv1);
+Edge *DiagSplit::alloc_edge()
+{
+ edges.emplace_back();
+ return &edges.back();
+}
- /* split */
- int tsplit = T(sub.patch, Pv0, Pv1);
- ef0.tu0 = ef.tu0;
- ef0.tu1 = tsplit;
+void DiagSplit::split_patches(Patch *patches, size_t patches_byte_stride)
+{
+ int patch_index = 0;
- ef1.tu0 = tsplit;
- ef1.tu1 = ef.tu1;
+ for (int f = 0; f < params.mesh->subd_faces.size(); f++) {
+ Mesh::SubdFace &face = params.mesh->subd_faces[f];
- /* create subpatches */
- QuadDice::SubPatch sub0 = {sub.patch, sub.P00, sub.P10, Pv0, Pv1};
- QuadDice::SubPatch sub1 = {sub.patch, Pv0, Pv1, sub.P01, sub.P11};
+ Patch *patch = (Patch *)(((char *)patches) + patch_index * patches_byte_stride);
- limit_edge_factors(sub0, ef0, 1 << params.max_level);
- limit_edge_factors(sub1, ef1, 1 << params.max_level);
+ if (face.is_quad()) {
+ patch_index++;
- split(sub0, ef0, depth + 1);
- split(sub1, ef1, depth + 1);
+ split_quad(face, patch);
+ }
+ else {
+ patch_index += face.num_corners;
+
+ split_ngon(face, patch, patches_byte_stride);
+ }
}
- else {
- dispatch(sub, ef);
+
+ params.mesh->vert_to_stitching_key_map.clear();
+ params.mesh->vert_stitching_map.clear();
+
+ post_split();
+}
+
+static Edge *create_edge_from_corner(DiagSplit *split,
+ const Mesh *mesh,
+ const Mesh::SubdFace &face,
+ int corner,
+ bool &reversed,
+ int v0,
+ int v1)
+{
+ int a = mesh->subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)];
+ int b = mesh->subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)];
+
+ reversed = !(b < a);
+
+ if (b < a) {
+ swap(a, b);
+ swap(v0, v1);
}
+
+ Edge *edge = split->alloc_edge();
+
+ edge->is_stitch_edge = true;
+ edge->stitch_start_vert_index = a;
+ edge->stitch_end_vert_index = b;
+
+ edge->start_vert_index = v0;
+ edge->end_vert_index = v1;
+
+ edge->stitch_edge_key = {a, b};
+
+ return edge;
}
-void DiagSplit::split_quad(Patch *patch, QuadDice::SubPatch *subpatch)
+void DiagSplit::split_quad(const Mesh::SubdFace &face, Patch *patch)
{
- QuadDice::SubPatch sub_split;
- QuadDice::EdgeFactors ef_split;
+ Subpatch subpatch(patch);
+
+ int v = alloc_verts(4);
+
+ bool v0_reversed, u1_reversed, v1_reversed, u0_reversed;
+ subpatch.edge_v0.edge = create_edge_from_corner(
+ this, params.mesh, face, 3, v0_reversed, v + 3, v + 0);
+ subpatch.edge_u1.edge = create_edge_from_corner(
+ this, params.mesh, face, 2, u1_reversed, v + 2, v + 3);
+ subpatch.edge_v1.edge = create_edge_from_corner(
+ this, params.mesh, face, 1, v1_reversed, v + 1, v + 2);
+ subpatch.edge_u0.edge = create_edge_from_corner(
+ this, params.mesh, face, 0, u0_reversed, v + 0, v + 1);
+
+ subpatch.edge_v0.sub_edges_created_in_reverse_order = !v0_reversed;
+ subpatch.edge_u1.sub_edges_created_in_reverse_order = u1_reversed;
+ subpatch.edge_v1.sub_edges_created_in_reverse_order = v1_reversed;
+ subpatch.edge_u0.sub_edges_created_in_reverse_order = !u0_reversed;
+
+ subpatch.edge_v0.indices_decrease_along_edge = v0_reversed;
+ subpatch.edge_u1.indices_decrease_along_edge = u1_reversed;
+ subpatch.edge_v1.indices_decrease_along_edge = v1_reversed;
+ subpatch.edge_u0.indices_decrease_along_edge = u0_reversed;
+
+ /* Forces a split in both axis for quads, needed to match split of ngons into quads. */
+ subpatch.edge_u0.T = DSPLIT_NON_UNIFORM;
+ subpatch.edge_u1.T = DSPLIT_NON_UNIFORM;
+ subpatch.edge_v0.T = DSPLIT_NON_UNIFORM;
+ subpatch.edge_v1.T = DSPLIT_NON_UNIFORM;
+
+ split(subpatch, -2);
+}
+
+static Edge *create_split_edge_from_corner(DiagSplit *split,
+ const Mesh *mesh,
+ const Mesh::SubdFace &face,
+ int corner,
+ int side,
+ bool &reversed,
+ int v0,
+ int v1,
+ int vc)
+{
+ Edge *edge = split->alloc_edge();
+
+ int a = mesh->subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)];
+ int b = mesh->subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)];
- if (subpatch) {
- sub_split = *subpatch;
+ if (b < a) {
+ edge->stitch_edge_key = {b, a};
}
else {
- sub_split.patch = patch;
- sub_split.P00 = make_float2(0.0f, 0.0f);
- sub_split.P10 = make_float2(1.0f, 0.0f);
- sub_split.P01 = make_float2(0.0f, 1.0f);
- sub_split.P11 = make_float2(1.0f, 1.0f);
+ edge->stitch_edge_key = {a, b};
}
- ef_split.tu0 = T(patch, sub_split.P00, sub_split.P10);
- ef_split.tu1 = T(patch, sub_split.P01, sub_split.P11);
- ef_split.tv0 = T(patch, sub_split.P00, sub_split.P01);
- ef_split.tv1 = T(patch, sub_split.P10, sub_split.P11);
+ reversed = !(b < a);
- limit_edge_factors(sub_split, ef_split, 1 << params.max_level);
+ if (side == 0) {
+ a = vc;
+ }
+ else {
+ b = vc;
+ }
+
+ if (!reversed) {
+ swap(a, b);
+ swap(v0, v1);
+ }
+
+ edge->is_stitch_edge = true;
+ edge->stitch_start_vert_index = a;
+ edge->stitch_end_vert_index = b;
+
+ edge->start_vert_index = v0;
+ edge->end_vert_index = v1;
+
+ return edge;
+}
+
+void DiagSplit::split_ngon(const Mesh::SubdFace &face, Patch *patches, size_t patches_byte_stride)
+{
+ Edge *prev_edge_u0 = nullptr;
+ Edge *first_edge_v0 = nullptr;
+
+ for (int corner = 0; corner < face.num_corners; corner++) {
+ Patch *patch = (Patch *)(((char *)patches) + corner * patches_byte_stride);
+
+ Subpatch subpatch(patch);
+
+ int v = alloc_verts(4);
+
+ /* Setup edges. */
+ Edge *edge_u1 = alloc_edge();
+ Edge *edge_v1 = alloc_edge();
+
+ edge_v1->is_stitch_edge = true;
+ edge_u1->is_stitch_edge = true;
+
+ edge_u1->stitch_start_vert_index = -(face.start_corner + mod(corner + 0, face.num_corners)) -
+ 1;
+ edge_u1->stitch_end_vert_index = STITCH_NGON_CENTER_VERT_INDEX_OFFSET + face.ptex_offset;
+
+ edge_u1->start_vert_index = v + 3;
+ edge_u1->end_vert_index = v + 2;
+
+ edge_u1->stitch_edge_key = {edge_u1->stitch_start_vert_index, edge_u1->stitch_end_vert_index};
+
+ edge_v1->stitch_start_vert_index = -(face.start_corner + mod(corner + 1, face.num_corners)) -
+ 1;
+ edge_v1->stitch_end_vert_index = STITCH_NGON_CENTER_VERT_INDEX_OFFSET + face.ptex_offset;
+
+ edge_v1->start_vert_index = v + 1;
+ edge_v1->end_vert_index = v + 2;
+
+ edge_v1->stitch_edge_key = {edge_v1->stitch_start_vert_index, edge_v1->stitch_end_vert_index};
+
+ bool v0_reversed, u0_reversed;
+
+ subpatch.edge_v0.edge = create_split_edge_from_corner(this,
+ params.mesh,
+ face,
+ corner - 1,
+ 0,
+ v0_reversed,
+ v + 3,
+ v + 0,
+ STITCH_NGON_SPLIT_EDGE_CENTER_VERT_TAG);
+
+ subpatch.edge_u1.edge = edge_u1;
+ subpatch.edge_v1.edge = edge_v1;
+
+ subpatch.edge_u0.edge = create_split_edge_from_corner(this,
+ params.mesh,
+ face,
+ corner + 0,
+ 1,
+ u0_reversed,
+ v + 0,
+ v + 1,
+ STITCH_NGON_SPLIT_EDGE_CENTER_VERT_TAG);
+
+ subpatch.edge_v0.sub_edges_created_in_reverse_order = !v0_reversed;
+ subpatch.edge_u1.sub_edges_created_in_reverse_order = false;
+ subpatch.edge_v1.sub_edges_created_in_reverse_order = true;
+ subpatch.edge_u0.sub_edges_created_in_reverse_order = !u0_reversed;
+
+ subpatch.edge_v0.indices_decrease_along_edge = v0_reversed;
+ subpatch.edge_u1.indices_decrease_along_edge = false;
+ subpatch.edge_v1.indices_decrease_along_edge = true;
+ subpatch.edge_u0.indices_decrease_along_edge = u0_reversed;
+
+ /* Perfrom split. */
+ {
+ subpatch.edge_u0.T = T(subpatch.patch, subpatch.c00, subpatch.c10);
+ subpatch.edge_u1.T = T(subpatch.patch, subpatch.c01, subpatch.c11);
+ subpatch.edge_v0.T = T(subpatch.patch, subpatch.c00, subpatch.c01);
+ subpatch.edge_v1.T = T(subpatch.patch, subpatch.c10, subpatch.c11);
+
+ resolve_edge_factors(subpatch);
+
+ split(subpatch, 0);
+ }
+
+ /* Update offsets after T is known from split. */
+ edge_u1->top = subpatch.edge_v0.edge;
+ edge_u1->stitch_top_offset = edge_u1->top->T * (v0_reversed ? -1 : 1);
+ edge_v1->top = subpatch.edge_u0.edge;
+ edge_v1->stitch_top_offset = edge_v1->top->T * (!u0_reversed ? -1 : 1);
+
+ if (corner == 0) {
+ first_edge_v0 = subpatch.edge_v0.edge;
+ }
+
+ if (prev_edge_u0) {
+ if (v0_reversed) {
+ subpatch.edge_v0.edge->stitch_offset = prev_edge_u0->T;
+ }
+ else {
+ prev_edge_u0->stitch_offset = subpatch.edge_v0.edge->T;
+ }
+
+ int T = subpatch.edge_v0.edge->T + prev_edge_u0->T;
+ subpatch.edge_v0.edge->stitch_edge_T = T;
+ prev_edge_u0->stitch_edge_T = T;
+ }
- split(sub_split, ef_split);
+ if (corner == face.num_corners - 1) {
+ if (v0_reversed) {
+ subpatch.edge_u0.edge->stitch_offset = first_edge_v0->T;
+ }
+ else {
+ first_edge_v0->stitch_offset = subpatch.edge_u0.edge->T;
+ }
+
+ int T = first_edge_v0->T + subpatch.edge_u0.edge->T;
+ first_edge_v0->stitch_edge_T = T;
+ subpatch.edge_u0.edge->stitch_edge_T = T;
+ }
+
+ prev_edge_u0 = subpatch.edge_u0.edge;
+ }
+}
+
+void DiagSplit::post_split()
+{
+ int num_stitch_verts = 0;
+
+ /* All patches are now split, and all T values known. */
+ foreach (Edge &edge, edges) {
+ if (edge.second_vert_index < 0) {
+ edge.second_vert_index = alloc_verts(edge.T - 1);
+ }
+
+ if (edge.is_stitch_edge) {
+ num_stitch_verts = max(num_stitch_verts,
+ max(edge.stitch_start_vert_index, edge.stitch_end_vert_index));
+ }
+ }
+
+ num_stitch_verts += 1;
+
+ /* Map of edge key to edge stitching vert offset. */
+ struct pair_hasher {
+ size_t operator()(const pair<int, int> &k) const
+ {
+ return hash_uint2(k.first, k.second);
+ }
+ };
+ typedef unordered_map<pair<int, int>, int, pair_hasher> edge_stitch_verts_map_t;
+ edge_stitch_verts_map_t edge_stitch_verts_map;
+
+ foreach (Edge &edge, edges) {
+ if (edge.is_stitch_edge) {
+ if (edge.stitch_edge_T == 0) {
+ edge.stitch_edge_T = edge.T;
+ }
+
+ if (edge_stitch_verts_map.find(edge.stitch_edge_key) == edge_stitch_verts_map.end()) {
+ edge_stitch_verts_map[edge.stitch_edge_key] = num_stitch_verts;
+ num_stitch_verts += edge.stitch_edge_T - 1;
+ }
+ }
+ }
+
+ /* Set start and end indices for edges generated from a split. */
+ foreach (Edge &edge, edges) {
+ if (edge.start_vert_index < 0) {
+ /* Fixup offsets. */
+ if (edge.top_indices_decrease) {
+ edge.top_offset = edge.top->T - edge.top_offset;
+ }
+
+ edge.start_vert_index = edge.top->get_vert_along_edge(edge.top_offset);
+ }
+
+ if (edge.end_vert_index < 0) {
+ if (edge.bottom_indices_decrease) {
+ edge.bottom_offset = edge.bottom->T - edge.bottom_offset;
+ }
+
+ edge.end_vert_index = edge.bottom->get_vert_along_edge(edge.bottom_offset);
+ }
+ }
+
+ int vert_offset = params.mesh->verts.size();
+
+ /* Add verts to stitching map. */
+ foreach (const Edge &edge, edges) {
+ if (edge.is_stitch_edge) {
+ int second_stitch_vert_index = edge_stitch_verts_map[edge.stitch_edge_key];
+
+ for (int i = 0; i <= edge.T; i++) {
+ /* Get proper stitching key. */
+ int key;
+
+ if (i == 0) {
+ key = edge.stitch_start_vert_index;
+ }
+ else if (i == edge.T) {
+ key = edge.stitch_end_vert_index;
+ }
+ else {
+ key = second_stitch_vert_index + i - 1 + edge.stitch_offset;
+ }
+
+ if (key == STITCH_NGON_SPLIT_EDGE_CENTER_VERT_TAG) {
+ if (i == 0) {
+ key = second_stitch_vert_index - 1 + edge.stitch_offset;
+ }
+ else if (i == edge.T) {
+ key = second_stitch_vert_index - 1 + edge.T;
+ }
+ }
+ else if (key < 0 && edge.top) { /* ngon spoke edge */
+ int s = edge_stitch_verts_map[edge.top->stitch_edge_key];
+ if (edge.stitch_top_offset >= 0) {
+ key = s - 1 + edge.stitch_top_offset;
+ }
+ else {
+ key = s - 1 + edge.top->stitch_edge_T + edge.stitch_top_offset;
+ }
+ }
+
+ /* Get real vert index. */
+ int vert = edge.get_vert_along_edge(i) + vert_offset;
+
+ /* Add to map */
+ if (params.mesh->vert_to_stitching_key_map.find(vert) ==
+ params.mesh->vert_to_stitching_key_map.end()) {
+ params.mesh->vert_to_stitching_key_map[vert] = key;
+ params.mesh->vert_stitching_map.insert({key, vert});
+ }
+ }
+ }
+ }
+
+ /* Dice; TODO(mai): Move this out of split. */
QuadDice dice(params);
- for (size_t i = 0; i < subpatches_quad.size(); i++) {
- QuadDice::SubPatch &sub = subpatches_quad[i];
- QuadDice::EdgeFactors &ef = edgefactors_quad[i];
+ int num_verts = num_alloced_verts;
+ int num_triangles = 0;
+
+ for (size_t i = 0; i < subpatches.size(); i++) {
+ subpatches[i].inner_grid_vert_offset = num_verts;
+ num_verts += subpatches[i].calc_num_inner_verts();
+ num_triangles += subpatches[i].calc_num_triangles();
+ }
+
+ dice.reserve(num_verts, num_triangles);
+
+ for (size_t i = 0; i < subpatches.size(); i++) {
+ Subpatch &sub = subpatches[i];
- ef.tu0 = max(ef.tu0, 1);
- ef.tu1 = max(ef.tu1, 1);
- ef.tv0 = max(ef.tv0, 1);
- ef.tv1 = max(ef.tv1, 1);
+ sub.edge_u0.T = max(sub.edge_u0.T, 1);
+ sub.edge_u1.T = max(sub.edge_u1.T, 1);
+ sub.edge_v0.T = max(sub.edge_v0.T, 1);
+ sub.edge_v1.T = max(sub.edge_v1.T, 1);
- dice.dice(sub, ef);
+ dice.dice(sub);
}
- subpatches_quad.clear();
- edgefactors_quad.clear();
+ /* Cleanup */
+ subpatches.clear();
+ edges.clear();
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/subd/subd_split.h b/intern/cycles/subd/subd_split.h
index 6e68d8ee598..773f4ddf120 100644
--- a/intern/cycles/subd/subd_split.h
+++ b/intern/cycles/subd/subd_split.h
@@ -23,35 +23,51 @@
* for more details. */
#include "subd/subd_dice.h"
+#include "subd/subd_subpatch.h"
+#include "util/util_deque.h"
#include "util/util_types.h"
#include "util/util_vector.h"
+#include <deque>
+
CCL_NAMESPACE_BEGIN
class Mesh;
class Patch;
-#define DSPLIT_NON_UNIFORM -1
-
class DiagSplit {
- public:
- vector<QuadDice::SubPatch> subpatches_quad;
- vector<QuadDice::EdgeFactors> edgefactors_quad;
-
SubdParams params;
- explicit DiagSplit(const SubdParams &params);
+ vector<Subpatch> subpatches;
+ /* deque is used so that element pointers remain vaild when size is changed. */
+ deque<Edge> edges;
float3 to_world(Patch *patch, float2 uv);
- int T(Patch *patch, float2 Pstart, float2 Pend);
+ int T(Patch *patch, float2 Pstart, float2 Pend, bool recursive_resolve = false);
+
+ void limit_edge_factor(int &T, Patch *patch, float2 Pstart, float2 Pend);
+ void resolve_edge_factors(Subpatch &sub);
+
void partition_edge(
Patch *patch, float2 *P, int *t0, int *t1, float2 Pstart, float2 Pend, int t);
- void dispatch(QuadDice::SubPatch &sub, QuadDice::EdgeFactors &ef);
- void split(QuadDice::SubPatch &sub, QuadDice::EdgeFactors &ef, int depth = 0);
+ void split(Subpatch &sub, int depth = 0);
+
+ int num_alloced_verts = 0;
+ int alloc_verts(int n); /* Returns start index of new verts. */
+
+ public:
+ Edge *alloc_edge();
+
+ explicit DiagSplit(const SubdParams &params);
+
+ void split_patches(Patch *patches, size_t patches_byte_stride);
+
+ void split_quad(const Mesh::SubdFace &face, Patch *patch);
+ void split_ngon(const Mesh::SubdFace &face, Patch *patches, size_t patches_byte_stride);
- void split_quad(Patch *patch, QuadDice::SubPatch *subpatch = NULL);
+ void post_split();
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/subd/subd_subpatch.h b/intern/cycles/subd/subd_subpatch.h
new file mode 100644
index 00000000000..1a32b763cb8
--- /dev/null
+++ b/intern/cycles/subd/subd_subpatch.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * 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.
+ */
+
+#ifndef __SUBD_SUBPATCH_H__
+#define __SUBD_SUBPATCH_H__
+
+#include "util/util_map.h"
+#include "util/util_types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Subpatch */
+
+class Subpatch {
+ public:
+ class Patch *patch; /* Patch this is a subpatch of. */
+ int inner_grid_vert_offset;
+
+ struct edge_t {
+ int T;
+ int offset; /* Offset along main edge, interpretation depends on the two flags below. */
+
+ bool indices_decrease_along_edge;
+ bool sub_edges_created_in_reverse_order;
+
+ struct Edge *edge;
+
+ int get_vert_along_edge(int n) const;
+ };
+
+ /*
+ * eu1
+ * c01 --------- c11
+ * | |
+ * ev0 | | ev1
+ * | |
+ * c00 --------- c10
+ * eu0
+ */
+
+ union {
+ float2 corners[4]; /* UV within patch, clockwise starting from uv (0, 0) towards (0, 1) etc. */
+ struct {
+ float2 c00, c01, c11, c10;
+ };
+ };
+
+ union {
+ edge_t
+ edges[4]; /* Edges of this subpatch, each edge starts at the corner of the same index. */
+ struct {
+ edge_t edge_v0, edge_u1, edge_v1, edge_u0;
+ };
+ };
+
+ explicit Subpatch(Patch *patch = nullptr)
+ : patch(patch),
+ c00(make_float2(0.0f, 0.0f)),
+ c01(make_float2(0.0f, 1.0f)),
+ c11(make_float2(1.0f, 1.0f)),
+ c10(make_float2(1.0f, 0.0f))
+ {
+ }
+
+ Subpatch(Patch *patch, float2 c00, float2 c01, float2 c11, float2 c10)
+ : patch(patch), c00(c00), c01(c01), c11(c11), c10(c10)
+ {
+ }
+
+ int calc_num_inner_verts() const
+ {
+ int Mu = max(edge_u0.T, edge_u1.T);
+ int Mv = max(edge_v0.T, edge_v1.T);
+ Mu = max(Mu, 2);
+ Mv = max(Mv, 2);
+ return (Mu - 1) * (Mv - 1);
+ }
+
+ int calc_num_triangles() const
+ {
+ int Mu = max(edge_u0.T, edge_u1.T);
+ int Mv = max(edge_v0.T, edge_v1.T);
+ Mu = max(Mu, 2);
+ Mv = max(Mv, 2);
+
+ int inner_triangles = (Mu - 2) * (Mv - 2) * 2;
+ int edge_triangles = edge_u0.T + edge_u1.T + edge_v0.T + edge_v1.T + (Mu - 2) * 2 +
+ (Mv - 2) * 2;
+
+ return inner_triangles + edge_triangles;
+ }
+
+ int get_vert_along_edge(int e, int n) const;
+
+ int get_vert_along_grid_edge(int edge, int n) const
+ {
+ int Mu = max(edge_u0.T, edge_u1.T);
+ int Mv = max(edge_v0.T, edge_v1.T);
+ Mu = max(Mu, 2);
+ Mv = max(Mv, 2);
+
+ switch (edge) {
+ case 0:
+ return inner_grid_vert_offset + n * (Mu - 1);
+ case 1:
+ return inner_grid_vert_offset + (Mu - 1) * (Mv - 2) + n;
+ case 2:
+ return inner_grid_vert_offset + ((Mu - 1) * (Mv - 1) - 1) - n * (Mu - 1);
+ case 3:
+ return inner_grid_vert_offset + (Mu - 2) - n;
+ }
+
+ return -1;
+ }
+};
+
+struct Edge {
+ /* Number of segments the edge will be diced into, see DiagSplit paper. */
+ int T;
+
+ /* top is edge adjacent to start, bottom is adjacent to end. */
+ Edge *top, *bottom;
+
+ int top_offset, bottom_offset;
+ bool top_indices_decrease, bottom_indices_decrease;
+
+ int start_vert_index;
+ int end_vert_index;
+
+ /* Index of the second vert from this edges corner along the edge towards the next corner. */
+ int second_vert_index;
+
+ /* Vertices on edge are to be stitched. */
+ bool is_stitch_edge;
+
+ /* Key to match this edge with others to be stitched with.
+ * The ints in the pair are ordered stitching indices */
+ pair<int, int> stitch_edge_key;
+
+ /* Full T along edge (may be larger than T for edges split from ngon edges) */
+ int stitch_edge_T;
+ int stitch_offset;
+ int stitch_top_offset;
+ int stitch_start_vert_index;
+ int stitch_end_vert_index;
+
+ Edge()
+ : T(0),
+ top(nullptr),
+ bottom(nullptr),
+ top_offset(-1),
+ bottom_offset(-1),
+ top_indices_decrease(false),
+ bottom_indices_decrease(false),
+ start_vert_index(-1),
+ end_vert_index(-1),
+ second_vert_index(-1),
+ is_stitch_edge(false),
+ stitch_edge_T(0),
+ stitch_offset(0)
+ {
+ }
+
+ int get_vert_along_edge(int n) const
+ {
+ assert(n >= 0 && n <= T);
+
+ if (n == 0) {
+ return start_vert_index;
+ }
+ else if (n == T) {
+ return end_vert_index;
+ }
+
+ return second_vert_index + n - 1;
+ }
+};
+
+inline int Subpatch::edge_t::get_vert_along_edge(int n) const
+{
+ assert(n >= 0 && n <= T);
+
+ if (!indices_decrease_along_edge && !sub_edges_created_in_reverse_order) {
+ n = offset + n;
+ }
+ else if (!indices_decrease_along_edge && sub_edges_created_in_reverse_order) {
+ n = edge->T - offset - T + n;
+ }
+ else if (indices_decrease_along_edge && !sub_edges_created_in_reverse_order) {
+ n = offset + T - n;
+ }
+ else if (indices_decrease_along_edge && sub_edges_created_in_reverse_order) {
+ n = edge->T - offset - n;
+ }
+
+ return edge->get_vert_along_edge(n);
+}
+
+inline int Subpatch::get_vert_along_edge(int edge, int n) const
+{
+ return edges[edge].get_vert_along_edge(n);
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __SUBD_SUBPATCH_H__ */
diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt
index 4f1c82897cc..a6a6b6704f0 100644
--- a/intern/cycles/util/CMakeLists.txt
+++ b/intern/cycles/util/CMakeLists.txt
@@ -55,6 +55,7 @@ set(SRC_HEADERS
util_boundbox.h
util_debug.h
util_defines.h
+ util_deque.h
util_guarded_allocator.cpp
util_foreach.h
util_function.h
diff --git a/intern/cycles/util/util_aligned_malloc.cpp b/intern/cycles/util/util_aligned_malloc.cpp
index 104e6c5e3f4..9b729cd4fc4 100644
--- a/intern/cycles/util/util_aligned_malloc.cpp
+++ b/intern/cycles/util/util_aligned_malloc.cpp
@@ -46,13 +46,7 @@ void *util_aligned_malloc(size_t size, int alignment)
return MEM_mallocN_aligned(size, alignment, "Cycles Aligned Alloc");
#elif defined(_WIN32)
return _aligned_malloc(size, alignment);
-#elif defined(__APPLE__)
- /* On Mac OS X, both the heap and the stack are guaranteed 16-byte aligned so
- * they work natively with SSE types with no further work.
- */
- assert(alignment == 16);
- return malloc(size);
-#elif defined(__FreeBSD__) || defined(__NetBSD__)
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
void *result;
if (posix_memalign(&result, alignment, size)) {
/* Non-zero means allocation error
diff --git a/intern/cycles/util/util_color.h b/intern/cycles/util/util_color.h
index 6e61190de6b..c6937ca78fe 100644
--- a/intern/cycles/util/util_color.h
+++ b/intern/cycles/util/util_color.h
@@ -43,11 +43,29 @@ ccl_device uchar4 color_float_to_byte(float3 c)
return make_uchar4(r, g, b, 0);
}
+ccl_device uchar4 color_float4_to_uchar4(float4 c)
+{
+ uchar r, g, b, a;
+
+ r = float_to_byte(c.x);
+ g = float_to_byte(c.y);
+ b = float_to_byte(c.z);
+ a = float_to_byte(c.w);
+
+ return make_uchar4(r, g, b, a);
+}
+
ccl_device_inline float3 color_byte_to_float(uchar4 c)
{
return make_float3(c.x * (1.0f / 255.0f), c.y * (1.0f / 255.0f), c.z * (1.0f / 255.0f));
}
+ccl_device_inline float4 color_uchar4_to_float4(uchar4 c)
+{
+ return make_float4(
+ c.x * (1.0f / 255.0f), c.y * (1.0f / 255.0f), c.z * (1.0f / 255.0f), c.w * (1.0f / 255.0f));
+}
+
ccl_device float color_srgb_to_linear(float c)
{
if (c < 0.04045f)
diff --git a/intern/cycles/util/util_debug.cpp b/intern/cycles/util/util_debug.cpp
index aabfea7fc49..3ce65802cff 100644
--- a/intern/cycles/util/util_debug.cpp
+++ b/intern/cycles/util/util_debug.cpp
@@ -86,6 +86,16 @@ void DebugFlags::CUDA::reset()
split_kernel = false;
}
+DebugFlags::OptiX::OptiX()
+{
+ reset();
+}
+
+void DebugFlags::OptiX::reset()
+{
+ cuda_streams = 1;
+}
+
DebugFlags::OpenCL::OpenCL() : device_type(DebugFlags::OpenCL::DEVICE_ALL), debug(false)
{
reset();
@@ -120,7 +130,7 @@ void DebugFlags::OpenCL::reset()
debug = (getenv("CYCLES_OPENCL_DEBUG") != NULL);
}
-DebugFlags::DebugFlags() : viewport_static_bvh(false)
+DebugFlags::DebugFlags() : viewport_static_bvh(false), running_inside_blender(false)
{
/* Nothing for now. */
}
@@ -130,6 +140,7 @@ void DebugFlags::reset()
viewport_static_bvh = false;
cpu.reset();
cuda.reset();
+ optix.reset();
opencl.reset();
}
@@ -145,7 +156,10 @@ std::ostream &operator<<(std::ostream &os, DebugFlagsConstRef debug_flags)
<< " Split : " << string_from_bool(debug_flags.cpu.split_kernel) << "\n";
os << "CUDA flags:\n"
- << " Adaptive Compile: " << string_from_bool(debug_flags.cuda.adaptive_compile) << "\n";
+ << " Adaptive Compile : " << string_from_bool(debug_flags.cuda.adaptive_compile) << "\n";
+
+ os << "OptiX flags:\n"
+ << " CUDA streams : " << debug_flags.optix.cuda_streams << "\n";
const char *opencl_device_type;
switch (debug_flags.opencl.device_type) {
diff --git a/intern/cycles/util/util_debug.h b/intern/cycles/util/util_debug.h
index 83d9e96ffa5..cf6b442b878 100644
--- a/intern/cycles/util/util_debug.h
+++ b/intern/cycles/util/util_debug.h
@@ -33,6 +33,8 @@ class DebugFlags {
/* Use static BVH in viewport, to match final render exactly. */
bool viewport_static_bvh;
+ bool running_inside_blender;
+
/* Descriptor of CPU feature-set to be used. */
struct CPU {
CPU();
@@ -97,6 +99,17 @@ class DebugFlags {
bool split_kernel;
};
+ /* Descriptor of OptiX feature-set to be used. */
+ struct OptiX {
+ OptiX();
+
+ /* Reset flags to their defaults. */
+ void reset();
+
+ /* Number of CUDA streams to launch kernels concurrently from. */
+ int cuda_streams;
+ };
+
/* Descriptor of OpenCL feature-set to be used. */
struct OpenCL {
OpenCL();
@@ -163,6 +176,9 @@ class DebugFlags {
/* Requested CUDA flags. */
CUDA cuda;
+ /* Requested OptiX flags. */
+ OptiX optix;
+
/* Requested OpenCL flags. */
OpenCL opencl;
diff --git a/intern/cycles/util/util_defines.h b/intern/cycles/util/util_defines.h
index 760985447a8..2778cffba3a 100644
--- a/intern/cycles/util/util_defines.h
+++ b/intern/cycles/util/util_defines.h
@@ -39,6 +39,7 @@
# define ccl_private
# define ccl_restrict __restrict
# define ccl_ref &
+# define ccl_optional_struct_init
# define __KERNEL_WITH_SSE_ALIGN__
# if defined(_WIN32) && !defined(FREE_WINDOWS)
diff --git a/intern/cycles/util/util_deque.h b/intern/cycles/util/util_deque.h
new file mode 100644
index 00000000000..ccac961aa7d
--- /dev/null
+++ b/intern/cycles/util/util_deque.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * 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.
+ */
+
+#ifndef __UTIL_DEQUE_H__
+#define __UTIL_DEQUE_H__
+
+#include <deque>
+
+CCL_NAMESPACE_BEGIN
+
+using std::deque;
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_DEQUE_H__ */
diff --git a/intern/cycles/util/util_hash.h b/intern/cycles/util/util_hash.h
index 2b1f26de03d..ca48758efcd 100644
--- a/intern/cycles/util/util_hash.h
+++ b/intern/cycles/util/util_hash.h
@@ -47,7 +47,8 @@ CCL_NAMESPACE_BEGIN
c -= b; \
c ^= rot(b, 4); \
b += a; \
- }
+ } \
+ ((void)0)
#define final(a, b, c) \
{ \
@@ -65,7 +66,8 @@ CCL_NAMESPACE_BEGIN
b -= rot(a, 14); \
c ^= b; \
c -= rot(b, 24); \
- }
+ } \
+ ((void)0)
ccl_device_inline uint hash_uint(uint kx)
{
@@ -213,6 +215,109 @@ ccl_device_inline float3 hash_float4_to_float3(float4 k)
hash_float4_to_float(make_float4(k.w, k.z, k.y, k.x)));
}
+/* SSE Versions Of Jenkins Lookup3 Hash Functions */
+
+#ifdef __KERNEL_SSE2__
+# define rot(x, k) (((x) << (k)) | (srl(x, 32 - (k))))
+
+# define mix(a, b, c) \
+ { \
+ a -= c; \
+ a ^= rot(c, 4); \
+ c += b; \
+ b -= a; \
+ b ^= rot(a, 6); \
+ a += c; \
+ c -= b; \
+ c ^= rot(b, 8); \
+ b += a; \
+ a -= c; \
+ a ^= rot(c, 16); \
+ c += b; \
+ b -= a; \
+ b ^= rot(a, 19); \
+ a += c; \
+ c -= b; \
+ c ^= rot(b, 4); \
+ b += a; \
+ }
+
+# define final(a, b, c) \
+ { \
+ c ^= b; \
+ c -= rot(b, 14); \
+ a ^= c; \
+ a -= rot(c, 11); \
+ b ^= a; \
+ b -= rot(a, 25); \
+ c ^= b; \
+ c -= rot(b, 16); \
+ a ^= c; \
+ a -= rot(c, 4); \
+ b ^= a; \
+ b -= rot(a, 14); \
+ c ^= b; \
+ c -= rot(b, 24); \
+ }
+
+ccl_device_inline ssei hash_ssei(ssei kx)
+{
+ ssei a, b, c;
+ a = b = c = ssei(0xdeadbeef + (1 << 2) + 13);
+
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+ccl_device_inline ssei hash_ssei2(ssei kx, ssei ky)
+{
+ ssei a, b, c;
+ a = b = c = ssei(0xdeadbeef + (2 << 2) + 13);
+
+ b += ky;
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+ccl_device_inline ssei hash_ssei3(ssei kx, ssei ky, ssei kz)
+{
+ ssei a, b, c;
+ a = b = c = ssei(0xdeadbeef + (3 << 2) + 13);
+
+ c += kz;
+ b += ky;
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+ccl_device_inline ssei hash_ssei4(ssei kx, ssei ky, ssei kz, ssei kw)
+{
+ ssei a, b, c;
+ a = b = c = ssei(0xdeadbeef + (4 << 2) + 13);
+
+ a += kx;
+ b += ky;
+ c += kz;
+ mix(a, b, c);
+
+ a += kw;
+ final(a, b, c);
+
+ return c;
+}
+
+# undef rot
+# undef final
+# undef mix
+
+#endif
+
#ifndef __KERNEL_GPU__
static inline uint hash_string(const char *str)
{
diff --git a/intern/cycles/util/util_map.h b/intern/cycles/util/util_map.h
index 8385b08dd5a..f1b2522362f 100644
--- a/intern/cycles/util/util_map.h
+++ b/intern/cycles/util/util_map.h
@@ -25,6 +25,7 @@ CCL_NAMESPACE_BEGIN
using std::map;
using std::pair;
using std::unordered_map;
+using std::unordered_multimap;
template<typename T> static void map_free_memory(T &data)
{
diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h
index dde0d31f467..53e528de66e 100644
--- a/intern/cycles/util/util_math.h
+++ b/intern/cycles/util/util_math.h
@@ -294,6 +294,21 @@ ccl_device_inline float mix(float a, float b, float t)
{
return a + t * (b - a);
}
+
+ccl_device_inline float smoothstep(float edge0, float edge1, float x)
+{
+ float result;
+ if (x < edge0)
+ result = 0.0f;
+ else if (x >= edge1)
+ result = 1.0f;
+ else {
+ float t = (x - edge0) / (edge1 - edge0);
+ result = (3.0f - 2.0f * t) * (t * t);
+ }
+ return result;
+}
+
#endif /* __KERNEL_OPENCL__ */
#ifndef __KERNEL_CUDA__
@@ -318,6 +333,12 @@ ccl_device_inline int quick_floor_to_int(float x)
return float_to_int(x) - ((x < 0) ? 1 : 0);
}
+ccl_device_inline float floorfrac(float x, int *i)
+{
+ *i = quick_floor_to_int(x);
+ return x - *i;
+}
+
ccl_device_inline int ceil_to_int(float f)
{
return float_to_int(ceilf(f));
@@ -617,6 +638,57 @@ ccl_device float bits_to_01(uint bits)
return bits * (1.0f / (float)0xFFFFFFFF);
}
+ccl_device_inline uint count_leading_zeros(uint x)
+{
+#if defined(__KERNEL_CUDA__) || defined(__KERNEL_OPTIX__)
+ return __clz(x);
+#elif defined(__KERNEL_OPENCL__)
+ return clz(x);
+#else
+ assert(x != 0);
+# ifdef _MSC_VER
+ unsigned long leading_zero = 0;
+ _BitScanReverse(&leading_zero, x);
+ return (31 - leading_zero);
+# else
+ return __builtin_clz(x);
+# endif
+#endif
+}
+
+ccl_device_inline uint count_trailing_zeros(uint x)
+{
+#if defined(__KERNEL_CUDA__) || defined(__KERNEL_OPTIX__)
+ return (__ffs(x) - 1);
+#elif defined(__KERNEL_OPENCL__)
+ return (31 - count_leading_zeros(x & -x));
+#else
+ assert(x != 0);
+# ifdef _MSC_VER
+ unsigned long ctz = 0;
+ _BitScanForward(&ctz, x);
+ return ctz;
+# else
+ return __builtin_ctz(x);
+# endif
+#endif
+}
+
+ccl_device_inline uint find_first_set(uint x)
+{
+#if defined(__KERNEL_CUDA__) || defined(__KERNEL_OPTIX__)
+ return __ffs(x);
+#elif defined(__KERNEL_OPENCL__)
+ return (x != 0) ? (32 - count_leading_zeros(x & (-x))) : 0;
+#else
+# ifdef _MSC_VER
+ return (x != 0) ? (32 - count_leading_zeros(x & (-x))) : 0;
+# else
+ return __builtin_ffs(x);
+# endif
+#endif
+}
+
/* projections */
ccl_device_inline float2 map_to_tube(const float3 co)
{
diff --git a/intern/cycles/util/util_math_float2.h b/intern/cycles/util/util_math_float2.h
index 9feaf042d19..bf21430af3c 100644
--- a/intern/cycles/util/util_math_float2.h
+++ b/intern/cycles/util/util_math_float2.h
@@ -35,7 +35,9 @@ ccl_device_inline float2 operator*(float f, const float2 &a);
ccl_device_inline float2 operator/(float f, const float2 &a);
ccl_device_inline float2 operator/(const float2 &a, float f);
ccl_device_inline float2 operator/(const float2 &a, const float2 &b);
+ccl_device_inline float2 operator+(const float2 &a, const float f);
ccl_device_inline float2 operator+(const float2 &a, const float2 &b);
+ccl_device_inline float2 operator-(const float2 &a, const float f);
ccl_device_inline float2 operator-(const float2 &a, const float2 &b);
ccl_device_inline float2 operator+=(float2 &a, const float2 &b);
ccl_device_inline float2 operator*=(float2 &a, const float2 &b);
@@ -48,6 +50,7 @@ ccl_device_inline bool operator!=(const float2 &a, const float2 &b);
ccl_device_inline bool is_zero(const float2 &a);
ccl_device_inline float average(const float2 &a);
+ccl_device_inline float distance(const float2 &a, const float2 &b);
ccl_device_inline float dot(const float2 &a, const float2 &b);
ccl_device_inline float cross(const float2 &a, const float2 &b);
ccl_device_inline float len(const float2 &a);
@@ -60,8 +63,11 @@ ccl_device_inline float2 clamp(const float2 &a, const float2 &mn, const float2 &
ccl_device_inline float2 fabs(const float2 &a);
ccl_device_inline float2 as_float2(const float4 &a);
ccl_device_inline float2 interp(const float2 &a, const float2 &b, float t);
+ccl_device_inline float2 floor(const float2 &a);
#endif /* !__KERNEL_OPENCL__ */
+ccl_device_inline float2 safe_divide_float2_float(const float2 a, const float b);
+
/*******************************************************************************
* Definition.
*/
@@ -103,11 +109,21 @@ ccl_device_inline float2 operator/(const float2 &a, const float2 &b)
return make_float2(a.x / b.x, a.y / b.y);
}
+ccl_device_inline float2 operator+(const float2 &a, const float f)
+{
+ return a + make_float2(f, f);
+}
+
ccl_device_inline float2 operator+(const float2 &a, const float2 &b)
{
return make_float2(a.x + b.x, a.y + b.y);
}
+ccl_device_inline float2 operator-(const float2 &a, const float f)
+{
+ return a - make_float2(f, f);
+}
+
ccl_device_inline float2 operator-(const float2 &a, const float2 &b)
{
return make_float2(a.x - b.x, a.y - b.y);
@@ -159,6 +175,11 @@ ccl_device_inline float average(const float2 &a)
return (a.x + a.y) * (1.0f / 2.0f);
}
+ccl_device_inline float distance(const float2 &a, const float2 &b)
+{
+ return len(a - b);
+}
+
ccl_device_inline float dot(const float2 &a, const float2 &b)
{
return a.x * b.x + a.y * b.y;
@@ -226,8 +247,18 @@ ccl_device_inline float2 mix(const float2 &a, const float2 &b, float t)
return a + t * (b - a);
}
+ccl_device_inline float2 floor(const float2 &a)
+{
+ return make_float2(floorf(a.x), floorf(a.y));
+}
+
#endif /* !__KERNEL_OPENCL__ */
+ccl_device_inline float2 safe_divide_float2_float(const float2 a, const float b)
+{
+ return (b != 0.0f) ? a / b : make_float2(0.0f, 0.0f);
+}
+
CCL_NAMESPACE_END
#endif /* __UTIL_MATH_FLOAT2_H__ */
diff --git a/intern/cycles/util/util_math_float3.h b/intern/cycles/util/util_math_float3.h
index c9a5b34aa58..dd2010715ba 100644
--- a/intern/cycles/util/util_math_float3.h
+++ b/intern/cycles/util/util_math_float3.h
@@ -35,7 +35,9 @@ ccl_device_inline float3 operator*(const float f, const float3 &a);
ccl_device_inline float3 operator/(const float f, const float3 &a);
ccl_device_inline float3 operator/(const float3 &a, const float f);
ccl_device_inline float3 operator/(const float3 &a, const float3 &b);
+ccl_device_inline float3 operator+(const float3 &a, const float f);
ccl_device_inline float3 operator+(const float3 &a, const float3 &b);
+ccl_device_inline float3 operator-(const float3 &a, const float f);
ccl_device_inline float3 operator-(const float3 &a, const float3 &b);
ccl_device_inline float3 operator+=(float3 &a, const float3 &b);
ccl_device_inline float3 operator-=(float3 &a, const float3 &b);
@@ -150,6 +152,11 @@ ccl_device_inline float3 operator/(const float3 &a, const float3 &b)
# endif
}
+ccl_device_inline float3 operator+(const float3 &a, const float f)
+{
+ return a + make_float3(f, f, f);
+}
+
ccl_device_inline float3 operator+(const float3 &a, const float3 &b)
{
# ifdef __KERNEL_SSE__
@@ -159,6 +166,11 @@ ccl_device_inline float3 operator+(const float3 &a, const float3 &b)
# endif
}
+ccl_device_inline float3 operator-(const float3 &a, const float f)
+{
+ return a - make_float3(f, f, f);
+}
+
ccl_device_inline float3 operator-(const float3 &a, const float3 &b)
{
# ifdef __KERNEL_SSE__
diff --git a/intern/cycles/util/util_math_float4.h b/intern/cycles/util/util_math_float4.h
index 1fb886572e3..bc5322a22bb 100644
--- a/intern/cycles/util/util_math_float4.h
+++ b/intern/cycles/util/util_math_float4.h
@@ -34,7 +34,9 @@ ccl_device_inline float4 operator*(const float4 &a, float f);
ccl_device_inline float4 operator*(float f, const float4 &a);
ccl_device_inline float4 operator/(const float4 &a, float f);
ccl_device_inline float4 operator/(const float4 &a, const float4 &b);
+ccl_device_inline float4 operator+(const float4 &a, const float f);
ccl_device_inline float4 operator+(const float4 &a, const float4 &b);
+ccl_device_inline float4 operator-(const float4 &a, const float f);
ccl_device_inline float4 operator-(const float4 &a, const float4 &b);
ccl_device_inline float4 operator+=(float4 &a, const float4 &b);
ccl_device_inline float4 operator*=(float4 &a, const float4 &b);
@@ -46,6 +48,7 @@ ccl_device_inline int4 operator>=(const float4 &a, const float4 &b);
ccl_device_inline int4 operator<=(const float4 &a, const float4 &b);
ccl_device_inline bool operator==(const float4 &a, const float4 &b);
+ccl_device_inline float distance(const float4 &a, const float4 &b);
ccl_device_inline float dot(const float4 &a, const float4 &b);
ccl_device_inline float len_squared(const float4 &a);
ccl_device_inline float4 rcp(const float4 &a);
@@ -61,8 +64,12 @@ ccl_device_inline float4 min(const float4 &a, const float4 &b);
ccl_device_inline float4 max(const float4 &a, const float4 &b);
ccl_device_inline float4 clamp(const float4 &a, const float4 &mn, const float4 &mx);
ccl_device_inline float4 fabs(const float4 &a);
+ccl_device_inline float4 floor(const float4 &a);
+ccl_device_inline float4 mix(const float4 &a, const float4 &b, float t);
#endif /* !__KERNEL_OPENCL__*/
+ccl_device_inline float4 safe_divide_float4_float(const float4 a, const float b);
+
#ifdef __KERNEL_SSE__
template<size_t index_0, size_t index_1, size_t index_2, size_t index_3>
__forceinline const float4 shuffle(const float4 &b);
@@ -139,6 +146,11 @@ ccl_device_inline float4 operator/(const float4 &a, const float4 &b)
# endif
}
+ccl_device_inline float4 operator+(const float4 &a, const float f)
+{
+ return a + make_float4(f, f, f, f);
+}
+
ccl_device_inline float4 operator+(const float4 &a, const float4 &b)
{
# ifdef __KERNEL_SSE__
@@ -148,6 +160,11 @@ ccl_device_inline float4 operator+(const float4 &a, const float4 &b)
# endif
}
+ccl_device_inline float4 operator-(const float4 &a, const float f)
+{
+ return a - make_float4(f, f, f, f);
+}
+
ccl_device_inline float4 operator-(const float4 &a, const float4 &b)
{
# ifdef __KERNEL_SSE__
@@ -213,6 +230,11 @@ ccl_device_inline bool operator==(const float4 &a, const float4 &b)
# endif
}
+ccl_device_inline float distance(const float4 &a, const float4 &b)
+{
+ return len(a - b);
+}
+
ccl_device_inline float dot(const float4 &a, const float4 &b)
{
# if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
@@ -338,6 +360,21 @@ ccl_device_inline float4 fabs(const float4 &a)
return make_float4(fabsf(a.x), fabsf(a.y), fabsf(a.z), fabsf(a.w));
# endif
}
+
+ccl_device_inline float4 floor(const float4 &a)
+{
+# ifdef __KERNEL_SSE__
+ return float4(_mm_floor_ps(a));
+# else
+ return make_float4(floorf(a.x), floorf(a.y), floorf(a.z), floorf(a.w));
+# endif
+}
+
+ccl_device_inline float4 mix(const float4 &a, const float4 &b, float t)
+{
+ return a + t * (b - a);
+}
+
#endif /* !__KERNEL_OPENCL__*/
#ifdef __KERNEL_SSE__
@@ -430,6 +467,11 @@ ccl_device_inline float4 load_float4(const float *v)
#endif /* !__KERNEL_GPU__ */
+ccl_device_inline float4 safe_divide_float4_float(const float4 a, const float b)
+{
+ return (b != 0.0f) ? a / b : make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+}
+
CCL_NAMESPACE_END
#endif /* __UTIL_MATH_FLOAT4_H__ */
diff --git a/intern/cycles/util/util_param.h b/intern/cycles/util/util_param.h
index cfbe416aba1..3f8e2d6d700 100644
--- a/intern/cycles/util/util_param.h
+++ b/intern/cycles/util/util_param.h
@@ -29,6 +29,11 @@ CCL_NAMESPACE_BEGIN
OIIO_NAMESPACE_USING
static constexpr TypeDesc TypeFloat2(TypeDesc::FLOAT, TypeDesc::VEC2);
+static constexpr TypeDesc TypeRGBA(TypeDesc::FLOAT, TypeDesc::VEC4, TypeDesc::COLOR);
+static constexpr TypeDesc TypeFloatArray4(TypeDesc::FLOAT,
+ TypeDesc::SCALAR,
+ TypeDesc::NOSEMANTICS,
+ 4);
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_ssef.h b/intern/cycles/util/util_ssef.h
index e6610dbb197..fa525daf37c 100644
--- a/intern/cycles/util/util_ssef.h
+++ b/intern/cycles/util/util_ssef.h
@@ -523,13 +523,29 @@ __forceinline ssei truncatei(const ssef &a)
return _mm_cvttps_epi32(a.m128);
}
+/* This is about 25% faster than straightforward floor to integer conversion
+ * due to better pipelining.
+ *
+ * Unsaturated add 0xffffffff (a < 0) is the same as subtract -1.
+ */
__forceinline ssei floori(const ssef &a)
{
-# if defined(__KERNEL_SSE41__)
- return ssei(floor(a));
-# else
- return ssei(a - ssef(0.5f));
-# endif
+ return truncatei(a) + cast((a < 0.0f).m128);
+}
+
+__forceinline ssef floorfrac(const ssef &x, ssei *i)
+{
+ *i = floori(x);
+ return x - ssef(*i);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Common Functions
+////////////////////////////////////////////////////////////////////////////////
+
+__forceinline ssef mix(const ssef &a, const ssef &b, const ssef &t)
+{
+ return madd(t, b, (ssef(1.0f) - t) * a);
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/intern/cycles/util/util_ssei.h b/intern/cycles/util/util_ssei.h
index 86429260a0e..e2bf81310cc 100644
--- a/intern/cycles/util/util_ssei.h
+++ b/intern/cycles/util/util_ssei.h
@@ -310,6 +310,15 @@ __forceinline ssei &operator|=(ssei &a, const int32_t &b)
return a = a | b;
}
+__forceinline ssei &operator^=(ssei &a, const ssei &b)
+{
+ return a = a ^ b;
+}
+__forceinline ssei &operator^=(ssei &a, const int32_t &b)
+{
+ return a = a ^ b;
+}
+
__forceinline ssei &operator<<=(ssei &a, const int32_t &b)
{
return a = a << b;
diff --git a/intern/cycles/util/util_system.cpp b/intern/cycles/util/util_system.cpp
index 0cd991c6231..f700f9bd277 100644
--- a/intern/cycles/util/util_system.cpp
+++ b/intern/cycles/util/util_system.cpp
@@ -357,7 +357,7 @@ size_t system_physical_ram()
MEMORYSTATUSEX ram;
ram.dwLength = sizeof(ram);
GlobalMemoryStatusEx(&ram);
- return ram.ullTotalPhys * 1024;
+ return ram.ullTotalPhys;
#elif defined(__APPLE__)
uint64_t ram = 0;
size_t len = sizeof(ram);
diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h
index cfe71d696ed..407654245cb 100644
--- a/intern/cycles/util/util_transform.h
+++ b/intern/cycles/util/util_transform.h
@@ -148,6 +148,32 @@ ccl_device_inline Transform make_transform(float a,
return t;
}
+ccl_device_inline Transform euler_to_transform(const float3 euler)
+{
+ float cx = cosf(euler.x);
+ float cy = cosf(euler.y);
+ float cz = cosf(euler.z);
+ float sx = sinf(euler.x);
+ float sy = sinf(euler.y);
+ float sz = sinf(euler.z);
+
+ Transform t;
+ t.x.x = cy * cz;
+ t.y.x = cy * sz;
+ t.z.x = -sy;
+
+ t.x.y = sy * sx * cz - cx * sz;
+ t.y.y = sy * sx * sz + cx * cz;
+ t.z.y = cy * sx;
+
+ t.x.z = sy * cx * cz + sx * sz;
+ t.y.z = sy * cx * sz - sx * cz;
+ t.z.z = cy * cx;
+
+ t.x.w = t.y.w = t.z.w = 0.0f;
+ return t;
+}
+
/* Constructs a coordinate frame from a normalized normal. */
ccl_device_inline Transform make_transform_frame(float3 N)
{
diff --git a/intern/ffmpeg/ffmpeg_compat.h b/intern/ffmpeg/ffmpeg_compat.h
index 863fbd40bb0..123e18430a9 100644
--- a/intern/ffmpeg/ffmpeg_compat.h
+++ b/intern/ffmpeg/ffmpeg_compat.h
@@ -364,7 +364,7 @@ void avcodec_free_frame(AVFrame **frame)
# define avio_size url_fsize
#endif
-/* there are some version inbetween, which have avio_... functions but no
+/* There are some version in between, which have avio_... functions but no
* AVIO_FLAG_... */
#ifndef AVIO_FLAG_WRITE
# define AVIO_FLAG_WRITE URL_WRONLY
@@ -528,35 +528,21 @@ bool av_check_encoded_with_ffmpeg(AVFormatContext *ctx)
return false;
}
-FFMPEG_INLINE
-AVRational av_get_r_frame_rate_compat(AVFormatContext *ctx, const AVStream *stream)
+/* Libav doesn't have av_guess_frame_rate().
+ * It was introduced in FFmpeg's lavf 55.1.100. */
+#ifdef AV_USING_LIBAV
+AVRational av_guess_frame_rate(AVFormatContext *ctx, AVStream *stream, AVFrame *frame)
{
- /* If the video is encoded with FFmpeg and we are decoding with FFmpeg
- * as well it seems to be more reliable to use r_frame_rate (tbr).
- *
- * For other cases we fall back to avg_frame_rate (fps) when possible.
- */
-#ifdef AV_USING_FFMPEG
- if (av_check_encoded_with_ffmpeg(ctx)) {
- return stream->r_frame_rate;
- }
-#endif
-
-#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 23, 1)
- /* For until r_frame_rate was deprecated use it. */
+ (void)ctx;
+ (void)frame;
+# if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 23, 1)
+ /* For until r_frame_rate was deprecated (in Libav) use it. */
return stream->r_frame_rate;
-#else
-# ifdef AV_USING_FFMPEG
- /* Some of the videos might have average frame rate set to, while the
- * r_frame_rate will show a correct value. This happens, for example, for
- * OGG video files saved with Blender. */
- if (stream->avg_frame_rate.den == 0) {
- return stream->r_frame_rate;
- }
-# endif
+# else
return stream->avg_frame_rate;
-#endif
+# endif
}
+#endif
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 32, 0)
# define AV_OPT_SEARCH_FAKE_OBJ 0
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index 0f735711b24..20bb144a924 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -316,7 +316,8 @@ extern GHOST_TSuccess GHOST_EndProgressBar(GHOST_WindowHandle windowhandle);
extern GHOST_TStandardCursor GHOST_GetCursorShape(GHOST_WindowHandle windowhandle);
/**
- * Set the shape of the cursor.
+ * Set the shape of the cursor. If the shape is not supported by the platform,
+ * it will use the default cursor instead.
* \param windowhandle The handle to the window
* \param cursorshape The new cursor shape type id.
* \return Indication of success.
@@ -325,6 +326,13 @@ extern GHOST_TSuccess GHOST_SetCursorShape(GHOST_WindowHandle windowhandle,
GHOST_TStandardCursor cursorshape);
/**
+ * Test if the standard cursor shape is supported by current platform.
+ * \return Indication of success.
+ */
+extern GHOST_TSuccess GHOST_HasCursorShape(GHOST_WindowHandle windowhandle,
+ GHOST_TStandardCursor cursorshape);
+
+/**
* Set the shape of the cursor to a custom cursor of specified size.
* \param windowhandle The handle to the window
* \param bitmap The bitmap data for the cursor.
@@ -477,7 +485,7 @@ extern GHOST_TEventDataPtr GHOST_GetEventData(GHOST_EventHandle eventhandle);
/**
* Returns the timer callback.
- * \param timertaskhandle The handle to the timertask
+ * \param timertaskhandle The handle to the timer-task.
* \return The timer callback.
*/
extern GHOST_TimerProcPtr GHOST_GetTimerProc(GHOST_TimerTaskHandle timertaskhandle);
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index f0ceb7fb8ba..27be80a2f20 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -402,7 +402,7 @@ class GHOST_ISystem {
#ifdef WITH_INPUT_NDOF
/**
* Sets 3D mouse deadzone
- * \param deadzone: Deadzone of the 3D mouse (both for rotation and pan) relative to full range
+ * \param deadzone: Dead-zone of the 3D mouse (both for rotation and pan) relative to full range
*/
virtual void setNDOFDeadZone(float deadzone) = 0;
#endif
diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h
index 1a1844bfe41..03a0db9abbe 100644
--- a/intern/ghost/GHOST_IWindow.h
+++ b/intern/ghost/GHOST_IWindow.h
@@ -280,6 +280,12 @@ class GHOST_IWindow {
virtual GHOST_TSuccess setCursorShape(GHOST_TStandardCursor cursorShape) = 0;
/**
+ * Test if the standard cursor shape is supported by current platform.
+ * \return Indication of success.
+ */
+ virtual GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor cursorShape) = 0;
+
+ /**
* Set the shape of the cursor to a custom cursor.
* \param bitmap The bitmap data for the cursor.
* \param mask The mask data for the cursor.
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 68516c3ecf8..891f9d982b9 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -197,11 +197,27 @@ typedef enum {
GHOST_kStandardCursorInfo,
GHOST_kStandardCursorDestroy,
GHOST_kStandardCursorHelp,
- GHOST_kStandardCursorCycle,
- GHOST_kStandardCursorSpray,
GHOST_kStandardCursorWait,
GHOST_kStandardCursorText,
GHOST_kStandardCursorCrosshair,
+ GHOST_kStandardCursorCrosshairA,
+ GHOST_kStandardCursorCrosshairB,
+ GHOST_kStandardCursorCrosshairC,
+ GHOST_kStandardCursorPencil,
+ GHOST_kStandardCursorUpArrow,
+ GHOST_kStandardCursorDownArrow,
+ GHOST_kStandardCursorVerticalSplit,
+ GHOST_kStandardCursorHorizontalSplit,
+ GHOST_kStandardCursorEraser,
+ GHOST_kStandardCursorKnife,
+ GHOST_kStandardCursorEyedropper,
+ GHOST_kStandardCursorZoomIn,
+ GHOST_kStandardCursorZoomOut,
+ GHOST_kStandardCursorMove,
+ GHOST_kStandardCursorNSEWScroll,
+ GHOST_kStandardCursorNSScroll,
+ GHOST_kStandardCursorEWScroll,
+ GHOST_kStandardCursorStop,
GHOST_kStandardCursorUpDown,
GHOST_kStandardCursorLeftRight,
GHOST_kStandardCursorTopSide,
@@ -214,7 +230,6 @@ typedef enum {
GHOST_kStandardCursorBottomLeftCorner,
GHOST_kStandardCursorCopy,
GHOST_kStandardCursorCustom,
- GHOST_kStandardCursorPencil,
GHOST_kStandardCursorNumCursors
} GHOST_TStandardCursor;
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index 78f171af7d1..a1a209af77a 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -264,6 +264,14 @@ GHOST_TSuccess GHOST_SetCursorShape(GHOST_WindowHandle windowhandle,
return window->setCursorShape(cursorshape);
}
+GHOST_TSuccess GHOST_HasCursorShape(GHOST_WindowHandle windowhandle,
+ GHOST_TStandardCursor cursorshape)
+{
+ GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
+
+ return window->hasCursorShape(cursorshape);
+}
+
GHOST_TSuccess GHOST_SetCustomCursorShape(GHOST_WindowHandle windowhandle,
GHOST_TUns8 *bitmap,
GHOST_TUns8 *mask,
diff --git a/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm b/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm
index 4d07a399002..4c9c58c36be 100644
--- a/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm
+++ b/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm
@@ -121,7 +121,8 @@ static bool load_driver_functions()
return true;
}
- module = dlopen("3DconnexionClient.framework/3DconnexionClient", RTLD_LAZY | RTLD_LOCAL);
+ module = dlopen("/Library/Frameworks/3DconnexionClient.framework/3DconnexionClient",
+ RTLD_LAZY | RTLD_LOCAL);
if (module) {
LOAD_FUNC(SetConnexionHandlers);
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index 376ebfa2a21..2026c1b7b4f 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -578,12 +578,13 @@ GHOST_TSuccess GHOST_SystemCocoa::init()
menuItem = [appMenu addItemWithTitle:@"Hide Blender"
action:@selector(hide:)
keyEquivalent:@"h"];
- [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
+ [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
menuItem = [appMenu addItemWithTitle:@"Hide others"
action:@selector(hideOtherApplications:)
keyEquivalent:@"h"];
- [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask | NSCommandKeyMask)];
+ [menuItem
+ setKeyEquivalentModifierMask:(NSEventModifierFlagOption | NSEventModifierFlagCommand)];
[appMenu addItemWithTitle:@"Show All"
action:@selector(unhideAllApplications:)
@@ -592,7 +593,7 @@ GHOST_TSuccess GHOST_SystemCocoa::init()
menuItem = [appMenu addItemWithTitle:@"Quit Blender"
action:@selector(terminate:)
keyEquivalent:@"q"];
- [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
+ [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
menuItem = [[NSMenuItem alloc] init];
[menuItem setSubmenu:appMenu];
@@ -608,19 +609,20 @@ GHOST_TSuccess GHOST_SystemCocoa::init()
menuItem = [windowMenu addItemWithTitle:@"Minimize"
action:@selector(performMiniaturize:)
keyEquivalent:@"m"];
- [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
+ [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
[windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
menuItem = [windowMenu addItemWithTitle:@"Enter Full Screen"
action:@selector(toggleFullScreen:)
keyEquivalent:@"f"];
- [menuItem setKeyEquivalentModifierMask:NSControlKeyMask | NSCommandKeyMask];
+ [menuItem
+ setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand];
menuItem = [windowMenu addItemWithTitle:@"Close"
action:@selector(performClose:)
keyEquivalent:@"w"];
- [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
+ [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
menuItem = [[NSMenuItem alloc] init];
[menuItem setSubmenu:windowMenu];
@@ -681,8 +683,8 @@ void GHOST_SystemCocoa::getMainDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns
// Returns max window contents (excluding title bar...)
NSRect contentRect = [NSWindow
contentRectForFrameRect:frame
- styleMask:(NSTitledWindowMask | NSClosableWindowMask |
- NSMiniaturizableWindowMask)];
+ styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
+ NSWindowStyleMaskMiniaturizable)];
width = contentRect.size.width;
height = contentRect.size.height;
@@ -714,8 +716,8 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const STR_String &title,
NSRect frame = [[NSScreen mainScreen] visibleFrame];
NSRect contentRect = [NSWindow
contentRectForFrameRect:frame
- styleMask:(NSTitledWindowMask | NSClosableWindowMask |
- NSMiniaturizableWindowMask)];
+ styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
+ NSWindowStyleMaskMiniaturizable)];
GHOST_TInt32 bottom = (contentRect.size.height - 1) - height - top;
@@ -853,10 +855,12 @@ GHOST_TSuccess GHOST_SystemCocoa::setMouseCursorPosition(GHOST_TInt32 x, GHOST_T
GHOST_TSuccess GHOST_SystemCocoa::getModifierKeys(GHOST_ModifierKeys &keys) const
{
- keys.set(GHOST_kModifierKeyOS, (m_modifierMask & NSCommandKeyMask) ? true : false);
- keys.set(GHOST_kModifierKeyLeftAlt, (m_modifierMask & NSAlternateKeyMask) ? true : false);
- keys.set(GHOST_kModifierKeyLeftShift, (m_modifierMask & NSShiftKeyMask) ? true : false);
- keys.set(GHOST_kModifierKeyLeftControl, (m_modifierMask & NSControlKeyMask) ? true : false);
+ keys.set(GHOST_kModifierKeyOS, (m_modifierMask & NSEventModifierFlagCommand) ? true : false);
+ keys.set(GHOST_kModifierKeyLeftAlt, (m_modifierMask & NSEventModifierFlagOption) ? true : false);
+ keys.set(GHOST_kModifierKeyLeftShift,
+ (m_modifierMask & NSEventModifierFlagShift) ? true : false);
+ keys.set(GHOST_kModifierKeyLeftControl,
+ (m_modifierMask & NSEventModifierFlagControl) ? true : false);
return GHOST_kSuccess;
}
@@ -912,7 +916,7 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
#endif
do {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:[NSDate distantPast]
inMode:NSDefaultRunLoopMode
dequeue:YES];
@@ -931,16 +935,16 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
// get keyDown events delivered to the view because they are
// special hotkeys to switch between views, so override directly
- if ([event type] == NSKeyDown && [event keyCode] == kVK_Tab &&
- ([event modifierFlags] & NSControlKeyMask)) {
+ if ([event type] == NSEventTypeKeyDown && [event keyCode] == kVK_Tab &&
+ ([event modifierFlags] & NSEventModifierFlagControl)) {
handleKeyEvent(event);
}
else {
// For some reason NSApp is swallowing the key up events when modifier
// key is pressed, even if there seems to be no apparent reason to do
// so, as a workaround we always handle these up events.
- if ([event type] == NSKeyUp &&
- ([event modifierFlags] & (NSCommandKeyMask | NSAlternateKeyMask)))
+ if ([event type] == NSEventTypeKeyUp &&
+ ([event modifierFlags] & (NSEventModifierFlagCommand | NSEventModifierFlagOption)))
handleKeyEvent(event);
[NSApp sendEvent:event];
@@ -982,31 +986,31 @@ GHOST_TSuccess GHOST_SystemCocoa::handleApplicationBecomeActiveEvent()
modifiers = [[[NSApplication sharedApplication] currentEvent] modifierFlags];
- if ((modifiers & NSShiftKeyMask) != (m_modifierMask & NSShiftKeyMask)) {
- pushEvent(
- new GHOST_EventKey(getMilliSeconds(),
- (modifiers & NSShiftKeyMask) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp,
- window,
- GHOST_kKeyLeftShift));
+ if ((modifiers & NSEventModifierFlagShift) != (m_modifierMask & NSEventModifierFlagShift)) {
+ pushEvent(new GHOST_EventKey(getMilliSeconds(),
+ (modifiers & NSEventModifierFlagShift) ? GHOST_kEventKeyDown :
+ GHOST_kEventKeyUp,
+ window,
+ GHOST_kKeyLeftShift));
}
- if ((modifiers & NSControlKeyMask) != (m_modifierMask & NSControlKeyMask)) {
+ if ((modifiers & NSEventModifierFlagControl) != (m_modifierMask & NSEventModifierFlagControl)) {
pushEvent(new GHOST_EventKey(getMilliSeconds(),
- (modifiers & NSControlKeyMask) ? GHOST_kEventKeyDown :
- GHOST_kEventKeyUp,
+ (modifiers & NSEventModifierFlagControl) ? GHOST_kEventKeyDown :
+ GHOST_kEventKeyUp,
window,
GHOST_kKeyLeftControl));
}
- if ((modifiers & NSAlternateKeyMask) != (m_modifierMask & NSAlternateKeyMask)) {
+ if ((modifiers & NSEventModifierFlagOption) != (m_modifierMask & NSEventModifierFlagOption)) {
pushEvent(new GHOST_EventKey(getMilliSeconds(),
- (modifiers & NSAlternateKeyMask) ? GHOST_kEventKeyDown :
- GHOST_kEventKeyUp,
+ (modifiers & NSEventModifierFlagOption) ? GHOST_kEventKeyDown :
+ GHOST_kEventKeyUp,
window,
GHOST_kKeyLeftAlt));
}
- if ((modifiers & NSCommandKeyMask) != (m_modifierMask & NSCommandKeyMask)) {
+ if ((modifiers & NSEventModifierFlagCommand) != (m_modifierMask & NSEventModifierFlagCommand)) {
pushEvent(new GHOST_EventKey(getMilliSeconds(),
- (modifiers & NSCommandKeyMask) ? GHOST_kEventKeyDown :
- GHOST_kEventKeyUp,
+ (modifiers & NSEventModifierFlagCommand) ? GHOST_kEventKeyDown :
+ GHOST_kEventKeyUp,
window,
GHOST_kKeyOS));
}
@@ -1413,7 +1417,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventT
GHOST_TabletData &ct = ((GHOST_WindowCocoa *)window)->GetCocoaTabletData();
switch (eventType) {
- case NSTabletPoint:
+ case NSEventTypeTabletPoint:
// workaround 2 cornercases:
// 1. if [event isEnteringProximity] was not triggered since program-start
// 2. device is not sending [event pointingDeviceType], due no eraser
@@ -1425,21 +1429,21 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventT
ct.Ytilt = [event tilt].y;
break;
- case NSTabletProximity:
+ case NSEventTypeTabletProximity:
ct.Pressure = 0;
ct.Xtilt = 0;
ct.Ytilt = 0;
if ([event isEnteringProximity]) {
// pointer is entering tablet area proximity
switch ([event pointingDeviceType]) {
- case NSPenPointingDevice:
+ case NSPointingDeviceTypePen:
ct.Active = GHOST_kTabletModeStylus;
break;
- case NSEraserPointingDevice:
+ case NSPointingDeviceTypeEraser:
ct.Active = GHOST_kTabletModeEraser;
break;
- case NSCursorPointingDevice:
- case NSUnknownPointingDevice:
+ case NSPointingDeviceTypeCursor:
+ case NSPointingDeviceTypeUnknown:
default:
ct.Active = GHOST_kTabletModeNone;
break;
@@ -1464,11 +1468,11 @@ bool GHOST_SystemCocoa::handleTabletEvent(void *eventPtr)
NSEvent *event = (NSEvent *)eventPtr;
switch ([event subtype]) {
- case NSTabletPointEventSubtype:
- handleTabletEvent(eventPtr, NSTabletPoint);
+ case NSEventSubtypeTabletPoint:
+ handleTabletEvent(eventPtr, NSEventTypeTabletPoint);
return true;
- case NSTabletProximityEventSubtype:
- handleTabletEvent(eventPtr, NSTabletProximity);
+ case NSEventSubtypeTabletProximity:
+ handleTabletEvent(eventPtr, NSEventTypeTabletProximity);
return true;
default:
// No tablet event included : do nothing
@@ -1498,17 +1502,17 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
cocoawindow = (CocoaWindow *)window->getOSWindow();
switch ([event type]) {
- case NSLeftMouseDown:
+ case NSEventTypeLeftMouseDown:
pushEvent(new GHOST_EventButton(
[event timestamp] * 1000, GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft));
handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
- case NSRightMouseDown:
+ case NSEventTypeRightMouseDown:
pushEvent(new GHOST_EventButton(
[event timestamp] * 1000, GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight));
handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
- case NSOtherMouseDown:
+ case NSEventTypeOtherMouseDown:
pushEvent(new GHOST_EventButton([event timestamp] * 1000,
GHOST_kEventButtonDown,
window,
@@ -1516,17 +1520,17 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
- case NSLeftMouseUp:
+ case NSEventTypeLeftMouseUp:
pushEvent(new GHOST_EventButton(
[event timestamp] * 1000, GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft));
handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
- case NSRightMouseUp:
+ case NSEventTypeRightMouseUp:
pushEvent(new GHOST_EventButton(
[event timestamp] * 1000, GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight));
handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
- case NSOtherMouseUp:
+ case NSEventTypeOtherMouseUp:
pushEvent(new GHOST_EventButton([event timestamp] * 1000,
GHOST_kEventButtonUp,
window,
@@ -1534,13 +1538,13 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
- case NSLeftMouseDragged:
- case NSRightMouseDragged:
- case NSOtherMouseDragged:
+ case NSEventTypeLeftMouseDragged:
+ case NSEventTypeRightMouseDragged:
+ case NSEventTypeOtherMouseDragged:
// Handle tablet events combined with mouse events
handleTabletEvent(event);
- case NSMouseMoved: {
+ case NSEventTypeMouseMoved: {
GHOST_TGrabCursorMode grab_mode = window->getCursorGrabMode();
/* TODO: CHECK IF THIS IS A TABLET EVENT */
@@ -1628,7 +1632,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
}
} break;
- case NSScrollWheel: {
+ case NSEventTypeScrollWheel: {
NSEventPhase momentumPhase = NSEventPhaseNone;
NSEventPhase phase = NSEventPhaseNone;
@@ -1750,17 +1754,20 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
switch ([event type]) {
- case NSKeyDown:
- case NSKeyUp:
+ case NSEventTypeKeyDown:
+ case NSEventTypeKeyUp:
charsIgnoringModifiers = [event charactersIgnoringModifiers];
if ([charsIgnoringModifiers length] > 0) {
keyCode = convertKey([event keyCode],
[charsIgnoringModifiers characterAtIndex:0],
- [event type] == NSKeyDown ? kUCKeyActionDown : kUCKeyActionUp);
+ [event type] == NSEventTypeKeyDown ? kUCKeyActionDown :
+ kUCKeyActionUp);
}
else {
- keyCode = convertKey(
- [event keyCode], 0, [event type] == NSKeyDown ? kUCKeyActionDown : kUCKeyActionUp);
+ keyCode = convertKey([event keyCode],
+ 0,
+ [event type] == NSEventTypeKeyDown ? kUCKeyActionDown :
+ kUCKeyActionUp);
}
/* handling both unicode or ascii */
@@ -1782,10 +1789,10 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
utf8_buf[0] = '\0';
/* no text with command key pressed */
- if (m_modifierMask & NSCommandKeyMask)
+ if (m_modifierMask & NSEventModifierFlagCommand)
utf8_buf[0] = '\0';
- if ((keyCode == GHOST_kKeyQ) && (m_modifierMask & NSCommandKeyMask))
+ if ((keyCode == GHOST_kKeyQ) && (m_modifierMask & NSEventModifierFlagCommand))
break; // Cmd-Q is directly handled by Cocoa
/* ascii is a subset of unicode */
@@ -1793,7 +1800,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
ascii = utf8_buf[0];
}
- if ([event type] == NSKeyDown) {
+ if ([event type] == NSEventTypeKeyDown) {
pushEvent(new GHOST_EventKey(
[event timestamp] * 1000, GHOST_kEventKeyDown, window, keyCode, ascii, utf8_buf));
#if 0
@@ -1824,36 +1831,39 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
m_ignoreMomentumScroll = true;
break;
- case NSFlagsChanged:
+ case NSEventTypeFlagsChanged:
modifiers = [event modifierFlags];
- if ((modifiers & NSShiftKeyMask) != (m_modifierMask & NSShiftKeyMask)) {
+ if ((modifiers & NSEventModifierFlagShift) != (m_modifierMask & NSEventModifierFlagShift)) {
pushEvent(new GHOST_EventKey([event timestamp] * 1000,
- (modifiers & NSShiftKeyMask) ? GHOST_kEventKeyDown :
- GHOST_kEventKeyUp,
+ (modifiers & NSEventModifierFlagShift) ? GHOST_kEventKeyDown :
+ GHOST_kEventKeyUp,
window,
GHOST_kKeyLeftShift));
}
- if ((modifiers & NSControlKeyMask) != (m_modifierMask & NSControlKeyMask)) {
- pushEvent(new GHOST_EventKey([event timestamp] * 1000,
- (modifiers & NSControlKeyMask) ? GHOST_kEventKeyDown :
- GHOST_kEventKeyUp,
- window,
- GHOST_kKeyLeftControl));
+ if ((modifiers & NSEventModifierFlagControl) !=
+ (m_modifierMask & NSEventModifierFlagControl)) {
+ pushEvent(new GHOST_EventKey(
+ [event timestamp] * 1000,
+ (modifiers & NSEventModifierFlagControl) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp,
+ window,
+ GHOST_kKeyLeftControl));
}
- if ((modifiers & NSAlternateKeyMask) != (m_modifierMask & NSAlternateKeyMask)) {
- pushEvent(new GHOST_EventKey([event timestamp] * 1000,
- (modifiers & NSAlternateKeyMask) ? GHOST_kEventKeyDown :
- GHOST_kEventKeyUp,
- window,
- GHOST_kKeyLeftAlt));
+ if ((modifiers & NSEventModifierFlagOption) !=
+ (m_modifierMask & NSEventModifierFlagOption)) {
+ pushEvent(new GHOST_EventKey(
+ [event timestamp] * 1000,
+ (modifiers & NSEventModifierFlagOption) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp,
+ window,
+ GHOST_kKeyLeftAlt));
}
- if ((modifiers & NSCommandKeyMask) != (m_modifierMask & NSCommandKeyMask)) {
- pushEvent(new GHOST_EventKey([event timestamp] * 1000,
- (modifiers & NSCommandKeyMask) ? GHOST_kEventKeyDown :
- GHOST_kEventKeyUp,
- window,
- GHOST_kKeyOS));
+ if ((modifiers & NSEventModifierFlagCommand) !=
+ (m_modifierMask & NSEventModifierFlagCommand)) {
+ pushEvent(new GHOST_EventKey(
+ [event timestamp] * 1000,
+ (modifiers & NSEventModifierFlagCommand) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp,
+ window,
+ GHOST_kKeyOS));
}
m_modifierMask = modifiers;
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h
index 5e857c05a09..66de8bcf7cc 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.h
+++ b/intern/ghost/intern/GHOST_WindowCocoa.h
@@ -215,6 +215,7 @@ class GHOST_WindowCocoa : public GHOST_Window {
*/
GHOST_TSuccess setOrder(GHOST_TWindowOrder order);
+ NSCursor *getStandardCursor(GHOST_TStandardCursor cursor) const;
void loadCursor(bool visible, GHOST_TStandardCursor cursor) const;
const GHOST_TabletData *GetTabletData()
@@ -296,6 +297,7 @@ class GHOST_WindowCocoa : public GHOST_Window {
* native window system calls.
*/
GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape);
+ GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor shape);
/**
* Sets the cursor shape on the window using
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index cb4100c1188..6087df978fa 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -315,8 +315,8 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
m_window = [[CocoaWindow alloc]
initWithContentRect:rect
- styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask |
- NSMiniaturizableWindowMask
+ styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
+ NSWindowStyleMaskResizable | NSWindowStyleMaskMiniaturizable
backing:NSBackingStoreBuffered
defer:NO];
@@ -550,8 +550,8 @@ void GHOST_WindowCocoa::getClientBounds(GHOST_Rect &bounds) const
// Max window contents as screen size (excluding title bar...)
NSRect contentRect = [CocoaWindow
contentRectForFrameRect:screenSize
- styleMask:(NSTitledWindowMask | NSClosableWindowMask |
- NSMiniaturizableWindowMask | NSResizableWindowMask)];
+ styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
+ NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable)];
rect = [m_window contentRectForFrameRect:[m_window frame]];
@@ -619,7 +619,7 @@ GHOST_TWindowState GHOST_WindowCocoa::getState() const
NSUInteger masks = [m_window styleMask];
- if (masks & NSFullScreenWindowMask) {
+ if (masks & NSWindowStyleMaskFullScreen) {
// Lion style fullscreen
if (!m_immediateDraw) {
state = GHOST_kWindowStateFullScreen;
@@ -748,7 +748,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
case GHOST_kWindowStateFullScreen: {
NSUInteger masks = [m_window styleMask];
- if (!(masks & NSFullScreenWindowMask)) {
+ if (!(masks & NSWindowStyleMaskFullScreen)) {
[m_window toggleFullScreen:nil];
}
break;
@@ -758,7 +758,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSUInteger masks = [m_window styleMask];
- if (masks & NSFullScreenWindowMask) {
+ if (masks & NSWindowStyleMaskFullScreen) {
// Lion style fullscreen
[m_window toggleFullScreen:nil];
}
@@ -851,7 +851,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setProgressBar(float progress)
[[NSImage imageNamed:@"NSApplicationIcon"] drawAtPoint:NSZeroPoint
fromRect:NSZeroRect
- operation:NSCompositeSourceOver
+ operation:NSCompositingOperationSourceOver
fraction:1.0];
// Track & Outline
@@ -904,7 +904,7 @@ GHOST_TSuccess GHOST_WindowCocoa::endProgressBar()
[dockIcon lockFocus];
[[NSImage imageNamed:@"NSApplicationIcon"] drawAtPoint:NSZeroPoint
fromRect:NSZeroRect
- operation:NSCompositeSourceOver
+ operation:NSCompositingOperationSourceOver
fraction:1.0];
[dockIcon unlockFocus];
[NSApp setApplicationIconImage:dockIcon];
@@ -925,12 +925,107 @@ GHOST_TSuccess GHOST_WindowCocoa::endProgressBar()
#pragma mark Cursor handling
-void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor cursor) const
+static NSCursor *getImageCursor(GHOST_TStandardCursor shape, NSString *name, NSPoint hotspot)
{
- static bool systemCursorVisible = true;
+ static NSCursor *cursors[(int)GHOST_kStandardCursorNumCursors] = {0};
+ static bool loaded[(int)GHOST_kStandardCursorNumCursors] = {false};
+
+ const int index = (int)shape;
+ if (!loaded[index]) {
+ /* Load image from file in application Resources folder. */
+ @autoreleasepool {
+ NSImage *image = [NSImage imageNamed:name];
+ if (image != NULL) {
+ cursors[index] = [[NSCursor alloc] initWithImage:image hotSpot:hotspot];
+ }
+ }
+
+ loaded[index] = true;
+ }
+
+ return cursors[index];
+}
- NSCursor *tmpCursor = nil;
+NSCursor *GHOST_WindowCocoa::getStandardCursor(GHOST_TStandardCursor shape) const
+{
+ switch (shape) {
+ case GHOST_kStandardCursorCustom:
+ if (m_customCursor) {
+ return m_customCursor;
+ }
+ else {
+ return NULL;
+ }
+ case GHOST_kStandardCursorDestroy:
+ return [NSCursor disappearingItemCursor];
+ case GHOST_kStandardCursorText:
+ return [NSCursor IBeamCursor];
+ case GHOST_kStandardCursorCrosshair:
+ return [NSCursor crosshairCursor];
+ case GHOST_kStandardCursorUpDown:
+ return [NSCursor resizeUpDownCursor];
+ case GHOST_kStandardCursorLeftRight:
+ return [NSCursor resizeLeftRightCursor];
+ case GHOST_kStandardCursorTopSide:
+ return [NSCursor resizeUpCursor];
+ case GHOST_kStandardCursorBottomSide:
+ return [NSCursor resizeDownCursor];
+ case GHOST_kStandardCursorLeftSide:
+ return [NSCursor resizeLeftCursor];
+ case GHOST_kStandardCursorRightSide:
+ return [NSCursor resizeRightCursor];
+ case GHOST_kStandardCursorCopy:
+ return [NSCursor dragCopyCursor];
+ case GHOST_kStandardCursorStop:
+ return [NSCursor operationNotAllowedCursor];
+ case GHOST_kStandardCursorMove:
+ return [NSCursor pointingHandCursor];
+ case GHOST_kStandardCursorDefault:
+ return [NSCursor arrowCursor];
+ case GHOST_kStandardCursorKnife:
+ return getImageCursor(shape, @"knife.pdf", NSMakePoint(6, 24));
+ case GHOST_kStandardCursorEraser:
+ return getImageCursor(shape, @"eraser.pdf", NSMakePoint(6, 24));
+ case GHOST_kStandardCursorPencil:
+ return getImageCursor(shape, @"pen.pdf", NSMakePoint(6, 24));
+ case GHOST_kStandardCursorEyedropper:
+ return getImageCursor(shape, @"eyedropper.pdf", NSMakePoint(6, 24));
+ case GHOST_kStandardCursorZoomIn:
+ return getImageCursor(shape, @"zoomin.pdf", NSMakePoint(8, 7));
+ case GHOST_kStandardCursorZoomOut:
+ return getImageCursor(shape, @"zoomout.pdf", NSMakePoint(8, 7));
+ case GHOST_kStandardCursorNSEWScroll:
+ return getImageCursor(shape, @"scrollnsew.pdf", NSMakePoint(16, 16));
+ case GHOST_kStandardCursorNSScroll:
+ return getImageCursor(shape, @"scrollns.pdf", NSMakePoint(16, 16));
+ case GHOST_kStandardCursorEWScroll:
+ return getImageCursor(shape, @"scrollew.pdf", NSMakePoint(16, 16));
+ case GHOST_kStandardCursorUpArrow:
+ return getImageCursor(shape, @"arrowup.pdf", NSMakePoint(16, 16));
+ case GHOST_kStandardCursorDownArrow:
+ return getImageCursor(shape, @"arrowdown.pdf", NSMakePoint(16, 16));
+ case GHOST_kStandardCursorLeftArrow:
+ return getImageCursor(shape, @"arrowleft.pdf", NSMakePoint(16, 16));
+ case GHOST_kStandardCursorRightArrow:
+ return getImageCursor(shape, @"arrowright.pdf", NSMakePoint(16, 16));
+ case GHOST_kStandardCursorVerticalSplit:
+ return getImageCursor(shape, @"splitv.pdf", NSMakePoint(16, 16));
+ case GHOST_kStandardCursorHorizontalSplit:
+ return getImageCursor(shape, @"splith.pdf", NSMakePoint(16, 16));
+ case GHOST_kStandardCursorCrosshairA:
+ return getImageCursor(shape, @"paint_cursor_cross.pdf", NSMakePoint(16, 15));
+ case GHOST_kStandardCursorCrosshairB:
+ return getImageCursor(shape, @"paint_cursor_dot.pdf", NSMakePoint(16, 15));
+ case GHOST_kStandardCursorCrosshairC:
+ return getImageCursor(shape, @"crossc.pdf", NSMakePoint(16, 16));
+ default:
+ return NULL;
+ }
+}
+void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor shape) const
+{
+ static bool systemCursorVisible = true;
if (visible != systemCursorVisible) {
if (visible) {
[NSCursor unhide];
@@ -942,57 +1037,12 @@ void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor cursor) c
}
}
- if (cursor == GHOST_kStandardCursorCustom && m_customCursor) {
- tmpCursor = m_customCursor;
- }
- else {
- switch (cursor) {
- case GHOST_kStandardCursorDestroy:
- tmpCursor = [NSCursor disappearingItemCursor];
- break;
- case GHOST_kStandardCursorText:
- tmpCursor = [NSCursor IBeamCursor];
- break;
- case GHOST_kStandardCursorCrosshair:
- tmpCursor = [NSCursor crosshairCursor];
- break;
- case GHOST_kStandardCursorUpDown:
- tmpCursor = [NSCursor resizeUpDownCursor];
- break;
- case GHOST_kStandardCursorLeftRight:
- tmpCursor = [NSCursor resizeLeftRightCursor];
- break;
- case GHOST_kStandardCursorTopSide:
- tmpCursor = [NSCursor resizeUpCursor];
- break;
- case GHOST_kStandardCursorBottomSide:
- tmpCursor = [NSCursor resizeDownCursor];
- break;
- case GHOST_kStandardCursorLeftSide:
- tmpCursor = [NSCursor resizeLeftCursor];
- break;
- case GHOST_kStandardCursorRightSide:
- tmpCursor = [NSCursor resizeRightCursor];
- break;
- case GHOST_kStandardCursorRightArrow:
- case GHOST_kStandardCursorInfo:
- case GHOST_kStandardCursorLeftArrow:
- case GHOST_kStandardCursorHelp:
- case GHOST_kStandardCursorCycle:
- case GHOST_kStandardCursorSpray:
- case GHOST_kStandardCursorWait:
- case GHOST_kStandardCursorTopLeftCorner:
- case GHOST_kStandardCursorTopRightCorner:
- case GHOST_kStandardCursorBottomRightCorner:
- case GHOST_kStandardCursorBottomLeftCorner:
- case GHOST_kStandardCursorCopy:
- case GHOST_kStandardCursorDefault:
- default:
- tmpCursor = [NSCursor arrowCursor];
- break;
- };
+ NSCursor *cursor = getStandardCursor(shape);
+ if (cursor == NULL) {
+ cursor = getStandardCursor(GHOST_kStandardCursorDefault);
}
- [tmpCursor set];
+
+ [cursor set];
}
GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible)
@@ -1047,11 +1097,6 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor sha
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- if (m_customCursor) {
- [m_customCursor release];
- m_customCursor = nil;
- }
-
if ([m_window isVisible]) {
loadCursor(getCursorVisibility(), shape);
}
@@ -1060,6 +1105,14 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor sha
return GHOST_kSuccess;
}
+GHOST_TSuccess GHOST_WindowCocoa::hasCursorShape(GHOST_TStandardCursor shape)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ GHOST_TSuccess success = (getStandardCursor(shape)) ? GHOST_kSuccess : GHOST_kFailure;
+ [pool drain];
+ return success;
+}
+
/** Reverse the bits in a GHOST_TUns8
static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
{
diff --git a/intern/ghost/intern/GHOST_WindowSDL.cpp b/intern/ghost/intern/GHOST_WindowSDL.cpp
index cd9863d7e72..99988dd55cc 100644
--- a/intern/ghost/intern/GHOST_WindowSDL.cpp
+++ b/intern/ghost/intern/GHOST_WindowSDL.cpp
@@ -301,19 +301,6 @@ static unsigned char sdl_std_cursor_top_left_corner[] = {
#define sdl_std_cursor_HOT_X_top_left_corner 0
#define sdl_std_cursor_HOT_Y_top_left_corner -14
-static unsigned char sdl_std_cursor_mask_spraycan[] = {
- 0x00, 0x0c, 0x18, 0x0d, 0x7c, 0x0d, 0x7c, 0x0d, 0x7e, 0x0d, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
- 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
-};
-static unsigned char sdl_std_cursor_spraycan[] = {
- 0x00, 0x06, 0x80, 0x00, 0x2c, 0x06, 0x9e, 0x00, 0x16, 0x06, 0x3f, 0x00, 0x21, 0x00, 0x27, 0x00,
- 0x25, 0x00, 0x27, 0x00, 0x25, 0x00, 0x27, 0x00, 0x27, 0x00, 0x21, 0x00, 0x21, 0x00, 0x3f, 0x00,
-};
-#define sdl_std_cursor_WIDTH_spraycan 12
-#define sdl_std_cursor_HEIGHT_spraycan 16
-#define sdl_std_cursor_HOT_X_spraycan -9
-#define sdl_std_cursor_HOT_Y_spraycan -14
-
static unsigned char sdl_std_cursor_mask_sb_v_double_arrow[] = {
0x38, 0x00, 0x7c, 0x00, 0xfe, 0x00, 0xff, 0x01, 0xff, 0x01, 0x7c, 0x00, 0x7c, 0x00, 0x7c,
0x00, 0x7c, 0x00, 0x7c, 0x00, 0xff, 0x01, 0xff, 0x01, 0xfe, 0x00, 0x7c, 0x00, 0x38, 0x00,
@@ -450,19 +437,6 @@ static unsigned char sdl_std_cursor_left_ptr[] = {
#define sdl_std_cursor_HOT_X_left_ptr -8
#define sdl_std_cursor_HOT_Y_left_ptr -14
-static unsigned char sdl_std_cursor_mask_exchange[] = {
- 0xe3, 0x07, 0xf7, 0x0f, 0xff, 0x1f, 0xff, 0x3f, 0x3f, 0x38, 0xff, 0x30, 0xff, 0x00, 0xff, 0x00,
- 0x00, 0xff, 0x00, 0xff, 0x0c, 0xfe, 0x1c, 0xfc, 0xfc, 0xff, 0xf8, 0xff, 0xf0, 0xef, 0xe0, 0xc7,
-};
-static unsigned char sdl_std_cursor_exchange[] = {
- 0xf1, 0x03, 0xfb, 0x07, 0x1f, 0x0c, 0x09, 0x08, 0x19, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x3f, 0x00, 0x26, 0x04, 0x24, 0x0c, 0x3e, 0xf8, 0x37, 0xf0, 0x23, 0x00, 0x00, 0x00, 0x00,
-};
-#define sdl_std_cursor_WIDTH_exchange 16
-#define sdl_std_cursor_HEIGHT_exchange 16
-#define sdl_std_cursor_HOT_X_exchange -6
-#define sdl_std_cursor_HOT_Y_exchange -8
-
static unsigned char sdl_std_cursor_mask_crosshair[] = {
0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01,
@@ -583,9 +557,9 @@ static SDL_Cursor *sdl_ghost_CreateCursor(
}
/* TODO, this is currently never freed but it wont leak either. */
-static void sdl_cursor_init(void)
+static void getStandardCursorShape(GHOST_TStandardCursor shape)
{
-
+ if (sdl_std_cursor_array[0] == NULL) {
#define DEF_CURSOR(name, ind) \
{ \
sdl_std_cursor_array[(int)ind] = sdl_ghost_CreateCursor( \
@@ -599,32 +573,32 @@ static void sdl_cursor_init(void)
} \
(void)0
- DEF_CURSOR(left_ptr, GHOST_kStandardCursorDefault);
- DEF_CURSOR(right_ptr, GHOST_kStandardCursorRightArrow);
- DEF_CURSOR(left_ptr, GHOST_kStandardCursorLeftArrow);
- DEF_CURSOR(umbrella, GHOST_kStandardCursorInfo); // TODO, replace this one.
- DEF_CURSOR(pirate, GHOST_kStandardCursorDestroy);
- DEF_CURSOR(question_arrow, GHOST_kStandardCursorHelp);
- DEF_CURSOR(exchange, GHOST_kStandardCursorCycle);
- DEF_CURSOR(spraycan, GHOST_kStandardCursorSpray);
- DEF_CURSOR(watch, GHOST_kStandardCursorWait);
- DEF_CURSOR(xterm, GHOST_kStandardCursorText);
- DEF_CURSOR(crosshair, GHOST_kStandardCursorCrosshair);
- DEF_CURSOR(sb_v_double_arrow, GHOST_kStandardCursorUpDown);
- DEF_CURSOR(sb_h_double_arrow, GHOST_kStandardCursorLeftRight);
- DEF_CURSOR(top_side, GHOST_kStandardCursorTopSide);
- DEF_CURSOR(bottom_side, GHOST_kStandardCursorBottomSide);
- DEF_CURSOR(left_side, GHOST_kStandardCursorLeftSide);
- DEF_CURSOR(right_side, GHOST_kStandardCursorRightSide);
- DEF_CURSOR(top_left_corner, GHOST_kStandardCursorTopLeftCorner);
- DEF_CURSOR(top_right_corner, GHOST_kStandardCursorTopRightCorner);
- DEF_CURSOR(bottom_right_corner, GHOST_kStandardCursorBottomRightCorner);
- DEF_CURSOR(bottom_left_corner, GHOST_kStandardCursorBottomLeftCorner);
- DEF_CURSOR(arrow, GHOST_kStandardCursorCopy);
- // DEF_CURSOR(arrow, GHOST_kStandardCursorCustom);
- DEF_CURSOR(arrow, GHOST_kStandardCursorPencil);
-
+ DEF_CURSOR(left_ptr, GHOST_kStandardCursorDefault);
+ DEF_CURSOR(right_ptr, GHOST_kStandardCursorRightArrow);
+ DEF_CURSOR(left_ptr, GHOST_kStandardCursorLeftArrow);
+ DEF_CURSOR(umbrella, GHOST_kStandardCursorInfo); // TODO, replace this one.
+ DEF_CURSOR(pirate, GHOST_kStandardCursorDestroy);
+ DEF_CURSOR(question_arrow, GHOST_kStandardCursorHelp);
+ DEF_CURSOR(watch, GHOST_kStandardCursorWait);
+ DEF_CURSOR(xterm, GHOST_kStandardCursorText);
+ DEF_CURSOR(crosshair, GHOST_kStandardCursorCrosshair);
+ DEF_CURSOR(sb_v_double_arrow, GHOST_kStandardCursorUpDown);
+ DEF_CURSOR(sb_h_double_arrow, GHOST_kStandardCursorLeftRight);
+ DEF_CURSOR(top_side, GHOST_kStandardCursorTopSide);
+ DEF_CURSOR(bottom_side, GHOST_kStandardCursorBottomSide);
+ DEF_CURSOR(left_side, GHOST_kStandardCursorLeftSide);
+ DEF_CURSOR(right_side, GHOST_kStandardCursorRightSide);
+ DEF_CURSOR(top_left_corner, GHOST_kStandardCursorTopLeftCorner);
+ DEF_CURSOR(top_right_corner, GHOST_kStandardCursorTopRightCorner);
+ DEF_CURSOR(bottom_right_corner, GHOST_kStandardCursorBottomRightCorner);
+ DEF_CURSOR(bottom_left_corner, GHOST_kStandardCursorBottomLeftCorner);
+ DEF_CURSOR(arrow, GHOST_kStandardCursorCopy);
+ // DEF_CURSOR(arrow, GHOST_kStandardCursorCustom);
+ DEF_CURSOR(arrow, GHOST_kStandardCursorPencil);
#undef DEF_CURSOR
+ }
+
+ return sdl_std_cursor_array[(int)shape];
}
GHOST_TSuccess GHOST_WindowSDL::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
@@ -634,14 +608,20 @@ GHOST_TSuccess GHOST_WindowSDL::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
GHOST_TSuccess GHOST_WindowSDL::setWindowCursorShape(GHOST_TStandardCursor shape)
{
- if (sdl_std_cursor_array[0] == NULL) {
- sdl_cursor_init();
+ SDL_Cursor *cursor = getStandardCursorShape(shape);
+ if (cursor == NULL) {
+ cursor = getStandardCursorShape(GHOST_kStandardCursorDefault);
}
- SDL_SetCursor(sdl_std_cursor_array[(int)shape]);
+ SDL_SetCursor(cursor);
return GHOST_kSuccess;
}
+GHOST_TSuccess GHOST_WindowSDL::hasCursorShape(GHOST_TStandardCursor shape)
+{
+ return (getStandardCursorShape(shape)) ? GHOST_kSuccess : GHOST_kFailure;
+}
+
GHOST_TSuccess GHOST_WindowSDL::setWindowCustomCursorShape(GHOST_TUns8 *bitmap,
GHOST_TUns8 *mask,
int sizex,
diff --git a/intern/ghost/intern/GHOST_WindowSDL.h b/intern/ghost/intern/GHOST_WindowSDL.h
index bb19b62e06d..a5c2fa9b185 100644
--- a/intern/ghost/intern/GHOST_WindowSDL.h
+++ b/intern/ghost/intern/GHOST_WindowSDL.h
@@ -100,6 +100,7 @@ class GHOST_WindowSDL : public GHOST_Window {
GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode);
GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape);
+ GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor shape);
GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap,
GHOST_TUns8 *mask,
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index e8b36c59366..d283e9e3aff 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -766,7 +766,133 @@ void GHOST_WindowWin32::registerMouseClickEvent(int press)
}
}
-void GHOST_WindowWin32::loadCursor(bool visible, GHOST_TStandardCursor cursor) const
+HCURSOR GHOST_WindowWin32::getStandardCursor(GHOST_TStandardCursor shape) const
+{
+ // Convert GHOST cursor to Windows OEM cursor
+ HANDLE cursor = NULL;
+ HMODULE module = ::GetModuleHandle(0);
+ GHOST_TUns32 flags = LR_SHARED | LR_DEFAULTSIZE;
+ int cx = 0, cy = 0;
+
+ switch (shape) {
+ case GHOST_kStandardCursorCustom:
+ if (m_customCursor) {
+ return m_customCursor;
+ }
+ else {
+ return NULL;
+ }
+ case GHOST_kStandardCursorRightArrow:
+ cursor = ::LoadImage(module, "arrowright_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorLeftArrow:
+ cursor = ::LoadImage(module, "arrowleft_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorUpArrow:
+ cursor = ::LoadImage(module, "arrowup_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorDownArrow:
+ cursor = ::LoadImage(module, "arrowdown_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorVerticalSplit:
+ cursor = ::LoadImage(module, "splitv_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorHorizontalSplit:
+ cursor = ::LoadImage(module, "splith_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorKnife:
+ cursor = ::LoadImage(module, "knife_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorEyedropper:
+ cursor = ::LoadImage(module, "eyedropper_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorZoomIn:
+ cursor = ::LoadImage(module, "zoomin_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorZoomOut:
+ cursor = ::LoadImage(module, "zoomout_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorMove:
+ cursor = ::LoadImage(module, "handopen_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorNSEWScroll:
+ cursor = ::LoadImage(module, "scrollnsew_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorNSScroll:
+ cursor = ::LoadImage(module, "scrollns_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorEWScroll:
+ cursor = ::LoadImage(module, "scrollew_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorHelp:
+ cursor = ::LoadImage(NULL, IDC_HELP, IMAGE_CURSOR, cx, cy, flags);
+ break; // Arrow and question mark
+ case GHOST_kStandardCursorWait:
+ cursor = ::LoadImage(NULL, IDC_WAIT, IMAGE_CURSOR, cx, cy, flags);
+ break; // Hourglass
+ case GHOST_kStandardCursorText:
+ cursor = ::LoadImage(NULL, IDC_IBEAM, IMAGE_CURSOR, cx, cy, flags);
+ break; // I-beam
+ case GHOST_kStandardCursorCrosshair:
+ cursor = ::LoadImage(module, "cross_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break; // Standard Cross
+ case GHOST_kStandardCursorCrosshairA:
+ cursor = ::LoadImage(module, "crossA_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break; // Crosshair A
+ case GHOST_kStandardCursorCrosshairB:
+ cursor = ::LoadImage(module, "crossB_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break; // Diagonal Crosshair B
+ case GHOST_kStandardCursorCrosshairC:
+ cursor = ::LoadImage(module, "crossC_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break; // Minimal Crosshair C
+ case GHOST_kStandardCursorBottomSide:
+ case GHOST_kStandardCursorUpDown:
+ cursor = ::LoadImage(module, "movens_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break; // Double-pointed arrow pointing north and south
+ case GHOST_kStandardCursorLeftSide:
+ case GHOST_kStandardCursorLeftRight:
+ cursor = ::LoadImage(module, "moveew_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break; // Double-pointed arrow pointing west and east
+ case GHOST_kStandardCursorTopSide:
+ cursor = ::LoadImage(NULL, IDC_UPARROW, IMAGE_CURSOR, cx, cy, flags);
+ break; // Vertical arrow
+ case GHOST_kStandardCursorTopLeftCorner:
+ cursor = ::LoadImage(NULL, IDC_SIZENWSE, IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorTopRightCorner:
+ cursor = ::LoadImage(NULL, IDC_SIZENESW, IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorBottomRightCorner:
+ cursor = ::LoadImage(NULL, IDC_SIZENWSE, IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorBottomLeftCorner:
+ cursor = ::LoadImage(NULL, IDC_SIZENESW, IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorPencil:
+ cursor = ::LoadImage(module, "pencil_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorEraser:
+ cursor = ::LoadImage(module, "eraser_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorDestroy:
+ case GHOST_kStandardCursorStop:
+ cursor = ::LoadImage(module, "forbidden_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break; // Slashed circle
+ case GHOST_kStandardCursorDefault:
+ cursor = NULL;
+ break;
+ default:
+ return NULL;
+ }
+
+ if (cursor == NULL) {
+ cursor = ::LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, cx, cy, flags);
+ }
+
+ return (HCURSOR)cursor;
+}
+
+void GHOST_WindowWin32::loadCursor(bool visible, GHOST_TStandardCursor shape) const
{
if (!visible) {
while (::ShowCursor(FALSE) >= 0)
@@ -777,88 +903,11 @@ void GHOST_WindowWin32::loadCursor(bool visible, GHOST_TStandardCursor cursor) c
;
}
- if (cursor == GHOST_kStandardCursorCustom && m_customCursor) {
- ::SetCursor(m_customCursor);
- }
- else {
- // Convert GHOST cursor to Windows OEM cursor
- bool success = true;
- LPCSTR id;
- switch (cursor) {
- case GHOST_kStandardCursorDefault:
- id = IDC_ARROW;
- break;
- case GHOST_kStandardCursorRightArrow:
- id = IDC_ARROW;
- break;
- case GHOST_kStandardCursorLeftArrow:
- id = IDC_ARROW;
- break;
- case GHOST_kStandardCursorInfo:
- id = IDC_SIZEALL;
- break; // Four-pointed arrow pointing north, south, east, and west
- case GHOST_kStandardCursorDestroy:
- id = IDC_NO;
- break; // Slashed circle
- case GHOST_kStandardCursorHelp:
- id = IDC_HELP;
- break; // Arrow and question mark
- case GHOST_kStandardCursorCycle:
- id = IDC_NO;
- break; // Slashed circle
- case GHOST_kStandardCursorSpray:
- id = IDC_SIZEALL;
- break; // Four-pointed arrow pointing north, south, east, and west
- case GHOST_kStandardCursorWait:
- id = IDC_WAIT;
- break; // Hourglass
- case GHOST_kStandardCursorText:
- id = IDC_IBEAM;
- break; // I-beam
- case GHOST_kStandardCursorCrosshair:
- id = IDC_CROSS;
- break; // Crosshair
- case GHOST_kStandardCursorUpDown:
- id = IDC_SIZENS;
- break; // Double-pointed arrow pointing north and south
- case GHOST_kStandardCursorLeftRight:
- id = IDC_SIZEWE;
- break; // Double-pointed arrow pointing west and east
- case GHOST_kStandardCursorTopSide:
- id = IDC_UPARROW;
- break; // Vertical arrow
- case GHOST_kStandardCursorBottomSide:
- id = IDC_SIZENS;
- break;
- case GHOST_kStandardCursorLeftSide:
- id = IDC_SIZEWE;
- break;
- case GHOST_kStandardCursorTopLeftCorner:
- id = IDC_SIZENWSE;
- break;
- case GHOST_kStandardCursorTopRightCorner:
- id = IDC_SIZENESW;
- break;
- case GHOST_kStandardCursorBottomRightCorner:
- id = IDC_SIZENWSE;
- break;
- case GHOST_kStandardCursorBottomLeftCorner:
- id = IDC_SIZENESW;
- break;
- case GHOST_kStandardCursorPencil:
- id = IDC_ARROW;
- break;
- case GHOST_kStandardCursorCopy:
- id = IDC_ARROW;
- break;
- default:
- success = false;
- }
-
- if (success) {
- ::SetCursor(::LoadCursor(0, id));
- }
+ HCURSOR cursor = getStandardCursor(shape);
+ if (cursor == NULL) {
+ cursor = getStandardCursor(GHOST_kStandardCursorDefault);
}
+ ::SetCursor(cursor);
}
GHOST_TSuccess GHOST_WindowWin32::setWindowCursorVisibility(bool visible)
@@ -908,11 +957,6 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode
GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cursorShape)
{
- if (m_customCursor) {
- DestroyCursor(m_customCursor);
- m_customCursor = NULL;
- }
-
if (::GetForegroundWindow() == m_hWnd) {
loadCursor(getCursorVisibility(), cursorShape);
}
@@ -920,6 +964,11 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cur
return GHOST_kSuccess;
}
+GHOST_TSuccess GHOST_WindowWin32::hasCursorShape(GHOST_TStandardCursor cursorShape)
+{
+ return (getStandardCursor(cursorShape)) ? GHOST_kSuccess : GHOST_kFailure;
+}
+
GHOST_TSuccess GHOST_WindowWin32::getPointerInfo(GHOST_PointerInfoWin32 *pointerInfo,
WPARAM wParam,
LPARAM lParam)
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index cf7177b0062..8dac142d6f4 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -386,6 +386,7 @@ class GHOST_WindowWin32 : public GHOST_Window {
* \param visible Flag for cursor visibility.
* \param cursorShape The cursor shape.
*/
+ HCURSOR getStandardCursor(GHOST_TStandardCursor shape) const;
void loadCursor(bool visible, GHOST_TStandardCursor cursorShape) const;
const GHOST_TabletData *GetTabletData()
@@ -456,6 +457,7 @@ class GHOST_WindowWin32 : public GHOST_Window {
* native window system calls.
*/
GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape);
+ GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor shape);
/**
* Sets the cursor shape on the window using
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index 166fea8a84b..8aa4a4e284a 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -1284,77 +1284,70 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type
return NULL;
}
-Cursor GHOST_WindowX11::getStandardCursor(GHOST_TStandardCursor g_cursor)
+GHOST_TSuccess GHOST_WindowX11::getStandardCursor(GHOST_TStandardCursor g_cursor, Cursor &xcursor)
{
unsigned int xcursor_id;
-#define GtoX(gcurs, xcurs) \
- case gcurs: \
- xcursor_id = xcurs
switch (g_cursor) {
- GtoX(GHOST_kStandardCursorRightArrow, XC_arrow);
- break;
- GtoX(GHOST_kStandardCursorLeftArrow, XC_top_left_arrow);
- break;
- GtoX(GHOST_kStandardCursorInfo, XC_hand1);
- break;
- GtoX(GHOST_kStandardCursorDestroy, XC_pirate);
- break;
- GtoX(GHOST_kStandardCursorHelp, XC_question_arrow);
- break;
- GtoX(GHOST_kStandardCursorCycle, XC_exchange);
- break;
- GtoX(GHOST_kStandardCursorSpray, XC_spraycan);
- break;
- GtoX(GHOST_kStandardCursorWait, XC_watch);
- break;
- GtoX(GHOST_kStandardCursorText, XC_xterm);
- break;
- GtoX(GHOST_kStandardCursorCrosshair, XC_crosshair);
- break;
- GtoX(GHOST_kStandardCursorUpDown, XC_sb_v_double_arrow);
- break;
- GtoX(GHOST_kStandardCursorLeftRight, XC_sb_h_double_arrow);
- break;
- GtoX(GHOST_kStandardCursorTopSide, XC_top_side);
- break;
- GtoX(GHOST_kStandardCursorBottomSide, XC_bottom_side);
- break;
- GtoX(GHOST_kStandardCursorLeftSide, XC_left_side);
- break;
- GtoX(GHOST_kStandardCursorRightSide, XC_right_side);
- break;
- GtoX(GHOST_kStandardCursorTopLeftCorner, XC_top_left_corner);
- break;
- GtoX(GHOST_kStandardCursorTopRightCorner, XC_top_right_corner);
- break;
- GtoX(GHOST_kStandardCursorBottomRightCorner, XC_bottom_right_corner);
- break;
- GtoX(GHOST_kStandardCursorBottomLeftCorner, XC_bottom_left_corner);
- break;
- GtoX(GHOST_kStandardCursorPencil, XC_pencil);
- break;
- GtoX(GHOST_kStandardCursorCopy, XC_arrow);
- break;
+ case GHOST_kStandardCursorHelp:
+ xcursor_id = XC_question_arrow;
+ break;
+ case GHOST_kStandardCursorWait:
+ xcursor_id = XC_watch;
+ break;
+ case GHOST_kStandardCursorText:
+ xcursor_id = XC_xterm;
+ break;
+ case GHOST_kStandardCursorCrosshair:
+ xcursor_id = XC_crosshair;
+ break;
+ case GHOST_kStandardCursorUpDown:
+ xcursor_id = XC_sb_v_double_arrow;
+ break;
+ case GHOST_kStandardCursorLeftRight:
+ xcursor_id = XC_sb_h_double_arrow;
+ break;
+ case GHOST_kStandardCursorTopSide:
+ xcursor_id = XC_top_side;
+ break;
+ case GHOST_kStandardCursorBottomSide:
+ xcursor_id = XC_bottom_side;
+ break;
+ case GHOST_kStandardCursorLeftSide:
+ xcursor_id = XC_left_side;
+ break;
+ case GHOST_kStandardCursorRightSide:
+ xcursor_id = XC_right_side;
+ break;
+ case GHOST_kStandardCursorTopLeftCorner:
+ xcursor_id = XC_top_left_corner;
+ break;
+ case GHOST_kStandardCursorTopRightCorner:
+ xcursor_id = XC_top_right_corner;
+ break;
+ case GHOST_kStandardCursorBottomRightCorner:
+ xcursor_id = XC_bottom_right_corner;
+ break;
+ case GHOST_kStandardCursorBottomLeftCorner:
+ xcursor_id = XC_bottom_left_corner;
+ break;
+ case GHOST_kStandardCursorDefault:
+ xcursor = None;
+ return GHOST_kSuccess;
default:
- xcursor_id = 0;
+ xcursor = None;
+ return GHOST_kFailure;
}
-#undef GtoX
- if (xcursor_id) {
- Cursor xcursor = m_standard_cursors[xcursor_id];
+ xcursor = m_standard_cursors[xcursor_id];
- if (!xcursor) {
- xcursor = XCreateFontCursor(m_display, xcursor_id);
+ if (!xcursor) {
+ xcursor = XCreateFontCursor(m_display, xcursor_id);
- m_standard_cursors[xcursor_id] = xcursor;
- }
-
- return xcursor;
- }
- else {
- return None;
+ m_standard_cursors[xcursor_id] = xcursor;
}
+
+ return GHOST_kSuccess;
}
Cursor GHOST_WindowX11::getEmptyCursor()
@@ -1380,10 +1373,12 @@ GHOST_TSuccess GHOST_WindowX11::setWindowCursorVisibility(bool visible)
Cursor xcursor;
if (visible) {
- if (m_visible_cursor)
+ if (m_visible_cursor) {
xcursor = m_visible_cursor;
- else
- xcursor = getStandardCursor(getCursorShape());
+ }
+ else if (getStandardCursor(getCursorShape(), xcursor) == GHOST_kFailure) {
+ getStandardCursor(getCursorShape(), xcursor);
+ }
}
else {
xcursor = getEmptyCursor();
@@ -1463,7 +1458,10 @@ GHOST_TSuccess GHOST_WindowX11::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
GHOST_TSuccess GHOST_WindowX11::setWindowCursorShape(GHOST_TStandardCursor shape)
{
- Cursor xcursor = getStandardCursor(shape);
+ Cursor xcursor;
+ if (getStandardCursor(shape, xcursor) == GHOST_kFailure) {
+ getStandardCursor(GHOST_kStandardCursorDefault, xcursor);
+ }
m_visible_cursor = xcursor;
@@ -1473,6 +1471,12 @@ GHOST_TSuccess GHOST_WindowX11::setWindowCursorShape(GHOST_TStandardCursor shape
return GHOST_kSuccess;
}
+GHOST_TSuccess GHOST_WindowX11::hasCursorShape(GHOST_TStandardCursor shape)
+{
+ Cursor xcursor;
+ return getStandardCursor(shape, xcursor);
+}
+
GHOST_TSuccess GHOST_WindowX11::setWindowCustomCursorShape(GHOST_TUns8 *bitmap,
GHOST_TUns8 *mask,
int sizex,
diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h
index 83e0a2b59db..0b8fe3a3a41 100644
--- a/intern/ghost/intern/GHOST_WindowX11.h
+++ b/intern/ghost/intern/GHOST_WindowX11.h
@@ -213,6 +213,7 @@ class GHOST_WindowX11 : public GHOST_Window {
* native window system calls.
*/
GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape);
+ GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor shape);
/**
* Sets the cursor shape on the window using
@@ -233,7 +234,7 @@ class GHOST_WindowX11 : public GHOST_Window {
GHOST_WindowX11(const GHOST_WindowX11 &);
- Cursor getStandardCursor(GHOST_TStandardCursor g_cursor);
+ GHOST_TSuccess getStandardCursor(GHOST_TStandardCursor g_cursor, Cursor &xcursor);
Cursor getEmptyCursor();
diff --git a/intern/guardedalloc/intern/mallocn.c b/intern/guardedalloc/intern/mallocn.c
index 1c96856fd0d..fa2d0d1e334 100644
--- a/intern/guardedalloc/intern/mallocn.c
+++ b/intern/guardedalloc/intern/mallocn.c
@@ -72,14 +72,7 @@ void *aligned_malloc(size_t size, size_t alignment)
{
#ifdef _WIN32
return _aligned_malloc(size, alignment);
-#elif defined(__APPLE__)
- /* On Mac OS X, both the heap and the stack are guaranteed 16-byte aligned so
- * they work natively with SSE types with no further work.
- */
- assert(alignment == 16);
- (void)alignment;
- return malloc(size);
-#elif defined(__FreeBSD__) || defined(__NetBSD__)
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
void *result;
if (posix_memalign(&result, alignment, size)) {
diff --git a/intern/libmv/libmv/autotrack/callbacks.h b/intern/libmv/libmv/autotrack/callbacks.h
index e65841de3ce..ee3d2eeb7c3 100644
--- a/intern/libmv/libmv/autotrack/callbacks.h
+++ b/intern/libmv/libmv/autotrack/callbacks.h
@@ -27,7 +27,7 @@ namespace mv {
struct OperationListener {
// All hooks return true to continue or false to indicate the operation
- // should abort. Hooks should be thread safe (reentrant).
+ // should abort. Hooks should be thread safe (re-entrant).
virtual bool Log(const string& message) = 0;
virtual bool Progress(double fraction) = 0;
virtual bool Cancelled() = 0;
diff --git a/intern/libmv/libmv/base/aligned_malloc.cc b/intern/libmv/libmv/base/aligned_malloc.cc
index cc0a5fbbba7..5d3e05e9df9 100644
--- a/intern/libmv/libmv/base/aligned_malloc.cc
+++ b/intern/libmv/libmv/base/aligned_malloc.cc
@@ -44,12 +44,7 @@ namespace libmv {
void *aligned_malloc(int size, int alignment) {
#ifdef _WIN32
return _aligned_malloc(size, alignment);
-#elif defined(__APPLE__)
- // On Mac OS X, both the heap and the stack are guaranteed 16-byte aligned so
- // they work natively with SSE types with no further work.
- CHECK_EQ(alignment, 16);
- return malloc(size);
-#elif defined(__FreeBSD__) || defined(__NetBSD__)
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
void *result;
if (posix_memalign(&result, alignment, size)) {
diff --git a/intern/libmv/libmv/tracking/brute_region_tracker.cc b/intern/libmv/libmv/tracking/brute_region_tracker.cc
index 4a2aef63a96..85aecb7f633 100644
--- a/intern/libmv/libmv/tracking/brute_region_tracker.cc
+++ b/intern/libmv/libmv/tracking/brute_region_tracker.cc
@@ -110,6 +110,8 @@ inline static __m128i SumOfAbsoluteDifferencesContiguousSSE(
case 13: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0); break;
case 14: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 0); break;
case 15: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0); break;
+ // To silence compiler warning.
+ default: mask = _mm_setzero_si128(); break;
#undef X
}
sad = _mm_add_epi32(sad, _mm_sad_epu8(_mm_and_si128(mask, a_trail),
diff --git a/intern/memutil/MEM_RefCounted.h b/intern/memutil/MEM_RefCounted.h
index 28b24d04586..42e595aadf4 100644
--- a/intern/memutil/MEM_RefCounted.h
+++ b/intern/memutil/MEM_RefCounted.h
@@ -34,8 +34,8 @@
* The default destructor of this object has been made protected on purpose.
* This disables the creation of shared objects on the stack.
*
- * @author Maarten Gribnau
- * @date March 31, 2001
+ * \author Maarten Gribnau
+ * \date March 31, 2001
*/
class MEM_RefCounted {
@@ -49,20 +49,20 @@ class MEM_RefCounted {
/**
* Returns the reference count of this object.
- * @return the reference count.
+ * \return the reference count.
*/
inline virtual int getRef() const;
/**
* Increases the reference count of this object.
- * @return the new reference count.
+ * \return the new reference count.
*/
inline virtual int incRef();
/**
* Decreases the reference count of this object.
* If the reference count reaches zero, the object self-destructs.
- * @return the new reference count.
+ * \return the new reference count.
*/
inline virtual int decRef();
diff --git a/intern/quadriflow/CMakeLists.txt b/intern/quadriflow/CMakeLists.txt
new file mode 100644
index 00000000000..615d5a34ce6
--- /dev/null
+++ b/intern/quadriflow/CMakeLists.txt
@@ -0,0 +1,45 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2019, Blender Foundation
+# All rights reserved.
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ../guardedalloc
+)
+
+set(INC_SYS
+ ../../extern/quadriflow/src
+ ${BOOST_INCLUDE_DIR}
+ ${EIGEN3_INCLUDE_DIRS}
+)
+
+set(SRC
+ quadriflow_capi.cpp
+ quadriflow_capi.hpp
+)
+
+set(LIB
+ extern_quadriflow
+)
+
+if (WIN32)
+ add_definitions(-D_USE_MATH_DEFINES)
+endif()
+
+blender_add_lib(bf_intern_quadriflow "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/intern/quadriflow/quadriflow_capi.cpp b/intern/quadriflow/quadriflow_capi.cpp
new file mode 100644
index 00000000000..302c7a0ae30
--- /dev/null
+++ b/intern/quadriflow/quadriflow_capi.cpp
@@ -0,0 +1,238 @@
+// Copyright 2019 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sebastian Parborg, Pablo Dobarro
+
+#include <unordered_map>
+
+#include "MEM_guardedalloc.h"
+
+#include "quadriflow_capi.hpp"
+#include "config.hpp"
+#include "field-math.hpp"
+#include "optimizer.hpp"
+#include "parametrizer.hpp"
+#include "loader.hpp"
+
+using namespace qflow;
+
+struct ObjVertex {
+ uint32_t p = (uint32_t)-1;
+ uint32_t n = (uint32_t)-1;
+ uint32_t uv = (uint32_t)-1;
+
+ ObjVertex()
+ {
+ }
+
+ ObjVertex(uint32_t pi)
+ {
+ p = pi;
+ }
+
+ bool operator==(const ObjVertex &v) const
+ {
+ return v.p == p && v.n == n && v.uv == uv;
+ }
+};
+
+struct ObjVertexHash : std::unary_function<ObjVertex, size_t> {
+ std::size_t operator()(const ObjVertex &v) const
+ {
+ size_t hash = std::hash<uint32_t>()(v.p);
+ hash = hash * 37 + std::hash<uint32_t>()(v.uv);
+ hash = hash * 37 + std::hash<uint32_t>()(v.n);
+ return hash;
+ }
+};
+
+typedef std::unordered_map<ObjVertex, uint32_t, ObjVertexHash> VertexMap;
+
+static int check_if_canceled(float progress,
+ void (*update_cb)(void *, float progress, int *cancel),
+ void *update_cb_data)
+{
+ int cancel = 0;
+ update_cb(update_cb_data, progress, &cancel);
+ return cancel;
+}
+
+void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd,
+ void (*update_cb)(void *, float progress, int *cancel),
+ void *update_cb_data)
+{
+ Parametrizer field;
+ VertexMap vertexMap;
+
+ /* Get remeshing parameters. */
+ int faces = qrd->target_faces;
+
+ if (qrd->preserve_sharp) {
+ field.flag_preserve_sharp = 1;
+ }
+ if (qrd->preserve_boundary) {
+ field.flag_preserve_boundary = 1;
+ }
+ if (qrd->adaptive_scale) {
+ field.flag_adaptive_scale = 1;
+ }
+ if (qrd->minimum_cost_flow) {
+ field.flag_minimum_cost_flow = 1;
+ }
+ if (qrd->aggresive_sat) {
+ field.flag_aggresive_sat = 1;
+ }
+ if (qrd->rng_seed) {
+ field.hierarchy.rng_seed = qrd->rng_seed;
+ }
+
+ if (check_if_canceled(0.0f, update_cb, update_cb_data) != 0) {
+ return;
+ }
+
+ /* Copy mesh to quadriflow data structures. */
+ std::vector<Vector3d> positions;
+ std::vector<uint32_t> indices;
+ std::vector<ObjVertex> vertices;
+
+ for (int i = 0; i < qrd->totverts; i++) {
+ Vector3d v(qrd->verts[i * 3], qrd->verts[i * 3 + 1], qrd->verts[i * 3 + 2]);
+ positions.push_back(v);
+ }
+
+ for (int q = 0; q < qrd->totfaces; q++) {
+ Vector3i f(qrd->faces[q * 3], qrd->faces[q * 3 + 1], qrd->faces[q * 3 + 2]);
+
+ ObjVertex tri[6];
+ int nVertices = 3;
+
+ tri[0] = ObjVertex(f[0]);
+ tri[1] = ObjVertex(f[1]);
+ tri[2] = ObjVertex(f[2]);
+
+ for (int i = 0; i < nVertices; ++i) {
+ const ObjVertex &v = tri[i];
+ VertexMap::const_iterator it = vertexMap.find(v);
+ if (it == vertexMap.end()) {
+ vertexMap[v] = (uint32_t)vertices.size();
+ indices.push_back((uint32_t)vertices.size());
+ vertices.push_back(v);
+ }
+ else {
+ indices.push_back(it->second);
+ }
+ }
+ }
+
+ field.F.resize(3, indices.size() / 3);
+ memcpy(field.F.data(), indices.data(), sizeof(uint32_t) * indices.size());
+
+ field.V.resize(3, vertices.size());
+ for (uint32_t i = 0; i < vertices.size(); ++i) {
+ field.V.col(i) = positions.at(vertices[i].p);
+ }
+
+ if (check_if_canceled(0.1f, update_cb, update_cb_data)) {
+ return;
+ }
+
+ /* Start processing the input mesh data */
+ field.NormalizeMesh();
+ field.Initialize(faces);
+
+ if (check_if_canceled(0.2f, update_cb, update_cb_data)) {
+ return;
+ }
+
+ /* Setup mesh boundary constraints if needed */
+ if (field.flag_preserve_boundary) {
+ Hierarchy &mRes = field.hierarchy;
+ mRes.clearConstraints();
+ for (uint32_t i = 0; i < 3 * mRes.mF.cols(); ++i) {
+ if (mRes.mE2E[i] == -1) {
+ uint32_t i0 = mRes.mF(i % 3, i / 3);
+ uint32_t i1 = mRes.mF((i + 1) % 3, i / 3);
+ Vector3d p0 = mRes.mV[0].col(i0), p1 = mRes.mV[0].col(i1);
+ Vector3d edge = p1 - p0;
+ if (edge.squaredNorm() > 0) {
+ edge.normalize();
+ mRes.mCO[0].col(i0) = p0;
+ mRes.mCO[0].col(i1) = p1;
+ mRes.mCQ[0].col(i0) = mRes.mCQ[0].col(i1) = edge;
+ mRes.mCQw[0][i0] = mRes.mCQw[0][i1] = mRes.mCOw[0][i0] = mRes.mCOw[0][i1] = 1.0;
+ }
+ }
+ }
+ mRes.propagateConstraints();
+ }
+
+ /* Optimize the mesh field orientations (tangental field etc) */
+ Optimizer::optimize_orientations(field.hierarchy);
+ field.ComputeOrientationSingularities();
+
+ if (check_if_canceled(0.3f, update_cb, update_cb_data)) {
+ return;
+ }
+
+ if (field.flag_adaptive_scale == 1) {
+ field.EstimateSlope();
+ }
+
+ if (check_if_canceled(0.4f, update_cb, update_cb_data)) {
+ return;
+ }
+
+ Optimizer::optimize_scale(field.hierarchy, field.rho, field.flag_adaptive_scale);
+ field.flag_adaptive_scale = 1;
+
+ Optimizer::optimize_positions(field.hierarchy, field.flag_adaptive_scale);
+
+ field.ComputePositionSingularities();
+
+ if (check_if_canceled(0.5f, update_cb, update_cb_data)) {
+ return;
+ }
+
+ /* Compute the final quad geomtry using a maxflow solver */
+ field.ComputeIndexMap();
+
+ if (check_if_canceled(0.9f, update_cb, update_cb_data)) {
+ return;
+ }
+
+ /* Get the output mesh data */
+ qrd->out_totverts = field.O_compact.size();
+ qrd->out_totfaces = field.F_compact.size();
+
+ qrd->out_verts = (float *)MEM_malloc_arrayN(
+ qrd->out_totverts, 3 * sizeof(float), "quadriflow remesher out verts");
+ qrd->out_faces = (unsigned int *)MEM_malloc_arrayN(
+ qrd->out_totfaces, 4 * sizeof(unsigned int), "quadriflow remesh out quads");
+
+ for (int i = 0; i < qrd->out_totverts; i++) {
+ auto t = field.O_compact[i] * field.normalize_scale + field.normalize_offset;
+ qrd->out_verts[i * 3] = t[0];
+ qrd->out_verts[i * 3 + 1] = t[1];
+ qrd->out_verts[i * 3 + 2] = t[2];
+ }
+
+ for (int i = 0; i < qrd->out_totfaces; i++) {
+ qrd->out_faces[i * 4] = field.F_compact[i][0];
+ qrd->out_faces[i * 4 + 1] = field.F_compact[i][1];
+ qrd->out_faces[i * 4 + 2] = field.F_compact[i][2];
+ qrd->out_faces[i * 4 + 3] = field.F_compact[i][3];
+ }
+}
diff --git a/intern/quadriflow/quadriflow_capi.hpp b/intern/quadriflow/quadriflow_capi.hpp
new file mode 100644
index 00000000000..c31fd6eff95
--- /dev/null
+++ b/intern/quadriflow/quadriflow_capi.hpp
@@ -0,0 +1,54 @@
+// Copyright 2019 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sebastian Parborg, Pablo Dobarro
+
+#ifndef QUADRIFLOW_CAPI_HPP
+#define QUADRIFLOW_CAPI_HPP
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct QuadriflowRemeshData {
+ float *verts;
+ unsigned int *faces;
+ int totfaces;
+ int totverts;
+
+ float *out_verts;
+ unsigned int *out_faces;
+ int out_totverts;
+ int out_totfaces;
+
+ int target_faces;
+ bool preserve_sharp;
+ bool preserve_boundary;
+ bool adaptive_scale;
+ bool minimum_cost_flow;
+ bool aggresive_sat;
+ int rng_seed;
+} QuadriflowRemeshData;
+
+void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd,
+ void (*update_cb)(void *, float progress, int *cancel),
+ void *update_cb_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // QUADRIFLOW_CAPI_HPP
diff --git a/intern/utfconv/utfconv.h b/intern/utfconv/utfconv.h
index befaeae63de..46c07500bf7 100644
--- a/intern/utfconv/utfconv.h
+++ b/intern/utfconv/utfconv.h
@@ -31,15 +31,15 @@ extern "C" {
/**
* Counts how many bytes is requered for for future utf-8 string using utf-16
- * @param string-16 pointer to working utf-16 string
- * @return How many bytes must be allocated includeng NULL.
+ * \param string16: pointer to working utf-16 string
+ * \return How many bytes must be allocated includeng NULL.
*/
size_t count_utf_8_from_16(const wchar_t *string16);
/**
* Counts how many wchar_t (two byte) is requered for for future utf-16 string using utf-8
- * @param string-8 pointer to working utf-8 string
- * @return How many bytes must be allocated includeng NULL.
+ * \param string8: pointer to working utf-8 string
+ * \return How many bytes must be allocated includeng NULL.
*/
size_t count_utf_16_from_8(const char *string8);
@@ -54,36 +54,36 @@ size_t count_utf_16_from_8(const char *string8);
/**
* Converts utf-16 string to allocated utf-8 string
- * @param in16 utf-16 string to convert
- * @param out8 utf-8 string to string the conversion
- * @param size8 the allocated size in bytes of out8
- * @return Returns any errors occured during conversion. See the block above,
+ * \param in16: utf-16 string to convert
+ * \param out8: utf-8 string to string the conversion
+ * \param size8: the allocated size in bytes of out8
+ * \return Returns any errors occured during conversion. See the block above,
*/
int conv_utf_16_to_8(const wchar_t *in16, char *out8, size_t size8);
/**
* Converts utf-8 string to allocated utf-16 string
- * @param in8 utf-8 string to convert
- * @param out16 utf-16 string to string the conversion
- * @param size16 the allocated size in wchar_t (two byte) of out16
- * @return Returns any errors occured during conversion. See the block above,
+ * \param in8: utf-8 string to convert
+ * \param out16: utf-16 string to string the conversion
+ * \param size16: the allocated size in wchar_t (two byte) of out16
+ * \return Returns any errors occured during conversion. See the block above,
*/
int conv_utf_8_to_16(const char *in8, wchar_t *out16, size_t size16);
/**
* Allocates and converts the utf-8 string from utf-16
- * @param in16 utf-16 string to convert
- * @param add any additional size which will be allocated for new utf-8 string in bytes
- * @return New allocated and converted utf-8 string or NULL if in16 is 0.
+ * \param in16: utf-16 string to convert
+ * \param add: any additional size which will be allocated for new utf-8 string in bytes
+ * \return New allocated and converted utf-8 string or NULL if in16 is 0.
*/
char *alloc_utf_8_from_16(const wchar_t *in16, size_t add);
/**
* Allocates and converts the utf-16 string from utf-8
- * @param in8 utf-8 string to convert
- * @param add any additional size which will be allocated for new utf-16 string
+ * \param in8: utf-8 string to convert
+ * \param add: any additional size which will be allocated for new utf-16 string
* in wchar_t (two bytes)
- * @return New allocated and converted utf-16 string or NULL if in8 is 0.
+ * \return New allocated and converted utf-16 string or NULL if in8 is 0.
*/
wchar_t *alloc_utf16_from_8(const char *in8, size_t add);
diff --git a/make.bat b/make.bat
index b0323cde1bb..ea80bd591f7 100644
--- a/make.bat
+++ b/make.bat
@@ -26,12 +26,6 @@ if "%SHOW_HELP%" == "1" (
goto EOF
)
-if "%BUILD_UPDATE%" == "1" (
- call "%BLENDER_DIR%\build_files\windows\update_sources.cmd"
- goto EOF
-)
-
-
if "%FORMAT%" == "1" (
call "%BLENDER_DIR%\build_files\windows\format.cmd"
goto EOF
@@ -54,6 +48,14 @@ if "%BUILD_VS_YEAR%" == "" (
)
)
+if "%BUILD_UPDATE%" == "1" (
+ call "%BLENDER_DIR%\build_files\windows\check_libraries.cmd"
+ if errorlevel 1 goto EOF
+
+ call "%BLENDER_DIR%\build_files\windows\update_sources.cmd"
+ goto EOF
+)
+
call "%BLENDER_DIR%\build_files\windows\set_build_dir.cmd"
echo Building blender with VS%BUILD_VS_YEAR% for %BUILD_ARCH% in %BUILD_DIR%
@@ -61,6 +63,11 @@ echo Building blender with VS%BUILD_VS_YEAR% for %BUILD_ARCH% in %BUILD_DIR%
call "%BLENDER_DIR%\build_files\windows\check_libraries.cmd"
if errorlevel 1 goto EOF
+if "%TEST%" == "1" (
+ call "%BLENDER_DIR%\build_files\windows\test.cmd"
+ goto EOF
+)
+
call "%BLENDER_DIR%\build_files\windows\check_submodules.cmd"
if errorlevel 1 goto EOF
diff --git a/release/darwin/Blender.app/Contents/Resources/arrowdown.pdf b/release/darwin/Blender.app/Contents/Resources/arrowdown.pdf
new file mode 100644
index 00000000000..8a262b21010
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/arrowdown.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/arrowleft.pdf b/release/darwin/Blender.app/Contents/Resources/arrowleft.pdf
new file mode 100644
index 00000000000..1ca740b6d70
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/arrowleft.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/arrowright.pdf b/release/darwin/Blender.app/Contents/Resources/arrowright.pdf
new file mode 100644
index 00000000000..c8c657f02a0
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/arrowright.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/arrowup.pdf b/release/darwin/Blender.app/Contents/Resources/arrowup.pdf
new file mode 100644
index 00000000000..2a74e8b293e
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/arrowup.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/crossc.pdf b/release/darwin/Blender.app/Contents/Resources/crossc.pdf
new file mode 100644
index 00000000000..a6bb7a4ef01
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/crossc.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/eraser.pdf b/release/darwin/Blender.app/Contents/Resources/eraser.pdf
new file mode 100644
index 00000000000..5a56be7006b
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/eraser.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/eyedropper.pdf b/release/darwin/Blender.app/Contents/Resources/eyedropper.pdf
new file mode 100644
index 00000000000..59b9fa936df
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/eyedropper.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/knife.pdf b/release/darwin/Blender.app/Contents/Resources/knife.pdf
new file mode 100644
index 00000000000..da4d48cde10
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/knife.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/paint_cursor_cross.pdf b/release/darwin/Blender.app/Contents/Resources/paint_cursor_cross.pdf
new file mode 100644
index 00000000000..4f658f3b722
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/paint_cursor_cross.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/paint_cursor_dot.pdf b/release/darwin/Blender.app/Contents/Resources/paint_cursor_dot.pdf
new file mode 100644
index 00000000000..a5eea954231
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/paint_cursor_dot.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/pen.pdf b/release/darwin/Blender.app/Contents/Resources/pen.pdf
new file mode 100644
index 00000000000..d98f9ee9c89
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/pen.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/scrollew.pdf b/release/darwin/Blender.app/Contents/Resources/scrollew.pdf
new file mode 100644
index 00000000000..35db18830e8
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/scrollew.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/scrollns.pdf b/release/darwin/Blender.app/Contents/Resources/scrollns.pdf
new file mode 100644
index 00000000000..b4046290d50
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/scrollns.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/scrollnsew.pdf b/release/darwin/Blender.app/Contents/Resources/scrollnsew.pdf
new file mode 100644
index 00000000000..f8c666b5347
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/scrollnsew.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/splith.pdf b/release/darwin/Blender.app/Contents/Resources/splith.pdf
new file mode 100644
index 00000000000..03265fd18aa
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/splith.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/splitv.pdf b/release/darwin/Blender.app/Contents/Resources/splitv.pdf
new file mode 100644
index 00000000000..95774f9c17d
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/splitv.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/zoomin.pdf b/release/darwin/Blender.app/Contents/Resources/zoomin.pdf
new file mode 100644
index 00000000000..da20349c1aa
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/zoomin.pdf
@@ -0,0 +1,674 @@
+%PDF-1.5 %âãÏÓ
+1 0 obj <</Metadata 2 0 R/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <</Length 48624/Subtype/XML/Type/Metadata>>stream
+<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
+<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 4.2.2-c063 53.352624, 2008/07/30-18:05:41 ">
+ <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+ <rdf:Description rdf:about=""
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <dc:format>application/pdf</dc:format>
+ <dc:title>
+ <rdf:Alt>
+ <rdf:li xml:lang="x-default">ZoominCursor</rdf:li>
+ </rdf:Alt>
+ </dc:title>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:xmp="http://ns.adobe.com/xap/1.0/"
+ xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/">
+ <xmp:CreatorTool>Adobe Illustrator CS4</xmp:CreatorTool>
+ <xmp:CreateDate>2011-08-25T16:21:20-07:00</xmp:CreateDate>
+ <xmp:ModifyDate>2011-08-25T16:21:20-07:00</xmp:ModifyDate>
+ <xmp:MetadataDate>2011-08-25T16:21:20-07:00</xmp:MetadataDate>
+ <xmp:Thumbnails>
+ <rdf:Alt>
+ <rdf:li rdf:parseType="Resource">
+ <xmpGImg:width>256</xmpGImg:width>
+ <xmpGImg:height>256</xmpGImg:height>
+ <xmpGImg:format>JPEG</xmpGImg:format>
+ <xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYqx&#xA;Hzr+bP5eeSkb/EOtQWtyBUWKEzXRr0/cRBpAD4kAe+KvCvNv/ObdpGzw+UvL7TUqFvNTfgu3Q+hC&#xA;SSD/AMZBiryfX/8AnKT859XLKusppkDf7psIIoqfKRhJMP8Ag8VYPqf5h+ftUJ/SXmTU7wN1Wa8n&#xA;de+wUvQDc4qkU9xcTuHnleVwKBnYsaeFTiroLi4gcvBK8TkULIxU08KjFU90z8w/P2lkfo3zJqdm&#xA;F6LDeTovbYqHoRsMVZxoH/OUn5z6QVVtZTU4F/3TfwRS1+ciiOY/8Hir1jyn/wA5t2jlIfNvl5oT&#xA;sGvNMk5rv1/cTFSAP+MpxV7r5K/Nn8vPOqL/AIe1qC6uSKmxcmG6FOv7iULIQPEAj3xVl2KuxV2K&#xA;uxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxViX5h/mn5L8gacLzzFfCKWQE2thF+8upyP&#xA;99xA9O3JqKO5xV8k/mX/AM5YeffM7TWXl8ny3ozVUfV2reyL/l3GxSvhGFp05HFXiMsss0ryzO0k&#xA;shLPI5LMzHckk7k4qsxV2KuxV2KuxV2KuxV2Kr4pZYZUlhdo5YyGSRCVZWG4II3BxV7d+Wn/ADlh&#xA;598sNDZeYGPmTRlop+sNS9jX/IuNy/ylDfMYq+tvy8/NPyX5/wBON55dvhLLGAbqwl/d3UBP+/Ii&#xA;enbktVPY4qy3FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXgP55/85Qab5Sa48veUjHqP&#xA;mVax3N4aPbWbdx4Syj+X7Kn7W4K4q+ONc13Wdd1OfVNZvJb/AFC4PKa5nYu7eAqegHYDYdsVQGKo&#xA;rTdM1LU72Ox021mvb2Y0itreNpZXP+SiAscVe3+SP+cPfzE1tY7nzBPB5cs23Mcv+k3dD/xTGQg/&#xA;2UgI8MVe2eWf+cQfym0pFbVEu9duBuxup2hiqP5Y7b0jT2ZmxV6NpP5WflrpKgaf5X0uBh/uwWkL&#xA;SfTIys5+/FWSW9naWylbaCOBTSqxqqDbp9kDFXXFnaXKhbmCOdRWiyKrjfr9oHFWN6t+Vn5a6spG&#xA;oeV9LnY/7sNpCsn0SKquPvxV5z5m/wCcQfym1VGbS0u9CuDuptZ2miqf5o7n1TT2VlxV4n53/wCc&#xA;PfzE0RZLny/PB5js13EcX+jXdB/xTISh/wBjISfDFXiGpaZqWmXsljqVrNZXsJpLbXEbRSof8pHA&#xA;YYqhcVR+h67rOhanBqmjXkthqFueUNzAxR18RUdQe4Ox74q+x/yM/wCcoNN82tb+XvNpj07zK1I7&#xA;a8FEtrxuw8IpT/L9lj9nchcVe/Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq+X/8AnJH/AJyR&#xA;msZrryV5KuuF2lYtZ1mI7xno1vbsOjjo7j7PQb1IVfJhJJqdycVaxV7j+T//ADi35o85xwax5gaT&#xA;QvLklHjLL/plwh3BhjcURGHR3+YVhir698j/AJb+S/I+n/UvLemRWfIUnuqc7ibvWWZqu2/atB2A&#xA;xVk2KuxV2KuxV2KuxV2KuxVjPnj8t/JfnjT/AKl5k0yK84ikF1ThcQ96xTLR137Voe4OKvkP84f+&#xA;cW/M/k2OfWPLzSa75cjq8nFf9MtkG5Msaijoo6unzKqMVeG4q2CQajYjFX1n/wA43f8AOSM19Na+&#xA;SvOt1zu3pFo2syneQ9Ft7hj1c9Ec/a6HehKr6gxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV4D/wA5&#xA;Qfnm3lLTT5S8vXHHzLqMdby5jPxWds47HtLKPs91X4tjxOKviokk1O5OKroopZZUiiRpJZGCxxqC&#xA;zMzGgAA3JJxV9gfkD/zjBZ6RDa+afPNstxrLUlsdFlAaK17q86moeXuFOye7fZVfSOKuxV2KuxV2&#xA;KuxV2KuxV2KuxV2KuxV83fn9/wA4wWesRXPmjyNbLb6ytZb7RogFiuu7PAooEl7lej+zfaVfIE8E&#xA;1vNJBPG0U8TFJYnBV1dTRlZTuCDsQcVWAkGo2IxV9q/84v8A55t5t00eUvMNxy8y6dHWzuZD8V5b&#xA;IO57yxD7Xdl+Lc8jir37FXYq7FXYq7FXYq7FXYq7FXYq7FWJfmn+YeneQPJd95ivAJJYh6Vhak0M&#xA;91JURR/L9pqdFBOKvzn13XNT13WbzWdUnNxqF/K09zM37Tuamg7AdAOw2xVAYq+w/wDnGD8gYdIs&#xA;7bzz5pteWs3CiXRbGUf7yxMKrO6n/drg1UH7A/yj8Kr6RxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kux&#xA;V2Kvm7/nJ/8AIGHV7O588+VrXjrNupl1qxiH+9USirToo/3agFWA+2P8ofEq+PMVR+ha5qehazZ6&#xA;zpc5t9QsJVntpl/ZdDUVHcHoR3G2Kv0Y/Kz8w9O8/wDkux8xWYEcso9K/tQamC6joJY/l+0teqkH&#xA;FWW4q7FXYq7FXYq7FXYq7FXYq7FXw5/zlh+ZbeZ/Pp8v2U3LRvLZa3op+GS9P+9D+/AgRjw4tTri&#xA;rw7FXuP/ADi3+T8fnPzQ3mDWIPU8uaFIrGNxVLi82eOEg7MiD43H+qDs2KvuPFXYq7FXYq7FXYq/&#xA;KvFXYq7FXYq/VTFXYq7FXYq7FXYq+Hf+cpPyej8m+Z18w6PB6flzXZGb00FEtrzdpIgBsqOPjQf6&#xA;wGy4q8NxV7j/AM4n/mW3ljz6vl+9m46N5kK29GPwx3o/3nf/AGZJiP8ArDwxV9x4q7FXYq7FXYq7&#xA;FXYq7FXYqxH82fOqeSvy81rzDyAubWApYg71upiIoNu4EjAn2BxV+bksss0rzSuZJZGLyOxqzMxq&#xA;SSe5OKq+mabe6nqVrptjGZr29mjt7aIdXllYIi/SxxV+kn5b+R9P8j+S9M8t2VG+pxD61OP93XD/&#xA;ABTSmu/xOTTwFB2xVk2KuxV2KuxV2KuxV+VeKuxV2KuxV+qmKuxV2KuxV2KuxVjP5keR9P8APHkv&#xA;U/Ld7RfrkR+qzn/dNwnxQyim/wALgV8RUd8Vfm3qem3umaldabfRmG9sppLe5iPVJYmKOv0MMVUI&#xA;pZYZUmicxyxsHjdTRlZTUEEdwcVfpH+U3nVPOv5eaL5h5A3N1AEvgNqXUJMU+3YGRSR7EYqy7FXY&#xA;q7FXYq7FXYq7FXYq+XP+c2/NhS08veUoX3maTU7xQafClYYNu4JaX7sVfJ2Kvef+cPfJC63+Yk/m&#xA;C5j5WflyD1Yydx9buaxw/cgkb2IGKvtvFXYq7FXYq7FXYq7FX5V4q7FXYq7FX6qYq7FXYq7FXYq7&#xA;FXYq+JP+cwvJC6J+YkHmC2j42fmOD1ZCNh9btqRzfehjb3JOKvBsVfWH/OEnmwva+YfKcz19Fo9T&#xA;s0Jr8L0hnp4AFYvvxV9SYq7FXYq7FXYq7FXYq7FXwJ/zlJr51f8AOfWVVuUGmJBYQ+3pRBpB9E0j&#xA;4q8mxV9y/wDOIPllNK/KZNUZaXGu3c90WOx9KFvq0a/KsTMP9bFXt+KuxV2KuxV2KuxV2KvyrxV2&#xA;KuxV2Kv1UxV2KuxV2KuxV2KuxV4h/wA5feWU1X8pn1RVrcaFdwXQYbn0pm+rSL8qyqx/1cVfDWKv&#xA;Wf8AnFvXzpH5z6MrNxg1NJ7Cb39WItGPpmjTFX33irsVdirsVdirsVdirsVfmZ+YepnVPP3mTUq8&#xA;heaneTKf8l53KgbnYD3xVj2Kv0r/ACr0kaT+WvlfT6cWg0u0Eo/4saFWk/4djirKcVdirsVflXir&#xA;sVdirsVdirsVdirsVdirsVdirsVfqpirsVdirFvzT0ldW/LXzRp5FWn0u7Ef/GRYWaM/Q6jFX5qY&#xA;qyD8vdTbS/PnlzUVbj9U1OzmJ6fCk6FgemxGKv00xV2KuxV2KuxV2KuxV2KvyvuJ3nuJZ3ADyuzs&#xA;B0qxqaYqp4q/U+zt1trSC2U1WCNY1NKbIoXp9GKquKuxV2KvyrxV2KuxV2KuxV2KuxV2KuxV2Kux&#xA;V2Kv1UxV2KuxVSvLdbm0ntmNFnjaNjSuzqV6fTir8sMVVLed4LiKdAC8Tq6g9KqaiuKv1QxV2Kux&#xA;V2KuxV2KuxV2KvyvuIHguJYHILxOyMR0qpoaYqp4q/U+zuFubSC5UUWeNZFFa7Oobr9OKquKuxV2&#xA;KvyrxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kv1UxV2KuxVSvLhba0nuWFVgjaRhWmyKW6/Rir8sMVVL&#xA;eB57iKBCA8rqik9KsaCuKv1QxV2KuxV2KuxV2KuxV2KvzM/MPTDpfn7zJptOIs9TvIVH+Sk7hSNh&#xA;sR7Yqx7FX6V/lZqy6t+WvlfUAatPpdoZP+Miwqsg+h1OKspxV2KuxV+W36J1X/ljn/5Fv/TFXfon&#xA;Vf8Aljn/AORb/wBMVd+idV/5Y5/+Rb/0xV36J1X/AJY5/wDkW/8ATFUJirsVdirsVRf6J1X/AJY5&#xA;/wDkW/8ATFXfonVf+WOf/kW/9MVd+idV/wCWOf8A5Fv/AExV36J1X/ljn/5Fv/TFX6k4q7FXYqxb&#xA;809WXSfy180agTRoNLuzH/xkaFljH0uwxV+amKsg/L3TG1Tz55c05V5fW9Ts4SOvwvOgYnrsBir9&#xA;NMVdirsVdirsVdirsVdir4E/5yk0A6R+c+ssq8YNTSC/h9/ViCyH6Zo3xV5Nir7l/wCcQfMyar+U&#xA;yaWzVuNCu57Uqdz6UzfWY2+VZWUf6uKvb8VdirsVdirsVdirsVflXirsVdirsVfqpirsVdirsVdi&#xA;rsVdirxD/nL7zMmlflM+lq1LjXbuC1CjY+lC31mRvlWJVP8ArYq+GsVes/8AOLegHV/zn0ZmXlBp&#xA;iT383t6URWM/RNImKvvvFXYq7FXYq7FXYq7FXYq+XP8AnNvymXtPL3m2FN4Wk0y8YCvwvWaDfsAV&#xA;l+/FXydir3n/AJw987ron5iT+X7mTjZ+Y4PSjB2H1u2rJD96GRfckYq+28VdirsVdirsVdirsVfl&#xA;XirsVdirsVfqpirsVdirsVdirsVdir4k/wCcwvO663+YkHl+2k5WflyD0pANx9buaSTfcgjX2IOK&#xA;vBsVfWH/ADhJ5TKWvmHzZMlPWaPTLNyKfClJp6eIJaL7sVfUmKuxV2KuxV2KuxV2KuxViP5s+Sk8&#xA;6/l5rXl7iDc3UBexJ2pdQkSwb9gZFAPsTir83JYpYZXhlQxyxsUkRhRlZTQgg9wcVV9M1K90zUrX&#xA;UrGQw3tlNHcW0o6pLEwdG+hhir9JPy388af548l6Z5ksqL9ciH1qAf7puE+GaI13+FwaeIoe+Ksm&#xA;xV2KuxV2KuxV2KvyrxV2KuxV2Kv1UxV2KuxV2KuxV2KsZ/Mjzxp/kfyXqfmS9o31OI/VYD/u64f4&#xA;YYhTf4nIr4Cp7Yq/NvU9SvdT1K61K+kM17ezSXFzKeryysXdvpY4qoRRSSyJFEpeSRgqIoqSxNAA&#xA;PfFX6R/lN5KTyV+Xmi+XuIFzawB74jet1MTLPv3AkYgewGKsuxV2KuxV2KuxV2KuxV2KuxV8Of8A&#xA;OWH5aN5Y8+t5gsoeOjeZC1xVR8Md6P8AehP9mSJR/rHwxV4dir3L/nFv84Y/JvmdvL2sT+n5c12R&#xA;V9RzRLa82WOUk7Kjj4HP+qTsuKvuLFXYq7FXYq7FXYq/KvFXYq7FXYq/VTFXYq7FXYq7FXYq+Hf+&#xA;cpPzhj85eZ18vaPP6nlzQpGX1ENUubzdZJQRsyIPgQ/6xGzYq8NxV7j/AM4n/lo3mfz6vmC9h5aN&#xA;5bK3FWHwyXp/3nT/AGBBlP8AqjxxV9x4q7FXYq7FXYq7FXYq7FXYq7FWJfmn+Xmnef8AyXfeXbwi&#xA;OWUerYXRFTBdR1MUny/ZanVSRir859d0PU9C1m80bVIDb6hYStBcwt+y6Ghoe4PUHuN8VQGKvsP/&#xA;AJxg/P6HV7O28jeabrjrNuoi0W+lP+9USiiwOx/3agFFJ+2P8ofEq+kcVdirsVdirsVdirsVdirs&#xA;VdirsVdirsVdir5u/wCcn/z+i0ezufI3le55azcqYtZvoj/vLEw+KBGH+7XBox/YH+UfhVfHmKo7&#xA;RNG1HW9YstH02Iz39/MlvaxDblJIwVak7Ab7nFX6M/lZ+XmneQPJdj5dsyJJYh6t/dAUM91JQyyf&#xA;L9la9FAGKstxV2KuxV2KuxV2KuxV2KuxV2KuxV4D/wA5QfkY3m3TT5t8vW/LzLp0dLy2jHxXlsg7&#xA;DvLEPs92X4dzxGKviogg0OxGKr4J5reaOeCRop4mDxSoSrq6mqsrDcEHcEYq+v8A8gf+cn7PWIrb&#xA;yv55uVt9ZWkVjrMpCxXXZUnY0CS9g3R/ZvtKvpHFXYq7FXYq7FXYq7FXYq7FXYq7FXYq+bvz+/5y&#xA;fs9HiufK/ka5W51lqxX2sxENFa9mSBtw8viw2T3b7Kr5AnnmuJpJ55GlnlYvLK5LOzsaszMdySdy&#xA;TiqniqpBPNbzRzwSNFPEweKVCVdXU1VlYbgg7gjFX2n/AM46/wDORUPm+GHyt5pmWLzTEvG0u2oq&#xA;X6KPuE4H2l/a6juAq99xV2KuxV2KuxV2KuxV2KuxV2KuxV2Kvl//AJyR/wCcbpr6a686+SrXndvW&#xA;XWdGiG8h6tcW6jq56ug+11G9QVXyYQQaHYjFWsVe5fk9/wA5SeZ/JscGj+YVk13y5HRI+Tf6ZbIN&#xA;gIpGNHRR0R/kGUYq+vPI/wCZHkvzxp/13y3qcV5xFZ7WvC4h7Ulhajrv3pQ9icVZNirsVdirsVdi&#xA;rsVdirsVYz54/MjyX5H0/wCu+ZNTis+QrBa153E3akUK1dt+9KDuRir5D/OH/nKTzP5yjn0fy8sm&#xA;heXJKpJxb/TLlDsRLIpoiMOqJ8izDFXhuKuxV2KuxVUgnmt5o54JGiniYPFKhKurqaqysNwQdwRi&#xA;r7T/AOcdf+ciofN8MPlbzTMsXmmJeNpdtRUv0UfcJwPtL+11HcBV77irsVdirsVdirsVdirsVdir&#xA;sVdirsVeA/nn/wA4v6b5ta48w+UhHp3mVqyXNmaJbXjdz4RSn+b7LH7W5LYq+ONc0LWdC1OfS9Zs&#xA;5bDULc8ZradSjr4Gh6g9iNj2xVAYqitN1PUtMvY77TbqayvYTWK5t5GilQ/5LoQwxV7f5I/5zC/M&#xA;TRFjtvMEEHmOzXYyS/6Nd0H/ABdGCh/2UZJ8cVe2eWf+cvvym1VFXVHu9CuDswuoGmiqf5ZLb1TT&#xA;3ZVxV6NpP5p/lrqyg6f5o0udj/usXcKyfTGzK4+7FWSW95aXKlraeOdRSrRsrjfp9knFXXF5aWyh&#xA;rmeOBTWjSMqDbr9ojFWOar+af5baSpOoeaNLgYdYzdwtJ47Rqxc/dirzjzN/zl9+U2lI66XJd67c&#xA;DZVtYGhir/lSXHpGnuqtirxPzv8A85hfmJrayW3l+CDy5ZtsJIv9Ju6H/i6QBB/sYwR44q8Q1LU9&#xA;S1O9kvtSupr29mNZbm4kaWVz/lO5LHFULiqO0bRNY1vUYtN0eymv7+c0itbdGkkam5PFQdgOpxVC&#xA;zwTW80kE8bRTxMUlicFXV1NGVlO4IOxBxVTxV2KuxVUgnmt5o54JGiniYPFKhKurqaqysNwQdwRi&#xA;r7T/AOcdf+ciofN8MPlbzTMsXmmJeNpdtRUv0UfcJwPtL+11HcBV77irsVdirsVdirsVdirsVdir&#xA;sVdirsVYl+Yf5WeS/P8Apws/MViJZYwRa38X7u6gJ/33KB078Wqp7jFXyT+Zf/OJ/n3yw0175fU+&#xA;ZNGWrD6utL2Nf8u33L/OIt8hirxGWKWGV4pkaOWMlXjcFWVhsQQdwcVWYq7FXYq7FXYq7FXYq7FV&#xA;8UUksixRI0kjkKiKCWJPQADrir278tP+cT/Pvmdob3zAp8t6M1GP1ha3si/5FvsU+cpX5HFX1t+X&#xA;n5WeS/IGnGz8u2IilkAF1fy/vLqcj/fkpHTvxWijsMVeX/8AORX/ADjrD5vhm80+VoVi80xLyu7R&#xA;aKl+ij7hOB9lv2uh7EKviyeCa3mkgnjaKeJiksTgq6upoysp3BB2IOKqeKuxV2KqkE81vNHPBI0U&#xA;8TB4pUJV1dTVWVhuCDuCMVfaf/OOv/ORUPm+GHyt5pmWLzTEvG0u2oqX6KPuE4H2l/a6juAq99xV&#xA;2KuxV2KuxV2KuxV2KuxV2KuxV2KuxViPnX8pvy886o3+IdFgurkigvkBhuhTp+/iKyEDwJI9sVeE&#xA;+bP+cJLVy83lPzC0NalLPU4+a79vXhCkAf8AGI4q8o1//nFv859ILMujJqcC/wC7rCeKWvyjYxzH&#xA;/gMVYNqf5e+fNLZl1Hy5qdpx6maznRdu4YpQjbFUjnt7iBwk8TxORUK6lTTxocVdBb3E7lIInlcC&#xA;pVFLGnjQYqnmmfl7581RlXTvLmp3fLoYbOd137lglAN8VZzoH/OLf5z6uVZtGTTIG/3dfzxRU+ca&#xA;mSYf8Bir1fyn/wA4SWqFJvNnmFpqUL2emR8F27evMGJB/wCMQxV7t5K/Kb8vPJSL/h7RYLW5Aob5&#xA;wZro16/v5S0gB8AQPbFWXYq7FXYq8C/5yK/5x1h83wzeafK0KxeaYl5XdotFS/RR9wnA+y37XQ9i&#xA;FXxZPBNbzSQTxtFPExSWJwVdXU0ZWU7gg7EHFVPFXYq7FVSCea3mjngkaKeJg8UqEq6upqrKw3BB&#xA;3BGKvtP/AJx1/wCciofN8MPlbzTMsXmmJeNpdtRUv0UfcJwPtL+11HcBV77irsVdirsVdirsVdir&#xA;sVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVeBf8AORX/ADjrD5vhm80+VoVi80xL&#xA;yu7RaKl+ij7hOB9lv2uh7EKviyeCa3mkgnjaKeJiksTgq6upoysp3BB2IOKqeKuxV2KqkE81vNHP&#xA;BI0U8TB4pUJV1dTVWVhuCDuCMVfaf/OOv/ORUPm+GHyt5pmWLzTEvG0u2oqX6KPuE4H2l/a6juAq&#xA;99xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KvAv+civ+cd&#xA;YfN8M3mnytCsXmmJeV3aLRUv0UfcJwPst+10PYhV8WTwTW80kE8bRTxMUlicFXV1NGVlO4IOxBxV&#xA;TxV2KuxVUgnmt5o54JGiniYPFKhKurqaqysNwQdwRir7T/5x1/5yKh83ww+VvNMyxeaYl42l21FS&#xA;/RR9wnA+0v7XUdwFXvuKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Ku&#xA;xV2KuxV4F/zkV/zjrD5vhm80+VoVi80xLyu7RaKl+ij7hOB9lv2uh7EKviyeCa3mkgnjaKeJiksT&#xA;gq6upoysp3BB2IOKqeKuxV2KqkE81vNHPBI0U8TB4pUJV1dTVWVhuCDuCMVfaf8Azjr/AM5FQ+b4&#xA;YfK3mmZYvNMS8bS7aipfoo+4TgfaX9rqO4Cr33FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY&#xA;q7FXYq7FXYq7FXYq7FXYq7FXYq8C/wCciv8AnHWHzfDN5p8rQrF5piXld2i0VL9FH3CcD7LftdD2&#xA;IVfFk8E1vNJBPG0U8TFJYnBV1dTRlZTuCDsQcVU8VdirsVVIJ5reaOeCRop4mDxSoSrq6mqsrDcE&#xA;HcEYq+0/+cdf+ciofN8MPlbzTMsXmmJeNpdtRUv0UfcJwPtL+11HcBV77irsVdirsVdirsVdirsV&#xA;dirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVeBf85Ff846w+b4ZvNPlaFYvNMS8ru0W&#xA;ipfoo+4TgfZb9roexCr4sngmt5pIJ42iniYpLE4KurqaMrKdwQdiDiqnirsVdiqpBPNbzRzwSNFP&#xA;EweKVCVdXU1VlYbgg7gjFX2n/wA46/8AORUPm+GHyt5pmWLzTEvG0u2oqX6KPuE4H2l/a6juAq99&#xA;xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KvAv+civ+cdYf&#xA;N8M3mnytCsXmmJeV3aLRUv0UfcJwPst+10PYhV8WTwTW80kE8bRTxMUlicFXV1NGVlO4IOxBxVTx&#xA;V2KuxV7f/wA46/kHqfnbU4PMmrGaw8rWEweOaNmimu5omrwgdaMqKw+OQfJfiqVVfcuKuxV2KuxV&#xA;2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KvAv+civ+cdYfN8M3mny&#xA;tCsXmmJeV3aLRUv0UfcJwPst+10PYhV8WTwTW80kE8bRTxMUlicFXV1NGVlO4IOxBxVTxV7Z/wA4&#xA;+f8AOPl759vU13XUe28oWz7ndHvXQ7xRHqIwdncf6q71KqvuGxsbKwsoLGxgS2s7ZFit7eJQiIiC&#xA;iqqjYADFVfFXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F&#xA;XYq8C/5yK/5x1h83wzeafK0KxeaYl5XdotFS/RR9wnA+y37XQ9iFXi/5B/8AOOup+dtTOreZIJrD&#xA;ytYTNHNG4aKa7mibi8CVoyorCkj/AOxHxVKqvt6xsbKwsoLGxgS2s7ZFit7eJQiIiCiqqjYADFVf&#xA;FX//2Q==</xmpGImg:image>
+ </rdf:li>
+ </rdf:Alt>
+ </xmp:Thumbnails>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
+ xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#"
+ xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#">
+ <xmpMM:OriginalDocumentID>uuid:9E3E5C9A8C81DB118734DB58FDDE4BA7</xmpMM:OriginalDocumentID>
+ <xmpMM:DocumentID>xmp.did:FF7F11740720681197A58AA60A3A792E</xmpMM:DocumentID>
+ <xmpMM:InstanceID>uuid:290e4a2c-d2d5-214f-ac9a-91dbf5b74460</xmpMM:InstanceID>
+ <xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass>
+ <xmpMM:History>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>converted</stEvt:action>
+ <stEvt:params>from application/pdf to &lt;unknown&gt;</stEvt:params>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:D07F11740720681191099C3B601C4548</stEvt:instanceID>
+ <stEvt:when>2008-04-17T14:19:10+05:30</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>
+ <rdf:Bag>
+ <rdf:li>/</rdf:li>
+ </rdf:Bag>
+ </stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>converted</stEvt:action>
+ <stEvt:params>from application/pdf to &lt;unknown&gt;</stEvt:params>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>converted</stEvt:action>
+ <stEvt:params>from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator</stEvt:params>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:FC7F117407206811B628E3BF27C8C41B</stEvt:instanceID>
+ <stEvt:when>2008-05-22T14:51:08-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>
+ <rdf:Bag>
+ <rdf:li>/</rdf:li>
+ </rdf:Bag>
+ </stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>converted</stEvt:action>
+ <stEvt:params>from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator</stEvt:params>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:FD7F117407206811B628E3BF27C8C41B</stEvt:instanceID>
+ <stEvt:when>2008-05-22T15:15:38-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>
+ <rdf:Bag>
+ <rdf:li>/</rdf:li>
+ </rdf:Bag>
+ </stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>converted</stEvt:action>
+ <stEvt:params>from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator</stEvt:params>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:0CC3BD25102DDD1181B594070CEB88D9</stEvt:instanceID>
+ <stEvt:when>2008-05-28T17:07:17-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>
+ <rdf:Bag>
+ <rdf:li>/</rdf:li>
+ </rdf:Bag>
+ </stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:F77F117407206811ACFEA91EFF4B1542</stEvt:instanceID>
+ <stEvt:when>2011-08-23T17:31:58-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>/</stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:FD7F11740720681197A58AA60A3A792E</stEvt:instanceID>
+ <stEvt:when>2011-08-25T16:11:20-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>/</stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:FE7F11740720681197A58AA60A3A792E</stEvt:instanceID>
+ <stEvt:when>2011-08-25T16:20:54-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>/</stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:FF7F11740720681197A58AA60A3A792E</stEvt:instanceID>
+ <stEvt:when>2011-08-25T16:21:13-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>/</stEvt:changed>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpMM:History>
+ <xmpMM:DerivedFrom rdf:parseType="Resource">
+ <stRef:instanceID>xmp.iid:FE7F11740720681197A58AA60A3A792E</stRef:instanceID>
+ <stRef:documentID>xmp.did:FE7F11740720681197A58AA60A3A792E</stRef:documentID>
+ <stRef:originalDocumentID>uuid:9E3E5C9A8C81DB118734DB58FDDE4BA7</stRef:originalDocumentID>
+ <stRef:renditionClass>proof:pdf</stRef:renditionClass>
+ </xmpMM:DerivedFrom>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/">
+ <illustrator:StartupProfile>Basic RGB</illustrator:StartupProfile>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/"
+ xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
+ xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/">
+ <xmpTPg:NPages>1</xmpTPg:NPages>
+ <xmpTPg:HasVisibleTransparency>False</xmpTPg:HasVisibleTransparency>
+ <xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint>
+ <xmpTPg:MaxPageSize rdf:parseType="Resource">
+ <stDim:w>20.000000</stDim:w>
+ <stDim:h>20.000000</stDim:h>
+ <stDim:unit>Pixels</stDim:unit>
+ </xmpTPg:MaxPageSize>
+ <xmpTPg:PlateNames>
+ <rdf:Seq>
+ <rdf:li>Cyan</rdf:li>
+ <rdf:li>Magenta</rdf:li>
+ <rdf:li>Yellow</rdf:li>
+ <rdf:li>Black</rdf:li>
+ </rdf:Seq>
+ </xmpTPg:PlateNames>
+ <xmpTPg:SwatchGroups>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:groupName>Default Swatch Group</xmpG:groupName>
+ <xmpG:groupType>0</xmpG:groupType>
+ <xmpG:Colorants>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>White</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>255</xmpG:red>
+ <xmpG:green>255</xmpG:green>
+ <xmpG:blue>255</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>Black</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>0</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Red</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>255</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>0</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Yellow</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>255</xmpG:red>
+ <xmpG:green>255</xmpG:green>
+ <xmpG:blue>0</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Green</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>255</xmpG:green>
+ <xmpG:blue>0</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Cyan</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>255</xmpG:green>
+ <xmpG:blue>255</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Blue</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>255</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Magenta</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>255</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>255</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=193 G=39 B=45</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>193</xmpG:red>
+ <xmpG:green>39</xmpG:green>
+ <xmpG:blue>45</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=237 G=28 B=36</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>237</xmpG:red>
+ <xmpG:green>28</xmpG:green>
+ <xmpG:blue>36</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=241 G=90 B=36</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>241</xmpG:red>
+ <xmpG:green>90</xmpG:green>
+ <xmpG:blue>36</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=247 G=147 B=30</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>247</xmpG:red>
+ <xmpG:green>147</xmpG:green>
+ <xmpG:blue>30</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=251 G=176 B=59</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>251</xmpG:red>
+ <xmpG:green>176</xmpG:green>
+ <xmpG:blue>59</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=252 G=238 B=33</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>252</xmpG:red>
+ <xmpG:green>238</xmpG:green>
+ <xmpG:blue>33</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=217 G=224 B=33</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>217</xmpG:red>
+ <xmpG:green>224</xmpG:green>
+ <xmpG:blue>33</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=140 G=198 B=63</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>140</xmpG:red>
+ <xmpG:green>198</xmpG:green>
+ <xmpG:blue>63</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=57 G=181 B=74</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>57</xmpG:red>
+ <xmpG:green>181</xmpG:green>
+ <xmpG:blue>74</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=146 B=69</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>146</xmpG:green>
+ <xmpG:blue>69</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=104 B=55</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>104</xmpG:green>
+ <xmpG:blue>55</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=34 G=181 B=115</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>34</xmpG:red>
+ <xmpG:green>181</xmpG:green>
+ <xmpG:blue>115</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=169 B=157</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>169</xmpG:green>
+ <xmpG:blue>157</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=41 G=171 B=226</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>41</xmpG:red>
+ <xmpG:green>171</xmpG:green>
+ <xmpG:blue>226</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=113 B=188</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>113</xmpG:green>
+ <xmpG:blue>188</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=46 G=49 B=146</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>46</xmpG:red>
+ <xmpG:green>49</xmpG:green>
+ <xmpG:blue>146</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=27 G=20 B=100</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>27</xmpG:red>
+ <xmpG:green>20</xmpG:green>
+ <xmpG:blue>100</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=102 G=45 B=145</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>102</xmpG:red>
+ <xmpG:green>45</xmpG:green>
+ <xmpG:blue>145</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=147 G=39 B=143</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>147</xmpG:red>
+ <xmpG:green>39</xmpG:green>
+ <xmpG:blue>143</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=158 G=0 B=93</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>158</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>93</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=212 G=20 B=90</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>212</xmpG:red>
+ <xmpG:green>20</xmpG:green>
+ <xmpG:blue>90</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=237 G=30 B=121</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>237</xmpG:red>
+ <xmpG:green>30</xmpG:green>
+ <xmpG:blue>121</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=199 G=178 B=153</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>199</xmpG:red>
+ <xmpG:green>178</xmpG:green>
+ <xmpG:blue>153</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=153 G=134 B=117</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>153</xmpG:red>
+ <xmpG:green>134</xmpG:green>
+ <xmpG:blue>117</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=115 G=99 B=87</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>115</xmpG:red>
+ <xmpG:green>99</xmpG:green>
+ <xmpG:blue>87</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=83 G=71 B=65</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>83</xmpG:red>
+ <xmpG:green>71</xmpG:green>
+ <xmpG:blue>65</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=198 G=156 B=109</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>198</xmpG:red>
+ <xmpG:green>156</xmpG:green>
+ <xmpG:blue>109</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=166 G=124 B=82</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>166</xmpG:red>
+ <xmpG:green>124</xmpG:green>
+ <xmpG:blue>82</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=140 G=98 B=57</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>140</xmpG:red>
+ <xmpG:green>98</xmpG:green>
+ <xmpG:blue>57</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=117 G=76 B=36</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>117</xmpG:red>
+ <xmpG:green>76</xmpG:green>
+ <xmpG:blue>36</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=96 G=56 B=19</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>96</xmpG:red>
+ <xmpG:green>56</xmpG:green>
+ <xmpG:blue>19</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=66 G=33 B=11</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>66</xmpG:red>
+ <xmpG:green>33</xmpG:green>
+ <xmpG:blue>11</xmpG:blue>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpG:Colorants>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:groupName>Grays</xmpG:groupName>
+ <xmpG:groupType>1</xmpG:groupType>
+ <xmpG:Colorants>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=0 B=0</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>0</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=26 G=26 B=26</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>26</xmpG:red>
+ <xmpG:green>26</xmpG:green>
+ <xmpG:blue>26</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=51 G=51 B=51</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>51</xmpG:red>
+ <xmpG:green>51</xmpG:green>
+ <xmpG:blue>51</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=77 G=77 B=77</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>77</xmpG:red>
+ <xmpG:green>77</xmpG:green>
+ <xmpG:blue>77</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=102 G=102 B=102</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>102</xmpG:red>
+ <xmpG:green>102</xmpG:green>
+ <xmpG:blue>102</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=128 G=128 B=128</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>128</xmpG:red>
+ <xmpG:green>128</xmpG:green>
+ <xmpG:blue>128</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=153 G=153 B=153</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>153</xmpG:red>
+ <xmpG:green>153</xmpG:green>
+ <xmpG:blue>153</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=179 G=179 B=179</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>179</xmpG:red>
+ <xmpG:green>179</xmpG:green>
+ <xmpG:blue>179</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=204 G=204 B=204</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>204</xmpG:red>
+ <xmpG:green>204</xmpG:green>
+ <xmpG:blue>204</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=230 G=230 B=230</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>230</xmpG:red>
+ <xmpG:green>230</xmpG:green>
+ <xmpG:blue>230</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=242 G=242 B=242</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>242</xmpG:red>
+ <xmpG:green>242</xmpG:green>
+ <xmpG:blue>242</xmpG:blue>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpG:Colorants>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:groupName>Splash</xmpG:groupName>
+ <xmpG:groupType>1</xmpG:groupType>
+ <xmpG:Colorants>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=214 G=149 B=68</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>214</xmpG:red>
+ <xmpG:green>149</xmpG:green>
+ <xmpG:blue>68</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=71 G=152 B=237</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>71</xmpG:red>
+ <xmpG:green>152</xmpG:green>
+ <xmpG:blue>237</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=42 G=81 B=224</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>42</xmpG:red>
+ <xmpG:green>81</xmpG:green>
+ <xmpG:blue>224</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=180 G=58 B=228</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>180</xmpG:red>
+ <xmpG:green>58</xmpG:green>
+ <xmpG:blue>228</xmpG:blue>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpG:Colorants>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpTPg:SwatchGroups>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
+ <pdf:Producer>Adobe PDF library 9.00</pdf:Producer>
+ </rdf:Description>
+ </rdf:RDF>
+</x:xmpmeta>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<?xpacket end="w"?> endstream endobj 3 0 obj <</Count 1/Kids[5 0 R]/Type/Pages>> endobj 5 0 obj <</ArtBox[2.0 3.0 18.0 19.0]/BleedBox[0.0 0.0 20.0 20.0]/Contents 6 0 R/MediaBox[0.0 0.0 20.0 20.0]/Parent 3 0 R/Resources<</ExtGState<</GS0 7 0 R>>/Properties<</MC0<</Color[65535 20224 20224]/Dimmed false/Editable true/Preview true/Printed true/Title(Layer 2)/Visible true>>/MC1<</Color[20224 20224 65535]/Dimmed false/Editable true/Preview true/Printed true/Title(Layer 4)/Visible true>>/MC2<</Color[0 21845 0]/Dimmed false/Editable true/Preview true/Printed true/Title(Layer 5)/Visible true>>>>>>/TrimBox[0.0 0.0 20.0 20.0]/Type/Page>> endobj 6 0 obj <</Filter/FlateDecode/Length 238>>stream
+H‰ÌR;®Â0ì÷{oÖŽm9-Ñ(^ý„øï!*nÏ®˜
+0000000016 00000 n
+0000000076 00000 n
+0000048777 00000 n
+0000000000 00000 f
+0000048828 00000 n
+0000049382 00000 n
+0000049688 00000 n
+0000049800 00000 n
+trailer <</Size 9/Root 1 0 R/Info 8 0 R/ID[<3661EF74478645EC8F1B98E18A5E6001><1DA54DD892824505A9E35B2A0D648A58>]>> startxref 49975 %%EOF \ No newline at end of file
diff --git a/release/darwin/Blender.app/Contents/Resources/zoomout.pdf b/release/darwin/Blender.app/Contents/Resources/zoomout.pdf
new file mode 100644
index 00000000000..6ded60dbc0f
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/zoomout.pdf
@@ -0,0 +1,676 @@
+%PDF-1.5 %âãÏÓ
+1 0 obj <</Metadata 2 0 R/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <</Length 48694/Subtype/XML/Type/Metadata>>stream
+<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
+<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 4.2.2-c063 53.352624, 2008/07/30-18:05:41 ">
+ <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+ <rdf:Description rdf:about=""
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <dc:format>application/pdf</dc:format>
+ <dc:title>
+ <rdf:Alt>
+ <rdf:li xml:lang="x-default">ZoomoutCursor</rdf:li>
+ </rdf:Alt>
+ </dc:title>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:xmp="http://ns.adobe.com/xap/1.0/"
+ xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/">
+ <xmp:CreatorTool>Adobe Illustrator CS4</xmp:CreatorTool>
+ <xmp:CreateDate>2011-08-25T16:23:51-07:00</xmp:CreateDate>
+ <xmp:ModifyDate>2011-08-25T16:23:51-07:00</xmp:ModifyDate>
+ <xmp:MetadataDate>2011-08-25T16:23:51-07:00</xmp:MetadataDate>
+ <xmp:Thumbnails>
+ <rdf:Alt>
+ <rdf:li rdf:parseType="Resource">
+ <xmpGImg:width>256</xmpGImg:width>
+ <xmpGImg:height>256</xmpGImg:height>
+ <xmpGImg:format>JPEG</xmpGImg:format>
+ <xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYqx&#xA;Hzr+bP5eeSkb/EOtQWtyBUWKEzXRr0/cRBpAD4kAe+KvCvNv/ObdpGzw+UvL7TUqFvNTfgu3Q+hC&#xA;SSD/AMZBiryfX/8AnKT859XLKusppkDf7psIIoqfKRhJMP8Ag8VYPqf5h+ftUJ/SXmTU7wN1Wa8n&#xA;de+wUvQDc4qkU9xcTuHnleVwKBnYsaeFTiroLi4gcvBK8TkULIxU08KjFU90z8w/P2lkfo3zJqdm&#xA;F6LDeTovbYqHoRsMVZxoH/OUn5z6QVVtZTU4F/3TfwRS1+ciiOY/8Hir1jyn/wA5t2jlIfNvl5oT&#xA;sGvNMk5rv1/cTFSAP+MpxV7r5K/Nn8vPOqL/AIe1qC6uSKmxcmG6FOv7iULIQPEAj3xVl2KuxV2K&#xA;uxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxViX5h/mn5L8gacLzzFfCKWQE2thF+8upyP&#xA;99xA9O3JqKO5xV8k/mX/AM5YeffM7TWXl8ny3ozVUfV2reyL/l3GxSvhGFp05HFXiMsss0ryzO0k&#xA;shLPI5LMzHckk7k4qsxV2KuxV2KuxV2KuxV2Kr4pZYZUlhdo5YyGSRCVZWG4II3BxV7d+Wn/ADlh&#xA;598sNDZeYGPmTRlop+sNS9jX/IuNy/ylDfMYq+tvy8/NPyX5/wBON55dvhLLGAbqwl/d3UBP+/Ii&#xA;enbktVPY4qy3FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXgP55/85Qab5Sa48veUjHqP&#xA;mVax3N4aPbWbdx4Syj+X7Kn7W4K4q+ONc13Wdd1OfVNZvJb/AFC4PKa5nYu7eAqegHYDYdsVQGKo&#xA;rTdM1LU72Ox021mvb2Y0itreNpZXP+SiAscVe3+SP+cPfzE1tY7nzBPB5cs23Mcv+k3dD/xTGQg/&#xA;2UgI8MVe2eWf+cQfym0pFbVEu9duBuxup2hiqP5Y7b0jT2ZmxV6NpP5WflrpKgaf5X0uBh/uwWkL&#xA;SfTIys5+/FWSW9naWylbaCOBTSqxqqDbp9kDFXXFnaXKhbmCOdRWiyKrjfr9oHFWN6t+Vn5a6spG&#xA;oeV9LnY/7sNpCsn0SKquPvxV5z5m/wCcQfym1VGbS0u9CuDuptZ2miqf5o7n1TT2VlxV4n53/wCc&#xA;PfzE0RZLny/PB5js13EcX+jXdB/xTISh/wBjISfDFXiGpaZqWmXsljqVrNZXsJpLbXEbRSof8pHA&#xA;YYqhcVR+h67rOhanBqmjXkthqFueUNzAxR18RUdQe4Ox74q+x/yM/wCcoNN82tb+XvNpj07zK1I7&#xA;a8FEtrxuw8IpT/L9lj9nchcVe/Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq+X/8AnJH/AJyR&#xA;msZrryV5KuuF2lYtZ1mI7xno1vbsOjjo7j7PQb1IVfJhJJqdycVaxV7j+T//ADi35o85xwax5gaT&#xA;QvLklHjLL/plwh3BhjcURGHR3+YVhir698j/AJb+S/I+n/UvLemRWfIUnuqc7ibvWWZqu2/atB2A&#xA;xVk2KuxV2KuxV2KuxV2KuxVjPnj8t/JfnjT/AKl5k0yK84ikF1ThcQ96xTLR137Voe4OKvkP84f+&#xA;cW/M/k2OfWPLzSa75cjq8nFf9MtkG5Msaijoo6unzKqMVeG4q2CQajYjFX1n/wA43f8AOSM19Na+&#xA;SvOt1zu3pFo2syneQ9Ft7hj1c9Ec/a6HehKr6gxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV4D/wA5&#xA;Qfnm3lLTT5S8vXHHzLqMdby5jPxWds47HtLKPs91X4tjxOKviokk1O5OKroopZZUiiRpJZGCxxqC&#xA;zMzGgAA3JJxV9gfkD/zjBZ6RDa+afPNstxrLUlsdFlAaK17q86moeXuFOye7fZVfSOKuxV2KuxV2&#xA;KuxV2KuxV2KuxV2KuxV83fn9/wA4wWesRXPmjyNbLb6ytZb7RogFiuu7PAooEl7lej+zfaVfIE8E&#xA;1vNJBPG0U8TFJYnBV1dTRlZTuCDsQcVWAkGo2IxV9q/84v8A55t5t00eUvMNxy8y6dHWzuZD8V5b&#xA;IO57yxD7Xdl+Lc8jir37FXYq7FXYq7FXYq7FXYq7FXYq7FWJfmn+YeneQPJd95ivAJJYh6Vhak0M&#xA;91JURR/L9pqdFBOKvzn13XNT13WbzWdUnNxqF/K09zM37Tuamg7AdAOw2xVAYq+w/wDnGD8gYdIs&#xA;7bzz5pteWs3CiXRbGUf7yxMKrO6n/drg1UH7A/yj8Kr6RxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kux&#xA;V2Kvm7/nJ/8AIGHV7O588+VrXjrNupl1qxiH+9USirToo/3agFWA+2P8ofEq+PMVR+ha5qehazZ6&#xA;zpc5t9QsJVntpl/ZdDUVHcHoR3G2Kv0Y/Kz8w9O8/wDkux8xWYEcso9K/tQamC6joJY/l+0teqkH&#xA;FWW4q7FXYq7FXYq7FXYq7FXYq7FXw5/zlh+ZbeZ/Pp8v2U3LRvLZa3op+GS9P+9D+/AgRjw4tTri&#xA;rw7FXuP/ADi3+T8fnPzQ3mDWIPU8uaFIrGNxVLi82eOEg7MiD43H+qDs2KvuPFXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq+Hf+cpPyej8m+Z18w6PB6flzXZGb00FEtrzdpIgBsqOPjQf6wGy4&#xA;q8NxV7j/AM4n/mW3ljz6vl+9m46N5kK29GPwx3o/3nf/AGZJiP8ArDwxV9x4q7FXYq7FXYq7FXYq&#xA;7FXYqxH82fOqeSvy81rzDyAubWApYg71upiIoNu4EjAn2BxV+bksss0rzSuZJZGLyOxqzMxqSSe5&#xA;OKq+mabe6nqVrptjGZr29mjt7aIdXllYIi/SxxV+kn5b+R9P8j+S9M8t2VG+pxD61OP93XD/ABTS&#xA;mu/xOTTwFB2xVk2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVjP5keR9P8APHkvU/Ld7Rfr&#xA;kR+qzn/dNwnxQyim/wALgV8RUd8Vfm3qem3umaldabfRmG9sppLe5iPVJYmKOv0MMVUIpZYZUmic&#xA;xyxsHjdTRlZTUEEdwcVfpH+U3nVPOv5eaL5h5A3N1AEvgNqXUJMU+3YGRSR7EYqy7FXYq7FXYq7F&#xA;XYq7FXYq+XP+c2/NhS08veUoX3maTU7xQafClYYNu4JaX7sVfJ2Kvef+cPfJC63+Yk/mC5j5Wfly&#xA;D1Yydx9buaxw/cgkb2IGKvtvFXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq+JP+cwvJ&#xA;C6J+YkHmC2j42fmOD1ZCNh9btqRzfehjb3JOKvBsVfWH/OEnmwva+YfKcz19Fo9Ts0Jr8L0hnp4A&#xA;FYvvxV9SYq7FXYq7FXYq7FXYq7FXwJ/zlJr51f8AOfWVVuUGmJBYQ+3pRBpB9E0j4q8mxV9y/wDO&#xA;IPllNK/KZNUZaXGu3c90WOx9KFvq0a/KsTMP9bFXt+KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV&#xA;2KuxV2KuxV4h/wA5feWU1X8pn1RVrcaFdwXQYbn0pm+rSL8qyqx/1cVfDWKvWf8AnFvXzpH5z6Mr&#xA;Nxg1NJ7Cb39WItGPpmjTFX33irsVdirsVdirsVdirsVfmZ+YepnVPP3mTUq8heaneTKf8l53Kgbn&#xA;YD3xVj2Kv0r/ACr0kaT+WvlfT6cWg0u0Eo/4saFWk/4djirKcVdirsVfmBquq6oNUvALycATyf7s&#xA;f+c++KoX9Lar/wAtk/8AyMf+uKu/S2q/8tk//Ix/64q79Lar/wAtk/8AyMf+uKu/S2q/8tk//Ix/&#xA;64q79Lar/wAtk/8AyMf+uKu/S2q/8tk//Ix/64q79Lar/wAtk/8AyMf+uKu/S2q/8tk//Ix/64q7&#xA;9Lar/wAtk/8AyMf+uKu/S2q/8tk//Ix/64q79Lar/wAtk/8AyMf+uKv1JxV2KuxVi35p6Surflr5&#xA;o08irT6XdiP/AIyLCzRn6HUYq/NTFWQfl7qbaX588uaircfqmp2cxPT4UnQsD02IxV+mmKuxV2Ku&#xA;xV2KuxV2KuxV+V9xO89xLO4AeV2dgOlWNTTFVPFX6n2duttaQWymqwRrGppTZFC9PoxVVxV2KuxV&#xA;+W2rf8dW8/4zyf8AEziqExV2KuxV2KuxV2KuxV2KuxV2KuxV+qmKuxV2KqV5brc2k9sxos8bRsaV&#xA;2dSvT6cVflhiqpbzvBcRToAXidXUHpVTUVxV+qGKuxV2KuxV2KuxV2KuxV+V9xA8FxLA5BeJ2RiO&#xA;lVNDTFVPFX6n2dwtzaQXKiizxrIorXZ1DdfpxVVxV2KuxV+W2rf8dW8/4zyf8TOKoTFXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FX6qYq7FXYqpXlwttaT3LCqwRtIwrTZFLdfoxV+WGKqlvA89xFAhAeV1RSelW&#xA;NBXFX6oYq7FXYq7FXYq7FXYq7FX5mfmHph0vz95k02nEWep3kKj/ACUncKRsNiPbFWPYq/Sv8rNW&#xA;XVvy18r6gDVp9LtDJ/xkWFVkH0OpxVlOKuxV2Kvy21b/AI6t5/xnk/4mcVQmKuxV2KuxV2KuxV2K&#xA;uxV2KuxV2Kv1UxV2KuxVi35p6suk/lr5o1AmjQaXdmP/AIyNCyxj6XYYq/NTFWQfl7pjap588uac&#xA;q8vrep2cJHX4XnQMT12AxV+mmKuxV2KuxV2KuxV2KuxV8Cf85SaAdI/OfWWVeMGppBfw+/qxBZD9&#xA;M0b4q8mxV9y/84g+Zk1X8pk0tmrcaFdz2pU7n0pm+sxt8qyso/1cVe34q7FXYq7FXYq7FXYq7FXY&#xA;q7FXYq7FXYq7FXYq7FXYq7FXiH/OX3mZNK/KZ9LVqXGu3cFqFGx9KFvrMjfKsSqf9bFXw1ir1n/n&#xA;FvQDq/5z6MzLyg0xJ7+b29KIrGfomkTFX33irsVdirsVdirsVdirsVfLn/ObflMvaeXvNsKbwtJp&#xA;l4wFfhes0G/YArL9+Kvk7FXvP/OHvnddE/MSfy/cycbPzHB6UYOw+t21ZIfvQyL7kjFX23irsVdi&#xA;rsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVfEn/OYXnddb/MSDy/bScrPy5B6UgG4+t3NJJvu&#xA;QRr7EHFXg2KvrD/nCTymUtfMPmyZKes0emWbkU+FKTT08QS0X3Yq+pMVdirsVdirsVdirsVdirEf&#xA;zZ8lJ51/LzWvL3EG5uoC9iTtS6hIlg37AyKAfYnFX5uSxSwyvDKhjljYpIjCjKymhBB7g4qr6ZqV&#xA;7pmpWupWMhhvbKaO4tpR1SWJg6N9DDFX6Sflv540/wA8eS9M8yWVF+uRD61AP903CfDNEa7/AAuD&#xA;TxFD3xVk2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVjP5keeNP8j+S9T8yXtG+pxH6rAf9&#xA;3XD/AAwxCm/xORXwFT2xV+bep6le6nqV1qV9IZr29mkuLmU9XllYu7fSxxVQiiklkSKJS8kjBURR&#xA;UliaAAe+Kv0j/KbyUnkr8vNF8vcQLm1gD3xG9bqYmWffuBIxA9gMVZdirsVdirsVdirsVdirsVdi&#xA;r4c/5yw/LRvLHn1vMFlDx0bzIWuKqPhjvR/vQn+zJEo/1j4Yq8OxV7l/zi3+cMfk3zO3l7WJ/T8u&#xA;a7Iq+o5oltebLHKSdlRx8Dn/AFSdlxV9xYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXw7/&#xA;AM5SfnDH5y8zr5e0ef1PLmhSMvqIapc3m6ySgjZkQfAh/wBYjZsVeG4q9x/5xP8Ay0bzP59XzBew&#xA;8tG8tlbirD4ZL0/7zp/sCDKf9UeOKvuPFXYq7FXYq7FXYq7FXYq7FXYqxL80/wAvNO8/+S77y7eE&#xA;Ryyj1bC6IqYLqOpik+X7LU6qSMVfnPruh6noWs3mjapAbfULCVoLmFv2XQ0ND3B6g9xviqAxV9h/&#xA;84wfn9Dq9nbeRvNN1x1m3URaLfSn/eqJRRYHY/7tQCik/bH+UPiVfSOKuxV2KuxV2KuxV2KuxV2K&#xA;uxV2KuxV2KuxV83f85P/AJ/RaPZ3Pkbyvc8tZuVMWs30R/3liYfFAjD/AHa4NGP7A/yj8Kr48xVH&#xA;aJo2o63rFlo+mxGe/v5kt7WIbcpJGCrUnYDfc4q/Rn8rPy807yB5LsfLtmRJLEPVv7oChnupKGWT&#xA;5fsrXooAxVluKuxV2KuxV2KuxV2KuxV2KuxV2KvAf+coPyMbzbpp82+Xrfl5l06Ol5bRj4ry2Qdh&#xA;3liH2e7L8O54jFXxUQQaHYjFV8E81vNHPBI0U8TB4pUJV1dTVWVhuCDuCMVfX/5A/wDOT9nrEVt5&#xA;X883K2+srSKx1mUhYrrsqTsaBJewbo/s32lX0jirsVdirsVdirsVdirsVdirsVdirsVfN35/f85P&#xA;2ejxXPlfyNcrc6y1Yr7WYiGitezJA24eXxYbJ7t9lV8gTzzXE0k88jSzysXllclnZ2NWZmO5JO5J&#xA;xVTxVUgnmt5o54JGiniYPFKhKurqaqysNwQdwRir7T/5x1/5yKh83ww+VvNMyxeaYl42l21FS/RR&#xA;9wnA+0v7XUdwFXvuKuxV2KuxV2KuxV2KuxV2KuxV2KuxV8v/APOSP/ON019NdedfJVrzu3rLrOjR&#xA;DeQ9WuLdR1c9XQfa6jeoKr5MIINDsRirWKvcvye/5yk8z+TY4NH8wrJrvlyOiR8m/wBMtkGwEUjG&#xA;joo6I/yDKMVfXnkf8yPJfnjT/rvlvU4rziKz2teFxD2pLC1HXfvSh7E4qybFXYq7FXYq7FXYq7FX&#xA;Yqxnzx+ZHkvyPp/13zJqcVnyFYLWvO4m7UihWrtv3pQdyMVfIf5w/wDOUnmfzlHPo/l5ZNC8uSVS&#xA;Ti3+mXKHYiWRTREYdUT5FmGKvDcVdirsVdiqpBPNbzRzwSNFPEweKVCVdXU1VlYbgg7gjFX2n/zj&#xA;r/zkVD5vhh8reaZli80xLxtLtqKl+ij7hOB9pf2uo7gKvfcVdirsVdirsVdirsVdirsVdirsVdir&#xA;wH88/wDnF/TfNrXHmHykI9O8ytWS5szRLa8bufCKU/zfZY/a3JbFXxxrmhazoWpz6XrNnLYahbnj&#xA;NbTqUdfA0PUHsRse2KoDFUVpup6lpl7HfabdTWV7CaxXNvI0UqH/ACXQhhir2/yR/wA5hfmJoix2&#xA;3mCCDzHZrsZJf9Gu6D/i6MFD/soyT44q9s8s/wDOX35Taqirqj3ehXB2YXUDTRVP8slt6pp7sq4q&#xA;9G0n80/y11ZQdP8ANGlzsf8AdYu4Vk+mNmVx92Kskt7y0uVLW08c6ilWjZXG/T7JOKuuLy0tlDXM&#xA;8cCmtGkZUG3X7RGKsc1X80/y20lSdQ80aXAw6xm7haTx2jVi5+7FXnHmb/nL78ptKR10uS7124Gy&#xA;rawNDFX/ACpLj0jT3VWxV4n53/5zC/MTW1ktvL8EHlyzbYSRf6Td0P8AxdIAg/2MYI8cVeIalqep&#xA;aneyX2pXU17ezGstzcSNLK5/yncljiqFxVHaNomsa3qMWm6PZTX9/OaRWtujSSNTcnioOwHU4qhZ&#xA;4JreaSCeNop4mKSxOCrq6mjKyncEHYg4qp4q7FXYqqQTzW80c8EjRTxMHilQlXV1NVZWG4IO4IxV&#xA;9p/846/85FQ+b4YfK3mmZYvNMS8bS7aipfoo+4TgfaX9rqO4Cr33FXYq7FXYq7FXYq7FXYq7FXYq&#xA;7FXYqxL8w/ys8l+f9OFn5isRLLGCLW/i/d3UBP8AvuUDp34tVT3GKvkn8y/+cT/Pvlhpr3y+p8ya&#xA;MtWH1daXsa/5dvuX+cRb5DFXiMsUsMrxTI0csZKvG4KsrDYgg7g4qsxV2KuxV2KuxV2KuxV2Kr4o&#xA;pJZFiiRpJHIVEUEsSegAHXFXt35af84n+ffM7Q3vmBT5b0ZqMfrC1vZF/wAi32KfOUr8jir62/Lz&#xA;8rPJfkDTjZ+XbERSyAC6v5f3l1OR/vyUjp34rRR2GKvL/wDnIr/nHWHzfDN5p8rQrF5piXld2i0V&#xA;L9FH3CcD7LftdD2IVfFk8E1vNJBPG0U8TFJYnBV1dTRlZTuCDsQcVU8VdirsVVIJ5reaOeCRop4m&#xA;DxSoSrq6mqsrDcEHcEYq+0/+cdf+ciofN8MPlbzTMsXmmJeNpdtRUv0UfcJwPtL+11HcBV77irsV&#xA;dirsVdirsVdirsVdirsVdirsVdirEfOv5Tfl551Rv8Q6LBdXJFBfIDDdCnT9/EVkIHgSR7Yq8J82&#xA;f84SWrl5vKfmFoa1KWepx8137evCFIA/4xHFXlGv/wDOLf5z6QWZdGTU4F/3dYTxS1+UbGOY/wDA&#xA;YqwbU/y98+aWzLqPlzU7Tj1M1nOi7dwxShG2KpHPb3EDhJ4nicioV1KmnjQ4q6C3uJ3KQRPK4FSq&#xA;KWNPGgxVPNM/L3z5qjKuneXNTu+XQw2c7rv3LBKAb4qznQP+cW/zn1cqzaMmmQN/u6/niip841Mk&#xA;w/4DFXq/lP8A5wktUKTebPMLTUoXs9Mj4Lt29eYMSD/xiGKvdvJX5Tfl55KRf8PaLBa3IFDfODNd&#xA;GvX9/KWkAPgCB7Yqy7FXYq7FXgX/ADkV/wA46w+b4ZvNPlaFYvNMS8ru0Wipfoo+4TgfZb9roexC&#xA;r4sngmt5pIJ42iniYpLE4KurqaMrKdwQdiDiqnirsVdiqpBPNbzRzwSNFPEweKVCVdXU1VlYbgg7&#xA;gjFX2n/zjr/zkVD5vhh8reaZli80xLxtLtqKl+ij7hOB9pf2uo7gKvfcVdirsVdirsVdirsVdirs&#xA;VdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirwL/nIr/nHWHzfDN5p8rQrF5piXld2i0V&#xA;L9FH3CcD7LftdD2IVfFk8E1vNJBPG0U8TFJYnBV1dTRlZTuCDsQcVU8VdirsVVIJ5reaOeCRop4m&#xA;DxSoSrq6mqsrDcEHcEYq+0/+cdf+ciofN8MPlbzTMsXmmJeNpdtRUv0UfcJwPtL+11HcBV77irsV&#xA;dirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVeBf85Ff846w+b4Zv&#xA;NPlaFYvNMS8ru0Wipfoo+4TgfZb9roexCr4sngmt5pIJ42iniYpLE4KurqaMrKdwQdiDiqnirsVd&#xA;iqpBPNbzRzwSNFPEweKVCVdXU1VlYbgg7gjFX2n/AM46/wDORUPm+GHyt5pmWLzTEvG0u2oqX6KP&#xA;uE4H2l/a6juAq99xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kux&#xA;V2KvAv8AnIr/AJx1h83wzeafK0KxeaYl5XdotFS/RR9wnA+y37XQ9iFXxZPBNbzSQTxtFPExSWJw&#xA;VdXU0ZWU7gg7EHFVPFXYq7FVSCea3mjngkaKeJg8UqEq6upqrKw3BB3BGKvtP/nHX/nIqHzfDD5W&#xA;80zLF5piXjaXbUVL9FH3CcD7S/tdR3AVe+4q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq&#xA;7FXYq7FXYq7FXYq7FXYq7FXgX/ORX/OOsPm+GbzT5WhWLzTEvK7tFoqX6KPuE4H2W/a6HsQq+LJ4&#xA;JreaSCeNop4mKSxOCrq6mjKyncEHYg4qp4q7FXYqqQTzW80c8EjRTxMHilQlXV1NVZWG4IO4IxV9&#xA;p/8AOOv/ADkVD5vhh8reaZli80xLxtLtqKl+ij7hOB9pf2uo7gKvfcVdirsVdirsVdirsVdirsVd&#xA;irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirwL/nIr/nHWHzfDN5p8rQrF5piXld2i0VL9&#xA;FH3CcD7LftdD2IVfFk8E1vNJBPG0U8TFJYnBV1dTRlZTuCDsQcVU8VdirsVVIJ5reaOeCRop4mDx&#xA;SoSrq6mqsrDcEHcEYq+0/wDnHX/nIqHzfDD5W80zLF5piXjaXbUVL9FH3CcD7S/tdR3AVe+4q7FX&#xA;Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXgX/ORX/OOsPm+Gbz&#xA;T5WhWLzTEvK7tFoqX6KPuE4H2W/a6HsQq+LJ4JreaSCeNop4mKSxOCrq6mjKyncEHYg4qp4q7FXY&#xA;q9v/AOcdfyD1PztqcHmTVjNYeVrCYPHNGzRTXc0TV4QOtGVFYfHIPkvxVKqvuXFXYq7FXYq7FXYq&#xA;7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXgX/ADkV/wA46w+b4ZvNPlaF&#xA;YvNMS8ru0Wipfoo+4TgfZb9roexCr4sngmt5pIJ42iniYpLE4KurqaMrKdwQdiDiqnir2z/nHz/n&#xA;Hy98+3qa7rqPbeULZ9zuj3rod4oj1EYOzuP9Vd6lVX3DY2NlYWUFjYwJbWdsixW9vEoRERBRVVRs&#xA;ABiqvirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVeB&#xA;f85Ff846w+b4ZvNPlaFYvNMS8ru0Wipfoo+4TgfZb9roexCrxf8AIP8A5x11PztqZ1bzJBNYeVrC&#xA;Zo5o3DRTXc0TcXgStGVFYUkf/Yj4qlVX29Y2NlYWUFjYwJbWdsixW9vEoRERBRVVRsABiqvir//Z</xmpGImg:image>
+ </rdf:li>
+ </rdf:Alt>
+ </xmp:Thumbnails>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
+ xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#"
+ xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#">
+ <xmpMM:OriginalDocumentID>uuid:9E3E5C9A8C81DB118734DB58FDDE4BA7</xmpMM:OriginalDocumentID>
+ <xmpMM:DocumentID>xmp.did:008011740720681197A58AA60A3A792E</xmpMM:DocumentID>
+ <xmpMM:InstanceID>uuid:d89cf8d7-60ea-364a-bd79-1b730e3e758c</xmpMM:InstanceID>
+ <xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass>
+ <xmpMM:History>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>converted</stEvt:action>
+ <stEvt:params>from application/pdf to &lt;unknown&gt;</stEvt:params>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:D07F11740720681191099C3B601C4548</stEvt:instanceID>
+ <stEvt:when>2008-04-17T14:19:10+05:30</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>
+ <rdf:Bag>
+ <rdf:li>/</rdf:li>
+ </rdf:Bag>
+ </stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>converted</stEvt:action>
+ <stEvt:params>from application/pdf to &lt;unknown&gt;</stEvt:params>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>converted</stEvt:action>
+ <stEvt:params>from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator</stEvt:params>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:FC7F117407206811B628E3BF27C8C41B</stEvt:instanceID>
+ <stEvt:when>2008-05-22T14:51:08-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>
+ <rdf:Bag>
+ <rdf:li>/</rdf:li>
+ </rdf:Bag>
+ </stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>converted</stEvt:action>
+ <stEvt:params>from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator</stEvt:params>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:FD7F117407206811B628E3BF27C8C41B</stEvt:instanceID>
+ <stEvt:when>2008-05-22T15:15:38-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>
+ <rdf:Bag>
+ <rdf:li>/</rdf:li>
+ </rdf:Bag>
+ </stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>converted</stEvt:action>
+ <stEvt:params>from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator</stEvt:params>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:0CC3BD25102DDD1181B594070CEB88D9</stEvt:instanceID>
+ <stEvt:when>2008-05-28T17:07:17-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>
+ <rdf:Bag>
+ <rdf:li>/</rdf:li>
+ </rdf:Bag>
+ </stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:F77F117407206811ACFEA91EFF4B1542</stEvt:instanceID>
+ <stEvt:when>2011-08-23T17:31:58-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>/</stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:F87F117407206811ACFEA91EFF4B1542</stEvt:instanceID>
+ <stEvt:when>2011-08-23T19:05:46-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>/</stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:F97F117407206811ACFEA91EFF4B1542</stEvt:instanceID>
+ <stEvt:when>2011-08-23T19:07:15-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>/</stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:008011740720681197A58AA60A3A792E</stEvt:instanceID>
+ <stEvt:when>2011-08-25T16:23:44-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>/</stEvt:changed>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpMM:History>
+ <xmpMM:DerivedFrom rdf:parseType="Resource">
+ <stRef:instanceID>uuid:4c3886fe-eb3e-c245-b671-dca17624cd71</stRef:instanceID>
+ <stRef:documentID>xmp.did:F97F117407206811ACFEA91EFF4B1542</stRef:documentID>
+ <stRef:originalDocumentID>uuid:9E3E5C9A8C81DB118734DB58FDDE4BA7</stRef:originalDocumentID>
+ <stRef:renditionClass>proof:pdf</stRef:renditionClass>
+ </xmpMM:DerivedFrom>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/">
+ <illustrator:StartupProfile>Basic RGB</illustrator:StartupProfile>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/"
+ xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
+ xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/">
+ <xmpTPg:NPages>1</xmpTPg:NPages>
+ <xmpTPg:HasVisibleTransparency>False</xmpTPg:HasVisibleTransparency>
+ <xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint>
+ <xmpTPg:MaxPageSize rdf:parseType="Resource">
+ <stDim:w>20.000000</stDim:w>
+ <stDim:h>20.000000</stDim:h>
+ <stDim:unit>Pixels</stDim:unit>
+ </xmpTPg:MaxPageSize>
+ <xmpTPg:PlateNames>
+ <rdf:Seq>
+ <rdf:li>Cyan</rdf:li>
+ <rdf:li>Magenta</rdf:li>
+ <rdf:li>Yellow</rdf:li>
+ <rdf:li>Black</rdf:li>
+ </rdf:Seq>
+ </xmpTPg:PlateNames>
+ <xmpTPg:SwatchGroups>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:groupName>Default Swatch Group</xmpG:groupName>
+ <xmpG:groupType>0</xmpG:groupType>
+ <xmpG:Colorants>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>White</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>255</xmpG:red>
+ <xmpG:green>255</xmpG:green>
+ <xmpG:blue>255</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>Black</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>0</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Red</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>255</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>0</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Yellow</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>255</xmpG:red>
+ <xmpG:green>255</xmpG:green>
+ <xmpG:blue>0</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Green</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>255</xmpG:green>
+ <xmpG:blue>0</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Cyan</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>255</xmpG:green>
+ <xmpG:blue>255</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Blue</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>255</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Magenta</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>255</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>255</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=193 G=39 B=45</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>193</xmpG:red>
+ <xmpG:green>39</xmpG:green>
+ <xmpG:blue>45</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=237 G=28 B=36</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>237</xmpG:red>
+ <xmpG:green>28</xmpG:green>
+ <xmpG:blue>36</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=241 G=90 B=36</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>241</xmpG:red>
+ <xmpG:green>90</xmpG:green>
+ <xmpG:blue>36</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=247 G=147 B=30</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>247</xmpG:red>
+ <xmpG:green>147</xmpG:green>
+ <xmpG:blue>30</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=251 G=176 B=59</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>251</xmpG:red>
+ <xmpG:green>176</xmpG:green>
+ <xmpG:blue>59</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=252 G=238 B=33</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>252</xmpG:red>
+ <xmpG:green>238</xmpG:green>
+ <xmpG:blue>33</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=217 G=224 B=33</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>217</xmpG:red>
+ <xmpG:green>224</xmpG:green>
+ <xmpG:blue>33</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=140 G=198 B=63</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>140</xmpG:red>
+ <xmpG:green>198</xmpG:green>
+ <xmpG:blue>63</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=57 G=181 B=74</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>57</xmpG:red>
+ <xmpG:green>181</xmpG:green>
+ <xmpG:blue>74</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=146 B=69</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>146</xmpG:green>
+ <xmpG:blue>69</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=104 B=55</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>104</xmpG:green>
+ <xmpG:blue>55</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=34 G=181 B=115</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>34</xmpG:red>
+ <xmpG:green>181</xmpG:green>
+ <xmpG:blue>115</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=169 B=157</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>169</xmpG:green>
+ <xmpG:blue>157</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=41 G=171 B=226</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>41</xmpG:red>
+ <xmpG:green>171</xmpG:green>
+ <xmpG:blue>226</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=113 B=188</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>113</xmpG:green>
+ <xmpG:blue>188</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=46 G=49 B=146</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>46</xmpG:red>
+ <xmpG:green>49</xmpG:green>
+ <xmpG:blue>146</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=27 G=20 B=100</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>27</xmpG:red>
+ <xmpG:green>20</xmpG:green>
+ <xmpG:blue>100</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=102 G=45 B=145</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>102</xmpG:red>
+ <xmpG:green>45</xmpG:green>
+ <xmpG:blue>145</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=147 G=39 B=143</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>147</xmpG:red>
+ <xmpG:green>39</xmpG:green>
+ <xmpG:blue>143</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=158 G=0 B=93</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>158</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>93</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=212 G=20 B=90</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>212</xmpG:red>
+ <xmpG:green>20</xmpG:green>
+ <xmpG:blue>90</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=237 G=30 B=121</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>237</xmpG:red>
+ <xmpG:green>30</xmpG:green>
+ <xmpG:blue>121</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=199 G=178 B=153</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>199</xmpG:red>
+ <xmpG:green>178</xmpG:green>
+ <xmpG:blue>153</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=153 G=134 B=117</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>153</xmpG:red>
+ <xmpG:green>134</xmpG:green>
+ <xmpG:blue>117</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=115 G=99 B=87</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>115</xmpG:red>
+ <xmpG:green>99</xmpG:green>
+ <xmpG:blue>87</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=83 G=71 B=65</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>83</xmpG:red>
+ <xmpG:green>71</xmpG:green>
+ <xmpG:blue>65</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=198 G=156 B=109</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>198</xmpG:red>
+ <xmpG:green>156</xmpG:green>
+ <xmpG:blue>109</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=166 G=124 B=82</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>166</xmpG:red>
+ <xmpG:green>124</xmpG:green>
+ <xmpG:blue>82</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=140 G=98 B=57</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>140</xmpG:red>
+ <xmpG:green>98</xmpG:green>
+ <xmpG:blue>57</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=117 G=76 B=36</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>117</xmpG:red>
+ <xmpG:green>76</xmpG:green>
+ <xmpG:blue>36</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=96 G=56 B=19</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>96</xmpG:red>
+ <xmpG:green>56</xmpG:green>
+ <xmpG:blue>19</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=66 G=33 B=11</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>66</xmpG:red>
+ <xmpG:green>33</xmpG:green>
+ <xmpG:blue>11</xmpG:blue>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpG:Colorants>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:groupName>Grays</xmpG:groupName>
+ <xmpG:groupType>1</xmpG:groupType>
+ <xmpG:Colorants>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=0 B=0</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>0</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=26 G=26 B=26</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>26</xmpG:red>
+ <xmpG:green>26</xmpG:green>
+ <xmpG:blue>26</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=51 G=51 B=51</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>51</xmpG:red>
+ <xmpG:green>51</xmpG:green>
+ <xmpG:blue>51</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=77 G=77 B=77</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>77</xmpG:red>
+ <xmpG:green>77</xmpG:green>
+ <xmpG:blue>77</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=102 G=102 B=102</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>102</xmpG:red>
+ <xmpG:green>102</xmpG:green>
+ <xmpG:blue>102</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=128 G=128 B=128</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>128</xmpG:red>
+ <xmpG:green>128</xmpG:green>
+ <xmpG:blue>128</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=153 G=153 B=153</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>153</xmpG:red>
+ <xmpG:green>153</xmpG:green>
+ <xmpG:blue>153</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=179 G=179 B=179</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>179</xmpG:red>
+ <xmpG:green>179</xmpG:green>
+ <xmpG:blue>179</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=204 G=204 B=204</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>204</xmpG:red>
+ <xmpG:green>204</xmpG:green>
+ <xmpG:blue>204</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=230 G=230 B=230</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>230</xmpG:red>
+ <xmpG:green>230</xmpG:green>
+ <xmpG:blue>230</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=242 G=242 B=242</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>242</xmpG:red>
+ <xmpG:green>242</xmpG:green>
+ <xmpG:blue>242</xmpG:blue>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpG:Colorants>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:groupName>Splash</xmpG:groupName>
+ <xmpG:groupType>1</xmpG:groupType>
+ <xmpG:Colorants>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=214 G=149 B=68</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>214</xmpG:red>
+ <xmpG:green>149</xmpG:green>
+ <xmpG:blue>68</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=71 G=152 B=237</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>71</xmpG:red>
+ <xmpG:green>152</xmpG:green>
+ <xmpG:blue>237</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=42 G=81 B=224</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>42</xmpG:red>
+ <xmpG:green>81</xmpG:green>
+ <xmpG:blue>224</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=180 G=58 B=228</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>180</xmpG:red>
+ <xmpG:green>58</xmpG:green>
+ <xmpG:blue>228</xmpG:blue>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpG:Colorants>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpTPg:SwatchGroups>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
+ <pdf:Producer>Adobe PDF library 9.00</pdf:Producer>
+ </rdf:Description>
+ </rdf:RDF>
+</x:xmpmeta>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<?xpacket end="w"?> endstream endobj 3 0 obj <</Count 1/Kids[5 0 R]/Type/Pages>> endobj 5 0 obj <</ArtBox[2.0 3.0 18.0 19.0]/BleedBox[0.0 0.0 20.0 20.0]/Contents 6 0 R/MediaBox[0.0 0.0 20.0 20.0]/Parent 3 0 R/Resources<</ExtGState<</GS0 7 0 R>>/Properties<</MC0<</Color[65535 20224 20224]/Dimmed false/Editable true/Preview true/Printed true/Title(Layer 2)/Visible true>>/MC1<</Color[20224 65535 65535]/Dimmed false/Editable true/Preview true/Printed true/Title(Layer 7)/Visible true>>/MC2<</Color[0 21845 0]/Dimmed false/Editable true/Preview true/Printed true/Title(Layer 5)/Visible true>>>>>>/TrimBox[0.0 0.0 20.0 20.0]/Type/Page>> endobj 6 0 obj <</Filter/FlateDecode/Length 214>>stream
+H‰ÌQ;Â0 Ý}Šw¤q›TéÊG]èP˜â3$ÊÄí±“ª0p
+ÏÔ' Û–<:ü¥Ê+íf²PiÃizÁ
+²ñó·ðÚ†|IgëÙ#ã@ÆKó€ÚƺR7Xïddšn%ýtOo
+0000000016 00000 n
+0000000076 00000 n
+0000048847 00000 n
+0000000000 00000 f
+0000048898 00000 n
+0000049452 00000 n
+0000049734 00000 n
+0000049846 00000 n
+trailer <</Size 9/Root 1 0 R/Info 8 0 R/ID[<6E648B55580B4616AD8999C45B44F5EC><51E6FA2ED7984AA4AE5261DEE0025340>]>> startxref 50022 %%EOF \ No newline at end of file
diff --git a/release/darwin/buildbot/background.tif b/release/darwin/buildbot/background.tif
new file mode 100644
index 00000000000..5253a6bf439
--- /dev/null
+++ b/release/darwin/buildbot/background.tif
Binary files differ
diff --git a/release/darwin/bundle.sh b/release/darwin/bundle.sh
index b0f489e6fc2..91ce4f61d37 100755
--- a/release/darwin/bundle.sh
+++ b/release/darwin/bundle.sh
@@ -54,6 +54,11 @@ while [[ $# -gt 0 ]]; do
shift
shift
;;
+ --background-image)
+ _background_image="$2"
+ shift
+ shift
+ ;;
-h|--help)
echo "Usage:"
echo " $(basename "$0") --source DIR --dmg IMAGENAME "
diff --git a/release/datafiles/blender_icons.svg b/release/datafiles/blender_icons.svg
index 2633ece87fc..4732b6d65f0 100644
--- a/release/datafiles/blender_icons.svg
+++ b/release/datafiles/blender_icons.svg
@@ -1,5362 +1,24022 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="602" height="640" id="svg2" sodipodi:version="0.32" inkscape:version="0.92.3 (2405546, 2018-03-11)" version="1.0" sodipodi:docname="blender_icons 2.81 - SMALL.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape" style="display:inline;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\ICONS - no backdrop.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
-
- <defs id="defs4">
-
- <linearGradient inkscape:collect="always" id="linearGradient11146">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop11142"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop11144"/>
- </linearGradient>
- <linearGradient id="linearGradient18495" inkscape:collect="always">
- <stop id="stop18497" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop18499" offset="1" style="stop-color:#000000;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient17265">
- <stop style="stop-color:#ffb769;stop-opacity:1;" offset="0" id="stop17267"/>
- <stop style="stop-color:#ffeeaa;stop-opacity:0;" offset="1" id="stop17269"/>
- </linearGradient>
- <linearGradient id="linearGradient17073">
- <stop style="stop-color:#2561b7;stop-opacity:1;" offset="0" id="stop17075"/>
- <stop style="stop-color:#f9fbff;stop-opacity:1;" offset="1" id="stop17077"/>
- </linearGradient>
- <linearGradient inkscape:collect="always" id="linearGradient18134">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop18136"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop18138"/>
- </linearGradient>
- <linearGradient id="linearGradient16595">
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop16597"/>
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="1" id="stop16599"/>
- </linearGradient>
- <linearGradient id="linearGradient16723">
- <stop style="stop-color:#343434;stop-opacity:0.61960787;" offset="0" id="stop16725"/>
- <stop style="stop-color:#3d3d3d;stop-opacity:1;" offset="1" id="stop16727"/>
- </linearGradient>
- <linearGradient id="linearGradient106427">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop106429"/>
- <stop style="stop-color:#030303;stop-opacity:1" offset="1" id="stop106431"/>
- </linearGradient>
- <linearGradient id="linearGradient29304">
- <stop style="stop-color:#11233f;stop-opacity:1;" offset="0" id="stop29306"/>
- <stop style="stop-color:#162d50;stop-opacity:0;" offset="1" id="stop29308"/>
- </linearGradient>
- <linearGradient id="linearGradient24343">
- <stop id="stop24345" offset="0" style="stop-color:#184990;stop-opacity:1;"/>
- <stop id="stop24347" offset="1" style="stop-color:#c1d5f3;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient25417">
- <stop id="stop25419" offset="0" style="stop-color:#60553b;stop-opacity:1;"/>
- <stop id="stop25421" offset="1" style="stop-color:#b0a17f;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient25108">
- <stop id="stop25110" offset="0" style="stop-color:white;stop-opacity:1;"/>
- <stop id="stop25112" offset="1" style="stop-color:#c6c6c6;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient43807">
- <stop style="stop-color:#e31b1b;stop-opacity:1;" offset="0" id="stop43809"/>
- <stop style="stop-color:#930000;stop-opacity:1;" offset="1" id="stop43811"/>
- </linearGradient>
- <linearGradient id="linearGradient38256">
- <stop id="stop38258" offset="0" style="stop-color:#e7e0c7;stop-opacity:1;"/>
- <stop id="stop38260" offset="1" style="stop-color:#f1eddf;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient40703">
- <stop style="stop-color:#143564;stop-opacity:1;" offset="0" id="stop40705"/>
- <stop style="stop-color:#c1d7f8;stop-opacity:1;" offset="1" id="stop40707"/>
- </linearGradient>
- <linearGradient id="linearGradient35411">
- <stop id="stop35414" offset="0" style="stop-color:#2b5385;stop-opacity:1;"/>
- <stop id="stop35416" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient28887">
- <stop style="stop-color:#2158a7;stop-opacity:1;" offset="0" id="stop28889"/>
- <stop style="stop-color:#2f73d5;stop-opacity:0.19607843;" offset="1" id="stop28891"/>
- </linearGradient>
- <linearGradient id="linearGradient24144">
- <stop id="stop24146" offset="0" style="stop-color:#3d361a;stop-opacity:1;"/>
- <stop style="stop-color:#d1c595;stop-opacity:1;" offset="0.17958513" id="stop24148"/>
- <stop id="stop24150" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient24727">
- <stop style="stop-color:#3d361a;stop-opacity:1;" offset="0" id="stop24729"/>
- <stop id="stop24731" offset="0.77520341" style="stop-color:#d1c595;stop-opacity:1;"/>
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="1" id="stop24733"/>
- </linearGradient>
- <linearGradient id="linearGradient24711">
- <stop style="stop-color:#3d361a;stop-opacity:1;" offset="0" id="stop24713"/>
- <stop id="stop24715" offset="0.21609697" style="stop-color:#d1c595;stop-opacity:1;"/>
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="1" id="stop24717"/>
- </linearGradient>
- <linearGradient id="linearGradient24687">
- <stop style="stop-color:#3d361a;stop-opacity:1;" offset="0" id="stop24689"/>
- <stop id="stop24691" offset="0.59630167" style="stop-color:#d1c595;stop-opacity:1;"/>
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="1" id="stop24693"/>
- </linearGradient>
- <linearGradient id="linearGradient42459">
- <stop style="stop-color:#e7dfab;stop-opacity:1;" offset="0" id="stop42461"/>
- <stop style="stop-color:#af9d33;stop-opacity:1;" offset="1" id="stop42463"/>
- </linearGradient>
- <linearGradient id="linearGradient24143">
- <stop id="stop24145" offset="0" style="stop-color:#3d361a;stop-opacity:1;"/>
- <stop style="stop-color:#d1c595;stop-opacity:1;" offset="0.5" id="stop24669"/>
- <stop id="stop24147" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient24642">
- <stop style="stop-color:#d0dbe8;stop-opacity:1;" offset="0" id="stop24644"/>
- <stop style="stop-color:#6ca3e9;stop-opacity:0;" offset="1" id="stop24646"/>
- </linearGradient>
- <linearGradient id="linearGradient24632">
- <stop style="stop-color:#28394f;stop-opacity:1;" offset="0" id="stop24634"/>
- <stop id="stop24636" offset="0.17637014" style="stop-color:#0d386a;stop-opacity:0.78431374;"/>
- <stop id="stop24638" offset="0.35274029" style="stop-color:#18437d;stop-opacity:0.47058824;"/>
- <stop style="stop-color:#154e94;stop-opacity:0;" offset="1" id="stop24640"/>
- </linearGradient>
- <linearGradient id="linearGradient23974">
- <stop id="stop23976" offset="0" style="stop-color:#2561b7;stop-opacity:1;"/>
- <stop id="stop23978" offset="1" style="stop-color:#f9fbff;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient40983">
- <stop style="stop-color:#6a9ae0;stop-opacity:1;" offset="0" id="stop40985"/>
- <stop style="stop-color:#5189db;stop-opacity:0;" offset="1" id="stop40987"/>
- </linearGradient>
- <linearGradient id="linearGradient8864">
- <stop id="stop8866" offset="0" style="stop-color:#b43214;stop-opacity:1;"/>
- <stop id="stop8868" offset="1" style="stop-color:#e86830;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient22562">
- <stop style="stop-color:#001e50;stop-opacity:1;" offset="0" id="stop22564"/>
- <stop style="stop-color:#1e3e70;stop-opacity:0;" offset="1" id="stop22566"/>
- </linearGradient>
- <linearGradient id="linearGradient22882">
- <stop style="stop-color:#323232;stop-opacity:0;" offset="0" id="stop22884"/>
- <stop id="stop22886" offset="0.21233012" style="stop-color:#323232;stop-opacity:0.49803922;"/>
- <stop id="stop22888" offset="0.54086536" style="stop-color:#323232;stop-opacity:1;"/>
- <stop style="stop-color:#323232;stop-opacity:0.49803922;" offset="0.83381736" id="stop22890"/>
- <stop style="stop-color:#323232;stop-opacity:0;" offset="1" id="stop22892"/>
- </linearGradient>
- <linearGradient id="linearGradient21609">
- <stop id="stop21611" offset="0" style="stop-color:black;stop-opacity:1"/>
- <stop id="stop21613" offset="1" style="stop-color:white;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient21609" id="linearGradient20961" gradientUnits="userSpaceOnUse" x1="162" y1="103.71875" x2="165" y2="103.75"/>
-
- <linearGradient id="linearGradient18105">
- <stop id="stop18107" offset="0" style="stop-color:#162d50;stop-opacity:1"/>
- <stop id="stop18109" offset="1" style="stop-color:#1e3e70;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient21327">
- <stop style="stop-color:#1e3e70;stop-opacity:1;" offset="0" id="stop21329"/>
- <stop style="stop-color:#1e3e70;stop-opacity:0;" offset="1" id="stop21331"/>
- </linearGradient>
- <linearGradient id="linearGradient18821">
- <stop style="stop-color:#fc6b58;stop-opacity:1;" offset="0" id="stop18823"/>
- <stop style="stop-color:#fc6b58;stop-opacity:0;" offset="1" id="stop18825"/>
- </linearGradient>
- <linearGradient id="linearGradient29149">
- <stop id="stop29151" offset="0" style="stop-color:#76adff;stop-opacity:1;"/>
- <stop id="stop29153" offset="1" style="stop-color:#a5c9ff;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient15437">
- <stop id="stop15439" offset="0" style="stop-color:#20529e;stop-opacity:1;"/>
- <stop id="stop15441" offset="1" style="stop-color:#1d3f71;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient15425">
- <stop style="stop-color:#8c0000;stop-opacity:1;" offset="0" id="stop15427"/>
- <stop style="stop-color:#c80000;stop-opacity:0;" offset="1" id="stop15429"/>
- </linearGradient>
- <linearGradient id="linearGradient14262">
- <stop id="stop14264" offset="0" style="stop-color:#2661b6;stop-opacity:1;"/>
- <stop id="stop14266" offset="1" style="stop-color:#c1d7f8;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient5060">
- <stop id="stop5062" offset="0" style="stop-color:black;stop-opacity:1;"/>
- <stop id="stop5064" offset="1" style="stop-color:#000000;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient27957">
- <stop id="stop27959" offset="0" style="stop-color:#ffffff;stop-opacity:0;"/>
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0.59290552" id="stop27963"/>
- <stop id="stop27961" offset="1" style="stop-color:#ffffff;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient20756">
- <stop style="stop-color:#932200;stop-opacity:1;" offset="0" id="stop20758"/>
- <stop style="stop-color:#f8420a;stop-opacity:1;" offset="1" id="stop20760"/>
- </linearGradient>
- <linearGradient id="linearGradient47130">
- <stop style="stop-color:#ed7b00;stop-opacity:1;" offset="0" id="stop47132"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop47134"/>
- </linearGradient>
- <linearGradient id="linearGradient32842">
- <stop style="stop-color:#183e75;stop-opacity:1;" offset="0" id="stop32844"/>
- <stop style="stop-color:#1d3f71;stop-opacity:0;" offset="1" id="stop32846"/>
- </linearGradient>
- <linearGradient id="linearGradient20973">
- <stop id="stop20975" offset="0" style="stop-color:#15ff00;stop-opacity:1;"/>
- <stop id="stop20977" offset="1" style="stop-color:#15ff00;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient20962">
- <stop style="stop-color:#00a8ff;stop-opacity:1;" offset="0" id="stop20965"/>
- <stop style="stop-color:#00a8ff;stop-opacity:0;" offset="1" id="stop20967"/>
- </linearGradient>
- <linearGradient id="linearGradient20036">
- <stop style="stop-color:#ffb55e;stop-opacity:1;" offset="0" id="stop20038"/>
- <stop style="stop-color:#ff8400;stop-opacity:0;" offset="1" id="stop20040"/>
- </linearGradient>
- <linearGradient id="linearGradient10585">
- <stop id="stop10587" offset="0.0000000" style="stop-color:#d7d7d7;stop-opacity:1.0000000;"/>
- <stop id="stop10595" offset="1.0000000" style="stop-color:#000000;stop-opacity:1.0000000;"/>
- </linearGradient>
- <linearGradient id="linearGradient31320">
- <stop style="stop-color:white;stop-opacity:1;" offset="0" id="stop31322"/>
- <stop style="stop-color:white;stop-opacity:0;" offset="1" id="stop31324"/>
- </linearGradient>
- <linearGradient id="linearGradient23178">
- <stop style="stop-color:#ff992b;stop-opacity:1;" offset="0" id="stop23180"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop23182"/>
- </linearGradient>
- <linearGradient id="linearGradient13938">
- <stop id="stop13940" offset="0" style="stop-color:#6e0c00;stop-opacity:1;"/>
- <stop id="stop13942" offset="1" style="stop-color:#ee3800;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient14232">
- <stop style="stop-color:#fff32a;stop-opacity:1;" offset="0" id="stop14234"/>
- <stop style="stop-color:#fff551;stop-opacity:0;" offset="1" id="stop14236"/>
- </linearGradient>
- <linearGradient id="linearGradient14418">
- <stop id="stop14420" offset="0" style="stop-color:#fa2509;stop-opacity:1;"/>
- <stop id="stop14422" offset="1" style="stop-color:#fa2509;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient1610" id="linearGradient18670" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.2078427,0,0,1.0516432,-357.40769,69.427229)" x1="362.28571" y1="-45.098213" x2="352.46426" y2="-54.124699"/>
-
- <linearGradient id="linearGradient31456">
- <stop style="stop-color:#2b1600;stop-opacity:1;" offset="0" id="stop31458"/>
- <stop style="stop-color:#6e3900;stop-opacity:0;" offset="1" id="stop31460"/>
- </linearGradient>
- <linearGradient id="linearGradient19425">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop19427"/>
- <stop id="stop19431" offset="0.63109845" style="stop-color:#fffffe;stop-opacity:0.65789473;"/>
- <stop style="stop-color:#fffffe;stop-opacity:0.0000000;" offset="1.0000000" id="stop19429"/>
- </linearGradient>
- <linearGradient id="linearGradient9030">
- <stop style="stop-color:white;stop-opacity:1;" offset="0" id="stop9032"/>
- <stop style="stop-color:white;stop-opacity:0;" offset="1" id="stop9034"/>
- </linearGradient>
- <linearGradient id="linearGradient1610">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop1611"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop1612"/>
- </linearGradient>
- <linearGradient id="linearGradient37542">
- <stop id="stop37544" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient30124">
- <stop style="stop-color:#1d4a8c;stop-opacity:1;" offset="0" id="stop30126"/>
- <stop style="stop-color:#c1d4f2;stop-opacity:1;" offset="1" id="stop30128"/>
- </linearGradient>
- <linearGradient id="linearGradient15893">
- <stop style="stop-color:#2968c3;stop-opacity:1;" offset="0" id="stop15895"/>
- <stop id="stop15897" offset="0.37679368" style="stop-color:#b5ccf0;stop-opacity:1;"/>
- <stop style="stop-color:#b5ccf0;stop-opacity:1;" offset="0.59786767" id="stop15899"/>
- <stop style="stop-color:#2968c3;stop-opacity:1;" offset="1" id="stop15901"/>
- </linearGradient>
- <linearGradient id="linearGradient319">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321"/>
- </linearGradient>
- <linearGradient id="linearGradient10069">
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop10071"/>
- <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop10073"/>
- </linearGradient>
- <linearGradient id="linearGradient32998">
- <stop style="stop-color:#2968c3;stop-opacity:1;" offset="0" id="stop33000"/>
- <stop style="stop-color:#c1d7f8;stop-opacity:1;" offset="1" id="stop33002"/>
- </linearGradient>
-
-
-
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient1610" id="linearGradient69009" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.5466301,0,0,1.6489946,-293.01107,-16.485383)" x1="582" y1="49.294117" x2="582" y2="47.176472"/>
-
- <linearGradient id="linearGradient39155">
- <stop id="stop39157" offset="0" style="stop-color:white;stop-opacity:1;"/>
- <stop id="stop39159" offset="1" style="stop-color:#dadada;stop-opacity:1;"/>
- </linearGradient>
-
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient1610" id="linearGradient25381" gradientUnits="userSpaceOnUse" gradientTransform="translate(-1,21)" x1="342" y1="288.5" x2="344.5" y2="288.5"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient1610" id="linearGradient25383" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0,1,-1,0,638,-40)" x1="342" y1="288.5" x2="344.5" y2="288.5"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient1610" id="linearGradient25385" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-1,0,0,-1,699,599)" x1="342" y1="288.5" x2="344.5" y2="288.5"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient1610" id="linearGradient25387" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0,-1,1,0,60,660)" x1="342" y1="288.5" x2="344.5" y2="288.5"/>
-
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient1610" id="linearGradient32298" gradientUnits="userSpaceOnUse" x1="-117.5" y1="431.5" x2="-119.5" y2="429.5" gradientTransform="translate(258,-96.99999)"/>
-
- <linearGradient id="linearGradient1610-7-6">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop1611-4-1"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop1612-0-4"/>
- </linearGradient>
- <linearGradient id="linearGradient10069-4-2">
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop10071-8-3"/>
- <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop10073-8-2"/>
- </linearGradient>
- <linearGradient id="linearGradient35411-4-27">
- <stop id="stop35414-0-9" offset="0" style="stop-color:#2b5385;stop-opacity:1;"/>
- <stop id="stop35416-9-5" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient35411-8-1-3">
- <stop id="stop35414-2-7-1" offset="0" style="stop-color:#2b5385;stop-opacity:1;"/>
- <stop id="stop35416-4-1-2" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient23974-5-4">
- <stop id="stop23976-27-1" offset="0" style="stop-color:#2561b7;stop-opacity:1;"/>
- <stop id="stop23978-6-1" offset="1" style="stop-color:#f9fbff;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient1610-8">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop1611-7"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop1612-4"/>
- </linearGradient>
- <linearGradient id="linearGradient319-77">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-9"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-31"/>
- </linearGradient>
- <linearGradient id="linearGradient23974-4">
- <stop id="stop23976-20" offset="0" style="stop-color:#2561b7;stop-opacity:1;"/>
- <stop id="stop23978-9" offset="1" style="stop-color:#f9fbff;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient319-37">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-2"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-60"/>
- </linearGradient>
-
- <linearGradient id="linearGradient1610-7409">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop1611-488"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop1612-2"/>
- </linearGradient>
- <linearGradient id="linearGradient40578-4-8-5">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop40580-8-9-5"/>
- <stop style="stop-color:black;stop-opacity:0;" offset="1" id="stop40582-6-8-17"/>
- </linearGradient>
- <linearGradient id="linearGradient58334-1">
- <stop id="stop58336-5" offset="0.0000000" style="stop-color:#ffffff;stop-opacity:0.87628865;"/>
- <stop id="stop58338-27" offset="1.0000000" style="stop-color:#fffffe;stop-opacity:0.0000000;"/>
- </linearGradient>
-
- <linearGradient id="linearGradient1610-6">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop1611-18"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop1612-92"/>
- </linearGradient>
- <linearGradient id="linearGradient10069-9">
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop10071-5"/>
- <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop10073-43"/>
- </linearGradient>
- <linearGradient id="linearGradient21327-6">
- <stop style="stop-color:#1e3e70;stop-opacity:1;" offset="0" id="stop21329-3"/>
- <stop style="stop-color:#1e3e70;stop-opacity:0;" offset="1" id="stop21331-4"/>
- </linearGradient>
- <linearGradient id="linearGradient20055-8-4">
- <stop id="stop20057-8-0" offset="0" style="stop-color:#0a2a5a;stop-opacity:1;"/>
- <stop id="stop20059-2-0" offset="1" style="stop-color:#3771c8;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient39088">
- <stop id="stop39090" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop39092" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient1610-83">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop1611-24"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop1612-11"/>
- </linearGradient>
- <linearGradient id="linearGradient10069-95">
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop10071-10"/>
- <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop10073-64"/>
- </linearGradient>
- <linearGradient id="linearGradient10069-3">
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop10071-87"/>
- <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop10073-42"/>
- </linearGradient>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient1610-83" id="linearGradient38961" gradientUnits="userSpaceOnUse" x1="488.5" y1="568" x2="495" y2="568"/>
-
- <linearGradient id="linearGradient319-46">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-03"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-62"/>
- </linearGradient>
-
- <linearGradient id="linearGradient1610-74-9-1">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop1611-0-8-7"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop1612-9-3-1"/>
- </linearGradient>
- <linearGradient id="linearGradient58334-8-6-5">
- <stop id="stop58336-8-9-2" offset="0.0000000" style="stop-color:#ffffff;stop-opacity:0.87628865;"/>
- <stop id="stop58338-24-8-7" offset="1.0000000" style="stop-color:#fffffe;stop-opacity:0.0000000;"/>
- </linearGradient>
- <linearGradient id="linearGradient319-5-6-2">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-761-2-1"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-89-7-6"/>
- </linearGradient>
- <linearGradient id="linearGradient13973-3-7-8">
- <stop style="stop-color:#3c4c18;stop-opacity:1;" offset="0" id="stop13975-1-8-9"/>
- <stop style="stop-color:#9aff31;stop-opacity:0;" offset="1" id="stop13977-2-0-2"/>
- </linearGradient>
- <linearGradient id="linearGradient37542-3-0-7-6">
- <stop id="stop37544-1-6-6-5" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546-2-1-7-0" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient319-34-8-7-0">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-11-9-8-0"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-38-3-1-6"/>
- </linearGradient>
- <linearGradient id="linearGradient10069-7-6-7-4">
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop10071-81-3-2-4"/>
- <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop10073-6-7-5-6"/>
- </linearGradient>
- <linearGradient id="linearGradient44627">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop44629"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop44631"/>
- </linearGradient>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient44627" id="linearGradient43826" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-1,0,0,1,1444.9824,-215)" x1="689.47357" y1="427" x2="685.47357" y2="427"/>
-
- <linearGradient id="linearGradient37542-7">
- <stop id="stop37544-40" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546-94" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient37542-5">
- <stop id="stop37544-1" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546-71" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient10069-9-71">
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop10071-5-1"/>
- <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop10073-43-5"/>
- </linearGradient>
- <linearGradient id="linearGradient23974-2">
- <stop id="stop23976-2" offset="0" style="stop-color:#2561b7;stop-opacity:1;"/>
- <stop id="stop23978-1" offset="1" style="stop-color:#f9fbff;stop-opacity:1"/>
- </linearGradient>
-
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient23974-2" id="linearGradient28968" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.4646688,0,0,1.4650206,168.77325,-157.03253)" x1="-38.103703" y1="266.11719" x2="-20.826464" y2="253.23859"/>
- <linearGradient id="linearGradient319-5">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-761"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-8"/>
- </linearGradient>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient37542-7" id="linearGradient29424" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.4646688,0,0,1.4650206,168.77325,-157.03253)" x1="-26.511335" y1="257.99881" x2="-30.075666" y2="259.87677"/>
-
- <linearGradient id="linearGradient21327-6-8">
- <stop style="stop-color:#1e3e70;stop-opacity:1;" offset="0" id="stop21329-3-4"/>
- <stop style="stop-color:#1e3e70;stop-opacity:0;" offset="1" id="stop21331-4-0"/>
- </linearGradient>
- <linearGradient id="linearGradient28526">
- <stop id="stop28528" offset="0" style="stop-color:#2561b7;stop-opacity:1;"/>
- <stop id="stop28530" offset="1" style="stop-color:#f9fbff;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient319-62">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-90"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-4"/>
- </linearGradient>
- <linearGradient id="linearGradient1610-52-2">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop1611-32-8"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop1612-46-8"/>
- </linearGradient>
- <linearGradient id="linearGradient319-62-8">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-90-6"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-4-0"/>
- </linearGradient>
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient1610-52-2" id="radialGradient29805" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.94105289,0.01178942,-0.01073736,0.8570756,238.4669,249.70522)" cx="-30.028414" cy="19.425121" fx="-30.028414" fy="19.425121" r="7"/>
-
-
- <radialGradient id="radialGradient16142-7" cx="20.892099" cy="64.567902" r="5.257" fx="20.892099" fy="64.567902" gradientUnits="userSpaceOnUse">
- <stop offset="0" style="stop-color:#F0F0F0" id="stop16144-4"/>
- <stop offset="1" style="stop-color:#474747" id="stop16146-0"/>
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="602"
+ height="640"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.92.3 (2405546, 2018-03-11)"
+ version="1.0"
+ sodipodi:docname="blender_icons 2.81 - SMALL.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ style="display:inline;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\ICONS - no backdrop.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <title
+ id="title49470">Blender icons v. 2.5.08</title>
+ <defs
+ id="defs4">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 320 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="602 : 320 : 1"
+ inkscape:persp3d-origin="301 : 213.33333 : 1"
+ id="perspective13101" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient11146">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop11142" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop11144" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient18495"
+ inkscape:collect="always">
+ <stop
+ id="stop18497"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop18499"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient17265">
+ <stop
+ style="stop-color:#ffb769;stop-opacity:1;"
+ offset="0"
+ id="stop17267" />
+ <stop
+ style="stop-color:#ffeeaa;stop-opacity:0;"
+ offset="1"
+ id="stop17269" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient17073">
+ <stop
+ style="stop-color:#2561b7;stop-opacity:1;"
+ offset="0"
+ id="stop17075" />
+ <stop
+ style="stop-color:#f9fbff;stop-opacity:1;"
+ offset="1"
+ id="stop17077" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient18134">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop18136" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop18138" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient16595">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop16597" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop16599" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient16723">
+ <stop
+ style="stop-color:#343434;stop-opacity:0.61960787;"
+ offset="0"
+ id="stop16725" />
+ <stop
+ style="stop-color:#3d3d3d;stop-opacity:1;"
+ offset="1"
+ id="stop16727" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient106427">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop106429" />
+ <stop
+ style="stop-color:#030303;stop-opacity:1"
+ offset="1"
+ id="stop106431" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient29304">
+ <stop
+ style="stop-color:#11233f;stop-opacity:1;"
+ offset="0"
+ id="stop29306" />
+ <stop
+ style="stop-color:#162d50;stop-opacity:0;"
+ offset="1"
+ id="stop29308" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient24343">
+ <stop
+ id="stop24345"
+ offset="0"
+ style="stop-color:#184990;stop-opacity:1;" />
+ <stop
+ id="stop24347"
+ offset="1"
+ style="stop-color:#c1d5f3;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient25417">
+ <stop
+ id="stop25419"
+ offset="0"
+ style="stop-color:#60553b;stop-opacity:1;" />
+ <stop
+ id="stop25421"
+ offset="1"
+ style="stop-color:#b0a17f;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient25108">
+ <stop
+ id="stop25110"
+ offset="0"
+ style="stop-color:white;stop-opacity:1;" />
+ <stop
+ id="stop25112"
+ offset="1"
+ style="stop-color:#c6c6c6;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient43807">
+ <stop
+ style="stop-color:#e31b1b;stop-opacity:1;"
+ offset="0"
+ id="stop43809" />
+ <stop
+ style="stop-color:#930000;stop-opacity:1;"
+ offset="1"
+ id="stop43811" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient38256">
+ <stop
+ id="stop38258"
+ offset="0"
+ style="stop-color:#e7e0c7;stop-opacity:1;" />
+ <stop
+ id="stop38260"
+ offset="1"
+ style="stop-color:#f1eddf;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient40703">
+ <stop
+ style="stop-color:#143564;stop-opacity:1;"
+ offset="0"
+ id="stop40705" />
+ <stop
+ style="stop-color:#c1d7f8;stop-opacity:1;"
+ offset="1"
+ id="stop40707" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient35411">
+ <stop
+ id="stop35414"
+ offset="0"
+ style="stop-color:#2b5385;stop-opacity:1;" />
+ <stop
+ id="stop35416"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient28887">
+ <stop
+ style="stop-color:#2158a7;stop-opacity:1;"
+ offset="0"
+ id="stop28889" />
+ <stop
+ style="stop-color:#2f73d5;stop-opacity:0.19607843;"
+ offset="1"
+ id="stop28891" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient24144">
+ <stop
+ id="stop24146"
+ offset="0"
+ style="stop-color:#3d361a;stop-opacity:1;" />
+ <stop
+ style="stop-color:#d1c595;stop-opacity:1;"
+ offset="0.17958513"
+ id="stop24148" />
+ <stop
+ id="stop24150"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient24727">
+ <stop
+ style="stop-color:#3d361a;stop-opacity:1;"
+ offset="0"
+ id="stop24729" />
+ <stop
+ id="stop24731"
+ offset="0.77520341"
+ style="stop-color:#d1c595;stop-opacity:1;" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop24733" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient24711">
+ <stop
+ style="stop-color:#3d361a;stop-opacity:1;"
+ offset="0"
+ id="stop24713" />
+ <stop
+ id="stop24715"
+ offset="0.21609697"
+ style="stop-color:#d1c595;stop-opacity:1;" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop24717" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient24687">
+ <stop
+ style="stop-color:#3d361a;stop-opacity:1;"
+ offset="0"
+ id="stop24689" />
+ <stop
+ id="stop24691"
+ offset="0.59630167"
+ style="stop-color:#d1c595;stop-opacity:1;" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop24693" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient42459">
+ <stop
+ style="stop-color:#e7dfab;stop-opacity:1;"
+ offset="0"
+ id="stop42461" />
+ <stop
+ style="stop-color:#af9d33;stop-opacity:1;"
+ offset="1"
+ id="stop42463" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient24143">
+ <stop
+ id="stop24145"
+ offset="0"
+ style="stop-color:#3d361a;stop-opacity:1;" />
+ <stop
+ style="stop-color:#d1c595;stop-opacity:1;"
+ offset="0.5"
+ id="stop24669" />
+ <stop
+ id="stop24147"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient24642">
+ <stop
+ style="stop-color:#d0dbe8;stop-opacity:1;"
+ offset="0"
+ id="stop24644" />
+ <stop
+ style="stop-color:#6ca3e9;stop-opacity:0;"
+ offset="1"
+ id="stop24646" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient24632">
+ <stop
+ style="stop-color:#28394f;stop-opacity:1;"
+ offset="0"
+ id="stop24634" />
+ <stop
+ id="stop24636"
+ offset="0.17637014"
+ style="stop-color:#0d386a;stop-opacity:0.78431374;" />
+ <stop
+ id="stop24638"
+ offset="0.35274029"
+ style="stop-color:#18437d;stop-opacity:0.47058824;" />
+ <stop
+ style="stop-color:#154e94;stop-opacity:0;"
+ offset="1"
+ id="stop24640" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient23974">
+ <stop
+ id="stop23976"
+ offset="0"
+ style="stop-color:#2561b7;stop-opacity:1;" />
+ <stop
+ id="stop23978"
+ offset="1"
+ style="stop-color:#f9fbff;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient40983">
+ <stop
+ style="stop-color:#6a9ae0;stop-opacity:1;"
+ offset="0"
+ id="stop40985" />
+ <stop
+ style="stop-color:#5189db;stop-opacity:0;"
+ offset="1"
+ id="stop40987" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient8864">
+ <stop
+ id="stop8866"
+ offset="0"
+ style="stop-color:#b43214;stop-opacity:1;" />
+ <stop
+ id="stop8868"
+ offset="1"
+ style="stop-color:#e86830;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient22562">
+ <stop
+ style="stop-color:#001e50;stop-opacity:1;"
+ offset="0"
+ id="stop22564" />
+ <stop
+ style="stop-color:#1e3e70;stop-opacity:0;"
+ offset="1"
+ id="stop22566" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient22882">
+ <stop
+ style="stop-color:#323232;stop-opacity:0;"
+ offset="0"
+ id="stop22884" />
+ <stop
+ id="stop22886"
+ offset="0.21233012"
+ style="stop-color:#323232;stop-opacity:0.49803922;" />
+ <stop
+ id="stop22888"
+ offset="0.54086536"
+ style="stop-color:#323232;stop-opacity:1;" />
+ <stop
+ style="stop-color:#323232;stop-opacity:0.49803922;"
+ offset="0.83381736"
+ id="stop22890" />
+ <stop
+ style="stop-color:#323232;stop-opacity:0;"
+ offset="1"
+ id="stop22892" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient21609">
+ <stop
+ id="stop21611"
+ offset="0"
+ style="stop-color:black;stop-opacity:1" />
+ <stop
+ id="stop21613"
+ offset="1"
+ style="stop-color:white;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient21609"
+ id="linearGradient20961"
+ gradientUnits="userSpaceOnUse"
+ x1="162"
+ y1="103.71875"
+ x2="165"
+ y2="103.75" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask20957">
+ <rect
+ y="101"
+ x="162"
+ height="5"
+ width="8"
+ id="rect20959"
+ style="fill:url(#linearGradient20961);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.29999995;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ </mask>
+ <linearGradient
+ id="linearGradient18105">
+ <stop
+ id="stop18107"
+ offset="0"
+ style="stop-color:#162d50;stop-opacity:1" />
+ <stop
+ id="stop18109"
+ offset="1"
+ style="stop-color:#1e3e70;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient21327">
+ <stop
+ style="stop-color:#1e3e70;stop-opacity:1;"
+ offset="0"
+ id="stop21329" />
+ <stop
+ style="stop-color:#1e3e70;stop-opacity:0;"
+ offset="1"
+ id="stop21331" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient18821">
+ <stop
+ style="stop-color:#fc6b58;stop-opacity:1;"
+ offset="0"
+ id="stop18823" />
+ <stop
+ style="stop-color:#fc6b58;stop-opacity:0;"
+ offset="1"
+ id="stop18825" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient29149">
+ <stop
+ id="stop29151"
+ offset="0"
+ style="stop-color:#76adff;stop-opacity:1;" />
+ <stop
+ id="stop29153"
+ offset="1"
+ style="stop-color:#a5c9ff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient15437">
+ <stop
+ id="stop15439"
+ offset="0"
+ style="stop-color:#20529e;stop-opacity:1;" />
+ <stop
+ id="stop15441"
+ offset="1"
+ style="stop-color:#1d3f71;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient15425">
+ <stop
+ style="stop-color:#8c0000;stop-opacity:1;"
+ offset="0"
+ id="stop15427" />
+ <stop
+ style="stop-color:#c80000;stop-opacity:0;"
+ offset="1"
+ id="stop15429" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient14262">
+ <stop
+ id="stop14264"
+ offset="0"
+ style="stop-color:#2661b6;stop-opacity:1;" />
+ <stop
+ id="stop14266"
+ offset="1"
+ style="stop-color:#c1d7f8;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5060">
+ <stop
+ id="stop5062"
+ offset="0"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ id="stop5064"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient27957">
+ <stop
+ id="stop27959"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0.59290552"
+ id="stop27963" />
+ <stop
+ id="stop27961"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient20756">
+ <stop
+ style="stop-color:#932200;stop-opacity:1;"
+ offset="0"
+ id="stop20758" />
+ <stop
+ style="stop-color:#f8420a;stop-opacity:1;"
+ offset="1"
+ id="stop20760" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient47130">
+ <stop
+ style="stop-color:#ed7b00;stop-opacity:1;"
+ offset="0"
+ id="stop47132" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop47134" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient32842">
+ <stop
+ style="stop-color:#183e75;stop-opacity:1;"
+ offset="0"
+ id="stop32844" />
+ <stop
+ style="stop-color:#1d3f71;stop-opacity:0;"
+ offset="1"
+ id="stop32846" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient20973">
+ <stop
+ id="stop20975"
+ offset="0"
+ style="stop-color:#15ff00;stop-opacity:1;" />
+ <stop
+ id="stop20977"
+ offset="1"
+ style="stop-color:#15ff00;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient20962">
+ <stop
+ style="stop-color:#00a8ff;stop-opacity:1;"
+ offset="0"
+ id="stop20965" />
+ <stop
+ style="stop-color:#00a8ff;stop-opacity:0;"
+ offset="1"
+ id="stop20967" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient20036">
+ <stop
+ style="stop-color:#ffb55e;stop-opacity:1;"
+ offset="0"
+ id="stop20038" />
+ <stop
+ style="stop-color:#ff8400;stop-opacity:0;"
+ offset="1"
+ id="stop20040" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10585">
+ <stop
+ id="stop10587"
+ offset="0.0000000"
+ style="stop-color:#d7d7d7;stop-opacity:1.0000000;" />
+ <stop
+ id="stop10595"
+ offset="1.0000000"
+ style="stop-color:#000000;stop-opacity:1.0000000;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient31320">
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="0"
+ id="stop31322" />
+ <stop
+ style="stop-color:white;stop-opacity:0;"
+ offset="1"
+ id="stop31324" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient23178">
+ <stop
+ style="stop-color:#ff992b;stop-opacity:1;"
+ offset="0"
+ id="stop23180" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop23182" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient13938">
+ <stop
+ id="stop13940"
+ offset="0"
+ style="stop-color:#6e0c00;stop-opacity:1;" />
+ <stop
+ id="stop13942"
+ offset="1"
+ style="stop-color:#ee3800;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient14232">
+ <stop
+ style="stop-color:#fff32a;stop-opacity:1;"
+ offset="0"
+ id="stop14234" />
+ <stop
+ style="stop-color:#fff551;stop-opacity:0;"
+ offset="1"
+ id="stop14236" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient14418">
+ <stop
+ id="stop14420"
+ offset="0"
+ style="stop-color:#fa2509;stop-opacity:1;" />
+ <stop
+ id="stop14422"
+ offset="1"
+ style="stop-color:#fa2509;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient1610"
+ id="linearGradient18670"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.2078427,0,0,1.0516432,-357.40769,69.427229)"
+ x1="362.28571"
+ y1="-45.098213"
+ x2="352.46426"
+ y2="-54.124699" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask18666">
+ <rect
+ y="6"
+ x="62.921577"
+ height="14.000001"
+ width="15.098035"
+ id="rect18668"
+ style="fill:url(#linearGradient18670);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ </mask>
+ <linearGradient
+ id="linearGradient31456">
+ <stop
+ style="stop-color:#2b1600;stop-opacity:1;"
+ offset="0"
+ id="stop31458" />
+ <stop
+ style="stop-color:#6e3900;stop-opacity:0;"
+ offset="1"
+ id="stop31460" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient19425">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop19427" />
+ <stop
+ id="stop19431"
+ offset="0.63109845"
+ style="stop-color:#fffffe;stop-opacity:0.65789473;" />
+ <stop
+ style="stop-color:#fffffe;stop-opacity:0.0000000;"
+ offset="1.0000000"
+ id="stop19429" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient9030">
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="0"
+ id="stop9032" />
+ <stop
+ style="stop-color:white;stop-opacity:0;"
+ offset="1"
+ id="stop9034" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1610">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop1611" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop1612" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37542">
+ <stop
+ id="stop37544"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient30124">
+ <stop
+ style="stop-color:#1d4a8c;stop-opacity:1;"
+ offset="0"
+ id="stop30126" />
+ <stop
+ style="stop-color:#c1d4f2;stop-opacity:1;"
+ offset="1"
+ id="stop30128" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient15893">
+ <stop
+ style="stop-color:#2968c3;stop-opacity:1;"
+ offset="0"
+ id="stop15895" />
+ <stop
+ id="stop15897"
+ offset="0.37679368"
+ style="stop-color:#b5ccf0;stop-opacity:1;" />
+ <stop
+ style="stop-color:#b5ccf0;stop-opacity:1;"
+ offset="0.59786767"
+ id="stop15899" />
+ <stop
+ style="stop-color:#2968c3;stop-opacity:1;"
+ offset="1"
+ id="stop15901" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10069">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop10071" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop10073" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient32998">
+ <stop
+ style="stop-color:#2968c3;stop-opacity:1;"
+ offset="0"
+ id="stop33000" />
+ <stop
+ style="stop-color:#c1d7f8;stop-opacity:1;"
+ offset="1"
+ id="stop33002" />
+ </linearGradient>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask17570">
+ <path
+ sodipodi:nodetypes="cccc"
+ style="fill:#ffffff;fill-rule:evenodd;stroke:none"
+ d="m -44,358 0,14 14,-14 -14,0 z"
+ id="path17572" />
+ </mask>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath18524">
+ <path
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png"
+ transform="matrix(-1.1435655,0,0,1.1436475,512.11415,45.72091)"
+ d="m 262,78.5 a 3.5,3.5 0 1 1 -7,0 3.5,3.5 0 1 1 7,0 z"
+ sodipodi:ry="3.5"
+ sodipodi:rx="3.5"
+ sodipodi:cy="78.5"
+ sodipodi:cx="258.5"
+ id="path18526"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.69954133;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;display:inline"
+ sodipodi:type="arc"
+ inkscape:transform-center-x="-6.3473305"
+ inkscape:transform-center-y="-6.3853012" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask18634">
+ <path
+ sodipodi:nodetypes="ccccscc"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 207,134 0,14 11,0 0,-7.5625 c -1.97252,-0.24738 -3.5,-1.89814 -3.5,-3.9375 0,-0.94675 0.35614,-1.81444 0.90625,-2.5 L 207,134 z"
+ id="path18636" />
+ </mask>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient1610"
+ id="linearGradient69009"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.5466301,0,0,1.6489946,-293.01107,-16.485383)"
+ x1="582"
+ y1="49.294117"
+ x2="582"
+ y2="47.176472" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask69005">
+ <rect
+ style="fill:url(#linearGradient69009);fill-opacity:1;display:inline"
+ id="rect69007"
+ width="24.746082"
+ height="26.383913"
+ x="596.30127"
+ y="39.580433" />
+ </mask>
+ <linearGradient
+ id="linearGradient39155">
+ <stop
+ id="stop39157"
+ offset="0"
+ style="stop-color:white;stop-opacity:1;" />
+ <stop
+ id="stop39159"
+ offset="1"
+ style="stop-color:#dadada;stop-opacity:1;" />
+ </linearGradient>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath24168">
+ <path
+ style="fill:#808080;fill-rule:evenodd;stroke:none"
+ d="m 134.27489,222.11125 c -3.9249,-6.46418 -7.61892,6.46419 -11.54381,0 l 0,0 -1.61614,0 0,8.77283 14.77608,0 0,-8.77283 -1.61613,0 z"
+ id="path24170"
+ sodipodi:nodetypes="cccccccc" />
+ </clipPath>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient1610"
+ id="linearGradient25381"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-1,21)"
+ x1="342"
+ y1="288.5"
+ x2="344.5"
+ y2="288.5" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient1610"
+ id="linearGradient25383"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0,1,-1,0,638,-40)"
+ x1="342"
+ y1="288.5"
+ x2="344.5"
+ y2="288.5" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient1610"
+ id="linearGradient25385"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-1,0,0,-1,699,599)"
+ x1="342"
+ y1="288.5"
+ x2="344.5"
+ y2="288.5" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient1610"
+ id="linearGradient25387"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0,-1,1,0,60,660)"
+ x1="342"
+ y1="288.5"
+ x2="344.5"
+ y2="288.5" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask25369">
+ <g
+ id="g25371"
+ transform="translate(-21,-21)">
+ <path
+ style="fill:url(#linearGradient25381);fill-rule:evenodd;stroke:none"
+ d="m 341,302 8,8 -8,8 0,-16 z"
+ id="path25373"
+ sodipodi:nodetypes="cccc"
+ inkscape:transform-center-x="4" />
+ <path
+ inkscape:transform-center-y="-4"
+ sodipodi:nodetypes="cccc"
+ id="path25375"
+ d="m 357,302 -8,8 -8,-8 16,0 z"
+ style="fill:url(#linearGradient25383);fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:transform-center-x="-4"
+ sodipodi:nodetypes="cccc"
+ id="path25377"
+ d="m 357,318 -8,-8 8,-8 0,16 z"
+ style="fill:url(#linearGradient25385);fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:transform-center-y="4"
+ sodipodi:nodetypes="cccc"
+ id="path25379"
+ d="m 341,318 8,-8 8,8 -16,0 z"
+ style="fill:url(#linearGradient25387);fill-rule:evenodd;stroke:none" />
+ </g>
+ </mask>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient1610"
+ id="linearGradient32298"
+ gradientUnits="userSpaceOnUse"
+ x1="-117.5"
+ y1="431.5"
+ x2="-119.5"
+ y2="429.5"
+ gradientTransform="translate(258,-96.99999)" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask32294">
+ <rect
+ y="323"
+ x="134"
+ height="16"
+ width="9"
+ id="rect32296"
+ style="fill:url(#linearGradient32298);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ </mask>
+ <linearGradient
+ id="linearGradient1610-7-6">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop1611-4-1" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop1612-0-4" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10069-4-2">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop10071-8-3" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop10073-8-2" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient35411-4-27">
+ <stop
+ id="stop35414-0-9"
+ offset="0"
+ style="stop-color:#2b5385;stop-opacity:1;" />
+ <stop
+ id="stop35416-9-5"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient35411-8-1-3">
+ <stop
+ id="stop35414-2-7-1"
+ offset="0"
+ style="stop-color:#2b5385;stop-opacity:1;" />
+ <stop
+ id="stop35416-4-1-2"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient23974-5-4">
+ <stop
+ id="stop23976-27-1"
+ offset="0"
+ style="stop-color:#2561b7;stop-opacity:1;" />
+ <stop
+ id="stop23978-6-1"
+ offset="1"
+ style="stop-color:#f9fbff;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1610-8">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop1611-7" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop1612-4" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-77">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-9" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-31" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient23974-4">
+ <stop
+ id="stop23976-20"
+ offset="0"
+ style="stop-color:#2561b7;stop-opacity:1;" />
+ <stop
+ id="stop23978-9"
+ offset="1"
+ style="stop-color:#f9fbff;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-37">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-2" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-60" />
+ </linearGradient>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath42711">
+ <rect
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect42713"
+ width="8.7252884"
+ height="17.464855"
+ x="127.4093"
+ y="214.76154" />
+ </clipPath>
+ <linearGradient
+ id="linearGradient1610-7409">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop1611-488" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop1612-2" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient40578-4-8-5">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop40580-8-9-5" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop40582-6-8-17" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient58334-1">
+ <stop
+ id="stop58336-5"
+ offset="0.0000000"
+ style="stop-color:#ffffff;stop-opacity:0.87628865;" />
+ <stop
+ id="stop58338-27"
+ offset="1.0000000"
+ style="stop-color:#fffffe;stop-opacity:0.0000000;" />
+ </linearGradient>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath43368-7">
+ <rect
+ style="fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect43370-1"
+ width="16"
+ height="16"
+ x="-79"
+ y="26" />
+ </clipPath>
+ <linearGradient
+ id="linearGradient1610-6">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop1611-18" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop1612-92" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10069-9">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop10071-5" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop10073-43" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient21327-6">
+ <stop
+ style="stop-color:#1e3e70;stop-opacity:1;"
+ offset="0"
+ id="stop21329-3" />
+ <stop
+ style="stop-color:#1e3e70;stop-opacity:0;"
+ offset="1"
+ id="stop21331-4" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient20055-8-4">
+ <stop
+ id="stop20057-8-0"
+ offset="0"
+ style="stop-color:#0a2a5a;stop-opacity:1;" />
+ <stop
+ id="stop20059-2-0"
+ offset="1"
+ style="stop-color:#3771c8;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient39088">
+ <stop
+ id="stop39090"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop39092"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1610-83">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop1611-24" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop1612-11" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10069-95">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop10071-10" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop10073-64" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10069-3">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop10071-87" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop10073-42" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient1610-83"
+ id="linearGradient38961"
+ gradientUnits="userSpaceOnUse"
+ x1="488.5"
+ y1="568"
+ x2="495"
+ y2="568" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask38956">
+ <rect
+ style="fill:url(#linearGradient38961);stroke:none;stroke-width:2.79999995;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect38958"
+ width="16"
+ height="12"
+ x="488"
+ y="560"
+ rx="0"
+ ry="0" />
+ </mask>
+ <linearGradient
+ id="linearGradient319-46">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-03" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-62" />
+ </linearGradient>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask40306">
+ <path
+ id="path40308"
+ d="m 195,11.00001 0,14 0.5,0 13.5,-13.5 0,-0.5 -14,0 z"
+ style="fill:#ffffff;fill-rule:evenodd;stroke:none"
+ sodipodi:nodetypes="cccccc" />
+ </mask>
+ <linearGradient
+ id="linearGradient1610-74-9-1">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop1611-0-8-7" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop1612-9-3-1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient58334-8-6-5">
+ <stop
+ id="stop58336-8-9-2"
+ offset="0.0000000"
+ style="stop-color:#ffffff;stop-opacity:0.87628865;" />
+ <stop
+ id="stop58338-24-8-7"
+ offset="1.0000000"
+ style="stop-color:#fffffe;stop-opacity:0.0000000;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-5-6-2">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-761-2-1" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-89-7-6" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient13973-3-7-8">
+ <stop
+ style="stop-color:#3c4c18;stop-opacity:1;"
+ offset="0"
+ id="stop13975-1-8-9" />
+ <stop
+ style="stop-color:#9aff31;stop-opacity:0;"
+ offset="1"
+ id="stop13977-2-0-2" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37542-3-0-7-6">
+ <stop
+ id="stop37544-1-6-6-5"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546-2-1-7-0"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-34-8-7-0">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-11-9-8-0" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-38-3-1-6" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10069-7-6-7-4">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop10071-81-3-2-4" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop10073-6-7-5-6" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient44627">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop44629" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop44631" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient44627"
+ id="linearGradient43826"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-1,0,0,1,1444.9824,-215)"
+ x1="689.47357"
+ y1="427"
+ x2="685.47357"
+ y2="427" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43822">
+ <rect
+ y="208"
+ x="754"
+ height="9"
+ width="12"
+ id="rect43824"
+ style="opacity:0.93999993;fill:url(#linearGradient43826);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" />
+ </mask>
+ <linearGradient
+ id="linearGradient37542-7">
+ <stop
+ id="stop37544-40"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546-94"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37542-5">
+ <stop
+ id="stop37544-1"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546-71"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10069-9-71">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop10071-5-1" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop10073-43-5" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient23974-2">
+ <stop
+ id="stop23976-2"
+ offset="0"
+ style="stop-color:#2561b7;stop-opacity:1;" />
+ <stop
+ id="stop23978-1"
+ offset="1"
+ style="stop-color:#f9fbff;stop-opacity:1" />
+ </linearGradient>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath28964">
+ <path
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\4.png"
+ sodipodi:nodetypes="ccccc"
+ style="fill:url(#linearGradient28968);fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;enable-background:new"
+ d="m 117.50984,228.63415 0,-15.01646 11.71735,5.49383 0,15.38271 -11.71735,-5.86008 z"
+ id="path28966" />
+ </clipPath>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient23974-2"
+ id="linearGradient28968"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.4646688,0,0,1.4650206,168.77325,-157.03253)"
+ x1="-38.103703"
+ y1="266.11719"
+ x2="-20.826464"
+ y2="253.23859" />
+ <linearGradient
+ id="linearGradient319-5">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-761" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-8" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient37542-7"
+ id="linearGradient29424"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.4646688,0,0,1.4650206,168.77325,-157.03253)"
+ x1="-26.511335"
+ y1="257.99881"
+ x2="-30.075666"
+ y2="259.87677" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask29419">
+ <path
+ id="path29422"
+ d="m 117.50984,229.00041 0,-15.38272 11.71735,5.49383 0,15.74897 -11.71735,-5.86008 z"
+ style="opacity:0.5;fill:url(#linearGradient29424);fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;enable-background:new"
+ sodipodi:nodetypes="ccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\4.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ </mask>
+ <linearGradient
+ id="linearGradient21327-6-8">
+ <stop
+ style="stop-color:#1e3e70;stop-opacity:1;"
+ offset="0"
+ id="stop21329-3-4" />
+ <stop
+ style="stop-color:#1e3e70;stop-opacity:0;"
+ offset="1"
+ id="stop21331-4-0" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient28526">
+ <stop
+ id="stop28528"
+ offset="0"
+ style="stop-color:#2561b7;stop-opacity:1;" />
+ <stop
+ id="stop28530"
+ offset="1"
+ style="stop-color:#f9fbff;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-62">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-90" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-4" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1610-52-2">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop1611-32-8" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop1612-46-8" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-62-8">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-90-6" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-4-0" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient1610-52-2"
+ id="radialGradient29805"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.94105289,0.01178942,-0.01073736,0.8570756,238.4669,249.70522)"
+ cx="-30.028414"
+ cy="19.425121"
+ fx="-30.028414"
+ fy="19.425121"
+ r="7" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask29801">
+ <rect
+ style="opacity:0.35;color:#000000;fill:url(#radialGradient29805);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.71217775;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new"
+ id="rect29803"
+ width="15"
+ height="16"
+ x="204"
+ y="257" />
+ </mask>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath50172-0">
+ <path
+ id="path50174-8"
+ d="m -177.34375,498 a 1.001098,1.001098 0 1 0 0.0937,2 l 3.65625,0 -4.25,5.9375 a 1.0001,1.0001 0 0 0 -0.1875,0.59375 l 0,0.5 a 1.0001,1.0001 0 0 0 1,1 L -171.75,508 a 1.0001,1.0001 0 1 0 0,-2 l -3.6875,0.0312 4.25,-5.9375 A 1.0001,1.0001 0 0 0 -171,499.5 l 0,-0.5 a 1.0001,1.0001 0 0 0 -1,-1 l -5.25,0 a 1.0001,1.0001 0 0 0 -0.0937,0 z"
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" />
+ </clipPath>
+ <radialGradient
+ id="radialGradient16142-7"
+ cx="20.892099"
+ cy="64.567902"
+ r="5.257"
+ fx="20.892099"
+ fy="64.567902"
+ gradientUnits="userSpaceOnUse">
+ <stop
+ offset="0"
+ style="stop-color:#F0F0F0"
+ id="stop16144-4" />
+ <stop
+ offset="1"
+ style="stop-color:#474747"
+ id="stop16146-0" />
</radialGradient>
- <linearGradient id="linearGradient37542-78">
- <stop id="stop37544-2" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546-78" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient9030-2">
- <stop style="stop-color:white;stop-opacity:1;" offset="0" id="stop9032-0"/>
- <stop style="stop-color:white;stop-opacity:0;" offset="1" id="stop9034-89"/>
- </linearGradient>
- <linearGradient id="linearGradient37542-04-82">
- <stop id="stop37544-9-0" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546-4-5" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient9030-38-2">
- <stop style="stop-color:white;stop-opacity:1;" offset="0" id="stop9032-6-7"/>
- <stop style="stop-color:white;stop-opacity:0;" offset="1" id="stop9034-9-6"/>
- </linearGradient>
- <linearGradient id="linearGradient30752-0">
- <stop style="stop-color:#0c1b63;stop-opacity:1;" offset="0" id="stop30754-9"/>
- <stop style="stop-color:#ffffff;stop-opacity:1" offset="1" id="stop30756-5"/>
- </linearGradient>
- <linearGradient id="linearGradient37542-7409-7-7-19-1">
- <stop id="stop37544-48-6-1-8-9" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546-82-1-0-6-8" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient44939-8-4-7-8-3-0-3">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop44941-8-5-40-2-4-2-4"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop44943-2-5-9-4-9-8-0"/>
- </linearGradient>
- <linearGradient id="linearGradient10069-9-7-5-4-6-5-0-3">
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop10071-5-4-58-5-9-1-2-1"/>
- <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop10073-43-0-4-0-8-0-4-9"/>
- </linearGradient>
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient37542-7409-7-7-0-9-9" id="radialGradient52641-2-8" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.39420438,-0.08239205,0.27256031,1.3040635,-361.27885,-161.73915)" cx="-302.79681" cy="462.0358" fx="-302.79681" fy="462.0358" r="8"/>
- <linearGradient id="linearGradient37542-7409-7-7-0-9-9">
- <stop id="stop37544-48-6-1-4-1-1" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546-82-1-0-9-3-3" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient319-31-8-9-1">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-23-2-8-4"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-34-4-4-2"/>
- </linearGradient>
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient37542-7409-7-7-0-9-9" id="radialGradient52883-6-8" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.39420438,-0.08239205,0.27256031,1.3040635,-362.22886,-161.73912)" cx="-302.79681" cy="462.0358" fx="-302.79681" fy="462.0358" r="8"/>
- <linearGradient id="linearGradient34488-1-8">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop34490-0-5-7"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop34492-4-0"/>
- </linearGradient>
- <linearGradient id="linearGradient32877-9-6-8">
- <stop style="stop-color:#b3b3b3;stop-opacity:1;" offset="0" id="stop32879-8-1-1"/>
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="1" id="stop32881-4-3-9"/>
- </linearGradient>
- <linearGradient id="linearGradient33058-4-9-5">
- <stop style="stop-color:#e5250b;stop-opacity:1;" offset="0" id="stop33060-3-3-9"/>
- <stop style="stop-color:#460000;stop-opacity:1;" offset="1" id="stop33062-9-4-7"/>
- </linearGradient>
- <linearGradient id="linearGradient44939-8-4-8-6-8">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop44941-8-5-0-0-0"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop44943-2-5-8-6-1"/>
- </linearGradient>
- <linearGradient id="linearGradient33058-2-7-1-7">
- <stop style="stop-color:#e5250b;stop-opacity:1;" offset="0" id="stop33060-1-8-8-5"/>
- <stop style="stop-color:#460000;stop-opacity:1;" offset="1" id="stop33062-4-3-4-5"/>
- </linearGradient>
- <linearGradient id="linearGradient4671-6-4-1-7">
- <stop id="stop4673-7-6-4-1" offset="0" style="stop-color:#ffd43b;stop-opacity:1;"/>
- <stop id="stop4675-8-0-8-1" offset="1" style="stop-color:#ffe873;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient4689-1-6-4-2">
- <stop id="stop4691-6-2-6-7" offset="0" style="stop-color:#5a9fd4;stop-opacity:1;"/>
- <stop id="stop4693-0-4-8-6" offset="1" style="stop-color:#306998;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient319-12-5">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-34-1"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-81-9"/>
- </linearGradient>
- <linearGradient id="linearGradient15425-8-7">
- <stop style="stop-color:#8c0000;stop-opacity:1;" offset="0" id="stop15427-5-9"/>
- <stop style="stop-color:#c80000;stop-opacity:0;" offset="1" id="stop15429-7-2"/>
- </linearGradient>
- <linearGradient id="linearGradient319-35-31-8">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-38-14-4"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-94-6-3"/>
- </linearGradient>
- <linearGradient id="linearGradient319-35-08-1">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-38-1-0"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-94-1-0"/>
- </linearGradient>
- <linearGradient id="linearGradient319-35-0">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-38-15"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-94-19"/>
- </linearGradient>
- <linearGradient id="linearGradient18105-2-9">
- <stop id="stop18107-8-4" offset="0" style="stop-color:#162d50;stop-opacity:1"/>
- <stop id="stop18109-1-4" offset="1" style="stop-color:#1e3e70;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient15531-9-5">
- <stop style="stop-color:#20539d;stop-opacity:1" offset="0" id="stop15534-1-3"/>
- <stop style="stop-color:#bdc9df;stop-opacity:1" offset="1" id="stop15537-7-5"/>
- </linearGradient>
- <linearGradient id="linearGradient23974-27-5">
- <stop id="stop23976-25-8" offset="0" style="stop-color:#2561b7;stop-opacity:1;"/>
- <stop id="stop23978-48-3" offset="1" style="stop-color:#f9fbff;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient27277-1-8">
- <stop id="stop27279-5-2" offset="0" style="stop-color:#444444;stop-opacity:1;"/>
- <stop id="stop27281-4-1" offset="1" style="stop-color:#adadad;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient21327-63-5">
- <stop style="stop-color:#1e3e70;stop-opacity:1;" offset="0" id="stop21329-9-2"/>
- <stop style="stop-color:#1e3e70;stop-opacity:0;" offset="1" id="stop21331-6-4"/>
- </linearGradient>
- <linearGradient id="linearGradient37542-40-9">
- <stop id="stop37544-6-0" offset="0" style="stop-color:#2561b7;stop-opacity:1"/>
- <stop id="stop37546-3-3" offset="1" style="stop-color:#f9fbff;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient319-84-1">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-78-7"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-30-96"/>
- </linearGradient>
- <linearGradient id="linearGradient319-84-3-2">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-78-3-8"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-30-9-8"/>
- </linearGradient>
- <linearGradient id="linearGradient15482-65">
- <stop id="stop15484-4" offset="0" style="stop-color:#2869ab;stop-opacity:1"/>
- <stop id="stop15486-2" offset="1" style="stop-color:#a7c8f0;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient319-6-11">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-73-0"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-51-9"/>
- </linearGradient>
- <linearGradient id="linearGradient15595-7">
- <stop style="stop-color:#1b4685;stop-opacity:1;" offset="0" id="stop15597-5"/>
- <stop style="stop-color:#183e75;stop-opacity:0;" offset="1" id="stop15599-3"/>
- </linearGradient>
- <linearGradient id="linearGradient319-6-1-5">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-73-4-5"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-51-8-0"/>
- </linearGradient>
- <linearGradient id="linearGradient1610-64-7">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop1611-8-1"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop1612-29-4"/>
- </linearGradient>
- <linearGradient id="linearGradient15275-9">
- <stop id="stop15277-2" offset="0" style="stop-color:black;stop-opacity:1;"/>
- <stop id="stop15279-1" offset="1" style="stop-color:white;stop-opacity:1;"/>
- </linearGradient>
-
- <linearGradient id="linearGradient15361-7">
- <stop style="stop-color:#2766a6;stop-opacity:1;" offset="0" id="stop15363-7"/>
- <stop style="stop-color:#6ba2e5;stop-opacity:1;" offset="1" id="stop15365-9"/>
- </linearGradient>
- <linearGradient id="linearGradient15320-0">
- <stop style="stop-color:#0868f5;stop-opacity:1;" offset="0" id="stop15322-3"/>
- <stop style="stop-color:#fbfdfe;stop-opacity:1;" offset="1" id="stop15324-8"/>
- </linearGradient>
- <linearGradient id="linearGradient23974-0-2">
- <stop id="stop23976-22-8" offset="0" style="stop-color:#2561b7;stop-opacity:1;"/>
- <stop id="stop23978-4-5" offset="1" style="stop-color:#f9fbff;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient31320-4-3">
- <stop style="stop-color:white;stop-opacity:1;" offset="0" id="stop31322-9-2"/>
- <stop style="stop-color:white;stop-opacity:0;" offset="1" id="stop31324-3-5"/>
- </linearGradient>
- <linearGradient id="linearGradient14262-95-2">
- <stop id="stop14264-2-2" offset="0" style="stop-color:#2661b6;stop-opacity:1;"/>
- <stop id="stop14266-7-2" offset="1" style="stop-color:#c1d7f8;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient319-40-7">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-95-9"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-16-1"/>
- </linearGradient>
- <linearGradient id="linearGradient23974-28-0-5">
- <stop id="stop23976-64-2-3" offset="0" style="stop-color:#2561b7;stop-opacity:1;"/>
- <stop id="stop23978-5-3-7" offset="1" style="stop-color:#f9fbff;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient319-23-4">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-65-0"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-3-5"/>
- </linearGradient>
- <linearGradient id="linearGradient23974-48-9">
- <stop id="stop23976-13-7" offset="0" style="stop-color:#2561b7;stop-opacity:1;"/>
- <stop id="stop23978-28-3" offset="1" style="stop-color:#f9fbff;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient20756-2-0">
- <stop style="stop-color:#2968c3;stop-opacity:1;" offset="0" id="stop20758-7-2"/>
- <stop style="stop-color:#b5ccf0;stop-opacity:1;" offset="1" id="stop20760-0-0"/>
- </linearGradient>
- <linearGradient id="linearGradient23974-1-2">
- <stop id="stop23976-3-3" offset="0" style="stop-color:#3e7dd7;stop-opacity:0"/>
- <stop style="stop-color:#8faedb;stop-opacity:1" offset="0.48394433" id="stop28407-8"/>
- <stop id="stop23978-26-7" offset="1" style="stop-color:#f9fbff;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient31320-0-3">
- <stop style="stop-color:white;stop-opacity:1;" offset="0" id="stop31322-4-5"/>
- <stop style="stop-color:white;stop-opacity:0;" offset="1" id="stop31324-9-8"/>
- </linearGradient>
- <linearGradient id="linearGradient14262-97-5">
- <stop id="stop14264-0-6" offset="0" style="stop-color:#2661b6;stop-opacity:1;"/>
- <stop id="stop14266-6-3" offset="1" style="stop-color:#c1d7f8;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient319-406-5">
- <stop style="stop-color:#ffffff;stop-opacity:0" offset="0" id="stop320-76-8"/>
- <stop style="stop-color:#ffffff;stop-opacity:1" offset="1" id="stop321-36-7"/>
- </linearGradient>
- <linearGradient id="linearGradient38363-7">
- <stop id="stop38365-1" offset="0" style="stop-color:#1d4d91;stop-opacity:1"/>
- <stop style="stop-color:#658fd4;stop-opacity:1;" offset="0.44217443" id="stop15519-3"/>
- <stop id="stop38367-1" offset="1" style="stop-color:#c3d7ff;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient37542-56-4">
- <stop id="stop37544-88-5" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546-9-2" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient319-528-2">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-68-7"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-86-7"/>
- </linearGradient>
- <linearGradient id="linearGradient10069-24-4">
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop10071-3-2"/>
- <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop10073-4-8"/>
- </linearGradient>
- <linearGradient id="linearGradient1610-67-6">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop1611-75-5"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop1612-31-3"/>
- </linearGradient>
- <linearGradient id="linearGradient9030-41-5">
- <stop style="stop-color:white;stop-opacity:1;" offset="0" id="stop9032-2-0"/>
- <stop style="stop-color:white;stop-opacity:0;" offset="1" id="stop9034-10-1"/>
- </linearGradient>
- <linearGradient id="linearGradient319-76-2">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-3-9"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-18-2"/>
- </linearGradient>
- <linearGradient id="linearGradient24679-9-1">
- <stop style="stop-color:#3d361a;stop-opacity:1;" offset="0" id="stop24681-7-0"/>
- <stop id="stop24683-6-7" offset="0.45537567" style="stop-color:#d1c595;stop-opacity:1;"/>
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="1" id="stop24685-4-8"/>
- </linearGradient>
- <linearGradient id="linearGradient24671-1-3">
- <stop style="stop-color:#3d361a;stop-opacity:1;" offset="0" id="stop24673-7-4"/>
- <stop id="stop24675-7-4" offset="0.29527253" style="stop-color:#d1c595;stop-opacity:1;"/>
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="1" id="stop24677-5-5"/>
- </linearGradient>
- <linearGradient id="linearGradient319-16-6">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-683-4"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-08-2"/>
- </linearGradient>
- <linearGradient id="linearGradient37542-86-8">
- <stop id="stop37544-39-4" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546-7-6" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient319-0-3">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-15-31"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-26-3"/>
- </linearGradient>
- <linearGradient id="linearGradient37542-86-0-1">
- <stop id="stop37544-39-8-4" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546-7-1-1" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient319-0-2-5">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-15-0-3"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-26-9-3"/>
- </linearGradient>
- <linearGradient id="linearGradient37542-86-2-7">
- <stop id="stop37544-39-5-3" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546-7-2-9" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient319-0-4-4">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-15-3-2"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-26-2-9"/>
- </linearGradient>
- <linearGradient id="linearGradient37542-86-0-6-8">
- <stop id="stop37544-39-8-7-4" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546-7-1-5-6" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient319-0-2-3-8">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-15-0-0-4"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-26-9-5-3"/>
- </linearGradient>
- <linearGradient id="linearGradient10069-5-1-4-8">
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop10071-9-18-9-9"/>
- <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop10073-8-252-1-7"/>
- </linearGradient>
- <linearGradient id="linearGradient36273-9-4-2-3">
- <stop id="stop36275-9-0-3-3" offset="0" style="stop-color:#ffffff;stop-opacity:1;"/>
- <stop id="stop36277-1-3-5-2" offset="1" style="stop-color:#ffffff;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient36273-9-4-22-0">
- <stop id="stop36275-9-0-6-7" offset="0" style="stop-color:#ffffff;stop-opacity:1;"/>
- <stop id="stop36277-1-3-6-9" offset="1" style="stop-color:#ffffff;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient10069-5-1-8">
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop10071-9-18-3"/>
- <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop10073-8-252-2"/>
- </linearGradient>
- <linearGradient id="linearGradient36273-9-4-8">
- <stop id="stop36275-9-0-0" offset="0" style="stop-color:#ffffff;stop-opacity:1;"/>
- <stop id="stop36277-1-3-8" offset="1" style="stop-color:#ffffff;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient10069-5-12">
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop10071-9-7"/>
- <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop10073-8-4"/>
- </linearGradient>
- <linearGradient id="linearGradient36273-9-9">
- <stop id="stop36275-9-8" offset="0" style="stop-color:#ffffff;stop-opacity:1;"/>
- <stop id="stop36277-1-35" offset="1" style="stop-color:#ffffff;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient15859-1-3">
- <stop style="stop-color:#ff992b;stop-opacity:1" offset="0" id="stop15861-1-4"/>
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="1" id="stop15863-7-73"/>
- </linearGradient>
- <linearGradient id="linearGradient319-95">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-242"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-44"/>
- </linearGradient>
- <linearGradient id="linearGradient37542-1">
- <stop id="stop37544-62" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546-4" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient319-75">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-8"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-39"/>
- </linearGradient>
- <linearGradient id="linearGradient1610-36-6-5">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop1611-1-9-6"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop1612-5-9-8"/>
- </linearGradient>
- <linearGradient id="linearGradient37542-96">
- <stop id="stop37544-7-1" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546-0" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient10069-37">
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop10071-0"/>
- <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop10073-2"/>
- </linearGradient>
- <linearGradient id="linearGradient81143-4">
- <stop style="stop-color:#2561b7;stop-opacity:1" offset="0" id="stop81145-0"/>
- <stop style="stop-color:#f9fbff;stop-opacity:1" offset="1" id="stop81147-7"/>
- </linearGradient>
- <linearGradient id="linearGradient37542-7-8-6-0">
- <stop id="stop37544-40-1-3-9" offset="0" style="stop-color:#ffffff;stop-opacity:1;"/>
- <stop id="stop37546-94-7-0-7" offset="1" style="stop-color:#030303;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient319-488-8-2">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-13-8-8"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-67-2-2"/>
- </linearGradient>
- <linearGradient id="linearGradient37542-7-8-6-0-8">
- <stop id="stop37544-40-1-3-9-3" offset="0" style="stop-color:#ffffff;stop-opacity:1;"/>
- <stop id="stop37546-94-7-0-7-1" offset="1" style="stop-color:#030303;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient106427-3">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop106429-1"/>
- <stop style="stop-color:#030303;stop-opacity:1" offset="1" id="stop106431-0"/>
- </linearGradient>
- <linearGradient id="linearGradient319-488-8-2-0">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-13-8-8-7"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-67-2-2-9"/>
- </linearGradient>
- <linearGradient id="linearGradient1610-36-6-7-9">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop1611-1-9-4-5"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop1612-5-9-87-3"/>
- </linearGradient>
- <linearGradient id="linearGradient1610-36-6-7-9-4">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop1611-1-9-4-5-0"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop1612-5-9-87-3-7"/>
- </linearGradient>
- <linearGradient id="linearGradient15097-0-8">
- <stop style="stop-color:#c4c4c4;stop-opacity:1" offset="0" id="stop15099-1-83"/>
- <stop style="stop-color:#868686;stop-opacity:1" offset="1" id="stop15101-9-3"/>
- </linearGradient>
- <linearGradient id="linearGradient23974-5-2-6-6">
- <stop id="stop23976-9-2-7-6" offset="0" style="stop-color:#2561b7;stop-opacity:1;"/>
- <stop id="stop23978-3-1-6-0" offset="1" style="stop-color:#f9fbff;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient31320-5-2-6-7">
- <stop style="stop-color:white;stop-opacity:1;" offset="0" id="stop31322-5-4-5-8"/>
- <stop style="stop-color:white;stop-opacity:0;" offset="1" id="stop31324-0-8-5-8"/>
- </linearGradient>
- <linearGradient id="linearGradient14262-9-5-9-4">
- <stop id="stop14264-5-2-9-0" offset="0" style="stop-color:#2661b6;stop-opacity:1;"/>
- <stop id="stop14266-0-4-4-2" offset="1" style="stop-color:#c1d7f8;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient319-92-8-5-0">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-40-7-9-3"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-93-7-0-5"/>
- </linearGradient>
- <linearGradient id="linearGradient1610-36-6-7-9-4-3">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop1611-1-9-4-5-0-6"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop1612-5-9-87-3-7-8"/>
- </linearGradient>
-
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient44627-7" id="linearGradient43054-6" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.3333333,0,0,1.2727273,2.6666667,29.454545)" x1="-4.2231579" y1="-92.440941" x2="-18.697306" y2="-115.04018"/>
- <linearGradient id="linearGradient44627-7">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop44629-4"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop44631-0"/>
- </linearGradient>
- <linearGradient id="linearGradient10069-9-5-1-8-2-5">
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop10071-5-43-3-0-0-4"/>
- <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop10073-43-1-8-2-5-2"/>
- </linearGradient>
- <linearGradient id="linearGradient10069-9-7-4-74-1">
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop10071-5-4-5-0-5"/>
- <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop10073-43-0-5-9-2"/>
- </linearGradient>
- <linearGradient id="linearGradient44939-8-5">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop44941-8-1"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop44943-2-7"/>
- </linearGradient>
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient44627-7" id="radialGradient48820-9" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,1.0769231,0,5.9230769)" cx="-31" cy="-83.5" fx="-31" fy="-83.5" r="6.5"/>
- <linearGradient id="linearGradient10069-9-7-4-4">
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop10071-5-4-5-8"/>
- <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop10073-43-0-5-6"/>
- </linearGradient>
- <linearGradient id="linearGradient44939-09">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop44941-0"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop44943-0"/>
- </linearGradient>
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient44627-7" id="radialGradient28589-9" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,1.0769231,0,5.9230769)" cx="-30.28125" cy="-84.341515" fx="-30.28125" fy="-84.341515" r="6.5"/>
-
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient43760-6-4" id="linearGradient43044-5" gradientUnits="userSpaceOnUse" x1="-44.709698" y1="-8.4836445" x2="-37.784756" y2="-18.517523" gradientTransform="translate(-0.04018164,0)"/>
- <linearGradient id="linearGradient43760-6-4">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop43762-7-3"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop43764-8-1"/>
- </linearGradient>
- <linearGradient id="linearGradient9030-71-3">
- <stop style="stop-color:white;stop-opacity:1;" offset="0" id="stop9032-15-3"/>
- <stop style="stop-color:white;stop-opacity:0;" offset="1" id="stop9034-276-4"/>
- </linearGradient>
- <linearGradient id="linearGradient10069-9-5-1-1">
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop10071-5-43-3-3"/>
- <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop10073-43-1-8-8"/>
- </linearGradient>
- <linearGradient id="linearGradient44939-2-8">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop44941-7-4"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop44943-7-0"/>
- </linearGradient>
-
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient43760-7" id="linearGradient45875-0" gradientUnits="userSpaceOnUse" gradientTransform="translate(14,0)" x1="-34.051685" y1="-129.32457" x2="-32.542458" y2="-139.90228"/>
- <linearGradient id="linearGradient43760-7">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop43762-79"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop43764-3"/>
- </linearGradient>
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient43760-7" id="radialGradient45877-1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.1099414,-0.9422316,0.4519816,0.05273803,38.220416,-152.21215)" cx="-25.452209" cy="-136.46503" fx="-25.452209" fy="-136.46503" r="8.0066185"/>
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient43760-7" id="radialGradient45451-2" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,0.9952162,167.99999,-60.91415)" cx="59.000011" cy="440.0191" fx="59.000011" fy="440.0191" r="6.5080619"/>
- <linearGradient id="linearGradient319-42-9">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-32-8"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-21-6"/>
- </linearGradient>
- <linearGradient id="linearGradient10069-9-7-0">
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop10071-5-4-2"/>
- <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop10073-43-0-8"/>
- </linearGradient>
-
-
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient1610-5-2" id="linearGradient43192-3" gradientUnits="userSpaceOnUse" x1="-47" y1="44" x2="-43" y2="44"/>
- <linearGradient id="linearGradient1610-5-2">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop1611-17-2"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop1612-115-1"/>
- </linearGradient>
-
-
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient1610-5-2" id="linearGradient43186-6" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0,-1,-1,0,6,6)" x1="-47" y1="44" x2="-43" y2="44"/>
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient44627-7" id="radialGradient25025-8" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.8918342,0,0,0.8918344,-15.699877,27.900732)" cx="49" cy="254.64285" fx="49" fy="254.64285" r="6.5"/>
- <linearGradient id="linearGradient10069-9-7-5-5">
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop10071-5-4-58-7"/>
- <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop10073-43-0-4-5"/>
- </linearGradient>
- <linearGradient id="linearGradient319-76-2-0">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-142-0"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-32-0"/>
- </linearGradient>
- <linearGradient id="linearGradient29761">
- <stop style="stop-color:#b74125;stop-opacity:1;" offset="0" id="stop29763"/>
- <stop style="stop-color:#f9fbff;stop-opacity:1" offset="1" id="stop29765"/>
- </linearGradient>
- <linearGradient id="linearGradient8864-1">
- <stop id="stop8866-0" offset="0" style="stop-color:#b43214;stop-opacity:1;"/>
- <stop id="stop8868-1" offset="1" style="stop-color:#e86830;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient1610-8-8">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop1611-7-7"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop1612-4-6"/>
- </linearGradient>
- <linearGradient id="linearGradient319-77-0">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-9-0"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-31-9"/>
- </linearGradient>
- <linearGradient id="linearGradient1610-4">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop1611-64"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop1612-20"/>
- </linearGradient>
- <linearGradient id="linearGradient1610-4-3">
- <stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop1611-64-0"/>
- <stop style="stop-color:white;stop-opacity:1;" offset="1" id="stop1612-20-3"/>
- </linearGradient>
- <linearGradient id="linearGradient16719">
- <stop id="stop16721" offset="0" style="stop-color:#84d458;stop-opacity:1"/>
- <stop style="stop-color:#5894d4;stop-opacity:1" offset="0.30000001" id="stop5079"/>
- <stop id="stop16723" offset="1" style="stop-color:#afd1f5;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient11820">
- <stop style="stop-color:#afd1f5;stop-opacity:1" offset="0" id="stop11822"/>
- <stop id="stop11824" offset="0.44444144" style="stop-color:#5894d4;stop-opacity:1"/>
- <stop style="stop-color:#5894d4;stop-opacity:1" offset="0.55555254" id="stop11826"/>
- <stop style="stop-color:#ef79ef;stop-opacity:1" offset="1" id="stop11828"/>
- </linearGradient>
- <linearGradient id="linearGradient28147-1-4">
- <stop id="stop28149-4-1" offset="0" style="stop-color:#afd1f5;stop-opacity:1"/>
- <stop style="stop-color:#5894d4;stop-opacity:1" offset="0.18750006" id="stop5469"/>
- <stop style="stop-color:#505050;stop-opacity:1" offset="0.40000001" id="stop28151-7-6"/>
- <stop id="stop28153-8-4" offset="0.60000002" style="stop-color:#505050;stop-opacity:1"/>
- <stop style="stop-color:#5894d4;stop-opacity:1" offset="0.81250006" id="stop5471"/>
- <stop id="stop28155-2-6" offset="1" style="stop-color:#afd1f5;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient319-65-4-8-7">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-14-9-5-9"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-49-3-6-8"/>
- </linearGradient>
- <linearGradient id="linearGradient44939-8-53">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop44941-8-7"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop44943-2-5"/>
- </linearGradient>
- <linearGradient id="linearGradient44939-8-53-7">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop44941-8-7-6"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop44943-2-5-2"/>
- </linearGradient>
- <linearGradient id="linearGradient319-0">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-22"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-19"/>
- </linearGradient>
- <linearGradient id="linearGradient37542-29">
- <stop id="stop37544-67" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546-45" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient319-36">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-18"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-390"/>
- </linearGradient>
- <linearGradient id="linearGradient37542-29-1">
- <stop id="stop37544-67-8" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546-45-9" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient37542-29-7">
- <stop id="stop37544-67-3" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546-45-0" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient319-36-40">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-18-7"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-390-4"/>
- </linearGradient>
- <linearGradient id="linearGradient37542-29-7-8">
- <stop id="stop37544-67-3-0" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546-45-0-9" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient319-36-40-2">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-18-7-8"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-390-4-6"/>
- </linearGradient>
- <linearGradient id="linearGradient319-36-40-2-4">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-18-7-8-5"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-390-4-6-6"/>
- </linearGradient>
- <linearGradient id="linearGradient23974-39">
- <stop id="stop23976-8" offset="0" style="stop-color:#2561b7;stop-opacity:1;"/>
- <stop id="stop23978-23" offset="1" style="stop-color:#f9fbff;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient31320-9">
- <stop style="stop-color:white;stop-opacity:1;" offset="0" id="stop31322-6"/>
- <stop style="stop-color:white;stop-opacity:0;" offset="1" id="stop31324-2"/>
- </linearGradient>
- <linearGradient id="linearGradient14262-6">
- <stop id="stop14264-29" offset="0" style="stop-color:#2661b6;stop-opacity:1;"/>
- <stop id="stop14266-9" offset="1" style="stop-color:#c1d7f8;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient319-61">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-47"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-45"/>
- </linearGradient>
-
-
- <filter color-interpolation-filters="sRGB" inkscape:collect="always" id="filter15613" x="-0.092011765" width="1.1840235" y="-0.097762503" height="1.1955251">
- <feGaussianBlur inkscape:collect="always" stdDeviation="0.65175" id="feGaussianBlur15615"/>
+ <linearGradient
+ id="linearGradient37542-78">
+ <stop
+ id="stop37544-2"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546-78"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient9030-2">
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="0"
+ id="stop9032-0" />
+ <stop
+ style="stop-color:white;stop-opacity:0;"
+ offset="1"
+ id="stop9034-89" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37542-04-82">
+ <stop
+ id="stop37544-9-0"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546-4-5"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient9030-38-2">
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="0"
+ id="stop9032-6-7" />
+ <stop
+ style="stop-color:white;stop-opacity:0;"
+ offset="1"
+ id="stop9034-9-6" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient30752-0">
+ <stop
+ style="stop-color:#0c1b63;stop-opacity:1;"
+ offset="0"
+ id="stop30754-9" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="1"
+ id="stop30756-5" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37542-7409-7-7-19-1">
+ <stop
+ id="stop37544-48-6-1-8-9"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546-82-1-0-6-8"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient44939-8-4-7-8-3-0-3">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop44941-8-5-40-2-4-2-4" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop44943-2-5-9-4-9-8-0" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10069-9-7-5-4-6-5-0-3">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop10071-5-4-58-5-9-1-2-1" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop10073-43-0-4-0-8-0-4-9" />
+ </linearGradient>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask52637-8-8">
+ <rect
+ mask="none"
+ style="fill:url(#radialGradient52641-2-8);fill-opacity:1;stroke:none;stroke-width:2.79999995000000010;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect52639-8-9"
+ width="7.9918551"
+ height="8.9366941"
+ x="-354"
+ y="458"
+ rx="0"
+ ry="0" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient37542-7409-7-7-0-9-9"
+ id="radialGradient52641-2-8"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.39420438,-0.08239205,0.27256031,1.3040635,-361.27885,-161.73915)"
+ cx="-302.79681"
+ cy="462.0358"
+ fx="-302.79681"
+ fy="462.0358"
+ r="8" />
+ <linearGradient
+ id="linearGradient37542-7409-7-7-0-9-9">
+ <stop
+ id="stop37544-48-6-1-4-1-1"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546-82-1-0-9-3-3"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-31-8-9-1">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-23-2-8-4" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-34-4-4-2" />
+ </linearGradient>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask52879-0-5">
+ <rect
+ mask="none"
+ style="fill:url(#radialGradient52883-6-8);fill-opacity:1;stroke:none;stroke-width:2.79999995000000010;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect52881-7-3"
+ width="7.9918551"
+ height="8.9366941"
+ x="-354.95001"
+ y="458"
+ rx="0"
+ ry="0" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient37542-7409-7-7-0-9-9"
+ id="radialGradient52883-6-8"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.39420438,-0.08239205,0.27256031,1.3040635,-362.22886,-161.73912)"
+ cx="-302.79681"
+ cy="462.0358"
+ fx="-302.79681"
+ fy="462.0358"
+ r="8" />
+ <linearGradient
+ id="linearGradient34488-1-8">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop34490-0-5-7" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop34492-4-0" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient32877-9-6-8">
+ <stop
+ style="stop-color:#b3b3b3;stop-opacity:1;"
+ offset="0"
+ id="stop32879-8-1-1" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop32881-4-3-9" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient33058-4-9-5">
+ <stop
+ style="stop-color:#e5250b;stop-opacity:1;"
+ offset="0"
+ id="stop33060-3-3-9" />
+ <stop
+ style="stop-color:#460000;stop-opacity:1;"
+ offset="1"
+ id="stop33062-9-4-7" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient44939-8-4-8-6-8">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop44941-8-5-0-0-0" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop44943-2-5-8-6-1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient33058-2-7-1-7">
+ <stop
+ style="stop-color:#e5250b;stop-opacity:1;"
+ offset="0"
+ id="stop33060-1-8-8-5" />
+ <stop
+ style="stop-color:#460000;stop-opacity:1;"
+ offset="1"
+ id="stop33062-4-3-4-5" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4671-6-4-1-7">
+ <stop
+ id="stop4673-7-6-4-1"
+ offset="0"
+ style="stop-color:#ffd43b;stop-opacity:1;" />
+ <stop
+ id="stop4675-8-0-8-1"
+ offset="1"
+ style="stop-color:#ffe873;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4689-1-6-4-2">
+ <stop
+ id="stop4691-6-2-6-7"
+ offset="0"
+ style="stop-color:#5a9fd4;stop-opacity:1;" />
+ <stop
+ id="stop4693-0-4-8-6"
+ offset="1"
+ style="stop-color:#306998;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-12-5">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-34-1" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-81-9" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient15425-8-7">
+ <stop
+ style="stop-color:#8c0000;stop-opacity:1;"
+ offset="0"
+ id="stop15427-5-9" />
+ <stop
+ style="stop-color:#c80000;stop-opacity:0;"
+ offset="1"
+ id="stop15429-7-2" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-35-31-8">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-38-14-4" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-94-6-3" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-35-08-1">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-38-1-0" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-94-1-0" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-35-0">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-38-15" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-94-19" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient18105-2-9">
+ <stop
+ id="stop18107-8-4"
+ offset="0"
+ style="stop-color:#162d50;stop-opacity:1" />
+ <stop
+ id="stop18109-1-4"
+ offset="1"
+ style="stop-color:#1e3e70;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient15531-9-5">
+ <stop
+ style="stop-color:#20539d;stop-opacity:1"
+ offset="0"
+ id="stop15534-1-3" />
+ <stop
+ style="stop-color:#bdc9df;stop-opacity:1"
+ offset="1"
+ id="stop15537-7-5" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient23974-27-5">
+ <stop
+ id="stop23976-25-8"
+ offset="0"
+ style="stop-color:#2561b7;stop-opacity:1;" />
+ <stop
+ id="stop23978-48-3"
+ offset="1"
+ style="stop-color:#f9fbff;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient27277-1-8">
+ <stop
+ id="stop27279-5-2"
+ offset="0"
+ style="stop-color:#444444;stop-opacity:1;" />
+ <stop
+ id="stop27281-4-1"
+ offset="1"
+ style="stop-color:#adadad;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient21327-63-5">
+ <stop
+ style="stop-color:#1e3e70;stop-opacity:1;"
+ offset="0"
+ id="stop21329-9-2" />
+ <stop
+ style="stop-color:#1e3e70;stop-opacity:0;"
+ offset="1"
+ id="stop21331-6-4" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37542-40-9">
+ <stop
+ id="stop37544-6-0"
+ offset="0"
+ style="stop-color:#2561b7;stop-opacity:1" />
+ <stop
+ id="stop37546-3-3"
+ offset="1"
+ style="stop-color:#f9fbff;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-84-1">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-78-7" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-30-96" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-84-3-2">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-78-3-8" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-30-9-8" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient15482-65">
+ <stop
+ id="stop15484-4"
+ offset="0"
+ style="stop-color:#2869ab;stop-opacity:1" />
+ <stop
+ id="stop15486-2"
+ offset="1"
+ style="stop-color:#a7c8f0;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-6-11">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-73-0" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-51-9" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient15595-7">
+ <stop
+ style="stop-color:#1b4685;stop-opacity:1;"
+ offset="0"
+ id="stop15597-5" />
+ <stop
+ style="stop-color:#183e75;stop-opacity:0;"
+ offset="1"
+ id="stop15599-3" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-6-1-5">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-73-4-5" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-51-8-0" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1610-64-7">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop1611-8-1" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop1612-29-4" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient15275-9">
+ <stop
+ id="stop15277-2"
+ offset="0"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ id="stop15279-1"
+ offset="1"
+ style="stop-color:white;stop-opacity:1;" />
+ </linearGradient>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath42711-8-1">
+ <rect
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect42713-4-3"
+ width="8.7252884"
+ height="17.464855"
+ x="127.4093"
+ y="214.76154" />
+ </clipPath>
+ <linearGradient
+ id="linearGradient15361-7">
+ <stop
+ style="stop-color:#2766a6;stop-opacity:1;"
+ offset="0"
+ id="stop15363-7" />
+ <stop
+ style="stop-color:#6ba2e5;stop-opacity:1;"
+ offset="1"
+ id="stop15365-9" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient15320-0">
+ <stop
+ style="stop-color:#0868f5;stop-opacity:1;"
+ offset="0"
+ id="stop15322-3" />
+ <stop
+ style="stop-color:#fbfdfe;stop-opacity:1;"
+ offset="1"
+ id="stop15324-8" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient23974-0-2">
+ <stop
+ id="stop23976-22-8"
+ offset="0"
+ style="stop-color:#2561b7;stop-opacity:1;" />
+ <stop
+ id="stop23978-4-5"
+ offset="1"
+ style="stop-color:#f9fbff;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient31320-4-3">
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="0"
+ id="stop31322-9-2" />
+ <stop
+ style="stop-color:white;stop-opacity:0;"
+ offset="1"
+ id="stop31324-3-5" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient14262-95-2">
+ <stop
+ id="stop14264-2-2"
+ offset="0"
+ style="stop-color:#2661b6;stop-opacity:1;" />
+ <stop
+ id="stop14266-7-2"
+ offset="1"
+ style="stop-color:#c1d7f8;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-40-7">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-95-9" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-16-1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient23974-28-0-5">
+ <stop
+ id="stop23976-64-2-3"
+ offset="0"
+ style="stop-color:#2561b7;stop-opacity:1;" />
+ <stop
+ id="stop23978-5-3-7"
+ offset="1"
+ style="stop-color:#f9fbff;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-23-4">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-65-0" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-3-5" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient23974-48-9">
+ <stop
+ id="stop23976-13-7"
+ offset="0"
+ style="stop-color:#2561b7;stop-opacity:1;" />
+ <stop
+ id="stop23978-28-3"
+ offset="1"
+ style="stop-color:#f9fbff;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient20756-2-0">
+ <stop
+ style="stop-color:#2968c3;stop-opacity:1;"
+ offset="0"
+ id="stop20758-7-2" />
+ <stop
+ style="stop-color:#b5ccf0;stop-opacity:1;"
+ offset="1"
+ id="stop20760-0-0" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient23974-1-2">
+ <stop
+ id="stop23976-3-3"
+ offset="0"
+ style="stop-color:#3e7dd7;stop-opacity:0" />
+ <stop
+ style="stop-color:#8faedb;stop-opacity:1"
+ offset="0.48394433"
+ id="stop28407-8" />
+ <stop
+ id="stop23978-26-7"
+ offset="1"
+ style="stop-color:#f9fbff;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient31320-0-3">
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="0"
+ id="stop31322-4-5" />
+ <stop
+ style="stop-color:white;stop-opacity:0;"
+ offset="1"
+ id="stop31324-9-8" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient14262-97-5">
+ <stop
+ id="stop14264-0-6"
+ offset="0"
+ style="stop-color:#2661b6;stop-opacity:1;" />
+ <stop
+ id="stop14266-6-3"
+ offset="1"
+ style="stop-color:#c1d7f8;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-406-5">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0"
+ offset="0"
+ id="stop320-76-8" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="1"
+ id="stop321-36-7" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient38363-7">
+ <stop
+ id="stop38365-1"
+ offset="0"
+ style="stop-color:#1d4d91;stop-opacity:1" />
+ <stop
+ style="stop-color:#658fd4;stop-opacity:1;"
+ offset="0.44217443"
+ id="stop15519-3" />
+ <stop
+ id="stop38367-1"
+ offset="1"
+ style="stop-color:#c3d7ff;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37542-56-4">
+ <stop
+ id="stop37544-88-5"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546-9-2"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-528-2">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-68-7" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-86-7" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10069-24-4">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop10071-3-2" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop10073-4-8" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1610-67-6">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop1611-75-5" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop1612-31-3" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient9030-41-5">
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="0"
+ id="stop9032-2-0" />
+ <stop
+ style="stop-color:white;stop-opacity:0;"
+ offset="1"
+ id="stop9034-10-1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-76-2">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-3-9" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-18-2" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient24679-9-1">
+ <stop
+ style="stop-color:#3d361a;stop-opacity:1;"
+ offset="0"
+ id="stop24681-7-0" />
+ <stop
+ id="stop24683-6-7"
+ offset="0.45537567"
+ style="stop-color:#d1c595;stop-opacity:1;" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop24685-4-8" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient24671-1-3">
+ <stop
+ style="stop-color:#3d361a;stop-opacity:1;"
+ offset="0"
+ id="stop24673-7-4" />
+ <stop
+ id="stop24675-7-4"
+ offset="0.29527253"
+ style="stop-color:#d1c595;stop-opacity:1;" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop24677-5-5" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-16-6">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-683-4" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-08-2" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37542-86-8">
+ <stop
+ id="stop37544-39-4"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546-7-6"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-0-3">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-15-31" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-26-3" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37542-86-0-1">
+ <stop
+ id="stop37544-39-8-4"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546-7-1-1"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-0-2-5">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-15-0-3" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-26-9-3" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37542-86-2-7">
+ <stop
+ id="stop37544-39-5-3"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546-7-2-9"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-0-4-4">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-15-3-2" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-26-2-9" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37542-86-0-6-8">
+ <stop
+ id="stop37544-39-8-7-4"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546-7-1-5-6"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-0-2-3-8">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-15-0-0-4" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-26-9-5-3" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10069-5-1-4-8">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop10071-9-18-9-9" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop10073-8-252-1-7" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient36273-9-4-2-3">
+ <stop
+ id="stop36275-9-0-3-3"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop36277-1-3-5-2"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient36273-9-4-22-0">
+ <stop
+ id="stop36275-9-0-6-7"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop36277-1-3-6-9"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10069-5-1-8">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop10071-9-18-3" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop10073-8-252-2" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient36273-9-4-8">
+ <stop
+ id="stop36275-9-0-0"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop36277-1-3-8"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10069-5-12">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop10071-9-7" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop10073-8-4" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient36273-9-9">
+ <stop
+ id="stop36275-9-8"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop36277-1-35"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient15859-1-3">
+ <stop
+ style="stop-color:#ff992b;stop-opacity:1"
+ offset="0"
+ id="stop15861-1-4" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop15863-7-73" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-95">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-242" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-44" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37542-1">
+ <stop
+ id="stop37544-62"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546-4"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-75">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-8" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-39" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1610-36-6-5">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop1611-1-9-6" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop1612-5-9-8" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37542-96">
+ <stop
+ id="stop37544-7-1"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546-0"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10069-37">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop10071-0" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop10073-2" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient81143-4">
+ <stop
+ style="stop-color:#2561b7;stop-opacity:1"
+ offset="0"
+ id="stop81145-0" />
+ <stop
+ style="stop-color:#f9fbff;stop-opacity:1"
+ offset="1"
+ id="stop81147-7" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37542-7-8-6-0">
+ <stop
+ id="stop37544-40-1-3-9"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop37546-94-7-0-7"
+ offset="1"
+ style="stop-color:#030303;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-488-8-2">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-13-8-8" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-67-2-2" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37542-7-8-6-0-8">
+ <stop
+ id="stop37544-40-1-3-9-3"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop37546-94-7-0-7-1"
+ offset="1"
+ style="stop-color:#030303;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient106427-3">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop106429-1" />
+ <stop
+ style="stop-color:#030303;stop-opacity:1"
+ offset="1"
+ id="stop106431-0" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-488-8-2-0">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-13-8-8-7" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-67-2-2-9" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1610-36-6-7-9">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop1611-1-9-4-5" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop1612-5-9-87-3" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1610-36-6-7-9-4">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop1611-1-9-4-5-0" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop1612-5-9-87-3-7" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient15097-0-8">
+ <stop
+ style="stop-color:#c4c4c4;stop-opacity:1"
+ offset="0"
+ id="stop15099-1-83" />
+ <stop
+ style="stop-color:#868686;stop-opacity:1"
+ offset="1"
+ id="stop15101-9-3" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient23974-5-2-6-6">
+ <stop
+ id="stop23976-9-2-7-6"
+ offset="0"
+ style="stop-color:#2561b7;stop-opacity:1;" />
+ <stop
+ id="stop23978-3-1-6-0"
+ offset="1"
+ style="stop-color:#f9fbff;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient31320-5-2-6-7">
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="0"
+ id="stop31322-5-4-5-8" />
+ <stop
+ style="stop-color:white;stop-opacity:0;"
+ offset="1"
+ id="stop31324-0-8-5-8" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient14262-9-5-9-4">
+ <stop
+ id="stop14264-5-2-9-0"
+ offset="0"
+ style="stop-color:#2661b6;stop-opacity:1;" />
+ <stop
+ id="stop14266-0-4-4-2"
+ offset="1"
+ style="stop-color:#c1d7f8;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-92-8-5-0">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-40-7-9-3" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-93-7-0-5" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1610-36-6-7-9-4-3">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop1611-1-9-4-5-0-6" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop1612-5-9-87-3-7-8" />
+ </linearGradient>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43050-6">
+ <rect
+ y="-122"
+ x="-24"
+ height="14"
+ width="16"
+ id="rect43052-3"
+ style="opacity:0.5;fill:url(#linearGradient43054-6);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ </mask>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient44627-7"
+ id="linearGradient43054-6"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.3333333,0,0,1.2727273,2.6666667,29.454545)"
+ x1="-4.2231579"
+ y1="-92.440941"
+ x2="-18.697306"
+ y2="-115.04018" />
+ <linearGradient
+ id="linearGradient44627-7">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop44629-4" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop44631-0" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10069-9-5-1-8-2-5">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop10071-5-43-3-0-0-4" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop10073-43-1-8-2-5-2" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10069-9-7-4-74-1">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop10071-5-4-5-0-5" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop10073-43-0-5-9-2" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient44939-8-5">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop44941-8-1" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop44943-2-7" />
+ </linearGradient>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask48816-8">
+ <rect
+ y="-84"
+ x="-44"
+ height="14"
+ width="13"
+ id="rect48818-4"
+ style="opacity:0.85;fill:url(#radialGradient48820-9);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient44627-7"
+ id="radialGradient48820-9"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,1.0769231,0,5.9230769)"
+ cx="-31"
+ cy="-83.5"
+ fx="-31"
+ fy="-83.5"
+ r="6.5" />
+ <linearGradient
+ id="linearGradient10069-9-7-4-4">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop10071-5-4-5-8" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop10073-43-0-5-6" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient44939-09">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop44941-0" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop44943-0" />
+ </linearGradient>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask28585-8">
+ <rect
+ style="opacity:0.85;fill:url(#radialGradient28589-9);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new"
+ id="rect28587-2"
+ width="13"
+ height="14"
+ x="-44"
+ y="-84" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient44627-7"
+ id="radialGradient28589-9"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,1.0769231,0,5.9230769)"
+ cx="-30.28125"
+ cy="-84.341515"
+ fx="-30.28125"
+ fy="-84.341515"
+ r="6.5" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43040-7">
+ <rect
+ style="opacity:0.5;fill:url(#linearGradient43044-5);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect43042-9"
+ width="15"
+ height="16"
+ x="-45.04018"
+ y="-24"
+ rx="0"
+ ry="0" />
+ </mask>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient43760-6-4"
+ id="linearGradient43044-5"
+ gradientUnits="userSpaceOnUse"
+ x1="-44.709698"
+ y1="-8.4836445"
+ x2="-37.784756"
+ y2="-18.517523"
+ gradientTransform="translate(-0.04018164,0)" />
+ <linearGradient
+ id="linearGradient43760-6-4">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop43762-7-3" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop43764-8-1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient9030-71-3">
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="0"
+ id="stop9032-15-3" />
+ <stop
+ style="stop-color:white;stop-opacity:0;"
+ offset="1"
+ id="stop9034-276-4" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10069-9-5-1-1">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop10071-5-43-3-3" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop10073-43-1-8-8" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient44939-2-8">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop44941-7-4" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop44943-7-0" />
+ </linearGradient>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask45865-7">
+ <g
+ id="g45867-3"
+ transform="translate(-14,0)">
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cssssssc"
+ id="path45869-7"
+ d="m -25.801826,-135.3217 c -0.907684,-0.32824 -0.906457,-1.55361 -0.440107,-2.23642 0.834186,-1.22138 2.593738,-1.15244 3.63669,-0.26277 1.530569,1.30563 1.388406,3.6923 0.08107,5.09763 -1.742467,1.8731 -4.73519,1.65156 -6.47424,-0.0993 -2.188413,-2.20322 -1.889457,-5.85971 0.277965,-7.95885 2.625036,-2.54234 6.931515,-2.199 9.311783,0.46129 2.764074,3.08924 2.372937,7.82808 -0.06591,10.77438"
+ style="fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline;enable-background:new"
+ mask="none" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc"
+ id="path45871-2"
+ d="m -19.40866,-140.32008 c 2.764074,3.08924 2.372937,7.82808 -0.06591,10.77438"
+ style="fill:none;stroke:url(#linearGradient45875-0);stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ mask="none"
+ style="fill:none;stroke:url(#radialGradient45877-1);stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline;enable-background:new"
+ d="m -25.801826,-135.3217 c -0.907684,-0.32824 -0.906457,-1.55361 -0.440107,-2.23642 0.834186,-1.22138 2.593738,-1.15244 3.63669,-0.26277"
+ id="path45873-6"
+ sodipodi:nodetypes="css" />
+ </g>
+ </mask>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient43760-7"
+ id="linearGradient45875-0"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(14,0)"
+ x1="-34.051685"
+ y1="-129.32457"
+ x2="-32.542458"
+ y2="-139.90228" />
+ <linearGradient
+ id="linearGradient43760-7">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop43762-79" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop43764-3" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient43760-7"
+ id="radialGradient45877-1"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.1099414,-0.9422316,0.4519816,0.05273803,38.220416,-152.21215)"
+ cx="-25.452209"
+ cy="-136.46503"
+ fx="-25.452209"
+ fy="-136.46503"
+ r="8.0066185" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask45447-7">
+ <rect
+ ry="0"
+ style="opacity:0.8;fill:url(#radialGradient45451-2);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect45449-4"
+ width="15"
+ height="15"
+ x="216"
+ y="366" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient43760-7"
+ id="radialGradient45451-2"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.9952162,167.99999,-60.91415)"
+ cx="59.000011"
+ cy="440.0191"
+ fx="59.000011"
+ fy="440.0191"
+ r="6.5080619" />
+ <linearGradient
+ id="linearGradient319-42-9">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-32-8" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-21-6" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10069-9-7-0">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop10071-5-4-2" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop10073-43-0-8" />
+ </linearGradient>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath43135-6">
+ <path
+ inkscape:connector-curvature="0"
+ id="path43137-1"
+ d="m -46,52 16,-16 -16,0 0,16 z"
+ style="opacity:0.5;fill:#ffff00;fill-rule:evenodd;stroke:none" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43188-4">
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.5;fill:url(#linearGradient43192-3);fill-rule:evenodd;stroke:none"
+ d="m -46,52 16,-16 -16,0 0,16 z"
+ id="path43190-2" />
+ </mask>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient1610-5-2"
+ id="linearGradient43192-3"
+ gradientUnits="userSpaceOnUse"
+ x1="-47"
+ y1="44"
+ x2="-43"
+ y2="44" />
+ <linearGradient
+ id="linearGradient1610-5-2">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop1611-17-2" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop1612-115-1" />
+ </linearGradient>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath43178-6">
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.5;fill:#ffff00;fill-rule:evenodd;stroke:none"
+ d="m -30,36 -1,0 -15,15 0,1 16,0 0,-16 z"
+ id="path43180-8"
+ sodipodi:nodetypes="cccccc" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43182-5">
+ <path
+ inkscape:connector-curvature="0"
+ id="path43184-7"
+ d="m -46,52 0,-1 15,-15 1,0 0,16 -16,0 z"
+ style="opacity:0.5;fill:url(#linearGradient43186-6);fill-rule:evenodd;stroke:none"
+ sodipodi:nodetypes="cccccc" />
+ </mask>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient1610-5-2"
+ id="linearGradient43186-6"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0,-1,-1,0,6,6)"
+ x1="-47"
+ y1="44"
+ x2="-43"
+ y2="44" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask25021-4">
+ <rect
+ style="fill:url(#radialGradient25025-8);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.70000005;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect25023-8"
+ width="13"
+ height="14"
+ x="26"
+ y="243" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient44627-7"
+ id="radialGradient25025-8"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.8918342,0,0,0.8918344,-15.699877,27.900732)"
+ cx="49"
+ cy="254.64285"
+ fx="49"
+ fy="254.64285"
+ r="6.5" />
+ <linearGradient
+ id="linearGradient10069-9-7-5-5">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop10071-5-4-58-7" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop10073-43-0-4-5" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-76-2-0">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-142-0" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-32-0" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient29761">
+ <stop
+ style="stop-color:#b74125;stop-opacity:1;"
+ offset="0"
+ id="stop29763" />
+ <stop
+ style="stop-color:#f9fbff;stop-opacity:1"
+ offset="1"
+ id="stop29765" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient8864-1">
+ <stop
+ id="stop8866-0"
+ offset="0"
+ style="stop-color:#b43214;stop-opacity:1;" />
+ <stop
+ id="stop8868-1"
+ offset="1"
+ style="stop-color:#e86830;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1610-8-8">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop1611-7-7" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop1612-4-6" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-77-0">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-9-0" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-31-9" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1610-4">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop1611-64" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop1612-20" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1610-4-3">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop1611-64-0" />
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="1"
+ id="stop1612-20-3" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient16719">
+ <stop
+ id="stop16721"
+ offset="0"
+ style="stop-color:#84d458;stop-opacity:1" />
+ <stop
+ style="stop-color:#5894d4;stop-opacity:1"
+ offset="0.30000001"
+ id="stop5079" />
+ <stop
+ id="stop16723"
+ offset="1"
+ style="stop-color:#afd1f5;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient11820">
+ <stop
+ style="stop-color:#afd1f5;stop-opacity:1"
+ offset="0"
+ id="stop11822" />
+ <stop
+ id="stop11824"
+ offset="0.44444144"
+ style="stop-color:#5894d4;stop-opacity:1" />
+ <stop
+ style="stop-color:#5894d4;stop-opacity:1"
+ offset="0.55555254"
+ id="stop11826" />
+ <stop
+ style="stop-color:#ef79ef;stop-opacity:1"
+ offset="1"
+ id="stop11828" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient28147-1-4">
+ <stop
+ id="stop28149-4-1"
+ offset="0"
+ style="stop-color:#afd1f5;stop-opacity:1" />
+ <stop
+ style="stop-color:#5894d4;stop-opacity:1"
+ offset="0.18750006"
+ id="stop5469" />
+ <stop
+ style="stop-color:#505050;stop-opacity:1"
+ offset="0.40000001"
+ id="stop28151-7-6" />
+ <stop
+ id="stop28153-8-4"
+ offset="0.60000002"
+ style="stop-color:#505050;stop-opacity:1" />
+ <stop
+ style="stop-color:#5894d4;stop-opacity:1"
+ offset="0.81250006"
+ id="stop5471" />
+ <stop
+ id="stop28155-2-6"
+ offset="1"
+ style="stop-color:#afd1f5;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-65-4-8-7">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-14-9-5-9" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-49-3-6-8" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient44939-8-53">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop44941-8-7" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop44943-2-5" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient44939-8-53-7">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop44941-8-7-6" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop44943-2-5-2" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-0">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-22" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-19" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37542-29">
+ <stop
+ id="stop37544-67"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546-45"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-36">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-18" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-390" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37542-29-1">
+ <stop
+ id="stop37544-67-8"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546-45-9"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37542-29-7">
+ <stop
+ id="stop37544-67-3"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546-45-0"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-36-40">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-18-7" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-390-4" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37542-29-7-8">
+ <stop
+ id="stop37544-67-3-0"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546-45-0-9"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-36-40-2">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-18-7-8" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-390-4-6" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-36-40-2-4">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-18-7-8-5" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-390-4-6-6" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient23974-39">
+ <stop
+ id="stop23976-8"
+ offset="0"
+ style="stop-color:#2561b7;stop-opacity:1;" />
+ <stop
+ id="stop23978-23"
+ offset="1"
+ style="stop-color:#f9fbff;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient31320-9">
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="0"
+ id="stop31322-6" />
+ <stop
+ style="stop-color:white;stop-opacity:0;"
+ offset="1"
+ id="stop31324-2" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient14262-6">
+ <stop
+ id="stop14264-29"
+ offset="0"
+ style="stop-color:#2661b6;stop-opacity:1;" />
+ <stop
+ id="stop14266-9"
+ offset="1"
+ style="stop-color:#c1d7f8;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-61">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-47" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-45" />
+ </linearGradient>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath15455">
+ <rect
+ style="color:#000000;fill:#d8d8d8;fill-opacity:1;stroke:none;stroke-width:1.20000005;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new"
+ id="rect15457"
+ width="16"
+ height="16"
+ x="301.96045"
+ y="236.91833" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask15700">
+ <path
+ style="color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.20000005;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter15613);enable-background:new"
+ d="m 302.9292,245.91834 -2.4375,-1.125 -0.53125,-9.84375 19.95312,-0.0469 0.0156,9.95313 -2.9375,1.09375 0,5.96875 -14,0 z"
+ id="path15702"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ </mask>
+ <filter
+ color-interpolation-filters="sRGB"
+ inkscape:collect="always"
+ id="filter15613"
+ x="-0.092011765"
+ width="1.1840235"
+ y="-0.097762503"
+ height="1.1955251">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.65175"
+ id="feGaussianBlur15615" />
</filter>
- <linearGradient id="linearGradient37542-55">
- <stop id="stop37544-61" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546-03" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient319-74">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-42"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-67"/>
- </linearGradient>
- <linearGradient id="linearGradient21609-6">
- <stop id="stop21611-3" offset="0" style="stop-color:black;stop-opacity:1"/>
- <stop id="stop21613-0" offset="1" style="stop-color:white;stop-opacity:1;"/>
- </linearGradient>
-
-
- <filter color-interpolation-filters="sRGB" inkscape:collect="always" id="filter15613-8" x="-0.092011765" width="1.1840235" y="-0.097762503" height="1.1955251">
- <feGaussianBlur inkscape:collect="always" stdDeviation="0.65175" id="feGaussianBlur15615-1"/>
+ <linearGradient
+ id="linearGradient37542-55">
+ <stop
+ id="stop37544-61"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546-03"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-74">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-42" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-67" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient21609-6">
+ <stop
+ id="stop21611-3"
+ offset="0"
+ style="stop-color:black;stop-opacity:1" />
+ <stop
+ id="stop21613-0"
+ offset="1"
+ style="stop-color:white;stop-opacity:1;" />
+ </linearGradient>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath15455-9">
+ <rect
+ style="color:#000000;fill:#d8d8d8;fill-opacity:1;stroke:none;stroke-width:1.20000005;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new"
+ id="rect15457-6"
+ width="16"
+ height="16"
+ x="301.96045"
+ y="236.91833" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask15700-4">
+ <path
+ style="color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.20000005000000010;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter15613-8);enable-background:new"
+ d="m 302.9292,245.91834 -2.4375,-1.125 -0.53125,-9.84375 19.95312,-0.0469 0.0156,9.95313 -2.9375,1.09375 0,5.96875 -14,0 z"
+ id="path15702-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ </mask>
+ <filter
+ color-interpolation-filters="sRGB"
+ inkscape:collect="always"
+ id="filter15613-8"
+ x="-0.092011765"
+ width="1.1840235"
+ y="-0.097762503"
+ height="1.1955251">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.65175"
+ id="feGaussianBlur15615-1" />
</filter>
- <filter color-interpolation-filters="sRGB" inkscape:label="Greyscale" id="filter15388">
-
-
-
+ <filter
+ color-interpolation-filters="sRGB"
+ inkscape:label="Greyscale"
+ id="filter15388">
+ <feColorMatrix
+ values="0.21 0.72 0.072 0 0 0.21 0.72 0.072 0 0 0.21 0.72 0.072 0 0 0 0 0 1 0 "
+ id="feColorMatrix15390"
+ result="fbSourceGraphic" />
+ <feColorMatrix
+ result="fbSourceGraphicAlpha"
+ in="fbSourceGraphic"
+ values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
+ id="feColorMatrix15392" />
+ <feColorMatrix
+ id="feColorMatrix15394"
+ values="0.21 0.72 0.072 0 0 0.21 0.72 0.072 0 0 0.21 0.72 0.072 0 0 0 0 0 1 0 "
+ in="fbSourceGraphic" />
</filter>
- <linearGradient id="linearGradient37542-91">
- <stop id="stop37544-81" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop37546-75" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient319-223">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-84"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-34"/>
- </linearGradient>
- <linearGradient id="linearGradient21609-3">
- <stop id="stop21611-9" offset="0" style="stop-color:black;stop-opacity:1"/>
- <stop id="stop21613-8" offset="1" style="stop-color:white;stop-opacity:1;"/>
- </linearGradient>
- <filter inkscape:label="Opacity" style="color-interpolation-filters:sRGB" id="filter17385">
-
-
+ <linearGradient
+ id="linearGradient37542-91">
+ <stop
+ id="stop37544-81"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop37546-75"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient319-223">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-84" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-34" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient21609-3">
+ <stop
+ id="stop21611-9"
+ offset="0"
+ style="stop-color:black;stop-opacity:1" />
+ <stop
+ id="stop21613-8"
+ offset="1"
+ style="stop-color:white;stop-opacity:1;" />
+ </linearGradient>
+ <filter
+ inkscape:label="Opacity"
+ style="color-interpolation-filters:sRGB"
+ id="filter17385">
+ <feColorMatrix
+ values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 5 -1 "
+ result="colormatrix"
+ id="feColorMatrix17387" />
+ <feComposite
+ k4="0"
+ k3="0"
+ k1="0"
+ in2="colormatrix"
+ operator="arithmetic"
+ k2="0.24"
+ result="composite"
+ id="feComposite17389" />
</filter>
- <linearGradient id="linearGradient1610-2">
- <stop id="stop1611-8-9" offset="0" style="stop-color:black;stop-opacity:1;"/>
- <stop style="stop-color:#000000;stop-opacity:1;" offset="0.5" id="stop6596"/>
- <stop id="stop1612-0-6" offset="1" style="stop-color:#c8c8c8;stop-opacity:1;"/>
- </linearGradient>
-
- <linearGradient id="linearGradient18821-1-16">
- <stop id="stop20589" offset="0" style="stop-color:#e3604f;stop-opacity:1;"/>
- <stop id="stop20591" offset="1" style="stop-color:#e3604f;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient39155-0-813">
- <stop style="stop-color:#e6e6e6;stop-opacity:1;" offset="0" id="stop20595"/>
- <stop style="stop-color:#c4c4c4;stop-opacity:1;" offset="1" id="stop20597"/>
- </linearGradient>
-
- <filter style="color-interpolation-filters:sRGB" inkscape:label="Drop Shadow" id="filter6146" x="-0.30000001" width="1.35" y="-0.15000001" height="1.4">
-
-
- <feGaussianBlur in="composite1" stdDeviation="1.5" result="blur" id="feGaussianBlur6152"/>
-
-
+ <linearGradient
+ id="linearGradient1610-2">
+ <stop
+ id="stop1611-8-9"
+ offset="0"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0.5"
+ id="stop6596" />
+ <stop
+ id="stop1612-0-6"
+ offset="1"
+ style="stop-color:#c8c8c8;stop-opacity:1;" />
+ </linearGradient>
+ <clipPath
+ id="clipPath13106-5"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path34850-6-6"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <linearGradient
+ id="linearGradient18821-1-16">
+ <stop
+ id="stop20589"
+ offset="0"
+ style="stop-color:#e3604f;stop-opacity:1;" />
+ <stop
+ id="stop20591"
+ offset="1"
+ style="stop-color:#e3604f;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient39155-0-813">
+ <stop
+ style="stop-color:#e6e6e6;stop-opacity:1;"
+ offset="0"
+ id="stop20595" />
+ <stop
+ style="stop-color:#c4c4c4;stop-opacity:1;"
+ offset="1"
+ id="stop20597" />
+ </linearGradient>
+ <clipPath
+ id="clipPath13106-9-2-9-9-4"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path34850-4-7-0-4-0"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none"
+ inkscape:connector-curvature="0" />
+ </clipPath>
+ <filter
+ style="color-interpolation-filters:sRGB"
+ inkscape:label="Drop Shadow"
+ id="filter6146"
+ x="-0.30000001"
+ width="1.35"
+ y="-0.15000001"
+ height="1.4">
+ <feFlood
+ flood-opacity="0.40000000000000002"
+ flood-color="rgb(0,0,0)"
+ result="flood"
+ id="feFlood6148" />
+ <feComposite
+ in="flood"
+ in2="SourceGraphic"
+ operator="in"
+ result="composite1"
+ id="feComposite6150" />
+ <feGaussianBlur
+ in="composite1"
+ stdDeviation="1.5"
+ result="blur"
+ id="feGaussianBlur6152" />
+ <feOffset
+ dx="-2"
+ dy="2"
+ result="offset"
+ id="feOffset6154" />
+ <feComposite
+ in="SourceGraphic"
+ in2="offset"
+ operator="over"
+ result="composite2"
+ id="feComposite6156" />
</filter>
- <filter style="color-interpolation-filters:sRGB" inkscape:label="Drop Shadow" id="filter6078" x="-0.30000001" width="1.35" height="1.4" y="-0.15000001">
-
-
- <feGaussianBlur in="composite1" stdDeviation="1.5" result="blur" id="feGaussianBlur6084"/>
-
-
+ <filter
+ style="color-interpolation-filters:sRGB"
+ inkscape:label="Drop Shadow"
+ id="filter6078"
+ x="-0.30000001"
+ width="1.35"
+ height="1.4"
+ y="-0.15000001">
+ <feFlood
+ flood-opacity="0.40000000000000002"
+ flood-color="rgb(0,0,0)"
+ result="flood"
+ id="feFlood6080" />
+ <feComposite
+ in="flood"
+ in2="SourceGraphic"
+ operator="in"
+ result="composite1"
+ id="feComposite6082" />
+ <feGaussianBlur
+ in="composite1"
+ stdDeviation="1.5"
+ result="blur"
+ id="feGaussianBlur6084" />
+ <feOffset
+ dx="-2"
+ dy="2"
+ result="offset"
+ id="feOffset6086" />
+ <feComposite
+ in="SourceGraphic"
+ in2="offset"
+ operator="over"
+ result="composite2"
+ id="feComposite6088" />
</filter>
-
-
-
- <radialGradient gradientUnits="userSpaceOnUse" fy="114.5684" fx="20.892099" r="5.256" cy="114.5684" cx="20.892099" id="aigrd2-3">
- <stop id="stop15566-9" style="stop-color:#F0F0F0" offset="0"/>
- <stop id="stop15568-7" style="stop-color:#9a9a9a;stop-opacity:1.0000000;" offset="1.0000000"/>
+ <clipPath
+ id="clipPath13106-7"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path34850-1"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <clipPath
+ id="clipPath23877-4"
+ clipPathUnits="userSpaceOnUse">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate"
+ id="rect23879-6"
+ width="15"
+ height="6"
+ x="952"
+ y="-540"
+ transform="scale(1,-1)" />
+ </clipPath>
+ <clipPath
+ id="clipPath20586-3"
+ clipPathUnits="userSpaceOnUse">
+ <ellipse
+ ry="2.25"
+ rx="4.5"
+ cy="554"
+ cx="53"
+ transform="matrix(1.870472,0.1894819,-0.6587894,2.4281336,319.59052,-798.11661)"
+ id="path34889-5"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate" />
+ </clipPath>
+ <radialGradient
+ gradientUnits="userSpaceOnUse"
+ fy="114.5684"
+ fx="20.892099"
+ r="5.256"
+ cy="114.5684"
+ cx="20.892099"
+ id="aigrd2-3">
+ <stop
+ id="stop15566-9"
+ style="stop-color:#F0F0F0"
+ offset="0" />
+ <stop
+ id="stop15568-7"
+ style="stop-color:#9a9a9a;stop-opacity:1.0000000;"
+ offset="1.0000000" />
</radialGradient>
- <linearGradient id="linearGradient319-367">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop320-53"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop321-562"/>
- </linearGradient>
-
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient18134" id="linearGradient12353" gradientUnits="userSpaceOnUse" gradientTransform="translate(21,-39)" x1="19" y1="550" x2="-1.8890873" y2="529.28772"/>
-
- <linearGradient id="linearGradient319-95-2-7-1-2">
- <stop style="stop-color:#ffffff;stop-opacity:0.75675678;" offset="0" id="stop320-43-7-3-3-3"/>
- <stop style="stop-color:#915515;stop-opacity:0;" offset="1" id="stop321-12-7-4-1-9"/>
- </linearGradient>
- <linearGradient id="linearGradient10069-8-3-3-0-3">
- <stop style="stop-color:#764511;stop-opacity:1;" offset="0" id="stop10071-9-8-7-1-8"/>
- <stop style="stop-color:#915515;stop-opacity:0;" offset="1" id="stop10073-2-7-1-0-5"/>
- </linearGradient>
- <linearGradient id="linearGradient13998-7-0">
- <stop id="stop14000-1-1" offset="0" style="stop-color:#f57d07;stop-opacity:1;"/>
- <stop id="stop14002-0-0" offset="1" style="stop-color:white;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient11146" id="linearGradient11162" gradientUnits="userSpaceOnUse" x1="16.5" y1="686.50714" x2="6" y2="697"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient11146" id="linearGradient11184" gradientUnits="userSpaceOnUse" x1="16.5" y1="686.50714" x2="6" y2="697" gradientTransform="translate(231,-399.00712)"/>
-
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient11146" id="linearGradient11190" gradientUnits="userSpaceOnUse" gradientTransform="translate(21)" x1="16.5" y1="686.50714" x2="6" y2="697"/>
-
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient11146" id="linearGradient11196" gradientUnits="userSpaceOnUse" gradientTransform="translate(42)" x1="16.5" y1="686.50714" x2="6" y2="697"/>
-
-
-
-
-
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient21517-3" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.891843,0,0,0.909224,-173.10957,172.3592)" cx="350.5" cy="14.5" fx="350.5" fy="14.5" r="6.9000001"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient11146" id="linearGradient31019" gradientUnits="userSpaceOnUse" gradientTransform="rotate(-45,271.82331,-251.06972)" x1="85.548706" y1="100.22395" x2="85.347076" y2="113.09817"/>
- <linearGradient id="linearGradient30958">
- <stop id="stop30960" offset="0" style="stop-color:#fff9cf;stop-opacity:1;"/>
- <stop id="stop30962" offset="1" style="stop-color:#c7bc52;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient18495" id="linearGradient14207" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0,-0.9569715,-1,0,322,353.18743)" x1="347.6467" y1="216.75188" x2="345.98633" y2="243.92201"/>
- <linearGradient gradientTransform="matrix(-1,0,0,1,194,-21)" inkscape:collect="always" xlink:href="#linearGradient35411" id="linearGradient35446-0" gradientUnits="userSpaceOnUse" x1="31" y1="60.000004" x2="34" y2="54.000004"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient11146" id="linearGradient14238" gradientUnits="userSpaceOnUse" x1="132" y1="120.4313" x2="93.029579" y2="78.9655"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient319" id="linearGradient14413" gradientUnits="userSpaceOnUse" x1="132" y1="120.4313" x2="93.029579" y2="78.9655" gradientTransform="translate(-5e-8,-7.9962027e-6)"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient319" id="linearGradient14478" gradientUnits="userSpaceOnUse" gradientTransform="translate(0,-8e-6)" x1="132" y1="120.4313" x2="93.029579" y2="78.9655"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient319" id="linearGradient13559" gradientUnits="userSpaceOnUse" gradientTransform="translate(-1.0000001e-7,-8.5e-6)" x1="132" y1="120.4313" x2="93.029579" y2="78.9655"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient319" id="linearGradient14293" gradientUnits="userSpaceOnUse" x1="132" y1="120.4313" x2="93.029579" y2="78.9655"/>
- <radialGradient id="radialGradient16824-1" cx="20.892099" cy="64.567902" r="5.257" fx="20.892099" fy="64.567902" gradientUnits="userSpaceOnUse">
- <stop offset="0" style="stop-color:#b7b7b7;stop-opacity:1;" id="stop16826-5"/>
- <stop id="stop16828-2" style="stop-color:#646464;stop-opacity:1;" offset="0.50338405"/>
- <stop offset="1" style="stop-color:#b7b7b7;stop-opacity:1;" id="stop16830-7"/>
+ <linearGradient
+ id="linearGradient319-367">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop320-53" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop321-562" />
+ </linearGradient>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43822-1">
+ <rect
+ y="208"
+ x="754"
+ height="9"
+ width="12"
+ id="rect43824-2"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.93999993;fill:url(#linearGradient43826);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:new" />
+ </mask>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient18134"
+ id="linearGradient12353"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(21,-39)"
+ x1="19"
+ y1="550"
+ x2="-1.8890873"
+ y2="529.28772" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask12349-3">
+ <rect
+ y="498"
+ x="27"
+ height="14"
+ width="14.25"
+ id="rect12351-8"
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient12353);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </mask>
+ <linearGradient
+ id="linearGradient319-95-2-7-1-2">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.75675678;"
+ offset="0"
+ id="stop320-43-7-3-3-3" />
+ <stop
+ style="stop-color:#915515;stop-opacity:0;"
+ offset="1"
+ id="stop321-12-7-4-1-9" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10069-8-3-3-0-3">
+ <stop
+ style="stop-color:#764511;stop-opacity:1;"
+ offset="0"
+ id="stop10071-9-8-7-1-8" />
+ <stop
+ style="stop-color:#915515;stop-opacity:0;"
+ offset="1"
+ id="stop10073-2-7-1-0-5" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient13998-7-0">
+ <stop
+ id="stop14000-1-1"
+ offset="0"
+ style="stop-color:#f57d07;stop-opacity:1;" />
+ <stop
+ id="stop14002-0-0"
+ offset="1"
+ style="stop-color:white;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11146"
+ id="linearGradient11162"
+ gradientUnits="userSpaceOnUse"
+ x1="16.5"
+ y1="686.50714"
+ x2="6"
+ y2="697" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11146"
+ id="linearGradient11184"
+ gradientUnits="userSpaceOnUse"
+ x1="16.5"
+ y1="686.50714"
+ x2="6"
+ y2="697"
+ gradientTransform="translate(231,-399.00712)" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask11180">
+ <rect
+ style="opacity:1;vector-effect:none;fill:url(#linearGradient11184);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ id="rect11182"
+ width="16"
+ height="16"
+ x="236"
+ y="282.99289" />
+ </mask>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11146"
+ id="linearGradient11190"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(21)"
+ x1="16.5"
+ y1="686.50714"
+ x2="6"
+ y2="697" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask11186">
+ <rect
+ y="682"
+ x="26"
+ height="16"
+ width="16"
+ id="rect11188"
+ style="opacity:1;vector-effect:none;fill:url(#linearGradient11190);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" />
+ </mask>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11146"
+ id="linearGradient11196"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(42)"
+ x1="16.5"
+ y1="686.50714"
+ x2="6"
+ y2="697" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask11192">
+ <rect
+ style="opacity:1;vector-effect:none;fill:url(#linearGradient11196);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ id="rect11194"
+ width="16"
+ height="16"
+ x="47"
+ y="682" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask11186-8">
+ <rect
+ y="682"
+ x="26"
+ height="16"
+ width="16"
+ id="rect11188-6"
+ style="opacity:1;vector-effect:none;fill:url(#linearGradient11190);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask11192-0">
+ <rect
+ style="opacity:1;vector-effect:none;fill:url(#linearGradient11196);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ id="rect11194-8"
+ width="16"
+ height="16"
+ x="47"
+ y="682" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask11180-3">
+ <rect
+ style="opacity:1;vector-effect:none;fill:url(#linearGradient11184);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ id="rect11182-3"
+ width="16"
+ height="16"
+ x="236"
+ y="282.99289" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask12349-3-2">
+ <rect
+ y="498"
+ x="27"
+ height="14"
+ width="14.25"
+ id="rect12351-8-5"
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient12353);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </mask>
+ <pattern
+ y="0"
+ x="0"
+ height="6"
+ width="6"
+ patternUnits="userSpaceOnUse"
+ id="EMFhbasepattern" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient21517-3"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.891843,0,0,0.909224,-173.10957,172.3592)"
+ cx="350.5"
+ cy="14.5"
+ fx="350.5"
+ fy="14.5"
+ r="6.9000001" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11146"
+ id="linearGradient31019"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="rotate(-45,271.82331,-251.06972)"
+ x1="85.548706"
+ y1="100.22395"
+ x2="85.347076"
+ y2="113.09817" />
+ <linearGradient
+ id="linearGradient30958">
+ <stop
+ id="stop30960"
+ offset="0"
+ style="stop-color:#fff9cf;stop-opacity:1;" />
+ <stop
+ id="stop30962"
+ offset="1"
+ style="stop-color:#c7bc52;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient18495"
+ id="linearGradient14207"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0,-0.9569715,-1,0,322,353.18743)"
+ x1="347.6467"
+ y1="216.75188"
+ x2="345.98633"
+ y2="243.92201" />
+ <linearGradient
+ gradientTransform="matrix(-1,0,0,1,194,-21)"
+ inkscape:collect="always"
+ xlink:href="#linearGradient35411"
+ id="linearGradient35446-0"
+ gradientUnits="userSpaceOnUse"
+ x1="31"
+ y1="60.000004"
+ x2="34"
+ y2="54.000004" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11146"
+ id="linearGradient14238"
+ gradientUnits="userSpaceOnUse"
+ x1="132"
+ y1="120.4313"
+ x2="93.029579"
+ y2="78.9655" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient319"
+ id="linearGradient14413"
+ gradientUnits="userSpaceOnUse"
+ x1="132"
+ y1="120.4313"
+ x2="93.029579"
+ y2="78.9655"
+ gradientTransform="translate(-5e-8,-7.9962027e-6)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient319"
+ id="linearGradient14478"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(0,-8e-6)"
+ x1="132"
+ y1="120.4313"
+ x2="93.029579"
+ y2="78.9655" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient319"
+ id="linearGradient13559"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-1.0000001e-7,-8.5e-6)"
+ x1="132"
+ y1="120.4313"
+ x2="93.029579"
+ y2="78.9655" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient319"
+ id="linearGradient14293"
+ gradientUnits="userSpaceOnUse"
+ x1="132"
+ y1="120.4313"
+ x2="93.029579"
+ y2="78.9655" />
+ <radialGradient
+ id="radialGradient16824-1"
+ cx="20.892099"
+ cy="64.567902"
+ r="5.257"
+ fx="20.892099"
+ fy="64.567902"
+ gradientUnits="userSpaceOnUse">
+ <stop
+ offset="0"
+ style="stop-color:#b7b7b7;stop-opacity:1;"
+ id="stop16826-5" />
+ <stop
+ id="stop16828-2"
+ style="stop-color:#646464;stop-opacity:1;"
+ offset="0.50338405" />
+ <stop
+ offset="1"
+ style="stop-color:#b7b7b7;stop-opacity:1;"
+ id="stop16830-7" />
</radialGradient>
- <linearGradient id="linearGradient16850-5">
- <stop style="stop-color:#e9e9e9;stop-opacity:0;" offset="0" id="stop16852-5"/>
- <stop id="stop16854-1" offset="0.38177863" style="stop-color:#e9e9e9;stop-opacity:1;"/>
- <stop style="stop-color:#e9e9e9;stop-opacity:0;" offset="1" id="stop16856-7"/>
- </linearGradient>
- <linearGradient id="linearGradient20756-2-8">
- <stop style="stop-color:#00327d;stop-opacity:1;" offset="0" id="stop20758-7-8"/>
- <stop style="stop-color:#65a1fb;stop-opacity:1;" offset="1" id="stop20760-7-2"/>
- </linearGradient>
- <linearGradient id="linearGradient43009-7">
- <stop style="stop-color:#e9e9e9;stop-opacity:1;" offset="0" id="stop43011-4"/>
- <stop id="stop16834-0" offset="0.30847755" style="stop-color:#e9e9e9;stop-opacity:0.49803922;"/>
- <stop style="stop-color:#e9e9e9;stop-opacity:0;" offset="1" id="stop43013-9"/>
- </linearGradient>
-
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="linearGradient13046" gradientUnits="userSpaceOnUse" gradientTransform="translate(360,-161.99999)" x1="-80" y1="151" x2="-80" y2="152.24998"/>
-
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="linearGradient13056" gradientUnits="userSpaceOnUse" gradientTransform="translate(360,-145.93749)" x1="-80" y1="151" x2="-80" y2="152.24998"/>
- <linearGradient id="linearGradient18344">
- <stop style="stop-color:#6c6c6c;stop-opacity:1;" offset="0" id="stop18346"/>
- <stop style="stop-color:#f0f0f0;stop-opacity:1;" offset="1" id="stop18348"/>
- </linearGradient>
-
-
-
-
-
- <filter style="color-interpolation-filters:sRGB" inkscape:label="Drop Shadow" id="filter6146-3" x="-0.30000001" width="1.35" y="-0.15000001" height="1.4">
-
-
- <feGaussianBlur in="composite1" stdDeviation="1.5" result="blur" id="feGaussianBlur6152-3"/>
-
-
+ <linearGradient
+ id="linearGradient16850-5">
+ <stop
+ style="stop-color:#e9e9e9;stop-opacity:0;"
+ offset="0"
+ id="stop16852-5" />
+ <stop
+ id="stop16854-1"
+ offset="0.38177863"
+ style="stop-color:#e9e9e9;stop-opacity:1;" />
+ <stop
+ style="stop-color:#e9e9e9;stop-opacity:0;"
+ offset="1"
+ id="stop16856-7" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient20756-2-8">
+ <stop
+ style="stop-color:#00327d;stop-opacity:1;"
+ offset="0"
+ id="stop20758-7-8" />
+ <stop
+ style="stop-color:#65a1fb;stop-opacity:1;"
+ offset="1"
+ id="stop20760-7-2" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient43009-7">
+ <stop
+ style="stop-color:#e9e9e9;stop-opacity:1;"
+ offset="0"
+ id="stop43011-4" />
+ <stop
+ id="stop16834-0"
+ offset="0.30847755"
+ style="stop-color:#e9e9e9;stop-opacity:0.49803922;" />
+ <stop
+ style="stop-color:#e9e9e9;stop-opacity:0;"
+ offset="1"
+ id="stop43013-9" />
+ </linearGradient>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask13041">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient13046);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate"
+ id="rect13043"
+ width="7"
+ height="8"
+ x="276"
+ y="-12" />
+ </mask>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="linearGradient13046"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(360,-161.99999)"
+ x1="-80"
+ y1="151"
+ x2="-80"
+ y2="152.24998" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask13052">
+ <rect
+ y="4.0625"
+ x="276"
+ height="8"
+ width="7"
+ id="rect13054"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient13056);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate"
+ transform="scale(1,-1)" />
+ </mask>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="linearGradient13056"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(360,-145.93749)"
+ x1="-80"
+ y1="151"
+ x2="-80"
+ y2="152.24998" />
+ <linearGradient
+ id="linearGradient18344">
+ <stop
+ style="stop-color:#6c6c6c;stop-opacity:1;"
+ offset="0"
+ id="stop18346" />
+ <stop
+ style="stop-color:#f0f0f0;stop-opacity:1;"
+ offset="1"
+ id="stop18348" />
+ </linearGradient>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath17188">
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#d3d7cf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate"
+ d="m 240.5,-19.90625 c -1.87005,0 -3.40625,1.536202 -3.40625,3.40625 v 2 c 0,1.87005 1.53621,3.40625 3.40625,3.40625 v -2.8125 c -0.33932,0 -0.59375,-0.254431 -0.59375,-0.59375 v -2 c 0,-0.339319 0.25443,-0.59375 0.59375,-0.59375 z"
+ id="path17190-4" />
+ </clipPath>
+ <clipPath
+ id="clipPath13106-5-7"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path34850-6-6-0"
+ d="m 125.5,433.5 h 23 v 41 h -33 v -31 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <clipPath
+ id="clipPath13484"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path13482"
+ d="m 125.5,433.5 h 23 v 41 h -33 v -31 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <clipPath
+ id="clipPath13106-9-2-9-9-4-8"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path34850-4-7-0-4-0-5"
+ d="m 125.5,433.5 h 23 v 41 h -33 v -31 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none"
+ inkscape:connector-curvature="0" />
+ </clipPath>
+ <clipPath
+ id="clipPath13526"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path13524"
+ d="m 125.5,433.5 h 23 v 41 h -33 v -31 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none"
+ inkscape:connector-curvature="0" />
+ </clipPath>
+ <filter
+ style="color-interpolation-filters:sRGB"
+ inkscape:label="Drop Shadow"
+ id="filter6146-3"
+ x="-0.30000001"
+ width="1.35"
+ y="-0.15000001"
+ height="1.4">
+ <feFlood
+ flood-opacity="0.40000000000000002"
+ flood-color="rgb(0,0,0)"
+ result="flood"
+ id="feFlood6148-3" />
+ <feComposite
+ in="flood"
+ in2="SourceGraphic"
+ operator="in"
+ result="composite1"
+ id="feComposite6150-7" />
+ <feGaussianBlur
+ in="composite1"
+ stdDeviation="1.5"
+ result="blur"
+ id="feGaussianBlur6152-3" />
+ <feOffset
+ dx="-2"
+ dy="2"
+ result="offset"
+ id="feOffset6154-2" />
+ <feComposite
+ in="SourceGraphic"
+ in2="offset"
+ operator="over"
+ result="composite2"
+ id="feComposite6156-7" />
</filter>
- <filter style="color-interpolation-filters:sRGB" inkscape:label="Drop Shadow" id="filter6078-7" x="-0.30000001" width="1.35" height="1.4" y="-0.15000001">
-
-
- <feGaussianBlur in="composite1" stdDeviation="1.5" result="blur" id="feGaussianBlur6084-6"/>
-
-
+ <filter
+ style="color-interpolation-filters:sRGB"
+ inkscape:label="Drop Shadow"
+ id="filter6078-7"
+ x="-0.30000001"
+ width="1.35"
+ height="1.4"
+ y="-0.15000001">
+ <feFlood
+ flood-opacity="0.40000000000000002"
+ flood-color="rgb(0,0,0)"
+ result="flood"
+ id="feFlood6080-2" />
+ <feComposite
+ in="flood"
+ in2="SourceGraphic"
+ operator="in"
+ result="composite1"
+ id="feComposite6082-8" />
+ <feGaussianBlur
+ in="composite1"
+ stdDeviation="1.5"
+ result="blur"
+ id="feGaussianBlur6084-6" />
+ <feOffset
+ dx="-2"
+ dy="2"
+ result="offset"
+ id="feOffset6086-4" />
+ <feComposite
+ in="SourceGraphic"
+ in2="offset"
+ operator="over"
+ result="composite2"
+ id="feComposite6088-9" />
</filter>
-
-
-
-
-
-
-
-
-
-
-
-
-
- <radialGradient gradientUnits="userSpaceOnUse" fy="114.5684" fx="20.892099" r="5.256" cy="114.5684" cx="20.892099" id="aigrd2-3-0">
- <stop id="stop15566-9-5" style="stop-color:#F0F0F0" offset="0"/>
- <stop id="stop15568-7-7" style="stop-color:#9a9a9a;stop-opacity:1.0000000;" offset="1.0000000"/>
+ <clipPath
+ id="clipPath13106-7-0"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path34850-1-9"
+ d="m 125.5,433.5 h 23 v 41 h -33 v -31 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <clipPath
+ id="clipPath13716"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path13714"
+ d="m 125.5,433.5 h 23 v 41 h -33 v -31 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <clipPath
+ id="clipPath13753"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path13751"
+ d="m 125.5,433.5 h 23 v 41 h -33 v -31 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <clipPath
+ id="clipPath13768"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path13766"
+ d="m 125.5,433.5 h 23 v 41 h -33 v -31 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <clipPath
+ id="clipPath23877-4-8"
+ clipPathUnits="userSpaceOnUse">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate"
+ id="rect23879-6-5"
+ width="15"
+ height="6"
+ x="952"
+ y="-540"
+ transform="scale(1,-1)" />
+ </clipPath>
+ <clipPath
+ id="clipPath13803"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path13801"
+ d="m 125.5,433.5 h 23 v 41 h -33 v -31 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <clipPath
+ id="clipPath13818"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path13816-7"
+ d="m 125.5,433.5 h 23 v 41 h -33 v -31 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <clipPath
+ id="clipPath20586-3-3"
+ clipPathUnits="userSpaceOnUse">
+ <ellipse
+ ry="2.25"
+ rx="4.5"
+ cy="554"
+ cx="53"
+ transform="matrix(1.870472,0.1894819,-0.6587894,2.4281336,319.59052,-798.11661)"
+ id="path34889-5-5"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate" />
+ </clipPath>
+ <clipPath
+ id="clipPath13830"
+ clipPathUnits="userSpaceOnUse">
+ <ellipse
+ ry="2.25"
+ rx="4.5"
+ cy="554"
+ cx="53"
+ transform="matrix(1.870472,0.1894819,-0.6587894,2.4281336,319.59052,-798.11661)"
+ id="ellipse13828"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate" />
+ </clipPath>
+ <clipPath
+ id="clipPath13845"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path13843"
+ d="m 125.5,433.5 h 23 v 41 h -33 v -31 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <clipPath
+ id="clipPath13860"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path13858"
+ d="m 125.5,433.5 h 23 v 41 h -33 v -31 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <clipPath
+ id="clipPath13875"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path13873"
+ d="m 125.5,433.5 h 23 v 41 h -33 v -31 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <clipPath
+ id="clipPath13890"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path13888"
+ d="m 125.5,433.5 h 23 v 41 h -33 v -31 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <radialGradient
+ gradientUnits="userSpaceOnUse"
+ fy="114.5684"
+ fx="20.892099"
+ r="5.256"
+ cy="114.5684"
+ cx="20.892099"
+ id="aigrd2-3-0">
+ <stop
+ id="stop15566-9-5"
+ style="stop-color:#F0F0F0"
+ offset="0" />
+ <stop
+ id="stop15568-7-7"
+ style="stop-color:#9a9a9a;stop-opacity:1.0000000;"
+ offset="1.0000000" />
</radialGradient>
- <radialGradient gradientUnits="userSpaceOnUse" fy="114.5684" fx="20.892099" r="5.256" cy="114.5684" cx="20.892099" id="radialGradient13905">
- <stop id="stop13901" style="stop-color:#F0F0F0" offset="0"/>
- <stop id="stop13903" style="stop-color:#9a9a9a;stop-opacity:1.0000000;" offset="1.0000000"/>
+ <radialGradient
+ gradientUnits="userSpaceOnUse"
+ fy="114.5684"
+ fx="20.892099"
+ r="5.256"
+ cy="114.5684"
+ cx="20.892099"
+ id="radialGradient13905">
+ <stop
+ id="stop13901"
+ style="stop-color:#F0F0F0"
+ offset="0" />
+ <stop
+ id="stop13903"
+ style="stop-color:#9a9a9a;stop-opacity:1.0000000;"
+ offset="1.0000000" />
</radialGradient>
-
-
-
-
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient29805-5" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.94105289,0.01178942,-0.01073736,0.8570756,238.4669,249.70522)" cx="-30.028414" cy="19.425121" fx="-30.028414" fy="19.425121" r="7"/>
-
-
- <linearGradient id="linearGradient17555">
- <stop style="stop-color:#000000;stop-opacity:0.49803922;" offset="0" id="stop17557"/>
- <stop style="stop-color:#ffffff;stop-opacity:0.49803922;" offset="1" id="stop17559"/>
- </linearGradient>
- <linearGradient id="linearGradient17549">
- <stop id="stop17551" offset="0" style="stop-color:#7f7f7f;stop-opacity:1;"/>
- <stop id="stop17553" offset="1" style="stop-color:#7f7f7f;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient40455-7-1-6-0">
- <stop id="stop40457-6-6-8-7" offset="0" style="stop-color:#fff991;stop-opacity:1;"/>
- <stop id="stop40459-1-8-7-9" offset="1" style="stop-color:#fffbb9;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient14829">
- <stop id="stop14831" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
- <stop id="stop14833" offset="1" style="stop-color:#757575;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient14605">
- <stop style="stop-color:#ffffff;stop-opacity:0.56485355;" offset="0" id="stop14607"/>
- <stop style="stop-color:#fffffe;stop-opacity:0;" offset="1" id="stop14609"/>
- </linearGradient>
-
- <linearGradient id="linearGradient10069-9-7-5-4-6-5-0-3-6">
- <stop style="stop-color:#252525;stop-opacity:1" offset="0" id="stop10071-5-4-58-5-9-1-2-1-9"/>
- <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop10073-43-0-4-0-8-0-4-9-3"/>
- </linearGradient>
- <radialGradient id="radialGradient16142-7-6" cx="20.892099" cy="64.567902" r="5.257" fx="20.892099" fy="64.567902" gradientUnits="userSpaceOnUse">
- <stop offset="0" style="stop-color:#F0F0F0" id="stop16144-4-6"/>
- <stop offset="1" style="stop-color:#474747" id="stop16146-0-8"/>
+ <clipPath
+ id="clipPath13916"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path13914"
+ d="m 125.5,433.5 h 23 v 41 h -33 v -31 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <clipPath
+ id="clipPath13931"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path13929-3"
+ d="m 125.5,433.5 h 23 v 41 h -33 v -31 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <clipPath
+ id="clipPath13946"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path13944"
+ d="m 125.5,433.5 h 23 v 41 h -33 v -31 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <clipPath
+ id="clipPath13961"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path13959"
+ d="m 125.5,433.5 h 23 v 41 h -33 v -31 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask29801-1">
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.35;fill:url(#radialGradient29805-5);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.71217775;marker:none;enable-background:new"
+ id="rect29803-5"
+ width="15"
+ height="16"
+ x="204"
+ y="257" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient29805-5"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.94105289,0.01178942,-0.01073736,0.8570756,238.4669,249.70522)"
+ cx="-30.028414"
+ cy="19.425121"
+ fx="-30.028414"
+ fy="19.425121"
+ r="7" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask40306-1">
+ <path
+ inkscape:connector-curvature="0"
+ id="path40308-8"
+ d="m 195,11.00001 v 14 h 0.5 l 13.5,-13.5 v -0.5 z"
+ style="fill:#ffffff;fill-rule:evenodd;stroke:none"
+ sodipodi:nodetypes="cccccc" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask17570-5">
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc"
+ style="fill:#ffffff;fill-rule:evenodd;stroke:none"
+ d="m -44,358 v 14 l 14,-14 z"
+ id="path17572-2" />
+ </mask>
+ <linearGradient
+ id="linearGradient17555">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop17557" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.49803922;"
+ offset="1"
+ id="stop17559" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient17549">
+ <stop
+ id="stop17551"
+ offset="0"
+ style="stop-color:#7f7f7f;stop-opacity:1;" />
+ <stop
+ id="stop17553"
+ offset="1"
+ style="stop-color:#7f7f7f;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient40455-7-1-6-0">
+ <stop
+ id="stop40457-6-6-8-7"
+ offset="0"
+ style="stop-color:#fff991;stop-opacity:1;" />
+ <stop
+ id="stop40459-1-8-7-9"
+ offset="1"
+ style="stop-color:#fffbb9;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient14829">
+ <stop
+ id="stop14831"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop14833"
+ offset="1"
+ style="stop-color:#757575;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient14605">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.56485355;"
+ offset="0"
+ id="stop14607" />
+ <stop
+ style="stop-color:#fffffe;stop-opacity:0;"
+ offset="1"
+ id="stop14609" />
+ </linearGradient>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath22590-7">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;marker:none;enable-background:accumulate"
+ id="rect22592-5-0"
+ width="12"
+ height="14"
+ x="-30"
+ y="490.00012" />
+ </clipPath>
+ <linearGradient
+ id="linearGradient10069-9-7-5-4-6-5-0-3-6">
+ <stop
+ style="stop-color:#252525;stop-opacity:1"
+ offset="0"
+ id="stop10071-5-4-58-5-9-1-2-1-9" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop10073-43-0-4-0-8-0-4-9-3" />
+ </linearGradient>
+ <radialGradient
+ id="radialGradient16142-7-6"
+ cx="20.892099"
+ cy="64.567902"
+ r="5.257"
+ fx="20.892099"
+ fy="64.567902"
+ gradientUnits="userSpaceOnUse">
+ <stop
+ offset="0"
+ style="stop-color:#F0F0F0"
+ id="stop16144-4-6" />
+ <stop
+ offset="1"
+ style="stop-color:#474747"
+ id="stop16146-0-8" />
</radialGradient>
-
- <radialGradient gradientUnits="userSpaceOnUse" fy="64.567902" fx="20.892099" r="5.257" cy="64.567902" cx="20.892099" id="radialGradient16142">
- <stop id="stop16144" style="stop-color:#F0F0F0" offset="0"/>
- <stop id="stop16146" style="stop-color:#474747" offset="1"/>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath50172-0-6">
+ <path
+ inkscape:connector-curvature="0"
+ id="path50174-8-6"
+ d="m -177.34375,498 a 1.001098,1.001098 0 1 0 0.0937,2 h 3.65625 l -4.25,5.9375 a 1.0001,1.0001 0 0 0 -0.1875,0.59375 v 0.5 a 1.0001,1.0001 0 0 0 1,1 L -171.75,508 a 1.0001,1.0001 0 1 0 0,-2 l -3.6875,0.0312 4.25,-5.9375 A 1.0001,1.0001 0 0 0 -171,499.5 V 499 a 1.0001,1.0001 0 0 0 -1,-1 h -5.25 a 1.0001,1.0001 0 0 0 -0.0937,0 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:2;marker:none;enable-background:accumulate" />
+ </clipPath>
+ <radialGradient
+ gradientUnits="userSpaceOnUse"
+ fy="64.567902"
+ fx="20.892099"
+ r="5.257"
+ cy="64.567902"
+ cx="20.892099"
+ id="radialGradient16142">
+ <stop
+ id="stop16144"
+ style="stop-color:#F0F0F0"
+ offset="0" />
+ <stop
+ id="stop16146"
+ style="stop-color:#474747"
+ offset="1" />
</radialGradient>
-
-
-
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="linearGradient23595" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,1.1666667,-737,357.33333)" x1="771.0965" y1="354.28479" x2="772" y2="358.85715"/>
- <linearGradient id="linearGradient23647">
- <stop style="stop-color:white;stop-opacity:1;" offset="0" id="stop23649"/>
- <stop style="stop-color:black;stop-opacity:1;" offset="1" id="stop23651"/>
- </linearGradient>
- <linearGradient id="linearGradient48327-1">
- <stop style="stop-color:black;stop-opacity:0;" offset="0" id="stop48329-23"/>
- <stop style="stop-color:black;stop-opacity:1;" offset="1" id="stop48331-3"/>
- </linearGradient>
- <linearGradient id="linearGradient15425-4-9-8">
- <stop style="stop-color:#960000;stop-opacity:1;" offset="0" id="stop15427-5-8-24"/>
- <stop style="stop-color:#c80000;stop-opacity:0;" offset="1" id="stop15429-8-2-5"/>
- </linearGradient>
-
-
-
-
-
-
-
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="linearGradient25573" gradientUnits="userSpaceOnUse" gradientTransform="translate(-1,21)" x1="342" y1="288.5" x2="344.01321" y2="288.5"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="linearGradient25575" gradientUnits="userSpaceOnUse" gradientTransform="rotate(90,339,299)" x1="342" y1="288.5" x2="344.5" y2="288.5"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="linearGradient25577" gradientUnits="userSpaceOnUse" gradientTransform="rotate(180,349.5,299.5)" x1="342" y1="288.5" x2="344.5" y2="288.5"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="linearGradient25579" gradientUnits="userSpaceOnUse" gradientTransform="rotate(-90,360,300)" x1="342" y1="288.5" x2="344.5" y2="288.5"/>
-
- <linearGradient id="linearGradient31356">
- <stop id="stop31358" offset="0" style="stop-color:#1a1a1a;stop-opacity:1"/>
- <stop id="stop31360" offset="1" style="stop-color:#1a1a1a;stop-opacity:0;"/>
- </linearGradient>
-
-
-
-
-
-
- <linearGradient gradientUnits="userSpaceOnUse" y2="91.058184" x2="56.916232" y1="91.058184" x1="45.115946" gradientTransform="matrix(0.99964634,0,0,1.0003538,-3.0966264e-8,-3.9490267e-6)" id="linearGradient23512">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop23508"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop23510"/>
- </linearGradient>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient17073" id="linearGradient23615" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.728189,0,0,1.727271,-142.53857,-4.802156)" x1="110.16959" y1="57.061836" x2="117.55341" y2="64.995972"/>
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient52641-2-8-6" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.39420438,-0.08239205,0.27256031,1.3040635,-361.27885,-161.73915)" cx="-302.79681" cy="462.0358" fx="-302.79681" fy="462.0358" r="8"/>
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient52883-6-8-3" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.39420438,-0.08239205,0.27256031,1.3040635,-362.22886,-161.73912)" cx="-302.79681" cy="462.0358" fx="-302.79681" fy="462.0358" r="8"/>
-
-
- <filter style="color-interpolation-filters:sRGB" inkscape:collect="always" id="filter15613-7" x="-0.092011765" width="1.1840235" y="-0.097762503" height="1.1955251">
- <feGaussianBlur inkscape:collect="always" stdDeviation="0.65175" id="feGaussianBlur15615-4"/>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath22590">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;marker:none;enable-background:accumulate"
+ id="rect22592"
+ width="12"
+ height="14"
+ x="-30"
+ y="490.00012" />
+ </clipPath>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath20586">
+ <ellipse
+ ry="2.25"
+ rx="4.5"
+ cy="554"
+ cx="53"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate"
+ id="path34889"
+ transform="matrix(1.870472,0.1894819,-0.6587894,2.4281336,319.59052,-798.11661)" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask23591">
+ <rect
+ mask="none"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient23595);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect23593"
+ width="11"
+ height="14"
+ x="30"
+ y="768" />
+ </mask>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="linearGradient23595"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,1.1666667,-737,357.33333)"
+ x1="771.0965"
+ y1="354.28479"
+ x2="772"
+ y2="358.85715" />
+ <linearGradient
+ id="linearGradient23647">
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="0"
+ id="stop23649" />
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="1"
+ id="stop23651" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient48327-1">
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="0"
+ id="stop48329-23" />
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="1"
+ id="stop48331-3" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient15425-4-9-8">
+ <stop
+ style="stop-color:#960000;stop-opacity:1;"
+ offset="0"
+ id="stop15427-5-8-24" />
+ <stop
+ style="stop-color:#c80000;stop-opacity:0;"
+ offset="1"
+ id="stop15429-8-2-5" />
+ </linearGradient>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask13041-1">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient13046);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate"
+ id="rect13043-7"
+ width="7"
+ height="8"
+ x="276"
+ y="-12" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask13052-5">
+ <rect
+ y="4.0625"
+ x="276"
+ height="8"
+ width="7"
+ id="rect13054-4"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient13056);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate"
+ transform="scale(1,-1)" />
+ </mask>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath17188-1">
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#d3d7cf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate"
+ d="m 240.5,-19.90625 c -1.87005,0 -3.40625,1.536202 -3.40625,3.40625 v 2 c 0,1.87005 1.53621,3.40625 3.40625,3.40625 v -2.8125 c -0.33932,0 -0.59375,-0.254431 -0.59375,-0.59375 v -2 c 0,-0.339319 0.25443,-0.59375 0.59375,-0.59375 z"
+ id="path17190-3" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask18666-3">
+ <rect
+ y="6"
+ x="62.921577"
+ height="14.000001"
+ width="15.098035"
+ id="rect18668-3"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient18670);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.5;marker:none;enable-background:accumulate" />
+ </mask>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath40897">
+ <rect
+ y="198"
+ x="-41"
+ height="16"
+ width="15"
+ id="rect40899"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.45;fill:#80b3ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.29999995;marker:none;enable-background:accumulate"
+ transform="scale(-1,1)" />
+ </clipPath>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath40902">
+ <rect
+ y="197"
+ x="-22"
+ height="17"
+ width="15"
+ id="rect40904"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.45;fill:#80b3ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.29999995;marker:none;enable-background:accumulate"
+ transform="scale(-1,1)" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask25561">
+ <g
+ transform="translate(-21,-21)"
+ id="g25563">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:transform-center-x="4"
+ sodipodi:nodetypes="cccc"
+ id="path25565"
+ d="m 341,302 8,8 -8,8 z"
+ style="fill:url(#linearGradient25573);fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:url(#linearGradient25575);fill-rule:evenodd;stroke:none"
+ d="m 357,302 -8,8 -8,-8 z"
+ id="path25567"
+ sodipodi:nodetypes="cccc"
+ inkscape:transform-center-y="-4" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:url(#linearGradient25577);fill-rule:evenodd;stroke:none"
+ d="m 357,318 -8,-8 8,-8 z"
+ id="path25569"
+ sodipodi:nodetypes="cccc"
+ inkscape:transform-center-x="-4" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:url(#linearGradient25579);fill-rule:evenodd;stroke:none"
+ d="m 341,318 8,-8 8,8 z"
+ id="path25571"
+ sodipodi:nodetypes="cccc"
+ inkscape:transform-center-y="4" />
+ </g>
+ </mask>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="linearGradient25573"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-1,21)"
+ x1="342"
+ y1="288.5"
+ x2="344.01321"
+ y2="288.5" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="linearGradient25575"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="rotate(90,339,299)"
+ x1="342"
+ y1="288.5"
+ x2="344.5"
+ y2="288.5" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="linearGradient25577"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="rotate(180,349.5,299.5)"
+ x1="342"
+ y1="288.5"
+ x2="344.5"
+ y2="288.5" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="linearGradient25579"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="rotate(-90,360,300)"
+ x1="342"
+ y1="288.5"
+ x2="344.5"
+ y2="288.5" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask25369-8">
+ <g
+ id="g25371-1"
+ transform="translate(-21,-21)">
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:url(#linearGradient25381);fill-rule:evenodd;stroke:none"
+ d="m 341,302 8,8 -8,8 z"
+ id="path25373-3"
+ sodipodi:nodetypes="cccc"
+ inkscape:transform-center-x="4" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:transform-center-y="-4"
+ sodipodi:nodetypes="cccc"
+ id="path25375-1"
+ d="m 357,302 -8,8 -8,-8 z"
+ style="fill:url(#linearGradient25575);fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:transform-center-x="-4"
+ sodipodi:nodetypes="cccc"
+ id="path25377-7"
+ d="m 357,318 -8,-8 8,-8 z"
+ style="fill:url(#linearGradient25577);fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:transform-center-y="4"
+ sodipodi:nodetypes="cccc"
+ id="path25379-8"
+ d="m 341,318 8,-8 8,8 z"
+ style="fill:url(#linearGradient25579);fill-rule:evenodd;stroke:none" />
+ </g>
+ </mask>
+ <linearGradient
+ id="linearGradient31356">
+ <stop
+ id="stop31358"
+ offset="0"
+ style="stop-color:#1a1a1a;stop-opacity:1" />
+ <stop
+ id="stop31360"
+ offset="1"
+ style="stop-color:#1a1a1a;stop-opacity:0;" />
+ </linearGradient>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath42711-8-1-7">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
+ id="rect42713-4-3-0"
+ width="8.7252884"
+ height="17.464855"
+ x="127.4093"
+ y="214.76154" />
+ </clipPath>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath42711-8">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
+ id="rect42713-6"
+ width="8.7252884"
+ height="17.464855"
+ x="127.4093"
+ y="214.76154" />
+ </clipPath>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath28964-6">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\4.png"
+ sodipodi:nodetypes="ccccc"
+ style="display:inline;fill:url(#linearGradient28968);fill-opacity:1;fill-rule:evenodd;stroke:none;enable-background:new"
+ d="m 117.50984,228.63415 v -15.01646 l 11.71735,5.49383 v 15.38271 z"
+ id="path28966-9" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask29419-2">
+ <path
+ inkscape:connector-curvature="0"
+ id="path29422-4"
+ d="m 117.50984,229.00041 v -15.38272 l 11.71735,5.49383 v 15.74897 z"
+ style="display:inline;opacity:0.5;fill:url(#linearGradient29424);fill-opacity:1;fill-rule:evenodd;stroke:none;enable-background:new"
+ sodipodi:nodetypes="ccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\4.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ </mask>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath45147">
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccc"
+ id="path45149"
+ d="m 5,261 h 13 v 1 h -1 v 1 h 1 v 1 h -1 v 1 h -1 v 2 h 2 v -1 h 1 v -1 h 1 v 1 h 1 v -1 h 1 v 13 H 5 Z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.2;fill:#3771c8;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3.0999999;marker:none;enable-background:accumulate" />
+ </clipPath>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath24168-2">
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#808080;fill-rule:evenodd;stroke:none"
+ d="m 134.27489,222.11125 c -3.9249,-6.46418 -7.61892,6.46419 -11.54381,0 v 0 h -1.61614 v 8.77283 h 14.77608 v -8.77283 z"
+ id="path24170-0"
+ sodipodi:nodetypes="cccccccc" />
+ </clipPath>
+ <linearGradient
+ gradientUnits="userSpaceOnUse"
+ y2="91.058184"
+ x2="56.916232"
+ y1="91.058184"
+ x1="45.115946"
+ gradientTransform="matrix(0.99964634,0,0,1.0003538,-3.0966264e-8,-3.9490267e-6)"
+ id="linearGradient23512">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop23508" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop23510" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient17073"
+ id="linearGradient23615"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.728189,0,0,1.727271,-142.53857,-4.802156)"
+ x1="110.16959"
+ y1="57.061836"
+ x2="117.55341"
+ y2="64.995972" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask52637-8-8-5">
+ <rect
+ mask="none"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient52641-2-8-6);fill-opacity:1;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
+ id="rect52639-8-9-0"
+ width="7.9918551"
+ height="8.9366941"
+ x="-354"
+ y="458"
+ rx="0"
+ ry="0" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient52641-2-8-6"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.39420438,-0.08239205,0.27256031,1.3040635,-361.27885,-161.73915)"
+ cx="-302.79681"
+ cy="462.0358"
+ fx="-302.79681"
+ fy="462.0358"
+ r="8" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask52879-0-5-1">
+ <rect
+ mask="none"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient52883-6-8-3);fill-opacity:1;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
+ id="rect52881-7-3-3"
+ width="7.9918551"
+ height="8.9366941"
+ x="-354.95001"
+ y="458"
+ rx="0"
+ ry="0" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient52883-6-8-3"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.39420438,-0.08239205,0.27256031,1.3040635,-362.22886,-161.73912)"
+ cx="-302.79681"
+ cy="462.0358"
+ fx="-302.79681"
+ fy="462.0358"
+ r="8" />
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath15455-4">
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#d8d8d8;fill-opacity:1;stroke:none;stroke-width:1.20000005;marker:none;enable-background:new"
+ id="rect15457-68"
+ width="16"
+ height="16"
+ x="301.96045"
+ y="236.91833" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask15700-40">
+ <path
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.20000005;marker:none;filter:url(#filter15613-7);enable-background:new"
+ d="m 302.9292,245.91834 -2.4375,-1.125 -0.53125,-9.84375 19.95312,-0.0469 0.0156,9.95313 -2.9375,1.09375 v 5.96875 h -14 z"
+ id="path15702-9"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ </mask>
+ <filter
+ style="color-interpolation-filters:sRGB"
+ inkscape:collect="always"
+ id="filter15613-7"
+ x="-0.092011765"
+ width="1.1840235"
+ y="-0.097762503"
+ height="1.1955251">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.65175"
+ id="feGaussianBlur15615-4" />
</filter>
-
-
- <filter style="color-interpolation-filters:sRGB" inkscape:collect="always" id="filter15613-8-8" x="-0.092011765" width="1.1840235" y="-0.097762503" height="1.1955251">
- <feGaussianBlur inkscape:collect="always" stdDeviation="0.65175" id="feGaussianBlur15615-1-5"/>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath15455-9-6">
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#d8d8d8;fill-opacity:1;stroke:none;stroke-width:1.20000005;marker:none;enable-background:new"
+ id="rect15457-6-0"
+ width="16"
+ height="16"
+ x="301.96045"
+ y="236.91833" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask15700-4-5">
+ <path
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.20000005;marker:none;filter:url(#filter15613-8-8);enable-background:new"
+ d="m 302.9292,245.91834 -2.4375,-1.125 -0.53125,-9.84375 19.95312,-0.0469 0.0156,9.95313 -2.9375,1.09375 v 5.96875 h -14 z"
+ id="path15702-5-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ </mask>
+ <filter
+ style="color-interpolation-filters:sRGB"
+ inkscape:collect="always"
+ id="filter15613-8-8"
+ x="-0.092011765"
+ width="1.1840235"
+ y="-0.097762503"
+ height="1.1955251">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.65175"
+ id="feGaussianBlur15615-1-5" />
</filter>
- <filter style="color-interpolation-filters:sRGB" inkscape:label="Greyscale" id="filter15388-0">
-
-
-
+ <filter
+ style="color-interpolation-filters:sRGB"
+ inkscape:label="Greyscale"
+ id="filter15388-0">
+ <feColorMatrix
+ values="0.21 0.72 0.072 0 0 0.21 0.72 0.072 0 0 0.21 0.72 0.072 0 0 0 0 0 1 0 "
+ id="feColorMatrix15390-7"
+ result="fbSourceGraphic" />
+ <feColorMatrix
+ result="fbSourceGraphicAlpha"
+ in="fbSourceGraphic"
+ values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
+ id="feColorMatrix15392-5" />
+ <feColorMatrix
+ id="feColorMatrix15394-7"
+ values="0.21 0.72 0.072 0 0 0.21 0.72 0.072 0 0 0.21 0.72 0.072 0 0 0 0 0 1 0 "
+ in="fbSourceGraphic" />
</filter>
- <filter inkscape:label="Opacity" style="color-interpolation-filters:sRGB" id="filter17385-7">
-
-
+ <filter
+ inkscape:label="Opacity"
+ style="color-interpolation-filters:sRGB"
+ id="filter17385-7">
+ <feColorMatrix
+ values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 5 -1 "
+ result="colormatrix"
+ id="feColorMatrix17387-2" />
+ <feComposite
+ k4="0"
+ k3="0"
+ k1="0"
+ in2="colormatrix"
+ operator="arithmetic"
+ k2="0.24"
+ result="composite"
+ id="feComposite17389-3" />
</filter>
-
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient48820-9-2" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,1.0769231,0,5.9230769)" cx="-31" cy="-83.5" fx="-31" fy="-83.5" r="6.5"/>
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient24837" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,1.0769231,0,5.9230769)" cx="-31" cy="-83.5" fx="-31" fy="-83.5" r="6.5"/>
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient28589-9-2" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,1.0769231,0,5.9230769)" cx="-30.28125" cy="-84.341515" fx="-30.28125" fy="-84.341515" r="6.5"/>
-
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient45877-1-9" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.1099414,-0.9422316,0.4519816,0.05273803,38.220416,-152.21215)" cx="-25.452209" cy="-136.46503" fx="-25.452209" fy="-136.46503" r="8.0066185"/>
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient45451-2-8" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,0.9952162,167.99999,-60.91415)" cx="59.000011" cy="440.0191" fx="59.000011" fy="440.0191" r="6.5080619"/>
-
-
-
-
-
-
-
-
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient25025-8-0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.8918342,0,0,0.8918344,-15.699877,27.900732)" cx="49" cy="254.64285" fx="49" fy="254.64285" r="6.5"/>
-
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient31865" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.986122,0,0,0.986122,2.8033684,0.804927)" cx="202" cy="58" fx="202" fy="58" r="7"/>
-
-
- <linearGradient id="linearGradient23974-3-78-2">
- <stop id="stop23976-6-5-7" offset="0" style="stop-color:#a3a3a3;stop-opacity:1"/>
- <stop id="stop23978-2-4-4" offset="1" style="stop-color:#ffffff;stop-opacity:1"/>
- </linearGradient>
- <linearGradient id="linearGradient23705">
- <stop id="stop23707" offset="0" style="stop-color:#d4d2bf;stop-opacity:1;"/>
- <stop id="stop23709" offset="1" style="stop-color:#857f5d;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient24168">
- <stop id="stop24170" offset="0" style="stop-color:#182437;stop-opacity:1;"/>
- <stop id="stop24172" offset="1" style="stop-color:#2b4163;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient18906">
- <stop id="stop18904" offset="0" style="stop-color:#ffb36b;stop-opacity:1"/>
- <stop style="stop-color:#ff982a;stop-opacity:1;" offset="0.6832175" id="stop18902"/>
- <stop id="stop18900" offset="1" style="stop-color:#b45d00;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient17438">
- <stop style="stop-color:#ff9f37;stop-opacity:1" offset="0" id="stop17440"/>
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="1" id="stop17442"/>
- </linearGradient>
- <linearGradient id="linearGradient17596">
- <stop style="stop-color:#ee7b00;stop-opacity:1" offset="0" id="stop17598"/>
- <stop style="stop-color:#ffc280;stop-opacity:1" offset="1" id="stop17600"/>
- </linearGradient>
- <linearGradient id="linearGradient17602">
- <stop id="stop17604" offset="0" style="stop-color:#592e00;stop-opacity:1"/>
- <stop id="stop17606" offset="1" style="stop-color:#9e5200;stop-opacity:0.57431373"/>
- </linearGradient>
- <linearGradient id="linearGradient37925">
- <stop id="stop37927" offset="0" style="stop-color:#e7cbab;stop-opacity:1;"/>
- <stop id="stop37929" offset="1" style="stop-color:#af7333;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient23906">
- <stop id="stop23908" offset="0" style="stop-color:#ff921d;stop-opacity:1;"/>
- <stop id="stop23910" offset="1" style="stop-color:#ffa751;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient24101">
- <stop style="stop-color:#643400;stop-opacity:1;" offset="0" id="stop24103"/>
- <stop id="stop24105" offset="0.22606115" style="stop-color:#ed983d;stop-opacity:1;"/>
- <stop style="stop-color:#fff0d5;stop-opacity:1;" offset="1" id="stop24107"/>
- </linearGradient>
- <linearGradient id="linearGradient23302">
- <stop id="stop23304" offset="0" style="stop-color:#b45d00;stop-opacity:1;"/>
- <stop style="stop-color:#ff982a;stop-opacity:1;" offset="0.39332664" id="stop23306"/>
- <stop id="stop23308" offset="1" style="stop-color:#ffedd5;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient24081">
- <stop id="stop24083" offset="0" style="stop-color:#b45d00;stop-opacity:1;"/>
- <stop style="stop-color:#ff982a;stop-opacity:1;" offset="0.3167825" id="stop24085"/>
- <stop id="stop24087" offset="1" style="stop-color:#ffedd5;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient20324">
- <stop id="stop20326" offset="0" style="stop-color:#35241b;stop-opacity:1;"/>
- <stop style="stop-color:#69390e;stop-opacity:0.8392157;" offset="0.17637014" id="stop20328"/>
- <stop style="stop-color:#6c5b15;stop-opacity:0.67843139;" offset="0.35274029" id="stop20330"/>
- <stop id="stop20332" offset="1" style="stop-color:#947b15;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient35391">
- <stop id="stop35393" offset="0" style="stop-color:#322800;stop-opacity:1;"/>
- <stop id="stop35395" offset="1" style="stop-color:#6e4800;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient14219">
- <stop id="stop14221" offset="0" style="stop-color:#ff8605;stop-opacity:1;"/>
- <stop id="stop14223" offset="1" style="stop-color:#9c6700;stop-opacity:0;"/>
- </linearGradient>
-
-
-
- <radialGradient id="radialGradient16824-1-2" cx="20.892099" cy="64.567902" r="5.257" fx="20.892099" fy="64.567902" gradientUnits="userSpaceOnUse">
- <stop offset="0" style="stop-color:#b7b7b7;stop-opacity:1;" id="stop16826-5-7"/>
- <stop id="stop16828-2-0" style="stop-color:#646464;stop-opacity:1;" offset="0.50338405"/>
- <stop offset="1" style="stop-color:#b7b7b7;stop-opacity:1;" id="stop16830-7-0"/>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43050-6-3">
+ <rect
+ y="-122"
+ x="-24"
+ height="14"
+ width="16"
+ id="rect43052-3-0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.5;fill:url(#linearGradient43054-6);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask48816-8-2">
+ <rect
+ y="-84"
+ x="-44"
+ height="14"
+ width="13"
+ id="rect48818-4-9"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.85;fill:url(#radialGradient48820-9-2);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;marker:none;enable-background:new" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient48820-9-2"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,1.0769231,0,5.9230769)"
+ cx="-31"
+ cy="-83.5"
+ fx="-31"
+ fy="-83.5"
+ r="6.5" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask24835">
+ <rect
+ y="-84"
+ x="-44"
+ height="14"
+ width="13"
+ id="rect24833"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.85;fill:url(#radialGradient48820-9-2);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;marker:none;enable-background:new" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient24837"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,1.0769231,0,5.9230769)"
+ cx="-31"
+ cy="-83.5"
+ fx="-31"
+ fy="-83.5"
+ r="6.5" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask28585-8-0">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.85;fill:url(#radialGradient28589-9-2);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;marker:none;enable-background:new"
+ id="rect28587-2-1"
+ width="13"
+ height="14"
+ x="-44"
+ y="-84" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient28589-9-2"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,1.0769231,0,5.9230769)"
+ cx="-30.28125"
+ cy="-84.341515"
+ fx="-30.28125"
+ fy="-84.341515"
+ r="6.5" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43040-7-4">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.5;fill:url(#linearGradient43044-5);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
+ id="rect43042-9-7"
+ width="15"
+ height="16"
+ x="-45.04018"
+ y="-24"
+ rx="0"
+ ry="0" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask45865-7-8">
+ <g
+ id="g45867-3-2"
+ transform="translate(-14)">
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cssssssc"
+ id="path45869-7-4"
+ d="m -25.801826,-135.3217 c -0.907684,-0.32824 -0.906457,-1.55361 -0.440107,-2.23642 0.834186,-1.22138 2.593738,-1.15244 3.63669,-0.26277 1.530569,1.30563 1.388406,3.6923 0.08107,5.09763 -1.742467,1.8731 -4.73519,1.65156 -6.47424,-0.0993 -2.188413,-2.20322 -1.889457,-5.85971 0.277965,-7.95885 2.625036,-2.54234 6.931515,-2.199 9.311783,0.46129 2.764074,3.08924 2.372937,7.82808 -0.06591,10.77438"
+ style="display:inline;fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
+ mask="none" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc"
+ id="path45871-2-6"
+ d="m -19.40866,-140.32008 c 2.764074,3.08924 2.372937,7.82808 -0.06591,10.77438"
+ style="display:inline;fill:none;stroke:url(#linearGradient45875-0);stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ mask="none"
+ style="display:inline;fill:none;stroke:url(#radialGradient45877-1-9);stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
+ d="m -25.801826,-135.3217 c -0.907684,-0.32824 -0.906457,-1.55361 -0.440107,-2.23642 0.834186,-1.22138 2.593738,-1.15244 3.63669,-0.26277"
+ id="path45873-6-5"
+ sodipodi:nodetypes="css" />
+ </g>
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient45877-1-9"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.1099414,-0.9422316,0.4519816,0.05273803,38.220416,-152.21215)"
+ cx="-25.452209"
+ cy="-136.46503"
+ fx="-25.452209"
+ fy="-136.46503"
+ r="8.0066185" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask45447-7-9">
+ <rect
+ ry="0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.8;fill:url(#radialGradient45451-2-8);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate"
+ id="rect45449-4-7"
+ width="15"
+ height="15"
+ x="216"
+ y="366" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient45451-2-8"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.9952162,167.99999,-60.91415)"
+ cx="59.000011"
+ cy="440.0191"
+ fx="59.000011"
+ fy="440.0191"
+ r="6.5080619" />
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath43135-6-7">
+ <path
+ inkscape:connector-curvature="0"
+ id="path43137-1-6"
+ d="M -46,52 -30,36 H -46 Z"
+ style="opacity:0.5;fill:#ffff00;fill-rule:evenodd;stroke:none" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43188-4-7">
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.5;fill:url(#linearGradient43192-3);fill-rule:evenodd;stroke:none"
+ d="M -46,52 -30,36 H -46 Z"
+ id="path43190-2-2" />
+ </mask>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath43178-6-7">
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.5;fill:#ffff00;fill-rule:evenodd;stroke:none"
+ d="m -30,36 h -1 l -15,15 v 1 h 16 z"
+ id="path43180-8-7"
+ sodipodi:nodetypes="cccccc" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43182-5-7">
+ <path
+ inkscape:connector-curvature="0"
+ id="path43184-7-3"
+ d="m -46,52 v -1 l 15,-15 h 1 v 16 z"
+ style="opacity:0.5;fill:url(#linearGradient43186-6);fill-rule:evenodd;stroke:none"
+ sodipodi:nodetypes="cccccc" />
+ </mask>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath25077">
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.5;fill:#ffff00;fill-rule:evenodd;stroke:none"
+ d="m -30,36 h -1 l -15,15 v 1 h 16 z"
+ id="path25075"
+ sodipodi:nodetypes="cccccc" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask25081">
+ <path
+ inkscape:connector-curvature="0"
+ id="path25079"
+ d="m -46,52 v -1 l 15,-15 h 1 v 16 z"
+ style="opacity:0.5;fill:url(#linearGradient43186-6);fill-rule:evenodd;stroke:none"
+ sodipodi:nodetypes="cccccc" />
+ </mask>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath25093">
+ <path
+ inkscape:connector-curvature="0"
+ id="path25091"
+ d="M -46,52 -30,36 H -46 Z"
+ style="opacity:0.5;fill:#ffff00;fill-rule:evenodd;stroke:none" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask25097">
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.5;fill:url(#linearGradient43192-3);fill-rule:evenodd;stroke:none"
+ d="M -46,52 -30,36 H -46 Z"
+ id="path25095" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask25021-4-6">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient25025-8-0);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.70000005;marker:none;enable-background:accumulate"
+ id="rect25023-8-6"
+ width="13"
+ height="14"
+ x="26"
+ y="243" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient25025-8-0"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.8918342,0,0,0.8918344,-15.699877,27.900732)"
+ cx="49"
+ cy="254.64285"
+ fx="49"
+ fy="254.64285"
+ r="6.5" />
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath31849">
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;enable-background:accumulate"
+ d="m 232.13187,93.950853 h 4.84276 l 4.23742,4.237465 v 4.842822 h -9.08018 v -9.080287 z"
+ id="path31851"
+ sodipodi:nodetypes="cccccc" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask31861">
+ <circle
+ r="11"
+ cy="58"
+ cx="202"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient31865);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="path31863" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient31865"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.986122,0,0,0.986122,2.8033684,0.804927)"
+ cx="202"
+ cy="58"
+ fx="202"
+ fy="58"
+ r="7" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask25369-1-6">
+ <g
+ id="g25371-3-4"
+ transform="translate(-21,-21)">
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:url(#linearGradient25381);fill-rule:evenodd;stroke:none"
+ d="m 341,302 8,8 -8,8 z"
+ id="path25373-1-0"
+ sodipodi:nodetypes="cccc"
+ inkscape:transform-center-x="4" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:transform-center-y="-4"
+ sodipodi:nodetypes="cccc"
+ id="path25375-1-0"
+ d="m 357,302 -8,8 -8,-8 z"
+ style="fill:url(#linearGradient25575);fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:transform-center-x="-4"
+ sodipodi:nodetypes="cccc"
+ id="path25377-0-4"
+ d="m 357,318 -8,-8 8,-8 z"
+ style="fill:url(#linearGradient25577);fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:transform-center-y="4"
+ sodipodi:nodetypes="cccc"
+ id="path25379-3-6"
+ d="m 341,318 8,-8 8,8 z"
+ style="fill:url(#linearGradient25579);fill-rule:evenodd;stroke:none" />
+ </g>
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask25369-1">
+ <g
+ id="g25371-3"
+ transform="translate(-21,-21)">
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:url(#linearGradient25381);fill-rule:evenodd;stroke:none"
+ d="m 341,302 8,8 -8,8 z"
+ id="path25373-1"
+ sodipodi:nodetypes="cccc"
+ inkscape:transform-center-x="4" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:transform-center-y="-4"
+ sodipodi:nodetypes="cccc"
+ id="path25375-1-2"
+ d="m 357,302 -8,8 -8,-8 z"
+ style="fill:url(#linearGradient25575);fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:transform-center-x="-4"
+ sodipodi:nodetypes="cccc"
+ id="path25377-0"
+ d="m 357,318 -8,-8 8,-8 z"
+ style="fill:url(#linearGradient25577);fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:transform-center-y="4"
+ sodipodi:nodetypes="cccc"
+ id="path25379-3"
+ d="m 341,318 8,-8 8,8 z"
+ style="fill:url(#linearGradient25579);fill-rule:evenodd;stroke:none" />
+ </g>
+ </mask>
+ <linearGradient
+ id="linearGradient23974-3-78-2">
+ <stop
+ id="stop23976-6-5-7"
+ offset="0"
+ style="stop-color:#a3a3a3;stop-opacity:1" />
+ <stop
+ id="stop23978-2-4-4"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient23705">
+ <stop
+ id="stop23707"
+ offset="0"
+ style="stop-color:#d4d2bf;stop-opacity:1;" />
+ <stop
+ id="stop23709"
+ offset="1"
+ style="stop-color:#857f5d;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient24168">
+ <stop
+ id="stop24170"
+ offset="0"
+ style="stop-color:#182437;stop-opacity:1;" />
+ <stop
+ id="stop24172"
+ offset="1"
+ style="stop-color:#2b4163;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient18906">
+ <stop
+ id="stop18904"
+ offset="0"
+ style="stop-color:#ffb36b;stop-opacity:1" />
+ <stop
+ style="stop-color:#ff982a;stop-opacity:1;"
+ offset="0.6832175"
+ id="stop18902" />
+ <stop
+ id="stop18900"
+ offset="1"
+ style="stop-color:#b45d00;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient17438">
+ <stop
+ style="stop-color:#ff9f37;stop-opacity:1"
+ offset="0"
+ id="stop17440" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop17442" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient17596">
+ <stop
+ style="stop-color:#ee7b00;stop-opacity:1"
+ offset="0"
+ id="stop17598" />
+ <stop
+ style="stop-color:#ffc280;stop-opacity:1"
+ offset="1"
+ id="stop17600" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient17602">
+ <stop
+ id="stop17604"
+ offset="0"
+ style="stop-color:#592e00;stop-opacity:1" />
+ <stop
+ id="stop17606"
+ offset="1"
+ style="stop-color:#9e5200;stop-opacity:0.57431373" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37925">
+ <stop
+ id="stop37927"
+ offset="0"
+ style="stop-color:#e7cbab;stop-opacity:1;" />
+ <stop
+ id="stop37929"
+ offset="1"
+ style="stop-color:#af7333;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient23906">
+ <stop
+ id="stop23908"
+ offset="0"
+ style="stop-color:#ff921d;stop-opacity:1;" />
+ <stop
+ id="stop23910"
+ offset="1"
+ style="stop-color:#ffa751;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient24101">
+ <stop
+ style="stop-color:#643400;stop-opacity:1;"
+ offset="0"
+ id="stop24103" />
+ <stop
+ id="stop24105"
+ offset="0.22606115"
+ style="stop-color:#ed983d;stop-opacity:1;" />
+ <stop
+ style="stop-color:#fff0d5;stop-opacity:1;"
+ offset="1"
+ id="stop24107" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient23302">
+ <stop
+ id="stop23304"
+ offset="0"
+ style="stop-color:#b45d00;stop-opacity:1;" />
+ <stop
+ style="stop-color:#ff982a;stop-opacity:1;"
+ offset="0.39332664"
+ id="stop23306" />
+ <stop
+ id="stop23308"
+ offset="1"
+ style="stop-color:#ffedd5;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient24081">
+ <stop
+ id="stop24083"
+ offset="0"
+ style="stop-color:#b45d00;stop-opacity:1;" />
+ <stop
+ style="stop-color:#ff982a;stop-opacity:1;"
+ offset="0.3167825"
+ id="stop24085" />
+ <stop
+ id="stop24087"
+ offset="1"
+ style="stop-color:#ffedd5;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient20324">
+ <stop
+ id="stop20326"
+ offset="0"
+ style="stop-color:#35241b;stop-opacity:1;" />
+ <stop
+ style="stop-color:#69390e;stop-opacity:0.8392157;"
+ offset="0.17637014"
+ id="stop20328" />
+ <stop
+ style="stop-color:#6c5b15;stop-opacity:0.67843139;"
+ offset="0.35274029"
+ id="stop20330" />
+ <stop
+ id="stop20332"
+ offset="1"
+ style="stop-color:#947b15;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient35391">
+ <stop
+ id="stop35393"
+ offset="0"
+ style="stop-color:#322800;stop-opacity:1;" />
+ <stop
+ id="stop35395"
+ offset="1"
+ style="stop-color:#6e4800;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient14219">
+ <stop
+ id="stop14221"
+ offset="0"
+ style="stop-color:#ff8605;stop-opacity:1;" />
+ <stop
+ id="stop14223"
+ offset="1"
+ style="stop-color:#9c6700;stop-opacity:0;" />
+ </linearGradient>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43822-7-6">
+ <rect
+ y="208"
+ x="754"
+ height="9"
+ width="12"
+ id="rect43824-6-2"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.93999993;fill:url(#linearGradient43826);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:new" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43822-5">
+ <rect
+ y="208"
+ x="754"
+ height="9"
+ width="12"
+ id="rect43824-61"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.93999993;fill:url(#linearGradient43826);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:new" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43822-7">
+ <rect
+ y="208"
+ x="754"
+ height="9"
+ width="12"
+ id="rect43824-6"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.93999993;fill:url(#linearGradient43826);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:new" />
+ </mask>
+ <radialGradient
+ id="radialGradient16824-1-2"
+ cx="20.892099"
+ cy="64.567902"
+ r="5.257"
+ fx="20.892099"
+ fy="64.567902"
+ gradientUnits="userSpaceOnUse">
+ <stop
+ offset="0"
+ style="stop-color:#b7b7b7;stop-opacity:1;"
+ id="stop16826-5-7" />
+ <stop
+ id="stop16828-2-0"
+ style="stop-color:#646464;stop-opacity:1;"
+ offset="0.50338405" />
+ <stop
+ offset="1"
+ style="stop-color:#b7b7b7;stop-opacity:1;"
+ id="stop16830-7-0" />
</radialGradient>
-
-
- <linearGradient id="linearGradient24143-0">
- <stop id="stop24145-0" offset="0" style="stop-color:#2c2c2c;stop-opacity:1;"/>
- <stop style="stop-color:#b3b3b3;stop-opacity:1;" offset="0.5" id="stop24669-1"/>
- <stop id="stop24147-4" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient40809">
- <stop style="stop-color:#0059d7;stop-opacity:1;" offset="0" id="stop40811"/>
- <stop style="stop-color:#b7d4ff;stop-opacity:1;" offset="1" id="stop40813"/>
- </linearGradient>
- <linearGradient id="linearGradient38796-7-9">
- <stop style="stop-color:#fc9694;stop-opacity:1;" offset="0" id="stop38798-6-8"/>
- <stop style="stop-color:#e71609;stop-opacity:1;" offset="1" id="stop38800-1-8"/>
- </linearGradient>
-
- <linearGradient id="linearGradient35407">
- <stop id="stop35409" offset="0" style="stop-color:#a17306;stop-opacity:1;"/>
- <stop style="stop-color:#cca649;stop-opacity:1;" offset="0.43277758" id="stop35411"/>
- <stop id="stop35413" offset="1" style="stop-color:#f9f5e9;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="linearGradient14472" gradientUnits="userSpaceOnUse" x1="80.768944" y1="504.67188" x2="76.885078" y2="501.58331"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient11146" id="linearGradient14474" gradientUnits="userSpaceOnUse" x1="89.526657" y1="511.42972" x2="78.000008" y2="501.04794"/>
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient11146" id="radialGradient14476" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.4624192,0,0,1.4467089,-36.975824,-224.99718)" cx="79.959885" cy="503.81497" fx="79.959885" fy="503.81497" r="2.9089756"/>
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient14262" id="radialGradient14478" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.8886193,0.8021825,-0.8051059,0.8972684,411.80247,-8.668512)" cx="74.518959" cy="499.99969" fx="74.518959" fy="499.99969" r="3.1650217"/>
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient11146" id="radialGradient28864" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.4624192,0,0,1.4467089,-36.975824,-224.99718)" cx="79.959885" cy="503.81497" fx="79.959885" fy="503.81497" r="2.9089756"/>
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient14262" id="radialGradient28872" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.8886193,0.8021825,-0.8051059,0.8972684,411.80247,-8.668512)" cx="74.518959" cy="499.99969" fx="74.518959" fy="499.99969" r="3.1650217"/>
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient11146" id="radialGradient28896" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.4624192,0,0,1.4467089,-36.975824,-224.99718)" cx="79.959885" cy="503.81497" fx="79.959885" fy="503.81497" r="2.9089756"/>
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient14262" id="radialGradient28904" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.8886193,0.8021825,-0.8051059,0.8972684,411.80247,-8.668512)" cx="74.518959" cy="499.99969" fx="74.518959" fy="499.99969" r="3.1650217"/>
-
- <linearGradient id="linearGradient39080">
- <stop style="stop-color:#1a2a3d;stop-opacity:1;" offset="0" id="stop39082"/>
- <stop id="stop39084" offset="0.5" style="stop-color:#95b0d1;stop-opacity:1;"/>
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="1" id="stop39086"/>
- </linearGradient>
- <linearGradient id="linearGradient37623">
- <stop id="stop37625" offset="0" style="stop-color:#e5e1ca;stop-opacity:1;"/>
- <stop id="stop37627" offset="1" style="stop-color:#d6ca22;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient19625">
- <stop id="stop19627" offset="0" style="stop-color:#2258a6;stop-opacity:1;"/>
- <stop id="stop19629" offset="1" style="stop-color:#c1d7f8;stop-opacity:1;"/>
- </linearGradient>
- <linearGradient id="linearGradient12678">
- <stop id="stop12680" offset="0" style="stop-color:#d40000;stop-opacity:1"/>
- <stop id="stop12682" offset="1" style="stop-color:#000000;stop-opacity:0;"/>
- </linearGradient>
- <linearGradient id="linearGradient71814">
- <stop style="stop-color:#6e0d00;stop-opacity:1;" offset="0" id="stop71816"/>
- <stop style="stop-color:#6f2913;stop-opacity:0;" offset="1" id="stop71818"/>
- </linearGradient>
-
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="linearGradient57454" gradientUnits="userSpaceOnUse" gradientTransform="translate(258.00306,-231.00101)" x1="75.25" y1="393.25" x2="73.5" y2="391.5"/>
-
-
-
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="linearGradient38478" gradientUnits="userSpaceOnUse" gradientTransform="translate(254.01612,-211.00101)" x1="96.824379" y1="393.90298" x2="94.246101" y2="391.21976"/>
- <linearGradient id="linearGradient4138">
- <stop style="stop-color:#6c432f;stop-opacity:1;" offset="0" id="stop4140"/>
- <stop style="stop-color:#c0966d;stop-opacity:1;" offset="1" id="stop4142"/>
- </linearGradient>
- <linearGradient id="linearGradient38831">
- <stop style="stop-color:#182b42;stop-opacity:1;" offset="0" id="stop38833"/>
- <stop id="stop38836" offset="0.38971797" style="stop-color:#598ac7;stop-opacity:1;"/>
- <stop style="stop-color:#f1f1f1;stop-opacity:1;" offset="1" id="stop38838"/>
- </linearGradient>
-
- <linearGradient id="linearGradient18056">
- <stop id="stop18058" offset="0" style="stop-color:#162d50;stop-opacity:1"/>
- <stop id="stop18060" offset="1" style="stop-color:#295498;stop-opacity:0.34057972;"/>
- </linearGradient>
-
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="linearGradient23199" gradientUnits="userSpaceOnUse" gradientTransform="translate(-1)" x1="22.75" y1="245" x2="24.5" y2="245"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="linearGradient23201" gradientUnits="userSpaceOnUse" gradientTransform="translate(-61)" x1="22.75" y1="245" x2="24.25" y2="245"/>
- <linearGradient id="linearGradient24695">
- <stop style="stop-color:#3d361a;stop-opacity:1;" offset="0" id="stop24697"/>
- <stop id="stop24699" offset="0.60401857" style="stop-color:#d1c595;stop-opacity:1;"/>
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="1" id="stop24701"/>
- </linearGradient>
- <linearGradient id="linearGradient22556">
- <stop id="stop22558" offset="0" style="stop-color:#6a9bef;stop-opacity:1"/>
- <stop style="stop-color:#bccee8;stop-opacity:0.58450705;" offset="0.77941167" id="stop22568"/>
- <stop id="stop22560" offset="1" style="stop-color:#ccdaed;stop-opacity:0;"/>
- </linearGradient>
-
- <linearGradient id="linearGradient4343-1-1-9-1">
- <stop id="stop4345-2-9-5-6" offset="0" style="stop-color:white;stop-opacity:1;"/>
- <stop id="stop4347-1-5-5-1" offset="1" style="stop-color:#fff9f9;stop-opacity:0;"/>
- </linearGradient>
-
-
-
-
- <linearGradient gradientUnits="userSpaceOnUse" y2="91.058182" x2="56.916233" y1="91.058182" x1="45.115948" gradientTransform="matrix(0.99964634,0,0,1.0003538,-3.0966264e-8,-8.1179537e-6)" id="linearGradient23512-7">
- <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop23508-4"/>
- <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop23510-3"/>
- </linearGradient>
-
-
-
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient48820-9-2-1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,1.0769231,0,5.9230769)" cx="-31" cy="-83.5" fx="-31" fy="-83.5" r="6.5"/>
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient55620" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,1.0769231,0,5.9230769)" cx="-31" cy="-83.5" fx="-31" fy="-83.5" r="6.5"/>
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient28589-9-2-0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,1.0769231,0,5.9230769)" cx="-30.28125" cy="-84.341515" fx="-30.28125" fy="-84.341515" r="6.5"/>
-
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient45877-1-9-2" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.1099414,-0.9422316,0.4519816,0.05273803,38.220416,-152.21215)" cx="-25.452209" cy="-136.46503" fx="-25.452209" fy="-136.46503" r="8.0066185"/>
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient45451-2-8-4" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,0.9952162,167.99999,-60.91415)" cx="59.000011" cy="440.0191" fx="59.000011" fy="440.0191" r="6.5080619"/>
-
-
-
-
-
-
-
-
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient25025-8-0-1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.8918342,0,0,0.8918344,-15.699877,27.900732)" cx="49" cy="254.64285" fx="49" fy="254.64285" r="6.5"/>
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient52641-2-8-6-3" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.39420438,-0.08239205,0.27256031,1.3040635,-361.27885,-161.73915)" cx="-302.79681" cy="462.0358" fx="-302.79681" fy="462.0358" r="8"/>
-
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient52883-6-8-3-0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.39420438,-0.08239205,0.27256031,1.3040635,-362.22886,-161.73912)" cx="-302.79681" cy="462.0358" fx="-302.79681" fy="462.0358" r="8"/>
-
-
-
-
-
-
-
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="linearGradient34189-1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.695652,0,0,0.869703,170.06515,482.33642)" x1="188.77448" y1="259.745" x2="164.0939" y2="242.22473"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient11146" id="linearGradient34191-9" gradientUnits="userSpaceOnUse" gradientTransform="translate(572.00001,970)" x1="-287.75" y1="-276.75" x2="-276" y2="-264.875"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="linearGradient40879-9-8-1-3" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.608695,0,0,0.760996,188.8695,512.23032)" x1="130.70929" y1="210.78392" x2="171.50414" y2="248.54021"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient11146" id="linearGradient34193-9" gradientUnits="userSpaceOnUse" gradientTransform="translate(576.00001,973)" x1="-283" y1="-272" x2="-277.01501" y2="-267.26749"/>
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient18495" id="radialGradient40883-4-0-3-9" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-0.06118084,-0.8594818,2.4629674,-0.1753088,-44.40057,787.15309)" cx="77.721619" cy="104.09358" fx="77.721619" fy="104.09358" r="3.9999998"/>
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient24562" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0474269,0.00526965,-0.00503098,0.9999873,209.98584,104.8287)" cx="27.411026" cy="255.58899" fx="27.411026" fy="255.58899" r="5.9250002"/>
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient22563" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0474269,0.00526965,-0.00503098,0.9999873,209.98584,104.8287)" cx="27.411026" cy="255.58899" fx="27.411026" fy="255.58899" r="5.9250002"/>
- <radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient22577" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0474269,0.00526965,-0.00503098,0.9999873,209.98584,104.8287)" cx="27.411026" cy="255.58899" fx="27.411026" fy="255.58899" r="5.9250002"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient11146" id="linearGradient22732-4" gradientUnits="userSpaceOnUse" x1="496.49335" y1="537.78113" x2="498.40021" y2="540.13623" gradientTransform="translate(42.000001,63)"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient11146" id="linearGradient22781" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-0.99999997,0,0,0.99999996,-2.7720701e-6,20.999999)" x1="496.49335" y1="537.78113" x2="498.40021" y2="540.13623"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient11146" id="linearGradient22785" gradientUnits="userSpaceOnUse" gradientTransform="translate(21,42)" x1="496.49335" y1="537.78113" x2="498.40021" y2="540.13623"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient11146" id="linearGradient22785-7" gradientUnits="userSpaceOnUse" gradientTransform="translate(21,42)" x1="496.49335" y1="537.78113" x2="498.40021" y2="540.13623"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient11146" id="linearGradient22939" gradientUnits="userSpaceOnUse" gradientTransform="translate(21,42)" x1="496.49335" y1="537.78113" x2="498.40021" y2="540.13623"/>
-
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43822-9">
+ <rect
+ y="208"
+ x="754"
+ height="9"
+ width="12"
+ id="rect43824-4"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.93999993;fill:url(#linearGradient43826);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:new" />
+ </mask>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath43368-7-3">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
+ id="rect43370-1-6"
+ width="16"
+ height="16"
+ x="-79"
+ y="26" />
+ </clipPath>
+ <linearGradient
+ id="linearGradient24143-0">
+ <stop
+ id="stop24145-0"
+ offset="0"
+ style="stop-color:#2c2c2c;stop-opacity:1;" />
+ <stop
+ style="stop-color:#b3b3b3;stop-opacity:1;"
+ offset="0.5"
+ id="stop24669-1" />
+ <stop
+ id="stop24147-4"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient40809">
+ <stop
+ style="stop-color:#0059d7;stop-opacity:1;"
+ offset="0"
+ id="stop40811" />
+ <stop
+ style="stop-color:#b7d4ff;stop-opacity:1;"
+ offset="1"
+ id="stop40813" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient38796-7-9">
+ <stop
+ style="stop-color:#fc9694;stop-opacity:1;"
+ offset="0"
+ id="stop38798-6-8" />
+ <stop
+ style="stop-color:#e71609;stop-opacity:1;"
+ offset="1"
+ id="stop38800-1-8" />
+ </linearGradient>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath43368-1">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
+ id="rect43370-7"
+ width="16"
+ height="16"
+ x="-79"
+ y="26" />
+ </clipPath>
+ <linearGradient
+ id="linearGradient35407">
+ <stop
+ id="stop35409"
+ offset="0"
+ style="stop-color:#a17306;stop-opacity:1;" />
+ <stop
+ style="stop-color:#cca649;stop-opacity:1;"
+ offset="0.43277758"
+ id="stop35411" />
+ <stop
+ id="stop35413"
+ offset="1"
+ style="stop-color:#f9f5e9;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="linearGradient14472"
+ gradientUnits="userSpaceOnUse"
+ x1="80.768944"
+ y1="504.67188"
+ x2="76.885078"
+ y2="501.58331" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11146"
+ id="linearGradient14474"
+ gradientUnits="userSpaceOnUse"
+ x1="89.526657"
+ y1="511.42972"
+ x2="78.000008"
+ y2="501.04794" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11146"
+ id="radialGradient14476"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.4624192,0,0,1.4467089,-36.975824,-224.99718)"
+ cx="79.959885"
+ cy="503.81497"
+ fx="79.959885"
+ fy="503.81497"
+ r="2.9089756" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient14262"
+ id="radialGradient14478"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.8886193,0.8021825,-0.8051059,0.8972684,411.80247,-8.668512)"
+ cx="74.518959"
+ cy="499.99969"
+ fx="74.518959"
+ fy="499.99969"
+ r="3.1650217" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11146"
+ id="radialGradient28864"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.4624192,0,0,1.4467089,-36.975824,-224.99718)"
+ cx="79.959885"
+ cy="503.81497"
+ fx="79.959885"
+ fy="503.81497"
+ r="2.9089756" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient14262"
+ id="radialGradient28872"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.8886193,0.8021825,-0.8051059,0.8972684,411.80247,-8.668512)"
+ cx="74.518959"
+ cy="499.99969"
+ fx="74.518959"
+ fy="499.99969"
+ r="3.1650217" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11146"
+ id="radialGradient28896"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.4624192,0,0,1.4467089,-36.975824,-224.99718)"
+ cx="79.959885"
+ cy="503.81497"
+ fx="79.959885"
+ fy="503.81497"
+ r="2.9089756" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient14262"
+ id="radialGradient28904"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.8886193,0.8021825,-0.8051059,0.8972684,411.80247,-8.668512)"
+ cx="74.518959"
+ cy="499.99969"
+ fx="74.518959"
+ fy="499.99969"
+ r="3.1650217" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43822-3">
+ <rect
+ y="208"
+ x="754"
+ height="9"
+ width="12"
+ id="rect43824-5"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.93999993;fill:url(#linearGradient43826);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:new" />
+ </mask>
+ <linearGradient
+ id="linearGradient39080">
+ <stop
+ style="stop-color:#1a2a3d;stop-opacity:1;"
+ offset="0"
+ id="stop39082" />
+ <stop
+ id="stop39084"
+ offset="0.5"
+ style="stop-color:#95b0d1;stop-opacity:1;" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop39086" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37623">
+ <stop
+ id="stop37625"
+ offset="0"
+ style="stop-color:#e5e1ca;stop-opacity:1;" />
+ <stop
+ id="stop37627"
+ offset="1"
+ style="stop-color:#d6ca22;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient19625">
+ <stop
+ id="stop19627"
+ offset="0"
+ style="stop-color:#2258a6;stop-opacity:1;" />
+ <stop
+ id="stop19629"
+ offset="1"
+ style="stop-color:#c1d7f8;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient12678">
+ <stop
+ id="stop12680"
+ offset="0"
+ style="stop-color:#d40000;stop-opacity:1" />
+ <stop
+ id="stop12682"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient71814">
+ <stop
+ style="stop-color:#6e0d00;stop-opacity:1;"
+ offset="0"
+ id="stop71816" />
+ <stop
+ style="stop-color:#6f2913;stop-opacity:0;"
+ offset="1"
+ id="stop71818" />
+ </linearGradient>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask57450-1">
+ <rect
+ y="154.99899"
+ x="326.00305"
+ height="15"
+ width="15"
+ id="rect57452-3"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient57454);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate" />
+ </mask>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="linearGradient57454"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(258.00306,-231.00101)"
+ x1="75.25"
+ y1="393.25"
+ x2="73.5"
+ y2="391.5" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask32294-8">
+ <rect
+ y="323"
+ x="134"
+ height="16"
+ width="9"
+ id="rect32296-9"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient32298);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask57450">
+ <rect
+ y="154.99899"
+ x="326.00305"
+ height="15"
+ width="15"
+ id="rect57452"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient57454);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask38474">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient38478);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect38476"
+ width="15"
+ height="15"
+ x="343.01611"
+ y="174.99901" />
+ </mask>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="linearGradient38478"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(254.01612,-211.00101)"
+ x1="96.824379"
+ y1="393.90298"
+ x2="94.246101"
+ y2="391.21976" />
+ <linearGradient
+ id="linearGradient4138">
+ <stop
+ style="stop-color:#6c432f;stop-opacity:1;"
+ offset="0"
+ id="stop4140" />
+ <stop
+ style="stop-color:#c0966d;stop-opacity:1;"
+ offset="1"
+ id="stop4142" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient38831">
+ <stop
+ style="stop-color:#182b42;stop-opacity:1;"
+ offset="0"
+ id="stop38833" />
+ <stop
+ id="stop38836"
+ offset="0.38971797"
+ style="stop-color:#598ac7;stop-opacity:1;" />
+ <stop
+ style="stop-color:#f1f1f1;stop-opacity:1;"
+ offset="1"
+ id="stop38838" />
+ </linearGradient>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask20957-5">
+ <rect
+ y="101"
+ x="162"
+ height="5"
+ width="8"
+ id="rect20959-8"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient20961);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.29999995;marker:none;enable-background:accumulate" />
+ </mask>
+ <linearGradient
+ id="linearGradient18056">
+ <stop
+ id="stop18058"
+ offset="0"
+ style="stop-color:#162d50;stop-opacity:1" />
+ <stop
+ id="stop18060"
+ offset="1"
+ style="stop-color:#295498;stop-opacity:0.34057972;" />
+ </linearGradient>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask23189">
+ <g
+ transform="translate(-28,49)"
+ id="g23193">
+ <rect
+ y="237"
+ x="22"
+ height="16"
+ width="9"
+ id="rect23195"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient23199);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate" />
+ <rect
+ transform="scale(-1,1)"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient23201);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
+ id="rect23197"
+ width="9"
+ height="16"
+ x="-38"
+ y="237" />
+ </g>
+ </mask>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="linearGradient23199"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-1)"
+ x1="22.75"
+ y1="245"
+ x2="24.5"
+ y2="245" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="linearGradient23201"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-61)"
+ x1="22.75"
+ y1="245"
+ x2="24.25"
+ y2="245" />
+ <linearGradient
+ id="linearGradient24695">
+ <stop
+ style="stop-color:#3d361a;stop-opacity:1;"
+ offset="0"
+ id="stop24697" />
+ <stop
+ id="stop24699"
+ offset="0.60401857"
+ style="stop-color:#d1c595;stop-opacity:1;" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop24701" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient22556">
+ <stop
+ id="stop22558"
+ offset="0"
+ style="stop-color:#6a9bef;stop-opacity:1" />
+ <stop
+ style="stop-color:#bccee8;stop-opacity:0.58450705;"
+ offset="0.77941167"
+ id="stop22568" />
+ <stop
+ id="stop22560"
+ offset="1"
+ style="stop-color:#ccdaed;stop-opacity:0;" />
+ </linearGradient>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask20957-7">
+ <rect
+ y="101"
+ x="162"
+ height="5"
+ width="8"
+ id="rect20959-85"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient20961);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.29999995;marker:none;enable-background:accumulate" />
+ </mask>
+ <linearGradient
+ id="linearGradient4343-1-1-9-1">
+ <stop
+ id="stop4345-2-9-5-6"
+ offset="0"
+ style="stop-color:white;stop-opacity:1;" />
+ <stop
+ id="stop4347-1-5-5-1"
+ offset="1"
+ style="stop-color:#fff9f9;stop-opacity:0;" />
+ </linearGradient>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask38956-7">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient38961);stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
+ id="rect38958-9"
+ width="16"
+ height="12"
+ x="488"
+ y="560"
+ rx="0"
+ ry="0" />
+ </mask>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath28964-6-5">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\4.png"
+ sodipodi:nodetypes="ccccc"
+ style="display:inline;fill:url(#linearGradient28968);fill-opacity:1;fill-rule:evenodd;stroke:none;enable-background:new"
+ d="m 117.50984,228.63415 v -15.01646 l 11.71735,5.49383 v 15.38271 z"
+ id="path28966-9-9" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask29419-2-7">
+ <path
+ inkscape:connector-curvature="0"
+ id="path29422-4-5"
+ d="m 117.50984,229.00041 v -15.38272 l 11.71735,5.49383 v 15.74897 z"
+ style="display:inline;opacity:0.5;fill:url(#linearGradient29424);fill-opacity:1;fill-rule:evenodd;stroke:none;enable-background:new"
+ sodipodi:nodetypes="ccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\4.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ </mask>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath24168-2-8">
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#808080;fill-rule:evenodd;stroke:none"
+ d="m 134.27489,222.11125 c -3.9249,-6.46418 -7.61892,6.46419 -11.54381,0 v 0 h -1.61614 v 8.77283 h 14.77608 v -8.77283 z"
+ id="path24170-0-1"
+ sodipodi:nodetypes="cccccccc" />
+ </clipPath>
+ <linearGradient
+ gradientUnits="userSpaceOnUse"
+ y2="91.058182"
+ x2="56.916233"
+ y1="91.058182"
+ x1="45.115948"
+ gradientTransform="matrix(0.99964634,0,0,1.0003538,-3.0966264e-8,-8.1179537e-6)"
+ id="linearGradient23512-7">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop23508-4" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop23510-3" />
+ </linearGradient>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath42711-8-1-7-8">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
+ id="rect42713-4-3-0-3"
+ width="8.7252884"
+ height="17.464855"
+ x="127.4093"
+ y="214.76154" />
+ </clipPath>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath42711-8-6">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
+ id="rect42713-6-8"
+ width="8.7252884"
+ height="17.464855"
+ x="127.4093"
+ y="214.76154" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43050-6-3-1">
+ <rect
+ y="-122"
+ x="-24"
+ height="14"
+ width="16"
+ id="rect43052-3-0-7"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.5;fill:url(#linearGradient43054-6);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask48816-8-2-1">
+ <rect
+ y="-84"
+ x="-44"
+ height="14"
+ width="13"
+ id="rect48818-4-9-3"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.85;fill:url(#radialGradient48820-9-2-1);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;marker:none;enable-background:new" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient48820-9-2-1"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,1.0769231,0,5.9230769)"
+ cx="-31"
+ cy="-83.5"
+ fx="-31"
+ fy="-83.5"
+ r="6.5" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask55618">
+ <rect
+ y="-84"
+ x="-44"
+ height="14"
+ width="13"
+ id="rect55616"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.85;fill:url(#radialGradient48820-9-2-1);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;marker:none;enable-background:new" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient55620"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,1.0769231,0,5.9230769)"
+ cx="-31"
+ cy="-83.5"
+ fx="-31"
+ fy="-83.5"
+ r="6.5" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask28585-8-0-2">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.85;fill:url(#radialGradient28589-9-2-0);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;marker:none;enable-background:new"
+ id="rect28587-2-1-4"
+ width="13"
+ height="14"
+ x="-44"
+ y="-84" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient28589-9-2-0"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,1.0769231,0,5.9230769)"
+ cx="-30.28125"
+ cy="-84.341515"
+ fx="-30.28125"
+ fy="-84.341515"
+ r="6.5" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43040-7-4-4">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.5;fill:url(#linearGradient43044-5);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
+ id="rect43042-9-7-6"
+ width="15"
+ height="16"
+ x="-45.04018"
+ y="-24"
+ rx="0"
+ ry="0" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask45865-7-8-2">
+ <g
+ id="g45867-3-2-8"
+ transform="translate(-14)">
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cssssssc"
+ id="path45869-7-4-7"
+ d="m -25.801826,-135.3217 c -0.907684,-0.32824 -0.906457,-1.55361 -0.440107,-2.23642 0.834186,-1.22138 2.593738,-1.15244 3.63669,-0.26277 1.530569,1.30563 1.388406,3.6923 0.08107,5.09763 -1.742467,1.8731 -4.73519,1.65156 -6.47424,-0.0993 -2.188413,-2.20322 -1.889457,-5.85971 0.277965,-7.95885 2.625036,-2.54234 6.931515,-2.199 9.311783,0.46129 2.764074,3.08924 2.372937,7.82808 -0.06591,10.77438"
+ style="display:inline;fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
+ mask="none" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc"
+ id="path45871-2-6-9"
+ d="m -19.40866,-140.32008 c 2.764074,3.08924 2.372937,7.82808 -0.06591,10.77438"
+ style="display:inline;fill:none;stroke:url(#linearGradient45875-0);stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ mask="none"
+ style="display:inline;fill:none;stroke:url(#radialGradient45877-1-9-2);stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
+ d="m -25.801826,-135.3217 c -0.907684,-0.32824 -0.906457,-1.55361 -0.440107,-2.23642 0.834186,-1.22138 2.593738,-1.15244 3.63669,-0.26277"
+ id="path45873-6-5-0"
+ sodipodi:nodetypes="css" />
+ </g>
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient45877-1-9-2"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.1099414,-0.9422316,0.4519816,0.05273803,38.220416,-152.21215)"
+ cx="-25.452209"
+ cy="-136.46503"
+ fx="-25.452209"
+ fy="-136.46503"
+ r="8.0066185" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask45447-7-9-1">
+ <rect
+ ry="0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.8;fill:url(#radialGradient45451-2-8-4);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate"
+ id="rect45449-4-7-7"
+ width="15"
+ height="15"
+ x="216"
+ y="366" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient45451-2-8-4"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.9952162,167.99999,-60.91415)"
+ cx="59.000011"
+ cy="440.0191"
+ fx="59.000011"
+ fy="440.0191"
+ r="6.5080619" />
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath43135-6-7-4">
+ <path
+ inkscape:connector-curvature="0"
+ id="path43137-1-6-7"
+ d="M -46,52 -30,36 H -46 Z"
+ style="opacity:0.5;fill:#ffff00;fill-rule:evenodd;stroke:none" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43188-4-7-7">
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.5;fill:url(#linearGradient43192-3);fill-rule:evenodd;stroke:none"
+ d="M -46,52 -30,36 H -46 Z"
+ id="path43190-2-2-9" />
+ </mask>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath43178-6-7-6">
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.5;fill:#ffff00;fill-rule:evenodd;stroke:none"
+ d="m -30,36 h -1 l -15,15 v 1 h 16 z"
+ id="path43180-8-7-3"
+ sodipodi:nodetypes="cccccc" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43182-5-7-1">
+ <path
+ inkscape:connector-curvature="0"
+ id="path43184-7-3-4"
+ d="m -46,52 v -1 l 15,-15 h 1 v 16 z"
+ style="opacity:0.5;fill:url(#linearGradient43186-6);fill-rule:evenodd;stroke:none"
+ sodipodi:nodetypes="cccccc" />
+ </mask>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath55878">
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.5;fill:#ffff00;fill-rule:evenodd;stroke:none"
+ d="m -30,36 h -1 l -15,15 v 1 h 16 z"
+ id="path55876"
+ sodipodi:nodetypes="cccccc" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask55882">
+ <path
+ inkscape:connector-curvature="0"
+ id="path55880"
+ d="m -46,52 v -1 l 15,-15 h 1 v 16 z"
+ style="opacity:0.5;fill:url(#linearGradient43186-6);fill-rule:evenodd;stroke:none"
+ sodipodi:nodetypes="cccccc" />
+ </mask>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath55894">
+ <path
+ inkscape:connector-curvature="0"
+ id="path55892"
+ d="M -46,52 -30,36 H -46 Z"
+ style="opacity:0.5;fill:#ffff00;fill-rule:evenodd;stroke:none" />
+ </clipPath>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask55898">
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.5;fill:url(#linearGradient43192-3);fill-rule:evenodd;stroke:none"
+ d="M -46,52 -30,36 H -46 Z"
+ id="path55896" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask25021-4-6-2">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient25025-8-0-1);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.70000005;marker:none;enable-background:accumulate"
+ id="rect25023-8-6-4"
+ width="13"
+ height="14"
+ x="26"
+ y="243" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient25025-8-0-1"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.8918342,0,0,0.8918344,-15.699877,27.900732)"
+ cx="49"
+ cy="254.64285"
+ fx="49"
+ fy="254.64285"
+ r="6.5" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask52637-8-8-5-0">
+ <rect
+ mask="none"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient52641-2-8-6-3);fill-opacity:1;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
+ id="rect52639-8-9-0-4"
+ width="7.9918551"
+ height="8.9366941"
+ x="-354"
+ y="458"
+ rx="0"
+ ry="0" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient52641-2-8-6-3"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.39420438,-0.08239205,0.27256031,1.3040635,-361.27885,-161.73915)"
+ cx="-302.79681"
+ cy="462.0358"
+ fx="-302.79681"
+ fy="462.0358"
+ r="8" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask52879-0-5-1-2">
+ <rect
+ mask="none"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient52883-6-8-3-0);fill-opacity:1;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
+ id="rect52881-7-3-3-5"
+ width="7.9918551"
+ height="8.9366941"
+ x="-354.95001"
+ y="458"
+ rx="0"
+ ry="0" />
+ </mask>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient52883-6-8-3-0"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.39420438,-0.08239205,0.27256031,1.3040635,-362.22886,-161.73912)"
+ cx="-302.79681"
+ cy="462.0358"
+ fx="-302.79681"
+ fy="462.0358"
+ r="8" />
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask20957-5-3">
+ <rect
+ y="101"
+ x="162"
+ height="5"
+ width="8"
+ id="rect20959-8-5"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient20961);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.29999995;marker:none;enable-background:accumulate" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask32294-8-1">
+ <rect
+ y="323"
+ x="134"
+ height="16"
+ width="9"
+ id="rect32296-9-9"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient32298);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask57450-1-2">
+ <rect
+ y="154.99899"
+ x="326.00305"
+ height="15"
+ width="15"
+ id="rect57452-3-0"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient57454);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43822-7-6-3">
+ <rect
+ y="208"
+ x="754"
+ height="9"
+ width="12"
+ id="rect43824-6-2-8"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.93999993;fill:url(#linearGradient43826);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:new" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask43822-5-0">
+ <rect
+ y="208"
+ x="754"
+ height="9"
+ width="12"
+ id="rect43824-61-1"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.93999993;fill:url(#linearGradient43826);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:new" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask38956-7-3">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient38961);stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
+ id="rect38958-9-4"
+ width="16"
+ height="12"
+ x="488"
+ y="560"
+ rx="0"
+ ry="0" />
+ </mask>
+ <mask
+ maskUnits="userSpaceOnUse"
+ id="mask20957-7-5">
+ <rect
+ y="101"
+ x="162"
+ height="5"
+ width="8"
+ id="rect20959-85-8"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient20961);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.29999995;marker:none;enable-background:accumulate" />
+ </mask>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="linearGradient34189-1"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.695652,0,0,0.869703,170.06515,482.33642)"
+ x1="188.77448"
+ y1="259.745"
+ x2="164.0939"
+ y2="242.22473" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11146"
+ id="linearGradient34191-9"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(572.00001,970)"
+ x1="-287.75"
+ y1="-276.75"
+ x2="-276"
+ y2="-264.875" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="linearGradient40879-9-8-1-3"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.608695,0,0,0.760996,188.8695,512.23032)"
+ x1="130.70929"
+ y1="210.78392"
+ x2="171.50414"
+ y2="248.54021" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11146"
+ id="linearGradient34193-9"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(576.00001,973)"
+ x1="-283"
+ y1="-272"
+ x2="-277.01501"
+ y2="-267.26749" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient18495"
+ id="radialGradient40883-4-0-3-9"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.06118084,-0.8594818,2.4629674,-0.1753088,-44.40057,787.15309)"
+ cx="77.721619"
+ cy="104.09358"
+ fx="77.721619"
+ fy="104.09358"
+ r="3.9999998" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient24562"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0474269,0.00526965,-0.00503098,0.9999873,209.98584,104.8287)"
+ cx="27.411026"
+ cy="255.58899"
+ fx="27.411026"
+ fy="255.58899"
+ r="5.9250002" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient22563"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0474269,0.00526965,-0.00503098,0.9999873,209.98584,104.8287)"
+ cx="27.411026"
+ cy="255.58899"
+ fx="27.411026"
+ fy="255.58899"
+ r="5.9250002" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="radialGradient22577"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0474269,0.00526965,-0.00503098,0.9999873,209.98584,104.8287)"
+ cx="27.411026"
+ cy="255.58899"
+ fx="27.411026"
+ fy="255.58899"
+ r="5.9250002" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11146"
+ id="linearGradient22732-4"
+ gradientUnits="userSpaceOnUse"
+ x1="496.49335"
+ y1="537.78113"
+ x2="498.40021"
+ y2="540.13623"
+ gradientTransform="translate(42.000001,63)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11146"
+ id="linearGradient22781"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.99999997,0,0,0.99999996,-2.7720701e-6,20.999999)"
+ x1="496.49335"
+ y1="537.78113"
+ x2="498.40021"
+ y2="540.13623" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11146"
+ id="linearGradient22785"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(21,42)"
+ x1="496.49335"
+ y1="537.78113"
+ x2="498.40021"
+ y2="540.13623" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11146"
+ id="linearGradient22785-7"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(21,42)"
+ x1="496.49335"
+ y1="537.78113"
+ x2="498.40021"
+ y2="540.13623" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11146"
+ id="linearGradient22939"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(21,42)"
+ x1="496.49335"
+ y1="537.78113"
+ x2="498.40021"
+ y2="540.13623" />
+ <pattern
+ y="0"
+ x="0"
+ height="6"
+ width="6"
+ patternUnits="userSpaceOnUse"
+ id="EMFhbasepattern-9" />
</defs>
-
-
- <path style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#1a1a1a;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="path23417" sodipodi:nodetypes="cc" d=""/>
- <path style="fill:none;stroke:#ffffff;stroke-width:1.79999995;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" id="path23347" sodipodi:nodetypes="cc" d=""/>
- <g inkscape:groupmode="layer" id="layer5" inkscape:label="grid" style="display:inline;opacity:0.3" sodipodi:insensitive="true">
- <g id="g40174" transform="translate(0,2)">
- <g id="g22995">
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect22955" width="1" height="7" x="422" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="401" height="7" width="1" id="rect22957" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect22959" width="1" height="7" x="380" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="359" height="7" width="1" id="rect22961" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect22963" width="1" height="7" x="338" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="317" height="7" width="1" id="rect22965" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect22967" width="1" height="7" x="296" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="275" height="7" width="1" id="rect22969" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect22971" width="1" height="7" x="254" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="233" height="7" width="1" id="rect22973" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect22975" width="1" height="7" x="212" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="191" height="7" width="1" id="rect22977" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect22979" width="1" height="7" x="170" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="149" height="7" width="1" id="rect22981" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect22983" width="1" height="7" x="128" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="107" height="7" width="1" id="rect22985" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect22987" width="1" height="7" x="86" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="65" height="7" width="1" id="rect22989" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect22991" width="1" height="7" x="44" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="23" height="7" width="1" id="rect22993" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect ry="0" rx="0" y="0" x="506" height="7" width="1" id="rect23024" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect23026" width="1" height="7" x="485" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="464" height="7" width="1" id="rect23028" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect23030" width="1" height="7" x="443" y="0" rx="0" ry="0"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect10985" width="1" height="7" x="527" y="0" rx="0" ry="0"/>
- </g>
- <g id="g24954">
- <g id="g23711" transform="translate(0,462)">
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect23713" width="6" height="1" x="0" y="26" rx="0" ry="0"/>
- <g id="g23715">
- <path id="path23717" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23719" inkscape:connector-curvature="0"/>
- <path id="path23721" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23723" inkscape:connector-curvature="0"/>
- <path id="path23725" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23727" inkscape:connector-curvature="0"/>
- <path id="path23729" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23731" inkscape:connector-curvature="0"/>
- <path id="path23733" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23735" inkscape:connector-curvature="0"/>
- <path id="path23737" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23739" inkscape:connector-curvature="0"/>
- <path id="path23741" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23743" inkscape:connector-curvature="0"/>
- <path id="path23745" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23747" inkscape:connector-curvature="0"/>
- <path id="path23749" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23751" inkscape:connector-curvature="0"/>
- <path id="path23753" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23755" inkscape:connector-curvature="0"/>
- <path id="path23757" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23759" inkscape:connector-curvature="0"/>
- <path id="path23761" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23763" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path10987" inkscape:connector-curvature="0"/>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#515151"
+ bordercolor="#323232"
+ borderopacity="1"
+ gridtolerance="10"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="2.8284271"
+ inkscape:cx="96.895184"
+ inkscape:cy="497.95432"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer8"
+ showgrid="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1051"
+ inkscape:window-x="-9"
+ inkscape:window-y="-9"
+ inkscape:snap-nodes="true"
+ inkscape:snap-bbox="true"
+ showguides="false"
+ inkscape:guide-bbox="true"
+ inkscape:object-nodes="true"
+ inkscape:object-paths="true"
+ inkscape:snap-intersection-line-segments="true"
+ inkscape:snap-intersection-grid-guide="false"
+ inkscape:window-maximized="1"
+ inkscape:bbox-paths="true"
+ inkscape:snap-global="true"
+ inkscape:snap-bbox-midpoints="true"
+ inkscape:snap-grids="true"
+ inkscape:snap-to-guides="true"
+ inkscape:snap-page="true"
+ units="pt"
+ inkscape:snap-center="true"
+ inkscape:snap-object-midpoints="false"
+ inkscape:snap-midpoints="true"
+ inkscape:snap-others="true"
+ inkscape:bbox-nodes="true"
+ inkscape:snap-intersection-paths="true"
+ inkscape:snap-smooth-nodes="true"
+ inkscape:measure-start="0,0"
+ inkscape:measure-end="0,0"
+ inkscape:snap-bbox-edge-midpoints="true"
+ inkscape:snap-text-baseline="false"
+ inkscape:pagecheckerboard="false"
+ inkscape:showpageshadow="true"
+ inkscape:lockguides="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid17394"
+ visible="true"
+ enabled="true"
+ spacingx="0.25"
+ spacingy="0.25"
+ empspacing="4"
+ color="#000000"
+ opacity="0.09803922"
+ dotted="false"
+ empcolor="#000000"
+ empopacity="0.25098039"
+ snapvisiblegridlinesonly="true"
+ originx="0"
+ originy="-2.7755576e-17" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Blender icons v. 2.5.08</dc:title>
+ <dc:date>21.05.2012</dc:date>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Andrzej Ambroż</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:rights>
+ <cc:Agent>
+ <dc:title>Andrzej Ambroż</dc:title>
+ </cc:Agent>
+ </dc:rights>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>Andrzej Ambroż</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:coverage />
+ <cc:license
+ rdf:resource="http://www.gnu.org/licenses/old-licenses/gpl-2.0.html" />
+ <dc:description>GNU General Public License, version 2 or later.</dc:description>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <path
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#1a1a1a;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="path23417"
+ sodipodi:nodetypes="cc"
+ d="" />
+ <path
+ style="fill:none;stroke:#ffffff;stroke-width:1.79999995;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="path23347"
+ sodipodi:nodetypes="cc"
+ d="" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer5"
+ inkscape:label="grid"
+ style="display:inline;opacity:0.3"
+ sodipodi:insensitive="true">
+ <g
+ id="g40174"
+ transform="translate(0,2)">
+ <g
+ id="g22995">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect22955"
+ width="1"
+ height="7"
+ x="422"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="401"
+ height="7"
+ width="1"
+ id="rect22957"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect22959"
+ width="1"
+ height="7"
+ x="380"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="359"
+ height="7"
+ width="1"
+ id="rect22961"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect22963"
+ width="1"
+ height="7"
+ x="338"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="317"
+ height="7"
+ width="1"
+ id="rect22965"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect22967"
+ width="1"
+ height="7"
+ x="296"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="275"
+ height="7"
+ width="1"
+ id="rect22969"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect22971"
+ width="1"
+ height="7"
+ x="254"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="233"
+ height="7"
+ width="1"
+ id="rect22973"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect22975"
+ width="1"
+ height="7"
+ x="212"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="191"
+ height="7"
+ width="1"
+ id="rect22977"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect22979"
+ width="1"
+ height="7"
+ x="170"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="149"
+ height="7"
+ width="1"
+ id="rect22981"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect22983"
+ width="1"
+ height="7"
+ x="128"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="107"
+ height="7"
+ width="1"
+ id="rect22985"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect22987"
+ width="1"
+ height="7"
+ x="86"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="65"
+ height="7"
+ width="1"
+ id="rect22989"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect22991"
+ width="1"
+ height="7"
+ x="44"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="23"
+ height="7"
+ width="1"
+ id="rect22993"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="506"
+ height="7"
+ width="1"
+ id="rect23024"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect23026"
+ width="1"
+ height="7"
+ x="485"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="464"
+ height="7"
+ width="1"
+ id="rect23028"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect23030"
+ width="1"
+ height="7"
+ x="443"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect10985"
+ width="1"
+ height="7"
+ x="527"
+ y="0"
+ rx="0"
+ ry="0" />
+ </g>
+ <g
+ id="g24954">
+ <g
+ id="g23711"
+ transform="translate(0,462)">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect23713"
+ width="6"
+ height="1"
+ x="0"
+ y="26"
+ rx="0"
+ ry="0" />
+ <g
+ id="g23715">
+ <path
+ id="path23717"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23719"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23721"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23723"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23725"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23727"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23729"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23731"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23733"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23735"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23737"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23739"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23741"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23743"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23745"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23747"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23749"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23751"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23753"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23755"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23757"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23759"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23761"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23763"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path10987"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g23765" transform="translate(0,441)">
- <rect ry="0" rx="0" y="26" x="0" height="1" width="6" id="rect23767" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <g id="g23769">
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23771" inkscape:connector-curvature="0"/>
- <path id="path23773" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23775" inkscape:connector-curvature="0"/>
- <path id="path23777" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23779" inkscape:connector-curvature="0"/>
- <path id="path23781" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23783" inkscape:connector-curvature="0"/>
- <path id="path23785" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23787" inkscape:connector-curvature="0"/>
- <path id="path23789" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23791" inkscape:connector-curvature="0"/>
- <path id="path23793" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23795" inkscape:connector-curvature="0"/>
- <path id="path23797" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23799" inkscape:connector-curvature="0"/>
- <path id="path23801" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23803" inkscape:connector-curvature="0"/>
- <path id="path23805" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23807" inkscape:connector-curvature="0"/>
- <path id="path23809" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23811" inkscape:connector-curvature="0"/>
- <path id="path23813" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23815" inkscape:connector-curvature="0"/>
- <path id="path23817" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10990" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
+ <g
+ id="g23765"
+ transform="translate(0,441)">
+ <rect
+ ry="0"
+ rx="0"
+ y="26"
+ x="0"
+ height="1"
+ width="6"
+ id="rect23767"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <g
+ id="g23769">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23771"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23773"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23775"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23777"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23779"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23781"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23783"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23785"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23787"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23789"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23791"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23793"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23795"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23797"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23799"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23801"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23803"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23805"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23807"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23809"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23811"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23813"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23815"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23817"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10990"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g23819" transform="translate(0,420)">
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect23821" width="6" height="1" x="0" y="26" rx="0" ry="0"/>
- <g id="g23823">
- <path id="path23825" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23827" inkscape:connector-curvature="0"/>
- <path id="path23829" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23831" inkscape:connector-curvature="0"/>
- <path id="path23833" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23835" inkscape:connector-curvature="0"/>
- <path id="path23837" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23839" inkscape:connector-curvature="0"/>
- <path id="path23841" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23843" inkscape:connector-curvature="0"/>
- <path id="path23845" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23847" inkscape:connector-curvature="0"/>
- <path id="path23849" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23851" inkscape:connector-curvature="0"/>
- <path id="path23853" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23855" inkscape:connector-curvature="0"/>
- <path id="path23857" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23859" inkscape:connector-curvature="0"/>
- <path id="path23861" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23863" inkscape:connector-curvature="0"/>
- <path id="path23865" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23867" inkscape:connector-curvature="0"/>
- <path id="path23869" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23871" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path10992" inkscape:connector-curvature="0"/>
+ <g
+ id="g23819"
+ transform="translate(0,420)">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect23821"
+ width="6"
+ height="1"
+ x="0"
+ y="26"
+ rx="0"
+ ry="0" />
+ <g
+ id="g23823">
+ <path
+ id="path23825"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23827"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23829"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23831"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23833"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23835"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23837"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23839"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23841"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23843"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23845"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23847"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23849"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23851"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23853"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23855"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23857"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23859"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23861"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23863"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23865"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23867"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23869"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23871"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path10992"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g23873" transform="translate(0,399)">
- <rect ry="0" rx="0" y="26" x="0" height="1" width="6" id="rect23875" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <g id="g23877">
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23879" inkscape:connector-curvature="0"/>
- <path id="path23881" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23883" inkscape:connector-curvature="0"/>
- <path id="path23885" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23887" inkscape:connector-curvature="0"/>
- <path id="path23889" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23891" inkscape:connector-curvature="0"/>
- <path id="path23893" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23895" inkscape:connector-curvature="0"/>
- <path id="path23897" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23899" inkscape:connector-curvature="0"/>
- <path id="path23901" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23903" inkscape:connector-curvature="0"/>
- <path id="path23905" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23907" inkscape:connector-curvature="0"/>
- <path id="path23909" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23911" inkscape:connector-curvature="0"/>
- <path id="path23913" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23915" inkscape:connector-curvature="0"/>
- <path id="path23917" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23919" inkscape:connector-curvature="0"/>
- <path id="path23921" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23923" inkscape:connector-curvature="0"/>
- <path id="path23925" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10994" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
+ <g
+ id="g23873"
+ transform="translate(0,399)">
+ <rect
+ ry="0"
+ rx="0"
+ y="26"
+ x="0"
+ height="1"
+ width="6"
+ id="rect23875"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <g
+ id="g23877">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23879"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23881"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23883"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23885"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23887"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23889"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23891"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23893"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23895"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23897"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23899"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23901"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23903"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23905"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23907"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23909"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23911"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23913"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23915"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23917"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23919"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23921"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23923"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23925"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10994"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g23927" transform="translate(0,378)">
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect23929" width="6" height="1" x="0" y="26" rx="0" ry="0"/>
- <g id="g23931">
- <path id="path23933" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23935" inkscape:connector-curvature="0"/>
- <path id="path23937" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23939" inkscape:connector-curvature="0"/>
- <path id="path23941" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23943" inkscape:connector-curvature="0"/>
- <path id="path23945" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23947" inkscape:connector-curvature="0"/>
- <path id="path23949" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23951" inkscape:connector-curvature="0"/>
- <path id="path23953" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23955" inkscape:connector-curvature="0"/>
- <path id="path23957" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23959" inkscape:connector-curvature="0"/>
- <path id="path23961" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23963" inkscape:connector-curvature="0"/>
- <path id="path23965" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23967" inkscape:connector-curvature="0"/>
- <path id="path23969" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23971" inkscape:connector-curvature="0"/>
- <path id="path23973" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23975" inkscape:connector-curvature="0"/>
- <path id="path23977" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23979" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path10996" inkscape:connector-curvature="0"/>
+ <g
+ id="g23927"
+ transform="translate(0,378)">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect23929"
+ width="6"
+ height="1"
+ x="0"
+ y="26"
+ rx="0"
+ ry="0" />
+ <g
+ id="g23931">
+ <path
+ id="path23933"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23935"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23937"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23939"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23941"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23943"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23945"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23947"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23949"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23951"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23953"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23955"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23957"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23959"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23961"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23963"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23965"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23967"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23969"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23971"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23973"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23975"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23977"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23979"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path10996"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g23981" transform="translate(0,357)">
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect23983" width="6" height="1" x="0" y="26" rx="0" ry="0"/>
- <g id="g23985">
- <path id="path23987" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23989" inkscape:connector-curvature="0"/>
- <path id="path23991" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23993" inkscape:connector-curvature="0"/>
- <path id="path23995" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path23997" inkscape:connector-curvature="0"/>
- <path id="path23999" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24001" inkscape:connector-curvature="0"/>
- <path id="path24003" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24005" inkscape:connector-curvature="0"/>
- <path id="path24007" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24009" inkscape:connector-curvature="0"/>
- <path id="path24011" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24013" inkscape:connector-curvature="0"/>
- <path id="path24015" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24017" inkscape:connector-curvature="0"/>
- <path id="path24019" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24021" inkscape:connector-curvature="0"/>
- <path id="path24023" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24025" inkscape:connector-curvature="0"/>
- <path id="path24027" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24029" inkscape:connector-curvature="0"/>
- <path id="path24031" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24033" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path10998" inkscape:connector-curvature="0"/>
+ <g
+ id="g23981"
+ transform="translate(0,357)">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect23983"
+ width="6"
+ height="1"
+ x="0"
+ y="26"
+ rx="0"
+ ry="0" />
+ <g
+ id="g23985">
+ <path
+ id="path23987"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23989"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23991"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23993"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23995"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path23997"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path23999"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24001"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24003"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24005"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24007"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24009"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24011"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24013"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24015"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24017"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24019"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24021"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24023"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24025"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24027"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24029"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24031"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24033"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path10998"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g24035" transform="translate(0,336)">
- <rect ry="0" rx="0" y="26" x="0" height="1" width="6" id="rect24037" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <g id="g24039">
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24041" inkscape:connector-curvature="0"/>
- <path id="path24043" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24045" inkscape:connector-curvature="0"/>
- <path id="path24047" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24049" inkscape:connector-curvature="0"/>
- <path id="path24051" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24053" inkscape:connector-curvature="0"/>
- <path id="path24055" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24057" inkscape:connector-curvature="0"/>
- <path id="path24059" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24061" inkscape:connector-curvature="0"/>
- <path id="path24063" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24065" inkscape:connector-curvature="0"/>
- <path id="path24067" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24069" inkscape:connector-curvature="0"/>
- <path id="path24071" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24073" inkscape:connector-curvature="0"/>
- <path id="path24075" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24077" inkscape:connector-curvature="0"/>
- <path id="path24079" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24081" inkscape:connector-curvature="0"/>
- <path id="path24083" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24085" inkscape:connector-curvature="0"/>
- <path id="path24087" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path11000" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
+ <g
+ id="g24035"
+ transform="translate(0,336)">
+ <rect
+ ry="0"
+ rx="0"
+ y="26"
+ x="0"
+ height="1"
+ width="6"
+ id="rect24037"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <g
+ id="g24039">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24041"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24043"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24045"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24047"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24049"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24051"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24053"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24055"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24057"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24059"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24061"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24063"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24065"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24067"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24069"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24071"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24073"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24075"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24077"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24079"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24081"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24083"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24085"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24087"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path11000"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g24089" transform="translate(0,315)">
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect24091" width="6" height="1" x="0" y="26" rx="0" ry="0"/>
- <g id="g24093">
- <path id="path24095" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24097" inkscape:connector-curvature="0"/>
- <path id="path24099" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24101" inkscape:connector-curvature="0"/>
- <path id="path24103" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24105" inkscape:connector-curvature="0"/>
- <path id="path24107" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24109" inkscape:connector-curvature="0"/>
- <path id="path24111" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24113" inkscape:connector-curvature="0"/>
- <path id="path24115" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24117" inkscape:connector-curvature="0"/>
- <path id="path24119" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24121" inkscape:connector-curvature="0"/>
- <path id="path24123" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24125" inkscape:connector-curvature="0"/>
- <path id="path24127" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24129" inkscape:connector-curvature="0"/>
- <path id="path24131" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24133" inkscape:connector-curvature="0"/>
- <path id="path24135" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24137" inkscape:connector-curvature="0"/>
- <path id="path24139" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24141" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path11002" inkscape:connector-curvature="0"/>
+ <g
+ id="g24089"
+ transform="translate(0,315)">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect24091"
+ width="6"
+ height="1"
+ x="0"
+ y="26"
+ rx="0"
+ ry="0" />
+ <g
+ id="g24093">
+ <path
+ id="path24095"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24097"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24099"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24101"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24103"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24105"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24107"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24109"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24111"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24113"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24115"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24117"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24119"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24121"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24123"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24125"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24127"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24129"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24131"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24133"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24135"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24137"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24139"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24141"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path11002"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g24143" transform="translate(0,294)">
- <rect ry="0" rx="0" y="26" x="0" height="1" width="6" id="rect24145" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <g id="g24147">
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24149" inkscape:connector-curvature="0"/>
- <path id="path24151" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24153" inkscape:connector-curvature="0"/>
- <path id="path24155" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24157" inkscape:connector-curvature="0"/>
- <path id="path24159" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24161" inkscape:connector-curvature="0"/>
- <path id="path24163" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24165" inkscape:connector-curvature="0"/>
- <path id="path24167" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24169" inkscape:connector-curvature="0"/>
- <path id="path24171" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24173" inkscape:connector-curvature="0"/>
- <path id="path24175" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24177" inkscape:connector-curvature="0"/>
- <path id="path24179" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24181" inkscape:connector-curvature="0"/>
- <path id="path24183" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24185" inkscape:connector-curvature="0"/>
- <path id="path24187" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24189" inkscape:connector-curvature="0"/>
- <path id="path24191" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24193" inkscape:connector-curvature="0"/>
- <path id="path24195" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path11004" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
+ <g
+ id="g24143"
+ transform="translate(0,294)">
+ <rect
+ ry="0"
+ rx="0"
+ y="26"
+ x="0"
+ height="1"
+ width="6"
+ id="rect24145"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <g
+ id="g24147">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24149"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24151"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24153"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24155"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24157"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24159"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24161"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24163"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24165"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24167"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24169"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24171"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24173"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24175"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24177"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24179"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24181"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24183"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24185"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24187"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24189"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24191"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24193"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24195"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path11004"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g24197" transform="translate(0,273)">
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect24199" width="6" height="1" x="0" y="26" rx="0" ry="0"/>
- <g id="g24201">
- <path id="path24203" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24205" inkscape:connector-curvature="0"/>
- <path id="path24207" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24209" inkscape:connector-curvature="0"/>
- <path id="path24211" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24213" inkscape:connector-curvature="0"/>
- <path id="path24215" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24217" inkscape:connector-curvature="0"/>
- <path id="path24219" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24221" inkscape:connector-curvature="0"/>
- <path id="path24223" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24225" inkscape:connector-curvature="0"/>
- <path id="path24227" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24229" inkscape:connector-curvature="0"/>
- <path id="path24231" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24233" inkscape:connector-curvature="0"/>
- <path id="path24235" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24237" inkscape:connector-curvature="0"/>
- <path id="path24239" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24241" inkscape:connector-curvature="0"/>
- <path id="path24243" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24245" inkscape:connector-curvature="0"/>
- <path id="path24247" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24249" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path11006" inkscape:connector-curvature="0"/>
+ <g
+ id="g24197"
+ transform="translate(0,273)">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect24199"
+ width="6"
+ height="1"
+ x="0"
+ y="26"
+ rx="0"
+ ry="0" />
+ <g
+ id="g24201">
+ <path
+ id="path24203"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24205"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24207"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24209"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24211"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24213"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24215"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24217"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24219"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24221"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24223"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24225"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24227"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24229"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24231"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24233"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24235"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24237"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24239"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24241"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24243"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24245"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24247"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24249"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path11006"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g24251" transform="translate(0,252)">
- <rect ry="0" rx="0" y="26" x="0" height="1" width="6" id="rect24253" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <g id="g24255">
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24257" inkscape:connector-curvature="0"/>
- <path id="path24259" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24261" inkscape:connector-curvature="0"/>
- <path id="path24263" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24265" inkscape:connector-curvature="0"/>
- <path id="path24267" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24269" inkscape:connector-curvature="0"/>
- <path id="path24271" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24273" inkscape:connector-curvature="0"/>
- <path id="path24275" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24277" inkscape:connector-curvature="0"/>
- <path id="path24279" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24281" inkscape:connector-curvature="0"/>
- <path id="path24283" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24285" inkscape:connector-curvature="0"/>
- <path id="path24287" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24289" inkscape:connector-curvature="0"/>
- <path id="path24291" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24293" inkscape:connector-curvature="0"/>
- <path id="path24295" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24297" inkscape:connector-curvature="0"/>
- <path id="path24299" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24301" inkscape:connector-curvature="0"/>
- <path id="path24303" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path11008" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
+ <g
+ id="g24251"
+ transform="translate(0,252)">
+ <rect
+ ry="0"
+ rx="0"
+ y="26"
+ x="0"
+ height="1"
+ width="6"
+ id="rect24253"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <g
+ id="g24255">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24257"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24259"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24261"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24263"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24265"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24267"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24269"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24271"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24273"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24275"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24277"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24279"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24281"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24283"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24285"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24287"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24289"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24291"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24293"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24295"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24297"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24299"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24301"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24303"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path11008"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g24305" transform="translate(0,231)">
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect24307" width="6" height="1" x="0" y="26" rx="0" ry="0"/>
- <g id="g24309">
- <path id="path24311" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24313" inkscape:connector-curvature="0"/>
- <path id="path24315" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24317" inkscape:connector-curvature="0"/>
- <path id="path24319" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24321" inkscape:connector-curvature="0"/>
- <path id="path24323" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24325" inkscape:connector-curvature="0"/>
- <path id="path24327" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24329" inkscape:connector-curvature="0"/>
- <path id="path24331" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24333" inkscape:connector-curvature="0"/>
- <path id="path24335" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24337" inkscape:connector-curvature="0"/>
- <path id="path24339" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24341" inkscape:connector-curvature="0"/>
- <path id="path24343" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24345" inkscape:connector-curvature="0"/>
- <path id="path24347" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24349" inkscape:connector-curvature="0"/>
- <path id="path24351" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24353" inkscape:connector-curvature="0"/>
- <path id="path24355" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24357" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path11010" inkscape:connector-curvature="0"/>
+ <g
+ id="g24305"
+ transform="translate(0,231)">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect24307"
+ width="6"
+ height="1"
+ x="0"
+ y="26"
+ rx="0"
+ ry="0" />
+ <g
+ id="g24309">
+ <path
+ id="path24311"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24313"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24315"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24317"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24319"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24321"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24323"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24325"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24327"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24329"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24331"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24333"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24335"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24337"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24339"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24341"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24343"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24345"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24347"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24349"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24351"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24353"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24355"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24357"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path11010"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g24359" transform="translate(0,210)">
- <rect ry="0" rx="0" y="26" x="0" height="1" width="6" id="rect24361" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <g id="g24363">
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24365" inkscape:connector-curvature="0"/>
- <path id="path24367" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24369" inkscape:connector-curvature="0"/>
- <path id="path24371" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24373" inkscape:connector-curvature="0"/>
- <path id="path24375" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24377" inkscape:connector-curvature="0"/>
- <path id="path24379" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24381" inkscape:connector-curvature="0"/>
- <path id="path24383" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24385" inkscape:connector-curvature="0"/>
- <path id="path24387" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24389" inkscape:connector-curvature="0"/>
- <path id="path24391" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24393" inkscape:connector-curvature="0"/>
- <path id="path24395" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24397" inkscape:connector-curvature="0"/>
- <path id="path24399" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24401" inkscape:connector-curvature="0"/>
- <path id="path24403" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24405" inkscape:connector-curvature="0"/>
- <path id="path24407" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24409" inkscape:connector-curvature="0"/>
- <path id="path24411" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path11012" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
+ <g
+ id="g24359"
+ transform="translate(0,210)">
+ <rect
+ ry="0"
+ rx="0"
+ y="26"
+ x="0"
+ height="1"
+ width="6"
+ id="rect24361"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <g
+ id="g24363">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24365"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24367"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24369"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24371"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24373"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24375"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24377"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24379"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24381"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24383"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24385"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24387"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24389"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24391"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24393"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24395"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24397"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24399"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24401"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24403"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24405"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24407"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24409"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24411"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path11012"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g24413" transform="translate(0,189)">
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect24415" width="6" height="1" x="0" y="26" rx="0" ry="0"/>
- <g id="g24417">
- <path id="path24419" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24421" inkscape:connector-curvature="0"/>
- <path id="path24423" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24425" inkscape:connector-curvature="0"/>
- <path id="path24427" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24429" inkscape:connector-curvature="0"/>
- <path id="path24431" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24433" inkscape:connector-curvature="0"/>
- <path id="path24435" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24437" inkscape:connector-curvature="0"/>
- <path id="path24439" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24441" inkscape:connector-curvature="0"/>
- <path id="path24443" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24445" inkscape:connector-curvature="0"/>
- <path id="path24447" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24449" inkscape:connector-curvature="0"/>
- <path id="path24451" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24453" inkscape:connector-curvature="0"/>
- <path id="path24455" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24457" inkscape:connector-curvature="0"/>
- <path id="path24459" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24461" inkscape:connector-curvature="0"/>
- <path id="path24463" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24465" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path11014" inkscape:connector-curvature="0"/>
+ <g
+ id="g24413"
+ transform="translate(0,189)">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect24415"
+ width="6"
+ height="1"
+ x="0"
+ y="26"
+ rx="0"
+ ry="0" />
+ <g
+ id="g24417">
+ <path
+ id="path24419"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24421"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24423"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24425"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24427"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24429"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24431"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24433"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24435"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24437"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24439"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24441"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24443"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24445"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24447"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24449"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24451"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24453"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24455"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24457"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24459"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24461"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24463"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24465"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path11014"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g24467" transform="translate(0,168)">
- <rect ry="0" rx="0" y="26" x="0" height="1" width="6" id="rect24469" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <g id="g24471">
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24473" inkscape:connector-curvature="0"/>
- <path id="path24475" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24477" inkscape:connector-curvature="0"/>
- <path id="path24479" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24481" inkscape:connector-curvature="0"/>
- <path id="path24483" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24485" inkscape:connector-curvature="0"/>
- <path id="path24487" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24489" inkscape:connector-curvature="0"/>
- <path id="path24491" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24493" inkscape:connector-curvature="0"/>
- <path id="path24495" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24497" inkscape:connector-curvature="0"/>
- <path id="path24499" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24501" inkscape:connector-curvature="0"/>
- <path id="path24503" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24505" inkscape:connector-curvature="0"/>
- <path id="path24507" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24509" inkscape:connector-curvature="0"/>
- <path id="path24511" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24513" inkscape:connector-curvature="0"/>
- <path id="path24515" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24517" inkscape:connector-curvature="0"/>
- <path id="path24519" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path11016" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
+ <g
+ id="g24467"
+ transform="translate(0,168)">
+ <rect
+ ry="0"
+ rx="0"
+ y="26"
+ x="0"
+ height="1"
+ width="6"
+ id="rect24469"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <g
+ id="g24471">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24473"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24475"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24477"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24479"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24481"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24483"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24485"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24487"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24489"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24491"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24493"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24495"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24497"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24499"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24501"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24503"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24505"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24507"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24509"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24511"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24513"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24515"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24517"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24519"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path11016"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g24521" transform="translate(0,147)">
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect24523" width="6" height="1" x="0" y="26" rx="0" ry="0"/>
- <g id="g24525">
- <path id="path24527" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24529" inkscape:connector-curvature="0"/>
- <path id="path24531" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24533" inkscape:connector-curvature="0"/>
- <path id="path24535" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24537" inkscape:connector-curvature="0"/>
- <path id="path24539" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24541" inkscape:connector-curvature="0"/>
- <path id="path24543" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24545" inkscape:connector-curvature="0"/>
- <path id="path24547" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24549" inkscape:connector-curvature="0"/>
- <path id="path24551" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24553" inkscape:connector-curvature="0"/>
- <path id="path24555" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24557" inkscape:connector-curvature="0"/>
- <path id="path24559" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24561" inkscape:connector-curvature="0"/>
- <path id="path24563" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24565" inkscape:connector-curvature="0"/>
- <path id="path24567" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24569" inkscape:connector-curvature="0"/>
- <path id="path24571" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24573" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path11018" inkscape:connector-curvature="0"/>
+ <g
+ id="g24521"
+ transform="translate(0,147)">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect24523"
+ width="6"
+ height="1"
+ x="0"
+ y="26"
+ rx="0"
+ ry="0" />
+ <g
+ id="g24525">
+ <path
+ id="path24527"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24529"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24531"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24533"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24535"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24537"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24539"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24541"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24543"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24545"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24547"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24549"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24551"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24553"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24555"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24557"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24559"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24561"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24563"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24565"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24567"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24569"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24571"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24573"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path11018"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g24575" transform="translate(0,126)">
- <rect ry="0" rx="0" y="26" x="0" height="1" width="6" id="rect24577" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <g id="g24579">
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24581" inkscape:connector-curvature="0"/>
- <path id="path24583" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24585" inkscape:connector-curvature="0"/>
- <path id="path24587" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24589" inkscape:connector-curvature="0"/>
- <path id="path24591" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24593" inkscape:connector-curvature="0"/>
- <path id="path24595" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24597" inkscape:connector-curvature="0"/>
- <path id="path24599" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24601" inkscape:connector-curvature="0"/>
- <path id="path24603" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24605" inkscape:connector-curvature="0"/>
- <path id="path24607" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24609" inkscape:connector-curvature="0"/>
- <path id="path24611" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24613" inkscape:connector-curvature="0"/>
- <path id="path24615" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24617" inkscape:connector-curvature="0"/>
- <path id="path24619" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24621" inkscape:connector-curvature="0"/>
- <path id="path24623" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24625" inkscape:connector-curvature="0"/>
- <path id="path24627" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path11020" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
+ <g
+ id="g24575"
+ transform="translate(0,126)">
+ <rect
+ ry="0"
+ rx="0"
+ y="26"
+ x="0"
+ height="1"
+ width="6"
+ id="rect24577"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <g
+ id="g24579">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24581"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24583"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24585"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24587"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24589"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24591"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24593"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24595"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24597"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24599"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24601"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24603"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24605"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24607"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24609"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24611"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24613"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24615"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24617"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24619"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24621"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24623"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24625"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24627"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path11020"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g24630" transform="translate(0,105)">
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect24632" width="6" height="1" x="0" y="26" rx="0" ry="0"/>
- <g id="g24634">
- <path id="path24636" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24638" inkscape:connector-curvature="0"/>
- <path id="path24640" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24642" inkscape:connector-curvature="0"/>
- <path id="path24644" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24646" inkscape:connector-curvature="0"/>
- <path id="path24648" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24650" inkscape:connector-curvature="0"/>
- <path id="path24652" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24654" inkscape:connector-curvature="0"/>
- <path id="path24656" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24658" inkscape:connector-curvature="0"/>
- <path id="path24660" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24662" inkscape:connector-curvature="0"/>
- <path id="path24664" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24666" inkscape:connector-curvature="0"/>
- <path id="path24668" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24670" inkscape:connector-curvature="0"/>
- <path id="path24672" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24674" inkscape:connector-curvature="0"/>
- <path id="path24676" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24678" inkscape:connector-curvature="0"/>
- <path id="path24680" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24682" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path11022" inkscape:connector-curvature="0"/>
+ <g
+ id="g24630"
+ transform="translate(0,105)">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect24632"
+ width="6"
+ height="1"
+ x="0"
+ y="26"
+ rx="0"
+ ry="0" />
+ <g
+ id="g24634">
+ <path
+ id="path24636"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24638"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24640"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24642"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24644"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24646"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24648"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24650"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24652"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24654"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24656"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24658"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24660"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24662"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24664"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24666"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24668"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24670"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24672"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24674"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24676"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24678"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24680"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24682"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path11022"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g24684" transform="translate(0,84)">
- <rect ry="0" rx="0" y="26" x="0" height="1" width="6" id="rect24686" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <g id="g24688">
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24690" inkscape:connector-curvature="0"/>
- <path id="path24692" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24694" inkscape:connector-curvature="0"/>
- <path id="path24696" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24698" inkscape:connector-curvature="0"/>
- <path id="path24700" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24702" inkscape:connector-curvature="0"/>
- <path id="path24704" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24706" inkscape:connector-curvature="0"/>
- <path id="path24708" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24710" inkscape:connector-curvature="0"/>
- <path id="path24712" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24714" inkscape:connector-curvature="0"/>
- <path id="path24716" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24718" inkscape:connector-curvature="0"/>
- <path id="path24720" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24722" inkscape:connector-curvature="0"/>
- <path id="path24724" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24726" inkscape:connector-curvature="0"/>
- <path id="path24728" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24730" inkscape:connector-curvature="0"/>
- <path id="path24732" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24734" inkscape:connector-curvature="0"/>
- <path id="path24736" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path11024" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
+ <g
+ id="g24684"
+ transform="translate(0,84)">
+ <rect
+ ry="0"
+ rx="0"
+ y="26"
+ x="0"
+ height="1"
+ width="6"
+ id="rect24686"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <g
+ id="g24688">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24690"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24692"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24694"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24696"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24698"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24700"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24702"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24704"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24706"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24708"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24710"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24712"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24714"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24716"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24718"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24720"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24722"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24724"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24726"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24728"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24730"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24732"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24734"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24736"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path11024"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g24738" transform="translate(0,63)">
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect24740" width="6" height="1" x="0" y="26" rx="0" ry="0"/>
- <g id="g24742">
- <path id="path24744" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24746" inkscape:connector-curvature="0"/>
- <path id="path24748" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24750" inkscape:connector-curvature="0"/>
- <path id="path24752" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24754" inkscape:connector-curvature="0"/>
- <path id="path24756" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24758" inkscape:connector-curvature="0"/>
- <path id="path24760" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24762" inkscape:connector-curvature="0"/>
- <path id="path24764" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24766" inkscape:connector-curvature="0"/>
- <path id="path24768" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24770" inkscape:connector-curvature="0"/>
- <path id="path24772" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24774" inkscape:connector-curvature="0"/>
- <path id="path24776" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24778" inkscape:connector-curvature="0"/>
- <path id="path24780" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24782" inkscape:connector-curvature="0"/>
- <path id="path24784" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24786" inkscape:connector-curvature="0"/>
- <path id="path24788" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24790" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path11026" inkscape:connector-curvature="0"/>
+ <g
+ id="g24738"
+ transform="translate(0,63)">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect24740"
+ width="6"
+ height="1"
+ x="0"
+ y="26"
+ rx="0"
+ ry="0" />
+ <g
+ id="g24742">
+ <path
+ id="path24744"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24746"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24748"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24750"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24752"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24754"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24756"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24758"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24760"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24762"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24764"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24766"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24768"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24770"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24772"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24774"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24776"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24778"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24780"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24782"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24784"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24786"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24788"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24790"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path11026"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g24792" transform="translate(0,42)">
- <rect ry="0" rx="0" y="26" x="0" height="1" width="6" id="rect24794" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <g id="g24796">
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24798" inkscape:connector-curvature="0"/>
- <path id="path24800" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24802" inkscape:connector-curvature="0"/>
- <path id="path24804" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24806" inkscape:connector-curvature="0"/>
- <path id="path24808" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24810" inkscape:connector-curvature="0"/>
- <path id="path24812" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24814" inkscape:connector-curvature="0"/>
- <path id="path24816" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24818" inkscape:connector-curvature="0"/>
- <path id="path24820" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24822" inkscape:connector-curvature="0"/>
- <path id="path24824" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24826" inkscape:connector-curvature="0"/>
- <path id="path24828" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24830" inkscape:connector-curvature="0"/>
- <path id="path24832" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24834" inkscape:connector-curvature="0"/>
- <path id="path24836" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24838" inkscape:connector-curvature="0"/>
- <path id="path24840" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24842" inkscape:connector-curvature="0"/>
- <path id="path24844" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path11028" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
+ <g
+ id="g24792"
+ transform="translate(0,42)">
+ <rect
+ ry="0"
+ rx="0"
+ y="26"
+ x="0"
+ height="1"
+ width="6"
+ id="rect24794"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <g
+ id="g24796">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24798"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24800"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24802"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24804"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24806"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24808"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24810"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24812"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24814"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24816"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24818"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24820"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24822"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24824"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24826"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24828"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24830"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24832"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24834"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24836"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24838"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24840"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24842"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24844"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path11028"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g24846" transform="translate(0,21)">
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect24848" width="6" height="1" x="0" y="26" rx="0" ry="0"/>
- <g id="g24850">
- <path id="path24852" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24854" inkscape:connector-curvature="0"/>
- <path id="path24856" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24858" inkscape:connector-curvature="0"/>
- <path id="path24860" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24862" inkscape:connector-curvature="0"/>
- <path id="path24864" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24866" inkscape:connector-curvature="0"/>
- <path id="path24868" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24870" inkscape:connector-curvature="0"/>
- <path id="path24872" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24874" inkscape:connector-curvature="0"/>
- <path id="path24876" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24878" inkscape:connector-curvature="0"/>
- <path id="path24880" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24882" inkscape:connector-curvature="0"/>
- <path id="path24884" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24886" inkscape:connector-curvature="0"/>
- <path id="path24888" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24890" inkscape:connector-curvature="0"/>
- <path id="path24892" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24894" inkscape:connector-curvature="0"/>
- <path id="path24896" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24898" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path11030" inkscape:connector-curvature="0"/>
+ <g
+ id="g24846"
+ transform="translate(0,21)">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect24848"
+ width="6"
+ height="1"
+ x="0"
+ y="26"
+ rx="0"
+ ry="0" />
+ <g
+ id="g24850">
+ <path
+ id="path24852"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24854"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24856"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24858"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24860"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24862"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24864"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24866"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24868"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24870"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24872"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24874"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24876"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24878"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24880"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24882"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24884"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24886"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24888"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24890"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24892"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24894"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24896"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24898"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path11030"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g24900">
- <rect ry="0" rx="0" y="26" x="0" height="1" width="6" id="rect24902" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <g id="g24904">
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24906" inkscape:connector-curvature="0"/>
- <path id="path24908" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24910" inkscape:connector-curvature="0"/>
- <path id="path24912" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24914" inkscape:connector-curvature="0"/>
- <path id="path24916" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24918" inkscape:connector-curvature="0"/>
- <path id="path24920" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24922" inkscape:connector-curvature="0"/>
- <path id="path24924" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24926" inkscape:connector-curvature="0"/>
- <path id="path24928" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24930" inkscape:connector-curvature="0"/>
- <path id="path24932" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24934" inkscape:connector-curvature="0"/>
- <path id="path24936" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24938" inkscape:connector-curvature="0"/>
- <path id="path24940" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24942" inkscape:connector-curvature="0"/>
- <path id="path24944" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24946" inkscape:connector-curvature="0"/>
- <path id="path24948" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path24950" inkscape:connector-curvature="0"/>
- <path id="path24952" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path11032" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
+ <g
+ id="g24900">
+ <rect
+ ry="0"
+ rx="0"
+ y="26"
+ x="0"
+ height="1"
+ width="6"
+ id="rect24902"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <g
+ id="g24904">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24906"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24908"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24910"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24912"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24914"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24916"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24918"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24920"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24922"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24924"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24926"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24928"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24930"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24932"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24934"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24936"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24938"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24940"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24942"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24944"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24946"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24948"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path24950"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24952"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path11032"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g transform="translate(0,483)" id="g39833">
- <rect ry="0" rx="0" y="26" x="0" height="1" width="6" id="rect39835" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <g id="g39837">
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39840" inkscape:connector-curvature="0"/>
- <path id="path39842" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39844" inkscape:connector-curvature="0"/>
- <path id="path39846" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39848" inkscape:connector-curvature="0"/>
- <path id="path39850" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39852" inkscape:connector-curvature="0"/>
- <path id="path39854" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39856" inkscape:connector-curvature="0"/>
- <path id="path39858" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39860" inkscape:connector-curvature="0"/>
- <path id="path39862" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39864" inkscape:connector-curvature="0"/>
- <path id="path39866" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39868" inkscape:connector-curvature="0"/>
- <path id="path39870" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39872" inkscape:connector-curvature="0"/>
- <path id="path39874" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39876" inkscape:connector-curvature="0"/>
- <path id="path39878" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39880" inkscape:connector-curvature="0"/>
- <path id="path39882" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39884" inkscape:connector-curvature="0"/>
- <path id="path39888" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path39890" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
+ <g
+ transform="translate(0,483)"
+ id="g39833">
+ <rect
+ ry="0"
+ rx="0"
+ y="26"
+ x="0"
+ height="1"
+ width="6"
+ id="rect39835"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <g
+ id="g39837">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39840"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39842"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39844"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39846"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39848"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39850"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39852"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39854"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39856"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39858"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39860"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39862"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39864"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39866"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39868"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39870"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39872"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39874"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39876"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39878"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39880"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39882"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39884"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39888"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39890"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g39892" transform="translate(0,504)">
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect39894" width="6" height="1" x="0" y="26" rx="0" ry="0"/>
- <g id="g39896">
- <path id="path39898" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39900" inkscape:connector-curvature="0"/>
- <path id="path39902" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39904" inkscape:connector-curvature="0"/>
- <path id="path39907" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39909" inkscape:connector-curvature="0"/>
- <path id="path39911" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39913" inkscape:connector-curvature="0"/>
- <path id="path39915" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39917" inkscape:connector-curvature="0"/>
- <path id="path39919" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39921" inkscape:connector-curvature="0"/>
- <path id="path39923" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39925" inkscape:connector-curvature="0"/>
- <path id="path39927" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39929" inkscape:connector-curvature="0"/>
- <path id="path39931" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39933" inkscape:connector-curvature="0"/>
- <path id="path39935" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39937" inkscape:connector-curvature="0"/>
- <path id="path39939" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39941" inkscape:connector-curvature="0"/>
- <path id="path39943" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39945" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39947" inkscape:connector-curvature="0"/>
+ <g
+ id="g39892"
+ transform="translate(0,504)">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect39894"
+ width="6"
+ height="1"
+ x="0"
+ y="26"
+ rx="0"
+ ry="0" />
+ <g
+ id="g39896">
+ <path
+ id="path39898"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39900"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39902"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39904"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39907"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39909"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39911"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39913"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39915"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39917"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39919"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39921"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39923"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39925"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39927"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39929"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39931"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39933"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39935"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39937"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39939"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39941"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39943"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39945"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39947"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g transform="translate(0,525)" id="g39949">
- <rect ry="0" rx="0" y="26" x="0" height="1" width="6" id="rect39951" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <g id="g39953">
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39955" inkscape:connector-curvature="0"/>
- <path id="path39957" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39959" inkscape:connector-curvature="0"/>
- <path id="path39961" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39963" inkscape:connector-curvature="0"/>
- <path id="path39965" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39967" inkscape:connector-curvature="0"/>
- <path id="path39969" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39971" inkscape:connector-curvature="0"/>
- <path id="path39973" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39975" inkscape:connector-curvature="0"/>
- <path id="path39977" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39979" inkscape:connector-curvature="0"/>
- <path id="path39981" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39983" inkscape:connector-curvature="0"/>
- <path id="path39985" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39987" inkscape:connector-curvature="0"/>
- <path id="path39989" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39991" inkscape:connector-curvature="0"/>
- <path id="path39993" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39995" inkscape:connector-curvature="0"/>
- <path id="path39997" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path39999" inkscape:connector-curvature="0"/>
- <path id="path40001" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path40003" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
+ <g
+ transform="translate(0,525)"
+ id="g39949">
+ <rect
+ ry="0"
+ rx="0"
+ y="26"
+ x="0"
+ height="1"
+ width="6"
+ id="rect39951"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <g
+ id="g39953">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39955"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39957"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39959"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39961"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39963"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39965"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39967"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39969"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39971"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39973"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39975"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39977"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39979"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39981"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39983"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39985"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39987"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39989"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39991"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39993"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39995"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path39997"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path39999"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40001"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40003"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g40005" transform="translate(0,546)">
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect40007" width="6" height="1" x="0" y="26" rx="0" ry="0"/>
- <g id="g40009">
- <path id="path40011" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40013" inkscape:connector-curvature="0"/>
- <path id="path40015" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40017" inkscape:connector-curvature="0"/>
- <path id="path40019" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40021" inkscape:connector-curvature="0"/>
- <path id="path40023" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40025" inkscape:connector-curvature="0"/>
- <path id="path40027" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40029" inkscape:connector-curvature="0"/>
- <path id="path40031" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40033" inkscape:connector-curvature="0"/>
- <path id="path40035" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40038" inkscape:connector-curvature="0"/>
- <path id="path40040" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40042" inkscape:connector-curvature="0"/>
- <path id="path40044" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40046" inkscape:connector-curvature="0"/>
- <path id="path40048" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40050" inkscape:connector-curvature="0"/>
- <path id="path40052" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40054" inkscape:connector-curvature="0"/>
- <path id="path40056" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40058" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40060" inkscape:connector-curvature="0"/>
+ <g
+ id="g40005"
+ transform="translate(0,546)">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect40007"
+ width="6"
+ height="1"
+ x="0"
+ y="26"
+ rx="0"
+ ry="0" />
+ <g
+ id="g40009">
+ <path
+ id="path40011"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40013"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40015"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40017"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40019"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40021"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40023"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40025"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40027"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40029"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40031"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40033"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40035"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40038"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40040"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40042"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40044"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40046"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40048"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40050"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40052"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40054"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40056"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40058"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40060"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g transform="translate(0,567)" id="g40062">
- <rect ry="0" rx="0" y="26" x="0" height="1" width="6" id="rect40064" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <g id="g40066">
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40068" inkscape:connector-curvature="0"/>
- <path id="path40070" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40072" inkscape:connector-curvature="0"/>
- <path id="path40074" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40076" inkscape:connector-curvature="0"/>
- <path id="path40078" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40080" inkscape:connector-curvature="0"/>
- <path id="path40082" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40084" inkscape:connector-curvature="0"/>
- <path id="path40086" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40088" inkscape:connector-curvature="0"/>
- <path id="path40090" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40092" inkscape:connector-curvature="0"/>
- <path id="path40094" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40096" inkscape:connector-curvature="0"/>
- <path id="path40098" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40100" inkscape:connector-curvature="0"/>
- <path id="path40102" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40104" inkscape:connector-curvature="0"/>
- <path id="path40106" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40108" inkscape:connector-curvature="0"/>
- <path id="path40110" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40112" inkscape:connector-curvature="0"/>
- <path id="path40114" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path40116" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
+ <g
+ transform="translate(0,567)"
+ id="g40062">
+ <rect
+ ry="0"
+ rx="0"
+ y="26"
+ x="0"
+ height="1"
+ width="6"
+ id="rect40064"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <g
+ id="g40066">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40068"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40070"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40072"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40074"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40076"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40078"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40080"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40082"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40084"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40086"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40088"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40090"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40092"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40094"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40096"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40098"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40100"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40102"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40104"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40106"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40108"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40110"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40112"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40114"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40116"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g40118" transform="translate(0,588)">
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect40120" width="6" height="1" x="0" y="26" rx="0" ry="0"/>
- <g id="g40122">
- <path id="path40124" d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40126" inkscape:connector-curvature="0"/>
- <path id="path40128" d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40130" inkscape:connector-curvature="0"/>
- <path id="path40132" d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40134" inkscape:connector-curvature="0"/>
- <path id="path40136" d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40138" inkscape:connector-curvature="0"/>
- <path id="path40140" d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40142" inkscape:connector-curvature="0"/>
- <path id="path40144" d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40146" inkscape:connector-curvature="0"/>
- <path id="path40148" d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40150" inkscape:connector-curvature="0"/>
- <path id="path40152" d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40154" inkscape:connector-curvature="0"/>
- <path id="path40156" d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40158" inkscape:connector-curvature="0"/>
- <path id="path40160" d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40162" inkscape:connector-curvature="0"/>
- <path id="path40164" d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40166" inkscape:connector-curvature="0"/>
- <path id="path40168" d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40170" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z" id="path40172" inkscape:connector-curvature="0"/>
+ <g
+ id="g40118"
+ transform="translate(0,588)">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect40120"
+ width="6"
+ height="1"
+ x="0"
+ y="26"
+ rx="0"
+ ry="0" />
+ <g
+ id="g40122">
+ <path
+ id="path40124"
+ d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40126"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40128"
+ d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40130"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40132"
+ d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40134"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40136"
+ d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40138"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40140"
+ d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40142"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40144"
+ d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40146"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40148"
+ d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40150"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40152"
+ d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40154"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40156"
+ d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40158"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40160"
+ d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40162"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40164"
+ d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40166"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path40168"
+ d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40170"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
+ id="path40172"
+ inkscape:connector-curvature="0" />
</g>
</g>
</g>
- <g transform="translate(0,633)" id="g25954">
- <rect ry="0" rx="0" y="0" x="422" height="7" width="1" id="rect25956" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect25958" width="1" height="7" x="401" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="380" height="7" width="1" id="rect25960" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect25962" width="1" height="7" x="359" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="338" height="7" width="1" id="rect25964" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect25966" width="1" height="7" x="317" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="296" height="7" width="1" id="rect25968" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect25970" width="1" height="7" x="275" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="254" height="7" width="1" id="rect25972" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect25974" width="1" height="7" x="233" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="212" height="7" width="1" id="rect25976" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect25978" width="1" height="7" x="191" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="170" height="7" width="1" id="rect25980" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect25982" width="1" height="7" x="149" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="128" height="7" width="1" id="rect25984" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect25986" width="1" height="7" x="107" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="86" height="7" width="1" id="rect25988" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect25990" width="1" height="7" x="65" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="44" height="7" width="1" id="rect25992" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect25994" width="1" height="7" x="23" y="0" rx="0" ry="0"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect25996" width="1" height="7" x="506" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="485" height="7" width="1" id="rect25998" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect26000" width="1" height="7" x="464" y="0" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="0" x="443" height="7" width="1" id="rect26002" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect ry="0" rx="0" y="0" x="527" height="7" width="1" id="rect11034" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- </g>
- </g>
- <g id="g30515" transform="translate(-121.95685,2)">
- <rect ry="0" rx="0" y="488" x="665.95685" height="1" width="6" id="rect26734" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect26788" width="6" height="1" x="665.95685" y="467" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="446" x="665.95685" height="1" width="6" id="rect26842" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect26896" width="6" height="1" x="665.95685" y="425" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="404" x="665.95685" height="1" width="6" id="rect26950" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect ry="0" rx="0" y="383" x="665.95685" height="1" width="6" id="rect27004" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect27058" width="6" height="1" x="665.95685" y="362" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="341" x="665.95685" height="1" width="6" id="rect27112" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect27166" width="6" height="1" x="665.95685" y="320" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="299" x="665.95685" height="1" width="6" id="rect27220" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect27274" width="6" height="1" x="665.95685" y="278" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="257" x="665.95685" height="1" width="6" id="rect27328" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect27382" width="6" height="1" x="665.95685" y="236" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="215" x="665.95685" height="1" width="6" id="rect27436" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect27490" width="6" height="1" x="665.95685" y="194" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="173" x="665.95685" height="1" width="6" id="rect27544" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect27598" width="6" height="1" x="665.95685" y="152" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="131" x="665.95685" height="1" width="6" id="rect27652" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect27706" width="6" height="1" x="665.95685" y="110" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="89" x="665.95685" height="1" width="6" id="rect27760" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect27814" width="6" height="1" x="665.95685" y="68" rx="0" ry="0"/>
- <rect ry="0" rx="0" y="47" x="665.95685" height="1" width="6" id="rect27868" style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" id="rect27922" width="6" height="1" x="665.95685" y="26" rx="0" ry="0"/>
- </g>
- <rect style="display:inline;overflow:visible;visibility:visible;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" id="rect28448" width="0" height="0" x="217.25" y="263.5"/>
+ <g
+ transform="translate(0,633)"
+ id="g25954">
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="422"
+ height="7"
+ width="1"
+ id="rect25956"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect25958"
+ width="1"
+ height="7"
+ x="401"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="380"
+ height="7"
+ width="1"
+ id="rect25960"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect25962"
+ width="1"
+ height="7"
+ x="359"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="338"
+ height="7"
+ width="1"
+ id="rect25964"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect25966"
+ width="1"
+ height="7"
+ x="317"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="296"
+ height="7"
+ width="1"
+ id="rect25968"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect25970"
+ width="1"
+ height="7"
+ x="275"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="254"
+ height="7"
+ width="1"
+ id="rect25972"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect25974"
+ width="1"
+ height="7"
+ x="233"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="212"
+ height="7"
+ width="1"
+ id="rect25976"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect25978"
+ width="1"
+ height="7"
+ x="191"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="170"
+ height="7"
+ width="1"
+ id="rect25980"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect25982"
+ width="1"
+ height="7"
+ x="149"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="128"
+ height="7"
+ width="1"
+ id="rect25984"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect25986"
+ width="1"
+ height="7"
+ x="107"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="86"
+ height="7"
+ width="1"
+ id="rect25988"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect25990"
+ width="1"
+ height="7"
+ x="65"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="44"
+ height="7"
+ width="1"
+ id="rect25992"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect25994"
+ width="1"
+ height="7"
+ x="23"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect25996"
+ width="1"
+ height="7"
+ x="506"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="485"
+ height="7"
+ width="1"
+ id="rect25998"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect26000"
+ width="1"
+ height="7"
+ x="464"
+ y="0"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="443"
+ height="7"
+ width="1"
+ id="rect26002"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ ry="0"
+ rx="0"
+ y="0"
+ x="527"
+ height="7"
+ width="1"
+ id="rect11034"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ </g>
+ </g>
+ <g
+ id="g30515"
+ transform="translate(-121.95685,2)">
+ <rect
+ ry="0"
+ rx="0"
+ y="488"
+ x="665.95685"
+ height="1"
+ width="6"
+ id="rect26734"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect26788"
+ width="6"
+ height="1"
+ x="665.95685"
+ y="467"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="446"
+ x="665.95685"
+ height="1"
+ width="6"
+ id="rect26842"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect26896"
+ width="6"
+ height="1"
+ x="665.95685"
+ y="425"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="404"
+ x="665.95685"
+ height="1"
+ width="6"
+ id="rect26950"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ ry="0"
+ rx="0"
+ y="383"
+ x="665.95685"
+ height="1"
+ width="6"
+ id="rect27004"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect27058"
+ width="6"
+ height="1"
+ x="665.95685"
+ y="362"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="341"
+ x="665.95685"
+ height="1"
+ width="6"
+ id="rect27112"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect27166"
+ width="6"
+ height="1"
+ x="665.95685"
+ y="320"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="299"
+ x="665.95685"
+ height="1"
+ width="6"
+ id="rect27220"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect27274"
+ width="6"
+ height="1"
+ x="665.95685"
+ y="278"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="257"
+ x="665.95685"
+ height="1"
+ width="6"
+ id="rect27328"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect27382"
+ width="6"
+ height="1"
+ x="665.95685"
+ y="236"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="215"
+ x="665.95685"
+ height="1"
+ width="6"
+ id="rect27436"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect27490"
+ width="6"
+ height="1"
+ x="665.95685"
+ y="194"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="173"
+ x="665.95685"
+ height="1"
+ width="6"
+ id="rect27544"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect27598"
+ width="6"
+ height="1"
+ x="665.95685"
+ y="152"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="131"
+ x="665.95685"
+ height="1"
+ width="6"
+ id="rect27652"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect27706"
+ width="6"
+ height="1"
+ x="665.95685"
+ y="110"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="89"
+ x="665.95685"
+ height="1"
+ width="6"
+ id="rect27760"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect27814"
+ width="6"
+ height="1"
+ x="665.95685"
+ y="68"
+ rx="0"
+ ry="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="47"
+ x="665.95685"
+ height="1"
+ width="6"
+ id="rect27868"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ id="rect27922"
+ width="6"
+ height="1"
+ x="665.95685"
+ y="26"
+ rx="0"
+ ry="0" />
+ </g>
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect28448"
+ width="0"
+ height="0"
+ x="217.25"
+ y="263.5" />
</g>
- <g inkscape:groupmode="layer" id="layer4" inkscape:label="sheet layout" style="display:inline" sodipodi:insensitive="true">
- <g style="display:inline;opacity:0.3;fill:#000000;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" transform="translate(21)" id="g28552-1">
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 536,14 v 0.75 h -1 v 1.5 h 1 V 17 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 16 h -1 v -1 h 1.5 v -1 z" id="path28554-7" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 539,14 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" id="path28556-4" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 544,14 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m 0,1 v 1 h 1 v -1 z m -2,-1 v -3 h -1 v 3 z" id="path28558-0" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 553,14 v 1.75 h -1 V 17 h -1 v 2 h 1 v -1.75 h 1 V 16 h 1 v -2 z" id="path28560-9" inkscape:connector-curvature="0"/>
- <rect style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" id="rect28562-4" width="1" height="1" x="548" y="18"/>
- <rect style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" id="rect28564-8" width="1" height="5" x="557" y="14"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 559,14 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z" id="path28566-8" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 565.75,14 v 1 H 565 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" id="path28568-2" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 570,14 v 0.75 h -1 v 3.5 h 1 V 19 h 2 v -1 -1.25 h -1 V 18 h -1 v -3 h 2 v -1 z" id="path28570-4" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 573,14 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" id="path28572-5" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:0.3;fill:#000000;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" transform="translate(21.98523,3)" id="g28574-5">
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 534,74 v 5 h 1 v -2 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" id="path28576-1" inkscape:connector-curvature="0"/>
- <rect style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" id="rect28578-7" width="1" height="5" x="538" y="74"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 540,74 v 5 h 1 2 v -1 h -2 v -4 z" id="path28580-1" inkscape:connector-curvature="0"/>
- <path id="path28582-1" d="m 544,74 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path28584-5" d="m 551,74 v 0.75 h -1 v 1.5 h 1 V 77 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 76 h -1 v -1 h 1.5 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path28586-2" d="m 554,74 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 558,74 v 5 h 1 2 v -1 h -2 v -4 z" id="path28588-7" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 562,74 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" id="path28590-6" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 567,74 v 0.75 h -1 v 3.5 h 1 V 79 h 2 v -1 h -2 v -3 h 2 v -1 z" id="path28592-1" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 570,74 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" id="path28594-4" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:0.3;fill:#000000;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" transform="translate(21)" id="g28596-2">
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 535,119 v 1 h 2 v 1 h 1 v -1.25 h -1 V 119 Z m 2,2 h -1 v 1 h 1 z m 0,1 v 1 h -2 v 1 h 2 v -0.75 h 1 V 122 Z" id="path28598-3" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 539,119 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 119 Z m 1,1 h 1 v 3 h -1 z" id="path28600-2" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 545,119 v 3.25 h 1 V 124 h 1 v -1.75 h 1 V 119 h -1 v 3 h -1 v -3 z" id="path28602-2" inkscape:connector-curvature="0"/>
- <rect style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" id="rect28604-1" width="1" height="5" x="549" y="119"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 551,119 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" id="path28606-6" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 555,119 v 3.25 h 1 V 124 h 1 v -1.75 h 1 V 124 h 1 v -1.75 h 1 V 119 h -1 v 3 h -1 v -2 h -1 v 2 h -1 v -3 z" id="path28608-8" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:0.3;fill:#000000;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" transform="translate(16,1)" id="g28610-5">
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 540,160 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" id="path28612-7" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 544,160 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 160 Z m 1,1 h 1 v 3 h -1 z" id="path28614-6" inkscape:connector-curvature="0"/>
- <rect style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" id="rect28616-1" width="1" height="5" x="548" y="160"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 550,160 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" id="path28618-8" inkscape:connector-curvature="0"/>
- <rect y="160" x="554" height="5" width="1" id="rect28620-9" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 556,160 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z" id="path28622-2" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 562,160 v 0.75 h -1 v 3.5 h 1 V 165 h 2 v -1 -1.25 h -0.99999 V 164 H 562 v -3 h 2 v -1 z" id="path28624-7" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:0.3;fill:#000000;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" transform="translate(21)" id="g28626-9">
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 535.75,224 v 1 H 535 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" id="path28628-5" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 539,224 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z" id="path28630-4" inkscape:connector-curvature="0"/>
- <rect style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" id="rect28632-3" width="1" height="5" x="544" y="224"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 546,224 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z" id="path28634-1" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 552.75,224 v 1 H 552 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" id="path28636-2" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 556,224 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" id="path28638-3" inkscape:connector-curvature="0"/>
- <rect y="224" x="560" height="5" width="1" id="rect28640-3" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 563,224 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z" id="path28642-4" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 567,224 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z" id="path28644-1" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:0.3;fill:#000000;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" transform="translate(22,-10)" id="g28646-1">
- <path id="path28648-3" d="m 535,267 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path28650-8" d="m 542,267 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 546,267 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 267 Z m 1,1 h 1 v 3 h -1 z" id="path28652-7" inkscape:connector-curvature="0"/>
- <rect style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" id="rect28654-4" width="1" height="5" x="550" y="267"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 552,267 v 5 h 1 v -2 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" id="path28656-2" inkscape:connector-curvature="0"/>
- <rect style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" id="rect28658-7" width="1" height="5" x="556" y="267"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 558,267 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" id="path28660-7" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 562,267 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 H 565 v -1.25 h -1 V 267 h -1 z m 1,1 h 1 v 1 h -1 z" id="path28662-9" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 567,267 v 0.75 h -1 v 1.5 h 1 V 270 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 269 h -1 v -1 h 1.5 v -1 z" id="path28664-3" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:0.3;fill:#000000;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" transform="translate(25,-1)" id="g28666-1">
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 532,36 v 0.75 h -1 v 1.5 h 1 V 39 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 38 h -1 v -1 h 1.5 v -1 z" id="path28668-9" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 539.75,36 v 1 H 539 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" id="path28670-8" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 543,36 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 36 Z m 1,1 h 1 v 3 h -1 z" id="path28672-6" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 547,36 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" id="path28674-5" inkscape:connector-curvature="0"/>
- <path id="path28676-0" d="m 555,36 v 1.75 h -1 V 39 h -1 v 2 h 1 v -1.75 h 1 V 38 h 1 v -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 558,36 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" id="path28678-2" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 562,36 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" id="path28680-8" inkscape:connector-curvature="0"/>
- <path id="path28682-6" d="m 566,36 v 2 h 1 v -2 z m 1,2 v 1 h 1 v -1 z m 1,0 h 1 v -2 h -1 z m 0,1 v 2 h 1 v -2 z m -1,0 h -1 v 2 h 1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path28684-0" d="m 570,36 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 535,36 v 5 h 1 v -2 h 1 v 2 h 1 v -5 h -1 v 2 h -1 v -2 z" id="path28686-2" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:0.3;fill:#000000;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" transform="translate(19,125)" id="g28688-4">
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 538,299 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z" id="path28690-8" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 542,299 v 4.25 h 1 V 304 h 2 v -0.75 h 1 V 299 h -1 v 4 h -2 v -4 z" id="path28692-6" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 547,299 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" id="path28694-5" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 551,299 v 5 h 1 2 v -1 h -2 v -4 z" id="path28696-0" inkscape:connector-curvature="0"/>
- <rect style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" id="rect28698-9" width="1" height="5" x="555" y="299"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 557,299 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z" id="path28700-0" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 562,299 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" id="path28702-0" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 566,299 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 H 569 v -1.25 h -1 V 299 h -1 z m 1,1 h 1 v 1 h -1 z" id="path28704-6" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:0.3;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" transform="translate(21,128)" id="g28706-1">
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 539.75,359 v 1 H 539 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" id="path28708-3" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 535,359 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 359 Z m 1,1 h 1 v 3 h -1 z" id="path28710-8" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 543,359 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" id="path28712-9" inkscape:connector-curvature="0"/>
- <path id="path28714-3" d="m 547.75,359 v 1 H 547 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:0.3;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" transform="translate(22,125)" id="g28716-4">
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 545,393 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 393 Z m 1,1 h 1 v 3 h -1 z" id="path28718-4" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 549,393 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" id="path28720-6" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 534,393 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z" id="path28722-0" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 541,393 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z" id="path28724-6" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 554,393 v 0.75 h -1 v 1.5 h 1 V 396 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 395 h -1 v -1 h 1.5 v -1 z" id="path28726-6" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:0.3;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" transform="translate(22.01477,127)" id="g28728-1">
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 538,412 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 412 Z m 1,1 h 1 v 3 h -1 z" id="path28730-8" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 534,412 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" id="path28732-4" inkscape:connector-curvature="0"/>
- <rect style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" id="rect28734-9" width="1" height="5" x="542" y="412"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 549,412 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z" id="path28736-6" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 553,412 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 H 556 v -1.25 h -1 V 412 h -1 z m 1,1 h 1 v 1 h -1 z" id="path28738-3" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 558,412 v 0.75 h -1 v 1.5 h 1 V 415 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 414 h -1 v -1 h 1.5 v -1 z" id="path28740-7" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 544,412 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" id="path28742-8" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:0.3;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" transform="translate(22.01477,127)" id="g28744-8">
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 534,434 v 5 h 1 1 v -0.5 h 1 V 437 h -0.75 v -1 H 537 v -1.25 h -1 V 434 h -1 z m 1,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z" id="path28746-2" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 556,434 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z" id="path28748-9" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 552,434 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z" id="path28750-1" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 562,434 v 0.75 h -1 v 1.5 h 1 V 437 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 436 h -1 v -1 h 1.5 v -1 z" id="path28752-3" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 543,434 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" id="path28754-5" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 538,434 v 4.25 h 1 V 439 h 2 v -0.75 h 1 V 434 h -1 v 4 h -2 v -4 z" id="path28756-9" inkscape:connector-curvature="0"/>
- <path id="path28758-8" d="m 547,434 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:0.3;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" transform="translate(19,127)" id="g28760-4">
- <rect style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" id="rect28762-0" width="1" height="5" x="542" y="486"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 537,486 v 4.25 h 1 V 491 h 2 v -0.75 h 1 V 486 h -1 v 4 h -2 v -4 z" id="path28764-7" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#000000;enable-background:new" id="g10763-6" transform="translate(21)">
- <path id="path10757-3" d="m 536,14 v 0.75 h -1 v 1.5 h 1 V 17 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 16 h -1 v -1 h 1.5 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10759-6" d="m 539,14 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10761-1" d="m 544,14 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m 0,1 v 1 h 1 v -1 z m -2,-1 v -3 h -1 v 3 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10763-5" d="m 553,14 v 1.75 h -1 V 17 h -1 v 2 h 1 v -1.75 h 1 V 16 h 1 v -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <rect y="18" x="548" height="1" width="1" id="rect10765-4" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <rect y="14" x="557" height="5" width="1" id="rect10767-2" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path id="path10769-0" d="m 559,14 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10771-9" d="m 565.75,14 v 1 H 565 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10773-7" d="m 570,14 v 0.75 h -1 v 3.5 h 1 V 19 h 2 v -1 -1.25 h -1 V 18 h -1 v -3 h 2 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10775-3" d="m 573,14 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#000000;enable-background:new" id="g10815-7" transform="translate(21.98523,3)">
- <path id="path10799-2" d="m 534,74 v 5 h 1 v -2 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <rect y="74" x="538" height="5" width="1" id="rect10801-6" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path id="path10803-0" d="m 540,74 v 5 h 1 2 v -1 h -2 v -4 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 544,74 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" id="path10805-1" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 551,74 v 0.75 h -1 v 1.5 h 1 V 77 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 76 h -1 v -1 h 1.5 v -1 z" id="path10807-6" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 554,74 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" id="path10809-5" inkscape:connector-curvature="0"/>
- <path id="path10811-7" d="m 558,74 v 5 h 1 2 v -1 h -2 v -4 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10813-5" d="m 562,74 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10815-4" d="m 567,74 v 0.75 h -1 v 3.5 h 1 V 79 h 2 v -1 h -2 v -3 h 2 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10817-1" d="m 570,74 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#000000;enable-background:new" id="g10827-2" transform="translate(21)">
- <path id="path10672-0" d="m 535,119 v 1 h 2 v 1 h 1 v -1.25 h -1 V 119 Z m 2,2 h -1 v 1 h 1 z m 0,1 v 1 h -2 v 1 h 2 v -0.75 h 1 V 122 Z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10678-0" d="m 539,119 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 119 Z m 1,1 h 1 v 3 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10680-1" d="m 545,119 v 3.25 h 1 V 124 h 1 v -1.75 h 1 V 119 h -1 v 3 h -1 v -3 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <rect y="119" x="549" height="5" width="1" id="rect10682-4" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path id="path10684-6" d="m 551,119 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10686-0" d="m 555,119 v 3.25 h 1 V 124 h 1 v -1.75 h 1 V 124 h 1 v -1.75 h 1 V 119 h -1 v 3 h -1 v -2 h -1 v 2 h -1 v -3 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#000000;enable-background:new" id="g10835-7" transform="translate(16,1)">
- <path id="path10688-1" d="m 540,160 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10690-7" d="m 544,160 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 160 Z m 1,1 h 1 v 3 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <rect y="160" x="548" height="5" width="1" id="rect10692-7" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path id="path10694-7" d="m 550,160 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <rect style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" id="rect10696-7" width="1" height="5" x="554" y="160"/>
- <path id="path10698-3" d="m 556,160 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10700-3" d="m 562,160 v 0.75 h -1 v 3.5 h 1 V 165 h 2 v -1 -1.25 h -0.99999 V 164 H 562 v -3 h 2 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#000000;enable-background:new" id="g10846-5" transform="translate(21)">
- <path id="path10703-9" d="m 535.75,224 v 1 H 535 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10705-9" d="m 539,224 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <rect y="224" x="544" height="5" width="1" id="rect10708-8" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path id="path10711-1" d="m 546,224 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10714-8" d="m 552.75,224 v 1 H 552 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10716-2" d="m 556,224 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <rect style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" id="rect10718-6" width="1" height="5" x="560" y="224"/>
- <path id="path10734-6" d="m 563,224 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10736-0" d="m 567,224 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#000000;enable-background:new" id="g10857-3" transform="translate(22,-10)">
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 535,267 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z" id="path10744-8" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 542,267 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z" id="path10746-0" inkscape:connector-curvature="0"/>
- <path id="path10748-1" d="m 546,267 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 267 Z m 1,1 h 1 v 3 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <rect y="267" x="550" height="5" width="1" id="rect10750-2" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path id="path10752-5" d="m 552,267 v 5 h 1 v -2 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <rect y="267" x="556" height="5" width="1" id="rect10754-0" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path id="path10756-9" d="m 558,267 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10758-4" d="m 562,267 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 H 565 v -1.25 h -1 V 267 h -1 z m 1,1 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10760-7" d="m 567,267 v 0.75 h -1 v 1.5 h 1 V 270 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 269 h -1 v -1 h 1.5 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#000000;enable-background:new" id="g10803-8" transform="translate(25,-1)">
- <path id="path10777-3" d="m 532,36 v 0.75 h -1 v 1.5 h 1 V 39 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 38 h -1 v -1 h 1.5 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10781-5" d="m 539.75,36 v 1 H 539 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10783-1" d="m 543,36 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 36 Z m 1,1 h 1 v 3 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10785-2" d="m 547,36 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 555,36 v 1.75 h -1 V 39 h -1 v 2 h 1 v -1.75 h 1 V 38 h 1 v -2 z" id="path10787-0" inkscape:connector-curvature="0"/>
- <path id="path10789-1" d="m 558,36 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10791-6" d="m 562,36 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 566,36 v 2 h 1 v -2 z m 1,2 v 1 h 1 v -1 z m 1,0 h 1 v -2 h -1 z m 0,1 v 2 h 1 v -2 z m -1,0 h -1 v 2 h 1 z" id="path10795-4" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 570,36 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" id="path10797-0" inkscape:connector-curvature="0"/>
- <path id="path10800-6" d="m 535,36 v 5 h 1 v -2 h 1 v 2 h 1 v -5 h -1 v 2 h -1 v -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#000000;enable-background:new" id="g10885-1" transform="translate(19,125)">
- <path id="path10869-8" d="m 538,299 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10871-9" d="m 542,299 v 4.25 h 1 V 304 h 2 v -0.75 h 1 V 299 h -1 v 4 h -2 v -4 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10873-8" d="m 547,299 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10875-4" d="m 551,299 v 5 h 1 2 v -1 h -2 v -4 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <rect y="299" x="555" height="5" width="1" id="rect10877-1" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path id="path10879-4" d="m 557,299 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10881-3" d="m 562,299 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10883-9" d="m 566,299 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 H 569 v -1.25 h -1 V 299 h -1 z m 1,1 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;enable-background:new" id="g10921-8" transform="translate(21,128)">
- <path id="path10895-8" d="m 539.75,359 v 1 H 539 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10897-0" d="m 535,359 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 359 Z m 1,1 h 1 v 3 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10899-8" d="m 543,359 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 547.75,359 v 1 H 547 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" id="path10901-7" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;enable-background:new" id="g10914-7" transform="translate(22,125)">
- <path id="path10903-8" d="m 545,393 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 393 Z m 1,1 h 1 v 3 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10906-3" d="m 549,393 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10908-8" d="m 534,393 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10910-3" d="m 541,393 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10912-7" d="m 554,393 v 0.75 h -1 v 1.5 h 1 V 396 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 395 h -1 v -1 h 1.5 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;enable-background:new" id="g10942-1" transform="translate(22.01477,127)">
- <path id="path10928-0" d="m 538,412 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 412 Z m 1,1 h 1 v 3 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10930-7" d="m 534,412 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <rect y="412" x="542" height="5" width="1" id="rect10932-3" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path id="path10934-4" d="m 549,412 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10936-9" d="m 553,412 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 H 556 v -1.25 h -1 V 412 h -1 z m 1,1 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10938-6" d="m 558,412 v 0.75 h -1 v 1.5 h 1 V 415 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 414 h -1 v -1 h 1.5 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10940-5" d="m 544,412 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;enable-background:new" id="g10966-1" transform="translate(22.01477,127)">
- <path id="path10951-0" d="m 534,434 v 5 h 1 1 v -0.5 h 1 V 437 h -0.75 v -1 H 537 v -1.25 h -1 V 434 h -1 z m 1,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10953-9" d="m 556,434 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10956-9" d="m 552,434 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10958-6" d="m 562,434 v 0.75 h -1 v 1.5 h 1 V 437 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 436 h -1 v -1 h 1.5 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10960-8" d="m 543,434 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path10962-3" d="m 538,434 v 4.25 h 1 V 439 h 2 v -0.75 h 1 V 434 h -1 v 4 h -2 v -4 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 547,434 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" id="path10964-4" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;enable-background:new" id="g10980-8" transform="translate(19,127)">
- <rect y="486" x="542" height="5" width="1" id="rect10975-4" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path id="path10978-9" d="m 537,486 v 4.25 h 1 V 491 h 2 v -0.75 h 1 V 486 h -1 v 4 h -2 v -4 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- </g>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.4;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 544,133 v 1 h 9 v 62 h -9 v 1 h 9 1 v -33 h 1 v -1 h -1 v -30 h -1 z" id="rect11044-9" sodipodi:nodetypes="ccccccccccccccc" inkscape:connector-curvature="0"/>
- <path id="path19464-5" d="m 0.749997,14 v 1 h -0.75 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path19466-3" d="m -3e-6,35 v 5 h 1 1 v -0.5 h 1 V 38 h -0.75 v -1 h 0.75 v -1.25 h -1 V 35 h -1 z m 1,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path19468-3" d="M 0.999997,56.25 V 57 h -1 v 3.5 h 1 v 0.75 h 2 v -1 h -2 v -3 h 2 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path19470-3" d="m -3e-6,77 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 77 Z m 1,1 h 1 v 3 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path19472-7" d="m -3e-6,99 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path19474-4" d="m -3e-6,119 v 5 h 1 v -2 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path19476-3" d="m 0.999997,140 v 0.75 h -1 v 3.5 h 1 V 145 h 2 v -1 -1.25 h -1 V 144 h -1 v -3 h 2 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path19478-8" d="m -3e-6,161 v 5 h 1 v -2 h 1 v 2 h 1 v -5 h -1 v 2 h -1 v -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <rect y="183" x="0.99999702" height="5" width="1" id="rect19480-0" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path id="path19482-8" d="m 1.999997,203 v 4 h -1 v -1 h -1 v 1 h 0.75 v 1 h 1.5 v -1 h 0.75 v -4 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path19484-8" d="m -3e-6,224 v 5 h 1 v -1.75 h 1 v -1.5 h -1 V 224 Z m 2,1.75 h 1 V 224 h -1 z m 0,1.5 V 229 h 1 v -1.75 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path19486-0" d="m -3e-6,245 v 5 h 1 2 v -1 h -2 v -4 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path19488-6" d="m 0,266 v 5 h 1 v -3 h 1 v -1 H 1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 H 4 v 1 H 3 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path19490-8" d="m -3e-6,287 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path19492-1" d="m 0.999997,308 v 1 h 1 v -1 z m 1,1 v 3 h 1 v -3 z m 0,3 h -1 v 1 h 1 z m -1,0 v -3 h -1 v 3 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" sodipodi:nodetypes="cccccccccccccccccccc" inkscape:connector-curvature="0"/>
- <path id="path19494-9" d="m -3e-6,329 v 5 h 1 v -2 h 1.25 v -1 h 0.75 v -1.25 h -1 V 329 h -1 z m 1,1 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path19496-8" d="m 0.999997,350 v 1 h 1 v -1 z m 1,1 v 3 h 1 v -3 z m 0,3 h -1 v 1 h 1 z m 0,1 v 1 h 1 v -1 z m -1,-1 v -3 h -1 v 3 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" sodipodi:nodetypes="ccccccccccccccccccccccccc" inkscape:connector-curvature="0"/>
- <path id="path19498-9" d="m -3e-6,371 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 h 0.75 v -1.25 h -1 V 371 h -1 z m 1,1 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path19500-7" d="m 0.999997,392 v 0.75 h -1 v 1.5 h 1 V 395 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 394 h -1 v -1 h 1.5 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path19502-2" d="m -3e-6,413 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path19504-2" d="m -3e-6,435 v 4.25 h 1 V 440 h 2 v -0.75 h 1 V 435 h -1 v 4 h -2 v -4 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path19506-8" d="m -3e-6,456 v 3.25 h 1 V 461 h 1 v -1.75 h 1 V 456 h -1 v 3 h -1 v -3 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path19508-2" d="m 0,476 v 3.25 H 1 V 481 h 1 v -1.75 H 2.999997 V 481 H 4 v -1.75 H 5 V 476 H 4 v 3 H 2.999997 v -2 H 2 v 2 H 1 v -3 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m -3e-6,498 v 2 h 1 v -2 z m 1,2 v 1 h 1 v -1 z m 1,0 h 1 v -2 h -1 z m 0,1 v 2 h 1 v -2 z m -1,0 h -1 v 2 h 1 z" id="rect19510-8" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 0.75,557 v 1 H 0 v 4 h 1 v -2 h 1 v 2 h 1 v -4 H 2.25 v -1 z M 1,558 h 1 v 1 H 1 Z" id="path38399-9" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 0,578 v 5 h 1 1 v -0.5 H 3 V 581 H 2.25 v -1 H 3 v -1.25 H 2 V 578 H 1 Z m 1,1 h 1 v 1 H 1 Z m 0,2 h 1 v 1 H 1 Z" id="path38401-0" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="M 1,599.25 V 600 H 0 v 3.5 h 1 v 0.75 h 2 v -1 H 1 v -3 h 2 v -1 z" id="path38403-7" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 0,620 v 1 3 1 h 2 v -0.75 h 1 v -3.5 H 2 V 620 Z m 1,1 h 1 v 3 H 1 Z" id="path38405-8" inkscape:connector-curvature="0"/>
- <path id="path38411-1" d="m 0.75,564 v 1 H 0 v 4 h 1 v -2 h 1 v 2 h 1 v -4 H 2.25 v -1 z M 1,565 h 1 v 1 H 1 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path38413-5" d="m 0.75,585 v 1 H 0 v 4 h 1 v -2 h 1 v 2 h 1 v -4 H 2.25 v -1 z M 1,586 h 1 v 1 H 1 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 0.75,606 v 1 H 0 v 4 h 1 v -2 h 1 v 2 h 1 v -4 H 2.25 v -1 z M 1,607 h 1 v 1 H 1 Z" id="path38415-8" inkscape:connector-curvature="0"/>
- <path id="path38417-6" d="m 0.75,627 v 1 H 0 v 4 h 1 v -2 h 1 v 2 h 1 v -4 H 2.25 v -1 z M 1,628 h 1 v 1 H 1 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path38419-1" d="m 548.75,557 v 1 H 548 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path38421-2" d="m 548,578 v 5 h 1 1 v -0.5 h 1 V 581 h -0.75 v -1 H 551 v -1.25 h -1 V 578 h -1 z m 1,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path38423-4" d="M 549,599.25 V 600 h -1 v 3.5 h 1 v 0.75 h 2 v -1 h -2 v -3 h 2 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path38425-2" d="m 548,620 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 620 Z m 1,1 h 1 v 3 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 548.75,564 v 1 H 548 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" id="path38427-5" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 548.75,585 v 1 H 548 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" id="path38429-8" inkscape:connector-curvature="0"/>
- <path id="path38431-6" d="m 548.75,606 v 1 H 548 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 548.75,627 v 1 H 548 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" id="path38433-2" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" id="path19537-6" d="m 12,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19539-5" d="m 33,2 v 1 h 2 v 1 h -1 v 1 h 1 V 4.25 h 1 V 2.75 H 35 V 2 Z m 1,3 h -1 v 1 1 h 3 V 6 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19541-3" d="m 54,2 v 1 h 2 v 1 h 1 V 2.75 H 56 V 2 Z m 2,2 h -1 v 1 h 1 z m 0,1 v 1 h -2 v 1 h 2 V 6.25 h 1 V 5 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19543-9" d="m 75,2 v 3 h 1 1 v 2 h 1 V 3 H 77 V 4 H 76 V 2 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19545-2" d="m 96,2 v 3 h 1 1 v 1 h -2 v 1 h 2 V 6.25 h 1 V 4.75 H 98 V 4 H 97 V 3 h 2 V 2 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19547-4" d="m 118,2 v 0.75 h -1 V 6 h 0.75 v 1 h 1.5 V 6 H 120 V 5 h -0.75 V 4 H 118 V 3 h 1.5 V 2 Z m 0,3 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19549-6" d="m 138,2 v 1 h 2 v 1 h -1 v 3 h 1 V 4.25 h 1 V 3 2 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19551-18" d="m 159.75,2 v 1 h -0.5 v 1 h 0.5 V 5 H 159 v 1 h 0.75 v 1 h 1.5 V 6 H 162 V 5 h -0.75 V 4 h 0.5 V 3 h -0.5 V 2 Z M 160,3 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19553-2" d="M 180.75,2 V 3 H 180 v 1 h 0.75 V 5 H 182 v 1 h -1.5 V 7 H 182 V 6.25 h 1 V 3 h -0.75 V 2 Z M 181,3 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccc" id="path19555-1" d="M 202.75,2 V 3 H 202 v 3 h 0.75 v 1 h 1.5 V 6 H 205 V 3 h -0.75 V 2 Z M 203,3 h 1 v 3 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 514,2 v 1 h 2 v 1 h -1 v 1 h 1 V 4.25 h 1 v -1.5 h -1 V 2 Z m 1,3 h -1 v 1 1 h 3 V 6 h -2 z" id="path19559-1"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 476,2 v 1 h 2 v 1 h 1 V 2.75 h -1 V 2 Z m 2,2 h -1 v 1 h 1 z m 0,1 v 1 h -2 v 1 h 2 V 6.25 h 1 V 5 Z" id="path19561-9"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 497,2 v 3 h 1 1 v 2 h 1 V 3 h -1 v 1 h -1 V 2 Z" id="path19563-7"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 518,2 v 3 h 1 1 v 1 h -2 v 1 h 2 V 6.25 h 1 v -1.5 h -1 V 4 h -1 V 3 h 2 V 2 h -2 z" id="path19565-6"/>
- <path inkscape:connector-curvature="0" id="path19577-2" d="m 200,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19579-9" d="m 244,2 v 1 h 2 v 1 h -1 v 1 h 1 V 4.25 h 1 v -1.5 h -1 V 2 Z m 1,3 h -1 v 1 1 h 3 V 6 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19581-5" d="m 265,2 v 1 h 2 v 1 h 1 V 2.75 h -1 V 2 Z m 2,2 h -1 v 1 h 1 z m 0,1 v 1 h -2 v 1 h 2 V 6.25 h 1 V 5 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19583-2" d="m 286,2 v 3 h 1 1 v 2 h 1 V 3 h -1 v 1 h -1 V 2 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19585-0" d="m 307,2 v 3 h 1 1 v 1 h -2 v 1 h 2 V 6.25 h 1 v -1.5 h -1 V 4 h -1 V 3 h 2 V 2 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19587-0" d="m 329,2 v 0.75 h -1 V 6 h 0.75 v 1 h 1.5 V 6 H 331 V 5 h -0.75 V 4 H 329 V 3 h 1.5 V 2 Z m 0,3 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19589-3" d="m 349,2 v 1 h 2 v 1 h -1 v 3 h 1 V 4.25 h 1 V 3 2 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19591-9" d="m 370.75,2 v 1 h -0.5 v 1 h 0.5 V 5 H 370 v 1 h 0.75 v 1 h 1.5 V 6 H 373 V 5 h -0.75 V 4 h 0.5 V 3 h -0.5 V 2 Z M 371,3 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19593-1" d="M 391.75,2 V 3 H 391 v 1 h 0.75 V 5 H 393 v 1 h -1.5 V 7 H 393 V 6.25 h 1 V 3 h -0.75 V 2 Z M 392,3 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19595-8" d="M 413.75,2 V 3 H 413 v 3 h 0.75 v 1 h 1.5 V 6 H 416 V 3 h -0.75 V 2 Z M 414,3 h 1 v 3 h -1 z m 0.25,1 v 1 h 0.5 V 4 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19597-1" d="m 221,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 224,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z" id="path19599-9"/>
- <path inkscape:connector-curvature="0" id="path19601-5" d="m 242,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19603-3" d="m 263,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19605-2" d="m 284,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19607-5" d="m 305,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19609-2" d="m 326,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19611-5" d="m 347,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19613-8" d="m 368,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19615-6" d="m 389,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19617-7" d="m 409,2 v 1 h 2 v 1 h -1 v 1 h 1 V 4.25 h 1 v -1.5 h -1 V 2 Z m 1,3 h -1 v 1 1 h 3 V 6 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19619-7" d="m 435,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19621-2" d="m 430,2 v 1 h 2 v 1 h -1 v 1 h 1 V 4.25 h 1 v -1.5 h -1 V 2 Z m 1,3 h -1 v 1 1 h 3 V 6 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19623-2" d="m 451,2 v 1 h 2 v 1 h -1 v 1 h 1 V 4.25 h 1 v -1.5 h -1 V 2 Z m 1,3 h -1 v 1 1 h 3 V 6 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 455,2 v 1 h 2 v 1 h -1 v 1 h 1 V 4.25 h 1 v -1.5 h -1 V 2 Z m 1,3 h -1 v 1 1 h 3 V 6 h -2 z" id="path19625-9"/>
- <path inkscape:connector-curvature="0" id="path19627-4" d="m 472,2 v 1 h 2 v 1 h -1 v 1 h 1 V 4.25 h 1 v -1.5 h -1 V 2 Z m 1,3 h -1 v 1 1 h 3 V 6 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path19629-1" d="m 493,2 v 1 h 2 v 1 h -1 v 1 h 1 V 4.25 h 1 v -1.5 h -1 V 2 Z m 1,3 h -1 v 1 1 h 3 V 6 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path11036-9" d="m 536,2 v 1 h 2 v 1 h -1 v 1 h 1 V 4.25 h 1 v -1.5 h -1 V 2 Z m 1,3 h -1 v 1 1 h 3 V 6 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 541,2 v 0.75 h -1 V 6 h 0.75 v 1 h 1.5 V 6 H 543 V 5 h -0.75 V 4 H 541 V 3 h 1.5 V 2 Z m 0,3 h 1 v 1 h -1 z" id="path11038-6"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 548.75,14 v 1 H 548 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" id="path11128-8"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 548,35 v 5 h 1 1 v -0.5 h 1 V 38 h -0.75 V 37 H 551 v -1.25 h -1 V 35 h -1 z m 1,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z" id="path11130-2"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="M 549,56.25 V 57 h -1 v 3.5 h 1 v 0.75 h 2 v -1 h -2 v -3 h 2 v -1 z" id="path11132-5"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 548,77 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 77 Z m 1,1 h 1 v 3 h -1 z" id="path11134-5"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 548,99 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" id="path11136-4"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 548,119 v 5 h 1 v -2 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" id="path11138-9"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 549,140 v 0.75 h -1 v 3.5 h 1 V 145 h 2 v -1 -1.25 h -1 V 144 h -1 v -3 h 2 v -1 z" id="path11140-1"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 548,161 v 5 h 1 v -2 h 1 v 2 h 1 v -5 h -1 v 2 h -1 v -2 z" id="path11142-2"/>
- <rect style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" id="rect11144-5" width="1" height="5" x="549" y="183"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 550,203 v 4 h -1 v -1 h -1 v 1 h 0.75 v 1 h 1.5 v -1 H 551 v -4 z" id="path11146-0"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 548,224 v 5 h 1 v -1.75 h 1 v -1.5 h -1 V 224 Z m 2,1.75 h 1 V 224 h -1 z m 0,1.5 V 229 h 1 v -1.75 z" id="path11148-8"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 548,245 v 5 h 1 2 v -1 h -2 v -4 z" id="path11150-3"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 548,266 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z" id="path11152-9"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 548,287 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z" id="path11154-3"/>
- <path inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccc" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 549,308 v 1 h 1 v -1 z m 1,1 v 3 h 1 v -3 z m 0,3 h -1 v 1 h 1 z m -1,0 v -3 h -1 v 3 z" id="path11156-9"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 548,329 v 5 h 1 v -2 h 1.25 v -1 H 551 v -1.25 h -1 V 329 h -1 z m 1,1 h 1 v 1 h -1 z" id="path11158-6"/>
- <path inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccccccccccccc" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 549,350 v 1 h 1 v -1 z m 1,1 v 3 h 1 v -3 z m 0,3 h -1 v 1 h 1 z m 0,1 v 1 h 1 v -1 z m -1,-1 v -3 h -1 v 3 z" id="path11160-7"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 548,371 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 H 551 v -1.25 h -1 V 371 h -1 z m 1,1 h 1 v 1 h -1 z" id="path11162-9"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 549,392 v 0.75 h -1 v 1.5 h 1 V 395 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 394 h -1 v -1 h 1.5 v -1 z" id="path11164-9"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 548,413 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" id="path11166-7"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 548,435 v 4.25 h 1 V 440 h 2 v -0.75 h 1 V 435 h -1 v 4 h -2 v -4 z" id="path11168-6"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 548,456 v 3.25 h 1 V 461 h 1 v -1.75 h 1 V 456 h -1 v 3 h -1 v -3 z" id="path11170-9"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="M 547,475.75 V 479 h 1 v 1.75 h 1 V 479 h 1 v 1.75 h 1 V 479 h 1 v -3.25 h -1 v 3 h -1 v -2 h -1 v 2 h -1 v -3 z" id="path11172-3"/>
- <path inkscape:connector-curvature="0" id="path11174-5" d="m 548,498 v 2 h 1 v -2 z m 1,2 v 1 h 1 v -1 z m 1,0 h 1 v -2 h -1 z m 0,1 v 2 h 1 v -2 z m -1,0 h -1 v 2 h 1 z" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path id="path38393-7" d="m 0,518 v 2.25 H 1 V 523 h 1 v -2.75 H 3 V 518 H 2 v 2 H 1 v -2 z" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path38395-6" d="m 0,539 v 1 h 2 v 1 h 1 v -1 -1 z m 2,2 H 1 v 1 h 1 z m -1,1 H 0 v 1 1 h 3 v -1 H 1 Z" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 548,518 v 2.25 h 1 V 523 h 1 v -2.75 h 1 V 518 h -1 v 2 h -1 v -2 z" id="path38435-6" inkscape:connector-curvature="0"/>
- <path style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 548,539 v 1 h 2 v 1 h 1 v -1 -1 z m 2,2 h -1 v 1 h 1 z m -1,1 h -1 v 1 1 h 3 v -1 h -2 z" id="path38437-5" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 12,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z" id="path41043-2"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 33,636 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 H 35 V 636 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z" id="path41045-5"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 54,636 v 1 h 2 v 1 h 1 v -1.25 H 56 V 636 Z m 2,2 h -1 v 1 h 1 z m 0,1 v 1 h -2 v 1 h 2 v -0.75 h 1 V 639 Z" id="path41047-4"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 75,636 v 3 h 1 1 v 2 h 1 v -4 h -1 v 1 h -1 v -2 z" id="path41049-4"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 96,636 v 3 h 1 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 H 98 V 638 h -1 v -1 h 2 v -1 h -2 z" id="path41051-1"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 118,636 v 0.75 h -1 V 640 h 0.75 v 1 h 1.5 v -1 H 120 v -1 h -0.75 v -1 H 118 v -1 h 1.5 v -1 z m 0,3 h 1 v 1 h -1 z" id="path41053-6"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 138,636 v 1 h 2 v 1 h -1 v 3 h 1 v -2.75 h 1 V 637 636 Z" id="path41055-1"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 159.75,636 v 1 h -0.5 v 1 h 0.5 v 1 H 159 v 1 h 0.75 v 1 h 1.5 v -1 H 162 v -1 h -0.75 v -1 h 0.5 v -1 h -0.5 v -1 z m 0.25,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z" id="path41057-6"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 180.75,636 v 1 H 180 v 1 h 0.75 v 1 H 182 v 1 h -1.5 v 1 h 1.5 v -0.75 h 1 V 637 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" id="path41059-3"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 202.75,636 v 1 H 202 v 3 h 0.75 v 1 h 1.5 v -1 H 205 v -3 h -0.75 v -1 z m 0.25,1 h 1 v 3 h -1 z" id="path41061-3" sodipodi:nodetypes="cccccccccccccccccc"/>
- <path inkscape:connector-curvature="0" id="path41063-5" d="m 514,636 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 V 636 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path41065-5" d="m 476,636 v 1 h 2 v 1 h 1 v -1.25 h -1 V 636 Z m 2,2 h -1 v 1 h 1 z m 0,1 v 1 h -2 v 1 h 2 v -0.75 h 1 V 639 Z" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path41067-3" d="m 497,636 v 3 h 1 1 v 2 h 1 v -4 h -1 v 1 h -1 v -2 z" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path41069-2" d="m 518,636 v 3 h 1 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 638 h -1 v -1 h 2 v -1 h -2 z" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 200,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z" id="path41071-8"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 244,636 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 V 636 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z" id="path41073-2"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 265,636 v 1 h 2 v 1 h 1 v -1.25 h -1 V 636 Z m 2,2 h -1 v 1 h 1 z m 0,1 v 1 h -2 v 1 h 2 v -0.75 h 1 V 639 Z" id="path41075-5"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 286,636 v 3 h 1 1 v 2 h 1 v -4 h -1 v 1 h -1 v -2 z" id="path41077-3"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 307,636 v 3 h 1 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 638 h -1 v -1 h 2 v -1 h -2 z" id="path41079-6"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 329,636 v 0.75 h -1 V 640 h 0.75 v 1 h 1.5 v -1 H 331 v -1 h -0.75 v -1 H 329 v -1 h 1.5 v -1 z m 0,3 h 1 v 1 h -1 z" id="path41081-1"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 349,636 v 1 h 2 v 1 h -1 v 3 h 1 v -2.75 h 1 V 637 636 Z" id="path41083-8"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 370.75,636 v 1 h -0.5 v 1 h 0.5 v 1 H 370 v 1 h 0.75 v 1 h 1.5 v -1 H 373 v -1 h -0.75 v -1 h 0.5 v -1 h -0.5 v -1 z m 0.25,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z" id="path41085-6"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 391.75,636 v 1 H 391 v 1 h 0.75 v 1 H 393 v 1 h -1.5 v 1 h 1.5 v -0.75 h 1 V 637 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" id="path41087-2"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 413.75,636 v 1 H 413 v 3 h 0.75 v 1 h 1.5 v -1 H 416 v -3 h -0.75 v -1 z m 0.25,1 h 1 v 3 h -1 z m 0.25,1 v 1 h 0.5 v -1 z" id="path41089-1"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 221,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z" id="path41091-4"/>
- <path inkscape:connector-curvature="0" id="path41093-6" d="m 224,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 242,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z" id="path41095-2"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 263,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z" id="path41097-9"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 284,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z" id="path41099-1"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 305,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z" id="path41101-5"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 326,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z" id="path41103-0"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 347,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z" id="path41105-3"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 368,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z" id="path41107-6"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 389,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z" id="path41109-4"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 409,636 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 V 636 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z" id="path41111-9"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 435,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z" id="path41113-2"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 430,636 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 V 636 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z" id="path41116-9"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 451,636 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 V 636 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z" id="path41118-3"/>
- <path inkscape:connector-curvature="0" id="path41120-4" d="m 455,636 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 V 636 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 472,636 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 V 636 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z" id="path41122-4"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 493,636 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 V 636 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z" id="path41124-0"/>
- <path inkscape:connector-curvature="0" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 536,636 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 V 636 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z" id="path41126-5"/>
- <path inkscape:connector-curvature="0" id="path41128-9" d="m 541,636 v 0.75 h -1 V 640 h 0.75 v 1 h 1.5 v -1 H 543 v -1 h -0.75 v -1 H 541 v -1 h 1.5 v -1 z m 0,3 h 1 v 1 h -1 z" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.4;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 545,238 v 1 h 9 v 41 h -9 v 1 h 9 1 v -21 h 1 v -1 h -1 v -21 h -1 z" id="rect11044-9-4" sodipodi:nodetypes="ccccccccccccccc" inkscape:connector-curvature="0"/>
- <g id="g6033" transform="rotate(-90,411.96778,491.48895)">
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" id="rect5498" width="1" height="5" x="522.48798" y="673.52118"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 433.45673,673.52118 v 4 h -1 v -1 h -1 v 1 h 0.75 v 1 h 1.5 v -1 h 0.75 v -4 z" id="path5500" sodipodi:nodetypes="ccccccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 454.45673,673.52118 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z" id="path5504" sodipodi:nodetypes="cccccccccccccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 419.45673,673.52118 v 0.75 h -1 v 1.5 h 1 v 0.75 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 v -0.75 h -1 v -1 h 1.5 v -1 z" id="path5506" sodipodi:nodetypes="ccccccccccccccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 443.45673,673.52118 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" id="path5508" sodipodi:nodetypes="ccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 422.45673,673.52118 v 4.25 h 1 v 0.75 h 2 v -0.75 h 1 v -4.25 h -1 v 4 h -2 v -4 z" id="path5510" sodipodi:nodetypes="ccccccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 427.45673,673.52118 v 5 h 1 1 v -0.5 h 1 v -1.5 h -0.75 v -1 h 0.75 v -1.25 h -1 v -0.75 h -1 z m 1,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z" id="path5512" sodipodi:nodetypes="ccccccccccccccccccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 440.45673,673.52118 v 0.75 h -1 v 3.5 h 1 v 0.75 h 2 v -1 h -2 v -3 h 2 v -1 z" id="path5514" sodipodi:nodetypes="ccccccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 435.45673,673.52118 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" id="path5516" sodipodi:nodetypes="ccccccccccccccc"/>
- <path id="path5520" d="m 449.45673,673.52118 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 460.45673,673.52118 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" id="path5522" sodipodi:nodetypes="ccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 464.45673,673.52118 v 5 h 1 v -2 h 1 v 2 h 1 v -5 h -1 v 2 h -1 v -2 z" id="path5524" sodipodi:nodetypes="ccccccccccccc"/>
- <path id="path5526" d="m 468.45673,673.52118 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccc"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 518.45673,673.52118 v 5 h 1 2 v -1 h -2 v -4 z" id="path5534" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccc"/>
- <path id="path5536" d="m 525.45673,673.52118 v 0.75 h -1 v 3.5 h 1 v 0.75 h 2 v -1 h -2 v -3 h 2 v -1 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 528.45673,673.52118 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" id="path5538" sodipodi:nodetypes="ccccccccccccccc"/>
- <path id="path5540" d="m 532.45673,673.52118 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccc"/>
- <path id="path5542" d="m 538.45673,673.52118 v 0.75 h -1 v 3.5 h 1 v 0.75 h 2 v -1 h -2 v -3 h 2 v -1 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccc"/>
- <path id="path5544" d="m 541.45673,673.52118 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccc"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 361.45673,673.52118 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" id="path5548" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 365.45673,673.52118 v 5 h 1 v -2 h 1 v 2 h 1 v -5 h -1 v 2 h -1 v -2 z" id="path5550" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccc"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" id="rect5552" width="1" height="5" x="369.48804" y="673.52118"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 372.45673,673.52118 v 0.75 h -1 v 1.5 h 1 v 0.75 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 v -0.75 h -1 v -1 h 1.5 v -1 z" id="path5554" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccccccccc"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 378.45673,673.52118 v 0.75 h -1 v 3.5 h 1 v 0.75 h 2 v -1 h -2 v -3 h 2 v -1 z" id="path5556" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccc"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 386.45673,673.52118 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z" id="path5558" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccc"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 382.45673,673.52118 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z" id="path5560" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccc"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 391.45673,673.52118 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" id="path5562" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 395.45673,673.52118 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" id="path5564" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccc"/>
- <path id="path5566" d="m 399.45673,673.52118 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccc"/>
- <path id="path5568" d="m 404.45673,673.52118 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" id="rect5570" width="1" height="5" x="410.48804" y="673.52118"/>
- <path id="path5572" d="m 413.45673,673.52118 v 0.75 h -1 v 1.5 h 1 v 0.75 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 v -0.75 h -1 v -1 h 1.5 v -1 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccccccccc"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" id="rect5648" width="1" height="1" x="546.48798" y="677.52118"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 326.20673,673.52118 v 1 h -0.75 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" id="path5654" sodipodi:nodetypes="cccccccccccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 329.45673,673.52118 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z" id="path5656" sodipodi:nodetypes="ccccccccccccccccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 335.45673,673.52118 v 5 h 1 1 v -0.5 h 1 v -1.5 h -0.75 v -1 h 0.75 v -1.25 h -1 v -0.75 h -1 z m 1,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z" id="path5658" sodipodi:nodetypes="ccccccccccccccccccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 339.45673,673.52118 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 h 0.75 v -1.25 h -1 v -0.75 h -1 z m 1,1 h 1 v 1 h -1 z" id="path5660" sodipodi:nodetypes="ccccccccccccccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 344.45673,673.52118 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z" id="path5662" sodipodi:nodetypes="cccccccccccccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 348.45673,673.52118 v 1 h 2 v 1 h 1 v -1 -1 z m 2,2 h -1 v 1 h 1 z m -1,1 h -1 v 1 1 h 3 v -1 h -2 z" id="path5664" sodipodi:nodetypes="ccccccccccccccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 295.20673,673.52118 v 1 h -0.75 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" id="path5666" sodipodi:nodetypes="cccccccccccccccccc"/>
- <path inkscape:connector-curvature="0" id="path5668" d="m 298.45673,673.52118 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" sodipodi:nodetypes="cccccccccccccccccc"/>
- <path inkscape:connector-curvature="0" id="path5670" d="m 303.45673,673.52118 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 v -0.75 z m 1,1 h 1 v 3 h -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" sodipodi:nodetypes="cccccccccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 307.45673,673.52118 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 h 0.75 v -1.25 h -1 v -0.75 h -1 z m 1,1 h 1 v 1 h -1 z" id="path5672" sodipodi:nodetypes="ccccccccccccccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 311.45673,673.52118 v 1 h 2 v 1 h 1 v -1 -1 z m 2,2 h -1 v 1 h 1 z m -1,1 h -1 v 1 1 h 3 v -1 h -2 z" id="path5674" sodipodi:nodetypes="ccccccccccccccccccccc"/>
- <path inkscape:connector-curvature="0" id="path5676" d="m 315.45673,673.52118 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" sodipodi:nodetypes="ccccccccccccccc"/>
- <path inkscape:connector-curvature="0" id="path5678" d="m 321.45673,673.52118 v 4 h -1 v -1 h -1 v 1 h 0.75 v 1 h 1.5 v -1 h 0.75 v -4 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" sodipodi:nodetypes="ccccccccccccc"/>
- <rect y="671.52118" x="349.48804" height="1" width="1" id="rect5680" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 267.45673,672.52117 v 0.75 h -1 v 0.25 h -0.25 v 1 h -0.75 v 3 h 0.75 v 1 h 0.25 v 0.25 h 1 v 0.75 h 3 v -0.75 h 1 v -0.25 h 0.25 v -1 h 0.75 v -3 h -0.75 v -1 h -0.25 v -0.25 h -1 v -0.75 z m 0,1 h 3 v 1 h 1 v 3 h -1 v 1 h -3 v -1 h -1 v -3 h 1 z" id="path5682" sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccc"/>
- <path inkscape:connector-curvature="0" id="path5684" d="m 268.45673,674.52117 v 0.75 h -1 v 1.5 h 1 v 0.75 h 1.25 v -1 h -1.25 v -1 h 1.25 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" sodipodi:nodetypes="ccccccccccccc"/>
- <path id="path5686" d="m 279.20673,673.52117 v 1 h -0.75 v 3 h 0.75 v 1 h 1.5 v -1 h 0.75 v -3 h -0.75 v -1 z m 0.25,1 h 1 v 3 h -1 z m 0.25,1 v 1 h 0.5 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccccccccccc"/>
- <path id="path5688" d="m 283.45673,673.52117 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 274.45673,673.52117 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 v -0.75 z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z" id="path5690" sodipodi:nodetypes="ccccccccccccccccccccc"/>
- <path id="path5692" d="m 290.42543,674.52118 v 1 h 1 v -1 z m -0.2187,3 v 1 h -0.75 v 1 h 1 v -1 h 1 v -1 z" style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccc"/>
- <path id="path41087-2-9" d="m 286.22238,673.50552 v 1 h -0.75 v 1 h 0.75 v 1 h 1.25 v 1 h -1.5 v 1 h 1.5 v -0.75 h 1 v -3.25 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccc"/>
- <path id="path6073" d="m 485.45673,673.52118 v 5 h 1 1 v -0.5 h 1 v -1.5 h -0.75 v -1 h 0.75 v -1.25 h -1 v -0.75 h -1 z m 1,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccccccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 493.42543,675.52119 v 1 h 2 v -1 z" id="path6075" sodipodi:nodetypes="ccccc"/>
- <path sodipodi:nodetypes="ccccccccccccc" id="path6077" d="m 489.45673,673.52118 v 2.25 h 1 v 2.75 h 1 v -2.75 h 1 v -2.25 h -1 v 2 h -1 v -2 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path sodipodi:nodetypes="ccccccccccccccccccccc" id="path6079" d="m 497.45673,673.52118 v 0.75 h -1 v 1.5 h 1 v 0.75 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 v -0.75 h -1 v -1 h 1.5 v -1 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path sodipodi:nodetypes="cccccccccccccccccc" id="path6082" d="m 501.20673,673.52118 v 1 h -0.75 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path sodipodi:nodetypes="ccccccccccccccccccccccc" inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 513.20673,673.52117 v 1 h -0.75 v 3 h 0.75 v 1 h 1.5 v -1 h 0.75 v -3 h -0.75 v -1 z m 0.25,1 h 1 v 3 h -1 z m 0.25,1 v 1 h 0.5 v -1 z" id="path6106"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0.6;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" id="rect6108" width="1" height="1" x="510.48804" y="677.52118"/>
- <path id="path6084" d="m 506.45673,673.52118 v 3 h 1 1 v 2 h 1 v -4 h -1 v 1 h -1 v -2 z" style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.6;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" d="m 476.45673,673.52118 v 0.75 h -1 v 3.5 h 1 v 0.75 h 2 v -1 h -2 v -3 h 2 v -1 z" id="path5514-7" sodipodi:nodetypes="ccccccccccccc"/>
- <path id="path6071" d="m 480.45673,673.52118 v 0.75 h -1 v 3.5 h 1 v 0.75 h 2 v -1 h -2 v -3 h 2 v -1 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccc"/>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="sheet layout"
+ style="display:inline"
+ sodipodi:insensitive="true">
+ <g
+ style="display:inline;opacity:0.3;fill:#000000;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="translate(21)"
+ id="g28552-1">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 536,14 v 0.75 h -1 v 1.5 h 1 V 17 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 16 h -1 v -1 h 1.5 v -1 z"
+ id="path28554-7"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 539,14 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ id="path28556-4"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 544,14 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m 0,1 v 1 h 1 v -1 z m -2,-1 v -3 h -1 v 3 z"
+ id="path28558-0"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 553,14 v 1.75 h -1 V 17 h -1 v 2 h 1 v -1.75 h 1 V 16 h 1 v -2 z"
+ id="path28560-9"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect28562-4"
+ width="1"
+ height="1"
+ x="548"
+ y="18" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect28564-8"
+ width="1"
+ height="5"
+ x="557"
+ y="14" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 559,14 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z"
+ id="path28566-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 565.75,14 v 1 H 565 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ id="path28568-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 570,14 v 0.75 h -1 v 3.5 h 1 V 19 h 2 v -1 -1.25 h -1 V 18 h -1 v -3 h 2 v -1 z"
+ id="path28570-4"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 573,14 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ id="path28572-5"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:0.3;fill:#000000;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="translate(21.98523,3)"
+ id="g28574-5">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 534,74 v 5 h 1 v -2 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ id="path28576-1"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect28578-7"
+ width="1"
+ height="5"
+ x="538"
+ y="74" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 540,74 v 5 h 1 2 v -1 h -2 v -4 z"
+ id="path28580-1"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path28582-1"
+ d="m 544,74 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path28584-5"
+ d="m 551,74 v 0.75 h -1 v 1.5 h 1 V 77 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 76 h -1 v -1 h 1.5 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path28586-2"
+ d="m 554,74 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 558,74 v 5 h 1 2 v -1 h -2 v -4 z"
+ id="path28588-7"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 562,74 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ id="path28590-6"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 567,74 v 0.75 h -1 v 3.5 h 1 V 79 h 2 v -1 h -2 v -3 h 2 v -1 z"
+ id="path28592-1"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 570,74 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ id="path28594-4"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:0.3;fill:#000000;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="translate(21)"
+ id="g28596-2">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 535,119 v 1 h 2 v 1 h 1 v -1.25 h -1 V 119 Z m 2,2 h -1 v 1 h 1 z m 0,1 v 1 h -2 v 1 h 2 v -0.75 h 1 V 122 Z"
+ id="path28598-3"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 539,119 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 119 Z m 1,1 h 1 v 3 h -1 z"
+ id="path28600-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 545,119 v 3.25 h 1 V 124 h 1 v -1.75 h 1 V 119 h -1 v 3 h -1 v -3 z"
+ id="path28602-2"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect28604-1"
+ width="1"
+ height="5"
+ x="549"
+ y="119" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 551,119 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ id="path28606-6"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 555,119 v 3.25 h 1 V 124 h 1 v -1.75 h 1 V 124 h 1 v -1.75 h 1 V 119 h -1 v 3 h -1 v -2 h -1 v 2 h -1 v -3 z"
+ id="path28608-8"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:0.3;fill:#000000;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="translate(16,1)"
+ id="g28610-5">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 540,160 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ id="path28612-7"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 544,160 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 160 Z m 1,1 h 1 v 3 h -1 z"
+ id="path28614-6"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect28616-1"
+ width="1"
+ height="5"
+ x="548"
+ y="160" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 550,160 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ id="path28618-8"
+ inkscape:connector-curvature="0" />
+ <rect
+ y="160"
+ x="554"
+ height="5"
+ width="1"
+ id="rect28620-9"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 556,160 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
+ id="path28622-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 562,160 v 0.75 h -1 v 3.5 h 1 V 165 h 2 v -1 -1.25 h -0.99999 V 164 H 562 v -3 h 2 v -1 z"
+ id="path28624-7"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:0.3;fill:#000000;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="translate(21)"
+ id="g28626-9">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 535.75,224 v 1 H 535 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ id="path28628-5"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 539,224 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
+ id="path28630-4"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect28632-3"
+ width="1"
+ height="5"
+ x="544"
+ y="224" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 546,224 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z"
+ id="path28634-1"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 552.75,224 v 1 H 552 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ id="path28636-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 556,224 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ id="path28638-3"
+ inkscape:connector-curvature="0" />
+ <rect
+ y="224"
+ x="560"
+ height="5"
+ width="1"
+ id="rect28640-3"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 563,224 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
+ id="path28642-4"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 567,224 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
+ id="path28644-1"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:0.3;fill:#000000;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="translate(22,-10)"
+ id="g28646-1">
+ <path
+ id="path28648-3"
+ d="m 535,267 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path28650-8"
+ d="m 542,267 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 546,267 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 267 Z m 1,1 h 1 v 3 h -1 z"
+ id="path28652-7"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect28654-4"
+ width="1"
+ height="5"
+ x="550"
+ y="267" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 552,267 v 5 h 1 v -2 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ id="path28656-2"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect28658-7"
+ width="1"
+ height="5"
+ x="556"
+ y="267" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 558,267 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ id="path28660-7"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 562,267 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 H 565 v -1.25 h -1 V 267 h -1 z m 1,1 h 1 v 1 h -1 z"
+ id="path28662-9"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 567,267 v 0.75 h -1 v 1.5 h 1 V 270 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 269 h -1 v -1 h 1.5 v -1 z"
+ id="path28664-3"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:0.3;fill:#000000;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="translate(25,-1)"
+ id="g28666-1">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 532,36 v 0.75 h -1 v 1.5 h 1 V 39 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 38 h -1 v -1 h 1.5 v -1 z"
+ id="path28668-9"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 539.75,36 v 1 H 539 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ id="path28670-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 543,36 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 36 Z m 1,1 h 1 v 3 h -1 z"
+ id="path28672-6"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 547,36 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ id="path28674-5"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path28676-0"
+ d="m 555,36 v 1.75 h -1 V 39 h -1 v 2 h 1 v -1.75 h 1 V 38 h 1 v -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 558,36 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ id="path28678-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 562,36 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ id="path28680-8"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path28682-6"
+ d="m 566,36 v 2 h 1 v -2 z m 1,2 v 1 h 1 v -1 z m 1,0 h 1 v -2 h -1 z m 0,1 v 2 h 1 v -2 z m -1,0 h -1 v 2 h 1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path28684-0"
+ d="m 570,36 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 535,36 v 5 h 1 v -2 h 1 v 2 h 1 v -5 h -1 v 2 h -1 v -2 z"
+ id="path28686-2"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:0.3;fill:#000000;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="translate(19,125)"
+ id="g28688-4">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 538,299 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
+ id="path28690-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 542,299 v 4.25 h 1 V 304 h 2 v -0.75 h 1 V 299 h -1 v 4 h -2 v -4 z"
+ id="path28692-6"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 547,299 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ id="path28694-5"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 551,299 v 5 h 1 2 v -1 h -2 v -4 z"
+ id="path28696-0"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect28698-9"
+ width="1"
+ height="5"
+ x="555"
+ y="299" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 557,299 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
+ id="path28700-0"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 562,299 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ id="path28702-0"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 566,299 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 H 569 v -1.25 h -1 V 299 h -1 z m 1,1 h 1 v 1 h -1 z"
+ id="path28704-6"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:0.3;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="translate(21,128)"
+ id="g28706-1">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 539.75,359 v 1 H 539 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ id="path28708-3"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 535,359 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 359 Z m 1,1 h 1 v 3 h -1 z"
+ id="path28710-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 543,359 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ id="path28712-9"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path28714-3"
+ d="m 547.75,359 v 1 H 547 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:0.3;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="translate(22,125)"
+ id="g28716-4">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 545,393 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 393 Z m 1,1 h 1 v 3 h -1 z"
+ id="path28718-4"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 549,393 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ id="path28720-6"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 534,393 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z"
+ id="path28722-0"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 541,393 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
+ id="path28724-6"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 554,393 v 0.75 h -1 v 1.5 h 1 V 396 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 395 h -1 v -1 h 1.5 v -1 z"
+ id="path28726-6"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:0.3;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="translate(22.01477,127)"
+ id="g28728-1">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 538,412 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 412 Z m 1,1 h 1 v 3 h -1 z"
+ id="path28730-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 534,412 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ id="path28732-4"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect28734-9"
+ width="1"
+ height="5"
+ x="542"
+ y="412" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 549,412 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
+ id="path28736-6"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 553,412 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 H 556 v -1.25 h -1 V 412 h -1 z m 1,1 h 1 v 1 h -1 z"
+ id="path28738-3"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 558,412 v 0.75 h -1 v 1.5 h 1 V 415 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 414 h -1 v -1 h 1.5 v -1 z"
+ id="path28740-7"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 544,412 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ id="path28742-8"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:0.3;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="translate(22.01477,127)"
+ id="g28744-8">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 534,434 v 5 h 1 1 v -0.5 h 1 V 437 h -0.75 v -1 H 537 v -1.25 h -1 V 434 h -1 z m 1,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z"
+ id="path28746-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 556,434 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
+ id="path28748-9"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 552,434 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
+ id="path28750-1"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 562,434 v 0.75 h -1 v 1.5 h 1 V 437 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 436 h -1 v -1 h 1.5 v -1 z"
+ id="path28752-3"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 543,434 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ id="path28754-5"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 538,434 v 4.25 h 1 V 439 h 2 v -0.75 h 1 V 434 h -1 v 4 h -2 v -4 z"
+ id="path28756-9"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path28758-8"
+ d="m 547,434 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:0.3;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="translate(19,127)"
+ id="g28760-4">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect28762-0"
+ width="1"
+ height="5"
+ x="542"
+ y="486" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 537,486 v 4.25 h 1 V 491 h 2 v -0.75 h 1 V 486 h -1 v 4 h -2 v -4 z"
+ id="path28764-7"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#000000;enable-background:new"
+ id="g10763-6"
+ transform="translate(21)">
+ <path
+ id="path10757-3"
+ d="m 536,14 v 0.75 h -1 v 1.5 h 1 V 17 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 16 h -1 v -1 h 1.5 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10759-6"
+ d="m 539,14 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10761-1"
+ d="m 544,14 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m 0,1 v 1 h 1 v -1 z m -2,-1 v -3 h -1 v 3 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10763-5"
+ d="m 553,14 v 1.75 h -1 V 17 h -1 v 2 h 1 v -1.75 h 1 V 16 h 1 v -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <rect
+ y="18"
+ x="548"
+ height="1"
+ width="1"
+ id="rect10765-4"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <rect
+ y="14"
+ x="557"
+ height="5"
+ width="1"
+ id="rect10767-2"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ id="path10769-0"
+ d="m 559,14 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10771-9"
+ d="m 565.75,14 v 1 H 565 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10773-7"
+ d="m 570,14 v 0.75 h -1 v 3.5 h 1 V 19 h 2 v -1 -1.25 h -1 V 18 h -1 v -3 h 2 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10775-3"
+ d="m 573,14 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#000000;enable-background:new"
+ id="g10815-7"
+ transform="translate(21.98523,3)">
+ <path
+ id="path10799-2"
+ d="m 534,74 v 5 h 1 v -2 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <rect
+ y="74"
+ x="538"
+ height="5"
+ width="1"
+ id="rect10801-6"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ id="path10803-0"
+ d="m 540,74 v 5 h 1 2 v -1 h -2 v -4 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 544,74 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ id="path10805-1"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 551,74 v 0.75 h -1 v 1.5 h 1 V 77 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 76 h -1 v -1 h 1.5 v -1 z"
+ id="path10807-6"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 554,74 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ id="path10809-5"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10811-7"
+ d="m 558,74 v 5 h 1 2 v -1 h -2 v -4 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10813-5"
+ d="m 562,74 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10815-4"
+ d="m 567,74 v 0.75 h -1 v 3.5 h 1 V 79 h 2 v -1 h -2 v -3 h 2 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10817-1"
+ d="m 570,74 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#000000;enable-background:new"
+ id="g10827-2"
+ transform="translate(21)">
+ <path
+ id="path10672-0"
+ d="m 535,119 v 1 h 2 v 1 h 1 v -1.25 h -1 V 119 Z m 2,2 h -1 v 1 h 1 z m 0,1 v 1 h -2 v 1 h 2 v -0.75 h 1 V 122 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10678-0"
+ d="m 539,119 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 119 Z m 1,1 h 1 v 3 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10680-1"
+ d="m 545,119 v 3.25 h 1 V 124 h 1 v -1.75 h 1 V 119 h -1 v 3 h -1 v -3 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <rect
+ y="119"
+ x="549"
+ height="5"
+ width="1"
+ id="rect10682-4"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ id="path10684-6"
+ d="m 551,119 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10686-0"
+ d="m 555,119 v 3.25 h 1 V 124 h 1 v -1.75 h 1 V 124 h 1 v -1.75 h 1 V 119 h -1 v 3 h -1 v -2 h -1 v 2 h -1 v -3 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#000000;enable-background:new"
+ id="g10835-7"
+ transform="translate(16,1)">
+ <path
+ id="path10688-1"
+ d="m 540,160 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10690-7"
+ d="m 544,160 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 160 Z m 1,1 h 1 v 3 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <rect
+ y="160"
+ x="548"
+ height="5"
+ width="1"
+ id="rect10692-7"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ id="path10694-7"
+ d="m 550,160 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect10696-7"
+ width="1"
+ height="5"
+ x="554"
+ y="160" />
+ <path
+ id="path10698-3"
+ d="m 556,160 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10700-3"
+ d="m 562,160 v 0.75 h -1 v 3.5 h 1 V 165 h 2 v -1 -1.25 h -0.99999 V 164 H 562 v -3 h 2 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#000000;enable-background:new"
+ id="g10846-5"
+ transform="translate(21)">
+ <path
+ id="path10703-9"
+ d="m 535.75,224 v 1 H 535 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10705-9"
+ d="m 539,224 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <rect
+ y="224"
+ x="544"
+ height="5"
+ width="1"
+ id="rect10708-8"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ id="path10711-1"
+ d="m 546,224 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10714-8"
+ d="m 552.75,224 v 1 H 552 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10716-2"
+ d="m 556,224 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect10718-6"
+ width="1"
+ height="5"
+ x="560"
+ y="224" />
+ <path
+ id="path10734-6"
+ d="m 563,224 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10736-0"
+ d="m 567,224 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#000000;enable-background:new"
+ id="g10857-3"
+ transform="translate(22,-10)">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 535,267 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z"
+ id="path10744-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 542,267 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
+ id="path10746-0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10748-1"
+ d="m 546,267 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 267 Z m 1,1 h 1 v 3 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <rect
+ y="267"
+ x="550"
+ height="5"
+ width="1"
+ id="rect10750-2"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ id="path10752-5"
+ d="m 552,267 v 5 h 1 v -2 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <rect
+ y="267"
+ x="556"
+ height="5"
+ width="1"
+ id="rect10754-0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ id="path10756-9"
+ d="m 558,267 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10758-4"
+ d="m 562,267 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 H 565 v -1.25 h -1 V 267 h -1 z m 1,1 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10760-7"
+ d="m 567,267 v 0.75 h -1 v 1.5 h 1 V 270 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 269 h -1 v -1 h 1.5 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#000000;enable-background:new"
+ id="g10803-8"
+ transform="translate(25,-1)">
+ <path
+ id="path10777-3"
+ d="m 532,36 v 0.75 h -1 v 1.5 h 1 V 39 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 38 h -1 v -1 h 1.5 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10781-5"
+ d="m 539.75,36 v 1 H 539 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10783-1"
+ d="m 543,36 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 36 Z m 1,1 h 1 v 3 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10785-2"
+ d="m 547,36 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 555,36 v 1.75 h -1 V 39 h -1 v 2 h 1 v -1.75 h 1 V 38 h 1 v -2 z"
+ id="path10787-0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10789-1"
+ d="m 558,36 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10791-6"
+ d="m 562,36 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 566,36 v 2 h 1 v -2 z m 1,2 v 1 h 1 v -1 z m 1,0 h 1 v -2 h -1 z m 0,1 v 2 h 1 v -2 z m -1,0 h -1 v 2 h 1 z"
+ id="path10795-4"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 570,36 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ id="path10797-0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10800-6"
+ d="m 535,36 v 5 h 1 v -2 h 1 v 2 h 1 v -5 h -1 v 2 h -1 v -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#000000;enable-background:new"
+ id="g10885-1"
+ transform="translate(19,125)">
+ <path
+ id="path10869-8"
+ d="m 538,299 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10871-9"
+ d="m 542,299 v 4.25 h 1 V 304 h 2 v -0.75 h 1 V 299 h -1 v 4 h -2 v -4 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10873-8"
+ d="m 547,299 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10875-4"
+ d="m 551,299 v 5 h 1 2 v -1 h -2 v -4 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <rect
+ y="299"
+ x="555"
+ height="5"
+ width="1"
+ id="rect10877-1"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ id="path10879-4"
+ d="m 557,299 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10881-3"
+ d="m 562,299 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10883-9"
+ d="m 566,299 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 H 569 v -1.25 h -1 V 299 h -1 z m 1,1 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g10921-8"
+ transform="translate(21,128)">
+ <path
+ id="path10895-8"
+ d="m 539.75,359 v 1 H 539 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10897-0"
+ d="m 535,359 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 359 Z m 1,1 h 1 v 3 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10899-8"
+ d="m 543,359 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 547.75,359 v 1 H 547 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ id="path10901-7"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g10914-7"
+ transform="translate(22,125)">
+ <path
+ id="path10903-8"
+ d="m 545,393 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 393 Z m 1,1 h 1 v 3 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10906-3"
+ d="m 549,393 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10908-8"
+ d="m 534,393 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10910-3"
+ d="m 541,393 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10912-7"
+ d="m 554,393 v 0.75 h -1 v 1.5 h 1 V 396 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 395 h -1 v -1 h 1.5 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g10942-1"
+ transform="translate(22.01477,127)">
+ <path
+ id="path10928-0"
+ d="m 538,412 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 412 Z m 1,1 h 1 v 3 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10930-7"
+ d="m 534,412 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <rect
+ y="412"
+ x="542"
+ height="5"
+ width="1"
+ id="rect10932-3"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ id="path10934-4"
+ d="m 549,412 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10936-9"
+ d="m 553,412 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 H 556 v -1.25 h -1 V 412 h -1 z m 1,1 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10938-6"
+ d="m 558,412 v 0.75 h -1 v 1.5 h 1 V 415 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 414 h -1 v -1 h 1.5 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10940-5"
+ d="m 544,412 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g10966-1"
+ transform="translate(22.01477,127)">
+ <path
+ id="path10951-0"
+ d="m 534,434 v 5 h 1 1 v -0.5 h 1 V 437 h -0.75 v -1 H 537 v -1.25 h -1 V 434 h -1 z m 1,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10953-9"
+ d="m 556,434 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10956-9"
+ d="m 552,434 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10958-6"
+ d="m 562,434 v 0.75 h -1 v 1.5 h 1 V 437 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 436 h -1 v -1 h 1.5 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10960-8"
+ d="m 543,434 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10962-3"
+ d="m 538,434 v 4.25 h 1 V 439 h 2 v -0.75 h 1 V 434 h -1 v 4 h -2 v -4 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 547,434 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ id="path10964-4"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g10980-8"
+ transform="translate(19,127)">
+ <rect
+ y="486"
+ x="542"
+ height="5"
+ width="1"
+ id="rect10975-4"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ id="path10978-9"
+ d="m 537,486 v 4.25 h 1 V 491 h 2 v -0.75 h 1 V 486 h -1 v 4 h -2 v -4 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.4;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 544,133 v 1 h 9 v 62 h -9 v 1 h 9 1 v -33 h 1 v -1 h -1 v -30 h -1 z"
+ id="rect11044-9"
+ sodipodi:nodetypes="ccccccccccccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19464-5"
+ d="m 0.749997,14 v 1 h -0.75 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19466-3"
+ d="m -3e-6,35 v 5 h 1 1 v -0.5 h 1 V 38 h -0.75 v -1 h 0.75 v -1.25 h -1 V 35 h -1 z m 1,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19468-3"
+ d="M 0.999997,56.25 V 57 h -1 v 3.5 h 1 v 0.75 h 2 v -1 h -2 v -3 h 2 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19470-3"
+ d="m -3e-6,77 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 77 Z m 1,1 h 1 v 3 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19472-7"
+ d="m -3e-6,99 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19474-4"
+ d="m -3e-6,119 v 5 h 1 v -2 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19476-3"
+ d="m 0.999997,140 v 0.75 h -1 v 3.5 h 1 V 145 h 2 v -1 -1.25 h -1 V 144 h -1 v -3 h 2 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19478-8"
+ d="m -3e-6,161 v 5 h 1 v -2 h 1 v 2 h 1 v -5 h -1 v 2 h -1 v -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <rect
+ y="183"
+ x="0.99999702"
+ height="5"
+ width="1"
+ id="rect19480-0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ id="path19482-8"
+ d="m 1.999997,203 v 4 h -1 v -1 h -1 v 1 h 0.75 v 1 h 1.5 v -1 h 0.75 v -4 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19484-8"
+ d="m -3e-6,224 v 5 h 1 v -1.75 h 1 v -1.5 h -1 V 224 Z m 2,1.75 h 1 V 224 h -1 z m 0,1.5 V 229 h 1 v -1.75 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19486-0"
+ d="m -3e-6,245 v 5 h 1 2 v -1 h -2 v -4 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19488-6"
+ d="m 0,266 v 5 h 1 v -3 h 1 v -1 H 1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 H 4 v 1 H 3 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19490-8"
+ d="m -3e-6,287 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19492-1"
+ d="m 0.999997,308 v 1 h 1 v -1 z m 1,1 v 3 h 1 v -3 z m 0,3 h -1 v 1 h 1 z m -1,0 v -3 h -1 v 3 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ sodipodi:nodetypes="cccccccccccccccccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19494-9"
+ d="m -3e-6,329 v 5 h 1 v -2 h 1.25 v -1 h 0.75 v -1.25 h -1 V 329 h -1 z m 1,1 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19496-8"
+ d="m 0.999997,350 v 1 h 1 v -1 z m 1,1 v 3 h 1 v -3 z m 0,3 h -1 v 1 h 1 z m 0,1 v 1 h 1 v -1 z m -1,-1 v -3 h -1 v 3 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ sodipodi:nodetypes="ccccccccccccccccccccccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19498-9"
+ d="m -3e-6,371 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 h 0.75 v -1.25 h -1 V 371 h -1 z m 1,1 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19500-7"
+ d="m 0.999997,392 v 0.75 h -1 v 1.5 h 1 V 395 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 394 h -1 v -1 h 1.5 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19502-2"
+ d="m -3e-6,413 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19504-2"
+ d="m -3e-6,435 v 4.25 h 1 V 440 h 2 v -0.75 h 1 V 435 h -1 v 4 h -2 v -4 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19506-8"
+ d="m -3e-6,456 v 3.25 h 1 V 461 h 1 v -1.75 h 1 V 456 h -1 v 3 h -1 v -3 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19508-2"
+ d="m 0,476 v 3.25 H 1 V 481 h 1 v -1.75 H 2.999997 V 481 H 4 v -1.75 H 5 V 476 H 4 v 3 H 2.999997 v -2 H 2 v 2 H 1 v -3 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m -3e-6,498 v 2 h 1 v -2 z m 1,2 v 1 h 1 v -1 z m 1,0 h 1 v -2 h -1 z m 0,1 v 2 h 1 v -2 z m -1,0 h -1 v 2 h 1 z"
+ id="rect19510-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 0.75,557 v 1 H 0 v 4 h 1 v -2 h 1 v 2 h 1 v -4 H 2.25 v -1 z M 1,558 h 1 v 1 H 1 Z"
+ id="path38399-9"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 0,578 v 5 h 1 1 v -0.5 H 3 V 581 H 2.25 v -1 H 3 v -1.25 H 2 V 578 H 1 Z m 1,1 h 1 v 1 H 1 Z m 0,2 h 1 v 1 H 1 Z"
+ id="path38401-0"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="M 1,599.25 V 600 H 0 v 3.5 h 1 v 0.75 h 2 v -1 H 1 v -3 h 2 v -1 z"
+ id="path38403-7"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 0,620 v 1 3 1 h 2 v -0.75 h 1 v -3.5 H 2 V 620 Z m 1,1 h 1 v 3 H 1 Z"
+ id="path38405-8"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path38411-1"
+ d="m 0.75,564 v 1 H 0 v 4 h 1 v -2 h 1 v 2 h 1 v -4 H 2.25 v -1 z M 1,565 h 1 v 1 H 1 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path38413-5"
+ d="m 0.75,585 v 1 H 0 v 4 h 1 v -2 h 1 v 2 h 1 v -4 H 2.25 v -1 z M 1,586 h 1 v 1 H 1 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 0.75,606 v 1 H 0 v 4 h 1 v -2 h 1 v 2 h 1 v -4 H 2.25 v -1 z M 1,607 h 1 v 1 H 1 Z"
+ id="path38415-8"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path38417-6"
+ d="m 0.75,627 v 1 H 0 v 4 h 1 v -2 h 1 v 2 h 1 v -4 H 2.25 v -1 z M 1,628 h 1 v 1 H 1 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path38419-1"
+ d="m 548.75,557 v 1 H 548 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path38421-2"
+ d="m 548,578 v 5 h 1 1 v -0.5 h 1 V 581 h -0.75 v -1 H 551 v -1.25 h -1 V 578 h -1 z m 1,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path38423-4"
+ d="M 549,599.25 V 600 h -1 v 3.5 h 1 v 0.75 h 2 v -1 h -2 v -3 h 2 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path38425-2"
+ d="m 548,620 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 620 Z m 1,1 h 1 v 3 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 548.75,564 v 1 H 548 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ id="path38427-5"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 548.75,585 v 1 H 548 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ id="path38429-8"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path38431-6"
+ d="m 548.75,606 v 1 H 548 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 548.75,627 v 1 H 548 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ id="path38433-2"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19537-6"
+ d="m 12,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19539-5"
+ d="m 33,2 v 1 h 2 v 1 h -1 v 1 h 1 V 4.25 h 1 V 2.75 H 35 V 2 Z m 1,3 h -1 v 1 1 h 3 V 6 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19541-3"
+ d="m 54,2 v 1 h 2 v 1 h 1 V 2.75 H 56 V 2 Z m 2,2 h -1 v 1 h 1 z m 0,1 v 1 h -2 v 1 h 2 V 6.25 h 1 V 5 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19543-9"
+ d="m 75,2 v 3 h 1 1 v 2 h 1 V 3 H 77 V 4 H 76 V 2 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19545-2"
+ d="m 96,2 v 3 h 1 1 v 1 h -2 v 1 h 2 V 6.25 h 1 V 4.75 H 98 V 4 H 97 V 3 h 2 V 2 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19547-4"
+ d="m 118,2 v 0.75 h -1 V 6 h 0.75 v 1 h 1.5 V 6 H 120 V 5 h -0.75 V 4 H 118 V 3 h 1.5 V 2 Z m 0,3 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19549-6"
+ d="m 138,2 v 1 h 2 v 1 h -1 v 3 h 1 V 4.25 h 1 V 3 2 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19551-18"
+ d="m 159.75,2 v 1 h -0.5 v 1 h 0.5 V 5 H 159 v 1 h 0.75 v 1 h 1.5 V 6 H 162 V 5 h -0.75 V 4 h 0.5 V 3 h -0.5 V 2 Z M 160,3 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19553-2"
+ d="M 180.75,2 V 3 H 180 v 1 h 0.75 V 5 H 182 v 1 h -1.5 V 7 H 182 V 6.25 h 1 V 3 h -0.75 V 2 Z M 181,3 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccc"
+ id="path19555-1"
+ d="M 202.75,2 V 3 H 202 v 3 h 0.75 v 1 h 1.5 V 6 H 205 V 3 h -0.75 V 2 Z M 203,3 h 1 v 3 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 514,2 v 1 h 2 v 1 h -1 v 1 h 1 V 4.25 h 1 v -1.5 h -1 V 2 Z m 1,3 h -1 v 1 1 h 3 V 6 h -2 z"
+ id="path19559-1" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 476,2 v 1 h 2 v 1 h 1 V 2.75 h -1 V 2 Z m 2,2 h -1 v 1 h 1 z m 0,1 v 1 h -2 v 1 h 2 V 6.25 h 1 V 5 Z"
+ id="path19561-9" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 497,2 v 3 h 1 1 v 2 h 1 V 3 h -1 v 1 h -1 V 2 Z"
+ id="path19563-7" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 518,2 v 3 h 1 1 v 1 h -2 v 1 h 2 V 6.25 h 1 v -1.5 h -1 V 4 h -1 V 3 h 2 V 2 h -2 z"
+ id="path19565-6" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19577-2"
+ d="m 200,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19579-9"
+ d="m 244,2 v 1 h 2 v 1 h -1 v 1 h 1 V 4.25 h 1 v -1.5 h -1 V 2 Z m 1,3 h -1 v 1 1 h 3 V 6 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19581-5"
+ d="m 265,2 v 1 h 2 v 1 h 1 V 2.75 h -1 V 2 Z m 2,2 h -1 v 1 h 1 z m 0,1 v 1 h -2 v 1 h 2 V 6.25 h 1 V 5 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19583-2"
+ d="m 286,2 v 3 h 1 1 v 2 h 1 V 3 h -1 v 1 h -1 V 2 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19585-0"
+ d="m 307,2 v 3 h 1 1 v 1 h -2 v 1 h 2 V 6.25 h 1 v -1.5 h -1 V 4 h -1 V 3 h 2 V 2 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19587-0"
+ d="m 329,2 v 0.75 h -1 V 6 h 0.75 v 1 h 1.5 V 6 H 331 V 5 h -0.75 V 4 H 329 V 3 h 1.5 V 2 Z m 0,3 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19589-3"
+ d="m 349,2 v 1 h 2 v 1 h -1 v 3 h 1 V 4.25 h 1 V 3 2 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19591-9"
+ d="m 370.75,2 v 1 h -0.5 v 1 h 0.5 V 5 H 370 v 1 h 0.75 v 1 h 1.5 V 6 H 373 V 5 h -0.75 V 4 h 0.5 V 3 h -0.5 V 2 Z M 371,3 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19593-1"
+ d="M 391.75,2 V 3 H 391 v 1 h 0.75 V 5 H 393 v 1 h -1.5 V 7 H 393 V 6.25 h 1 V 3 h -0.75 V 2 Z M 392,3 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19595-8"
+ d="M 413.75,2 V 3 H 413 v 3 h 0.75 v 1 h 1.5 V 6 H 416 V 3 h -0.75 V 2 Z M 414,3 h 1 v 3 h -1 z m 0.25,1 v 1 h 0.5 V 4 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19597-1"
+ d="m 221,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 224,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z"
+ id="path19599-9" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19601-5"
+ d="m 242,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19603-3"
+ d="m 263,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19605-2"
+ d="m 284,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19607-5"
+ d="m 305,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19609-2"
+ d="m 326,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19611-5"
+ d="m 347,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19613-8"
+ d="m 368,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19615-6"
+ d="m 389,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19617-7"
+ d="m 409,2 v 1 h 2 v 1 h -1 v 1 h 1 V 4.25 h 1 v -1.5 h -1 V 2 Z m 1,3 h -1 v 1 1 h 3 V 6 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19619-7"
+ d="m 435,2 v 1 h -1 v 1 h 1 v 3 h 1 V 2 Z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19621-2"
+ d="m 430,2 v 1 h 2 v 1 h -1 v 1 h 1 V 4.25 h 1 v -1.5 h -1 V 2 Z m 1,3 h -1 v 1 1 h 3 V 6 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19623-2"
+ d="m 451,2 v 1 h 2 v 1 h -1 v 1 h 1 V 4.25 h 1 v -1.5 h -1 V 2 Z m 1,3 h -1 v 1 1 h 3 V 6 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 455,2 v 1 h 2 v 1 h -1 v 1 h 1 V 4.25 h 1 v -1.5 h -1 V 2 Z m 1,3 h -1 v 1 1 h 3 V 6 h -2 z"
+ id="path19625-9" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19627-4"
+ d="m 472,2 v 1 h 2 v 1 h -1 v 1 h 1 V 4.25 h 1 v -1.5 h -1 V 2 Z m 1,3 h -1 v 1 1 h 3 V 6 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19629-1"
+ d="m 493,2 v 1 h 2 v 1 h -1 v 1 h 1 V 4.25 h 1 v -1.5 h -1 V 2 Z m 1,3 h -1 v 1 1 h 3 V 6 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path11036-9"
+ d="m 536,2 v 1 h 2 v 1 h -1 v 1 h 1 V 4.25 h 1 v -1.5 h -1 V 2 Z m 1,3 h -1 v 1 1 h 3 V 6 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 541,2 v 0.75 h -1 V 6 h 0.75 v 1 h 1.5 V 6 H 543 V 5 h -0.75 V 4 H 541 V 3 h 1.5 V 2 Z m 0,3 h 1 v 1 h -1 z"
+ id="path11038-6" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 548.75,14 v 1 H 548 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ id="path11128-8" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 548,35 v 5 h 1 1 v -0.5 h 1 V 38 h -0.75 V 37 H 551 v -1.25 h -1 V 35 h -1 z m 1,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z"
+ id="path11130-2" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="M 549,56.25 V 57 h -1 v 3.5 h 1 v 0.75 h 2 v -1 h -2 v -3 h 2 v -1 z"
+ id="path11132-5" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 548,77 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 77 Z m 1,1 h 1 v 3 h -1 z"
+ id="path11134-5" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 548,99 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ id="path11136-4" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 548,119 v 5 h 1 v -2 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ id="path11138-9" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 549,140 v 0.75 h -1 v 3.5 h 1 V 145 h 2 v -1 -1.25 h -1 V 144 h -1 v -3 h 2 v -1 z"
+ id="path11140-1" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 548,161 v 5 h 1 v -2 h 1 v 2 h 1 v -5 h -1 v 2 h -1 v -2 z"
+ id="path11142-2" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect11144-5"
+ width="1"
+ height="5"
+ x="549"
+ y="183" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 550,203 v 4 h -1 v -1 h -1 v 1 h 0.75 v 1 h 1.5 v -1 H 551 v -4 z"
+ id="path11146-0" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 548,224 v 5 h 1 v -1.75 h 1 v -1.5 h -1 V 224 Z m 2,1.75 h 1 V 224 h -1 z m 0,1.5 V 229 h 1 v -1.75 z"
+ id="path11148-8" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 548,245 v 5 h 1 2 v -1 h -2 v -4 z"
+ id="path11150-3" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 548,266 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z"
+ id="path11152-9" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 548,287 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
+ id="path11154-3" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccc"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 549,308 v 1 h 1 v -1 z m 1,1 v 3 h 1 v -3 z m 0,3 h -1 v 1 h 1 z m -1,0 v -3 h -1 v 3 z"
+ id="path11156-9" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 548,329 v 5 h 1 v -2 h 1.25 v -1 H 551 v -1.25 h -1 V 329 h -1 z m 1,1 h 1 v 1 h -1 z"
+ id="path11158-6" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccc"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 549,350 v 1 h 1 v -1 z m 1,1 v 3 h 1 v -3 z m 0,3 h -1 v 1 h 1 z m 0,1 v 1 h 1 v -1 z m -1,-1 v -3 h -1 v 3 z"
+ id="path11160-7" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 548,371 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 H 551 v -1.25 h -1 V 371 h -1 z m 1,1 h 1 v 1 h -1 z"
+ id="path11162-9" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 549,392 v 0.75 h -1 v 1.5 h 1 V 395 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 394 h -1 v -1 h 1.5 v -1 z"
+ id="path11164-9" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 548,413 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ id="path11166-7" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 548,435 v 4.25 h 1 V 440 h 2 v -0.75 h 1 V 435 h -1 v 4 h -2 v -4 z"
+ id="path11168-6" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 548,456 v 3.25 h 1 V 461 h 1 v -1.75 h 1 V 456 h -1 v 3 h -1 v -3 z"
+ id="path11170-9" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="M 547,475.75 V 479 h 1 v 1.75 h 1 V 479 h 1 v 1.75 h 1 V 479 h 1 v -3.25 h -1 v 3 h -1 v -2 h -1 v 2 h -1 v -3 z"
+ id="path11172-3" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path11174-5"
+ d="m 548,498 v 2 h 1 v -2 z m 1,2 v 1 h 1 v -1 z m 1,0 h 1 v -2 h -1 z m 0,1 v 2 h 1 v -2 z m -1,0 h -1 v 2 h 1 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ id="path38393-7"
+ d="m 0,518 v 2.25 H 1 V 523 h 1 v -2.75 H 3 V 518 H 2 v 2 H 1 v -2 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path38395-6"
+ d="m 0,539 v 1 h 2 v 1 h 1 v -1 -1 z m 2,2 H 1 v 1 h 1 z m -1,1 H 0 v 1 1 h 3 v -1 H 1 Z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 548,518 v 2.25 h 1 V 523 h 1 v -2.75 h 1 V 518 h -1 v 2 h -1 v -2 z"
+ id="path38435-6"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 548,539 v 1 h 2 v 1 h 1 v -1 -1 z m 2,2 h -1 v 1 h 1 z m -1,1 h -1 v 1 1 h 3 v -1 h -2 z"
+ id="path38437-5"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 12,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z"
+ id="path41043-2" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 33,636 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 H 35 V 636 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z"
+ id="path41045-5" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 54,636 v 1 h 2 v 1 h 1 v -1.25 H 56 V 636 Z m 2,2 h -1 v 1 h 1 z m 0,1 v 1 h -2 v 1 h 2 v -0.75 h 1 V 639 Z"
+ id="path41047-4" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 75,636 v 3 h 1 1 v 2 h 1 v -4 h -1 v 1 h -1 v -2 z"
+ id="path41049-4" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 96,636 v 3 h 1 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 H 98 V 638 h -1 v -1 h 2 v -1 h -2 z"
+ id="path41051-1" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 118,636 v 0.75 h -1 V 640 h 0.75 v 1 h 1.5 v -1 H 120 v -1 h -0.75 v -1 H 118 v -1 h 1.5 v -1 z m 0,3 h 1 v 1 h -1 z"
+ id="path41053-6" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 138,636 v 1 h 2 v 1 h -1 v 3 h 1 v -2.75 h 1 V 637 636 Z"
+ id="path41055-1" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 159.75,636 v 1 h -0.5 v 1 h 0.5 v 1 H 159 v 1 h 0.75 v 1 h 1.5 v -1 H 162 v -1 h -0.75 v -1 h 0.5 v -1 h -0.5 v -1 z m 0.25,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z"
+ id="path41057-6" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 180.75,636 v 1 H 180 v 1 h 0.75 v 1 H 182 v 1 h -1.5 v 1 h 1.5 v -0.75 h 1 V 637 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ id="path41059-3" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 202.75,636 v 1 H 202 v 3 h 0.75 v 1 h 1.5 v -1 H 205 v -3 h -0.75 v -1 z m 0.25,1 h 1 v 3 h -1 z"
+ id="path41061-3"
+ sodipodi:nodetypes="cccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path41063-5"
+ d="m 514,636 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 V 636 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path41065-5"
+ d="m 476,636 v 1 h 2 v 1 h 1 v -1.25 h -1 V 636 Z m 2,2 h -1 v 1 h 1 z m 0,1 v 1 h -2 v 1 h 2 v -0.75 h 1 V 639 Z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path41067-3"
+ d="m 497,636 v 3 h 1 1 v 2 h 1 v -4 h -1 v 1 h -1 v -2 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path41069-2"
+ d="m 518,636 v 3 h 1 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 638 h -1 v -1 h 2 v -1 h -2 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 200,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z"
+ id="path41071-8" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 244,636 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 V 636 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z"
+ id="path41073-2" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 265,636 v 1 h 2 v 1 h 1 v -1.25 h -1 V 636 Z m 2,2 h -1 v 1 h 1 z m 0,1 v 1 h -2 v 1 h 2 v -0.75 h 1 V 639 Z"
+ id="path41075-5" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 286,636 v 3 h 1 1 v 2 h 1 v -4 h -1 v 1 h -1 v -2 z"
+ id="path41077-3" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 307,636 v 3 h 1 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 638 h -1 v -1 h 2 v -1 h -2 z"
+ id="path41079-6" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 329,636 v 0.75 h -1 V 640 h 0.75 v 1 h 1.5 v -1 H 331 v -1 h -0.75 v -1 H 329 v -1 h 1.5 v -1 z m 0,3 h 1 v 1 h -1 z"
+ id="path41081-1" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 349,636 v 1 h 2 v 1 h -1 v 3 h 1 v -2.75 h 1 V 637 636 Z"
+ id="path41083-8" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 370.75,636 v 1 h -0.5 v 1 h 0.5 v 1 H 370 v 1 h 0.75 v 1 h 1.5 v -1 H 373 v -1 h -0.75 v -1 h 0.5 v -1 h -0.5 v -1 z m 0.25,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z"
+ id="path41085-6" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 391.75,636 v 1 H 391 v 1 h 0.75 v 1 H 393 v 1 h -1.5 v 1 h 1.5 v -0.75 h 1 V 637 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ id="path41087-2" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 413.75,636 v 1 H 413 v 3 h 0.75 v 1 h 1.5 v -1 H 416 v -3 h -0.75 v -1 z m 0.25,1 h 1 v 3 h -1 z m 0.25,1 v 1 h 0.5 v -1 z"
+ id="path41089-1" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 221,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z"
+ id="path41091-4" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path41093-6"
+ d="m 224,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 242,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z"
+ id="path41095-2" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 263,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z"
+ id="path41097-9" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 284,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z"
+ id="path41099-1" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 305,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z"
+ id="path41101-5" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 326,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z"
+ id="path41103-0" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 347,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z"
+ id="path41105-3" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 368,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z"
+ id="path41107-6" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 389,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z"
+ id="path41109-4" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 409,636 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 V 636 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z"
+ id="path41111-9" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 435,636 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z"
+ id="path41113-2" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 430,636 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 V 636 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z"
+ id="path41116-9" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 451,636 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 V 636 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z"
+ id="path41118-3" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path41120-4"
+ d="m 455,636 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 V 636 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 472,636 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 V 636 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z"
+ id="path41122-4" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 493,636 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 V 636 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z"
+ id="path41124-0" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 536,636 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 V 636 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z"
+ id="path41126-5" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path41128-9"
+ d="m 541,636 v 0.75 h -1 V 640 h 0.75 v 1 h 1.5 v -1 H 543 v -1 h -0.75 v -1 H 541 v -1 h 1.5 v -1 z m 0,3 h 1 v 1 h -1 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.4;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 545,238 v 1 h 9 v 41 h -9 v 1 h 9 1 v -21 h 1 v -1 h -1 v -21 h -1 z"
+ id="rect11044-9-4"
+ sodipodi:nodetypes="ccccccccccccccc"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g6033"
+ transform="rotate(-90,411.96778,491.48895)">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect5498"
+ width="1"
+ height="5"
+ x="522.48798"
+ y="673.52118" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 433.45673,673.52118 v 4 h -1 v -1 h -1 v 1 h 0.75 v 1 h 1.5 v -1 h 0.75 v -4 z"
+ id="path5500"
+ sodipodi:nodetypes="ccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 454.45673,673.52118 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
+ id="path5504"
+ sodipodi:nodetypes="cccccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 419.45673,673.52118 v 0.75 h -1 v 1.5 h 1 v 0.75 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 v -0.75 h -1 v -1 h 1.5 v -1 z"
+ id="path5506"
+ sodipodi:nodetypes="ccccccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 443.45673,673.52118 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ id="path5508"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 422.45673,673.52118 v 4.25 h 1 v 0.75 h 2 v -0.75 h 1 v -4.25 h -1 v 4 h -2 v -4 z"
+ id="path5510"
+ sodipodi:nodetypes="ccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 427.45673,673.52118 v 5 h 1 1 v -0.5 h 1 v -1.5 h -0.75 v -1 h 0.75 v -1.25 h -1 v -0.75 h -1 z m 1,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z"
+ id="path5512"
+ sodipodi:nodetypes="ccccccccccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 440.45673,673.52118 v 0.75 h -1 v 3.5 h 1 v 0.75 h 2 v -1 h -2 v -3 h 2 v -1 z"
+ id="path5514"
+ sodipodi:nodetypes="ccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 435.45673,673.52118 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ id="path5516"
+ sodipodi:nodetypes="ccccccccccccccc" />
+ <path
+ id="path5520"
+ d="m 449.45673,673.52118 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 460.45673,673.52118 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ id="path5522"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 464.45673,673.52118 v 5 h 1 v -2 h 1 v 2 h 1 v -5 h -1 v 2 h -1 v -2 z"
+ id="path5524"
+ sodipodi:nodetypes="ccccccccccccc" />
+ <path
+ id="path5526"
+ d="m 468.45673,673.52118 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccc" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 518.45673,673.52118 v 5 h 1 2 v -1 h -2 v -4 z"
+ id="path5534"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
+ <path
+ id="path5536"
+ d="m 525.45673,673.52118 v 0.75 h -1 v 3.5 h 1 v 0.75 h 2 v -1 h -2 v -3 h 2 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 528.45673,673.52118 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ id="path5538"
+ sodipodi:nodetypes="ccccccccccccccc" />
+ <path
+ id="path5540"
+ d="m 532.45673,673.52118 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccc" />
+ <path
+ id="path5542"
+ d="m 538.45673,673.52118 v 0.75 h -1 v 3.5 h 1 v 0.75 h 2 v -1 h -2 v -3 h 2 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccc" />
+ <path
+ id="path5544"
+ d="m 541.45673,673.52118 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccc" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 361.45673,673.52118 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ id="path5548"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 365.45673,673.52118 v 5 h 1 v -2 h 1 v 2 h 1 v -5 h -1 v 2 h -1 v -2 z"
+ id="path5550"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccc" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect5552"
+ width="1"
+ height="5"
+ x="369.48804"
+ y="673.52118" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 372.45673,673.52118 v 0.75 h -1 v 1.5 h 1 v 0.75 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 v -0.75 h -1 v -1 h 1.5 v -1 z"
+ id="path5554"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccc" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 378.45673,673.52118 v 0.75 h -1 v 3.5 h 1 v 0.75 h 2 v -1 h -2 v -3 h 2 v -1 z"
+ id="path5556"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccc" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 386.45673,673.52118 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
+ id="path5558"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccc" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 382.45673,673.52118 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
+ id="path5560"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccc" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 391.45673,673.52118 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ id="path5562"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 395.45673,673.52118 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ id="path5564"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccc" />
+ <path
+ id="path5566"
+ d="m 399.45673,673.52118 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccc" />
+ <path
+ id="path5568"
+ d="m 404.45673,673.52118 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect5570"
+ width="1"
+ height="5"
+ x="410.48804"
+ y="673.52118" />
+ <path
+ id="path5572"
+ d="m 413.45673,673.52118 v 0.75 h -1 v 1.5 h 1 v 0.75 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 v -0.75 h -1 v -1 h 1.5 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccc" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect5648"
+ width="1"
+ height="1"
+ x="546.48798"
+ y="677.52118" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 326.20673,673.52118 v 1 h -0.75 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ id="path5654"
+ sodipodi:nodetypes="cccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 329.45673,673.52118 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z"
+ id="path5656"
+ sodipodi:nodetypes="ccccccccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 335.45673,673.52118 v 5 h 1 1 v -0.5 h 1 v -1.5 h -0.75 v -1 h 0.75 v -1.25 h -1 v -0.75 h -1 z m 1,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z"
+ id="path5658"
+ sodipodi:nodetypes="ccccccccccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 339.45673,673.52118 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 h 0.75 v -1.25 h -1 v -0.75 h -1 z m 1,1 h 1 v 1 h -1 z"
+ id="path5660"
+ sodipodi:nodetypes="ccccccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 344.45673,673.52118 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
+ id="path5662"
+ sodipodi:nodetypes="cccccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 348.45673,673.52118 v 1 h 2 v 1 h 1 v -1 -1 z m 2,2 h -1 v 1 h 1 z m -1,1 h -1 v 1 1 h 3 v -1 h -2 z"
+ id="path5664"
+ sodipodi:nodetypes="ccccccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 295.20673,673.52118 v 1 h -0.75 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ id="path5666"
+ sodipodi:nodetypes="cccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path5668"
+ d="m 298.45673,673.52118 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ sodipodi:nodetypes="cccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path5670"
+ d="m 303.45673,673.52118 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 v -0.75 z m 1,1 h 1 v 3 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ sodipodi:nodetypes="cccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 307.45673,673.52118 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 h 0.75 v -1.25 h -1 v -0.75 h -1 z m 1,1 h 1 v 1 h -1 z"
+ id="path5672"
+ sodipodi:nodetypes="ccccccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 311.45673,673.52118 v 1 h 2 v 1 h 1 v -1 -1 z m 2,2 h -1 v 1 h 1 z m -1,1 h -1 v 1 1 h 3 v -1 h -2 z"
+ id="path5674"
+ sodipodi:nodetypes="ccccccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path5676"
+ d="m 315.45673,673.52118 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ sodipodi:nodetypes="ccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path5678"
+ d="m 321.45673,673.52118 v 4 h -1 v -1 h -1 v 1 h 0.75 v 1 h 1.5 v -1 h 0.75 v -4 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ sodipodi:nodetypes="ccccccccccccc" />
+ <rect
+ y="671.52118"
+ x="349.48804"
+ height="1"
+ width="1"
+ id="rect5680"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 267.45673,672.52117 v 0.75 h -1 v 0.25 h -0.25 v 1 h -0.75 v 3 h 0.75 v 1 h 0.25 v 0.25 h 1 v 0.75 h 3 v -0.75 h 1 v -0.25 h 0.25 v -1 h 0.75 v -3 h -0.75 v -1 h -0.25 v -0.25 h -1 v -0.75 z m 0,1 h 3 v 1 h 1 v 3 h -1 v 1 h -3 v -1 h -1 v -3 h 1 z"
+ id="path5682"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path5684"
+ d="m 268.45673,674.52117 v 0.75 h -1 v 1.5 h 1 v 0.75 h 1.25 v -1 h -1.25 v -1 h 1.25 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ sodipodi:nodetypes="ccccccccccccc" />
+ <path
+ id="path5686"
+ d="m 279.20673,673.52117 v 1 h -0.75 v 3 h 0.75 v 1 h 1.5 v -1 h 0.75 v -3 h -0.75 v -1 z m 0.25,1 h 1 v 3 h -1 z m 0.25,1 v 1 h 0.5 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccc" />
+ <path
+ id="path5688"
+ d="m 283.45673,673.52117 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 274.45673,673.52117 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 v -0.75 z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z"
+ id="path5690"
+ sodipodi:nodetypes="ccccccccccccccccccccc" />
+ <path
+ id="path5692"
+ d="m 290.42543,674.52118 v 1 h 1 v -1 z m -0.2187,3 v 1 h -0.75 v 1 h 1 v -1 h 1 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccc" />
+ <path
+ id="path41087-2-9"
+ d="m 286.22238,673.50552 v 1 h -0.75 v 1 h 0.75 v 1 h 1.25 v 1 h -1.5 v 1 h 1.5 v -0.75 h 1 v -3.25 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccc" />
+ <path
+ id="path6073"
+ d="m 485.45673,673.52118 v 5 h 1 1 v -0.5 h 1 v -1.5 h -0.75 v -1 h 0.75 v -1.25 h -1 v -0.75 h -1 z m 1,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 493.42543,675.52119 v 1 h 2 v -1 z"
+ id="path6075"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ sodipodi:nodetypes="ccccccccccccc"
+ id="path6077"
+ d="m 489.45673,673.52118 v 2.25 h 1 v 2.75 h 1 v -2.75 h 1 v -2.25 h -1 v 2 h -1 v -2 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccc"
+ id="path6079"
+ d="m 497.45673,673.52118 v 0.75 h -1 v 1.5 h 1 v 0.75 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 v -0.75 h -1 v -1 h 1.5 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cccccccccccccccccc"
+ id="path6082"
+ d="m 501.20673,673.52118 v 1 h -0.75 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 513.20673,673.52117 v 1 h -0.75 v 3 h 0.75 v 1 h 1.5 v -1 h 0.75 v -3 h -0.75 v -1 z m 0.25,1 h 1 v 3 h -1 z m 0.25,1 v 1 h 0.5 v -1 z"
+ id="path6106" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect6108"
+ width="1"
+ height="1"
+ x="510.48804"
+ y="677.52118" />
+ <path
+ id="path6084"
+ d="m 506.45673,673.52118 v 3 h 1 1 v 2 h 1 v -4 h -1 v 1 h -1 v -2 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.6;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 476.45673,673.52118 v 0.75 h -1 v 3.5 h 1 v 0.75 h 2 v -1 h -2 v -3 h 2 v -1 z"
+ id="path5514-7"
+ sodipodi:nodetypes="ccccccccccccc" />
+ <path
+ id="path6071"
+ d="m 480.45673,673.52118 v 0.75 h -1 v 3.5 h 1 v 0.75 h 2 v -1 h -2 v -3 h 2 v -1 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.6;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccc" />
</g>
</g>
- <g inkscape:groupmode="layer" id="layer8" inkscape:label="2.81" style="display:inline">
- <path inkscape:connector-curvature="0" id="path6587" d="M 61.503909,123 A 6.5039066,6.5039066 0 0 1 55.000003,129.50391 6.5039066,6.5039066 0 0 1 48.496097,123 6.5039066,6.5039066 0 0 1 55.000003,116.4961 6.5039066,6.5039066 0 0 1 61.503909,123 Z" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <g id="g10975" transform="translate(-378.00707,-293.99994)" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96"/>
- <g id="g10009" transform="translate(5.3904633e-4,-20.999933)" style="display:inline;opacity:1;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96"/>
- <g transform="translate(-380,231)" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g12153" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96"/>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" transform="translate(-336.00001,210.00001)" id="g12215" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g12492" transform="translate(20.999999)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96"/>
- <g id="g12457" transform="matrix(0.69230791,0,0,0.69230793,-403.07713,196.14887)" style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.44444394;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g12921" transform="translate(21.999999,-3)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96"/>
- <g style="display:inline;opacity:0.41300001;fill:#ffffff;enable-background:new" id="g5202-0" transform="translate(496.99495,-311.99288)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g13534" transform="translate(-9.5367432e-7,21)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96"/>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g13838" transform="rotate(90,160.07935,395.5873)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g id="g13835" transform="matrix(0,1,1,0,205.49208,-205.33334)" style="fill:#ffffff"/>
- </g>
- <g style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" id="g6922" transform="translate(-378.0172,105)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <circle r="0" cy="162.5" cx="415.5" style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" id="ellipse13645"/>
- </g>
- <g style="display:inline;fill:#ffffff;stroke-width:1.15384614;enable-background:new" id="g14341" transform="translate(-441.00001,525.00001)"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14199" transform="translate(-9.5367432e-7,20)"/>
- <g style="display:inline;fill:#ffffff;stroke:#666666;enable-background:new" id="g14215" inkscape:transform-center-x="-1.2499" inkscape:transform-center-y="9.9999999e-006" transform="matrix(0,-1,-1,0,723.9999,577.00011)"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14644" transform="translate(-9.5367432e-7,30)"/>
- <circle transform="scale(-1)" cy="-286.5" cx="-353.50003" id="ellipse14264" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" r="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g13212" transform="rotate(-180,454.00583,490.49795)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96"/>
- <g transform="translate(-105,22)" id="g13043" style="display:inline;opacity:0.4;fill:#ffffff;enable-background:new">
- <g id="g13161" style="fill:#ffffff"/>
- </g>
- <path inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="circle21483" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" r="4" cy="335.5" cx="493.5" d="" inkscape:connector-curvature="0"/>
- <circle r="0" cx="456.5" cy="420.50391" id="ellipse20722" style="display:inline;opacity:0.1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" transform="translate(71.999999)" id="g22120"/>
- <path cx="306.99524" cy="291.97034" r="4.4703369" style="display:inline;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;enable-background:new" id="path24502" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" d="" inkscape:connector-curvature="0"/>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.15384436;enable-background:new" id="g22419" transform="matrix(-0.866668,0,0,0.866668,728.467,163.39943)"/>
- <g style="display:inline;fill:#ffffff;stroke:#666666;enable-background:new" id="g22765" transform="translate(29.999999)"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" transform="translate(46.999999,3)" id="g23484"/>
- <g style="display:inline;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="g22604" transform="translate(420,147)">
- <g style="display:inline;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" transform="matrix(0,-1,-1,0,688.99474,-44.97944)" id="g22557"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g22477" transform="rotate(180,475,353.5)"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" transform="translate(2.9786369,-3.978636)" id="g22894"/>
- <g transform="matrix(-1,0,0,1,761,0)" id="g23294" style="display:inline;fill:#ffffff;enable-background:new"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" transform="rotate(90,681.00003,3.9999745)" id="g23519"/>
- <g id="g23547" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" transform="matrix(-1,0,0,1,985.8323,-544.99999)"/>
- <g id="g6085" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 199.5,221.00391 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.5 v 1.08789 c -2.83241,0.47934 -5.00001,2.94243 -5,5.9082 0,3.30787 2.69334,6 6.00195,6 3.30861,0 6.00196,-2.69214 6.00196,-6 0,-1.22417 -0.37149,-2.36223 -1.00391,-3.3125 a 0.50005,0.50005 0 0 0 0.10352,-0.0801 l 1.75,-1.75 a 0.50005,0.50005 0 0 0 -0.36329,-0.85937 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1.75,1.75 a 0.50005,0.50005 0 0 0 -0.0117,0.0137 C 205.28833,223.73959 203.73131,223 202.00195,223 c -6.5e-4,0 -0.001,0 -0.002,0 v -0.99609 h 1.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 z M 202.00195,224 c 2.76833,0 5.00196,2.23273 5.00196,5 0,2.76726 -2.23363,5 -5.00196,5 C 199.23362,234 197,231.76727 197,229 c -1e-5,-2.76727 2.23362,-5 5.00195,-5 z" id="path17270" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 201.49219,224.99609 A 0.50005,0.50005 0 0 0 201,225.50391 v 3.91992 a 0.50005,0.50005 0 0 0 0.11328,0.40429 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.39453,0.10352 H 204.5 a 0.50005,0.50005 0 1 0 0,-1 H 202 v -3.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50782 z" id="path17274" inkscape:connector-curvature="0"/>
- </g>
- <g id="g6171" style="fill:#ffffff">
- <path sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc" inkscape:connector-curvature="0" id="path17287" d="m 405.5,476.00781 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 0.99999,-1e-5 1.99999,10e-6 3,0 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 5,1.99219 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 1,0 1.99999,10e-6 3,0 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 -1,0 -1.99999,-10e-6 -3,0 z m -5,3.00781 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 0.99999,-1e-5 1.99999,10e-6 3,0 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 5,1.99219 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 0.99999,-10e-6 1.99999,10e-6 3,0 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <g id="g17301" style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;enable-background:new" transform="translate(-41.999692,86.008184)">
- <path inkscape:connector-curvature="0" id="path17299" d="m 452.49219,387 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 V 387.5 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.0053,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66922,0 -1.3386,0 -2.00781,0 z m 4.50781,1.98438 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.0053,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.00529,0 -3.00781,0 z m 0.5,1 c 0.66922,-10e-6 1.3386,0 2.00781,0 v 2.00781 c -0.66922,0 -1.33859,0 -2.00781,0 z m -0.49219,4 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00253,0 2.0053,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.00529,0 -3.00781,0 z m 0.5,1 c 0.66922,-10e-6 1.3386,0 2.00781,0 v 2.00781 c -0.66921,0 -1.33859,0 -2.00781,0 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 201.5,389 a 0.50005,0.50005 0 0 0 -0.41406,0.2207 l -5.75,8.5 a 0.50005,0.50005 0 0 0 -0.0254,0.041 C 195.09791,398.15241 195,398.57992 195,399 c 0,1.21742 0.89627,2.23231 2.16602,2.91602 C 198.43576,402.59972 200.13233,403 202,403 c 1.86767,0 3.56424,-0.40028 4.83398,-1.08398 C 208.10373,401.23231 209,400.21742 209,399 c 0,-0.41956 -0.0964,-0.84696 -0.3125,-1.24023 a 0.50005,0.50005 0 0 0 -0.0234,-0.0391 l -5.75,-8.5 A 0.50005,0.50005 0 0 0 202.5,389 Z m 0.26562,1 h 0.46876 l 5.58007,8.24805 C 207.94195,398.48303 208,398.73145 208,399 c 0,0.71558 -0.55783,1.45211 -1.64062,2.03516 C 205.27658,401.6182 203.72216,402 202,402 c -1.72216,0 -3.27658,-0.3818 -4.35938,-0.96484 C 196.55783,400.45211 196,399.71558 196,399 c 0,-0.26272 0.0617,-0.52241 0.1875,-0.75586 z" id="path17361" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 55,389 c -3.86012,0 -7,3.13988 -7,7 0,3.86012 3.13988,7 7,7 3.86012,0 7,-3.13988 7,-7 0,-3.86012 -3.13988,-7 -7,-7 z m 0,1 c 3.31968,0 6,2.68032 6,6 0,3.31968 -2.68032,6 -6,6 -3.31968,0 -6,-2.68032 -6,-6 0,-3.31968 2.68032,-6 6,-6 z" id="path17412" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 6.5,389 A 0.50005,0.50005 0 0 0 6,389.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 19.5,389 Z m 0.5,1 h 12 v 12 H 7 Z" id="rect17430" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" id="path17434" d="m 27.5,410 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.949219 L 32,420.62695 V 423.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2.87305 L 39.550781,414 H 40.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 A 0.50005,0.50005 0 0 0 40.5,410 h -3 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -6 v -0.5 A 0.50005,0.50005 0 0 0 30.5,410 Z m 0.5,1 h 2 v 2 h -2 z m 10,0 h 2 v 2 h -2 z m -7,1 h 6 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.914062 l -3.214843,6 h -2.398438 l -3.214843,-6 H 30.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 z m 2,9 h 2 v 2 h -2 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <g id="g17481" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" transform="translate(-332.00634,585.99911)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g style="opacity:0.7;fill:#ffffff;stroke-width:1.1535517" transform="matrix(0.86707513,0,0,0.86670066,799.68613,161.07329)" id="g17477">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 432.96875,577.99609 a 0.50015801,0.499942 0 0 0 -0.0488,0.006 0.50015801,0.499942 0 0 0 -0.0879,0.0215 c -0.22504,0.005 -0.45054,4.4e-4 -0.67383,0.0273 -1.50924,0.18184 -2.95823,0.85326 -4.0957,1.98242 -2.27494,2.25834 -2.72493,5.78034 -1.08984,8.53711 1.26078,2.1257 3.51721,3.36761 5.89257,3.41407 6.5e-4,10e-6 10e-4,-2e-5 0.002,0 a 0.50015801,0.499942 0 0 0 0.32031,-0.01 c 0.60037,-0.016 1.20402,-0.0867 1.80078,-0.26367 a 0.50073965,0.5005234 0 1 0 -0.28516,-0.95899 c -0.52501,0.15567 -1.05482,0.21548 -1.58203,0.22657 -0.32205,-0.21838 -0.86207,-0.82158 -1.28906,-1.77344 -0.15847,-0.35327 -0.29568,-0.76712 -0.41992,-1.20508 H 433.5 a 0.50043241,0.50021629 0 1 0 0,-1 h -2.31641 C 431.07457,586.38509 431,585.72514 431,585 c 0,-0.72848 0.074,-1.38791 0.18359,-2 h 3.5625 c 0.15752,0.77172 0.25391,1.61389 0.25391,2.5 a 0.50015801,0.499942 0 1 0 1,0 c 0,-0.883 -0.0936,-1.71998 -0.24023,-2.5 h 2.88671 c 0.41677,1.17713 0.47801,2.4832 0.0937,3.74609 a 0.50015801,0.499942 0 1 0 0.95704,0.28907 c 0.93293,-3.06617 -0.34127,-6.37791 -3.08789,-8.03125 -1.07945,-0.64978 -2.27964,-0.96925 -3.47657,-0.99219 a 0.50015801,0.499942 0 0 0 -0.14648,-0.0156 0.50015801,0.499942 0 0 0 -0.0176,0 z m 0.0273,1.13086 c 0.3107,0.30928 0.79344,0.97648 1.16602,1.90039 0.12076,0.29947 0.23379,0.62673 0.33594,0.97266 h -3.08399 c 0.12298,-0.42695 0.25956,-0.8299 0.41602,-1.17578 0.37038,-0.81882 0.82294,-1.39159 1.16601,-1.69727 z m 1.33789,0.0312 c 0.60769,0.13919 1.20278,0.36589 1.75977,0.70118 0.89497,0.53872 1.60631,1.28287 2.10156,2.14062 h -2.66797 c -0.12978,-0.47868 -0.2726,-0.9368 -0.4375,-1.3457 -0.23548,-0.58396 -0.48644,-1.07928 -0.75586,-1.4961 z m -2.70507,0.0156 c -0.24979,0.35295 -0.49203,0.75628 -0.71094,1.24023 -0.21038,0.4651 -0.38853,1.0058 -0.53906,1.58594 h -2.5586 c 0.26045,-0.4489 0.56294,-0.87823 0.94531,-1.25781 0.81076,-0.80484 1.80942,-1.32143 2.86329,-1.56836 z m -4.26758,3.80664 A 0.50043241,0.50021629 0 0 0 427.50195,583 h 2.66993 C 430.0701,583.62227 430,584.28017 430,585 c 0,0.71751 0.0707,1.37536 0.17188,2 h -2.66993 a 0.50043241,0.50021629 0 0 0 -0.14648,0.0234 c -0.47566,-1.32219 -0.45827,-2.74775 0.006,-4.04297 z M 427.80469,588 h 2.57226 c 0.15111,0.59053 0.32906,1.14077 0.54102,1.61328 0.21198,0.47256 0.44409,0.86643 0.68555,1.21289 -1.53987,-0.36784 -2.91769,-1.3294 -3.76954,-2.76562 -0.0116,-0.0196 -0.0179,-0.0409 -0.0293,-0.0606 z" transform="matrix(1.1533026,0,0,1.1538009,-539.37632,-861.97281)" id="path17465" inkscape:connector-curvature="0"/>
- <path cx="-40.000011" cy="-186.99979" r="7.5" id="path17471" style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.1535517;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" d="" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 767.49023,1 c -0.3497,0.00648 -0.58488,0.3607678 -0.45507,0.6855469 l 2,5 c 0.1836,0.4628079 0.85703,0.4022128 0.95507,-0.085937 l 0.43946,-2.1738282 2.16797,-0.4355468 c 0.48875,-0.096787 0.55077,-0.7707095 0.0879,-0.9550782 l -5,-2 C 767.62345,1.0105047 767.55703,0.99855041 767.49023,1 Z" id="path17479" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- </g>
- <g transform="translate(41.999988,1.0000045)" id="g10697" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 35.744141,52.003906 c -0.89409,0.01843 -1.828792,0.373713 -2.597657,1.142578 l -5,5 c -0.837869,0.83787 -1.178323,2.041781 -1.11914,3.226563 0.05918,1.184782 0.515289,2.376617 1.36914,3.230469 0.852133,0.852132 2.037527,1.314671 3.220704,1.376953 1.183176,0.06228 2.389387,-0.280013 3.236328,-1.126953 l 6,-6 a 0.50005,0.50005 0 1 0 -0.707032,-0.707032 l -6,6 c -0.60312,0.603121 -1.522254,0.886172 -2.476562,0.835938 -0.954308,-0.05023 -1.918539,-0.43807 -2.566406,-1.085938 -0.646149,-0.646148 -1.030262,-1.616046 -1.078125,-2.574218 -0.04786,-0.958173 0.23781,-1.878436 0.828125,-2.46875 l 5,-5 c 1.184971,-1.184974 2.75871,-1.004381 3.554687,-0.248047 0.796393,0.756731 0.863064,2.416231 -0.261719,3.541015 l -4.5,4.5 c -0.592865,0.592866 -1.094745,0.448224 -1.417968,0.125 -0.323224,-0.323223 -0.467866,-0.825103 0.125,-1.417968 l 3.5,-3.5 a 0.50005,0.50005 0 1 0 -0.707032,-0.707032 l -3.5,3.5 c -0.907134,0.907135 -0.801776,2.155255 -0.125,2.832032 0.676777,0.676776 1.924897,0.782134 2.832032,-0.125 l 4.5,-4.5 c 1.483397,-1.483398 1.519845,-3.762437 0.24414,-4.97461 -0.60598,-0.5758 -1.459426,-0.89343 -2.353515,-0.875 z" id="path10693" inkscape:connector-curvature="0"/>
- <rect style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" id="rect10695" width="16" height="16" x="26" y="52" rx="0.5" ry="0.5"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g10711" transform="translate(598,-637)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g transform="translate(-189)" id="g10709" style="fill:#ffffff">
- <rect y="214.99997" x="-152" height="16" width="16" id="rect10699" style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate" transform="rotate(-90,-11.999985,564.99999)"/>
- <g id="g10703" style="fill:#ffffff"/>
- <path id="path10707" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m -350.42969,690.01758 c -0.79787,-0.038 -1.57177,0.27684 -2.16015,0.86523 l -1.48633,1.48828 c -0.61577,0.57533 -0.93433,1.35407 -0.89258,2.1543 a 0.50005,0.50005 0 1 0 0.99805,-0.0508 c -0.0269,-0.51495 0.15566,-0.98016 0.57617,-1.37305 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 l 1.5,-1.5 c 0.41161,-0.41161 0.88966,-0.59872 1.40429,-0.57422 0.51464,0.0245 1.08439,0.26993 1.63868,0.82422 0.55479,0.5548 0.80954,1.13546 0.83789,1.65235 0.0283,0.51688 -0.15241,0.9848 -0.57422,1.3789 a 0.50005,0.50005 0 0 0 -0.0137,0.0117 l -1.5,1.5 c -0.41213,0.41213 -0.87694,0.60352 -1.39649,0.60352 a 0.50005,0.50005 0 1 0 0,1 c 0.78067,0 1.52491,-0.31788 2.10352,-0.89649 l 1.48828,-1.48828 c 0.61768,-0.57711 0.9366,-1.36125 0.89258,-2.16406 -0.044,-0.80281 -0.43566,-1.60948 -1.13086,-2.30469 -0.69571,-0.69571 -1.49901,-1.07724 -2.29688,-1.11523 z m -6.00976,6 c -0.80753,-0.0482 -1.5954,0.26944 -2.17578,0.89062 l -1.48829,1.48828 c -0.58838,0.58839 -0.90322,1.36034 -0.86523,2.15821 0.038,0.79787 0.41952,1.60311 1.11523,2.29883 0.69521,0.6952 1.50384,1.08487 2.30664,1.1289 0.80281,0.044 1.585,-0.27294 2.16211,-0.89062 l 1.48829,-1.48828 C -353.31787,701.0249 -353,700.28067 -353,699.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.51955 -0.19139,0.98436 -0.60352,1.39648 l -1.5,1.5 a 0.50005,0.50005 0 0 0 -0.0117,0.0117 c -0.39411,0.42182 -0.86007,0.60452 -1.37696,0.57618 -0.51688,-0.0283 -1.0995,-0.2831 -1.65429,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.82227,-1.63867 -0.0245,-0.51463 0.16065,-0.99268 0.57227,-1.40429 l 1.5,-1.5 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 c 0.39634,-0.4242 0.86629,-0.60725 1.38672,-0.57618 a 0.50005,0.50005 0 1 0 0.0586,-0.99804 z m 4.92968,-2.02149 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -5,5 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 5,-5 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z" inkscape:connector-curvature="0"/>
- </g>
- </g>
- <g transform="translate(-252,-252)" id="g10731" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 328,368 c -3.86007,0 -7,3.13993 -7,7 0,3.86007 3.13993,7 7,7 3.86007,0 7,-3.13993 7,-7 0,-3.86007 -3.13993,-7 -7,-7 z m 0,1 c 3.31963,0 6,2.68037 6,6 0,3.31963 -2.68037,6 -6,6 -3.31963,0 -6,-2.68037 -6,-6 0,-3.31963 2.68037,-6 6,-6 z" id="path10721" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 327.12891,369.9668 a 1.0001,1.0001 0 0 0 -0.16797,0.0234 c -2.00329,0.41569 -3.57155,1.99062 -3.97656,3.9961 a 1.0003053,1.0003053 0 1 0 1.96093,0.39648 c 0.24758,-1.22589 1.19732,-2.17949 2.42188,-2.43359 a 1.0001,1.0001 0 0 0 -0.23828,-1.98242 z" id="path10723" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 332.49609,373.0957 a 0.40004001,0.40004001 0 0 0 -0.27929,0.6875 l 2,2 a 0.40050528,0.40050528 0 1 0 0.5664,-0.5664 l -2,-2 a 0.40004001,0.40004001 0 0 0 -0.28711,-0.1211 z m -0.75,2.25 a 0.40004001,0.40004001 0 0 0 -0.27929,0.6875 l 2,2 a 0.40050528,0.40050528 0 1 0 0.5664,-0.5664 l -2,-2 a 0.40004001,0.40004001 0 0 0 -0.28711,-0.1211 z m -1.25,1.75 a 0.40004001,0.40004001 0 0 0 -0.27929,0.6875 l 2,2 a 0.40050528,0.40050528 0 1 0 0.5664,-0.5664 l -2,-2 a 0.40004001,0.40004001 0 0 0 -0.28711,-0.1211 z m -1.75,1.25 a 0.40004001,0.40004001 0 0 0 -0.27929,0.6875 l 2,2 a 0.40050528,0.40050528 0 1 0 0.5664,-0.5664 l -2,-2 a 0.40004001,0.40004001 0 0 0 -0.28711,-0.1211 z m -2.23632,0.75 a 0.40004001,0.40004001 0 0 0 -0.27344,0.70508 l 2,1.75 a 0.40004001,0.40004001 0 1 0 0.52734,-0.60156 l -2,-1.75 a 0.40004001,0.40004001 0 0 0 -0.2539,-0.10352 z" id="path10727" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g15743" transform="translate(221,4.4999696e-6)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M -98.580078,578 C -99.98888,578 -101,579.16322 -101,580.5 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.87198 0.530524,-1.5 1.419922,-1.5 0.889383,0 1.580078,0.67678 1.580078,1.5 0,0.82323 -0.69069,1.49999 -1.580078,1.5 h -4.914062 a 0.50005,0.50005 0 1 0 0,1 h 4.914062 C -97.171286,582.99999 -96,581.88555 -96,580.5 c 0,-1.38554 -1.171281,-2.5 -2.580078,-2.5 z m -8.916012,0.004 c -1.38554,0 -2.5,1.17128 -2.5,2.58007 0,1.40881 1.16321,2.41797 2.5,2.41797 a 0.50005,0.50005 0 1 0 0,-1 c -0.87198,0 -1.5,-0.52857 -1.5,-1.41797 0,-0.88938 0.67678,-1.58007 1.5,-1.58007 0.82323,0 1.49804,0.69069 1.49804,1.58007 v 4.91211 a 0.50005,0.50005 0 1 0 1,0 v -4.91211 c -10e-6,-1.40879 -1.1125,-2.58007 -2.49804,-2.58007 z m 6.98828,5.98828 A 0.50005,0.50005 0 0 0 -101,584.5 v 4.91211 c 1e-5,1.40879 1.114453,2.58008 2.5,2.58008 1.385539,0 2.5,-1.17128 2.5,-2.58008 0,-1.4088 -1.163215,-2.41992 -2.5,-2.41992 a 0.50005,0.50005 0 1 0 0,1 c 0.871975,0 1.5,0.53052 1.5,1.41992 0,0.88938 -0.676779,1.58008 -1.5,1.58008 -0.823233,0 -1.499992,-0.69069 -1.5,-1.58008 V 584.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -6.90821,3.0039 c -1.40879,2e-5 -2.58007,1.11446 -2.58007,2.5 0,1.38554 1.17128,2.5 2.58007,2.5 1.40881,0 2.41993,-1.16321 2.41993,-2.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.87198 -0.53053,1.5 -1.41993,1.5 -0.88938,0 -1.58007,-0.67678 -1.58007,-1.5 0,-0.82323 0.69069,-1.49999 1.58007,-1.5 h 4.91211 a 0.50005,0.50005 0 1 0 0,-1 z" id="path10848" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-84.000002,1.45e-5)" id="g10880" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g transform="translate(-523,-55.999969)" id="g10853" style="fill:#ffffff"/>
- <g id="g10878" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 157.49219,453.99222 A 0.50005,0.50005 0 0 0 157,454.50003 v 4 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" id="path10874" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 80.476562,451.02148 a 0.50005,0.50005 0 0 0 -0.314453,0.8711 c 0.58809,0.54453 0.841797,1.0856 0.841797,1.60156 L 81,459.5 a 0.50005,0.50005 0 1 0 1,0 l 0.0039,-6.00586 c 0,-0.8509 -0.431789,-1.65971 -1.162109,-2.33594 a 0.50005,0.50005 0 0 0 -0.365235,-0.13672 z M 71.5625,452 C 69.59752,452 68,453.59753 68,455.5625 v 7.875 C 68,465.40247 69.59752,467 71.5625,467 h 3.875 C 77.40247,467 79,465.40247 79,463.4375 v -7.875 C 79,453.59753 77.40247,452 75.4375,452 Z m 0,1 h 3.875 C 76.86577,453 78,454.13423 78,455.5625 v 7.875 C 78,464.86577 76.86577,466 75.4375,466 h -3.875 C 70.13422,466 69,464.86577 69,463.4375 v -7.875 C 69,454.13423 70.13422,453 71.5625,453 Z m 11.929688,0.0371 A 0.50005,0.50005 0 0 0 83,453.54297 v 4.05859 a 0.50005,0.50005 0 1 0 1,0 v -4.05859 a 0.50005,0.50005 0 0 0 -0.507812,-0.50586 z" transform="translate(84.000002,-1.449997e-5)" id="rect10876" inkscape:connector-curvature="0"/>
- </g>
- </g>
- <path inkscape:connector-curvature="0" id="path10927" d="m 10.484375,452 c -0.752,0 -1.4538175,0.239 -2.0234375,0.64453 C 7.5752675,453.27508 7,454.31514 7,455.48438 V 458.5 c 3e-5,0.27537 0.2226769,0.4989 0.4980469,0.5 l 4.0097651,0.008 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 L 12,452.53516 v -0.002 -0.0352 C 11.999,452.22272 11.77534,452.00003 11.5,452 Z M 13,452 v 1 h 1.515625 C 15.900145,453 17,454.09985 17,455.48438 v 8.03124 C 17,464.90014 15.900145,466 14.515625,466 h -4.03125 C 9.099855,466 8,464.90014 8,463.51562 V 460 H 7 v 3.51562 C 7,465.43685 8.563145,467 10.484375,467 h 4.03125 C 16.436855,467 18,465.43686 18,463.51562 v -8.03124 C 18,453.56315 16.436855,452 14.515625,452 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="rect10947" d="M 31.484375,452 C 29.563145,452 28,453.56315 28,455.48438 v 8.03124 C 28,465.43685 29.563145,467 31.484375,467 h 4.03125 C 37.436855,467 39,465.43685 39,463.51562 v -8.03124 C 39,453.56315 37.436855,452 35.515625,452 Z m 0,1 h 4.03125 C 36.900155,453 38,454.09985 38,455.48438 v 8.03124 C 38,464.90015 36.900155,466 35.515625,466 h -4.03125 C 30.099845,466 29,464.90015 29,463.51562 v -8.03124 C 29,454.09985 30.099845,453 31.484375,453 Z m 1.5625,1 C 32.475545,454 32,454.47555 32,455.04688 v 3.90624 C 32,459.52445 32.475545,460 33.046875,460 h 0.90625 C 34.524455,460 35,459.52445 35,458.95312 v -3.90624 C 35,454.47555 34.524455,454 33.953125,454 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 69.492188,306 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z" id="path10850" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 48.492188,306 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 7,3 a 0.50005,0.50005 0 1 0 0,1 h 5.99414 a 0.50005,0.50005 0 1 0 0,-1 z m -7,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 7,3 a 0.50005,0.50005 0 1 0 0,1 h 5.99414 a 0.50005,0.50005 0 1 0 0,-1 z m -7,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z" id="path10852" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 27.492188,306 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 4,3 a 0.50005,0.50005 0 1 0 0,1 h 4.99414 a 0.50005,0.50005 0 1 0 0,-1 z m -4,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 4,3 a 0.50005,0.50005 0 1 0 0,1 h 4.99414 a 0.50005,0.50005 0 1 0 0,-1 z m -4,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z" id="path10854" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 6.5,306 a 0.50005,0.50005 0 1 0 0,1 h 12.992188 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 5.992188 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.992188 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 5.992188 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.992188 a 0.50005,0.50005 0 1 0 0,-1 z" id="path10856" inkscape:connector-curvature="0"/>
- <g transform="translate(-462.00711,-314.99994)" id="g10872" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:2.20000005;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 552.5,621 a 0.50005,0.50005 0 1 0 0,1 h 1.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 4.02344,0 a 0.50005,0.50005 0 1 0 0,1 h 1.91601 a 0.50005,0.50005 0 1 0 0,-1 z m 3.9707,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99805 a 0.50005,0.50005 0 1 0 0,-1 z m 3.99805,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z M 552.5,624 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99805 a 0.50005,0.50005 0 1 0 0,-1 z m 4.05273,0 a 0.50005,0.50005 0 1 0 0,1 h 1.91797 a 0.50005,0.50005 0 1 0 0,-1 z m 3.94727,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99219 a 0.50005,0.50005 0 1 0 0,-1 z m -11,3 a 0.50005,0.50005 0 1 0 0,1 h 1.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 4.02344,0 a 0.50005,0.50005 0 1 0 0,1 h 1.91601 a 0.50005,0.50005 0 1 0 0,-1 z m 3.9707,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99805 a 0.50005,0.50005 0 1 0 0,-1 z m 3.99805,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z M 552.5,630 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99805 a 0.50005,0.50005 0 1 0 0,-1 z m 4.05273,0 a 0.50005,0.50005 0 1 0 0,1 h 1.91797 a 0.50005,0.50005 0 1 0 0,-1 z m 3.94727,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99219 a 0.50005,0.50005 0 1 0 0,-1 z m -11,3 a 0.50005,0.50005 0 1 0 0,1 h 1.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 4.02344,0 a 0.50005,0.50005 0 1 0 0,1 h 1.91601 a 0.50005,0.50005 0 1 0 0,-1 z m 3.9707,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99805 a 0.50005,0.50005 0 1 0 0,-1 z m 3.99805,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z" id="path10870" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 201.49219,305 a 0.50005,0.50005 0 1 0 0,1 h 2.5039 l -0.002,0.14258 -4.95898,11.4082 a 0.50005,0.50005 0 0 0 -0.041,0.21289 L 199,318 h -2.50781 a 0.50005,0.50005 0 1 0 0,1 h 6 a 0.50005,0.50005 0 1 0 0,-1 H 200 a 0.50005,0.50005 0 0 0 0,-0.0137 l -0.004,-0.13867 4.95508,-11.39844 a 0.50005,0.50005 0 0 0 0.041,-0.19141 L 204.99609,306 h 2.4961 a 0.50005,0.50005 0 1 0 0,-1 z" id="path10892" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 216.49219,305 a 0.50005,0.50005 0 1 0 0,1 H 218 v 6.00391 c 0,2.19985 1.79782,3.99206 4,3.99609 h 1 a 0.50005,0.50005 0 0 0 0.002,0 c 2.20199,-0.005 3.998,-1.79624 3.998,-3.99609 V 306 h 1.49219 a 0.50005,0.50005 0 1 0 0,-1 h -4 a 0.50005,0.50005 0 1 0 0,1 H 226 v 6.00391 c 0,1.65832 -1.33799,2.99265 -3.00195,2.99609 H 222 c -1.66382,-0.003 -3,-1.33777 -3,-2.99609 V 306 h 1.49219 a 0.50005,0.50005 0 1 0 0,-1 z m 1,13 a 0.50005,0.50005 0 1 0 0,1 h 10 a 0.50005,0.50005 0 1 0 0,-1 z" id="path10901" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 111.5,305 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 13 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 13 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -13 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z" id="rect10983" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 113.49219,307 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z" id="path10977" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 132.5,305 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 13 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 13 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -13 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z" id="rect11046" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 134.49219,310 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z" id="path11048" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 153.5,305 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 13 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 13 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -13 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z" id="rect11050" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 155.49219,314 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z" id="path11052" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 177,305 a 1.0001,1.0001 0 0 0 -1,1 v 5.83203 a 1.0001,1.0001 0 0 0 0,0.32617 V 318 a 1.0001,1.0001 0 0 0 1,1 h 6 c 2.19729,0 4,-1.80271 4,-4 0,-1.76747 -1.1852,-3.22799 -2.78516,-3.75195 C 184.67235,310.59788 185,309.84948 185,309 c 0,-2.19729 -1.80271,-4 -4,-4 z m 1,2 h 3 c 1.11641,0 2,0.88359 2,2 0,1.11641 -0.88359,2 -2,2 h -3 z m 0,6 h 3 2 c 1.11641,0 2,0.88359 2,2 0,1.11641 -0.88359,2 -2,2 h -5 z" id="path10949" inkscape:connector-curvature="0"/>
- <g transform="matrix(0,1,1,0,37.999948,363)" id="g11084" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 202,473 c -3.86007,0 -7,3.13993 -7,7 0,3.86007 3.13993,7 7,7 3.86007,0 7,-3.13993 7,-7 0,-3.86007 -3.13993,-7 -7,-7 z m 0,1 c 1.09865,0 2,0.90135 2,2 0,1.09865 -0.90135,2 -2,2 -1.09865,0 -2,-0.90135 -2,-2 0,-1.09865 0.90135,-2 2,-2 z m -4,4 c 1.09865,0 2,0.90135 2,2 0,1.09865 -0.90135,2 -2,2 -1.09865,0 -2,-0.90135 -2,-2 0,-1.09865 0.90135,-2 2,-2 z m 8,0 c 1.09865,0 2,0.90135 2,2 0,1.09865 -0.90135,2 -2,2 -1.09865,0 -2,-0.90135 -2,-2 0,-1.09865 0.90135,-2 2,-2 z m -4,1 c 0.54636,0 1,0.45364 1,1 0,0.54636 -0.45364,1 -1,1 -0.54636,0 -1,-0.45364 -1,-1 0,-0.54636 0.45364,-1 1,-1 z m 0,3 c 1.09865,0 2,0.90135 2,2 0,1.09865 -0.90135,2 -2,2 -1.09865,0 -2,-0.90135 -2,-2 0,-1.09865 0.90135,-2 2,-2 z m 4.96484,4 a 0.50005,0.50005 0 0 0 -0.47265,0.49219 A 0.50005,0.50005 0 0 0 207,487 h 0.5 c 0.83333,0 1.14655,0.35353 1.64648,0.85352 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 C 209.35355,486.64647 208.66667,486 207.5,486 H 207 a 0.50005,0.50005 0 0 0 -0.0352,0 z" transform="matrix(0,1,1,0,-363,-37.999948)" id="circle11078" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" id="g13852" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96" style="display:inline;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new">
- <g id="g11167" transform="matrix(0,-1,-1,0,688.99474,-44.97944)" style="display:inline;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 14.505859,263.01562 a 0.55005501,0.55005501 0 0 0 -0.05664,0.004 c -1.480032,0.16258 -2.81124,0.9768 -3.632813,2.21875 -0.754587,1.14068 -0.9438173,2.54615 -0.65039,3.875 l -3.5234379,3.52149 c -0.4164576,0.37981 -0.6354253,0.95498 -0.6601562,1.61328 -0.024627,0.65553 0.1896767,1.40646 0.7832031,2 0.5945619,0.59455 1.3481437,0.80114 1.9980469,0.76953 0.6519363,-0.0317 1.2112985,-0.25543 1.5917971,-0.63672 l 3.533203,-3.54297 c 1.328363,0.29148 2.734045,0.0991 3.873047,-0.6543 1.240498,-0.82051 2.05459,-2.151 2.21875,-3.6289 a 0.55005501,0.55005501 0 0 0 -0.160157,-0.45117 l -0.943359,-0.92969 a 0.55005501,0.55005501 0 0 0 -0.775391,0.002 l -1.80664,1.79883 h -0.589844 l -1.679687,-1.67969 v -0.58984 l 1.804687,-1.80078 a 0.55005501,0.55005501 0 0 0 0.0039,-0.77539 l -0.93164,-0.94727 a 0.55005501,0.55005501 0 0 0 -0.396485,-0.16602 z m -0.15625,1.17383 0.316407,0.32227 -1.580078,1.57617 a 0.55005501,0.55005501 0 0 0 -0.16211,0.39063 l 0.002,1.04687 a 0.55005501,0.55005501 0 0 0 0.16211,0.38672 l 2.001953,2.00195 a 0.55005501,0.55005501 0 0 0 0.388672,0.16211 l 1.046875,-0.002 a 0.55005501,0.55005501 0 0 0 0.386718,-0.16016 l 1.580079,-1.57422 0.318359,0.31446 c -0.183326,1.05859 -0.751902,2.01444 -1.654297,2.61132 -0.970627,0.64202 -2.219467,0.82961 -3.330078,0.49219 a 0.55005501,0.55005501 0 0 0 -0.548828,0.13672 l -3.699219,3.70899 c -0.1021327,0.10234 -0.4754005,0.29532 -0.8691406,0.31445 -0.395773,0.0192 -0.8021096,-0.0834 -1.1660156,-0.44727 -0.3650748,-0.36508 -0.4778317,-0.78393 -0.4628907,-1.18164 0.014838,-0.39496 0.2099663,-0.75541 0.3046875,-0.84179 a 0.55005501,0.55005501 0 0 0 0.017578,-0.0176 l 3.7070314,-3.70508 a 0.55005501,0.55005501 0 0 0 0.136719,-0.54883 c -0.339386,-1.11269 -0.154519,-2.36033 0.488281,-3.33203 0.59791,-0.90384 1.555081,-1.47203 2.615234,-1.6543 z" id="path11179" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(62.999978,21.041695)" id="g11141" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g transform="translate(-126)" id="g11139" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 206.72656,599 c -0.19328,-0.004 -0.38654,0.0132 -0.57422,0.0508 -0.75071,0.15014 -1.44693,0.5778 -2.00586,1.13672 l -2.14453,2.10742 -1.14843,-1.14844 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 1.64649,1.64648 -4.64844,4.68945 A 0.50005,0.50005 0 0 0 197,608.54102 v 0.79296 l -1.85352,1.85352 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 2,-2 A 0.50005,0.50005 0 0 0 198,609.54102 v -0.79493 l 4.50195,-4.53711 1.29297,1.29297 -4.5039,4.53907 H 198.5 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -2,2 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 1.85351,-1.85351 H 199.5 a 0.50005,0.50005 0 0 0 0.35547,-0.14844 l 4.64648,-4.6836 1.64453,1.64454 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.14258,-1.14257 2.13867,-2.10547 0.004,-0.004 c 0.55892,-0.55893 0.98657,-1.25515 1.13671,-2.00586 0.15015,-0.75072 -0.0189,-1.58331 -0.63671,-2.20117 -0.4634,-0.46339 -1.04712,-0.67435 -1.62696,-0.6875 z" transform="translate(63.000022,-21.041695)" id="path11133" inkscape:connector-curvature="0"/>
- </g>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g13475" transform="translate(-21.000002,4.4999696e-6)">
- <path sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccccccccc" mask="none" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" d="m 111,515 v 2 h 2 v -2 z m 2,2 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 2,0 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 2,0 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 0,2 v 2 h 2 v -2 z m -10,2 v -2 h -2 v 2 z m 2,0 h 2 v -2 h -2 z m 4,0 h 2 v -2 h -2 z" id="path12185" inkscape:connector-curvature="0"/>
- <g transform="translate(63,-231)" id="g12189" style="opacity:0.6;fill:#ffffff">
- <path id="path12187" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" d="m 48,753 v 3.5 c 0,0.82843 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67157 1.5,-1.5 V 756 c 0,-0.5 0.53412,-1 1,-1 0.55229,0 1,0.44772 1,1 v 2.5 c 0,0.82843 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67157 1.5,-1.5 V 757 c 0,-0.55228 0.44772,-1 1,-1 0.55229,0 1,-0.44771 1,-1 v -2 h -2 v 0 h -2 v 0 h -2 v 0 h -2 v 0 z" inkscape:connector-curvature="0" sodipodi:nodetypes="csssssssssssscccccccccc"/>
- </g>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" transform="matrix(-1,0,0,1,88.999998,-231)" id="g12197">
- <path inkscape:connector-curvature="0" id="path12191" transform="matrix(-1,0,0,1,90,231)" d="m 75,519 v 7 c 0,0.5 0.25,1 1,1 0.75,0 1,-0.5 1,-1 v -1 c 0,-0.5 0.53412,-1 1,-1 0.55229,0 1,0.44772 1,1 v 2.5 c 0,0.82843 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67157 1.5,-1.5 V 526 c 0,-0.55228 0.44772,-1 1,-1 0.55229,0 1,-0.44771 1,-1 v -3.08789 A 1.50015,1.50015 0 0 1 83.5,521 h -3 A 1.50015,1.50015 0 0 1 79,519.5 V 519 Z" style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 16.5,746 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -6 v -0.5 A 0.50005,0.50005 0 0 0 9.5,747 h -3 A 0.50005,0.50005 0 0 0 6,747.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 A 0.50005,0.50005 0 0 0 10,750.5 V 749 h 6 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 A 0.50005,0.50005 0 0 0 19.5,746 Z m 0.5,1 h 2 v 2 h -2 z m -10,1 h 2 v 2 H 7 Z" id="path12195" inkscape:connector-curvature="0"/>
- </g>
- <g id="g17491" transform="matrix(0.875,0,0,0.875,264.125,159.75)" style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.14285719;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <rect y="430" x="257" height="16" width="16" id="rect17483" style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3.42857146;marker:none;enable-background:accumulate"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 496,535.9375 c -2.73936,0 -5.1213,1.56371 -6.29102,3.84961 -0.49329,0.96401 -0.77148,2.05765 -0.77148,3.21289 0,3.89459 3.16791,7.0625 7.0625,7.0625 3.89459,0 7.0625,-3.16791 7.0625,-7.0625 0,-3.89459 -3.16791,-7.0625 -7.0625,-7.0625 z m 0,1 c 3.35415,0 6.0625,2.70835 6.0625,6.0625 0,3.35415 -2.70834,6.0625 -6.0625,6.0625 -3.35415,0 -6.0625,-2.70835 -6.0625,-6.0625 0,-0.99492 0.23889,-1.93072 0.66211,-2.75781 1.00359,-1.96124 3.04116,-3.30469 5.40039,-3.30469 z M 496,538 a 0.99999996,0.99999996 0 0 0 -1,1 0.99999996,0.99999996 0 0 0 1,1 0.99999996,0.99999996 0 0 0 1,-1 0.99999996,0.99999996 0 0 0 -1,-1 z m -2.82422,1.16211 a 1.0001001,1.0001001 0 0 0 -0.6875,0.30469 c -0.61854,0.6208 -1.06287,1.393 -1.28906,2.24023 a 1.0001001,1.0001001 0 1 0 1.93164,0.51563 c 0.13595,-0.50922 0.40262,-0.97353 0.77344,-1.34571 a 1.0001001,1.0001001 0 0 0 -0.72852,-1.71484 z" transform="matrix(1.1428571,0,0,1.1428571,-301.85714,-182.57143)" id="path17485" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;stroke-width:1.09730649;enable-background:new" transform="matrix(1,0,0,0.83050847,1300,-195.57627)" id="g8019-1">
- <path sodipodi:nodetypes="cccccccccc" inkscape:connector-curvature="0" d="m -1207,502.79592 v 14.44898 h 2 v -14.44898 z m 6,0 v 14.44898 h 2 v -14.44898 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.19461298;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" id="path8013-3"/>
- </g>
- <path style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" d="m 16.999998,228 a 4,4 0 0 1 -4,4 4,4 0 0 1 -3.9999999,-4 4,4 0 0 1 3.9999999,-4 4,4 0 0 1 4,4 z" id="circle8021-5" inkscape:connector-curvature="0"/>
- <g id="g5627" style="fill:#ffffff">
- <g id="g5620" style="fill:#ffffff">
- <g id="g5614" style="fill:#ffffff">
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" transform="translate(-42.000002,21.000005)" id="g4035-9" style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 99,599 c -2.74773,0 -5,2.25226 -5,5 0,1.1945 0.441488,2.28163 1.148438,3.14453 l -5.001954,5.00195 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 5.001953,-5.00196 C 96.718369,608.55851 97.805503,609 99,609 c 2.74773,0 5,-2.25227 5,-5 0,-2.74774 -2.25227,-5 -5,-5 z m 0,1 c 2.20227,0 4,1.79773 4,4 0,2.20226 -1.79773,4 -4,4 -2.20227,0 -4,-1.79774 -4,-4 0,-2.20227 1.79773,-4 4,-4 z" transform="translate(42.000002,-21.000005)" id="path4031-4" inkscape:connector-curvature="0"/>
- </g>
- </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer8"
+ inkscape:label="2.81"
+ style="display:inline">
+ <path
+ inkscape:connector-curvature="0"
+ id="path6587"
+ d="M 61.503909,123 A 6.5039066,6.5039066 0 0 1 55.000003,129.50391 6.5039066,6.5039066 0 0 1 48.496097,123 6.5039066,6.5039066 0 0 1 55.000003,116.4961 6.5039066,6.5039066 0 0 1 61.503909,123 Z"
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <g
+ id="g10975"
+ transform="translate(-378.00707,-293.99994)"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ <g
+ id="g10009"
+ transform="translate(5.3904633e-4,-20.999933)"
+ style="display:inline;opacity:1;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ <g
+ transform="translate(-380,231)"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g12153"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ transform="translate(-336.00001,210.00001)"
+ id="g12215"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12492"
+ transform="translate(20.999999)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ <g
+ id="g12457"
+ transform="matrix(0.69230791,0,0,0.69230793,-403.07713,196.14887)"
+ style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.44444394;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12921"
+ transform="translate(21.999999,-3)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ <g
+ style="display:inline;opacity:0.41300001;fill:#ffffff;enable-background:new"
+ id="g5202-0"
+ transform="translate(496.99495,-311.99288)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13534"
+ transform="translate(-9.5367432e-7,21)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g13838"
+ transform="rotate(90,160.07935,395.5873)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ id="g13835"
+ transform="matrix(0,1,1,0,205.49208,-205.33334)"
+ style="fill:#ffffff" />
+ </g>
+ <g
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
+ id="g6922"
+ transform="translate(-378.0172,105)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <circle
+ r="0"
+ cy="162.5"
+ cx="415.5"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ id="ellipse13645" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;stroke-width:1.15384614;enable-background:new"
+ id="g14341"
+ transform="translate(-441.00001,525.00001)" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14199"
+ transform="translate(-9.5367432e-7,20)" />
+ <g
+ style="display:inline;fill:#ffffff;stroke:#666666;enable-background:new"
+ id="g14215"
+ inkscape:transform-center-x="-1.2499"
+ inkscape:transform-center-y="9.9999999e-006"
+ transform="matrix(0,-1,-1,0,723.9999,577.00011)" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14644"
+ transform="translate(-9.5367432e-7,30)" />
+ <circle
+ transform="scale(-1)"
+ cy="-286.5"
+ cx="-353.50003"
+ id="ellipse14264"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ r="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13212"
+ transform="rotate(-180,454.00583,490.49795)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ <g
+ transform="translate(-105,22)"
+ id="g13043"
+ style="display:inline;opacity:0.4;fill:#ffffff;enable-background:new">
+ <g
+ id="g13161"
+ style="fill:#ffffff" />
+ </g>
+ <path
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ id="circle21483"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ r="4"
+ cy="335.5"
+ cx="493.5"
+ d=""
+ inkscape:connector-curvature="0" />
+ <circle
+ r="0"
+ cx="456.5"
+ cy="420.50391"
+ id="ellipse20722"
+ style="display:inline;opacity:0.1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="translate(71.999999)"
+ id="g22120" />
+ <path
+ cx="306.99524"
+ cy="291.97034"
+ r="4.4703369"
+ style="display:inline;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;enable-background:new"
+ id="path24502"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ d=""
+ inkscape:connector-curvature="0" />
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.15384436;enable-background:new"
+ id="g22419"
+ transform="matrix(-0.866668,0,0,0.866668,728.467,163.39943)" />
+ <g
+ style="display:inline;fill:#ffffff;stroke:#666666;enable-background:new"
+ id="g22765"
+ transform="translate(29.999999)" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(46.999999,3)"
+ id="g23484" />
+ <g
+ style="display:inline;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ id="g22604"
+ transform="translate(420,147)">
+ <g
+ style="display:inline;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="matrix(0,-1,-1,0,688.99474,-44.97944)"
+ id="g22557" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22477"
+ transform="rotate(180,475,353.5)" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(2.9786369,-3.978636)"
+ id="g22894" />
+ <g
+ transform="matrix(-1,0,0,1,761,0)"
+ id="g23294"
+ style="display:inline;fill:#ffffff;enable-background:new" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="rotate(90,681.00003,3.9999745)"
+ id="g23519" />
+ <g
+ id="g23547"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ transform="matrix(-1,0,0,1,985.8323,-544.99999)" />
+ <g
+ id="g6085"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 199.5,221.00391 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.5 v 1.08789 c -2.83241,0.47934 -5.00001,2.94243 -5,5.9082 0,3.30787 2.69334,6 6.00195,6 3.30861,0 6.00196,-2.69214 6.00196,-6 0,-1.22417 -0.37149,-2.36223 -1.00391,-3.3125 a 0.50005,0.50005 0 0 0 0.10352,-0.0801 l 1.75,-1.75 a 0.50005,0.50005 0 0 0 -0.36329,-0.85937 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1.75,1.75 a 0.50005,0.50005 0 0 0 -0.0117,0.0137 C 205.28833,223.73959 203.73131,223 202.00195,223 c -6.5e-4,0 -0.001,0 -0.002,0 v -0.99609 h 1.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 z M 202.00195,224 c 2.76833,0 5.00196,2.23273 5.00196,5 0,2.76726 -2.23363,5 -5.00196,5 C 199.23362,234 197,231.76727 197,229 c -1e-5,-2.76727 2.23362,-5 5.00195,-5 z"
+ id="path17270"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 201.49219,224.99609 A 0.50005,0.50005 0 0 0 201,225.50391 v 3.91992 a 0.50005,0.50005 0 0 0 0.11328,0.40429 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.39453,0.10352 H 204.5 a 0.50005,0.50005 0 1 0 0,-1 H 202 v -3.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50782 z"
+ id="path17274"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g6171"
+ style="fill:#ffffff">
+ <path
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path17287"
+ d="m 405.5,476.00781 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 0.99999,-1e-5 1.99999,10e-6 3,0 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 5,1.99219 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 1,0 1.99999,10e-6 3,0 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 -1,0 -1.99999,-10e-6 -3,0 z m -5,3.00781 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 0.99999,-1e-5 1.99999,10e-6 3,0 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 5,1.99219 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 0.99999,-10e-6 1.99999,10e-6 3,0 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <g
+ id="g17301"
+ style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;enable-background:new"
+ transform="translate(-41.999692,86.008184)">
+ <path
+ inkscape:connector-curvature="0"
+ id="path17299"
+ d="m 452.49219,387 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 V 387.5 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.0053,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66922,0 -1.3386,0 -2.00781,0 z m 4.50781,1.98438 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.0053,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.00529,0 -3.00781,0 z m 0.5,1 c 0.66922,-10e-6 1.3386,0 2.00781,0 v 2.00781 c -0.66922,0 -1.33859,0 -2.00781,0 z m -0.49219,4 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00253,0 2.0053,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.00529,0 -3.00781,0 z m 0.5,1 c 0.66922,-10e-6 1.3386,0 2.00781,0 v 2.00781 c -0.66921,0 -1.33859,0 -2.00781,0 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
</g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g12132" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:7.17647076;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 202.5,578 c -3.57273,0 -6.5,2.92727 -6.5,6.5 0,1.60752 0.59683,3.08042 1.57422,4.21875 l -2.42774,2.42773 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2.42578,-2.42579 c 1.13822,0.977 2.61355,1.57227 4.2207,1.57227 3.57273,0 6.5,-2.92728 6.5,-6.5 0,-3.57273 -2.92727,-6.5 -6.5,-6.5 z m 0,1 c 3.02727,0 5.5,2.47272 5.5,5.5 0,3.02727 -2.47273,5.5 -5.5,5.5 -3.02727,0 -5.5,-2.47273 -5.5,-5.5 0,-3.02728 2.47273,-5.5 5.5,-5.5 z m -0.008,1.99219 A 0.50005,0.50005 0 0 0 202,581.5 v 2.5 h -2.5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 2.5 a 0.50005,0.50005 0 1 0 1,0 V 585 h 2.5 a 0.50005,0.50005 0 1 0 0,-1 H 203 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" transform="translate(1.8536743e-6,-4.4999696e-6)" id="path4043-7" inkscape:connector-curvature="0"/>
- <g id="g4159-3" transform="translate(61.94871,1.10183)" style="display:inline;fill:#ffffff;enable-background:new"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate" id="rect4248-2" width="16" height="16" x="193.95" y="577.04999"/>
- </g>
- <g id="g7089-6" style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" transform="matrix(-0.75,0,0,0.75,348.75712,418.75712)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g id="g7087-1" style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 118.51367,601 a 0.50005001,0.50005001 0 0 0 -0.50586,0.50586 v 3.50195 h -3.50195 a 0.50005001,0.50005001 0 1 0 0,0.99805 h 3.50195 v 3.50195 a 0.50005001,0.50005001 0 1 0 0.99805,0 v -3.50195 h 3.50195 a 0.50005001,0.50005001 0 1 0 0,-0.99805 h -3.50195 v -3.50195 A 0.50005001,0.50005001 0 0 0 118.51367,601 Z" transform="matrix(-1.3333333,0,0,1.3333333,465.00949,-558.34283)" id="path7083-5" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 201.5,389 a 0.50005,0.50005 0 0 0 -0.41406,0.2207 l -5.75,8.5 a 0.50005,0.50005 0 0 0 -0.0254,0.041 C 195.09791,398.15241 195,398.57992 195,399 c 0,1.21742 0.89627,2.23231 2.16602,2.91602 C 198.43576,402.59972 200.13233,403 202,403 c 1.86767,0 3.56424,-0.40028 4.83398,-1.08398 C 208.10373,401.23231 209,400.21742 209,399 c 0,-0.41956 -0.0964,-0.84696 -0.3125,-1.24023 a 0.50005,0.50005 0 0 0 -0.0234,-0.0391 l -5.75,-8.5 A 0.50005,0.50005 0 0 0 202.5,389 Z m 0.26562,1 h 0.46876 l 5.58007,8.24805 C 207.94195,398.48303 208,398.73145 208,399 c 0,0.71558 -0.55783,1.45211 -1.64062,2.03516 C 205.27658,401.6182 203.72216,402 202,402 c -1.72216,0 -3.27658,-0.3818 -4.35938,-0.96484 C 196.55783,400.45211 196,399.71558 196,399 c 0,-0.26272 0.0617,-0.52241 0.1875,-0.75586 z"
+ id="path17361"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 55,389 c -3.86012,0 -7,3.13988 -7,7 0,3.86012 3.13988,7 7,7 3.86012,0 7,-3.13988 7,-7 0,-3.86012 -3.13988,-7 -7,-7 z m 0,1 c 3.31968,0 6,2.68032 6,6 0,3.31968 -2.68032,6 -6,6 -3.31968,0 -6,-2.68032 -6,-6 0,-3.31968 2.68032,-6 6,-6 z"
+ id="path17412"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 6.5,389 A 0.50005,0.50005 0 0 0 6,389.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 19.5,389 Z m 0.5,1 h 12 v 12 H 7 Z"
+ id="rect17430"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path17434"
+ d="m 27.5,410 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.949219 L 32,420.62695 V 423.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2.87305 L 39.550781,414 H 40.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 A 0.50005,0.50005 0 0 0 40.5,410 h -3 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -6 v -0.5 A 0.50005,0.50005 0 0 0 30.5,410 Z m 0.5,1 h 2 v 2 h -2 z m 10,0 h 2 v 2 h -2 z m -7,1 h 6 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.914062 l -3.214843,6 h -2.398438 l -3.214843,-6 H 30.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 z m 2,9 h 2 v 2 h -2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <g
+ id="g17481"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ transform="translate(-332.00634,585.99911)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ style="opacity:0.7;fill:#ffffff;stroke-width:1.1535517"
+ transform="matrix(0.86707513,0,0,0.86670066,799.68613,161.07329)"
+ id="g17477">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 432.96875,577.99609 a 0.50015801,0.499942 0 0 0 -0.0488,0.006 0.50015801,0.499942 0 0 0 -0.0879,0.0215 c -0.22504,0.005 -0.45054,4.4e-4 -0.67383,0.0273 -1.50924,0.18184 -2.95823,0.85326 -4.0957,1.98242 -2.27494,2.25834 -2.72493,5.78034 -1.08984,8.53711 1.26078,2.1257 3.51721,3.36761 5.89257,3.41407 6.5e-4,10e-6 10e-4,-2e-5 0.002,0 a 0.50015801,0.499942 0 0 0 0.32031,-0.01 c 0.60037,-0.016 1.20402,-0.0867 1.80078,-0.26367 a 0.50073965,0.5005234 0 1 0 -0.28516,-0.95899 c -0.52501,0.15567 -1.05482,0.21548 -1.58203,0.22657 -0.32205,-0.21838 -0.86207,-0.82158 -1.28906,-1.77344 -0.15847,-0.35327 -0.29568,-0.76712 -0.41992,-1.20508 H 433.5 a 0.50043241,0.50021629 0 1 0 0,-1 h -2.31641 C 431.07457,586.38509 431,585.72514 431,585 c 0,-0.72848 0.074,-1.38791 0.18359,-2 h 3.5625 c 0.15752,0.77172 0.25391,1.61389 0.25391,2.5 a 0.50015801,0.499942 0 1 0 1,0 c 0,-0.883 -0.0936,-1.71998 -0.24023,-2.5 h 2.88671 c 0.41677,1.17713 0.47801,2.4832 0.0937,3.74609 a 0.50015801,0.499942 0 1 0 0.95704,0.28907 c 0.93293,-3.06617 -0.34127,-6.37791 -3.08789,-8.03125 -1.07945,-0.64978 -2.27964,-0.96925 -3.47657,-0.99219 a 0.50015801,0.499942 0 0 0 -0.14648,-0.0156 0.50015801,0.499942 0 0 0 -0.0176,0 z m 0.0273,1.13086 c 0.3107,0.30928 0.79344,0.97648 1.16602,1.90039 0.12076,0.29947 0.23379,0.62673 0.33594,0.97266 h -3.08399 c 0.12298,-0.42695 0.25956,-0.8299 0.41602,-1.17578 0.37038,-0.81882 0.82294,-1.39159 1.16601,-1.69727 z m 1.33789,0.0312 c 0.60769,0.13919 1.20278,0.36589 1.75977,0.70118 0.89497,0.53872 1.60631,1.28287 2.10156,2.14062 h -2.66797 c -0.12978,-0.47868 -0.2726,-0.9368 -0.4375,-1.3457 -0.23548,-0.58396 -0.48644,-1.07928 -0.75586,-1.4961 z m -2.70507,0.0156 c -0.24979,0.35295 -0.49203,0.75628 -0.71094,1.24023 -0.21038,0.4651 -0.38853,1.0058 -0.53906,1.58594 h -2.5586 c 0.26045,-0.4489 0.56294,-0.87823 0.94531,-1.25781 0.81076,-0.80484 1.80942,-1.32143 2.86329,-1.56836 z m -4.26758,3.80664 A 0.50043241,0.50021629 0 0 0 427.50195,583 h 2.66993 C 430.0701,583.62227 430,584.28017 430,585 c 0,0.71751 0.0707,1.37536 0.17188,2 h -2.66993 a 0.50043241,0.50021629 0 0 0 -0.14648,0.0234 c -0.47566,-1.32219 -0.45827,-2.74775 0.006,-4.04297 z M 427.80469,588 h 2.57226 c 0.15111,0.59053 0.32906,1.14077 0.54102,1.61328 0.21198,0.47256 0.44409,0.86643 0.68555,1.21289 -1.53987,-0.36784 -2.91769,-1.3294 -3.76954,-2.76562 -0.0116,-0.0196 -0.0179,-0.0409 -0.0293,-0.0606 z"
+ transform="matrix(1.1533026,0,0,1.1538009,-539.37632,-861.97281)"
+ id="path17465"
+ inkscape:connector-curvature="0" />
+ <path
+ cx="-40.000011"
+ cy="-186.99979"
+ r="7.5"
+ id="path17471"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.1535517;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d=""
+ inkscape:connector-curvature="0" />
</g>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 240,602 c -1.21759,0 -2.24187,0.34734 -2.94727,1.05273 C 236.34734,603.75813 236,604.78241 236,606 v 3.41992 a 0.50005,0.50005 0 0 0 0.11328,0.4043 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 236.58203,610 H 236.75 A 0.50005,0.50005 0 0 0 237,609.06445 V 606 c 0,-1.03241 0.27766,-1.75813 0.75977,-2.24023 C 238.24187,603.27766 238.96759,603 240,603 h 4.29297 l 2.85351,2.85352 A 0.50005,0.50005 0 0 0 247.5,606 h 1.5 c 0.63889,0 1.1225,0.20453 1.45898,0.54102 C 250.79547,606.8775 251,607.36111 251,608 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 608 c 0,-0.86111 -0.29547,-1.6275 -0.83398,-2.16602 C 250.6275,605.29547 249.86111,605 249,605 h -1.29297 l -2.85351,-2.85352 A 0.50005,0.50005 0 0 0 244.5,602 Z m -0.5,7 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z m 6,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -9,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 9,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z" id="circle12878-4" inkscape:connector-curvature="0"/>
- <g transform="matrix(-0.75,0,0,0.75,369.25,419.25)" style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff;stroke-width:1.33333325;enable-background:new" id="g10315-7" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333325" id="g10313-3">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 300.99023,247.67578 a 0.666995,0.666995 0 1 0 0,1.33399 h 10.66602 a 0.666995,0.666995 0 1 0 0,-1.33399 z" id="path10309-7" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 767.49023,1 c -0.3497,0.00648 -0.58488,0.3607678 -0.45507,0.6855469 l 2,5 c 0.1836,0.4628079 0.85703,0.4022128 0.95507,-0.085937 l 0.43946,-2.1738282 2.16797,-0.4355468 c 0.48875,-0.096787 0.55077,-0.7707095 0.0879,-0.9550782 l -5,-2 C 767.62345,1.0105047 767.55703,0.99855041 767.49023,1 Z"
+ id="path17479"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ </g>
+ <g
+ transform="translate(41.999988,1.0000045)"
+ id="g10697"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 35.744141,52.003906 c -0.89409,0.01843 -1.828792,0.373713 -2.597657,1.142578 l -5,5 c -0.837869,0.83787 -1.178323,2.041781 -1.11914,3.226563 0.05918,1.184782 0.515289,2.376617 1.36914,3.230469 0.852133,0.852132 2.037527,1.314671 3.220704,1.376953 1.183176,0.06228 2.389387,-0.280013 3.236328,-1.126953 l 6,-6 a 0.50005,0.50005 0 1 0 -0.707032,-0.707032 l -6,6 c -0.60312,0.603121 -1.522254,0.886172 -2.476562,0.835938 -0.954308,-0.05023 -1.918539,-0.43807 -2.566406,-1.085938 -0.646149,-0.646148 -1.030262,-1.616046 -1.078125,-2.574218 -0.04786,-0.958173 0.23781,-1.878436 0.828125,-2.46875 l 5,-5 c 1.184971,-1.184974 2.75871,-1.004381 3.554687,-0.248047 0.796393,0.756731 0.863064,2.416231 -0.261719,3.541015 l -4.5,4.5 c -0.592865,0.592866 -1.094745,0.448224 -1.417968,0.125 -0.323224,-0.323223 -0.467866,-0.825103 0.125,-1.417968 l 3.5,-3.5 a 0.50005,0.50005 0 1 0 -0.707032,-0.707032 l -3.5,3.5 c -0.907134,0.907135 -0.801776,2.155255 -0.125,2.832032 0.676777,0.676776 1.924897,0.782134 2.832032,-0.125 l 4.5,-4.5 c 1.483397,-1.483398 1.519845,-3.762437 0.24414,-4.97461 -0.60598,-0.5758 -1.459426,-0.89343 -2.353515,-0.875 z"
+ id="path10693"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ id="rect10695"
+ width="16"
+ height="16"
+ x="26"
+ y="52"
+ rx="0.5"
+ ry="0.5" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g10711"
+ transform="translate(598,-637)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ transform="translate(-189)"
+ id="g10709"
+ style="fill:#ffffff">
+ <rect
+ y="214.99997"
+ x="-152"
+ height="16"
+ width="16"
+ id="rect10699"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
+ transform="rotate(-90,-11.999985,564.99999)" />
+ <g
+ id="g10703"
+ style="fill:#ffffff" />
+ <path
+ id="path10707"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -350.42969,690.01758 c -0.79787,-0.038 -1.57177,0.27684 -2.16015,0.86523 l -1.48633,1.48828 c -0.61577,0.57533 -0.93433,1.35407 -0.89258,2.1543 a 0.50005,0.50005 0 1 0 0.99805,-0.0508 c -0.0269,-0.51495 0.15566,-0.98016 0.57617,-1.37305 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 l 1.5,-1.5 c 0.41161,-0.41161 0.88966,-0.59872 1.40429,-0.57422 0.51464,0.0245 1.08439,0.26993 1.63868,0.82422 0.55479,0.5548 0.80954,1.13546 0.83789,1.65235 0.0283,0.51688 -0.15241,0.9848 -0.57422,1.3789 a 0.50005,0.50005 0 0 0 -0.0137,0.0117 l -1.5,1.5 c -0.41213,0.41213 -0.87694,0.60352 -1.39649,0.60352 a 0.50005,0.50005 0 1 0 0,1 c 0.78067,0 1.52491,-0.31788 2.10352,-0.89649 l 1.48828,-1.48828 c 0.61768,-0.57711 0.9366,-1.36125 0.89258,-2.16406 -0.044,-0.80281 -0.43566,-1.60948 -1.13086,-2.30469 -0.69571,-0.69571 -1.49901,-1.07724 -2.29688,-1.11523 z m -6.00976,6 c -0.80753,-0.0482 -1.5954,0.26944 -2.17578,0.89062 l -1.48829,1.48828 c -0.58838,0.58839 -0.90322,1.36034 -0.86523,2.15821 0.038,0.79787 0.41952,1.60311 1.11523,2.29883 0.69521,0.6952 1.50384,1.08487 2.30664,1.1289 0.80281,0.044 1.585,-0.27294 2.16211,-0.89062 l 1.48829,-1.48828 C -353.31787,701.0249 -353,700.28067 -353,699.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.51955 -0.19139,0.98436 -0.60352,1.39648 l -1.5,1.5 a 0.50005,0.50005 0 0 0 -0.0117,0.0117 c -0.39411,0.42182 -0.86007,0.60452 -1.37696,0.57618 -0.51688,-0.0283 -1.0995,-0.2831 -1.65429,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.82227,-1.63867 -0.0245,-0.51463 0.16065,-0.99268 0.57227,-1.40429 l 1.5,-1.5 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 c 0.39634,-0.4242 0.86629,-0.60725 1.38672,-0.57618 a 0.50005,0.50005 0 1 0 0.0586,-0.99804 z m 4.92968,-2.02149 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -5,5 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 5,-5 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g10247-8" style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" transform="matrix(-0.53033009,-0.53033009,-0.53033009,0.53033009,454.86353,636.75914)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g id="g10245-2" style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 306.99023,241.72461 a 0.66673335,0.66673335 0 0 0 -0.65625,0.67578 v 5.93359 h -5.93359 a 0.66673335,0.66673335 0 1 0 0,1.33204 h 5.93359 v 5.93359 a 0.66673335,0.66673335 0 1 0 1.33204,0 v -5.93359 h 5.93359 a 0.66673335,0.66673335 0 1 0 0,-1.33204 h -5.93359 v -5.93359 a 0.66673335,0.66673335 0 0 0 -0.67579,-0.67578 z" id="path10243-3" inkscape:connector-curvature="0"/>
+ <g
+ transform="translate(-252,-252)"
+ id="g10731"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 328,368 c -3.86007,0 -7,3.13993 -7,7 0,3.86007 3.13993,7 7,7 3.86007,0 7,-3.13993 7,-7 0,-3.86007 -3.13993,-7 -7,-7 z m 0,1 c 3.31963,0 6,2.68037 6,6 0,3.31963 -2.68037,6 -6,6 -3.31963,0 -6,-2.68037 -6,-6 0,-3.31963 2.68037,-6 6,-6 z"
+ id="path10721"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 327.12891,369.9668 a 1.0001,1.0001 0 0 0 -0.16797,0.0234 c -2.00329,0.41569 -3.57155,1.99062 -3.97656,3.9961 a 1.0003053,1.0003053 0 1 0 1.96093,0.39648 c 0.24758,-1.22589 1.19732,-2.17949 2.42188,-2.43359 a 1.0001,1.0001 0 0 0 -0.23828,-1.98242 z"
+ id="path10723"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 332.49609,373.0957 a 0.40004001,0.40004001 0 0 0 -0.27929,0.6875 l 2,2 a 0.40050528,0.40050528 0 1 0 0.5664,-0.5664 l -2,-2 a 0.40004001,0.40004001 0 0 0 -0.28711,-0.1211 z m -0.75,2.25 a 0.40004001,0.40004001 0 0 0 -0.27929,0.6875 l 2,2 a 0.40050528,0.40050528 0 1 0 0.5664,-0.5664 l -2,-2 a 0.40004001,0.40004001 0 0 0 -0.28711,-0.1211 z m -1.25,1.75 a 0.40004001,0.40004001 0 0 0 -0.27929,0.6875 l 2,2 a 0.40050528,0.40050528 0 1 0 0.5664,-0.5664 l -2,-2 a 0.40004001,0.40004001 0 0 0 -0.28711,-0.1211 z m -1.75,1.25 a 0.40004001,0.40004001 0 0 0 -0.27929,0.6875 l 2,2 a 0.40050528,0.40050528 0 1 0 0.5664,-0.5664 l -2,-2 a 0.40004001,0.40004001 0 0 0 -0.28711,-0.1211 z m -2.23632,0.75 a 0.40004001,0.40004001 0 0 0 -0.27344,0.70508 l 2,1.75 a 0.40004001,0.40004001 0 1 0 0.52734,-0.60156 l -2,-1.75 a 0.40004001,0.40004001 0 0 0 -0.2539,-0.10352 z"
+ id="path10727"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g15743"
+ transform="translate(221,4.4999696e-6)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M -98.580078,578 C -99.98888,578 -101,579.16322 -101,580.5 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.87198 0.530524,-1.5 1.419922,-1.5 0.889383,0 1.580078,0.67678 1.580078,1.5 0,0.82323 -0.69069,1.49999 -1.580078,1.5 h -4.914062 a 0.50005,0.50005 0 1 0 0,1 h 4.914062 C -97.171286,582.99999 -96,581.88555 -96,580.5 c 0,-1.38554 -1.171281,-2.5 -2.580078,-2.5 z m -8.916012,0.004 c -1.38554,0 -2.5,1.17128 -2.5,2.58007 0,1.40881 1.16321,2.41797 2.5,2.41797 a 0.50005,0.50005 0 1 0 0,-1 c -0.87198,0 -1.5,-0.52857 -1.5,-1.41797 0,-0.88938 0.67678,-1.58007 1.5,-1.58007 0.82323,0 1.49804,0.69069 1.49804,1.58007 v 4.91211 a 0.50005,0.50005 0 1 0 1,0 v -4.91211 c -10e-6,-1.40879 -1.1125,-2.58007 -2.49804,-2.58007 z m 6.98828,5.98828 A 0.50005,0.50005 0 0 0 -101,584.5 v 4.91211 c 1e-5,1.40879 1.114453,2.58008 2.5,2.58008 1.385539,0 2.5,-1.17128 2.5,-2.58008 0,-1.4088 -1.163215,-2.41992 -2.5,-2.41992 a 0.50005,0.50005 0 1 0 0,1 c 0.871975,0 1.5,0.53052 1.5,1.41992 0,0.88938 -0.676779,1.58008 -1.5,1.58008 -0.823233,0 -1.499992,-0.69069 -1.5,-1.58008 V 584.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -6.90821,3.0039 c -1.40879,2e-5 -2.58007,1.11446 -2.58007,2.5 0,1.38554 1.17128,2.5 2.58007,2.5 1.40881,0 2.41993,-1.16321 2.41993,-2.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.87198 -0.53053,1.5 -1.41993,1.5 -0.88938,0 -1.58007,-0.67678 -1.58007,-1.5 0,-0.82323 0.69069,-1.49999 1.58007,-1.5 h 4.91211 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path10848"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-84.000002,1.45e-5)"
+ id="g10880"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ transform="translate(-523,-55.999969)"
+ id="g10853"
+ style="fill:#ffffff" />
+ <g
+ id="g10878"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 157.49219,453.99222 A 0.50005,0.50005 0 0 0 157,454.50003 v 4 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path10874"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 80.476562,451.02148 a 0.50005,0.50005 0 0 0 -0.314453,0.8711 c 0.58809,0.54453 0.841797,1.0856 0.841797,1.60156 L 81,459.5 a 0.50005,0.50005 0 1 0 1,0 l 0.0039,-6.00586 c 0,-0.8509 -0.431789,-1.65971 -1.162109,-2.33594 a 0.50005,0.50005 0 0 0 -0.365235,-0.13672 z M 71.5625,452 C 69.59752,452 68,453.59753 68,455.5625 v 7.875 C 68,465.40247 69.59752,467 71.5625,467 h 3.875 C 77.40247,467 79,465.40247 79,463.4375 v -7.875 C 79,453.59753 77.40247,452 75.4375,452 Z m 0,1 h 3.875 C 76.86577,453 78,454.13423 78,455.5625 v 7.875 C 78,464.86577 76.86577,466 75.4375,466 h -3.875 C 70.13422,466 69,464.86577 69,463.4375 v -7.875 C 69,454.13423 70.13422,453 71.5625,453 Z m 11.929688,0.0371 A 0.50005,0.50005 0 0 0 83,453.54297 v 4.05859 a 0.50005,0.50005 0 1 0 1,0 v -4.05859 a 0.50005,0.50005 0 0 0 -0.507812,-0.50586 z"
+ transform="translate(84.000002,-1.449997e-5)"
+ id="rect10876"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g12144" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:7.17647076;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 181.5,578 c -3.57273,0 -6.5,2.92727 -6.5,6.5 0,1.60752 0.59683,3.08042 1.57422,4.21875 l -2.42774,2.42773 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2.42578,-2.42579 c 1.13822,0.977 2.61355,1.57227 4.2207,1.57227 3.57273,0 6.5,-2.92728 6.5,-6.5 0,-3.57273 -2.92727,-6.5 -6.5,-6.5 z m 0,1 c 2.85852,0 5.21992,2.20548 5.47461,5 h -6.26758 l 2.14649,-2.14648 c 0.32529,-0.31801 0.0914,-0.86992 -0.36329,-0.85743 -0.12976,0.004 -0.25303,0.0575 -0.34375,0.15039 l -2.95703,2.95704 c -0.26095,0.19951 -0.26189,0.59214 -0.002,0.79296 0.002,10e-4 0.004,0.003 0.006,0.004 l 2.95312,2.95313 c 0.47127,0.49023 1.19727,-0.23577 0.70704,-0.70704 L 180.70703,585 h 6.26758 c -0.25469,2.79451 -2.61609,5 -5.47461,5 -3.02727,0 -5.5,-2.47273 -5.5,-5.5 0,-3.02728 2.47273,-5.5 5.5,-5.5 z" transform="translate(1.8536743e-6,-4.4999696e-6)" id="path9890-4" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" transform="translate(40.94871,1.10183)" id="g9896-8"/>
- <rect y="577.04999" x="172.95" height="16" width="16" id="rect9898-1" style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g5506-8" transform="translate(-44.000002,63.000005)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 556.57617,409.98047 a 0.55005501,0.55005501 0 0 0 -0.42383,0.18555 c -0.46657,0.51387 -1.20227,1.13094 -1.20312,2.14257 -10e-4,1.1847 0.85571,2.11411 1.94336,2.91797 1.08765,0.80386 2.47935,1.527 3.84765,2.25782 0.44143,0.23577 0.88243,0.47055 1.3086,0.70312 1.11316,0.60746 2.13512,1.2144 2.84375,1.81836 0.70862,0.60396 1.05894,1.15906 1.05859,1.68359 -4e-4,0.48086 -0.32771,1.0064 -0.79492,1.38086 a 0.55027044,0.55027044 0 1 0 0.6875,0.85938 c 0.65297,-0.52334 1.20625,-1.30182 1.20703,-2.23828 6.6e-4,-0.99421 -0.62031,-1.82029 -1.44531,-2.52344 -0.825,-0.70315 -1.89813,-1.32892 -3.03125,-1.94727 -0.43383,-0.23675 -0.87476,-0.47023 -1.31445,-0.70508 -1.37366,-0.73367 -2.73478,-1.45092 -3.71289,-2.17382 -0.97812,-0.72291 -1.49874,-1.40647 -1.49805,-2.03125 3.7e-4,-0.43907 0.39742,-0.83099 0.91797,-1.4043 a 0.55005501,0.55005501 0 0 0 -0.39063,-0.92578 z" id="path5432-2" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 565.45508,409.94531 a 0.55005501,0.55005501 0 0 0 -0.31446,0.97071 c 0.44122,0.38244 0.8125,1.03351 0.8125,1.58398 -0.002,0.56635 -0.25363,0.95243 -0.74218,1.35938 -0.48909,0.40739 -1.20703,0.77343 -1.95703,1.14843 a 0.55028291,0.55028291 0 1 0 0.49218,0.98438 c 0.75,-0.375 1.5313,-0.75874 2.16797,-1.28907 0.63668,-0.53032 1.13681,-1.26964 1.13867,-2.20312 0,-0.98667 -0.54281,-1.85212 -1.19335,-2.41602 a 0.55005501,0.55005501 0 0 0 -0.4043,-0.13867 z m -6.95313,8.00196 a 0.55005501,0.55005501 0 0 0 -0.24804,0.0605 c -0.75,0.375 -1.5313,0.75874 -2.16797,1.28907 -0.63668,0.53032 -1.13681,1.26964 -1.13867,2.20312 0,0.98843 0.53602,1.85319 1.19335,2.41797 a 0.55122854,0.55122854 0 1 0 0.71876,-0.83594 c -0.44771,-0.38466 -0.8125,-1.01968 -0.8125,-1.58203 0.002,-0.56635 0.25363,-0.95243 0.74218,-1.35938 0.48909,-0.40739 1.20703,-0.77343 1.95703,-1.14843 a 0.55005501,0.55005501 0 0 0 -0.24414,-1.04492 z" id="path5435-6" inkscape:connector-curvature="0"/>
- <path id="path5484-0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 557.5,421 a 0.50005,0.50005 0 1 0 0,1 h 2 A 0.50005,0.50005 0 0 0 560,421.58008 0.50005,0.50005 0 0 0 560.5,422 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -4 A 0.50005,0.50005 0 0 0 560,421.41992 0.50005,0.50005 0 0 0 559.5,421 Z m 0,-9 a 0.50005,0.50005 0 1 0 0,1 h 4 A 0.50005,0.50005 0 0 0 562,412.58008 0.50005,0.50005 0 0 0 562.5,413 h 2 a 0.50005,0.50005 0 1 0 0,-1 h -2 A 0.50005,0.50005 0 0 0 562,412.41992 0.50005,0.50005 0 0 0 561.5,412 Z" inkscape:connector-curvature="0"/>
+ <path
+ inkscape:connector-curvature="0"
+ id="path10927"
+ d="m 10.484375,452 c -0.752,0 -1.4538175,0.239 -2.0234375,0.64453 C 7.5752675,453.27508 7,454.31514 7,455.48438 V 458.5 c 3e-5,0.27537 0.2226769,0.4989 0.4980469,0.5 l 4.0097651,0.008 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 L 12,452.53516 v -0.002 -0.0352 C 11.999,452.22272 11.77534,452.00003 11.5,452 Z M 13,452 v 1 h 1.515625 C 15.900145,453 17,454.09985 17,455.48438 v 8.03124 C 17,464.90014 15.900145,466 14.515625,466 h -4.03125 C 9.099855,466 8,464.90014 8,463.51562 V 460 H 7 v 3.51562 C 7,465.43685 8.563145,467 10.484375,467 h 4.03125 C 16.436855,467 18,465.43686 18,463.51562 v -8.03124 C 18,453.56315 16.436855,452 14.515625,452 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="rect10947"
+ d="M 31.484375,452 C 29.563145,452 28,453.56315 28,455.48438 v 8.03124 C 28,465.43685 29.563145,467 31.484375,467 h 4.03125 C 37.436855,467 39,465.43685 39,463.51562 v -8.03124 C 39,453.56315 37.436855,452 35.515625,452 Z m 0,1 h 4.03125 C 36.900155,453 38,454.09985 38,455.48438 v 8.03124 C 38,464.90015 36.900155,466 35.515625,466 h -4.03125 C 30.099845,466 29,464.90015 29,463.51562 v -8.03124 C 29,454.09985 30.099845,453 31.484375,453 Z m 1.5625,1 C 32.475545,454 32,454.47555 32,455.04688 v 3.90624 C 32,459.52445 32.475545,460 33.046875,460 h 0.90625 C 34.524455,460 35,459.52445 35,458.95312 v -3.90624 C 35,454.47555 34.524455,454 33.953125,454 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 69.492188,306 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path10850"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 48.492188,306 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 7,3 a 0.50005,0.50005 0 1 0 0,1 h 5.99414 a 0.50005,0.50005 0 1 0 0,-1 z m -7,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 7,3 a 0.50005,0.50005 0 1 0 0,1 h 5.99414 a 0.50005,0.50005 0 1 0 0,-1 z m -7,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path10852"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 27.492188,306 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 4,3 a 0.50005,0.50005 0 1 0 0,1 h 4.99414 a 0.50005,0.50005 0 1 0 0,-1 z m -4,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 4,3 a 0.50005,0.50005 0 1 0 0,1 h 4.99414 a 0.50005,0.50005 0 1 0 0,-1 z m -4,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path10854"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 6.5,306 a 0.50005,0.50005 0 1 0 0,1 h 12.992188 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 5.992188 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.992188 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 5.992188 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.992188 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path10856"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="translate(-462.00711,-314.99994)"
+ id="g10872"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:2.20000005;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 552.5,621 a 0.50005,0.50005 0 1 0 0,1 h 1.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 4.02344,0 a 0.50005,0.50005 0 1 0 0,1 h 1.91601 a 0.50005,0.50005 0 1 0 0,-1 z m 3.9707,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99805 a 0.50005,0.50005 0 1 0 0,-1 z m 3.99805,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z M 552.5,624 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99805 a 0.50005,0.50005 0 1 0 0,-1 z m 4.05273,0 a 0.50005,0.50005 0 1 0 0,1 h 1.91797 a 0.50005,0.50005 0 1 0 0,-1 z m 3.94727,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99219 a 0.50005,0.50005 0 1 0 0,-1 z m -11,3 a 0.50005,0.50005 0 1 0 0,1 h 1.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 4.02344,0 a 0.50005,0.50005 0 1 0 0,1 h 1.91601 a 0.50005,0.50005 0 1 0 0,-1 z m 3.9707,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99805 a 0.50005,0.50005 0 1 0 0,-1 z m 3.99805,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z M 552.5,630 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99805 a 0.50005,0.50005 0 1 0 0,-1 z m 4.05273,0 a 0.50005,0.50005 0 1 0 0,1 h 1.91797 a 0.50005,0.50005 0 1 0 0,-1 z m 3.94727,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99219 a 0.50005,0.50005 0 1 0 0,-1 z m -11,3 a 0.50005,0.50005 0 1 0 0,1 h 1.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 4.02344,0 a 0.50005,0.50005 0 1 0 0,1 h 1.91601 a 0.50005,0.50005 0 1 0 0,-1 z m 3.9707,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99805 a 0.50005,0.50005 0 1 0 0,-1 z m 3.99805,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path10870"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 201.49219,305 a 0.50005,0.50005 0 1 0 0,1 h 2.5039 l -0.002,0.14258 -4.95898,11.4082 a 0.50005,0.50005 0 0 0 -0.041,0.21289 L 199,318 h -2.50781 a 0.50005,0.50005 0 1 0 0,1 h 6 a 0.50005,0.50005 0 1 0 0,-1 H 200 a 0.50005,0.50005 0 0 0 0,-0.0137 l -0.004,-0.13867 4.95508,-11.39844 a 0.50005,0.50005 0 0 0 0.041,-0.19141 L 204.99609,306 h 2.4961 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path10892"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 216.49219,305 a 0.50005,0.50005 0 1 0 0,1 H 218 v 6.00391 c 0,2.19985 1.79782,3.99206 4,3.99609 h 1 a 0.50005,0.50005 0 0 0 0.002,0 c 2.20199,-0.005 3.998,-1.79624 3.998,-3.99609 V 306 h 1.49219 a 0.50005,0.50005 0 1 0 0,-1 h -4 a 0.50005,0.50005 0 1 0 0,1 H 226 v 6.00391 c 0,1.65832 -1.33799,2.99265 -3.00195,2.99609 H 222 c -1.66382,-0.003 -3,-1.33777 -3,-2.99609 V 306 h 1.49219 a 0.50005,0.50005 0 1 0 0,-1 z m 1,13 a 0.50005,0.50005 0 1 0 0,1 h 10 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path10901"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 111.5,305 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 13 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 13 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -13 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
+ id="rect10983"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 113.49219,307 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path10977"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 132.5,305 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 13 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 13 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -13 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
+ id="rect11046"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 134.49219,310 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path11048"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 153.5,305 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 13 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 13 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -13 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
+ id="rect11050"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 155.49219,314 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path11052"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 177,305 a 1.0001,1.0001 0 0 0 -1,1 v 5.83203 a 1.0001,1.0001 0 0 0 0,0.32617 V 318 a 1.0001,1.0001 0 0 0 1,1 h 6 c 2.19729,0 4,-1.80271 4,-4 0,-1.76747 -1.1852,-3.22799 -2.78516,-3.75195 C 184.67235,310.59788 185,309.84948 185,309 c 0,-2.19729 -1.80271,-4 -4,-4 z m 1,2 h 3 c 1.11641,0 2,0.88359 2,2 0,1.11641 -0.88359,2 -2,2 h -3 z m 0,6 h 3 2 c 1.11641,0 2,0.88359 2,2 0,1.11641 -0.88359,2 -2,2 h -5 z"
+ id="path10949"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="matrix(0,1,1,0,37.999948,363)"
+ id="g11084"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 202,473 c -3.86007,0 -7,3.13993 -7,7 0,3.86007 3.13993,7 7,7 3.86007,0 7,-3.13993 7,-7 0,-3.86007 -3.13993,-7 -7,-7 z m 0,1 c 1.09865,0 2,0.90135 2,2 0,1.09865 -0.90135,2 -2,2 -1.09865,0 -2,-0.90135 -2,-2 0,-1.09865 0.90135,-2 2,-2 z m -4,4 c 1.09865,0 2,0.90135 2,2 0,1.09865 -0.90135,2 -2,2 -1.09865,0 -2,-0.90135 -2,-2 0,-1.09865 0.90135,-2 2,-2 z m 8,0 c 1.09865,0 2,0.90135 2,2 0,1.09865 -0.90135,2 -2,2 -1.09865,0 -2,-0.90135 -2,-2 0,-1.09865 0.90135,-2 2,-2 z m -4,1 c 0.54636,0 1,0.45364 1,1 0,0.54636 -0.45364,1 -1,1 -0.54636,0 -1,-0.45364 -1,-1 0,-0.54636 0.45364,-1 1,-1 z m 0,3 c 1.09865,0 2,0.90135 2,2 0,1.09865 -0.90135,2 -2,2 -1.09865,0 -2,-0.90135 -2,-2 0,-1.09865 0.90135,-2 2,-2 z m 4.96484,4 a 0.50005,0.50005 0 0 0 -0.47265,0.49219 A 0.50005,0.50005 0 0 0 207,487 h 0.5 c 0.83333,0 1.14655,0.35353 1.64648,0.85352 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 C 209.35355,486.64647 208.66667,486 207.5,486 H 207 a 0.50005,0.50005 0 0 0 -0.0352,0 z"
+ transform="matrix(0,1,1,0,-363,-37.999948)"
+ id="circle11078"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ id="g13852"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ style="display:inline;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new">
+ <g
+ id="g11167"
+ transform="matrix(0,-1,-1,0,688.99474,-44.97944)"
+ style="display:inline;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 14.505859,263.01562 a 0.55005501,0.55005501 0 0 0 -0.05664,0.004 c -1.480032,0.16258 -2.81124,0.9768 -3.632813,2.21875 -0.754587,1.14068 -0.9438173,2.54615 -0.65039,3.875 l -3.5234379,3.52149 c -0.4164576,0.37981 -0.6354253,0.95498 -0.6601562,1.61328 -0.024627,0.65553 0.1896767,1.40646 0.7832031,2 0.5945619,0.59455 1.3481437,0.80114 1.9980469,0.76953 0.6519363,-0.0317 1.2112985,-0.25543 1.5917971,-0.63672 l 3.533203,-3.54297 c 1.328363,0.29148 2.734045,0.0991 3.873047,-0.6543 1.240498,-0.82051 2.05459,-2.151 2.21875,-3.6289 a 0.55005501,0.55005501 0 0 0 -0.160157,-0.45117 l -0.943359,-0.92969 a 0.55005501,0.55005501 0 0 0 -0.775391,0.002 l -1.80664,1.79883 h -0.589844 l -1.679687,-1.67969 v -0.58984 l 1.804687,-1.80078 a 0.55005501,0.55005501 0 0 0 0.0039,-0.77539 l -0.93164,-0.94727 a 0.55005501,0.55005501 0 0 0 -0.396485,-0.16602 z m -0.15625,1.17383 0.316407,0.32227 -1.580078,1.57617 a 0.55005501,0.55005501 0 0 0 -0.16211,0.39063 l 0.002,1.04687 a 0.55005501,0.55005501 0 0 0 0.16211,0.38672 l 2.001953,2.00195 a 0.55005501,0.55005501 0 0 0 0.388672,0.16211 l 1.046875,-0.002 a 0.55005501,0.55005501 0 0 0 0.386718,-0.16016 l 1.580079,-1.57422 0.318359,0.31446 c -0.183326,1.05859 -0.751902,2.01444 -1.654297,2.61132 -0.970627,0.64202 -2.219467,0.82961 -3.330078,0.49219 a 0.55005501,0.55005501 0 0 0 -0.548828,0.13672 l -3.699219,3.70899 c -0.1021327,0.10234 -0.4754005,0.29532 -0.8691406,0.31445 -0.395773,0.0192 -0.8021096,-0.0834 -1.1660156,-0.44727 -0.3650748,-0.36508 -0.4778317,-0.78393 -0.4628907,-1.18164 0.014838,-0.39496 0.2099663,-0.75541 0.3046875,-0.84179 a 0.55005501,0.55005501 0 0 0 0.017578,-0.0176 l 3.7070314,-3.70508 a 0.55005501,0.55005501 0 0 0 0.136719,-0.54883 c -0.339386,-1.11269 -0.154519,-2.36033 0.488281,-3.33203 0.59791,-0.90384 1.555081,-1.47203 2.615234,-1.6543 z"
+ id="path11179"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(62.999978,21.041695)"
+ id="g11141"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ transform="translate(-126)"
+ id="g11139"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 206.72656,599 c -0.19328,-0.004 -0.38654,0.0132 -0.57422,0.0508 -0.75071,0.15014 -1.44693,0.5778 -2.00586,1.13672 l -2.14453,2.10742 -1.14843,-1.14844 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 1.64649,1.64648 -4.64844,4.68945 A 0.50005,0.50005 0 0 0 197,608.54102 v 0.79296 l -1.85352,1.85352 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 2,-2 A 0.50005,0.50005 0 0 0 198,609.54102 v -0.79493 l 4.50195,-4.53711 1.29297,1.29297 -4.5039,4.53907 H 198.5 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -2,2 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 1.85351,-1.85351 H 199.5 a 0.50005,0.50005 0 0 0 0.35547,-0.14844 l 4.64648,-4.6836 1.64453,1.64454 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.14258,-1.14257 2.13867,-2.10547 0.004,-0.004 c 0.55892,-0.55893 0.98657,-1.25515 1.13671,-2.00586 0.15015,-0.75072 -0.0189,-1.58331 -0.63671,-2.20117 -0.4634,-0.46339 -1.04712,-0.67435 -1.62696,-0.6875 z"
+ transform="translate(63.000022,-21.041695)"
+ id="path11133"
+ inkscape:connector-curvature="0" />
+ </g>
</g>
- <g transform="matrix(-0.53033009,-0.53033009,-0.53033009,0.53033009,706.86353,657.75914)" style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" id="g10178-9" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none" id="g10176-5">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 306.99023,241.72461 a 0.66673335,0.66673335 0 0 0 -0.65625,0.67578 v 5.93359 h -5.93359 a 0.66673335,0.66673335 0 1 0 0,1.33204 h 5.93359 v 5.93359 a 0.66673335,0.66673335 0 1 0 1.33204,0 v -5.93359 h 5.93359 a 0.66673335,0.66673335 0 1 0 0,-1.33204 h -5.93359 v -5.93359 a 0.66673335,0.66673335 0 0 0 -0.67579,-0.67578 z" id="path10174-2" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13475"
+ transform="translate(-21.000002,4.4999696e-6)">
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
+ mask="none"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 111,515 v 2 h 2 v -2 z m 2,2 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 2,0 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 2,0 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 0,2 v 2 h 2 v -2 z m -10,2 v -2 h -2 v 2 z m 2,0 h 2 v -2 h -2 z m 4,0 h 2 v -2 h -2 z"
+ id="path12185"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="translate(63,-231)"
+ id="g12189"
+ style="opacity:0.6;fill:#ffffff">
+ <path
+ id="path12187"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 48,753 v 3.5 c 0,0.82843 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67157 1.5,-1.5 V 756 c 0,-0.5 0.53412,-1 1,-1 0.55229,0 1,0.44772 1,1 v 2.5 c 0,0.82843 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67157 1.5,-1.5 V 757 c 0,-0.55228 0.44772,-1 1,-1 0.55229,0 1,-0.44771 1,-1 v -2 h -2 v 0 h -2 v 0 h -2 v 0 h -2 v 0 z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csssssssssssscccccccccc" />
</g>
</g>
- <g transform="translate(20.999998,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g23194">
- <g transform="translate(430,-112)" id="g12465" style="fill:#ffffff"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 79.570312,578.01758 c -0.797869,-0.038 -1.571767,0.27684 -2.160156,0.86523 l -1.486328,1.48828 c -0.615772,0.57533 -0.93433,1.35407 -0.892578,2.1543 a 0.50005,0.50005 0 1 0 0.998047,-0.0508 c -0.02687,-0.51495 0.155664,-0.98016 0.576172,-1.37305 a 0.50005,0.50005 0 0 0 0.01172,-0.0117 l 1.5,-1.5 c 0.411611,-0.41161 0.889666,-0.59872 1.404296,-0.57422 0.514631,0.0245 1.084383,0.26993 1.638672,0.82422 0.554795,0.5548 0.809544,1.13546 0.837891,1.65235 0.02835,0.51688 -0.152405,0.9848 -0.574219,1.3789 a 0.50005,0.50005 0 0 0 -0.01367,0.0117 l -1.5,1.5 c -0.412129,0.41213 -0.876932,0.60352 -1.396484,0.60352 a 0.50005,0.50005 0 1 0 0,1 c 0.780667,0 1.524905,-0.31788 2.103516,-0.89649 l 1.488281,-1.48828 c 0.617686,-0.57711 0.936606,-1.36125 0.892578,-2.16406 -0.04403,-0.80281 -0.435654,-1.60948 -1.130859,-2.30469 -0.695711,-0.69571 -1.499006,-1.07724 -2.296876,-1.11523 z m -1.080078,3.97851 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -5,5 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 5,-5 a 0.50005,0.50005 0 0 0 -0.363282,-0.85743 z m -4.929687,2.02149 c -0.807524,-0.0482 -1.595401,0.26944 -2.175781,0.89062 l -1.488282,1.48828 c -0.588388,0.58839 -0.903228,1.36034 -0.865234,2.15821 0.03799,0.79787 0.419524,1.60311 1.115234,2.29883 0.695206,0.6952 1.503832,1.08487 2.306641,1.1289 0.802809,0.044 1.584996,-0.27294 2.162109,-0.89062 l 1.488282,-1.48828 C 76.682126,589.0249 77,588.28067 77,587.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.51955 -0.191386,0.98436 -0.603516,1.39648 l -1.5,1.5 a 0.50005,0.50005 0 0 0 -0.01172,0.0117 c -0.394107,0.42182 -0.860068,0.60452 -1.376954,0.57618 -0.516885,-0.0283 -1.099502,-0.2831 -1.654296,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.822266,-1.63867 -0.02451,-0.51463 0.160654,-0.99268 0.572266,-1.40429 l 1.5,-1.5 a 0.50005,0.50005 0 0 0 0.01172,-0.0117 c 0.39634,-0.4242 0.866283,-0.60725 1.386719,-0.57618 a 0.50005,0.50005 0 1 0 0.05859,-0.99804 z" id="path12469" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="matrix(-1,0,0,1,88.999998,-231)"
+ id="g12197">
+ <path
+ inkscape:connector-curvature="0"
+ id="path12191"
+ transform="matrix(-1,0,0,1,90,231)"
+ d="m 75,519 v 7 c 0,0.5 0.25,1 1,1 0.75,0 1,-0.5 1,-1 v -1 c 0,-0.5 0.53412,-1 1,-1 0.55229,0 1,0.44772 1,1 v 2.5 c 0,0.82843 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67157 1.5,-1.5 V 526 c 0,-0.55228 0.44772,-1 1,-1 0.55229,0 1,-0.44771 1,-1 v -3.08789 A 1.50015,1.50015 0 0 1 83.5,521 h -3 A 1.50015,1.50015 0 0 1 79,519.5 V 519 Z"
+ style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 16.5,746 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -6 v -0.5 A 0.50005,0.50005 0 0 0 9.5,747 h -3 A 0.50005,0.50005 0 0 0 6,747.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 A 0.50005,0.50005 0 0 0 10,750.5 V 749 h 6 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 A 0.50005,0.50005 0 0 0 19.5,746 Z m 0.5,1 h 2 v 2 h -2 z m -10,1 h 2 v 2 H 7 Z"
+ id="path12195"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g17491"
+ transform="matrix(0.875,0,0,0.875,264.125,159.75)"
+ style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.14285719;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <rect
+ y="430"
+ x="257"
+ height="16"
+ width="16"
+ id="rect17483"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3.42857146;marker:none;enable-background:accumulate" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 496,535.9375 c -2.73936,0 -5.1213,1.56371 -6.29102,3.84961 -0.49329,0.96401 -0.77148,2.05765 -0.77148,3.21289 0,3.89459 3.16791,7.0625 7.0625,7.0625 3.89459,0 7.0625,-3.16791 7.0625,-7.0625 0,-3.89459 -3.16791,-7.0625 -7.0625,-7.0625 z m 0,1 c 3.35415,0 6.0625,2.70835 6.0625,6.0625 0,3.35415 -2.70834,6.0625 -6.0625,6.0625 -3.35415,0 -6.0625,-2.70835 -6.0625,-6.0625 0,-0.99492 0.23889,-1.93072 0.66211,-2.75781 1.00359,-1.96124 3.04116,-3.30469 5.40039,-3.30469 z M 496,538 a 0.99999996,0.99999996 0 0 0 -1,1 0.99999996,0.99999996 0 0 0 1,1 0.99999996,0.99999996 0 0 0 1,-1 0.99999996,0.99999996 0 0 0 -1,-1 z m -2.82422,1.16211 a 1.0001001,1.0001001 0 0 0 -0.6875,0.30469 c -0.61854,0.6208 -1.06287,1.393 -1.28906,2.24023 a 1.0001001,1.0001001 0 1 0 1.93164,0.51563 c 0.13595,-0.50922 0.40262,-0.97353 0.77344,-1.34571 a 1.0001001,1.0001001 0 0 0 -0.72852,-1.71484 z"
+ transform="matrix(1.1428571,0,0,1.1428571,-301.85714,-182.57143)"
+ id="path17485"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;stroke-width:1.09730649;enable-background:new"
+ transform="matrix(1,0,0,0.83050847,1300,-195.57627)"
+ id="g8019-1">
+ <path
+ sodipodi:nodetypes="cccccccccc"
+ inkscape:connector-curvature="0"
+ d="m -1207,502.79592 v 14.44898 h 2 v -14.44898 z m 6,0 v 14.44898 h 2 v -14.44898 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.19461298;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="path8013-3" />
+ </g>
+ <path
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 16.999998,228 a 4,4 0 0 1 -4,4 4,4 0 0 1 -3.9999999,-4 4,4 0 0 1 3.9999999,-4 4,4 0 0 1 4,4 z"
+ id="circle8021-5"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g5627"
+ style="fill:#ffffff">
+ <g
+ id="g5620"
+ style="fill:#ffffff">
+ <g
+ id="g5614"
+ style="fill:#ffffff">
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="translate(-42.000002,21.000005)"
+ id="g4035-9"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 99,599 c -2.74773,0 -5,2.25226 -5,5 0,1.1945 0.441488,2.28163 1.148438,3.14453 l -5.001954,5.00195 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 5.001953,-5.00196 C 96.718369,608.55851 97.805503,609 99,609 c 2.74773,0 5,-2.25227 5,-5 0,-2.74774 -2.25227,-5 -5,-5 z m 0,1 c 2.20227,0 4,1.79773 4,4 0,2.20226 -1.79773,4 -4,4 -2.20227,0 -4,-1.79774 -4,-4 0,-2.20227 1.79773,-4 4,-4 z"
+ transform="translate(42.000002,-21.000005)"
+ id="path4031-4"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ </g>
</g>
- <g style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.15384436;enable-background:new" id="g12595" transform="matrix(0.866668,0,0,0.866668,-177.46699,184.39943)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g style="fill:#ffffff;stroke-width:1.15384436" id="g12593">
- <path style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" d="m 34,557 c -3.860079,0 -7,3.13992 -7,7 0,3.86008 3.139921,7 7,7 3.860079,0 7,-3.13992 7,-7 0,-3.86008 -3.139921,-7 -7,-7 z m 0,1 c 3.305801,0 5.975833,2.65852 5.998047,5.95898 C 38.886544,564.90262 36.995365,566 34,566 v 4 c -3.319633,0 -6,-2.68037 -6,-6 0,-0.0145 0.0019,-0.0285 0.002,-0.043 C 29.113203,564.90101 31.002992,566 34,566 Z" transform="matrix(1.1538444,0,0,1.1538444,204.76929,-212.76825)" id="path12589" inkscape:connector-curvature="0"/>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12132"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:7.17647076;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 202.5,578 c -3.57273,0 -6.5,2.92727 -6.5,6.5 0,1.60752 0.59683,3.08042 1.57422,4.21875 l -2.42774,2.42773 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2.42578,-2.42579 c 1.13822,0.977 2.61355,1.57227 4.2207,1.57227 3.57273,0 6.5,-2.92728 6.5,-6.5 0,-3.57273 -2.92727,-6.5 -6.5,-6.5 z m 0,1 c 3.02727,0 5.5,2.47272 5.5,5.5 0,3.02727 -2.47273,5.5 -5.5,5.5 -3.02727,0 -5.5,-2.47273 -5.5,-5.5 0,-3.02728 2.47273,-5.5 5.5,-5.5 z m -0.008,1.99219 A 0.50005,0.50005 0 0 0 202,581.5 v 2.5 h -2.5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 2.5 a 0.50005,0.50005 0 1 0 1,0 V 585 h 2.5 a 0.50005,0.50005 0 1 0 0,-1 H 203 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ transform="translate(1.8536743e-6,-4.4999696e-6)"
+ id="path4043-7"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g4159-3"
+ transform="translate(61.94871,1.10183)"
+ style="display:inline;fill:#ffffff;enable-background:new" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
+ id="rect4248-2"
+ width="16"
+ height="16"
+ x="193.95"
+ y="577.04999" />
+ </g>
+ <g
+ id="g7089-6"
+ style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="matrix(-0.75,0,0,0.75,348.75712,418.75712)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ id="g7087-1"
+ style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 118.51367,601 a 0.50005001,0.50005001 0 0 0 -0.50586,0.50586 v 3.50195 h -3.50195 a 0.50005001,0.50005001 0 1 0 0,0.99805 h 3.50195 v 3.50195 a 0.50005001,0.50005001 0 1 0 0.99805,0 v -3.50195 h 3.50195 a 0.50005001,0.50005001 0 1 0 0,-0.99805 h -3.50195 v -3.50195 A 0.50005001,0.50005001 0 0 0 118.51367,601 Z"
+ transform="matrix(-1.3333333,0,0,1.3333333,465.00949,-558.34283)"
+ id="path7083-5"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g6666-5" transform="translate(-63.000002,42.000005)" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.79999995;marker:none;enable-background:accumulate" d="m 363.5,536 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z m 2,2 v 1 h 1 v -1 z m 1,1 v 1 h 1 v -1 z m 1,1 v 1 h 1 v -1 z m 0,1 h -1 v 1 h 1 z m -1,1 h -1 v 1 h 1 z m 2,0 v 1 h 3 v -1 z" transform="translate(63.000002,-42.000005)" id="rect40533-7-0" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 240,602 c -1.21759,0 -2.24187,0.34734 -2.94727,1.05273 C 236.34734,603.75813 236,604.78241 236,606 v 3.41992 a 0.50005,0.50005 0 0 0 0.11328,0.4043 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 236.58203,610 H 236.75 A 0.50005,0.50005 0 0 0 237,609.06445 V 606 c 0,-1.03241 0.27766,-1.75813 0.75977,-2.24023 C 238.24187,603.27766 238.96759,603 240,603 h 4.29297 l 2.85351,2.85352 A 0.50005,0.50005 0 0 0 247.5,606 h 1.5 c 0.63889,0 1.1225,0.20453 1.45898,0.54102 C 250.79547,606.8775 251,607.36111 251,608 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 608 c 0,-0.86111 -0.29547,-1.6275 -0.83398,-2.16602 C 250.6275,605.29547 249.86111,605 249,605 h -1.29297 l -2.85351,-2.85352 A 0.50005,0.50005 0 0 0 244.5,602 Z m -0.5,7 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z m 6,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -9,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 9,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z"
+ id="circle12878-4"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="matrix(-0.75,0,0,0.75,369.25,419.25)"
+ style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff;stroke-width:1.33333325;enable-background:new"
+ id="g10315-7"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333325"
+ id="g10313-3">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 300.99023,247.67578 a 0.666995,0.666995 0 1 0 0,1.33399 h 10.66602 a 0.666995,0.666995 0 1 0 0,-1.33399 z"
+ id="path10309-7"
+ inkscape:connector-curvature="0" />
+ </g>
</g>
- <g transform="matrix(-1,0,0,1,635,-357)" id="g12824" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="path12813" d="m 363.5,431 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 0 0 0.14648,0.35352 L 368,437.70703 V 441.5 a 0.50005,0.50005 0 0 0 0.14648,0.35352 l 3,3 A 0.50005,0.50005 0 0 0 372,444.5 v -6.79297 l 4.85352,-4.85351 A 0.50005,0.50005 0 0 0 377,432.5 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 0.29297 l -4.85352,4.85351 A 0.50005,0.50005 0 0 0 371,437.5 v 5.79297 l -2,-2 V 437.5 a 0.50005,0.50005 0 0 0 -0.14648,-0.35352 L 364,432.29297 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
+ <g
+ id="g10247-8"
+ style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="matrix(-0.53033009,-0.53033009,-0.53033009,0.53033009,454.86353,636.75914)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ id="g10245-2"
+ style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 306.99023,241.72461 a 0.66673335,0.66673335 0 0 0 -0.65625,0.67578 v 5.93359 h -5.93359 a 0.66673335,0.66673335 0 1 0 0,1.33204 h 5.93359 v 5.93359 a 0.66673335,0.66673335 0 1 0 1.33204,0 v -5.93359 h 5.93359 a 0.66673335,0.66673335 0 1 0 0,-1.33204 h -5.93359 v -5.93359 a 0.66673335,0.66673335 0 0 0 -0.67579,-0.67578 z"
+ id="path10243-3"
+ inkscape:connector-curvature="0" />
+ </g>
</g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g6750-7" transform="translate(-314.99995,-567)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <rect y="598" x="614" height="16" width="16" id="rect6732-0" style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1;stroke-opacity:1;marker:none"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 618.74609,599 a 0.50005,0.50005 0 0 0 -0.48437,0.37695 l -3.2461,12.75 A 0.50005,0.50005 0 0 0 615,612.25 v 0.25 a 0.50005,0.50005 0 1 0 1,0 v -0.1875 l 0.84961,-3.33398 A 0.50005,0.50005 0 0 0 617,609 h 4 a 0.50005,0.50005 0 0 0 0.14844,-0.0195 h 0.002 L 622,612.3125 V 612.5 a 0.50005,0.50005 0 1 0 1,0 v -0.25 a 0.50005,0.50005 0 0 0 -0.0156,-0.12305 l -3.25391,-12.75 A 0.50005,0.50005 0 0 0 619.24609,599 Z m 0.25,1.54492 1.90235,7.45508 h -3.80078 z" id="path6736-8" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 310,45 v -5 h 1.5 c 0.83481,0 1.5,0.664144 1.5,1.498047 v 2.007812 c 0,0.833914 -0.66519,1.498047 -1.5,1.496094 z m 4,-1.494141 V 41.498047 C 314,40.122764 312.87431,39 311.5,39 H 310 v -6.5 c 0.004,-0.28226 -0.22555,-0.512233 -0.50781,-0.507812 C 309.21605,31.996188 308.99568,32.22386 309,32.5 v 13 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 l 2,0.002 c 1.37431,0.002 2.5,-1.120801 2.5,-2.496094 z" transform="translate(314.99995,567)" id="path6744-7" inkscape:connector-curvature="0" sodipodi:nodetypes="ccsccccccsccccccccc"/>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12144"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:7.17647076;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 181.5,578 c -3.57273,0 -6.5,2.92727 -6.5,6.5 0,1.60752 0.59683,3.08042 1.57422,4.21875 l -2.42774,2.42773 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2.42578,-2.42579 c 1.13822,0.977 2.61355,1.57227 4.2207,1.57227 3.57273,0 6.5,-2.92728 6.5,-6.5 0,-3.57273 -2.92727,-6.5 -6.5,-6.5 z m 0,1 c 2.85852,0 5.21992,2.20548 5.47461,5 h -6.26758 l 2.14649,-2.14648 c 0.32529,-0.31801 0.0914,-0.86992 -0.36329,-0.85743 -0.12976,0.004 -0.25303,0.0575 -0.34375,0.15039 l -2.95703,2.95704 c -0.26095,0.19951 -0.26189,0.59214 -0.002,0.79296 0.002,10e-4 0.004,0.003 0.006,0.004 l 2.95312,2.95313 c 0.47127,0.49023 1.19727,-0.23577 0.70704,-0.70704 L 180.70703,585 h 6.26758 c -0.25469,2.79451 -2.61609,5 -5.47461,5 -3.02727,0 -5.5,-2.47273 -5.5,-5.5 0,-3.02728 2.47273,-5.5 5.5,-5.5 z"
+ transform="translate(1.8536743e-6,-4.4999696e-6)"
+ id="path9890-4"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(40.94871,1.10183)"
+ id="g9896-8" />
+ <rect
+ y="577.04999"
+ x="172.95"
+ height="16"
+ width="16"
+ id="rect9898-1"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g5506-8"
+ transform="translate(-44.000002,63.000005)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 556.57617,409.98047 a 0.55005501,0.55005501 0 0 0 -0.42383,0.18555 c -0.46657,0.51387 -1.20227,1.13094 -1.20312,2.14257 -10e-4,1.1847 0.85571,2.11411 1.94336,2.91797 1.08765,0.80386 2.47935,1.527 3.84765,2.25782 0.44143,0.23577 0.88243,0.47055 1.3086,0.70312 1.11316,0.60746 2.13512,1.2144 2.84375,1.81836 0.70862,0.60396 1.05894,1.15906 1.05859,1.68359 -4e-4,0.48086 -0.32771,1.0064 -0.79492,1.38086 a 0.55027044,0.55027044 0 1 0 0.6875,0.85938 c 0.65297,-0.52334 1.20625,-1.30182 1.20703,-2.23828 6.6e-4,-0.99421 -0.62031,-1.82029 -1.44531,-2.52344 -0.825,-0.70315 -1.89813,-1.32892 -3.03125,-1.94727 -0.43383,-0.23675 -0.87476,-0.47023 -1.31445,-0.70508 -1.37366,-0.73367 -2.73478,-1.45092 -3.71289,-2.17382 -0.97812,-0.72291 -1.49874,-1.40647 -1.49805,-2.03125 3.7e-4,-0.43907 0.39742,-0.83099 0.91797,-1.4043 a 0.55005501,0.55005501 0 0 0 -0.39063,-0.92578 z"
+ id="path5432-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 565.45508,409.94531 a 0.55005501,0.55005501 0 0 0 -0.31446,0.97071 c 0.44122,0.38244 0.8125,1.03351 0.8125,1.58398 -0.002,0.56635 -0.25363,0.95243 -0.74218,1.35938 -0.48909,0.40739 -1.20703,0.77343 -1.95703,1.14843 a 0.55028291,0.55028291 0 1 0 0.49218,0.98438 c 0.75,-0.375 1.5313,-0.75874 2.16797,-1.28907 0.63668,-0.53032 1.13681,-1.26964 1.13867,-2.20312 0,-0.98667 -0.54281,-1.85212 -1.19335,-2.41602 a 0.55005501,0.55005501 0 0 0 -0.4043,-0.13867 z m -6.95313,8.00196 a 0.55005501,0.55005501 0 0 0 -0.24804,0.0605 c -0.75,0.375 -1.5313,0.75874 -2.16797,1.28907 -0.63668,0.53032 -1.13681,1.26964 -1.13867,2.20312 0,0.98843 0.53602,1.85319 1.19335,2.41797 a 0.55122854,0.55122854 0 1 0 0.71876,-0.83594 c -0.44771,-0.38466 -0.8125,-1.01968 -0.8125,-1.58203 0.002,-0.56635 0.25363,-0.95243 0.74218,-1.35938 0.48909,-0.40739 1.20703,-0.77343 1.95703,-1.14843 a 0.55005501,0.55005501 0 0 0 -0.24414,-1.04492 z"
+ id="path5435-6"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5484-0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 557.5,421 a 0.50005,0.50005 0 1 0 0,1 h 2 A 0.50005,0.50005 0 0 0 560,421.58008 0.50005,0.50005 0 0 0 560.5,422 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -4 A 0.50005,0.50005 0 0 0 560,421.41992 0.50005,0.50005 0 0 0 559.5,421 Z m 0,-9 a 0.50005,0.50005 0 1 0 0,1 h 4 A 0.50005,0.50005 0 0 0 562,412.58008 0.50005,0.50005 0 0 0 562.5,413 h 2 a 0.50005,0.50005 0 1 0 0,-1 h -2 A 0.50005,0.50005 0 0 0 562,412.41992 0.50005,0.50005 0 0 0 561.5,412 Z"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="matrix(-0.53033009,-0.53033009,-0.53033009,0.53033009,706.86353,657.75914)"
+ style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ id="g10178-9"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none"
+ id="g10176-5">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 306.99023,241.72461 a 0.66673335,0.66673335 0 0 0 -0.65625,0.67578 v 5.93359 h -5.93359 a 0.66673335,0.66673335 0 1 0 0,1.33204 h 5.93359 v 5.93359 a 0.66673335,0.66673335 0 1 0 1.33204,0 v -5.93359 h 5.93359 a 0.66673335,0.66673335 0 1 0 0,-1.33204 h -5.93359 v -5.93359 a 0.66673335,0.66673335 0 0 0 -0.67579,-0.67578 z"
+ id="path10174-2"
+ inkscape:connector-curvature="0" />
+ </g>
</g>
- <g transform="translate(-231.00712,-588.00007)" id="g23192-6" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g transform="translate(21)" id="g23190-0" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 553.5,620 a 0.50005,0.50005 0 1 0 0,1 h 10.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 10.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 10.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,5 a 0.50005,0.50005 0 1 0 0,1 h 10.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 10.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 11 a 0.50005,0.50005 0 1 0 0,-1 z" id="path23186-9" inkscape:connector-curvature="0"/>
+ <g
+ transform="translate(20.999998,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g23194">
+ <g
+ transform="translate(430,-112)"
+ id="g12465"
+ style="fill:#ffffff" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 79.570312,578.01758 c -0.797869,-0.038 -1.571767,0.27684 -2.160156,0.86523 l -1.486328,1.48828 c -0.615772,0.57533 -0.93433,1.35407 -0.892578,2.1543 a 0.50005,0.50005 0 1 0 0.998047,-0.0508 c -0.02687,-0.51495 0.155664,-0.98016 0.576172,-1.37305 a 0.50005,0.50005 0 0 0 0.01172,-0.0117 l 1.5,-1.5 c 0.411611,-0.41161 0.889666,-0.59872 1.404296,-0.57422 0.514631,0.0245 1.084383,0.26993 1.638672,0.82422 0.554795,0.5548 0.809544,1.13546 0.837891,1.65235 0.02835,0.51688 -0.152405,0.9848 -0.574219,1.3789 a 0.50005,0.50005 0 0 0 -0.01367,0.0117 l -1.5,1.5 c -0.412129,0.41213 -0.876932,0.60352 -1.396484,0.60352 a 0.50005,0.50005 0 1 0 0,1 c 0.780667,0 1.524905,-0.31788 2.103516,-0.89649 l 1.488281,-1.48828 c 0.617686,-0.57711 0.936606,-1.36125 0.892578,-2.16406 -0.04403,-0.80281 -0.435654,-1.60948 -1.130859,-2.30469 -0.695711,-0.69571 -1.499006,-1.07724 -2.296876,-1.11523 z m -1.080078,3.97851 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -5,5 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 5,-5 a 0.50005,0.50005 0 0 0 -0.363282,-0.85743 z m -4.929687,2.02149 c -0.807524,-0.0482 -1.595401,0.26944 -2.175781,0.89062 l -1.488282,1.48828 c -0.588388,0.58839 -0.903228,1.36034 -0.865234,2.15821 0.03799,0.79787 0.419524,1.60311 1.115234,2.29883 0.695206,0.6952 1.503832,1.08487 2.306641,1.1289 0.802809,0.044 1.584996,-0.27294 2.162109,-0.89062 l 1.488282,-1.48828 C 76.682126,589.0249 77,588.28067 77,587.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.51955 -0.191386,0.98436 -0.603516,1.39648 l -1.5,1.5 a 0.50005,0.50005 0 0 0 -0.01172,0.0117 c -0.394107,0.42182 -0.860068,0.60452 -1.376954,0.57618 -0.516885,-0.0283 -1.099502,-0.2831 -1.654296,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.822266,-1.63867 -0.02451,-0.51463 0.160654,-0.99268 0.572266,-1.40429 l 1.5,-1.5 a 0.50005,0.50005 0 0 0 0.01172,-0.0117 c 0.39634,-0.4242 0.866283,-0.60725 1.386719,-0.57618 a 0.50005,0.50005 0 1 0 0.05859,-0.99804 z"
+ id="path12469"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.15384436;enable-background:new"
+ id="g12595"
+ transform="matrix(0.866668,0,0,0.866668,-177.46699,184.39943)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ style="fill:#ffffff;stroke-width:1.15384436"
+ id="g12593">
+ <path
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ d="m 34,557 c -3.860079,0 -7,3.13992 -7,7 0,3.86008 3.139921,7 7,7 3.860079,0 7,-3.13992 7,-7 0,-3.86008 -3.139921,-7 -7,-7 z m 0,1 c 3.305801,0 5.975833,2.65852 5.998047,5.95898 C 38.886544,564.90262 36.995365,566 34,566 v 4 c -3.319633,0 -6,-2.68037 -6,-6 0,-0.0145 0.0019,-0.0285 0.002,-0.043 C 29.113203,564.90101 31.002992,566 34,566 Z"
+ transform="matrix(1.1538444,0,0,1.1538444,204.76929,-212.76825)"
+ id="path12589"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g12563-2" transform="translate(-84.000002,4.4999696e-6)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path inkscape:connector-curvature="0" id="rect12547-2" d="m 405,32 v 8 h 14 v -8 z m 2.50781,2 h 8.98438 c 0.67616,-0.0096 0.67616,1.009563 0,1 h -8.98438 c -0.67616,0.0096 -0.67616,-1.009563 0,-1 z m 0,3 h 8.98438 c 0.67616,-0.0096 0.67616,1.009563 0,1 h -8.98438 c -0.67616,0.0096 -0.67616,-1.009563 0,-1 z" style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.00000003, 2.00000004;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" sodipodi:nodetypes="ccccccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 407.50781,42 a 0.50005,0.50005 0 1 0 0,1 h 8.98438 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 8.98438 a 0.50005,0.50005 0 1 0 0,-1 z" id="path12541-0" inkscape:connector-curvature="0"/>
+ <g
+ id="g6666-5"
+ transform="translate(-63.000002,42.000005)"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.79999995;marker:none;enable-background:accumulate"
+ d="m 363.5,536 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z m 2,2 v 1 h 1 v -1 z m 1,1 v 1 h 1 v -1 z m 1,1 v 1 h 1 v -1 z m 0,1 h -1 v 1 h 1 z m -1,1 h -1 v 1 h 1 z m 2,0 v 1 h 3 v -1 z"
+ transform="translate(63.000002,-42.000005)"
+ id="rect40533-7-0"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="matrix(-1,0,0,1,635,-357)"
+ id="g12824"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="path12813"
+ d="m 363.5,431 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 0 0 0.14648,0.35352 L 368,437.70703 V 441.5 a 0.50005,0.50005 0 0 0 0.14648,0.35352 l 3,3 A 0.50005,0.50005 0 0 0 372,444.5 v -6.79297 l 4.85352,-4.85351 A 0.50005,0.50005 0 0 0 377,432.5 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 0.29297 l -4.85352,4.85351 A 0.50005,0.50005 0 0 0 371,437.5 v 5.79297 l -2,-2 V 437.5 a 0.50005,0.50005 0 0 0 -0.14648,-0.35352 L 364,432.29297 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g6750-7"
+ transform="translate(-314.99995,-567)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <rect
+ y="598"
+ x="614"
+ height="16"
+ width="16"
+ id="rect6732-0"
+ style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1;stroke-opacity:1;marker:none" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 618.74609,599 a 0.50005,0.50005 0 0 0 -0.48437,0.37695 l -3.2461,12.75 A 0.50005,0.50005 0 0 0 615,612.25 v 0.25 a 0.50005,0.50005 0 1 0 1,0 v -0.1875 l 0.84961,-3.33398 A 0.50005,0.50005 0 0 0 617,609 h 4 a 0.50005,0.50005 0 0 0 0.14844,-0.0195 h 0.002 L 622,612.3125 V 612.5 a 0.50005,0.50005 0 1 0 1,0 v -0.25 a 0.50005,0.50005 0 0 0 -0.0156,-0.12305 l -3.25391,-12.75 A 0.50005,0.50005 0 0 0 619.24609,599 Z m 0.25,1.54492 1.90235,7.45508 h -3.80078 z"
+ id="path6736-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 310,45 v -5 h 1.5 c 0.83481,0 1.5,0.664144 1.5,1.498047 v 2.007812 c 0,0.833914 -0.66519,1.498047 -1.5,1.496094 z m 4,-1.494141 V 41.498047 C 314,40.122764 312.87431,39 311.5,39 H 310 v -6.5 c 0.004,-0.28226 -0.22555,-0.512233 -0.50781,-0.507812 C 309.21605,31.996188 308.99568,32.22386 309,32.5 v 13 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 l 2,0.002 c 1.37431,0.002 2.5,-1.120801 2.5,-2.496094 z"
+ transform="translate(314.99995,567)"
+ id="path6744-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccsccccccsccccccccc" />
+ </g>
+ <g
+ transform="translate(-231.00712,-588.00007)"
+ id="g23192-6"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ transform="translate(21)"
+ id="g23190-0"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 553.5,620 a 0.50005,0.50005 0 1 0 0,1 h 10.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 10.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 10.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,5 a 0.50005,0.50005 0 1 0 0,1 h 10.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 10.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 11 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path23186-9"
+ inkscape:connector-curvature="0" />
+ </g>
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 279.5,32 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 292.5,32 Z m 0.5,1 h 12 v 12 h -12 z" id="rect12615-8" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 282.56641,35 a 0.50005,0.50005 0 1 0 -0.008,1 l 4.9375,0.03125 a 0.50005,0.50005 0 1 0 0.008,-1 z m 0,2 a 0.50005,0.50005 0 1 0 -0.008,1 l 3.9375,0.03125 a 0.50005,0.50005 0 1 0 0.008,-1 z m 0.004,2 a 0.50006099,0.50006099 0 1 0 -0.0156,1 l 1.9375,0.03125 a 0.50006099,0.50006099 0 1 0 0.0156,-1 z m -0.006,2 a 0.50005,0.50005 0 1 0 -0.004,1 l 5.9375,0.03125 a 0.50005,0.50005 0 1 0 0.004,-1 z" id="path12623-2" inkscape:connector-curvature="0"/>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g10061" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g id="g9978" transform="translate(159,3)" style="display:inline;fill:#ffffff;enable-background:new">
- <g style="display:inline;fill:#ffffff;stroke-width:1.25052631;enable-background:new" id="g9976" transform="matrix(0.79966332,0,0,0.79966332,-130.65118,113.69494)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 142,578 c -2.19759,0 -4,1.80241 -4,4 0,0.9193 0.32769,1.75955 0.85547,2.4375 l -3.70899,3.70898 a 0.50029086,0.50029086 0 1 0 0.70704,0.70704 l 3.70898,-3.70899 C 140.24045,585.67231 141.0807,586 142,586 c 2.19759,0 4,-1.80241 4,-4 0,-2.19759 -1.80241,-4 -4,-4 z m 0,1 c 1.65213,0 3,1.34787 3,3 0,1.65213 -1.34787,3 -3,3 -1.65214,0 -3,-1.34787 -3,-3 0,-1.65214 1.34786,-3 3,-3 z" transform="matrix(1.2505263,0,0,1.2505263,-35.450942,-145.9301)" id="path9971" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g12563-2"
+ transform="translate(-84.000002,4.4999696e-6)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ inkscape:connector-curvature="0"
+ id="rect12547-2"
+ d="m 405,32 v 8 h 14 v -8 z m 2.50781,2 h 8.98438 c 0.67616,-0.0096 0.67616,1.009563 0,1 h -8.98438 c -0.67616,0.0096 -0.67616,-1.009563 0,-1 z m 0,3 h 8.98438 c 0.67616,-0.0096 0.67616,1.009563 0,1 h -8.98438 c -0.67616,0.0096 -0.67616,-1.009563 0,-1 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.00000003, 2.00000004;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ sodipodi:nodetypes="ccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 407.50781,42 a 0.50005,0.50005 0 1 0 0,1 h 8.98438 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 8.98438 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path12541-0"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 279.5,32 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 292.5,32 Z m 0.5,1 h 12 v 12 h -12 z"
+ id="rect12615-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 282.56641,35 a 0.50005,0.50005 0 1 0 -0.008,1 l 4.9375,0.03125 a 0.50005,0.50005 0 1 0 0.008,-1 z m 0,2 a 0.50005,0.50005 0 1 0 -0.008,1 l 3.9375,0.03125 a 0.50005,0.50005 0 1 0 0.008,-1 z m 0.004,2 a 0.50006099,0.50006099 0 1 0 -0.0156,1 l 1.9375,0.03125 a 0.50006099,0.50006099 0 1 0 0.0156,-1 z m -0.006,2 a 0.50005,0.50005 0 1 0 -0.004,1 l 5.9375,0.03125 a 0.50005,0.50005 0 1 0 0.004,-1 z"
+ id="path12623-2"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g10061"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ id="g9978"
+ transform="translate(159,3)"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <g
+ style="display:inline;fill:#ffffff;stroke-width:1.25052631;enable-background:new"
+ id="g9976"
+ transform="matrix(0.79966332,0,0,0.79966332,-130.65118,113.69494)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 142,578 c -2.19759,0 -4,1.80241 -4,4 0,0.9193 0.32769,1.75955 0.85547,2.4375 l -3.70899,3.70898 a 0.50029086,0.50029086 0 1 0 0.70704,0.70704 l 3.70898,-3.70899 C 140.24045,585.67231 141.0807,586 142,586 c 2.19759,0 4,-1.80241 4,-4 0,-2.19759 -1.80241,-4 -4,-4 z m 0,1 c 1.65213,0 3,1.34787 3,3 0,1.65213 -1.34787,3 -3,3 -1.65214,0 -3,-1.34787 -3,-3 0,-1.65214 1.34786,-3 3,-3 z"
+ transform="matrix(1.2505263,0,0,1.2505263,-35.450942,-145.9301)"
+ id="path9971"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" transform="translate(-21.00001,84.99938)" id="g10042">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 135.48438,579 c -0.12718,0.004 -0.248,0.0564 -0.3379,0.14648 l -3,3 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 580 h 0.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -1 v 0.002 c -0.005,0 -0.0101,-0.002 -0.0156,-0.002 z M 132,584 v 7.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 9 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c 0.01,-0.67616 -1.00956,-0.67616 -1,0 v 3.5 h -8 v -7 z" transform="translate(21.000012,-84.999384)" id="path10038" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ transform="translate(-21.00001,84.99938)"
+ id="g10042">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 135.48438,579 c -0.12718,0.004 -0.248,0.0564 -0.3379,0.14648 l -3,3 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 580 h 0.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -1 v 0.002 c -0.005,0 -0.0101,-0.002 -0.0156,-0.002 z M 132,584 v 7.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 9 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c 0.01,-0.67616 -1.00956,-0.67616 -1,0 v 3.5 h -8 v -7 z"
+ transform="translate(21.000012,-84.999384)"
+ id="path10038"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 370.49414,224.00195 a 0.50005,0.50005 0 0 0 -0.34766,0.14649 l -4,3.99804 a 0.50005,0.50005 0 0 0 0,0.70704 l 4,4 a 0.50005,0.50005 0 0 0 0.70508,0 l 3.99219,-3.97852 a 0.50005,0.50005 0 0 0 0.002,-0.70703 l -3.99218,-4.01953 a 0.50005,0.50005 0 0 0 -0.35938,-0.14649 z m 0.004,1.20899 3.28711,3.30859 L 370.5,231.79297 367.20703,228.5 Z" id="path23352-4" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 349.49414,224 c -0.13124,0.001 -0.25681,0.0537 -0.34961,0.14648 l -3.99805,4 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 3.99805,4 c 0.19526,0.19518 0.51177,0.19518 0.70703,0 l 3.99219,-3.97852 c 0.19574,-0.19471 0.19663,-0.51121 0.002,-0.70703 l -3.99218,-4.01953 c -0.0949,-0.0959 -0.2245,-0.14948 -0.35943,-0.14844 z" id="path23378-3" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 328.48047,226.75 a 0.50005,0.50005 0 0 0 -0.39063,0.21484 l -3.99023,5.72461 a 0.50005,0.50005 0 0 0 -0.0898,0.27735 L 324,233.49219 A 0.50005,0.50005 0 0 0 324.5,234 h 8 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 233 a 0.50005,0.50005 0 0 0 -0.0898,-0.28516 l -4,-5.75 A 0.50005,0.50005 0 0 0 328.48047,226.75 Z m 0.0195,1.375 3.39062,4.875 h -6.78906 z" id="path23380-3" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 307.48242,226.75 c -0.15739,0.006 -0.30286,0.0854 -0.39258,0.21484 l -4,5.75 c -0.0583,0.0837 -0.0897,0.18317 -0.0898,0.28516 v 0.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 8 c 0.27999,2e-5 0.50544,-0.22983 0.5,-0.50977 l -0.01,-0.47461 c -0.002,-0.0985 -0.0321,-0.19425 -0.0879,-0.27539 l -3.99023,-5.77539 c -0.0971,-0.14016 -0.25903,-0.22114 -0.42945,-0.21484 z" id="path23382-9" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccc"/>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g12105" transform="translate(-147.00001,-566.99994)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <rect y="597.99994" x="278" height="16" width="16" id="rect12101" style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 286,599 c -3.8542,0 -7,3.1458 -7,7 0,3.8542 3.1458,7 7,7 3.8542,0 7,-3.1458 7,-7 0,-3.8542 -3.1458,-7 -7,-7 z m 0,2 c 2.77332,0 5,2.22668 5,5 0,2.77332 -2.22668,5 -5,5 -2.77332,0 -5,-2.22668 -5,-5 0,-2.77332 2.22668,-5 5,-5 z" id="path12103" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 6.5,32 A 0.50005,0.50005 0 0 0 6,32.5 v 13 A 0.50005,0.50005 0 0 0 6.5,46 h 13 A 0.50005,0.50005 0 0 0 20,45.5 v -13 A 0.50005,0.50005 0 0 0 19.5,32 Z M 7,33 H 19 V 45 H 7 Z" id="rect12121" inkscape:connector-curvature="0"/>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g12135" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 158.5,222 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 155.29297,225 H 153.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.79297 l 2.85351,2.85352 A 0.50005,0.50005 0 0 0 158.5,234 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 222.78125 222.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 159 v 10 h -0.29297 l -2.85351,-2.85352 A 0.50005,0.50005 0 0 0 155.5,230 H 154 v -4 h 1.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 z" id="path12129" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 165.4668,223.01562 a 0.50005,0.50005 0 0 0 -0.42188,0.72071 c 1.27607,2.70648 1.27309,5.84072 -0.008,8.54492 a 0.50017783,0.50017783 0 1 0 0.9043,0.42773 c 1.40867,-2.97397 1.41118,-6.42391 0.008,-9.40039 a 0.50005,0.50005 0 0 0 -0.48242,-0.29297 z m -2.86133,0.9375 a 0.50005,0.50005 0 0 0 -0.43359,0.74219 c 1.10287,2.06013 1.10465,4.5334 0.006,6.59571 a 0.50023236,0.50023236 0 1 0 0.88282,0.4707 c 1.25518,-2.35583 1.25203,-5.18378 -0.008,-7.53711 a 0.50005,0.50005 0 0 0 -0.44726,-0.27149 z" id="path12133" inkscape:connector-curvature="0"/>
- </g>
- <g id="g6417" style="fill:#ffffff">
- <path id="path8180-3" d="m 470.66016,493.97656 c -0.37961,-0.006 -0.76447,0.0652 -1.1211,0.21289 -0.93286,0.38641 -1.54492,1.30084 -1.54492,2.31055 v 3.5 h 1 v -3.5 c 0,-0.60813 0.3659,-1.154 0.92774,-1.38672 0.5437,-0.22521 1.42162,-0.0569 1.71874,0.24024 l 0.5,0.5 c 0.47128,0.49023 1.19727,-0.23577 0.70704,-0.70704 l -0.5,-0.5 c -0.35144,-0.35143 -0.81472,-0.56325 -1.31055,-0.63867 -0.12396,-0.0188 -0.25042,-0.0294 -0.37695,-0.0312 z m 8.67382,0 c -0.12653,0.002 -0.25299,0.0124 -0.37695,0.0312 -0.49583,0.0754 -0.95911,0.28724 -1.31055,0.63867 l -0.5,0.5 c -0.49023,0.47127 0.23577,1.19727 0.70704,0.70704 l 0.5,-0.5 c 0.29713,-0.29714 1.17505,-0.46545 1.71875,-0.24024 C 480.63411,495.346 481,495.89187 481,496.5 v 3.5 h 1 v -3.5 c 0,-1.00971 -0.61206,-1.92414 -1.54492,-2.31055 -0.35663,-0.1477 -0.74149,-0.21856 -1.1211,-0.21289 z M 468.49414,501 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1 3.00586 a 0.50005,0.50005 0 0 0 0.41602,-0.22266 L 474.76758,505 h 0.46484 l 1.85156,2.77734 A 0.50005,0.50005 0 0 0 477.5,508 h 2.99414 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -6 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z M 474,502 v 2.34766 L 472.23242,507 h -2.23828 -1 L 469,502.00195 Z m 1.99414,0 5,0.002 V 507 h -0.5 H 480 477.76758 L 476,504.34766 Z" style="fill:#ffffff;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" inkscape:connector-curvature="0"/>
- <path sodipodi:nodetypes="ccccccccccc" inkscape:connector-curvature="0" id="path8043-2" d="m 470.49414,503 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 H 471.5 c 0.16717,-10e-6 0.32328,-0.0836 0.41602,-0.22266 l 1,-1.5 c 0.0559,-0.0838 0.0852,-0.18249 0.084,-0.2832 l -0.006,-0.5 c -0.003,-0.27384 -0.22614,-0.49413 -0.5,-0.49414 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <path style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" d="m 115,32 v 2 h 6 v -2 z m 6,2 v 2 h 2 v -2 z m 2,2 v 6 h 2 v -6 z m 0,6 h -2 v 2 h 2 z m -2,2 h -6 v 2 h 6 z m -6,0 v -2 h -2 v 2 z m -2,-2 v -6 h -2 v 6 z m 0,-6 h 2 v -2 h -2 z" id="rect23113-8" inkscape:connector-curvature="0"/>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" transform="translate(-420.00718,439.99283)" id="g7406-1-2" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 27.492188,598.99219 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.49805 L 41,605 l -1,-0.002 -0.0059,2.99414 H 27.992188 v -8 h 8 v 3.5 c 2.9e-5,0.27613 0.223869,0.49997 0.5,0.5 h 4 c 0.44533,-1.7e-4 0.668305,-0.53852 0.353515,-0.85352 l -4,-4 c -0.09376,-0.0938 -0.22116,-0.14439 -0.353515,-0.14453 v -0.002 h -0.0078 z M 35,610 l -2,0.004 v 1.98828 h -2.507812 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 7 c 0.676159,0.01 0.676159,-1.00956 0,-1 H 35 Z" transform="translate(420.00718,-439.99283)" id="path7395-0-0" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 53.494141,601.99414 a 0.50005,0.50005 0 0 0 -0.347657,0.85938 l 3.646485,3.64648 -3.646485,3.64648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 4,-4 a 0.50005,0.50005 0 0 0 0,-0.70704 l -4,-4 a 0.50005,0.50005 0 0 0 -0.359375,-0.15234 z" id="path9518-7-7" inkscape:connector-curvature="0"/>
- <g id="g6733" transform="translate(-42.000002,503.9)" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <rect ry="0" rx="0" y="31" x="68" height="16" width="16" id="rect4338" style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 81.75,32.099609 c -1.433114,0 -2.573994,0.599965 -3.328125,1.414063 -0.754131,0.814098 -1.193245,1.779187 -1.615234,2.65039 -0.42199,0.871204 -0.825206,1.64712 -1.308594,2.146485 -0.483388,0.499365 -0.99066,0.789062 -1.998047,0.789062 H 69 v 2 h 4.5 c 1.476988,0 2.648427,-0.585302 3.435547,-1.398437 0.78712,-0.813135 1.246208,-1.787219 1.671875,-2.666016 0.425667,-0.878796 0.819561,-1.663707 1.28125,-2.162109 0.461689,-0.498402 0.919442,-0.773438 1.861328,-0.773438 H 83 v -2 z" id="path4336" inkscape:connector-curvature="0"/>
- <g id="g23052" style="opacity:0.7;fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 27,536.90039 v 1.19922 h 0.75 c 0.646429,0 1.301953,0.38 1.880859,1.04297 0.578907,0.66296 1.046871,1.58637 1.289063,2.49023 0.207018,0.77346 1.367174,0.46292 1.160156,-0.31054 -0.287808,-1.07411 -0.818828,-2.13723 -1.544922,-2.96875 -0.726093,-0.83153 -1.681585,-1.45313 -2.785156,-1.45313 z m 13.25,9 c -1.91571,0 -2.93215,0.90502 -3.558594,1.66992 -0.313222,0.38245 -0.555819,0.7142 -0.798828,0.91797 -0.243008,0.20377 -0.458964,0.3125 -0.892578,0.3125 -0.401011,0 -0.71548,-0.20341 -1.054688,-0.64648 -0.339207,-0.44308 -0.639641,-1.1033 -0.878906,-1.79492 -0.238226,-0.80225 -1.442094,-0.38505 -1.132812,0.39257 0.260735,0.7537 0.585301,1.5146 1.058594,2.13282 C 33.46548,549.50298 34.151011,550 35,550 c 0.691386,0 1.25668,-0.25378 1.662109,-0.59375 0.405429,-0.33997 0.678457,-0.73364 0.958985,-1.07617 0.561056,-0.68506 1.044616,-1.23047 2.628906,-1.23047 H 41 v -1.19922 z" transform="translate(42.000002,-503.9)" id="path4334" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 370.49414,224.00195 a 0.50005,0.50005 0 0 0 -0.34766,0.14649 l -4,3.99804 a 0.50005,0.50005 0 0 0 0,0.70704 l 4,4 a 0.50005,0.50005 0 0 0 0.70508,0 l 3.99219,-3.97852 a 0.50005,0.50005 0 0 0 0.002,-0.70703 l -3.99218,-4.01953 a 0.50005,0.50005 0 0 0 -0.35938,-0.14649 z m 0.004,1.20899 3.28711,3.30859 L 370.5,231.79297 367.20703,228.5 Z"
+ id="path23352-4"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 349.49414,224 c -0.13124,0.001 -0.25681,0.0537 -0.34961,0.14648 l -3.99805,4 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 3.99805,4 c 0.19526,0.19518 0.51177,0.19518 0.70703,0 l 3.99219,-3.97852 c 0.19574,-0.19471 0.19663,-0.51121 0.002,-0.70703 l -3.99218,-4.01953 c -0.0949,-0.0959 -0.2245,-0.14948 -0.35943,-0.14844 z"
+ id="path23378-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 328.48047,226.75 a 0.50005,0.50005 0 0 0 -0.39063,0.21484 l -3.99023,5.72461 a 0.50005,0.50005 0 0 0 -0.0898,0.27735 L 324,233.49219 A 0.50005,0.50005 0 0 0 324.5,234 h 8 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 233 a 0.50005,0.50005 0 0 0 -0.0898,-0.28516 l -4,-5.75 A 0.50005,0.50005 0 0 0 328.48047,226.75 Z m 0.0195,1.375 3.39062,4.875 h -6.78906 z"
+ id="path23380-3"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 307.48242,226.75 c -0.15739,0.006 -0.30286,0.0854 -0.39258,0.21484 l -4,5.75 c -0.0583,0.0837 -0.0897,0.18317 -0.0898,0.28516 v 0.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 8 c 0.27999,2e-5 0.50544,-0.22983 0.5,-0.50977 l -0.01,-0.47461 c -0.002,-0.0985 -0.0321,-0.19425 -0.0879,-0.27539 l -3.99023,-5.77539 c -0.0971,-0.14016 -0.25903,-0.22114 -0.42945,-0.21484 z"
+ id="path23382-9"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccc" />
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g12105"
+ transform="translate(-147.00001,-566.99994)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <rect
+ y="597.99994"
+ x="278"
+ height="16"
+ width="16"
+ id="rect12101"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 286,599 c -3.8542,0 -7,3.1458 -7,7 0,3.8542 3.1458,7 7,7 3.8542,0 7,-3.1458 7,-7 0,-3.8542 -3.1458,-7 -7,-7 z m 0,2 c 2.77332,0 5,2.22668 5,5 0,2.77332 -2.22668,5 -5,5 -2.77332,0 -5,-2.22668 -5,-5 0,-2.77332 2.22668,-5 5,-5 z"
+ id="path12103"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 6.5,32 A 0.50005,0.50005 0 0 0 6,32.5 v 13 A 0.50005,0.50005 0 0 0 6.5,46 h 13 A 0.50005,0.50005 0 0 0 20,45.5 v -13 A 0.50005,0.50005 0 0 0 19.5,32 Z M 7,33 H 19 V 45 H 7 Z"
+ id="rect12121"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g12135"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 158.5,222 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 155.29297,225 H 153.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.79297 l 2.85351,2.85352 A 0.50005,0.50005 0 0 0 158.5,234 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 222.78125 222.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 159 v 10 h -0.29297 l -2.85351,-2.85352 A 0.50005,0.50005 0 0 0 155.5,230 H 154 v -4 h 1.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 z"
+ id="path12129"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 165.4668,223.01562 a 0.50005,0.50005 0 0 0 -0.42188,0.72071 c 1.27607,2.70648 1.27309,5.84072 -0.008,8.54492 a 0.50017783,0.50017783 0 1 0 0.9043,0.42773 c 1.40867,-2.97397 1.41118,-6.42391 0.008,-9.40039 a 0.50005,0.50005 0 0 0 -0.48242,-0.29297 z m -2.86133,0.9375 a 0.50005,0.50005 0 0 0 -0.43359,0.74219 c 1.10287,2.06013 1.10465,4.5334 0.006,6.59571 a 0.50023236,0.50023236 0 1 0 0.88282,0.4707 c 1.25518,-2.35583 1.25203,-5.18378 -0.008,-7.53711 a 0.50005,0.50005 0 0 0 -0.44726,-0.27149 z"
+ id="path12133"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g6417"
+ style="fill:#ffffff">
+ <path
+ id="path8180-3"
+ d="m 470.66016,493.97656 c -0.37961,-0.006 -0.76447,0.0652 -1.1211,0.21289 -0.93286,0.38641 -1.54492,1.30084 -1.54492,2.31055 v 3.5 h 1 v -3.5 c 0,-0.60813 0.3659,-1.154 0.92774,-1.38672 0.5437,-0.22521 1.42162,-0.0569 1.71874,0.24024 l 0.5,0.5 c 0.47128,0.49023 1.19727,-0.23577 0.70704,-0.70704 l -0.5,-0.5 c -0.35144,-0.35143 -0.81472,-0.56325 -1.31055,-0.63867 -0.12396,-0.0188 -0.25042,-0.0294 -0.37695,-0.0312 z m 8.67382,0 c -0.12653,0.002 -0.25299,0.0124 -0.37695,0.0312 -0.49583,0.0754 -0.95911,0.28724 -1.31055,0.63867 l -0.5,0.5 c -0.49023,0.47127 0.23577,1.19727 0.70704,0.70704 l 0.5,-0.5 c 0.29713,-0.29714 1.17505,-0.46545 1.71875,-0.24024 C 480.63411,495.346 481,495.89187 481,496.5 v 3.5 h 1 v -3.5 c 0,-1.00971 -0.61206,-1.92414 -1.54492,-2.31055 -0.35663,-0.1477 -0.74149,-0.21856 -1.1211,-0.21289 z M 468.49414,501 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1 3.00586 a 0.50005,0.50005 0 0 0 0.41602,-0.22266 L 474.76758,505 h 0.46484 l 1.85156,2.77734 A 0.50005,0.50005 0 0 0 477.5,508 h 2.99414 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -6 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z M 474,502 v 2.34766 L 472.23242,507 h -2.23828 -1 L 469,502.00195 Z m 1.99414,0 5,0.002 V 507 h -0.5 H 480 477.76758 L 476,504.34766 Z"
+ style="fill:#ffffff;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path8043-2"
+ d="m 470.49414,503 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 H 471.5 c 0.16717,-10e-6 0.32328,-0.0836 0.41602,-0.22266 l 1,-1.5 c 0.0559,-0.0838 0.0852,-0.18249 0.084,-0.2832 l -0.006,-0.5 c -0.003,-0.27384 -0.22614,-0.49413 -0.5,-0.49414 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <path
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="m 115,32 v 2 h 6 v -2 z m 6,2 v 2 h 2 v -2 z m 2,2 v 6 h 2 v -6 z m 0,6 h -2 v 2 h 2 z m -2,2 h -6 v 2 h 6 z m -6,0 v -2 h -2 v 2 z m -2,-2 v -6 h -2 v 6 z m 0,-6 h 2 v -2 h -2 z"
+ id="rect23113-8"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ transform="translate(-420.00718,439.99283)"
+ id="g7406-1-2"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 27.492188,598.99219 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.49805 L 41,605 l -1,-0.002 -0.0059,2.99414 H 27.992188 v -8 h 8 v 3.5 c 2.9e-5,0.27613 0.223869,0.49997 0.5,0.5 h 4 c 0.44533,-1.7e-4 0.668305,-0.53852 0.353515,-0.85352 l -4,-4 c -0.09376,-0.0938 -0.22116,-0.14439 -0.353515,-0.14453 v -0.002 h -0.0078 z M 35,610 l -2,0.004 v 1.98828 h -2.507812 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 7 c 0.676159,0.01 0.676159,-1.00956 0,-1 H 35 Z"
+ transform="translate(420.00718,-439.99283)"
+ id="path7395-0-0"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 53.494141,601.99414 a 0.50005,0.50005 0 0 0 -0.347657,0.85938 l 3.646485,3.64648 -3.646485,3.64648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 4,-4 a 0.50005,0.50005 0 0 0 0,-0.70704 l -4,-4 a 0.50005,0.50005 0 0 0 -0.359375,-0.15234 z"
+ id="path9518-7-7"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g6733"
+ transform="translate(-42.000002,503.9)"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <rect
+ ry="0"
+ rx="0"
+ y="31"
+ x="68"
+ height="16"
+ width="16"
+ id="rect4338"
+ style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 81.75,32.099609 c -1.433114,0 -2.573994,0.599965 -3.328125,1.414063 -0.754131,0.814098 -1.193245,1.779187 -1.615234,2.65039 -0.42199,0.871204 -0.825206,1.64712 -1.308594,2.146485 -0.483388,0.499365 -0.99066,0.789062 -1.998047,0.789062 H 69 v 2 h 4.5 c 1.476988,0 2.648427,-0.585302 3.435547,-1.398437 0.78712,-0.813135 1.246208,-1.787219 1.671875,-2.666016 0.425667,-0.878796 0.819561,-1.663707 1.28125,-2.162109 0.461689,-0.498402 0.919442,-0.773438 1.861328,-0.773438 H 83 v -2 z"
+ id="path4336"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g23052"
+ style="opacity:0.7;fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 27,536.90039 v 1.19922 h 0.75 c 0.646429,0 1.301953,0.38 1.880859,1.04297 0.578907,0.66296 1.046871,1.58637 1.289063,2.49023 0.207018,0.77346 1.367174,0.46292 1.160156,-0.31054 -0.287808,-1.07411 -0.818828,-2.13723 -1.544922,-2.96875 -0.726093,-0.83153 -1.681585,-1.45313 -2.785156,-1.45313 z m 13.25,9 c -1.91571,0 -2.93215,0.90502 -3.558594,1.66992 -0.313222,0.38245 -0.555819,0.7142 -0.798828,0.91797 -0.243008,0.20377 -0.458964,0.3125 -0.892578,0.3125 -0.401011,0 -0.71548,-0.20341 -1.054688,-0.64648 -0.339207,-0.44308 -0.639641,-1.1033 -0.878906,-1.79492 -0.238226,-0.80225 -1.442094,-0.38505 -1.132812,0.39257 0.260735,0.7537 0.585301,1.5146 1.058594,2.13282 C 33.46548,549.50298 34.151011,550 35,550 c 0.691386,0 1.25668,-0.25378 1.662109,-0.59375 0.405429,-0.33997 0.678457,-0.73364 0.958985,-1.07617 0.561056,-0.68506 1.044616,-1.23047 2.628906,-1.23047 H 41 v -1.19922 z"
+ transform="translate(42.000002,-503.9)"
+ id="path4334"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g7579" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 48.499998,536.00001 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 2 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 4 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -2 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z m 7,6 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 2 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0,5 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 2 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="rect5843" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccccccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 50,540 v 8.5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 54 v -1 h -3 v -4 h 3 v -1 h -3 v -3 z" id="path5849" inkscape:connector-curvature="0"/>
- </g>
- <g id="g7627" style="fill:#ffffff">
- <g transform="matrix(1,0,0,-1,-42.000002,917.99993)" id="g4806" style="opacity:0.6;fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 300.5,375 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5.5 v -1 h -5 v -2 h 5 v -1 z m 8.5,0 v 1 h 2 v 2 h -2 v 1 h 2.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z" id="path4801" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 302.5,378 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3.5 v -1 h -3 v -2 h 3 v -1 z m 6.5,0 v 1 h 4 v 2 h -4 v 1 h 4.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z" id="path4804" inkscape:connector-curvature="0"/>
+ <g
+ id="g7579"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 48.499998,536.00001 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 2 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 4 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -2 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z m 7,6 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 2 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0,5 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 2 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="rect5843"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 50,540 v 8.5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 54 v -1 h -3 v -4 h 3 v -1 h -3 v -3 z"
+ id="path5849"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g7627"
+ style="fill:#ffffff">
+ <g
+ transform="matrix(1,0,0,-1,-42.000002,917.99993)"
+ id="g4806"
+ style="opacity:0.6;fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 300.5,375 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5.5 v -1 h -5 v -2 h 5 v -1 z m 8.5,0 v 1 h 2 v 2 h -2 v 1 h 2.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path4801"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 302.5,378 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3.5 v -1 h -3 v -2 h 3 v -1 z m 6.5,0 v 1 h 4 v 2 h -4 v 1 h 4.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path4804"
+ inkscape:connector-curvature="0" />
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 265,536 v 13.96484 h 1 V 536 Z m -4.5,10 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3.5 v -4 z m 6.5,0 v 4 h 4.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path4817" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 218.5,74 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 13 c 1.7e-4,0.445324 0.53852,0.668302 0.85352,0.353516 l 3.64648,-3.646485 3.64648,3.646485 c 0.315,0.314786 0.85335,0.09181 0.85352,-0.353516 v -13 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z" id="rect9857" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 326.49023,56 a 0.50005,0.50005 0 0 0 -0.34375,0.152344 l -4,4 a 0.50005,0.50005 0 0 0 0,0.707031 l 4,4 a 0.50005,0.50005 0 1 0 0.70704,-0.707031 l -3.14649,-3.146485 H 334.5 a 0.50005,0.50005 0 1 0 0,-1 h -10.79297 l 3.14649,-3.146484 A 0.50005,0.50005 0 0 0 326.49023,56 Z" id="path12420" inkscape:connector-curvature="0"/>
- <g id="g12536" transform="matrix(0,1,1,0,270,-183)" style="display:inline;opacity:1;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 261.49023,51.996094 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -4,4 a 0.50005,0.50005 0 0 0 0,0.707032 l 4,4 a 0.50005,0.50005 0 1 0 0.70704,-0.707032 L 258.70703,57 H 268.5 c 0.83435,0 1.5,0.665651 1.5,1.5 v 5 a 0.50005,0.50005 0 1 0 1,0 v -5 c 0,-1.374789 -1.12521,-2.5 -2.5,-2.5 h -9.79297 l 3.14649,-3.146484 a 0.50005,0.50005 0 0 0 -0.36329,-0.857422 z" id="path12534" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 350.50195,56 a 0.50005,0.50005 0 0 0 -0.34765,0.859375 l 3.14648,3.146484 h -10.79297 a 0.50005,0.50005 0 1 0 0,1 h 10.79297 l -3.14648,3.146485 a 0.50005,0.50005 0 1 0 0.70703,0.707031 l 4,-4 a 0.50005,0.50005 0 0 0 0,-0.707031 l -4,-4 A 0.50005,0.50005 0 0 0 350.50195,56 Z" id="path9970" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 283.49023,52.996094 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -4,4 a 0.50005,0.50005 0 0 0 0,0.707032 l 4,4 a 0.50005,0.50005 0 1 0 0.70704,-0.707032 L 280.70703,58 H 288 c 2.21506,0 4,1.784939 4,4 0,2.215061 -1.78494,4 -4,4 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 c 2.7555,0 5,-2.244499 5,-5 0,-2.755501 -2.2445,-5 -5,-5 h -7.29297 l 3.14649,-3.146484 a 0.50005,0.50005 0 0 0 -0.36329,-0.857422 z" id="path13225" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 309.49414,52.994141 a 0.50005,0.50005 0 0 0 -0.34766,0.859375 L 312.29297,57 H 305 c -2.7555,0 -5,2.244499 -5,5 0,2.755501 2.2445,5 5,5 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 305 c -2.21506,0 -4,-1.784939 -4,-4 0,-2.215061 1.78494,-4 4,-4 h 7.29297 l -3.14649,3.146484 a 0.50005,0.50005 0 1 0 0.70704,0.707032 l 4,-4 a 0.50005,0.50005 0 0 0 0,-0.707032 l -4,-4 a 0.50005,0.50005 0 0 0 -0.35938,-0.152343 z" id="path13229" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 355.49219,73.992188 A 0.50004994,0.50004994 0 0 0 355,74.5 v 3.792969 l -2.11914,-2.117188 a 0.50004994,0.50004994 0 0 0 -0.0234,-0.02539 c -10e-4,-0.0015 -0.002,-0.0024 -0.004,-0.0039 a 0.50004994,0.50004994 0 0 0 -0.1875,-0.121093 c -1.78999,-1.727877 -3.76997,-2.331734 -5.85938,-1.875 -2.1873,0.478135 -3.98484,2.053048 -4.77539,4.175781 a 0.50004994,0.50004994 0 1 0 0.9375,0.347656 c 0.67415,-1.810183 2.19925,-3.142137 4.05078,-3.546875 1.87803,-0.410528 3.46011,0.02939 5.12305,1.722656 a 0.50004994,0.50004994 0 0 0 0.002,0.002 0.50004994,0.50004994 0 0 0 0.002,0.002 0.50004994,0.50004994 0 0 0 0.0332,0.03125 L 354.29297,79 H 350.5 a 0.50004994,0.50004994 0 1 0 0,1 h 5 a 0.50004994,0.50004994 0 0 0 0.5,-0.5 v -5 a 0.50004994,0.50004994 0 0 0 -0.50781,-0.507812 z" id="path13235" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 342.49805,81.992188 a 0.50004994,0.50004994 0 0 0 -0.5,0.5 v 5 a 0.50004994,0.50004994 0 1 0 1,0 v -3.792969 l 2.11914,2.11914 a 0.50004994,0.50004994 0 0 0 0.0234,0.02539 l 0.004,0.002 c 7.2e-4,7.3e-4 0.001,0.0012 0.002,0.002 a 0.50004994,0.50004994 0 0 0 0.18555,0.121094 c 1.78998,1.727877 3.76997,2.331734 5.85938,1.875 2.1873,-0.478136 3.98484,-2.053048 4.77539,-4.175781 a 0.50028327,0.50028327 0 1 0 -0.9375,-0.34961 c -0.67415,1.810184 -2.19925,3.14409 -4.05078,3.548829 -1.87804,0.410528 -3.46011,-0.03135 -5.12305,-1.72461 a 0.50004994,0.50004994 0 0 0 -0.004,-0.0039 l -0.0332,-0.03125 -2.11328,-2.115234 h 3.79297 a 0.50004994,0.50004994 0 1 0 0,-1 z" id="path13252" inkscape:connector-curvature="0"/>
- <g id="g12053" transform="translate(0.99999815,210)" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 237.49414,326.05078 c -0.11724,0.001 -0.22936,0.0482 -0.3125,0.13086 l -2,2 c -0.17593,0.17578 -0.17593,0.46094 0,0.63672 l 2,2 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 2,-2 c 0.17593,-0.17578 0.17593,-0.46094 0,-0.63672 l -2,-2 c -0.086,-0.0855 -0.20293,-0.13272 -0.32422,-0.13086 z m 11,0 c -0.11724,0.001 -0.22936,0.0482 -0.3125,0.13086 l -2,2 c -0.17593,0.17578 -0.17593,0.46094 0,0.63672 l 2,2 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 2,-2 c 0.17593,-0.17578 0.17593,-0.46094 0,-0.63672 l -2,-2 c -0.086,-0.0855 -0.20293,-0.13272 -0.32422,-0.13086 z m -6.02734,6.75 c -0.1137,0.009 -0.21981,0.0605 -0.29688,0.14453 l -3,3.25 c -0.16377,0.17723 -0.15861,0.45209 0.0117,0.62305 l 3,3 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 3,-3 c 0.17031,-0.17096 0.17547,-0.44582 0.0117,-0.62305 l -3,-3.25 c -0.0927,-0.10101 -0.22649,-0.15422 -0.36328,-0.14453 z m 0.0332,1.11133 2.37695,2.57617 -2.37695,2.375 -2.37695,-2.37695 z" id="path12048" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc"/>
- <path style="opacity:0.5;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" d="m 239.12109,326 1.43946,1.43945 c 0.58556,0.5858 0.58556,1.5353 0,2.1211 L 239.12109,331 h 7.75782 l -1.43946,-1.43945 c -0.58556,-0.5858 -0.58556,-1.5353 0,-2.1211 L 246.87891,326 Z" id="path12051" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g23466" transform="translate(-1.8536743e-6,-0.999995)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 10.482422,494 c -0.189602,0.007 -0.359053,0.12023 -0.4375,0.29297 l -3.7734376,8.25 c -0.00134,0.003 -0.00264,0.007 -0.00391,0.01 C 6.1587525,502.80633 6,503.10119 6,503.5 c 0,0.83813 0.5261723,1.53471 1.296875,1.92188 0.7707027,0.38715 1.7901254,0.55582 3.023437,0.57226 0.295371,0.003 0.52928,-0.24867 0.503907,-0.54297 9.47e-4,0.0108 -0.01109,-0.37852 -0.01563,-0.70898 -0.0045,-0.33047 -0.0078,-0.6698 -0.0078,-0.74219 0,-1.86768 1.015625,-3.51914 2.519531,-4.4375 0.228366,-0.13928 0.306682,-0.43361 0.177735,-0.66797 L 10.9375,494.25781 C 10.846425,494.09307 10.670549,493.99343 10.482422,494 Z M 18,494 c -1.098638,0 -1.999999,0.90136 -2,2 1e-6,1.09864 0.901362,2 2,2 1.098638,0 1.999999,-0.90136 2,-2 -1e-6,-1.09864 -0.901362,-2 -2,-2 z m -2,6 c -2.203217,0 -3.999999,1.79678 -4,4 10e-7,2.20322 1.796783,4 4,4 2.203217,0 3.999999,-1.79678 4,-4 -1e-6,-2.20322 -1.796783,-4 -4,-4 z m 0,1 c 1.662777,0 2.999999,1.33722 3,3 -1e-6,1.66278 -1.337223,3 -3,3 -1.662777,0 -2.999999,-1.33722 -3,-3 10e-7,-1.66278 1.337223,-3 3,-3 z m -0.541016,1.0332 C 14.658737,502.0332 14,502.69389 14,503.49414 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.25981 0.199172,-0.46094 0.458984,-0.46094 a 0.50005,0.50005 0 1 0 0,-1 z" transform="translate(1.8536743e-6,0.999995)" id="path10645" inkscape:connector-curvature="0"/>
- </g>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.70000005;marker:none;enable-background:accumulate" id="rect12082" width="16" height="16" x="26" y="136" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96"/>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g14497">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 324.60938,536 C 323.75288,536 323,536.6483 323,537.5 v 3 c 0,0.8517 0.75288,1.5 1.60938,1.5 h 4.78124 C 330.24712,542 331,541.3517 331,540.5 v -3 c 0,-0.8517 -0.75287,-1.5 -1.60938,-1.5 z M 332,537 v 3 c 0.56267,0 1,-0.50398 1,-1.03125 v -0.9375 C 333,537.50408 332.56269,537 332,537 Z m -7.53516,3 a 0.50005,0.50005 0 0 1 0.0352,0 h 5 a 0.50005,0.50005 0 1 1 0,1 h -5 a 0.50030966,0.50030966 0 0 1 -0.0352,-1 z m -1.85546,4 C 321.75288,544 321,544.6483 321,545.5 v 3 c 0,0.8517 0.75288,1.5 1.60938,1.5 h 4.78124 C 328.24712,550 329,549.3517 329,548.5 v -3 c 0,-0.8517 -0.75287,-1.5 -1.60938,-1.5 z M 330,546 v 3 c 0.56267,0 1,-0.50398 1,-1.03125 v -0.9375 C 331,546.50408 330.56269,546 330,546 Z m -7.53516,2 a 0.50005,0.50005 0 0 1 0.0352,0 h 5 a 0.50005,0.50005 0 1 1 0,1 h -5 a 0.50030966,0.50030966 0 0 1 -0.0352,-1 z" transform="translate(1.8536743e-6,-4.4999696e-6)" id="rect12085" inkscape:connector-curvature="0"/>
- <g transform="translate(0,231)" style="opacity:1;fill:#ffffff" id="g12112">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 332.5,307 v 1 c 0.55917,0 0.9084,0.14278 1.13281,0.36719 C 333.85722,308.5916 334,308.94083 334,309.5 v 5 c 0,0.55917 -0.14278,0.9084 -0.36719,1.13281 C 333.4084,315.85722 333.05917,316 332.5,316 h -2 v 1 h 2 c 0.73927,0 1.38886,-0.20918 1.83984,-0.66016 C 334.79082,315.88886 335,315.23927 335,314.5 v -5 c 0,-0.73927 -0.20918,-1.38886 -0.66016,-1.83984 C 333.88886,307.20918 333.23927,307 332.5,307 Z" id="path12102" inkscape:connector-curvature="0" sodipodi:nodetypes="ccsssssccsssssc"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 265,536 v 13.96484 h 1 V 536 Z m -4.5,10 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3.5 v -4 z m 6.5,0 v 4 h 4.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path4817"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 218.5,74 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 13 c 1.7e-4,0.445324 0.53852,0.668302 0.85352,0.353516 l 3.64648,-3.646485 3.64648,3.646485 c 0.315,0.314786 0.85335,0.09181 0.85352,-0.353516 v -13 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z"
+ id="rect9857"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 326.49023,56 a 0.50005,0.50005 0 0 0 -0.34375,0.152344 l -4,4 a 0.50005,0.50005 0 0 0 0,0.707031 l 4,4 a 0.50005,0.50005 0 1 0 0.70704,-0.707031 l -3.14649,-3.146485 H 334.5 a 0.50005,0.50005 0 1 0 0,-1 h -10.79297 l 3.14649,-3.146484 A 0.50005,0.50005 0 0 0 326.49023,56 Z"
+ id="path12420"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g12536"
+ transform="matrix(0,1,1,0,270,-183)"
+ style="display:inline;opacity:1;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 261.49023,51.996094 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -4,4 a 0.50005,0.50005 0 0 0 0,0.707032 l 4,4 a 0.50005,0.50005 0 1 0 0.70704,-0.707032 L 258.70703,57 H 268.5 c 0.83435,0 1.5,0.665651 1.5,1.5 v 5 a 0.50005,0.50005 0 1 0 1,0 v -5 c 0,-1.374789 -1.12521,-2.5 -2.5,-2.5 h -9.79297 l 3.14649,-3.146484 a 0.50005,0.50005 0 0 0 -0.36329,-0.857422 z"
+ id="path12534"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 350.50195,56 a 0.50005,0.50005 0 0 0 -0.34765,0.859375 l 3.14648,3.146484 h -10.79297 a 0.50005,0.50005 0 1 0 0,1 h 10.79297 l -3.14648,3.146485 a 0.50005,0.50005 0 1 0 0.70703,0.707031 l 4,-4 a 0.50005,0.50005 0 0 0 0,-0.707031 l -4,-4 A 0.50005,0.50005 0 0 0 350.50195,56 Z"
+ id="path9970"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 283.49023,52.996094 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -4,4 a 0.50005,0.50005 0 0 0 0,0.707032 l 4,4 a 0.50005,0.50005 0 1 0 0.70704,-0.707032 L 280.70703,58 H 288 c 2.21506,0 4,1.784939 4,4 0,2.215061 -1.78494,4 -4,4 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 c 2.7555,0 5,-2.244499 5,-5 0,-2.755501 -2.2445,-5 -5,-5 h -7.29297 l 3.14649,-3.146484 a 0.50005,0.50005 0 0 0 -0.36329,-0.857422 z"
+ id="path13225"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 309.49414,52.994141 a 0.50005,0.50005 0 0 0 -0.34766,0.859375 L 312.29297,57 H 305 c -2.7555,0 -5,2.244499 -5,5 0,2.755501 2.2445,5 5,5 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 305 c -2.21506,0 -4,-1.784939 -4,-4 0,-2.215061 1.78494,-4 4,-4 h 7.29297 l -3.14649,3.146484 a 0.50005,0.50005 0 1 0 0.70704,0.707032 l 4,-4 a 0.50005,0.50005 0 0 0 0,-0.707032 l -4,-4 a 0.50005,0.50005 0 0 0 -0.35938,-0.152343 z"
+ id="path13229"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 355.49219,73.992188 A 0.50004994,0.50004994 0 0 0 355,74.5 v 3.792969 l -2.11914,-2.117188 a 0.50004994,0.50004994 0 0 0 -0.0234,-0.02539 c -10e-4,-0.0015 -0.002,-0.0024 -0.004,-0.0039 a 0.50004994,0.50004994 0 0 0 -0.1875,-0.121093 c -1.78999,-1.727877 -3.76997,-2.331734 -5.85938,-1.875 -2.1873,0.478135 -3.98484,2.053048 -4.77539,4.175781 a 0.50004994,0.50004994 0 1 0 0.9375,0.347656 c 0.67415,-1.810183 2.19925,-3.142137 4.05078,-3.546875 1.87803,-0.410528 3.46011,0.02939 5.12305,1.722656 a 0.50004994,0.50004994 0 0 0 0.002,0.002 0.50004994,0.50004994 0 0 0 0.002,0.002 0.50004994,0.50004994 0 0 0 0.0332,0.03125 L 354.29297,79 H 350.5 a 0.50004994,0.50004994 0 1 0 0,1 h 5 a 0.50004994,0.50004994 0 0 0 0.5,-0.5 v -5 a 0.50004994,0.50004994 0 0 0 -0.50781,-0.507812 z"
+ id="path13235"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 342.49805,81.992188 a 0.50004994,0.50004994 0 0 0 -0.5,0.5 v 5 a 0.50004994,0.50004994 0 1 0 1,0 v -3.792969 l 2.11914,2.11914 a 0.50004994,0.50004994 0 0 0 0.0234,0.02539 l 0.004,0.002 c 7.2e-4,7.3e-4 0.001,0.0012 0.002,0.002 a 0.50004994,0.50004994 0 0 0 0.18555,0.121094 c 1.78998,1.727877 3.76997,2.331734 5.85938,1.875 2.1873,-0.478136 3.98484,-2.053048 4.77539,-4.175781 a 0.50028327,0.50028327 0 1 0 -0.9375,-0.34961 c -0.67415,1.810184 -2.19925,3.14409 -4.05078,3.548829 -1.87804,0.410528 -3.46011,-0.03135 -5.12305,-1.72461 a 0.50004994,0.50004994 0 0 0 -0.004,-0.0039 l -0.0332,-0.03125 -2.11328,-2.115234 h 3.79297 a 0.50004994,0.50004994 0 1 0 0,-1 z"
+ id="path13252"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g12053"
+ transform="translate(0.99999815,210)"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 237.49414,326.05078 c -0.11724,0.001 -0.22936,0.0482 -0.3125,0.13086 l -2,2 c -0.17593,0.17578 -0.17593,0.46094 0,0.63672 l 2,2 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 2,-2 c 0.17593,-0.17578 0.17593,-0.46094 0,-0.63672 l -2,-2 c -0.086,-0.0855 -0.20293,-0.13272 -0.32422,-0.13086 z m 11,0 c -0.11724,0.001 -0.22936,0.0482 -0.3125,0.13086 l -2,2 c -0.17593,0.17578 -0.17593,0.46094 0,0.63672 l 2,2 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 2,-2 c 0.17593,-0.17578 0.17593,-0.46094 0,-0.63672 l -2,-2 c -0.086,-0.0855 -0.20293,-0.13272 -0.32422,-0.13086 z m -6.02734,6.75 c -0.1137,0.009 -0.21981,0.0605 -0.29688,0.14453 l -3,3.25 c -0.16377,0.17723 -0.15861,0.45209 0.0117,0.62305 l 3,3 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 3,-3 c 0.17031,-0.17096 0.17547,-0.44582 0.0117,-0.62305 l -3,-3.25 c -0.0927,-0.10101 -0.22649,-0.15422 -0.36328,-0.14453 z m 0.0332,1.11133 2.37695,2.57617 -2.37695,2.375 -2.37695,-2.37695 z"
+ id="path12048"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc" />
+ <path
+ style="opacity:0.5;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="m 239.12109,326 1.43946,1.43945 c 0.58556,0.5858 0.58556,1.5353 0,2.1211 L 239.12109,331 h 7.75782 l -1.43946,-1.43945 c -0.58556,-0.5858 -0.58556,-1.5353 0,-2.1211 L 246.87891,326 Z"
+ id="path12051"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g23466"
+ transform="translate(-1.8536743e-6,-0.999995)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 10.482422,494 c -0.189602,0.007 -0.359053,0.12023 -0.4375,0.29297 l -3.7734376,8.25 c -0.00134,0.003 -0.00264,0.007 -0.00391,0.01 C 6.1587525,502.80633 6,503.10119 6,503.5 c 0,0.83813 0.5261723,1.53471 1.296875,1.92188 0.7707027,0.38715 1.7901254,0.55582 3.023437,0.57226 0.295371,0.003 0.52928,-0.24867 0.503907,-0.54297 9.47e-4,0.0108 -0.01109,-0.37852 -0.01563,-0.70898 -0.0045,-0.33047 -0.0078,-0.6698 -0.0078,-0.74219 0,-1.86768 1.015625,-3.51914 2.519531,-4.4375 0.228366,-0.13928 0.306682,-0.43361 0.177735,-0.66797 L 10.9375,494.25781 C 10.846425,494.09307 10.670549,493.99343 10.482422,494 Z M 18,494 c -1.098638,0 -1.999999,0.90136 -2,2 1e-6,1.09864 0.901362,2 2,2 1.098638,0 1.999999,-0.90136 2,-2 -1e-6,-1.09864 -0.901362,-2 -2,-2 z m -2,6 c -2.203217,0 -3.999999,1.79678 -4,4 10e-7,2.20322 1.796783,4 4,4 2.203217,0 3.999999,-1.79678 4,-4 -1e-6,-2.20322 -1.796783,-4 -4,-4 z m 0,1 c 1.662777,0 2.999999,1.33722 3,3 -1e-6,1.66278 -1.337223,3 -3,3 -1.662777,0 -2.999999,-1.33722 -3,-3 10e-7,-1.66278 1.337223,-3 3,-3 z m -0.541016,1.0332 C 14.658737,502.0332 14,502.69389 14,503.49414 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.25981 0.199172,-0.46094 0.458984,-0.46094 a 0.50005,0.50005 0 1 0 0,-1 z"
+ transform="translate(1.8536743e-6,0.999995)"
+ id="path10645"
+ inkscape:connector-curvature="0" />
+ </g>
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.70000005;marker:none;enable-background:accumulate"
+ id="rect12082"
+ width="16"
+ height="16"
+ x="26"
+ y="136"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14497">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 324.60938,536 C 323.75288,536 323,536.6483 323,537.5 v 3 c 0,0.8517 0.75288,1.5 1.60938,1.5 h 4.78124 C 330.24712,542 331,541.3517 331,540.5 v -3 c 0,-0.8517 -0.75287,-1.5 -1.60938,-1.5 z M 332,537 v 3 c 0.56267,0 1,-0.50398 1,-1.03125 v -0.9375 C 333,537.50408 332.56269,537 332,537 Z m -7.53516,3 a 0.50005,0.50005 0 0 1 0.0352,0 h 5 a 0.50005,0.50005 0 1 1 0,1 h -5 a 0.50030966,0.50030966 0 0 1 -0.0352,-1 z m -1.85546,4 C 321.75288,544 321,544.6483 321,545.5 v 3 c 0,0.8517 0.75288,1.5 1.60938,1.5 h 4.78124 C 328.24712,550 329,549.3517 329,548.5 v -3 c 0,-0.8517 -0.75287,-1.5 -1.60938,-1.5 z M 330,546 v 3 c 0.56267,0 1,-0.50398 1,-1.03125 v -0.9375 C 331,546.50408 330.56269,546 330,546 Z m -7.53516,2 a 0.50005,0.50005 0 0 1 0.0352,0 h 5 a 0.50005,0.50005 0 1 1 0,1 h -5 a 0.50030966,0.50030966 0 0 1 -0.0352,-1 z"
+ transform="translate(1.8536743e-6,-4.4999696e-6)"
+ id="rect12085"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="translate(0,231)"
+ style="opacity:1;fill:#ffffff"
+ id="g12112">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 332.5,307 v 1 c 0.55917,0 0.9084,0.14278 1.13281,0.36719 C 333.85722,308.5916 334,308.94083 334,309.5 v 5 c 0,0.55917 -0.14278,0.9084 -0.36719,1.13281 C 333.4084,315.85722 333.05917,316 332.5,316 h -2 v 1 h 2 c 0.73927,0 1.38886,-0.20918 1.83984,-0.66016 C 334.79082,315.88886 335,315.23927 335,314.5 v -5 c 0,-0.73927 -0.20918,-1.38886 -0.66016,-1.83984 C 333.88886,307.20918 333.23927,307 332.5,307 Z"
+ id="path12102"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccsssssccsssssc" />
</g>
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 218.5,472 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z m -2,2 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 12 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 217 v -1 h 2.50781 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 477 H 229 v 2.5 c 0,0.525 -0.14815,0.87861 -0.38477,1.11523 C 228.37862,480.85186 228.02499,481 227.5,481 h -1 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2.5 h -4.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 482 h 0.5 c 0.72501,0 1.37138,-0.22683 1.82227,-0.67773 C 229.77315,480.87137 230,480.225 230,479.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 224 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 6 v 1 h -6 z m 4,3 v 1 h 1 v -1 z m 2,0 v 1 h 1 v -1 z m 2,0 v 1 h 1 v -1 z m 2,0 v 1 h 1 v -1 z" id="path12120" inkscape:connector-curvature="0"/>
- <g id="g12136" transform="translate(21.999998,314.99995)" style="fill:#ffffff"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g12254" transform="translate(-21.000002,-20.999995)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" d="m 75,599 v 2 h 1 v -2 z m 3,0 v 1 h 2 v -1 z m 4,0 v 2 h 1 v -2 z m -6,3 c -2.197587,0 -4,1.80241 -4,4 0,0.91965 0.327327,1.75942 0.855469,2.4375 l -3.708985,3.70898 a 0.50005001,0.50005001 0 1 0 0.707032,0.70704 L 73.5625,609.14453 C 74.240452,609.67231 75.080704,610 76,610 c 2.197595,0 3.998047,-1.80241 3.998047,-4 0,-2.19759 -1.800452,-4 -3.998047,-4 z m 6,1 v 2 h 1 v -2 z m -6,0.002 c 1.652136,0 3,1.34592 3,2.99805 0,1.65213 -1.347864,3 -3,3 -1.652128,0 -3,-1.34787 -3,-3 0,-1.65214 1.347872,-2.99805 3,-2.99805 z M 82,607 v 2 h 1 v -2 z m -7,4 v 2 h 1 v -2 z m 7,0 v 2 h 1 v -2 z m -4,1 v 1 h 2 v -1 z" transform="translate(21.000002,20.999995)" id="rect12197" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.25;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 96,620 v 3.5 h 1 V 621 h 6 v 12 h -6 v -2.25 H 96 V 634 h 8 v -14 z" id="rect12222" inkscape:connector-curvature="0"/>
- </g>
- <g id="g5759" style="fill:#ffffff">
- <path id="path12148" d="m 161.5,578 c -3.02272,0 -5.5,2.47726 -5.5,5.5 0,1.3328 0.48165,2.55856 1.2793,3.51367 l -4.13282,4.13281 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 4.13281,-4.13282 C 158.94144,588.51835 160.1672,589 161.5,589 c 3.02273,0 5.5,-2.47727 5.5,-5.5 0,-3.02274 -2.47727,-5.5 -5.5,-5.5 z m 0,1 c 2.47727,0 4.5,2.02272 4.5,4.5 0,2.47727 -2.02273,4.5 -4.5,4.5 -2.47726,0 -4.5,-2.02273 -4.5,-4.5 0,-2.47728 2.02274,-4.5 4.5,-4.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path sodipodi:nodetypes="ccccscccccccccccccsccc" inkscape:connector-curvature="0" id="path12161" d="m 159.5,583 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2.2168 c -2.1e-4,0.14132 0.0594,0.27613 0.16406,0.37109 0.61652,0.55704 1.43526,0.91211 2.33594,0.91211 0.90068,0 1.71942,-0.35507 2.33594,-0.91211 0.10467,-0.095 0.16427,-0.22977 0.16406,-0.37109 V 583.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.97266,6.91992 c -0.2654,0.0146 -0.47303,0.2342 -0.47266,0.5 V 591.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1.08008 c -4.1e-4,-0.30465 -0.27082,-0.53814 -0.57227,-0.49414 -0.31225,0.0453 -0.61944,0.0742 -0.92773,0.0742 -0.30829,0 -0.61548,-0.0289 -0.92773,-0.0742 -0.0329,-0.005 -0.0663,-0.007 -0.0996,-0.006 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g12207" transform="translate(20.999998,4.4999696e-6)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:7.17647076;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 223.5,578 c -3.57273,0 -6.5,2.92727 -6.5,6.5 0,1.60752 0.59683,3.08042 1.57422,4.21875 l -2.42774,2.42773 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2.42578,-2.42579 c 1.13822,0.977 2.61355,1.57227 4.2207,1.57227 3.57273,0 6.5,-2.92728 6.5,-6.5 0,-3.57273 -2.92727,-6.5 -6.5,-6.5 z m 0,1 c 3.02727,0 5.5,2.47272 5.5,5.5 0,3.02727 -2.47273,5.5 -5.5,5.5 -3.02727,0 -5.5,-2.47273 -5.5,-5.5 0,-3.02728 2.47273,-5.5 5.5,-5.5 z m -3,5 a 0.50005,0.50005 0 1 0 0,1 h 6 a 0.50005,0.50005 0 1 0 0,-1 z" transform="translate(-20.999998,-4.4999696e-6)" id="path12193" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" transform="translate(61.94871,1.10183)" id="g12200"/>
- <rect y="577.04999" x="193.95" height="16" width="16" id="rect12202" style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g12222" transform="rotate(-180,422.50583,500.99795)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g id="g23057" style="opacity:1;fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 415.99805,494 c -0.46823,5.5e-4 -0.93866,0.108 -1.3711,0.32422 l -6.83789,3.39453 a 0.50005,0.50005 0 0 0 -0.0273,0.0137 c -2.00082,1.15513 -3.06722,3.4434 -2.66602,5.71875 0.40121,2.27536 2.18559,4.05973 4.46094,4.46094 0.56884,0.1003 1.13889,0.11012 1.69141,0.0352 1.65755,-0.22472 3.1599,-1.20077 4.02734,-2.70313 a 0.50005,0.50005 0 0 0 0.0156,-0.0293 l 3.38476,-6.84179 c 0.57659,-1.15316 0.3761,-2.57898 -0.54687,-3.50196 -0.57687,-0.57686 -1.35049,-0.872 -2.13086,-0.87109 z m 0.3125,1.02539 c 0.41467,0.0623 0.80824,0.24966 1.11133,0.55273 0.60613,0.60614 0.74722,1.57588 0.36132,2.34766 a 0.50005,0.50005 0 0 0 -0.002,0.002 l -3.375,6.82032 c -0.9493,1.63933 -2.81295,2.50814 -4.67578,2.17968 -1.86473,-0.3288 -3.32159,-1.78565 -3.65039,-3.65039 -0.3288,-1.86473 0.54196,-3.7311 2.18164,-4.67773 l 6.81055,-3.38086 a 0.50005,0.50005 0 0 0 0.002,0 c 0.38589,-0.19295 0.82165,-0.25567 1.23633,-0.19336 z m -0.29883,0.9707 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m -5.5,3 c -1.92707,0 -3.5,1.57293 -3.5,3.5 0,1.92707 1.57293,3.5 3.5,3.5 1.92707,0 3.5,-1.57293 3.5,-3.5 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 0,1.97461 a 1.4874268,1.5 0 0 1 1.48828,1.5 1.4874268,1.5 0 0 1 -1.48828,1.5 1.4874268,1.5 0 0 1 -1.48828,-1.5 1.4874268,1.5 0 0 1 1.48828,-1.5 z" transform="rotate(180,422.50583,500.99795)" id="circle12201" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 218.5,472 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z m -2,2 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 12 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 217 v -1 h 2.50781 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 477 H 229 v 2.5 c 0,0.525 -0.14815,0.87861 -0.38477,1.11523 C 228.37862,480.85186 228.02499,481 227.5,481 h -1 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2.5 h -4.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 482 h 0.5 c 0.72501,0 1.37138,-0.22683 1.82227,-0.67773 C 229.77315,480.87137 230,480.225 230,479.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 224 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 6 v 1 h -6 z m 4,3 v 1 h 1 v -1 z m 2,0 v 1 h 1 v -1 z m 2,0 v 1 h 1 v -1 z m 2,0 v 1 h 1 v -1 z"
+ id="path12120"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g12136"
+ transform="translate(21.999998,314.99995)"
+ style="fill:#ffffff" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12254"
+ transform="translate(-21.000002,-20.999995)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ d="m 75,599 v 2 h 1 v -2 z m 3,0 v 1 h 2 v -1 z m 4,0 v 2 h 1 v -2 z m -6,3 c -2.197587,0 -4,1.80241 -4,4 0,0.91965 0.327327,1.75942 0.855469,2.4375 l -3.708985,3.70898 a 0.50005001,0.50005001 0 1 0 0.707032,0.70704 L 73.5625,609.14453 C 74.240452,609.67231 75.080704,610 76,610 c 2.197595,0 3.998047,-1.80241 3.998047,-4 0,-2.19759 -1.800452,-4 -3.998047,-4 z m 6,1 v 2 h 1 v -2 z m -6,0.002 c 1.652136,0 3,1.34592 3,2.99805 0,1.65213 -1.347864,3 -3,3 -1.652128,0 -3,-1.34787 -3,-3 0,-1.65214 1.347872,-2.99805 3,-2.99805 z M 82,607 v 2 h 1 v -2 z m -7,4 v 2 h 1 v -2 z m 7,0 v 2 h 1 v -2 z m -4,1 v 1 h 2 v -1 z"
+ transform="translate(21.000002,20.999995)"
+ id="rect12197"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.25;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 96,620 v 3.5 h 1 V 621 h 6 v 12 h -6 v -2.25 H 96 V 634 h 8 v -14 z"
+ id="rect12222"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g5759"
+ style="fill:#ffffff">
+ <path
+ id="path12148"
+ d="m 161.5,578 c -3.02272,0 -5.5,2.47726 -5.5,5.5 0,1.3328 0.48165,2.55856 1.2793,3.51367 l -4.13282,4.13281 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 4.13281,-4.13282 C 158.94144,588.51835 160.1672,589 161.5,589 c 3.02273,0 5.5,-2.47727 5.5,-5.5 0,-3.02274 -2.47727,-5.5 -5.5,-5.5 z m 0,1 c 2.47727,0 4.5,2.02272 4.5,4.5 0,2.47727 -2.02273,4.5 -4.5,4.5 -2.47726,0 -4.5,-2.02273 -4.5,-4.5 0,-2.47728 2.02274,-4.5 4.5,-4.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccccscccccccccccccsccc"
+ inkscape:connector-curvature="0"
+ id="path12161"
+ d="m 159.5,583 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2.2168 c -2.1e-4,0.14132 0.0594,0.27613 0.16406,0.37109 0.61652,0.55704 1.43526,0.91211 2.33594,0.91211 0.90068,0 1.71942,-0.35507 2.33594,-0.91211 0.10467,-0.095 0.16427,-0.22977 0.16406,-0.37109 V 583.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.97266,6.91992 c -0.2654,0.0146 -0.47303,0.2342 -0.47266,0.5 V 591.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1.08008 c -4.1e-4,-0.30465 -0.27082,-0.53814 -0.57227,-0.49414 -0.31225,0.0453 -0.61944,0.0742 -0.92773,0.0742 -0.30829,0 -0.61548,-0.0289 -0.92773,-0.0742 -0.0329,-0.005 -0.0663,-0.007 -0.0996,-0.006 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12207"
+ transform="translate(20.999998,4.4999696e-6)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:7.17647076;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 223.5,578 c -3.57273,0 -6.5,2.92727 -6.5,6.5 0,1.60752 0.59683,3.08042 1.57422,4.21875 l -2.42774,2.42773 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2.42578,-2.42579 c 1.13822,0.977 2.61355,1.57227 4.2207,1.57227 3.57273,0 6.5,-2.92728 6.5,-6.5 0,-3.57273 -2.92727,-6.5 -6.5,-6.5 z m 0,1 c 3.02727,0 5.5,2.47272 5.5,5.5 0,3.02727 -2.47273,5.5 -5.5,5.5 -3.02727,0 -5.5,-2.47273 -5.5,-5.5 0,-3.02728 2.47273,-5.5 5.5,-5.5 z m -3,5 a 0.50005,0.50005 0 1 0 0,1 h 6 a 0.50005,0.50005 0 1 0 0,-1 z"
+ transform="translate(-20.999998,-4.4999696e-6)"
+ id="path12193"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(61.94871,1.10183)"
+ id="g12200" />
+ <rect
+ y="577.04999"
+ x="193.95"
+ height="16"
+ width="16"
+ id="rect12202"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12222"
+ transform="rotate(-180,422.50583,500.99795)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ id="g23057"
+ style="opacity:1;fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 415.99805,494 c -0.46823,5.5e-4 -0.93866,0.108 -1.3711,0.32422 l -6.83789,3.39453 a 0.50005,0.50005 0 0 0 -0.0273,0.0137 c -2.00082,1.15513 -3.06722,3.4434 -2.66602,5.71875 0.40121,2.27536 2.18559,4.05973 4.46094,4.46094 0.56884,0.1003 1.13889,0.11012 1.69141,0.0352 1.65755,-0.22472 3.1599,-1.20077 4.02734,-2.70313 a 0.50005,0.50005 0 0 0 0.0156,-0.0293 l 3.38476,-6.84179 c 0.57659,-1.15316 0.3761,-2.57898 -0.54687,-3.50196 -0.57687,-0.57686 -1.35049,-0.872 -2.13086,-0.87109 z m 0.3125,1.02539 c 0.41467,0.0623 0.80824,0.24966 1.11133,0.55273 0.60613,0.60614 0.74722,1.57588 0.36132,2.34766 a 0.50005,0.50005 0 0 0 -0.002,0.002 l -3.375,6.82032 c -0.9493,1.63933 -2.81295,2.50814 -4.67578,2.17968 -1.86473,-0.3288 -3.32159,-1.78565 -3.65039,-3.65039 -0.3288,-1.86473 0.54196,-3.7311 2.18164,-4.67773 l 6.81055,-3.38086 a 0.50005,0.50005 0 0 0 0.002,0 c 0.38589,-0.19295 0.82165,-0.25567 1.23633,-0.19336 z m -0.29883,0.9707 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m -5.5,3 c -1.92707,0 -3.5,1.57293 -3.5,3.5 0,1.92707 1.57293,3.5 3.5,3.5 1.92707,0 3.5,-1.57293 3.5,-3.5 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 0,1.97461 a 1.4874268,1.5 0 0 1 1.48828,1.5 1.4874268,1.5 0 0 1 -1.48828,1.5 1.4874268,1.5 0 0 1 -1.48828,-1.5 1.4874268,1.5 0 0 1 1.48828,-1.5 z"
+ transform="rotate(180,422.50583,500.99795)"
+ id="circle12201"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g transform="translate(-148,-336)" id="g12234" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g id="g12230" style="opacity:0.7;fill:#ffffff" transform="matrix(1,0,0,-1,0,1004)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 258.5,161 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 8 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 6.5 v -5 h -1 v 4 h -1 v -2 h -1 v 2 h -1 v -4 h -1 v 4 h -1 v -7 h 6 v -1 z m 11.5,0 v 1 h 1 v 7 h -1 v 1 h 1.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -8 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" transform="matrix(1,0,0,-1,148,668)" id="path12225" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccccccccccc"/>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ id="g13413"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 475.5,579 c -0.82252,0 -1.5,0.67748 -1.5,1.5 0,0.82252 0.67748,1.5 1.5,1.5 0.82252,0 1.5,-0.67748 1.5,-1.5 0,-0.82252 -0.67748,-1.5 -1.5,-1.5 z m 0,5 c -0.82252,0 -1.5,0.67748 -1.5,1.5 0,0.82252 0.67748,1.5 1.5,1.5 0.82252,0 1.5,-0.67748 1.5,-1.5 0,-0.82252 -0.67748,-1.5 -1.5,-1.5 z m 0,5 c -0.82252,0 -1.5,0.67748 -1.5,1.5 0,0.82252 0.67748,1.5 1.5,1.5 0.82252,0 1.5,-0.67748 1.5,-1.5 0,-0.82252 -0.67748,-1.5 -1.5,-1.5 z"
+ id="ellipse12367"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssssssssssss" />
+ </g>
+ <g
+ transform="translate(-1.4853674e-5,-83.999995)"
+ id="g8655"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 475,157.99609 c -1.79823,1e-5 -2.78534,0.23261 -3.38867,0.75196 C 471.00799,159.2674 471,160.00249 471,160.49609 v 0.5 h -0.002 c -0.12828,0 -0.91099,4e-5 -1.63867,0.53711 -0.72848,0.53766 -1.35958,1.60963 -1.35938,3.4668 9e-5,0.84676 0.12547,1.43896 0.35352,1.89453 0.22804,0.45557 0.5457,0.7425 0.81445,0.98047 a 0.50086817,0.50086817 0 1 0 0.66406,-0.75 c -0.2639,-0.23368 -0.44506,-0.40021 -0.58398,-0.67773 -0.13888,-0.27753 -0.24792,-0.69815 -0.248,-1.44727 -1.7e-4,-1.64286 0.494,-2.32325 0.95312,-2.66211 0.45913,-0.33885 0.92388,-0.3418 1.04688,-0.3418 h 0.44336 a 0.50005,0.50005 0 0 0 0.0586,0.004 l 3,-0.01 a 0.50005,0.50005 0 0 0 -0.002,-1 h -0.002 -0.002 L 472,160.99414 v -0.49805 c 0,-0.4936 -0.008,-0.75638 0.26367,-0.99023 0.27167,-0.23385 1.03456,-0.50976 2.73633,-0.50977 1.70177,0 2.46467,0.27592 2.73633,0.50977 0.27166,0.23385 0.26367,0.49663 0.26367,0.99023 v 1.99414 c -6e-5,0.47857 -0.26457,0.78886 -0.8457,1.12891 -0.58114,0.34005 -1.43184,0.62116 -2.30664,0.90234 -0.87481,0.28119 -1.77478,0.56315 -2.50586,0.98829 -0.73108,0.42513 -1.34192,1.08253 -1.3418,1.98046 v 2.01368 c 0,0.4936 0.008,1.22869 0.61133,1.74804 0.60334,0.51936 1.59044,0.75196 3.38867,0.75196 1.79823,-1e-5 2.78534,-0.23261 3.38867,-0.75196 C 478.99201,170.7326 479,169.99751 479,169.50391 v -0.5 c 0.127,0 0.91215,5.4e-4 1.64062,-0.53711 0.72848,-0.53766 1.35958,-1.60963 1.35938,-3.4668 -1.6e-4,-1.56962 -0.66959,-2.34844 -1.13672,-2.84375 a 0.5001364,0.5001364 0 1 0 -0.72656,0.6875 c 0.47073,0.49913 0.86314,0.83133 0.86328,2.15625 1.7e-4,1.64286 -0.494,2.32325 -0.95312,2.66211 -0.45913,0.33885 -0.92388,0.3418 -1.04688,0.3418 h -0.44336 A 0.50005,0.50005 0 0 0 478.49805,168 l -3,0.01 a 0.50005,0.50005 0 0 0 0.002,1 h 0.002 0.002 L 478,169.00586 v 0.49805 c 0,0.4936 0.008,0.75638 -0.26367,0.99023 -0.27167,0.23385 -1.03456,0.50976 -2.73633,0.50977 -1.70177,0 -2.46467,-0.27592 -2.73633,-0.50977 C 471.99201,170.26029 472,169.99751 472,169.50391 v -2.01368 c -6e-5,-0.47218 0.26437,-0.77913 0.8457,-1.11718 0.58133,-0.33805 1.43145,-0.61908 2.30664,-0.90039 0.8752,-0.28132 1.77441,-0.56222 2.50586,-0.99024 0.73146,-0.42801 1.34168,-1.09087 1.3418,-1.99219 v -1.99414 c 0,-0.4936 -0.008,-1.22869 -0.61133,-1.74804 -0.60334,-0.51936 -1.59044,-0.75196 -3.38867,-0.75196 z"
+ id="path12249"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g8671"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
+ transform="translate(-1.031325,-21.999745)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.75542808px;marker:none;enable-background:accumulate"
+ d="m 493.5,74 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 9.640625 c -0.56586,-0.207564 -1.28645,-0.181296 -1.98242,0.07227 -1.35506,0.496297 -2.23747,1.698784 -1.9707,2.685547 0.26595,0.987122 1.58042,1.385047 2.93554,0.888671 1.10845,-0.406749 1.93232,-1.304268 2.00977,-2.189453 0.006,-0.03222 0.008,-0.06493 0.008,-0.09766 V 85.474609 76 h 8 v 7.140625 c -0.56586,-0.207559 -1.28645,-0.181291 -1.98242,0.07227 -1.35507,0.496303 -2.23747,1.698788 -1.9707,2.685547 0.26596,0.987109 1.58042,1.385032 2.93554,0.888671 1.10846,-0.406754 1.93232,-1.304272 2.00977,-2.189453 0.006,-0.03222 0.008,-0.06493 0.008,-0.09766 V 84.474609 74.5 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z"
+ transform="translate(1.031325,21.999745)"
+ id="ellipse8665"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccc" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12503"
+ transform="translate(47.999998,90.000005)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 464.5,-16 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1.5 v 12 h -1.5 c -0.67616,-0.00956 -0.67616,1.0095626 0,1 h 5 c 0.67616,0.00956 0.67616,-1.0095626 0,-1 H 468 v -6 h 3 v 0.5 c -0.01,0.6761613 1.00956,0.6761613 1,0 v -0.9199219 c 0.009,-0.053677 0.009,-0.1084325 0,-0.1621093 V -10.5 c 0.01,-0.676161 -1.00956,-0.676161 -1,0 v 0.5 h -3 v -5 h 6 v 1.5 c -0.01,0.676161 1.00956,0.676161 1,0 v -2 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z"
+ id="path12501"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccc" />
+ </g>
+ <g
+ transform="matrix(0.92857149,0,0,0.92857137,106.93015,-501.7093)"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;stroke-width:1.07692313;enable-background:new"
+ id="g8599"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ sodipodi:nodetypes="cccccccccccssccsssss"
+ inkscape:connector-curvature="0"
+ id="path8595"
+ transform="matrix(1.076923,0,0,1.0769231,-739.76878,506.92345)"
+ d="m 992.67578,105.26367 c -0.19597,-0.18575 -0.45872,-0.28437 -0.72851,-0.27344 -0.89539,0.0396 -1.29072,1.14623 -0.62305,1.74415 L 992.69727,108 H 986 c -1.36099,-0.0279 -1.36099,2.02794 0,2 h 3.0918 c -0.003,0.002 -0.005,0.004 -0.008,0.006 l -4.75,4.24805 c -0.99479,0.88933 0.3392,2.38151 1.33399,1.49218 l 2.33984,-2.09375 C 988.08993,116.60772 990.52575,119 993.5,119 c 3.02565,0 5.49805,-2.47428 5.49805,-5.5 0,-1.56564 -0.66395,-2.97983 -1.72241,-3.98356 z M 993.5,110 c 1.94471,0 3.5,1.5551 3.5,3.5 0,1.94489 -1.55529,3.5 -3.5,3.5 -1.94472,0 -3.5,-1.55511 -3.5,-3.5 0,-1.9449 1.55528,-3.5 3.5,-3.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ id="path8597"
+ d="m 331.99999,629.15424 a 1.86519,1.8457757 0 0 1 -1.86519,1.84577 1.86519,1.8457757 0 0 1 -1.86519,-1.84577 1.86519,1.8457757 0 0 1 1.86519,-1.84578 1.86519,1.8457757 0 0 1 1.86519,1.84578 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.15384626;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g12575"
+ transform="matrix(0.8666665,0,0,0.8666665,-253.07368,16.407198)"
+ style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.15384638;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 285.49219,388.99219 c -0.2763,0.004 -0.49651,0.23152 -0.49219,0.50781 v 2.6543 c -0.76567,0.19832 -1.43883,0.61396 -1.95508,1.18359 l -2.1914,-2.19141 c -0.0944,-0.0966 -0.22433,-0.15264 -0.35938,-0.15234 -0.4485,2.4e-4 -0.66889,0.54638 -0.34766,0.85938 l 2.32032,2.32031 C 282.17933,394.72335 282.0013,395.33918 282,396 h -2.5 c -0.66693,0 -0.66693,1 0,1 h 2.64062 c 0.19916,0.76891 0.61811,1.44388 1.19141,1.96094 l -2.18555,2.18554 c -0.4717,0.4717 0.23534,1.17874 0.70704,0.70704 l 2.3164,-2.31641 c 0.54947,0.28561 1.16223,0.46289 1.82227,0.46289 0.003,0 0.005,10e-6 0.008,0 v 2.5 c 0,0.66693 1,0.66693 1,0 v -2.64648 c 0.76569,-0.20169 1.4388,-0.6203 1.95312,-1.19336 l 2.19336,2.19336 c 0.47143,0.50593 1.2141,-0.23683 0.70704,-0.70704 l -2.32422,-2.32421 c 0.28283,-0.54738 0.45703,-1.15786 0.45703,-1.81446 0,-0.003 0,-0.005 0,-0.008 H 292.5 c 0.66693,0 0.66693,-1 0,-1 h -2.66016 c -0.20083,-0.76245 -0.61615,-1.43374 -1.18554,-1.94727 l 2.19922,-2.19921 c 0.32695,-0.31816 0.0927,-0.87325 -0.36329,-0.85938 -0.12999,0.004 -0.25338,0.0589 -0.34375,0.15234 l -2.33007,2.33008 C 287.26914,392.1921 286.6571,392.01496 286,392.01367 V 389.5 c 0.004,-0.28226 -0.22555,-0.51222 -0.50781,-0.50781 z m 0.5,4.02148 c 1.65884,0 2.99414,1.3353 2.99414,2.99414 0,1.65885 -1.3353,2.99219 -2.99414,2.99219 C 284.33334,399 283,397.66666 283,396.00781 c 0,-1.65884 1.33334,-2.99414 2.99219,-2.99414 z"
+ transform="matrix(1.1538464,0,0,1.1538464,292.00815,-18.931386)"
+ id="circle12556"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g6143"
+ style="fill:#ffffff">
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ id="g12901"
+ transform="matrix(-0.79928788,0,0,0.79928788,828.43189,282.2677)"
+ style="display:inline;opacity:0.7;fill:#ffffff;stroke-width:1.25111365;enable-background:new">
+ <path
+ id="path12894"
+ transform="matrix(-1.2511137,0,0,1.2511137,1036.4625,-353.14898)"
+ d="m 535.49805,458.00391 a 0.50004999,0.50004999 0 0 0 -0.50391,0.50781 l 0.002,1.33984 c -0.37236,0.0723 -0.71902,0.21977 -1.02148,0.42774 l -1.12695,-1.12305 a 0.50004999,0.50004999 0 0 0 -0.3418,-0.15039 0.50004999,0.50004999 0 0 0 -0.36328,0.85742 l 1.12695,1.12305 c -0.20781,0.30095 -0.35637,0.64504 -0.42969,1.01562 l -1.3457,0.004 a 0.50033487,0.50033487 0 0 0 0.002,1 l 1.33789,-0.002 c 0.0677,0.37781 0.20888,0.73164 0.41602,1.03906 l -1.10742,1.10937 a 0.50004999,0.50004999 0 1 0 0.70508,0.70508 l 1.10351,-1.10156 c 0.30838,0.21694 0.66219,0.37111 1.04492,0.44531 l -0.002,1.30078 a 0.50033678,0.50033678 0 1 0 1,0.004 l 0.002,-1.30274 c 0.3865,-0.0701 0.74651,-0.21619 1.0586,-0.43164 l 1.08203,1.08594 a 0.50005719,0.50005719 0 1 0 0.70703,-0.70508 l -1.08398,-1.08984 c 0.21441,-0.31231 0.36249,-0.67226 0.43164,-1.05859 h 1.30664 a 0.50098,0.50098 0 1 0 0,-1.00196 h -1.3125 c -0.0748,-0.37855 -0.23067,-0.72769 -0.44532,-1.0332 l 1.10352,-1.10547 a 0.50004999,0.50004999 0 0 0 -0.34961,-0.85937 0.50004999,0.50004999 0 0 0 -0.35742,0.15234 l -1.10938,1.10742 c -0.30548,-0.20557 -0.65624,-0.346 -1.03125,-0.41406 l -0.004,-1.33984 a 0.50004999,0.50004999 0 0 0 -0.49219,-0.50586 0.50004999,0.50004999 0 0 1 -0.002,0 z m -0.002,3.29882 c 0.66274,0 1.20117,0.53844 1.20118,1.20118 0,0.66273 -0.53844,1.19921 -1.20118,1.19921 -0.66273,0 -1.19921,-0.53648 -1.19921,-1.19921 0,-0.66273 0.53648,-1.20117 1.19921,-1.20118 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.25111365;enable-background:new"
+ transform="matrix(-0.79928788,0,0,0.79928788,833.43189,275.2677)"
+ id="g12909">
+ <path
+ id="path12903"
+ transform="matrix(-1.2511137,0,0,1.2511137,1042.718,-344.39118)"
+ d="m 540.49805,451.00391 a 0.50004999,0.50004999 0 0 0 -0.50391,0.50781 l 0.002,1.33984 c -0.37236,0.0723 -0.71902,0.21977 -1.02148,0.42774 l -1.12695,-1.12305 a 0.50004999,0.50004999 0 0 0 -0.3418,-0.15039 0.50004999,0.50004999 0 0 0 -0.36328,0.85742 l 1.12695,1.12305 c -0.20781,0.30095 -0.35637,0.64503 -0.42969,1.01562 l -1.3457,0.004 a 0.50033487,0.50033487 0 0 0 0.002,1 l 1.33789,-0.002 c 0.0677,0.37781 0.20888,0.73164 0.41602,1.03906 l -1.10742,1.10937 a 0.50004999,0.50004999 0 1 0 0.70508,0.70508 l 1.10351,-1.10156 c 0.30838,0.21694 0.66219,0.37111 1.04492,0.44531 l -0.002,1.30078 a 0.50033678,0.50033678 0 1 0 1,0.004 l 0.002,-1.30274 c 0.386,-0.07 0.74484,-0.21858 1.05664,-0.43359 l 1.08399,1.08789 a 0.50005719,0.50005719 0 1 0 0.70703,-0.70508 l -1.08398,-1.08984 c 0.21441,-0.31231 0.36249,-0.67226 0.43164,-1.05859 h 1.30664 a 0.50098,0.50098 0 1 0 0,-1.00196 h -1.3125 c -0.0748,-0.37855 -0.23067,-0.72769 -0.44532,-1.0332 l 1.10352,-1.10547 a 0.50004999,0.50004999 0 0 0 -0.34961,-0.85937 0.50004999,0.50004999 0 0 0 -0.35742,0.15234 l -1.10938,1.10742 c -0.30548,-0.20557 -0.65624,-0.346 -1.03125,-0.41406 l -0.004,-1.33984 a 0.50004999,0.50004999 0 0 0 -0.49219,-0.50586 0.50004999,0.50004999 0 0 1 -0.002,0 z m -0.002,3.29882 c 0.66274,0 1.20117,0.53844 1.20118,1.20118 0,0.66273 -0.53844,1.19921 -1.20118,1.19921 -0.66273,0 -1.19921,-0.53648 -1.19921,-1.19921 0,-0.66273 0.53648,-1.20117 1.19921,-1.20118 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ inkscape:connector-curvature="0" />
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 414.5,494 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 13 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -13 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path12232" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" id="g13413" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96" style="display:inline;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 475.5,579 c -0.82252,0 -1.5,0.67748 -1.5,1.5 0,0.82252 0.67748,1.5 1.5,1.5 0.82252,0 1.5,-0.67748 1.5,-1.5 0,-0.82252 -0.67748,-1.5 -1.5,-1.5 z m 0,5 c -0.82252,0 -1.5,0.67748 -1.5,1.5 0,0.82252 0.67748,1.5 1.5,1.5 0.82252,0 1.5,-0.67748 1.5,-1.5 0,-0.82252 -0.67748,-1.5 -1.5,-1.5 z m 0,5 c -0.82252,0 -1.5,0.67748 -1.5,1.5 0,0.82252 0.67748,1.5 1.5,1.5 0.82252,0 1.5,-0.67748 1.5,-1.5 0,-0.82252 -0.67748,-1.5 -1.5,-1.5 z" id="ellipse12367" inkscape:connector-curvature="0" sodipodi:nodetypes="sssssssssssssss"/>
- </g>
- <g transform="translate(-1.4853674e-5,-83.999995)" id="g8655" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 475,157.99609 c -1.79823,1e-5 -2.78534,0.23261 -3.38867,0.75196 C 471.00799,159.2674 471,160.00249 471,160.49609 v 0.5 h -0.002 c -0.12828,0 -0.91099,4e-5 -1.63867,0.53711 -0.72848,0.53766 -1.35958,1.60963 -1.35938,3.4668 9e-5,0.84676 0.12547,1.43896 0.35352,1.89453 0.22804,0.45557 0.5457,0.7425 0.81445,0.98047 a 0.50086817,0.50086817 0 1 0 0.66406,-0.75 c -0.2639,-0.23368 -0.44506,-0.40021 -0.58398,-0.67773 -0.13888,-0.27753 -0.24792,-0.69815 -0.248,-1.44727 -1.7e-4,-1.64286 0.494,-2.32325 0.95312,-2.66211 0.45913,-0.33885 0.92388,-0.3418 1.04688,-0.3418 h 0.44336 a 0.50005,0.50005 0 0 0 0.0586,0.004 l 3,-0.01 a 0.50005,0.50005 0 0 0 -0.002,-1 h -0.002 -0.002 L 472,160.99414 v -0.49805 c 0,-0.4936 -0.008,-0.75638 0.26367,-0.99023 0.27167,-0.23385 1.03456,-0.50976 2.73633,-0.50977 1.70177,0 2.46467,0.27592 2.73633,0.50977 0.27166,0.23385 0.26367,0.49663 0.26367,0.99023 v 1.99414 c -6e-5,0.47857 -0.26457,0.78886 -0.8457,1.12891 -0.58114,0.34005 -1.43184,0.62116 -2.30664,0.90234 -0.87481,0.28119 -1.77478,0.56315 -2.50586,0.98829 -0.73108,0.42513 -1.34192,1.08253 -1.3418,1.98046 v 2.01368 c 0,0.4936 0.008,1.22869 0.61133,1.74804 0.60334,0.51936 1.59044,0.75196 3.38867,0.75196 1.79823,-1e-5 2.78534,-0.23261 3.38867,-0.75196 C 478.99201,170.7326 479,169.99751 479,169.50391 v -0.5 c 0.127,0 0.91215,5.4e-4 1.64062,-0.53711 0.72848,-0.53766 1.35958,-1.60963 1.35938,-3.4668 -1.6e-4,-1.56962 -0.66959,-2.34844 -1.13672,-2.84375 a 0.5001364,0.5001364 0 1 0 -0.72656,0.6875 c 0.47073,0.49913 0.86314,0.83133 0.86328,2.15625 1.7e-4,1.64286 -0.494,2.32325 -0.95312,2.66211 -0.45913,0.33885 -0.92388,0.3418 -1.04688,0.3418 h -0.44336 A 0.50005,0.50005 0 0 0 478.49805,168 l -3,0.01 a 0.50005,0.50005 0 0 0 0.002,1 h 0.002 0.002 L 478,169.00586 v 0.49805 c 0,0.4936 0.008,0.75638 -0.26367,0.99023 -0.27167,0.23385 -1.03456,0.50976 -2.73633,0.50977 -1.70177,0 -2.46467,-0.27592 -2.73633,-0.50977 C 471.99201,170.26029 472,169.99751 472,169.50391 v -2.01368 c -6e-5,-0.47218 0.26437,-0.77913 0.8457,-1.11718 0.58133,-0.33805 1.43145,-0.61908 2.30664,-0.90039 0.8752,-0.28132 1.77441,-0.56222 2.50586,-0.99024 0.73146,-0.42801 1.34168,-1.09087 1.3418,-1.99219 v -1.99414 c 0,-0.4936 -0.008,-1.22869 -0.61133,-1.74804 -0.60334,-0.51936 -1.59044,-0.75196 -3.38867,-0.75196 z" id="path12249" inkscape:connector-curvature="0"/>
- </g>
- <g id="g8671" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" transform="translate(-1.031325,-21.999745)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.75542808px;marker:none;enable-background:accumulate" d="m 493.5,74 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 9.640625 c -0.56586,-0.207564 -1.28645,-0.181296 -1.98242,0.07227 -1.35506,0.496297 -2.23747,1.698784 -1.9707,2.685547 0.26595,0.987122 1.58042,1.385047 2.93554,0.888671 1.10845,-0.406749 1.93232,-1.304268 2.00977,-2.189453 0.006,-0.03222 0.008,-0.06493 0.008,-0.09766 V 85.474609 76 h 8 v 7.140625 c -0.56586,-0.207559 -1.28645,-0.181291 -1.98242,0.07227 -1.35507,0.496303 -2.23747,1.698788 -1.9707,2.685547 0.26596,0.987109 1.58042,1.385032 2.93554,0.888671 1.10846,-0.406754 1.93232,-1.304272 2.00977,-2.189453 0.006,-0.03222 0.008,-0.06493 0.008,-0.09766 V 84.474609 74.5 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z" transform="translate(1.031325,21.999745)" id="ellipse8665" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccccccccc"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g12503" transform="translate(47.999998,90.000005)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 464.5,-16 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1.5 v 12 h -1.5 c -0.67616,-0.00956 -0.67616,1.0095626 0,1 h 5 c 0.67616,0.00956 0.67616,-1.0095626 0,-1 H 468 v -6 h 3 v 0.5 c -0.01,0.6761613 1.00956,0.6761613 1,0 v -0.9199219 c 0.009,-0.053677 0.009,-0.1084325 0,-0.1621093 V -10.5 c 0.01,-0.676161 -1.00956,-0.676161 -1,0 v 0.5 h -3 v -5 h 6 v 1.5 c -0.01,0.676161 1.00956,0.676161 1,0 v -2 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z" id="path12501" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccccc"/>
- </g>
- <g transform="matrix(0.92857149,0,0,0.92857137,106.93015,-501.7093)" style="display:inline;opacity:0.98999999;fill:#ffffff;stroke-width:1.07692313;enable-background:new" id="g8599" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path sodipodi:nodetypes="cccccccccccssccsssss" inkscape:connector-curvature="0" id="path8595" transform="matrix(1.076923,0,0,1.0769231,-739.76878,506.92345)" d="m 992.67578,105.26367 c -0.19597,-0.18575 -0.45872,-0.28437 -0.72851,-0.27344 -0.89539,0.0396 -1.29072,1.14623 -0.62305,1.74415 L 992.69727,108 H 986 c -1.36099,-0.0279 -1.36099,2.02794 0,2 h 3.0918 c -0.003,0.002 -0.005,0.004 -0.008,0.006 l -4.75,4.24805 c -0.99479,0.88933 0.3392,2.38151 1.33399,1.49218 l 2.33984,-2.09375 C 988.08993,116.60772 990.52575,119 993.5,119 c 3.02565,0 5.49805,-2.47428 5.49805,-5.5 0,-1.56564 -0.66395,-2.97983 -1.72241,-3.98356 z M 993.5,110 c 1.94471,0 3.5,1.5551 3.5,3.5 0,1.94489 -1.55529,3.5 -3.5,3.5 -1.94472,0 -3.5,-1.55511 -3.5,-3.5 0,-1.9449 1.55528,-3.5 3.5,-3.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path id="path8597" d="m 331.99999,629.15424 a 1.86519,1.8457757 0 0 1 -1.86519,1.84577 1.86519,1.8457757 0 0 1 -1.86519,-1.84577 1.86519,1.8457757 0 0 1 1.86519,-1.84578 1.86519,1.8457757 0 0 1 1.86519,1.84578 z" style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.15384626;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" inkscape:connector-curvature="0"/>
- </g>
- <g id="g12575" transform="matrix(0.8666665,0,0,0.8666665,-253.07368,16.407198)" style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.15384638;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 285.49219,388.99219 c -0.2763,0.004 -0.49651,0.23152 -0.49219,0.50781 v 2.6543 c -0.76567,0.19832 -1.43883,0.61396 -1.95508,1.18359 l -2.1914,-2.19141 c -0.0944,-0.0966 -0.22433,-0.15264 -0.35938,-0.15234 -0.4485,2.4e-4 -0.66889,0.54638 -0.34766,0.85938 l 2.32032,2.32031 C 282.17933,394.72335 282.0013,395.33918 282,396 h -2.5 c -0.66693,0 -0.66693,1 0,1 h 2.64062 c 0.19916,0.76891 0.61811,1.44388 1.19141,1.96094 l -2.18555,2.18554 c -0.4717,0.4717 0.23534,1.17874 0.70704,0.70704 l 2.3164,-2.31641 c 0.54947,0.28561 1.16223,0.46289 1.82227,0.46289 0.003,0 0.005,10e-6 0.008,0 v 2.5 c 0,0.66693 1,0.66693 1,0 v -2.64648 c 0.76569,-0.20169 1.4388,-0.6203 1.95312,-1.19336 l 2.19336,2.19336 c 0.47143,0.50593 1.2141,-0.23683 0.70704,-0.70704 l -2.32422,-2.32421 c 0.28283,-0.54738 0.45703,-1.15786 0.45703,-1.81446 0,-0.003 0,-0.005 0,-0.008 H 292.5 c 0.66693,0 0.66693,-1 0,-1 h -2.66016 c -0.20083,-0.76245 -0.61615,-1.43374 -1.18554,-1.94727 l 2.19922,-2.19921 c 0.32695,-0.31816 0.0927,-0.87325 -0.36329,-0.85938 -0.12999,0.004 -0.25338,0.0589 -0.34375,0.15234 l -2.33007,2.33008 C 287.26914,392.1921 286.6571,392.01496 286,392.01367 V 389.5 c 0.004,-0.28226 -0.22555,-0.51222 -0.50781,-0.50781 z m 0.5,4.02148 c 1.65884,0 2.99414,1.3353 2.99414,2.99414 0,1.65885 -1.3353,2.99219 -2.99414,2.99219 C 284.33334,399 283,397.66666 283,396.00781 c 0,-1.65884 1.33334,-2.99414 2.99219,-2.99414 z" transform="matrix(1.1538464,0,0,1.1538464,292.00815,-18.931386)" id="circle12556" inkscape:connector-curvature="0"/>
</g>
- <g id="g6143" style="fill:#ffffff">
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="g12901" transform="matrix(-0.79928788,0,0,0.79928788,828.43189,282.2677)" style="display:inline;opacity:0.7;fill:#ffffff;stroke-width:1.25111365;enable-background:new">
- <path id="path12894" transform="matrix(-1.2511137,0,0,1.2511137,1036.4625,-353.14898)" d="m 535.49805,458.00391 a 0.50004999,0.50004999 0 0 0 -0.50391,0.50781 l 0.002,1.33984 c -0.37236,0.0723 -0.71902,0.21977 -1.02148,0.42774 l -1.12695,-1.12305 a 0.50004999,0.50004999 0 0 0 -0.3418,-0.15039 0.50004999,0.50004999 0 0 0 -0.36328,0.85742 l 1.12695,1.12305 c -0.20781,0.30095 -0.35637,0.64504 -0.42969,1.01562 l -1.3457,0.004 a 0.50033487,0.50033487 0 0 0 0.002,1 l 1.33789,-0.002 c 0.0677,0.37781 0.20888,0.73164 0.41602,1.03906 l -1.10742,1.10937 a 0.50004999,0.50004999 0 1 0 0.70508,0.70508 l 1.10351,-1.10156 c 0.30838,0.21694 0.66219,0.37111 1.04492,0.44531 l -0.002,1.30078 a 0.50033678,0.50033678 0 1 0 1,0.004 l 0.002,-1.30274 c 0.3865,-0.0701 0.74651,-0.21619 1.0586,-0.43164 l 1.08203,1.08594 a 0.50005719,0.50005719 0 1 0 0.70703,-0.70508 l -1.08398,-1.08984 c 0.21441,-0.31231 0.36249,-0.67226 0.43164,-1.05859 h 1.30664 a 0.50098,0.50098 0 1 0 0,-1.00196 h -1.3125 c -0.0748,-0.37855 -0.23067,-0.72769 -0.44532,-1.0332 l 1.10352,-1.10547 a 0.50004999,0.50004999 0 0 0 -0.34961,-0.85937 0.50004999,0.50004999 0 0 0 -0.35742,0.15234 l -1.10938,1.10742 c -0.30548,-0.20557 -0.65624,-0.346 -1.03125,-0.41406 l -0.004,-1.33984 a 0.50004999,0.50004999 0 0 0 -0.49219,-0.50586 0.50004999,0.50004999 0 0 1 -0.002,0 z m -0.002,3.29882 c 0.66274,0 1.20117,0.53844 1.20118,1.20118 0,0.66273 -0.53844,1.19921 -1.20118,1.19921 -0.66273,0 -1.19921,-0.53648 -1.19921,-1.19921 0,-0.66273 0.53648,-1.20117 1.19921,-1.20118 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12259"
+ transform="matrix(0,-1,-1,0,312,-85.999995)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ transform="rotate(90,-175.5,-141.5)"
+ id="g12255"
+ mask="none">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 237.5,284 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path12253"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
</g>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.25111365;enable-background:new" transform="matrix(-0.79928788,0,0,0.79928788,833.43189,275.2677)" id="g12909">
- <path id="path12903" transform="matrix(-1.2511137,0,0,1.2511137,1042.718,-344.39118)" d="m 540.49805,451.00391 a 0.50004999,0.50004999 0 0 0 -0.50391,0.50781 l 0.002,1.33984 c -0.37236,0.0723 -0.71902,0.21977 -1.02148,0.42774 l -1.12695,-1.12305 a 0.50004999,0.50004999 0 0 0 -0.3418,-0.15039 0.50004999,0.50004999 0 0 0 -0.36328,0.85742 l 1.12695,1.12305 c -0.20781,0.30095 -0.35637,0.64503 -0.42969,1.01562 l -1.3457,0.004 a 0.50033487,0.50033487 0 0 0 0.002,1 l 1.33789,-0.002 c 0.0677,0.37781 0.20888,0.73164 0.41602,1.03906 l -1.10742,1.10937 a 0.50004999,0.50004999 0 1 0 0.70508,0.70508 l 1.10351,-1.10156 c 0.30838,0.21694 0.66219,0.37111 1.04492,0.44531 l -0.002,1.30078 a 0.50033678,0.50033678 0 1 0 1,0.004 l 0.002,-1.30274 c 0.386,-0.07 0.74484,-0.21858 1.05664,-0.43359 l 1.08399,1.08789 a 0.50005719,0.50005719 0 1 0 0.70703,-0.70508 l -1.08398,-1.08984 c 0.21441,-0.31231 0.36249,-0.67226 0.43164,-1.05859 h 1.30664 a 0.50098,0.50098 0 1 0 0,-1.00196 h -1.3125 c -0.0748,-0.37855 -0.23067,-0.72769 -0.44532,-1.0332 l 1.10352,-1.10547 a 0.50004999,0.50004999 0 0 0 -0.34961,-0.85937 0.50004999,0.50004999 0 0 0 -0.35742,0.15234 l -1.10938,1.10742 c -0.30548,-0.20557 -0.65624,-0.346 -1.03125,-0.41406 l -0.004,-1.33984 a 0.50004999,0.50004999 0 0 0 -0.49219,-0.50586 0.50004999,0.50004999 0 0 1 -0.002,0 z m -0.002,3.29882 c 0.66274,0 1.20117,0.53844 1.20118,1.20118 0,0.66273 -0.53844,1.19921 -1.20118,1.19921 -0.66273,0 -1.19921,-0.53648 -1.19921,-1.19921 0,-0.66273 0.53648,-1.20117 1.19921,-1.20118 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -614.5,272 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.50781 v 5 H -614.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 284 h 5 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -0.49219 v -3.5 a 0.50005,0.50005 0 1 0 -1,0 V 281 H -605.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -5 v -1.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -1.49219 v -5 H -611.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 274 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 h -3.5 v -0.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -1.41406 a 0.50005,0.50005 0 0 0 -0.16016,0 H -614 Z m 0,9 h 2 v 2 h -2 z m 9,0 h 2 v 2 h -2 z"
+ id="path12257"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12585"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ transform="matrix(-1,0,0,1,782,4.4999696e-6)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 387.53125,473 C 386.69103,473 386,473.69103 386,474.53125 V 475 h -0.5 c -0.84022,0 -1.5,0.70952 -1.5,1.53125 v 0.9375 c 0,0.82173 0.65978,1.53125 1.5,1.53125 h 0.96875 c 0.1915,0 0.40039,-0.14519 0.61133,-0.21289 l 0.3164,0.31641 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -0.5,-0.5 a 0.50005,0.50005 0 0 0 -0.70704,0 C 386.86607,477.9269 386.67628,478 386.46875,478 H 385.5 c -0.28602,0 -0.5,-0.22674 -0.5,-0.53125 v -0.9375 C 385,476.22674 385.21398,476 385.5,476 h 0.96875 c 0.02,0 0.0255,2.9e-4 0.0156,0 A 0.50005,0.50005 0 0 0 387,475.48438 c 2.9e-4,0.01 0,0.004 0,-0.0156 v -0.9375 C 387,474.24523 387.24523,474 387.53125,474 h 0.9375 c 0.28603,0 0.53125,0.24521 0.53125,0.53125 v 0.9375 c 0,0.20745 -0.0731,0.39731 -0.10352,0.42773 a 0.50005,0.50005 0 0 0 0,0.70704 l 0.5,0.5 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -0.31641,-0.3164 C 389.85483,475.86914 390,475.66029 390,475.46875 v -0.9375 C 390,473.69101 389.30896,473 388.46875,473 Z m 6.71289,7.74414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 0.5,0.5 a 0.50005,0.50005 0 0 0 0.70704,0 c -0.0536,0.0536 0.0619,-0.0282 0.21093,-0.0586 C 395.46351,482.01449 395.64626,482 395.75,482 h 0.75 c 0.30453,0 0.5,0.19546 0.5,0.5 v 0.9375 c 0,0.30451 -0.23248,0.5625 -0.5,0.5625 h -0.9375 c -0.02,0 -0.0255,-2.9e-4 -0.0156,0 a 0.50005,0.50005 0 0 0 -0.46485,0.2832 0.50005,0.50005 0 0 0 -0.0117,0.0215 c -0.002,0.004 -0.003,0.004 -0.006,0.01 -0.006,0.0121 -0.0155,0.0273 -0.0273,0.0566 -0.006,0.0147 -0.012,0.0324 -0.0195,0.0606 -0.007,0.0281 -0.0176,0.13022 -0.0176,0.13086 V 485.5 c 0,0.28602 -0.24525,0.53126 -0.53125,0.53125 H 393.5 c -0.28602,0 -0.5,-0.22674 -0.5,-0.53125 v -0.9375 c 0,-0.19821 0.0977,-0.45261 0.11133,-0.4668 a 0.50005,0.50005 0 0 0 -0.008,-0.69922 l -0.5,-0.5 a 0.50005,0.50005 0 1 0 -0.70704,0.70704 l 0.31836,0.31836 C 392.14451,484.14157 392,484.36068 392,484.5625 V 485.5 c 0,0.82173 0.65978,1.53125 1.5,1.53125 h 0.96875 C 395.30899,487.03126 396,486.34022 396,485.5 V 485 h 0.5 c 0.85872,0 1.5,-0.74077 1.5,-1.5625 V 482.5 c 0,-0.82174 -0.67829,-1.5 -1.5,-1.5 h -0.75 c -0.17782,0 -0.40107,0.0167 -0.63477,0.0645 -0.0763,0.0156 -0.15636,0.0877 -0.23437,0.10938 l -0.27734,-0.27735 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path12199"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 393.5,473 c -0.82416,0 -1.5,0.67974 -1.5,1.5 v 1 c 0,0.42842 0.21502,0.76851 0.50586,1.03711 l -4.96289,4.96484 C 387.27424,481.21375 386.93403,481 386.50781,481 h -1 c -0.82026,0 -1.5,0.67584 -1.5,1.5 0,0.82416 0.67974,1.5 1.5,1.5 h 1 0.5 v 0.5 1 c 0,0.82026 0.67585,1.5 1.5,1.5 0.82416,0 1.5,-0.67975 1.5,-1.5 v -1 c 0,-0.42841 -0.21502,-0.76851 -0.50586,-1.03711 l 4.96289,-4.96484 C 394.73357,478.78626 395.07378,479 395.5,479 h 1 c 0.82026,0 1.5,-0.67584 1.5,-1.5 0,-0.82416 -0.67974,-1.5 -1.5,-1.5 h -1 -0.5 v -0.5 -1 c 0,-0.82026 -0.67584,-1.5 -1.5,-1.5 z"
+ id="path12208"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssccsssscccssssccsssscccss" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 388.50781,494 c -0.82415,0 -1.5,0.67974 -1.5,1.5 v 1 0.5 h -0.5 -1 c -0.82026,0 -1.5,0.67584 -1.5,1.5 0,0.82416 0.67974,1.5 1.5,1.5 h 1 c 0.42622,0 0.76643,-0.21374 1.03516,-0.50195 l 4.96289,4.96484 C 392.21502,504.73149 392,505.07159 392,505.5 v 1 c 0,0.82025 0.67584,1.5 1.5,1.5 0.82416,0 1.5,-0.67974 1.5,-1.5 v -1 -0.5 h 0.5 1 c 0.82026,0 1.5,-0.67584 1.5,-1.5 0,-0.82416 -0.67974,-1.5 -1.5,-1.5 h -1 c -0.42622,0 -0.76642,0.21375 -1.03516,0.50195 l -4.96289,-4.96484 c 0.29085,-0.2686 0.50586,-0.60869 0.50586,-1.03711 v -1 c 0,-0.82026 -0.67584,-1.5 -1.5,-1.5 z"
+ id="path12213"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sscccssssccsssscccssssccsss" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12687"
+ transform="translate(-1.8536743e-6,42.000005)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 313.48633,389.00977 a 0.50005,0.50005 0 0 0 -0.13281,0.0156 l -10.64454,2.70117 a 0.50005,0.50005 0 0 0 -0.0176,0.006 c -0.39202,0.1157 -0.73529,0.32904 -1.00782,0.60156 -0.57977,0.57978 -0.79354,1.4303 -0.73828,2.33399 0.0553,0.90369 0.37679,1.88678 0.94141,2.83789 a 0.50005,0.50005 0 0 0 0,0.002 c 0.0547,0.092 0.11038,0.1837 0.16992,0.27539 a 0.50056694,0.50056694 0 1 0 0.83984,-0.54492 c -0.0521,-0.0802 -0.10227,-0.16121 -0.15039,-0.24219 -0.4939,-0.83198 -0.75942,-1.68043 -0.80273,-2.38867 -0.0433,-0.70823 0.13039,-1.24953 0.44726,-1.5664 0.16272,-0.16272 0.36207,-0.28412 0.58399,-0.34961 l 9.81055,-2.49024 -2.49024,9.81445 c -0.0654,0.2249 -0.18247,0.41294 -0.34961,0.58008 -0.32315,0.32316 -0.90925,0.49604 -1.67187,0.42578 -0.76263,-0.0702 -1.66859,-0.38268 -2.52735,-0.93164 a 0.50005,0.50005 0 1 0 -0.53906,0.8418 c 0.97998,0.62645 2.02029,0.99785 2.97656,1.08594 0.95627,0.0881 1.86106,-0.10716 2.46875,-0.71485 0.27194,-0.27193 0.4884,-0.61189 0.60352,-1.00781 a 0.50005,0.50005 0 0 0 0.004,-0.0176 l 2.70117,-10.64453 a 0.50005,0.50005 0 0 0 -0.47461,-0.62304 z M 308,393.99414 a 1,1 0 0 0 -1,1 1,1 0 0 0 0.0352,0.25586 l -0.88868,0.88867 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 0.88671,-0.88672 a 1,1 0 0 0 0.25977,0.0352 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z m -3.50977,3.99219 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85937 z m -3.00195,3 a 0.50005,0.50005 0 0 0 -0.3418,0.15234 l -1,1.00391 a 0.50005,0.50005 0 1 0 0.70704,0.70508 l 1,-1.00391 a 0.50005,0.50005 0 0 0 -0.36524,-0.85742 z"
+ transform="translate(1.8536743e-6,-42.000005)"
+ id="path7527-5"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12682"
+ transform="translate(-1.8536743e-6,42.000005)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 325.05469,389.00391 c -0.66782,-0.018 -1.21728,4.6e-4 -1.57813,0.002 h -0.002 c -0.34416,2.5e-4 -0.65424,0.0639 -0.91602,0.22852 -0.2623,0.16491 -0.44433,0.43888 -0.51367,0.7207 -0.13867,0.56363 0.037,1.13654 0.3125,1.76758 0.55094,1.26206 1.63318,2.77176 2.73438,4.10351 a 0.50004997,0.50004997 0 1 0 0.76953,-0.63867 c -1.06758,-1.2911 -2.11546,-2.78301 -2.58789,-3.86523 -0.23622,-0.54112 -0.29509,-0.9754 -0.25782,-1.12696 0.0186,-0.0758 0.0265,-0.0852 0.0742,-0.11523 0.0478,-0.03 0.16614,-0.0742 0.38672,-0.0742 a 0.50004997,0.50004997 0 0 0 0.002,0 c 1.54352,-0.006 5.58742,-0.20164 8.14453,2.35547 2.5571,2.5571 2.35972,6.59906 2.35351,8.14258 a 0.50004997,0.50004997 0 0 0 0,0.002 c 0,0.22058 -0.0442,0.33897 -0.0742,0.38672 -0.03,0.0477 -0.0375,0.0575 -0.11328,0.0762 -0.15155,0.0373 -0.58779,-0.0216 -1.1289,-0.25781 -1.08223,-0.47244 -2.57414,-1.52227 -3.86524,-2.58985 a 0.50015227,0.50015227 0 1 0 -0.63672,0.77149 c 1.33176,1.1012 2.8395,2.18343 4.10157,2.73437 0.63103,0.27547 1.20395,0.45117 1.76757,0.3125 0.28182,-0.0693 0.55774,-0.25136 0.72266,-0.51367 0.16426,-0.26126 0.22607,-0.57268 0.22656,-0.91601 v -0.004 c 0.006,-1.44452 0.29493,-5.9121 -2.64648,-8.85352 -2.20662,-2.20661 -5.27193,-2.59451 -7.27539,-2.64843 z m 3.95117,4.99023 a 1,1 0 0 0 -1,1 1,1 0 0 0 0.0332,0.25781 l -0.88672,0.88672 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 0.88671,-0.88672 a 1,1 0 0 0 0.25977,0.0352 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z m -3.50977,3.99219 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85937 z m -3.00195,3 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1.00391 a 0.50005,0.50005 0 1 0 0.70899,0.70508 l 1,-1.00391 a 0.50005,0.50005 0 0 0 -0.36524,-0.85742 z"
+ transform="translate(1.8536743e-6,-42.000005)"
+ id="path7537-6"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12674"
+ transform="translate(-1.8536743e-6,63.000005)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.70000005;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ d="m 343.50586,388.99219 a 0.50005,0.50005 0 0 0 -0.35547,0.14648 l -1.00391,1.00781 a 0.50005,0.50005 0 0 0 -0.0937,0.57618 l 3,6 a 0.50005,0.50005 0 1 0 0.89454,-0.44532 l -2.83985,-5.67968 0.60547,-0.60547 h 6.4707 l 4.72266,10.39062 -0.60937,0.60938 -5.98633,0.008 -0.35743,-0.72656 a 0.50005,0.50005 0 1 0 -0.89648,0.4414 l 0.49414,1.00586 A 0.50005,0.50005 0 0 0 348,402 l 6.50586,-0.008 a 0.50005,0.50005 0 0 0 0.35352,-0.14649 l 1,-1 a 0.50005,0.50005 0 0 0 0.10156,-0.56054 l -5,-11 a 0.50005,0.50005 0 0 0 -0.45508,-0.29297 z m 5.5,6.00195 a 1,1 0 0 0 -1,1 1,1 0 0 0 0.0332,0.25977 l -0.14258,0.14257 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 0.14453,-0.14454 a 1,1 0 0 0 0.25781,0.0352 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z m -2.50977,2.99219 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85937 z m -3.00195,3 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1.00391 a 0.50005,0.50005 0 1 0 0.70899,0.70508 l 1,-1.00391 a 0.50005,0.50005 0 0 0 -0.36524,-0.85742 z"
+ transform="translate(1.8536743e-6,-63.000005)"
+ id="circle12662"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g12707"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;stroke-width:1.07692313;enable-background:new"
+ transform="matrix(0.92857149,0,0,0.92857137,22.930148,44.290705)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 327.94922,619.99609 c -0.89539,0.0396 -1.29072,1.14622 -0.62305,1.74414 l 1.37305,1.26563 h -6.69727 c -1.36099,-0.0279 -1.36099,2.02794 0,2 h 3.0918 c -0.003,0.002 -0.005,0.004 -0.008,0.006 l -4.75,4.24805 c -0.99479,0.88933 0.33919,2.38151 1.33398,1.49218 l 2.33985,-2.09375 c 0.0823,2.95524 2.51793,5.34766 5.49218,5.34766 3.02565,0 5.49805,-2.47428 5.49805,-5.5 0,-1.56564 -0.6642,-2.98065 -1.72266,-3.98438 l -4.59961,-4.25195 c -0.19597,-0.18575 -0.45872,-0.28437 -0.72851,-0.27344 z m 1.55273,5.00977 c 1.94471,0 3.5,1.5551 3.5,3.5 0,1.94489 -1.55529,3.5 -3.5,3.5 -1.94472,0 -3.5,-1.55511 -3.5,-3.5 0,-1.9449 1.55528,-3.5 3.5,-3.5 z m -0.0176,1.78516 a 1.7319623,1.7139345 0 0 0 -1.73243,1.71484 1.7319623,1.7139345 0 0 0 1.73243,1.71289 1.7319623,1.7139345 0 0 0 1.73242,-1.71289 1.7319623,1.7139345 0 0 0 -1.73242,-1.71484 z"
+ transform="matrix(1.076923,0,0,1.0769231,-24.694004,-47.697685)"
+ id="path12703"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-210.00712,-588.00007)"
+ id="g12466"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ transform="translate(22)"
+ id="g12463"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 557.5,620 a 0.50005,0.50005 0 1 0 0,1 h 6.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 6.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 6.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,5 a 0.50005,0.50005 0 1 0 0,1 h 6.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 6.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 7 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path12459"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 553.48438,620 a 0.50005,0.50005 0 0 0 -0.3379,0.14648 l -2,2 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 553,621.70703 V 625.5 a 0.50005,0.50005 0 1 0 1,0 v -5 A 0.50005,0.50005 0 0 0 553.48438,620 Z M 553,628 c -0.79172,0 -1.70536,0.42737 -1.98047,1.35938 a 0.50062501,0.50062501 0 1 0 0.96094,0.28124 C 552.10464,629.21999 552.55814,629 553,629 c 0.31942,0 0.59941,0.0632 0.75391,0.16602 0.1545,0.10279 0.25034,0.21211 0.2539,0.58789 5.6e-4,0.20689 -0.076,0.32805 -0.29687,0.52148 -0.22152,0.19398 -0.57835,0.40234 -0.9668,0.64453 -0.38845,0.24219 -0.81151,0.52364 -1.1543,0.93555 -0.34278,0.4119 -0.58774,0.96871 -0.58984,1.64258 A 0.50005,0.50005 0 0 0 551.5,634 h 3 a 0.50005,0.50005 0 1 0 0,-1 h -2.32227 c 0.0615,-0.1621 0.068,-0.36972 0.17969,-0.50391 0.22282,-0.26775 0.55267,-0.50197 0.91602,-0.72851 0.36335,-0.22654 0.7571,-0.44007 1.09765,-0.73828 0.34056,-0.29822 0.6393,-0.73918 0.63672,-1.28125 a 0.50005,0.50005 0 0 0 0,-0.002 c -0.006,-0.62417 -0.29003,-1.13985 -0.69922,-1.41211 C 553.89941,628.06173 553.43058,628 553,628 Z"
+ id="path12461"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g12259" transform="matrix(0,-1,-1,0,312,-85.999995)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" transform="rotate(90,-175.5,-141.5)" id="g12255" mask="none">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 237.5,284 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path12253" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ id="g21139"
+ style="display:inline;opacity:0.7;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 412,179 c -3.86007,0 -7,3.13993 -7,7 0,3.86007 3.13993,7 7,7 3.86007,0 7,-3.13993 7,-7 0,-3.86007 -3.13993,-7 -7,-7 z m 0,1 c 3.31963,0 6,2.68037 6,6 0,3.31963 -2.68037,6 -6,6 -3.31963,0 -6,-2.68037 -6,-6 0,-3.31963 2.68037,-6 6,-6 z"
+ id="path12522"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 412,184 c -1.09865,0 -2,0.90135 -2,2 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 0,-1.09865 -0.90135,-2 -2,-2 z"
+ id="path12526"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
+ <g
+ transform="rotate(-180,670.50713,476.50011)"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
+ id="g9316-9"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ transform="translate(438,704)"
+ id="g8254-6"
+ style="fill:#ffffff" />
+ <g
+ style="fill:#ffffff;stroke-width:1.09491563"
+ id="g8219-5"
+ transform="matrix(0.99217072,0,0,0.84072177,457.69618,698.42569)" />
+ <g
+ id="g8268-6"
+ transform="rotate(90,613.50354,483.5038)"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 746.49219,-91.007812 A 0.50005,0.50005 0 0 0 746,-90.5 v 2.503906 l -2.5,0.0039 a 0.50005,0.50005 0 1 0 0,1 l 3,-0.0039 a 0.50005,0.50005 0 0 0 0.5,-0.5 V -90.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 2.00781,3.015624 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z m 5,0 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z m -7.00781,1.986329 A 0.50005,0.50005 0 0 0 746,-85.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.505859 z m 0,5 A 0.50005,0.50005 0 0 0 746,-80.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.505859 z"
+ id="path8265-4"
+ inkscape:connector-curvature="0" />
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m -614.5,272 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.50781 v 5 H -614.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 284 h 5 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -0.49219 v -3.5 a 0.50005,0.50005 0 1 0 -1,0 V 281 H -605.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -5 v -1.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -1.49219 v -5 H -611.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 274 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 h -3.5 v -0.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -1.41406 a 0.50005,0.50005 0 0 0 -0.16016,0 H -614 Z m 0,9 h 2 v 2 h -2 z m 9,0 h 2 v 2 h -2 z" id="path12257" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g12585" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96" transform="matrix(-1,0,0,1,782,4.4999696e-6)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 387.53125,473 C 386.69103,473 386,473.69103 386,474.53125 V 475 h -0.5 c -0.84022,0 -1.5,0.70952 -1.5,1.53125 v 0.9375 c 0,0.82173 0.65978,1.53125 1.5,1.53125 h 0.96875 c 0.1915,0 0.40039,-0.14519 0.61133,-0.21289 l 0.3164,0.31641 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -0.5,-0.5 a 0.50005,0.50005 0 0 0 -0.70704,0 C 386.86607,477.9269 386.67628,478 386.46875,478 H 385.5 c -0.28602,0 -0.5,-0.22674 -0.5,-0.53125 v -0.9375 C 385,476.22674 385.21398,476 385.5,476 h 0.96875 c 0.02,0 0.0255,2.9e-4 0.0156,0 A 0.50005,0.50005 0 0 0 387,475.48438 c 2.9e-4,0.01 0,0.004 0,-0.0156 v -0.9375 C 387,474.24523 387.24523,474 387.53125,474 h 0.9375 c 0.28603,0 0.53125,0.24521 0.53125,0.53125 v 0.9375 c 0,0.20745 -0.0731,0.39731 -0.10352,0.42773 a 0.50005,0.50005 0 0 0 0,0.70704 l 0.5,0.5 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -0.31641,-0.3164 C 389.85483,475.86914 390,475.66029 390,475.46875 v -0.9375 C 390,473.69101 389.30896,473 388.46875,473 Z m 6.71289,7.74414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 0.5,0.5 a 0.50005,0.50005 0 0 0 0.70704,0 c -0.0536,0.0536 0.0619,-0.0282 0.21093,-0.0586 C 395.46351,482.01449 395.64626,482 395.75,482 h 0.75 c 0.30453,0 0.5,0.19546 0.5,0.5 v 0.9375 c 0,0.30451 -0.23248,0.5625 -0.5,0.5625 h -0.9375 c -0.02,0 -0.0255,-2.9e-4 -0.0156,0 a 0.50005,0.50005 0 0 0 -0.46485,0.2832 0.50005,0.50005 0 0 0 -0.0117,0.0215 c -0.002,0.004 -0.003,0.004 -0.006,0.01 -0.006,0.0121 -0.0155,0.0273 -0.0273,0.0566 -0.006,0.0147 -0.012,0.0324 -0.0195,0.0606 -0.007,0.0281 -0.0176,0.13022 -0.0176,0.13086 V 485.5 c 0,0.28602 -0.24525,0.53126 -0.53125,0.53125 H 393.5 c -0.28602,0 -0.5,-0.22674 -0.5,-0.53125 v -0.9375 c 0,-0.19821 0.0977,-0.45261 0.11133,-0.4668 a 0.50005,0.50005 0 0 0 -0.008,-0.69922 l -0.5,-0.5 a 0.50005,0.50005 0 1 0 -0.70704,0.70704 l 0.31836,0.31836 C 392.14451,484.14157 392,484.36068 392,484.5625 V 485.5 c 0,0.82173 0.65978,1.53125 1.5,1.53125 h 0.96875 C 395.30899,487.03126 396,486.34022 396,485.5 V 485 h 0.5 c 0.85872,0 1.5,-0.74077 1.5,-1.5625 V 482.5 c 0,-0.82174 -0.67829,-1.5 -1.5,-1.5 h -0.75 c -0.17782,0 -0.40107,0.0167 -0.63477,0.0645 -0.0763,0.0156 -0.15636,0.0877 -0.23437,0.10938 l -0.27734,-0.27735 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z" id="path12199" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 393.5,473 c -0.82416,0 -1.5,0.67974 -1.5,1.5 v 1 c 0,0.42842 0.21502,0.76851 0.50586,1.03711 l -4.96289,4.96484 C 387.27424,481.21375 386.93403,481 386.50781,481 h -1 c -0.82026,0 -1.5,0.67584 -1.5,1.5 0,0.82416 0.67974,1.5 1.5,1.5 h 1 0.5 v 0.5 1 c 0,0.82026 0.67585,1.5 1.5,1.5 0.82416,0 1.5,-0.67975 1.5,-1.5 v -1 c 0,-0.42841 -0.21502,-0.76851 -0.50586,-1.03711 l 4.96289,-4.96484 C 394.73357,478.78626 395.07378,479 395.5,479 h 1 c 0.82026,0 1.5,-0.67584 1.5,-1.5 0,-0.82416 -0.67974,-1.5 -1.5,-1.5 h -1 -0.5 v -0.5 -1 c 0,-0.82026 -0.67584,-1.5 -1.5,-1.5 z" id="path12208" inkscape:connector-curvature="0" sodipodi:nodetypes="sssccsssscccssssccsssscccss"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 388.50781,494 c -0.82415,0 -1.5,0.67974 -1.5,1.5 v 1 0.5 h -0.5 -1 c -0.82026,0 -1.5,0.67584 -1.5,1.5 0,0.82416 0.67974,1.5 1.5,1.5 h 1 c 0.42622,0 0.76643,-0.21374 1.03516,-0.50195 l 4.96289,4.96484 C 392.21502,504.73149 392,505.07159 392,505.5 v 1 c 0,0.82025 0.67584,1.5 1.5,1.5 0.82416,0 1.5,-0.67974 1.5,-1.5 v -1 -0.5 h 0.5 1 c 0.82026,0 1.5,-0.67584 1.5,-1.5 0,-0.82416 -0.67974,-1.5 -1.5,-1.5 h -1 c -0.42622,0 -0.76642,0.21375 -1.03516,0.50195 l -4.96289,-4.96484 c 0.29085,-0.2686 0.50586,-0.60869 0.50586,-1.03711 v -1 c 0,-0.82026 -0.67584,-1.5 -1.5,-1.5 z" id="path12213" inkscape:connector-curvature="0" sodipodi:nodetypes="sscccssssccsssscccssssccsss"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g12687" transform="translate(-1.8536743e-6,42.000005)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 313.48633,389.00977 a 0.50005,0.50005 0 0 0 -0.13281,0.0156 l -10.64454,2.70117 a 0.50005,0.50005 0 0 0 -0.0176,0.006 c -0.39202,0.1157 -0.73529,0.32904 -1.00782,0.60156 -0.57977,0.57978 -0.79354,1.4303 -0.73828,2.33399 0.0553,0.90369 0.37679,1.88678 0.94141,2.83789 a 0.50005,0.50005 0 0 0 0,0.002 c 0.0547,0.092 0.11038,0.1837 0.16992,0.27539 a 0.50056694,0.50056694 0 1 0 0.83984,-0.54492 c -0.0521,-0.0802 -0.10227,-0.16121 -0.15039,-0.24219 -0.4939,-0.83198 -0.75942,-1.68043 -0.80273,-2.38867 -0.0433,-0.70823 0.13039,-1.24953 0.44726,-1.5664 0.16272,-0.16272 0.36207,-0.28412 0.58399,-0.34961 l 9.81055,-2.49024 -2.49024,9.81445 c -0.0654,0.2249 -0.18247,0.41294 -0.34961,0.58008 -0.32315,0.32316 -0.90925,0.49604 -1.67187,0.42578 -0.76263,-0.0702 -1.66859,-0.38268 -2.52735,-0.93164 a 0.50005,0.50005 0 1 0 -0.53906,0.8418 c 0.97998,0.62645 2.02029,0.99785 2.97656,1.08594 0.95627,0.0881 1.86106,-0.10716 2.46875,-0.71485 0.27194,-0.27193 0.4884,-0.61189 0.60352,-1.00781 a 0.50005,0.50005 0 0 0 0.004,-0.0176 l 2.70117,-10.64453 a 0.50005,0.50005 0 0 0 -0.47461,-0.62304 z M 308,393.99414 a 1,1 0 0 0 -1,1 1,1 0 0 0 0.0352,0.25586 l -0.88868,0.88867 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 0.88671,-0.88672 a 1,1 0 0 0 0.25977,0.0352 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z m -3.50977,3.99219 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85937 z m -3.00195,3 a 0.50005,0.50005 0 0 0 -0.3418,0.15234 l -1,1.00391 a 0.50005,0.50005 0 1 0 0.70704,0.70508 l 1,-1.00391 a 0.50005,0.50005 0 0 0 -0.36524,-0.85742 z" transform="translate(1.8536743e-6,-42.000005)" id="path7527-5" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g12682" transform="translate(-1.8536743e-6,42.000005)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 325.05469,389.00391 c -0.66782,-0.018 -1.21728,4.6e-4 -1.57813,0.002 h -0.002 c -0.34416,2.5e-4 -0.65424,0.0639 -0.91602,0.22852 -0.2623,0.16491 -0.44433,0.43888 -0.51367,0.7207 -0.13867,0.56363 0.037,1.13654 0.3125,1.76758 0.55094,1.26206 1.63318,2.77176 2.73438,4.10351 a 0.50004997,0.50004997 0 1 0 0.76953,-0.63867 c -1.06758,-1.2911 -2.11546,-2.78301 -2.58789,-3.86523 -0.23622,-0.54112 -0.29509,-0.9754 -0.25782,-1.12696 0.0186,-0.0758 0.0265,-0.0852 0.0742,-0.11523 0.0478,-0.03 0.16614,-0.0742 0.38672,-0.0742 a 0.50004997,0.50004997 0 0 0 0.002,0 c 1.54352,-0.006 5.58742,-0.20164 8.14453,2.35547 2.5571,2.5571 2.35972,6.59906 2.35351,8.14258 a 0.50004997,0.50004997 0 0 0 0,0.002 c 0,0.22058 -0.0442,0.33897 -0.0742,0.38672 -0.03,0.0477 -0.0375,0.0575 -0.11328,0.0762 -0.15155,0.0373 -0.58779,-0.0216 -1.1289,-0.25781 -1.08223,-0.47244 -2.57414,-1.52227 -3.86524,-2.58985 a 0.50015227,0.50015227 0 1 0 -0.63672,0.77149 c 1.33176,1.1012 2.8395,2.18343 4.10157,2.73437 0.63103,0.27547 1.20395,0.45117 1.76757,0.3125 0.28182,-0.0693 0.55774,-0.25136 0.72266,-0.51367 0.16426,-0.26126 0.22607,-0.57268 0.22656,-0.91601 v -0.004 c 0.006,-1.44452 0.29493,-5.9121 -2.64648,-8.85352 -2.20662,-2.20661 -5.27193,-2.59451 -7.27539,-2.64843 z m 3.95117,4.99023 a 1,1 0 0 0 -1,1 1,1 0 0 0 0.0332,0.25781 l -0.88672,0.88672 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 0.88671,-0.88672 a 1,1 0 0 0 0.25977,0.0352 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z m -3.50977,3.99219 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85937 z m -3.00195,3 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1.00391 a 0.50005,0.50005 0 1 0 0.70899,0.70508 l 1,-1.00391 a 0.50005,0.50005 0 0 0 -0.36524,-0.85742 z" transform="translate(1.8536743e-6,-42.000005)" id="path7537-6" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g12674" transform="translate(-1.8536743e-6,63.000005)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.70000005;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" d="m 343.50586,388.99219 a 0.50005,0.50005 0 0 0 -0.35547,0.14648 l -1.00391,1.00781 a 0.50005,0.50005 0 0 0 -0.0937,0.57618 l 3,6 a 0.50005,0.50005 0 1 0 0.89454,-0.44532 l -2.83985,-5.67968 0.60547,-0.60547 h 6.4707 l 4.72266,10.39062 -0.60937,0.60938 -5.98633,0.008 -0.35743,-0.72656 a 0.50005,0.50005 0 1 0 -0.89648,0.4414 l 0.49414,1.00586 A 0.50005,0.50005 0 0 0 348,402 l 6.50586,-0.008 a 0.50005,0.50005 0 0 0 0.35352,-0.14649 l 1,-1 a 0.50005,0.50005 0 0 0 0.10156,-0.56054 l -5,-11 a 0.50005,0.50005 0 0 0 -0.45508,-0.29297 z m 5.5,6.00195 a 1,1 0 0 0 -1,1 1,1 0 0 0 0.0332,0.25977 l -0.14258,0.14257 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 0.14453,-0.14454 a 1,1 0 0 0 0.25781,0.0352 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z m -2.50977,2.99219 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85937 z m -3.00195,3 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1.00391 a 0.50005,0.50005 0 1 0 0.70899,0.70508 l 1,-1.00391 a 0.50005,0.50005 0 0 0 -0.36524,-0.85742 z" transform="translate(1.8536743e-6,-63.000005)" id="circle12662" inkscape:connector-curvature="0"/>
- </g>
- <g id="g12707" style="display:inline;opacity:0.98999999;fill:#ffffff;stroke-width:1.07692313;enable-background:new" transform="matrix(0.92857149,0,0,0.92857137,22.930148,44.290705)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 327.94922,619.99609 c -0.89539,0.0396 -1.29072,1.14622 -0.62305,1.74414 l 1.37305,1.26563 h -6.69727 c -1.36099,-0.0279 -1.36099,2.02794 0,2 h 3.0918 c -0.003,0.002 -0.005,0.004 -0.008,0.006 l -4.75,4.24805 c -0.99479,0.88933 0.33919,2.38151 1.33398,1.49218 l 2.33985,-2.09375 c 0.0823,2.95524 2.51793,5.34766 5.49218,5.34766 3.02565,0 5.49805,-2.47428 5.49805,-5.5 0,-1.56564 -0.6642,-2.98065 -1.72266,-3.98438 l -4.59961,-4.25195 c -0.19597,-0.18575 -0.45872,-0.28437 -0.72851,-0.27344 z m 1.55273,5.00977 c 1.94471,0 3.5,1.5551 3.5,3.5 0,1.94489 -1.55529,3.5 -3.5,3.5 -1.94472,0 -3.5,-1.55511 -3.5,-3.5 0,-1.9449 1.55528,-3.5 3.5,-3.5 z m -0.0176,1.78516 a 1.7319623,1.7139345 0 0 0 -1.73243,1.71484 1.7319623,1.7139345 0 0 0 1.73243,1.71289 1.7319623,1.7139345 0 0 0 1.73242,-1.71289 1.7319623,1.7139345 0 0 0 -1.73242,-1.71484 z" transform="matrix(1.076923,0,0,1.0769231,-24.694004,-47.697685)" id="path12703" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-210.00712,-588.00007)" id="g12466" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g transform="translate(22)" id="g12463" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 557.5,620 a 0.50005,0.50005 0 1 0 0,1 h 6.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 6.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 6.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,5 a 0.50005,0.50005 0 1 0 0,1 h 6.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 6.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 7 a 0.50005,0.50005 0 1 0 0,-1 z" id="path12459" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 553.48438,620 a 0.50005,0.50005 0 0 0 -0.3379,0.14648 l -2,2 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 553,621.70703 V 625.5 a 0.50005,0.50005 0 1 0 1,0 v -5 A 0.50005,0.50005 0 0 0 553.48438,620 Z M 553,628 c -0.79172,0 -1.70536,0.42737 -1.98047,1.35938 a 0.50062501,0.50062501 0 1 0 0.96094,0.28124 C 552.10464,629.21999 552.55814,629 553,629 c 0.31942,0 0.59941,0.0632 0.75391,0.16602 0.1545,0.10279 0.25034,0.21211 0.2539,0.58789 5.6e-4,0.20689 -0.076,0.32805 -0.29687,0.52148 -0.22152,0.19398 -0.57835,0.40234 -0.9668,0.64453 -0.38845,0.24219 -0.81151,0.52364 -1.1543,0.93555 -0.34278,0.4119 -0.58774,0.96871 -0.58984,1.64258 A 0.50005,0.50005 0 0 0 551.5,634 h 3 a 0.50005,0.50005 0 1 0 0,-1 h -2.32227 c 0.0615,-0.1621 0.068,-0.36972 0.17969,-0.50391 0.22282,-0.26775 0.55267,-0.50197 0.91602,-0.72851 0.36335,-0.22654 0.7571,-0.44007 1.09765,-0.73828 0.34056,-0.29822 0.6393,-0.73918 0.63672,-1.28125 a 0.50005,0.50005 0 0 0 0,-0.002 c -0.006,-0.62417 -0.29003,-1.13985 -0.69922,-1.41211 C 553.89941,628.06173 553.43058,628 553,628 Z" id="path12461" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 160.5,327 c -0.8223,0 -1.5,0.67765 -1.5,1.5 v 4 c 0,0.82235 0.6777,1.5 1.5,1.5 h 5 c 0.8224,0 1.5,-0.67765 1.5,-1.5 v -4 c 0,-0.82235 -0.6776,-1.5 -1.5,-1.5 z m 0,5 h 5 a 0.50005,0.50005 0 1 1 0,1 h -5 a 0.50005,0.50005 0 1 1 0,-1 z"
+ transform="rotate(180,670.50713,476.50011)"
+ id="rect8324-7-9-0"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-1022,-287.00021)"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
+ id="g9304-8"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ transform="translate(419,704)"
+ id="g8292-1"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 746.49219,-91.007812 A 0.50005,0.50005 0 0 0 746,-90.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 0,5 A 0.50005,0.50005 0 0 0 746,-85.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 0,5 A 0.50005,0.50005 0 0 0 746,-80.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z"
+ id="path8290-6"
+ inkscape:connector-curvature="0" />
</g>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" id="g21139" style="display:inline;opacity:0.7;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 412,179 c -3.86007,0 -7,3.13993 -7,7 0,3.86007 3.13993,7 7,7 3.86007,0 7,-3.13993 7,-7 0,-3.86007 -3.13993,-7 -7,-7 z m 0,1 c 3.31963,0 6,2.68037 6,6 0,3.31963 -2.68037,6 -6,6 -3.31963,0 -6,-2.68037 -6,-6 0,-3.31963 2.68037,-6 6,-6 z" id="path12522" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 412,184 c -1.09865,0 -2,0.90135 -2,2 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 0,-1.09865 -0.90135,-2 -2,-2 z" id="path12526" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- </g>
- <g transform="rotate(-180,670.50713,476.50011)" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" id="g9316-9" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g transform="translate(438,704)" id="g8254-6" style="fill:#ffffff"/>
- <g style="fill:#ffffff;stroke-width:1.09491563" id="g8219-5" transform="matrix(0.99217072,0,0,0.84072177,457.69618,698.42569)"/>
- <g id="g8268-6" transform="rotate(90,613.50354,483.5038)" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 746.49219,-91.007812 A 0.50005,0.50005 0 0 0 746,-90.5 v 2.503906 l -2.5,0.0039 a 0.50005,0.50005 0 1 0 0,1 l 3,-0.0039 a 0.50005,0.50005 0 0 0 0.5,-0.5 V -90.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 2.00781,3.015624 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z m 5,0 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z m -7.00781,1.986329 A 0.50005,0.50005 0 0 0 746,-85.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.505859 z m 0,5 A 0.50005,0.50005 0 0 0 746,-80.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.505859 z" id="path8265-4" inkscape:connector-curvature="0"/>
+ <g
+ transform="translate(435,709)"
+ id="g8299-5"
+ style="fill:#ffffff" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 134.5,330 c -0.8224,0 -1.5,0.67765 -1.5,1.5 v 4 c 0,0.82235 0.6776,1.5 1.5,1.5 h 5 c 0.8224,0 1.5,-0.67765 1.5,-1.5 v -4 c 0,-0.82235 -0.6776,-1.5 -1.5,-1.5 z m 0,5 h 5 a 0.50005,0.50005 0 1 1 0,1 h -5 a 0.50005,0.50005 0 1 1 0,-1 z"
+ transform="translate(1022,287.00021)"
+ id="rect8324-7-9"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-1021,-287.00021)"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
+ id="g9296-0"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ id="g8328-6"
+ transform="translate(415,710)"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 115.5,331 c -0.82235,0 -1.5,0.67765 -1.5,1.5 v 4 c 0,0.82235 0.67765,1.5 1.5,1.5 h 5 c 0.82235,0 1.5,-0.67765 1.5,-1.5 v -4 c 0,-0.82235 -0.67765,-1.5 -1.5,-1.5 z m 0,5 h 5 a 0.50005,0.50005 0 1 1 0,1 h -5 a 0.50005,0.50005 0 1 1 0,-1 z"
+ transform="translate(606,-422.99979)"
+ id="rect8324-7"
+ inkscape:connector-curvature="0" />
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 160.5,327 c -0.8223,0 -1.5,0.67765 -1.5,1.5 v 4 c 0,0.82235 0.6777,1.5 1.5,1.5 h 5 c 0.8224,0 1.5,-0.67765 1.5,-1.5 v -4 c 0,-0.82235 -0.6776,-1.5 -1.5,-1.5 z m 0,5 h 5 a 0.50005,0.50005 0 1 1 0,1 h -5 a 0.50005,0.50005 0 1 1 0,-1 z" transform="rotate(180,670.50713,476.50011)" id="rect8324-7-9-0" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-1022,-287.00021)" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" id="g9304-8" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g transform="translate(419,704)" id="g8292-1" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 746.49219,-91.007812 A 0.50005,0.50005 0 0 0 746,-90.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 0,5 A 0.50005,0.50005 0 0 0 746,-85.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 0,5 A 0.50005,0.50005 0 0 0 746,-80.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z" id="path8290-6" inkscape:connector-curvature="0"/>
+ <g
+ id="g8338-5"
+ transform="rotate(90,593.00354,462.0038)"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 746.49219,-91.007812 A 0.50005,0.50005 0 0 0 746,-90.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 0,5 A 0.50005,0.50005 0 0 0 746,-85.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 0,5 A 0.50005,0.50005 0 0 0 746,-80.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z"
+ id="path8336-9"
+ inkscape:connector-curvature="0" />
</g>
- <g transform="translate(435,709)" id="g8299-5" style="fill:#ffffff"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 134.5,330 c -0.8224,0 -1.5,0.67765 -1.5,1.5 v 4 c 0,0.82235 0.6776,1.5 1.5,1.5 h 5 c 0.8224,0 1.5,-0.67765 1.5,-1.5 v -4 c 0,-0.82235 -0.6776,-1.5 -1.5,-1.5 z m 0,5 h 5 a 0.50005,0.50005 0 1 1 0,1 h -5 a 0.50005,0.50005 0 1 1 0,-1 z" transform="translate(1022,287.00021)" id="rect8324-7-9" inkscape:connector-curvature="0"/>
</g>
- <g transform="translate(-1021,-287.00021)" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" id="g9296-0" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g id="g8328-6" transform="translate(415,710)" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 115.5,331 c -0.82235,0 -1.5,0.67765 -1.5,1.5 v 4 c 0,0.82235 0.67765,1.5 1.5,1.5 h 5 c 0.82235,0 1.5,-0.67765 1.5,-1.5 v -4 c 0,-0.82235 -0.67765,-1.5 -1.5,-1.5 z m 0,5 h 5 a 0.50005,0.50005 0 1 1 0,1 h -5 a 0.50005,0.50005 0 1 1 0,-1 z" transform="translate(606,-422.99979)" id="rect8324-7" inkscape:connector-curvature="0"/>
+ <path
+ inkscape:connector-curvature="0"
+ id="path22951-5"
+ d="m 52.5,410 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 A 0.50005,0.50005 0 0 0 56,413.5 V 412 h 0.5 c 1.293073,0 2.425866,0.35206 3.21875,1.00977 C 60.511634,413.66747 61,414.62406 61,416 c 0,1.58333 -0.78109,3.05511 -2.240234,4.16406 C 57.300621,421.27301 55.159091,422 52.5,422 H 52 v -1.5 A 0.50005,0.50005 0 0 0 51.5,420 h -3 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 A 0.50005,0.50005 0 0 0 52,423.5 V 423 h 0.5 c 2.840909,0 5.199379,-0.77301 6.865234,-2.03906 C 61.03109,419.69489 62,417.91667 62,416 62,414.37594 61.372824,413.08253 60.357422,412.24023 59.34202,411.39794 57.973784,411 56.5,411 H 56 v -0.5 A 0.50005,0.50005 0 0 0 55.5,410 Z m 0.5,1 h 2 v 2 h -2 z m -4,10 h 2 v 2 h -2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 53.5,431 a 1.50015,1.50015 0 1 0 0,3 H 55 c 1.249468,0.006 2.332699,0.37671 3.013672,0.94141 0.682107,0.56564 1.059323,1.26298 0.988281,2.4707 -0.09036,1.53611 -0.972327,2.5432 -2.498047,3.35351 -1.525719,0.81032 -3.632465,1.22991 -5.447265,1.23438 H 49.5 a 1.50015,1.50015 0 1 0 0,3 h 1.5625 0.002 c 2.24072,-0.006 4.728077,-0.46126 6.845703,-1.58594 2.117627,-1.12468 3.928252,-3.11228 4.087891,-5.82617 0.120132,-2.04228 -0.719411,-3.83841 -2.068359,-4.95703 -1.348949,-1.11862 -3.108979,-1.6232 -4.923829,-1.63086 h -0.002 z"
+ id="path8588-0"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="display:inline;opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ id="rect5217-4-0"
+ width="16"
+ height="16"
+ x="110"
+ y="430"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12761"
+ transform="translate(71.999998,4.4999696e-6)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 51.5,515 a 0.50005,0.50005 0 0 0 -0.353516,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 48,518.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.353516,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 62,525.5 v -10 A 0.50005,0.50005 0 0 0 61.5,515 Z m 0.207031,1 H 61 v 9.29297 L 58.292969,528 H 49 v -9.29297 z M 52,519 v 2 h 2 v -2 z m 2,2 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 0,2 v 2 h 2 v -2 z m 0,2 h -2 v 2 h 2 z m -2,0 v -2 h -2 v 2 z m -2,0 h -2 v 2 h 2 z m 0,-2 v -2 h -2 v 2 z"
+ transform="translate(-71.999998,-4.4999696e-6)"
+ id="path12740"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12793"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 92.496094,325.99414 a 0.50005,0.50005 0 0 0 -0.382813,0.82227 l 4.5,5.5 a 0.50005,0.50005 0 0 0 0.773438,0 l 4.500001,-5.5 a 0.50005,0.50005 0 1 0 -0.77344,-0.63282 L 97,331.21094 92.886719,326.18359 a 0.50005,0.50005 0 0 0 -0.390625,-0.18945 z"
+ id="path10173-4"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 91.25,334 c -0.683851,0 -1.25,0.56615 -1.25,1.25 v 3.5 c 0,0.68385 0.566149,1.25 1.25,1.25 h 3.5 c 0.683851,0 1.25,-0.56615 1.25,-1.25 v -3.5 C 96,334.56615 95.433851,334 94.75,334 Z m 8,0 c -0.683851,0 -1.25,0.56615 -1.25,1.25 v 3.5 c 0,0.68385 0.566149,1.25 1.25,1.25 h 3.5 c 0.68385,0 1.25,-0.56615 1.25,-1.25 v -3.5 c 0,-0.68385 -0.56615,-1.25 -1.25,-1.25 z m -7.75,4 h 2 1 a 0.50005,0.50005 0 1 1 0,1 h -1 -2 a 0.50005,0.50005 0 1 1 0,-1 z m 8,0 h 2 1 a 0.50005,0.50005 0 1 1 0,1 h -1 -2 a 0.50005,0.50005 0 1 1 0,-1 z"
+ id="rect13911"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g12836"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ transform="translate(-123,458.99979)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 540.5,263 c -2.47936,0 -4.5,2.02064 -4.5,4.5 0,2.47936 2.02064,4.5 4.5,4.5 2.47936,0 4.5,-2.02064 4.5,-4.5 0,-2.47936 -2.02064,-4.5 -4.5,-4.5 z m 0,1 c 1.93892,0 3.5,1.56108 3.5,3.5 0,1.40621 -0.82672,2.60476 -2.01758,3.16211 -0.16784,-2.48561 -2.15892,-4.47669 -4.64453,-4.64453 C 537.89524,264.82672 539.09379,264 540.5,264 Z"
+ transform="translate(123,-458.99979)"
+ id="path12830"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 657.50195,-192.93359 a 0.50004997,0.50004997 0 0 0 -0.22656,0.0508 c -2.27231,1.07327 -3.57921,3.51034 -3.21484,5.99609 0.36436,2.48575 2.31598,4.44563 4.80078,4.82227 2.48479,0.37663 4.92837,-0.91763 6.01367,-3.1836 a 0.50013262,0.50013262 0 1 0 -0.90234,-0.43164 c -0.89704,1.8729 -2.90867,2.93833 -4.96289,2.62696 -2.05422,-0.31138 -3.6598,-1.92406 -3.96094,-3.97852 -0.30115,-2.05446 0.77387,-4.06001 2.65234,-4.94727 a 0.50004997,0.50004997 0 0 0 -0.19922,-0.95507 z"
+ id="path12834"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12981"
+ transform="translate(-1.8536743e-6,-20.999995)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 226.5,206.99414 a 0.50004997,0.50004997 0 0 0 -0.34766,0.85938 L 228.29883,210 h -10.5918 l 2.14649,-2.14648 a 0.50004997,0.50004997 0 1 0 -0.70704,-0.70704 l -2.95703,2.95704 a 0.50004997,0.50004997 0 0 0 -0.002,0.79296 0.50004997,0.50004997 0 0 0 0.008,0.006 l 2.95117,2.95118 a 0.50004997,0.50004997 0 1 0 0.70704,-0.70704 L 217.70703,211 h 10.5918 l -2.14649,2.14648 a 0.50004997,0.50004997 0 1 0 0.70704,0.70704 l 2.96484,-2.9668 a 0.50004997,0.50004997 0 0 0 0.0195,-0.0156 l 0.0156,-0.0176 a 0.50004997,0.50004997 0 0 0 0.0234,-0.68164 0.50004997,0.50004997 0 0 0 -0.0234,-0.0254 0.50004997,0.50004997 0 0 0 -0.01,-0.01 l -2.99023,-2.99024 A 0.50004997,0.50004997 0 0 0 226.5,206.99414 Z"
+ id="path12879"
+ inkscape:connector-curvature="0" />
+ <path
+ id="circle12970"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="m 224.00001,202.49817 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z m 5,0 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z m -10,0 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 94.513672,32 a 0.50005,0.50005 0 0 0 -0.417969,0.203125 c -2.416051,3.180716 -3.444751,6.003207 -3.857422,8.287109 -0.412671,2.283903 -0.216543,4.049887 -0.21875,5.00586 a 0.50005,0.50005 0 1 0 1,0.0039 c 0.0025,-1.084327 -0.183742,-2.690936 0.203125,-4.832031 0.386868,-2.141095 1.341004,-4.795942 3.667969,-7.859375 A 0.50005,0.50005 0 0 0 94.513672,32 Z m 4.955078,3.001953 a 0.50005,0.50005 0 0 0 -0.304688,0.126953 c -4.123582,3.585034 -5.171874,7.536346 -5.171874,10.376953 a 0.50005,0.50005 0 1 0 1,0 c 0,-2.600212 0.913619,-6.219783 4.828124,-9.623047 A 0.50005,0.50005 0 0 0 99.46875,35.001953 Z m 4.02539,5.003906 c -3.01703,-0.0065 -5.494281,2.470749 -5.501952,5.498047 a 0.50005,0.50005 0 1 0 1,0.0039 c 0.0063,-2.484383 2.030992,-4.507263 4.500002,-4.501953 a 0.50005,0.50005 0 1 0 0.002,-1 z"
+ id="path18476-0-2"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g7347"
+ transform="translate(921.00001,-553)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <rect
+ transform="scale(-1,1)"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
+ id="rect7240"
+ width="16"
+ height="16"
+ x="396"
+ y="731" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -408.50391,736.99414 a 0.50005,0.50005 0 0 0 -0.43554,0.26563 c -1.5311,2.80698 -2.01417,5.0457 -2.02149,8.22461 a 0.50005,0.50005 0 1 0 1,0.004 c 0.007,-3.0834 0.43147,-5.05503 1.90039,-7.74805 a 0.50005,0.50005 0 0 0 -0.44336,-0.74609 z m 6.99805,2 a 0.50005,0.50005 0 0 0 -0.37891,0.18555 C -403.15877,740.70849 -404,742.16634 -404,745.5 a 0.50005,0.50005 0 1 0 1,0 c 0,-3.18014 0.65877,-4.20849 1.88477,-5.67969 a 0.50005,0.50005 0 0 0 -0.39063,-0.82617 z"
+ id="path7245"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -407.5,732 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 7,2 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path7250"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccc" />
+ </g>
+ <g
+ id="g6932"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 543.50781,181.99023 a 1.50015,1.50015 0 0 0 -0.67773,0.16797 c -3.41741,1.7087 -5.83009,5.05846 -5.83008,9.3418 a 1.50015,1.50015 0 1 0 3,0 c -10e-6,-3.21666 1.58731,-5.3669 4.16992,-6.6582 a 1.50015,1.50015 0 0 0 -0.66211,-2.85157 z"
+ id="path7270"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 536.49609,179.00195 a 0.50005,0.50005 0 0 0 -0.35351,0.12891 c -4.08383,3.59037 -5.14329,7.80863 -5.13086,13.36328 a 0.50005,0.50005 0 1 0 1,-0.002 c -0.0122,-5.43221 0.92902,-9.21403 4.79101,-12.60938 a 0.50005,0.50005 0 0 0 -0.30664,-0.88086 z"
+ id="path7282"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ transform="translate(919,-532)"
+ id="g6686"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <rect
+ transform="scale(-1,1)"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
+ id="rect6673"
+ width="16"
+ height="16"
+ x="415"
+ y="710" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -416.49609,713.99609 a 0.50005,0.50005 0 0 0 -0.31055,0.10938 c -0.21339,0.16596 -0.41872,0.33348 -0.61524,0.50195 -4.0339,3.45843 -4.51787,6.50897 -4.57812,9.88281 a 0.50009544,0.50009544 0 1 0 1,0.0195 c 0.059,-3.3038 0.37586,-5.83955 4.22852,-9.14258 0.1842,-0.15793 0.37703,-0.31626 0.57812,-0.47266 a 0.50005,0.50005 0 0 0 -0.30273,-0.89844 z"
+ id="path6675"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6688"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -427.5,716 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -2,5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 5,-10 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccc" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 265.00049,180.00029 c -0.56524,0 -1.07102,0.24537 -1.44727,0.61718 -0.37625,0.37181 -0.64955,0.85716 -0.88086,1.40821 -0.46263,1.10209 -0.75684,2.49042 -1.08008,3.85937 -0.32324,1.36896 -0.67626,2.7158 -1.17383,3.66406 -0.49757,0.94827 -1.04163,1.45118 -1.91211,1.45118 a 0.50005,0.50005 0 1 0 0,1 c 1.29399,0 2.21222,-0.8721 2.79688,-1.98633 0.58466,-1.11424 0.93562,-2.51739 1.26172,-3.89844 0.32609,-1.38105 0.62614,-2.74272 1.0293,-3.70312 0.20157,-0.48021 0.4296,-0.85424 0.6621,-1.08399 0.2325,-0.22975 0.4436,-0.32812 0.74415,-0.32812 0.30054,0 0.51164,0.0984 0.74414,0.32812 0.23249,0.22975 0.46053,0.60378 0.66211,1.08399 0.40315,0.9604 0.7032,2.32207 1.02929,3.70312 0.3261,1.38105 0.67511,2.7842 1.25977,3.89844 0.58466,1.11423 1.50289,1.98633 2.79687,1.98633 a 0.50005,0.50005 0 1 0 0,-1 c -0.87047,0 -1.41258,-0.50291 -1.91015,-1.45118 -0.49757,-0.94826 -0.85059,-2.2951 -1.17383,-3.66406 -0.32324,-1.36895 -0.61745,-2.75728 -1.08008,-3.85937 -0.23131,-0.55105 -0.50461,-1.0364 -0.88086,-1.40821 -0.37625,-0.37181 -0.88203,-0.61718 -1.44726,-0.61718 z"
+ id="path10124-9"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10162-3"
+ d="m 349.01758,181.25 a 0.50005,0.50005 0 0 0 -0.41992,0.20312 l -6.48243,8.7461 a 0.50005,0.50005 0 1 0 0.80274,0.5957 L 349,182.58984 l 6.07031,8.20313 a 0.50005,0.50005 0 1 0 0.80469,-0.59375 l -6.47266,-8.7461 A 0.50005,0.50005 0 0 0 349.01758,181.25 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
+ id="rect18819-6"
+ width="16"
+ height="16"
+ x="320"
+ y="178"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ <g
+ style="display:inline;fill:#ffffff;stroke-width:1.03551209;enable-background:new"
+ id="g10170-0"
+ transform="matrix(0.93036376,0,0,1.0023904,257.63778,150.90833)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.03551209;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 23.460938,40.029297 A 0.51780782,0.51780782 0 0 1 22.96875,39.486328 L 23,38.607422 v -0.0039 c 0.0063,-2.697355 1.432558,-5.191614 3.748047,-6.542969 2.32064,-1.354362 5.185219,-1.354362 7.505859,0 2.32064,1.354362 3.748047,3.85629 3.748047,6.560547 v 0.882812 a 0.51780782,0.51780782 0 1 1 -1.035156,0 V 38.6211 c 0,-2.339918 -1.23548,-4.49829 -3.236328,-5.666016 -2.000849,-1.167726 -4.460089,-1.167727 -6.460938,0 -2.000848,1.167726 -3.234375,3.326098 -3.234375,5.666016 a 0.51780782,0.51780782 0 0 1 -0.002,0.01758 l -0.0293,0.882812 a 0.51780782,0.51780782 0 0 1 -0.542968,0.507813 z"
+ id="path10174-7"
+ inkscape:connector-curvature="0" />
+ </g>
+ <rect
+ y="178"
+ x="299"
+ height="16"
+ width="16"
+ id="rect4967"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 307,180 c -1.24829,0 -2.24461,0.83463 -3,1.93555 -0.75539,1.10091 -1.32403,2.51399 -1.76367,3.91601 -0.87928,2.80405 -1.23047,5.58594 -1.23047,5.58594 a 0.50013931,0.50013931 0 1 0 0.99219,0.12695 c 0,0 0.34791,-2.71791 1.19336,-5.41406 0.42272,-1.34808 0.97296,-2.68677 1.63281,-3.64844 C 305.48407,181.54029 306.19904,181 307,181 c 0.80095,0 1.51593,0.54029 2.17578,1.50195 0.65985,0.96167 1.21009,2.30036 1.63281,3.64844 0.84545,2.69615 1.19336,5.41406 1.19336,5.41406 a 0.50013931,0.50013931 0 1 0 0.99219,-0.12695 c 0,0 -0.35119,-2.78189 -1.23047,-5.58594 -0.43964,-1.40202 -1.00828,-2.8151 -1.76367,-3.91601 C 309.24461,180.83464 308.24829,180 307,180 Z"
+ id="path13261"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 327.48047,181 a 0.50005,0.50005 0 0 0 -0.46875,0.39453 c -0.73399,3.42527 -2.46804,7.48775 -5.67969,8.63477 a 0.50005,0.50005 0 1 0 0.33594,0.9414 c 3.19373,-1.14062 4.90029,-4.45895 5.83203,-7.61914 0.93174,3.16019 2.6383,6.47852 5.83203,7.61914 a 0.50005,0.50005 0 1 0 0.33594,-0.9414 c -3.21165,-1.14702 -4.9457,-5.2095 -5.67969,-8.63477 A 0.50005,0.50005 0 0 0 327.48047,181 Z"
+ id="path10168-6-7"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="matrix(-1,0,0,1,401.98389,150.99638)"
+ id="g13323"
+ style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="path13321"
+ d="M 9.96875,29.048828 C 9.4658605,28.864829 8.9025328,28.986924 8.5410156,29.310547 8.1794984,29.63417 7.9598217,30.084792 7.7695312,30.613281 7.3889504,31.670259 7.1601578,33.086794 6.90625,34.523438 c -0.2539078,1.436643 -0.5324149,2.889409 -0.9414062,3.929687 -0.2044957,0.520139 -0.4424423,0.932648 -0.6894532,1.1875 -0.2470108,0.254852 -0.473033,0.363281 -0.7851562,0.363281 a 0.50005,0.50005 0 1 0 0,1 c 0.5904168,0 1.1159371,-0.267683 1.5039062,-0.667968 0.3879692,-0.400286 0.6690516,-0.922242 0.9023438,-1.515626 0.4665844,-1.186767 0.7390333,-2.679616 0.9941406,-4.123046 0.2551073,-1.443431 0.4935421,-2.842034 0.8183594,-3.744141 0.1624086,-0.451054 0.3541704,-0.76594 0.5,-0.896484 0.1458295,-0.130544 0.1865427,-0.15232 0.4160156,-0.06836 0.057045,0.02087 0.1634141,0.101911 0.2832031,0.296875 0.1197889,0.194965 0.2422649,0.485737 0.3515629,0.826172 0.218596,0.680871 0.393488,1.55941 0.582031,2.373047 0.188543,0.813637 0.358157,1.549689 0.740234,2.082031 0.191039,0.266171 0.511622,0.515788 0.900391,0.50586 0.388769,-0.0099 0.704011,-0.230804 1.001953,-0.542969 0.337514,-0.353626 0.595779,-0.497442 0.722656,-0.529297 0.126878,-0.03186 0.138013,-0.02504 0.242188,0.06836 0.20835,0.186805 0.512485,0.892009 0.740234,1.732422 0.227749,0.840413 0.429042,1.804722 0.716797,2.601563 0.143877,0.39842 0.30542,0.75895 0.542969,1.05664 0.237548,0.297691 0.601614,0.544922 1.027343,0.544922 a 0.50005,0.50005 0 1 0 0,-1 c -0.0724,0 -0.124723,-0.01782 -0.246093,-0.169922 -0.12137,-0.152098 -0.260285,-0.426776 -0.384766,-0.771484 -0.248961,-0.689415 -0.452791,-1.642926 -0.691406,-2.523438 -0.238616,-0.880511 -0.460258,-1.699598 -1.037109,-2.216796 -0.288426,-0.2586 -0.735893,-0.398016 -1.154297,-0.292969 -0.418405,0.105047 -0.794027,0.38192 -1.203125,0.810547 -0.205362,0.215165 -0.318948,0.232836 -0.302735,0.232422 0.01621,-4.14e-4 0.02252,0.02861 -0.0625,-0.08984 C 12.22449,34.745505 11.999507,34.047965 11.816406,33.257812 11.633305,32.46766 11.457527,31.57275 11.210938,30.804688 11.087643,30.420656 10.949285,30.066996 10.761719,29.761719 10.574152,29.456442 10.328076,29.1803 9.96875,29.048828 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g5270-3"
+ transform="translate(497.99495,-311.99288)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ id="path5169-5"
+ style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ d="m -115,532 h 16.005051 v 16 H -115 Z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <g
+ transform="translate(-1)"
+ id="g5191-5"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 386.48633,221 c -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 1 6.55664 C 384.86022,229.298 384,230.30731 384,231.50781 c 0,1.372 1.12214,2.49414 2.49414,2.49414 1.372,0 2.49414,-1.12214 2.49414,-2.49414 0,-1.20116 -0.8593,-2.21054 -1.99414,-2.44336 v -6.55664 -1 c 0.004,-0.28226 -0.22555,-0.51223 -0.50781,-0.50781 z m 1.00781,1.00781 v 3 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -1,8.00586 c 0.83156,0 1.49414,0.66258 1.49414,1.49414 0,0.83156 -0.66258,1.49414 -1.49414,1.49414 -0.83156,0 -1.49414,-0.66258 -1.49414,-1.49414 0,-0.83156 0.66258,-1.49414 1.49414,-1.49414 z"
+ transform="translate(-496.99495,311.99288)"
+ id="path5112-6"
+ inkscape:connector-curvature="0" />
</g>
- <g id="g8338-5" transform="rotate(90,593.00354,462.0038)" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 746.49219,-91.007812 A 0.50005,0.50005 0 0 0 746,-90.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 0,5 A 0.50005,0.50005 0 0 0 746,-85.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 0,5 A 0.50005,0.50005 0 0 0 746,-80.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z" id="path8336-9" inkscape:connector-curvature="0"/>
+ <g
+ transform="translate(-2.9999978)"
+ style="display:inline;opacity:0.7;fill:#ffffff;enable-background:new"
+ id="g5186-5-5-7">
+ <path
+ id="path5179-0-9-1"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -97.896484,538.39648 -1.707032,1.70704 0.75,0.75 c 0.195265,0.19518 0.511767,0.19518 0.707032,0 l 0.52539,-0.5254 0.47461,-0.4746 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 z m -0.614086,-1.39969 a 0.50005,0.50005 0 0 0 -0.34376,0.15039 l -4.4121,4.41015 c -0.38435,-0.27257 -0.83195,-0.45926 -1.31446,-0.52734 a 0.50005,0.50005 0 0 0 -0.0996,-0.006 0.50005,0.50005 0 0 0 -0.041,0.99609 c 0.71727,0.10121 1.32147,0.58072 1.58398,1.25586 0.26252,0.67514 0.14019,1.43694 -0.32031,1.9961 -0.46051,0.55917 -1.18354,0.82547 -1.89649,0.69726 a 0.50014796,0.50014796 0 1 0 -0.17773,0.98438 c 1.06733,0.19194 2.15825,-0.20977 2.84766,-1.04688 0.6894,-0.83711 0.87347,-1.98341 0.48047,-2.99414 -0.0911,-0.23424 -0.21129,-0.45079 -0.35352,-0.65039 l 4.41016,-4.4082 a 0.50005,0.50005 0 0 0 -0.36328,-0.85742 z"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g4847-8" transform="translate(-230.99288,-230.99288)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g transform="translate(126)" style="opacity:0.6;fill:#ffffff" id="g4287-2">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 156.5,158 c -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 0.75 h 1 v -0.75 C 157.01223,158.22555 156.78226,157.99558 156.5,158 Z m 7,0 c -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 2.4961 L 160.00195,161 160,162 l 3.00781,0.004 v 6.0039 h -6.0039 L 157,165 l -1,0.002 0.004,3.00586 h -2.4961 c -0.67616,-0.01 -0.67616,1.00957 0,1 h 2.4961 l 0.004,2.5 c -0.01,0.67616 1.00957,0.67616 1,0 l -0.004,-2.5 h 6.0039 v 2.5 c -0.01,0.67616 1.00957,0.67616 1,0 v -2.5 h 2.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -2.5 v -6.0039 l 2.5,0.004 c 0.67616,0.01 0.67616,-1.00956 0,-1 l -2.5,-0.004 v -2.4961 C 164.0119,158.22555 163.78226,157.99558 163.5,158 Z m -9.99414,3 c -0.6733,-0.0135 -0.6832,1 -0.01,1 l 0.75782,0.008 0.008,-1 z" transform="translate(104.99288,230.99288)" id="path4273-3" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g7388-6"
+ transform="translate(731,-238)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <rect
+ transform="scale(-1,1)"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
+ id="rect7384-9"
+ width="16"
+ height="16"
+ x="437"
+ y="710" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -447.96289,710.98828 a 1.0001,1.0001 0 0 0 -0.83789,0.41211 c -3.30626,4.40835 -3.18183,10.96743 -3.18555,12.58399 a 1.0001,1.0001 0 1 0 2,0.006 c 0.004,-1.64212 0.0934,-7.79897 2.78711,-11.39062 a 1.0001,1.0001 0 0 0 -0.76367,-1.61133 z m 4.97461,3.00195 a 1.0001,1.0001 0 0 0 -0.69727,0.28125 c -2.25424,2.12239 -3.3739,3.98924 -3.89062,5.64258 C -448.0929,721.56741 -448,722.96385 -448,724 a 1.0001,1.0001 0 1 0 2,0 c 0,-1.13631 -0.0696,-2.20308 0.33203,-3.48828 0.40167,-1.28521 1.28135,-2.83224 3.35352,-4.7832 a 1.0001,1.0001 0 0 0 -0.67383,-1.73829 z m 3.94531,4.00782 a 1.0001,1.0001 0 0 0 -0.16797,0.0234 C -441.66808,718.54973 -444,720.82862 -444,724 a 1.0001,1.0001 0 1 0 2,0 c 0,-2.17354 1.66808,-3.68979 3.21094,-4.02148 a 1.0001,1.0001 0 0 0 -0.25391,-1.98047 z"
+ id="path7133-7"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ id="path13682"
+ d="m 100.45117,431 c -0.36065,0.005 -0.725199,0.0666 -1.080078,0.1875 -1.419514,0.48381 -2.371094,1.8128 -2.371094,3.3125 a 0.50005006,0.50005006 0 1 1 -1,0 c 0,-0.53249 0.102694,-1.04562 0.277344,-1.52734 -0.0921,0.0103 -0.173784,0.0274 -0.277344,0.0273 -3.307786,0 -6,2.69221 -6,6 0,3.30779 2.692214,6 6,6 3.307786,0 6.000002,-2.69221 6.000002,-6 v -0.002 c -4.7e-4,-0.11093 0.014,-0.19694 0.0332,-0.27344 -0.83987,0.3046 -1.77022,0.36483 -2.67578,0.12695 a 0.50005006,0.50005006 0 1 1 0.253906,-0.96679 c 1.450494,0.38101 2.978064,-0.20116 3.806644,-1.45118 0.82858,-1.25001 0.7694,-2.88277 -0.14649,-4.07031 -0.68691,-0.89068 -1.73836,-1.37897 -2.82031,-1.36328 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14534">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 100.24805,410.01367 c -1.271268,0.11136 -2.328782,0.98616 -2.845706,2.17774 -2.575841,-0.61979 -5.266939,0.50372 -6.597656,2.80859 -1.356612,2.34971 -0.965414,5.32365 0.953124,7.24219 1.918537,1.91853 4.892473,2.30974 7.242188,0.95312 2.30486,-1.33072 3.42838,-4.02182 2.80859,-6.59765 1.3618,-0.59077 2.3103,-1.88718 2.17774,-3.40235 -0.14775,-1.68875 -1.49289,-3.03389 -3.18164,-3.18164 -0.1894,-0.0166 -0.37503,-0.0159 -0.55664,0 z m 0.0234,0.9961 c 0.14685,-0.0133 0.29578,-0.0133 0.44727,0 1.21193,0.10603 2.16545,1.05955 2.27148,2.27148 0.10604,1.21192 -0.66865,2.31795 -1.84375,2.63281 a 0.50005006,0.50005006 0 0 0 -0.35937,0.58203 l 0.0352,0.17969 a 0.50005006,0.50005006 0 0 0 0.008,0.0293 c 0.58634,2.18824 -0.36816,4.49227 -2.33008,5.625 -1.961931,1.13272 -4.433244,0.80698 -6.035156,-0.79492 -1.601912,-1.60191 -1.927645,-4.07323 -0.794922,-6.03516 1.132722,-1.96193 3.43675,-2.91642 5.625,-2.33008 a 0.50005006,0.50005006 0 0 0 0.0293,0.008 l 0.179687,0.0352 a 0.50005006,0.50005006 0 0 0 0.582032,-0.35937 c 0.275511,-1.02822 1.157648,-1.75045 2.185539,-1.84375 z M 94.5,416 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 A 0.50005,0.50005 0 0 0 97.5,416 Z m 0.5,1 h 2 v 2 h -2 z"
+ transform="translate(1.8536743e-6,-4.4999696e-6)"
+ id="circle13742"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14020"
+ transform="translate(153.00001,38.000005)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -76.5,394 -3.751953,0.006 c -0.228491,0.001 -0.427071,0.15722 -0.482422,0.37891 l -1.25,4.99414 c -0.07853,0.31517 0.159565,0.6204 0.484375,0.62095 h 3.75 c 0.22922,-3.6e-4 0.428845,-0.15652 0.484375,-0.37891 l 1.25,-5 C -75.936984,394.30587 -76.175116,394.00052 -76.5,394 Z m 6,0 -3.751953,0.006 c -0.228491,0.001 -0.427071,0.15722 -0.482422,0.37891 l -1.25,4.99414 c -0.07853,0.31517 0.159565,0.6204 0.484375,0.62095 h 3.75 c 0.22922,-3.6e-4 0.428845,-0.15652 0.484375,-0.37891 l 1.25,-5 C -69.936984,394.30587 -70.175116,394.00052 -70.5,394 Z m -8,7 -3.751953,0.006 c -0.228491,0.001 -0.427071,0.15722 -0.482422,0.37891 l -1.25,4.99414 c -0.07853,0.31517 0.159565,0.6204 0.484375,0.62095 h 3.75 c 0.22922,-3.6e-4 0.428845,-0.15652 0.484375,-0.37891 l 1.25,-5 C -77.936984,401.30587 -78.175116,401.00052 -78.5,401 Z m 6,0 -3.751953,0.006 c -0.228491,0.001 -0.427071,0.15722 -0.482422,0.37891 l -1.25,4.99414 c -0.07853,0.31517 0.159565,0.6204 0.484375,0.62095 h 3.75 c 0.22922,-3.6e-4 0.428845,-0.15652 0.484375,-0.37891 l 1.25,-5 C -71.936984,401.30587 -72.175116,401.00052 -72.5,401 Z"
+ id="path13999"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 11.455078,430.98242 a 1.50015,1.50015 0 0 0 -1.4765624,1.52149 v 6.3789 l -3.5605468,3.56055 a 1.50015,1.50015 0 1 0 2.1210937,2.12109 l 3.5605465,-3.56054 h 6.378907 a 1.50015,1.50015 0 1 0 0,-3 h -5.5 v -5.5 a 1.50015,1.50015 0 0 0 -1.523438,-1.52149 z"
+ id="path12350-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 199.50586,431 c -0.31034,2.7e-4 -0.5455,0.28021 -0.49219,0.58594 0.36378,2.06995 0.21088,3.24033 -0.13086,3.98828 -0.34174,0.74794 -0.89741,1.14621 -1.5625,1.65234 -0.66509,0.50614 -1.42742,1.12518 -1.87304,2.24414 -0.44562,1.11896 -0.57595,2.68203 -0.19141,5.10742 0.0385,0.24306 0.24806,0.422 0.49414,0.42188 h 8.75586 c 0.30739,1.4e-4 0.54213,-0.27449 0.49414,-0.57812 -0.36857,-2.32471 -0.21903,-3.70089 0.13086,-4.58204 0.34989,-0.88114 0.89751,-1.32255 1.54492,-1.8164 0.64741,-0.49385 1.4068,-1.03318 1.86328,-2.03516 0.45648,-1.00198 0.58623,-2.39428 0.20313,-4.57422 C 208.70043,431.17484 208.49284,431.0002 208.25,431 Z"
+ id="path8644-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccscccccssccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 96.5,473 c -2.087116,0 -3.478164,1.04607 -4.390625,2.1875 a 0.50024408,0.50024408 0 0 0 0.78125,0.625 C 93.690488,474.81193 94.734388,474 96.5,474 c 2.098393,0 3.134109,0.87695 3.75195,1.94531 C 100.8698,477.01367 101,478.31651 101,479 h -5.25 c -1.273438,0 -2.443243,0.36418 -3.314453,1.05469 -0.87121,0.69051 -1.427734,1.72791 -1.427735,2.94531 10e-7,1.2174 0.556525,2.2548 1.427735,2.94531 C 93.306757,486.63582 94.476562,487 95.75,487 h 0.75 c 1.755585,0 3.387714,-0.96684 4.53711,-2.0332 0.0781,0.53303 0.28951,1.00434 0.64062,1.35547 C 102.12862,486.77315 102.775,487 103.5,487 a 0.50005,0.50005 0 1 0 0,-1 c -0.525,0 -0.87862,-0.14815 -1.11523,-0.38477 C 102.14815,485.37862 102,485.025 102,484.5 V 479 c 0,-0.79721 -0.12242,-2.24322 -0.88086,-3.55469 C 100.3607,474.13385 98.896459,473 96.5,473 Z m -0.75,7 H 101 v 3.56055 C 100.04582,484.68473 98.18875,486 96.5,486 h -0.75 c -1.081007,0 -2.03187,-0.31555 -2.693359,-0.83984 -0.66149,-0.52429 -1.048828,-1.23676 -1.048829,-2.16016 10e-7,-0.9234 0.387339,-1.63587 1.048829,-2.16016 C 93.718131,480.31555 94.668993,480 95.75,480 Z"
+ id="path10278-2"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g12310-0"
+ transform="translate(62.999998,210)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 222,431 c -0.1326,2e-5 -0.25976,0.0527 -0.35352,0.14648 L 218.79297,434 H 216.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 7 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2.29297 l 2.85351,2.85352 c 0.0938,0.0938 0.22092,0.14646 0.35352,0.14648 h 0.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 431.78125 431.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 6.4668,2.01562 a 0.50005,0.50005 0 0 0 -0.42188,0.72071 c 1.27607,2.70648 1.27328,5.84072 -0.008,8.54492 a 0.50017783,0.50017783 0 1 0 0.9043,0.42773 c 1.40867,-2.97397 1.41099,-6.42391 0.008,-9.40039 a 0.50005,0.50005 0 0 0 -0.48242,-0.29297 z m -2.86133,0.9375 a 0.50005,0.50005 0 0 0 -0.43359,0.74219 c 1.10286,2.06013 1.1045,4.5334 0.006,6.59571 a 0.50023236,0.50023236 0 1 0 0.88282,0.4707 c 1.25518,-2.35583 1.25221,-5.18378 -0.008,-7.53711 a 0.50005,0.50005 0 0 0 -0.44726,-0.27149 z"
+ transform="translate(-62.999998,-210)"
+ id="path12304-9"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g5260"
+ transform="translate(21,42)"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="path13014"
+ d="m 176.5,410 a 0.50005,0.50005 0 1 0 0,1 h 0.79297 L 178,411.70703 v 10.58594 L 177.29297,423 H 176.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 0.64648,-0.64649 0.64648,0.64649 A 0.50005,0.50005 0 0 0 179.5,424 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -0.79297 L 179,422.29297 V 411.70703 L 179.70703,411 H 180.5 a 0.50005,0.50005 0 1 0 0,-1 h -1 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -0.64648,0.64649 -0.64648,-0.64649 A 0.50005,0.50005 0 0 0 177.5,410 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path13066"
+ d="m 174.5,414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2.5 v -1 h -2 v -4 h 2 v -1 z m 5.5,0 v 1 h 7.00781 v 4 H 180 v 1 h 7.50781 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13176"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 14,472 c -0.486111,0 -0.97894,0.16032 -1.363281,0.50195 C 12.252378,472.84359 12,473.375 12,474 v 4 H 8.5 c -0.2761309,3e-5 -0.4999724,0.22387 -0.5,0.5 v 4 c 0,0.33333 -0.182083,0.72505 -0.4785156,1.02148 C 7.2250518,483.81792 6.8333333,484 6.5,484 c -0.2761309,3e-5 -0.4999724,0.22387 -0.5,0.5 v 2 c 2.76e-5,0.27613 0.2238691,0.49997 0.5,0.5 h 3 c 0.1325988,-2e-5 0.259759,-0.0527 0.3535156,-0.14648 L 11,485.70703 V 486.5 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 5 c 1.777778,0 3.5,-1.46429 3.5,-3.5 v -5 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 H 16 v -4 c 0,-0.625 -0.252378,-1.15641 -0.636719,-1.49805 C 14.97894,472.16032 14.486111,472 14,472 Z m 0,1 c 0.263889,0 0.52106,0.0897 0.699219,0.24805 C 14.877378,473.40641 15,473.625 15,474 v 4 h -0.5 c -0.676161,-0.01 -0.676161,1.00956 0,1 H 19 v 1 H 9 v -1 h 3.5 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 V 474 c 0,-0.375 0.122622,-0.59359 0.300781,-0.75195 C 13.47894,473.08968 13.736111,473 14,473 Z m -5,8 h 10 v 2.5 c 0,1.46429 -1.277778,2.5 -2.5,2.5 H 16 v -1.5 c 0.0044,-0.28227 -0.225547,-0.51223 -0.507812,-0.50781 C 15.216044,483.9965 14.995681,484.22386 15,484.5 v 1.5 h -3 v -1.5 c -1.7e-4,-0.44532 -0.538517,-0.6683 -0.853516,-0.35352 L 9.2929688,486 H 7 v -1.22266 C 7.4441801,484.6575 7.9061001,484.55093 8.2285156,484.22852 8.682083,483.77495 9,483.16667 9,482.5 Z"
+ transform="translate(1.8536743e-6,-4.4999696e-6)"
+ id="path5504-6"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="scsccccccccccccccsccccscsscscccccccccscsccssccccccccccccsc" />
+ </g>
+ <g
+ transform="translate(-664,-513.00021)"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
+ id="g8745-3"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 475.25,53 a 0.50005,0.50005 0 0 0 -0.21289,0.04687 l -5.75391,2.708984 a 0.50005,0.50005 0 0 0 -0.28515,0.453125 v 7.292969 a 0.50005,0.50005 0 0 0 0.27539,0.447266 l 6.00195,3.001953 a 0.50005,0.50005 0 0 0 0.44727,0 l 6.00195,-3.001953 A 0.50005,0.50005 0 0 0 482,63.501953 v -6.916015 a 0.50005,0.50005 0 0 0 0,-0.181641 v -0.195313 a 0.50005,0.50005 0 0 0 -0.28711,-0.453125 l -5.75,-2.707031 A 0.50005,0.50005 0 0 0 475.75,53 Z m 0.11133,1 h 0.27734 l 5.00977,2.359375 -5.14844,2.509766 -5.14844,-2.509766 z M 469.99805,57.298828 475,59.738281 v 5.957031 l -5.00195,-2.501953 z M 481,57.300781 v 5.892578 l -5,2.5 v -5.955078 z"
+ transform="translate(664,513.00021)"
+ id="path8739-6"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-801.00006,344.99979)"
+ id="g13204"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1339.5,-270 a 0.50004994,0.50004994 0 1 0 0,1 h 6 a 0.50004994,0.50004994 0 1 0 0,-1 z m 0,3 a 0.50004994,0.50004994 0 1 0 0,1 h 6 a 0.50004994,0.50004994 0 1 0 0,-1 z m 0,3 a 0.50004994,0.50004994 0 1 0 0,1 h 6 a 0.50004994,0.50004994 0 1 0 0,-1 z m -7,3 a 0.50004994,0.50004994 0 1 0 0,1 h 13 a 0.50004994,0.50004994 0 1 0 0,-1 z m -0.014,3 a 0.50004994,0.50004994 0 1 0 0,1 h 13.0449 a 0.50004994,0.50004994 0 1 0 0,-1 z"
+ id="path13198"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1332.4922,-263 c -0.2761,-0.004 -0.4965,-0.23166 -0.4922,-0.50781 v -5.08789 c 0,-0.86662 0.4883,-1.66406 1.2578,-2.08789 0.7696,-0.42387 1.709,-0.42387 2.4785,0 0.7695,0.42383 1.2559,1.22127 1.2559,2.08789 v 5.08789 c 0.01,0.67616 -1.0096,0.67616 -1,0 V -266 H 1333 v 2.49219 c 0,0.28226 -0.2255,0.51222 -0.5078,0.50781 z m 0.5078,-4 h 2.9922 v -1.5957 c 0,-0.49379 -0.2728,-0.95455 -0.7383,-1.21094 -0.4655,-0.25638 -1.0482,-0.25638 -1.5137,0 -0.4655,0.25639 -0.7402,0.71715 -0.7402,1.21094 z"
+ id="path13202"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccsccsc" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 114.49219,166.99219 A 0.50005,0.50005 0 0 0 114,167.5 v 1.5 h -2.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 1 0 1,0 V 170 h 2.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path4913-5-0"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ id="g10431-7"
+ transform="matrix(1,0,0,-1,52.999998,288.99725)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ <g
+ transform="translate(62.999998,189)"
+ id="g13463"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 221.5,410 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 218.29297,413 H 216.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 7 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.79297 l 2.85351,2.85352 A 0.50005,0.50005 0 0 0 221.5,424 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 410.78125 410.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 222 v 12 h -0.29297 l -2.85351,-2.85352 A 0.50005,0.50005 0 0 0 218.5,420 H 217 v -6 h 1.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 z m 6.75977,1.01562 a 0.50005,0.50005 0 0 0 -0.42188,0.72071 c 1.27607,2.70648 1.27328,5.84072 -0.008,8.54492 a 0.50017783,0.50017783 0 1 0 0.9043,0.42773 c 1.40867,-2.97397 1.41099,-6.42391 0.008,-9.40039 a 0.50005,0.50005 0 0 0 -0.48242,-0.29297 z m -2.86133,0.9375 a 0.50005,0.50005 0 0 0 -0.43359,0.74219 c 1.10286,2.06013 1.1045,4.5334 0.006,6.59571 a 0.50023236,0.50023236 0 1 0 0.88282,0.4707 c 1.25518,-2.35583 1.25221,-5.18378 -0.008,-7.53711 a 0.50005,0.50005 0 0 0 -0.44726,-0.27149 z"
+ transform="translate(-62.999998,-189)"
+ id="path13456"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-274.03132,440.00025)"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
+ id="g13513"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.75542808px;marker:none;enable-background:accumulate"
+ d="m 220.5,536 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9.64062 a 1.8365096,2.6222708 64.987834 0 0 -1.98242,0.0723 1.8365096,2.6222708 64.987834 0 0 -1.9707,2.68555 1.8365096,2.6222708 64.987834 0 0 2.93554,0.88867 1.8365096,2.6222708 64.987834 0 0 2.00977,-2.18945 A 0.50005,0.50005 0 0 0 221,547.5 V 547.47461 538 h 8 v 7.14062 a 1.8365125,2.6222911 64.988434 0 0 -1.98242,0.0723 1.8365125,2.6222911 64.988434 0 0 -1.9707,2.68555 1.8365125,2.6222911 64.988434 0 0 2.93554,0.88867 1.8365125,2.6222911 64.988434 0 0 2.00977,-2.18945 A 0.50005,0.50005 0 0 0 230,546.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ transform="translate(274.03132,-440.00025)"
+ id="ellipse13504"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ id="g12940-5"
+ style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 411.49219,577.94727 A 0.50005,0.50005 0 0 0 411,578.45508 v 7 a 0.50005,0.50005 0 1 0 1,0 v -7 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 408.47656,580 a 0.50005,0.50005 0 0 0 -0.22265,0.0684 c -2.54449,1.43695 -3.79437,4.38222 -3.03125,7.16797 0.76312,2.78575 3.34282,4.71875 6.27734,4.71875 2.93452,0 5.51422,-1.933 6.27734,-4.71875 0.76312,-2.78575 -0.48676,-5.73102 -3.03125,-7.16797 a 0.50025967,0.50025967 0 1 0 -0.49218,0.87109 c 2.15894,1.21922 3.20113,3.68764 2.55859,6.03321 -0.64254,2.34557 -2.81597,3.98242 -5.3125,3.98242 -2.49653,0 -4.66996,-1.63685 -5.3125,-3.98242 -0.64254,-2.34557 0.39965,-4.81399 2.55859,-6.03321 A 0.50005,0.50005 0 0 0 408.47656,580 Z"
+ transform="translate(1.8536743e-6,-4.4999696e-6)"
+ id="path12897-5"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g10027-7"
+ transform="translate(109,-110)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ sodipodi:nodetypes="sssssccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path9906-8-8"
+ d="m 264.5,688 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" />
+ <g
+ id="g9914-5"
+ transform="translate(99.99999,195.99938)"
+ style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 366.48438,579 c -0.12718,0.004 -0.248,0.0564 -0.3379,0.14648 l -3,3 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 580 h 1.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -2 v 0.002 c -0.005,0 -0.0101,-0.002 -0.0156,-0.002 z M 363,584 v 7.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 10 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -5 c 0.01,-0.67616 -1.00956,-0.67616 -1,0 v 4.5 h -9 v -7 z"
+ transform="translate(-208.99999,-85.99938)"
+ id="path9910-5"
+ inkscape:connector-curvature="0" />
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 385.5,390 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 3 v 3 h -3 z" id="path4281-8" inkscape:connector-curvature="0"/>
- </g>
- <path inkscape:connector-curvature="0" id="path22951-5" d="m 52.5,410 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 A 0.50005,0.50005 0 0 0 56,413.5 V 412 h 0.5 c 1.293073,0 2.425866,0.35206 3.21875,1.00977 C 60.511634,413.66747 61,414.62406 61,416 c 0,1.58333 -0.78109,3.05511 -2.240234,4.16406 C 57.300621,421.27301 55.159091,422 52.5,422 H 52 v -1.5 A 0.50005,0.50005 0 0 0 51.5,420 h -3 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 A 0.50005,0.50005 0 0 0 52,423.5 V 423 h 0.5 c 2.840909,0 5.199379,-0.77301 6.865234,-2.03906 C 61.03109,419.69489 62,417.91667 62,416 62,414.37594 61.372824,413.08253 60.357422,412.24023 59.34202,411.39794 57.973784,411 56.5,411 H 56 v -0.5 A 0.50005,0.50005 0 0 0 55.5,410 Z m 0.5,1 h 2 v 2 h -2 z m -4,10 h 2 v 2 h -2 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 53.5,431 a 1.50015,1.50015 0 1 0 0,3 H 55 c 1.249468,0.006 2.332699,0.37671 3.013672,0.94141 0.682107,0.56564 1.059323,1.26298 0.988281,2.4707 -0.09036,1.53611 -0.972327,2.5432 -2.498047,3.35351 -1.525719,0.81032 -3.632465,1.22991 -5.447265,1.23438 H 49.5 a 1.50015,1.50015 0 1 0 0,3 h 1.5625 0.002 c 2.24072,-0.006 4.728077,-0.46126 6.845703,-1.58594 2.117627,-1.12468 3.928252,-3.11228 4.087891,-5.82617 0.120132,-2.04228 -0.719411,-3.83841 -2.068359,-4.95703 -1.348949,-1.11862 -3.108979,-1.6232 -4.923829,-1.63086 h -0.002 z" id="path8588-0" inkscape:connector-curvature="0"/>
- <rect style="display:inline;opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" id="rect5217-4-0" width="16" height="16" x="110" y="430" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g12761" transform="translate(71.999998,4.4999696e-6)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" d="m 51.5,515 a 0.50005,0.50005 0 0 0 -0.353516,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 48,518.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.353516,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 62,525.5 v -10 A 0.50005,0.50005 0 0 0 61.5,515 Z m 0.207031,1 H 61 v 9.29297 L 58.292969,528 H 49 v -9.29297 z M 52,519 v 2 h 2 v -2 z m 2,2 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 0,2 v 2 h 2 v -2 z m 0,2 h -2 v 2 h 2 z m -2,0 v -2 h -2 v 2 z m -2,0 h -2 v 2 h 2 z m 0,-2 v -2 h -2 v 2 z" transform="translate(-71.999998,-4.4999696e-6)" id="path12740" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g12793" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 92.496094,325.99414 a 0.50005,0.50005 0 0 0 -0.382813,0.82227 l 4.5,5.5 a 0.50005,0.50005 0 0 0 0.773438,0 l 4.500001,-5.5 a 0.50005,0.50005 0 1 0 -0.77344,-0.63282 L 97,331.21094 92.886719,326.18359 a 0.50005,0.50005 0 0 0 -0.390625,-0.18945 z" id="path10173-4" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 91.25,334 c -0.683851,0 -1.25,0.56615 -1.25,1.25 v 3.5 c 0,0.68385 0.566149,1.25 1.25,1.25 h 3.5 c 0.683851,0 1.25,-0.56615 1.25,-1.25 v -3.5 C 96,334.56615 95.433851,334 94.75,334 Z m 8,0 c -0.683851,0 -1.25,0.56615 -1.25,1.25 v 3.5 c 0,0.68385 0.566149,1.25 1.25,1.25 h 3.5 c 0.68385,0 1.25,-0.56615 1.25,-1.25 v -3.5 c 0,-0.68385 -0.56615,-1.25 -1.25,-1.25 z m -7.75,4 h 2 1 a 0.50005,0.50005 0 1 1 0,1 h -1 -2 a 0.50005,0.50005 0 1 1 0,-1 z m 8,0 h 2 1 a 0.50005,0.50005 0 1 1 0,1 h -1 -2 a 0.50005,0.50005 0 1 1 0,-1 z" id="rect13911" inkscape:connector-curvature="0"/>
- </g>
- <g id="g12836" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" transform="translate(-123,458.99979)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 540.5,263 c -2.47936,0 -4.5,2.02064 -4.5,4.5 0,2.47936 2.02064,4.5 4.5,4.5 2.47936,0 4.5,-2.02064 4.5,-4.5 0,-2.47936 -2.02064,-4.5 -4.5,-4.5 z m 0,1 c 1.93892,0 3.5,1.56108 3.5,3.5 0,1.40621 -0.82672,2.60476 -2.01758,3.16211 -0.16784,-2.48561 -2.15892,-4.47669 -4.64453,-4.64453 C 537.89524,264.82672 539.09379,264 540.5,264 Z" transform="translate(123,-458.99979)" id="path12830" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 657.50195,-192.93359 a 0.50004997,0.50004997 0 0 0 -0.22656,0.0508 c -2.27231,1.07327 -3.57921,3.51034 -3.21484,5.99609 0.36436,2.48575 2.31598,4.44563 4.80078,4.82227 2.48479,0.37663 4.92837,-0.91763 6.01367,-3.1836 a 0.50013262,0.50013262 0 1 0 -0.90234,-0.43164 c -0.89704,1.8729 -2.90867,2.93833 -4.96289,2.62696 -2.05422,-0.31138 -3.6598,-1.92406 -3.96094,-3.97852 -0.30115,-2.05446 0.77387,-4.06001 2.65234,-4.94727 a 0.50004997,0.50004997 0 0 0 -0.19922,-0.95507 z" id="path12834" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g12981" transform="translate(-1.8536743e-6,-20.999995)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 226.5,206.99414 a 0.50004997,0.50004997 0 0 0 -0.34766,0.85938 L 228.29883,210 h -10.5918 l 2.14649,-2.14648 a 0.50004997,0.50004997 0 1 0 -0.70704,-0.70704 l -2.95703,2.95704 a 0.50004997,0.50004997 0 0 0 -0.002,0.79296 0.50004997,0.50004997 0 0 0 0.008,0.006 l 2.95117,2.95118 a 0.50004997,0.50004997 0 1 0 0.70704,-0.70704 L 217.70703,211 h 10.5918 l -2.14649,2.14648 a 0.50004997,0.50004997 0 1 0 0.70704,0.70704 l 2.96484,-2.9668 a 0.50004997,0.50004997 0 0 0 0.0195,-0.0156 l 0.0156,-0.0176 a 0.50004997,0.50004997 0 0 0 0.0234,-0.68164 0.50004997,0.50004997 0 0 0 -0.0234,-0.0254 0.50004997,0.50004997 0 0 0 -0.01,-0.01 l -2.99023,-2.99024 A 0.50004997,0.50004997 0 0 0 226.5,206.99414 Z" id="path12879" inkscape:connector-curvature="0"/>
- <path id="circle12970" style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" d="m 224.00001,202.49817 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z m 5,0 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z m -10,0 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 94.513672,32 a 0.50005,0.50005 0 0 0 -0.417969,0.203125 c -2.416051,3.180716 -3.444751,6.003207 -3.857422,8.287109 -0.412671,2.283903 -0.216543,4.049887 -0.21875,5.00586 a 0.50005,0.50005 0 1 0 1,0.0039 c 0.0025,-1.084327 -0.183742,-2.690936 0.203125,-4.832031 0.386868,-2.141095 1.341004,-4.795942 3.667969,-7.859375 A 0.50005,0.50005 0 0 0 94.513672,32 Z m 4.955078,3.001953 a 0.50005,0.50005 0 0 0 -0.304688,0.126953 c -4.123582,3.585034 -5.171874,7.536346 -5.171874,10.376953 a 0.50005,0.50005 0 1 0 1,0 c 0,-2.600212 0.913619,-6.219783 4.828124,-9.623047 A 0.50005,0.50005 0 0 0 99.46875,35.001953 Z m 4.02539,5.003906 c -3.01703,-0.0065 -5.494281,2.470749 -5.501952,5.498047 a 0.50005,0.50005 0 1 0 1,0.0039 c 0.0063,-2.484383 2.030992,-4.507263 4.500002,-4.501953 a 0.50005,0.50005 0 1 0 0.002,-1 z" id="path18476-0-2" inkscape:connector-curvature="0"/>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g7347" transform="translate(921.00001,-553)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <rect transform="scale(-1,1)" style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate" id="rect7240" width="16" height="16" x="396" y="731"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m -408.50391,736.99414 a 0.50005,0.50005 0 0 0 -0.43554,0.26563 c -1.5311,2.80698 -2.01417,5.0457 -2.02149,8.22461 a 0.50005,0.50005 0 1 0 1,0.004 c 0.007,-3.0834 0.43147,-5.05503 1.90039,-7.74805 a 0.50005,0.50005 0 0 0 -0.44336,-0.74609 z m 6.99805,2 a 0.50005,0.50005 0 0 0 -0.37891,0.18555 C -403.15877,740.70849 -404,742.16634 -404,745.5 a 0.50005,0.50005 0 1 0 1,0 c 0,-3.18014 0.65877,-4.20849 1.88477,-5.67969 a 0.50005,0.50005 0 0 0 -0.39063,-0.82617 z" id="path7245" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m -407.5,732 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 7,2 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path7250" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccc"/>
- </g>
- <g id="g6932" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 543.50781,181.99023 a 1.50015,1.50015 0 0 0 -0.67773,0.16797 c -3.41741,1.7087 -5.83009,5.05846 -5.83008,9.3418 a 1.50015,1.50015 0 1 0 3,0 c -10e-6,-3.21666 1.58731,-5.3669 4.16992,-6.6582 a 1.50015,1.50015 0 0 0 -0.66211,-2.85157 z" id="path7270" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 536.49609,179.00195 a 0.50005,0.50005 0 0 0 -0.35351,0.12891 c -4.08383,3.59037 -5.14329,7.80863 -5.13086,13.36328 a 0.50005,0.50005 0 1 0 1,-0.002 c -0.0122,-5.43221 0.92902,-9.21403 4.79101,-12.60938 a 0.50005,0.50005 0 0 0 -0.30664,-0.88086 z" id="path7282" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" transform="translate(919,-532)" id="g6686" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <rect transform="scale(-1,1)" style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate" id="rect6673" width="16" height="16" x="415" y="710"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m -416.49609,713.99609 a 0.50005,0.50005 0 0 0 -0.31055,0.10938 c -0.21339,0.16596 -0.41872,0.33348 -0.61524,0.50195 -4.0339,3.45843 -4.51787,6.50897 -4.57812,9.88281 a 0.50009544,0.50009544 0 1 0 1,0.0195 c 0.059,-3.3038 0.37586,-5.83955 4.22852,-9.14258 0.1842,-0.15793 0.37703,-0.31626 0.57812,-0.47266 a 0.50005,0.50005 0 0 0 -0.30273,-0.89844 z" id="path6675" inkscape:connector-curvature="0"/>
- <path id="path6688" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m -427.5,716 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -2,5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 5,-10 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccccccccccccccc"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 265.00049,180.00029 c -0.56524,0 -1.07102,0.24537 -1.44727,0.61718 -0.37625,0.37181 -0.64955,0.85716 -0.88086,1.40821 -0.46263,1.10209 -0.75684,2.49042 -1.08008,3.85937 -0.32324,1.36896 -0.67626,2.7158 -1.17383,3.66406 -0.49757,0.94827 -1.04163,1.45118 -1.91211,1.45118 a 0.50005,0.50005 0 1 0 0,1 c 1.29399,0 2.21222,-0.8721 2.79688,-1.98633 0.58466,-1.11424 0.93562,-2.51739 1.26172,-3.89844 0.32609,-1.38105 0.62614,-2.74272 1.0293,-3.70312 0.20157,-0.48021 0.4296,-0.85424 0.6621,-1.08399 0.2325,-0.22975 0.4436,-0.32812 0.74415,-0.32812 0.30054,0 0.51164,0.0984 0.74414,0.32812 0.23249,0.22975 0.46053,0.60378 0.66211,1.08399 0.40315,0.9604 0.7032,2.32207 1.02929,3.70312 0.3261,1.38105 0.67511,2.7842 1.25977,3.89844 0.58466,1.11423 1.50289,1.98633 2.79687,1.98633 a 0.50005,0.50005 0 1 0 0,-1 c -0.87047,0 -1.41258,-0.50291 -1.91015,-1.45118 -0.49757,-0.94826 -0.85059,-2.2951 -1.17383,-3.66406 -0.32324,-1.36895 -0.61745,-2.75728 -1.08008,-3.85937 -0.23131,-0.55105 -0.50461,-1.0364 -0.88086,-1.40821 -0.37625,-0.37181 -0.88203,-0.61718 -1.44726,-0.61718 z" id="path10124-9" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" id="path10162-3" d="m 349.01758,181.25 a 0.50005,0.50005 0 0 0 -0.41992,0.20312 l -6.48243,8.7461 a 0.50005,0.50005 0 1 0 0.80274,0.5957 L 349,182.58984 l 6.07031,8.20313 a 0.50005,0.50005 0 1 0 0.80469,-0.59375 l -6.47266,-8.7461 A 0.50005,0.50005 0 0 0 349.01758,181.25 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate" id="rect18819-6" width="16" height="16" x="320" y="178" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96"/>
- <g style="display:inline;fill:#ffffff;stroke-width:1.03551209;enable-background:new" id="g10170-0" transform="matrix(0.93036376,0,0,1.0023904,257.63778,150.90833)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.03551209;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 23.460938,40.029297 A 0.51780782,0.51780782 0 0 1 22.96875,39.486328 L 23,38.607422 v -0.0039 c 0.0063,-2.697355 1.432558,-5.191614 3.748047,-6.542969 2.32064,-1.354362 5.185219,-1.354362 7.505859,0 2.32064,1.354362 3.748047,3.85629 3.748047,6.560547 v 0.882812 a 0.51780782,0.51780782 0 1 1 -1.035156,0 V 38.6211 c 0,-2.339918 -1.23548,-4.49829 -3.236328,-5.666016 -2.000849,-1.167726 -4.460089,-1.167727 -6.460938,0 -2.000848,1.167726 -3.234375,3.326098 -3.234375,5.666016 a 0.51780782,0.51780782 0 0 1 -0.002,0.01758 l -0.0293,0.882812 a 0.51780782,0.51780782 0 0 1 -0.542968,0.507813 z" id="path10174-7" inkscape:connector-curvature="0"/>
</g>
- <rect y="178" x="299" height="16" width="16" id="rect4967" style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 307,180 c -1.24829,0 -2.24461,0.83463 -3,1.93555 -0.75539,1.10091 -1.32403,2.51399 -1.76367,3.91601 -0.87928,2.80405 -1.23047,5.58594 -1.23047,5.58594 a 0.50013931,0.50013931 0 1 0 0.99219,0.12695 c 0,0 0.34791,-2.71791 1.19336,-5.41406 0.42272,-1.34808 0.97296,-2.68677 1.63281,-3.64844 C 305.48407,181.54029 306.19904,181 307,181 c 0.80095,0 1.51593,0.54029 2.17578,1.50195 0.65985,0.96167 1.21009,2.30036 1.63281,3.64844 0.84545,2.69615 1.19336,5.41406 1.19336,5.41406 a 0.50013931,0.50013931 0 1 0 0.99219,-0.12695 c 0,0 -0.35119,-2.78189 -1.23047,-5.58594 -0.43964,-1.40202 -1.00828,-2.8151 -1.76367,-3.91601 C 309.24461,180.83464 308.24829,180 307,180 Z" id="path13261" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 327.48047,181 a 0.50005,0.50005 0 0 0 -0.46875,0.39453 c -0.73399,3.42527 -2.46804,7.48775 -5.67969,8.63477 a 0.50005,0.50005 0 1 0 0.33594,0.9414 c 3.19373,-1.14062 4.90029,-4.45895 5.83203,-7.61914 0.93174,3.16019 2.6383,6.47852 5.83203,7.61914 a 0.50005,0.50005 0 1 0 0.33594,-0.9414 c -3.21165,-1.14702 -4.9457,-5.2095 -5.67969,-8.63477 A 0.50005,0.50005 0 0 0 327.48047,181 Z" id="path10168-6-7" inkscape:connector-curvature="0"/>
- <g transform="matrix(-1,0,0,1,401.98389,150.99638)" id="g13323" style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff">
- <path inkscape:connector-curvature="0" id="path13321" d="M 9.96875,29.048828 C 9.4658605,28.864829 8.9025328,28.986924 8.5410156,29.310547 8.1794984,29.63417 7.9598217,30.084792 7.7695312,30.613281 7.3889504,31.670259 7.1601578,33.086794 6.90625,34.523438 c -0.2539078,1.436643 -0.5324149,2.889409 -0.9414062,3.929687 -0.2044957,0.520139 -0.4424423,0.932648 -0.6894532,1.1875 -0.2470108,0.254852 -0.473033,0.363281 -0.7851562,0.363281 a 0.50005,0.50005 0 1 0 0,1 c 0.5904168,0 1.1159371,-0.267683 1.5039062,-0.667968 0.3879692,-0.400286 0.6690516,-0.922242 0.9023438,-1.515626 0.4665844,-1.186767 0.7390333,-2.679616 0.9941406,-4.123046 0.2551073,-1.443431 0.4935421,-2.842034 0.8183594,-3.744141 0.1624086,-0.451054 0.3541704,-0.76594 0.5,-0.896484 0.1458295,-0.130544 0.1865427,-0.15232 0.4160156,-0.06836 0.057045,0.02087 0.1634141,0.101911 0.2832031,0.296875 0.1197889,0.194965 0.2422649,0.485737 0.3515629,0.826172 0.218596,0.680871 0.393488,1.55941 0.582031,2.373047 0.188543,0.813637 0.358157,1.549689 0.740234,2.082031 0.191039,0.266171 0.511622,0.515788 0.900391,0.50586 0.388769,-0.0099 0.704011,-0.230804 1.001953,-0.542969 0.337514,-0.353626 0.595779,-0.497442 0.722656,-0.529297 0.126878,-0.03186 0.138013,-0.02504 0.242188,0.06836 0.20835,0.186805 0.512485,0.892009 0.740234,1.732422 0.227749,0.840413 0.429042,1.804722 0.716797,2.601563 0.143877,0.39842 0.30542,0.75895 0.542969,1.05664 0.237548,0.297691 0.601614,0.544922 1.027343,0.544922 a 0.50005,0.50005 0 1 0 0,-1 c -0.0724,0 -0.124723,-0.01782 -0.246093,-0.169922 -0.12137,-0.152098 -0.260285,-0.426776 -0.384766,-0.771484 -0.248961,-0.689415 -0.452791,-1.642926 -0.691406,-2.523438 -0.238616,-0.880511 -0.460258,-1.699598 -1.037109,-2.216796 -0.288426,-0.2586 -0.735893,-0.398016 -1.154297,-0.292969 -0.418405,0.105047 -0.794027,0.38192 -1.203125,0.810547 -0.205362,0.215165 -0.318948,0.232836 -0.302735,0.232422 0.01621,-4.14e-4 0.02252,0.02861 -0.0625,-0.08984 C 12.22449,34.745505 11.999507,34.047965 11.816406,33.257812 11.633305,32.46766 11.457527,31.57275 11.210938,30.804688 11.087643,30.420656 10.949285,30.066996 10.761719,29.761719 10.574152,29.456442 10.328076,29.1803 9.96875,29.048828 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g5270-3" transform="translate(497.99495,-311.99288)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path id="path5169-5" style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" d="m -115,532 h 16.005051 v 16 H -115 Z" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"/>
- <g transform="translate(-1)" id="g5191-5" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 386.48633,221 c -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 1 6.55664 C 384.86022,229.298 384,230.30731 384,231.50781 c 0,1.372 1.12214,2.49414 2.49414,2.49414 1.372,0 2.49414,-1.12214 2.49414,-2.49414 0,-1.20116 -0.8593,-2.21054 -1.99414,-2.44336 v -6.55664 -1 c 0.004,-0.28226 -0.22555,-0.51223 -0.50781,-0.50781 z m 1.00781,1.00781 v 3 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -1,8.00586 c 0.83156,0 1.49414,0.66258 1.49414,1.49414 0,0.83156 -0.66258,1.49414 -1.49414,1.49414 -0.83156,0 -1.49414,-0.66258 -1.49414,-1.49414 0,-0.83156 0.66258,-1.49414 1.49414,-1.49414 z" transform="translate(-496.99495,311.99288)" id="path5112-6" inkscape:connector-curvature="0"/>
+ <g
+ transform="translate(365,4.4999696e-6)"
+ id="g13349"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 349.5,578 c -1.48507,0 -2.8535,0.46731 -3.86133,1.33594 C 344.63084,580.20456 344,581.48473 344,583 v 3 c 0,0.83333 -0.007,1.35913 -0.11133,1.78711 -0.10481,0.42798 -0.303,0.80502 -0.77929,1.40039 A 0.50005,0.50005 0 0 0 343,589.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1 1 a 0.50005,0.50005 0 0 0 0.33008,-0.12305 l 1.64648,-1.44336 1.41992,1.41993 A 0.50005,0.50005 0 0 0 349.25,592 h 0.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 1.39648,-1.39649 1.39648,1.39649 A 0.50005,0.50005 0 0 0 353.25,592 h 1.25 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 -1 -5.5 c 0,-1.51527 -0.63084,-2.79544 -1.63867,-3.66406 C 352.3535,578.46731 350.98507,578 349.5,578 Z m 0,1 c 1.27493,0 2.40681,0.40238 3.20898,1.09375 C 353.51116,580.78512 354,581.75527 354,583 v 5.5 1 1.5 h -0.54297 l -1.60351,-1.60352 a 0.50005,0.50005 0 0 0 -0.70704,0 L 349.54297,591 h -0.0859 l -1.60351,-1.60352 a 0.50005,0.50005 0 0 0 -0.6836,-0.0234 L 345.3125,591 H 344.5 344 v -1.38867 c 0.42104,-0.55984 0.73249,-1.05984 0.86133,-1.58594 C 345.00652,587.43254 345,586.83333 345,586 v -3 c 0,-1.24473 0.48884,-2.21488 1.29102,-2.90625 C 347.09319,579.40238 348.22507,579 349.5,579 Z m -1.00586,2.99219 a 0.50005,0.50005 0 0 0 -0.34766,0.15429 l -0.64648,0.64649 -0.64648,-0.64649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 0.64649,0.64648 -0.64649,0.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 0.64648,-0.64649 0.64648,0.64649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -0.64649,-0.64648 0.64649,-0.64648 a 0.50005,0.50005 0 0 0 -0.35938,-0.86133 z m 4,0 a 0.50005,0.50005 0 0 0 -0.34766,0.15429 l -0.64648,0.64649 -0.64648,-0.64649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 0.64649,0.64648 -0.64649,0.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 0.64648,-0.64649 0.64648,0.64649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -0.64649,-0.64648 0.64649,-0.64648 a 0.50005,0.50005 0 0 0 -0.35938,-0.86133 z"
+ transform="translate(-365,-4.4999696e-6)"
+ id="path13343"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 291.98438,431.0625 c -1.31822,0 -2.69153,0.28723 -3.69727,1.29297 a 1.0001,1.0001 0 1 0 1.41406,1.41406 c 0.49426,-0.49426 1.2483,-0.70703 2.28321,-0.70703 a 1.0001,1.0001 0 1 0 0,-2 z m -7.24024,3.04297 c -0.74589,-0.0115 -1.46694,0.0868 -2.13086,0.30664 -1.32784,0.43972 -2.4721,1.53683 -2.61719,3.06055 -0.19518,2.0499 0.80702,3.49399 1.02735,4.3457 0.14607,0.56468 0.0225,0.72298 -0.18164,0.91797 -0.20413,0.19499 -0.61247,0.33203 -0.84961,0.33203 a 1.0001,1.0001 0 1 0 0,2 c 0.76285,0 1.57391,-0.25956 2.23047,-0.88672 0.65655,-0.62715 1.03297,-1.71849 0.73632,-2.86523 -0.37187,-1.43756 -1.0944,-2.37562 -0.97265,-3.6543 0.0682,-0.71615 0.4403,-1.08149 1.25586,-1.35156 0.81556,-0.27008 2.03005,-0.27431 3.23242,0.0684 1.20237,0.34267 2.38417,1.01511 3.21875,1.95703 0.83458,0.94191 1.35114,2.12713 1.29297,3.68945 -0.0218,0.58526 -0.18864,0.77371 -0.37305,0.89453 -0.18441,0.12083 -0.50228,0.18156 -0.91016,0.0723 -0.65709,-0.17607 -1.01294,-0.58503 -1.30078,-1.30274 -0.28784,-0.7177 -0.4082,-1.70364 -0.4082,-2.62695 a 1.0001,1.0001 0 1 0 -2,0 c 0,1.07669 0.11104,2.27463 0.55078,3.37109 0.43975,1.09647 1.30771,2.13309 2.64063,2.49024 0.84212,0.22565 1.76567,0.1664 2.52343,-0.33008 0.75729,-0.49617 1.23505,-1.42269 1.2754,-2.49219 v -0.002 c 0.0762,-2.06159 -0.66061,-3.80964 -1.79493,-5.08984 -1.1347,-1.28064 -2.63964,-2.11968 -4.16601,-2.55469 -0.76319,-0.21751 -1.53341,-0.33806 -2.2793,-0.34961 z"
+ id="path8292"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 495.50391,451.99219 c -1.93006,0 -3.50391,1.57292 -3.50391,3.5 v 2 c 0,0.41666 0.19292,0.77495 0.45898,1.04101 0.26607,0.26607 0.62435,0.45899 1.04102,0.45899 a 0.50005,0.50005 0 1 0 0,-1 c -0.0833,0 -0.22505,-0.0571 -0.33398,-0.16602 C 493.05708,457.71724 493,457.57552 493,457.49219 v -2 c 0,-1.38664 1.11314,-2.5 2.50391,-2.5 h 1.0039 c 1.39077,0 2.50196,1.11336 2.50196,2.5 v 2 c 0,0.0833 -0.0571,0.22505 -0.16602,0.33398 -0.10893,0.10893 -0.25065,0.16602 -0.33398,0.16602 a 0.50005,0.50005 0 1 0 0,1 c 0.41666,0 0.77494,-0.19292 1.04101,-0.45899 0.26607,-0.26606 0.45899,-0.62435 0.45899,-1.04101 v -2 c 0,-1.92708 -1.57191,-3.5 -3.50196,-3.5 z m 3.94921,7.41406 a 0.50005,0.50005 0 0 0 -0.48632,0.33203 c -0.17381,0.48217 -0.35767,1.04392 -0.75391,1.48047 -0.39624,0.43655 -0.98986,0.78906 -2.17578,0.78906 -1.18761,0 -1.78805,-0.34711 -2.19141,-0.77929 -0.40336,-0.43219 -0.59802,-0.98975 -0.78515,-1.47266 a 0.50005,0.50005 0 0 0 -0.67578,-0.27344 c -0.97162,0.44606 -1.78522,0.89986 -2.38868,1.45508 C 489.39264,461.49272 489,462.19074 489,462.99219 v 2.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13.00977 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2.5 c 0,-0.79711 -0.38431,-1.49976 -0.98243,-2.06446 -0.59811,-0.56469 -1.40897,-1.02891 -2.38086,-1.47461 a 0.50005,0.50005 0 0 0 -0.19336,-0.0469 z m 0.17579,1.19922 c 0.68529,0.34567 1.33558,0.69455 1.71289,1.05078 0.46505,0.43906 0.66797,0.84399 0.66797,1.33594 v 2 H 490 v -2 c 0,-0.49365 0.20477,-0.8868 0.67383,-1.31836 0.38208,-0.35154 1.03995,-0.69804 1.73437,-1.04492 0.1643,0.40983 0.28954,0.83601 0.70508,1.28125 0.58146,0.623 1.5239,1.09765 2.92383,1.09765 1.40162,0 2.34196,-0.48473 2.91601,-1.11719 0.40651,-0.44786 0.51938,-0.87307 0.67579,-1.28515 z"
+ id="path6745-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 134.50977,472.99414 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5039 c 0.0205,0.58311 0.0403,1.03618 -0.0488,1.24805 -0.22838,0.54301 -0.5609,0.82668 -1.00781,1.10937 -0.44691,0.28269 -1.00733,0.53131 -1.53711,0.97461 -0.52977,0.4433 -1.00108,1.10059 -1.22656,2.08789 -0.22548,0.9873 -0.2332,2.29903 0.0625,4.16406 0.0385,0.24311 0.24801,0.42203 0.49414,0.42188 h 8.75586 c 0.30739,1.4e-4 0.54213,-0.2745 0.49414,-0.57812 -0.36883,-2.32606 -0.21493,-3.6368 0.12305,-4.40821 0.33798,-0.7714 0.85304,-1.08606 1.49804,-1.45508 0.645,-0.36901 1.43565,-0.7809 1.90821,-1.70703 0.47255,-0.92613 0.59571,-2.25921 0.21289,-4.4375 C 145.70043,474.17484 145.49284,474.0002 145.25,474 h -7.24023 v -0.50586 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m 3,1.00586 h 6.78125 c 0.25456,1.74951 0.14487,2.81594 -0.15235,3.39844 -0.3247,0.63637 -0.84774,0.91198 -1.51367,1.29297 -0.66593,0.38098 -1.46183,0.87882 -1.91797,1.91992 -0.41222,0.94085 -0.49675,2.35477 -0.23633,4.38867 h -7.73437 c -0.19264,-1.47462 -0.23076,-2.65205 -0.0684,-3.36328 0.18281,-0.80045 0.49635,-1.21142 0.89258,-1.54297 0.39622,-0.33155 0.90291,-0.56523 1.42968,-0.89844 0.52678,-0.33321 1.07351,-0.7985 1.39649,-1.5664 0.22021,-0.52359 0.17686,-1.05487 0.13867,-1.63477 h 0.48438 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 z"
+ id="path13566"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccscsccccccccccccccccccccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 160.5,431 a 1.5,1.5 0 0 0 -1.5,1.5 1.5,1.5 0 0 0 0.0879,0.5 h -4.56836 a 1.50015,1.50015 0 1 0 0,3 H 158 v 1.94922 c -1.31983,1.3363 -2.47353,2.76999 -2.9707,5.25586 a 1.50015,1.50015 0 1 0 2.9414,0.58984 c 0.37009,-1.85045 0.99513,-2.60285 2.0293,-3.6289 1.03417,1.02605 1.65921,1.77845 2.0293,3.6289 a 1.50015,1.50015 0 1 0 2.9414,-0.58984 c -0.49717,-2.48587 -1.65087,-3.91956 -2.9707,-5.25586 V 436 h 3.48047 a 1.50015,1.50015 0 1 0 0,-3 h -2.53711 c -0.0387,0.18925 -0.094,0.37697 -0.17774,0.55664 C 162.35553,434.4361 161.47038,435 160.5,435 a 0.50005,0.50005 0 1 1 0,-1 1.5,1.5 0 0 0 0.41406,-0.0586 c 0.009,-0.002 0.0169,-0.005 0.0254,-0.008 a 1.5,1.5 0 0 0 0.35157,-0.16211 c 0.006,-0.004 0.0133,-0.006 0.0195,-0.01 a 1.5,1.5 0 0 0 0.004,-0.002 1.5,1.5 0 0 0 0.29102,-0.25 c 0.009,-0.0103 0.0202,-0.0187 0.0293,-0.0293 a 1.5,1.5 0 0 0 0.21484,-0.33008 c 0.003,-0.006 0.007,-0.01 0.01,-0.0156 0.002,-0.005 0.004,-0.0104 0.006,-0.0156 A 1.5,1.5 0 0 0 162,432.5 1.5,1.5 0 0 0 160.5,431 Z"
+ id="path13634"
+ inkscape:connector-curvature="0"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 428.49023,603.99414 a 0.50005,0.50005 0 0 0 -0.34961,0.85938 l 4,4 a 0.50005,0.50005 0 0 0 0.70704,0 l 4,-4 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 l -3.64648,3.64649 -3.64648,-3.64649 a 0.50005,0.50005 0 0 0 -0.35743,-0.15234 z"
+ id="path13549"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 410.49414,601.99414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 3.64649,3.64648 -3.64649,3.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 4,-4 a 0.50005,0.50005 0 0 0 0,-0.70704 l -4,-4 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path13551"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="rotate(-180,307.00525,417)"
+ id="g13597"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 289.50391,410 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -0.99414 c -1.17529,0 -2.25213,0.41841 -2.88477,1.18164 -0.28029,0.32895 -0.0395,0.83456 0.39258,0.82422 0.14712,-0.004 0.28501,-0.0726 0.37695,-0.1875 C 286.27001,413.36537 287.08306,413 288.00977,413 h 0.99414 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m -4.58594,3.95898 c -1.10666,0.0478 -2.07229,0.36866 -2.82031,0.91211 -0.99737,0.72461 -1.58789,1.85424 -1.58789,3.12891 v 1 h -1.50586 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -0.49414 v -1 c 0,-0.97533 0.41802,-1.76979 1.17578,-2.32031 0.75777,-0.55053 1.87662,-0.84701 3.26562,-0.6836 1.98998,0.23412 3.41358,1.22814 4.10352,2.33203 0.68994,1.10391 0.68215,2.23778 -0.14844,3.06836 -0.83795,0.83796 -1.98844,0.89361 -3.08398,0.26368 -1.09554,-0.62994 -2.08242,-1.9799 -2.31641,-3.96875 -0.0504,-0.69579 -1.10528,-0.57121 -0.99219,0.11718 0.26601,2.26115 1.40414,3.91119 2.8086,4.71875 0.70223,0.40379 1.48456,0.58895 2.23632,0.52735 0.75176,-0.0616 1.47366,-0.37015 2.05469,-0.95117 1.16941,-1.16942 1.16162,-2.91055 0.28906,-4.30664 -0.87256,-1.3961 -2.57396,-2.52709 -4.83398,-2.79297 -0.39761,-0.0468 -0.78151,-0.0608 -1.15039,-0.0449 z M 280.00391,421 h 2 v 2 h -2 z"
+ transform="rotate(180,307.00525,417)"
+ id="path13595"
+ inkscape:connector-curvature="0" />
+ </g>
+ <rect
+ style="display:inline;opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ id="rect13550"
+ width="16"
+ height="16"
+ x="488.00128"
+ y="430.00018"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13226"
+ transform="translate(-189,84.000005)">
+ <path
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;enable-background:accumulate"
+ d="m 285,536 -0.15625,1.90625 c -0.6231,0.14227 -1.07677,0.25145 -1.59375,0.59375 l -1.75,-1.5 -1.5,1.5 1.5,1.75 c -0.34229,0.51699 -0.45148,0.97065 -0.59375,1.59375 L 279,542 v 1 1 l 1.90625,0.15625 c 0.14227,0.6231 0.25145,1.07677 0.59375,1.59375 l -1.5,1.75 1.5,1.5 1.75,-1.5 c 0.51699,0.34229 0.97065,0.45148 1.59375,0.59375 L 285,550 h 1 1 l 0.15625,-1.90625 c 0.6231,-0.14227 1.07677,-0.25145 1.59375,-0.59375 l 1.75,1.5 1.5,-1.5 -1.5,-1.75 c 0.34229,-0.51699 0.45148,-0.97065 0.59375,-1.59375 L 293,544 v -1 -1 l -1.90625,-0.15625 C 290.95148,541.22065 290.8423,540.76698 290.5,540.25 l 1.5,-1.75 -1.5,-1.5 -1.75,1.5 c -0.51699,-0.34229 -0.97065,-0.45148 -1.59375,-0.59375 L 287,536 h -1 z m 1,5 c 1.11641,0 2,0.88359 2,2 0,1.11641 -0.88359,2 -2,2 -1.11641,0 -2,-0.88359 -2,-2 0,-1.11641 0.88359,-2 2,-2 z"
+ transform="translate(189,-84.000005)"
+ id="path52982-3"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.14285719;enable-background:new"
+ id="g13938"
+ transform="matrix(0.875,0,0,0.875,-254.625,-304.87495)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3.42857146;marker:none;enable-background:accumulate"
+ id="rect13853"
+ width="16"
+ height="16"
+ x="299"
+ y="408.99994" />
+ </g>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14058"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 451.5,536 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 8 v 8 h -8 z"
+ id="path14208"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 449.49219,537.99219 A 0.50005,0.50005 0 0 0 449,538.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 450 v -8.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -2,2 A 0.50005,0.50005 0 0 0 447,540.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 448 v -8.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path14212"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 460.48438,536 c -0.12717,0.004 -0.248,0.0564 -0.3379,0.14648 l -9,9 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 9 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c 1.1e-4,-0.28235 -0.23341,-0.50879 -0.51562,-0.5 z"
+ id="path14252"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 414.55664,159.95508 a 0.50005,0.50005 0 0 0 -0.47461,0.61133 L 414.38867,162 h -4.70898 l 0.30859,-1.39062 a 0.5003812,0.5003812 0 1 0 -0.97656,-0.21876 L 408.6543,162 H 406.5 a 0.50005,0.50005 0 1 0 0,1 h 1.93164 l -0.66602,3 H 405.5 a 0.50005,0.50005 0 1 0 0,1 h 2.04297 l -0.53125,2.39062 a 0.5003812,0.5003812 0 1 0 0.97656,0.21876 L 408.56836,167 h 6.88672 l 0.55664,2.60352 a 0.50005,0.50005 0 1 0 0.97656,-0.20704 L 416.47656,167 H 418.5 a 0.50005,0.50005 0 1 0 0,-1 h -2.23633 l -0.63867,-3 h 1.875 a 0.50005,0.50005 0 1 0 0,-1 h -2.08984 l -0.34961,-1.64258 a 0.50005,0.50005 0 0 0 -0.50391,-0.40234 z M 409.45703,163 h 5.14453 l 0.64063,3 h -6.45117 z"
+ id="path13985"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14370"
+ transform="translate(20.999998,4.4999696e-6)">
+ <path
+ id="rect14323"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 141.51562,82 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 145.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 145.5,82 Z m 0.5,1 H 145 v 4 h -2.98438 z m -9.5,-1 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 136.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 136.5,82 Z m 0.5,1 H 136 v 4 h -2.98438 z m 8.5,-9 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 145.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 145.5,74 Z m 0.5,1 H 145 v 4 h -2.98438 z m -9.5,-1 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 136.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 136.5,74 Z m 0.5,1 H 136 v 4 h -2.98438 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g6448"
+ style="fill:#ffffff">
+ <path
+ d="m 103,78.000008 h 1 v 1 h -1 z m 0,-3 h 1 v 1 h -1 z m -8,3 h 1 v 1 h -1 z m 0,3 h 1 v 1 h -1 z m 0,-6 h 1 v 1 h -1 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="rect14452"
+ inkscape:connector-curvature="0" />
+ <path
+ d="m 98.515625,74 c -0.276131,2.8e-5 -0.499972,0.223869 -0.5,0.5 v 6 c 2.8e-5,0.276131 0.223869,0.499972 0.5,0.5 H 101.5 c 0.27613,-2.8e-5 0.49997,-0.223869 0.5,-0.5 v -6 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m 0.5,1 H 101 v 2 h -1.984375 z m 0,3 H 101 v 2 h -1.984375 z m -8.5,-4 c -0.276131,2.8e-5 -0.499972,0.223869 -0.5,0.5 v 12 c 2.8e-5,0.276131 0.223869,0.499972 0.5,0.5 H 93.5 c 0.276131,-2.8e-5 0.499972,-0.223869 0.5,-0.5 v -12 c -2.8e-5,-0.276131 -0.223869,-0.499972 -0.5,-0.5 z m 0.5,1 H 93 v 2 h -1.984375 z m 0,3 H 93 v 2 h -1.984375 z m 0,3 H 93 v 2 h -1.984375 z m 0,3 H 93 v 2 h -1.984375 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="path14479"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccc" />
+ </g>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14591">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 9.25,74 a 0.50005,0.50005 0 0 0 -0.4765625,0.351562 l -2.75,8.820313 A 0.50005,0.50005 0 0 0 6,83.320312 v 0.173829 a 0.50005,0.50005 0 1 0 1,0 v -0.09766 L 7.7460938,81 A 0.50005,0.50005 0 0 0 7.75,81 h 3.5 a 0.50005,0.50005 0 0 0 0.0039,0 L 12,83.396484 v 0.09766 a 0.50005,0.50005 0 1 0 1,0 v -0.173829 a 0.50005,0.50005 0 0 0 -0.02344,-0.148437 l -2.75,-8.820313 A 0.50005,0.50005 0 0 0 9.75,74 Z M 9.5,75.375 10.941406,80 H 8.0585938 Z"
+ id="path14584"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 14.5,79 a 0.50005,0.50005 0 1 0 0,1 H 19 v 0.08008 l -4.896484,6.365234 A 0.50005,0.50005 0 0 0 14,86.75 v 0.75 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5 a 0.50005,0.50005 0 1 0 0,-1 H 15 v -0.08008 l 4.896484,-6.365234 A 0.50005,0.50005 0 0 0 20,80.25 V 79.5 A 0.50005,0.50005 0 0 0 19.5,79 Z"
+ id="path14589"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 69.5,74 a 0.50005,0.50005 0 1 0 0,1 h 13 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 10 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 7 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14593"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 30.474609,74.994141 a 0.50004997,0.50004997 0 0 0 -0.40625,0.757812 L 33.128906,81 H 27.5 a 0.50004997,0.50004997 0 1 0 0,1 h 5.628906 l -3.060547,5.248047 a 0.50004997,0.50004997 0 1 0 0.863282,0.503906 L 34,82.492188 l 3.068359,5.259765 a 0.50004997,0.50004997 0 1 0 0.863282,-0.503906 L 34.871094,82 H 40.5 a 0.50004997,0.50004997 0 1 0 0,-1 h -5.628906 l 3.060547,-5.248047 A 0.50004997,0.50004997 0 1 0 37.068359,75.248047 L 34,80.507812 30.931641,75.248047 a 0.50004997,0.50004997 0 0 0 -0.457032,-0.253906 z"
+ id="path14603"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 50.494141,73.992188 A 0.50004997,0.50004997 0 0 0 50.417969,74 H 49.5 a 0.50004997,0.50004997 0 1 0 0,1 H 50 v 1.125 c 0,1.632015 0.971328,2.853007 2.201172,3.775391 L 53,80.5 v 0.5 0.5 l -0.798828,0.599609 C 50.971326,83.021991 50,84.242992 50,85.875 V 87 h -0.5 a 0.50004997,0.50004997 0 1 0 0,1 h 0.921875 a 0.50004997,0.50004997 0 0 0 0.160156,0 h 7.837891 a 0.50004997,0.50004997 0 0 0 0.162109,0 H 59.5 a 0.50004997,0.50004997 0 1 0 0,-1 H 59 v -1.125 c 0,-1.632008 -0.969373,-2.853009 -2.199219,-3.775391 L 56,81.5 V 81.035156 A 0.50004997,0.50004997 0 0 0 56,81 v -0.5 l 0.800781,-0.599609 C 58.030625,78.978007 59,77.757015 59,76.125 V 75 h 0.5 a 0.50004997,0.50004997 0 1 0 0,-1 h -0.919922 a 0.50004997,0.50004997 0 0 0 -0.162109,0 h -7.835938 a 0.50004997,0.50004997 0 0 0 -0.08789,-0.0078 z M 51,75 h 7 v 1.125 c 0,1.245243 -0.698245,2.147707 -1.800781,2.974609 l -1,0.75 A 0.50004997,0.50004997 0 0 0 55,80.25 V 80.964844 81 81.75 a 0.50004997,0.50004997 0 0 0 0.199219,0.400391 l 1,0.75 C 57.301151,83.726838 57.999238,84.628869 58,85.873047 V 87 h -7 v -1.125 -0.002 c 7.62e-4,-1.244178 0.698849,-2.146209 1.800781,-2.972656 l 1,-0.75 A 0.50004997,0.50004997 0 0 0 54,81.75 V 81.035156 A 0.50004997,0.50004997 0 0 0 54,81 v -0.75 a 0.50004997,0.50004997 0 0 0 -0.199219,-0.400391 l -1,-0.75 C 51.698847,78.273158 51.000762,77.371141 51,76.126953 v -0.002 z"
+ id="path14614"
+ inkscape:connector-curvature="0" />
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ id="g14256"
+ transform="translate(-21.000002,4.4999696e-6)"
+ style="display:inline;opacity:0.4;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 92.496094,325.99414 a 0.50005,0.50005 0 0 0 -0.382813,0.82227 l 4.5,5.5 a 0.50005,0.50005 0 0 0 0.773438,0 l 4.500001,-5.5 a 0.50005,0.50005 0 1 0 -0.77344,-0.63282 L 97,331.21094 92.886719,326.18359 a 0.50005,0.50005 0 0 0 -0.390625,-0.18945 z"
+ id="path14250"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path14254"
+ d="m 91.25,334 c -0.683851,0 -1.25,0.56615 -1.25,1.25 v 3.5 c 0,0.68385 0.566149,1.25 1.25,1.25 h 3.5 c 0.683851,0 1.25,-0.56615 1.25,-1.25 v -3.5 C 96,334.56615 95.433851,334 94.75,334 Z m 8,0 c -0.683851,0 -1.25,0.56615 -1.25,1.25 v 3.5 c 0,0.68385 0.566149,1.25 1.25,1.25 h 3.5 c 0.68385,0 1.25,-0.56615 1.25,-1.25 v -3.5 c 0,-0.68385 -0.56615,-1.25 -1.25,-1.25 z m -7.75,4 h 2 1 a 0.50005,0.50005 0 1 1 0,1 h -1 -2 a 0.50005,0.50005 0 1 1 0,-1 z m 8,0 h 2 1 a 0.50005,0.50005 0 1 1 0,1 h -1 -2 a 0.50005,0.50005 0 1 1 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 6.5,116 A 0.50005,0.50005 0 0 0 6,116.5 v 4 a 0.50005,0.50005 0 1 0 1,0 V 117 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 z m 9.007812,0 a 0.50005,0.50005 0 1 0 0,1 h 3.5 v 3.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -9.0156245,9 A 0.50005,0.50005 0 0 0 6,125.50781 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 H 7 v -3.5 A 0.50005,0.50005 0 0 0 6.4921875,125 Z M 19.5,125 a 0.50005,0.50005 0 0 0 -0.492188,0.50781 v 3.5 h -3.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4 A 0.50005,0.50005 0 0 0 19.5,125 Z"
+ id="path13927"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 48,11 v 2 h 2 v -2 z m 2,4 v 2 h 2 v -2 z m 2,3 v 2 h 2 v -2 z m 3,3 v 2 h 1.5 v 1 H 59 v 1 h 3 v -2 h -3 v -1 h -2 v -1 z"
+ id="path14341"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccc" />
+ <g
+ transform="matrix(-1,0,0,1,1290,302.99979)"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
+ id="g8530-0"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1258.4766,-286 a 0.50005,0.50005 0 0 0 -0.4102,0.25195 l -4,7 A 0.50005,0.50005 0 0 0 1254.5,-278 h 8 a 0.50005,0.50005 0 0 0 0.4336,-0.74805 l -4,-7 A 0.50005,0.50005 0 0 0 1258.4766,-286 Z m 0.023,1.50781 3.1387,5.49219 h -6.2774 z"
+ id="path8523-4"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1253.5,-289 c -0.8225,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z"
+ id="ellipse8525-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 27.5,11 A 0.50005,0.50005 0 0 0 27,11.5 v 10.851562 l 1,-1.75 V 12 h 12 v 12 h -3.099609 c 0.122248,0.339531 0.117057,0.686553 0.0039,1 H 40.5 A 0.50005,0.50005 0 0 0 41,24.5 v -13 A 0.50005,0.50005 0 0 0 40.5,11 Z"
+ transform="matrix(-1,0,0,1,1290,-302.99979)"
+ id="path8528-7"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path14394"
+ d="m 98.999998,11.000004 v 4.000002 h -1 -1 v 3 h -1 v -2 h -1 v 5.000001 h -1 v -2.000001 h -1 v 3.560548 h -1 v -2.085938 h -1 v 2.525389 h -1 v 2 L 104,25.000007 v -2.421875 h -1 v -4.578126 h -1 v 2.000001 h -1 v -6.000003 h -1.000002 v -3 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 76,11 c -0.08389,-2.87e-4 -0.166503,0.02054 -0.240234,0.06055 l -5.5,3 C 70.099297,14.148474 69.999666,14.317023 70,14.5 v 7 c -3.35e-4,0.182978 0.0993,0.351528 0.259766,0.439453 l 5.5,3 C 75.833498,24.979467 75.916111,25.000288 76,25 h 1 c 0.08389,2.87e-4 0.166503,-0.02053 0.240234,-0.06055 l 5.5,-3 C 82.900703,21.851526 83.000334,21.682977 83,21.5 v -7 c 3.35e-4,-0.182978 -0.0993,-0.351528 -0.259766,-0.439453 l -5.5,-3 C 77.166502,11.020533 77.083889,10.999712 77,11 Z m 0.382812,2 h 0.240235 L 81,15.390625 v 5.21875 L 76.617188,23 H 76.382812 L 72,20.609375 v -5.21875 z"
+ id="path14426"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccc" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14475"
+ transform="translate(-1.8536743e-6,25.000005)">
+ <g
+ transform="matrix(1,0,0,-1,-294,368)"
+ id="g4806-1"
+ style="opacity:1;fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 300.5,375 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 11 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 10 v 2 h -10 z"
+ id="path4801-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 302.5,378 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 11 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 10 v 2 h -10 z"
+ id="path4804-1"
+ inkscape:connector-curvature="0" />
</g>
- <g transform="translate(-2.9999978)" style="display:inline;opacity:0.7;fill:#ffffff;enable-background:new" id="g5186-5-5-7">
- <path id="path5179-0-9-1" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m -97.896484,538.39648 -1.707032,1.70704 0.75,0.75 c 0.195265,0.19518 0.511767,0.19518 0.707032,0 l 0.52539,-0.5254 0.47461,-0.4746 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 z m -0.614086,-1.39969 a 0.50005,0.50005 0 0 0 -0.34376,0.15039 l -4.4121,4.41015 c -0.38435,-0.27257 -0.83195,-0.45926 -1.31446,-0.52734 a 0.50005,0.50005 0 0 0 -0.0996,-0.006 0.50005,0.50005 0 0 0 -0.041,0.99609 c 0.71727,0.10121 1.32147,0.58072 1.58398,1.25586 0.26252,0.67514 0.14019,1.43694 -0.32031,1.9961 -0.46051,0.55917 -1.18354,0.82547 -1.89649,0.69726 a 0.50014796,0.50014796 0 1 0 -0.17773,0.98438 c 1.06733,0.19194 2.15825,-0.20977 2.84766,-1.04688 0.6894,-0.83711 0.87347,-1.98341 0.48047,-2.99414 -0.0911,-0.23424 -0.21129,-0.45079 -0.35352,-0.65039 l 4.41016,-4.4082 a 0.50005,0.50005 0 0 0 -0.36328,-0.85742 z" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 8.5,-4 A 0.50005,0.50005 0 0 0 8,-3.5 v 3 A 0.50005,0.50005 0 0 0 8.5,0 h 11 A 0.50005,0.50005 0 0 0 20,-0.5 v -3 A 0.50005,0.50005 0 0 0 19.5,-4 Z M 9,-3 h 10 v 2 H 9 Z"
+ id="path4817-4"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14588"
+ transform="translate(-42.000002,25.000005)">
+ <path
+ id="path14541"
+ d="m 153.5,-9 c -0.27613,2.76e-5 -0.49997,0.2238691 -0.5,0.5 v 8 c 3e-5,0.27613094 0.22387,0.499972391047 0.5,0.5 h 8 c 0.27613,-2.7608953e-5 0.49997,-0.22386906 0.5,-0.5 v -8 c -3e-5,-0.2761309 -0.22387,-0.4999724 -0.5,-0.5 z m 6.5,1 c 0.54636,0 1,0.4536376 1,1 0,0.5463624 -0.45364,1 -1,1 -0.54636,0 -1,-0.4536376 -1,-1 0,-0.5463624 0.45364,-1 1,-1 z m -2.98047,1.75 c 0.17034,0.00643 0.32566,0.099184 0.41211,0.2460938 l 2.5,4.25 C 160.12825,-1.4202448 159.88728,-0.99936558 159.5,-1 h -5 c -0.38728,6.3442e-4 -0.62825,-0.4202448 -0.43164,-0.7539062 l 2.5,-4.25 c 0.0935,-0.1589489 0.26691,-0.2535338 0.45117,-0.2460938 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g14560"
+ transform="translate(147)"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 10.5,-14 c -0.276131,2.8e-5 -0.499972,0.223869 -0.5,0.5 v 3 c 2.8e-5,0.276131 0.223869,0.499972 0.5,0.5 h 9 c 0.276131,-2.8e-5 0.499972,-0.223869 0.5,-0.5 v -3 c -2.8e-5,-0.276131 -0.223869,-0.499972 -0.5,-0.5 z m 0.5,1 h 8 v 2 h -8 z m 5,7 v 1 h 3 v 2 h -3 v 1 h 3.5 c 0.276131,-2.76e-5 0.499972,-0.2238691 0.5,-0.5 v -3 c -2.8e-5,-0.2761309 -0.223869,-0.4999724 -0.5,-0.5 z"
+ id="path14558"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccc" />
</g>
</g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g7388-6" transform="translate(731,-238)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <rect transform="scale(-1,1)" style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate" id="rect7384-9" width="16" height="16" x="437" y="710"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m -447.96289,710.98828 a 1.0001,1.0001 0 0 0 -0.83789,0.41211 c -3.30626,4.40835 -3.18183,10.96743 -3.18555,12.58399 a 1.0001,1.0001 0 1 0 2,0.006 c 0.004,-1.64212 0.0934,-7.79897 2.78711,-11.39062 a 1.0001,1.0001 0 0 0 -0.76367,-1.61133 z m 4.97461,3.00195 a 1.0001,1.0001 0 0 0 -0.69727,0.28125 c -2.25424,2.12239 -3.3739,3.98924 -3.89062,5.64258 C -448.0929,721.56741 -448,722.96385 -448,724 a 1.0001,1.0001 0 1 0 2,0 c 0,-1.13631 -0.0696,-2.20308 0.33203,-3.48828 0.40167,-1.28521 1.28135,-2.83224 3.35352,-4.7832 a 1.0001,1.0001 0 0 0 -0.67383,-1.73829 z m 3.94531,4.00782 a 1.0001,1.0001 0 0 0 -0.16797,0.0234 C -441.66808,718.54973 -444,720.82862 -444,724 a 1.0001,1.0001 0 1 0 2,0 c 0,-2.17354 1.66808,-3.68979 3.21094,-4.02148 a 1.0001,1.0001 0 0 0 -0.25391,-1.98047 z" id="path7133-7" inkscape:connector-curvature="0"/>
- </g>
- <path inkscape:connector-curvature="0" id="path13682" d="m 100.45117,431 c -0.36065,0.005 -0.725199,0.0666 -1.080078,0.1875 -1.419514,0.48381 -2.371094,1.8128 -2.371094,3.3125 a 0.50005006,0.50005006 0 1 1 -1,0 c 0,-0.53249 0.102694,-1.04562 0.277344,-1.52734 -0.0921,0.0103 -0.173784,0.0274 -0.277344,0.0273 -3.307786,0 -6,2.69221 -6,6 0,3.30779 2.692214,6 6,6 3.307786,0 6.000002,-2.69221 6.000002,-6 v -0.002 c -4.7e-4,-0.11093 0.014,-0.19694 0.0332,-0.27344 -0.83987,0.3046 -1.77022,0.36483 -2.67578,0.12695 a 0.50005006,0.50005006 0 1 1 0.253906,-0.96679 c 1.450494,0.38101 2.978064,-0.20116 3.806644,-1.45118 0.82858,-1.25001 0.7694,-2.88277 -0.14649,-4.07031 -0.68691,-0.89068 -1.73836,-1.37897 -2.82031,-1.36328 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g14534">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 100.24805,410.01367 c -1.271268,0.11136 -2.328782,0.98616 -2.845706,2.17774 -2.575841,-0.61979 -5.266939,0.50372 -6.597656,2.80859 -1.356612,2.34971 -0.965414,5.32365 0.953124,7.24219 1.918537,1.91853 4.892473,2.30974 7.242188,0.95312 2.30486,-1.33072 3.42838,-4.02182 2.80859,-6.59765 1.3618,-0.59077 2.3103,-1.88718 2.17774,-3.40235 -0.14775,-1.68875 -1.49289,-3.03389 -3.18164,-3.18164 -0.1894,-0.0166 -0.37503,-0.0159 -0.55664,0 z m 0.0234,0.9961 c 0.14685,-0.0133 0.29578,-0.0133 0.44727,0 1.21193,0.10603 2.16545,1.05955 2.27148,2.27148 0.10604,1.21192 -0.66865,2.31795 -1.84375,2.63281 a 0.50005006,0.50005006 0 0 0 -0.35937,0.58203 l 0.0352,0.17969 a 0.50005006,0.50005006 0 0 0 0.008,0.0293 c 0.58634,2.18824 -0.36816,4.49227 -2.33008,5.625 -1.961931,1.13272 -4.433244,0.80698 -6.035156,-0.79492 -1.601912,-1.60191 -1.927645,-4.07323 -0.794922,-6.03516 1.132722,-1.96193 3.43675,-2.91642 5.625,-2.33008 a 0.50005006,0.50005006 0 0 0 0.0293,0.008 l 0.179687,0.0352 a 0.50005006,0.50005006 0 0 0 0.582032,-0.35937 c 0.275511,-1.02822 1.157648,-1.75045 2.185539,-1.84375 z M 94.5,416 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 A 0.50005,0.50005 0 0 0 97.5,416 Z m 0.5,1 h 2 v 2 h -2 z" transform="translate(1.8536743e-6,-4.4999696e-6)" id="circle13742" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14020" transform="translate(153.00001,38.000005)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m -76.5,394 -3.751953,0.006 c -0.228491,0.001 -0.427071,0.15722 -0.482422,0.37891 l -1.25,4.99414 c -0.07853,0.31517 0.159565,0.6204 0.484375,0.62095 h 3.75 c 0.22922,-3.6e-4 0.428845,-0.15652 0.484375,-0.37891 l 1.25,-5 C -75.936984,394.30587 -76.175116,394.00052 -76.5,394 Z m 6,0 -3.751953,0.006 c -0.228491,0.001 -0.427071,0.15722 -0.482422,0.37891 l -1.25,4.99414 c -0.07853,0.31517 0.159565,0.6204 0.484375,0.62095 h 3.75 c 0.22922,-3.6e-4 0.428845,-0.15652 0.484375,-0.37891 l 1.25,-5 C -69.936984,394.30587 -70.175116,394.00052 -70.5,394 Z m -8,7 -3.751953,0.006 c -0.228491,0.001 -0.427071,0.15722 -0.482422,0.37891 l -1.25,4.99414 c -0.07853,0.31517 0.159565,0.6204 0.484375,0.62095 h 3.75 c 0.22922,-3.6e-4 0.428845,-0.15652 0.484375,-0.37891 l 1.25,-5 C -77.936984,401.30587 -78.175116,401.00052 -78.5,401 Z m 6,0 -3.751953,0.006 c -0.228491,0.001 -0.427071,0.15722 -0.482422,0.37891 l -1.25,4.99414 c -0.07853,0.31517 0.159565,0.6204 0.484375,0.62095 h 3.75 c 0.22922,-3.6e-4 0.428845,-0.15652 0.484375,-0.37891 l 1.25,-5 C -71.936984,401.30587 -72.175116,401.00052 -72.5,401 Z" id="path13999" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 11.455078,430.98242 a 1.50015,1.50015 0 0 0 -1.4765624,1.52149 v 6.3789 l -3.5605468,3.56055 a 1.50015,1.50015 0 1 0 2.1210937,2.12109 l 3.5605465,-3.56054 h 6.378907 a 1.50015,1.50015 0 1 0 0,-3 h -5.5 v -5.5 a 1.50015,1.50015 0 0 0 -1.523438,-1.52149 z" id="path12350-2" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 199.50586,431 c -0.31034,2.7e-4 -0.5455,0.28021 -0.49219,0.58594 0.36378,2.06995 0.21088,3.24033 -0.13086,3.98828 -0.34174,0.74794 -0.89741,1.14621 -1.5625,1.65234 -0.66509,0.50614 -1.42742,1.12518 -1.87304,2.24414 -0.44562,1.11896 -0.57595,2.68203 -0.19141,5.10742 0.0385,0.24306 0.24806,0.422 0.49414,0.42188 h 8.75586 c 0.30739,1.4e-4 0.54213,-0.27449 0.49414,-0.57812 -0.36857,-2.32471 -0.21903,-3.70089 0.13086,-4.58204 0.34989,-0.88114 0.89751,-1.32255 1.54492,-1.8164 0.64741,-0.49385 1.4068,-1.03318 1.86328,-2.03516 0.45648,-1.00198 0.58623,-2.39428 0.20313,-4.57422 C 208.70043,431.17484 208.49284,431.0002 208.25,431 Z" id="path8644-7" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccscccccssccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 96.5,473 c -2.087116,0 -3.478164,1.04607 -4.390625,2.1875 a 0.50024408,0.50024408 0 0 0 0.78125,0.625 C 93.690488,474.81193 94.734388,474 96.5,474 c 2.098393,0 3.134109,0.87695 3.75195,1.94531 C 100.8698,477.01367 101,478.31651 101,479 h -5.25 c -1.273438,0 -2.443243,0.36418 -3.314453,1.05469 -0.87121,0.69051 -1.427734,1.72791 -1.427735,2.94531 10e-7,1.2174 0.556525,2.2548 1.427735,2.94531 C 93.306757,486.63582 94.476562,487 95.75,487 h 0.75 c 1.755585,0 3.387714,-0.96684 4.53711,-2.0332 0.0781,0.53303 0.28951,1.00434 0.64062,1.35547 C 102.12862,486.77315 102.775,487 103.5,487 a 0.50005,0.50005 0 1 0 0,-1 c -0.525,0 -0.87862,-0.14815 -1.11523,-0.38477 C 102.14815,485.37862 102,485.025 102,484.5 V 479 c 0,-0.79721 -0.12242,-2.24322 -0.88086,-3.55469 C 100.3607,474.13385 98.896459,473 96.5,473 Z m -0.75,7 H 101 v 3.56055 C 100.04582,484.68473 98.18875,486 96.5,486 h -0.75 c -1.081007,0 -2.03187,-0.31555 -2.693359,-0.83984 -0.66149,-0.52429 -1.048828,-1.23676 -1.048829,-2.16016 10e-7,-0.9234 0.387339,-1.63587 1.048829,-2.16016 C 93.718131,480.31555 94.668993,480 95.75,480 Z" id="path10278-2" inkscape:connector-curvature="0"/>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g12310-0" transform="translate(62.999998,210)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 222,431 c -0.1326,2e-5 -0.25976,0.0527 -0.35352,0.14648 L 218.79297,434 H 216.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 7 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2.29297 l 2.85351,2.85352 c 0.0938,0.0938 0.22092,0.14646 0.35352,0.14648 h 0.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 431.78125 431.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 6.4668,2.01562 a 0.50005,0.50005 0 0 0 -0.42188,0.72071 c 1.27607,2.70648 1.27328,5.84072 -0.008,8.54492 a 0.50017783,0.50017783 0 1 0 0.9043,0.42773 c 1.40867,-2.97397 1.41099,-6.42391 0.008,-9.40039 a 0.50005,0.50005 0 0 0 -0.48242,-0.29297 z m -2.86133,0.9375 a 0.50005,0.50005 0 0 0 -0.43359,0.74219 c 1.10286,2.06013 1.1045,4.5334 0.006,6.59571 a 0.50023236,0.50023236 0 1 0 0.88282,0.4707 c 1.25518,-2.35583 1.25221,-5.18378 -0.008,-7.53711 a 0.50005,0.50005 0 0 0 -0.44726,-0.27149 z" transform="translate(-62.999998,-210)" id="path12304-9" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14668"
+ transform="matrix(-1,0,0,1,530,30.000005)">
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 258.5,-19 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 13 c 3e-5,0.2761309 0.22387,0.4999724 0.5,0.5 h 13 c 0.27613,-2.76e-5 0.49997,-0.2238691 0.5,-0.5 v -13 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m 1.5,2 h 6 v 4 h 4 v 6 h -6 v -4 h -4 z"
+ id="path14664" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.5;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.89999986;marker:none;enable-background:accumulate"
+ d="m 260,-17 h 6 v 4 h -2 v 2 h -4 z"
+ id="path14666"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.55;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 261.03125,601 C 260.46859,601 260,601.46859 260,602.03125 v 7.9375 c 0,0.56266 0.46859,1.03125 1.03125,1.03125 h 7.9375 C 269.53141,611 270,610.53141 270,609.96875 v -7.9375 C 270,601.46859 269.53141,601 268.96875,601 Z m 0,1 h 7.9375 c 0.026,0 0.0312,0.005 0.0312,0.0312 v 7.9375 c 0,0.026 -0.005,0.0312 -0.0312,0.0312 h -7.9375 c -0.026,0 -0.0312,-0.005 -0.0312,-0.0312 v -7.9375 c 0,-0.026 0.005,-0.0312 0.0312,-0.0312 z"
+ id="rect13790"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path13905"
+ d="M 282.03125,601 C 281.46859,601 281,601.46859 281,602.03125 v 7.9375 c 0,0.56266 0.46859,1.03125 1.03125,1.03125 h 7.9375 C 290.53141,611 291,610.53141 291,609.96875 v -7.9375 C 291,601.46859 290.53141,601 289.96875,601 Z m 6.94922,1.99023 a 1.0001,1.0001 0 0 1 0.72656,1.7168 l -4,4 a 1.0001,1.0001 0 0 1 -1.41406,0 l -2,-2 a 1.0001,1.0001 0 1 1 1.41406,-1.41406 l 1.29297,1.29297 3.29297,-3.29297 a 1.0001,1.0001 0 0 1 0.6875,-0.30274 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 265,622 c -2.7555,0 -5,2.2445 -5,5 0,2.7555 2.2445,5 5,5 2.7555,0 5,-2.2445 5,-5 0,-2.7555 -2.2445,-5 -5,-5 z m 0,1 c 2.21506,0 4,1.78494 4,4 0,2.21506 -1.78494,4 -4,4 -2.21506,0 -4,-1.78494 -4,-4 0,-2.21506 1.78494,-4 4,-4 z"
+ id="path13966"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 286,622 c -2.7555,0 -5,2.2445 -5,5 0,2.7555 2.2445,5 5,5 2.7555,0 5,-2.2445 5,-5 0,-2.7555 -2.2445,-5 -5,-5 z"
+ id="circle13982"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 220.4707,623.75 c -0.26463,0.0156 -0.47113,0.23492 -0.4707,0.5 v 4.25 c 1.7e-4,0.35718 0.36395,0.59902 0.69336,0.46094 l 4.75,-2 c 0.39771,-0.16741 0.41088,-0.72615 0.0215,-0.91211 l -4.75,-2.25 c -0.076,-0.0366 -0.15996,-0.0534 -0.24416,-0.0488 z"
+ id="path14031"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 370,625 c -1.09865,0 -2,0.90135 -2,2 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 0,-1.09865 -0.90135,-2 -2,-2 z"
+ id="circle14040"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 28.5,431 a 1.50015,1.50015 0 0 0 -1.341797,2.16992 l 5.5,11 a 1.50015,1.50015 0 0 0 2.683594,0 l 5.5,-11 A 1.50015,1.50015 0 0 0 39.5,431 Z m 2.425781,3 h 6.148438 L 34,440.14648 Z"
+ id="path14201"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 306.49219,577.99219 A 0.50004997,0.50004997 0 0 0 306,578.5 v 2.79297 l -2.14648,-2.14649 a 0.50004997,0.50004997 0 1 0 -0.70704,0.70704 L 306,582.70703 v 0.58203 c -0.58959,0.34718 -0.99219,0.98165 -0.99219,1.71094 h -0.30078 l -2.85351,-2.85352 a 0.50004997,0.50004997 0 0 0 -0.35938,-0.15234 0.50004997,0.50004997 0 0 0 -0.34766,0.85938 L 303.29297,585 H 300.5 a 0.50004997,0.50004997 0 1 0 0,1 h 2.79297 l -2.14649,2.14648 a 0.50004997,0.50004997 0 1 0 0.70704,0.70704 L 304.70703,586 h 0.58203 c 0.34718,0.58959 0.98165,0.99219 1.71094,0.99219 v 0.30078 l -2.85352,2.85351 a 0.50004997,0.50004997 0 1 0 0.70704,0.70704 L 307,588.70703 V 591.5 a 0.50004997,0.50004997 0 1 0 1,0 v -2.79297 l 2.14648,2.14649 a 0.50004997,0.50004997 0 1 0 0.70704,-0.70704 L 308,587.29297 v -0.58203 c 0.58959,-0.34718 0.99219,-0.98165 0.99219,-1.71094 h 0.30078 l 2.85351,2.85352 a 0.50004997,0.50004997 0 1 0 0.70704,-0.70704 L 310.70703,585 H 313.5 a 0.50004997,0.50004997 0 1 0 0,-1 h -2.79297 l 2.14649,-2.14648 a 0.50004997,0.50004997 0 0 0 -0.36329,-0.85743 0.50004997,0.50004997 0 0 0 -0.34375,0.15039 L 309.29297,584 h -0.58203 c -0.34718,-0.58959 -0.98165,-0.99219 -1.71094,-0.99219 v -0.30078 l 2.85352,-2.85351 a 0.50004997,0.50004997 0 1 0 -0.70704,-0.70704 L 307,581.29297 V 578.5 a 0.50004997,0.50004997 0 0 0 -0.50781,-0.50781 z M 307,584.00781 c 0.55427,0 0.99219,0.43792 0.99219,0.99219 0,0.55427 -0.43792,0.99219 -0.99219,0.99219 -0.55427,0 -0.99219,-0.43792 -0.99219,-0.99219 0,-0.55427 0.43792,-0.99219 0.99219,-0.99219 z"
+ id="path14282"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14048"
+ transform="translate(294,571)">
+ <g
+ transform="matrix(-0.53033009,-0.53033009,-0.53033009,0.53033009,472.85846,-15.235808)"
+ id="g13853"
+ style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 306.99023,243.60938 a 0.66673335,0.66673335 0 0 0 -0.65625,0.67578 v 4.99023 h -4.99023 a 0.666995,0.666995 0 1 0 0,1.33399 h 4.99023 v 4.99023 a 0.66673335,0.66673335 0 1 0 1.33204,0 v -4.99023 h 4.99023 a 0.666995,0.666995 0 1 0 0,-1.33399 h -4.99023 v -4.99023 a 0.66673335,0.66673335 0 0 0 -0.67579,-0.67578 z"
+ id="path13850"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 177.49219,-56.007812 A 0.50005,0.50005 0 0 0 177,-55.5 v 6 a 0.50005,0.50005 0 1 0 1,0 V -52 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 H 178 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 7.00195,0.002 a 0.50005,0.50005 0 0 0 -0.34766,0.859375 l 2.64649,2.646484 -2.64649,2.646484 a 0.50005,0.50005 0 1 0 0.70704,0.707032 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.707032 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.152343 z M 180.5,-53 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path13907"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="rotate(-180,275.49999,225.99747)"
+ id="g14033">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 184.49414,-76.005859 c -0.4494,8.8e-5 -0.67059,0.546839 -0.34766,0.859375 l 2.64649,2.646484 -2.64649,2.646484 c -0.4905,0.471264 0.23578,1.197538 0.70704,0.707032 l 3,-3 c 0.19518,-0.195265 0.19518,-0.511767 0,-0.707032 l -3,-3 c -0.0942,-0.09737 -0.2239,-0.152345 -0.35938,-0.152343 z M 175.49219,-73 c -0.27615,0.0043 -0.49651,0.231666 -0.49219,0.507812 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z m 5.00781,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m 3,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m -6,0.0078 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z M 175.49219,-70 c -0.27615,0.0043 -0.49651,0.231666 -0.49219,0.507812 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z"
+ id="path14029"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 175.5,-67 c -0.8225,0 -1.5,0.677495 -1.5,1.5 0,0.822505 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.677495 1.5,-1.5 0,-0.822505 -0.6775,-1.5 -1.5,-1.5 z"
+ id="circle14031"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14223"
+ transform="rotate(-180,317.49493,236.50149)">
+ <g
+ style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none"
+ id="g14219"
+ transform="matrix(-0.53033009,-0.53033009,-0.53033009,0.53033009,472.85846,-15.235808)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 306.99023,243.60938 a 0.66673335,0.66673335 0 0 0 -0.65625,0.67578 v 4.99023 h -4.99023 a 0.666995,0.666995 0 1 0 0,1.33399 h 4.99023 v 4.99023 a 0.66673335,0.66673335 0 1 0 1.33204,0 v -4.99023 h 4.99023 a 0.666995,0.666995 0 1 0 0,-1.33399 h -4.99023 v -4.99023 a 0.66673335,0.66673335 0 0 0 -0.67579,-0.67578 z"
+ id="path14217"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 177.49219,-56.007812 A 0.50005,0.50005 0 0 0 177,-55.5 v 6 a 0.50005,0.50005 0 1 0 1,0 V -52 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 H 178 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 7.00195,0.002 a 0.50005,0.50005 0 0 0 -0.34766,0.859375 l 2.64649,2.646484 -2.64649,2.646484 a 0.50005,0.50005 0 1 0 0.70704,0.707032 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.707032 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.152343 z M 180.5,-53 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14221"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14371"
+ transform="matrix(1,0,0,-1,336,494)">
+ <g
+ transform="matrix(1,0,0,-1,0,-99.00505)"
+ id="g14352"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 520.49414,515 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 2.64649,2.64648 -2.64649,2.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.70704 l -3,-3 A 0.50005,0.50005 0 0 0 520.49414,515 Z m 0.0332,2.99414 a 0.50005,0.50005 0 0 0 -0.14843,0.0215 l -1,0.25 a 0.50005,0.50005 0 0 0 0.0937,0.98633 0.50005,0.50005 0 0 0 0.14843,-0.0176 l 1,-0.25 a 0.50005,0.50005 0 0 0 -0.0937,-0.99024 z m -3,0.75 a 0.50005,0.50005 0 0 0 -0.14843,0.0215 l -1,0.25 a 0.50005,0.50005 0 0 0 0.0937,0.98633 0.50005,0.50005 0 0 0 0.14843,-0.0176 l 1,-0.25 a 0.50005,0.50005 0 0 0 -0.0937,-0.99024 z m -3.02343,1.24805 a 0.50005,0.50005 0 0 0 -0.35743,0.15429 l -1,1 a 0.50005,0.50005 0 0 0 0.34766,0.85938 0.50005,0.50005 0 0 0 0.35938,-0.15234 l 1,-1 a 0.50005,0.50005 0 0 0 -0.34961,-0.86133 z m -1.9961,3 A 0.50005,0.50005 0 0 0 512,523.5 v 1 a 0.50005,0.50005 0 0 0 0.49219,0.50781 A 0.50005,0.50005 0 0 0 513,524.5 v -1 a 0.50005,0.50005 0 0 0 -0.49219,-0.50781 z"
+ transform="translate(-336,-593.00505)"
+ id="path14350"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 176.5,-32 c 0.8225,0 1.5,-0.677495 1.5,-1.5 0,-0.822505 -0.6775,-1.5 -1.5,-1.5 -0.8225,0 -1.5,0.677495 -1.5,1.5 0,0.822505 0.6775,1.5 1.5,1.5 z"
+ id="circle14357"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14377"
+ transform="translate(210,592)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 184.49414,-76.005859 c -0.4494,8.8e-5 -0.67059,0.546839 -0.34766,0.859375 l 2.64649,2.646484 -2.64649,2.646484 c -0.4905,0.471264 0.23578,1.197538 0.70704,0.707032 l 3,-3 c 0.19518,-0.195265 0.19518,-0.511767 0,-0.707032 l -3,-3 c -0.0942,-0.09737 -0.2239,-0.152345 -0.35938,-0.152343 z M 175.49219,-73 c -0.27615,0.0043 -0.49651,0.231666 -0.49219,0.507812 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z m 5.00781,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m 3,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m -6,0.0078 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z M 175.49219,-70 c -0.27615,0.0043 -0.49651,0.231666 -0.49219,0.507812 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z"
+ id="path14373"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 175.5,-67 c -0.8225,0 -1.5,0.677495 -1.5,1.5 0,0.822505 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.677495 1.5,-1.5 0,-0.822505 -0.6775,-1.5 -1.5,-1.5 z"
+ id="circle14375"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="matrix(-1,0,0,1,676.99998,550)"
+ id="g14389">
+ <g
+ id="g14381"
+ transform="matrix(1,0,0,-1,0,-99.00505)"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 500.50586,518.99219 A 0.50005,0.50005 0 0 0 500,519.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.49219,-0.50781 0.50005,0.50005 0 0 1 -0.002,0 z m -8.00977,2.99609 a 0.50005,0.50005 0 0 0 -0.34961,0.15234 l -3,3 a 0.50005,0.50005 0 0 0 0,0.70704 l 3,3 a 0.50005,0.50005 0 0 0 0.35938,0.15234 0.50005,0.50005 0 0 0 0.34766,-0.85938 l -2.64649,-2.64648 2.64649,-2.64648 a 0.50005,0.50005 0 0 0 -0.35743,-0.85938 z m 7.00977,0.006 a 0.50005,0.50005 0 0 0 -0.35938,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.34766,-0.85938 z m -3.0293,2.00391 a 0.50005,0.50005 0 0 0 -0.0976,0.0176 l -1,0.25 a 0.50005,0.50005 0 1 0 0.24218,0.96876 l 1,-0.25 a 0.50005,0.50005 0 0 0 -0.0937,-0.98633 0.50005,0.50005 0 0 0 -0.0508,0 z m -3,0.75 a 0.50005,0.50005 0 0 0 -0.0976,0.0176 l -1,0.25 a 0.50005,0.50005 0 1 0 0.24218,0.96876 l 1,-0.25 a 0.50005,0.50005 0 0 0 -0.0937,-0.98633 0.50005,0.50005 0 0 0 -0.0508,0 z"
+ transform="rotate(-180,338.49999,225.49747)"
+ id="path14379"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 176.5,-32 c 0.8225,0 1.5,-0.677495 1.5,-1.5 0,-0.822505 -0.6775,-1.5 -1.5,-1.5 -0.8225,0 -1.5,0.677495 -1.5,1.5 0,0.822505 0.6775,1.5 1.5,1.5 z"
+ id="circle14385"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 412,120 c -1.65093,0 -3,1.34907 -3,3 0,1.65093 1.34907,3 3,3 1.65093,0 3,-1.34907 3,-3 0,-1.65093 -1.34907,-3 -3,-3 z m 0,1 c 1.11049,0 2,0.88951 2,2 0,1.11049 -0.88951,2 -2,2 -1.11049,0 -2,-0.88951 -2,-2 0,-1.11049 0.88951,-2 2,-2 z"
+ id="circle14295"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 13.492188,54.005859 a 0.50005,0.50005 0 0 0 -0.345704,0.146485 l -3.9999996,4 a 0.50005,0.50005 0 1 0 0.7070312,0.707031 L 13,55.712891 v 9.792968 a 0.50005,0.50005 0 1 0 1,0 v -9.792968 l 3.146484,3.146484 a 0.50005,0.50005 0 1 0 0.707032,-0.707031 l -4,-4 a 0.50005,0.50005 0 0 0 -0.361328,-0.146485 z"
+ id="path14327"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 34.492188,54.005859 A 0.50005,0.50005 0 0 0 34,54.511719 v 9.792969 l -3.146484,-3.146485 a 0.50005,0.50005 0 1 0 -0.707032,0.707031 l 4,4 a 0.50005,0.50005 0 0 0 0.707032,0 l 4,-4 A 0.50005,0.50005 0 1 0 38.146484,61.158203 L 35,64.304688 v -9.792969 a 0.50005,0.50005 0 0 0 -0.507812,-0.50586 z"
+ id="path14329"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.79999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 202.5,621.00003 a 5.4999997,5.4999997 0 0 0 -5.5,5.5 5.4999997,5.4999997 0 0 0 5.5,5.5 5.4999997,5.4999997 0 0 0 5.5,-5.5 5.4999997,5.4999997 0 0 0 -5.5,-5.5 z m -0.002,1.98438 a 0.50005001,0.50005001 0 0 1 0.50781,0.52343 v 2.5 h 2.50195 a 0.50005001,0.50005001 0 1 1 0,0.99805 h -2.50195 v 2.50195 a 0.50005001,0.50005001 0 0 1 -0.50586,0.50586 0.50005001,0.50005001 0 0 1 -0.49219,-0.50586 v -2.50195 h -2.5 a 0.50005001,0.50005001 0 1 1 0,-0.99805 h 2.5 v -2.5 a 0.50005001,0.50005001 0 0 1 0.49024,-0.52343 z"
+ id="path14370"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 33.75,200 c -0.212514,-4.2e-4 -0.402079,0.13353 -0.472656,0.33398 L 31.644531,205 H 27.5 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 0.75 c 4.22e-4,0.17006 0.08724,0.32824 0.230469,0.41992 l 3.166015,2.03711 -1.367187,3.87695 c -0.01909,0.0533 -0.029,0.10942 -0.0293,0.16602 v 0.75 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 0.75 c 0.119714,-2e-5 0.235448,-0.043 0.326172,-0.12109 L 33.935547,211 h 0.128906 l 3.359375,2.87891 c 0.09174,0.079 0.209022,0.12201 0.330078,0.12109 L 38.5,213.99414 c 0.273087,-0.002 0.49394,-0.223 0.496094,-0.49609 L 39,212.75195 c -7.9e-5,-0.0572 -0.01,-0.11407 -0.0293,-0.16797 l -1.367187,-3.87695 3.166015,-2.03711 C 40.912757,206.57824 40.999577,206.42006 41,206.25 v -0.75 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 h -4.144531 l -1.632813,-4.66602 C 34.652079,200.13353 34.462514,199.99958 34.25,200 h -0.251953 z"
+ id="path14398"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 12.75,200 a 0.50004997,0.50004997 0 0 0 -0.472656,0.33398 L 10.644531,205 H 6.5 A 0.50004997,0.50004997 0 0 0 6,205.5 v 0.75 a 0.50004997,0.50004997 0 0 0 0.2304688,0.41992 l 3.1660156,2.03711 -1.3671875,3.87695 A 0.50004997,0.50004997 0 0 0 8,212.75 v 0.75 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 0.75 a 0.50004997,0.50004997 0 0 0 0.3261719,-0.12109 L 12.935547,211 h 0.128906 l 3.359375,2.87891 A 0.50004997,0.50004997 0 0 0 16.753906,214 L 17.5,213.99414 a 0.50004997,0.50004997 0 0 0 0.496094,-0.49609 L 18,212.75195 a 0.50004997,0.50004997 0 0 0 -0.0293,-0.16797 l -1.367187,-3.87695 3.166015,-2.03711 A 0.50004997,0.50004997 0 0 0 20,206.25 V 205.5 A 0.50004997,0.50004997 0 0 0 19.5,205 h -4.144531 l -1.632813,-4.66602 A 0.50004997,0.50004997 0 0 0 13.25,200 h -0.251953 z m 0.25,1.30078 1.527344,4.36524 A 0.50004997,0.50004997 0 0 0 15,206 h 3.962891 l -3.232422,2.08008 a 0.50004997,0.50004997 0 0 0 -0.201172,0.58594 L 17,212.83398 l -0.002,0.16407 h -0.06445 l -3.357422,-2.87696 A 0.50004997,0.50004997 0 0 0 13.25,210 h -0.5 a 0.50004997,0.50004997 0 0 0 -0.326172,0.12109 L 9.0644531,213 H 9 v -0.16406 l 1.470703,-4.16992 a 0.50004997,0.50004997 0 0 0 -0.201172,-0.58594 L 7.0371094,206 H 11 a 0.50004997,0.50004997 0 0 0 0.472656,-0.33398 z"
+ id="path14401"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="translate(0.99996615,4.4999696e-6)"
+ id="g13708"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 48.5,578 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 L 47.9922,589 c 0,1.51667 1.219299,3 2.984374,3 1.765077,0 3.015625,-1.475 3.015626,-3 L 54,578.5 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z m 2.5,10 c 0.546362,0 1,0.45364 1,1 0,0.54636 -0.453638,1 -1,1 -0.546362,0 -1,-0.45364 -1,-1 0,-0.54636 0.453638,-1 1,-1 z"
+ transform="translate(-0.99998)"
+ id="path13694" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 58.492188,586 c -0.132599,2e-5 -0.259759,0.0527 -0.353516,0.14648 l -4.75,4.75 c -0.09377,0.0938 -0.14646,0.22092 -0.146484,0.35352 v 0.25 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 H 60.5 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -5 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ id="path13696"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 56.486328,579 c -0.130565,0.002 -0.25534,0.0541 -0.347656,0.14648 l -2,2 c -0.09377,0.0938 -0.14646,0.22092 -0.146484,0.35352 v 6 c 1.71e-4,0.44532 0.538516,0.6683 0.853515,0.35352 l 5,-5 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -3,-3 C 56.750515,579.05126 56.620954,578.99846 56.486328,579 Z"
+ id="path13698"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccc" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g9998"
+ transform="matrix(-1,0,0,1,907.99986,4.6999695e-6)">
+ <g
+ transform="matrix(-0.61504365,0,0,0.61502939,510.71013,122.71015)"
+ id="g13879"
+ style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.6259197;enable-background:new" />
+ <g
+ id="g9988"
+ style="fill:#ffffff">
+ <path
+ id="path13882"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 478.49219,473.00781 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,10e-6 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.0053,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66922,10e-6 -1.3386,0 -2.00781,0 z m -0.49233,3.9922 2.99609,0.006 c 0.2754,6.1e-4 0.49976,0.22265 0.5,0.49805 l 0.004,6.45885 c 0,1.02328 -0.80629,2.03747 -2,2.03711 -1.19534,0 -1.99609,-1.02155 -1.99609,-2.04297 l -0.004,-6.45704 c 1.8e-4,-0.27638 0.22362,-0.50048 0.5,-0.5 z m 1.5,6 a 1,0.99999999 0 0 0 -1,1.00001 1,0.99999999 0 0 0 1,1 1,0.99999999 0 0 0 1,-1 1,0.99999999 0 0 0 -1,-1.00001 z"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path13884"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 469.49219,474.00781 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,10e-6 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.0053,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66922,10e-6 -1.3386,0 -2.00781,0 z m 5.5151,2.99233 c 0.12999,0.002 0.25408,0.0546 0.34596,0.14655 l 1.00065,0.99942 c 0.094,0.094 0.14673,0.22146 0.14655,0.35436 v 4.0001 c 2e-5,0.4458 -0.53925,0.66879 -0.85409,0.35316 l -2.99954,-3.00067 c -0.19472,-0.19518 -0.19472,-0.51115 0,-0.70633 l 2.00009,-2.00004 c 0.0954,-0.0955 0.2254,-0.14835 0.36038,-0.14655 z"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path13886"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 468.49219,483.00781 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,10e-6 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.0053,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66922,10e-6 -1.3386,0 -2.00781,0 z m 4.52221,-1.00695 c 0.12731,0.004 0.24847,0.0555 0.33876,0.14535 l 3.00074,3.00066 c 0.31399,0.31533 0.0906,0.8529 -0.35437,0.85288 h -2.99954 c -0.27591,-1.9e-4 -0.49954,-0.22381 -0.49972,-0.49972 v -2.99946 c 7e-5,-0.28163 0.23261,-0.50765 0.51413,-0.49971 z"
+ inkscape:connector-curvature="0" />
+ </g>
</g>
- <g id="g5260" transform="translate(21,42)" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="path13014" d="m 176.5,410 a 0.50005,0.50005 0 1 0 0,1 h 0.79297 L 178,411.70703 v 10.58594 L 177.29297,423 H 176.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 0.64648,-0.64649 0.64648,0.64649 A 0.50005,0.50005 0 0 0 179.5,424 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -0.79297 L 179,422.29297 V 411.70703 L 179.70703,411 H 180.5 a 0.50005,0.50005 0 1 0 0,-1 h -1 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -0.64648,0.64649 -0.64648,-0.64649 A 0.50005,0.50005 0 0 0 177.5,410 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path inkscape:connector-curvature="0" id="path13066" d="m 174.5,414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2.5 v -1 h -2 v -4 h 2 v -1 z m 5.5,0 v 1 h 7.00781 v 4 H 180 v 1 h 7.50781 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g13176" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 14,472 c -0.486111,0 -0.97894,0.16032 -1.363281,0.50195 C 12.252378,472.84359 12,473.375 12,474 v 4 H 8.5 c -0.2761309,3e-5 -0.4999724,0.22387 -0.5,0.5 v 4 c 0,0.33333 -0.182083,0.72505 -0.4785156,1.02148 C 7.2250518,483.81792 6.8333333,484 6.5,484 c -0.2761309,3e-5 -0.4999724,0.22387 -0.5,0.5 v 2 c 2.76e-5,0.27613 0.2238691,0.49997 0.5,0.5 h 3 c 0.1325988,-2e-5 0.259759,-0.0527 0.3535156,-0.14648 L 11,485.70703 V 486.5 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 5 c 1.777778,0 3.5,-1.46429 3.5,-3.5 v -5 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 H 16 v -4 c 0,-0.625 -0.252378,-1.15641 -0.636719,-1.49805 C 14.97894,472.16032 14.486111,472 14,472 Z m 0,1 c 0.263889,0 0.52106,0.0897 0.699219,0.24805 C 14.877378,473.40641 15,473.625 15,474 v 4 h -0.5 c -0.676161,-0.01 -0.676161,1.00956 0,1 H 19 v 1 H 9 v -1 h 3.5 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 V 474 c 0,-0.375 0.122622,-0.59359 0.300781,-0.75195 C 13.47894,473.08968 13.736111,473 14,473 Z m -5,8 h 10 v 2.5 c 0,1.46429 -1.277778,2.5 -2.5,2.5 H 16 v -1.5 c 0.0044,-0.28227 -0.225547,-0.51223 -0.507812,-0.50781 C 15.216044,483.9965 14.995681,484.22386 15,484.5 v 1.5 h -3 v -1.5 c -1.7e-4,-0.44532 -0.538517,-0.6683 -0.853516,-0.35352 L 9.2929688,486 H 7 v -1.22266 C 7.4441801,484.6575 7.9061001,484.55093 8.2285156,484.22852 8.682083,483.77495 9,483.16667 9,482.5 Z" transform="translate(1.8536743e-6,-4.4999696e-6)" id="path5504-6" inkscape:connector-curvature="0" sodipodi:nodetypes="scsccccccccccccccsccccscsscscccccccccscsccssccccccccccccsc"/>
- </g>
- <g transform="translate(-664,-513.00021)" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" id="g8745-3" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 475.25,53 a 0.50005,0.50005 0 0 0 -0.21289,0.04687 l -5.75391,2.708984 a 0.50005,0.50005 0 0 0 -0.28515,0.453125 v 7.292969 a 0.50005,0.50005 0 0 0 0.27539,0.447266 l 6.00195,3.001953 a 0.50005,0.50005 0 0 0 0.44727,0 l 6.00195,-3.001953 A 0.50005,0.50005 0 0 0 482,63.501953 v -6.916015 a 0.50005,0.50005 0 0 0 0,-0.181641 v -0.195313 a 0.50005,0.50005 0 0 0 -0.28711,-0.453125 l -5.75,-2.707031 A 0.50005,0.50005 0 0 0 475.75,53 Z m 0.11133,1 h 0.27734 l 5.00977,2.359375 -5.14844,2.509766 -5.14844,-2.509766 z M 469.99805,57.298828 475,59.738281 v 5.957031 l -5.00195,-2.501953 z M 481,57.300781 v 5.892578 l -5,2.5 v -5.955078 z" transform="translate(664,513.00021)" id="path8739-6" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-801.00006,344.99979)" id="g13204" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 1339.5,-270 a 0.50004994,0.50004994 0 1 0 0,1 h 6 a 0.50004994,0.50004994 0 1 0 0,-1 z m 0,3 a 0.50004994,0.50004994 0 1 0 0,1 h 6 a 0.50004994,0.50004994 0 1 0 0,-1 z m 0,3 a 0.50004994,0.50004994 0 1 0 0,1 h 6 a 0.50004994,0.50004994 0 1 0 0,-1 z m -7,3 a 0.50004994,0.50004994 0 1 0 0,1 h 13 a 0.50004994,0.50004994 0 1 0 0,-1 z m -0.014,3 a 0.50004994,0.50004994 0 1 0 0,1 h 13.0449 a 0.50004994,0.50004994 0 1 0 0,-1 z" id="path13198" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 1332.4922,-263 c -0.2761,-0.004 -0.4965,-0.23166 -0.4922,-0.50781 v -5.08789 c 0,-0.86662 0.4883,-1.66406 1.2578,-2.08789 0.7696,-0.42387 1.709,-0.42387 2.4785,0 0.7695,0.42383 1.2559,1.22127 1.2559,2.08789 v 5.08789 c 0.01,0.67616 -1.0096,0.67616 -1,0 V -266 H 1333 v 2.49219 c 0,0.28226 -0.2255,0.51222 -0.5078,0.50781 z m 0.5078,-4 h 2.9922 v -1.5957 c 0,-0.49379 -0.2728,-0.95455 -0.7383,-1.21094 -0.4655,-0.25638 -1.0482,-0.25638 -1.5137,0 -0.4655,0.25639 -0.7402,0.71715 -0.7402,1.21094 z" id="path13202" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccsccsc"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 114.49219,166.99219 A 0.50005,0.50005 0 0 0 114,167.5 v 1.5 h -2.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 1 0 1,0 V 170 h 2.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" id="path4913-5-0" inkscape:connector-curvature="0"/>
- <g style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new" id="g10431-7" transform="matrix(1,0,0,-1,52.999998,288.99725)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96"/>
- <g transform="translate(62.999998,189)" id="g13463" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 221.5,410 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 218.29297,413 H 216.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 7 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.79297 l 2.85351,2.85352 A 0.50005,0.50005 0 0 0 221.5,424 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 410.78125 410.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 222 v 12 h -0.29297 l -2.85351,-2.85352 A 0.50005,0.50005 0 0 0 218.5,420 H 217 v -6 h 1.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 z m 6.75977,1.01562 a 0.50005,0.50005 0 0 0 -0.42188,0.72071 c 1.27607,2.70648 1.27328,5.84072 -0.008,8.54492 a 0.50017783,0.50017783 0 1 0 0.9043,0.42773 c 1.40867,-2.97397 1.41099,-6.42391 0.008,-9.40039 a 0.50005,0.50005 0 0 0 -0.48242,-0.29297 z m -2.86133,0.9375 a 0.50005,0.50005 0 0 0 -0.43359,0.74219 c 1.10286,2.06013 1.1045,4.5334 0.006,6.59571 a 0.50023236,0.50023236 0 1 0 0.88282,0.4707 c 1.25518,-2.35583 1.25221,-5.18378 -0.008,-7.53711 a 0.50005,0.50005 0 0 0 -0.44726,-0.27149 z" transform="translate(-62.999998,-189)" id="path13456" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-274.03132,440.00025)" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" id="g13513" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.75542808px;marker:none;enable-background:accumulate" d="m 220.5,536 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9.64062 a 1.8365096,2.6222708 64.987834 0 0 -1.98242,0.0723 1.8365096,2.6222708 64.987834 0 0 -1.9707,2.68555 1.8365096,2.6222708 64.987834 0 0 2.93554,0.88867 1.8365096,2.6222708 64.987834 0 0 2.00977,-2.18945 A 0.50005,0.50005 0 0 0 221,547.5 V 547.47461 538 h 8 v 7.14062 a 1.8365125,2.6222911 64.988434 0 0 -1.98242,0.0723 1.8365125,2.6222911 64.988434 0 0 -1.9707,2.68555 1.8365125,2.6222911 64.988434 0 0 2.93554,0.88867 1.8365125,2.6222911 64.988434 0 0 2.00977,-2.18945 A 0.50005,0.50005 0 0 0 230,546.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z" transform="translate(274.03132,-440.00025)" id="ellipse13504" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" id="g12940-5" style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 411.49219,577.94727 A 0.50005,0.50005 0 0 0 411,578.45508 v 7 a 0.50005,0.50005 0 1 0 1,0 v -7 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 408.47656,580 a 0.50005,0.50005 0 0 0 -0.22265,0.0684 c -2.54449,1.43695 -3.79437,4.38222 -3.03125,7.16797 0.76312,2.78575 3.34282,4.71875 6.27734,4.71875 2.93452,0 5.51422,-1.933 6.27734,-4.71875 0.76312,-2.78575 -0.48676,-5.73102 -3.03125,-7.16797 a 0.50025967,0.50025967 0 1 0 -0.49218,0.87109 c 2.15894,1.21922 3.20113,3.68764 2.55859,6.03321 -0.64254,2.34557 -2.81597,3.98242 -5.3125,3.98242 -2.49653,0 -4.66996,-1.63685 -5.3125,-3.98242 -0.64254,-2.34557 0.39965,-4.81399 2.55859,-6.03321 A 0.50005,0.50005 0 0 0 408.47656,580 Z" transform="translate(1.8536743e-6,-4.4999696e-6)" id="path12897-5" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g10027-7" transform="translate(109,-110)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path sodipodi:nodetypes="sssssccccccccccccc" inkscape:connector-curvature="0" id="path9906-8-8" d="m 264.5,688 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"/>
- <g id="g9914-5" transform="translate(99.99999,195.99938)" style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 366.48438,579 c -0.12718,0.004 -0.248,0.0564 -0.3379,0.14648 l -3,3 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 580 h 1.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -2 v 0.002 c -0.005,0 -0.0101,-0.002 -0.0156,-0.002 z M 363,584 v 7.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 10 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -5 c 0.01,-0.67616 -1.00956,-0.67616 -1,0 v 4.5 h -9 v -7 z" transform="translate(-208.99999,-85.99938)" id="path9910-5" inkscape:connector-curvature="0"/>
- </g>
- </g>
- <g transform="translate(365,4.4999696e-6)" id="g13349" style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 349.5,578 c -1.48507,0 -2.8535,0.46731 -3.86133,1.33594 C 344.63084,580.20456 344,581.48473 344,583 v 3 c 0,0.83333 -0.007,1.35913 -0.11133,1.78711 -0.10481,0.42798 -0.303,0.80502 -0.77929,1.40039 A 0.50005,0.50005 0 0 0 343,589.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1 1 a 0.50005,0.50005 0 0 0 0.33008,-0.12305 l 1.64648,-1.44336 1.41992,1.41993 A 0.50005,0.50005 0 0 0 349.25,592 h 0.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 1.39648,-1.39649 1.39648,1.39649 A 0.50005,0.50005 0 0 0 353.25,592 h 1.25 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 -1 -5.5 c 0,-1.51527 -0.63084,-2.79544 -1.63867,-3.66406 C 352.3535,578.46731 350.98507,578 349.5,578 Z m 0,1 c 1.27493,0 2.40681,0.40238 3.20898,1.09375 C 353.51116,580.78512 354,581.75527 354,583 v 5.5 1 1.5 h -0.54297 l -1.60351,-1.60352 a 0.50005,0.50005 0 0 0 -0.70704,0 L 349.54297,591 h -0.0859 l -1.60351,-1.60352 a 0.50005,0.50005 0 0 0 -0.6836,-0.0234 L 345.3125,591 H 344.5 344 v -1.38867 c 0.42104,-0.55984 0.73249,-1.05984 0.86133,-1.58594 C 345.00652,587.43254 345,586.83333 345,586 v -3 c 0,-1.24473 0.48884,-2.21488 1.29102,-2.90625 C 347.09319,579.40238 348.22507,579 349.5,579 Z m -1.00586,2.99219 a 0.50005,0.50005 0 0 0 -0.34766,0.15429 l -0.64648,0.64649 -0.64648,-0.64649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 0.64649,0.64648 -0.64649,0.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 0.64648,-0.64649 0.64648,0.64649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -0.64649,-0.64648 0.64649,-0.64648 a 0.50005,0.50005 0 0 0 -0.35938,-0.86133 z m 4,0 a 0.50005,0.50005 0 0 0 -0.34766,0.15429 l -0.64648,0.64649 -0.64648,-0.64649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 0.64649,0.64648 -0.64649,0.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 0.64648,-0.64649 0.64648,0.64649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -0.64649,-0.64648 0.64649,-0.64648 a 0.50005,0.50005 0 0 0 -0.35938,-0.86133 z" transform="translate(-365,-4.4999696e-6)" id="path13343" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 291.98438,431.0625 c -1.31822,0 -2.69153,0.28723 -3.69727,1.29297 a 1.0001,1.0001 0 1 0 1.41406,1.41406 c 0.49426,-0.49426 1.2483,-0.70703 2.28321,-0.70703 a 1.0001,1.0001 0 1 0 0,-2 z m -7.24024,3.04297 c -0.74589,-0.0115 -1.46694,0.0868 -2.13086,0.30664 -1.32784,0.43972 -2.4721,1.53683 -2.61719,3.06055 -0.19518,2.0499 0.80702,3.49399 1.02735,4.3457 0.14607,0.56468 0.0225,0.72298 -0.18164,0.91797 -0.20413,0.19499 -0.61247,0.33203 -0.84961,0.33203 a 1.0001,1.0001 0 1 0 0,2 c 0.76285,0 1.57391,-0.25956 2.23047,-0.88672 0.65655,-0.62715 1.03297,-1.71849 0.73632,-2.86523 -0.37187,-1.43756 -1.0944,-2.37562 -0.97265,-3.6543 0.0682,-0.71615 0.4403,-1.08149 1.25586,-1.35156 0.81556,-0.27008 2.03005,-0.27431 3.23242,0.0684 1.20237,0.34267 2.38417,1.01511 3.21875,1.95703 0.83458,0.94191 1.35114,2.12713 1.29297,3.68945 -0.0218,0.58526 -0.18864,0.77371 -0.37305,0.89453 -0.18441,0.12083 -0.50228,0.18156 -0.91016,0.0723 -0.65709,-0.17607 -1.01294,-0.58503 -1.30078,-1.30274 -0.28784,-0.7177 -0.4082,-1.70364 -0.4082,-2.62695 a 1.0001,1.0001 0 1 0 -2,0 c 0,1.07669 0.11104,2.27463 0.55078,3.37109 0.43975,1.09647 1.30771,2.13309 2.64063,2.49024 0.84212,0.22565 1.76567,0.1664 2.52343,-0.33008 0.75729,-0.49617 1.23505,-1.42269 1.2754,-2.49219 v -0.002 c 0.0762,-2.06159 -0.66061,-3.80964 -1.79493,-5.08984 -1.1347,-1.28064 -2.63964,-2.11968 -4.16601,-2.55469 -0.76319,-0.21751 -1.53341,-0.33806 -2.2793,-0.34961 z" id="path8292" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 495.50391,451.99219 c -1.93006,0 -3.50391,1.57292 -3.50391,3.5 v 2 c 0,0.41666 0.19292,0.77495 0.45898,1.04101 0.26607,0.26607 0.62435,0.45899 1.04102,0.45899 a 0.50005,0.50005 0 1 0 0,-1 c -0.0833,0 -0.22505,-0.0571 -0.33398,-0.16602 C 493.05708,457.71724 493,457.57552 493,457.49219 v -2 c 0,-1.38664 1.11314,-2.5 2.50391,-2.5 h 1.0039 c 1.39077,0 2.50196,1.11336 2.50196,2.5 v 2 c 0,0.0833 -0.0571,0.22505 -0.16602,0.33398 -0.10893,0.10893 -0.25065,0.16602 -0.33398,0.16602 a 0.50005,0.50005 0 1 0 0,1 c 0.41666,0 0.77494,-0.19292 1.04101,-0.45899 0.26607,-0.26606 0.45899,-0.62435 0.45899,-1.04101 v -2 c 0,-1.92708 -1.57191,-3.5 -3.50196,-3.5 z m 3.94921,7.41406 a 0.50005,0.50005 0 0 0 -0.48632,0.33203 c -0.17381,0.48217 -0.35767,1.04392 -0.75391,1.48047 -0.39624,0.43655 -0.98986,0.78906 -2.17578,0.78906 -1.18761,0 -1.78805,-0.34711 -2.19141,-0.77929 -0.40336,-0.43219 -0.59802,-0.98975 -0.78515,-1.47266 a 0.50005,0.50005 0 0 0 -0.67578,-0.27344 c -0.97162,0.44606 -1.78522,0.89986 -2.38868,1.45508 C 489.39264,461.49272 489,462.19074 489,462.99219 v 2.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13.00977 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2.5 c 0,-0.79711 -0.38431,-1.49976 -0.98243,-2.06446 -0.59811,-0.56469 -1.40897,-1.02891 -2.38086,-1.47461 a 0.50005,0.50005 0 0 0 -0.19336,-0.0469 z m 0.17579,1.19922 c 0.68529,0.34567 1.33558,0.69455 1.71289,1.05078 0.46505,0.43906 0.66797,0.84399 0.66797,1.33594 v 2 H 490 v -2 c 0,-0.49365 0.20477,-0.8868 0.67383,-1.31836 0.38208,-0.35154 1.03995,-0.69804 1.73437,-1.04492 0.1643,0.40983 0.28954,0.83601 0.70508,1.28125 0.58146,0.623 1.5239,1.09765 2.92383,1.09765 1.40162,0 2.34196,-0.48473 2.91601,-1.11719 0.40651,-0.44786 0.51938,-0.87307 0.67579,-1.28515 z" id="path6745-8" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 134.50977,472.99414 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5039 c 0.0205,0.58311 0.0403,1.03618 -0.0488,1.24805 -0.22838,0.54301 -0.5609,0.82668 -1.00781,1.10937 -0.44691,0.28269 -1.00733,0.53131 -1.53711,0.97461 -0.52977,0.4433 -1.00108,1.10059 -1.22656,2.08789 -0.22548,0.9873 -0.2332,2.29903 0.0625,4.16406 0.0385,0.24311 0.24801,0.42203 0.49414,0.42188 h 8.75586 c 0.30739,1.4e-4 0.54213,-0.2745 0.49414,-0.57812 -0.36883,-2.32606 -0.21493,-3.6368 0.12305,-4.40821 0.33798,-0.7714 0.85304,-1.08606 1.49804,-1.45508 0.645,-0.36901 1.43565,-0.7809 1.90821,-1.70703 0.47255,-0.92613 0.59571,-2.25921 0.21289,-4.4375 C 145.70043,474.17484 145.49284,474.0002 145.25,474 h -7.24023 v -0.50586 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m 3,1.00586 h 6.78125 c 0.25456,1.74951 0.14487,2.81594 -0.15235,3.39844 -0.3247,0.63637 -0.84774,0.91198 -1.51367,1.29297 -0.66593,0.38098 -1.46183,0.87882 -1.91797,1.91992 -0.41222,0.94085 -0.49675,2.35477 -0.23633,4.38867 h -7.73437 c -0.19264,-1.47462 -0.23076,-2.65205 -0.0684,-3.36328 0.18281,-0.80045 0.49635,-1.21142 0.89258,-1.54297 0.39622,-0.33155 0.90291,-0.56523 1.42968,-0.89844 0.52678,-0.33321 1.07351,-0.7985 1.39649,-1.5664 0.22021,-0.52359 0.17686,-1.05487 0.13867,-1.63477 h 0.48438 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 z" id="path13566" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccscsccccccccccccccccccccccccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 160.5,431 a 1.5,1.5 0 0 0 -1.5,1.5 1.5,1.5 0 0 0 0.0879,0.5 h -4.56836 a 1.50015,1.50015 0 1 0 0,3 H 158 v 1.94922 c -1.31983,1.3363 -2.47353,2.76999 -2.9707,5.25586 a 1.50015,1.50015 0 1 0 2.9414,0.58984 c 0.37009,-1.85045 0.99513,-2.60285 2.0293,-3.6289 1.03417,1.02605 1.65921,1.77845 2.0293,3.6289 a 1.50015,1.50015 0 1 0 2.9414,-0.58984 c -0.49717,-2.48587 -1.65087,-3.91956 -2.9707,-5.25586 V 436 h 3.48047 a 1.50015,1.50015 0 1 0 0,-3 h -2.53711 c -0.0387,0.18925 -0.094,0.37697 -0.17774,0.55664 C 162.35553,434.4361 161.47038,435 160.5,435 a 0.50005,0.50005 0 1 1 0,-1 1.5,1.5 0 0 0 0.41406,-0.0586 c 0.009,-0.002 0.0169,-0.005 0.0254,-0.008 a 1.5,1.5 0 0 0 0.35157,-0.16211 c 0.006,-0.004 0.0133,-0.006 0.0195,-0.01 a 1.5,1.5 0 0 0 0.004,-0.002 1.5,1.5 0 0 0 0.29102,-0.25 c 0.009,-0.0103 0.0202,-0.0187 0.0293,-0.0293 a 1.5,1.5 0 0 0 0.21484,-0.33008 c 0.003,-0.006 0.007,-0.01 0.01,-0.0156 0.002,-0.005 0.004,-0.0104 0.006,-0.0156 A 1.5,1.5 0 0 0 162,432.5 1.5,1.5 0 0 0 160.5,431 Z" id="path13634" inkscape:connector-curvature="0" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 428.49023,603.99414 a 0.50005,0.50005 0 0 0 -0.34961,0.85938 l 4,4 a 0.50005,0.50005 0 0 0 0.70704,0 l 4,-4 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 l -3.64648,3.64649 -3.64648,-3.64649 a 0.50005,0.50005 0 0 0 -0.35743,-0.15234 z" id="path13549" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 410.49414,601.99414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 3.64649,3.64648 -3.64649,3.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 4,-4 a 0.50005,0.50005 0 0 0 0,-0.70704 l -4,-4 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z" id="path13551" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" transform="rotate(-180,307.00525,417)" id="g13597" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 289.50391,410 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -0.99414 c -1.17529,0 -2.25213,0.41841 -2.88477,1.18164 -0.28029,0.32895 -0.0395,0.83456 0.39258,0.82422 0.14712,-0.004 0.28501,-0.0726 0.37695,-0.1875 C 286.27001,413.36537 287.08306,413 288.00977,413 h 0.99414 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m -4.58594,3.95898 c -1.10666,0.0478 -2.07229,0.36866 -2.82031,0.91211 -0.99737,0.72461 -1.58789,1.85424 -1.58789,3.12891 v 1 h -1.50586 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -0.49414 v -1 c 0,-0.97533 0.41802,-1.76979 1.17578,-2.32031 0.75777,-0.55053 1.87662,-0.84701 3.26562,-0.6836 1.98998,0.23412 3.41358,1.22814 4.10352,2.33203 0.68994,1.10391 0.68215,2.23778 -0.14844,3.06836 -0.83795,0.83796 -1.98844,0.89361 -3.08398,0.26368 -1.09554,-0.62994 -2.08242,-1.9799 -2.31641,-3.96875 -0.0504,-0.69579 -1.10528,-0.57121 -0.99219,0.11718 0.26601,2.26115 1.40414,3.91119 2.8086,4.71875 0.70223,0.40379 1.48456,0.58895 2.23632,0.52735 0.75176,-0.0616 1.47366,-0.37015 2.05469,-0.95117 1.16941,-1.16942 1.16162,-2.91055 0.28906,-4.30664 -0.87256,-1.3961 -2.57396,-2.52709 -4.83398,-2.79297 -0.39761,-0.0468 -0.78151,-0.0608 -1.15039,-0.0449 z M 280.00391,421 h 2 v 2 h -2 z" transform="rotate(180,307.00525,417)" id="path13595" inkscape:connector-curvature="0"/>
- </g>
- <rect style="display:inline;opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" id="rect13550" width="16" height="16" x="488.00128" y="430.00018" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g13226" transform="translate(-189,84.000005)">
- <path style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;enable-background:accumulate" d="m 285,536 -0.15625,1.90625 c -0.6231,0.14227 -1.07677,0.25145 -1.59375,0.59375 l -1.75,-1.5 -1.5,1.5 1.5,1.75 c -0.34229,0.51699 -0.45148,0.97065 -0.59375,1.59375 L 279,542 v 1 1 l 1.90625,0.15625 c 0.14227,0.6231 0.25145,1.07677 0.59375,1.59375 l -1.5,1.75 1.5,1.5 1.75,-1.5 c 0.51699,0.34229 0.97065,0.45148 1.59375,0.59375 L 285,550 h 1 1 l 0.15625,-1.90625 c 0.6231,-0.14227 1.07677,-0.25145 1.59375,-0.59375 l 1.75,1.5 1.5,-1.5 -1.5,-1.75 c 0.34229,-0.51699 0.45148,-0.97065 0.59375,-1.59375 L 293,544 v -1 -1 l -1.90625,-0.15625 C 290.95148,541.22065 290.8423,540.76698 290.5,540.25 l 1.5,-1.75 -1.5,-1.5 -1.75,1.5 c -0.51699,-0.34229 -0.97065,-0.45148 -1.59375,-0.59375 L 287,536 h -1 z m 1,5 c 1.11641,0 2,0.88359 2,2 0,1.11641 -0.88359,2 -2,2 -1.11641,0 -2,-0.88359 -2,-2 0,-1.11641 0.88359,-2 2,-2 z" transform="translate(189,-84.000005)" id="path52982-3" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.14285719;enable-background:new" id="g13938" transform="matrix(0.875,0,0,0.875,-254.625,-304.87495)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3.42857146;marker:none;enable-background:accumulate" id="rect13853" width="16" height="16" x="299" y="408.99994"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g14058" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 451.5,536 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 8 v 8 h -8 z" id="path14208" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 449.49219,537.99219 A 0.50005,0.50005 0 0 0 449,538.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 450 v -8.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -2,2 A 0.50005,0.50005 0 0 0 447,540.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 448 v -8.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" id="path14212" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 460.48438,536 c -0.12717,0.004 -0.248,0.0564 -0.3379,0.14648 l -9,9 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 9 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c 1.1e-4,-0.28235 -0.23341,-0.50879 -0.51562,-0.5 z" id="path14252" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccc"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 414.55664,159.95508 a 0.50005,0.50005 0 0 0 -0.47461,0.61133 L 414.38867,162 h -4.70898 l 0.30859,-1.39062 a 0.5003812,0.5003812 0 1 0 -0.97656,-0.21876 L 408.6543,162 H 406.5 a 0.50005,0.50005 0 1 0 0,1 h 1.93164 l -0.66602,3 H 405.5 a 0.50005,0.50005 0 1 0 0,1 h 2.04297 l -0.53125,2.39062 a 0.5003812,0.5003812 0 1 0 0.97656,0.21876 L 408.56836,167 h 6.88672 l 0.55664,2.60352 a 0.50005,0.50005 0 1 0 0.97656,-0.20704 L 416.47656,167 H 418.5 a 0.50005,0.50005 0 1 0 0,-1 h -2.23633 l -0.63867,-3 h 1.875 a 0.50005,0.50005 0 1 0 0,-1 h -2.08984 l -0.34961,-1.64258 a 0.50005,0.50005 0 0 0 -0.50391,-0.40234 z M 409.45703,163 h 5.14453 l 0.64063,3 h -6.45117 z" id="path13985" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14370" transform="translate(20.999998,4.4999696e-6)">
- <path id="rect14323" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 141.51562,82 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 145.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 145.5,82 Z m 0.5,1 H 145 v 4 h -2.98438 z m -9.5,-1 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 136.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 136.5,82 Z m 0.5,1 H 136 v 4 h -2.98438 z m 8.5,-9 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 145.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 145.5,74 Z m 0.5,1 H 145 v 4 h -2.98438 z m -9.5,-1 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 136.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 136.5,74 Z m 0.5,1 H 136 v 4 h -2.98438 z" inkscape:connector-curvature="0"/>
- </g>
- <g id="g6448" style="fill:#ffffff">
- <path d="m 103,78.000008 h 1 v 1 h -1 z m 0,-3 h 1 v 1 h -1 z m -8,3 h 1 v 1 h -1 z m 0,3 h 1 v 1 h -1 z m 0,-6 h 1 v 1 h -1 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" id="rect14452" inkscape:connector-curvature="0"/>
- <path d="m 98.515625,74 c -0.276131,2.8e-5 -0.499972,0.223869 -0.5,0.5 v 6 c 2.8e-5,0.276131 0.223869,0.499972 0.5,0.5 H 101.5 c 0.27613,-2.8e-5 0.49997,-0.223869 0.5,-0.5 v -6 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m 0.5,1 H 101 v 2 h -1.984375 z m 0,3 H 101 v 2 h -1.984375 z m -8.5,-4 c -0.276131,2.8e-5 -0.499972,0.223869 -0.5,0.5 v 12 c 2.8e-5,0.276131 0.223869,0.499972 0.5,0.5 H 93.5 c 0.276131,-2.8e-5 0.499972,-0.223869 0.5,-0.5 v -12 c -2.8e-5,-0.276131 -0.223869,-0.499972 -0.5,-0.5 z m 0.5,1 H 93 v 2 h -1.984375 z m 0,3 H 93 v 2 h -1.984375 z m 0,3 H 93 v 2 h -1.984375 z m 0,3 H 93 v 2 h -1.984375 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" id="path14479" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccc"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g14591">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 9.25,74 a 0.50005,0.50005 0 0 0 -0.4765625,0.351562 l -2.75,8.820313 A 0.50005,0.50005 0 0 0 6,83.320312 v 0.173829 a 0.50005,0.50005 0 1 0 1,0 v -0.09766 L 7.7460938,81 A 0.50005,0.50005 0 0 0 7.75,81 h 3.5 a 0.50005,0.50005 0 0 0 0.0039,0 L 12,83.396484 v 0.09766 a 0.50005,0.50005 0 1 0 1,0 v -0.173829 a 0.50005,0.50005 0 0 0 -0.02344,-0.148437 l -2.75,-8.820313 A 0.50005,0.50005 0 0 0 9.75,74 Z M 9.5,75.375 10.941406,80 H 8.0585938 Z" id="path14584" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 14.5,79 a 0.50005,0.50005 0 1 0 0,1 H 19 v 0.08008 l -4.896484,6.365234 A 0.50005,0.50005 0 0 0 14,86.75 v 0.75 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5 a 0.50005,0.50005 0 1 0 0,-1 H 15 v -0.08008 l 4.896484,-6.365234 A 0.50005,0.50005 0 0 0 20,80.25 V 79.5 A 0.50005,0.50005 0 0 0 19.5,79 Z" id="path14589" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 69.5,74 a 0.50005,0.50005 0 1 0 0,1 h 13 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 10 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 7 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z" id="path14593" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 30.474609,74.994141 a 0.50004997,0.50004997 0 0 0 -0.40625,0.757812 L 33.128906,81 H 27.5 a 0.50004997,0.50004997 0 1 0 0,1 h 5.628906 l -3.060547,5.248047 a 0.50004997,0.50004997 0 1 0 0.863282,0.503906 L 34,82.492188 l 3.068359,5.259765 a 0.50004997,0.50004997 0 1 0 0.863282,-0.503906 L 34.871094,82 H 40.5 a 0.50004997,0.50004997 0 1 0 0,-1 h -5.628906 l 3.060547,-5.248047 A 0.50004997,0.50004997 0 1 0 37.068359,75.248047 L 34,80.507812 30.931641,75.248047 a 0.50004997,0.50004997 0 0 0 -0.457032,-0.253906 z" id="path14603" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 50.494141,73.992188 A 0.50004997,0.50004997 0 0 0 50.417969,74 H 49.5 a 0.50004997,0.50004997 0 1 0 0,1 H 50 v 1.125 c 0,1.632015 0.971328,2.853007 2.201172,3.775391 L 53,80.5 v 0.5 0.5 l -0.798828,0.599609 C 50.971326,83.021991 50,84.242992 50,85.875 V 87 h -0.5 a 0.50004997,0.50004997 0 1 0 0,1 h 0.921875 a 0.50004997,0.50004997 0 0 0 0.160156,0 h 7.837891 a 0.50004997,0.50004997 0 0 0 0.162109,0 H 59.5 a 0.50004997,0.50004997 0 1 0 0,-1 H 59 v -1.125 c 0,-1.632008 -0.969373,-2.853009 -2.199219,-3.775391 L 56,81.5 V 81.035156 A 0.50004997,0.50004997 0 0 0 56,81 v -0.5 l 0.800781,-0.599609 C 58.030625,78.978007 59,77.757015 59,76.125 V 75 h 0.5 a 0.50004997,0.50004997 0 1 0 0,-1 h -0.919922 a 0.50004997,0.50004997 0 0 0 -0.162109,0 h -7.835938 a 0.50004997,0.50004997 0 0 0 -0.08789,-0.0078 z M 51,75 h 7 v 1.125 c 0,1.245243 -0.698245,2.147707 -1.800781,2.974609 l -1,0.75 A 0.50004997,0.50004997 0 0 0 55,80.25 V 80.964844 81 81.75 a 0.50004997,0.50004997 0 0 0 0.199219,0.400391 l 1,0.75 C 57.301151,83.726838 57.999238,84.628869 58,85.873047 V 87 h -7 v -1.125 -0.002 c 7.62e-4,-1.244178 0.698849,-2.146209 1.800781,-2.972656 l 1,-0.75 A 0.50004997,0.50004997 0 0 0 54,81.75 V 81.035156 A 0.50004997,0.50004997 0 0 0 54,81 v -0.75 a 0.50004997,0.50004997 0 0 0 -0.199219,-0.400391 l -1,-0.75 C 51.698847,78.273158 51.000762,77.371141 51,76.126953 v -0.002 z" id="path14614" inkscape:connector-curvature="0"/>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="g14256" transform="translate(-21.000002,4.4999696e-6)" style="display:inline;opacity:0.4;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 92.496094,325.99414 a 0.50005,0.50005 0 0 0 -0.382813,0.82227 l 4.5,5.5 a 0.50005,0.50005 0 0 0 0.773438,0 l 4.500001,-5.5 a 0.50005,0.50005 0 1 0 -0.77344,-0.63282 L 97,331.21094 92.886719,326.18359 a 0.50005,0.50005 0 0 0 -0.390625,-0.18945 z" id="path14250" inkscape:connector-curvature="0"/>
- <path id="path14254" d="m 91.25,334 c -0.683851,0 -1.25,0.56615 -1.25,1.25 v 3.5 c 0,0.68385 0.566149,1.25 1.25,1.25 h 3.5 c 0.683851,0 1.25,-0.56615 1.25,-1.25 v -3.5 C 96,334.56615 95.433851,334 94.75,334 Z m 8,0 c -0.683851,0 -1.25,0.56615 -1.25,1.25 v 3.5 c 0,0.68385 0.566149,1.25 1.25,1.25 h 3.5 c 0.68385,0 1.25,-0.56615 1.25,-1.25 v -3.5 c 0,-0.68385 -0.56615,-1.25 -1.25,-1.25 z m -7.75,4 h 2 1 a 0.50005,0.50005 0 1 1 0,1 h -1 -2 a 0.50005,0.50005 0 1 1 0,-1 z m 8,0 h 2 1 a 0.50005,0.50005 0 1 1 0,1 h -1 -2 a 0.50005,0.50005 0 1 1 0,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 6.5,116 A 0.50005,0.50005 0 0 0 6,116.5 v 4 a 0.50005,0.50005 0 1 0 1,0 V 117 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 z m 9.007812,0 a 0.50005,0.50005 0 1 0 0,1 h 3.5 v 3.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -9.0156245,9 A 0.50005,0.50005 0 0 0 6,125.50781 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 H 7 v -3.5 A 0.50005,0.50005 0 0 0 6.4921875,125 Z M 19.5,125 a 0.50005,0.50005 0 0 0 -0.492188,0.50781 v 3.5 h -3.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4 A 0.50005,0.50005 0 0 0 19.5,125 Z" id="path13927" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 48,11 v 2 h 2 v -2 z m 2,4 v 2 h 2 v -2 z m 2,3 v 2 h 2 v -2 z m 3,3 v 2 h 1.5 v 1 H 59 v 1 h 3 v -2 h -3 v -1 h -2 v -1 z" id="path14341" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccccccc"/>
- <g transform="matrix(-1,0,0,1,1290,302.99979)" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" id="g8530-0" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1258.4766,-286 a 0.50005,0.50005 0 0 0 -0.4102,0.25195 l -4,7 A 0.50005,0.50005 0 0 0 1254.5,-278 h 8 a 0.50005,0.50005 0 0 0 0.4336,-0.74805 l -4,-7 A 0.50005,0.50005 0 0 0 1258.4766,-286 Z m 0.023,1.50781 3.1387,5.49219 h -6.2774 z" id="path8523-4" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1253.5,-289 c -0.8225,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z" id="ellipse8525-5" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 27.5,11 A 0.50005,0.50005 0 0 0 27,11.5 v 10.851562 l 1,-1.75 V 12 h 12 v 12 h -3.099609 c 0.122248,0.339531 0.117057,0.686553 0.0039,1 H 40.5 A 0.50005,0.50005 0 0 0 41,24.5 v -13 A 0.50005,0.50005 0 0 0 40.5,11 Z" transform="matrix(-1,0,0,1,1290,-302.99979)" id="path8528-7" inkscape:connector-curvature="0"/>
- </g>
- <path sodipodi:nodetypes="cccccccccccccccccccccccccccccc" inkscape:connector-curvature="0" id="path14394" d="m 98.999998,11.000004 v 4.000002 h -1 -1 v 3 h -1 v -2 h -1 v 5.000001 h -1 v -2.000001 h -1 v 3.560548 h -1 v -2.085938 h -1 v 2.525389 h -1 v 2 L 104,25.000007 v -2.421875 h -1 v -4.578126 h -1 v 2.000001 h -1 v -6.000003 h -1.000002 v -3 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 76,11 c -0.08389,-2.87e-4 -0.166503,0.02054 -0.240234,0.06055 l -5.5,3 C 70.099297,14.148474 69.999666,14.317023 70,14.5 v 7 c -3.35e-4,0.182978 0.0993,0.351528 0.259766,0.439453 l 5.5,3 C 75.833498,24.979467 75.916111,25.000288 76,25 h 1 c 0.08389,2.87e-4 0.166503,-0.02053 0.240234,-0.06055 l 5.5,-3 C 82.900703,21.851526 83.000334,21.682977 83,21.5 v -7 c 3.35e-4,-0.182978 -0.0993,-0.351528 -0.259766,-0.439453 l -5.5,-3 C 77.166502,11.020533 77.083889,10.999712 77,11 Z m 0.382812,2 h 0.240235 L 81,15.390625 v 5.21875 L 76.617188,23 H 76.382812 L 72,20.609375 v -5.21875 z" id="path14426" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccccc"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14475" transform="translate(-1.8536743e-6,25.000005)">
- <g transform="matrix(1,0,0,-1,-294,368)" id="g4806-1" style="opacity:1;fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 300.5,375 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 11 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 10 v 2 h -10 z" id="path4801-8" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 302.5,378 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 11 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 10 v 2 h -10 z" id="path4804-1" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 8.5,-4 A 0.50005,0.50005 0 0 0 8,-3.5 v 3 A 0.50005,0.50005 0 0 0 8.5,0 h 11 A 0.50005,0.50005 0 0 0 20,-0.5 v -3 A 0.50005,0.50005 0 0 0 19.5,-4 Z M 9,-3 h 10 v 2 H 9 Z" id="path4817-4" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14588" transform="translate(-42.000002,25.000005)">
- <path id="path14541" d="m 153.5,-9 c -0.27613,2.76e-5 -0.49997,0.2238691 -0.5,0.5 v 8 c 3e-5,0.27613094 0.22387,0.499972391047 0.5,0.5 h 8 c 0.27613,-2.7608953e-5 0.49997,-0.22386906 0.5,-0.5 v -8 c -3e-5,-0.2761309 -0.22387,-0.4999724 -0.5,-0.5 z m 6.5,1 c 0.54636,0 1,0.4536376 1,1 0,0.5463624 -0.45364,1 -1,1 -0.54636,0 -1,-0.4536376 -1,-1 0,-0.5463624 0.45364,-1 1,-1 z m -2.98047,1.75 c 0.17034,0.00643 0.32566,0.099184 0.41211,0.2460938 l 2.5,4.25 C 160.12825,-1.4202448 159.88728,-0.99936558 159.5,-1 h -5 c -0.38728,6.3442e-4 -0.62825,-0.4202448 -0.43164,-0.7539062 l 2.5,-4.25 c 0.0935,-0.1589489 0.26691,-0.2535338 0.45117,-0.2460938 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <g id="g14560" transform="translate(147)" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 10.5,-14 c -0.276131,2.8e-5 -0.499972,0.223869 -0.5,0.5 v 3 c 2.8e-5,0.276131 0.223869,0.499972 0.5,0.5 h 9 c 0.276131,-2.8e-5 0.499972,-0.223869 0.5,-0.5 v -3 c -2.8e-5,-0.276131 -0.223869,-0.499972 -0.5,-0.5 z m 0.5,1 h 8 v 2 h -8 z m 5,7 v 1 h 3 v 2 h -3 v 1 h 3.5 c 0.276131,-2.76e-5 0.499972,-0.2238691 0.5,-0.5 v -3 c -2.8e-5,-0.2761309 -0.223869,-0.4999724 -0.5,-0.5 z" id="path14558" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccccccccccccc"/>
- </g>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14668" transform="matrix(-1,0,0,1,530,30.000005)">
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 258.5,-19 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 13 c 3e-5,0.2761309 0.22387,0.4999724 0.5,0.5 h 13 c 0.27613,-2.76e-5 0.49997,-0.2238691 0.5,-0.5 v -13 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m 1.5,2 h 6 v 4 h 4 v 6 h -6 v -4 h -4 z" id="path14664"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:0.5;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.89999986;marker:none;enable-background:accumulate" d="m 260,-17 h 6 v 4 h -2 v 2 h -4 z" id="path14666" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccc"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.55;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 261.03125,601 C 260.46859,601 260,601.46859 260,602.03125 v 7.9375 c 0,0.56266 0.46859,1.03125 1.03125,1.03125 h 7.9375 C 269.53141,611 270,610.53141 270,609.96875 v -7.9375 C 270,601.46859 269.53141,601 268.96875,601 Z m 0,1 h 7.9375 c 0.026,0 0.0312,0.005 0.0312,0.0312 v 7.9375 c 0,0.026 -0.005,0.0312 -0.0312,0.0312 h -7.9375 c -0.026,0 -0.0312,-0.005 -0.0312,-0.0312 v -7.9375 c 0,-0.026 0.005,-0.0312 0.0312,-0.0312 z" id="rect13790" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" id="path13905" d="M 282.03125,601 C 281.46859,601 281,601.46859 281,602.03125 v 7.9375 c 0,0.56266 0.46859,1.03125 1.03125,1.03125 h 7.9375 C 290.53141,611 291,610.53141 291,609.96875 v -7.9375 C 291,601.46859 290.53141,601 289.96875,601 Z m 6.94922,1.99023 a 1.0001,1.0001 0 0 1 0.72656,1.7168 l -4,4 a 1.0001,1.0001 0 0 1 -1.41406,0 l -2,-2 a 1.0001,1.0001 0 1 1 1.41406,-1.41406 l 1.29297,1.29297 3.29297,-3.29297 a 1.0001,1.0001 0 0 1 0.6875,-0.30274 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 265,622 c -2.7555,0 -5,2.2445 -5,5 0,2.7555 2.2445,5 5,5 2.7555,0 5,-2.2445 5,-5 0,-2.7555 -2.2445,-5 -5,-5 z m 0,1 c 2.21506,0 4,1.78494 4,4 0,2.21506 -1.78494,4 -4,4 -2.21506,0 -4,-1.78494 -4,-4 0,-2.21506 1.78494,-4 4,-4 z" id="path13966" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 286,622 c -2.7555,0 -5,2.2445 -5,5 0,2.7555 2.2445,5 5,5 2.7555,0 5,-2.2445 5,-5 0,-2.7555 -2.2445,-5 -5,-5 z" id="circle13982" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 220.4707,623.75 c -0.26463,0.0156 -0.47113,0.23492 -0.4707,0.5 v 4.25 c 1.7e-4,0.35718 0.36395,0.59902 0.69336,0.46094 l 4.75,-2 c 0.39771,-0.16741 0.41088,-0.72615 0.0215,-0.91211 l -4.75,-2.25 c -0.076,-0.0366 -0.15996,-0.0534 -0.24416,-0.0488 z" id="path14031" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 370,625 c -1.09865,0 -2,0.90135 -2,2 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 0,-1.09865 -0.90135,-2 -2,-2 z" id="circle14040" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 28.5,431 a 1.50015,1.50015 0 0 0 -1.341797,2.16992 l 5.5,11 a 1.50015,1.50015 0 0 0 2.683594,0 l 5.5,-11 A 1.50015,1.50015 0 0 0 39.5,431 Z m 2.425781,3 h 6.148438 L 34,440.14648 Z" id="path14201" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 306.49219,577.99219 A 0.50004997,0.50004997 0 0 0 306,578.5 v 2.79297 l -2.14648,-2.14649 a 0.50004997,0.50004997 0 1 0 -0.70704,0.70704 L 306,582.70703 v 0.58203 c -0.58959,0.34718 -0.99219,0.98165 -0.99219,1.71094 h -0.30078 l -2.85351,-2.85352 a 0.50004997,0.50004997 0 0 0 -0.35938,-0.15234 0.50004997,0.50004997 0 0 0 -0.34766,0.85938 L 303.29297,585 H 300.5 a 0.50004997,0.50004997 0 1 0 0,1 h 2.79297 l -2.14649,2.14648 a 0.50004997,0.50004997 0 1 0 0.70704,0.70704 L 304.70703,586 h 0.58203 c 0.34718,0.58959 0.98165,0.99219 1.71094,0.99219 v 0.30078 l -2.85352,2.85351 a 0.50004997,0.50004997 0 1 0 0.70704,0.70704 L 307,588.70703 V 591.5 a 0.50004997,0.50004997 0 1 0 1,0 v -2.79297 l 2.14648,2.14649 a 0.50004997,0.50004997 0 1 0 0.70704,-0.70704 L 308,587.29297 v -0.58203 c 0.58959,-0.34718 0.99219,-0.98165 0.99219,-1.71094 h 0.30078 l 2.85351,2.85352 a 0.50004997,0.50004997 0 1 0 0.70704,-0.70704 L 310.70703,585 H 313.5 a 0.50004997,0.50004997 0 1 0 0,-1 h -2.79297 l 2.14649,-2.14648 a 0.50004997,0.50004997 0 0 0 -0.36329,-0.85743 0.50004997,0.50004997 0 0 0 -0.34375,0.15039 L 309.29297,584 h -0.58203 c -0.34718,-0.58959 -0.98165,-0.99219 -1.71094,-0.99219 v -0.30078 l 2.85352,-2.85351 a 0.50004997,0.50004997 0 1 0 -0.70704,-0.70704 L 307,581.29297 V 578.5 a 0.50004997,0.50004997 0 0 0 -0.50781,-0.50781 z M 307,584.00781 c 0.55427,0 0.99219,0.43792 0.99219,0.99219 0,0.55427 -0.43792,0.99219 -0.99219,0.99219 -0.55427,0 -0.99219,-0.43792 -0.99219,-0.99219 0,-0.55427 0.43792,-0.99219 0.99219,-0.99219 z" id="path14282" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14048" transform="translate(294,571)">
- <g transform="matrix(-0.53033009,-0.53033009,-0.53033009,0.53033009,472.85846,-15.235808)" id="g13853" style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 306.99023,243.60938 a 0.66673335,0.66673335 0 0 0 -0.65625,0.67578 v 4.99023 h -4.99023 a 0.666995,0.666995 0 1 0 0,1.33399 h 4.99023 v 4.99023 a 0.66673335,0.66673335 0 1 0 1.33204,0 v -4.99023 h 4.99023 a 0.666995,0.666995 0 1 0 0,-1.33399 h -4.99023 v -4.99023 a 0.66673335,0.66673335 0 0 0 -0.67579,-0.67578 z" id="path13850" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 177.49219,-56.007812 A 0.50005,0.50005 0 0 0 177,-55.5 v 6 a 0.50005,0.50005 0 1 0 1,0 V -52 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 H 178 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 7.00195,0.002 a 0.50005,0.50005 0 0 0 -0.34766,0.859375 l 2.64649,2.646484 -2.64649,2.646484 a 0.50005,0.50005 0 1 0 0.70704,0.707032 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.707032 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.152343 z M 180.5,-53 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z" id="path13907" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" transform="rotate(-180,275.49999,225.99747)" id="g14033">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 184.49414,-76.005859 c -0.4494,8.8e-5 -0.67059,0.546839 -0.34766,0.859375 l 2.64649,2.646484 -2.64649,2.646484 c -0.4905,0.471264 0.23578,1.197538 0.70704,0.707032 l 3,-3 c 0.19518,-0.195265 0.19518,-0.511767 0,-0.707032 l -3,-3 c -0.0942,-0.09737 -0.2239,-0.152345 -0.35938,-0.152343 z M 175.49219,-73 c -0.27615,0.0043 -0.49651,0.231666 -0.49219,0.507812 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z m 5.00781,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m 3,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m -6,0.0078 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z M 175.49219,-70 c -0.27615,0.0043 -0.49651,0.231666 -0.49219,0.507812 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z" id="path14029" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 175.5,-67 c -0.8225,0 -1.5,0.677495 -1.5,1.5 0,0.822505 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.677495 1.5,-1.5 0,-0.822505 -0.6775,-1.5 -1.5,-1.5 z" id="circle14031" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14223" transform="rotate(-180,317.49493,236.50149)">
- <g style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none" id="g14219" transform="matrix(-0.53033009,-0.53033009,-0.53033009,0.53033009,472.85846,-15.235808)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 306.99023,243.60938 a 0.66673335,0.66673335 0 0 0 -0.65625,0.67578 v 4.99023 h -4.99023 a 0.666995,0.666995 0 1 0 0,1.33399 h 4.99023 v 4.99023 a 0.66673335,0.66673335 0 1 0 1.33204,0 v -4.99023 h 4.99023 a 0.666995,0.666995 0 1 0 0,-1.33399 h -4.99023 v -4.99023 a 0.66673335,0.66673335 0 0 0 -0.67579,-0.67578 z" id="path14217" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 177.49219,-56.007812 A 0.50005,0.50005 0 0 0 177,-55.5 v 6 a 0.50005,0.50005 0 1 0 1,0 V -52 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 H 178 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 7.00195,0.002 a 0.50005,0.50005 0 0 0 -0.34766,0.859375 l 2.64649,2.646484 -2.64649,2.646484 a 0.50005,0.50005 0 1 0 0.70704,0.707032 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.707032 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.152343 z M 180.5,-53 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z" id="path14221" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14371" transform="matrix(1,0,0,-1,336,494)">
- <g transform="matrix(1,0,0,-1,0,-99.00505)" id="g14352" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 520.49414,515 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 2.64649,2.64648 -2.64649,2.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.70704 l -3,-3 A 0.50005,0.50005 0 0 0 520.49414,515 Z m 0.0332,2.99414 a 0.50005,0.50005 0 0 0 -0.14843,0.0215 l -1,0.25 a 0.50005,0.50005 0 0 0 0.0937,0.98633 0.50005,0.50005 0 0 0 0.14843,-0.0176 l 1,-0.25 a 0.50005,0.50005 0 0 0 -0.0937,-0.99024 z m -3,0.75 a 0.50005,0.50005 0 0 0 -0.14843,0.0215 l -1,0.25 a 0.50005,0.50005 0 0 0 0.0937,0.98633 0.50005,0.50005 0 0 0 0.14843,-0.0176 l 1,-0.25 a 0.50005,0.50005 0 0 0 -0.0937,-0.99024 z m -3.02343,1.24805 a 0.50005,0.50005 0 0 0 -0.35743,0.15429 l -1,1 a 0.50005,0.50005 0 0 0 0.34766,0.85938 0.50005,0.50005 0 0 0 0.35938,-0.15234 l 1,-1 a 0.50005,0.50005 0 0 0 -0.34961,-0.86133 z m -1.9961,3 A 0.50005,0.50005 0 0 0 512,523.5 v 1 a 0.50005,0.50005 0 0 0 0.49219,0.50781 A 0.50005,0.50005 0 0 0 513,524.5 v -1 a 0.50005,0.50005 0 0 0 -0.49219,-0.50781 z" transform="translate(-336,-593.00505)" id="path14350" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 176.5,-32 c 0.8225,0 1.5,-0.677495 1.5,-1.5 0,-0.822505 -0.6775,-1.5 -1.5,-1.5 -0.8225,0 -1.5,0.677495 -1.5,1.5 0,0.822505 0.6775,1.5 1.5,1.5 z" id="circle14357" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14377" transform="translate(210,592)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 184.49414,-76.005859 c -0.4494,8.8e-5 -0.67059,0.546839 -0.34766,0.859375 l 2.64649,2.646484 -2.64649,2.646484 c -0.4905,0.471264 0.23578,1.197538 0.70704,0.707032 l 3,-3 c 0.19518,-0.195265 0.19518,-0.511767 0,-0.707032 l -3,-3 c -0.0942,-0.09737 -0.2239,-0.152345 -0.35938,-0.152343 z M 175.49219,-73 c -0.27615,0.0043 -0.49651,0.231666 -0.49219,0.507812 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z m 5.00781,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m 3,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m -6,0.0078 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z M 175.49219,-70 c -0.27615,0.0043 -0.49651,0.231666 -0.49219,0.507812 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z" id="path14373" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 175.5,-67 c -0.8225,0 -1.5,0.677495 -1.5,1.5 0,0.822505 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.677495 1.5,-1.5 0,-0.822505 -0.6775,-1.5 -1.5,-1.5 z" id="circle14375" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" transform="matrix(-1,0,0,1,676.99998,550)" id="g14389">
- <g id="g14381" transform="matrix(1,0,0,-1,0,-99.00505)" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 500.50586,518.99219 A 0.50005,0.50005 0 0 0 500,519.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.49219,-0.50781 0.50005,0.50005 0 0 1 -0.002,0 z m -8.00977,2.99609 a 0.50005,0.50005 0 0 0 -0.34961,0.15234 l -3,3 a 0.50005,0.50005 0 0 0 0,0.70704 l 3,3 a 0.50005,0.50005 0 0 0 0.35938,0.15234 0.50005,0.50005 0 0 0 0.34766,-0.85938 l -2.64649,-2.64648 2.64649,-2.64648 a 0.50005,0.50005 0 0 0 -0.35743,-0.85938 z m 7.00977,0.006 a 0.50005,0.50005 0 0 0 -0.35938,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.34766,-0.85938 z m -3.0293,2.00391 a 0.50005,0.50005 0 0 0 -0.0976,0.0176 l -1,0.25 a 0.50005,0.50005 0 1 0 0.24218,0.96876 l 1,-0.25 a 0.50005,0.50005 0 0 0 -0.0937,-0.98633 0.50005,0.50005 0 0 0 -0.0508,0 z m -3,0.75 a 0.50005,0.50005 0 0 0 -0.0976,0.0176 l -1,0.25 a 0.50005,0.50005 0 1 0 0.24218,0.96876 l 1,-0.25 a 0.50005,0.50005 0 0 0 -0.0937,-0.98633 0.50005,0.50005 0 0 0 -0.0508,0 z" transform="rotate(-180,338.49999,225.49747)" id="path14379" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 176.5,-32 c 0.8225,0 1.5,-0.677495 1.5,-1.5 0,-0.822505 -0.6775,-1.5 -1.5,-1.5 -0.8225,0 -1.5,0.677495 -1.5,1.5 0,0.822505 0.6775,1.5 1.5,1.5 z" id="circle14385" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 412,120 c -1.65093,0 -3,1.34907 -3,3 0,1.65093 1.34907,3 3,3 1.65093,0 3,-1.34907 3,-3 0,-1.65093 -1.34907,-3 -3,-3 z m 0,1 c 1.11049,0 2,0.88951 2,2 0,1.11049 -0.88951,2 -2,2 -1.11049,0 -2,-0.88951 -2,-2 0,-1.11049 0.88951,-2 2,-2 z" id="circle14295" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 13.492188,54.005859 a 0.50005,0.50005 0 0 0 -0.345704,0.146485 l -3.9999996,4 a 0.50005,0.50005 0 1 0 0.7070312,0.707031 L 13,55.712891 v 9.792968 a 0.50005,0.50005 0 1 0 1,0 v -9.792968 l 3.146484,3.146484 a 0.50005,0.50005 0 1 0 0.707032,-0.707031 l -4,-4 a 0.50005,0.50005 0 0 0 -0.361328,-0.146485 z" id="path14327" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 34.492188,54.005859 A 0.50005,0.50005 0 0 0 34,54.511719 v 9.792969 l -3.146484,-3.146485 a 0.50005,0.50005 0 1 0 -0.707032,0.707031 l 4,4 a 0.50005,0.50005 0 0 0 0.707032,0 l 4,-4 A 0.50005,0.50005 0 1 0 38.146484,61.158203 L 35,64.304688 v -9.792969 a 0.50005,0.50005 0 0 0 -0.507812,-0.50586 z" id="path14329" inkscape:connector-curvature="0"/>
- <path style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.79999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" d="m 202.5,621.00003 a 5.4999997,5.4999997 0 0 0 -5.5,5.5 5.4999997,5.4999997 0 0 0 5.5,5.5 5.4999997,5.4999997 0 0 0 5.5,-5.5 5.4999997,5.4999997 0 0 0 -5.5,-5.5 z m -0.002,1.98438 a 0.50005001,0.50005001 0 0 1 0.50781,0.52343 v 2.5 h 2.50195 a 0.50005001,0.50005001 0 1 1 0,0.99805 h -2.50195 v 2.50195 a 0.50005001,0.50005001 0 0 1 -0.50586,0.50586 0.50005001,0.50005001 0 0 1 -0.49219,-0.50586 v -2.50195 h -2.5 a 0.50005001,0.50005001 0 1 1 0,-0.99805 h 2.5 v -2.5 a 0.50005001,0.50005001 0 0 1 0.49024,-0.52343 z" id="path14370" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 33.75,200 c -0.212514,-4.2e-4 -0.402079,0.13353 -0.472656,0.33398 L 31.644531,205 H 27.5 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 0.75 c 4.22e-4,0.17006 0.08724,0.32824 0.230469,0.41992 l 3.166015,2.03711 -1.367187,3.87695 c -0.01909,0.0533 -0.029,0.10942 -0.0293,0.16602 v 0.75 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 0.75 c 0.119714,-2e-5 0.235448,-0.043 0.326172,-0.12109 L 33.935547,211 h 0.128906 l 3.359375,2.87891 c 0.09174,0.079 0.209022,0.12201 0.330078,0.12109 L 38.5,213.99414 c 0.273087,-0.002 0.49394,-0.223 0.496094,-0.49609 L 39,212.75195 c -7.9e-5,-0.0572 -0.01,-0.11407 -0.0293,-0.16797 l -1.367187,-3.87695 3.166015,-2.03711 C 40.912757,206.57824 40.999577,206.42006 41,206.25 v -0.75 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 h -4.144531 l -1.632813,-4.66602 C 34.652079,200.13353 34.462514,199.99958 34.25,200 h -0.251953 z" id="path14398" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 12.75,200 a 0.50004997,0.50004997 0 0 0 -0.472656,0.33398 L 10.644531,205 H 6.5 A 0.50004997,0.50004997 0 0 0 6,205.5 v 0.75 a 0.50004997,0.50004997 0 0 0 0.2304688,0.41992 l 3.1660156,2.03711 -1.3671875,3.87695 A 0.50004997,0.50004997 0 0 0 8,212.75 v 0.75 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 0.75 a 0.50004997,0.50004997 0 0 0 0.3261719,-0.12109 L 12.935547,211 h 0.128906 l 3.359375,2.87891 A 0.50004997,0.50004997 0 0 0 16.753906,214 L 17.5,213.99414 a 0.50004997,0.50004997 0 0 0 0.496094,-0.49609 L 18,212.75195 a 0.50004997,0.50004997 0 0 0 -0.0293,-0.16797 l -1.367187,-3.87695 3.166015,-2.03711 A 0.50004997,0.50004997 0 0 0 20,206.25 V 205.5 A 0.50004997,0.50004997 0 0 0 19.5,205 h -4.144531 l -1.632813,-4.66602 A 0.50004997,0.50004997 0 0 0 13.25,200 h -0.251953 z m 0.25,1.30078 1.527344,4.36524 A 0.50004997,0.50004997 0 0 0 15,206 h 3.962891 l -3.232422,2.08008 a 0.50004997,0.50004997 0 0 0 -0.201172,0.58594 L 17,212.83398 l -0.002,0.16407 h -0.06445 l -3.357422,-2.87696 A 0.50004997,0.50004997 0 0 0 13.25,210 h -0.5 a 0.50004997,0.50004997 0 0 0 -0.326172,0.12109 L 9.0644531,213 H 9 v -0.16406 l 1.470703,-4.16992 a 0.50004997,0.50004997 0 0 0 -0.201172,-0.58594 L 7.0371094,206 H 11 a 0.50004997,0.50004997 0 0 0 0.472656,-0.33398 z" id="path14401" inkscape:connector-curvature="0"/>
- <g transform="translate(0.99996615,4.4999696e-6)" id="g13708" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 48.5,578 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 L 47.9922,589 c 0,1.51667 1.219299,3 2.984374,3 1.765077,0 3.015625,-1.475 3.015626,-3 L 54,578.5 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z m 2.5,10 c 0.546362,0 1,0.45364 1,1 0,0.54636 -0.453638,1 -1,1 -0.546362,0 -1,-0.45364 -1,-1 0,-0.54636 0.453638,-1 1,-1 z" transform="translate(-0.99998)" id="path13694"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 58.492188,586 c -0.132599,2e-5 -0.259759,0.0527 -0.353516,0.14648 l -4.75,4.75 c -0.09377,0.0938 -0.14646,0.22092 -0.146484,0.35352 v 0.25 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 H 60.5 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -5 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z" id="path13696" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 56.486328,579 c -0.130565,0.002 -0.25534,0.0541 -0.347656,0.14648 l -2,2 c -0.09377,0.0938 -0.14646,0.22092 -0.146484,0.35352 v 6 c 1.71e-4,0.44532 0.538516,0.6683 0.853515,0.35352 l 5,-5 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -3,-3 C 56.750515,579.05126 56.620954,578.99846 56.486328,579 Z" id="path13698" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccc"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g9998" transform="matrix(-1,0,0,1,907.99986,4.6999695e-6)">
- <g transform="matrix(-0.61504365,0,0,0.61502939,510.71013,122.71015)" id="g13879" style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.6259197;enable-background:new"/>
- <g id="g9988" style="fill:#ffffff">
- <path id="path13882" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 478.49219,473.00781 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,10e-6 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.0053,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66922,10e-6 -1.3386,0 -2.00781,0 z m -0.49233,3.9922 2.99609,0.006 c 0.2754,6.1e-4 0.49976,0.22265 0.5,0.49805 l 0.004,6.45885 c 0,1.02328 -0.80629,2.03747 -2,2.03711 -1.19534,0 -1.99609,-1.02155 -1.99609,-2.04297 l -0.004,-6.45704 c 1.8e-4,-0.27638 0.22362,-0.50048 0.5,-0.5 z m 1.5,6 a 1,0.99999999 0 0 0 -1,1.00001 1,0.99999999 0 0 0 1,1 1,0.99999999 0 0 0 1,-1 1,0.99999999 0 0 0 -1,-1.00001 z" inkscape:connector-curvature="0"/>
- <path id="path13884" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 469.49219,474.00781 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,10e-6 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.0053,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66922,10e-6 -1.3386,0 -2.00781,0 z m 5.5151,2.99233 c 0.12999,0.002 0.25408,0.0546 0.34596,0.14655 l 1.00065,0.99942 c 0.094,0.094 0.14673,0.22146 0.14655,0.35436 v 4.0001 c 2e-5,0.4458 -0.53925,0.66879 -0.85409,0.35316 l -2.99954,-3.00067 c -0.19472,-0.19518 -0.19472,-0.51115 0,-0.70633 l 2.00009,-2.00004 c 0.0954,-0.0955 0.2254,-0.14835 0.36038,-0.14655 z" inkscape:connector-curvature="0"/>
- <path id="path13886" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 468.49219,483.00781 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,10e-6 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.0053,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66922,10e-6 -1.3386,0 -2.00781,0 z m 4.52221,-1.00695 c 0.12731,0.004 0.24847,0.0555 0.33876,0.14535 l 3.00074,3.00066 c 0.31399,0.31533 0.0906,0.8529 -0.35437,0.85288 h -2.99954 c -0.27591,-1.9e-4 -0.49954,-0.22381 -0.49972,-0.49972 v -2.99946 c 7e-5,-0.28163 0.23261,-0.50765 0.51413,-0.49971 z" inkscape:connector-curvature="0"/>
- </g>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 304.5,158 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m 4.5,5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m -8.5,2 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z" id="rect13801" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14472" transform="translate(-42.000002,4.4999696e-6)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 373.5,158 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m -10.5,9 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z" id="rect14387" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 366.49219,160.99219 a 0.50005,0.50005 0 0 0 -0.31641,0.12109 0.50005,0.50005 0 0 0 -0.0195,0.0156 0.50005,0.50005 0 0 0 -0.0176,0.0176 0.50005,0.50005 0 0 0 -0.002,0.004 0.50005,0.50005 0 0 0 -0.0312,0.0332 0.50005,0.50005 0 0 0 -0.002,0.004 A 0.50005,0.50005 0 0 0 366,161.58203 V 162.5 a 0.50005,0.50005 0 1 0 1,0 V 162 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 h -0.91992 a 0.50005,0.50005 0 0 0 -0.0879,-0.008 z m 7,0 A 0.50005,0.50005 0 0 0 373.41797,161 H 372.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.91992 a 0.50005,0.50005 0 0 0 -0.11328,-0.4043 0.50005,0.50005 0 0 0 -0.002,-0.004 0.50005,0.50005 0 0 0 -0.0312,-0.0332 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.0332,-0.0312 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.32031,-0.11133 z M 369.5,161 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m -3.00781,2.99219 A 0.50005,0.50005 0 0 0 366,164.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 7,0 A 0.50005,0.50005 0 0 0 373,164.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -7,3 A 0.50005,0.50005 0 0 0 366,167.5 v 0.91992 a 0.50005,0.50005 0 0 0 0.11328,0.4043 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 366.58203,169 H 367.5 a 0.50005,0.50005 0 1 0 0,-1 H 367 v -0.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 7,0 A 0.50005,0.50005 0 0 0 373,167.5 v 0.5 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.91992 a 0.50005,0.50005 0 0 0 0.4043,-0.11328 0.50005,0.50005 0 0 0 0.004,-0.002 0.50005,0.50005 0 0 0 0.0332,-0.0312 0.50005,0.50005 0 0 0 0.002,-0.004 0.50005,0.50005 0 0 0 0.0312,-0.0332 0.50005,0.50005 0 0 0 0.002,-0.004 A 0.50005,0.50005 0 0 0 374,168.41797 V 167.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 369.5,168 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z" id="path14452" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14467" transform="translate(-63.000002,4.4999696e-6)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 347.5,161 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2.5 h -1.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v 1 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m -2,3 h 2 v 2 h -2 z m 4,1 h 2 v 2 h -2 z" id="rect14393" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 342.49219,157.99219 a 0.50005,0.50005 0 0 0 -0.31641,0.12109 0.50005,0.50005 0 0 0 -0.0195,0.0156 0.50005,0.50005 0 0 0 -0.0176,0.0176 0.50005,0.50005 0 0 0 -0.002,0.004 0.50005,0.50005 0 0 0 -0.0312,0.0332 0.50005,0.50005 0 0 0 -0.002,0.004 0.50005,0.50005 0 0 0 -0.0274,0.0371 0.50005,0.50005 0 0 0 -0.002,0.004 A 0.50005,0.50005 0 0 0 342,158.58203 V 159.5 a 0.50005,0.50005 0 1 0 1,0 V 159 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 h -0.91992 a 0.50005,0.50005 0 0 0 -0.0879,-0.008 z m 13,0 A 0.50005,0.50005 0 0 0 355.41797,158 H 354.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.91992 a 0.50005,0.50005 0 0 0 -0.11328,-0.4043 0.50005,0.50005 0 0 0 -0.002,-0.004 0.50005,0.50005 0 0 0 -0.0312,-0.0332 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.0332,-0.0312 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.32031,-0.11133 z M 345.5,158 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m -9.00781,2.99219 A 0.50005,0.50005 0 0 0 342,161.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 13,0 A 0.50005,0.50005 0 0 0 355,161.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -13,3 A 0.50005,0.50005 0 0 0 342,164.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 13,0 A 0.50005,0.50005 0 0 0 355,164.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -13,3 A 0.50005,0.50005 0 0 0 342,167.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 13,0 A 0.50005,0.50005 0 0 0 355,167.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -13,3 A 0.50005,0.50005 0 0 0 342,170.5 v 0.91992 a 0.50005,0.50005 0 0 0 0.11328,0.4043 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 342.58203,172 H 343.5 a 0.50005,0.50005 0 1 0 0,-1 H 343 v -0.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 13,0 A 0.50005,0.50005 0 0 0 355,170.5 v 0.5 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.91992 a 0.50005,0.50005 0 0 0 0.4043,-0.11328 0.50005,0.50005 0 0 0 0.004,-0.002 0.50005,0.50005 0 0 0 0.0332,-0.0312 0.50005,0.50005 0 0 0 0.002,-0.004 0.50005,0.50005 0 0 0 0.0312,-0.0332 0.50005,0.50005 0 0 0 0.002,-0.004 0.50005,0.50005 0 0 0 0.0274,-0.0371 0.50005,0.50005 0 0 0 0.002,-0.004 0.50005,0.50005 0 0 0 0.074,-0.35325 V 170.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 345.5,171 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z" id="path14460" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 118.5,201 a 0.50005,0.50005 0 0 0 -0.5,0.5 V 212 h -6.5 a 0.50005,0.50005 0 1 0 0,1 h 7 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 202 h 5.5 a 0.50005,0.50005 0 1 0 0,-1 z" id="path13715" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 144.5,201 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 133.29297,212 H 132.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 L 144.70703,202 H 145.5 a 0.50005,0.50005 0 1 0 0,-1 z" id="path13875" inkscape:connector-curvature="0"/>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g13432">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 166,201 c -1.59692,0 -2.85915,0.78757 -3.86133,1.88086 -1.00218,1.09329 -1.79297,2.49805 -2.57422,3.87305 -0.78125,1.375 -1.55296,2.72024 -2.4414,3.68945 C 156.2346,211.41257 155.27808,212 154,212 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 c 1.59692,0 2.85915,-0.78757 3.86133,-1.88086 1.00218,-1.09329 1.79297,-2.49805 2.57422,-3.87305 0.78125,-1.375 1.55296,-2.72024 2.4414,-3.68945 C 163.7654,202.58743 164.72192,202 166,202 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 z" id="path14036" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 154.5,200 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 202 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 H 157 v -0.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 0.41992 a 0.50005,0.50005 0 0 0 0,0.16211 V 202 h -1 z m 8.50781,10 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -3.5 a 0.50005,0.50005 0 1 0 0,1 h 3.5 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 v -0.42383 a 0.50005,0.50005 0 0 0 0,-0.15234 z" id="path14257" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 291.5,201 a 0.50005,0.50005 0 0 0 -0.5,0.5 c 0,2.47889 -0.15954,4.38104 -0.52734,5.8125 -0.36781,1.43146 -0.92559,2.38009 -1.74024,3.05273 C 287.10312,211.71053 284.21571,212 279.5,212 a 0.50005,0.50005 0 1 0 0,1 c 4.75093,0 7.86511,-0.21053 9.86914,-1.86523 1.00202,-0.82736 1.66924,-2.00373 2.07227,-3.57227 0.36978,-1.43916 0.48747,-3.33151 0.51171,-5.5625 H 292.5 a 0.50005,0.50005 0 1 0 0,-1 z" id="path14276" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 312.5,201 a 0.50005,0.50005 0 0 0 -0.5,0.5 c 0,3.43021 -1.19149,5.7903 -3.2168,7.45898 -2.0253,1.66869 -4.93239,2.63003 -8.34375,3.04493 a 0.50005,0.50005 0 1 0 0.1211,0.99218 c 3.52614,-0.42885 6.61905,-1.41978 8.85937,-3.26562 2.13154,-1.75622 3.41037,-4.32825 3.5332,-7.73047 H 313.5 a 0.50005,0.50005 0 1 0 0,-1 z" id="path14278" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 439,201 c -1.59692,0 -2.85915,0.78757 -3.86133,1.88086 -1.00218,1.09329 -1.79297,2.49805 -2.57422,3.87305 -0.78125,1.375 -1.55296,2.72024 -2.4414,3.68945 C 429.2346,211.41257 428.27808,212 427,212 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 c 1.59692,0 2.85915,-0.78757 3.86133,-1.88086 1.00218,-1.09329 1.79297,-2.49805 2.57422,-3.87305 0.78125,-1.375 1.55296,-2.72024 2.4414,-3.68945 C 436.7654,202.58743 437.72192,202 439,202 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 z" id="path14305" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 321.5,201 a 0.50005,0.50005 0 1 0 0,1 h 0.5 c 0.11714,0 0.21825,0.0354 0.36133,0.1582 0.14308,0.12279 0.30922,0.33684 0.46875,0.63282 0.31905,0.59195 0.61443,1.49542 0.87109,2.55468 0.51334,2.11854 0.89163,4.86411 1.30664,7.24024 a 0.50005,0.50005 0 0 0 0.98242,0.008 c 0.24141,-1.26736 0.60565,-2.19557 0.98829,-2.76953 0.38264,-0.57396 0.74023,-0.76172 1.02148,-0.76172 0.28125,0 0.63884,0.18776 1.02148,0.76172 0.38264,0.57396 0.74688,1.50217 0.98829,2.76953 a 0.50005,0.50005 0 0 0 0.96093,0.0762 c 0.24086,-0.66235 0.48023,-1.14224 0.6836,-1.42187 0.20337,-0.27964 0.32487,-0.31055 0.3457,-0.31055 0.0208,0 0.14233,0.0309 0.3457,0.31055 0.20337,0.27963 0.44274,0.75952 0.6836,1.42187 A 0.50005,0.50005 0 0 0 333.5,213 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -0.69141 c -0.20925,-0.52074 -0.41629,-1.01454 -0.65429,-1.3418 -0.29663,-0.40786 -0.67513,-0.7207 -1.1543,-0.7207 -0.47917,0 -0.85767,0.31284 -1.1543,0.7207 -0.10194,0.14017 -0.18655,0.39972 -0.28125,0.57422 -0.21984,-0.70238 -0.40285,-1.50076 -0.71093,-1.96289 -0.49236,-0.73854 -1.13477,-1.20703 -1.85352,-1.20703 -0.71875,0 -1.36116,0.46849 -1.85352,1.20703 -0.20879,0.3132 -0.31334,0.90706 -0.48242,1.33008 -0.30463,-1.87209 -0.5915,-3.83467 -0.99218,-5.48828 -0.26658,-1.10016 -0.56623,-2.0626 -0.96094,-2.79492 -0.19736,-0.36617 -0.41893,-0.67716 -0.69727,-0.91602 C 322.73533,201.16153 322.38008,201 322,201 Z" id="path53380-0" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 342.45117,201 a 0.50059574,0.50059574 0 0 0 0.0488,1 c 0.0215,2e-5 0.18225,-1.7e-4 0.33398,0 0.0105,0.42607 0.0502,2.52232 0.33594,5.05664 0.15671,1.39002 0.37504,2.78188 0.69727,3.86719 0.16111,0.54265 0.34457,1.00922 0.59179,1.38086 0.24723,0.37163 0.61429,0.69531 1.09375,0.69531 0.39174,0 0.74881,-0.20864 0.97657,-0.48047 0.22775,-0.27182 0.37091,-0.59987 0.48632,-0.96289 0.23084,-0.72603 0.34622,-1.61436 0.46876,-2.48828 0.12253,-0.87392 0.25275,-1.73314 0.44921,-2.31641 0.0982,-0.29163 0.21467,-0.50852 0.31446,-0.62109 C 348.34784,206.01829 348.39286,206 348.5,206 c 0.16824,0 0.2932,0.0848 0.48633,0.39062 0.19312,0.30582 0.37727,0.78401 0.5625,1.28321 0.18523,0.49919 0.37171,1.01992 0.64453,1.46289 0.27281,0.44297 0.71019,0.86328 1.30664,0.86328 0.41993,0 0.77613,-0.23568 0.99219,-0.49219 0.21606,-0.2565 0.34747,-0.53797 0.4707,-0.78906 0.12323,-0.25109 0.23849,-0.47074 0.33594,-0.58984 C 353.39628,208.0098 353.41651,208 353.5,208 c 0.0859,0 0.18647,0.0811 0.39844,0.32617 0.10598,0.12255 0.22449,0.26923 0.39453,0.40625 C 354.463,208.86945 354.71104,209 355,209 c 0.008,0 0.14542,-2.8e-4 0.27539,0 0.065,1.4e-4 0.13031,6e-5 0.18164,0 0.0513,-6e-5 0.0312,0.005 0.12109,0 a 0.50080138,0.50080138 0 1 0 -0.0566,-1 c 0.0748,-0.004 -0.0172,-5e-5 -0.0664,0 -0.0492,5e-5 -0.11331,1.4e-4 -0.17774,0 -0.12885,-2.8e-4 -0.25041,0 -0.27734,0 -0.0108,0 -0.0173,0.004 -0.0801,-0.0469 -0.0628,-0.0506 -0.15527,-0.15364 -0.26562,-0.28124 C 354.43358,207.41667 354.08387,207 353.5,207 c -0.4167,0 -0.76719,0.23824 -0.97656,0.49414 -0.20937,0.2559 -0.33683,0.53625 -0.45899,0.78516 -0.12215,0.24891 -0.23808,0.46744 -0.33789,0.58593 C 351.62675,208.98373 351.59835,209 351.5,209 c -0.14972,0 -0.26794,-0.0816 -0.45703,-0.38867 -0.18909,-0.30703 -0.37082,-0.78435 -0.55664,-1.28516 -0.18583,-0.5008 -0.37575,-1.02457 -0.65625,-1.46875 C 349.54958,205.41324 349.10136,205 348.5,205 c -0.39664,0 -0.76041,0.19848 -1,0.46875 -0.23959,0.27027 -0.39279,0.60017 -0.51562,0.96484 -0.24567,0.72934 -0.36739,1.61988 -0.49024,2.4961 -0.12285,0.87621 -0.24515,1.73764 -0.43164,2.32422 -0.0933,0.29328 -0.20581,0.51202 -0.29883,0.62304 -0.093,0.11102 -0.1237,0.12305 -0.21094,0.12305 -0.027,0 -0.10877,-0.0201 -0.26171,-0.25 -0.15295,-0.22991 -0.31979,-0.62276 -0.46485,-1.11133 -0.29011,-0.97714 -0.5088,-2.33541 -0.66211,-3.69531 -0.30662,-2.7198 -0.36328,-5.45313 -0.36328,-5.45313 a 0.50005,0.50005 0 0 0 -0.5,-0.49023 c -0.0468,0 -0.74734,5e-5 -0.80078,0 a 0.50005,0.50005 0 0 0 -0.0488,0 z" id="path16468-1" inkscape:connector-curvature="0"/>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g14237">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 207.5,201 a 0.50005,0.50005 0 0 0 -0.40039,0.19922 c -1.548,2.064 -2.85356,4.80197 -4.58594,6.99023 C 200.78129,210.37772 198.70216,212 195.5,212 a 0.50005,0.50005 0 1 0 0,1 c 3.54784,0 5.96871,-1.87772 7.79883,-4.18945 1.7781,-2.24603 3.06678,-4.88493 4.4707,-6.81055 H 208.5 a 0.50005,0.50005 0 1 0 0,-1 z" id="path14262" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 197,199.99609 c -0.79172,0 -1.70536,0.42738 -1.98047,1.35938 a 0.50090117,0.50090117 0 1 0 0.96094,0.2832 c 0.12417,-0.42064 0.57767,-0.64258 1.01953,-0.64258 0.26308,0 0.50603,0.0889 0.67773,0.2461 0.17133,0.15683 0.29488,0.38005 0.29883,0.75976 0.001,0.2095 -0.10056,0.41777 -0.33789,0.6875 -0.23733,0.26973 -0.59584,0.56699 -0.97656,0.90235 -0.76143,0.67072 -1.65792,1.5571 -1.66211,2.90234 a 0.50005,0.50005 0 0 0 0.5,0.50195 h 3 a 0.50005,0.50005 0 1 0 0,-1 h -2.33398 c 0.18416,-0.62502 0.58645,-1.15066 1.1582,-1.65429 0.36326,-0.31999 0.74752,-0.62977 1.0664,-0.99219 0.31889,-0.36243 0.58851,-0.81103 0.58594,-1.35156 a 0.50005,0.50005 0 0 0 0,-0.002 c -0.006,-0.61869 -0.24656,-1.14755 -0.62304,-1.49218 -0.37648,-0.34464 -0.8666,-0.50782 -1.35352,-0.50782 z" id="path12457-3" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g14233">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 186.5,201 a 0.50005,0.50005 0 0 0 -0.40039,0.19922 c -1.548,2.064 -2.85356,4.80197 -4.58594,6.99023 C 179.78129,210.37772 177.70216,212 174.5,212 a 0.50005,0.50005 0 1 0 0,1 c 3.54784,0 5.96871,-1.87772 7.79883,-4.18945 1.7781,-2.24603 3.06678,-4.88493 4.4707,-6.81055 H 187.5 a 0.50005,0.50005 0 1 0 0,-1 z" id="path14011" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 176.48438,199.99609 a 0.50005,0.50005 0 0 0 -0.3379,0.14649 l -2,2 a 0.50005,0.50005 0 1 0 0.70704,0.70703 L 176,201.70312 V 206.5 a 0.50005,0.50005 0 1 0 1,0 v -6.00391 a 0.50005,0.50005 0 0 0 -0.51562,-0.5 z" id="path12461-0" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g14241">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 228.5,201 a 0.50005,0.50005 0 0 0 -0.47461,0.3418 c -0.75176,2.25527 -1.61792,4.94183 -3.29101,7.0332 -1.6731,2.09137 -4.11183,3.625 -8.23438,3.625 a 0.50005,0.50005 0 1 0 0,1 c 4.37745,0 7.18872,-1.71637 9.01562,-4 1.74159,-2.17699 2.6089,-4.81175 3.33594,-7 H 229.5 a 0.50005,0.50005 0 1 0 0,-1 z" id="path14266" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 218.99805,199.99609 c -0.79172,0 -1.70536,0.42738 -1.98047,1.35938 a 0.50005,0.50005 0 1 0 0.95898,0.2832 c 0.12417,-0.42064 0.57962,-0.64258 1.02149,-0.64258 0.26387,0 0.51715,0.0894 0.69531,0.24805 0.17816,0.15864 0.30325,0.37905 0.30664,0.75586 0.001,0.39768 -0.25396,0.75725 -0.76367,1.07422 a 0.50005,0.50005 0 0 0 0,0.84766 c 0.51034,0.31737 0.7656,0.67798 0.76367,1.07617 -0.004,0.37528 -0.12888,0.59561 -0.30664,0.7539 -0.17816,0.15864 -0.43144,0.24805 -0.69531,0.24805 -0.44187,0 -0.89732,-0.21999 -1.02149,-0.64062 a 0.50005,0.50005 0 1 0 -0.95898,0.28124 c 0.27511,0.93201 1.18875,1.35938 1.98047,1.35938 0.48612,0 0.97796,-0.16058 1.36133,-0.50195 0.38336,-0.34137 0.63501,-0.871 0.64062,-1.49414 a 0.50005,0.50005 0 0 0 0,-0.002 c 0.003,-0.61795 -0.34308,-1.09989 -0.77734,-1.5039 0.43425,-0.40402 0.78027,-0.88601 0.77734,-1.50391 a 0.50005,0.50005 0 0 0 0,-0.002 c -0.006,-0.62314 -0.25726,-1.15277 -0.64062,-1.49414 -0.38337,-0.34137 -0.87521,-0.50196 -1.36133,-0.50196 z" id="path14395" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g14249">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 270.5,201 a 0.50005,0.50005 0 0 0 -0.5,0.5 c 0,3.44341 -1.07548,6.03173 -3.02344,7.79102 C 265.02861,211.0503 262.16329,212 258.5,212 a 0.50005,0.50005 0 1 0 0,1 c 3.83671,0 6.97139,-1.00062 9.14844,-2.9668 2.06597,-1.86586 3.15029,-4.63736 3.26367,-8.0332 H 271.5 a 0.50005,0.50005 0 1 0 0,-1 z" id="path14273" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 258.5,199.99609 a 0.50005,0.50005 0 0 0 -0.5,0.5 V 202.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.5 c 0.41667,0 1,0.45 1,1.5 0,1.04998 -0.58056,1.4941 -1.00195,1.49609 -0.52634,0.003 -0.86013,-0.33871 -1.05078,-0.72265 a 0.50005,0.50005 0 1 0 -0.89454,0.44531 c 0.30945,0.62316 0.97566,1.28254 1.94922,1.27734 C 261.08054,206.99099 262,205.95002 262,204.5 c 0,-1.45 -0.91667,-2.5 -2,-2.5 h -1 v -1.00391 h 2.5 a 0.50005,0.50005 0 1 0 0,-1 z" id="path14399" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g14245">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 249.5,201 a 0.50005,0.50005 0 0 0 -0.49805,0.45508 c -0.24047,2.64524 -1.32572,5.28945 -3.23633,7.25976 C 243.85502,210.68516 241.12778,212 237.5,212 a 0.50005,0.50005 0 1 0 0,1 c 3.87222,0 6.89498,-1.43516 8.98438,-3.58984 1.97612,-2.03788 3.06007,-4.712 3.39843,-7.41016 H 250.5 a 0.50005,0.50005 0 1 0 0,-1 z" id="path14271" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 238.4668,199.99414 c -0.21842,0.0156 -0.40126,0.17156 -0.45118,0.38477 l -1,4 c -0.0786,0.31522 0.15949,0.62057 0.48438,0.62109 h 2.5 v 1.5 c -0.01,0.67616 1.00956,0.67616 1,0 v -4 c -0.009,-0.6573 -0.9907,-0.6573 -1,0 v 1.5 h -1.85938 l 0.84376,-3.37891 c 0.0877,-0.33109 -0.17587,-0.65038 -0.51758,-0.62695 z" id="path14402" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccc"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 375.5,201 a 0.50005,0.50005 0 0 0 -0.47852,0.35547 c -0.97912,3.26329 -1.65795,6.01658 -2.41406,7.89453 -0.37805,0.93897 -0.77714,1.65307 -1.20117,2.10156 C 370.98222,211.80006 370.56872,212 370,212 c -0.81989,0 -1.77194,-0.85368 -2.74219,-1.84961 -0.48512,-0.49796 -0.97309,-1.01146 -1.49609,-1.41992 C 365.23871,208.32201 364.66174,208 364,208 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 c 0.32338,0 0.70916,0.17799 1.14648,0.51953 0.43732,0.34154 0.9074,0.82804 1.39649,1.33008 C 367.52115,211.85368 368.58382,213 370,213 c 0.83577,0 1.56694,-0.36242 2.13281,-0.96094 0.56587,-0.59851 1.00027,-1.41738 1.40235,-2.41601 0.7683,-1.90825 1.43134,-4.57357 2.33398,-7.62305 H 376.5 a 0.50005,0.50005 0 1 0 0,-1 z" id="path16580-7" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 396.5,201 a 0.50005,0.50005 0 0 0 -0.40039,0.19922 c -1.548,2.064 -2.85356,4.80197 -4.58594,6.99023 C 389.78129,210.37772 387.70216,212 384.5,212 a 0.50005,0.50005 0 1 0 0,1 c 3.54784,0 5.96871,-1.87772 7.79883,-4.18945 1.7781,-2.24603 3.06678,-4.88493 4.4707,-6.81055 H 397.5 a 0.50005,0.50005 0 1 0 0,-1 z" id="path14011-0" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 418.5,201 c -3.54784,0 -5.96871,1.87772 -7.79883,4.18945 -1.7781,2.24603 -3.06678,4.88493 -4.4707,6.81055 H 405.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.40039,-0.19922 c 1.548,-2.064 2.85356,-4.80197 4.58594,-6.99023 C 413.21871,203.62228 415.29784,202 418.5,202 a 0.50005,0.50005 0 1 0 0,-1 z" id="path14049" inkscape:connector-curvature="0"/>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g14253">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 447.5,200 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 1 0 1,0 V 201 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 z m 9.00781,0 a 0.50005,0.50005 0 1 0 0,1 h 3.5 v 3.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -9.01562,9 A 0.50005,0.50005 0 0 0 447,209.50781 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 H 448 v -3.5 A 0.50005,0.50005 0 0 0 447.49219,209 Z M 460.5,209 a 0.50005,0.50005 0 0 0 -0.49219,0.50781 v 3.5 h -3.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4 A 0.50005,0.50005 0 0 0 460.5,209 Z" id="path13927-5" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 449.5,203 a 0.50005,0.50005 0 1 0 0,1 h 1 c 0.39167,0 0.74862,0.27445 1.13672,0.86719 0.3881,0.59273 0.74407,1.4462 1.08594,2.3164 0.34186,0.8702 0.67067,1.75605 1.06836,2.4668 0.19884,0.35538 0.41332,0.66981 0.68554,0.91797 0.27222,0.24816 0.62761,0.43164 1.02344,0.43164 0.625,0 1.13349,-0.27613 1.44727,-0.64648 0.31377,-0.37036 0.47247,-0.79704 0.61523,-1.17774 0.14276,-0.3807 0.2723,-0.71757 0.41406,-0.91016 C 458.11833,208.07304 458.20536,208 458.5,208 a 0.50005,0.50005 0 1 0 0,-1 c -0.58036,0 -1.05583,0.30196 -1.32812,0.67188 -0.2723,0.36991 -0.40839,0.78304 -0.54688,1.15234 -0.13849,0.3693 -0.27667,0.69262 -0.43945,0.88476 C 456.02276,209.90113 455.875,210 455.5,210 c -0.10417,0 -0.20191,-0.0353 -0.34961,-0.16992 -0.1477,-0.13465 -0.31994,-0.3671 -0.48828,-0.66797 -0.33669,-0.60175 -0.66413,-1.4659 -1.00977,-2.3457 -0.34563,-0.8798 -0.70841,-1.77633 -1.17968,-2.4961 C 452.00138,203.60055 451.35833,203 450.5,203 Z" id="path14224" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g13322" transform="translate(-1.8536743e-6,21.000005)">
- <g id="g14281" transform="translate(84,200)" style="opacity:0.6;fill:#ffffff">
- <g transform="matrix(1,0,0,-1,-294,368)" id="g14276" style="opacity:1;fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 300.5,375 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 9 v 2 h -9 z" id="path14272" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 304.5,378 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 8 v 2 h -8 z" id="path14274" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 304.5,158 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m 4.5,5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m -8.5,2 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z"
+ id="rect13801"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14472"
+ transform="translate(-42.000002,4.4999696e-6)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 373.5,158 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m -10.5,9 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z"
+ id="rect14387"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 366.49219,160.99219 a 0.50005,0.50005 0 0 0 -0.31641,0.12109 0.50005,0.50005 0 0 0 -0.0195,0.0156 0.50005,0.50005 0 0 0 -0.0176,0.0176 0.50005,0.50005 0 0 0 -0.002,0.004 0.50005,0.50005 0 0 0 -0.0312,0.0332 0.50005,0.50005 0 0 0 -0.002,0.004 A 0.50005,0.50005 0 0 0 366,161.58203 V 162.5 a 0.50005,0.50005 0 1 0 1,0 V 162 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 h -0.91992 a 0.50005,0.50005 0 0 0 -0.0879,-0.008 z m 7,0 A 0.50005,0.50005 0 0 0 373.41797,161 H 372.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.91992 a 0.50005,0.50005 0 0 0 -0.11328,-0.4043 0.50005,0.50005 0 0 0 -0.002,-0.004 0.50005,0.50005 0 0 0 -0.0312,-0.0332 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.0332,-0.0312 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.32031,-0.11133 z M 369.5,161 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m -3.00781,2.99219 A 0.50005,0.50005 0 0 0 366,164.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 7,0 A 0.50005,0.50005 0 0 0 373,164.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -7,3 A 0.50005,0.50005 0 0 0 366,167.5 v 0.91992 a 0.50005,0.50005 0 0 0 0.11328,0.4043 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 366.58203,169 H 367.5 a 0.50005,0.50005 0 1 0 0,-1 H 367 v -0.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 7,0 A 0.50005,0.50005 0 0 0 373,167.5 v 0.5 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.91992 a 0.50005,0.50005 0 0 0 0.4043,-0.11328 0.50005,0.50005 0 0 0 0.004,-0.002 0.50005,0.50005 0 0 0 0.0332,-0.0312 0.50005,0.50005 0 0 0 0.002,-0.004 0.50005,0.50005 0 0 0 0.0312,-0.0332 0.50005,0.50005 0 0 0 0.002,-0.004 A 0.50005,0.50005 0 0 0 374,168.41797 V 167.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 369.5,168 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14452"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14467"
+ transform="translate(-63.000002,4.4999696e-6)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 347.5,161 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2.5 h -1.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v 1 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m -2,3 h 2 v 2 h -2 z m 4,1 h 2 v 2 h -2 z"
+ id="rect14393"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 342.49219,157.99219 a 0.50005,0.50005 0 0 0 -0.31641,0.12109 0.50005,0.50005 0 0 0 -0.0195,0.0156 0.50005,0.50005 0 0 0 -0.0176,0.0176 0.50005,0.50005 0 0 0 -0.002,0.004 0.50005,0.50005 0 0 0 -0.0312,0.0332 0.50005,0.50005 0 0 0 -0.002,0.004 0.50005,0.50005 0 0 0 -0.0274,0.0371 0.50005,0.50005 0 0 0 -0.002,0.004 A 0.50005,0.50005 0 0 0 342,158.58203 V 159.5 a 0.50005,0.50005 0 1 0 1,0 V 159 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 h -0.91992 a 0.50005,0.50005 0 0 0 -0.0879,-0.008 z m 13,0 A 0.50005,0.50005 0 0 0 355.41797,158 H 354.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.91992 a 0.50005,0.50005 0 0 0 -0.11328,-0.4043 0.50005,0.50005 0 0 0 -0.002,-0.004 0.50005,0.50005 0 0 0 -0.0312,-0.0332 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.0332,-0.0312 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.32031,-0.11133 z M 345.5,158 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m -9.00781,2.99219 A 0.50005,0.50005 0 0 0 342,161.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 13,0 A 0.50005,0.50005 0 0 0 355,161.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -13,3 A 0.50005,0.50005 0 0 0 342,164.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 13,0 A 0.50005,0.50005 0 0 0 355,164.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -13,3 A 0.50005,0.50005 0 0 0 342,167.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 13,0 A 0.50005,0.50005 0 0 0 355,167.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -13,3 A 0.50005,0.50005 0 0 0 342,170.5 v 0.91992 a 0.50005,0.50005 0 0 0 0.11328,0.4043 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 342.58203,172 H 343.5 a 0.50005,0.50005 0 1 0 0,-1 H 343 v -0.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 13,0 A 0.50005,0.50005 0 0 0 355,170.5 v 0.5 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.91992 a 0.50005,0.50005 0 0 0 0.4043,-0.11328 0.50005,0.50005 0 0 0 0.004,-0.002 0.50005,0.50005 0 0 0 0.0332,-0.0312 0.50005,0.50005 0 0 0 0.002,-0.004 0.50005,0.50005 0 0 0 0.0312,-0.0332 0.50005,0.50005 0 0 0 0.002,-0.004 0.50005,0.50005 0 0 0 0.0274,-0.0371 0.50005,0.50005 0 0 0 0.002,-0.004 0.50005,0.50005 0 0 0 0.074,-0.35325 V 170.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 345.5,171 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14460"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 118.5,201 a 0.50005,0.50005 0 0 0 -0.5,0.5 V 212 h -6.5 a 0.50005,0.50005 0 1 0 0,1 h 7 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 202 h 5.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path13715"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 144.5,201 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 133.29297,212 H 132.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 L 144.70703,202 H 145.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path13875"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13432">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 166,201 c -1.59692,0 -2.85915,0.78757 -3.86133,1.88086 -1.00218,1.09329 -1.79297,2.49805 -2.57422,3.87305 -0.78125,1.375 -1.55296,2.72024 -2.4414,3.68945 C 156.2346,211.41257 155.27808,212 154,212 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 c 1.59692,0 2.85915,-0.78757 3.86133,-1.88086 1.00218,-1.09329 1.79297,-2.49805 2.57422,-3.87305 0.78125,-1.375 1.55296,-2.72024 2.4414,-3.68945 C 163.7654,202.58743 164.72192,202 166,202 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14036"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 154.5,200 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 202 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 H 157 v -0.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 0.41992 a 0.50005,0.50005 0 0 0 0,0.16211 V 202 h -1 z m 8.50781,10 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -3.5 a 0.50005,0.50005 0 1 0 0,1 h 3.5 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 v -0.42383 a 0.50005,0.50005 0 0 0 0,-0.15234 z"
+ id="path14257"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 291.5,201 a 0.50005,0.50005 0 0 0 -0.5,0.5 c 0,2.47889 -0.15954,4.38104 -0.52734,5.8125 -0.36781,1.43146 -0.92559,2.38009 -1.74024,3.05273 C 287.10312,211.71053 284.21571,212 279.5,212 a 0.50005,0.50005 0 1 0 0,1 c 4.75093,0 7.86511,-0.21053 9.86914,-1.86523 1.00202,-0.82736 1.66924,-2.00373 2.07227,-3.57227 0.36978,-1.43916 0.48747,-3.33151 0.51171,-5.5625 H 292.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14276"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 312.5,201 a 0.50005,0.50005 0 0 0 -0.5,0.5 c 0,3.43021 -1.19149,5.7903 -3.2168,7.45898 -2.0253,1.66869 -4.93239,2.63003 -8.34375,3.04493 a 0.50005,0.50005 0 1 0 0.1211,0.99218 c 3.52614,-0.42885 6.61905,-1.41978 8.85937,-3.26562 2.13154,-1.75622 3.41037,-4.32825 3.5332,-7.73047 H 313.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14278"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 439,201 c -1.59692,0 -2.85915,0.78757 -3.86133,1.88086 -1.00218,1.09329 -1.79297,2.49805 -2.57422,3.87305 -0.78125,1.375 -1.55296,2.72024 -2.4414,3.68945 C 429.2346,211.41257 428.27808,212 427,212 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 c 1.59692,0 2.85915,-0.78757 3.86133,-1.88086 1.00218,-1.09329 1.79297,-2.49805 2.57422,-3.87305 0.78125,-1.375 1.55296,-2.72024 2.4414,-3.68945 C 436.7654,202.58743 437.72192,202 439,202 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14305"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 321.5,201 a 0.50005,0.50005 0 1 0 0,1 h 0.5 c 0.11714,0 0.21825,0.0354 0.36133,0.1582 0.14308,0.12279 0.30922,0.33684 0.46875,0.63282 0.31905,0.59195 0.61443,1.49542 0.87109,2.55468 0.51334,2.11854 0.89163,4.86411 1.30664,7.24024 a 0.50005,0.50005 0 0 0 0.98242,0.008 c 0.24141,-1.26736 0.60565,-2.19557 0.98829,-2.76953 0.38264,-0.57396 0.74023,-0.76172 1.02148,-0.76172 0.28125,0 0.63884,0.18776 1.02148,0.76172 0.38264,0.57396 0.74688,1.50217 0.98829,2.76953 a 0.50005,0.50005 0 0 0 0.96093,0.0762 c 0.24086,-0.66235 0.48023,-1.14224 0.6836,-1.42187 0.20337,-0.27964 0.32487,-0.31055 0.3457,-0.31055 0.0208,0 0.14233,0.0309 0.3457,0.31055 0.20337,0.27963 0.44274,0.75952 0.6836,1.42187 A 0.50005,0.50005 0 0 0 333.5,213 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -0.69141 c -0.20925,-0.52074 -0.41629,-1.01454 -0.65429,-1.3418 -0.29663,-0.40786 -0.67513,-0.7207 -1.1543,-0.7207 -0.47917,0 -0.85767,0.31284 -1.1543,0.7207 -0.10194,0.14017 -0.18655,0.39972 -0.28125,0.57422 -0.21984,-0.70238 -0.40285,-1.50076 -0.71093,-1.96289 -0.49236,-0.73854 -1.13477,-1.20703 -1.85352,-1.20703 -0.71875,0 -1.36116,0.46849 -1.85352,1.20703 -0.20879,0.3132 -0.31334,0.90706 -0.48242,1.33008 -0.30463,-1.87209 -0.5915,-3.83467 -0.99218,-5.48828 -0.26658,-1.10016 -0.56623,-2.0626 -0.96094,-2.79492 -0.19736,-0.36617 -0.41893,-0.67716 -0.69727,-0.91602 C 322.73533,201.16153 322.38008,201 322,201 Z"
+ id="path53380-0"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 342.45117,201 a 0.50059574,0.50059574 0 0 0 0.0488,1 c 0.0215,2e-5 0.18225,-1.7e-4 0.33398,0 0.0105,0.42607 0.0502,2.52232 0.33594,5.05664 0.15671,1.39002 0.37504,2.78188 0.69727,3.86719 0.16111,0.54265 0.34457,1.00922 0.59179,1.38086 0.24723,0.37163 0.61429,0.69531 1.09375,0.69531 0.39174,0 0.74881,-0.20864 0.97657,-0.48047 0.22775,-0.27182 0.37091,-0.59987 0.48632,-0.96289 0.23084,-0.72603 0.34622,-1.61436 0.46876,-2.48828 0.12253,-0.87392 0.25275,-1.73314 0.44921,-2.31641 0.0982,-0.29163 0.21467,-0.50852 0.31446,-0.62109 C 348.34784,206.01829 348.39286,206 348.5,206 c 0.16824,0 0.2932,0.0848 0.48633,0.39062 0.19312,0.30582 0.37727,0.78401 0.5625,1.28321 0.18523,0.49919 0.37171,1.01992 0.64453,1.46289 0.27281,0.44297 0.71019,0.86328 1.30664,0.86328 0.41993,0 0.77613,-0.23568 0.99219,-0.49219 0.21606,-0.2565 0.34747,-0.53797 0.4707,-0.78906 0.12323,-0.25109 0.23849,-0.47074 0.33594,-0.58984 C 353.39628,208.0098 353.41651,208 353.5,208 c 0.0859,0 0.18647,0.0811 0.39844,0.32617 0.10598,0.12255 0.22449,0.26923 0.39453,0.40625 C 354.463,208.86945 354.71104,209 355,209 c 0.008,0 0.14542,-2.8e-4 0.27539,0 0.065,1.4e-4 0.13031,6e-5 0.18164,0 0.0513,-6e-5 0.0312,0.005 0.12109,0 a 0.50080138,0.50080138 0 1 0 -0.0566,-1 c 0.0748,-0.004 -0.0172,-5e-5 -0.0664,0 -0.0492,5e-5 -0.11331,1.4e-4 -0.17774,0 -0.12885,-2.8e-4 -0.25041,0 -0.27734,0 -0.0108,0 -0.0173,0.004 -0.0801,-0.0469 -0.0628,-0.0506 -0.15527,-0.15364 -0.26562,-0.28124 C 354.43358,207.41667 354.08387,207 353.5,207 c -0.4167,0 -0.76719,0.23824 -0.97656,0.49414 -0.20937,0.2559 -0.33683,0.53625 -0.45899,0.78516 -0.12215,0.24891 -0.23808,0.46744 -0.33789,0.58593 C 351.62675,208.98373 351.59835,209 351.5,209 c -0.14972,0 -0.26794,-0.0816 -0.45703,-0.38867 -0.18909,-0.30703 -0.37082,-0.78435 -0.55664,-1.28516 -0.18583,-0.5008 -0.37575,-1.02457 -0.65625,-1.46875 C 349.54958,205.41324 349.10136,205 348.5,205 c -0.39664,0 -0.76041,0.19848 -1,0.46875 -0.23959,0.27027 -0.39279,0.60017 -0.51562,0.96484 -0.24567,0.72934 -0.36739,1.61988 -0.49024,2.4961 -0.12285,0.87621 -0.24515,1.73764 -0.43164,2.32422 -0.0933,0.29328 -0.20581,0.51202 -0.29883,0.62304 -0.093,0.11102 -0.1237,0.12305 -0.21094,0.12305 -0.027,0 -0.10877,-0.0201 -0.26171,-0.25 -0.15295,-0.22991 -0.31979,-0.62276 -0.46485,-1.11133 -0.29011,-0.97714 -0.5088,-2.33541 -0.66211,-3.69531 -0.30662,-2.7198 -0.36328,-5.45313 -0.36328,-5.45313 a 0.50005,0.50005 0 0 0 -0.5,-0.49023 c -0.0468,0 -0.74734,5e-5 -0.80078,0 a 0.50005,0.50005 0 0 0 -0.0488,0 z"
+ id="path16468-1"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14237">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 207.5,201 a 0.50005,0.50005 0 0 0 -0.40039,0.19922 c -1.548,2.064 -2.85356,4.80197 -4.58594,6.99023 C 200.78129,210.37772 198.70216,212 195.5,212 a 0.50005,0.50005 0 1 0 0,1 c 3.54784,0 5.96871,-1.87772 7.79883,-4.18945 1.7781,-2.24603 3.06678,-4.88493 4.4707,-6.81055 H 208.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14262"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 197,199.99609 c -0.79172,0 -1.70536,0.42738 -1.98047,1.35938 a 0.50090117,0.50090117 0 1 0 0.96094,0.2832 c 0.12417,-0.42064 0.57767,-0.64258 1.01953,-0.64258 0.26308,0 0.50603,0.0889 0.67773,0.2461 0.17133,0.15683 0.29488,0.38005 0.29883,0.75976 0.001,0.2095 -0.10056,0.41777 -0.33789,0.6875 -0.23733,0.26973 -0.59584,0.56699 -0.97656,0.90235 -0.76143,0.67072 -1.65792,1.5571 -1.66211,2.90234 a 0.50005,0.50005 0 0 0 0.5,0.50195 h 3 a 0.50005,0.50005 0 1 0 0,-1 h -2.33398 c 0.18416,-0.62502 0.58645,-1.15066 1.1582,-1.65429 0.36326,-0.31999 0.74752,-0.62977 1.0664,-0.99219 0.31889,-0.36243 0.58851,-0.81103 0.58594,-1.35156 a 0.50005,0.50005 0 0 0 0,-0.002 c -0.006,-0.61869 -0.24656,-1.14755 -0.62304,-1.49218 -0.37648,-0.34464 -0.8666,-0.50782 -1.35352,-0.50782 z"
+ id="path12457-3"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14233">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 186.5,201 a 0.50005,0.50005 0 0 0 -0.40039,0.19922 c -1.548,2.064 -2.85356,4.80197 -4.58594,6.99023 C 179.78129,210.37772 177.70216,212 174.5,212 a 0.50005,0.50005 0 1 0 0,1 c 3.54784,0 5.96871,-1.87772 7.79883,-4.18945 1.7781,-2.24603 3.06678,-4.88493 4.4707,-6.81055 H 187.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14011"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 176.48438,199.99609 a 0.50005,0.50005 0 0 0 -0.3379,0.14649 l -2,2 a 0.50005,0.50005 0 1 0 0.70704,0.70703 L 176,201.70312 V 206.5 a 0.50005,0.50005 0 1 0 1,0 v -6.00391 a 0.50005,0.50005 0 0 0 -0.51562,-0.5 z"
+ id="path12461-0"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14241">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 228.5,201 a 0.50005,0.50005 0 0 0 -0.47461,0.3418 c -0.75176,2.25527 -1.61792,4.94183 -3.29101,7.0332 -1.6731,2.09137 -4.11183,3.625 -8.23438,3.625 a 0.50005,0.50005 0 1 0 0,1 c 4.37745,0 7.18872,-1.71637 9.01562,-4 1.74159,-2.17699 2.6089,-4.81175 3.33594,-7 H 229.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14266"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 218.99805,199.99609 c -0.79172,0 -1.70536,0.42738 -1.98047,1.35938 a 0.50005,0.50005 0 1 0 0.95898,0.2832 c 0.12417,-0.42064 0.57962,-0.64258 1.02149,-0.64258 0.26387,0 0.51715,0.0894 0.69531,0.24805 0.17816,0.15864 0.30325,0.37905 0.30664,0.75586 0.001,0.39768 -0.25396,0.75725 -0.76367,1.07422 a 0.50005,0.50005 0 0 0 0,0.84766 c 0.51034,0.31737 0.7656,0.67798 0.76367,1.07617 -0.004,0.37528 -0.12888,0.59561 -0.30664,0.7539 -0.17816,0.15864 -0.43144,0.24805 -0.69531,0.24805 -0.44187,0 -0.89732,-0.21999 -1.02149,-0.64062 a 0.50005,0.50005 0 1 0 -0.95898,0.28124 c 0.27511,0.93201 1.18875,1.35938 1.98047,1.35938 0.48612,0 0.97796,-0.16058 1.36133,-0.50195 0.38336,-0.34137 0.63501,-0.871 0.64062,-1.49414 a 0.50005,0.50005 0 0 0 0,-0.002 c 0.003,-0.61795 -0.34308,-1.09989 -0.77734,-1.5039 0.43425,-0.40402 0.78027,-0.88601 0.77734,-1.50391 a 0.50005,0.50005 0 0 0 0,-0.002 c -0.006,-0.62314 -0.25726,-1.15277 -0.64062,-1.49414 -0.38337,-0.34137 -0.87521,-0.50196 -1.36133,-0.50196 z"
+ id="path14395"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14249">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 270.5,201 a 0.50005,0.50005 0 0 0 -0.5,0.5 c 0,3.44341 -1.07548,6.03173 -3.02344,7.79102 C 265.02861,211.0503 262.16329,212 258.5,212 a 0.50005,0.50005 0 1 0 0,1 c 3.83671,0 6.97139,-1.00062 9.14844,-2.9668 2.06597,-1.86586 3.15029,-4.63736 3.26367,-8.0332 H 271.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14273"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 258.5,199.99609 a 0.50005,0.50005 0 0 0 -0.5,0.5 V 202.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.5 c 0.41667,0 1,0.45 1,1.5 0,1.04998 -0.58056,1.4941 -1.00195,1.49609 -0.52634,0.003 -0.86013,-0.33871 -1.05078,-0.72265 a 0.50005,0.50005 0 1 0 -0.89454,0.44531 c 0.30945,0.62316 0.97566,1.28254 1.94922,1.27734 C 261.08054,206.99099 262,205.95002 262,204.5 c 0,-1.45 -0.91667,-2.5 -2,-2.5 h -1 v -1.00391 h 2.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14399"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14245">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 249.5,201 a 0.50005,0.50005 0 0 0 -0.49805,0.45508 c -0.24047,2.64524 -1.32572,5.28945 -3.23633,7.25976 C 243.85502,210.68516 241.12778,212 237.5,212 a 0.50005,0.50005 0 1 0 0,1 c 3.87222,0 6.89498,-1.43516 8.98438,-3.58984 1.97612,-2.03788 3.06007,-4.712 3.39843,-7.41016 H 250.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14271"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 238.4668,199.99414 c -0.21842,0.0156 -0.40126,0.17156 -0.45118,0.38477 l -1,4 c -0.0786,0.31522 0.15949,0.62057 0.48438,0.62109 h 2.5 v 1.5 c -0.01,0.67616 1.00956,0.67616 1,0 v -4 c -0.009,-0.6573 -0.9907,-0.6573 -1,0 v 1.5 h -1.85938 l 0.84376,-3.37891 c 0.0877,-0.33109 -0.17587,-0.65038 -0.51758,-0.62695 z"
+ id="path14402"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccc" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 375.5,201 a 0.50005,0.50005 0 0 0 -0.47852,0.35547 c -0.97912,3.26329 -1.65795,6.01658 -2.41406,7.89453 -0.37805,0.93897 -0.77714,1.65307 -1.20117,2.10156 C 370.98222,211.80006 370.56872,212 370,212 c -0.81989,0 -1.77194,-0.85368 -2.74219,-1.84961 -0.48512,-0.49796 -0.97309,-1.01146 -1.49609,-1.41992 C 365.23871,208.32201 364.66174,208 364,208 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 c 0.32338,0 0.70916,0.17799 1.14648,0.51953 0.43732,0.34154 0.9074,0.82804 1.39649,1.33008 C 367.52115,211.85368 368.58382,213 370,213 c 0.83577,0 1.56694,-0.36242 2.13281,-0.96094 0.56587,-0.59851 1.00027,-1.41738 1.40235,-2.41601 0.7683,-1.90825 1.43134,-4.57357 2.33398,-7.62305 H 376.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path16580-7"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 396.5,201 a 0.50005,0.50005 0 0 0 -0.40039,0.19922 c -1.548,2.064 -2.85356,4.80197 -4.58594,6.99023 C 389.78129,210.37772 387.70216,212 384.5,212 a 0.50005,0.50005 0 1 0 0,1 c 3.54784,0 5.96871,-1.87772 7.79883,-4.18945 1.7781,-2.24603 3.06678,-4.88493 4.4707,-6.81055 H 397.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14011-0"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 418.5,201 c -3.54784,0 -5.96871,1.87772 -7.79883,4.18945 -1.7781,2.24603 -3.06678,4.88493 -4.4707,6.81055 H 405.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.40039,-0.19922 c 1.548,-2.064 2.85356,-4.80197 4.58594,-6.99023 C 413.21871,203.62228 415.29784,202 418.5,202 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14049"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14253">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 447.5,200 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 1 0 1,0 V 201 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 z m 9.00781,0 a 0.50005,0.50005 0 1 0 0,1 h 3.5 v 3.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -9.01562,9 A 0.50005,0.50005 0 0 0 447,209.50781 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 H 448 v -3.5 A 0.50005,0.50005 0 0 0 447.49219,209 Z M 460.5,209 a 0.50005,0.50005 0 0 0 -0.49219,0.50781 v 3.5 h -3.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4 A 0.50005,0.50005 0 0 0 460.5,209 Z"
+ id="path13927-5"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 449.5,203 a 0.50005,0.50005 0 1 0 0,1 h 1 c 0.39167,0 0.74862,0.27445 1.13672,0.86719 0.3881,0.59273 0.74407,1.4462 1.08594,2.3164 0.34186,0.8702 0.67067,1.75605 1.06836,2.4668 0.19884,0.35538 0.41332,0.66981 0.68554,0.91797 0.27222,0.24816 0.62761,0.43164 1.02344,0.43164 0.625,0 1.13349,-0.27613 1.44727,-0.64648 0.31377,-0.37036 0.47247,-0.79704 0.61523,-1.17774 0.14276,-0.3807 0.2723,-0.71757 0.41406,-0.91016 C 458.11833,208.07304 458.20536,208 458.5,208 a 0.50005,0.50005 0 1 0 0,-1 c -0.58036,0 -1.05583,0.30196 -1.32812,0.67188 -0.2723,0.36991 -0.40839,0.78304 -0.54688,1.15234 -0.13849,0.3693 -0.27667,0.69262 -0.43945,0.88476 C 456.02276,209.90113 455.875,210 455.5,210 c -0.10417,0 -0.20191,-0.0353 -0.34961,-0.16992 -0.1477,-0.13465 -0.31994,-0.3671 -0.48828,-0.66797 -0.33669,-0.60175 -0.66413,-1.4659 -1.00977,-2.3457 -0.34563,-0.8798 -0.70841,-1.77633 -1.17968,-2.4961 C 452.00138,203.60055 451.35833,203 450.5,203 Z"
+ id="path14224"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13322"
+ transform="translate(-1.8536743e-6,21.000005)">
+ <g
+ id="g14281"
+ transform="translate(84,200)"
+ style="opacity:0.6;fill:#ffffff">
+ <g
+ transform="matrix(1,0,0,-1,-294,368)"
+ id="g14276"
+ style="opacity:1;fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 300.5,375 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 9 v 2 h -9 z"
+ id="path14272"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 304.5,378 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 8 v 2 h -8 z"
+ id="path14274"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 93.5,179 c -0.412872,-7.2e-4 -0.648693,0.47092 -0.400391,0.80078 l 3,4 c 0.2,0.26732 0.600782,0.26732 0.800782,0 l 3,-4 C 100.14869,179.47092 99.912872,178.99928 99.5,179 Z" id="path14203-1" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccc"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g13175">
- <path id="path34600-2" d="m 162.47852,32 c -0.75576,10e-7 -1.40256,0.282822 -1.83399,0.75 -0.30821,0.333747 -0.37373,0.80118 -0.46094,1.25 H 159.25 c -1.74879,0 -3.25,1.267585 -3.25,3 0,0.03444 0.0105,0.06555 0.0117,0.09961 C 156.33181,37.034347 156.66178,37 157,37 c 2.03325,0 3.79424,1.241664 4.57227,3 H 164.25 c 0.73055,0 1.4115,-0.231259 1.91992,-0.667969 C 166.67834,38.895322 167,38.242126 167,37.5 c 0,-1.192468 -0.94634,-2.062761 -2.04297,-2.306641 -0.002,-0.488483 0.0124,-1.101037 -0.24609,-1.74414 C 164.40699,32.693065 163.65613,32.000002 162.47852,32 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.0000006;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 157,38 c -2.20322,0 -4,1.796783 -4,4 0,2.203217 1.79678,4 4,4 2.20322,0 4,-1.796783 4,-4 0,-2.203217 -1.79678,-4 -4,-4 z m 0,1 c 1.66278,0 3,1.337223 3,3 0,1.662777 -1.33722,3 -3,3 -1.66278,0 -3,-1.337223 -3,-3 0,-1.662777 1.33722,-3 3,-3 z" id="ellipse13733" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 154.5,32 c 0.8225,0 1.5,0.677496 1.5,1.5 0,0.822504 -0.6775,1.5 -1.5,1.5 -0.8225,0 -1.5,-0.677496 -1.5,-1.5 0,-0.822504 0.6775,-1.5 1.5,-1.5 z" id="ellipse12632-2" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 292.49023,367.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -10,10 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 10,-10 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z" id="path14294" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14429" transform="translate(-1.8536743e-6,42.000005)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 201.49805,368.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.7207 C 203.68137,373.39211 205,375.04034 205,377 c 0,1.45833 -0.66274,2.34651 -1.76562,2.75 -1.1029,0.40349 -2.7161,0.26002 -4.5,-0.69141 a 0.50005,0.50005 0 1 0 -0.46876,0.88282 c 1.9661,1.04857 3.8529,1.2801 5.3125,0.74609 C 205.03775,380.15349 206,378.79167 206,377 c 0,-2.43412 -1.54431,-4.24525 -3.00195,-6.65039 v -0.85547 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z" transform="translate(1.8536743e-6,-42.000005)" id="path14357" inkscape:connector-curvature="0"/>
- <g style="opacity:0.6;fill:#ffffff" id="g13445">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 195.49805,367.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 370 H 199.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -1.50195 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 V 369 H 204.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.49805 v 0.49414 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.5,1 h 1 v 1 h -1 z m 11,0 h 1 v 1 h -1 z" transform="translate(1.8536743e-6,-42.000005)" id="path14367" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 93.5,179 c -0.412872,-7.2e-4 -0.648693,0.47092 -0.400391,0.80078 l 3,4 c 0.2,0.26732 0.600782,0.26732 0.800782,0 l 3,-4 C 100.14869,179.47092 99.912872,178.99928 99.5,179 Z"
+ id="path14203-1"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ </g>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13175">
+ <path
+ id="path34600-2"
+ d="m 162.47852,32 c -0.75576,10e-7 -1.40256,0.282822 -1.83399,0.75 -0.30821,0.333747 -0.37373,0.80118 -0.46094,1.25 H 159.25 c -1.74879,0 -3.25,1.267585 -3.25,3 0,0.03444 0.0105,0.06555 0.0117,0.09961 C 156.33181,37.034347 156.66178,37 157,37 c 2.03325,0 3.79424,1.241664 4.57227,3 H 164.25 c 0.73055,0 1.4115,-0.231259 1.91992,-0.667969 C 166.67834,38.895322 167,38.242126 167,37.5 c 0,-1.192468 -0.94634,-2.062761 -2.04297,-2.306641 -0.002,-0.488483 0.0124,-1.101037 -0.24609,-1.74414 C 164.40699,32.693065 163.65613,32.000002 162.47852,32 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.0000006;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 157,38 c -2.20322,0 -4,1.796783 -4,4 0,2.203217 1.79678,4 4,4 2.20322,0 4,-1.796783 4,-4 0,-2.203217 -1.79678,-4 -4,-4 z m 0,1 c 1.66278,0 3,1.337223 3,3 0,1.662777 -1.33722,3 -3,3 -1.66278,0 -3,-1.337223 -3,-3 0,-1.662777 1.33722,-3 3,-3 z"
+ id="ellipse13733"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 154.5,32 c 0.8225,0 1.5,0.677496 1.5,1.5 0,0.822504 -0.6775,1.5 -1.5,1.5 -0.8225,0 -1.5,-0.677496 -1.5,-1.5 0,-0.822504 0.6775,-1.5 1.5,-1.5 z"
+ id="ellipse12632-2"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 292.49023,367.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -10,10 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 10,-10 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
+ id="path14294"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14429"
+ transform="translate(-1.8536743e-6,42.000005)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 201.49805,368.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.7207 C 203.68137,373.39211 205,375.04034 205,377 c 0,1.45833 -0.66274,2.34651 -1.76562,2.75 -1.1029,0.40349 -2.7161,0.26002 -4.5,-0.69141 a 0.50005,0.50005 0 1 0 -0.46876,0.88282 c 1.9661,1.04857 3.8529,1.2801 5.3125,0.74609 C 205.03775,380.15349 206,378.79167 206,377 c 0,-2.43412 -1.54431,-4.24525 -3.00195,-6.65039 v -0.85547 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ transform="translate(1.8536743e-6,-42.000005)"
+ id="path14357"
+ inkscape:connector-curvature="0" />
+ <g
+ style="opacity:0.6;fill:#ffffff"
+ id="g13445">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 195.49805,367.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 370 H 199.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -1.50195 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 V 369 H 204.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.49805 v 0.49414 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.5,1 h 1 v 1 h -1 z m 11,0 h 1 v 1 h -1 z"
+ transform="translate(1.8536743e-6,-42.000005)"
+ id="path14367"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14422" transform="translate(-1.8536743e-6,42.000005)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 222.49805,369.99414 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 l 0.002,0.60742 c -2.27831,0.46511 -4,2.48538 -4,4.89844 0,2.75551 2.24464,5 5,5 2.75536,0 5,-2.24449 5,-5 0,-2.41306 -1.72169,-4.43333 -4,-4.89844 l -0.002,-0.60742 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z M 223,372 c 2.21488,0 4,1.78488 4,4 0,2.21512 -1.78512,4 -4,4 -2.21488,0 -4,-1.78488 -4,-4 0,-2.21512 1.78512,-4 4,-4 z" transform="translate(1.8536743e-6,-42.000005)" id="ellipse14399" inkscape:connector-curvature="0"/>
- <g style="opacity:0.6;fill:#ffffff" id="g13453">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 216.49805,367.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 370 H 220.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -1.50195 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 V 369 h -1.5039 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.5039 v 0.49414 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.50976,1 h 1 v 1 h -1 z m 11.00976,0 h 1 v 1 h -1 z" transform="translate(1.8536743e-6,-42.000005)" id="path14421" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14422"
+ transform="translate(-1.8536743e-6,42.000005)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 222.49805,369.99414 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 l 0.002,0.60742 c -2.27831,0.46511 -4,2.48538 -4,4.89844 0,2.75551 2.24464,5 5,5 2.75536,0 5,-2.24449 5,-5 0,-2.41306 -1.72169,-4.43333 -4,-4.89844 l -0.002,-0.60742 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z M 223,372 c 2.21488,0 4,1.78488 4,4 0,2.21512 -1.78512,4 -4,4 -2.21488,0 -4,-1.78488 -4,-4 0,-2.21512 1.78512,-4 4,-4 z"
+ transform="translate(1.8536743e-6,-42.000005)"
+ id="ellipse14399"
+ inkscape:connector-curvature="0" />
+ <g
+ style="opacity:0.6;fill:#ffffff"
+ id="g13453">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 216.49805,367.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 370 H 220.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -1.50195 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 V 369 h -1.5039 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.5039 v 0.49414 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.50976,1 h 1 v 1 h -1 z m 11.00976,0 h 1 v 1 h -1 z"
+ transform="translate(1.8536743e-6,-42.000005)"
+ id="path14421"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14414" transform="translate(-1.8536743e-6,42.000005)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 250.05859,327.01172 c -2.15963,0 -4.15811,1.13935 -5.24023,2.99219 -1.08212,1.85283 -1.08212,4.1413 0,5.99414 1.08212,1.85284 3.0806,2.99218 5.24023,2.99218 l 0.43164,0.01 a 0.50009544,0.50009544 0 1 0 0.0195,-1 l -0.44141,-0.01 a 0.50004985,0.50004985 0 0 0 -0.01,0 c -1.80804,0 -3.47523,-0.95213 -4.37695,-2.49609 -0.90172,-1.54396 -0.90172,-3.44041 0,-4.98437 0.90107,-1.54285 2.56651,-2.49668 4.37305,-2.49805 l 0.4375,0.004 a 0.50004985,0.50004985 0 1 0 0.008,-1 l -0.4375,-0.004 a 0.50004985,0.50004985 0 0 0 -0.004,0 z" id="ellipse14411" inkscape:connector-curvature="0"/>
- <g style="opacity:0.6;fill:#ffffff" id="g13459">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 237.49805,367.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 H 238 v 8 h -0.50195 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 381 H 245 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -5.00195 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 H 239 v -8 h 0.49805 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 370 H 245 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -5.00195 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 0,11 h 1 v 1 h -1 z" transform="translate(1.8536743e-6,-42.000005)" id="path14415" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14414"
+ transform="translate(-1.8536743e-6,42.000005)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 250.05859,327.01172 c -2.15963,0 -4.15811,1.13935 -5.24023,2.99219 -1.08212,1.85283 -1.08212,4.1413 0,5.99414 1.08212,1.85284 3.0806,2.99218 5.24023,2.99218 l 0.43164,0.01 a 0.50009544,0.50009544 0 1 0 0.0195,-1 l -0.44141,-0.01 a 0.50004985,0.50004985 0 0 0 -0.01,0 c -1.80804,0 -3.47523,-0.95213 -4.37695,-2.49609 -0.90172,-1.54396 -0.90172,-3.44041 0,-4.98437 0.90107,-1.54285 2.56651,-2.49668 4.37305,-2.49805 l 0.4375,0.004 a 0.50004985,0.50004985 0 1 0 0.008,-1 l -0.4375,-0.004 a 0.50004985,0.50004985 0 0 0 -0.004,0 z"
+ id="ellipse14411"
+ inkscape:connector-curvature="0" />
+ <g
+ style="opacity:0.6;fill:#ffffff"
+ id="g13459">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 237.49805,367.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 H 238 v 8 h -0.50195 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 381 H 245 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -5.00195 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 H 239 v -8 h 0.49805 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 370 H 245 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -5.00195 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 0,11 h 1 v 1 h -1 z"
+ transform="translate(1.8536743e-6,-42.000005)"
+ id="path14415"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14406" transform="translate(-1.8536743e-6,42.000005)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 258.49805,325.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.50976,1 h 1 v 1 h -1 z m 11.00976,0 h 1 v 1 h -1 z m -11.50976,10 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.50976,1 h 1 v 1 h -1 z m 11.00976,0 h 1 v 1 h -1 z" id="path14443" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 265,328 c -2.75536,0 -5,2.24449 -5,5 0,2.75551 2.24464,5 5,5 2.75536,0 5,-2.24449 5,-5 0,-2.75551 -2.24464,-5 -5,-5 z m 0,1 c 2.21488,0 4,1.78488 4,4 0,2.21512 -1.78512,4 -4,4 -2.21488,0 -4,-1.78488 -4,-4 0,-2.21512 1.78512,-4 4,-4 z" id="ellipse14445" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14334" transform="translate(-231,63.000005)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 250.05859,306.01172 c -2.15963,0 -4.15811,1.13935 -5.24023,2.99219 -1.08212,1.85283 -1.08212,4.1413 0,5.99414 1.08212,1.85284 3.0806,2.99218 5.24023,2.99218 l 0.43164,0.01 c 0.28003,0.005 0.50992,-0.22015 0.50977,-0.50023 l -0.004,-10.98438 c -2e-5,-0.27461 -0.22149,-0.49783 -0.49609,-0.5 l -0.4375,-0.004 c -0.001,-10e-6 -0.003,-10e-6 -0.004,0 z" id="path13470" inkscape:connector-curvature="0" sodipodi:nodetypes="ccscccccccc"/>
- <g transform="translate(0,-21)" id="g13541" style="opacity:0.6;fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 6.4980469,367.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 H 7 v 8 H 6.4980469 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 381 H 14 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 8.9980469 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 H 8 v -8 h 0.4980469 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 370 H 14 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 8.9980469 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 0,11 h 1 v 1 h -1 z" transform="translate(231,-42.000005)" id="path13523" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14406"
+ transform="translate(-1.8536743e-6,42.000005)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 258.49805,325.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.50976,1 h 1 v 1 h -1 z m 11.00976,0 h 1 v 1 h -1 z m -11.50976,10 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.50976,1 h 1 v 1 h -1 z m 11.00976,0 h 1 v 1 h -1 z"
+ id="path14443"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 265,328 c -2.75536,0 -5,2.24449 -5,5 0,2.75551 2.24464,5 5,5 2.75536,0 5,-2.24449 5,-5 0,-2.75551 -2.24464,-5 -5,-5 z m 0,1 c 2.21488,0 4,1.78488 4,4 0,2.21512 -1.78512,4 -4,4 -2.21488,0 -4,-1.78488 -4,-4 0,-2.21512 1.78512,-4 4,-4 z"
+ id="ellipse14445"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14334"
+ transform="translate(-231,63.000005)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 250.05859,306.01172 c -2.15963,0 -4.15811,1.13935 -5.24023,2.99219 -1.08212,1.85283 -1.08212,4.1413 0,5.99414 1.08212,1.85284 3.0806,2.99218 5.24023,2.99218 l 0.43164,0.01 c 0.28003,0.005 0.50992,-0.22015 0.50977,-0.50023 l -0.004,-10.98438 c -2e-5,-0.27461 -0.22149,-0.49783 -0.49609,-0.5 l -0.4375,-0.004 c -0.001,-10e-6 -0.003,-10e-6 -0.004,0 z"
+ id="path13470"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccscccccccc" />
+ <g
+ transform="translate(0,-21)"
+ id="g13541"
+ style="opacity:0.6;fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 6.4980469,367.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 H 7 v 8 H 6.4980469 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 381 H 14 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 8.9980469 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 H 8 v -8 h 0.4980469 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 370 H 14 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 8.9980469 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 0,11 h 1 v 1 h -1 z"
+ transform="translate(231,-42.000005)"
+ id="path13523"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14339" transform="translate(-231,63.000005)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 258.49805,304.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.50976,1 h 1 v 1 h -1 z m 11.00976,0 h 1 v 1 h -1 z m -11.50976,10 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.50976,1 h 1 v 1 h -1 z m 11.00976,0 h 1 v 1 h -1 z" id="path13555" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 265,307 c -2.75536,0 -5,2.24449 -5,5 0,2.75551 2.24464,5 5,5 2.75536,0 5,-2.24449 5,-5 0,-2.75551 -2.24464,-5 -5,-5 z" id="ellipse13557" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14394" transform="translate(-252,63.000005)">
- <path id="path17351-9" d="m 328,307 c -1.30038,0 -2.48006,0.21939 -3.37891,0.60352 -0.44942,0.19206 -0.83127,0.42394 -1.12304,0.71875 -0.29178,0.2948 -0.49805,0.67796 -0.49805,1.10156 v 2.30664 2.8457 c 0,0.4236 0.20627,0.80676 0.49805,1.10156 0.29177,0.29481 0.67362,0.52669 1.12304,0.71875 C 325.51994,316.78061 326.69962,317 328,317 c 1.30038,0 2.48006,-0.21939 3.37891,-0.60352 0.44942,-0.19206 0.83127,-0.42394 1.12304,-0.71875 0.29178,-0.2948 0.49805,-0.67796 0.49805,-1.10156 v -2.8457 -2.30664 c 0,-0.4236 -0.20627,-0.80676 -0.49805,-1.10156 -0.29177,-0.29481 -0.67362,-0.52669 -1.12304,-0.71875 C 330.48006,307.21939 329.30038,307 328,307 Z m 0,1 c 1.01151,0 1.92459,0.13316 2.61914,0.3418 0.34727,0.10431 0.63991,0.22479 0.88086,0.38281 0.24095,0.15802 0.5,0.38269 0.5,0.77539 0,0.3927 -0.25905,0.61737 -0.5,0.77539 -0.24095,0.15802 -0.53359,0.2785 -0.88086,0.38281 C 329.92459,310.86684 329.01151,311 328,311 c -1.0115,0 -1.92459,-0.13316 -2.61914,-0.3418 -0.34727,-0.10431 -0.63991,-0.22479 -0.88086,-0.38281 -0.24095,-0.15802 -0.5,-0.38268 -0.5,-0.77539 0,-0.3927 0.25905,-0.61737 0.5,-0.77539 0.24095,-0.15802 0.53359,-0.2785 0.88086,-0.38281 C 326.07541,308.13316 326.9885,308 328,308 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 321.49805,304.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -0.5 v -1 h 1 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -0.5 h 1 v 1 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -11.00976,11 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1 a 0.50005,0.50005 0 1 0 -1,0 v 0.5 h -1 v -1 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 z m 12.00976,0 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 1 h -1 v -0.5 a 0.50005,0.50005 0 1 0 -1,0 v 1 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z" id="path14314" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14390" transform="translate(-294,63.000005)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 347.50586,306 c -0.31034,2.7e-4 -0.5455,0.28021 -0.49219,0.58594 0.36436,2.07324 0.1958,3.10943 -0.10742,3.63086 -0.30322,0.52143 -0.79091,0.68645 -1.46094,0.9414 -0.67003,0.25495 -1.50865,0.62325 -1.98242,1.58985 -0.47377,0.96659 -0.59114,2.40736 -0.20703,4.83007 0.0385,0.24306 0.24806,0.422 0.49414,0.42188 h 6.75586 c 0.30739,1.4e-4 0.54213,-0.27449 0.49414,-0.57812 -0.369,-2.32739 -0.20658,-3.57589 0.11523,-4.23438 0.32182,-0.65849 0.7931,-0.85067 1.43555,-1.0957 0.64245,-0.24504 1.46993,-0.51949 1.96484,-1.37305 0.49492,-0.85356 0.6091,-2.12804 0.22657,-4.30469 C 354.70043,306.17484 354.49284,306.0002 354.25,306 Z" id="path14318" inkscape:connector-curvature="0" sodipodi:nodetypes="ccssccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 342.49805,304.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 10.50976,10 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z" id="path14320" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14350" transform="translate(-210,63.000005)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 307,306 c -3.30761,0 -6,2.6922 -6,6 0,3.3078 2.69239,6 6,6 3.30761,0 6,-2.6922 6,-6 0,-3.3078 -2.69239,-6 -6,-6 z m 4.75781,6.73438 a 0.50005,0.50005 0 0 1 0.28516,0.91992 c -1.16187,0.83991 -2.99782,1.34961 -5.04297,1.34961 -2.04361,0 -3.88093,-0.50932 -5.04297,-1.34766 a 0.50005,0.50005 0 0 1 0.25586,-0.91016 0.50005,0.50005 0 0 1 0.33008,0.0977 c 0.89908,0.64864 2.58702,1.16016 4.45703,1.16016 1.87213,0 3.55862,-0.50874 4.45703,-1.15821 a 0.50005,0.50005 0 0 1 0.30078,-0.11132 z" id="ellipse14291" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 300.49805,304.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -0.5 v -1 h 1 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -0.5 h 1 v 1 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -11.00976,11 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1 a 0.50005,0.50005 0 1 0 -1,0 v 0.5 h -1 v -1 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 z m 12.00976,0 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 1 h -1 v -0.5 a 0.50005,0.50005 0 1 0 -1,0 v 1 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z" id="path14322" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14344" transform="translate(-168,63.000005)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 286,307 c -1.846,0 -3.56208,0.52582 -4.8457,1.40625 C 279.87068,309.28668 279,310.55671 279,312 c 0,1.44329 0.87068,2.71332 2.1543,3.59375 C 282.43792,316.47418 284.154,317 286,317 c 1.846,0 3.56208,-0.52582 4.8457,-1.40625 C 292.12932,314.71332 293,313.44329 293,312 c 0,-1.44329 -0.87068,-2.71332 -2.1543,-3.59375 C 289.56208,307.52582 287.846,307 286,307 Z m 2.49219,3.61719 A 0.50005,0.50005 0 0 1 289,311.125 c 0,0.62131 -0.43923,1.10886 -0.98438,1.41016 C 287.47049,312.83646 286.77233,313 286,313 c -0.77233,0 -1.47049,-0.16354 -2.01562,-0.46484 C 283.43923,312.23386 283,311.74631 283,311.125 a 0.50005,0.50005 0 0 1 0.49414,-0.50586 A 0.50005,0.50005 0 0 1 284,311.125 c 0,0.13737 0.11369,0.33891 0.46875,0.53516 C 284.82381,311.85641 285.37451,312 286,312 c 0.62549,0 1.17619,-0.14359 1.53125,-0.33984 C 287.88631,311.46391 288,311.26237 288,311.125 a 0.50005,0.50005 0 0 1 0.49219,-0.50781 z" id="path13633" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 279.49805,304.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -0.5 v -1 h 1 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -0.5 h 1 v 1 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -11.00976,11 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1 a 0.50005,0.50005 0 1 0 -1,0 v 0.5 h -1 v -1 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 z m 12.00976,0 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 1 h -1 v -0.5 a 0.50005,0.50005 0 1 0 -1,0 v 1 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z" id="path14324" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 429.50781,389 C 427.57283,389 426,390.57283 426,392.50781 v 6.98438 c 0,1.93498 1.57283,3.50781 3.50781,3.50781 h 6.98438 C 438.42717,403 440,401.42717 440,399.49219 v -6.98438 C 440,390.57283 438.42717,389 436.49219,389 Z m 0,1 h 6.98438 c 1.39828,0 2.50781,1.10953 2.50781,2.50781 v 6.98438 C 439,400.89047 437.89047,402 436.49219,402 h -6.98438 C 428.10953,402 427,400.89047 427,399.49219 v -6.98438 C 427,391.10953 428.10953,390 429.50781,390 Z" id="rect14490" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 243.49219,220.9707 c -0.18907,0.009 -0.3569,0.12383 -0.4336,0.29688 l -4,9 c -0.084,0.18909 -0.0428,0.41038 0.10352,0.55664 l 4,4 c 0.19526,0.19518 0.51177,0.19518 0.70703,0 l 4,-4 c 0.14634,-0.14626 0.1875,-0.36755 0.10352,-0.55664 l -4,-9 c -0.0836,-0.18859 -0.27441,-0.3065 -0.48047,-0.29688 z" id="path13222-6" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 264.49219,220.9707 a 0.50005,0.50005 0 0 0 -0.4336,0.29688 l -4,9 a 0.50005,0.50005 0 0 0 0.10352,0.55664 l 4,4 a 0.50005,0.50005 0 0 0 0.70703,0 l 4,-4 a 0.50005,0.50005 0 0 0 0.10352,-0.55664 l -4,-9 a 0.50005,0.50005 0 0 0 -0.48047,-0.29688 z m 0.0234,1.73047 3.4043,7.65821 -3.4043,3.40429 -3.40429,-3.40429 z" id="path14674" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 289.5,368 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 2.5 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -5,5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 2.5 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -5,5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 2.5 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z" id="path13250" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g13344" transform="translate(-42.000002,21.000005)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 449.5,494 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 1 c 0,-0.0417 0.006,-0.0117 -0.0469,0.0547 -0.0531,0.0664 -0.15023,0.15467 -0.2539,0.23242 -0.16609,0.12457 -0.2761,0.17993 -0.33789,0.21289 H 447.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 1 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.77539 c 0.40889,-0.49501 0.89786,-0.93068 1.47461,-1.26367 l 0.42578,-0.26758 L 451,496.29297 V 494.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 8.28125,0.002 c -0.50453,0.0148 -1.01019,0.15125 -1.46875,0.41602 a 0.50005,0.50005 0 0 0 -0.0156,0.01 l -5.04688,3.17579 -0.0156,0.01 a 0.50005,0.50005 0 0 0 -0.19532,0.2207 c -1.45784,0.9884 -2.27996,2.6934 -1.9707,4.44727 0.32821,1.86134 1.78904,3.32218 3.65039,3.65039 0.641,0.11303 1.28349,0.0836 1.88867,-0.0703 a 0.50005,0.50005 0 1 0 -0.24609,-0.96875 c -0.47064,0.11969 -0.96915,0.14277 -1.46875,0.0547 -1.45073,-0.25581 -2.58404,-1.38913 -2.83985,-2.83985 -0.2558,-1.45072 0.42152,-2.90212 1.69727,-3.63867 a 0.50005,0.50005 0 0 0 0.0156,-0.01 l 0.0274,-0.0156 a 0.50005,0.50005 0 0 0 0.01,-0.008 l 5.00977,-3.15039 c 0.83503,-0.4821 1.88265,-0.34391 2.56445,0.33789 0.6818,0.68178 0.81999,1.72943 0.33789,2.56445 a 0.50005,0.50005 0 0 0 -0.006,0.0137 0.50005,0.50005 0 0 0 -0.0195,0.0371 l -1.6289,3.02539 a 0.50005,0.50005 0 1 0 0.8789,0.47266 l 1.63477,-3.03711 0.008,-0.0117 c 6.7e-4,-10e-4 -6.7e-4,-0.003 0,-0.004 l 0.006,-0.01 a 0.50005,0.50005 0 0 0 0.0586,-0.3125 c 0.51014,-1.16591 0.35331,-2.52952 -0.5625,-3.44531 -0.49921,-0.49921 -1.13538,-0.80107 -1.80078,-0.88868 -0.16635,-0.0219 -0.33377,-0.0303 -0.50195,-0.0254 z M 458,496 a 1,1 0 0 0 -1,1 1,1 0 0 0 1,1 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z m -4.65039,2.64258 -1.05078,0.66211 a 1.50015,1.50015 0 0 1 -0.0488,0.0293 c -0.34485,0.1991 -0.62663,0.47142 -0.83594,0.78711 l 4.22461,4.22657 1.3613,1.35936 V 507.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1 c 0,-0.0833 0.0571,-0.22505 0.16602,-0.33398 C 459.27495,506.05708 459.41667,506 459.5,506 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -1.79297 z" transform="translate(42.000002,-21.000005)" id="path13315" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 449.50391,369 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 11 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 H 455 c 1.08333,0 2.07323,-0.26796 2.8125,-0.85938 C 458.55177,379.54921 459,378.625 459,377.5 c 0,-1.125 -0.44823,-2.04921 -1.1875,-2.64062 -0.49098,-0.39279 -1.11527,-0.59695 -1.78125,-0.72071 C 456.61178,373.63193 457,372.89881 457,372 c 0,-0.96354 -0.41934,-1.76349 -1.07422,-2.26758 C 455.27091,369.22833 454.41324,369 453.5,369 Z m 0.5,1 H 453.5 c 0.74361,0 1.38549,0.19369 1.81641,0.52539 0.43091,0.3317 0.68359,0.7813 0.68359,1.47461 0,0.69331 -0.25268,1.14291 -0.68359,1.47461 C 454.88549,373.80631 454.24361,374 453.5,374 h -3.49609 z m 0,5 h 3.46093 0.0352 1.5 c 0.91667,0 1.67677,0.23204 2.1875,0.64062 0.51073,0.40859 0.8125,0.98438 0.8125,1.85938 0,0.875 -0.30177,1.45079 -0.8125,1.85938 C 456.67677,379.76796 455.91667,380 455,380 h -4.99609 z" id="path10949-7" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccscsccscsccscscscccccscscscc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 408.50391,369 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5.91992 a 0.50005,0.50005 0 0 0 0,0.16211 V 380.5 a 0.50005,0.50005 0 1 0 1,0 V 376 h 3.25586 l 3.84961,4.8125 a 0.50024018,0.50024018 0 1 0 0.78124,-0.625 l -3.49414,-4.36914 c 1.48603,-0.40423 2.60743,-1.70768 2.60743,-3.31836 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 0.5,1 h 3.5 c 1.38662,0 2.5,1.11337 2.5,2.5 0,1.38663 -1.11338,2.5 -2.5,2.5 a 0.50005,0.50005 0 0 0 -0.004,0 h -3.49609 z" id="path13132" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 431.51758,369.26562 C 429.42795,369.91461 428,371.85293 428,374.04102 V 376 c 0,1.78552 0.9537,3.43731 2.5,4.33008 1.54631,0.89277 3.45369,0.89277 5,0 1.5463,-0.89277 2.5,-2.54456 2.5,-4.33008 v -0.5 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 h -4 a 0.50004997,0.50004997 0 1 0 0,1 h 3.5 c 0,1.42986 -0.7617,2.74991 -2,3.46484 -1.23829,0.71494 -2.76171,0.71494 -4,0 -1.2383,-0.71493 -2,-2.03498 -2,-3.46484 v -1.95898 c 0,-1.75422 1.13918,-3.30002 2.81445,-3.82032 1.69498,-0.52641 3.36746,-0.003 4.25196,1.5293 a 0.50050004,0.50050004 0 1 0 0.86718,-0.5 c -1.1155,-1.93212 -3.34609,-2.62724 -5.41601,-1.98438 z" id="path13141" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g13321" transform="translate(-42.000002,21.000005)">
- <g id="g13309" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 365.49219,94.992188 a 0.50005,0.50005 0 0 0 -0.38867,0.195312 0.50005,0.50005 0 0 0 -0.004,0.0059 l -1.95313,1.953125 a 0.50005,0.50005 0 1 0 0.70704,0.707032 L 365,96.707031 V 98.5 a 0.50005,0.50005 0 1 0 1,0 v -1.792969 l 1.14648,1.146485 a 0.50005,0.50005 0 1 0 0.70704,-0.707032 l -1.95704,-1.957031 a 0.50005,0.50005 0 0 0 -0.40429,-0.197265 z m 9.05859,1.941406 a 0.50005,0.50005 0 0 0 -0.0586,0.0059 h -2.93164 a 0.50005,0.50005 0 1 0 0,1 h 1.79297 l -3.14649,3.146486 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 3.14649,-3.146485 v 1.792965 a 0.50005,0.50005 0 1 0 1,0 v -2.931637 a 0.50005,0.50005 0 0 0 -0.50977,-0.574218 z m -0.0566,7.060546 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 375.29297,106 H 371.5 a 0.50005,0.50005 0 1 0 0,1 h 3.79297 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.95703,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.006,-0.004 l -1.95312,-1.95313 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z" id="path13047-6" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14339"
+ transform="translate(-231,63.000005)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 258.49805,304.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.50976,1 h 1 v 1 h -1 z m 11.00976,0 h 1 v 1 h -1 z m -11.50976,10 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.50976,1 h 1 v 1 h -1 z m 11.00976,0 h 1 v 1 h -1 z"
+ id="path13555"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 265,307 c -2.75536,0 -5,2.24449 -5,5 0,2.75551 2.24464,5 5,5 2.75536,0 5,-2.24449 5,-5 0,-2.75551 -2.24464,-5 -5,-5 z"
+ id="ellipse13557"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14394"
+ transform="translate(-252,63.000005)">
+ <path
+ id="path17351-9"
+ d="m 328,307 c -1.30038,0 -2.48006,0.21939 -3.37891,0.60352 -0.44942,0.19206 -0.83127,0.42394 -1.12304,0.71875 -0.29178,0.2948 -0.49805,0.67796 -0.49805,1.10156 v 2.30664 2.8457 c 0,0.4236 0.20627,0.80676 0.49805,1.10156 0.29177,0.29481 0.67362,0.52669 1.12304,0.71875 C 325.51994,316.78061 326.69962,317 328,317 c 1.30038,0 2.48006,-0.21939 3.37891,-0.60352 0.44942,-0.19206 0.83127,-0.42394 1.12304,-0.71875 0.29178,-0.2948 0.49805,-0.67796 0.49805,-1.10156 v -2.8457 -2.30664 c 0,-0.4236 -0.20627,-0.80676 -0.49805,-1.10156 -0.29177,-0.29481 -0.67362,-0.52669 -1.12304,-0.71875 C 330.48006,307.21939 329.30038,307 328,307 Z m 0,1 c 1.01151,0 1.92459,0.13316 2.61914,0.3418 0.34727,0.10431 0.63991,0.22479 0.88086,0.38281 0.24095,0.15802 0.5,0.38269 0.5,0.77539 0,0.3927 -0.25905,0.61737 -0.5,0.77539 -0.24095,0.15802 -0.53359,0.2785 -0.88086,0.38281 C 329.92459,310.86684 329.01151,311 328,311 c -1.0115,0 -1.92459,-0.13316 -2.61914,-0.3418 -0.34727,-0.10431 -0.63991,-0.22479 -0.88086,-0.38281 -0.24095,-0.15802 -0.5,-0.38268 -0.5,-0.77539 0,-0.3927 0.25905,-0.61737 0.5,-0.77539 0.24095,-0.15802 0.53359,-0.2785 0.88086,-0.38281 C 326.07541,308.13316 326.9885,308 328,308 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 321.49805,304.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -0.5 v -1 h 1 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -0.5 h 1 v 1 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -11.00976,11 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1 a 0.50005,0.50005 0 1 0 -1,0 v 0.5 h -1 v -1 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 z m 12.00976,0 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 1 h -1 v -0.5 a 0.50005,0.50005 0 1 0 -1,0 v 1 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path14314"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14390"
+ transform="translate(-294,63.000005)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 347.50586,306 c -0.31034,2.7e-4 -0.5455,0.28021 -0.49219,0.58594 0.36436,2.07324 0.1958,3.10943 -0.10742,3.63086 -0.30322,0.52143 -0.79091,0.68645 -1.46094,0.9414 -0.67003,0.25495 -1.50865,0.62325 -1.98242,1.58985 -0.47377,0.96659 -0.59114,2.40736 -0.20703,4.83007 0.0385,0.24306 0.24806,0.422 0.49414,0.42188 h 6.75586 c 0.30739,1.4e-4 0.54213,-0.27449 0.49414,-0.57812 -0.369,-2.32739 -0.20658,-3.57589 0.11523,-4.23438 0.32182,-0.65849 0.7931,-0.85067 1.43555,-1.0957 0.64245,-0.24504 1.46993,-0.51949 1.96484,-1.37305 0.49492,-0.85356 0.6091,-2.12804 0.22657,-4.30469 C 354.70043,306.17484 354.49284,306.0002 354.25,306 Z"
+ id="path14318"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccssccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 342.49805,304.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 10.50976,10 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z"
+ id="path14320"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14350"
+ transform="translate(-210,63.000005)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 307,306 c -3.30761,0 -6,2.6922 -6,6 0,3.3078 2.69239,6 6,6 3.30761,0 6,-2.6922 6,-6 0,-3.3078 -2.69239,-6 -6,-6 z m 4.75781,6.73438 a 0.50005,0.50005 0 0 1 0.28516,0.91992 c -1.16187,0.83991 -2.99782,1.34961 -5.04297,1.34961 -2.04361,0 -3.88093,-0.50932 -5.04297,-1.34766 a 0.50005,0.50005 0 0 1 0.25586,-0.91016 0.50005,0.50005 0 0 1 0.33008,0.0977 c 0.89908,0.64864 2.58702,1.16016 4.45703,1.16016 1.87213,0 3.55862,-0.50874 4.45703,-1.15821 a 0.50005,0.50005 0 0 1 0.30078,-0.11132 z"
+ id="ellipse14291"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 300.49805,304.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -0.5 v -1 h 1 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -0.5 h 1 v 1 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -11.00976,11 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1 a 0.50005,0.50005 0 1 0 -1,0 v 0.5 h -1 v -1 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 z m 12.00976,0 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 1 h -1 v -0.5 a 0.50005,0.50005 0 1 0 -1,0 v 1 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path14322"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14344"
+ transform="translate(-168,63.000005)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 286,307 c -1.846,0 -3.56208,0.52582 -4.8457,1.40625 C 279.87068,309.28668 279,310.55671 279,312 c 0,1.44329 0.87068,2.71332 2.1543,3.59375 C 282.43792,316.47418 284.154,317 286,317 c 1.846,0 3.56208,-0.52582 4.8457,-1.40625 C 292.12932,314.71332 293,313.44329 293,312 c 0,-1.44329 -0.87068,-2.71332 -2.1543,-3.59375 C 289.56208,307.52582 287.846,307 286,307 Z m 2.49219,3.61719 A 0.50005,0.50005 0 0 1 289,311.125 c 0,0.62131 -0.43923,1.10886 -0.98438,1.41016 C 287.47049,312.83646 286.77233,313 286,313 c -0.77233,0 -1.47049,-0.16354 -2.01562,-0.46484 C 283.43923,312.23386 283,311.74631 283,311.125 a 0.50005,0.50005 0 0 1 0.49414,-0.50586 A 0.50005,0.50005 0 0 1 284,311.125 c 0,0.13737 0.11369,0.33891 0.46875,0.53516 C 284.82381,311.85641 285.37451,312 286,312 c 0.62549,0 1.17619,-0.14359 1.53125,-0.33984 C 287.88631,311.46391 288,311.26237 288,311.125 a 0.50005,0.50005 0 0 1 0.49219,-0.50781 z"
+ id="path13633"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 279.49805,304.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -0.5 v -1 h 1 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -0.5 h 1 v 1 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -11.00976,11 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1 a 0.50005,0.50005 0 1 0 -1,0 v 0.5 h -1 v -1 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 z m 12.00976,0 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 1 h -1 v -0.5 a 0.50005,0.50005 0 1 0 -1,0 v 1 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path14324"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 429.50781,389 C 427.57283,389 426,390.57283 426,392.50781 v 6.98438 c 0,1.93498 1.57283,3.50781 3.50781,3.50781 h 6.98438 C 438.42717,403 440,401.42717 440,399.49219 v -6.98438 C 440,390.57283 438.42717,389 436.49219,389 Z m 0,1 h 6.98438 c 1.39828,0 2.50781,1.10953 2.50781,2.50781 v 6.98438 C 439,400.89047 437.89047,402 436.49219,402 h -6.98438 C 428.10953,402 427,400.89047 427,399.49219 v -6.98438 C 427,391.10953 428.10953,390 429.50781,390 Z"
+ id="rect14490"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 243.49219,220.9707 c -0.18907,0.009 -0.3569,0.12383 -0.4336,0.29688 l -4,9 c -0.084,0.18909 -0.0428,0.41038 0.10352,0.55664 l 4,4 c 0.19526,0.19518 0.51177,0.19518 0.70703,0 l 4,-4 c 0.14634,-0.14626 0.1875,-0.36755 0.10352,-0.55664 l -4,-9 c -0.0836,-0.18859 -0.27441,-0.3065 -0.48047,-0.29688 z"
+ id="path13222-6"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 264.49219,220.9707 a 0.50005,0.50005 0 0 0 -0.4336,0.29688 l -4,9 a 0.50005,0.50005 0 0 0 0.10352,0.55664 l 4,4 a 0.50005,0.50005 0 0 0 0.70703,0 l 4,-4 a 0.50005,0.50005 0 0 0 0.10352,-0.55664 l -4,-9 a 0.50005,0.50005 0 0 0 -0.48047,-0.29688 z m 0.0234,1.73047 3.4043,7.65821 -3.4043,3.40429 -3.40429,-3.40429 z"
+ id="path14674"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 289.5,368 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 2.5 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -5,5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 2.5 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -5,5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 2.5 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path13250"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13344"
+ transform="translate(-42.000002,21.000005)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 449.5,494 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 1 c 0,-0.0417 0.006,-0.0117 -0.0469,0.0547 -0.0531,0.0664 -0.15023,0.15467 -0.2539,0.23242 -0.16609,0.12457 -0.2761,0.17993 -0.33789,0.21289 H 447.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 1 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.77539 c 0.40889,-0.49501 0.89786,-0.93068 1.47461,-1.26367 l 0.42578,-0.26758 L 451,496.29297 V 494.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 8.28125,0.002 c -0.50453,0.0148 -1.01019,0.15125 -1.46875,0.41602 a 0.50005,0.50005 0 0 0 -0.0156,0.01 l -5.04688,3.17579 -0.0156,0.01 a 0.50005,0.50005 0 0 0 -0.19532,0.2207 c -1.45784,0.9884 -2.27996,2.6934 -1.9707,4.44727 0.32821,1.86134 1.78904,3.32218 3.65039,3.65039 0.641,0.11303 1.28349,0.0836 1.88867,-0.0703 a 0.50005,0.50005 0 1 0 -0.24609,-0.96875 c -0.47064,0.11969 -0.96915,0.14277 -1.46875,0.0547 -1.45073,-0.25581 -2.58404,-1.38913 -2.83985,-2.83985 -0.2558,-1.45072 0.42152,-2.90212 1.69727,-3.63867 a 0.50005,0.50005 0 0 0 0.0156,-0.01 l 0.0274,-0.0156 a 0.50005,0.50005 0 0 0 0.01,-0.008 l 5.00977,-3.15039 c 0.83503,-0.4821 1.88265,-0.34391 2.56445,0.33789 0.6818,0.68178 0.81999,1.72943 0.33789,2.56445 a 0.50005,0.50005 0 0 0 -0.006,0.0137 0.50005,0.50005 0 0 0 -0.0195,0.0371 l -1.6289,3.02539 a 0.50005,0.50005 0 1 0 0.8789,0.47266 l 1.63477,-3.03711 0.008,-0.0117 c 6.7e-4,-10e-4 -6.7e-4,-0.003 0,-0.004 l 0.006,-0.01 a 0.50005,0.50005 0 0 0 0.0586,-0.3125 c 0.51014,-1.16591 0.35331,-2.52952 -0.5625,-3.44531 -0.49921,-0.49921 -1.13538,-0.80107 -1.80078,-0.88868 -0.16635,-0.0219 -0.33377,-0.0303 -0.50195,-0.0254 z M 458,496 a 1,1 0 0 0 -1,1 1,1 0 0 0 1,1 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z m -4.65039,2.64258 -1.05078,0.66211 a 1.50015,1.50015 0 0 1 -0.0488,0.0293 c -0.34485,0.1991 -0.62663,0.47142 -0.83594,0.78711 l 4.22461,4.22657 1.3613,1.35936 V 507.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1 c 0,-0.0833 0.0571,-0.22505 0.16602,-0.33398 C 459.27495,506.05708 459.41667,506 459.5,506 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -1.79297 z"
+ transform="translate(42.000002,-21.000005)"
+ id="path13315"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 449.50391,369 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 11 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 H 455 c 1.08333,0 2.07323,-0.26796 2.8125,-0.85938 C 458.55177,379.54921 459,378.625 459,377.5 c 0,-1.125 -0.44823,-2.04921 -1.1875,-2.64062 -0.49098,-0.39279 -1.11527,-0.59695 -1.78125,-0.72071 C 456.61178,373.63193 457,372.89881 457,372 c 0,-0.96354 -0.41934,-1.76349 -1.07422,-2.26758 C 455.27091,369.22833 454.41324,369 453.5,369 Z m 0.5,1 H 453.5 c 0.74361,0 1.38549,0.19369 1.81641,0.52539 0.43091,0.3317 0.68359,0.7813 0.68359,1.47461 0,0.69331 -0.25268,1.14291 -0.68359,1.47461 C 454.88549,373.80631 454.24361,374 453.5,374 h -3.49609 z m 0,5 h 3.46093 0.0352 1.5 c 0.91667,0 1.67677,0.23204 2.1875,0.64062 0.51073,0.40859 0.8125,0.98438 0.8125,1.85938 0,0.875 -0.30177,1.45079 -0.8125,1.85938 C 456.67677,379.76796 455.91667,380 455,380 h -4.99609 z"
+ id="path10949-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccscsccscsccscscscccccscscscc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 408.50391,369 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5.91992 a 0.50005,0.50005 0 0 0 0,0.16211 V 380.5 a 0.50005,0.50005 0 1 0 1,0 V 376 h 3.25586 l 3.84961,4.8125 a 0.50024018,0.50024018 0 1 0 0.78124,-0.625 l -3.49414,-4.36914 c 1.48603,-0.40423 2.60743,-1.70768 2.60743,-3.31836 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 0.5,1 h 3.5 c 1.38662,0 2.5,1.11337 2.5,2.5 0,1.38663 -1.11338,2.5 -2.5,2.5 a 0.50005,0.50005 0 0 0 -0.004,0 h -3.49609 z"
+ id="path13132"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 431.51758,369.26562 C 429.42795,369.91461 428,371.85293 428,374.04102 V 376 c 0,1.78552 0.9537,3.43731 2.5,4.33008 1.54631,0.89277 3.45369,0.89277 5,0 1.5463,-0.89277 2.5,-2.54456 2.5,-4.33008 v -0.5 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 h -4 a 0.50004997,0.50004997 0 1 0 0,1 h 3.5 c 0,1.42986 -0.7617,2.74991 -2,3.46484 -1.23829,0.71494 -2.76171,0.71494 -4,0 -1.2383,-0.71493 -2,-2.03498 -2,-3.46484 v -1.95898 c 0,-1.75422 1.13918,-3.30002 2.81445,-3.82032 1.69498,-0.52641 3.36746,-0.003 4.25196,1.5293 a 0.50050004,0.50050004 0 1 0 0.86718,-0.5 c -1.1155,-1.93212 -3.34609,-2.62724 -5.41601,-1.98438 z"
+ id="path13141"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13321"
+ transform="translate(-42.000002,21.000005)">
+ <g
+ id="g13309"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 365.49219,94.992188 a 0.50005,0.50005 0 0 0 -0.38867,0.195312 0.50005,0.50005 0 0 0 -0.004,0.0059 l -1.95313,1.953125 a 0.50005,0.50005 0 1 0 0.70704,0.707032 L 365,96.707031 V 98.5 a 0.50005,0.50005 0 1 0 1,0 v -1.792969 l 1.14648,1.146485 a 0.50005,0.50005 0 1 0 0.70704,-0.707032 l -1.95704,-1.957031 a 0.50005,0.50005 0 0 0 -0.40429,-0.197265 z m 9.05859,1.941406 a 0.50005,0.50005 0 0 0 -0.0586,0.0059 h -2.93164 a 0.50005,0.50005 0 1 0 0,1 h 1.79297 l -3.14649,3.146486 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 3.14649,-3.146485 v 1.792965 a 0.50005,0.50005 0 1 0 1,0 v -2.931637 a 0.50005,0.50005 0 0 0 -0.50977,-0.574218 z m -0.0566,7.060546 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 375.29297,106 H 371.5 a 0.50005,0.50005 0 1 0 0,1 h 3.79297 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.95703,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.006,-0.004 l -1.95312,-1.95313 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path13047-6"
+ inkscape:connector-curvature="0" />
</g>
- <g id="g13313" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98000004;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 324.5,121 c -1.14583,0 -1.86235,0.56478 -2.18359,1.12695 C 321.99517,122.68912 322,123.25 322,123.25 V 125 h -0.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 327 v -1.75 c 0,0 0.005,-0.56088 -0.31641,-1.12305 C 326.36235,121.56478 325.64583,121 324.5,121 Z m 0,1 c 0.85417,0 1.13765,0.31022 1.31641,0.62305 C 325.99517,122.93588 326,123.25 326,123.25 V 125 h -3 v -1.75 c 0,0 0.005,-0.31412 0.18359,-0.62695 C 323.36235,122.31022 323.64583,122 324.5,122 Z m -0.5,4 h 1 v 2 h -1 z" transform="translate(42.000002,-21.000005)" id="rect13261" inkscape:connector-curvature="0"/>
+ <g
+ id="g13313"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98000004;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 324.5,121 c -1.14583,0 -1.86235,0.56478 -2.18359,1.12695 C 321.99517,122.68912 322,123.25 322,123.25 V 125 h -0.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 327 v -1.75 c 0,0 0.005,-0.56088 -0.31641,-1.12305 C 326.36235,121.56478 325.64583,121 324.5,121 Z m 0,1 c 0.85417,0 1.13765,0.31022 1.31641,0.62305 C 325.99517,122.93588 326,123.25 326,123.25 V 125 h -3 v -1.75 c 0,0 0.005,-0.31412 0.18359,-0.62695 C 323.36235,122.31022 323.64583,122 324.5,122 Z m -0.5,4 h 1 v 2 h -1 z"
+ transform="translate(42.000002,-21.000005)"
+ id="rect13261"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="g13337" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" transform="matrix(-1,0,0,1,1458,302.99979)">
- <path style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 1262.5,-278.49979 h -13 v -13 h 13 v 13" id="path14450" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1257.5039,-287 c -0.191,-10e-4 -0.3661,0.1063 -0.4512,0.27734 l -3,6 c -0.1652,0.33223 0.076,0.72231 0.4473,0.72266 h 6 c 0.371,-3.5e-4 0.6125,-0.39043 0.4473,-0.72266 l -3,-6 c -0.084,-0.16853 -0.2552,-0.27571 -0.4434,-0.27734 z" id="path13331" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1252.5,-289 c -0.8225,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z" id="ellipse13333" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 1249.5,-292 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 12.9199 a 0.50005,0.50005 0 0 0 0.4043,-0.11328 0.50005,0.50005 0 0 0 0,-0.002 0.50005,0.50005 0 0 0 0.033,-0.0312 0.50005,0.50005 0 0 0 0,-0.004 0.50005,0.50005 0 0 0 0.031,-0.0332 0.50005,0.50005 0 0 0 0,-0.004 0.50005,0.50005 0 0 0 0.1035,-0.39453 V -291.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z" id="path13335" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" transform="matrix(1,0,0,-1,-1.8536743e-6,6.0000045)" id="g13398">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 237.5,-19 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z" id="path13392" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 237.5,-19 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 13 c 1.7e-4,0.4453235 0.53852,0.6683012 0.85352,0.3535156 l 13,-12.9999996 C 251.1683,-18.461483 250.94532,-18.99983 250.5,-19 Z" id="path13396" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccc"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g13454" transform="translate(41.999998,-20.999995)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 174.5,32 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 187.5,32 Z m 0.5,1 h 12 v 12 h -12 z" id="path13377" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 174.58789,32.005859 C 174.30358,31.956646 174.00013,32.166007 174,32.5 v 13 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 h 13 c 0.44532,-1.7e-4 0.6683,-0.538517 0.35352,-0.853516 l -13,-13 c -0.0788,-0.0787 -0.17086,-0.12422 -0.26563,-0.140625 z M 178.49609,38 c 0.191,-10e-4 0.36608,0.106304 0.45118,0.277344 l 3,6 C 182.11247,44.609574 181.8713,44.99965 181.5,45 h -6 c -0.371,-3.5e-4 -0.61247,-0.390426 -0.44727,-0.722656 l 3,-6 c 0.084,-0.16853 0.25516,-0.275714 0.44336,-0.277344 z" id="path13379" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 184.5,35 c 0.82251,0 1.5,0.677494 1.5,1.5 0,0.822506 -0.67749,1.5 -1.5,1.5 -0.82251,0 -1.5,-0.677494 -1.5,-1.5 0,-0.822506 0.67749,-1.5 1.5,-1.5 z" id="ellipse13420" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g14346">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 184.27734,515 c -0.3909,-0.007 -0.822,0.0708 -1.2832,0.25781 -1.22985,0.49878 -2.7569,1.66874 -4.85742,3.90039 -2.09205,2.22266 -3.24657,3.73559 -3.77539,4.91602 -0.26441,0.59022 -0.37396,1.11195 -0.31641,1.58984 0.0576,0.4779 0.29454,0.88243 0.60156,1.18946 0.013,0.0131 0.0267,0.0255 0.041,0.0371 l 2.5,2 c 0.49277,0.39559 1.11361,-0.29808 0.66602,-0.74414 l -2,-2 c -0.36948,-0.36947 -0.29946,-0.99351 0,-1.29296 0.3216,-0.32161 0.86101,-0.43196 1.29296,0 l 2,2 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -2,-2 c -0.36948,-0.36947 -0.29946,-0.99351 0,-1.29296 0.3216,-0.32161 0.86101,-0.43196 1.29296,0 l 2,2 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.97657,-1.9746 c -0.008,-0.009 -0.0153,-0.0172 -0.0234,-0.0254 -0.36948,-0.36947 -0.29946,-0.99351 0,-1.29296 0.3216,-0.32161 0.86101,-0.43196 1.29296,0 l 2,2 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.97657,-1.9746 c -0.008,-0.009 -0.0153,-0.0172 -0.0234,-0.0254 -0.36948,-0.36947 -0.29946,-0.99351 0,-1.29296 0.3216,-0.32161 0.86101,-0.43196 1.29296,0 l 2,2 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -2,-2 c -0.36948,-0.36947 -0.29946,-0.99351 0,-1.29296 0.3216,-0.32161 0.86101,-0.43196 1.29296,0 l 2,2 c 0.44606,0.44759 1.13973,-0.17325 0.74414,-0.66602 l -2,-2.5 c -0.0116,-0.0143 -0.024,-0.028 -0.0371,-0.041 -0.30703,-0.30702 -0.7149,-0.52843 -1.19922,-0.61132 -0.12109,-0.0207 -0.24665,-0.0327 -0.37696,-0.0352 z" transform="translate(1.8536743e-6,-4.4999696e-6)" id="path14236" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g13042" transform="translate(-21.000002,42.000005)">
- <g id="g13022" transform="translate(-42.00718,397.99283)" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 447.5,159 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 10 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5.5 v 2 h -2.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 7 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 455 v -2 h 5.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -10 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 12 v 9 h -12 z" id="path13020" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccc"/>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ id="g13337"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
+ transform="matrix(-1,0,0,1,1458,302.99979)">
+ <path
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1262.5,-278.49979 h -13 v -13 h 13 v 13"
+ id="path14450"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1257.5039,-287 c -0.191,-10e-4 -0.3661,0.1063 -0.4512,0.27734 l -3,6 c -0.1652,0.33223 0.076,0.72231 0.4473,0.72266 h 6 c 0.371,-3.5e-4 0.6125,-0.39043 0.4473,-0.72266 l -3,-6 c -0.084,-0.16853 -0.2552,-0.27571 -0.4434,-0.27734 z"
+ id="path13331"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1252.5,-289 c -0.8225,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z"
+ id="ellipse13333"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1249.5,-292 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 12.9199 a 0.50005,0.50005 0 0 0 0.4043,-0.11328 0.50005,0.50005 0 0 0 0,-0.002 0.50005,0.50005 0 0 0 0.033,-0.0312 0.50005,0.50005 0 0 0 0,-0.004 0.50005,0.50005 0 0 0 0.031,-0.0332 0.50005,0.50005 0 0 0 0,-0.004 0.50005,0.50005 0 0 0 0.1035,-0.39453 V -291.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
+ id="path13335"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="matrix(1,0,0,-1,-1.8536743e-6,6.0000045)"
+ id="g13398">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 237.5,-19 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
+ id="path13392"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 237.5,-19 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 13 c 1.7e-4,0.4453235 0.53852,0.6683012 0.85352,0.3535156 l 13,-12.9999996 C 251.1683,-18.461483 250.94532,-18.99983 250.5,-19 Z"
+ id="path13396"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13454"
+ transform="translate(41.999998,-20.999995)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 174.5,32 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 187.5,32 Z m 0.5,1 h 12 v 12 h -12 z"
+ id="path13377"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 174.58789,32.005859 C 174.30358,31.956646 174.00013,32.166007 174,32.5 v 13 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 h 13 c 0.44532,-1.7e-4 0.6683,-0.538517 0.35352,-0.853516 l -13,-13 c -0.0788,-0.0787 -0.17086,-0.12422 -0.26563,-0.140625 z M 178.49609,38 c 0.191,-10e-4 0.36608,0.106304 0.45118,0.277344 l 3,6 C 182.11247,44.609574 181.8713,44.99965 181.5,45 h -6 c -0.371,-3.5e-4 -0.61247,-0.390426 -0.44727,-0.722656 l 3,-6 c 0.084,-0.16853 0.25516,-0.275714 0.44336,-0.277344 z"
+ id="path13379"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 184.5,35 c 0.82251,0 1.5,0.677494 1.5,1.5 0,0.822506 -0.67749,1.5 -1.5,1.5 -0.82251,0 -1.5,-0.677494 -1.5,-1.5 0,-0.822506 0.67749,-1.5 1.5,-1.5 z"
+ id="ellipse13420"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14346">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 184.27734,515 c -0.3909,-0.007 -0.822,0.0708 -1.2832,0.25781 -1.22985,0.49878 -2.7569,1.66874 -4.85742,3.90039 -2.09205,2.22266 -3.24657,3.73559 -3.77539,4.91602 -0.26441,0.59022 -0.37396,1.11195 -0.31641,1.58984 0.0576,0.4779 0.29454,0.88243 0.60156,1.18946 0.013,0.0131 0.0267,0.0255 0.041,0.0371 l 2.5,2 c 0.49277,0.39559 1.11361,-0.29808 0.66602,-0.74414 l -2,-2 c -0.36948,-0.36947 -0.29946,-0.99351 0,-1.29296 0.3216,-0.32161 0.86101,-0.43196 1.29296,0 l 2,2 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -2,-2 c -0.36948,-0.36947 -0.29946,-0.99351 0,-1.29296 0.3216,-0.32161 0.86101,-0.43196 1.29296,0 l 2,2 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.97657,-1.9746 c -0.008,-0.009 -0.0153,-0.0172 -0.0234,-0.0254 -0.36948,-0.36947 -0.29946,-0.99351 0,-1.29296 0.3216,-0.32161 0.86101,-0.43196 1.29296,0 l 2,2 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.97657,-1.9746 c -0.008,-0.009 -0.0153,-0.0172 -0.0234,-0.0254 -0.36948,-0.36947 -0.29946,-0.99351 0,-1.29296 0.3216,-0.32161 0.86101,-0.43196 1.29296,0 l 2,2 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -2,-2 c -0.36948,-0.36947 -0.29946,-0.99351 0,-1.29296 0.3216,-0.32161 0.86101,-0.43196 1.29296,0 l 2,2 c 0.44606,0.44759 1.13973,-0.17325 0.74414,-0.66602 l -2,-2.5 c -0.0116,-0.0143 -0.024,-0.028 -0.0371,-0.041 -0.30703,-0.30702 -0.7149,-0.52843 -1.19922,-0.61132 -0.12109,-0.0207 -0.24665,-0.0327 -0.37696,-0.0352 z"
+ transform="translate(1.8536743e-6,-4.4999696e-6)"
+ id="path14236"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13042"
+ transform="translate(-21.000002,42.000005)">
+ <g
+ id="g13022"
+ transform="translate(-42.00718,397.99283)"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 447.5,159 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 10 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5.5 v 2 h -2.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 7 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 455 v -2 h 5.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -10 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 12 v 9 h -12 z"
+ id="path13020"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccc" />
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 410.49023,558.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3,3 a 0.50005,0.50005 0 0 0 0,0.70704 l 3,3 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 L 408.70703,563 H 416.5 a 0.50005,0.50005 0 1 0 0,-1 h -7.79297 l 2.14649,-2.14648 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z" id="path12420-1" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g13097">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 74,477 c -0.710648,0 -1.272904,0.36437 -1.621094,0.82227 -0.348189,0.45789 -0.546604,0.99437 -0.748047,1.49023 -0.201442,0.49586 -0.404614,0.94894 -0.65039,1.24023 C 70.734693,480.84402 70.491667,481 70,481 h -1 v 1 h 1 c 0.758333,0 1.359057,-0.34402 1.746094,-0.80273 0.387036,-0.45871 0.605739,-1.00563 0.810547,-1.50977 0.204807,-0.50414 0.397017,-0.96766 0.61914,-1.25977 C 73.397904,478.13563 73.585648,478 74,478 c 0.376652,0 0.584084,0.165 0.837891,0.55664 0.253806,0.39164 0.470672,0.98903 0.689453,1.61524 0.21878,0.6262 0.438752,1.28115 0.794922,1.82812 0.35617,0.54697 0.933457,1.00595 1.68164,1 0.673157,-0.005 1.209041,-0.26371 1.570313,-0.62109 0.361272,-0.35739 0.571027,-0.77752 0.771484,-1.14649 0.200458,-0.36897 0.389328,-0.68586 0.623047,-0.89258 C 81.202469,480.13313 81.474401,480 82,480 h 1 v -1 h -1 c -0.724401,0 -1.296219,0.23882 -1.695312,0.5918 -0.399094,0.35298 -0.632099,0.78332 -0.837891,1.16211 -0.205793,0.37878 -0.386663,0.70727 -0.595703,0.91406 -0.209041,0.20679 -0.423157,0.32843 -0.875,0.33203 -0.376817,0.003 -0.58078,-0.15803 -0.833985,-0.54688 -0.253205,-0.38884 -0.470733,-0.98529 -0.689453,-1.61132 -0.218719,-0.62603 -0.439353,-1.28142 -0.794922,-1.83008 C 75.322166,477.46306 74.748348,477 74,477 Z" id="path15332-4" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 82.5,473 -13,0.004 a 0.50005,0.50005 0 0 0 -0.5,0.5 V 480 h 1 v -5.99609 L 82,474 v 4 h 1 v -4.5 A 0.50005,0.50005 0 0 0 82.5,473 Z m -0.5,8 v 5 H 70 v -3 h -1 v 3.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 A 0.50005,0.50005 0 0 0 83,486.5 V 481 Z" id="path12638-3" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g13177" transform="translate(-1.8536743e-6,-20.999995)">
- <g id="g13282" transform="translate(20,-21)" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 246.49805,74 c -0.13192,5.4e-4 -0.25829,0.0532 -0.35157,0.146484 C 245.43577,74.857204 244.09848,76 241.5,76 A 0.50005,0.50005 0 0 0 241,76.5 V 79 h -0.5 c -0.75833,0 -1.38671,0.318735 -1.90625,0.734375 -0.51954,0.41563 -0.962,0.926849 -1.44727,1.412109 -0.39648,0.39648 0.31056,1.103512 0.70704,0.707032 0.4558,-0.45581 0.79842,-0.643904 1.18164,-0.746094 C 239.41838,81.005232 239.875,81 240.5,81 h 0.5 v 4.5 c 0,0.75694 -0.56911,1.365513 -1.18359,1.476562 -0.30725,0.0555 -0.62032,0.004 -0.94141,-0.228515 -0.32109,-0.23272 -0.65388,-0.66673 -0.90039,-1.40625 A 0.50005,0.50005 0 0 0 237,85.5 v 1 a 0.50005,0.50005 0 0 0 0.14648,0.353516 C 238.22544,87.932473 239.1944,88.00968 240,88 c 0,0 0.002,0 0.002,0 9.9e-4,0 0.003,10e-7 0.004,0 0.001,-1.6e-5 0.003,1.8e-5 0.004,0 0.36494,-7.26e-4 0.98133,-0.05472 1.67773,-0.203125 0.19213,-0.0454 0.36061,-0.131526 0.54297,-0.197266 0.41443,-0.1248 0.82232,-0.201598 1.24219,-0.449218 C 244.82222,86.354491 246,84.75992 246,82 v -1 h 2.5 c 0.1326,-2e-5 0.25976,-0.0527 0.35352,-0.146484 l 1,-1 C 250.16831,79.538516 249.94532,79.00017 249.5,79 H 246 v -2.529297 c 0.26613,0.242116 0.53257,0.477435 0.83203,0.527344 0.63268,0.10544 1.23725,-0.0679 1.76563,-0.332031 1.05675,-0.52838 1.9005,-1.45715 2.25586,-1.8125 0.45304,-0.47127 -0.23577,-1.160072 -0.70704,-0.707032 -0.31826,0.31827 -0.84181,0.673592 -1.40039,0.763672 -0.55857,0.0901 -1.16912,-0.02339 -1.88867,-0.759765 -0.0945,-0.0967 -0.22417,-0.150901 -0.35937,-0.150391 z m -2.50977,3.013672 c 0.004,-1.62e-4 0.008,1.67e-4 0.0117,0 V 83 c 0,1.65476 -0.45037,2.602541 -1.13477,3.181641 -0.20404,0.172661 -0.46051,0.286861 -0.72656,0.390625 C 242.64927,85.748655 243,84.573733 243,83 v -5.982422 c 0.35078,0.0051 0.69957,0.0073 0.98828,-0.0039 z" transform="translate(-19.999998,41.999995)" id="path13240" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 410.49023,558.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3,3 a 0.50005,0.50005 0 0 0 0,0.70704 l 3,3 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 L 408.70703,563 H 416.5 a 0.50005,0.50005 0 1 0 0,-1 h -7.79297 l 2.14649,-2.14648 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
+ id="path12420-1"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13097">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 74,477 c -0.710648,0 -1.272904,0.36437 -1.621094,0.82227 -0.348189,0.45789 -0.546604,0.99437 -0.748047,1.49023 -0.201442,0.49586 -0.404614,0.94894 -0.65039,1.24023 C 70.734693,480.84402 70.491667,481 70,481 h -1 v 1 h 1 c 0.758333,0 1.359057,-0.34402 1.746094,-0.80273 0.387036,-0.45871 0.605739,-1.00563 0.810547,-1.50977 0.204807,-0.50414 0.397017,-0.96766 0.61914,-1.25977 C 73.397904,478.13563 73.585648,478 74,478 c 0.376652,0 0.584084,0.165 0.837891,0.55664 0.253806,0.39164 0.470672,0.98903 0.689453,1.61524 0.21878,0.6262 0.438752,1.28115 0.794922,1.82812 0.35617,0.54697 0.933457,1.00595 1.68164,1 0.673157,-0.005 1.209041,-0.26371 1.570313,-0.62109 0.361272,-0.35739 0.571027,-0.77752 0.771484,-1.14649 0.200458,-0.36897 0.389328,-0.68586 0.623047,-0.89258 C 81.202469,480.13313 81.474401,480 82,480 h 1 v -1 h -1 c -0.724401,0 -1.296219,0.23882 -1.695312,0.5918 -0.399094,0.35298 -0.632099,0.78332 -0.837891,1.16211 -0.205793,0.37878 -0.386663,0.70727 -0.595703,0.91406 -0.209041,0.20679 -0.423157,0.32843 -0.875,0.33203 -0.376817,0.003 -0.58078,-0.15803 -0.833985,-0.54688 -0.253205,-0.38884 -0.470733,-0.98529 -0.689453,-1.61132 -0.218719,-0.62603 -0.439353,-1.28142 -0.794922,-1.83008 C 75.322166,477.46306 74.748348,477 74,477 Z"
+ id="path15332-4"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 82.5,473 -13,0.004 a 0.50005,0.50005 0 0 0 -0.5,0.5 V 480 h 1 v -5.99609 L 82,474 v 4 h 1 v -4.5 A 0.50005,0.50005 0 0 0 82.5,473 Z m -0.5,8 v 5 H 70 v -3 h -1 v 3.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 A 0.50005,0.50005 0 0 0 83,486.5 V 481 Z"
+ id="path12638-3"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13177"
+ transform="translate(-1.8536743e-6,-20.999995)">
+ <g
+ id="g13282"
+ transform="translate(20,-21)"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 246.49805,74 c -0.13192,5.4e-4 -0.25829,0.0532 -0.35157,0.146484 C 245.43577,74.857204 244.09848,76 241.5,76 A 0.50005,0.50005 0 0 0 241,76.5 V 79 h -0.5 c -0.75833,0 -1.38671,0.318735 -1.90625,0.734375 -0.51954,0.41563 -0.962,0.926849 -1.44727,1.412109 -0.39648,0.39648 0.31056,1.103512 0.70704,0.707032 0.4558,-0.45581 0.79842,-0.643904 1.18164,-0.746094 C 239.41838,81.005232 239.875,81 240.5,81 h 0.5 v 4.5 c 0,0.75694 -0.56911,1.365513 -1.18359,1.476562 -0.30725,0.0555 -0.62032,0.004 -0.94141,-0.228515 -0.32109,-0.23272 -0.65388,-0.66673 -0.90039,-1.40625 A 0.50005,0.50005 0 0 0 237,85.5 v 1 a 0.50005,0.50005 0 0 0 0.14648,0.353516 C 238.22544,87.932473 239.1944,88.00968 240,88 c 0,0 0.002,0 0.002,0 9.9e-4,0 0.003,10e-7 0.004,0 0.001,-1.6e-5 0.003,1.8e-5 0.004,0 0.36494,-7.26e-4 0.98133,-0.05472 1.67773,-0.203125 0.19213,-0.0454 0.36061,-0.131526 0.54297,-0.197266 0.41443,-0.1248 0.82232,-0.201598 1.24219,-0.449218 C 244.82222,86.354491 246,84.75992 246,82 v -1 h 2.5 c 0.1326,-2e-5 0.25976,-0.0527 0.35352,-0.146484 l 1,-1 C 250.16831,79.538516 249.94532,79.00017 249.5,79 H 246 v -2.529297 c 0.26613,0.242116 0.53257,0.477435 0.83203,0.527344 0.63268,0.10544 1.23725,-0.0679 1.76563,-0.332031 1.05675,-0.52838 1.9005,-1.45715 2.25586,-1.8125 0.45304,-0.47127 -0.23577,-1.160072 -0.70704,-0.707032 -0.31826,0.31827 -0.84181,0.673592 -1.40039,0.763672 -0.55857,0.0901 -1.16912,-0.02339 -1.88867,-0.759765 -0.0945,-0.0967 -0.22417,-0.150901 -0.35937,-0.150391 z m -2.50977,3.013672 c 0.004,-1.62e-4 0.008,1.67e-4 0.0117,0 V 83 c 0,1.65476 -0.45037,2.602541 -1.13477,3.181641 -0.20404,0.172661 -0.46051,0.286861 -0.72656,0.390625 C 242.64927,85.748655 243,84.573733 243,83 v -5.982422 c 0.35078,0.0051 0.69957,0.0073 0.98828,-0.0039 z"
+ transform="translate(-19.999998,41.999995)"
+ id="path13240"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" id="g13304" transform="translate(-84.000015,-126)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 475,157.99609 c -1.79823,1e-5 -2.78534,0.23261 -3.38867,0.75196 C 471.00799,159.2674 471,160.00249 471,160.49609 v 0.5 h -0.002 c -0.12828,0 -0.91099,4e-5 -1.63867,0.53711 -0.72848,0.53766 -1.35958,1.60963 -1.35938,3.4668 9e-5,0.84676 0.12547,1.43896 0.35352,1.89453 0.22804,0.45557 0.5457,0.7425 0.81445,0.98047 a 0.50086817,0.50086817 0 1 0 0.66406,-0.75 c -0.2639,-0.23368 -0.44506,-0.40021 -0.58398,-0.67773 -0.13888,-0.27753 -0.24792,-0.69815 -0.248,-1.44727 -1.7e-4,-1.64286 0.494,-2.32325 0.95312,-2.66211 0.45913,-0.33885 0.92388,-0.3418 1.04688,-0.3418 h 0.44336 a 0.50005,0.50005 0 0 0 0.0586,0.004 l 3,-0.01 a 0.50005,0.50005 0 0 0 -0.002,-1 h -0.002 -0.002 L 472,160.99414 v -0.49805 c 0,-0.4936 -0.008,-0.75638 0.26367,-0.99023 0.27167,-0.23385 1.03456,-0.50976 2.73633,-0.50977 1.70177,0 2.46467,0.27592 2.73633,0.50977 0.27166,0.23385 0.26367,0.49663 0.26367,0.99023 v 1.99414 c -6e-5,0.47857 -0.26457,0.78886 -0.8457,1.12891 -0.58114,0.34005 -1.43184,0.62116 -2.30664,0.90234 -0.87481,0.28119 -1.77478,0.56315 -2.50586,0.98829 -0.73108,0.42513 -1.34192,1.08253 -1.3418,1.98046 v 2.01368 c 0,0.4936 0.008,1.22869 0.61133,1.74804 0.60334,0.51936 1.59044,0.75196 3.38867,0.75196 1.79823,-1e-5 2.78534,-0.23261 3.38867,-0.75196 C 478.99201,170.7326 479,169.99751 479,169.50391 v -0.5 c 0.127,0 0.91215,5.4e-4 1.64062,-0.53711 0.72848,-0.53766 1.35958,-1.60963 1.35938,-3.4668 -1.6e-4,-1.56962 -0.66959,-2.34844 -1.13672,-2.84375 a 0.5001364,0.5001364 0 1 0 -0.72656,0.6875 c 0.47073,0.49913 0.86314,0.83133 0.86328,2.15625 1.7e-4,1.64286 -0.494,2.32325 -0.95312,2.66211 -0.45913,0.33885 -0.92388,0.3418 -1.04688,0.3418 h -0.44336 A 0.50005,0.50005 0 0 0 478.49805,168 l -3,0.01 a 0.50005,0.50005 0 0 0 0.002,1 h 0.002 0.002 L 478,169.00586 v 0.49805 c 0,0.4936 0.008,0.75638 -0.26367,0.99023 -0.27167,0.23385 -1.03456,0.50976 -2.73633,0.50977 -1.70177,0 -2.46467,-0.27592 -2.73633,-0.50977 C 471.99201,170.26029 472,169.99751 472,169.50391 v -2.01368 c -6e-5,-0.47218 0.26437,-0.77913 0.8457,-1.11718 0.58133,-0.33805 1.43145,-0.61908 2.30664,-0.90039 0.8752,-0.28132 1.77441,-0.56222 2.50586,-0.99024 0.73146,-0.42801 1.34168,-1.09087 1.3418,-1.99219 v -1.99414 c 0,-0.4936 -0.008,-1.22869 -0.61133,-1.74804 -0.60334,-0.51936 -1.59044,-0.75196 -3.38867,-0.75196 z" id="path13302" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 433,120 c -1.65093,0 -3,1.34907 -3,3 0,1.65093 1.34907,3 3,3 1.65093,0 3,-1.34907 3,-3 0,-1.65093 -1.34907,-3 -3,-3 z" id="circle13367" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="g13384" transform="translate(-21.000002,-105)" style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
- <rect style="display:inline;opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" id="rect13372" width="16" height="16" x="236" y="325" rx="0" ry="0"/>
- <g id="g13382" transform="translate(1)" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 238.49414,326.05078 c -0.11724,0.001 -0.22936,0.0482 -0.3125,0.13086 l -2,2 c -0.17593,0.17578 -0.17593,0.46094 0,0.63672 l 2,2 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 2,-2 c 0.17593,-0.17578 0.17593,-0.46094 0,-0.63672 l -2,-2 c -0.086,-0.0855 -0.20293,-0.13272 -0.32422,-0.13086 z m 9,0 c -0.11724,0.001 -0.22936,0.0482 -0.3125,0.13086 l -2,2 c -0.17593,0.17578 -0.17593,0.46094 0,0.63672 l 2,2 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 2,-2 c 0.17593,-0.17578 0.17593,-0.46094 0,-0.63672 l -2,-2 c -0.086,-0.0855 -0.20293,-0.13272 -0.32422,-0.13086 z" id="path13378" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccc"/>
- <path style="opacity:0.5;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" d="m 240.12109,326 1.43946,1.43945 c 0.58556,0.5858 0.58556,1.5353 0,2.1211 L 240.12109,331 h 5.75782 l -1.43946,-1.43945 c -0.58556,-0.5858 -0.58556,-1.5353 0,-2.1211 L 245.87891,326 Z" id="path13380" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
+ id="g13304"
+ transform="translate(-84.000015,-126)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 475,157.99609 c -1.79823,1e-5 -2.78534,0.23261 -3.38867,0.75196 C 471.00799,159.2674 471,160.00249 471,160.49609 v 0.5 h -0.002 c -0.12828,0 -0.91099,4e-5 -1.63867,0.53711 -0.72848,0.53766 -1.35958,1.60963 -1.35938,3.4668 9e-5,0.84676 0.12547,1.43896 0.35352,1.89453 0.22804,0.45557 0.5457,0.7425 0.81445,0.98047 a 0.50086817,0.50086817 0 1 0 0.66406,-0.75 c -0.2639,-0.23368 -0.44506,-0.40021 -0.58398,-0.67773 -0.13888,-0.27753 -0.24792,-0.69815 -0.248,-1.44727 -1.7e-4,-1.64286 0.494,-2.32325 0.95312,-2.66211 0.45913,-0.33885 0.92388,-0.3418 1.04688,-0.3418 h 0.44336 a 0.50005,0.50005 0 0 0 0.0586,0.004 l 3,-0.01 a 0.50005,0.50005 0 0 0 -0.002,-1 h -0.002 -0.002 L 472,160.99414 v -0.49805 c 0,-0.4936 -0.008,-0.75638 0.26367,-0.99023 0.27167,-0.23385 1.03456,-0.50976 2.73633,-0.50977 1.70177,0 2.46467,0.27592 2.73633,0.50977 0.27166,0.23385 0.26367,0.49663 0.26367,0.99023 v 1.99414 c -6e-5,0.47857 -0.26457,0.78886 -0.8457,1.12891 -0.58114,0.34005 -1.43184,0.62116 -2.30664,0.90234 -0.87481,0.28119 -1.77478,0.56315 -2.50586,0.98829 -0.73108,0.42513 -1.34192,1.08253 -1.3418,1.98046 v 2.01368 c 0,0.4936 0.008,1.22869 0.61133,1.74804 0.60334,0.51936 1.59044,0.75196 3.38867,0.75196 1.79823,-1e-5 2.78534,-0.23261 3.38867,-0.75196 C 478.99201,170.7326 479,169.99751 479,169.50391 v -0.5 c 0.127,0 0.91215,5.4e-4 1.64062,-0.53711 0.72848,-0.53766 1.35958,-1.60963 1.35938,-3.4668 -1.6e-4,-1.56962 -0.66959,-2.34844 -1.13672,-2.84375 a 0.5001364,0.5001364 0 1 0 -0.72656,0.6875 c 0.47073,0.49913 0.86314,0.83133 0.86328,2.15625 1.7e-4,1.64286 -0.494,2.32325 -0.95312,2.66211 -0.45913,0.33885 -0.92388,0.3418 -1.04688,0.3418 h -0.44336 A 0.50005,0.50005 0 0 0 478.49805,168 l -3,0.01 a 0.50005,0.50005 0 0 0 0.002,1 h 0.002 0.002 L 478,169.00586 v 0.49805 c 0,0.4936 0.008,0.75638 -0.26367,0.99023 -0.27167,0.23385 -1.03456,0.50976 -2.73633,0.50977 -1.70177,0 -2.46467,-0.27592 -2.73633,-0.50977 C 471.99201,170.26029 472,169.99751 472,169.50391 v -2.01368 c -6e-5,-0.47218 0.26437,-0.77913 0.8457,-1.11718 0.58133,-0.33805 1.43145,-0.61908 2.30664,-0.90039 0.8752,-0.28132 1.77441,-0.56222 2.50586,-0.99024 0.73146,-0.42801 1.34168,-1.09087 1.3418,-1.99219 v -1.99414 c 0,-0.4936 -0.008,-1.22869 -0.61133,-1.74804 -0.60334,-0.51936 -1.59044,-0.75196 -3.38867,-0.75196 z"
+ id="path13302"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 433,120 c -1.65093,0 -3,1.34907 -3,3 0,1.65093 1.34907,3 3,3 1.65093,0 3,-1.34907 3,-3 0,-1.65093 -1.34907,-3 -3,-3 z"
+ id="circle13367"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ id="g13384"
+ transform="translate(-21.000002,-105)"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
+ <rect
+ style="display:inline;opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ id="rect13372"
+ width="16"
+ height="16"
+ x="236"
+ y="325"
+ rx="0"
+ ry="0" />
+ <g
+ id="g13382"
+ transform="translate(1)"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 238.49414,326.05078 c -0.11724,0.001 -0.22936,0.0482 -0.3125,0.13086 l -2,2 c -0.17593,0.17578 -0.17593,0.46094 0,0.63672 l 2,2 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 2,-2 c 0.17593,-0.17578 0.17593,-0.46094 0,-0.63672 l -2,-2 c -0.086,-0.0855 -0.20293,-0.13272 -0.32422,-0.13086 z m 9,0 c -0.11724,0.001 -0.22936,0.0482 -0.3125,0.13086 l -2,2 c -0.17593,0.17578 -0.17593,0.46094 0,0.63672 l 2,2 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 2,-2 c 0.17593,-0.17578 0.17593,-0.46094 0,-0.63672 l -2,-2 c -0.086,-0.0855 -0.20293,-0.13272 -0.32422,-0.13086 z"
+ id="path13378"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccc" />
+ <path
+ style="opacity:0.5;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="m 240.12109,326 1.43946,1.43945 c 0.58556,0.5858 0.58556,1.5353 0,2.1211 L 240.12109,331 h 5.75782 l -1.43946,-1.43945 c -0.58556,-0.5858 -0.58556,-1.5353 0,-2.1211 L 245.87891,326 Z"
+ id="path13380"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
</g>
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 221.50195,227 c -0.35971,-0.001 -0.6028,0.36671 -0.46093,0.69727 l 3,7 c 0.18151,0.42185 0.78799,0.39645 0.93359,-0.0391 l 0.91992,-2.76367 2.76367,-0.91992 c 0.43555,-0.1456 0.46095,-0.75208 0.0391,-0.93359 l -7,-3 c -0.0617,-0.0266 -0.12814,-0.0406 -0.19535,-0.041 z" id="path12946-5" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g12888" transform="translate(-1.8536743e-6,21.000005)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 241.48438,452 c -0.12717,0.004 -0.248,0.0564 -0.3379,0.14648 l -3,3 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c 1.1e-4,-0.28235 -0.23341,-0.50879 -0.51562,-0.5 z M 243,452 v 5 h -5 v 1.5 c 2e-5,0.1326 0.0527,0.25976 0.14648,0.35352 l 2,2 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 2.64648,-2.64649 1.64648,1.64649 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 2.64648,-2.64649 0.64648,0.64649 1,1 c 0.315,0.31479 0.85335,0.0918 0.85352,-0.35352 v -6 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 4.49219,9 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -2.64648,2.64649 -1.64648,-1.64649 c -0.19527,-0.19519 -0.51177,-0.19519 -0.70704,0 l -2.64648,2.64649 -1.64648,-1.64649 c -0.315,-0.31479 -0.85335,-0.0918 -0.85352,0.35352 v 2 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2.00781 9.99219 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -2e-5,-0.1326 -0.0527,-0.25976 -0.14648,-0.35352 l -1,-1 -1,-1 c -0.0957,-0.0957 -0.22603,-0.14855 -0.36133,-0.14648 z" id="path14234" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccc"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g13069" transform="translate(-21.000002,42.000005)">
- <path sodipodi:nodetypes="ccccccccccccccc" inkscape:connector-curvature="0" id="ellipse12909" d="m 290,517 h 2.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -2.91992 c -0.029,-0.005 -0.0584,-0.008 -0.0879,-0.008 -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 1 5.64062 c -0.56586,-0.20756 -1.28645,-0.18129 -1.98242,0.0723 -1.35506,0.4963 -2.23747,1.69879 -1.9707,2.68555 0.26595,0.98712 1.58042,1.38505 2.93554,0.88867 1.22872,-0.45129 2.01759,-1.35494 2.01758,-2.53711 z" style="display:inline;overflow:visible;visibility:visible;opacity:0.98999999;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.75542808px;marker:none;enable-background:accumulate"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 283.51562,517 a 0.50005,0.50005 0 0 0 -0.22656,0.0566 c -1.99745,1.00305 -3.4683,2.88412 -4.03515,5.13477 -0.56686,2.25064 -0.17629,4.64784 1.07421,6.56836 a 0.50005,0.50005 0 1 0 0.8379,-0.54493 c -1.09418,-1.68042 -1.44042,-3.798 -0.94141,-5.77929 0.49902,-1.9813 1.78869,-3.62011 3.51367,-4.48633 A 0.50005,0.50005 0 0 0 283.51562,517 Z m 0.98243,3 a 0.50005,0.50005 0 0 0 -0.26758,0.082 c -1.21391,0.77866 -2.01457,2.12204 -2.19336,3.63086 -0.17879,1.50883 0.2812,3.02564 1.26367,4.11719 a 0.50005,0.50005 0 1 0 0.74219,-0.66992 c -0.77619,-0.86237 -1.15757,-2.0993 -1.01172,-3.33008 0.14584,-1.23079 0.79828,-2.30329 1.73828,-2.90625 A 0.50005,0.50005 0 0 0 284.49805,520 Z" id="path12979" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" transform="translate(336,21.000005)" id="g13340">
- <g id="g13324" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 501.98047,136.99023 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 l -2.7207,2.7207 c -0.0264,-10e-4 -0.0514,-0.008 -0.0781,-0.008 -0.82235,0 -1.5,0.67765 -1.5,1.5 0,0.82235 0.67765,1.5 1.5,1.5 0.82235,0 1.5,-0.67765 1.5,-1.5 0,-0.0267 -0.006,-0.0518 -0.008,-0.0781 l 2.7207,-2.7207 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z" transform="translate(-336,-21.000005)" id="rect13317" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 221.50195,227 c -0.35971,-0.001 -0.6028,0.36671 -0.46093,0.69727 l 3,7 c 0.18151,0.42185 0.78799,0.39645 0.93359,-0.0391 l 0.91992,-2.76367 2.76367,-0.91992 c 0.43555,-0.1456 0.46095,-0.75208 0.0391,-0.93359 l -7,-3 c -0.0617,-0.0266 -0.12814,-0.0406 -0.19535,-0.041 z"
+ id="path12946-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12888"
+ transform="translate(-1.8536743e-6,21.000005)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 241.48438,452 c -0.12717,0.004 -0.248,0.0564 -0.3379,0.14648 l -3,3 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c 1.1e-4,-0.28235 -0.23341,-0.50879 -0.51562,-0.5 z M 243,452 v 5 h -5 v 1.5 c 2e-5,0.1326 0.0527,0.25976 0.14648,0.35352 l 2,2 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 2.64648,-2.64649 1.64648,1.64649 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 2.64648,-2.64649 0.64648,0.64649 1,1 c 0.315,0.31479 0.85335,0.0918 0.85352,-0.35352 v -6 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 4.49219,9 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -2.64648,2.64649 -1.64648,-1.64649 c -0.19527,-0.19519 -0.51177,-0.19519 -0.70704,0 l -2.64648,2.64649 -1.64648,-1.64649 c -0.315,-0.31479 -0.85335,-0.0918 -0.85352,0.35352 v 2 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2.00781 9.99219 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -2e-5,-0.1326 -0.0527,-0.25976 -0.14648,-0.35352 l -1,-1 -1,-1 c -0.0957,-0.0957 -0.22603,-0.14855 -0.36133,-0.14648 z"
+ id="path14234"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccc" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13069"
+ transform="translate(-21.000002,42.000005)">
+ <path
+ sodipodi:nodetypes="ccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="ellipse12909"
+ d="m 290,517 h 2.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -2.91992 c -0.029,-0.005 -0.0584,-0.008 -0.0879,-0.008 -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 1 5.64062 c -0.56586,-0.20756 -1.28645,-0.18129 -1.98242,0.0723 -1.35506,0.4963 -2.23747,1.69879 -1.9707,2.68555 0.26595,0.98712 1.58042,1.38505 2.93554,0.88867 1.22872,-0.45129 2.01759,-1.35494 2.01758,-2.53711 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.98999999;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.75542808px;marker:none;enable-background:accumulate" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 283.51562,517 a 0.50005,0.50005 0 0 0 -0.22656,0.0566 c -1.99745,1.00305 -3.4683,2.88412 -4.03515,5.13477 -0.56686,2.25064 -0.17629,4.64784 1.07421,6.56836 a 0.50005,0.50005 0 1 0 0.8379,-0.54493 c -1.09418,-1.68042 -1.44042,-3.798 -0.94141,-5.77929 0.49902,-1.9813 1.78869,-3.62011 3.51367,-4.48633 A 0.50005,0.50005 0 0 0 283.51562,517 Z m 0.98243,3 a 0.50005,0.50005 0 0 0 -0.26758,0.082 c -1.21391,0.77866 -2.01457,2.12204 -2.19336,3.63086 -0.17879,1.50883 0.2812,3.02564 1.26367,4.11719 a 0.50005,0.50005 0 1 0 0.74219,-0.66992 c -0.77619,-0.86237 -1.15757,-2.0993 -1.01172,-3.33008 0.14584,-1.23079 0.79828,-2.30329 1.73828,-2.90625 A 0.50005,0.50005 0 0 0 284.49805,520 Z"
+ id="path12979"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(336,21.000005)"
+ id="g13340">
+ <g
+ id="g13324"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 501.98047,136.99023 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 l -2.7207,2.7207 c -0.0264,-10e-4 -0.0514,-0.008 -0.0781,-0.008 -0.82235,0 -1.5,0.67765 -1.5,1.5 0,0.82235 0.67765,1.5 1.5,1.5 0.82235,0 1.5,-0.67765 1.5,-1.5 0,-0.0267 -0.006,-0.0518 -0.008,-0.0781 l 2.7207,-2.7207 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z"
+ transform="translate(-336,-21.000005)"
+ id="rect13317"
+ inkscape:connector-curvature="0" />
</g>
- <g id="g13338" transform="translate(717.99456,-488.99997)" style="opacity:0.6;fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 489.49414,140 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.5 v 5 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -0.50781 h 5 V 150.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -0.5 v -4 h -1 v 4 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.49219 h -5 V 148.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -0.5 v -5 h 0.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -0.50781 H 496 v -1 h -4.00586 V 140.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 0,8 h 1 v 1 h -1 z m 8,0 h 1 v 1 h -1 z" transform="translate(-1053.9946,467.99997)" id="path13330" inkscape:connector-curvature="0"/>
+ <g
+ id="g13338"
+ transform="translate(717.99456,-488.99997)"
+ style="opacity:0.6;fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 489.49414,140 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.5 v 5 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -0.50781 h 5 V 150.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -0.5 v -4 h -1 v 4 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.49219 h -5 V 148.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -0.5 v -5 h 0.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -0.50781 H 496 v -1 h -4.00586 V 140.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 0,8 h 1 v 1 h -1 z m 8,0 h 1 v 1 h -1 z"
+ transform="translate(-1053.9946,467.99997)"
+ id="path13330"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" transform="translate(357,21.000005)" id="g13370">
- <g id="g13360" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 181.98438,115.98633 A 1.0001,1.0001 0 0 0 181,117 v 4.83203 a 1.0001,1.0001 0 0 0 0.28906,0.88477 1.0001,1.0001 0 0 0 0.006,0.006 1.0001,1.0001 0 0 0 0.0137,0.0137 A 1.0001,1.0001 0 0 0 182.1582,123 H 187 a 1.0001,1.0001 0 1 0 0,-2 h -4 v -4 a 1.0001,1.0001 0 0 0 -1.01562,-1.01367 z" id="path13358" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(357,21.000005)"
+ id="g13370">
+ <g
+ id="g13360"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 181.98438,115.98633 A 1.0001,1.0001 0 0 0 181,117 v 4.83203 a 1.0001,1.0001 0 0 0 0.28906,0.88477 1.0001,1.0001 0 0 0 0.006,0.006 1.0001,1.0001 0 0 0 0.0137,0.0137 A 1.0001,1.0001 0 0 0 182.1582,123 H 187 a 1.0001,1.0001 0 1 0 0,-2 h -4 v -4 a 1.0001,1.0001 0 0 0 -1.01562,-1.01367 z"
+ id="path13358"
+ inkscape:connector-curvature="0" />
</g>
- <g transform="matrix(0,-1,-1,0,301.99245,326.99752)" id="g13368" style="fill:#ffffff">
- <g style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new" id="g13366" transform="translate(760.99456,-488.99997)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g id="g13364" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m -563.5,607 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 l 0.006,-5.50781 h -1 L -555,616 h -8 v -8 h 5.00391 v -1 z" id="path13362" inkscape:connector-curvature="0"/>
+ <g
+ transform="matrix(0,-1,-1,0,301.99245,326.99752)"
+ id="g13368"
+ style="fill:#ffffff">
+ <g
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ id="g13366"
+ transform="translate(760.99456,-488.99997)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ id="g13364"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -563.5,607 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 l 0.006,-5.50781 h -1 L -555,616 h -8 v -8 h 5.00391 v -1 z"
+ id="path13362"
+ inkscape:connector-curvature="0" />
</g>
</g>
</g>
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 352.72656,472.9707 c -0.84514,-0.0154 -1.69148,0.28718 -2.33008,0.92578 l -2.13476,2.13477 c -1.14247,-0.0826 -2.16028,-0.0359 -2.98047,0.30273 -0.89973,0.37145 -1.59595,1.03428 -2.08008,1.92774 C 342.23291,480.04863 342,482.7268 342,486.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 c 3.7729,0 6.45106,-0.23075 8.23828,-1.19727 0.89361,-0.48326 1.5563,-1.17766 1.92774,-2.07812 0.33865,-0.82099 0.38541,-1.84087 0.30273,-2.98633 l 2.13477,-2.13476 c 1.27714,-1.27719 1.21033,-3.38733 -0.0547,-4.65235 -0.63251,-0.63254 -1.47713,-0.96507 -2.32227,-0.98047 z m -0.01,1.00391 c 0.59016,0.0124 1.18356,0.24213 1.625,0.68359 0.88286,0.88287 0.92532,2.36759 0.0547,3.23828 l -2.25,2.25 a 0.50004997,0.50004997 0 0 0 -0.14453,0.4043 c 0.11985,1.19116 0.0231,2.10252 -0.26172,2.79297 -0.28481,0.69045 -0.74712,1.18455 -1.47851,1.58008 -1.27506,0.68955 -3.50366,0.96361 -6.50586,1.02734 l 3.10352,-3.10351 c 0.19538,0.094 0.41106,0.15234 0.64062,0.15234 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.22956 0.0584,0.44524 0.15234,0.64062 l -3.10351,3.10352 c 0.0645,-3.00197 0.34215,-5.23052 1.0332,-6.50586 0.3964,-0.73154 0.8902,-1.19371 1.58008,-1.47851 0.68987,-0.28481 1.59959,-0.38153 2.78711,-0.26172 a 0.50004997,0.50004997 0 0 0 0.4043,-0.14453 l 2.25,-2.25 c 0.43534,-0.43536 1.02312,-0.64126 1.61328,-0.62891 z" id="path8087-0" inkscape:connector-curvature="0"/>
- <g id="g6603" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 237.49219,305 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 1 0 1,0 V 306 h 3 v 12 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -1.5 v -12 h 3 v 1.5 a 0.50005,0.50005 0 1 0 1,0 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 7,6 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 1 0 1,0 V 312 h 2 v 6 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 h -0.5 v -6 h 2 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z" id="path6924-7" inkscape:connector-curvature="0"/>
- </g>
- <path inkscape:connector-curvature="0" d="m 353,628 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m 9,-3 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" id="path14337"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 374.4375,121.17773 c -0.55229,-0.19531 -1.19407,-0.23097 -1.84766,0.002 -0.65359,0.23293 -1.30733,0.71399 -1.9707,1.49609 -0.28137,0.33173 -0.45085,0.79694 -0.61914,1.24219 -0.17701,-0.45587 -0.36207,-0.94012 -0.61914,-1.24219 -0.66249,-0.77846 -1.31558,-1.25837 -1.96875,-1.49023 -0.65317,-0.23186 -1.2953,-0.19616 -1.84766,-0.002 -1.10471,0.38842 -1.89002,1.32506 -2.44922,1.9961 a 0.50064603,0.50064603 0 1 0 0.76954,0.64062 c 0.54481,-0.65377 1.26345,-1.43095 2.00976,-1.69336 0.37316,-0.1312 0.7444,-0.1559 1.18359,0 0.4392,0.1559 0.95757,0.51168 1.54102,1.19727 0.19894,0.23376 0.56603,0.91963 0.64063,1.27734 A 0.50005,0.50005 0 0 0 369.75,125 h 0.5 a 0.50005,0.50005 0 0 0 0.49023,-0.40234 c 0.0736,-0.37229 0.37785,-0.96363 0.64063,-1.27344 0.58467,-0.68931 1.10595,-1.04668 1.54492,-1.20313 0.43897,-0.15644 0.80714,-0.13175 1.17969,0 0.74509,0.2635 1.46354,1.04375 2.00976,1.69922 a 0.50064603,0.50064603 0 1 0 0.76954,-0.64062 c -0.55904,-0.67084 -1.34269,-1.61133 -2.44727,-2.00196 z" id="path17826-1" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14433" transform="rotate(-90,380.52904,134)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 390.04688,140.46484 a 0.50005,0.50005 0 0 0 -0.41797,0.20704 l -2.95508,3.93945 a 0.50005,0.50005 0 0 0 -0.01,0.70703 l 2.96485,3.95312 a 0.50019216,0.50019216 0 1 0 0.80078,-0.5996 l -2.40039,-3.20118 h 7.1914 l -0.63867,1.27735 a 0.50005635,0.50005635 0 1 0 0.89453,0.44726 l 0.96875,-1.93554 a 0.50005,0.50005 0 0 0 -0.006,-0.58399 l -0.96289,-1.92773 a 0.50005635,0.50005635 0 1 0 -0.89453,0.44726 l 0.63867,1.27539 h -7.1914 l 2.40039,-3.19922 a 0.50005,0.50005 0 0 0 -0.38281,-0.80664 z" id="path17796-5" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 348.5,120 c -1.47879,0 -2.81353,0.43206 -3.80469,1.06641 C 343.70416,121.70075 343,122.54357 343,123.5 c 0,1.02778 0.79097,1.88608 1.87891,2.49805 1.08228,0.60878 2.52394,0.99597 4.09765,1 0.0129,9.4e-4 3.75669,0.27336 6.02344,-2.21094 V 127.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -4.25 a 0.50005,0.50005 0 1 0 0,1 h 3.10156 c -1.87731,2.16501 -5.32031,2 -5.32031,2 A 0.50005,0.50005 0 0 0 349,126 c -1.41667,0 -2.71684,-0.36001 -3.62891,-0.87305 C 344.45903,124.61392 344,123.97222 344,123.5 c 0,-0.41012 0.41561,-1.06779 1.23438,-1.5918 C 346.05313,121.38419 347.21846,121 348.5,121 a 0.50005,0.50005 0 1 0 0,-1 z" id="path18766-5" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g12950" transform="translate(-42.000002,4.4999696e-6)">
- <g id="g12531-9" transform="translate(-209.00718,-44.00717)" style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 446.5,161 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 8 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 447 v -7 h 0.5 4.9707 1.0293 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 452.4707 447.5 Z m 4.50718,10.00717 L 451,173 h -1.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.91992 c 0.0537,0.009 0.10843,0.009 0.16211,0 H 453.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 452 l 0.007,-1.99283 z" id="path12529-5" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccccc"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 352.72656,472.9707 c -0.84514,-0.0154 -1.69148,0.28718 -2.33008,0.92578 l -2.13476,2.13477 c -1.14247,-0.0826 -2.16028,-0.0359 -2.98047,0.30273 -0.89973,0.37145 -1.59595,1.03428 -2.08008,1.92774 C 342.23291,480.04863 342,482.7268 342,486.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 c 3.7729,0 6.45106,-0.23075 8.23828,-1.19727 0.89361,-0.48326 1.5563,-1.17766 1.92774,-2.07812 0.33865,-0.82099 0.38541,-1.84087 0.30273,-2.98633 l 2.13477,-2.13476 c 1.27714,-1.27719 1.21033,-3.38733 -0.0547,-4.65235 -0.63251,-0.63254 -1.47713,-0.96507 -2.32227,-0.98047 z m -0.01,1.00391 c 0.59016,0.0124 1.18356,0.24213 1.625,0.68359 0.88286,0.88287 0.92532,2.36759 0.0547,3.23828 l -2.25,2.25 a 0.50004997,0.50004997 0 0 0 -0.14453,0.4043 c 0.11985,1.19116 0.0231,2.10252 -0.26172,2.79297 -0.28481,0.69045 -0.74712,1.18455 -1.47851,1.58008 -1.27506,0.68955 -3.50366,0.96361 -6.50586,1.02734 l 3.10352,-3.10351 c 0.19538,0.094 0.41106,0.15234 0.64062,0.15234 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.22956 0.0584,0.44524 0.15234,0.64062 l -3.10351,3.10352 c 0.0645,-3.00197 0.34215,-5.23052 1.0332,-6.50586 0.3964,-0.73154 0.8902,-1.19371 1.58008,-1.47851 0.68987,-0.28481 1.59959,-0.38153 2.78711,-0.26172 a 0.50004997,0.50004997 0 0 0 0.4043,-0.14453 l 2.25,-2.25 c 0.43534,-0.43536 1.02312,-0.64126 1.61328,-0.62891 z"
+ id="path8087-0"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g6603"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 237.49219,305 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 1 0 1,0 V 306 h 3 v 12 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -1.5 v -12 h 3 v 1.5 a 0.50005,0.50005 0 1 0 1,0 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 7,6 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 1 0 1,0 V 312 h 2 v 6 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 h -0.5 v -6 h 2 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path6924-7"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ d="m 353,628 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m 9,-3 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="path14337" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 374.4375,121.17773 c -0.55229,-0.19531 -1.19407,-0.23097 -1.84766,0.002 -0.65359,0.23293 -1.30733,0.71399 -1.9707,1.49609 -0.28137,0.33173 -0.45085,0.79694 -0.61914,1.24219 -0.17701,-0.45587 -0.36207,-0.94012 -0.61914,-1.24219 -0.66249,-0.77846 -1.31558,-1.25837 -1.96875,-1.49023 -0.65317,-0.23186 -1.2953,-0.19616 -1.84766,-0.002 -1.10471,0.38842 -1.89002,1.32506 -2.44922,1.9961 a 0.50064603,0.50064603 0 1 0 0.76954,0.64062 c 0.54481,-0.65377 1.26345,-1.43095 2.00976,-1.69336 0.37316,-0.1312 0.7444,-0.1559 1.18359,0 0.4392,0.1559 0.95757,0.51168 1.54102,1.19727 0.19894,0.23376 0.56603,0.91963 0.64063,1.27734 A 0.50005,0.50005 0 0 0 369.75,125 h 0.5 a 0.50005,0.50005 0 0 0 0.49023,-0.40234 c 0.0736,-0.37229 0.37785,-0.96363 0.64063,-1.27344 0.58467,-0.68931 1.10595,-1.04668 1.54492,-1.20313 0.43897,-0.15644 0.80714,-0.13175 1.17969,0 0.74509,0.2635 1.46354,1.04375 2.00976,1.69922 a 0.50064603,0.50064603 0 1 0 0.76954,-0.64062 c -0.55904,-0.67084 -1.34269,-1.61133 -2.44727,-2.00196 z"
+ id="path17826-1"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14433"
+ transform="rotate(-90,380.52904,134)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 390.04688,140.46484 a 0.50005,0.50005 0 0 0 -0.41797,0.20704 l -2.95508,3.93945 a 0.50005,0.50005 0 0 0 -0.01,0.70703 l 2.96485,3.95312 a 0.50019216,0.50019216 0 1 0 0.80078,-0.5996 l -2.40039,-3.20118 h 7.1914 l -0.63867,1.27735 a 0.50005635,0.50005635 0 1 0 0.89453,0.44726 l 0.96875,-1.93554 a 0.50005,0.50005 0 0 0 -0.006,-0.58399 l -0.96289,-1.92773 a 0.50005635,0.50005635 0 1 0 -0.89453,0.44726 l 0.63867,1.27539 h -7.1914 l 2.40039,-3.19922 a 0.50005,0.50005 0 0 0 -0.38281,-0.80664 z"
+ id="path17796-5"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 348.5,120 c -1.47879,0 -2.81353,0.43206 -3.80469,1.06641 C 343.70416,121.70075 343,122.54357 343,123.5 c 0,1.02778 0.79097,1.88608 1.87891,2.49805 1.08228,0.60878 2.52394,0.99597 4.09765,1 0.0129,9.4e-4 3.75669,0.27336 6.02344,-2.21094 V 127.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -4.25 a 0.50005,0.50005 0 1 0 0,1 h 3.10156 c -1.87731,2.16501 -5.32031,2 -5.32031,2 A 0.50005,0.50005 0 0 0 349,126 c -1.41667,0 -2.71684,-0.36001 -3.62891,-0.87305 C 344.45903,124.61392 344,123.97222 344,123.5 c 0,-0.41012 0.41561,-1.06779 1.23438,-1.5918 C 346.05313,121.38419 347.21846,121 348.5,121 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path18766-5"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12950"
+ transform="translate(-42.000002,4.4999696e-6)">
+ <g
+ id="g12531-9"
+ transform="translate(-209.00718,-44.00717)"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 446.5,161 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 8 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 447 v -7 h 0.5 4.9707 1.0293 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 452.4707 447.5 Z m 4.50718,10.00717 L 451,173 h -1.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.91992 c 0.0537,0.009 0.10843,0.009 0.16211,0 H 453.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 452 l 0.007,-1.99283 z"
+ id="path12529-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccc" />
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 206.5,115.99219 c -1.39025,0 -2.5,1.19177 -2.5,2.61523 V 120.5 a 0.50004994,0.50004994 0 1 0 1,0 v -1.89258 c 0,-0.91233 0.68117,-1.61523 1.5,-1.61523 0.81884,0 1.5,0.70289 1.5,1.61523 V 120.5 a 0.50004994,0.50004994 0 1 0 1,0 v -1.89258 c 0,-1.42345 -1.10974,-2.61523 -2.5,-2.61523 z m -2.00781,9 A 0.50004994,0.50004994 0 0 0 204,125.5 v 1.88477 c 0,1.42346 1.10975,2.61523 2.5,2.61523 1.39026,0 2.5,-1.19178 2.5,-2.61523 V 125.5 a 0.50004994,0.50004994 0 1 0 -1,0 v 1.88477 c 0,0.91234 -0.68116,1.61523 -1.5,1.61523 -0.81883,0 -1.5,-0.7029 -1.5,-1.61523 V 125.5 a 0.50004994,0.50004994 0 0 0 -0.50781,-0.50781 z" transform="translate(42.000002,-4.4999696e-6)" id="path12537-3" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g12957" transform="translate(-42.000002,4.4999696e-6)">
- <g style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new" transform="translate(-188.00718,-44.00717)" id="g12922">
- <path id="path12920" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 451.00718,171.00717 451,173 h -1.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.91992 c 0.0537,0.009 0.10843,0.009 0.16211,0 H 453.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 452 l 0.007,-1.99283 z M 446.5,161 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 8 a 0.50005,0.50005 0 0 0 0.5,0.5 h 7 a 0.50005,0.50005 0 1 0 0,-1 H 447 v -7 h 0.5 4.9707 1.0293 a 0.50005,0.50005 0 1 0 0,-1 H 452.4707 447.5 Z" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 206.5,115.99219 c -1.39025,0 -2.5,1.19177 -2.5,2.61523 V 120.5 a 0.50004994,0.50004994 0 1 0 1,0 v -1.89258 c 0,-0.91233 0.68117,-1.61523 1.5,-1.61523 0.81884,0 1.5,0.70289 1.5,1.61523 V 120.5 a 0.50004994,0.50004994 0 1 0 1,0 v -1.89258 c 0,-1.42345 -1.10974,-2.61523 -2.5,-2.61523 z m -2.00781,9 A 0.50004994,0.50004994 0 0 0 204,125.5 v 1.88477 c 0,1.42346 1.10975,2.61523 2.5,2.61523 1.39026,0 2.5,-1.19178 2.5,-2.61523 V 125.5 a 0.50004994,0.50004994 0 1 0 -1,0 v 1.88477 c 0,0.91234 -0.68116,1.61523 -1.5,1.61523 -0.81883,0 -1.5,-0.7029 -1.5,-1.61523 V 125.5 a 0.50004994,0.50004994 0 0 0 -0.50781,-0.50781 z"
+ transform="translate(42.000002,-4.4999696e-6)"
+ id="path12537-3"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12957"
+ transform="translate(-42.000002,4.4999696e-6)">
+ <g
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ transform="translate(-188.00718,-44.00717)"
+ id="g12922">
+ <path
+ id="path12920"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 451.00718,171.00717 451,173 h -1.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.91992 c 0.0537,0.009 0.10843,0.009 0.16211,0 H 453.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 452 l 0.007,-1.99283 z M 446.5,161 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 8 a 0.50005,0.50005 0 0 0 0.5,0.5 h 7 a 0.50005,0.50005 0 1 0 0,-1 H 447 v -7 h 0.5 4.9707 1.0293 a 0.50005,0.50005 0 1 0 0,-1 H 452.4707 447.5 Z"
+ inkscape:connector-curvature="0" />
</g>
- <path id="path12942" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 269.5,120 c -1.40822,0 -2.5,1.26701 -2.5,2.75195 v 1.5 c 0,1.48181 1.09178,2.74805 2.5,2.74805 1.40823,0 2.5,-1.26624 2.5,-2.74805 v -0.32031 a 0.50004994,0.50004994 0 1 0 -1,0 v 0.32031 c 0,1.00094 -0.69911,1.74805 -1.5,1.74805 -0.80086,0 -1.5,-0.74712 -1.5,-1.74805 v -1.5 C 268,121.7464 268.69914,121 269.5,121 a 0.50004994,0.50004994 0 1 0 0,-1 z m 0,-4 c -1.40823,0 -2.5,1.26624 -2.5,2.74805 v 0.32031 a 0.50004994,0.50004994 0 1 0 1,0 v -0.32031 C 268,117.74711 268.69911,117 269.5,117 c 0.80086,0 1.5,0.74712 1.5,1.74805 v 1.5 C 271,121.2536 270.30086,122 269.5,122 a 0.50004994,0.50004994 0 1 0 0,1 c 1.40822,0 2.5,-1.26701 2.5,-2.75195 v -1.5 C 272,117.26624 270.90822,116 269.5,116 Z" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 225.02539,389.05664 c -1.23014,0.0645 -2.42356,0.6345 -3.37891,1.58984 l -4,4 c -0.95534,0.95535 -1.53001,2.15146 -1.59765,3.38477 -0.0676,1.23331 0.38786,2.49571 1.41406,3.50977 1.02392,1.0118 2.28158,1.46686 3.51172,1.40234 1.23014,-0.0645 2.42356,-0.6345 3.37891,-1.58984 l 4,-4 c 0.95534,-0.95535 1.53001,-2.15146 1.59765,-3.38477 0.0676,-1.23331 -0.38786,-2.49571 -1.41406,-3.50977 -1.02392,-1.0118 -2.28158,-1.46686 -3.51172,-1.40234 z m 0.0527,0.99805 c 0.95617,-0.0502 1.91199,0.28134 2.75586,1.11523 0.8416,0.83164 1.17171,1.78562 1.11914,2.74414 -0.0526,0.95853 -0.50462,1.93041 -1.30664,2.73242 l -4,4 c -0.80201,0.80202 -1.76844,1.24868 -2.7246,1.29883 -0.95617,0.0502 -1.91199,-0.28134 -2.75586,-1.11523 -0.8416,-0.83164 -1.17171,-1.78562 -1.11914,-2.74414 0.0526,-0.95853 0.50462,-1.93041 1.30664,-2.73242 l 4,-4 c 0.80201,-0.80202 1.76844,-1.24868 2.7246,-1.29883 z" id="path14559-9" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g13834" transform="rotate(90,244,438.00001)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g id="g13861" transform="rotate(-90,244.00797,459)" style="fill:#ffffff;stroke:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 258.99609,451.98828 a 1.0001,1.0001 0 0 0 -0.82031,1.56641 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 0 0 0,1.10938 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 1 0 1.66406,1.10938 l 2,-3 a 1.0001,1.0001 0 0 0 0,-1.10938 L 260.20898,459 l 1.63086,-2.44531 a 1.0001,1.0001 0 0 0 0,-1.10938 l -2,-3 a 1.0001,1.0001 0 0 0 -0.84375,-0.45703 z m 5,0 a 1.0001,1.0001 0 0 0 -0.82031,1.56641 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 0 0 0,1.10938 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 1 0 1.66406,1.10938 l 2,-3 a 1.0001,1.0001 0 0 0 0,-1.10938 L 265.20898,459 l 1.63086,-2.44531 a 1.0001,1.0001 0 0 0 0,-1.10938 l -2,-3 a 1.0001,1.0001 0 0 0 -0.84375,-0.45703 z m 5,0 a 1.0001,1.0001 0 0 0 -0.82031,1.56641 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 0 0 0,1.10938 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 1 0 1.66406,1.10938 l 2,-3 a 1.0001,1.0001 0 0 0 0,-1.10938 L 270.20898,459 l 1.63086,-2.44531 a 1.0001,1.0001 0 0 0 0,-1.10938 l -2,-3 a 1.0001,1.0001 0 0 0 -0.84375,-0.45703 z" id="path13856" inkscape:connector-curvature="0"/>
+ <path
+ id="path12942"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 269.5,120 c -1.40822,0 -2.5,1.26701 -2.5,2.75195 v 1.5 c 0,1.48181 1.09178,2.74805 2.5,2.74805 1.40823,0 2.5,-1.26624 2.5,-2.74805 v -0.32031 a 0.50004994,0.50004994 0 1 0 -1,0 v 0.32031 c 0,1.00094 -0.69911,1.74805 -1.5,1.74805 -0.80086,0 -1.5,-0.74712 -1.5,-1.74805 v -1.5 C 268,121.7464 268.69914,121 269.5,121 a 0.50004994,0.50004994 0 1 0 0,-1 z m 0,-4 c -1.40823,0 -2.5,1.26624 -2.5,2.74805 v 0.32031 a 0.50004994,0.50004994 0 1 0 1,0 v -0.32031 C 268,117.74711 268.69911,117 269.5,117 c 0.80086,0 1.5,0.74712 1.5,1.74805 v 1.5 C 271,121.2536 270.30086,122 269.5,122 a 0.50004994,0.50004994 0 1 0 0,1 c 1.40822,0 2.5,-1.26701 2.5,-2.75195 v -1.5 C 272,117.26624 270.90822,116 269.5,116 Z"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 225.02539,389.05664 c -1.23014,0.0645 -2.42356,0.6345 -3.37891,1.58984 l -4,4 c -0.95534,0.95535 -1.53001,2.15146 -1.59765,3.38477 -0.0676,1.23331 0.38786,2.49571 1.41406,3.50977 1.02392,1.0118 2.28158,1.46686 3.51172,1.40234 1.23014,-0.0645 2.42356,-0.6345 3.37891,-1.58984 l 4,-4 c 0.95534,-0.95535 1.53001,-2.15146 1.59765,-3.38477 0.0676,-1.23331 -0.38786,-2.49571 -1.41406,-3.50977 -1.02392,-1.0118 -2.28158,-1.46686 -3.51172,-1.40234 z m 0.0527,0.99805 c 0.95617,-0.0502 1.91199,0.28134 2.75586,1.11523 0.8416,0.83164 1.17171,1.78562 1.11914,2.74414 -0.0526,0.95853 -0.50462,1.93041 -1.30664,2.73242 l -4,4 c -0.80201,0.80202 -1.76844,1.24868 -2.7246,1.29883 -0.95617,0.0502 -1.91199,-0.28134 -2.75586,-1.11523 -0.8416,-0.83164 -1.17171,-1.78562 -1.11914,-2.74414 0.0526,-0.95853 0.50462,-1.93041 1.30664,-2.73242 l 4,-4 c 0.80201,-0.80202 1.76844,-1.24868 2.7246,-1.29883 z"
+ id="path14559-9"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13834"
+ transform="rotate(90,244,438.00001)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ id="g13861"
+ transform="rotate(-90,244.00797,459)"
+ style="fill:#ffffff;stroke:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 258.99609,451.98828 a 1.0001,1.0001 0 0 0 -0.82031,1.56641 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 0 0 0,1.10938 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 1 0 1.66406,1.10938 l 2,-3 a 1.0001,1.0001 0 0 0 0,-1.10938 L 260.20898,459 l 1.63086,-2.44531 a 1.0001,1.0001 0 0 0 0,-1.10938 l -2,-3 a 1.0001,1.0001 0 0 0 -0.84375,-0.45703 z m 5,0 a 1.0001,1.0001 0 0 0 -0.82031,1.56641 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 0 0 0,1.10938 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 1 0 1.66406,1.10938 l 2,-3 a 1.0001,1.0001 0 0 0 0,-1.10938 L 265.20898,459 l 1.63086,-2.44531 a 1.0001,1.0001 0 0 0 0,-1.10938 l -2,-3 a 1.0001,1.0001 0 0 0 -0.84375,-0.45703 z m 5,0 a 1.0001,1.0001 0 0 0 -0.82031,1.56641 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 0 0 0,1.10938 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 1 0 1.66406,1.10938 l 2,-3 a 1.0001,1.0001 0 0 0 0,-1.10938 L 270.20898,459 l 1.63086,-2.44531 a 1.0001,1.0001 0 0 0 0,-1.10938 l -2,-3 a 1.0001,1.0001 0 0 0 -0.84375,-0.45703 z"
+ id="path13856"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <path id="path15447" d="m 539.5,10.000005 c -3.5682,0 -6.5,2.931819 -6.5,6.499999 0,1.42599 0.4737,2.74606 1.2637,3.822271 l -3.9707,3.9707 a 1.0001,1.0001 0 1 0 1.414,1.41406 l 3.9707,-3.9707 c 1.0762,0.78998 2.3963,1.26367 3.8223,1.26367 3.5682,0 6.5,-2.93182 6.5,-6.500001 0,-3.56818 -2.9318,-6.499999 -6.5,-6.499999 z m 0,2.999999 c 0.051,0 0.098,0.0135 0.1484,0.0156 a 0.50005,0.50005 0 0 1 0.3516,0.4844 v 2.5 h 2.5 a 0.50005,0.50005 0 0 1 0.4863,0.35742 0.50005,0.50005 0 0 1 0,0.002 c 0,0.0477 0.014,0.0925 0.014,0.14062 0,0.0488 -0.012,0.0942 -0.014,0.14258 A 0.50005,0.50005 0 0 1 542.5,17.000004 H 540 v 2.5 a 0.50005,0.50005 0 0 1 -0.3574,0.486331 c -0.048,0.002 -0.092,0.0137 -0.1406,0.0137 -0.049,0 -0.094,-0.0117 -0.1426,-0.0137 A 0.50005,0.50005 0 0 1 539,19.500004 v -2.5 h -2.5 a 0.50005,0.50005 0 0 1 -0.4863,-0.35742 0.50005,0.50005 0 0 1 0,-0.002 c 0,-0.0476 -0.014,-0.0925 -0.014,-0.14062 0,-0.0488 0.012,-0.0942 0.014,-0.14258 a 0.50005,0.50005 0 0 1 0.4863,-0.35738 h 2.5 v -2.5 a 0.50005,0.50005 0 0 1 0.3516,-0.48438 c 0.05,-0.002 0.098,-0.0156 0.1484,-0.0156 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:7.17647076;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 467.5,10.000005 a 0.50005006,0.50005006 0 0 0 -0.5,0.5 v 15 a 0.50005006,0.50005006 0 0 0 0.5,0.5 h 15 a 0.50005006,0.50005006 0 0 0 0.5,-0.5 v -15 a 0.50005006,0.50005006 0 0 0 -0.5,-0.5 z m 0.5,0.999999 h 4 v 4 h -4 z m 5,0 h 4 v 4 h -4 z m 5,0 h 4 v 4 h -4 z m -10,5 h 4 v 4.000001 h -4 z m 5,0 h 4 v 4.000001 h -4 z m 5,0 h 4 v 4.000001 h -4 z m -10,5.000001 h 4 v 4 h -4 z m 5,0 h 4 v 4 h -4 z m 5,0 h 4 v 4 h -4 z" id="rect15343" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" id="path15369" d="m 449.75,12.000004 a 0.50005006,0.50005006 0 0 0 -0.4824,0.36914 l -3.25,12.000001 a 0.50005006,0.50005006 0 0 0 0.4824,0.63086 h 15 a 0.50005006,0.50005006 0 0 0 0.4824,-0.63086 l -3.25,-12.000001 a 0.50005006,0.50005006 0 0 0 -0.4824,-0.36914 z m 0.3828,1 h 2.086 l -0.2169,2 h -2.4121 z m 3.0938,0 h 1.5468 l 0.2168,2 h -1.9804 z m 2.5547,0 h 2.0859 l 0.541,2 h -2.4101 z m -6.461,3 h 2.5723 l -0.3262,3 h -3.0586 z m 3.5801,0 h 2.1992 l 0.3262,3 h -2.8516 z m 3.207,0 h 2.5723 l 0.8125,3 h -3.0586 z m -7.8711,4.000001 h 3.2207 l -0.4336,4 h -3.8711 z m 4.2305,0 h 3.0664 l 0.4356,4 h -3.9375 z m 4.0762,0 h 3.2207 l 1.084,4 h -3.8711 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <g id="g14544" transform="translate(41.999998,84.000005)" style="display:inline;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 142.16211,494.00195 c -0.3928,-0.016 -0.79264,0.0268 -1.18555,0.13086 -1.05738,0.28017 -1.9221,0.97933 -2.44336,1.89453 -2.51672,-0.22477 -4.91162,1.1516 -5.97656,3.44727 -1.07271,2.31243 -0.56559,5.05473 1.26367,6.83008 1.82926,1.77534 4.58788,2.20194 6.86719,1.06054 2.20676,-1.10505 3.49065,-3.45007 3.27539,-5.89257 0.59118,-0.33407 1.10512,-0.8107 1.46875,-1.41797 0.83525,-1.3949 0.74131,-3.16186 -0.23633,-4.46094 -0.73322,-0.97431 -1.8548,-1.54394 -3.0332,-1.5918 z m -0.041,1 c 0.88379,0.0353 1.72432,0.4611 2.27539,1.19336 0.73477,0.97635 0.80549,2.29734 0.17774,3.34571 -0.62775,1.04836 -1.82561,1.61054 -3.0332,1.42382 a 0.50005006,0.50005006 0 1 0 -0.15235,0.98828 c 0.54314,0.084 1.08325,0.0449 1.59571,-0.0859 0.0521,1.92511 -0.99653,3.7274 -2.7461,4.60351 -1.90239,0.95265 -4.19394,0.59896 -5.7207,-0.88281 -1.52677,-1.48177 -1.94806,-3.76137 -1.05274,-5.69141 0.84423,-1.81987 2.6839,-2.93301 4.66602,-2.88086 -0.0398,0.15646 -0.0768,0.3137 -0.0977,0.47657 a 0.50013931,0.50013931 0 0 0 0.99219,0.12695 c 0.15491,-1.21208 1.02585,-2.20656 2.20703,-2.51953 0.2953,-0.0782 0.59408,-0.10943 0.88867,-0.0977 z" transform="translate(-41.999998,-84.000005)" id="path14540" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 241.25,624 c -0.36727,2.9e-4 -0.60893,0.38318 -0.45117,0.71484 l 2.25,4.75 c 0.18125,0.37923 0.72109,0.37923 0.90234,0 l 2.25,-4.75 C 246.35893,624.38318 246.11727,624.00029 245.75,624 Z" id="path14837" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccc"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g13609" transform="translate(-187,-89.999995)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="fill:#ffffff;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" d="M 9.5,578 C 7.96808,578 7,579.29203 7,580.5 v 9 c 0,1.20797 0.96808,2.5 2.5,2.5 h 9 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -9 C 8.53192,591 8,590.17765 8,589.5 8,588.82235 8.53192,588 9.5,588 h 9 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 4,1 c 1.37479,0 2.5,1.12521 2.5,2.5 0,1.18026 -0.86027,2.25 -2,2.44531 V 585 h -1 v -1.5 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 0.83435,0 1.5,-0.66565 1.5,-1.5 0,-0.83435 -0.66565,-1.5 -1.5,-1.5 -0.83435,0 -1.5,0.66565 -1.5,1.5 v 0.5 h -1 v -0.5 c 0,-1.37479 1.12521,-2.5 2.5,-2.5 z m -0.5,7 h 1 v 1 h -1 z m -3.5,3 a 0.50005,0.50005 0 1 0 0,1 h 9 a 0.50005,0.50005 0 1 0 0,-1 z" transform="translate(187,89.999995)" id="path13602" inkscape:connector-curvature="0"/>
- </g>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="g10909" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" transform="matrix(-1,0,0,1,1290,262.99979)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 968.5,168.00021 c 0.2761,3e-5 0.5,0.22387 0.5,0.5 v 13 c 0,0.27613 -0.2239,0.49997 -0.5,0.5 h -13 c -0.2761,-3e-5 -0.5,-0.22387 -0.5,-0.5 v -13 c 0,-0.27613 0.2239,-0.49997 0.5,-0.5 z m -10,2 c -0.8225,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z m 4.97656,3 c -0.1708,0.008 -0.32545,0.10335 -0.41015,0.25195 l -4,7 c -0.1903,0.33312 0.05,0.74758 0.43359,0.74805 h 8 c 0.3836,-4.7e-4 0.62389,-0.41493 0.43359,-0.74805 l -4,-7 c -0.093,-0.16311 -0.26943,-0.26042 -0.45703,-0.25195 z" id="path10907" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 220.50391,17 c -0.19102,-0.0013 -0.36611,0.106306 -0.45118,0.277344 l -3,6 C 216.88757,23.609565 217.12899,23.99963 217.5,24 h 6 c 0.37101,-3.7e-4 0.61243,-0.390435 0.44727,-0.722656 l -3,-6 C 220.86345,17.108826 220.69211,17.001644 220.50391,17 Z" id="path13331-5" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccc"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g20257" transform="translate(171,5.7999696e-6)">
- <path id="path20203" d="m -156.48438,137 c -0.27612,3e-5 -0.49996,0.22387 -0.5,0.5 v 0.5 h -1.5 c -0.32865,0.005 -0.51562,0.25232 -0.51562,0.5 v 0.5 h 2.51562 1 H -153 v -0.5 c 0,-0.25267 -0.14909,-0.49526 -0.48438,-0.5 h -1.5 v -0.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 3.48438,2 0.0156,0.5 v 0.5 h -6 v -0.5 L -159,139 h -1.48438 c -0.27612,3e-5 -0.49996,0.22387 -0.5,0.5 v 3.5 h 2.3086 a 1.50015,1.50015 0 0 1 0.16211,-0.0137 1.50015,1.50015 0 0 1 1.52929,1.69726 V 149 h 5.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <g id="g20226" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m -158.49414,143.99609 a 0.50005,0.50005 0 0 0 -0.0508,0.004 h -3.93946 a 0.50005,0.50005 0 1 0 0,1 h 2.79297 l -5.14648,5.14648 a 0.50005,0.50005 0 1 0 0.70703,0.70704 l 5.14648,-5.14649 V 148.5 a 0.50005,0.50005 0 1 0 1,0 v -3.94336 a 0.50005,0.50005 0 0 0 -0.50976,-0.56055 z" id="path20207" inkscape:connector-curvature="0"/>
+ <path
+ id="path15447"
+ d="m 539.5,10.000005 c -3.5682,0 -6.5,2.931819 -6.5,6.499999 0,1.42599 0.4737,2.74606 1.2637,3.822271 l -3.9707,3.9707 a 1.0001,1.0001 0 1 0 1.414,1.41406 l 3.9707,-3.9707 c 1.0762,0.78998 2.3963,1.26367 3.8223,1.26367 3.5682,0 6.5,-2.93182 6.5,-6.500001 0,-3.56818 -2.9318,-6.499999 -6.5,-6.499999 z m 0,2.999999 c 0.051,0 0.098,0.0135 0.1484,0.0156 a 0.50005,0.50005 0 0 1 0.3516,0.4844 v 2.5 h 2.5 a 0.50005,0.50005 0 0 1 0.4863,0.35742 0.50005,0.50005 0 0 1 0,0.002 c 0,0.0477 0.014,0.0925 0.014,0.14062 0,0.0488 -0.012,0.0942 -0.014,0.14258 A 0.50005,0.50005 0 0 1 542.5,17.000004 H 540 v 2.5 a 0.50005,0.50005 0 0 1 -0.3574,0.486331 c -0.048,0.002 -0.092,0.0137 -0.1406,0.0137 -0.049,0 -0.094,-0.0117 -0.1426,-0.0137 A 0.50005,0.50005 0 0 1 539,19.500004 v -2.5 h -2.5 a 0.50005,0.50005 0 0 1 -0.4863,-0.35742 0.50005,0.50005 0 0 1 0,-0.002 c 0,-0.0476 -0.014,-0.0925 -0.014,-0.14062 0,-0.0488 0.012,-0.0942 0.014,-0.14258 a 0.50005,0.50005 0 0 1 0.4863,-0.35738 h 2.5 v -2.5 a 0.50005,0.50005 0 0 1 0.3516,-0.48438 c 0.05,-0.002 0.098,-0.0156 0.1484,-0.0156 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:7.17647076;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 467.5,10.000005 a 0.50005006,0.50005006 0 0 0 -0.5,0.5 v 15 a 0.50005006,0.50005006 0 0 0 0.5,0.5 h 15 a 0.50005006,0.50005006 0 0 0 0.5,-0.5 v -15 a 0.50005006,0.50005006 0 0 0 -0.5,-0.5 z m 0.5,0.999999 h 4 v 4 h -4 z m 5,0 h 4 v 4 h -4 z m 5,0 h 4 v 4 h -4 z m -10,5 h 4 v 4.000001 h -4 z m 5,0 h 4 v 4.000001 h -4 z m 5,0 h 4 v 4.000001 h -4 z m -10,5.000001 h 4 v 4 h -4 z m 5,0 h 4 v 4 h -4 z m 5,0 h 4 v 4 h -4 z"
+ id="rect15343"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path15369"
+ d="m 449.75,12.000004 a 0.50005006,0.50005006 0 0 0 -0.4824,0.36914 l -3.25,12.000001 a 0.50005006,0.50005006 0 0 0 0.4824,0.63086 h 15 a 0.50005006,0.50005006 0 0 0 0.4824,-0.63086 l -3.25,-12.000001 a 0.50005006,0.50005006 0 0 0 -0.4824,-0.36914 z m 0.3828,1 h 2.086 l -0.2169,2 h -2.4121 z m 3.0938,0 h 1.5468 l 0.2168,2 h -1.9804 z m 2.5547,0 h 2.0859 l 0.541,2 h -2.4101 z m -6.461,3 h 2.5723 l -0.3262,3 h -3.0586 z m 3.5801,0 h 2.1992 l 0.3262,3 h -2.8516 z m 3.207,0 h 2.5723 l 0.8125,3 h -3.0586 z m -7.8711,4.000001 h 3.2207 l -0.4336,4 h -3.8711 z m 4.2305,0 h 3.0664 l 0.4356,4 h -3.9375 z m 4.0762,0 h 3.2207 l 1.084,4 h -3.8711 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <g
+ id="g14544"
+ transform="translate(41.999998,84.000005)"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 142.16211,494.00195 c -0.3928,-0.016 -0.79264,0.0268 -1.18555,0.13086 -1.05738,0.28017 -1.9221,0.97933 -2.44336,1.89453 -2.51672,-0.22477 -4.91162,1.1516 -5.97656,3.44727 -1.07271,2.31243 -0.56559,5.05473 1.26367,6.83008 1.82926,1.77534 4.58788,2.20194 6.86719,1.06054 2.20676,-1.10505 3.49065,-3.45007 3.27539,-5.89257 0.59118,-0.33407 1.10512,-0.8107 1.46875,-1.41797 0.83525,-1.3949 0.74131,-3.16186 -0.23633,-4.46094 -0.73322,-0.97431 -1.8548,-1.54394 -3.0332,-1.5918 z m -0.041,1 c 0.88379,0.0353 1.72432,0.4611 2.27539,1.19336 0.73477,0.97635 0.80549,2.29734 0.17774,3.34571 -0.62775,1.04836 -1.82561,1.61054 -3.0332,1.42382 a 0.50005006,0.50005006 0 1 0 -0.15235,0.98828 c 0.54314,0.084 1.08325,0.0449 1.59571,-0.0859 0.0521,1.92511 -0.99653,3.7274 -2.7461,4.60351 -1.90239,0.95265 -4.19394,0.59896 -5.7207,-0.88281 -1.52677,-1.48177 -1.94806,-3.76137 -1.05274,-5.69141 0.84423,-1.81987 2.6839,-2.93301 4.66602,-2.88086 -0.0398,0.15646 -0.0768,0.3137 -0.0977,0.47657 a 0.50013931,0.50013931 0 0 0 0.99219,0.12695 c 0.15491,-1.21208 1.02585,-2.20656 2.20703,-2.51953 0.2953,-0.0782 0.59408,-0.10943 0.88867,-0.0977 z"
+ transform="translate(-41.999998,-84.000005)"
+ id="path14540"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 241.25,624 c -0.36727,2.9e-4 -0.60893,0.38318 -0.45117,0.71484 l 2.25,4.75 c 0.18125,0.37923 0.72109,0.37923 0.90234,0 l 2.25,-4.75 C 246.35893,624.38318 246.11727,624.00029 245.75,624 Z"
+ id="path14837"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13609"
+ transform="translate(-187,-89.999995)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="fill:#ffffff;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="M 9.5,578 C 7.96808,578 7,579.29203 7,580.5 v 9 c 0,1.20797 0.96808,2.5 2.5,2.5 h 9 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -9 C 8.53192,591 8,590.17765 8,589.5 8,588.82235 8.53192,588 9.5,588 h 9 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 4,1 c 1.37479,0 2.5,1.12521 2.5,2.5 0,1.18026 -0.86027,2.25 -2,2.44531 V 585 h -1 v -1.5 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 0.83435,0 1.5,-0.66565 1.5,-1.5 0,-0.83435 -0.66565,-1.5 -1.5,-1.5 -0.83435,0 -1.5,0.66565 -1.5,1.5 v 0.5 h -1 v -0.5 c 0,-1.37479 1.12521,-2.5 2.5,-2.5 z m -0.5,7 h 1 v 1 h -1 z m -3.5,3 a 0.50005,0.50005 0 1 0 0,1 h 9 a 0.50005,0.50005 0 1 0 0,-1 z"
+ transform="translate(187,89.999995)"
+ id="path13602"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ id="g10909"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
+ transform="matrix(-1,0,0,1,1290,262.99979)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 968.5,168.00021 c 0.2761,3e-5 0.5,0.22387 0.5,0.5 v 13 c 0,0.27613 -0.2239,0.49997 -0.5,0.5 h -13 c -0.2761,-3e-5 -0.5,-0.22387 -0.5,-0.5 v -13 c 0,-0.27613 0.2239,-0.49997 0.5,-0.5 z m -10,2 c -0.8225,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z m 4.97656,3 c -0.1708,0.008 -0.32545,0.10335 -0.41015,0.25195 l -4,7 c -0.1903,0.33312 0.05,0.74758 0.43359,0.74805 h 8 c 0.3836,-4.7e-4 0.62389,-0.41493 0.43359,-0.74805 l -4,-7 c -0.093,-0.16311 -0.26943,-0.26042 -0.45703,-0.25195 z"
+ id="path10907"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 220.50391,17 c -0.19102,-0.0013 -0.36611,0.106306 -0.45118,0.277344 l -3,6 C 216.88757,23.609565 217.12899,23.99963 217.5,24 h 6 c 0.37101,-3.7e-4 0.61243,-0.390435 0.44727,-0.722656 l -3,-6 C 220.86345,17.108826 220.69211,17.001644 220.50391,17 Z"
+ id="path13331-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g20257"
+ transform="translate(171,5.7999696e-6)">
+ <path
+ id="path20203"
+ d="m -156.48438,137 c -0.27612,3e-5 -0.49996,0.22387 -0.5,0.5 v 0.5 h -1.5 c -0.32865,0.005 -0.51562,0.25232 -0.51562,0.5 v 0.5 h 2.51562 1 H -153 v -0.5 c 0,-0.25267 -0.14909,-0.49526 -0.48438,-0.5 h -1.5 v -0.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 3.48438,2 0.0156,0.5 v 0.5 h -6 v -0.5 L -159,139 h -1.48438 c -0.27612,3e-5 -0.49996,0.22387 -0.5,0.5 v 3.5 h 2.3086 a 1.50015,1.50015 0 0 1 0.16211,-0.0137 1.50015,1.50015 0 0 1 1.52929,1.69726 V 149 h 5.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g20226"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -158.49414,143.99609 a 0.50005,0.50005 0 0 0 -0.0508,0.004 h -3.93946 a 0.50005,0.50005 0 1 0 0,1 h 2.79297 l -5.14648,5.14648 a 0.50005,0.50005 0 1 0 0.70703,0.70704 l 5.14648,-5.14649 V 148.5 a 0.50005,0.50005 0 1 0 1,0 v -3.94336 a 0.50005,0.50005 0 0 0 -0.50976,-0.56055 z"
+ id="path20207"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g20243" transform="matrix(-1,0,0,1,-102.98438,5.7999696e-6)">
- <path id="path20230" transform="matrix(-1,0,0,1,-274.98438,0)" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m -144.5,139 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 9 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 2 c 0.10658,-1e-5 0.20011,-0.0408 0.28125,-0.0977 l -3.3418,-3.34179 a 1.50015,1.50015 0 1 1 2.1211,-2.1211 L -135,144.87891 V 139.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -1.48438 L -137,139.5 v 0.5 h -6 v -0.5 l 0.0156,-0.5 z m 5,-2 c 0.27613,3e-5 0.49997,0.22387 0.5,0.5 v 0.5 h 1.5 c 0.32865,0.005 0.51562,0.25232 0.51562,0.5 v 0.5 h -2.51562 -1 -2.48438 v -0.5 c 0,-0.25267 0.14909,-0.49526 0.48438,-0.5 h 1.5 v -0.5 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 z" inkscape:connector-curvature="0"/>
- <g transform="rotate(180,-150.98485,147.5)" id="g20236" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m -158.49414,143.99609 a 0.50005,0.50005 0 0 0 -0.0508,0.004 h -3.93946 a 0.50005,0.50005 0 1 0 0,1 h 2.79297 l -5.14648,5.14648 a 0.50005,0.50005 0 1 0 0.70703,0.70704 l 5.14648,-5.14649 V 148.5 a 0.50005,0.50005 0 1 0 1,0 v -3.94336 a 0.50005,0.50005 0 0 0 -0.50976,-0.56055 z" id="path20234" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g20243"
+ transform="matrix(-1,0,0,1,-102.98438,5.7999696e-6)">
+ <path
+ id="path20230"
+ transform="matrix(-1,0,0,1,-274.98438,0)"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -144.5,139 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 9 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 2 c 0.10658,-1e-5 0.20011,-0.0408 0.28125,-0.0977 l -3.3418,-3.34179 a 1.50015,1.50015 0 1 1 2.1211,-2.1211 L -135,144.87891 V 139.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -1.48438 L -137,139.5 v 0.5 h -6 v -0.5 l 0.0156,-0.5 z m 5,-2 c 0.27613,3e-5 0.49997,0.22387 0.5,0.5 v 0.5 h 1.5 c 0.32865,0.005 0.51562,0.25232 0.51562,0.5 v 0.5 h -2.51562 -1 -2.48438 v -0.5 c 0,-0.25267 0.14909,-0.49526 0.48438,-0.5 h 1.5 v -0.5 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 z"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="rotate(180,-150.98485,147.5)"
+ id="g20236"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -158.49414,143.99609 a 0.50005,0.50005 0 0 0 -0.0508,0.004 h -3.93946 a 0.50005,0.50005 0 1 0 0,1 h 2.79297 l -5.14648,5.14648 a 0.50005,0.50005 0 1 0 0.70703,0.70704 l 5.14648,-5.14649 V 148.5 a 0.50005,0.50005 0 1 0 1,0 v -3.94336 a 0.50005,0.50005 0 0 0 -0.50976,-0.56055 z"
+ id="path20234"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g20375" transform="matrix(-1,0,0,1,131,5.7999696e-6)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 48.492188,137 A 0.50005,0.50005 0 0 0 48,137.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,137 Z m 0,5 A 0.50005,0.50005 0 0 0 48,142.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,142 Z m 0,5 A 0.50005,0.50005 0 0 0 48,147.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,147 Z" id="path20369" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 51.515625,137 c -0.27612,3e-5 -0.49996,0.22387 -0.5,0.5 V 138 H 50 v 1 h 1.515625 1 H 55 v -0.5 c 0,-0.25267 -0.149085,-0.49526 -0.484375,-0.5 h -1.5 v -0.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z M 55,139 l 0.01563,0.5 V 140 H 50 v 9 h 6.515625 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -0.35938 l -2.580078,-2.58007 a 1.50015,1.50015 0 1 1 2.121094,-2.1211 l 0.458984,0.45899 V 139.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path20371" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 55.490234,143.99414 a 0.50005,0.50005 0 0 0 -0.349609,0.85938 L 60.287109,150 h -2.792968 a 0.50005,0.50005 0 1 0 0,1 h 3.939453 a 0.50005,0.50005 0 0 0 0.560547,-0.57031 V 146.5 a 0.50005,0.50005 0 1 0 -1,0 v 2.79297 l -5.146485,-5.14649 a 0.50005,0.50005 0 0 0 -0.357422,-0.15234 z" id="path20373" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g20474">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 48.492188,137 A 0.50005,0.50005 0 0 0 48,137.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,137 Z m 0,5 A 0.50005,0.50005 0 0 0 48,142.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,142 Z m 0,5 A 0.50005,0.50005 0 0 0 48,147.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,147 Z" id="path8290-6-5" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 51.509766,137 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 V 138 H 50 v 1 h 1.509766 1 2.515625 v -0.5 c 0,-0.24768 -0.186975,-0.495 -0.515625,-0.5 h -1.5 v -0.5 c -4e-5,-0.27613 -0.22388,-0.49997 -0.5,-0.5 z m 3.515625,2 -0.01563,0.5 V 140 H 50 v 9 h 4.009766 v -4.31641 c -0.12178,-0.91601 0.605587,-1.72326 1.529296,-1.69726 0.05424,0.002 0.10831,0.007 0.16211,0.0137 h 1.308594 v -3.5 c -4e-5,-0.27613 -0.22388,-0.49997 -0.5,-0.5 z" id="path20454" inkscape:connector-curvature="0"/>
- <g transform="matrix(-1,0,0,1,-102.97428,1.2445863e-6)" id="g20458" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m -158.49414,143.99609 a 0.50005,0.50005 0 0 0 -0.0508,0.004 h -3.93946 a 0.50005,0.50005 0 1 0 0,1 h 2.79297 l -5.14648,5.14648 a 0.50005,0.50005 0 1 0 0.70703,0.70704 l 5.14648,-5.14649 V 148.5 a 0.50005,0.50005 0 1 0 1,0 v -3.94336 a 0.50005,0.50005 0 0 0 -0.50976,-0.56055 z" id="path20456" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g20375"
+ transform="matrix(-1,0,0,1,131,5.7999696e-6)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 48.492188,137 A 0.50005,0.50005 0 0 0 48,137.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,137 Z m 0,5 A 0.50005,0.50005 0 0 0 48,142.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,142 Z m 0,5 A 0.50005,0.50005 0 0 0 48,147.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,147 Z"
+ id="path20369"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 51.515625,137 c -0.27612,3e-5 -0.49996,0.22387 -0.5,0.5 V 138 H 50 v 1 h 1.515625 1 H 55 v -0.5 c 0,-0.25267 -0.149085,-0.49526 -0.484375,-0.5 h -1.5 v -0.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z M 55,139 l 0.01563,0.5 V 140 H 50 v 9 h 6.515625 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -0.35938 l -2.580078,-2.58007 a 1.50015,1.50015 0 1 1 2.121094,-2.1211 l 0.458984,0.45899 V 139.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path20371"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 55.490234,143.99414 a 0.50005,0.50005 0 0 0 -0.349609,0.85938 L 60.287109,150 h -2.792968 a 0.50005,0.50005 0 1 0 0,1 h 3.939453 a 0.50005,0.50005 0 0 0 0.560547,-0.57031 V 146.5 a 0.50005,0.50005 0 1 0 -1,0 v 2.79297 l -5.146485,-5.14649 a 0.50005,0.50005 0 0 0 -0.357422,-0.15234 z"
+ id="path20373"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g20474">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 48.492188,137 A 0.50005,0.50005 0 0 0 48,137.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,137 Z m 0,5 A 0.50005,0.50005 0 0 0 48,142.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,142 Z m 0,5 A 0.50005,0.50005 0 0 0 48,147.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,147 Z"
+ id="path8290-6-5"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 51.509766,137 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 V 138 H 50 v 1 h 1.509766 1 2.515625 v -0.5 c 0,-0.24768 -0.186975,-0.495 -0.515625,-0.5 h -1.5 v -0.5 c -4e-5,-0.27613 -0.22388,-0.49997 -0.5,-0.5 z m 3.515625,2 -0.01563,0.5 V 140 H 50 v 9 h 4.009766 v -4.31641 c -0.12178,-0.91601 0.605587,-1.72326 1.529296,-1.69726 0.05424,0.002 0.10831,0.007 0.16211,0.0137 h 1.308594 v -3.5 c -4e-5,-0.27613 -0.22388,-0.49997 -0.5,-0.5 z"
+ id="path20454"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="matrix(-1,0,0,1,-102.97428,1.2445863e-6)"
+ id="g20458"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -158.49414,143.99609 a 0.50005,0.50005 0 0 0 -0.0508,0.004 h -3.93946 a 0.50005,0.50005 0 1 0 0,1 h 2.79297 l -5.14648,5.14648 a 0.50005,0.50005 0 1 0 0.70703,0.70704 l 5.14648,-5.14649 V 148.5 a 0.50005,0.50005 0 1 0 1,0 v -3.94336 a 0.50005,0.50005 0 0 0 -0.50976,-0.56055 z"
+ id="path20456"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g21550" transform="translate(-21.000002,189)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 471.54297,473 -3,3 h 1.20703 8.20703 l 3,-3 z m 0.41406,1 h 6.58594 l -1,1 h -6.58594 z m 5.54297,3 -9.00781,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 478,477.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -0.5,1 -0.008,8.00781 h -8 v -8.00195 z" transform="translate(21.000002,-189)" id="path21430" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 503,285.04297 -0.85352,0.85351 L 500,288.04297 v 9.41406 l 3,-3 z" id="path21432" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccc"/>
- </g>
- <g transform="translate(-243,336)" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g21571">
- <path inkscape:connector-curvature="0" id="rect21332" d="M 775.46875,284 C 774.66371,284 774,284.66371 774,285.46875 v 11.0625 c 0,0.80504 0.66371,1.46875 1.46875,1.46875 h 8.0625 C 784.33629,298 785,297.33629 785,296.53125 v -0.58203 c -1.68181,-0.24823 -3,-1.70468 -3,-3.44922 0,-1.74454 1.31819,-3.20099 3,-3.44922 v -3.58203 C 785,284.66371 784.33629,284 783.53125,284 Z M 775,285 h 9 v 3 h -9 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 785.5,295 c -1.37479,0 -2.5,-1.12521 -2.5,-2.5 0,-1.37479 1.12521,-2.5 2.5,-2.5 1.37479,0 2.5,1.12521 2.5,2.5 0,1.37479 -1.12521,2.5 -2.5,2.5 z" id="circle21336" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- </g>
- <g transform="translate(-285,336)" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g21575">
- <path sodipodi:nodetypes="sscssssccsssscccss" inkscape:connector-curvature="0" id="rect21315-8" d="m 797,284 c -1.09935,0 -2,0.90065 -2,2 v 2 8 c 0,1.09935 0.90065,2 2,2 h 7 c 1.09935,0 2,-0.90065 2,-2 v -0.5 c 0.01,-0.67616 -1.00956,-0.67616 -1,0 v 0.5 c 0,0.56265 -0.43735,1 -1,1 h -7 c -0.56265,0 -1,-0.43735 -1,-1 v -8 h 10 v -2 c 0,-1.09935 -0.90065,-2 -2,-2 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 806.5,294 c -1.37479,0 -2.5,-1.12521 -2.5,-2.5 0,-1.37479 1.12521,-2.5 2.5,-2.5 1.37479,0 2.5,1.12521 2.5,2.5 0,1.37479 -1.12521,2.5 -2.5,2.5 z" id="circle21317-8" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14854" transform="translate(-70.000007,21.000006)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 333.49219,94.992188 A 0.50005,0.50005 0 0 0 333,95.5 v 8.91016 l -4.68555,1.875 a 0.50050477,0.50050477 0 1 0 0.3711,0.92968 l 4.82812,-1.93164 7.82422,2.68946 a 0.50005,0.50005 0 1 0 0.32422,-0.94532 L 334,104.39258 V 95.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z" id="path14834" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 335.50586,95.435547 c -0.27842,-0.0032 -0.50585,0.221565 -0.50586,0.5 v 6.884763 c -1.3e-4,0.21757 0.14044,0.41026 0.34766,0.47657 l 6,1.92968 c 0.32275,0.10319 0.65252,-0.13772 0.65234,-0.47656 v -6.884766 c 1.3e-4,-0.217571 -0.14044,-0.410257 -0.34766,-0.476562 l -6,-1.929688 c -0.0474,-0.01505 -0.0968,-0.02295 -0.14648,-0.02344 z" id="path14836" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccc"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" transform="matrix(-1,0,0,1,551.0001,21.000006)" id="g14869">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 263.49219,94.992188 A 0.50005,0.50005 0 0 0 263,95.5 v 8.91016 l -4.68555,1.875 a 0.50050477,0.50050477 0 1 0 0.3711,0.92968 l 4.82812,-1.93164 7.82422,2.68946 a 0.50005,0.50005 0 1 0 0.32422,-0.94532 L 264,104.39258 V 95.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z" id="path14865" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 265.50586,95.435547 c -0.27842,-0.0032 -0.50585,0.221565 -0.50586,0.5 v 6.884763 c -1.3e-4,0.21757 0.14044,0.41026 0.34766,0.47657 l 6,1.92968 c 0.32275,0.10319 0.65252,-0.13772 0.65234,-0.47656 v -6.884766 c 1.3e-4,-0.217571 -0.14044,-0.410257 -0.34766,-0.476562 l -6,-1.929688 c -0.0474,-0.01505 -0.0968,-0.02295 -0.14648,-0.02344 z" id="path14867" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccc"/>
- </g>
- <g transform="translate(-6.3536743e-6,22.000006)" style="display:inline;fill:#ffffff;enable-background:new" id="g22568">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 307.51172,103 c -0.0577,-0.001 -0.11517,0.007 -0.16992,0.0254 l -6,2 c -0.45678,0.15155 -0.45678,0.79767 0,0.94922 l 6,2 c 0.10269,0.0343 0.21371,0.0343 0.3164,0 l 6,-2 c 0.45678,-0.15155 0.45678,-0.79767 0,-0.94922 l -6,-2 c -0.0473,-0.0157 -0.0967,-0.0243 -0.14648,-0.0254 z" id="path14873" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 307.49219,93.992188 A 0.50005,0.50005 0 0 0 307,94.5 v 5.88867 l -5.6582,1.88672 a 0.50028181,0.50028181 0 1 0 0.3164,0.94922 l 5.8418,-1.94727 5.8418,1.94727 a 0.50028181,0.50028181 0 1 0 0.3164,-0.94922 L 308,100.38867 V 94.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z" id="path14875" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g20896" transform="translate(-189,63.000005)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 161.50391,410 c -0.82054,0 -1.4961,0.67556 -1.4961,1.49609 0,0.82054 0.67556,1.4961 1.4961,1.4961 0.82053,0 1.49609,-0.67556 1.49609,-1.4961 C 163,410.67556 162.32444,410 161.50391,410 Z M 153.5,411 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 414 h 0.51562 2.49805 L 160,417.28711 c -1.65939,1.40974 -3.24134,2.62162 -3.98828,6.10742 -0.17787,0.67446 0.86019,0.89868 0.97656,0.21094 0.67528,-3.15139 1.92341,-4.0882 3.51758,-5.42774 1.58398,1.34059 2.83152,2.27747 3.51953,5.42969 0.13318,0.66658 1.13543,0.44609 0.97656,-0.21484 -0.76273,-3.49457 -2.35104,-4.70351 -4.00195,-6.11719 L 161.01367,414 h 2.2168 3.28515 c 0.6573,-0.009 0.6573,-0.9907 0,-1 h -3.04296 c -0.45945,0.59659 -1.17125,0.99219 -1.96875,0.99219 -0.79751,0 -1.50931,-0.3956 -1.96875,-0.99219 H 157.51562 157 v -1.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z" transform="translate(189,-63.000005)" id="path20782" inkscape:connector-curvature="0"/>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" transform="translate(188,-63)" id="g20817" style="fill:#ffffff"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.4;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 285.49219,220.9707 a 0.50005,0.50005 0 0 0 -0.4336,0.29688 l -4,9 a 0.50005,0.50005 0 0 0 0.10352,0.55664 l 4,4 a 0.50005,0.50005 0 0 0 0.70703,0 l 4,-4 a 0.50005,0.50005 0 0 0 0.10352,-0.55664 l -4,-9 a 0.50005,0.50005 0 0 0 -0.48047,-0.29688 z m 0.0234,1.73047 3.4043,7.65821 -3.4043,3.40429 -3.40429,-3.40429 z" id="path20963" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" transform="translate(-189,168)" id="g21028">
- <path inkscape:connector-curvature="0" id="path21020" d="m 342.5,348 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" sodipodi:nodetypes="ccccccccc"/>
- <g id="g21026" transform="translate(188,-63)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96" style="fill:#ffffff">
- <path id="circle21024" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 162.50391,410 c -0.82054,0 -1.4961,0.67556 -1.4961,1.49609 0,0.82054 0.67556,1.4961 1.4961,1.4961 0.82053,0 1.49609,-0.67556 1.49609,-1.4961 C 164,410.67556 163.32444,410 162.50391,410 Z M 159.5,413 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.01562 0.49805 L 161,417.28711 c -1.65939,1.40974 -3.24134,2.62162 -3.98828,6.10742 -0.17787,0.67446 0.86019,0.89868 0.97656,0.21094 0.67528,-3.15139 1.92341,-4.0882 3.51758,-5.42774 1.58398,1.34059 2.83152,2.27747 3.51953,5.42969 0.13318,0.66658 1.13543,0.44609 0.97656,-0.21484 -0.76273,-3.49457 -2.35104,-4.70351 -4.00195,-6.11719 L 162.01367,414 h 2.2168 3.28515 c 0.6573,-0.009 0.6573,-0.9907 0,-1 h -3.04296 c -0.45945,0.59659 -1.17125,0.99219 -1.96875,0.99219 -0.79751,0 -1.50931,-0.3956 -1.96875,-0.99219 h -0.0195 z" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g21550"
+ transform="translate(-21.000002,189)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 471.54297,473 -3,3 h 1.20703 8.20703 l 3,-3 z m 0.41406,1 h 6.58594 l -1,1 h -6.58594 z m 5.54297,3 -9.00781,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 478,477.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -0.5,1 -0.008,8.00781 h -8 v -8.00195 z"
+ transform="translate(21.000002,-189)"
+ id="path21430"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 503,285.04297 -0.85352,0.85351 L 500,288.04297 v 9.41406 l 3,-3 z"
+ id="path21432"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc" />
+ </g>
+ <g
+ transform="translate(-243,336)"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g21571">
+ <path
+ inkscape:connector-curvature="0"
+ id="rect21332"
+ d="M 775.46875,284 C 774.66371,284 774,284.66371 774,285.46875 v 11.0625 c 0,0.80504 0.66371,1.46875 1.46875,1.46875 h 8.0625 C 784.33629,298 785,297.33629 785,296.53125 v -0.58203 c -1.68181,-0.24823 -3,-1.70468 -3,-3.44922 0,-1.74454 1.31819,-3.20099 3,-3.44922 v -3.58203 C 785,284.66371 784.33629,284 783.53125,284 Z M 775,285 h 9 v 3 h -9 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 785.5,295 c -1.37479,0 -2.5,-1.12521 -2.5,-2.5 0,-1.37479 1.12521,-2.5 2.5,-2.5 1.37479,0 2.5,1.12521 2.5,2.5 0,1.37479 -1.12521,2.5 -2.5,2.5 z"
+ id="circle21336"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
+ <g
+ transform="translate(-285,336)"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g21575">
+ <path
+ sodipodi:nodetypes="sscssssccsssscccss"
+ inkscape:connector-curvature="0"
+ id="rect21315-8"
+ d="m 797,284 c -1.09935,0 -2,0.90065 -2,2 v 2 8 c 0,1.09935 0.90065,2 2,2 h 7 c 1.09935,0 2,-0.90065 2,-2 v -0.5 c 0.01,-0.67616 -1.00956,-0.67616 -1,0 v 0.5 c 0,0.56265 -0.43735,1 -1,1 h -7 c -0.56265,0 -1,-0.43735 -1,-1 v -8 h 10 v -2 c 0,-1.09935 -0.90065,-2 -2,-2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 806.5,294 c -1.37479,0 -2.5,-1.12521 -2.5,-2.5 0,-1.37479 1.12521,-2.5 2.5,-2.5 1.37479,0 2.5,1.12521 2.5,2.5 0,1.37479 -1.12521,2.5 -2.5,2.5 z"
+ id="circle21317-8"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14854"
+ transform="translate(-70.000007,21.000006)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 333.49219,94.992188 A 0.50005,0.50005 0 0 0 333,95.5 v 8.91016 l -4.68555,1.875 a 0.50050477,0.50050477 0 1 0 0.3711,0.92968 l 4.82812,-1.93164 7.82422,2.68946 a 0.50005,0.50005 0 1 0 0.32422,-0.94532 L 334,104.39258 V 95.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z"
+ id="path14834"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 335.50586,95.435547 c -0.27842,-0.0032 -0.50585,0.221565 -0.50586,0.5 v 6.884763 c -1.3e-4,0.21757 0.14044,0.41026 0.34766,0.47657 l 6,1.92968 c 0.32275,0.10319 0.65252,-0.13772 0.65234,-0.47656 v -6.884766 c 1.3e-4,-0.217571 -0.14044,-0.410257 -0.34766,-0.476562 l -6,-1.929688 c -0.0474,-0.01505 -0.0968,-0.02295 -0.14648,-0.02344 z"
+ id="path14836"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccc" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="matrix(-1,0,0,1,551.0001,21.000006)"
+ id="g14869">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 263.49219,94.992188 A 0.50005,0.50005 0 0 0 263,95.5 v 8.91016 l -4.68555,1.875 a 0.50050477,0.50050477 0 1 0 0.3711,0.92968 l 4.82812,-1.93164 7.82422,2.68946 a 0.50005,0.50005 0 1 0 0.32422,-0.94532 L 264,104.39258 V 95.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z"
+ id="path14865"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 265.50586,95.435547 c -0.27842,-0.0032 -0.50585,0.221565 -0.50586,0.5 v 6.884763 c -1.3e-4,0.21757 0.14044,0.41026 0.34766,0.47657 l 6,1.92968 c 0.32275,0.10319 0.65252,-0.13772 0.65234,-0.47656 v -6.884766 c 1.3e-4,-0.217571 -0.14044,-0.410257 -0.34766,-0.476562 l -6,-1.929688 c -0.0474,-0.01505 -0.0968,-0.02295 -0.14648,-0.02344 z"
+ id="path14867"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccc" />
+ </g>
+ <g
+ transform="translate(-6.3536743e-6,22.000006)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22568">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 307.51172,103 c -0.0577,-0.001 -0.11517,0.007 -0.16992,0.0254 l -6,2 c -0.45678,0.15155 -0.45678,0.79767 0,0.94922 l 6,2 c 0.10269,0.0343 0.21371,0.0343 0.3164,0 l 6,-2 c 0.45678,-0.15155 0.45678,-0.79767 0,-0.94922 l -6,-2 c -0.0473,-0.0157 -0.0967,-0.0243 -0.14648,-0.0254 z"
+ id="path14873"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 307.49219,93.992188 A 0.50005,0.50005 0 0 0 307,94.5 v 5.88867 l -5.6582,1.88672 a 0.50028181,0.50028181 0 1 0 0.3164,0.94922 l 5.8418,-1.94727 5.8418,1.94727 a 0.50028181,0.50028181 0 1 0 0.3164,-0.94922 L 308,100.38867 V 94.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z"
+ id="path14875"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g20896"
+ transform="translate(-189,63.000005)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 161.50391,410 c -0.82054,0 -1.4961,0.67556 -1.4961,1.49609 0,0.82054 0.67556,1.4961 1.4961,1.4961 0.82053,0 1.49609,-0.67556 1.49609,-1.4961 C 163,410.67556 162.32444,410 161.50391,410 Z M 153.5,411 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 414 h 0.51562 2.49805 L 160,417.28711 c -1.65939,1.40974 -3.24134,2.62162 -3.98828,6.10742 -0.17787,0.67446 0.86019,0.89868 0.97656,0.21094 0.67528,-3.15139 1.92341,-4.0882 3.51758,-5.42774 1.58398,1.34059 2.83152,2.27747 3.51953,5.42969 0.13318,0.66658 1.13543,0.44609 0.97656,-0.21484 -0.76273,-3.49457 -2.35104,-4.70351 -4.00195,-6.11719 L 161.01367,414 h 2.2168 3.28515 c 0.6573,-0.009 0.6573,-0.9907 0,-1 h -3.04296 c -0.45945,0.59659 -1.17125,0.99219 -1.96875,0.99219 -0.79751,0 -1.50931,-0.3956 -1.96875,-0.99219 H 157.51562 157 v -1.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z"
+ transform="translate(189,-63.000005)"
+ id="path20782"
+ inkscape:connector-curvature="0" />
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="translate(188,-63)"
+ id="g20817"
+ style="fill:#ffffff" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.4;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 285.49219,220.9707 a 0.50005,0.50005 0 0 0 -0.4336,0.29688 l -4,9 a 0.50005,0.50005 0 0 0 0.10352,0.55664 l 4,4 a 0.50005,0.50005 0 0 0 0.70703,0 l 4,-4 a 0.50005,0.50005 0 0 0 0.10352,-0.55664 l -4,-9 a 0.50005,0.50005 0 0 0 -0.48047,-0.29688 z m 0.0234,1.73047 3.4043,7.65821 -3.4043,3.40429 -3.40429,-3.40429 z"
+ id="path20963"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(-189,168)"
+ id="g21028">
+ <path
+ inkscape:connector-curvature="0"
+ id="path21020"
+ d="m 342.5,348 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ sodipodi:nodetypes="ccccccccc" />
+ <g
+ id="g21026"
+ transform="translate(188,-63)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ style="fill:#ffffff">
+ <path
+ id="circle21024"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 162.50391,410 c -0.82054,0 -1.4961,0.67556 -1.4961,1.49609 0,0.82054 0.67556,1.4961 1.4961,1.4961 0.82053,0 1.49609,-0.67556 1.49609,-1.4961 C 164,410.67556 163.32444,410 162.50391,410 Z M 159.5,413 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.01562 0.49805 L 161,417.28711 c -1.65939,1.40974 -3.24134,2.62162 -3.98828,6.10742 -0.17787,0.67446 0.86019,0.89868 0.97656,0.21094 0.67528,-3.15139 1.92341,-4.0882 3.51758,-5.42774 1.58398,1.34059 2.83152,2.27747 3.51953,5.42969 0.13318,0.66658 1.13543,0.44609 0.97656,-0.21484 -0.76273,-3.49457 -2.35104,-4.70351 -4.00195,-6.11719 L 162.01367,414 h 2.2168 3.28515 c 0.6573,-0.009 0.6573,-0.9907 0,-1 h -3.04296 c -0.45945,0.59659 -1.17125,0.99219 -1.96875,0.99219 -0.79751,0 -1.50931,-0.3956 -1.96875,-0.99219 h -0.0195 z"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" transform="translate(-84.000002,-62.999995)" id="g21409">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 269.13867,410.0332 c -0.49613,-0.0451 -1.03862,0.15972 -1.49219,0.61328 l -8.5,8.5 c -0.0639,0.0642 -0.10909,0.14453 -0.13086,0.23243 l -1,4 c -0.0904,0.36537 0.2401,0.69582 0.60547,0.60547 l 4,-1 c 0.0879,-0.0218 0.16823,-0.067 0.23243,-0.13086 l 8.5,-8.5 c 0.45356,-0.45357 0.65838,-0.99606 0.61328,-1.49219 -0.0451,-0.49613 -0.30436,-0.90592 -0.61328,-1.21485 l -1,-1 c -0.30893,-0.30892 -0.71872,-0.56817 -1.21485,-0.61328 z m -1.88867,2.42383 2.29297,2.29297 -7.29883,7.29883 -3.05859,0.76562 0.76562,-3.05859 z" transform="translate(84.000002,62.999995)" id="path21405" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccsccccccccc"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" transform="translate(-21.000001)" id="g12839">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 353.13867,473.0332 c -0.49613,-0.0451 -1.03862,0.15972 -1.49219,0.61328 l -0.75,0.75 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 3,3 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 0.75,-0.75 c 0.45356,-0.45357 0.65838,-0.99606 0.61328,-1.49219 -0.0451,-0.49613 -0.30436,-0.90592 -0.61328,-1.21485 l -1,-1 c -0.30893,-0.30892 -0.71872,-0.56817 -1.21485,-0.61328 z m -3.39644,2.7168 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -6.25,6.25 c -0.0639,0.0642 -0.10909,0.14453 -0.13086,0.23243 l -1,4 c -0.0904,0.36537 0.2401,0.69582 0.60547,0.60547 l 4,-1 c 0.0879,-0.0218 0.16823,-0.067 0.23243,-0.13086 l 6.25,-6.25 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -3,-3 c -0.0957,-0.0957 -0.22605,-0.14856 -0.36137,-0.14648 z" id="path12837" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccscccccccccccccccc"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g14495" transform="matrix(-1,0,0,1,718.99999,4.4999696e-6)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 363.49414,141.99414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 7.15235,7.15234 H 367.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 0 0 0.006,0 0.50005,0.50005 0 0 0 0.0937,-0.0117 0.50005,0.50005 0 0 0 0.0488,-0.0117 0.50005,0.50005 0 0 0 0.3515,-0.54301 v -3.93359 a 0.50005,0.50005 0 1 0 -1,0 v 2.78711 l -7.14648,-7.14649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z" id="path14485" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 368.49414,137 a 0.50005,0.50005 0 0 0 -0.0937,0.01 0.50005,0.50005 0 0 0 -0.0488,0.0117 A 0.50005,0.50005 0 0 0 368,137.56445 V 141.5 a 0.50005,0.50005 0 1 0 1,0 v -2.78711 l 7.14648,7.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 L 369.70117,138 H 372.5 a 0.50005,0.50005 0 1 0 0,-1 h -4 a 0.50005,0.50005 0 0 0 -0.006,0 z" id="path14491" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g19653" transform="translate(-628,42.000005)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 143.13867,515.0332 c -0.49613,-0.0451 -1.03862,0.15972 -1.49219,0.61328 l -1.75,1.75 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 3,3 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 1.75,-1.75 c 0.45356,-0.45357 0.65838,-0.99606 0.61328,-1.49219 -0.0451,-0.49613 -0.30436,-0.90592 -0.61328,-1.21485 l -1,-1 c -0.30893,-0.30892 -0.71872,-0.56817 -1.21485,-0.61328 z m -4.39648,3.7168 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 l -0.25,0.25 a 0.50005,0.50005 0 0 0 0,0.70704 l 3,3 a 0.50005,0.50005 0 0 0 0.70704,0 l 0.25,-0.25 a 0.50005,0.50005 0 0 0 0,-0.70704 l -3,-3 A 0.50005,0.50005 0 0 0 138.74219,518.75 Z m -1.25196,2.24609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -4.25,4.25 c -0.83838,0.83839 -1.06879,1.7573 -0.80273,2.4668 C 132.35981,528.57278 133.04167,529 133.75,529 H 138 c 1.00042,0 2,-0.79793 2,-2 v -3.5 a 0.50005,0.50005 0 1 0 -1,0 v 3.5 c 0,0.66505 -0.50442,1 -1,1 h -4.25 c -0.29167,0 -0.60981,-0.19778 -0.71875,-0.48828 -0.10894,-0.2905 -0.0893,-0.74659 0.57227,-1.4082 l 4.25,-4.25 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z" transform="translate(628,-42.000005)" id="path19637" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" transform="translate(418,-4.7064591e-6)" id="g19647"/>
- </g>
- <path inkscape:connector-curvature="0" id="path20483" d="m 75.999998,620 c -3.860077,0 -7,3.13991 -7,7 0,3.86009 3.139924,7 7,7 3.860076,0 7,-3.13991 7,-7 0,-3.86009 -3.139923,-7 -7,-7 z m 2.990234,2.98633 a 1.0001,1.0001 0 0 1 0.716797,1.7207 L 77.41406,627 l 2.292969,2.29297 a 1.0001,1.0001 0 1 1 -1.414062,1.41406 l -2.292969,-2.29297 -2.292969,2.29297 a 1.0001,1.0001 0 1 1 -1.414062,-1.41406 L 74.585936,627 72.292967,624.70703 a 1.0001,1.0001 0 0 1 0.697265,-1.7168 1.0001,1.0001 0 0 1 0.716797,0.30274 l 2.292969,2.29297 2.292969,-2.29297 a 1.0001,1.0001 0 0 1 0.697265,-0.30664 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <g transform="translate(-1.8536743e-6,3.4999696e-6)" inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="g20495" style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
- <g transform="translate(-189,588)" id="g20491" style="fill:#ffffff"/>
- <path id="path20493" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 34,622 c -1.783333,0 -3,1.5 -3,3 h 2 c 0,-0.5 0.283333,-1 1,-1 0.716667,0 1,0.5 1,1 0,0.24702 -0.03644,0.30082 -0.117188,0.41016 -0.08074,0.10934 -0.253932,0.25966 -0.513671,0.4707 C 33.849662,626.30294 33,627.16667 33,628.5 v 0.5 h 2 v -0.5 c 0,-0.66667 0.150338,-0.67794 0.630859,-1.06836 0.240261,-0.19521 0.567072,-0.43551 0.861329,-0.83398 C 36.786444,626.19918 37,625.62798 37,625 c 0,-1.5 -1.216667,-3 -3,-3 z m -1,8.00009 h 2 v 2 H 33 Z M 34,620 c -3.86007,0 -7,3.13991 -7,7 0,3.86009 3.13993,7 7,7 3.86008,0 7,-3.13991 7,-7 0,-3.86009 -3.13992,-7 -7,-7 z m 0,1 c 3.31964,0 6,2.68035 6,6 0,3.31965 -2.68036,6 -6,6 -3.31963,0 -6,-2.68035 -6,-6 0,-3.31965 2.68037,-6 6,-6 z" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 55.011717,620 c -0.689946,-0.004 -1.325726,0.38513 -1.634766,1.00195 l -5.1875,10.3711 c -0.594248,1.18749 0.293094,2.62623 1.621094,2.62695 h 10.378906 c 1.327265,-7.2e-4 2.213373,-1.43788 1.621094,-2.625 l -5.1875,-10.37305 C 56.317741,620.39258 55.693326,620.0046 55.011717,620 Z m -1.011719,3 h 2 v 6 h -2 z m 0,7 h 2 v 2 h -2 z" id="path20558" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="g20538" transform="rotate(-180,317.50525,417)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 331.50586,410 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path20529" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 323.95117,412.94531 c -0.75176,0.0616 -1.47366,0.37015 -2.05469,0.95117 -1.16941,1.16942 -1.16162,2.91055 -0.28906,4.30664 0.87256,1.3961 2.57397,2.52709 4.83399,2.79297 C 329.94786,421.40861 333,419.08206 333,416 v -0.5 a 0.50005,0.50005 0 1 0 -1,0 v 0.5 c 0,2.41794 -2.42686,4.35855 -5.44141,4.00391 -1.98998,-0.23412 -3.41357,-1.22813 -4.10351,-2.33203 -0.68994,-1.10391 -0.68215,-2.23778 0.14844,-3.06836 0.83795,-0.83796 1.98844,-0.89361 3.08398,-0.26368 1.09554,0.62994 2.08242,1.9799 2.31641,3.96875 a 0.50005,0.50005 0 1 0 0.99218,-0.11718 c -0.26601,-2.26115 -1.40413,-3.91119 -2.80859,-4.71875 -0.70223,-0.40379 -1.48457,-0.58895 -2.23633,-0.52735 z m 3.54102,9.04883 a 0.50005,0.50005 0 0 0 -0.37696,0.1875 C 326.73975,422.63463 325.92671,423 325,423 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 c 1.17529,0 2.25213,-0.41841 2.88477,-1.18164 a 0.50005,0.50005 0 0 0 -0.39258,-0.82422 z" id="path20536" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 331,410 c -2.22355,0 -4.0767,1.3002 -5.12305,3.18945 0.93682,-0.21724 1.92473,-0.28964 2.92578,-0.17187 0.40221,0.0473 0.78928,0.12403 1.16797,0.21484 C 330.29795,413.09146 330.64197,413 331,413 h 0.5 c 2.02848,0.0287 2.02848,-3.02869 0,-3 z m -3.05859,3.95898 c -3.69856,-0.0756 -6.93164,2.52898 -6.93164,6.04102 v 1.5 c -0.0287,2.02848 3.02869,2.02848 3,0 V 420 c 0,-1.75382 1.80351,-3.30654 4.32617,-3.00977 0.37314,0.0439 0.71883,0.11732 1.03711,0.21485 1.3077,0.40071 2.14372,1.21003 2.47656,1.91211 0.22905,0.48316 0.34095,1.19341 -0.0996,1.63281 -0.4946,0.4933 -1.25,0.34848 -1.89258,-0.0527 -0.70436,-0.44 -1.43726,-1.36047 -1.75195,-2.71875 -0.21041,-0.0194 -0.41646,-0.0328 -0.60742,-0.0234 -1.06865,0.0527 -1.81638,0.53365 -2.19727,1.13086 0.52848,1.85114 1.6077,3.30531 2.9668,4.15429 1.61509,1.00892 3.82413,1.05951 5.33594,-0.2539 0.0754,-0.0514 0.14605,-0.10959 0.21093,-0.17383 0.0562,-0.057 0.10785,-0.11837 0.1543,-0.18359 1.19162,-1.34198 1.31147,-3.2788 0.5918,-4.79688 -0.75194,-1.58612 -2.28118,-2.87289 -4.3086,-3.49414 -0.49344,-0.15121 -1.01745,-0.26354 -1.5664,-0.32812 -0.2499,-0.0294 -0.49757,-0.0457 -0.74414,-0.0508 z" id="path20562" inkscape:connector-curvature="0" sodipodi:nodetypes="scccsccscsccsccccccccccccccccc"/>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g20665">
- <path id="path20610" d="m 348.51367,409.98828 a 1.50015,1.50015 0 0 0 -0.80859,0.24024 C 343.03811,413.14537 342,418.71429 342,422.5 a 1.50015,1.50015 0 1 0 3,0 c 0,-0.89832 0.0865,-1.89371 0.26758,-2.9043 -0.25845,-3.40076 0.85029,-7.04233 3.87109,-9.4707 a 1.50015,1.50015 0 0 0 -0.625,-0.13672 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.4;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path20608" d="m 351.51367,409.98828 a 1.50015,1.50015 0 0 0 -0.80859,0.24024 c -4.71461,2.94662 -5.33528,8.77693 -3.58399,12.86328 a 1.5005399,1.5005399 0 1 0 2.75782,-1.1836 c -0.38431,-0.89672 -0.59027,-1.91481 -0.62891,-2.95117 -0.67215,-3.14692 0.29131,-6.6121 2.9043,-8.82422 a 1.50015,1.50015 0 0 0 -0.64063,-0.14453 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" id="path20592" d="m 354.51367,409.98828 a 1.50015,1.50015 0 0 0 -0.80859,0.24024 c -4.9147,3.07168 -4.9147,10.47128 0,13.54296 a 1.50015,1.50015 0 1 0 1.58984,-2.54296 c -3.0853,-1.92832 -3.0853,-6.52872 0,-8.45704 a 1.50015,1.50015 0 0 0 -0.78125,-2.7832 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g22444" transform="translate(-1.8536743e-6,-41.999995)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 292.5,305 -9.00781,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.50781 l 0.0391,2.49219 1,-0.0156 -0.0312,-1.98438 8,-0.008 -0.006,8.01172 -2,0.0195 0.01,1 2.49414,-0.0234 a 0.50005,0.50005 0 0 0 0.49414,-0.5 L 293,305.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z" id="path22408" inkscape:connector-curvature="0"/>
- <path id="path22122" d="m 279,309 v 2 h 2 v -2 z m 2,2 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 2,0 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 0,2 v 2 h 2 v -2 z m 0,2 h -2 v 2 h 2 z m 0,2 v 2 h 2 v -2 z m -2,0 h -2 v 2 h 2 z m -2,0 v -2 h -2 v 2 z m -2,0 h -2 v 2 h 2 z m 0,-2 v -2 h -2 v 2 z m 2,0 h 2 v -2 h -2 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" transform="translate(422.00881,-131.00682)" id="g22132">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m -76.509766,394.00586 a 0.50005,0.50005 0 0 0 -0.486328,0.38867 l -3.011718,12.98828 a 0.50005,0.50005 0 0 0 0.486328,0.61328 h 9.974609 a 0.50005,0.50005 0 0 0 0.488281,-0.38476 l 3.03711,-12.99024 a 0.50005,0.50005 0 0 0 -0.488282,-0.61523 z m 0.398438,1 h 3.974609 l -1.154297,5 h -3.978515 z m 5,0 h 3.972656 l -1.169922,5 h -3.955078 z m -6.390625,6 h 3.980469 l -1.382813,5.99023 h -3.986328 z m 5.005859,0 h 3.953125 l -1.40039,5.99023 h -3.933594 z" id="path22130" inkscape:connector-curvature="0"/>
- </g>
- <g id="g22232" transform="translate(-42.000002,-20.999995)" style="display:inline;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 145.49023,283.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -3,3 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -3,3 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -3,3 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -3,3 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z" id="path22209" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 132.5,284 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -6 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 3 v 5 h -3 z m 6.5,8 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 6 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 5 v 3 h -5 z" id="path22212" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-231,-83.999995)" style="display:inline;fill:#ffffff;enable-background:new" id="g26345">
- <g id="g22592" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 300.5,326 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z" id="path22548" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 307.49219,326.99219 A 0.50005,0.50005 0 0 0 307,327.5 v 5.5 h -5.5 a 0.50005,0.50005 0 1 0 0,1 h 5.5 v 2 h -5.5 a 0.50005,0.50005 0 1 0 0,1 h 5.5 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 337 h 2 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 337 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 311 v -2 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 311 v -5.5 a 0.50005,0.50005 0 1 0 -1,0 v 5.5 h -2 v -5.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 308,334 h 2 v 2 h -2 z" id="path22585" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="translate(-84.000002,-62.999995)"
+ id="g21409">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 269.13867,410.0332 c -0.49613,-0.0451 -1.03862,0.15972 -1.49219,0.61328 l -8.5,8.5 c -0.0639,0.0642 -0.10909,0.14453 -0.13086,0.23243 l -1,4 c -0.0904,0.36537 0.2401,0.69582 0.60547,0.60547 l 4,-1 c 0.0879,-0.0218 0.16823,-0.067 0.23243,-0.13086 l 8.5,-8.5 c 0.45356,-0.45357 0.65838,-0.99606 0.61328,-1.49219 -0.0451,-0.49613 -0.30436,-0.90592 -0.61328,-1.21485 l -1,-1 c -0.30893,-0.30892 -0.71872,-0.56817 -1.21485,-0.61328 z m -1.88867,2.42383 2.29297,2.29297 -7.29883,7.29883 -3.05859,0.76562 0.76562,-3.05859 z"
+ transform="translate(84.000002,62.999995)"
+ id="path21405"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccsccccccccc" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="translate(-21.000001)"
+ id="g12839">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 353.13867,473.0332 c -0.49613,-0.0451 -1.03862,0.15972 -1.49219,0.61328 l -0.75,0.75 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 3,3 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 0.75,-0.75 c 0.45356,-0.45357 0.65838,-0.99606 0.61328,-1.49219 -0.0451,-0.49613 -0.30436,-0.90592 -0.61328,-1.21485 l -1,-1 c -0.30893,-0.30892 -0.71872,-0.56817 -1.21485,-0.61328 z m -3.39644,2.7168 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -6.25,6.25 c -0.0639,0.0642 -0.10909,0.14453 -0.13086,0.23243 l -1,4 c -0.0904,0.36537 0.2401,0.69582 0.60547,0.60547 l 4,-1 c 0.0879,-0.0218 0.16823,-0.067 0.23243,-0.13086 l 6.25,-6.25 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -3,-3 c -0.0957,-0.0957 -0.22605,-0.14856 -0.36137,-0.14648 z"
+ id="path12837"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccscccccccccccccccc" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g14495"
+ transform="matrix(-1,0,0,1,718.99999,4.4999696e-6)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 363.49414,141.99414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 7.15235,7.15234 H 367.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 0 0 0.006,0 0.50005,0.50005 0 0 0 0.0937,-0.0117 0.50005,0.50005 0 0 0 0.0488,-0.0117 0.50005,0.50005 0 0 0 0.3515,-0.54301 v -3.93359 a 0.50005,0.50005 0 1 0 -1,0 v 2.78711 l -7.14648,-7.14649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path14485"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 368.49414,137 a 0.50005,0.50005 0 0 0 -0.0937,0.01 0.50005,0.50005 0 0 0 -0.0488,0.0117 A 0.50005,0.50005 0 0 0 368,137.56445 V 141.5 a 0.50005,0.50005 0 1 0 1,0 v -2.78711 l 7.14648,7.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 L 369.70117,138 H 372.5 a 0.50005,0.50005 0 1 0 0,-1 h -4 a 0.50005,0.50005 0 0 0 -0.006,0 z"
+ id="path14491"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g19653"
+ transform="translate(-628,42.000005)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 143.13867,515.0332 c -0.49613,-0.0451 -1.03862,0.15972 -1.49219,0.61328 l -1.75,1.75 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 3,3 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 1.75,-1.75 c 0.45356,-0.45357 0.65838,-0.99606 0.61328,-1.49219 -0.0451,-0.49613 -0.30436,-0.90592 -0.61328,-1.21485 l -1,-1 c -0.30893,-0.30892 -0.71872,-0.56817 -1.21485,-0.61328 z m -4.39648,3.7168 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 l -0.25,0.25 a 0.50005,0.50005 0 0 0 0,0.70704 l 3,3 a 0.50005,0.50005 0 0 0 0.70704,0 l 0.25,-0.25 a 0.50005,0.50005 0 0 0 0,-0.70704 l -3,-3 A 0.50005,0.50005 0 0 0 138.74219,518.75 Z m -1.25196,2.24609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -4.25,4.25 c -0.83838,0.83839 -1.06879,1.7573 -0.80273,2.4668 C 132.35981,528.57278 133.04167,529 133.75,529 H 138 c 1.00042,0 2,-0.79793 2,-2 v -3.5 a 0.50005,0.50005 0 1 0 -1,0 v 3.5 c 0,0.66505 -0.50442,1 -1,1 h -4.25 c -0.29167,0 -0.60981,-0.19778 -0.71875,-0.48828 -0.10894,-0.2905 -0.0893,-0.74659 0.57227,-1.4082 l 4.25,-4.25 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
+ transform="translate(628,-42.000005)"
+ id="path19637"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="translate(418,-4.7064591e-6)"
+ id="g19647" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ id="path20483"
+ d="m 75.999998,620 c -3.860077,0 -7,3.13991 -7,7 0,3.86009 3.139924,7 7,7 3.860076,0 7,-3.13991 7,-7 0,-3.86009 -3.139923,-7 -7,-7 z m 2.990234,2.98633 a 1.0001,1.0001 0 0 1 0.716797,1.7207 L 77.41406,627 l 2.292969,2.29297 a 1.0001,1.0001 0 1 1 -1.414062,1.41406 l -2.292969,-2.29297 -2.292969,2.29297 a 1.0001,1.0001 0 1 1 -1.414062,-1.41406 L 74.585936,627 72.292967,624.70703 a 1.0001,1.0001 0 0 1 0.697265,-1.7168 1.0001,1.0001 0 0 1 0.716797,0.30274 l 2.292969,2.29297 2.292969,-2.29297 a 1.0001,1.0001 0 0 1 0.697265,-0.30664 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <g
+ transform="translate(-1.8536743e-6,3.4999696e-6)"
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ id="g20495"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
+ <g
+ transform="translate(-189,588)"
+ id="g20491"
+ style="fill:#ffffff" />
+ <path
+ id="path20493"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 34,622 c -1.783333,0 -3,1.5 -3,3 h 2 c 0,-0.5 0.283333,-1 1,-1 0.716667,0 1,0.5 1,1 0,0.24702 -0.03644,0.30082 -0.117188,0.41016 -0.08074,0.10934 -0.253932,0.25966 -0.513671,0.4707 C 33.849662,626.30294 33,627.16667 33,628.5 v 0.5 h 2 v -0.5 c 0,-0.66667 0.150338,-0.67794 0.630859,-1.06836 0.240261,-0.19521 0.567072,-0.43551 0.861329,-0.83398 C 36.786444,626.19918 37,625.62798 37,625 c 0,-1.5 -1.216667,-3 -3,-3 z m -1,8.00009 h 2 v 2 H 33 Z M 34,620 c -3.86007,0 -7,3.13991 -7,7 0,3.86009 3.13993,7 7,7 3.86008,0 7,-3.13991 7,-7 0,-3.86009 -3.13992,-7 -7,-7 z m 0,1 c 3.31964,0 6,2.68035 6,6 0,3.31965 -2.68036,6 -6,6 -3.31963,0 -6,-2.68035 -6,-6 0,-3.31965 2.68037,-6 6,-6 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 55.011717,620 c -0.689946,-0.004 -1.325726,0.38513 -1.634766,1.00195 l -5.1875,10.3711 c -0.594248,1.18749 0.293094,2.62623 1.621094,2.62695 h 10.378906 c 1.327265,-7.2e-4 2.213373,-1.43788 1.621094,-2.625 l -5.1875,-10.37305 C 56.317741,620.39258 55.693326,620.0046 55.011717,620 Z m -1.011719,3 h 2 v 6 h -2 z m 0,7 h 2 v 2 h -2 z"
+ id="path20558"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ id="g20538"
+ transform="rotate(-180,317.50525,417)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 331.50586,410 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path20529"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 323.95117,412.94531 c -0.75176,0.0616 -1.47366,0.37015 -2.05469,0.95117 -1.16941,1.16942 -1.16162,2.91055 -0.28906,4.30664 0.87256,1.3961 2.57397,2.52709 4.83399,2.79297 C 329.94786,421.40861 333,419.08206 333,416 v -0.5 a 0.50005,0.50005 0 1 0 -1,0 v 0.5 c 0,2.41794 -2.42686,4.35855 -5.44141,4.00391 -1.98998,-0.23412 -3.41357,-1.22813 -4.10351,-2.33203 -0.68994,-1.10391 -0.68215,-2.23778 0.14844,-3.06836 0.83795,-0.83796 1.98844,-0.89361 3.08398,-0.26368 1.09554,0.62994 2.08242,1.9799 2.31641,3.96875 a 0.50005,0.50005 0 1 0 0.99218,-0.11718 c -0.26601,-2.26115 -1.40413,-3.91119 -2.80859,-4.71875 -0.70223,-0.40379 -1.48457,-0.58895 -2.23633,-0.52735 z m 3.54102,9.04883 a 0.50005,0.50005 0 0 0 -0.37696,0.1875 C 326.73975,422.63463 325.92671,423 325,423 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 c 1.17529,0 2.25213,-0.41841 2.88477,-1.18164 a 0.50005,0.50005 0 0 0 -0.39258,-0.82422 z"
+ id="path20536"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 331,410 c -2.22355,0 -4.0767,1.3002 -5.12305,3.18945 0.93682,-0.21724 1.92473,-0.28964 2.92578,-0.17187 0.40221,0.0473 0.78928,0.12403 1.16797,0.21484 C 330.29795,413.09146 330.64197,413 331,413 h 0.5 c 2.02848,0.0287 2.02848,-3.02869 0,-3 z m -3.05859,3.95898 c -3.69856,-0.0756 -6.93164,2.52898 -6.93164,6.04102 v 1.5 c -0.0287,2.02848 3.02869,2.02848 3,0 V 420 c 0,-1.75382 1.80351,-3.30654 4.32617,-3.00977 0.37314,0.0439 0.71883,0.11732 1.03711,0.21485 1.3077,0.40071 2.14372,1.21003 2.47656,1.91211 0.22905,0.48316 0.34095,1.19341 -0.0996,1.63281 -0.4946,0.4933 -1.25,0.34848 -1.89258,-0.0527 -0.70436,-0.44 -1.43726,-1.36047 -1.75195,-2.71875 -0.21041,-0.0194 -0.41646,-0.0328 -0.60742,-0.0234 -1.06865,0.0527 -1.81638,0.53365 -2.19727,1.13086 0.52848,1.85114 1.6077,3.30531 2.9668,4.15429 1.61509,1.00892 3.82413,1.05951 5.33594,-0.2539 0.0754,-0.0514 0.14605,-0.10959 0.21093,-0.17383 0.0562,-0.057 0.10785,-0.11837 0.1543,-0.18359 1.19162,-1.34198 1.31147,-3.2788 0.5918,-4.79688 -0.75194,-1.58612 -2.28118,-2.87289 -4.3086,-3.49414 -0.49344,-0.15121 -1.01745,-0.26354 -1.5664,-0.32812 -0.2499,-0.0294 -0.49757,-0.0457 -0.74414,-0.0508 z"
+ id="path20562"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="scccsccscsccsccccccccccccccccc" />
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g20665">
+ <path
+ id="path20610"
+ d="m 348.51367,409.98828 a 1.50015,1.50015 0 0 0 -0.80859,0.24024 C 343.03811,413.14537 342,418.71429 342,422.5 a 1.50015,1.50015 0 1 0 3,0 c 0,-0.89832 0.0865,-1.89371 0.26758,-2.9043 -0.25845,-3.40076 0.85029,-7.04233 3.87109,-9.4707 a 1.50015,1.50015 0 0 0 -0.625,-0.13672 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.4;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path20608"
+ d="m 351.51367,409.98828 a 1.50015,1.50015 0 0 0 -0.80859,0.24024 c -4.71461,2.94662 -5.33528,8.77693 -3.58399,12.86328 a 1.5005399,1.5005399 0 1 0 2.75782,-1.1836 c -0.38431,-0.89672 -0.59027,-1.91481 -0.62891,-2.95117 -0.67215,-3.14692 0.29131,-6.6121 2.9043,-8.82422 a 1.50015,1.50015 0 0 0 -0.64063,-0.14453 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path20592"
+ d="m 354.51367,409.98828 a 1.50015,1.50015 0 0 0 -0.80859,0.24024 c -4.9147,3.07168 -4.9147,10.47128 0,13.54296 a 1.50015,1.50015 0 1 0 1.58984,-2.54296 c -3.0853,-1.92832 -3.0853,-6.52872 0,-8.45704 a 1.50015,1.50015 0 0 0 -0.78125,-2.7832 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22444"
+ transform="translate(-1.8536743e-6,-41.999995)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 292.5,305 -9.00781,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.50781 l 0.0391,2.49219 1,-0.0156 -0.0312,-1.98438 8,-0.008 -0.006,8.01172 -2,0.0195 0.01,1 2.49414,-0.0234 a 0.50005,0.50005 0 0 0 0.49414,-0.5 L 293,305.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path22408"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path22122"
+ d="m 279,309 v 2 h 2 v -2 z m 2,2 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 2,0 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 0,2 v 2 h 2 v -2 z m 0,2 h -2 v 2 h 2 z m 0,2 v 2 h 2 v -2 z m -2,0 h -2 v 2 h 2 z m -2,0 v -2 h -2 v 2 z m -2,0 h -2 v 2 h 2 z m 0,-2 v -2 h -2 v 2 z m 2,0 h 2 v -2 h -2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="translate(422.00881,-131.00682)"
+ id="g22132">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -76.509766,394.00586 a 0.50005,0.50005 0 0 0 -0.486328,0.38867 l -3.011718,12.98828 a 0.50005,0.50005 0 0 0 0.486328,0.61328 h 9.974609 a 0.50005,0.50005 0 0 0 0.488281,-0.38476 l 3.03711,-12.99024 a 0.50005,0.50005 0 0 0 -0.488282,-0.61523 z m 0.398438,1 h 3.974609 l -1.154297,5 h -3.978515 z m 5,0 h 3.972656 l -1.169922,5 h -3.955078 z m -6.390625,6 h 3.980469 l -1.382813,5.99023 h -3.986328 z m 5.005859,0 h 3.953125 l -1.40039,5.99023 h -3.933594 z"
+ id="path22130"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g22232"
+ transform="translate(-42.000002,-20.999995)"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 145.49023,283.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -3,3 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -3,3 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -3,3 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -3,3 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
+ id="path22209"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 132.5,284 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -6 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 3 v 5 h -3 z m 6.5,8 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 6 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 5 v 3 h -5 z"
+ id="path22212"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-231,-83.999995)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g26345">
+ <g
+ id="g22592"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 300.5,326 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
+ id="path22548"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 307.49219,326.99219 A 0.50005,0.50005 0 0 0 307,327.5 v 5.5 h -5.5 a 0.50005,0.50005 0 1 0 0,1 h 5.5 v 2 h -5.5 a 0.50005,0.50005 0 1 0 0,1 h 5.5 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 337 h 2 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 337 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 311 v -2 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 311 v -5.5 a 0.50005,0.50005 0 1 0 -1,0 v 5.5 h -2 v -5.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 308,334 h 2 v 2 h -2 z"
+ id="path22585"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g transform="translate(-168.00001,-20.999988)" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g26390">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 74.492188,262.99219 a 0.50005,0.50005 0 0 0 -0.09961,0.0117 l -4.90039,0.004 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 5 a 0.50005,0.50005 0 1 0 1,0 V 269 H 74.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4.49805 L 79.5,264 a 0.50005,0.50005 0 1 0 0,-1 l -4.892578,0.004 a 0.50005,0.50005 0 0 0 -0.115234,-0.0117 z M 74,264.00391 V 268 h -4.007812 v -3.99414 z" transform="translate(168.00001,20.999988)" id="path23021" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 250.48438,284 a 0.50005,0.50005 0 0 0 -0.3379,0.14648 l -13.00781,13.00782 a 0.50005,0.50005 0 0 0 0.35352,0.85351 L 250.5,298 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 250.48438,284 Z M 250,285.70703 V 297 l -11.30078,0.008 z" id="path23044" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-2.8536743e-6,-20.999996)" id="g22228" style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 225.5,286 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6.5 h -6.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 l -0.008,4.00586 a 0.50005,0.50005 0 0 0 0.50195,0.50195 L 229.5,298 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -11 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 3 v 10 l -10.00781,0.008 0.006,-3.00781 H 225.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 z" id="path22226" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 222.5,284 a 0.50005,0.50005 0 0 1 0.5,0.5 v 6 a 0.50005,0.50005 0 0 1 -0.5,0.5 h -6 a 0.50005,0.50005 0 0 1 -0.5,-0.5 v -6 a 0.50005,0.50005 0 0 1 0.5,-0.5 z m -0.5,1 h -5 v 5 h 5 z" id="rect22230" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 327.41406,263 a 0.50005,0.50005 0 1 0 0,1 h 1.17969 c 1.54365,0 2.90268,0.42079 3.85937,1.21484 0.9567,0.79406 1.54688,1.95474 1.54688,3.60352 0,1.90166 -0.93943,3.66928 -2.68164,4.99414 -1.74221,1.32486 -4.29199,2.1875 -7.44922,2.1875 h -2.36133 a 0.50005,0.50005 0 1 0 0,1 h 2.36133 c 3.33916,0 6.10577,-0.91054 8.05469,-2.39258 1.94891,-1.48204 3.07617,-3.55426 3.07617,-5.78906 0,-1.89677 -0.72902,-3.39433 -1.9082,-4.37305 C 331.91261,263.46659 330.31821,263 328.59375,263 Z" id="path22657" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g22284" transform="translate(-1.8536743e-6,-41.999995)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 54.75,284 a 0.50004997,0.50004997 0 0 0 -0.431641,0.24805 l -3.646484,6.25 a 0.50004997,0.50004997 0 0 0 -0.002,0.002 c -1.211575,2.0985 -0.741006,4.77251 1.115234,6.33008 1.856239,1.55756 4.573449,1.55756 6.429688,0 1.85624,-1.55757 2.326809,-4.23158 1.115234,-6.33008 a 0.50004997,0.50004997 0 0 0 -0.002,-0.002 l -3.646484,-6.25 A 0.50004997,0.50004997 0 0 0 55.25,284 Z m 0.25,1.06445 3.464844,5.9375 c 0.970958,1.6837 0.594513,3.81305 -0.894532,5.0625 -1.489569,1.2499 -3.651055,1.2499 -5.140624,0 -1.489045,-1.24945 -1.86549,-3.3788 -0.894532,-5.0625 V 291 Z m -0.511719,2.92969 a 0.50004997,0.50004997 0 0 0 -0.429687,0.27148 l -1.697266,3.20704 c -0.166111,0.28617 -0.283806,0.59778 -0.349609,0.92187 a 0.50005872,0.50005872 0 1 0 0.980469,0.19727 c 0.04414,-0.2174 0.122796,-0.42496 0.234374,-0.61719 a 0.50004997,0.50004997 0 0 0 0.0098,-0.0176 l 1.705078,-3.22265 a 0.50004997,0.50004997 0 0 0 -0.453125,-0.74024 z" id="path22264" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g22457" transform="translate(20.999998,-20.999995)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999952;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 280.5,284 a 0.50004976,0.50004976 0 0 0 -0.5,0.5 v 0.75 7.25 a 0.50004976,0.50004976 0 0 0 0.5,0.5 h 0.5 a 0.50004976,0.50004976 0 0 0 0.2832,-0.0879 l 10.5,-7.25 A 0.50004976,0.50004976 0 0 0 292,285.25 v -0.75 a 0.50004976,0.50004976 0 0 0 -0.5,-0.5 z m 0.5,1 h 9.98242 L 281,291.89258 V 285.25 Z" id="path22322" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999952;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 285.25,292 a 0.50004976,0.50004976 0 1 0 0,1 H 291 v 0.15625 l -10,3.80859 V 295.25 a 0.50004976,0.50004976 0 1 0 -1,0 v 2.25 a 0.50004976,0.50004976 0 0 0 0.5,0.5 h 0.5 a 0.50004976,0.50004976 0 0 0 0.17773,-0.0332 l 10.5,-4 A 0.50004976,0.50004976 0 0 0 292,293.5 v -1 a 0.50004976,0.50004976 0 0 0 -0.5,-0.5 z" id="path22334" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g22510" transform="translate(-1.8536743e-6,21.000005)">
- <g style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new" id="g22476" transform="translate(168,-42)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 447.5,263 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.5 v 8 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 276 h 8 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 A 0.50005,0.50005 0 0 0 460.5,274 H 460 v -8 h 0.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -2 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -8 v -0.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 11,0 h 1 v 1 h -1 z m -9,1 h 8 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.5 v 8 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -8 v -0.5 A 0.50005,0.50005 0 0 0 449.5,274 H 449 v -8 h 0.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 z m -2,10 h 1 v 1 h -1 z m 11,0 h 1 v 1 h -1 z" transform="translate(-168,20.999995)" id="path22458" inkscape:connector-curvature="0"/>
+ <g
+ transform="translate(-168.00001,-20.999988)"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g26390">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 74.492188,262.99219 a 0.50005,0.50005 0 0 0 -0.09961,0.0117 l -4.90039,0.004 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 5 a 0.50005,0.50005 0 1 0 1,0 V 269 H 74.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4.49805 L 79.5,264 a 0.50005,0.50005 0 1 0 0,-1 l -4.892578,0.004 a 0.50005,0.50005 0 0 0 -0.115234,-0.0117 z M 74,264.00391 V 268 h -4.007812 v -3.99414 z"
+ transform="translate(168.00001,20.999988)"
+ id="path23021"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 250.48438,284 a 0.50005,0.50005 0 0 0 -0.3379,0.14648 l -13.00781,13.00782 a 0.50005,0.50005 0 0 0 0.35352,0.85351 L 250.5,298 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 250.48438,284 Z M 250,285.70703 V 297 l -11.30078,0.008 z"
+ id="path23044"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-2.8536743e-6,-20.999996)"
+ id="g22228"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 225.5,286 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6.5 h -6.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 l -0.008,4.00586 a 0.50005,0.50005 0 0 0 0.50195,0.50195 L 229.5,298 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -11 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 3 v 10 l -10.00781,0.008 0.006,-3.00781 H 225.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 z"
+ id="path22226"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 222.5,284 a 0.50005,0.50005 0 0 1 0.5,0.5 v 6 a 0.50005,0.50005 0 0 1 -0.5,0.5 h -6 a 0.50005,0.50005 0 0 1 -0.5,-0.5 v -6 a 0.50005,0.50005 0 0 1 0.5,-0.5 z m -0.5,1 h -5 v 5 h 5 z"
+ id="rect22230"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 327.41406,263 a 0.50005,0.50005 0 1 0 0,1 h 1.17969 c 1.54365,0 2.90268,0.42079 3.85937,1.21484 0.9567,0.79406 1.54688,1.95474 1.54688,3.60352 0,1.90166 -0.93943,3.66928 -2.68164,4.99414 -1.74221,1.32486 -4.29199,2.1875 -7.44922,2.1875 h -2.36133 a 0.50005,0.50005 0 1 0 0,1 h 2.36133 c 3.33916,0 6.10577,-0.91054 8.05469,-2.39258 1.94891,-1.48204 3.07617,-3.55426 3.07617,-5.78906 0,-1.89677 -0.72902,-3.39433 -1.9082,-4.37305 C 331.91261,263.46659 330.31821,263 328.59375,263 Z"
+ id="path22657"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22284"
+ transform="translate(-1.8536743e-6,-41.999995)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 54.75,284 a 0.50004997,0.50004997 0 0 0 -0.431641,0.24805 l -3.646484,6.25 a 0.50004997,0.50004997 0 0 0 -0.002,0.002 c -1.211575,2.0985 -0.741006,4.77251 1.115234,6.33008 1.856239,1.55756 4.573449,1.55756 6.429688,0 1.85624,-1.55757 2.326809,-4.23158 1.115234,-6.33008 a 0.50004997,0.50004997 0 0 0 -0.002,-0.002 l -3.646484,-6.25 A 0.50004997,0.50004997 0 0 0 55.25,284 Z m 0.25,1.06445 3.464844,5.9375 c 0.970958,1.6837 0.594513,3.81305 -0.894532,5.0625 -1.489569,1.2499 -3.651055,1.2499 -5.140624,0 -1.489045,-1.24945 -1.86549,-3.3788 -0.894532,-5.0625 V 291 Z m -0.511719,2.92969 a 0.50004997,0.50004997 0 0 0 -0.429687,0.27148 l -1.697266,3.20704 c -0.166111,0.28617 -0.283806,0.59778 -0.349609,0.92187 a 0.50005872,0.50005872 0 1 0 0.980469,0.19727 c 0.04414,-0.2174 0.122796,-0.42496 0.234374,-0.61719 a 0.50004997,0.50004997 0 0 0 0.0098,-0.0176 l 1.705078,-3.22265 a 0.50004997,0.50004997 0 0 0 -0.453125,-0.74024 z"
+ id="path22264"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22457"
+ transform="translate(20.999998,-20.999995)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999952;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 280.5,284 a 0.50004976,0.50004976 0 0 0 -0.5,0.5 v 0.75 7.25 a 0.50004976,0.50004976 0 0 0 0.5,0.5 h 0.5 a 0.50004976,0.50004976 0 0 0 0.2832,-0.0879 l 10.5,-7.25 A 0.50004976,0.50004976 0 0 0 292,285.25 v -0.75 a 0.50004976,0.50004976 0 0 0 -0.5,-0.5 z m 0.5,1 h 9.98242 L 281,291.89258 V 285.25 Z"
+ id="path22322"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999952;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 285.25,292 a 0.50004976,0.50004976 0 1 0 0,1 H 291 v 0.15625 l -10,3.80859 V 295.25 a 0.50004976,0.50004976 0 1 0 -1,0 v 2.25 a 0.50004976,0.50004976 0 0 0 0.5,0.5 h 0.5 a 0.50004976,0.50004976 0 0 0 0.17773,-0.0332 l 10.5,-4 A 0.50004976,0.50004976 0 0 0 292,293.5 v -1 a 0.50004976,0.50004976 0 0 0 -0.5,-0.5 z"
+ id="path22334"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22510"
+ transform="translate(-1.8536743e-6,21.000005)">
+ <g
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ id="g22476"
+ transform="translate(168,-42)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 447.5,263 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.5 v 8 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 276 h 8 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 A 0.50005,0.50005 0 0 0 460.5,274 H 460 v -8 h 0.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -2 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -8 v -0.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 11,0 h 1 v 1 h -1 z m -9,1 h 8 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.5 v 8 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -8 v -0.5 A 0.50005,0.50005 0 0 0 449.5,274 H 449 v -8 h 0.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 z m -2,10 h 1 v 1 h -1 z m 11,0 h 1 v 1 h -1 z"
+ transform="translate(-168,20.999995)"
+ id="path22458"
+ inkscape:connector-curvature="0" />
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 451.5,246 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 4 v 4 h -4 z" id="rect22466" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" transform="translate(21.999998,18.000004)" id="g22745">
- <g id="g22756" transform="translate(20,-60)" style="fill:#ffffff">
- <g id="g22751" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999952;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 279.5,288 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 0.71484 L 283,295.64062 V 297.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1.85938 L 288.78516,291 H 289.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -2 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 0.5 h -5 v -0.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 8,0 h 1 v 1 h -1 z m -6,1 h 5 v 0.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 0.11523 l -2.40039,4 h -1.42968 l -2.40039,-4 H 281.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 z m 2,6 h 1 v 1 h -1 z" id="path22741" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 283.5,284 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3.5 h 1 v -3 h 8 v 10 h -3.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path22747" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccc"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 451.5,246 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 4 v 4 h -4 z"
+ id="rect22466"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(21.999998,18.000004)"
+ id="g22745">
+ <g
+ id="g22756"
+ transform="translate(20,-60)"
+ style="fill:#ffffff">
+ <g
+ id="g22751"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999952;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 279.5,288 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 0.71484 L 283,295.64062 V 297.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1.85938 L 288.78516,291 H 289.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -2 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 0.5 h -5 v -0.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 8,0 h 1 v 1 h -1 z m -6,1 h 5 v 0.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 0.11523 l -2.40039,4 h -1.42968 l -2.40039,-4 H 281.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 z m 2,6 h 1 v 1 h -1 z"
+ id="path22741"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 283.5,284 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3.5 h 1 v -3 h 8 v 10 h -3.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path22747"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccc" />
</g>
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g21947" transform="matrix(-1,0,0,1,67.986641,-20.999995)">
- <path id="circle21927" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 27.460938,284.01172 a 0.50005,0.50005 0 1 0 0.04297,0.99805 c 3.348416,-0.1388 6.600566,1.12874 8.972656,3.49609 2.372091,2.36735 3.645762,5.61811 3.513672,8.9668 a 0.50038206,0.50038206 0 1 0 1,0.0391 c 0.143077,-3.62723 -1.237239,-7.14863 -3.80664,-9.71289 -2.569402,-2.56427 -6.09572,-3.93745 -9.722656,-3.78711 z m -0.0332,4.00586 a 0.50005,0.50005 0 1 0 0.0625,0.99804 c 2.281784,-0.14542 4.516597,0.69332 6.140625,2.30274 1.62403,1.60942 2.482218,3.83613 2.357422,6.11914 a 0.50005,0.50005 0 1 0 0.998047,0.0547 c 0.140364,-2.5678 -0.823774,-5.07459 -2.65039,-6.88477 -1.826617,-1.81018 -4.341781,-2.75341 -6.908204,-2.58984 z m 0.03711,4.01172 a 0.50005,0.50005 0 1 0 0.107422,0.99414 c 1.199607,-0.12917 2.392346,0.29002 3.248046,1.14062 0.855701,0.8506 1.282148,2.03988 1.160157,3.24024 a 0.50005,0.50005 0 1 0 0.99414,0.10156 c 0.152408,-1.49965 -0.380162,-2.99006 -1.449218,-4.05274 -1.069056,-1.06268 -2.561836,-1.5852 -4.060547,-1.42382 z M 28,296 c -0.546362,0 -1,0.45364 -1,1 0,0.54636 0.453638,1 1,1 0.546362,0 1,-0.45364 1,-1 0,-0.54636 -0.453638,-1 -1,-1 z" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g22083" transform="translate(-1.8536743e-6,-42.000055)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 205.49805,242 -3.00586,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 5 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 206,252 h 2.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 208.5,246 H 206 v -3.5 A 0.50005,0.50005 0 0 0 205.49805,242 Z M 205,243.00195 V 246 h -2.00781 v -2.99414 z M 202.99219,247 H 205 v 4 h -2.00781 z M 206,247 h 2 v 4 h -2 z m -3.00781,5 h 2.00586 l -0.006,3.00781 h -2 z" transform="translate(1.8536743e-6,42.000055)" id="path22040" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 200.53711,284.16992 a 0.50005,0.50005 0 0 0 -0.13477,0.0156 c -3.14392,0.73681 -5.37898,3.53464 -5.40234,6.76367 -0.0234,3.22902 2.17176,6.05956 5.30469,6.8418 a 0.50005,0.50005 0 1 0 0.24219,-0.96875 c -2.69014,-0.67168 -4.56694,-3.09259 -4.54688,-5.86524 0.0201,-2.77265 1.93128,-5.16615 4.63086,-5.79883 a 0.50005,0.50005 0 0 0 -0.0937,-0.98828 z" id="path22034" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g21627" transform="translate(2.8146326e-5,-41.999965)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 495.5,305 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -3.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3.5 h -1.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 7 a 0.50005,0.50005 0 1 0 1,0 V 312 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 308 h 3.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 306 h 6.5 a 0.50005,0.50005 0 1 0 0,-1 z" id="path21618" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 502.5,308 c -5.79307,0 -10.5,4.70693 -10.5,10.5 a 0.50004997,0.50004997 0 1 0 1,0 c 0,-5.25263 4.24737,-9.5 9.5,-9.5 a 0.50004997,0.50004997 0 1 0 0,-1 z" id="circle21622" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g21555" transform="translate(-1.8536743e-6,-20.999995)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 160.50391,263.00391 c -0.82069,0 -1.4961,0.67734 -1.4961,1.49804 1e-5,0.64713 0.422,1.19917 1.00196,1.40625 -0.004,0.17741 -0.01,0.3625 -0.01,0.58594 0,0.8575 0.30572,1.55064 0.73242,2.08984 0.42671,0.53921 0.958,0.94374 1.45313,1.34375 0.99025,0.80003 1.81445,1.48075 1.81445,3.0293 0,1.03964 -0.41467,1.75679 -1.05859,2.26367 C 162.29747,275.72759 161.4016,276 160.5,276 c -0.9016,0 -1.79749,-0.27241 -2.44141,-0.7793 C 157.41467,274.71382 157,273.99667 157,272.95703 v -1.25 l 1.14648,1.14649 c 0.47127,0.49023 1.19727,-0.23577 0.70704,-0.70704 l -2,-2 c -0.315,-0.31479 -0.85335,-0.0918 -0.85352,0.35352 v 2.45703 c 0,1.32194 0.58533,2.37688 1.44141,3.05078 0.85608,0.6739 1.96019,0.99219 3.05859,0.99219 1.0984,0 2.20251,-0.31829 3.05859,-0.99219 0.85608,-0.6739 1.44141,-1.72884 1.44141,-3.05078 0,-1.93167 -1.1758,-2.99085 -2.18555,-3.80664 -0.50487,-0.40789 -0.97358,-0.77897 -1.29687,-1.1875 C 161.19428,267.55436 161,267.12816 161,266.49414 c 0,-0.20716 0.005,-0.40692 0.01,-0.58984 0.57393,-0.21035 0.99023,-0.75955 0.99023,-1.40235 0,-0.8207 -0.67541,-1.49804 -1.49609,-1.49804 z m 0,1 c 0.27921,0 0.49609,0.21676 0.49609,0.49804 0,0.28129 -0.21688,0.49805 -0.49609,0.49805 -0.27922,0 -0.4961,-0.21676 -0.4961,-0.49805 0,-0.28128 0.21688,-0.49804 0.4961,-0.49804 z" transform="translate(1.8536743e-6,20.999995)" id="path16949-6-5" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="g22126">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 178.5,158 c -0.1326,3e-5 -0.25976,0.0527 -0.35352,0.14649 l -1.99219,1.99218 c -0.11574,0.11126 -0.14648,0.23321 -0.14648,0.35352 v 0.5 h 1 l 0.008,-0.30096 L 178.70703,159 H 187 v 8.29297 l -2.70703,2.70508 -5.28516,-0.006 v 1 l 5.49219,0.008 c 0.1326,-3e-5 0.25975,-0.0527 0.35351,-0.14648 l 3,-3 c 0.0938,-0.0938 0.14646,-0.22092 0.14649,-0.35352 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path22118" inkscape:connector-curvature="0" sodipodi:nodetypes="cccscccccccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 174.5,162 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0,6 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path22124" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccc"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="g21749">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 199.49973,158 c -0.1326,3e-5 -0.25976,0.0527 -0.35352,0.14649 l -2,2 c -0.10516,0.10095 -0.13867,0.22574 -0.13867,0.3457 v 0.5 h 1 l 0.003,-0.2957 L 199.70703,159 H 208 v 8.29297 l -1.69086,1.69085 -0.3016,0.008 v 1 h 0.5 c 0.12522,0 0.24874,-0.0375 0.35352,-0.14648 l 1.99218,-1.99219 c 0.0938,-0.0938 0.14646,-0.22092 0.14649,-0.35352 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -0.49219,11.99219 v 1 l 1.99219,0.008 v -1 z" id="path21666" inkscape:connector-curvature="0" sodipodi:nodetypes="cccscccccccccsccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 195.5,162 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 9 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 7,0 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 9 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path21689" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccc"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g22356" transform="translate(-336,-62.999995)">
- <path inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" sodipodi:nodetypes="ccccc" id="path22236" d="m 363.5,308.5 3,-3 h 6 l -3,3 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 366.5,305 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 363.5,309 h 6 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 372.5,305 Z m 0.20703,1 h 4.58594 l -2,2 h -4.58594 z m 9.77735,3 a 0.50005,0.50005 0 0 0 -0.3379,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 373,312.5 v 6 a 0.50005,0.50005 0 0 0 0.85352,0.35352 l 3,-3 A 0.50005,0.50005 0 0 0 377,315.5 v -6 A 0.50005,0.50005 0 0 0 376.48438,309 Z M 376,310.70703 v 4.58594 l -2,2 v -4.58594 z M 369.5,312 l -6.00781,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6 a 0.50005,0.50005 0 0 0 0.5,0.5 h 6 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 370,312.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -0.5,1 -0.008,5.00781 h -5 v -5.00195 z" id="path22324" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g22409">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 347.75,247 -5.25781,0.002 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 8 a 0.50005,0.50005 0 0 0 0.5,0.5 h 8 a 0.50005,0.50005 0 0 0 0.5,-0.49804 L 351,251.50195 a 0.50005,0.50005 0 1 0 -1,-0.004 l -0.008,3.5039 h -7 v -7 L 347.75,248 a 0.50005,0.50005 0 1 0 0,-1 z" id="path22405" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 350.49219,241.99219 A 0.50005,0.50005 0 0 0 350,242.5 v 4.59766 c -0.58199,0.20687 -1.00586,0.75933 -1.00586,1.4082 0,0.82235 0.67765,1.5 1.5,1.5 0.36227,0 0.69258,-0.13606 0.95313,-0.35352 l 3.79492,2.27735 a 0.50109829,0.50109829 0 1 0 0.51562,-0.85938 l -3.79297,-2.27734 c 0.0184,-0.0931 0.0293,-0.18901 0.0293,-0.28711 0,-0.10213 -0.0114,-0.20218 -0.0312,-0.29883 l 3.79492,-2.27734 a 0.50109829,0.50109829 0 1 0 -0.51562,-0.85938 l -3.80469,2.28321 C 351.30689,247.24613 351.16128,247.1604 351,247.10156 V 242.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" transform="translate(1.8536743e-6,-4.4999696e-6)" id="path22407" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g22292" transform="translate(-88.000002,-170)">
- <g transform="translate(20,10)" id="g22287" style="fill:#ffffff">
- <path style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" d="m 112,515 v 2 h -1 v 4 h 1 v 2 h 2 v -8 z m 10,0 v 8 h 2 v -2 h 1 v -4 h -1 v -2 z m -7,3 v 2 h 6 v -2 z" transform="translate(68.000002,160)" id="rect22279" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g21947"
+ transform="matrix(-1,0,0,1,67.986641,-20.999995)">
+ <path
+ id="circle21927"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 27.460938,284.01172 a 0.50005,0.50005 0 1 0 0.04297,0.99805 c 3.348416,-0.1388 6.600566,1.12874 8.972656,3.49609 2.372091,2.36735 3.645762,5.61811 3.513672,8.9668 a 0.50038206,0.50038206 0 1 0 1,0.0391 c 0.143077,-3.62723 -1.237239,-7.14863 -3.80664,-9.71289 -2.569402,-2.56427 -6.09572,-3.93745 -9.722656,-3.78711 z m -0.0332,4.00586 a 0.50005,0.50005 0 1 0 0.0625,0.99804 c 2.281784,-0.14542 4.516597,0.69332 6.140625,2.30274 1.62403,1.60942 2.482218,3.83613 2.357422,6.11914 a 0.50005,0.50005 0 1 0 0.998047,0.0547 c 0.140364,-2.5678 -0.823774,-5.07459 -2.65039,-6.88477 -1.826617,-1.81018 -4.341781,-2.75341 -6.908204,-2.58984 z m 0.03711,4.01172 a 0.50005,0.50005 0 1 0 0.107422,0.99414 c 1.199607,-0.12917 2.392346,0.29002 3.248046,1.14062 0.855701,0.8506 1.282148,2.03988 1.160157,3.24024 a 0.50005,0.50005 0 1 0 0.99414,0.10156 c 0.152408,-1.49965 -0.380162,-2.99006 -1.449218,-4.05274 -1.069056,-1.06268 -2.561836,-1.5852 -4.060547,-1.42382 z M 28,296 c -0.546362,0 -1,0.45364 -1,1 0,0.54636 0.453638,1 1,1 0.546362,0 1,-0.45364 1,-1 0,-0.54636 -0.453638,-1 -1,-1 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22083"
+ transform="translate(-1.8536743e-6,-42.000055)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 205.49805,242 -3.00586,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 5 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 206,252 h 2.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 208.5,246 H 206 v -3.5 A 0.50005,0.50005 0 0 0 205.49805,242 Z M 205,243.00195 V 246 h -2.00781 v -2.99414 z M 202.99219,247 H 205 v 4 h -2.00781 z M 206,247 h 2 v 4 h -2 z m -3.00781,5 h 2.00586 l -0.006,3.00781 h -2 z"
+ transform="translate(1.8536743e-6,42.000055)"
+ id="path22040"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 200.53711,284.16992 a 0.50005,0.50005 0 0 0 -0.13477,0.0156 c -3.14392,0.73681 -5.37898,3.53464 -5.40234,6.76367 -0.0234,3.22902 2.17176,6.05956 5.30469,6.8418 a 0.50005,0.50005 0 1 0 0.24219,-0.96875 c -2.69014,-0.67168 -4.56694,-3.09259 -4.54688,-5.86524 0.0201,-2.77265 1.93128,-5.16615 4.63086,-5.79883 a 0.50005,0.50005 0 0 0 -0.0937,-0.98828 z"
+ id="path22034"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g21627"
+ transform="translate(2.8146326e-5,-41.999965)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 495.5,305 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -3.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3.5 h -1.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 7 a 0.50005,0.50005 0 1 0 1,0 V 312 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 308 h 3.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 306 h 6.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path21618"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 502.5,308 c -5.79307,0 -10.5,4.70693 -10.5,10.5 a 0.50004997,0.50004997 0 1 0 1,0 c 0,-5.25263 4.24737,-9.5 9.5,-9.5 a 0.50004997,0.50004997 0 1 0 0,-1 z"
+ id="circle21622"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g21555"
+ transform="translate(-1.8536743e-6,-20.999995)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 160.50391,263.00391 c -0.82069,0 -1.4961,0.67734 -1.4961,1.49804 1e-5,0.64713 0.422,1.19917 1.00196,1.40625 -0.004,0.17741 -0.01,0.3625 -0.01,0.58594 0,0.8575 0.30572,1.55064 0.73242,2.08984 0.42671,0.53921 0.958,0.94374 1.45313,1.34375 0.99025,0.80003 1.81445,1.48075 1.81445,3.0293 0,1.03964 -0.41467,1.75679 -1.05859,2.26367 C 162.29747,275.72759 161.4016,276 160.5,276 c -0.9016,0 -1.79749,-0.27241 -2.44141,-0.7793 C 157.41467,274.71382 157,273.99667 157,272.95703 v -1.25 l 1.14648,1.14649 c 0.47127,0.49023 1.19727,-0.23577 0.70704,-0.70704 l -2,-2 c -0.315,-0.31479 -0.85335,-0.0918 -0.85352,0.35352 v 2.45703 c 0,1.32194 0.58533,2.37688 1.44141,3.05078 0.85608,0.6739 1.96019,0.99219 3.05859,0.99219 1.0984,0 2.20251,-0.31829 3.05859,-0.99219 0.85608,-0.6739 1.44141,-1.72884 1.44141,-3.05078 0,-1.93167 -1.1758,-2.99085 -2.18555,-3.80664 -0.50487,-0.40789 -0.97358,-0.77897 -1.29687,-1.1875 C 161.19428,267.55436 161,267.12816 161,266.49414 c 0,-0.20716 0.005,-0.40692 0.01,-0.58984 0.57393,-0.21035 0.99023,-0.75955 0.99023,-1.40235 0,-0.8207 -0.67541,-1.49804 -1.49609,-1.49804 z m 0,1 c 0.27921,0 0.49609,0.21676 0.49609,0.49804 0,0.28129 -0.21688,0.49805 -0.49609,0.49805 -0.27922,0 -0.4961,-0.21676 -0.4961,-0.49805 0,-0.28128 0.21688,-0.49804 0.4961,-0.49804 z"
+ transform="translate(1.8536743e-6,20.999995)"
+ id="path16949-6-5"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22356"
+ transform="translate(-336,-62.999995)">
+ <path
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ sodipodi:nodetypes="ccccc"
+ id="path22236"
+ d="m 363.5,308.5 3,-3 h 6 l -3,3 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 366.5,305 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 363.5,309 h 6 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 372.5,305 Z m 0.20703,1 h 4.58594 l -2,2 h -4.58594 z m 9.77735,3 a 0.50005,0.50005 0 0 0 -0.3379,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 373,312.5 v 6 a 0.50005,0.50005 0 0 0 0.85352,0.35352 l 3,-3 A 0.50005,0.50005 0 0 0 377,315.5 v -6 A 0.50005,0.50005 0 0 0 376.48438,309 Z M 376,310.70703 v 4.58594 l -2,2 v -4.58594 z M 369.5,312 l -6.00781,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6 a 0.50005,0.50005 0 0 0 0.5,0.5 h 6 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 370,312.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -0.5,1 -0.008,5.00781 h -5 v -5.00195 z"
+ id="path22324"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22409">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 347.75,247 -5.25781,0.002 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 8 a 0.50005,0.50005 0 0 0 0.5,0.5 h 8 a 0.50005,0.50005 0 0 0 0.5,-0.49804 L 351,251.50195 a 0.50005,0.50005 0 1 0 -1,-0.004 l -0.008,3.5039 h -7 v -7 L 347.75,248 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path22405"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 350.49219,241.99219 A 0.50005,0.50005 0 0 0 350,242.5 v 4.59766 c -0.58199,0.20687 -1.00586,0.75933 -1.00586,1.4082 0,0.82235 0.67765,1.5 1.5,1.5 0.36227,0 0.69258,-0.13606 0.95313,-0.35352 l 3.79492,2.27735 a 0.50109829,0.50109829 0 1 0 0.51562,-0.85938 l -3.79297,-2.27734 c 0.0184,-0.0931 0.0293,-0.18901 0.0293,-0.28711 0,-0.10213 -0.0114,-0.20218 -0.0312,-0.29883 l 3.79492,-2.27734 a 0.50109829,0.50109829 0 1 0 -0.51562,-0.85938 l -3.80469,2.28321 C 351.30689,247.24613 351.16128,247.1604 351,247.10156 V 242.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ transform="translate(1.8536743e-6,-4.4999696e-6)"
+ id="path22407"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22292"
+ transform="translate(-88.000002,-170)">
+ <g
+ transform="translate(20,10)"
+ id="g22287"
+ style="fill:#ffffff">
+ <path
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="m 112,515 v 2 h -1 v 4 h 1 v 2 h 2 v -8 z m 10,0 v 8 h 2 v -2 h 1 v -4 h -1 v -2 z m -7,3 v 2 h 6 v -2 z"
+ transform="translate(68.000002,160)"
+ id="rect22279"
+ inkscape:connector-curvature="0" />
</g>
- <path inkscape:connector-curvature="0" id="path22290" d="m 203,691 v 5 c 0,0.5 0.25,1 1,1 0.75,0 1,-0.5 1,-1 v -1 c 0,-0.5 0.53412,-1 1,-1 0.55229,0 1,0.44772 1,1 v 2.5 c 0,0.82843 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67157 1.5,-1.5 V 697 c 0,-0.55228 0.44772,-1 1,-1 0.55229,0 1,-0.44771 1,-1 v -1 h -3 v -3 z" style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" sodipodi:nodetypes="csssssssssssscccc"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g22354" transform="translate(-26.000002,-443)">
- <g id="g22339" transform="translate(0,10)" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 154,242 v 2 h -1 v 4 h 1 v 2 h 2 v -8 z m 10,0 v 8 h 2 v -2 h 1 v -4 h -1 v -2 z m -7,3 v 2 h 6 v -2 z" transform="translate(26.000002,433)" id="path22321" inkscape:connector-curvature="0"/>
+ <path
+ inkscape:connector-curvature="0"
+ id="path22290"
+ d="m 203,691 v 5 c 0,0.5 0.25,1 1,1 0.75,0 1,-0.5 1,-1 v -1 c 0,-0.5 0.53412,-1 1,-1 0.55229,0 1,0.44772 1,1 v 2.5 c 0,0.82843 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67157 1.5,-1.5 V 697 c 0,-0.55228 0.44772,-1 1,-1 0.55229,0 1,-0.44771 1,-1 v -1 h -3 v -3 z"
+ style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ sodipodi:nodetypes="csssssssssssscccc" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22354"
+ transform="translate(-26.000002,-443)">
+ <g
+ id="g22339"
+ transform="translate(0,10)"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 154,242 v 2 h -1 v 4 h 1 v 2 h 2 v -8 z m 10,0 v 8 h 2 v -2 h 1 v -4 h -1 v -2 z m -7,3 v 2 h 6 v -2 z"
+ transform="translate(26.000002,433)"
+ id="path22321"
+ inkscape:connector-curvature="0" />
</g>
- <g transform="translate(-267.99969,306.00818)" style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;enable-background:new" id="g22352">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 452.49219,387 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 V 387.5 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.0053,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66922,0 -1.3386,0 -2.00781,0 z m 4.50781,0.98438 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.0053,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.00529,0 -3.00781,0 z M 447.5,389 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1,-10e-6 2,10e-6 3,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1,0 -2,0 -3,0 z m 10.5,0.98438 c 0.66922,-10e-6 1.3386,0 2.00781,0 v 2.00781 c -0.66922,0 -1.33859,0 -2.00781,0 z M 448,390 c 0.66667,0 1.33333,0 2,0 v 2 c -0.66667,0 -1.33333,0 -2,0 z" id="path22350" inkscape:connector-curvature="0"/>
+ <g
+ transform="translate(-267.99969,306.00818)"
+ style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;enable-background:new"
+ id="g22352">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 452.49219,387 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 V 387.5 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.0053,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66922,0 -1.3386,0 -2.00781,0 z m 4.50781,0.98438 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.0053,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.00529,0 -3.00781,0 z M 447.5,389 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1,-10e-6 2,10e-6 3,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1,0 -2,0 -3,0 z m 10.5,0.98438 c 0.66922,-10e-6 1.3386,0 2.00781,0 v 2.00781 c -0.66922,0 -1.33859,0 -2.00781,0 z M 448,390 c 0.66667,0 1.33333,0 2,0 v 2 c -0.66667,0 -1.33333,0 -2,0 z"
+ id="path22350"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 118.89062,157.9668 c -1.59478,-0.0195 -3.16997,0.53887 -4.2539,1.6914 l -0.74024,0.73828 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 2,2 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 0.5,-0.5 c 0.5849,-0.58491 1.58165,-0.89809 2.3457,-0.69336 0.80156,0.21477 1.42585,0.83907 1.64062,1.64062 0.20473,0.76404 -0.10844,1.76078 -0.69336,2.3457 l -0.5,0.5 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 2,2 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 0.75,-0.75 c 2.22378,-2.22379 2.21818,-6.29752 -0.0977,-8.61329 -1.15793,-1.15796 -2.77045,-1.75392 -4.36524,-1.77343 z m -6.14848,3.7832 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -1.25,1.25 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 2,2 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 1.25,-1.25 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -2,-2 c -0.0957,-0.0957 -0.226,-0.14854 -0.36128,-0.14648 z m 6.00019,6 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -1.25,1.25 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 2,2 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 1.25,-1.25 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -2,-2 c -0.0957,-0.0957 -0.22612,-0.14859 -0.36147,-0.14648 z" id="path21201-1" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccscccccccccccccccccccccccccccccc"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g22386" transform="translate(-886.00002,80.000125)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 433,263 c -3.84758,0 -6.97776,3.12003 -6.99805,6.96289 -6e-5,0.0125 -0.002,0.0246 -0.002,0.0371 a 0.50004994,0.50004994 0 0 0 0.002,0.0488 0.50004994,0.50004994 0 0 0 0,0.002 l -0.01,6.45508 a 0.50005,0.50005 0 0 0 0.50195,0.50195 L 432.96484,277 A 0.50004994,0.50004994 0 0 0 433,277 c 0.0171,0 0.0337,-0.002 0.0508,-0.002 a 0.50005,0.50005 0 0 0 0.008,0 C 436.89154,276.96613 440,273.84031 440,270 c 0,-3.86007 -3.1399,-7 -7,-7 z m 0,1 c 3.3196,0 6,2.68037 6,6 0,3.31963 -2.6804,6 -6,6 l -6.00781,0.008 0.01,-6.00781 a 0.50005,0.50005 0 0 0 0,-0.0215 C 427.01364,266.66895 429.68766,264 433,264 Z" transform="translate(886.00002,-80.000125)" id="path22377" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1314.5,189 a 0.50005,0.50005 0 1 0 0,1 h 4.5 v 4.5 a 0.50005,0.50005 0 1 0 1,0 v -5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z" id="path22381" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g22599" transform="translate(-1.8536743e-6,-21.999995)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 132.5,285 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z" id="path22722" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 139,287 c -2.75493,0 -5,2.24492 -5,5 0,2.75508 2.24507,5 5,5 2.75493,0 5,-2.24492 5,-5 0,-2.75508 -2.24507,-5 -5,-5 z m 0,1.09961 c 2.1604,0 3.90039,1.73975 3.90039,3.90039 0,2.16064 -1.73999,3.90039 -3.90039,3.90039 -2.1604,0 -3.90039,-1.73975 -3.90039,-3.90039 0,-2.16064 1.73999,-3.90039 3.90039,-3.90039 z" id="ellipse22724" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" transform="translate(-356.99997,168.00001)" id="g23559">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 495.49219,199.99219 A 0.50005,0.50005 0 0 0 495,200.5 v 6.79297 l -3.85352,3.85351 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 495.70703,208 H 502.5 a 0.50005,0.50005 0 1 0 0,-1 H 496 v -6.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" id="path23553" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 499.49023,202.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -2,2 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2,-2 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z M 489.5,207 a 0.50005,0.50005 0 1 0 0,1 h 3.25 a 0.50005,0.50005 0 1 0 0,-1 z m 5.99219,2.74219 A 0.50005,0.50005 0 0 0 495,210.25 v 3.25 a 0.50005,0.50005 0 1 0 1,0 v -3.25 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" id="path23557" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 163.00977,368 c -1.1753,0 -2.25213,0.41841 -2.88477,1.18164 a 0.50005,0.50005 0 1 0 0.76953,0.63672 C 161.27001,369.36537 162.08306,369 163.00977,369 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 z m -1.44141,3.00391 c -1.72788,-0.20328 -3.32792,0.12142 -4.53125,0.90234 -1.20333,0.78092 -1.99513,2.0489 -2.02734,3.58398 v 0.004 0.006 c 0,1.08246 0.28424,1.81368 0.53711,2.38867 0.25286,0.575 0.45312,0.97127 0.45312,1.61133 0,0.46148 -0.10735,0.76987 -0.43555,1.02734 -0.3282,0.25748 -0.96151,0.47266 -2.05468,0.47266 a 0.50005,0.50005 0 1 0 0,1 c 1.21947,0 2.08348,-0.22395 2.67187,-0.68555 C 156.77003,380.85286 157,380.16225 157,379.5 c 0,-0.85994 -0.29523,-1.46367 -0.53711,-2.01367 -0.24115,-0.54835 -0.44991,-1.06809 -0.45117,-1.98047 0.0269,-1.212 0.60444,-2.1349 1.57031,-2.76172 0.96712,-0.62763 2.33652,-0.92835 3.86914,-0.74805 1.98998,0.23412 3.41358,1.22813 4.10352,2.33203 0.68994,1.10391 0.68215,2.23778 -0.14844,3.06836 -0.83795,0.83796 -1.98844,0.89361 -3.08398,0.26368 -1.09554,-0.62994 -2.08047,-1.9799 -2.31446,-3.96875 a 0.50051111,0.50051111 0 1 0 -0.99414,0.11718 c 0.26602,2.26115 1.40609,3.91119 2.81055,4.71875 1.40446,0.80757 3.12702,0.73822 4.28906,-0.42382 1.16941,-1.16942 1.16162,-2.91055 0.28906,-4.30664 -0.87256,-1.3961 -2.57396,-2.52709 -4.83398,-2.79297 z" id="path23575" inkscape:connector-curvature="0"/>
- <g transform="matrix(-1,0,0,1,382.99922,-15.999998)" style="display:inline;fill:#ffffff;enable-background:new" id="g24066">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 198.03906,347.00195 c -0.16252,-0.007 -0.32108,0.006 -0.47461,0.0371 -1.22821,0.25238 -1.95915,1.36682 -2.45507,2.09766 a 0.60006002,0.60006002 0 1 0 0.99218,0.67383 c 0.46736,-0.68874 1.16385,-1.48449 1.70508,-1.59571 0.27061,-0.0556 0.53217,-0.0252 0.94727,0.3125 0.41509,0.33772 0.93861,1.01123 1.49804,2.15625 a 0.60006002,0.60006002 0 0 0 0.53907,0.33594 h 0.41406 a 0.60006002,0.60006002 0 0 0 0.54101,-0.33789 c 0.54756,-1.13491 1.06338,-1.80121 1.47657,-2.13476 0.41318,-0.3336 0.68072,-0.3648 0.95898,-0.3086 0.55653,0.1125 1.2624,0.90264 1.7168,1.57227 a 0.60006002,0.60006002 0 1 0 0.99218,-0.67383 c -0.49155,-0.72441 -1.2401,-1.82545 -2.4707,-2.07422 -0.6153,-0.12438 -1.32524,0.0455 -1.95117,0.55078 -0.51038,0.41204 -0.98784,1.19591 -1.4707,2.07617 -0.49098,-0.88906 -0.97541,-1.67806 -1.48633,-2.09375 -0.46868,-0.38133 -0.98509,-0.5741 -1.47266,-0.59375 z M 202.23047,353 c -0.77376,-7.6e-4 -1.47981,0.46475 -2.07031,1.12109 a 0.60022344,0.60022344 0 1 0 0.89257,0.80274 c 0.54185,-0.60226 0.93231,-0.77859 1.30469,-0.71289 0.37239,0.0657 0.94999,0.47591 1.63867,1.53906 a 0.60006002,0.60006002 0 0 0 1.00782,0 c 0.68868,-1.06315 1.26628,-1.47336 1.63867,-1.53906 0.37238,-0.0657 0.76284,0.11063 1.30469,0.71289 a 0.60022344,0.60022344 0 1 0 0.89257,-0.80274 c -0.67486,-0.75011 -1.50108,-1.25149 -2.40625,-1.09179 -0.70977,0.12522 -1.32665,0.68468 -1.93359,1.45508 -0.60694,-0.7704 -1.22382,-1.32986 -1.93359,-1.45508 -0.11315,-0.02 -0.2254,-0.0292 -0.33594,-0.0293 z" transform="matrix(-1,0,0,1,382.99922,15.999998)" id="path23960" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 185.50195,372 c 1.37479,0 2.5,1.12521 2.5,2.5 0,1.37479 -1.12521,2.5 -2.5,2.5 -1.37479,0 -2.5,-1.12521 -2.5,-2.5 0,-1.37479 1.12521,-2.5 2.5,-2.5 z" id="circle24296" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g24237" transform="translate(-1.8536743e-6,21.000005)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 176.49609,335 c -1.37479,0 -2.5,1.12521 -2.5,2.5 0,1.37479 1.12521,2.5 2.5,2.5 1.37479,0 2.5,-1.12521 2.5,-2.5 0,-1.37479 -1.12521,-2.5 -2.5,-2.5 z" id="circle24230" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 181.54297,326 a 0.60006002,0.60006002 0 1 0 0,1.19922 h 0.97656 c 1.24133,0 2.31915,0.34169 3.06836,0.9668 0.74922,0.6251 1.21289,1.52687 1.21289,2.85156 0,2.62859 -2.35092,5.18453 -6.32422,5.78906 a 0.60006002,0.60006002 0 1 0 0.18164,1.18555 c 4.40846,-0.67075 7.3418,-3.63746 7.3418,-6.97461 0,-1.62072 -0.62669,-2.92584 -1.64258,-3.77344 C 185.34154,326.39654 183.97898,326 182.51953,326 Z" id="path24226" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g24286" transform="matrix(-1,0,0,1,319.99683,63.000005)">
- <path sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" d="m 153,284 v 2 h 2 v -2 z m 2,2 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 2,0 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m -6,8 v -2 h -2 v 2 z m 0,-2 h 2 v -2 h -2 z m 0,-2 v -2 h -2 v 2 z m 2,0 h 2 v -2 h -2 z m 2,0 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m -2,2 h -2 v 2 h 2 z" id="path24240" inkscape:connector-curvature="0" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 163.99805,292.00391 c -1.65006,0 -2.99805,1.34799 -2.99805,2.99804 0,1.65006 1.34799,2.99805 2.99805,2.99805 1.65005,0 2.99804,-1.34799 2.99804,-2.99805 0,-1.65005 -1.34799,-2.99804 -2.99804,-2.99804 z" id="circle24230-9" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- </g>
- <g id="g24294" style="display:inline;fill:#ffffff;enable-background:new" transform="translate(83.999995,110)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 185.48047,363.06055 c -0.59845,-0.12754 -1.28387,0.0442 -1.90039,0.56445 -0.53509,0.4515 -1.05167,1.28657 -1.57813,2.31055 -0.51724,-1.01439 -1.02781,-1.84334 -1.5625,-2.29102 -0.61731,-0.51686 -1.30605,-0.68638 -1.90625,-0.56055 -1.20039,0.25167 -1.95047,1.38331 -2.44726,2.14258 a 0.50005,0.50005 0 1 0 0.83594,0.54688 c 0.467,-0.71375 1.196,-1.58087 1.8164,-1.71094 0.3102,-0.065 0.61722,-0.0219 1.0586,0.34766 0.44137,0.36955 0.97784,1.09019 1.54101,2.30078 A 0.50005,0.50005 0 0 0 181.79102,367 h 0.42187 a 0.50005,0.50005 0 0 0 0.45313,-0.28711 c 0.57516,-1.22093 1.11551,-1.9484 1.55859,-2.32227 0.44308,-0.37386 0.74393,-0.41807 1.04687,-0.35351 0.60589,0.12912 1.32737,1.00382 1.80664,1.73633 a 0.50005,0.50005 0 1 0 0.83594,-0.54688 c -0.50216,-0.76749 -1.23669,-1.91095 -2.43359,-2.16601 z M 176.5,370.0332 c -0.89413,-0.17031 -1.70729,0.35696 -2.38477,1.16992 a 0.50064923,0.50064923 0 1 0 0.76954,0.64063 c 0.57252,-0.68703 1.00936,-0.90781 1.42773,-0.82813 0.41837,0.0797 1.03934,0.56817 1.75781,1.76563 a 0.50005,0.50005 0 0 0 0.85938,0 c 0.71847,-1.19746 1.33944,-1.68594 1.75781,-1.76563 0.41837,-0.0797 0.85521,0.1411 1.42773,0.82813 a 0.50064923,0.50064923 0 1 0 0.76954,-0.64063 c -0.67748,-0.81296 -1.49064,-1.34023 -2.38477,-1.16992 -0.73042,0.13913 -1.36539,0.76726 -2,1.66797 -0.63461,-0.90071 -1.26958,-1.52884 -2,-1.66797 z m 6.18555,4.01758 c -0.21091,-0.0352 -0.44348,0.01 -0.63282,0.10938 -0.37867,0.19867 -0.6452,0.54404 -0.97656,1.07422 a 0.50018582,0.50018582 0 1 0 0.84766,0.53124 c 0.29364,-0.46982 0.52711,-0.68574 0.59375,-0.7207 0.0333,-0.0175 0.0107,-0.007 0.004,-0.008 -0.007,-0.001 0.0186,0.003 0.0781,0.0488 0.23799,0.1848 0.74712,0.97866 1.54492,1.78906 a 0.50005,0.50005 0 0 0 0.71094,0 c 0.7978,-0.8104 1.30693,-1.60426 1.54492,-1.78906 0.0595,-0.0462 0.0849,-0.05 0.0781,-0.0488 -0.007,10e-4 -0.0294,-0.01 0.004,0.008 0.0666,0.035 0.30011,0.25088 0.59375,0.7207 a 0.50018582,0.50018582 0 1 0 0.84766,-0.53124 c -0.33136,-0.53018 -0.59789,-0.87555 -0.97656,-1.07422 -0.18934,-0.0993 -0.42191,-0.14455 -0.63282,-0.10938 -0.2109,0.0352 -0.38371,0.13261 -0.52734,0.24414 -0.45025,0.34963 -0.83062,0.92221 -1.28711,1.47266 -0.45649,-0.55045 -0.83686,-1.12303 -1.28711,-1.47266 -0.14363,-0.11153 -0.31644,-0.20897 -0.52734,-0.24414 z" id="path24292" inkscape:connector-curvature="0"/>
- </g>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" transform="rotate(90,171,281.00001)" id="g24322" style="display:inline;fill:#ffffff;enable-background:new">
- <g style="fill:#ffffff;stroke:#ffffff" transform="rotate(-90,244.00797,459)" id="g24320">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 267.50195,451.98633 a 0.50005,0.50005 0 0 0 -0.34765,0.85937 l 2.66015,2.66016 -2.67383,2.89648 a 0.50005,0.50005 0 0 0 -0.13281,0.33985 v 0.5 a 0.50005,0.50005 0 0 0 0.13281,0.33984 l 2.67383,2.89649 -2.66015,2.66015 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 3,-3 a 0.50005,0.50005 0 0 0 0.0137,-0.69336 l -2.86719,-3.10546 v -0.10938 l 2.86719,-3.10547 a 0.50005,0.50005 0 0 0 -0.0137,-0.69336 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z" id="path24314" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.85;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 263.50195,451.98633 a 0.50005,0.50005 0 0 0 -0.34765,0.85937 l 2.66015,2.66016 -2.67383,2.89648 a 0.50005,0.50005 0 0 0 -0.13281,0.33985 v 0.5 a 0.50005,0.50005 0 0 0 0.13281,0.33984 l 2.67383,2.89649 -2.66015,2.66015 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 3,-3 a 0.50005,0.50005 0 0 0 0.0137,-0.69336 l -2.86719,-3.10546 v -0.10938 l 2.86719,-3.10547 a 0.50005,0.50005 0 0 0 -0.0137,-0.69336 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z" id="path24324" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 259.50195,451.98633 a 0.50005,0.50005 0 0 0 -0.34765,0.85937 l 2.66015,2.66016 -2.67383,2.89648 a 0.50005,0.50005 0 0 0 -0.13281,0.33985 v 0.5 a 0.50005,0.50005 0 0 0 0.13281,0.33984 l 2.67383,2.89649 -2.66015,2.66015 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 3,-3 a 0.50005,0.50005 0 0 0 0.0137,-0.69336 l -2.86719,-3.10546 v -0.10938 l 2.86719,-3.10547 a 0.50005,0.50005 0 0 0 -0.0137,-0.69336 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z" id="path24326" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 118.89062,157.9668 c -1.59478,-0.0195 -3.16997,0.53887 -4.2539,1.6914 l -0.74024,0.73828 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 2,2 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 0.5,-0.5 c 0.5849,-0.58491 1.58165,-0.89809 2.3457,-0.69336 0.80156,0.21477 1.42585,0.83907 1.64062,1.64062 0.20473,0.76404 -0.10844,1.76078 -0.69336,2.3457 l -0.5,0.5 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 2,2 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 0.75,-0.75 c 2.22378,-2.22379 2.21818,-6.29752 -0.0977,-8.61329 -1.15793,-1.15796 -2.77045,-1.75392 -4.36524,-1.77343 z m -6.14848,3.7832 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -1.25,1.25 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 2,2 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 1.25,-1.25 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -2,-2 c -0.0957,-0.0957 -0.226,-0.14854 -0.36128,-0.14648 z m 6.00019,6 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -1.25,1.25 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 2,2 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 1.25,-1.25 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -2,-2 c -0.0957,-0.0957 -0.22612,-0.14859 -0.36147,-0.14648 z"
+ id="path21201-1"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccscccccccccccccccccccccccccccccc" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22386"
+ transform="translate(-886.00002,80.000125)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 433,263 c -3.84758,0 -6.97776,3.12003 -6.99805,6.96289 -6e-5,0.0125 -0.002,0.0246 -0.002,0.0371 a 0.50004994,0.50004994 0 0 0 0.002,0.0488 0.50004994,0.50004994 0 0 0 0,0.002 l -0.01,6.45508 a 0.50005,0.50005 0 0 0 0.50195,0.50195 L 432.96484,277 A 0.50004994,0.50004994 0 0 0 433,277 c 0.0171,0 0.0337,-0.002 0.0508,-0.002 a 0.50005,0.50005 0 0 0 0.008,0 C 436.89154,276.96613 440,273.84031 440,270 c 0,-3.86007 -3.1399,-7 -7,-7 z m 0,1 c 3.3196,0 6,2.68037 6,6 0,3.31963 -2.6804,6 -6,6 l -6.00781,0.008 0.01,-6.00781 a 0.50005,0.50005 0 0 0 0,-0.0215 C 427.01364,266.66895 429.68766,264 433,264 Z"
+ transform="translate(886.00002,-80.000125)"
+ id="path22377"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1314.5,189 a 0.50005,0.50005 0 1 0 0,1 h 4.5 v 4.5 a 0.50005,0.50005 0 1 0 1,0 v -5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path22381"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22599"
+ transform="translate(-1.8536743e-6,-21.999995)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 132.5,285 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
+ id="path22722"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 139,287 c -2.75493,0 -5,2.24492 -5,5 0,2.75508 2.24507,5 5,5 2.75493,0 5,-2.24492 5,-5 0,-2.75508 -2.24507,-5 -5,-5 z m 0,1.09961 c 2.1604,0 3.90039,1.73975 3.90039,3.90039 0,2.16064 -1.73999,3.90039 -3.90039,3.90039 -2.1604,0 -3.90039,-1.73975 -3.90039,-3.90039 0,-2.16064 1.73999,-3.90039 3.90039,-3.90039 z"
+ id="ellipse22724"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
+ transform="translate(-356.99997,168.00001)"
+ id="g23559">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 495.49219,199.99219 A 0.50005,0.50005 0 0 0 495,200.5 v 6.79297 l -3.85352,3.85351 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 495.70703,208 H 502.5 a 0.50005,0.50005 0 1 0 0,-1 H 496 v -6.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path23553"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 499.49023,202.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -2,2 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2,-2 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z M 489.5,207 a 0.50005,0.50005 0 1 0 0,1 h 3.25 a 0.50005,0.50005 0 1 0 0,-1 z m 5.99219,2.74219 A 0.50005,0.50005 0 0 0 495,210.25 v 3.25 a 0.50005,0.50005 0 1 0 1,0 v -3.25 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path23557"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 163.00977,368 c -1.1753,0 -2.25213,0.41841 -2.88477,1.18164 a 0.50005,0.50005 0 1 0 0.76953,0.63672 C 161.27001,369.36537 162.08306,369 163.00977,369 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 z m -1.44141,3.00391 c -1.72788,-0.20328 -3.32792,0.12142 -4.53125,0.90234 -1.20333,0.78092 -1.99513,2.0489 -2.02734,3.58398 v 0.004 0.006 c 0,1.08246 0.28424,1.81368 0.53711,2.38867 0.25286,0.575 0.45312,0.97127 0.45312,1.61133 0,0.46148 -0.10735,0.76987 -0.43555,1.02734 -0.3282,0.25748 -0.96151,0.47266 -2.05468,0.47266 a 0.50005,0.50005 0 1 0 0,1 c 1.21947,0 2.08348,-0.22395 2.67187,-0.68555 C 156.77003,380.85286 157,380.16225 157,379.5 c 0,-0.85994 -0.29523,-1.46367 -0.53711,-2.01367 -0.24115,-0.54835 -0.44991,-1.06809 -0.45117,-1.98047 0.0269,-1.212 0.60444,-2.1349 1.57031,-2.76172 0.96712,-0.62763 2.33652,-0.92835 3.86914,-0.74805 1.98998,0.23412 3.41358,1.22813 4.10352,2.33203 0.68994,1.10391 0.68215,2.23778 -0.14844,3.06836 -0.83795,0.83796 -1.98844,0.89361 -3.08398,0.26368 -1.09554,-0.62994 -2.08047,-1.9799 -2.31446,-3.96875 a 0.50051111,0.50051111 0 1 0 -0.99414,0.11718 c 0.26602,2.26115 1.40609,3.91119 2.81055,4.71875 1.40446,0.80757 3.12702,0.73822 4.28906,-0.42382 1.16941,-1.16942 1.16162,-2.91055 0.28906,-4.30664 -0.87256,-1.3961 -2.57396,-2.52709 -4.83398,-2.79297 z"
+ id="path23575"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="matrix(-1,0,0,1,382.99922,-15.999998)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g24066">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 198.03906,347.00195 c -0.16252,-0.007 -0.32108,0.006 -0.47461,0.0371 -1.22821,0.25238 -1.95915,1.36682 -2.45507,2.09766 a 0.60006002,0.60006002 0 1 0 0.99218,0.67383 c 0.46736,-0.68874 1.16385,-1.48449 1.70508,-1.59571 0.27061,-0.0556 0.53217,-0.0252 0.94727,0.3125 0.41509,0.33772 0.93861,1.01123 1.49804,2.15625 a 0.60006002,0.60006002 0 0 0 0.53907,0.33594 h 0.41406 a 0.60006002,0.60006002 0 0 0 0.54101,-0.33789 c 0.54756,-1.13491 1.06338,-1.80121 1.47657,-2.13476 0.41318,-0.3336 0.68072,-0.3648 0.95898,-0.3086 0.55653,0.1125 1.2624,0.90264 1.7168,1.57227 a 0.60006002,0.60006002 0 1 0 0.99218,-0.67383 c -0.49155,-0.72441 -1.2401,-1.82545 -2.4707,-2.07422 -0.6153,-0.12438 -1.32524,0.0455 -1.95117,0.55078 -0.51038,0.41204 -0.98784,1.19591 -1.4707,2.07617 -0.49098,-0.88906 -0.97541,-1.67806 -1.48633,-2.09375 -0.46868,-0.38133 -0.98509,-0.5741 -1.47266,-0.59375 z M 202.23047,353 c -0.77376,-7.6e-4 -1.47981,0.46475 -2.07031,1.12109 a 0.60022344,0.60022344 0 1 0 0.89257,0.80274 c 0.54185,-0.60226 0.93231,-0.77859 1.30469,-0.71289 0.37239,0.0657 0.94999,0.47591 1.63867,1.53906 a 0.60006002,0.60006002 0 0 0 1.00782,0 c 0.68868,-1.06315 1.26628,-1.47336 1.63867,-1.53906 0.37238,-0.0657 0.76284,0.11063 1.30469,0.71289 a 0.60022344,0.60022344 0 1 0 0.89257,-0.80274 c -0.67486,-0.75011 -1.50108,-1.25149 -2.40625,-1.09179 -0.70977,0.12522 -1.32665,0.68468 -1.93359,1.45508 -0.60694,-0.7704 -1.22382,-1.32986 -1.93359,-1.45508 -0.11315,-0.02 -0.2254,-0.0292 -0.33594,-0.0293 z"
+ transform="matrix(-1,0,0,1,382.99922,15.999998)"
+ id="path23960"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 185.50195,372 c 1.37479,0 2.5,1.12521 2.5,2.5 0,1.37479 -1.12521,2.5 -2.5,2.5 -1.37479,0 -2.5,-1.12521 -2.5,-2.5 0,-1.37479 1.12521,-2.5 2.5,-2.5 z"
+ id="circle24296"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g24237"
+ transform="translate(-1.8536743e-6,21.000005)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 176.49609,335 c -1.37479,0 -2.5,1.12521 -2.5,2.5 0,1.37479 1.12521,2.5 2.5,2.5 1.37479,0 2.5,-1.12521 2.5,-2.5 0,-1.37479 -1.12521,-2.5 -2.5,-2.5 z"
+ id="circle24230"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 181.54297,326 a 0.60006002,0.60006002 0 1 0 0,1.19922 h 0.97656 c 1.24133,0 2.31915,0.34169 3.06836,0.9668 0.74922,0.6251 1.21289,1.52687 1.21289,2.85156 0,2.62859 -2.35092,5.18453 -6.32422,5.78906 a 0.60006002,0.60006002 0 1 0 0.18164,1.18555 c 4.40846,-0.67075 7.3418,-3.63746 7.3418,-6.97461 0,-1.62072 -0.62669,-2.92584 -1.64258,-3.77344 C 185.34154,326.39654 183.97898,326 182.51953,326 Z"
+ id="path24226"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g24286"
+ transform="matrix(-1,0,0,1,319.99683,63.000005)">
+ <path
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 153,284 v 2 h 2 v -2 z m 2,2 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 2,0 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m -6,8 v -2 h -2 v 2 z m 0,-2 h 2 v -2 h -2 z m 0,-2 v -2 h -2 v 2 z m 2,0 h 2 v -2 h -2 z m 2,0 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m -2,2 h -2 v 2 h 2 z"
+ id="path24240"
+ inkscape:connector-curvature="0"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 163.99805,292.00391 c -1.65006,0 -2.99805,1.34799 -2.99805,2.99804 0,1.65006 1.34799,2.99805 2.99805,2.99805 1.65005,0 2.99804,-1.34799 2.99804,-2.99805 0,-1.65005 -1.34799,-2.99804 -2.99804,-2.99804 z"
+ id="circle24230-9"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
+ <g
+ id="g24294"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(83.999995,110)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 185.48047,363.06055 c -0.59845,-0.12754 -1.28387,0.0442 -1.90039,0.56445 -0.53509,0.4515 -1.05167,1.28657 -1.57813,2.31055 -0.51724,-1.01439 -1.02781,-1.84334 -1.5625,-2.29102 -0.61731,-0.51686 -1.30605,-0.68638 -1.90625,-0.56055 -1.20039,0.25167 -1.95047,1.38331 -2.44726,2.14258 a 0.50005,0.50005 0 1 0 0.83594,0.54688 c 0.467,-0.71375 1.196,-1.58087 1.8164,-1.71094 0.3102,-0.065 0.61722,-0.0219 1.0586,0.34766 0.44137,0.36955 0.97784,1.09019 1.54101,2.30078 A 0.50005,0.50005 0 0 0 181.79102,367 h 0.42187 a 0.50005,0.50005 0 0 0 0.45313,-0.28711 c 0.57516,-1.22093 1.11551,-1.9484 1.55859,-2.32227 0.44308,-0.37386 0.74393,-0.41807 1.04687,-0.35351 0.60589,0.12912 1.32737,1.00382 1.80664,1.73633 a 0.50005,0.50005 0 1 0 0.83594,-0.54688 c -0.50216,-0.76749 -1.23669,-1.91095 -2.43359,-2.16601 z M 176.5,370.0332 c -0.89413,-0.17031 -1.70729,0.35696 -2.38477,1.16992 a 0.50064923,0.50064923 0 1 0 0.76954,0.64063 c 0.57252,-0.68703 1.00936,-0.90781 1.42773,-0.82813 0.41837,0.0797 1.03934,0.56817 1.75781,1.76563 a 0.50005,0.50005 0 0 0 0.85938,0 c 0.71847,-1.19746 1.33944,-1.68594 1.75781,-1.76563 0.41837,-0.0797 0.85521,0.1411 1.42773,0.82813 a 0.50064923,0.50064923 0 1 0 0.76954,-0.64063 c -0.67748,-0.81296 -1.49064,-1.34023 -2.38477,-1.16992 -0.73042,0.13913 -1.36539,0.76726 -2,1.66797 -0.63461,-0.90071 -1.26958,-1.52884 -2,-1.66797 z m 6.18555,4.01758 c -0.21091,-0.0352 -0.44348,0.01 -0.63282,0.10938 -0.37867,0.19867 -0.6452,0.54404 -0.97656,1.07422 a 0.50018582,0.50018582 0 1 0 0.84766,0.53124 c 0.29364,-0.46982 0.52711,-0.68574 0.59375,-0.7207 0.0333,-0.0175 0.0107,-0.007 0.004,-0.008 -0.007,-0.001 0.0186,0.003 0.0781,0.0488 0.23799,0.1848 0.74712,0.97866 1.54492,1.78906 a 0.50005,0.50005 0 0 0 0.71094,0 c 0.7978,-0.8104 1.30693,-1.60426 1.54492,-1.78906 0.0595,-0.0462 0.0849,-0.05 0.0781,-0.0488 -0.007,10e-4 -0.0294,-0.01 0.004,0.008 0.0666,0.035 0.30011,0.25088 0.59375,0.7207 a 0.50018582,0.50018582 0 1 0 0.84766,-0.53124 c -0.33136,-0.53018 -0.59789,-0.87555 -0.97656,-1.07422 -0.18934,-0.0993 -0.42191,-0.14455 -0.63282,-0.10938 -0.2109,0.0352 -0.38371,0.13261 -0.52734,0.24414 -0.45025,0.34963 -0.83062,0.92221 -1.28711,1.47266 -0.45649,-0.55045 -0.83686,-1.12303 -1.28711,-1.47266 -0.14363,-0.11153 -0.31644,-0.20897 -0.52734,-0.24414 z"
+ id="path24292"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="rotate(90,171,281.00001)"
+ id="g24322"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <g
+ style="fill:#ffffff;stroke:#ffffff"
+ transform="rotate(-90,244.00797,459)"
+ id="g24320">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 267.50195,451.98633 a 0.50005,0.50005 0 0 0 -0.34765,0.85937 l 2.66015,2.66016 -2.67383,2.89648 a 0.50005,0.50005 0 0 0 -0.13281,0.33985 v 0.5 a 0.50005,0.50005 0 0 0 0.13281,0.33984 l 2.67383,2.89649 -2.66015,2.66015 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 3,-3 a 0.50005,0.50005 0 0 0 0.0137,-0.69336 l -2.86719,-3.10546 v -0.10938 l 2.86719,-3.10547 a 0.50005,0.50005 0 0 0 -0.0137,-0.69336 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path24314"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.85;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 263.50195,451.98633 a 0.50005,0.50005 0 0 0 -0.34765,0.85937 l 2.66015,2.66016 -2.67383,2.89648 a 0.50005,0.50005 0 0 0 -0.13281,0.33985 v 0.5 a 0.50005,0.50005 0 0 0 0.13281,0.33984 l 2.67383,2.89649 -2.66015,2.66015 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 3,-3 a 0.50005,0.50005 0 0 0 0.0137,-0.69336 l -2.86719,-3.10546 v -0.10938 l 2.86719,-3.10547 a 0.50005,0.50005 0 0 0 -0.0137,-0.69336 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path24324"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 259.50195,451.98633 a 0.50005,0.50005 0 0 0 -0.34765,0.85937 l 2.66015,2.66016 -2.67383,2.89648 a 0.50005,0.50005 0 0 0 -0.13281,0.33985 v 0.5 a 0.50005,0.50005 0 0 0 0.13281,0.33984 l 2.67383,2.89649 -2.66015,2.66015 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 3,-3 a 0.50005,0.50005 0 0 0 0.0137,-0.69336 l -2.86719,-3.10546 v -0.10938 l 2.86719,-3.10547 a 0.50005,0.50005 0 0 0 -0.0137,-0.69336 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path24326"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g24475" transform="matrix(-1,0,0,1,551.00038,4.4999696e-6)">
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" transform="translate(188,63)" id="g24356">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 265.26367,347.00781 c -0.18015,-0.0118 -0.36127,-0.0106 -0.54101,0.002 -0.71897,0.05 -1.42538,0.29465 -2.03516,0.72656 -1.07953,0.76463 -1.69855,2.00863 -1.68359,3.31055 -0.73615,0.10606 -1.42713,0.4336 -1.96289,0.96289 -0.64152,0.63369 -1.00529,1.49176 -1.03125,2.39062 A 0.50005,0.50005 0 0 0 258,354.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -0.96484 a 0.50005,0.50005 0 0 0 0,-0.0352 c 0,-0.66852 0.26659,-1.30947 0.74219,-1.7793 0.47558,-0.46982 1.12059,-0.7287 1.78906,-0.7207 a 0.50005,0.50005 0 0 0 0.49609,-0.61914 c -0.14075,-1.09982 0.33186,-2.1861 1.23828,-2.82813 0.9161,-0.64887 2.11612,-0.73246 3.11329,-0.21679 C 267.37607,348.85161 268,349.87739 268,351 a 0.50005,0.50005 0 0 0 0.002,0.043 c -0.15856,-0.001 -0.31755,-0.003 -0.47461,0.0137 -0.85318,0.0929 -1.67617,0.45304 -2.33203,1.06641 a 0.5002238,0.5002238 0 1 0 0.6836,0.73047 c 0.98705,-0.92311 2.4814,-1.08629 3.65234,-0.39649 1.17094,0.6898 1.72204,2.04918 1.35937,3.33399 -0.36266,1.2848 -1.55342,2.17677 -2.92187,2.17578 -1.36845,-10e-4 -2.5592,-0.89437 -2.91992,-2.17969 a 0.50005,0.50005 0 0 0 -0.0469,-0.11719 0.50004997,0.50004997 0 0 0 0,-0.002 0.50004997,0.50004997 0 0 0 -0.0156,-0.0977 c -0.19194,-0.87762 -0.95663,-1.51856 -1.85742,-1.56836 -0.9008,-0.0498 -1.73485,0.50125 -2.02539,1.35157 a 0.50060304,0.50060304 0 0 0 0.94726,0.32421 c 0.14448,-0.42284 0.5581,-0.70333 1.02149,-0.67773 0.46338,0.0256 0.84227,0.34777 0.9375,0.7832 a 0.50004997,0.50004997 0 0 0 0.0566,0.1543 0.50005,0.50005 0 0 0 0.0195,0.11914 c 0.4828,1.72035 2.07532,2.90916 3.88086,2.91016 1.80554,10e-4 3.40131,-1.18467 3.88672,-2.9043 0.4854,-1.71963 -0.26339,-3.55306 -1.81446,-4.4668 -0.33807,-0.19915 -0.69725,-0.33834 -1.06445,-0.43164 A 0.50005,0.50005 0 0 0 269,351 c 0,-1.4945 -0.83461,-2.86624 -2.16211,-3.55273 -0.49781,-0.25748 -1.03377,-0.40392 -1.57422,-0.43946 z" transform="matrix(-1,0,0,1,363.00038,-63.000004)" id="path24346" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g24475"
+ transform="matrix(-1,0,0,1,551.00038,4.4999696e-6)">
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ transform="translate(188,63)"
+ id="g24356">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 265.26367,347.00781 c -0.18015,-0.0118 -0.36127,-0.0106 -0.54101,0.002 -0.71897,0.05 -1.42538,0.29465 -2.03516,0.72656 -1.07953,0.76463 -1.69855,2.00863 -1.68359,3.31055 -0.73615,0.10606 -1.42713,0.4336 -1.96289,0.96289 -0.64152,0.63369 -1.00529,1.49176 -1.03125,2.39062 A 0.50005,0.50005 0 0 0 258,354.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -0.96484 a 0.50005,0.50005 0 0 0 0,-0.0352 c 0,-0.66852 0.26659,-1.30947 0.74219,-1.7793 0.47558,-0.46982 1.12059,-0.7287 1.78906,-0.7207 a 0.50005,0.50005 0 0 0 0.49609,-0.61914 c -0.14075,-1.09982 0.33186,-2.1861 1.23828,-2.82813 0.9161,-0.64887 2.11612,-0.73246 3.11329,-0.21679 C 267.37607,348.85161 268,349.87739 268,351 a 0.50005,0.50005 0 0 0 0.002,0.043 c -0.15856,-0.001 -0.31755,-0.003 -0.47461,0.0137 -0.85318,0.0929 -1.67617,0.45304 -2.33203,1.06641 a 0.5002238,0.5002238 0 1 0 0.6836,0.73047 c 0.98705,-0.92311 2.4814,-1.08629 3.65234,-0.39649 1.17094,0.6898 1.72204,2.04918 1.35937,3.33399 -0.36266,1.2848 -1.55342,2.17677 -2.92187,2.17578 -1.36845,-10e-4 -2.5592,-0.89437 -2.91992,-2.17969 a 0.50005,0.50005 0 0 0 -0.0469,-0.11719 0.50004997,0.50004997 0 0 0 0,-0.002 0.50004997,0.50004997 0 0 0 -0.0156,-0.0977 c -0.19194,-0.87762 -0.95663,-1.51856 -1.85742,-1.56836 -0.9008,-0.0498 -1.73485,0.50125 -2.02539,1.35157 a 0.50060304,0.50060304 0 0 0 0.94726,0.32421 c 0.14448,-0.42284 0.5581,-0.70333 1.02149,-0.67773 0.46338,0.0256 0.84227,0.34777 0.9375,0.7832 a 0.50004997,0.50004997 0 0 0 0.0566,0.1543 0.50005,0.50005 0 0 0 0.0195,0.11914 c 0.4828,1.72035 2.07532,2.90916 3.88086,2.91016 1.80554,10e-4 3.40131,-1.18467 3.88672,-2.9043 0.4854,-1.71963 -0.26339,-3.55306 -1.81446,-4.4668 -0.33807,-0.19915 -0.69725,-0.33834 -1.06445,-0.43164 A 0.50005,0.50005 0 0 0 269,351 c 0,-1.4945 -0.83461,-2.86624 -2.16211,-3.55273 -0.49781,-0.25748 -1.03377,-0.40392 -1.57422,-0.43946 z"
+ transform="matrix(-1,0,0,1,363.00038,-63.000004)"
+ id="path24346"
+ inkscape:connector-curvature="0" />
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999976;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 290.99609,357 c -1.09865,0 -2,0.90134 -2,2 0,1.09866 0.90135,2 2,2 1.09866,0 2,-0.90134 2,-2 0,-1.09866 -0.90134,-2 -2,-2 z" id="circle24448" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g24513" transform="matrix(0,1,1,0,-152.00318,47.006352)">
- <g id="g24612" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 142.49609,347.00195 c -1.17351,0 -2.15665,0.82286 -2.42187,1.91797 1.14862,0.70733 2.04128,1.7894 2.50586,3.07422 1.33547,-0.0457 2.41601,-1.14613 2.41601,-2.49219 0,-1.37479 -1.12521,-2.5 -2.5,-2.5 z m 0.50196,8 c -1.65181,0 -3.00196,1.35015 -3.00196,3.00196 0,1.65181 1.35015,3.00195 3.00196,3.00195 1.65181,0 3.00195,-1.35014 3.00195,-3.00195 0,-1.65181 -1.35014,-3.00196 -3.00195,-3.00196 z" transform="matrix(0,1,1,0,-47.006352,152.00318)" id="circle24338" inkscape:connector-curvature="0"/>
- <path id="circle24481" transform="matrix(0,1,1,0,-47.006347,152.00318)" d="m 136.9668,349.03125 c -2.73852,0 -4.97071,2.23218 -4.97071,4.9707 0,2.73853 2.23219,4.96875 4.97071,4.96875 0.74568,0 1.44822,-0.1767 2.08398,-0.47265 -0.0209,-0.16376 -0.0508,-0.32518 -0.0508,-0.49414 0,-0.2598 0.0297,-0.51312 0.0781,-0.75977 -0.60661,0.39452 -1.33048,0.62695 -2.11132,0.62695 -2.14404,0 -3.8711,-1.72509 -3.8711,-3.86914 0,-2.14404 1.72706,-3.87109 3.8711,-3.87109 2.14405,0 3.86914,1.72705 3.86914,3.87109 0,0.23797 -0.0296,0.46946 -0.0703,0.69532 0.35109,-0.23908 0.74721,-0.40722 1.16407,-0.52539 0.002,-0.0568 0.008,-0.11267 0.008,-0.16993 0,-2.73852 -2.23217,-4.9707 -4.9707,-4.9707 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999976;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 290.99609,357 c -1.09865,0 -2,0.90134 -2,2 0,1.09866 0.90135,2 2,2 1.09866,0 2,-0.90134 2,-2 0,-1.09866 -0.90134,-2 -2,-2 z"
+ id="circle24448"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g24513"
+ transform="matrix(0,1,1,0,-152.00318,47.006352)">
+ <g
+ id="g24612"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 142.49609,347.00195 c -1.17351,0 -2.15665,0.82286 -2.42187,1.91797 1.14862,0.70733 2.04128,1.7894 2.50586,3.07422 1.33547,-0.0457 2.41601,-1.14613 2.41601,-2.49219 0,-1.37479 -1.12521,-2.5 -2.5,-2.5 z m 0.50196,8 c -1.65181,0 -3.00196,1.35015 -3.00196,3.00196 0,1.65181 1.35015,3.00195 3.00196,3.00195 1.65181,0 3.00195,-1.35014 3.00195,-3.00195 0,-1.65181 -1.35014,-3.00196 -3.00195,-3.00196 z"
+ transform="matrix(0,1,1,0,-47.006352,152.00318)"
+ id="circle24338"
+ inkscape:connector-curvature="0" />
+ <path
+ id="circle24481"
+ transform="matrix(0,1,1,0,-47.006347,152.00318)"
+ d="m 136.9668,349.03125 c -2.73852,0 -4.97071,2.23218 -4.97071,4.9707 0,2.73853 2.23219,4.96875 4.97071,4.96875 0.74568,0 1.44822,-0.1767 2.08398,-0.47265 -0.0209,-0.16376 -0.0508,-0.32518 -0.0508,-0.49414 0,-0.2598 0.0297,-0.51312 0.0781,-0.75977 -0.60661,0.39452 -1.33048,0.62695 -2.11132,0.62695 -2.14404,0 -3.8711,-1.72509 -3.8711,-3.86914 0,-2.14404 1.72706,-3.87109 3.8711,-3.87109 2.14405,0 3.86914,1.72705 3.86914,3.87109 0,0.23797 -0.0296,0.46946 -0.0703,0.69532 0.35109,-0.23908 0.74721,-0.40722 1.16407,-0.52539 0.002,-0.0568 0.008,-0.11267 0.008,-0.16993 0,-2.73852 -2.23217,-4.9707 -4.9707,-4.9707 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g22255" transform="translate(-1.8536743e-6,-20.999994)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40018749;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 521.5,287 c -5.3,0 -9.5,4.7037 -9.5,9.5 v 1 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1 c 0,-1.05 0.68155,-2.47832 1.73828,-3.59375 C 518.79501,291.79082 520.19444,291 521.5,291 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0,1 h 0.5 v 2 h -0.5 c -1.69444,0 -3.29501,0.95918 -4.48828,2.21875 C 515.81845,293.47832 515,295.05 515,296.5 v 0.5 h -2 v -0.5 c 0,-4.2037 3.8,-8.5 8.5,-8.5 z" id="path21998" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 512.5,263 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 6.60938 c 0.29756,-0.51189 0.62592,-1.00687 1,-1.46876 V 264 h 2 v 2.71875 c 0.32103,-0.24305 0.65292,-0.47168 1,-0.67969 V 263.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" transform="translate(1.8536743e-6,20.999994)" id="path22786" inkscape:connector-curvature="0"/>
- </g>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate" id="rect40784" width="16" height="16" x="110" y="262"/>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g22709" transform="matrix(0,-1,-1,0,408.99494,408.99999)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 153.49219,289.73828 A 0.50005,0.50005 0 0 0 153,290.24414 l -0.008,7.26172 a 0.50005,0.50005 0 0 0 0.50195,0.50195 l 7.25586,-0.0137 a 0.50005,0.50005 0 1 0 0,-1 l -6.75781,0.0137 0.008,-6.76172 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" id="path21430-0" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 115.04297,242 -4,4 h 9.95117 l 0.006,9.95703 3.85352,-3.85351 L 125,251.95703 124.99414,242 Z m 0.41406,1 h 7.9707 l -2,2 h -7.9707 z m 8.53711,0.56641 0.006,7.97656 -2,2 -0.006,-7.97656 z" transform="matrix(0,-1,-1,0,408.99999,408.99494)" id="path21432-2" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g22406" transform="translate(20.999998,-20.999994)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 240.49805,288 -3.00586,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 241,288.5 A 0.50005,0.50005 0 0 0 240.49805,288 Z M 240,289.00195 l -0.008,8.00586 h -2 v -8.00195 z" id="path22383" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 250.49805,284 -3.00586,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 251,284.5 A 0.50005,0.50005 0 0 0 250.49805,284 Z M 250,285.00195 l -0.008,8.00586 h -2 v -8.00195 z M 245.49805,286 l -3.00586,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 246,286.5 A 0.50005,0.50005 0 0 0 245.49805,286 Z M 245,287.00195 l -0.008,8.00586 h -2 v -8.00195 z" id="path22387" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g22579" transform="matrix(-1,0,0,1,571.99995,-62.999994)">
- <g style="opacity:1;fill:#ffffff" id="g22529">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 268.5,242 c -1.88693,0 -3.42464,1.51084 -3.48828,3.38281 -0.009,0.0385 -0.0124,0.0778 -0.0117,0.11719 -4.1e-4,0.0117 -4.1e-4,0.0234 0,0.0352 V 249 h -3.5 c -0.0381,-4.2e-4 -0.0761,0.004 -0.11328,0.0117 C 259.5129,249.07334 258,250.61174 258,252.5 c 0,1.88693 1.51084,3.42464 3.38281,3.48828 0.0385,0.009 0.0778,0.0124 0.11719,0.0117 h 7 c 0.92807,0 1.81837,-0.36915 2.47461,-1.02539 C 271.63085,254.31837 272,253.42807 272,252.5 v -7 c 7.2e-4,-0.0394 -0.003,-0.0787 -0.0117,-0.11719 C 271.92462,243.51084 270.38693,242 268.5,242 Z m 0,1 c 1.38663,0 2.5,1.11337 2.5,2.5 -4.1e-4,0.0117 -4.1e-4,0.0234 0,0.0352 V 252.5 c 0,0.66323 -0.26345,1.2986 -0.73242,1.76758 C 269.7986,254.73655 269.16323,255 268.5,255 h -7 c -1.38663,0 -2.5,-1.11337 -2.5,-2.5 0,-1.38663 1.11337,-2.5 2.5,-2.5 h 3.75 c 0.1326,-2e-5 0.25976,-0.0527 0.35352,-0.14648 l 0.25,-0.25 c 0.0938,-0.0938 0.14646,-0.22092 0.14648,-0.35352 v -3.75 c 0,-1.38663 1.11337,-2.5 2.5,-2.5 z" transform="matrix(-1,0,0,1,571.99995,62.999994)" id="path22488" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g22255"
+ transform="translate(-1.8536743e-6,-20.999994)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40018749;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 521.5,287 c -5.3,0 -9.5,4.7037 -9.5,9.5 v 1 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1 c 0,-1.05 0.68155,-2.47832 1.73828,-3.59375 C 518.79501,291.79082 520.19444,291 521.5,291 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0,1 h 0.5 v 2 h -0.5 c -1.69444,0 -3.29501,0.95918 -4.48828,2.21875 C 515.81845,293.47832 515,295.05 515,296.5 v 0.5 h -2 v -0.5 c 0,-4.2037 3.8,-8.5 8.5,-8.5 z"
+ id="path21998"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 512.5,263 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 6.60938 c 0.29756,-0.51189 0.62592,-1.00687 1,-1.46876 V 264 h 2 v 2.71875 c 0.32103,-0.24305 0.65292,-0.47168 1,-0.67969 V 263.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ transform="translate(1.8536743e-6,20.999994)"
+ id="path22786"
+ inkscape:connector-curvature="0" />
+ </g>
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
+ id="rect40784"
+ width="16"
+ height="16"
+ x="110"
+ y="262" />
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g22709"
+ transform="matrix(0,-1,-1,0,408.99494,408.99999)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 153.49219,289.73828 A 0.50005,0.50005 0 0 0 153,290.24414 l -0.008,7.26172 a 0.50005,0.50005 0 0 0 0.50195,0.50195 l 7.25586,-0.0137 a 0.50005,0.50005 0 1 0 0,-1 l -6.75781,0.0137 0.008,-6.76172 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path21430-0"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 115.04297,242 -4,4 h 9.95117 l 0.006,9.95703 3.85352,-3.85351 L 125,251.95703 124.99414,242 Z m 0.41406,1 h 7.9707 l -2,2 h -7.9707 z m 8.53711,0.56641 0.006,7.97656 -2,2 -0.006,-7.97656 z"
+ transform="matrix(0,-1,-1,0,408.99999,408.99494)"
+ id="path21432-2"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g22406"
+ transform="translate(20.999998,-20.999994)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 240.49805,288 -3.00586,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 241,288.5 A 0.50005,0.50005 0 0 0 240.49805,288 Z M 240,289.00195 l -0.008,8.00586 h -2 v -8.00195 z"
+ id="path22383"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 250.49805,284 -3.00586,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 251,284.5 A 0.50005,0.50005 0 0 0 250.49805,284 Z M 250,285.00195 l -0.008,8.00586 h -2 v -8.00195 z M 245.49805,286 l -3.00586,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 246,286.5 A 0.50005,0.50005 0 0 0 245.49805,286 Z M 245,287.00195 l -0.008,8.00586 h -2 v -8.00195 z"
+ id="path22387"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g22579"
+ transform="matrix(-1,0,0,1,571.99995,-62.999994)">
+ <g
+ style="opacity:1;fill:#ffffff"
+ id="g22529">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 268.5,242 c -1.88693,0 -3.42464,1.51084 -3.48828,3.38281 -0.009,0.0385 -0.0124,0.0778 -0.0117,0.11719 -4.1e-4,0.0117 -4.1e-4,0.0234 0,0.0352 V 249 h -3.5 c -0.0381,-4.2e-4 -0.0761,0.004 -0.11328,0.0117 C 259.5129,249.07334 258,250.61174 258,252.5 c 0,1.88693 1.51084,3.42464 3.38281,3.48828 0.0385,0.009 0.0778,0.0124 0.11719,0.0117 h 7 c 0.92807,0 1.81837,-0.36915 2.47461,-1.02539 C 271.63085,254.31837 272,253.42807 272,252.5 v -7 c 7.2e-4,-0.0394 -0.003,-0.0787 -0.0117,-0.11719 C 271.92462,243.51084 270.38693,242 268.5,242 Z m 0,1 c 1.38663,0 2.5,1.11337 2.5,2.5 -4.1e-4,0.0117 -4.1e-4,0.0234 0,0.0352 V 252.5 c 0,0.66323 -0.26345,1.2986 -0.73242,1.76758 C 269.7986,254.73655 269.16323,255 268.5,255 h -7 c -1.38663,0 -2.5,-1.11337 -2.5,-2.5 0,-1.38663 1.11337,-2.5 2.5,-2.5 h 3.75 c 0.1326,-2e-5 0.25976,-0.0527 0.35352,-0.14648 l 0.25,-0.25 c 0.0938,-0.0938 0.14646,-0.22092 0.14648,-0.35352 v -3.75 c 0,-1.38663 1.11337,-2.5 2.5,-2.5 z"
+ transform="matrix(-1,0,0,1,571.99995,62.999994)"
+ id="path22488"
+ inkscape:connector-curvature="0" />
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 303.49219,307.99219 A 0.50005,0.50005 0 0 0 303,308.5 v 6.91992 a 0.50005,0.50005 0 0 0 0.11328,0.4043 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 303.58203,316 H 310.5 a 0.50005,0.50005 0 1 0 0,-1 H 304 v -6.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" id="path22537" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" transform="matrix(-1,0,0,1,550.99293,-20.999994)" id="g22139">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 310.5,287 -10.00781,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 311,287.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -0.5,1 -0.008,9.00781 h -9 v -9.00195 z" id="path22135" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 300.5,284 a 0.50005,0.50005 0 1 0 0,1 h 10 a 0.50005,0.50005 0 1 0 0,-1 z m 12.99219,2.99219 A 0.50005,0.50005 0 0 0 313,287.5 l -0.008,10.00586 a 0.50005,0.50005 0 1 0 1,0.002 L 314,287.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" id="path22141" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g22221" transform="translate(20.999998,-20.999994)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 48.5,267 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 9 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 13 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -6 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 H 54 v -2.5 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z m 0.5,1 h 4 v 2 h -4 z m 0,3 h 2 v 2 h -2 z m 3,0 h 4 v 2 h -4 z m 5,0 h 4 v 2 h -4 z m -8,3 h 4 v 2 h -4 z m 5,0 h 4 v 2 h -4 z m 5,0 h 2 v 2 h -2 z" transform="translate(-20.999998,20.999994)" id="rect22184" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 40.5,284 a 0.50005,0.50005 0 0 1 0.5,0.5 v 3 a 0.50005,0.50005 0 0 1 -0.5,0.5 h -5 A 0.50005,0.50005 0 0 1 35,287.5 v -3 a 0.50005,0.50005 0 0 1 0.5,-0.5 z m -0.5,1 h -4 v 2 h 4 z" id="rect22200" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g21692" transform="translate(-1.8536743e-6,-41.999984)">
- <g transform="translate(-63)" style="display:inline;opacity:1;fill:#ffffff;stroke:#f9f9f9;enable-background:new" id="g21667">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:6.5999999;stroke-opacity:1;marker:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 145.49219,241.99219 A 0.50005,0.50005 0 0 0 145,242.5 c 0,1.27778 -0.82701,2.37965 -2.66602,3.44141 -1.66335,0.96034 -4.28314,1.19403 -6.30078,1.06054 -0.9786,-0.0647 -1.78811,-0.30625 -2.3125,-0.61133 -0.52058,-0.30284 -0.71591,-0.62257 -0.71875,-0.88476 0.003,-0.26222 0.19817,-0.58387 0.71875,-0.88672 0.5244,-0.30506 1.3339,-0.54463 2.3125,-0.60937 1.74084,-0.11517 3.90302,0.0169 5.24414,0.6875 a 0.50005,0.50005 0 1 0 0.44532,-0.89454 c -1.65888,-0.82943 -3.92118,-0.91239 -5.75586,-0.79101 -1.10098,0.0728 -2.04234,0.3336 -2.74805,0.74414 -0.63776,0.37101 -1.097,0.90981 -1.18359,1.55273 A 0.50005,0.50005 0 0 0 132,245.5 c 0,0.002 0.002,0.004 0.002,0.006 -1e-5,0.002 -0.002,0.004 -0.002,0.006 a 0.50005,0.50005 0 0 0 0.0352,0.18945 0.50005,0.50005 0 0 0 0.002,0.006 c 0.0881,0.64105 0.54525,1.17861 1.18164,1.54883 0.70571,0.41055 1.64707,0.66937 2.74805,0.74219 2.1415,0.14167 4.88621,-0.0477 6.86718,-1.19141 C 144.82884,245.65491 146,244.22222 146,242.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -0.27539,5.25195 a 0.50005,0.50005 0 0 0 -0.4375,0.67578 C 144.90088,248.25504 145,248.58141 145,249 c 0,1.83333 -0.82701,2.87965 -2.66602,3.94141 -1.66335,0.96034 -4.28314,1.19403 -6.30078,1.06054 -0.9786,-0.0647 -1.78811,-0.30625 -2.3125,-0.61133 -0.52058,-0.30284 -0.71591,-0.62257 -0.71875,-0.88476 0.003,-0.26222 0.19817,-0.58387 0.71875,-0.88672 0.5244,-0.30506 1.3339,-0.54463 2.3125,-0.60937 1.74084,-0.11517 3.90302,0.0169 5.24414,0.6875 a 0.50005,0.50005 0 1 0 0.44532,-0.89454 c -1.65888,-0.82943 -3.92118,-0.91239 -5.75586,-0.79101 -1.10098,0.0728 -2.04234,0.3336 -2.74805,0.74414 -0.63776,0.37101 -1.097,0.90981 -1.18359,1.55273 A 0.50005,0.50005 0 0 0 132,252.5 c 0,0.002 0.002,0.004 0.002,0.006 -1e-5,0.002 -0.002,0.004 -0.002,0.006 a 0.50005,0.50005 0 0 0 0.0371,0.19531 c 0.0881,0.64105 0.54525,1.17861 1.18164,1.54883 0.70571,0.41055 1.64707,0.66937 2.74805,0.74219 2.1415,0.14167 4.88621,-0.0477 6.86718,-1.19141 1.96806,-1.13625 3.12917,-2.60303 3.16016,-4.72266 A 0.50005,0.50005 0 0 0 146,249 a 0.50005,0.50005 0 0 0 -0.0137,-0.12695 c -0.0205,-0.51808 -0.14222,-0.95284 -0.26563,-1.29297 a 0.50005,0.50005 0 0 0 -0.5039,-0.33594 z m 0.043,7 a 0.50005,0.50005 0 0 0 -0.4336,0.76953 c 0,0 0.17383,0.35663 0.17383,0.51953 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.59989 -0.32617,-1.04687 -0.32617,-1.04687 a 0.50005,0.50005 0 0 0 -0.41406,-0.24219 z" transform="translate(63.000002,41.999984)" id="path21655" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 303.49219,307.99219 A 0.50005,0.50005 0 0 0 303,308.5 v 6.91992 a 0.50005,0.50005 0 0 0 0.11328,0.4043 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 303.58203,316 H 310.5 a 0.50005,0.50005 0 1 0 0,-1 H 304 v -6.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path22537"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ transform="matrix(-1,0,0,1,550.99293,-20.999994)"
+ id="g22139">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 310.5,287 -10.00781,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 311,287.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -0.5,1 -0.008,9.00781 h -9 v -9.00195 z"
+ id="path22135"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 300.5,284 a 0.50005,0.50005 0 1 0 0,1 h 10 a 0.50005,0.50005 0 1 0 0,-1 z m 12.99219,2.99219 A 0.50005,0.50005 0 0 0 313,287.5 l -0.008,10.00586 a 0.50005,0.50005 0 1 0 1,0.002 L 314,287.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path22141"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g22221"
+ transform="translate(20.999998,-20.999994)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 48.5,267 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 9 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 13 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -6 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 H 54 v -2.5 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z m 0.5,1 h 4 v 2 h -4 z m 0,3 h 2 v 2 h -2 z m 3,0 h 4 v 2 h -4 z m 5,0 h 4 v 2 h -4 z m -8,3 h 4 v 2 h -4 z m 5,0 h 4 v 2 h -4 z m 5,0 h 2 v 2 h -2 z"
+ transform="translate(-20.999998,20.999994)"
+ id="rect22184"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 40.5,284 a 0.50005,0.50005 0 0 1 0.5,0.5 v 3 a 0.50005,0.50005 0 0 1 -0.5,0.5 h -5 A 0.50005,0.50005 0 0 1 35,287.5 v -3 a 0.50005,0.50005 0 0 1 0.5,-0.5 z m -0.5,1 h -4 v 2 h 4 z"
+ id="rect22200"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g21692"
+ transform="translate(-1.8536743e-6,-41.999984)">
+ <g
+ transform="translate(-63)"
+ style="display:inline;opacity:1;fill:#ffffff;stroke:#f9f9f9;enable-background:new"
+ id="g21667">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:6.5999999;stroke-opacity:1;marker:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 145.49219,241.99219 A 0.50005,0.50005 0 0 0 145,242.5 c 0,1.27778 -0.82701,2.37965 -2.66602,3.44141 -1.66335,0.96034 -4.28314,1.19403 -6.30078,1.06054 -0.9786,-0.0647 -1.78811,-0.30625 -2.3125,-0.61133 -0.52058,-0.30284 -0.71591,-0.62257 -0.71875,-0.88476 0.003,-0.26222 0.19817,-0.58387 0.71875,-0.88672 0.5244,-0.30506 1.3339,-0.54463 2.3125,-0.60937 1.74084,-0.11517 3.90302,0.0169 5.24414,0.6875 a 0.50005,0.50005 0 1 0 0.44532,-0.89454 c -1.65888,-0.82943 -3.92118,-0.91239 -5.75586,-0.79101 -1.10098,0.0728 -2.04234,0.3336 -2.74805,0.74414 -0.63776,0.37101 -1.097,0.90981 -1.18359,1.55273 A 0.50005,0.50005 0 0 0 132,245.5 c 0,0.002 0.002,0.004 0.002,0.006 -1e-5,0.002 -0.002,0.004 -0.002,0.006 a 0.50005,0.50005 0 0 0 0.0352,0.18945 0.50005,0.50005 0 0 0 0.002,0.006 c 0.0881,0.64105 0.54525,1.17861 1.18164,1.54883 0.70571,0.41055 1.64707,0.66937 2.74805,0.74219 2.1415,0.14167 4.88621,-0.0477 6.86718,-1.19141 C 144.82884,245.65491 146,244.22222 146,242.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -0.27539,5.25195 a 0.50005,0.50005 0 0 0 -0.4375,0.67578 C 144.90088,248.25504 145,248.58141 145,249 c 0,1.83333 -0.82701,2.87965 -2.66602,3.94141 -1.66335,0.96034 -4.28314,1.19403 -6.30078,1.06054 -0.9786,-0.0647 -1.78811,-0.30625 -2.3125,-0.61133 -0.52058,-0.30284 -0.71591,-0.62257 -0.71875,-0.88476 0.003,-0.26222 0.19817,-0.58387 0.71875,-0.88672 0.5244,-0.30506 1.3339,-0.54463 2.3125,-0.60937 1.74084,-0.11517 3.90302,0.0169 5.24414,0.6875 a 0.50005,0.50005 0 1 0 0.44532,-0.89454 c -1.65888,-0.82943 -3.92118,-0.91239 -5.75586,-0.79101 -1.10098,0.0728 -2.04234,0.3336 -2.74805,0.74414 -0.63776,0.37101 -1.097,0.90981 -1.18359,1.55273 A 0.50005,0.50005 0 0 0 132,252.5 c 0,0.002 0.002,0.004 0.002,0.006 -1e-5,0.002 -0.002,0.004 -0.002,0.006 a 0.50005,0.50005 0 0 0 0.0371,0.19531 c 0.0881,0.64105 0.54525,1.17861 1.18164,1.54883 0.70571,0.41055 1.64707,0.66937 2.74805,0.74219 2.1415,0.14167 4.88621,-0.0477 6.86718,-1.19141 1.96806,-1.13625 3.12917,-2.60303 3.16016,-4.72266 A 0.50005,0.50005 0 0 0 146,249 a 0.50005,0.50005 0 0 0 -0.0137,-0.12695 c -0.0205,-0.51808 -0.14222,-0.95284 -0.26563,-1.29297 a 0.50005,0.50005 0 0 0 -0.5039,-0.33594 z m 0.043,7 a 0.50005,0.50005 0 0 0 -0.4336,0.76953 c 0,0 0.17383,0.35663 0.17383,0.51953 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.59989 -0.32617,-1.04687 -0.32617,-1.04687 a 0.50005,0.50005 0 0 0 -0.41406,-0.24219 z"
+ transform="translate(63.000002,41.999984)"
+ id="path21655"
+ inkscape:connector-curvature="0" />
</g>
- <g id="g21673" style="display:inline;opacity:1;fill:#ffffff;stroke:#f9f9f9;enable-background:new" transform="translate(-63,6)"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 219.50391,243 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 218.38224,244.61833 217.33333,245 216.5,245 a 0.50005,0.50005 0 1 0 0,1 c 1.00319,0 2.15225,-0.6005 3,-1.7832 0.82397,1.14952 1.9314,1.74461 2.91406,1.77734 a 0.50005,0.50005 0 0 0 0.002,0 0.50005,0.50005 0 0 0 0.084,0.006 0.50005,0.50005 0 0 0 0.0996,-0.008 c 0.97927,-0.0378 2.08023,-0.63118 2.90039,-1.77539 0.84775,1.1827 1.99681,1.7832 3,1.7832 a 0.50005,0.50005 0 1 0 0,-1 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 225.50391,243 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 224.38224,244.61833 223.33333,245 222.5,245 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 219.50391,243 Z m 1,5 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 219.38224,249.61833 218.33333,250 217.5,250 a 0.50005,0.50005 0 1 0 0,1 c 1.00319,0 2.15225,-0.6005 3,-1.7832 0.82397,1.14952 1.9314,1.74461 2.91406,1.77734 a 0.50005,0.50005 0 0 0 0.002,0 0.50005,0.50005 0 0 0 0.084,0.006 0.50005,0.50005 0 0 0 0.0859,-0.006 0.50005,0.50005 0 0 0 0.0137,-0.002 c 0.97927,-0.0378 2.08023,-0.63118 2.90039,-1.77539 0.84775,1.1827 1.99681,1.7832 3,1.7832 a 0.50005,0.50005 0 1 0 0,-1 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 226.50391,248 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 225.38224,249.61833 224.33333,250 223.5,250 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 220.50391,248 Z m -1,5 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 218.38224,254.61833 217.33333,255 216.5,255 a 0.50005,0.50005 0 1 0 0,1 c 1.00319,0 2.15225,-0.6005 3,-1.7832 0.82397,1.14952 1.9314,1.74461 2.91406,1.77734 a 0.50005,0.50005 0 0 0 0.002,0 0.50005,0.50005 0 0 0 0.084,0.006 0.50005,0.50005 0 0 0 0.0996,-0.008 c 0.97927,-0.0378 2.08023,-0.63118 2.90039,-1.77539 0.84775,1.1827 1.99681,1.7832 3,1.7832 a 0.50005,0.50005 0 1 0 0,-1 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 225.50391,253 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 224.38224,254.61833 223.33333,255 222.5,255 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 219.50391,253 Z" id="path21858" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 97.689453,242.01172 c -0.394683,0.0302 -0.787753,0.12022 -1.167969,0.27148 C 95.00062,242.88827 94,244.36319 94,246 a 0.50005,0.50005 0 0 0 0.01563,0.13281 c -0.365184,0.0927 -0.722816,0.22834 -1.058594,0.42774 -1.441397,0.85595 -2.170881,2.51688 -1.878906,4.14453 -0.687144,0.57705 -1.108155,1.44799 -1.076172,2.39648 0.05016,1.48769 1.192146,2.71921 2.671875,2.88086 1.398175,0.15274 2.699752,-0.69789 3.152344,-2.00781 0.896041,0.0388 1.769696,-0.22225 2.498047,-0.74609 1.073726,0.85551 2.557876,1.01607 3.789066,0.37695 1.30171,-0.67573 2.04374,-2.09602 1.85742,-3.55078 -0.16328,-1.27499 -1.01006,-2.34261 -2.17968,-2.80664 0.45466,-1.38242 0.13144,-2.9211 -0.88477,-3.9961 -0.56221,-0.59473 -1.277273,-0.98709 -2.042974,-1.15625 -0.38285,-0.0846 -0.779145,-0.11418 -1.173828,-0.084 z m 0.521485,0.99609 c 0.734455,0.0517 1.440532,0.37287 1.968752,0.93164 0.84514,0.89404 1.0593,2.20845 0.54101,3.32422 a 0.50005,0.50005 0 0 0 -0.0527,0.2168 0.50005,0.50005 0 0 0 0.38672,0.58203 c 1.02426,0.23341 1.79232,1.07713 1.92578,2.11914 0.13345,1.04201 -0.39575,2.0531 -1.32813,2.53711 -0.93238,0.48401 -2.064441,0.33572 -2.83984,-0.37305 a 0.50005,0.50005 0 0 0 -0.203125,-0.11914 0.50005,0.50005 0 0 0 -0.28125,-0.0977 0.50005,0.50005 0 0 0 -0.351563,0.1289 c -0.657713,0.57559 -1.533142,0.83597 -2.398437,0.71289 a 0.50008765,0.50008765 0 0 0 -0.542969,0.33008 0.50005,0.50005 0 0 0 -0.09766,0.19727 c -0.248328,0.96717 -1.16166,1.59867 -2.154297,1.49023 -0.992636,-0.10844 -1.747599,-0.92195 -1.78125,-1.91992 -0.02307,-0.68418 0.30371,-1.29829 0.824219,-1.67774 a 0.50005,0.50005 0 0 0 0.166016,-0.11718 c 0.198328,-0.11547 0.417989,-0.19976 0.65625,-0.24219 a 0.50005,0.50005 0 0 0 -0.08984,-0.99414 0.50005,0.50005 0 0 0 -0.08398,0.01 c -0.160251,0.0285 -0.313314,0.0746 -0.46289,0.12695 -0.0646,-1.10299 0.477746,-2.17237 1.457031,-2.75391 1.157707,-0.68748 2.624443,-0.52021 3.599609,0.4082 a 0.50009764,0.50009764 0 0 0 0.689453,-0.7246 c -0.648161,-0.6171 -1.462878,-0.98259 -2.308593,-1.07813 -0.148752,-0.017 -0.299358,-0.0157 -0.449254,-0.0158 A 0.50005,0.50005 0 0 0 95,246 c 0,-1.23027 0.747501,-2.33232 1.890625,-2.78711 0.428672,-0.17055 0.879639,-0.23611 1.320313,-0.20508 z" id="path21574" inkscape:connector-curvature="0"/>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g23463">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 10.492188,241.99219 A 0.50005,0.50005 0 0 0 10.417969,242 H 6.5 A 0.50005,0.50005 0 0 0 6,242.5 v 5 A 0.50005,0.50005 0 0 0 6.5,248 H 8 v 7.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 A 0.50005,0.50005 0 0 0 18,255.5 V 248 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 19.5,242 h -3.919922 a 0.50005,0.50005 0 0 0 -0.404297,0.11328 0.50005,0.50005 0 0 0 -0.01953,0.0156 0.50005,0.50005 0 0 0 -0.01758,0.0176 0.50005,0.50005 0 0 0 -0.002,0.004 0.50005,0.50005 0 0 0 -0.03125,0.0332 0.50005,0.50005 0 0 0 -0.002,0.004 A 0.50005,0.50005 0 0 0 15,242.58203 V 243 c 0,0.71532 -0.380592,1.37478 -1,1.73242 -0.619409,0.35765 -1.380591,0.35765 -2,0 -0.619408,-0.35764 -1,-1.0171 -1,-1.73242 v -0.41992 a 0.50005,0.50005 0 0 0 -0.113281,-0.4043 0.50005,0.50005 0 0 0 -0.002,-0.004 0.50005,0.50005 0 0 0 -0.03125,-0.0332 0.50005,0.50005 0 0 0 -0.0039,-0.002 0.50005,0.50005 0 0 0 -0.0332,-0.0312 0.50005,0.50005 0 0 0 -0.0039,-0.002 0.50005,0.50005 0 0 0 -0.320312,-0.11133 z M 7,243 h 3 c 0,1.07096 0.57257,2.06216 1.5,2.59766 0.927429,0.53549 2.072571,0.53549 3,0 0.92743,-0.5355 1.5,-1.5267 1.5,-2.59766 h 3 v 4 H 17.5 A 0.50005,0.50005 0 0 0 17,247.5 V 255 H 9 v -7.5 A 0.50005,0.50005 0 0 0 8.5,247 H 7 Z" id="path22384" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g22840" transform="translate(-1.8536743e-6,-19.999994)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 412,286 c 1.65601,0 3,1.37486 3,3.04688 0,1.67201 -1.34399,3.04687 -3,3.04687 -1.65601,0 -3,-1.37486 -3,-3.04687 C 409,287.37486 410.34399,286 412,286 Z m 0,1 c -1.10534,0 -2,0.90526 -2,2.04688 0,1.14161 0.89466,2.04687 2,2.04687 1.10534,0 2,-0.90526 2,-2.04687 C 414,287.90526 413.10534,287 412,287 Z" id="circle22836" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999982;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 412,283 c -3.5093,0 -6,2.77253 -6,5.91992 V 296 h -0.96094 a 0.50004991,0.50004991 0 1 0 0,1 H 406.5 a 0.50004991,0.50004991 0 0 0 0.5,-0.5 v -7.58008 C 407,286.29196 409.01002,284 412,284 c 2.99076,0 5,2.29197 5,4.91992 V 296.5 a 0.50004991,0.50004991 0 0 0 0.5,0.5 h 1.46094 a 0.50004991,0.50004991 0 1 0 0,-1 H 418 v -7.08008 C 418,285.77251 415.50996,283 412,283 Z" id="path22838" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.95;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 54.951172,347 c -1.831463,0.10706 -3.628606,0.91857 -4.910156,2.35742 -2.943003,3.30422 -2.532587,8.31019 0.05078,11.44531 a 0.5501659,0.5501659 0 1 0 0.849609,-0.69921 c -2.251956,-2.73294 -2.615242,-7.16516 -0.07813,-10.01368 2.156081,-2.42072 6.066547,-2.73646 8.435547,-0.43164 1.937906,1.88542 2.205459,5.18464 0.267578,7.14453 -1.518438,1.53565 -4.123722,1.73043 -5.623047,0.11133 -1.098553,-1.18629 -1.217866,-3.2114 0.03516,-4.28515 0.40623,-0.34811 0.977609,-0.54432 1.501953,-0.52539 0.524344,0.0189 0.981344,0.22421 1.291015,0.67968 0.145266,0.21367 0.237116,0.58238 0.201172,0.86719 -0.03594,0.28481 -0.127716,0.44479 -0.371094,0.5332 a 0.55049551,0.55049551 0 1 0 0.375,1.03516 c 0.656421,-0.23845 1.015068,-0.85266 1.087891,-1.42969 0.07282,-0.57703 -0.06773,-1.15869 -0.384765,-1.625 -0.517269,-0.76081 -1.34716,-1.12886 -2.160157,-1.1582 -0.812997,-0.0293 -1.63015,0.25121 -2.257812,0.78906 -1.781519,1.52664 -1.618395,4.25452 -0.125,5.86719 1.955333,2.11153 5.283443,1.86538 7.21289,-0.0859 2.400922,-2.4282 2.076076,-6.41165 -0.283203,-8.70703 -1.417731,-1.37933 -3.283772,-1.9762 -5.115234,-1.86914 z" id="path23662-2" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 81.492188,347.13672 c -0.442306,0.006 -0.696492,0.5058 -0.441407,0.86719 0.49808,0.72856 0.898438,1.27175 0.898438,2.60351 0,2.36371 -1.912476,5.29297 -6.919922,5.29297 -2.17926,0 -3.451901,-0.37865 -4.130859,-0.79883 -0.678959,-0.42018 -0.798829,-0.80387 -0.798829,-1.10156 0,-0.45749 0.450606,-1.844 3.496094,-2.17969 0.731186,-0.0565 0.647202,-1.15413 -0.08398,-1.09765 -0.01241,9.1e-4 -0.02479,0.002 -0.03711,0.004 C 70.097311,351.09872 69,352.84097 69,354 c 0,0.6737 0.378574,1.45551 1.318359,2.03711 0.939785,0.58159 2.407524,0.96289 4.710938,0.96289 5.452133,0 8.021484,-3.41358 8.021484,-6.39258 0,-1.58243 -0.595669,-2.49605 -1.09375,-3.22461 -0.103149,-0.1556 -0.278176,-0.24826 -0.464843,-0.24609 z M 77.5,350.96875 c -0.645258,0.008 -0.75144,0.92907 -0.125,1.08398 0.86985,0.23625 1.603372,0.59862 2.212891,1.02539 0.601573,0.42066 1.232432,-0.48169 0.630859,-0.90234 -0.709221,-0.49659 -1.560177,-0.91545 -2.554688,-1.18555 -0.05329,-0.0154 -0.108604,-0.0226 -0.164062,-0.0215 z m 4.814453,4.19141 c -0.370377,0.014 -0.621193,0.38283 -0.498047,0.73242 0.0943,0.28097 0.132813,0.5225 0.132813,0.67969 0,0.15896 0.01621,0.32983 0.0059,0.58398 -0.01039,0.25415 -0.04509,0.56394 -0.138672,0.89063 -0.187171,0.65336 -0.583988,1.36714 -1.576172,1.91796 -0.642059,0.35673 -0.106902,1.31962 0.535157,0.96289 1.249156,-0.69348 1.849012,-1.70822 2.097656,-2.57617 0.124322,-0.43397 0.166734,-0.83367 0.179687,-1.15039 0.01295,-0.31671 -0.002,-0.5795 -0.002,-0.6289 0,-0.3203 -0.06792,-0.66136 -0.191406,-1.0293 -0.07498,-0.23555 -0.297898,-0.39215 -0.544922,-0.38281 z" id="path42609-7" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 75.492188,347.04102 A 0.50005,0.50005 0 0 0 75,347.54688 V 354.5 a 0.50005,0.50005 0 1 0 1,0 v -6.95312 a 0.50005,0.50005 0 0 0 -0.507812,-0.50586 z m 0,10.95117 A 0.50005,0.50005 0 0 0 75,358.5 v 2.04688 a 0.50005,0.50005 0 1 0 1,0 V 358.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z" id="rect42619-7" inkscape:connector-curvature="0"/>
- <path style="display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.79999995;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m 114.49609,354 a 3.4824922,3.4824822 0 0 0 -3.48242,3.48242 3.4824922,3.4824822 0 0 0 3.48242,3.48242 3.4824922,3.4824822 0 0 0 3.48243,-3.48242 A 3.4824922,3.4824822 0 0 0 114.49609,354 Z m -0.50586,0.98633 h 1.01368 v 1.98633 H 117 v 1.01367 h -1.99609 v 1.98633 h -1.01368 v -1.98633 h -1.99609 v -1.01367 h 1.99609 z" id="circle23722" inkscape:connector-curvature="0"/>
- <path style="display:inline;opacity:0.6;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;enable-background:new" d="m 121.47461,347 a 3.4883757,3.4883673 0 0 0 -3.48828,3.48828 3.4883757,3.4883673 0 0 0 3.48828,3.48828 3.4883757,3.4883673 0 0 0 3.48828,-3.48828 A 3.4883757,3.4883673 0 0 0 121.47461,347 Z m -2.48047,3 H 124 v 1.01367 h -5.00586 z" id="circle23728" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g23638">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.85;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 229.49023,351.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -0.74609,0.7461 -1.67773,-0.83985 a 0.50005,0.50005 0 0 0 -0.62305,0.14649 L 225.5,353 h -1 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -1,1 A 0.50005,0.50005 0 0 0 223,354.5 v 2.79297 l -1.85352,1.85351 a 0.50005,0.50005 0 0 0 0,0.70704 l 1,1 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -0.64649,-0.64648 1.64649,-1.64648 A 0.50005,0.50005 0 0 0 224,357.5 v -2.79297 L 224.70703,354 H 225.75 a 0.50005,0.50005 0 0 0 0.40039,-0.19922 l 0.5,-0.66601 1.62695,0.8125 a 0.50005,0.50005 0 0 0 0.57618,-0.0937 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z" id="path42208-0" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 223.49219,347 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 l -2,2 A 0.50005,0.50005 0 0 0 221,349.5 v 0.79297 L 220.29297,351 H 218.5 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -1,1 a 0.50005,0.50005 0 0 0 0,0.70704 L 218,353.70703 v 2.58594 l -1.85352,1.85351 A 0.50005,0.50005 0 0 0 216,358.5 v 2 a 0.50005,0.50005 0 1 0 1,0 v -1.79297 l 1.85352,-1.85351 A 0.50005,0.50005 0 0 0 219,356.5 v -3 a 0.50005,0.50005 0 0 0 -0.14648,-0.35352 l -0.64649,-0.64648 0.5,-0.5 H 220.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 1,-1 A 0.50005,0.50005 0 0 0 222,350.5 v -0.79297 l 1.5,-1.5 0.64648,0.64649 A 0.50005,0.50005 0 0 0 224.5,349 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 348 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 h -2 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -2.29297 l -0.85351,-0.85352 A 0.50005,0.50005 0 0 0 223.49219,347 Z" id="path42222-9" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 228.5,357 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -1,1 a 0.50005,0.50005 0 0 0 0,0.70704 l 0.64649,0.64648 -0.64649,0.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 0,-0.70704 l -0.64649,-0.64648 0.5,-0.5 H 229.5 a 0.50005,0.50005 0 1 0 0,-1 z" id="path23824" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g24220" transform="translate(-1.8536743e-6,63.000006)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 32.855469,347.00586 c -0.706567,0.052 -1.35787,0.479 -1.669922,1.15234 a 0.50005,0.50005 0 1 0 0.90625,0.42188 c 0.210359,-0.45391 0.713864,-0.68179 1.193359,-0.53906 0.479496,0.14272 0.777196,0.60845 0.705078,1.10351 C 33.918117,349.63959 33.500288,350 33,350 h -5.5 c -0.676161,-0.01 -0.676161,1.00956 0,1 H 33 c 0.98952,0 1.835874,-0.73175 1.978516,-1.71094 0.142642,-0.97918 -0.459806,-1.92277 -1.408204,-2.20508 -0.237099,-0.0706 -0.479321,-0.0955 -0.714843,-0.0781 z M 38.488281,349 c -0.867889,0.005 -1.700579,0.46414 -2.154297,1.25 a 0.5005035,0.5005035 0 1 0 0.867188,0.5 c 0.36563,-0.63329 1.125339,-0.91026 1.8125,-0.66016 0.68716,0.25011 1.089874,0.94977 0.96289,1.66993 C 39.849581,352.47992 39.231261,353 38.5,353 h -11 c -0.676161,-0.01 -0.676161,1.00956 0,1 h 11 c 1.209914,0 2.252791,-0.87487 2.462891,-2.06641 0.210099,-1.19153 -0.470475,-2.36938 -1.607422,-2.7832 C 39.071232,349.04694 38.777578,348.99817 38.488281,349 Z M 27.5,356 c -0.676161,-0.01 -0.676161,1.00956 0,1 H 35.464844 35.5 c 0.74205,0 1.3672,0.53453 1.482422,1.26758 0.115221,0.73305 -0.315216,1.43251 -1.021484,1.66015 -0.706269,0.22765 -1.466229,-0.0896 -1.800782,-0.75195 a 0.50006246,0.50006246 0 1 0 -0.892578,0.45117 c 0.553327,1.09549 1.831882,1.62847 3,1.25196 1.168118,-0.37652 1.891741,-1.55517 1.701172,-2.76758 C 37.778181,356.89891 36.727299,356 35.5,356 Z" transform="translate(1.8536743e-6,-63.000006)" id="path24132" inkscape:connector-curvature="0"/>
- <g id="g24588" style="opacity:0.8;fill:#ffffff"/>
- <g id="g24584" style="opacity:0.8;fill:#ffffff"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g22036" transform="translate(-21.000002,4.4999696e-6)">
- <g transform="matrix(-1,0,0,1,508.99288,-42.00012)" id="g23159" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 286.49219,242 a 0.50005,0.50005 0 0 0 -0.5,0.5 L 286,255.50781 a 0.50005,0.50005 0 0 0 0.5,0.5 h 6 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 242.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 4.72656 l -4.7207,10.22852 z M 292,244.77344 v 10.23437 h -4.72266 z" transform="matrix(-1,0,0,1,487.99288,42.000116)" id="path23171" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 202.99219,284 v 1 H 208 l -0.008,12.00781 -4.99805,-0.008 -0.002,1 5.5,0.008 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 209,284.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z" id="path21181" inkscape:connector-curvature="0"/>
+ <g
+ id="g21673"
+ style="display:inline;opacity:1;fill:#ffffff;stroke:#f9f9f9;enable-background:new"
+ transform="translate(-63,6)" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 219.50391,243 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 218.38224,244.61833 217.33333,245 216.5,245 a 0.50005,0.50005 0 1 0 0,1 c 1.00319,0 2.15225,-0.6005 3,-1.7832 0.82397,1.14952 1.9314,1.74461 2.91406,1.77734 a 0.50005,0.50005 0 0 0 0.002,0 0.50005,0.50005 0 0 0 0.084,0.006 0.50005,0.50005 0 0 0 0.0996,-0.008 c 0.97927,-0.0378 2.08023,-0.63118 2.90039,-1.77539 0.84775,1.1827 1.99681,1.7832 3,1.7832 a 0.50005,0.50005 0 1 0 0,-1 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 225.50391,243 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 224.38224,244.61833 223.33333,245 222.5,245 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 219.50391,243 Z m 1,5 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 219.38224,249.61833 218.33333,250 217.5,250 a 0.50005,0.50005 0 1 0 0,1 c 1.00319,0 2.15225,-0.6005 3,-1.7832 0.82397,1.14952 1.9314,1.74461 2.91406,1.77734 a 0.50005,0.50005 0 0 0 0.002,0 0.50005,0.50005 0 0 0 0.084,0.006 0.50005,0.50005 0 0 0 0.0859,-0.006 0.50005,0.50005 0 0 0 0.0137,-0.002 c 0.97927,-0.0378 2.08023,-0.63118 2.90039,-1.77539 0.84775,1.1827 1.99681,1.7832 3,1.7832 a 0.50005,0.50005 0 1 0 0,-1 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 226.50391,248 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 225.38224,249.61833 224.33333,250 223.5,250 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 220.50391,248 Z m -1,5 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 218.38224,254.61833 217.33333,255 216.5,255 a 0.50005,0.50005 0 1 0 0,1 c 1.00319,0 2.15225,-0.6005 3,-1.7832 0.82397,1.14952 1.9314,1.74461 2.91406,1.77734 a 0.50005,0.50005 0 0 0 0.002,0 0.50005,0.50005 0 0 0 0.084,0.006 0.50005,0.50005 0 0 0 0.0996,-0.008 c 0.97927,-0.0378 2.08023,-0.63118 2.90039,-1.77539 0.84775,1.1827 1.99681,1.7832 3,1.7832 a 0.50005,0.50005 0 1 0 0,-1 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 225.50391,253 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 224.38224,254.61833 223.33333,255 222.5,255 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 219.50391,253 Z"
+ id="path21858"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 97.689453,242.01172 c -0.394683,0.0302 -0.787753,0.12022 -1.167969,0.27148 C 95.00062,242.88827 94,244.36319 94,246 a 0.50005,0.50005 0 0 0 0.01563,0.13281 c -0.365184,0.0927 -0.722816,0.22834 -1.058594,0.42774 -1.441397,0.85595 -2.170881,2.51688 -1.878906,4.14453 -0.687144,0.57705 -1.108155,1.44799 -1.076172,2.39648 0.05016,1.48769 1.192146,2.71921 2.671875,2.88086 1.398175,0.15274 2.699752,-0.69789 3.152344,-2.00781 0.896041,0.0388 1.769696,-0.22225 2.498047,-0.74609 1.073726,0.85551 2.557876,1.01607 3.789066,0.37695 1.30171,-0.67573 2.04374,-2.09602 1.85742,-3.55078 -0.16328,-1.27499 -1.01006,-2.34261 -2.17968,-2.80664 0.45466,-1.38242 0.13144,-2.9211 -0.88477,-3.9961 -0.56221,-0.59473 -1.277273,-0.98709 -2.042974,-1.15625 -0.38285,-0.0846 -0.779145,-0.11418 -1.173828,-0.084 z m 0.521485,0.99609 c 0.734455,0.0517 1.440532,0.37287 1.968752,0.93164 0.84514,0.89404 1.0593,2.20845 0.54101,3.32422 a 0.50005,0.50005 0 0 0 -0.0527,0.2168 0.50005,0.50005 0 0 0 0.38672,0.58203 c 1.02426,0.23341 1.79232,1.07713 1.92578,2.11914 0.13345,1.04201 -0.39575,2.0531 -1.32813,2.53711 -0.93238,0.48401 -2.064441,0.33572 -2.83984,-0.37305 a 0.50005,0.50005 0 0 0 -0.203125,-0.11914 0.50005,0.50005 0 0 0 -0.28125,-0.0977 0.50005,0.50005 0 0 0 -0.351563,0.1289 c -0.657713,0.57559 -1.533142,0.83597 -2.398437,0.71289 a 0.50008765,0.50008765 0 0 0 -0.542969,0.33008 0.50005,0.50005 0 0 0 -0.09766,0.19727 c -0.248328,0.96717 -1.16166,1.59867 -2.154297,1.49023 -0.992636,-0.10844 -1.747599,-0.92195 -1.78125,-1.91992 -0.02307,-0.68418 0.30371,-1.29829 0.824219,-1.67774 a 0.50005,0.50005 0 0 0 0.166016,-0.11718 c 0.198328,-0.11547 0.417989,-0.19976 0.65625,-0.24219 a 0.50005,0.50005 0 0 0 -0.08984,-0.99414 0.50005,0.50005 0 0 0 -0.08398,0.01 c -0.160251,0.0285 -0.313314,0.0746 -0.46289,0.12695 -0.0646,-1.10299 0.477746,-2.17237 1.457031,-2.75391 1.157707,-0.68748 2.624443,-0.52021 3.599609,0.4082 a 0.50009764,0.50009764 0 0 0 0.689453,-0.7246 c -0.648161,-0.6171 -1.462878,-0.98259 -2.308593,-1.07813 -0.148752,-0.017 -0.299358,-0.0157 -0.449254,-0.0158 A 0.50005,0.50005 0 0 0 95,246 c 0,-1.23027 0.747501,-2.33232 1.890625,-2.78711 0.428672,-0.17055 0.879639,-0.23611 1.320313,-0.20508 z"
+ id="path21574"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g23463">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 10.492188,241.99219 A 0.50005,0.50005 0 0 0 10.417969,242 H 6.5 A 0.50005,0.50005 0 0 0 6,242.5 v 5 A 0.50005,0.50005 0 0 0 6.5,248 H 8 v 7.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 A 0.50005,0.50005 0 0 0 18,255.5 V 248 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 19.5,242 h -3.919922 a 0.50005,0.50005 0 0 0 -0.404297,0.11328 0.50005,0.50005 0 0 0 -0.01953,0.0156 0.50005,0.50005 0 0 0 -0.01758,0.0176 0.50005,0.50005 0 0 0 -0.002,0.004 0.50005,0.50005 0 0 0 -0.03125,0.0332 0.50005,0.50005 0 0 0 -0.002,0.004 A 0.50005,0.50005 0 0 0 15,242.58203 V 243 c 0,0.71532 -0.380592,1.37478 -1,1.73242 -0.619409,0.35765 -1.380591,0.35765 -2,0 -0.619408,-0.35764 -1,-1.0171 -1,-1.73242 v -0.41992 a 0.50005,0.50005 0 0 0 -0.113281,-0.4043 0.50005,0.50005 0 0 0 -0.002,-0.004 0.50005,0.50005 0 0 0 -0.03125,-0.0332 0.50005,0.50005 0 0 0 -0.0039,-0.002 0.50005,0.50005 0 0 0 -0.0332,-0.0312 0.50005,0.50005 0 0 0 -0.0039,-0.002 0.50005,0.50005 0 0 0 -0.320312,-0.11133 z M 7,243 h 3 c 0,1.07096 0.57257,2.06216 1.5,2.59766 0.927429,0.53549 2.072571,0.53549 3,0 0.92743,-0.5355 1.5,-1.5267 1.5,-2.59766 h 3 v 4 H 17.5 A 0.50005,0.50005 0 0 0 17,247.5 V 255 H 9 v -7.5 A 0.50005,0.50005 0 0 0 8.5,247 H 7 Z"
+ id="path22384"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g22840"
+ transform="translate(-1.8536743e-6,-19.999994)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 412,286 c 1.65601,0 3,1.37486 3,3.04688 0,1.67201 -1.34399,3.04687 -3,3.04687 -1.65601,0 -3,-1.37486 -3,-3.04687 C 409,287.37486 410.34399,286 412,286 Z m 0,1 c -1.10534,0 -2,0.90526 -2,2.04688 0,1.14161 0.89466,2.04687 2,2.04687 1.10534,0 2,-0.90526 2,-2.04687 C 414,287.90526 413.10534,287 412,287 Z"
+ id="circle22836"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999982;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 412,283 c -3.5093,0 -6,2.77253 -6,5.91992 V 296 h -0.96094 a 0.50004991,0.50004991 0 1 0 0,1 H 406.5 a 0.50004991,0.50004991 0 0 0 0.5,-0.5 v -7.58008 C 407,286.29196 409.01002,284 412,284 c 2.99076,0 5,2.29197 5,4.91992 V 296.5 a 0.50004991,0.50004991 0 0 0 0.5,0.5 h 1.46094 a 0.50004991,0.50004991 0 1 0 0,-1 H 418 v -7.08008 C 418,285.77251 415.50996,283 412,283 Z"
+ id="path22838"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.95;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 54.951172,347 c -1.831463,0.10706 -3.628606,0.91857 -4.910156,2.35742 -2.943003,3.30422 -2.532587,8.31019 0.05078,11.44531 a 0.5501659,0.5501659 0 1 0 0.849609,-0.69921 c -2.251956,-2.73294 -2.615242,-7.16516 -0.07813,-10.01368 2.156081,-2.42072 6.066547,-2.73646 8.435547,-0.43164 1.937906,1.88542 2.205459,5.18464 0.267578,7.14453 -1.518438,1.53565 -4.123722,1.73043 -5.623047,0.11133 -1.098553,-1.18629 -1.217866,-3.2114 0.03516,-4.28515 0.40623,-0.34811 0.977609,-0.54432 1.501953,-0.52539 0.524344,0.0189 0.981344,0.22421 1.291015,0.67968 0.145266,0.21367 0.237116,0.58238 0.201172,0.86719 -0.03594,0.28481 -0.127716,0.44479 -0.371094,0.5332 a 0.55049551,0.55049551 0 1 0 0.375,1.03516 c 0.656421,-0.23845 1.015068,-0.85266 1.087891,-1.42969 0.07282,-0.57703 -0.06773,-1.15869 -0.384765,-1.625 -0.517269,-0.76081 -1.34716,-1.12886 -2.160157,-1.1582 -0.812997,-0.0293 -1.63015,0.25121 -2.257812,0.78906 -1.781519,1.52664 -1.618395,4.25452 -0.125,5.86719 1.955333,2.11153 5.283443,1.86538 7.21289,-0.0859 2.400922,-2.4282 2.076076,-6.41165 -0.283203,-8.70703 -1.417731,-1.37933 -3.283772,-1.9762 -5.115234,-1.86914 z"
+ id="path23662-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 81.492188,347.13672 c -0.442306,0.006 -0.696492,0.5058 -0.441407,0.86719 0.49808,0.72856 0.898438,1.27175 0.898438,2.60351 0,2.36371 -1.912476,5.29297 -6.919922,5.29297 -2.17926,0 -3.451901,-0.37865 -4.130859,-0.79883 -0.678959,-0.42018 -0.798829,-0.80387 -0.798829,-1.10156 0,-0.45749 0.450606,-1.844 3.496094,-2.17969 0.731186,-0.0565 0.647202,-1.15413 -0.08398,-1.09765 -0.01241,9.1e-4 -0.02479,0.002 -0.03711,0.004 C 70.097311,351.09872 69,352.84097 69,354 c 0,0.6737 0.378574,1.45551 1.318359,2.03711 0.939785,0.58159 2.407524,0.96289 4.710938,0.96289 5.452133,0 8.021484,-3.41358 8.021484,-6.39258 0,-1.58243 -0.595669,-2.49605 -1.09375,-3.22461 -0.103149,-0.1556 -0.278176,-0.24826 -0.464843,-0.24609 z M 77.5,350.96875 c -0.645258,0.008 -0.75144,0.92907 -0.125,1.08398 0.86985,0.23625 1.603372,0.59862 2.212891,1.02539 0.601573,0.42066 1.232432,-0.48169 0.630859,-0.90234 -0.709221,-0.49659 -1.560177,-0.91545 -2.554688,-1.18555 -0.05329,-0.0154 -0.108604,-0.0226 -0.164062,-0.0215 z m 4.814453,4.19141 c -0.370377,0.014 -0.621193,0.38283 -0.498047,0.73242 0.0943,0.28097 0.132813,0.5225 0.132813,0.67969 0,0.15896 0.01621,0.32983 0.0059,0.58398 -0.01039,0.25415 -0.04509,0.56394 -0.138672,0.89063 -0.187171,0.65336 -0.583988,1.36714 -1.576172,1.91796 -0.642059,0.35673 -0.106902,1.31962 0.535157,0.96289 1.249156,-0.69348 1.849012,-1.70822 2.097656,-2.57617 0.124322,-0.43397 0.166734,-0.83367 0.179687,-1.15039 0.01295,-0.31671 -0.002,-0.5795 -0.002,-0.6289 0,-0.3203 -0.06792,-0.66136 -0.191406,-1.0293 -0.07498,-0.23555 -0.297898,-0.39215 -0.544922,-0.38281 z"
+ id="path42609-7"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 75.492188,347.04102 A 0.50005,0.50005 0 0 0 75,347.54688 V 354.5 a 0.50005,0.50005 0 1 0 1,0 v -6.95312 a 0.50005,0.50005 0 0 0 -0.507812,-0.50586 z m 0,10.95117 A 0.50005,0.50005 0 0 0 75,358.5 v 2.04688 a 0.50005,0.50005 0 1 0 1,0 V 358.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z"
+ id="rect42619-7"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.79999995;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 114.49609,354 a 3.4824922,3.4824822 0 0 0 -3.48242,3.48242 3.4824922,3.4824822 0 0 0 3.48242,3.48242 3.4824922,3.4824822 0 0 0 3.48243,-3.48242 A 3.4824922,3.4824822 0 0 0 114.49609,354 Z m -0.50586,0.98633 h 1.01368 v 1.98633 H 117 v 1.01367 h -1.99609 v 1.98633 h -1.01368 v -1.98633 h -1.99609 v -1.01367 h 1.99609 z"
+ id="circle23722"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;opacity:0.6;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;enable-background:new"
+ d="m 121.47461,347 a 3.4883757,3.4883673 0 0 0 -3.48828,3.48828 3.4883757,3.4883673 0 0 0 3.48828,3.48828 3.4883757,3.4883673 0 0 0 3.48828,-3.48828 A 3.4883757,3.4883673 0 0 0 121.47461,347 Z m -2.48047,3 H 124 v 1.01367 h -5.00586 z"
+ id="circle23728"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g23638">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.85;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 229.49023,351.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -0.74609,0.7461 -1.67773,-0.83985 a 0.50005,0.50005 0 0 0 -0.62305,0.14649 L 225.5,353 h -1 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -1,1 A 0.50005,0.50005 0 0 0 223,354.5 v 2.79297 l -1.85352,1.85351 a 0.50005,0.50005 0 0 0 0,0.70704 l 1,1 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -0.64649,-0.64648 1.64649,-1.64648 A 0.50005,0.50005 0 0 0 224,357.5 v -2.79297 L 224.70703,354 H 225.75 a 0.50005,0.50005 0 0 0 0.40039,-0.19922 l 0.5,-0.66601 1.62695,0.8125 a 0.50005,0.50005 0 0 0 0.57618,-0.0937 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
+ id="path42208-0"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 223.49219,347 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 l -2,2 A 0.50005,0.50005 0 0 0 221,349.5 v 0.79297 L 220.29297,351 H 218.5 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -1,1 a 0.50005,0.50005 0 0 0 0,0.70704 L 218,353.70703 v 2.58594 l -1.85352,1.85351 A 0.50005,0.50005 0 0 0 216,358.5 v 2 a 0.50005,0.50005 0 1 0 1,0 v -1.79297 l 1.85352,-1.85351 A 0.50005,0.50005 0 0 0 219,356.5 v -3 a 0.50005,0.50005 0 0 0 -0.14648,-0.35352 l -0.64649,-0.64648 0.5,-0.5 H 220.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 1,-1 A 0.50005,0.50005 0 0 0 222,350.5 v -0.79297 l 1.5,-1.5 0.64648,0.64649 A 0.50005,0.50005 0 0 0 224.5,349 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 348 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 h -2 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -2.29297 l -0.85351,-0.85352 A 0.50005,0.50005 0 0 0 223.49219,347 Z"
+ id="path42222-9"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 228.5,357 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -1,1 a 0.50005,0.50005 0 0 0 0,0.70704 l 0.64649,0.64648 -0.64649,0.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 0,-0.70704 l -0.64649,-0.64648 0.5,-0.5 H 229.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path23824"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g24220"
+ transform="translate(-1.8536743e-6,63.000006)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 32.855469,347.00586 c -0.706567,0.052 -1.35787,0.479 -1.669922,1.15234 a 0.50005,0.50005 0 1 0 0.90625,0.42188 c 0.210359,-0.45391 0.713864,-0.68179 1.193359,-0.53906 0.479496,0.14272 0.777196,0.60845 0.705078,1.10351 C 33.918117,349.63959 33.500288,350 33,350 h -5.5 c -0.676161,-0.01 -0.676161,1.00956 0,1 H 33 c 0.98952,0 1.835874,-0.73175 1.978516,-1.71094 0.142642,-0.97918 -0.459806,-1.92277 -1.408204,-2.20508 -0.237099,-0.0706 -0.479321,-0.0955 -0.714843,-0.0781 z M 38.488281,349 c -0.867889,0.005 -1.700579,0.46414 -2.154297,1.25 a 0.5005035,0.5005035 0 1 0 0.867188,0.5 c 0.36563,-0.63329 1.125339,-0.91026 1.8125,-0.66016 0.68716,0.25011 1.089874,0.94977 0.96289,1.66993 C 39.849581,352.47992 39.231261,353 38.5,353 h -11 c -0.676161,-0.01 -0.676161,1.00956 0,1 h 11 c 1.209914,0 2.252791,-0.87487 2.462891,-2.06641 0.210099,-1.19153 -0.470475,-2.36938 -1.607422,-2.7832 C 39.071232,349.04694 38.777578,348.99817 38.488281,349 Z M 27.5,356 c -0.676161,-0.01 -0.676161,1.00956 0,1 H 35.464844 35.5 c 0.74205,0 1.3672,0.53453 1.482422,1.26758 0.115221,0.73305 -0.315216,1.43251 -1.021484,1.66015 -0.706269,0.22765 -1.466229,-0.0896 -1.800782,-0.75195 a 0.50006246,0.50006246 0 1 0 -0.892578,0.45117 c 0.553327,1.09549 1.831882,1.62847 3,1.25196 1.168118,-0.37652 1.891741,-1.55517 1.701172,-2.76758 C 37.778181,356.89891 36.727299,356 35.5,356 Z"
+ transform="translate(1.8536743e-6,-63.000006)"
+ id="path24132"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g24588"
+ style="opacity:0.8;fill:#ffffff" />
+ <g
+ id="g24584"
+ style="opacity:0.8;fill:#ffffff" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22036"
+ transform="translate(-21.000002,4.4999696e-6)">
+ <g
+ transform="matrix(-1,0,0,1,508.99288,-42.00012)"
+ id="g23159"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 286.49219,242 a 0.50005,0.50005 0 0 0 -0.5,0.5 L 286,255.50781 a 0.50005,0.50005 0 0 0 0.5,0.5 h 6 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 242.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 4.72656 l -4.7207,10.22852 z M 292,244.77344 v 10.23437 h -4.72266 z"
+ transform="matrix(-1,0,0,1,487.99288,42.000116)"
+ id="path23171"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 202.99219,284 v 1 H 208 l -0.008,12.00781 -4.99805,-0.008 -0.002,1 5.5,0.008 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 209,284.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path21181"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g22891" transform="translate(443.99999,-274)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m -141,519.5 v 1.5 h 1 v -1.5 z m 0,2.5 v 2 h 1 v -2 z m 0,3 v 1.2793 l -2.58594,2.35156 0.67188,0.73828 2.60351,-2.36719 L -139,527 v -1 h -1 v -1 z m 3.00781,1 v 1 h 2 v -1 z M -135,526 v 1 h 1.5 v -1 z" mask="none" id="path12456" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 303.5,242 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 300,245.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 314,252.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 h 8.58594 l -2,2 h -8.58594 z M 313,243.70703 v 8.58594 l -2,2 v -8.58594 z M 301,246 h 9 v 9 h -9 z" transform="translate(-443.99999,274)" id="path12458" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g22594" transform="translate(-1.8536743e-6,21.000005)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999976;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 239.00391,336 c 1.09865,0 2,0.90134 2,2 0,1.09866 -0.90135,2 -2,2 -1.09866,0 -2,-0.90134 -2,-2 0,-1.09866 0.90134,-2 2,-2 z" id="circle22541" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- <g id="g22585" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 244.04102,347.03125 c -1.67358,-0.0335 -3.28213,0.6908 -3.99805,2.26758 -0.007,0.016 -0.0126,0.0323 -0.0176,0.0488 l -2,5.99414 c -0.21093,0.63281 0.73829,0.94921 0.94922,0.3164 l 1.98437,-5.95117 c 0.004,-0.009 0.0113,-0.0162 0.0156,-0.0254 l 7.3457,7.3457 c -0.008,0.004 -0.0138,0.008 -0.0215,0.0117 l -5.95703,1.98633 c -0.63281,0.21093 -0.31641,1.16015 0.3164,0.94922 l 6,-2 c 0.0166,-0.006 0.0329,-0.0122 0.0488,-0.0195 1.57453,-0.7157 2.29587,-2.32277 2.26172,-3.9961 -0.0342,-1.67332 -0.77095,-3.46821 -2.11523,-4.8125 -1.34429,-1.34428 -3.13893,-2.08176 -4.8125,-2.11523 z m -0.0195,1 c 1.00796,0.0202 2.11393,0.36656 3.0879,0.99414 -1.6826,0.11569 -2.73353,0.941 -3.59961,1.77734 l -1.94336,-1.94335 c 0.60824,-0.57833 1.46627,-0.84791 2.45507,-0.82813 z M 247.5,350 h 0.5 c 0,6.5e-4 0,10e-4 0,0.002 l 0.002,0.5 c -6.4e-4,1.6083 -0.66875,2.43361 -1.50586,3.28711 l -2.2832,-2.2832 C 245.06632,350.66889 245.89088,350 247.5,350 Z m 1.47656,0.89258 c 0.62645,0.97337 0.97164,2.0788 0.99219,3.08594 0.0202,0.98929 -0.2502,1.84704 -0.82813,2.45507 l -1.9414,-1.9414 c 0.83635,-0.86594 1.6611,-1.91749 1.77734,-3.59961 z" transform="translate(1.8536743e-6,-21.000005)" id="path24556" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccscccccsccccc"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22891"
+ transform="translate(443.99999,-274)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -141,519.5 v 1.5 h 1 v -1.5 z m 0,2.5 v 2 h 1 v -2 z m 0,3 v 1.2793 l -2.58594,2.35156 0.67188,0.73828 2.60351,-2.36719 L -139,527 v -1 h -1 v -1 z m 3.00781,1 v 1 h 2 v -1 z M -135,526 v 1 h 1.5 v -1 z"
+ mask="none"
+ id="path12456"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 303.5,242 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 300,245.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 314,252.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 h 8.58594 l -2,2 h -8.58594 z M 313,243.70703 v 8.58594 l -2,2 v -8.58594 z M 301,246 h 9 v 9 h -9 z"
+ transform="translate(-443.99999,274)"
+ id="path12458"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22594"
+ transform="translate(-1.8536743e-6,21.000005)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999976;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 239.00391,336 c 1.09865,0 2,0.90134 2,2 0,1.09866 -0.90135,2 -2,2 -1.09866,0 -2,-0.90134 -2,-2 0,-1.09866 0.90134,-2 2,-2 z"
+ id="circle22541"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <g
+ id="g22585"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 244.04102,347.03125 c -1.67358,-0.0335 -3.28213,0.6908 -3.99805,2.26758 -0.007,0.016 -0.0126,0.0323 -0.0176,0.0488 l -2,5.99414 c -0.21093,0.63281 0.73829,0.94921 0.94922,0.3164 l 1.98437,-5.95117 c 0.004,-0.009 0.0113,-0.0162 0.0156,-0.0254 l 7.3457,7.3457 c -0.008,0.004 -0.0138,0.008 -0.0215,0.0117 l -5.95703,1.98633 c -0.63281,0.21093 -0.31641,1.16015 0.3164,0.94922 l 6,-2 c 0.0166,-0.006 0.0329,-0.0122 0.0488,-0.0195 1.57453,-0.7157 2.29587,-2.32277 2.26172,-3.9961 -0.0342,-1.67332 -0.77095,-3.46821 -2.11523,-4.8125 -1.34429,-1.34428 -3.13893,-2.08176 -4.8125,-2.11523 z m -0.0195,1 c 1.00796,0.0202 2.11393,0.36656 3.0879,0.99414 -1.6826,0.11569 -2.73353,0.941 -3.59961,1.77734 l -1.94336,-1.94335 c 0.60824,-0.57833 1.46627,-0.84791 2.45507,-0.82813 z M 247.5,350 h 0.5 c 0,6.5e-4 0,10e-4 0,0.002 l 0.002,0.5 c -6.4e-4,1.6083 -0.66875,2.43361 -1.50586,3.28711 l -2.2832,-2.2832 C 245.06632,350.66889 245.89088,350 247.5,350 Z m 1.47656,0.89258 c 0.62645,0.97337 0.97164,2.0788 0.99219,3.08594 0.0202,0.98929 -0.2502,1.84704 -0.82813,2.45507 l -1.9414,-1.9414 c 0.83635,-0.86594 1.6611,-1.91749 1.77734,-3.59961 z"
+ transform="translate(1.8536743e-6,-21.000005)"
+ id="path24556"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccscccccsccccc" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g22663" transform="translate(-126,21.000005)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.0999999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 219.77539,326 c -0.5582,0 -1.07768,0.24943 -1.49219,0.64258 -0.41451,0.39314 -0.75014,0.92623 -1.04101,1.57422 -0.58174,1.29596 -0.98621,3.07228 -1.23828,5.21484 a 0.55005495,0.55005495 0 1 0 1.09179,0.12891 c 0.24409,-2.07475 0.64639,-3.77175 1.15039,-4.89453 0.252,-0.5614 0.52906,-0.97431 0.79297,-1.22461 0.26391,-0.25031 0.48846,-0.3418 0.73633,-0.3418 0.24788,0 0.46416,0.0907 0.7207,0.33398 0.25655,0.24329 0.52547,0.64294 0.77149,1.17579 0.49204,1.06569 0.89452,2.64518 1.18945,4.47851 0.3037,1.88782 0.70794,3.53465 1.27539,4.76367 0.28373,0.61451 0.60805,1.12901 1.01367,1.51367 0.40563,0.38466 0.92032,0.63477 1.47852,0.63477 1.08819,0 1.93098,-0.8296 2.51953,-1.97266 0.58855,-1.14305 0.99634,-2.67751 1.25,-4.45312 a 0.55005495,0.55005495 0 1 0 -1.08789,-0.15625 c -0.2425,1.69747 -0.64149,3.13986 -1.13867,4.10547 -0.49719,0.9656 -1.01901,1.37695 -1.54297,1.37695 -0.24788,0 -0.46416,-0.0907 -0.7207,-0.33398 -0.25655,-0.24329 -0.52547,-0.64294 -0.77149,-1.17579 -0.49204,-1.06569 -0.89451,-2.64518 -1.18945,-4.47851 -0.30369,-1.88783 -0.70794,-3.53465 -1.27539,-4.76367 -0.28373,-0.61451 -0.60805,-1.12901 -1.01367,-1.51367 C 220.84828,326.25011 220.33359,326 219.77539,326 Z" id="use22627" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 218.75,333 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z m 6.5,0 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z" id="rect42619-7-8" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(41.999999,42.000005)" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g22961">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 534.49219,599 C 534.2199,599 534,599.223 534,599.5 v 1.5 h -2.5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 3 h -2.5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 1.5 c 0,0.277 0.2199,0.5 0.49219,0.5 h 0.0156 C 534.7801,608 535,607.777 535,607.5 v -8 c 0,-0.277 -0.2199,-0.5 -0.49219,-0.5 z m 1.25781,1 v 7 H 537 c 1.69468,0 3,-1.30532 3,-3 v -1 c 0,-1.69468 -1.30532,-3 -3,-3 z" transform="translate(-41.999999,-42.000005)" id="path22706-5" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 499.48633,561.0293 A 0.50005,0.50005 0 0 0 499.33984,562 c 1.47643,0.53891 2.51536,1.92006 2.64649,3.53906 0.13107,1.61836 -0.67676,3.15596 -2.04688,3.94727 -1.28647,0.743 -2.75259,0.74008 -4.125,-0.375 -1.33989,-1.08866 -2.72844,-1.33025 -3.91015,-1.00586 -1.18172,0.32439 -2.13574,1.15878 -2.81055,2.10351 a 0.50005,0.50005 0 1 0 0.8125,0.58204 c 0.57519,-0.80527 1.37908,-1.47983 2.26367,-1.72266 0.88459,-0.24283 1.87074,-0.10991 3.01563,0.82031 1.65841,1.34746 3.6606,1.38311 5.2539,0.46289 1.70792,-0.9864 2.70484,-2.89411 2.54297,-4.89258 -0.16181,-1.99781 -1.44971,-3.72278 -3.30078,-4.39843 a 0.50005,0.50005 0 0 0 -0.19531,-0.0312 z" id="path22783-2" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" transform="rotate(-180,349.00525,417)" id="g22180" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 324.95117,410.94531 c -0.75176,0.0616 -1.47366,0.37015 -2.05469,0.95117 -1.16941,1.16942 -1.16162,2.91055 -0.28906,4.30664 0.87256,1.3961 2.57397,2.52709 4.83399,2.79297 2.83908,0.33401 5.63985,-1.05664 6.5332,-3.3125 a 0.50005,0.50005 0 1 0 -0.92969,-0.36718 c -0.67177,1.69632 -3.05327,2.97373 -5.48633,2.6875 -1.98998,-0.23411 -3.41357,-1.22813 -4.10351,-2.33203 -0.68994,-1.10391 -0.68215,-2.23778 0.14844,-3.06836 0.83795,-0.83796 1.98844,-0.89361 3.08398,-0.26368 1.09554,0.62994 2.08242,1.9799 2.31641,3.96875 a 0.50005,0.50005 0 1 0 0.99218,-0.11718 c -0.26601,-2.26115 -1.40413,-3.91119 -2.80859,-4.71875 -0.70223,-0.40379 -1.48457,-0.58895 -2.23633,-0.52735 z m 3.54102,9.04883 a 0.50005,0.50005 0 0 0 -0.37696,0.1875 c -0.31249,0.377 -0.92604,0.69672 -1.66015,0.78906 a 0.50005,0.50005 0 1 0 0.125,0.99219 c 0.94034,-0.11828 1.77818,-0.50935 2.30469,-1.14453 a 0.50005,0.50005 0 0 0 -0.39258,-0.82422 z" id="path22178" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 331.50586,410 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -10,10 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path22182" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccc"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g22365" transform="translate(-1.8536743e-6,-25.999995)">
- <path id="path22215" d="m 302,649 v 8 h 4 v -8 z m 1,1 h 2 v 1 h -2 z m 0,2 h 2 v 1 h -2 z m 0,2 h 2 v 1 h -2 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" inkscape:connector-curvature="0"/>
- <path sodipodi:nodetypes="sssssssssccccc" inkscape:connector-curvature="0" id="rect21916" d="m 301.5,647 c -0.82235,0 -1.5,0.67765 -1.5,1.5 v 9 c 0,0.82235 0.67765,1.5 1.5,1.5 h 11 c 0.82235,0 1.5,-0.67765 1.5,-1.5 v -9 c 0,-0.82235 -0.67765,-1.5 -1.5,-1.5 z m -0.5,1 h 12 v 10 h -12 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g22423">
- <g id="g22461" style="fill:#ffffff">
- <path sodipodi:nodetypes="ssscccssssccsss" inkscape:connector-curvature="0" id="path22413" d="m 175.5,599 c -0.82235,0 -1.5,0.67765 -1.5,1.5 v 6 c 0,0.64672 0.42101,1.19773 1,1.40625 V 606.5 v -3 -3 c 0,-0.28564 0.21436,-0.5 0.5,-0.5 h 9 c 0.28564,0 0.5,0.21436 0.5,0.5 v 1.5 h 1 v -1.5 c 0,-0.82235 -0.67765,-1.5 -1.5,-1.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path id="rect22415" transform="translate(0,-50)" d="m 177.5,653 c -0.82235,0 -1.5,0.67765 -1.5,1.5 v 6 c 0,0.82235 0.67765,1.5 1.5,1.5 h 9 c 0.82235,0 1.5,-0.67765 1.5,-1.5 v -6 c 0,-0.82235 -0.67765,-1.5 -1.5,-1.5 z m 2.00391,2 c 0.1882,0.002 0.35956,0.10882 0.44336,0.27734 l 2,4 c 0.16517,0.33222 -0.0763,0.72229 -0.44727,0.72266 h -4 c -0.37097,-3.7e-4 -0.61244,-0.39044 -0.44727,-0.72266 l 2,-4 c 0.0851,-0.17104 0.26016,-0.27834 0.45118,-0.27734 z m 3.99609,0 h 3 a 0.50005,0.50005 0 1 1 0,1 h -3 a 0.50005,0.50005 0 1 1 0,-1 z m 0,2 h 3 a 0.50005,0.50005 0 1 1 0,1 h -3 a 0.50005,0.50005 0 1 1 0,-1 z m 0,2 h 2 a 0.50005,0.50005 0 1 1 0,1 h -2 a 0.50005,0.50005 0 1 1 0,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22663"
+ transform="translate(-126,21.000005)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.0999999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 219.77539,326 c -0.5582,0 -1.07768,0.24943 -1.49219,0.64258 -0.41451,0.39314 -0.75014,0.92623 -1.04101,1.57422 -0.58174,1.29596 -0.98621,3.07228 -1.23828,5.21484 a 0.55005495,0.55005495 0 1 0 1.09179,0.12891 c 0.24409,-2.07475 0.64639,-3.77175 1.15039,-4.89453 0.252,-0.5614 0.52906,-0.97431 0.79297,-1.22461 0.26391,-0.25031 0.48846,-0.3418 0.73633,-0.3418 0.24788,0 0.46416,0.0907 0.7207,0.33398 0.25655,0.24329 0.52547,0.64294 0.77149,1.17579 0.49204,1.06569 0.89452,2.64518 1.18945,4.47851 0.3037,1.88782 0.70794,3.53465 1.27539,4.76367 0.28373,0.61451 0.60805,1.12901 1.01367,1.51367 0.40563,0.38466 0.92032,0.63477 1.47852,0.63477 1.08819,0 1.93098,-0.8296 2.51953,-1.97266 0.58855,-1.14305 0.99634,-2.67751 1.25,-4.45312 a 0.55005495,0.55005495 0 1 0 -1.08789,-0.15625 c -0.2425,1.69747 -0.64149,3.13986 -1.13867,4.10547 -0.49719,0.9656 -1.01901,1.37695 -1.54297,1.37695 -0.24788,0 -0.46416,-0.0907 -0.7207,-0.33398 -0.25655,-0.24329 -0.52547,-0.64294 -0.77149,-1.17579 -0.49204,-1.06569 -0.89451,-2.64518 -1.18945,-4.47851 -0.30369,-1.88783 -0.70794,-3.53465 -1.27539,-4.76367 -0.28373,-0.61451 -0.60805,-1.12901 -1.01367,-1.51367 C 220.84828,326.25011 220.33359,326 219.77539,326 Z"
+ id="use22627"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 218.75,333 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z m 6.5,0 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="rect42619-7-8"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(41.999999,42.000005)"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g22961">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 534.49219,599 C 534.2199,599 534,599.223 534,599.5 v 1.5 h -2.5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 3 h -2.5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 1.5 c 0,0.277 0.2199,0.5 0.49219,0.5 h 0.0156 C 534.7801,608 535,607.777 535,607.5 v -8 c 0,-0.277 -0.2199,-0.5 -0.49219,-0.5 z m 1.25781,1 v 7 H 537 c 1.69468,0 3,-1.30532 3,-3 v -1 c 0,-1.69468 -1.30532,-3 -3,-3 z"
+ transform="translate(-41.999999,-42.000005)"
+ id="path22706-5"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 499.48633,561.0293 A 0.50005,0.50005 0 0 0 499.33984,562 c 1.47643,0.53891 2.51536,1.92006 2.64649,3.53906 0.13107,1.61836 -0.67676,3.15596 -2.04688,3.94727 -1.28647,0.743 -2.75259,0.74008 -4.125,-0.375 -1.33989,-1.08866 -2.72844,-1.33025 -3.91015,-1.00586 -1.18172,0.32439 -2.13574,1.15878 -2.81055,2.10351 a 0.50005,0.50005 0 1 0 0.8125,0.58204 c 0.57519,-0.80527 1.37908,-1.47983 2.26367,-1.72266 0.88459,-0.24283 1.87074,-0.10991 3.01563,0.82031 1.65841,1.34746 3.6606,1.38311 5.2539,0.46289 1.70792,-0.9864 2.70484,-2.89411 2.54297,-4.89258 -0.16181,-1.99781 -1.44971,-3.72278 -3.30078,-4.39843 a 0.50005,0.50005 0 0 0 -0.19531,-0.0312 z"
+ id="path22783-2"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="rotate(-180,349.00525,417)"
+ id="g22180"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 324.95117,410.94531 c -0.75176,0.0616 -1.47366,0.37015 -2.05469,0.95117 -1.16941,1.16942 -1.16162,2.91055 -0.28906,4.30664 0.87256,1.3961 2.57397,2.52709 4.83399,2.79297 2.83908,0.33401 5.63985,-1.05664 6.5332,-3.3125 a 0.50005,0.50005 0 1 0 -0.92969,-0.36718 c -0.67177,1.69632 -3.05327,2.97373 -5.48633,2.6875 -1.98998,-0.23411 -3.41357,-1.22813 -4.10351,-2.33203 -0.68994,-1.10391 -0.68215,-2.23778 0.14844,-3.06836 0.83795,-0.83796 1.98844,-0.89361 3.08398,-0.26368 1.09554,0.62994 2.08242,1.9799 2.31641,3.96875 a 0.50005,0.50005 0 1 0 0.99218,-0.11718 c -0.26601,-2.26115 -1.40413,-3.91119 -2.80859,-4.71875 -0.70223,-0.40379 -1.48457,-0.58895 -2.23633,-0.52735 z m 3.54102,9.04883 a 0.50005,0.50005 0 0 0 -0.37696,0.1875 c -0.31249,0.377 -0.92604,0.69672 -1.66015,0.78906 a 0.50005,0.50005 0 1 0 0.125,0.99219 c 0.94034,-0.11828 1.77818,-0.50935 2.30469,-1.14453 a 0.50005,0.50005 0 0 0 -0.39258,-0.82422 z"
+ id="path22178"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 331.50586,410 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -10,10 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path22182"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccc" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22365"
+ transform="translate(-1.8536743e-6,-25.999995)">
+ <path
+ id="path22215"
+ d="m 302,649 v 8 h 4 v -8 z m 1,1 h 2 v 1 h -2 z m 0,2 h 2 v 1 h -2 z m 0,2 h 2 v 1 h -2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="sssssssssccccc"
+ inkscape:connector-curvature="0"
+ id="rect21916"
+ d="m 301.5,647 c -0.82235,0 -1.5,0.67765 -1.5,1.5 v 9 c 0,0.82235 0.67765,1.5 1.5,1.5 h 11 c 0.82235,0 1.5,-0.67765 1.5,-1.5 v -9 c 0,-0.82235 -0.67765,-1.5 -1.5,-1.5 z m -0.5,1 h 12 v 10 h -12 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22423">
+ <g
+ id="g22461"
+ style="fill:#ffffff">
+ <path
+ sodipodi:nodetypes="ssscccssssccsss"
+ inkscape:connector-curvature="0"
+ id="path22413"
+ d="m 175.5,599 c -0.82235,0 -1.5,0.67765 -1.5,1.5 v 6 c 0,0.64672 0.42101,1.19773 1,1.40625 V 606.5 v -3 -3 c 0,-0.28564 0.21436,-0.5 0.5,-0.5 h 9 c 0.28564,0 0.5,0.21436 0.5,0.5 v 1.5 h 1 v -1.5 c 0,-0.82235 -0.67765,-1.5 -1.5,-1.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ id="rect22415"
+ transform="translate(0,-50)"
+ d="m 177.5,653 c -0.82235,0 -1.5,0.67765 -1.5,1.5 v 6 c 0,0.82235 0.67765,1.5 1.5,1.5 h 9 c 0.82235,0 1.5,-0.67765 1.5,-1.5 v -6 c 0,-0.82235 -0.67765,-1.5 -1.5,-1.5 z m 2.00391,2 c 0.1882,0.002 0.35956,0.10882 0.44336,0.27734 l 2,4 c 0.16517,0.33222 -0.0763,0.72229 -0.44727,0.72266 h -4 c -0.37097,-3.7e-4 -0.61244,-0.39044 -0.44727,-0.72266 l 2,-4 c 0.0851,-0.17104 0.26016,-0.27834 0.45118,-0.27734 z m 3.99609,0 h 3 a 0.50005,0.50005 0 1 1 0,1 h -3 a 0.50005,0.50005 0 1 1 0,-1 z m 0,2 h 3 a 0.50005,0.50005 0 1 1 0,1 h -3 a 0.50005,0.50005 0 1 1 0,-1 z m 0,2 h 2 a 0.50005,0.50005 0 1 1 0,1 h -2 a 0.50005,0.50005 0 1 1 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <path sodipodi:nodetypes="cccccccccccccccscccccccccccccc" inkscape:connector-curvature="0" id="path22769" d="m 517.98438,9.9863345 c -0.55152,0.009 -0.99193,0.4621405 -0.98438,1.0136695 v 7 h -1.10156 l -0.91016,-6.14648 c -0.0643,-0.48249 -0.46671,-0.84859 -0.95312,-0.86719 -0.63083,-0.0229 -1.12488,0.53711 -1.02344,1.16015 L 514,18.816414 v 0.88671 1.296881 h -1 v -1.746091 l -2.58984,-1.16602 c -0.12175,-0.0548 -0.25324,-0.0847 -0.38672,-0.0879 -0.88449,-0.0197 -1.35703,1.03438 -0.75391,1.68164 l 3.5,3.750001 c 1.45044,1.55404 3.38812,2.64316 5.12305,2.55469 2.20226,-0.16055 4.09501,-1.6226 4.80664,-3.71289 l 2.25586,-6.269531 c 0.1808,-0.48082 -0.16432,-0.99701 -0.67774,-1.01368 -0.32862,-0.0101 -0.62553,0.19494 -0.73242,0.50586 l -0.90039,2.50392 h -0.74023 l 1.07812,-5.81836 c 0.12593,-0.63116 -0.36843,-1.215229 -1.01172,-1.19531 -0.47506,0.0156 -0.8735,0.36343 -0.95312,0.83203 l -1.14453,6.18164 H 519 v -7 c 0.008,-0.563769 -0.45189,-1.0224695 -1.01562,-1.0136695 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 264.49219,453.00195 a 0.50005,0.50005 0 0 0 -0.34571,0.14649 l -5,4.99804 a 0.50005,0.50005 0 0 0 0,0.70704 l 5,5 a 0.50005,0.50005 0 0 0 0.70508,0 l 4.99219,-4.97852 a 0.50005,0.50005 0 0 0 0.002,-0.70703 l -4.99218,-5.01953 a 0.50005,0.50005 0 0 0 -0.36133,-0.14649 z m 0.006,1.20703 4.28711,4.31055 -4.2853,4.27344 -4.29297,-4.29297 z" id="path22390" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 243.49219,453 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -5,5 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 5,5 c 0.19504,0.19389 0.51004,0.19389 0.70508,0 l 4.99219,-4.97852 c 0.19574,-0.19471 0.19663,-0.51121 0.002,-0.70703 l -4.99218,-5.02149 c -0.0957,-0.0957 -0.22606,-0.14857 -0.36138,-0.14648 z" id="path22397" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccc"/>
- <g transform="matrix(-1,0,0,1,384.8323,63.000015)" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g23034">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 310.58203,494 c -1.1875,0 -2.13583,0.69085 -2.52344,1.62109 -0.3876,0.93025 -0.20775,2.10475 0.66993,2.98243 l 2.5,2.5 c 0.62232,0.62232 0.69247,1.32282 0.45507,1.89257 C 311.4462,503.56585 310.89453,504 310.08203,504 l -6.53515,-0.008 2.13867,-2.13867 a 0.50005,0.50005 0 1 0 -0.70703,-0.70704 l -2.9336,2.93555 -0.01,0.008 a 0.50005,0.50005 0 0 0 -0.20704,0.41602 0.50005,0.50005 0 0 0 0,0.008 0.50005,0.50005 0 0 0 0.004,0.0469 0.50005,0.50005 0 0 0 0.008,0.0488 0.50005,0.50005 0 0 0 0.19336,0.29882 l 2.94532,2.94532 a 0.50005,0.50005 0 1 0 0.70703,-0.70704 l -2.1543,-2.15429 6.55078,0.008 c 1.1875,0 2.13584,-0.69085 2.52344,-1.62109 0.3876,-0.93025 0.20775,-2.10475 -0.66992,-2.98243 l -2.5,-2.5 c -0.62233,-0.62232 -0.69248,-1.32282 -0.45508,-1.89257 0.2374,-0.56976 0.78906,-1.00391 1.60156,-1.00391 h 4.75 a 0.50005,0.50005 0 1 0 0,-1 z" id="path23032" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g22949" transform="matrix(1,0,0,-1,168,540.00935)">
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" transform="matrix(0,-1,-1,0,558.00846,761.00467)" id="g22540" style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 469.00195,355 C 467.90167,355 467,355.90326 467,357.00391 c 0,1.10064 0.90167,2.00391 2.00195,2.0039 1.10028,0 2.00196,-0.90326 2.00196,-2.0039 0,-1.10064 -0.90168,-2.00391 -2.00196,-2.00391 z" id="path22508" inkscape:connector-curvature="0" sodipodi:nodetypes="sscss"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 468.5,349 c -0.82251,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.67749,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.82251 -0.67749,-1.5 -1.5,-1.5 z" id="path22516" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 475.5,356 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z" id="path22518" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 474.50195,350.00781 c -0.82202,10e-6 -1.50195,0.67415 -1.50195,1.4961 0,0.82195 0.67993,1.49609 1.50195,1.49609 0.82203,0 1.50195,-0.67414 1.50196,-1.49609 -1e-5,-0.82196 -0.67993,-1.4961 -1.50196,-1.4961 z" id="path22520" inkscape:connector-curvature="0" sodipodi:nodetypes="csscc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 468,351.5 v 4 h 1 v -4 z m 5.14648,0.64648 -3.49609,3.50977 0.70899,0.70508 3.49414,-3.50781 z M 470.5,357 v 1 h 4 v -1 z" id="path22536" inkscape:connector-curvature="0"/>
+ <path
+ sodipodi:nodetypes="cccccccccccccccscccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path22769"
+ d="m 517.98438,9.9863345 c -0.55152,0.009 -0.99193,0.4621405 -0.98438,1.0136695 v 7 h -1.10156 l -0.91016,-6.14648 c -0.0643,-0.48249 -0.46671,-0.84859 -0.95312,-0.86719 -0.63083,-0.0229 -1.12488,0.53711 -1.02344,1.16015 L 514,18.816414 v 0.88671 1.296881 h -1 v -1.746091 l -2.58984,-1.16602 c -0.12175,-0.0548 -0.25324,-0.0847 -0.38672,-0.0879 -0.88449,-0.0197 -1.35703,1.03438 -0.75391,1.68164 l 3.5,3.750001 c 1.45044,1.55404 3.38812,2.64316 5.12305,2.55469 2.20226,-0.16055 4.09501,-1.6226 4.80664,-3.71289 l 2.25586,-6.269531 c 0.1808,-0.48082 -0.16432,-0.99701 -0.67774,-1.01368 -0.32862,-0.0101 -0.62553,0.19494 -0.73242,0.50586 l -0.90039,2.50392 h -0.74023 l 1.07812,-5.81836 c 0.12593,-0.63116 -0.36843,-1.215229 -1.01172,-1.19531 -0.47506,0.0156 -0.8735,0.36343 -0.95312,0.83203 l -1.14453,6.18164 H 519 v -7 c 0.008,-0.563769 -0.45189,-1.0224695 -1.01562,-1.0136695 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 264.49219,453.00195 a 0.50005,0.50005 0 0 0 -0.34571,0.14649 l -5,4.99804 a 0.50005,0.50005 0 0 0 0,0.70704 l 5,5 a 0.50005,0.50005 0 0 0 0.70508,0 l 4.99219,-4.97852 a 0.50005,0.50005 0 0 0 0.002,-0.70703 l -4.99218,-5.01953 a 0.50005,0.50005 0 0 0 -0.36133,-0.14649 z m 0.006,1.20703 4.28711,4.31055 -4.2853,4.27344 -4.29297,-4.29297 z"
+ id="path22390"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 243.49219,453 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -5,5 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 5,5 c 0.19504,0.19389 0.51004,0.19389 0.70508,0 l 4.99219,-4.97852 c 0.19574,-0.19471 0.19663,-0.51121 0.002,-0.70703 l -4.99218,-5.02149 c -0.0957,-0.0957 -0.22606,-0.14857 -0.36138,-0.14648 z"
+ id="path22397"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccc" />
+ <g
+ transform="matrix(-1,0,0,1,384.8323,63.000015)"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g23034">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 310.58203,494 c -1.1875,0 -2.13583,0.69085 -2.52344,1.62109 -0.3876,0.93025 -0.20775,2.10475 0.66993,2.98243 l 2.5,2.5 c 0.62232,0.62232 0.69247,1.32282 0.45507,1.89257 C 311.4462,503.56585 310.89453,504 310.08203,504 l -6.53515,-0.008 2.13867,-2.13867 a 0.50005,0.50005 0 1 0 -0.70703,-0.70704 l -2.9336,2.93555 -0.01,0.008 a 0.50005,0.50005 0 0 0 -0.20704,0.41602 0.50005,0.50005 0 0 0 0,0.008 0.50005,0.50005 0 0 0 0.004,0.0469 0.50005,0.50005 0 0 0 0.008,0.0488 0.50005,0.50005 0 0 0 0.19336,0.29882 l 2.94532,2.94532 a 0.50005,0.50005 0 1 0 0.70703,-0.70704 l -2.1543,-2.15429 6.55078,0.008 c 1.1875,0 2.13584,-0.69085 2.52344,-1.62109 0.3876,-0.93025 0.20775,-2.10475 -0.66992,-2.98243 l -2.5,-2.5 c -0.62233,-0.62232 -0.69248,-1.32282 -0.45508,-1.89257 0.2374,-0.56976 0.78906,-1.00391 1.60156,-1.00391 h 4.75 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path23032"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22949"
+ transform="matrix(1,0,0,-1,168,540.00935)">
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="matrix(0,-1,-1,0,558.00846,761.00467)"
+ id="g22540"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 469.00195,355 C 467.90167,355 467,355.90326 467,357.00391 c 0,1.10064 0.90167,2.00391 2.00195,2.0039 1.10028,0 2.00196,-0.90326 2.00196,-2.0039 0,-1.10064 -0.90168,-2.00391 -2.00196,-2.00391 z"
+ id="path22508"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sscss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 468.5,349 c -0.82251,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.67749,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.82251 -0.67749,-1.5 -1.5,-1.5 z"
+ id="path22516"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 475.5,356 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z"
+ id="path22518"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 474.50195,350.00781 c -0.82202,10e-6 -1.50195,0.67415 -1.50195,1.4961 0,0.82195 0.67993,1.49609 1.50195,1.49609 0.82203,0 1.50195,-0.67414 1.50196,-1.49609 -1e-5,-0.82196 -0.67993,-1.4961 -1.50196,-1.4961 z"
+ id="path22520"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csscc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 468,351.5 v 4 h 1 v -4 z m 5.14648,0.64648 -3.49609,3.50977 0.70899,0.70508 3.49414,-3.50781 z M 470.5,357 v 1 h 4 v -1 z"
+ id="path22536"
+ inkscape:connector-curvature="0" />
</g>
- <g style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new" id="g22761" transform="matrix(0,-1,-1,0,554.00846,765.00467)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 468.5,349 c -0.82251,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.67749,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.82251 -0.67749,-1.5 -1.5,-1.5 z m 0,1 c 0.28207,0 0.5,0.21793 0.5,0.5 0,0.28207 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28207 0.21793,-0.5 0.5,-0.5 z m 0.50195,5 C 467.90167,355 467,355.90326 467,357.00391 c 0,1.10064 0.90167,2.00391 2.00195,2.0039 1.10028,0 2.00196,-0.90326 2.00196,-2.0039 0,-1.10064 -0.90168,-2.00391 -2.00196,-2.00391 z m 0,1 c 0.55916,0 1.00196,0.44302 1.00196,1.00391 0,0.56088 -0.4428,1.0039 -1.00196,1.0039 -0.55915,0 -1.00195,-0.44302 -1.00195,-1.0039 C 468,356.44302 468.4428,356 469.00195,356 Z m 6.49805,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z" id="path22750" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 468,351.5 v 4 h 1 v -4 z" id="path22755" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 470.5,357 v 1 h 4 v -1 z" id="path22757" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ id="g22761"
+ transform="matrix(0,-1,-1,0,554.00846,765.00467)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 468.5,349 c -0.82251,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.67749,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.82251 -0.67749,-1.5 -1.5,-1.5 z m 0,1 c 0.28207,0 0.5,0.21793 0.5,0.5 0,0.28207 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28207 0.21793,-0.5 0.5,-0.5 z m 0.50195,5 C 467.90167,355 467,355.90326 467,357.00391 c 0,1.10064 0.90167,2.00391 2.00195,2.0039 1.10028,0 2.00196,-0.90326 2.00196,-2.0039 0,-1.10064 -0.90168,-2.00391 -2.00196,-2.00391 z m 0,1 c 0.55916,0 1.00196,0.44302 1.00196,1.00391 0,0.56088 -0.4428,1.0039 -1.00196,1.0039 -0.55915,0 -1.00195,-0.44302 -1.00195,-1.0039 C 468,356.44302 468.4428,356 469.00195,356 Z m 6.49805,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z"
+ id="path22750"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 468,351.5 v 4 h 1 v -4 z"
+ id="path22755"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 470.5,357 v 1 h 4 v -1 z"
+ id="path22757"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g22484" transform="translate(-220,-220)">
- <path id="path22480" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 334.5,777 c -0.15738,-3e-4 -0.30571,0.0735 -0.40039,0.19922 L 332.75,779 H 332 c -0.54535,0 -1,0.45465 -1,1 v 9 c 0,0.54535 0.45465,1 1,1 h 12 c 0.54535,0 1,-0.45465 1,-1 v -9 c 0,-0.54535 -0.45465,-1 -1,-1 h -3.75 l -1.34961,-1.80078 C 338.80571,777.07351 338.65738,776.9997 338.5,777 Z m 1,1 h 2 c 0.27613,3e-5 0.49997,0.22387 0.5,0.5 v 1 c -3e-5,0.27613 -0.22387,0.49997 -0.5,0.5 h -2 c -0.27613,-3e-5 -0.49997,-0.22387 -0.5,-0.5 v -1 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 z m -3.5,3 h 9 v 7 h -9 v -6.5 z m 11,1 c 0.54636,0 1,0.45364 1,1 0,0.54636 -0.45364,1 -1,1 -0.54636,0 -1,-0.45364 -1,-1 0,-0.54636 0.45364,-1 1,-1 z m 0,4 c 0.54636,0 1,0.45364 1,1 0,0.54636 -0.45364,1 -1,1 -0.54636,0 -1,-0.45364 -1,-1 0,-0.54636 0.45364,-1 1,-1 z" inkscape:connector-curvature="0" sodipodi:nodetypes="cccsssssssscccccccccccccccccccssssssssss"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.2;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 333.5,782 a 0.50005006,0.50005006 0 1 0 0,1 h 6.00195 a 0.50005006,0.50005006 0 1 0 0,-1 z m 0,2 a 0.50005006,0.50005006 0 1 0 0,1 h 6.00195 a 0.50005006,0.50005006 0 1 0 0,-1 z m 0,2 a 0.50005006,0.50005006 0 1 0 0,1 h 6.00195 a 0.50005006,0.50005006 0 1 0 0,-1 z" id="path22526" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" d="m 342.50195,777 c -0.67617,-0.01 -0.67617,1.00957 0,1 h 1 c 0.67617,0.01 0.67617,-1.00957 0,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" id="path22529" sodipodi:nodetypes="ccccc"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g22589">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 120.85938,263.01172 c -2.71113,-0.14985 -5.132,0.84146 -7.07032,2.78125 -2.61921,2.6212 -3.50441,6.90582 -2.24609,9.9043 0.25386,0.60493 0.66496,1.06469 1.2168,1.20507 0.55183,0.14039 1.13738,-0.0925 1.59375,-0.54882 l 10,-10 a 0.50005,0.50005 0 0 0 0.01,-0.01 c 0.45574,-0.48275 0.74002,-1.03795 0.61133,-1.61328 -0.12869,-0.57533 -0.64203,-0.96413 -1.31445,-1.18164 -0.96105,-0.31088 -1.89708,-0.48716 -2.80078,-0.53711 z m -0.0586,0.98437 c 0.81237,0.051 1.66258,0.21855 2.55078,0.50586 0.49509,0.16015 0.62426,0.33915 0.64844,0.44727 0.0242,0.10812 -0.028,0.35187 -0.36328,0.70703 l -9.99024,9.99023 c -0.29363,0.29364 -0.48952,0.32555 -0.64062,0.28711 -0.1511,-0.0384 -0.36452,-0.20246 -0.54102,-0.62304 -1.05362,-2.51071 -0.27172,-6.50583 2.03125,-8.81055 1.77041,-1.77175 3.86758,-2.65679 6.30469,-2.50391 z M 115.48438,267 a 0.50005,0.50005 0 0 0 -0.34376,0.15234 C 113.75486,268.5381 112.997,270.82305 113,272.5 a 0.50005,0.50005 0 1 0 1,0 c -0.002,-1.34281 0.7435,-3.53647 1.84766,-4.64062 A 0.50005,0.50005 0 0 0 115.48438,267 Z m 7.02343,3 a 0.50005,0.50005 0 1 0 0,1 c 0.67897,0 1.01439,0.13886 1.19922,0.33398 0.18483,0.19513 0.30078,0.54691 0.30078,1.16602 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.74159 -0.136,-1.38882 -0.57617,-1.85352 C 123.99147,270.18179 123.32885,270 122.50781,270 Z m -2.01562,1.99219 A 0.50005,0.50005 0 0 0 120,272.5 c 0,0.86111 0.31215,1.53681 0.80469,1.94727 0.49254,0.41045 1.11198,0.55273 1.69531,0.55273 0.41667,0 0.79723,0.10772 1.05469,0.32227 C 123.81215,275.53681 124,275.86111 124,276.5 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.86111 -0.31215,-1.53681 -0.80469,-1.94727 C 123.70277,274.14228 123.08333,274 122.5,274 c -0.41667,0 -0.79723,-0.10772 -1.05469,-0.32227 C 121.18785,273.46319 121,273.13889 121,272.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -2,2 A 0.50005,0.50005 0 0 0 118,274.5 c 0,0.82103 0.18179,1.48561 0.64648,1.92578 C 119.11118,276.86595 119.75841,277 120.5,277 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -1 c -0.61911,0 -0.97089,-0.11595 -1.16602,-0.30078 C 119.13886,275.51439 119,275.17897 119,274.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" id="path22545" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 310.26367,452.0293 c -0.67255,-0.0123 -1.33821,0.3 -1.8789,0.8789 l -0.23829,0.23828 a 0.50004997,0.50004997 0 0 0 -0.084,0.10938 0.50004997,0.50004997 0 0 0 -0.0879,0.0723 l -1.26563,1.25196 c -0.23797,0.23547 -0.44036,0.48356 -0.58984,0.75781 a 0.50004997,0.50004997 0 1 0 0.87695,0.47852 c 0.0885,-0.16243 0.22753,-0.33889 0.41602,-0.52539 l 1.26562,-1.25391 a 0.50004997,0.50004997 0 0 0 0.0899,-0.11523 0.50004997,0.50004997 0 0 0 0.002,-0.002 0.50004997,0.50004997 0 0 0 0.084,-0.0664 l 0.25,-0.25 a 0.50004997,0.50004997 0 0 0 0.0117,-0.0117 c 0.39332,-0.4211 0.76594,-0.57109 1.12891,-0.56446 0.36298,0.007 0.75841,0.18208 1.15234,0.57618 0.39504,0.3952 0.56757,0.78617 0.57422,1.14648 0.007,0.36031 -0.14053,0.73397 -0.56445,1.13672 l -0.26758,0.2539 a 0.50004997,0.50004997 0 0 0 -0.0957,0.12305 0.50004997,0.50004997 0 0 0 -0.0859,0.0684 l -1.25,1.25 a 0.50004997,0.50004997 0 0 0 -0.0137,0.0117 c -0.16233,0.1738 -0.32346,0.30196 -0.48047,0.39063 a 0.50026213,0.50026213 0 1 0 0.49219,0.87109 c 0.25644,-0.14482 0.49753,-0.33919 0.7207,-0.57813 l 1.23828,-1.23828 a 0.50004997,0.50004997 0 0 0 0.0859,-0.11133 0.50004997,0.50004997 0 0 0 0.0781,-0.0625 l 0.26563,-0.25195 c 0.57608,-0.54732 0.88934,-1.2117 0.87695,-1.88281 -0.0124,-0.67111 -0.33835,-1.30493 -0.86718,-1.83399 -0.52994,-0.53015 -1.16729,-0.85488 -1.83985,-0.86718 z m -1.77344,3.96679 a 0.50004997,0.50004997 0 0 0 -0.34375,0.15039 l -4.01367,4.01563 a 0.50004997,0.50004997 0 1 0 0.70703,0.70703 l 4.01368,-4.01562 a 0.50004997,0.50004997 0 0 0 -0.36329,-0.85743 z m -4.94921,2.1836 a 0.50004997,0.50004997 0 0 0 -0.22852,0.0469 c -0.33394,0.14944 -0.64532,0.37928 -0.92773,0.68164 l -1.23829,1.23828 a 0.50004997,0.50004997 0 0 0 -0.0547,0.0645 l -0.18555,0.17578 c -0.57608,0.54731 -0.88934,1.2117 -0.87695,1.88281 0.0124,0.67111 0.33835,1.30494 0.86718,1.83399 0.52994,0.53016 1.16729,0.85489 1.83985,0.86718 0.67255,0.0123 1.33821,-0.3 1.8789,-0.8789 l 0.23829,-0.23828 a 0.50004997,0.50004997 0 0 0 0.0605,-0.0723 0.50004997,0.50004997 0 0 0 0.004,-0.004 l 1.18359,-1.17187 c 0.27971,-0.27677 0.50962,-0.57119 0.66211,-0.9043 a 0.50004997,0.50004997 0 1 0 -0.9082,-0.41601 c -0.0851,0.18591 -0.2355,0.39018 -0.45703,0.60937 l -1.26563,1.25391 a 0.50004997,0.50004997 0 0 0 -0.0664,0.0762 0.50004997,0.50004997 0 0 0 -0.004,0.006 l -0.16602,0.16601 a 0.50004997,0.50004997 0 0 0 -0.0117,0.0117 c -0.39332,0.4211 -0.76594,0.57109 -1.12891,0.56446 -0.36298,-0.007 -0.75841,-0.18208 -1.15234,-0.57618 -0.39505,-0.3952 -0.56758,-0.78617 -0.57422,-1.14648 -0.007,-0.36031 0.14053,-0.73396 0.56445,-1.13672 l 0.26758,-0.2539 a 0.50004997,0.50004997 0 0 0 0.0742,-0.0879 l 1.16797,-1.16796 a 0.50004997,0.50004997 0 0 0 0.0117,-0.0117 c 0.20545,-0.21996 0.40997,-0.36564 0.60547,-0.45313 a 0.50004997,0.50004997 0 0 0 -0.17968,-0.95898 z" id="path23240-3" inkscape:connector-curvature="0"/>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g23545-6" transform="rotate(-90,318.41616,448.41614)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 393.99219,462.28516 -2.13867,-2.13868 c -0.318,-0.32528 -0.86991,-0.0915 -0.85743,0.36329 0.004,0.12976 0.0575,0.25303 0.15039,0.34375 l 2.93555,2.93359 0.008,0.01 c 0.0962,0.13317 0.25175,0.21055 0.41602,0.20703 0.003,2e-5 0.005,2e-5 0.008,0 0.0157,-6e-4 0.0313,-0.002 0.0469,-0.004 0.0164,-0.002 0.0327,-0.005 0.0488,-0.008 0.11995,-0.0256 0.2263,-0.0944 0.29882,-0.19336 l 2.94532,-2.94531 c 0.49057,-0.47126 -0.23578,-1.19761 -0.70704,-0.70704 l -2.15429,2.1543 L 395,457.5 c 0,-2.47936 -2.02064,-4.5 -4.5,-4.5 -2.47936,0 -4.5,2.02064 -4.5,4.5 v 6 c -0.01,0.67616 1.00956,0.67616 1,0 v -6 c 0,-1.93892 1.56108,-3.5 3.5,-3.5 1.93826,0 3.49893,1.56005 3.5,3.49902 z" transform="rotate(90,318.41616,448.41614)" id="path23541-6" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccssccsscc"/>
- </g>
- <g transform="translate(-346,-11.999995)" id="g24012-1" style="display:inline;fill:#ffffff;enable-background:new">
- <g style="opacity:0.7;fill:#ffffff;stroke-width:1.18252182" transform="matrix(0.84565033,0,0,0.84565033,271.3184,206.1572)" id="g24008-0">
- <g style="fill:#ffffff;stroke-width:1.18252182" transform="translate(829,-385)" id="g24002-7"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.18252182;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 480.06836,304.9375 c -0.78863,-0.0147 -1.5648,0.35582 -2.23633,1.02734 l -1.47851,1.47852 a 0.59132004,0.59132004 0 1 0 0.83593,0.83594 l 1.47852,-1.47852 c 0.51101,-0.511 0.96056,-0.68742 1.37695,-0.67969 0.41639,0.008 0.86317,0.20868 1.33399,0.67969 0.4709,0.4711 0.67191,0.91763 0.67968,1.33399 0.008,0.41635 -0.16868,0.86595 -0.67968,1.37695 l -1.47852,1.47851 a 0.59132004,0.59132004 0 1 0 0.83594,0.83594 l 1.47851,-1.47851 c 0.67153,-0.67153 1.04012,-1.44777 1.02539,-2.23633 -0.0147,-0.78856 -0.40379,-1.52464 -1.02539,-2.14649 -0.62168,-0.62194 -1.35785,-1.01269 -2.14648,-1.02734 z m -0.94336,3.50977 a 0.59132004,0.59132004 0 0 0 -0.40625,0.17773 l -1.47852,1.47852 a 0.59132004,0.59132004 0 1 0 0.83594,0.83593 l 1.47852,-1.47851 a 0.59132004,0.59132004 0 0 0 -0.42969,-1.01367 z m -8.27344,4.72851 a 0.59132004,0.59132004 0 0 0 -0.4082,0.17774 l -1.51367,1.49218 a 0.59132004,0.59132004 0 0 0 -0.008,0.006 c -0.65272,0.66501 -1.01668,1.4358 -1.00782,2.22266 0.009,0.78686 0.38697,1.53124 1.01172,2.15625 0.62485,0.62507 1.3751,1.00952 2.16992,1.01953 0.79483,0.01 1.57721,-0.36041 2.25,-1.0332 l 1.47852,-1.47657 a 0.59178867,0.59178867 0 1 0 -0.83594,-0.83789 l -1.47851,1.47852 c -0.50973,0.50972 -0.97241,0.69289 -1.40039,0.6875 -0.42799,-0.005 -0.87805,-0.206 -1.34571,-0.67383 -0.46775,-0.46794 -0.66322,-0.91244 -0.66797,-1.33398 -0.005,-0.42154 0.17763,-0.8773 0.67188,-1.38086 l 1.50586,-1.48438 a 0.59132004,0.59132004 0 0 0 -0.42188,-1.01953 z m 2.65625,0.88867 a 0.59132004,0.59132004 0 0 0 -0.40625,0.17774 l -1.47851,1.47851 a 0.59132004,0.59132004 0 1 0 0.83593,0.83594 l 1.47852,-1.47852 a 0.59132004,0.59132004 0 0 0 -0.42969,-1.01367 z" id="path24006-7" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22484"
+ transform="translate(-220,-220)">
+ <path
+ id="path22480"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 334.5,777 c -0.15738,-3e-4 -0.30571,0.0735 -0.40039,0.19922 L 332.75,779 H 332 c -0.54535,0 -1,0.45465 -1,1 v 9 c 0,0.54535 0.45465,1 1,1 h 12 c 0.54535,0 1,-0.45465 1,-1 v -9 c 0,-0.54535 -0.45465,-1 -1,-1 h -3.75 l -1.34961,-1.80078 C 338.80571,777.07351 338.65738,776.9997 338.5,777 Z m 1,1 h 2 c 0.27613,3e-5 0.49997,0.22387 0.5,0.5 v 1 c -3e-5,0.27613 -0.22387,0.49997 -0.5,0.5 h -2 c -0.27613,-3e-5 -0.49997,-0.22387 -0.5,-0.5 v -1 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 z m -3.5,3 h 9 v 7 h -9 v -6.5 z m 11,1 c 0.54636,0 1,0.45364 1,1 0,0.54636 -0.45364,1 -1,1 -0.54636,0 -1,-0.45364 -1,-1 0,-0.54636 0.45364,-1 1,-1 z m 0,4 c 0.54636,0 1,0.45364 1,1 0,0.54636 -0.45364,1 -1,1 -0.54636,0 -1,-0.45364 -1,-1 0,-0.54636 0.45364,-1 1,-1 z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccsssssssscccccccccccccccccccssssssssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.2;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 333.5,782 a 0.50005006,0.50005006 0 1 0 0,1 h 6.00195 a 0.50005006,0.50005006 0 1 0 0,-1 z m 0,2 a 0.50005006,0.50005006 0 1 0 0,1 h 6.00195 a 0.50005006,0.50005006 0 1 0 0,-1 z m 0,2 a 0.50005006,0.50005006 0 1 0 0,1 h 6.00195 a 0.50005006,0.50005006 0 1 0 0,-1 z"
+ id="path22526"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 342.50195,777 c -0.67617,-0.01 -0.67617,1.00957 0,1 h 1 c 0.67617,0.01 0.67617,-1.00957 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="path22529"
+ sodipodi:nodetypes="ccccc" />
+ </g>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22589">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 120.85938,263.01172 c -2.71113,-0.14985 -5.132,0.84146 -7.07032,2.78125 -2.61921,2.6212 -3.50441,6.90582 -2.24609,9.9043 0.25386,0.60493 0.66496,1.06469 1.2168,1.20507 0.55183,0.14039 1.13738,-0.0925 1.59375,-0.54882 l 10,-10 a 0.50005,0.50005 0 0 0 0.01,-0.01 c 0.45574,-0.48275 0.74002,-1.03795 0.61133,-1.61328 -0.12869,-0.57533 -0.64203,-0.96413 -1.31445,-1.18164 -0.96105,-0.31088 -1.89708,-0.48716 -2.80078,-0.53711 z m -0.0586,0.98437 c 0.81237,0.051 1.66258,0.21855 2.55078,0.50586 0.49509,0.16015 0.62426,0.33915 0.64844,0.44727 0.0242,0.10812 -0.028,0.35187 -0.36328,0.70703 l -9.99024,9.99023 c -0.29363,0.29364 -0.48952,0.32555 -0.64062,0.28711 -0.1511,-0.0384 -0.36452,-0.20246 -0.54102,-0.62304 -1.05362,-2.51071 -0.27172,-6.50583 2.03125,-8.81055 1.77041,-1.77175 3.86758,-2.65679 6.30469,-2.50391 z M 115.48438,267 a 0.50005,0.50005 0 0 0 -0.34376,0.15234 C 113.75486,268.5381 112.997,270.82305 113,272.5 a 0.50005,0.50005 0 1 0 1,0 c -0.002,-1.34281 0.7435,-3.53647 1.84766,-4.64062 A 0.50005,0.50005 0 0 0 115.48438,267 Z m 7.02343,3 a 0.50005,0.50005 0 1 0 0,1 c 0.67897,0 1.01439,0.13886 1.19922,0.33398 0.18483,0.19513 0.30078,0.54691 0.30078,1.16602 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.74159 -0.136,-1.38882 -0.57617,-1.85352 C 123.99147,270.18179 123.32885,270 122.50781,270 Z m -2.01562,1.99219 A 0.50005,0.50005 0 0 0 120,272.5 c 0,0.86111 0.31215,1.53681 0.80469,1.94727 0.49254,0.41045 1.11198,0.55273 1.69531,0.55273 0.41667,0 0.79723,0.10772 1.05469,0.32227 C 123.81215,275.53681 124,275.86111 124,276.5 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.86111 -0.31215,-1.53681 -0.80469,-1.94727 C 123.70277,274.14228 123.08333,274 122.5,274 c -0.41667,0 -0.79723,-0.10772 -1.05469,-0.32227 C 121.18785,273.46319 121,273.13889 121,272.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -2,2 A 0.50005,0.50005 0 0 0 118,274.5 c 0,0.82103 0.18179,1.48561 0.64648,1.92578 C 119.11118,276.86595 119.75841,277 120.5,277 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -1 c -0.61911,0 -0.97089,-0.11595 -1.16602,-0.30078 C 119.13886,275.51439 119,275.17897 119,274.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path22545"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 310.26367,452.0293 c -0.67255,-0.0123 -1.33821,0.3 -1.8789,0.8789 l -0.23829,0.23828 a 0.50004997,0.50004997 0 0 0 -0.084,0.10938 0.50004997,0.50004997 0 0 0 -0.0879,0.0723 l -1.26563,1.25196 c -0.23797,0.23547 -0.44036,0.48356 -0.58984,0.75781 a 0.50004997,0.50004997 0 1 0 0.87695,0.47852 c 0.0885,-0.16243 0.22753,-0.33889 0.41602,-0.52539 l 1.26562,-1.25391 a 0.50004997,0.50004997 0 0 0 0.0899,-0.11523 0.50004997,0.50004997 0 0 0 0.002,-0.002 0.50004997,0.50004997 0 0 0 0.084,-0.0664 l 0.25,-0.25 a 0.50004997,0.50004997 0 0 0 0.0117,-0.0117 c 0.39332,-0.4211 0.76594,-0.57109 1.12891,-0.56446 0.36298,0.007 0.75841,0.18208 1.15234,0.57618 0.39504,0.3952 0.56757,0.78617 0.57422,1.14648 0.007,0.36031 -0.14053,0.73397 -0.56445,1.13672 l -0.26758,0.2539 a 0.50004997,0.50004997 0 0 0 -0.0957,0.12305 0.50004997,0.50004997 0 0 0 -0.0859,0.0684 l -1.25,1.25 a 0.50004997,0.50004997 0 0 0 -0.0137,0.0117 c -0.16233,0.1738 -0.32346,0.30196 -0.48047,0.39063 a 0.50026213,0.50026213 0 1 0 0.49219,0.87109 c 0.25644,-0.14482 0.49753,-0.33919 0.7207,-0.57813 l 1.23828,-1.23828 a 0.50004997,0.50004997 0 0 0 0.0859,-0.11133 0.50004997,0.50004997 0 0 0 0.0781,-0.0625 l 0.26563,-0.25195 c 0.57608,-0.54732 0.88934,-1.2117 0.87695,-1.88281 -0.0124,-0.67111 -0.33835,-1.30493 -0.86718,-1.83399 -0.52994,-0.53015 -1.16729,-0.85488 -1.83985,-0.86718 z m -1.77344,3.96679 a 0.50004997,0.50004997 0 0 0 -0.34375,0.15039 l -4.01367,4.01563 a 0.50004997,0.50004997 0 1 0 0.70703,0.70703 l 4.01368,-4.01562 a 0.50004997,0.50004997 0 0 0 -0.36329,-0.85743 z m -4.94921,2.1836 a 0.50004997,0.50004997 0 0 0 -0.22852,0.0469 c -0.33394,0.14944 -0.64532,0.37928 -0.92773,0.68164 l -1.23829,1.23828 a 0.50004997,0.50004997 0 0 0 -0.0547,0.0645 l -0.18555,0.17578 c -0.57608,0.54731 -0.88934,1.2117 -0.87695,1.88281 0.0124,0.67111 0.33835,1.30494 0.86718,1.83399 0.52994,0.53016 1.16729,0.85489 1.83985,0.86718 0.67255,0.0123 1.33821,-0.3 1.8789,-0.8789 l 0.23829,-0.23828 a 0.50004997,0.50004997 0 0 0 0.0605,-0.0723 0.50004997,0.50004997 0 0 0 0.004,-0.004 l 1.18359,-1.17187 c 0.27971,-0.27677 0.50962,-0.57119 0.66211,-0.9043 a 0.50004997,0.50004997 0 1 0 -0.9082,-0.41601 c -0.0851,0.18591 -0.2355,0.39018 -0.45703,0.60937 l -1.26563,1.25391 a 0.50004997,0.50004997 0 0 0 -0.0664,0.0762 0.50004997,0.50004997 0 0 0 -0.004,0.006 l -0.16602,0.16601 a 0.50004997,0.50004997 0 0 0 -0.0117,0.0117 c -0.39332,0.4211 -0.76594,0.57109 -1.12891,0.56446 -0.36298,-0.007 -0.75841,-0.18208 -1.15234,-0.57618 -0.39505,-0.3952 -0.56758,-0.78617 -0.57422,-1.14648 -0.007,-0.36031 0.14053,-0.73396 0.56445,-1.13672 l 0.26758,-0.2539 a 0.50004997,0.50004997 0 0 0 0.0742,-0.0879 l 1.16797,-1.16796 a 0.50004997,0.50004997 0 0 0 0.0117,-0.0117 c 0.20545,-0.21996 0.40997,-0.36564 0.60547,-0.45313 a 0.50004997,0.50004997 0 0 0 -0.17968,-0.95898 z"
+ id="path23240-3"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g23545-6"
+ transform="rotate(-90,318.41616,448.41614)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 393.99219,462.28516 -2.13867,-2.13868 c -0.318,-0.32528 -0.86991,-0.0915 -0.85743,0.36329 0.004,0.12976 0.0575,0.25303 0.15039,0.34375 l 2.93555,2.93359 0.008,0.01 c 0.0962,0.13317 0.25175,0.21055 0.41602,0.20703 0.003,2e-5 0.005,2e-5 0.008,0 0.0157,-6e-4 0.0313,-0.002 0.0469,-0.004 0.0164,-0.002 0.0327,-0.005 0.0488,-0.008 0.11995,-0.0256 0.2263,-0.0944 0.29882,-0.19336 l 2.94532,-2.94531 c 0.49057,-0.47126 -0.23578,-1.19761 -0.70704,-0.70704 l -2.15429,2.1543 L 395,457.5 c 0,-2.47936 -2.02064,-4.5 -4.5,-4.5 -2.47936,0 -4.5,2.02064 -4.5,4.5 v 6 c -0.01,0.67616 1.00956,0.67616 1,0 v -6 c 0,-1.93892 1.56108,-3.5 3.5,-3.5 1.93826,0 3.49893,1.56005 3.5,3.49902 z"
+ transform="rotate(90,318.41616,448.41614)"
+ id="path23541-6"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccssccsscc" />
+ </g>
+ <g
+ transform="translate(-346,-11.999995)"
+ id="g24012-1"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <g
+ style="opacity:0.7;fill:#ffffff;stroke-width:1.18252182"
+ transform="matrix(0.84565033,0,0,0.84565033,271.3184,206.1572)"
+ id="g24008-0">
+ <g
+ style="fill:#ffffff;stroke-width:1.18252182"
+ transform="translate(829,-385)"
+ id="g24002-7" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.18252182;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 480.06836,304.9375 c -0.78863,-0.0147 -1.5648,0.35582 -2.23633,1.02734 l -1.47851,1.47852 a 0.59132004,0.59132004 0 1 0 0.83593,0.83594 l 1.47852,-1.47852 c 0.51101,-0.511 0.96056,-0.68742 1.37695,-0.67969 0.41639,0.008 0.86317,0.20868 1.33399,0.67969 0.4709,0.4711 0.67191,0.91763 0.67968,1.33399 0.008,0.41635 -0.16868,0.86595 -0.67968,1.37695 l -1.47852,1.47851 a 0.59132004,0.59132004 0 1 0 0.83594,0.83594 l 1.47851,-1.47851 c 0.67153,-0.67153 1.04012,-1.44777 1.02539,-2.23633 -0.0147,-0.78856 -0.40379,-1.52464 -1.02539,-2.14649 -0.62168,-0.62194 -1.35785,-1.01269 -2.14648,-1.02734 z m -0.94336,3.50977 a 0.59132004,0.59132004 0 0 0 -0.40625,0.17773 l -1.47852,1.47852 a 0.59132004,0.59132004 0 1 0 0.83594,0.83593 l 1.47852,-1.47851 a 0.59132004,0.59132004 0 0 0 -0.42969,-1.01367 z m -8.27344,4.72851 a 0.59132004,0.59132004 0 0 0 -0.4082,0.17774 l -1.51367,1.49218 a 0.59132004,0.59132004 0 0 0 -0.008,0.006 c -0.65272,0.66501 -1.01668,1.4358 -1.00782,2.22266 0.009,0.78686 0.38697,1.53124 1.01172,2.15625 0.62485,0.62507 1.3751,1.00952 2.16992,1.01953 0.79483,0.01 1.57721,-0.36041 2.25,-1.0332 l 1.47852,-1.47657 a 0.59178867,0.59178867 0 1 0 -0.83594,-0.83789 l -1.47851,1.47852 c -0.50973,0.50972 -0.97241,0.69289 -1.40039,0.6875 -0.42799,-0.005 -0.87805,-0.206 -1.34571,-0.67383 -0.46775,-0.46794 -0.66322,-0.91244 -0.66797,-1.33398 -0.005,-0.42154 0.17763,-0.8773 0.67188,-1.38086 l 1.50586,-1.48438 a 0.59132004,0.59132004 0 0 0 -0.42188,-1.01953 z m 2.65625,0.88867 a 0.59132004,0.59132004 0 0 0 -0.40625,0.17774 l -1.47851,1.47851 a 0.59132004,0.59132004 0 1 0 0.83593,0.83594 l 1.47852,-1.47852 a 0.59132004,0.59132004 0 0 0 -0.42969,-1.01367 z"
+ id="path24006-7"
+ inkscape:connector-curvature="0" />
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 668.49414,464.99414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 678.29297,476 H 675.25 a 0.50005,0.50005 0 1 0 0,1 h 4.18945 A 0.50005,0.50005 0 0 0 680,476.43945 V 472.25 a 0.50005,0.50005 0 1 0 -1,0 v 3.04297 l -10.14648,-10.14649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z" id="path24010-2" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 310.57031,473.01758 c -0.79787,-0.038 -1.57177,0.27684 -2.16015,0.86523 l -1.48633,1.48828 c -0.61577,0.57533 -0.93433,1.35407 -0.89258,2.1543 a 0.50005,0.50005 0 1 0 0.99805,-0.0508 c -0.0269,-0.51495 0.15566,-0.98016 0.57617,-1.37305 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 l 1.5,-1.5 c 0.41161,-0.41161 0.88966,-0.59872 1.40429,-0.57422 0.51464,0.0245 1.08439,0.26993 1.63868,0.82422 0.55479,0.5548 0.80954,1.13546 0.83789,1.65235 0.0283,0.51688 -0.15241,0.9848 -0.57422,1.3789 a 0.50005,0.50005 0 0 0 -0.0137,0.0117 l -1.5,1.5 c -0.41213,0.41213 -0.87694,0.60352 -1.39649,0.60352 a 0.50005,0.50005 0 1 0 0,1 c 0.78067,0 1.52491,-0.31788 2.10352,-0.89649 l 1.48828,-1.48828 c 0.61768,-0.57711 0.9366,-1.36125 0.89258,-2.16406 -0.044,-0.80281 -0.43566,-1.60948 -1.13086,-2.30469 -0.69571,-0.69571 -1.49901,-1.07724 -2.29688,-1.11523 z m -1.08008,3.97851 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -5,5 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 5,-5 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -4.92968,2.02149 c -0.80753,-0.0482 -1.5954,0.26944 -2.17578,0.89062 l -1.48829,1.48828 c -0.58838,0.58839 -0.90322,1.36034 -0.86523,2.15821 0.038,0.79787 0.41952,1.60311 1.11523,2.29883 0.69521,0.6952 1.50384,1.08487 2.30664,1.1289 0.80281,0.044 1.585,-0.27294 2.16211,-0.89062 l 1.48829,-1.48828 C 307.68213,484.0249 308,483.28067 308,482.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.51955 -0.19139,0.98436 -0.60352,1.39648 l -1.5,1.5 a 0.50005,0.50005 0 0 0 -0.0117,0.0117 c -0.39411,0.42182 -0.86007,0.60452 -1.37696,0.57618 -0.51688,-0.0283 -1.0995,-0.2831 -1.65429,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.82227,-1.63867 -0.0245,-0.51463 0.16065,-0.99268 0.57227,-1.40429 l 1.5,-1.5 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 c 0.39634,-0.4242 0.86629,-0.60725 1.38672,-0.57618 a 0.50005,0.50005 0 1 0 0.0586,-0.99804 z" id="path23281" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g23341" transform="translate(62.999998,-41.999995)">
- <g transform="translate(231,-63)" id="g23324" style="opacity:0.6;fill:#ffffff">
- <g transform="translate(430,-112)" id="g23301" style="fill:#ffffff"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 79.570312,578.01758 c -0.797869,-0.038 -1.571767,0.27684 -2.160156,0.86523 l -0.486328,0.48828 c -0.615772,0.57533 -0.93433,1.35407 -0.892578,2.1543 a 0.50005,0.50005 0 1 0 0.998047,-0.0508 c -0.02687,-0.51495 0.155664,-0.98016 0.576172,-1.37305 a 0.50005,0.50005 0 0 0 0.01172,-0.0117 l 0.5,-0.5 c 0.411611,-0.41161 0.889666,-0.59872 1.404296,-0.57422 0.514631,0.0245 1.084383,0.26993 1.638672,0.82422 0.554795,0.5548 0.809544,1.13546 0.837891,1.65235 0.02835,0.51688 -0.152405,0.9848 -0.574219,1.3789 a 0.50005,0.50005 0 0 0 -0.01367,0.0117 l -0.5,0.5 c -0.412129,0.41213 -0.876932,0.60352 -1.396484,0.60352 a 0.50005,0.50005 0 1 0 0,1 c 0.780667,0 1.524905,-0.31788 2.103516,-0.89649 l 0.488281,-0.48828 c 0.617686,-0.57711 0.936606,-1.36125 0.892578,-2.16406 -0.04403,-0.80281 -0.435654,-1.60948 -1.130859,-2.30469 -0.695711,-0.69571 -1.499006,-1.07724 -2.296876,-1.11523 z m -0.830078,3.72851 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.363282,-0.85743 z m -6.179687,3.27149 c -0.807524,-0.0482 -1.595401,0.26944 -2.175781,0.89062 l -0.488282,0.48828 c -0.588388,0.58839 -0.903228,1.36034 -0.865234,2.15821 0.03799,0.79787 0.419524,1.60311 1.115234,2.29883 0.695206,0.6952 1.503832,1.08487 2.306641,1.1289 0.802809,0.044 1.584996,-0.27294 2.162109,-0.89062 l 0.488282,-0.48828 C 75.682126,590.0249 76,589.28067 76,588.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.51955 -0.191386,0.98436 -0.603516,1.39648 l -0.5,0.5 a 0.50005,0.50005 0 0 0 -0.01172,0.0117 c -0.394107,0.42182 -0.860068,0.60452 -1.376954,0.57618 -0.516885,-0.0283 -1.099502,-0.2831 -1.654296,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.822266,-1.63867 -0.02451,-0.51463 0.160654,-0.99268 0.572266,-1.40429 l 0.5,-0.5 a 0.50005,0.50005 0 0 0 0.01172,-0.0117 c 0.39634,-0.4242 0.866283,-0.60725 1.386719,-0.57618 a 0.50005,0.50005 0 1 0 0.05859,-0.99804 z m 1.679687,1.22851 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.363282,-0.85743 z" id="path23322" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 668.49414,464.99414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 678.29297,476 H 675.25 a 0.50005,0.50005 0 1 0 0,1 h 4.18945 A 0.50005,0.50005 0 0 0 680,476.43945 V 472.25 a 0.50005,0.50005 0 1 0 -1,0 v 3.04297 l -10.14648,-10.14649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path24010-2"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 310.57031,473.01758 c -0.79787,-0.038 -1.57177,0.27684 -2.16015,0.86523 l -1.48633,1.48828 c -0.61577,0.57533 -0.93433,1.35407 -0.89258,2.1543 a 0.50005,0.50005 0 1 0 0.99805,-0.0508 c -0.0269,-0.51495 0.15566,-0.98016 0.57617,-1.37305 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 l 1.5,-1.5 c 0.41161,-0.41161 0.88966,-0.59872 1.40429,-0.57422 0.51464,0.0245 1.08439,0.26993 1.63868,0.82422 0.55479,0.5548 0.80954,1.13546 0.83789,1.65235 0.0283,0.51688 -0.15241,0.9848 -0.57422,1.3789 a 0.50005,0.50005 0 0 0 -0.0137,0.0117 l -1.5,1.5 c -0.41213,0.41213 -0.87694,0.60352 -1.39649,0.60352 a 0.50005,0.50005 0 1 0 0,1 c 0.78067,0 1.52491,-0.31788 2.10352,-0.89649 l 1.48828,-1.48828 c 0.61768,-0.57711 0.9366,-1.36125 0.89258,-2.16406 -0.044,-0.80281 -0.43566,-1.60948 -1.13086,-2.30469 -0.69571,-0.69571 -1.49901,-1.07724 -2.29688,-1.11523 z m -1.08008,3.97851 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -5,5 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 5,-5 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -4.92968,2.02149 c -0.80753,-0.0482 -1.5954,0.26944 -2.17578,0.89062 l -1.48829,1.48828 c -0.58838,0.58839 -0.90322,1.36034 -0.86523,2.15821 0.038,0.79787 0.41952,1.60311 1.11523,2.29883 0.69521,0.6952 1.50384,1.08487 2.30664,1.1289 0.80281,0.044 1.585,-0.27294 2.16211,-0.89062 l 1.48829,-1.48828 C 307.68213,484.0249 308,483.28067 308,482.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.51955 -0.19139,0.98436 -0.60352,1.39648 l -1.5,1.5 a 0.50005,0.50005 0 0 0 -0.0117,0.0117 c -0.39411,0.42182 -0.86007,0.60452 -1.37696,0.57618 -0.51688,-0.0283 -1.0995,-0.2831 -1.65429,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.82227,-1.63867 -0.0245,-0.51463 0.16065,-0.99268 0.57227,-1.40429 l 1.5,-1.5 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 c 0.39634,-0.4242 0.86629,-0.60725 1.38672,-0.57618 a 0.50005,0.50005 0 1 0 0.0586,-0.99804 z"
+ id="path23281"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g23341"
+ transform="translate(62.999998,-41.999995)">
+ <g
+ transform="translate(231,-63)"
+ id="g23324"
+ style="opacity:0.6;fill:#ffffff">
+ <g
+ transform="translate(430,-112)"
+ id="g23301"
+ style="fill:#ffffff" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 79.570312,578.01758 c -0.797869,-0.038 -1.571767,0.27684 -2.160156,0.86523 l -0.486328,0.48828 c -0.615772,0.57533 -0.93433,1.35407 -0.892578,2.1543 a 0.50005,0.50005 0 1 0 0.998047,-0.0508 c -0.02687,-0.51495 0.155664,-0.98016 0.576172,-1.37305 a 0.50005,0.50005 0 0 0 0.01172,-0.0117 l 0.5,-0.5 c 0.411611,-0.41161 0.889666,-0.59872 1.404296,-0.57422 0.514631,0.0245 1.084383,0.26993 1.638672,0.82422 0.554795,0.5548 0.809544,1.13546 0.837891,1.65235 0.02835,0.51688 -0.152405,0.9848 -0.574219,1.3789 a 0.50005,0.50005 0 0 0 -0.01367,0.0117 l -0.5,0.5 c -0.412129,0.41213 -0.876932,0.60352 -1.396484,0.60352 a 0.50005,0.50005 0 1 0 0,1 c 0.780667,0 1.524905,-0.31788 2.103516,-0.89649 l 0.488281,-0.48828 c 0.617686,-0.57711 0.936606,-1.36125 0.892578,-2.16406 -0.04403,-0.80281 -0.435654,-1.60948 -1.130859,-2.30469 -0.695711,-0.69571 -1.499006,-1.07724 -2.296876,-1.11523 z m -0.830078,3.72851 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.363282,-0.85743 z m -6.179687,3.27149 c -0.807524,-0.0482 -1.595401,0.26944 -2.175781,0.89062 l -0.488282,0.48828 c -0.588388,0.58839 -0.903228,1.36034 -0.865234,2.15821 0.03799,0.79787 0.419524,1.60311 1.115234,2.29883 0.695206,0.6952 1.503832,1.08487 2.306641,1.1289 0.802809,0.044 1.584996,-0.27294 2.162109,-0.89062 l 0.488282,-0.48828 C 75.682126,590.0249 76,589.28067 76,588.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.51955 -0.191386,0.98436 -0.603516,1.39648 l -0.5,0.5 a 0.50005,0.50005 0 0 0 -0.01172,0.0117 c -0.394107,0.42182 -0.860068,0.60452 -1.376954,0.57618 -0.516885,-0.0283 -1.099502,-0.2831 -1.654296,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.822266,-1.63867 -0.02451,-0.51463 0.160654,-0.99268 0.572266,-1.40429 l 0.5,-0.5 a 0.50005,0.50005 0 0 0 0.01172,-0.0117 c 0.39634,-0.4242 0.866283,-0.60725 1.386719,-0.57618 a 0.50005,0.50005 0 1 0 0.05859,-0.99804 z m 1.679687,1.22851 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.363282,-0.85743 z"
+ id="path23322"
+ inkscape:connector-curvature="0" />
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 301.49414,515.99414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 312.29297,528 H 309.25 a 0.50005,0.50005 0 1 0 0,1 h 4.18945 A 0.50005,0.50005 0 0 0 314,528.43945 V 524.25 a 0.50005,0.50005 0 1 0 -1,0 v 3.04297 l -11.14648,-11.14649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z" id="path23333" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g22284-9" transform="translate(168,-252)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 54.75,284 a 0.50004997,0.50004997 0 0 0 -0.431641,0.24805 l -3.646484,6.25 a 0.50004997,0.50004997 0 0 0 -0.002,0.002 c -1.211575,2.0985 -0.741006,4.77251 1.115234,6.33008 1.856239,1.55756 4.573449,1.55756 6.429688,0 1.85624,-1.55757 2.326809,-4.23158 1.115234,-6.33008 a 0.50004997,0.50004997 0 0 0 -0.002,-0.002 l -3.646484,-6.25 A 0.50004997,0.50004997 0 0 0 55.25,284 Z m 0.25,1.06445 3.464844,5.9375 c 0.970958,1.6837 0.594513,3.81305 -0.894532,5.0625 -1.489569,1.2499 -3.651055,1.2499 -5.140624,0 -1.489045,-1.24945 -1.86549,-3.3788 -0.894532,-5.0625 V 291 Z m -0.511719,2.92969 a 0.50004997,0.50004997 0 0 0 -0.429687,0.27148 l -1.697266,3.20704 c -0.166111,0.28617 -0.283806,0.59778 -0.349609,0.92187 a 0.50005872,0.50005872 0 1 0 0.980469,0.19727 c 0.04414,-0.2174 0.122796,-0.42496 0.234374,-0.61719 a 0.50004997,0.50004997 0 0 0 0.0098,-0.0176 l 1.705078,-3.22265 a 0.50004997,0.50004997 0 0 0 -0.453125,-0.74024 z" id="path22264-7" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(189,-210)" style="display:inline;fill:#ffffff;enable-background:new" id="g23463-9">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 6.5,242 A 0.50005,0.50005 0 0 0 6,242.5 v 5 A 0.50005,0.50005 0 0 0 6.5,248 H 8 v 7.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 A 0.50005,0.50005 0 0 0 18,255.5 V 248 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 19.5,242 h -4 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 c 0,0.71532 -0.380592,1.37478 -1,1.73242 -0.619409,0.35765 -1.380591,0.35765 -2,0 -0.619408,-0.35764 -1,-1.0171 -1,-1.73242 v -0.5 A 0.50005,0.50005 0 0 0 10.5,242 Z m 0.5,1 h 3 c 0,1.07096 0.57257,2.06216 1.5,2.59766 0.927429,0.53549 2.072571,0.53549 3,0 0.92743,-0.5355 1.5,-1.5267 1.5,-2.59766 h 3 v 4 H 17.5 A 0.50005,0.50005 0 0 0 17,247.5 V 255 H 9 v -7.5 A 0.50005,0.50005 0 0 0 8.5,247 H 7 Z" id="path22384-8" inkscape:connector-curvature="0"/>
- </g>
- <g id="g6342" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="path8743" d="m 31.5,494 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 A 0.50005,0.50005 0 0 0 40.5,494 Z m 0.5,1 h 8 v 8 h -8 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path id="path8759" d="m 38,496 c -0.546362,0 -1,0.45364 -1,1 0,0.54636 0.453638,1 1,1 0.546362,0 1,-0.45364 1,-1 0,-0.54636 -0.453638,-1 -1,-1 z m -3.513672,1.05078 c -0.16529,0.005 -0.314526,0.10024 -0.388672,0.24805 l -2.75,5.5 c -0.148607,0.29892 0.06852,0.64991 0.402344,0.65039 h 5.75 c 0.340259,-0.001 0.55634,-0.36474 0.394531,-0.66406 l -3,-5.5 c -0.08111,-0.14873 -0.238867,-0.23931 -0.408203,-0.23438 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" id="path8807" d="M 29.492188,495.99219 A 0.50005,0.50005 0 0 0 29,496.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 30 v -8.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z m -2,2 A 0.50005,0.50005 0 0 0 27,498.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 28 v -8.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.69300022;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" transform="translate(-21.000002,42.000006)" id="g12626" style="display:inline;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 31.492188,367.99219 A 0.50005,0.50005 0 0 0 31,368.5 v 8.79297 l -3.853516,3.85351 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 31.707031,378 H 40.5 a 0.50005,0.50005 0 1 0 0,-1 H 32 v -8.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z" id="path12205" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 433.5,536 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4.98242 8.01758 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -13 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -0.5,5.48242 c -0.007,-0.18325 -0.1131,-0.34814 -0.27734,-0.42969 l -2,-1 c -0.24704,-0.12272 -0.54679,-0.0222 -0.66993,0.22461 l -4,8 c -0.12272,0.24704 -0.0222,0.54679 0.22461,0.66993 l 2,1 c 0.24704,0.12272 0.54679,0.0222 0.66993,-0.22461 l 4,-8 c 0.0373,-0.0744 0.0554,-0.15702 0.0527,-0.24024 z M 434,537 h 1 v 12 h -1 z m 3.5,1 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 11 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="rect11443" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 157.49219,472.99219 A 0.50005,0.50005 0 0 0 157,473.5 v 8.79297 l -3.85352,3.85351 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 157.70703,483 H 166.5 a 0.50005,0.50005 0 1 0 0,-1 H 158 v -8.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" id="path22612" inkscape:connector-curvature="0"/>
- <g transform="translate(-21.000002,4.4999696e-6)" inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new" id="g12548">
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" transform="translate(640.00001,-112)" id="g7753-3">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m -539.42969,690.01758 c -0.79787,-0.038 -1.57177,0.27684 -2.16015,0.86523 l -0.48633,0.48828 c -0.61577,0.57533 -0.93433,1.35407 -0.89258,2.1543 a 0.50005,0.50005 0 1 0 0.99805,-0.0508 c -0.0269,-0.51495 0.15566,-0.98016 0.57617,-1.37305 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 l 0.5,-0.5 c 0.41161,-0.41161 0.88966,-0.59872 1.40429,-0.57422 0.51464,0.0245 1.08439,0.26993 1.63868,0.82422 0.55479,0.5548 0.80954,1.13546 0.83789,1.65235 0.0283,0.51688 -0.15241,0.9848 -0.57422,1.3789 a 0.50005,0.50005 0 0 0 -0.0137,0.0117 l -0.5,0.5 c -0.41213,0.41213 -0.87694,0.60352 -1.39649,0.60352 a 0.50005,0.50005 0 1 0 0,1 c 0.78067,0 1.52491,-0.31788 2.10352,-0.89649 l 0.48828,-0.48828 c 0.61768,-0.57711 0.9366,-1.36125 0.89258,-2.16406 -0.044,-0.80281 -0.43566,-1.60948 -1.13086,-2.30469 -0.69571,-0.69571 -1.49901,-1.07724 -2.29688,-1.11523 z m -7.00976,7 c -0.80753,-0.0482 -1.5954,0.26944 -2.17578,0.89062 l -0.48829,0.48828 c -0.58838,0.58839 -0.90322,1.36034 -0.86523,2.15821 0.038,0.79787 0.41952,1.60311 1.11523,2.29883 0.69521,0.6952 1.50384,1.08487 2.30664,1.1289 0.80281,0.044 1.585,-0.27294 2.16211,-0.89062 l 0.48829,-0.48828 C -543.31787,702.0249 -543,701.28067 -543,700.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.51955 -0.19139,0.98436 -0.60352,1.39648 l -0.5,0.5 a 0.50005,0.50005 0 0 0 -0.0117,0.0117 c -0.39411,0.42182 -0.86007,0.60452 -1.37696,0.57618 -0.51688,-0.0283 -1.0995,-0.2831 -1.65429,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.82227,-1.63867 -0.0245,-0.51463 0.16065,-0.99268 0.57227,-1.40429 l 0.5,-0.5 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 c 0.39634,-0.4242 0.86629,-0.60725 1.38672,-0.57618 a 0.50005,0.50005 0 1 0 0.0586,-0.99804 z" id="path12469-4" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 301.49414,515.99414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 312.29297,528 H 309.25 a 0.50005,0.50005 0 1 0 0,1 h 4.18945 A 0.50005,0.50005 0 0 0 314,528.43945 V 524.25 a 0.50005,0.50005 0 1 0 -1,0 v 3.04297 l -11.14648,-11.14649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path23333"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22284-9"
+ transform="translate(168,-252)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 54.75,284 a 0.50004997,0.50004997 0 0 0 -0.431641,0.24805 l -3.646484,6.25 a 0.50004997,0.50004997 0 0 0 -0.002,0.002 c -1.211575,2.0985 -0.741006,4.77251 1.115234,6.33008 1.856239,1.55756 4.573449,1.55756 6.429688,0 1.85624,-1.55757 2.326809,-4.23158 1.115234,-6.33008 a 0.50004997,0.50004997 0 0 0 -0.002,-0.002 l -3.646484,-6.25 A 0.50004997,0.50004997 0 0 0 55.25,284 Z m 0.25,1.06445 3.464844,5.9375 c 0.970958,1.6837 0.594513,3.81305 -0.894532,5.0625 -1.489569,1.2499 -3.651055,1.2499 -5.140624,0 -1.489045,-1.24945 -1.86549,-3.3788 -0.894532,-5.0625 V 291 Z m -0.511719,2.92969 a 0.50004997,0.50004997 0 0 0 -0.429687,0.27148 l -1.697266,3.20704 c -0.166111,0.28617 -0.283806,0.59778 -0.349609,0.92187 a 0.50005872,0.50005872 0 1 0 0.980469,0.19727 c 0.04414,-0.2174 0.122796,-0.42496 0.234374,-0.61719 a 0.50004997,0.50004997 0 0 0 0.0098,-0.0176 l 1.705078,-3.22265 a 0.50004997,0.50004997 0 0 0 -0.453125,-0.74024 z"
+ id="path22264-7"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(189,-210)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g23463-9">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 6.5,242 A 0.50005,0.50005 0 0 0 6,242.5 v 5 A 0.50005,0.50005 0 0 0 6.5,248 H 8 v 7.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 A 0.50005,0.50005 0 0 0 18,255.5 V 248 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 19.5,242 h -4 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 c 0,0.71532 -0.380592,1.37478 -1,1.73242 -0.619409,0.35765 -1.380591,0.35765 -2,0 -0.619408,-0.35764 -1,-1.0171 -1,-1.73242 v -0.5 A 0.50005,0.50005 0 0 0 10.5,242 Z m 0.5,1 h 3 c 0,1.07096 0.57257,2.06216 1.5,2.59766 0.927429,0.53549 2.072571,0.53549 3,0 0.92743,-0.5355 1.5,-1.5267 1.5,-2.59766 h 3 v 4 H 17.5 A 0.50005,0.50005 0 0 0 17,247.5 V 255 H 9 v -7.5 A 0.50005,0.50005 0 0 0 8.5,247 H 7 Z"
+ id="path22384-8"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g6342"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="path8743"
+ d="m 31.5,494 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 A 0.50005,0.50005 0 0 0 40.5,494 Z m 0.5,1 h 8 v 8 h -8 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ id="path8759"
+ d="m 38,496 c -0.546362,0 -1,0.45364 -1,1 0,0.54636 0.453638,1 1,1 0.546362,0 1,-0.45364 1,-1 0,-0.54636 -0.453638,-1 -1,-1 z m -3.513672,1.05078 c -0.16529,0.005 -0.314526,0.10024 -0.388672,0.24805 l -2.75,5.5 c -0.148607,0.29892 0.06852,0.64991 0.402344,0.65039 h 5.75 c 0.340259,-0.001 0.55634,-0.36474 0.394531,-0.66406 l -3,-5.5 c -0.08111,-0.14873 -0.238867,-0.23931 -0.408203,-0.23438 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path8807"
+ d="M 29.492188,495.99219 A 0.50005,0.50005 0 0 0 29,496.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 30 v -8.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z m -2,2 A 0.50005,0.50005 0 0 0 27,498.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 28 v -8.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.69300022;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="translate(-21.000002,42.000006)"
+ id="g12626"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 31.492188,367.99219 A 0.50005,0.50005 0 0 0 31,368.5 v 8.79297 l -3.853516,3.85351 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 31.707031,378 H 40.5 a 0.50005,0.50005 0 1 0 0,-1 H 32 v -8.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z"
+ id="path12205"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 433.5,536 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4.98242 8.01758 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -13 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -0.5,5.48242 c -0.007,-0.18325 -0.1131,-0.34814 -0.27734,-0.42969 l -2,-1 c -0.24704,-0.12272 -0.54679,-0.0222 -0.66993,0.22461 l -4,8 c -0.12272,0.24704 -0.0222,0.54679 0.22461,0.66993 l 2,1 c 0.24704,0.12272 0.54679,0.0222 0.66993,-0.22461 l 4,-8 c 0.0373,-0.0744 0.0554,-0.15702 0.0527,-0.24024 z M 434,537 h 1 v 12 h -1 z m 3.5,1 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 11 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="rect11443"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 157.49219,472.99219 A 0.50005,0.50005 0 0 0 157,473.5 v 8.79297 l -3.85352,3.85351 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 157.70703,483 H 166.5 a 0.50005,0.50005 0 1 0 0,-1 H 158 v -8.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path22612"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="translate(-21.000002,4.4999696e-6)"
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ id="g12548">
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ transform="translate(640.00001,-112)"
+ id="g7753-3">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -539.42969,690.01758 c -0.79787,-0.038 -1.57177,0.27684 -2.16015,0.86523 l -0.48633,0.48828 c -0.61577,0.57533 -0.93433,1.35407 -0.89258,2.1543 a 0.50005,0.50005 0 1 0 0.99805,-0.0508 c -0.0269,-0.51495 0.15566,-0.98016 0.57617,-1.37305 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 l 0.5,-0.5 c 0.41161,-0.41161 0.88966,-0.59872 1.40429,-0.57422 0.51464,0.0245 1.08439,0.26993 1.63868,0.82422 0.55479,0.5548 0.80954,1.13546 0.83789,1.65235 0.0283,0.51688 -0.15241,0.9848 -0.57422,1.3789 a 0.50005,0.50005 0 0 0 -0.0137,0.0117 l -0.5,0.5 c -0.41213,0.41213 -0.87694,0.60352 -1.39649,0.60352 a 0.50005,0.50005 0 1 0 0,1 c 0.78067,0 1.52491,-0.31788 2.10352,-0.89649 l 0.48828,-0.48828 c 0.61768,-0.57711 0.9366,-1.36125 0.89258,-2.16406 -0.044,-0.80281 -0.43566,-1.60948 -1.13086,-2.30469 -0.69571,-0.69571 -1.49901,-1.07724 -2.29688,-1.11523 z m -7.00976,7 c -0.80753,-0.0482 -1.5954,0.26944 -2.17578,0.89062 l -0.48829,0.48828 c -0.58838,0.58839 -0.90322,1.36034 -0.86523,2.15821 0.038,0.79787 0.41952,1.60311 1.11523,2.29883 0.69521,0.6952 1.50384,1.08487 2.30664,1.1289 0.80281,0.044 1.585,-0.27294 2.16211,-0.89062 l 0.48829,-0.48828 C -543.31787,702.0249 -543,701.28067 -543,700.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.51955 -0.19139,0.98436 -0.60352,1.39648 l -0.5,0.5 a 0.50005,0.50005 0 0 0 -0.0117,0.0117 c -0.39411,0.42182 -0.86007,0.60452 -1.37696,0.57618 -0.51688,-0.0283 -1.0995,-0.2831 -1.65429,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.82227,-1.63867 -0.0245,-0.51463 0.16065,-0.99268 0.57227,-1.40429 l 0.5,-0.5 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 c 0.39634,-0.4242 0.86629,-0.60725 1.38672,-0.57618 a 0.50005,0.50005 0 1 0 0.0586,-0.99804 z"
+ id="path12469-4"
+ inkscape:connector-curvature="0" />
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 94.492188,577.99219 A 0.50005,0.50005 0 0 0 94,578.5 v 2 a 0.50005,0.50005 0 1 0 1,0 v -2 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z m -2.998047,1.00195 a 0.50005,0.50005 0 0 0 -0.347657,0.85938 l 1,1 a 0.50005,0.50005 0 1 0 0.707032,-0.70704 l -1,-1 a 0.50005,0.50005 0 0 0 -0.359375,-0.15234 z M 90.5,582 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z m 11,5 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z m -2.007812,1.99219 A 0.50005,0.50005 0 0 0 99,589.5 v 2 a 0.50005,0.50005 0 1 0 1,0 v -2 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z m 2.001952,0.002 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 1,1 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1,-1 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z" id="path12538" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-1.8536743e-6,4.4999696e-6)" id="g23748" style="display:inline;fill:#ffffff;enable-background:new">
- <path inkscape:connector-curvature="0" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" d="m 49,558 v 3 h 3 v -3 z m 3,3 v 3 h 3 v -3 z m 3,0 h 3 v -3 h -3 z m 3,0 v 3 h 3 v -3 z m 0,3 h -3 v 3 h 3 z m 0,3 v 3 h 3 v -3 z m -3,0 h -3 v 3 h 3 z m -3,0 v -3 h -3 v 3 z" id="path10767" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 48.5,557 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 61.5,557 Z m 0.5,1 h 12 v 12 H 49 Z" id="rect22625" inkscape:connector-curvature="0"/>
- </g>
- <g transform="matrix(-1,0,0,1,593.8323,-41.999985)" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g24182">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 309.83203,496 c -0.79167,0 -1.54903,0.39305 -1.86328,1.11133 -0.31425,0.71827 -0.0786,1.6538 0.75977,2.49219 l 2.5,2.5 c 0.66161,0.66161 0.67598,1.10108 0.55273,1.38281 C 311.658,503.76805 311.29036,504 310.83203,504 l -7.28515,-0.008 2.13867,-2.13867 a 0.50005,0.50005 0 1 0 -0.70703,-0.70704 l -2.9336,2.93555 -0.01,0.008 a 0.50005,0.50005 0 0 0 -0.20704,0.41602 0.50005,0.50005 0 0 0 0,0.008 0.50005,0.50005 0 0 0 0.004,0.0469 0.50005,0.50005 0 0 0 0.008,0.0488 0.50005,0.50005 0 0 0 0.19336,0.29882 l 2.94532,2.94532 a 0.50005,0.50005 0 1 0 0.70703,-0.70704 l -2.1543,-2.15429 7.30078,0.008 c 0.79167,0 1.55099,-0.39305 1.86524,-1.11133 0.31424,-0.71827 0.0767,-1.6538 -0.76172,-2.49219 l -2.5,-2.5 c -0.66161,-0.66161 -0.67404,-1.10108 -0.55078,-1.38281 C 309.00802,497.23195 309.3737,497 309.83203,497 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 z" id="path24180" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(112.05535,339.92702)" id="g44391-4" style="display:inline;opacity:0.7;fill:#ffffff;enable-background:new">
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate" id="rect44387-5" width="16" height="16" x="103" y="111"/>
- <circle r="8" cy="118" cx="132" style="display:inline;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" id="circle44389-4" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" transform="matrix(-0.248353,0.02816779,0.02830718,0.248422,140.45214,86.01031)"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g23689-9" transform="rotate(180,957.9976,414.99747)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1419.4941,588.00195 c 4.1402,0 7.5079,-3.36769 7.5079,-7.50781 a 0.50004997,0.50004997 0 1 0 -1,0 c 0,3.59968 -2.9082,6.50781 -6.5079,6.50781 a 0.50004997,0.50004997 0 1 0 0,1 z" id="path23647-2" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1416.4941,585.10156 c 4.1942,0 7.6075,-3.41326 7.6075,-7.60742 a 0.6006,0.6006 0 1 0 -1.2012,0 c 0,3.54564 -2.8606,6.40625 -6.4063,6.40625 a 0.600585,0.600585 0 1 0 0,1.20117 z" id="path23668-9" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1413.4941,582.10156 c 4.1942,0 7.6075,-3.41326 7.6075,-7.60742 a 0.6006,0.6006 0 1 0 -1.2012,0 c 0,3.54564 -2.8606,6.40625 -6.4063,6.40625 a 0.600585,0.600585 0 1 0 0,1.20117 z" id="path23670-8" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g23935-0" transform="translate(-924,-332)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1404.4688,576.96289 a 1.50015,1.50015 0 0 0 -0.1036,0.01 c -4.9348,0.53258 -8.8525,4.44095 -9.3925,9.375 a 1.5001977,1.5001977 0 1 0 2.9824,0.32812 c 0.3887,-3.55095 3.1789,-6.33741 6.7304,-6.7207 a 1.50015,1.50015 0 0 0 -0.2167,-2.99219 z" id="path23640-2-5" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1405.498,573.99805 c -7.4498,0 -13.5,6.0501 -13.5,13.5 a 0.50004997,0.50004997 0 1 0 1,0 c 0,-6.90946 5.5906,-12.5 12.5,-12.5 a 0.50004997,0.50004997 0 1 0 0,-1 z" id="path23706-8" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g13692-5-0" transform="translate(316.0071,-315)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 47.5,578 A 0.50005,0.50005 0 0 0 47,578.5 L 46.9922,589 c 0,1.51667 1.219298,3 2.984374,3 1.765077,0 3.015625,-1.475 3.015626,-3 L 53,578.5 A 0.50005,0.50005 0 0 0 52.5,578 Z m 0.5,1 h 4 l -0.0078,10 c 0,0.975 -0.811952,2 -2.015626,2 -1.203673,0 -1.984375,-1.01667 -1.984374,-2 z" id="path13679-7-1" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 58.492188,586 a 0.50005,0.50005 0 1 0 0,1 H 60 v 4 h -6.257812 a 0.50005,0.50005 0 1 0 0,1 H 60.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 60.5,586 Z" id="path13681-7-8" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 56.492188,579 a 0.50005,0.50005 0 0 0 -0.345704,0.14648 l -2,2 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 56.5,580.20703 58.792969,582.5 l -4.646485,4.64648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 5,-5 a 0.50005,0.50005 0 0 0 0,-0.70704 l -3,-3 A 0.50005,0.50005 0 0 0 56.492188,579 Z" id="path13684-4-3" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 50,588 c -0.546362,0 -1,0.45364 -1,1 0,0.54636 0.453638,1 1,1 0.546362,0 1,-0.45364 1,-1 0,-0.54636 -0.453638,-1 -1,-1 z" id="circle13686-9-5" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g23993-7" transform="matrix(1,0,0,-1,-1008,851.0067)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1437,595.60938 c 0,6.25034 4.6305,11.38281 10.4004,11.38281 a 0.60006002,0.60006002 0 1 0 0,-1.19922 c -5.0564,0 -9.2012,-4.52271 -9.2012,-10.18359 a 0.60006002,0.60006002 0 1 0 -1.1992,0 z" id="path23981-7" inkscape:connector-curvature="0"/>
- <g style="opacity:0.6;fill:#ffffff" id="g23987-2">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1444.5,597 c -1.4566,10e-6 -2.897,0.34937 -4.2207,1.02148 a 0.50005,0.50005 0 1 0 0.4531,0.89063 c 1.1877,-0.60305 2.4706,-0.9121 3.7676,-0.91211 a 0.50005,0.50005 0 1 0 0,-1 z m -8.0176,4.01172 a 0.50005,0.50005 0 0 0 -0.4043,0.23242 C 1434.7288,603.30241 1434,605.86102 1434,608.5 a 0.50005,0.50005 0 1 0 1,0 c 0,-2.45438 0.6833,-4.83156 1.9141,-6.70898 a 0.50005,0.50005 0 0 0 -0.4317,-0.7793 z" id="path23983-7" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 94.492188,577.99219 A 0.50005,0.50005 0 0 0 94,578.5 v 2 a 0.50005,0.50005 0 1 0 1,0 v -2 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z m -2.998047,1.00195 a 0.50005,0.50005 0 0 0 -0.347657,0.85938 l 1,1 a 0.50005,0.50005 0 1 0 0.707032,-0.70704 l -1,-1 a 0.50005,0.50005 0 0 0 -0.359375,-0.15234 z M 90.5,582 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z m 11,5 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z m -2.007812,1.99219 A 0.50005,0.50005 0 0 0 99,589.5 v 2 a 0.50005,0.50005 0 1 0 1,0 v -2 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z m 2.001952,0.002 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 1,1 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1,-1 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path12538"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-1.8536743e-6,4.4999696e-6)"
+ id="g23748"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 49,558 v 3 h 3 v -3 z m 3,3 v 3 h 3 v -3 z m 3,0 h 3 v -3 h -3 z m 3,0 v 3 h 3 v -3 z m 0,3 h -3 v 3 h 3 z m 0,3 v 3 h 3 v -3 z m -3,0 h -3 v 3 h 3 z m -3,0 v -3 h -3 v 3 z"
+ id="path10767"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 48.5,557 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 61.5,557 Z m 0.5,1 h 12 v 12 H 49 Z"
+ id="rect22625"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="matrix(-1,0,0,1,593.8323,-41.999985)"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g24182">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 309.83203,496 c -0.79167,0 -1.54903,0.39305 -1.86328,1.11133 -0.31425,0.71827 -0.0786,1.6538 0.75977,2.49219 l 2.5,2.5 c 0.66161,0.66161 0.67598,1.10108 0.55273,1.38281 C 311.658,503.76805 311.29036,504 310.83203,504 l -7.28515,-0.008 2.13867,-2.13867 a 0.50005,0.50005 0 1 0 -0.70703,-0.70704 l -2.9336,2.93555 -0.01,0.008 a 0.50005,0.50005 0 0 0 -0.20704,0.41602 0.50005,0.50005 0 0 0 0,0.008 0.50005,0.50005 0 0 0 0.004,0.0469 0.50005,0.50005 0 0 0 0.008,0.0488 0.50005,0.50005 0 0 0 0.19336,0.29882 l 2.94532,2.94532 a 0.50005,0.50005 0 1 0 0.70703,-0.70704 l -2.1543,-2.15429 7.30078,0.008 c 0.79167,0 1.55099,-0.39305 1.86524,-1.11133 0.31424,-0.71827 0.0767,-1.6538 -0.76172,-2.49219 l -2.5,-2.5 c -0.66161,-0.66161 -0.67404,-1.10108 -0.55078,-1.38281 C 309.00802,497.23195 309.3737,497 309.83203,497 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path24180"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(112.05535,339.92702)"
+ id="g44391-4"
+ style="display:inline;opacity:0.7;fill:#ffffff;enable-background:new">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
+ id="rect44387-5"
+ width="16"
+ height="16"
+ x="103"
+ y="111" />
+ <circle
+ r="8"
+ cy="118"
+ cx="132"
+ style="display:inline;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="circle44389-4"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ transform="matrix(-0.248353,0.02816779,0.02830718,0.248422,140.45214,86.01031)" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g23689-9"
+ transform="rotate(180,957.9976,414.99747)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1419.4941,588.00195 c 4.1402,0 7.5079,-3.36769 7.5079,-7.50781 a 0.50004997,0.50004997 0 1 0 -1,0 c 0,3.59968 -2.9082,6.50781 -6.5079,6.50781 a 0.50004997,0.50004997 0 1 0 0,1 z"
+ id="path23647-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1416.4941,585.10156 c 4.1942,0 7.6075,-3.41326 7.6075,-7.60742 a 0.6006,0.6006 0 1 0 -1.2012,0 c 0,3.54564 -2.8606,6.40625 -6.4063,6.40625 a 0.600585,0.600585 0 1 0 0,1.20117 z"
+ id="path23668-9"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1413.4941,582.10156 c 4.1942,0 7.6075,-3.41326 7.6075,-7.60742 a 0.6006,0.6006 0 1 0 -1.2012,0 c 0,3.54564 -2.8606,6.40625 -6.4063,6.40625 a 0.600585,0.600585 0 1 0 0,1.20117 z"
+ id="path23670-8"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g23935-0"
+ transform="translate(-924,-332)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1404.4688,576.96289 a 1.50015,1.50015 0 0 0 -0.1036,0.01 c -4.9348,0.53258 -8.8525,4.44095 -9.3925,9.375 a 1.5001977,1.5001977 0 1 0 2.9824,0.32812 c 0.3887,-3.55095 3.1789,-6.33741 6.7304,-6.7207 a 1.50015,1.50015 0 0 0 -0.2167,-2.99219 z"
+ id="path23640-2-5"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1405.498,573.99805 c -7.4498,0 -13.5,6.0501 -13.5,13.5 a 0.50004997,0.50004997 0 1 0 1,0 c 0,-6.90946 5.5906,-12.5 12.5,-12.5 a 0.50004997,0.50004997 0 1 0 0,-1 z"
+ id="path23706-8"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g13692-5-0"
+ transform="translate(316.0071,-315)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 47.5,578 A 0.50005,0.50005 0 0 0 47,578.5 L 46.9922,589 c 0,1.51667 1.219298,3 2.984374,3 1.765077,0 3.015625,-1.475 3.015626,-3 L 53,578.5 A 0.50005,0.50005 0 0 0 52.5,578 Z m 0.5,1 h 4 l -0.0078,10 c 0,0.975 -0.811952,2 -2.015626,2 -1.203673,0 -1.984375,-1.01667 -1.984374,-2 z"
+ id="path13679-7-1"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 58.492188,586 a 0.50005,0.50005 0 1 0 0,1 H 60 v 4 h -6.257812 a 0.50005,0.50005 0 1 0 0,1 H 60.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 60.5,586 Z"
+ id="path13681-7-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 56.492188,579 a 0.50005,0.50005 0 0 0 -0.345704,0.14648 l -2,2 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 56.5,580.20703 58.792969,582.5 l -4.646485,4.64648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 5,-5 a 0.50005,0.50005 0 0 0 0,-0.70704 l -3,-3 A 0.50005,0.50005 0 0 0 56.492188,579 Z"
+ id="path13684-4-3"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 50,588 c -0.546362,0 -1,0.45364 -1,1 0,0.54636 0.453638,1 1,1 0.546362,0 1,-0.45364 1,-1 0,-0.54636 -0.453638,-1 -1,-1 z"
+ id="circle13686-9-5"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g23993-7"
+ transform="matrix(1,0,0,-1,-1008,851.0067)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1437,595.60938 c 0,6.25034 4.6305,11.38281 10.4004,11.38281 a 0.60006002,0.60006002 0 1 0 0,-1.19922 c -5.0564,0 -9.2012,-4.52271 -9.2012,-10.18359 a 0.60006002,0.60006002 0 1 0 -1.1992,0 z"
+ id="path23981-7"
+ inkscape:connector-curvature="0" />
+ <g
+ style="opacity:0.6;fill:#ffffff"
+ id="g23987-2">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1444.5,597 c -1.4566,10e-6 -2.897,0.34937 -4.2207,1.02148 a 0.50005,0.50005 0 1 0 0.4531,0.89063 c 1.1877,-0.60305 2.4706,-0.9121 3.7676,-0.91211 a 0.50005,0.50005 0 1 0 0,-1 z m -8.0176,4.01172 a 0.50005,0.50005 0 0 0 -0.4043,0.23242 C 1434.7288,603.30241 1434,605.86102 1434,608.5 a 0.50005,0.50005 0 1 0 1,0 c 0,-2.45438 0.6833,-4.83156 1.9141,-6.70898 a 0.50005,0.50005 0 0 0 -0.4317,-0.7793 z"
+ id="path23983-7"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" transform="rotate(180,947.5,425.5)" id="g24104-2">
- <g id="g24094-5" style="opacity:0.5;fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 449,242 c -1.0986,0 -2,0.90135 -2,2 0,0.73315 0.40645,1.37054 1,1.71875 V 250 h 1 v -4 c 1.0986,0 2,-0.90135 2,-2 h 4 v -1 h -4.28125 c -0.34822,-0.59355 -0.98563,-1 -1.71875,-1 z m 0,1 c 0.5582,0 1,0.44179 1,1 0,0.55821 -0.4418,1 -1,1 -0.5582,0 -1,-0.44179 -1,-1 0,-0.55821 0.4418,-1 1,-1 z" transform="rotate(-180,947.5,425.5)" id="circle24085-2" inkscape:connector-curvature="0" sodipodi:nodetypes="ssccccccccssssss"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="rotate(180,947.5,425.5)"
+ id="g24104-2">
+ <g
+ id="g24094-5"
+ style="opacity:0.5;fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 449,242 c -1.0986,0 -2,0.90135 -2,2 0,0.73315 0.40645,1.37054 1,1.71875 V 250 h 1 v -4 c 1.0986,0 2,-0.90135 2,-2 h 4 v -1 h -4.28125 c -0.34822,-0.59355 -0.98563,-1 -1.71875,-1 z m 0,1 c 0.5582,0 1,0.44179 1,1 0,0.55821 -0.4418,1 -1,1 -0.5582,0 -1,-0.44179 -1,-1 0,-0.55821 0.4418,-1 1,-1 z"
+ transform="rotate(-180,947.5,425.5)"
+ id="circle24085-2"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ssccccccccssssss" />
</g>
- <g id="g24102-2" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 459,242 c -1.0986,0 -2,0.90135 -2,2 0,0.36859 0.10883,0.71022 0.28516,1.00781 l -7.27735,7.27735 C 449.71022,252.10883 449.36858,252 449,252 c -1.0986,0 -2,0.90135 -2,2 0,1.09865 0.9014,2 2,2 1.0986,0 2,-0.90135 2,-2 0,-0.36859 -0.10883,-0.71022 -0.28516,-1.00781 l 7.27735,-7.27735 C 458.28978,245.89117 458.63142,246 459,246 c 1.0986,0 2,-0.90135 2,-2 0,-1.09865 -0.9014,-2 -2,-2 z m 0,1 c 0.5582,0 1,0.44179 1,1 0,0.55821 -0.4418,1 -1,1 -0.5582,0 -1,-0.44179 -1,-1 0,-0.55821 0.4418,-1 1,-1 z m -10,10 c 0.5582,0 1,0.44179 1,1 0,0.55821 -0.4418,1 -1,1 -0.5582,0 -1,-0.44179 -1,-1 0,-0.55821 0.4418,-1 1,-1 z" transform="rotate(-180,947.5,425.5)" id="path24100-8" inkscape:connector-curvature="0"/>
+ <g
+ id="g24102-2"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 459,242 c -1.0986,0 -2,0.90135 -2,2 0,0.36859 0.10883,0.71022 0.28516,1.00781 l -7.27735,7.27735 C 449.71022,252.10883 449.36858,252 449,252 c -1.0986,0 -2,0.90135 -2,2 0,1.09865 0.9014,2 2,2 1.0986,0 2,-0.90135 2,-2 0,-0.36859 -0.10883,-0.71022 -0.28516,-1.00781 l 7.27735,-7.27735 C 458.28978,245.89117 458.63142,246 459,246 c 1.0986,0 2,-0.90135 2,-2 0,-1.09865 -0.9014,-2 -2,-2 z m 0,1 c 0.5582,0 1,0.44179 1,1 0,0.55821 -0.4418,1 -1,1 -0.5582,0 -1,-0.44179 -1,-1 0,-0.55821 0.4418,-1 1,-1 z m -10,10 c 0.5582,0 1,0.44179 1,1 0,0.55821 -0.4418,1 -1,1 -0.5582,0 -1,-0.44179 -1,-1 0,-0.55821 0.4418,-1 1,-1 z"
+ transform="rotate(-180,947.5,425.5)"
+ id="path24100-8"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 416.49023,242.95508 a 0.55005501,0.55005501 0 0 0 -0.55078,0.55078 v 0.77539 l -0.44922,0.45117 -0.61132,-0.61133 a 0.55005501,0.55005501 0 0 0 -0.38868,-0.16211 h -1.77148 l -0.83984,-0.83789 a 0.55005501,0.55005501 0 0 0 -0.77735,0 l -1,1 a 0.55005501,0.55005501 0 0 0 -0.16211,0.38868 v 1.77148 l -0.67773,0.67773 h -0.77149 a 0.55005501,0.55005501 0 0 0 -0.39062,0.16211 l -0.83789,0.8418 h -0.77149 a 0.55005501,0.55005501 0 0 0 -0.55078,0.55078 v 2.00391 a 0.55005501,0.55005501 0 0 0 0.55078,0.55078 h 0.77344 l 0.67578,0.67383 v 0.54492 l -0.67578,0.68164 -0.76758,-0.008 a 0.55005501,0.55005501 0 0 0 -0.55664,0.54883 v 1.21093 0.78907 a 0.550785,0.550785 0 1 0 1.10157,0 v -0.78907 -0.65429 l 0.44336,0.004 a 0.55005501,0.55005501 0 0 0 0.39648,-0.16211 l 1,-1.00781 a 0.55005501,0.55005501 0 0 0 0.16016,-0.38672 v -1 a 0.55005501,0.55005501 0 0 0 -0.16211,-0.39062 l -1,-0.99414 a 0.55005501,0.55005501 0 0 0 -0.38868,-0.16211 h -0.44921 v -0.90235 h 0.44921 a 0.55005501,0.55005501 0 0 0 0.38868,-0.16211 l 0.83984,-0.84375 h 0.77148 a 0.55005501,0.55005501 0 0 0 0.38868,-0.16015 l 1,-1 a 0.55005501,0.55005501 0 0 0 0.16211,-0.38867 v -1.77344 l 0.44921,-0.44922 0.61133,0.61133 a 0.55005501,0.55005501 0 0 0 0.38867,0.16015 h 1.77149 l 0.83984,0.83985 a 0.55005501,0.55005501 0 0 0 0.77735,0 l 1,-1 a 0.55005501,0.55005501 0 0 0 0.16211,-0.38867 v -0.45508 h 1.44921 a 0.55005501,0.55005501 0 1 0 0,-1.09961 z" id="path42222-9-3-2" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g10865-1-4" transform="translate(209.9929,-231)">
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="g12049-3-5" transform="translate(126,64.00005)" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 52.0071,410.99995 v 1 L 61.5,412 c 0.676161,0.01 0.676161,-1.00956 0,-1 z M 48.5,416 c -0.676161,-0.01 -0.676161,1.00956 0,1 l 5.5071,-5e-5 v -1 z m 10.5071,-5e-5 v 1 L 61.5,417 c 0.676161,0.01 0.676161,-1.00956 0,-1 z M 48.5,421 c -0.676161,-0.01 -0.676161,1.00956 0,1 l 9.5071,-5e-5 v -1 z" id="path12047-5-1" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccc"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 416.49023,242.95508 a 0.55005501,0.55005501 0 0 0 -0.55078,0.55078 v 0.77539 l -0.44922,0.45117 -0.61132,-0.61133 a 0.55005501,0.55005501 0 0 0 -0.38868,-0.16211 h -1.77148 l -0.83984,-0.83789 a 0.55005501,0.55005501 0 0 0 -0.77735,0 l -1,1 a 0.55005501,0.55005501 0 0 0 -0.16211,0.38868 v 1.77148 l -0.67773,0.67773 h -0.77149 a 0.55005501,0.55005501 0 0 0 -0.39062,0.16211 l -0.83789,0.8418 h -0.77149 a 0.55005501,0.55005501 0 0 0 -0.55078,0.55078 v 2.00391 a 0.55005501,0.55005501 0 0 0 0.55078,0.55078 h 0.77344 l 0.67578,0.67383 v 0.54492 l -0.67578,0.68164 -0.76758,-0.008 a 0.55005501,0.55005501 0 0 0 -0.55664,0.54883 v 1.21093 0.78907 a 0.550785,0.550785 0 1 0 1.10157,0 v -0.78907 -0.65429 l 0.44336,0.004 a 0.55005501,0.55005501 0 0 0 0.39648,-0.16211 l 1,-1.00781 a 0.55005501,0.55005501 0 0 0 0.16016,-0.38672 v -1 a 0.55005501,0.55005501 0 0 0 -0.16211,-0.39062 l -1,-0.99414 a 0.55005501,0.55005501 0 0 0 -0.38868,-0.16211 h -0.44921 v -0.90235 h 0.44921 a 0.55005501,0.55005501 0 0 0 0.38868,-0.16211 l 0.83984,-0.84375 h 0.77148 a 0.55005501,0.55005501 0 0 0 0.38868,-0.16015 l 1,-1 a 0.55005501,0.55005501 0 0 0 0.16211,-0.38867 v -1.77344 l 0.44921,-0.44922 0.61133,0.61133 a 0.55005501,0.55005501 0 0 0 0.38867,0.16015 h 1.77149 l 0.83984,0.83985 a 0.55005501,0.55005501 0 0 0 0.77735,0 l 1,-1 a 0.55005501,0.55005501 0 0 0 0.16211,-0.38867 v -0.45508 h 1.44921 a 0.55005501,0.55005501 0 1 0 0,-1.09961 z"
+ id="path42222-9-3-2"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g10865-1-4"
+ transform="translate(209.9929,-231)">
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ id="g12049-3-5"
+ transform="translate(126,64.00005)"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 52.0071,410.99995 v 1 L 61.5,412 c 0.676161,0.01 0.676161,-1.00956 0,-1 z M 48.5,416 c -0.676161,-0.01 -0.676161,1.00956 0,1 l 5.5071,-5e-5 v -1 z m 10.5071,-5e-5 v 1 L 61.5,417 c 0.676161,0.01 0.676161,-1.00956 0,-1 z M 48.5,421 c -0.676161,-0.01 -0.676161,1.00956 0,1 l 9.5071,-5e-5 v -1 z"
+ id="path12047-5-1"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccc" />
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 175.5,474 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 7,4 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 4,4 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z" id="circle14100-8-7" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-0.00710095,-1)" id="g24230-2" style="display:inline;fill:#ffffff;enable-background:new">
- <g style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" transform="translate(126,64.00005)" id="g24222-6" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 53.5,411 a 0.50005,0.50005 0 1 0 0,1 h 8 a 0.50005,0.50005 0 1 0 0,-1 z m 0,5 a 0.50005,0.50005 0 1 0 0,1 h 8 a 0.50005,0.50005 0 1 0 0,-1 z m 0,5 a 0.50005,0.50005 0 1 0 0,1 h 8 a 0.50005,0.50005 0 1 0 0,-1 z" id="path24220-9" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 175.5,474 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 7,4 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 4,4 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z"
+ id="circle14100-8-7"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-0.00710095,-1)"
+ id="g24230-2"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <g
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
+ transform="translate(126,64.00005)"
+ id="g24222-6"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 53.5,411 a 0.50005,0.50005 0 1 0 0,1 h 8 a 0.50005,0.50005 0 1 0 0,-1 z m 0,5 a 0.50005,0.50005 0 1 0 0,1 h 8 a 0.50005,0.50005 0 1 0 0,-1 z m 0,5 a 0.50005,0.50005 0 1 0 0,1 h 8 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path24220-9"
+ inkscape:connector-curvature="0" />
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 175.5,474 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,5 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,5 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z" id="circle24228-7" inkscape:connector-curvature="0" sodipodi:nodetypes="sssssssssssssss"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g24393-7" transform="matrix(-1,0,0,1,1912.004,-92)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 1367.5039,334.00195 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 9.99219 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 9.9961 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -9.99219 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z m 0.5,1 H 1377 v 8.99219 h -8.9961 z" id="path24368-5" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 1376,338 -4.4961,0.002 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 V 343 h 1 v -3.99805 L 1376,339 Z m 3,0 v 1 l 1,0.002 v 7.99024 h -7.9961 V 346 h -1 v 1.49219 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 8.9961 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -8.99024 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z" id="path24388-3" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(112.05535,339.92702)" id="g44391" style="display:inline;opacity:0.7;fill:#ffffff;enable-background:new">
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate" id="rect44387" width="16" height="16" x="103" y="111"/>
- <path transform="matrix(-0.248353,0.02816779,0.02830718,0.248422,140.45214,86.01031)" style="display:inline;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 140,118 a 8,8 0 0 1 -8,8 8,8 0 0 1 -8,-8 8,8 0 0 1 8,-8 8,8 0 0 1 8,8 z" id="circle44389" inkscape:connector-curvature="0"/>
- </g>
- <g transform="matrix(-1,0,0,1,593.8323,-41.99999)" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g22538"/>
- <g id="g15557" transform="translate(42)" style="fill:#ffffff">
- <g transform="matrix(1,0,0,-1,-42,813.00707)" id="g15497" style="display:inline;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 346,286.00391 c 0,-1.09977 -0.90081,-2.00196 -2,-2.00196 -1.09919,0 -2,0.90219 -2,2.00196 0,1.09976 0.90081,2.0039 2,2.0039 1.09919,0 2,-0.90414 2,-2.0039 z m -1,0 c 0,0.56041 -0.44233,1.0039 -1,1.0039 -0.55767,0 -1,-0.44349 -1,-1.0039 0,-0.56041 0.44233,-1.00196 1,-1.00196 0.55767,0 1,0.44155 1,1.00196 z" id="ellipse15493" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 356,296.00391 c 0,-1.09734 -0.90199,-1.9961 -2,-1.9961 -1.09801,0 -2,0.89876 -2,1.9961 0,1.09733 0.90199,1.99609 2,1.99609 1.09801,0 2,-0.89876 2,-1.99609 z" id="ellipse15495" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 175.5,474 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,5 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,5 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z"
+ id="circle24228-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssssssssssss" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g24393-7"
+ transform="matrix(-1,0,0,1,1912.004,-92)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1367.5039,334.00195 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 9.99219 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 9.9961 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -9.99219 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z m 0.5,1 H 1377 v 8.99219 h -8.9961 z"
+ id="path24368-5"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1376,338 -4.4961,0.002 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 V 343 h 1 v -3.99805 L 1376,339 Z m 3,0 v 1 l 1,0.002 v 7.99024 h -7.9961 V 346 h -1 v 1.49219 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 8.9961 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -8.99024 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z"
+ id="path24388-3"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(112.05535,339.92702)"
+ id="g44391"
+ style="display:inline;opacity:0.7;fill:#ffffff;enable-background:new">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
+ id="rect44387"
+ width="16"
+ height="16"
+ x="103"
+ y="111" />
+ <path
+ transform="matrix(-0.248353,0.02816779,0.02830718,0.248422,140.45214,86.01031)"
+ style="display:inline;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 140,118 a 8,8 0 0 1 -8,8 8,8 0 0 1 -8,-8 8,8 0 0 1 8,-8 8,8 0 0 1 8,8 z"
+ id="circle44389"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="matrix(-1,0,0,1,593.8323,-41.99999)"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g22538" />
+ <g
+ id="g15557"
+ transform="translate(42)"
+ style="fill:#ffffff">
+ <g
+ transform="matrix(1,0,0,-1,-42,813.00707)"
+ id="g15497"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 346,286.00391 c 0,-1.09977 -0.90081,-2.00196 -2,-2.00196 -1.09919,0 -2,0.90219 -2,2.00196 0,1.09976 0.90081,2.0039 2,2.0039 1.09919,0 2,-0.90414 2,-2.0039 z m -1,0 c 0,0.56041 -0.44233,1.0039 -1,1.0039 -0.55767,0 -1,-0.44349 -1,-1.0039 0,-0.56041 0.44233,-1.00196 1,-1.00196 0.55767,0 1,0.44155 1,1.00196 z"
+ id="ellipse15493"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 356,296.00391 c 0,-1.09734 -0.90199,-1.9961 -2,-1.9961 -1.09801,0 -2,0.89876 -2,1.9961 0,1.09733 0.90199,1.99609 2,1.99609 1.09801,0 2,-0.89876 2,-1.99609 z"
+ id="ellipse15495"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 306.49609,516.00391 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z m -2.00976,0.99414 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36328,-0.85937 z m -1.00195,3 a 0.50005,0.50005 0 0 0 -0.34766,0.85937 l 1,1 a 0.50005,0.50005 0 1 0 0.70703,-0.70703 l -1,-1 a 0.50005,0.50005 0 0 0 -0.35937,-0.15234 z m 3.01171,2.00586 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 2.9961,0.99414 a 0.50005,0.50005 0 0 0 -0.34961,0.85937 l 1,1 a 0.50005,0.50005 0 1 0 0.70703,-0.70703 l -1,-1 a 0.50005,0.50005 0 0 0 -0.35742,-0.15234 z m 0.99414,3 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36328,-0.85937 z m -4.9961,1.00586 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z" id="path15483-4" inkscape:connector-curvature="0"/>
- </g>
- <g id="g6238" style="fill:#ffffff">
- <g id="g15734" style="fill:#ffffff">
- <g style="opacity:0.6;fill:#ffffff" id="g15738">
- <path inkscape:connector-curvature="0" id="path15684" d="m 532.57617,472.98047 a 0.55005501,0.55005501 0 0 0 -0.42383,0.18555 c -0.46657,0.51387 -1.20227,1.13094 -1.20312,2.14257 -10e-4,1.1847 0.85571,2.11411 1.94336,2.91797 1.08765,0.80386 2.47935,1.527 3.84765,2.25782 0.44144,0.23578 0.88242,0.47056 1.3086,0.70312 1.11316,0.60746 2.13512,1.2144 2.84375,1.81836 0.70862,0.60396 1.05894,1.15906 1.05859,1.68359 -4e-4,0.48086 -0.32771,1.0064 -0.79492,1.38086 a 0.55027044,0.55027044 0 1 0 0.6875,0.85938 c 0.65297,-0.52334 1.20625,-1.30182 1.20703,-2.23828 6.6e-4,-0.99421 -0.62031,-1.82029 -1.44531,-2.52344 -0.825,-0.70315 -1.89813,-1.32892 -3.03125,-1.94727 -0.43382,-0.23673 -0.87477,-0.47022 -1.31445,-0.70508 -1.37366,-0.73367 -2.73478,-1.45092 -3.71289,-2.17382 -0.97812,-0.72291 -1.49874,-1.40647 -1.49805,-2.03125 3.7e-4,-0.43907 0.39742,-0.83099 0.91797,-1.4043 a 0.55005501,0.55005501 0 0 0 -0.39063,-0.92578 z m 1.92578,7.9668 a 0.55005501,0.55005501 0 0 0 -0.24804,0.0605 c -0.75,0.375 -1.5313,0.75874 -2.16797,1.28907 -0.63668,0.53032 -1.13681,1.26964 -1.13867,2.20312 0,0.98843 0.53602,1.85319 1.19335,2.41797 a 0.55122854,0.55122854 0 1 0 0.71876,-0.83594 c -0.44771,-0.38466 -0.8125,-1.01968 -0.8125,-1.58203 0.002,-0.56635 0.25363,-0.95243 0.74218,-1.35938 0.48909,-0.40739 1.20703,-0.77343 1.95703,-1.14843 a 0.55005501,0.55005501 0 0 0 -0.24414,-1.04492 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 306.49609,516.00391 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z m -2.00976,0.99414 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36328,-0.85937 z m -1.00195,3 a 0.50005,0.50005 0 0 0 -0.34766,0.85937 l 1,1 a 0.50005,0.50005 0 1 0 0.70703,-0.70703 l -1,-1 a 0.50005,0.50005 0 0 0 -0.35937,-0.15234 z m 3.01171,2.00586 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 2.9961,0.99414 a 0.50005,0.50005 0 0 0 -0.34961,0.85937 l 1,1 a 0.50005,0.50005 0 1 0 0.70703,-0.70703 l -1,-1 a 0.50005,0.50005 0 0 0 -0.35742,-0.15234 z m 0.99414,3 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36328,-0.85937 z m -4.9961,1.00586 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path15483-4"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g6238"
+ style="fill:#ffffff">
+ <g
+ id="g15734"
+ style="fill:#ffffff">
+ <g
+ style="opacity:0.6;fill:#ffffff"
+ id="g15738">
+ <path
+ inkscape:connector-curvature="0"
+ id="path15684"
+ d="m 532.57617,472.98047 a 0.55005501,0.55005501 0 0 0 -0.42383,0.18555 c -0.46657,0.51387 -1.20227,1.13094 -1.20312,2.14257 -10e-4,1.1847 0.85571,2.11411 1.94336,2.91797 1.08765,0.80386 2.47935,1.527 3.84765,2.25782 0.44144,0.23578 0.88242,0.47056 1.3086,0.70312 1.11316,0.60746 2.13512,1.2144 2.84375,1.81836 0.70862,0.60396 1.05894,1.15906 1.05859,1.68359 -4e-4,0.48086 -0.32771,1.0064 -0.79492,1.38086 a 0.55027044,0.55027044 0 1 0 0.6875,0.85938 c 0.65297,-0.52334 1.20625,-1.30182 1.20703,-2.23828 6.6e-4,-0.99421 -0.62031,-1.82029 -1.44531,-2.52344 -0.825,-0.70315 -1.89813,-1.32892 -3.03125,-1.94727 -0.43382,-0.23673 -0.87477,-0.47022 -1.31445,-0.70508 -1.37366,-0.73367 -2.73478,-1.45092 -3.71289,-2.17382 -0.97812,-0.72291 -1.49874,-1.40647 -1.49805,-2.03125 3.7e-4,-0.43907 0.39742,-0.83099 0.91797,-1.4043 a 0.55005501,0.55005501 0 0 0 -0.39063,-0.92578 z m 1.92578,7.9668 a 0.55005501,0.55005501 0 0 0 -0.24804,0.0605 c -0.75,0.375 -1.5313,0.75874 -2.16797,1.28907 -0.63668,0.53032 -1.13681,1.26964 -1.13867,2.20312 0,0.98843 0.53602,1.85319 1.19335,2.41797 a 0.55122854,0.55122854 0 1 0 0.71876,-0.83594 c -0.44771,-0.38466 -0.8125,-1.01968 -0.8125,-1.58203 0.002,-0.56635 0.25363,-0.95243 0.74218,-1.35938 0.48909,-0.40739 1.20703,-0.77343 1.95703,-1.14843 a 0.55005501,0.55005501 0 0 0 -0.24414,-1.04492 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
- <path inkscape:connector-curvature="0" id="path15690" d="m 533.5,475 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z m 0,9 a 0.50005,0.50005 0 1 0 0,1 h 2 A 0.50005,0.50005 0 0 0 536,484.58008 0.50005,0.50005 0 0 0 536.5,485 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -4 A 0.50005,0.50005 0 0 0 536,484.41992 0.50005,0.50005 0 0 0 535.5,484 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
+ <path
+ inkscape:connector-curvature="0"
+ id="path15690"
+ d="m 533.5,475 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z m 0,9 a 0.50005,0.50005 0 1 0 0,1 h 2 A 0.50005,0.50005 0 0 0 536,484.58008 0.50005,0.50005 0 0 0 536.5,485 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -4 A 0.50005,0.50005 0 0 0 536,484.41992 0.50005,0.50005 0 0 0 535.5,484 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
- <path sodipodi:nodetypes="sssssccccccccccccc" inkscape:connector-curvature="0" id="path13640-8" d="m 540.5,472.25 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g15124-5" transform="translate(-558,-200)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 247.59961,579 a 0.60006002,0.60006002 0 0 0 -0.41797,1.03125 l 2.78711,2.78711 a 0.60076499,0.60076499 0 0 0 0.84961,-0.84961 l -2.78711,-2.78711 A 0.60006002,0.60006002 0 0 0 247.59961,579 Z m -0.11133,2.89453 a 0.60006002,0.60006002 0 0 0 -0.41211,0.18164 l -1,1 a 0.60006002,0.60006002 0 1 0 0.84766,0.84766 l 1,-1 a 0.60006002,0.60006002 0 0 0 -0.43555,-1.0293 z m -3,3 a 0.60006002,0.60006002 0 0 0 -0.41211,0.18164 l -1,1 a 0.60006002,0.60006002 0 1 0 0.84766,0.84766 l 1,-1 a 0.60006002,0.60006002 0 0 0 -0.43555,-1.0293 z m -3,3 a 0.60006002,0.60006002 0 0 0 -0.41211,0.18164 l -1,1 a 0.60006002,0.60006002 0 1 0 0.84766,0.84766 l 1,-1 a 0.60006002,0.60006002 0 0 0 -0.43555,-1.0293 z M 237.59961,589 a 0.60006002,0.60006002 0 0 0 -0.41797,1.03125 l 2.78711,2.78711 a 0.60076499,0.60076499 0 0 0 0.84961,-0.84961 l -2.78711,-2.78711 A 0.60006002,0.60006002 0 0 0 237.59961,589 Z" transform="translate(558,200)" id="path15289-7" inkscape:connector-curvature="0"/>
- </g>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="g15178-7" style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" transform="matrix(-0.53033009,-0.53033009,-0.53033009,0.53033009,580.8635,617.75914)">
- <g id="g15176-5" style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none">
- <g id="g15174-3" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 281.51172,579 a 0.50005002,0.50005002 0 0 0 -0.41797,0.20898 c -2.81255,3.79393 -2.81255,9.78811 0,13.58204 a 0.50005002,0.50005002 0 1 0 0.80273,-0.59571 c -2.50459,-3.37852 -2.50459,-9.0121 0,-12.39062 A 0.50005002,0.50005002 0 0 0 281.51172,579 Z m 8.95898,0 a 0.50005002,0.50005002 0 0 0 -0.38476,0.80469 c 2.50459,3.37852 2.50459,9.0121 0,12.39062 a 0.50059472,0.50059472 0 1 0 0.80468,0.59571 c 2.81256,-3.79393 2.81256,-9.78811 0,-13.58204 A 0.50005002,0.50005002 0 0 0 290.47266,579 a 0.50005002,0.50005002 0 0 1 -0.002,0 z m -6.98047,2.99219 a 0.50005002,0.50005002 0 0 0 -0.39648,0.79883 l 2.29102,3.20898 -2.29297,3.20898 a 0.50131814,0.50131814 0 1 0 0.8164,0.58204 l 2.0918,-2.92969 2.0918,2.92969 a 0.50131814,0.50131814 0 1 0 0.8164,-0.58204 L 286.61523,586 l 2.29102,-3.20898 a 0.50005002,0.50005002 0 0 0 -0.0312,-0.63282 0.50005002,0.50005002 0 0 0 -0.78125,0.0508 l -2.0938,2.92967 -2.09375,-2.92969 a 0.50005002,0.50005002 0 0 0 -0.0527,-0.0664 0.50005002,0.50005002 0 0 0 -0.36329,-0.15039 z" transform="matrix(-0.94280903,-0.94280903,-0.94280903,0.94280903,1130.0723,-34.785543)" id="path15160-1" inkscape:connector-curvature="0"/>
+ <path
+ sodipodi:nodetypes="sssssccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path13640-8"
+ d="m 540.5,472.25 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g15124-5"
+ transform="translate(-558,-200)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 247.59961,579 a 0.60006002,0.60006002 0 0 0 -0.41797,1.03125 l 2.78711,2.78711 a 0.60076499,0.60076499 0 0 0 0.84961,-0.84961 l -2.78711,-2.78711 A 0.60006002,0.60006002 0 0 0 247.59961,579 Z m -0.11133,2.89453 a 0.60006002,0.60006002 0 0 0 -0.41211,0.18164 l -1,1 a 0.60006002,0.60006002 0 1 0 0.84766,0.84766 l 1,-1 a 0.60006002,0.60006002 0 0 0 -0.43555,-1.0293 z m -3,3 a 0.60006002,0.60006002 0 0 0 -0.41211,0.18164 l -1,1 a 0.60006002,0.60006002 0 1 0 0.84766,0.84766 l 1,-1 a 0.60006002,0.60006002 0 0 0 -0.43555,-1.0293 z m -3,3 a 0.60006002,0.60006002 0 0 0 -0.41211,0.18164 l -1,1 a 0.60006002,0.60006002 0 1 0 0.84766,0.84766 l 1,-1 a 0.60006002,0.60006002 0 0 0 -0.43555,-1.0293 z M 237.59961,589 a 0.60006002,0.60006002 0 0 0 -0.41797,1.03125 l 2.78711,2.78711 a 0.60076499,0.60076499 0 0 0 0.84961,-0.84961 l -2.78711,-2.78711 A 0.60006002,0.60006002 0 0 0 237.59961,589 Z"
+ transform="translate(558,200)"
+ id="path15289-7"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ id="g15178-7"
+ style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="matrix(-0.53033009,-0.53033009,-0.53033009,0.53033009,580.8635,617.75914)">
+ <g
+ id="g15176-5"
+ style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none">
+ <g
+ id="g15174-3"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 281.51172,579 a 0.50005002,0.50005002 0 0 0 -0.41797,0.20898 c -2.81255,3.79393 -2.81255,9.78811 0,13.58204 a 0.50005002,0.50005002 0 1 0 0.80273,-0.59571 c -2.50459,-3.37852 -2.50459,-9.0121 0,-12.39062 A 0.50005002,0.50005002 0 0 0 281.51172,579 Z m 8.95898,0 a 0.50005002,0.50005002 0 0 0 -0.38476,0.80469 c 2.50459,3.37852 2.50459,9.0121 0,12.39062 a 0.50059472,0.50059472 0 1 0 0.80468,0.59571 c 2.81256,-3.79393 2.81256,-9.78811 0,-13.58204 A 0.50005002,0.50005002 0 0 0 290.47266,579 a 0.50005002,0.50005002 0 0 1 -0.002,0 z m -6.98047,2.99219 a 0.50005002,0.50005002 0 0 0 -0.39648,0.79883 l 2.29102,3.20898 -2.29297,3.20898 a 0.50131814,0.50131814 0 1 0 0.8164,0.58204 l 2.0918,-2.92969 2.0918,2.92969 a 0.50131814,0.50131814 0 1 0 0.8164,-0.58204 L 286.61523,586 l 2.29102,-3.20898 a 0.50005002,0.50005002 0 0 0 -0.0312,-0.63282 0.50005002,0.50005002 0 0 0 -0.78125,0.0508 l -2.0938,2.92967 -2.09375,-2.92969 a 0.50005002,0.50005002 0 0 0 -0.0527,-0.0664 0.50005002,0.50005002 0 0 0 -0.36329,-0.15039 z"
+ transform="matrix(-0.94280903,-0.94280903,-0.94280903,0.94280903,1130.0723,-34.785543)"
+ id="path15160-1"
+ inkscape:connector-curvature="0" />
</g>
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g15242-0" transform="translate(-558,-305)">
- <g id="g15149-2" transform="translate(21,43)" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 259.49219,578.99219 A 0.50005,0.50005 0 0 0 259,579.5 v 11.91992 a 0.50005,0.50005 0 0 0 0.11328,0.4043 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 259.58203,592 H 271.5 a 0.50005,0.50005 0 1 0 0,-1 H 260 v -11.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 1.94922,3.08593 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3.28515,0.70899 a 0.50005,0.50005 0 0 0 -0.18945,0.96484 l 1,0.41602 a 0.50005,0.50005 0 1 0 0.38477,-0.92188 l -1,-0.41797 a 0.50005,0.50005 0 0 0 -0.19532,-0.041 z m 2.57813,1.99609 a 0.50005,0.50005 0 0 0 -0.45508,0.69922 l 0.41797,1 a 0.50037731,0.50037731 0 0 0 0.92383,-0.38476 l -0.41797,-1 a 0.50005,0.50005 0 0 0 -0.46875,-0.31446 z m 1.16601,3.25 a 0.50005,0.50005 0 0 0 -0.49218,0.50586 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50782,-0.50586 z" transform="translate(537,262)" id="path15133-4" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g15242-0"
+ transform="translate(-558,-305)">
+ <g
+ id="g15149-2"
+ transform="translate(21,43)"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 259.49219,578.99219 A 0.50005,0.50005 0 0 0 259,579.5 v 11.91992 a 0.50005,0.50005 0 0 0 0.11328,0.4043 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 259.58203,592 H 271.5 a 0.50005,0.50005 0 1 0 0,-1 H 260 v -11.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 1.94922,3.08593 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3.28515,0.70899 a 0.50005,0.50005 0 0 0 -0.18945,0.96484 l 1,0.41602 a 0.50005,0.50005 0 1 0 0.38477,-0.92188 l -1,-0.41797 a 0.50005,0.50005 0 0 0 -0.19532,-0.041 z m 2.57813,1.99609 a 0.50005,0.50005 0 0 0 -0.45508,0.69922 l 0.41797,1 a 0.50037731,0.50037731 0 0 0 0.92383,-0.38476 l -0.41797,-1 a 0.50005,0.50005 0 0 0 -0.46875,-0.31446 z m 1.16601,3.25 a 0.50005,0.50005 0 0 0 -0.49218,0.50586 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50782,-0.50586 z"
+ transform="translate(537,262)"
+ id="path15133-4"
+ inkscape:connector-curvature="0" />
</g>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" transform="translate(555.01703,519.07892)" id="g12701-3-4" style="display:inline;fill:#ffffff;enable-background:new"/>
- </g>
- <g transform="translate(-390.0036,-305.9964)" style="display:inline;fill:#ffffff;enable-background:new" id="g15818-1">
- <path inkscape:connector-curvature="0" id="path15352-4" d="m 718.49219,868 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 L 717,869.29297 718.70703,871 l 1.14649,-1.14648 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -1,-1 c -0.0957,-0.0957 -0.22603,-0.14855 -0.36133,-0.14648 z m -2.19922,2 -5.14649,5.14648 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 1,1 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 L 718,871.70703 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" sodipodi:nodetypes="ccccccscccccccc"/>
- <g transform="translate(42)" id="g15380-9" style="opacity:1;fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 672.49219,862.99219 A 0.50005,0.50005 0 0 0 672,863.5 v 1.5 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 866 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 673 v -1.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 8,0.5 A 0.50005,0.50005 0 0 0 680,864 v 1 h -1 a 0.50005,0.50005 0 1 0 0,1 h 1 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -1 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 0,7.5 A 0.50005,0.50005 0 0 0 680,871.5 v 1.5 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 874 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 681 v -1.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" id="path15378-5" inkscape:connector-curvature="0"/>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="translate(555.01703,519.07892)"
+ id="g12701-3-4"
+ style="display:inline;fill:#ffffff;enable-background:new" />
+ </g>
+ <g
+ transform="translate(-390.0036,-305.9964)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g15818-1">
+ <path
+ inkscape:connector-curvature="0"
+ id="path15352-4"
+ d="m 718.49219,868 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 L 717,869.29297 718.70703,871 l 1.14649,-1.14648 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -1,-1 c -0.0957,-0.0957 -0.22603,-0.14855 -0.36133,-0.14648 z m -2.19922,2 -5.14649,5.14648 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 1,1 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 L 718,871.70703 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ sodipodi:nodetypes="ccccccscccccccc" />
+ <g
+ transform="translate(42)"
+ id="g15380-9"
+ style="opacity:1;fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 672.49219,862.99219 A 0.50005,0.50005 0 0 0 672,863.5 v 1.5 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 866 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 673 v -1.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 8,0.5 A 0.50005,0.50005 0 0 0 680,864 v 1 h -1 a 0.50005,0.50005 0 1 0 0,1 h 1 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -1 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 0,7.5 A 0.50005,0.50005 0 0 0 680,871.5 v 1.5 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 874 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 681 v -1.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path15378-5"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g transform="translate(-126.00356,356.99997)" style="display:inline;fill:#ffffff;enable-background:new" id="g15185-9">
- <path id="circle24228-7-4-8" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 301,99 c -0.54636,0 -1,0.453638 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.546362 -0.45364,-1 -1,-1 z m 0,4 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m 0,4 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m 3.5,-7 c -0.67616,-0.0096 -0.67616,1.00956 0,1 h 2.25977 c -0.20553,-0.30677 -0.35861,-0.64616 -0.48438,-1 z m 0,4 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 8 c 0.67616,0.01 0.67616,-1.00956 0,-1 z m 0,4 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 8 c 0.67616,0.01 0.67616,-1.00956 0,-1 z" inkscape:connector-curvature="0" sodipodi:nodetypes="sssssssssssssssccccccccccccccc"/>
- <path sodipodi:nodetypes="sssssccccccccccccc" inkscape:connector-curvature="0" id="path13640-7-5" d="m 310.5,95 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"/>
- </g>
- <g id="g15277" transform="translate(21,-41)" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 216.49219,286 a 0.50005,0.50005 0 0 0 -0.5,0.5 L 216,297.50781 a 0.50005,0.50005 0 0 0 0.5,0.5 h 11 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 295 h -1 v 2.00781 H 217 L 216.99219,287 H 219 v -1 z" id="path15273" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 227.53906,284 c -0.61479,0.0726 -1.18185,0.348 -1.74609,0.6543 C 224.66449,285.2669 223.53333,286 222.5,286 h -1 a 0.50005,0.50005 0 1 0 0,1 h 1 c 1.46667,0 2.71051,-0.8919 3.76953,-1.4668 0.52951,-0.28745 1.00932,-0.49644 1.38672,-0.54101 0.3774,-0.0446 0.64533,0.0164 0.99023,0.36133 0.34491,0.3449 0.40591,0.61283 0.36133,0.99023 -0.0446,0.3774 -0.25356,0.85721 -0.54101,1.38672 C 227.8919,288.78949 227,290.03333 227,291.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 c 0,-1.03333 0.7331,-2.16449 1.3457,-3.29297 0.3063,-0.56424 0.58169,-1.1313 0.6543,-1.74609 0.0726,-0.61479 -0.11639,-1.28436 -0.64648,-1.81446 -0.5301,-0.53009 -1.19967,-0.71909 -1.81446,-0.64648 z" id="path15275" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-541,-51)" style="display:inline;fill:#ffffff;enable-background:new" id="g15431-6">
- <path inkscape:connector-curvature="0" id="rect15415-8" d="m 548,653 c -0.54532,0 -1,0.45468 -1,1 v 9 c 0,0.54532 0.45468,1 1,1 h 10 c 0.54532,0 1,-0.45468 1,-1 v -1 h -1 v 1 h -10 v -4 -5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="rect15379-7" d="m 550,650 c -0.54532,0 -1,0.45468 -1,1 v 9 c 0,0.54532 0.45468,1 1,1 h 10 c 0.54532,0 1,-0.45468 1,-1 v -9 c 0,-0.54532 -0.45468,-1 -1,-1 z m 0,1 h 2 v 2 h -2 z m 0,3 h 10 v 6 h -10 z" style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"/>
- </g>
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 342.5,158 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 13 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -13 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 6.5,3 c 2.20237,0 4,1.79764 4,4 0,2.20237 -1.79763,4 -4,4 -2.20236,0 -4,-1.79763 -4,-4 0,-2.20236 1.79764,-4 4,-4 z" id="rect13348"/>
- <g id="g15500" style="display:inline;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 384.5,158 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 12 v 2 h -12 z m -0.5,9 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 12 v 2 h -12 z" id="path15496" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccccccc"/>
- <path style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" d="M 393.00001,165 A 2.000005,2.000005 0 0 1 391,167.00001 2.000005,2.000005 0 0 1 388.99999,165 2.000005,2.000005 0 0 1 391,162.99999 2.000005,2.000005 0 0 1 393.00001,165 Z" id="circle15498" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g20455" transform="rotate(-180,359.49632,417.00345)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 283.49219,330.00781 c -0.1326,3e-5 -0.25976,0.0527 -0.35352,0.14649 l -2,2 c -0.0938,0.0938 -0.14645,0.22091 -0.14648,0.35351 v 5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5 c 0.1326,-3e-5 0.25975,-0.0527 0.35351,-0.14648 l 2,-2 c 0.0938,-0.0938 0.14646,-0.22092 0.14649,-0.35352 v -5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path20447" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 284.25,326 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -4.75,4.75 A 0.50005,0.50005 0 0 0 279,331.25 l -0.008,8.25586 a 0.50005,0.50005 0 0 0 0.50195,0.50195 L 287.75,340 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 4.75,-4.75 A 0.50005,0.50005 0 0 0 293,334.75 l -0.008,-8.24414 a 0.50005,0.50005 0 0 0 -0.49805,-0.49805 z m 0.20703,1 7.53711,0.006 0.006,7.53711 -4.45703,4.45703 -7.55078,0.008 0.008,-7.55078 z" id="path20449" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g15543" transform="translate(42,-41.999994)">
- <g id="g15520" transform="translate(231.99999,-397.99995)" style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 429.48047,53 c -0.15153,0.004 -0.29304,0.07659 -0.38477,0.197266 l -2.94922,2.949218 C 425.83169,56.461484 426.05468,56.99983 426.5,57 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 54 h 7 v 3.5 c -0.01,0.676161 1.00956,0.676161 1,0 v -4 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 h -8 c -0.005,-6.2e-5 -0.009,-6.2e-5 -0.0137,0 -6.7e-4,1.8e-5 -0.001,-2.1e-5 -0.002,0 -0.001,4.1e-5 -0.003,-5e-5 -0.004,0 z M 426,58.000004 V 66.5 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 h 4.25 c 0.67616,0.0096 0.67616,-1.009563 0,-1 H 427 v -7.999996 z" transform="translate(-273.99999,439.99994)" id="path15514" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccc"/>
+ <g
+ transform="translate(-126.00356,356.99997)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g15185-9">
+ <path
+ id="circle24228-7-4-8"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 301,99 c -0.54636,0 -1,0.453638 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.546362 -0.45364,-1 -1,-1 z m 0,4 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m 0,4 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m 3.5,-7 c -0.67616,-0.0096 -0.67616,1.00956 0,1 h 2.25977 c -0.20553,-0.30677 -0.35861,-0.64616 -0.48438,-1 z m 0,4 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 8 c 0.67616,0.01 0.67616,-1.00956 0,-1 z m 0,4 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 8 c 0.67616,0.01 0.67616,-1.00956 0,-1 z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssssssssssssccccccccccccccc" />
+ <path
+ sodipodi:nodetypes="sssssccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path13640-7-5"
+ d="m 310.5,95 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" />
+ </g>
+ <g
+ id="g15277"
+ transform="translate(21,-41)"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 216.49219,286 a 0.50005,0.50005 0 0 0 -0.5,0.5 L 216,297.50781 a 0.50005,0.50005 0 0 0 0.5,0.5 h 11 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 295 h -1 v 2.00781 H 217 L 216.99219,287 H 219 v -1 z"
+ id="path15273"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 227.53906,284 c -0.61479,0.0726 -1.18185,0.348 -1.74609,0.6543 C 224.66449,285.2669 223.53333,286 222.5,286 h -1 a 0.50005,0.50005 0 1 0 0,1 h 1 c 1.46667,0 2.71051,-0.8919 3.76953,-1.4668 0.52951,-0.28745 1.00932,-0.49644 1.38672,-0.54101 0.3774,-0.0446 0.64533,0.0164 0.99023,0.36133 0.34491,0.3449 0.40591,0.61283 0.36133,0.99023 -0.0446,0.3774 -0.25356,0.85721 -0.54101,1.38672 C 227.8919,288.78949 227,290.03333 227,291.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 c 0,-1.03333 0.7331,-2.16449 1.3457,-3.29297 0.3063,-0.56424 0.58169,-1.1313 0.6543,-1.74609 0.0726,-0.61479 -0.11639,-1.28436 -0.64648,-1.81446 -0.5301,-0.53009 -1.19967,-0.71909 -1.81446,-0.64648 z"
+ id="path15275"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-541,-51)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g15431-6">
+ <path
+ inkscape:connector-curvature="0"
+ id="rect15415-8"
+ d="m 548,653 c -0.54532,0 -1,0.45468 -1,1 v 9 c 0,0.54532 0.45468,1 1,1 h 10 c 0.54532,0 1,-0.45468 1,-1 v -1 h -1 v 1 h -10 v -4 -5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="rect15379-7"
+ d="m 550,650 c -0.54532,0 -1,0.45468 -1,1 v 9 c 0,0.54532 0.45468,1 1,1 h 10 c 0.54532,0 1,-0.45468 1,-1 v -9 c 0,-0.54532 -0.45468,-1 -1,-1 z m 0,1 h 2 v 2 h -2 z m 0,3 h 10 v 6 h -10 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 342.5,158 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 13 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -13 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 6.5,3 c 2.20237,0 4,1.79764 4,4 0,2.20237 -1.79763,4 -4,4 -2.20236,0 -4,-1.79763 -4,-4 0,-2.20236 1.79764,-4 4,-4 z"
+ id="rect13348" />
+ <g
+ id="g15500"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 384.5,158 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 12 v 2 h -12 z m -0.5,9 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 12 v 2 h -12 z"
+ id="path15496"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccc" />
+ <path
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="M 393.00001,165 A 2.000005,2.000005 0 0 1 391,167.00001 2.000005,2.000005 0 0 1 388.99999,165 2.000005,2.000005 0 0 1 391,162.99999 2.000005,2.000005 0 0 1 393.00001,165 Z"
+ id="circle15498"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g20455"
+ transform="rotate(-180,359.49632,417.00345)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 283.49219,330.00781 c -0.1326,3e-5 -0.25976,0.0527 -0.35352,0.14649 l -2,2 c -0.0938,0.0938 -0.14645,0.22091 -0.14648,0.35351 v 5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5 c 0.1326,-3e-5 0.25975,-0.0527 0.35351,-0.14648 l 2,-2 c 0.0938,-0.0938 0.14646,-0.22092 0.14649,-0.35352 v -5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path20447"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 284.25,326 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -4.75,4.75 A 0.50005,0.50005 0 0 0 279,331.25 l -0.008,8.25586 a 0.50005,0.50005 0 0 0 0.50195,0.50195 L 287.75,340 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 4.75,-4.75 A 0.50005,0.50005 0 0 0 293,334.75 l -0.008,-8.24414 a 0.50005,0.50005 0 0 0 -0.49805,-0.49805 z m 0.20703,1 7.53711,0.006 0.006,7.53711 -4.45703,4.45703 -7.55078,0.008 0.008,-7.55078 z"
+ id="path20449"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g15543"
+ transform="translate(42,-41.999994)">
+ <g
+ id="g15520"
+ transform="translate(231.99999,-397.99995)"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 430.48047,53 c -0.15153,0.004 -0.29304,0.07659 -0.38477,0.197266 l -3.94922,3.949218 C 425.83169,57.461484 426.05468,57.99983 426.5,58 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 54 h 6 v 3.5 c -0.01,0.676161 1.00956,0.676161 1,0 v -4 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 h -7 c -0.005,-6.2e-5 -0.009,-6.2e-5 -0.0137,0 -6.7e-4,1.8e-5 -0.001,-2.1e-5 -0.002,0 -0.001,4.1e-5 -0.003,-5e-5 -0.004,0 z M 426,59.000004 V 66.5 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 h 4.25 c 0.67616,0.0096 0.67616,-1.009563 0,-1 H 427 v -6.999996 z"
+ transform="translate(-273.99999,439.99994)"
+ id="path15514"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccc" />
</g>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.25111365;enable-background:new" transform="matrix(-0.79928788,0,0,0.79928788,686.43544,-75.73586)" id="g12909-3">
- <path style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" d="m 435.50195,58 a 0.50005,0.50005 0 0 0 -0.50586,0.507812 L 435,59.847656 c -0.37235,0.07227 -0.71903,0.219786 -1.02148,0.427735 l -1.12696,-1.123047 a 0.50005,0.50005 0 0 0 -0.34375,-0.150391 0.50005,0.50005 0 0 0 -0.36133,0.859375 l 1.12696,1.123047 c -0.20773,0.30118 -0.3566,0.644813 -0.42969,1.015625 l -1.3457,0.002 a 0.5009775,0.5009775 0 0 0 0.002,1.001953 L 432.83789,63 c 0.0676,0.378442 0.20857,0.7312 0.41602,1.039062 l -1.10743,1.109376 a 0.50005,0.50005 0 1 0 0.70508,0.705078 l 1.10352,-1.101563 c 0.30785,0.216541 0.661,0.370975 1.04297,0.445313 l -0.002,1.300781 a 0.50098382,0.50098382 0 1 0 1.00196,0.0039 L 436,65.199219 c 0.38598,-0.06997 0.74484,-0.216649 1.05664,-0.431641 l 1.08203,1.085938 a 0.5000572,0.5000572 0 1 0 0.70899,-0.705078 l -1.08399,-1.087891 C 437.97884,63.747505 438.12621,63.387471 438.19531,63 H 439.5 a 0.50033424,0.50033424 0 1 0 0,-1 h -1.31055 c -0.0748,-0.379778 -0.22985,-0.730801 -0.44531,-1.037109 l 1.10156,-1.103516 A 0.50005,0.50005 0 0 0 438.49805,59 a 0.50005,0.50005 0 0 0 -0.35743,0.154297 l -1.10742,1.105469 C 436.72738,60.053691 436.37559,59.913865 436,59.845703 l -0.004,-1.339844 A 0.50005,0.50005 0 0 0 435.50195,58 Z m -0.002,3.300781 c 0.66274,0 1.19921,0.536481 1.19922,1.199219 0,0.662738 -0.53648,1.199219 -1.19922,1.199219 -0.66274,-8e-6 -1.19922,-0.536481 -1.19922,-1.199219 0,-0.66273 0.53649,-1.199211 1.19922,-1.199219 z" transform="matrix(-1.2511137,0,0,1.2511137,911.35554,147.30094)" id="path12903-0" inkscape:connector-curvature="0"/>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.25111365;enable-background:new"
+ transform="matrix(-0.79928788,0,0,0.79928788,686.43544,-75.73586)"
+ id="g12909-3">
+ <path
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ d="m 435.50195,58 a 0.50005,0.50005 0 0 0 -0.50586,0.507812 L 435,59.847656 c -0.37235,0.07227 -0.71903,0.219786 -1.02148,0.427735 l -1.12696,-1.123047 a 0.50005,0.50005 0 0 0 -0.34375,-0.150391 0.50005,0.50005 0 0 0 -0.36133,0.859375 l 1.12696,1.123047 c -0.20773,0.30118 -0.3566,0.644813 -0.42969,1.015625 l -1.3457,0.002 a 0.5009775,0.5009775 0 0 0 0.002,1.001953 L 432.83789,63 c 0.0676,0.378442 0.20857,0.7312 0.41602,1.039062 l -1.10743,1.109376 a 0.50005,0.50005 0 1 0 0.70508,0.705078 l 1.10352,-1.101563 c 0.30785,0.216541 0.661,0.370975 1.04297,0.445313 l -0.002,1.300781 a 0.50098382,0.50098382 0 1 0 1.00196,0.0039 L 436,65.199219 c 0.38598,-0.06997 0.74484,-0.216649 1.05664,-0.431641 l 1.08203,1.085938 a 0.5000572,0.5000572 0 1 0 0.70899,-0.705078 l -1.08399,-1.087891 C 437.97884,63.747505 438.12621,63.387471 438.19531,63 H 439.5 a 0.50033424,0.50033424 0 1 0 0,-1 h -1.31055 c -0.0748,-0.379778 -0.22985,-0.730801 -0.44531,-1.037109 l 1.10156,-1.103516 A 0.50005,0.50005 0 0 0 438.49805,59 a 0.50005,0.50005 0 0 0 -0.35743,0.154297 l -1.10742,1.105469 C 436.72738,60.053691 436.37559,59.913865 436,59.845703 l -0.004,-1.339844 A 0.50005,0.50005 0 0 0 435.50195,58 Z m -0.002,3.300781 c 0.66274,0 1.19921,0.536481 1.19922,1.199219 0,0.662738 -0.53648,1.199219 -1.19922,1.199219 -0.66274,-8e-6 -1.19922,-0.536481 -1.19922,-1.199219 0,-0.66273 0.53649,-1.199211 1.19922,-1.199219 z"
+ transform="matrix(-1.2511137,0,0,1.2511137,911.35554,147.30094)"
+ id="path12903-0"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g transform="translate(-583.99495,-390.00505)" id="g15882-7" style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 351.50586,598.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.79297 l -2.70703,2.70703 h -2.79297 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -1,1 a 0.50005,0.50005 0 0 0 0,0.70704 l 6,6 a 0.50005,0.50005 0 0 0 0.70704,0 l 1,-1 a 0.50005,0.50005 0 0 0 0.14648,-0.35352 v -2.79297 l 2.70703,-2.70703 h 0.79297 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1 a 0.50005,0.50005 0 0 0 -0.14648,-0.35352 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35352,-0.14648 z m 0.5,1 h 0.29297 l 2.70703,2.70703 v 0.29297 h -0.5 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 a 0.50005,0.50005 0 0 0 -0.14648,0.35352 v 2.79297 l -0.5,0.5 -5.29297,-5.29297 0.5,-0.5 h 2.79297 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 a 0.50005,0.50005 0 0 0 0.14648,-0.35352 z m -5.75977,8.24609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3.75,3.75 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 3.75,-3.75 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z" transform="translate(583.99495,390.00505)" id="path15847-7" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-583.99495,-390.00505)" style="display:inline;fill:#ffffff;enable-background:new" id="g16002-8">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 372.50586,598.99414 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 0.79297 l 3.70703,3.70703 h 0.79297 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1 c -2e-5,-0.1326 -0.0527,-0.25975 -0.14648,-0.35352 l -3,-3 c -0.0938,-0.0938 -0.22092,-0.14646 -0.35352,-0.14648 z m -1.20703,2 -2,2 h -2.79297 c -0.1326,2e-5 -0.25976,0.0527 -0.35352,0.14648 l -1,1 c -0.19519,0.19528 -0.19519,0.51177 0,0.70704 l 6,6 c 0.19527,0.1952 0.51176,0.1952 0.70704,0 l 1,-1 c 0.0938,-0.0938 0.14646,-0.22092 0.14648,-0.35352 v -2.79297 l 2,-2 z m -4.05274,7.24609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3.75,3.75 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 3.75,-3.75 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z" transform="translate(583.99495,390.00505)" id="path15876-9" inkscape:connector-curvature="0"/>
- </g>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" transform="translate(-21.000047,168)" id="g15951-6" style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 27.5,347 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3.5 h 1 v -3 h 3 v -1 z m 9.5,0 v 1 h 3 v 3 h 1 v -3.5 A 0.50005,0.50005 0 0 0 40.5,347 Z m -10,10 v 3.5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 31 v -1 h -3 v -3 z m 13,0 v 3 h -3 v 1 h 3.5 A 0.50005,0.50005 0 0 0 41,360.5 V 357 Z" id="path15947-7" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 30.5,350 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 7 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 7 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -7 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z" id="rect15949-3" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g16385" transform="translate(-21,21.00001)">
- <path id="path16351" d="m 118,95.5 c -3.58986,0 -6.5,2.41014 -6.5,6 1,1 3,2.5 6.5,2.5 z" style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" inkscape:connector-curvature="0" sodipodi:nodetypes="cccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 118,95 c -3.86007,0 -7,3.139925 -7,7 0,3.86008 3.13992,7 7,7 3.86008,0 7,-3.13992 7,-7 0,-3.860075 -3.13993,-7 -7,-7 z m 0,1 c 3.31963,0 6,2.680365 6,6 0,3.31964 -2.68036,6 -6,6 -3.31964,0 -6,-2.68036 -6,-6 0,-3.319635 2.68037,-6 6,-6 z" id="path16353" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 123.24414,102.64453 a 0.60006002,0.60006002 0 0 0 -0.41797,1.0293 l 0.5,0.5 a 0.60006002,0.60006002 0 1 0 0.84766,-0.84766 l -0.5,-0.5 a 0.60006002,0.60006002 0 0 0 -0.42969,-0.18164 z m -2.25,0.75 a 0.60006002,0.60006002 0 0 0 -0.41797,1.0293 l 1.75,1.75 a 0.60006002,0.60006002 0 1 0 0.84766,-0.84766 l -1.75,-1.75 a 0.60006002,0.60006002 0 0 0 -0.42969,-0.18164 z m -2.5,0.5 a 0.60006002,0.60006002 0 0 0 -0.41797,1.0293 l 2.75,2.75 a 0.60006002,0.60006002 0 1 0 0.84766,-0.84766 l -2.75,-2.75 a 0.60006002,0.60006002 0 0 0 -0.42969,-0.18164 z m 0,3 a 0.60006002,0.60006002 0 0 0 -0.41797,1.0293 l 0.75,0.75 a 0.60006002,0.60006002 0 1 0 0.84766,-0.84766 l -0.75,-0.75 a 0.60006002,0.60006002 0 0 0 -0.42969,-0.18164 z" id="path16355" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-168,-294)" id="g16054" style="display:inline;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 180.82031,32.001953 c -2.53256,0.0762 -4.74925,1.739751 -5.52929,4.150391 -0.66549,2.0566 -0.15791,4.2781 1.25,5.847656 H 176.25 a 0.50005,0.50005 0 0 0 -0.35352,0.146484 l -1.75,1.75 A 0.50005,0.50005 0 0 0 174,44.25 v 1.25 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1.25 a 0.50005,0.50005 0 0 0 -0.14648,-0.353516 l -1.75,-1.75 A 0.50005,0.50005 0 0 0 185.75,42 h -0.29492 c 1.50007,-1.670137 1.96594,-4.059297 1.13281,-6.1875 -0.92362,-2.35937 -3.23501,-3.886777 -5.76758,-3.810547 z m 0.0332,1.099609 c 2.07177,-0.0624 3.95341,1.181239 4.70898,3.111329 0.75557,1.9301 0.2178,4.121692 -1.3457,5.482421 A 0.55028534,0.55028534 0 0 0 184.03906,42 H 183.5 a 0.50005,0.50005 0 1 0 0,1 h 2.04297 L 187,44.457031 V 45 H 175 V 44.457031 L 176.45703,43 H 180.5 a 0.50005,0.50005 0 1 0 0,-1 h -2.37695 a 0.55005501,0.55005501 0 0 0 -0.11133,-0.117188 c -1.64252,-1.264239 -2.31195,-3.418585 -1.67383,-5.390624 0.63812,-1.972051 2.44385,-3.328265 4.51563,-3.390626 z" transform="translate(168,294)" id="path16048" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 348.55469,328.69141 a 0.50005,0.50005 0 0 0 -0.0859,0.008 c -1.42662,0.22929 -2.54672,1.3539 -2.77148,2.78125 a 0.50012645,0.50012645 0 1 0 0.98828,0.1543 c 0.15806,-1.00378 0.94009,-1.78798 1.94336,-1.94922 a 0.50005,0.50005 0 0 0 -0.0742,-0.99414 z" id="path16052" inkscape:connector-curvature="0"/>
- </g>
- <g id="g16187" style="display:inline;fill:#ffffff;enable-background:new" transform="translate(462.00505,-96.005057)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 103.49609,556.99023 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1.57031,1.57032 c -1.22858,-1.06562 -2.825838,-1.7168 -4.576171,-1.7168 -3.86007,0 -7,3.13993 -7,7 0,1.75033 0.649231,3.34954 1.714844,4.57813 l -1.568359,1.56835 a 0.50005,0.50005 0 1 0 0.707031,0.70704 l 1.568359,-1.56836 c 1.228585,1.06561 2.827793,1.71484 4.578125,1.71484 3.860071,0 7.000001,-3.13993 7.000001,-7 0,-1.75033 -0.65118,-3.34759 -1.7168,-4.57617 l 1.57032,-1.57031 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -6.490231,1.00391 c 3.319631,0 6.000001,2.68037 6.000001,6 0,3.31963 -2.68037,6 -6.000001,6 -3.31963,0 -6,-2.68037 -6,-6 0,-0.88092 0.193846,-1.71405 0.533203,-2.4668 l 0.466797,0.4668 1,1 v 2 h 2 v 1 l 1,1 v 2 h 0.75 1.25 l 1,-1 1.000001,-1 v -1 l -1.000001,-1 h -2 -1 l -1,-1 h -1 l 1,-1 h 1 l 2,-2 -1,-1 h -1 l -1,-1 0.894532,-0.89453 c 0.358617,-0.0666 0.727234,-0.10547 1.105468,-0.10547 z" transform="translate(-462.00505,96.005057)" id="circle16176" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g8419-9" transform="translate(1279.001,-241)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <rect style="display:inline;opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" id="rect8368-4" width="16" height="16" x="-1148" y="398"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m -1140.8984,400.01367 c -2.0857,0.12882 -4.0362,1.26078 -5.1621,3.1211 -1.5012,2.48042 -1.1755,5.66201 0.7968,7.78711 1.9724,2.12509 5.1198,2.68733 7.7051,1.375 2.5853,-1.31234 3.9907,-4.18482 3.4395,-7.03126 a 0.50030025,0.50030025 0 1 0 -0.9825,0.18946 c 0.4673,2.4126 -0.7188,4.8369 -2.9101,5.94922 -2.1913,1.11231 -4.8478,0.63909 -6.5195,-1.16211 -1.6718,-1.8012 -1.9463,-4.48748 -0.6739,-6.58985 1.2724,-2.10236 3.7774,-3.10263 6.1485,-2.45703 a 0.50104088,0.50104088 0 1 0 0.2636,-0.96679 c -0.6993,-0.19043 -1.4102,-0.25779 -2.1054,-0.21485 z" id="ellipse8370-9" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 144.98047,157.99023 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 l -3.71289,3.71484 c -0.0265,-0.001 -0.0513,-0.008 -0.0781,-0.008 -0.8224,0 -1.5,0.67765 -1.5,1.5 0,0.82235 0.6776,1.5 1.5,1.5 0.8224,0 1.5,-0.67765 1.5,-1.5 0,-0.0274 -0.006,-0.0531 -0.008,-0.0801 l 3.71289,-3.71289 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z" transform="translate(-1279.001,241)" id="rect8385-9" inkscape:connector-curvature="0"/>
- </g>
- <g id="g15336" style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
- <path sodipodi:nodetypes="sssss" inkscape:connector-curvature="0" id="path13329" d="m 369.99998,160.99999 c -2.20236,0 -4,1.79764 -4,4 0,2.20237 1.79764,4 4,4 2.20237,0 4,-1.79763 4,-4 0,-2.20236 -1.79763,-4 -4,-4 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 363.5,158 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z" id="rect13350" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g23051-0" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96" transform="translate(210,20.999991)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 243.49219,389 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -3,3 c -0.49023,0.47127 0.23577,1.19727 0.70704,0.70704 L 243,390.70703 V 402 h -1.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 4 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 244 v -11.29297 l 2.14648,2.14649 c 0.47127,0.49023 1.19727,-0.23577 0.70704,-0.70704 l -3,-3 c -0.0957,-0.0957 -0.22603,-0.14855 -0.36133,-0.14648 z" transform="translate(-210,-20.999991)" id="path23043-3" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccc"/>
- </g>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="g22966-4" transform="translate(-504,167.99288)" style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 366.5,389 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 363,392.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 377,399.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 h 8.58008 l -1.99414,2 h -8.58594 z M 376,390.70117 v 8.5918 l -2,2 v -8.58789 z M 364,393 h 9 v 9 h -9 z" transform="translate(504,-167.99288)" id="path22960-9" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 870.49219,220.99219 A 0.50005,0.50005 0 0 0 870,221.5 v 9.79297 l -2.85352,2.86133 a 0.50005,0.50005 0 1 0 0.70704,0.70508 L 870.70703,232 H 880.5 a 0.50005,0.50005 0 1 0 0,-1 H 871 v -9.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" id="path23055-1" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-327,477.99999)" style="display:inline;fill:#ffffff;enable-background:new" id="g16423-6">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 391,389 c -3.83836,-10e-6 -6.96097,3.10534 -6.99609,6.93555 A 0.50005,0.50005 0 0 0 384,396 c 0,3.86012 3.13988,7.00001 7,7 0.0171,0 0.0337,-0.002 0.0508,-0.002 a 0.50005,0.50005 0 0 0 0.01,-0.002 C 394.89256,402.96308 398,399.83968 398,396 c 0,-0.0171 -0.002,-0.0337 -0.002,-0.0508 a 0.50005,0.50005 0 0 0 -0.002,-0.01 c -0.0328,-3.81095 -3.12289,-6.90166 -6.93359,-6.93554 A 0.50005,0.50005 0 0 0 391,389 Z m 0,1 c 3.31968,0 6,2.68032 6,6 0,0.16955 -0.0858,0.36541 -0.34766,0.60352 -0.26184,0.2381 -0.68795,0.48634 -1.23632,0.69726 C 394.31926,397.72262 392.74298,398 391,398 c -0.65939,0 -1.28221,-0.0509 -1.87695,-0.12305 C 389.05085,397.28221 389,396.65939 389,396 c 0,-1.74298 0.27738,-3.31926 0.69922,-4.41602 0.21092,-0.54837 0.45916,-0.97448 0.69726,-1.23632 C 390.63459,390.08581 390.83045,390 391,390 Z m -1.76367,0.26367 c -0.17337,0.28719 -0.33274,0.60224 -0.47071,0.96094 C 388.28261,392.48043 388,394.15308 388,396 c 0,0.59486 0.0379,1.16229 0.0937,1.71289 -0.55897,-0.113 -1.07951,-0.24662 -1.50977,-0.41211 -0.54837,-0.21092 -0.97448,-0.45916 -1.23632,-0.69726 C 385.08581,396.36541 385,396.16955 385,396 c 0,-2.70567 1.78034,-4.98512 4.23633,-5.73633 z m -3.97266,7.5 c 0.28719,0.17337 0.60224,0.33274 0.96094,0.47071 0.58524,0.22509 1.26802,0.40153 2.00977,0.53124 0.12972,0.74174 0.30616,1.42453 0.53124,2.00977 0.13797,0.3587 0.29734,0.67375 0.47071,0.96094 -1.89863,-0.58074 -3.39192,-2.07402 -3.97266,-3.97266 z m 11.47266,0 C 395.98511,400.21966 393.70566,402 391,402 c -0.16955,0 -0.36541,-0.0858 -0.60352,-0.34766 -0.2381,-0.26184 -0.48634,-0.68795 -0.69726,-1.23632 -0.16549,-0.43026 -0.29911,-0.9508 -0.41211,-1.50977 0.5506,0.0559 1.11803,0.0937 1.71289,0.0937 1.84692,0 3.51957,-0.28262 4.77539,-0.76562 0.3587,-0.13797 0.67375,-0.29734 0.96094,-0.47071 z" transform="translate(327,-477.99999)" id="path22958-5" inkscape:connector-curvature="0"/>
- <g transform="translate(327,-415)" id="g23066-1" style="display:inline;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 391,330 c -1.84692,0 -3.51957,0.28261 -4.77539,0.76562 -0.62791,0.24151 -1.15478,0.53052 -1.55078,0.89063 C 384.27783,332.01636 384,332.47917 384,333 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.16955 0.0858,-0.36541 0.34766,-0.60352 0.26184,-0.2381 0.68795,-0.48634 1.23632,-0.69726 C 387.68074,331.27738 389.25702,331 391,331 c 1.74298,0 3.31926,0.27738 4.41602,0.69922 0.54837,0.21092 0.97448,0.45916 1.23632,0.69726 C 396.91419,332.63459 397,332.83045 397,333 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.52083 -0.27783,-0.98364 -0.67383,-1.34375 -0.396,-0.36011 -0.92287,-0.64912 -1.55078,-0.89063 C 394.51957,330.28261 392.84692,330 391,330 Z" id="path23061-5" inkscape:connector-curvature="0"/>
+ <g
+ transform="translate(-583.99495,-390.00505)"
+ id="g15882-7"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 351.50586,598.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.79297 l -2.70703,2.70703 h -2.79297 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -1,1 a 0.50005,0.50005 0 0 0 0,0.70704 l 6,6 a 0.50005,0.50005 0 0 0 0.70704,0 l 1,-1 a 0.50005,0.50005 0 0 0 0.14648,-0.35352 v -2.79297 l 2.70703,-2.70703 h 0.79297 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1 a 0.50005,0.50005 0 0 0 -0.14648,-0.35352 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35352,-0.14648 z m 0.5,1 h 0.29297 l 2.70703,2.70703 v 0.29297 h -0.5 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 a 0.50005,0.50005 0 0 0 -0.14648,0.35352 v 2.79297 l -0.5,0.5 -5.29297,-5.29297 0.5,-0.5 h 2.79297 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 a 0.50005,0.50005 0 0 0 0.14648,-0.35352 z m -5.75977,8.24609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3.75,3.75 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 3.75,-3.75 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
+ transform="translate(583.99495,390.00505)"
+ id="path15847-7"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-583.99495,-390.00505)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g16002-8">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 372.50586,598.99414 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 0.79297 l 3.70703,3.70703 h 0.79297 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1 c -2e-5,-0.1326 -0.0527,-0.25975 -0.14648,-0.35352 l -3,-3 c -0.0938,-0.0938 -0.22092,-0.14646 -0.35352,-0.14648 z m -1.20703,2 -2,2 h -2.79297 c -0.1326,2e-5 -0.25976,0.0527 -0.35352,0.14648 l -1,1 c -0.19519,0.19528 -0.19519,0.51177 0,0.70704 l 6,6 c 0.19527,0.1952 0.51176,0.1952 0.70704,0 l 1,-1 c 0.0938,-0.0938 0.14646,-0.22092 0.14648,-0.35352 v -2.79297 l 2,-2 z m -4.05274,7.24609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3.75,3.75 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 3.75,-3.75 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
+ transform="translate(583.99495,390.00505)"
+ id="path15876-9"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="translate(-21.000047,168)"
+ id="g15951-6"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 27.5,347 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3.5 h 1 v -3 h 3 v -1 z m 9.5,0 v 1 h 3 v 3 h 1 v -3.5 A 0.50005,0.50005 0 0 0 40.5,347 Z m -10,10 v 3.5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 31 v -1 h -3 v -3 z m 13,0 v 3 h -3 v 1 h 3.5 A 0.50005,0.50005 0 0 0 41,360.5 V 357 Z"
+ id="path15947-7"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 30.5,350 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 7 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 7 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -7 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ id="rect15949-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g16385"
+ transform="translate(-21,21.00001)">
+ <path
+ id="path16351"
+ d="m 118,95.5 c -3.58986,0 -6.5,2.41014 -6.5,6 1,1 3,2.5 6.5,2.5 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 118,95 c -3.86007,0 -7,3.139925 -7,7 0,3.86008 3.13992,7 7,7 3.86008,0 7,-3.13992 7,-7 0,-3.860075 -3.13993,-7 -7,-7 z m 0,1 c 3.31963,0 6,2.680365 6,6 0,3.31964 -2.68036,6 -6,6 -3.31964,0 -6,-2.68036 -6,-6 0,-3.319635 2.68037,-6 6,-6 z"
+ id="path16353"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 123.24414,102.64453 a 0.60006002,0.60006002 0 0 0 -0.41797,1.0293 l 0.5,0.5 a 0.60006002,0.60006002 0 1 0 0.84766,-0.84766 l -0.5,-0.5 a 0.60006002,0.60006002 0 0 0 -0.42969,-0.18164 z m -2.25,0.75 a 0.60006002,0.60006002 0 0 0 -0.41797,1.0293 l 1.75,1.75 a 0.60006002,0.60006002 0 1 0 0.84766,-0.84766 l -1.75,-1.75 a 0.60006002,0.60006002 0 0 0 -0.42969,-0.18164 z m -2.5,0.5 a 0.60006002,0.60006002 0 0 0 -0.41797,1.0293 l 2.75,2.75 a 0.60006002,0.60006002 0 1 0 0.84766,-0.84766 l -2.75,-2.75 a 0.60006002,0.60006002 0 0 0 -0.42969,-0.18164 z m 0,3 a 0.60006002,0.60006002 0 0 0 -0.41797,1.0293 l 0.75,0.75 a 0.60006002,0.60006002 0 1 0 0.84766,-0.84766 l -0.75,-0.75 a 0.60006002,0.60006002 0 0 0 -0.42969,-0.18164 z"
+ id="path16355"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-168,-294)"
+ id="g16054"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 180.82031,32.001953 c -2.53256,0.0762 -4.74925,1.739751 -5.52929,4.150391 -0.66549,2.0566 -0.15791,4.2781 1.25,5.847656 H 176.25 a 0.50005,0.50005 0 0 0 -0.35352,0.146484 l -1.75,1.75 A 0.50005,0.50005 0 0 0 174,44.25 v 1.25 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1.25 a 0.50005,0.50005 0 0 0 -0.14648,-0.353516 l -1.75,-1.75 A 0.50005,0.50005 0 0 0 185.75,42 h -0.29492 c 1.50007,-1.670137 1.96594,-4.059297 1.13281,-6.1875 -0.92362,-2.35937 -3.23501,-3.886777 -5.76758,-3.810547 z m 0.0332,1.099609 c 2.07177,-0.0624 3.95341,1.181239 4.70898,3.111329 0.75557,1.9301 0.2178,4.121692 -1.3457,5.482421 A 0.55028534,0.55028534 0 0 0 184.03906,42 H 183.5 a 0.50005,0.50005 0 1 0 0,1 h 2.04297 L 187,44.457031 V 45 H 175 V 44.457031 L 176.45703,43 H 180.5 a 0.50005,0.50005 0 1 0 0,-1 h -2.37695 a 0.55005501,0.55005501 0 0 0 -0.11133,-0.117188 c -1.64252,-1.264239 -2.31195,-3.418585 -1.67383,-5.390624 0.63812,-1.972051 2.44385,-3.328265 4.51563,-3.390626 z"
+ transform="translate(168,294)"
+ id="path16048"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 348.55469,328.69141 a 0.50005,0.50005 0 0 0 -0.0859,0.008 c -1.42662,0.22929 -2.54672,1.3539 -2.77148,2.78125 a 0.50012645,0.50012645 0 1 0 0.98828,0.1543 c 0.15806,-1.00378 0.94009,-1.78798 1.94336,-1.94922 a 0.50005,0.50005 0 0 0 -0.0742,-0.99414 z"
+ id="path16052"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g16187"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(462.00505,-96.005057)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 103.49609,556.99023 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1.57031,1.57032 c -1.22858,-1.06562 -2.825838,-1.7168 -4.576171,-1.7168 -3.86007,0 -7,3.13993 -7,7 0,1.75033 0.649231,3.34954 1.714844,4.57813 l -1.568359,1.56835 a 0.50005,0.50005 0 1 0 0.707031,0.70704 l 1.568359,-1.56836 c 1.228585,1.06561 2.827793,1.71484 4.578125,1.71484 3.860071,0 7.000001,-3.13993 7.000001,-7 0,-1.75033 -0.65118,-3.34759 -1.7168,-4.57617 l 1.57032,-1.57031 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -6.490231,1.00391 c 3.319631,0 6.000001,2.68037 6.000001,6 0,3.31963 -2.68037,6 -6.000001,6 -3.31963,0 -6,-2.68037 -6,-6 0,-0.88092 0.193846,-1.71405 0.533203,-2.4668 l 0.466797,0.4668 1,1 v 2 h 2 v 1 l 1,1 v 2 h 0.75 1.25 l 1,-1 1.000001,-1 v -1 l -1.000001,-1 h -2 -1 l -1,-1 h -1 l 1,-1 h 1 l 2,-2 -1,-1 h -1 l -1,-1 0.894532,-0.89453 c 0.358617,-0.0666 0.727234,-0.10547 1.105468,-0.10547 z"
+ transform="translate(-462.00505,96.005057)"
+ id="circle16176"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g8419-9"
+ transform="translate(1279.001,-241)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <rect
+ style="display:inline;opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="rect8368-4"
+ width="16"
+ height="16"
+ x="-1148"
+ y="398" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -1140.8984,400.01367 c -2.0857,0.12882 -4.0362,1.26078 -5.1621,3.1211 -1.5012,2.48042 -1.1755,5.66201 0.7968,7.78711 1.9724,2.12509 5.1198,2.68733 7.7051,1.375 2.5853,-1.31234 3.9907,-4.18482 3.4395,-7.03126 a 0.50030025,0.50030025 0 1 0 -0.9825,0.18946 c 0.4673,2.4126 -0.7188,4.8369 -2.9101,5.94922 -2.1913,1.11231 -4.8478,0.63909 -6.5195,-1.16211 -1.6718,-1.8012 -1.9463,-4.48748 -0.6739,-6.58985 1.2724,-2.10236 3.7774,-3.10263 6.1485,-2.45703 a 0.50104088,0.50104088 0 1 0 0.2636,-0.96679 c -0.6993,-0.19043 -1.4102,-0.25779 -2.1054,-0.21485 z"
+ id="ellipse8370-9"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 144.98047,157.99023 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 l -3.71289,3.71484 c -0.0265,-0.001 -0.0513,-0.008 -0.0781,-0.008 -0.8224,0 -1.5,0.67765 -1.5,1.5 0,0.82235 0.6776,1.5 1.5,1.5 0.8224,0 1.5,-0.67765 1.5,-1.5 0,-0.0274 -0.006,-0.0531 -0.008,-0.0801 l 3.71289,-3.71289 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z"
+ transform="translate(-1279.001,241)"
+ id="rect8385-9"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g15336"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
+ <path
+ sodipodi:nodetypes="sssss"
+ inkscape:connector-curvature="0"
+ id="path13329"
+ d="m 369.99998,160.99999 c -2.20236,0 -4,1.79764 -4,4 0,2.20237 1.79764,4 4,4 2.20237,0 4,-1.79763 4,-4 0,-2.20236 -1.79763,-4 -4,-4 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 363.5,158 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
+ id="rect13350"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g23051-0"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ transform="translate(210,20.999991)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 243.49219,389 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -3,3 c -0.49023,0.47127 0.23577,1.19727 0.70704,0.70704 L 243,390.70703 V 402 h -1.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 4 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 244 v -11.29297 l 2.14648,2.14649 c 0.47127,0.49023 1.19727,-0.23577 0.70704,-0.70704 l -3,-3 c -0.0957,-0.0957 -0.22603,-0.14855 -0.36133,-0.14648 z"
+ transform="translate(-210,-20.999991)"
+ id="path23043-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccc" />
+ </g>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ id="g22966-4"
+ transform="translate(-504,167.99288)"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 366.5,389 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 363,392.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 377,399.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 h 8.58008 l -1.99414,2 h -8.58594 z M 376,390.70117 v 8.5918 l -2,2 v -8.58789 z M 364,393 h 9 v 9 h -9 z"
+ transform="translate(504,-167.99288)"
+ id="path22960-9"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 870.49219,220.99219 A 0.50005,0.50005 0 0 0 870,221.5 v 9.79297 l -2.85352,2.86133 a 0.50005,0.50005 0 1 0 0.70704,0.70508 L 870.70703,232 H 880.5 a 0.50005,0.50005 0 1 0 0,-1 H 871 v -9.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path23055-1"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-327,477.99999)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g16423-6">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 391,389 c -3.83836,-10e-6 -6.96097,3.10534 -6.99609,6.93555 A 0.50005,0.50005 0 0 0 384,396 c 0,3.86012 3.13988,7.00001 7,7 0.0171,0 0.0337,-0.002 0.0508,-0.002 a 0.50005,0.50005 0 0 0 0.01,-0.002 C 394.89256,402.96308 398,399.83968 398,396 c 0,-0.0171 -0.002,-0.0337 -0.002,-0.0508 a 0.50005,0.50005 0 0 0 -0.002,-0.01 c -0.0328,-3.81095 -3.12289,-6.90166 -6.93359,-6.93554 A 0.50005,0.50005 0 0 0 391,389 Z m 0,1 c 3.31968,0 6,2.68032 6,6 0,0.16955 -0.0858,0.36541 -0.34766,0.60352 -0.26184,0.2381 -0.68795,0.48634 -1.23632,0.69726 C 394.31926,397.72262 392.74298,398 391,398 c -0.65939,0 -1.28221,-0.0509 -1.87695,-0.12305 C 389.05085,397.28221 389,396.65939 389,396 c 0,-1.74298 0.27738,-3.31926 0.69922,-4.41602 0.21092,-0.54837 0.45916,-0.97448 0.69726,-1.23632 C 390.63459,390.08581 390.83045,390 391,390 Z m -1.76367,0.26367 c -0.17337,0.28719 -0.33274,0.60224 -0.47071,0.96094 C 388.28261,392.48043 388,394.15308 388,396 c 0,0.59486 0.0379,1.16229 0.0937,1.71289 -0.55897,-0.113 -1.07951,-0.24662 -1.50977,-0.41211 -0.54837,-0.21092 -0.97448,-0.45916 -1.23632,-0.69726 C 385.08581,396.36541 385,396.16955 385,396 c 0,-2.70567 1.78034,-4.98512 4.23633,-5.73633 z m -3.97266,7.5 c 0.28719,0.17337 0.60224,0.33274 0.96094,0.47071 0.58524,0.22509 1.26802,0.40153 2.00977,0.53124 0.12972,0.74174 0.30616,1.42453 0.53124,2.00977 0.13797,0.3587 0.29734,0.67375 0.47071,0.96094 -1.89863,-0.58074 -3.39192,-2.07402 -3.97266,-3.97266 z m 11.47266,0 C 395.98511,400.21966 393.70566,402 391,402 c -0.16955,0 -0.36541,-0.0858 -0.60352,-0.34766 -0.2381,-0.26184 -0.48634,-0.68795 -0.69726,-1.23632 -0.16549,-0.43026 -0.29911,-0.9508 -0.41211,-1.50977 0.5506,0.0559 1.11803,0.0937 1.71289,0.0937 1.84692,0 3.51957,-0.28262 4.77539,-0.76562 0.3587,-0.13797 0.67375,-0.29734 0.96094,-0.47071 z"
+ transform="translate(327,-477.99999)"
+ id="path22958-5"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="translate(327,-415)"
+ id="g23066-1"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 391,330 c -1.84692,0 -3.51957,0.28261 -4.77539,0.76562 -0.62791,0.24151 -1.15478,0.53052 -1.55078,0.89063 C 384.27783,332.01636 384,332.47917 384,333 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.16955 0.0858,-0.36541 0.34766,-0.60352 0.26184,-0.2381 0.68795,-0.48634 1.23632,-0.69726 C 387.68074,331.27738 389.25702,331 391,331 c 1.74298,0 3.31926,0.27738 4.41602,0.69922 0.54837,0.21092 0.97448,0.45916 1.23632,0.69726 C 396.91419,332.63459 397,332.83045 397,333 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.52083 -0.27783,-0.98364 -0.67383,-1.34375 -0.396,-0.36011 -0.92287,-0.64912 -1.55078,-0.89063 C 394.51957,330.28261 392.84692,330 391,330 Z"
+ id="path23061-5"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g transform="translate(-348,477.99999)" style="display:inline;fill:#ffffff;enable-background:new" id="g16413-1">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 759.5,-89 a 0.50005,0.50005 0 0 0 -0.41406,0.220703 l -5.75,8.5 a 0.50005,0.50005 0 0 0 -0.0254,0.04102 C 753.09798,-79.847634 753,-79.420118 753,-79 c 0,1.217423 0.89627,2.23231 2.16602,2.916016 C 756.43576,-75.400278 758.13235,-75 760,-75 c 1.86765,0 3.56424,-0.400278 4.83398,-1.083984 C 766.10373,-76.76769 767,-77.782577 767,-79 c 0,-0.419749 -0.0968,-0.847195 -0.3125,-1.240234 a 0.50005,0.50005 0 0 0 -0.0234,-0.03906 l -5.75,-8.5 A 0.50005,0.50005 0 0 0 760.5,-89 Z m 0.26562,1 h 0.46876 l 5.58007,8.248047 C 765.94193,-79.51674 766,-79.268361 766,-79 c 0,0.715577 -0.55782,1.452112 -1.64062,2.035156 C 763.27657,-76.3818 761.72215,-76 760,-76 c -1.72215,0 -3.27657,-0.3818 -4.35938,-0.964844 C 754.55782,-77.547888 754,-78.284423 754,-79 c 0,-0.262685 0.0617,-0.522361 0.1875,-0.755859 z" id="path22956-5" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 760,-82 c -1.85842,0 -3.5402,0.34854 -4.79688,0.898438 -0.62833,0.274948 -1.15274,0.599804 -1.54296,0.982421 C 753.26993,-79.736524 753,-79.270893 753,-78.75 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.169742 0.0937,-0.393844 0.36133,-0.65625 0.26762,-0.262406 0.69425,-0.539532 1.24219,-0.779297 C 756.69939,-80.665077 758.26862,-81 760,-81 c 1.73138,0 3.30061,0.334923 4.39648,0.814453 0.54794,0.239765 0.97457,0.516891 1.24219,0.779297 C 765.90629,-79.143844 766,-78.919742 766,-78.75 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.520893 -0.26993,-0.986524 -0.66016,-1.369141 -0.39022,-0.382617 -0.91463,-0.707473 -1.54296,-0.982421 C 763.5402,-81.65146 761.85842,-82 760,-82 Z" id="path23072-3" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(147)" inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="g12973-3-2" style="display:inline;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 178.49219,368 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 l -2,2 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 178,369.70703 v 7.58594 l -3,3 V 378.5 A 0.50005,0.50005 0 0 0 174.49219,377.99219 0.50005,0.50005 0 0 0 174,378.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 1 0 0,-1 h -1.79297 l 3,-3 h 7.58594 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2,-2 a 0.50005,0.50005 0 0 0 0,-0.70704 l -2,-2 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 186.29297,377 H 179 v -7.29297 l 1.14648,1.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -2,-2 A 0.50005,0.50005 0 0 0 178.49219,368 Z" transform="translate(-147)" id="path12965-4-0" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g16957-2" transform="rotate(90,380.00189,176.00657)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path id="path16949-6" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 479,347 c -1.09865,0 -1.99999,0.90135 -2,2 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 -10e-6,-1.09865 -0.90135,-2 -2,-2 z m 0,1 c 0.55821,0 1,0.44179 1,1 0,0.55821 -0.44179,1 -1,1 -0.55821,0 -1,-0.44179 -1,-1 0,-0.55821 0.44179,-1 1,-1 z m 0.5,9 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m -10,-11 c -0.82251,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.67749,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.82251 -0.67749,-1.5 -1.5,-1.5 z m 0,1 c 0.28207,0 0.5,0.21793 0.5,0.5 0,0.28207 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28207 0.21793,-0.5 0.5,-0.5 z m 0,8 c -1.37478,0 -2.5,1.12522 -2.5,2.5 0,1.37478 1.12522,2.5 2.5,2.5 1.37478,0 2.5,-1.12522 2.5,-2.5 0,-1.37478 -1.12522,-2.5 -2.5,-2.5 z m 0,1 c 0.83434,0 1.5,0.66566 1.5,1.5 0,0.83434 -0.66566,1.5 -1.5,1.5 -0.83434,0 -1.5,-0.66566 -1.5,-1.5 0,-0.83434 0.66566,-1.5 1.5,-1.5 z" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 469.49219,348.99219 A 0.50005,0.50005 0 0 0 469,349.5 v 5 a 0.50005,0.50005 0 1 0 1,0 v -5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 7.99804,1.0039 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -5,5 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 5,-5 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z M 473.5,358 a 0.50005,0.50005 0 1 0 0,1 h 5 a 0.50005,0.50005 0 1 0 0,-1 z" id="path16955-3" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g15967">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 244,561 c -1.65093,0 -3,1.34907 -3,3 0,1.65093 1.34907,3 3,3 1.65093,0 3,-1.34907 3,-3 0,-1.65093 -1.34907,-3 -3,-3 z" id="path17035" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 243.92383,557 c -0.2146,0.003 -0.42883,0.0151 -0.64063,0.0371 -2.54151,0.26418 -4.8299,1.914 -5.80664,4.42187 -1.30231,3.34383 0.14236,7.14072 3.33789,8.77344 3.19554,1.63272 7.11991,0.57913 9.06641,-2.43554 a 0.50005,0.50005 0 1 0 -0.83984,-0.54297 c -1.67274,2.59068 -5.02539,3.49293 -7.77149,2.08984 -2.7461,-1.40309 -3.98048,-4.64795 -2.86133,-7.52148 1.11915,-2.87354 4.22361,-4.42733 7.19532,-3.60352 a 0.50036742,0.50036742 0 1 0 0.26562,-0.96484 c -0.64839,-0.17975 -1.3015,-0.26149 -1.94531,-0.25391 z M 249,557 c -1.09865,0 -2,0.90135 -2,2 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 0,-1.09865 -0.90135,-2 -2,-2 z" id="path17037" inkscape:connector-curvature="0"/>
- </g>
- <g transform="rotate(90,243.5,333.5)" id="g12586" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 469.5,356 c -1.37478,0 -2.5,1.12522 -2.5,2.5 0,1.37478 1.12522,2.5 2.5,2.5 1.37478,0 2.5,-1.12522 2.5,-2.5 0,-1.37478 -1.12522,-2.5 -2.5,-2.5 z" id="path12572" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- <g id="g23031" style="opacity:0.7;fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 218.5,557 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.64684 0.42097,1.19777 1,1.40625 V 564.5 c -0.01,0.67616 1.01,0.67616 1,0 v -4.59375 c 0.57903,-0.20848 1,-0.75941 1,-1.40625 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 9.5,0 c -1.09865,0 -2,0.90135 -2,2 0,0.36859 0.10883,0.71022 0.28516,1.00781 l -5.13868,5.13867 c -0.49023,0.47127 0.23577,1.19727 0.70704,0.70704 l 5.13867,-5.13868 C 227.28978,560.89117 227.63141,561 228,561 c 1.09865,-10e-6 2,-0.90135 2,-2 0,-1.09865 -0.90135,-1.99999 -2,-2 z m 0.5,10 c -0.64684,0 -1.19777,0.42097 -1.40625,1 H 222.5 c -0.67616,-0.01 -0.67616,1.01 0,1 h 4.59375 c 0.20848,0.57903 0.75941,1 1.40625,1 0.82251,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.67749,-1.5 -1.5,-1.5 z" transform="matrix(0,-1,-1,0,1038,577)" id="path12578" inkscape:connector-curvature="0"/>
+ <g
+ transform="translate(-348,477.99999)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g16413-1">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 759.5,-89 a 0.50005,0.50005 0 0 0 -0.41406,0.220703 l -5.75,8.5 a 0.50005,0.50005 0 0 0 -0.0254,0.04102 C 753.09798,-79.847634 753,-79.420118 753,-79 c 0,1.217423 0.89627,2.23231 2.16602,2.916016 C 756.43576,-75.400278 758.13235,-75 760,-75 c 1.86765,0 3.56424,-0.400278 4.83398,-1.083984 C 766.10373,-76.76769 767,-77.782577 767,-79 c 0,-0.419749 -0.0968,-0.847195 -0.3125,-1.240234 a 0.50005,0.50005 0 0 0 -0.0234,-0.03906 l -5.75,-8.5 A 0.50005,0.50005 0 0 0 760.5,-89 Z m 0.26562,1 h 0.46876 l 5.58007,8.248047 C 765.94193,-79.51674 766,-79.268361 766,-79 c 0,0.715577 -0.55782,1.452112 -1.64062,2.035156 C 763.27657,-76.3818 761.72215,-76 760,-76 c -1.72215,0 -3.27657,-0.3818 -4.35938,-0.964844 C 754.55782,-77.547888 754,-78.284423 754,-79 c 0,-0.262685 0.0617,-0.522361 0.1875,-0.755859 z"
+ id="path22956-5"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 760,-82 c -1.85842,0 -3.5402,0.34854 -4.79688,0.898438 -0.62833,0.274948 -1.15274,0.599804 -1.54296,0.982421 C 753.26993,-79.736524 753,-79.270893 753,-78.75 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.169742 0.0937,-0.393844 0.36133,-0.65625 0.26762,-0.262406 0.69425,-0.539532 1.24219,-0.779297 C 756.69939,-80.665077 758.26862,-81 760,-81 c 1.73138,0 3.30061,0.334923 4.39648,0.814453 0.54794,0.239765 0.97457,0.516891 1.24219,0.779297 C 765.90629,-79.143844 766,-78.919742 766,-78.75 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.520893 -0.26993,-0.986524 -0.66016,-1.369141 -0.39022,-0.382617 -0.91463,-0.707473 -1.54296,-0.982421 C 763.5402,-81.65146 761.85842,-82 760,-82 Z"
+ id="path23072-3"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(147)"
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ id="g12973-3-2"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 178.49219,368 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 l -2,2 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 178,369.70703 v 7.58594 l -3,3 V 378.5 A 0.50005,0.50005 0 0 0 174.49219,377.99219 0.50005,0.50005 0 0 0 174,378.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 1 0 0,-1 h -1.79297 l 3,-3 h 7.58594 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2,-2 a 0.50005,0.50005 0 0 0 0,-0.70704 l -2,-2 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 186.29297,377 H 179 v -7.29297 l 1.14648,1.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -2,-2 A 0.50005,0.50005 0 0 0 178.49219,368 Z"
+ transform="translate(-147)"
+ id="path12965-4-0"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g16957-2"
+ transform="rotate(90,380.00189,176.00657)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ id="path16949-6"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 479,347 c -1.09865,0 -1.99999,0.90135 -2,2 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 -10e-6,-1.09865 -0.90135,-2 -2,-2 z m 0,1 c 0.55821,0 1,0.44179 1,1 0,0.55821 -0.44179,1 -1,1 -0.55821,0 -1,-0.44179 -1,-1 0,-0.55821 0.44179,-1 1,-1 z m 0.5,9 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m -10,-11 c -0.82251,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.67749,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.82251 -0.67749,-1.5 -1.5,-1.5 z m 0,1 c 0.28207,0 0.5,0.21793 0.5,0.5 0,0.28207 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28207 0.21793,-0.5 0.5,-0.5 z m 0,8 c -1.37478,0 -2.5,1.12522 -2.5,2.5 0,1.37478 1.12522,2.5 2.5,2.5 1.37478,0 2.5,-1.12522 2.5,-2.5 0,-1.37478 -1.12522,-2.5 -2.5,-2.5 z m 0,1 c 0.83434,0 1.5,0.66566 1.5,1.5 0,0.83434 -0.66566,1.5 -1.5,1.5 -0.83434,0 -1.5,-0.66566 -1.5,-1.5 0,-0.83434 0.66566,-1.5 1.5,-1.5 z"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 469.49219,348.99219 A 0.50005,0.50005 0 0 0 469,349.5 v 5 a 0.50005,0.50005 0 1 0 1,0 v -5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 7.99804,1.0039 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -5,5 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 5,-5 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z M 473.5,358 a 0.50005,0.50005 0 1 0 0,1 h 5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path16955-3"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g15967">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 244,561 c -1.65093,0 -3,1.34907 -3,3 0,1.65093 1.34907,3 3,3 1.65093,0 3,-1.34907 3,-3 0,-1.65093 -1.34907,-3 -3,-3 z"
+ id="path17035"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 243.92383,557 c -0.2146,0.003 -0.42883,0.0151 -0.64063,0.0371 -2.54151,0.26418 -4.8299,1.914 -5.80664,4.42187 -1.30231,3.34383 0.14236,7.14072 3.33789,8.77344 3.19554,1.63272 7.11991,0.57913 9.06641,-2.43554 a 0.50005,0.50005 0 1 0 -0.83984,-0.54297 c -1.67274,2.59068 -5.02539,3.49293 -7.77149,2.08984 -2.7461,-1.40309 -3.98048,-4.64795 -2.86133,-7.52148 1.11915,-2.87354 4.22361,-4.42733 7.19532,-3.60352 a 0.50036742,0.50036742 0 1 0 0.26562,-0.96484 c -0.64839,-0.17975 -1.3015,-0.26149 -1.94531,-0.25391 z M 249,557 c -1.09865,0 -2,0.90135 -2,2 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 0,-1.09865 -0.90135,-2 -2,-2 z"
+ id="path17037"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="rotate(90,243.5,333.5)"
+ id="g12586"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 469.5,356 c -1.37478,0 -2.5,1.12522 -2.5,2.5 0,1.37478 1.12522,2.5 2.5,2.5 1.37478,0 2.5,-1.12522 2.5,-2.5 0,-1.37478 -1.12522,-2.5 -2.5,-2.5 z"
+ id="path12572"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <g
+ id="g23031"
+ style="opacity:0.7;fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 218.5,557 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.64684 0.42097,1.19777 1,1.40625 V 564.5 c -0.01,0.67616 1.01,0.67616 1,0 v -4.59375 c 0.57903,-0.20848 1,-0.75941 1,-1.40625 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 9.5,0 c -1.09865,0 -2,0.90135 -2,2 0,0.36859 0.10883,0.71022 0.28516,1.00781 l -5.13868,5.13867 c -0.49023,0.47127 0.23577,1.19727 0.70704,0.70704 l 5.13867,-5.13868 C 227.28978,560.89117 227.63141,561 228,561 c 1.09865,-10e-6 2,-0.90135 2,-2 0,-1.09865 -0.90135,-1.99999 -2,-2 z m 0.5,10 c -0.64684,0 -1.19777,0.42097 -1.40625,1 H 222.5 c -0.67616,-0.01 -0.67616,1.01 0,1 h 4.59375 c 0.20848,0.57903 0.75941,1 1.40625,1 0.82251,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.67749,-1.5 -1.5,-1.5 z"
+ transform="matrix(0,-1,-1,0,1038,577)"
+ id="path12578"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g transform="translate(-21.00225)" style="display:inline;fill:#ffffff;stroke:#ffffff;enable-background:new" id="g13169-8-6" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999964;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 469.49414,55.992188 A 0.50004982,0.50004982 0 0 0 469.00195,56.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z m 2,1 A 0.50004982,0.50004982 0 0 0 471.00195,57.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z m 2,1 A 0.50004982,0.50004982 0 0 0 473.00195,58.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z m 2,1 A 0.50004982,0.50004982 0 0 0 475.00195,59.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z" id="path13150-5-2" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.9;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999964;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 471.49609,54.992188 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 v 0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 v -0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 1.99805,1 A 0.50004982,0.50004982 0 0 0 477.00195,58.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z" id="path13154-7-3" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999964;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 473.49609,53.992188 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 v 0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 v -0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 1.99805,1 A 0.50004982,0.50004982 0 0 0 479.00195,57.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z" id="path13161-0-0" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999964;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 475.49609,52.992188 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 v 0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 v -0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 1.99805,1 A 0.50004982,0.50004982 0 0 0 481.00195,56.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z" id="path13163-4-8" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 535.5,494 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 1 c 2e-5,0.1326 0.0527,0.25976 0.14648,0.35352 L 536,496.70703 v 2.61524 l -4.38672,5.36132 -0.004,0.004 c -0.58889,0.7361 -0.70787,1.57018 -0.44922,2.2168 0.25864,0.64662 0.88151,1.0957 1.58984,1.0957 h 10.5 c 0.70833,0 1.33692,-0.44332 1.60352,-1.0918 0.26614,-0.64736 0.14367,-1.48967 -0.4668,-2.22461 L 540,499.32227 v -2.61524 l 0.85352,-0.85351 c 0.0938,-0.0938 0.14646,-0.22092 0.14648,-0.35352 v -1 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 4 v 0.29297 l -0.85352,0.85351 c -0.0938,0.0938 -0.14646,0.22092 -0.14648,0.35352 v 3 c 1.3e-4,0.11538 0.0402,0.22717 0.11328,0.31641 l 4.5,5.5 c 6.6e-4,10e-4 9.5e-4,0.003 0.002,0.004 0.42848,0.51418 0.43133,0.91996 0.3125,1.20899 C 543.80886,506.81822 543.54167,507 543.25,507 h -10.5 c -0.29167,0 -0.5438,-0.17592 -0.66016,-0.4668 -0.11635,-0.29088 -0.11033,-0.7068 0.30078,-1.2207 l 4.4961,-5.49609 c 0.0731,-0.0892 0.11315,-0.20103 0.11328,-0.31641 v -3 c -2e-5,-0.1326 -0.0527,-0.25976 -0.14648,-0.35352 L 536,495.29297 Z m 0,8 c -0.14428,-3.9e-4 -0.2817,0.0616 -0.37695,0.16992 l -1.75,2 c -0.28426,0.32357 -0.0537,0.83118 0.37695,0.83008 h 7.5 c 0.43069,10e-4 0.66121,-0.50651 0.37695,-0.83008 l -1.75,-2 C 540.2817,503.06155 540.14428,502.99961 540,503 Z" id="path13700" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g16377" transform="translate(-217,44.000001)">
- <path id="path16340" d="m 589,450 c -1.09935,0 -2,0.90065 -2,2 v 0.42969 c 0.73665,0.57364 1.18952,1.45204 1.23438,2.41601 C 588.47082,454.9447 588.72885,455 589,455 h 1 c 1.09935,0 2,-0.90065 2,-2 v -1 c 0,-1.09935 -0.90065,-2 -2,-2 z m 2.58789,6.00586 c -0.28431,-0.0492 -0.58776,0.16015 -0.58789,0.49414 0,0.25 -0.25,0.5 -0.5,0.5 h -2 c -0.25,0 -0.5,-0.25 -0.5,-0.5 v 0.5 c 0,0.36306 -0.26134,0.68419 -0.44336,0.93555 l 0.004,0.004 c 0.41161,0.41161 0.88215,0.75715 1.375,1.25 0.40738,0.40739 0.86402,1.03976 1.01172,1.81055 H 593.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 459 c 0,-0.66667 -0.3572,-1.18923 -0.77148,-1.60352 -0.41429,-0.41428 -0.90447,-0.77946 -1.375,-1.25 -0.0788,-0.0787 -0.17086,-0.12422 -0.26563,-0.14062 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0" sodipodi:nodetypes="ssccsssssscccccccsccccsccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 584,453 c -1.09935,0 -2,0.90065 -2,2 v 1 c 0,1.09935 0.90065,2 2,2 h 1 c 1.09935,0 2,-0.90065 2,-2 v -1 c 0,-1.09935 -0.90065,-2 -2,-2 z m -1.51562,6 c -0.12717,0.004 -0.248,0.0564 -0.3379,0.14648 -0.47053,0.47054 -0.96071,0.83572 -1.375,1.25 C 580.3572,460.81077 580,461.33333 580,462 v 1.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 8 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 462 c 0,-0.66667 -0.3572,-1.18923 -0.77148,-1.60352 -0.41429,-0.41428 -0.90447,-0.77946 -1.375,-1.25 -0.32034,-0.32057 -0.86773,-0.0838 -0.85352,0.36914 8.5e-4,0.0269 -0.0479,0.18374 -0.16406,0.30274 C 585.71981,459.93736 585.56612,460 585.5,460 h -2 c -0.0803,0 -0.22193,-0.0571 -0.33203,-0.16797 -0.1101,-0.11083 -0.16786,-0.25596 -0.16797,-0.33203 1.1e-4,-0.28235 -0.23341,-0.50879 -0.51562,-0.5 z" id="path16332" inkscape:connector-curvature="0" sodipodi:nodetypes="ssssssssscccsccccsccccssccc"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 450.32227,452.0625 C 448.61213,452.13527 447,453.5463 447,456 c 0,2.05278 1.07076,4.01178 2.38672,5.71289 1.31595,1.70111 2.90024,3.15481 4.03125,4.16016 A 0.50005,0.50005 0 0 0 453.75,466 h 0.5 a 0.50005,0.50005 0 0 0 0.33203,-0.12695 c 1.13101,-1.00535 2.7153,-2.45905 4.03125,-4.16016 C 459.92924,460.01178 461,458.05278 461,456 c 0,-2.4537 -1.61213,-3.86473 -3.32227,-3.9375 -1.52139,-0.0647 -3.0532,0.927 -3.67773,2.69727 -0.62453,-1.77027 -2.15634,-2.76201 -3.67773,-2.69727 z m 0.043,1 c 1.22737,-0.0522 2.55838,0.74689 2.89258,2.5293 A 0.50005,0.50005 0 0 0 453.75,456 h 0.5 a 0.50005,0.50005 0 0 0 0.49219,-0.4082 c 0.3342,-1.78241 1.66521,-2.58153 2.89258,-2.5293 C 458.86213,453.1147 460,453.9537 460,456 c 0,1.69722 -0.92924,3.48822 -2.17578,5.09961 -1.20727,1.56061 -2.67447,2.91135 -3.7832,3.90039 h -0.082 c -1.10873,-0.98904 -2.57593,-2.33978 -3.7832,-3.90039 C 448.92924,459.48822 448,457.69722 448,456 c 0,-2.0463 1.13787,-2.88527 2.36523,-2.9375 z" id="path6081" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 471.32227,452.0625 C 469.61213,452.13527 468,453.5463 468,456 c 0,1.29326 0.43161,2.55298 1.07227,3.72852 0.16015,0.29312 0.55714,0.34983 0.79296,0.11328 l 3.63477,-3.63477 1.64648,1.64649 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 2.64648,-2.64649 2.48242,2.48242 c 0.27743,0.27645 0.75058,0.14111 0.83985,-0.24023 C 481.93311,456.97518 482,456.49157 482,456 c 0,-2.4537 -1.61213,-3.86473 -3.32227,-3.9375 -1.52139,-0.0647 -3.0532,0.927 -3.67773,2.69727 -0.62453,-1.77027 -2.15634,-2.76201 -3.67773,-2.69727 z M 478.49219,458 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -2.64648,2.64649 -1.64648,-1.64649 c -0.19527,-0.19519 -0.51177,-0.19519 -0.70704,0 l -2.34765,2.34766 c -0.18257,0.18194 -0.19694,0.47283 -0.0332,0.67188 1.2321,1.49847 2.62304,2.79208 3.65235,3.70703 0.0914,0.0816 0.20953,0.12673 0.33202,0.12695 h 0.5 c 0.12249,-2.2e-4 0.24064,-0.0454 0.33203,-0.12695 1.41546,-1.2582 3.54029,-3.21344 4.96094,-5.48828 0.12374,-0.19754 0.0946,-0.45438 -0.0703,-0.61915 l -1.61914,-1.61914 c -0.0957,-0.0957 -0.22604,-0.14856 -0.36134,-0.14648 z" id="path6086" inkscape:connector-curvature="0" sodipodi:nodetypes="csccccccccscccccccccccccccccc"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g16467" transform="translate(-221.99998,478)">
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g12626-8" transform="translate(726.00003,-499.00001)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 30.492188,367.99219 A 0.50005,0.50005 0 0 0 30,368.5 v 9.79297 l -2.853516,2.85351 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 30.707031,379 H 40.5 a 0.50005,0.50005 0 1 0 0,-1 H 31 v -9.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z" id="path12205-4" inkscape:connector-curvature="0"/>
+ <g
+ transform="translate(-21.00225)"
+ style="display:inline;fill:#ffffff;stroke:#ffffff;enable-background:new"
+ id="g13169-8-6"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999964;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 469.49414,55.992188 A 0.50004982,0.50004982 0 0 0 469.00195,56.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z m 2,1 A 0.50004982,0.50004982 0 0 0 471.00195,57.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z m 2,1 A 0.50004982,0.50004982 0 0 0 473.00195,58.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z m 2,1 A 0.50004982,0.50004982 0 0 0 475.00195,59.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z"
+ id="path13150-5-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.9;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999964;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 471.49609,54.992188 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 v 0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 v -0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 1.99805,1 A 0.50004982,0.50004982 0 0 0 477.00195,58.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z"
+ id="path13154-7-3"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999964;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 473.49609,53.992188 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 v 0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 v -0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 1.99805,1 A 0.50004982,0.50004982 0 0 0 479.00195,57.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z"
+ id="path13161-0-0"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999964;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 475.49609,52.992188 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 v 0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 v -0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 1.99805,1 A 0.50004982,0.50004982 0 0 0 481.00195,56.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z"
+ id="path13163-4-8"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 535.5,494 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 1 c 2e-5,0.1326 0.0527,0.25976 0.14648,0.35352 L 536,496.70703 v 2.61524 l -4.38672,5.36132 -0.004,0.004 c -0.58889,0.7361 -0.70787,1.57018 -0.44922,2.2168 0.25864,0.64662 0.88151,1.0957 1.58984,1.0957 h 10.5 c 0.70833,0 1.33692,-0.44332 1.60352,-1.0918 0.26614,-0.64736 0.14367,-1.48967 -0.4668,-2.22461 L 540,499.32227 v -2.61524 l 0.85352,-0.85351 c 0.0938,-0.0938 0.14646,-0.22092 0.14648,-0.35352 v -1 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 4 v 0.29297 l -0.85352,0.85351 c -0.0938,0.0938 -0.14646,0.22092 -0.14648,0.35352 v 3 c 1.3e-4,0.11538 0.0402,0.22717 0.11328,0.31641 l 4.5,5.5 c 6.6e-4,10e-4 9.5e-4,0.003 0.002,0.004 0.42848,0.51418 0.43133,0.91996 0.3125,1.20899 C 543.80886,506.81822 543.54167,507 543.25,507 h -10.5 c -0.29167,0 -0.5438,-0.17592 -0.66016,-0.4668 -0.11635,-0.29088 -0.11033,-0.7068 0.30078,-1.2207 l 4.4961,-5.49609 c 0.0731,-0.0892 0.11315,-0.20103 0.11328,-0.31641 v -3 c -2e-5,-0.1326 -0.0527,-0.25976 -0.14648,-0.35352 L 536,495.29297 Z m 0,8 c -0.14428,-3.9e-4 -0.2817,0.0616 -0.37695,0.16992 l -1.75,2 c -0.28426,0.32357 -0.0537,0.83118 0.37695,0.83008 h 7.5 c 0.43069,10e-4 0.66121,-0.50651 0.37695,-0.83008 l -1.75,-2 C 540.2817,503.06155 540.14428,502.99961 540,503 Z"
+ id="path13700"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g16377"
+ transform="translate(-217,44.000001)">
+ <path
+ id="path16340"
+ d="m 589,450 c -1.09935,0 -2,0.90065 -2,2 v 0.42969 c 0.73665,0.57364 1.18952,1.45204 1.23438,2.41601 C 588.47082,454.9447 588.72885,455 589,455 h 1 c 1.09935,0 2,-0.90065 2,-2 v -1 c 0,-1.09935 -0.90065,-2 -2,-2 z m 2.58789,6.00586 c -0.28431,-0.0492 -0.58776,0.16015 -0.58789,0.49414 0,0.25 -0.25,0.5 -0.5,0.5 h -2 c -0.25,0 -0.5,-0.25 -0.5,-0.5 v 0.5 c 0,0.36306 -0.26134,0.68419 -0.44336,0.93555 l 0.004,0.004 c 0.41161,0.41161 0.88215,0.75715 1.375,1.25 0.40738,0.40739 0.86402,1.03976 1.01172,1.81055 H 593.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 459 c 0,-0.66667 -0.3572,-1.18923 -0.77148,-1.60352 -0.41429,-0.41428 -0.90447,-0.77946 -1.375,-1.25 -0.0788,-0.0787 -0.17086,-0.12422 -0.26563,-0.14062 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ssccsssssscccccccsccccsccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 584,453 c -1.09935,0 -2,0.90065 -2,2 v 1 c 0,1.09935 0.90065,2 2,2 h 1 c 1.09935,0 2,-0.90065 2,-2 v -1 c 0,-1.09935 -0.90065,-2 -2,-2 z m -1.51562,6 c -0.12717,0.004 -0.248,0.0564 -0.3379,0.14648 -0.47053,0.47054 -0.96071,0.83572 -1.375,1.25 C 580.3572,460.81077 580,461.33333 580,462 v 1.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 8 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 462 c 0,-0.66667 -0.3572,-1.18923 -0.77148,-1.60352 -0.41429,-0.41428 -0.90447,-0.77946 -1.375,-1.25 -0.32034,-0.32057 -0.86773,-0.0838 -0.85352,0.36914 8.5e-4,0.0269 -0.0479,0.18374 -0.16406,0.30274 C 585.71981,459.93736 585.56612,460 585.5,460 h -2 c -0.0803,0 -0.22193,-0.0571 -0.33203,-0.16797 -0.1101,-0.11083 -0.16786,-0.25596 -0.16797,-0.33203 1.1e-4,-0.28235 -0.23341,-0.50879 -0.51562,-0.5 z"
+ id="path16332"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ssssssssscccsccccsccccssccc" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 450.32227,452.0625 C 448.61213,452.13527 447,453.5463 447,456 c 0,2.05278 1.07076,4.01178 2.38672,5.71289 1.31595,1.70111 2.90024,3.15481 4.03125,4.16016 A 0.50005,0.50005 0 0 0 453.75,466 h 0.5 a 0.50005,0.50005 0 0 0 0.33203,-0.12695 c 1.13101,-1.00535 2.7153,-2.45905 4.03125,-4.16016 C 459.92924,460.01178 461,458.05278 461,456 c 0,-2.4537 -1.61213,-3.86473 -3.32227,-3.9375 -1.52139,-0.0647 -3.0532,0.927 -3.67773,2.69727 -0.62453,-1.77027 -2.15634,-2.76201 -3.67773,-2.69727 z m 0.043,1 c 1.22737,-0.0522 2.55838,0.74689 2.89258,2.5293 A 0.50005,0.50005 0 0 0 453.75,456 h 0.5 a 0.50005,0.50005 0 0 0 0.49219,-0.4082 c 0.3342,-1.78241 1.66521,-2.58153 2.89258,-2.5293 C 458.86213,453.1147 460,453.9537 460,456 c 0,1.69722 -0.92924,3.48822 -2.17578,5.09961 -1.20727,1.56061 -2.67447,2.91135 -3.7832,3.90039 h -0.082 c -1.10873,-0.98904 -2.57593,-2.33978 -3.7832,-3.90039 C 448.92924,459.48822 448,457.69722 448,456 c 0,-2.0463 1.13787,-2.88527 2.36523,-2.9375 z"
+ id="path6081"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 471.32227,452.0625 C 469.61213,452.13527 468,453.5463 468,456 c 0,1.29326 0.43161,2.55298 1.07227,3.72852 0.16015,0.29312 0.55714,0.34983 0.79296,0.11328 l 3.63477,-3.63477 1.64648,1.64649 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 2.64648,-2.64649 2.48242,2.48242 c 0.27743,0.27645 0.75058,0.14111 0.83985,-0.24023 C 481.93311,456.97518 482,456.49157 482,456 c 0,-2.4537 -1.61213,-3.86473 -3.32227,-3.9375 -1.52139,-0.0647 -3.0532,0.927 -3.67773,2.69727 -0.62453,-1.77027 -2.15634,-2.76201 -3.67773,-2.69727 z M 478.49219,458 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -2.64648,2.64649 -1.64648,-1.64649 c -0.19527,-0.19519 -0.51177,-0.19519 -0.70704,0 l -2.34765,2.34766 c -0.18257,0.18194 -0.19694,0.47283 -0.0332,0.67188 1.2321,1.49847 2.62304,2.79208 3.65235,3.70703 0.0914,0.0816 0.20953,0.12673 0.33202,0.12695 h 0.5 c 0.12249,-2.2e-4 0.24064,-0.0454 0.33203,-0.12695 1.41546,-1.2582 3.54029,-3.21344 4.96094,-5.48828 0.12374,-0.19754 0.0946,-0.45438 -0.0703,-0.61915 l -1.61914,-1.61914 c -0.0957,-0.0957 -0.22604,-0.14856 -0.36134,-0.14648 z"
+ id="path6086"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csccccccccscccccccccccccccccc" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g16467"
+ transform="translate(-221.99998,478)">
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12626-8"
+ transform="translate(726.00003,-499.00001)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 30.492188,367.99219 A 0.50005,0.50005 0 0 0 30,368.5 v 9.79297 l -2.853516,2.85351 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 30.707031,379 H 40.5 a 0.50005,0.50005 0 1 0 0,-1 H 31 v -9.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z"
+ id="path12205-4"
+ inkscape:connector-curvature="0" />
</g>
- <g transform="matrix(-1,0,0,1,1420,227.99979)" id="g8805-9" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 653.5,-359 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 8 0.5 h 1 v -0.5 -7.5 h 7.5 0.5 v -1 h -0.5 z" id="path8743-5" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 542,349 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m -3.48047,2.05078 c -0.16946,-0.008 -0.32881,0.0808 -0.41211,0.22852 l -2.25,4 c -0.17018,0.3004 0.0473,0.67264 0.39258,0.67187 h 4.5 c 0.34528,7.7e-4 0.56276,-0.37147 0.39258,-0.67187 l -2.25,-4 c -0.0765,-0.13552 -0.21755,-0.22152 -0.37305,-0.22852 z" transform="matrix(-1,0,0,1,1198,-705.99979)" id="path8759-7" inkscape:connector-curvature="0"/>
+ <g
+ transform="matrix(-1,0,0,1,1420,227.99979)"
+ id="g8805-9"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 653.5,-359 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 8 0.5 h 1 v -0.5 -7.5 h 7.5 0.5 v -1 h -0.5 z"
+ id="path8743-5"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 542,349 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m -3.48047,2.05078 c -0.16946,-0.008 -0.32881,0.0808 -0.41211,0.22852 l -2.25,4 c -0.17018,0.3004 0.0473,0.67264 0.39258,0.67187 h 4.5 c 0.34528,7.7e-4 0.56276,-0.37147 0.39258,-0.67187 l -2.25,-4 c -0.0765,-0.13552 -0.21755,-0.22152 -0.37305,-0.22852 z"
+ transform="matrix(-1,0,0,1,1198,-705.99979)"
+ id="path8759-7"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g16449" transform="translate(-284.99998,478)">
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g15951-6-3" transform="translate(746.99995,-478)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 27.5,347 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3.5 h 1 v -3 h 3 v -1 z m 9.5,0 v 1 h 3 v 3 h 1 v -3.5 A 0.50005,0.50005 0 0 0 40.5,347 Z m -10,10 v 3.5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 31 v -1 h -3 v -3 z m 13,0 v 3 h -3 v 1 h 3.5 A 0.50005,0.50005 0 0 0 41,360.5 V 357 Z" id="path15947-7-2" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g16449"
+ transform="translate(-284.99998,478)">
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g15951-6-3"
+ transform="translate(746.99995,-478)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 27.5,347 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3.5 h 1 v -3 h 3 v -1 z m 9.5,0 v 1 h 3 v 3 h 1 v -3.5 A 0.50005,0.50005 0 0 0 40.5,347 Z m -10,10 v 3.5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 31 v -1 h -3 v -3 z m 13,0 v 3 h -3 v 1 h 3.5 A 0.50005,0.50005 0 0 0 41,360.5 V 357 Z"
+ id="path15947-7-2"
+ inkscape:connector-curvature="0" />
</g>
- <g transform="matrix(-1,0,0,1,1439,229.99979)" id="g8805-98" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 653.5,-359 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 8 v 8 h -8 z" id="path8743-9" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 656,-357 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m 3.50391,1 c -0.18479,-10e-4 -0.35529,0.0993 -0.44336,0.26172 l -3,5.5 c -0.1805,0.33311 0.0606,0.73812 0.43945,0.73828 h 5.75 c 0.37101,-3.7e-4 0.61244,-0.39044 0.44727,-0.72266 l -2.75,-5.5 c -0.0838,-0.16852 -0.25516,-0.2757 -0.44336,-0.27734 z" id="circle8761-3" inkscape:connector-curvature="0" sodipodi:nodetypes="ssssscccccccc"/>
+ <g
+ transform="matrix(-1,0,0,1,1439,229.99979)"
+ id="g8805-98"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 653.5,-359 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 8 v 8 h -8 z"
+ id="path8743-9"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 656,-357 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m 3.50391,1 c -0.18479,-10e-4 -0.35529,0.0993 -0.44336,0.26172 l -3,5.5 c -0.1805,0.33311 0.0606,0.73812 0.43945,0.73828 h 5.75 c 0.37101,-3.7e-4 0.61244,-0.39044 0.44727,-0.72266 l -2.75,-5.5 c -0.0838,-0.16852 -0.25516,-0.2757 -0.44336,-0.27734 z"
+ id="circle8761-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ssssscccccccc" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g16457" transform="translate(-284.99998,478)">
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="g7406-1-2-5" transform="translate(347.99997,-290.00356)" style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
- <path id="path7416-1-8-5" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 453,170 v 2 h -2.5 a 0.50005,0.50005 0 1 0 0,1 h 2.91992 a 0.50005,0.50005 0 0 0 0.16211,0 h 0.83789 a 0.50005,0.50005 0 0 0 0.16211,0 H 457.5 a 0.50005,0.50005 0 1 0 0,-1 H 455 v -2 z m -5.5,-11 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 8 h -12 z" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g16457"
+ transform="translate(-284.99998,478)">
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ id="g7406-1-2-5"
+ transform="translate(347.99997,-290.00356)"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
+ <path
+ id="path7416-1-8-5"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 453,170 v 2 h -2.5 a 0.50005,0.50005 0 1 0 0,1 h 2.91992 a 0.50005,0.50005 0 0 0 0.16211,0 h 0.83789 a 0.50005,0.50005 0 0 0 0.16211,0 H 457.5 a 0.50005,0.50005 0 1 0 0,-1 H 455 v -2 z m -5.5,-11 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 8 h -12 z"
+ inkscape:connector-curvature="0" />
</g>
- <g style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" id="g16437" transform="matrix(-1,0,0,1,1460,227.99979)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 520,349 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m -4.50391,1.05078 c -0.16882,0.001 -0.32263,0.0972 -0.39843,0.24805 l -2.75,5.5 c -0.15067,0.29943 0.0671,0.65258 0.40234,0.65234 h 5.75 c 0.34173,-2.4e-4 0.55851,-0.36622 0.39453,-0.66601 l -3,-5.5 c -0.0795,-0.14558 -0.23258,-0.23538 -0.39844,-0.23438 z" transform="matrix(-1,0,0,1,1175,-705.99979)" id="path16433" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
+ id="g16437"
+ transform="matrix(-1,0,0,1,1460,227.99979)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 520,349 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m -4.50391,1.05078 c -0.16882,0.001 -0.32263,0.0972 -0.39843,0.24805 l -2.75,5.5 c -0.15067,0.29943 0.0671,0.65258 0.40234,0.65234 h 5.75 c 0.34173,-2.4e-4 0.55851,-0.36622 0.39453,-0.66601 l -3,-5.5 c -0.0795,-0.14558 -0.23258,-0.23538 -0.39844,-0.23438 z"
+ transform="matrix(-1,0,0,1,1175,-705.99979)"
+ id="path16433"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g transform="translate(-189,-42.000004)" style="display:inline;fill:#ffffff;enable-background:new" id="g17809-9">
- <g id="g17552-8" transform="matrix(-1,0,0,1,508.00011,-7e-5)" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 201.49219,94.998047 a 0.50005,0.50005 0 0 0 -0.38867,0.195312 0.50005,0.50005 0 0 0 -0.006,0.0059 l -3.95118,3.953125 a 0.50005,0.50005 0 1 0 0.70704,0.707031 L 201,96.712891 v 8.792969 a 0.50005,0.50005 0 1 0 1,0 v -8.792969 l 3.14648,3.146484 a 0.50005,0.50005 0 1 0 0.70704,-0.707031 l -3.95508,-3.955078 a 0.50005,0.50005 0 0 0 -0.40625,-0.199219 z" id="path14327-2" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 195.49219,104.99219 A 0.50005,0.50005 0 0 0 195,105.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 12 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 1 0 -1,0 v 2.5 h -11 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" id="rect17542-1" inkscape:connector-curvature="0"/>
+ <g
+ transform="translate(-189,-42.000004)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g17809-9">
+ <g
+ id="g17552-8"
+ transform="matrix(-1,0,0,1,508.00011,-7e-5)"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 201.49219,94.998047 a 0.50005,0.50005 0 0 0 -0.38867,0.195312 0.50005,0.50005 0 0 0 -0.006,0.0059 l -3.95118,3.953125 a 0.50005,0.50005 0 1 0 0.70704,0.707031 L 201,96.712891 v 8.792969 a 0.50005,0.50005 0 1 0 1,0 v -8.792969 l 3.14648,3.146484 a 0.50005,0.50005 0 1 0 0.70704,-0.707031 l -3.95508,-3.955078 a 0.50005,0.50005 0 0 0 -0.40625,-0.199219 z"
+ id="path14327-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 195.49219,104.99219 A 0.50005,0.50005 0 0 0 195,105.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 12 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 1 0 -1,0 v 2.5 h -11 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="rect17542-1"
+ inkscape:connector-curvature="0" />
</g>
- <g id="g17548-0" transform="matrix(-1,0,0,1,508.00011,-7e-5)" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 222.49219,95.005859 A 0.50005,0.50005 0 0 0 222,95.511719 v 8.792971 l -3.14648,-3.14649 a 0.50005,0.50005 0 1 0 -0.70704,0.70703 l 3.95704,3.95704 a 0.50005,0.50005 0 0 0 0.79296,0.002 0.50005,0.50005 0 0 0 0.004,-0.006 l 3.95313,-3.95313 a 0.50005,0.50005 0 1 0 -0.70704,-0.70703 L 223,104.30469 v -8.792971 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z" id="path14329-2" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 216.49219,104.99219 A 0.50005,0.50005 0 0 0 216,105.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 12 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 1 0 -1,0 v 2.5 h -11 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" id="path17546-9" inkscape:connector-curvature="0"/>
+ <g
+ id="g17548-0"
+ transform="matrix(-1,0,0,1,508.00011,-7e-5)"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 222.49219,95.005859 A 0.50005,0.50005 0 0 0 222,95.511719 v 8.792971 l -3.14648,-3.14649 a 0.50005,0.50005 0 1 0 -0.70704,0.70703 l 3.95704,3.95704 a 0.50005,0.50005 0 0 0 0.79296,0.002 0.50005,0.50005 0 0 0 0.004,-0.006 l 3.95313,-3.95313 a 0.50005,0.50005 0 1 0 -0.70704,-0.70703 L 223,104.30469 v -8.792971 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z"
+ id="path14329-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 216.49219,104.99219 A 0.50005,0.50005 0 0 0 216,105.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 12 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 1 0 -1,0 v 2.5 h -11 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path17546-9"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g id="g6601" style="fill:#ffffff">
- <path style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 61.503909,123 c 0,3.59202 -2.911894,6.50391 -6.503906,6.50391 -3.592012,0 -6.503906,-2.91189 -6.503906,-6.50391 0,-3.59201 2.911894,-6.5039 6.503906,-6.5039 3.592012,0 6.503906,2.91189 6.503906,6.5039 z" id="path6589" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 54.999998,115.99609 c -3.862225,0 -7.003902,3.14168 -7.003906,7.00391 -2e-6,3.86223 3.141676,7.00391 7.003906,7.00391 3.86223,0 7.003908,-3.14168 7.003906,-7.00391 -4e-6,-3.86223 -3.141681,-7.00391 -7.003906,-7.00391 z m 0,1 c 3.321786,0 6.003903,2.68212 6.003906,6.00391 2e-6,3.32179 -2.682117,6.00391 -6.003906,6.00391 -3.321789,0 -6.003908,-2.68212 -6.003906,-6.00391 3e-6,-3.32179 2.68212,-6.00391 6.003906,-6.00391 z" id="path10735" inkscape:connector-curvature="0"/>
- </g>
- <g id="g8734" transform="translate(231.99999,-418.99995)" style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 388.48047,74 c -0.15153,0.004 -0.29304,0.07659 -0.38477,0.197266 l -3.94922,3.949218 C 383.83169,78.461484 384.05468,78.99983 384.5,79 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 75 h 8 v 12 h -12 v -7 h -1 v 7.5 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 h 13 c 0.27613,-2.8e-5 0.49997,-0.223869 0.5,-0.5 v -13 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 h -9 c -0.005,-6.2e-5 -0.009,-6.2e-5 -0.0137,0 -6.7e-4,1.8e-5 -0.001,-2.1e-5 -0.002,0 -0.001,4.1e-5 -0.003,-5e-5 -0.004,0 z" transform="translate(-231.99999,418.99995)" id="path8730" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccc"/>
- </g>
- <g transform="translate(-1.9999991e-6)" id="g13408" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g id="g12509" transform="translate(336.99999,-439.99995)" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 156.48438,493 c -0.12717,0.004 -0.248,0.0564 -0.3379,0.14648 l -4,4 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c 1.1e-4,-0.28235 -0.23341,-0.50879 -0.51562,-0.5 z" id="path12507" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccc"/>
+ <g
+ id="g6601"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 61.503909,123 c 0,3.59202 -2.911894,6.50391 -6.503906,6.50391 -3.592012,0 -6.503906,-2.91189 -6.503906,-6.50391 0,-3.59201 2.911894,-6.5039 6.503906,-6.5039 3.592012,0 6.503906,2.91189 6.503906,6.5039 z"
+ id="path6589"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 54.999998,115.99609 c -3.862225,0 -7.003902,3.14168 -7.003906,7.00391 -2e-6,3.86223 3.141676,7.00391 7.003906,7.00391 3.86223,0 7.003908,-3.14168 7.003906,-7.00391 -4e-6,-3.86223 -3.141681,-7.00391 -7.003906,-7.00391 z m 0,1 c 3.321786,0 6.003903,2.68212 6.003906,6.00391 2e-6,3.32179 -2.682117,6.00391 -6.003906,6.00391 -3.321789,0 -6.003908,-2.68212 -6.003906,-6.00391 3e-6,-3.32179 2.68212,-6.00391 6.003906,-6.00391 z"
+ id="path10735"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g8734"
+ transform="translate(231.99999,-418.99995)"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 158.48048,492.99995 c -0.15153,0.004 -0.29304,0.0766 -0.38477,0.19727 l -4.94922,4.94921 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4.5 h 5 v 12 h -10 v -6 h -1 v 6.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 11 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -13 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -6 c -0.005,-6e-5 -0.009,-6e-5 -0.0137,0 -6.7e-4,2e-5 -0.001,-2e-5 -0.002,0 -0.001,4e-5 -0.003,-5e-5 -0.004,0 z"
+ id="path8730"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccc" />
+ </g>
+ <path
+ id="path20685"
+ d="m 447.49219,73.99409 c -0.27615,0.0043 -0.49651,0.231666 -0.49219,0.507812 V 87.49409 c -0.005,0.338081 0.24757,0.509435 0.5,0.507812 l 0.5,-0.0039 v -1.996094 h 2 v 1.996094 h 8 v -1.996094 h 2 v 1.996094 h 0.5 c 0.25244,0 0.50478,-0.169732 0.5,-0.507812 V 74.501902 c 0.005,-0.338081 -0.24762,-0.509415 -0.5,-0.507812 l -0.5,0.0039 v 2.003906 h -2 V 73.99799 h -8 v 2.003906 h -2 V 73.99799 Z M 448,77.001902 h 2 v 2 h -2 z m 10,0 h 2 v 2 h -2 z m -5.52344,1.003906 c 0.1005,-0.004 0.20016,0.02317 0.28516,0.07617 l 4,2.5 c 0.3129,0.1959 0.3129,0.651757 0,0.847657 l -4,2.5 c -0.3331,0.2087 -0.76573,-0.03073 -0.76563,-0.423829 v -5 c -2e-4,-0.2687 0.21197,-0.489 0.48047,-0.5 z M 448,80.001902 h 2 v 2 h -2 z m 10,0 h 2 v 2 h -2 z m -10,3 h 2 v 1.992188 h -2 z m 10,0 h 2 v 1.992188 h -2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g18316"
+ transform="translate(21,-62.999962)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 496,305 c -3.86007,0 -7,3.13993 -7,7 0,3.86007 3.13993,7 7,7 3.86007,0 7,-3.13993 7,-7 0,-3.86007 -3.13993,-7 -7,-7 z m 0,1 c 3.31963,0 6,2.68037 6,6 0,3.31963 -2.68037,6 -6,6 -3.31963,0 -6,-2.68037 -6,-6 0,-3.31963 2.68037,-6 6,-6 z"
+ id="circle17690"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 496.49219,306.99219 A 0.50005,0.50005 0 0 0 496,307.5 v 5 a 0.50005,0.50005 0 0 0 0.22266,0.41602 l 3,2 a 0.50005,0.50005 0 1 0 0.55468,-0.83204 L 497,312.23242 V 307.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path17692"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 491.5,312 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path17694"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.9;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 492.74414,308.24414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 1.75,1.75 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.75,-1.75 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path17696"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g18539-5"
+ transform="translate(-699.95,-1104.9501)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1240.9492,1334.9492 v 5 h 4 v -5 z"
+ id="path18533-4"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1236.6992,1327.9531 v 1 h 2.25 c 0.4241,0 0.7403,0.2467 0.8828,0.5762 0.1425,0.3295 0.1253,0.7107 -0.2422,1.0781 l -4,4 c -0.6325,0.6326 -0.7433,1.5055 -0.4492,2.1778 0.2941,0.6722 0.9778,1.1757 1.8028,1.1757 l 3.0059,-0.012 v -1 l -3.0058,0.012 c -0.425,0 -0.7434,-0.2484 -0.8868,-0.5761 -0.1434,-0.3278 -0.1271,-0.7029 0.2403,-1.0703 l 4,-4 c 0.6326,-0.6326 0.7446,-1.5077 0.4531,-2.1817 -0.2915,-0.674 -0.9748,-1.1797 -1.8008,-1.1797 z"
+ id="path18537-0"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1233.4531,1325.9492 c -0.191,0 -0.3661,0.1064 -0.4511,0.2774 l -2,4 c -0.1651,0.3322 0.076,0.7222 0.4472,0.7226 h 4 c 0.371,-4e-4 0.6124,-0.3904 0.4473,-0.7226 l -2,-4 c -0.084,-0.1686 -0.2552,-0.2758 -0.4434,-0.2774 z"
+ id="path18541-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
+ </g>
+ <g
+ transform="matrix(-1,0,0,1,1727,-80)"
+ id="g17779"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1455.5,512 c -0.2761,3e-5 -0.5,0.22387 -0.5,0.5 v 2 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 11 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 v -2 c 0,-0.27613 -0.2239,-0.49997 -0.5,-0.5 z m 0.5,4 v 6.5 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 9 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 V 516 Z m 4,1 h 2 c 1.3523,-0.0191 1.3523,2.01913 0,2 h -2 c -1.3523,0.0191 -1.3523,-2.01913 0,-2 z"
+ id="path17776"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cssccsscccsccsccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1468,514 v 0.5 c 0,0.62337 -0.4468,1.06807 -1,1.28906 V 516 v 1 h 1.5 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 v -2 c 0,-0.27613 -0.2239,-0.49997 -0.5,-0.5 z m -1,4 v 4.5 c 0,0.8167 -0.6835,1.49991 -1.5,1.5 h -7.5 v 0.5 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 9 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 V 518 Z"
+ id="path17787"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csccccsscccsccsccscc" />
+ </g>
+ <g
+ transform="translate(-1.8554137e-6,5.18e-5)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13451"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ id="g23046"
+ style="opacity:1;fill:#ffffff">
+ <path
+ style="opacity:0.98999999;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ d="m 16.501953,536 c -1.926262,0 -3.498047,1.57178 -3.498047,3.49805 0,1.92626 1.571785,3.49804 3.498047,3.49804 C 18.428216,542.99609 20,541.42431 20,539.49805 20,537.57178 18.428216,536 16.501953,536 Z m 0,0.99609 a 0.50005,0.50005 0 1 1 0,1 C 15.666793,537.99609 15,538.66288 15,539.49805 a 0.50005,0.50005 0 1 1 -1,0 c 0,-1.37561 1.126353,-2.50196 2.501953,-2.50196 z"
+ transform="translate(1.8554137e-6,-5.18e-5)"
+ id="circle12697"
+ inkscape:connector-curvature="0" />
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 502.49219,52.992188 A 0.50005,0.50005 0 0 0 502.41797,53 H 501.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.919922 a 0.50005,0.50005 0 0 0 -0.11328,-0.404297 0.50005,0.50005 0 0 0 -0.002,-0.0039 0.50005,0.50005 0 0 0 -0.0312,-0.0332 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.0332,-0.03125 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.32031,-0.111328 z M 495.5,53 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3.99219,2.992188 A 0.50005,0.50005 0 0 0 502,56.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 0,3 A 0.50005,0.50005 0 0 0 502,59.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m -13,0.0078 A 0.50005,0.50005 0 0 0 489,59.507812 V 60.5 a 0.50005,0.50005 0 1 0 1,0 V 59.507812 A 0.50005,0.50005 0 0 0 489.49219,59 Z m 0,2.992188 A 0.50005,0.50005 0 0 0 489,62.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 13,0 A 0.50005,0.50005 0 0 0 502,62.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m -13,3 A 0.50005,0.50005 0 0 0 489,65.5 v 0.919922 a 0.50005,0.50005 0 0 0 0.11328,0.404297 0.50005,0.50005 0 0 0 0.0156,0.01953 0.50005,0.50005 0 0 0 0.0176,0.01758 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.03125 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 489.58203,67 H 490.5 a 0.50005,0.50005 0 1 0 0,-1 H 490 v -0.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 13,0 A 0.50005,0.50005 0 0 0 502,65.5 V 66 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.91992 a 0.50005,0.50005 0 0 0 0.4043,-0.113281 0.50005,0.50005 0 0 0 0.004,-0.002 0.50005,0.50005 0 0 0 0.0332,-0.03125 0.50005,0.50005 0 0 0 0.002,-0.0039 0.50005,0.50005 0 0 0 0.0312,-0.0332 0.50005,0.50005 0 0 0 0.002,-0.0039 A 0.50005,0.50005 0 0 0 503,66.417969 V 65.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z M 492.5,66 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z" id="path9066-1" inkscape:connector-curvature="0"/>
- </g>
- <path id="path20685" d="m 447.49219,73.99409 c -0.27615,0.0043 -0.49651,0.231666 -0.49219,0.507812 V 87.49409 c -0.005,0.338081 0.24757,0.509435 0.5,0.507812 l 0.5,-0.0039 v -1.996094 h 2 v 1.996094 h 8 v -1.996094 h 2 v 1.996094 h 0.5 c 0.25244,0 0.50478,-0.169732 0.5,-0.507812 V 74.501902 c 0.005,-0.338081 -0.24762,-0.509415 -0.5,-0.507812 l -0.5,0.0039 v 2.003906 h -2 V 73.99799 h -8 v 2.003906 h -2 V 73.99799 Z M 448,77.001902 h 2 v 2 h -2 z m 10,0 h 2 v 2 h -2 z m -5.52344,1.003906 c 0.1005,-0.004 0.20016,0.02317 0.28516,0.07617 l 4,2.5 c 0.3129,0.1959 0.3129,0.651757 0,0.847657 l -4,2.5 c -0.3331,0.2087 -0.76573,-0.03073 -0.76563,-0.423829 v -5 c -2e-4,-0.2687 0.21197,-0.489 0.48047,-0.5 z M 448,80.001902 h 2 v 2 h -2 z m 10,0 h 2 v 2 h -2 z m -10,3 h 2 v 1.992188 h -2 z m 10,0 h 2 v 1.992188 h -2 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g18316" transform="translate(21,-62.999962)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 496,305 c -3.86007,0 -7,3.13993 -7,7 0,3.86007 3.13993,7 7,7 3.86007,0 7,-3.13993 7,-7 0,-3.86007 -3.13993,-7 -7,-7 z m 0,1 c 3.31963,0 6,2.68037 6,6 0,3.31963 -2.68037,6 -6,6 -3.31963,0 -6,-2.68037 -6,-6 0,-3.31963 2.68037,-6 6,-6 z" id="circle17690" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 496.49219,306.99219 A 0.50005,0.50005 0 0 0 496,307.5 v 5 a 0.50005,0.50005 0 0 0 0.22266,0.41602 l 3,2 a 0.50005,0.50005 0 1 0 0.55468,-0.83204 L 497,312.23242 V 307.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" id="path17692" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 491.5,312 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z" id="path17694" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.9;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 492.74414,308.24414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 1.75,1.75 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.75,-1.75 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z" id="path17696" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g18539-5" transform="translate(-699.95,-1104.9501)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1240.9492,1334.9492 v 5 h 4 v -5 z" id="path18533-4" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1236.6992,1327.9531 v 1 h 2.25 c 0.4241,0 0.7403,0.2467 0.8828,0.5762 0.1425,0.3295 0.1253,0.7107 -0.2422,1.0781 l -4,4 c -0.6325,0.6326 -0.7433,1.5055 -0.4492,2.1778 0.2941,0.6722 0.9778,1.1757 1.8028,1.1757 l 3.0059,-0.012 v -1 l -3.0058,0.012 c -0.425,0 -0.7434,-0.2484 -0.8868,-0.5761 -0.1434,-0.3278 -0.1271,-0.7029 0.2403,-1.0703 l 4,-4 c 0.6326,-0.6326 0.7446,-1.5077 0.4531,-2.1817 -0.2915,-0.674 -0.9748,-1.1797 -1.8008,-1.1797 z" id="path18537-0" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1233.4531,1325.9492 c -0.191,0 -0.3661,0.1064 -0.4511,0.2774 l -2,4 c -0.1651,0.3322 0.076,0.7222 0.4472,0.7226 h 4 c 0.371,-4e-4 0.6124,-0.3904 0.4473,-0.7226 l -2,-4 c -0.084,-0.1686 -0.2552,-0.2758 -0.4434,-0.2774 z" id="path18541-3" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccc"/>
- </g>
- <g transform="matrix(-1,0,0,1,1727,-80)" id="g17779" style="display:inline;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 1455.5,512 c -0.2761,3e-5 -0.5,0.22387 -0.5,0.5 v 2 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 11 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 v -2 c 0,-0.27613 -0.2239,-0.49997 -0.5,-0.5 z m 0.5,4 v 6.5 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 9 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 V 516 Z m 4,1 h 2 c 1.3523,-0.0191 1.3523,2.01913 0,2 h -2 c -1.3523,0.0191 -1.3523,-2.01913 0,-2 z" id="path17776" inkscape:connector-curvature="0" sodipodi:nodetypes="cssccsscccsccsccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 1468,514 v 0.5 c 0,0.62337 -0.4468,1.06807 -1,1.28906 V 516 v 1 h 1.5 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 v -2 c 0,-0.27613 -0.2239,-0.49997 -0.5,-0.5 z m -1,4 v 4.5 c 0,0.8167 -0.6835,1.49991 -1.5,1.5 h -7.5 v 0.5 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 9 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 V 518 Z" id="path17787" inkscape:connector-curvature="0" sodipodi:nodetypes="csccccsscccsccsccscc"/>
- </g>
- <g transform="translate(-1.8554137e-6,5.18e-5)" style="display:inline;fill:#ffffff;enable-background:new" id="g13451" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g id="g23046" style="opacity:1;fill:#ffffff">
- <path style="opacity:0.98999999;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" d="m 16.501953,536 c -1.926262,0 -3.498047,1.57178 -3.498047,3.49805 0,1.92626 1.571785,3.49804 3.498047,3.49804 C 18.428216,542.99609 20,541.42431 20,539.49805 20,537.57178 18.428216,536 16.501953,536 Z m 0,0.99609 a 0.50005,0.50005 0 1 1 0,1 C 15.666793,537.99609 15,538.66288 15,539.49805 a 0.50005,0.50005 0 1 1 -1,0 c 0,-1.37561 1.126353,-2.50196 2.501953,-2.50196 z" transform="translate(1.8554137e-6,-5.18e-5)" id="circle12697" inkscape:connector-curvature="0"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 10.503906,539.99219 a 0.50005,0.50005 0 0 0 -0.492187,0.39843 L 9.6542969,542 H 7.5 a 0.50005,0.50005 0 1 0 0,1 H 9.4316406 L 8.765625,546 H 6.5 a 0.50005,0.50005 0 1 0 0,1 h 2.0429688 l -0.53125,2.39062 a 0.50038237,0.50038237 0 1 0 0.9765624,0.21876 L 9.5683594,547 H 16.53125 l 0.476562,2.58984 a 0.50032015,0.50032015 0 1 0 0.984376,-0.17968 L 17.546875,547 H 19.5 a 0.50005,0.50005 0 1 0 0,-1 H 17.363281 L 17.0625,544.37109 a 0.50005,0.50005 0 1 0 -0.982422,0.18164 L 16.345703,546 H 9.7910156 l 0.6660154,-3 H 12.5 a 0.50005,0.50005 0 1 0 0,-1 h -1.820312 l 0.308593,-1.39062 a 0.50005,0.50005 0 0 0 -0.484375,-0.61719 z"
+ id="path8399"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13993"
+ transform="translate(-21.000002,-20.999948)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 132.5,557 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -8 a 0.50005,0.50005 0 1 0 -1,0 v 7.5 h -12 v -12 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path13936"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccsssssssssssssccc"
+ inkscape:connector-curvature="0"
+ id="path12191-1"
+ d="m 136.5,557 c -0.25,0 -0.5,0.25 -0.5,0.5 v 5.5 c 0,0.5 0.25,1 1,1 0.75,0 1,-0.5 1,-1 v -1 c 0,-0.5 0.53412,-1 1,-1 0.55229,0 1,0.44772 1,1 v 3.5 c 0,0.82843 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67157 1.5,-1.5 V 562 c 0,-0.55228 0.44772,-1 1,-1 h 0.5 c 0.85547,0 1.5,-0.66406 1.5,-1.5 v -2 c 0,-0.25 -0.25,-0.5 -0.5,-0.5 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(-1141.0001,-747.9999)"
+ id="g17971-7">
+ <g
+ style="fill:#ffffff"
+ transform="translate(62,59)"
+ id="g17967-7">
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1085.5,1514 c -0.2761,0 -0.5,0.2239 -0.5,0.5 v 13 c 0,0.2761 0.2239,0.5 0.5,0.5 h 0.5 v -2 h 1 v 2 h 9.5 c 0.2761,0 0.5,-0.2239 0.5,-0.5 v -13 c 0,-0.2761 -0.2239,-0.5 -0.5,-0.5 h -9.5 v 2 h -1 v -2 z m 3.5,2 h 6 v 1 h -6 z m -3,1 h 1 v 2 h -1 z m 3,1 h 6 v 1 h -6 z m -3,2 h 1 v 2 h -1 z m 3,0 h 6 v 1 h -6 z m 0,2 h 4 v 1 h -4 z m -3,1 h 1 v 2 h -1 z"
+ transform="translate(169,-289)"
+ id="path17960-2" />
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 10.503906,539.99219 a 0.50005,0.50005 0 0 0 -0.492187,0.39843 L 9.6542969,542 H 7.5 a 0.50005,0.50005 0 1 0 0,1 H 9.4316406 L 8.765625,546 H 6.5 a 0.50005,0.50005 0 1 0 0,1 h 2.0429688 l -0.53125,2.39062 a 0.50038237,0.50038237 0 1 0 0.9765624,0.21876 L 9.5683594,547 H 16.53125 l 0.476562,2.58984 a 0.50032015,0.50032015 0 1 0 0.984376,-0.17968 L 17.546875,547 H 19.5 a 0.50005,0.50005 0 1 0 0,-1 H 17.363281 L 17.0625,544.37109 a 0.50005,0.50005 0 1 0 -0.982422,0.18164 L 16.345703,546 H 9.7910156 l 0.6660154,-3 H 12.5 a 0.50005,0.50005 0 1 0 0,-1 h -1.820312 l 0.308593,-1.39062 a 0.50005,0.50005 0 0 0 -0.484375,-0.61719 z" id="path8399" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g13993" transform="translate(-21.000002,-20.999948)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 132.5,557 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -8 a 0.50005,0.50005 0 1 0 -1,0 v 7.5 h -12 v -12 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 z" id="path13936" inkscape:connector-curvature="0"/>
- <path sodipodi:nodetypes="ccsssssssssssssccc" inkscape:connector-curvature="0" id="path12191-1" d="m 136.5,557 c -0.25,0 -0.5,0.25 -0.5,0.5 v 5.5 c 0,0.5 0.25,1 1,1 0.75,0 1,-0.5 1,-1 v -1 c 0,-0.5 0.53412,-1 1,-1 0.55229,0 1,0.44772 1,1 v 3.5 c 0,0.82843 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67157 1.5,-1.5 V 562 c 0,-0.55228 0.44772,-1 1,-1 h 0.5 c 0.85547,0 1.5,-0.66406 1.5,-1.5 v -2 c 0,-0.25 -0.25,-0.5 -0.5,-0.5 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"/>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" transform="translate(-1141.0001,-747.9999)" id="g17971-7">
- <g style="fill:#ffffff" transform="translate(62,59)" id="g17967-7">
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1085.5,1514 c -0.2761,0 -0.5,0.2239 -0.5,0.5 v 13 c 0,0.2761 0.2239,0.5 0.5,0.5 h 0.5 v -2 h 1 v 2 h 9.5 c 0.2761,0 0.5,-0.2239 0.5,-0.5 v -13 c 0,-0.2761 -0.2239,-0.5 -0.5,-0.5 h -9.5 v 2 h -1 v -2 z m 3.5,2 h 6 v 1 h -6 z m -3,1 h 1 v 2 h -1 z m 3,1 h 6 v 1 h -6 z m -3,2 h 1 v 2 h -1 z m 3,0 h 6 v 1 h -6 z m 0,2 h 4 v 1 h -4 z m -3,1 h 1 v 2 h -1 z" transform="translate(169,-289)" id="path17960-2"/>
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 134.49999,536.00009 c -1.3764,0 -2.5,1.1236 -2.5,2.5 v 7 c 0,1.3764 1.1236,2.5 2.5,2.5 h 0.5 v 2.5 c -8e-4,0.4686 0.5855,0.6809 0.8848,0.3203 l 2.3496,-2.8203 h 5.2656 c 1.3764,0 2.5,-1.1236 2.5,-2.5 v -7 c 0,-1.3764 -1.1236,-2.5 -2.5,-2.5 z m 3.5,2 h 2 v 2 h -2 z m -1,3 h 3 v 4 h 1 v 1 h -4 v -1 h 1 v -3 h -1 z"
+ id="path17991-2" />
+ <g
+ transform="matrix(1,0,0,-1,-167.9929,1043.9931)"
+ id="g17666-2"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ transform="rotate(90,475.00001,500.9999)"
+ inkscape:transform-center-y="9.9999999e-006"
+ inkscape:transform-center-x="-1.2499"
+ id="g17664-3"
+ style="fill:#ffffff" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path17674"
+ d="m 475.00071,508.00091 c -3.8601,0 -7,-3.1399 -7,-7 0,-3.8601 3.1399,-7 7,-7 3.8601,0 7,3.1399 7,7 0,3.8601 -3.1399,7 -7,7 z m 2.96094,-1.99804 a 1.0001,1.0001 0 0 0 1.04102,-0.98633 1.0001,1.0001 0 0 0 -0.20899,-0.62305 l -2.57617,-3.43555 1.60742,-2.41015 a 1.0001,1.0001 0 1 0 -1.66406,-1.10938 l -1.91211,2.86914 a 1.0001,1.0001 0 0 0 -0.26367,0.68164 1.0001,1.0001 0 0 0 0.004,0.0801 1.0001,1.0001 0 0 0 0.30664,0.66016 l 2.89844,3.86328 a 1.0001,1.0001 0 0 0 0.76758,0.41016 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ id="g7662"
+ style="fill:#ffffff"
+ transform="matrix(1,0,0,-1,0,1085.9844)">
+ <path
+ inkscape:connector-curvature="0"
+ id="path17742-5"
+ d="m 468.50781,535.99219 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 5.00586 l -1,-0.006 v 2 l 1,0.006 V 546 h -1.00586 l 0.006,-2.00781 h -2 L 478.00195,546 h -2 l 0.006,-2.00781 h -2 L 474.00195,546 h -2 l 0.006,-2.00781 h -2 L 470.00195,546 h -0.99414 v -2.00391 l 1,-0.006 v -2 l -1,0.006 z m 3,7 h 2 v -2 h -2 z m 4,0 h 2 v -2 h -2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" />
+ <path
+ id="path17758-8"
+ d="m 470.00781,539.99219 v 2 h 2 v -2 z m 4,0 v 2 h 2 v -2 z m 4,0 v 2 h 2 v -2 z"
+ style="display:inline;opacity:0.8;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g15578-7"
+ transform="matrix(1,0,0,-1,894.00002,921)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -467.5,287 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 10 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2.5 v -1 h -2 v -9 h 9 v 2 h 1 v -2.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path15572-4"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -463.50002,301 c -0.27613,-3e-5 -0.49997,-0.22387 -0.5,-0.5 v -9 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 h 9 c 0.27613,3e-5 0.49997,0.22387 0.5,0.5 v 4.5 h -1 v -4 h -8 v 8 h 5 v -2.5 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 h 2.5 1 v 0.5 c -2e-5,0.1326 -0.0527,0.25972 -0.14648,0.35352 l -3,3 c -0.0938,0.0938 -0.22092,0.14646 -0.35352,0.14648 z"
+ id="path15574-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccsccc" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g18361">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 447.49414,577.99023 a 0.50005,0.50005 0 0 0 -0.49219,0.50782 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -2.6875 c 1.48423,-2.56389 4.60739,-3.65907 7.36719,-2.58008 2.762,1.07985 4.31643,4.00744 3.66406,6.90039 -0.65237,2.89295 -3.31139,4.87021 -6.26953,4.66016 -2.95814,-0.21006 -5.31375,-2.5439 -5.55078,-5.5 a 0.50005,0.50005 0 1 0 -0.99609,0.0801 c 0.27595,3.44157 3.03067,6.17147 6.47461,6.41602 3.44393,0.24455 6.55885,-2.06751 7.31836,-5.43555 0.7595,-3.36803 -1.05982,-6.79554 -4.27539,-8.05273 -0.8039,-0.3143 -1.63664,-0.46878 -2.45899,-0.47852 -2.43307,-0.0288 -4.77966,1.22272 -6.08594,3.40821 v -2.91797 a 0.50005,0.50005 0 0 0 -0.50781,-0.50782 z m 8.98828,3.00391 a 0.50005,0.50005 0 0 0 -0.38281,0.20508 l -3,4 a 0.50005,0.50005 0 0 0 -0.0156,0.57812 l 2,3 a 0.50005,0.50005 0 1 0 0.83204,-0.55468 l -1.80274,-2.70508 2.78711,-3.7168 a 0.50005,0.50005 0 0 0 0.10352,-0.3125 0.50005,0.50005 0 0 0 -0.52149,-0.49414 z"
+ id="path13619"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="matrix(0,-1,-1,0,954.9999,1060.0001)"
+ inkscape:transform-center-y="9.9999999e-006"
+ inkscape:transform-center-x="-1.2499"
+ id="g16343-6"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ id="path18041"
+ d="m 517.0019,53.000264 c -0.47496,-0.0438 -0.94252,0.0803 -1.30468,0.35742 -0.28815,0.22047 -0.55389,0.56737 -0.6211,1.0332 -0.0672,0.46584 0.11485,1.01133 0.57227,1.46876 l 0.14648,0.14648 h -4.29297 c -0.53506,4e-5 -1.03128,0.28661 -1.29883,0.75 -0.26752,0.46339 -0.26752,1.03661 0,1.5 0.26755,0.46339 0.76375,0.75 1.29883,0.75 h 0.79297 l -2.64648,2.64648 c -0.79091,0.79079 -0.84722,1.93194 -0.29297,2.65625 0.22044,0.28814 0.56748,0.55402 1.0332,0.6211 0.46572,0.0671 1.0091,-0.11342 1.4668,-0.57031 l 1.4043,-1.40235 c 0.55515,1.96585 2.10614,3.53021 4.16406,3.94141 2.37442,0.47444 4.78539,-0.66388 5.92773,-2.79883 1.14235,-2.13495 0.75134,-4.77035 -0.96094,-6.48242 a 0.50005,0.50005 0 0 0 -0.002,-0.004 l -4.0332,-3.96094 c -0.39539,-0.39541 -0.87856,-0.60853 -1.35352,-0.65234 z m -0.0957,1.00195 c 0.24304,0.0198 0.50958,0.1248 0.74219,0.35743 a 0.50005,0.50005 0 0 0 0.004,0.002 l 4.03125,3.96289 c 1.40369,1.40351 1.72164,3.55449 0.78516,5.30469 -0.93648,1.7502 -2.90114,2.678 -4.84766,2.28906 -1.9465,-0.38894 -3.40679,-2.00407 -3.60937,-3.97266 a 0.50005,0.50005 0 0 0 -0.85156,-0.30273 l -2.01172,2.00976 c -0.29296,0.29245 -0.47153,0.30809 -0.61719,0.28711 -0.14566,-0.021 -0.29945,-0.12932 -0.38281,-0.23828 -0.21096,-0.27568 -0.25826,-0.87658 0.20703,-1.34179 l 3.5,-3.5 a 0.50005,0.50005 0 0 0 -0.35352,-0.85352 h -2 c -0.17943,0 -0.34387,-0.0946 -0.43359,-0.25 -0.0897,-0.15539 -0.0897,-0.34461 0,-0.5 0.0897,-0.15539 0.25413,-0.24999 0.43359,-0.25 h 5.5 a 0.50005,0.50005 0 0 0 0.35352,-0.85352 l -1,-1 c -0.29258,-0.29257 -0.31008,-0.47147 -0.28906,-0.61718 0.021,-0.14571 0.13127,-0.29945 0.24023,-0.38282 0.13784,-0.10546 0.35657,-0.17021 0.59961,-0.15039 z m 1.5957,5.00391 c -1.37479,0 -2.5,1.12521 -2.5,2.5 0,1.37479 1.12521,2.5 2.5,2.5 1.37479,0 2.5,-1.12521 2.5,-2.5 0,-1.37479 -1.12521,-2.5 -2.5,-2.5 z m 0,1 c 0.83435,0 1.5,0.66565 1.5,1.5 0,0.83435 -0.66565,1.5 -1.5,1.5 -0.83435,0 -1.5,-0.66565 -1.5,-1.5 0,-0.83435 0.66565,-1.5 1.5,-1.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ id="path14479-6"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 111.51563,74 c -0.27614,2.8e-5 -0.49998,0.223869 -0.5,0.5 v 12 c 2e-5,0.276131 0.22386,0.499972 0.5,0.5 H 114.5 c 0.27613,-2.8e-5 0.49997,-0.223869 0.5,-0.5 v -12 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m 0.5,1 H 114 v 2 h -1.98437 z m 0,3 H 114 v 2 h -1.98437 z m 0,3 H 114 v 2 h -1.98437 z m 0,3 H 114 v 2 h -1.98437 z M 124,81.000005 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m 8,-3 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m 8,-3 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="matrix(-1,0,0,1,1689,365.99979)"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
+ id="g8530-0-8"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1258.4766,-286 c -0.1708,0.008 -0.3255,0.10335 -0.4102,0.25195 l -4,7 c -0.1903,0.33312 0.05,0.74758 0.4336,0.74805 h 8 c 0.3836,-4.7e-4 0.6239,-0.41493 0.4336,-0.74805 l -4,-7 c -0.093,-0.16311 -0.2694,-0.26042 -0.457,-0.25195 z"
+ id="path8523-4-0"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1253.5,-289 c -0.8225,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z"
+ id="ellipse8525-5-4"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 27.5,11 A 0.50005,0.50005 0 0 0 27,11.5 v 10.851562 l 1,-1.75 V 12 h 12 v 12 h -3.099609 c 0.122248,0.339531 0.117057,0.686553 0.0039,1 H 40.5 A 0.50005,0.50005 0 0 0 41,24.5 v -13 A 0.50005,0.50005 0 0 0 40.5,11 Z"
+ transform="matrix(-1,0,0,1,1290,-302.99979)"
+ id="path8528-7-3" />
+ </g>
+ <rect
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ id="rect6696"
+ width="0"
+ height="0"
+ x="-18"
+ y="-28" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 180.25977,430.99023 c -1.56005,0 -2.83737,0.68503 -4,1.32227 -0.15986,0.0876 -0.25939,0.25522 -0.25977,0.4375 v 1.75 c -0.002,0.58015 0.81953,0.69801 0.98047,0.14062 0.5477,-1.86218 2.26129,-2.69946 3.87109,-2.56445 0.056,0.003 0.0879,0.0161 0.14258,0.0195 C 182.58833,432.2915 184,433.38188 184,435.75 V 437 h -4.17383 c -1.71873,0 -2.95078,0.48602 -3.73828,1.26172 -0.7875,0.77569 -1.09766,1.80326 -1.09766,2.77539 0,1.37482 0.63393,2.43409 1.58008,3.07031 C 177.51646,444.74365 178.73744,445 180,445 c 1.61266,0 3.42658,-0.64151 4.45508,-1.56836 0.43191,0.42904 0.80166,0.78819 1.11328,1.03906 0.38759,0.31203 0.75096,0.5293 1.18164,0.5293 h 0.75 c 0.31531,0 0.5,-0.25 0.5,-0.5 0,-0.25 -0.16406,-0.5 -0.5,-0.5 -0.0833,0 -0.22505,-0.0571 -0.33398,-0.16602 C 187.05708,443.72508 187,443.58333 187,443.5 v -7 c 0,-1.04167 -0.0843,-2.5 -1.08398,-3.57617 -1.37045,-1.47528 -2.91602,-1.9336 -5.65625,-1.9336 z M 181.5,438 h 2.5 v 4.49023 c -0.8549,0.62028 -1.60427,0.95721 -2.2793,1.14844 -0.1561,0.0477 -0.30873,0.061 -0.46679,0.0977 -0.63626,0.10402 -1.2211,0.10508 -1.65821,-0.0742 C 178.58677,443.24823 178,442.20833 178,441 c 0,-0.63889 0.21654,-1.3962 0.74414,-1.97656 C 179.27174,438.44308 180.11111,438 181.5,438 Z"
+ id="path7432"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sccccccscccscscssssscsscsscccccsss" />
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="matrix(0.866668,0,0,0.866668,-9.46699,121.39943)"
+ id="g5914"
+ style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.15384436;enable-background:new">
+ <g
+ id="g5912"
+ style="fill:#ffffff;stroke-width:1.15384436">
+ <path
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ d="m 202,494 c -3.86008,0 -7,3.13992 -7,7 0,3.86008 3.13992,7 7,7 3.86008,0 7,-3.13992 7,-7 0,-3.86008 -3.13992,-7 -7,-7 z m 0,1 c 3.3058,0 5.97583,2.65852 5.99805,5.95898 C 206.88654,501.90262 204.99536,503 202,503 v 4 c -3.31963,0 -6,-2.68037 -6,-6 0,-0.0145 0.002,-0.0285 0.002,-0.043 1.1112,0.94401 3.00099,2.043 5.998,2.043 z"
+ transform="matrix(1.1538444,0,0,1.1538444,10.923433,-140.07605)"
+ id="path5908"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 134.49999,536.00009 c -1.3764,0 -2.5,1.1236 -2.5,2.5 v 7 c 0,1.3764 1.1236,2.5 2.5,2.5 h 0.5 v 2.5 c -8e-4,0.4686 0.5855,0.6809 0.8848,0.3203 l 2.3496,-2.8203 h 5.2656 c 1.3764,0 2.5,-1.1236 2.5,-2.5 v -7 c 0,-1.3764 -1.1236,-2.5 -2.5,-2.5 z m 3.5,2 h 2 v 2 h -2 z m -1,3 h 3 v 4 h 1 v 1 h -4 v -1 h 1 v -3 h -1 z" id="path17991-2"/>
- <g transform="matrix(1,0,0,-1,-167.9929,1043.9931)" id="g17666-2" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g transform="rotate(90,475.00001,500.9999)" inkscape:transform-center-y="9.9999999e-006" inkscape:transform-center-x="-1.2499" id="g17664-3" style="fill:#ffffff"/>
- <path inkscape:connector-curvature="0" id="path17674" d="m 475.00071,508.00091 c -3.8601,0 -7,-3.1399 -7,-7 0,-3.8601 3.1399,-7 7,-7 3.8601,0 7,3.1399 7,7 0,3.8601 -3.1399,7 -7,7 z m 2.96094,-1.99804 a 1.0001,1.0001 0 0 0 1.04102,-0.98633 1.0001,1.0001 0 0 0 -0.20899,-0.62305 l -2.57617,-3.43555 1.60742,-2.41015 a 1.0001,1.0001 0 1 0 -1.66406,-1.10938 l -1.91211,2.86914 a 1.0001,1.0001 0 0 0 -0.26367,0.68164 1.0001,1.0001 0 0 0 0.004,0.0801 1.0001,1.0001 0 0 0 0.30664,0.66016 l 2.89844,3.86328 a 1.0001,1.0001 0 0 0 0.76758,0.41016 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g id="g7662" style="fill:#ffffff" transform="matrix(1,0,0,-1,0,1085.9844)">
- <path inkscape:connector-curvature="0" id="path17742-5" d="m 468.50781,535.99219 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 5.00586 l -1,-0.006 v 2 l 1,0.006 V 546 h -1.00586 l 0.006,-2.00781 h -2 L 478.00195,546 h -2 l 0.006,-2.00781 h -2 L 474.00195,546 h -2 l 0.006,-2.00781 h -2 L 470.00195,546 h -0.99414 v -2.00391 l 1,-0.006 v -2 l -1,0.006 z m 3,7 h 2 v -2 h -2 z m 4,0 h 2 v -2 h -2 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"/>
- <path id="path17758-8" d="m 470.00781,539.99219 v 2 h 2 v -2 z m 4,0 v 2 h 2 v -2 z m 4,0 v 2 h 2 v -2 z" style="display:inline;opacity:0.8;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g15578-7" transform="matrix(1,0,0,-1,894.00002,921)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m -467.5,287 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 10 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2.5 v -1 h -2 v -9 h 9 v 2 h 1 v -2.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path15572-4" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m -463.50002,301 c -0.27613,-3e-5 -0.49997,-0.22387 -0.5,-0.5 v -9 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 h 9 c 0.27613,3e-5 0.49997,0.22387 0.5,0.5 v 4.5 h -1 v -4 h -8 v 8 h 5 v -2.5 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 h 2.5 1 v 0.5 c -2e-5,0.1326 -0.0527,0.25972 -0.14648,0.35352 l -3,3 c -0.0938,0.0938 -0.22092,0.14646 -0.35352,0.14648 z" id="path15574-3" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccsccc"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g18361">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 447.49414,577.99023 a 0.50005,0.50005 0 0 0 -0.49219,0.50782 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -2.6875 c 1.48423,-2.56389 4.60739,-3.65907 7.36719,-2.58008 2.762,1.07985 4.31643,4.00744 3.66406,6.90039 -0.65237,2.89295 -3.31139,4.87021 -6.26953,4.66016 -2.95814,-0.21006 -5.31375,-2.5439 -5.55078,-5.5 a 0.50005,0.50005 0 1 0 -0.99609,0.0801 c 0.27595,3.44157 3.03067,6.17147 6.47461,6.41602 3.44393,0.24455 6.55885,-2.06751 7.31836,-5.43555 0.7595,-3.36803 -1.05982,-6.79554 -4.27539,-8.05273 -0.8039,-0.3143 -1.63664,-0.46878 -2.45899,-0.47852 -2.43307,-0.0288 -4.77966,1.22272 -6.08594,3.40821 v -2.91797 a 0.50005,0.50005 0 0 0 -0.50781,-0.50782 z m 8.98828,3.00391 a 0.50005,0.50005 0 0 0 -0.38281,0.20508 l -3,4 a 0.50005,0.50005 0 0 0 -0.0156,0.57812 l 2,3 a 0.50005,0.50005 0 1 0 0.83204,-0.55468 l -1.80274,-2.70508 2.78711,-3.7168 a 0.50005,0.50005 0 0 0 0.10352,-0.3125 0.50005,0.50005 0 0 0 -0.52149,-0.49414 z" id="path13619" inkscape:connector-curvature="0"/>
- <g transform="matrix(0,-1,-1,0,954.9999,1060.0001)" inkscape:transform-center-y="9.9999999e-006" inkscape:transform-center-x="-1.2499" id="g16343-6" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"/>
- </g>
- <path inkscape:connector-curvature="0" id="path18041" d="m 517.0019,53.000264 c -0.47496,-0.0438 -0.94252,0.0803 -1.30468,0.35742 -0.28815,0.22047 -0.55389,0.56737 -0.6211,1.0332 -0.0672,0.46584 0.11485,1.01133 0.57227,1.46876 l 0.14648,0.14648 h -4.29297 c -0.53506,4e-5 -1.03128,0.28661 -1.29883,0.75 -0.26752,0.46339 -0.26752,1.03661 0,1.5 0.26755,0.46339 0.76375,0.75 1.29883,0.75 h 0.79297 l -2.64648,2.64648 c -0.79091,0.79079 -0.84722,1.93194 -0.29297,2.65625 0.22044,0.28814 0.56748,0.55402 1.0332,0.6211 0.46572,0.0671 1.0091,-0.11342 1.4668,-0.57031 l 1.4043,-1.40235 c 0.55515,1.96585 2.10614,3.53021 4.16406,3.94141 2.37442,0.47444 4.78539,-0.66388 5.92773,-2.79883 1.14235,-2.13495 0.75134,-4.77035 -0.96094,-6.48242 a 0.50005,0.50005 0 0 0 -0.002,-0.004 l -4.0332,-3.96094 c -0.39539,-0.39541 -0.87856,-0.60853 -1.35352,-0.65234 z m -0.0957,1.00195 c 0.24304,0.0198 0.50958,0.1248 0.74219,0.35743 a 0.50005,0.50005 0 0 0 0.004,0.002 l 4.03125,3.96289 c 1.40369,1.40351 1.72164,3.55449 0.78516,5.30469 -0.93648,1.7502 -2.90114,2.678 -4.84766,2.28906 -1.9465,-0.38894 -3.40679,-2.00407 -3.60937,-3.97266 a 0.50005,0.50005 0 0 0 -0.85156,-0.30273 l -2.01172,2.00976 c -0.29296,0.29245 -0.47153,0.30809 -0.61719,0.28711 -0.14566,-0.021 -0.29945,-0.12932 -0.38281,-0.23828 -0.21096,-0.27568 -0.25826,-0.87658 0.20703,-1.34179 l 3.5,-3.5 a 0.50005,0.50005 0 0 0 -0.35352,-0.85352 h -2 c -0.17943,0 -0.34387,-0.0946 -0.43359,-0.25 -0.0897,-0.15539 -0.0897,-0.34461 0,-0.5 0.0897,-0.15539 0.25413,-0.24999 0.43359,-0.25 h 5.5 a 0.50005,0.50005 0 0 0 0.35352,-0.85352 l -1,-1 c -0.29258,-0.29257 -0.31008,-0.47147 -0.28906,-0.61718 0.021,-0.14571 0.13127,-0.29945 0.24023,-0.38282 0.13784,-0.10546 0.35657,-0.17021 0.59961,-0.15039 z m 1.5957,5.00391 c -1.37479,0 -2.5,1.12521 -2.5,2.5 0,1.37479 1.12521,2.5 2.5,2.5 1.37479,0 2.5,-1.12521 2.5,-2.5 0,-1.37479 -1.12521,-2.5 -2.5,-2.5 z m 0,1 c 0.83435,0 1.5,0.66565 1.5,1.5 0,0.83435 -0.66565,1.5 -1.5,1.5 -0.83435,0 -1.5,-0.66565 -1.5,-1.5 0,-0.83435 0.66565,-1.5 1.5,-1.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path id="path14479-6" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 111.51563,74 c -0.27614,2.8e-5 -0.49998,0.223869 -0.5,0.5 v 12 c 2e-5,0.276131 0.22386,0.499972 0.5,0.5 H 114.5 c 0.27613,-2.8e-5 0.49997,-0.223869 0.5,-0.5 v -12 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m 0.5,1 H 114 v 2 h -1.98437 z m 0,3 H 114 v 2 h -1.98437 z m 0,3 H 114 v 2 h -1.98437 z m 0,3 H 114 v 2 h -1.98437 z M 124,81.000005 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m 8,-3 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m 8,-3 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z" inkscape:connector-curvature="0"/>
- <g transform="matrix(-1,0,0,1,1689,365.99979)" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" id="g8530-0-8" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1258.4766,-286 c -0.1708,0.008 -0.3255,0.10335 -0.4102,0.25195 l -4,7 c -0.1903,0.33312 0.05,0.74758 0.4336,0.74805 h 8 c 0.3836,-4.7e-4 0.6239,-0.41493 0.4336,-0.74805 l -4,-7 c -0.093,-0.16311 -0.2694,-0.26042 -0.457,-0.25195 z" id="path8523-4-0" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1253.5,-289 c -0.8225,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z" id="ellipse8525-5-4" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 27.5,11 A 0.50005,0.50005 0 0 0 27,11.5 v 10.851562 l 1,-1.75 V 12 h 12 v 12 h -3.099609 c 0.122248,0.339531 0.117057,0.686553 0.0039,1 H 40.5 A 0.50005,0.50005 0 0 0 41,24.5 v -13 A 0.50005,0.50005 0 0 0 40.5,11 Z" transform="matrix(-1,0,0,1,1290,-302.99979)" id="path8528-7-3"/>
- </g>
- <rect style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" id="rect6696" width="0" height="0" x="-18" y="-28"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 180.25977,430.99023 c -1.56005,0 -2.83737,0.68503 -4,1.32227 -0.15986,0.0876 -0.25939,0.25522 -0.25977,0.4375 v 1.75 c -0.002,0.58015 0.81953,0.69801 0.98047,0.14062 0.5477,-1.86218 2.26129,-2.69946 3.87109,-2.56445 0.056,0.003 0.0879,0.0161 0.14258,0.0195 C 182.58833,432.2915 184,433.38188 184,435.75 V 437 h -4.17383 c -1.71873,0 -2.95078,0.48602 -3.73828,1.26172 -0.7875,0.77569 -1.09766,1.80326 -1.09766,2.77539 0,1.37482 0.63393,2.43409 1.58008,3.07031 C 177.51646,444.74365 178.73744,445 180,445 c 1.61266,0 3.42658,-0.64151 4.45508,-1.56836 0.43191,0.42904 0.80166,0.78819 1.11328,1.03906 0.38759,0.31203 0.75096,0.5293 1.18164,0.5293 h 0.75 c 0.31531,0 0.5,-0.25 0.5,-0.5 0,-0.25 -0.16406,-0.5 -0.5,-0.5 -0.0833,0 -0.22505,-0.0571 -0.33398,-0.16602 C 187.05708,443.72508 187,443.58333 187,443.5 v -7 c 0,-1.04167 -0.0843,-2.5 -1.08398,-3.57617 -1.37045,-1.47528 -2.91602,-1.9336 -5.65625,-1.9336 z M 181.5,438 h 2.5 v 4.49023 c -0.8549,0.62028 -1.60427,0.95721 -2.2793,1.14844 -0.1561,0.0477 -0.30873,0.061 -0.46679,0.0977 -0.63626,0.10402 -1.2211,0.10508 -1.65821,-0.0742 C 178.58677,443.24823 178,442.20833 178,441 c 0,-0.63889 0.21654,-1.3962 0.74414,-1.97656 C 179.27174,438.44308 180.11111,438 181.5,438 Z" id="path7432" inkscape:connector-curvature="0" sodipodi:nodetypes="sccccccscccscscssssscsscsscccccsss"/>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" transform="matrix(0.866668,0,0,0.866668,-9.46699,121.39943)" id="g5914" style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.15384436;enable-background:new">
- <g id="g5912" style="fill:#ffffff;stroke-width:1.15384436">
- <path style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" d="m 202,494 c -3.86008,0 -7,3.13992 -7,7 0,3.86008 3.13992,7 7,7 3.86008,0 7,-3.13992 7,-7 0,-3.86008 -3.13992,-7 -7,-7 z m 0,1 c 3.3058,0 5.97583,2.65852 5.99805,5.95898 C 206.88654,501.90262 204.99536,503 202,503 v 4 c -3.31963,0 -6,-2.68037 -6,-6 0,-0.0145 0.002,-0.0285 0.002,-0.043 1.1112,0.94401 3.00099,2.043 5.998,2.043 z" transform="matrix(1.1538444,0,0,1.1538444,10.923433,-140.07605)" id="path5908" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g5920"
+ transform="translate(168,-62.999995)">
+ <path
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ id="path5916"
+ d="m 49,558 v 3 h 3 v -3 z m 3,3 v 3 h 3 v -3 z m 3,0 h 3 v -3 h -3 z m 3,0 v 3 h 3 v -3 z m 0,3 h -3 v 3 h 3 z m 0,3 v 3 h 3 v -3 z m -3,0 h -3 v 3 h 3 z m -3,0 v -3 h -3 v 3 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path5918"
+ d="m 48.5,557 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 61.5,557 Z m 0.5,1 h 12 v 12 H 49 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ transform="translate(420.00505,-159.00506)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g5937">
+ <path
+ id="path5935"
+ transform="translate(-462.00505,96.005057)"
+ d="m 103.49609,556.99023 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1.57031,1.57032 c -1.22858,-1.06562 -2.825838,-1.7168 -4.576171,-1.7168 -3.86007,0 -7,3.13993 -7,7 0,1.75033 0.649231,3.34954 1.714844,4.57813 l -1.568359,1.56835 a 0.50005,0.50005 0 1 0 0.707031,0.70704 l 1.568359,-1.56836 c 1.228585,1.06561 2.827793,1.71484 4.578125,1.71484 3.860071,0 7.000001,-3.13993 7.000001,-7 0,-1.75033 -0.65118,-3.34759 -1.7168,-4.57617 l 1.57032,-1.57031 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -6.490231,1.00391 c 3.319631,0 6.000001,2.68037 6.000001,6 0,3.31963 -2.68037,6 -6.000001,6 -3.31963,0 -6,-2.68037 -6,-6 0,-0.88092 0.193846,-1.71405 0.533203,-2.4668 l 0.466797,0.4668 1,1 v 2 h 2 v 1 l 1,1 v 2 h 0.75 1.25 l 1,-1 1.000001,-1 v -1 l -1.000001,-1 h -2 -1 l -1,-1 h -1 l 1,-1 h 1 l 2,-2 -1,-1 h -1 l -1,-1 0.894532,-0.89453 c 0.358617,-0.0666 0.727234,-0.10547 1.105468,-0.10547 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 202,556.99628 c -1.79823,1e-5 -2.78534,0.23261 -3.38867,0.75196 C 198.00799,558.26759 198,559.00268 198,559.49628 v 0.5 h -0.002 c -0.12828,0 -0.91099,4e-5 -1.63867,0.53711 -0.72848,0.53766 -1.35958,1.60963 -1.35938,3.4668 9e-5,0.84676 0.12547,1.43896 0.35352,1.89453 0.22804,0.45557 0.5457,0.7425 0.81445,0.98047 a 0.50086817,0.50086817 0 1 0 0.66406,-0.75 c -0.2639,-0.23368 -0.44506,-0.40021 -0.58398,-0.67773 -0.13888,-0.27753 -0.24792,-0.69815 -0.248,-1.44727 -1.7e-4,-1.64286 0.494,-2.32325 0.95312,-2.66211 0.45913,-0.33885 0.92388,-0.3418 1.04688,-0.3418 h 0.44336 a 0.50005,0.50005 0 0 0 0.0586,0.004 l 3,-0.01 a 0.50005,0.50005 0 0 0 -0.002,-1 h -0.002 -0.002 L 199,559.99428 v -0.49805 c 0,-0.4936 -0.008,-0.75638 0.26367,-0.99023 0.27167,-0.23385 1.03456,-0.50976 2.73633,-0.50977 1.70177,0 2.46467,0.27592 2.73633,0.50977 0.27166,0.23385 0.26367,0.49663 0.26367,0.99023 v 1.99414 c -6e-5,0.47857 -0.26457,0.78886 -0.8457,1.12891 -0.58114,0.34005 -1.43184,0.62116 -2.30664,0.90234 -0.87481,0.28119 -1.77478,0.56315 -2.50586,0.98829 -0.73108,0.42513 -1.34192,1.08253 -1.3418,1.98046 v 2.01368 c 0,0.4936 0.008,1.22869 0.61133,1.74804 0.60334,0.51936 1.59044,0.75196 3.38867,0.75196 1.79823,-10e-6 2.78534,-0.23261 3.38867,-0.75196 C 205.99201,569.73274 206,568.99765 206,568.50405 v -0.5 c 0.127,0 0.91215,5.4e-4 1.64062,-0.53711 0.72848,-0.53766 1.35958,-1.60963 1.35938,-3.4668 -1.6e-4,-1.56962 -0.66959,-2.34844 -1.13672,-2.84375 a 0.5001364,0.5001364 0 1 0 -0.72656,0.6875 c 0.47073,0.49913 0.86314,0.83133 0.86328,2.15625 1.7e-4,1.64286 -0.494,2.32325 -0.95312,2.66211 -0.45913,0.33885 -0.92388,0.3418 -1.04688,0.3418 h -0.44336 a 0.50005,0.50005 0 0 0 -0.0586,-0.004 l -3,0.01 a 0.50005,0.50005 0 0 0 0.002,1 h 0.002 0.002 l 2.49595,-0.004 v 0.49805 c 0,0.4936 0.008,0.75638 -0.26367,0.99023 -0.27167,0.23385 -1.03456,0.50976 -2.73633,0.50977 -1.70177,0 -2.46467,-0.27592 -2.73633,-0.50977 -0.27166,-0.2339 -0.26367,-0.49668 -0.26367,-0.99028 v -2.01368 c -6e-5,-0.47218 0.26437,-0.77913 0.8457,-1.11718 0.58133,-0.33805 1.43145,-0.61908 2.30664,-0.90039 0.8752,-0.28132 1.77441,-0.56222 2.50586,-0.99024 0.73146,-0.42801 1.34168,-1.09087 1.3418,-1.99219 v -1.99414 c 0,-0.4936 -0.008,-1.22869 -0.61133,-1.74804 -0.60334,-0.51936 -1.59044,-0.75196 -3.38867,-0.75196 z"
+ id="path12249-6"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g5996"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ transform="matrix(-1,0,0,1,552.8323,1.5e-5)">
+ <path
+ inkscape:connector-curvature="0"
+ id="path5994"
+ d="m 310.58203,494 c -1.1875,0 -2.13583,0.69085 -2.52344,1.62109 -0.3876,0.93025 -0.20775,2.10475 0.66993,2.98243 l 2.5,2.5 c 0.62232,0.62232 0.69247,1.32282 0.45507,1.89257 C 311.4462,503.56585 310.89453,504 310.08203,504 l -6.53515,-0.008 2.13867,-2.13867 a 0.50005,0.50005 0 1 0 -0.70703,-0.70704 l -2.9336,2.93555 -0.01,0.008 a 0.50005,0.50005 0 0 0 -0.20704,0.41602 0.50005,0.50005 0 0 0 0,0.008 0.50005,0.50005 0 0 0 0.004,0.0469 0.50005,0.50005 0 0 0 0.008,0.0488 0.50005,0.50005 0 0 0 0.19336,0.29882 l 2.94532,2.94532 a 0.50005,0.50005 0 1 0 0.70703,-0.70704 l -2.1543,-2.15429 6.55078,0.008 c 1.1875,0 2.13584,-0.69085 2.52344,-1.62109 0.3876,-0.93025 0.20775,-2.10475 -0.66992,-2.98243 l -2.5,-2.5 c -0.62233,-0.62232 -0.69248,-1.32282 -0.45508,-1.89257 0.2374,-0.56976 0.78906,-1.00391 1.60156,-1.00391 h 4.75 a 0.50005,0.50005 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 90.5,494 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.949219 L 95,504.62695 V 507.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2.87305 L 102.55078,498 H 103.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -3 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -6 v -0.5 A 0.50005,0.50005 0 0 0 93.5,494 Z m 0.5,1 h 2 v 2 h -2 z m 10,0 h 2 v 2 h -2 z m -7,1 h 6 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.91406 l -3.214841,6 h -2.398438 l -3.214843,-6 H 93.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 z m 2,9 h 2 v 2 h -2 z"
+ id="path6000" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 115.5,494 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 496 h 0.5 c 1.29307,0 2.42587,0.35206 3.21875,1.00977 C 123.51163,497.66747 124,498.62406 124,500 c 0,1.58333 -0.78109,3.05511 -2.24023,4.16406 C 120.30062,505.27301 118.15909,506 115.5,506 H 115 v -1.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -3 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 507 h 0.5 c 2.84091,0 5.19938,-0.77301 6.86523,-2.03906 C 124.03109,503.69489 125,501.91667 125,500 c 0,-1.62406 -0.62718,-2.91747 -1.64258,-3.75977 C 122.34202,495.39794 120.97378,495 119.5,495 H 119 v -0.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m -4,10 h 2 v 2 h -2 z"
+ id="path6006" />
+ <g
+ transform="matrix(-1,0,0,1,1290,764.99979)"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
+ id="g8530-0-8-3"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1258.4766,-286 c -0.1708,0.008 -0.3255,0.10335 -0.4102,0.25195 l -4,7 c -0.1903,0.33312 0.05,0.74758 0.4336,0.74805 h 8 c 0.3836,-4.7e-4 0.6239,-0.41493 0.4336,-0.74805 l -4,-7 c -0.093,-0.16311 -0.2694,-0.26042 -0.457,-0.25195 z"
+ id="path8523-4-0-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1253.5,-289 c -0.8225,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z"
+ id="ellipse8525-5-4-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 27.5,11 A 0.50005,0.50005 0 0 0 27,11.5 v 10.851562 l 1,-1.75 V 12 h 12 v 12 h -3.099609 c 0.122248,0.339531 0.117057,0.686553 0.0039,1 H 40.5 A 0.50005,0.50005 0 0 0 41,24.5 v -13 A 0.50005,0.50005 0 0 0 40.5,11 Z"
+ transform="matrix(-1,0,0,1,1290,-302.99979)"
+ id="path8528-7-3-1" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g6348"
+ transform="translate(41.999953,147)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ inkscape:connector-curvature="0"
+ id="path6344"
+ d="m 27.5,347 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3.5 h 1 v -3 h 3 v -1 z m 9.5,0 v 1 h 3 v 3 h 1 v -3.5 A 0.50005,0.50005 0 0 0 40.5,347 Z m -10,10 v 3.5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 31 v -1 h -3 v -3 z m 13,0 v 3 h -3 v 1 h 3.5 A 0.50005,0.50005 0 0 0 41,360.5 V 357 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="path6346"
+ d="m 30.5,350 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 7 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 7 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -7 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ id="path6351"
+ d="m 310.57031,494.01758 c -0.79787,-0.038 -1.57177,0.27684 -2.16015,0.86523 l -1.48633,1.48828 c -0.61577,0.57533 -0.93433,1.35407 -0.89258,2.1543 a 0.50005,0.50005 0 1 0 0.99805,-0.0508 c -0.0269,-0.51495 0.15566,-0.98016 0.57617,-1.37305 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 l 1.5,-1.5 c 0.41161,-0.41161 0.88966,-0.59872 1.40429,-0.57422 0.51464,0.0245 1.08439,0.26993 1.63868,0.82422 0.55479,0.5548 0.80954,1.13546 0.83789,1.65235 0.0283,0.51688 -0.15241,0.9848 -0.57422,1.3789 a 0.50005,0.50005 0 0 0 -0.0137,0.0117 l -1.5,1.5 c -0.41213,0.41213 -0.87694,0.60352 -1.39649,0.60352 a 0.50005,0.50005 0 1 0 0,1 c 0.78067,0 1.52491,-0.31788 2.10352,-0.89649 l 1.48828,-1.48828 c 0.61768,-0.57711 0.9366,-1.36125 0.89258,-2.16406 -0.044,-0.80281 -0.43566,-1.60948 -1.13086,-2.30469 -0.69571,-0.69571 -1.49901,-1.07724 -2.29688,-1.11523 z m -1.08008,3.97851 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -5,5 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 5,-5 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -4.92968,2.02149 c -0.80753,-0.0482 -1.5954,0.26944 -2.17578,0.89062 l -1.48829,1.48828 c -0.58838,0.58839 -0.90322,1.36034 -0.86523,2.15821 0.038,0.79787 0.41952,1.60311 1.11523,2.29883 0.69521,0.6952 1.50384,1.08487 2.30664,1.1289 0.80281,0.044 1.585,-0.27294 2.16211,-0.89062 l 1.48829,-1.48828 C 307.68213,505.0249 308,504.28067 308,503.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.51955 -0.19139,0.98436 -0.60352,1.39648 l -1.5,1.5 a 0.50005,0.50005 0 0 0 -0.0117,0.0117 c -0.39411,0.42182 -0.86007,0.60452 -1.37696,0.57618 -0.51688,-0.0283 -1.0995,-0.2831 -1.65429,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.82227,-1.63867 -0.0245,-0.51463 0.16065,-0.99268 0.57227,-1.40429 l 1.5,-1.5 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 c 0.39634,-0.4242 0.86629,-0.60725 1.38672,-0.57618 a 0.50005,0.50005 0 1 0 0.0586,-0.99804 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g6359"
+ transform="rotate(90,306.5,333.5)">
+ <path
+ sodipodi:nodetypes="sssss"
+ inkscape:connector-curvature="0"
+ id="path6353"
+ d="m 469.5,356 c -1.37478,0 -2.5,1.12522 -2.5,2.5 0,1.37478 1.12522,2.5 2.5,2.5 1.37478,0 2.5,-1.12522 2.5,-2.5 0,-1.37478 -1.12522,-2.5 -2.5,-2.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <g
+ style="opacity:0.7;fill:#ffffff"
+ id="g6357">
+ <path
+ id="path6355"
+ transform="matrix(0,-1,-1,0,1038,577)"
+ d="m 218.5,557 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.64684 0.42097,1.19777 1,1.40625 V 564.5 c -0.01,0.67616 1.01,0.67616 1,0 v -4.59375 c 0.57903,-0.20848 1,-0.75941 1,-1.40625 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 9.5,0 c -1.09865,0 -2,0.90135 -2,2 0,0.36859 0.10883,0.71022 0.28516,1.00781 l -5.13868,5.13867 c -0.49023,0.47127 0.23577,1.19727 0.70704,0.70704 l 5.13867,-5.13868 C 227.28978,560.89117 227.63141,561 228,561 c 1.09865,-10e-6 2,-0.90135 2,-2 0,-1.09865 -0.90135,-1.99999 -2,-2 z m 0.5,10 c -0.64684,0 -1.19777,0.42097 -1.40625,1 H 222.5 c -0.67616,-0.01 -0.67616,1.01 0,1 h 4.59375 c 0.20848,0.57903 0.75941,1 1.40625,1 0.82251,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.67749,-1.5 -1.5,-1.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g5920" transform="translate(168,-62.999995)">
- <path inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="path5916" d="m 49,558 v 3 h 3 v -3 z m 3,3 v 3 h 3 v -3 z m 3,0 h 3 v -3 h -3 z m 3,0 v 3 h 3 v -3 z m 0,3 h -3 v 3 h 3 z m 0,3 v 3 h 3 v -3 z m -3,0 h -3 v 3 h 3 z m -3,0 v -3 h -3 v 3 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" id="path5918" d="m 48.5,557 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 61.5,557 Z m 0.5,1 h 12 v 12 H 49 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g transform="translate(420.00505,-159.00506)" style="display:inline;fill:#ffffff;enable-background:new" id="g5937">
- <path id="path5935" transform="translate(-462.00505,96.005057)" d="m 103.49609,556.99023 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1.57031,1.57032 c -1.22858,-1.06562 -2.825838,-1.7168 -4.576171,-1.7168 -3.86007,0 -7,3.13993 -7,7 0,1.75033 0.649231,3.34954 1.714844,4.57813 l -1.568359,1.56835 a 0.50005,0.50005 0 1 0 0.707031,0.70704 l 1.568359,-1.56836 c 1.228585,1.06561 2.827793,1.71484 4.578125,1.71484 3.860071,0 7.000001,-3.13993 7.000001,-7 0,-1.75033 -0.65118,-3.34759 -1.7168,-4.57617 l 1.57032,-1.57031 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -6.490231,1.00391 c 3.319631,0 6.000001,2.68037 6.000001,6 0,3.31963 -2.68037,6 -6.000001,6 -3.31963,0 -6,-2.68037 -6,-6 0,-0.88092 0.193846,-1.71405 0.533203,-2.4668 l 0.466797,0.4668 1,1 v 2 h 2 v 1 l 1,1 v 2 h 0.75 1.25 l 1,-1 1.000001,-1 v -1 l -1.000001,-1 h -2 -1 l -1,-1 h -1 l 1,-1 h 1 l 2,-2 -1,-1 h -1 l -1,-1 0.894532,-0.89453 c 0.358617,-0.0666 0.727234,-0.10547 1.105468,-0.10547 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 202,556.99628 c -1.79823,1e-5 -2.78534,0.23261 -3.38867,0.75196 C 198.00799,558.26759 198,559.00268 198,559.49628 v 0.5 h -0.002 c -0.12828,0 -0.91099,4e-5 -1.63867,0.53711 -0.72848,0.53766 -1.35958,1.60963 -1.35938,3.4668 9e-5,0.84676 0.12547,1.43896 0.35352,1.89453 0.22804,0.45557 0.5457,0.7425 0.81445,0.98047 a 0.50086817,0.50086817 0 1 0 0.66406,-0.75 c -0.2639,-0.23368 -0.44506,-0.40021 -0.58398,-0.67773 -0.13888,-0.27753 -0.24792,-0.69815 -0.248,-1.44727 -1.7e-4,-1.64286 0.494,-2.32325 0.95312,-2.66211 0.45913,-0.33885 0.92388,-0.3418 1.04688,-0.3418 h 0.44336 a 0.50005,0.50005 0 0 0 0.0586,0.004 l 3,-0.01 a 0.50005,0.50005 0 0 0 -0.002,-1 h -0.002 -0.002 L 199,559.99428 v -0.49805 c 0,-0.4936 -0.008,-0.75638 0.26367,-0.99023 0.27167,-0.23385 1.03456,-0.50976 2.73633,-0.50977 1.70177,0 2.46467,0.27592 2.73633,0.50977 0.27166,0.23385 0.26367,0.49663 0.26367,0.99023 v 1.99414 c -6e-5,0.47857 -0.26457,0.78886 -0.8457,1.12891 -0.58114,0.34005 -1.43184,0.62116 -2.30664,0.90234 -0.87481,0.28119 -1.77478,0.56315 -2.50586,0.98829 -0.73108,0.42513 -1.34192,1.08253 -1.3418,1.98046 v 2.01368 c 0,0.4936 0.008,1.22869 0.61133,1.74804 0.60334,0.51936 1.59044,0.75196 3.38867,0.75196 1.79823,-10e-6 2.78534,-0.23261 3.38867,-0.75196 C 205.99201,569.73274 206,568.99765 206,568.50405 v -0.5 c 0.127,0 0.91215,5.4e-4 1.64062,-0.53711 0.72848,-0.53766 1.35958,-1.60963 1.35938,-3.4668 -1.6e-4,-1.56962 -0.66959,-2.34844 -1.13672,-2.84375 a 0.5001364,0.5001364 0 1 0 -0.72656,0.6875 c 0.47073,0.49913 0.86314,0.83133 0.86328,2.15625 1.7e-4,1.64286 -0.494,2.32325 -0.95312,2.66211 -0.45913,0.33885 -0.92388,0.3418 -1.04688,0.3418 h -0.44336 a 0.50005,0.50005 0 0 0 -0.0586,-0.004 l -3,0.01 a 0.50005,0.50005 0 0 0 0.002,1 h 0.002 0.002 l 2.49595,-0.004 v 0.49805 c 0,0.4936 0.008,0.75638 -0.26367,0.99023 -0.27167,0.23385 -1.03456,0.50976 -2.73633,0.50977 -1.70177,0 -2.46467,-0.27592 -2.73633,-0.50977 -0.27166,-0.2339 -0.26367,-0.49668 -0.26367,-0.99028 v -2.01368 c -6e-5,-0.47218 0.26437,-0.77913 0.8457,-1.11718 0.58133,-0.33805 1.43145,-0.61908 2.30664,-0.90039 0.8752,-0.28132 1.77441,-0.56222 2.50586,-0.99024 0.73146,-0.42801 1.34168,-1.09087 1.3418,-1.99219 v -1.99414 c 0,-0.4936 -0.008,-1.22869 -0.61133,-1.74804 -0.60334,-0.51936 -1.59044,-0.75196 -3.38867,-0.75196 z" id="path12249-6" inkscape:connector-curvature="0"/>
- <g id="g5996" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" transform="matrix(-1,0,0,1,552.8323,1.5e-5)">
- <path inkscape:connector-curvature="0" id="path5994" d="m 310.58203,494 c -1.1875,0 -2.13583,0.69085 -2.52344,1.62109 -0.3876,0.93025 -0.20775,2.10475 0.66993,2.98243 l 2.5,2.5 c 0.62232,0.62232 0.69247,1.32282 0.45507,1.89257 C 311.4462,503.56585 310.89453,504 310.08203,504 l -6.53515,-0.008 2.13867,-2.13867 a 0.50005,0.50005 0 1 0 -0.70703,-0.70704 l -2.9336,2.93555 -0.01,0.008 a 0.50005,0.50005 0 0 0 -0.20704,0.41602 0.50005,0.50005 0 0 0 0,0.008 0.50005,0.50005 0 0 0 0.004,0.0469 0.50005,0.50005 0 0 0 0.008,0.0488 0.50005,0.50005 0 0 0 0.19336,0.29882 l 2.94532,2.94532 a 0.50005,0.50005 0 1 0 0.70703,-0.70704 l -2.1543,-2.15429 6.55078,0.008 c 1.1875,0 2.13584,-0.69085 2.52344,-1.62109 0.3876,-0.93025 0.20775,-2.10475 -0.66992,-2.98243 l -2.5,-2.5 c -0.62233,-0.62232 -0.69248,-1.32282 -0.45508,-1.89257 0.2374,-0.56976 0.78906,-1.00391 1.60156,-1.00391 h 4.75 a 0.50005,0.50005 0 1 0 0,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 90.5,494 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.949219 L 95,504.62695 V 507.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2.87305 L 102.55078,498 H 103.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -3 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -6 v -0.5 A 0.50005,0.50005 0 0 0 93.5,494 Z m 0.5,1 h 2 v 2 h -2 z m 10,0 h 2 v 2 h -2 z m -7,1 h 6 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.91406 l -3.214841,6 h -2.398438 l -3.214843,-6 H 93.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 z m 2,9 h 2 v 2 h -2 z" id="path6000"/>
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 115.5,494 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 496 h 0.5 c 1.29307,0 2.42587,0.35206 3.21875,1.00977 C 123.51163,497.66747 124,498.62406 124,500 c 0,1.58333 -0.78109,3.05511 -2.24023,4.16406 C 120.30062,505.27301 118.15909,506 115.5,506 H 115 v -1.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -3 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 507 h 0.5 c 2.84091,0 5.19938,-0.77301 6.86523,-2.03906 C 124.03109,503.69489 125,501.91667 125,500 c 0,-1.62406 -0.62718,-2.91747 -1.64258,-3.75977 C 122.34202,495.39794 120.97378,495 119.5,495 H 119 v -0.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m -4,10 h 2 v 2 h -2 z" id="path6006"/>
- <g transform="matrix(-1,0,0,1,1290,764.99979)" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" id="g8530-0-8-3" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1258.4766,-286 c -0.1708,0.008 -0.3255,0.10335 -0.4102,0.25195 l -4,7 c -0.1903,0.33312 0.05,0.74758 0.4336,0.74805 h 8 c 0.3836,-4.7e-4 0.6239,-0.41493 0.4336,-0.74805 l -4,-7 c -0.093,-0.16311 -0.2694,-0.26042 -0.457,-0.25195 z" id="path8523-4-0-3" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1253.5,-289 c -0.8225,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z" id="ellipse8525-5-4-7" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 27.5,11 A 0.50005,0.50005 0 0 0 27,11.5 v 10.851562 l 1,-1.75 V 12 h 12 v 12 h -3.099609 c 0.122248,0.339531 0.117057,0.686553 0.0039,1 H 40.5 A 0.50005,0.50005 0 0 0 41,24.5 v -13 A 0.50005,0.50005 0 0 0 40.5,11 Z" transform="matrix(-1,0,0,1,1290,-302.99979)" id="path8528-7-3-1"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g6348" transform="translate(41.999953,147)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path inkscape:connector-curvature="0" id="path6344" d="m 27.5,347 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3.5 h 1 v -3 h 3 v -1 z m 9.5,0 v 1 h 3 v 3 h 1 v -3.5 A 0.50005,0.50005 0 0 0 40.5,347 Z m -10,10 v 3.5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 31 v -1 h -3 v -3 z m 13,0 v 3 h -3 v 1 h 3.5 A 0.50005,0.50005 0 0 0 41,360.5 V 357 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path sodipodi:nodetypes="ccccccccc" inkscape:connector-curvature="0" id="path6346" d="m 30.5,350 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 7 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 7 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -7 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <path inkscape:connector-curvature="0" id="path6351" d="m 310.57031,494.01758 c -0.79787,-0.038 -1.57177,0.27684 -2.16015,0.86523 l -1.48633,1.48828 c -0.61577,0.57533 -0.93433,1.35407 -0.89258,2.1543 a 0.50005,0.50005 0 1 0 0.99805,-0.0508 c -0.0269,-0.51495 0.15566,-0.98016 0.57617,-1.37305 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 l 1.5,-1.5 c 0.41161,-0.41161 0.88966,-0.59872 1.40429,-0.57422 0.51464,0.0245 1.08439,0.26993 1.63868,0.82422 0.55479,0.5548 0.80954,1.13546 0.83789,1.65235 0.0283,0.51688 -0.15241,0.9848 -0.57422,1.3789 a 0.50005,0.50005 0 0 0 -0.0137,0.0117 l -1.5,1.5 c -0.41213,0.41213 -0.87694,0.60352 -1.39649,0.60352 a 0.50005,0.50005 0 1 0 0,1 c 0.78067,0 1.52491,-0.31788 2.10352,-0.89649 l 1.48828,-1.48828 c 0.61768,-0.57711 0.9366,-1.36125 0.89258,-2.16406 -0.044,-0.80281 -0.43566,-1.60948 -1.13086,-2.30469 -0.69571,-0.69571 -1.49901,-1.07724 -2.29688,-1.11523 z m -1.08008,3.97851 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -5,5 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 5,-5 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -4.92968,2.02149 c -0.80753,-0.0482 -1.5954,0.26944 -2.17578,0.89062 l -1.48829,1.48828 c -0.58838,0.58839 -0.90322,1.36034 -0.86523,2.15821 0.038,0.79787 0.41952,1.60311 1.11523,2.29883 0.69521,0.6952 1.50384,1.08487 2.30664,1.1289 0.80281,0.044 1.585,-0.27294 2.16211,-0.89062 l 1.48829,-1.48828 C 307.68213,505.0249 308,504.28067 308,503.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.51955 -0.19139,0.98436 -0.60352,1.39648 l -1.5,1.5 a 0.50005,0.50005 0 0 0 -0.0117,0.0117 c -0.39411,0.42182 -0.86007,0.60452 -1.37696,0.57618 -0.51688,-0.0283 -1.0995,-0.2831 -1.65429,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.82227,-1.63867 -0.0245,-0.51463 0.16065,-0.99268 0.57227,-1.40429 l 1.5,-1.5 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 c 0.39634,-0.4242 0.86629,-0.60725 1.38672,-0.57618 a 0.50005,0.50005 0 1 0 0.0586,-0.99804 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g6359" transform="rotate(90,306.5,333.5)">
- <path sodipodi:nodetypes="sssss" inkscape:connector-curvature="0" id="path6353" d="m 469.5,356 c -1.37478,0 -2.5,1.12522 -2.5,2.5 0,1.37478 1.12522,2.5 2.5,2.5 1.37478,0 2.5,-1.12522 2.5,-2.5 0,-1.37478 -1.12522,-2.5 -2.5,-2.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <g style="opacity:0.7;fill:#ffffff" id="g6357">
- <path id="path6355" transform="matrix(0,-1,-1,0,1038,577)" d="m 218.5,557 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.64684 0.42097,1.19777 1,1.40625 V 564.5 c -0.01,0.67616 1.01,0.67616 1,0 v -4.59375 c 0.57903,-0.20848 1,-0.75941 1,-1.40625 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 9.5,0 c -1.09865,0 -2,0.90135 -2,2 0,0.36859 0.10883,0.71022 0.28516,1.00781 l -5.13868,5.13867 c -0.49023,0.47127 0.23577,1.19727 0.70704,0.70704 l 5.13867,-5.13868 C 227.28978,560.89117 227.63141,561 228,561 c 1.09865,-10e-6 2,-0.90135 2,-2 0,-1.09865 -0.90135,-1.99999 -2,-2 z m 0.5,10 c -0.64684,0 -1.19777,0.42097 -1.40625,1 H 222.5 c -0.67616,-0.01 -0.67616,1.01 0,1 h 4.59375 c 0.20848,0.57903 0.75941,1 1.40625,1 0.82251,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.67749,-1.5 -1.5,-1.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0"/>
+ <g
+ style="fill:#ffffff"
+ id="g6505"
+ transform="translate(84,-21)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 31.5,494 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 A 0.50005,0.50005 0 0 0 40.5,494 Z m 0.5,1 h 8 v 8 h -8 z"
+ id="path6499"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 38,496 c -0.546362,0 -1,0.45364 -1,1 0,0.54636 0.453638,1 1,1 0.546362,0 1,-0.45364 1,-1 0,-0.54636 -0.453638,-1 -1,-1 z m -3.513672,1.05078 c -0.16529,0.005 -0.314526,0.10024 -0.388672,0.24805 l -2.75,5.5 c -0.148607,0.29892 0.06852,0.64991 0.402344,0.65039 h 5.75 c 0.340259,-0.001 0.55634,-0.36474 0.394531,-0.66406 l -3,-5.5 c -0.08111,-0.14873 -0.238867,-0.23931 -0.408203,-0.23438 z"
+ id="path6501"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.69300022;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 29.492188,495.99219 A 0.50005,0.50005 0 0 0 29,496.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 30 v -8.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z m -2,2 A 0.50005,0.50005 0 0 0 27,498.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 28 v -8.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z"
+ id="path6503"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g8734-0"
+ transform="translate(-104.00001,-19.99995)"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 158.48048,492.99995 c -0.15153,0.004 -0.29304,0.0766 -0.38477,0.19727 l -4.94922,4.94921 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4.5 h 5 v 12 h -10 v -6 h -1 v 6.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 11 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -13 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -6 c -0.005,-6e-5 -0.009,-6e-5 -0.0137,0 -6.7e-4,2e-5 -0.001,-2e-5 -0.002,0 -0.001,4e-5 -0.003,-5e-5 -0.004,0 z"
+ id="path8730-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccc" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 56.515625,452 c 0.752,0 1.453818,0.239 2.023438,0.64453 C 59.424733,453.27508 60,454.31514 60,455.48438 V 458.5 c -3e-5,0.27537 -0.222677,0.4989 -0.498047,0.5 l -4.009765,0.008 c -0.27613,-3e-5 -0.49997,-0.22387 -0.5,-0.5 L 55,452.53516 v -0.002 -0.0352 C 55.001,452.22272 55.22466,452.00003 55.5,452 Z M 54,452 v 1 H 52.484375 C 51.099855,453 50,454.09985 50,455.48438 v 8.03124 C 50,464.90014 51.099855,466 52.484375,466 h 4.03125 C 57.900145,466 59,464.90014 59,463.51562 V 460 h 1 v 3.51562 C 60,465.43685 58.436855,467 56.515625,467 h -4.03125 C 50.563145,467 49,465.43686 49,463.51562 v -8.03124 C 49,453.56315 50.563145,452 52.484375,452 Z"
+ id="path6557"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6596"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 92.484375,452 c -0.752,0 -1.453818,0.239 -2.023438,0.64453 C 89.575267,453.27508 89,454.31514 89,455.48438 V 458.5 c 3e-5,0.27537 0.222677,0.4989 0.498047,0.5 l 4.009765,0.008 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 L 94,452.53516 v -0.002 -0.0352 C 93.999,452.22272 93.77534,452.00003 93.5,452 Z M 95,452 v 1 h 1.515625 C 97.900145,453 99,454.09985 99,455.48438 v 8.03124 C 99,464.90014 97.900145,466 96.515625,466 h -4.03125 C 91.099855,466 90,464.90014 90,463.51562 V 460 h -1 v 3.51562 C 89,465.43685 90.563145,467 92.484375,467 h 4.03125 C 98.436855,467 100,465.43686 100,463.51562 v -8.03124 C 100,453.56315 98.436855,452 96.515625,452 Z m 6.47656,-0.97852 a 0.50005,0.50005 0 0 0 -0.31445,0.8711 c 0.58809,0.54453 0.8418,1.0856 0.8418,1.60156 L 102,459.5 a 0.50005,0.50005 0 1 0 1,0 l 0.004,-6.00586 c 0,-0.8509 -0.43179,-1.65971 -1.16211,-2.33594 a 0.50005,0.50005 0 0 0 -0.36524,-0.13672 z m 3.01563,2.01563 A 0.50005,0.50005 0 0 0 104,453.54297 v 4.05859 a 0.50005,0.50005 0 1 0 1,0 v -4.05859 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6598"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 113.48438,452 C 111.56315,452 110,453.56315 110,455.48438 v 8.03124 c 0,1.92123 1.56315,3.48438 3.48438,3.48438 h 4.03125 C 119.43685,467 121,465.43685 121,463.51562 v -8.03124 C 121,453.56315 119.43685,452 117.51563,452 Z m 0,1 h 4.03125 c 1.38452,0 2.48437,1.09985 2.48437,2.48438 v 8.03124 C 120,464.90015 118.90015,466 117.51563,466 h -4.03125 C 112.09985,466 111,464.90015 111,463.51562 v -8.03124 C 111,454.09985 112.09985,453 113.48438,453 Z m 1.5625,1 C 114.47554,454 114,454.47555 114,455.04688 v 3.90624 c 0,0.57133 0.47554,1.04688 1.04688,1.04688 h 0.90625 C 116.52446,460 117,459.52445 117,458.95312 v -3.90624 C 117,454.47555 116.52446,454 115.95313,454 Z m 7.42968,-2.97852 a 0.50005,0.50005 0 0 0 -0.31445,0.8711 c 0.58809,0.54453 0.8418,1.0856 0.8418,1.60156 L 123,459.5 a 0.50005,0.50005 0 1 0 1,0 l 0.004,-6.00586 c 0,-0.8509 -0.43179,-1.65971 -1.16211,-2.33594 a 0.50005,0.50005 0 0 0 -0.36524,-0.13672 z m 3.01563,2.01563 A 0.50005,0.50005 0 0 0 125,453.54297 v 4.05859 a 0.50005,0.50005 0 1 0 1,0 v -4.05859 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6600"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 138.51562,452 c 0.752,0 1.45382,0.239 2.02344,0.64453 0.88567,0.63055 1.46094,1.67061 1.46094,2.83985 V 458.5 c -3e-5,0.27537 -0.22268,0.4989 -0.49805,0.5 l -4.00976,0.008 c -0.27613,-3e-5 -0.49997,-0.22387 -0.5,-0.5 L 137,452.53516 v -0.002 -0.0352 c 0.001,-0.27524 0.22466,-0.49793 0.5,-0.49796 z M 136,452 v 1 h -1.51563 C 133.09986,453 132,454.09985 132,455.48438 v 8.03124 c 0,1.38452 1.09986,2.48438 2.48437,2.48438 h 4.03125 C 139.90014,466 141,464.90014 141,463.51562 V 460 h 1 v 3.51562 C 142,465.43685 140.43685,467 138.51562,467 h -4.03125 C 132.56315,467 131,465.43686 131,463.51562 v -8.03124 C 131,453.56315 132.56315,452 134.48437,452 Z m 7.47656,-0.97852 a 0.50005,0.50005 0 0 0 -0.31445,0.8711 c 0.58809,0.54453 0.8418,1.0856 0.8418,1.60156 L 144,459.5 a 0.50005,0.50005 0 1 0 1,0 l 0.004,-6.00586 c 0,-0.8509 -0.43179,-1.65971 -1.16211,-2.33594 a 0.50005,0.50005 0 0 0 -0.36524,-0.13672 z m 3.01563,2.01563 A 0.50005,0.50005 0 0 0 146,453.54297 v 4.05859 a 0.50005,0.50005 0 1 0 1,0 v -4.05859 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g26277"
+ transform="translate(273,-20.99999)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 203.5,284 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -8,8 A 0.50005,0.50005 0 0 0 195,292.5 l -0.008,5.00586 a 0.50005,0.50005 0 0 0 0.5,0.50195 L 208.5,298 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 208 v 12 l -12.00781,0.008 0.008,-4.30078 z"
+ id="path23052"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 200.5,284 -5.00781,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 1 0 1,0 v -4.50195 L 200.5,285 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path23056"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 351.48242,557.01562 -0.96875,0.0156 c -0.0189,2.6e-4 -0.0378,0.002 -0.0566,0.004 -2.58289,0.33067 -4.57988,2.60038 -4.45117,5.21484 0.0288,0.58487 0.23179,1.09854 0.44141,1.5957 l -3.78516,3.78516 c -0.33708,0.30742 -0.60091,0.7293 -0.64063,1.23047 -0.0397,0.50117 0.17261,1.03979 0.625,1.49219 0.45357,0.45356 0.99596,0.65829 1.49219,0.61328 0.49624,-0.045 0.906,-0.30379 1.21485,-0.61328 l 3.80664,-3.80664 c 0.52791,0.22561 1.0693,0.4331 1.69336,0.45117 2.60313,0.0754 4.83493,-1.87377 5.11328,-4.46289 0.001,-0.0136 0.002,-0.0273 0.002,-0.041 l 0.0215,-0.9668 c 0.0105,-0.45102 -0.53451,-0.68424 -0.85351,-0.36523 L 352.29297,564 h -1.58594 L 349,562.29297 v -1.58594 l 2.84375,-2.83789 c 0.31756,-0.31766 0.0878,-0.86042 -0.36133,-0.85352 z"
+ id="path18095"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccc" />
+ <g
+ transform="translate(-1162,-873.9944)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g17413-4-0">
+ <path
+ inkscape:connector-curvature="0"
+ id="path17404-8-7"
+ transform="translate(1162,873.9944)"
+ d="m 164.48438,535.00586 a 0.50005,0.50005 0 0 0 -0.1211,0.0195 l -1.36328,0.3887 0.01,2.03906 1.63085,-0.46679 A 0.50005,0.50005 0 0 0 165,536.50586 v -1 a 0.50005,0.50005 0 0 0 -0.51562,-0.5 z M 162,535.70117 l -2,0.57031 0.01,2.03907 2,-0.57227 z m -3,0.85547 -1.63672,0.46875 A 0.50005,0.50005 0 0 0 157,537.50586 v 1 a 0.50005,0.50005 0 0 0 0.63672,0.48047 l 1.36914,-0.39063 z M 157,542 v 1 l 8.5,0.01 c 0.276,-5e-4 0.4995,-0.224 0.5,-0.5 -5e-4,-0.276 -0.224,-0.4995 -0.5,-0.5 z m -3,2.00586 v 5.49219 c 0,0.2761 0.2239,0.5 0.5,0.5 h 11 c 0.2761,0 0.5,-0.2239 0.5,-0.5 v -4.99219 c 0,-0.2761 -0.2239,-0.5 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1315.5078,1411.9922 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1.5 1.5 h -1 z"
+ id="path17409-0-0"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-574,-936.9944)"
+ id="g17429-7-7"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1063.5078,1410.9922 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1.5 1.5 h -1 z"
+ id="path17417-2-4"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 1340,1411 v 2 l 1.5,-0.01 1.75,-2 z m 4.5,-0.01 -1.75,2 h 2.75 l 1.7266,-2 z m 4,0 -1.7266,2 2.7266,0.01 c 0.276,-5e-4 0.4995,-0.224 0.5,-0.5 v -1 c -5e-4,-0.276 -0.224,-0.4995 -0.5,-0.5 z m -8.5,4.01 0.01,1.9922 -3.0098,0.01 v 5.4921 c 0,0.2761 0.2239,0.5 0.5,0.5 h 12 c 0.2761,0 0.5,-0.2239 0.5,-0.5 V 1415.5 c 0,-0.2761 -0.2239,-0.5 -0.5,-0.5 z m 2.5156,1 c 0.084,0 0.1663,0.026 0.2383,0.068 l 4.25,2.5 c 0.33,0.1931 0.33,0.6701 0,0.8632 l -4.25,2.5 c -0.3336,0.1966 -0.7545,-0.044 -0.7539,-0.4316 v -5 c -10e-5,-0.2823 0.2334,-0.51 0.5156,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00157475;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ transform="translate(-273)"
+ id="path17425-5" />
+ </g>
+ <path
+ sodipodi:nodetypes="cccccscccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path17971-6"
+ d="m 433.60156,411.10938 c -0.0348,2.9e-4 -0.0695,0.004 -0.10351,0.0117 -2.03912,0.46668 -3.49042,2.28707 -3.49219,4.37891 9e-4,0.50625 0.15089,0.99318 0.31836,1.46875 l -2.42774,2.42773 c -1.00968,1.00969 -1.01874,2.3133 -0.3125,3.01954 0.70624,0.70624 2.00985,0.69718 3.01954,-0.3125 l 2.42968,-2.42969 c 0.47476,0.16775 0.9595,0.31841 1.46485,0.32031 6.7e-4,0 0.001,0 0.002,0 2.10425,-9.3e-4 3.93168,-1.46897 4.38672,-3.52344 0.0316,-0.14237 -4.7e-4,-0.29146 -0.0879,-0.4082 l -0.64844,-0.86328 c -0.17598,-0.23372 -0.51414,-0.2671 -0.73242,-0.0723 L 435.31055,417 h -1.08008 L 433,415.56445 v -0.85742 l 1.85352,-1.85351 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -0.89063,-0.89062 c -0.0957,-0.0957 -0.22603,-0.14855 -0.36133,-0.14648 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path18042-5"
+ d="m 413.49609,411 c -1.31297,0 -2.2906,0.33758 -3.34961,1.39648 -1.07833,1.0783 -1.34444,2.83666 -0.73437,4.48438 l -2.51563,2.51562 c -1.00968,1.00969 -1.01874,2.3133 -0.3125,3.01954 0.70624,0.70624 2.00985,0.69718 3.01954,-0.3125 l 2.51757,-2.51758 c 1.64574,0.60684 3.4036,0.3464 4.48243,-0.73242 1.05892,-1.05893 1.39668,-2.03818 1.39257,-3.35547 a 0.50005,0.50005 0 0 0 -0.14648,-0.35157 l -1,-1 a 0.50005,0.50005 0 0 0 -0.70703,0 L 414.28906,416 h -0.58594 l -0.70703,-0.70703 v -0.58594 l 1.85352,-1.85351 a 0.50005,0.50005 0 0 0 0,-0.70704 l -1,-1 A 0.50005,0.50005 0 0 0 413.49609,411 Z m -0.18164,1.02539 0.47461,0.47461 -1.64648,1.64648 A 0.50005,0.50005 0 0 0 411.99609,414.5 v 1 a 0.50005,0.50005 0 0 0 0.14649,0.35352 l 1,1 A 0.50005,0.50005 0 0 0 413.49609,417 h 1 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 1.64648,-1.64649 0.47461,0.47461 c -0.0187,1.03267 -0.19304,1.58367 -1.07422,2.46484 -0.83209,0.8321 -2.35353,1.13617 -3.75195,0.47266 a 0.50005,0.50005 0 0 0 -0.56836,0.0977 l -2.67969,2.67968 c -0.74031,0.74032 -1.3117,0.60626 -1.60546,0.3125 -0.29376,-0.29376 -0.42782,-0.86515 0.3125,-1.60546 l 2.67773,-2.67774 a 0.50005,0.50005 0 0 0 0.0977,-0.56836 c -0.66677,-1.39852 -0.3581,-2.92122 0.47461,-3.7539 0.88058,-0.8805 1.43264,-1.05616 2.46093,-1.07813 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <g
+ transform="translate(-104.9941,85.0365)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g19021-7-6">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.70000005;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 448.5,284 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -10,1 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m 5,0 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m 5,0 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m -10,4 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -10,1 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m 5,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 5,0 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m -10,4 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -10,1 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m 5,0 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m 5,0 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z"
+ id="ellipse19010-6-5"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g19186-9-4"
+ transform="translate(-146.9941,85.0365)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 327.49805,368.03711 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 l -7,7 a 0.50005,0.50005 0 0 0 0,0.70703 l 7,7 a 0.50005,0.50005 0 0 0 0.70704,0 l 7.03124,-7 a 0.50005,0.50005 0 0 0 0,-0.70703 l -7.03124,-7 a 0.50005,0.50005 0 0 0 -0.36133,-0.14648 z m 0.008,1.20703 6.32226,6.29297 -6.32226,6.29297 -6.29297,-6.29297 z m 0,4.79297 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z"
+ transform="translate(146.9941,-85.0365)"
+ id="path19093-9-7"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g19103-5"
+ transform="rotate(-90,394.50012,1587.5001)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 457.5,473 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -7.5 -0.5 c -0.5244,0 -1.02378,0.21717 -1.39258,0.57617 -0.3688,0.3592 -0.60742,0.86058 -0.60742,1.42578 V 485 c 10e-5,0.5302 0.21104,1.03916 0.58594,1.41406 C 447.96084,486.78896 448.4698,487 449,487 h 2.5 c 0.2762,0 0.5,-0.2238 0.5,-0.5 v -9 c 0,-0.2761 -0.2238,-0.4999 -0.5,-0.5 H 449 c -0.4523,0 -1,-0.47105 -1,-0.99805 0,-0.2635 0.13823,-0.51462 0.33203,-0.69922 C 448.52543,475.11903 448.775,475 449,475 h 8 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.5 v 5 h -1.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -4 v 1 h 4 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 A 0.50005,0.50005 0 0 0 460.5,482 H 460 v -5 h 0.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m 0,9 h 2 v 2 h -2 z"
+ transform="rotate(90,394.50012,1587.5001)"
+ id="path19040-4"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 428.25,452 c -0.6506,0 -1.23633,0.19727 -1.64453,0.60547 -0.4083,0.4081 -0.60567,0.99393 -0.60547,1.64453 v 9.5 c 2e-4,0.6505 0.19727,1.23643 0.60547,1.64453 C 427.01357,465.80273 427.5994,466 428.25,466 H 429 v -1 h -0.75 c -0.4574,0 -0.7477,-0.1227 -0.9375,-0.3125 -0.1898,-0.1898 -0.3124,-0.48 -0.3125,-0.9375 v -9.5 c -10e-5,-0.4574 0.1227,-0.7477 0.3125,-0.9375 C 427.5023,453.1227 427.7926,453 428.25,453 H 429 v -1 z m 8.75,0 v 1 h 0.75 c 0.4574,0 0.7477,0.1227 0.9375,0.3125 0.1898,0.1898 0.3125,0.4801 0.3125,0.9375 v 9.5 c 0,0.4574 -0.1227,0.7477 -0.3125,0.9375 C 438.4977,464.8773 438.2074,465 437.75,465 H 437 v 1 h 0.75 c 0.6506,0 1.23643,-0.19727 1.64453,-0.60547 C 439.80273,464.98643 440,464.4006 440,463.75 v -9.5 c 0,-0.6506 -0.19727,-1.23643 -0.60547,-1.64453 C 438.98643,452.19727 438.4006,452 437.75,452 Z m -4,4 v 2 h -1.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -2 v 1 h 2 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.5 v 2 h 1 v -2 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 461 h 2 v -1 h -2 v -1.5 A 0.50005,0.50005 0 0 0 435.5,458 H 434 v -2 z m -1,3 h 3 v 3 h -3 z"
+ id="path19168-3"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 411,536 v 4 h -2.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2.5 h -4 v 1 h 4 v 2.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2.5 v 4 h 1 v -4 h 2.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 544 h 4 v -1 h -4 v -2.5 A 0.50005,0.50005 0 0 0 414.5,540 H 412 v -4 z m -2,5 h 5 v 5 h -5 z m 2,2 v 1 h 1 v -1 z"
+ id="rect19268-0"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g9974-4-9"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(-84.00001,21.000005)">
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path14003-8"
+ transform="translate(84.000014,-21.000005)"
+ d="M 308.06055,557 C 307.40848,557.63639 307,558.52103 307,559.5 c 0,1.5 0.75,2.5 2,3.14453 v 0.004 6.85156 c -0.0287,2.02848 3.02869,2.02848 3,0 v -6.85156 -0.002 c 1.28948,-0.66521 2,-1.64648 2,-3.14648 0,-0.97897 -0.40848,-1.86361 -1.06055,-2.5 H 312.91797 312 V 560 l -1,1 h -1 l -1,-1 2e-5,-3 z M 310,569 h 1 v 1 h -1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ sodipodi:nodetypes="ccccccccccccccscscsccc"
+ id="path14013-6"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 387.00001,542 387,536.5 c 0.004,-0.28226 -0.22555,-0.51223 -0.50781,-0.50781 -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 l 10e-6,5.5 z m 0.75,2 H 388.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -4 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 0.75001 v 1 c -0.75,0 -1.25,0.5 -1.25,1.25 L 384,547.5 c -10e-6,0.78517 0.31169,1.44054 0.78516,1.86719 0.47346,0.42664 1.08725,0.63281 1.69726,0.63281 0.61001,0 1.22902,-0.20449 1.71094,-0.62891 0.48192,-0.42441 0.80663,-1.08156 0.80664,-1.87109 l 10e-6,-1.25 c 0,-0.75 -0.5,-1.25 -1.25,-1.25 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-1134,-16.999998)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g23520-0">
+ <path
+ inkscape:connector-curvature="0"
+ d="m 1461,518 c -1.3523,-0.0191 -1.3523,2.01913 0,2 h 2 c 1.3523,0.0191 1.3523,-2.01913 0,-2 z m -5,-1 v 7.5 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 11 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 V 517 h -1 v 7 h -10 v -7 z m 12.5,-1 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 v -3 c 0,-0.27613 -0.2239,-0.49997 -0.5,-0.5 h -13 c -0.2761,3e-5 -0.5,0.22387 -0.5,0.5 v 3 c 0,0.27613 0.2239,0.49997 0.5,0.5 z m -12.5,-3 h 12 v 2 h -12 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path23618-7"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccc" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g23658-7-6"
+ transform="translate(-1113,-79.999998)">
+ <path
+ id="path23654-6-8"
+ transform="translate(0,-21)"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1456,538 v 7.5 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 11 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 V 538 Z m 5,1 h 2 a 1.0001,1.0001 0 1 1 0,2 h -2 a 1.0001,1.0001 0 1 1 0,-2 z m -5.5,-6 c -0.2761,3e-5 -0.5,0.22387 -0.5,0.5 v 3 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 13 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 v -3 c 0,-0.27613 -0.2239,-0.49997 -0.5,-0.5 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g19402"
+ transform="translate(0,1.9921509e-6)"
+ style="fill:#ffffff">
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(-83.999995,42.000004)"
+ id="g19210">
+ <path
+ inkscape:connector-curvature="0"
+ d="m 348.48047,347 c -3.16361,0.009 -5.86504,2.31609 -6.39063,5.45117 -0.52558,3.13508 1.27477,6.20467 4.25977,7.25781 a 0.50005,0.50005 0 1 0 0.33203,-0.94336 c -2.52985,-0.89255 -4.05213,-3.48414 -3.60547,-6.14843 0.44666,-2.66429 2.72792,-4.6094 5.40821,-4.61719 2.68028,-0.008 4.97166,1.92234 5.43359,4.58398 0.46193,2.66165 -1.0456,5.26268 -3.57031,6.16993 a 0.50043111,0.50043111 0 1 0 0.33984,0.9414 c 2.9789,-1.07046 4.75841,-4.14926 4.21484,-7.28125 -0.54356,-3.13198 -3.25826,-5.42325 -6.42187,-5.41406 z m 0.0195,4.99999 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.64684 0.42097,1.19777 1,1.40625 v 0.59375 c -0.01,0.67616 1.00956,0.67616 1,0 v -0.59375 c 0.57902,-0.20848 1,-0.75941 1,-1.40625 0,-0.8225 -0.67751,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m -0.002,3.98438 c -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 1 c -0.01,0.67616 1.00957,0.67616 1,0 v -1 c 0.004,-0.28226 -0.22555,-0.51223 -0.50781,-0.50781 z m 0,3 c -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 1.00195 c -0.01,0.67616 1.00957,0.67616 1,0 v -1.00195 c 0.004,-0.28226 -0.22555,-0.51223 -0.50781,-0.50781 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="circle19208" />
</g>
</g>
- <g style="fill:#ffffff" id="g6505" transform="translate(84,-21)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 31.5,494 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 A 0.50005,0.50005 0 0 0 40.5,494 Z m 0.5,1 h 8 v 8 h -8 z" id="path6499" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 38,496 c -0.546362,0 -1,0.45364 -1,1 0,0.54636 0.453638,1 1,1 0.546362,0 1,-0.45364 1,-1 0,-0.54636 -0.453638,-1 -1,-1 z m -3.513672,1.05078 c -0.16529,0.005 -0.314526,0.10024 -0.388672,0.24805 l -2.75,5.5 c -0.148607,0.29892 0.06852,0.64991 0.402344,0.65039 h 5.75 c 0.340259,-0.001 0.55634,-0.36474 0.394531,-0.66406 l -3,-5.5 c -0.08111,-0.14873 -0.238867,-0.23931 -0.408203,-0.23438 z" id="path6501" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.69300022;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 29.492188,495.99219 A 0.50005,0.50005 0 0 0 29,496.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 30 v -8.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z m -2,2 A 0.50005,0.50005 0 0 0 27,498.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 28 v -8.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z" id="path6503" inkscape:connector-curvature="0"/>
- </g>
- <g id="g8734-0" transform="translate(-104.00001,-19.99995)" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 388.48047,74 c -0.15153,0.004 -0.29304,0.07659 -0.38477,0.197266 l -3.94922,3.949218 C 383.83169,78.461484 384.05468,78.99983 384.5,79 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 75 h 8 v 12 h -12 v -7 h -1 v 7.5 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 h 13 c 0.27613,-2.8e-5 0.49997,-0.223869 0.5,-0.5 v -13 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 h -9 c -0.005,-6.2e-5 -0.009,-6.2e-5 -0.0137,0 -6.7e-4,1.8e-5 -0.001,-2.1e-5 -0.002,0 -0.001,4.1e-5 -0.003,-5e-5 -0.004,0 z" transform="translate(-231.99999,418.99995)" id="path8730-7" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccc"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 56.515625,452 c 0.752,0 1.453818,0.239 2.023438,0.64453 C 59.424733,453.27508 60,454.31514 60,455.48438 V 458.5 c -3e-5,0.27537 -0.222677,0.4989 -0.498047,0.5 l -4.009765,0.008 c -0.27613,-3e-5 -0.49997,-0.22387 -0.5,-0.5 L 55,452.53516 v -0.002 -0.0352 C 55.001,452.22272 55.22466,452.00003 55.5,452 Z M 54,452 v 1 H 52.484375 C 51.099855,453 50,454.09985 50,455.48438 v 8.03124 C 50,464.90014 51.099855,466 52.484375,466 h 4.03125 C 57.900145,466 59,464.90014 59,463.51562 V 460 h 1 v 3.51562 C 60,465.43685 58.436855,467 56.515625,467 h -4.03125 C 50.563145,467 49,465.43686 49,463.51562 v -8.03124 C 49,453.56315 50.563145,452 52.484375,452 Z" id="path6557" inkscape:connector-curvature="0"/>
- <path id="path6596" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 92.484375,452 c -0.752,0 -1.453818,0.239 -2.023438,0.64453 C 89.575267,453.27508 89,454.31514 89,455.48438 V 458.5 c 3e-5,0.27537 0.222677,0.4989 0.498047,0.5 l 4.009765,0.008 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 L 94,452.53516 v -0.002 -0.0352 C 93.999,452.22272 93.77534,452.00003 93.5,452 Z M 95,452 v 1 h 1.515625 C 97.900145,453 99,454.09985 99,455.48438 v 8.03124 C 99,464.90014 97.900145,466 96.515625,466 h -4.03125 C 91.099855,466 90,464.90014 90,463.51562 V 460 h -1 v 3.51562 C 89,465.43685 90.563145,467 92.484375,467 h 4.03125 C 98.436855,467 100,465.43686 100,463.51562 v -8.03124 C 100,453.56315 98.436855,452 96.515625,452 Z m 6.47656,-0.97852 a 0.50005,0.50005 0 0 0 -0.31445,0.8711 c 0.58809,0.54453 0.8418,1.0856 0.8418,1.60156 L 102,459.5 a 0.50005,0.50005 0 1 0 1,0 l 0.004,-6.00586 c 0,-0.8509 -0.43179,-1.65971 -1.16211,-2.33594 a 0.50005,0.50005 0 0 0 -0.36524,-0.13672 z m 3.01563,2.01563 A 0.50005,0.50005 0 0 0 104,453.54297 v 4.05859 a 0.50005,0.50005 0 1 0 1,0 v -4.05859 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z" inkscape:connector-curvature="0"/>
- <path id="path6598" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 113.48438,452 C 111.56315,452 110,453.56315 110,455.48438 v 8.03124 c 0,1.92123 1.56315,3.48438 3.48438,3.48438 h 4.03125 C 119.43685,467 121,465.43685 121,463.51562 v -8.03124 C 121,453.56315 119.43685,452 117.51563,452 Z m 0,1 h 4.03125 c 1.38452,0 2.48437,1.09985 2.48437,2.48438 v 8.03124 C 120,464.90015 118.90015,466 117.51563,466 h -4.03125 C 112.09985,466 111,464.90015 111,463.51562 v -8.03124 C 111,454.09985 112.09985,453 113.48438,453 Z m 1.5625,1 C 114.47554,454 114,454.47555 114,455.04688 v 3.90624 c 0,0.57133 0.47554,1.04688 1.04688,1.04688 h 0.90625 C 116.52446,460 117,459.52445 117,458.95312 v -3.90624 C 117,454.47555 116.52446,454 115.95313,454 Z m 7.42968,-2.97852 a 0.50005,0.50005 0 0 0 -0.31445,0.8711 c 0.58809,0.54453 0.8418,1.0856 0.8418,1.60156 L 123,459.5 a 0.50005,0.50005 0 1 0 1,0 l 0.004,-6.00586 c 0,-0.8509 -0.43179,-1.65971 -1.16211,-2.33594 a 0.50005,0.50005 0 0 0 -0.36524,-0.13672 z m 3.01563,2.01563 A 0.50005,0.50005 0 0 0 125,453.54297 v 4.05859 a 0.50005,0.50005 0 1 0 1,0 v -4.05859 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z" inkscape:connector-curvature="0"/>
- <path id="path6600" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 138.51562,452 c 0.752,0 1.45382,0.239 2.02344,0.64453 0.88567,0.63055 1.46094,1.67061 1.46094,2.83985 V 458.5 c -3e-5,0.27537 -0.22268,0.4989 -0.49805,0.5 l -4.00976,0.008 c -0.27613,-3e-5 -0.49997,-0.22387 -0.5,-0.5 L 137,452.53516 v -0.002 -0.0352 c 0.001,-0.27524 0.22466,-0.49793 0.5,-0.49796 z M 136,452 v 1 h -1.51563 C 133.09986,453 132,454.09985 132,455.48438 v 8.03124 c 0,1.38452 1.09986,2.48438 2.48437,2.48438 h 4.03125 C 139.90014,466 141,464.90014 141,463.51562 V 460 h 1 v 3.51562 C 142,465.43685 140.43685,467 138.51562,467 h -4.03125 C 132.56315,467 131,465.43686 131,463.51562 v -8.03124 C 131,453.56315 132.56315,452 134.48437,452 Z m 7.47656,-0.97852 a 0.50005,0.50005 0 0 0 -0.31445,0.8711 c 0.58809,0.54453 0.8418,1.0856 0.8418,1.60156 L 144,459.5 a 0.50005,0.50005 0 1 0 1,0 l 0.004,-6.00586 c 0,-0.8509 -0.43179,-1.65971 -1.16211,-2.33594 a 0.50005,0.50005 0 0 0 -0.36524,-0.13672 z m 3.01563,2.01563 A 0.50005,0.50005 0 0 0 146,453.54297 v 4.05859 a 0.50005,0.50005 0 1 0 1,0 v -4.05859 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z" inkscape:connector-curvature="0"/>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g26277" transform="translate(273,-20.99999)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 203.5,284 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -8,8 A 0.50005,0.50005 0 0 0 195,292.5 l -0.008,5.00586 a 0.50005,0.50005 0 0 0 0.5,0.50195 L 208.5,298 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 208 v 12 l -12.00781,0.008 0.008,-4.30078 z" id="path23052" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 200.5,284 -5.00781,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 1 0 1,0 v -4.50195 L 200.5,285 a 0.50005,0.50005 0 1 0 0,-1 z" id="path23056" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 351.48242,557.01562 -0.96875,0.0156 c -0.0189,2.6e-4 -0.0378,0.002 -0.0566,0.004 -2.58289,0.33067 -4.57988,2.60038 -4.45117,5.21484 0.0288,0.58487 0.23179,1.09854 0.44141,1.5957 l -3.78516,3.78516 c -0.33708,0.30742 -0.60091,0.7293 -0.64063,1.23047 -0.0397,0.50117 0.17261,1.03979 0.625,1.49219 0.45357,0.45356 0.99596,0.65829 1.49219,0.61328 0.49624,-0.045 0.906,-0.30379 1.21485,-0.61328 l 3.80664,-3.80664 c 0.52791,0.22561 1.0693,0.4331 1.69336,0.45117 2.60313,0.0754 4.83493,-1.87377 5.11328,-4.46289 0.001,-0.0136 0.002,-0.0273 0.002,-0.041 l 0.0215,-0.9668 c 0.0105,-0.45102 -0.53451,-0.68424 -0.85351,-0.36523 L 352.29297,564 h -1.58594 L 349,562.29297 v -1.58594 l 2.84375,-2.83789 c 0.31756,-0.31766 0.0878,-0.86042 -0.36133,-0.85352 z" id="path18095" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccc"/>
- <g transform="translate(-1162,-873.9944)" style="display:inline;fill:#ffffff;enable-background:new" id="g17413-4-0">
- <path inkscape:connector-curvature="0" id="path17404-8-7" transform="translate(1162,873.9944)" d="m 164.48438,535.00586 a 0.50005,0.50005 0 0 0 -0.1211,0.0195 l -1.36328,0.3887 0.01,2.03906 1.63085,-0.46679 A 0.50005,0.50005 0 0 0 165,536.50586 v -1 a 0.50005,0.50005 0 0 0 -0.51562,-0.5 z M 162,535.70117 l -2,0.57031 0.01,2.03907 2,-0.57227 z m -3,0.85547 -1.63672,0.46875 A 0.50005,0.50005 0 0 0 157,537.50586 v 1 a 0.50005,0.50005 0 0 0 0.63672,0.48047 l 1.36914,-0.39063 z M 157,542 v 1 l 8.5,0.01 c 0.276,-5e-4 0.4995,-0.224 0.5,-0.5 -5e-4,-0.276 -0.224,-0.4995 -0.5,-0.5 z m -3,2.00586 v 5.49219 c 0,0.2761 0.2239,0.5 0.5,0.5 h 11 c 0.2761,0 0.5,-0.2239 0.5,-0.5 v -4.99219 c 0,-0.2761 -0.2239,-0.5 -0.5,-0.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 1315.5078,1411.9922 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1.5 1.5 h -1 z" id="path17409-0-0" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-574,-936.9944)" id="g17429-7-7" style="display:inline;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 1063.5078,1410.9922 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1.5 1.5 h -1 z" id="path17417-2-4" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" d="m 1340,1411 v 2 l 1.5,-0.01 1.75,-2 z m 4.5,-0.01 -1.75,2 h 2.75 l 1.7266,-2 z m 4,0 -1.7266,2 2.7266,0.01 c 0.276,-5e-4 0.4995,-0.224 0.5,-0.5 v -1 c -5e-4,-0.276 -0.224,-0.4995 -0.5,-0.5 z m -8.5,4.01 0.01,1.9922 -3.0098,0.01 v 5.4921 c 0,0.2761 0.2239,0.5 0.5,0.5 h 12 c 0.2761,0 0.5,-0.2239 0.5,-0.5 V 1415.5 c 0,-0.2761 -0.2239,-0.5 -0.5,-0.5 z m 2.5156,1 c 0.084,0 0.1663,0.026 0.2383,0.068 l 4.25,2.5 c 0.33,0.1931 0.33,0.6701 0,0.8632 l -4.25,2.5 c -0.3336,0.1966 -0.7545,-0.044 -0.7539,-0.4316 v -5 c -10e-5,-0.2823 0.2334,-0.51 0.5156,-0.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00157475;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" transform="translate(-273)" id="path17425-5"/>
- </g>
- <path sodipodi:nodetypes="cccccscccccccccccccccc" inkscape:connector-curvature="0" id="path17971-6" d="m 433.60156,411.10938 c -0.0348,2.9e-4 -0.0695,0.004 -0.10351,0.0117 -2.03912,0.46668 -3.49042,2.28707 -3.49219,4.37891 9e-4,0.50625 0.15089,0.99318 0.31836,1.46875 l -2.42774,2.42773 c -1.00968,1.00969 -1.01874,2.3133 -0.3125,3.01954 0.70624,0.70624 2.00985,0.69718 3.01954,-0.3125 l 2.42968,-2.42969 c 0.47476,0.16775 0.9595,0.31841 1.46485,0.32031 6.7e-4,0 0.001,0 0.002,0 2.10425,-9.3e-4 3.93168,-1.46897 4.38672,-3.52344 0.0316,-0.14237 -4.7e-4,-0.29146 -0.0879,-0.4082 l -0.64844,-0.86328 c -0.17598,-0.23372 -0.51414,-0.2671 -0.73242,-0.0723 L 435.31055,417 h -1.08008 L 433,415.56445 v -0.85742 l 1.85352,-1.85351 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -0.89063,-0.89062 c -0.0957,-0.0957 -0.22603,-0.14855 -0.36133,-0.14648 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path inkscape:connector-curvature="0" id="path18042-5" d="m 413.49609,411 c -1.31297,0 -2.2906,0.33758 -3.34961,1.39648 -1.07833,1.0783 -1.34444,2.83666 -0.73437,4.48438 l -2.51563,2.51562 c -1.00968,1.00969 -1.01874,2.3133 -0.3125,3.01954 0.70624,0.70624 2.00985,0.69718 3.01954,-0.3125 l 2.51757,-2.51758 c 1.64574,0.60684 3.4036,0.3464 4.48243,-0.73242 1.05892,-1.05893 1.39668,-2.03818 1.39257,-3.35547 a 0.50005,0.50005 0 0 0 -0.14648,-0.35157 l -1,-1 a 0.50005,0.50005 0 0 0 -0.70703,0 L 414.28906,416 h -0.58594 l -0.70703,-0.70703 v -0.58594 l 1.85352,-1.85351 a 0.50005,0.50005 0 0 0 0,-0.70704 l -1,-1 A 0.50005,0.50005 0 0 0 413.49609,411 Z m -0.18164,1.02539 0.47461,0.47461 -1.64648,1.64648 A 0.50005,0.50005 0 0 0 411.99609,414.5 v 1 a 0.50005,0.50005 0 0 0 0.14649,0.35352 l 1,1 A 0.50005,0.50005 0 0 0 413.49609,417 h 1 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 1.64648,-1.64649 0.47461,0.47461 c -0.0187,1.03267 -0.19304,1.58367 -1.07422,2.46484 -0.83209,0.8321 -2.35353,1.13617 -3.75195,0.47266 a 0.50005,0.50005 0 0 0 -0.56836,0.0977 l -2.67969,2.67968 c -0.74031,0.74032 -1.3117,0.60626 -1.60546,0.3125 -0.29376,-0.29376 -0.42782,-0.86515 0.3125,-1.60546 l 2.67773,-2.67774 a 0.50005,0.50005 0 0 0 0.0977,-0.56836 c -0.66677,-1.39852 -0.3581,-2.92122 0.47461,-3.7539 0.88058,-0.8805 1.43264,-1.05616 2.46093,-1.07813 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <g transform="translate(-104.9941,85.0365)" style="display:inline;fill:#ffffff;enable-background:new" id="g19021-7-6">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.70000005;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 448.5,284 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -10,1 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m 5,0 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m 5,0 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m -10,4 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -10,1 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m 5,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 5,0 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m -10,4 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -10,1 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m 5,0 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m 5,0 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z" id="ellipse19010-6-5" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g19186-9-4" transform="translate(-146.9941,85.0365)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 327.49805,368.03711 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 l -7,7 a 0.50005,0.50005 0 0 0 0,0.70703 l 7,7 a 0.50005,0.50005 0 0 0 0.70704,0 l 7.03124,-7 a 0.50005,0.50005 0 0 0 0,-0.70703 l -7.03124,-7 a 0.50005,0.50005 0 0 0 -0.36133,-0.14648 z m 0.008,1.20703 6.32226,6.29297 -6.32226,6.29297 -6.29297,-6.29297 z m 0,4.79297 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z" transform="translate(146.9941,-85.0365)" id="path19093-9-7" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g19103-5" transform="rotate(-90,394.50012,1587.5001)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 457.5,473 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -7.5 -0.5 c -0.5244,0 -1.02378,0.21717 -1.39258,0.57617 -0.3688,0.3592 -0.60742,0.86058 -0.60742,1.42578 V 485 c 10e-5,0.5302 0.21104,1.03916 0.58594,1.41406 C 447.96084,486.78896 448.4698,487 449,487 h 2.5 c 0.2762,0 0.5,-0.2238 0.5,-0.5 v -9 c 0,-0.2761 -0.2238,-0.4999 -0.5,-0.5 H 449 c -0.4523,0 -1,-0.47105 -1,-0.99805 0,-0.2635 0.13823,-0.51462 0.33203,-0.69922 C 448.52543,475.11903 448.775,475 449,475 h 8 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.5 v 5 h -1.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -4 v 1 h 4 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 A 0.50005,0.50005 0 0 0 460.5,482 H 460 v -5 h 0.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m 0,9 h 2 v 2 h -2 z" transform="rotate(90,394.50012,1587.5001)" id="path19040-4" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 428.25,452 c -0.6506,0 -1.23633,0.19727 -1.64453,0.60547 -0.4083,0.4081 -0.60567,0.99393 -0.60547,1.64453 v 9.5 c 2e-4,0.6505 0.19727,1.23643 0.60547,1.64453 C 427.01357,465.80273 427.5994,466 428.25,466 H 429 v -1 h -0.75 c -0.4574,0 -0.7477,-0.1227 -0.9375,-0.3125 -0.1898,-0.1898 -0.3124,-0.48 -0.3125,-0.9375 v -9.5 c -10e-5,-0.4574 0.1227,-0.7477 0.3125,-0.9375 C 427.5023,453.1227 427.7926,453 428.25,453 H 429 v -1 z m 8.75,0 v 1 h 0.75 c 0.4574,0 0.7477,0.1227 0.9375,0.3125 0.1898,0.1898 0.3125,0.4801 0.3125,0.9375 v 9.5 c 0,0.4574 -0.1227,0.7477 -0.3125,0.9375 C 438.4977,464.8773 438.2074,465 437.75,465 H 437 v 1 h 0.75 c 0.6506,0 1.23643,-0.19727 1.64453,-0.60547 C 439.80273,464.98643 440,464.4006 440,463.75 v -9.5 c 0,-0.6506 -0.19727,-1.23643 -0.60547,-1.64453 C 438.98643,452.19727 438.4006,452 437.75,452 Z m -4,4 v 2 h -1.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -2 v 1 h 2 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.5 v 2 h 1 v -2 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 461 h 2 v -1 h -2 v -1.5 A 0.50005,0.50005 0 0 0 435.5,458 H 434 v -2 z m -1,3 h 3 v 3 h -3 z" id="path19168-3" inkscape:connector-curvature="0"/>
- <path style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" d="m 411,536 v 4 h -2.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2.5 h -4 v 1 h 4 v 2.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2.5 v 4 h 1 v -4 h 2.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 544 h 4 v -1 h -4 v -2.5 A 0.50005,0.50005 0 0 0 414.5,540 H 412 v -4 z m -2,5 h 5 v 5 h -5 z m 2,2 v 1 h 1 v -1 z" id="rect19268-0" inkscape:connector-curvature="0"/>
- <g id="g9974-4-9" style="display:inline;fill:#ffffff;enable-background:new" transform="translate(-84.00001,21.000005)">
- <path sodipodi:nodetypes="ccccccccccccccccccccccc" inkscape:connector-curvature="0" id="path14003-8" transform="translate(84.000014,-21.000005)" d="M 308.06055,557 C 307.40848,557.63639 307,558.52103 307,559.5 c 0,1.5 0.75,2.5 2,3.14453 v 0.004 6.85156 c -0.0287,2.02848 3.02869,2.02848 3,0 v -6.85156 -0.002 c 1.28948,-0.66521 2,-1.64648 2,-3.14648 0,-0.97897 -0.40848,-1.86361 -1.06055,-2.5 H 312.91797 312 V 560 l -1,1 h -1 l -1,-1 2e-5,-3 z M 310,569 h 1 v 1 h -1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path sodipodi:nodetypes="ccccccccccccccscscsccc" id="path14013-6" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 387.00001,542 387,536.5 c 0.004,-0.28226 -0.22555,-0.51223 -0.50781,-0.50781 -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 l 10e-6,5.5 z m 0.75,2 H 388.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -4 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 0.75001 v 1 c -0.75,0 -1.25,0.5 -1.25,1.25 L 384,547.5 c -10e-6,0.78517 0.31169,1.44054 0.78516,1.86719 0.47346,0.42664 1.08725,0.63281 1.69726,0.63281 0.61001,0 1.22902,-0.20449 1.71094,-0.62891 0.48192,-0.42441 0.80663,-1.08156 0.80664,-1.87109 l 10e-6,-1.25 c 0,-0.75 -0.5,-1.25 -1.25,-1.25 z" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-1134,-16.999998)" style="display:inline;fill:#ffffff;enable-background:new" id="g23520-0">
- <path inkscape:connector-curvature="0" d="m 1461,518 c -1.3523,-0.0191 -1.3523,2.01913 0,2 h 2 c 1.3523,0.0191 1.3523,-2.01913 0,-2 z m -5,-1 v 7.5 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 11 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 V 517 h -1 v 7 h -10 v -7 z m 12.5,-1 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 v -3 c 0,-0.27613 -0.2239,-0.49997 -0.5,-0.5 h -13 c -0.2761,3e-5 -0.5,0.22387 -0.5,0.5 v 3 c 0,0.27613 0.2239,0.49997 0.5,0.5 z m -12.5,-3 h 12 v 2 h -12 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" id="path23618-7" sodipodi:nodetypes="cccccccccccccccccccccccccccccc"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g23658-7-6" transform="translate(-1113,-79.999998)">
- <path id="path23654-6-8" transform="translate(0,-21)" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 1456,538 v 7.5 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 11 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 V 538 Z m 5,1 h 2 a 1.0001,1.0001 0 1 1 0,2 h -2 a 1.0001,1.0001 0 1 1 0,-2 z m -5.5,-6 c -0.2761,3e-5 -0.5,0.22387 -0.5,0.5 v 3 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 13 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 v -3 c 0,-0.27613 -0.2239,-0.49997 -0.5,-0.5 z" inkscape:connector-curvature="0"/>
- </g>
- <g id="g19402" transform="translate(0,1.9921509e-6)" style="fill:#ffffff">
- <g style="display:inline;fill:#ffffff;enable-background:new" transform="translate(-83.999995,42.000004)" id="g19210">
- <path inkscape:connector-curvature="0" d="m 348.48047,347 c -3.16361,0.009 -5.86504,2.31609 -6.39063,5.45117 -0.52558,3.13508 1.27477,6.20467 4.25977,7.25781 a 0.50005,0.50005 0 1 0 0.33203,-0.94336 c -2.52985,-0.89255 -4.05213,-3.48414 -3.60547,-6.14843 0.44666,-2.66429 2.72792,-4.6094 5.40821,-4.61719 2.68028,-0.008 4.97166,1.92234 5.43359,4.58398 0.46193,2.66165 -1.0456,5.26268 -3.57031,6.16993 a 0.50043111,0.50043111 0 1 0 0.33984,0.9414 c 2.9789,-1.07046 4.75841,-4.14926 4.21484,-7.28125 -0.54356,-3.13198 -3.25826,-5.42325 -6.42187,-5.41406 z m 0.0195,4.99999 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.64684 0.42097,1.19777 1,1.40625 v 0.59375 c -0.01,0.67616 1.00956,0.67616 1,0 v -0.59375 c 0.57902,-0.20848 1,-0.75941 1,-1.40625 0,-0.8225 -0.67751,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m -0.002,3.98438 c -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 1 c -0.01,0.67616 1.00957,0.67616 1,0 v -1 c 0.004,-0.28226 -0.22555,-0.51223 -0.50781,-0.50781 z m 0,3 c -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 1.00195 c -0.01,0.67616 1.00957,0.67616 1,0 v -1.00195 c 0.004,-0.28226 -0.22555,-0.51223 -0.50781,-0.50781 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" id="circle19208"/>
- </g>
- </g>
- <g id="g19394" transform="translate(0,1.9921509e-6)" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" d="m 390.5,416 c -0.98118,0 -1.79306,0.19786 -2.45312,0.51562 -0.008,0.17574 -0.0332,0.34151 -0.0332,0.52149 0,4.06772 2.58548,6.61176 5.30078,6.95117 2.02213,0.29647 2.40413,-2.76745 0.3711,-2.97656 -1.2847,-0.16059 -2.67188,-1.04233 -2.67188,-3.97461 0,-0.37546 0.0235,-0.72058 0.0664,-1.03711 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" id="path19340" sodipodi:nodetypes="scsccscs"/>
- <path id="path5291" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 395,410 c -1.86938,0 -3.40407,0.68718 -4.4375,1.85938 -0.30774,0.34905 -0.56557,0.74269 -0.7832,1.16601 C 390.01692,413.00864 390.25738,413 390.5,413 h 0.44922 c 0.11262,-0.16825 0.23234,-0.32999 0.36328,-0.47852 C 392.15407,411.56692 393.36938,411 395,411 h 0.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 z m -4.5,4 c -1.84524,0 -3.47115,0.52889 -4.64258,1.5625 C 384.686,416.59611 384,418.13095 384,420 v 0.5 a 0.50005,0.50005 0 1 0 1,0 V 420 c 0,-1.63095 0.564,-2.84611 1.51758,-3.6875 C 387.47115,415.47111 388.84524,415 390.5,415 h 1.00781 c 3.27827,0 5.29896,2.17669 5.49805,3.57031 a 0.50005,0.50005 0 1 0 0.98828,-0.14062 C 397.69323,416.32331 395.21551,414 391.50781,414 Z" inkscape:connector-curvature="0"/>
- </g>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" transform="matrix(0.93036376,0,0,1.0023904,215.63778,150.90833)" id="g19530" style="display:inline;fill:#ffffff;stroke-width:1.03551209;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.03551209;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 30.216797,30 a 0.51780782,0.51780782 0 0 0 -0.337891,0.126953 l -3.761718,3.242188 c -1.859424,1.602556 -3.136719,3.536893 -3.136719,6.128906 a 0.51780782,0.51780782 0 1 0 1.035156,0 c 0,-2.262051 1.045193,-3.852838 2.777344,-5.345703 l 3.615234,-3.115235 h 0.152344 l 3.617187,3.115235 a 0.51780782,0.51780782 0 0 0 0,0.002 c 1.732844,1.491631 2.775391,3.081554 2.775391,5.34375 a 0.5185545,0.5185545 0 1 0 1.037109,0 c 0,-2.591868 -1.275948,-4.527155 -3.136718,-6.128906 L 31.091797,30.126953 A 0.51780782,0.51780782 0 0 0 30.753906,30 Z" id="path19532" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-84,22.000001)" id="g13033" style="display:inline;fill:#ffffff;enable-background:new">
- <path sodipodi:nodetypes="ccccccccsssss" inkscape:connector-curvature="0" id="path12959" d="m 473.49999,411 -2.99609,0.006 c -0.2754,6.1e-4 -0.49976,0.22265 -0.5,0.49805 l -0.004,8.45884 c 0,1.02328 0.80629,2.03747 2,2.03711 1.19534,0 1.99609,-1.02155 1.99609,-2.04297 l 0.004,-8.45703 c -1.8e-4,-0.27638 -0.22362,-0.50048 -0.5,-0.5 z m -1.5,8 c 0.55228,0 1,0.44772 1,1 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.55228 0.44772,-1 1,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path sodipodi:nodetypes="cccccccccc" inkscape:connector-curvature="0" id="path12972" d="m 478.14648,418.14648 -3,3 c -0.31399,0.31533 -0.0915,0.85354 0.35352,0.85352 h 3 2 c 0.27591,-1.9e-4 0.49982,-0.22409 0.5,-0.5 v -3 c -7e-5,-0.28163 -0.23215,-0.50794 -0.51367,-0.5 h -2 c -0.12731,0.004 -0.24956,0.0566 -0.33985,0.14648 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path sodipodi:nodetypes="cccccccccc" inkscape:connector-curvature="0" id="path12974" d="m 477.49257,412.00014 c -0.12999,0.002 -0.25408,0.0546 -0.34596,0.14655 l -2.00065,1.99942 c -0.094,0.094 -0.14673,0.22146 -0.14655,0.35436 v 4.0001 c -2e-5,0.4458 0.53925,0.66879 0.85409,0.35316 l 3.99954,-4.00067 c 0.19472,-0.19518 0.19472,-0.51115 0,-0.70633 l -2.00009,-2.00004 c -0.0954,-0.0955 -0.2254,-0.14835 -0.36038,-0.14655 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g12998" transform="translate(1.1628419e-6,-21)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 157.5,205 c 2.47936,0 4.5,2.02063 4.5,4.5 0,2.47937 -2.02064,4.5 -4.5,4.5 -2.47936,0 -4.5,-2.02063 -4.5,-4.5 0,-2.47937 2.02064,-4.5 4.5,-4.5 z m 0,1 c -1.93892,0 -3.5,1.56107 -3.5,3.5 0,1.93893 1.56108,3.5 3.5,3.5 1.93892,0 3.5,-1.56107 3.5,-3.5 0,-1.93893 -1.56108,-3.5 -3.5,-3.5 z" id="ellipse12887" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 162.86914,200.01562 c 2.18302,0.17973 3.92401,1.9135 4.11328,4.09571 0.18928,2.18221 -1.22622,4.18928 -3.3457,4.74219 a 0.50005,0.50005 0 1 1 -0.25391,-0.9668 c 1.65432,-0.43156 2.75125,-1.98618 2.60352,-3.68945 -0.14774,-1.70328 -1.49531,-3.04527 -3.19922,-3.18555 -1.70391,-0.14028 -3.25342,0.96296 -3.67773,2.61914 a 0.50005,0.50005 0 1 1 -0.96876,-0.24805 c 0.54363,-2.12187 2.5455,-3.54691 4.72852,-3.36719 z" id="path12892" inkscape:connector-curvature="0"/>
- <path style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" d="m 159.00001,209.49817 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z" id="circle12960" inkscape:connector-curvature="0"/>
- <path style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" d="m 164.00001,204.49817 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z" id="circle12962" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g12986" transform="translate(1.1628419e-6,-21)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 199.5,205 c 2.47936,0 4.5,2.02063 4.5,4.5 0,2.47937 -2.02064,4.5 -4.5,4.5 -2.47936,0 -4.5,-2.02063 -4.5,-4.5 0,-2.47937 2.02064,-4.5 4.5,-4.5 z m 0,1 c -1.93892,0 -3.5,1.56107 -3.5,3.5 0,1.93893 1.56108,3.5 3.5,3.5 1.93892,0 3.5,-1.56107 3.5,-3.5 0,-1.93893 -1.56108,-3.5 -3.5,-3.5 z" id="ellipse12910" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 204.86914,200.01562 c 2.18302,0.17973 3.92401,1.9135 4.11328,4.09571 0.18928,2.18221 -1.22622,4.18928 -3.3457,4.74219 a 0.50005,0.50005 0 1 1 -0.25391,-0.9668 c 1.65432,-0.43156 2.75125,-1.98618 2.60352,-3.68945 -0.14774,-1.70328 -1.49531,-3.04527 -3.19922,-3.18555 -1.70391,-0.14028 -3.25342,0.96296 -3.67773,2.61914 a 0.50005,0.50005 0 1 1 -0.96876,-0.24805 c 0.54363,-2.12187 2.5455,-3.54691 4.72852,-3.36719 z" id="path12915" inkscape:connector-curvature="0"/>
- <path style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" d="m 201.00001,209.49817 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z" id="circle12964" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(1.1628419e-6)" style="display:inline;fill:#ffffff;enable-background:new" id="g13014" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 111.5,179 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 1 0 1,0 V 180 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 z m 9.00781,0 a 0.50005,0.50005 0 1 0 0,1 h 3.5 v 3.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -9.01562,9 A 0.50005,0.50005 0 0 0 111,188.50781 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 H 112 v -3.5 A 0.50005,0.50005 0 0 0 111.49219,188 Z M 124.5,188 a 0.50005,0.50005 0 0 0 -0.49219,0.50781 v 3.5 h -3.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4 A 0.50005,0.50005 0 0 0 124.5,188 Z" id="path12919" inkscape:connector-curvature="0"/>
- <path style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" d="m 120,186.00359 a 1.99635,1.99635 0 0 1 -1.99635,1.99635 1.99635,1.99635 0 0 1 -1.99635,-1.99635 1.99635,1.99635 0 0 1 1.99635,-1.99635 1.99635,1.99635 0 0 1 1.99635,1.99635 z" id="path12956" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new" id="g22801-1" transform="translate(696,857.9975)">
- <path id="path22797-9" d="m -239.5,-446.99219 c -2.47912,0 -4.5,2.01847 -4.5,4.4961 0,2.47763 2.02088,4.49609 4.5,4.49609 2.47912,0 4.5,-2.01846 4.5,-4.49609 0,-2.47763 -2.02088,-4.4961 -4.5,-4.4961 z m 0,1.1875 c 1.83471,0 3.31055,1.47622 3.31055,3.3086 0,1.83238 -1.47584,3.30859 -3.31055,3.30859 -1.8347,0 -3.31055,-1.47621 -3.31055,-3.30859 0,-1.83238 1.47585,-3.3086 3.31055,-3.3086 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0"/>
- </g>
- <g id="g22943" style="display:inline;fill:#ffffff;enable-background:new" transform="translate(-2.1686213e-6,9.0033549e-6)">
- <g style="fill:#ffffff" id="g12942" transform="translate(-20,18)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path inkscape:connector-curvature="0" id="path12932" d="m 155.50195,121.99414 a 0.50005,0.50005 0 0 0 -0.36133,0.85352 C 156.37329,124.12237 157.775,126 160.5,126 c 2.725,0 4.12681,-1.87774 5.35938,-3.15234 a 0.50005,0.50005 0 1 0 -0.71876,-0.69532 C 163.83477,123.50274 162.775,125 160.5,125 c -2.275,0 -3.33487,-1.49737 -4.64062,-2.84766 a 0.50005,0.50005 0 0 0 -0.35743,-0.1582 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
- <path sodipodi:nodetypes="ccccccccc" inkscape:connector-curvature="0" id="path12946" d="m 132.50195,143 c -0.35971,-0.001 -0.6028,0.36671 -0.46093,0.69727 l 3,7 c 0.18151,0.42185 0.78799,0.39645 0.93359,-0.0391 l 0.91992,-2.76367 2.76367,-0.91992 c 0.43555,-0.1456 0.46095,-0.75208 0.0391,-0.93359 l -7,-3 c -0.0617,-0.0266 -0.12814,-0.0406 -0.19535,-0.041 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
- <g transform="translate(0.99999783,9.0033549e-6)" id="g22948" style="display:inline;fill:#ffffff;enable-background:new">
- <path inkscape:connector-curvature="0" id="path12633" d="m 155.50195,139.99414 a 0.50005,0.50005 0 0 0 -0.36133,0.85352 C 156.37329,142.12237 157.775,144 160.5,144 c 2.725,0 4.12681,-1.87774 5.35938,-3.15234 a 0.50005,0.50005 0 1 0 -0.71876,-0.69532 C 163.83477,141.50274 162.775,143 160.5,143 c -2.275,0 -3.33487,-1.49737 -4.64062,-2.84766 a 0.50005,0.50005 0 0 0 -0.35743,-0.1582 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path inkscape:connector-curvature="0" id="path12645" d="m 152.50195,143 a 0.50005,0.50005 0 0 0 -0.46093,0.69727 l 3,7 a 0.50005,0.50005 0 1 0 0.91796,-0.39454 l -2.50781,-5.85156 5.85156,2.50781 a 0.50005,0.50005 0 1 0 0.39454,-0.91796 l -7,-3 A 0.50005,0.50005 0 0 0 152.50195,143 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
- <g style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new" id="g14837" transform="translate(-210,-315)">
- <path inkscape:connector-curvature="0" id="path14829" d="m 415.5,452.00781 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00251,0 -2.00529,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66921,0 -1.33859,10e-6 -2.00781,0 z m -10.5,9 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00251,0 -2.00529,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66921,0 -1.33859,10e-6 -2.00781,0 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path inkscape:connector-curvature="0" id="path22198" d="m 411.50391,454 a 0.50005,0.50005 0 0 0 -0.35743,0.14648 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 0.85156,-0.85157 0.78515,0.006 a 0.50005,0.50005 0 1 0 0.006,-1 z m -3.01368,2.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 A 0.50005,0.50005 0 0 0 407,458.5 v 1.00781 a 0.50005,0.50005 0 1 0 1,0 v -0.80078 l 0.85352,-0.85351 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m 7.99415,0.9961 A 0.50005,0.50005 0 0 0 415.99219,458.5 v 0.80078 l -0.85352,0.85352 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 0.14649,-0.35352 V 458.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -3.00196,4.00976 a 0.50005,0.50005 0 0 0 -0.34375,0.15235 l -0.85156,0.85156 -0.7832,-0.006 a 0.50005,0.50005 0 1 0 -0.008,1 l 0.99219,0.008 a 0.50005,0.50005 0 0 0 0.35742,-0.14648 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36328,-0.85938 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
- <rect style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" id="rect5375" width="6" height="5" x="218" y="119"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 303.5,600 c -1.92707,0 -3.5,1.57293 -3.5,3.5 v 0.5 h 1 v -0.5 c 0,-1.38663 1.11337,-2.5 2.5,-2.5 1.38663,0 2.5,1.11337 2.5,2.5 v 1.5 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 8 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 313.5,605 H 307 v -1.5 c 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 2.5,6 h 7 v 4 h -7 z m 3,1 v 2 h 1 v -2 z" id="path19950-6" inkscape:connector-curvature="0"/>
- <g transform="matrix(0.86666667,0,0,0.86666667,39.533341,-302.8)" id="g12476-7-0" style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.15384614;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path inkscape:connector-curvature="0" id="path12470-5-6" d="m 454,555.92383 c -4.45393,0 -8.07617,3.62224 -8.07617,8.07617 0,4.45393 3.62224,8.07617 8.07617,8.07617 4.45393,0 8.07617,-3.62224 8.07617,-8.07617 0,-4.45393 -3.62224,-8.07617 -8.07617,-8.07617 z m 0,1.15234 c 3.83034,0 6.92383,3.09349 6.92383,6.92383 0,3.83034 -3.09349,6.92383 -6.92383,6.92383 -3.83034,0 -6.92383,-3.09349 -6.92383,-6.92383 0,-3.83034 3.09349,-6.92383 6.92383,-6.92383 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.15384614;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path sodipodi:nodetypes="ccccc" inkscape:connector-curvature="0" id="path12474-5-2" d="m 454,561.69141 c -1.26767,-10e-6 -2.3086,1.04092 -2.30859,2.30859 -1e-5,1.26767 1.04092,2.3086 2.30859,2.30859 1.26767,10e-6 2.3086,-1.04092 2.30859,-2.30859 1e-5,-1.26767 -1.04092,-2.3086 -2.30859,-2.30859 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.15384603;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path20496-2" d="m 454,558.23047 c -3.17259,10e-6 -5.76953,2.59694 -5.76953,5.76953 -1e-5,3.17259 2.59694,5.76952 5.76953,5.76953 3.1726,10e-6 5.76954,-2.59693 5.76953,-5.76953 0,-3.1726 -2.59693,-5.76954 -5.76953,-5.76953 z m 0,2.30859 c 1.92543,0 3.46094,1.53551 3.46094,3.46094 0,1.92543 -1.53551,3.46094 -3.46094,3.46094 -1.92542,-1e-5 -3.46094,-1.53552 -3.46094,-3.46094 0,-1.92542 1.53552,-3.46093 3.46094,-3.46094 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.9;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.30769229;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.15384614;enable-background:new" id="g12520-1-5" transform="matrix(0.86666667,0,0,0.86666667,60.533341,-302.8)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path inkscape:connector-curvature="0" id="path12513-1-0" d="m 454,555.92383 c -4.45393,0 -8.07617,3.62224 -8.07617,8.07617 0,4.45393 3.62224,8.07617 8.07617,8.07617 4.45393,0 8.07617,-3.62224 8.07617,-8.07617 0,-4.45393 -3.62224,-8.07617 -8.07617,-8.07617 z m 0,1.15234 c 3.83034,0 6.92383,3.09349 6.92383,6.92383 0,3.83034 -3.09349,6.92383 -6.92383,6.92383 -3.83034,0 -6.92383,-3.09349 -6.92383,-6.92383 0,-3.83034 3.09349,-6.92383 6.92383,-6.92383 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.15384614;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path20498-6" d="m 454,558.23047 c -3.17259,0 -5.76953,2.59694 -5.76953,5.76953 -1e-5,3.1726 2.59693,5.76953 5.76953,5.76953 3.1726,0 5.76954,-2.59693 5.76953,-5.76953 0,-3.17259 -2.59694,-5.76953 -5.76953,-5.76953 z m 0,2.30859 c 1.92542,0 3.46093,1.53552 3.46094,3.46094 0,1.92543 -1.53551,3.46094 -3.46094,3.46094 -1.92543,0 -3.46094,-1.53551 -3.46094,-3.46094 10e-6,-1.92542 1.53552,-3.46094 3.46094,-3.46094 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.30769229;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g5294-1-7-1" transform="translate(41.999998,-357)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path sodipodi:nodetypes="sssss" inkscape:connector-curvature="0" id="path5168-0-2-8" d="m 433,541 c -1.09865,0 -2,0.90135 -2,2 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 0,-1.09865 -0.90135,-2 -2,-2 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path5260-6-8-7" d="m 433.08008,537.98438 c -2.77576,0 -5.01953,2.26323 -5.01953,5.01562 0,2.7524 2.24277,5.02307 5.02148,5.01562 L 439.00195,548 a 1.0001,1.0001 0 1 0 -0.004,-2 l -5.91993,0.0156 c -1.70285,0.005 -3.01757,-1.33278 -3.01757,-3.01562 0,-1.68217 1.31272,-3.01459 3.01757,-3.01562 L 438.99805,540 a 1.0001,1.0001 0 1 0 0.004,-2 l -5.91992,-0.0156 a 1.0001,1.0001 0 0 0 -0.002,0 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.9;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path12602-0-0" d="m 433,536 c -2.50006,0 -4.81247,1.33488 -6.0625,3.5 -1.25002,2.16512 -1.25002,4.83488 0,7 1.25003,2.16512 3.56244,3.5 6.0625,3.5 h 6.5 a 0.50005,0.50005 0 1 0 0,-1 H 433 c -2.1444,0 -4.12312,-1.1429 -5.19531,-3 -1.0722,-1.8571 -1.0722,-4.1429 0,-6 1.07219,-1.8571 3.05091,-3 5.19531,-3 h 6.5 a 0.50005,0.50005 0 1 0 0,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <path inkscape:connector-curvature="0" id="path20009-7" d="m 328.5,600 c -1.92707,0 -3.5,1.57293 -3.5,3.5 v 1.5 h -0.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 8 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 332 v -1.5 c 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 0,1 c 1.38663,0 2.5,1.11337 2.5,2.5 v 1.5 h -5 v -1.5 c 0,-1.38663 1.11337,-2.5 2.5,-2.5 z m -0.5,6 h 1 v 1 1 h -1 v -1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path id="path20615" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 345.50001,453 c -1.92707,0 -3.5,1.57293 -3.5,3.5 v 0.5 h 1 v -0.5 c 0,-1.38663 1.11337,-2.5 2.5,-2.5 1.38663,0 2.5,1.11337 2.5,2.5 v 1.5 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 8 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -6.5 v -1.5 c 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 2.5,6 h 7 v 4 h -7 z m 3,0.99999 h 1 V 462 h -1 z" inkscape:connector-curvature="0"/>
- <g id="g20632" style="display:inline;fill:#ffffff;enable-background:new" transform="translate(696.00001,793)">
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="g20623" transform="translate(-740.00001,-750)" style="display:inline;fill:#ffffff;enable-background:new">
- <path inkscape:connector-curvature="0" id="path20621" transform="translate(594,-43.000004)" d="m -179.5,453 c -1.92707,0 -3.5,1.57293 -3.5,3.5 v 1.5 h -0.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 8 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -0.5 v -1.5 c 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 0,1 c 1.38663,0 2.5,1.11337 2.5,2.5 v 1.5 h -5 v -1.5 c 0,-1.38663 1.11337,-2.5 2.5,-2.5 z m -0.5,6 h 1 v 1 1 h -1 v -1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
+ <g
+ id="g19394"
+ transform="translate(0,1.9921509e-6)"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ d="m 390.5,416 c -0.98118,0 -1.79306,0.19786 -2.45312,0.51562 -0.008,0.17574 -0.0332,0.34151 -0.0332,0.52149 0,4.06772 2.58548,6.61176 5.30078,6.95117 2.02213,0.29647 2.40413,-2.76745 0.3711,-2.97656 -1.2847,-0.16059 -2.67188,-1.04233 -2.67188,-3.97461 0,-0.37546 0.0235,-0.72058 0.0664,-1.03711 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="path19340"
+ sodipodi:nodetypes="scsccscs" />
+ <path
+ id="path5291"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 395,410 c -1.86938,0 -3.40407,0.68718 -4.4375,1.85938 -0.30774,0.34905 -0.56557,0.74269 -0.7832,1.16601 C 390.01692,413.00864 390.25738,413 390.5,413 h 0.44922 c 0.11262,-0.16825 0.23234,-0.32999 0.36328,-0.47852 C 392.15407,411.56692 393.36938,411 395,411 h 0.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 z m -4.5,4 c -1.84524,0 -3.47115,0.52889 -4.64258,1.5625 C 384.686,416.59611 384,418.13095 384,420 v 0.5 a 0.50005,0.50005 0 1 0 1,0 V 420 c 0,-1.63095 0.564,-2.84611 1.51758,-3.6875 C 387.47115,415.47111 388.84524,415 390.5,415 h 1.00781 c 3.27827,0 5.29896,2.17669 5.49805,3.57031 a 0.50005,0.50005 0 1 0 0.98828,-0.14062 C 397.69323,416.32331 395.21551,414 391.50781,414 Z"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="matrix(0.93036376,0,0,1.0023904,215.63778,150.90833)"
+ id="g19530"
+ style="display:inline;fill:#ffffff;stroke-width:1.03551209;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.03551209;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 30.216797,30 a 0.51780782,0.51780782 0 0 0 -0.337891,0.126953 l -3.761718,3.242188 c -1.859424,1.602556 -3.136719,3.536893 -3.136719,6.128906 a 0.51780782,0.51780782 0 1 0 1.035156,0 c 0,-2.262051 1.045193,-3.852838 2.777344,-5.345703 l 3.615234,-3.115235 h 0.152344 l 3.617187,3.115235 a 0.51780782,0.51780782 0 0 0 0,0.002 c 1.732844,1.491631 2.775391,3.081554 2.775391,5.34375 a 0.5185545,0.5185545 0 1 0 1.037109,0 c 0,-2.591868 -1.275948,-4.527155 -3.136718,-6.128906 L 31.091797,30.126953 A 0.51780782,0.51780782 0 0 0 30.753906,30 Z"
+ id="path19532"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-84,22.000001)"
+ id="g13033"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ sodipodi:nodetypes="ccccccccsssss"
+ inkscape:connector-curvature="0"
+ id="path12959"
+ d="m 473.49999,411 -2.99609,0.006 c -0.2754,6.1e-4 -0.49976,0.22265 -0.5,0.49805 l -0.004,8.45884 c 0,1.02328 0.80629,2.03747 2,2.03711 1.19534,0 1.99609,-1.02155 1.99609,-2.04297 l 0.004,-8.45703 c -1.8e-4,-0.27638 -0.22362,-0.50048 -0.5,-0.5 z m -1.5,8 c 0.55228,0 1,0.44772 1,1 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.55228 0.44772,-1 1,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ sodipodi:nodetypes="cccccccccc"
+ inkscape:connector-curvature="0"
+ id="path12972"
+ d="m 478.14648,418.14648 -3,3 c -0.31399,0.31533 -0.0915,0.85354 0.35352,0.85352 h 3 2 c 0.27591,-1.9e-4 0.49982,-0.22409 0.5,-0.5 v -3 c -7e-5,-0.28163 -0.23215,-0.50794 -0.51367,-0.5 h -2 c -0.12731,0.004 -0.24956,0.0566 -0.33985,0.14648 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ sodipodi:nodetypes="cccccccccc"
+ inkscape:connector-curvature="0"
+ id="path12974"
+ d="m 477.49257,412.00014 c -0.12999,0.002 -0.25408,0.0546 -0.34596,0.14655 l -2.00065,1.99942 c -0.094,0.094 -0.14673,0.22146 -0.14655,0.35436 v 4.0001 c -2e-5,0.4458 0.53925,0.66879 0.85409,0.35316 l 3.99954,-4.00067 c 0.19472,-0.19518 0.19472,-0.51115 0,-0.70633 l -2.00009,-2.00004 c -0.0954,-0.0955 -0.2254,-0.14835 -0.36038,-0.14655 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12998"
+ transform="translate(1.1628419e-6,-21)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 157.5,205 c 2.47936,0 4.5,2.02063 4.5,4.5 0,2.47937 -2.02064,4.5 -4.5,4.5 -2.47936,0 -4.5,-2.02063 -4.5,-4.5 0,-2.47937 2.02064,-4.5 4.5,-4.5 z m 0,1 c -1.93892,0 -3.5,1.56107 -3.5,3.5 0,1.93893 1.56108,3.5 3.5,3.5 1.93892,0 3.5,-1.56107 3.5,-3.5 0,-1.93893 -1.56108,-3.5 -3.5,-3.5 z"
+ id="ellipse12887"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 162.86914,200.01562 c 2.18302,0.17973 3.92401,1.9135 4.11328,4.09571 0.18928,2.18221 -1.22622,4.18928 -3.3457,4.74219 a 0.50005,0.50005 0 1 1 -0.25391,-0.9668 c 1.65432,-0.43156 2.75125,-1.98618 2.60352,-3.68945 -0.14774,-1.70328 -1.49531,-3.04527 -3.19922,-3.18555 -1.70391,-0.14028 -3.25342,0.96296 -3.67773,2.61914 a 0.50005,0.50005 0 1 1 -0.96876,-0.24805 c 0.54363,-2.12187 2.5455,-3.54691 4.72852,-3.36719 z"
+ id="path12892"
+ inkscape:connector-curvature="0" />
+ <path
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="m 159.00001,209.49817 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z"
+ id="circle12960"
+ inkscape:connector-curvature="0" />
+ <path
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="m 164.00001,204.49817 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z"
+ id="circle12962"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12986"
+ transform="translate(1.1628419e-6,-21)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 199.5,205 c 2.47936,0 4.5,2.02063 4.5,4.5 0,2.47937 -2.02064,4.5 -4.5,4.5 -2.47936,0 -4.5,-2.02063 -4.5,-4.5 0,-2.47937 2.02064,-4.5 4.5,-4.5 z m 0,1 c -1.93892,0 -3.5,1.56107 -3.5,3.5 0,1.93893 1.56108,3.5 3.5,3.5 1.93892,0 3.5,-1.56107 3.5,-3.5 0,-1.93893 -1.56108,-3.5 -3.5,-3.5 z"
+ id="ellipse12910"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 204.86914,200.01562 c 2.18302,0.17973 3.92401,1.9135 4.11328,4.09571 0.18928,2.18221 -1.22622,4.18928 -3.3457,4.74219 a 0.50005,0.50005 0 1 1 -0.25391,-0.9668 c 1.65432,-0.43156 2.75125,-1.98618 2.60352,-3.68945 -0.14774,-1.70328 -1.49531,-3.04527 -3.19922,-3.18555 -1.70391,-0.14028 -3.25342,0.96296 -3.67773,2.61914 a 0.50005,0.50005 0 1 1 -0.96876,-0.24805 c 0.54363,-2.12187 2.5455,-3.54691 4.72852,-3.36719 z"
+ id="path12915"
+ inkscape:connector-curvature="0" />
+ <path
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="m 201.00001,209.49817 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z"
+ id="circle12964"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(1.1628419e-6)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13014"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 111.5,179 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 1 0 1,0 V 180 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 z m 9.00781,0 a 0.50005,0.50005 0 1 0 0,1 h 3.5 v 3.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -9.01562,9 A 0.50005,0.50005 0 0 0 111,188.50781 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 H 112 v -3.5 A 0.50005,0.50005 0 0 0 111.49219,188 Z M 124.5,188 a 0.50005,0.50005 0 0 0 -0.49219,0.50781 v 3.5 h -3.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4 A 0.50005,0.50005 0 0 0 124.5,188 Z"
+ id="path12919"
+ inkscape:connector-curvature="0" />
+ <path
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="m 120,186.00359 a 1.99635,1.99635 0 0 1 -1.99635,1.99635 1.99635,1.99635 0 0 1 -1.99635,-1.99635 1.99635,1.99635 0 0 1 1.99635,-1.99635 1.99635,1.99635 0 0 1 1.99635,1.99635 z"
+ id="path12956"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ id="g22801-1"
+ transform="translate(696,857.9975)">
+ <path
+ id="path22797-9"
+ d="m -239.5,-446.99219 c -2.47912,0 -4.5,2.01847 -4.5,4.4961 0,2.47763 2.02088,4.49609 4.5,4.49609 2.47912,0 4.5,-2.01846 4.5,-4.49609 0,-2.47763 -2.02088,-4.4961 -4.5,-4.4961 z m 0,1.1875 c 1.83471,0 3.31055,1.47622 3.31055,3.3086 0,1.83238 -1.47584,3.30859 -3.31055,3.30859 -1.8347,0 -3.31055,-1.47621 -3.31055,-3.30859 0,-1.83238 1.47585,-3.3086 3.31055,-3.3086 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g22943"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(-2.1686213e-6,9.0033549e-6)">
+ <g
+ style="fill:#ffffff"
+ id="g12942"
+ transform="translate(-20,18)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ inkscape:connector-curvature="0"
+ id="path12932"
+ d="m 155.50195,121.99414 a 0.50005,0.50005 0 0 0 -0.36133,0.85352 C 156.37329,124.12237 157.775,126 160.5,126 c 2.725,0 4.12681,-1.87774 5.35938,-3.15234 a 0.50005,0.50005 0 1 0 -0.71876,-0.69532 C 163.83477,123.50274 162.775,125 160.5,125 c -2.275,0 -3.33487,-1.49737 -4.64062,-2.84766 a 0.50005,0.50005 0 0 0 -0.35743,-0.1582 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="path12946"
+ d="m 132.50195,143 c -0.35971,-0.001 -0.6028,0.36671 -0.46093,0.69727 l 3,7 c 0.18151,0.42185 0.78799,0.39645 0.93359,-0.0391 l 0.91992,-2.76367 2.76367,-0.91992 c 0.43555,-0.1456 0.46095,-0.75208 0.0391,-0.93359 l -7,-3 c -0.0617,-0.0266 -0.12814,-0.0406 -0.19535,-0.041 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ transform="translate(0.99999783,9.0033549e-6)"
+ id="g22948"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ id="path12633"
+ d="m 155.50195,139.99414 a 0.50005,0.50005 0 0 0 -0.36133,0.85352 C 156.37329,142.12237 157.775,144 160.5,144 c 2.725,0 4.12681,-1.87774 5.35938,-3.15234 a 0.50005,0.50005 0 1 0 -0.71876,-0.69532 C 163.83477,141.50274 162.775,143 160.5,143 c -2.275,0 -3.33487,-1.49737 -4.64062,-2.84766 a 0.50005,0.50005 0 0 0 -0.35743,-0.1582 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path12645"
+ d="m 152.50195,143 a 0.50005,0.50005 0 0 0 -0.46093,0.69727 l 3,7 a 0.50005,0.50005 0 1 0 0.91796,-0.39454 l -2.50781,-5.85156 5.85156,2.50781 a 0.50005,0.50005 0 1 0 0.39454,-0.91796 l -7,-3 A 0.50005,0.50005 0 0 0 152.50195,143 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ id="g14837"
+ transform="translate(-210,-315)">
+ <path
+ inkscape:connector-curvature="0"
+ id="path14829"
+ d="m 415.5,452.00781 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00251,0 -2.00529,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66921,0 -1.33859,10e-6 -2.00781,0 z m -10.5,9 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00251,0 -2.00529,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66921,0 -1.33859,10e-6 -2.00781,0 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path22198"
+ d="m 411.50391,454 a 0.50005,0.50005 0 0 0 -0.35743,0.14648 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 0.85156,-0.85157 0.78515,0.006 a 0.50005,0.50005 0 1 0 0.006,-1 z m -3.01368,2.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 A 0.50005,0.50005 0 0 0 407,458.5 v 1.00781 a 0.50005,0.50005 0 1 0 1,0 v -0.80078 l 0.85352,-0.85351 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m 7.99415,0.9961 A 0.50005,0.50005 0 0 0 415.99219,458.5 v 0.80078 l -0.85352,0.85352 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 0.14649,-0.35352 V 458.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -3.00196,4.00976 a 0.50005,0.50005 0 0 0 -0.34375,0.15235 l -0.85156,0.85156 -0.7832,-0.006 a 0.50005,0.50005 0 1 0 -0.008,1 l 0.99219,0.008 a 0.50005,0.50005 0 0 0 0.35742,-0.14648 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36328,-0.85938 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <rect
+ style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ id="rect5375"
+ width="6"
+ height="5"
+ x="218"
+ y="119" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 303.5,600 c -1.92707,0 -3.5,1.57293 -3.5,3.5 v 0.5 h 1 v -0.5 c 0,-1.38663 1.11337,-2.5 2.5,-2.5 1.38663,0 2.5,1.11337 2.5,2.5 v 1.5 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 8 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 313.5,605 H 307 v -1.5 c 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 2.5,6 h 7 v 4 h -7 z m 3,1 v 2 h 1 v -2 z"
+ id="path19950-6"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="matrix(0.86666667,0,0,0.86666667,39.533341,-302.8)"
+ id="g12476-7-0"
+ style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.15384614;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ inkscape:connector-curvature="0"
+ id="path12470-5-6"
+ d="m 454,555.92383 c -4.45393,0 -8.07617,3.62224 -8.07617,8.07617 0,4.45393 3.62224,8.07617 8.07617,8.07617 4.45393,0 8.07617,-3.62224 8.07617,-8.07617 0,-4.45393 -3.62224,-8.07617 -8.07617,-8.07617 z m 0,1.15234 c 3.83034,0 6.92383,3.09349 6.92383,6.92383 0,3.83034 -3.09349,6.92383 -6.92383,6.92383 -3.83034,0 -6.92383,-3.09349 -6.92383,-6.92383 0,-3.83034 3.09349,-6.92383 6.92383,-6.92383 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.15384614;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0"
+ id="path12474-5-2"
+ d="m 454,561.69141 c -1.26767,-10e-6 -2.3086,1.04092 -2.30859,2.30859 -1e-5,1.26767 1.04092,2.3086 2.30859,2.30859 1.26767,10e-6 2.3086,-1.04092 2.30859,-2.30859 1e-5,-1.26767 -1.04092,-2.3086 -2.30859,-2.30859 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.15384603;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path20496-2"
+ d="m 454,558.23047 c -3.17259,10e-6 -5.76953,2.59694 -5.76953,5.76953 -1e-5,3.17259 2.59694,5.76952 5.76953,5.76953 3.1726,10e-6 5.76954,-2.59693 5.76953,-5.76953 0,-3.1726 -2.59693,-5.76954 -5.76953,-5.76953 z m 0,2.30859 c 1.92543,0 3.46094,1.53551 3.46094,3.46094 0,1.92543 -1.53551,3.46094 -3.46094,3.46094 -1.92542,-1e-5 -3.46094,-1.53552 -3.46094,-3.46094 0,-1.92542 1.53552,-3.46093 3.46094,-3.46094 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.9;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.30769229;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.15384614;enable-background:new"
+ id="g12520-1-5"
+ transform="matrix(0.86666667,0,0,0.86666667,60.533341,-302.8)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ inkscape:connector-curvature="0"
+ id="path12513-1-0"
+ d="m 454,555.92383 c -4.45393,0 -8.07617,3.62224 -8.07617,8.07617 0,4.45393 3.62224,8.07617 8.07617,8.07617 4.45393,0 8.07617,-3.62224 8.07617,-8.07617 0,-4.45393 -3.62224,-8.07617 -8.07617,-8.07617 z m 0,1.15234 c 3.83034,0 6.92383,3.09349 6.92383,6.92383 0,3.83034 -3.09349,6.92383 -6.92383,6.92383 -3.83034,0 -6.92383,-3.09349 -6.92383,-6.92383 0,-3.83034 3.09349,-6.92383 6.92383,-6.92383 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.15384614;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path20498-6"
+ d="m 454,558.23047 c -3.17259,0 -5.76953,2.59694 -5.76953,5.76953 -1e-5,3.1726 2.59693,5.76953 5.76953,5.76953 3.1726,0 5.76954,-2.59693 5.76953,-5.76953 0,-3.17259 -2.59694,-5.76953 -5.76953,-5.76953 z m 0,2.30859 c 1.92542,0 3.46093,1.53552 3.46094,3.46094 0,1.92543 -1.53551,3.46094 -3.46094,3.46094 -1.92543,0 -3.46094,-1.53551 -3.46094,-3.46094 10e-6,-1.92542 1.53552,-3.46094 3.46094,-3.46094 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.30769229;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g5294-1-7-1"
+ transform="translate(41.999998,-357)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ sodipodi:nodetypes="sssss"
+ inkscape:connector-curvature="0"
+ id="path5168-0-2-8"
+ d="m 433,541 c -1.09865,0 -2,0.90135 -2,2 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 0,-1.09865 -0.90135,-2 -2,-2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path5260-6-8-7"
+ d="m 433.08008,537.98438 c -2.77576,0 -5.01953,2.26323 -5.01953,5.01562 0,2.7524 2.24277,5.02307 5.02148,5.01562 L 439.00195,548 a 1.0001,1.0001 0 1 0 -0.004,-2 l -5.91993,0.0156 c -1.70285,0.005 -3.01757,-1.33278 -3.01757,-3.01562 0,-1.68217 1.31272,-3.01459 3.01757,-3.01562 L 438.99805,540 a 1.0001,1.0001 0 1 0 0.004,-2 l -5.91992,-0.0156 a 1.0001,1.0001 0 0 0 -0.002,0 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.9;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path12602-0-0"
+ d="m 433,536 c -2.50006,0 -4.81247,1.33488 -6.0625,3.5 -1.25002,2.16512 -1.25002,4.83488 0,7 1.25003,2.16512 3.56244,3.5 6.0625,3.5 h 6.5 a 0.50005,0.50005 0 1 0 0,-1 H 433 c -2.1444,0 -4.12312,-1.1429 -5.19531,-3 -1.0722,-1.8571 -1.0722,-4.1429 0,-6 1.07219,-1.8571 3.05091,-3 5.19531,-3 h 6.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ id="path20009-7"
+ d="m 328.5,600 c -1.92707,0 -3.5,1.57293 -3.5,3.5 v 1.5 h -0.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 8 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 332 v -1.5 c 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 0,1 c 1.38663,0 2.5,1.11337 2.5,2.5 v 1.5 h -5 v -1.5 c 0,-1.38663 1.11337,-2.5 2.5,-2.5 z m -0.5,6 h 1 v 1 1 h -1 v -1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ id="path20615"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 345.50001,453 c -1.92707,0 -3.5,1.57293 -3.5,3.5 v 0.5 h 1 v -0.5 c 0,-1.38663 1.11337,-2.5 2.5,-2.5 1.38663,0 2.5,1.11337 2.5,2.5 v 1.5 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 8 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -6.5 v -1.5 c 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 2.5,6 h 7 v 4 h -7 z m 3,0.99999 h 1 V 462 h -1 z"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g20632"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(696.00001,793)">
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ id="g20623"
+ transform="translate(-740.00001,-750)"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ id="path20621"
+ transform="translate(594,-43.000004)"
+ d="m -179.5,453 c -1.92707,0 -3.5,1.57293 -3.5,3.5 v 1.5 h -0.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 8 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -0.5 v -1.5 c 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 0,1 c 1.38663,0 2.5,1.11337 2.5,2.5 v 1.5 h -5 v -1.5 c 0,-1.38663 1.11337,-2.5 2.5,-2.5 z m -0.5,6 h 1 v 1 1 h -1 v -1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g11319-4" transform="rotate(90,348.9944,289.99188)">
- <path sodipodi:nodetypes="cccccc" inkscape:connector-curvature="0" id="path11311-4" d="m 202.98828,114.98828 c -0.55228,0.008 -0.99388,0.46139 -0.98633,1.01367 v 8 c -0.0191,1.35232 2.01913,1.35232 2,0 v -8 c 0.008,-0.56299 -0.45068,-1.02136 -1.01367,-1.01367 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" transform="translate(760.99456,-488.99997)" id="g11317-7" style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
- <g id="g11315-1" style="fill:#ffffff">
- <path sodipodi:nodetypes="ccccccccccccccccccccc" inkscape:connector-curvature="0" id="path11313-84" d="m -564.5,609 c -0.5954,-0.006 -0.70014,0.84767 -0.12109,0.98633 l -0.28321,-0.0723 1.91992,7.70703 c 0.0555,0.22241 0.25515,0.37858 0.48438,0.37894 h 11 c 0.27461,-2e-5 0.49783,-0.22149 0.5,-0.49609 l 0.01,-0.99805 c 2.2e-4,-0.0476 -0.006,-0.0949 -0.0195,-0.14063 l -2.00585,-7.00195 c -0.0613,-0.21559 -0.25857,-0.36405 -0.4827,-0.36328 l -2.49599,-0.0137 0.002,1 2.11903,0.0157 1.88086,6.56836 -0.002,0.42969 h -10.11328 l -1.74414,-7 3.85953,-0.0138 v -1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g11319-4"
+ transform="rotate(90,348.9944,289.99188)">
+ <path
+ sodipodi:nodetypes="cccccc"
+ inkscape:connector-curvature="0"
+ id="path11311-4"
+ d="m 202.98828,114.98828 c -0.55228,0.008 -0.99388,0.46139 -0.98633,1.01367 v 8 c -0.0191,1.35232 2.01913,1.35232 2,0 v -8 c 0.008,-0.56299 -0.45068,-1.02136 -1.01367,-1.01367 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="translate(760.99456,-488.99997)"
+ id="g11317-7"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
+ <g
+ id="g11315-1"
+ style="fill:#ffffff">
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path11313-84"
+ d="m -564.5,609 c -0.5954,-0.006 -0.70014,0.84767 -0.12109,0.98633 l -0.28321,-0.0723 1.91992,7.70703 c 0.0555,0.22241 0.25515,0.37858 0.48438,0.37894 h 11 c 0.27461,-2e-5 0.49783,-0.22149 0.5,-0.49609 l 0.01,-0.99805 c 2.2e-4,-0.0476 -0.006,-0.0949 -0.0195,-0.14063 l -2.00585,-7.00195 c -0.0613,-0.21559 -0.25857,-0.36405 -0.4827,-0.36328 l -2.49599,-0.0137 0.002,1 2.11903,0.0157 1.88086,6.56836 -0.002,0.42969 h -10.11328 l -1.74414,-7 3.85953,-0.0138 v -1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
</g>
</g>
- <path id="path16385" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 515.5,432 c -0.1326,2e-5 -0.25976,0.0527 -0.35352,0.14647 L 513.29297,434 H 510.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 8 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 6.45312 0.004 c 0.0131,-8.2e-4 0.0261,-0.002 0.0391,-0.004 0.004,5e-5 0.008,5e-5 0.0117,0 0.0143,0.002 0.0286,0.003 0.043,0.004 h 0.006 5.44336 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -8 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -1.79297 l -1.85351,-1.85353 C 518.76,432.05268 518.6327,431.99995 518.5,432 Z m 1.49781,1.99804 c 2.21589,-3.2e-4 4.00185,1.7855 4.00195,4.00196 -9e-4,2.19736 -1.75841,3.97457 -3.95508,4 -0.0131,8.2e-4 -0.0261,0.002 -0.0391,0.004 -0.0149,-0.002 -0.0299,-0.003 -0.0449,-0.004 -10e-4,0 -0.003,0 -0.004,0 -2.19824,-0.0228 -3.95803,-1.80057 -3.95898,-4 9e-5,-2.21578 1.78479,-4.00131 4,-4.00196 z M 516.99805,435 C 515.34742,435 514,436.34922 514,438 c 0,1.65079 1.34742,3 2.99805,3 1.65063,0 3,-1.34921 3,-3 0,-1.65078 -1.34937,-3 -3,-3 z m 0,1 c 1.11009,0 2,0.88955 2,2 0,1.11045 -0.88991,2 -2,2 C 515.88796,440 515,439.11045 515,438 c 0,-1.11045 0.88796,-2 1.99805,-2 z" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" d="m 140.99637,186.00011 a 1.99635,1.99635 0 0 1 -1.99635,1.99635 1.99635,1.99635 0 0 1 -1.99635,-1.99635 1.99635,1.99635 0 0 1 1.99635,-1.99635 1.99635,1.99635 0 0 1 1.99635,1.99635 z m -8.50223,-7.00402 a 0.50005,0.50005 0 0 0 -0.34766,0.85743 l 3,3 C 134.44086,183.71574 134,184.80241 134,186 c 2e-5,1.19757 0.44085,2.28425 1.14648,3.14648 l -3,3 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 3,-3 C 136.71574,190.55915 137.80243,191 139,191 c 1.19757,0 2.28426,-0.44085 3.14648,-1.14648 l 3,3 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -3,-3 C 143.55915,188.28425 143.99998,187.19757 144,186 c 0,-1.19759 -0.44086,-2.28426 -1.14648,-3.14648 l 3,-3 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3,3 C 141.28425,181.44086 140.19759,181 139,181 c -1.19759,0 -2.28425,0.44086 -3.14648,1.14648 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.15039 z M 139,182 c 2.21506,0 4.00001,1.78494 4,4 -4e-5,2.21502 -1.78498,4 -4,4 -2.21502,0 -3.99996,-1.78498 -4,-4 -1e-5,-2.21506 1.78494,-4 4,-4 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" id="circle20581-1"/>
- <path inkscape:connector-curvature="0" id="path22635-0-9" d="m 494.5,432 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 492.29297,434 H 489.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 8 a 0.50005,0.50005 0 0 0 0.5,0.5 h 12 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -8 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -1.79297 l -1.85351,-1.85352 A 0.50005,0.50005 0 0 0 497.5,432 Z m 0.20703,1 h 2.58594 l 1.85351,1.85352 A 0.50005,0.50005 0 0 0 499.5,435 h 1.5 v 7 h -11 v -7 h 2.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 z m -0.46094,2.74414 a 0.50005,0.50005 0 0 0 -0.34961,0.85938 l 1.39649,1.39648 -1.39649,1.39648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 496,438.70703 l 1.39648,1.39649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 L 496.70703,438 l 1.39649,-1.39648 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 L 496,437.29297 l -1.39648,-1.39649 a 0.50005,0.50005 0 0 0 -0.35743,-0.15234 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path sodipodi:nodetypes="ccccccccc" inkscape:connector-curvature="0" id="path19969-0" d="m 469.49023,433 c -0.3497,0.006 -0.58488,0.36077 -0.45507,0.68555 l 4,10.00195 c 0.1779,0.45034 0.82806,0.4102 0.94922,-0.0586 l 1.17578,-4.46875 4.46679,-1.17578 c 0.46499,-0.12321 0.50486,-0.76769 0.0586,-0.94727 l -10,-4.00195 c -0.0621,-0.0247 -0.12852,-0.0366 -0.19532,-0.0351 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path inkscape:connector-curvature="0" id="path19971-4" d="m 448.49023,433 a 0.50005,0.50005 0 0 0 -0.45507,0.68555 l 4,10.00195 a 0.50050292,0.50050292 0 1 0 0.92968,-0.37109 l -3.5664,-8.91797 8.91601,3.5664 a 0.50005,0.50005 0 1 0 0.3711,-0.92773 l -10,-4.00195 A 0.50005,0.50005 0 0 0 448.49023,433 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <g transform="translate(37.00977,-1667.9941)" id="g20814-2" style="fill:#ffffff">
- <g id="g20812-7" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="path20793-9" transform="translate(491.99023,1667.9941)" d="m -58.978516,159.00391 c -0.268711,-0.0142 -0.522461,0.007 -0.761718,0.0664 -0.47849,0.1192 -0.892924,0.44895 -1.089844,0.90235 -0.19686,0.4535 -0.203572,0.98669 -0.07617,1.59179 0.50982,2.4202 3.039112,5.6664 6.039062,8.0293 1.49994,1.1815 2.89794,1.95798 4.06836,2.26758 0.58523,0.1549 1.120142,0.1985 1.601562,0.0664 0.48143,-0.1318 0.896965,-0.48805 1.078125,-0.97265 0.36233,-0.9692 -0.01465,-2.1613 -0.732421,-3.5 -0.585772,-1.09244 -1.450912,-2.27994 -2.509766,-3.44922 h 1.695312 a 0.50005,0.50005 0 1 0 0,-1 h -2.828125 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2.82812 a 0.50005,0.50005 0 1 0 1,0 v -1.53906 c 0.962773,1.08028 1.742337,2.16783 2.259766,3.13281 0.65736,1.226 0.838188,2.25364 0.679687,2.67774 -0.0793,0.212 -0.1766,0.29452 -0.40625,0.35742 -0.229719,0.063 -0.603428,0.0576 -1.080078,-0.0684 -0.95331,-0.2522 -2.281914,-0.96184 -3.708984,-2.08594 -2.85409,-2.248 -5.274721,-5.54511 -5.675781,-7.44921 -0.10032,-0.47611 -0.06643,-0.80379 0.01367,-0.98829 0.0801,-0.1845 0.178092,-0.26942 0.414062,-0.32812 0.47178,-0.1177 1.518783,0.0927 2.851563,0.85351 a 0.50043231,0.50036032 0 0 0 0.496093,-0.86914 c -1.081755,-0.61755 -2.02199,-0.98079 -2.828125,-1.02343 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path inkscape:connector-curvature="0" id="path20798-7" d="m 435.91471,1838.9185 a 0.49989467,0.50020516 0 0 1 -0.10766,0.08 c -1.55117,0.8755 -2.8107,1.2341 -3.77887,0.8468 -0.48409,-0.1937 -0.84555,-0.6327 -0.96369,-1.1577 -0.11806,-0.525 -0.0453,-1.1245 0.17673,-1.8153 0.88827,-2.7631 3.96133,-6.3033 7.15309,-8.3953 1.59595,-1.046 2.94158,-1.5736 4.02185,-1.474 0.5401,0.05 1.04109,0.3065 1.31713,0.757 0.27597,0.4504 0.3235,1.0201 0.20985,1.6633 a 0.50049929,0.50081015 0 1 1 -0.98577,-0.174 c 0.0873,-0.4946 0.0235,-0.8034 -0.076,-0.9657 -0.0994,-0.1623 -0.23754,-0.2538 -0.55637,-0.2832 -0.63756,-0.059 -1.88509,0.331 -3.38253,1.3124 -2.99493,1.9629 -5.99799,5.5314 -6.74857,7.8663 -0.18764,0.5837 -0.21297,1.0235 -0.15327,1.2889 0.0597,0.2653 0.15122,0.3664 0.35757,0.449 0.41277,0.1651 1.48565,0.019 2.91733,-0.7889 a 0.49989467,0.50020516 0 0 1 0.59917,0.7903 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
+ <path
+ id="path16385"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 515.5,432 c -0.1326,2e-5 -0.25976,0.0527 -0.35352,0.14647 L 513.29297,434 H 510.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 8 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 6.45312 0.004 c 0.0131,-8.2e-4 0.0261,-0.002 0.0391,-0.004 0.004,5e-5 0.008,5e-5 0.0117,0 0.0143,0.002 0.0286,0.003 0.043,0.004 h 0.006 5.44336 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -8 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -1.79297 l -1.85351,-1.85353 C 518.76,432.05268 518.6327,431.99995 518.5,432 Z m 1.49781,1.99804 c 2.21589,-3.2e-4 4.00185,1.7855 4.00195,4.00196 -9e-4,2.19736 -1.75841,3.97457 -3.95508,4 -0.0131,8.2e-4 -0.0261,0.002 -0.0391,0.004 -0.0149,-0.002 -0.0299,-0.003 -0.0449,-0.004 -10e-4,0 -0.003,0 -0.004,0 -2.19824,-0.0228 -3.95803,-1.80057 -3.95898,-4 9e-5,-2.21578 1.78479,-4.00131 4,-4.00196 z M 516.99805,435 C 515.34742,435 514,436.34922 514,438 c 0,1.65079 1.34742,3 2.99805,3 1.65063,0 3,-1.34921 3,-3 0,-1.65078 -1.34937,-3 -3,-3 z m 0,1 c 1.11009,0 2,0.88955 2,2 0,1.11045 -0.88991,2 -2,2 C 515.88796,440 515,439.11045 515,438 c 0,-1.11045 0.88796,-2 1.99805,-2 z"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 140.99637,186.00011 a 1.99635,1.99635 0 0 1 -1.99635,1.99635 1.99635,1.99635 0 0 1 -1.99635,-1.99635 1.99635,1.99635 0 0 1 1.99635,-1.99635 1.99635,1.99635 0 0 1 1.99635,1.99635 z m -8.50223,-7.00402 a 0.50005,0.50005 0 0 0 -0.34766,0.85743 l 3,3 C 134.44086,183.71574 134,184.80241 134,186 c 2e-5,1.19757 0.44085,2.28425 1.14648,3.14648 l -3,3 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 3,-3 C 136.71574,190.55915 137.80243,191 139,191 c 1.19757,0 2.28426,-0.44085 3.14648,-1.14648 l 3,3 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -3,-3 C 143.55915,188.28425 143.99998,187.19757 144,186 c 0,-1.19759 -0.44086,-2.28426 -1.14648,-3.14648 l 3,-3 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3,3 C 141.28425,181.44086 140.19759,181 139,181 c -1.19759,0 -2.28425,0.44086 -3.14648,1.14648 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.15039 z M 139,182 c 2.21506,0 4.00001,1.78494 4,4 -4e-5,2.21502 -1.78498,4 -4,4 -2.21502,0 -3.99996,-1.78498 -4,-4 -1e-5,-2.21506 1.78494,-4 4,-4 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="circle20581-1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path22635-0-9"
+ d="m 494.5,432 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 492.29297,434 H 489.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 8 a 0.50005,0.50005 0 0 0 0.5,0.5 h 12 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -8 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -1.79297 l -1.85351,-1.85352 A 0.50005,0.50005 0 0 0 497.5,432 Z m 0.20703,1 h 2.58594 l 1.85351,1.85352 A 0.50005,0.50005 0 0 0 499.5,435 h 1.5 v 7 h -11 v -7 h 2.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 z m -0.46094,2.74414 a 0.50005,0.50005 0 0 0 -0.34961,0.85938 l 1.39649,1.39648 -1.39649,1.39648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 496,438.70703 l 1.39648,1.39649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 L 496.70703,438 l 1.39649,-1.39648 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 L 496,437.29297 l -1.39648,-1.39649 a 0.50005,0.50005 0 0 0 -0.35743,-0.15234 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="path19969-0"
+ d="m 469.49023,433 c -0.3497,0.006 -0.58488,0.36077 -0.45507,0.68555 l 4,10.00195 c 0.1779,0.45034 0.82806,0.4102 0.94922,-0.0586 l 1.17578,-4.46875 4.46679,-1.17578 c 0.46499,-0.12321 0.50486,-0.76769 0.0586,-0.94727 l -10,-4.00195 c -0.0621,-0.0247 -0.12852,-0.0366 -0.19532,-0.0351 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19971-4"
+ d="m 448.49023,433 a 0.50005,0.50005 0 0 0 -0.45507,0.68555 l 4,10.00195 a 0.50050292,0.50050292 0 1 0 0.92968,-0.37109 l -3.5664,-8.91797 8.91601,3.5664 a 0.50005,0.50005 0 1 0 0.3711,-0.92773 l -10,-4.00195 A 0.50005,0.50005 0 0 0 448.49023,433 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <g
+ transform="translate(37.00977,-1667.9941)"
+ id="g20814-2"
+ style="fill:#ffffff">
+ <g
+ id="g20812-7"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="path20793-9"
+ transform="translate(491.99023,1667.9941)"
+ d="m -58.978516,159.00391 c -0.268711,-0.0142 -0.522461,0.007 -0.761718,0.0664 -0.47849,0.1192 -0.892924,0.44895 -1.089844,0.90235 -0.19686,0.4535 -0.203572,0.98669 -0.07617,1.59179 0.50982,2.4202 3.039112,5.6664 6.039062,8.0293 1.49994,1.1815 2.89794,1.95798 4.06836,2.26758 0.58523,0.1549 1.120142,0.1985 1.601562,0.0664 0.48143,-0.1318 0.896965,-0.48805 1.078125,-0.97265 0.36233,-0.9692 -0.01465,-2.1613 -0.732421,-3.5 -0.585772,-1.09244 -1.450912,-2.27994 -2.509766,-3.44922 h 1.695312 a 0.50005,0.50005 0 1 0 0,-1 h -2.828125 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2.82812 a 0.50005,0.50005 0 1 0 1,0 v -1.53906 c 0.962773,1.08028 1.742337,2.16783 2.259766,3.13281 0.65736,1.226 0.838188,2.25364 0.679687,2.67774 -0.0793,0.212 -0.1766,0.29452 -0.40625,0.35742 -0.229719,0.063 -0.603428,0.0576 -1.080078,-0.0684 -0.95331,-0.2522 -2.281914,-0.96184 -3.708984,-2.08594 -2.85409,-2.248 -5.274721,-5.54511 -5.675781,-7.44921 -0.10032,-0.47611 -0.06643,-0.80379 0.01367,-0.98829 0.0801,-0.1845 0.178092,-0.26942 0.414062,-0.32812 0.47178,-0.1177 1.518783,0.0927 2.851563,0.85351 a 0.50043231,0.50036032 0 0 0 0.496093,-0.86914 c -1.081755,-0.61755 -2.02199,-0.98079 -2.828125,-1.02343 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path20798-7"
+ d="m 435.91471,1838.9185 a 0.49989467,0.50020516 0 0 1 -0.10766,0.08 c -1.55117,0.8755 -2.8107,1.2341 -3.77887,0.8468 -0.48409,-0.1937 -0.84555,-0.6327 -0.96369,-1.1577 -0.11806,-0.525 -0.0453,-1.1245 0.17673,-1.8153 0.88827,-2.7631 3.96133,-6.3033 7.15309,-8.3953 1.59595,-1.046 2.94158,-1.5736 4.02185,-1.474 0.5401,0.05 1.04109,0.3065 1.31713,0.757 0.27597,0.4504 0.3235,1.0201 0.20985,1.6633 a 0.50049929,0.50081015 0 1 1 -0.98577,-0.174 c 0.0873,-0.4946 0.0235,-0.8034 -0.076,-0.9657 -0.0994,-0.1623 -0.23754,-0.2538 -0.55637,-0.2832 -0.63756,-0.059 -1.88509,0.331 -3.38253,1.3124 -2.99493,1.9629 -5.99799,5.5314 -6.74857,7.8663 -0.18764,0.5837 -0.21297,1.0235 -0.15327,1.2889 0.0597,0.2653 0.15122,0.3664 0.35757,0.449 0.41277,0.1651 1.48565,0.019 2.91733,-0.7889 a 0.49989467,0.50020516 0 0 1 0.59917,0.7903 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
</g>
- <g transform="translate(378.00977,-125.994)" id="g20863-5" style="display:inline;fill:#ffffff;enable-background:new">
- <path inkscape:connector-curvature="0" id="path20855-2" d="M 79.490234,286.99609 A 0.50005,0.50005 0 0 0 79.439453,287 H 76.5 a 0.50005,0.50005 0 1 0 0,1 h 1.792969 l -5.146485,5.14648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 79,288.70703 V 290.5 a 0.50005,0.50005 0 1 0 1,0 v -2.93945 a 0.50005,0.50005 0 0 0 -0.509766,-0.56446 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path20857-3" transform="translate(171.99023,125.994)" d="m -100.49805,157.99805 a 0.50005,0.50005 0 0 0 -0.38867,0.19531 0.50005,0.50005 0 0 0 -0.004,0.006 l -1.95313,1.95312 a 0.50005,0.50005 0 1 0 0.70703,0.70704 l 1.14649,-1.14649 v 7.57422 c -0.59356,0.34821 -1,0.9856 -1,1.71875 0,1.09865 0.90135,2 1.999996,2 0.73315,0 1.370541,-0.40645 1.71875,-1 h 7.574218 l -1.146484,1.14648 a 0.50005,0.50005 0 1 0 0.707031,0.70704 l 1.957031,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.0059,-0.004 l -1.953125,-1.95313 A 0.50005,0.50005 0 0 0 -91.496094,167 a 0.50005,0.50005 0 0 0 -0.347656,0.85938 l 1.146484,1.14648 h -7.292968 c 0,-1.09865 -0.901352,-2 -2,-2 v -7.29297 l 1.146484,1.14649 a 0.50005,0.50005 0 1 0 0.707031,-0.70704 l -1.957031,-1.95703 a 0.50005,0.50005 0 0 0 -0.4043,-0.19726 z m 0.507816,10.00781 c 0.558208,0 1,0.44179 1,1 0,0.55821 -0.441792,1 -1,1 -0.558206,0 -0.999996,-0.44179 -0.999996,-1 0,-0.55821 0.44179,-1 0.999996,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g transform="matrix(-1,0,0,1,1033.9931,42.006004)" id="g20880-1" style="display:inline;fill:#ffffff;enable-background:new">
- <path inkscape:connector-curvature="0" id="ellipse20865-9" transform="matrix(-1,0,0,1,483.9931,-42.006004)" d="m -28.482422,162.00195 a 0.50005,0.50005 0 0 0 -0.365234,0.85743 l 1.146484,1.14648 h -5.585937 c -0.348208,-0.59355 -0.987551,-1 -1.720703,-1 -1.098651,0 -2,0.90135 -2,2 0,1.09865 0.901349,2 2,2 1.09865,0 2,-0.90135 2,-2 h 5.30664 l -1.146484,1.14648 a 0.50064056,0.50064056 0 0 0 0.708984,0.70704 l 2,-2 a 0.50005,0.50005 0 0 0 0,-0.70704 l -2,-2 a 0.50005,0.50005 0 0 0 -0.34375,-0.15039 z m -6.52539,2.00391 c 0.55821,0 1,0.44179 1,1 0,0.55821 -0.44179,1 -1,1 -0.558211,0 -1,-0.44179 -1,-1 0,-0.55821 0.441789,-1 1,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" transform="matrix(0,1,1,0,-94.00249,680.99203)" id="g20878-5" style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
- <g id="g20876-3" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="path20873-7" d="M -559.99805,608.99609 -564.5,609 a 0.50005,0.50005 0 0 0 -0.5,0.50391 l 0.008,1.00195 a 0.50005,0.50005 0 0 0 0.0195,0.13281 l 1.99219,6.99805 A 0.50005,0.50005 0 0 0 -562.5,618 h 11 a 0.50005,0.50005 0 0 0 0.5,-0.49609 l 0.01,-0.99805 a 0.50005,0.50005 0 0 0 -0.0195,-0.14063 l -2.00585,-7.00195 A 0.50005,0.50005 0 0 0 -553.49609,609 l -3.50196,-0.004 v 1 l 3.125,0.004 1.88086,6.57031 -0.002,0.42969 h -10.12695 l -1.8711,-6.56836 -0.004,-0.43164 3.99804,-0.004 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
+ <g
+ transform="translate(378.00977,-125.994)"
+ id="g20863-5"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ id="path20855-2"
+ d="M 79.490234,286.99609 A 0.50005,0.50005 0 0 0 79.439453,287 H 76.5 a 0.50005,0.50005 0 1 0 0,1 h 1.792969 l -5.146485,5.14648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 79,288.70703 V 290.5 a 0.50005,0.50005 0 1 0 1,0 v -2.93945 a 0.50005,0.50005 0 0 0 -0.509766,-0.56446 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path20857-3"
+ transform="translate(171.99023,125.994)"
+ d="m -100.49805,157.99805 a 0.50005,0.50005 0 0 0 -0.38867,0.19531 0.50005,0.50005 0 0 0 -0.004,0.006 l -1.95313,1.95312 a 0.50005,0.50005 0 1 0 0.70703,0.70704 l 1.14649,-1.14649 v 7.57422 c -0.59356,0.34821 -1,0.9856 -1,1.71875 0,1.09865 0.90135,2 1.999996,2 0.73315,0 1.370541,-0.40645 1.71875,-1 h 7.574218 l -1.146484,1.14648 a 0.50005,0.50005 0 1 0 0.707031,0.70704 l 1.957031,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.0059,-0.004 l -1.953125,-1.95313 A 0.50005,0.50005 0 0 0 -91.496094,167 a 0.50005,0.50005 0 0 0 -0.347656,0.85938 l 1.146484,1.14648 h -7.292968 c 0,-1.09865 -0.901352,-2 -2,-2 v -7.29297 l 1.146484,1.14649 a 0.50005,0.50005 0 1 0 0.707031,-0.70704 l -1.957031,-1.95703 a 0.50005,0.50005 0 0 0 -0.4043,-0.19726 z m 0.507816,10.00781 c 0.558208,0 1,0.44179 1,1 0,0.55821 -0.441792,1 -1,1 -0.558206,0 -0.999996,-0.44179 -0.999996,-1 0,-0.55821 0.44179,-1 0.999996,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ transform="matrix(-1,0,0,1,1033.9931,42.006004)"
+ id="g20880-1"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ id="ellipse20865-9"
+ transform="matrix(-1,0,0,1,483.9931,-42.006004)"
+ d="m -28.482422,162.00195 a 0.50005,0.50005 0 0 0 -0.365234,0.85743 l 1.146484,1.14648 h -5.585937 c -0.348208,-0.59355 -0.987551,-1 -1.720703,-1 -1.098651,0 -2,0.90135 -2,2 0,1.09865 0.901349,2 2,2 1.09865,0 2,-0.90135 2,-2 h 5.30664 l -1.146484,1.14648 a 0.50064056,0.50064056 0 0 0 0.708984,0.70704 l 2,-2 a 0.50005,0.50005 0 0 0 0,-0.70704 l -2,-2 a 0.50005,0.50005 0 0 0 -0.34375,-0.15039 z m -6.52539,2.00391 c 0.55821,0 1,0.44179 1,1 0,0.55821 -0.44179,1 -1,1 -0.558211,0 -1,-0.44179 -1,-1 0,-0.55821 0.441789,-1 1,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="matrix(0,1,1,0,-94.00249,680.99203)"
+ id="g20878-5"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
+ <g
+ id="g20876-3"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="path20873-7"
+ d="M -559.99805,608.99609 -564.5,609 a 0.50005,0.50005 0 0 0 -0.5,0.50391 l 0.008,1.00195 a 0.50005,0.50005 0 0 0 0.0195,0.13281 l 1.99219,6.99805 A 0.50005,0.50005 0 0 0 -562.5,618 h 11 a 0.50005,0.50005 0 0 0 0.5,-0.49609 l 0.01,-0.99805 a 0.50005,0.50005 0 0 0 -0.0195,-0.14063 l -2.00585,-7.00195 A 0.50005,0.50005 0 0 0 -553.49609,609 l -3.50196,-0.004 v 1 l 3.125,0.004 1.88086,6.57031 -0.002,0.42969 h -10.12695 l -1.8711,-6.56836 -0.004,-0.43164 3.99804,-0.004 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
</g>
</g>
- <g transform="translate(122.00977,-1668.9941)" id="g20207-3" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 346.49414,1805.9941 a 0.50005,0.50005 0 0 0 -0.34766,0.8594 l 3,3 C 348.44086,1810.7157 348,1811.8024 348,1813 c 2e-5,1.197 0.44143,2.2825 1.14648,3.1445 l -3,3 a 0.50005,0.50005 0 1 0 0.70704,0.7071 l 3,-3 c 0.86236,0.7061 1.94846,1.1484 3.14648,1.1484 0.73402,0 1.42595,-0.1693 2.05469,-0.4551 l -0.77344,-0.7734 C 353.87701,1816.9083 353.45144,1817 353,1817 c -2.21502,0 -3.99996,-1.785 -4,-4 -10e-6,-2.2151 1.78494,-4 4,-4 2.21506,0 4.00001,1.7849 4,4 -10e-6,0.4593 -0.093,0.8925 -0.23438,1.3027 l 0.76954,0.7696 c 0.29106,-0.6335 0.46483,-1.3311 0.46484,-2.0723 0,-1.198 -0.44234,-2.2841 -1.14844,-3.1465 l 3.00196,-3.0019 a 0.50005,0.50005 0 0 0 -0.36329,-0.8575 0.50005,0.50005 0 0 0 -0.34375,0.1504 l -3.00195,3.002 C 355.28248,1808.4414 354.19705,1808 353,1808 c -1.19759,0 -2.28425,0.4409 -3.14648,1.1465 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.1524 z" id="path20884-9"/>
- <path inkscape:connector-curvature="0" id="path20886-9" transform="translate(427.99023,1668.9941)" d="m -74.990234,142.01953 c -1.09866,0 -2,0.9013 -2,2 0,1.0986 0.90134,2 2,2 0.381313,0 0.73472,-0.11501 1.039062,-0.30273 a 0.50005,0.50005 0 0 0 0.107422,0.15625 l 4.146484,4.14648 h -1.621093 a 0.50005,0.50005 0 1 0 0,1 h 2.828125 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2.82812 a 0.50005,0.50005 0 1 0 -1,0 v 1.62109 l -4.146485,-4.14648 a 0.50005,0.50005 0 0 0 -0.15625,-0.10743 c 0.187715,-0.30434 0.302735,-0.65777 0.302735,-1.03906 0,-1.0987 -0.90134,-2 -2,-2 z m 0,1 c 0.5582,0 1,0.4418 1,1 0,0.5581 -0.4418,1 -1,1 -0.5582,0 -1,-0.4419 -1,-1 0,-0.5582 0.4418,-1 1,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g20897-5" transform="translate(399.00976,-125.9939)">
- <path inkscape:connector-curvature="0" id="path20888-1" transform="translate(171.99024,125.9939)" d="m -71.318359,158.00586 a 0.50005,0.50005 0 1 0 0,1 h 1.689453 l -3.382813,4.26953 c -0.291076,-0.16603 -0.621698,-0.26953 -0.978515,-0.26953 -0.733151,0 -1.370542,0.40645 -1.71875,1 h -4.582032 l 1.146485,-1.14648 a 0.50005,0.50005 0 0 0 -0.363281,-0.85743 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -2,2 a 0.50005,0.50005 0 0 0 0,0.70704 l 2,2 a 0.50005,0.50005 0 1 0 0.707031,-0.70704 l -1.146485,-1.14648 h 4.300782 c 0,1.09865 0.901352,2 2,2 1.098648,0 2,-0.90135 2,-2 0,-0.37821 -0.113913,-0.72852 -0.298828,-1.03125 l 3.298828,-4.16211 v 1.52148 a 0.50005,0.50005 0 1 0 1,0 v -2.82812 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -2.671875,6 c 0.558208,0 1,0.44179 1,1 0,0.55821 -0.441792,1 -1,1 -0.558208,0 -1,-0.44179 -1,-1 0,-0.55821 0.441792,-1 1,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path20890-1" d="m 99.244141,291.73828 a 0.50005,0.50005 0 0 0 -0.396485,0.81641 L 102.36133,297 h -1.68945 a 0.50005,0.50005 0 1 0 0,1 H 103.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2.82812 a 0.50005,0.50005 0 1 0 -1,0 v 1.52148 l -3.367188,-4.25977 a 0.50005,0.50005 0 0 0 -0.388671,-0.19531 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <path inkscape:connector-curvature="0" id="path20072-2" d="m 97.917969,157.99219 c -1.58517,-0.0121 -3.159728,0.54254 -4.271485,1.65429 l -3.5,3.5 a 0.50005,0.50005 0 0 0 0,0.70704 l 2,2 a 0.50005,0.50005 0 0 0 0.707032,0 l 3.25,-3.25 c 0.584908,-0.58491 1.581654,-0.89809 2.345703,-0.69336 0.801559,0.21477 1.425851,0.83907 1.640621,1.64062 0.20473,0.76404 -0.108435,1.76078 -0.693356,2.3457 l -3.25,3.25 a 0.50005,0.50005 0 0 0 0,0.70704 l 2,2 a 0.50005,0.50005 0 0 0 0.707032,0 l 3.474604,-3.47657 a 0.50005,0.50005 0 0 0 0.0254,-0.0234 0.50005,0.50005 0 0 0 0.12109,-0.18946 c 2.06467,-2.25524 2.04105,-6.1641 -0.21875,-8.42383 -1.15788,-1.15791 -2.752722,-1.73596 -4.337891,-1.74804 z m -0.0078,1.0332 c 1.340871,0.01 2.694311,0.47748 3.638671,1.42188 1.8888,1.88873 1.87387,5.423 0.0977,7.19921 L 98.5,170.79297 97.207031,169.5 l 2.896489,-2.89648 c 0.84012,-0.84012 1.27,-2.1299 0.95312,-3.3125 -0.30683,-1.14511 -1.202555,-2.04084 -2.347656,-2.34766 -1.182591,-0.31687 -2.472368,0.11299 -3.3125,0.95312 L 92.5,164.79297 91.207031,163.5 l 3.146485,-3.14648 c 0.888243,-0.88825 2.21577,-1.33772 3.55664,-1.32813 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path id="path20705" d="m 34.5,578 c -1.48507,0 -2.8535,0.46731 -3.86133,1.33594 C 29.63084,580.20456 29,581.48473 29,583 v 3.5 c 0,1.66667 0.001,2.82293 -0.89062,3.9375 -0.0709,0.0887 -0.10946,0.19893 -0.10938,0.3125 v 0.75 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 H 29 c 1.04885,0 2.13736,-0.63444 3.45898,-2.04297 l 1.66797,1.875 c 0.19883,0.22274 0.54727,0.22274 0.7461,0 l 1.62695,-1.83008 1.62695,1.83008 c 0.0947,0.10662 0.23044,0.16774 0.37305,0.16797 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 -1 -5.5 c 0,-1.51527 -0.63084,-2.79544 -1.63867,-3.66406 C 37.3535,578.46731 35.98507,578 34.5,578 Z m -3.00781,4 c 0.1353,-0.002 0.26563,0.0508 0.36133,0.14648 l 2,2 c 0.31479,0.315 0.09181,0.85335 -0.35352,0.85352 h -2 c -0.27613,-3e-5 -0.49997,-0.22387 -0.5,-0.5 v -2 c -10e-6,-0.27311 0.21911,-0.496 0.49219,-0.5 z m 5.99219,0 c 0.2822,-0.009 0.51573,0.21765 0.51562,0.5 v 2 c -3e-5,0.27613 -0.22387,0.49997 -0.5,0.5 h -2 c -0.44532,-1.7e-4 -0.66831,-0.53852 -0.35352,-0.85352 l 2,-2 c 0.0899,-0.0901 0.21072,-0.14248 0.3379,-0.14648 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" id="path13646-9" d="m 406.50195,437 a 0.50005,0.50005 0 0 0 -0.33203,0.84375 c 1.3239,1.43817 3.0824,4.1582 6.3457,4.1582 3.26331,0 5.02376,-2.72003 6.34766,-4.1582 a 0.50037481,0.50037481 0 1 0 -0.73633,-0.67773 c -1.43556,1.55946 -2.90607,3.83593 -5.61133,3.83593 -2.70525,0 -4.17576,-2.27647 -5.61132,-3.83593 A 0.50005,0.50005 0 0 0 406.50195,437 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <g transform="translate(315,-0.999996)" id="g13630-2" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path inkscape:connector-curvature="0" d="m 164.50781,224 a 0.50004997,0.50004997 0 0 1 0.43164,0.27148 c 1.44011,2.71955 1.43779,6.74164 -0.008,9.45899 a 0.50022794,0.50022794 0 1 1 -0.88281,-0.4707 c 1.24398,-2.33836 1.24519,-6.17912 0.006,-8.51954 A 0.50004997,0.50004997 0 0 1 164.50781,224 Z m -1.99609,1.99805 a 0.50004997,0.50004997 0 0 1 0.49219,0.50586 v 4.99218 a 0.50004997,0.50004997 0 1 1 -1,0 v -4.99218 a 0.50004997,0.50004997 0 0 1 0.50781,-0.50586 z M 159.25,223 c -0.1326,2e-5 -0.25976,0.0527 -0.35352,0.14648 L 156.04297,226 H 154.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.54297 l 2.85351,2.85352 c 0.0938,0.0938 0.22092,0.14646 0.35352,0.14648 h 0.25 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 223.78125 223.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" id="path13628-2"/>
- </g>
- <path inkscape:connector-curvature="0" id="path13642-1" d="m 453.5,222 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 450.29297,225 H 448.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.79297 l 2.85351,2.85352 A 0.50005,0.50005 0 0 0 453.5,234 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 222.78125 222.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 454 v 10 h -0.29297 l -2.85351,-2.85352 A 0.50005,0.50005 0 0 0 450.5,230 H 449 v -4 h 1.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g14825-7" transform="translate(-189,-315)">
- <path sodipodi:nodetypes="cccccccccccccccccc" inkscape:connector-curvature="0" id="path14782-1" d="m 415.5,452.00781 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3.00781 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3.00781 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3.00781 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -10,10 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3.00781 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3.00781 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3.00781 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path inkscape:connector-curvature="0" id="path14818-4" d="m 409.49219,454.00781 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -1.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 l 0.008,3 a 0.50005,0.50005 0 1 0 1,-0.002 l -0.006,-2.49805 h 1.49805 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1.5 h 2.5 a 0.50005,0.50005 0 1 0 0,-1 z m 3.99804,2.98828 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3,3.00782 a 0.50005,0.50005 0 1 0 0.70704,0.70508 l 3,-3.00586 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z M 416.49219,458 A 0.50005,0.50005 0 0 0 416,458.50781 v 2.5 h -1.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.49805 L 411.50195,463 a 0.50005,0.50005 0 1 0 -0.004,1 l 3,0.008 a 0.50005,0.50005 0 0 0 0.50195,-0.5 v -1.5 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 A 0.50005,0.50005 0 0 0 416.49219,458 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
- <g id="g19296" transform="translate(850,-280)" style="fill:#ffffff"/>
- <path inkscape:connector-curvature="0" id="path19316" d="m 541.57031,410.01758 c -0.79787,-0.038 -1.57177,0.27684 -2.16015,0.86523 l -1.26368,1.26367 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.26367,-1.26368 c 0.41161,-0.41161 0.88966,-0.59872 1.40429,-0.57422 0.51464,0.0245 1.08439,0.26993 1.63868,0.82422 0.55479,0.5548 0.80954,1.13546 0.83789,1.65235 0.0283,0.51688 -0.15241,0.9848 -0.57422,1.3789 a 0.50005,0.50005 0 0 0 -0.0137,0.0117 l -1.26368,1.26367 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.25195,-1.25196 c 0.61768,-0.57711 0.9366,-1.36125 0.89258,-2.16406 -0.044,-0.80281 -0.43566,-1.60948 -1.13086,-2.30469 -0.69571,-0.69571 -1.49901,-1.07724 -2.29688,-1.11523 z m -8.08008,6.97851 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1.25,1.25 c -0.58838,0.58839 -0.90322,1.36034 -0.86523,2.15821 0.038,0.79787 0.41952,1.60311 1.11523,2.29883 0.69521,0.6952 1.50384,1.08487 2.30664,1.1289 0.80281,0.044 1.585,-0.27294 2.16211,-0.89062 l 1.23829,-1.23828 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 l -1.25,1.25 a 0.50005,0.50005 0 0 0 -0.0117,0.0117 c -0.39411,0.42182 -0.86007,0.60452 -1.37696,0.57618 -0.51688,-0.0283 -1.0995,-0.2831 -1.65429,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.82227,-1.63867 -0.0245,-0.51463 0.16065,-0.99268 0.57227,-1.40429 l 1.25,-1.25 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path id="path19349" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 534.23047,436.74023 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 l -1.47656,1.47656 c -0.71563,0.66862 -1.1007,1.61087 -1.04883,2.55664 0.0519,0.94577 0.50998,1.86545 1.27539,2.63086 0.76642,0.76642 1.68942,1.21503 2.6289,1.25977 0.93949,0.0447 1.85838,-0.33299 2.53516,-1.00977 l 1.5,-1.5 a 1.0001,1.0001 0 1 0 -1.41406,-1.41406 l -1.5,1.5 c -0.32323,0.32322 -0.65433,0.4455 -1.02735,0.42773 -0.37301,-0.0178 -0.82501,-0.19415 -1.30859,-0.67773 -0.48459,-0.48459 -0.6709,-0.9542 -0.69141,-1.32813 -0.0205,-0.37392 0.0941,-0.68177 0.41797,-0.98437 a 1.0001,1.0001 0 0 0 0.0234,-0.0234 l 1.5,-1.5 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z m 6.84765,-5.70703 c -0.93948,-0.0447 -1.85838,0.33299 -2.53515,1.00977 l -1.5,1.5 a 1.0001,1.0001 0 1 0 1.41406,1.41406 l 1.5,-1.5 c 0.32322,-0.32322 0.65433,-0.4455 1.02734,-0.42773 0.37302,0.0178 0.82502,0.19415 1.3086,0.67773 0.48459,0.48459 0.6709,0.9542 0.6914,1.32813 0.0205,0.37392 -0.0941,0.68177 -0.41796,0.98437 a 1.0001,1.0001 0 0 0 -0.0234,0.0234 l -1.5,1.5 a 1.0001,1.0001 0 1 0 1.41406,1.41406 l 1.47656,-1.47656 c 0.71562,-0.66862 1.1007,-1.61087 1.04883,-2.55664 -0.0519,-0.94577 -0.50998,-1.86545 -1.27539,-2.63086 -0.76642,-0.76642 -1.68942,-1.21503 -2.62891,-1.25977 z m -1.09765,3.95703 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 l -4,4 a 1.0001,1.0001 0 1 0 1.41406,1.41406 l 4,-4 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 433.5,433 c -3.27784,-9.4e-4 -5.036,2.7211 -6.36328,4.16211 -0.17644,0.19146 -0.17644,0.48627 0,0.67773 1.3275,1.44124 3.08593,4.15993 6.36328,4.16211 3.27801,0.002 5.03608,-2.72118 6.36328,-4.16211 0.17644,-0.19146 0.17644,-0.48627 0,-0.67773 C 438.53587,435.72096 436.77755,433.00094 433.5,433 Z m 0,1 a 3.4999952,3.4999933 0 0 1 3.5,3.5 3.4999952,3.4999933 0 0 1 -3.5,3.5 3.4999952,3.4999933 0 0 1 -3.5,-3.5 3.4999952,3.4999933 0 0 1 3.5,-3.5 z m 0,2 a 1.4999952,1.4999944 0 0 0 -1.5,1.5 1.4999952,1.4999944 0 0 0 1.5,1.5 1.4999952,1.4999944 0 0 0 1.5,-1.5 1.4999952,1.4999944 0 0 0 -1.5,-1.5 z" id="path19347-7"/>
- <g id="g19953" transform="translate(823.99998,415.99995)" style="display:inline;fill:#ffffff;enable-background:new">
- <path inkscape:connector-curvature="0" id="path19355-8-8" d="m -725.49998,-278.99995 c -2.725,0 -4.12655,1.87775 -5.35938,3.15234 -0.18751,0.19385 -0.18751,0.50147 0,0.69532 1.23247,1.2748 2.63438,3.15234 5.35938,3.15234 2.725,0 4.12648,-1.87882 5.35938,-3.15625 0.18625,-0.1936 0.18624,-0.49976 0,-0.69336 -1.23336,-1.2779 -2.63506,-3.15039 -5.35938,-3.15039 z m 0,1 c 1.37479,0 2.5,1.12521 2.5,2.5 0,1.37479 -1.12521,2.5 -2.5,2.5 -1.37479,0 -2.5,-1.12521 -2.5,-2.5 0,-1.37479 1.12521,-2.5 2.5,-2.5 z m 0,1 c -0.83435,0 -1.5,0.66565 -1.5,1.5 0,0.83435 0.66565,1.5 1.5,1.5 0.83435,0 1.5,-0.66565 1.5,-1.5 0,-0.83435 -0.66565,-1.5 -1.5,-1.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path sodipodi:nodetypes="cccccccccc" inkscape:connector-curvature="0" id="path19363-8-5" d="m -733.49805,-273 c -0.35971,-10e-4 -0.6028,0.36671 -0.46093,0.69727 l 3,7 c 0.18151,0.42185 0.78799,0.39645 0.93359,-0.0391 l 0.91992,-2.76367 2.76367,-0.91992 c 0.43555,-0.1456 0.46095,-0.75208 0.0391,-0.93359 l -7,-3 c -0.0617,-0.0267 -0.12812,-0.0406 -0.19532,-0.041 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
- <g id="g19964" transform="translate(823.99998,415.99995)" style="display:inline;fill:#ffffff;enable-background:new">
- <path inkscape:connector-curvature="0" id="path20627-2" d="m -704.49998,-278.99995 c -2.725,0 -4.12655,1.87775 -5.35938,3.15234 -0.18751,0.19385 -0.1875,0.50147 0,0.69532 1.23247,1.2748 2.63438,3.15234 5.35938,3.15234 2.725,0 4.12648,-1.87882 5.35938,-3.15625 0.18625,-0.1936 0.18624,-0.49976 0,-0.69336 -1.23336,-1.2779 -2.63506,-3.15039 -5.35938,-3.15039 z m 0,1 c 1.37479,0 2.5,1.12521 2.5,2.5 0,1.37479 -1.12521,2.5 -2.5,2.5 -1.37479,0 -2.5,-1.12521 -2.5,-2.5 0,-1.37479 1.12521,-2.5 2.5,-2.5 z m 0,1 c -0.83435,0 -1.5,0.66565 -1.5,1.5 0,0.83435 0.66565,1.5 1.5,1.5 0.83435,0 1.5,-0.66565 1.5,-1.5 0,-0.83435 -0.66565,-1.5 -1.5,-1.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path inkscape:connector-curvature="0" id="path20671-8" d="m -712.49805,-273 a 0.50005,0.50005 0 0 0 -0.46093,0.69727 l 3,7 a 0.50005,0.50005 0 1 0 0.91796,-0.39454 l -2.50781,-5.85156 5.85156,2.50781 a 0.50005,0.50005 0 1 0 0.39454,-0.91796 l -7,-3 a 0.50005,0.50005 0 0 0 -0.19532,-0.041 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
- <path inkscape:connector-curvature="0" id="path19886" d="m 489.50195,227 a 0.50005,0.50005 0 0 0 -0.33203,0.84375 c 1.3239,1.43817 3.0824,4.1582 6.3457,4.1582 3.26331,0 5.02376,-2.72003 6.34766,-4.1582 a 0.50037481,0.50037481 0 1 0 -0.73633,-0.67773 c -1.43556,1.55946 -2.90607,3.83593 -5.61133,3.83593 -2.70525,0 -4.17576,-2.27647 -5.61132,-3.83593 A 0.50005,0.50005 0 0 0 489.50195,227 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" transform="matrix(-1,0,0,1,970.03864,-190)" id="g19901" style="display:inline;fill:#ffffff;enable-background:new">
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 516.5,223 c -3.27784,-9.4e-4 -5.036,2.7211 -6.36328,4.16211 -0.17644,0.19146 -0.17644,0.48627 0,0.67773 1.32749,1.44124 3.08593,4.16011 6.36328,4.16211 3.27801,0.002 5.03607,-2.72118 6.36328,-4.16211 0.17644,-0.19146 0.17644,-0.48627 0,-0.67773 C 521.53587,225.72096 519.77754,223.00094 516.5,223 Z m 0,1 a 3.4999952,3.4999933 0 0 1 3.5,3.5 3.4999952,3.4999933 0 0 1 -3.5,3.5 3.4999952,3.4999933 0 0 1 -3.5,-3.5 3.4999952,3.4999933 0 0 1 3.5,-3.5 z m 0,2 a 1.4999952,1.4999944 0 0 0 -1.5,1.5 1.4999952,1.4999944 0 0 0 1.5,1.5 1.4999952,1.4999944 0 0 0 1.5,-1.5 1.4999952,1.4999944 0 0 0 -1.5,-1.5 z" transform="matrix(-1,0,0,1,970.03864,190)" id="path19890"/>
- </g>
- <g transform="translate(1e-5,4e-6)" id="g20019-5" style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
- <path inkscape:connector-curvature="0" id="path20013-1" d="m 365.5,433 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 8.5 c 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 v -8.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 8 c 0,0.55821 -0.44179,1 -1,1 -0.55821,0 -1,-0.44179 -1,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path id="path20015-6" transform="translate(718,837)" d="m -345.50781,-403 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 L -348,-400.70703 v 1.41406 l 2.5,-2.5 1.29297,1.29297 -3.79297,3.79297 v 1.41406 l 4.85352,-4.85351 a 0.50005,0.50005 0 0 0 0,-0.70704 l -2,-2 A 0.50005,0.50005 0 0 0 -345.50781,-403 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" inkscape:connector-curvature="0"/>
- <path sodipodi:nodetypes="ccccccccccc" inkscape:connector-curvature="0" id="path20017-8" d="m 373.25,440 -1,1 H 375 v 2 h -4.75 l -1,1 h 6.25 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
- <g transform="translate(483,-126)" id="g11187" style="display:inline;fill:#ffffff;enable-background:new">
- <path inkscape:connector-curvature="0" id="path10969" transform="translate(-483,126)" d="m 533.49219,157.99219 a 0.50005,0.50005 0 0 0 -0.38867,0.19531 0.50005,0.50005 0 0 0 -0.004,0.006 l -1.95313,1.95312 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 533,159.70703 v 7.57422 c -0.59355,0.34821 -1,0.9856 -1,1.71875 0,1.09865 0.90135,2 2,2 0.73315,0 1.37054,-0.40645 1.71875,-1 h 7.57422 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.95703,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.006,-0.004 l -1.95312,-1.95313 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 543.29297,169 H 536 c 0,-1.09865 -0.90135,-2 -2,-2 v -7.29297 l 1.14648,1.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.95704,-1.95703 a 0.50005,0.50005 0 0 0 -0.40429,-0.19726 z M 534,168 c 0.55821,0 1,0.44179 1,1 0,0.55821 -0.44179,1 -1,1 -0.55821,0 -1,-0.44179 -1,-1 0,-0.55821 0.44179,-1 1,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g transform="translate(42.000003,4e-6)" id="g20430-5" style="display:inline;fill:#ffffff;enable-background:new"/>
- <g id="g6336" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="path17349-5" d="m 156.49609,393.24609 a 0.50005,0.50005 0 0 0 -0.27343,0.91993 c 0.927,0.618 2.37713,0.83398 3.77734,0.83398 1.39708,0 2.84978,-0.21561 3.77734,-0.83398 a 0.50005,0.50005 0 1 0 -0.55468,-0.83204 C 162.65022,393.71561 161.2722,394 160,394 c -1.27563,0 -2.64966,-0.28402 -3.22266,-0.66602 a 0.50005,0.50005 0 0 0 -0.28125,-0.0879 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path inkscape:connector-curvature="0" id="path17351" d="m 160,389 c -1.5802,0 -3.01318,0.28529 -4.0957,0.77734 -0.54126,0.24603 -0.9977,0.54261 -1.33789,0.90821 C 154.22621,391.05115 154,391.5062 154,392 v 3 5 c 0,0.4938 0.22621,0.94885 0.56641,1.31445 0.34019,0.3656 0.79663,0.66218 1.33789,0.90821 C 156.98682,402.71471 158.4198,403 160,403 c 1.5802,0 3.01318,-0.28529 4.0957,-0.77734 0.54126,-0.24603 0.9977,-0.54261 1.33789,-0.90821 C 165.77379,400.94885 166,400.4938 166,400 v -5 -3 c 0,-0.4938 -0.22621,-0.94885 -0.56641,-1.31445 -0.34019,-0.3656 -0.79663,-0.66218 -1.33789,-0.90821 C 163.01318,389.28529 161.5802,389 160,389 Z m 0,1 c 1.45737,0 2.77356,0.27473 3.68164,0.6875 0.45404,0.20638 0.8031,0.4471 1.01953,0.67969 C 164.9176,391.59978 165,391.80344 165,392 v 3 5 c 0,0.19656 -0.0824,0.40022 -0.29883,0.63281 -0.21643,0.23259 -0.56549,0.47331 -1.01953,0.67969 C 162.77356,401.72527 161.45737,402 160,402 c -1.45737,0 -2.77356,-0.27473 -3.68164,-0.6875 -0.45404,-0.20638 -0.8031,-0.4471 -1.01953,-0.67969 C 155.0824,400.40022 155,400.19656 155,400 v -5 -3 c 0,-0.19656 0.0824,-0.40022 0.29883,-0.63281 0.21643,-0.23259 0.56549,-0.47331 1.01953,-0.67969 C 157.22644,390.27473 158.54263,390 160,390 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
- <g id="g6344" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="path17355-2" d="m 181,390 c -2.19521,0 -4.16987,0.64081 -5.61914,1.70898 -1.44928,1.06818 -2.38087,2.59156 -2.38086,4.29102 0,1.69945 0.93159,3.22284 2.38086,4.29102 C 176.83013,401.35919 178.80479,402 181,402 c 2.19521,0 4.16987,-0.64081 5.61914,-1.70898 C 188.06841,399.22284 189,397.69945 189,396 c 0,-1.69945 -0.93159,-3.22284 -2.38086,-4.29102 C 185.16987,390.64081 183.19522,390 181,390 Z m 0,1 c 1.99941,0 3.77332,0.59085 5.02539,1.51367 C 187.27746,393.4365 188,394.66345 188,396 c 0,1.33655 -0.72254,2.5635 -1.97461,3.48633 C 184.77332,400.40915 182.99941,401 181,401 c -1.99941,0 -3.77332,-0.59085 -5.02539,-1.51367 C 174.72254,398.5635 174,397.33655 174,396 c 0,-1.33654 0.72254,-2.5635 1.97461,-3.48633 C 177.22668,391.59085 179.00059,391 181,391 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path17357" d="M 178.49219,394.49219 A 0.50005,0.50005 0 0 0 178,395.00195 v 0.25 c 5.5e-4,0.26762 0.10104,0.43267 0.23438,0.61719 0.13369,0.18504 0.32089,0.36854 0.5664,0.53516 0.49103,0.33322 1.21831,0.59296 2.19727,0.5957 0.98079,0.003 1.71165,-0.25661 2.20312,-0.5918 0.24574,-0.16759 0.43113,-0.35326 0.56445,-0.53906 0.13296,-0.18529 0.23383,-0.34989 0.23438,-0.61719 v -0.002 -0.24805 a 0.50005,0.50005 0 1 0 -1,-0.004 v 0.2521 c 0,-0.11242 0.009,-0.0414 -0.0469,0.0371 -0.0564,0.0786 -0.16044,0.18856 -0.3164,0.29492 -0.31192,0.21273 -0.83026,0.42022 -1.63477,0.41797 -0.80517,-0.002 -1.32795,-0.21164 -1.64062,-0.42383 -0.15634,-0.10609 -0.26023,-0.21522 -0.31641,-0.29297 C 178.98874,395.20545 179,395.13726 179,395.25 v -0.25195 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate" id="rect17374-9" width="12.937499" height="12.937502" x="111.0625" y="390.0625"/>
- <g id="g6320" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="rect17377-5" d="m 111.4668,389 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13.0957 a 0.50005,0.50005 0 0 0 0.5,0.5 H 124.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 389.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 H 124 v 12.0957 h -12.0332 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path17381" d="M 115.49219,390.99219 A 0.50005,0.50005 0 0 0 115,391.5 v 1.5 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 v 4 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 399 h 4 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 399 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 121 v -4 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 121 v -1.5 a 0.50005,0.50005 0 1 0 -1,0 v 1.5 h -4 v -1.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 116,394 h 4 v 4 h -4 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g id="g6312" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="path17390-7" mask="none" d="m 96,389 a 0.50005,0.50005 0 0 0 -0.240234,0.0605 l -5.5,3 A 0.50005,0.50005 0 0 0 90,392.5 v 7 a 0.50005,0.50005 0 0 0 0.259766,0.43945 l 5.5,3 A 0.50005,0.50005 0 0 0 96,403 h 1 a 0.50005,0.50005 0 0 0 0.240234,-0.0605 l 5.499996,-3 A 0.50005,0.50005 0 0 0 103,399.5 v -7 a 0.50005,0.50005 0 0 0 -0.25977,-0.43945 l -5.499996,-3 A 0.50005,0.50005 0 0 0 97,389 Z m 0.126953,1 h 0.746094 L 102,392.79688 v 6.40624 L 96.873047,402 H 96.126953 L 91,399.20312 v -6.40624 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path17400" d="m 92.5,392 a 0.50005,0.50005 0 1 0 0,1 H 98.513672 100.5 a 0.50005,0.50005 0 1 0 0,-1 z m 6.013672,1 a 0.50005,0.50005 0 0 0 -0.404297,0.1875 l -3.595703,4.49609 -2.613281,-3.48437 a 0.50078095,0.50078095 0 1 0 -0.800782,0.60156 l 3,4 A 0.50005,0.50005 0 0 0 94.486328,399 a 0.50005,0.50005 0 0 0 0.404297,-0.1875 l 3.595703,-4.49609 2.613282,3.48437 a 0.50078015,0.50078015 0 1 0 0.80078,-0.60156 l -2.999999,-4 A 0.50005,0.50005 0 0 0 98.513672,393 Z m -4.027344,6 H 92.5 a 0.50005,0.50005 0 1 0 0,1 h 8 a 0.50005,0.50005 0 1 0 0,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <rect y="389" x="69" height="14" width="14" id="rect17416-6" style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"/>
- <g id="g6304" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="path17418-8" d="m 76,388.9375 c -3.894591,0 -7.0625,3.1679 -7.0625,7.0625 0,3.89459 3.167908,7.0625 7.0625,7.0625 3.894592,0 7.0625,-3.16791 7.0625,-7.0625 0,-3.8946 -3.167909,-7.0625 -7.0625,-7.0625 z m 0,1 c 3.354153,0 6.0625,2.70834 6.0625,6.0625 0,3.35415 -2.708348,6.0625 -6.0625,6.0625 -3.354152,0 -6.0625,-2.70835 -6.0625,-6.0625 0,-3.35416 2.708347,-6.0625 6.0625,-6.0625 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path17424" d="m 75.476562,390.74414 a 0.50005,0.50005 0 0 0 -0.40039,0.24024 C 74.184416,392.40936 74,393.97991 74,396 c 0,0.33476 0.05553,0.60654 0.06836,0.92188 -1.166939,-0.0798 -2.112698,-0.42664 -3.201171,-1.52344 a 0.50005,0.50005 0 1 0 -0.710938,0.70312 c 1.257685,1.26731 2.545083,1.75219 3.986328,1.83008 0.125352,1.11893 0.352857,2.1649 0.933594,3.08594 a 0.50122772,0.50122772 0 1 0 0.847656,-0.53516 C 75.471077,399.76437 75.263567,398.92779 75.142578,398 H 76 c 2.575016,3.5e-4 3.847653,-0.61523 4.722656,-1.05273 a 0.50005,0.50005 0 1 0 -0.445312,-0.89454 C 79.402347,396.49023 78.424978,397.00033 76,397 H 75.072266 C 75.055487,396.65897 75,396.38014 75,396 c 0,-1.96025 0.172858,-3.28436 0.923828,-4.48438 a 0.50005,0.50005 0 0 0 -0.447266,-0.77148 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g id="g6296" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="path8006-3-4" d="m 30.5,389 a 0.50005,0.50005 0 0 0 -0.353516,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 27,392.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.353516,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 41,399.5 v -10 A 0.50005,0.50005 0 0 0 40.5,389 Z m 0.207031,1 H 40 v 9.29297 L 37.292969,402 H 28 v -9.29297 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path8009-8" d="m 39.490234,389.98828 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 L 37.292969,392 H 29.5 a 0.50005,0.50005 0 1 0 0,1 H 37 v 7.5 a 0.50005,0.50005 0 1 0 1,0 v -7.79297 l 1.853516,-1.86133 a 0.50005,0.50005 0 0 0 -0.363282,-0.85742 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g id="g6397" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="rect12565-1-6" d="m 258.5,32 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 A 0.50005,0.50005 0 0 0 272,45.5 V 41 h -1 v 4 H 259 V 33 h 12 v 1 h 1 V 32.5 A 0.50005,0.50005 0 0 0 271.5,32 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 261.5,35 c -0.67616,-0.0096 -0.67616,1.009563 0,1 H 272 v -1 z m 0,2 c -0.67616,-0.0096 -0.67616,1.009563 0,1 H 272 v -1 z m 0,2 c -0.67616,-0.0096 -0.67616,1.009563 0,1 H 272 v -1 z" id="path12613-4-1" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccc"/>
- </g>
- <g id="g6375" style="fill:#ffffff">
- <rect y="31.999996" x="27" height="14" width="14" id="rect12107-7" style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path12109-5" d="m 34,32 c -3.860074,0 -7,3.139926 -7,7 0,3.860083 3.139927,7 7,7 3.860082,0 7,-3.139918 7,-7 0,-3.860073 -3.139917,-7 -7,-7 z m 0,1 c 3.319643,0 6,2.680365 6,6 0,3.319644 -2.680356,6 -6,6 -3.319635,0 -6,-2.680357 -6,-6 0,-3.319634 2.680366,-6 6,-6 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path12115-8" d="M 28.507812,38.244141 A 0.50005,0.50005 0 0 0 28.15625,39.101562 C 29.521925,40.47768 30.901684,41.000009 32.5,41 H 34 c 2.575017,3.52e-4 3.847654,-0.615233 4.722656,-1.052734 A 0.50005,0.50005 0 1 0 38.277344,39.052734 C 37.402346,39.490233 36.424977,40.000332 34,40 h -1.5 c -1.401674,7e-6 -2.403186,-0.362534 -3.632812,-1.601562 a 0.50005,0.50005 0 0 0 -0.359376,-0.154297 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g id="g6383" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="path12123-3" d="m 51.5,32 a 0.50005,0.50005 0 0 0 -0.353516,0.146484 l -3,3 A 0.50005,0.50005 0 0 0 48,35.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.353516,-0.146484 l 3,-3 A 0.50005,0.50005 0 0 0 62,42.5 v -10 A 0.50005,0.50005 0 0 0 61.5,32 Z m 0.207031,1 H 61 v 9.292969 L 58.292969,45 H 49 v -9.292969 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path12125-1" d="m 60.490234,32.988281 a 0.50005,0.50005 0 0 0 -0.34375,0.152344 L 58.292969,35 H 50.5 a 0.50005,0.50005 0 1 0 0,1 H 58 v 7.5 a 0.50005,0.50005 0 1 0 1,0 v -7.792969 l 1.853516,-1.861328 a 0.50005,0.50005 0 0 0 -0.363282,-0.857422 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g id="g6328" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="path12377-5" d="m 135.5,389 a 0.50004997,0.50004997 0 0 0 -0.33008,0.12305 l -2,1.75 A 0.50004997,0.50004997 0 0 0 133,391.25 V 393 h -1.5 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 1.5 c 0,0.98611 0.74054,1.6889 1.56836,1.91992 0.71525,0.19961 1.51421,0.0482 2.18359,-0.38476 L 136,397.93945 V 400.25 c 0,0.88889 0.39419,1.61848 0.96875,2.07812 C 137.54331,402.78777 138.275,403 139,403 c 0.725,0 1.45669,-0.21223 2.03125,-0.67188 C 141.60581,401.86848 142,401.13889 142,400.25 v -2.31055 l 1.24805,-1.40429 c 0.66938,0.43298 1.46834,0.58437 2.18359,0.38476 C 146.25946,396.6889 147,395.98611 147,395 v -1.5 A 0.50004997,0.50004997 0 0 0 146.5,393 H 145 v -1.75 a 0.50004997,0.50004997 0 0 0 -0.16992,-0.37695 l -2,-1.75 A 0.50004997,0.50004997 0 0 0 142.5,389 h -2 a 0.50004997,0.50004997 0 0 0 -0.35352,0.14648 L 139.29297,390 h -0.58594 l -0.85351,-0.85352 A 0.50004997,0.50004997 0 0 0 137.5,389 Z m 0.1875,1 h 1.60547 l 0.85351,0.85352 A 0.50004997,0.50004997 0 0 0 138.5,391 h 1 a 0.50004997,0.50004997 0 0 0 0.35352,-0.14648 L 140.70703,390 h 1.60547 L 144,391.47852 V 393.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 1.5 v 1 c 0,0.51389 -0.32196,0.8111 -0.83789,0.95508 -0.39408,0.10997 -0.8212,-0.0629 -1.20703,-0.25 a 0.50004997,0.50004997 0 0 0 -0.82813,-0.53711 l -2,2.25 A 0.50004997,0.50004997 0 0 0 141,397.75 v 2.5 c 0,0.61111 -0.23081,1.00652 -0.59375,1.29688 C 140.04331,401.83723 139.525,402 139,402 c -0.525,0 -1.04331,-0.16277 -1.40625,-0.45312 C 137.23081,401.25652 137,400.86111 137,400.25 v -2.5 a 0.50004997,0.50004997 0 0 0 -0.12695,-0.33203 l -2,-2.25 a 0.50004997,0.50004997 0 0 0 -0.82813,0.53711 c -0.38583,0.18707 -0.81295,0.35997 -1.20703,0.25 C 132.32196,395.8111 132,395.51389 132,395 v -1 h 1.5 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -2.02344 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path inkscape:connector-curvature="0" id="path12383" d="m 137,392 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -0.5,0.5 A 0.50005,0.50005 0 0 0 136,393 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.29297 L 137.20703,393 H 137.5 a 0.50005,0.50005 0 1 0 0,-1 z m 4,0 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -0.5,0.5 A 0.50005,0.50005 0 0 0 140,393 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.29297 L 141.20703,393 H 141.5 a 0.50005,0.50005 0 1 0 0,-1 z m -2.5,3 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 363.51562,184 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 1 0 1,0 V 185 h 12 v 3.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z" id="path10187-3-4" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 70.5,410 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.859375 l -0.824219,3.29883 a 0.50005,0.50005 0 0 0 -0.04102,0.16797 l -1.478516,5.91211 A 0.50005,0.50005 0 0 0 69.5,424 h 4.921875 a 0.50005,0.50005 0 0 0 0.160156,0 h 4.892578 a 0.50005,0.50005 0 0 0 0.484375,-0.37695 l 3.03711,-11.99024 a 0.50005,0.50005 0 0 0 -0.484375,-0.62304 l -4.90625,-0.006 a 0.50005,0.50005 0 0 0 -0.205078,0 L 74,411 v -0.5 A 0.50005,0.50005 0 0 0 73.5,410 Z m 0.5,1 h 2 v 2 h -0.921875 a 0.50005,0.50005 0 0 0 -0.160156,0 H 71 Z m 3,1 2.859375,0.004 -1.25,4.99609 h -3.96875 l 0.75,-3 H 73.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 z m 3.888672,0.004 3.980469,0.006 -1.263672,4.99 H 76.640625 Z M 71.390625,418 h 3.96875 l -1.25,5 h -3.96875 z m 5,0 h 3.960937 l -1.265624,5 h -3.945313 z" id="path14034" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 184.49609,623.99414 a 0.50005,0.50005 0 0 0 -0.34961,0.85938 L 186.29297,627 h -10.58594 l 2.14649,-2.14648 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 l -3,3 a 0.50005,0.50005 0 0 0 0,0.70704 l 3,3 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 L 175.70703,628 h 10.58594 l -2.14649,2.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.70704 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35743,-0.15234 z" id="path13677-7" inkscape:connector-curvature="0"/>
- <g id="g6391" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="path13580-7" d="m 72.5,32 a 0.50004997,0.50004997 0 0 0 -0.330078,0.123047 l -2,1.75 A 0.50004997,0.50004997 0 0 0 70,34.25 V 36 H 68.5 A 0.50004997,0.50004997 0 0 0 68,36.5 V 38 c 0,0.986111 0.740543,1.688903 1.568359,1.919922 0.715248,0.199604 1.51421,0.04822 2.183594,-0.384766 L 73,40.939453 V 43.25 c 0,0.888889 0.394191,1.618478 0.96875,2.078125 C 74.543309,45.787772 75.275,46 76,46 76.725,46 77.456691,45.787772 78.03125,45.328125 78.605809,44.868478 79,44.138889 79,43.25 v -2.310547 l 1.248047,-1.404297 c 0.669384,0.432987 1.468346,0.58437 2.183594,0.384766 C 83.259457,39.688903 84,38.986111 84,38 V 36.5 A 0.50004997,0.50004997 0 0 0 83.5,36 H 82 v -1.75 a 0.50004997,0.50004997 0 0 0 -0.169922,-0.376953 l -2,-1.75 A 0.50004997,0.50004997 0 0 0 79.5,32 h -2 a 0.50004997,0.50004997 0 0 0 -0.353516,0.146484 L 76.292969,33 H 75.707031 L 74.853516,32.146484 A 0.50004997,0.50004997 0 0 0 74.5,32 Z m 0.1875,1 h 1.605469 l 0.853515,0.853516 A 0.50004997,0.50004997 0 0 0 75.5,34 h 1 a 0.50004997,0.50004997 0 0 0 0.353516,-0.146484 L 77.707031,33 H 79.3125 L 81,34.478516 V 36.5 A 0.50004997,0.50004997 0 0 0 81.5,37 H 83 v 1 c 0,0.513889 -0.321957,0.811097 -0.837891,0.955078 -0.394082,0.109977 -0.821203,-0.06293 -1.207031,-0.25 a 0.50004997,0.50004997 0 0 0 -0.828125,-0.537109 l -2,2.25 A 0.50004997,0.50004997 0 0 0 78,40.75 v 2.5 c 0,0.611111 -0.230809,1.006522 -0.59375,1.296875 C 77.043309,44.837228 76.525,45 76,45 75.475,45 74.956691,44.837228 74.59375,44.546875 74.230809,44.256522 74,43.861111 74,43.25 v -2.5 a 0.50004997,0.50004997 0 0 0 -0.126953,-0.332031 l -2,-2.25 a 0.50004997,0.50004997 0 0 0 -0.828125,0.537109 c -0.385828,0.187069 -0.812949,0.359977 -1.207031,0.25 C 69.321957,38.811097 69,38.513889 69,38 v -1 h 1.5 A 0.50004997,0.50004997 0 0 0 71,36.5 v -2.023438 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path inkscape:connector-curvature="0" id="path13586" d="m 74,35 a 0.50005,0.50005 0 0 0 -0.353516,0.146484 l -0.5,0.5 A 0.50005,0.50005 0 0 0 73,36 v 0.5 a 0.50005,0.50005 0 1 0 1,0 V 36.207031 L 74.207031,36 H 74.5 a 0.50005,0.50005 0 1 0 0,-1 z m 4,0 a 0.50005,0.50005 0 0 0 -0.353516,0.146484 l -0.5,0.5 A 0.50005,0.50005 0 0 0 77,36 v 0.5 a 0.50005,0.50005 0 1 0 1,0 V 36.207031 L 78.207031,36 H 78.5 a 0.50005,0.50005 0 1 0 0,-1 z m -2.5,3 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 418.50786,518.99219 a 0.50005,0.50005 0 0 1 0.49219,0.50781 v 6 a 0.50005,0.50005 0 1 1 -1,0 v -2.92578 a 0.50005,0.50005 0 0 1 -0.5,0.41797 h -1 a 0.50005,0.50005 0 1 1 0,-1 h 1 a 0.50005,0.50005 0 0 1 0.5,0.42187 V 519.5 a 0.50005,0.50005 0 0 1 0.50781,-0.50781 z m -13,0 a 0.50005,0.50005 0 0 1 0.49219,0.50781 v 6 a 0.50005,0.50005 0 1 1 -1,0 v -6 a 0.50005,0.50005 0 0 1 0.50781,-0.50781 z m 4.99805,0.002 a 0.50005,0.50005 0 0 1 0.34766,0.85937 l -2.64649,2.64649 2.64649,2.64648 a 0.50005,0.50005 0 1 1 -0.70704,0.70703 l -3,-3 a 0.50005,0.50005 0 0 1 0,-0.70703 l 3,-3 a 0.50005,0.50005 0 0 1 0.35938,-0.15234 z M 414.50005,522 a 0.50005,0.50005 0 1 1 0,1 h -1 a 0.50005,0.50005 0 1 1 0,-1 z m -3,0 a 0.50005,0.50005 0 1 1 0,1 h -1 a 0.50005,0.50005 0 1 1 0,-1 z" id="path14267" inkscape:connector-curvature="0"/>
- <g id="g6366" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="path14380-1" d="m 34,116 c -3.860075,0 -7,3.13992 -7,7 0,3.86007 3.139928,7 7,7 3.860072,0 7,-3.13993 7,-7 0,-3.86008 -3.139925,-7 -7,-7 z m 0,1 c 3.319633,0 6,2.68036 6,6 0,3.31963 -2.680364,6 -6,6 -3.319636,0 -6,-2.68037 -6,-6 0,-3.31964 2.680367,-6 6,-6 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path id="path14287" transform="translate(540,10)" d="m -506.01562,106.24414 a 0.50005,0.50005 0 0 0 -0.375,0.19336 c -0.70647,0.88308 -1.16919,1.99665 -1.41016,3.5625 H -511.75 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 3.83203 c -0.0522,0.60644 -0.082,1.26334 -0.082,2 0,0.73665 0.0299,1.39356 0.082,2 H -511.75 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 3.94922 c 0.24099,1.56587 0.70375,2.67949 1.41016,3.5625 a 0.50024408,0.50024408 0 0 0 0.78124,-0.625 c -0.56556,-0.70695 -0.96391,-1.59657 -1.18554,-2.9375 h 6.54492 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -6.66797 c -0.0526,-0.59052 -0.082,-1.24749 -0.082,-2 0,-0.75251 0.0294,-1.40947 0.082,-2 h 6.66797 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -6.54492 c 0.22165,-1.34096 0.62004,-2.23062 1.18554,-2.9375 a 0.50005,0.50005 0 0 0 -0.40624,-0.81836 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0"/>
- </g>
- <rect style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate" id="rect14475-9" width="14" height="14" x="468" y="389"/>
- <g id="g6259" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="path14478-2" d="m 475,388.9375 c -3.89459,0 -7.0625,3.1679 -7.0625,7.0625 0,3.89459 3.16791,7.0625 7.0625,7.0625 3.89459,0 7.0625,-3.16791 7.0625,-7.0625 0,-3.8946 -3.16791,-7.0625 -7.0625,-7.0625 z m 0,1 c 3.35415,0 6.0625,2.70834 6.0625,6.0625 0,3.35415 -2.70835,6.0625 -6.0625,6.0625 -3.35415,0 -6.0625,-2.70835 -6.0625,-6.0625 0,-3.35416 2.70835,-6.0625 6.0625,-6.0625 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path14482" d="m 474.47656,390.74414 a 0.50005,0.50005 0 0 0 -0.40039,0.24024 C 473.18442,392.40936 473,393.97991 473,396 c 0,1.96736 0.17366,3.58622 1.07617,5.01758 a 0.50122941,0.50122941 0 1 0 0.84766,-0.53516 C 474.1712,399.28878 474,397.90804 474,396 c 0,-1.96025 0.17286,-3.28436 0.92383,-4.48438 a 0.50005,0.50005 0 0 0 -0.44727,-0.77148 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g id="g6251" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="path14492-1-5" d="m 452.5,389 c -0.79539,1.6e-4 -1.5587,0.31644 -2.12109,0.87891 l -2.5,2.5 C 447.31644,392.9413 447.00016,393.70461 447,394.5 v 5.5 c 1.7e-4,1.65084 1.34916,2.99983 3,3 h 5.5 c 0.79539,-1.6e-4 1.5587,-0.31644 2.12109,-0.87891 l 2.5,-2.5 c 0.56247,-0.56238 0.87875,-1.3257 0.87891,-2.12109 v -5.75 c -8e-5,-0.79524 -0.25969,-1.50187 -0.75391,-1.99609 C 459.75187,389.25969 459.04524,389.00008 458.25,389 Z m 0,1 h 5.75 c 0.58541,6e-5 1.00348,0.17535 1.28906,0.46094 0.28559,0.28558 0.46088,0.70365 0.46094,1.28906 v 5.75 c -10e-5,0.53061 -0.21073,1.03891 -0.58594,1.41406 l -2.5,2.5 C 456.53889,401.78928 456.03061,401.9999 455.5,402 H 450 c -1.11046,-1.1e-4 -1.99989,-0.88954 -2,-2 v -5.5 c 10e-5,-0.53061 0.21072,-1.03889 0.58594,-1.41406 l 2.5,-2.5 C 451.46111,390.21072 451.96939,390.0001 452.5,390 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path inkscape:connector-curvature="0" id="path14494-2" d="m 458.49023,390.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z M 450.5,393 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 1 0 0,-1 z m 5.99219,1.99219 A 0.50005,0.50005 0 0 0 456,395.5 v 4 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
- <g id="g6275" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="path14559-8" d="m 519.02539,389.05664 c -1.23014,0.0645 -2.42356,0.6345 -3.37891,1.58984 l -4,4 c -0.95534,0.95535 -1.53001,2.15146 -1.59765,3.38477 -0.0676,1.23331 0.38786,2.49571 1.41406,3.50977 1.02392,1.0118 2.28158,1.46686 3.51172,1.40234 1.23014,-0.0645 2.42356,-0.6345 3.37891,-1.58984 l 4,-4 c 0.95534,-0.95535 1.53001,-2.15146 1.59765,-3.38477 0.0676,-1.23331 -0.38786,-2.4957 -1.41406,-3.50977 -1.02392,-1.0118 -2.28158,-1.46686 -3.51172,-1.40234 z m 0.0527,0.99805 c 0.95617,-0.0502 1.91199,0.28134 2.75586,1.11523 0.8416,0.83165 1.17171,1.78562 1.11914,2.74414 -0.0526,0.95853 -0.50462,1.93042 -1.30664,2.73242 l -4,4 c -0.80201,0.80202 -1.76844,1.24868 -2.7246,1.29883 -0.95617,0.0502 -1.91199,-0.28134 -2.75586,-1.11523 -0.8416,-0.83164 -1.17171,-1.78562 -1.11914,-2.74414 0.0526,-0.95853 0.50462,-1.93041 1.30664,-2.73242 l 4,-4 c 0.80201,-0.80202 1.76844,-1.24868 2.7246,-1.29883 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path14564" d="m 517.47266,391.99414 a 0.50005,0.50005 0 0 0 -0.45899,0.62305 c 0.18668,0.77642 0.28491,1.42494 1.14063,2.24414 0.815,0.78022 1.39282,0.94312 2.24023,1.12695 a 0.50005,0.50005 0 1 0 0.21094,-0.97656 c -0.84931,-0.18425 -1.03849,-0.18255 -1.75977,-0.87305 -0.72218,-0.69136 -0.65665,-0.91268 -0.85937,-1.75586 a 0.50005,0.50005 0 0 0 -0.51367,-0.38867 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g id="g6267" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="path14468-2" d="m 499.91406,389.05664 c -0.77439,-0.15321 -1.63518,-0.1241 -2.51367,0.0664 -1.75698,0.38102 -3.63558,1.4051 -5.25391,3.02343 -1.61833,1.61833 -2.64241,3.49693 -3.02343,5.25391 -0.38103,1.75698 -0.11706,3.43764 0.96093,4.51563 1.07799,1.07798 2.75865,1.34196 4.51563,0.96093 1.75698,-0.38102 3.63558,-1.40511 5.25391,-3.02343 1.61832,-1.61833 2.64241,-3.49693 3.02343,-5.25391 0.38102,-1.75698 0.11705,-3.43764 -0.96093,-4.51563 -0.539,-0.53899 -1.22757,-0.87413 -2.00196,-1.02734 z m -0.21289,0.97656 c 0.61146,0.11888 1.12564,0.37564 1.50781,0.75782 0.76435,0.76434 1.0245,2.05973 0.69141,3.5957 -0.33309,1.53597 -1.26116,3.26702 -2.75391,4.75976 -1.49274,1.49275 -3.22379,2.42081 -4.75976,2.75391 -1.53597,0.3331 -2.83136,0.0729 -3.5957,-0.69141 -0.76435,-0.76434 -1.02451,-2.05973 -0.69141,-3.5957 0.33309,-1.53597 1.26117,-3.26702 2.75391,-4.75976 1.49274,-1.49275 3.22379,-2.42082 4.75976,-2.75391 0.76799,-0.16655 1.47643,-0.18529 2.08789,-0.0664 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path14550" d="m 493.47266,393.99414 a 0.50005,0.50005 0 0 0 -0.45899,0.62305 c 0.22122,0.92011 0.78151,1.92168 1.64063,2.74414 0.81151,0.77689 1.74924,1.41197 2.74023,1.62695 a 0.50005,0.50005 0 1 0 0.21094,-0.97656 c -0.70573,-0.1531 -1.535,-0.67922 -2.25977,-1.37305 -0.71878,-0.6881 -1.19119,-1.55637 -1.35937,-2.25586 a 0.50005,0.50005 0 0 0 -0.51367,-0.38867 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <path inkscape:connector-curvature="0" d="m 71.5,536 c -1.3819,0 -2.5,1.1181 -2.5,2.5 v 1 c 0,1.3818 1.118,2.5 2.5,2.5 h 9 c 1.382,0 2.5,-1.1182 2.5,-2.5 v -1 c 0,-1.3857 -1.13452,-2.48443 -2.51172,-2.48633 z m 3.5,1.00586 5.48633,0.008 c 0.8628,0 1.51367,0.63203 1.51367,1.48633 v 1 c 0,0.8578 -0.642,1.5 -1.5,1.5 H 75 Z M 71.5,544 c -1.3819,0 -2.5,1.1181 -2.5,2.5 v 1 c 0,1.3818 1.118,2.5 2.5,2.5 h 9 c 1.382,0 2.5,-1.1182 2.5,-2.5 v -1 c 0,-1.3857 -1.13452,-2.48443 -2.51172,-2.48633 z m 6.50977,1.00977 2.47656,0.004 c 0.8628,0 1.51367,0.63203 1.51367,1.48633 v 1 c 0,0.8578 -0.642,1.5 -1.5,1.5 H 78 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" id="path18055-4"/>
- <g id="g6286" style="fill:#ffffff">
- <path d="m 303.5,369 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 300,372.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 313,378.5 v -9 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 312 v 8.29297 L 309.29297,381 H 301 v -8.29297 z m 1.79883,5.03711 c -0.82251,0 -1.5,0.67749 -1.5,1.5 0,0.8225 0.67749,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21793 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28207 0.21793,-0.5 0.5,-0.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" id="path19061-0-7-6" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" id="path8009-8-5-8-9-1-5" d="M 312.14648,369.14648 309.29297,372 H 300.5 v 1 h 8.5 l 0.006,8.53711 h 1 l -0.006,-8.83008 2.85352,-2.85351 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
- <path id="path18998-9" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 398,581 h -1 v -2 l 0.8535,-0.8535 c 0.091,0.09 0.1465,0.2154 0.1465,0.3535 z m -1,-2 0.8535,-0.8535 C 397.7635,578.0555 397.6381,578 397.5,578 h -9 c -0.1326,0 -0.2598,0.053 -0.3535,0.1465 l -4,4.0078 c -0.094,0.094 -0.1465,0.2209 -0.1465,0.3535 V 591.5 c 0,0.2761 0.2239,0.5 0.5,0.5 h 13 c 0.2761,0 0.5,-0.2239 0.5,-0.5 V 589 c -10e-5,-1.0628 -0.406,-2.084 -1.1367,-2.8438 l -0.01,-0.01 L 394.707,584 h 2.793 c 0.6761,0.01 0.6761,-1.0096 0,-1 h -3.9395 c -0.3255,-0.042 -0.6029,0.235 -0.5605,0.5605 V 587.5 c -0.01,0.6761 1.0096,0.6761 1,0 v -2.793 l 2.1426,2.1426 c 0.5484,0.5702 0.8573,1.3426 0.8574,2.1504 v 2 h -12 v -8.2852 L 388.707,579 Z" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccscccccccssssscccccccccccccccccc"/>
- <path inkscape:connector-curvature="0" id="path20392" d="m 154.49904,493.99904 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.86133 l -0.82812,3.30664 a 0.50005,0.50005 0 0 0 -0.002,0.006 0.50005,0.50005 0 0 0 -0.0352,0.14258 0.50005,0.50005 0 0 0 0,0.004 l -1.48047,5.91993 a 0.50005,0.50005 0 0 0 0.48437,0.62304 h 4.92383 a 0.50005,0.50005 0 0 0 0.14453,0 h 4.90821 a 0.50005,0.50005 0 0 0 0.48437,-0.3789 l 3.03711,-11.99024 a 0.50005,0.50005 0 0 0 -0.48437,-0.62109 l -4.91016,-0.006 a 0.50005,0.50005 0 0 0 -0.20117,0 l -3.40235,-0.006 v -0.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -0.92187 a 0.50005,0.50005 0 0 0 -0.14453,0 h -0.9336 z m 3,1 2.85938,0.004 -1.24805,4.99609 h -3.96875 l 0.75,-3 h 1.10742 a 0.50005,0.50005 0 0 0 0.5,-0.5 z m 3.89063,0.006 3.98047,0.006 -1.26367,4.98828 h -3.96485 z m -6.49805,5.99414 h 3.96875 l -1.25195,5.00195 h -3.9668 z m 5,0 h 3.96094 l -1.26758,5.00195 h -3.94336 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 426.49214,518.99219 A 0.50005,0.50005 0 0 0 425.99995,519.5 v 6 a 0.50005,0.50005 0 1 0 1,0 v -2.92578 a 0.50005,0.50005 0 0 0 0.5,0.41797 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -1 a 0.50005,0.50005 0 0 0 -0.5,0.42187 V 519.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 13,0 A 0.50005,0.50005 0 0 0 438.99995,519.5 v 6 a 0.50005,0.50005 0 1 0 1,0 v -6 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -4.99805,0.002 a 0.50005,0.50005 0 0 0 -0.34766,0.85937 l 2.64649,2.64649 -2.64649,2.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.70703 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z M 430.49995,522 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z" id="path20420" inkscape:connector-curvature="0"/>
- <path id="path19004-3" d="m 512,536 c -0.52447,0 -1.0237,0.21715 -1.39258,0.57617 C 510.23866,536.93533 510,537.43678 510,538.00195 V 548 c 8e-5,0.53017 0.21103,1.03915 0.58594,1.41406 C 510.96085,549.78897 511.46978,550 512,550 h 1.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -10 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 512 c -0.45232,0 -1,-0.47106 -1,-0.99805 0,-0.26349 0.1383,-0.51454 0.33203,-0.69922 C 511.52545,537.11905 511.77501,537 512,537 h 6 v 2 h 2 v -2 h 2 v 2.00586 L 520,539 v 2 l 2,0.006 v 2 L 520,543 v 2 l 2,0.006 V 547 h -1.99414 l -0.01,-2 h -2 l 0.01,2 H 515 v 1 h 8.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -11 z m 8,7 v -2 h -2 v 2 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" inkscape:connector-curvature="0"/>
- <path sodipodi:nodetypes="cccccccccc" inkscape:connector-curvature="0" d="m 516,545 h 2 v -2 h -2 z m 0,-4 h 2 v -2 h -2 z" style="display:inline;opacity:0.8;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" id="path19014-3-8"/>
- <g transform="translate(42.000006)" style="display:inline;fill:#ffffff;enable-background:new" id="g6098">
- <path id="circle20459-6" transform="translate(-42)" d="m 469.08398,415.58594 c -0.81593,0.95753 -1.21878,2.22985 -1.04296,3.52148 0.24625,1.80912 1.56436,3.29294 3.33203,3.75 1.43669,0.37149 2.93514,-0.006 4.03515,-0.9414 -0.29636,0.0501 -0.5984,0.084 -0.9082,0.084 -0.38579,0 -0.76279,-0.0423 -1.12695,-0.11914 -0.56283,0.14546 -1.16207,0.15983 -1.75,0.008 -1.37737,-0.35614 -2.39992,-1.50634 -2.5918,-2.91601 -0.0626,-0.45958 -0.0236,-0.91417 0.0879,-1.34571 C 469.04268,417.26409 469,416.88831 469,416.50391 c 0,-0.31305 0.0328,-0.61873 0.084,-0.91797 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path sodipodi:nodetypes="cssccscc" id="circle20463-7" transform="translate(-42)" d="M 473.08594,412.25 C 471.30049,412.84735 470,414.51742 470,416.5 c 0,2.47936 2.02064,4.5 4.5,4.5 0.48878,0 0.95142,-0.0971 1.39258,-0.24219 -0.56289,-0.17378 -1.08535,-0.43906 -1.55664,-0.77343 C 472.47547,419.89744 471,418.3827 471,416.5 c 0,-1.08365 0.4989,-2.0367 1.26758,-2.67773 0.18577,-0.57127 0.46679,-1.09859 0.81836,-1.57227 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" id="circle19345" d="m 435.5,411 c -2.47344,0 -4.5,2.02656 -4.5,4.5 0,2.47344 2.02656,4.5 4.5,4.5 2.47344,0 4.5,-2.02656 4.5,-4.5 0,-2.47344 -2.02656,-4.5 -4.5,-4.5 z m 0,2 c 1.39256,0 2.5,1.10744 2.5,2.5 0,1.39256 -1.10744,2.5 -2.5,2.5 -1.39256,0 -2.5,-1.10744 -2.5,-2.5 0,-1.39256 1.10744,-2.5 2.5,-2.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <path style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.70000005;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" d="m 240.51382,409.98613 a 0.50005,0.50005 0 0 0 -0.3594,0.1524 l -3,3 a 0.50005,0.50005 0 1 0 0.707,0.707 l 3,-3 a 0.50005,0.50005 0 0 0 -0.3476,-0.8594 z m 5,0 a 0.50005,0.50005 0 0 0 -0.3594,0.1524 l -8,8 a 0.50005,0.50005 0 1 0 0.707,0.707 l 8,-8 a 0.50005,0.50005 0 0 0 -0.3476,-0.8594 z m 5,0 a 0.50005,0.50005 0 0 0 -0.3594,0.1524 l -4.416,4.416 c 0.2729,0.1952 0.5118,0.4341 0.707,0.707 l 4.416,-4.416 a 0.50005,0.50005 0 0 0 -0.3476,-0.8594 z m 0,5 a 0.50005,0.50005 0 0 0 -0.3594,0.1524 l -8,8 a 0.50005,0.50005 0 1 0 0.707,0.707 l 8,-8 a 0.50005,0.50005 0 0 0 -0.3476,-0.8594 z m -6.5059,1.0059 a 1.0000001,1 0 0 0 -1,1 1.0000001,1 0 0 0 1,1 1.0000001,1 0 0 0 1,-1 1.0000001,1 0 0 0 -1,-1 z m -2.4375,2.7305 -4.416,4.416 a 0.50005,0.50005 0 1 0 0.707,0.707 l 4.416,-4.416 c -0.2729,-0.1952 -0.5118,-0.4341 -0.707,-0.707 z m 8.9434,1.2636 a 0.50005,0.50005 0 0 0 -0.3594,0.1524 l -3,3 a 0.50005,0.50005 0 1 0 0.707,0.707 l 3,-3 a 0.50005,0.50005 0 0 0 -0.3476,-0.8594 z" id="path21556-6" inkscape:connector-curvature="0" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\path21556-6.png" inkscape:export-xdpi="115" inkscape:export-ydpi="115"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g19348" transform="translate(-252,-1102)">
- <g style="fill:#ffffff;stroke:#ffffff" id="g19344">
- <g id="g19337" style="opacity:0;fill:#ffffff"/>
- <path inkscape:connector-curvature="0" id="path19342" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 701,1726 v 7.25 c 0,0.4861 0.17047,0.94 0.49023,1.2598 0.31977,0.3197 0.77366,0.4902 1.25977,0.4902 h 6.5 c 0.48611,0 0.94,-0.1705 1.25977,-0.4902 C 710.82953,1734.19 711,1733.7361 711,1733.25 V 1726 h -1 v 7.25 c 0,0.2639 -0.0795,0.435 -0.19727,0.5527 C 709.685,1733.9205 709.51389,1734 709.25,1734 h -6.5 c -0.26389,0 -0.435,-0.08 -0.55273,-0.1973 C 702.07953,1733.685 702,1733.5139 702,1733.25 V 1726 Z m 3.5,-4 c -0.27613,0 -0.49997,0.2239 -0.5,0.5 v 1.5 h -3.5 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 11 c 0.67616,0.01 0.67616,-1.0096 0,-1 H 708 v -1.5 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 z m 0.5,1 h 2 v 1 h -2 z" sodipodi:nodetypes="cscsscsccscsscscccccccccccccccccc"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 704.49219,1726.9922 c -0.27614,0 -0.4965,0.2317 -0.49219,0.5078 v 4 c -0.01,0.6762 1.00956,0.6762 1,0 v -4 c 0.004,-0.2823 -0.22555,-0.5122 -0.50781,-0.5078 z m 3,0 c -0.27614,0 -0.4965,0.2317 -0.49219,0.5078 v 4 c -0.01,0.6762 1.00956,0.6762 1,0 v -4 c 0.004,-0.2823 -0.22555,-0.5122 -0.50781,-0.5078 z" id="path19346" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccc"/>
- </g>
- <path inkscape:connector-curvature="0" id="path21010-5" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 115.5,442 a 0.50004997,0.50004997 0 1 0 0,1 h 5 a 0.50004997,0.50004997 0 1 0 0,-1 z m 0,2 a 0.50004997,0.50004997 0 1 0 0,1 h 1.5 v 0.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 1 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 V 445 h 1.5 a 0.50004997,0.50004997 0 1 0 0,-1 z m 2.5,-13 c -3.2833,0 -6,2.4414 -6,5.5 0,1.7222 1.0876,3.2946 2.1465,4.3535 0.094,0.094 0.2209,0.1465 0.3535,0.1465 h 7 c 0.1326,0 0.2598,-0.053 0.3535,-0.1465 0.7109,-0.7108 1.4222,-1.6513 1.8262,-2.7148 C 123.8776,437.6179 124,437.066 124,436.5 c 0,-3.0586 -2.7167,-5.5 -6,-5.5 z m -2.5098,5.0059 c 0.1351,0 0.2662,0.047 0.3633,0.1406 L 116.707,437 h 2.586 l 0.8535,-0.8535 c 0.4712,-0.4506 1.1576,0.2358 0.707,0.707 L 120,437.707 v 1.793 0.5 h -1 v -0.5 -1.5 h -2 v 1.5 0.5 h -1 v -0.5 -1.793 l -0.8535,-0.8535 c -0.302,-0.3119 -0.09,-0.8341 0.3437,-0.8476 z"/>
- <g transform="translate(477,-1375)" id="g20978-8" style="display:inline;fill:#ffffff;enable-background:new">
- <path id="path20982-6" transform="translate(42,-42)" d="m -377.5,1847 c -2.13972,0 -3.85417,1.5351 -4.30664,3.541 -0.63415,-0.8727 -1.53397,-1.541 -2.69336,-1.541 -1.92708,0 -3.5,1.573 -3.5,3.5 0,1.9271 1.57294,3.5 3.5,3.5 h 7 c 2.47937,0 4.5,-2.0207 4.5,-4.5 0,-2.4793 -2.02063,-4.5 -4.5,-4.5 z m 0,3 c 0.82251,0 1.5,0.6775 1.5,1.5 0,0.8225 -0.67749,1.5 -1.5,1.5 -0.82251,0 -1.5,-0.6775 -1.5,-1.5 0,-0.8225 0.67749,-1.5 1.5,-1.5 z m -7,1 c 0.82251,0 1.5,0.6775 1.5,1.5 0,0.8225 -0.67749,1.5 -1.5,1.5 -0.82251,0 -1.5,-0.6775 -1.5,-1.5 0,-0.8225 0.67749,-1.5 1.5,-1.5 z m 7,0 c -0.28208,0 -0.5,0.2179 -0.5,0.5 0,0.2821 0.21792,0.5 0.5,0.5 0.28208,0 0.5,-0.2179 0.5,-0.5 0,-0.2821 -0.21792,-0.5 -0.5,-0.5 z m -3.94922,0.998 c 8e-5,7e-4 -8e-5,0 0,0 H -381.5 a 0.50005006,0.50005006 0 0 0 0.0508,0 z m -3.05078,0 c -0.28208,0 -0.5,0.2179 -0.5,0.5 0,0.2821 0.21792,0.5 0.5,0.5 0.28208,0 0.5,-0.2179 0.5,-0.5 0,-0.2821 -0.21792,-0.5 -0.5,-0.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path id="path20992-7" transform="translate(42,-42)" d="M -385.50781,1856.9922 A 0.50005,0.50005 0 0 0 -386,1857.5 v 1 1 a 0.50005,0.50005 0 0 0 1,0 v -0.5 h 1 v 1.5 c 3e-5,0.1326 0.0527,0.2597 0.14648,0.3535 l 1,1 c 0.0937,0.094 0.22092,0.1465 0.35352,0.1465 h 5 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -4 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 h -6 c -0.27613,0 -0.49997,0.2239 -0.5,0.5 v 0.5 h -1 v -0.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.5078 z m 11.99219,0.01 c -0.10819,0 -0.21237,0.042 -0.29688,0.1094 l -2.5,2 c -0.25044,0.2002 -0.25044,0.581 0,0.7812 l 2.5,2 c 0.32747,0.2621 0.81265,0.029 0.8125,-0.3906 v -4 c 1.1e-4,-0.2823 -0.23341,-0.5088 -0.51562,-0.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 342.55078,494 a 0.50005,0.50005 0 0 1 0.33593,0.1641 l 2.64844,2.84179 h 1.00781 c 0.45995,0.6015 1.17678,1 1.97852,1 h -3.20312 a 0.50005,0.50005 0 0 1 -0.36719,-0.1582 l -2.79492,-2.99999 A 0.50005,0.50005 0 0 1 342.5,494 a 0.50005,0.50005 0 0 1 0.0508,0 z m 5.9707,4.00589 c 0.80174,0 1.51857,-0.3985 1.97852,-1 h 2.02148 a 0.50005,0.50005 0 0 1 0.35352,0.1465 l 3,3 a 0.50005,0.50005 0 1 1 -0.70704,0.707 l -2.85351,-2.8535 h -2.29297 v 3.832 c 0.96356,1.6489 2.8299,3.71521 5.58203,4.17391 A 0.50086299,0.50086299 0 1 1 355.43945,507 c -2.4267,-0.4044 -4.21553,-1.8644 -5.39844,-3.34761 a 0.50005,0.50005 0 0 1 -0.002,0 c -0.001,0 -0.003,0 -0.004,0 -1.00443,-0.9218 -2.17404,-1 -3.22851,-0.2383 -1.05449,0.76181 -1.78322,2.34671 -1.78321,4.09771 a 0.50005,0.50005 0 1 1 -1,0 c -10e-6,-2.0216 0.80114,-3.89961 2.19727,-4.90821 0.69807,-0.5043 1.49696,-0.7238 2.2832,-0.668 0.17359,0.012 0.34649,0.043 0.51758,0.082 a 0.50005,0.50005 0 0 1 0,-0.01 v -4 z m 0,-3.99999 c 0.8225,0 1.5,0.6775 1.5,1.49999 0,0.8225 -0.6775,1.5 -1.5,1.5 -0.8225,0 -1.5,-0.6775 -1.5,-1.5 0,-0.82249 0.6775,-1.49999 1.5,-1.49999 z" id="path20567-5" inkscape:connector-curvature="0"/>
- <path sodipodi:nodetypes="scssssssssssssssssssssssssssssccccccccccccscssssssscccccccc" inkscape:connector-curvature="0" id="path15245-5-5" d="m 498.5,10 c -2.1397,0 -3.80728,1.4725 -4.33008,3.2441 C 493.52022,12.4964 492.6594,12 491.5,12 c -1.9271,0 -3.5,1.5729 -3.5,3.5 0,1.927 1.5729,3.5 3.5,3.5 h 7 c 2.4794,0 4.5,-2.0207 4.5,-4.5 0,-2.4794 -2.0206,-4.5 -4.5,-4.5 z m 0,3 c 0.8225,0 1.5,0.6774 1.5,1.5 0,0.8225 -0.6775,1.5 -1.5,1.5 -0.8225,0 -1.5,-0.6775 -1.5,-1.5 0,-0.8226 0.6775,-1.5 1.5,-1.5 z m -7,1 c 0.8225,0 1.5,0.6774 1.5,1.5 0,0.8225 -0.6775,1.5 -1.5,1.5 -0.8225,0 -1.5,-0.6775 -1.5,-1.5 0,-0.8226 0.6775,-1.5 1.5,-1.5 z m 7,0 c -0.2821,0 -0.5,0.2179 -0.5,0.5 0,0.282 0.2179,0.5 0.5,0.5 0.2821,0 0.5,-0.218 0.5,-0.5 0,-0.2821 -0.2179,-0.5 -0.5,-0.5 z m -7,1 c -0.2821,0 -0.5,0.2179 -0.5,0.5 0,0.282 0.2179,0.5 0.5,0.5 0.2821,0 0.5,-0.218 0.5,-0.5 0,-0.2821 -0.2179,-0.5 -0.5,-0.5 z m 1,5 c -0.2761,0 -0.5,0.2239 -0.5,0.5 v 1 0.5 h -1 v -0.5 c 0.004,-0.2823 -0.22555,-0.5122 -0.50781,-0.5078 -0.27615,0 -0.49651,0.2316 -0.49219,0.5078 v 1 1 c 0.009,0.6573 0.9907,0.6573 1,0 V 23 h 1 v 0.5 1 c 0,0.1326 0.053,0.2597 0.14648,0.3535 l 1,1 C 493.24048,25.9475 493.3674,26 493.5,26 h 5 c 0.2761,0 0.5,-0.2239 0.5,-0.5 v -5 c 0,-0.2761 -0.2239,-0.5 -0.5,-0.5 z m 10.98438,1 c -0.0871,0 -0.17191,0.028 -0.2461,0.074 l -3.25,2 c -0.31714,0.1953 -0.31714,0.6563 0,0.8516 l 3.25,2 c 0.33298,0.2045 0.76131,-0.035 0.76172,-0.4258 v -4 c 1.1e-4,-0.2823 -0.23341,-0.5088 -0.51562,-0.5 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;enable-background:new"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.24999976;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 302.64518,431.00052 a 1.1251124,1.1233465 0 0 0 -0.7734,0.3412 l -1.5313,1.5269 a 1.1251124,1.1233465 0 1 0 1.5918,1.5874 l 1.5293,-1.5269 a 1.1251124,1.1233465 0 0 0 -0.8164,-1.9286 z m 5.0977,0 a 1.1251124,1.1233465 0 0 0 -0.7735,0.3393 l -6.6289,6.6185 a 1.125572,1.1238054 0 1 0 1.5918,1.5893 l 2.1289,-2.1256 c 0.2384,-1.1729 1.1734,-2.1044 2.3477,-2.344 l 2.1523,-2.1489 a 1.1251124,1.1233465 0 0 0 -0.8183,-1.9286 z m 5.0996,0 a 1.1251124,1.1233465 0 0 0 -0.7735,0.3393 l -3.916,3.9099 c 0.7144,0.3005 1.2901,0.8706 1.5996,1.5795 l 3.9063,-3.9001 a 1.1251124,1.1233465 0 0 0 -0.8164,-1.9286 z m 0,5.0916 a 1.1251124,1.1233465 0 0 0 -0.7735,0.3393 l -2.123,2.1197 c -0.2257,1.2122 -1.1902,2.1751 -2.4043,2.4005 l -2.1016,2.0983 a 1.1251124,1.1233465 0 1 0 1.5918,1.5873 l 6.627,-6.6165 a 1.1251124,1.1233465 0 0 0 -0.8164,-1.9286 z m -5.8418,0.9204 c -0.5601,0 -0.9917,0.4296 -0.9981,0.9867 0.01,0.5524 0.4434,0.9887 0.9981,0.9887 0.5547,0 0.9926,-0.4363 0.998,-0.9887 -0.01,-0.5571 -0.438,-0.9867 -0.998,-0.9867 z m -2.7656,2.149 -3.8946,3.8884 a 1.1251124,1.1233465 0 1 0 1.5918,1.5873 l 3.8848,-3.8786 c -0.7095,-0.3088 -1.2808,-0.8846 -1.582,-1.5971 z m 8.6074,2.0202 a 1.1251124,1.1233465 0 0 0 -0.7735,0.3413 l -1.5293,1.5269 a 1.1251124,1.1233465 0 1 0 1.5899,1.5873 l 1.5293,-1.5269 a 1.1251124,1.1233465 0 0 0 -0.8164,-1.9286 z" id="path21492-2" inkscape:connector-curvature="0"/>
- <g transform="translate(-329.98994,63.99547)" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" id="g21552">
- <path id="path8055" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 823.98994,430.00453 v 2 h 5 v 3.7086 l 1.8538,-1.85485 c 0.0937,-0.0939 0.14631,-0.22111 0.1462,-0.35375 0.0114,-0.97402 0,-3.0415 0,-3.5 z m -3,3 v 4 h 7 l -4e-5,-4 z m 11.48438,1.125 c -0.12717,0.004 -0.24801,0.0564 -0.3379,0.14648 l -3.72851,3.72852 h -8.91211 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 8.49414 v -4.5 a 0.50005,0.50005 0 0 1 0.49219,-0.50586 0.50005,0.50005 0 0 1 0.50781,0.50586 v 4.33203 l 3.85352,-3.85351 c 0.0938,-0.0938 0.14645,-0.22092 0.14648,-0.35352 v -5 c 1.1e-4,-0.28235 -0.23342,-0.50879 -0.51562,-0.5 z" inkscape:connector-curvature="0"/>
- </g>
- <g id="g20181-9" style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new" transform="translate(-288.99602,63.999021)">
- <g id="g5276" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 803.49219,433.99219 A 0.50005,0.50005 0 0 0 803,434.5 v 4 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 4.99804,4.00586 a 0.50005,0.50005 0 0 0 -0.49414,0.50586 v 5 a 0.50005,0.50005 0 1 0 1,0 v -5 a 0.50005,0.50005 0 0 0 -0.50586,-0.50586 z" id="path20179-2" inkscape:connector-curvature="0"/>
- <path id="path20173-5" transform="translate(288.99602,-63.999021)" d="m 514.5,497.99805 a 0.50004997,0.50004997 0 0 0 -0.35352,0.14453 l -4,4 A 0.50004997,0.50004997 0 0 0 510,502.49805 v 5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 l 9,0.006 a 0.50004997,0.50004997 0 0 0 0.35547,-0.14649 l 4,-4.0039 A 0.50004997,0.50004997 0 0 0 524,503.49805 v -5 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z m 0.20898,1 h 7.5879 l -3.00391,3.00586 L 511.70312,502 Z M 523,499.70703 v 3.58399 l -3.70703,3.71289 L 511,507 v -4 l 8.5,0.004 a 0.50004997,0.50004997 0 0 0 0.35547,-0.14844 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" inkscape:connector-curvature="0"/>
- </g>
- </g>
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 241.49219,158.00781 c -0.1326,3e-5 -0.25976,0.0527 -0.35352,0.14649 l -4,4 c -0.0938,0.0938 -0.14645,0.22091 -0.14648,0.35351 v 9 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 9 c 0.1326,-3e-5 0.25975,-0.0527 0.35351,-0.14648 l 4,-4 c 0.0938,-0.0938 0.14646,-0.22092 0.14649,-0.35352 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 6.99804,1.98828 a 0.50005,0.50005 0 0 1 0.36329,0.85743 L 247,162.70703 V 169.5 a 0.50005,0.50005 0 1 1 -1,0 V 163 h -6.5 a 0.50005,0.50005 0 1 1 0,-1 h 6.79297 l 1.85351,-1.85352 a 0.50005,0.50005 0 0 1 0.34375,-0.15039 z" id="path22168"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 48.5,183 c -0.27613,4e-5 -0.49997,0.22388 -0.5,0.5 v 9 c 3e-5,0.27614 0.22387,0.49997 0.5,0.5 h 9 c 0.27613,-3e-5 0.49997,-0.22386 0.5,-0.5 v -9 c -3e-5,-0.27612 -0.22387,-0.49996 -0.5,-0.5 z" id="path5234" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 52.49219,179.00781 c -0.1326,4e-5 -0.25976,0.0527 -0.35352,0.1465 l -1.99219,1.99217 C 50.02584,181.26245 50,181.375 50,181.5 v 0.5 h 1 l 0.003,-0.296 1.69618,-1.69619 h 8.29297 v 8.29298 L 59.29548,189.99745 59,190 v 1 h 0.5 c 0.11717,0 0.23766,-0.0261 0.3457,-0.13867 l 2,-2 c 0.0938,-0.0938 0.14646,-0.22091 0.14649,-0.35352 v -9 c -3e-5,-0.27612 -0.22387,-0.49996 -0.5,-0.5 z" id="path5236" inkscape:connector-curvature="0" sodipodi:nodetypes="cccscccccccccscccccc"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" transform="translate(0.00711,-0.00712)" id="g26453-0">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 10.486328,179.01367 c -0.1326,3e-5 -0.259761,0.0527 -0.353516,0.14649 l -1.9941401,1.99414 c -0.4908663,0.47125 0.2357781,1.1979 0.7070312,0.70703 l 1.8476559,-1.84766 h 8.292969 v 8.29297 l -2.707031,2.70703 H 7.9882812 l 0.00461,-3.00655 -1,-0.002 -0.00656,3.5085 c 2.76e-5,0.27613 0.2238691,0.49997 0.5,0.5 h 8.9999998 c 0.132599,-2e-5 0.259759,-0.0527 0.353516,-0.14648 l 3,-3 c 0.09377,-0.0938 0.14646,-0.22092 0.146484,-0.35352 v -9 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z" id="path26449-3" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 6.4921875,183.00781 c -0.2761309,3e-5 -0.4999724,0.22387 -0.5,0.5 v 3 c 2.76e-5,0.27613 0.2238691,0.49997 0.5,0.5 h 3 c 0.2761309,-3e-5 0.4999724,-0.22387 0.5,-0.5 v -3 c -2.76e-5,-0.27613 -0.2238691,-0.49997 -0.5,-0.5 z" id="path26451-7" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g26527-9" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96" transform="matrix(0,-1,-1,0,220.01421,219.98576)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 27.486328,183.01367 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 2 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 9 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -2 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z" id="path26523-4" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 31.478516,179.02148 c -0.1326,3e-5 -0.259761,0.0527 -0.353516,0.14649 l -1.992188,1.99219 c -0.490839,0.47125 0.235779,1.19787 0.707032,0.70703 l 1.845703,-1.84571 h 8.292969 v 8.29297 l -2.707032,2.70703 h -8.292968 l 0.0072,-4.00727 -1,-0.002 -0.0072,4.50727 c -0.0011,0.27689 0.223106,0.50192 0.5,0.50195 h 9 c 0.132599,-2e-5 0.259759,-0.0527 0.353515,-0.14648 l 3,-3 c 0.09377,-0.0938 0.14646,-0.22092 0.146485,-0.35352 v -9 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z" id="path26525-5" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccc"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" transform="translate(147.00711,297.99288)" id="g26495-7">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 69.992896,-134.99288 v 7.50781 c 2.5e-5,0.27537 0.222678,0.4989 0.498046,0.5 l 7.507813,0.0312 0.0039,-1 -7.009765,-0.0293 v -7.00971 z" id="path26487-1" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccc"/>
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 219.49998,158 c -0.13356,2e-5 -0.26156,0.0535 -0.35547,0.14843 l -2.9707,3 c -0.31212,0.31578 -0.0885,0.85141 0.35546,0.85157 h 8.7793 l 2.85352,-2.85352 c 0.0907,-0.0928 0.21399,-0.14678 0.34375,-0.15039 0.45472,-0.0125 0.68855,0.53942 0.36328,0.85742 l -2.85352,2.85352 V 171.5 c 1.8e-4,0.44532 0.53852,0.66829 0.85352,0.35351 l 3,-3.01367 c 0.0938,-0.0938 0.14646,-0.22091 0.14648,-0.35351 L 230,158.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" transform="translate(-147.00711,-297.99288)" id="path26489-2" sodipodi:nodetypes="cccccccccccccccc"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g24420">
- <g id="g24277-2" style="display:inline;fill:#ffffff;enable-background:new" transform="translate(252.00711,707.99288)">
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="g26501-5" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" transform="translate(-252.00673,-707.99218)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 258.49962,136.9993 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path26499-8" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.55;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 10.955781,-569.99288 v 1 h 2.037109 v 5 H 7.9928902 v -1.99219 h -1 v 8.49219 a 0.50005,0.50005 0 0 0 0.5,0.5 H 13.49289 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5.5 h 5.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -6 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 3.037109,1 h 5 v 5 h -5 z m -5.9999998,6 H 12.99289 v 5 H 7.9928902 Z" id="path26503-3" inkscape:connector-curvature="0"/>
+ <g
+ transform="translate(122.00977,-1668.9941)"
+ id="g20207-3"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 346.49414,1805.9941 a 0.50005,0.50005 0 0 0 -0.34766,0.8594 l 3,3 C 348.44086,1810.7157 348,1811.8024 348,1813 c 2e-5,1.197 0.44143,2.2825 1.14648,3.1445 l -3,3 a 0.50005,0.50005 0 1 0 0.70704,0.7071 l 3,-3 c 0.86236,0.7061 1.94846,1.1484 3.14648,1.1484 0.73402,0 1.42595,-0.1693 2.05469,-0.4551 l -0.77344,-0.7734 C 353.87701,1816.9083 353.45144,1817 353,1817 c -2.21502,0 -3.99996,-1.785 -4,-4 -10e-6,-2.2151 1.78494,-4 4,-4 2.21506,0 4.00001,1.7849 4,4 -10e-6,0.4593 -0.093,0.8925 -0.23438,1.3027 l 0.76954,0.7696 c 0.29106,-0.6335 0.46483,-1.3311 0.46484,-2.0723 0,-1.198 -0.44234,-2.2841 -1.14844,-3.1465 l 3.00196,-3.0019 a 0.50005,0.50005 0 0 0 -0.36329,-0.8575 0.50005,0.50005 0 0 0 -0.34375,0.1504 l -3.00195,3.002 C 355.28248,1808.4414 354.19705,1808 353,1808 c -1.19759,0 -2.28425,0.4409 -3.14648,1.1465 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.1524 z"
+ id="path20884-9" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path20886-9"
+ transform="translate(427.99023,1668.9941)"
+ d="m -74.990234,142.01953 c -1.09866,0 -2,0.9013 -2,2 0,1.0986 0.90134,2 2,2 0.381313,0 0.73472,-0.11501 1.039062,-0.30273 a 0.50005,0.50005 0 0 0 0.107422,0.15625 l 4.146484,4.14648 h -1.621093 a 0.50005,0.50005 0 1 0 0,1 h 2.828125 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2.82812 a 0.50005,0.50005 0 1 0 -1,0 v 1.62109 l -4.146485,-4.14648 a 0.50005,0.50005 0 0 0 -0.15625,-0.10743 c 0.187715,-0.30434 0.302735,-0.65777 0.302735,-1.03906 0,-1.0987 -0.90134,-2 -2,-2 z m 0,1 c 0.5582,0 1,0.4418 1,1 0,0.5581 -0.4418,1 -1,1 -0.5582,0 -1,-0.4419 -1,-1 0,-0.5582 0.4418,-1 1,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g20897-5"
+ transform="translate(399.00976,-125.9939)">
+ <path
+ inkscape:connector-curvature="0"
+ id="path20888-1"
+ transform="translate(171.99024,125.9939)"
+ d="m -71.318359,158.00586 a 0.50005,0.50005 0 1 0 0,1 h 1.689453 l -3.382813,4.26953 c -0.291076,-0.16603 -0.621698,-0.26953 -0.978515,-0.26953 -0.733151,0 -1.370542,0.40645 -1.71875,1 h -4.582032 l 1.146485,-1.14648 a 0.50005,0.50005 0 0 0 -0.363281,-0.85743 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -2,2 a 0.50005,0.50005 0 0 0 0,0.70704 l 2,2 a 0.50005,0.50005 0 1 0 0.707031,-0.70704 l -1.146485,-1.14648 h 4.300782 c 0,1.09865 0.901352,2 2,2 1.098648,0 2,-0.90135 2,-2 0,-0.37821 -0.113913,-0.72852 -0.298828,-1.03125 l 3.298828,-4.16211 v 1.52148 a 0.50005,0.50005 0 1 0 1,0 v -2.82812 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -2.671875,6 c 0.558208,0 1,0.44179 1,1 0,0.55821 -0.441792,1 -1,1 -0.558208,0 -1,-0.44179 -1,-1 0,-0.55821 0.441792,-1 1,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path20890-1"
+ d="m 99.244141,291.73828 a 0.50005,0.50005 0 0 0 -0.396485,0.81641 L 102.36133,297 h -1.68945 a 0.50005,0.50005 0 1 0 0,1 H 103.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2.82812 a 0.50005,0.50005 0 1 0 -1,0 v 1.52148 l -3.367188,-4.25977 a 0.50005,0.50005 0 0 0 -0.388671,-0.19531 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ id="path20072-2"
+ d="m 97.917969,157.99219 c -1.58517,-0.0121 -3.159728,0.54254 -4.271485,1.65429 l -3.5,3.5 a 0.50005,0.50005 0 0 0 0,0.70704 l 2,2 a 0.50005,0.50005 0 0 0 0.707032,0 l 3.25,-3.25 c 0.584908,-0.58491 1.581654,-0.89809 2.345703,-0.69336 0.801559,0.21477 1.425851,0.83907 1.640621,1.64062 0.20473,0.76404 -0.108435,1.76078 -0.693356,2.3457 l -3.25,3.25 a 0.50005,0.50005 0 0 0 0,0.70704 l 2,2 a 0.50005,0.50005 0 0 0 0.707032,0 l 3.474604,-3.47657 a 0.50005,0.50005 0 0 0 0.0254,-0.0234 0.50005,0.50005 0 0 0 0.12109,-0.18946 c 2.06467,-2.25524 2.04105,-6.1641 -0.21875,-8.42383 -1.15788,-1.15791 -2.752722,-1.73596 -4.337891,-1.74804 z m -0.0078,1.0332 c 1.340871,0.01 2.694311,0.47748 3.638671,1.42188 1.8888,1.88873 1.87387,5.423 0.0977,7.19921 L 98.5,170.79297 97.207031,169.5 l 2.896489,-2.89648 c 0.84012,-0.84012 1.27,-2.1299 0.95312,-3.3125 -0.30683,-1.14511 -1.202555,-2.04084 -2.347656,-2.34766 -1.182591,-0.31687 -2.472368,0.11299 -3.3125,0.95312 L 92.5,164.79297 91.207031,163.5 l 3.146485,-3.14648 c 0.888243,-0.88825 2.21577,-1.33772 3.55664,-1.32813 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ id="path20705"
+ d="m 34.5,578 c -1.48507,0 -2.8535,0.46731 -3.86133,1.33594 C 29.63084,580.20456 29,581.48473 29,583 v 3.5 c 0,1.66667 0.001,2.82293 -0.89062,3.9375 -0.0709,0.0887 -0.10946,0.19893 -0.10938,0.3125 v 0.75 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 H 29 c 1.04885,0 2.13736,-0.63444 3.45898,-2.04297 l 1.66797,1.875 c 0.19883,0.22274 0.54727,0.22274 0.7461,0 l 1.62695,-1.83008 1.62695,1.83008 c 0.0947,0.10662 0.23044,0.16774 0.37305,0.16797 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 -1 -5.5 c 0,-1.51527 -0.63084,-2.79544 -1.63867,-3.66406 C 37.3535,578.46731 35.98507,578 34.5,578 Z m -3.00781,4 c 0.1353,-0.002 0.26563,0.0508 0.36133,0.14648 l 2,2 c 0.31479,0.315 0.09181,0.85335 -0.35352,0.85352 h -2 c -0.27613,-3e-5 -0.49997,-0.22387 -0.5,-0.5 v -2 c -10e-6,-0.27311 0.21911,-0.496 0.49219,-0.5 z m 5.99219,0 c 0.2822,-0.009 0.51573,0.21765 0.51562,0.5 v 2 c -3e-5,0.27613 -0.22387,0.49997 -0.5,0.5 h -2 c -0.44532,-1.7e-4 -0.66831,-0.53852 -0.35352,-0.85352 l 2,-2 c 0.0899,-0.0901 0.21072,-0.14248 0.3379,-0.14648 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path13646-9"
+ d="m 406.50195,437 a 0.50005,0.50005 0 0 0 -0.33203,0.84375 c 1.3239,1.43817 3.0824,4.1582 6.3457,4.1582 3.26331,0 5.02376,-2.72003 6.34766,-4.1582 a 0.50037481,0.50037481 0 1 0 -0.73633,-0.67773 c -1.43556,1.55946 -2.90607,3.83593 -5.61133,3.83593 -2.70525,0 -4.17576,-2.27647 -5.61132,-3.83593 A 0.50005,0.50005 0 0 0 406.50195,437 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <g
+ transform="translate(315,-0.999996)"
+ id="g13630-2"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ inkscape:connector-curvature="0"
+ d="m 164.50781,224 a 0.50004997,0.50004997 0 0 1 0.43164,0.27148 c 1.44011,2.71955 1.43779,6.74164 -0.008,9.45899 a 0.50022794,0.50022794 0 1 1 -0.88281,-0.4707 c 1.24398,-2.33836 1.24519,-6.17912 0.006,-8.51954 A 0.50004997,0.50004997 0 0 1 164.50781,224 Z m -1.99609,1.99805 a 0.50004997,0.50004997 0 0 1 0.49219,0.50586 v 4.99218 a 0.50004997,0.50004997 0 1 1 -1,0 v -4.99218 a 0.50004997,0.50004997 0 0 1 0.50781,-0.50586 z M 159.25,223 c -0.1326,2e-5 -0.25976,0.0527 -0.35352,0.14648 L 156.04297,226 H 154.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.54297 l 2.85351,2.85352 c 0.0938,0.0938 0.22092,0.14646 0.35352,0.14648 h 0.25 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 223.78125 223.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path13628-2" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ id="path13642-1"
+ d="m 453.5,222 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 450.29297,225 H 448.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.79297 l 2.85351,2.85352 A 0.50005,0.50005 0 0 0 453.5,234 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 222.78125 222.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 454 v 10 h -0.29297 l -2.85351,-2.85352 A 0.50005,0.50005 0 0 0 450.5,230 H 449 v -4 h 1.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14825-7"
+ transform="translate(-189,-315)">
+ <path
+ sodipodi:nodetypes="cccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path14782-1"
+ d="m 415.5,452.00781 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3.00781 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3.00781 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3.00781 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -10,10 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3.00781 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3.00781 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3.00781 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14818-4"
+ d="m 409.49219,454.00781 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -1.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 l 0.008,3 a 0.50005,0.50005 0 1 0 1,-0.002 l -0.006,-2.49805 h 1.49805 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1.5 h 2.5 a 0.50005,0.50005 0 1 0 0,-1 z m 3.99804,2.98828 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3,3.00782 a 0.50005,0.50005 0 1 0 0.70704,0.70508 l 3,-3.00586 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z M 416.49219,458 A 0.50005,0.50005 0 0 0 416,458.50781 v 2.5 h -1.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.49805 L 411.50195,463 a 0.50005,0.50005 0 1 0 -0.004,1 l 3,0.008 a 0.50005,0.50005 0 0 0 0.50195,-0.5 v -1.5 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 A 0.50005,0.50005 0 0 0 416.49219,458 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ id="g19296"
+ transform="translate(850,-280)"
+ style="fill:#ffffff" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19316"
+ d="m 541.57031,410.01758 c -0.79787,-0.038 -1.57177,0.27684 -2.16015,0.86523 l -1.26368,1.26367 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.26367,-1.26368 c 0.41161,-0.41161 0.88966,-0.59872 1.40429,-0.57422 0.51464,0.0245 1.08439,0.26993 1.63868,0.82422 0.55479,0.5548 0.80954,1.13546 0.83789,1.65235 0.0283,0.51688 -0.15241,0.9848 -0.57422,1.3789 a 0.50005,0.50005 0 0 0 -0.0137,0.0117 l -1.26368,1.26367 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.25195,-1.25196 c 0.61768,-0.57711 0.9366,-1.36125 0.89258,-2.16406 -0.044,-0.80281 -0.43566,-1.60948 -1.13086,-2.30469 -0.69571,-0.69571 -1.49901,-1.07724 -2.29688,-1.11523 z m -8.08008,6.97851 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1.25,1.25 c -0.58838,0.58839 -0.90322,1.36034 -0.86523,2.15821 0.038,0.79787 0.41952,1.60311 1.11523,2.29883 0.69521,0.6952 1.50384,1.08487 2.30664,1.1289 0.80281,0.044 1.585,-0.27294 2.16211,-0.89062 l 1.23829,-1.23828 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 l -1.25,1.25 a 0.50005,0.50005 0 0 0 -0.0117,0.0117 c -0.39411,0.42182 -0.86007,0.60452 -1.37696,0.57618 -0.51688,-0.0283 -1.0995,-0.2831 -1.65429,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.82227,-1.63867 -0.0245,-0.51463 0.16065,-0.99268 0.57227,-1.40429 l 1.25,-1.25 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ id="path19349"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 534.23047,436.74023 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 l -1.47656,1.47656 c -0.71563,0.66862 -1.1007,1.61087 -1.04883,2.55664 0.0519,0.94577 0.50998,1.86545 1.27539,2.63086 0.76642,0.76642 1.68942,1.21503 2.6289,1.25977 0.93949,0.0447 1.85838,-0.33299 2.53516,-1.00977 l 1.5,-1.5 a 1.0001,1.0001 0 1 0 -1.41406,-1.41406 l -1.5,1.5 c -0.32323,0.32322 -0.65433,0.4455 -1.02735,0.42773 -0.37301,-0.0178 -0.82501,-0.19415 -1.30859,-0.67773 -0.48459,-0.48459 -0.6709,-0.9542 -0.69141,-1.32813 -0.0205,-0.37392 0.0941,-0.68177 0.41797,-0.98437 a 1.0001,1.0001 0 0 0 0.0234,-0.0234 l 1.5,-1.5 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z m 6.84765,-5.70703 c -0.93948,-0.0447 -1.85838,0.33299 -2.53515,1.00977 l -1.5,1.5 a 1.0001,1.0001 0 1 0 1.41406,1.41406 l 1.5,-1.5 c 0.32322,-0.32322 0.65433,-0.4455 1.02734,-0.42773 0.37302,0.0178 0.82502,0.19415 1.3086,0.67773 0.48459,0.48459 0.6709,0.9542 0.6914,1.32813 0.0205,0.37392 -0.0941,0.68177 -0.41796,0.98437 a 1.0001,1.0001 0 0 0 -0.0234,0.0234 l -1.5,1.5 a 1.0001,1.0001 0 1 0 1.41406,1.41406 l 1.47656,-1.47656 c 0.71562,-0.66862 1.1007,-1.61087 1.04883,-2.55664 -0.0519,-0.94577 -0.50998,-1.86545 -1.27539,-2.63086 -0.76642,-0.76642 -1.68942,-1.21503 -2.62891,-1.25977 z m -1.09765,3.95703 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 l -4,4 a 1.0001,1.0001 0 1 0 1.41406,1.41406 l 4,-4 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 433.5,433 c -3.27784,-9.4e-4 -5.036,2.7211 -6.36328,4.16211 -0.17644,0.19146 -0.17644,0.48627 0,0.67773 1.3275,1.44124 3.08593,4.15993 6.36328,4.16211 3.27801,0.002 5.03608,-2.72118 6.36328,-4.16211 0.17644,-0.19146 0.17644,-0.48627 0,-0.67773 C 438.53587,435.72096 436.77755,433.00094 433.5,433 Z m 0,1 a 3.4999952,3.4999933 0 0 1 3.5,3.5 3.4999952,3.4999933 0 0 1 -3.5,3.5 3.4999952,3.4999933 0 0 1 -3.5,-3.5 3.4999952,3.4999933 0 0 1 3.5,-3.5 z m 0,2 a 1.4999952,1.4999944 0 0 0 -1.5,1.5 1.4999952,1.4999944 0 0 0 1.5,1.5 1.4999952,1.4999944 0 0 0 1.5,-1.5 1.4999952,1.4999944 0 0 0 -1.5,-1.5 z"
+ id="path19347-7" />
+ <g
+ id="g19953"
+ transform="translate(823.99998,415.99995)"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ id="path19355-8-8"
+ d="m -725.49998,-278.99995 c -2.725,0 -4.12655,1.87775 -5.35938,3.15234 -0.18751,0.19385 -0.18751,0.50147 0,0.69532 1.23247,1.2748 2.63438,3.15234 5.35938,3.15234 2.725,0 4.12648,-1.87882 5.35938,-3.15625 0.18625,-0.1936 0.18624,-0.49976 0,-0.69336 -1.23336,-1.2779 -2.63506,-3.15039 -5.35938,-3.15039 z m 0,1 c 1.37479,0 2.5,1.12521 2.5,2.5 0,1.37479 -1.12521,2.5 -2.5,2.5 -1.37479,0 -2.5,-1.12521 -2.5,-2.5 0,-1.37479 1.12521,-2.5 2.5,-2.5 z m 0,1 c -0.83435,0 -1.5,0.66565 -1.5,1.5 0,0.83435 0.66565,1.5 1.5,1.5 0.83435,0 1.5,-0.66565 1.5,-1.5 0,-0.83435 -0.66565,-1.5 -1.5,-1.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ sodipodi:nodetypes="cccccccccc"
+ inkscape:connector-curvature="0"
+ id="path19363-8-5"
+ d="m -733.49805,-273 c -0.35971,-10e-4 -0.6028,0.36671 -0.46093,0.69727 l 3,7 c 0.18151,0.42185 0.78799,0.39645 0.93359,-0.0391 l 0.91992,-2.76367 2.76367,-0.91992 c 0.43555,-0.1456 0.46095,-0.75208 0.0391,-0.93359 l -7,-3 c -0.0617,-0.0267 -0.12812,-0.0406 -0.19532,-0.041 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ id="g19964"
+ transform="translate(823.99998,415.99995)"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ id="path20627-2"
+ d="m -704.49998,-278.99995 c -2.725,0 -4.12655,1.87775 -5.35938,3.15234 -0.18751,0.19385 -0.1875,0.50147 0,0.69532 1.23247,1.2748 2.63438,3.15234 5.35938,3.15234 2.725,0 4.12648,-1.87882 5.35938,-3.15625 0.18625,-0.1936 0.18624,-0.49976 0,-0.69336 -1.23336,-1.2779 -2.63506,-3.15039 -5.35938,-3.15039 z m 0,1 c 1.37479,0 2.5,1.12521 2.5,2.5 0,1.37479 -1.12521,2.5 -2.5,2.5 -1.37479,0 -2.5,-1.12521 -2.5,-2.5 0,-1.37479 1.12521,-2.5 2.5,-2.5 z m 0,1 c -0.83435,0 -1.5,0.66565 -1.5,1.5 0,0.83435 0.66565,1.5 1.5,1.5 0.83435,0 1.5,-0.66565 1.5,-1.5 0,-0.83435 -0.66565,-1.5 -1.5,-1.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path20671-8"
+ d="m -712.49805,-273 a 0.50005,0.50005 0 0 0 -0.46093,0.69727 l 3,7 a 0.50005,0.50005 0 1 0 0.91796,-0.39454 l -2.50781,-5.85156 5.85156,2.50781 a 0.50005,0.50005 0 1 0 0.39454,-0.91796 l -7,-3 a 0.50005,0.50005 0 0 0 -0.19532,-0.041 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ id="path19886"
+ d="m 489.50195,227 a 0.50005,0.50005 0 0 0 -0.33203,0.84375 c 1.3239,1.43817 3.0824,4.1582 6.3457,4.1582 3.26331,0 5.02376,-2.72003 6.34766,-4.1582 a 0.50037481,0.50037481 0 1 0 -0.73633,-0.67773 c -1.43556,1.55946 -2.90607,3.83593 -5.61133,3.83593 -2.70525,0 -4.17576,-2.27647 -5.61132,-3.83593 A 0.50005,0.50005 0 0 0 489.50195,227 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="matrix(-1,0,0,1,970.03864,-190)"
+ id="g19901"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 516.5,223 c -3.27784,-9.4e-4 -5.036,2.7211 -6.36328,4.16211 -0.17644,0.19146 -0.17644,0.48627 0,0.67773 1.32749,1.44124 3.08593,4.16011 6.36328,4.16211 3.27801,0.002 5.03607,-2.72118 6.36328,-4.16211 0.17644,-0.19146 0.17644,-0.48627 0,-0.67773 C 521.53587,225.72096 519.77754,223.00094 516.5,223 Z m 0,1 a 3.4999952,3.4999933 0 0 1 3.5,3.5 3.4999952,3.4999933 0 0 1 -3.5,3.5 3.4999952,3.4999933 0 0 1 -3.5,-3.5 3.4999952,3.4999933 0 0 1 3.5,-3.5 z m 0,2 a 1.4999952,1.4999944 0 0 0 -1.5,1.5 1.4999952,1.4999944 0 0 0 1.5,1.5 1.4999952,1.4999944 0 0 0 1.5,-1.5 1.4999952,1.4999944 0 0 0 -1.5,-1.5 z"
+ transform="matrix(-1,0,0,1,970.03864,190)"
+ id="path19890" />
+ </g>
+ <g
+ transform="translate(1e-5,4e-6)"
+ id="g20019-5"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ id="path20013-1"
+ d="m 365.5,433 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 8.5 c 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 v -8.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 8 c 0,0.55821 -0.44179,1 -1,1 -0.55821,0 -1,-0.44179 -1,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ id="path20015-6"
+ transform="translate(718,837)"
+ d="m -345.50781,-403 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 L -348,-400.70703 v 1.41406 l 2.5,-2.5 1.29297,1.29297 -3.79297,3.79297 v 1.41406 l 4.85352,-4.85351 a 0.50005,0.50005 0 0 0 0,-0.70704 l -2,-2 A 0.50005,0.50005 0 0 0 -345.50781,-403 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path20017-8"
+ d="m 373.25,440 -1,1 H 375 v 2 h -4.75 l -1,1 h 6.25 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ transform="translate(483,-126)"
+ id="g11187"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ id="path10969"
+ transform="translate(-483,126)"
+ d="m 533.49219,157.99219 a 0.50005,0.50005 0 0 0 -0.38867,0.19531 0.50005,0.50005 0 0 0 -0.004,0.006 l -1.95313,1.95312 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 533,159.70703 v 7.57422 c -0.59355,0.34821 -1,0.9856 -1,1.71875 0,1.09865 0.90135,2 2,2 0.73315,0 1.37054,-0.40645 1.71875,-1 h 7.57422 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.95703,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.006,-0.004 l -1.95312,-1.95313 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 543.29297,169 H 536 c 0,-1.09865 -0.90135,-2 -2,-2 v -7.29297 l 1.14648,1.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.95704,-1.95703 a 0.50005,0.50005 0 0 0 -0.40429,-0.19726 z M 534,168 c 0.55821,0 1,0.44179 1,1 0,0.55821 -0.44179,1 -1,1 -0.55821,0 -1,-0.44179 -1,-1 0,-0.55821 0.44179,-1 1,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ transform="translate(42.000003,4e-6)"
+ id="g20430-5"
+ style="display:inline;fill:#ffffff;enable-background:new" />
+ <g
+ id="g6336"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="path17349-5"
+ d="m 156.49609,393.24609 a 0.50005,0.50005 0 0 0 -0.27343,0.91993 c 0.927,0.618 2.37713,0.83398 3.77734,0.83398 1.39708,0 2.84978,-0.21561 3.77734,-0.83398 a 0.50005,0.50005 0 1 0 -0.55468,-0.83204 C 162.65022,393.71561 161.2722,394 160,394 c -1.27563,0 -2.64966,-0.28402 -3.22266,-0.66602 a 0.50005,0.50005 0 0 0 -0.28125,-0.0879 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path17351"
+ d="m 160,389 c -1.5802,0 -3.01318,0.28529 -4.0957,0.77734 -0.54126,0.24603 -0.9977,0.54261 -1.33789,0.90821 C 154.22621,391.05115 154,391.5062 154,392 v 3 5 c 0,0.4938 0.22621,0.94885 0.56641,1.31445 0.34019,0.3656 0.79663,0.66218 1.33789,0.90821 C 156.98682,402.71471 158.4198,403 160,403 c 1.5802,0 3.01318,-0.28529 4.0957,-0.77734 0.54126,-0.24603 0.9977,-0.54261 1.33789,-0.90821 C 165.77379,400.94885 166,400.4938 166,400 v -5 -3 c 0,-0.4938 -0.22621,-0.94885 -0.56641,-1.31445 -0.34019,-0.3656 -0.79663,-0.66218 -1.33789,-0.90821 C 163.01318,389.28529 161.5802,389 160,389 Z m 0,1 c 1.45737,0 2.77356,0.27473 3.68164,0.6875 0.45404,0.20638 0.8031,0.4471 1.01953,0.67969 C 164.9176,391.59978 165,391.80344 165,392 v 3 5 c 0,0.19656 -0.0824,0.40022 -0.29883,0.63281 -0.21643,0.23259 -0.56549,0.47331 -1.01953,0.67969 C 162.77356,401.72527 161.45737,402 160,402 c -1.45737,0 -2.77356,-0.27473 -3.68164,-0.6875 -0.45404,-0.20638 -0.8031,-0.4471 -1.01953,-0.67969 C 155.0824,400.40022 155,400.19656 155,400 v -5 -3 c 0,-0.19656 0.0824,-0.40022 0.29883,-0.63281 0.21643,-0.23259 0.56549,-0.47331 1.01953,-0.67969 C 157.22644,390.27473 158.54263,390 160,390 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ id="g6344"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="path17355-2"
+ d="m 181,390 c -2.19521,0 -4.16987,0.64081 -5.61914,1.70898 -1.44928,1.06818 -2.38087,2.59156 -2.38086,4.29102 0,1.69945 0.93159,3.22284 2.38086,4.29102 C 176.83013,401.35919 178.80479,402 181,402 c 2.19521,0 4.16987,-0.64081 5.61914,-1.70898 C 188.06841,399.22284 189,397.69945 189,396 c 0,-1.69945 -0.93159,-3.22284 -2.38086,-4.29102 C 185.16987,390.64081 183.19522,390 181,390 Z m 0,1 c 1.99941,0 3.77332,0.59085 5.02539,1.51367 C 187.27746,393.4365 188,394.66345 188,396 c 0,1.33655 -0.72254,2.5635 -1.97461,3.48633 C 184.77332,400.40915 182.99941,401 181,401 c -1.99941,0 -3.77332,-0.59085 -5.02539,-1.51367 C 174.72254,398.5635 174,397.33655 174,396 c 0,-1.33654 0.72254,-2.5635 1.97461,-3.48633 C 177.22668,391.59085 179.00059,391 181,391 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path17357"
+ d="M 178.49219,394.49219 A 0.50005,0.50005 0 0 0 178,395.00195 v 0.25 c 5.5e-4,0.26762 0.10104,0.43267 0.23438,0.61719 0.13369,0.18504 0.32089,0.36854 0.5664,0.53516 0.49103,0.33322 1.21831,0.59296 2.19727,0.5957 0.98079,0.003 1.71165,-0.25661 2.20312,-0.5918 0.24574,-0.16759 0.43113,-0.35326 0.56445,-0.53906 0.13296,-0.18529 0.23383,-0.34989 0.23438,-0.61719 v -0.002 -0.24805 a 0.50005,0.50005 0 1 0 -1,-0.004 v 0.2521 c 0,-0.11242 0.009,-0.0414 -0.0469,0.0371 -0.0564,0.0786 -0.16044,0.18856 -0.3164,0.29492 -0.31192,0.21273 -0.83026,0.42022 -1.63477,0.41797 -0.80517,-0.002 -1.32795,-0.21164 -1.64062,-0.42383 -0.15634,-0.10609 -0.26023,-0.21522 -0.31641,-0.29297 C 178.98874,395.20545 179,395.13726 179,395.25 v -0.25195 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
+ id="rect17374-9"
+ width="12.937499"
+ height="12.937502"
+ x="111.0625"
+ y="390.0625" />
+ <g
+ id="g6320"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="rect17377-5"
+ d="m 111.4668,389 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13.0957 a 0.50005,0.50005 0 0 0 0.5,0.5 H 124.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 389.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 H 124 v 12.0957 h -12.0332 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path17381"
+ d="M 115.49219,390.99219 A 0.50005,0.50005 0 0 0 115,391.5 v 1.5 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 v 4 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 399 h 4 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 399 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 121 v -4 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 121 v -1.5 a 0.50005,0.50005 0 1 0 -1,0 v 1.5 h -4 v -1.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 116,394 h 4 v 4 h -4 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ id="g6312"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="path17390-7"
+ mask="none"
+ d="m 96,389 a 0.50005,0.50005 0 0 0 -0.240234,0.0605 l -5.5,3 A 0.50005,0.50005 0 0 0 90,392.5 v 7 a 0.50005,0.50005 0 0 0 0.259766,0.43945 l 5.5,3 A 0.50005,0.50005 0 0 0 96,403 h 1 a 0.50005,0.50005 0 0 0 0.240234,-0.0605 l 5.499996,-3 A 0.50005,0.50005 0 0 0 103,399.5 v -7 a 0.50005,0.50005 0 0 0 -0.25977,-0.43945 l -5.499996,-3 A 0.50005,0.50005 0 0 0 97,389 Z m 0.126953,1 h 0.746094 L 102,392.79688 v 6.40624 L 96.873047,402 H 96.126953 L 91,399.20312 v -6.40624 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path17400"
+ d="m 92.5,392 a 0.50005,0.50005 0 1 0 0,1 H 98.513672 100.5 a 0.50005,0.50005 0 1 0 0,-1 z m 6.013672,1 a 0.50005,0.50005 0 0 0 -0.404297,0.1875 l -3.595703,4.49609 -2.613281,-3.48437 a 0.50078095,0.50078095 0 1 0 -0.800782,0.60156 l 3,4 A 0.50005,0.50005 0 0 0 94.486328,399 a 0.50005,0.50005 0 0 0 0.404297,-0.1875 l 3.595703,-4.49609 2.613282,3.48437 a 0.50078015,0.50078015 0 1 0 0.80078,-0.60156 l -2.999999,-4 A 0.50005,0.50005 0 0 0 98.513672,393 Z m -4.027344,6 H 92.5 a 0.50005,0.50005 0 1 0 0,1 h 8 a 0.50005,0.50005 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <rect
+ y="389"
+ x="69"
+ height="14"
+ width="14"
+ id="rect17416-6"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate" />
+ <g
+ id="g6304"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="path17418-8"
+ d="m 76,388.9375 c -3.894591,0 -7.0625,3.1679 -7.0625,7.0625 0,3.89459 3.167908,7.0625 7.0625,7.0625 3.894592,0 7.0625,-3.16791 7.0625,-7.0625 0,-3.8946 -3.167909,-7.0625 -7.0625,-7.0625 z m 0,1 c 3.354153,0 6.0625,2.70834 6.0625,6.0625 0,3.35415 -2.708348,6.0625 -6.0625,6.0625 -3.354152,0 -6.0625,-2.70835 -6.0625,-6.0625 0,-3.35416 2.708347,-6.0625 6.0625,-6.0625 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path17424"
+ d="m 75.476562,390.74414 a 0.50005,0.50005 0 0 0 -0.40039,0.24024 C 74.184416,392.40936 74,393.97991 74,396 c 0,0.33476 0.05553,0.60654 0.06836,0.92188 -1.166939,-0.0798 -2.112698,-0.42664 -3.201171,-1.52344 a 0.50005,0.50005 0 1 0 -0.710938,0.70312 c 1.257685,1.26731 2.545083,1.75219 3.986328,1.83008 0.125352,1.11893 0.352857,2.1649 0.933594,3.08594 a 0.50122772,0.50122772 0 1 0 0.847656,-0.53516 C 75.471077,399.76437 75.263567,398.92779 75.142578,398 H 76 c 2.575016,3.5e-4 3.847653,-0.61523 4.722656,-1.05273 a 0.50005,0.50005 0 1 0 -0.445312,-0.89454 C 79.402347,396.49023 78.424978,397.00033 76,397 H 75.072266 C 75.055487,396.65897 75,396.38014 75,396 c 0,-1.96025 0.172858,-3.28436 0.923828,-4.48438 a 0.50005,0.50005 0 0 0 -0.447266,-0.77148 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ id="g6296"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="path8006-3-4"
+ d="m 30.5,389 a 0.50005,0.50005 0 0 0 -0.353516,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 27,392.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.353516,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 41,399.5 v -10 A 0.50005,0.50005 0 0 0 40.5,389 Z m 0.207031,1 H 40 v 9.29297 L 37.292969,402 H 28 v -9.29297 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path8009-8"
+ d="m 39.490234,389.98828 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 L 37.292969,392 H 29.5 a 0.50005,0.50005 0 1 0 0,1 H 37 v 7.5 a 0.50005,0.50005 0 1 0 1,0 v -7.79297 l 1.853516,-1.86133 a 0.50005,0.50005 0 0 0 -0.363282,-0.85742 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ id="g6397"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="rect12565-1-6"
+ d="m 258.5,32 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 A 0.50005,0.50005 0 0 0 272,45.5 V 41 h -1 v 4 H 259 V 33 h 12 v 1 h 1 V 32.5 A 0.50005,0.50005 0 0 0 271.5,32 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 261.5,35 c -0.67616,-0.0096 -0.67616,1.009563 0,1 H 272 v -1 z m 0,2 c -0.67616,-0.0096 -0.67616,1.009563 0,1 H 272 v -1 z m 0,2 c -0.67616,-0.0096 -0.67616,1.009563 0,1 H 272 v -1 z"
+ id="path12613-4-1"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccc" />
+ </g>
+ <g
+ id="g6375"
+ style="fill:#ffffff">
+ <rect
+ y="31.999996"
+ x="27"
+ height="14"
+ width="14"
+ id="rect12107-7"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path12109-5"
+ d="m 34,32 c -3.860074,0 -7,3.139926 -7,7 0,3.860083 3.139927,7 7,7 3.860082,0 7,-3.139918 7,-7 0,-3.860073 -3.139917,-7 -7,-7 z m 0,1 c 3.319643,0 6,2.680365 6,6 0,3.319644 -2.680356,6 -6,6 -3.319635,0 -6,-2.680357 -6,-6 0,-3.319634 2.680366,-6 6,-6 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path12115-8"
+ d="M 28.507812,38.244141 A 0.50005,0.50005 0 0 0 28.15625,39.101562 C 29.521925,40.47768 30.901684,41.000009 32.5,41 H 34 c 2.575017,3.52e-4 3.847654,-0.615233 4.722656,-1.052734 A 0.50005,0.50005 0 1 0 38.277344,39.052734 C 37.402346,39.490233 36.424977,40.000332 34,40 h -1.5 c -1.401674,7e-6 -2.403186,-0.362534 -3.632812,-1.601562 a 0.50005,0.50005 0 0 0 -0.359376,-0.154297 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ id="g6383"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="path12123-3"
+ d="m 51.5,32 a 0.50005,0.50005 0 0 0 -0.353516,0.146484 l -3,3 A 0.50005,0.50005 0 0 0 48,35.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.353516,-0.146484 l 3,-3 A 0.50005,0.50005 0 0 0 62,42.5 v -10 A 0.50005,0.50005 0 0 0 61.5,32 Z m 0.207031,1 H 61 v 9.292969 L 58.292969,45 H 49 v -9.292969 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path12125-1"
+ d="m 60.490234,32.988281 a 0.50005,0.50005 0 0 0 -0.34375,0.152344 L 58.292969,35 H 50.5 a 0.50005,0.50005 0 1 0 0,1 H 58 v 7.5 a 0.50005,0.50005 0 1 0 1,0 v -7.792969 l 1.853516,-1.861328 a 0.50005,0.50005 0 0 0 -0.363282,-0.857422 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ id="g6328"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="path12377-5"
+ d="m 135.5,389 a 0.50004997,0.50004997 0 0 0 -0.33008,0.12305 l -2,1.75 A 0.50004997,0.50004997 0 0 0 133,391.25 V 393 h -1.5 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 1.5 c 0,0.98611 0.74054,1.6889 1.56836,1.91992 0.71525,0.19961 1.51421,0.0482 2.18359,-0.38476 L 136,397.93945 V 400.25 c 0,0.88889 0.39419,1.61848 0.96875,2.07812 C 137.54331,402.78777 138.275,403 139,403 c 0.725,0 1.45669,-0.21223 2.03125,-0.67188 C 141.60581,401.86848 142,401.13889 142,400.25 v -2.31055 l 1.24805,-1.40429 c 0.66938,0.43298 1.46834,0.58437 2.18359,0.38476 C 146.25946,396.6889 147,395.98611 147,395 v -1.5 A 0.50004997,0.50004997 0 0 0 146.5,393 H 145 v -1.75 a 0.50004997,0.50004997 0 0 0 -0.16992,-0.37695 l -2,-1.75 A 0.50004997,0.50004997 0 0 0 142.5,389 h -2 a 0.50004997,0.50004997 0 0 0 -0.35352,0.14648 L 139.29297,390 h -0.58594 l -0.85351,-0.85352 A 0.50004997,0.50004997 0 0 0 137.5,389 Z m 0.1875,1 h 1.60547 l 0.85351,0.85352 A 0.50004997,0.50004997 0 0 0 138.5,391 h 1 a 0.50004997,0.50004997 0 0 0 0.35352,-0.14648 L 140.70703,390 h 1.60547 L 144,391.47852 V 393.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 1.5 v 1 c 0,0.51389 -0.32196,0.8111 -0.83789,0.95508 -0.39408,0.10997 -0.8212,-0.0629 -1.20703,-0.25 a 0.50004997,0.50004997 0 0 0 -0.82813,-0.53711 l -2,2.25 A 0.50004997,0.50004997 0 0 0 141,397.75 v 2.5 c 0,0.61111 -0.23081,1.00652 -0.59375,1.29688 C 140.04331,401.83723 139.525,402 139,402 c -0.525,0 -1.04331,-0.16277 -1.40625,-0.45312 C 137.23081,401.25652 137,400.86111 137,400.25 v -2.5 a 0.50004997,0.50004997 0 0 0 -0.12695,-0.33203 l -2,-2.25 a 0.50004997,0.50004997 0 0 0 -0.82813,0.53711 c -0.38583,0.18707 -0.81295,0.35997 -1.20703,0.25 C 132.32196,395.8111 132,395.51389 132,395 v -1 h 1.5 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -2.02344 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path12383"
+ d="m 137,392 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -0.5,0.5 A 0.50005,0.50005 0 0 0 136,393 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.29297 L 137.20703,393 H 137.5 a 0.50005,0.50005 0 1 0 0,-1 z m 4,0 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -0.5,0.5 A 0.50005,0.50005 0 0 0 140,393 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.29297 L 141.20703,393 H 141.5 a 0.50005,0.50005 0 1 0 0,-1 z m -2.5,3 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 363.51562,184 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 1 0 1,0 V 185 h 12 v 3.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path10187-3-4"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 70.5,410 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.859375 l -0.824219,3.29883 a 0.50005,0.50005 0 0 0 -0.04102,0.16797 l -1.478516,5.91211 A 0.50005,0.50005 0 0 0 69.5,424 h 4.921875 a 0.50005,0.50005 0 0 0 0.160156,0 h 4.892578 a 0.50005,0.50005 0 0 0 0.484375,-0.37695 l 3.03711,-11.99024 a 0.50005,0.50005 0 0 0 -0.484375,-0.62304 l -4.90625,-0.006 a 0.50005,0.50005 0 0 0 -0.205078,0 L 74,411 v -0.5 A 0.50005,0.50005 0 0 0 73.5,410 Z m 0.5,1 h 2 v 2 h -0.921875 a 0.50005,0.50005 0 0 0 -0.160156,0 H 71 Z m 3,1 2.859375,0.004 -1.25,4.99609 h -3.96875 l 0.75,-3 H 73.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 z m 3.888672,0.004 3.980469,0.006 -1.263672,4.99 H 76.640625 Z M 71.390625,418 h 3.96875 l -1.25,5 h -3.96875 z m 5,0 h 3.960937 l -1.265624,5 h -3.945313 z"
+ id="path14034"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 184.49609,623.99414 a 0.50005,0.50005 0 0 0 -0.34961,0.85938 L 186.29297,627 h -10.58594 l 2.14649,-2.14648 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 l -3,3 a 0.50005,0.50005 0 0 0 0,0.70704 l 3,3 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 L 175.70703,628 h 10.58594 l -2.14649,2.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.70704 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35743,-0.15234 z"
+ id="path13677-7"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g6391"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="path13580-7"
+ d="m 72.5,32 a 0.50004997,0.50004997 0 0 0 -0.330078,0.123047 l -2,1.75 A 0.50004997,0.50004997 0 0 0 70,34.25 V 36 H 68.5 A 0.50004997,0.50004997 0 0 0 68,36.5 V 38 c 0,0.986111 0.740543,1.688903 1.568359,1.919922 0.715248,0.199604 1.51421,0.04822 2.183594,-0.384766 L 73,40.939453 V 43.25 c 0,0.888889 0.394191,1.618478 0.96875,2.078125 C 74.543309,45.787772 75.275,46 76,46 76.725,46 77.456691,45.787772 78.03125,45.328125 78.605809,44.868478 79,44.138889 79,43.25 v -2.310547 l 1.248047,-1.404297 c 0.669384,0.432987 1.468346,0.58437 2.183594,0.384766 C 83.259457,39.688903 84,38.986111 84,38 V 36.5 A 0.50004997,0.50004997 0 0 0 83.5,36 H 82 v -1.75 a 0.50004997,0.50004997 0 0 0 -0.169922,-0.376953 l -2,-1.75 A 0.50004997,0.50004997 0 0 0 79.5,32 h -2 a 0.50004997,0.50004997 0 0 0 -0.353516,0.146484 L 76.292969,33 H 75.707031 L 74.853516,32.146484 A 0.50004997,0.50004997 0 0 0 74.5,32 Z m 0.1875,1 h 1.605469 l 0.853515,0.853516 A 0.50004997,0.50004997 0 0 0 75.5,34 h 1 a 0.50004997,0.50004997 0 0 0 0.353516,-0.146484 L 77.707031,33 H 79.3125 L 81,34.478516 V 36.5 A 0.50004997,0.50004997 0 0 0 81.5,37 H 83 v 1 c 0,0.513889 -0.321957,0.811097 -0.837891,0.955078 -0.394082,0.109977 -0.821203,-0.06293 -1.207031,-0.25 a 0.50004997,0.50004997 0 0 0 -0.828125,-0.537109 l -2,2.25 A 0.50004997,0.50004997 0 0 0 78,40.75 v 2.5 c 0,0.611111 -0.230809,1.006522 -0.59375,1.296875 C 77.043309,44.837228 76.525,45 76,45 75.475,45 74.956691,44.837228 74.59375,44.546875 74.230809,44.256522 74,43.861111 74,43.25 v -2.5 a 0.50004997,0.50004997 0 0 0 -0.126953,-0.332031 l -2,-2.25 a 0.50004997,0.50004997 0 0 0 -0.828125,0.537109 c -0.385828,0.187069 -0.812949,0.359977 -1.207031,0.25 C 69.321957,38.811097 69,38.513889 69,38 v -1 h 1.5 A 0.50004997,0.50004997 0 0 0 71,36.5 v -2.023438 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path13586"
+ d="m 74,35 a 0.50005,0.50005 0 0 0 -0.353516,0.146484 l -0.5,0.5 A 0.50005,0.50005 0 0 0 73,36 v 0.5 a 0.50005,0.50005 0 1 0 1,0 V 36.207031 L 74.207031,36 H 74.5 a 0.50005,0.50005 0 1 0 0,-1 z m 4,0 a 0.50005,0.50005 0 0 0 -0.353516,0.146484 l -0.5,0.5 A 0.50005,0.50005 0 0 0 77,36 v 0.5 a 0.50005,0.50005 0 1 0 1,0 V 36.207031 L 78.207031,36 H 78.5 a 0.50005,0.50005 0 1 0 0,-1 z m -2.5,3 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 418.50786,518.99219 a 0.50005,0.50005 0 0 1 0.49219,0.50781 v 6 a 0.50005,0.50005 0 1 1 -1,0 v -2.92578 a 0.50005,0.50005 0 0 1 -0.5,0.41797 h -1 a 0.50005,0.50005 0 1 1 0,-1 h 1 a 0.50005,0.50005 0 0 1 0.5,0.42187 V 519.5 a 0.50005,0.50005 0 0 1 0.50781,-0.50781 z m -13,0 a 0.50005,0.50005 0 0 1 0.49219,0.50781 v 6 a 0.50005,0.50005 0 1 1 -1,0 v -6 a 0.50005,0.50005 0 0 1 0.50781,-0.50781 z m 4.99805,0.002 a 0.50005,0.50005 0 0 1 0.34766,0.85937 l -2.64649,2.64649 2.64649,2.64648 a 0.50005,0.50005 0 1 1 -0.70704,0.70703 l -3,-3 a 0.50005,0.50005 0 0 1 0,-0.70703 l 3,-3 a 0.50005,0.50005 0 0 1 0.35938,-0.15234 z M 414.50005,522 a 0.50005,0.50005 0 1 1 0,1 h -1 a 0.50005,0.50005 0 1 1 0,-1 z m -3,0 a 0.50005,0.50005 0 1 1 0,1 h -1 a 0.50005,0.50005 0 1 1 0,-1 z"
+ id="path14267"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g6366"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="path14380-1"
+ d="m 34,116 c -3.860075,0 -7,3.13992 -7,7 0,3.86007 3.139928,7 7,7 3.860072,0 7,-3.13993 7,-7 0,-3.86008 -3.139925,-7 -7,-7 z m 0,1 c 3.319633,0 6,2.68036 6,6 0,3.31963 -2.680364,6 -6,6 -3.319636,0 -6,-2.68037 -6,-6 0,-3.31964 2.680367,-6 6,-6 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ id="path14287"
+ transform="translate(540,10)"
+ d="m -506.01562,106.24414 a 0.50005,0.50005 0 0 0 -0.375,0.19336 c -0.70647,0.88308 -1.16919,1.99665 -1.41016,3.5625 H -511.75 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 3.83203 c -0.0522,0.60644 -0.082,1.26334 -0.082,2 0,0.73665 0.0299,1.39356 0.082,2 H -511.75 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 3.94922 c 0.24099,1.56587 0.70375,2.67949 1.41016,3.5625 a 0.50024408,0.50024408 0 0 0 0.78124,-0.625 c -0.56556,-0.70695 -0.96391,-1.59657 -1.18554,-2.9375 h 6.54492 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -6.66797 c -0.0526,-0.59052 -0.082,-1.24749 -0.082,-2 0,-0.75251 0.0294,-1.40947 0.082,-2 h 6.66797 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -6.54492 c 0.22165,-1.34096 0.62004,-2.23062 1.18554,-2.9375 a 0.50005,0.50005 0 0 0 -0.40624,-0.81836 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
+ id="rect14475-9"
+ width="14"
+ height="14"
+ x="468"
+ y="389" />
+ <g
+ id="g6259"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="path14478-2"
+ d="m 475,388.9375 c -3.89459,0 -7.0625,3.1679 -7.0625,7.0625 0,3.89459 3.16791,7.0625 7.0625,7.0625 3.89459,0 7.0625,-3.16791 7.0625,-7.0625 0,-3.8946 -3.16791,-7.0625 -7.0625,-7.0625 z m 0,1 c 3.35415,0 6.0625,2.70834 6.0625,6.0625 0,3.35415 -2.70835,6.0625 -6.0625,6.0625 -3.35415,0 -6.0625,-2.70835 -6.0625,-6.0625 0,-3.35416 2.70835,-6.0625 6.0625,-6.0625 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14482"
+ d="m 474.47656,390.74414 a 0.50005,0.50005 0 0 0 -0.40039,0.24024 C 473.18442,392.40936 473,393.97991 473,396 c 0,1.96736 0.17366,3.58622 1.07617,5.01758 a 0.50122941,0.50122941 0 1 0 0.84766,-0.53516 C 474.1712,399.28878 474,397.90804 474,396 c 0,-1.96025 0.17286,-3.28436 0.92383,-4.48438 a 0.50005,0.50005 0 0 0 -0.44727,-0.77148 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ id="g6251"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="path14492-1-5"
+ d="m 452.5,389 c -0.79539,1.6e-4 -1.5587,0.31644 -2.12109,0.87891 l -2.5,2.5 C 447.31644,392.9413 447.00016,393.70461 447,394.5 v 5.5 c 1.7e-4,1.65084 1.34916,2.99983 3,3 h 5.5 c 0.79539,-1.6e-4 1.5587,-0.31644 2.12109,-0.87891 l 2.5,-2.5 c 0.56247,-0.56238 0.87875,-1.3257 0.87891,-2.12109 v -5.75 c -8e-5,-0.79524 -0.25969,-1.50187 -0.75391,-1.99609 C 459.75187,389.25969 459.04524,389.00008 458.25,389 Z m 0,1 h 5.75 c 0.58541,6e-5 1.00348,0.17535 1.28906,0.46094 0.28559,0.28558 0.46088,0.70365 0.46094,1.28906 v 5.75 c -10e-5,0.53061 -0.21073,1.03891 -0.58594,1.41406 l -2.5,2.5 C 456.53889,401.78928 456.03061,401.9999 455.5,402 H 450 c -1.11046,-1.1e-4 -1.99989,-0.88954 -2,-2 v -5.5 c 10e-5,-0.53061 0.21072,-1.03889 0.58594,-1.41406 l 2.5,-2.5 C 451.46111,390.21072 451.96939,390.0001 452.5,390 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14494-2"
+ d="m 458.49023,390.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z M 450.5,393 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 1 0 0,-1 z m 5.99219,1.99219 A 0.50005,0.50005 0 0 0 456,395.5 v 4 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ id="g6275"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="path14559-8"
+ d="m 519.02539,389.05664 c -1.23014,0.0645 -2.42356,0.6345 -3.37891,1.58984 l -4,4 c -0.95534,0.95535 -1.53001,2.15146 -1.59765,3.38477 -0.0676,1.23331 0.38786,2.49571 1.41406,3.50977 1.02392,1.0118 2.28158,1.46686 3.51172,1.40234 1.23014,-0.0645 2.42356,-0.6345 3.37891,-1.58984 l 4,-4 c 0.95534,-0.95535 1.53001,-2.15146 1.59765,-3.38477 0.0676,-1.23331 -0.38786,-2.4957 -1.41406,-3.50977 -1.02392,-1.0118 -2.28158,-1.46686 -3.51172,-1.40234 z m 0.0527,0.99805 c 0.95617,-0.0502 1.91199,0.28134 2.75586,1.11523 0.8416,0.83165 1.17171,1.78562 1.11914,2.74414 -0.0526,0.95853 -0.50462,1.93042 -1.30664,2.73242 l -4,4 c -0.80201,0.80202 -1.76844,1.24868 -2.7246,1.29883 -0.95617,0.0502 -1.91199,-0.28134 -2.75586,-1.11523 -0.8416,-0.83164 -1.17171,-1.78562 -1.11914,-2.74414 0.0526,-0.95853 0.50462,-1.93041 1.30664,-2.73242 l 4,-4 c 0.80201,-0.80202 1.76844,-1.24868 2.7246,-1.29883 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14564"
+ d="m 517.47266,391.99414 a 0.50005,0.50005 0 0 0 -0.45899,0.62305 c 0.18668,0.77642 0.28491,1.42494 1.14063,2.24414 0.815,0.78022 1.39282,0.94312 2.24023,1.12695 a 0.50005,0.50005 0 1 0 0.21094,-0.97656 c -0.84931,-0.18425 -1.03849,-0.18255 -1.75977,-0.87305 -0.72218,-0.69136 -0.65665,-0.91268 -0.85937,-1.75586 a 0.50005,0.50005 0 0 0 -0.51367,-0.38867 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ id="g6267"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="path14468-2"
+ d="m 499.91406,389.05664 c -0.77439,-0.15321 -1.63518,-0.1241 -2.51367,0.0664 -1.75698,0.38102 -3.63558,1.4051 -5.25391,3.02343 -1.61833,1.61833 -2.64241,3.49693 -3.02343,5.25391 -0.38103,1.75698 -0.11706,3.43764 0.96093,4.51563 1.07799,1.07798 2.75865,1.34196 4.51563,0.96093 1.75698,-0.38102 3.63558,-1.40511 5.25391,-3.02343 1.61832,-1.61833 2.64241,-3.49693 3.02343,-5.25391 0.38102,-1.75698 0.11705,-3.43764 -0.96093,-4.51563 -0.539,-0.53899 -1.22757,-0.87413 -2.00196,-1.02734 z m -0.21289,0.97656 c 0.61146,0.11888 1.12564,0.37564 1.50781,0.75782 0.76435,0.76434 1.0245,2.05973 0.69141,3.5957 -0.33309,1.53597 -1.26116,3.26702 -2.75391,4.75976 -1.49274,1.49275 -3.22379,2.42081 -4.75976,2.75391 -1.53597,0.3331 -2.83136,0.0729 -3.5957,-0.69141 -0.76435,-0.76434 -1.02451,-2.05973 -0.69141,-3.5957 0.33309,-1.53597 1.26117,-3.26702 2.75391,-4.75976 1.49274,-1.49275 3.22379,-2.42082 4.75976,-2.75391 0.76799,-0.16655 1.47643,-0.18529 2.08789,-0.0664 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14550"
+ d="m 493.47266,393.99414 a 0.50005,0.50005 0 0 0 -0.45899,0.62305 c 0.22122,0.92011 0.78151,1.92168 1.64063,2.74414 0.81151,0.77689 1.74924,1.41197 2.74023,1.62695 a 0.50005,0.50005 0 1 0 0.21094,-0.97656 c -0.70573,-0.1531 -1.535,-0.67922 -2.25977,-1.37305 -0.71878,-0.6881 -1.19119,-1.55637 -1.35937,-2.25586 a 0.50005,0.50005 0 0 0 -0.51367,-0.38867 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ d="m 71.5,536 c -1.3819,0 -2.5,1.1181 -2.5,2.5 v 1 c 0,1.3818 1.118,2.5 2.5,2.5 h 9 c 1.382,0 2.5,-1.1182 2.5,-2.5 v -1 c 0,-1.3857 -1.13452,-2.48443 -2.51172,-2.48633 z m 3.5,1.00586 5.48633,0.008 c 0.8628,0 1.51367,0.63203 1.51367,1.48633 v 1 c 0,0.8578 -0.642,1.5 -1.5,1.5 H 75 Z M 71.5,544 c -1.3819,0 -2.5,1.1181 -2.5,2.5 v 1 c 0,1.3818 1.118,2.5 2.5,2.5 h 9 c 1.382,0 2.5,-1.1182 2.5,-2.5 v -1 c 0,-1.3857 -1.13452,-2.48443 -2.51172,-2.48633 z m 6.50977,1.00977 2.47656,0.004 c 0.8628,0 1.51367,0.63203 1.51367,1.48633 v 1 c 0,0.8578 -0.642,1.5 -1.5,1.5 H 78 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path18055-4" />
+ <g
+ id="g6286"
+ style="fill:#ffffff">
+ <path
+ d="m 303.5,369 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 300,372.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 313,378.5 v -9 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 312 v 8.29297 L 309.29297,381 H 301 v -8.29297 z m 1.79883,5.03711 c -0.82251,0 -1.5,0.67749 -1.5,1.5 0,0.8225 0.67749,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21793 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28207 0.21793,-0.5 0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="path19061-0-7-6"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path8009-8-5-8-9-1-5"
+ d="M 312.14648,369.14648 309.29297,372 H 300.5 v 1 h 8.5 l 0.006,8.53711 h 1 l -0.006,-8.83008 2.85352,-2.85351 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <path
+ id="path18998-9"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 398,581 h -1 v -2 l 0.8535,-0.8535 c 0.091,0.09 0.1465,0.2154 0.1465,0.3535 z m -1,-2 0.8535,-0.8535 C 397.7635,578.0555 397.6381,578 397.5,578 h -9 c -0.1326,0 -0.2598,0.053 -0.3535,0.1465 l -4,4.0078 c -0.094,0.094 -0.1465,0.2209 -0.1465,0.3535 V 591.5 c 0,0.2761 0.2239,0.5 0.5,0.5 h 13 c 0.2761,0 0.5,-0.2239 0.5,-0.5 V 589 c -10e-5,-1.0628 -0.406,-2.084 -1.1367,-2.8438 l -0.01,-0.01 L 394.707,584 h 2.793 c 0.6761,0.01 0.6761,-1.0096 0,-1 h -3.9395 c -0.3255,-0.042 -0.6029,0.235 -0.5605,0.5605 V 587.5 c -0.01,0.6761 1.0096,0.6761 1,0 v -2.793 l 2.1426,2.1426 c 0.5484,0.5702 0.8573,1.3426 0.8574,2.1504 v 2 h -12 v -8.2852 L 388.707,579 Z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccscccccccssssscccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path20392"
+ d="m 154.49904,493.99904 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.86133 l -0.82812,3.30664 a 0.50005,0.50005 0 0 0 -0.002,0.006 0.50005,0.50005 0 0 0 -0.0352,0.14258 0.50005,0.50005 0 0 0 0,0.004 l -1.48047,5.91993 a 0.50005,0.50005 0 0 0 0.48437,0.62304 h 4.92383 a 0.50005,0.50005 0 0 0 0.14453,0 h 4.90821 a 0.50005,0.50005 0 0 0 0.48437,-0.3789 l 3.03711,-11.99024 a 0.50005,0.50005 0 0 0 -0.48437,-0.62109 l -4.91016,-0.006 a 0.50005,0.50005 0 0 0 -0.20117,0 l -3.40235,-0.006 v -0.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -0.92187 a 0.50005,0.50005 0 0 0 -0.14453,0 h -0.9336 z m 3,1 2.85938,0.004 -1.24805,4.99609 h -3.96875 l 0.75,-3 h 1.10742 a 0.50005,0.50005 0 0 0 0.5,-0.5 z m 3.89063,0.006 3.98047,0.006 -1.26367,4.98828 h -3.96485 z m -6.49805,5.99414 h 3.96875 l -1.25195,5.00195 h -3.9668 z m 5,0 h 3.96094 l -1.26758,5.00195 h -3.94336 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 426.49214,518.99219 A 0.50005,0.50005 0 0 0 425.99995,519.5 v 6 a 0.50005,0.50005 0 1 0 1,0 v -2.92578 a 0.50005,0.50005 0 0 0 0.5,0.41797 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -1 a 0.50005,0.50005 0 0 0 -0.5,0.42187 V 519.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 13,0 A 0.50005,0.50005 0 0 0 438.99995,519.5 v 6 a 0.50005,0.50005 0 1 0 1,0 v -6 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -4.99805,0.002 a 0.50005,0.50005 0 0 0 -0.34766,0.85937 l 2.64649,2.64649 -2.64649,2.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.70703 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z M 430.49995,522 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path20420"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path19004-3"
+ d="m 512,536 c -0.52447,0 -1.0237,0.21715 -1.39258,0.57617 C 510.23866,536.93533 510,537.43678 510,538.00195 V 548 c 8e-5,0.53017 0.21103,1.03915 0.58594,1.41406 C 510.96085,549.78897 511.46978,550 512,550 h 1.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -10 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 512 c -0.45232,0 -1,-0.47106 -1,-0.99805 0,-0.26349 0.1383,-0.51454 0.33203,-0.69922 C 511.52545,537.11905 511.77501,537 512,537 h 6 v 2 h 2 v -2 h 2 v 2.00586 L 520,539 v 2 l 2,0.006 v 2 L 520,543 v 2 l 2,0.006 V 547 h -1.99414 l -0.01,-2 h -2 l 0.01,2 H 515 v 1 h 8.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -11 z m 8,7 v -2 h -2 v 2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cccccccccc"
+ inkscape:connector-curvature="0"
+ d="m 516,545 h 2 v -2 h -2 z m 0,-4 h 2 v -2 h -2 z"
+ style="display:inline;opacity:0.8;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="path19014-3-8" />
+ <g
+ transform="translate(42.000006)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g6098">
+ <path
+ id="circle20459-6"
+ transform="translate(-42)"
+ d="m 469.08398,415.58594 c -0.81593,0.95753 -1.21878,2.22985 -1.04296,3.52148 0.24625,1.80912 1.56436,3.29294 3.33203,3.75 1.43669,0.37149 2.93514,-0.006 4.03515,-0.9414 -0.29636,0.0501 -0.5984,0.084 -0.9082,0.084 -0.38579,0 -0.76279,-0.0423 -1.12695,-0.11914 -0.56283,0.14546 -1.16207,0.15983 -1.75,0.008 -1.37737,-0.35614 -2.39992,-1.50634 -2.5918,-2.91601 -0.0626,-0.45958 -0.0236,-0.91417 0.0879,-1.34571 C 469.04268,417.26409 469,416.88831 469,416.50391 c 0,-0.31305 0.0328,-0.61873 0.084,-0.91797 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cssccscc"
+ id="circle20463-7"
+ transform="translate(-42)"
+ d="M 473.08594,412.25 C 471.30049,412.84735 470,414.51742 470,416.5 c 0,2.47936 2.02064,4.5 4.5,4.5 0.48878,0 0.95142,-0.0971 1.39258,-0.24219 -0.56289,-0.17378 -1.08535,-0.43906 -1.55664,-0.77343 C 472.47547,419.89744 471,418.3827 471,416.5 c 0,-1.08365 0.4989,-2.0367 1.26758,-2.67773 0.18577,-0.57127 0.46679,-1.09859 0.81836,-1.57227 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="circle19345"
+ d="m 435.5,411 c -2.47344,0 -4.5,2.02656 -4.5,4.5 0,2.47344 2.02656,4.5 4.5,4.5 2.47344,0 4.5,-2.02656 4.5,-4.5 0,-2.47344 -2.02656,-4.5 -4.5,-4.5 z m 0,2 c 1.39256,0 2.5,1.10744 2.5,2.5 0,1.39256 -1.10744,2.5 -2.5,2.5 -1.39256,0 -2.5,-1.10744 -2.5,-2.5 0,-1.39256 1.10744,-2.5 2.5,-2.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <path
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.70000005;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ d="m 240.51382,409.98613 a 0.50005,0.50005 0 0 0 -0.3594,0.1524 l -3,3 a 0.50005,0.50005 0 1 0 0.707,0.707 l 3,-3 a 0.50005,0.50005 0 0 0 -0.3476,-0.8594 z m 5,0 a 0.50005,0.50005 0 0 0 -0.3594,0.1524 l -8,8 a 0.50005,0.50005 0 1 0 0.707,0.707 l 8,-8 a 0.50005,0.50005 0 0 0 -0.3476,-0.8594 z m 5,0 a 0.50005,0.50005 0 0 0 -0.3594,0.1524 l -4.416,4.416 c 0.2729,0.1952 0.5118,0.4341 0.707,0.707 l 4.416,-4.416 a 0.50005,0.50005 0 0 0 -0.3476,-0.8594 z m 0,5 a 0.50005,0.50005 0 0 0 -0.3594,0.1524 l -8,8 a 0.50005,0.50005 0 1 0 0.707,0.707 l 8,-8 a 0.50005,0.50005 0 0 0 -0.3476,-0.8594 z m -6.5059,1.0059 a 1.0000001,1 0 0 0 -1,1 1.0000001,1 0 0 0 1,1 1.0000001,1 0 0 0 1,-1 1.0000001,1 0 0 0 -1,-1 z m -2.4375,2.7305 -4.416,4.416 a 0.50005,0.50005 0 1 0 0.707,0.707 l 4.416,-4.416 c -0.2729,-0.1952 -0.5118,-0.4341 -0.707,-0.707 z m 8.9434,1.2636 a 0.50005,0.50005 0 0 0 -0.3594,0.1524 l -3,3 a 0.50005,0.50005 0 1 0 0.707,0.707 l 3,-3 a 0.50005,0.50005 0 0 0 -0.3476,-0.8594 z"
+ id="path21556-6"
+ inkscape:connector-curvature="0"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\path21556-6.png"
+ inkscape:export-xdpi="115"
+ inkscape:export-ydpi="115" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g19348"
+ transform="translate(-252,-1102)">
+ <g
+ style="fill:#ffffff;stroke:#ffffff"
+ id="g19344">
+ <g
+ id="g19337"
+ style="opacity:0;fill:#ffffff" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19342"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 701,1726 v 7.25 c 0,0.4861 0.17047,0.94 0.49023,1.2598 0.31977,0.3197 0.77366,0.4902 1.25977,0.4902 h 6.5 c 0.48611,0 0.94,-0.1705 1.25977,-0.4902 C 710.82953,1734.19 711,1733.7361 711,1733.25 V 1726 h -1 v 7.25 c 0,0.2639 -0.0795,0.435 -0.19727,0.5527 C 709.685,1733.9205 709.51389,1734 709.25,1734 h -6.5 c -0.26389,0 -0.435,-0.08 -0.55273,-0.1973 C 702.07953,1733.685 702,1733.5139 702,1733.25 V 1726 Z m 3.5,-4 c -0.27613,0 -0.49997,0.2239 -0.5,0.5 v 1.5 h -3.5 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 11 c 0.67616,0.01 0.67616,-1.0096 0,-1 H 708 v -1.5 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 z m 0.5,1 h 2 v 1 h -2 z"
+ sodipodi:nodetypes="cscsscsccscsscscccccccccccccccccc" />
</g>
- <g transform="matrix(0,1,1,0,850.0517,109.94829)" id="g26539-4" style="display:inline;fill:#ffffff;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 27.544922,-565.04492 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 2 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 8 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -2 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z" id="path26497-4" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.55;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 28.544922,-570.04492 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 3.5 h 1 v -3 h 5 v 3 h 1 v -3 h 5 v 5 h -3 v 1 h 3.5 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -6 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z m -0.5,9 0.0049,3.49327 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 6 c 0.275371,-3e-5 0.498899,-0.22268 0.5,-0.49805 l 0.0019,-3.5 -1,-0.002 v 3 h -5 l -0.0068,-2.99132 z" id="path26505-7" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccccccccccccccccc"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 704.49219,1726.9922 c -0.27614,0 -0.4965,0.2317 -0.49219,0.5078 v 4 c -0.01,0.6762 1.00956,0.6762 1,0 v -4 c 0.004,-0.2823 -0.22555,-0.5122 -0.50781,-0.5078 z m 3,0 c -0.27614,0 -0.4965,0.2317 -0.49219,0.5078 v 4 c -0.01,0.6762 1.00956,0.6762 1,0 v -4 c 0.004,-0.2823 -0.22555,-0.5122 -0.50781,-0.5078 z"
+ id="path19346"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccc" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ id="path21010-5"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 115.5,442 a 0.50004997,0.50004997 0 1 0 0,1 h 5 a 0.50004997,0.50004997 0 1 0 0,-1 z m 0,2 a 0.50004997,0.50004997 0 1 0 0,1 h 1.5 v 0.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 1 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 V 445 h 1.5 a 0.50004997,0.50004997 0 1 0 0,-1 z m 2.5,-13 c -3.2833,0 -6,2.4414 -6,5.5 0,1.7222 1.0876,3.2946 2.1465,4.3535 0.094,0.094 0.2209,0.1465 0.3535,0.1465 h 7 c 0.1326,0 0.2598,-0.053 0.3535,-0.1465 0.7109,-0.7108 1.4222,-1.6513 1.8262,-2.7148 C 123.8776,437.6179 124,437.066 124,436.5 c 0,-3.0586 -2.7167,-5.5 -6,-5.5 z m -2.5098,5.0059 c 0.1351,0 0.2662,0.047 0.3633,0.1406 L 116.707,437 h 2.586 l 0.8535,-0.8535 c 0.4712,-0.4506 1.1576,0.2358 0.707,0.707 L 120,437.707 v 1.793 0.5 h -1 v -0.5 -1.5 h -2 v 1.5 0.5 h -1 v -0.5 -1.793 l -0.8535,-0.8535 c -0.302,-0.3119 -0.09,-0.8341 0.3437,-0.8476 z" />
+ <g
+ transform="translate(477,-1375)"
+ id="g20978-8"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ id="path20982-6"
+ transform="translate(42,-42)"
+ d="m -377.5,1847 c -2.13972,0 -3.85417,1.5351 -4.30664,3.541 -0.63415,-0.8727 -1.53397,-1.541 -2.69336,-1.541 -1.92708,0 -3.5,1.573 -3.5,3.5 0,1.9271 1.57294,3.5 3.5,3.5 h 7 c 2.47937,0 4.5,-2.0207 4.5,-4.5 0,-2.4793 -2.02063,-4.5 -4.5,-4.5 z m 0,3 c 0.82251,0 1.5,0.6775 1.5,1.5 0,0.8225 -0.67749,1.5 -1.5,1.5 -0.82251,0 -1.5,-0.6775 -1.5,-1.5 0,-0.8225 0.67749,-1.5 1.5,-1.5 z m -7,1 c 0.82251,0 1.5,0.6775 1.5,1.5 0,0.8225 -0.67749,1.5 -1.5,1.5 -0.82251,0 -1.5,-0.6775 -1.5,-1.5 0,-0.8225 0.67749,-1.5 1.5,-1.5 z m 7,0 c -0.28208,0 -0.5,0.2179 -0.5,0.5 0,0.2821 0.21792,0.5 0.5,0.5 0.28208,0 0.5,-0.2179 0.5,-0.5 0,-0.2821 -0.21792,-0.5 -0.5,-0.5 z m -3.94922,0.998 c 8e-5,7e-4 -8e-5,0 0,0 H -381.5 a 0.50005006,0.50005006 0 0 0 0.0508,0 z m -3.05078,0 c -0.28208,0 -0.5,0.2179 -0.5,0.5 0,0.2821 0.21792,0.5 0.5,0.5 0.28208,0 0.5,-0.2179 0.5,-0.5 0,-0.2821 -0.21792,-0.5 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path20992-7"
+ transform="translate(42,-42)"
+ d="M -385.50781,1856.9922 A 0.50005,0.50005 0 0 0 -386,1857.5 v 1 1 a 0.50005,0.50005 0 0 0 1,0 v -0.5 h 1 v 1.5 c 3e-5,0.1326 0.0527,0.2597 0.14648,0.3535 l 1,1 c 0.0937,0.094 0.22092,0.1465 0.35352,0.1465 h 5 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -4 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 h -6 c -0.27613,0 -0.49997,0.2239 -0.5,0.5 v 0.5 h -1 v -0.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.5078 z m 11.99219,0.01 c -0.10819,0 -0.21237,0.042 -0.29688,0.1094 l -2.5,2 c -0.25044,0.2002 -0.25044,0.581 0,0.7812 l 2.5,2 c 0.32747,0.2621 0.81265,0.029 0.8125,-0.3906 v -4 c 1.1e-4,-0.2823 -0.23341,-0.5088 -0.51562,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 342.55078,494 a 0.50005,0.50005 0 0 1 0.33593,0.1641 l 2.64844,2.84179 h 1.00781 c 0.45995,0.6015 1.17678,1 1.97852,1 h -3.20312 a 0.50005,0.50005 0 0 1 -0.36719,-0.1582 l -2.79492,-2.99999 A 0.50005,0.50005 0 0 1 342.5,494 a 0.50005,0.50005 0 0 1 0.0508,0 z m 5.9707,4.00589 c 0.80174,0 1.51857,-0.3985 1.97852,-1 h 2.02148 a 0.50005,0.50005 0 0 1 0.35352,0.1465 l 3,3 a 0.50005,0.50005 0 1 1 -0.70704,0.707 l -2.85351,-2.8535 h -2.29297 v 3.832 c 0.96356,1.6489 2.8299,3.71521 5.58203,4.17391 A 0.50086299,0.50086299 0 1 1 355.43945,507 c -2.4267,-0.4044 -4.21553,-1.8644 -5.39844,-3.34761 a 0.50005,0.50005 0 0 1 -0.002,0 c -0.001,0 -0.003,0 -0.004,0 -1.00443,-0.9218 -2.17404,-1 -3.22851,-0.2383 -1.05449,0.76181 -1.78322,2.34671 -1.78321,4.09771 a 0.50005,0.50005 0 1 1 -1,0 c -10e-6,-2.0216 0.80114,-3.89961 2.19727,-4.90821 0.69807,-0.5043 1.49696,-0.7238 2.2832,-0.668 0.17359,0.012 0.34649,0.043 0.51758,0.082 a 0.50005,0.50005 0 0 1 0,-0.01 v -4 z m 0,-3.99999 c 0.8225,0 1.5,0.6775 1.5,1.49999 0,0.8225 -0.6775,1.5 -1.5,1.5 -0.8225,0 -1.5,-0.6775 -1.5,-1.5 0,-0.82249 0.6775,-1.49999 1.5,-1.49999 z"
+ id="path20567-5"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="scssssssssssssssssssssssssssssccccccccccccscssssssscccccccc"
+ inkscape:connector-curvature="0"
+ id="path15245-5-5"
+ d="m 498.5,10 c -2.1397,0 -3.80728,1.4725 -4.33008,3.2441 C 493.52022,12.4964 492.6594,12 491.5,12 c -1.9271,0 -3.5,1.5729 -3.5,3.5 0,1.927 1.5729,3.5 3.5,3.5 h 7 c 2.4794,0 4.5,-2.0207 4.5,-4.5 0,-2.4794 -2.0206,-4.5 -4.5,-4.5 z m 0,3 c 0.8225,0 1.5,0.6774 1.5,1.5 0,0.8225 -0.6775,1.5 -1.5,1.5 -0.8225,0 -1.5,-0.6775 -1.5,-1.5 0,-0.8226 0.6775,-1.5 1.5,-1.5 z m -7,1 c 0.8225,0 1.5,0.6774 1.5,1.5 0,0.8225 -0.6775,1.5 -1.5,1.5 -0.8225,0 -1.5,-0.6775 -1.5,-1.5 0,-0.8226 0.6775,-1.5 1.5,-1.5 z m 7,0 c -0.2821,0 -0.5,0.2179 -0.5,0.5 0,0.282 0.2179,0.5 0.5,0.5 0.2821,0 0.5,-0.218 0.5,-0.5 0,-0.2821 -0.2179,-0.5 -0.5,-0.5 z m -7,1 c -0.2821,0 -0.5,0.2179 -0.5,0.5 0,0.282 0.2179,0.5 0.5,0.5 0.2821,0 0.5,-0.218 0.5,-0.5 0,-0.2821 -0.2179,-0.5 -0.5,-0.5 z m 1,5 c -0.2761,0 -0.5,0.2239 -0.5,0.5 v 1 0.5 h -1 v -0.5 c 0.004,-0.2823 -0.22555,-0.5122 -0.50781,-0.5078 -0.27615,0 -0.49651,0.2316 -0.49219,0.5078 v 1 1 c 0.009,0.6573 0.9907,0.6573 1,0 V 23 h 1 v 0.5 1 c 0,0.1326 0.053,0.2597 0.14648,0.3535 l 1,1 C 493.24048,25.9475 493.3674,26 493.5,26 h 5 c 0.2761,0 0.5,-0.2239 0.5,-0.5 v -5 c 0,-0.2761 -0.2239,-0.5 -0.5,-0.5 z m 10.98438,1 c -0.0871,0 -0.17191,0.028 -0.2461,0.074 l -3.25,2 c -0.31714,0.1953 -0.31714,0.6563 0,0.8516 l 3.25,2 c 0.33298,0.2045 0.76131,-0.035 0.76172,-0.4258 v -4 c 1.1e-4,-0.2823 -0.23341,-0.5088 -0.51562,-0.5 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;enable-background:new" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.24999976;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 302.64518,431.00052 a 1.1251124,1.1233465 0 0 0 -0.7734,0.3412 l -1.5313,1.5269 a 1.1251124,1.1233465 0 1 0 1.5918,1.5874 l 1.5293,-1.5269 a 1.1251124,1.1233465 0 0 0 -0.8164,-1.9286 z m 5.0977,0 a 1.1251124,1.1233465 0 0 0 -0.7735,0.3393 l -6.6289,6.6185 a 1.125572,1.1238054 0 1 0 1.5918,1.5893 l 2.1289,-2.1256 c 0.2384,-1.1729 1.1734,-2.1044 2.3477,-2.344 l 2.1523,-2.1489 a 1.1251124,1.1233465 0 0 0 -0.8183,-1.9286 z m 5.0996,0 a 1.1251124,1.1233465 0 0 0 -0.7735,0.3393 l -3.916,3.9099 c 0.7144,0.3005 1.2901,0.8706 1.5996,1.5795 l 3.9063,-3.9001 a 1.1251124,1.1233465 0 0 0 -0.8164,-1.9286 z m 0,5.0916 a 1.1251124,1.1233465 0 0 0 -0.7735,0.3393 l -2.123,2.1197 c -0.2257,1.2122 -1.1902,2.1751 -2.4043,2.4005 l -2.1016,2.0983 a 1.1251124,1.1233465 0 1 0 1.5918,1.5873 l 6.627,-6.6165 a 1.1251124,1.1233465 0 0 0 -0.8164,-1.9286 z m -5.8418,0.9204 c -0.5601,0 -0.9917,0.4296 -0.9981,0.9867 0.01,0.5524 0.4434,0.9887 0.9981,0.9887 0.5547,0 0.9926,-0.4363 0.998,-0.9887 -0.01,-0.5571 -0.438,-0.9867 -0.998,-0.9867 z m -2.7656,2.149 -3.8946,3.8884 a 1.1251124,1.1233465 0 1 0 1.5918,1.5873 l 3.8848,-3.8786 c -0.7095,-0.3088 -1.2808,-0.8846 -1.582,-1.5971 z m 8.6074,2.0202 a 1.1251124,1.1233465 0 0 0 -0.7735,0.3413 l -1.5293,1.5269 a 1.1251124,1.1233465 0 1 0 1.5899,1.5873 l 1.5293,-1.5269 a 1.1251124,1.1233465 0 0 0 -0.8164,-1.9286 z"
+ id="path21492-2"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="translate(-329.98994,63.99547)"
+ style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
+ id="g21552">
+ <path
+ id="path8055"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 823.98994,430.00453 v 2 h 5 v 3.7086 l 1.8538,-1.85485 c 0.0937,-0.0939 0.14631,-0.22111 0.1462,-0.35375 0.0114,-0.97402 0,-3.0415 0,-3.5 z m -3,3 v 4 h 7 l -4e-5,-4 z m 11.48438,1.125 c -0.12717,0.004 -0.24801,0.0564 -0.3379,0.14648 l -3.72851,3.72852 h -8.91211 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 8.49414 v -4.5 a 0.50005,0.50005 0 0 1 0.49219,-0.50586 0.50005,0.50005 0 0 1 0.50781,0.50586 v 4.33203 l 3.85352,-3.85351 c 0.0938,-0.0938 0.14645,-0.22092 0.14648,-0.35352 v -5 c 1.1e-4,-0.28235 -0.23342,-0.50879 -0.51562,-0.5 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g20181-9"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ transform="translate(-288.99602,63.999021)">
+ <g
+ id="g5276"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 803.49219,433.99219 A 0.50005,0.50005 0 0 0 803,434.5 v 4 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 4.99804,4.00586 a 0.50005,0.50005 0 0 0 -0.49414,0.50586 v 5 a 0.50005,0.50005 0 1 0 1,0 v -5 a 0.50005,0.50005 0 0 0 -0.50586,-0.50586 z"
+ id="path20179-2"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path20173-5"
+ transform="translate(288.99602,-63.999021)"
+ d="m 514.5,497.99805 a 0.50004997,0.50004997 0 0 0 -0.35352,0.14453 l -4,4 A 0.50004997,0.50004997 0 0 0 510,502.49805 v 5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 l 9,0.006 a 0.50004997,0.50004997 0 0 0 0.35547,-0.14649 l 4,-4.0039 A 0.50004997,0.50004997 0 0 0 524,503.49805 v -5 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z m 0.20898,1 h 7.5879 l -3.00391,3.00586 L 511.70312,502 Z M 523,499.70703 v 3.58399 l -3.70703,3.71289 L 511,507 v -4 l 8.5,0.004 a 0.50004997,0.50004997 0 0 0 0.35547,-0.14844 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ inkscape:connector-curvature="0" />
</g>
- <g id="g24260-8" style="display:inline;fill:#ffffff;enable-background:new" transform="translate(252.00711,707.99288)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.55;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 61.490943,-569.99488 -3.5,0.008 0.0039,1 2.998047,-0.006 v 5 l -3.001953,0.006 0.0039,1 3.5,-0.008 c 0.275368,-0.001 0.498022,-0.22463 0.498047,-0.5 v -6 c -2.6e-5,-0.2769 -0.22506,-0.50105 -0.501953,-0.5 z m -12.498053,9.002 v 3.49219 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 6 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -3.49219 h -1 v 2.99219 h -5 v -2.99219 z" id="path26507-9" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 48.49289,-570.99288 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 8 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 8 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -8 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z" id="path26509-9" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 48.5,183 c -0.27613,4e-5 -0.49997,0.22388 -0.5,0.5 v 9 c 3e-5,0.27614 0.22387,0.49997 0.5,0.5 h 9 c 0.27613,-3e-5 0.49997,-0.22386 0.5,-0.5 v -9 c -3e-5,-0.27612 -0.22387,-0.49996 -0.5,-0.5 z"
+ id="path5234"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 52.49219,179.00781 c -0.1326,4e-5 -0.25976,0.0527 -0.35352,0.1465 l -1.99219,1.99217 C 50.02584,181.26245 50,181.375 50,181.5 v 0.5 h 1 l 0.003,-0.296 1.69618,-1.69619 h 8.29297 v 8.29298 L 59.29548,189.99745 59,190 v 1 h 0.5 c 0.11717,0 0.23766,-0.0261 0.3457,-0.13867 l 2,-2 c 0.0938,-0.0938 0.14646,-0.22091 0.14649,-0.35352 v -9 c -3e-5,-0.27612 -0.22387,-0.49996 -0.5,-0.5 z"
+ id="path5236"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccscccccccccscccccc" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="translate(0.00711,-0.00712)"
+ id="g26453-0">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 10.486328,179.01367 c -0.1326,3e-5 -0.259761,0.0527 -0.353516,0.14649 l -1.9941401,1.99414 c -0.4908663,0.47125 0.2357781,1.1979 0.7070312,0.70703 l 1.8476559,-1.84766 h 8.292969 v 8.29297 l -2.707031,2.70703 H 7.9882812 l 0.00461,-3.00655 -1,-0.002 -0.00656,3.5085 c 2.76e-5,0.27613 0.2238691,0.49997 0.5,0.5 h 8.9999998 c 0.132599,-2e-5 0.259759,-0.0527 0.353516,-0.14648 l 3,-3 c 0.09377,-0.0938 0.14646,-0.22092 0.146484,-0.35352 v -9 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ id="path26449-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 6.4921875,183.00781 c -0.2761309,3e-5 -0.4999724,0.22387 -0.5,0.5 v 3 c 2.76e-5,0.27613 0.2238691,0.49997 0.5,0.5 h 3 c 0.2761309,-3e-5 0.4999724,-0.22387 0.5,-0.5 v -3 c -2.76e-5,-0.27613 -0.2238691,-0.49997 -0.5,-0.5 z"
+ id="path26451-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g26527-9"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ transform="matrix(0,-1,-1,0,220.01421,219.98576)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 27.486328,183.01367 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 2 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 9 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -2 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ id="path26523-4"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 31.478516,179.02148 c -0.1326,3e-5 -0.259761,0.0527 -0.353516,0.14649 l -1.992188,1.99219 c -0.490839,0.47125 0.235779,1.19787 0.707032,0.70703 l 1.845703,-1.84571 h 8.292969 v 8.29297 l -2.707032,2.70703 h -8.292968 l 0.0072,-4.00727 -1,-0.002 -0.0072,4.50727 c -0.0011,0.27689 0.223106,0.50192 0.5,0.50195 h 9 c 0.132599,-2e-5 0.259759,-0.0527 0.353515,-0.14648 l 3,-3 c 0.09377,-0.0938 0.14646,-0.22092 0.146485,-0.35352 v -9 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ id="path26525-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccc" />
+ </g>
+ <g
+ transform="translate(252.00711,707.99288)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g24277-2">
+ <g
+ transform="translate(-252.00673,-707.99218)"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g26501-5"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="path26499-8"
+ d="m 258.49962,136.9993 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
- <g id="g24272-6" style="display:inline;fill:#ffffff;enable-background:new" transform="translate(251.96252,708.00986)">
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new" id="g26513-4" transform="translate(-189.96252,-708.00986)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 259.5,138 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 11.00195 a 0.50005,0.50005 0 0 0 0.5,0.5 l 4,-0.002 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -11 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 3 v 10 l -3,0.002 z" id="path24266-1" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 77.537109,-571.00977 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 13 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 5 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -13 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z" id="path26515-7" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
+ <path
+ inkscape:connector-curvature="0"
+ id="path26503-3"
+ d="m 10.955781,-569.99288 v 1 h 2.037109 v 5 H 7.9928902 v -1.99219 h -1 v 8.49219 a 0.50005,0.50005 0 0 0 0.5,0.5 H 13.49289 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5.5 h 5.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -6 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 3.037109,1 h 5 v 5 h -5 z m -5.9999998,6 H 12.99289 v 5 H 7.9928902 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.55;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g26539-4"
+ transform="matrix(0,1,1,0,850.0517,109.94829)">
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="path26497-4"
+ d="m 27.544922,-565.04492 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 2 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 8 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -2 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path26505-7"
+ d="m 28.544922,-570.04492 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 3.5 h 1 v -3 h 5 v 3 h 1 v -3 h 5 v 5 h -3 v 1 h 3.5 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -6 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z m -0.5,9 0.0049,3.49327 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 6 c 0.275371,-3e-5 0.498899,-0.22268 0.5,-0.49805 l 0.0019,-3.5 -1,-0.002 v 3 h -5 l -0.0068,-2.99132 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.55;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ transform="translate(252.00711,707.99288)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g24260-8">
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path26507-9"
+ d="m 61.490943,-569.99488 -3.5,0.008 0.0039,1 2.998047,-0.006 v 5 l -3.001953,0.006 0.0039,1 3.5,-0.008 c 0.275368,-0.001 0.498022,-0.22463 0.498047,-0.5 v -6 c -2.6e-5,-0.2769 -0.22506,-0.50105 -0.501953,-0.5 z m -12.498053,9.002 v 3.49219 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 6 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -3.49219 h -1 v 2.99219 h -5 v -2.99219 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.55;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="path26509-9"
+ d="m 48.49289,-570.99288 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 8 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 8 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -8 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ transform="translate(251.96252,708.00986)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g24272-6">
+ <g
+ transform="translate(-189.96252,-708.00986)"
+ id="g26513-4"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ inkscape:connector-curvature="0"
+ id="path24266-1"
+ d="m 259.5,138 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 11.00195 a 0.50005,0.50005 0 0 0 0.5,0.5 l 4,-0.002 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -11 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 3 v 10 l -3,0.002 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="path26515-7"
+ d="m 77.537109,-571.00977 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 13 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 5 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -13 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12992"
+ transform="translate(2.6297176e-6,-20.999997)"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ id="path12908"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 183.8125,200.01562 c 2.21359,0.18235 3.97803,1.94071 4.16992,4.1543 0.19189,2.2136 -1.24344,4.25155 -3.39258,4.8125 a 0.5007349,0.5007349 0 1 1 -0.2539,-0.96875 c 1.68376,-0.43948 2.80079,-2.02289 2.65039,-3.75781 -0.1504,-1.73492 -1.52164,-3.10129 -3.25586,-3.24414 -1.73423,-0.14285 -3.31219,0.98104 -3.74414,2.66797 a 0.50005,0.50005 0 1 1 -0.96875,-0.24805 c 0.55114,-2.15241 2.58133,-3.59836 4.79492,-3.41602 z M 178.5,205 a 0.50005,0.50005 0 1 1 0,1 c -1.41705,0 -2.69209,0.85096 -3.23438,2.16016 -0.54228,1.30919 -0.24224,2.81243 0.75977,3.81445 1.00201,1.00201 2.50527,1.30205 3.81445,0.75977 C 181.14903,212.19209 182,210.91706 182,209.5 a 0.50005,0.50005 0 1 1 1,0 c 0,1.81865 -1.09714,3.46223 -2.77734,4.1582 -1.68021,0.69597 -3.61833,0.30942 -4.9043,-0.97656 -1.28598,-1.28598 -1.67253,-3.22408 -0.97656,-4.9043 C 175.03776,206.09713 176.68136,205 178.5,205 Z"
+ inkscape:connector-curvature="0" />
+ <path
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="M 182.99634,206.50183 A 1.4981741,1.4981725 0 0 1 181.49817,208 a 1.4981741,1.4981725 0 0 1 -1.49818,-1.49817 1.4981741,1.4981725 0 0 1 1.49818,-1.49817 1.4981741,1.4981725 0 0 1 1.49817,1.49817 z"
+ id="circle12958"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g21469-5"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(498,-1438)">
+ <path
+ inkscape:connector-curvature="0"
+ id="path21106-9"
+ d="m -356.5,1850 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.2179 0.5,0.5 0,0.2821 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.2179 -0.5,-0.5 0,-0.2821 0.21794,-0.5 0.5,-0.5 z m -7,1 a 0.5,0.5 0 0 0 -0.5,0.5 0.5,0.5 0 0 0 0.5,0.5 0.5,0.5 0 0 0 0.5,-0.5 0.5,0.5 0 0 0 -0.5,-0.5 z"
+ style="display:inline;opacity:0.7;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.70000005;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" />
+ <path
+ sodipodi:nodetypes="csssscccsscccsccccccscccccccccccccccccccccsccsccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ d="m -357.5,1856.0041 h 0.49805 c 3.5943,0 5.00195,-2.5001 5.00195,-4.5001 v 0 c 0,-2.4794 -2.02064,-4.5 -4.5,-4.5 -1.88915,0 -3.45662,1.2594 -4.10547,3 h -0.51758 c -0.64602,-0.6132 -1.47755,-0.9979 -2.375,-1 h -0.002 c -1.92707,0 -3.5,1.5729 -3.5,3.5 0,1.9271 1.57293,3.5 3.5,3.5 z m -6,-1.0041 c -1.38663,0 -2.5,-1.1134 -2.5,-2.5 0,-1.386 1.11233,-2.4989 2.49805,-2.5 0.71036,0 1.38608,0.3048 1.85937,0.834 0.0951,0.1059 0.23074,0.1663 0.37305,0.166 h 0.90234 c 0.22809,10e-5 0.42734,-0.1542 0.48438,-0.375 0.39914,-1.5459 1.78609,-2.6224 3.38281,-2.625 1.93892,0 3.5,1.5611 3.5,3.5 0,1.9279 -1.54523,3.4765 -3.46875,3.4941 -0.0392,0 -0.0785,-6e-4 -0.11719,0.01 H -357.5 Z m -1.00781,1.9922 c -0.27614,0 -0.4965,0.2317 -0.49219,0.5078 v 1 1 c 0.009,0.6573 0.9907,0.6573 1,0 v -0.5 h 1 v 1.5 c 3e-5,0.1326 0.0527,0.2597 0.14648,0.3535 l 1,1 c 0.0937,0.094 0.22092,0.1465 0.35352,0.1465 h 5 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -1.5039 h 0.33594 l 2.61914,1.9043 c 0.0852,0.064 0.18852,0.099 0.29492,0.1 h 0.25 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -4 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 h -0.25 c -0.106,-10e-5 -0.20927,0.034 -0.29492,0.096 L -355.66211,1859 H -356 v -2 h -1 v 4 h -4.29297 L -362,1860.293 V 1857 h -1 v 1 h -1 v -0.5 c 0.004,-0.2823 -0.22555,-0.5122 -0.50781,-0.5078 z M -353,1858.3008 v 2.3984 l -1.65039,-1.1992 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="path21108-3" />
+ <path
+ id="rect24266"
+ d="m -362,1857 h 5 v 1 h -5 z"
+ style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(624,-1354)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g24304">
+ <path
+ style="display:inline;opacity:0.7;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.70000005;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ d="m -356.5,1850 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.2179 0.5,0.5 0,0.2821 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.2179 -0.5,-0.5 0,-0.2821 0.21794,-0.5 0.5,-0.5 z m -7,1 a 0.5,0.5 0 0 0 -0.5,0.5 0.5,0.5 0 0 0 0.5,0.5 0.5,0.5 0 0 0 0.5,-0.5 0.5,0.5 0 0 0 -0.5,-0.5 z"
+ id="path24284"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24300"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -357.5,1856.0041 h 0.49805 c 3.5943,0 5.00195,-2.5001 5.00195,-4.5001 v 0 c 0,-2.4794 -2.02064,-4.5 -4.5,-4.5 -1.88915,0 -3.45662,1.2594 -4.10547,3 h -0.51758 c -0.64602,-0.6132 -1.47755,-0.9979 -2.375,-1 h -0.002 c -1.92707,0 -3.5,1.5729 -3.5,3.5 0,1.9271 1.57293,3.5 3.5,3.5 z m -6,-1.0041 c -1.38663,0 -2.5,-1.1134 -2.5,-2.5 0,-1.386 1.11233,-2.4989 2.49805,-2.5 0.71036,0 1.38608,0.3048 1.85937,0.834 0.0951,0.1059 0.23074,0.1663 0.37305,0.166 h 0.90234 c 0.22809,10e-5 0.42734,-0.1542 0.48438,-0.375 0.39914,-1.5459 1.78609,-2.6224 3.38281,-2.625 1.93892,0 3.5,1.5611 3.5,3.5 0,1.9279 -1.54523,3.4765 -3.46875,3.4941 -0.0392,0 -0.0785,-6e-4 -0.11719,0.01 H -357.5 Z m -1.00781,1.9922 c -0.27614,0 -0.4965,0.2317 -0.49219,0.5078 v 1 1 c 0.009,0.6573 0.9907,0.6573 1,0 v -0.5 h 1 v 1.5 c 3e-5,0.1326 0.0527,0.2597 0.14648,0.3535 l 1,1 c 0.0937,0.094 0.22092,0.1465 0.35352,0.1465 h 5 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -1.5039 h 0.33594 l 2.61914,1.9043 c 0.0852,0.064 0.18852,0.099 0.29492,0.1 h 0.25 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -4 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 h -0.25 c -0.106,-10e-5 -0.20927,0.034 -0.29492,0.096 L -355.66211,1859 H -356 v -2 h -1 v 4 h -4.29297 L -362,1860.293 V 1857 h -1 v 1 h -1 v -0.5 c 0.004,-0.2823 -0.22555,-0.5122 -0.50781,-0.5078 z M -353,1858.3008 v 2.3984 l -1.65039,-1.1992 z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csssscccsscccsccccccscccccccccccccccccccccsccsccccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m -362,1857 h 5 v 1 h -5 z"
+ id="path24302" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ id="path12791-5"
+ d="m 385,621 a 1.0001,1.0001 0 1 0 0,2 h 12 a 1.0001,1.0001 0 1 0 0,-2 z m 0,5 a 1.0001,1.0001 0 1 0 0,2 h 12 a 1.0001,1.0001 0 1 0 0,-2 z m 0,5 a 1.0001,1.0001 0 1 0 0,2 h 12 a 1.0001,1.0001 0 1 0 0,-2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <g
+ transform="translate(1.7499929e-7,23.000001)"
+ id="g21364"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <g
+ id="g5447"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 430.49219,134.99219 a 0.50005,0.50005 0 0 0 -0.38867,0.19531 0.50005,0.50005 0 0 0 -0.004,0.006 l -1.95313,1.95312 a 0.50005,0.50005 0 1 0 0.70703,0.70704 L 430,136.70703 V 140.5 a 0.50005,0.50005 0 1 0 1,0 v -3.79297 l 1.14648,1.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.95704,-1.95703 a 0.50005,0.50005 0 0 0 -0.40429,-0.19726 z m 7.00195,7.00195 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 438.29297,144 H 434.5 a 0.50005,0.50005 0 1 0 0,1 h 3.79297 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.95703,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.006,-0.004 l -1.95313,-1.95313 a 0.50005,0.50005 0 0 0 -0.35937,-0.15234 z m -11.00195,2.99805 A 0.50005,0.50005 0 0 0 426,145.5 v 2.93945 A 0.50005,0.50005 0 0 0 426.56055,149 H 429.5 a 0.50005,0.50005 0 1 0 0,-1 h -1.79297 l 1.14649,-1.14648 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 L 427,147.29297 V 145.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path21358"
+ inkscape:connector-curvature="0" />
+ <path
+ id="circle21362"
+ d="M 432.99635,144 A 1.99635,1.99635 0 0 1 431,145.99635 1.99635,1.99635 0 0 1 429.00365,144 1.99635,1.99635 0 0 1 431,142.00365 1.99635,1.99635 0 0 1 432.99635,144 Z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g12992" transform="translate(2.6297176e-6,-20.999997)" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path id="path12908" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 183.8125,200.01562 c 2.21359,0.18235 3.97803,1.94071 4.16992,4.1543 0.19189,2.2136 -1.24344,4.25155 -3.39258,4.8125 a 0.5007349,0.5007349 0 1 1 -0.2539,-0.96875 c 1.68376,-0.43948 2.80079,-2.02289 2.65039,-3.75781 -0.1504,-1.73492 -1.52164,-3.10129 -3.25586,-3.24414 -1.73423,-0.14285 -3.31219,0.98104 -3.74414,2.66797 a 0.50005,0.50005 0 1 1 -0.96875,-0.24805 c 0.55114,-2.15241 2.58133,-3.59836 4.79492,-3.41602 z M 178.5,205 a 0.50005,0.50005 0 1 1 0,1 c -1.41705,0 -2.69209,0.85096 -3.23438,2.16016 -0.54228,1.30919 -0.24224,2.81243 0.75977,3.81445 1.00201,1.00201 2.50527,1.30205 3.81445,0.75977 C 181.14903,212.19209 182,210.91706 182,209.5 a 0.50005,0.50005 0 1 1 1,0 c 0,1.81865 -1.09714,3.46223 -2.77734,4.1582 -1.68021,0.69597 -3.61833,0.30942 -4.9043,-0.97656 -1.28598,-1.28598 -1.67253,-3.22408 -0.97656,-4.9043 C 175.03776,206.09713 176.68136,205 178.5,205 Z" inkscape:connector-curvature="0"/>
- <path style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" d="M 182.99634,206.50183 A 1.4981741,1.4981725 0 0 1 181.49817,208 a 1.4981741,1.4981725 0 0 1 -1.49818,-1.49817 1.4981741,1.4981725 0 0 1 1.49818,-1.49817 1.4981741,1.4981725 0 0 1 1.49817,1.49817 z" id="circle12958" inkscape:connector-curvature="0"/>
- </g>
- <g id="g21469-5" style="display:inline;fill:#ffffff;enable-background:new" transform="translate(498,-1438)">
- <path inkscape:connector-curvature="0" id="path21106-9" d="m -356.5,1850 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.2179 0.5,0.5 0,0.2821 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.2179 -0.5,-0.5 0,-0.2821 0.21794,-0.5 0.5,-0.5 z m -7,1 a 0.5,0.5 0 0 0 -0.5,0.5 0.5,0.5 0 0 0 0.5,0.5 0.5,0.5 0 0 0 0.5,-0.5 0.5,0.5 0 0 0 -0.5,-0.5 z" style="display:inline;opacity:0.7;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.70000005;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"/>
- <path sodipodi:nodetypes="csssscccsscccsccccccscccccccccccccccccccccsccsccccccccccccccccccc" inkscape:connector-curvature="0" d="m -357.5,1856.0041 h 0.49805 c 3.5943,0 5.00195,-2.5001 5.00195,-4.5001 v 0 c 0,-2.4794 -2.02064,-4.5 -4.5,-4.5 -1.88915,0 -3.45662,1.2594 -4.10547,3 h -0.51758 c -0.64602,-0.6132 -1.47755,-0.9979 -2.375,-1 h -0.002 c -1.92707,0 -3.5,1.5729 -3.5,3.5 0,1.9271 1.57293,3.5 3.5,3.5 z m -6,-1.0041 c -1.38663,0 -2.5,-1.1134 -2.5,-2.5 0,-1.386 1.11233,-2.4989 2.49805,-2.5 0.71036,0 1.38608,0.3048 1.85937,0.834 0.0951,0.1059 0.23074,0.1663 0.37305,0.166 h 0.90234 c 0.22809,10e-5 0.42734,-0.1542 0.48438,-0.375 0.39914,-1.5459 1.78609,-2.6224 3.38281,-2.625 1.93892,0 3.5,1.5611 3.5,3.5 0,1.9279 -1.54523,3.4765 -3.46875,3.4941 -0.0392,0 -0.0785,-6e-4 -0.11719,0.01 H -357.5 Z m -1.00781,1.9922 c -0.27614,0 -0.4965,0.2317 -0.49219,0.5078 v 1 1 c 0.009,0.6573 0.9907,0.6573 1,0 v -0.5 h 1 v 1.5 c 3e-5,0.1326 0.0527,0.2597 0.14648,0.3535 l 1,1 c 0.0937,0.094 0.22092,0.1465 0.35352,0.1465 h 5 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -1.5039 h 0.33594 l 2.61914,1.9043 c 0.0852,0.064 0.18852,0.099 0.29492,0.1 h 0.25 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -4 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 h -0.25 c -0.106,-10e-5 -0.20927,0.034 -0.29492,0.096 L -355.66211,1859 H -356 v -2 h -1 v 4 h -4.29297 L -362,1860.293 V 1857 h -1 v 1 h -1 v -0.5 c 0.004,-0.2823 -0.22555,-0.5122 -0.50781,-0.5078 z M -353,1858.3008 v 2.3984 l -1.65039,-1.1992 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" id="path21108-3"/>
- <path id="rect24266" d="m -362,1857 h 5 v 1 h -5 z" style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g24264-7"
+ transform="translate(-910,-1146)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1028,1556 c -3.2833,0 -6,2.4414 -6,5.5 0,1.7056 0.9046,3.146 2.1523,4.3594 l 0.9942,0.9941 a 0.50004997,0.50004997 0 0 0 0.3027,0.1485 0.50004997,0.50004997 0 0 0 0.051,0.998 h 5 a 0.50004997,0.50004997 0 0 0 0.045,-0.998 0.50004997,0.50004997 0 0 0 0.3086,-0.1485 l 0.9981,-0.998 v 0 c 1.2122,-1.1985 2.1465,-2.6518 2.1465,-4.3535 0,-3.0586 -2.7167,-5.5 -6,-5.5 z m 0,1 c 2.7919,0 5,2.0358 5,4.5 0,1.3342 -0.7428,2.5488 -1.8516,3.6445 l -1,1 a 0.50004997,0.50004997 0 0 0 0.2793,0.8535 h -4.8594 a 0.50004997,0.50004997 0 0 0 0.2871,-0.8535 l -1,-1 a 0.50004997,0.50004997 0 0 0 -0.01,-0.01 c -1.1397,-1.1082 -1.8477,-2.2864 -1.8477,-3.6406 0,-2.4642 2.2081,-4.5 5,-4.5 z m -2.5,12 a 0.50004997,0.50004997 0 1 0 0,1 h 1.5 v 0.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 1 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -0.5 h 1.5 a 0.50004997,0.50004997 0 1 0 0,-1 z"
+ id="path24260-0"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1025.4902,1561.0059 a 0.50005,0.50005 0 0 0 -0.3437,0.8476 l 0.8535,0.8535 v 1.543 a 0.50005,0.50005 0 1 0 1,0 V 1563 h 2 v 1.25 a 0.50005,0.50005 0 1 0 1,0 v -1.543 l 0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.707,-0.707 L 1029.293,1562 h -2.586 l -0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.3633,-0.1406 z"
+ id="path24262-3"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-847,-1062)"
+ id="g24813"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ id="path24809"
+ d="m 1028,1556 c -3.2833,0 -6,2.4414 -6,5.5 0,1.7056 0.9046,3.146 2.1523,4.3594 l 0.9942,0.9941 a 0.50004997,0.50004997 0 0 0 0.3027,0.1485 0.50004997,0.50004997 0 0 0 0.051,0.998 h 5 a 0.50004997,0.50004997 0 0 0 0.045,-0.998 0.50004997,0.50004997 0 0 0 0.3086,-0.1485 l 0.9981,-0.998 v 0 c 1.2122,-1.1985 2.1465,-2.6518 2.1465,-4.3535 0,-3.0586 -2.7167,-5.5 -6,-5.5 z m 0,1 c 2.7919,0 5,2.0358 5,4.5 0,1.3342 -0.7428,2.5488 -1.8516,3.6445 l -1,1 a 0.50004997,0.50004997 0 0 0 0.2793,0.8535 h -4.8594 a 0.50004997,0.50004997 0 0 0 0.2871,-0.8535 l -1,-1 a 0.50004997,0.50004997 0 0 0 -0.01,-0.01 c -1.1397,-1.1082 -1.8477,-2.2864 -1.8477,-3.6406 0,-2.4642 2.2081,-4.5 5,-4.5 z m -2.5,12 a 0.50004997,0.50004997 0 1 0 0,1 h 1.5 v 0.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 1 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -0.5 h 1.5 a 0.50004997,0.50004997 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path24811"
+ d="m 1025.4902,1561.0059 a 0.50005,0.50005 0 0 0 -0.3437,0.8476 l 0.8535,0.8535 v 1.543 a 0.50005,0.50005 0 1 0 1,0 V 1563 h 2 v 1.25 a 0.50005,0.50005 0 1 0 1,0 v -1.543 l 0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.707,-0.707 L 1029.293,1562 h -2.586 l -0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.3633,-0.1406 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g24819"
+ transform="translate(-1015,-999)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1028,1556 c -3.2833,0 -6,2.4414 -6,5.5 0,1.7056 0.9046,3.146 2.1523,4.3594 l 0.9942,0.9941 a 0.50004997,0.50004997 0 0 0 0.3027,0.1485 0.50004997,0.50004997 0 0 0 0.051,0.998 h 5 a 0.50004997,0.50004997 0 0 0 0.045,-0.998 0.50004997,0.50004997 0 0 0 0.3086,-0.1485 l 0.9981,-0.998 v 0 c 1.2122,-1.1985 2.1465,-2.6518 2.1465,-4.3535 0,-3.0586 -2.7167,-5.5 -6,-5.5 z m 0,1 c 2.7919,0 5,2.0358 5,4.5 0,1.3342 -0.7428,2.5488 -1.8516,3.6445 l -1,1 a 0.50004997,0.50004997 0 0 0 0.2793,0.8535 h -4.8594 a 0.50004997,0.50004997 0 0 0 0.2871,-0.8535 l -1,-1 a 0.50004997,0.50004997 0 0 0 -0.01,-0.01 c -1.1397,-1.1082 -1.8477,-2.2864 -1.8477,-3.6406 0,-2.4642 2.2081,-4.5 5,-4.5 z m -2.5,12 a 0.50004997,0.50004997 0 1 0 0,1 h 1.5 v 0.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 1 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -0.5 h 1.5 a 0.50004997,0.50004997 0 1 0 0,-1 z"
+ id="path24815"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1025.4902,1561.0059 a 0.50005,0.50005 0 0 0 -0.3437,0.8476 l 0.8535,0.8535 v 1.543 a 0.50005,0.50005 0 1 0 1,0 V 1563 h 2 v 1.25 a 0.50005,0.50005 0 1 0 1,0 v -1.543 l 0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.707,-0.707 L 1029.293,1562 h -2.586 l -0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.3633,-0.1406 z"
+ id="path24817"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g25431"
+ transform="translate(-21)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 153.5,119 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 9 v 9 h -9 z"
+ id="rect25412"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 157,121 v 2 h 1 v -2 z m 0,3 v 1.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5 v -1 h -1 v -1 z m 3,1 v 1 h 2 v -1 z"
+ id="rect25414"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 157.5,116 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h 1 v -1 h 8 v 8 h -1 v 1 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path25426"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ id="g13935-4"
+ transform="translate(83.999996,42)">
+ <path
+ id="path13929-36"
+ d="m 36,74 c -2.455669,0 -4.49388,1.771475 -4.916016,4.105469 0.482305,-0.09011 0.975221,-0.129499 1.470704,-0.07422 0.662841,0.07415 0.551512,1.068296 -0.111329,0.994141 -0.485685,-0.05419 -0.971969,-0.01789 -1.4375,0.101562 0.06678,2.656434 2.202258,4.79532 4.857422,4.867188 0.121572,-0.473413 0.166164,-0.965209 0.109375,-1.455079 -0.03822,-0.293198 0.18493,-0.555356 0.480469,-0.564453 0.262666,-0.0085 0.487095,0.187762 0.513672,0.449219 0.05787,0.499184 0.03624,1.001242 -0.05469,1.490234 C 39.23754,83.484981 41,81.449595 41,79 41,76.23858 38.761426,74 36,74 Z m -1.568358,4.830076 c 0.100656,9.56e-4 0.198679,0.03227 0.28125,0.08984 0.540828,0.363139 1.00483,0.82779 1.367188,1.369141 0.405708,0.559881 -0.466114,1.144515 -0.830078,0.556641 -0.289893,-0.43309 -0.661079,-0.805188 -1.09375,-1.095703 -0.420141,-0.271725 -0.224948,-0.923754 0.27539,-0.919922 z"
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="scccccccccssccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 29.484375,78.757812 a 0.50005,0.50005 0 0 0 -0.267578,0.08789 c -1.670208,1.118756 -2.507905,3.13395 -2.125,5.107422 0.382905,1.973472 1.913458,3.526488 3.880859,3.939453 1.967402,0.412965 3.994569,-0.393928 5.138672,-2.046875 a 0.50005,0.50005 0 1 0 -0.822266,-0.568359 c -0.916718,1.324431 -2.534938,1.967608 -4.111328,1.636718 -1.576389,-0.330889 -2.798664,-1.57109 -3.105468,-3.152343 -0.306805,-1.581254 0.36291,-3.18953 1.701172,-4.085938 a 0.50005,0.50005 0 0 0 -0.289063,-0.917968 z"
+ id="path13933-5"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g25821">
+ <g
+ id="g24262-4"
+ transform="translate(-188.99644,-1801.0029)"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="rect24246-3"
+ transform="translate(188.99644,1801.0029)"
+ d="m 489.00391,329.99805 v 2 h 1 v -1 h 1 v -1 z m 0,4 v 2 h 1 v -2 z m 0,4 v 2 h 2 v -1 h -1 v -1 z m 9,0 v 1 h -1 v 1 h 2 v -2 z m -5,1 v 1 h 2 v -1 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 493.49609,325.98633 c -0.27689,3e-5 -0.50105,0.22506 -0.5,0.50195 l 0.008,4.00586 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4.5 v 4.50195 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path24264-0"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccc" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 472.49609,325.98633 c -0.27689,3e-5 -0.50105,0.22506 -0.5,0.50195 l 0.006,3.50586 -3.49804,0.002 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 9 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 9 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3.5 h 3.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path24338-8"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccc" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g25828">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 515.49805,329.98633 c -0.27766,-0.001 -0.50302,0.22429 -0.50196,0.50195 l 0.008,5.00586 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4.99805 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path24344-9"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ <g
+ id="g24392-5"
+ transform="translate(-166.99644,-1801.0029)"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccaccc"
+ inkscape:connector-curvature="0"
+ id="rect24376-2"
+ transform="translate(166.99644,1801.0029)"
+ d="M 515.00391,325.99609 V 326 H 515 v 2 h 1 v -1.00391 h 1.00391 v -1 z m 4,0 v 1 h 2 v -1 z M 523,326 v 1 h 1 v 1 h 1.00391 v -2.00391 z m 1.00391,3.99609 v 2 h 1 v -2 z m -13,0.002 v 2 h 1 v -1 h 1 v -1 z m 13,3.99804 v 1 h -1 v 1 h 2 v -2 z m -13,0.002 v 2 h 1 v -2 z m 0,4 v 2 h 2 v -1 h -1 v -1 z m 9,0 v 1 h -1 v 1 h 2 v -2 z m -5,1 v 1 h 2 v -1 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
+ </g>
</g>
- <g transform="translate(624,-1354)" style="display:inline;fill:#ffffff;enable-background:new" id="g24304">
- <path style="display:inline;opacity:0.7;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.70000005;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" d="m -356.5,1850 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.2179 0.5,0.5 0,0.2821 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.2179 -0.5,-0.5 0,-0.2821 0.21794,-0.5 0.5,-0.5 z m -7,1 a 0.5,0.5 0 0 0 -0.5,0.5 0.5,0.5 0 0 0 0.5,0.5 0.5,0.5 0 0 0 0.5,-0.5 0.5,0.5 0 0 0 -0.5,-0.5 z" id="path24284" inkscape:connector-curvature="0"/>
- <path id="path24300" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m -357.5,1856.0041 h 0.49805 c 3.5943,0 5.00195,-2.5001 5.00195,-4.5001 v 0 c 0,-2.4794 -2.02064,-4.5 -4.5,-4.5 -1.88915,0 -3.45662,1.2594 -4.10547,3 h -0.51758 c -0.64602,-0.6132 -1.47755,-0.9979 -2.375,-1 h -0.002 c -1.92707,0 -3.5,1.5729 -3.5,3.5 0,1.9271 1.57293,3.5 3.5,3.5 z m -6,-1.0041 c -1.38663,0 -2.5,-1.1134 -2.5,-2.5 0,-1.386 1.11233,-2.4989 2.49805,-2.5 0.71036,0 1.38608,0.3048 1.85937,0.834 0.0951,0.1059 0.23074,0.1663 0.37305,0.166 h 0.90234 c 0.22809,10e-5 0.42734,-0.1542 0.48438,-0.375 0.39914,-1.5459 1.78609,-2.6224 3.38281,-2.625 1.93892,0 3.5,1.5611 3.5,3.5 0,1.9279 -1.54523,3.4765 -3.46875,3.4941 -0.0392,0 -0.0785,-6e-4 -0.11719,0.01 H -357.5 Z m -1.00781,1.9922 c -0.27614,0 -0.4965,0.2317 -0.49219,0.5078 v 1 1 c 0.009,0.6573 0.9907,0.6573 1,0 v -0.5 h 1 v 1.5 c 3e-5,0.1326 0.0527,0.2597 0.14648,0.3535 l 1,1 c 0.0937,0.094 0.22092,0.1465 0.35352,0.1465 h 5 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -1.5039 h 0.33594 l 2.61914,1.9043 c 0.0852,0.064 0.18852,0.099 0.29492,0.1 h 0.25 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -4 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 h -0.25 c -0.106,-10e-5 -0.20927,0.034 -0.29492,0.096 L -355.66211,1859 H -356 v -2 h -1 v 4 h -4.29297 L -362,1860.293 V 1857 h -1 v 1 h -1 v -0.5 c 0.004,-0.2823 -0.22555,-0.5122 -0.50781,-0.5078 z M -353,1858.3008 v 2.3984 l -1.65039,-1.1992 z" inkscape:connector-curvature="0" sodipodi:nodetypes="csssscccsscccsccccccscccccccccccccccccccccsccsccccccccccccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" d="m -362,1857 h 5 v 1 h -5 z" id="path24302"/>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 535.49609,325.98633 c -0.27689,3e-5 -0.50105,0.22506 -0.5,0.50195 l 0.008,3.00781 c 10e-4,0.27537 0.22463,0.49802 0.5,0.49805 h 5.5 v 5.50195 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -4,4.0039 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 9 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 l 9.00782,0.01 c 0.27689,-3e-5 0.50105,-0.22506 0.5,-0.50195 l -0.008,-3.00586 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -5.5 v -5.50196 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path24415-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccc" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g25815">
+ <g
+ transform="translate(-230.99644,-1801.0029)"
+ id="g24435-3"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccacccaccccc"
+ inkscape:connector-curvature="0"
+ id="rect24419-6"
+ transform="translate(230.99644,1801.0029)"
+ d="m 447.00391,325.99805 v 2 h 1 v -1 h 1 v -1 z m 4,0 v 1 h 2 v -1 z m 4,0 v 1 h 2 v -1 z m 4,0 v 1 h 1 v 1 h 1 v -2 z m -12,4 v 2 h 1 v -2 z m 13,0 v 2 h 1 v -2 z m -13,4 v 2 h 1 v -2 z m 13,0 v 2 h 1 v -2 z m -13,4 v 2 h 2 v -1 h -1 v -1 z m 13,0 v 1 h -1 v 1 h 2 v -2 z m -9,1 v 1 h 2 v -1 z m 4,0 v 1 h 2 v -1 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
+ </g>
</g>
- <path inkscape:connector-curvature="0" id="path12791-5" d="m 385,621 a 1.0001,1.0001 0 1 0 0,2 h 12 a 1.0001,1.0001 0 1 0 0,-2 z m 0,5 a 1.0001,1.0001 0 1 0 0,2 h 12 a 1.0001,1.0001 0 1 0 0,-2 z m 0,5 a 1.0001,1.0001 0 1 0 0,2 h 12 a 1.0001,1.0001 0 1 0 0,-2 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <g transform="translate(1.7499929e-7,23.000001)" id="g21364" style="display:inline;fill:#ffffff;enable-background:new">
- <g id="g5447" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 430.49219,134.99219 a 0.50005,0.50005 0 0 0 -0.38867,0.19531 0.50005,0.50005 0 0 0 -0.004,0.006 l -1.95313,1.95312 a 0.50005,0.50005 0 1 0 0.70703,0.70704 L 430,136.70703 V 140.5 a 0.50005,0.50005 0 1 0 1,0 v -3.79297 l 1.14648,1.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.95704,-1.95703 a 0.50005,0.50005 0 0 0 -0.40429,-0.19726 z m 7.00195,7.00195 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 438.29297,144 H 434.5 a 0.50005,0.50005 0 1 0 0,1 h 3.79297 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.95703,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.006,-0.004 l -1.95313,-1.95313 a 0.50005,0.50005 0 0 0 -0.35937,-0.15234 z m -11.00195,2.99805 A 0.50005,0.50005 0 0 0 426,145.5 v 2.93945 A 0.50005,0.50005 0 0 0 426.56055,149 H 429.5 a 0.50005,0.50005 0 1 0 0,-1 h -1.79297 l 1.14649,-1.14648 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 L 427,147.29297 V 145.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" id="path21358" inkscape:connector-curvature="0"/>
- <path id="circle21362" d="M 432.99635,144 A 1.99635,1.99635 0 0 1 431,145.99635 1.99635,1.99635 0 0 1 429.00365,144 1.99635,1.99635 0 0 1 431,142.00365 1.99635,1.99635 0 0 1 432.99635,144 Z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" inkscape:connector-curvature="0"/>
+ <g
+ transform="translate(876,-1690)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g24686-1"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Dysk Google\PROJEKTY BIEŻĄCE - Andrzej\BLENDER 2.8 ICONS redesign\MOCKUPS\gizmo icon_1.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -419.5,1827 a 0.50005,0.50005 0 1 0 0,1 h 2.79492 l -2.96875,2.9688 c 0.24471,0.2267 0.48032,0.4623 0.70703,0.707 L -416,1828.709 v 2.791 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -2.98438,6.7793 -3.50585,3.5059 C -426.28828,1837.1081 -426.63057,1837 -427,1837 c -1.09865,0 -2,0.9013 -2,2 0,1.0986 0.90135,2 2,2 1.09865,0 2,-0.9014 2,-2 0,-0.3677 -0.10771,-0.7107 -0.2832,-1.0078 l 3.50586,-3.5059 c -0.22252,-0.2491 -0.45807,-0.4843 -0.70704,-0.707 z M -427,1838 c 0.55821,0 1,0.4417 1,1 0,0.5582 -0.44179,1 -1,1 -0.55821,0 -1,-0.4418 -1,-1 0,-0.5583 0.44179,-1 1,-1 z"
+ id="path24506-4"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -428.49556,1829 a 0.4997692,0.49966962 0 1 0 0,0.9993 c 5.80308,0 10.49606,4.6921 10.49606,10.494 a 0.4997692,0.49966962 0 1 0 0.99944,0 c 0,-6.3418 -5.1523,-11.4933 -11.4955,-11.4933 z"
+ id="ellipse24510-0"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ id="path22885-3-7"
+ d="m 537.4922,557 c -0.1299,0 -0.2539,0.055 -0.3457,0.1465 -1.4018,1.4018 -2.9571,1.8535 -5.6465,1.8535 -0.2761,0 -0.5,0.2239 -0.5,0.5 v 3 c 0,2.4627 0.6805,4.0682 1.7871,5.2754 1.1066,1.2072 2.5736,2.0242 4.1777,3.1348 0.084,0.058 0.1832,0.09 0.2852,0.09 h 0.5 c 0.102,-2e-4 0.2015,-0.032 0.2852,-0.09 1.6041,-1.1106 3.0711,-1.9276 4.1777,-3.1348 C 543.3195,566.5682 544,564.9627 544,562.5 v -3 c 0,-0.2761 -0.2239,-0.5 -0.5,-0.5 -2.6894,0 -4.2447,-0.4517 -5.6465,-1.8535 -0.096,-0.096 -0.226,-0.1486 -0.3613,-0.1465 z m 3.4766,3.9902 a 1.0001,1.0001 0 0 1 0.8124,1.6348 l -4,5 a 1.0001,1.0001 0 0 1 -1.4882,0.082 l -2,-2 a 1.0001,1.0001 0 1 1 1.414,-1.414 l 1.209,1.209 3.3028,-4.127 a 1.0001,1.0001 0 0 1 0.75,-0.3848 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 516.49219,557 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 C 514.74469,558.54828 513.18939,559 510.5,559 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 c 0,2.46272 0.6805,4.06818 1.78711,5.27539 1.10661,1.20722 2.57356,2.02419 4.17773,3.13477 A 0.50005,0.50005 0 0 0 516.25,571 h 0.5 a 0.50005,0.50005 0 0 0 0.28516,-0.0898 c 1.60417,-1.11058 3.07112,-1.92755 4.17773,-3.13477 C 522.3195,566.56818 523,564.96272 523,562.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 c -2.68939,0 -4.24469,-0.45172 -5.64648,-1.85352 A 0.50005,0.50005 0 0 0 516.49219,557 Z m 0.008,1.07031 c 1.42533,1.26825 3.16641,1.79779 5.5,1.86524 V 562.5 c 0,2.28728 -0.5695,3.55682 -1.52539,4.59961 -0.92707,1.01135 -2.30655,1.81425 -3.88867,2.90039 h -0.17188 c -1.58212,-1.08614 -2.9616,-1.88904 -3.88867,-2.90039 C 511.5695,566.05682 511,564.78728 511,562.5 v -2.56445 c 2.33359,-0.0675 4.07467,-0.59699 5.5,-1.86524 z"
+ id="path22877-22-0"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 511.99933,414.00018 h 9 v 5 h -9 z m -1.5,-2 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 8 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5.5 v 1 h -2.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 6 c 0.6573,-0.009 0.6573,-0.9907 0,-1 h -2.5 v -1 h 5.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -8 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 11 v 7 h -11 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ id="rect22324-2" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 489.5,412 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 8 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5.5 v 1 h -2.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 6 c 0.6573,-0.009 0.6573,-0.9907 0,-1 H 496 v -1 h 5.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -8 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 11 v 7 h -11 z"
+ id="path22338-8"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccc" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g25476"
+ transform="translate(-20)">
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g25445"
+ transform="translate(-218,-111)">
+ <path
+ sodipodi:nodetypes="ssssccccccccssssccs"
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 301.5,305 c -0.82235,0 -1.5,0.67765 -1.5,1.5 v 5 c 0,0.82235 1,1.5 1.5,1.5 h 0.5 v -3 h -0.5 c -0.67616,0.01 -0.67616,-1.01 0,-1 h 11 c 0.67616,-0.01 0.67616,1.01 0,1 H 312 v 3 h 0.5 c 0.82235,0 1.5,-0.67765 1.5,-1.5 v -5 c 0,-0.82235 -0.67765,-1.5 -1.5,-1.5 H 312 302 Z"
+ transform="translate(70,363)"
+ id="path25441" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 135,562 v 8.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 562 Z m 6,2 c 0.54636,0 1,0.45364 1,1 0,0.54636 -0.45364,1 -1,1 -0.54636,0 -1,-0.45364 -1,-1 0,-0.54636 0.45364,-1 1,-1 z m -2.50781,2 c 0.16994,-0.003 0.32953,0.0812 0.42383,0.22266 l 2,3 c 0.22142,0.33228 -0.0167,0.77726 -0.41602,0.77734 h -4 c -0.39932,-8e-5 -0.63744,-0.44506 -0.41602,-0.77734 l 2,-3 c 0.0912,-0.13686 0.24381,-0.21966 0.40821,-0.22266 z"
+ transform="translate(238,111)"
+ id="path25443"
+ inkscape:connector-curvature="0" />
</g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g24264-7" transform="translate(-910,-1146)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 1028,1556 c -3.2833,0 -6,2.4414 -6,5.5 0,1.7056 0.9046,3.146 2.1523,4.3594 l 0.9942,0.9941 a 0.50004997,0.50004997 0 0 0 0.3027,0.1485 0.50004997,0.50004997 0 0 0 0.051,0.998 h 5 a 0.50004997,0.50004997 0 0 0 0.045,-0.998 0.50004997,0.50004997 0 0 0 0.3086,-0.1485 l 0.9981,-0.998 v 0 c 1.2122,-1.1985 2.1465,-2.6518 2.1465,-4.3535 0,-3.0586 -2.7167,-5.5 -6,-5.5 z m 0,1 c 2.7919,0 5,2.0358 5,4.5 0,1.3342 -0.7428,2.5488 -1.8516,3.6445 l -1,1 a 0.50004997,0.50004997 0 0 0 0.2793,0.8535 h -4.8594 a 0.50004997,0.50004997 0 0 0 0.2871,-0.8535 l -1,-1 a 0.50004997,0.50004997 0 0 0 -0.01,-0.01 c -1.1397,-1.1082 -1.8477,-2.2864 -1.8477,-3.6406 0,-2.4642 2.2081,-4.5 5,-4.5 z m -2.5,12 a 0.50004997,0.50004997 0 1 0 0,1 h 1.5 v 0.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 1 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -0.5 h 1.5 a 0.50004997,0.50004997 0 1 0 0,-1 z" id="path24260-0" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 1025.4902,1561.0059 a 0.50005,0.50005 0 0 0 -0.3437,0.8476 l 0.8535,0.8535 v 1.543 a 0.50005,0.50005 0 1 0 1,0 V 1563 h 2 v 1.25 a 0.50005,0.50005 0 1 0 1,0 v -1.543 l 0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.707,-0.707 L 1029.293,1562 h -2.586 l -0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.3633,-0.1406 z" id="path24262-3" inkscape:connector-curvature="0"/>
+ <path
+ sodipodi:nodetypes="ccccccscsccccccccccccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path5256"
+ d="m 197.50977,409.99414 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5039 c 0.0205,0.58311 0.0403,1.03618 -0.0488,1.24805 -0.22838,0.54301 -0.5609,0.82668 -1.00781,1.10937 -0.44691,0.28269 -1.00733,0.53131 -1.53711,0.97461 -0.52977,0.4433 -1.00108,1.10059 -1.22656,2.08789 -0.22548,0.9873 -0.2332,2.29903 0.0625,4.16406 0.0385,0.24311 0.24801,0.42203 0.49414,0.42188 h 8.75586 c 0.30739,1.4e-4 0.54213,-0.2745 0.49414,-0.57812 -0.36883,-2.32606 -0.21493,-3.6368 0.12305,-4.40821 0.33798,-0.7714 0.85304,-1.08606 1.49804,-1.45508 0.645,-0.36901 1.43565,-0.7809 1.90821,-1.70703 0.47255,-0.92613 0.59571,-2.25921 0.21289,-4.4375 C 208.70043,411.17484 208.49284,411.0002 208.25,411 h -7.24023 v -0.50586 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m 3,1.00586 h 6.78125 c 0.25456,1.74951 0.14487,2.81594 -0.15235,3.39844 -0.3247,0.63637 -0.84774,0.91198 -1.51367,1.29297 -0.66593,0.38098 -1.46183,0.87882 -1.91797,1.91992 -0.41222,0.94085 -0.49675,2.35477 -0.23633,4.38867 h -7.73437 c -0.19264,-1.47462 -0.23076,-2.65205 -0.0684,-3.36328 0.18281,-0.80045 0.49635,-1.21142 0.89258,-1.54297 0.39622,-0.33155 0.90291,-0.56523 1.42968,-0.89844 0.52678,-0.33321 1.07351,-0.7985 1.39649,-1.5664 0.22021,-0.52359 0.17686,-1.05487 0.13867,-1.63477 h 0.48438 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path5262"
+ d="m 180.5,410 c -2.08712,0 -3.47816,1.04607 -4.39062,2.1875 a 0.50024408,0.50024408 0 0 0 0.78125,0.625 C 177.69049,411.81193 178.73439,411 180.5,411 c 2.09839,0 3.13411,0.87695 3.75195,1.94531 C 184.8698,414.01367 185,415.31651 185,416 h -5.25 c -1.27344,0 -2.44324,0.36418 -3.31445,1.05469 -0.87121,0.69051 -1.42774,1.72791 -1.42774,2.94531 0,1.2174 0.55653,2.2548 1.42774,2.94531 C 177.30676,423.63582 178.47656,424 179.75,424 h 0.75 c 1.75558,0 3.38771,-0.96684 4.53711,-2.0332 0.0781,0.53303 0.28951,1.00434 0.64062,1.35547 C 186.12862,423.77315 186.775,424 187.5,424 a 0.50005,0.50005 0 1 0 0,-1 c -0.525,0 -0.87862,-0.14815 -1.11523,-0.38477 C 186.14815,422.37862 186,422.025 186,421.5 V 416 c 0,-0.79721 -0.12242,-2.24322 -0.88086,-3.55469 C 184.3607,411.13385 182.89646,410 180.5,410 Z m -0.75,7 H 185 v 3.56055 C 184.04582,421.68473 182.18875,423 180.5,423 h -0.75 c -1.08101,0 -2.03187,-0.31555 -2.69336,-0.83984 -0.66149,-0.52429 -1.04883,-1.23676 -1.04883,-2.16016 0,-0.9234 0.38734,-1.63587 1.04883,-2.16016 C 177.71813,417.31555 178.66899,417 179.75,417 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="translate(-105,-20.999997)"
+ id="g24881"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ id="path24877"
+ d="m 183.8125,200.01562 c 2.21359,0.18235 3.97803,1.94071 4.16992,4.1543 0.19189,2.2136 -1.24344,4.25155 -3.39258,4.8125 a 0.5007349,0.5007349 0 1 1 -0.2539,-0.96875 c 1.68376,-0.43948 2.80079,-2.02289 2.65039,-3.75781 -0.1504,-1.73492 -1.52164,-3.10129 -3.25586,-3.24414 -1.73423,-0.14285 -3.31219,0.98104 -3.74414,2.66797 a 0.50005,0.50005 0 1 1 -0.96875,-0.24805 c 0.55114,-2.15241 2.58133,-3.59836 4.79492,-3.41602 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <g
+ id="g24891"
+ transform="matrix(-1,0,0,1,356.9996,0)"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ d="M 176.99634,212.50183 A 1.4981741,1.4981725 0 0 1 175.49817,214 a 1.4981741,1.4981725 0 0 1 -1.49818,-1.49817 1.4981741,1.4981725 0 0 1 1.49818,-1.49817 1.4981741,1.4981725 0 0 1 1.49817,1.49817 z m 2.39233,-7.41199 c 0.85602,0.17256 1.66292,0.59211 2.30469,1.23828 1.28353,1.29236 1.66074,3.23682 0.95508,4.91602 -0.70566,1.6792 -2.35829,2.76833 -4.17969,2.75586 a 0.50005,0.50005 0 1 1 0.008,-1 c 1.41921,0.01 2.70016,-0.83611 3.25,-2.14453 0.54985,-1.30842 0.25598,-2.81527 -0.74414,-3.82227 -1.00012,-1.00699 -2.50427,-1.31041 -3.8164,-0.76953 C 175.85388,206.80455 175,208.08075 175,209.5 a 0.50005,0.50005 0 1 1 -1,0 c 0,-1.82144 1.10118,-3.466 2.78516,-4.16016 0.84199,-0.34708 1.7475,-0.42255 2.60351,-0.25 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ id="ellipse24887" />
+ </g>
</g>
- <g transform="translate(-847,-1062)" id="g24813" style="display:inline;fill:#ffffff;enable-background:new">
- <path inkscape:connector-curvature="0" id="path24809" d="m 1028,1556 c -3.2833,0 -6,2.4414 -6,5.5 0,1.7056 0.9046,3.146 2.1523,4.3594 l 0.9942,0.9941 a 0.50004997,0.50004997 0 0 0 0.3027,0.1485 0.50004997,0.50004997 0 0 0 0.051,0.998 h 5 a 0.50004997,0.50004997 0 0 0 0.045,-0.998 0.50004997,0.50004997 0 0 0 0.3086,-0.1485 l 0.9981,-0.998 v 0 c 1.2122,-1.1985 2.1465,-2.6518 2.1465,-4.3535 0,-3.0586 -2.7167,-5.5 -6,-5.5 z m 0,1 c 2.7919,0 5,2.0358 5,4.5 0,1.3342 -0.7428,2.5488 -1.8516,3.6445 l -1,1 a 0.50004997,0.50004997 0 0 0 0.2793,0.8535 h -4.8594 a 0.50004997,0.50004997 0 0 0 0.2871,-0.8535 l -1,-1 a 0.50004997,0.50004997 0 0 0 -0.01,-0.01 c -1.1397,-1.1082 -1.8477,-2.2864 -1.8477,-3.6406 0,-2.4642 2.2081,-4.5 5,-4.5 z m -2.5,12 a 0.50004997,0.50004997 0 1 0 0,1 h 1.5 v 0.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 1 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -0.5 h 1.5 a 0.50004997,0.50004997 0 1 0 0,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path24811" d="m 1025.4902,1561.0059 a 0.50005,0.50005 0 0 0 -0.3437,0.8476 l 0.8535,0.8535 v 1.543 a 0.50005,0.50005 0 1 0 1,0 V 1563 h 2 v 1.25 a 0.50005,0.50005 0 1 0 1,0 v -1.543 l 0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.707,-0.707 L 1029.293,1562 h -2.586 l -0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.3633,-0.1406 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 490,307 c -0.55226,6e-5 -0.99994,0.44774 -1,1 v 8 c 6e-5,0.55226 0.44774,0.99994 1,1 h 12 c 0.55226,-6e-5 0.99994,-0.44774 1,-1 v -8 c -6e-5,-0.55226 -0.44774,-0.99994 -1,-1 z m 6,1 a 4,4 0 0 1 4,4 4,4 0 0 1 -4,4 4,4 0 0 1 -4,-4 4,4 0 0 1 4,-4 z"
+ id="path25011-0" />
+ <g
+ transform="translate(1055,731)"
+ style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="g25234-0">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -580,-424 c -2.7555,0 -5,2.2445 -5,5 0,2.7555 2.2445,5 5,5 2.7555,0 5,-2.2445 5,-5 0,-2.7555 -2.2445,-5 -5,-5 z m 0,1 c 2.21506,0 4,1.78494 4,4 0,2.21506 -1.78494,4 -4,4 -2.21506,0 -4,-1.78494 -4,-4 0,-2.21506 1.78494,-4 4,-4 z m -0.52148,1 a 0.50005,0.50005 0 0 0 -0.084,0.0117 c -1.2099,0.24373 -2.15796,1.187 -2.38476,2.38867 a 0.50005,0.50005 0 1 0 0.98242,0.18555 c 0.15048,-0.79727 0.77874,-1.42839 1.59961,-1.59375 A 0.50005,0.50005 0 0 0 -580.52148,-422 Z"
+ id="path25232-0"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 542.77344,306 a 1.0001,1.0001 0 0 0 -0.41211,0.0781 l -4.74024,2 a 1.0004654,1.0004654 0 1 0 0.77735,1.84376 l 1.54883,-0.65235 -2.69532,5.375 -2.78906,-2.30078 a 1.50015,1.50015 0 1 0 -1.9082,2.3125 l 4.24023,3.5 a 1.50015,1.50015 0 0 0 2.29688,-0.48437 l 3.53711,-7.0586 0.41015,1.63086 a 1.0001,1.0001 0 1 0 1.93946,-0.48828 l -1.25977,-5 A 1.0001,1.0001 0 0 0 542.77344,306 Z"
+ id="path25427-8" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 521.51367,306 a 0.50005,0.50005 0 0 0 -0.23633,0.0527 l -4,2 a 0.50005,0.50005 0 1 0 0.44532,0.89454 l 2.8164,-1.40821 -4.20508,8.1875 -4.52148,-3.61718 a 0.50024018,0.50024018 0 1 0 -0.625,0.78124 l 5,4 a 0.50005,0.50005 0 0 0 0.75781,-0.1621 l 4.4375,-8.64063 0.63281,2.5332 a 0.50005,0.50005 0 1 0 0.96876,-0.24218 l -1,-4 A 0.50005,0.50005 0 0 0 521.51367,306 Z"
+ id="path25488-0"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g5381"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.03999233px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 329.97518,350.98014 a 0.52004817,0.52004817 0 0 0 -0.38086,0.19532 l -3.61133,4.51562 -3.09179,-3.5332 a 0.52004817,0.52004817 0 1 0 -0.78321,0.68359 l 3.5,4 a 0.52004817,0.52004817 0 0 0 0.79883,-0.0176 l 3.61133,-4.51367 3.08984,3.53125 a 0.52004817,0.52004817 0 1 0 0.78321,-0.68359 l -3.5,-4 a 0.52004817,0.52004817 0 0 0 -0.41602,-0.17774 z"
+ id="path4898"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.03999233px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 321.49219,347.97266 A 0.52004817,0.52004817 0 0 0 320.97852,348.5 v 11 a 0.520505,0.520505 0 0 0 1.04101,0 V 358 h 11.95899 v 1.5 a 0.520505,0.520505 0 0 0 1.04101,0 v -11 a 0.52004817,0.52004817 0 0 0 -0.52734,-0.52734 0.52004817,0.52004817 0 0 0 -0.51367,0.52734 v 1.5 h -11.95899 v -1.5 a 0.52004817,0.52004817 0 0 0 -0.52734,-0.52734 z M 322.01953,351 h 11.95899 v 6 h -11.95899 z"
+ id="path4902" />
+ </g>
+ <g
+ transform="translate(166.89495,43.00791)"
+ id="g9160-3"
+ style="display:inline;fill:#ffffff;enable-background:new" />
+ <g
+ id="g5375"
+ style="fill:#ffffff">
+ <path
+ inkscape:connector-curvature="0"
+ id="path9106-6-2"
+ d="m 346.49261,354.99229 a 0.50005,0.50005 0 0 0 -0.49219,0.50781 v 3 c 0,0.725 0.22685,1.37138 0.67773,1.82226 0.45089,0.45089 1.09727,0.67774 1.82227,0.67774 0.725,0 1.37138,-0.22685 1.82226,-0.67774 0.45089,-0.45088 0.67774,-1.09726 0.67774,-1.82226 v -3 a 0.50005,0.50005 0 1 0 -1,0 v 3 c 0,0.525 -0.14815,0.87862 -0.38477,1.11523 -0.23661,0.23661 -0.59023,0.38477 -1.11523,0.38477 -0.525,0 -0.87862,-0.14816 -1.11524,-0.38477 -0.23661,-0.23661 -0.38476,-0.59023 -0.38476,-1.11523 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ d="m 348.49261,349.99229 a 0.50005,0.50005 0 0 0 -0.49219,0.50781 v 6 a 0.50005,0.50005 0 1 0 1,0 v -6 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -5.99219,-2.99219 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 1.75 c 0,0.97222 0.53688,1.82801 1.27539,2.19726 a 0.50005635,0.50005635 0 1 0 0.44726,-0.89453 c -0.26148,-0.13074 -0.72265,-0.77495 -0.72265,-1.30273 v -1.75 h 5 v 1.75 c 0,0.52778 -0.46312,1.17199 -0.72461,1.30273 a 0.50005635,0.50005635 0 1 0 0.44726,0.89453 c 0.73852,-0.36925 1.27735,-1.22504 1.27735,-2.19726 v -1.75 h 2.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="path9108-6-6"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-40.999997,-42)"
+ id="g25194-8-8"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <circle
+ cx="221"
+ cy="285"
+ id="circle25190-1-7"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ r="0" />
+ <path
+ id="circle25383"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 221,284 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m 3,0 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m 3,1 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m -5.67188,2.04688 c -0.72617,0.0892 -1.40636,0.31348 -2.02343,0.63867 -1.23415,0.65038 -2.22638,1.68758 -2.94922,2.84375 -0.72284,1.15617 -1.1805,2.43169 -1.32227,3.60742 -0.14176,1.17573 0.0178,2.28295 0.6875,3.0293 0.68189,0.75993 1.69067,0.98063 2.61328,0.6914 C 219.35231,297.53818 220,296.54997 220,295.5 c 0,-0.87561 0.22937,-1.10992 0.64258,-1.29297 C 221.05579,294.02398 221.75437,294 222.5,294 c 0.79276,0 1.56488,-0.14919 2.20703,-0.5332 0.52292,-0.31271 0.89501,-0.8382 1.11524,-1.4668 h 1.13281 a 0.50004994,0.50004994 0 0 0 0.002,0 c 1.02746,0 1.90966,-0.75672 2.0293,-1.76953 0.11964,-1.01284 -0.5686,-1.95303 -1.57031,-2.17969 -0.73109,-0.16542 -1.38414,0.17264 -1.8711,0.68945 -0.49389,-0.69239 -1.0864,-1.29918 -1.91601,-1.52148 -0.80279,-0.21511 -1.57461,-0.26104 -2.30079,-0.17187 z m 0.11915,0.98632 c 0.59872,-0.0738 1.23897,-0.0331 1.92382,0.15039 0.66836,0.17909 1.23082,0.75735 1.69727,1.56446 a 0.50004994,0.50004994 0 0 0 0.90234,-0.0781 c 0.17721,-0.4818 0.69836,-0.76361 1.22461,-0.64453 0.52625,0.11908 0.85819,0.58537 0.79883,1.08789 C 227.93478,290.61583 227.49838,291 226.95703,291 H 225.5 a 0.50004994,0.50004994 0 0 0 -0.49219,0.41406 c -0.10308,0.5846 -0.38181,0.93776 -0.8125,1.19532 C 223.76463,292.86693 223.16312,293 222.5,293 c -0.74508,0 -1.54761,-0.0253 -2.26172,0.29102 C 219.52417,293.60735 219,294.37315 219,295.5 c 0,0.63163 -0.40649,1.2273 -0.96484,1.40234 -0.62221,0.19506 -1.12911,0.0874 -1.57032,-0.40429 -0.37675,-0.41988 -0.55858,-1.23603 -0.4375,-2.24024 0.12109,-1.00421 0.53101,-2.16478 1.17774,-3.19922 0.64673,-1.03443 1.52684,-1.94044 2.5664,-2.48828 0.51979,-0.27392 1.07706,-0.46333 1.67579,-0.53711 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 90.494141,178.99609 a 0.50005,0.50005 0 0 0 -0.347657,0.85743 l 3,3 C 92.440854,183.71574 91.999993,184.80241 92,186 c 2e-5,1.19757 0.440853,2.28425 1.146484,3.14648 l -3,3 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 3,-3 C 94.715742,190.55915 95.802428,191 97,191 c 1.197573,0 2.284258,-0.44085 3.14648,-1.14648 l 3,3 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -3,-3 C 101.55915,188.28425 101.99998,187.19757 102,186 c 0,-1.19759 -0.44086,-2.28426 -1.14648,-3.14648 l 3,-3 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3,3 C 99.284255,181.44086 98.197592,181 97,181 c -1.19759,0 -2.284254,0.44086 -3.146484,1.14648 l -3,-3 a 0.50005,0.50005 0 0 0 -0.359375,-0.15039 z M 97,182 c 2.21506,0 4.00001,1.78494 4,4 -4e-5,2.21502 -1.784977,4 -4,4 -2.215019,0 -3.999963,-1.78498 -4,-4 -1.2e-5,-2.21506 1.784946,-4 4,-4 z"
+ id="path25165"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g10845">
+ <path
+ inkscape:connector-curvature="0"
+ d="m 473,628 a 1.0001,1.0001 0 1 0 0,2 h 2 a 1.0001,1.0001 0 1 0 0,-2 z m -4.5,-6 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.5 v 7.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 a 0.50005,0.50005 0 1 0 -1,0 v 4.5 h -8 v -7 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 H 469 v -2 h 4.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path24739-4" />
+ <path
+ sodipodi:nodetypes="sssssccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path27428"
+ d="m 478.50003,620.0003 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" />
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g27418"
+ transform="translate(83.999997,-84)">
+ <path
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ d="m 352.50003,305.0003 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z"
+ id="path27589"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssccccccccccccc" />
+ <g
+ id="g27675-2"
+ transform="rotate(90,232.49897,657.49643)"
+ style="display:inline;opacity:0.7;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -109.99609,533.99609 -0.004,7.11133 c -1.67885,0.25428 -2.99414,1.64686 -2.99414,3.39453 0,1.92568 1.57041,3.49805 3.49609,3.49805 1.92569,0 3.49805,-1.57236 3.49805,-3.49805 0,-1.74925 -1.31894,-3.14219 -3,-3.39453 l 0.004,-7.11133 z m 0.49804,8.00977 c 1.38524,0 2.49805,1.11085 2.49805,2.49609 0,1.38525 -1.1128,2.49805 -2.49805,2.49805 -1.38524,0 -2.49609,-1.11281 -2.49609,-2.49805 0,-1.38523 1.11086,-2.49609 2.49609,-2.49609 z"
+ id="path27671-7"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -108.5,534 v 3 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path27673-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ </g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g24819" transform="translate(-1015,-999)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 1028,1556 c -3.2833,0 -6,2.4414 -6,5.5 0,1.7056 0.9046,3.146 2.1523,4.3594 l 0.9942,0.9941 a 0.50004997,0.50004997 0 0 0 0.3027,0.1485 0.50004997,0.50004997 0 0 0 0.051,0.998 h 5 a 0.50004997,0.50004997 0 0 0 0.045,-0.998 0.50004997,0.50004997 0 0 0 0.3086,-0.1485 l 0.9981,-0.998 v 0 c 1.2122,-1.1985 2.1465,-2.6518 2.1465,-4.3535 0,-3.0586 -2.7167,-5.5 -6,-5.5 z m 0,1 c 2.7919,0 5,2.0358 5,4.5 0,1.3342 -0.7428,2.5488 -1.8516,3.6445 l -1,1 a 0.50004997,0.50004997 0 0 0 0.2793,0.8535 h -4.8594 a 0.50004997,0.50004997 0 0 0 0.2871,-0.8535 l -1,-1 a 0.50004997,0.50004997 0 0 0 -0.01,-0.01 c -1.1397,-1.1082 -1.8477,-2.2864 -1.8477,-3.6406 0,-2.4642 2.2081,-4.5 5,-4.5 z m -2.5,12 a 0.50004997,0.50004997 0 1 0 0,1 h 1.5 v 0.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 1 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -0.5 h 1.5 a 0.50004997,0.50004997 0 1 0 0,-1 z" id="path24815" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 1025.4902,1561.0059 a 0.50005,0.50005 0 0 0 -0.3437,0.8476 l 0.8535,0.8535 v 1.543 a 0.50005,0.50005 0 1 0 1,0 V 1563 h 2 v 1.25 a 0.50005,0.50005 0 1 0 1,0 v -1.543 l 0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.707,-0.707 L 1029.293,1562 h -2.586 l -0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.3633,-0.1406 z" id="path24817" inkscape:connector-curvature="0"/>
+ <g
+ style="display:inline;enable-background:new"
+ id="g27444"
+ transform="translate(-18.000003,-64)">
+ <g
+ id="g27675"
+ transform="rotate(90,282.99897,687.99643)"
+ style="opacity:0.7">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -109.99609,533.99609 -0.004,7.11133 c -1.67885,0.25428 -2.99414,1.64686 -2.99414,3.39453 0,1.92568 1.57041,3.49805 3.49609,3.49805 1.92569,0 3.49805,-1.57236 3.49805,-3.49805 0,-1.74925 -1.31894,-3.14219 -3,-3.39453 l 0.004,-7.11133 z m 0.49804,8.00977 c 1.38524,0 2.49805,1.11085 2.49805,2.49609 0,1.38525 -1.1128,2.49805 -2.49805,2.49805 -1.38524,0 -2.49609,-1.11281 -2.49609,-2.49805 0,-1.38523 1.11086,-2.49609 2.49609,-2.49609 z"
+ id="path27671"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -108.5,534 v 3 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path27673"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 430.49414,284.99414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 2.64649,2.64648 -2.64649,2.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2.64648,-2.64649 2.64648,2.64649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -2.64649,-2.64648 2.64649,-2.64648 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 l -2.64648,2.64649 -2.64648,-2.64649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path27679"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(4.7134341e-6,4.7134317e-6)"
+ style="display:inline;enable-background:new"
+ id="g27915">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 180.5,263 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5 v 0.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5 v 1.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -7 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 6 v 6 h -2 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 183 v -0.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 181 Z"
+ id="path27886"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 176.50781,262.99414 a 0.50005,0.50005 0 0 0 -0.45508,0.72852 l 1,2 a 0.50005,0.50005 0 1 0 0.89454,-0.44532 l -1,-2 a 0.50005,0.50005 0 0 0 -0.43946,-0.2832 z m -2.02539,3.00195 a 0.50005,0.50005 0 0 0 -0.20508,0.95118 l 2,1 a 0.50005,0.50005 0 1 0 0.44532,-0.89454 l -2,-1 a 0.50005,0.50005 0 0 0 -0.24024,-0.0566 z m 11,6 a 0.50005,0.50005 0 0 0 -0.20508,0.95118 l 2,1 a 0.50005,0.50005 0 1 0 0.44532,-0.89454 l -2,-1 a 0.50005,0.50005 0 0 0 -0.24024,-0.0566 z m -0.97461,1.99805 a 0.50005,0.50005 0 0 0 -0.45508,0.72852 l 1,2 a 0.50005,0.50005 0 1 0 0.89454,-0.44532 l -1,-2 a 0.50005,0.50005 0 0 0 -0.43946,-0.2832 z"
+ id="path27898"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 174.5,269 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 7 a 0.50005,0.50005 0 0 0 0.5,0.5 h 7 a 0.50005,0.50005 0 0 0 0.5,-0.5 l -0.008,-4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -1.5 v -1.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -1.4961 L 178,269.50391 A 0.50005,0.50005 0 0 0 177.5,269 Z m 0.5,1 h 1.99609 l -0.004,0.49609 a 0.50005,0.50005 0 0 0 0.5,0.50391 h 1.5 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.5 l 0.008,3 h -6 z"
+ id="path10946"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g27501-8"
+ transform="translate(-20.999927,104.99988)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.85;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 346.54688,478.16016 a 0.50005,0.50005 0 0 0 -0.18165,0.0293 c -1.54898,0.53108 -2.52602,2.0719 -2.34375,3.69922 0.18228,1.62732 1.47542,2.91657 3.10352,3.0918 1.6281,0.17523 3.16703,-0.80811 3.69141,-2.35938 a 0.50005,0.50005 0 1 0 -0.94727,-0.32031 c -0.37611,1.11265 -1.46896,1.81123 -2.63672,1.68555 -1.16775,-0.12568 -2.08606,-1.04179 -2.2168,-2.20899 -0.13073,-1.1672 0.56282,-2.26166 1.67383,-2.64257 a 0.50005,0.50005 0 0 0 -0.14257,-0.97461 z"
+ id="path27478-1"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 346.52148,476.09375 a 0.50004994,0.50004994 0 0 0 -0.0859,0.01 c -2.69151,0.53044 -4.58334,2.97414 -4.42578,5.71289 0.15755,2.73875 2.31815,4.94772 5.05273,5.16601 2.73458,0.21829 5.21856,-1.61975 5.80859,-4.29883 a 0.50004994,0.50004994 0 1 0 -0.97656,-0.21484 c -0.48423,2.19868 -2.50772,3.69672 -4.75195,3.51758 -2.24424,-0.17915 -4.00546,-1.98086 -4.13477,-4.22852 -0.1293,-2.24766 1.41221,-4.2385 3.6211,-4.67383 a 0.50004994,0.50004994 0 0 0 -0.10743,-0.99023 z"
+ id="circle27480-1"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 353.49219,473 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -5,5 c -0.0938,0.0938 -0.14646,0.22092 -0.14648,0.35352 v 1.79297 l -0.85352,0.85351 c -0.49023,0.47127 0.23577,1.19727 0.70704,0.70704 L 348.70703,481 H 350.5 c 0.1326,-2e-5 0.25976,-0.0527 0.35352,-0.14648 l 5,-5 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -2,-2 c -0.0957,-0.0957 -0.22603,-0.14855 -0.36133,-0.14648 z"
+ id="path27485-1"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccc" />
+ </g>
+ <path
+ sodipodi:nodetypes="cccccccc"
+ inkscape:connector-curvature="0"
+ id="path27639"
+ d="m 29.959614,221.99997 c -0.53618,0.022 -0.95938,0.4634 -0.95898,1 v 10 c 7.2e-4,0.7847 0.8635,1.2629 1.5293,0.8477 l 8,-5 c 0.625909,-0.3918 0.625909,-1.3036 0,-1.6954 l -8,-5 c -0.17045,-0.107 -0.36922,-0.1601 -0.57032,-0.1523 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 185.04038,221.99997 c 0.53618,0.022 0.95938,0.4634 0.95898,1 v 10 c -7.2e-4,0.7847 -0.8635,1.2629 -1.5293,0.8477 l -8,-5 c -0.62591,-0.3918 -0.62591,-1.3036 0,-1.6954 l 8,-5 c 0.17045,-0.107 0.36922,-0.1601 0.57032,-0.1523 z"
+ id="path9268"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path27528"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 132.5104,224 c -0.27994,-0.01 -0.50979,0.22 -0.50977,0.5 v 7 c -0.001,0.4307 0.5065,0.6613 0.83008,0.377 l 4,-3.5 c 0.22872,-0.1993 0.22872,-0.5547 0,-0.754 l -4,-3.5 c -0.0889,-0.078 -0.20238,-0.1211 -0.32031,-0.123 z m 9.96289,-1 c -0.13302,0.01 -0.25746,0.068 -0.34571,0.168 l -4,4.5 c -0.16816,0.1894 -0.16816,0.4746 0,0.664 l 4,4.5 c 0.19883,0.2227 0.54727,0.2227 0.7461,0 l 4,-4.5 c 0.16816,-0.1894 0.16816,-0.4746 0,-0.664 l -4,-4.5 c -0.10092,-0.114 -0.24831,-0.1759 -0.40039,-0.168 z" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path27544"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 51.506493,224 c -0.27842,0 -0.50585,0.2216 -0.50586,0.5 v 7 c -6.1e-4,0.4051 0.45544,0.6427 0.78711,0.4102 l 5,-3.5 c 0.28542,-0.199 0.28542,-0.6214 0,-0.8204 l -5,-3.5 c -0.0826,-0.058 -0.1806,-0.089 -0.28125,-0.09 z m 6.49414,-1 v 10 h 2 v -10 z" />
+ <path
+ d="m 124.49003,224 c 0.27994,-0.01 0.50979,0.22 0.50977,0.5 v 7 c 0.001,0.4307 -0.5065,0.6613 -0.83008,0.377 l -4,-3.5 c -0.22872,-0.1993 -0.22872,-0.5547 0,-0.754 l 4,-3.5 c 0.0889,-0.078 0.20238,-0.1211 0.32031,-0.123 z m -9.96289,-1 c 0.13302,0.01 0.25746,0.068 0.34571,0.168 l 4,4.5 c 0.16816,0.1894 0.16816,0.4746 0,0.664 l -4,4.5 c -0.19883,0.2227 -0.54727,0.2227 -0.7461,0 l -4,-4.5 c -0.16816,-0.1894 -0.16816,-0.4746 0,-0.664 l 4,-4.5 c 0.10092,-0.114 0.24831,-0.1759 0.40039,-0.168 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path9201"
+ inkscape:connector-curvature="0" />
+ <path
+ d="m 79.49414,224 c 0.27842,0 0.50585,0.2216 0.50586,0.5 v 7 c 6.1e-4,0.4051 -0.45544,0.6427 -0.78711,0.4102 l -5,-3.5 c -0.28542,-0.199 -0.28542,-0.6214 0,-0.8204 l 5,-3.5 c 0.0826,-0.058 0.1806,-0.089 0.28125,-0.09 z M 73,223 v 10 h -2 v -10 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path9203"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path9205"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 75.50586,203 c -0.27842,0 -0.50585,0.2216 -0.50586,0.5 v 7 c -6.1e-4,0.4051 0.45544,0.6427 0.78711,0.4102 l 5,-3.5 c 0.28542,-0.199 0.28542,-0.6214 0,-0.8204 l -5,-3.5 c -0.0826,-0.058 -0.1806,-0.089 -0.28125,-0.09 z M 71,203 v 8 h 2 v -8 z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccc" />
+ <path
+ d="m 55.49414,203 c 0.27842,0 0.50585,0.2216 0.50586,0.5 v 7 c 6.1e-4,0.4051 -0.45544,0.6427 -0.78711,0.4102 l -5,-3.5 c -0.28542,-0.199 -0.28542,-0.6214 0,-0.8204 l 5,-3.5 c 0.0826,-0.058 0.1806,-0.089 0.28125,-0.09 z m 4.507668,0 v 8 h -2 v -8 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path9208"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path9205-9"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 94.50586,623 c -0.27842,0 -0.50585,0.2216 -0.50586,0.5 v 7 c -6.1e-4,0.4051 0.45544,0.6427 0.78711,0.4102 l 5,-3.5 c 0.28542,-0.199 0.28542,-0.6214 0,-0.8204 l -5,-3.5 c -0.0826,-0.058 -0.1806,-0.089 -0.28125,-0.09 z"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ d="m 113.9992,624.50586 c 0,-0.27842 0.2216,-0.50584 0.5,-0.50586 h 7 c 0.4051,-6e-4 0.6427,0.45544 0.4102,0.78711 l -3.5,5 c -0.199,0.28542 -0.6214,0.28542 -0.8204,0 l -3.5,-5 c -0.058,-0.0826 -0.089,-0.1806 -0.09,-0.28125 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path9225"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path9227"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 141.49531,622.99926 c 0.27843,0 0.50584,0.2216 0.50587,0.5 v 7 c 5.9e-4,0.4051 -0.45545,0.6427 -0.78712,0.4102 l -5,-3.5 c -0.28541,-0.199 -0.28541,-0.6214 0,-0.8204 l 5,-3.5 c 0.0826,-0.058 0.1806,-0.089 0.28125,-0.09 z"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path9229"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 156,629.49414 c 0,0.27842 0.2216,0.50584 0.5,0.50586 h 7 c 0.4051,6e-4 0.6427,-0.45544 0.4102,-0.78711 l -3.5,-5 c -0.199,-0.28542 -0.6214,-0.28542 -0.8204,0 l -3.5,5 c -0.058,0.0826 -0.089,0.1806 -0.09,0.28125 z"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path27544-8"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 471.50586,371 c -0.27842,0 -0.50585,0.2216 -0.50586,0.5 v 7 c -6.1e-4,0.4051 0.45544,0.6427 0.78711,0.4102 l 5,-3.5 c 0.28542,-0.199 0.28542,-0.6214 0,-0.8204 l -5,-3.5 c -0.0826,-0.058 -0.1806,-0.089 -0.28125,-0.09 z M 478,371 v 8 h 2 v -8 z"
+ sodipodi:nodetypes="cccccccccccccc" />
+ <path
+ sodipodi:nodetypes="cccccccccccccc"
+ d="m 500,371.50586 c 0,-0.27842 -0.2216,-0.50585 -0.5,-0.50586 h -7 c -0.4051,-6.1e-4 -0.6427,0.45544 -0.4102,0.78711 l 3.5,5 c 0.199,0.28542 0.6214,0.28542 0.8204,0 l 3.5,-5 c 0.058,-0.0826 0.089,-0.1806 0.09,-0.28125 z M 500,378 h -8 v 2 h 8 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path9258"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path9260"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 542,379.49414 c 0,0.27842 -0.2216,0.50585 -0.5,0.50586 h -7 c -0.4051,6.1e-4 -0.6427,-0.45544 -0.4102,-0.78711 l 3.5,-5 c 0.199,-0.28542 0.6214,-0.28542 0.8204,0 l 3.5,5 c 0.058,0.0826 0.089,0.1806 0.09,0.28125 z M 542,373 h -8 v -2 h 8 z"
+ sodipodi:nodetypes="cccccccccccccc" />
+ <path
+ sodipodi:nodetypes="cccccccccccccc"
+ d="m 520.49414,371 c 0.27842,0 0.50585,0.2216 0.50586,0.5 v 7 c 6.1e-4,0.4051 -0.45544,0.6427 -0.78711,0.4102 l -5,-3.5 c -0.28542,-0.199 -0.28542,-0.6214 0,-0.8204 l 5,-3.5 c 0.0826,-0.058 0.1806,-0.089 0.28125,-0.09 z M 514,371 v 8 h -2 v -8 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path9264"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g9217">
+ <path
+ inkscape:connector-curvature="0"
+ id="path24965-8"
+ d="m 447.5,599 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 1 0 0,-1 H 448 v -9 h 9 v 7.5 a 0.50005,0.50005 0 1 0 1,0 v -8 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 9.99219,11.74219 A 0.50005,0.50005 0 0 0 457,611.25 v 1.25 a 0.50005,0.50005 0 1 0 1,0 v -1.25 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path24881-9"
+ d="m 455.5,602 c -0.58333,0 -1.08834,0.16632 -1.52734,0.45898 -0.43901,0.29267 -0.82618,0.6875 -1.32618,1.1875 l -1,1 c -0.5,0.5 -0.86283,0.85517 -1.17382,1.0625 C 450.16166,605.91632 449.91667,606 449.5,606 h -1 v 1 h 1 c 0.58333,0 1.08834,-0.16632 1.52734,-0.45898 0.43901,-0.29267 0.82618,-0.6875 1.32618,-1.1875 l 1,-1 c 0.5,-0.5 0.86283,-0.85517 1.17382,-1.0625 C 454.83834,603.08368 455.08333,603 455.5,603 h 1 v -1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.65;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ id="g9239">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 468.4999,598.99994 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3.5 h 1 v -3 h 3 v -1 z m 9.5,0 v 1 h 3 v 3 h 1 v -3.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10,10 v 3.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3.5 v -1 h -3 v -3 z m 13,0 v 3 h -3 v 1 h 3.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3.5 z"
+ id="path24895-4"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.65;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 471.4999,601.99994 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h 1 v -1 h 1 v -1 z m 2.5,0 v 1 h 2 v -1 z m 3,0 v 1 h 1 v 1 h 1 v -1.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -6,3 v 2 h 1 v -2 z m 7,0 v 2 h 1 v -2 z m -7,3 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.5 v -1 h -1 v -1 z m 7,0 v 1 h -1 v 1 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1.5 z m -4,1 v 1 h 2 v -1 z"
+ id="path24923-3"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(1223,668.01218)"
+ style="display:inline;enable-background:new"
+ id="g27937-4">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -733.49414,-90.007812 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6.501953 h 1 v -6.001953 h 6 v -1 z m 12.50195,7.001953 v 6 h -6.00195 v 1 h 6.50195 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -6.5 z"
+ id="path27667-4-6"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -724.49219,-90.007812 a 0.50005,0.50005 0 1 0 0,1 h 2.78321 l -4.13868,4.148437 a 0.50005,0.50005 0 1 0 0.70899,0.705078 l 4.14648,-4.15625 v 2.802735 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -4.01172,7.998046 a 0.50005,0.50005 0 0 0 -0.34375,0.150391 l -4.14648,4.136719 v -2.783203 a 0.50005,0.50005 0 1 0 -1,0 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -2.80274 l 4.1543,-4.144532 a 0.50005,0.50005 0 0 0 -0.36133,-0.859375 z"
+ id="path27669-6-3"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(1223,668.01218)"
+ style="display:inline;enable-background:new"
+ id="g27941-8">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -699.50391,-90.009766 a 0.50005,0.50005 0 0 0 -0.34375,0.150391 l -4.14648,4.136719 v -2.783203 a 0.50005,0.50005 0 1 0 -1,0 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -2.80274 l 4.1543,-4.144532 a 0.50005,0.50005 0 0 0 -0.36133,-0.859375 z m -11.98828,8.001954 a 0.50005,0.50005 0 1 0 0,1 h 2.78321 l -4.13868,4.148437 a 0.50005,0.50005 0 1 0 0.70899,0.705078 l 4.14648,-4.15625 v 2.802735 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path27716-4-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -710.49414,-88.007812 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4.501953 h 1 v -4.001953 h 4 v -1 z m 8.50195,5.001953 v 4 h -4.00195 v 1 h 4.50195 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4.5 z"
+ id="path27721-4-5"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ id="path10295"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 61,288 v -2.5 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 H 58 v 1 h 2 v 2 z m -13,0 v -2.5 c 2.8e-5,-0.27613 0.223869,-0.49997 0.5,-0.5 H 51 v 1 h -2 v 2 z m 13,7 v 2.5 c -2.8e-5,0.27613 -0.223869,0.49997 -0.5,0.5 H 58 v -1 h 2 v -2 z m -13,0 v 2.5 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 H 51 v -1 h -2 v -2 z"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g10303"
+ transform="matrix(-1,0,0,1,68.007122,83.99992)">
+ <g
+ transform="translate(-0.012711,-83.995405)"
+ id="g10299">
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path10297"
+ transform="matrix(-1,0,0,1,68.019833,-0.004515)"
+ d="m 36.007812,284 v 2 h -1.5 c -0.27613,3e-5 -0.499969,0.22387 -0.5,0.5 v 1.49805 l -3.988281,0.006 c -0.812117,9.2e-4 -1.516225,0.45838 -1.832031,1.12695 -0.315807,0.66858 -0.189691,1.55835 0.478516,2.22656 l 4,4 c 0.413276,0.41327 0.416416,0.77582 0.271484,1.08789 -0.144932,0.31206 -0.483162,0.5586 -0.917969,0.5586 l -4.513672,0.006 c -0.676088,-0.008 -0.674098,1.01079 0.002,1 l 4.511719,-0.006 c 0.815193,0 1.513263,-0.46717 1.824219,-1.13672 0.310955,-0.66954 0.189571,-1.55652 -0.470703,-2.2168 l -4,-4 c -0.426033,-0.42603 -0.426504,-0.78429 -0.28125,-1.0918 0.145253,-0.30751 0.489852,-0.55418 0.927734,-0.55468 L 34,288.99805 c 0.0026,2e-5 0.0052,2e-5 0.0078,0 V 290.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5 v 2 h 1 v -2 h 1.5 c 0.27613,-3e-5 0.499971,-0.22387 0.5,-0.5 V 289 h 2 v -1 h -2 v -1.5 c -2.9e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -1.5 v -2 z m -1.027343,3 h 3.027343 v 3 h -3.027343 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
</g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g25431" transform="translate(-21)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 153.5,119 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 9 v 9 h -9 z" id="rect25412" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 157,121 v 2 h 1 v -2 z m 0,3 v 1.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5 v -1 h -1 v -1 z m 3,1 v 1 h 2 v -1 z" id="rect25414" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 157.5,116 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h 1 v -1 h 8 v 8 h -1 v 1 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z" id="path25426" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="g13935-4" transform="translate(83.999996,42)">
- <path id="path13929-36" d="m 36,74 c -2.455669,0 -4.49388,1.771475 -4.916016,4.105469 0.482305,-0.09011 0.975221,-0.129499 1.470704,-0.07422 0.662841,0.07415 0.551512,1.068296 -0.111329,0.994141 -0.485685,-0.05419 -0.971969,-0.01789 -1.4375,0.101562 0.06678,2.656434 2.202258,4.79532 4.857422,4.867188 0.121572,-0.473413 0.166164,-0.965209 0.109375,-1.455079 -0.03822,-0.293198 0.18493,-0.555356 0.480469,-0.564453 0.262666,-0.0085 0.487095,0.187762 0.513672,0.449219 0.05787,0.499184 0.03624,1.001242 -0.05469,1.490234 C 39.23754,83.484981 41,81.449595 41,79 41,76.23858 38.761426,74 36,74 Z m -1.568358,4.830076 c 0.100656,9.56e-4 0.198679,0.03227 0.28125,0.08984 0.540828,0.363139 1.00483,0.82779 1.367188,1.369141 0.405708,0.559881 -0.466114,1.144515 -0.830078,0.556641 -0.289893,-0.43309 -0.661079,-0.805188 -1.09375,-1.095703 -0.420141,-0.271725 -0.224948,-0.923754 0.27539,-0.919922 z" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0" sodipodi:nodetypes="scccccccccssccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 29.484375,78.757812 a 0.50005,0.50005 0 0 0 -0.267578,0.08789 c -1.670208,1.118756 -2.507905,3.13395 -2.125,5.107422 0.382905,1.973472 1.913458,3.526488 3.880859,3.939453 1.967402,0.412965 3.994569,-0.393928 5.138672,-2.046875 a 0.50005,0.50005 0 1 0 -0.822266,-0.568359 c -0.916718,1.324431 -2.534938,1.967608 -4.111328,1.636718 -1.576389,-0.330889 -2.798664,-1.57109 -3.105468,-3.152343 -0.306805,-1.581254 0.36291,-3.18953 1.701172,-4.085938 a 0.50005,0.50005 0 0 0 -0.289063,-0.917968 z" id="path13933-5" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g25821">
- <g id="g24262-4" transform="translate(-188.99644,-1801.0029)" style="display:inline;fill:#ffffff;enable-background:new">
- <path sodipodi:nodetypes="ccccccccccccccccccccccccccccccc" inkscape:connector-curvature="0" id="rect24246-3" transform="translate(188.99644,1801.0029)" d="m 489.00391,329.99805 v 2 h 1 v -1 h 1 v -1 z m 0,4 v 2 h 1 v -2 z m 0,4 v 2 h 2 v -1 h -1 v -1 z m 9,0 v 1 h -1 v 1 h 2 v -2 z m -5,1 v 1 h 2 v -1 z" style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 493.49609,325.98633 c -0.27689,3e-5 -0.50105,0.22506 -0.5,0.50195 l 0.008,4.00586 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4.5 v 4.50195 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path24264-0" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccc"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 472.49609,325.98633 c -0.27689,3e-5 -0.50105,0.22506 -0.5,0.50195 l 0.006,3.50586 -3.49804,0.002 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 9 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 9 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3.5 h 3.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path24338-8" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccc"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g25828">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 515.49805,329.98633 c -0.27766,-0.001 -0.50302,0.22429 -0.50196,0.50195 l 0.008,5.00586 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4.99805 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path24344-9" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- <g id="g24392-5" transform="translate(-166.99644,-1801.0029)" style="display:inline;fill:#ffffff;enable-background:new">
- <path sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccaccc" inkscape:connector-curvature="0" id="rect24376-2" transform="translate(166.99644,1801.0029)" d="M 515.00391,325.99609 V 326 H 515 v 2 h 1 v -1.00391 h 1.00391 v -1 z m 4,0 v 1 h 2 v -1 z M 523,326 v 1 h 1 v 1 h 1.00391 v -2.00391 z m 1.00391,3.99609 v 2 h 1 v -2 z m -13,0.002 v 2 h 1 v -1 h 1 v -1 z m 13,3.99804 v 1 h -1 v 1 h 2 v -2 z m -13,0.002 v 2 h 1 v -2 z m 0,4 v 2 h 2 v -1 h -1 v -1 z m 9,0 v 1 h -1 v 1 h 2 v -2 z m -5,1 v 1 h 2 v -1 z" style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"/>
- </g>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 535.49609,325.98633 c -0.27689,3e-5 -0.50105,0.22506 -0.5,0.50195 l 0.008,3.00781 c 10e-4,0.27537 0.22463,0.49802 0.5,0.49805 h 5.5 v 5.50195 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -4,4.0039 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 9 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 l 9.00782,0.01 c 0.27689,-3e-5 0.50105,-0.22506 0.5,-0.50195 l -0.008,-3.00586 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -5.5 v -5.50196 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path24415-7" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccc"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g25815">
- <g transform="translate(-230.99644,-1801.0029)" id="g24435-3" style="display:inline;fill:#ffffff;enable-background:new">
- <path sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccacccaccccc" inkscape:connector-curvature="0" id="rect24419-6" transform="translate(230.99644,1801.0029)" d="m 447.00391,325.99805 v 2 h 1 v -1 h 1 v -1 z m 4,0 v 1 h 2 v -1 z m 4,0 v 1 h 2 v -1 z m 4,0 v 1 h 1 v 1 h 1 v -2 z m -12,4 v 2 h 1 v -2 z m 13,0 v 2 h 1 v -2 z m -13,4 v 2 h 1 v -2 z m 13,0 v 2 h 1 v -2 z m -13,4 v 2 h 2 v -1 h -1 v -1 z m 13,0 v 1 h -1 v 1 h 2 v -2 z m -9,1 v 1 h 2 v -1 z m 4,0 v 1 h 2 v -1 z" style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"/>
- </g>
- </g>
- <g transform="translate(876,-1690)" style="display:inline;fill:#ffffff;enable-background:new" id="g24686-1" inkscape:export-filename="C:\Users\Andrzej Ambroż\Dysk Google\PROJEKTY BIEŻĄCE - Andrzej\BLENDER 2.8 ICONS redesign\MOCKUPS\gizmo icon_1.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m -419.5,1827 a 0.50005,0.50005 0 1 0 0,1 h 2.79492 l -2.96875,2.9688 c 0.24471,0.2267 0.48032,0.4623 0.70703,0.707 L -416,1828.709 v 2.791 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -2.98438,6.7793 -3.50585,3.5059 C -426.28828,1837.1081 -426.63057,1837 -427,1837 c -1.09865,0 -2,0.9013 -2,2 0,1.0986 0.90135,2 2,2 1.09865,0 2,-0.9014 2,-2 0,-0.3677 -0.10771,-0.7107 -0.2832,-1.0078 l 3.50586,-3.5059 c -0.22252,-0.2491 -0.45807,-0.4843 -0.70704,-0.707 z M -427,1838 c 0.55821,0 1,0.4417 1,1 0,0.5582 -0.44179,1 -1,1 -0.55821,0 -1,-0.4418 -1,-1 0,-0.5583 0.44179,-1 1,-1 z" id="path24506-4" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m -428.49556,1829 a 0.4997692,0.49966962 0 1 0 0,0.9993 c 5.80308,0 10.49606,4.6921 10.49606,10.494 a 0.4997692,0.49966962 0 1 0 0.99944,0 c 0,-6.3418 -5.1523,-11.4933 -11.4955,-11.4933 z" id="ellipse24510-0" inkscape:connector-curvature="0"/>
- </g>
- <path id="path22885-3-7" d="m 537.4922,557 c -0.1299,0 -0.2539,0.055 -0.3457,0.1465 -1.4018,1.4018 -2.9571,1.8535 -5.6465,1.8535 -0.2761,0 -0.5,0.2239 -0.5,0.5 v 3 c 0,2.4627 0.6805,4.0682 1.7871,5.2754 1.1066,1.2072 2.5736,2.0242 4.1777,3.1348 0.084,0.058 0.1832,0.09 0.2852,0.09 h 0.5 c 0.102,-2e-4 0.2015,-0.032 0.2852,-0.09 1.6041,-1.1106 3.0711,-1.9276 4.1777,-3.1348 C 543.3195,566.5682 544,564.9627 544,562.5 v -3 c 0,-0.2761 -0.2239,-0.5 -0.5,-0.5 -2.6894,0 -4.2447,-0.4517 -5.6465,-1.8535 -0.096,-0.096 -0.226,-0.1486 -0.3613,-0.1465 z m 3.4766,3.9902 a 1.0001,1.0001 0 0 1 0.8124,1.6348 l -4,5 a 1.0001,1.0001 0 0 1 -1.4882,0.082 l -2,-2 a 1.0001,1.0001 0 1 1 1.414,-1.414 l 1.209,1.209 3.3028,-4.127 a 1.0001,1.0001 0 0 1 0.75,-0.3848 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 516.49219,557 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 C 514.74469,558.54828 513.18939,559 510.5,559 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 c 0,2.46272 0.6805,4.06818 1.78711,5.27539 1.10661,1.20722 2.57356,2.02419 4.17773,3.13477 A 0.50005,0.50005 0 0 0 516.25,571 h 0.5 a 0.50005,0.50005 0 0 0 0.28516,-0.0898 c 1.60417,-1.11058 3.07112,-1.92755 4.17773,-3.13477 C 522.3195,566.56818 523,564.96272 523,562.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 c -2.68939,0 -4.24469,-0.45172 -5.64648,-1.85352 A 0.50005,0.50005 0 0 0 516.49219,557 Z m 0.008,1.07031 c 1.42533,1.26825 3.16641,1.79779 5.5,1.86524 V 562.5 c 0,2.28728 -0.5695,3.55682 -1.52539,4.59961 -0.92707,1.01135 -2.30655,1.81425 -3.88867,2.90039 h -0.17188 c -1.58212,-1.08614 -2.9616,-1.88904 -3.88867,-2.90039 C 511.5695,566.05682 511,564.78728 511,562.5 v -2.56445 c 2.33359,-0.0675 4.07467,-0.59699 5.5,-1.86524 z" id="path22877-22-0" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" d="m 511.99933,414.00018 h 9 v 5 h -9 z m -1.5,-2 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 8 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5.5 v 1 h -2.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 6 c 0.6573,-0.009 0.6573,-0.9907 0,-1 h -2.5 v -1 h 5.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -8 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 11 v 7 h -11 z" style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" id="rect22324-2"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 489.5,412 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 8 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5.5 v 1 h -2.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 6 c 0.6573,-0.009 0.6573,-0.9907 0,-1 H 496 v -1 h 5.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -8 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 11 v 7 h -11 z" id="path22338-8" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccc"/>
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g25476" transform="translate(-20)">
- <g style="display:inline;fill:#ffffff;enable-background:new" id="g25445" transform="translate(-218,-111)">
- <path sodipodi:nodetypes="ssssccccccccssssccs" inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 301.5,305 c -0.82235,0 -1.5,0.67765 -1.5,1.5 v 5 c 0,0.82235 1,1.5 1.5,1.5 h 0.5 v -3 h -0.5 c -0.67616,0.01 -0.67616,-1.01 0,-1 h 11 c 0.67616,-0.01 0.67616,1.01 0,1 H 312 v 3 h 0.5 c 0.82235,0 1.5,-0.67765 1.5,-1.5 v -5 c 0,-0.82235 -0.67765,-1.5 -1.5,-1.5 H 312 302 Z" transform="translate(70,363)" id="path25441"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 135,562 v 8.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 562 Z m 6,2 c 0.54636,0 1,0.45364 1,1 0,0.54636 -0.45364,1 -1,1 -0.54636,0 -1,-0.45364 -1,-1 0,-0.54636 0.45364,-1 1,-1 z m -2.50781,2 c 0.16994,-0.003 0.32953,0.0812 0.42383,0.22266 l 2,3 c 0.22142,0.33228 -0.0167,0.77726 -0.41602,0.77734 h -4 c -0.39932,-8e-5 -0.63744,-0.44506 -0.41602,-0.77734 l 2,-3 c 0.0912,-0.13686 0.24381,-0.21966 0.40821,-0.22266 z" transform="translate(238,111)" id="path25443" inkscape:connector-curvature="0"/>
- </g>
- </g>
- <path sodipodi:nodetypes="ccccccscsccccccccccccccccccccccccccccccccc" inkscape:connector-curvature="0" id="path5256" d="m 197.50977,409.99414 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5039 c 0.0205,0.58311 0.0403,1.03618 -0.0488,1.24805 -0.22838,0.54301 -0.5609,0.82668 -1.00781,1.10937 -0.44691,0.28269 -1.00733,0.53131 -1.53711,0.97461 -0.52977,0.4433 -1.00108,1.10059 -1.22656,2.08789 -0.22548,0.9873 -0.2332,2.29903 0.0625,4.16406 0.0385,0.24311 0.24801,0.42203 0.49414,0.42188 h 8.75586 c 0.30739,1.4e-4 0.54213,-0.2745 0.49414,-0.57812 -0.36883,-2.32606 -0.21493,-3.6368 0.12305,-4.40821 0.33798,-0.7714 0.85304,-1.08606 1.49804,-1.45508 0.645,-0.36901 1.43565,-0.7809 1.90821,-1.70703 0.47255,-0.92613 0.59571,-2.25921 0.21289,-4.4375 C 208.70043,411.17484 208.49284,411.0002 208.25,411 h -7.24023 v -0.50586 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m 3,1.00586 h 6.78125 c 0.25456,1.74951 0.14487,2.81594 -0.15235,3.39844 -0.3247,0.63637 -0.84774,0.91198 -1.51367,1.29297 -0.66593,0.38098 -1.46183,0.87882 -1.91797,1.91992 -0.41222,0.94085 -0.49675,2.35477 -0.23633,4.38867 h -7.73437 c -0.19264,-1.47462 -0.23076,-2.65205 -0.0684,-3.36328 0.18281,-0.80045 0.49635,-1.21142 0.89258,-1.54297 0.39622,-0.33155 0.90291,-0.56523 1.42968,-0.89844 0.52678,-0.33321 1.07351,-0.7985 1.39649,-1.5664 0.22021,-0.52359 0.17686,-1.05487 0.13867,-1.63477 h 0.48438 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path inkscape:connector-curvature="0" id="path5262" d="m 180.5,410 c -2.08712,0 -3.47816,1.04607 -4.39062,2.1875 a 0.50024408,0.50024408 0 0 0 0.78125,0.625 C 177.69049,411.81193 178.73439,411 180.5,411 c 2.09839,0 3.13411,0.87695 3.75195,1.94531 C 184.8698,414.01367 185,415.31651 185,416 h -5.25 c -1.27344,0 -2.44324,0.36418 -3.31445,1.05469 -0.87121,0.69051 -1.42774,1.72791 -1.42774,2.94531 0,1.2174 0.55653,2.2548 1.42774,2.94531 C 177.30676,423.63582 178.47656,424 179.75,424 h 0.75 c 1.75558,0 3.38771,-0.96684 4.53711,-2.0332 0.0781,0.53303 0.28951,1.00434 0.64062,1.35547 C 186.12862,423.77315 186.775,424 187.5,424 a 0.50005,0.50005 0 1 0 0,-1 c -0.525,0 -0.87862,-0.14815 -1.11523,-0.38477 C 186.14815,422.37862 186,422.025 186,421.5 V 416 c 0,-0.79721 -0.12242,-2.24322 -0.88086,-3.55469 C 184.3607,411.13385 182.89646,410 180.5,410 Z m -0.75,7 H 185 v 3.56055 C 184.04582,421.68473 182.18875,423 180.5,423 h -0.75 c -1.08101,0 -2.03187,-0.31555 -2.69336,-0.83984 -0.66149,-0.52429 -1.04883,-1.23676 -1.04883,-2.16016 0,-0.9234 0.38734,-1.63587 1.04883,-2.16016 C 177.71813,417.31555 178.66899,417 179.75,417 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" transform="translate(-105,-20.999997)" id="g24881" style="display:inline;fill:#ffffff;enable-background:new">
- <path inkscape:connector-curvature="0" id="path24877" d="m 183.8125,200.01562 c 2.21359,0.18235 3.97803,1.94071 4.16992,4.1543 0.19189,2.2136 -1.24344,4.25155 -3.39258,4.8125 a 0.5007349,0.5007349 0 1 1 -0.2539,-0.96875 c 1.68376,-0.43948 2.80079,-2.02289 2.65039,-3.75781 -0.1504,-1.73492 -1.52164,-3.10129 -3.25586,-3.24414 -1.73423,-0.14285 -3.31219,0.98104 -3.74414,2.66797 a 0.50005,0.50005 0 1 1 -0.96875,-0.24805 c 0.55114,-2.15241 2.58133,-3.59836 4.79492,-3.41602 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <g id="g24891" transform="matrix(-1,0,0,1,356.9996,0)" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" d="M 176.99634,212.50183 A 1.4981741,1.4981725 0 0 1 175.49817,214 a 1.4981741,1.4981725 0 0 1 -1.49818,-1.49817 1.4981741,1.4981725 0 0 1 1.49818,-1.49817 1.4981741,1.4981725 0 0 1 1.49817,1.49817 z m 2.39233,-7.41199 c 0.85602,0.17256 1.66292,0.59211 2.30469,1.23828 1.28353,1.29236 1.66074,3.23682 0.95508,4.91602 -0.70566,1.6792 -2.35829,2.76833 -4.17969,2.75586 a 0.50005,0.50005 0 1 1 0.008,-1 c 1.41921,0.01 2.70016,-0.83611 3.25,-2.14453 0.54985,-1.30842 0.25598,-2.81527 -0.74414,-3.82227 -1.00012,-1.00699 -2.50427,-1.31041 -3.8164,-0.76953 C 175.85388,206.80455 175,208.08075 175,209.5 a 0.50005,0.50005 0 1 1 -1,0 c 0,-1.82144 1.10118,-3.466 2.78516,-4.16016 0.84199,-0.34708 1.7475,-0.42255 2.60351,-0.25 z" style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" id="ellipse24887"/>
- </g>
- </g>
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 490,307 c -0.55226,6e-5 -0.99994,0.44774 -1,1 v 8 c 6e-5,0.55226 0.44774,0.99994 1,1 h 12 c 0.55226,-6e-5 0.99994,-0.44774 1,-1 v -8 c -6e-5,-0.55226 -0.44774,-0.99994 -1,-1 z m 6,1 a 4,4 0 0 1 4,4 4,4 0 0 1 -4,4 4,4 0 0 1 -4,-4 4,4 0 0 1 4,-4 z" id="path25011-0"/>
- <g transform="translate(1055,731)" style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" id="g25234-0">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m -580,-424 c -2.7555,0 -5,2.2445 -5,5 0,2.7555 2.2445,5 5,5 2.7555,0 5,-2.2445 5,-5 0,-2.7555 -2.2445,-5 -5,-5 z m 0,1 c 2.21506,0 4,1.78494 4,4 0,2.21506 -1.78494,4 -4,4 -2.21506,0 -4,-1.78494 -4,-4 0,-2.21506 1.78494,-4 4,-4 z m -0.52148,1 a 0.50005,0.50005 0 0 0 -0.084,0.0117 c -1.2099,0.24373 -2.15796,1.187 -2.38476,2.38867 a 0.50005,0.50005 0 1 0 0.98242,0.18555 c 0.15048,-0.79727 0.77874,-1.42839 1.59961,-1.59375 A 0.50005,0.50005 0 0 0 -580.52148,-422 Z" id="path25232-0" inkscape:connector-curvature="0"/>
- </g>
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 542.77344,306 a 1.0001,1.0001 0 0 0 -0.41211,0.0781 l -4.74024,2 a 1.0004654,1.0004654 0 1 0 0.77735,1.84376 l 1.54883,-0.65235 -2.69532,5.375 -2.78906,-2.30078 a 1.50015,1.50015 0 1 0 -1.9082,2.3125 l 4.24023,3.5 a 1.50015,1.50015 0 0 0 2.29688,-0.48437 l 3.53711,-7.0586 0.41015,1.63086 a 1.0001,1.0001 0 1 0 1.93946,-0.48828 l -1.25977,-5 A 1.0001,1.0001 0 0 0 542.77344,306 Z" id="path25427-8"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 521.51367,306 a 0.50005,0.50005 0 0 0 -0.23633,0.0527 l -4,2 a 0.50005,0.50005 0 1 0 0.44532,0.89454 l 2.8164,-1.40821 -4.20508,8.1875 -4.52148,-3.61718 a 0.50024018,0.50024018 0 1 0 -0.625,0.78124 l 5,4 a 0.50005,0.50005 0 0 0 0.75781,-0.1621 l 4.4375,-8.64063 0.63281,2.5332 a 0.50005,0.50005 0 1 0 0.96876,-0.24218 l -1,-4 A 0.50005,0.50005 0 0 0 521.51367,306 Z" id="path25488-0" inkscape:connector-curvature="0"/>
- <g id="g5381" style="fill:#ffffff">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.03999233px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 329.97518,350.98014 a 0.52004817,0.52004817 0 0 0 -0.38086,0.19532 l -3.61133,4.51562 -3.09179,-3.5332 a 0.52004817,0.52004817 0 1 0 -0.78321,0.68359 l 3.5,4 a 0.52004817,0.52004817 0 0 0 0.79883,-0.0176 l 3.61133,-4.51367 3.08984,3.53125 a 0.52004817,0.52004817 0 1 0 0.78321,-0.68359 l -3.5,-4 a 0.52004817,0.52004817 0 0 0 -0.41602,-0.17774 z" id="path4898" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.03999233px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 321.49219,347.97266 A 0.52004817,0.52004817 0 0 0 320.97852,348.5 v 11 a 0.520505,0.520505 0 0 0 1.04101,0 V 358 h 11.95899 v 1.5 a 0.520505,0.520505 0 0 0 1.04101,0 v -11 a 0.52004817,0.52004817 0 0 0 -0.52734,-0.52734 0.52004817,0.52004817 0 0 0 -0.51367,0.52734 v 1.5 h -11.95899 v -1.5 a 0.52004817,0.52004817 0 0 0 -0.52734,-0.52734 z M 322.01953,351 h 11.95899 v 6 h -11.95899 z" id="path4902"/>
- </g>
- <g transform="translate(166.89495,43.00791)" id="g9160-3" style="display:inline;fill:#ffffff;enable-background:new"/>
- <g id="g5375" style="fill:#ffffff">
- <path inkscape:connector-curvature="0" id="path9106-6-2" d="m 346.49261,354.99229 a 0.50005,0.50005 0 0 0 -0.49219,0.50781 v 3 c 0,0.725 0.22685,1.37138 0.67773,1.82226 0.45089,0.45089 1.09727,0.67774 1.82227,0.67774 0.725,0 1.37138,-0.22685 1.82226,-0.67774 0.45089,-0.45088 0.67774,-1.09726 0.67774,-1.82226 v -3 a 0.50005,0.50005 0 1 0 -1,0 v 3 c 0,0.525 -0.14815,0.87862 -0.38477,1.11523 -0.23661,0.23661 -0.59023,0.38477 -1.11523,0.38477 -0.525,0 -0.87862,-0.14816 -1.11524,-0.38477 -0.23661,-0.23661 -0.38476,-0.59023 -0.38476,-1.11523 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path d="m 348.49261,349.99229 a 0.50005,0.50005 0 0 0 -0.49219,0.50781 v 6 a 0.50005,0.50005 0 1 0 1,0 v -6 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -5.99219,-2.99219 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 1.75 c 0,0.97222 0.53688,1.82801 1.27539,2.19726 a 0.50005635,0.50005635 0 1 0 0.44726,-0.89453 c -0.26148,-0.13074 -0.72265,-0.77495 -0.72265,-1.30273 v -1.75 h 5 v 1.75 c 0,0.52778 -0.46312,1.17199 -0.72461,1.30273 a 0.50005635,0.50005635 0 1 0 0.44726,0.89453 c 0.73852,-0.36925 1.27735,-1.22504 1.27735,-2.19726 v -1.75 h 2.5 a 0.50005,0.50005 0 1 0 0,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" id="path9108-6-6" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(-40.999997,-42)" id="g25194-8-8" style="display:inline;fill:#ffffff;enable-background:new">
- <circle cx="221" cy="285" id="circle25190-1-7" style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" r="0"/>
- <path id="circle25383" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 221,284 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m 3,0 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m 3,1 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m -5.67188,2.04688 c -0.72617,0.0892 -1.40636,0.31348 -2.02343,0.63867 -1.23415,0.65038 -2.22638,1.68758 -2.94922,2.84375 -0.72284,1.15617 -1.1805,2.43169 -1.32227,3.60742 -0.14176,1.17573 0.0178,2.28295 0.6875,3.0293 0.68189,0.75993 1.69067,0.98063 2.61328,0.6914 C 219.35231,297.53818 220,296.54997 220,295.5 c 0,-0.87561 0.22937,-1.10992 0.64258,-1.29297 C 221.05579,294.02398 221.75437,294 222.5,294 c 0.79276,0 1.56488,-0.14919 2.20703,-0.5332 0.52292,-0.31271 0.89501,-0.8382 1.11524,-1.4668 h 1.13281 a 0.50004994,0.50004994 0 0 0 0.002,0 c 1.02746,0 1.90966,-0.75672 2.0293,-1.76953 0.11964,-1.01284 -0.5686,-1.95303 -1.57031,-2.17969 -0.73109,-0.16542 -1.38414,0.17264 -1.8711,0.68945 -0.49389,-0.69239 -1.0864,-1.29918 -1.91601,-1.52148 -0.80279,-0.21511 -1.57461,-0.26104 -2.30079,-0.17187 z m 0.11915,0.98632 c 0.59872,-0.0738 1.23897,-0.0331 1.92382,0.15039 0.66836,0.17909 1.23082,0.75735 1.69727,1.56446 a 0.50004994,0.50004994 0 0 0 0.90234,-0.0781 c 0.17721,-0.4818 0.69836,-0.76361 1.22461,-0.64453 0.52625,0.11908 0.85819,0.58537 0.79883,1.08789 C 227.93478,290.61583 227.49838,291 226.95703,291 H 225.5 a 0.50004994,0.50004994 0 0 0 -0.49219,0.41406 c -0.10308,0.5846 -0.38181,0.93776 -0.8125,1.19532 C 223.76463,292.86693 223.16312,293 222.5,293 c -0.74508,0 -1.54761,-0.0253 -2.26172,0.29102 C 219.52417,293.60735 219,294.37315 219,295.5 c 0,0.63163 -0.40649,1.2273 -0.96484,1.40234 -0.62221,0.19506 -1.12911,0.0874 -1.57032,-0.40429 -0.37675,-0.41988 -0.55858,-1.23603 -0.4375,-2.24024 0.12109,-1.00421 0.53101,-2.16478 1.17774,-3.19922 0.64673,-1.03443 1.52684,-1.94044 2.5664,-2.48828 0.51979,-0.27392 1.07706,-0.46333 1.67579,-0.53711 z" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 90.494141,178.99609 a 0.50005,0.50005 0 0 0 -0.347657,0.85743 l 3,3 C 92.440854,183.71574 91.999993,184.80241 92,186 c 2e-5,1.19757 0.440853,2.28425 1.146484,3.14648 l -3,3 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 3,-3 C 94.715742,190.55915 95.802428,191 97,191 c 1.197573,0 2.284258,-0.44085 3.14648,-1.14648 l 3,3 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -3,-3 C 101.55915,188.28425 101.99998,187.19757 102,186 c 0,-1.19759 -0.44086,-2.28426 -1.14648,-3.14648 l 3,-3 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3,3 C 99.284255,181.44086 98.197592,181 97,181 c -1.19759,0 -2.284254,0.44086 -3.146484,1.14648 l -3,-3 a 0.50005,0.50005 0 0 0 -0.359375,-0.15039 z M 97,182 c 2.21506,0 4.00001,1.78494 4,4 -4e-5,2.21502 -1.784977,4 -4,4 -2.215019,0 -3.999963,-1.78498 -4,-4 -1.2e-5,-2.21506 1.784946,-4 4,-4 z" id="path25165" inkscape:connector-curvature="0"/>
- <g id="g10845">
- <path inkscape:connector-curvature="0" d="m 473,628 a 1.0001,1.0001 0 1 0 0,2 h 2 a 1.0001,1.0001 0 1 0 0,-2 z m -4.5,-6 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.5 v 7.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 a 0.50005,0.50005 0 1 0 -1,0 v 4.5 h -8 v -7 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 H 469 v -2 h 4.5 a 0.50005,0.50005 0 1 0 0,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" id="path24739-4"/>
- <path sodipodi:nodetypes="sssssccccccccccccc" inkscape:connector-curvature="0" id="path27428" d="m 478.50003,620.0003 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"/>
- </g>
- <g style="display:inline;enable-background:new" id="g27418" transform="translate(83.999997,-84)">
- <path style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" d="m 352.50003,305.0003 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z" id="path27589" inkscape:connector-curvature="0" sodipodi:nodetypes="sssssccccccccccccc"/>
- <g id="g27675-2" transform="rotate(90,232.49897,657.49643)" style="display:inline;opacity:0.7;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m -109.99609,533.99609 -0.004,7.11133 c -1.67885,0.25428 -2.99414,1.64686 -2.99414,3.39453 0,1.92568 1.57041,3.49805 3.49609,3.49805 1.92569,0 3.49805,-1.57236 3.49805,-3.49805 0,-1.74925 -1.31894,-3.14219 -3,-3.39453 l 0.004,-7.11133 z m 0.49804,8.00977 c 1.38524,0 2.49805,1.11085 2.49805,2.49609 0,1.38525 -1.1128,2.49805 -2.49805,2.49805 -1.38524,0 -2.49609,-1.11281 -2.49609,-2.49805 0,-1.38523 1.11086,-2.49609 2.49609,-2.49609 z" id="path27671-7" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m -108.5,534 v 3 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path27673-7" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccc"/>
- </g>
- </g>
- <g style="display:inline;enable-background:new" id="g27444" transform="translate(-18.000003,-64)">
- <g id="g27675" transform="rotate(90,282.99897,687.99643)" style="opacity:0.7">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m -109.99609,533.99609 -0.004,7.11133 c -1.67885,0.25428 -2.99414,1.64686 -2.99414,3.39453 0,1.92568 1.57041,3.49805 3.49609,3.49805 1.92569,0 3.49805,-1.57236 3.49805,-3.49805 0,-1.74925 -1.31894,-3.14219 -3,-3.39453 l 0.004,-7.11133 z m 0.49804,8.00977 c 1.38524,0 2.49805,1.11085 2.49805,2.49609 0,1.38525 -1.1128,2.49805 -2.49805,2.49805 -1.38524,0 -2.49609,-1.11281 -2.49609,-2.49805 0,-1.38523 1.11086,-2.49609 2.49609,-2.49609 z" id="path27671" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m -108.5,534 v 3 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path27673" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccc"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 430.49414,284.99414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 2.64649,2.64648 -2.64649,2.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2.64648,-2.64649 2.64648,2.64649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -2.64649,-2.64648 2.64649,-2.64648 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 l -2.64648,2.64649 -2.64648,-2.64649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z" id="path27679" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(4.7134341e-6,4.7134317e-6)" style="display:inline;enable-background:new" id="g27915">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 180.5,263 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5 v 0.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5 v 1.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -7 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 6 v 6 h -2 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 183 v -0.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 181 Z" id="path27886" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 176.50781,262.99414 a 0.50005,0.50005 0 0 0 -0.45508,0.72852 l 1,2 a 0.50005,0.50005 0 1 0 0.89454,-0.44532 l -1,-2 a 0.50005,0.50005 0 0 0 -0.43946,-0.2832 z m -2.02539,3.00195 a 0.50005,0.50005 0 0 0 -0.20508,0.95118 l 2,1 a 0.50005,0.50005 0 1 0 0.44532,-0.89454 l -2,-1 a 0.50005,0.50005 0 0 0 -0.24024,-0.0566 z m 11,6 a 0.50005,0.50005 0 0 0 -0.20508,0.95118 l 2,1 a 0.50005,0.50005 0 1 0 0.44532,-0.89454 l -2,-1 a 0.50005,0.50005 0 0 0 -0.24024,-0.0566 z m -0.97461,1.99805 a 0.50005,0.50005 0 0 0 -0.45508,0.72852 l 1,2 a 0.50005,0.50005 0 1 0 0.89454,-0.44532 l -1,-2 a 0.50005,0.50005 0 0 0 -0.43946,-0.2832 z" id="path27898" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 174.5,269 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 7 a 0.50005,0.50005 0 0 0 0.5,0.5 h 7 a 0.50005,0.50005 0 0 0 0.5,-0.5 l -0.008,-4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -1.5 v -1.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -1.4961 L 178,269.50391 A 0.50005,0.50005 0 0 0 177.5,269 Z m 0.5,1 h 1.99609 l -0.004,0.49609 a 0.50005,0.50005 0 0 0 0.5,0.50391 h 1.5 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.5 l 0.008,3 h -6 z" id="path10946" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;enable-background:new" id="g27501-8" transform="translate(-20.999927,104.99988)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.85;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 346.54688,478.16016 a 0.50005,0.50005 0 0 0 -0.18165,0.0293 c -1.54898,0.53108 -2.52602,2.0719 -2.34375,3.69922 0.18228,1.62732 1.47542,2.91657 3.10352,3.0918 1.6281,0.17523 3.16703,-0.80811 3.69141,-2.35938 a 0.50005,0.50005 0 1 0 -0.94727,-0.32031 c -0.37611,1.11265 -1.46896,1.81123 -2.63672,1.68555 -1.16775,-0.12568 -2.08606,-1.04179 -2.2168,-2.20899 -0.13073,-1.1672 0.56282,-2.26166 1.67383,-2.64257 a 0.50005,0.50005 0 0 0 -0.14257,-0.97461 z" id="path27478-1" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 346.52148,476.09375 a 0.50004994,0.50004994 0 0 0 -0.0859,0.01 c -2.69151,0.53044 -4.58334,2.97414 -4.42578,5.71289 0.15755,2.73875 2.31815,4.94772 5.05273,5.16601 2.73458,0.21829 5.21856,-1.61975 5.80859,-4.29883 a 0.50004994,0.50004994 0 1 0 -0.97656,-0.21484 c -0.48423,2.19868 -2.50772,3.69672 -4.75195,3.51758 -2.24424,-0.17915 -4.00546,-1.98086 -4.13477,-4.22852 -0.1293,-2.24766 1.41221,-4.2385 3.6211,-4.67383 a 0.50004994,0.50004994 0 0 0 -0.10743,-0.99023 z" id="circle27480-1" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 353.49219,473 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -5,5 c -0.0938,0.0938 -0.14646,0.22092 -0.14648,0.35352 v 1.79297 l -0.85352,0.85351 c -0.49023,0.47127 0.23577,1.19727 0.70704,0.70704 L 348.70703,481 H 350.5 c 0.1326,-2e-5 0.25976,-0.0527 0.35352,-0.14648 l 5,-5 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -2,-2 c -0.0957,-0.0957 -0.22603,-0.14855 -0.36133,-0.14648 z" id="path27485-1" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccc"/>
- </g>
- <path sodipodi:nodetypes="cccccccc" inkscape:connector-curvature="0" id="path27639" d="m 29.959614,221.99997 c -0.53618,0.022 -0.95938,0.4634 -0.95898,1 v 10 c 7.2e-4,0.7847 0.8635,1.2629 1.5293,0.8477 l 8,-5 c 0.625909,-0.3918 0.625909,-1.3036 0,-1.6954 l -8,-5 c -0.17045,-0.107 -0.36922,-0.1601 -0.57032,-0.1523 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 185.04038,221.99997 c 0.53618,0.022 0.95938,0.4634 0.95898,1 v 10 c -7.2e-4,0.7847 -0.8635,1.2629 -1.5293,0.8477 l -8,-5 c -0.62591,-0.3918 -0.62591,-1.3036 0,-1.6954 l 8,-5 c 0.17045,-0.107 0.36922,-0.1601 0.57032,-0.1523 z" id="path9268" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccc"/>
- <path inkscape:connector-curvature="0" id="path27528" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 132.5104,224 c -0.27994,-0.01 -0.50979,0.22 -0.50977,0.5 v 7 c -0.001,0.4307 0.5065,0.6613 0.83008,0.377 l 4,-3.5 c 0.22872,-0.1993 0.22872,-0.5547 0,-0.754 l -4,-3.5 c -0.0889,-0.078 -0.20238,-0.1211 -0.32031,-0.123 z m 9.96289,-1 c -0.13302,0.01 -0.25746,0.068 -0.34571,0.168 l -4,4.5 c -0.16816,0.1894 -0.16816,0.4746 0,0.664 l 4,4.5 c 0.19883,0.2227 0.54727,0.2227 0.7461,0 l 4,-4.5 c 0.16816,-0.1894 0.16816,-0.4746 0,-0.664 l -4,-4.5 c -0.10092,-0.114 -0.24831,-0.1759 -0.40039,-0.168 z"/>
- <path inkscape:connector-curvature="0" id="path27544" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 51.506493,224 c -0.27842,0 -0.50585,0.2216 -0.50586,0.5 v 7 c -6.1e-4,0.4051 0.45544,0.6427 0.78711,0.4102 l 5,-3.5 c 0.28542,-0.199 0.28542,-0.6214 0,-0.8204 l -5,-3.5 c -0.0826,-0.058 -0.1806,-0.089 -0.28125,-0.09 z m 6.49414,-1 v 10 h 2 v -10 z"/>
- <path d="m 124.49003,224 c 0.27994,-0.01 0.50979,0.22 0.50977,0.5 v 7 c 0.001,0.4307 -0.5065,0.6613 -0.83008,0.377 l -4,-3.5 c -0.22872,-0.1993 -0.22872,-0.5547 0,-0.754 l 4,-3.5 c 0.0889,-0.078 0.20238,-0.1211 0.32031,-0.123 z m -9.96289,-1 c 0.13302,0.01 0.25746,0.068 0.34571,0.168 l 4,4.5 c 0.16816,0.1894 0.16816,0.4746 0,0.664 l -4,4.5 c -0.19883,0.2227 -0.54727,0.2227 -0.7461,0 l -4,-4.5 c -0.16816,-0.1894 -0.16816,-0.4746 0,-0.664 l 4,-4.5 c 0.10092,-0.114 0.24831,-0.1759 0.40039,-0.168 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" id="path9201" inkscape:connector-curvature="0"/>
- <path d="m 79.49414,224 c 0.27842,0 0.50585,0.2216 0.50586,0.5 v 7 c 6.1e-4,0.4051 -0.45544,0.6427 -0.78711,0.4102 l -5,-3.5 c -0.28542,-0.199 -0.28542,-0.6214 0,-0.8204 l 5,-3.5 c 0.0826,-0.058 0.1806,-0.089 0.28125,-0.09 z M 73,223 v 10 h -2 v -10 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" id="path9203" inkscape:connector-curvature="0"/>
- <path id="path9205" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 75.50586,203 c -0.27842,0 -0.50585,0.2216 -0.50586,0.5 v 7 c -6.1e-4,0.4051 0.45544,0.6427 0.78711,0.4102 l 5,-3.5 c 0.28542,-0.199 0.28542,-0.6214 0,-0.8204 l -5,-3.5 c -0.0826,-0.058 -0.1806,-0.089 -0.28125,-0.09 z M 71,203 v 8 h 2 v -8 z" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccc"/>
- <path d="m 55.49414,203 c 0.27842,0 0.50585,0.2216 0.50586,0.5 v 7 c 6.1e-4,0.4051 -0.45544,0.6427 -0.78711,0.4102 l -5,-3.5 c -0.28542,-0.199 -0.28542,-0.6214 0,-0.8204 l 5,-3.5 c 0.0826,-0.058 0.1806,-0.089 0.28125,-0.09 z m 4.507668,0 v 8 h -2 v -8 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" id="path9208" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccc"/>
- <path inkscape:connector-curvature="0" id="path9205-9" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 94.50586,623 c -0.27842,0 -0.50585,0.2216 -0.50586,0.5 v 7 c -6.1e-4,0.4051 0.45544,0.6427 0.78711,0.4102 l 5,-3.5 c 0.28542,-0.199 0.28542,-0.6214 0,-0.8204 l -5,-3.5 c -0.0826,-0.058 -0.1806,-0.089 -0.28125,-0.09 z" sodipodi:nodetypes="ccccccccc"/>
- <path sodipodi:nodetypes="ccccccccc" d="m 113.9992,624.50586 c 0,-0.27842 0.2216,-0.50584 0.5,-0.50586 h 7 c 0.4051,-6e-4 0.6427,0.45544 0.4102,0.78711 l -3.5,5 c -0.199,0.28542 -0.6214,0.28542 -0.8204,0 l -3.5,-5 c -0.058,-0.0826 -0.089,-0.1806 -0.09,-0.28125 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" id="path9225" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" id="path9227" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 141.49531,622.99926 c 0.27843,0 0.50584,0.2216 0.50587,0.5 v 7 c 5.9e-4,0.4051 -0.45545,0.6427 -0.78712,0.4102 l -5,-3.5 c -0.28541,-0.199 -0.28541,-0.6214 0,-0.8204 l 5,-3.5 c 0.0826,-0.058 0.1806,-0.089 0.28125,-0.09 z" sodipodi:nodetypes="ccccccccc"/>
- <path inkscape:connector-curvature="0" id="path9229" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 156,629.49414 c 0,0.27842 0.2216,0.50584 0.5,0.50586 h 7 c 0.4051,6e-4 0.6427,-0.45544 0.4102,-0.78711 l -3.5,-5 c -0.199,-0.28542 -0.6214,-0.28542 -0.8204,0 l -3.5,5 c -0.058,0.0826 -0.089,0.1806 -0.09,0.28125 z" sodipodi:nodetypes="ccccccccc"/>
- <path inkscape:connector-curvature="0" id="path27544-8" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 471.50586,371 c -0.27842,0 -0.50585,0.2216 -0.50586,0.5 v 7 c -6.1e-4,0.4051 0.45544,0.6427 0.78711,0.4102 l 5,-3.5 c 0.28542,-0.199 0.28542,-0.6214 0,-0.8204 l -5,-3.5 c -0.0826,-0.058 -0.1806,-0.089 -0.28125,-0.09 z M 478,371 v 8 h 2 v -8 z" sodipodi:nodetypes="cccccccccccccc"/>
- <path sodipodi:nodetypes="cccccccccccccc" d="m 500,371.50586 c 0,-0.27842 -0.2216,-0.50585 -0.5,-0.50586 h -7 c -0.4051,-6.1e-4 -0.6427,0.45544 -0.4102,0.78711 l 3.5,5 c 0.199,0.28542 0.6214,0.28542 0.8204,0 l 3.5,-5 c 0.058,-0.0826 0.089,-0.1806 0.09,-0.28125 z M 500,378 h -8 v 2 h 8 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" id="path9258" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" id="path9260" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 542,379.49414 c 0,0.27842 -0.2216,0.50585 -0.5,0.50586 h -7 c -0.4051,6.1e-4 -0.6427,-0.45544 -0.4102,-0.78711 l 3.5,-5 c 0.199,-0.28542 0.6214,-0.28542 0.8204,0 l 3.5,5 c 0.058,0.0826 0.089,0.1806 0.09,0.28125 z M 542,373 h -8 v -2 h 8 z" sodipodi:nodetypes="cccccccccccccc"/>
- <path sodipodi:nodetypes="cccccccccccccc" d="m 520.49414,371 c 0.27842,0 0.50585,0.2216 0.50586,0.5 v 7 c 6.1e-4,0.4051 -0.45544,0.6427 -0.78711,0.4102 l -5,-3.5 c -0.28542,-0.199 -0.28542,-0.6214 0,-0.8204 l 5,-3.5 c 0.0826,-0.058 0.1806,-0.089 0.28125,-0.09 z M 514,371 v 8 h -2 v -8 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" id="path9264" inkscape:connector-curvature="0"/>
- <g id="g9217">
- <path inkscape:connector-curvature="0" id="path24965-8" d="m 447.5,599 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 1 0 0,-1 H 448 v -9 h 9 v 7.5 a 0.50005,0.50005 0 1 0 1,0 v -8 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 9.99219,11.74219 A 0.50005,0.50005 0 0 0 457,611.25 v 1.25 a 0.50005,0.50005 0 1 0 1,0 v -1.25 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path24881-9" d="m 455.5,602 c -0.58333,0 -1.08834,0.16632 -1.52734,0.45898 -0.43901,0.29267 -0.82618,0.6875 -1.32618,1.1875 l -1,1 c -0.5,0.5 -0.86283,0.85517 -1.17382,1.0625 C 450.16166,605.91632 449.91667,606 449.5,606 h -1 v 1 h 1 c 0.58333,0 1.08834,-0.16632 1.52734,-0.45898 0.43901,-0.29267 0.82618,-0.6875 1.32618,-1.1875 l 1,-1 c 0.5,-0.5 0.86283,-0.85517 1.17382,-1.0625 C 454.83834,603.08368 455.08333,603 455.5,603 h 1 v -1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.65;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g id="g9239">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 468.4999,598.99994 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3.5 h 1 v -3 h 3 v -1 z m 9.5,0 v 1 h 3 v 3 h 1 v -3.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10,10 v 3.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3.5 v -1 h -3 v -3 z m 13,0 v 3 h -3 v 1 h 3.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3.5 z" id="path24895-4" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.65;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 471.4999,601.99994 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h 1 v -1 h 1 v -1 z m 2.5,0 v 1 h 2 v -1 z m 3,0 v 1 h 1 v 1 h 1 v -1.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -6,3 v 2 h 1 v -2 z m 7,0 v 2 h 1 v -2 z m -7,3 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.5 v -1 h -1 v -1 z m 7,0 v 1 h -1 v 1 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1.5 z m -4,1 v 1 h 2 v -1 z" id="path24923-3" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(1223,668.01218)" style="display:inline;enable-background:new" id="g27937-4">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m -733.49414,-90.007812 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6.501953 h 1 v -6.001953 h 6 v -1 z m 12.50195,7.001953 v 6 h -6.00195 v 1 h 6.50195 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -6.5 z" id="path27667-4-6" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m -724.49219,-90.007812 a 0.50005,0.50005 0 1 0 0,1 h 2.78321 l -4.13868,4.148437 a 0.50005,0.50005 0 1 0 0.70899,0.705078 l 4.14648,-4.15625 v 2.802735 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -4.01172,7.998046 a 0.50005,0.50005 0 0 0 -0.34375,0.150391 l -4.14648,4.136719 v -2.783203 a 0.50005,0.50005 0 1 0 -1,0 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -2.80274 l 4.1543,-4.144532 a 0.50005,0.50005 0 0 0 -0.36133,-0.859375 z" id="path27669-6-3" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(1223,668.01218)" style="display:inline;enable-background:new" id="g27941-8">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m -699.50391,-90.009766 a 0.50005,0.50005 0 0 0 -0.34375,0.150391 l -4.14648,4.136719 v -2.783203 a 0.50005,0.50005 0 1 0 -1,0 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -2.80274 l 4.1543,-4.144532 a 0.50005,0.50005 0 0 0 -0.36133,-0.859375 z m -11.98828,8.001954 a 0.50005,0.50005 0 1 0 0,1 h 2.78321 l -4.13868,4.148437 a 0.50005,0.50005 0 1 0 0.70899,0.705078 l 4.14648,-4.15625 v 2.802735 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z" id="path27716-4-8" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m -710.49414,-88.007812 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4.501953 h 1 v -4.001953 h 4 v -1 z m 8.50195,5.001953 v 4 h -4.00195 v 1 h 4.50195 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4.5 z" id="path27721-4-5" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;enable-background:new" id="g10536" transform="translate(-21,636)">
- <path inkscape:connector-curvature="0" d="m 82,-348 v -2.5 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 H 79 v 1 h 2 v 2 z m -13,0 v -2.5 c 2.8e-5,-0.27613 0.223869,-0.49997 0.5,-0.5 H 72 v 1 h -2 v 2 z m 13,7 v 2.5 c -2.8e-5,0.27613 -0.223869,0.49997 -0.5,0.5 H 79 v -1 h 2 v -2 z m -13,0 v 2.5 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 H 72 v -1 h -2 v -2 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" id="path10295"/>
- <g transform="matrix(-1,0,0,1,89.007122,-552.00008)" id="g10303">
- <g id="g10299" transform="translate(-0.012711,-83.995405)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 36.007812,284 v 2 h -1.5 c -0.27613,3e-5 -0.499969,0.22387 -0.5,0.5 v 1.49805 l -3.988281,0.006 c -0.812117,9.2e-4 -1.516225,0.45838 -1.832031,1.12695 -0.315807,0.66858 -0.189691,1.55835 0.478516,2.22656 l 4,4 c 0.413276,0.41327 0.416416,0.77582 0.271484,1.08789 -0.144932,0.31206 -0.483162,0.5586 -0.917969,0.5586 l -4.513672,0.006 c -0.676088,-0.008 -0.674098,1.01079 0.002,1 l 4.511719,-0.006 c 0.815193,0 1.513263,-0.46717 1.824219,-1.13672 0.310955,-0.66954 0.189571,-1.55652 -0.470703,-2.2168 l -4,-4 c -0.426033,-0.42603 -0.426504,-0.78429 -0.28125,-1.0918 0.145253,-0.30751 0.489852,-0.55418 0.927734,-0.55468 L 34,288.99805 c 0.0026,2e-5 0.0052,2e-5 0.0078,0 V 290.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5 v 2 h 1 v -2 h 1.5 c 0.27613,-3e-5 0.499971,-0.22387 0.5,-0.5 V 289 h 2 v -1 h -2 v -1.5 c -2.9e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -1.5 v -2 z m -1.027343,3 h 3.027343 v 3 h -3.027343 z" transform="matrix(-1,0,0,1,68.019833,-0.004515)" id="path10297" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccc"/>
+ <g
+ id="g10319"
+ transform="translate(-21,84)">
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ d="m 29,207 v 1 h -2 v -1 z m 4,4 h 1 v 3 h -1 z m 0,-10 h 1 v 3 h -1 z m -2.5,4 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 208 h 0.335938 l 2.61914,1.9043 c 0.08568,0.0623 0.188958,0.0958 0.294922,0.0957 h 0.25 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -4 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 h -0.25 c -0.105964,-1.5e-4 -0.209238,0.0334 -0.294922,0.0957 L 37.335938,207 H 37 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 5.027344 v 3 H 31 Z m 9,0.30078 v 2.39844 L 38.349609,207.5 Z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="path10313" />
+ <path
+ id="path10315"
+ transform="translate(21,-84)"
+ d="m 54,285 v 2 h 1 v -2 z m -2.5,3 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 6 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -6 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 5.027344 v 5 H 52 Z m -4,2 v 1 h 2 v -1 z m 11,0 v 1 h 2 v -1 z m -5,5 v 2 h 1 v -2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="matrix(-0.53033009,-0.53033009,-0.53033009,0.53033009,559.86353,322.75914)"
+ style="display:inline;opacity:1;fill:#5fd38d;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ id="g10335"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ style="fill:#5fd38d;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none"
+ id="g10333">
+ <g
+ id="g10331">
+ <path
+ inkscape:connector-curvature="0"
+ id="path10321-5"
+ transform="matrix(-0.94280903,-0.94280903,-0.94280903,0.94280903,832.14463,223.54416)"
+ d="m 262.58789,287.02734 a 0.60006001,0.60006001 0 0 0 -0.47266,0.95899 l 2.14844,3.02929 -2.14844,3.0293 a 0.60024527,0.60024527 0 1 0 0.97852,0.69531 l 1.90625,-2.6875 1.90625,2.6875 a 0.60024527,0.60024527 0 1 0 0.97852,-0.69531 l -2.14844,-3.0293 2.14844,-3.02929 a 0.60005997,0.60005997 0 0 0 -0.041,-0.75781 0.60005997,0.60005997 0 0 0 -0.9375,0.0625 l -1.90625,2.6875 -1.90625,-2.6875 a 0.60006001,0.60006001 0 0 0 -0.0645,-0.0781 0.60006001,0.60006001 0 0 0 -0.44141,-0.18555 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 310.32458,237.24123 a 0.66673335,0.66673335 0 0 0 -0.58971,-0.19749 c -6.22865,0.92525 -11.88001,6.57661 -12.80526,12.80526 a 0.66680952,0.66680952 0 1 0 1.31891,0.19749 c 0.82395,-5.54666 6.1358,-10.85851 11.68246,-11.68246 a 0.66673335,0.66673335 0 0 0 0.3936,-1.1228 z m 8.44938,8.44937 a 0.66673335,0.66673335 0 0 1 0.19749,0.58972 c -0.92525,6.22865 -6.57661,11.88001 -12.80526,12.80526 a 0.66673335,0.66673335 0 1 1 -0.19611,-1.31753 c 5.54665,-0.82395 10.8585,-6.1358 11.68245,-11.68246 a 0.66673335,0.66673335 0 0 1 1.12143,-0.39499 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333337px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path10329-8" />
</g>
</g>
- <g transform="translate(0,-552)" id="g10319">
- <path id="path10313" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" d="m 29,207 v 1 h -2 v -1 z m 4,4 h 1 v 3 h -1 z m 0,-10 h 1 v 3 h -1 z m -2.5,4 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 208 h 0.335938 l 2.61914,1.9043 c 0.08568,0.0623 0.188958,0.0958 0.294922,0.0957 h 0.25 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -4 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 h -0.25 c -0.105964,-1.5e-4 -0.209238,0.0334 -0.294922,0.0957 L 37.335938,207 H 37 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 5.027344 v 3 H 31 Z m 9,0.30078 v 2.39844 L 38.349609,207.5 Z" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccc"/>
- <path inkscape:connector-curvature="0" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" d="m 54,285 v 2 h 1 v -2 z m -2.5,3 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 6 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -6 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 5.027344 v 5 H 52 Z m -4,2 v 1 h 2 v -1 z m 11,0 v 1 h 2 v -1 z m -5,5 v 2 h 1 v -2 z" transform="translate(21,-84)" id="path10315"/>
+ </g>
+ <g
+ transform="translate(105.00004,2.4e-4)"
+ id="g10345">
+ <g
+ style="opacity:0.7"
+ id="g10341">
+ <path
+ inkscape:connector-curvature="0"
+ id="path10337-7"
+ d="M 344.49219,287.99219 A 0.50005,0.50005 0 0 0 344,288.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 0,5 A 0.50005,0.50005 0 0 0 344,293.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 1 0 0,-1 H 345 v -1.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 348.5,295 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="rect10339"
+ d="m 351.5,293 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 3 v 3 h -3 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="g10335" style="display:inline;opacity:1;fill:#5fd38d;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" transform="matrix(-0.53033009,-0.53033009,-0.53033009,0.53033009,580.86353,-313.24086)">
- <g id="g10333" style="fill:#5fd38d;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none">
- <g id="g10331">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 262.58789,287.02734 a 0.60006001,0.60006001 0 0 0 -0.47266,0.95899 l 2.14844,3.02929 -2.14844,3.0293 a 0.60024527,0.60024527 0 1 0 0.97852,0.69531 l 1.90625,-2.6875 1.90625,2.6875 a 0.60024527,0.60024527 0 1 0 0.97852,-0.69531 l -2.14844,-3.0293 2.14844,-3.02929 a 0.60005997,0.60005997 0 0 0 -0.041,-0.75781 0.60005997,0.60005997 0 0 0 -0.9375,0.0625 l -1.90625,2.6875 -1.90625,-2.6875 a 0.60006001,0.60006001 0 0 0 -0.0645,-0.0781 0.60006001,0.60006001 0 0 0 -0.44141,-0.18555 z" transform="matrix(-0.94280903,-0.94280903,-0.94280903,0.94280903,832.14463,223.54416)" id="path10321-5" inkscape:connector-curvature="0"/>
- <path id="path10329-8" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333337px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 310.32458,237.24123 a 0.66673335,0.66673335 0 0 0 -0.58971,-0.19749 c -6.22865,0.92525 -11.88001,6.57661 -12.80526,12.80526 a 0.66680952,0.66680952 0 1 0 1.31891,0.19749 c 0.82395,-5.54666 6.1358,-10.85851 11.68246,-11.68246 a 0.66673335,0.66673335 0 0 0 0.3936,-1.1228 z m 8.44938,8.44937 a 0.66673335,0.66673335 0 0 1 0.19749,0.58972 c -0.92525,6.22865 -6.57661,11.88001 -12.80526,12.80526 a 0.66673335,0.66673335 0 1 1 -0.19611,-1.31753 c 5.54665,-0.82395 10.8585,-6.1358 11.68245,-11.68246 a 0.66673335,0.66673335 0 0 1 1.12143,-0.39499 z" inkscape:connector-curvature="0"/>
- </g>
- </g>
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="rect10343"
+ d="m 342.5,284 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ transform="translate(62.97587,-41.03945)"
+ id="g10359"
+ style="display:inline;enable-background:new">
+ <g
+ transform="translate(0,21)"
+ id="g10357">
+ <path
+ style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.66666663;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill"
+ d="m 264.02413,311.53945 a 1.5,1.5 0 0 1 -1.5,1.5 1.5,1.5 0 0 1 -1.5,-1.5 1.5,1.5 0 0 1 1.5,-1.5 1.5,1.5 0 0 1 1.5,1.5 z"
+ id="path10347-2"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="circle10349"
+ d="m 269.02344,314.03906 c -1.09865,0 -2,0.90136 -2,2 0,1.09865 0.90135,2 2,2 1.09864,0 2,-0.90135 2,-2 0,-1.09864 -0.90136,-2 -2,-2 z m 0,1 c 0.5582,0 1,0.4418 1,1 0,0.55821 -0.4418,1 -1,1 -0.55821,0 -1,-0.44179 -1,-1 0,-0.5582 0.44179,-1 1,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10351-7"
+ d="m 258.53125,304.03516 a 0.50005,0.50005 0 1 0 0,1 h 12 a 0.50005,0.50005 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10355-4"
+ d="m 264.79492,304.18164 a 0.60006002,0.60006002 0 0 0 -0.58594,0.4043 l -2.25,6.25 a 0.60006002,0.60006002 0 1 0 1.12891,0.40625 l 2.25,-6.25 a 0.60006002,0.60006002 0 0 0 -0.54297,-0.81055 z m -1.27148,7.75391 a 0.60006002,0.60006002 0 0 0 -0.33594,1.09961 l 4,2.7207 a 0.60006002,0.60006002 0 1 0 0.67383,-0.99219 l -4,-2.7207 a 0.60006002,0.60006002 0 0 0 -0.33789,-0.10742 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#fbfbfb;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
- <g id="g10345" transform="translate(126.00004,-635.99976)">
- <g id="g10341" style="opacity:0.7">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 344.49219,287.99219 A 0.50005,0.50005 0 0 0 344,288.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 0,5 A 0.50005,0.50005 0 0 0 344,293.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 1 0 0,-1 H 345 v -1.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 348.5,295 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z" id="path10337-7" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 351.5,293 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 3 v 3 h -3 z" id="rect10339" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 342.5,284 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="rect10343" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- </g>
- <g style="display:inline;enable-background:new" id="g10359" transform="translate(83.97587,-677.03945)">
- <g id="g10357" transform="translate(0,21)">
- <path inkscape:connector-curvature="0" id="path10347-2" d="m 264.02413,311.53945 a 1.5,1.5 0 0 1 -1.5,1.5 1.5,1.5 0 0 1 -1.5,-1.5 1.5,1.5 0 0 1 1.5,-1.5 1.5,1.5 0 0 1 1.5,1.5 z" style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.66666663;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 269.02344,314.03906 c -1.09865,0 -2,0.90136 -2,2 0,1.09865 0.90135,2 2,2 1.09864,0 2,-0.90135 2,-2 0,-1.09864 -0.90136,-2 -2,-2 z m 0,1 c 0.5582,0 1,0.4418 1,1 0,0.55821 -0.4418,1 -1,1 -0.55821,0 -1,-0.44179 -1,-1 0,-0.5582 0.44179,-1 1,-1 z" id="circle10349" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 258.53125,304.03516 a 0.50005,0.50005 0 1 0 0,1 h 12 a 0.50005,0.50005 0 1 0 0,-1 z" id="path10351-7" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#fbfbfb;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 264.79492,304.18164 a 0.60006002,0.60006002 0 0 0 -0.58594,0.4043 l -2.25,6.25 a 0.60006002,0.60006002 0 1 0 1.12891,0.40625 l 2.25,-6.25 a 0.60006002,0.60006002 0 0 0 -0.54297,-0.81055 z m -1.27148,7.75391 a 0.60006002,0.60006002 0 0 0 -0.33594,1.09961 l 4,2.7207 a 0.60006002,0.60006002 0 1 0 0.67383,-0.99219 l -4,-2.7207 a 0.60006002,0.60006002 0 0 0 -0.33789,-0.10742 z" id="path10355-4" inkscape:connector-curvature="0"/>
- </g>
+ </g>
+ <g
+ transform="translate(11,-136)"
+ id="g10373">
+ <path
+ inkscape:connector-curvature="0"
+ id="path10361"
+ d="m 275.4707,427 c -0.42985,0.004 -0.62994,0.5874 -0.31869,0.87125 0.40897,0.54487 0.81793,1.08974 1.2269,1.63461 -0.43981,0.59662 -0.90116,1.17907 -1.32716,1.78476 -0.21053,0.38613 0.24226,0.86663 0.6402,0.67938 0.28682,-0.15751 0.42097,-0.48416 0.63231,-0.72356 0.22655,-0.3022 0.4531,-0.6044 0.67965,-0.9066 0.3916,0.51133 0.76296,1.03993 1.16735,1.54035 0.31222,0.30974 0.89981,0.009 0.83079,-0.42566 -0.0715,-0.31923 -0.34727,-0.53953 -0.51804,-0.80941 -0.28503,-0.37975 -0.57007,-0.75951 -0.8551,-1.13926 0.43981,-0.59662 0.90116,-1.17907 1.32716,-1.78476 0.21053,-0.38613 -0.24226,-0.86663 -0.6402,-0.67938 -0.28682,0.15751 -0.42097,0.48416 -0.63231,0.72356 -0.22655,0.3022 -0.4531,0.6044 -0.67965,0.9066 -0.39082,-0.51197 -0.76442,-1.03847 -1.1661,-1.54128 -0.0981,-0.0907 -0.23371,-0.13896 -0.36711,-0.1306 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <g
+ id="g10367"
+ transform="translate(115.99999,-73.00002)"
+ style="display:inline;opacity:0.6;enable-background:new"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ inkscape:connector-curvature="0"
+ id="path10363"
+ transform="translate(-378.99999,209.00002)"
+ d="m 534.48047,284 a 0.50005,0.50005 0 0 0 -0.38477,0.19727 l -2.92382,2.92578 -0.0254,0.0234 c -4.5e-4,4.6e-4 4.5e-4,0.002 0,0.002 a 0.50005,0.50005 0 0 0 -0.13671,0.25781 c -7.9e-4,0.004 -0.003,0.008 -0.004,0.0117 A 0.50005,0.50005 0 0 0 531,287.50781 V 296.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 1 0 0,-1 H 532 v -8 h 2.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 285 h 6 v 2.5 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -7 a 0.50005,0.50005 0 0 0 -0.0137,0 c -6.7e-4,2e-5 -10e-4,-2e-5 -0.002,0 -10e-4,4e-5 -0.003,-5e-5 -0.004,0 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
- <g id="g10373" transform="translate(32,-772)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 275.4707,427 c -0.42985,0.004 -0.62994,0.5874 -0.31869,0.87125 0.40897,0.54487 0.81793,1.08974 1.2269,1.63461 -0.43981,0.59662 -0.90116,1.17907 -1.32716,1.78476 -0.21053,0.38613 0.24226,0.86663 0.6402,0.67938 0.28682,-0.15751 0.42097,-0.48416 0.63231,-0.72356 0.22655,-0.3022 0.4531,-0.6044 0.67965,-0.9066 0.3916,0.51133 0.76296,1.03993 1.16735,1.54035 0.31222,0.30974 0.89981,0.009 0.83079,-0.42566 -0.0715,-0.31923 -0.34727,-0.53953 -0.51804,-0.80941 -0.28503,-0.37975 -0.57007,-0.75951 -0.8551,-1.13926 0.43981,-0.59662 0.90116,-1.17907 1.32716,-1.78476 0.21053,-0.38613 -0.24226,-0.86663 -0.6402,-0.67938 -0.28682,0.15751 -0.42097,0.48416 -0.63231,0.72356 -0.22655,0.3022 -0.4531,0.6044 -0.67965,0.9066 -0.39082,-0.51197 -0.76442,-1.03847 -1.1661,-1.54128 -0.0981,-0.0907 -0.23371,-0.13896 -0.36711,-0.1306 z" id="path10361" inkscape:connector-curvature="0"/>
- <g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" style="display:inline;opacity:0.6;enable-background:new" transform="translate(115.99999,-73.00002)" id="g10367">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 534.48047,284 a 0.50005,0.50005 0 0 0 -0.38477,0.19727 l -2.92382,2.92578 -0.0254,0.0234 c -4.5e-4,4.6e-4 4.5e-4,0.002 0,0.002 a 0.50005,0.50005 0 0 0 -0.13671,0.25781 c -7.9e-4,0.004 -0.003,0.008 -0.004,0.0117 A 0.50005,0.50005 0 0 0 531,287.50781 V 296.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 1 0 0,-1 H 532 v -8 h 2.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 285 h 6 v 2.5 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -7 a 0.50005,0.50005 0 0 0 -0.0137,0 c -6.7e-4,2e-5 -10e-4,-2e-5 -0.002,0 -10e-4,4e-5 -0.003,-5e-5 -0.004,0 z" transform="translate(-378.99999,209.00002)" id="path10363" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 273.50391,425 c -0.46998,0.0749 -0.80823,0.50172 -1.06635,0.87006 -0.4326,0.65782 -0.45638,1.4618 -0.43756,2.22236 0.008,1.23972 -0.0164,2.48035 0.0134,3.71944 0.0716,0.88933 0.54871,1.83354 1.40415,2.18708 0.42463,0.112 0.78249,-0.44168 0.50598,-0.78285 -0.29758,-0.24384 -0.6397,-0.4766 -0.77031,-0.86624 -0.24243,-0.63283 -0.12529,-1.31954 -0.15325,-1.98084 0.006,-1.03207 -0.0114,-2.06474 0.009,-3.09642 0.0299,-0.56822 0.33188,-1.12862 0.8373,-1.40532 0.33744,-0.28816 0.10108,-0.88712 -0.34243,-0.86727 z" id="path10369" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 280.48828,425 c -0.4389,-0.0149 -0.66492,0.60436 -0.31958,0.87564 0.63959,0.33681 0.88258,1.10168 0.83716,1.78593 -0.006,1.35522 0.0116,2.71106 -0.009,4.06588 -0.029,0.57068 -0.33398,1.12767 -0.83582,1.41135 -0.3334,0.28584 -0.081,0.8949 0.35685,0.86114 0.46399,-0.0793 0.79448,-0.50451 1.05034,-0.86849 0.42617,-0.65052 0.45767,-1.4445 0.43766,-2.19695 -0.008,-1.24867 0.0164,-2.49826 -0.0134,-3.7463 -0.0691,-0.87707 -0.53296,-1.78778 -1.35661,-2.16868 -0.0478,-0.0138 -0.0978,-0.0204 -0.14755,-0.0195 z" id="path10371" inkscape:connector-curvature="0"/>
- </g>
- <g id="g10379" transform="translate(64,-573)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 471.5,221 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 468,224.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 8 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 480,231.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 479 v 9.29297 L 476.29297,234 H 469 v -9.29297 z" id="path10375" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00157475;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 474,225.99805 c -1.09907,0 -2,0.90288 -2,2.00195 0,1.09907 0.90093,2 2,2 1.09907,0 2.00195,-0.90093 2.00195,-2 0,-1.09907 -0.90288,-2.00195 -2.00195,-2.00195 z" id="circle10377" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- </g>
- <g id="g28780" transform="translate(21)">
- <path inkscape:connector-curvature="0" id="path10381" d="m 531.50781,-348.00781 a 0.50005,0.50005 0 0 0 -0.5,0.5 L 531,-338.5 a 0.50005,0.50005 0 0 0 0.5,0.5 l 9.00781,-0.008 a 0.50005,0.50005 0 0 0 0.5,-0.5 c 0,-5.24079 -4.25921,-9.5 -9.5,-9.5 z m 0.5,1.10156 c 4.27858,0.26151 7.63693,3.61986 7.89844,7.89844 L 532,-339 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- <path inkscape:connector-curvature="0" id="path10384-1" d="m 542.98047,-351.00977 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 l -3,3 a 1.0001,1.0001 0 1 0 1.41406,1.41406 l 3,-3 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g id="g10393" transform="translate(-126)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 560.99219,-349.49609 c 0,-1.37714 1.12676,-2.50391 2.5039,-2.50391 1.37715,0 2.50391,1.12677 2.50391,2.50391 0,1.37713 -1.12676,2.5039 -2.50391,2.5039 -1.37714,0 -2.5039,-1.12677 -2.5039,-2.5039 z" id="ellipse10386" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 552,-339.99219 c 0,-1.09609 0.89673,-1.99609 1.99219,-1.99609 1.09546,0 1.99414,0.9 1.99414,1.99609 0,1.09609 -0.89868,1.99805 -1.99414,1.99805 -1.09546,0 -1.99219,-0.90196 -1.99219,-1.99805 z m 1,0 c 0,0.55685 0.43837,0.99805 0.99219,0.99805 0.55382,0 0.99414,-0.4412 0.99414,-0.99805 0,-0.55685 -0.44032,-0.99609 -0.99414,-0.99609 -0.55382,0 -0.99219,0.43924 -0.99219,0.99609 z" id="ellipse10388" inkscape:connector-curvature="0"/>
- <path inkscape:connector-curvature="0" id="path28690" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.19999993;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 560.36798,-346.98792 a 0.60364676,0.60365756 0 0 0 -0.41654,0.18273 l -0.77413,0.77415 a 0.60366279,0.6036736 0 1 0 0.85273,0.8547 l 0.77609,-0.77611 a 0.60364676,0.60365756 0 0 0 -0.43815,-1.03547 z m -2.99662,2.98989 a 0.61117943,0.61029182 0 0 0 -0.42173,0.18473 l -0.78379,0.78265 a 0.61119567,0.61030804 0 1 0 0.86336,0.8641 l 0.78578,-0.78463 a 0.61117943,0.61029182 0 0 0 -0.44362,-1.04685 z"/>
- </g>
- <g id="g10409" transform="translate(-189)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 560.99219,-349.49609 c 0,-1.37714 1.12676,-2.50391 2.5039,-2.50391 1.37715,0 2.50391,1.12677 2.50391,2.50391 0,1.37713 -1.12676,2.5039 -2.50391,2.5039 -1.37714,0 -2.5039,-1.12677 -2.5039,-2.5039 z" id="ellipse10403" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 552,-339.99219 c 0,-1.09609 0.89673,-1.99609 1.99219,-1.99609 1.09546,0 1.99414,0.9 1.99414,1.99609 0,1.09609 -0.89868,1.99805 -1.99414,1.99805 -1.09546,0 -1.99219,-0.90196 -1.99219,-1.99805 z m 1,0 c 0,0.55685 0.43837,0.99805 0.99219,0.99805 0.55382,0 0.99414,-0.4412 0.99414,-0.99805 0,-0.55685 -0.44032,-0.99609 -0.99414,-0.99609 -0.55382,0 -0.99219,0.43924 -0.99219,0.99609 z" id="ellipse10405" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 563.50195,-343.01367 a 0.50005,0.50005 0 0 0 -0.49414,0.50586 v 4 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.50586,-0.50586 z m -5.99414,2.00586 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z" id="path10407-7" inkscape:connector-curvature="0"/>
- </g>
- <g id="g10415" transform="translate(63,21)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 350.99219,-370.49609 c 0,-1.37714 1.12676,-2.50391 2.5039,-2.50391 1.37715,0 2.50391,1.12677 2.50391,2.50391 0,1.37713 -1.12676,2.5039 -2.50391,2.5039 -1.37714,0 -2.5039,-1.12677 -2.5039,-2.5039 z" id="ellipse10411" inkscape:connector-curvature="0" sodipodi:nodetypes="sssss"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 348.4707,-367.9375 c -0.33462,0.0898 -0.64722,0.26623 -0.90039,0.51953 l -4.97851,4.98242 c -0.50693,0.50809 -0.70493,1.24983 -0.51953,1.94336 0.18541,0.69355 0.72692,1.23774 1.41992,1.42383 0.69276,0.18603 1.43437,-0.0128 1.9414,-0.52148 l 4.97852,-4.98047 c 0.50694,-0.50808 0.70495,-1.25177 0.51953,-1.94531 -0.1854,-0.69356 -0.72693,-1.23578 -1.41992,-1.42188 -0.34638,-0.093 -0.70553,-0.09 -1.04102,0 z m 0.78125,0.96484 c 0.34883,0.0937 0.61917,0.3662 0.71289,0.7168 0.0937,0.35062 -0.006,0.72222 -0.26172,0.97852 l -4.97656,4.98046 c -0.25562,0.25646 -0.62555,0.35546 -0.97461,0.26172 -0.3488,-0.0937 -0.62111,-0.36425 -0.71484,-0.71484 -0.0937,-0.35061 0.006,-0.7222 0.26172,-0.97852 l 4.97851,-4.98242 c 0.25563,-0.25646 0.62557,-0.35545 0.97461,-0.26172 z" id="path10413-7" inkscape:connector-curvature="0"/>
- </g>
- <g id="g9298" transform="translate(21)">
- <path inkscape:connector-curvature="0" id="path10419-4" d="m 306.49219,-348.01172 a 0.50005,0.50005 0 0 0 -0.38867,0.19531 l -1.95704,1.95703 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 306,-346.29883 v 5.79297 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5.79297 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.95117,-1.94922 a 0.50005,0.50005 0 0 0 0.008,-0.79883 l -1.95898,-1.95899 a 0.50005,0.50005 0 1 0 -0.70704,0.70704 l 1.14649,1.14648 H 307 v -5.29297 l 1.14648,1.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.96094,-1.96093 -0.006,-0.008 a 0.50005,0.50005 0 0 0 -0.39453,-0.1836 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path inkscape:connector-curvature="0" id="path10421-9" d="m 306.44531,-351.99805 c -1.16966,-0.043 -2.35048,0.23548 -3.40039,0.84766 -2.09911,1.22396 -3.28024,3.5522 -3.00586,5.94141 0.27491,2.39372 1.98225,4.44954 4.31055,5.18554 a 0.50004997,0.50004997 0 1 0 0.30078,-0.95312 c -1.94954,-0.61628 -3.38871,-2.3582 -3.61719,-4.34766 -0.22899,-1.99397 0.75092,-3.93196 2.51563,-4.96094 1.76401,-1.02856 3.9738,-0.9382 5.67187,0.20118 0.93801,0.62937 1.92387,1.08398 3.2793,1.08398 h 1 a 0.50004997,0.50004997 0 1 0 0,-1 h -1 c -1.14457,0 -1.85649,-0.33615 -2.7207,-0.91602 -1.00565,-0.67477 -2.16433,-1.03898 -3.33399,-1.08203 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
- <g id="g10433" transform="rotate(-180,390.99654,-344.99764)">
- <g id="g10429" transform="translate(1)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 393.49219,289.00391 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 1.73047 l -2.76953,2.76953 h -1.73047 c -0.27613,2e-5 -0.49997,0.22386 -0.5,0.5 v 1.02929 c 3e-5,0.27613 0.22387,0.47068 0.5,0.47071 h 1 c 0.2725,0 0.5,0.17071 0.5,0.5 v 1 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1.73243 l 2.76758,-2.76757 h 1.73242 c 0.27613,-2e-5 0.49997,-0.22386 0.5,-0.5 v -1.02735 c -3e-5,-0.27613 -0.22387,-0.47262 -0.5,-0.47265 h -1 c -0.2725,0 -0.5,-0.17071 -0.5,-0.5 v -1 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" transform="rotate(180,390.49654,-26.99764)" id="path10423-5" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 395.47852,-349.00391 a 0.50004997,0.50004997 0 0 0 -0.32032,0.86914 c 1.10925,1.04157 1.85525,2.61894 1.8418,4.13086 -0.0174,1.95759 -1.00719,3.50006 -2.74023,4.44727 -1.67823,0.91724 -3.81516,0.64624 -5.48829,-0.40625 l 0.0234,0.0156 C 387.83199,-340.63237 386.68507,-341 385.50781,-341 H 384.5 a 0.50004997,0.50004997 0 1 0 0,1 h 1.00586 0.002 c 0.96887,0 1.91412,0.30361 2.70899,0.86914 l 0.0117,0.008 0.0117,0.008 c 1.93164,1.2151 4.44119,1.56274 6.5,0.4375 2.004,-1.0953 3.23927,-3.01733 3.25977,-5.31836 0.0163,-1.83862 -0.84967,-3.64045 -2.1582,-4.86914 a 0.50004997,0.50004997 0 0 0 -0.36328,-0.13868 z" id="path10431-8" inkscape:connector-curvature="0"/>
- </g>
- <g id="g10447" transform="translate(41.999997,-21)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 478.49609,-323.00781 a 0.50005,0.50005 0 0 0 -0.34765,0.85937 l 2.64648,2.64649 -2.64648,2.64648 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.70703 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z" id="path10443" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 473.4375,-330.97461 c -0.67078,0.0637 -1.33815,0.24001 -1.97461,0.53711 -2.54627,1.1886 -3.92907,3.99498 -3.32031,6.73828 0.60875,2.7433 3.04739,4.69922 5.85742,4.69922 h 2.29297 l -2.14453,2.14453 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.70703 l -3,-3 a 0.50005,0.50005 0 1 0 -0.70703,0.70703 L 476.29688,-320 H 474 c -2.34689,0 -4.37244,-1.62485 -4.88086,-3.91602 -0.50842,-2.29116 0.63902,-4.62253 2.76563,-5.61523 2.12705,-0.99291 4.66398,-0.38512 6.07812,1.48242 l 0.74023,0.97656 C 479.25532,-326.34303 480.1366,-326 481,-326 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 H 481 c -0.59704,0 -1.17055,-0.2407 -1.5,-0.67578 l -0.74023,-0.97656 c -1.27424,-1.68278 -3.30992,-2.51346 -5.32227,-2.32227 z" id="path10445" inkscape:connector-curvature="0"/>
- </g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 412.5,-372.99219 c -0.82054,0 -1.49609,0.67557 -1.49609,1.4961 0,0.82054 0.67555,1.49609 1.49609,1.49609 0.82053,0 1.49609,-0.67555 1.49609,-1.49609 0,-0.82053 -0.67556,-1.4961 -1.49609,-1.4961 z M 418,-372 c -0.71373,0 -1.37556,0.3819 -1.73242,1 -0.19053,0.33001 -0.2484,0.68266 -0.25586,0.99609 v 0.0117 h -1.54297 C 414.0093,-369.3956 413.2975,-369 412.5,-369 c -0.79751,0 -1.50931,-0.3956 -1.96875,-0.99219 h -0.0195 -5.01563 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 5.01563 0.49805 l -0.0137,3.28711 c -1.65939,1.40974 -3.24134,2.62162 -3.98828,6.10742 -0.17787,0.67446 0.8602,0.89868 0.97657,0.21094 0.67528,-3.15139 1.9234,-4.08819 3.51757,-5.42773 1.58398,1.34059 2.83152,2.27746 3.51953,5.42968 0.13318,0.66658 1.13544,0.44609 0.97657,-0.21484 -0.76273,-3.49457 -2.35105,-4.70351 -4.00196,-6.11719 l 0.0137,-3.27539 h 2.21679 1.78516 v 0.004 c 0.007,0.31344 0.0653,0.66608 0.25586,0.99609 0.35686,0.61811 1.01869,1 1.73242,1 h 0.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 418 c -0.35807,0 -0.6862,-0.1899 -0.86523,-0.5 -0.0738,-0.12789 -0.11835,-0.32209 -0.12305,-0.51953 v -0.96875 c 0.005,-0.19744 0.0492,-0.39164 0.12305,-0.51953 0.17903,-0.3101 0.50716,-0.5 0.86523,-0.5 h 0.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 z" id="path10449" inkscape:connector-curvature="0"/>
- <g id="g28776" transform="translate(21)">
- <path id="path10435" transform="translate(21,-636)" d="m 447.50977,297.01172 a 0.50005,0.50005 0 1 0 0,1 h 6.2832 c -0.26437,-0.28877 -0.47061,-0.62726 -0.60742,-1 z m 11.29882,0 c -0.13697,0.37274 -0.34281,0.71123 -0.60742,1 h 2.3086 a 0.50005,0.50005 0 1 0 0,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" inkscape:connector-curvature="0"/>
- <path sodipodi:nodetypes="sssss" inkscape:connector-curvature="0" id="ellipse10439" d="m 476.99609,-342 c 1.09999,0 2.00391,0.90231 2.00391,2.00195 0,1.09965 -0.90392,2 -2.00391,2 -1.09998,0 -2.00195,-0.90035 -2.00195,-2 0,-1.09964 0.90197,-2.00195 2.00195,-2.00195 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path inkscape:connector-curvature="0" id="ellipse10441" d="m 472.49805,-351.99805 c 1.37513,0 2.50195,1.12557 2.50195,2.5 0,1.37444 -1.12682,2.49805 -2.50195,2.49805 -1.37514,0 -2.5,-1.12361 -2.5,-2.49805 0,-1.37443 1.12486,-2.5 2.5,-2.5 z m 0,1 c -0.83537,0 -1.5,0.66668 -1.5,1.5 0,0.83332 0.66463,1.49805 1.5,1.49805 0.83537,0 1.50195,-0.66473 1.50195,-1.49805 0,-0.83332 -0.66658,-1.5 -1.50195,-1.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <path inkscape:connector-curvature="0" id="path10451" d="m 472.50195,-345.99609 a 0.50005,0.50005 0 0 0 -0.49218,0.50781 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50782,-0.50781 z m 0,3 a 0.50005,0.50005 0 0 0 -0.49218,0.50781 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50782,-0.50781 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g id="g10457" transform="translate(-105)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 554.5,284 c -1.37479,0 -2.5,1.12521 -2.5,2.5 v 2.00781 c 0,1.37479 1.12521,2.5 2.5,2.5 1.37479,0 2.5,-1.12521 2.5,-2.5 v -0.5 h 1.51172 0.49805 l -0.0137,3.28711 c -1.65939,1.40974 -3.24134,2.62162 -3.98828,6.10742 -0.17787,0.67446 0.86019,0.89868 0.97657,0.21094 0.67528,-3.15139 1.9234,-4.08819 3.51757,-5.42773 1.58398,1.34059 2.83152,2.27746 3.51953,5.42968 0.13318,0.66658 1.13544,0.44609 0.97657,-0.21484 -0.76273,-3.49457 -2.35105,-4.70351 -4.00196,-6.11719 l 0.0137,-3.27539 h 2.21679 3.28516 c 0.6573,-0.009 0.6573,-0.9907 0,-1 h -3.04297 C 562.0093,287.6044 561.2975,288 560.5,288 c -0.79751,0 -1.50931,-0.3956 -1.96875,-0.99219 H 558.51172 557 V 286.5 c 0,-1.37479 -1.12521,-2.5 -2.5,-2.5 z m 6,0.008 c -0.82054,0 -1.49609,0.67557 -1.49609,1.4961 0,0.82054 0.67555,1.49609 1.49609,1.49609 0.82053,0 1.49609,-0.67555 1.49609,-1.49609 0,-0.82053 -0.67556,-1.4961 -1.49609,-1.4961 z m -6,0.992 c 0.83435,0 1.5,0.66565 1.5,1.5 v 2.00781 c 0,0.83435 -0.66565,1.5 -1.5,1.5 -0.83435,0 -1.5,-0.66565 -1.5,-1.5 V 286.5 c 0,-0.83435 0.66565,-1.5 1.5,-1.5 z" transform="translate(0,-636)" id="path10453" inkscape:connector-curvature="0"/>
- </g>
- <g id="g10464" style="opacity:0.8" transform="translate(0,-21)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 237.5,-323 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path10460" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 237.52148,-329 a 0.50005,0.50005 0 0 0 -0.5,0.49805 l -0.0215,4.5 1,0.004 0.0195,-4.00195 H 247 v 9 h -4 v 1 h 4.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z" id="path10462" inkscape:connector-curvature="0"/>
- </g>
- <path inkscape:connector-curvature="0" id="path10466" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" d="m 251,-347 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,12 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z"/>
- <g id="g10474" transform="translate(-4,-17)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 137.5,-326 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" id="path10468" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 137.52148,-331 a 0.50005,0.50005 0 0 0 -0.5,0.49609 l -0.0215,3.5 1,0.008 0.0176,-3.00391 H 145 v 7 h -3 v 1 h 3.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -8 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z" id="path10470" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 141.52148,-335 a 0.50005,0.50005 0 0 0 -0.5,0.49609 l -0.0215,2.5 1,0.008 0.0176,-2.00391 H 149 v 7 h -2 v 1 h 2.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -8 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z" id="path10472" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:0.8;enable-background:new" id="g10480" transform="translate(146,-637)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 51.492188,285.99219 a 0.50005,0.50005 0 0 0 -0.388672,0.19531 0.50005,0.50005 0 0 0 -0.0039,0.006 l -1.953125,1.95312 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 51,287.70703 V 295.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 7.792969 l -1.146485,1.14648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 1.957031,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.0059,-0.004 l -1.953125,-1.95313 a 0.50005,0.50005 0 1 0 -0.707032,0.70704 L 59.292969,295 H 52 v -7.29297 l 1.146484,1.14649 a 0.50005,0.50005 0 1 0 0.707032,-0.70704 l -1.957032,-1.95703 a 0.50005,0.50005 0 0 0 -0.404296,-0.19726 z" id="path10478" inkscape:connector-curvature="0"/>
- </g>
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 197.50977,285.99609 a 0.50005,0.50005 0 0 0 -0.31055,0.10547 c -1.78384,1.33863 -2.5833,3.62488 -2.02149,5.78321 0.56181,2.15833 2.37387,3.7674 4.58399,4.0664 2.05389,0.27788 4.06729,-0.6352 5.23828,-2.31445 V 296.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -4 a 0.50005,0.50005 0 1 0 0,1 h 2.72656 c -0.95112,1.41787 -2.62038,2.19029 -4.33008,1.95898 -1.8109,-0.24499 -3.29162,-1.5577 -3.75195,-3.32617 -0.46033,-1.76847 0.19267,-3.63559 1.6543,-4.73242 a 0.50005,0.50005 0 0 0 -0.28906,-0.9043 z" transform="translate(21,-636)" id="path10482"/>
- <path inkscape:connector-curvature="0" d="m 188,-347 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,12 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" id="path10484"/>
- <path inkscape:connector-curvature="0" id="path10486" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" d="m 209,-347 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,12 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z"/>
- <path d="m 230,-347 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,12 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" id="path10488" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.85;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 181.5,-350.00977 a 0.50005,0.50005 0 0 0 -0.34766,0.85743 l 1.14649,1.14648 -6.29297,6.29297 -1.14648,-1.14649 a 0.50005,0.50005 0 1 0 -0.70704,0.70704 l 3,3 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.14649,-1.14648 6.29297,-6.29297 1.14648,1.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -3,-3 A 0.50005,0.50005 0 0 0 181.5,-350.00977 Z" id="path10490" inkscape:connector-curvature="0"/>
- <g transform="rotate(180,181.00319,109.50118)" id="g10502">
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 138.61719,286.00781 a 0.60006002,0.60006002 0 0 0 -0.47657,0.99024 l 1.61133,2.01953 a 1.5007322,1.5007322 0 0 1 1.2461,1.5625 l 0.92773,1.16211 a 0.60006002,0.60006002 0 0 0 0.4668,0.23242 0.60006002,0.60006002 0 0 0 0.4707,-0.98047 l -1.58789,-1.99023 1.58984,-2.00782 a 0.60006002,0.60006002 0 1 0 -0.9414,-0.74414 l -1.41602,1.78907 -1.42969,-1.79102 a 0.60006002,0.60006002 0 0 0 -0.46093,-0.24219 z" transform="rotate(-180,170.50319,427.50118)" id="path10492"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 201.60938,559.02148 a 0.60006002,0.60006002 0 0 0 -0.47071,0.98243 l 1.59766,2.00195 -1.59766,2.00195 a 0.6002929,0.6002929 0 1 0 0.9375,0.75 l 1.42774,-1.78906 1.42773,1.78906 a 0.6002929,0.6002929 0 1 0 0.9375,-0.75 l -1.59766,-2.00195 1.59766,-2.00195 a 0.6002929,0.6002929 0 1 0 -0.9375,-0.75 l -1.42773,1.78906 -1.42774,-1.78906 a 0.60006002,0.60006002 0 0 0 -0.46679,-0.23243 z" id="path10496" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 196.50391,561 a 0.50004997,0.50004997 0 0 0 -0.22657,0.0547 c 0,0 -0.3567,0.1843 -0.66796,0.57226 C 195.29811,562.01491 195,562.63889 195,563.5 v 5 c 0,0.86111 0.29839,1.4864 0.60938,1.875 0.31098,0.3886 0.66796,0.57227 0.66796,0.57227 a 0.50004997,0.50004997 0 1 0 0.44532,-0.89454 c 0,0 -0.14302,-0.0665 -0.33204,-0.30273 C 196.20161,569.5138 196,569.13889 196,568.5 v -5 c 0,-0.63889 0.20189,-1.01282 0.39062,-1.24805 0.18874,-0.23523 0.33204,-0.30078 0.33204,-0.30078 A 0.50004997,0.50004997 0 0 0 196.50391,561 Z" id="path10498" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 207.48828,557 a 0.50004997,0.50004997 0 0 0 -0.20508,0.95117 c 0,0 0.14526,0.0655 0.33399,0.30078 0.18873,0.23523 0.38867,0.60916 0.38867,1.24805 v 5 c 0,0.63889 -0.20161,1.0138 -0.39063,1.25 -0.18901,0.2362 -0.33203,0.30273 -0.33203,0.30273 a 0.50006306,0.50006306 0 1 0 0.44727,0.89454 c 0,0 0.35503,-0.18367 0.66601,-0.57227 0.31099,-0.3886 0.60938,-1.01389 0.60938,-1.875 v -5 c 0,-0.86111 -0.29811,-1.48509 -0.60938,-1.87305 -0.31127,-0.38796 -0.66796,-0.57226 -0.66796,-0.57226 A 0.50004997,0.50004997 0 0 0 207.48828,557 Z" id="path10500" inkscape:connector-curvature="0"/>
- </g>
- <g transform="translate(0,-169)" id="g10508" style="opacity:1">
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 91.347656,288.96484 a 0.51005099,0.51005099 0 0 0 -0.376953,0.20899 c -1.08977,1.44807 -1.289364,3.38767 -0.521484,5.03125 0.76787,1.64358 2.380967,2.72477 4.185547,2.80078 1.781016,0.075 3.455174,-0.8442 4.365234,-2.38086 v 1.875 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 99.5,293 h -3 a 0.50005,0.50005 0 1 0 0,1 h 1.693359 a 0.51006897,0.51006897 0 0 0 -0.03906,0.0586 c -0.71442,1.24711 -2.052293,1.98773 -3.476563,1.92774 -1.42426,-0.06 -2.695887,-0.90979 -3.304687,-2.21289 -0.60881,-1.3031 -0.449088,-2.83939 0.414062,-3.98633 a 0.51005099,0.51005099 0 0 0 -0.388671,-0.82227 0.51005099,0.51005099 0 0 0 -0.05078,0 z" transform="translate(21,-467)" id="path10504"/>
- </g>
- <g style="opacity:0.7;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" id="g10514" transform="translate(3,-280)">
- <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 95.398438,282.97461 a 0.50004994,0.50004994 0 0 0 -0.05078,0.002 0.50004994,0.50004994 0 0 0 -0.367187,0.20313 c -1.08755,1.44512 -1.289758,3.38123 -0.523438,5.02148 0.76632,1.64025 2.376885,2.71907 4.177735,2.79492 1.781962,0.0751 3.458632,-0.84789 4.365232,-2.38867 V 290.5 a 0.50004997,0.50004997 0 1 0 1,0 v -3 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 h -3 a 0.50004997,0.50004997 0 1 0 0,1 h 1.70312 a 0.50004994,0.50004994 0 0 0 -0.0391,0.0645 c -0.71624,1.25031 -2.05833,1.99179 -3.486324,1.93164 -1.42799,-0.0601 -2.704083,-0.91231 -3.314453,-2.21875 -0.61036,-1.30644 -0.449354,-2.8462 0.416016,-3.99609 A 0.50004994,0.50004994 0 0 0 95.3984,282.97466 Z" transform="translate(18,-356)" id="path10510"/>
- </g>
- <g transform="translate(0,-252)" id="g10528">
- <g transform="translate(46,-388)" id="g10520" style="display:inline;opacity:0.7;enable-background:new">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 50.492188,287.99219 a 0.50005,0.50005 0 0 0 -0.388672,0.19531 0.50005,0.50005 0 0 0 -0.0039,0.006 l -1.953125,1.95312 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 50,289.70703 V 295.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5.792969 l -1.146485,1.14648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 1.957031,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.0059,-0.004 l -1.953125,-1.95313 a 0.50005,0.50005 0 1 0 -0.707032,0.70704 L 56.292969,295 H 51 v -5.29297 l 1.146484,1.14649 a 0.50005,0.50005 0 1 0 0.707032,-0.70704 l -1.957032,-1.95703 a 0.50005,0.50005 0 0 0 -0.404296,-0.19726 z" id="path10518" inkscape:connector-curvature="0"/>
- </g>
- <g style="display:inline;opacity:1;enable-background:new" id="g10526" transform="translate(42,-384)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 50.492188,287.99219 a 0.50005,0.50005 0 0 0 -0.388672,0.19531 0.50005,0.50005 0 0 0 -0.0039,0.006 l -1.953125,1.95312 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 50,289.70703 V 295.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5.792969 l -1.146485,1.14648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 1.957031,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.0059,-0.004 l -1.953125,-1.95313 a 0.50005,0.50005 0 1 0 -0.707032,0.70704 L 56.292969,295 H 51 v -5.29297 l 1.146484,1.14649 a 0.50005,0.50005 0 1 0 0.707032,-0.70704 l -1.957032,-1.95703 a 0.50005,0.50005 0 0 0 -0.404296,-0.19726 z" id="path10524" inkscape:connector-curvature="0"/>
- </g>
+ <path
+ inkscape:connector-curvature="0"
+ id="path10369"
+ d="m 273.50391,425 c -0.46998,0.0749 -0.80823,0.50172 -1.06635,0.87006 -0.4326,0.65782 -0.45638,1.4618 -0.43756,2.22236 0.008,1.23972 -0.0164,2.48035 0.0134,3.71944 0.0716,0.88933 0.54871,1.83354 1.40415,2.18708 0.42463,0.112 0.78249,-0.44168 0.50598,-0.78285 -0.29758,-0.24384 -0.6397,-0.4766 -0.77031,-0.86624 -0.24243,-0.63283 -0.12529,-1.31954 -0.15325,-1.98084 0.006,-1.03207 -0.0114,-2.06474 0.009,-3.09642 0.0299,-0.56822 0.33188,-1.12862 0.8373,-1.40532 0.33744,-0.28816 0.10108,-0.88712 -0.34243,-0.86727 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10371"
+ d="m 280.48828,425 c -0.4389,-0.0149 -0.66492,0.60436 -0.31958,0.87564 0.63959,0.33681 0.88258,1.10168 0.83716,1.78593 -0.006,1.35522 0.0116,2.71106 -0.009,4.06588 -0.029,0.57068 -0.33398,1.12767 -0.83582,1.41135 -0.3334,0.28584 -0.081,0.8949 0.35685,0.86114 0.46399,-0.0793 0.79448,-0.50451 1.05034,-0.86849 0.42617,-0.65052 0.45767,-1.4445 0.43766,-2.19695 -0.008,-1.24867 0.0164,-2.49826 -0.0134,-3.7463 -0.0691,-0.87707 -0.53296,-1.78778 -1.35661,-2.16868 -0.0478,-0.0138 -0.0978,-0.0204 -0.14755,-0.0195 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ transform="translate(43,63)"
+ id="g10379">
+ <path
+ inkscape:connector-curvature="0"
+ id="path10375"
+ d="m 471.5,221 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 468,224.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 8 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 480,231.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 479 v 9.29297 L 476.29297,234 H 469 v -9.29297 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ sodipodi:nodetypes="sssss"
+ inkscape:connector-curvature="0"
+ id="circle10377"
+ d="m 474,225.99805 c -1.09907,0 -2,0.90288 -2,2.00195 0,1.09907 0.90093,2 2,2 1.09907,0 2.00195,-0.90093 2.00195,-2 0,-1.09907 -0.90288,-2.00195 -2.00195,-2.00195 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00157475;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ transform="translate(0,636)"
+ id="g28780">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 531.50781,-348.00781 a 0.50005,0.50005 0 0 0 -0.5,0.5 L 531,-338.5 a 0.50005,0.50005 0 0 0 0.5,0.5 l 9.00781,-0.008 a 0.50005,0.50005 0 0 0 0.5,-0.5 c 0,-5.24079 -4.25921,-9.5 -9.5,-9.5 z m 0.5,1.10156 c 4.27858,0.26151 7.63693,3.61986 7.89844,7.89844 L 532,-339 Z"
+ id="path10381"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 542.98047,-351.00977 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 l -3,3 a 1.0001,1.0001 0 1 0 1.41406,1.41406 l 3,-3 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z"
+ id="path10384-1"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-147,636)"
+ id="g10393">
+ <path
+ sodipodi:nodetypes="sssss"
+ inkscape:connector-curvature="0"
+ id="ellipse10386"
+ d="m 560.99219,-349.49609 c 0,-1.37714 1.12676,-2.50391 2.5039,-2.50391 1.37715,0 2.50391,1.12677 2.50391,2.50391 0,1.37713 -1.12676,2.5039 -2.50391,2.5039 -1.37714,0 -2.5039,-1.12677 -2.5039,-2.5039 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="ellipse10388"
+ d="m 552,-339.99219 c 0,-1.09609 0.89673,-1.99609 1.99219,-1.99609 1.09546,0 1.99414,0.9 1.99414,1.99609 0,1.09609 -0.89868,1.99805 -1.99414,1.99805 -1.09546,0 -1.99219,-0.90196 -1.99219,-1.99805 z m 1,0 c 0,0.55685 0.43837,0.99805 0.99219,0.99805 0.55382,0 0.99414,-0.4412 0.99414,-0.99805 0,-0.55685 -0.44032,-0.99609 -0.99414,-0.99609 -0.55382,0 -0.99219,0.43924 -0.99219,0.99609 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ d="m 560.36798,-346.98792 a 0.60364676,0.60365756 0 0 0 -0.41654,0.18273 l -0.77413,0.77415 a 0.60366279,0.6036736 0 1 0 0.85273,0.8547 l 0.77609,-0.77611 a 0.60364676,0.60365756 0 0 0 -0.43815,-1.03547 z m -2.99662,2.98989 a 0.61117943,0.61029182 0 0 0 -0.42173,0.18473 l -0.78379,0.78265 a 0.61119567,0.61030804 0 1 0 0.86336,0.8641 l 0.78578,-0.78463 a 0.61117943,0.61029182 0 0 0 -0.44362,-1.04685 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.19999993;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path28690"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-210,636)"
+ id="g10409">
+ <path
+ sodipodi:nodetypes="sssss"
+ inkscape:connector-curvature="0"
+ id="ellipse10403"
+ d="m 560.99219,-349.49609 c 0,-1.37714 1.12676,-2.50391 2.5039,-2.50391 1.37715,0 2.50391,1.12677 2.50391,2.50391 0,1.37713 -1.12676,2.5039 -2.50391,2.5039 -1.37714,0 -2.5039,-1.12677 -2.5039,-2.5039 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="ellipse10405"
+ d="m 552,-339.99219 c 0,-1.09609 0.89673,-1.99609 1.99219,-1.99609 1.09546,0 1.99414,0.9 1.99414,1.99609 0,1.09609 -0.89868,1.99805 -1.99414,1.99805 -1.09546,0 -1.99219,-0.90196 -1.99219,-1.99805 z m 1,0 c 0,0.55685 0.43837,0.99805 0.99219,0.99805 0.55382,0 0.99414,-0.4412 0.99414,-0.99805 0,-0.55685 -0.44032,-0.99609 -0.99414,-0.99609 -0.55382,0 -0.99219,0.43924 -0.99219,0.99609 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10407-7"
+ d="m 563.50195,-343.01367 a 0.50005,0.50005 0 0 0 -0.49414,0.50586 v 4 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.50586,-0.50586 z m -5.99414,2.00586 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ transform="translate(42,657)"
+ id="g10415">
+ <path
+ sodipodi:nodetypes="sssss"
+ inkscape:connector-curvature="0"
+ id="ellipse10411"
+ d="m 350.99219,-370.49609 c 0,-1.37714 1.12676,-2.50391 2.5039,-2.50391 1.37715,0 2.50391,1.12677 2.50391,2.50391 0,1.37713 -1.12676,2.5039 -2.50391,2.5039 -1.37714,0 -2.5039,-1.12677 -2.5039,-2.5039 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10413-7"
+ d="m 348.4707,-367.9375 c -0.33462,0.0898 -0.64722,0.26623 -0.90039,0.51953 l -4.97851,4.98242 c -0.50693,0.50809 -0.70493,1.24983 -0.51953,1.94336 0.18541,0.69355 0.72692,1.23774 1.41992,1.42383 0.69276,0.18603 1.43437,-0.0128 1.9414,-0.52148 l 4.97852,-4.98047 c 0.50694,-0.50808 0.70495,-1.25177 0.51953,-1.94531 -0.1854,-0.69356 -0.72693,-1.23578 -1.41992,-1.42188 -0.34638,-0.093 -0.70553,-0.09 -1.04102,0 z m 0.78125,0.96484 c 0.34883,0.0937 0.61917,0.3662 0.71289,0.7168 0.0937,0.35062 -0.006,0.72222 -0.26172,0.97852 l -4.97656,4.98046 c -0.25562,0.25646 -0.62555,0.35546 -0.97461,0.26172 -0.3488,-0.0937 -0.62111,-0.36425 -0.71484,-0.71484 -0.0937,-0.35061 0.006,-0.7222 0.26172,-0.97852 l 4.97851,-4.98242 c 0.25563,-0.25646 0.62557,-0.35545 0.97461,-0.26172 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ transform="translate(0,636)"
+ id="g9298">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 306.49219,-348.01172 a 0.50005,0.50005 0 0 0 -0.38867,0.19531 l -1.95704,1.95703 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 306,-346.29883 v 5.79297 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5.79297 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.95117,-1.94922 a 0.50005,0.50005 0 0 0 0.008,-0.79883 l -1.95898,-1.95899 a 0.50005,0.50005 0 1 0 -0.70704,0.70704 l 1.14649,1.14648 H 307 v -5.29297 l 1.14648,1.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.96094,-1.96093 -0.006,-0.008 a 0.50005,0.50005 0 0 0 -0.39453,-0.1836 z"
+ id="path10419-4"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 306.44531,-351.99805 c -1.16966,-0.043 -2.35048,0.23548 -3.40039,0.84766 -2.09911,1.22396 -3.28024,3.5522 -3.00586,5.94141 0.27491,2.39372 1.98225,4.44954 4.31055,5.18554 a 0.50004997,0.50004997 0 1 0 0.30078,-0.95312 c -1.94954,-0.61628 -3.38871,-2.3582 -3.61719,-4.34766 -0.22899,-1.99397 0.75092,-3.93196 2.51563,-4.96094 1.76401,-1.02856 3.9738,-0.9382 5.67187,0.20118 0.93801,0.62937 1.92387,1.08398 3.2793,1.08398 h 1 a 0.50004997,0.50004997 0 1 0 0,-1 h -1 c -1.14457,0 -1.85649,-0.33615 -2.7207,-0.91602 -1.00565,-0.67477 -2.16433,-1.03898 -3.33399,-1.08203 z"
+ id="path10421-9"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="rotate(-180,380.49654,-26.99764)"
+ id="g10433">
+ <g
+ transform="translate(1)"
+ id="g10429">
+ <path
+ inkscape:connector-curvature="0"
+ id="path10423-5"
+ transform="rotate(180,390.49654,-26.99764)"
+ d="m 393.49219,289.00391 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 1.73047 l -2.76953,2.76953 h -1.73047 c -0.27613,2e-5 -0.49997,0.22386 -0.5,0.5 v 1.02929 c 3e-5,0.27613 0.22387,0.47068 0.5,0.47071 h 1 c 0.2725,0 0.5,0.17071 0.5,0.5 v 1 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1.73243 l 2.76758,-2.76757 h 1.73242 c 0.27613,-2e-5 0.49997,-0.22386 0.5,-0.5 v -1.02735 c -3e-5,-0.27613 -0.22387,-0.47262 -0.5,-0.47265 h -1 c -0.2725,0 -0.5,-0.17071 -0.5,-0.5 v -1 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
- <g id="g10534" transform="translate(42,-63)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 216.5,-282 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6 a 0.50005,0.50005 0 0 0 0.5,0.5 h 7 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -6 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 6 v 5 h -6 z" id="path10530" inkscape:connector-curvature="0"/>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 226.5,-289 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 12 h -2 z" id="path10532" inkscape:connector-curvature="0"/>
+ <path
+ inkscape:connector-curvature="0"
+ id="path10431-8"
+ d="m 395.47852,-349.00391 a 0.50004997,0.50004997 0 0 0 -0.32032,0.86914 c 1.10925,1.04157 1.85525,2.61894 1.8418,4.13086 -0.0174,1.95759 -1.00719,3.50006 -2.74023,4.44727 -1.67823,0.91724 -3.81516,0.64624 -5.48829,-0.40625 l 0.0234,0.0156 C 387.83199,-340.63237 386.68507,-341 385.50781,-341 H 384.5 a 0.50004997,0.50004997 0 1 0 0,1 h 1.00586 0.002 c 0.96887,0 1.91412,0.30361 2.70899,0.86914 l 0.0117,0.008 0.0117,0.008 c 1.93164,1.2151 4.44119,1.56274 6.5,0.4375 2.004,-1.0953 3.23927,-3.01733 3.25977,-5.31836 0.0163,-1.83862 -0.84967,-3.64045 -2.1582,-4.86914 a 0.50004997,0.50004997 0 0 0 -0.36328,-0.13868 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ transform="translate(20.999997,615)"
+ id="g10447">
+ <path
+ inkscape:connector-curvature="0"
+ id="path10443"
+ d="m 478.49609,-323.00781 a 0.50005,0.50005 0 0 0 -0.34765,0.85937 l 2.64648,2.64649 -2.64648,2.64648 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.70703 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10445"
+ d="m 473.4375,-330.97461 c -0.67078,0.0637 -1.33815,0.24001 -1.97461,0.53711 -2.54627,1.1886 -3.92907,3.99498 -3.32031,6.73828 0.60875,2.7433 3.04739,4.69922 5.85742,4.69922 h 2.29297 l -2.14453,2.14453 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.70703 l -3,-3 a 0.50005,0.50005 0 1 0 -0.70703,0.70703 L 476.29688,-320 H 474 c -2.34689,0 -4.37244,-1.62485 -4.88086,-3.91602 -0.50842,-2.29116 0.63902,-4.62253 2.76563,-5.61523 2.12705,-0.99291 4.66398,-0.38512 6.07812,1.48242 l 0.74023,0.97656 C 479.25532,-326.34303 480.1366,-326 481,-326 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 H 481 c -0.59704,0 -1.17055,-0.2407 -1.5,-0.67578 l -0.74023,-0.97656 c -1.27424,-1.68278 -3.30992,-2.51346 -5.32227,-2.32227 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ id="path10449"
+ d="m 391.5,263.00781 c -0.82054,0 -1.49609,0.67557 -1.49609,1.4961 0,0.82054 0.67555,1.49609 1.49609,1.49609 0.82053,0 1.49609,-0.67555 1.49609,-1.49609 0,-0.82053 -0.67556,-1.4961 -1.49609,-1.4961 z M 397,264 c -0.71373,0 -1.37556,0.3819 -1.73242,1 -0.19053,0.33001 -0.2484,0.68266 -0.25586,0.99609 v 0.0117 h -1.54297 C 393.0093,266.6044 392.2975,267 391.5,267 c -0.79751,0 -1.50931,-0.3956 -1.96875,-0.99219 h -0.0195 -5.01563 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 5.01563 0.49805 l -0.0137,3.28711 c -1.65939,1.40974 -3.24134,2.62162 -3.98828,6.10742 -0.17787,0.67446 0.8602,0.89868 0.97657,0.21094 0.67528,-3.15139 1.9234,-4.08819 3.51757,-5.42773 1.58398,1.34059 2.83152,2.27746 3.51953,5.42968 0.13318,0.66658 1.13544,0.44609 0.97657,-0.21484 -0.76273,-3.49457 -2.35105,-4.70351 -4.00196,-6.11719 l 0.0137,-3.27539 h 2.21679 1.78516 v 0.004 c 0.007,0.31344 0.0653,0.66608 0.25586,0.99609 0.35686,0.61811 1.01869,1 1.73242,1 h 0.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 397 c -0.35807,0 -0.6862,-0.1899 -0.86523,-0.5 -0.0738,-0.12789 -0.11835,-0.32209 -0.12305,-0.51953 v -0.96875 c 0.005,-0.19744 0.0492,-0.39164 0.12305,-0.51953 0.17903,-0.3101 0.50716,-0.5 0.86523,-0.5 h 0.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <g
+ transform="translate(0,636)"
+ id="g28776">
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 447.50977,297.01172 a 0.50005,0.50005 0 1 0 0,1 h 6.2832 c -0.26437,-0.28877 -0.47061,-0.62726 -0.60742,-1 z m 11.29882,0 c -0.13697,0.37274 -0.34281,0.71123 -0.60742,1 h 2.3086 a 0.50005,0.50005 0 1 0 0,-1 z"
+ transform="translate(21,-636)"
+ id="path10435" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 476.99609,-342 c 1.09999,0 2.00391,0.90231 2.00391,2.00195 0,1.09965 -0.90392,2 -2.00391,2 -1.09998,0 -2.00195,-0.90035 -2.00195,-2 0,-1.09964 0.90197,-2.00195 2.00195,-2.00195 z"
+ id="ellipse10439"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 472.49805,-351.99805 c 1.37513,0 2.50195,1.12557 2.50195,2.5 0,1.37444 -1.12682,2.49805 -2.50195,2.49805 -1.37514,0 -2.5,-1.12361 -2.5,-2.49805 0,-1.37443 1.12486,-2.5 2.5,-2.5 z m 0,1 c -0.83537,0 -1.5,0.66668 -1.5,1.5 0,0.83332 0.66463,1.49805 1.5,1.49805 0.83537,0 1.50195,-0.66473 1.50195,-1.49805 0,-0.83332 -0.66658,-1.5 -1.50195,-1.5 z"
+ id="ellipse10441"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 472.50195,-345.99609 a 0.50005,0.50005 0 0 0 -0.49218,0.50781 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50782,-0.50781 z m 0,3 a 0.50005,0.50005 0 0 0 -0.49218,0.50781 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50782,-0.50781 z"
+ id="path10451"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-126,636)"
+ id="g10457">
+ <path
+ inkscape:connector-curvature="0"
+ id="path10453"
+ transform="translate(0,-636)"
+ d="m 554.5,284 c -1.37479,0 -2.5,1.12521 -2.5,2.5 v 2.00781 c 0,1.37479 1.12521,2.5 2.5,2.5 1.37479,0 2.5,-1.12521 2.5,-2.5 v -0.5 h 1.51172 0.49805 l -0.0137,3.28711 c -1.65939,1.40974 -3.24134,2.62162 -3.98828,6.10742 -0.17787,0.67446 0.86019,0.89868 0.97657,0.21094 0.67528,-3.15139 1.9234,-4.08819 3.51757,-5.42773 1.58398,1.34059 2.83152,2.27746 3.51953,5.42968 0.13318,0.66658 1.13544,0.44609 0.97657,-0.21484 -0.76273,-3.49457 -2.35105,-4.70351 -4.00196,-6.11719 l 0.0137,-3.27539 h 2.21679 3.28516 c 0.6573,-0.009 0.6573,-0.9907 0,-1 h -3.04297 C 562.0093,287.6044 561.2975,288 560.5,288 c -0.79751,0 -1.50931,-0.3956 -1.96875,-0.99219 H 558.51172 557 V 286.5 c 0,-1.37479 -1.12521,-2.5 -2.5,-2.5 z m 6,0.008 c -0.82054,0 -1.49609,0.67557 -1.49609,1.4961 0,0.82054 0.67555,1.49609 1.49609,1.49609 0.82053,0 1.49609,-0.67555 1.49609,-1.49609 0,-0.82053 -0.67556,-1.4961 -1.49609,-1.4961 z m -6,0.992 c 0.83435,0 1.5,0.66565 1.5,1.5 v 2.00781 c 0,0.83435 -0.66565,1.5 -1.5,1.5 -0.83435,0 -1.5,-0.66565 -1.5,-1.5 V 286.5 c 0,-0.83435 0.66565,-1.5 1.5,-1.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ transform="translate(-21,615)"
+ style="opacity:0.8"
+ id="g10464">
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="path10460"
+ d="m 237.5,-323 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10462"
+ d="m 237.52148,-329 a 0.50005,0.50005 0 0 0 -0.5,0.49805 l -0.0215,4.5 1,0.004 0.0195,-4.00195 H 247 v 9 h -4 v 1 h 4.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <path
+ d="m 230,289 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,12 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ id="path10466"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="translate(-25,619)"
+ id="g10474">
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="path10468"
+ d="m 137.5,-326 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10470"
+ d="m 137.52148,-331 a 0.50005,0.50005 0 0 0 -0.5,0.49609 l -0.0215,3.5 1,0.008 0.0176,-3.00391 H 145 v 7 h -3 v 1 h 3.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -8 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10472"
+ d="m 141.52148,-335 a 0.50005,0.50005 0 0 0 -0.5,0.49609 l -0.0215,2.5 1,0.008 0.0176,-2.00391 H 149 v 7 h -2 v 1 h 2.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -8 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ transform="translate(125,-1)"
+ id="g10480"
+ style="display:inline;opacity:0.8;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ id="path10478"
+ d="m 51.492188,285.99219 a 0.50005,0.50005 0 0 0 -0.388672,0.19531 0.50005,0.50005 0 0 0 -0.0039,0.006 l -1.953125,1.95312 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 51,287.70703 V 295.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 7.792969 l -1.146485,1.14648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 1.957031,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.0059,-0.004 l -1.953125,-1.95313 a 0.50005,0.50005 0 1 0 -0.707032,0.70704 L 59.292969,295 H 52 v -7.29297 l 1.146484,1.14649 a 0.50005,0.50005 0 1 0 0.707032,-0.70704 l -1.957032,-1.95703 a 0.50005,0.50005 0 0 0 -0.404296,-0.19726 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <path
+ id="path10482"
+ d="m 197.50977,285.99609 a 0.50005,0.50005 0 0 0 -0.31055,0.10547 c -1.78384,1.33863 -2.5833,3.62488 -2.02149,5.78321 0.56181,2.15833 2.37387,3.7674 4.58399,4.0664 2.05389,0.27788 4.06729,-0.6352 5.23828,-2.31445 V 296.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -4 a 0.50005,0.50005 0 1 0 0,1 h 2.72656 c -0.95112,1.41787 -2.62038,2.19029 -4.33008,1.95898 -1.8109,-0.24499 -3.29162,-1.5577 -3.75195,-3.32617 -0.46033,-1.76847 0.19267,-3.63559 1.6543,-4.73242 a 0.50005,0.50005 0 0 0 -0.28906,-0.9043 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10484"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ d="m 167,289 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,12 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z"
+ inkscape:connector-curvature="0" />
+ <path
+ d="m 188,289 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,12 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ id="path10486"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10488"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ d="m 209,289 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,12 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10490"
+ d="m 160.5,285.99023 a 0.50005,0.50005 0 0 0 -0.34766,0.85743 l 1.14649,1.14648 -6.29297,6.29297 -1.14648,-1.14649 a 0.50005,0.50005 0 1 0 -0.70704,0.70704 l 3,3 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.14649,-1.14648 6.29297,-6.29297 1.14648,1.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -3,-3 A 0.50005,0.50005 0 0 0 160.5,285.99023 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.85;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <g
+ id="g10502"
+ transform="rotate(180,170.50319,427.50118)">
+ <path
+ id="path10492"
+ transform="rotate(-180,170.50319,427.50118)"
+ d="m 138.61719,286.00781 a 0.60006002,0.60006002 0 0 0 -0.47657,0.99024 l 1.61133,2.01953 a 1.5007322,1.5007322 0 0 1 1.2461,1.5625 l 0.92773,1.16211 a 0.60006002,0.60006002 0 0 0 0.4668,0.23242 0.60006002,0.60006002 0 0 0 0.4707,-0.98047 l -1.58789,-1.99023 1.58984,-2.00782 a 0.60006002,0.60006002 0 1 0 -0.9414,-0.74414 l -1.41602,1.78907 -1.42969,-1.79102 a 0.60006002,0.60006002 0 0 0 -0.46093,-0.24219 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10496"
+ d="m 201.60938,559.02148 a 0.60006002,0.60006002 0 0 0 -0.47071,0.98243 l 1.59766,2.00195 -1.59766,2.00195 a 0.6002929,0.6002929 0 1 0 0.9375,0.75 l 1.42774,-1.78906 1.42773,1.78906 a 0.6002929,0.6002929 0 1 0 0.9375,-0.75 l -1.59766,-2.00195 1.59766,-2.00195 a 0.6002929,0.6002929 0 1 0 -0.9375,-0.75 l -1.42773,1.78906 -1.42774,-1.78906 a 0.60006002,0.60006002 0 0 0 -0.46679,-0.23243 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10498"
+ d="m 196.50391,561 a 0.50004997,0.50004997 0 0 0 -0.22657,0.0547 c 0,0 -0.3567,0.1843 -0.66796,0.57226 C 195.29811,562.01491 195,562.63889 195,563.5 v 5 c 0,0.86111 0.29839,1.4864 0.60938,1.875 0.31098,0.3886 0.66796,0.57227 0.66796,0.57227 a 0.50004997,0.50004997 0 1 0 0.44532,-0.89454 c 0,0 -0.14302,-0.0665 -0.33204,-0.30273 C 196.20161,569.5138 196,569.13889 196,568.5 v -5 c 0,-0.63889 0.20189,-1.01282 0.39062,-1.24805 0.18874,-0.23523 0.33204,-0.30078 0.33204,-0.30078 A 0.50004997,0.50004997 0 0 0 196.50391,561 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10500"
+ d="m 207.48828,557 a 0.50004997,0.50004997 0 0 0 -0.20508,0.95117 c 0,0 0.14526,0.0655 0.33399,0.30078 0.18873,0.23523 0.38867,0.60916 0.38867,1.24805 v 5 c 0,0.63889 -0.20161,1.0138 -0.39063,1.25 -0.18901,0.2362 -0.33203,0.30273 -0.33203,0.30273 a 0.50006306,0.50006306 0 1 0 0.44727,0.89454 c 0,0 0.35503,-0.18367 0.66601,-0.57227 0.31099,-0.3886 0.60938,-1.01389 0.60938,-1.875 v -5 c 0,-0.86111 -0.29811,-1.48509 -0.60938,-1.87305 -0.31127,-0.38796 -0.66796,-0.57226 -0.66796,-0.57226 A 0.50004997,0.50004997 0 0 0 207.48828,557 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ style="opacity:1"
+ id="g10508"
+ transform="translate(-21,467)">
+ <path
+ id="path10504"
+ transform="translate(21,-467)"
+ d="m 91.347656,288.96484 a 0.51005099,0.51005099 0 0 0 -0.376953,0.20899 c -1.08977,1.44807 -1.289364,3.38767 -0.521484,5.03125 0.76787,1.64358 2.380967,2.72477 4.185547,2.80078 1.781016,0.075 3.455174,-0.8442 4.365234,-2.38086 v 1.875 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 99.5,293 h -3 a 0.50005,0.50005 0 1 0 0,1 h 1.693359 a 0.51006897,0.51006897 0 0 0 -0.03906,0.0586 c -0.71442,1.24711 -2.052293,1.98773 -3.476563,1.92774 -1.42426,-0.06 -2.695887,-0.90979 -3.304687,-2.21289 -0.60881,-1.3031 -0.449088,-2.83939 0.414062,-3.98633 a 0.51005099,0.51005099 0 0 0 -0.388671,-0.82227 0.51005099,0.51005099 0 0 0 -0.05078,0 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-18,356)"
+ id="g10514"
+ style="opacity:0.7;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke">
+ <path
+ id="path10510"
+ transform="translate(18,-356)"
+ d="m 95.398438,282.97461 a 0.50004994,0.50004994 0 0 0 -0.05078,0.002 0.50004994,0.50004994 0 0 0 -0.367187,0.20313 c -1.08755,1.44512 -1.289758,3.38123 -0.523438,5.02148 0.76632,1.64025 2.376885,2.71907 4.177735,2.79492 1.781962,0.0751 3.458632,-0.84789 4.365232,-2.38867 V 290.5 a 0.50004997,0.50004997 0 1 0 1,0 v -3 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 h -3 a 0.50004997,0.50004997 0 1 0 0,1 h 1.70312 a 0.50004994,0.50004994 0 0 0 -0.0391,0.0645 c -0.71624,1.25031 -2.05833,1.99179 -3.486324,1.93164 -1.42799,-0.0601 -2.704083,-0.91231 -3.314453,-2.21875 -0.61036,-1.30644 -0.449354,-2.8462 0.416016,-3.99609 A 0.50004994,0.50004994 0 0 0 95.3984,282.97466 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g10528"
+ transform="translate(-21,384)">
+ <g
+ style="display:inline;opacity:0.7;enable-background:new"
+ id="g10520"
+ transform="translate(46,-388)">
+ <path
+ inkscape:connector-curvature="0"
+ id="path10518"
+ d="m 50.492188,287.99219 a 0.50005,0.50005 0 0 0 -0.388672,0.19531 0.50005,0.50005 0 0 0 -0.0039,0.006 l -1.953125,1.95312 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 50,289.70703 V 295.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5.792969 l -1.146485,1.14648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 1.957031,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.0059,-0.004 l -1.953125,-1.95313 a 0.50005,0.50005 0 1 0 -0.707032,0.70704 L 56.292969,295 H 51 v -5.29297 l 1.146484,1.14649 a 0.50005,0.50005 0 1 0 0.707032,-0.70704 l -1.957032,-1.95703 a 0.50005,0.50005 0 0 0 -0.404296,-0.19726 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ transform="translate(42,-384)"
+ id="g10526"
+ style="display:inline;opacity:1;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ id="path10524"
+ d="m 50.492188,287.99219 a 0.50005,0.50005 0 0 0 -0.388672,0.19531 0.50005,0.50005 0 0 0 -0.0039,0.006 l -1.953125,1.95312 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 50,289.70703 V 295.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5.792969 l -1.146485,1.14648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 1.957031,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.0059,-0.004 l -1.953125,-1.95313 a 0.50005,0.50005 0 1 0 -0.707032,0.70704 L 56.292969,295 H 51 v -5.29297 l 1.146484,1.14649 a 0.50005,0.50005 0 1 0 0.707032,-0.70704 l -1.957032,-1.95703 a 0.50005,0.50005 0 0 0 -0.404296,-0.19726 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
</g>
- <g style="display:inline;enable-background:new" id="g36486" transform="translate(-63,-21)">
- <g transform="translate(-342.99706,-162.50454)" id="g36382" style="display:inline;opacity:1;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <path style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" d="m 695.49706,256.50454 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z" id="path36380" inkscape:connector-curvature="0" sodipodi:nodetypes="sssssccccccccccccc"/>
+ <g
+ transform="translate(21,573)"
+ id="g10534">
+ <path
+ inkscape:connector-curvature="0"
+ id="path10530"
+ d="m 216.5,-282 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6 a 0.50005,0.50005 0 0 0 0.5,0.5 h 7 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -6 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 6 v 5 h -6 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10532"
+ d="m 226.5,-289 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 12 h -2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g27713"
+ transform="translate(-80)">
+ <path
+ id="rect27779"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 618,63 h 1 v 1.999999 h -1 z m -2,0 h 1 v 1.999999 h -1 z m -2,0 h 1 v 1.999999 h -1 z M 613.53711,53 C 612.69436,53 612,53.694362 612,54.537109 v 8 2.925782 C 612,66.305638 612.69436,67 613.53711,67 h 8.92578 c 0.73741,0 1.36143,-0.531036 1.50586,-1.228516 0.0206,-0.09964 0.0312,-0.20325 0.0312,-0.308593 v -2.925782 -8 C 624,53.694362 623.30564,53 622.46289,53 Z m 0,9 h 8.92578 C 622.76894,62 623,62.231065 623,62.537109 v 2.925782 C 623,65.768935 622.76894,66 622.46289,66 h -8.92578 C 613.23106,66 613,65.768935 613,65.462891 V 62.537109 C 613,62.231065 613.23106,62 613.53711,62 Z"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ id="path27891"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 489.5,45 a 0.50004994,0.50004994 0 0 0 -0.0996,0.01172 0.50004994,0.50004994 0 0 0 -0.0937,0.03125 0.50004994,0.50004994 0 0 0 -0.0879,0.04883 0.50004994,0.50004994 0 0 0 -0.0391,0.03125 0.50004994,0.50004994 0 0 0 -0.0371,0.0332 0.50004994,0.50004994 0 0 0 -0.0312,0.03906 0.50004994,0.50004994 0 0 0 -0.0293,0.04102 0.50004994,0.50004994 0 0 0 -0.0234,0.04297 0.50004994,0.50004994 0 0 0 -0.0195,0.04687 0.50004994,0.50004994 0 0 0 -0.0156,0.04687 0.50004994,0.50004994 0 0 0 -0.01,0.04883 0.50004994,0.50004994 0 0 0 -0.002,0.150391 0.50004994,0.50004994 0 0 0 0.01,0.04883 0.50004994,0.50004994 0 0 0 0.0156,0.04687 0.50004994,0.50004994 0 0 0 0.0176,0.04687 0.50004994,0.50004994 0 0 0 0.0234,0.04297 0.50004994,0.50004994 0 0 0 0.0293,0.04297 0.50004994,0.50004994 0 0 0 0.0664,0.07227 0.50004994,0.50004994 0 0 0 0.26953,0.123047 A 0.50004994,0.50004994 0 0 0 489.5,46 h 13 a 0.50004994,0.50004994 0 0 0 0.0996,-0.01172 0.50004994,0.50004994 0 0 0 0.0469,-0.01367 0.50004994,0.50004994 0 0 0 0.0469,-0.01758 0.50004994,0.50004994 0 0 0 0.0449,-0.02148 0.50004994,0.50004994 0 0 0 0.082,-0.05859 0.50004994,0.50004994 0 0 0 0.0371,-0.0332 0.50004994,0.50004994 0 0 0 0.0312,-0.03906 0.50004994,0.50004994 0 0 0 0.0723,-0.13086 0.50004994,0.50004994 0 0 0 0.0156,-0.04687 0.50004994,0.50004994 0 0 0 0.0156,-0.09961 0.50004994,0.50004994 0 0 0 0,-0.04883 0.50004994,0.50004994 0 0 0 -0.0137,-0.09961 0.50004994,0.50004994 0 0 0 -0.0156,-0.04687 0.50004994,0.50004994 0 0 0 -0.0176,-0.04687 0.50004994,0.50004994 0 0 0 -0.0527,-0.08594 0.50004994,0.50004994 0 0 0 -0.0312,-0.03711 0.50004994,0.50004994 0 0 0 -0.0742,-0.06641 0.50004994,0.50004994 0 0 0 -0.043,-0.02734 0.50004994,0.50004994 0 0 0 -0.043,-0.02344 0.50004994,0.50004994 0 0 0 -0.0469,-0.01758 0.50004994,0.50004994 0 0 0 -0.0488,-0.01367 0.50004994,0.50004994 0 0 0 -0.0488,-0.0098 A 0.50004994,0.50004994 0 0 0 502.5,45 Z m 4.5,-3.5 c -3e-5,0.276131 -0.22387,0.499972 -0.5,0.5 h -2 c -0.27613,-2.8e-5 -0.49997,-0.223869 -0.5,-0.5 v -2 c 3e-5,-0.276131 0.22387,-0.499972 0.5,-0.5 h 2 c 0.27613,2.8e-5 0.49997,0.223869 0.5,0.5 z M 493,41 v -1 h -1 v 1 z m 5,-3.5 c -3e-5,0.276131 -0.22387,0.499972 -0.5,0.5 h -2 c -0.27613,-2.8e-5 -0.49997,-0.223869 -0.5,-0.5 v -2 c 3e-5,-0.276131 0.22387,-0.499972 0.5,-0.5 h 2 c 0.27613,2.8e-5 0.49997,0.223869 0.5,0.5 z m -4,0 c -3e-5,0.276131 -0.22387,0.499972 -0.5,0.5 h -2 c -0.27613,-2.8e-5 -0.49997,-0.223869 -0.5,-0.5 v -2 c 3e-5,-0.276131 0.22387,-0.499972 0.5,-0.5 h 2 c 0.27613,2.8e-5 0.49997,0.223869 0.5,0.5 z M 489.5,33 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 10 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 13 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -10 A 0.50004997,0.50004997 0 0 0 502.5,33 Z m 0.5,1 h 12 v 9 h -12 z"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g27886"
+ transform="translate(-123,-21)">
+ <g
+ style="display:inline;enable-background:new"
+ id="g28033"
+ transform="translate(21,-21)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00157475;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 516.03711,33 C 514.91694,33 514,33.916938 514,35.037109 V 36 c -0.0409,0.706384 1.0409,0.706384 1,0 V 35.037109 C 515,34.454485 515.45448,34 516.03711,34 h 4.92578 C 521.54552,34 522,34.454485 522,35.037109 v 5.058594 c -0.58287,0.214917 -1,0.784943 -1,1.441406 v 1.925782 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 H 522 V 46 h 1 v -2.037109 h 0.5 c 0.27613,-2.8e-5 0.49997,-0.223869 0.5,-0.5 v -1.925782 c 0,-0.656467 -0.41713,-1.22649 -1,-1.441406 V 35.037109 C 523,33.916938 522.08306,33 520.96289,33 Z"
+ transform="translate(102,41)"
+ id="path28027"
+ inkscape:connector-curvature="0" />
</g>
- <g id="g36393" style="display:inline;enable-background:new" transform="translate(-587.00005,105)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 279.5,77 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 10 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 11 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -6 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 280 v -3 h 2 v 0.5 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 h 3.26562 c -0.20665,-0.306775 -0.36146,-0.646717 -0.48828,-1 H 283 v -0.5 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m 0.5,5 h 10 v 5 h -10 z" transform="translate(650.00005,-84)" id="path36378" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccc"/>
+ <g
+ style="display:inline;enable-background:new"
+ id="g28053-2">
+ <path
+ inkscape:connector-curvature="0"
+ id="rect28051-4"
+ transform="translate(21,-21)"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 616,85 h 1 v 0.999999 h -1 z m -2,0 h 1 v 0.999999 h -1 z m -0.46289,-8 C 612.69436,77 612,77.694362 612,78.537109 v 7.925782 C 612,87.305638 612.69436,88 613.53711,88 h 5.92578 c 0.73741,0 1.36143,-0.531036 1.50586,-1.228516 0.0206,-0.09964 0.0312,-0.20325 0.0312,-0.308593 V 78.537109 C 621,77.694362 620.30564,77 619.46289,77 Z m 0,7 h 5.92578 C 619.76894,84 620,84.231065 620,84.537109 v 1.925782 C 620,86.768935 619.76894,87 619.46289,87 h -5.92578 C 613.23106,87 613,86.768935 613,86.462891 V 84.537109 C 613,84.231065 613.23106,84 613.53711,84 Z" />
</g>
</g>
- <g style="display:inline;enable-background:new" id="g36374-6" transform="translate(-881.00006,546)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 90.5,536 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 13 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 95 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,5 h 12 v 8 H 91 Z" transform="translate(881.00006,-546)" id="rect36366-6" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccccc"/>
+ <g
+ id="g27900"
+ transform="translate(-123,-21)">
+ <g
+ transform="translate(0,-21)"
+ id="g28156">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 543.5,33 c -0.8225,0 -1.5,0.677492 -1.5,1.5 0,0.230167 0.0579,0.446791 0.15234,0.642578 a 0.50005,0.50005 0 0 0 -0.006,0.0039 L 540.29297,37 H 539.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.35352,-0.146484 l 2,-2 a 0.50005,0.50005 0 0 0 0.004,-0.0059 C 543.05321,35.942094 543.26984,36 543.5,36 c 0.8225,0 1.5,-0.677492 1.5,-1.5 0,-0.822508 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.217938 0.5,0.5 0,0.282062 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.217938 -0.5,-0.5 0,-0.282062 0.21794,-0.5 0.5,-0.5 z m 0,5 c -0.64684,0 -1.19777,0.420971 -1.40625,1 H 539.5 a 0.50005,0.50005 0 1 0 0,1 h 2.59375 c 0.20848,0.579029 0.75941,1 1.40625,1 0.8225,0 1.5,-0.677492 1.5,-1.5 0,-0.822508 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.217938 0.5,0.5 0,0.282062 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.217938 -0.5,-0.5 0,-0.282062 0.21794,-0.5 0.5,-0.5 z m -4,2.992188 a 0.50005,0.50005 0 1 0 0,1 h 0.79297 l 1.85351,1.853515 a 0.50005,0.50005 0 0 0 0.008,0.0078 C 542.05866,46.050309 542,46.268282 542,46.5 c 0,0.822508 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.677492 1.5,-1.5 0,-0.822508 -0.6775,-1.5 -1.5,-1.5 -0.22767,0 -0.44256,0.05591 -0.63672,0.148438 a 0.50005,0.50005 0 0 0 -0.01,-0.0098 l -2,-2 A 0.50005,0.50005 0 0 0 540.5,42.992188 Z M 543.5,46 c 0.28206,0 0.5,0.217938 0.5,0.5 0,0.282062 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.217938 -0.5,-0.5 0,-0.282062 0.21794,-0.5 0.5,-0.5 z"
+ transform="translate(123,41)"
+ id="circle28098"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g28053"
+ transform="translate(21)">
+ <path
+ id="rect28051"
+ transform="translate(21,-21)"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 616,85 h 1 v 0.999999 h -1 z m -2,0 h 1 v 0.999999 h -1 z m -0.46289,-8 C 612.69436,77 612,77.694362 612,78.537109 v 7.925782 C 612,87.305638 612.69436,88 613.53711,88 h 5.92578 c 0.73741,0 1.36143,-0.531036 1.50586,-1.228516 0.0206,-0.09964 0.0312,-0.20325 0.0312,-0.308593 V 78.537109 C 621,77.694362 620.30564,77 619.46289,77 Z m 0,7 h 5.92578 C 619.76894,84 620,84.231065 620,84.537109 v 1.925782 C 620,86.768935 619.76894,87 619.46289,87 h -5.92578 C 613.23106,87 613,86.768935 613,86.462891 V 84.537109 C 613,84.231065 613.23106,84 613.53711,84 Z"
+ inkscape:connector-curvature="0" />
+ </g>
</g>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 363.5,74 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 13 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 368 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,5 h 12 v 8 h -12 z" id="rect36366-6-8" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccccc"/>
- <g style="display:inline;enable-background:new" id="g28096">
- <path sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccssccccccsssc" inkscape:connector-curvature="0" id="path27877" d="m 406.5,53 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 11 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 h 4.5 v -1 h -4 V 54 h 5 v 1 h 2 v -1 h 5 v 10 h -2 v 1 h 2.5 c 0.27613,-2.8e-5 0.49997,-0.223869 0.5,-0.5 v -11 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m 7.5,2 v 1 h 2 v -1 z m 0,1 h -2 v 1 h 2 z m 0,1 v 1 h 2 v -1 z m 0,1 h -2 v 1 h 2 z m 0,1 v 1 h 2 v -1 z m 0,1 h -2 v 1 h 2 z m 0,1 v 1 h -1.5 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 V 65 c 0,1.099351 0.90065,2 2,2 1.09935,0 2,-0.900649 2,-2 v -4 z m -1,2 h 1 1 v 2 c 0,0.562649 -0.43735,1 -1,1 -0.56265,0 -1,-0.437351 -1,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- <g transform="translate(-80)" id="g27713" style="display:inline;enable-background:new">
- <path inkscape:connector-curvature="0" d="m 618,63 h 1 v 1.999999 h -1 z m -2,0 h 1 v 1.999999 h -1 z m -2,0 h 1 v 1.999999 h -1 z M 613.53711,53 C 612.69436,53 612,53.694362 612,54.537109 v 8 2.925782 C 612,66.305638 612.69436,67 613.53711,67 h 8.92578 c 0.73741,0 1.36143,-0.531036 1.50586,-1.228516 0.0206,-0.09964 0.0312,-0.20325 0.0312,-0.308593 v -2.925782 -8 C 624,53.694362 623.30564,53 622.46289,53 Z m 0,9 h 8.92578 C 622.76894,62 623,62.231065 623,62.537109 v 2.925782 C 623,65.768935 622.76894,66 622.46289,66 h -8.92578 C 613.23106,66 613,65.768935 613,65.462891 V 62.537109 C 613,62.231065 613.23106,62 613.53711,62 Z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" id="rect27779"/>
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 511.5,452 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.64684,0 1.19777,-0.42097 1.40625,-1 h 1.1875 c 0.20848,0.57903 0.75941,1 1.40625,1 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 -0.64637,0 -1.19742,0.42162 -1.40625,1 h -1.1875 c -0.20883,-0.57838 -0.75988,-1 -1.40625,-1 z m 11,0 c -0.64637,0 -1.19742,0.42162 -1.40625,1 H 520.5 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 516.29297,457 h -3.38672 c -0.20883,-0.57838 -0.75988,-1 -1.40625,-1 -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.64684,0 1.19777,-0.42097 1.40625,-1 H 516.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 L 520.70703,454 h 0.38672 c 0.20848,0.57903 0.75941,1 1.40625,1 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -11,1 c 0.27091,0 0.47782,0.20294 0.49414,0.46875 a 0.50005,0.50005 0 0 0 0,0.0625 C 511.97782,453.79707 511.77091,454 511.5,454 c -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 4,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.27091,0 -0.47782,-0.20293 -0.49414,-0.46875 a 0.50005,0.50005 0 0 0 0,-0.0625 C 515.02218,453.20294 515.22909,453 515.5,453 Z m 7,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.27091,0 -0.47782,-0.20293 -0.49414,-0.46875 a 0.50005,0.50005 0 0 0 0,-0.0625 C 522.02218,453.20294 522.22909,453 522.5,453 Z m 0,3 c -0.64637,0 -1.19742,0.42162 -1.40625,1 H 520.5 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -5,5 A 0.50005,0.50005 0 0 0 515,462.5 v 0.59375 c -0.57903,0.20848 -1,0.75941 -1,1.40625 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.64684 -0.42097,-1.19777 -1,-1.40625 v -0.38672 L 520.70703,458 h 0.38672 c 0.20848,0.57903 0.75941,1 1.40625,1 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -11,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 11,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.27091,0 -0.47782,-0.20293 -0.49414,-0.46875 a 0.50005,0.50005 0 0 0 0,-0.0625 C 522.02218,457.20294 522.22909,457 522.5,457 Z m -11,3 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 11,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.23017 0.0579,0.44679 0.15234,0.64258 a 0.50005,0.50005 0 0 0 -0.006,0.004 l -1,1 a 0.50005,0.50005 0 0 0 -0.004,0.006 C 519.94679,463.05791 519.73016,463 519.5,463 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.23002 -0.058,-0.44493 -0.15234,-0.64062 a 0.50005,0.50005 0 0 0 0.006,-0.006 l 1,-1 a 0.50005,0.50005 0 0 0 0.004,-0.004 c 0.1955,0.0946 0.41225,0.15062 0.64234,0.15062 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -11,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 11,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m -3,3 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m -4.0293,0.006 a 0.50005,0.50005 0 0 0 0.0371,0 0.50005,0.50005 0 0 0 0.0176,0 c 0.26874,0.0134 0.4746,0.22107 0.4746,0.494 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.27158 0.20391,-0.47876 0.4707,-0.49414 z"
+ id="circle28282" />
+ <g
+ id="g27867"
+ transform="translate(41.999996,-83.999998)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 114.5,97 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 10 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m -3,6 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 10 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path27865"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccc" />
+ </g>
+ <g
+ id="g28017"
+ transform="translate(-42.000004,-83.999998)">
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ style="display:inline;opacity:1;enable-background:new"
+ id="g13408-5"
+ transform="translate(-357.00711,41.992878)">
+ <g
+ style="display:inline;opacity:0.98999999;enable-background:new"
+ transform="translate(378.99999,-439.99995)"
+ id="g12509-8" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 531.49219,52.992188 a 0.50005,0.50005 0 0 0 -0.31641,0.121093 0.50005,0.50005 0 0 0 -0.0195,0.01563 0.50005,0.50005 0 0 0 -0.0176,0.01758 0.50005,0.50005 0 0 0 -0.002,0.0039 0.50005,0.50005 0 0 0 -0.0312,0.0332 0.50005,0.50005 0 0 0 -0.002,0.0039 0.50005,0.50005 0 0 0 -0.0273,0.03711 0.50005,0.50005 0 0 0 -0.002,0.0039 A 0.50005,0.50005 0 0 0 531,53.582031 V 54.5 a 0.50005,0.50005 0 1 0 1,0 V 54 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 h -0.91992 a 0.50005,0.50005 0 0 0 -0.0879,-0.0078 z m 13,0 A 0.50005,0.50005 0 0 0 544.41797,53 H 543.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.919922 a 0.50005,0.50005 0 0 0 -0.11328,-0.404297 0.50005,0.50005 0 0 0 -0.002,-0.0039 0.50005,0.50005 0 0 0 -0.0312,-0.0332 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.0332,-0.03125 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.32031,-0.111328 z M 534.5,53 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m -9.00781,2.992188 A 0.50005,0.50005 0 0 0 531,56.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 13,0 A 0.50005,0.50005 0 0 0 544,56.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m -13,3 A 0.50005,0.50005 0 0 0 531,59.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 13,0 A 0.50005,0.50005 0 0 0 544,59.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m -13,3 A 0.50005,0.50005 0 0 0 531,62.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 13,0 A 0.50005,0.50005 0 0 0 544,62.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m -13,3 A 0.50005,0.50005 0 0 0 531,65.5 v 0.919922 a 0.50005,0.50005 0 0 0 0.11328,0.404297 0.50005,0.50005 0 0 0 0.0156,0.01953 0.50005,0.50005 0 0 0 0.0176,0.01758 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.03125 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 531.58203,67 H 532.5 a 0.50005,0.50005 0 1 0 0,-1 H 532 v -0.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 13,0 A 0.50005,0.50005 0 0 0 544,65.5 V 66 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.91992 a 0.50005,0.50005 0 0 0 0.4043,-0.113281 0.50005,0.50005 0 0 0 0.004,-0.002 0.50005,0.50005 0 0 0 0.0332,-0.03125 0.50005,0.50005 0 0 0 0.002,-0.0039 0.50005,0.50005 0 0 0 0.0312,-0.0332 0.50005,0.50005 0 0 0 0.002,-0.0039 A 0.50005,0.50005 0 0 0 545,66.417969 V 65.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z M 534.5,66 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path27987"
+ inkscape:connector-curvature="0" />
</g>
- <path inkscape:connector-curvature="0" d="m 489.5,45 a 0.50004994,0.50004994 0 0 0 -0.0996,0.01172 0.50004994,0.50004994 0 0 0 -0.0937,0.03125 0.50004994,0.50004994 0 0 0 -0.0879,0.04883 0.50004994,0.50004994 0 0 0 -0.0391,0.03125 0.50004994,0.50004994 0 0 0 -0.0371,0.0332 0.50004994,0.50004994 0 0 0 -0.0312,0.03906 0.50004994,0.50004994 0 0 0 -0.0293,0.04102 0.50004994,0.50004994 0 0 0 -0.0234,0.04297 0.50004994,0.50004994 0 0 0 -0.0195,0.04687 0.50004994,0.50004994 0 0 0 -0.0156,0.04687 0.50004994,0.50004994 0 0 0 -0.01,0.04883 0.50004994,0.50004994 0 0 0 -0.002,0.150391 0.50004994,0.50004994 0 0 0 0.01,0.04883 0.50004994,0.50004994 0 0 0 0.0156,0.04687 0.50004994,0.50004994 0 0 0 0.0176,0.04687 0.50004994,0.50004994 0 0 0 0.0234,0.04297 0.50004994,0.50004994 0 0 0 0.0293,0.04297 0.50004994,0.50004994 0 0 0 0.0664,0.07227 0.50004994,0.50004994 0 0 0 0.26953,0.123047 A 0.50004994,0.50004994 0 0 0 489.5,46 h 13 a 0.50004994,0.50004994 0 0 0 0.0996,-0.01172 0.50004994,0.50004994 0 0 0 0.0469,-0.01367 0.50004994,0.50004994 0 0 0 0.0469,-0.01758 0.50004994,0.50004994 0 0 0 0.0449,-0.02148 0.50004994,0.50004994 0 0 0 0.082,-0.05859 0.50004994,0.50004994 0 0 0 0.0371,-0.0332 0.50004994,0.50004994 0 0 0 0.0312,-0.03906 0.50004994,0.50004994 0 0 0 0.0723,-0.13086 0.50004994,0.50004994 0 0 0 0.0156,-0.04687 0.50004994,0.50004994 0 0 0 0.0156,-0.09961 0.50004994,0.50004994 0 0 0 0,-0.04883 0.50004994,0.50004994 0 0 0 -0.0137,-0.09961 0.50004994,0.50004994 0 0 0 -0.0156,-0.04687 0.50004994,0.50004994 0 0 0 -0.0176,-0.04687 0.50004994,0.50004994 0 0 0 -0.0527,-0.08594 0.50004994,0.50004994 0 0 0 -0.0312,-0.03711 0.50004994,0.50004994 0 0 0 -0.0742,-0.06641 0.50004994,0.50004994 0 0 0 -0.043,-0.02734 0.50004994,0.50004994 0 0 0 -0.043,-0.02344 0.50004994,0.50004994 0 0 0 -0.0469,-0.01758 0.50004994,0.50004994 0 0 0 -0.0488,-0.01367 0.50004994,0.50004994 0 0 0 -0.0488,-0.0098 A 0.50004994,0.50004994 0 0 0 502.5,45 Z m 4.5,-3.5 c -3e-5,0.276131 -0.22387,0.499972 -0.5,0.5 h -2 c -0.27613,-2.8e-5 -0.49997,-0.223869 -0.5,-0.5 v -2 c 3e-5,-0.276131 0.22387,-0.499972 0.5,-0.5 h 2 c 0.27613,2.8e-5 0.49997,0.223869 0.5,0.5 z M 493,41 v -1 h -1 v 1 z m 5,-3.5 c -3e-5,0.276131 -0.22387,0.499972 -0.5,0.5 h -2 c -0.27613,-2.8e-5 -0.49997,-0.223869 -0.5,-0.5 v -2 c 3e-5,-0.276131 0.22387,-0.499972 0.5,-0.5 h 2 c 0.27613,2.8e-5 0.49997,0.223869 0.5,0.5 z m -4,0 c -3e-5,0.276131 -0.22387,0.499972 -0.5,0.5 h -2 c -0.27613,-2.8e-5 -0.49997,-0.223869 -0.5,-0.5 v -2 c 3e-5,-0.276131 0.22387,-0.499972 0.5,-0.5 h 2 c 0.27613,2.8e-5 0.49997,0.223869 0.5,0.5 z M 489.5,33 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 10 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 13 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -10 A 0.50004997,0.50004997 0 0 0 502.5,33 Z m 0.5,1 h 12 v 9 h -12 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" id="path27891"/>
- <g transform="translate(-123,-21)" id="g27886">
- <g transform="translate(21,-21)" id="g28033" style="display:inline;enable-background:new">
- <path inkscape:connector-curvature="0" id="path28027" transform="translate(102,41)" d="M 516.03711,33 C 514.91694,33 514,33.916938 514,35.037109 V 36 c -0.0409,0.706384 1.0409,0.706384 1,0 V 35.037109 C 515,34.454485 515.45448,34 516.03711,34 h 4.92578 C 521.54552,34 522,34.454485 522,35.037109 v 5.058594 c -0.58287,0.214917 -1,0.784943 -1,1.441406 v 1.925782 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 H 522 V 46 h 1 v -2.037109 h 0.5 c 0.27613,-2.8e-5 0.49997,-0.223869 0.5,-0.5 v -1.925782 c 0,-0.656467 -0.41713,-1.22649 -1,-1.441406 V 35.037109 C 523,33.916938 522.08306,33 520.96289,33 Z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00157475;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
- <g id="g28053-2" style="display:inline;enable-background:new">
- <path d="m 616,85 h 1 v 0.999999 h -1 z m -2,0 h 1 v 0.999999 h -1 z m -0.46289,-8 C 612.69436,77 612,77.694362 612,78.537109 v 7.925782 C 612,87.305638 612.69436,88 613.53711,88 h 5.92578 c 0.73741,0 1.36143,-0.531036 1.50586,-1.228516 0.0206,-0.09964 0.0312,-0.20325 0.0312,-0.308593 V 78.537109 C 621,77.694362 620.30564,77 619.46289,77 Z m 0,7 h 5.92578 C 619.76894,84 620,84.231065 620,84.537109 v 1.925782 C 620,86.768935 619.76894,87 619.46289,87 h -5.92578 C 613.23106,87 613,86.768935 613,86.462891 V 84.537109 C 613,84.231065 613.23106,84 613.53711,84 Z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" transform="translate(21,-21)" id="rect28051-4" inkscape:connector-curvature="0"/>
- </g>
+ <g
+ transform="rotate(-180,149.5,102.00001)"
+ id="g27919-7"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 117.5,98 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 2 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m -4,5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path27916-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccc" />
</g>
- <g transform="translate(-123,-21)" id="g27900">
- <g id="g28156" transform="translate(0,-21)">
- <path inkscape:connector-curvature="0" id="circle28098" transform="translate(123,41)" d="m 543.5,33 c -0.8225,0 -1.5,0.677492 -1.5,1.5 0,0.230167 0.0579,0.446791 0.15234,0.642578 a 0.50005,0.50005 0 0 0 -0.006,0.0039 L 540.29297,37 H 539.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.35352,-0.146484 l 2,-2 a 0.50005,0.50005 0 0 0 0.004,-0.0059 C 543.05321,35.942094 543.26984,36 543.5,36 c 0.8225,0 1.5,-0.677492 1.5,-1.5 0,-0.822508 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.217938 0.5,0.5 0,0.282062 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.217938 -0.5,-0.5 0,-0.282062 0.21794,-0.5 0.5,-0.5 z m 0,5 c -0.64684,0 -1.19777,0.420971 -1.40625,1 H 539.5 a 0.50005,0.50005 0 1 0 0,1 h 2.59375 c 0.20848,0.579029 0.75941,1 1.40625,1 0.8225,0 1.5,-0.677492 1.5,-1.5 0,-0.822508 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.217938 0.5,0.5 0,0.282062 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.217938 -0.5,-0.5 0,-0.282062 0.21794,-0.5 0.5,-0.5 z m -4,2.992188 a 0.50005,0.50005 0 1 0 0,1 h 0.79297 l 1.85351,1.853515 a 0.50005,0.50005 0 0 0 0.008,0.0078 C 542.05866,46.050309 542,46.268282 542,46.5 c 0,0.822508 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.677492 1.5,-1.5 0,-0.822508 -0.6775,-1.5 -1.5,-1.5 -0.22767,0 -0.44256,0.05591 -0.63672,0.148438 a 0.50005,0.50005 0 0 0 -0.01,-0.0098 l -2,-2 A 0.50005,0.50005 0 0 0 540.5,42.992188 Z M 543.5,46 c 0.28206,0 0.5,0.217938 0.5,0.5 0,0.282062 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.217938 -0.5,-0.5 0,-0.282062 0.21794,-0.5 0.5,-0.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
- <g transform="translate(21)" id="g28053">
- <path inkscape:connector-curvature="0" d="m 616,85 h 1 v 0.999999 h -1 z m -2,0 h 1 v 0.999999 h -1 z m -0.46289,-8 C 612.69436,77 612,77.694362 612,78.537109 v 7.925782 C 612,87.305638 612.69436,88 613.53711,88 h 5.92578 c 0.73741,0 1.36143,-0.531036 1.50586,-1.228516 0.0206,-0.09964 0.0312,-0.20325 0.0312,-0.308593 V 78.537109 C 621,77.694362 620.30564,77 619.46289,77 Z m 0,7 h 5.92578 C 619.76894,84 620,84.231065 620,84.537109 v 1.925782 C 620,86.768935 619.76894,87 619.46289,87 h -5.92578 C 613.23106,87 613,86.768935 613,86.462891 V 84.537109 C 613,84.231065 613.23106,84 613.53711,84 Z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" transform="translate(21,-21)" id="rect28051"/>
+ </g>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ id="g27948"
+ transform="translate(62.999996,-19.999998)"
+ style="display:inline;opacity:1;enable-background:new">
+ <g
+ id="g27945"
+ transform="translate(1,-1)">
+ <g
+ id="g27954">
+ <path
+ id="path27939"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 237.49414,326.05078 c -0.11724,0.001 -0.22936,0.0482 -0.3125,0.13086 l -2,2 c -0.17593,0.17578 -0.17593,0.46094 0,0.63672 l 2,2 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 2,-2 c 0.17593,-0.17578 0.17593,-0.46094 0,-0.63672 l -2,-2 c -0.086,-0.0855 -0.20293,-0.13272 -0.32422,-0.13086 z m 11,0 c -0.11724,0.001 -0.22936,0.0482 -0.3125,0.13086 l -2,2 c -0.17593,0.17578 -0.17593,0.46094 0,0.63672 l 2,2 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 2,-2 c 0.17593,-0.17578 0.17593,-0.46094 0,-0.63672 l -2,-2 c -0.086,-0.0855 -0.20293,-0.13272 -0.32422,-0.13086 z m -6.02734,6.75 a 0.45004499,0.45004499 0 0 0 -0.29688,0.14453 l -3,3.25 a 0.45004499,0.45004499 0 0 0 0.0117,0.62305 l 3,3 a 0.45004499,0.45004499 0 0 0 0.63672,0 l 3,-3 a 0.45004499,0.45004499 0 0 0 0.0117,-0.62305 l -3,-3.25 a 0.45004499,0.45004499 0 0 0 -0.36328,-0.14453 z m 0.0332,1.11133 2.37695,2.57617 -2.37695,2.375 -2.37695,-2.37695 z"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="path27943"
+ d="m 239.12109,326 1.43946,1.43945 c 0.58556,0.5858 0.58556,1.5353 0,2.1211 L 239.12109,331 h 7.75782 l -1.43946,-1.43945 c -0.58556,-0.5858 -0.58556,-1.5353 0,-2.1211 L 246.87891,326 Z"
+ style="opacity:0.5;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" />
</g>
</g>
- <path id="circle28282" d="m 511.5,452 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.64684,0 1.19777,-0.42097 1.40625,-1 h 1.1875 c 0.20848,0.57903 0.75941,1 1.40625,1 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 -0.64637,0 -1.19742,0.42162 -1.40625,1 h -1.1875 c -0.20883,-0.57838 -0.75988,-1 -1.40625,-1 z m 11,0 c -0.64637,0 -1.19742,0.42162 -1.40625,1 H 520.5 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 516.29297,457 h -3.38672 c -0.20883,-0.57838 -0.75988,-1 -1.40625,-1 -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.64684,0 1.19777,-0.42097 1.40625,-1 H 516.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 L 520.70703,454 h 0.38672 c 0.20848,0.57903 0.75941,1 1.40625,1 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -11,1 c 0.27091,0 0.47782,0.20294 0.49414,0.46875 a 0.50005,0.50005 0 0 0 0,0.0625 C 511.97782,453.79707 511.77091,454 511.5,454 c -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 4,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.27091,0 -0.47782,-0.20293 -0.49414,-0.46875 a 0.50005,0.50005 0 0 0 0,-0.0625 C 515.02218,453.20294 515.22909,453 515.5,453 Z m 7,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.27091,0 -0.47782,-0.20293 -0.49414,-0.46875 a 0.50005,0.50005 0 0 0 0,-0.0625 C 522.02218,453.20294 522.22909,453 522.5,453 Z m 0,3 c -0.64637,0 -1.19742,0.42162 -1.40625,1 H 520.5 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -5,5 A 0.50005,0.50005 0 0 0 515,462.5 v 0.59375 c -0.57903,0.20848 -1,0.75941 -1,1.40625 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.64684 -0.42097,-1.19777 -1,-1.40625 v -0.38672 L 520.70703,458 h 0.38672 c 0.20848,0.57903 0.75941,1 1.40625,1 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -11,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 11,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.27091,0 -0.47782,-0.20293 -0.49414,-0.46875 a 0.50005,0.50005 0 0 0 0,-0.0625 C 522.02218,457.20294 522.22909,457 522.5,457 Z m -11,3 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 11,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.23017 0.0579,0.44679 0.15234,0.64258 a 0.50005,0.50005 0 0 0 -0.006,0.004 l -1,1 a 0.50005,0.50005 0 0 0 -0.004,0.006 C 519.94679,463.05791 519.73016,463 519.5,463 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.23002 -0.058,-0.44493 -0.15234,-0.64062 a 0.50005,0.50005 0 0 0 0.006,-0.006 l 1,-1 a 0.50005,0.50005 0 0 0 0.004,-0.004 c 0.1955,0.0946 0.41225,0.15062 0.64234,0.15062 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -11,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 11,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m -3,3 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m -4.0293,0.006 a 0.50005,0.50005 0 0 0 0.0371,0 0.50005,0.50005 0 0 0 0.0176,0 c 0.26874,0.0134 0.4746,0.22107 0.4746,0.494 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.27158 0.20391,-0.47876 0.4707,-0.49414 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" inkscape:connector-curvature="0"/>
</g>
- <g transform="translate(-4.4569653e-6,1.6485533e-6)" style="display:inline;enable-background:new" id="g27998">
- <g transform="translate(42,-84)" id="g27867">
- <path sodipodi:nodetypes="cccccccccccccccccc" inkscape:connector-curvature="0" id="path27865" d="m 114.5,97 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 10 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m -3,6 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 10 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
+ <path
+ inkscape:connector-curvature="0"
+ id="path27826"
+ d="m 226.98047,602.99023 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 L 222,607.58594 l -2.29297,-2.29297 a 1.0001,1.0001 0 1 0 -1.41406,1.41406 l 3,3 a 1.0001,1.0001 0 0 0 1.41406,0 l 5,-5 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <g
+ style="fill:#ffffff"
+ id="g28127"
+ transform="translate(-42,21)">
+ <path
+ inkscape:connector-curvature="0"
+ id="rect28073"
+ d="m 468.5,116 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 7 a 0.50005,0.50005 0 1 0 0,-1 H 469 v -9 h 9 v 6.5 a 0.50005,0.50005 0 1 0 1,0 v -7 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ d="M 475.99635,122 A 1.99635,1.99635 0 0 1 474,123.99635 1.99635,1.99635 0 0 1 472.00365,122 1.99635,1.99635 0 0 1 474,120.00365 1.99635,1.99635 0 0 1 475.99635,122 Z m 0.50756,2.01562 c -0.44709,0.002 -0.6672,0.54472 -0.34766,0.85743 l 4.14648,4.14648 L 477.5,129 c -0.67616,-0.01 -0.67616,1.00956 0,1 l 4.00977,0.0195 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 L 482,125.5 c 0.01,-0.67616 -1.00956,-0.67616 -1,0 l 0.01,2.8125 -4.14649,-4.14648 c -0.0945,-0.0966 -0.22417,-0.15091 -0.35937,-0.1504 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="circle28066" />
+ </g>
+ <g
+ id="g28092"
+ transform="translate(0,-20)"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 363.5,95 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 V 99 h 14 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 368 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path28072"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccc" />
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="rect28074"
+ d="m 363.5,100 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 7 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -7 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ id="g28092-0"
+ transform="translate(-273,442)"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 363.5,95 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 V 99 h 14 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 368 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path28072-2"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccc" />
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="rect28074-9"
+ d="m 363.5,100 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 7 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -7 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ transform="translate(-63,-21)"
+ id="g36486"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g36382"
+ transform="translate(-342.99706,-162.50454)">
+ <path
+ sodipodi:nodetypes="sssssccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path36380"
+ d="m 695.49706,256.50454 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" />
</g>
- <g transform="translate(-42,-84)" id="g28017">
- <g transform="translate(-357.00711,41.992878)" id="g13408-5" style="display:inline;opacity:1;enable-background:new" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g id="g12509-8" transform="translate(378.99999,-439.99995)" style="display:inline;opacity:0.98999999;enable-background:new"/>
- <path inkscape:connector-curvature="0" id="path27987" d="m 531.49219,52.992188 a 0.50005,0.50005 0 0 0 -0.31641,0.121093 0.50005,0.50005 0 0 0 -0.0195,0.01563 0.50005,0.50005 0 0 0 -0.0176,0.01758 0.50005,0.50005 0 0 0 -0.002,0.0039 0.50005,0.50005 0 0 0 -0.0312,0.0332 0.50005,0.50005 0 0 0 -0.002,0.0039 0.50005,0.50005 0 0 0 -0.0273,0.03711 0.50005,0.50005 0 0 0 -0.002,0.0039 A 0.50005,0.50005 0 0 0 531,53.582031 V 54.5 a 0.50005,0.50005 0 1 0 1,0 V 54 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 h -0.91992 a 0.50005,0.50005 0 0 0 -0.0879,-0.0078 z m 13,0 A 0.50005,0.50005 0 0 0 544.41797,53 H 543.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.919922 a 0.50005,0.50005 0 0 0 -0.11328,-0.404297 0.50005,0.50005 0 0 0 -0.002,-0.0039 0.50005,0.50005 0 0 0 -0.0312,-0.0332 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.0332,-0.03125 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.32031,-0.111328 z M 534.5,53 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m -9.00781,2.992188 A 0.50005,0.50005 0 0 0 531,56.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 13,0 A 0.50005,0.50005 0 0 0 544,56.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m -13,3 A 0.50005,0.50005 0 0 0 531,59.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 13,0 A 0.50005,0.50005 0 0 0 544,59.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m -13,3 A 0.50005,0.50005 0 0 0 531,62.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 13,0 A 0.50005,0.50005 0 0 0 544,62.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m -13,3 A 0.50005,0.50005 0 0 0 531,65.5 v 0.919922 a 0.50005,0.50005 0 0 0 0.11328,0.404297 0.50005,0.50005 0 0 0 0.0156,0.01953 0.50005,0.50005 0 0 0 0.0176,0.01758 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.03125 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 531.58203,67 H 532.5 a 0.50005,0.50005 0 1 0 0,-1 H 532 v -0.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 13,0 A 0.50005,0.50005 0 0 0 544,65.5 V 66 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.91992 a 0.50005,0.50005 0 0 0 0.4043,-0.113281 0.50005,0.50005 0 0 0 0.004,-0.002 0.50005,0.50005 0 0 0 0.0332,-0.03125 0.50005,0.50005 0 0 0 0.002,-0.0039 0.50005,0.50005 0 0 0 0.0312,-0.0332 0.50005,0.50005 0 0 0 0.002,-0.0039 A 0.50005,0.50005 0 0 0 545,66.417969 V 65.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z M 534.5,66 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
- </g>
- <g style="display:inline;enable-background:new" id="g27919-7" transform="rotate(-180,149.5,102.00001)">
- <path sodipodi:nodetypes="cccccccccccccccccc" inkscape:connector-curvature="0" id="path27916-5" d="m 117.5,98 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 2 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m -4,5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
- </g>
+ <g
+ transform="translate(-587.00005,105)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g36393">
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path36378"
+ transform="translate(650.00005,-84)"
+ d="m 279.5,77 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 V 80 h 1 v -2 h 2 v 0.5 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 h 3.26562 c -0.20665,-0.306775 -0.36146,-0.646717 -0.48828,-1 H 283 v -0.5 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m -0.5,4 v 6.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 11 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -6 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 1,1 h 10 v 5 h -10 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
- <g style="display:inline;opacity:1;enable-background:new" transform="translate(63,-20)" id="g27948" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
- <g transform="translate(1,-1)" id="g27945">
- <g id="g27954">
- <path inkscape:connector-curvature="0" d="m 237.49414,326.05078 c -0.11724,0.001 -0.22936,0.0482 -0.3125,0.13086 l -2,2 c -0.17593,0.17578 -0.17593,0.46094 0,0.63672 l 2,2 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 2,-2 c 0.17593,-0.17578 0.17593,-0.46094 0,-0.63672 l -2,-2 c -0.086,-0.0855 -0.20293,-0.13272 -0.32422,-0.13086 z m 11,0 c -0.11724,0.001 -0.22936,0.0482 -0.3125,0.13086 l -2,2 c -0.17593,0.17578 -0.17593,0.46094 0,0.63672 l 2,2 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 2,-2 c 0.17593,-0.17578 0.17593,-0.46094 0,-0.63672 l -2,-2 c -0.086,-0.0855 -0.20293,-0.13272 -0.32422,-0.13086 z m -6.02734,6.75 a 0.45004499,0.45004499 0 0 0 -0.29688,0.14453 l -3,3.25 a 0.45004499,0.45004499 0 0 0 0.0117,0.62305 l 3,3 a 0.45004499,0.45004499 0 0 0 0.63672,0 l 3,-3 a 0.45004499,0.45004499 0 0 0 0.0117,-0.62305 l -3,-3.25 a 0.45004499,0.45004499 0 0 0 -0.36328,-0.14453 z m 0.0332,1.11133 2.37695,2.57617 -2.37695,2.375 -2.37695,-2.37695 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" id="path27939"/>
- <path style="opacity:0.5;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" d="m 239.12109,326 1.43946,1.43945 c 0.58556,0.5858 0.58556,1.5353 0,2.1211 L 239.12109,331 h 7.75782 l -1.43946,-1.43945 c -0.58556,-0.5858 -0.58556,-1.5353 0,-2.1211 L 246.87891,326 Z" id="path27943" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccc"/>
- </g>
- </g>
+ </g>
+ <g
+ id="g27914"
+ style="fill:#ffffff"
+ transform="translate(-21)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 69.5,157.98633 a 0.50005,0.50005 0 0 0 -0.492188,0.50586 v 12.9082 a 0.50005,0.50005 0 0 0 0.08203,0.37695 0.50005,0.50005 0 0 0 0.002,0.004 0.50005,0.50005 0 0 0 0.0293,0.0352 0.50005,0.50005 0 0 0 0.002,0.004 0.50005,0.50005 0 0 0 0.03125,0.0332 0.50005,0.50005 0 0 0 0.02539,0.0215 0.50005,0.50005 0 0 0 0.01172,0.0117 0.50005,0.50005 0 0 0 0.0039,0.002 0.50005,0.50005 0 0 0 0.04102,0.0293 0.50005,0.50005 0 0 0 0.353516,0.0742 h 12.917968 a 0.50005,0.50005 0 1 0 0,-1 h -12.5 v -12.5 A 0.50005,0.50005 0 0 0 69.5,157.98633 Z"
+ id="path15133-4-4"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 72.5,165 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 3 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 3 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -3 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ id="path22120-2-1"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ </g>
+ <g
+ id="g27942"
+ style="fill:#ffffff"
+ transform="translate(-21)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 49.46875,159 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 11 a 0.50005,0.50005 0 0 0 0.5,0.5 h 11 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -11 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 10 v 10 h -10 z"
+ id="path26471-6-1"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 53.5,163 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 3 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 3 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -3 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ id="path22120-2-1-2"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ </g>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ transform="translate(-230.99288,-230.99288)"
+ id="g27963"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
+ <g
+ id="g27959"
+ style="opacity:0.6;fill:#ffffff"
+ transform="translate(126)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 268.49219,388.99219 c -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 2.49609 l -2.50586,-0.004 c -0.67605,-0.0108 -0.67808,1.00811 -0.002,1 L 268,392.99609 V 399 h -6.00391 l -0.004,-2.50781 c 0.008,-0.67608 -1.01082,-0.67405 -1,0.002 L 260.99609,399 H 258.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 2.49609 l 0.004,2.5 c -0.01,0.67616 1.00956,0.67616 1,0 l -0.004,-2.5 H 268 v 2.5 c -0.01,0.67616 1.00956,0.67616 1,0 V 400 h 2.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 269 v -6.00391 l 2.5,0.004 c 0.67616,0.01 0.67616,-1.00956 0,-1 l -2.5,-0.004 V 389.5 c 0.004,-0.28226 -0.22555,-0.51223 -0.50781,-0.50781 z"
+ id="path27957"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccc" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 385.5,390 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path27961"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ </g>
+ <g
+ id="g28061"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(42,62.999998)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 40.433594,95 a 0.55005501,0.55005501 0 0 0 -0.378906,0.166016 l -3.44336,3.445312 a 0.55005501,0.55005501 0 1 0 0.777344,0.777344 l 3.445312,-3.44336 A 0.55005501,0.55005501 0 0 0 40.433594,95 Z m -9.445313,9.44531 a 0.55005501,0.55005501 0 0 0 -0.376953,0.16602 l -3.445312,3.44336 a 0.55104336,0.55104336 0 1 0 0.779296,0.77929 l 3.44336,-3.44531 a 0.55005501,0.55005501 0 0 0 -0.400391,-0.94336 z"
+ id="path27971"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 32.5,100 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 3 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 3 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -3 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ id="path27982"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ </g>
+ <g
+ id="g28078-6"
+ transform="rotate(90,48.5,-204.5)"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 412.5,-364 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 11 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 9,0 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 11 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path28076-4"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccc" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 175.5,159 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 8,0 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -8,8 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 8,0 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path28080-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 217.5,159 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 11 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 11 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path28082-0"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 241.49219,158.00781 c -0.1326,3e-5 -0.25982,0.0527 -0.35352,0.14649 l -4,4 c -0.094,0.0938 -0.14648,0.22091 -0.14648,0.35351 v 9 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 9 c 0.1326,-3e-5 0.25971,-0.0527 0.35351,-0.14648 l 4,-4 c 0.094,-0.0938 0.14649,-0.22092 0.14649,-0.35352 v -9 c 0,-0.27613 -0.2239,-0.49997 -0.5,-0.5 z m 7.48828,0.98242 a 1.0001,1.0001 0 0 1 0.72656,1.7168 L 247,163.41406 V 170 a 1.0001,1.0001 0 1 1 -2,0 v -6 h -6 a 1.0001,1.0001 0 1 1 0,-2 h 6.58594 l 2.70703,-2.70703 a 1.0001,1.0001 0 0 1 0.6875,-0.30274 z"
+ id="path28084-2"
+ inkscape:connector-curvature="0" />
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g28075-6"
+ transform="rotate(-180,339.00356,333)">
+ <g
+ transform="matrix(1,0,0,-1,0,999)"
+ style="opacity:0.7;fill:#ffffff"
+ id="g28071-5">
+ <path
+ inkscape:connector-curvature="0"
+ id="path28067-0"
+ transform="matrix(-1,0,0,1,358.00712,333)"
+ d="m -61.992188,164 v 7 h 1 v -3 h 2 v 1 h 1 v -1 h 2 v 3 h 1 v -3 h 2 v 1 h 1 v -1 h 2 v 3 h 1 v -7 h -1 v 3 h -2 v -1 h -1 v 1 h -2 v -3 h -1 v 3 h -2 v -1 h -1 v 1 h -2 v -3 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="path28073-8"
+ d="m 406.5,504 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ transform="translate(31.00018,129.00007)"
+ id="g28194"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ id="path28192"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 384.49023,-72.003906 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -2,2 a 0.50005,0.50005 0 1 0 0.70704,0.707032 l 2,-2 a 0.50005,0.50005 0 0 0 -0.36329,-0.857422 z m -3.03909,1.003895 c -0.65376,0 -1.30797,0.247425 -1.80469,0.744141 l -3.90234,3.902343 c -0.99343,0.993436 -0.99342,2.615944 0,3.609375 0.99343,0.993439 2.61594,0.993433 3.60938,0 l 3.90234,-3.902343 c 0.59653,-0.596538 0.82886,-1.419487 0.70898,-2.197266 l -0.40429,0.404297 a 1.50015,1.50015 0 1 1 -2.1211,-2.121094 l 0.40235,-0.402344 c -0.12952,-0.01981 -0.25989,-0.03711 -0.39063,-0.03711 z m -3.92969,4.970703 a 1.5291373,1.5291373 0 0 1 1.06055,0.447266 1.5291373,1.5291373 0 0 1 0,2.164062 1.5291373,1.5291373 0 0 1 -2.16406,0 1.5291373,1.5291373 0 0 1 0,-2.164062 1.5291373,1.5291373 0 0 1 1.10351,-0.447266 z m 6.97071,-9.970703 a 0.50005006,0.50005006 0 0 0 -0.34571,0.146484 l -1.85351,1.853516 h -1.79297 a 0.50005006,0.50005006 0 0 0 -0.0156,0 c -1.20241,0.03739 -2.21615,0.567689 -2.82618,1.425781 -0.61003,0.858093 -0.81106,2.015517 -0.53906,3.257813 0.01,0.04516 0.0301,0.08787 0.041,0.132812 l 0.86914,-0.86914 c -0.07,-0.784044 0.0959,-1.449869 0.44531,-1.941407 0.42534,-0.598307 1.10488,-0.976749 2.04101,-1.005859 h 1.98438 a 0.50005006,0.50005006 0 0 0 0.35352,-0.146484 l 1.64648,-1.646485 3.29297,3.292969 -1.64649,1.646484 a 0.50005006,0.50005006 0 0 0 -0.14648,0.353516 v 1.984375 c -0.0276,0.936587 -0.40343,1.616407 -1,2.041016 -0.49129,0.349673 -1.16015,0.516006 -1.94727,0.445312 l -0.86718,0.867188 c 0.0475,0.01158 0.0928,0.03258 0.14062,0.04297 1.24206,0.269931 2.39721,0.06874 3.25391,-0.541015 0.85669,-0.609757 1.38451,-1.621806 1.41992,-2.824219 a 0.50005006,0.50005006 0 0 0 0,-0.01563 v -1.792969 l 1.85352,-1.853515 a 0.50005006,0.50005006 0 0 0 0,-0.707032 l -4,-4 a 0.50005006,0.50005006 0 0 0 -0.36133,-0.146484 z" />
+ </g>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
+ style="display:inline;opacity:1;stroke:#ffffff;enable-background:new"
+ id="g28228"
+ transform="translate(-0.99999996)">
+ <g
+ style="display:inline;opacity:0.98999999;stroke:#ffffff;enable-background:new"
+ transform="translate(338.99999,-439.99995)"
+ id="g28217">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 501.49219 52.992188 C 501.21604 52.996495 500.99568 53.223854 501 53.5 L 501 54.5 C 500.99 55.176161 502.00956 55.176161 502 54.5 L 502 53.5 C 502.004 53.217735 501.77446 52.987773 501.49219 52.992188 z M 495.48438 53 C 495.3572 53.004 495.23638 53.056404 495.14648 53.146484 L 490.14648 58.146484 C 490.04522 58.247821 490.01608 58.369975 490.01562 58.492188 L 490 58.507812 L 490 60.5 C 489.99 61.176161 491.00956 61.176161 491 60.5 L 491 59 L 495.5 59 C 495.77613 58.99997 495.99997 58.77613 496 58.5 L 496 54 L 496.5 54 C 497.17616 54.0096 497.17616 52.990437 496.5 53 L 495.5 53 L 495.5 53.001953 C 495.49455 53.001948 495.48986 52.999829 495.48438 53 z M 498.5 53 C 497.82384 52.9904 497.82384 54.009563 498.5 54 L 499.5 54 C 500.17616 54.0096 500.17616 52.990437 499.5 53 L 498.5 53 z M 501.49219 55.992188 C 501.21604 55.996495 500.99568 56.223854 501 56.5 L 501 57.5 C 500.99 58.176161 502.00956 58.176161 502 57.5 L 502 56.5 C 502.004 56.217735 501.77446 55.987773 501.49219 55.992188 z M 501.49219 58.992188 C 501.21604 58.996495 500.99568 59.223854 501 59.5 L 501 60.5 C 500.99 61.176161 502.00956 61.176161 502 60.5 L 502 59.5 C 502.004 59.217735 501.77446 58.987773 501.49219 58.992188 z M 490.49219 61.992188 C 490.21604 61.996495 489.99568 62.223854 490 62.5 L 490 63.5 C 489.99 64.176161 491.00956 64.176161 491 63.5 L 491 62.5 C 491.004 62.217735 490.77446 61.987773 490.49219 61.992188 z M 501.49219 61.992188 C 501.21604 61.996495 500.99568 62.223854 501 62.5 L 501 63.5 C 500.99 64.176161 502.00956 64.176161 502 63.5 L 502 62.5 C 502.004 62.217735 501.77446 61.987773 501.49219 61.992188 z M 490.49219 64.992188 C 490.21604 64.996494 489.99568 65.223854 490 65.5 L 490 66.5 C 489.99 67.176161 491.00956 67.176161 491 66.5 L 491 65.5 C 491.004 65.217735 490.77446 64.987773 490.49219 64.992188 z M 501.49219 64.992188 C 501.21604 64.996494 500.99568 65.223854 501 65.5 L 501 66.5 C 500.99 67.176161 502.00956 67.176161 502 66.5 L 502 65.5 C 502.004 65.217735 501.77446 64.987773 501.49219 64.992188 z M 492.5 66 C 491.82384 65.9904 491.82384 67.009563 492.5 67 L 493.5 67 C 494.17616 67.0096 494.17616 65.990437 493.5 66 L 492.5 66 z M 495.5 66 C 494.82384 65.9904 494.82384 67.009563 495.5 67 L 496.5 67 C 497.17616 67.0096 497.17616 65.990437 496.5 66 L 495.5 66 z M 498.5 66 C 497.82384 65.9904 497.82384 67.009563 498.5 67 L 499.5 67 C 500.17616 67.0096 500.17616 65.990437 499.5 66 L 498.5 66 z "
+ transform="translate(-337.99999,439.99995)"
+ id="path28215" />
</g>
</g>
</g>
- <g inkscape:groupmode="layer" id="layer2" inkscape:label="EMPTY ICON TRACKING" style="display:none">
- <g id="g16331" style="fill:#ffcc00">
- <text id="text16071" y="25" x="280.8446" style="font-style:normal;font-weight:normal;font-size:19.20428658px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999994" xml:space="preserve"><tspan style="fill:#ffcc00;stroke-width:0.99999994" y="25" x="280.8446" id="tspan16069" sodipodi:role="line">1</tspan></text>
- <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" x="133.86958" y="67" id="text16075"><tspan sodipodi:role="line" id="tspan16073" x="133.86958" y="67" style="fill:#ffcc00;stroke-width:0.99999988">2</tspan></text>
- <text id="text16079" y="67" x="154.86958" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" xml:space="preserve"><tspan style="fill:#ffcc00;stroke-width:0.99999988" y="67" x="154.86958" id="tspan16077" sodipodi:role="line">3</tspan></text>
- <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" x="133.86958" y="88" id="text16087"><tspan sodipodi:role="line" id="tspan16085" x="133.86958" y="88" style="fill:#ffcc00;stroke-width:0.99999988">4</tspan></text>
- <text inkscape:transform-center-y="3.1243423" inkscape:transform-center-x="3.1988381" id="text16091" y="88" x="175.86958" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" xml:space="preserve"><tspan style="fill:#ffcc00;stroke-width:0.99999988" y="88" x="175.86958" id="tspan16089" sodipodi:role="line">5</tspan></text>
- <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" x="196.86958" y="88" id="text16095" inkscape:transform-center-x="3.1988381" inkscape:transform-center-y="3.1243423"><tspan sodipodi:role="line" id="tspan16093" x="196.86958" y="88" style="fill:#ffcc00;stroke-width:0.99999988">6</tspan></text>
- <text inkscape:transform-center-y="3.1243423" inkscape:transform-center-x="3.1988381" id="text16099" y="88" x="301.86957" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" xml:space="preserve"><tspan style="fill:#ffcc00;stroke-width:0.99999988" y="88" x="301.86957" id="tspan16097" sodipodi:role="line">7</tspan></text>
- <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" x="237.86957" y="151" id="text16103" inkscape:transform-center-x="3.1988381" inkscape:transform-center-y="3.1243423"><tspan sodipodi:role="line" id="tspan16101" x="237.86957" y="151" style="fill:#ffcc00;stroke-width:0.99999988">8</tspan></text>
- <text inkscape:transform-center-y="3.1243423" inkscape:transform-center-x="3.1988381" id="text16107" y="172" x="7.8695679" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" xml:space="preserve"><tspan style="fill:#ffcc00;stroke-width:0.99999988" y="172" x="7.8695679" id="tspan16105" sodipodi:role="line">9</tspan></text>
- <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" x="27.869568" y="172" id="text16111" inkscape:transform-center-x="3.1988381" inkscape:transform-center-y="3.1243423"><tspan sodipodi:role="line" id="tspan16109" x="27.869568" y="172" style="fill:#ffcc00;stroke-width:0.99999988">A</tspan></text>
- <text inkscape:transform-center-y="3.1243423" inkscape:transform-center-x="3.1988381" id="text16115" y="172" x="49.869568" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" xml:space="preserve"><tspan style="fill:#ffcc00;stroke-width:0.99999988" y="172" x="49.869568" id="tspan16113" sodipodi:role="line">B</tspan></text>
- <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" x="69.869568" y="172" id="text16119" inkscape:transform-center-x="3.1988381" inkscape:transform-center-y="3.1243423"><tspan sodipodi:role="line" id="tspan16117" x="69.869568" y="172" style="fill:#ffcc00;stroke-width:0.99999988">C</tspan></text>
- <text inkscape:transform-center-y="3.1243423" inkscape:transform-center-x="3.1988381" id="text16123" y="340" x="5.8695679" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" xml:space="preserve"><tspan style="fill:#ffcc00;stroke-width:0.99999988" y="340" x="5.8695679" id="tspan16121" sodipodi:role="line">D</tspan></text>
- <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" x="26.869568" y="340" id="text16127" inkscape:transform-center-x="3.1988381" inkscape:transform-center-y="3.1243423"><tspan sodipodi:role="line" id="tspan16125" x="26.869568" y="340" style="fill:#ffcc00;stroke-width:0.99999988">E</tspan></text>
- <text inkscape:transform-center-y="3.1243423" inkscape:transform-center-x="3.1988381" id="text16131" y="340" x="49.869568" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" xml:space="preserve"><tspan style="fill:#ffcc00;stroke-width:0.99999988" y="340" x="49.869568" id="tspan16129" sodipodi:role="line">F</tspan></text>
- <text inkscape:transform-center-x="3.1988381" inkscape:transform-center-y="3.1243423" id="text16155" y="529" x="194.86957" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" xml:space="preserve"><tspan style="fill:#ffcc00;stroke-width:0.99999988" y="529" x="194.86957" id="tspan16153" sodipodi:role="line">N</tspan></text>
- <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" x="215.86957" y="529" id="text16159" inkscape:transform-center-y="3.1243423" inkscape:transform-center-x="3.1988381"><tspan sodipodi:role="line" id="tspan16157" x="215.86957" y="529" style="fill:#ffcc00;stroke-width:0.99999988">O</tspan></text>
- <text inkscape:transform-center-x="3.1988381" inkscape:transform-center-y="3.1243423" id="text16167" y="550" x="194.86957" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" xml:space="preserve"><tspan style="fill:#ffcc00;stroke-width:0.99999988" y="550" x="194.86957" id="tspan16165" sodipodi:role="line">P</tspan></text>
- <text transform="scale(1.0088573,0.99122046)" xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:16.21410179px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" x="339.99878" y="553.21686" id="text16171" inkscape:transform-center-y="2.6620037" inkscape:transform-center-x="2.773985"><tspan sodipodi:role="line" id="tspan16169" x="339.99878" y="553.21686" style="fill:#ffcc00;stroke-width:0.99999988">Q</tspan><tspan id="tspan16173" sodipodi:role="line" x="339.99878" y="553.21686" style="fill:#ffcc00;stroke-width:0.99999988"/></text>
- <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" x="384.86957" y="550" id="text16177" inkscape:transform-center-y="3.1243423" inkscape:transform-center-x="3.1988381"><tspan sodipodi:role="line" id="tspan16175" x="384.86957" y="550" style="fill:#ffcc00;stroke-width:0.99999988">R</tspan></text>
- <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" x="154.86957" y="571" id="text16185" inkscape:transform-center-y="3.1243423" inkscape:transform-center-x="3.1988381"><tspan sodipodi:role="line" id="tspan16183" x="154.86957" y="571" style="fill:#ffcc00;stroke-width:0.99999988">T</tspan></text>
- <text inkscape:transform-center-x="3.1988381" inkscape:transform-center-y="3.1243423" id="text16189" y="571" x="174.86957" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" xml:space="preserve"><tspan style="fill:#ffcc00;stroke-width:0.99999988" y="571" x="174.86957" id="tspan16187" sodipodi:role="line">U</tspan></text>
- <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" x="279.86957" y="571" id="text16193" inkscape:transform-center-y="3.1243423" inkscape:transform-center-x="3.1988381"><tspan sodipodi:role="line" id="tspan16191" x="279.86957" y="571" style="fill:#ffcc00;stroke-width:0.99999988">V</tspan></text>
- <text transform="scale(0.89679029,1.1150879)" inkscape:transform-center-x="2.5726168" inkscape:transform-center-y="3.1243143" id="text16197" y="549.73242" x="239.73518" style="font-style:normal;font-weight:normal;font-size:16.91629601px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" xml:space="preserve"><tspan style="fill:#ffcc00;stroke-width:0.99999988" y="549.73242" x="239.73518" id="tspan16195" sodipodi:role="line">W</tspan></text>
- <text inkscape:transform-center-x="3.1988381" inkscape:transform-center-y="3.1243423" id="text16215" y="613" x="447.86957" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" xml:space="preserve"><tspan style="fill:#ffcc00;stroke-width:0.99999988" y="613" x="447.86957" id="tspan16213" sodipodi:role="line">X</tspan></text>
- <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" x="467.86957" y="613" id="text16219" inkscape:transform-center-y="3.1243423" inkscape:transform-center-x="3.1988381"><tspan sodipodi:role="line" id="tspan16217" x="467.86957" y="613" style="fill:#ffcc00;stroke-width:0.99999988">Y</tspan></text>
- <text inkscape:transform-center-x="3.1988381" inkscape:transform-center-y="3.1243423" id="text16223" y="613" x="489.86957" style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" xml:space="preserve"><tspan style="fill:#ffcc00;stroke-width:0.99999988" y="613" x="489.86957" id="tspan16221" sodipodi:role="line">Z</tspan></text>
- <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:18.67848969px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999994" x="507.88174" y="612.0321" id="text16227" inkscape:transform-center-y="3.0937591" inkscape:transform-center-x="3.1675179"><tspan sodipodi:role="line" id="tspan16225" x="507.88174" y="612.0321" style="fill:#ffcc00;stroke-width:0.99999994">@</tspan></text>
- <text inkscape:transform-center-x="2.8268697" inkscape:transform-center-y="2.7610486" id="text16239" y="633.06055" x="467.99258" style="font-style:normal;font-weight:normal;font-size:16.66976738px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988" xml:space="preserve"><tspan style="fill:#ffcc00;stroke-width:0.99999988" y="633.06055" x="467.99258" id="tspan16237" sodipodi:role="line">%</tspan></text>
- <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:18.86315918px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999994" x="491.83517" y="634.06061" id="text16243" inkscape:transform-center-y="3.124405" inkscape:transform-center-x="3.1987998"><tspan sodipodi:role="line" id="tspan16241" x="491.83517" y="634.06061" style="fill:#ffcc00;stroke-width:0.99999994">?</tspan></text>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="EMPTY ICON TRACKING"
+ style="display:none">
+ <g
+ id="g16331"
+ style="fill:#ffcc00">
+ <text
+ id="text16071"
+ y="25"
+ x="280.8446"
+ style="font-style:normal;font-weight:normal;font-size:19.20428658px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999994"
+ xml:space="preserve"><tspan
+ style="fill:#ffcc00;stroke-width:0.99999994"
+ y="25"
+ x="280.8446"
+ id="tspan16069"
+ sodipodi:role="line">1</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ x="133.86958"
+ y="67"
+ id="text16075"><tspan
+ sodipodi:role="line"
+ id="tspan16073"
+ x="133.86958"
+ y="67"
+ style="fill:#ffcc00;stroke-width:0.99999988">2</tspan></text>
+ <text
+ id="text16079"
+ y="67"
+ x="154.86958"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ xml:space="preserve"><tspan
+ style="fill:#ffcc00;stroke-width:0.99999988"
+ y="67"
+ x="154.86958"
+ id="tspan16077"
+ sodipodi:role="line">3</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ x="133.86958"
+ y="88"
+ id="text16087"><tspan
+ sodipodi:role="line"
+ id="tspan16085"
+ x="133.86958"
+ y="88"
+ style="fill:#ffcc00;stroke-width:0.99999988">4</tspan></text>
+ <text
+ inkscape:transform-center-y="3.1243423"
+ inkscape:transform-center-x="3.1988381"
+ id="text16091"
+ y="88"
+ x="175.86958"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ xml:space="preserve"><tspan
+ style="fill:#ffcc00;stroke-width:0.99999988"
+ y="88"
+ x="175.86958"
+ id="tspan16089"
+ sodipodi:role="line">5</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ x="196.86958"
+ y="88"
+ id="text16095"
+ inkscape:transform-center-x="3.1988381"
+ inkscape:transform-center-y="3.1243423"><tspan
+ sodipodi:role="line"
+ id="tspan16093"
+ x="196.86958"
+ y="88"
+ style="fill:#ffcc00;stroke-width:0.99999988">6</tspan></text>
+ <text
+ inkscape:transform-center-y="3.1243423"
+ inkscape:transform-center-x="3.1988381"
+ id="text16099"
+ y="88"
+ x="301.86957"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ xml:space="preserve"><tspan
+ style="fill:#ffcc00;stroke-width:0.99999988"
+ y="88"
+ x="301.86957"
+ id="tspan16097"
+ sodipodi:role="line">7</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ x="237.86957"
+ y="151"
+ id="text16103"
+ inkscape:transform-center-x="3.1988381"
+ inkscape:transform-center-y="3.1243423"><tspan
+ sodipodi:role="line"
+ id="tspan16101"
+ x="237.86957"
+ y="151"
+ style="fill:#ffcc00;stroke-width:0.99999988">8</tspan></text>
+ <text
+ inkscape:transform-center-y="3.1243423"
+ inkscape:transform-center-x="3.1988381"
+ id="text16107"
+ y="172"
+ x="7.8695679"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ xml:space="preserve"><tspan
+ style="fill:#ffcc00;stroke-width:0.99999988"
+ y="172"
+ x="7.8695679"
+ id="tspan16105"
+ sodipodi:role="line">9</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ x="27.869568"
+ y="172"
+ id="text16111"
+ inkscape:transform-center-x="3.1988381"
+ inkscape:transform-center-y="3.1243423"><tspan
+ sodipodi:role="line"
+ id="tspan16109"
+ x="27.869568"
+ y="172"
+ style="fill:#ffcc00;stroke-width:0.99999988">A</tspan></text>
+ <text
+ inkscape:transform-center-y="3.1243423"
+ inkscape:transform-center-x="3.1988381"
+ id="text16115"
+ y="172"
+ x="49.869568"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ xml:space="preserve"><tspan
+ style="fill:#ffcc00;stroke-width:0.99999988"
+ y="172"
+ x="49.869568"
+ id="tspan16113"
+ sodipodi:role="line">B</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ x="69.869568"
+ y="172"
+ id="text16119"
+ inkscape:transform-center-x="3.1988381"
+ inkscape:transform-center-y="3.1243423"><tspan
+ sodipodi:role="line"
+ id="tspan16117"
+ x="69.869568"
+ y="172"
+ style="fill:#ffcc00;stroke-width:0.99999988">C</tspan></text>
+ <text
+ inkscape:transform-center-y="3.1243423"
+ inkscape:transform-center-x="3.1988381"
+ id="text16123"
+ y="340"
+ x="5.8695679"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ xml:space="preserve"><tspan
+ style="fill:#ffcc00;stroke-width:0.99999988"
+ y="340"
+ x="5.8695679"
+ id="tspan16121"
+ sodipodi:role="line">D</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ x="26.869568"
+ y="340"
+ id="text16127"
+ inkscape:transform-center-x="3.1988381"
+ inkscape:transform-center-y="3.1243423"><tspan
+ sodipodi:role="line"
+ id="tspan16125"
+ x="26.869568"
+ y="340"
+ style="fill:#ffcc00;stroke-width:0.99999988">E</tspan></text>
+ <text
+ inkscape:transform-center-y="3.1243423"
+ inkscape:transform-center-x="3.1988381"
+ id="text16131"
+ y="340"
+ x="49.869568"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ xml:space="preserve"><tspan
+ style="fill:#ffcc00;stroke-width:0.99999988"
+ y="340"
+ x="49.869568"
+ id="tspan16129"
+ sodipodi:role="line">F</tspan></text>
+ <text
+ inkscape:transform-center-x="3.1988381"
+ inkscape:transform-center-y="3.1243423"
+ id="text16155"
+ y="529"
+ x="194.86957"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ xml:space="preserve"><tspan
+ style="fill:#ffcc00;stroke-width:0.99999988"
+ y="529"
+ x="194.86957"
+ id="tspan16153"
+ sodipodi:role="line">N</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ x="215.86957"
+ y="529"
+ id="text16159"
+ inkscape:transform-center-y="3.1243423"
+ inkscape:transform-center-x="3.1988381"><tspan
+ sodipodi:role="line"
+ id="tspan16157"
+ x="215.86957"
+ y="529"
+ style="fill:#ffcc00;stroke-width:0.99999988">O</tspan></text>
+ <text
+ inkscape:transform-center-x="3.1988381"
+ inkscape:transform-center-y="3.1243423"
+ id="text16167"
+ y="550"
+ x="194.86957"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ xml:space="preserve"><tspan
+ style="fill:#ffcc00;stroke-width:0.99999988"
+ y="550"
+ x="194.86957"
+ id="tspan16165"
+ sodipodi:role="line">P</tspan></text>
+ <text
+ transform="scale(1.0088573,0.99122046)"
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:16.21410179px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ x="339.99878"
+ y="553.21686"
+ id="text16171"
+ inkscape:transform-center-y="2.6620037"
+ inkscape:transform-center-x="2.773985"><tspan
+ sodipodi:role="line"
+ id="tspan16169"
+ x="339.99878"
+ y="553.21686"
+ style="fill:#ffcc00;stroke-width:0.99999988">Q</tspan><tspan
+ id="tspan16173"
+ sodipodi:role="line"
+ x="339.99878"
+ y="553.21686"
+ style="fill:#ffcc00;stroke-width:0.99999988" /></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ x="384.86957"
+ y="550"
+ id="text16177"
+ inkscape:transform-center-y="3.1243423"
+ inkscape:transform-center-x="3.1988381"><tspan
+ sodipodi:role="line"
+ id="tspan16175"
+ x="384.86957"
+ y="550"
+ style="fill:#ffcc00;stroke-width:0.99999988">R</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ x="154.86957"
+ y="571"
+ id="text16185"
+ inkscape:transform-center-y="3.1243423"
+ inkscape:transform-center-x="3.1988381"><tspan
+ sodipodi:role="line"
+ id="tspan16183"
+ x="154.86957"
+ y="571"
+ style="fill:#ffcc00;stroke-width:0.99999988">T</tspan></text>
+ <text
+ inkscape:transform-center-x="3.1988381"
+ inkscape:transform-center-y="3.1243423"
+ id="text16189"
+ y="571"
+ x="174.86957"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ xml:space="preserve"><tspan
+ style="fill:#ffcc00;stroke-width:0.99999988"
+ y="571"
+ x="174.86957"
+ id="tspan16187"
+ sodipodi:role="line">U</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ x="279.86957"
+ y="571"
+ id="text16193"
+ inkscape:transform-center-y="3.1243423"
+ inkscape:transform-center-x="3.1988381"><tspan
+ sodipodi:role="line"
+ id="tspan16191"
+ x="279.86957"
+ y="571"
+ style="fill:#ffcc00;stroke-width:0.99999988">V</tspan></text>
+ <text
+ transform="scale(0.89679029,1.1150879)"
+ inkscape:transform-center-x="2.5726168"
+ inkscape:transform-center-y="3.1243143"
+ id="text16197"
+ y="549.73242"
+ x="239.73518"
+ style="font-style:normal;font-weight:normal;font-size:16.91629601px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ xml:space="preserve"><tspan
+ style="fill:#ffcc00;stroke-width:0.99999988"
+ y="549.73242"
+ x="239.73518"
+ id="tspan16195"
+ sodipodi:role="line">W</tspan></text>
+ <text
+ inkscape:transform-center-x="3.1988381"
+ inkscape:transform-center-y="3.1243423"
+ id="text16215"
+ y="613"
+ x="447.86957"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ xml:space="preserve"><tspan
+ style="fill:#ffcc00;stroke-width:0.99999988"
+ y="613"
+ x="447.86957"
+ id="tspan16213"
+ sodipodi:role="line">X</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ x="467.86957"
+ y="613"
+ id="text16219"
+ inkscape:transform-center-y="3.1243423"
+ inkscape:transform-center-x="3.1988381"><tspan
+ sodipodi:role="line"
+ id="tspan16217"
+ x="467.86957"
+ y="613"
+ style="fill:#ffcc00;stroke-width:0.99999988">Y</tspan></text>
+ <text
+ inkscape:transform-center-x="3.1988381"
+ inkscape:transform-center-y="3.1243423"
+ id="text16223"
+ y="613"
+ x="489.86957"
+ style="font-style:normal;font-weight:normal;font-size:18.86315727px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ xml:space="preserve"><tspan
+ style="fill:#ffcc00;stroke-width:0.99999988"
+ y="613"
+ x="489.86957"
+ id="tspan16221"
+ sodipodi:role="line">Z</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:18.67848969px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999994"
+ x="507.88174"
+ y="612.0321"
+ id="text16227"
+ inkscape:transform-center-y="3.0937591"
+ inkscape:transform-center-x="3.1675179"><tspan
+ sodipodi:role="line"
+ id="tspan16225"
+ x="507.88174"
+ y="612.0321"
+ style="fill:#ffcc00;stroke-width:0.99999994">@</tspan></text>
+ <text
+ inkscape:transform-center-x="2.8268697"
+ inkscape:transform-center-y="2.7610486"
+ id="text16239"
+ y="633.06055"
+ x="467.99258"
+ style="font-style:normal;font-weight:normal;font-size:16.66976738px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999988"
+ xml:space="preserve"><tspan
+ style="fill:#ffcc00;stroke-width:0.99999988"
+ y="633.06055"
+ x="467.99258"
+ id="tspan16237"
+ sodipodi:role="line">%</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:18.86315918px;line-height:0;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:0.99999994"
+ x="491.83517"
+ y="634.06061"
+ id="text16243"
+ inkscape:transform-center-y="3.124405"
+ inkscape:transform-center-x="3.1987998"><tspan
+ sodipodi:role="line"
+ id="tspan16241"
+ x="491.83517"
+ y="634.06061"
+ style="fill:#ffcc00;stroke-width:0.99999994">?</tspan></text>
</g>
</g>
</svg>
diff --git a/release/datafiles/blender_icons16/icon16_brush_blob.dat b/release/datafiles/blender_icons16/icon16_brush_blob.dat
new file mode 100644
index 00000000000..4f57ce5ef27
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_brush_blob.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_checkmark.dat b/release/datafiles/blender_icons16/icon16_checkmark.dat
new file mode 100644
index 00000000000..8e77c3329ed
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_checkmark.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_desktop.dat b/release/datafiles/blender_icons16/icon16_desktop.dat
new file mode 100644
index 00000000000..4a08daed9a9
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_desktop.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_disk_drive.dat b/release/datafiles/blender_icons16/icon16_disk_drive.dat
index a9b9284c4ec..84235c0b1fe 100644
--- a/release/datafiles/blender_icons16/icon16_disk_drive.dat
+++ b/release/datafiles/blender_icons16/icon16_disk_drive.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_external_drive.dat b/release/datafiles/blender_icons16/icon16_external_drive.dat
new file mode 100644
index 00000000000..3996681d0af
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_external_drive.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_file.dat b/release/datafiles/blender_icons16/icon16_file.dat
index 71c75181ec8..5e617c4b04d 100644
--- a/release/datafiles/blender_icons16/icon16_file.dat
+++ b/release/datafiles/blender_icons16/icon16_file.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_file_archive.dat b/release/datafiles/blender_icons16/icon16_file_archive.dat
new file mode 100644
index 00000000000..39b322c6d1d
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_file_archive.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_file_blank.dat b/release/datafiles/blender_icons16/icon16_file_blank.dat
index 25dcaf83f46..f37302f004a 100644
--- a/release/datafiles/blender_icons16/icon16_file_blank.dat
+++ b/release/datafiles/blender_icons16/icon16_file_blank.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_file_cache.dat b/release/datafiles/blender_icons16/icon16_file_cache.dat
index 25abc74c4f8..d62078bfbf4 100644
--- a/release/datafiles/blender_icons16/icon16_file_cache.dat
+++ b/release/datafiles/blender_icons16/icon16_file_cache.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_file_folder.dat b/release/datafiles/blender_icons16/icon16_file_folder.dat
index 963efe592ae..fa31dce044c 100644
--- a/release/datafiles/blender_icons16/icon16_file_folder.dat
+++ b/release/datafiles/blender_icons16/icon16_file_folder.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_file_hidden.dat b/release/datafiles/blender_icons16/icon16_file_hidden.dat
index 3696ec26f44..55a1fbe7275 100644
--- a/release/datafiles/blender_icons16/icon16_file_hidden.dat
+++ b/release/datafiles/blender_icons16/icon16_file_hidden.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_filebrowser.dat b/release/datafiles/blender_icons16/icon16_filebrowser.dat
index fc9f039d2a0..2bc6608eb5b 100644
--- a/release/datafiles/blender_icons16/icon16_filebrowser.dat
+++ b/release/datafiles/blender_icons16/icon16_filebrowser.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_network_drive.dat b/release/datafiles/blender_icons16/icon16_network_drive.dat
new file mode 100644
index 00000000000..8570bbc3634
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_network_drive.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_newfolder.dat b/release/datafiles/blender_icons16/icon16_newfolder.dat
index bdc2c1d0b07..c097b1372f6 100644
--- a/release/datafiles/blender_icons16/icon16_newfolder.dat
+++ b/release/datafiles/blender_icons16/icon16_newfolder.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_snap_edge.dat b/release/datafiles/blender_icons16/icon16_snap_edge.dat
index a60c3ea5ef2..3b99378ddf9 100644
--- a/release/datafiles/blender_icons16/icon16_snap_edge.dat
+++ b/release/datafiles/blender_icons16/icon16_snap_edge.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_snap_face.dat b/release/datafiles/blender_icons16/icon16_snap_face.dat
index fb54c740b77..5670707a416 100644
--- a/release/datafiles/blender_icons16/icon16_snap_face.dat
+++ b/release/datafiles/blender_icons16/icon16_snap_face.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_snap_face_center.dat b/release/datafiles/blender_icons16/icon16_snap_face_center.dat
new file mode 100644
index 00000000000..c9e2670b881
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_snap_face_center.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_snap_grid.dat b/release/datafiles/blender_icons16/icon16_snap_grid.dat
index eafb1c826e6..d3d8e3af335 100644
--- a/release/datafiles/blender_icons16/icon16_snap_grid.dat
+++ b/release/datafiles/blender_icons16/icon16_snap_grid.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_snap_increment.dat b/release/datafiles/blender_icons16/icon16_snap_increment.dat
index 3c0134c0dd8..af3e08ae73d 100644
--- a/release/datafiles/blender_icons16/icon16_snap_increment.dat
+++ b/release/datafiles/blender_icons16/icon16_snap_increment.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_snap_midpoint.dat b/release/datafiles/blender_icons16/icon16_snap_midpoint.dat
index 903ab37dc24..e90145e77c9 100644
--- a/release/datafiles/blender_icons16/icon16_snap_midpoint.dat
+++ b/release/datafiles/blender_icons16/icon16_snap_midpoint.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_snap_perpendicular.dat b/release/datafiles/blender_icons16/icon16_snap_perpendicular.dat
index 02b86db4396..fc07f330dec 100644
--- a/release/datafiles/blender_icons16/icon16_snap_perpendicular.dat
+++ b/release/datafiles/blender_icons16/icon16_snap_perpendicular.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_snap_vertex.dat b/release/datafiles/blender_icons16/icon16_snap_vertex.dat
index 1da3ef6e9ca..2b9b0c6faf5 100644
--- a/release/datafiles/blender_icons16/icon16_snap_vertex.dat
+++ b/release/datafiles/blender_icons16/icon16_snap_vertex.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_snap_volume.dat b/release/datafiles/blender_icons16/icon16_snap_volume.dat
index 501dff71487..6708c6ec9c7 100644
--- a/release/datafiles/blender_icons16/icon16_snap_volume.dat
+++ b/release/datafiles/blender_icons16/icon16_snap_volume.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_system.dat b/release/datafiles/blender_icons16/icon16_system.dat
index 7dadcd8b0c0..d67129a494d 100644
--- a/release/datafiles/blender_icons16/icon16_system.dat
+++ b/release/datafiles/blender_icons16/icon16_system.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_transform_origins.dat b/release/datafiles/blender_icons16/icon16_transform_origins.dat
new file mode 100644
index 00000000000..b62403e6f7e
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_transform_origins.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_brush_blob.dat b/release/datafiles/blender_icons32/icon32_brush_blob.dat
new file mode 100644
index 00000000000..5f43c0e3943
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_brush_blob.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_checkmark.dat b/release/datafiles/blender_icons32/icon32_checkmark.dat
new file mode 100644
index 00000000000..25fda0999e8
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_checkmark.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_desktop.dat b/release/datafiles/blender_icons32/icon32_desktop.dat
new file mode 100644
index 00000000000..1400d07381d
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_desktop.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_disk_drive.dat b/release/datafiles/blender_icons32/icon32_disk_drive.dat
index 7bee6bbc43f..cbbd957bc77 100644
--- a/release/datafiles/blender_icons32/icon32_disk_drive.dat
+++ b/release/datafiles/blender_icons32/icon32_disk_drive.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_external_drive.dat b/release/datafiles/blender_icons32/icon32_external_drive.dat
new file mode 100644
index 00000000000..cd16d0e1735
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_external_drive.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_file.dat b/release/datafiles/blender_icons32/icon32_file.dat
index 98df9a1b787..9124262b4d0 100644
--- a/release/datafiles/blender_icons32/icon32_file.dat
+++ b/release/datafiles/blender_icons32/icon32_file.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_file_archive.dat b/release/datafiles/blender_icons32/icon32_file_archive.dat
new file mode 100644
index 00000000000..aac33e53e13
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_file_archive.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_file_blank.dat b/release/datafiles/blender_icons32/icon32_file_blank.dat
index 638ff73e1c9..3dc0abc0da0 100644
--- a/release/datafiles/blender_icons32/icon32_file_blank.dat
+++ b/release/datafiles/blender_icons32/icon32_file_blank.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_file_cache.dat b/release/datafiles/blender_icons32/icon32_file_cache.dat
index 589fb101d96..309e556ae74 100644
--- a/release/datafiles/blender_icons32/icon32_file_cache.dat
+++ b/release/datafiles/blender_icons32/icon32_file_cache.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_file_folder.dat b/release/datafiles/blender_icons32/icon32_file_folder.dat
index e6996db1046..89d0058fae3 100644
--- a/release/datafiles/blender_icons32/icon32_file_folder.dat
+++ b/release/datafiles/blender_icons32/icon32_file_folder.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_file_hidden.dat b/release/datafiles/blender_icons32/icon32_file_hidden.dat
index 3f1a6c84ac3..20fd6e9ef10 100644
--- a/release/datafiles/blender_icons32/icon32_file_hidden.dat
+++ b/release/datafiles/blender_icons32/icon32_file_hidden.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_filebrowser.dat b/release/datafiles/blender_icons32/icon32_filebrowser.dat
index 127f7dd38ad..52d9c74503f 100644
--- a/release/datafiles/blender_icons32/icon32_filebrowser.dat
+++ b/release/datafiles/blender_icons32/icon32_filebrowser.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_network_drive.dat b/release/datafiles/blender_icons32/icon32_network_drive.dat
new file mode 100644
index 00000000000..36a18f0882c
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_network_drive.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_newfolder.dat b/release/datafiles/blender_icons32/icon32_newfolder.dat
index 27f60520c4b..d2762e1e878 100644
--- a/release/datafiles/blender_icons32/icon32_newfolder.dat
+++ b/release/datafiles/blender_icons32/icon32_newfolder.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_snap_edge.dat b/release/datafiles/blender_icons32/icon32_snap_edge.dat
index 2104e04cfa6..3c9761b753a 100644
--- a/release/datafiles/blender_icons32/icon32_snap_edge.dat
+++ b/release/datafiles/blender_icons32/icon32_snap_edge.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_snap_face.dat b/release/datafiles/blender_icons32/icon32_snap_face.dat
index 2b1051e118b..4d82dceaaec 100644
--- a/release/datafiles/blender_icons32/icon32_snap_face.dat
+++ b/release/datafiles/blender_icons32/icon32_snap_face.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_snap_face_center.dat b/release/datafiles/blender_icons32/icon32_snap_face_center.dat
new file mode 100644
index 00000000000..83cf15dd718
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_snap_face_center.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_snap_grid.dat b/release/datafiles/blender_icons32/icon32_snap_grid.dat
index 134b893ef39..4fe02b4aba8 100644
--- a/release/datafiles/blender_icons32/icon32_snap_grid.dat
+++ b/release/datafiles/blender_icons32/icon32_snap_grid.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_snap_increment.dat b/release/datafiles/blender_icons32/icon32_snap_increment.dat
index f20787fb96d..e568597688c 100644
--- a/release/datafiles/blender_icons32/icon32_snap_increment.dat
+++ b/release/datafiles/blender_icons32/icon32_snap_increment.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_snap_midpoint.dat b/release/datafiles/blender_icons32/icon32_snap_midpoint.dat
index c22b196035a..f6960397517 100644
--- a/release/datafiles/blender_icons32/icon32_snap_midpoint.dat
+++ b/release/datafiles/blender_icons32/icon32_snap_midpoint.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_snap_perpendicular.dat b/release/datafiles/blender_icons32/icon32_snap_perpendicular.dat
index 2460b0150ab..8d162c9e497 100644
--- a/release/datafiles/blender_icons32/icon32_snap_perpendicular.dat
+++ b/release/datafiles/blender_icons32/icon32_snap_perpendicular.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_snap_vertex.dat b/release/datafiles/blender_icons32/icon32_snap_vertex.dat
index cdf1fb716a4..4e93827e0a0 100644
--- a/release/datafiles/blender_icons32/icon32_snap_vertex.dat
+++ b/release/datafiles/blender_icons32/icon32_snap_vertex.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_snap_volume.dat b/release/datafiles/blender_icons32/icon32_snap_volume.dat
index 6b2373f9e32..37b50076e0e 100644
--- a/release/datafiles/blender_icons32/icon32_snap_volume.dat
+++ b/release/datafiles/blender_icons32/icon32_snap_volume.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_system.dat b/release/datafiles/blender_icons32/icon32_system.dat
index 0e8abd4e73f..1fbd7048ba7 100644
--- a/release/datafiles/blender_icons32/icon32_system.dat
+++ b/release/datafiles/blender_icons32/icon32_system.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_transform_origins.dat b/release/datafiles/blender_icons32/icon32_transform_origins.dat
new file mode 100644
index 00000000000..e7da1c49b6b
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_transform_origins.dat
Binary files differ
diff --git a/release/datafiles/blender_icons_geom.py b/release/datafiles/blender_icons_geom.py
index 644d0756234..b2f029ee511 100644
--- a/release/datafiles/blender_icons_geom.py
+++ b/release/datafiles/blender_icons_geom.py
@@ -46,7 +46,7 @@ import bpy
# Generic functions
def area_tri_signed_2x_v2(v1, v2, v3):
- return (v1[0] - v2[0]) * (v2[1] - v3[1]) + (v1[1] - v2[1]) * (v3[0] - v2[0])
+ return (v1[0] - v2[0]) * (v2[1] - v3[1]) + (v1[1] - v2[1]) * (v3[0] - v2[0])
class TriMesh:
diff --git a/release/datafiles/brushicons/gp_brush_airbrush.png b/release/datafiles/brushicons/gp_brush_airbrush.png
new file mode 100644
index 00000000000..3c9aa4273bf
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_airbrush.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_chisel.png b/release/datafiles/brushicons/gp_brush_chisel.png
new file mode 100644
index 00000000000..6fa5071e9be
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_chisel.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_marker.png b/release/datafiles/brushicons/gp_brush_marker.png
index c7a62b78ca7..35a6f38280f 100644
--- a/release/datafiles/brushicons/gp_brush_marker.png
+++ b/release/datafiles/brushicons/gp_brush_marker.png
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.draw_sharp.dat b/release/datafiles/icons/brush.sculpt.draw_sharp.dat
new file mode 100644
index 00000000000..c3e0c7a7536
--- /dev/null
+++ b/release/datafiles/icons/brush.sculpt.draw_sharp.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.elastic_deform.dat b/release/datafiles/icons/brush.sculpt.elastic_deform.dat
new file mode 100644
index 00000000000..6d0ea25c1fe
--- /dev/null
+++ b/release/datafiles/icons/brush.sculpt.elastic_deform.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.mask.dat b/release/datafiles/icons/brush.sculpt.mask.dat
index a0ae683193d..02efb60857f 100644
--- a/release/datafiles/icons/brush.sculpt.mask.dat
+++ b/release/datafiles/icons/brush.sculpt.mask.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.pinch.dat b/release/datafiles/icons/brush.sculpt.pinch.dat
index d81c885e144..4a76c725561 100644
--- a/release/datafiles/icons/brush.sculpt.pinch.dat
+++ b/release/datafiles/icons/brush.sculpt.pinch.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.pose.dat b/release/datafiles/icons/brush.sculpt.pose.dat
new file mode 100644
index 00000000000..6183583ea27
--- /dev/null
+++ b/release/datafiles/icons/brush.sculpt.pose.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.simplify.dat b/release/datafiles/icons/brush.sculpt.simplify.dat
index a7f6ef47c36..f7de2f97aa1 100644
--- a/release/datafiles/icons/brush.sculpt.simplify.dat
+++ b/release/datafiles/icons/brush.sculpt.simplify.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.snake_hook.dat b/release/datafiles/icons/brush.sculpt.snake_hook.dat
index 3b0a8b47bd8..64256d93702 100644
--- a/release/datafiles/icons/brush.sculpt.snake_hook.dat
+++ b/release/datafiles/icons/brush.sculpt.snake_hook.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.sculpt.border_hide.dat b/release/datafiles/icons/ops.sculpt.border_hide.dat
index c95e81a3099..67cd306805c 100644
--- a/release/datafiles/icons/ops.sculpt.border_hide.dat
+++ b/release/datafiles/icons/ops.sculpt.border_hide.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.sculpt.border_mask.dat b/release/datafiles/icons/ops.sculpt.border_mask.dat
index aa4ba9165a3..701b96e31d9 100644
--- a/release/datafiles/icons/ops.sculpt.border_mask.dat
+++ b/release/datafiles/icons/ops.sculpt.border_mask.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.sculpt.mesh_filter.dat b/release/datafiles/icons/ops.sculpt.mesh_filter.dat
new file mode 100644
index 00000000000..164e08b78be
--- /dev/null
+++ b/release/datafiles/icons/ops.sculpt.mesh_filter.dat
Binary files differ
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject 5557cda2a6dc34fc2e18d89fde8e5aa50e374e3
+Subproject 1f6ec7f7a145c36808231090c8666febb49db22
diff --git a/release/datafiles/prvicons.png b/release/datafiles/prvicons.png
index edbffae420b..7c78507a539 100644
--- a/release/datafiles/prvicons.png
+++ b/release/datafiles/prvicons.png
Binary files differ
diff --git a/release/datafiles/prvicons.svg b/release/datafiles/prvicons.svg
index 63cd8dc1954..6c81c0c16b7 100644
--- a/release/datafiles/prvicons.svg
+++ b/release/datafiles/prvicons.svg
@@ -10,20 +10,20 @@
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="192"
- height="192"
+ width="1792"
+ height="256"
id="svg2"
sodipodi:version="0.32"
- inkscape:version="0.92.2 2405546, 2018-03-11"
+ inkscape:version="0.92.3 (2405546, 2018-03-11)"
version="1.0"
sodipodi:docname="prvicons.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
style="display:inline;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
+ inkscape:export-filename="D:\blender-2.8-git\blender\release\datafiles\prvicons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
<metadata
- id="metadata2373">
+ id="metadata2699">
<rdf:RDF>
<cc:Work
rdf:about="">
@@ -35,7 +35,7 @@
</rdf:RDF>
</metadata>
<sodipodi:namedview
- pagecolor="#ffffff"
+ pagecolor="#5b5b5b"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
@@ -43,17 +43,105 @@
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
- inkscape:window-width="1074"
- inkscape:window-height="1896"
- id="namedview2371"
- showgrid="false"
- inkscape:zoom="1.2291667"
- inkscape:cx="60.20339"
- inkscape:cy="13.830508"
- inkscape:window-x="1080"
- inkscape:window-y="0"
- inkscape:window-maximized="0"
- inkscape:current-layer="layer1" />
+ inkscape:window-width="1920"
+ inkscape:window-height="1017"
+ id="namedview2697"
+ showgrid="true"
+ inkscape:snap-bbox="true"
+ inkscape:bbox-paths="true"
+ inkscape:bbox-nodes="true"
+ inkscape:snap-bbox-edge-midpoints="true"
+ inkscape:snap-bbox-midpoints="true"
+ inkscape:zoom="1"
+ inkscape:cx="755.9435"
+ inkscape:cy="49.285986"
+ inkscape:window-x="1912"
+ inkscape:window-y="-8"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1"
+ inkscape:snap-page="true"
+ inkscape:object-paths="true"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:snap-grids="true"
+ inkscape:snap-intersection-paths="true"
+ inkscape:snap-smooth-nodes="true"
+ inkscape:snap-nodes="true"
+ inkscape:snap-global="true"
+ showborder="true"
+ inkscape:showpageshadow="true"
+ inkscape:pagecheckerboard="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid6640"
+ color="#d3d3d3"
+ opacity="0.1254902"
+ empcolor="#ffffff"
+ empopacity="0.25098039"
+ spacingx="1"
+ spacingy="1"
+ empspacing="1"
+ originx="116"
+ originy="-514"
+ visible="true"
+ enabled="true" />
+ <inkscape:grid
+ type="xygrid"
+ id="grid5463"
+ enabled="false"
+ empspacing="0"
+ spacingx="256"
+ spacingy="256"
+ visible="true" />
+ <sodipodi:guide
+ position="256,68"
+ orientation="1,0"
+ id="guide5465"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="512,77"
+ orientation="1,0"
+ id="guide5467"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="768,27"
+ orientation="1,0"
+ id="guide5469"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="1024,5.75"
+ orientation="1,0"
+ id="guide5471"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="1280,-2.5"
+ orientation="1,0"
+ id="guide5473"
+ inkscape:locked="false" />
+ <inkscape:grid
+ type="xygrid"
+ id="grid5475"
+ spacingx="32"
+ spacingy="32"
+ enabled="true" />
+ <inkscape:grid
+ type="xygrid"
+ id="grid5500"
+ spacingx="8"
+ spacingy="8"
+ enabled="false"
+ empspacing="4" />
+ <sodipodi:guide
+ position="1536,19.79899"
+ orientation="1,0"
+ id="guide14233"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="391,162"
+ orientation="0,1"
+ id="guide14345"
+ inkscape:locked="false" />
+ </sodipodi:namedview>
<defs
id="defs4">
<linearGradient
@@ -703,7 +791,7 @@
x2="24.25"
y1="245"
x1="22.75"
- gradientTransform="translate(-61,0)"
+ gradientTransform="translate(-61)"
gradientUnits="userSpaceOnUse"
id="linearGradient23201"
xlink:href="#linearGradient1610"
@@ -713,7 +801,7 @@
x2="24.5"
y1="245"
x1="22.75"
- gradientTransform="translate(-1,0)"
+ gradientTransform="translate(-1)"
gradientUnits="userSpaceOnUse"
id="linearGradient23199"
xlink:href="#linearGradient1610"
@@ -957,7 +1045,7 @@
x2="424.75217"
y1="77.44017"
x1="441.98615"
- gradientTransform="translate(0.01387,0)"
+ gradientTransform="translate(0.01387)"
gradientUnits="userSpaceOnUse"
id="linearGradient22896"
xlink:href="#linearGradient319"
@@ -967,7 +1055,7 @@
x2="424.75217"
y1="78"
x1="438.61115"
- gradientTransform="translate(0.01387,0)"
+ gradientTransform="translate(0.01387)"
gradientUnits="userSpaceOnUse"
id="linearGradient22846"
xlink:href="#linearGradient319"
@@ -977,7 +1065,7 @@
x2="424.75217"
y1="77"
x1="437.98615"
- gradientTransform="translate(0.01387,0)"
+ gradientTransform="translate(0.01387)"
gradientUnits="userSpaceOnUse"
id="linearGradient22844"
xlink:href="#linearGradient319"
@@ -2342,7 +2430,7 @@
x2="336.72485"
y1="143.70836"
x1="349.04059"
- gradientTransform="matrix(0.707107,-0.707107,0.707107,0.707107,-241.7085,428.4841)"
+ gradientTransform="rotate(-45,396.37194,506.00979)"
gradientUnits="userSpaceOnUse"
id="linearGradient15748"
xlink:href="#linearGradient37542"
@@ -3952,7 +4040,7 @@
x2="54.8125"
y1="500"
x1="108"
- gradientTransform="translate(42,0)"
+ gradientTransform="translate(42)"
gradientUnits="userSpaceOnUse"
id="linearGradient16638"
xlink:href="#linearGradient1610"
@@ -3962,7 +4050,7 @@
x2="26.561054"
y1="501.74075"
x1="85.874489"
- gradientTransform="translate(42,0)"
+ gradientTransform="translate(42)"
gradientUnits="userSpaceOnUse"
id="linearGradient16640"
xlink:href="#linearGradient15809"
@@ -4088,7 +4176,7 @@
x2="415.94211"
y1="-34"
x1="416.00461"
- gradientTransform="translate(-0.004608,0)"
+ gradientTransform="translate(-0.004608)"
gradientUnits="userSpaceOnUse"
id="linearGradient30243"
xlink:href="#linearGradient24081"
@@ -4098,7 +4186,7 @@
x2="416.5"
y1="-29.933779"
x1="416.5"
- gradientTransform="translate(-0.004608,0)"
+ gradientTransform="translate(-0.004608)"
gradientUnits="userSpaceOnUse"
id="linearGradient30245"
xlink:href="#linearGradient16500"
@@ -4108,7 +4196,7 @@
x2="416.46497"
y1="-34.342831"
x1="416.41162"
- gradientTransform="translate(-1,0)"
+ gradientTransform="translate(-1)"
gradientUnits="userSpaceOnUse"
id="linearGradient30247"
xlink:href="#linearGradient20324"
@@ -4190,7 +4278,7 @@
x2="415.45193"
y1="-31.506163"
x1="415.41223"
- gradientTransform="translate(-0.004608,0)"
+ gradientTransform="translate(-0.004608)"
gradientUnits="userSpaceOnUse"
id="linearGradient30340"
xlink:href="#linearGradient1610"
@@ -4200,7 +4288,7 @@
x2="416.5"
y1="-29.933779"
x1="416.5"
- gradientTransform="translate(-0.004608,0)"
+ gradientTransform="translate(-0.004608)"
gradientUnits="userSpaceOnUse"
id="linearGradient30342"
xlink:href="#linearGradient16500"
@@ -4210,7 +4298,7 @@
x2="416.46497"
y1="-33.8125"
x1="416.5"
- gradientTransform="translate(-1,0)"
+ gradientTransform="translate(-1)"
gradientUnits="userSpaceOnUse"
id="linearGradient30344"
xlink:href="#linearGradient16500"
@@ -4301,7 +4389,7 @@
x2="415.45193"
y1="-31.506163"
x1="415.41223"
- gradientTransform="translate(-0.004608,0)"
+ gradientTransform="translate(-0.004608)"
gradientUnits="userSpaceOnUse"
id="linearGradient30408"
xlink:href="#linearGradient1610"
@@ -4311,7 +4399,7 @@
x2="416.5"
y1="-29.933779"
x1="416.5"
- gradientTransform="translate(-0.004608,0)"
+ gradientTransform="translate(-0.004608)"
gradientUnits="userSpaceOnUse"
id="linearGradient30410"
xlink:href="#linearGradient16500"
@@ -4321,7 +4409,7 @@
x2="416.46497"
y1="-33.8125"
x1="416.5"
- gradientTransform="translate(-1,0)"
+ gradientTransform="translate(-1)"
gradientUnits="userSpaceOnUse"
id="linearGradient30412"
xlink:href="#linearGradient16500"
@@ -4558,7 +4646,7 @@
x2="-42.377892"
y1="442.6875"
x1="-51.6875"
- gradientTransform="translate(18,0)"
+ gradientTransform="translate(18)"
gradientUnits="userSpaceOnUse"
id="linearGradient17135"
xlink:href="#linearGradient1610"
@@ -4883,7 +4971,7 @@
inkscape:collect="always" />
<linearGradient
y2="-32.351803"
- x2="4.8398785e-16"
+ x2="4.8398785e-016"
y1="-29.678047"
x1="4.9341426"
gradientUnits="userSpaceOnUse"
@@ -5632,7 +5720,7 @@
x2="476.76578"
y1="163.08553"
x1="480.09564"
- gradientTransform="translate(-6,0)"
+ gradientTransform="translate(-6)"
gradientUnits="userSpaceOnUse"
id="linearGradient23241"
xlink:href="#linearGradient19625"
@@ -5681,7 +5769,7 @@
x2="475.50031"
y1="163.08553"
x1="480.09564"
- gradientTransform="translate(-6,0)"
+ gradientTransform="translate(-6)"
gradientUnits="userSpaceOnUse"
id="linearGradient23445"
xlink:href="#linearGradient23974"
@@ -5759,7 +5847,7 @@
x2="60.155113"
y1="253.5"
x1="79.04213"
- gradientTransform="translate(-21,0)"
+ gradientTransform="translate(-21)"
gradientUnits="userSpaceOnUse"
id="linearGradient40967"
xlink:href="#linearGradient32842"
@@ -6107,7 +6195,7 @@
x2="476.68781"
y1="163"
x1="483.00034"
- gradientTransform="translate(-6,0)"
+ gradientTransform="translate(-6)"
gradientUnits="userSpaceOnUse"
id="linearGradient24543"
xlink:href="#linearGradient1610"
@@ -6309,7 +6397,7 @@
x2="284.9375"
y1="200.66605"
x1="268.21783"
- gradientTransform="translate(0.01612278,0)"
+ gradientTransform="translate(0.01612278)"
gradientUnits="userSpaceOnUse"
id="linearGradient41172"
xlink:href="#linearGradient319"
@@ -6361,7 +6449,7 @@
x2="265.70886"
y1="215.3125"
x1="276.39999"
- gradientTransform="translate(0.01612278,0)"
+ gradientTransform="translate(0.01612278)"
gradientUnits="userSpaceOnUse"
id="linearGradient42093"
xlink:href="#linearGradient23974"
@@ -6402,7 +6490,7 @@
x2="290.98389"
y1="195"
x1="265.98389"
- gradientTransform="translate(0.01612278,0)"
+ gradientTransform="translate(0.01612278)"
gradientUnits="userSpaceOnUse"
id="linearGradient42290"
xlink:href="#linearGradient319"
@@ -6581,7 +6669,7 @@
x2="388.78125"
y1="410"
x1="387"
- gradientTransform="translate(-1,0)"
+ gradientTransform="translate(-1)"
gradientUnits="userSpaceOnUse"
id="linearGradient22249"
xlink:href="#linearGradient319"
@@ -6591,7 +6679,7 @@
x2="389.14081"
y1="409.84152"
x1="386.88852"
- gradientTransform="translate(-1,0)"
+ gradientTransform="translate(-1)"
gradientUnits="userSpaceOnUse"
id="linearGradient22251"
xlink:href="#linearGradient319"
@@ -6601,7 +6689,7 @@
x2="388.86676"
y1="409.86362"
x1="387"
- gradientTransform="translate(-1,0)"
+ gradientTransform="translate(-1)"
gradientUnits="userSpaceOnUse"
id="linearGradient22253"
xlink:href="#linearGradient319"
@@ -6839,7 +6927,7 @@
x2="145.5"
y1="627.5"
x1="145.5"
- gradientTransform="matrix(0,1,-1,0,850,297)"
+ gradientTransform="rotate(90,276.5,573.5)"
gradientUnits="userSpaceOnUse"
id="linearGradient23177"
xlink:href="#linearGradient20324"
@@ -6849,7 +6937,7 @@
x2="145.5"
y1="627.5"
x1="145.5"
- gradientTransform="matrix(-1,0,0,-1,366,1072)"
+ gradientTransform="rotate(180,183,536)"
gradientUnits="userSpaceOnUse"
id="linearGradient23179"
xlink:href="#linearGradient20324"
@@ -6859,7 +6947,7 @@
x2="145.5"
y1="627.5"
x1="145.5"
- gradientTransform="matrix(0,-1,1,0,-409,588)"
+ gradientTransform="rotate(-90,89.5,498.5)"
gradientUnits="userSpaceOnUse"
id="linearGradient23181"
xlink:href="#linearGradient20324"
@@ -6889,7 +6977,7 @@
x2="150.5"
y1="647.75"
x1="150.5"
- gradientTransform="matrix(0,1,-1,0,870,292)"
+ gradientTransform="rotate(90,289,581)"
gradientUnits="userSpaceOnUse"
id="linearGradient23187"
xlink:href="#linearGradient37623"
@@ -6909,7 +6997,7 @@
x2="150.5"
y1="647.75"
x1="150.5"
- gradientTransform="matrix(0,-1,1,0,-429,593)"
+ gradientTransform="rotate(-90,82,511)"
gradientUnits="userSpaceOnUse"
id="linearGradient23191"
xlink:href="#linearGradient37623"
@@ -7079,7 +7167,7 @@
x2="145.5"
y1="627.5"
x1="145.5"
- gradientTransform="matrix(0,1,-1,0,850,297)"
+ gradientTransform="rotate(90,276.5,573.5)"
gradientUnits="userSpaceOnUse"
id="linearGradient23580"
xlink:href="#linearGradient20324"
@@ -7089,7 +7177,7 @@
x2="145.5"
y1="627.5"
x1="145.5"
- gradientTransform="matrix(-1,0,0,-1,366,1072)"
+ gradientTransform="rotate(180,183,536)"
gradientUnits="userSpaceOnUse"
id="linearGradient23582"
xlink:href="#linearGradient20324"
@@ -7099,7 +7187,7 @@
x2="145.5"
y1="627.5"
x1="145.5"
- gradientTransform="matrix(0,-1,1,0,-409,588)"
+ gradientTransform="rotate(-90,89.5,498.5)"
gradientUnits="userSpaceOnUse"
id="linearGradient23587"
xlink:href="#linearGradient20324"
@@ -7129,7 +7217,7 @@
x2="150.5"
y1="647.75"
x1="150.5"
- gradientTransform="matrix(0,1,-1,0,870,292)"
+ gradientTransform="rotate(90,289,581)"
gradientUnits="userSpaceOnUse"
id="linearGradient23593"
xlink:href="#linearGradient37623"
@@ -7149,7 +7237,7 @@
x2="150.5"
y1="647.75"
x1="150.5"
- gradientTransform="matrix(0,-1,1,0,-429,593)"
+ gradientTransform="rotate(-90,82,511)"
gradientUnits="userSpaceOnUse"
id="linearGradient23600"
xlink:href="#linearGradient37623"
@@ -7399,7 +7487,7 @@
x2="145.5"
y1="627.5"
x1="145.5"
- gradientTransform="matrix(0,1,-1,0,850,297)"
+ gradientTransform="rotate(90,276.5,573.5)"
gradientUnits="userSpaceOnUse"
id="linearGradient23813"
xlink:href="#linearGradient24632"
@@ -7409,7 +7497,7 @@
x2="145.5"
y1="627.5"
x1="145.5"
- gradientTransform="matrix(-1,0,0,-1,366,1072)"
+ gradientTransform="rotate(180,183,536)"
gradientUnits="userSpaceOnUse"
id="linearGradient23815"
xlink:href="#linearGradient24632"
@@ -7419,7 +7507,7 @@
x2="145.5"
y1="627.5"
x1="145.5"
- gradientTransform="matrix(0,-1,1,0,-409,588)"
+ gradientTransform="rotate(-90,89.5,498.5)"
gradientUnits="userSpaceOnUse"
id="linearGradient23817"
xlink:href="#linearGradient24632"
@@ -7449,7 +7537,7 @@
x2="150.5"
y1="647.75"
x1="150.5"
- gradientTransform="matrix(0,1,-1,0,870,292)"
+ gradientTransform="rotate(90,289,581)"
gradientUnits="userSpaceOnUse"
id="linearGradient23823"
xlink:href="#linearGradient24642"
@@ -7469,7 +7557,7 @@
x2="150.5"
y1="647.75"
x1="150.5"
- gradientTransform="matrix(0,-1,1,0,-429,593)"
+ gradientTransform="rotate(-90,82,511)"
gradientUnits="userSpaceOnUse"
id="linearGradient23827"
xlink:href="#linearGradient24642"
@@ -8133,7 +8221,7 @@
x2="269.3085"
y1="279.72827"
x1="248.69196"
- gradientTransform="translate(-1,0)"
+ gradientTransform="translate(-1)"
gradientUnits="userSpaceOnUse"
id="linearGradient62436"
xlink:href="#linearGradient319"
@@ -8153,7 +8241,7 @@
x2="327.92044"
y1="283.61511"
x1="354.50601"
- gradientTransform="matrix(0,-1,1,0,59,638)"
+ gradientTransform="rotate(-90,348.5,289.5)"
gradientUnits="userSpaceOnUse"
id="linearGradient62560"
xlink:href="#linearGradient319"
@@ -8173,7 +8261,7 @@
x2="344.5"
y1="288.5"
x1="342"
- gradientTransform="matrix(0,1,-1,0,638,-40)"
+ gradientTransform="rotate(90,339,299)"
gradientUnits="userSpaceOnUse"
id="linearGradient25383"
xlink:href="#linearGradient1610"
@@ -8183,7 +8271,7 @@
x2="344.5"
y1="288.5"
x1="342"
- gradientTransform="matrix(-1,0,0,-1,699,599)"
+ gradientTransform="rotate(180,349.5,299.5)"
gradientUnits="userSpaceOnUse"
id="linearGradient25385"
xlink:href="#linearGradient1610"
@@ -8193,7 +8281,7 @@
x2="344.5"
y1="288.5"
x1="342"
- gradientTransform="matrix(0,-1,1,0,60,660)"
+ gradientTransform="rotate(-90,360,300)"
gradientUnits="userSpaceOnUse"
id="linearGradient25387"
xlink:href="#linearGradient1610"
@@ -8213,7 +8301,7 @@
x2="344.5"
y1="288.5"
x1="342"
- gradientTransform="matrix(0,1,-1,0,638,-40)"
+ gradientTransform="rotate(90,339,299)"
gradientUnits="userSpaceOnUse"
id="linearGradient25575"
xlink:href="#linearGradient1610"
@@ -8223,7 +8311,7 @@
x2="344.5"
y1="288.5"
x1="342"
- gradientTransform="matrix(-1,0,0,-1,699,599)"
+ gradientTransform="rotate(180,349.5,299.5)"
gradientUnits="userSpaceOnUse"
id="linearGradient25577"
xlink:href="#linearGradient1610"
@@ -8233,7 +8321,7 @@
x2="344.5"
y1="288.5"
x1="342"
- gradientTransform="matrix(0,-1,1,0,60,660)"
+ gradientTransform="rotate(-90,360,300)"
gradientUnits="userSpaceOnUse"
id="linearGradient25579"
xlink:href="#linearGradient1610"
@@ -8821,7 +8909,7 @@
x2="99.628899"
y1="114.71685"
x1="112.18942"
- gradientTransform="translate(19.367382,0)"
+ gradientTransform="translate(19.367382)"
gradientUnits="userSpaceOnUse"
id="linearGradient27771"
xlink:href="#linearGradient13973"
@@ -8923,7 +9011,7 @@
x2="353.72073"
y1="314.11398"
x1="352.98236"
- gradientTransform="matrix(0.707107,-0.707107,0.707107,0.707107,-346.7085,428.4841)"
+ gradientTransform="rotate(-45,343.872,632.75601)"
gradientUnits="userSpaceOnUse"
id="linearGradient53127"
xlink:href="#linearGradient37542"
@@ -9157,7 +9245,7 @@
x2="-14.000002"
y1="448"
x1="-22.902081"
- gradientTransform="translate(2e-6,0)"
+ gradientTransform="translate(2e-6)"
gradientUnits="userSpaceOnUse"
id="linearGradient50870"
xlink:href="#linearGradient23178"
@@ -9185,7 +9273,7 @@
x2="452.63602"
y1="89.363937"
x1="458.99997"
- gradientTransform="matrix(0.7071068,-0.7071068,0.7071067,0.7071067,-140.04288,401.30258)"
+ gradientTransform="rotate(-45,414.39357,369.69801)"
gradientUnits="userSpaceOnUse"
id="linearGradient33585"
xlink:href="#linearGradient9030"
@@ -9824,7 +9912,7 @@
x2="332.88193"
y1="126.23978"
x1="387.30396"
- gradientTransform="matrix(0.707107,-0.707107,0.707107,0.707107,-241.7085,428.4841)"
+ gradientTransform="rotate(-45,396.37194,506.00979)"
gradientUnits="userSpaceOnUse"
id="linearGradient37636"
xlink:href="#linearGradient37542"
@@ -9834,7 +9922,7 @@
x2="353.72073"
y1="314.11398"
x1="352.98236"
- gradientTransform="matrix(0.707107,-0.707107,0.707107,0.707107,-346.7085,428.4841)"
+ gradientTransform="rotate(-45,343.872,632.75601)"
gradientUnits="userSpaceOnUse"
id="linearGradient37638"
xlink:href="#linearGradient37542"
@@ -11307,7 +11395,7 @@
x2="-20"
y1="283"
x1="-20"
- gradientTransform="translate(-2,0)"
+ gradientTransform="translate(-2)"
gradientUnits="userSpaceOnUse"
id="linearGradient38570"
xlink:href="#linearGradient1610"
@@ -11473,7 +11561,7 @@
x2="97.75"
y1="84.25"
x1="101"
- gradientTransform="translate(21,0)"
+ gradientTransform="translate(21)"
gradientUnits="userSpaceOnUse"
id="linearGradient39843-3"
xlink:href="#linearGradient1610-8"
@@ -11494,7 +11582,7 @@
x2="96.592278"
y1="81.439644"
x1="87.44548"
- gradientTransform="translate(21,0)"
+ gradientTransform="translate(21)"
gradientUnits="userSpaceOnUse"
id="linearGradient39845-2"
xlink:href="#linearGradient319-77"
@@ -11606,7 +11694,7 @@
x2="424.75217"
y1="77"
x1="437.98615"
- gradientTransform="translate(0.01387,0)"
+ gradientTransform="translate(0.01387)"
gradientUnits="userSpaceOnUse"
id="linearGradient41672"
xlink:href="#linearGradient319"
@@ -11616,7 +11704,7 @@
x2="424.75217"
y1="78"
x1="438.61115"
- gradientTransform="translate(0.01387,0)"
+ gradientTransform="translate(0.01387)"
gradientUnits="userSpaceOnUse"
id="linearGradient41674"
xlink:href="#linearGradient319"
@@ -11626,7 +11714,7 @@
x2="424.75217"
y1="77.44017"
x1="441.98615"
- gradientTransform="translate(0.01387,0)"
+ gradientTransform="translate(0.01387)"
gradientUnits="userSpaceOnUse"
id="linearGradient41676"
xlink:href="#linearGradient319"
@@ -11718,7 +11806,7 @@
x2="99.628899"
y1="113.45913"
x1="111.46314"
- gradientTransform="translate(19.367382,0)"
+ gradientTransform="translate(19.367382)"
gradientUnits="userSpaceOnUse"
id="linearGradient38724"
xlink:href="#linearGradient13973"
@@ -11864,7 +11952,7 @@
x2="-28.177105"
y1="-121.58411"
x1="-70.605209"
- gradientTransform="translate(22,0)"
+ gradientTransform="translate(22)"
gradientUnits="userSpaceOnUse"
id="linearGradient39686-1"
xlink:href="#linearGradient1610-3-7"
@@ -11885,7 +11973,7 @@
x2="-55.5975"
y1="-124"
x1="-74"
- gradientTransform="translate(22,0)"
+ gradientTransform="translate(22)"
gradientUnits="userSpaceOnUse"
id="linearGradient39688-9"
xlink:href="#linearGradient319-5-9-4"
@@ -13353,7 +13441,7 @@
x2="-88"
y1="408"
x1="-97"
- gradientTransform="translate(6,0)"
+ gradientTransform="translate(6)"
gradientUnits="userSpaceOnUse"
id="linearGradient38695"
xlink:href="#linearGradient16500"
@@ -13393,7 +13481,7 @@
x2="-88"
y1="413.51562"
x1="-90.5"
- gradientTransform="matrix(-1,0,0,-1,-157,821.03125)"
+ gradientTransform="rotate(180,-78.5,410.51562)"
gradientUnits="userSpaceOnUse"
id="linearGradient38706"
xlink:href="#linearGradient319"
@@ -13413,7 +13501,7 @@
x2="-88"
y1="408"
x1="-97"
- gradientTransform="translate(8,0)"
+ gradientTransform="translate(8)"
gradientUnits="userSpaceOnUse"
id="linearGradient38723"
xlink:href="#linearGradient16500"
@@ -13443,7 +13531,7 @@
x2="-86.75"
y1="413.98114"
x1="-89.75"
- gradientTransform="matrix(-1,0,0,-1,-156,821.03125)"
+ gradientTransform="rotate(180,-78,410.51562)"
gradientUnits="userSpaceOnUse"
id="linearGradient38729"
xlink:href="#linearGradient319"
@@ -13463,7 +13551,7 @@
x2="-86.75"
y1="413.98114"
x1="-89.75"
- gradientTransform="matrix(-1,0,0,-1,-156,824.54874)"
+ gradientTransform="rotate(180,-78,412.27437)"
gradientUnits="userSpaceOnUse"
id="linearGradient38736"
xlink:href="#linearGradient319"
@@ -13492,7 +13580,7 @@
x2="-88"
y1="408"
x1="-97"
- gradientTransform="translate(6,0)"
+ gradientTransform="translate(6)"
gradientUnits="userSpaceOnUse"
id="linearGradient39203"
xlink:href="#linearGradient16500"
@@ -13541,7 +13629,7 @@
x2="-88"
y1="408"
x1="-97"
- gradientTransform="translate(6,0)"
+ gradientTransform="translate(6)"
gradientUnits="userSpaceOnUse"
id="linearGradient39252"
xlink:href="#linearGradient16500"
@@ -13654,7 +13742,7 @@
x2="58.680996"
y1="641.73358"
x1="39.102718"
- gradientTransform="translate(-20,0)"
+ gradientTransform="translate(-20)"
gradientUnits="userSpaceOnUse"
id="linearGradient39508"
xlink:href="#linearGradient319-46"
@@ -13885,7 +13973,7 @@
x2="99.628899"
y1="112.62726"
x1="111.2239"
- gradientTransform="translate(19.367382,0)"
+ gradientTransform="translate(19.367382)"
gradientUnits="userSpaceOnUse"
id="linearGradient40639-1-2-1"
xlink:href="#linearGradient13973-3-7-8"
@@ -14295,7 +14383,7 @@
x2="336.40625"
y1="108.35222"
x1="351.15625"
- gradientTransform="matrix(-1,0,0,-1,698,183)"
+ gradientTransform="rotate(180,349,91.5)"
gradientUnits="userSpaceOnUse"
id="linearGradient44944"
xlink:href="#linearGradient44939-8"
@@ -14563,7 +14651,7 @@
x2="353.72073"
y1="314.11398"
x1="352.98236"
- gradientTransform="matrix(0.707107,-0.707107,0.707107,0.707107,-346.7085,428.4841)"
+ gradientTransform="rotate(-45,343.872,632.75601)"
gradientUnits="userSpaceOnUse"
id="linearGradient25449"
xlink:href="#linearGradient37542"
@@ -14818,7 +14906,7 @@
id="stop37546-94" />
</linearGradient>
<linearGradient
- gradientTransform="matrix(0,1,-1,0,634.98585,-146.00607)"
+ gradientTransform="rotate(90,390.49596,244.48989)"
y2="247.99998"
x2="392.0101"
y1="222.99998"
@@ -15112,13 +15200,13 @@
x2="752"
y1="402"
x1="743"
- gradientTransform="matrix(0,-1,1,0,-239.00001,1286)"
+ gradientTransform="rotate(-90,523.5,762.5)"
gradientUnits="userSpaceOnUse"
id="linearGradient28583"
xlink:href="#linearGradient16500"
inkscape:collect="always" />
<linearGradient
- gradientTransform="matrix(0,1,-1,0,574.99991,384.00001)"
+ gradientTransform="rotate(90,95.49995,479.49996)"
y2="406.47784"
x2="161.83331"
y1="413.87982"
@@ -15142,7 +15230,7 @@
x2="163.11441"
y1="544.21143"
x1="148.56801"
- gradientTransform="matrix(0,1,-1,0,719.99999,383.00001)"
+ gradientTransform="rotate(90,168.49999,551.5)"
gradientUnits="userSpaceOnUse"
id="linearGradient28600"
xlink:href="#linearGradient319"
@@ -15685,7 +15773,7 @@
x2="85.347076"
y1="100.22395"
x1="85.548706"
- gradientTransform="matrix(0.707107,-0.707107,0.707107,0.707107,257.1483,118.6716)"
+ gradientTransform="rotate(-45,271.82331,-251.06972)"
gradientUnits="userSpaceOnUse"
id="linearGradient31019"
xlink:href="#linearGradient319"
@@ -15705,7 +15793,7 @@
x2="85.347076"
y1="100.22395"
x1="85.548706"
- gradientTransform="matrix(0.707107,-0.707107,0.707107,0.707107,257.1483,118.6716)"
+ gradientTransform="rotate(-45,271.82331,-251.06972)"
gradientUnits="userSpaceOnUse"
id="linearGradient31055"
xlink:href="#linearGradient319"
@@ -15725,7 +15813,7 @@
x2="85.347076"
y1="100.22395"
x1="85.548706"
- gradientTransform="matrix(0.707107,-0.707107,0.707107,0.707107,257.1483,118.6716)"
+ gradientTransform="rotate(-45,271.82331,-251.06972)"
gradientUnits="userSpaceOnUse"
id="linearGradient31151"
xlink:href="#linearGradient319"
@@ -15745,7 +15833,7 @@
x2="85.60022"
y1="99.348953"
x1="85.861206"
- gradientTransform="matrix(0.707107,-0.707107,0.707107,0.707107,257.14826,118.6716)"
+ gradientTransform="rotate(-45,271.82329,-251.06967)"
gradientUnits="userSpaceOnUse"
id="linearGradient31155"
xlink:href="#linearGradient30958"
@@ -15850,7 +15938,7 @@
x2="-303.00003"
y1="475"
x1="-307"
- gradientTransform="translate(-42,0)"
+ gradientTransform="translate(-42)"
gradientUnits="userSpaceOnUse"
id="linearGradient52998-5-5"
xlink:href="#linearGradient319-31-8-9-1"
@@ -15882,7 +15970,7 @@
x2="-304.76843"
y1="476.0105"
x1="-308.7684"
- gradientTransform="translate(-42,0)"
+ gradientTransform="translate(-42)"
gradientUnits="userSpaceOnUse"
id="linearGradient53000-3-9"
xlink:href="#linearGradient319-31-8-9-1"
@@ -16554,31 +16642,45 @@
offset="1"
id="stop39175-18" />
</linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient37667"
+ id="linearGradient13927"
+ gradientUnits="userSpaceOnUse"
+ x1="804.17645"
+ y1="-262.1517"
+ x2="832.15369"
+ y2="-234.17448" />
</defs>
<path
inkscape:connector-curvature="0"
d=""
sodipodi:nodetypes="cc"
id="path23417"
- style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#1a1a1a;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#1a1a1a;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
<path
inkscape:connector-curvature="0"
d=""
sodipodi:nodetypes="cc"
id="path23347"
- style="fill:none;stroke:#ffffff;stroke-width:1.79999995;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ style="fill:none;stroke:#ffffff;stroke-width:1.79999995;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="sheet_layout"
- style="display:inline" />
+ style="display:none"
+ transform="translate(116,578)" />
<g
- transform="translate(-872,-180)"
+ transform="translate(-756,398)"
style="display:inline"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="ICONS">
<g
+ style="opacity:0.5"
+ id="g7488"
+ transform="translate(218)" />
+ <g
transform="translate(-211.20006,170)"
id="g10203" />
<g
@@ -16748,7 +16850,7 @@
<g
id="g17117" />
<g
- transform="translate(9,0)"
+ transform="translate(9)"
id="g17121" />
<g
id="g17128"
@@ -16797,7 +16899,7 @@
transform="translate(67,200.06499)"
id="g22051" />
<g
- transform="translate(-23,0)"
+ transform="translate(-23)"
id="g40816">
<g
id="g40830" />
@@ -16855,7 +16957,7 @@
inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
- transform="matrix(-1,0,0,-1,104.1613,262.99999)"
+ transform="rotate(180,52.08065,131.5)"
style="display:inline;stroke:#ffffff">
<path
inkscape:connector-curvature="0"
@@ -16918,13 +17020,6 @@
inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
- <rect
- y="180"
- x="872"
- height="192"
- width="192"
- id="rect30285"
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:5.39191818;marker:none;enable-background:accumulate" />
<g
transform="translate(0,12)"
id="g46790" />
@@ -16937,714 +17032,262 @@
d=""
inkscape:connector-curvature="0" />
<g
- id="g15770-4"
- transform="translate(-1653.0047,902.99644)"
- style="display:inline;opacity:0.6;enable-background:new">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 2691.4961,-577 c -1.4585,10e-6 -2.8611,0.57961 -3.877,1.63477 L 2673.293,-561 h 14.705 c 0.5523,-6e-5 0.9999,-0.44774 1,-1 v -10.5 c 0,-1.94484 1.5551,-3.5 3.5,-3.5 0.6573,-0.009 0.9864,-0.50465 0.9864,-1 z"
- id="path15766-8"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="cccccccc"
- inkscape:connector-curvature="0"
- d="m 2691.4963,-576.50002 h 19.9969 c 0.5523,-3e-5 1,0.44769 1.0015,0.99998 l 0.01,41.00357 c 0,0.55581 -0.4477,1.00353 -1,1 h -37.0035 c -0.5559,0.004 -1.0036,-0.44419 -1,-1 v -24.00355"
- style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- id="path15768-2" />
- </g>
- <path
- sodipodi:nodetypes="ccssssssccccscssscccccsscscsccccssccc"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 875.49998,329 c -0.4167,0 -0.7749,0.19292 -1.041,0.45898 -0.2661,0.26607 -0.459,0.62435 -0.459,1.04102 v 32 c 0,3.03164 2.4684,5.5 5.5,5.5 H 912.5 c 3.0316,0 5.5,-2.46836 5.5,-5.5 v -20 c 0,-0.42425 -0.1991,-0.77237 -0.4648,-1.04883 -0.2658,-0.27646 -0.6395,-0.51191 -1.1055,-0.44531 l 0.07,-0.006 h -6.5 -27.50002 c -0.095,0 -0.1807,0.0361 -0.3223,0.17773 -0.1417,0.14177 -0.1777,0.22697 -0.1777,0.32227 v 21 c 0,1.20549 -0.8756,2.25014 -2.0625,2.46094 -1.1869,0.2108 -2.3701,-0.46784 -2.7852,-1.59961 -0.041,-0.1158 -0.061,-0.23824 -0.058,-0.36119 h 2.4062 v -0.008 c 0.03,-2.1e-4 0.058,0.005 0.088,0 0.2451,-0.0435 0.4121,-0.2432 0.4121,-0.49219 v -21 c 0,-0.74923 0.3782,-1.35083 0.7637,-1.73633 0.3856,-0.38565 0.9871,-0.76367 1.7363,-0.76367 h 27.50002 v -4.5 c 0,-0.41667 -0.1929,-0.77495 -0.459,-1.04102 -0.2661,-0.26606 -0.6243,-0.45898 -1.041,-0.45898 l -18.02732,0.0449 c -0.055,1.2e-4 -0.1892,-0.0544 -0.2989,-0.17383 -0.1114,-0.1193 -0.1738,-0.28349 -0.1738,-0.37109 v -2 c 0,-0.41667 -0.1929,-0.77495 -0.459,-1.04102 -0.2661,-0.26606 -0.6243,-0.45898 -1.041,-0.45898 z"
- id="path15794"
- inkscape:connector-curvature="0" />
- <g
- transform="translate(-1139.094,997)"
+ transform="translate(810,316.5)"
style="display:inline;enable-background:new"
- id="g16516">
- <g
- id="g15792"
- transform="translate(-500,-182)"
- style="opacity:0.6">
- <path
- sodipodi:nodetypes="cscssscssssssssssccsc"
- inkscape:connector-curvature="0"
- d="m 2564.8618,-451.50005 c 0.3211,0.5561 0.8787,0.91004 1.4878,0.98518 0.2496,0.0308 0.5078,0.0148 0.7619,-0.0533 0.8744,-0.23427 1.4824,-1.02663 1.4824,-1.93185 v -22 c 0,-0.4714 0.5286,-1 1,-1 l 34,2e-5 c 0.4667,-0.0667 1,0.52863 1,1.00003 v 22 c 0,2.76142 -2.2386,5 -5,5 h -33 c -2.7614,0 -5,-2.23858 -5,-5 v -33 c 0,-0.5 0.5,-1 1,-1 h 13 c 0.5,0 1,0.5 1,1 v 2 c 0,0.5 0.4872,1.0452 0.9723,1.0442 l 18.0277,-0.0442 c 0.5,0 1,0.5 1,1 v 2"
- style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- id="path15787" />
- <path
- sodipodi:nodetypes="cc"
- inkscape:connector-curvature="0"
- id="path15790"
- d="m 2596.5,-479.5 v 1.5"
- style="fill:none;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
- </g>
- <g
- id="g15799"
- transform="matrix(0,1,1,0,2028.5,-908.5)"
- style="display:inline;opacity:1;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
- inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <path
- id="path15797"
- style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- d="m 271.5,63.5 v -5 c 0,-1.104569 -0.89543,-2 -2,-2 h -11 m 4,5 -5,-5 5,-5"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccc" />
- </g>
- </g>
+ id="g72880" />
+ <image
+ sodipodi:absref="C:\Users\Andrzej Ambroż\Desktop\a230341b4bf9a9d653c3e8062c4702e859d6d32f.png"
+ y="143.4964"
+ x="8460.25"
+ id="image7203"
+ xlink:href="file:///C:/Users/Andrzej%20Ambro%C5%BC/Desktop/a230341b4bf9a9d653c3e8062c4702e859d6d32f.png"
+ style="stroke-width:0.69403505;image-rendering:optimizeSpeed"
+ preserveAspectRatio="none"
+ height="487.00717"
+ width="1377.452" />
<g
- style="display:inline;opacity:0.6;enable-background:new"
- transform="translate(-1653.0001,855.00002)"
- id="g6937">
- <path
- inkscape:connector-curvature="0"
- id="path6933"
- d="m 2691.4961,-577 c -1.4585,10e-6 -2.8611,0.57961 -3.877,1.63477 L 2673.293,-561 h 14.705 c 0.5523,-6e-5 0.9999,-0.44774 1,-1 v -10.5 c 0,-1.94484 1.5551,-3.5 3.5,-3.5 0.6573,-0.009 0.9864,-0.50465 0.9864,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <path
- id="path6935"
- style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- d="m 2691.4963,-576.50002 h 19.9969 c 0.5523,-3e-5 1,0.44769 1.0015,0.99998 l 0.01,41.00357 c 0,0.55581 -0.4477,1.00353 -1,1 h -37.0035 c -0.5559,0.004 -1.0036,-0.44419 -1,-1 v -24.00355"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccc" />
- </g>
+ transform="translate(-30,-450)"
+ id="g7205" />
<g
- id="g6943"
- transform="translate(-1701.0001,855.00002)"
- style="display:inline;opacity:0.6;enable-background:new">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 2691.4961,-577 c -1.4585,10e-6 -2.8611,0.57961 -3.877,1.63477 L 2673.293,-561 h 14.705 c 0.5523,-6e-5 0.9999,-0.44774 1,-1 v -10.5 c 0,-1.94484 1.5551,-3.5 3.5,-3.5 0.6573,-0.009 0.9864,-0.50465 0.9864,-1 z"
- id="path6939"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="cccccccc"
- inkscape:connector-curvature="0"
- d="m 2691.4963,-576.50002 h 19.9969 c 0.5523,-3e-5 1,0.44769 1.0015,0.99998 l 0.01,41.00357 c 0,0.55581 -0.4477,1.00353 -1,1 h -37.0035 c -0.5559,0.004 -1.0036,-0.44419 -1,-1 v -24.00355"
- style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- id="path6941" />
- </g>
+ id="g7480"
+ transform="matrix(8.4250411,0,0,8.2967687,-7333.563,3000.3193)"
+ style="stroke-width:0.1196078" />
<g
- style="display:inline;opacity:0.6;enable-background:new"
- transform="translate(-1749.0047,854.99644)"
- id="g6949">
- <path
- inkscape:connector-curvature="0"
- id="path6945"
- d="m 2691.4961,-577 c -1.4585,10e-6 -2.8611,0.57961 -3.877,1.63477 L 2673.293,-561 h 14.705 c 0.5523,-6e-5 0.9999,-0.44774 1,-1 v -10.5 c 0,-1.94484 1.5551,-3.5 3.5,-3.5 0.6573,-0.009 0.9864,-0.50465 0.9864,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <path
- id="path6947"
- style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- d="m 2691.4963,-576.50002 h 19.9969 c 0.5523,-3e-5 1,0.44769 1.0015,0.99998 l 0.01,41.00357 c 0,0.55581 -0.4477,1.00353 -1,1 h -37.0035 c -0.5559,0.004 -1.0036,-0.44419 -1,-1 v -24.00355"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccc" />
- </g>
+ style="stroke-width:0.1196078"
+ transform="matrix(8.4250411,0,0,-8.2967687,-7336.563,-3470.4526)"
+ id="g7569" />
<g
- id="g6955"
- transform="translate(-1797.0001,855.00002)"
- style="display:inline;opacity:0.6;enable-background:new">
+ style="display:inline;stroke-width:0.10177074;enable-background:new"
+ id="g7452"
+ transform="matrix(14.821991,0,0,14.654739,-7251.9905,-1149.2844)">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 2691.4961,-577 c -1.4585,10e-6 -2.8611,0.57961 -3.877,1.63477 L 2673.293,-561 h 14.705 c 0.5523,-6e-5 0.9999,-0.44774 1,-1 v -10.5 c 0,-1.94484 1.5551,-3.5 3.5,-3.5 0.6573,-0.009 0.9864,-0.50465 0.9864,-1 z"
- id="path6951"
+ style="display:inline;opacity:0.2;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.20354147;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 613.67414,61.535437 h 8.65173 c 0.57439,0 1.03681,0.46242 1.03681,1.036816 v 2.839759 c 0,0.574396 -0.46242,1.036815 -1.03681,1.036815 h -8.65173 c -0.57439,0 -1.03681,-0.462419 -1.03681,-1.036815 v -2.839759 c 0,-0.574396 0.46242,-1.036816 1.03681,-1.036816 z"
+ id="rect7450"
inkscape:connector-curvature="0" />
<path
- sodipodi:nodetypes="cccccccc"
- inkscape:connector-curvature="0"
- d="m 2691.4963,-576.50002 h 19.9969 c 0.5523,-3e-5 1,0.44769 1.0015,0.99998 l 0.01,41.00357 c 0,0.55581 -0.4477,1.00353 -1,1 h -37.0035 c -0.5559,0.004 -1.0036,-0.44419 -1,-1 v -24.00355"
- style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- id="path6953" />
- </g>
- <g
- id="g6961"
- transform="translate(-1653.0001,807.00002)"
- style="display:inline;opacity:0.6;enable-background:new">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 2691.4961,-577 c -1.4585,10e-6 -2.8611,0.57961 -3.877,1.63477 L 2673.293,-561 h 14.705 c 0.5523,-6e-5 0.9999,-0.44774 1,-1 v -10.5 c 0,-1.94484 1.5551,-3.5 3.5,-3.5 0.6573,-0.009 0.9864,-0.50465 0.9864,-1 z"
- id="path6957"
+ id="path7424"
+ transform="matrix(0.10118267,0,0,0.10236222,598.97766,126.33073)"
+ d="M 145.24609,-711 C 139.56927,-711 135,-706.4825 135,-700.87109 v 78 C 135,-628.4825 139.56927,-633 145.24609,-633 h 85.50782 c 5.67682,0 10.24609,4.5175 10.24609,10.12891 v -78 C 241,-706.4825 236.43073,-711 230.75391,-711 Z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
inkscape:connector-curvature="0" />
<path
- sodipodi:nodetypes="cccccccc"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 553.24414,21.003906 c -6.21668,0 -11.25391,4.978036 -11.25391,11.123047 v 78.001957 27.74414 c 0,6.14501 5.03723,11.12304 11.25391,11.12304 h 85.51172 c 2.7198,0 5.21303,-0.95235 7.1582,-2.53906 2.50094,-2.04005 4.09571,-5.12741 4.09571,-8.58398 V 110.12891 32.126953 c 0,-6.145011 -5.03723,-11.123047 -11.25391,-11.123047 z m 0,1.984375 h 85.51172 c 5.13704,0 9.24609,4.060861 9.24609,9.138672 v 71.667967 c -2.03176,-2.89305 -5.41213,-4.789061 -9.24609,-4.789061 h -85.51172 c -3.83396,0 -7.21433,1.896011 -9.24609,4.789061 V 32.126953 c 0,-5.077811 4.10905,-9.138672 9.24609,-9.138672 z m 0,78.001949 h 85.51172 c 5.13704,0 8.58679,4.26374 8.58679,9.34155 v 27.33166 c 0,5.07781 -3.53119,8.66614 -8.66823,8.66614 h -85.34878 c -5.13704,0 -8.66823,-3.58833 -8.66823,-8.66614 v -27.33166 c 0,-5.07781 3.44969,-9.34155 8.58673,-9.34155 z"
+ id="rect7426"
+ transform="matrix(0.10118267,0,0,0.10236222,557.69513,51.299216)"
inkscape:connector-curvature="0"
- d="m 2691.4963,-576.50002 h 19.9969 c 0.5523,-3e-5 1,0.44769 1.0015,0.99998 l 0.01,41.00357 c 0,0.55581 -0.4477,1.00353 -1,1 h -37.0035 c -0.5559,0.004 -1.0036,-0.44419 -1,-1 v -24.00355"
- style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- id="path6959" />
- </g>
- <g
- style="display:inline;opacity:0.6;enable-background:new"
- transform="translate(-1701.0001,807.00002)"
- id="g6967">
+ sodipodi:nodetypes="sscssscscsssssscsscsssssssssss" />
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.10177073;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 621.91311,62.457001 c 0.22334,0 0.40429,0.180956 0.40429,0.404297 v 0.0098 c 0,0.22334 -0.18095,0.404297 -0.40429,0.404297 -0.22335,0 -0.40625,-0.180957 -0.40625,-0.404297 v -0.0098 c 0,-0.223341 0.1829,-0.404297 0.40625,-0.404297 z"
+ id="rect7434"
inkscape:connector-curvature="0"
- id="path6963"
- d="m 2691.4961,-577 c -1.4585,10e-6 -2.8611,0.57961 -3.877,1.63477 L 2673.293,-561 h 14.705 c 0.5523,-6e-5 0.9999,-0.44774 1,-1 v -10.5 c 0,-1.94484 1.5551,-3.5 3.5,-3.5 0.6573,-0.009 0.9864,-0.50465 0.9864,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="sssssss" />
<path
- id="path6965"
- style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- d="m 2691.4963,-576.50002 h 19.9969 c 0.5523,-3e-5 1,0.44769 1.0015,0.99998 l 0.01,41.00357 c 0,0.55581 -0.4477,1.00353 -1,1 h -37.0035 c -0.5559,0.004 -1.0036,-0.44419 -1,-1 v -24.00355"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.20354147;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 613.57935,62.45579 c -0.056,0.0012 -0.10057,0.04747 -0.0996,0.103516 v 2.867187 c -0.01,0.144644 0.21266,0.144644 0.20312,0 v -2.867187 c 9.9e-4,-0.05757 -0.0459,-0.104503 -0.10351,-0.103516 z m 0.60742,0 c -0.056,0.0012 -0.10057,0.04747 -0.0996,0.103516 v 2.867187 c -0.01,0.144644 0.21266,0.144644 0.20312,0 v -2.867187 c 9.9e-4,-0.05757 -0.0459,-0.104503 -0.10351,-0.103516 z m 0.60742,0 c -0.0568,1.15e-4 -0.10253,0.04671 -0.10156,0.103516 v 2.867187 c 0,0.136713 0.20507,0.136713 0.20507,0 v -2.867187 c 9.9e-4,-0.05757 -0.0459,-0.104503 -0.10351,-0.103516 z m 0.60742,0 c -0.0568,1.15e-4 -0.10253,0.04671 -0.10156,0.103516 v 2.867187 c -0.01,0.144644 0.21266,0.144644 0.20312,0 v -2.867187 c 9.7e-4,-0.0568 -0.0447,-0.103401 -0.10156,-0.103516 z m 0.60547,0 c -0.056,0.0012 -0.10057,0.04747 -0.0996,0.103516 v 2.867187 c -0.01,0.144644 0.21266,0.144644 0.20312,0 v -2.867187 c 9.9e-4,-0.05757 -0.0459,-0.104503 -0.10351,-0.103516 z"
+ id="path7444"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccc" />
+ sodipodi:nodetypes="ccccccccccccccccssccccccccccccccc" />
</g>
<g
- id="g6973"
- transform="translate(-1749.0047,806.99644)"
- style="display:inline;opacity:0.6;enable-background:new">
+ transform="matrix(12.319682,0,0,12.172353,-5459.9739,-996.34032)"
+ id="g7322"
+ style="display:inline;stroke-width:0.12309717;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 2691.4961,-577 c -1.4585,10e-6 -2.8611,0.57961 -3.877,1.63477 L 2673.293,-561 h 14.705 c 0.5523,-6e-5 0.9999,-0.44774 1,-1 v -10.5 c 0,-1.94484 1.5551,-3.5 3.5,-3.5 0.6573,-0.009 0.9864,-0.50465 0.9864,-1 z"
- id="path6969"
+ style="display:inline;opacity:0.2;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.24619435;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 613.67414,61.612633 h 8.65173 c 0.57439,0 1.03681,0.46242 1.03681,1.036815 v 2.762566 c 0,0.574395 -0.46242,1.036815 -1.03681,1.036815 h -8.65173 c -0.57439,0 -1.03681,-0.46242 -1.03681,-1.036815 v -2.762566 c 0,-0.574395 0.46242,-1.036815 1.03681,-1.036815 z"
+ id="rect7418"
inkscape:connector-curvature="0" />
<path
- sodipodi:nodetypes="cccccccc"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.41910744;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="M 145.24609,-711 C 139.56928,-711.01185 135,-706.4825 135,-700.87109 v 78 c 0,-5.61141 4.56928,-10.14076 10.24609,-10.12891 l 85.17749,0.17786 c 5.67681,0.0118 10.24609,4.5175 10.24609,10.12891 v -78 c 0,-5.61141 -4.56928,-10.11706 -10.24609,-10.12891 l -42.58875,-0.0889 z"
+ transform="matrix(0.10118267,0,0,0.10236222,598.97766,126.33073)"
+ id="rect7413"
inkscape:connector-curvature="0"
- d="m 2691.4963,-576.50002 h 19.9969 c 0.5523,-3e-5 1,0.44769 1.0015,0.99998 l 0.01,41.00357 c 0,0.55581 -0.4477,1.00353 -1,1 h -37.0035 c -0.5559,0.004 -1.0036,-0.44419 -1,-1 v -24.00355"
- style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- id="path6971" />
- </g>
- <g
- style="display:inline;opacity:0.6;enable-background:new"
- transform="translate(-1797.0001,807.00002)"
- id="g6979">
+ sodipodi:nodetypes="sscsscsscs" />
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 717.48242,42.996094 c -5.24135,0 -9.49414,4.190752 -9.49414,9.355468 v 65.017578 22.26953 c 0,5.16472 4.25279,9.35547 9.49414,9.35547 h 70.02539 c 5.24136,0 9.49414,-4.19075 9.49414,-9.35547 V 117.36914 52.351562 c 0,-5.164716 -4.25278,-9.355468 -9.49414,-9.355468 z m 0,1.984375 h 70.02539 c 4.15996,0 7.48047,3.271903 7.48047,7.371093 v 59.269528 c -1.73801,-2.19271 -4.43984,-3.60742 -7.48047,-3.60742 h -70.02539 c -3.04062,0 -5.74244,1.41471 -7.48047,3.60742 V 52.351562 c 0,-4.09919 3.32052,-7.371093 7.48047,-7.371093 z m 0,65.017581 h 70.02539 c 4.15996,0 6.83699,3.09749 6.83699,7.19667 l 0,21.8621 c -10e-6,4.09919 -3.14714,7.28736 -7.3071,7.28736 l -69.08523,0 c -4.15995,0 -7.30707,-3.18817 -7.30709,-7.28736 -3.1e-4,-47.435614 0,-14.3539 0,-21.8621 0,-4.09918 2.67709,-7.19667 6.83704,-7.19667 z"
+ transform="matrix(0.12219364,0,0,0.1240074,526.00203,48.095825)"
+ id="rect7312"
inkscape:connector-curvature="0"
- id="path6975"
- d="m 2691.4961,-577 c -1.4585,10e-6 -2.8611,0.57961 -3.877,1.63477 L 2673.293,-561 h 14.705 c 0.5523,-6e-5 0.9999,-0.44774 1,-1 v -10.5 c 0,-1.94484 1.5551,-3.5 3.5,-3.5 0.6573,-0.009 0.9864,-0.50465 0.9864,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <path
- id="path6977"
- style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- d="m 2691.4963,-576.50002 h 19.9969 c 0.5523,-3e-5 1,0.44769 1.0015,0.99998 l 0.01,41.00357 c 0,0.55581 -0.4477,1.00353 -1,1 h -37.0035 c -0.5559,0.004 -1.0036,-0.44419 -1,-1 v -24.00355"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccc" />
+ sodipodi:nodetypes="sscsssscsssssscsscssssssssscs" />
+ <g
+ id="g7411"
+ transform="matrix(-1,0,0,1,1235.8994,0)"
+ style="stroke-width:0.12309717">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.12309717;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 613.88871,62.499044 c -0.23599,0 -0.42773,0.193143 -0.42773,0.429687 v 0.0098 c 0,0.236544 0.19174,0.429687 0.42773,0.429687 0.23599,0 0.42774,-0.193143 0.42774,-0.429687 v -0.0098 c 0,-0.236544 -0.19175,-0.429687 -0.42774,-0.429687 z"
+ id="rect7316"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssss" />
+ <g
+ transform="translate(6.2733256)"
+ id="g7368"
+ style="display:inline;stroke-width:0.12309717;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.24619435;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 613.40672,62.503838 c -0.0633,0.0071 -0.11074,0.06131 -0.10937,0.125 V 65.4804 c 0,0.165367 0.24805,0.165367 0.24805,0 v -2.851562 c 0.002,-0.07532 -0.0639,-0.13455 -0.13868,-0.125 z m 0.64679,10e-7 c -0.0633,0.0071 -0.11074,0.06131 -0.10937,0.125 V 65.4804 c -0.005,0.169458 0.25158,0.169458 0.24609,0 v -2.851562 c 0.002,-0.07444 -0.0627,-0.133249 -0.13672,-0.124999 z m 0.64937,10e-7 c -0.0633,0.0071 -0.11074,0.06131 -0.10937,0.125 v 2.85156 c -0.005,0.169458 0.25158,0.169458 0.24609,0 v -2.851562 c 0.002,-0.07444 -0.0627,-0.133249 -0.13672,-0.124998 z m 0.65195,1e-6 c -0.0633,0.0071 -0.11075,0.06131 -0.10938,0.125 v 2.85156 c -0.005,0.169247 0.25137,0.169247 0.2461,0 v -2.851562 c 0.002,-0.07444 -0.0627,-0.133249 -0.13672,-0.124998 z m 0.64937,-3e-6 c -0.0633,0.0071 -0.11075,0.06131 -0.10938,0.125 V 65.4804 c -0.005,0.169248 0.25136,0.169248 0.2461,0 v -2.851563 c 0.002,-0.07444 -0.0627,-0.133249 -0.13672,-0.124999 z"
+ id="path7359"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccsscccccccccccccccccccccccccc" />
+ </g>
+ </g>
</g>
<g
- transform="translate(810,316.5)"
- style="display:inline;enable-background:new"
- id="g72880" />
- <g
- id="g3789">
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 996,189 v 0.75 h -1 v 3.5 h 1 V 194 h 2 v -1 -1.25 h -1 V 193 h -1 v -3 h 2 v -1 z"
- id="path72434" />
- <rect
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- id="rect72436"
- width="1"
- height="5"
- x="1029"
- y="189" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 954,189 v 4 h -1 v -1 h -1 v 1 h 0.75 v 1 h 1.5 v -1 H 955 v -4 z"
- id="path72438" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 999,189 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
- id="path72440" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 975,189 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
- id="path72442" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 940,189 v 0.75 h -1 v 1.5 h 1 V 192 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 191 h -1 v -1 h 1.5 v -1 z"
- id="path72446" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 964,189 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
- id="path72448" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 943,189 v 4.25 h 1 V 194 h 2 v -0.75 h 1 V 189 h -1 v 4 h -2 v -4 z"
- id="path72450" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 948,189 v 5 h 1 1 v -0.5 h 1 V 192 h -0.75 v -1 H 951 v -1.25 h -1 V 189 h -1 z m 1,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z"
- id="path72452" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 961,189 v 0.75 h -1 v 3.5 h 1 V 194 h 2 v -1 h -2 v -3 h 2 v -1 z"
- id="path72454" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 956,189 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
- id="path72456" />
- <path
- inkscape:connector-curvature="0"
- id="path72458"
- d="m 1019,189 v 5 h 1 2 v -1 h -2 v -4 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6" />
- <path
- id="path72460"
- d="m 970,189 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 981,189 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
- id="path72462" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 985,189 v 5 h 1 v -2 h 1 v 2 h 1 v -5 h -1 v 2 h -1 v -2 z"
- id="path72464" />
- <path
- id="path72466"
- d="m 989,189 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <path
- id="path72468"
- d="m 1004,189 v 4.25 h 1 V 194 h 2 v -0.75 h 1 V 189 h -1 v 4 h -2 v -4 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <path
- id="path72470"
- d="m 1012,189 v 0.75 h -1 v 3.5 h 1 V 194 h 2 v -1 -1.25 h -1 V 193 h -1 v -3 h 2 v -1 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 1015,189 v 5 h 1 v -2 h 1.25 v -1 h 0.75 v -1.25 h -1 V 189 h -1 z m 1,1 h 1 v 1 h -1 z"
- id="path72472" />
- <path
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 1025,189 v 5 h 1 2 v -1 h -2 v -4 z"
- id="path72474"
- inkscape:connector-curvature="0" />
- <path
- id="path72476"
- d="m 1032,189 v 0.75 h -1 v 3.5 h 1 V 194 h 2 v -1 h -2 v -3 h 2 v -1 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 1035,189 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
- id="path72478" />
- <path
- id="path72480"
- d="m 1039,189 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <path
- id="path72482"
- d="m 1045,189 v 0.75 h -1 v 3.5 h 1 V 194 h 2 v -1 h -2 v -3 h 2 v -1 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <path
- id="path72484"
- d="m 1048,189 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 1052.75,193 v 1 H 1052 v 1 h 1 v -1 h 1 v -1 z"
- id="path72486" />
- <path
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 882,189 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
- id="path32008-7"
- inkscape:connector-curvature="0" />
- <path
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 886,189 v 5 h 1 v -2 h 1 v 2 h 1 v -5 h -1 v 2 h -1 v -2 z"
- id="path32010-4"
- inkscape:connector-curvature="0" />
- <rect
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- id="rect32012-0"
- width="1"
- height="5"
- x="890"
- y="189" />
- <path
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 893,189 v 0.75 h -1 v 1.5 h 1 V 192 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 191 h -1 v -1 h 1.5 v -1 z"
- id="path32015-9"
- inkscape:connector-curvature="0" />
- <path
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 899,189 v 0.75 h -1 v 3.5 h 1 V 194 h 2 v -1 h -2 v -3 h 2 v -1 z"
- id="path32017-4"
- inkscape:connector-curvature="0" />
- <path
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 907,189 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
- id="path32019-8"
- inkscape:connector-curvature="0" />
- <path
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 903,189 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
- id="path32021-8"
- inkscape:connector-curvature="0" />
- <path
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 912,189 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
- id="path32023-2"
- inkscape:connector-curvature="0" />
- <path
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 916,189 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
- id="path32026-4"
- inkscape:connector-curvature="0" />
- <path
- id="path32029-5"
- d="m 920,189 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <path
- id="path32031-5"
- d="m 925,189 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <rect
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- id="rect32033-1"
- width="1"
- height="5"
- x="931"
- y="189" />
- <path
- id="path32035-7"
- d="m 934,189 v 0.75 h -1 v 1.5 h 1 V 192 h 1 v 1 h -2 v 1 h 2 v -0.75 h 1 v -1.5 h -1 V 191 h -1 v -1 h 1.5 v -1 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 888,197 v 5 h 1 v -2 h 1 v 2 h 1 v -5 h -1 v 2 h -1 v -2 z"
- id="path72562" />
- <rect
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- id="rect72564"
- width="1"
- height="5"
- x="892"
- y="197" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 882,197 v 3.25 h 1 V 202 h 1 v -1.75 h 1 V 202 h 1 v -1.75 h 1 V 197 h -1 v 3 h -1 v -2 h -1 v 2 h -1 v -3 z"
- id="path72576" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 940,197 v 2.25 h 1 V 202 h 1 v -2.75 h 1 V 197 h -1 v 2 h -1 v -2 z"
- id="path72578" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 904.75,197 v 1 H 904 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
- id="path72580" />
+ id="g7565"
+ transform="matrix(1.4994746,0,0,1.4999989,582.92919,419.89982)">
<path
+ id="path28027-5"
+ transform="translate(294.00001,-553.00001)"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.00098109;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 816.43612,111.73314 c 0,0.5515 0.7823,1.33328 1.3338,1.33333 h 10.0035 c 0.5538,-5e-5 1.3359,-0.77955 1.3338,-1.33333 v -8.00001 c -0.0108,-2.92338 -2.53774,-5.20733 -5.3352,-5.666667 l 3e-5,-63.33338 c -9e-4,-7.597621 -6.34645,-13.676694 -14.00685,-13.666674 l -44.01737,-3e-6 c -7.9872,0.0106 -13.99805,6.01116 -13.99805,14 v 9 l 2.07069,-0.06546 v -9 c 0,-7.01107 4.91866,-11.925191 11.93126,-11.934541 l 44.01542,3e-6 c 6.5948,-0.009 12.0041,5.153493 12.0049,11.666674 l -3e-5,63.331427 c -2.80192,0.45829 -5.33501,2.738541 -5.3359,5.668621 z m 2.0007,2.66667 v 5.33334 c 6e-5,0.55226 0.78364,1.33327 1.3359,1.33333 h 6 c 0.55226,-6e-5 1.33374,-0.78107 1.3338,-1.33333 v -5.33334 h -2.0007 v 4.66667 h -4.6683 v -4.66667 z"
inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 895,197 v 0.75 h -1 v 3.5 h 1 V 202 h 2 v -1 h -2 v -3 h 2 v -1 z"
- id="path72582" />
- <path
- id="path72588"
- d="m 898,197 v 5 h 1 v -2 h 1 v 2 h 1 v -5 h -1 v 2 h -1 v -2 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <path
- id="path72590"
- d="m 909,197 v 0.75 h -1 v 3.5 h 1 V 202 h 2 v -1 h -2 v -3 h 2 v -1 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 913,197 v 0.75 h -1 v 3.5 h 1 V 202 h 2 v -1 h -2 v -3 h 2 v -1 z"
- id="path72592" />
- <path
- id="path72594"
- d="m 917,197 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 921,197 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z"
- id="path72596" />
- <path
- id="path72598"
- d="m 927,197 v 5 h 1 v -2 h 1.25 v -1 H 930 v -1.25 h -1 V 197 h -1 z m 1,1 h 1 v 1 h -1 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <path
- id="path72600"
- d="m 931.75,197 v 1 H 931 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <path
- id="path72602"
- d="m 935,197 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <rect
- y="197"
- x="946"
- height="5"
- width="1"
- id="rect72604"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6" />
- <path
- id="path72606"
- d="m 948,197 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <path
- id="path72608"
- d="m 954.75,197 v 1 H 954 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <path
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 958,197 v 5 h 1 2 v -1 h -2 v -4 z"
- id="path72610"
- inkscape:connector-curvature="0" />
- <path
- id="path72612"
- d="m 963,197 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <path
- id="path72614"
- d="m 967,197 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <path
- id="path72616"
- d="m 973,197 v 0.75 h -1 v 3.5 h 1 V 202 h 2 v -1 -1.25 h -1 V 201 h -1 v -3 h 2 v -1 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <rect
- y="197"
- x="984"
- height="5"
- width="1"
- id="rect72618"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6" />
- <path
- id="path72620"
- d="m 978,197 v 3.25 h 1 V 202 h 1 v -1.75 h 1 V 202 h 1 v -1.75 h 1 V 197 h -1 v 3 h -1 v -2 h -1 v 2 h -1 v -3 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 990,197 v 5 h 1 v -2 h 1 v 2 h 1 v -5 h -1 v 2 h -1 v -2 z"
- id="path72622" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 986,197 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
- id="path72624" />
- <path
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 997,197 v 0.75 h -1 v 3.5 h 1 V 202 h 2 v -1 h -2 v -3 h 2 v -1 z"
- id="path32207-9-7"
- inkscape:connector-curvature="0" />
- <path
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 1001,197 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
- id="path32209-6-7"
- inkscape:connector-curvature="0" />
- <path
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 1005,197 v 5 h 1 v -2 h 1.25 v -1 h 0.75 v -1.25 h -1 V 197 h -1 z m 1,1 h 1 v 1 h -1 z"
- id="path32211-3-7"
- inkscape:connector-curvature="0" />
- <path
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 1009,197 v 2.25 h 1 V 202 h 1 v -2.75 h 1 V 197 h -1 v 2 h -1 v -2 z"
- id="path32213-7-3"
- inkscape:connector-curvature="0" />
- <path
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 1013,197 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 h 0.75 v -1.25 h -1 V 197 h -1 z m 1,1 h 1 v 1 h -1 z"
- id="path32216-8-3"
- inkscape:connector-curvature="0" />
- <rect
- y="197"
- x="1017"
- height="5"
- width="1"
- id="rect32218-8-5"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6" />
- <path
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 1020,197 v 0.75 h -1 v 3.5 h 1 V 202 h 2 v -1 -1.25 h -1 V 201 h -1 v -3 h 2 v -1 z"
- id="path32220-2-9"
- inkscape:connector-curvature="0" />
- <path
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 1023,197 v 5 h 1 v -2 h 1 v 2 h 1 v -5 h -1 v 2 h -1 v -2 z"
- id="path32222-9-9"
- inkscape:connector-curvature="0" />
- <path
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 1027,197 v 1 h 1 v 4 h 1 v -4 h 1 v -1 z"
- id="path32224-1-8"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 1035,197 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
- id="path72678" />
- <path
- inkscape:connector-curvature="0"
- id="path72680"
- d="m 1045,197 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6" />
- <rect
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- id="rect72682"
- width="1"
- height="5"
- x="1033"
- y="197" />
- <rect
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- id="rect72684"
- width="1"
- height="1"
- x="1049"
- y="201" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate;opacity:0.6"
- d="m 1040,197 v 5 h 1 v -2 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
- id="path72686" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
- d="m 1028.75,209 v 1 H 1028 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
- id="path32244-2" />
- <path
- inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
- d="m 1032,209 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v -1 z m 1,0 h 1 v 3 h 1 v -5 h -1 v 1 h -1 z"
- id="path32246-0" />
+ sodipodi:nodetypes="cccccccccsccsccccccccccccccccc" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.99947333;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 2506.2815,-377.92073 c -5.52,0.36326 -8.7584,3.47967 -8.7584,8.43246 0,4.43345 3.2458,8.13054 7.4769,8.85937 V -347 c 0,9.91268 -7.251,17.99291 -17,18 l -15.3901,0.0264 v 2.96484 H 2488 c 11.4103,-0.008 20.0341,-9.52115 20.0341,-20.99121 v -13.6289 c 4.2339,-0.72648 7.4827,-4.42393 7.4827,-8.85937 0,-4.95279 -3.4428,-8.31926 -9.2353,-8.43249 z m 0.406,2.98323 c 3.3303,0 5.8304,2.11776 5.8304,5.44923 0,3.33147 -2.6676,6 -5.9979,6 -3.3304,0 -5.9979,-2.66853 -5.9979,-6 0,-3.33147 2.835,-5.44923 6.1654,-5.44923 z M 2515,-303 c -4.4432,-10e-6 -8.6177,3.4839 -9,7 h -34 l 1,4 h 33 c 0.7202,4.24251 4.561,7.00001 9,7 4.9511,10e-6 9,-4.04722 9,-9 0,-4.95279 -4.0489,-9.00001 -9,-9 z m 0,3 c 3.3304,0 6,2.66853 6,6 0,3.33146 -2.6696,6 -6,6 -3.3303,0 -6,-2.66854 -6,-6 0,-3.33147 2.6697,-6 6,-6 z m -42,37 v 4 h 15 c 9.749,0.007 17,8.08732 17,18 v 13 c -4.2311,0.72882 -7.0144,4.57086 -7.0144,9.00433 0,4.9528 4.0457,9.00001 8.9969,8.99999 4.9511,2e-5 8.9968,-4.04719 8.9968,-8.99999 0,-4.43545 -2.7454,-8.27785 -6.9793,-9.00433 v -14 c 0,-11.47007 -9.5897,-20.99166 -21,-21 z m 33.9825,38.00433 c 3.3303,0 5.9979,2.66852 5.9979,6 0,3.33148 -2.6676,6 -5.9979,6 -3.3304,0 -5.9979,-2.66852 -5.9979,-6 0,-3.33148 2.6675,-6 5.9979,-6 z"
+ id="circle7536"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cscsccccscscscsssccccccscscssscscscscscsccsssss" />
+ <g
+ transform="matrix(12.319682,0,0,12.172353,-5203.9739,-996.3403)"
+ id="g7322-0"
+ style="display:inline;stroke-width:0.12309717;enable-background:new">
<path
inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
- d="m 1038,209 v 5 h 1 1 v -0.5 h 1 V 212 h -0.75 v -1 h 0.75 v -1.25 h -1 V 209 h -1 z m 1,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z"
- id="path32248-9" />
+ style="display:inline;opacity:0.2;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.24619435;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 613.67414,61.612633 h 8.65173 c 0.57439,0 1.03681,0.46242 1.03681,1.036815 v 2.762566 c 0,0.574395 -0.46242,1.036815 -1.03681,1.036815 h -8.65173 c -0.57439,0 -1.03681,-0.46242 -1.03681,-1.036815 v -2.762566 c 0,-0.574395 0.46242,-1.036815 1.03681,-1.036815 z"
+ id="rect7418-6" />
<path
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.41910744;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="M 145.24609,-711 C 139.56928,-711.01185 135,-706.4825 135,-700.87109 v 78 c 0,-5.61141 4.56928,-10.14076 10.24609,-10.12891 l 85.17749,0.17786 c 5.67681,0.0118 10.24609,4.5175 10.24609,10.12891 v -78 c 0,-5.61141 -4.56928,-10.11706 -10.24609,-10.12891 l -42.58875,-0.0889 z"
+ transform="matrix(0.10118267,0,0,0.10236222,598.97766,126.33073)"
+ id="rect7413-9"
inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
- d="m 1042,209 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 h 0.75 v -1.25 h -1 V 209 h -1 z m 1,1 h 1 v 1 h -1 z"
- id="path32250-7" />
+ sodipodi:nodetypes="sscsscsscs" />
<path
inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
- d="m 1047,209 v 1 h 2 v -1 z m 2,1 v 3 h 1 v -3 z m 0,3 h -2 v 1 h 2 z m -2,0 v -3 h -1 v 3 z"
- id="path32252-3" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.00080752;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 717.48242,42.996094 c -5.24135,0 -9.49414,4.190752 -9.49414,9.355468 v 65.017578 22.26953 c 0,5.16472 4.25279,9.35547 9.49414,9.35547 h 70.02539 c 5.24136,0 9.49414,-4.19075 9.49414,-9.35547 V 117.36914 52.351562 c 0,-5.164716 -4.25278,-9.355468 -9.49414,-9.355468 z m 0,1.984375 h 70.02539 c 4.15996,0 7.48047,3.271903 7.48047,7.371093 v 59.269528 c -1.73801,-2.19271 -4.43984,-3.60742 -7.48047,-3.60742 h -70.02539 c -3.04062,0 -5.74244,1.41471 -7.48047,3.60742 V 52.351562 c 0,-4.09919 3.32052,-7.371093 7.48047,-7.371093 z m 0,65.017581 h 70.02539 c 4.15996,0 6.83699,3.09748 6.83699,7.19666 l 0,21.86209 c -10e-6,4.09919 -3.14714,7.28737 -7.3071,7.28737 l -69.08523,0 c -4.15995,0 -7.3071,-3.18818 -7.30709,-7.28737 l 0,-21.86209 c 0,-4.09918 2.67709,-7.19666 6.83704,-7.19666 z"
+ transform="matrix(0.12219364,0,0,0.1240074,526.00203,48.095825)"
+ id="rect7312-4"
+ sodipodi:nodetypes="sscsssscsssssscsscssssssssscs" />
+ <g
+ id="g7411-1"
+ transform="matrix(-1,0,0,1,1235.8994,0)"
+ style="stroke-width:0.12309717">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.12309717;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 613.88871,62.499042 c -0.23599,0 -0.42773,0.193143 -0.42773,0.429687 v 0.0098 c 0,0.236544 0.19174,0.429687 0.42773,0.429687 0.23599,0 0.42774,-0.193143 0.42774,-0.429687 v -0.0098 c 0,-0.236544 -0.19175,-0.429687 -0.42774,-0.429687 z"
+ id="rect7316-4"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssss" />
+ <g
+ transform="translate(6.2733256)"
+ id="g7368-5"
+ style="display:inline;stroke-width:0.12309717;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.24619435;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 613.40672,62.503836 c -0.0633,0.0071 -0.11074,0.06131 -0.10937,0.125 v 2.851562 c 0,0.165367 0.24805,0.165367 0.24805,0 v -2.851562 c 0.002,-0.07532 -0.0639,-0.13455 -0.13868,-0.125 z m 0.64937,3e-6 c -0.0633,0.0071 -0.11074,0.06131 -0.10937,0.125 v 2.851562 c -0.005,0.169458 0.25158,0.169458 0.24609,0 v -2.851562 c 0.002,-0.07444 -0.0627,-0.133249 -0.13672,-0.125 z m 0.64936,3e-6 c -0.0633,0.0071 -0.11074,0.06131 -0.10937,0.125 v 2.851562 c -0.005,0.169458 0.25158,0.169458 0.24609,0 v -2.851562 c 0.002,-0.07444 -0.0627,-0.133249 -0.13672,-0.125 z m 0.64938,3e-6 c -0.0633,0.0071 -0.11075,0.06131 -0.10938,0.125 v 2.851562 c -0.005,0.169248 0.25136,0.169248 0.2461,0 v -2.851562 c 0.002,-0.07444 -0.0627,-0.133249 -0.13672,-0.125 z m 0.64937,-9e-6 c -0.0633,0.0071 -0.11075,0.06131 -0.10938,0.125 v 2.851562 c -0.005,0.169248 0.25136,0.169248 0.2461,0 v -2.851562 c 0.002,-0.07444 -0.0627,-0.133249 -0.13672,-0.125 z"
+ id="path7359-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccsscccccccccccccccccccccccccc" />
+ </g>
+ </g>
+ </g>
+ <g
+ transform="matrix(1.4999994,0,0,1.4999994,-370.74654,70.499826)"
+ style="display:inline;opacity:1;enable-background:new"
+ id="g13919">
<path
+ id="path13909"
+ d="m 831.51367,-289.48633 -41.0039,41 0.0254,-0.0117 c 2.2475,-2.24076 5.45583,-3.83326 8.62951,-3.83529 h 26.66668 c 1.09262,-1.2e-4 1.9998,-0.91463 2,-2 V -281 c 0.003,-3.17329 1.43156,-6.21618 3.67255,-8.46289 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
- d="m 1051,209 v 1 h 2 v 1 h 1 v -1 -1 z m 2,2 h -1 v 1 h 1 z m -1,1 h -1 v 1 1 h 3 v -1 h -2 z"
- id="path32254-7" />
+ sodipodi:nodetypes="ccccccccc" />
<path
+ sodipodi:nodetypes="cssssscccccccc"
inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
- d="m 997.75,209 v 1 H 997 v 4 h 1 v -2 h 1 v 2 h 1 v -4 h -0.75 v -1 z m 0.25,1 h 1 v 1 h -1 z"
- id="path32256-2" />
+ id="path13911"
+ transform="translate(752,-312)"
+ d="M 130.49803,21.058926 88.026621,21 c -5.522842,-0.0077 -9.528596,4.477157 -9.528595,10.000004 l 0,27.000002 c 0,2.209139 -2.45753,4.333345 -4.666669,4.333345 h -27 c -5.522847,0 -10.333348,4.995641 -10.333348,10.518488 l 0.02841,74.142351 c -0.007,1.09637 0.910592,2.01376 2.007812,2.00586 h 91.957949 c 1.09615,0.007 2.00587,-0.9072 2.00587,-2 V 23.057949 c -0.003,-1.092216 -0.90724,-1.999083 -2,-1.999023 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<path
inkscape:connector-curvature="0"
- id="path32258-6"
- d="m 1001,209 v 5 h 1 v -3 h 1 v -1 h -1 v -1 z m 2,2 v 1 h 1 v 2 h 1 v -5 h -1 v 2 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:0;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 79.513672,22.513672 -41.003906,41 0.02539,-0.01172 A 12,12 0 0 1 47,60 h 27 c 1.09262,-1.2e-4 1.993941,-0.91463 1.994141,-2 L 76,31 a 12,12 0 0 1 3.503906,-8.462891 z"
+ transform="translate(752,-312)"
+ id="path13913" />
<path
inkscape:connector-curvature="0"
- id="path32260-0"
- d="m 1006,209 v 1 3 1 h 2 v -0.75 h 1 v -3.5 h -1 V 209 Z m 1,1 h 1 v 3 h -1 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:0;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 831.51367,-289.48633 -41.0039,41 0.0254,-0.0117 A 12,12 0 0 1 799,-252 h 27 c 1.09262,-1.2e-4 1.99394,-0.91463 1.99414,-2 L 828,-281 a 12,12 0 0 1 3.50391,-8.46289 z"
+ id="path13915" />
<path
inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
- d="m 1010,209 v 5 h 1 v -2 h 1 v 2 h 1 v -2 h -0.75 v -1 h 0.75 v -1.25 h -1 V 209 h -1 z m 1,1 h 1 v 1 h -1 z"
- id="path32262-1" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:url(#linearGradient13927);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 831.51367,-289.48633 -41.0039,41 0.0254,-0.0117 A 12,12 0 0 1 799,-252 h 27 c 1.09262,-1.2e-4 1.99394,-0.91463 1.99414,-2 L 828,-281 a 12,12 0 0 1 3.50391,-8.46289 z"
+ id="path13917" />
+ </g>
+ <g
+ id="g7323"
+ style="display:inline;opacity:0.6;enable-background:new"
+ transform="matrix(1.4894891,0,0,1.4922753,-112.65937,307.51188)">
<path
+ id="path7473"
+ transform="translate(756,-312)"
+ d="m 80,-136.5 -40.5,40.5 0.0078,1.345703 c 1.453885,-2.021331 3.879556,-3.1306 6.552027,-3.1306 h 30.211702 c 1.09262,-1.2e-4 2.013913,-0.924983 2.014113,-2.010353 v -30.15529 c 0,-3.35059 1.0361,-5.08351 3.054202,-6.53774 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
- d="m 1014,209 v 1 h 2 v 1 h 1 v -1 -1 z m 2,2 h -1 v 1 h 1 z m -1,1 h -1 v 1 1 h 3 v -1 h -2 z"
- id="path32264-6" />
+ sodipodi:nodetypes="cccsccccc" />
<path
+ sodipodi:nodetypes="ccccccccccc"
inkscape:connector-curvature="0"
- id="path32266-5"
- d="m 1018,209 v 5 h 1 2 v -1 h -2 v -1 h 1 v -1 h -1 v -1 h 2 v -1 h -2 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ d="m -449.99998,886.9875 c -3e-5,0.5523 0.44769,1 0.99998,1.0015 L -325,888 c 0.55581,0 1.00353,-0.4477 1,-1 v -92.0036 c 0.004,-0.5558 -0.44419,-1.0036 -1,-1 L -403,794 c -2.38695,0 -4.67613,0.94821 -6.36396,2.63604 l -38,38 C -449.05179,836.32387 -450,838.61305 -450,841 Z"
+ style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2.6667285;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ transform="matrix(0,1,1,0,0,0)"
+ id="path7495" />
+ </g>
+ <g
+ style="display:inline;opacity:1;stroke-width:4;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="matrix(1.5,0,0,1.5,-192.5,-37.5)"
+ id="g13907">
<path
+ sodipodi:nodetypes="sscsscssccssss"
inkscape:connector-curvature="0"
- id="path32268-7"
- d="m 1024,209 v 4 h -1 v -1 h -1 v 1 h 0.75 v 1 h 1.5 v -1 h 0.75 v -4 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
- <rect
- y="207"
- x="1052"
- height="1"
- width="1"
- id="rect32270-5"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ id="path13903"
+ transform="translate(803,-241)"
+ d="m 195.5,38 c -1.94642,0 -3.5,1.60898 -3.5,3.5 V 62 c 0.95388,-0.792604 2.00859,-1.333333 3.33333,-1.333333 h 121.33334 c 1.32476,0 2.37945,0.540729 3.33333,1.333333 v -9.333333 c 0,-1.9217 -1.41163,-4 -3.33333,-4 l -76.66667,0 c -0.3983,1e-5 -1.38322,-0.157923 -1.66472,-0.439453 C 238.05368,47.945614 238,47.064867 238,46.666667 V 41.333333 C 238,39.411633 236.58837,38 234.66667,38 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
+ sodipodi:nodetypes="sssssssss"
inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
- d="m 969.96875,208 v 0.75 h -1 V 209 h -0.25 v 1 h -0.75 v 3 h 0.75 v 1 h 0.25 v 0.25 h 1 V 215 h 3 v -0.75 h 1 V 214 h 0.25 v -1 h 0.75 v -3 h -0.75 v -1 h -0.25 v -0.25 h -1 V 208 Z m 0,1 h 3 v 1 h 1 v 3 h -1 v 1 h -3 v -1 h -1 v -3 h 1 z"
- id="path32272-1"
- sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccc" />
+ id="path13905"
+ d="m 998.33333,-177.66667 c -1.9217,0 -3.33333,1.41164 -3.33333,3.33334 V -110.5 c 0,1.9217 1.5783,3.5 3.5,3.5 h 121 c 1.9217,0 3.5,-1.5783 3.5,-3.5 v -63.83333 c 0,-1.9217 -1.4116,-3.33334 -3.3333,-3.33334 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:105.70774078;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ style="display:inline;opacity:0.6;stroke-width:4;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="matrix(1.5,0,0,1.5009002,63.500003,7.666537)"
+ id="g7351">
<path
+ sodipodi:nodetypes="sscsscssccssss"
inkscape:connector-curvature="0"
- id="path32274-2"
- d="m 970.96875,210 v 0.75 h -1 v 1.5 h 1 V 213 h 1.25 v -1 h -1.25 v -1 h 1.25 v -1 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
- sodipodi:nodetypes="ccccccccccccc" />
- <path
- id="path72688"
- d="m 981.71875,209 v 1 h -0.75 v 3 h 0.75 v 1 h 1.5 v -1 h 0.75 v -3 h -0.75 v -1 z m 0.25,1 h 1 v 3 h -1 z m 0.25,1 v 1 h 0.5 v -1 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
- inkscape:connector-curvature="0" />
- <path
- id="path72690"
- d="m 985.96875,209 v 1 h -1 v 1 h 1 v 3 h 1 v -5 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
- inkscape:connector-curvature="0" />
+ id="path7347"
+ d="m 998.33333,-232.97121 c -1.94642,0 -3.33333,1.44031 -3.33333,3.33133 l 0,20.65427 c 0.95388,-0.7926 2.00859,-1.33253 3.33333,-1.33253 h 121.33337 c 1.3248,0 2.3794,0.53993 3.3333,1.33253 V -218.5 c 0,-1.9217 -1.4116,-3.81094 -3.3333,-3.81094 H 1043 c -0.3983,10e-6 -1.4457,-0.0538 -1.7272,-0.33535 -0.2816,-0.2816 -0.2728,-1.26525 -0.2728,-1.66345 V -229.5 c 0,-1.9217 -1.4116,-3.47121 -3.3333,-3.47121 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:105.70774078;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 365.33333,63.346928 c -1.9217,0 -3.33333,1.409634 -3.33333,3.331334 V 130.5 c 0,1.9217 1.5783,3.5 3.5,3.5 h 121 c 1.9217,0 3.5,-1.5783 3.5,-3.5 l 0,-63.821738 c 0,-1.9217 -1.41164,-3.331334 -3.33334,-3.331334 z m 58.6237,11.660884 c 0.80833,-0.01124 1.58681,0.305088 2.1582,0.876954 l 13.01563,13.015625 c 2.84522,2.82159 -1.41214,7.076991 -4.23242,4.230468 L 427.01758,85.25 l -0.0117,25.76562 v 0.002 c 0.001,0.96287 1.07551,2.00781 2.00781,2.00781 h 13 c 4.08709,-0.10004 4.08709,6.08246 0,5.98242 h -13 c -4.3889,0 -7.99023,-3.56607 -7.99023,-7.99219 l 0.01,-25.804682 -7.90039,7.917968 c -2.81555,2.949086 -7.1776,-1.400901 -4.23633,-4.224609 l 12.98438,-13.017578 c 0.55099,-0.552467 1.29599,-0.867849 2.07617,-0.878907 z"
+ transform="translate(633,-271)"
+ id="path7349"
inkscape:connector-curvature="0"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
- d="m 976.96875,209 v 1 h 2 v 1 h -1 v 1 h 1 v -0.75 h 1 v -1.5 h -1 V 209 Z m 1,3 h -1 v 1 1 h 3 v -1 h -2 z"
- id="path72694" />
- <path
- id="path72696"
- d="m 992.96875,210 v 1 h 1 v -1 z m -0.21875,3 v 1 H 992 v 1 h 1 v -1 h 1 v -1 z"
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
- inkscape:connector-curvature="0" />
- <path
- style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
- d="m 988.75,209 v 1 h -0.5 v 1 h 0.5 v 1 H 988 v 1 h 0.75 v 1 h 1.5 v -1 H 991 v -1 h -0.75 v -1 h 0.5 v -1 h -0.5 v -1 z m 0.25,1 h 1 v 1 h -1 z m 0,2 h 1 v 1 h -1 z"
- id="path19551-18-1"
- inkscape:connector-curvature="0" />
+ sodipodi:nodetypes="ssssssssscccccccsccsccccccc" />
</g>
</g>
</svg>
diff --git a/release/datafiles/prvicons_update.py b/release/datafiles/prvicons_update.py
index bc170b98545..85e92e9e564 100755
--- a/release/datafiles/prvicons_update.py
+++ b/release/datafiles/prvicons_update.py
@@ -17,6 +17,8 @@ if sys.platform == 'darwin':
cmd = (
inkscape_path,
os.path.join(BASEDIR, "prvicons.svg"),
+ "--export-width=1792",
+ "--export-height=256",
"--without-gui",
"--export-png=" + os.path.join(BASEDIR, "prvicons.png"),
)
diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c
index 4ad99993ada..7785c9d2962 100644
--- a/release/datafiles/userdef/userdef_default.c
+++ b/release/datafiles/userdef/userdef_default.c
@@ -21,6 +21,7 @@
#include "DNA_userdef_types.h"
#include "DNA_curve_types.h"
+#include "DNA_space_types.h"
#include "BLI_math_rotation.h"
@@ -63,8 +64,6 @@ const UserDef U_default = {
.gpu_flag = 0,
.app_flag = 0,
.language = 0,
- .userpref = USER_SECTION_INTERFACE,
- .userpref_flag = 0,
.viewzoom = USER_ZOOM_DOLLY,
.mixbufsize = 2048,
.audiodevice = 0,
@@ -182,6 +181,13 @@ const UserDef U_default = {
.pie_menu_confirm = 0,
.pie_menu_radius = 100,
.pie_menu_threshold = 12,
+ .opensubdiv_compute_type = 0,
+ .gpencil_multisamples = 4,
+ .factor_display_type = USER_FACTOR_AS_FACTOR,
+ .render_display_type = USER_RENDER_DISPLAY_WINDOW,
+ .filebrowser_display_type = USER_TEMP_SPACE_DISPLAY_WINDOW,
+ .viewport_aa = 8,
+
.walk_navigation =
{
.mouse_speed = 1,
@@ -192,10 +198,24 @@ const UserDef U_default = {
.teleport_time = 0.2,
.flag = 0,
},
- .opensubdiv_compute_type = 0,
- .gpencil_multisamples = 4,
- .factor_display_type = USER_FACTOR_AS_FACTOR,
- .viewport_aa = 8,
+
+ .space_data =
+ {
+ .section_active = USER_SECTION_INTERFACE,
+ },
+
+ .file_space_data =
+ {
+ .display_type = FILE_VERTICALDISPLAY,
+ .thumbnail_size = 128,
+ .sort_type = FILE_SORT_ALPHA,
+ .details_flags = FILE_DETAILS_SIZE | FILE_DETAILS_DATETIME,
+ .flag = FILE_HIDE_DOT,
+
+ .temp_win_sizex = 1020,
+ .temp_win_sizey = 600,
+ },
+
.runtime =
{
.is_dirty = 0,
diff --git a/release/datafiles/userdef/userdef_default_theme.c b/release/datafiles/userdef/userdef_default_theme.c
index 9f037fa4793..80bed03debf 100644
--- a/release/datafiles/userdef/userdef_default_theme.c
+++ b/release/datafiles/userdef/userdef_default_theme.c
@@ -254,6 +254,7 @@ const bTheme U_theme_default = {
.icon_object_data = RGBA(0x00d4a3ff),
.icon_modifier = RGBA(0x84b8ffff),
.icon_shading = RGBA(0xea7581ff),
+ .icon_folder = RGBA(0xe3c16eff),
},
.space_properties = {
.back = RGBA(0x42424200),
@@ -316,14 +317,14 @@ const bTheme U_theme_default = {
.vertex_select = RGBA(0xff7a00ff),
.vertex_bevel = RGBA(0x00a5ffff),
.edge = RGBA(0x000000ff),
- .edge_select = RGBA(0xff7a00ff),
+ .edge_select = RGBA(0xffa000ff),
.edge_seam = RGBA(0xdb2512ff),
.edge_sharp = RGBA(0x00ffffff),
.edge_facesel = RGBA(0x4b4b4bff),
.edge_crease = RGBA(0xcc0099ff),
.edge_bevel = RGBA(0x00a5ffff),
.face = RGBA(0xffffff12),
- .face_select = RGBA(0xffc8526c),
+ .face_select = RGBA(0xffa5526c),
.face_dot = RGBA(0xff8a00ff),
.extra_edge_len = RGBA(0x150806ff),
.extra_edge_angle = RGBA(0x4d4d00ff),
@@ -370,7 +371,7 @@ const bTheme U_theme_default = {
.paint_curve_handle = RGBA(0x7fff7f7f),
},
.space_file = {
- .back = RGBA(0x35353500),
+ .back = RGBA(0x33333300),
.title = RGBA(0xffffffff),
.text = RGBA(0xe6e6e6ff),
.text_hi = RGBA(0xffffffff),
@@ -381,13 +382,14 @@ const bTheme U_theme_default = {
.tab_inactive = RGBA(0x2b2b2bff),
.tab_back = RGBA(0x232323ff),
.tab_outline = RGBA(0x232323ff),
- .button = RGBA(0x424242ff),
+ .button = RGBA(0x4b4b4bff),
.button_title = RGBA(0xffffffff),
.button_text = RGBA(0xe5e5e5ff),
.button_text_hi = RGBA(0xffffffff),
+ .execution_buts = RGBA(0x444444ff),
.panelcolors = {
- .header = RGBA(0x424242cc),
- .back = RGBA(0x333333b3),
+ .header = RGBA(0x4b4b4bff),
+ .back = RGBA(0x404040ff),
.sub_back = RGBA(0x0000003e),
},
.hilite = RGBA(0x4f76b3ff),
@@ -912,6 +914,8 @@ const bTheme U_theme_default = {
.lock_marker = RGBA(0x7f7f7fff),
.path_before = RGBA(0xff0000ff),
.path_after = RGBA(0x0000ffff),
+ .path_keyframe_before = RGBA(0xffc4c4ff),
+ .path_keyframe_after = RGBA(0xc4c4ffff),
.gp_vertex_size = 1,
.metadatatext = RGBA(0xffffffff),
},
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject 4a66c4e0b80f5483c8434554c615a56fef71d62
+Subproject eb9bab0e7153fda8de113af9e3c54eca74c986e
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject 80e2be8ff8e23dad3487d4ceef82ce7067cee41
+Subproject d9ed9d4d064c74c86e2767cd4be32d602a0ee31
diff --git a/release/scripts/freestyle/styles/apriori_density.py b/release/scripts/freestyle/styles/apriori_density.py
index 1de2c4c0334..ad5e610e422 100644
--- a/release/scripts/freestyle/styles/apriori_density.py
+++ b/release/scripts/freestyle/styles/apriori_density.py
@@ -41,8 +41,8 @@ Operators.select(AndUP1D(QuantitativeInvisibilityUP1D(0), pyHighViewMapDensityUP
bpred = TrueBP1D()
upred = AndUP1D(QuantitativeInvisibilityUP1D(0), pyHighViewMapDensityUP1D(0.0007,5))
Operators.bidirectional_chain(ChainPredicateIterator(upred, bpred), NotUP1D(QuantitativeInvisibilityUP1D(0)))
-shaders_list = [
+shaders_list = [
ConstantThicknessShader(2),
ConstantColorShader(0.0, 0.0, 0.0, 1.0)
- ]
+]
Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/modules/bl_app_override/__init__.py b/release/scripts/modules/bl_app_override/__init__.py
index 2104b10bf85..112fe040f0c 100644
--- a/release/scripts/modules/bl_app_override/__init__.py
+++ b/release/scripts/modules/bl_app_override/__init__.py
@@ -90,7 +90,7 @@ def ui_draw_filter_register(
ret = real_func(*args, **kw)
else:
if ui_test is None:
- UILayout.__getattribute__(self, "label")("")
+ UILayout.__getattribute__(self, "label")(text="")
else:
assert(ui_test is True)
# may need to be set
@@ -111,7 +111,7 @@ def ui_draw_filter_register(
ret = real_func(*args, **kw)
else:
if ui_test is None:
- UILayout.__getattribute__(self, "label")("")
+ UILayout.__getattribute__(self, "label")(text="")
else:
assert(ui_test is True)
ret = None
@@ -131,7 +131,7 @@ def ui_draw_filter_register(
ret = real_func(*args, **kw)
else:
if ui_test is None:
- UILayout.__getattribute__(self, "label")("")
+ UILayout.__getattribute__(self, "label")(text="")
else:
assert(ui_test is True)
ret = None
@@ -151,7 +151,7 @@ def ui_draw_filter_register(
ret = real_func(*args, **kw)
else:
if ui_test is None:
- real_func("")
+ real_func(text="")
else:
assert(ui_test is True)
ret = None
diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
index fdd36589d4d..4aaa30a0508 100644
--- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
+++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
@@ -838,7 +838,12 @@ def dump_messages(do_messages, do_checks, settings):
# For now, enable all official addons, before extracting msgids.
addons = utils.enable_addons(support={"OFFICIAL"})
# Note this is not needed if we have been started with factory settings, but just in case...
- utils.enable_addons(support={"COMMUNITY", "TESTING"}, disable=True)
+ # XXX This is not working well, spent a whole day trying to understand *why* we still have references of
+ # those removed calsses in things like `bpy.types.OperatorProperties.__subclasses__()`
+ # (could not even reproduce it from regular py console in Blender with UI...).
+ # For some reasons, cleanup does not happen properly, *and* we have no way to tell which class is valid
+ # and which has been unregistered. So for now, just go for the dirty, easy way: do not disable add-ons. :(
+ # ~ utils.enable_addons(support={"COMMUNITY", "TESTING"}, disable=True)
reports = _gen_reports(_gen_check_ctxt(settings) if do_checks else None)
diff --git a/release/scripts/modules/bl_i18n_utils/utils_rtl.py b/release/scripts/modules/bl_i18n_utils/utils_rtl.py
index 11d1da068b4..1a71bb735bc 100755
--- a/release/scripts/modules/bl_i18n_utils/utils_rtl.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_rtl.py
@@ -37,29 +37,29 @@ import ctypes
import re
-#define FRIBIDI_MASK_NEUTRAL 0x00000040L /* Is neutral */
+#define FRIBIDI_MASK_NEUTRAL 0x00000040L /* Is neutral */
FRIBIDI_PAR_ON = 0x00000040
-#define FRIBIDI_FLAG_SHAPE_MIRRORING 0x00000001
-#define FRIBIDI_FLAG_REORDER_NSM 0x00000002
+#define FRIBIDI_FLAG_SHAPE_MIRRORING 0x00000001
+#define FRIBIDI_FLAG_REORDER_NSM 0x00000002
-#define FRIBIDI_FLAG_SHAPE_ARAB_PRES 0x00000100
-#define FRIBIDI_FLAG_SHAPE_ARAB_LIGA 0x00000200
-#define FRIBIDI_FLAG_SHAPE_ARAB_CONSOLE 0x00000400
+#define FRIBIDI_FLAG_SHAPE_ARAB_PRES 0x00000100
+#define FRIBIDI_FLAG_SHAPE_ARAB_LIGA 0x00000200
+#define FRIBIDI_FLAG_SHAPE_ARAB_CONSOLE 0x00000400
-#define FRIBIDI_FLAG_REMOVE_BIDI 0x00010000
-#define FRIBIDI_FLAG_REMOVE_JOINING 0x00020000
-#define FRIBIDI_FLAG_REMOVE_SPECIALS 0x00040000
+#define FRIBIDI_FLAG_REMOVE_BIDI 0x00010000
+#define FRIBIDI_FLAG_REMOVE_JOINING 0x00020000
+#define FRIBIDI_FLAG_REMOVE_SPECIALS 0x00040000
-#define FRIBIDI_FLAGS_DEFAULT ( \
-# FRIBIDI_FLAG_SHAPE_MIRRORING | \
-# FRIBIDI_FLAG_REORDER_NSM | \
-# FRIBIDI_FLAG_REMOVE_SPECIALS )
+#define FRIBIDI_FLAGS_DEFAULT ( \
+# FRIBIDI_FLAG_SHAPE_MIRRORING | \
+# FRIBIDI_FLAG_REORDER_NSM | \
+# FRIBIDI_FLAG_REMOVE_SPECIALS )
-#define FRIBIDI_FLAGS_ARABIC ( \
-# FRIBIDI_FLAG_SHAPE_ARAB_PRES | \
-# FRIBIDI_FLAG_SHAPE_ARAB_LIGA )
+#define FRIBIDI_FLAGS_ARABIC ( \
+# FRIBIDI_FLAG_SHAPE_ARAB_PRES | \
+# FRIBIDI_FLAG_SHAPE_ARAB_LIGA )
FRIBIDI_FLAG_SHAPE_MIRRORING = 0x00000001
FRIBIDI_FLAG_REORDER_NSM = 0x00000002
diff --git a/release/scripts/modules/bl_keymap_utils/io.py b/release/scripts/modules/bl_keymap_utils/io.py
index 2ff30cf4d52..a93e86bc0a1 100644
--- a/release/scripts/modules/bl_keymap_utils/io.py
+++ b/release/scripts/modules/bl_keymap_utils/io.py
@@ -80,7 +80,7 @@ def _kmi_properties_to_lines_recursive(level, properties, lines):
from bpy.types import OperatorProperties
def string_value(value):
- if isinstance(value, (str, bool, int)):
+ if isinstance(value, (str, bool, int, set)):
return repr(value)
elif isinstance(value, float):
return repr_f32(value)
diff --git a/release/scripts/modules/bpy_extras/image_utils.py b/release/scripts/modules/bpy_extras/image_utils.py
index 03864d652e4..f4d34de5037 100644
--- a/release/scripts/modules/bpy_extras/image_utils.py
+++ b/release/scripts/modules/bpy_extras/image_utils.py
@@ -24,17 +24,18 @@ __all__ = (
# limited replacement for BPyImage.comprehensiveImageLoad
-def load_image(imagepath,
- dirname="",
- place_holder=False,
- recursive=False,
- ncase_cmp=True,
- convert_callback=None,
- verbose=False,
- relpath=None,
- check_existing=False,
- force_reload=False,
- ):
+def load_image(
+ imagepath,
+ dirname="",
+ place_holder=False,
+ recursive=False,
+ ncase_cmp=True,
+ convert_callback=None,
+ verbose=False,
+ relpath=None,
+ check_existing=False,
+ force_reload=False,
+):
"""
Return an image from the file path with options to search multiple paths
and return a placeholder if its not found.
@@ -161,15 +162,17 @@ def load_image(imagepath,
variants = [imagepath]
if dirname:
- variants += [os.path.join(dirname, imagepath),
- os.path.join(dirname, bpy.path.basename(imagepath)),
- ]
+ variants += [
+ os.path.join(dirname, imagepath),
+ os.path.join(dirname, bpy.path.basename(imagepath)),
+ ]
for filepath_test in variants:
if ncase_cmp:
- ncase_variants = (filepath_test,
- bpy.path.resolve_ncase(filepath_test),
- )
+ ncase_variants = (
+ filepath_test,
+ bpy.path.resolve_ncase(filepath_test),
+ )
else:
ncase_variants = (filepath_test, )
diff --git a/release/scripts/modules/bpy_extras/io_utils.py b/release/scripts/modules/bpy_extras/io_utils.py
index 96b9596a57d..380b63066ef 100644
--- a/release/scripts/modules/bpy_extras/io_utils.py
+++ b/release/scripts/modules/bpy_extras/io_utils.py
@@ -44,10 +44,11 @@ from bpy.props import (
def _check_axis_conversion(op):
if hasattr(op, "axis_forward") and hasattr(op, "axis_up"):
- return axis_conversion_ensure(op,
- "axis_forward",
- "axis_up",
- )
+ return axis_conversion_ensure(
+ op,
+ "axis_forward",
+ "axis_up",
+ )
return False
@@ -93,10 +94,12 @@ class ExportHelper:
if check_extension is not None:
filepath = self.filepath
if os.path.basename(filepath):
- filepath = bpy.path.ensure_ext(filepath,
- self.filename_ext
- if check_extension
- else "")
+ filepath = bpy.path.ensure_ext(
+ filepath,
+ self.filename_ext
+ if check_extension
+ else "",
+ )
if filepath != self.filepath:
self.filepath = filepath
@@ -134,8 +137,10 @@ def orientation_helper(axis_forward='Y', axis_up='Z'):
def _update_axis_forward(self, _context):
if self.axis_forward[-1] == self.axis_up[-1]:
- self.axis_up = (self.axis_up[0:-1] +
- 'XYZ'[('XYZ'.index(self.axis_up[-1]) + 1) % 3])
+ self.axis_up = (
+ self.axis_up[0:-1] +
+ 'XYZ'[('XYZ'.index(self.axis_up[-1]) + 1) % 3]
+ )
cls.__annotations__['axis_forward'] = EnumProperty(
name="Forward",
@@ -153,8 +158,10 @@ def orientation_helper(axis_forward='Y', axis_up='Z'):
def _update_axis_up(self, _context):
if self.axis_up[-1] == self.axis_forward[-1]:
- self.axis_forward = (self.axis_forward[0:-1] +
- 'XYZ'[('XYZ'.index(self.axis_forward[-1]) + 1) % 3])
+ self.axis_forward = (
+ self.axis_forward[0:-1] +
+ 'XYZ'[('XYZ'.index(self.axis_forward[-1]) + 1) % 3]
+ )
cls.__annotations__['axis_up'] = EnumProperty(
name="Up",
@@ -405,14 +412,15 @@ path_reference_mode = EnumProperty(
)
-def path_reference(filepath,
- base_src,
- base_dst,
- mode='AUTO',
- copy_subdir="",
- copy_set=None,
- library=None,
- ):
+def path_reference(
+ filepath,
+ base_src,
+ base_dst,
+ mode='AUTO',
+ copy_subdir="",
+ copy_set=None,
+ library=None,
+):
"""
Return a filepath relative to a destination directory, for use with
exporters.
@@ -540,22 +548,29 @@ def unique_name(key, name, name_dict, name_max=-1, clean_func=None, sep="."):
if name_new is None:
count = 1
name_dict_values = name_dict.values()
- name_new = name_new_orig = (name if clean_func is None
- else clean_func(name))
+ name_new = name_new_orig = (
+ name if clean_func is None
+ else clean_func(name)
+ )
if name_max == -1:
while name_new in name_dict_values:
- name_new = "%s%s%03d" % (name_new_orig, sep, count)
+ name_new = "%s%s%03d" % (
+ name_new_orig,
+ sep,
+ count,
+ )
count += 1
else:
name_new = name_new[:name_max]
while name_new in name_dict_values:
count_str = "%03d" % count
- name_new = "%.*s%s%s" % (name_max - (len(count_str) + 1),
- name_new_orig,
- sep,
- count_str,
- )
+ name_new = "%.*s%s%s" % (
+ name_max - (len(count_str) + 1),
+ name_new_orig,
+ sep,
+ count_str,
+ )
count += 1
name_dict[key] = name_new
diff --git a/release/scripts/modules/bpy_extras/node_shader_utils.py b/release/scripts/modules/bpy_extras/node_shader_utils.py
index 0eac9794930..4ca3e675c37 100644
--- a/release/scripts/modules/bpy_extras/node_shader_utils.py
+++ b/release/scripts/modules/bpy_extras/node_shader_utils.py
@@ -619,10 +619,6 @@ class ShaderImageTextureWrapper():
self.translation = tex.translation
self.rotation = tex.rotation
self.scale = tex.scale
- self.use_min = tex.use_min
- self.use_max = tex.use_max
- self.min = tex.min
- self.max = tex.max
tex.is_readonly = is_readonly_back
@@ -750,70 +746,36 @@ class ShaderImageTextureWrapper():
def translation_get(self):
- return self.node_mapping.translation if self.node_mapping is not None else Vector((0.0, 0.0, 0.0))
+ if self.node_mapping is None:
+ return Vector((0.0, 0.0, 0.0))
+ return self.node_mapping.inputs['Location'].default_value
@_set_check
def translation_set(self, translation):
- self.node_mapping.translation = translation
+ self.node_mapping.inputs['Location'].default_value = translation
translation = property(translation_get, translation_set)
def rotation_get(self):
- return self.node_mapping.rotation if self.node_mapping is not None else Vector((0.0, 0.0, 0.0))
+ if self.node_mapping is None:
+ return Vector((0.0, 0.0, 0.0))
+ return self.node_mapping.inputs['Rotation'].default_value
@_set_check
def rotation_set(self, rotation):
- self.node_mapping.rotation = rotation
+ self.node_mapping.inputs['Rotation'].default_value = rotation
rotation = property(rotation_get, rotation_set)
def scale_get(self):
- return self.node_mapping.scale if self.node_mapping is not None else Vector((1.0, 1.0, 1.0))
+ if self.node_mapping is None:
+ return Vector((0.0, 0.0, 0.0))
+ return self.node_mapping.inputs['Scale'].default_value
@_set_check
def scale_set(self, scale):
- self.node_mapping.scale = scale
+ self.node_mapping.inputs['Scale'].default_value = scale
scale = property(scale_get, scale_set)
-
-
- def use_min_get(self):
- return self.node_mapping.use_min if self.node_mapping is not None else False
-
- @_set_check
- def use_min_set(self, use_min):
- self.node_mapping.use_min = use_min
-
- use_min = property(use_min_get, use_min_set)
-
-
- def use_max_get(self):
- return self.node_mapping.use_max if self.node_mapping is not None else False
-
- @_set_check
- def use_max_set(self, use_max):
- self.node_mapping.use_max = use_max
-
- use_max = property(use_max_get, use_max_set)
-
-
- def min_get(self):
- return self.node_mapping.min if self.node_mapping is not None else Vector((0.0, 0.0, 0.0))
-
- @_set_check
- def min_set(self, min):
- self.node_mapping.min = min
-
- min = property(min_get, min_set)
-
-
- def max_get(self):
- return self.node_mapping.max if self.node_mapping is not None else Vector((0.0, 0.0, 0.0))
-
- @_set_check
- def max_set(self, max):
- self.node_mapping.max = max
-
- max = property(max_get, max_set)
diff --git a/release/scripts/modules/bpy_extras/view3d_utils.py b/release/scripts/modules/bpy_extras/view3d_utils.py
index a2e394b270f..9e4958802f1 100644
--- a/release/scripts/modules/bpy_extras/view3d_utils.py
+++ b/release/scripts/modules/bpy_extras/view3d_utils.py
@@ -47,10 +47,11 @@ def region_2d_to_vector_3d(region, rv3d, coord):
if rv3d.is_perspective:
persinv = rv3d.perspective_matrix.inverted()
- out = Vector(((2.0 * coord[0] / region.width) - 1.0,
- (2.0 * coord[1] / region.height) - 1.0,
- -0.5
- ))
+ out = Vector((
+ (2.0 * coord[0] / region.width) - 1.0,
+ (2.0 * coord[1] / region.height) - 1.0,
+ -0.5
+ ))
w = out.dot(persinv[3].xyz) + persinv[3][3]
@@ -99,9 +100,11 @@ def region_2d_to_origin_3d(region, rv3d, coord, clamp=None):
dx = (2.0 * coord[0] / region.width) - 1.0
dy = (2.0 * coord[1] / region.height) - 1.0
persinv = persmat.inverted()
- origin_start = ((persinv.col[0].xyz * dx) +
- (persinv.col[1].xyz * dy) +
- persinv.translation)
+ origin_start = (
+ (persinv.col[0].xyz * dx) +
+ (persinv.col[1].xyz * dy) +
+ persinv.translation
+ )
if clamp != 0.0:
if rv3d.view_perspective != 'CAMERA':
@@ -149,17 +152,19 @@ def region_2d_to_location_3d(region, rv3d, coord, depth_location):
from mathutils.geometry import intersect_line_plane
viewinv = rv3d.view_matrix.inverted()
view_vec = viewinv.col[2].copy()
- return intersect_line_plane(origin_start,
- origin_end,
- depth_location,
- view_vec, 1,
- )
+ return intersect_line_plane(
+ origin_start,
+ origin_end,
+ depth_location,
+ view_vec, 1,
+ )
else:
from mathutils.geometry import intersect_point_line
- return intersect_point_line(depth_location,
- origin_start,
- origin_end,
- )[0]
+ return intersect_point_line(
+ depth_location,
+ origin_start,
+ origin_end,
+ )[0]
def location_3d_to_region_2d(region, rv3d, coord, default=None):
@@ -184,8 +189,9 @@ def location_3d_to_region_2d(region, rv3d, coord, default=None):
width_half = region.width / 2.0
height_half = region.height / 2.0
- return Vector((width_half + width_half * (prj.x / prj.w),
- height_half + height_half * (prj.y / prj.w),
- ))
+ return Vector((
+ width_half + width_half * (prj.x / prj.w),
+ height_half + height_half * (prj.y / prj.w),
+ ))
else:
return default
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py
index eca79795269..29470895079 100644
--- a/release/scripts/modules/bpy_types.py
+++ b/release/scripts/modules/bpy_types.py
@@ -60,12 +60,14 @@ class Library(bpy_types.ID):
# See: readblenentry.c, IDTYPE_FLAGS_ISLINKABLE,
# we could make this an attribute in rna.
- attr_links = ("actions", "armatures", "brushes", "cameras",
- "curves", "grease_pencils", "collections", "images",
- "lights", "lattices", "materials", "metaballs",
- "meshes", "node_groups", "objects", "scenes",
- "sounds", "speakers", "textures", "texts",
- "fonts", "worlds")
+ attr_links = (
+ "actions", "armatures", "brushes", "cameras",
+ "curves", "grease_pencils", "collections", "images",
+ "lights", "lattices", "materials", "metaballs",
+ "meshes", "node_groups", "objects", "scenes",
+ "sounds", "speakers", "textures", "texts",
+ "fonts", "worlds",
+ )
return tuple(id_block
for attr in attr_links
@@ -90,11 +92,13 @@ class Texture(bpy_types.ID):
def users_object_modifier(self):
"""Object modifiers that use this texture"""
import bpy
- return tuple(obj for obj in bpy.data.objects if
- self in [mod.texture
- for mod in obj.modifiers
- if mod.type == 'DISPLACE']
- )
+ return tuple(
+ obj for obj in bpy.data.objects if
+ self in [
+ mod.texture
+ for mod in obj.modifiers
+ if mod.type == 'DISPLACE']
+ )
class Collection(bpy_types.ID):
@@ -122,10 +126,15 @@ class Object(bpy_types.ID):
def users_collection(self):
"""The collections this object is in. Warning: takes O(len(bpy.data.collections) + len(bpy.data.scenes)) time."""
import bpy
- return tuple(collection for collection in bpy.data.collections
- if self in collection.objects[:]) + \
- tuple(scene.collection for scene in bpy.data.scenes
- if self in scene.collection.objects[:])
+ return (
+ tuple(
+ collection for collection in bpy.data.collections
+ if self in collection.objects[:]
+ ) + tuple(
+ scene.collection for scene in bpy.data.scenes
+ if self in scene.collection.objects[:]
+ )
+ )
@property
def users_scene(self):
@@ -252,18 +261,6 @@ class _GenericBone:
return (self.head + self.tail) * 0.5
@property
- def length(self):
- """
- The distance from head to tail,
- when set the head is moved to fit the length.
- """
- return self.vector.length
-
- @length.setter
- def length(self, value):
- self.tail = self.head + ((self.tail - self.head).normalized() * value)
-
- @property
def vector(self):
"""
The direction this bone is pointing.
@@ -483,18 +480,20 @@ class MeshLoopTriangle(StructRNA):
"""The midpoint of the face."""
face_verts = self.vertices[:]
mesh_verts = self.id_data.vertices
- return (mesh_verts[face_verts[0]].co +
- mesh_verts[face_verts[1]].co +
- mesh_verts[face_verts[2]].co
- ) / 3.0
+ return (
+ mesh_verts[face_verts[0]].co +
+ mesh_verts[face_verts[1]].co +
+ mesh_verts[face_verts[2]].co
+ ) / 3.0
@property
def edge_keys(self):
verts = self.vertices[:]
- return (ord_ind(verts[0], verts[1]),
- ord_ind(verts[1], verts[2]),
- ord_ind(verts[2], verts[0]),
- )
+ return (
+ ord_ind(verts[0], verts[1]),
+ ord_ind(verts[1], verts[2]),
+ ord_ind(verts[2], verts[0]),
+ )
class MeshPolygon(StructRNA):
@@ -862,15 +861,15 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
# collect paths
files = []
for directory in searchpaths:
- files.extend(
- [(f, os.path.join(directory, f))
+ files.extend([
+ (f, os.path.join(directory, f))
for f in os.listdir(directory)
if (not f.startswith("."))
if ((filter_ext is None) or
(filter_ext(os.path.splitext(f)[1])))
if ((filter_path is None) or
(filter_path(f)))
- ])
+ ])
files.sort()
@@ -928,11 +927,13 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
ext_valid = getattr(self, "preset_extensions", {".py", ".xml"})
props_default = getattr(self, "preset_operator_defaults", None)
add_operator = getattr(self, "preset_add_operator", None)
- self.path_menu(bpy.utils.preset_paths(self.preset_subdir),
- self.preset_operator,
- props_default=props_default,
- filter_ext=lambda ext: ext.lower() in ext_valid,
- add_operator=add_operator)
+ self.path_menu(
+ bpy.utils.preset_paths(self.preset_subdir),
+ self.preset_operator,
+ props_default=props_default,
+ filter_ext=lambda ext: ext.lower() in ext_valid,
+ add_operator=add_operator,
+ )
@classmethod
def draw_collapsible(cls, context, layout):
@@ -967,9 +968,10 @@ class NodeSocket(StructRNA, metaclass=RNAMetaPropGroup):
@property
def links(self):
"""List of node links from or to this socket. Warning: takes O(len(nodetree.links)) time."""
- return tuple(link for link in self.id_data.links
- if (link.from_socket == self or
- link.to_socket == self))
+ return tuple(
+ link for link in self.id_data.links
+ if (link.from_socket == self or
+ link.to_socket == self))
class NodeSocketInterface(StructRNA, metaclass=RNAMetaPropGroup):
diff --git a/release/scripts/modules/console/complete_import.py b/release/scripts/modules/console/complete_import.py
index ff3099d7285..6f51f6b691b 100644
--- a/release/scripts/modules/console/complete_import.py
+++ b/release/scripts/modules/console/complete_import.py
@@ -178,7 +178,7 @@ def complete(line):
words = line.split(' ')
if len(words) == 3 and words[0] == 'from':
return ['import ']
- if len(words) < 3 and (words[0] in ['import', 'from']):
+ if len(words) < 3 and (words[0] in {'import', 'from'}):
if len(words) == 1:
return get_root_modules()
mod = words[1].split('.')
diff --git a/release/scripts/modules/rna_info.py b/release/scripts/modules/rna_info.py
index 6f51dcf3aeb..8a46246cf91 100644
--- a/release/scripts/modules/rna_info.py
+++ b/release/scripts/modules/rna_info.py
@@ -542,7 +542,7 @@ def BuildRNAInfo():
# Use for faster lookups
# use rna_struct.identifier as the key for each dict
rna_struct_dict = {} # store identifier:rna lookups
- rna_full_path_dict = {} # store the result of full_rna_struct_path(rna_struct)
+ rna_full_path_dict = {} # store the result of full_rna_struct_path(rna_struct)
rna_children_dict = {} # store all rna_structs nested from here
rna_references_dict = {} # store a list of rna path strings that reference this type
# rna_functions_dict = {} # store all functions directly in this type (not inherited)
diff --git a/release/scripts/modules/rna_manual_reference.py b/release/scripts/modules/rna_manual_reference.py
index a09f1f2285f..1f01523534f 100644
--- a/release/scripts/modules/rna_manual_reference.py
+++ b/release/scripts/modules/rna_manual_reference.py
@@ -37,12 +37,24 @@ if LANG is not None:
url_manual_mapping = (
("bpy.types.cyclesobjectsettings.use_adaptive_subdivision*", "render/cycles/object_settings/adaptive_subdiv.html#bpy-types-cyclesobjectsettings-use-adaptive-subdivision"),
+ ("bpy.types.rendersettings_simplify_gpencil_view_modifier*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-view-modifier"),
+ ("bpy.types.brushgpencilsettings.use_settings_stabilizer*", "grease_pencil/modes/draw/tool_settings/brushes/draw_brush.html#bpy-types-brushgpencilsettings-use-settings-stabilizer"),
+ ("bpy.types.gpencilsculptsettings.use_multiframe_falloff*", "grease_pencil/multiframe.html#bpy-types-gpencilsculptsettings-use-multiframe-falloff"),
+ ("bpy.types.rendersettings_simplify_gpencil_remove_lines*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-remove-lines"),
+ ("bpy.types.toolsettings.use_transform_pivot_point_align*", "scene_layout/object/editing/transform/control/options.html#bpy-types-toolsettings-use-transform-pivot-point-align"),
("bpy.types.cyclesrendersettings.offscreen_dicing_scale*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-offscreen-dicing-scale"),
("bpy.types.linestylegeometrymodifier_backbonestretcher*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/backbone_stretcher.html#bpy-types-linestylegeometrymodifier-backbonestretcher"),
("bpy.types.linestylegeometrymodifier_sinusdisplacement*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/sinus_displacement.html#bpy-types-linestylegeometrymodifier-sinusdisplacement"),
("bpy.types.linestylegeometrymodifier_polygonalization*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/polygonization.html#bpy-types-linestylegeometrymodifier-polygonalization"),
("bpy.types.cyclesrendersettings.distance_cull_margin*", "render/cycles/render_settings/simplify.html#bpy-types-cyclesrendersettings-distance-cull-margin"),
+ ("bpy.types.materialgpencilstyle.use_fill_texture_mix*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-use-fill-texture-mix"),
+ ("bpy.types.rendersettings_simplify_gpencil_shader_fx*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-shader-fx"),
+ ("bpy.types.rendersettings_simplify_gpencil_view_fill*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-view-fill"),
+ ("bpy.types.brushgpencilsettings.use_jitter_pressure*", "grease_pencil/modes/draw/tool_settings/brushes/draw_brush.html#bpy-types-brushgpencilsettings-use-jitter-pressure"),
+ ("bpy.types.brushgpencilsettings.use_settings_random*", "grease_pencil/modes/draw/tool_settings/brushes/draw_brush.html#bpy-types-brushgpencilsettings-use-settings-random"),
("bpy.types.linestylegeometrymodifier_simplification*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/simplification.html#bpy-types-linestylegeometrymodifier-simplification"),
+ ("bpy.types.materialgpencilstyle.use_overlap_strokes*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-use-overlap-strokes"),
+ ("bpy.types.toolsettings.use_gpencil_weight_data_add*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-weight-data-add"),
("bpy.types.cyclesrendersettings.camera_cull_margin*", "render/cycles/render_settings/simplify.html#bpy-types-cyclesrendersettings-camera-cull-margin"),
("bpy.types.linestylegeometrymodifier_perlinnoise1d*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/perlin_noise_1d.html#bpy-types-linestylegeometrymodifier-perlinnoise1d"),
("bpy.types.linestylegeometrymodifier_perlinnoise2d*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/perlin_noise_2d.html#bpy-types-linestylegeometrymodifier-perlinnoise2d"),
@@ -51,38 +63,69 @@ url_manual_mapping = (
("bpy.types.linestylegeometrymodifier_guidinglines*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/guiding_lines.html#bpy-types-linestylegeometrymodifier-guidinglines"),
("bpy.types.linestylegeometrymodifier_spatialnoise*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/spatial_noise.html#bpy-types-linestylegeometrymodifier-spatialnoise"),
("bpy.types.linestylethicknessmodifier_calligraphy*", "render/freestyle/parameter_editor/line_style/modifiers/thickness/calligraphy.html#bpy-types-linestylethicknessmodifier-calligraphy"),
+ ("bpy.types.rendersettings_simplify_gpencil_onplay*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-onplay"),
+ ("bpy.types.toolsettings.use_gpencil_draw_additive*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-draw-additive"),
+ ("bpy.types.toolsettings.use_transform_data_origin*", "scene_layout/object/editing/transform/control/options.html#bpy-types-toolsettings-use-transform-data-origin"),
("bpy.types.cyclesrendersettings.max_subdivisions*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-max-subdivisions"),
("bpy.types.linestyle*modifier_distancefromcamera*", "render/freestyle/parameter_editor/line_style/modifiers/color/distance_from_camera.html#bpy-types-linestyle-modifier-distancefromcamera"),
("bpy.types.linestyle*modifier_distancefromobject*", "render/freestyle/parameter_editor/line_style/modifiers/color/distance_from_object.html#bpy-types-linestyle-modifier-distancefromobject"),
("bpy.types.linestylegeometrymodifier_2dtransform*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/2d_transform.html#bpy-types-linestylegeometrymodifier-2dtransform"),
("bpy.types.linestylegeometrymodifier_beziercurve*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/bezier_curve.html#bpy-types-linestylegeometrymodifier-beziercurve"),
+ ("bpy.types.rendersettings_simplify_gpencil_blend*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-blend"),
+ ("bpy.types.toolsettings.gpencil_stroke_placement*", "grease_pencil/modes/draw/stroke_placement.html#bpy-types-toolsettings-gpencil-stroke-placement"),
("bpy.types.cyclesrendersettings.use_camera_cull*", "render/cycles/render_settings/simplify.html#bpy-types-cyclesrendersettings-use-camera-cull"),
("bpy.types.linestylegeometrymodifier_tipremover*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/tip_remover.html#bpy-types-linestylegeometrymodifier-tipremover"),
+ ("bpy.types.rendersettings_simplify_gpencil_tint*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-tint"),
+ ("bpy.types.toolsettings.use_gpencil_draw_onback*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-draw-onback"),
("bpy.types.cyclesmaterialsettings.displacement*", "render/cycles/material_settings.html#bpy-types-cyclesmaterialsettings-displacement"),
("bpy.types.linestylegeometrymodifier_blueprint*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/blueprint.html#bpy-types-linestylegeometrymodifier-blueprint"),
+ ("bpy.types.materialgpencilstyle.alignment_mode*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-alignment-mode"),
("bpy.types.rendersettings.simplify_subdivision*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-subdivision"),
+ ("bpy.ops.object.vertex_group_copy_to_selected*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-copy-to-selected"),
("bpy.types.cyclesrendersettings.dicing_camera*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-dicing-camera"),
("bpy.types.cyclesrendersettings.texture_limit*", "render/cycles/render_settings/simplify.html#bpy-types-cyclesrendersettings-texture-limit"),
+ ("bpy.types.gpencilsculptguide.reference_point*", "grease_pencil/modes/draw/guides.html#bpy-types-gpencilsculptguide-reference-point"),
("bpy.types.linestylegeometrymodifier_2doffset*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/2d_offset.html#bpy-types-linestylegeometrymodifier-2doffset"),
("bpy.types.linestylegeometrymodifier_sampling*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/sampling.html#bpy-types-linestylegeometrymodifier-sampling"),
("bpy.types.cyclesrendersettings.*dicing_rate*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-dicing-rate"),
+ ("bpy.types.materialgpencilstyle.stroke_style*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-stroke-style"),
("bpy.types.rendersettings.use_file_extension*", "render/output/settings.html#bpy-types-rendersettings-use-file-extension"),
("bpy.types.spaceview3d.transform_orientation*", "scene_layout/object/editing/transform/control/orientations.html#bpy-types-spaceview3d-transform-orientation"),
("bpy.ops.object.constraint_add_with_targets*", "animation/constraints/interface/adding_removing.html#bpy-ops-object-constraint-add-with-targets"),
+ ("bpy.ops.object.vertex_group_copy_to_linked*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-copy-to-linked"),
("bpy.types.cyclesobjectsettings.dicing_rate*", "render/cycles/object_settings/adaptive_subdiv.html#bpy-types-cyclesobjectsettings-dicing-rate"),
+ ("bpy.types.materialgpencilstyle.show_stroke*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-show-stroke"),
("bpy.types.posebone.use_ik_rotation_control*", "animation/armatures/posing/bone_constraints/inverse_kinematics/introduction.html#bpy-types-posebone-use-ik-rotation-control"),
("bpy.ops.constraint.disable_keep_transform*", "animation/constraints/interface/common.html#bpy-ops-constraint-disable-keep-transform"),
+ ("bpy.ops.object.vertex_group_normalize_all*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-normalize-all"),
+ ("bpy.types.brushgpencilsettings.pen_jitter*", "grease_pencil/modes/draw/tool_settings/brushes/draw_brush.html#bpy-types-brushgpencilsettings-pen-jitter"),
+ ("bpy.types.gpencillayer.use_onion_skinning*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-use-onion-skinning"),
+ ("bpy.types.gpencilsculptguide.use_snapping*", "grease_pencil/modes/draw/guides.html#bpy-types-gpencilsculptguide-use-snapping"),
+ ("bpy.types.gpencilsculptsettings.lock_axis*", "grease_pencil/modes/draw/drawing_planes.html#bpy-types-gpencilsculptsettings-lock-axis"),
("bpy.types.imagepaint.use_backface_culling*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-types-imagepaint-use-backface-culling"),
("bpy.types.linestyle*modifier_curvature_3d*", "render/freestyle/parameter_editor/line_style/modifiers/color/curvature_3d.html#bpy-types-linestyle-modifier-curvature-3d"),
+ ("bpy.types.materialgpencilstyle.fill_color*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-fill-color"),
+ ("bpy.types.materialgpencilstyle.fill_style*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-fill-style"),
+ ("bpy.types.materialgpencilstyle.mix_factor*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-mix-factor"),
("bpy.types.rendersettings.use_render_cache*", "render/output/settings.html#bpy-types-rendersettings-use-render-cache"),
+ ("bpy.types.rendersettings_simplify_gpencil*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil"),
("bpy.types.sceneeevee.use_taa_reprojection*", "render/eevee/render_settings/sampling.html#bpy-types-sceneeevee-use-taa-reprojection"),
+ ("bpy.types.sequenceeditor.use_overlay_lock*", "video_editing/preview/properties.html#bpy-types-sequenceeditor-use-overlay-lock"),
+ ("bpy.types.toolsettings.gpencil_selectmode*", "grease_pencil/selecting.html#bpy-types-toolsettings-gpencil-selectmode"),
+ ("bpy.ops.gpencil.active_frames_delete_all*", "grease_pencil/animation/tools.html#bpy-ops-gpencil-active-frames-delete-all"),
+ ("bpy.ops.gpencil.stroke_merge_by_distance*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-stroke-merge-by-distance"),
("bpy.ops.object.anim_transforms_to_deltas*", "scene_layout/object/editing/transform/clear_apply.html#bpy-ops-object-anim-transforms-to-deltas"),
+ ("bpy.types.brushgpencilsettings.uv_random*", "grease_pencil/modes/draw/tool_settings/brushes/draw_brush.html#bpy-types-brushgpencilsettings-uv-random"),
("bpy.types.compositornodeplanetrackdeform*", "compositing/types/distort/plane_track_deform.html#bpy-types-compositornodeplanetrackdeform"),
("bpy.types.linestyle*modifier_alongstroke*", "render/freestyle/parameter_editor/line_style/modifiers/color/along_stroke.html#bpy-types-linestyle-modifier-alongstroke"),
("bpy.types.linestyle*modifier_creaseangle*", "render/freestyle/parameter_editor/line_style/modifiers/color/crease_angle.html#bpy-types-linestyle-modifier-creaseangle"),
("bpy.types.linestylecolormodifier_tangent*", "render/freestyle/parameter_editor/line_style/modifiers/color/tangent.html#bpy-types-linestylecolormodifier-tangent"),
+ ("bpy.types.materialgpencilstyle.mix_color*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-mix-color"),
+ ("bpy.types.materialgpencilstyle.show_fill*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-show-fill"),
("bpy.types.rendersettings.use_placeholder*", "render/output/settings.html#bpy-types-rendersettings-use-placeholder"),
("bpy.types.shadernodesubsurfacescattering*", "render/shader_nodes/shader/sss.html#bpy-types-shadernodesubsurfacescattering"),
+ ("bpy.ops.object.vertex_group_limit_total*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-limit-total"),
+ ("bpy.ops.object.vertex_group_remove_from*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-remove-from"),
("bpy.types.compositornodecolorcorrection*", "compositing/types/color/color_correction.html#bpy-types-compositornodecolorcorrection"),
("bpy.types.compositornodemoviedistortion*", "compositing/types/distort/movie_distortion.html#bpy-types-compositornodemoviedistortion"),
("bpy.types.ffmpegsettings.audio_channels*", "scene_layout/scene/properties.html#bpy-types-ffmpegsettings-audio-channels"),
@@ -96,14 +139,21 @@ url_manual_mapping = (
("bpy.types.compositornodedoubleedgemask*", "compositing/types/matte/double_edge_mask.html#bpy-types-compositornodedoubleedgemask"),
("bpy.types.ffmpegsettings.audio_mixrate*", "scene_layout/scene/properties.html#bpy-types-ffmpegsettings-audio-mixrate"),
("bpy.types.material.preview_render_type*", "render/materials/preview.html#bpy-types-material-preview-render-type"),
+ ("bpy.types.materialgpencilstyle.pattern*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-pattern"),
+ ("bpy.types.materialgpencilstyle.texture*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-texture"),
("bpy.types.rendersettings.use_overwrite*", "render/output/settings.html#bpy-types-rendersettings-use-overwrite"),
("bpy.types.sceneeevee.volumetric_shadow*", "render/eevee/render_settings/volumetrics.html#bpy-types-sceneeevee-volumetric-shadow"),
("bpy.types.shadernodebsdfhairprincipled*", "render/shader_nodes/shader/hair_principled.html#bpy-types-shadernodebsdfhairprincipled"),
("bpy.types.shadernodevectordisplacement*", "render/shader_nodes/vector/vector_displacement.html#bpy-types-shadernodevectordisplacement"),
("bpy.types.spacegrapheditor.show_cursor*", "editors/graph_editor/fcurves/properties.html#bpy-types-spacegrapheditor-show-cursor"),
("bpy.types.spaceimageeditor.show_repeat*", "editors/image/view_tab.html#bpy-types-spaceimageeditor-show-repeat"),
+ ("bpy.ops.curve.normals_make_consistent*", "modeling/curves/editing/control_points.html#bpy-ops-curve-normals-make-consistent"),
+ ("bpy.ops.gpencil.stroke_simplify_fixed*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-simplify-fixed"),
+ ("bpy.ops.object.gpencil_modifier_apply*", "grease_pencil/modifiers/introduction.html#bpy-ops-object-gpencil-modifier-apply"),
+ ("bpy.ops.object.vertex_group_normalize*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-normalize"),
("bpy.ops.object.visual_transform_apply*", "scene_layout/object/editing/transform/clear_apply.html#bpy-ops-object-visual-transform-apply"),
("bpy.types.brush.texture_overlay_alpha*", "sculpt_paint/brush/display.html#bpy-types-brush-texture-overlay-alpha"),
+ ("bpy.types.brushgpencilsettings.random*", "grease_pencil/modes/draw/tool_settings/brushes/draw_brush.html#bpy-types-brushgpencilsettings-random"),
("bpy.types.compositornodebilateralblur*", "compositing/types/filter/bilateral_blur.html#bpy-types-compositornodebilateralblur"),
("bpy.types.compositornodedistancematte*", "compositing/types/matte/distance_key.html#bpy-types-compositornodedistancematte"),
("bpy.types.imagepaint.screen_grab_size*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-types-imagepaint-screen-grab-size"),
@@ -111,8 +161,12 @@ url_manual_mapping = (
("bpy.types.particlesettingstextureslot*", "physics/particles/texture_influence.html#bpy-types-particlesettingstextureslot"),
("bpy.types.posebone.ik_rotation_weight*", "animation/armatures/posing/bone_constraints/inverse_kinematics/introduction.html#bpy-types-posebone-ik-rotation-weight"),
("bpy.types.sceneeevee.volumetric_light*", "render/eevee/render_settings/volumetrics.html#bpy-types-sceneeevee-volumetric-light"),
+ ("bpy.types.sequenceeditor.show_overlay*", "video_editing/preview/properties.html#bpy-types-sequenceeditor-show-overlay"),
+ ("bpy.types.spline.radius_interpolation*", "modeling/curves/properties/active_spline.html#bpy-types-spline-radius-interpolation"),
+ ("bpy.ops.gpencil.interpolate_sequence*", "grease_pencil/animation/tools.html#bpy-ops-gpencil-interpolate-sequence"),
("bpy.ops.mesh.normals_make_consistent*", "modeling/meshes/editing/normals.html#bpy-ops-mesh-normals-make-consistent"),
("bpy.ops.object.duplicate_move_linked*", "scene_layout/object/editing/duplication.html#bpy-ops-object-duplicate-move-linked"),
+ ("bpy.ops.object.vertex_group_quantize*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-quantize"),
("bpy.ops.view3d.localview_remove_from*", "editors/3dview/navigate/views.html#bpy-ops-view3d-localview-remove-from"),
("bpy.types.brush.cursor_overlay_alpha*", "sculpt_paint/brush/display.html#bpy-types-brush-cursor-overlay-alpha"),
("bpy.types.brush.topology_rake_factor*", "sculpt_paint/sculpting/tool_settings/dyntopo.html#bpy-types-brush-topology-rake-factor"),
@@ -121,15 +175,23 @@ url_manual_mapping = (
("bpy.types.compositornodekeyingscreen*", "compositing/types/matte/keying_screen.html#bpy-types-compositornodekeyingscreen"),
("bpy.types.dynamicpaintcanvassettings*", "physics/dynamic_paint/canvas.html#bpy-types-dynamicpaintcanvassettings"),
("bpy.types.fmodifierfunctiongenerator*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifierfunctiongenerator"),
+ ("bpy.types.gpencillayer.use_solo_mode*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-use-solo-mode"),
+ ("bpy.types.greasepencil.use_multiedit*", "grease_pencil/multiframe.html#bpy-types-greasepencil-use-multiedit"),
+ ("bpy.types.materialgpencilstyle.color*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-color"),
("bpy.types.movietrackingstabilization*", "movie_clip/tracking/clip/properties/stabilization/index.html#bpy-types-movietrackingstabilization"),
("bpy.types.object.display_bounds_type*", "scene_layout/object/properties/display.html#bpy-types-object-display-bounds-type"),
("bpy.types.shadernodeambientocclusion*", "render/shader_nodes/input/ao.html#bpy-types-shadernodeambientocclusion"),
("bpy.types.shadernodevolumeabsorption*", "render/shader_nodes/shader/volume_absorption.html#bpy-types-shadernodevolumeabsorption"),
("bpy.types.shadernodevolumeprincipled*", "render/shader_nodes/shader/volume_principled.html#bpy-types-shadernodevolumeprincipled"),
("bpy.types.toolsettings.use_uv_sculpt*", "modeling/meshes/editing/uv/uv_sculpt.html#bpy-types-toolsettings-use-uv-sculpt"),
+ ("bpy.ops.gpencil.interpolate_reverse*", "grease_pencil/animation/interpolation.html#bpy-ops-gpencil-interpolate-reverse"),
+ ("bpy.ops.gpencil.set_active_material*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-set-active-material"),
+ ("bpy.ops.gpencil.stroke_change_color*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-change-color"),
+ ("bpy.ops.gpencil.stroke_cyclical_set*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-cyclical-set"),
("bpy.ops.mesh.set_normals_from_faces*", "modeling/meshes/editing/normals.html#bpy-ops-mesh-set-normals-from-faces"),
("bpy.ops.object.duplicates_make_real*", "scene_layout/object/editing/transform/clear_apply.html#bpy-ops-object-duplicates-make-real"),
("bpy.ops.object.transforms_to_deltas*", "scene_layout/object/editing/transform/clear_apply.html#bpy-ops-object-transforms-to-deltas"),
+ ("bpy.ops.sequencer.view_ghost_border*", "video_editing/preview/properties.html#bpy-ops-sequencer-view-ghost-border"),
("bpy.types.brush.use_primary_overlay*", "sculpt_paint/brush/display.html#bpy-types-brush-use-primary-overlay"),
("bpy.types.compositornodechromamatte*", "compositing/types/matte/chroma_key.html#bpy-types-compositornodechromamatte"),
("bpy.types.compositornodedilateerode*", "compositing/types/filter/dilate_erode.html#bpy-types-compositornodedilateerode"),
@@ -137,6 +199,8 @@ url_manual_mapping = (
("bpy.types.compositornodesplitviewer*", "compositing/types/output/split_viewer.html#bpy-types-compositornodesplitviewer"),
("bpy.types.curve.use_uv_as_generated*", "editors/uv/generated_uvs.html#bpy-types-curve-use-uv-as-generated"),
("bpy.types.dynamicpaintbrushsettings*", "physics/dynamic_paint/brush.html#bpy-types-dynamicpaintbrushsettings"),
+ ("bpy.types.materialgpencilstyle.flip*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-flip"),
+ ("bpy.types.materialgpencilstyle.mode*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-mode"),
("bpy.types.rendersettings.use_border*", "render/output/settings.html#bpy-types-rendersettings-use-border"),
("bpy.types.sceneeevee.bokeh_max_size*", "render/eevee/render_settings/depth_of_field.html#bpy-types-sceneeevee-bokeh-max-size"),
("bpy.types.shadernodebsdfanisotropic*", "render/shader_nodes/shader/anisotropic.html#bpy-types-shadernodebsdfanisotropic"),
@@ -149,8 +213,13 @@ url_manual_mapping = (
("bpy.ops.node.read_fullsamplelayers*", "interface/controls/nodes/editing.html#bpy-ops-node-read-fullsamplelayers"),
("bpy.ops.object.datalayout_transfer*", "modeling/meshes/editing/data_transfer.html#bpy-ops-object-datalayout-transfer"),
("bpy.ops.object.randomize_transform*", "scene_layout/object/editing/transform/tools.html#bpy-ops-object-randomize-transform"),
+ ("bpy.ops.object.vertex_group_invert*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-invert"),
("bpy.ops.object.vertex_group_levels*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-levels"),
+ ("bpy.ops.object.vertex_group_mirror*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-mirror"),
+ ("bpy.ops.object.vertex_group_remove*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-remove"),
+ ("bpy.ops.object.vertex_group_smooth*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-smooth"),
("bpy.ops.sequencer.crossfade_sounds*", "video_editing/sequencer/strips/transitions/cross.html#bpy-ops-sequencer-crossfade-sounds"),
+ ("bpy.ops.sequencer.export_subtitles*", "video_editing/preview/introduction.html#bpy-ops-sequencer-export-subtitles"),
("bpy.ops.transform.edge_bevelweight*", "modeling/meshes/editing/edges.html#bpy-ops-transform-edge-bevelweight"),
("bpy.ops.wm.previews_batch_generate*", "files/blend/previews.html#bpy-ops-wm-previews-batch-generate"),
("bpy.types.brush.use_cursor_overlay*", "sculpt_paint/brush/display.html#bpy-types-brush-use-cursor-overlay"),
@@ -173,12 +242,17 @@ url_manual_mapping = (
("bpy.types.shadernodebsdfrefraction*", "render/shader_nodes/shader/refraction.html#bpy-types-shadernodebsdfrefraction"),
("bpy.types.shadernodeoutputmaterial*", "render/shader_nodes/output/material.html#bpy-types-shadernodeoutputmaterial"),
("bpy.types.shadernodetexenvironment*", "render/shader_nodes/textures/environment.html#bpy-types-shadernodetexenvironment"),
+ ("bpy.types.subdividegpencilmodifier*", "grease_pencil/modifiers/generate/subdivide.html#bpy-types-subdividegpencilmodifier"),
+ ("bpy.types.thicknessgpencilmodifier*", "grease_pencil/modifiers/deform/thickness.html#bpy-types-thicknessgpencilmodifier"),
("bpy.types.transformcacheconstraint*", "animation/constraints/transform/transform_cache.html#bpy-types-transformcacheconstraint"),
("bpy.types.userpreferencesfilepaths*", "editors/preferences/file_paths.html#bpy-types-userpreferencesfilepaths"),
("bpy.types.vertexweighteditmodifier*", "modeling/modifiers/modify/weight_edit.html#bpy-types-vertexweighteditmodifier"),
("bpy.ops.curve.match_texture_space*", "editors/uv/generated_uvs.html#bpy-ops-curve-match-texture-space"),
("bpy.ops.font.text_paste_from_file*", "modeling/texts/selecting_editing.html#bpy-ops-font-text-paste-from-file"),
+ ("bpy.ops.gpencil.frame_clean_loose*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-frame-clean-loose"),
+ ("bpy.ops.object.vertex_group_clean*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-clean"),
("bpy.ops.render.play-rendered-anim*", "render/output/animation_player.html#bpy-ops-render-play-rendered-anim"),
+ ("bpy.types.armaturegpencilmodifier*", "grease_pencil/modifiers/deform/armature.html#bpy-types-armaturegpencilmodifier"),
("bpy.types.camera.show_composition*", "render/cameras.html#bpy-types-camera-show-composition"),
("bpy.types.compositornodealphaover*", "compositing/types/color/alpha_over.html#bpy-types-compositornodealphaover"),
("bpy.types.compositornodebokehblur*", "compositing/types/filter/bokeh_blur.html#bpy-types-compositornodebokehblur"),
@@ -194,6 +268,9 @@ url_manual_mapping = (
("bpy.types.compositornodetranslate*", "compositing/types/distort/translate.html#bpy-types-compositornodetranslate"),
("bpy.types.fluidsimulationmodifier*", "physics/fluid/index.html#bpy-types-fluidsimulationmodifier"),
("bpy.types.freestylemodulesettings*", "render/freestyle/python.html#bpy-types-freestylemodulesettings"),
+ ("bpy.types.gpencillayer.blend_mode*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-blend-mode"),
+ ("bpy.types.gpencillayer.mask_layer*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-mask-layer"),
+ ("bpy.types.gpencilsculptguide.type*", "grease_pencil/modes/draw/guides.html#bpy-types-gpencilsculptguide-type"),
("bpy.types.laplaciandeformmodifier*", "modeling/modifiers/deform/laplacian_deform.html#bpy-types-laplaciandeformmodifier"),
("bpy.types.laplaciansmoothmodifier*", "modeling/modifiers/deform/laplacian_smooth.html#bpy-types-laplaciansmoothmodifier"),
("bpy.types.limitdistanceconstraint*", "animation/constraints/transform/limit_distance.html#bpy-types-limitdistanceconstraint"),
@@ -204,9 +281,16 @@ url_manual_mapping = (
("bpy.types.shadernodeeeveespecular*", "render/shader_nodes/shader/specular_bsdf.html#bpy-types-shadernodeeeveespecular"),
("bpy.types.shadernodehuesaturation*", "render/shader_nodes/color/hue_saturation.html#bpy-types-shadernodehuesaturation"),
("bpy.types.shadernodevolumescatter*", "render/shader_nodes/shader/volume_scatter.html#bpy-types-shadernodevolumescatter"),
+ ("bpy.types.simplifygpencilmodifier*", "grease_pencil/modifiers/generate/simplify.html#bpy-types-simplifygpencilmodifier"),
("bpy.types.spacegrapheditor.cursor*", "editors/graph_editor/introduction.html#bpy-types-spacegrapheditor-cursor"),
("bpy.types.vertexweightmixmodifier*", "modeling/modifiers/modify/weight_mix.html#bpy-types-vertexweightmixmodifier"),
+ ("bpy.ops.gpencil.frame_clean_fill*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-frame-clean-fill"),
+ ("bpy.ops.gpencil.stroke_subdivide*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-subdivide"),
("bpy.ops.object.constraints_clear*", "animation/constraints/interface/adding_removing.html#bpy-ops-object-constraints-clear"),
+ ("bpy.ops.object.vertex_group_copy*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-copy"),
+ ("bpy.ops.object.vertex_group_lock*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-lock"),
+ ("bpy.ops.object.vertex_group_move*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-move"),
+ ("bpy.ops.object.vertex_group_sort*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-sort"),
("bpy.ops.uv.average_islands_scale*", "modeling/meshes/editing/uv/layout.html#bpy-ops-uv-average-islands-scale"),
("bpy.ops.view3d.edit_mesh_extrude*", "modeling/meshes/editing/duplicating/extrude.html#bpy-ops-view3d-edit-mesh-extrude"),
("bpy.types.brightcontrastmodifier*", "video_editing/sequencer/properties/modifiers.html#bpy-types-brightcontrastmodifier"),
@@ -228,18 +312,31 @@ url_manual_mapping = (
("bpy.types.copyrotationconstraint*", "animation/constraints/transform/copy_rotation.html#bpy-types-copyrotationconstraint"),
("bpy.types.cyclesmaterialsettings*", "render/cycles/material_settings.html#bpy-types-cyclesmaterialsettings"),
("bpy.types.imagepaint.use_occlude*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-types-imagepaint-use-occlude"),
+ ("bpy.types.latticegpencilmodifier*", "grease_pencil/modifiers/deform/lattice.html#bpy-types-latticegpencilmodifier"),
("bpy.types.mesh.auto_smooth_angle*", "modeling/meshes/structure.html#bpy-types-mesh-auto-smooth-angle"),
("bpy.types.objectsolverconstraint*", "animation/constraints/motion_tracking/object_solver.html#bpy-types-objectsolverconstraint"),
+ ("bpy.types.opacitygpencilmodifier*", "grease_pencil/modifiers/color/opacity.html#bpy-types-opacitygpencilmodifier"),
("bpy.types.particlesystemmodifier*", "physics/particles/index.html#bpy-types-particlesystemmodifier"),
("bpy.types.sceneeevee.motion_blur*", "render/eevee/render_settings/motion_blur.html#bpy-types-sceneeevee-motion-blur"),
("bpy.types.sceneeevee.taa_samples*", "render/eevee/render_settings/sampling.html#bpy-types-sceneeevee-taa-samples"),
+ ("bpy.types.sequenceeditor.overlay*", "video_editing/preview/properties.html#bpy-types-sequenceeditor-overlay"),
("bpy.types.shadernodedisplacement*", "render/shader_nodes/vector/displacement.html#bpy-types-shadernodedisplacement"),
("bpy.types.shadernodelightfalloff*", "render/shader_nodes/color/light_falloff.html#bpy-types-shadernodelightfalloff"),
("bpy.types.shadernodeparticleinfo*", "render/shader_nodes/input/particle_info.html#bpy-types-shadernodeparticleinfo"),
("bpy.types.weightednormalmodifier*", "modeling/modifiers/modify/weighted_normal.html#bpy-types-weightednormalmodifier"),
+ ("bpy.ops.curve.spline_weight_set*", "modeling/curves/editing/other.html#bpy-ops-curve-spline-weight-set"),
+ ("bpy.ops.gpencil.blank_frame_add*", "grease_pencil/animation/tools.html#bpy-ops-gpencil-blank-frame-add"),
+ ("bpy.ops.gpencil.frame_duplicate*", "grease_pencil/animation/tools.html#bpy-ops-gpencil-frame-duplicate"),
+ ("bpy.ops.gpencil.stroke_caps_set*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-caps-set"),
+ ("bpy.ops.gpencil.stroke_separate*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-stroke-separate"),
+ ("bpy.ops.gpencil.stroke_simplify*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-simplify"),
("bpy.ops.object.constraints_copy*", "animation/constraints/interface/adding_removing.html#bpy-ops-object-constraints-copy"),
+ ("bpy.ops.object.gpencil_modifier*", "grease_pencil/modifiers/index.html#bpy-ops-object-gpencil-modifier"),
("bpy.ops.object.make_single_user*", "scene_layout/object/editing/duplication.html#bpy-ops-object-make-single-user"),
("bpy.ops.object.select_hierarchy*", "scene_layout/object/selecting.html#bpy-ops-object-select-hierarchy"),
+ ("bpy.ops.object.vertex_group_add*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-add"),
+ ("bpy.ops.object.vertex_group_fix*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-fix"),
+ ("bpy.ops.paint.weight_from_bones*", "sculpt_paint/weight_paint/editing.html#bpy-ops-paint-weight-from-bones"),
("bpy.ops.screen.screen_full_area*", "interface/window_system/areas.html#bpy-ops-screen-screen-full-area"),
("bpy.ops.transform.rotate_normal*", "modeling/meshes/editing/normals.html#bpy-ops-transform-rotate-normal"),
("bpy.ops.transform.shrink_fatten*", "modeling/meshes/editing/transform/shrink-fatten.html#bpy-ops-transform-shrink-fatten"),
@@ -258,8 +355,12 @@ url_manual_mapping = (
("bpy.types.dampedtrackconstraint*", "animation/constraints/tracking/damped_track.html#bpy-types-dampedtrackconstraint"),
("bpy.types.distortednoisetexture*", "render/materials/legacy_textures/types/distorted_noise.html#bpy-types-distortednoisetexture"),
("bpy.types.followtrackconstraint*", "animation/constraints/motion_tracking/follow_track.html#bpy-types-followtrackconstraint"),
+ ("bpy.types.gpencilsculptsettings*", "grease_pencil/properties/index.html#bpy-types-gpencilsculptsettings"),
("bpy.types.lockedtrackconstraint*", "animation/constraints/tracking/locked_track.html#bpy-types-lockedtrackconstraint"),
+ ("bpy.types.material.blend_method*", "render/eevee/materials/settings.html#bpy-types-material-blend-method"),
+ ("bpy.types.mirrorgpencilmodifier*", "grease_pencil/modifiers/generate/mirror.html#bpy-types-mirrorgpencilmodifier"),
("bpy.types.obstaclefluidsettings*", "physics/fluid/types/obstacle.html#bpy-types-obstaclefluidsettings"),
+ ("bpy.types.offsetgpencilmodifier*", "grease_pencil/modifiers/deform/offset.html#bpy-types-offsetgpencilmodifier"),
("bpy.types.particlefluidsettings*", "physics/particles/emitter/physics/fluid.html#bpy-types-particlefluidsettings"),
("bpy.types.sceneeevee.volumetric*", "render/eevee/render_settings/volumetrics.html#bpy-types-sceneeevee-volumetric"),
("bpy.types.shadernodebsdfdiffuse*", "render/shader_nodes/shader/diffuse.html#bpy-types-shadernodebsdfdiffuse"),
@@ -269,14 +370,22 @@ url_manual_mapping = (
("bpy.types.shadernodetexgradient*", "render/shader_nodes/textures/gradient.html#bpy-types-shadernodetexgradient"),
("bpy.types.shadernodetexmusgrave*", "render/shader_nodes/textures/musgrave.html#bpy-types-shadernodetexmusgrave"),
("bpy.types.shadernodevectorcurve*", "render/shader_nodes/vector/curves.html#bpy-types-shadernodevectorcurve"),
+ ("bpy.types.smoothgpencilmodifier*", "grease_pencil/modifiers/deform/smooth.html#bpy-types-smoothgpencilmodifier"),
+ ("bpy.types.spline.use_endpoint_u*", "modeling/curves/properties/active_spline.html#bpy-types-spline-use-endpoint-u"),
("bpy.types.userpreferencessystem*", "editors/preferences/system.html#bpy-types-userpreferencessystem"),
+ ("bpy.ops.curve.switch_direction*", "modeling/curves/editing/segments.html#bpy-ops-curve-switch-direction"),
+ ("bpy.ops.gpencil.duplicate_move*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-duplicate-move"),
+ ("bpy.ops.gpencil.stroke_arrange*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-arrange"),
("bpy.ops.mesh.bridge-edge-loops*", "modeling/meshes/editing/edges.html#bpy-ops-mesh-bridge-edge-loops"),
("bpy.ops.object.paths_calculate*", "animation/motion_paths.html#bpy-ops-object-paths-calculate"),
("bpy.ops.object.transform_apply*", "scene_layout/object/editing/transform/clear_apply.html#bpy-ops-object-transform-apply"),
("bpy.ops.outliner.lib_operation*", "files/linked_libraries.html#bpy-ops-outliner-lib-operation"),
("bpy.ops.screen.region_quadview*", "editors/3dview/navigate/views.html#bpy-ops-screen-region-quadview"),
("bpy.ops.uv.follow_active_quads*", "modeling/meshes/editing/uv/unwrapping/mapping_types.html#bpy-ops-uv-follow-active-quads"),
+ ("bpy.types.arraygpencilmodifier*", "grease_pencil/modifiers/generate/array.html#bpy-types-arraygpencilmodifier"),
+ ("bpy.types.buildgpencilmodifier*", "grease_pencil/modifiers/generate/build.html#bpy-types-buildgpencilmodifier"),
("bpy.types.colorbalancemodifier*", "video_editing/sequencer/properties/modifiers.html#bpy-types-colorbalancemodifier"),
+ ("bpy.types.colorgpencilmodifier*", "grease_pencil/modifiers/color/hue_saturation.html#bpy-types-colorgpencilmodifier"),
("bpy.types.compositornodefilter*", "compositing/types/filter/filter_node.html#bpy-types-compositornodefilter"),
("bpy.types.compositornodehuesat*", "compositing/types/color/hue_saturation.html#bpy-types-compositornodehuesat"),
("bpy.types.compositornodeidmask*", "compositing/types/converter/id_mask.html#bpy-types-compositornodeidmask"),
@@ -294,8 +403,10 @@ url_manual_mapping = (
("bpy.types.ffmpegsettings.audio*", "render/output/file_formats.html#bpy-types-ffmpegsettings-audio"),
("bpy.types.followpathconstraint*", "animation/constraints/relationship/follow_path.html#bpy-types-followpathconstraint"),
("bpy.types.gaussianblursequence*", "video_editing/sequencer/strips/effects/blur.html#bpy-types-gaussianblursequence"),
+ ("bpy.types.gpencillayer.opacity*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-opacity"),
("bpy.types.image.display_aspect*", "editors/image/view_tab.html#bpy-types-image-display-aspect"),
("bpy.types.limitscaleconstraint*", "animation/constraints/transform/limit_scale.html#bpy-types-limitscaleconstraint"),
+ ("bpy.types.materialgpencilstyle*", "grease_pencil/materials/index.html#bpy-types-materialgpencilstyle"),
("bpy.types.mesh.use_auto_smooth*", "modeling/meshes/structure.html#bpy-types-mesh-use-auto-smooth"),
("bpy.types.outflowfluidsettings*", "physics/fluid/types/flow.html#bpy-types-outflowfluidsettings"),
("bpy.types.scene.background_set*", "scene_layout/scene/properties.html#bpy-types-scene-background-set"),
@@ -318,16 +429,24 @@ url_manual_mapping = (
("bpy.types.unifiedpaintsettings*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-types-unifiedpaintsettings"),
("bpy.types.userpreferencesinput*", "editors/preferences/input.html#bpy-types-userpreferencesinput"),
("bpy.types.whitebalancemodifier*", "video_editing/sequencer/properties/modifiers.html#bpy-types-whitebalancemodifier"),
+ ("bpy.ops.curve.handle_type_set*", "modeling/curves/editing/control_points.html#bpy-ops-curve-handle-type-set"),
+ ("bpy.ops.curve.spline_type_set*", "modeling/curves/editing/curve.html#bpy-ops-curve-spline-type-set"),
+ ("bpy.ops.gpencil.move_to_layer*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-move-to-layer"),
+ ("bpy.ops.gpencil.stroke_sample*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-sample"),
+ ("bpy.ops.gpencil.stroke_smooth*", "grease_pencil/modes/edit/point_menu.html#bpy-ops-gpencil-stroke-smooth"),
("bpy.ops.mesh.smoothen_normals*", "modeling/meshes/editing/normals.html#bpy-ops-mesh-smoothen-normals"),
("bpy.ops.object.duplicate_move*", "scene_layout/object/editing/duplication.html#bpy-ops-object-duplicate-move"),
+ ("bpy.ops.object.hook_add_selob*", "modeling/meshes/editing/vertices.html#bpy-ops-object-hook-add-selob"),
("bpy.ops.object.select_by_type*", "scene_layout/object/selecting.html#bpy-ops-object-select-by-type"),
("bpy.ops.object.select_grouped*", "scene_layout/object/selecting.html#bpy-ops-object-select-grouped"),
("bpy.ops.object.select_pattern*", "scene_layout/object/selecting.html#bpy-ops-object-select-pattern"),
("bpy.ops.screen.repeat_history*", "interface/undo_redo.html#bpy-ops-screen-repeat-history"),
("bpy.ops.sequencer.refresh_all*", "video_editing/sequencer/navigating.html#bpy-ops-sequencer-refresh-all"),
+ ("bpy.ops.surface.primitive*add*", "modeling/surfaces/primitives.html#bpy-ops-surface-primitive-add"),
("bpy.ops.transform.edge_crease*", "modeling/meshes/editing/edges.html#bpy-ops-transform-edge-crease"),
("bpy.ops.uv.seams_from_islands*", "modeling/meshes/editing/uv/unwrapping/seams.html#bpy-ops-uv-seams-from-islands"),
("bpy.types.brush.icon_filepath*", "sculpt_paint/brush/display.html#bpy-types-brush-icon-filepath"),
+ ("bpy.types.brush.smooth_stroke*", "grease_pencil/modes/draw/tool_settings/brushes/draw_brush.html#bpy-types-brush-smooth-stroke"),
("bpy.types.camera.display_size*", "render/cameras.html#bpy-types-camera-display-size"),
("bpy.types.compositornodedblur*", "compositing/types/filter/directional_blur.html#bpy-types-compositornodedblur"),
("bpy.types.compositornodegamma*", "compositing/types/color/gamma.html#bpy-types-compositornodegamma"),
@@ -340,11 +459,13 @@ url_manual_mapping = (
("bpy.types.copyscaleconstraint*", "animation/constraints/transform/copy_scale.html#bpy-types-copyscaleconstraint"),
("bpy.types.cyclesworldsettings*", "render/cycles/world_settings.html#bpy-types-cyclesworldsettings"),
("bpy.types.domainfluidsettings*", "physics/fluid/types/domain.html#bpy-types-domainfluidsettings"),
+ ("bpy.types.hookgpencilmodifier*", "grease_pencil/modifiers/deform/hook.html#bpy-types-hookgpencilmodifier"),
("bpy.types.imageformatsettings*", "files/media/image_formats.html#bpy-types-imageformatsettings"),
("bpy.types.inflowfluidsettings*", "physics/fluid/types/flow.html#bpy-types-inflowfluidsettings"),
("bpy.types.kinematicconstraint*", "animation/constraints/tracking/ik_solver.html#bpy-types-kinematicconstraint"),
("bpy.types.mesh.use_paint_mask*", "sculpt_paint/brush/introduction.html#bpy-types-mesh-use-paint-mask"),
("bpy.types.movietrackingcamera*", "movie_clip/tracking/clip/properties/camera_data.html#bpy-types-movietrackingcamera"),
+ ("bpy.types.noisepencilmodifier*", "grease_pencil/modifiers/deform/noise.html#bpy-types-noisepencilmodifier"),
("bpy.types.object.display_type*", "scene_layout/object/properties/display.html#bpy-types-object-display-type"),
("bpy.types.particledupliweight*", "physics/particles/emitter/vertex_groups.html#bpy-types-particledupliweight"),
("bpy.types.poseboneconstraints*", "animation/armatures/posing/bone_constraints/index.html#bpy-types-poseboneconstraints"),
@@ -359,9 +480,14 @@ url_manual_mapping = (
("bpy.types.shadernodewireframe*", "render/shader_nodes/input/wireframe.html#bpy-types-shadernodewireframe"),
("bpy.types.smokedomainsettings*", "physics/smoke/types/domain.html#bpy-types-smokedomainsettings"),
("bpy.types.spacesequenceeditor*", "video_editing/index.html#bpy-types-spacesequenceeditor"),
+ ("bpy.types.spline.resolution_u*", "modeling/curves/properties/active_spline.html#bpy-types-spline-resolution-u"),
+ ("bpy.types.spline.use_bezier_u*", "modeling/curves/properties/active_spline.html#bpy-types-spline-use-bezier-u"),
+ ("bpy.types.spline.use_cyclic_u*", "modeling/curves/properties/active_spline.html#bpy-types-spline-use-cyclic-u"),
("bpy.types.stretchtoconstraint*", "animation/constraints/tracking/stretch_to.html#bpy-types-stretchtoconstraint"),
("bpy.types.texturenodecurvergb*", "editors/texture_node/types/color/rgb_curves.html#bpy-types-texturenodecurvergb"),
("bpy.types.texturenodevaltorgb*", "editors/texture_node/types/converter/rgb_to_bw.html#bpy-types-texturenodevaltorgb"),
+ ("bpy.types.timegpencilmodifier*", "grease_pencil/modifiers/deform/time_offset.html#bpy-types-timegpencilmodifier"),
+ ("bpy.types.tintgpencilmodifier*", "grease_pencil/modifiers/color/tint.html#bpy-types-tintgpencilmodifier"),
("bpy.types.transformconstraint*", "animation/constraints/transform/transformation.html#bpy-types-transformconstraint"),
("bpy.types.triangulatemodifier*", "modeling/modifiers/generate/triangulate.html#bpy-types-triangulatemodifier"),
("bpy.types.userpreferencesedit*", "editors/preferences/editing.html#bpy-types-userpreferencesedit"),
@@ -369,6 +495,12 @@ url_manual_mapping = (
("bpy.types.windowmanager.addon*", "editors/preferences/addons.html#bpy-types-windowmanager-addon"),
("bpy.ops.anim.keyframe_delete*", "animation/keyframes/editing.html#bpy-ops-anim-keyframe-delete"),
("bpy.ops.anim.keyframe_insert*", "animation/keyframes/editing.html#bpy-ops-anim-keyframe-insert"),
+ ("bpy.ops.console.autocomplete*", "editors/python_console.html#bpy-ops-console-autocomplete"),
+ ("bpy.ops.curve.dissolve_verts*", "modeling/curves/editing/curve.html#bpy-ops-curve-dissolve-verts"),
+ ("bpy.ops.curve.duplicate_move*", "modeling/curves/editing/curve.html#bpy-ops-curve-duplicate-move"),
+ ("bpy.ops.gpencil.extrude_move*", "grease_pencil/modes/edit/point_menu.html#bpy-ops-gpencil-extrude-move"),
+ ("bpy.ops.gpencil.stroke_merge*", "grease_pencil/modes/edit/point_menu.html#bpy-ops-gpencil-stroke-merge"),
+ ("bpy.ops.gpencil.stroke_split*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-stroke-split"),
("bpy.ops.mesh.average_normals*", "modeling/meshes/editing/normals.html#bpy-ops-mesh-average-normals"),
("bpy.ops.mesh.vertices_smooth*", "modeling/meshes/editing/transform/smooth.html#bpy-ops-mesh-vertices-smooth"),
("bpy.ops.node.read_viewlayers*", "interface/controls/nodes/editing.html#bpy-ops-node-read-viewlayers"),
@@ -392,11 +524,14 @@ url_manual_mapping = (
("bpy.types.compositornodemask*", "compositing/types/input/mask.html#bpy-types-compositornodemask"),
("bpy.types.compositornodemath*", "compositing/types/converter/math.html#bpy-types-compositornodemath"),
("bpy.types.compositornodetime*", "compositing/types/input/time.html#bpy-types-compositornodetime"),
+ ("bpy.types.curve.resolution_u*", "modeling/curves/properties/shape.html#bpy-types-curve-resolution-u"),
+ ("bpy.types.curve.resolution_v*", "modeling/surfaces/properties/shape.html#bpy-types-curve-resolution-v"),
("bpy.types.curvepaintsettings*", "modeling/curves/editing/other.html#bpy-types-curvepaintsettings"),
("bpy.types.fluidfluidsettings*", "physics/fluid/types/fluid_object.html#bpy-types-fluidfluidsettings"),
("bpy.types.fmodifiergenerator*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifiergenerator"),
("bpy.types.freestylelinestyle*", "render/freestyle/parameter_editor/line_style/index.html#bpy-types-freestylelinestyle"),
("bpy.types.gammacrosssequence*", "video_editing/sequencer/strips/transitions/cross.html#bpy-types-gammacrosssequence"),
+ ("bpy.types.gpencilsculptguide*", "grease_pencil/modes/draw/guides.html#bpy-types-gpencilsculptguide"),
("bpy.types.huecorrectmodifier*", "video_editing/sequencer/properties/modifiers.html#bpy-types-huecorrectmodifier"),
("bpy.types.imagepaint.stencil*", "sculpt_paint/texture_paint/tool_settings/mask.html#bpy-types-imagepaint-stencil"),
("bpy.types.meshdeformmodifier*", "modeling/modifiers/deform/mesh_deform.html#bpy-types-meshdeformmodifier"),
@@ -410,6 +545,7 @@ url_manual_mapping = (
("bpy.types.shadernodeemission*", "render/shader_nodes/shader/emission.html#bpy-types-shadernodeemission"),
("bpy.types.shadernodegeometry*", "render/shader_nodes/input/geometry.html#bpy-types-shadernodegeometry"),
("bpy.types.shadernodehairinfo*", "render/shader_nodes/input/hair_info.html#bpy-types-shadernodehairinfo"),
+ ("bpy.types.shadernodemaprange*", "render/shader_nodes/converter/map_range.html#bpy-types-shadernodemaprange"),
("bpy.types.shadernodergbcurve*", "render/shader_nodes/color/rgb_curves.html#bpy-types-shadernodergbcurve"),
("bpy.types.shadernodeseparate*", "render/shader_nodes/converter/combine_separate.html#bpy-types-shadernodeseparate"),
("bpy.types.shadernodetexbrick*", "render/shader_nodes/textures/brick.html#bpy-types-shadernodetexbrick"),
@@ -421,7 +557,14 @@ url_manual_mapping = (
("bpy.types.splineikconstraint*", "animation/constraints/tracking/spline_ik.html#bpy-types-splineikconstraint"),
("bpy.types.texturenodetexture*", "editors/texture_node/types/input/texture.html#bpy-types-texturenodetexture"),
("bpy.ops.anim.keyframe_clear*", "animation/keyframes/editing.html#bpy-ops-anim-keyframe-clear"),
+ ("bpy.ops.curve.cyclic_toggle*", "modeling/curves/editing/curve.html#bpy-ops-curve-cyclic-toggle"),
("bpy.ops.curve.primitive*add*", "modeling/curves/primitives.html#bpy-ops-curve-primitive-add"),
+ ("bpy.ops.curve.smooth_radius*", "modeling/curves/editing/control_points.html#bpy-ops-curve-smooth-radius"),
+ ("bpy.ops.curve.smooth_weight*", "modeling/curves/editing/control_points.html#bpy-ops-curve-smooth-weight"),
+ ("bpy.ops.gpencil.interpolate*", "grease_pencil/animation/tools.html#bpy-ops-gpencil-interpolate"),
+ ("bpy.ops.gpencil.stroke_flip*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-flip"),
+ ("bpy.ops.gpencil.stroke_join*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-join"),
+ ("bpy.ops.gpencil.stroke_trim*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-trim"),
("bpy.ops.mesh.duplicate_move*", "modeling/meshes/editing/duplicating/duplicate.html#bpy-ops-mesh-duplicate-move"),
("bpy.ops.mesh.extrude_region*", "modeling/meshes/editing/duplicating/extrude.html#bpy-ops-mesh-extrude-region"),
("bpy.ops.object.parent_clear*", "scene_layout/object/properties/relations/parents.html#bpy-ops-object-parent-clear"),
@@ -444,6 +587,8 @@ url_manual_mapping = (
("bpy.types.edgesplitmodifier*", "modeling/modifiers/generate/edge_split.html#bpy-types-edgesplitmodifier"),
("bpy.types.fmodifierenvelope*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifierenvelope"),
("bpy.types.freestylesettings*", "render/freestyle/view_layer.html#bpy-types-freestylesettings"),
+ ("bpy.types.gpencillayer.hide*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-hide"),
+ ("bpy.types.gpencillayer.lock*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-lock"),
("bpy.types.imagepaint.dither*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-types-imagepaint-dither"),
("bpy.types.mesh.texture_mesh*", "editors/uv/generated_uvs.html#bpy-types-mesh-texture-mesh"),
("bpy.types.mesh.use_mirror_x*", "modeling/meshes/editing/mesh_options.html#bpy-types-mesh-use-mirror-x"),
@@ -462,6 +607,7 @@ url_manual_mapping = (
("bpy.types.shadernodetexwave*", "render/shader_nodes/textures/wave.html#bpy-types-shadernodetexwave"),
("bpy.types.smokecollsettings*", "physics/smoke/types/collision.html#bpy-types-smokecollsettings"),
("bpy.types.smokeflowsettings*", "physics/smoke/types/flow_object.html#bpy-types-smokeflowsettings"),
+ ("bpy.types.spline.use_smooth*", "modeling/curves/properties/active_spline.html#bpy-types-spline-use-smooth"),
("bpy.types.texturenodebricks*", "editors/texture_node/types/patterns/bricks.html#bpy-types-texturenodebricks"),
("bpy.types.texturenodemixrgb*", "editors/texture_node/types/color/mix_rgb.html#bpy-types-texturenodemixrgb"),
("bpy.types.texturenodeoutput*", "editors/texture_node/types/output/output.html#bpy-types-texturenodeoutput"),
@@ -470,6 +616,8 @@ url_manual_mapping = (
("bpy.types.uvprojectmodifier*", "modeling/modifiers/modify/uv_project.html#bpy-types-uvprojectmodifier"),
("bpy.types.wireframemodifier*", "modeling/modifiers/generate/wireframe.html#bpy-types-wireframemodifier"),
("bpy.types.worldmistsettings*", "render/cycles/world_settings.html#bpy-types-worldmistsettings"),
+ ("bpy.ops.curve.extrude_move*", "modeling/curves/editing/control_points.html#bpy-ops-curve-extrude-move"),
+ ("bpy.ops.curve.make_segment*", "modeling/curves/editing/control_points.html#bpy-ops-curve-make-segment"),
("bpy.ops.mesh.loopcut_slide*", "modeling/meshes/editing/subdividing/loop.html#bpy-ops-mesh-loopcut-slide"),
("bpy.ops.mesh.merge_normals*", "modeling/meshes/editing/normals.html#bpy-ops-mesh-merge-normals"),
("bpy.ops.mesh.normals_tools*", "modeling/meshes/editing/normals.html#bpy-ops-mesh-normals-tools"),
@@ -504,6 +652,8 @@ url_manual_mapping = (
("bpy.types.sceneeevee.bloom*", "render/eevee/render_settings/bloom.html#bpy-types-sceneeevee-bloom"),
("bpy.types.scenerenderlayer*", "render/layers/layers.html#bpy-types-scenerenderlayer"),
("bpy.types.sequencemodifier*", "video_editing/sequencer/properties/modifiers.html#bpy-types-sequencemodifier"),
+ ("bpy.types.shaderfxcolorize*", "grease_pencil/visual_effects/colorize.html#bpy-types-shaderfxcolorize"),
+ ("bpy.types.shaderfxpixelate*", "grease_pencil/visual_effects/pixelate.html#bpy-types-shaderfxpixelate"),
("bpy.types.shadernodeinvert*", "render/shader_nodes/color/invert.html#bpy-types-shadernodeinvert"),
("bpy.types.shadernodemixrgb*", "render/shader_nodes/color/mix.html#bpy-types-shadernodemixrgb"),
("bpy.types.shadernodenormal*", "render/shader_nodes/vector/normal.html#bpy-types-shadernodenormal"),
@@ -519,6 +669,8 @@ url_manual_mapping = (
("bpy.types.subtractsequence*", "video_editing/sequencer/strips/effects/subtract.html#bpy-types-subtractsequence"),
("bpy.types.texturenodegroup*", "editors/texture_node/types/groups.html#bpy-types-texturenodegroup"),
("bpy.types.texturenodeimage*", "editors/texture_node/types/input/image.html#bpy-types-texturenodeimage"),
+ ("bpy.ops.curve.smooth_tilt*", "modeling/curves/editing/control_points.html#bpy-ops-curve-smooth-tilt"),
+ ("bpy.ops.gpencil.reproject*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-reproject"),
("bpy.ops.mesh.flip_normals*", "modeling/meshes/editing/normals.html#bpy-ops-mesh-flip-normals"),
("bpy.ops.object.lightprobe*", "render/eevee/lightprobes/index.html#bpy-ops-object-lightprobe"),
("bpy.ops.object.make_links*", "scene_layout/object/editing/duplication.html#bpy-ops-object-make-links"),
@@ -552,6 +704,7 @@ url_manual_mapping = (
("bpy.types.rigidbodyobject*", "physics/rigid_body/index.html#bpy-types-rigidbodyobject"),
("bpy.types.sceneeevee.gtao*", "render/eevee/render_settings/ambient_occlusion.html#bpy-types-sceneeevee-gtao"),
("bpy.types.shadernodebevel*", "render/shader_nodes/input/bevel.html#bpy-types-shadernodebevel"),
+ ("bpy.types.shadernodeclamp*", "render/shader_nodes/converter/clamp.html#bpy-types-shadernodeclamp"),
("bpy.types.shadernodegamma*", "render/shader_nodes/color/gamma.html#bpy-types-shadernodegamma"),
("bpy.types.shadernodegroup*", "render/shader_nodes/groups.html#bpy-types-shadernodegroup"),
("bpy.types.shadernodeuvmap*", "render/shader_nodes/input/uv_map.html#bpy-types-shadernodeuvmap"),
@@ -562,6 +715,10 @@ url_manual_mapping = (
("bpy.types.subsurfmodifier*", "modeling/modifiers/generate/subdivision_surface.html#bpy-types-subsurfmodifier"),
("bpy.types.texturenodemath*", "editors/texture_node/types/converter/math.html#bpy-types-texturenodemath"),
("bpy.types.userpreferences*", "editors/preferences/index.html#bpy-types-userpreferences"),
+ ("bpy.ops.curve.select_row*", "modeling/surfaces/selecting.html#bpy-ops-curve-select-row"),
+ ("bpy.ops.curve.tilt_clear*", "modeling/curves/editing/control_points.html#bpy-ops-curve-tilt-clear"),
+ ("bpy.ops.curve.vertex_add*", "modeling/curves/editing/other.html#bpy-ops-curve-vertex-add"),
+ ("bpy.ops.gpencil.dissolve*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-dissolve"),
("bpy.ops.graph.frame_jump*", "editors/graph_editor/fcurves/properties.html#bpy-ops-graph-frame-jump"),
("bpy.ops.mesh.edge_rotate*", "modeling/meshes/editing/edges.html#bpy-ops-mesh-edge-rotate"),
("bpy.ops.object.hide_view*", "scene_layout/object/editing/introduction.html#bpy-ops-object-hide-view"),
@@ -586,9 +743,11 @@ url_manual_mapping = (
("bpy.types.rigidbodyworld*", "physics/rigid_body/world.html#bpy-types-rigidbodyworld"),
("bpy.types.sceneeevee.ssr*", "render/eevee/render_settings/screen_space_reflections.html#bpy-types-sceneeevee-ssr"),
("bpy.types.sceneeevee.sss*", "render/eevee/render_settings/subsurface_scattering.html#bpy-types-sceneeevee-sss"),
+ ("bpy.types.shaderfxshadow*", "grease_pencil/visual_effects/shadow.html#bpy-types-shaderfxshadow"),
("bpy.types.shadernodebump*", "render/shader_nodes/vector/bump.html#bpy-types-shadernodebump"),
("bpy.types.shadernodemath*", "render/shader_nodes/converter/math.html#bpy-types-shadernodemath"),
("bpy.types.smoothmodifier*", "modeling/modifiers/deform/smooth.html#bpy-types-smoothmodifier"),
+ ("bpy.types.spline.order_u*", "modeling/curves/properties/active_spline.html#bpy-types-spline-order-u"),
("bpy.types.timelinemarker*", "animation/markers.html#bpy-types-timelinemarker"),
("bpy.types.usersolidlight*", "editors/preferences/lights.html#bpy-types-usersolidlight"),
("bpy.types.uvwarpmodifier*", "modeling/modifiers/modify/uv_warp.html#bpy-types-uvwarpmodifier"),
@@ -596,6 +755,7 @@ url_manual_mapping = (
("bpy.types.walknavigation*", "editors/3dview/navigate/walk_fly.html#bpy-types-walknavigation"),
("bpy.ops.*.select_circle*", "interface/selecting.html#bpy-ops-select-circle"),
("bpy.ops.anim.keying_set*", "animation/keyframes/keying_sets.html#bpy-ops-anim-keying-set"),
+ ("bpy.ops.curve.subdivide*", "modeling/curves/editing/segments.html#bpy-ops-curve-subdivide"),
("bpy.ops.ed.undo_history*", "interface/undo_redo.html#bpy-ops-ed-undo-history"),
("bpy.ops.mesh.edge_split*", "modeling/meshes/editing/edges.html#bpy-ops-mesh-edge-split"),
("bpy.ops.mesh.mark_sharp*", "modeling/meshes/editing/edges.html#bpy-ops-mesh-mark-sharp"),
@@ -606,6 +766,7 @@ url_manual_mapping = (
("bpy.ops.uv.cube_project*", "modeling/meshes/editing/uv/unwrapping/mapping_types.html#bpy-ops-uv-cube-project"),
("bpy.ops.uv.pack_islands*", "modeling/meshes/editing/uv/layout.html#bpy-ops-uv-pack-islands"),
("bpy.ops.wm.app_template*", "advanced/app_templates.html#bpy-ops-wm-app-template"),
+ ("bpy.ops.wm.batch_rename*", "files/blend/rename.html#bpy-ops-wm-batch-rename"),
("bpy.ops.wm.redraw_timer*", "advanced/operators.html#bpy-ops-wm-redraw-timer"),
("bpy.types.*light.shadow*", "render/eevee/lighting.html#bpy-types-light-shadow"),
("bpy.types.armaturebones*", "animation/armatures/bones/index.html#bpy-types-armaturebones"),
@@ -634,6 +795,8 @@ url_manual_mapping = (
("bpy.types.scenesequence*", "video_editing/sequencer/strips/scene.html#bpy-types-scenesequence"),
("bpy.types.screwmodifier*", "modeling/modifiers/generate/screw.html#bpy-types-screwmodifier"),
("bpy.types.sequenceproxy*", "video_editing/sequencer/properties/proxy_cache.html#bpy-types-sequenceproxy"),
+ ("bpy.types.shaderfxlight*", "grease_pencil/visual_effects/light.html#bpy-types-shaderfxlight"),
+ ("bpy.types.shaderfxswirl*", "grease_pencil/visual_effects/swirl.html#bpy-types-shaderfxswirl"),
("bpy.types.shadernodergb*", "render/shader_nodes/input/rgb.html#bpy-types-shadernodergb"),
("bpy.types.smokemodifier*", "physics/smoke/index.html#bpy-types-smokemodifier"),
("bpy.types.soundsequence*", "video_editing/sequencer/strips/sound.html#bpy-types-soundsequence"),
@@ -642,16 +805,24 @@ url_manual_mapping = (
("bpy.types.stuccitexture*", "render/materials/legacy_textures/types/stucci.html#bpy-types-stuccitexture"),
("bpy.types.windowmanager*", "interface/index.html#bpy-types-windowmanager"),
("bpy.ops.*.select_lasso*", "interface/selecting.html#bpy-ops-select-lasso"),
+ ("bpy.ops.curve.decimate*", "modeling/curves/editing/curve.html#bpy-ops-curve-decimate"),
+ ("bpy.ops.curve.separate*", "modeling/curves/editing/curve.html#bpy-ops-curve-separate"),
+ ("bpy.ops.gpencil.delete*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-delete"),
+ ("bpy.ops.gpencil.select*", "grease_pencil/selecting.html#bpy-ops-gpencil-select"),
("bpy.ops.mesh.mark_seam*", "modeling/meshes/editing/edges.html#bpy-ops-mesh-mark-seam"),
("bpy.ops.mesh.subdivide*", "modeling/meshes/editing/subdividing/subdivide.html#bpy-ops-mesh-subdivide"),
("bpy.ops.object.convert*", "scene_layout/object/editing/introduction.html#bpy-ops-object-convert"),
+ ("bpy.ops.object.gpencil*", "grease_pencil/index.html#bpy-ops-object-gpencil"),
("bpy.ops.object.speaker*", "render/output/audio/speaker.html#bpy-ops-object-speaker"),
("bpy.ops.transform.bend*", "modeling/meshes/editing/transform/bend.html#bpy-ops-transform-bend"),
+ ("bpy.ops.transform.tilt*", "modeling/curves/editing/control_points.html#bpy-ops-transform-tilt"),
+ ("bpy.ops.wm.search_menu*", "interface/controls/templates/operator_search.html#bpy-ops-wm-search-menu"),
("bpy.types.bakesettings*", "render/cycles/baking.html#bpy-types-bakesettings"),
("bpy.types.blendtexture*", "render/materials/legacy_textures/types/blend.html#bpy-types-blendtexture"),
("bpy.types.castmodifier*", "modeling/modifiers/deform/cast.html#bpy-types-castmodifier"),
("bpy.types.colormanaged*", "render/color_management.html#bpy-types-colormanaged"),
("bpy.types.glowsequence*", "video_editing/sequencer/strips/effects/glow.html#bpy-types-glowsequence"),
+ ("bpy.types.gpencillayer*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer"),
("bpy.types.hookmodifier*", "modeling/modifiers/deform/hooks.html#bpy-types-hookmodifier"),
("bpy.types.latticepoint*", "animation/lattice.html#bpy-types-latticepoint"),
("bpy.types.magictexture*", "render/materials/legacy_textures/types/magic.html#bpy-types-magictexture"),
@@ -664,6 +835,10 @@ url_manual_mapping = (
("bpy.types.object.scale*", "scene_layout/object/properties/transforms.html#bpy-types-object-scale"),
("bpy.types.particleedit*", "physics/particles/mode.html#bpy-types-particleedit"),
("bpy.types.scene.camera*", "scene_layout/scene/properties.html#bpy-types-scene-camera"),
+ ("bpy.types.shaderfxblur*", "grease_pencil/visual_effects/blur.html#bpy-types-shaderfxblur"),
+ ("bpy.types.shaderfxflip*", "grease_pencil/visual_effects/flip.html#bpy-types-shaderfxflip"),
+ ("bpy.types.shaderfxglow*", "grease_pencil/visual_effects/glow.html#bpy-types-shaderfxglow"),
+ ("bpy.types.shaderfxwave*", "grease_pencil/visual_effects/wave_distortion.html#bpy-types-shaderfxwave"),
("bpy.types.skinmodifier*", "modeling/modifiers/generate/skin.html#bpy-types-skinmodifier"),
("bpy.types.spaceconsole*", "editors/python_console.html#bpy-types-spaceconsole"),
("bpy.types.textsequence*", "video_editing/sequencer/strips/text.html#bpy-types-textsequence"),
@@ -673,7 +848,9 @@ url_manual_mapping = (
("bpy.types.warpmodifier*", "modeling/modifiers/deform/warp.html#bpy-types-warpmodifier"),
("bpy.types.wavemodifier*", "modeling/modifiers/deform/wave.html#bpy-types-wavemodifier"),
("bpy.types.wipesequence*", "video_editing/sequencer/strips/transitions/wipe.html#bpy-types-wipesequence"),
+ ("bpy.ops.gpencil.paste*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-paste"),
("bpy.ops.image.project*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-ops-image-project"),
+ ("bpy.ops.mesh.decimate*", "modeling/meshes/editing/cleanup.html#bpy-ops-mesh-decimate"),
("bpy.ops.object.*clear*", "scene_layout/object/editing/transform/clear_apply.html#bpy-ops-object-clear"),
("bpy.ops.object.delete*", "scene_layout/object/editing/introduction.html#bpy-ops-object-delete"),
("bpy.ops.screen.header*", "interface/window_system/regions.html#bpy-ops-screen-header"),
@@ -690,11 +867,16 @@ url_manual_mapping = (
("bpy.types.particlekey*", "physics/particles/emitter/physics/keyed.html#bpy-types-particlekey"),
("bpy.types.posebone.ik*", "animation/armatures/posing/bone_constraints/inverse_kinematics/introduction.html#bpy-types-posebone-ik"),
("bpy.types.renderlayer*", "render/layers/layers.html#bpy-types-renderlayer"),
+ ("bpy.types.shaderfxrim*", "grease_pencil/visual_effects/rim.html#bpy-types-shaderfxrim"),
("bpy.types.spaceview3d*", "editors/3dview/index.html#bpy-types-spaceview3d"),
("bpy.types.uipopupmenu*", "interface/controls/buttons/menus.html#bpy-types-uipopupmenu"),
("bpy.types.vertexpaint*", "sculpt_paint/vertex_paint/index.html#bpy-types-vertexpaint"),
("bpy.types.woodtexture*", "render/materials/legacy_textures/types/wood.html#bpy-types-woodtexture"),
("bpy.ops.*.select_box*", "interface/selecting.html#bpy-ops-select-box"),
+ ("bpy.ops.curve.delete*", "modeling/curves/editing/curve.html#bpy-ops-curve-delete"),
+ ("bpy.ops.curve.reveal*", "modeling/curves/editing/curve.html#bpy-ops-curve-reveal"),
+ ("bpy.ops.curve.smooth*", "modeling/curves/editing/control_points.html#bpy-ops-curve-smooth"),
+ ("bpy.ops.gpencil.copy*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-copy"),
("bpy.ops.object.align*", "scene_layout/object/editing/transform/tools.html#bpy-ops-object-align"),
("bpy.ops.object.empty*", "modeling/empties.html#bpy-ops-object-empty"),
("bpy.ops.object.quick*", "physics/introduction.html#bpy-ops-object-quick"),
@@ -713,6 +895,7 @@ url_manual_mapping = (
("bpy.types.renderview*", "render/output/multiview/index.html#bpy-types-renderview"),
("bpy.types.sceneeevee*", "render/eevee/index.html#bpy-types-sceneeevee"),
("bpy.types.vectorfont*", "modeling/texts/index.html#bpy-types-vectorfont"),
+ ("bpy.ops.curve.split*", "modeling/curves/editing/curve.html#bpy-ops-curve-split"),
("bpy.ops.mesh.bisect*", "modeling/meshes/editing/subdividing/bisect.html#bpy-ops-mesh-bisect"),
("bpy.ops.object.join*", "scene_layout/object/editing/introduction.html#bpy-ops-object-join"),
("bpy.ops.object.text*", "modeling/texts/index.html#bpy-ops-object-text"),
@@ -734,6 +917,8 @@ url_manual_mapping = (
("bpy.ops.collection*", "scene_layout/collections/collections.html#bpy-ops-collection"),
("bpy.ops.constraint*", "animation/constraints/index.html#bpy-ops-constraint"),
("bpy.ops.curve.draw*", "modeling/curves/editing/other.html#bpy-ops-curve-draw"),
+ ("bpy.ops.curve.hide*", "modeling/curves/editing/curve.html#bpy-ops-curve-hide"),
+ ("bpy.ops.curve.spin*", "modeling/surfaces/editing/surface.html#bpy-ops-curve-spin"),
("bpy.ops.mesh.knife*", "modeling/meshes/editing/subdividing/knife.html#bpy-ops-mesh-knife"),
("bpy.ops.mesh.noise*", "modeling/meshes/editing/transform/noise.html#bpy-ops-mesh-noise"),
("bpy.ops.mesh.screw*", "modeling/meshes/editing/duplicating/screw.html#bpy-ops-mesh-screw"),
@@ -751,6 +936,7 @@ url_manual_mapping = (
("bpy.types.nodetree*", "interface/controls/nodes/parts.html#bpy-types-nodetree"),
("bpy.types.particle*", "physics/particles/index.html#bpy-types-particle"),
("bpy.types.sequence*", "video_editing/index.html#bpy-types-sequence"),
+ ("bpy.types.shaderfx*", "grease_pencil/visual_effects/index.html#bpy-types-shaderfx"),
("bpy.types.shapekey*", "animation/shape_keys/index.html#bpy-types-shapekey"),
("bpy.types.spacenla*", "editors/nla/index.html#bpy-types-spacenla"),
("bpy.types.sunlight*", "render/lights/light_object.html#bpy-types-sunlight"),
@@ -758,6 +944,7 @@ url_manual_mapping = (
("bpy.ops.rigidbody*", "physics/rigid_body/index.html#bpy-ops-rigidbody"),
("bpy.ops.sequencer*", "video_editing/index.html#bpy-ops-sequencer"),
("bpy.ops.transform*", "scene_layout/object/editing/transform/index.html#bpy-ops-transform"),
+ ("bpy.ops.uv.select*", "editors/uv/selecting.html#bpy-ops-uv-select"),
("bpy.ops.uv.stitch*", "modeling/meshes/editing/uv/layout.html#bpy-ops-uv-stitch"),
("bpy.ops.uv.unwrap*", "modeling/meshes/editing/uv/unwrapping/mapping_types.html#bpy-ops-uv-unwrap"),
("bpy.types.animviz*", "animation/motion_paths.html#bpy-types-animviz"),
@@ -783,6 +970,7 @@ url_manual_mapping = (
("bpy.types.render*", "render/index.html#bpy-types-render"),
("bpy.types.sculpt*", "sculpt_paint/sculpting/index.html#bpy-types-sculpt"),
("bpy.types.shader*", "render/shader_nodes/shader/index.html#bpy-types-shader"),
+ ("bpy.types.spline*", "modeling/curves/properties/active_spline.html#bpy-types-spline"),
("bpy.types.window*", "interface/index.html#bpy-types-window"),
("bpy.ops.buttons*", "interface/index.html#bpy-ops-buttons"),
("bpy.ops.console*", "editors/python_console.html#bpy-ops-console"),
@@ -795,6 +983,7 @@ url_manual_mapping = (
("bpy.ops.surface*", "modeling/surfaces/index.html#bpy-ops-surface"),
("bpy.ops.texture*", "render/materials/legacy_textures/index.html#bpy-ops-texture"),
("bpy.ops.uv.weld*", "modeling/meshes/editing/uv/layout.html#bpy-ops-uv-weld"),
+ ("bpy.ops.wm.tool*", "interface/tool_system.html#bpy-ops-wm-tool"),
("bpy.types.addon*", "editors/preferences/addons.html#bpy-types-addon"),
("bpy.types.brush*", "sculpt_paint/brush/brush.html#bpy-types-brush"),
("bpy.types.curve*", "modeling/curves/index.html#bpy-types-curve"),
diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py
index 2ff6c3fc1b0..202fd865723 100644
--- a/release/scripts/modules/rna_prop_ui.py
+++ b/release/scripts/modules/rna_prop_ui.py
@@ -231,13 +231,15 @@ def draw(layout, context, context_member, property_type, use_edit=True):
if rna_item.id_data.library is not None:
use_edit = False
+ is_lib_override = rna_item.id_data.override_library and rna_item.id_data.override_library.reference
assert(isinstance(rna_item, property_type))
items = rna_item.items()
items.sort()
- if use_edit:
+ # TODO: Allow/support adding new custom props to overrides.
+ if use_edit and not is_lib_override:
row = layout.row()
props = row.operator("wm.properties_add", text="Add")
props.data_path = context_member
@@ -303,6 +305,9 @@ def draw(layout, context, context_member, property_type, use_edit=True):
if use_edit:
row = split.row(align=True)
+ # Do not allow editing of overridden properties (we cannot use a poll function of the operators here
+ # since they's have no access to the specific property...).
+ row.enabled = not(is_lib_override and key in rna_item.id_data.override_library.reference)
if not is_rna:
props = row.operator("wm.properties_edit", text="Edit")
assign_props(props, val_draw, key)
diff --git a/release/scripts/presets/interface_theme/blender_light.xml b/release/scripts/presets/interface_theme/blender_light.xml
index 49b01ec3309..dee7d2d2c59 100644
--- a/release/scripts/presets/interface_theme/blender_light.xml
+++ b/release/scripts/presets/interface_theme/blender_light.xml
@@ -22,16 +22,17 @@
icon_object_data="#00d4a3ff"
icon_modifier="#84b8ffff"
icon_shading="#ea7581ff"
+ icon_folder="#e3c16eff"
icon_border_intensity="0.85"
>
<wcol_regular>
<ThemeWidgetColors
- outline="#999999"
- inner="#c0c0c0ff"
+ outline="#b8b8b8"
+ inner="#dbdbdbff"
inner_sel="#668cccff"
item="#191919ff"
text="#1a1a1a"
- text_sel="#000000"
+ text_sel="#ffffff"
show_shaded="FALSE"
shadetop="0"
shadedown="-5"
@@ -41,7 +42,7 @@
</wcol_regular>
<wcol_tool>
<ThemeWidgetColors
- outline="#c7c7c7"
+ outline="#b8b8b8"
inner="#dbdbdbff"
inner_sel="#5680c2ff"
item="#191919ff"
@@ -56,7 +57,7 @@
</wcol_tool>
<wcol_toolbar_item>
<ThemeWidgetColors
- outline="#808080"
+ outline="#363636"
inner="#434343ff"
inner_sel="#5680c2ff"
item="#ffffff8f"
@@ -71,11 +72,11 @@
</wcol_toolbar_item>
<wcol_radio>
<ThemeWidgetColors
- outline="#373737"
- inner="#595959ff"
+ outline="#3b3b3b"
+ inner="#3b3b3bff"
inner_sel="#5680c2e6"
item="#ffffffff"
- text="#e6e6e6"
+ text="#d9d9d9"
text_sel="#ffffff"
show_shaded="FALSE"
shadetop="5"
@@ -92,7 +93,7 @@
item="#5680c2ff"
text="#dddddd"
text_sel="#ffffff"
- show_shaded="FALSE"
+ show_shaded="TRUE"
shadetop="-8"
shadedown="0"
roundness="0.4"
@@ -102,14 +103,14 @@
<wcol_option>
<ThemeWidgetColors
outline="#373737"
- inner="#666666ff"
- inner_sel="#5680c2e6"
+ inner="#3c3c3cff"
+ inner_sel="#5680c2ff"
item="#ffffffff"
text="#1a1a1a"
text_sel="#000000"
- show_shaded="FALSE"
- shadetop="0"
- shadedown="-15"
+ show_shaded="TRUE"
+ shadetop="-5"
+ shadedown="0"
roundness="0.4"
>
</ThemeWidgetColors>
@@ -137,8 +138,8 @@
item="#80b1ffff"
text="#1a1a1a"
text_sel="#ffffff"
- show_shaded="FALSE"
- shadetop="-10"
+ show_shaded="TRUE"
+ shadetop="3"
shadedown="0"
roundness="0.4"
>
@@ -146,14 +147,14 @@
</wcol_num>
<wcol_numslider>
<ThemeWidgetColors
- outline="#999999"
- inner="#3c3c3cff"
- inner_sel="#333333ff"
- item="#5680c2ff"
- text="#ffffff"
- text_sel="#ffffff"
+ outline="#b8b8b8"
+ inner="#999999ff"
+ inner_sel="#999999ff"
+ item="#e6e6e6ff"
+ text="#1a1a1a"
+ text_sel="#000000"
show_shaded="TRUE"
- shadetop="-4"
+ shadetop="-3"
shadedown="0"
roundness="0.4"
>
@@ -206,12 +207,12 @@
</wcol_pulldown>
<wcol_menu_back>
<ThemeWidgetColors
- outline="#19191a"
- inner="#1f1f1fef"
- inner_sel="#585858ff"
+ outline="#a6a6a6"
+ inner="#c0c0c0ff"
+ inner_sel="#cdcdcdff"
item="#727272ff"
- text="#a5a5a5"
- text_sel="#ffffff"
+ text="#1a1a1a"
+ text_sel="#1a1a1a"
show_shaded="FALSE"
shadetop="25"
shadedown="-20"
@@ -255,7 +256,7 @@
inner="#00000000"
inner_sel="#5680c2e6"
item="#ffffff8f"
- text="#e6e6e6"
+ text="#1a1a1a"
text_sel="#ffffff"
show_shaded="FALSE"
shadetop="38"
@@ -298,8 +299,8 @@
<ThemeWidgetColors
outline="#e6e6e6"
inner="#00000000"
- inner_sel="#446599ff"
- item="#80b1ffff"
+ inner_sel="#808080ff"
+ item="#1a1a1aff"
text="#1a1a1a"
text_sel="#ffffff"
show_shaded="FALSE"
@@ -542,7 +543,7 @@
button_text="#000000"
button_text_hi="#ffffff"
navigation_bar="#00000000"
- execution_buts="#00000000"
+ execution_buts="#999999e6"
tab_active="#6697e6"
tab_inactive="#cccccc"
tab_back="#999999ff"
diff --git a/release/scripts/presets/keyconfig/blender.py b/release/scripts/presets/keyconfig/blender.py
index 60684be9163..8a7689d6d60 100644
--- a/release/scripts/presets/keyconfig/blender.py
+++ b/release/scripts/presets/keyconfig/blender.py
@@ -5,15 +5,15 @@ from bpy.props import (
EnumProperty,
)
-dirname, filename = os.path.split(__file__)
-idname = os.path.splitext(filename)[0]
+DIRNAME, FILENAME = os.path.split(__file__)
+IDNAME = os.path.splitext(FILENAME)[0]
def update_fn(_self, _context):
load()
class Prefs(bpy.types.KeyConfigPreferences):
- bl_idname = idname
+ bl_idname = IDNAME
select_mouse: EnumProperty(
name="Select Mouse",
@@ -154,7 +154,7 @@ class Prefs(bpy.types.KeyConfigPreferences):
col.prop(self, "use_v3d_shade_ex_pie")
-blender_default = bpy.utils.execfile(os.path.join(dirname, "keymap_data", "blender_default.py"))
+blender_default = bpy.utils.execfile(os.path.join(DIRNAME, "keymap_data", "blender_default.py"))
def load():
@@ -163,7 +163,7 @@ def load():
from bl_keymap_utils.io import keyconfig_init_from_data
prefs = context.preferences
- kc = context.window_manager.keyconfigs.new(idname)
+ kc = context.window_manager.keyconfigs.new(IDNAME)
kc_prefs = kc.preferences
keyconfig_data = blender_default.generate_keymaps(
diff --git a/release/scripts/presets/keyconfig/blender_27x.py b/release/scripts/presets/keyconfig/blender_27x.py
index 052f5dd706a..4ce77f46213 100644
--- a/release/scripts/presets/keyconfig/blender_27x.py
+++ b/release/scripts/presets/keyconfig/blender_27x.py
@@ -4,15 +4,15 @@ from bpy.props import (
EnumProperty,
)
-dirname, filename = os.path.split(__file__)
-idname = os.path.splitext(filename)[0]
+DIRNAME, FILENAME = os.path.split(__file__)
+IDNAME = os.path.splitext(FILENAME)[0]
def update_fn(_self, _context):
load()
class Prefs(bpy.types.KeyConfigPreferences):
- bl_idname = idname
+ bl_idname = IDNAME
select_mouse: EnumProperty(
name="Select Mouse",
@@ -39,7 +39,7 @@ class Prefs(bpy.types.KeyConfigPreferences):
split.column()
-blender_default = bpy.utils.execfile(os.path.join(dirname, "keymap_data", "blender_default.py"))
+blender_default = bpy.utils.execfile(os.path.join(DIRNAME, "keymap_data", "blender_default.py"))
def load():
from sys import platform
@@ -47,7 +47,7 @@ def load():
from bl_keymap_utils.io import keyconfig_init_from_data
prefs = context.preferences
- kc = context.window_manager.keyconfigs.new(idname)
+ kc = context.window_manager.keyconfigs.new(IDNAME)
kc_prefs = kc.preferences
keyconfig_data = blender_default.generate_keymaps(
diff --git a/release/scripts/presets/keyconfig/industry_compatible.py b/release/scripts/presets/keyconfig/industry_compatible.py
index 3f9ce98c7e5..09a43452e93 100644
--- a/release/scripts/presets/keyconfig/industry_compatible.py
+++ b/release/scripts/presets/keyconfig/industry_compatible.py
@@ -1,52 +1,18 @@
import os
import bpy
-# ------------------------------------------------------------------------------
-# Operators needed by this keymap to function
-
-# Selection Modes
-
-class IC_KEYMAP_OT_mesh_select_mode(bpy.types.Operator):
- bl_idname = "ic_keymap.mesh_select_mode"
- bl_label = "Switch to Vertex, Edge or Face Mode from any mode"
- bl_options = {'UNDO'}
-
- type: bpy.props.EnumProperty(
- name="Mode",
- items=(
- ('VERT', "Vertex", "Switcth to Vertex Mode From any Mode"),
- ('EDGE', "Edge", "Switcth to Edge Mode From any Mode"),
- ('FACE', "Face", "Switcth to Face Mode From any Mode"),
- ),
- )
-
- @classmethod
- def poll(cls, context):
- return (context.active_object is not None) and (context.object.type == 'MESH')
-
- def execute(self, context):
- bpy.ops.object.mode_set(mode='EDIT')
- bpy.ops.mesh.select_mode(type=self.type)
-
- return{'FINISHED'}
-
-
-classes = (
- IC_KEYMAP_OT_mesh_select_mode,
-)
-
# ------------------------------------------------------------------------------
# Keymap
-dirname, filename = os.path.split(__file__)
-idname = os.path.splitext(filename)[0]
+DIRNAME, FILENAME = os.path.split(__file__)
+IDNAME = os.path.splitext(FILENAME)[0]
def update_fn(_self, _context):
load()
-industry_compatible = bpy.utils.execfile(os.path.join(dirname, "keymap_data", "industry_compatible_data.py"))
+industry_compatible = bpy.utils.execfile(os.path.join(DIRNAME, "keymap_data", "industry_compatible_data.py"))
def load():
@@ -55,7 +21,7 @@ def load():
prefs = bpy.context.preferences
- kc = bpy.context.window_manager.keyconfigs.new(idname)
+ kc = bpy.context.window_manager.keyconfigs.new(IDNAME)
params = industry_compatible.Params(use_mouse_emulate_3_button=prefs.inputs.use_mouse_emulate_3_button)
keyconfig_data = industry_compatible.generate_keymaps(params)
@@ -66,8 +32,4 @@ def load():
keyconfig_init_from_data(kc, keyconfig_data)
if __name__ == "__main__":
- # XXX, no way to unregister
- for cls in classes:
- bpy.utils.register_class(cls)
-
load()
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 203b9ced317..ddf7accc2b2 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -409,6 +409,7 @@ def km_window(params):
items.extend([
("wm.doc_view_manual_ui_context", {"type": 'F1', "value": 'PRESS'}, None),
op_panel("TOPBAR_PT_name", {"type": 'F2', "value": 'PRESS'}, [("keep_open", False)]),
+ ("wm.batch_rename", {"type": 'F2', "value": 'PRESS', "alt": True}, None),
("wm.search_menu", {"type": 'F3', "value": 'PRESS'}, None),
op_menu("TOPBAR_MT_file_context_menu", {"type": 'F4', "value": 'PRESS'}),
])
@@ -1058,9 +1059,10 @@ def km_view3d(params):
("view3d.view_axis", {"type": 'NDOF_BUTTON_TOP', "value": 'PRESS', "shift": True},
{"properties": [("type", 'TOP'), ("align_active", True)]}),
# Selection.
- *(("view3d.select",
- {"type": params.select_mouse, "value": params.select_mouse_value, **{m: True for m in mods}},
- {"properties": [(c, True) for c in props]},
+ *((
+ "view3d.select",
+ {"type": params.select_mouse, "value": params.select_mouse_value, **{m: True for m in mods}},
+ {"properties": [(c, True) for c in props]},
) for props, mods in (
(("deselect_all",) if not params.legacy else (), ()),
(("toggle",), ("shift",)),
@@ -1585,6 +1587,11 @@ def km_image(params):
("image.clear_render_border", {"type": 'B', "value": 'PRESS', "ctrl": True, "alt": True}, None),
])
+ if params.legacy:
+ items.extend([
+ ("image.view_center_cursor", {"type": 'HOME', "value": 'PRESS', "alt": True}, None),
+ ])
+
return keymap
@@ -1761,7 +1768,7 @@ def km_info(params):
return keymap
-def km_file_browser(_params):
+def km_file_browser(params):
items = []
keymap = (
"File Browser",
@@ -1770,6 +1777,11 @@ def km_file_browser(_params):
)
items.extend([
+ *_template_space_region_type_toggle(
+ toolbar_key={"type": 'T', "value": 'PRESS'},
+ ),
+ ("screen.region_toggle", {"type": 'N', "value": 'PRESS'},
+ {"properties": [("region_type", 'TOOL_PROPS')]}),
("file.parent", {"type": 'UP_ARROW', "value": 'PRESS', "alt": True}, None),
("file.previous", {"type": 'LEFT_ARROW', "value": 'PRESS', "alt": True}, None),
("file.next", {"type": 'RIGHT_ARROW', "value": 'PRESS', "alt": True}, None),
@@ -1779,10 +1791,23 @@ def km_file_browser(_params):
("file.next", {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True}, None),
("wm.context_toggle", {"type": 'H', "value": 'PRESS'},
{"properties": [("data_path", 'space_data.params.show_hidden')]}),
- ("file.directory_new", {"type": 'I', "value": 'PRESS'}, None),
+ ("file.directory_new", {"type": 'I', "value": 'PRESS'},
+ {"properties": [("confirm", False)]}),
("file.smoothscroll", {"type": 'TIMER1', "value": 'ANY', "any": True}, None),
- ("file.bookmark_toggle", {"type": 'T', "value": 'PRESS'}, None),
("file.bookmark_add", {"type": 'B', "value": 'PRESS', "ctrl": True}, None),
+ ("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS'},
+ {"properties": [("increment", 1)]}),
+ ("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "shift": True},
+ {"properties": [("increment", 10)]}),
+ ("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True},
+ {"properties": [("increment", 100)]}),
+ ("file.filenum", {"type": 'NUMPAD_MINUS', "value": 'PRESS'},
+ {"properties": [("increment", -1)]}),
+ ("file.filenum", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "shift": True},
+ {"properties": [("increment", -10)]}),
+ ("file.filenum", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True},
+ {"properties": [("increment", -100)]}),
+ op_menu("FILEBROWSER_MT_context_menu", params.context_menu_event),
])
return keymap
@@ -1800,17 +1825,13 @@ def km_file_browser_main(params):
("file.execute", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'},
{"properties": [("need_active", True)]}),
("file.refresh", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None),
- ("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK'}, None),
- ("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True},
+ ("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK'},
+ {"properties": [("open", False), ("deselect_all", not params.legacy)]}),
+ ("file.select", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
+ ("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True},
{"properties": [("extend", True)]}),
- ("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True, "ctrl": True},
+ ("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True},
{"properties": [("extend", True), ("fill", True)]}),
- ("file.select", {"type": 'RIGHTMOUSE', "value": 'CLICK'},
- {"properties": [("open", False)]}),
- ("file.select", {"type": 'RIGHTMOUSE', "value": 'CLICK', "shift": True},
- {"properties": [("extend", True), ("open", False)]}),
- ("file.select", {"type": 'RIGHTMOUSE', "value": 'CLICK', "alt": True},
- {"properties": [("extend", True), ("fill", True), ("open", False)]}),
("file.select_walk", {"type": 'UP_ARROW', "value": 'PRESS'},
{"properties": [("direction", 'UP')]}),
("file.select_walk", {"type": 'UP_ARROW', "value": 'PRESS', "shift": True},
@@ -1842,20 +1863,10 @@ def km_file_browser_main(params):
("file.select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None),
("file.select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY', "shift": True},
{"properties": [("mode", 'ADD')]}),
- ("file.rename", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, None),
+ ("file.select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY', "ctrl": True},
+ {"properties": [("mode", 'SUB')]}),
("file.highlight", {"type": 'MOUSEMOVE', "value": 'ANY', "any": True}, None),
- ("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS'},
- {"properties": [("increment", 1)]}),
- ("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "shift": True},
- {"properties": [("increment", 10)]}),
- ("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True},
- {"properties": [("increment", 100)]}),
- ("file.filenum", {"type": 'NUMPAD_MINUS', "value": 'PRESS'},
- {"properties": [("increment", -1)]}),
- ("file.filenum", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "shift": True},
- {"properties": [("increment", -10)]}),
- ("file.filenum", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True},
- {"properties": [("increment", -100)]}),
+ ("file.sort_column_ui_context", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None),
])
return keymap
@@ -2428,10 +2439,10 @@ def km_sequencer(params):
{"properties": [("mode", 'TIME_EXTEND')]}),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None),
- ("sequencer.select",{"type": 'LEFT_BRACKET', "value": 'PRESS'},
- {"properties": [("left_right", 'LEFT'), ("linked_time", True)]}),
- ("sequencer.select",{"type": 'RIGHT_BRACKET', "value": 'PRESS'},
- {"properties": [("left_right", 'RIGHT'), ("linked_time", True)]}),
+ ("sequencer.select", {"type": 'LEFT_BRACKET', "value": 'PRESS'},
+ {"properties": [("left_right", 'LEFT'), ("linked_time", True)]}),
+ ("sequencer.select", {"type": 'RIGHT_BRACKET', "value": 'PRESS'},
+ {"properties": [("left_right", 'RIGHT'), ("linked_time", True)]}),
])
return keymap
@@ -2652,13 +2663,12 @@ def km_clip_editor(params):
("clip.hide_tracks", {"type": 'H', "value": 'PRESS', "shift": True},
{"properties": [("unselected", True)]}),
("clip.hide_tracks_clear", {"type": 'H', "value": 'PRESS', "alt": True}, None),
- ("clip.slide_plane_marker", {"type": params.action_mouse, "value": 'PRESS'}, None),
+ ("clip.slide_plane_marker", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG'}, None),
("clip.keyframe_insert", {"type": 'I', "value": 'PRESS'}, None),
("clip.keyframe_delete", {"type": 'I', "value": 'PRESS', "alt": True}, None),
("clip.join_tracks", {"type": 'J', "value": 'PRESS', "ctrl": True}, None),
op_menu("CLIP_MT_tracking_context_menu", params.context_menu_event),
- ("wm.context_toggle", {"type": 'L', "value": 'PRESS'},
- {"properties": [("data_path", 'space_data.lock_selection')]}),
+ ("clip.lock_selection_toggle", {"type": 'L', "value": 'PRESS'}, None),
("wm.context_toggle", {"type": 'D', "value": 'PRESS', "alt": True},
{"properties": [("data_path", 'space_data.show_disabled')]}),
("wm.context_toggle", {"type": 'S', "value": 'PRESS', "alt": True},
@@ -2681,6 +2691,11 @@ def km_clip_editor(params):
("clip.paste_tracks", {"type": 'V', "value": 'PRESS', "ctrl": True}, None),
])
+ if params.legacy:
+ items.extend([
+ ("clip.view_center_cursor", {"type": 'HOME', "value": 'PRESS', "alt": True}, None),
+ ])
+
return keymap
@@ -2948,13 +2963,6 @@ def km_grease_pencil(_params):
# Erase
("gpencil.annotate", {"type": 'RIGHTMOUSE', "value": 'PRESS', "key_modifier": 'D'},
{"properties": [("mode", 'ERASER'), ("wait_for_input", False)]}),
-
- # Add blank frame (B because it's easy to reach from D).
- ("gpencil.blank_frame_add", {"type": 'B', "value": 'PRESS', "key_modifier": 'D'}, None),
- # Delete active frame - for easier video tutorials/review sessions.
- # This works even when not in edit mode.
- ("gpencil.active_frames_delete_all", {"type": 'X', "value": 'PRESS', "key_modifier": 'D'}, None),
- ("gpencil.active_frames_delete_all", {"type": 'DEL', "value": 'PRESS', "key_modifier": 'D'}, None),
])
return keymap
@@ -3037,6 +3045,8 @@ def km_grease_pencil_stroke_edit_mode(params):
op_menu("VIEW3D_MT_edit_gpencil_delete", {"type": 'DEL', "value": 'PRESS'}),
("gpencil.dissolve", {"type": 'X', "value": 'PRESS', "ctrl": True}, None),
("gpencil.dissolve", {"type": 'DEL', "value": 'PRESS', "ctrl": True}, None),
+ # Animation menu
+ ("gpencil.blank_frame_add", {"type": 'I', "value": 'PRESS', "shift": True}, None),
("gpencil.active_frames_delete_all", {"type": 'X', "value": 'PRESS', "shift": True}, None),
("gpencil.active_frames_delete_all", {"type": 'DEL', "value": 'PRESS', "shift": True}, None),
# Context menu
@@ -3068,7 +3078,7 @@ def km_grease_pencil_stroke_edit_mode(params):
# Isolate layer
("gpencil.layer_isolate", {"type": 'NUMPAD_ASTERIX', "value": 'PRESS'}, None),
# Move to layer
- ("gpencil.move_to_layer", {"type": 'M', "value": 'PRESS'}, None),
+ op_menu("GPENCIL_MT_move_to_layer", {"type": 'M', "value": 'PRESS'}),
# Transform tools
("transform.translate", {"type": 'G', "value": 'PRESS'}, None),
("transform.translate", {"type": params.select_tweak, "value": 'ANY'}, None),
@@ -3125,6 +3135,19 @@ def km_grease_pencil_stroke_paint_mode(params):
op_panel("VIEW3D_PT_gpencil_draw_context_menu", params.context_menu_event),
# Draw delete menu
op_menu("GPENCIL_MT_gpencil_draw_delete", {"type": 'X', "value": 'PRESS'}),
+ # Animation menu
+ ("gpencil.blank_frame_add", {"type": 'I', "value": 'PRESS', "shift": True}, None),
+ ("gpencil.active_frames_delete_all", {"type": 'X', "value": 'PRESS', "shift": True}, None),
+ ("gpencil.active_frames_delete_all", {"type": 'DEL', "value": 'PRESS', "shift": True}, None),
+ # Interpolation
+ ("gpencil.interpolate", {"type": 'E', "value": 'PRESS', "ctrl": True, "alt": True}, None),
+ ("gpencil.interpolate_sequence", {"type": 'E', "value": 'PRESS', "shift": True, "ctrl": True}, None),
+ # Show/hide
+ ("gpencil.reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None),
+ ("gpencil.hide", {"type": 'H', "value": 'PRESS'},
+ {"properties": [("unselected", False)]}),
+ ("gpencil.hide", {"type": 'H', "value": 'PRESS', "shift": True},
+ {"properties": [("unselected", True)]}),
])
return keymap
@@ -3154,7 +3177,7 @@ def km_grease_pencil_stroke_paint_draw_brush(params):
("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("mode", 'ERASER'), ("wait_for_input", False)]}),
# Constrain Guides Speedlines
- # Freehand
+ # Freehand
("gpencil.draw", {"type": 'O', "value": 'PRESS'}, None),
("gpencil.draw", {"type": 'J', "value": 'PRESS'}, None),
("gpencil.draw", {"type": 'J', "value": 'PRESS', "alt": True}, None),
@@ -3166,11 +3189,11 @@ def km_grease_pencil_stroke_paint_draw_brush(params):
("gpencil.draw", {"type": 'L', "value": 'PRESS', "alt": True}, None),
("gpencil.draw", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
("gpencil.draw", {"type": 'V', "value": 'PRESS'}, None),
- # Mirror or flip
+ # Mirror or flip
("gpencil.draw", {"type": 'M', "value": 'PRESS'}, None),
- # Mode
+ # Mode
("gpencil.draw", {"type": 'C', "value": 'PRESS'}, None),
- # Set reference point
+ # Set reference point
("gpencil.draw", {"type": 'C', "value": 'PRESS', "alt": True}, None),
# Tablet Mappings for Drawing ------------------ */
# For now, only support direct drawing using the eraser, as most users using a tablet
@@ -3266,7 +3289,7 @@ def km_grease_pencil_stroke_sculpt_mode(params):
return keymap
-def km_grease_pencil_stroke_weight_mode(params):
+def km_grease_pencil_stroke_weight_mode(_params):
items = []
keymap = (
"Grease Pencil Stroke Weight Mode",
@@ -3463,6 +3486,8 @@ def km_object_mode(params):
("object.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None),
("object.duplicate_move_linked", {"type": 'D', "value": 'PRESS', "alt": True}, None),
("object.join", {"type": 'J', "value": 'PRESS', "ctrl": True}, None),
+ ("wm.context_toggle", {"type": 'PERIOD', "value": 'PRESS', "ctrl": True},
+ {"properties": [("data_path", 'tool_settings.use_transform_data_origin')]}),
("anim.keyframe_insert_menu", {"type": 'I', "value": 'PRESS'}, None),
("anim.keyframe_delete_v3d", {"type": 'I', "value": 'PRESS', "alt": True}, None),
("anim.keying_set_active_set", {"type": 'I', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None),
@@ -3834,9 +3859,16 @@ def km_sculpt(params):
("paint.mask_lasso_gesture", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, None),
("wm.context_toggle", {"type": 'M', "value": 'PRESS', "ctrl": True},
{"properties": [("data_path", 'scene.tool_settings.sculpt.show_mask')]}),
+ ("sculpt.mask_expand", {"type": 'A', "value": 'PRESS', "shift": True},
+ {"properties": [("use_normals", False), ("keep_previous_mask", False), ("invert", True), ("smooth_iterations", 2)]}),
+ ("sculpt.mask_expand", {"type": 'A', "value": 'PRESS', "shift": True, 'alt': True},
+ {"properties": [("use_normals", True), ("keep_previous_mask", True), ("invert", False), ("smooth_iterations", 0)]}),
# Dynamic topology
("sculpt.dynamic_topology_toggle", {"type": 'D', "value": 'PRESS', "ctrl": True}, None),
("sculpt.set_detail_size", {"type": 'D', "value": 'PRESS', "shift": True}, None),
+ # Remesh
+ ("object.voxel_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
+ ("object.quadriflow_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True, "alt": True}, None),
# Brush properties
("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS'},
{"properties": [("scalar", 0.9)]}),
@@ -3886,6 +3918,7 @@ def km_sculpt(params):
{"properties": [("data_path", 'tool_settings.sculpt.brush.use_smooth_stroke')]}),
op_menu("VIEW3D_MT_angle_control", {"type": 'R', "value": 'PRESS'}),
op_panel("VIEW3D_PT_sculpt_context_menu", params.context_menu_event),
+ op_menu_pie("VIEW3D_MT_sculpt_mask_edit_pie", {"type" : 'A', "value": 'PRESS'})
])
if params.legacy:
@@ -5006,7 +5039,7 @@ def km_image_editor_tool_uv_cursor(params):
def km_image_editor_tool_uv_select(params):
return (
- "Image Editor Tool: Uv, Select",
+ "Image Editor Tool: Uv, Tweak",
{"space_type": 'IMAGE_EDITOR', "region_type": 'WINDOW'},
{"items": _template_items_tool_select(params, "uv.select", "uv.cursor_set")},
)
@@ -5093,7 +5126,7 @@ def km_image_editor_tool_uv_scale(params):
def km_node_editor_tool_select(params):
return (
- "Node Tool: Select",
+ "Node Tool: Tweak",
{"space_type": 'NODE_EDITOR', "region_type": 'WINDOW'},
{"items": [
("node.select", {"type": params.select_mouse, "value": 'PRESS'},
@@ -5157,7 +5190,7 @@ def km_3d_view_tool_cursor(params):
def km_3d_view_tool_select(params):
return (
- "3D View Tool: Select",
+ "3D View Tool: Tweak",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
{"items": _template_items_tool_select(params, "view3d.select", "view3d.cursor3d")},
)
@@ -5452,11 +5485,11 @@ def km_3d_view_tool_edit_mesh_poly_build(params):
"3D View Tool: Edit Mesh, Poly Build",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
{"items": [
- ("mesh.polybuild_face_at_cursor_move", {"type": params.tool_mouse, "value": 'PRESS'},
+ ("mesh.polybuild_extrude_at_cursor_move", {"type": params.tool_mouse, "value": 'PRESS'},
{"properties": [("TRANSFORM_OT_translate", [("release_confirm", True)])]}),
- ("mesh.polybuild_split_at_cursor_move", {"type": params.tool_mouse, "value": 'PRESS', "ctrl": True},
+ ("mesh.polybuild_face_at_cursor_move", {"type": params.tool_mouse, "value": 'PRESS', "ctrl": True},
{"properties": [("TRANSFORM_OT_translate", [("release_confirm", True)])]}),
- ("mesh.polybuild_dissolve_at_cursor", {"type": params.tool_mouse, "value": 'CLICK', "alt": True}, None),
+ ("mesh.polybuild_delete_at_cursor", {"type": params.tool_mouse, "value": 'CLICK', "shift": True}, None),
]},
)
@@ -5553,8 +5586,17 @@ def km_3d_view_tool_edit_mesh_shear(params):
"3D View Tool: Edit Mesh, Shear",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
{"items": [
- ("transform.shear", {"type": params.tool_tweak, "value": 'ANY'},
- {"properties": [("release_confirm", True)]}),
+ ("transform.shear",
+ {"type": params.tool_tweak, "value": 'NORTH'},
+ {"properties": [("release_confirm", True), ("orient_axis_ortho", 'Y')]}),
+ ("transform.shear",
+ {"type": params.tool_tweak, "value": 'SOUTH'},
+ {"properties": [("release_confirm", True), ("orient_axis_ortho", 'Y')]}),
+
+ # Use as fallback to catch diagonals too.
+ ("transform.shear",
+ {"type": params.tool_tweak, "value": 'ANY'},
+ {"properties": [("release_confirm", True), ("orient_axis_ortho", 'X')]}),
]},
)
@@ -5695,6 +5737,15 @@ def km_3d_view_tool_sculpt_lasso_mask(params):
]},
)
+def km_3d_view_tool_sculpt_mesh_filter(params):
+ return (
+ "3D View Tool: Sculpt, Mesh Filter",
+ {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
+ {"items": [
+ ("sculpt.mesh_filter", {"type": params.tool_tweak, "value": 'ANY'},
+ None)
+ ]},
+ )
def km_3d_view_tool_paint_weight_sample_weight(params):
return (
@@ -5821,7 +5872,7 @@ def km_3d_view_tool_paint_gpencil_cutter(params):
def km_3d_view_tool_edit_gpencil_select(params):
return (
- "3D View Tool: Edit Gpencil, Select",
+ "3D View Tool: Edit Gpencil, Tweak",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
{"items": _template_items_tool_select(params, "gpencil.select", "view3d.cursor3d")},
)
@@ -5854,6 +5905,16 @@ def km_3d_view_tool_edit_gpencil_select_lasso(params):
)
+def km_3d_view_tool_edit_gpencil_extrude(params):
+ return (
+ "3D View Tool: Edit Gpencil, Extrude",
+ {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
+ {"items": [
+ ("gpencil.extrude_move", {"type": params.tool_tweak, "value": 'ANY'}, None),
+ ]},
+ )
+
+
def km_3d_view_tool_edit_gpencil_radius(params):
return (
"3D View Tool: Edit Gpencil, Radius",
@@ -5916,7 +5977,7 @@ def km_3d_view_tool_sculpt_gpencil_paint(_params):
def km_3d_view_tool_sculpt_gpencil_select(params):
return (
- "3D View Tool: Sculpt Gpencil, Select",
+ "3D View Tool: Sculpt Gpencil, Tweak",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
{"items": _template_items_tool_select(params, "gpencil.select", "view3d.cursor3d")},
)
@@ -6136,6 +6197,7 @@ def generate_keymaps(params=None):
km_3d_view_tool_sculpt_box_hide(params),
km_3d_view_tool_sculpt_box_mask(params),
km_3d_view_tool_sculpt_lasso_mask(params),
+ km_3d_view_tool_sculpt_mesh_filter(params),
km_3d_view_tool_paint_weight_sample_weight(params),
km_3d_view_tool_paint_weight_sample_vertex_group(params),
km_3d_view_tool_paint_weight_gradient(params),
@@ -6149,6 +6211,7 @@ def generate_keymaps(params=None):
km_3d_view_tool_edit_gpencil_select_box(params),
km_3d_view_tool_edit_gpencil_select_circle(params),
km_3d_view_tool_edit_gpencil_select_lasso(params),
+ km_3d_view_tool_edit_gpencil_extrude(params),
km_3d_view_tool_edit_gpencil_radius(params),
km_3d_view_tool_edit_gpencil_bend(params),
km_3d_view_tool_edit_gpencil_shear(params),
diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
index 20f496adea9..5ce79936836 100644
--- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
+++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
@@ -182,6 +182,8 @@ def km_window(params):
)
items.extend([
+ ("wm.batch_rename", {"type": 'RET', "value": 'PRESS', "alt": True}, None),
+
# File operations
("wm.read_homefile", {"type": 'N', "value": 'PRESS', "ctrl": True}, None),
op_menu("TOPBAR_MT_file_open_recent", {"type": 'O', "value": 'PRESS', "shift": True, "ctrl": True}),
@@ -1169,16 +1171,33 @@ def km_file_browser(params):
items.extend([
("file.parent", {"type": 'UP_ARROW', "value": 'PRESS', "alt": True}, None),
+ ("file.parent", {"type": 'UP_ARROW', "value": 'PRESS', "ctrl": True}, None),
("file.previous", {"type": 'LEFT_ARROW', "value": 'PRESS', "alt": True}, None),
+ ("file.previous", {"type": 'LEFT_ARROW', "value": 'PRESS', "ctrl": True}, None),
("file.next", {"type": 'RIGHT_ARROW', "value": 'PRESS', "alt": True}, None),
- ("file.refresh", {"type": 'R', "value": 'PRESS'}, None),
- ("file.parent", {"type": 'P', "value": 'PRESS'}, None),
+ ("file.next", {"type": 'RIGHT_ARROW', "value": 'PRESS', "ctrl": True}, None),
+ ("file.refresh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
("wm.context_toggle", {"type": 'H', "value": 'PRESS'},
{"properties": [("data_path", 'space_data.params.show_hidden')]}),
- ("file.directory_new", {"type": 'I', "value": 'PRESS'}, None),
+ ("file.directory_new", {"type": 'I', "value": 'PRESS'},
+ {"properties": [("confirm", False)]}),
("file.smoothscroll", {"type": 'TIMER1', "value": 'ANY', "any": True}, None),
- ("file.bookmark_toggle", {"type": 'T', "value": 'PRESS'}, None),
+ ("wm.context_toggle", {"type": 'T', "value": 'PRESS'},
+ {"properties": [("data_path", 'space_data.show_region_toolbar')]}),
("file.bookmark_add", {"type": 'B', "value": 'PRESS', "ctrl": True}, None),
+ ("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS'},
+ {"properties": [("increment", 1)]}),
+ ("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "shift": True},
+ {"properties": [("increment", 10)]}),
+ ("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True},
+ {"properties": [("increment", 100)]}),
+ ("file.filenum", {"type": 'NUMPAD_MINUS', "value": 'PRESS'},
+ {"properties": [("increment", -1)]}),
+ ("file.filenum", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "shift": True},
+ {"properties": [("increment", -10)]}),
+ ("file.filenum", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True},
+ {"properties": [("increment", -100)]}),
+ op_menu("FILEBROWSER_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
])
return keymap
@@ -1196,13 +1215,13 @@ def km_file_browser_main(params):
("file.execute", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'},
{"properties": [("need_active", True)]}),
("file.refresh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
- ("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK'}, None),
- ("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True},
+ ("file.select", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
+ ("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK'},
+ {"properties": [("open", False), ("deselect_all", True)]}),
+ ("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True},
{"properties": [("extend", True)]}),
- ("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True, "ctrl": True},
+ ("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True,},
{"properties": [("extend", True), ("fill", True)]}),
- ("file.select", {"type": 'RIGHTMOUSE', "value": 'CLICK'},
- {"properties": [("open", False)]}),
("file.select", {"type": 'RIGHTMOUSE', "value": 'CLICK', "shift": True},
{"properties": [("extend", True), ("open", False)]}),
("file.select", {"type": 'RIGHTMOUSE', "value": 'CLICK', "alt": True},
@@ -1239,18 +1258,7 @@ def km_file_browser_main(params):
("file.select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY', "shift": True},
{"properties": [("mode", 'ADD')]}),
("file.highlight", {"type": 'MOUSEMOVE', "value": 'ANY', "any": True}, None),
- ("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS'},
- {"properties": [("increment", 1)]}),
- ("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "shift": True},
- {"properties": [("increment", 10)]}),
- ("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True},
- {"properties": [("increment", 100)]}),
- ("file.filenum", {"type": 'NUMPAD_MINUS', "value": 'PRESS'},
- {"properties": [("increment", -1)]}),
- ("file.filenum", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "shift": True},
- {"properties": [("increment", -10)]}),
- ("file.filenum", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True},
- {"properties": [("increment", -100)]}),
+ ("file.sort_column_ui_context", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None),
])
return keymap
@@ -2207,22 +2215,6 @@ def km_grease_pencil(_params):
)
items.extend([
- # Draw
- ("gpencil.annotate", {"type": 'LEFTMOUSE', "value": 'PRESS', "key_modifier": 'D'},
- {"properties": [("mode", 'DRAW'), ("wait_for_input", False)]}),
- # Draw - straight lines
- ("gpencil.annotate", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True, "key_modifier": 'D'},
- {"properties": [("mode", 'DRAW_STRAIGHT'), ("wait_for_input", False)]}),
- # Draw - poly lines
- ("gpencil.annotate", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "alt": True, "key_modifier": 'D'},
- {"properties": [("mode", 'DRAW_POLY'), ("wait_for_input", False)]}),
- # Erase
- ("gpencil.annotate", {"type": 'RIGHTMOUSE', "value": 'PRESS', "key_modifier": 'D'},
- {"properties": [("mode", 'ERASER'), ("wait_for_input", False)]}),
-
- # Add blank frame (B because it's easy to reach from D).
- ("gpencil.blank_frame_add", {"type": 'B', "value": 'PRESS', "key_modifier": 'D'}, None),
- # Delete active frame - for easier video tutorials/review sessions.
# This works even when not in edit mode.
("gpencil.active_frames_delete_all", {"type": 'BACK_SPACE', "value": 'PRESS', "key_modifier": 'D'}, None),
("gpencil.active_frames_delete_all", {"type": 'DEL', "value": 'PRESS', "key_modifier": 'D'}, None),
@@ -2872,6 +2864,14 @@ def km_image_paint(params):
{"properties": [("data_path", 'tool_settings.image_paint.brush.use_smooth_stroke')]}),
op_menu("VIEW3D_MT_angle_control", {"type": 'R', "value": 'PRESS'}),
op_panel("VIEW3D_PT_paint_texture_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ # Tools
+ ("paint.brush_select", {"type": 'D', "value": 'PRESS'},
+ {"properties": [("image_tool", 'DRAW')]}),
+ ("paint.brush_select", {"type": 'B', "value": 'PRESS'},
+ {"properties": [("image_tool", 'SOFTEN')]}),
+ ("paint.brush_select", {"type": 'G', "value": 'PRESS'},
+ {"properties": [("image_tool", 'FILL')]}),
+ op_tool("builtin.select_box", {"type": 'Q', "value": 'PRESS'}),
])
return keymap
@@ -2914,6 +2914,12 @@ def km_vertex_paint(params):
{"properties": [("data_path", 'tool_settings.vertex_paint.brush.use_smooth_stroke')]}),
op_menu("VIEW3D_MT_angle_control", {"type": 'R', "value": 'PRESS'}),
op_panel("VIEW3D_PT_paint_vertex_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ # Tools
+ ("paint.brush_select", {"type": 'D', "value": 'PRESS'},
+ {"properties": [("vertex_tool", 'DRAW')]}),
+ ("paint.brush_select", {"type": 'B', "value": 'PRESS'},
+ {"properties": [("vertex_tool", 'BLUR')]}),
+ op_tool("builtin.select_box", {"type": 'Q', "value": 'PRESS'}),
])
return keymap
@@ -2929,7 +2935,6 @@ def km_weight_paint(params):
items.extend([
("paint.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
- ("paint.weight_sample", {"type": 'I', "value": 'PRESS'}, None),
("paint.weight_sample_group", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, None),
("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS'},
{"properties": [("scalar", 0.9)]}),
@@ -2945,6 +2950,13 @@ def km_weight_paint(params):
op_panel("VIEW3D_PT_paint_weight_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
# Bone selection for combined weight paint + pose mode.
("view3d.select", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, None),
+ # Tools
+ ("paint.brush_select", {"type": 'D', "value": 'PRESS'},
+ {"properties": [("weight_tool", 'DRAW')]}),
+ ("paint.brush_select", {"type": 'B', "value": 'PRESS'},
+ {"properties": [("weight_tool", 'BLUR')]}),
+ op_tool("builtin.sample_weight", {"type": 'I', "value": 'PRESS'}),
+ op_tool("builtin.select_box", {"type": 'Q', "value": 'PRESS'}),
])
return keymap
@@ -3377,12 +3389,12 @@ def km_object_non_modal(params):
items.extend([
- ("ic_keymap.mesh_select_mode",{"type": 'ONE', "value": 'PRESS'},
- {"properties": [("type", 'VERT')]}),
- ("ic_keymap.mesh_select_mode",{"type": 'TWO', "value": 'PRESS'},
- {"properties": [("type", 'EDGE')]}),
- ("ic_keymap.mesh_select_mode",{"type": 'THREE', "value": 'PRESS'},
- {"properties": [("type", 'FACE')]}),
+ ("object.mode_set_with_submode",{"type": 'ONE', "value": 'PRESS'},
+ {"properties": [("mode", 'EDIT'), ("mesh_select_mode", {'VERT'})]}),
+ ("object.mode_set_with_submode",{"type": 'TWO', "value": 'PRESS'},
+ {"properties": [("mode", 'EDIT'), ("mesh_select_mode", {'EDGE'})]}),
+ ("object.mode_set_with_submode",{"type": 'THREE', "value": 'PRESS'},
+ {"properties": [("mode", 'EDIT'), ("mesh_select_mode", {'FACE'})]}),
("object.mode_set",{"type": 'ONE', "value": 'PRESS'},
{"properties": [("mode", 'EDIT')]}),
("object.mode_set",{"type": 'FOUR', "value": 'PRESS'},
diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py
index bd727ec3e83..0f95371d4c5 100644
--- a/release/scripts/startup/bl_operators/add_mesh_torus.py
+++ b/release/scripts/startup/bl_operators/add_mesh_torus.py
@@ -125,7 +125,7 @@ def add_uvs(mesh, minor_seg, major_seg):
class AddTorus(Operator, object_utils.AddObjectHelper):
- """Add a torus mesh"""
+ """Construct a torus mesh"""
bl_idname = "mesh.primitive_torus_add"
bl_label = "Add Torus"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
@@ -252,10 +252,12 @@ class AddTorus(Operator, object_utils.AddObjectHelper):
self.major_radius = self.abso_minor_rad + extra_helper
self.minor_radius = extra_helper
- verts_loc, faces = add_torus(self.major_radius,
- self.minor_radius,
- self.major_segments,
- self.minor_segments)
+ verts_loc, faces = add_torus(
+ self.major_radius,
+ self.minor_radius,
+ self.major_segments,
+ self.minor_segments,
+ )
mesh = bpy.data.meshes.new(data_("Torus"))
diff --git a/release/scripts/startup/bl_operators/clip.py b/release/scripts/startup/bl_operators/clip.py
index e857d8547a7..fcde95a48fe 100644
--- a/release/scripts/startup/bl_operators/clip.py
+++ b/release/scripts/startup/bl_operators/clip.py
@@ -39,6 +39,17 @@ def CLIP_spaces_walk(context, all_screens, tarea, tspace, callback, *args):
def CLIP_set_viewport_background(context, clip, clip_user):
+
+ def check_camera_has_distortion(tracking_camera):
+ if tracking_camera.distortion_model == 'POLYNOMIAL':
+ return not all(k == 0 for k in (tracking_camera.k1,
+ tracking_camera.k2,
+ tracking_camera.k3))
+ elif tracking_camera.distortion_model == 'DIVISION':
+ return not all(k == 0 for k in (tracking_camera.division_k1,
+ tracking_camera.division_k2))
+ return False
+
def set_background(cam, clip, user):
bgpic = None
@@ -53,7 +64,8 @@ def CLIP_set_viewport_background(context, clip, clip_user):
bgpic.source = 'MOVIE_CLIP'
bgpic.clip = clip
bgpic.clip_user.proxy_render_size = user.proxy_render_size
- bgpic.clip_user.use_render_undistorted = True
+ if check_camera_has_distortion(clip.tracking.camera):
+ bgpic.clip_user.use_render_undistorted = True
bgpic.use_camera_clip = False
cam.show_background_images = True
diff --git a/release/scripts/startup/bl_operators/freestyle.py b/release/scripts/startup/bl_operators/freestyle.py
index 3d619f97e6e..baac3556fb2 100644
--- a/release/scripts/startup/bl_operators/freestyle.py
+++ b/release/scripts/startup/bl_operators/freestyle.py
@@ -106,24 +106,24 @@ class SCENE_OT_freestyle_fill_range_by_selection(bpy.types.Operator):
m.range_max = max_dist
return {'FINISHED'}
# Find selected mesh objects
- selection = [ob for ob in scene.objects if ob.select_get() and ob.type == 'MESH' and ob.name != source.name]
+ selection = [ob for ob in scene.objects if ob.select_get() and ob.type == 'MESH' and ob.name != ref.name]
if selection:
# Compute the min/max distance from the reference to mesh vertices
min_dist = sys.float_info.max
max_dist = -min_dist
if m.type == 'DISTANCE_FROM_CAMERA':
for ob in selection:
- ob_to_cam = matrix_to_camera * ob.matrix_world
+ ob_to_cam = matrix_to_camera @ ob.matrix_world
for vert in ob.data.vertices:
# dist in the camera space
- dist = (ob_to_cam * vert.co).length
+ dist = (ob_to_cam @ vert.co).length
min_dist = min(dist, min_dist)
max_dist = max(dist, max_dist)
elif m.type == 'DISTANCE_FROM_OBJECT':
for ob in selection:
for vert in ob.data.vertices:
# dist in the world space
- dist = (ob.matrix_world * vert.co - target_location).length
+ dist = (ob.matrix_world @ vert.co - target_location).length
min_dist = min(dist, min_dist)
max_dist = max(dist, max_dist)
# Fill the Range Min/Max entries with the computed distances
diff --git a/release/scripts/startup/bl_operators/mask.py b/release/scripts/startup/bl_operators/mask.py
index 68f926c636b..2635f535b0b 100644
--- a/release/scripts/startup/bl_operators/mask.py
+++ b/release/scripts/startup/bl_operators/mask.py
@@ -20,7 +20,7 @@
from bpy.types import Menu
from bpy.app.translations import contexts as i18n_contexts
-
+
class MASK_MT_add(Menu):
bl_idname = "MASK_MT_add"
diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py
index 097b93ea9ca..661a7bd4aea 100644
--- a/release/scripts/startup/bl_operators/presets.py
+++ b/release/scripts/startup/bl_operators/presets.py
@@ -670,9 +670,9 @@ class AddPresetGpencilMaterial(AddPresetBase, Operator):
"gpcolor.stroke_image",
"gpcolor.pixel_size",
"gpcolor.use_stroke_pattern",
- "gpcolor.use_stroke_texture_mix",
- "gpcolor.mix_stroke_factor",
- "gpcolor.alignment_mode",
+ "gpcolor.use_stroke_texture_mix",
+ "gpcolor.mix_stroke_factor",
+ "gpcolor.alignment_mode",
"gpcolor.fill_style",
"gpcolor.fill_color",
"gpcolor.fill_image",
diff --git a/release/scripts/startup/bl_operators/rigidbody.py b/release/scripts/startup/bl_operators/rigidbody.py
index f16f97ab156..4c014ff7ac4 100644
--- a/release/scripts/startup/bl_operators/rigidbody.py
+++ b/release/scripts/startup/bl_operators/rigidbody.py
@@ -89,7 +89,7 @@ class CopyRigidbodySettings(Operator):
class BakeToKeyframes(Operator):
'''Bake rigid body transformations of selected objects to keyframes'''
bl_idname = "rigidbody.bake_to_keyframes"
- bl_label = "Bake To Keyframes"
+ bl_label = "Bake to Keyframes"
bl_options = {'REGISTER', 'UNDO'}
frame_start: IntProperty(
diff --git a/release/scripts/startup/bl_operators/sequencer.py b/release/scripts/startup/bl_operators/sequencer.py
index b1152157cf8..ab87dc47075 100644
--- a/release/scripts/startup/bl_operators/sequencer.py
+++ b/release/scripts/startup/bl_operators/sequencer.py
@@ -136,8 +136,237 @@ class SequencerDeinterlaceSelectedMovies(Operator):
return {'FINISHED'}
+class SequencerFadesClear(Operator):
+ """Removes fade animation from selected sequences"""
+ bl_idname = "sequencer.fades_clear"
+ bl_label = "Clear Fades"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(cls, context):
+ return context.scene and context.scene.sequence_editor and context.scene.sequence_editor.active_strip
+
+ def execute(self, context):
+ fcurves = context.scene.animation_data.action.fcurves
+ fcurve_map = {
+ curve.data_path: curve
+ for curve in fcurves
+ if curve.data_path.startswith("sequence_editor.sequences_all")
+ }
+ for sequence in context.selected_sequences:
+ animated_property = "volume" if hasattr(sequence, "volume") else "blend_alpha"
+ data_path = sequence.path_from_id() + "." + animated_property
+ curve = fcurve_map.get(data_path)
+ if curve:
+ fcurves.remove(curve)
+ setattr(sequence, animated_property, 1.0)
+
+ return {'FINISHED'}
+
+
+class SequencerFadesAdd(Operator):
+ """Adds or updates a fade animation for either visual or audio strips"""
+ bl_idname = "sequencer.fades_add"
+ bl_label = "Add Fades"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ duration_seconds: bpy.props.FloatProperty(
+ name="Fade Duration",
+ description="Duration of the fade in seconds",
+ default=1.0,
+ min=0.01)
+ type: bpy.props.EnumProperty(
+ items=(
+ ('IN_OUT', 'Fade In And Out', 'Fade selected strips in and out'),
+ ('IN', 'Fade In', 'Fade in selected strips'),
+ ('OUT', 'Fade Out', 'Fade out selected strips'),
+ ('CURSOR_FROM', 'From Playhead', 'Fade from the time cursor to the end of overlapping sequences'),
+ ('CURSOR_TO', 'To Playhead', 'Fade from the start of sequences under the time cursor to the current frame'),
+ ),
+ name="Fade type",
+ description="Fade in, out, both in and out, to, or from the playhead. Default is both in and out",
+ default='IN_OUT')
+
+ @classmethod
+ def poll(cls, context):
+ # Can't use context.selected_sequences as it can have an impact on performances
+ return context.scene and context.scene.sequence_editor and context.scene.sequence_editor.active_strip
+
+ def execute(self, context):
+ from math import floor
+
+ # We must create a scene action first if there's none
+ scene = context.scene
+ if not scene.animation_data:
+ scene.animation_data_create()
+ if not scene.animation_data.action:
+ action = bpy.data.actions.new(scene.name + "Action")
+ scene.animation_data.action = action
+
+ sequences = context.selected_sequences
+ if self.type in {'CURSOR_TO', 'CURSOR_FROM'}:
+ sequences = [
+ s for s in sequences
+ if s.frame_final_start < context.scene.frame_current < s.frame_final_end
+ ]
+
+ max_duration = min(sequences, key=lambda s: s.frame_final_duration).frame_final_duration
+ max_duration = floor(max_duration / 2.0) if self.type == 'IN_OUT' else max_duration
+
+ faded_sequences = []
+ for sequence in sequences:
+ duration = self.calculate_fade_duration(context, sequence)
+ duration = min(duration, max_duration)
+ if not self.is_long_enough(sequence, duration):
+ continue
+
+ animated_property = 'volume' if hasattr(sequence, 'volume') else 'blend_alpha'
+ fade_fcurve = self.fade_find_or_create_fcurve(context, sequence, animated_property)
+ fades = self.calculate_fades(sequence, fade_fcurve, animated_property, duration)
+ self.fade_animation_clear(fade_fcurve, fades)
+ self.fade_animation_create(fade_fcurve, fades)
+ faded_sequences.append(sequence)
+
+ sequence_string = "sequence" if len(faded_sequences) == 1 else "sequences"
+ self.report({'INFO'}, "Added fade animation to {} {}.".format(len(faded_sequences), sequence_string))
+ return {'FINISHED'}
+
+ def calculate_fade_duration(self, context, sequence):
+ frame_current = context.scene.frame_current
+ duration = 0.0
+ if self.type == 'CURSOR_TO':
+ duration = abs(frame_current - sequence.frame_final_start)
+ elif self.type == 'CURSOR_FROM':
+ duration = abs(sequence.frame_final_end - frame_current)
+ else:
+ duration = calculate_duration_frames(context, self.duration_seconds)
+ return max(1, duration)
+
+ def is_long_enough(self, sequence, duration=0.0):
+ minimum_duration = duration * 2 if self.type == 'IN_OUT' else duration
+ return sequence.frame_final_duration >= minimum_duration
+
+ def calculate_fades(self, sequence, fade_fcurve, animated_property, duration):
+ """
+ Returns a list of Fade objects
+ """
+ fades = []
+ if self.type in {'IN', 'IN_OUT', 'CURSOR_TO'}:
+ fade = Fade(sequence, fade_fcurve, 'IN', animated_property, duration)
+ fades.append(fade)
+ if self.type in {'OUT', 'IN_OUT', 'CURSOR_FROM'}:
+ fade = Fade(sequence, fade_fcurve, 'OUT', animated_property, duration)
+ fades.append(fade)
+ return fades
+
+ def fade_find_or_create_fcurve(self, context, sequence, animated_property):
+ """
+ Iterates over all the fcurves until it finds an fcurve with a data path
+ that corresponds to the sequence.
+ Returns the matching FCurve or creates a new one if the function can't find a match.
+ """
+ fade_fcurve = None
+ fcurves = context.scene.animation_data.action.fcurves
+ searched_data_path = sequence.path_from_id(animated_property)
+ for fcurve in fcurves:
+ if fcurve.data_path == searched_data_path:
+ fade_fcurve = fcurve
+ break
+ if not fade_fcurve:
+ fade_fcurve = fcurves.new(data_path=searched_data_path)
+ return fade_fcurve
+
+ def fade_animation_clear(self, fade_fcurve, fades):
+ """
+ Removes existing keyframes in the fades' time range, in fast mode, without
+ updating the fcurve
+ """
+ keyframe_points = fade_fcurve.keyframe_points
+ for fade in fades:
+ for keyframe in keyframe_points:
+ # The keyframe points list doesn't seem to always update as the
+ # operator re-runs Leading to trying to remove nonexistent keyframes
+ try:
+ if fade.start.x < keyframe.co[0] <= fade.end.x:
+ keyframe_points.remove(keyframe, fast=True)
+ except Exception:
+ pass
+ fade_fcurve.update()
+
+ def fade_animation_create(self, fade_fcurve, fades):
+ """
+ Inserts keyframes in the fade_fcurve in fast mode using the Fade objects.
+ Updates the fcurve after having inserted all keyframes to finish the animation.
+ """
+ keyframe_points = fade_fcurve.keyframe_points
+ for fade in fades:
+ for point in (fade.start, fade.end):
+ keyframe_points.insert(frame=point.x, value=point.y, options={'FAST'})
+ fade_fcurve.update()
+ # The graph editor and the audio waveforms only redraw upon "moving" a keyframe
+ keyframe_points[-1].co = keyframe_points[-1].co
+
+
+class Fade:
+ # Data structure to represent fades.
+ __slots__ = (
+ "type",
+ "animated_property",
+ "duration",
+ "max_value",
+ "start",
+ "end",
+ )
+
+ def __init__(self, sequence, fade_fcurve, type, animated_property, duration):
+ from mathutils import Vector
+ self.type = type
+ self.animated_property = animated_property
+ self.duration = duration
+ self.max_value = self.calculate_max_value(sequence, fade_fcurve)
+
+ if type == 'IN':
+ self.start = Vector((sequence.frame_final_start, 0.0))
+ self.end = Vector((sequence.frame_final_start + self.duration, self.max_value))
+ elif type == 'OUT':
+ self.start = Vector((sequence.frame_final_end - self.duration, self.max_value))
+ self.end = Vector((sequence.frame_final_end, 0.0))
+
+ def calculate_max_value(self, sequence, fade_fcurve):
+ """
+ Returns the maximum Y coordinate the fade animation should use for a given sequence
+ Uses either the sequence's value for the animated property, or the next keyframe after the fade
+ """
+ max_value = 0.0
+
+ if not fade_fcurve.keyframe_points:
+ max_value = getattr(sequence, self.animated_property, 1.0)
+ else:
+ if self.type == 'IN':
+ fade_end = sequence.frame_final_start + self.duration
+ keyframes = (k for k in fade_fcurve.keyframe_points if k.co[0] >= fade_end)
+ if self.type == 'OUT':
+ fade_start = sequence.frame_final_end - self.duration
+ keyframes = (k for k in reversed(fade_fcurve.keyframe_points) if k.co[0] <= fade_start)
+ try:
+ max_value = next(keyframes).co[1]
+ except StopIteration:
+ pass
+
+ return max_value if max_value > 0.0 else 1.0
+
+ def __repr__(self):
+ return "Fade {}: {} to {}".format(self.type, self.start, self.end)
+
+
+def calculate_duration_frames(context, duration_seconds):
+ return round(duration_seconds * context.scene.render.fps / context.scene.render.fps_base)
+
+
classes = (
SequencerCrossfadeSounds,
SequencerCutMulticam,
SequencerDeinterlaceSelectedMovies,
+ SequencerFadesClear,
+ SequencerFadesAdd,
)
diff --git a/release/scripts/startup/bl_operators/userpref.py b/release/scripts/startup/bl_operators/userpref.py
index 6ec6855296c..b052f333d2a 100644
--- a/release/scripts/startup/bl_operators/userpref.py
+++ b/release/scripts/startup/bl_operators/userpref.py
@@ -537,7 +537,7 @@ class PREFERENCES_OT_addon_refresh(Operator):
class PREFERENCES_OT_addon_install(Operator):
"""Install an add-on"""
bl_idname = "preferences.addon_install"
- bl_label = "Install Add-on from File..."
+ bl_label = "Install Add-on"
overwrite: BoolProperty(
name="Overwrite",
diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py
index fdf74c420a9..4e61874b440 100644
--- a/release/scripts/startup/bl_operators/uvcalc_smart_project.py
+++ b/release/scripts/startup/bl_operators/uvcalc_smart_project.py
@@ -55,10 +55,10 @@ def pointInTri2D(v, v1, v2, v3):
x= key[i]
y= key[i+1]
- if xmax<x: xmax= x
- if ymax<y: ymax= y
- if xmin>x: xmin= x
- if ymin>y: ymin= y
+ if xmax<x: xmax= x
+ if ymax<y: ymax= y
+ if xmin>x: xmin= x
+ if ymin>y: ymin= y
x= v.x
y= v.y
@@ -169,7 +169,7 @@ def island2Edge(island):
# Its okay to leave the length in there.
# for e in length_sorted_edges:
- # e.pop(2)
+ # e.pop(2)
# return edges and unique points
return length_sorted_edges, [v.to_3d() for v in unique_points.values()]
@@ -410,7 +410,7 @@ def mergeUvIslands(islandList):
elif Intersect == 0: # No intersection?? Place it.
# Progress
removedCount += 1
-# XXX Window.DrawProgressBar(0.0, 'Merged: %i islands, Ctrl to finish early.' % removedCount)
+# XXX Window.DrawProgressBar(0.0, 'Merged: %i islands, Ctrl to finish early.' % removedCount)
# Move faces into new island and offset
targetIsland[0].extend(sourceIsland[0])
@@ -485,7 +485,7 @@ def getUvIslands(faceGroups, me):
islandList = []
-# XXX Window.DrawProgressBar(0.0, 'Splitting %d projection groups into UV islands:' % len(faceGroups))
+# XXX Window.DrawProgressBar(0.0, 'Splitting %d projection groups into UV islands:' % len(faceGroups))
# print '\tSplitting %d projection groups into UV islands:' % len(faceGroups),
# Find grouped faces
@@ -552,7 +552,7 @@ def getUvIslands(faceGroups, me):
break
# if not ok will stop looping
-# XXX Window.DrawProgressBar(0.1, 'Optimizing Rotation for %i UV Islands' % len(islandList))
+# XXX Window.DrawProgressBar(0.1, 'Optimizing Rotation for %i UV Islands' % len(islandList))
for island in islandList:
optiRotateUvIsland(island)
@@ -562,7 +562,7 @@ def getUvIslands(faceGroups, me):
def packIslands(islandList):
if USER_FILL_HOLES:
- # XXX Window.DrawProgressBar(0.1, 'Merging Islands (Ctrl: skip merge)...')
+ # XXX Window.DrawProgressBar(0.1, 'Merging Islands (Ctrl: skip merge)...')
mergeUvIslands(islandList) # Modify in place
# Now we have UV islands, we need to pack them.
@@ -611,18 +611,18 @@ def packIslands(islandList):
# with the islands.
# print '\tPacking UV Islands...'
-# XXX Window.DrawProgressBar(0.7, "Packing %i UV Islands..." % len(packBoxes) )
+# XXX Window.DrawProgressBar(0.7, "Packing %i UV Islands..." % len(packBoxes) )
# time1 = time.time()
packWidth, packHeight = geometry.box_pack_2d(packBoxes)
# print 'Box Packing Time:', time.time() - time1
- # if len(pa ckedLs) != len(islandList):
+ # if len(packedLs) != len(islandList):
# raise ValueError("Packed boxes differs from original length")
# print '\tWriting Packed Data to faces'
-# XXX Window.DrawProgressBar(0.8, "Writing Packed Data to faces")
+# XXX Window.DrawProgressBar(0.8, "Writing Packed Data to faces")
# Sort by ID, so there in sync again
islandIdx = len(islandList)
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index bf1c79e766f..cb9af88f45f 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -25,6 +25,7 @@ from bpy.types import (
)
from bpy.props import (
BoolProperty,
+ CollectionProperty,
EnumProperty,
FloatProperty,
IntProperty,
@@ -79,6 +80,10 @@ rna_module_prop = StringProperty(
def context_path_validate(context, data_path):
+ # Silently ignore invalid data paths created by T65397.
+ if "(null)" in data_path:
+ return Ellipsis
+
try:
value = eval("context.%s" % data_path) if data_path else Ellipsis
except AttributeError as ex:
@@ -1174,6 +1179,7 @@ rna_vector_subtype_items = (
('QUATERNION', "Quaternion Rotation", "Quaternion rotation (affects NLA blending)"),
)
+
class WM_OT_properties_edit(Operator):
bl_idname = "wm.properties_edit"
bl_label = "Edit Property"
@@ -1763,6 +1769,456 @@ class WM_OT_toolbar(Operator):
return {'FINISHED'}
+class BatchRenameAction(bpy.types.PropertyGroup):
+ # category: StringProperty()
+ type: EnumProperty(
+ name="Operation",
+ items=(
+ ('REPLACE', "Find/Replace", "Replace text in the name"),
+ ('SET', "Set Name", "Set a new name or prefix/suffix the existing one"),
+ ('STRIP', "Strip Characters", "Strip leading/trailing text from the name"),
+ ('CASE', "Change Case", "Change case of each name"),
+ ),
+ )
+
+ # We could split these into sub-properties, however it's not so important.
+
+ # type: 'SET'.
+ set_name: StringProperty(name="Name")
+ set_method: EnumProperty(
+ name="Method",
+ items=(
+ ('NEW', "New", ""),
+ ('PREFIX', "Prefix", ""),
+ ('SUFFIX', "Suffix", ""),
+ ),
+ default='SUFFIX',
+ )
+
+ # type: 'STRIP'.
+ strip_chars: EnumProperty(
+ name="Strip Characters",
+ options={'ENUM_FLAG'},
+ items=(
+ ('SPACE', "Spaces", ""),
+ ('DIGIT', "Digits", ""),
+ ('PUNCT', "Punctuation", ""),
+ ),
+ )
+
+ # type: 'STRIP'.
+ strip_part: EnumProperty(
+ name="Strip Part",
+ options={'ENUM_FLAG'},
+ items=(
+ ('START', "Start", ""),
+ ('END', "End", ""),
+ ),
+ )
+
+ # type: 'REPLACE'.
+ replace_src: StringProperty(name="Find")
+ replace_dst: StringProperty(name="Replace")
+ replace_match_case: BoolProperty(name="Case Sensitive")
+ use_replace_regex_src: BoolProperty(
+ name="Regular Expression Find",
+ description="Use regular expressions to match text in the 'Find' field"
+ )
+ use_replace_regex_dst: BoolProperty(
+ name="Regular Expression Replace",
+ description="Use regular expression for the replacement text (supporting groups)"
+ )
+
+ # type: 'CASE'.
+ case_method: EnumProperty(
+ name="Case",
+ items=(
+ ('UPPER', "Upper Case", ""),
+ ('LOWER', "Lower Case", ""),
+ ('TITLE', "Title Case", ""),
+ ),
+ )
+
+ # Weak, add/remove as properties.
+ op_add: BoolProperty()
+ op_remove: BoolProperty()
+
+
+class WM_OT_batch_rename(Operator):
+ bl_idname = "wm.batch_rename"
+ bl_label = "Batch Rename"
+
+ bl_options = {'UNDO'}
+
+ data_type: EnumProperty(
+ name="Type",
+ items=(
+ ('OBJECT', "Objects", ""),
+ ('MATERIAL', "Materials", ""),
+ None,
+ # Enum identifiers are compared with 'object.type'.
+ ('MESH', "Meshes", ""),
+ ('CURVE', "Curves", ""),
+ ('META', "Meta Balls", ""),
+ ('ARMATURE', "Armatures", ""),
+ ('LATTICE', "Lattices", ""),
+ ('GPENCIL', "Grease Pencils", ""),
+ ('CAMERA', "Cameras", ""),
+ ('SPEAKER', "Speakers", ""),
+ ('LIGHT_PROBE', "Light Probes", ""),
+ None,
+ ('BONE', "Bones", ""),
+ ('NODE', "Nodes", ""),
+ ('SEQUENCE_STRIP', "Sequence Strips", ""),
+ ),
+ description="Type of data to rename",
+ )
+
+ data_source: EnumProperty(
+ name="Source",
+ items=(
+ ('SELECT', "Selected", ""),
+ ('ALL', "All", ""),
+ ),
+ )
+
+ actions: CollectionProperty(type=BatchRenameAction)
+
+ @staticmethod
+ def _data_from_context(context, data_type, only_selected, check_context=False):
+
+ mode = context.mode
+ scene = context.scene
+ space = context.space_data
+ space_type = None if (space is None) else space.type
+
+ data = None
+ if space_type == 'SEQUENCE_EDITOR':
+ data_type_test = 'SEQUENCE_STRIP'
+ if check_context:
+ return data_type_test
+ if data_type == data_type_test:
+ data = (
+ # TODO, we don't have access to seqbasep, this won't work when inside metas.
+ [seq for seq in context.scene.sequence_editor.sequences_all if seq.select]
+ if only_selected else
+ context.scene.sequence_editor.sequences_all,
+ "name",
+ "Strip(s)",
+ )
+ elif space_type == 'NODE_EDITOR':
+ data_type_test = 'NODE'
+ if check_context:
+ return data_type_test
+ if data_type == data_type_test:
+ data = (
+ context.selected_nodes
+ if only_selected else
+ list(space.node_tree.nodes),
+ "name",
+ "Node(s)",
+ )
+ else:
+ if mode == 'POSE' or (mode == 'WEIGHT_PAINT' and context.pose_object):
+ data_type_test = 'BONE'
+ if check_context:
+ return data_type_test
+ if data_type == data_type_test:
+ data = (
+ [pchan.bone for pchan in context.selected_pose_bones]
+ if only_selected else
+ [pchan.bone for ob in context.objects_in_mode_unique_data for pbone in ob.pose.bones],
+ "name",
+ "Bone(s)",
+ )
+ elif mode == 'EDIT_ARMATURE':
+ data_type_test = 'BONE'
+ if check_context:
+ return data_type_test
+ if data_type == data_type_test:
+ data = (
+ context.selected_editable_bones
+ if only_selected else
+ [ebone for ob in context.objects_in_mode_unique_data for ebone in ob.data.edit_bones],
+ "name",
+ "Edit Bone(s)",
+ )
+
+ if check_context:
+ return 'OBJECT'
+
+ object_data_type_attrs_map = {
+ 'MESH': ("meshes", "Mesh(es)"),
+ 'CURVE': ("curves", "Curve(s)"),
+ 'META': ("metaballs", "MetaBall(s)"),
+ 'ARMATURE': ("armatures", "Armature(s)"),
+ 'LATTICE': ("lattices", "Lattice(s)"),
+ 'GPENCIL': ("grease_pencils", "Grease Pencil(s)"),
+ 'CAMERA': ("cameras", "Camera(s)"),
+ 'SPEAKER': ("speakers", "Speaker(s)"),
+ 'LIGHT_PROBE': ("light_probes", "LightProbe(s)"),
+ }
+
+ # Finish with space types.
+ if data is None:
+
+ if data_type == 'OBJECT':
+ data = (
+ context.selected_editable_objects
+ if only_selected else
+ [id for id in bpy.data.objects if id.library is None],
+ "name",
+ "Object(s)",
+ )
+ elif data_type == 'MATERIAL':
+ data = (
+ tuple(set(
+ slot.material
+ for ob in context.selected_objects
+ for slot in ob.material_slots
+ if slot.material is not None
+ ))
+ if only_selected else
+ [id for id in bpy.data.materials if id.library is None],
+ "name",
+ "Material(s)",
+ )
+ elif data_type in object_data_type_attrs_map.keys():
+ attr, descr = object_data_type_attrs_map[data_type]
+ data = (
+ tuple(set(
+ id
+ for ob in context.selected_objects
+ if ob.type == data_type
+ for id in (ob.data,)
+ if id is not None and id.library is None
+ ))
+ if only_selected else
+ [id for id in getattr(bpy.data, attr) if id.library is None],
+ "name",
+ descr,
+ )
+
+
+ return data
+
+ @staticmethod
+ def _apply_actions(actions, name):
+ import string
+ import re
+
+ for action in actions:
+ ty = action.type
+ if ty == 'SET':
+ text = action.set_name
+ method = action.set_method
+ if method == 'NEW':
+ name = text
+ elif method == 'PREFIX':
+ name = text + name
+ elif method == 'SUFFIX':
+ name = name + text
+ else:
+ assert(0)
+
+ elif ty == 'STRIP':
+ chars = action.strip_chars
+ chars_strip = (
+ "{:s}{:s}{:s}"
+ ).format(
+ string.punctuation if 'PUNCT' in chars else "",
+ string.digits if 'DIGIT' in chars else "",
+ " " if 'SPACE' in chars else "",
+ )
+ part = action.strip_part
+ if 'START' in part:
+ name = name.lstrip(chars_strip)
+ if 'END' in part:
+ name = name.rstrip(chars_strip)
+
+ elif ty == 'REPLACE':
+ if action.use_replace_regex_src:
+ replace_src = action.replace_src
+ if action.use_replace_regex_dst:
+ replace_dst = action.replace_dst
+ else:
+ replace_dst = re.escape(action.replace_dst)
+ else:
+ replace_src = re.escape(action.replace_src)
+ replace_dst = re.escape(action.replace_dst)
+ name = re.sub(
+ replace_src,
+ replace_dst,
+ name,
+ flags=(
+ 0 if action.replace_match_case else
+ re.IGNORECASE
+ ),
+ )
+ elif ty == 'CASE':
+ method = action.case_method
+ if method == 'UPPER':
+ name = name.upper()
+ elif method == 'LOWER':
+ name = name.lower()
+ elif method == 'TITLE':
+ name = name.title()
+ else:
+ assert(0)
+ else:
+ assert(0)
+ return name
+
+ def _data_update(self, context):
+ only_selected = self.data_source == 'SELECT'
+
+ self._data = self._data_from_context(context, self.data_type, only_selected)
+ if self._data is None:
+ self.data_type = self._data_from_context(context, None, False, check_context=True)
+ self._data = self._data_from_context(context, self.data_type, only_selected)
+
+ self._data_source_prev = self.data_source
+ self._data_type_prev = self.data_type
+
+ def draw(self, context):
+ import re
+
+ layout = self.layout
+
+ split = layout.split(factor=0.5)
+ split.label(text="Data Type:")
+ split.prop(self, "data_type", text="")
+
+ split = layout.split(factor=0.5)
+ split.label(text="Rename {:d} {:s}:".format(len(self._data[0]), self._data[2]))
+ split.row().prop(self, "data_source", expand=True)
+
+ for action in self.actions:
+ box = layout.box()
+
+ row = box.row(align=True)
+ row.prop(action, "type", text="")
+ row.prop(action, "op_add", text="", icon='ADD')
+ row.prop(action, "op_remove", text="", icon='REMOVE')
+
+ ty = action.type
+ if ty == 'SET':
+ box.prop(action, "set_method")
+ box.prop(action, "set_name")
+ elif ty == 'STRIP':
+ box.row().prop(action, "strip_chars")
+ box.row().prop(action, "strip_part")
+ elif ty == 'REPLACE':
+
+ row = box.row(align=True)
+ re_error_src = None
+ if action.use_replace_regex_src:
+ try:
+ re.compile(action.replace_src)
+ except Exception as ex:
+ re_error_src = str(ex)
+ row.alert = True
+ row.prop(action, "replace_src")
+ row.prop(action, "use_replace_regex_src", text="", icon='SORTBYEXT')
+ if re_error_src is not None:
+ box.label(text=re_error_src)
+
+ re_error_dst = None
+ row = box.row(align=True)
+ if action.use_replace_regex_src:
+ if action.use_replace_regex_dst:
+ if re_error_src is None:
+ try:
+ re.sub(action.replace_src, action.replace_dst, "")
+ except Exception as ex:
+ re_error_dst = str(ex)
+ row.alert = True
+
+ row.prop(action, "replace_dst")
+ rowsub = row.row(align=True)
+ rowsub.active = action.use_replace_regex_src
+ rowsub.prop(action, "use_replace_regex_dst", text="", icon='SORTBYEXT')
+ if re_error_dst is not None:
+ box.label(text=re_error_dst)
+
+ row = box.row()
+ row.prop(action, "replace_match_case")
+ elif ty == 'CASE':
+ box.row().prop(action, "case_method", expand=True)
+
+ def check(self, context):
+ changed = False
+ for i, action in enumerate(self.actions):
+ if action.op_add:
+ action.op_add = False
+ self.actions.add()
+ if i + 2 != len(self.actions):
+ self.actions.move(len(self.actions) - 1, i + 1)
+ changed = True
+ break
+ if action.op_remove:
+ action.op_remove = False
+ if len(self.actions) > 1:
+ self.actions.remove(i)
+ changed = True
+ break
+
+ if (
+ (self._data_source_prev != self.data_source) or
+ (self._data_type_prev != self.data_type)
+ ):
+ self._data_update(context)
+ changed = True
+
+ return changed
+
+ def execute(self, context):
+ import re
+
+ seq, attr, descr = self._data
+
+ actions = self.actions
+
+ # Sanitize actions.
+ for action in actions:
+ if action.use_replace_regex_src:
+ try:
+ re.compile(action.replace_src)
+ except Exception as ex:
+ self.report({'ERROR'}, "Invalid regular expression (find): " + str(ex))
+ return {'CANCELLED'}
+
+ if action.use_replace_regex_dst:
+ try:
+ re.sub(action.replace_src, action.replace_dst, "")
+ except Exception as ex:
+ self.report({'ERROR'}, "Invalid regular expression (replace): " + str(ex))
+ return {'CANCELLED'}
+
+ total_len = 0
+ change_len = 0
+ for item in seq:
+ name_src = getattr(item, attr)
+ name_dst = self._apply_actions(actions, name_src)
+ if name_src != name_dst:
+ setattr(item, attr, name_dst)
+ change_len += 1
+ total_len += 1
+
+ self.report({'INFO'}, "Renamed {:d} of {:d} {:s}".format(change_len, total_len, descr))
+
+ return {'FINISHED'}
+
+ def invoke(self, context, event):
+
+ self._data_update(context)
+
+ if not self.actions:
+ self.actions.add()
+ wm = context.window_manager
+ return wm.invoke_props_dialog(self, width=400)
+
+
class WM_MT_splash(Menu):
bl_label = "Splash"
@@ -1979,5 +2435,7 @@ classes = (
WM_OT_tool_set_by_id,
WM_OT_tool_set_by_index,
WM_OT_toolbar,
+ BatchRenameAction,
+ WM_OT_batch_rename,
WM_MT_splash,
)
diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py
index 6fa953574cb..dce2d2f2758 100644
--- a/release/scripts/startup/bl_ui/properties_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_constraint.py
@@ -370,6 +370,8 @@ class ConstraintButtonsPanel:
def COPY_ROTATION(self, _context, layout, con):
self.target_template(layout, con)
+ layout.prop(con, "euler_order", text="Order")
+
split = layout.split()
col = split.column()
@@ -390,7 +392,7 @@ class ConstraintButtonsPanel:
sub.active = con.use_z
sub.prop(con, "invert_z", text="Invert")
- layout.prop(con, "use_offset")
+ layout.prop(con, "mix_mode", text="Mix")
self.space_template(layout, con)
@@ -430,6 +432,7 @@ class ConstraintButtonsPanel:
row.prop(con, "use_z", text="Z")
layout.prop(con, "power")
+ layout.prop(con, "use_make_uniform")
row = layout.row()
row.prop(con, "use_offset")
@@ -456,6 +459,8 @@ class ConstraintButtonsPanel:
def COPY_TRANSFORMS(self, _context, layout, con):
self.target_template(layout, con)
+ layout.prop(con, "mix_mode", text="Mix")
+
self.space_template(layout, con)
# def SCRIPT(self, context, layout, con):
@@ -684,6 +689,9 @@ class ConstraintButtonsPanel:
col.row().label(text="Source:")
col.row().prop(con, "map_from", expand=True)
+ if con.map_from == 'ROTATION':
+ layout.prop(con, "from_rotation_mode", text="Mode")
+
split = layout.split()
ext = "" if con.map_from == 'LOCATION' else "_rot" if con.map_from == 'ROTATION' else "_scale"
@@ -726,6 +734,9 @@ class ConstraintButtonsPanel:
col.label(text="Destination:")
col.row().prop(con, "map_to", expand=True)
+ if con.map_to == 'ROTATION':
+ layout.prop(con, "to_euler_order", text="Order")
+
split = layout.split()
ext = "" if con.map_to == 'LOCATION' else "_rot" if con.map_to == 'ROTATION' else "_scale"
@@ -750,6 +761,8 @@ class ConstraintButtonsPanel:
sub.prop(con, "to_min_z" + ext, text="Min")
sub.prop(con, "to_max_z" + ext, text="Max")
+ layout.prop(con, "mix_mode" + ext, text="Mix")
+
self.space_template(layout, con)
def SHRINKWRAP(self, _context, layout, con):
diff --git a/release/scripts/startup/bl_ui/properties_data_bone.py b/release/scripts/startup/bl_ui/properties_data_bone.py
index 8b691ddcc2a..c50b9414667 100644
--- a/release/scripts/startup/bl_ui/properties_data_bone.py
+++ b/release/scripts/startup/bl_ui/properties_data_bone.py
@@ -232,11 +232,13 @@ class BONE_PT_relations(BoneButtonsPanel, Panel):
sub = col.column()
sub.active = (bone.parent is not None)
sub.prop(bone, "use_connect")
- sub.prop(bone, "use_inherit_rotation")
- sub.prop(bone, "use_inherit_scale")
sub = col.column()
sub.active = (not bone.parent or not bone.use_connect)
sub.prop(bone, "use_local_location")
+ sub = col.column()
+ sub.active = (bone.parent is not None)
+ sub.prop(bone, "use_inherit_rotation")
+ sub.prop(bone, "inherit_scale")
class BONE_PT_display(BoneButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/properties_data_camera.py b/release/scripts/startup/bl_ui/properties_data_camera.py
index 32e99910d71..eef70056be8 100644
--- a/release/scripts/startup/bl_ui/properties_data_camera.py
+++ b/release/scripts/startup/bl_ui/properties_data_camera.py
@@ -289,7 +289,7 @@ class DATA_PT_camera_background_image(CameraButtonsPanel, Panel):
elif bg.source == 'MOVIE_CLIP' and bg.clip:
row.prop(bg.clip, "name", text="", emboss=False)
elif bg.source and bg.use_camera_clip:
- row.label(text="Camera Clip")
+ row.label(text="Active Clip")
else:
row.label(text="Not Set")
@@ -329,7 +329,7 @@ class DATA_PT_camera_background_image(CameraButtonsPanel, Panel):
sub.template_image_stereo_3d(bg.image.stereo_3d_format)
elif bg.source == 'MOVIE_CLIP':
- box.prop(bg, "use_camera_clip")
+ box.prop(bg, "use_camera_clip", text="Active Clip")
column = box.column()
column.active = not bg.use_camera_clip
diff --git a/release/scripts/startup/bl_ui/properties_data_empty.py b/release/scripts/startup/bl_ui/properties_data_empty.py
index 6650aef61aa..4ce87b85410 100644
--- a/release/scripts/startup/bl_ui/properties_data_empty.py
+++ b/release/scripts/startup/bl_ui/properties_data_empty.py
@@ -60,6 +60,7 @@ class DATA_PT_empty(DataButtonsPanel, Panel):
col.row().prop(ob, "empty_image_side", text="Side", expand=True)
col.prop(ob, "show_empty_image_orthographic", text="Display Orthographic")
col.prop(ob, "show_empty_image_perspective", text="Display Perspective")
+ col.prop(ob, "show_empty_image_only_axis_aligned")
class DATA_PT_empty_image(DataButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/properties_data_gpencil.py b/release/scripts/startup/bl_ui/properties_data_gpencil.py
index ca814f9c8da..751af892778 100644
--- a/release/scripts/startup/bl_ui/properties_data_gpencil.py
+++ b/release/scripts/startup/bl_ui/properties_data_gpencil.py
@@ -127,7 +127,7 @@ class DATA_PT_gpencil_layers(DataButtonsPanel, Panel):
row = layout.row()
layer_rows = 7
-
+
col = row.column()
col.template_list("GPENCIL_UL_layer", "", gpd, "layers", gpd.layers, "active_index",
rows=layer_rows, sort_reverse=True, sort_lock=True)
@@ -152,13 +152,13 @@ class DATA_PT_gpencil_layers(DataButtonsPanel, Panel):
sub = col.column(align=True)
sub.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
sub.operator("gpencil.layer_isolate", icon='RESTRICT_VIEW_ON', text="").affect_visibility = True
-
+
# Layer main properties
- row = layout.row()
+ row = layout.row()
col = layout.column(align=True)
if gpl:
-
+
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = True
diff --git a/release/scripts/startup/bl_ui/properties_data_lattice.py b/release/scripts/startup/bl_ui/properties_data_lattice.py
index 330844440d0..2193fbb9ffd 100644
--- a/release/scripts/startup/bl_ui/properties_data_lattice.py
+++ b/release/scripts/startup/bl_ui/properties_data_lattice.py
@@ -43,13 +43,10 @@ class DATA_PT_context_lattice(DataButtonsPanel, Panel):
lat = context.lattice
space = context.space_data
- split = layout.split(factor=0.65)
if ob:
- split.template_ID(ob, "data")
- split.separator()
+ layout.template_ID(ob, "data")
elif lat:
- split.template_ID(space, "pin_id")
- split.separator()
+ layout.template_ID(space, "pin_id")
class DATA_PT_lattice(DataButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/properties_data_light.py b/release/scripts/startup/bl_ui/properties_data_light.py
index 376b7561739..6f730cf3307 100644
--- a/release/scripts/startup/bl_ui/properties_data_light.py
+++ b/release/scripts/startup/bl_ui/properties_data_light.py
@@ -175,17 +175,10 @@ class DATA_PT_EEVEE_shadow(DataButtonsPanel, Panel):
col = layout.column()
sub = col.column(align=True)
- sub.prop(light, "shadow_buffer_clip_start", text="Clip Start")
- if light.type == 'SUN':
- sub.prop(light, "shadow_buffer_clip_end", text="End")
-
- col.prop(light, "shadow_buffer_soft", text="Softness")
-
- col.separator()
+ if light.type != 'SUN':
+ sub.prop(light, "shadow_buffer_clip_start", text="Clip Start")
col.prop(light, "shadow_buffer_bias", text="Bias")
- col.prop(light, "shadow_buffer_exp", text="Exponent")
- col.prop(light, "shadow_buffer_bleed_bias", text="Bleed Bias")
class DATA_PT_EEVEE_shadow_cascaded_shadow_map(DataButtonsPanel, Panel):
@@ -245,7 +238,6 @@ class DATA_PT_EEVEE_shadow_contact(DataButtonsPanel, Panel):
col.active = light.use_shadow and light.use_contact_shadow
col.prop(light, "contact_shadow_distance", text="Distance")
- col.prop(light, "contact_shadow_soft_size", text="Softness")
col.prop(light, "contact_shadow_bias", text="Bias")
col.prop(light, "contact_shadow_thickness", text="Thickness")
@@ -335,8 +327,8 @@ classes = (
DATA_PT_EEVEE_light,
DATA_PT_EEVEE_light_distance,
DATA_PT_EEVEE_shadow,
- DATA_PT_EEVEE_shadow_contact,
DATA_PT_EEVEE_shadow_cascaded_shadow_map,
+ DATA_PT_EEVEE_shadow_contact,
DATA_PT_area,
DATA_PT_spot,
DATA_PT_falloff_curve,
diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py
index 47c90199031..51f24007271 100644
--- a/release/scripts/startup/bl_ui/properties_data_mesh.py
+++ b/release/scripts/startup/bl_ui/properties_data_mesh.py
@@ -72,8 +72,8 @@ class MESH_MT_shape_key_context_menu(Menu):
layout.separator()
layout.operator("object.shape_key_remove", icon='X', text="Delete All Shape Keys").all = True
layout.separator()
- layout.operator("object.shape_key_move", icon='TRIA_UP_BAR', text="Move To Top").type = 'TOP'
- layout.operator("object.shape_key_move", icon='TRIA_DOWN_BAR', text="Move To Bottom").type = 'BOTTOM'
+ layout.operator("object.shape_key_move", icon='TRIA_UP_BAR', text="Move to Top").type = 'TOP'
+ layout.operator("object.shape_key_move", icon='TRIA_DOWN_BAR', text="Move to Bottom").type = 'BOTTOM'
class MESH_UL_vgroups(UIList):
@@ -459,6 +459,7 @@ class DATA_PT_vertex_colors(MeshButtonsPanel, Panel):
col.operator("mesh.vertex_color_add", icon='ADD', text="")
col.operator("mesh.vertex_color_remove", icon='REMOVE', text="")
+
class DATA_PT_remesh(MeshButtonsPanel, Panel):
bl_label = "Remesh"
bl_options = {'DEFAULT_CLOSED'}
@@ -467,14 +468,22 @@ class DATA_PT_remesh(MeshButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
- col = layout.column()
+ layout.use_property_decorate = False
+ row = layout.row()
mesh = context.mesh
- col.prop(mesh, "remesh_voxel_size")
- col.prop(mesh, "remesh_smooth_normals")
- col.prop(mesh, "remesh_preserve_paint_mask")
- col.operator("object.voxel_remesh", text="Voxel Remesh")
-
+ row.prop(mesh, "remesh_mode", text="Mode", expand=True)
+ col = layout.column()
+ if (mesh.remesh_mode == 'VOXEL'):
+ col.prop(mesh, "remesh_voxel_size")
+ col.prop(mesh, "remesh_voxel_adaptivity")
+ col.prop(mesh, "remesh_fix_poles")
+ col.prop(mesh, "remesh_smooth_normals")
+ col.prop(mesh, "remesh_preserve_volume")
+ col.prop(mesh, "remesh_preserve_paint_mask")
+ col.operator("object.voxel_remesh", text="Voxel Remesh")
+ else:
+ col.operator("object.quadriflow_remesh", text="QuadriFlow Remesh")
class DATA_PT_customdata(MeshButtonsPanel, Panel):
bl_label = "Geometry Data"
@@ -484,6 +493,7 @@ class DATA_PT_customdata(MeshButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
+ layout.use_property_decorate = False
obj = context.object
me = context.mesh
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index 47c911821fc..124fe77cb52 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -1783,7 +1783,7 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
col.label(text="Material:")
row = col.row(align=True)
-
+
row.prop_search(md, "material", gpd, "materials", text="", icon='SHADING_TEXTURE')
row.prop(md, "invert_materials", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
@@ -2012,15 +2012,19 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
col.prop(md, "factor")
row = layout.row()
- row.prop(md, "create_materials")
- row.prop(md, "modify_color")
+ row.prop(md, "opacity_mode", text="Mode")
- col = layout.column()
- col.separator()
- col.label(text="Vertex Group:")
- row = col.row(align=True)
- row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
- row.prop(md, "invert_vertex", text="", icon='ARROW_LEFTRIGHT')
+ if md.opacity_mode == 'MATERIAL':
+ row = layout.row()
+ row.prop(md, "create_materials")
+ row.prop(md, "modify_color", text="Change")
+ else:
+ col = layout.column()
+ col.separator()
+ col.label(text="Vertex Group:")
+ row = col.row(align=True)
+ row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+ row.prop(md, "invert_vertex", text="", icon='ARROW_LEFTRIGHT')
col = layout.column()
col.separator()
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index 6f089f93f00..ca9c518f443 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -169,8 +169,8 @@ class GreasePencilStrokeEditPanel:
layout.label(text="Edit:")
row = layout.row(align=True)
row.operator("gpencil.copy", text="Copy")
- row.operator("gpencil.paste", text="Paste").type = 'COPY'
- row.operator("gpencil.paste", text="Paste & Merge").type = 'MERGE'
+ row.operator("gpencil.paste", text="Paste").type = 'ACTIVE'
+ row.operator("gpencil.paste", text="Paste by Layer").type = 'LAYER'
col = layout.column(align=True)
col.operator("gpencil.delete")
@@ -311,7 +311,7 @@ class GreasePencilAppearancePanel:
layout.prop(gp_settings, "use_cursor", text="Show Brush")
if brush.gpencil_tool == 'DRAW':
- layout.prop(gp_settings, "show_lasso", text="Show fill color while drawing")
+ layout.prop(gp_settings, "show_lasso", text="Show Fill Color While Drawing")
if brush.gpencil_tool == 'FILL':
layout.prop(brush, "cursor_color_add", text="Color")
@@ -507,8 +507,9 @@ class GPENCIL_MT_pie_tools_more(Menu):
# gpd = context.gpencil_data
col = pie.column(align=True)
- col.operator("gpencil.copy", icon='COPYDOWN', text="Copy")
- col.operator("gpencil.paste", icon='PASTEDOWN', text="Paste")
+ col.operator("gpencil.copy", text="Copy", icon='COPYDOWN')
+ col.operator("gpencil.paste", text="Paste", icon='PASTEDOWN').type = 'ACTIVE'
+ col.operator("gpencil.paste", text="Paste by Layer").type = 'LAYER'
col = pie.column(align=True)
col.operator("gpencil.select_more", icon='ADD')
@@ -590,31 +591,65 @@ class GPENCIL_MT_snap(Menu):
layout.operator("view3d.snap_cursor_to_grid", text="Cursor to Grid")
+class GPENCIL_MT_move_to_layer(Menu):
+ bl_label = "Move to Layer"
+
+ def draw(self, context):
+ layout = self.layout
+ gpd = context.gpencil_data
+ if gpd:
+ gpl_active = context.active_gpencil_layer
+ tot_layers = len(gpd.layers)
+ i = tot_layers - 1
+ while(i >= 0):
+ gpl = gpd.layers[i]
+ if gpl.info == gpl_active.info:
+ icon = 'GREASEPENCIL'
+ else:
+ icon = 'NONE'
+ layout.operator("gpencil.move_to_layer", text=gpl.info, icon=icon).layer = i
+ i -= 1
+
+ layout.separator()
+
+ layout.operator("gpencil.layer_add", text="New Layer", icon='ADD')
+
+
class GPENCIL_MT_gpencil_draw_delete(Menu):
- bl_label = "GPencil Draw Delete"
+ bl_label = "Delete"
def draw(self, _context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
- layout.operator("gpencil.active_frames_delete_all", text="Delete Frame")
+ layout.operator("gpencil.delete", text="Delete Active Keyframe (Active Layer)").type = 'FRAME'
+ layout.operator("gpencil.active_frames_delete_all", text="Delete Active Keyframes (All Layers)")
class GPENCIL_MT_cleanup(Menu):
bl_label = "Clean Up"
def draw(self, _context):
+
+ ob = _context.active_object
+
layout = self.layout
+
layout.operator("gpencil.frame_clean_loose", text="Delete Loose Points")
- layout.operator("gpencil.stroke_merge_by_distance", text="Merge by Distance")
+
+ if ob.mode != 'PAINT_GPENCIL':
+ layout.operator("gpencil.stroke_merge_by_distance", text="Merge by Distance")
+
layout.separator()
layout.operator("gpencil.frame_clean_fill", text="Boundary Strokes").mode = 'ACTIVE'
layout.operator("gpencil.frame_clean_fill", text="Boundary Strokes all Frames").mode = 'ALL'
- layout.separator()
- layout.operator("gpencil.reproject")
+ if ob.mode != 'PAINT_GPENCIL':
+ layout.separator()
+
+ layout.operator("gpencil.reproject")
class GPENCIL_UL_annotation_layer(UIList):
@@ -857,7 +892,8 @@ class GreasePencilMaterialsPanel:
if is_view3d and brush is not None:
gp_settings = brush.gpencil_settings
if gp_settings.use_material_pin is False:
- ma = ob.material_slots[ob.active_material_index].material
+ if ob.active_material_index > 0:
+ ma = ob.material_slots[ob.active_material_index].material
else:
ma = gp_settings.material
@@ -914,6 +950,32 @@ class GPENCIL_UL_layer(UIList):
icon_value=icon,
)
+class GreasePencilSimplifyPanel:
+
+ def draw_header(self, context):
+ rd = context.scene.render
+ self.layout.prop(rd, "simplify_gpencil", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ rd = context.scene.render
+
+ layout.active = rd.simplify_gpencil
+
+ col = layout.column()
+ col.prop(rd, "simplify_gpencil_onplay", text="Playback Only")
+ col.prop(rd, "simplify_gpencil_view_modifier", text="Modifiers")
+ col.prop(rd, "simplify_gpencil_shader_fx", text="ShaderFX")
+ col.prop(rd, "simplify_gpencil_blend", text="Layers Blending")
+ col.prop(rd, "simplify_gpencil_tint", text="Layers Tinting")
+
+ col.prop(rd, "simplify_gpencil_view_fill")
+ sub = col.column()
+ sub.active = rd.simplify_gpencil_view_fill
+ sub.prop(rd, "simplify_gpencil_remove_lines", text="Lines")
classes = (
GPENCIL_MT_pie_tool_palette,
@@ -923,6 +985,7 @@ classes = (
GPENCIL_MT_snap,
GPENCIL_MT_cleanup,
+ GPENCIL_MT_move_to_layer,
GPENCIL_MT_gpencil_draw_delete,
diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py
index f3c34cf4660..0849437b680 100644
--- a/release/scripts/startup/bl_ui/properties_material.py
+++ b/release/scripts/startup/bl_ui/properties_material.py
@@ -202,33 +202,47 @@ class EEVEE_MATERIAL_PT_volume(MaterialButtonsPanel, Panel):
panel_node_draw(layout, mat.node_tree, 'OUTPUT_MATERIAL', "Volume")
+def draw_material_settings(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ mat = context.material
+
+ layout.prop(mat, "use_backface_culling")
+ layout.prop(mat, "blend_method")
+ layout.prop(mat, "shadow_method")
+
+ row = layout.row()
+ row.active = ((mat.blend_method == 'CLIP') or (mat.shadow_method == 'CLIP'))
+ row.prop(mat, "alpha_threshold")
+
+ if mat.blend_method not in {'OPAQUE', 'CLIP', 'HASHED'}:
+ layout.prop(mat, "show_transparent_back")
+
+ layout.prop(mat, "use_screen_refraction")
+ layout.prop(mat, "refraction_depth")
+ layout.prop(mat, "use_sss_translucency")
+ layout.prop(mat, "pass_index")
+
+
class EEVEE_MATERIAL_PT_settings(MaterialButtonsPanel, Panel):
bl_label = "Settings"
bl_context = "material"
COMPAT_ENGINES = {'BLENDER_EEVEE'}
def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- layout.use_property_decorate = False
-
- mat = context.material
-
- layout.prop(mat, "use_backface_culling")
- layout.prop(mat, "blend_method")
- layout.prop(mat, "shadow_method")
+ draw_material_settings(self, context)
- row = layout.row()
- row.active = ((mat.blend_method == 'CLIP') or (mat.shadow_method == 'CLIP'))
- row.prop(mat, "alpha_threshold")
- if mat.blend_method not in {'OPAQUE', 'CLIP', 'HASHED'}:
- layout.prop(mat, "show_transparent_back")
+class EEVEE_MATERIAL_PT_viewport_settings(MaterialButtonsPanel, Panel):
+ bl_label = "Settings"
+ bl_context = "material"
+ bl_parent_id = "MATERIAL_PT_viewport"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
- layout.prop(mat, "use_screen_refraction")
- layout.prop(mat, "refraction_depth")
- layout.prop(mat, "use_sss_translucency")
- layout.prop(mat, "pass_index")
+ def draw(self, context):
+ draw_material_settings(self, context)
class MATERIAL_PT_viewport(MaterialButtonsPanel, Panel):
@@ -263,6 +277,7 @@ classes = (
EEVEE_MATERIAL_PT_volume,
EEVEE_MATERIAL_PT_settings,
MATERIAL_PT_viewport,
+ EEVEE_MATERIAL_PT_viewport_settings,
MATERIAL_PT_custom_props,
)
diff --git a/release/scripts/startup/bl_ui/properties_material_gpencil.py b/release/scripts/startup/bl_ui/properties_material_gpencil.py
index 2deff845994..02aec00edf6 100644
--- a/release/scripts/startup/bl_ui/properties_material_gpencil.py
+++ b/release/scripts/startup/bl_ui/properties_material_gpencil.py
@@ -48,6 +48,7 @@ class GPENCIL_MT_color_context_menu(Menu):
layout.operator("object.material_slot_remove_unused")
+
class GPENCIL_UL_matslots(UIList):
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
slot = item
@@ -164,6 +165,7 @@ class MATERIAL_PT_gpencil_strokecolor(GPMaterialButtonsPanel, Panel):
if gpcolor.mode == 'LINE' and gpcolor.stroke_style != 'TEXTURE':
col.prop(gpcolor, "use_overlap_strokes")
+
class MATERIAL_PT_gpencil_fillcolor(GPMaterialButtonsPanel, Panel):
bl_label = "Fill"
bl_parent_id = 'MATERIAL_PT_gpencil_surface'
@@ -218,7 +220,7 @@ class MATERIAL_PT_gpencil_fillcolor(GPMaterialButtonsPanel, Panel):
col.template_ID(gpcolor, "fill_image", open="image.open")
if gpcolor.fill_style == 'TEXTURE':
- col.prop(gpcolor, "use_fill_pattern", text="Use As Stencil Mask")
+ col.prop(gpcolor, "use_fill_pattern", text="Use as Stencil Mask")
if gpcolor.use_fill_pattern is True:
col.prop(gpcolor, "fill_color", text="Color")
@@ -229,7 +231,7 @@ class MATERIAL_PT_gpencil_fillcolor(GPMaterialButtonsPanel, Panel):
col.prop(gpcolor, "texture_clamp", text="Clip Image")
if gpcolor.use_fill_pattern is False:
- col.prop(gpcolor, "use_fill_texture_mix", text="Mix With Color")
+ col.prop(gpcolor, "use_fill_texture_mix", text="Mix with Color")
if gpcolor.use_fill_texture_mix is True:
col.prop(gpcolor, "fill_color", text="Mix Color")
@@ -274,7 +276,8 @@ class MATERIAL_PT_gpencil_material_presets(PresetPanel, Panel):
preset_add_operator = "scene.gpencil_material_preset_add"
-classes = (GPENCIL_UL_matslots,
+classes = (
+ GPENCIL_UL_matslots,
GPENCIL_MT_color_context_menu,
MATERIAL_PT_gpencil_slots,
MATERIAL_PT_gpencil_preview,
@@ -283,7 +286,8 @@ classes = (GPENCIL_UL_matslots,
MATERIAL_PT_gpencil_strokecolor,
MATERIAL_PT_gpencil_fillcolor,
MATERIAL_PT_gpencil_options,
- MATERIAL_PT_gpencil_custom_props,)
+ MATERIAL_PT_gpencil_custom_props,
+)
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
diff --git a/release/scripts/startup/bl_ui/properties_object.py b/release/scripts/startup/bl_ui/properties_object.py
index 7424c090764..d2ba047e07e 100644
--- a/release/scripts/startup/bl_ui/properties_object.py
+++ b/release/scripts/startup/bl_ui/properties_object.py
@@ -109,20 +109,18 @@ class OBJECT_PT_delta_transform(ObjectButtonsPanel, Panel):
ob = context.object
- col = flow.column()
- col.prop(ob, "delta_location")
+ col = layout.column()
+ col.prop(ob, "delta_location", text="Location")
- col = flow.column()
rotation_mode = ob.rotation_mode
if rotation_mode == 'QUATERNION':
col.prop(ob, "delta_rotation_quaternion", text="Rotation")
elif rotation_mode == 'AXIS_ANGLE':
- col.label(text="Not for Axis-Angle")
+ pass
else:
- col.prop(ob, "delta_rotation_euler", text="Delta Rotation")
+ col.prop(ob, "delta_rotation_euler", text="Rotation")
- col = flow.column()
- col.prop(ob, "delta_scale")
+ col.prop(ob, "delta_scale", text="Scale")
class OBJECT_PT_relations(ObjectButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py
index ebbf278c5e7..076b1f2592c 100644
--- a/release/scripts/startup/bl_ui/properties_particle.py
+++ b/release/scripts/startup/bl_ui/properties_particle.py
@@ -960,10 +960,10 @@ class PARTICLE_PT_physics_relations(ParticleButtonsPanel, Panel):
#col.alert = key.valid
col.prop(key, "object")
col.prop(key, "system", text="System")
-
- col.active = psys.use_keyed_timing
- col.prop(key, "time")
- col.prop(key, "duration")
+ sub = col.column(align=True)
+ sub.active = psys.use_keyed_timing
+ sub.prop(key, "time")
+ sub.prop(key, "duration")
elif part.physics_type == 'BOIDS':
sub = layout.column()
# doesn't work yet
@@ -1091,14 +1091,13 @@ class PARTICLE_PT_physics_integration(ParticleButtonsPanel, Panel):
col.prop(part, "integrator")
col.prop(part, "timestep")
- sub = col.row()
- sub.prop(part, "subframes")
- supports_courant = part.physics_type == 'FLUID'
- subsub = sub.row()
- subsub.enabled = supports_courant
- subsub.prop(part, "use_adaptive_subframes", text="")
- if supports_courant and part.use_adaptive_subframes:
- col.prop(part, "courant_target", text="Threshold")
+ col.prop(part, "subframes")
+
+ if part.physics_type == 'FLUID':
+ col.prop(part, "use_adaptive_subframes", text="Adaptive")
+ sub = col.row()
+ sub.enabled = part.use_adaptive_subframes
+ sub.prop(part, "courant_target", text="Threshold")
class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel):
@@ -1122,33 +1121,28 @@ class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
boids = particle_get_settings(context).boids
layout.enabled = particle_panel_enabled(context, context.particle_system)
# Currently boids can only use the first state so these are commented out for now.
- #row = layout.row()
+ # row = layout.row()
# row.template_list("UI_UL_list", "particle_boids", boids, "states",
- # boids, "active_boid_state_index", compact="True")
- #col = row.row()
- #sub = col.row(align=True)
- #sub.operator("boid.state_add", icon='ADD', text="")
- #sub.operator("boid.state_del", icon='REMOVE', text="")
- #sub = row.row(align=True)
- #sub.operator("boid.state_move_up", icon='TRIA_UP', text="")
- #sub.operator("boid.state_move_down", icon='TRIA_DOWN', text="")
+ # boids, "active_boid_state_index", compact="True")
+ # col = row.row()
+ # sub = col.row(align=True)
+ # sub.operator("boid.state_add", icon='ADD', text="")
+ # sub.operator("boid.state_del", icon='REMOVE', text="")
+ # sub = row.row(align=True)
+ # sub.operator("boid.state_move_up", icon='TRIA_UP', text="")
+ # sub.operator("boid.state_move_down", icon='TRIA_DOWN', text="")
state = boids.active_boid_state
- #layout.prop(state, "name", text="State name")
-
- row = layout.row()
- row.prop(state, "ruleset_type")
- if state.ruleset_type == 'FUZZY':
- row.prop(state, "rule_fuzzy", slider=True)
- else:
- row.label(text="")
+ # layout.prop(state, "name", text="State name")
row = layout.row()
row.template_list("UI_UL_list", "particle_boids_rules", state,
@@ -1164,47 +1158,46 @@ class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel):
subsub.operator("boid.rule_move_up", icon='TRIA_UP', text="")
subsub.operator("boid.rule_move_down", icon='TRIA_DOWN', text="")
+ layout.prop(state, "ruleset_type")
+ if state.ruleset_type == 'FUZZY':
+ layout.prop(state, "rule_fuzzy", slider=True)
+
rule = state.active_boid_rule
if rule:
- row = layout.row()
- row.prop(rule, "name", text="")
- # somebody make nice icons for boids here please! -jahka
- row.prop(rule, "use_in_air", icon='TRIA_UP', text="")
- row.prop(rule, "use_on_land", icon='TRIA_DOWN', text="")
+ col = layout.column(align=True)
+ col.prop(rule, "use_in_air")
+ col.prop(rule, "use_on_land")
- row = layout.row()
+ col = layout.column()
if rule.type == 'GOAL':
- row.prop(rule, "object")
- row = layout.row()
- row.prop(rule, "use_predict")
+ col.prop(rule, "object")
+ col.prop(rule, "use_predict")
elif rule.type == 'AVOID':
- row.prop(rule, "object")
- row = layout.row()
- row.prop(rule, "use_predict")
- row.prop(rule, "fear_factor")
+ col.prop(rule, "object")
+ col.prop(rule, "use_predict")
+ col.prop(rule, "fear_factor")
elif rule.type == 'FOLLOW_PATH':
- row.label(text="Not yet functional")
+ col.label(text="Not yet functional")
elif rule.type == 'AVOID_COLLISION':
- row.prop(rule, "use_avoid")
- row.prop(rule, "use_avoid_collision")
- row.prop(rule, "look_ahead")
+ col.prop(rule, "use_avoid")
+ col.prop(rule, "use_avoid_collision")
+ col.prop(rule, "look_ahead")
elif rule.type == 'FOLLOW_LEADER':
- row.prop(rule, "object", text="")
- row.prop(rule, "distance")
- row = layout.row()
- row.prop(rule, "use_line")
- sub = row.row()
- sub.active = rule.line
+ col.prop(rule, "object")
+ col.prop(rule, "distance")
+ col.prop(rule, "use_line")
+ sub = col.row()
+ sub.active = rule.use_line
sub.prop(rule, "queue_count")
elif rule.type == 'AVERAGE_SPEED':
- row.prop(rule, "speed", slider=True)
- row.prop(rule, "wander", slider=True)
- row.prop(rule, "level", slider=True)
+ col.prop(rule, "speed", slider=True)
+ col.prop(rule, "wander", slider=True)
+ col.prop(rule, "level", slider=True)
elif rule.type == 'FIGHT':
- row.prop(rule, "distance")
- row.prop(rule, "flee_distance")
+ col.prop(rule, "distance")
+ col.prop(rule, "flee_distance")
class PARTICLE_PT_render(ParticleButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index 92b649e863c..b4c864c16cd 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -25,6 +25,8 @@ from bl_ui.space_view3d import (
VIEW3D_PT_shading_options,
)
+from bl_ui.properties_grease_pencil_common import GreasePencilSimplifyPanel
+
class RenderButtonsPanel:
bl_space_type = 'PROPERTIES'
@@ -314,7 +316,6 @@ class RENDER_PT_eevee_subsurface_scattering(RenderButtonsPanel, Panel):
col = layout.column()
col.prop(props, "sss_samples")
col.prop(props, "sss_jitter_threshold")
- col.prop(props, "use_sss_separate_albedo")
class RENDER_PT_eevee_screen_space_reflections(RenderButtonsPanel, Panel):
@@ -366,7 +367,6 @@ class RENDER_PT_eevee_shadows(RenderButtonsPanel, Panel):
props = scene.eevee
col = layout.column()
- col.prop(props, "shadow_method")
col.prop(props, "shadow_cube_size", text="Cube Size")
col.prop(props, "shadow_cascade_size", text="Cascade Size")
col.prop(props, "use_shadow_high_bitdepth")
@@ -655,36 +655,12 @@ class RENDER_PT_simplify_render(RenderButtonsPanel, Panel):
col.prop(rd, "simplify_child_particles_render", text="Max Child Particles")
-class RENDER_PT_simplify_greasepencil(RenderButtonsPanel, Panel):
+class RENDER_PT_simplify_greasepencil(RenderButtonsPanel, Panel, GreasePencilSimplifyPanel):
bl_label = "Grease Pencil"
bl_parent_id = "RENDER_PT_simplify"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
bl_options = {'DEFAULT_CLOSED'}
- def draw_header(self, context):
- rd = context.scene.render
- self.layout.prop(rd, "simplify_gpencil", text="")
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- layout.use_property_decorate = False
-
- rd = context.scene.render
-
- layout.active = rd.simplify_gpencil
-
- col = layout.column()
- col.prop(rd, "simplify_gpencil_onplay", text="Playback Only")
- col.prop(rd, "simplify_gpencil_view_modifier", text="Modifiers")
- col.prop(rd, "simplify_gpencil_shader_fx", text="ShaderFX")
- col.prop(rd, "simplify_gpencil_blend", text="Layers Blending")
-
- col.prop(rd, "simplify_gpencil_view_fill")
- sub = col.column()
- sub.active = rd.simplify_gpencil_view_fill
- sub.prop(rd, "simplify_gpencil_remove_lines", text="Lines")
-
classes = (
RENDER_PT_context,
diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py
index 60a7751e910..0b4ca2902c1 100644
--- a/release/scripts/startup/bl_ui/properties_scene.py
+++ b/release/scripts/startup/bl_ui/properties_scene.py
@@ -63,7 +63,7 @@ class SCENE_PT_scene(SceneButtonsPanel, Panel):
layout.prop(scene, "camera")
layout.prop(scene, "background_set")
- layout.prop(scene, "active_clip")
+ layout.prop(scene, "active_clip", text="Active Clip")
class SCENE_PT_unit(SceneButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index 4edda9b2460..b5154e72de6 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -1221,7 +1221,7 @@ class CLIP_PT_tools_grease_pencil_draw(AnnotationDrawingToolsPanel, Panel):
class CLIP_MT_view_zoom(Menu):
bl_label = "Fractional Zoom"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
ratios = ((1, 8), (1, 4), (1, 2), (1, 1), (2, 1), (4, 1), (8, 1))
@@ -1255,16 +1255,17 @@ class CLIP_MT_view(Menu):
layout.operator("clip.view_selected")
layout.operator("clip.view_all")
layout.operator("clip.view_all", text="View Fit").fit_view = True
+ layout.operator("clip.view_center_cursor")
layout.separator()
-
+
layout.operator("clip.view_zoom_in")
layout.operator("clip.view_zoom_out")
layout.separator()
-
+
layout.prop(sc, "show_metadata")
-
+
layout.separator()
layout.menu("CLIP_MT_view_zoom")
diff --git a/release/scripts/startup/bl_ui/space_console.py b/release/scripts/startup/bl_ui/space_console.py
index 2db1b06c902..54a72cf59d0 100644
--- a/release/scripts/startup/bl_ui/space_console.py
+++ b/release/scripts/startup/bl_ui/space_console.py
@@ -125,10 +125,11 @@ class CONSOLE_MT_console(Menu):
layout.operator("console.autocomplete", text="Autocomplete")
+
class CONSOLE_MT_context_menu(Menu):
bl_label = "Console Context Menu"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.operator("console.clear")
diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py
index b939586ff81..a322b96f9dd 100644
--- a/release/scripts/startup/bl_ui/space_filebrowser.py
+++ b/release/scripts/startup/bl_ui/space_filebrowser.py
@@ -33,59 +33,133 @@ class FILEBROWSER_HT_header(Header):
layout.template_header()
layout.menu("FILEBROWSER_MT_view")
+ layout.menu("FILEBROWSER_MT_select")
- row = layout.row(align=True)
- row.operator("file.previous", text="", icon='BACK')
- row.operator("file.next", text="", icon='FORWARD')
- row.operator("file.parent", text="", icon='FILE_PARENT')
- row.operator("file.refresh", text="", icon='FILE_REFRESH')
+ # can be None when save/reload with a file selector open
+
+ layout.separator_spacer()
+
+ layout.template_running_jobs()
- layout.operator_context = 'EXEC_DEFAULT'
- layout.operator("file.directory_new", icon='NEWFOLDER', text="")
- layout.operator_context = 'INVOKE_DEFAULT'
+class FILEBROWSER_PT_display(Panel):
+ bl_space_type = 'FILE_BROWSER'
+ bl_region_type = 'HEADER'
+ bl_label = "Display"
+ @classmethod
+ def poll(cls, context):
# can be None when save/reload with a file selector open
- if params:
- is_lib_browser = params.use_library_browsing
+ return context.space_data.params is not None
- layout.prop(params, "display_type", expand=True, text="")
- layout.prop(params, "sort_method", expand=True, text="")
- layout.prop(params, "show_hidden", text="", icon='FILE_HIDDEN')
+ def draw(self, context):
+ layout = self.layout
- layout.separator_spacer()
+ space = context.space_data
+ params = space.params
+ is_lib_browser = params.use_library_browsing
- layout.template_running_jobs()
+ layout.label(text="Display as")
+ layout.column().prop(params, "display_type", expand=True)
- if params:
- layout.prop(params, "use_filter", text="", icon='FILTER')
+ layout.use_property_split = True
+ layout.use_property_decorate = False # No animation.
- row = layout.row(align=True)
- row.active = params.use_filter
- row.prop(params, "use_filter_folder", text="")
+ if params.display_type == 'THUMBNAIL':
+ layout.prop(params, "display_size", text="Size")
+ else:
+ layout.prop(params, "show_details_size", text="Size")
+ layout.prop(params, "show_details_datetime", text="Date")
- if params.filter_glob:
- # if st.active_operator and hasattr(st.active_operator, "filter_glob"):
- # row.prop(params, "filter_glob", text="")
- row.label(text=params.filter_glob)
- else:
- row.prop(params, "use_filter_blender", text="")
- row.prop(params, "use_filter_backup", text="")
- row.prop(params, "use_filter_image", text="")
- row.prop(params, "use_filter_movie", text="")
- row.prop(params, "use_filter_script", text="")
- row.prop(params, "use_filter_font", text="")
- row.prop(params, "use_filter_sound", text="")
- row.prop(params, "use_filter_text", text="")
+ layout.prop(params, "recursion_level", text="Recursions")
+
+ layout.use_property_split = False
+ layout.separator()
+
+ layout.label(text="Sort by")
+ layout.column().prop(params, "sort_method", expand=True)
+ layout.prop(params, "use_sort_invert")
+
+
+class FILEBROWSER_PT_filter(Panel):
+ bl_space_type = 'FILE_BROWSER'
+ bl_region_type = 'HEADER'
+ bl_label = "Filter"
+
+ @classmethod
+ def poll(cls, context):
+ # can be None when save/reload with a file selector open
+ return context.space_data.params is not None
+
+ def draw(self, context):
+ layout = self.layout
+
+ space = context.space_data
+ params = space.params
+ is_lib_browser = params.use_library_browsing
- if is_lib_browser:
- row.prop(params, "use_filter_blendid", text="")
- if params.use_filter_blendid:
- row.separator()
- row.prop(params, "filter_id_category", text="")
+ row = layout.row(align=True)
+ row.prop(params, "use_filter", text="", toggle=0)
+ row.label(text="Filter")
- row.separator()
- row.prop(params, "filter_search", text="", icon='VIEWZOOM')
+ col = layout.column()
+ col.active = params.use_filter
+
+ row = col.row()
+ row.label(icon='FILE_FOLDER')
+ row.prop(params, "use_filter_folder", text="Folders", toggle=0)
+
+ if params.filter_glob:
+ col.label(text=params.filter_glob)
+ else:
+ row = col.row()
+ row.label(icon='FILE_BLEND')
+ row.prop(params, "use_filter_blender",
+ text=".blend Files", toggle=0)
+ row = col.row()
+ row.label(icon='FILE_BACKUP')
+ row.prop(params, "use_filter_backup",
+ text="Backup .blend Files", toggle=0)
+ row = col.row()
+ row.label(icon='FILE_IMAGE')
+ row.prop(params, "use_filter_image", text="Image Files", toggle=0)
+ row = col.row()
+ row.label(icon='FILE_MOVIE')
+ row.prop(params, "use_filter_movie", text="Movie Files", toggle=0)
+ row = col.row()
+ row.label(icon='FILE_SCRIPT')
+ row.prop(params, "use_filter_script",
+ text="Script Files", toggle=0)
+ row = col.row()
+ row.label(icon='FILE_FONT')
+ row.prop(params, "use_filter_font", text="Font Files", toggle=0)
+ row = col.row()
+ row.label(icon='FILE_SOUND')
+ row.prop(params, "use_filter_sound", text="Sound Files", toggle=0)
+ row = col.row()
+ row.label(icon='FILE_TEXT')
+ row.prop(params, "use_filter_text", text="Text Files", toggle=0)
+
+ col.separator()
+
+ if is_lib_browser:
+ row = col.row()
+ row.label(icon='BLANK1') # Indentation
+ row.prop(params, "use_filter_blendid",
+ text="Blender IDs", toggle=0)
+ if params.use_filter_blendid:
+ row = col.row()
+ row.label(icon='BLANK1') # Indentation
+ row.prop(params, "filter_id_category", text="")
+
+ col.separator()
+
+ layout.prop(params, "show_hidden")
+
+
+def panel_poll_is_upper_region(region):
+ # The upper region is left-aligned, the lower is split into it then. Note that after "Flip Regions" it's right-aligned.
+ return region.alignment in {'LEFT', 'RIGHT'}
class FILEBROWSER_UL_dir(UIList):
@@ -119,10 +193,13 @@ class FILEBROWSER_UL_dir(UIList):
class FILEBROWSER_PT_bookmarks_volumes(Panel):
bl_space_type = 'FILE_BROWSER'
bl_region_type = 'TOOLS'
- bl_options = {'DEFAULT_CLOSED'}
bl_category = "Bookmarks"
bl_label = "Volumes"
+ @classmethod
+ def poll(cls, context):
+ return panel_poll_is_upper_region(context.region)
+
def draw(self, context):
layout = self.layout
space = context.space_data
@@ -141,7 +218,7 @@ class FILEBROWSER_PT_bookmarks_system(Panel):
@classmethod
def poll(cls, context):
- return not context.preferences.filepaths.hide_system_bookmarks
+ return not context.preferences.filepaths.hide_system_bookmarks and panel_poll_is_upper_region(context.region)
def draw(self, context):
layout = self.layout
@@ -161,8 +238,10 @@ class FILEBROWSER_MT_bookmarks_context_menu(Menu):
layout.operator("file.bookmark_cleanup", icon='X', text="Cleanup")
layout.separator()
- layout.operator("file.bookmark_move", icon='TRIA_UP_BAR', text="Move To Top").direction = 'TOP'
- layout.operator("file.bookmark_move", icon='TRIA_DOWN_BAR', text="Move To Bottom").direction = 'BOTTOM'
+ layout.operator("file.bookmark_move", icon='TRIA_UP_BAR',
+ text="Move to Top").direction = 'TOP'
+ layout.operator("file.bookmark_move", icon='TRIA_DOWN_BAR',
+ text="Move to Bottom").direction = 'BOTTOM'
class FILEBROWSER_PT_bookmarks_favorites(Panel):
@@ -171,6 +250,10 @@ class FILEBROWSER_PT_bookmarks_favorites(Panel):
bl_category = "Bookmarks"
bl_label = "Favorites"
+ @classmethod
+ def poll(cls, context):
+ return panel_poll_is_upper_region(context.region)
+
def draw(self, context):
layout = self.layout
space = context.space_data
@@ -185,12 +268,15 @@ class FILEBROWSER_PT_bookmarks_favorites(Panel):
col = row.column(align=True)
col.operator("file.bookmark_add", icon='ADD', text="")
col.operator("file.bookmark_delete", icon='REMOVE', text="")
- col.menu("FILEBROWSER_MT_bookmarks_context_menu", icon='DOWNARROW_HLT', text="")
+ col.menu("FILEBROWSER_MT_bookmarks_context_menu",
+ icon='DOWNARROW_HLT', text="")
if num_rows > 1:
col.separator()
- col.operator("file.bookmark_move", icon='TRIA_UP', text="").direction = 'UP'
- col.operator("file.bookmark_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
+ col.operator("file.bookmark_move", icon='TRIA_UP',
+ text="").direction = 'UP'
+ col.operator("file.bookmark_move", icon='TRIA_DOWN',
+ text="").direction = 'DOWN'
else:
layout.operator("file.bookmark_add", icon='ADD')
@@ -203,7 +289,7 @@ class FILEBROWSER_PT_bookmarks_recents(Panel):
@classmethod
def poll(cls, context):
- return not context.preferences.filepaths.hide_recent_locations
+ return not context.preferences.filepaths.hide_recent_locations and panel_poll_is_upper_region(context.region)
def draw(self, context):
layout = self.layout
@@ -227,7 +313,7 @@ class FILEBROWSER_PT_advanced_filter(Panel):
@classmethod
def poll(cls, context):
# only useful in append/link (library) context currently...
- return context.space_data.params.use_library_browsing
+ return context.space_data.params.use_library_browsing and panel_poll_is_upper_region(context.region)
def draw(self, context):
layout = self.layout
@@ -242,6 +328,87 @@ class FILEBROWSER_PT_advanced_filter(Panel):
col.prop(params, "filter_id")
+class FILEBROWSER_PT_directory_path(Panel):
+ bl_space_type = 'FILE_BROWSER'
+ bl_region_type = 'UI'
+ bl_label = "Directory Path"
+ bl_category = "Attributes"
+ bl_options = {'HIDE_HEADER'}
+
+ def is_header_visible(self, context):
+ for region in context.area.regions:
+ if region.type == 'HEADER' and region.height <= 1:
+ return False
+
+ return True
+
+ def is_option_region_visible(self, context, space):
+ if not space.active_operator:
+ return False
+
+ for region in context.area.regions:
+ if region.type == 'TOOL_PROPS' and region.width <= 1:
+ return False
+
+ return True
+
+ def draw(self, context):
+ layout = self.layout
+ space = context.space_data
+ params = space.params
+
+ layout.scale_x = 1.3
+ layout.scale_y = 1.3
+
+ row = layout.row()
+ flow = row.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=False)
+
+ subrow = flow.row()
+
+ subsubrow = subrow.row(align=True)
+ subsubrow.operator("file.previous", text="", icon='BACK')
+ subsubrow.operator("file.next", text="", icon='FORWARD')
+ subsubrow.operator("file.parent", text="", icon='FILE_PARENT')
+ subsubrow.operator("file.refresh", text="", icon='FILE_REFRESH')
+
+ subsubrow = subrow.row()
+ subsubrow.operator_context = 'EXEC_DEFAULT'
+ subsubrow.operator("file.directory_new", icon='NEWFOLDER', text="")
+
+ subrow.template_file_select_path(params)
+
+ subrow = flow.row()
+
+ subsubrow = subrow.row()
+ subsubrow.scale_x = 0.6
+ subsubrow.prop(params, "filter_search", text="", icon='VIEWZOOM')
+
+ # Uses prop_with_popover() as popover() only adds the triangle icon in headers.
+ subrow.prop_with_popover(
+ params,
+ "display_type",
+ panel="FILEBROWSER_PT_display",
+ text="",
+ icon_only=True,
+ )
+ subrow.prop_with_popover(
+ params,
+ "display_type",
+ panel="FILEBROWSER_PT_filter",
+ text="",
+ icon='FILTER',
+ icon_only=True,
+ )
+
+ if space.active_operator:
+ subrow.operator(
+ "screen.region_toggle",
+ text="",
+ icon='PREFERENCES',
+ depress=self.is_option_region_visible(context, space)
+ ).region_type = 'TOOL_PROPS'
+
+
class FILEBROWSER_MT_view(Menu):
bl_label = "View"
@@ -250,7 +417,7 @@ class FILEBROWSER_MT_view(Menu):
st = context.space_data
params = st.params
- layout.prop(st, "show_region_toolbar")
+ layout.prop(st, "show_region_toolbar", text="Source List")
layout.prop(st, "show_region_ui", text="File Path")
layout.separator()
@@ -263,8 +430,64 @@ class FILEBROWSER_MT_view(Menu):
layout.menu("INFO_MT_area")
+class FILEBROWSER_MT_select(Menu):
+ bl_label = "Select"
+
+ def draw(self, context):
+ layout = self.layout
+ st = context.space_data
+
+ layout.operator("file.select_all", text="All").action = 'SELECT'
+ layout.operator("file.select_all", text="None").action = 'DESELECT'
+ layout.operator("file.select_all", text="Inverse").action = 'INVERT'
+
+ layout.separator()
+
+ layout.operator("file.select_box")
+
+
+class FILEBROWSER_MT_context_menu(Menu):
+ bl_label = "Files Context Menu"
+
+ def draw(self, context):
+ layout = self.layout
+ st = context.space_data
+ params = st.params
+
+ layout.operator("file.previous", text="Back")
+ layout.operator("file.next", text="Forward")
+ layout.operator("file.parent", text="Go to Parent")
+ layout.operator("file.refresh", text="Refresh")
+
+ layout.separator()
+
+ layout.operator("file.filenum", text="Increase Number",
+ icon='ADD').increment = 1
+ layout.operator("file.filenum", text="Decrease Number",
+ icon='REMOVE').increment = -1
+
+ layout.separator()
+
+ layout.operator("file.rename", text="Rename")
+ # layout.operator("file.delete")
+ sub = layout.row()
+ sub.operator_context = 'EXEC_DEFAULT'
+ sub.operator("file.directory_new", text="New Folder")
+ layout.operator("file.bookmark_add", text="Add Bookmark")
+
+ layout.separator()
+
+ layout.prop_menu_enum(params, "display_type")
+ if params.display_type == 'THUMBNAIL':
+ layout.prop_menu_enum(params, "display_size")
+ layout.prop_menu_enum(params, "recursion_level", text="Recursions")
+ layout.prop_menu_enum(params, "sort_method")
+
+
classes = (
FILEBROWSER_HT_header,
+ FILEBROWSER_PT_display,
+ FILEBROWSER_PT_filter,
FILEBROWSER_UL_dir,
FILEBROWSER_PT_bookmarks_volumes,
FILEBROWSER_PT_bookmarks_system,
@@ -272,7 +495,10 @@ classes = (
FILEBROWSER_PT_bookmarks_favorites,
FILEBROWSER_PT_bookmarks_recents,
FILEBROWSER_PT_advanced_filter,
+ FILEBROWSER_PT_directory_path,
FILEBROWSER_MT_view,
+ FILEBROWSER_MT_select,
+ FILEBROWSER_MT_context_menu,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index f24971347e1..aaa73b2c864 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -113,6 +113,8 @@ class IMAGE_MT_view(Menu):
layout.operator("image.view_all", text="Frame All")
layout.operator("image.view_all", text="Frame All Fit").fit_view = True
+ layout.operator("image.view_center_cursor", text="Center View to Cursor")
+
layout.separator()
if show_render:
@@ -238,6 +240,7 @@ class IMAGE_MT_image(Menu):
layout.separator()
layout.menu("IMAGE_MT_image_invert")
+ layout.operator("image.resize", text="Resize")
if ima and not show_render:
if ima.packed_file:
@@ -961,7 +964,6 @@ class IMAGE_PT_view_display_uv_edit_overlays(Panel):
col = layout.column()
col.prop(uvedit, "edge_display_type", text="Display As")
- col.prop(uvedit, "show_edges", text="Edges")
col.prop(uvedit, "show_faces", text="Faces")
col = layout.column()
diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py
index eabf71365d5..82ed701aa4c 100644
--- a/release/scripts/startup/bl_ui/space_info.py
+++ b/release/scripts/startup/bl_ui/space_info.py
@@ -34,7 +34,7 @@ class INFO_MT_editor_menus(Menu):
bl_idname = "INFO_MT_editor_menus"
bl_label = ""
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.menu("INFO_MT_view")
layout.menu("INFO_MT_info")
@@ -43,7 +43,7 @@ class INFO_MT_editor_menus(Menu):
class INFO_MT_view(Menu):
bl_label = "View"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.menu("INFO_MT_area")
@@ -52,7 +52,7 @@ class INFO_MT_view(Menu):
class INFO_MT_info(Menu):
bl_label = "Info"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.operator("info.select_all", text="Select All").action = 'SELECT'
@@ -107,12 +107,13 @@ class INFO_MT_area(Menu):
class INFO_MT_context_menu(Menu):
bl_label = "Info Context Menu"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.operator("info.report_copy", text="Copy")
layout.operator("info.report_delete", text="Delete")
+
classes = (
INFO_HT_header,
INFO_MT_editor_menus,
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index d5f7f0ae498..a942b8769cf 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -187,7 +187,7 @@ class SEQUENCER_MT_range(Menu):
class SEQUENCER_MT_preview_zoom(Menu):
bl_label = "Fractional Zoom"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_PREVIEW'
@@ -502,6 +502,10 @@ class SEQUENCER_MT_add(Menu):
col.menu("SEQUENCER_MT_add_transitions", icon='ARROW_LEFTRIGHT')
col.enabled = selected_sequences_len(context) >= 2
+ col = layout.column()
+ col.operator_menu_enum("sequencer.fades_add", "type", text="Fade", icon="IPO_EASE_IN_OUT")
+ col.enabled = selected_sequences_len(context) >= 1
+
class SEQUENCER_MT_add_empty(Menu):
bl_label = "Empty"
@@ -749,26 +753,33 @@ class SEQUENCER_MT_context_menu(Menu):
layout.operator("sequencer.gap_remove").all = False
layout.operator("sequencer.gap_insert")
+ layout.separator()
+
strip = act_strip(context)
if strip:
strip_type = strip.type
+ selected_sequences_count = selected_sequences_len(context)
if strip_type != 'SOUND':
-
layout.separator()
layout.operator_menu_enum("sequencer.strip_modifier_add", "type", text="Add Modifier")
layout.operator("sequencer.strip_modifier_copy", text="Copy Modifiers to Selection")
- if selected_sequences_len(context) >= 2:
+ if selected_sequences_count >= 2:
layout.separator()
col = layout.column()
col.menu("SEQUENCER_MT_add_transitions", text="Add Transition")
- elif selected_sequences_len(context) >= 2:
+ elif selected_sequences_count >= 2:
layout.separator()
layout.operator("sequencer.crossfade_sounds", text="Crossfade Sounds")
+ if selected_sequences_count >= 1:
+ col = layout.column()
+ col.operator_menu_enum("sequencer.fades_add", "type", text="Fade")
+ layout.operator("sequencer.fades_clear", text="Clear Fade")
+
if strip_type in {
'CROSS', 'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER',
'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP', 'WIPE', 'GLOW',
@@ -1467,7 +1478,7 @@ class SEQUENCER_PT_time(SequencerButtonsPanel, Panel):
split.alignment = 'RIGHT'
split.label(text="End")
split = split.split(factor=0.8 + max_factor, align=True)
- split.label(text="{:>14}".format(smpte_from_frame(frame_final_end) + ":"))
+ split.label(text="{:>14}".format(smpte_from_frame(frame_final_end)))
split.alignment = 'RIGHT'
split.label(text=str(frame_final_end) + " ")
@@ -1511,7 +1522,7 @@ class SEQUENCER_PT_time(SequencerButtonsPanel, Panel):
split.label(text="Playhead")
split = split.split(factor=0.8 + max_factor, align=True)
playhead = frame_current - frame_final_start
- split.label(text="{:>14}".format(smpte_from_frame(playhead) + ":"))
+ split.label(text="{:>14}".format(smpte_from_frame(playhead)))
split.alignment = 'RIGHT'
split.label(text=str(playhead) + " ")
@@ -1560,10 +1571,13 @@ class SEQUENCER_PT_adjust_sound(SequencerButtonsPanel, Panel):
col.prop(strip, "volume", text="Volume")
col.prop(strip, "pitch")
+
+ col = layout.column()
col.prop(strip, "pan")
+ col.enabled = sound is not None and sound.use_mono
if sound is not None:
-
+ col = layout.column()
if st.waveform_display_type == 'DEFAULT_WAVEFORMS':
col.prop(strip, "show_waveform")
col.prop(sound, "use_mono")
@@ -1678,7 +1692,7 @@ class SEQUENCER_PT_adjust_video(SequencerButtonsPanel, Panel):
col.prop(strip, "undistort")
col.separator()
- col.prop(strip, "playback_direction")
+ col.prop(strip, "use_reverse_frames")
class SEQUENCER_PT_adjust_color(SequencerButtonsPanel, Panel):
@@ -1880,7 +1894,7 @@ class SEQUENCER_PT_preview(SequencerButtonsPanel_Output, Panel):
col = layout.column()
col.prop(render, "sequencer_gl_preview", text="Preview Shading")
- if render.sequencer_gl_preview in ['SOLID', 'WIREFRAME']:
+ if render.sequencer_gl_preview in {'SOLID', 'WIREFRAME'}:
col.prop(render, "use_sequencer_override_scene_strip")
@@ -1894,6 +1908,7 @@ class SEQUENCER_PT_view(SequencerButtonsPanel_Output, Panel):
layout.use_property_decorate = False
st = context.space_data
+ ed = context.scene.sequence_editor
col = layout.column()
col.prop(st, "display_channel", text="Channel")
@@ -1905,6 +1920,7 @@ class SEQUENCER_PT_view(SequencerButtonsPanel_Output, Panel):
col.prop(st, "show_separate_color")
col.prop(st, "proxy_render_size")
+ col.prop(ed, "use_prefetch")
class SEQUENCER_PT_frame_overlay(SequencerButtonsPanel_Output, Panel):
diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py
index 500f889eea9..04a904edde3 100644
--- a/release/scripts/startup/bl_ui/space_time.py
+++ b/release/scripts/startup/bl_ui/space_time.py
@@ -48,26 +48,27 @@ class TIME_HT_editor_buttons(Header):
# hide the play-reversed button
# since JACK transport doesn't support reversed playback
if scene.sync_mode == 'AUDIO_SYNC' and context.preferences.system.audio_device == 'JACK':
- sub = row.row(align=True)
- sub.scale_x = 1.4
- sub.operator("screen.animation_play", text="", icon='PLAY')
+ row.scale_x = 2
+ row.operator("screen.animation_play", text="", icon='PLAY')
+ row.scale_x = 1
else:
row.operator("screen.animation_play", text="", icon='PLAY_REVERSE').reverse = True
row.operator("screen.animation_play", text="", icon='PLAY')
else:
- sub = row.row(align=True)
- sub.scale_x = 1.4
- sub.operator("screen.animation_play", text="", icon='PAUSE')
+ row.scale_x = 2
+ row.operator("screen.animation_play", text="", icon='PAUSE')
+ row.scale_x = 1
row.operator("screen.keyframe_jump", text="", icon='NEXT_KEYFRAME').next = True
row.operator("screen.frame_jump", text="", icon='FF').end = True
layout.separator_spacer()
row = layout.row()
- row.scale_x = 0.95
if scene.show_subframe:
+ row.scale_x = 1.15
row.prop(scene, "frame_float", text="")
else:
+ row.scale_x = 0.95
row.prop(scene, "frame_current", text="")
row = layout.row(align=True)
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index fabf8abaeab..aa5be13c01b 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -48,6 +48,7 @@ def generate_from_enum_ex(
icon_prefix,
type,
attr,
+ cursor='DEFAULT',
tooldef_keywords={},
):
tool_defs = []
@@ -60,6 +61,7 @@ def generate_from_enum_ex(
idname=idname_prefix + name,
label=name,
icon=icon_prefix + idname.lower(),
+ cursor=cursor,
data_block=idname,
**tooldef_keywords,
)
@@ -199,7 +201,7 @@ class _defs_annotate:
idname="builtin.annotate_line",
label="Annotate Line",
icon="ops.gpencil.draw.line",
- cursor='CROSSHAIR',
+ cursor='PAINT_BRUSH',
keymap="Generic Tool: Annotate Line",
draw_settings=draw_settings,
)
@@ -210,7 +212,7 @@ class _defs_annotate:
idname="builtin.annotate_polygon",
label="Annotate Polygon",
icon="ops.gpencil.draw.poly",
- cursor='CROSSHAIR',
+ cursor='PAINT_BRUSH',
keymap="Generic Tool: Annotate Polygon",
draw_settings=draw_settings,
)
@@ -225,7 +227,7 @@ class _defs_annotate:
idname="builtin.annotate_eraser",
label="Annotate Eraser",
icon="ops.gpencil.draw.eraser",
- cursor='CROSSHAIR', # XXX: Always show brush circle when enabled
+ cursor='ERASER',
keymap="Generic Tool: Annotate Eraser",
draw_settings=draw_settings,
)
@@ -324,10 +326,10 @@ class _defs_view3d_select:
pass
return dict(
idname="builtin.select",
- label="Select",
+ label="Tweak",
icon="ops.generic.select",
widget=None,
- keymap="3D View Tool: Select",
+ keymap="3D View Tool: Tweak",
draw_settings=draw_settings,
)
@@ -490,12 +492,17 @@ class _defs_edit_mesh:
@ToolDef.from_fn
def poly_build():
+ def draw_settings(_context, layout, tool):
+ props = tool.operator_properties("mesh.polybuild_face_at_cursor_move")
+ props_macro = props.MESH_OT_polybuild_face_at_cursor
+ layout.prop(props_macro, "create_quads")
return dict(
idname="builtin.poly_build",
label="Poly Build",
icon="ops.mesh.polybuild_hover",
widget="VIEW3D_GGT_mesh_preselect_elem",
keymap=(),
+ draw_settings=draw_settings,
)
@ToolDef.from_fn
@@ -719,8 +726,6 @@ class _defs_edit_mesh:
def shear():
def draw_settings(context, layout, tool):
props = tool.operator_properties("transform.shear")
- layout.label(text="View Axis:")
- layout.prop(props, "shear_axis", expand=True)
_template_widget.VIEW3D_GGT_xform_gizmo.draw_settings_with_index(context, layout, 2)
return dict(
idname="builtin.shear",
@@ -982,6 +987,23 @@ class _defs_sculpt:
keymap=(),
)
+ @ToolDef.from_fn
+ def mesh_filter():
+ def draw_settings(_context, layout, tool):
+ props = tool.operator_properties("sculpt.mesh_filter")
+ layout.prop(props, "type", expand=False)
+ layout.prop(props, "strength")
+ layout.prop(props, "deform_axis")
+
+ return dict(
+ idname="builtin.mesh_filter",
+ label="Mesh Filter",
+ icon="ops.sculpt.mesh_filter",
+ widget=None,
+ keymap=(),
+ draw_settings=draw_settings,
+ )
+
class _defs_vertex_paint:
@@ -1189,7 +1211,7 @@ class _defs_image_uv_select:
pass
return dict(
idname="builtin.select",
- label="Select",
+ label="Tweak",
icon="ops.generic.select",
widget=None,
keymap=(),
@@ -1298,6 +1320,7 @@ class _defs_gpencil_paint:
icon_prefix="brush.gpencil_draw.",
type=bpy.types.Brush,
attr="gpencil_tool",
+ cursor='PAINT_CROSS',
tooldef_keywords=dict(
operator="gpencil.draw",
),
@@ -1387,7 +1410,7 @@ class _defs_gpencil_edit:
layout.prop(context.tool_settings.gpencil_sculpt, "intersection_threshold")
return dict(
idname="builtin.select",
- label="Select",
+ label="Tweak",
icon="ops.generic.select",
widget=None,
keymap=(),
@@ -1552,10 +1575,10 @@ class _defs_node_select:
pass
return dict(
idname="builtin.select",
- label="Select",
+ label="Tweak",
icon="ops.generic.select",
widget=None,
- keymap="Node Tool: Select",
+ keymap="Node Tool: Tweak",
draw_settings=draw_settings,
)
@@ -1964,6 +1987,13 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
),
_defs_sculpt.hide_border,
None,
+ _defs_sculpt.mesh_filter,
+ None,
+ _defs_transform.translate,
+ _defs_transform.rotate,
+ _defs_transform.scale,
+ _defs_transform.transform,
+ None,
*_tools_annotate,
],
'PAINT_TEXTURE': [
diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py
index d0ad9a8f31e..fef0e095099 100644
--- a/release/scripts/startup/bl_ui/space_topbar.py
+++ b/release/scripts/startup/bl_ui/space_topbar.py
@@ -349,7 +349,7 @@ class TOPBAR_MT_app_about(Menu):
layout.separator()
layout.operator("wm.url_open_preset", text="Blender Website", icon='URL').type = 'BLENDER'
- layout.operator("wm.url_open", text="Credits", icon='URL').type = 'CREDITS'
+ layout.operator("wm.url_open_preset", text="Credits", icon='URL').type = 'CREDITS'
layout.separator()
@@ -465,7 +465,6 @@ class TOPBAR_MT_render(Menu):
layout.operator("render.view_show", text="View Render")
layout.operator("render.play_rendered_anim", text="View Animation")
- layout.prop_menu_enum(rd, "display_mode", text="Display Mode")
layout.separator()
@@ -505,6 +504,8 @@ class TOPBAR_MT_edit(Menu):
props.name = "TOPBAR_PT_name"
props.keep_open = False
+ layout.operator("wm.batch_rename")
+
layout.separator()
# Should move elsewhere (impacts outliner & 3D view).
@@ -561,7 +562,7 @@ class TOPBAR_MT_help(Menu):
show_developer = context.preferences.view.show_developer_ui
- layout.operator("wm.url_open_preset", text="Manual", icon='HELP',).type = 'MANUAL'
+ layout.operator("wm.url_open_preset", text="Manual", icon='HELP').type = 'MANUAL'
layout.operator(
"wm.url_open", text="Tutorials", icon='URL',
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 8ed8eb04898..be41fb52118 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -265,6 +265,26 @@ class USERPREF_PT_interface_editors(PreferencePanel, Panel):
flow.prop(view, "factor_display_type")
+class USERPREF_PT_interface_temporary_windows(PreferencePanel, Panel):
+ bl_label = "Temporary Windows"
+ bl_parent_id = "USERPREF_PT_interface_editors"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ prefs = context.preferences
+ return (prefs.active_section == 'INTERFACE')
+
+ def draw_props(self, context, layout):
+ prefs = context.preferences
+ view = prefs.view
+
+ flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
+
+ flow.prop(view, "render_display_type", text="Render in")
+ flow.prop(view, "filebrowser_display_type", text="File Browser")
+
+
class USERPREF_PT_interface_menus(Panel):
bl_space_type = 'PREFERENCES'
bl_region_type = 'WINDOW'
@@ -814,26 +834,21 @@ class PreferenceThemeWidgetColorPanel:
layout.use_property_split = True
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
+ flow = layout.grid_flow(row_major=False, columns=2, even_columns=True, even_rows=False, align=False)
- col = flow.column()
- col.prop(widget_style, "outline")
+ col = flow.column(align=True)
+ col.prop(widget_style, "text")
+ col.prop(widget_style, "text_sel", text="Selected")
col.prop(widget_style, "item", slider=True)
- col.prop(widget_style, "inner", slider=True)
- col.prop(widget_style, "inner_sel", slider=True)
- col = flow.column()
- col.prop(widget_style, "text")
- col.prop(widget_style, "text_sel")
- col.prop(widget_style, "roundness")
+ col = flow.column(align=True)
+ col.prop(widget_style, "inner", slider=True)
+ col.prop(widget_style, "inner_sel", text="Selected", slider=True)
+ col.prop(widget_style, "outline")
- col = flow.column()
- col.prop(widget_style, "show_shaded")
+ col.separator()
- colsub = col.column()
- colsub.active = widget_style.show_shaded
- colsub.prop(widget_style, "shadetop")
- colsub.prop(widget_style, "shadedown")
+ col.prop(widget_style, "roundness")
@classmethod
def poll(cls, context):
@@ -841,6 +856,31 @@ class PreferenceThemeWidgetColorPanel:
return (prefs.active_section == 'THEMES')
+class PreferenceThemeWidgetShadePanel:
+ bl_space_type = 'PREFERENCES'
+ bl_region_type = 'WINDOW'
+
+ def draw(self, context):
+ theme = context.preferences.themes[0]
+ ui = theme.user_interface
+ widget_style = getattr(ui, self.wcol)
+ layout = self.layout
+
+ layout.use_property_split = True
+
+ col = layout.column(align=True)
+ col.active = widget_style.show_shaded
+ col.prop(widget_style, "shadetop", text="Shade Top")
+ col.prop(widget_style, "shadedown", text="Down")
+
+ def draw_header(self, context):
+ theme = context.preferences.themes[0]
+ ui = theme.user_interface
+ widget_style = getattr(ui, self.wcol)
+
+ self.layout.prop(widget_style, "show_shaded", text="")
+
+
class USERPREF_PT_theme_interface_state(PreferencePanel, Panel):
bl_label = "State"
bl_options = {'DEFAULT_CLOSED'}
@@ -937,6 +977,7 @@ class USERPREF_PT_theme_interface_icons(PreferencePanel, Panel):
flow.prop(ui, "icon_object_data")
flow.prop(ui, "icon_modifier")
flow.prop(ui, "icon_shading")
+ flow.prop(ui, "icon_folder")
flow.prop(ui, "icon_border_intensity")
@@ -1136,6 +1177,15 @@ class ThemeGenericClassGenerator():
"wcol": wcol,
})
+ panel_shade_id = "USERPREF_PT_theme_interface_shade_" + wcol
+ yield type(panel_shade_id, (PreferenceThemeWidgetShadePanel, Panel), {
+ "bl_label": "Shaded",
+ "bl_options": {'DEFAULT_CLOSED'},
+ "bl_parent_id": panel_id,
+ "draw": PreferenceThemeWidgetShadePanel.draw,
+ "wcol": wcol,
+ })
+
@staticmethod
def generate_theme_area_child_panel_classes(parent_id, rna_type, theme_area, datapath):
def generate_child_panel_classes_recurse(parent_id, rna_type, theme_area, datapath):
@@ -1355,7 +1405,6 @@ class USERPREF_PT_saveload_file_browser(PreferencePanel, Panel):
flow.prop(paths, "show_hidden_files_datablocks")
flow.prop(paths, "hide_recent_locations")
flow.prop(paths, "hide_system_bookmarks")
- flow.prop(paths, "show_thumbnails")
class USERPREF_MT_ndof_settings(Menu):
@@ -2089,6 +2138,7 @@ classes = (
USERPREF_PT_interface_display,
USERPREF_PT_interface_editors,
+ USERPREF_PT_interface_temporary_windows,
USERPREF_PT_interface_translation,
USERPREF_PT_interface_text,
USERPREF_PT_interface_menus,
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index b684e4aa2dd..aca8ea701ce 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -129,6 +129,8 @@ class VIEW3D_HT_tool_header(Header):
if mode_string == 'EDIT_MESH':
_row, sub = row_for_mirror()
sub.prop(context.object.data, "use_mirror_x", text="X", toggle=True)
+ sub.prop(context.object.data, "use_mirror_y", text="Y", toggle=True)
+ sub.prop(context.object.data, "use_mirror_z", text="Z", toggle=True)
tool_settings = context.tool_settings
layout.prop(tool_settings, "use_mesh_automerge", text="")
elif mode_string == 'EDIT_ARMATURE':
@@ -139,7 +141,10 @@ class VIEW3D_HT_tool_header(Header):
sub.prop(context.object.pose, "use_mirror_x", text="X", toggle=True)
elif mode_string == 'PAINT_WEIGHT':
row, sub = row_for_mirror()
- sub.prop(context.object.data, "use_mirror_x", text="X", toggle=True)
+ wpaint = context.tool_settings.weight_paint
+ sub.prop(wpaint, "use_symmetry_x", text="X", toggle=True)
+ sub.prop(wpaint, "use_symmetry_y", text="Y", toggle=True)
+ sub.prop(wpaint, "use_symmetry_z", text="Z", toggle=True)
row.popover(panel="VIEW3D_PT_tools_weightpaint_symmetry_for_topbar", text="")
elif mode_string == 'SCULPT':
row, sub = row_for_mirror()
@@ -605,7 +610,7 @@ class VIEW3D_HT_header(Header):
row.prop(tool_settings, "gpencil_selectmode_edit", text="", expand=True)
# Select mode for Sculpt
- if gpd.is_stroke_sculpt_mode :
+ if gpd.is_stroke_sculpt_mode:
row = layout.row(align=True)
row.prop(tool_settings, "use_gpencil_select_mask_point", text="")
row.prop(tool_settings, "use_gpencil_select_mask_stroke", text="")
@@ -2100,6 +2105,9 @@ class VIEW3D_MT_object_relations(Menu):
layout.operator("object.proxy_make", text="Make Proxy...")
+ if bpy.app.use_override_library:
+ layout.operator("object.make_override_library", text="Make Library Override...")
+
layout.operator("object.make_dupli_face")
layout.separator()
@@ -2215,7 +2223,7 @@ class VIEW3D_MT_object_rigid_body(Menu):
layout.operator("rigidbody.mass_calculate", text="Calculate Mass")
layout.operator("rigidbody.object_settings_copy", text="Copy from Active")
layout.operator("object.visual_transform_apply", text="Apply Transformation")
- layout.operator("rigidbody.bake_to_keyframes", text="Bake To Keyframes")
+ layout.operator("rigidbody.bake_to_keyframes", text="Bake to Keyframes")
layout.separator()
@@ -2330,6 +2338,7 @@ class VIEW3D_MT_object_context_menu(Menu):
layout.separator()
layout.operator("object.convert", text="Convert to Mesh").target = 'MESH'
+ layout.operator("object.convert", text="Convert to Grease Pencil").target = 'GPENCIL'
layout.operator_menu_enum("object.origin_set", text="Set Origin", property="type")
layout.separator()
@@ -2359,10 +2368,10 @@ class VIEW3D_MT_object_context_menu(Menu):
layout.operator_context = 'INVOKE_REGION_WIN'
- props = layout.operator("wm.context_modal_mouse", text="Energy")
+ props = layout.operator("wm.context_modal_mouse", text="Power")
props.data_path_iter = "selected_editable_objects"
props.data_path_item = "data.energy"
- props.header_text = "Light Energy: %.3f"
+ props.header_text = "Light Power: %.3f"
if light.type == 'AREA':
props = layout.operator("wm.context_modal_mouse", text="Size X")
@@ -2650,7 +2659,6 @@ class VIEW3D_MT_make_links(Menu):
layout.operator("object.join_uvs") # stupid place to add this!
-
class VIEW3D_MT_brush_paint_modes(Menu):
bl_label = "Enabled Modes"
@@ -2807,7 +2815,7 @@ class VIEW3D_MT_paint_weight(Menu):
class VIEW3D_MT_sculpt(Menu):
bl_label = "Sculpt"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
props = layout.operator("paint.hide_show", text="Show All")
@@ -2823,6 +2831,7 @@ class VIEW3D_MT_sculpt(Menu):
props.area = 'INSIDE'
props = layout.operator("paint.hide_show", text="Hide Masked")
+ props.action = 'HIDE'
props.area = 'MASKED'
layout.separator()
@@ -2841,6 +2850,79 @@ class VIEW3D_MT_sculpt(Menu):
props = layout.operator("view3d.select_box", text="Box Mask")
props = layout.operator("paint.mask_lasso_gesture", text="Lasso Mask")
+ layout.separator()
+
+ props = layout.operator("sculpt.mask_filter", text='Smooth Mask')
+ props.filter_type = 'SMOOTH'
+ props.auto_iteration_count = True
+
+ props = layout.operator("sculpt.mask_filter", text='Sharpen Mask')
+ props.filter_type = 'SHARPEN'
+ props.auto_iteration_count = True
+
+ props = layout.operator("sculpt.mask_filter", text='Grow Mask')
+ props.filter_type = 'GROW'
+ props.auto_iteration_count = True
+
+ props = layout.operator("sculpt.mask_filter", text='Shrink Mask')
+ props.filter_type = 'SHRINK'
+ props.auto_iteration_count = True
+
+ props = layout.operator("sculpt.mask_filter", text='Increase Contrast')
+ props.filter_type = 'CONTRAST_INCREASE'
+ props.auto_iteration_count = False
+
+ props = layout.operator("sculpt.mask_filter", text='Decrease Contrast')
+ props.filter_type = 'CONTRAST_DECREASE'
+ props.auto_iteration_count = False
+
+ layout.separator()
+
+ props = layout.operator("sculpt.mask_expand", text="Expand Mask By Topology")
+ props.use_normals = False
+ props.keep_previous_mask = False
+ props.invert = True
+ props.smooth_iterations = 2
+
+ props = layout.operator("sculpt.mask_expand", text="Expand Mask By Curvature")
+ props.use_normals = True
+ props.keep_previous_mask = True
+ props.invert = False
+ props.smooth_iterations = 0
+
+ layout.separator()
+
+ props = layout.operator("mesh.paint_mask_extract", text="Mask Extract")
+
+ layout.separator()
+
+ props = layout.operator("sculpt.dirty_mask", text='Dirty Mask')
+
+ layout.separator()
+ layout.menu("VIEW3D_MT_sculpt_set_pivot", text="Set Pivot")
+
+
+class VIEW3D_MT_sculpt_set_pivot(Menu):
+ bl_label = "Sculpt Set Pivot"
+
+ def draw(self, context):
+ layout = self.layout
+
+ props = layout.operator("sculpt.set_pivot_position", text="Pivot to Origin")
+ props.mode = 'ORIGIN'
+
+ props = layout.operator("sculpt.set_pivot_position", text="Pivot to Unmasked")
+ props.mode = 'UNMASKED'
+
+ props = layout.operator("sculpt.set_pivot_position", text="Pivot to Mask Border")
+ props.mode = 'BORDER'
+
+ props = layout.operator("sculpt.set_pivot_position", text="Pivot to Active Vertex")
+ props.mode = 'ACTIVE'
+
+ props = layout.operator("sculpt.set_pivot_position", text="Pivot to Surface Under Cursor")
+ props.mode = 'SURFACE'
+
class VIEW3D_MT_particle(Menu):
bl_label = "Particle"
@@ -3189,7 +3271,7 @@ class BoneOptions:
"use_deform",
"use_envelope_multiply",
"use_inherit_rotation",
- "use_inherit_scale",
+ "inherit_scale",
]
if context.mode == 'EDIT_ARMATURE':
@@ -3384,9 +3466,11 @@ class VIEW3D_MT_edit_mesh_context_menu(Menu):
col.operator("mesh.loopcut_slide")
col.operator("mesh.offset_edge_loops_slide")
+
+ col.separator()
+
col.operator("mesh.knife_tool")
col.operator("mesh.bisect")
- col.operator("mesh.bridge_edge_loops", text="Bridge Edge Loops")
col.separator()
@@ -3933,7 +4017,9 @@ class VIEW3D_MT_edit_gpencil_delete(Menu):
layout.separator()
- layout.operator("gpencil.active_frames_delete_all")
+ layout.operator("gpencil.delete", text="Delete Active Keyframe (Active Layer)").type = 'FRAME'
+ layout.operator("gpencil.active_frames_delete_all", text="Delete Active Keyframes (All Layers)")
+
# Edit Curve
# draw_curve is used by VIEW3D_MT_edit_curve and VIEW3D_MT_edit_surface
@@ -4368,7 +4454,7 @@ class VIEW3D_MT_edit_armature_delete(Menu):
layout.operator("armature.dissolve", text="Dissolve Bones")
-# ********** Grease Pencil Stroke menus **********
+# ********** Grease Pencil menus **********
class VIEW3D_MT_gpencil_autoweights(Menu):
bl_label = "Generate Weights"
@@ -4389,7 +4475,7 @@ class VIEW3D_MT_gpencil_simplify(Menu):
class VIEW3D_MT_paint_gpencil(Menu):
- bl_label = "Strokes"
+ bl_label = "Draw"
def draw(self, _context):
@@ -4400,8 +4486,8 @@ class VIEW3D_MT_paint_gpencil(Menu):
layout.separator()
- layout.operator("gpencil.delete", text="Delete Frame").type = 'FRAME'
- layout.operator("gpencil.active_frames_delete_all")
+ layout.menu("VIEW3D_MT_edit_gpencil_showhide")
+ layout.menu("GPENCIL_MT_cleanup")
class VIEW3D_MT_assign_material(Menu):
@@ -4460,8 +4546,8 @@ class VIEW3D_MT_edit_gpencil(Menu):
layout.operator("gpencil.duplicate_move", text="Duplicate")
layout.operator("gpencil.stroke_split", text="Split")
layout.operator("gpencil.copy", text="Copy", icon='COPYDOWN')
- layout.operator("gpencil.paste", text="Paste", icon='PASTEDOWN').type = 'COPY'
- layout.operator("gpencil.paste", text="Paste & Merge").type = 'MERGE'
+ layout.operator("gpencil.paste", text="Paste", icon='PASTEDOWN').type = 'ACTIVE'
+ layout.operator("gpencil.paste", text="Paste by Layer").type = 'LAYER'
layout.separator()
@@ -4492,13 +4578,14 @@ class VIEW3D_MT_edit_gpencil_stroke(Menu):
layout.separator()
- layout.operator_menu_enum("gpencil.stroke_join", "type", text="Join...")
+ layout.operator_menu_enum("gpencil.stroke_join", "type", text="Join")
layout.separator()
- layout.operator_menu_enum("gpencil.move_to_layer", "layer", text="Move to Layer")
+ layout.menu("GPENCIL_MT_move_to_layer")
layout.menu("VIEW3D_MT_assign_material")
- layout.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange Strokes...")
+ layout.operator("gpencil.set_active_material", text="Set as Active Material")
+ layout.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange Strokes")
layout.separator()
@@ -4507,7 +4594,7 @@ class VIEW3D_MT_edit_gpencil_stroke(Menu):
op.type = 'CLOSE'
op.geometry = True
layout.operator("gpencil.stroke_cyclical_set", text="Toggle Cyclic").type = 'TOGGLE'
- layout.operator_menu_enum("gpencil.stroke_caps_set", text="Toggle Caps...", property="type")
+ layout.operator_menu_enum("gpencil.stroke_caps_set", text="Toggle Caps", property="type")
layout.operator("gpencil.stroke_flip", text="Switch Direction")
@@ -4564,17 +4651,18 @@ class VIEW3D_MT_gpencil_animation(Menu):
def draw(self, _context):
layout = self.layout
- layout.operator("gpencil.blank_frame_add")
+ layout.operator("gpencil.blank_frame_add", text="Insert Blank Keyframe (Active Layer)")
+ layout.operator("gpencil.blank_frame_add", text="Insert Blank Keyframe (All Layers)").all_layers = True
layout.separator()
- layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame")
- layout.operator("gpencil.frame_duplicate", text="Duplicate All Layers").mode = 'ALL'
+ layout.operator("gpencil.frame_duplicate", text="Duplicate Active Keyframe (Active Layer)")
+ layout.operator("gpencil.frame_duplicate", text="Duplicate Active Keyframe (All Layers)").mode = 'ALL'
layout.separator()
- layout.operator("gpencil.delete", text="Delete Active Frame").type = 'FRAME'
- layout.operator("gpencil.active_frames_delete_all", text="Delete All Active Frames")
+ layout.operator("gpencil.delete", text="Delete Active Keyframe (Active Layer)").type = 'FRAME'
+ layout.operator("gpencil.active_frames_delete_all", text="Delete Active Keyframes (All Layers)")
class VIEW3D_MT_edit_gpencil_transform(Menu):
@@ -4595,18 +4683,19 @@ class VIEW3D_MT_edit_gpencil_transform(Menu):
layout.operator("transform.transform", text="Shrink Fatten").mode = 'GPENCIL_SHRINKFATTEN'
- layout.operator("gpencil.interpolate", text="Interpolate")
- layout.operator("gpencil.interpolate_sequence", text="Sequence")
-
class VIEW3D_MT_edit_gpencil_showhide(Menu):
bl_label = "Show/hide"
def draw(self, _context):
layout = self.layout
- layout.operator("gpencil.hide", text="Hide Active Layer")
layout.operator("gpencil.reveal", text="Show All Layers")
+ layout.separator()
+
+ layout.operator("gpencil.hide", text="Hide Active Layer").unselected = False
+ layout.operator("gpencil.hide", text="Hide Inactive Layers").unselected = True
+
class VIEW3D_MT_edit_gpencil_interpolate(Menu):
bl_label = "Interpolate"
@@ -4775,6 +4864,37 @@ class VIEW3D_MT_proportional_editing_falloff_pie(Menu):
pie.prop(tool_settings, "proportional_edit_falloff", expand=True)
+class VIEW3D_MT_sculpt_mask_edit_pie(Menu):
+ bl_label = "Mask Edit"
+
+ def draw(self, _context):
+ layout = self.layout
+ pie = layout.menu_pie()
+
+ op = pie.operator("paint.mask_flood_fill", text='Invert Mask')
+ op.mode = 'INVERT'
+ op = pie.operator("paint.mask_flood_fill", text='Clear Mask')
+ op.mode = 'VALUE'
+ op = pie.operator("sculpt.mask_filter", text='Smooth Mask')
+ op.filter_type = 'SMOOTH'
+ op.auto_iteration_count = True
+ op = pie.operator("sculpt.mask_filter", text='Sharpen Mask')
+ op.filter_type = 'SHARPEN'
+ op.auto_iteration_count = True
+ op = pie.operator("sculpt.mask_filter", text='Grow Mask')
+ op.filter_type = 'GROW'
+ op.auto_iteration_count = True
+ op = pie.operator("sculpt.mask_filter", text='Shrink Mask')
+ op.filter_type = 'SHRINK'
+ op.auto_iteration_count = True
+ op = pie.operator("sculpt.mask_filter", text='Increase Contrast')
+ op.filter_type = 'CONTRAST_INCREASE'
+ op.auto_iteration_count = False
+ op = pie.operator("sculpt.mask_filter", text='Decrease Contrast')
+ op.filter_type = 'CONTRAST_DECREASE'
+ op.auto_iteration_count = False
+
+
# ********** Panel **********
@@ -4910,7 +5030,7 @@ class VIEW3D_PT_collections(Panel):
bl_label = "Collections"
bl_options = {'DEFAULT_CLOSED'}
- def _draw_collection(self, layout, view_layer, collection, index):
+ def _draw_collection(self, layout, view_layer, use_local_collections, collection, index):
need_separator = index
for child in collection.children:
index += 1
@@ -4936,6 +5056,7 @@ class VIEW3D_PT_collections(Panel):
pass
row = layout.row()
+ row.use_property_decorate = False
sub = row.split(factor=0.98)
subrow = sub.row()
subrow.alignment = 'LEFT'
@@ -4946,11 +5067,21 @@ class VIEW3D_PT_collections(Panel):
sub = row.split()
subrow = sub.row(align=True)
subrow.alignment = 'RIGHT'
- subrow.active = collection.is_visible # Parent collection runtime visibility
- subrow.prop(child, "hide_viewport", text="", emboss=False)
+ if not use_local_collections:
+ subrow.active = collection.is_visible # Parent collection runtime visibility
+ subrow.prop(child, "hide_viewport", text="", emboss=False)
+ elif not child.is_visible:
+ subrow.active = False
+ subrow.label(text="", icon='REMOVE')
+ else:
+ subrow.active = collection.visible_get() # Parent collection runtime visibility
+ icon = 'HIDE_OFF' if child.visible_get() else 'HIDE_ON'
+ props = subrow.operator("object.hide_collection", text="", icon=icon, emboss=False)
+ props.collection_index = index
+ props.toggle = True
for child in collection.children:
- index = self._draw_collection(layout, view_layer, child, index)
+ index = self._draw_collection(layout, view_layer, use_local_collections, child, index)
return index
@@ -4958,11 +5089,17 @@ class VIEW3D_PT_collections(Panel):
layout = self.layout
layout.use_property_split = False
+ view = context.space_data
view_layer = context.view_layer
+
+ layout.use_property_split = True
+ layout.prop(view, "use_local_collections")
+ layout.separator()
+
# We pass index 0 here because the index is increased
# so the first real index is 1
# And we start with index as 1 because we skip the master collection
- self._draw_collection(layout, view_layer, view_layer.layer_collection, 0)
+ self._draw_collection(layout, view_layer, view.use_local_collections, view_layer.layer_collection, 0)
class VIEW3D_PT_object_type_visibility(Panel):
@@ -5049,7 +5186,8 @@ class VIEW3D_PT_shading_lighting(Panel):
@classmethod
def poll(cls, context):
shading = VIEW3D_PT_shading.get_shading(context)
- return shading.type in {'SOLID', 'MATERIAL'}
+ engine = context.scene.render.engine
+ return shading.type in {'SOLID', 'MATERIAL'} or engine == 'BLENDER_EEVEE' and shading.type == 'RENDERED'
def draw(self, context):
layout = self.layout
@@ -5097,7 +5235,6 @@ class VIEW3D_PT_shading_lighting(Panel):
elif shading.light == 'MATCAP':
sub.scale_y = 0.6 # smaller matcap preview
-
sub.template_icon_view(shading, "studio_light", scale_popup=3.0)
col = split.column()
@@ -5107,8 +5244,30 @@ class VIEW3D_PT_shading_lighting(Panel):
elif shading.type == 'MATERIAL':
col.prop(shading, "use_scene_lights")
col.prop(shading, "use_scene_world")
+ col = layout.column()
+ split = col.split(factor=0.9)
if not shading.use_scene_world:
+ col = split.column()
+ sub = col.row()
+ sub.scale_y = 0.6
+ sub.template_icon_view(shading, "studio_light", scale_popup=3)
+
+ col = split.column()
+ col.operator("preferences.studiolight_show", emboss=False, text="", icon='PREFERENCES')
+
+ split = layout.split(factor=0.9)
+ col = split.column()
+ col.prop(shading, "studiolight_rotate_z", text="Rotation")
+ col.prop(shading, "studiolight_intensity")
+ col.prop(shading, "studiolight_background_alpha")
+ col = split.column() # to align properly with above
+
+ elif shading.type == 'RENDERED':
+ col.prop(shading, "use_scene_lights_render")
+ col.prop(shading, "use_scene_world_render")
+
+ if not shading.use_scene_world_render:
col = layout.column()
split = col.split(factor=0.9)
@@ -5120,12 +5279,12 @@ class VIEW3D_PT_shading_lighting(Panel):
col = split.column()
col.operator("preferences.studiolight_show", emboss=False, text="", icon='PREFERENCES')
- if shading.selected_studio_light.type == 'WORLD':
- split = layout.split(factor=0.9)
- col = split.column()
- col.prop(shading, "studiolight_rotate_z", text="Rotation")
- col.prop(shading, "studiolight_background_alpha")
- col = split.column() # to align properly with above
+ split = layout.split(factor=0.9)
+ col = split.column()
+ col.prop(shading, "studiolight_rotate_z", text="Rotation")
+ col.prop(shading, "studiolight_intensity")
+ col.prop(shading, "studiolight_background_alpha")
+ col = split.column() # to align properly with above
class VIEW3D_PT_shading_color(Panel):
@@ -5251,8 +5410,10 @@ class VIEW3D_PT_shading_options(Panel):
sub.active = shading.show_object_outline
sub.prop(shading, "object_outline_color", text="")
+ if shading.type == 'SOLID':
col = layout.column()
- if (shading.light == 'STUDIO') and (shading.type != 'WIREFRAME'):
+ if shading.light in {'STUDIO', 'MATCAP'}:
+ col.active = shading.selected_studio_light.has_specular_highlight_pass
col.prop(shading, "show_specular_highlight", text="Specular Lighting")
@@ -5520,6 +5681,7 @@ class VIEW3D_PT_overlay_edit_mesh(Panel):
layout = self.layout
view = context.space_data
+ shading = view.shading
overlay = view.overlay
display_all = overlay.show_overlays
@@ -5529,6 +5691,7 @@ class VIEW3D_PT_overlay_edit_mesh(Panel):
split = col.split()
sub = split.column()
+ sub.active = not ((shading.type == 'WIREFRAME') or shading.show_xray)
sub.prop(overlay, "show_edges", text="Edges")
sub = split.column()
sub.prop(overlay, "show_faces", text="Faces")
@@ -5887,13 +6050,6 @@ class VIEW3D_PT_pivot_point(Panel):
col.label(text="Pivot Point")
col.prop(tool_settings, "transform_pivot_point", expand=True)
- if (obj is None) or (mode in {'OBJECT', 'POSE', 'WEIGHT_PAINT'}):
- col.separator()
-
- col.label(text="Affect Only")
- col.prop(tool_settings, "use_transform_data_origin", text="Origins")
- col.prop(tool_settings, "use_transform_pivot_point_align", text="Locations")
-
class VIEW3D_PT_snapping(Panel):
bl_space_type = 'VIEW_3D'
@@ -6043,7 +6199,7 @@ class VIEW3D_PT_gpencil_guide(Panel):
col.active = settings.use_guide
col.prop(settings, "type", expand=True)
- if settings.type == 'PARALLEL':
+ if settings.type in {'ISO', 'PARALLEL', 'RADIAL'}:
col.prop(settings, "angle")
row = col.row(align=True)
@@ -6055,7 +6211,7 @@ class VIEW3D_PT_gpencil_guide(Panel):
else:
col.prop(settings, "spacing")
- if settings.type in {'CIRCULAR', 'RADIAL'}:
+ if settings.type in {'CIRCULAR', 'RADIAL'} or settings.use_snapping:
col.label(text="Reference Point")
row = col.row(align=True)
row.prop(settings, "reference_point", expand=True)
@@ -6102,17 +6258,17 @@ class VIEW3D_PT_overlay_gpencil_options(Panel):
sub.prop(overlay, "gpencil_grid_opacity", text="Canvas", slider=True)
row = col.row()
- row.prop(overlay, "use_gpencil_paper", text="")
+ row.prop(overlay, "use_gpencil_fade_layers", text="")
sub = row.row()
- sub.active = overlay.use_gpencil_paper
- sub.prop(overlay, "gpencil_paper_opacity", text="Fade 3D Objects", slider=True)
+ sub.active = overlay.use_gpencil_fade_layers
+ sub.prop(overlay, "gpencil_fade_layer", text="Fade Layers", slider=True)
- if context.object.mode == 'PAINT_GPENCIL':
- row = col.row()
- row.prop(overlay, "use_gpencil_fade_layers", text="")
- sub = row.row()
- sub.active = overlay.use_gpencil_fade_layers
- sub.prop(overlay, "gpencil_fade_layer", text="Fade Layers", slider=True)
+ row = col.row()
+ row.prop(overlay, "use_gpencil_paper", text="")
+ sub = row.row(align=True)
+ sub.active = overlay.use_gpencil_paper
+ sub.prop(overlay, "gpencil_paper_opacity", text="Fade Objects", slider=True)
+ sub.prop(overlay, "use_gpencil_fade_objects", text="", icon='OUTLINER_OB_GREASEPENCIL')
if context.object.mode in {'EDIT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'}:
layout.prop(overlay, "use_gpencil_edit_lines", text="Edit Lines")
@@ -6276,66 +6432,124 @@ class VIEW3D_PT_gpencil_multi_frame(Panel):
class VIEW3D_MT_gpencil_edit_context_menu(Menu):
- bl_label = "Edit Context Menu"
+ bl_label = ""
def draw(self, context):
- layout = self.layout
+
+ is_point_mode = context.tool_settings.gpencil_selectmode_edit == 'POINT'
+ is_stroke_mode = context.tool_settings.gpencil_selectmode_edit == 'STROKE'
+ is_segment_mode = context.tool_settings.gpencil_selectmode_edit == 'SEGMENT'
+
is_3d_view = context.space_data.type == 'VIEW_3D'
+ layout = self.layout
+
layout.operator_context = 'INVOKE_REGION_WIN'
- # Add
- layout.operator("gpencil.stroke_subdivide", text="Subdivide")
+ row = layout.row()
- layout.separator()
+ if is_point_mode or is_segment_mode:
+ col = row.column()
- # Transform
- layout.operator("transform.transform", text="Shrink/Fatten").mode = 'GPENCIL_SHRINKFATTEN'
- layout.operator("gpencil.stroke_smooth", text="Smooth")
- layout.operator("gpencil.stroke_trim", text="Trim")
+ col.label(text="Point Context Menu", icon='GP_SELECT_POINTS')
+ col.separator()
- layout.separator()
+ # Additive Operators
+ col.operator("gpencil.stroke_subdivide", text="Subdivide").only_selected = True
- # Modify
- layout.menu("VIEW3D_MT_assign_material")
- layout.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange Strokes")
- layout.operator("gpencil.stroke_flip", text="Flip Direction")
- layout.operator_menu_enum("gpencil.stroke_caps_set", text="Toggle Caps", property="type")
+ col.separator()
- layout.separator()
+ col.operator("gpencil.extrude_move", text="Extrude Points")
- layout.operator("gpencil.duplicate_move", text="Duplicate")
- layout.operator("gpencil.copy", text="Copy", icon='COPYDOWN')
- layout.operator("gpencil.paste", text="Paste", icon='PASTEDOWN').type = 'COPY'
- layout.operator("gpencil.paste", text="Paste & Merge").type = 'MERGE'
- layout.menu("VIEW3D_MT_gpencil_copy_layer")
- layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame")
- layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame All Layers").mode = 'ALL'
+ col.separator()
- layout.separator()
+ # Deform Operators
+ col.operator("gpencil.stroke_smooth", text="Smooth Points").only_selected = True
+ col.operator("transform.bend", text="Bend")
+ col.operator("transform.shear", text="Shear")
+ col.operator("transform.tosphere", text="To Sphere")
+ col.operator("transform.transform", text="Shrink Fatten").mode = 'GPENCIL_SHRINKFATTEN'
- layout.operator("gpencil.stroke_join", text="Join").type = 'JOIN'
- layout.operator("gpencil.stroke_join", text="Join & Copy").type = 'JOINCOPY'
- layout.operator_menu_enum("gpencil.stroke_separate", "mode")
- layout.operator("gpencil.stroke_split", text="Split")
- op = layout.operator("gpencil.stroke_cyclical_set", text="Close")
- op.type = 'CLOSE'
- op.geometry = True
+ col.separator()
- layout.separator()
+ col.menu("VIEW3D_MT_mirror", text="Mirror Points")
+ col.menu("VIEW3D_MT_snap", text="Snap Points")
- layout.menu("VIEW3D_MT_mirror")
- layout.menu("VIEW3D_MT_snap")
+ col.separator()
- layout.separator()
+ # Duplicate operators
+ col.operator("gpencil.duplicate_move", text="Duplicate")
+ col.operator("gpencil.copy", text="Copy", icon='COPYDOWN')
+ col.operator("gpencil.paste", text="Paste", icon='PASTEDOWN').type = 'ACTIVE'
+ col.operator("gpencil.paste", text="Paste by Layer").type = 'LAYER'
- # Remove
- if is_3d_view:
- layout.menu("GPENCIL_MT_cleanup")
+ col.separator()
- layout.menu("VIEW3D_MT_gpencil_simplify")
- layout.operator("gpencil.stroke_merge", text="Merge")
- layout.menu("VIEW3D_MT_edit_gpencil_delete")
+ # Removal Operators
+ col.operator("gpencil.stroke_merge", text="Merge Points")
+ col.operator("gpencil.stroke_merge_by_distance").use_unselected = False
+ col.operator("gpencil.stroke_split", text="Split")
+ col.operator("gpencil.stroke_separate", text="Separate").mode = 'POINT'
+
+ col.separator()
+
+ col.operator("gpencil.delete", text="Delete Points").type = 'POINTS'
+ col.operator("gpencil.dissolve", text="Dissolve Points").type = 'POINTS'
+ col.operator("gpencil.dissolve", text="Dissolve Between").type = 'BETWEEN'
+ col.operator("gpencil.dissolve", text="Dissolve Unselected").type = 'UNSELECT'
+
+ if is_stroke_mode:
+
+ col = row.column()
+ col.label(text="Stroke Context Menu", icon='GP_SELECT_STROKES')
+ col.separator()
+
+ # Main Strokes Operators
+ col.operator("gpencil.stroke_subdivide", text="Subdivide").only_selected = False
+ col.menu("VIEW3D_MT_gpencil_simplify")
+ col.operator("gpencil.stroke_trim", text="Trim")
+
+ col.separator()
+
+ col.operator("gpencil.stroke_smooth", text="Smooth Stroke").only_selected = False
+ col.operator("transform.transform", text="Shrink Fatten").mode = 'GPENCIL_SHRINKFATTEN'
+
+ col.separator()
+
+ # Layer and Materials operators
+ col.menu("GPENCIL_MT_move_to_layer")
+ col.menu("VIEW3D_MT_assign_material")
+ col.operator("gpencil.set_active_material", text="Set as Active Material")
+ col.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange Strokes")
+
+ col.separator()
+
+ col.menu("VIEW3D_MT_mirror", text="Mirror Stroke")
+ col.menu("VIEW3D_MT_snap", text="Snap Stroke")
+
+ col.separator()
+
+ # Duplicate operators
+ col.operator("gpencil.duplicate_move", text="Duplicate")
+ col.operator("gpencil.copy", text="Copy", icon='COPYDOWN')
+ col.operator("gpencil.paste", text="Paste", icon='PASTEDOWN').type = 'ACTIVE'
+ col.operator("gpencil.paste", text="Paste by Layer").type = 'LAYER'
+
+ col.separator()
+
+ # Removal Operators
+ col.operator("gpencil.stroke_merge_by_distance").use_unselected = True
+ col.operator_menu_enum("gpencil.stroke_join", "type", text="Join")
+ col.operator("gpencil.stroke_split", text="Split")
+ col.operator("gpencil.stroke_separate", text="Separate").mode = 'STROKE'
+
+ col.separator()
+
+ col.operator("gpencil.delete", text="Delete Strokes").type = 'STROKES'
+
+ col.separator()
+
+ col.operator("gpencil.reproject", text="Reproject Strokes")
class VIEW3D_PT_gpencil_sculpt_context_menu(Panel):
@@ -6360,14 +6574,18 @@ class VIEW3D_PT_gpencil_sculpt_context_menu(Panel):
layout.operator_context = 'INVOKE_REGION_WIN'
- layout.operator("gpencil.blank_frame_add", text="Insert Blank", icon='ADD')
- layout.operator("gpencil.frame_duplicate", text="Duplicate Active", icon='DUPLICATE')
- layout.operator("gpencil.frame_duplicate", text="Duplicate for All Layers", icon='DUPLICATE').mode = 'ALL'
+ layout.operator("gpencil.blank_frame_add", text="Insert Blank in Active Layer", icon='ADD')
+ layout.operator("gpencil.blank_frame_add", text="Insert Blank in All Layers", icon='ADD').all_layers = True
+
+ layout.separator()
+
+ layout.operator("gpencil.frame_duplicate", text="Duplicate Active Layer", icon='DUPLICATE')
+ layout.operator("gpencil.frame_duplicate", text="Duplicate All Layers", icon='DUPLICATE').mode = 'ALL'
layout.separator()
- layout.operator("gpencil.delete", text="Delete Active", icon='REMOVE').type = 'FRAME'
- layout.operator("gpencil.active_frames_delete_all", text="Delete All Active Layers", icon='REMOVE')
+ layout.operator("gpencil.delete", text="Delete Active Layer", icon='REMOVE').type = 'FRAME'
+ layout.operator("gpencil.active_frames_delete_all", text="Delete All Layers", icon='REMOVE')
class VIEW3D_PT_gpencil_draw_context_menu(Panel):
@@ -6393,14 +6611,18 @@ class VIEW3D_PT_gpencil_draw_context_menu(Panel):
layout.operator_context = 'INVOKE_REGION_WIN'
- layout.operator("gpencil.blank_frame_add", text="Insert Blank", icon='ADD')
- layout.operator("gpencil.frame_duplicate", text="Duplicate Active", icon='DUPLICATE')
- layout.operator("gpencil.frame_duplicate", text="Duplicate for All Layers", icon='DUPLICATE').mode = 'ALL'
+ layout.operator("gpencil.blank_frame_add", text="Insert Blank in Active Layer", icon='ADD')
+ layout.operator("gpencil.blank_frame_add", text="Insert Blank in All Layers", icon='ADD').all_layers = True
+
+ layout.separator()
+
+ layout.operator("gpencil.frame_duplicate", text="Duplicate Active Layer", icon='DUPLICATE')
+ layout.operator("gpencil.frame_duplicate", text="Duplicate All Layers", icon='DUPLICATE').mode = 'ALL'
layout.separator()
- layout.operator("gpencil.delete", text="Delete Active", icon='REMOVE').type = 'FRAME'
- layout.operator("gpencil.active_frames_delete_all", text="Delete All Active Layers", icon='REMOVE')
+ layout.operator("gpencil.delete", text="Delete Active Layer", icon='REMOVE').type = 'FRAME'
+ layout.operator("gpencil.active_frames_delete_all", text="Delete All Layers", icon='REMOVE')
class VIEW3D_PT_paint_vertex_context_menu(Panel):
@@ -6585,6 +6807,7 @@ classes = (
VIEW3D_MT_gpencil_vertex_group,
VIEW3D_MT_paint_weight,
VIEW3D_MT_sculpt,
+ VIEW3D_MT_sculpt_set_pivot,
VIEW3D_MT_particle,
VIEW3D_MT_particle_context_menu,
VIEW3D_MT_particle_showhide,
@@ -6666,6 +6889,7 @@ classes = (
VIEW3D_MT_snap_pie,
VIEW3D_MT_orientations_pie,
VIEW3D_MT_proportional_editing_falloff_pie,
+ VIEW3D_MT_sculpt_mask_edit_pie,
VIEW3D_PT_active_tool,
VIEW3D_PT_active_tool_duplicate,
VIEW3D_PT_view3d_properties,
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 5246d8fa864..3aee14e0239 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -122,6 +122,39 @@ def is_not_gpencil_edit_mode(context):
return not is_gpmode
+# ********** default tools for object mode ****************
+
+
+class VIEW3D_PT_tools_object_options(View3DPanel, Panel):
+ bl_category = "Tool"
+ bl_context = ".objectmode" # dot on purpose (access from topbar)
+ bl_label = "Options"
+
+ def draw(self, context):
+ # layout = self.layout
+ pass
+
+
+class VIEW3D_PT_tools_object_options_transform(View3DPanel, Panel):
+ bl_category = "Tool"
+ bl_context = ".objectmode" # dot on purpose (access from topbar)
+ bl_label = "Transform"
+ bl_parent_id = "VIEW3D_PT_tools_object_options"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ tool_settings = context.tool_settings
+
+ layout.label(text="Affect Only")
+ layout.prop(tool_settings, "use_transform_data_origin", text="Origins")
+ layout.prop(tool_settings, "use_transform_pivot_point_align", text="Locations")
+ layout.prop(tool_settings, "use_transform_skip_children", text="Parents")
+
+
# ********** default tools for editmode_mesh ****************
@@ -144,11 +177,21 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
ob = context.active_object
mesh = ob.data
- col = layout.column(align=True)
- col.prop(mesh, "use_mirror_x")
+ split = layout.split()
+
+ col = split.column()
+ col.alignment = 'RIGHT'
+ col.label(text="Mirror")
+
+ col = split.column()
row = col.row(align=True)
- row.active = ob.data.use_mirror_x
+ row.prop(mesh, "use_mirror_x", text="X", toggle=True)
+ row.prop(mesh, "use_mirror_y", text="Y", toggle=True)
+ row.prop(mesh, "use_mirror_z", text="Z", toggle=True)
+
+ row = layout.row(align=True)
+ row.active = ob.data.use_mirror_x or ob.data.use_mirror_y or ob.data.use_mirror_z
row.prop(mesh, "use_mirror_topology")
@@ -176,8 +219,10 @@ class VIEW3D_PT_tools_meshedit_options_automerge(View3DPanel, Panel):
layout.use_property_split = True
layout.use_property_decorate = False
- layout.active = tool_settings.use_mesh_automerge
- layout.prop(tool_settings, "double_threshold", text="Threshold")
+ col = layout.column(align=True)
+ col.active = tool_settings.use_mesh_automerge
+ col.prop(tool_settings, "use_mesh_automerge_and_split", toggle=False)
+ col.prop(tool_settings, "double_threshold", text="Threshold")
# ********** default tools for editmode_curve ****************
@@ -261,12 +306,17 @@ class VIEW3D_PT_tools_posemode_options(View3DPanel, Panel):
pose = context.active_object.pose
layout = self.layout
+ tool_settings = context.tool_settings
+
layout.prop(pose, "use_auto_ik")
layout.prop(pose, "use_mirror_x")
col = layout.column()
col.active = pose.use_mirror_x
col.prop(pose, "use_mirror_relative")
+ layout.label(text="Affect Only")
+ layout.prop(tool_settings, "use_transform_pivot_point_align", text="Locations")
+
# ********** default tools for paint modes ****************
@@ -363,6 +413,25 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
if not self.is_popover:
brush_basic_sculpt_settings(col, context, brush)
+ # normal_radius_factor
+ col.separator()
+ row = col.row()
+ row.prop(brush, "normal_radius_factor", slider=True)
+
+ if brush.sculpt_tool == 'ELASTIC_DEFORM':
+ col.separator()
+ row = col.row()
+ row.prop(brush, "elastic_deform_type")
+ row = col.row()
+ row.prop(brush, "elastic_deform_volume_preservation", slider=True)
+ elif brush.sculpt_tool == 'POSE':
+ row = col.row()
+ row.prop(brush, "pose_offset")
+ elif brush.sculpt_tool == 'GRAB':
+ col.separator()
+ row = col.row()
+ row.prop(brush, "use_grab_active_vertex")
+
# topology_rake_factor
if (
capabilities.has_topology_rake and
@@ -385,7 +454,10 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
# crease_pinch_factor
if capabilities.has_pinch_factor:
row = col.row(align=True)
- row.prop(brush, "crease_pinch_factor", slider=True, text="Pinch")
+ if (brush.sculpt_tool in ('BLOB', 'SNAKE_HOOK')):
+ row.prop(brush, "crease_pinch_factor", slider=True, text="Magnify")
+ else:
+ row.prop(brush, "crease_pinch_factor", slider=True, text="Pinch")
# rake_factor
if capabilities.has_rake_factor:
@@ -567,6 +639,7 @@ class VIEW3D_PT_tools_brush_options(Panel, View3DPaintPanel):
brush_texpaint_common_options(self, context, layout, brush, settings, True)
elif context.sculpt_object and brush:
+ col.prop(brush, "use_automasking_topology")
if capabilities.has_accumulate:
col.prop(brush, "use_accumulate")
@@ -575,6 +648,7 @@ class VIEW3D_PT_tools_brush_options(Panel, View3DPaintPanel):
if capabilities.has_sculpt_plane:
col.prop(brush, "sculpt_plane")
col.prop(brush, "use_original_normal")
+ col.prop(brush, "use_original_plane")
col.prop(brush, "use_frontface", text="Front Faces Only")
col.prop(brush, "use_projected")
@@ -702,6 +776,7 @@ class VIEW3D_PT_stencil_projectpaint(View3DPanel, Panel):
bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Mask"
bl_options = {'DEFAULT_CLOSED'}
+ bl_ui_units_x = 14
@classmethod
def poll(cls, context):
@@ -726,20 +801,20 @@ class VIEW3D_PT_stencil_projectpaint(View3DPanel, Panel):
col = layout.column()
col.active = ipaint.use_stencil_layer
+ col.label(text="Stencil Image")
+ col.template_ID(ipaint, "stencil_image", new="image.new", open="image.open")
+
stencil_text = mesh.uv_layer_stencil.name if mesh.uv_layer_stencil else ""
- split = col.split(factor=0.5)
+
+ col.separator()
+
+ split = col.split()
colsub = split.column()
colsub.alignment = 'RIGHT'
colsub.label(text="UV Layer")
split.column().menu("VIEW3D_MT_tools_projectpaint_stencil", text=stencil_text, translate=False)
- # todo this should be combined into a single row
- split = col.split(factor=0.5)
- colsub = split.column()
- colsub.alignment = 'RIGHT'
- colsub.label(text="Stencil Image")
- colsub = split.column()
- colsub.template_ID(ipaint, "stencil_image", new="image.new", open="image.open")
+ col.separator()
row = col.row(align=True)
row.prop(ipaint, "stencil_color", text="Display Color")
@@ -912,6 +987,8 @@ class VIEW3D_PT_tools_brush_stroke(Panel, View3DPaintPanel):
if brush.sculpt_capabilities.has_space_attenuation:
col.prop(brush, "use_space_attenuation")
+ col.prop(brush, "use_scene_spacing")
+
if brush.sculpt_capabilities.has_jitter:
row = col.row(align=True)
@@ -1139,6 +1216,7 @@ class VIEW3D_PT_sculpt_dyntopo_remesh(Panel, View3DPaintPanel):
col = flow.column()
col.operator("sculpt.detail_flood_fill")
+
class VIEW3D_PT_sculpt_voxel_remesh(Panel, View3DPaintPanel):
bl_context = ".sculpt_mode" # dot on purpose (access from topbar)
bl_label = "Remesh"
@@ -1149,15 +1227,6 @@ class VIEW3D_PT_sculpt_voxel_remesh(Panel, View3DPaintPanel):
def poll(cls, context):
return (context.sculpt_object and context.tool_settings.sculpt)
- def draw_header(self, context):
- is_popover = self.is_popover
- layout = self.layout
- layout.operator(
- "object.voxel_remesh",
- text="",
- emboss=is_popover,
- )
-
def draw(self, context):
layout = self.layout
layout.use_property_split = True
@@ -1166,12 +1235,16 @@ class VIEW3D_PT_sculpt_voxel_remesh(Panel, View3DPaintPanel):
col = layout.column()
mesh = context.active_object.data
col.prop(mesh, "remesh_voxel_size")
+ col.prop(mesh, "remesh_voxel_adaptivity")
+ col.prop(mesh, "remesh_fix_poles")
col.prop(mesh, "remesh_smooth_normals")
+ col.prop(mesh, "remesh_preserve_volume")
col.prop(mesh, "remesh_preserve_paint_mask")
col.operator("object.voxel_remesh", text="Remesh")
# TODO, move to space_view3d.py
+
class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel):
bl_context = ".sculpt_mode" # dot on purpose (access from topbar)
bl_label = "Options"
@@ -1780,7 +1853,7 @@ class VIEW3D_PT_tools_grease_pencil_brush(View3DPanel, Panel):
brush = gpencil_paint.brush
sub = col.column(align=True)
- sub.operator("gpencil.brush_presets_create", icon='HELP', text="")
+ sub.operator("gpencil.brush_presets_create", icon='PRESET_NEW', text="")
if brush is not None:
gp_settings = brush.gpencil_settings
@@ -1808,7 +1881,6 @@ class VIEW3D_PT_tools_grease_pencil_brush_option(View3DPanel, Panel):
bl_context = ".greasepencil_paint"
bl_label = "Options"
bl_category = "Tool"
- bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
@@ -1888,7 +1960,6 @@ class VIEW3D_PT_tools_grease_pencil_brush_settings(View3DPanel, Panel):
bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option'
bl_label = "Post-Processing"
bl_category = "Tool"
- bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
@@ -1922,6 +1993,9 @@ class VIEW3D_PT_tools_grease_pencil_brush_settings(View3DPanel, Panel):
col.prop(gp_settings, "random_subdiv", text="Randomness", slider=True)
col = layout.column(align=True)
+ col.prop(gp_settings, "simplify_factor")
+
+ col = layout.column(align=True)
col.prop(gp_settings, "trim")
@@ -2151,6 +2225,8 @@ class VIEW3D_PT_gpencil_brush_presets(PresetPanel, Panel):
classes = (
VIEW3D_MT_brush_context_menu,
VIEW3D_MT_brush_context_menu_paint_modes,
+ VIEW3D_PT_tools_object_options,
+ VIEW3D_PT_tools_object_options_transform,
VIEW3D_PT_tools_meshedit_options,
VIEW3D_PT_tools_meshedit_options_automerge,
VIEW3D_PT_tools_curveedit_options_stroke,
@@ -2177,12 +2253,12 @@ classes = (
VIEW3D_PT_tools_brush_display_custom_icon,
VIEW3D_PT_sculpt_dyntopo,
VIEW3D_PT_sculpt_dyntopo_remesh,
+ VIEW3D_PT_sculpt_voxel_remesh,
VIEW3D_PT_sculpt_symmetry,
VIEW3D_PT_sculpt_symmetry_for_topbar,
VIEW3D_PT_sculpt_options,
VIEW3D_PT_sculpt_options_unified,
VIEW3D_PT_sculpt_options_gravity,
- VIEW3D_PT_sculpt_voxel_remesh,
VIEW3D_PT_tools_weightpaint_symmetry,
VIEW3D_PT_tools_weightpaint_symmetry_for_topbar,
VIEW3D_PT_tools_weightpaint_options,
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 5dc2cf8d106..f0f1baba642 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -190,6 +190,7 @@ shader_node_categories = [
NodeItem("ShaderNodeParticleInfo"),
NodeItem("ShaderNodeCameraData"),
NodeItem("ShaderNodeUVMap"),
+ NodeItem("ShaderNodeVertexColor"),
NodeItem("ShaderNodeUVAlongStroke", poll=line_style_shader_nodes_poll),
NodeItem("NodeGroupInput", poll=group_input_output_item_poll),
]),
diff --git a/release/windows/blendthumb/src/BlenderThumb.cpp b/release/windows/blendthumb/src/BlenderThumb.cpp
deleted file mode 100644
index 553428d5b5d..00000000000
--- a/release/windows/blendthumb/src/BlenderThumb.cpp
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <shlwapi.h>
-#include <thumbcache.h> // For IThumbnailProvider.
-#include <new>
-
-#pragma comment(lib, "shlwapi.lib")
-
-// this thumbnail provider implements IInitializeWithStream to enable being hosted
-// in an isolated process for robustness
-
-class CBlendThumb : public IInitializeWithStream, public IThumbnailProvider
-{
-public:
- CBlendThumb() : _cRef(1), _pStream(NULL) {}
-
- virtual ~CBlendThumb()
- {
- if (_pStream)
- {
- _pStream->Release();
- }
- }
-
- // IUnknown
- IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv)
- {
- static const QITAB qit[] =
- {
- QITABENT(CBlendThumb, IInitializeWithStream),
- QITABENT(CBlendThumb, IThumbnailProvider),
- { 0 },
- };
- return QISearch(this, qit, riid, ppv);
- }
-
- IFACEMETHODIMP_(ULONG) AddRef()
- {
- return InterlockedIncrement(&_cRef);
- }
-
- IFACEMETHODIMP_(ULONG) Release()
- {
- ULONG cRef = InterlockedDecrement(&_cRef);
- if (!cRef)
- {
- delete this;
- }
- return cRef;
- }
-
- // IInitializeWithStream
- IFACEMETHODIMP Initialize(IStream *pStream, DWORD grfMode);
-
- // IThumbnailProvider
- IFACEMETHODIMP GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha);
-
-private:
- long _cRef;
- IStream *_pStream; // provided during initialization.
-};
-
-HRESULT CBlendThumb_CreateInstance(REFIID riid, void **ppv)
-{
- CBlendThumb *pNew = new (std::nothrow) CBlendThumb();
- HRESULT hr = pNew ? S_OK : E_OUTOFMEMORY;
- if (SUCCEEDED(hr))
- {
- hr = pNew->QueryInterface(riid, ppv);
- pNew->Release();
- }
- return hr;
-}
-
-// IInitializeWithStream
-IFACEMETHODIMP CBlendThumb::Initialize(IStream *pStream, DWORD)
-{
- HRESULT hr = E_UNEXPECTED; // can only be inited once
- if (_pStream == NULL)
- {
- // take a reference to the stream if we have not been inited yet
- hr = pStream->QueryInterface(&_pStream);
- }
- return hr;
-}
-
-#include <math.h>
-#include <zlib.h>
-#include "Wincodec.h"
-const unsigned char gzip_magic[3] = { 0x1f, 0x8b, 0x08 };
-
-// IThumbnailProvider
-IFACEMETHODIMP CBlendThumb::GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha)
-{
- ULONG BytesRead;
- HRESULT hr = S_FALSE;
- LARGE_INTEGER SeekPos;
-
- // Compressed?
- unsigned char in_magic[3];
- _pStream->Read(&in_magic,3,&BytesRead);
- bool gzipped = true;
- for ( int i=0; i < 3; i++ )
- if ( in_magic[i] != gzip_magic[i] )
- {
- gzipped = false;
- break;
- }
-
- if (gzipped)
- {
- // Zlib inflate
- z_stream stream;
- stream.zalloc = Z_NULL;
- stream.zfree = Z_NULL;
- stream.opaque = Z_NULL;
-
- // Get compressed file length
- SeekPos.QuadPart = 0;
- _pStream->Seek(SeekPos,STREAM_SEEK_END,NULL);
-
- // Get compressed and uncompressed size
- uLong source_size;
- uLongf dest_size;
- //SeekPos.QuadPart = -4; // last 4 bytes define size of uncompressed file
- //ULARGE_INTEGER Tell;
- //_pStream->Seek(SeekPos,STREAM_SEEK_END,&Tell);
- //source_size = (uLong)Tell.QuadPart + 4; // src
- //_pStream->Read(&dest_size,4,&BytesRead); // dest
- dest_size = 1024*70; // thumbnail is currently always inside the first 65KB...if it moves or enlargens this line will have to change or go!
- source_size = (uLong)max(SeekPos.QuadPart,dest_size); // for safety, assume no compression
-
- // Input
- Bytef* src = new Bytef[source_size];
- stream.next_in = (Bytef*)src;
- stream.avail_in = (uInt)source_size;
-
- // Output
- Bytef* dest = new Bytef[dest_size];
- stream.next_out = (Bytef*)dest;
- stream.avail_out = dest_size;
-
- // IStream to src
- SeekPos.QuadPart = 0;
- _pStream->Seek(SeekPos,STREAM_SEEK_SET,NULL);
- _pStream->Read(src,source_size,&BytesRead);
-
- // Do the inflation
- int err;
- err = inflateInit2(&stream,16); // 16 means "gzip"...nice!
- err = inflate(&stream, Z_FINISH);
- err = inflateEnd(&stream);
-
- // Replace the IStream, which is read-only
- _pStream->Release();
- _pStream = SHCreateMemStream(dest,dest_size);
-
- delete[] src;
- delete[] dest;
- }
-
- // Blender version, early out if sub 2.5
- SeekPos.QuadPart = 9;
- _pStream->Seek(SeekPos,STREAM_SEEK_SET,NULL);
- char version[4];
- version[3] = '\0';
- _pStream->Read(&version,3,&BytesRead);
- if ( BytesRead != 3)
- return E_UNEXPECTED;
- int iVersion = atoi(version);
- if ( iVersion < 250 )
- return S_FALSE;
-
- // 32 or 64 bit blend?
- SeekPos.QuadPart = 7;
- _pStream->Seek(SeekPos,STREAM_SEEK_SET,NULL);
-
- char _PointerSize;
- _pStream->Read(&_PointerSize,1,&BytesRead);
-
- int PointerSize = _PointerSize == '_' ? 4 : 8;
- int HeaderSize = 16 + PointerSize;
-
- // Find and read thumbnail ("TEST") block
- SeekPos.QuadPart = 12;
- _pStream->Seek(SeekPos,STREAM_SEEK_SET,NULL);
- int BlockOffset = 12;
- while ( _pStream )
- {
- // Scan current block
- char BlockName[5];
- BlockName[4] = '\0';
- int BlockSize = 0;
-
- if (_pStream->Read(BlockName,4,&BytesRead) == S_OK && _pStream->Read((void*)&BlockSize,4,&BytesRead) == S_OK)
- {
- if ( strcmp (BlockName,"TEST") != 0 )
- {
- SeekPos.QuadPart = BlockOffset += HeaderSize + BlockSize;
- _pStream->Seek(SeekPos,STREAM_SEEK_SET,NULL);
- continue;
- }
- }
- else break; // eof
-
- // Found the block
- SeekPos.QuadPart = BlockOffset + HeaderSize;
- _pStream->Seek(SeekPos,STREAM_SEEK_SET,NULL);
-
- int width, height;
- _pStream->Read((char*)&width,4,&BytesRead);
- _pStream->Read((char*)&height,4,&BytesRead);
- BlockSize -= 8;
-
- // Isolate RGBA data
- char* pRGBA = new char[BlockSize];
- _pStream->Read(pRGBA,BlockSize,&BytesRead);
-
- if (BytesRead != (ULONG)BlockSize)
- return E_UNEXPECTED;
-
- // Convert to BGRA for Windows
- for (int i=0; i < BlockSize; i+=4 )
- {
- #define RED_BYTE pRGBA[i]
- #define BLUE_BYTE pRGBA[i+2]
-
- char red = RED_BYTE;
- RED_BYTE = BLUE_BYTE;
- BLUE_BYTE = red;
- }
-
- // Flip vertically (Blender stores it upside-down)
- unsigned int LineSize = width*4;
- char* FlippedImage = new char[BlockSize];
- for (int i=0; i<height; i++)
- {
- if ( 0 != memcpy_s(&FlippedImage[ (height - i - 1)*LineSize ],LineSize,&pRGBA[ i*LineSize ],LineSize))
- return E_UNEXPECTED;
- }
- delete[] pRGBA;
- pRGBA = FlippedImage;
-
- // Create image
- *phbmp = CreateBitmap(width,height,1,32,pRGBA);
- if (!*phbmp)
- return E_FAIL;
- *pdwAlpha = WTSAT_ARGB; // it's actually BGRA, not sure why this works
-
- // Scale down if required
- if ( (unsigned)width > cx || (unsigned)height > cx )
- {
- float scale = 1.0f / (max(width,height) / (float)cx);
- LONG NewWidth = (LONG)(width *scale);
- LONG NewHeight = (LONG)(height *scale);
-
-#ifdef _DEBUG
-#if 1
- MessageBox(0,L"Attach now",L"Debugging",MB_OK);
-#endif
-#endif
- IWICImagingFactory *pImgFac;
- hr = CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pImgFac));
-
- IWICBitmap* WICBmp;
- hr = pImgFac->CreateBitmapFromHBITMAP(*phbmp,0,WICBitmapUseAlpha,&WICBmp);
-
- BITMAPINFO bmi = {};
- bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
- bmi.bmiHeader.biWidth = NewWidth;
- bmi.bmiHeader.biHeight = -NewHeight;
- bmi.bmiHeader.biPlanes = 1;
- bmi.bmiHeader.biBitCount = 32;
- bmi.bmiHeader.biCompression = BI_RGB;
-
- BYTE *pBits;
- HBITMAP ResizedHBmp = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void**)&pBits, NULL, 0);
- hr = ResizedHBmp ? S_OK : E_OUTOFMEMORY;
- if (SUCCEEDED(hr))
- {
- IWICBitmapScaler* pIScaler;
- hr = pImgFac->CreateBitmapScaler(&pIScaler);
- hr = pIScaler->Initialize(WICBmp,NewWidth,NewHeight,WICBitmapInterpolationModeFant);
-
- WICRect rect = {0, 0, NewWidth, NewHeight};
- hr = pIScaler->CopyPixels(&rect, NewWidth * 4, NewWidth * NewHeight * 4, pBits);
-
- if (SUCCEEDED(hr))
- {
- DeleteObject(*phbmp);
- *phbmp = ResizedHBmp;
- }
- else
- DeleteObject(ResizedHBmp);
-
- pIScaler->Release();
- }
- WICBmp->Release();
- pImgFac->Release();
- }
- else
- hr = S_OK;
- break;
- }
- return hr;
-}
diff --git a/release/windows/blendthumb/src/Dll.cpp b/release/windows/blendthumb/src/Dll.cpp
deleted file mode 100644
index 7b0521cd5a8..00000000000
--- a/release/windows/blendthumb/src/Dll.cpp
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <objbase.h>
-#include <shlwapi.h>
-#include <thumbcache.h> // For IThumbnailProvider.
-#include <shlobj.h> // For SHChangeNotify
-#include <new>
-
-extern HRESULT CBlendThumb_CreateInstance(REFIID riid, void **ppv);
-
-#define SZ_CLSID_BLENDTHUMBHANDLER L"{D45F043D-F17F-4e8a-8435-70971D9FA46D}"
-#define SZ_BLENDTHUMBHANDLER L"Blender Thumbnail Handler"
-const CLSID CLSID_BlendThumbHandler = { 0xd45f043d, 0xf17f, 0x4e8a, { 0x84, 0x35, 0x70, 0x97, 0x1d, 0x9f, 0xa4, 0x6d } };
-
-typedef HRESULT (*PFNCREATEINSTANCE)(REFIID riid, void **ppvObject);
-struct CLASS_OBJECT_INIT
-{
- const CLSID *pClsid;
- PFNCREATEINSTANCE pfnCreate;
-};
-
-// add classes supported by this module here
-const CLASS_OBJECT_INIT c_rgClassObjectInit[] =
-{
- { &CLSID_BlendThumbHandler, CBlendThumb_CreateInstance }
-};
-
-
-long g_cRefModule = 0;
-
-// Handle the DLL's module
-HINSTANCE g_hInst = NULL;
-
-// Standard DLL functions
-STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, void *)
-{
- if (dwReason == DLL_PROCESS_ATTACH)
- {
- g_hInst = hInstance;
- DisableThreadLibraryCalls(hInstance);
- }
- return TRUE;
-}
-
-STDAPI DllCanUnloadNow()
-{
- // Only allow the DLL to be unloaded after all outstanding references have been released
- return (g_cRefModule == 0) ? S_OK : S_FALSE;
-}
-
-void DllAddRef()
-{
- InterlockedIncrement(&g_cRefModule);
-}
-
-void DllRelease()
-{
- InterlockedDecrement(&g_cRefModule);
-}
-
-class CClassFactory : public IClassFactory
-{
-public:
- static HRESULT CreateInstance(REFCLSID clsid, const CLASS_OBJECT_INIT *pClassObjectInits, size_t cClassObjectInits, REFIID riid, void **ppv)
- {
- *ppv = NULL;
- HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
- for (size_t i = 0; i < cClassObjectInits; i++)
- {
- if (clsid == *pClassObjectInits[i].pClsid)
- {
- IClassFactory *pClassFactory = new (std::nothrow) CClassFactory(pClassObjectInits[i].pfnCreate);
- hr = pClassFactory ? S_OK : E_OUTOFMEMORY;
- if (SUCCEEDED(hr))
- {
- hr = pClassFactory->QueryInterface(riid, ppv);
- pClassFactory->Release();
- }
- break; // match found
- }
- }
- return hr;
- }
-
- CClassFactory(PFNCREATEINSTANCE pfnCreate) : _cRef(1), _pfnCreate(pfnCreate)
- {
- DllAddRef();
- }
-
- // IUnknown
- IFACEMETHODIMP QueryInterface(REFIID riid, void ** ppv)
- {
- static const QITAB qit[] =
- {
- QITABENT(CClassFactory, IClassFactory),
- { 0 }
- };
- return QISearch(this, qit, riid, ppv);
- }
-
- IFACEMETHODIMP_(ULONG) AddRef()
- {
- return InterlockedIncrement(&_cRef);
- }
-
- IFACEMETHODIMP_(ULONG) Release()
- {
- long cRef = InterlockedDecrement(&_cRef);
- if (cRef == 0)
- {
- delete this;
- }
- return cRef;
- }
-
- // IClassFactory
- IFACEMETHODIMP CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
- {
- return punkOuter ? CLASS_E_NOAGGREGATION : _pfnCreate(riid, ppv);
- }
-
- IFACEMETHODIMP LockServer(BOOL fLock)
- {
- if (fLock)
- {
- DllAddRef();
- }
- else
- {
- DllRelease();
- }
- return S_OK;
- }
-
-private:
- ~CClassFactory()
- {
- DllRelease();
- }
-
- long _cRef;
- PFNCREATEINSTANCE _pfnCreate;
-};
-
-STDAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **ppv)
-{
- return CClassFactory::CreateInstance(clsid, c_rgClassObjectInit, ARRAYSIZE(c_rgClassObjectInit), riid, ppv);
-}
-
-// A struct to hold the information required for a registry entry
-
-struct REGISTRY_ENTRY
-{
- HKEY hkeyRoot;
- PCWSTR pszKeyName;
- PCWSTR pszValueName;
- DWORD dwValueType;
- PCWSTR pszData;
-};
-
-// Creates a registry key (if needed) and sets the default value of the key
-
-HRESULT CreateRegKeyAndSetValue(const REGISTRY_ENTRY *pRegistryEntry)
-{
- HKEY hKey;
- HRESULT hr = HRESULT_FROM_WIN32(RegCreateKeyExW(pRegistryEntry->hkeyRoot, pRegistryEntry->pszKeyName,
- 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL));
- if (SUCCEEDED(hr))
- {
- // All this just to support REG_DWORD...
- DWORD size;
- DWORD data;
- BYTE* lpData = (LPBYTE) pRegistryEntry->pszData;
- switch (pRegistryEntry->dwValueType)
- {
- case REG_SZ:
- size = ((DWORD) wcslen(pRegistryEntry->pszData) + 1) * sizeof(WCHAR);
- break;
- case REG_DWORD:
- size = sizeof(DWORD);
- data = (DWORD)pRegistryEntry->pszData;
- lpData = (BYTE*)&data;
- break;
- default:
- return E_INVALIDARG;
- }
-
- hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, pRegistryEntry->pszValueName, 0, pRegistryEntry->dwValueType,
- lpData, size ));
- RegCloseKey(hKey);
- }
- return hr;
-}
-
-//
-// Registers this COM server
-//
-STDAPI DllRegisterServer()
-{
- HRESULT hr;
-
- WCHAR szModuleName[MAX_PATH];
-
- if (!GetModuleFileNameW(g_hInst, szModuleName, ARRAYSIZE(szModuleName)))
- {
- hr = HRESULT_FROM_WIN32(GetLastError());
- }
- else
- {
- const REGISTRY_ENTRY rgRegistryEntries[] =
- {
- // RootKey KeyName ValueName ValueType Data
- {HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER, NULL, REG_SZ, SZ_BLENDTHUMBHANDLER},
- {HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER L"\\InProcServer32", NULL, REG_SZ, szModuleName},
- {HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER L"\\InProcServer32", L"ThreadingModel", REG_SZ, L"Apartment"},
- {HKEY_CURRENT_USER, L"Software\\Classes\\.blend\\", L"Treatment", REG_DWORD, 0}, // doesn't appear to do anything...
- {HKEY_CURRENT_USER, L"Software\\Classes\\.blend\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}", NULL, REG_SZ, SZ_CLSID_BLENDTHUMBHANDLER},
- };
-
- hr = S_OK;
- for (int i = 0; i < ARRAYSIZE(rgRegistryEntries) && SUCCEEDED(hr); i++)
- {
- hr = CreateRegKeyAndSetValue(&rgRegistryEntries[i]);
- }
- }
- if (SUCCEEDED(hr))
- {
- // This tells the shell to invalidate the thumbnail cache. This is important because any .blend files
- // viewed before registering this handler would otherwise show cached blank thumbnails.
- SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
- }
- return hr;
-}
-
-//
-// Unregisters this COM server
-//
-STDAPI DllUnregisterServer()
-{
- HRESULT hr = S_OK;
-
- const PCWSTR rgpszKeys[] =
- {
- L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER,
- L"Software\\Classes\\.blend\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}"
- };
-
- // Delete the registry entries
- for (int i = 0; i < ARRAYSIZE(rgpszKeys) && SUCCEEDED(hr); i++)
- {
- hr = HRESULT_FROM_WIN32(RegDeleteTreeW(HKEY_CURRENT_USER, rgpszKeys[i]));
- if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
- {
- // If the registry entry has already been deleted, say S_OK.
- hr = S_OK;
- }
- }
- return hr;
-}
diff --git a/release/windows/icons/cursors/arrowdown.cur b/release/windows/icons/cursors/arrowdown.cur
new file mode 100644
index 00000000000..251f3453e63
--- /dev/null
+++ b/release/windows/icons/cursors/arrowdown.cur
Binary files differ
diff --git a/release/windows/icons/cursors/arrowleft.cur b/release/windows/icons/cursors/arrowleft.cur
new file mode 100644
index 00000000000..6935e461a05
--- /dev/null
+++ b/release/windows/icons/cursors/arrowleft.cur
Binary files differ
diff --git a/release/windows/icons/cursors/arrowright.cur b/release/windows/icons/cursors/arrowright.cur
new file mode 100644
index 00000000000..ae561a54d04
--- /dev/null
+++ b/release/windows/icons/cursors/arrowright.cur
Binary files differ
diff --git a/release/windows/icons/cursors/arrowup.cur b/release/windows/icons/cursors/arrowup.cur
new file mode 100644
index 00000000000..5c29145f16b
--- /dev/null
+++ b/release/windows/icons/cursors/arrowup.cur
Binary files differ
diff --git a/release/windows/icons/cursors/cross.cur b/release/windows/icons/cursors/cross.cur
new file mode 100644
index 00000000000..62c5c322cfb
--- /dev/null
+++ b/release/windows/icons/cursors/cross.cur
Binary files differ
diff --git a/release/windows/icons/cursors/crossa.cur b/release/windows/icons/cursors/crossa.cur
new file mode 100644
index 00000000000..7a2bfa7f406
--- /dev/null
+++ b/release/windows/icons/cursors/crossa.cur
Binary files differ
diff --git a/release/windows/icons/cursors/crossb.cur b/release/windows/icons/cursors/crossb.cur
new file mode 100644
index 00000000000..78bb1a3574b
--- /dev/null
+++ b/release/windows/icons/cursors/crossb.cur
Binary files differ
diff --git a/release/windows/icons/cursors/crossc.cur b/release/windows/icons/cursors/crossc.cur
new file mode 100644
index 00000000000..5c54525b2dc
--- /dev/null
+++ b/release/windows/icons/cursors/crossc.cur
Binary files differ
diff --git a/release/windows/icons/cursors/eraser.cur b/release/windows/icons/cursors/eraser.cur
new file mode 100644
index 00000000000..c1e14ef3bae
--- /dev/null
+++ b/release/windows/icons/cursors/eraser.cur
Binary files differ
diff --git a/release/windows/icons/cursors/eyedropper.cur b/release/windows/icons/cursors/eyedropper.cur
new file mode 100644
index 00000000000..2294297b210
--- /dev/null
+++ b/release/windows/icons/cursors/eyedropper.cur
Binary files differ
diff --git a/release/windows/icons/cursors/forbidden.cur b/release/windows/icons/cursors/forbidden.cur
new file mode 100644
index 00000000000..2e45bad168b
--- /dev/null
+++ b/release/windows/icons/cursors/forbidden.cur
Binary files differ
diff --git a/release/windows/icons/cursors/handopen.cur b/release/windows/icons/cursors/handopen.cur
new file mode 100644
index 00000000000..cba18448873
--- /dev/null
+++ b/release/windows/icons/cursors/handopen.cur
Binary files differ
diff --git a/release/windows/icons/cursors/knife.cur b/release/windows/icons/cursors/knife.cur
new file mode 100644
index 00000000000..edc97d9e9f2
--- /dev/null
+++ b/release/windows/icons/cursors/knife.cur
Binary files differ
diff --git a/release/windows/icons/cursors/moveew.cur b/release/windows/icons/cursors/moveew.cur
new file mode 100644
index 00000000000..c2bef134cca
--- /dev/null
+++ b/release/windows/icons/cursors/moveew.cur
Binary files differ
diff --git a/release/windows/icons/cursors/movens.cur b/release/windows/icons/cursors/movens.cur
new file mode 100644
index 00000000000..409176a23f9
--- /dev/null
+++ b/release/windows/icons/cursors/movens.cur
Binary files differ
diff --git a/release/windows/icons/cursors/pencil.cur b/release/windows/icons/cursors/pencil.cur
new file mode 100644
index 00000000000..ac76b367d25
--- /dev/null
+++ b/release/windows/icons/cursors/pencil.cur
Binary files differ
diff --git a/release/windows/icons/cursors/pointer.cur b/release/windows/icons/cursors/pointer.cur
new file mode 100644
index 00000000000..d9b1ee8a60b
--- /dev/null
+++ b/release/windows/icons/cursors/pointer.cur
Binary files differ
diff --git a/release/windows/icons/cursors/scrollew.cur b/release/windows/icons/cursors/scrollew.cur
new file mode 100644
index 00000000000..c5eab1b9890
--- /dev/null
+++ b/release/windows/icons/cursors/scrollew.cur
Binary files differ
diff --git a/release/windows/icons/cursors/scrollns.cur b/release/windows/icons/cursors/scrollns.cur
new file mode 100644
index 00000000000..4b443220da8
--- /dev/null
+++ b/release/windows/icons/cursors/scrollns.cur
Binary files differ
diff --git a/release/windows/icons/cursors/scrollnsew.cur b/release/windows/icons/cursors/scrollnsew.cur
new file mode 100644
index 00000000000..fd0cad49c42
--- /dev/null
+++ b/release/windows/icons/cursors/scrollnsew.cur
Binary files differ
diff --git a/release/windows/icons/cursors/splith.cur b/release/windows/icons/cursors/splith.cur
new file mode 100644
index 00000000000..9b74fca7c6f
--- /dev/null
+++ b/release/windows/icons/cursors/splith.cur
Binary files differ
diff --git a/release/windows/icons/cursors/splitv.cur b/release/windows/icons/cursors/splitv.cur
new file mode 100644
index 00000000000..68a739eb11b
--- /dev/null
+++ b/release/windows/icons/cursors/splitv.cur
Binary files differ
diff --git a/release/windows/icons/cursors/zoomin.cur b/release/windows/icons/cursors/zoomin.cur
new file mode 100644
index 00000000000..8e6930b465a
--- /dev/null
+++ b/release/windows/icons/cursors/zoomin.cur
Binary files differ
diff --git a/release/windows/icons/cursors/zoomout.cur b/release/windows/icons/cursors/zoomout.cur
new file mode 100644
index 00000000000..834686c7ec0
--- /dev/null
+++ b/release/windows/icons/cursors/zoomout.cur
Binary files differ
diff --git a/release/windows/icons/winblender.rc b/release/windows/icons/winblender.rc
index 244c2cb2e2c..ba3363aacc5 100644
--- a/release/windows/icons/winblender.rc
+++ b/release/windows/icons/winblender.rc
@@ -13,6 +13,31 @@
APPICON ICON DISCARDABLE "winblender.ico"
BLENDERFILE ICON DISCARDABLE "winblenderfile.ico"
+pointer_cursor CURSOR "cursors/pointer.cur"
+moveew_cursor CURSOR "cursors/moveew.cur"
+movens_cursor CURSOR "cursors/movens.cur"
+arrowdown_cursor CURSOR "cursors/arrowdown.cur"
+arrowleft_cursor CURSOR "cursors/arrowleft.cur"
+arrowright_cursor CURSOR "cursors/arrowright.cur"
+arrowup_cursor CURSOR "cursors/arrowup.cur"
+cross_cursor CURSOR "cursors/cross.cur"
+crossA_cursor CURSOR "cursors/crossa.cur"
+crossB_cursor CURSOR "cursors/crossb.cur"
+crossC_cursor CURSOR "cursors/crossc.cur"
+eraser_cursor CURSOR "cursors/eraser.cur"
+eyedropper_cursor CURSOR "cursors/eyedropper.cur"
+handopen_cursor CURSOR "cursors/handopen.cur"
+knife_cursor CURSOR "cursors/knife.cur"
+pencil_cursor CURSOR "cursors/pencil.cur"
+scrollew_cursor CURSOR "cursors/scrollew.cur"
+scrollns_cursor CURSOR "cursors/scrollns.cur"
+scrollnsew_cursor CURSOR "cursors/scrollnsew.cur"
+splith_cursor CURSOR "cursors/splith.cur"
+splitv_cursor CURSOR "cursors/splitv.cur"
+zoomin_cursor CURSOR "cursors/zoomin.cur"
+zoomout_cursor CURSOR "cursors/zoomout.cur"
+forbidden_cursor CURSOR "cursors/forbidden.cur"
+
IDR_VERSION1 VERSIONINFO
FILEVERSION BLEN_VER_RC_1, BLEN_VER_RC_2, BLEN_VER_RC_3, BLEN_VER_RC_4
PRODUCTVERSION BLEN_VER_RC_1, BLEN_VER_RC_2, BLEN_VER_RC_3, BLEN_VER_RC_4
@@ -27,7 +52,7 @@ BEGIN
VALUE "ProductVersion", BLEN_VER_RC_STR
VALUE "CompanyName", "Blender Foundation"
VALUE "FileDescription", "Blender"
- VALUE "LegalCopyright", "GPLv2 (Blender Foundation)"
+ VALUE "LegalCopyright", "GPLv3 (Blender Foundation)"
VALUE "OriginalFilename", "blender.exe"
VALUE "ProductName", "Blender"
END
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index 76442048594..203543b0ef0 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -153,3 +153,7 @@ endif()
if(WITH_ALEMBIC)
add_subdirectory(alembic)
endif()
+
+if(WIN32)
+ add_subdirectory(blendthumb)
+endif()
diff --git a/source/blender/alembic/ABC_alembic.h b/source/blender/alembic/ABC_alembic.h
index 696e0ff1810..7c5efaf309d 100644
--- a/source/blender/alembic/ABC_alembic.h
+++ b/source/blender/alembic/ABC_alembic.h
@@ -27,6 +27,7 @@ extern "C" {
struct CacheReader;
struct ListBase;
+struct Main;
struct Mesh;
struct Object;
struct Scene;
@@ -103,7 +104,9 @@ bool ABC_import(struct bContext *C,
bool validate_meshes,
bool as_background_job);
-AbcArchiveHandle *ABC_create_handle(const char *filename, struct ListBase *object_paths);
+AbcArchiveHandle *ABC_create_handle(struct Main *bmain,
+ const char *filename,
+ struct ListBase *object_paths);
void ABC_free_handle(AbcArchiveHandle *handle);
diff --git a/source/blender/alembic/intern/abc_archive.cc b/source/blender/alembic/intern/abc_archive.cc
index c4252d20d48..bb527c23b20 100644
--- a/source/blender/alembic/intern/abc_archive.cc
+++ b/source/blender/alembic/intern/abc_archive.cc
@@ -24,6 +24,10 @@
#include "abc_archive.h"
extern "C" {
#include "BKE_blender_version.h"
+#include "BKE_main.h"
+
+#include "BLI_path_util.h"
+#include "BLI_string.h"
}
#ifdef WIN32
@@ -95,20 +99,24 @@ static IArchive open_archive(const std::string &filename,
return IArchive();
}
-ArchiveReader::ArchiveReader(const char *filename)
+ArchiveReader::ArchiveReader(struct Main *bmain, const char *filename)
{
+ char abs_filename[FILE_MAX];
+ BLI_strncpy(abs_filename, filename, FILE_MAX);
+ BLI_path_abs(abs_filename, BKE_main_blendfile_path(bmain));
+
#ifdef WIN32
- UTF16_ENCODE(filename);
- std::wstring wstr(filename_16);
+ UTF16_ENCODE(abs_filename);
+ std::wstring wstr(abs_filename_16);
m_infile.open(wstr.c_str(), std::ios::in | std::ios::binary);
- UTF16_UN_ENCODE(filename);
+ UTF16_UN_ENCODE(abs_filename);
#else
- m_infile.open(filename, std::ios::in | std::ios::binary);
+ m_infile.open(abs_filename, std::ios::in | std::ios::binary);
#endif
m_streams.push_back(&m_infile);
- m_archive = open_archive(filename, m_streams, m_is_hdf5);
+ m_archive = open_archive(abs_filename, m_streams, m_is_hdf5);
/* We can't open an HDF5 file from a stream, so close it. */
if (m_is_hdf5) {
diff --git a/source/blender/alembic/intern/abc_archive.h b/source/blender/alembic/intern/abc_archive.h
index 343a8112aa2..a64de742cdf 100644
--- a/source/blender/alembic/intern/abc_archive.h
+++ b/source/blender/alembic/intern/abc_archive.h
@@ -34,6 +34,8 @@
#include <fstream>
+struct Main;
+
/* Wrappers around input and output archives. The goal is to be able to use
* streams so that unicode paths work on Windows (T49112), and to make sure that
* the stream objects remain valid as long as the archives are open.
@@ -46,7 +48,7 @@ class ArchiveReader {
bool m_is_hdf5;
public:
- explicit ArchiveReader(const char *filename);
+ ArchiveReader(struct Main *bmain, const char *filename);
bool valid() const;
diff --git a/source/blender/alembic/intern/abc_curves.cc b/source/blender/alembic/intern/abc_curves.cc
index 13872618d74..50aa13bea4f 100644
--- a/source/blender/alembic/intern/abc_curves.cc
+++ b/source/blender/alembic/intern/abc_curves.cc
@@ -111,7 +111,7 @@ void AbcCurveWriter::do_write()
const BPoint *point = nurbs->bp;
- for (int i = 0; i < totpoint; ++i, ++point) {
+ for (int i = 0; i < totpoint; i++, point++) {
copy_yup_from_zup(temp_vert.getValue(), point->vec);
verts.push_back(temp_vert);
weights.push_back(point->vec[3]);
@@ -127,7 +127,7 @@ void AbcCurveWriter::do_write()
const BezTriple *bezier = nurbs->bezt;
/* TODO(kevin): store info about handles, Alembic doesn't have this. */
- for (int i = 0; i < totpoint; ++i, ++bezier) {
+ for (int i = 0; i < totpoint; i++, bezier++) {
copy_yup_from_zup(temp_vert.getValue(), bezier->vec[1]);
verts.push_back(temp_vert);
widths.push_back(bezier->radius);
@@ -144,7 +144,7 @@ void AbcCurveWriter::do_write()
* cyclic since other software need those.
*/
- for (int i = 0; i < nurbs->orderu; ++i) {
+ for (int i = 0; i < nurbs->orderu; i++) {
verts.push_back(verts[i]);
}
}
@@ -156,7 +156,7 @@ void AbcCurveWriter::do_write()
* require/expect them. */
knots.resize(num_knots + 2);
- for (int i = 0; i < num_knots; ++i) {
+ for (int i = 0; i < num_knots; i++) {
knots[i + 1] = nurbs->knotsu[i];
}
@@ -316,7 +316,7 @@ void AbcCurveReader::read_curve_sample(Curve *cu,
int knot_offset = 0;
size_t idx = 0;
- for (size_t i = 0; i < num_vertices->size(); ++i) {
+ for (size_t i = 0; i < num_vertices->size(); i++) {
const int num_verts = (*num_vertices)[i];
Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "abc_getnurb"));
@@ -357,7 +357,7 @@ void AbcCurveReader::read_curve_sample(Curve *cu,
const int end = idx + num_verts;
int overlap = 0;
- for (int j = start, k = end - nu->orderu; j < nu->orderu; ++j, ++k) {
+ for (int j = start, k = end - nu->orderu; j < nu->orderu; j++, k++) {
const Imath::V3f &p1 = (*positions)[j];
const Imath::V3f &p2 = (*positions)[k];
@@ -365,7 +365,7 @@ void AbcCurveReader::read_curve_sample(Curve *cu,
break;
}
- ++overlap;
+ overlap++;
}
/* TODO: Special case, need to figure out how it coincides with knots. */
@@ -393,7 +393,7 @@ void AbcCurveReader::read_curve_sample(Curve *cu,
nu->bp = static_cast<BPoint *>(MEM_callocN(sizeof(BPoint) * nu->pntsu, "abc_getnurb"));
BPoint *bp = nu->bp;
- for (int j = 0; j < nu->pntsu; ++j, ++bp, ++idx) {
+ for (int j = 0; j < nu->pntsu; j++, bp++, idx++) {
const Imath::V3f &pos = (*positions)[idx];
if (do_radius) {
@@ -418,7 +418,7 @@ void AbcCurveReader::read_curve_sample(Curve *cu,
/* TODO: second check is temporary, for until the check for cycles is rock solid. */
if (periodicity == Alembic::AbcGeom::kPeriodic && (KNOTSU(nu) == knots->size() - 2)) {
/* Skip first and last knots. */
- for (size_t i = 1; i < knots->size() - 1; ++i) {
+ for (size_t i = 1; i < knots->size() - 1; i++) {
nu->knotsu[i - 1] = (*knots)[knot_offset + i];
}
}
@@ -476,7 +476,7 @@ Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh,
if (same_topology) {
Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
- for (curve_idx = 0; nurbs; nurbs = nurbs->next, ++curve_idx) {
+ for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
const int num_in_alembic = (*num_vertices)[curve_idx];
const int num_in_blender = nurbs->pntsu;
@@ -493,13 +493,13 @@ Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh,
}
else {
Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
- for (curve_idx = 0; nurbs; nurbs = nurbs->next, ++curve_idx) {
+ for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
const int totpoint = (*num_vertices)[curve_idx];
if (nurbs->bp) {
BPoint *point = nurbs->bp;
- for (int i = 0; i < totpoint; ++i, ++point, ++vertex_idx) {
+ for (int i = 0; i < totpoint; i++, point++, vertex_idx++) {
const Imath::V3f &pos = (*positions)[vertex_idx];
copy_zup_from_yup(point->vec, pos.getValue());
}
@@ -507,7 +507,7 @@ Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh,
else if (nurbs->bezt) {
BezTriple *bezier = nurbs->bezt;
- for (int i = 0; i < totpoint; ++i, ++bezier, ++vertex_idx) {
+ for (int i = 0; i < totpoint; i++, bezier++, vertex_idx++) {
const Imath::V3f &pos = (*positions)[vertex_idx];
copy_zup_from_yup(bezier->vec[1], pos.getValue());
}
diff --git a/source/blender/alembic/intern/abc_customdata.cc b/source/blender/alembic/intern/abc_customdata.cc
index 63887d36381..7f04bb77052 100644
--- a/source/blender/alembic/intern/abc_customdata.cc
+++ b/source/blender/alembic/intern/abc_customdata.cc
@@ -72,12 +72,12 @@ static void get_uvs(const CDStreamConfig &config,
uvs.resize(config.totloop);
/* Iterate in reverse order to match exported polygons. */
- for (int i = 0; i < num_poly; ++i) {
+ for (int i = 0; i < num_poly; i++) {
MPoly &current_poly = polygons[i];
MLoopUV *loopuv = mloopuv_array + current_poly.loopstart + current_poly.totloop;
- for (int j = 0; j < current_poly.totloop; ++j, ++cnt) {
- --loopuv;
+ for (int j = 0; j < current_poly.totloop; j++, cnt++) {
+ loopuv--;
uvidx[cnt] = cnt;
uvs[cnt][0] = loopuv->uv[0];
@@ -90,14 +90,14 @@ static void get_uvs(const CDStreamConfig &config,
std::vector<std::vector<uint32_t>> idx_map(config.totvert);
int idx_count = 0;
- for (int i = 0; i < num_poly; ++i) {
+ for (int i = 0; i < num_poly; i++) {
MPoly &current_poly = polygons[i];
MLoop *looppoly = mloop + current_poly.loopstart + current_poly.totloop;
MLoopUV *loopuv = mloopuv_array + current_poly.loopstart + current_poly.totloop;
- for (int j = 0; j < current_poly.totloop; ++j) {
- --looppoly;
- --loopuv;
+ for (int j = 0; j < current_poly.totloop; j++) {
+ looppoly--;
+ loopuv--;
Imath::V2f uv(loopuv->uv[0], loopuv->uv[1]);
bool found_same = false;
@@ -188,12 +188,12 @@ static void write_mcol(const OCompoundProperty &prop,
Imath::C4f col;
- for (int i = 0; i < config.totpoly; ++i) {
+ for (int i = 0; i < config.totpoly; i++) {
MPoly *p = &polys[i];
MCol *cface = &cfaces[p->loopstart + p->totloop];
MLoop *mloop = &mloops[p->loopstart + p->totloop];
- for (int j = 0; j < p->totloop; ++j) {
+ for (int j = 0; j < p->totloop; j++) {
cface--;
mloop--;
@@ -230,7 +230,7 @@ void write_custom_data(const OCompoundProperty &prop,
const int active_layer = CustomData_get_active_layer(data, cd_data_type);
const int tot_layers = CustomData_number_of_layers(data, cd_data_type);
- for (int i = 0; i < tot_layers; ++i) {
+ for (int i = 0; i < tot_layers; i++) {
void *cd_data = CustomData_get_layer_n(data, cd_data_type, i);
const char *name = CustomData_get_layer_name(data, cd_data_type, i);
@@ -268,11 +268,11 @@ static void read_uvs(const CDStreamConfig &config,
unsigned int uv_index, loop_index, rev_loop_index;
- for (int i = 0; i < config.totpoly; ++i) {
+ for (int i = 0; i < config.totpoly; i++) {
MPoly &poly = mpolys[i];
unsigned int rev_loop_offset = poly.loopstart + poly.totloop - 1;
- for (int f = 0; f < poly.totloop; ++f) {
+ for (int f = 0; f < poly.totloop; f++) {
loop_index = poly.loopstart + f;
rev_loop_index = rev_loop_offset - f;
uv_index = (*indices)[loop_index];
@@ -368,14 +368,14 @@ static void read_custom_data_mcols(const std::string &iobject_full_name,
* is why we have to check for indices->size() > 0 */
bool use_dual_indexing = is_facevarying && indices->size() > 0;
- for (int i = 0; i < config.totpoly; ++i) {
+ for (int i = 0; i < config.totpoly; i++) {
MPoly *poly = &mpolys[i];
MCol *cface = &cfaces[poly->loopstart + poly->totloop];
MLoop *mloop = &mloops[poly->loopstart + poly->totloop];
- for (int j = 0; j < poly->totloop; ++j, ++face_index) {
- --cface;
- --mloop;
+ for (int j = 0; j < poly->totloop; j++, face_index++) {
+ cface--;
+ mloop--;
color_index = is_facevarying ? face_index : mloop->v;
if (use_dual_indexing) {
@@ -456,7 +456,7 @@ void read_custom_data(const std::string &iobject_full_name,
const size_t num_props = prop.getNumProperties();
- for (size_t i = 0; i < num_props; ++i) {
+ for (size_t i = 0; i < num_props; i++) {
const Alembic::Abc::PropertyHeader &prop_header = prop.getPropertyHeader(i);
/* Read UVs according to convention. */
diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc
index f19e0257b1b..69a376d00b0 100644
--- a/source/blender/alembic/intern/abc_exporter.cc
+++ b/source/blender/alembic/intern/abc_exporter.cc
@@ -202,7 +202,7 @@ AbcExporter::~AbcExporter()
}
/* Free shapes vector */
- for (int i = 0, e = m_shapes.size(); i != e; ++i) {
+ for (int i = 0, e = m_shapes.size(); i != e; i++) {
delete m_shapes[i];
}
@@ -223,7 +223,7 @@ void AbcExporter::getShutterSamples(unsigned int nr_of_samples,
double time_inc = (shutter_close - shutter_open) / nr_of_samples;
/* sample between shutter open & close */
- for (int sample = 0; sample < nr_of_samples; ++sample) {
+ for (int sample = 0; sample < nr_of_samples; sample++) {
double sample_time = shutter_open + time_inc * sample;
double time = (frame_offset + sample_time) / time_factor;
@@ -257,13 +257,13 @@ void AbcExporter::getFrameSet(unsigned int nr_of_samples, std::set<double> &fram
getShutterSamples(nr_of_samples, false, shutter_samples);
for (double frame = m_settings.frame_start; frame <= m_settings.frame_end; frame += 1.0) {
- for (size_t j = 0; j < nr_of_samples; ++j) {
+ for (size_t j = 0; j < nr_of_samples; j++) {
frames.insert(frame + shutter_samples[j]);
}
}
}
-void AbcExporter::operator()(float &progress, bool &was_canceled)
+void AbcExporter::operator()(short *do_update, float *progress, bool *was_canceled)
{
std::string scene_name;
@@ -332,10 +332,11 @@ void AbcExporter::operator()(float &progress, bool &was_canceled)
size_t i = 0;
for (; begin != end; ++begin) {
- progress = (++i / size);
+ *progress = (++i / size);
+ *do_update = 1;
if (G.is_break) {
- was_canceled = true;
+ *was_canceled = true;
break;
}
@@ -345,7 +346,7 @@ void AbcExporter::operator()(float &progress, bool &was_canceled)
setCurrentFrame(m_bmain, frame);
if (shape_frames.count(frame) != 0) {
- for (int i = 0, e = m_shapes.size(); i != e; ++i) {
+ for (int i = 0, e = m_shapes.size(); i != e; i++) {
m_shapes[i]->write();
}
}
diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h
index e6a7a3fc7f4..a73289fcf95 100644
--- a/source/blender/alembic/intern/abc_exporter.h
+++ b/source/blender/alembic/intern/abc_exporter.h
@@ -104,7 +104,7 @@ class AbcExporter {
AbcExporter(Main *bmain, const char *filename, ExportSettings &settings);
~AbcExporter();
- void operator()(float &progress, bool &was_canceled);
+ void operator()(short *do_update, float *progress, bool *was_canceled);
protected:
void getShutterSamples(unsigned int nr_of_samples,
diff --git a/source/blender/alembic/intern/abc_hair.cc b/source/blender/alembic/intern/abc_hair.cc
index b2489169856..98387be2e61 100644
--- a/source/blender/alembic/intern/abc_hair.cc
+++ b/source/blender/alembic/intern/abc_hair.cc
@@ -79,10 +79,14 @@ void AbcHairWriter::do_write()
if (m_psys->pathcache) {
ParticleSettings *part = m_psys->part;
+ bool export_children = m_settings.export_child_hairs && m_psys->childcache &&
+ part->childtype != 0;
- write_hair_sample(mesh, part, verts, norm_values, uv_values, hvertices);
+ if (!export_children || part->draw & PART_DRAW_PARENT) {
+ write_hair_sample(mesh, part, verts, norm_values, uv_values, hvertices);
+ }
- if (m_settings.export_child_hairs && m_psys->childcache) {
+ if (export_children) {
write_hair_child_sample(mesh, part, verts, norm_values, uv_values, hvertices);
}
}
@@ -139,7 +143,7 @@ void AbcHairWriter::write_hair_sample(Mesh *mesh,
float normal[3];
Imath::V3f tmp_nor;
- for (int p = 0; p < m_psys->totpart; ++p, ++pa) {
+ for (int p = 0; p < m_psys->totpart; p++, pa++) {
/* underlying info for faces-only emission */
path = cache[p];
@@ -173,7 +177,7 @@ void AbcHairWriter::write_hair_sample(Mesh *mesh,
const int num = (pa->num_dmcache >= 0) ? pa->num_dmcache : pa->num;
/* iterate over all faces to find a corresponding underlying UV */
- for (int n = 0; n < mesh->totface; ++n) {
+ for (int n = 0; n < mesh->totface; n++) {
MFace *face = &mface[n];
MTFace *tface = mtface + n;
unsigned int vtx[4];
@@ -183,7 +187,7 @@ void AbcHairWriter::write_hair_sample(Mesh *mesh,
vtx[3] = face->v4;
bool found = false;
- for (int o = 0; o < 4; ++o) {
+ for (int o = 0; o < 4; o++) {
if (o > 2 && vtx[o] == 0) {
break;
}
@@ -210,7 +214,7 @@ void AbcHairWriter::write_hair_sample(Mesh *mesh,
int steps = path->segments + 1;
hvertices.push_back(steps);
- for (k = 0; k < steps; ++k, ++path) {
+ for (k = 0; k < steps; k++, path++) {
float vert[3];
copy_v3_v3(vert, path->co);
mul_m4_v3(inv_mat, vert);
@@ -240,7 +244,7 @@ void AbcHairWriter::write_hair_child_sample(Mesh *mesh,
ChildParticle *pc = m_psys->child;
- for (int p = 0; p < m_psys->totchild; ++p, ++pc) {
+ for (int p = 0; p < m_psys->totchild; p++, pc++) {
path = cache[p];
if (part->from == PART_FROM_FACE && part->childtype != PART_CHILD_PARTICLES && mtface) {
@@ -278,7 +282,7 @@ void AbcHairWriter::write_hair_child_sample(Mesh *mesh,
int steps = path->segments + 1;
hvertices.push_back(steps);
- for (int k = 0; k < steps; ++k) {
+ for (int k = 0; k < steps; k++) {
float vert[3];
copy_v3_v3(vert, path->co);
mul_m4_v3(inv_mat, vert);
@@ -286,7 +290,7 @@ void AbcHairWriter::write_hair_child_sample(Mesh *mesh,
/* Convert Z-up to Y-up. */
verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1]));
- ++path;
+ path++;
}
}
}
diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc
index 8728303923a..12c59964a8c 100644
--- a/source/blender/alembic/intern/abc_mesh.cc
+++ b/source/blender/alembic/intern/abc_mesh.cc
@@ -116,7 +116,7 @@ static void get_vertices(struct Mesh *mesh, std::vector<Imath::V3f> &points)
MVert *verts = mesh->mvert;
- for (int i = 0, e = mesh->totvert; i < e; ++i) {
+ for (int i = 0, e = mesh->totvert; i < e; i++) {
copy_yup_from_zup(points[i].getValue(), verts[i].co);
}
}
@@ -137,7 +137,7 @@ static void get_topology(struct Mesh *mesh,
loop_counts.reserve(num_poly);
/* NOTE: data needs to be written in the reverse order. */
- for (int i = 0; i < num_poly; ++i) {
+ for (int i = 0; i < num_poly; i++) {
MPoly &poly = mpoly[i];
loop_counts.push_back(poly.totloop);
@@ -145,7 +145,7 @@ static void get_topology(struct Mesh *mesh,
MLoop *loop = mloop + poly.loopstart + (poly.totloop - 1);
- for (int j = 0; j < poly.totloop; ++j, --loop) {
+ for (int j = 0; j < poly.totloop; j++, loop--) {
poly_verts.push_back(loop->v);
}
}
@@ -164,7 +164,7 @@ static void get_creases(struct Mesh *mesh,
MEdge *edge = mesh->medge;
- for (int i = 0, e = mesh->totedge; i < e; ++i) {
+ for (int i = 0, e = mesh->totedge; i < e; i++) {
const float sharpness = static_cast<float>(edge[i].crease) * factor;
if (sharpness != 0.0f) {
@@ -185,7 +185,7 @@ static void get_vertex_normals(struct Mesh *mesh, std::vector<Imath::V3f> &norma
MVert *verts = mesh->mvert;
float no[3];
- for (int i = 0, e = mesh->totvert; i < e; ++i) {
+ for (int i = 0, e = mesh->totvert; i < e; i++) {
normal_short_to_float_v3(no, verts[i].no);
copy_yup_from_zup(normals[i].getValue(), no);
}
@@ -209,8 +209,8 @@ static void get_loop_normals(struct Mesh *mesh, std::vector<Imath::V3f> &normals
int abc_index = 0;
if (lnors) {
- for (int i = 0, e = mesh->totpoly; i < e; ++i, ++mp) {
- for (int j = mp->totloop - 1; j >= 0; --j, ++abc_index) {
+ for (int i = 0, e = mesh->totpoly; i < e; i++, mp++) {
+ for (int j = mp->totloop - 1; j >= 0; j--, abc_index++) {
int blender_index = mp->loopstart + j;
copy_yup_from_zup(normals[abc_index].getValue(), lnors[blender_index]);
}
@@ -219,20 +219,20 @@ static void get_loop_normals(struct Mesh *mesh, std::vector<Imath::V3f> &normals
else {
float no[3];
- for (int i = 0, e = mesh->totpoly; i < e; ++i, ++mp) {
+ for (int i = 0, e = mesh->totpoly; i < e; i++, mp++) {
ml = mloop + mp->loopstart + (mp->totloop - 1);
/* Flat shaded, use common normal for all verts. */
if ((mp->flag & ME_SMOOTH) == 0) {
BKE_mesh_calc_poly_normal(mp, ml - (mp->totloop - 1), verts, no);
- for (int j = 0; j < mp->totloop; --ml, ++j, ++abc_index) {
+ for (int j = 0; j < mp->totloop; ml--, j++, abc_index++) {
copy_yup_from_zup(normals[abc_index].getValue(), no);
}
}
else {
/* Smooth shaded, use individual vert normals. */
- for (int j = 0; j < mp->totloop; --ml, ++j, ++abc_index) {
+ for (int j = 0; j < mp->totloop; ml--, j++, abc_index++) {
normal_short_to_float_v3(no, verts[ml->v].no);
copy_yup_from_zup(normals[abc_index].getValue(), no);
}
@@ -561,7 +561,7 @@ Mesh *AbcGenericMeshWriter::getFinalMesh(bool &r_needsfree)
BM_mesh_triangulate(bm, quad_method, ngon_method, 4, tag_only, NULL, NULL, NULL);
- Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
if (r_needsfree) {
@@ -615,7 +615,7 @@ void AbcGenericMeshWriter::getVelocities(struct Mesh *mesh, std::vector<Imath::V
if (fss->meshVelocities) {
float *mesh_vels = reinterpret_cast<float *>(fss->meshVelocities);
- for (int i = 0; i < totverts; ++i) {
+ for (int i = 0; i < totverts; i++) {
copy_yup_from_zup(vels[i].getValue(), mesh_vels);
mesh_vels += 3;
}
@@ -631,7 +631,7 @@ void AbcGenericMeshWriter::getGeoGroups(struct Mesh *mesh,
const int num_poly = mesh->totpoly;
MPoly *polygons = mesh->mpoly;
- for (int i = 0; i < num_poly; ++i) {
+ for (int i = 0; i < num_poly; i++) {
MPoly &current_poly = polygons[i];
short mnr = current_poly.mat_nr;
@@ -658,7 +658,7 @@ void AbcGenericMeshWriter::getGeoGroups(struct Mesh *mesh,
std::vector<int32_t> faceArray;
- for (int i = 0, e = mesh->totface; i < e; ++i) {
+ for (int i = 0, e = mesh->totface; i < e; i++) {
faceArray.push_back(i);
}
@@ -707,7 +707,7 @@ static void assign_materials(Main *bmain,
std::map<std::string, int>::const_iterator it = mat_index_map.begin();
int matcount = 0;
- for (; it != mat_index_map.end(); ++it, ++matcount) {
+ for (; it != mat_index_map.end(); ++it, matcount++) {
if (!BKE_object_material_slot_add(bmain, ob)) {
can_assign = false;
break;
@@ -770,7 +770,7 @@ static void read_mverts_interp(MVert *mverts,
const float weight)
{
float tmp[3];
- for (int i = 0; i < positions->size(); ++i) {
+ for (int i = 0; i < positions->size(); i++) {
MVert &mvert = mverts[i];
const Imath::V3f &floor_pos = (*positions)[i];
const Imath::V3f &ceil_pos = (*ceil_positions)[i];
@@ -801,7 +801,7 @@ void read_mverts(MVert *mverts,
const P3fArraySamplePtr &positions,
const N3fArraySamplePtr &normals)
{
- for (int i = 0; i < positions->size(); ++i) {
+ for (int i = 0; i < positions->size(); i++) {
MVert &mvert = mverts[i];
Imath::V3f pos_in = (*positions)[i];
@@ -839,7 +839,7 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
unsigned int rev_loop_index = 0;
unsigned int uv_index = 0;
- for (int i = 0; i < face_counts->size(); ++i) {
+ for (int i = 0; i < face_counts->size(); i++) {
const int face_size = (*face_counts)[i];
MPoly &poly = mpolys[i];
@@ -856,7 +856,7 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
/* NOTE: Alembic data is stored in the reverse order. */
rev_loop_index = loop_index + (face_size - 1);
- for (int f = 0; f < face_size; ++f, ++loop_index, --rev_loop_index) {
+ for (int f = 0; f < face_size; f++, loop_index++, rev_loop_index--) {
MLoop &loop = mloops[rev_loop_index];
loop.v = (*face_indices)[loop_index];
@@ -899,9 +899,9 @@ static void process_normals(CDStreamConfig &config, const AbcMeshData &mesh_data
MPoly *mpoly = mesh->mpoly;
int abc_index = 0;
- for (int i = 0, e = mesh->totpoly; i < e; ++i, ++mpoly) {
+ for (int i = 0, e = mesh->totpoly; i < e; i++, mpoly++) {
/* As usual, ABC orders the loops in reverse. */
- for (int j = mpoly->totloop - 1; j >= 0; --j, ++abc_index) {
+ for (int j = mpoly->totloop - 1; j >= 0; j--, abc_index++) {
int blender_index = mpoly->loopstart + j;
copy_zup_from_yup(lnors[blender_index], loop_normals[abc_index].getValue());
}
@@ -1192,8 +1192,6 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
existing_mesh, positions->size(), 0, 0, face_indices->size(), face_counts->size());
settings.read_flag |= MOD_MESHSEQ_READ_ALL;
- /* XXX fixme after 2.80; mesh->flag isn't copied by BKE_mesh_new_nomain_from_template() */
- new_mesh->flag |= (existing_mesh->flag & ME_AUTOSMOOTH);
}
else {
/* If the face count changed (e.g. by triangulation), only read points.
@@ -1246,7 +1244,7 @@ void AbcMeshReader::assign_facesets_to_mpoly(const ISampleSelector &sample_sel,
int current_mat = 0;
- for (int i = 0; i < face_sets.size(); ++i) {
+ for (int i = 0; i < face_sets.size(); i++) {
const std::string &grp_name = face_sets[i];
if (r_mat_map.find(grp_name) == r_mat_map.end()) {
@@ -1292,7 +1290,7 @@ void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const ISampleSel
ABC_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2)
{
- for (int i = 0, e = totedge; i < e; ++i) {
+ for (int i = 0, e = totedge; i < e; i++) {
MEdge &edge = edges[i];
if (edge.v1 == v1 && edge.v2 == v2) {
@@ -1416,11 +1414,24 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
Int32ArraySamplePtr indices = sample.getCreaseIndices();
Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses();
- MEdge *edges = mesh->medge;
-
if (indices && sharpnesses) {
- for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, ++s) {
- MEdge *edge = find_edge(edges, mesh->totedge, (*indices)[i], (*indices)[i + 1]);
+ MEdge *edges = mesh->medge;
+ int totedge = mesh->totedge;
+
+ for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, s++) {
+ int v1 = (*indices)[i];
+ int v2 = (*indices)[i + 1];
+
+ if (v2 < v1) {
+ /* It appears to be common to store edges with the smallest index first, in which case this
+ * prevents us from doing the second search below. */
+ std::swap(v1, v2);
+ }
+
+ MEdge *edge = find_edge(edges, totedge, v1, v2);
+ if (edge == NULL) {
+ edge = find_edge(edges, totedge, v2, v1);
+ }
if (edge) {
edge->crease = unit_float_to_uchar_clamp((*sharpnesses)[s]);
diff --git a/source/blender/alembic/intern/abc_nurbs.cc b/source/blender/alembic/intern/abc_nurbs.cc
index c78cc4570c9..739276dffa6 100644
--- a/source/blender/alembic/intern/abc_nurbs.cc
+++ b/source/blender/alembic/intern/abc_nurbs.cc
@@ -74,7 +74,7 @@ AbcNurbsWriter::AbcNurbsWriter(Object *ob,
Curve *curve = static_cast<Curve *>(m_object->data);
size_t numNurbs = BLI_listbase_count(&curve->nurb);
- for (size_t i = 0; i < numNurbs; ++i) {
+ for (size_t i = 0; i < numNurbs; i++) {
std::stringstream str;
str << m_name << '_' << i;
@@ -106,7 +106,7 @@ static void get_knots(std::vector<float> &knots, const int num_knots, float *nu_
knots.push_back(0.0f);
- for (int i = 0; i < num_knots; ++i) {
+ for (int i = 0; i < num_knots; i++) {
knots.push_back(nu_knots[i]);
}
@@ -136,7 +136,7 @@ void AbcNurbsWriter::do_write()
}
size_t count = 0;
- for (Nurb *nu = static_cast<Nurb *>(nulb->first); nu; nu = nu->next, ++count) {
+ for (Nurb *nu = static_cast<Nurb *>(nulb->first); nu; nu = nu->next, count++) {
std::vector<float> knotsU;
get_knots(knotsU, KNOTSU(nu), nu->knotsu);
@@ -149,7 +149,7 @@ void AbcNurbsWriter::do_write()
const BPoint *bp = nu->bp;
- for (int i = 0; i < size; ++i, ++bp) {
+ for (int i = 0; i < size; i++, bp++) {
copy_yup_from_zup(positions[i].getValue(), bp->vec);
weights[i] = bp->vec[3];
}
@@ -229,7 +229,7 @@ static bool set_knots(const FloatArraySamplePtr &knots, float *&nu_knots)
const size_t num_knots = knots->size() - 2;
nu_knots = static_cast<float *>(MEM_callocN(num_knots * sizeof(float), "abc_setsplineknotsu"));
- for (size_t i = 0; i < num_knots; ++i) {
+ for (size_t i = 0; i < num_knots; i++) {
nu_knots[i] = (*knots)[i + 1];
}
@@ -281,7 +281,7 @@ void AbcNurbsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSele
BPoint *bp = nu->bp;
float posw_in = 1.0f;
- for (int i = 0; i < num_points; ++i, ++bp) {
+ for (int i = 0; i < num_points; i++, bp++) {
const Imath::V3f &pos_in = (*positions)[i];
if (weights) {
@@ -349,7 +349,7 @@ void AbcNurbsReader::getNurbsPatches(const IObject &obj)
return;
}
- for (int i = 0; i < num_children; ++i) {
+ for (int i = 0; i < num_children; i++) {
bool ok = true;
IObject child(obj, obj.getChildHeader(i).getName());
diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_object.cc
index ebebbc0da1e..b05246371fa 100644
--- a/source/blender/alembic/intern/abc_object.cc
+++ b/source/blender/alembic/intern/abc_object.cc
@@ -195,14 +195,14 @@ static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1,
* the matrices manually.
*/
- for (int i = 0; i < 4; ++i) {
- for (int j = 0; j < 4; ++j) {
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
mat0[i][j] = static_cast<float>(m0[i][j]);
}
}
- for (int i = 0; i < 4; ++i) {
- for (int j = 0; j < 4; ++j) {
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
mat1[i][j] = static_cast<float>(m1[i][j]);
}
}
@@ -211,8 +211,8 @@ static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1,
Imath::M44d m;
- for (int i = 0; i < 4; ++i) {
- for (int j = 0; j < 4; ++j) {
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
m[i][j] = ret[i][j];
}
}
@@ -389,11 +389,11 @@ int AbcObjectReader::refcount() const
void AbcObjectReader::incref()
{
- ++m_refcount;
+ m_refcount++;
}
void AbcObjectReader::decref()
{
- --m_refcount;
+ m_refcount--;
BLI_assert(m_refcount >= 0);
}
diff --git a/source/blender/alembic/intern/abc_transform.cc b/source/blender/alembic/intern/abc_transform.cc
index 08f8eb8bd8f..505acfc164a 100644
--- a/source/blender/alembic/intern/abc_transform.cc
+++ b/source/blender/alembic/intern/abc_transform.cc
@@ -122,7 +122,7 @@ Imath::Box3d AbcTransformWriter::bounds()
{
Imath::Box3d bounds;
- for (int i = 0; i < m_children.size(); ++i) {
+ for (int i = 0; i < m_children.size(); i++) {
Imath::Box3d box(m_children[i]->bounds());
bounds.extendBy(box);
}
diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc
index 2fc340f73ce..b6743c8b363 100644
--- a/source/blender/alembic/intern/abc_util.cc
+++ b/source/blender/alembic/intern/abc_util.cc
@@ -90,8 +90,8 @@ Imath::M44d convert_matrix(float mat[4][4])
{
Imath::M44d m;
- for (int i = 0; i < 4; ++i) {
- for (int j = 0; j < 4; ++j) {
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
m[i][j] = mat[i][j];
}
}
@@ -226,8 +226,8 @@ void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMod
void convert_matrix(const Imath::M44d &xform, Object *ob, float r_mat[4][4])
{
- for (int i = 0; i < 4; ++i) {
- for (int j = 0; j < 4; ++j) {
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
r_mat[i][j] = static_cast<float>(xform[i][j]);
}
}
diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc
index dc525e0c46c..1034c5b319f 100644
--- a/source/blender/alembic/intern/alembic_capi.cc
+++ b/source/blender/alembic/intern/alembic_capi.cc
@@ -129,7 +129,7 @@ static bool gather_objects_paths(const IObject &object, ListBase *object_paths)
size_t children_claiming_this_object = 0;
size_t num_children = object.getNumChildren();
- for (size_t i = 0; i < num_children; ++i) {
+ for (size_t i = 0; i < num_children; i++) {
bool child_claims_this_object = gather_objects_paths(object.getChild(i), object_paths);
children_claiming_this_object += child_claims_this_object ? 1 : 0;
}
@@ -173,9 +173,11 @@ static bool gather_objects_paths(const IObject &object, ListBase *object_paths)
return parent_is_part_of_this_object;
}
-AbcArchiveHandle *ABC_create_handle(const char *filename, ListBase *object_paths)
+AbcArchiveHandle *ABC_create_handle(struct Main *bmain,
+ const char *filename,
+ ListBase *object_paths)
{
- ArchiveReader *archive = new ArchiveReader(filename);
+ ArchiveReader *archive = new ArchiveReader(bmain, filename);
if (!archive->valid()) {
delete archive;
@@ -222,6 +224,7 @@ static void find_iobject(const IObject &object, IObject &ret, const std::string
struct ExportJobData {
ViewLayer *view_layer;
Main *bmain;
+ wmWindowManager *wm;
char filename[1024];
ExportSettings settings;
@@ -246,8 +249,7 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo
* scene frame in separate threads
*/
G.is_rendering = true;
- BKE_spacedata_draw_locks(true);
-
+ WM_set_locked_interface(data->wm, true);
G.is_break = false;
DEG_graph_build_from_view_layer(
@@ -261,7 +263,7 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo
const int orig_frame = CFRA;
data->was_canceled = false;
- exporter(*data->progress, data->was_canceled);
+ exporter(do_update, progress, &data->was_canceled);
if (CFRA != orig_frame) {
CFRA = orig_frame;
@@ -296,7 +298,7 @@ static void export_endjob(void *customdata)
}
G.is_rendering = false;
- BKE_spacedata_draw_locks(false);
+ WM_set_locked_interface(data->wm, false);
}
bool ABC_export(Scene *scene,
@@ -310,6 +312,7 @@ bool ABC_export(Scene *scene,
job->view_layer = CTX_data_view_layer(C);
job->bmain = CTX_data_main(C);
+ job->wm = CTX_wm_manager(C);
job->export_ok = false;
BLI_strncpy(job->filename, filepath, 1024);
@@ -330,7 +333,7 @@ bool ABC_export(Scene *scene,
* hardcore refactoring. */
new (&job->settings) ExportSettings();
job->settings.scene = scene;
- job->settings.depsgraph = DEG_graph_new(scene, job->view_layer, DAG_EVAL_RENDER);
+ job->settings.depsgraph = DEG_graph_new(job->bmain, scene, job->view_layer, DAG_EVAL_RENDER);
/* TODO(Sybren): for now we only export the active scene layer.
* Later in the 2.8 development process this may be replaced by using
@@ -452,7 +455,7 @@ static std::pair<bool, AbcObjectReader *> visit_object(
AbcObjectReader::ptr_vector claiming_child_readers;
AbcObjectReader::ptr_vector nonclaiming_child_readers;
AbcObjectReader::ptr_vector assign_as_parent;
- for (size_t i = 0; i < num_children; ++i) {
+ for (size_t i = 0; i < num_children; i++) {
const IObject ichild = object.getChild(i);
/* TODO: When we only support C++11, use std::tie() instead. */
@@ -649,7 +652,7 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
WM_set_locked_interface(data->wm, true);
- ArchiveReader *archive = new ArchiveReader(data->filename);
+ ArchiveReader *archive = new ArchiveReader(data->bmain, data->filename);
if (!archive->valid()) {
#ifndef WITH_ALEMBIC_HDF5
diff --git a/source/blender/avi/intern/avi_options.c b/source/blender/avi/intern/avi_options.c
index 4f7e26c874c..65db8c19397 100644
--- a/source/blender/avi/intern/avi_options.c
+++ b/source/blender/avi/intern/avi_options.c
@@ -42,8 +42,8 @@ AviError AVI_set_compress_option(
(void)stream; /* unused */
- if (movie->header->TotalFrames !=
- 0) { /* Can't change params after we have already started writing frames */
+ if (movie->header->TotalFrames != 0) {
+ /* Can't change params after we have already started writing frames. */
return AVI_ERROR_OPTION;
}
diff --git a/release/windows/blendthumb/CMakeLists.txt b/source/blender/blendthumb/CMakeLists.txt
index 45c583d1421..6c786dfcc7a 100644
--- a/release/windows/blendthumb/CMakeLists.txt
+++ b/source/blender/blendthumb/CMakeLists.txt
@@ -19,13 +19,8 @@
# ***** END GPL LICENSE BLOCK *****
#-----------------------------------------------------------------------------
-cmake_minimum_required(VERSION 2.8)
-project(BlendThumb)
+include_directories(${ZLIB_INCLUDE_DIRS})
-#Bring the headers, such as Student.h into the project
-include_directories(${ZLIB_INCLUDE})
-
-#Can manually add the sources using the set command as follows:
set(SRC
src/BlenderThumb.cpp
src/BlendThumb.def
@@ -34,5 +29,10 @@ set(SRC
)
add_library(BlendThumb SHARED ${SRC})
-target_link_libraries(BlendThumb ${ZLIB_LIBS})
-install (TARGETS BlendThumb DESTINATION bin)
+target_link_libraries(BlendThumb ${ZLIB_LIBRARIES})
+
+install(
+ FILES $<TARGET_FILE:BlendThumb>
+ COMPONENT Blender
+ DESTINATION "."
+)
diff --git a/release/windows/blendthumb/src/BlendThumb.def b/source/blender/blendthumb/src/BlendThumb.def
index 71f9236735f..71f9236735f 100644
--- a/release/windows/blendthumb/src/BlendThumb.def
+++ b/source/blender/blendthumb/src/BlendThumb.def
diff --git a/release/windows/blendthumb/src/BlendThumb.rc b/source/blender/blendthumb/src/BlendThumb.rc
index 5dfd416b0c5..5dfd416b0c5 100644
--- a/release/windows/blendthumb/src/BlendThumb.rc
+++ b/source/blender/blendthumb/src/BlendThumb.rc
diff --git a/source/blender/blendthumb/src/BlenderThumb.cpp b/source/blender/blendthumb/src/BlenderThumb.cpp
new file mode 100644
index 00000000000..be0adffbdfd
--- /dev/null
+++ b/source/blender/blendthumb/src/BlenderThumb.cpp
@@ -0,0 +1,321 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <shlwapi.h>
+#include <thumbcache.h> // For IThumbnailProvider.
+#include <new>
+
+#pragma comment(lib, "shlwapi.lib")
+
+// this thumbnail provider implements IInitializeWithStream to enable being hosted
+// in an isolated process for robustness
+
+class CBlendThumb : public IInitializeWithStream, public IThumbnailProvider {
+ public:
+ CBlendThumb() : _cRef(1), _pStream(NULL)
+ {
+ }
+
+ virtual ~CBlendThumb()
+ {
+ if (_pStream) {
+ _pStream->Release();
+ }
+ }
+
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv)
+ {
+ static const QITAB qit[] = {
+ QITABENT(CBlendThumb, IInitializeWithStream),
+ QITABENT(CBlendThumb, IThumbnailProvider),
+ {0},
+ };
+ return QISearch(this, qit, riid, ppv);
+ }
+
+ IFACEMETHODIMP_(ULONG) AddRef()
+ {
+ return InterlockedIncrement(&_cRef);
+ }
+
+ IFACEMETHODIMP_(ULONG) Release()
+ {
+ ULONG cRef = InterlockedDecrement(&_cRef);
+ if (!cRef) {
+ delete this;
+ }
+ return cRef;
+ }
+
+ // IInitializeWithStream
+ IFACEMETHODIMP Initialize(IStream *pStream, DWORD grfMode);
+
+ // IThumbnailProvider
+ IFACEMETHODIMP GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha);
+
+ private:
+ long _cRef;
+ IStream *_pStream; // provided during initialization.
+};
+
+HRESULT CBlendThumb_CreateInstance(REFIID riid, void **ppv)
+{
+ CBlendThumb *pNew = new (std::nothrow) CBlendThumb();
+ HRESULT hr = pNew ? S_OK : E_OUTOFMEMORY;
+ if (SUCCEEDED(hr)) {
+ hr = pNew->QueryInterface(riid, ppv);
+ pNew->Release();
+ }
+ return hr;
+}
+
+// IInitializeWithStream
+IFACEMETHODIMP CBlendThumb::Initialize(IStream *pStream, DWORD)
+{
+ HRESULT hr = E_UNEXPECTED; // can only be inited once
+ if (_pStream == NULL) {
+ // take a reference to the stream if we have not been inited yet
+ hr = pStream->QueryInterface(&_pStream);
+ }
+ return hr;
+}
+
+#include <math.h>
+#include <zlib.h>
+#include "Wincodec.h"
+const unsigned char gzip_magic[3] = {0x1f, 0x8b, 0x08};
+
+// IThumbnailProvider
+IFACEMETHODIMP CBlendThumb::GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha)
+{
+ ULONG BytesRead;
+ HRESULT hr = S_FALSE;
+ LARGE_INTEGER SeekPos;
+
+ // Compressed?
+ unsigned char in_magic[3];
+ _pStream->Read(&in_magic, 3, &BytesRead);
+ bool gzipped = true;
+ for (int i = 0; i < 3; i++)
+ if (in_magic[i] != gzip_magic[i]) {
+ gzipped = false;
+ break;
+ }
+
+ if (gzipped) {
+ // Zlib inflate
+ z_stream stream;
+ stream.zalloc = Z_NULL;
+ stream.zfree = Z_NULL;
+ stream.opaque = Z_NULL;
+
+ // Get compressed file length
+ SeekPos.QuadPart = 0;
+ _pStream->Seek(SeekPos, STREAM_SEEK_END, NULL);
+
+ // Get compressed and uncompressed size
+ uLong source_size;
+ uLongf dest_size;
+ // SeekPos.QuadPart = -4; // last 4 bytes define size of uncompressed file
+ // ULARGE_INTEGER Tell;
+ //_pStream->Seek(SeekPos,STREAM_SEEK_END,&Tell);
+ // source_size = (uLong)Tell.QuadPart + 4; // src
+ //_pStream->Read(&dest_size,4,&BytesRead); // dest
+ dest_size = 1024 * 70; // thumbnail is currently always inside the first 65KB...if it moves or
+ // enlargens this line will have to change or go!
+ source_size = (uLong)max(SeekPos.QuadPart, dest_size); // for safety, assume no compression
+
+ // Input
+ Bytef *src = new Bytef[source_size];
+ stream.next_in = (Bytef *)src;
+ stream.avail_in = (uInt)source_size;
+
+ // Output
+ Bytef *dest = new Bytef[dest_size];
+ stream.next_out = (Bytef *)dest;
+ stream.avail_out = dest_size;
+
+ // IStream to src
+ SeekPos.QuadPart = 0;
+ _pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
+ _pStream->Read(src, source_size, &BytesRead);
+
+ // Do the inflation
+ int err;
+ err = inflateInit2(&stream, 16); // 16 means "gzip"...nice!
+ err = inflate(&stream, Z_FINISH);
+ err = inflateEnd(&stream);
+
+ // Replace the IStream, which is read-only
+ _pStream->Release();
+ _pStream = SHCreateMemStream(dest, dest_size);
+
+ delete[] src;
+ delete[] dest;
+ }
+
+ // Blender version, early out if sub 2.5
+ SeekPos.QuadPart = 9;
+ _pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
+ char version[4];
+ version[3] = '\0';
+ _pStream->Read(&version, 3, &BytesRead);
+ if (BytesRead != 3) {
+ return E_UNEXPECTED;
+ }
+ int iVersion = atoi(version);
+ if (iVersion < 250) {
+ return S_FALSE;
+ }
+
+ // 32 or 64 bit blend?
+ SeekPos.QuadPart = 7;
+ _pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
+
+ char _PointerSize;
+ _pStream->Read(&_PointerSize, 1, &BytesRead);
+
+ int PointerSize = _PointerSize == '_' ? 4 : 8;
+ int HeaderSize = 16 + PointerSize;
+
+ // Find and read thumbnail ("TEST") block
+ SeekPos.QuadPart = 12;
+ _pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
+ int BlockOffset = 12;
+ while (_pStream) {
+ // Scan current block
+ char BlockName[5];
+ BlockName[4] = '\0';
+ int BlockSize = 0;
+
+ if (_pStream->Read(BlockName, 4, &BytesRead) == S_OK &&
+ _pStream->Read((void *)&BlockSize, 4, &BytesRead) == S_OK) {
+ if (strcmp(BlockName, "TEST") != 0) {
+ SeekPos.QuadPart = BlockOffset += HeaderSize + BlockSize;
+ _pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
+ continue;
+ }
+ }
+ else {
+ break; // eof
+ }
+
+ // Found the block
+ SeekPos.QuadPart = BlockOffset + HeaderSize;
+ _pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
+
+ int width, height;
+ _pStream->Read((char *)&width, 4, &BytesRead);
+ _pStream->Read((char *)&height, 4, &BytesRead);
+ BlockSize -= 8;
+
+ // Isolate RGBA data
+ char *pRGBA = new char[BlockSize];
+ _pStream->Read(pRGBA, BlockSize, &BytesRead);
+
+ if (BytesRead != (ULONG)BlockSize) {
+ return E_UNEXPECTED;
+ }
+
+ // Convert to BGRA for Windows
+ for (int i = 0; i < BlockSize; i += 4) {
+#define RED_BYTE pRGBA[i]
+#define BLUE_BYTE pRGBA[i + 2]
+
+ char red = RED_BYTE;
+ RED_BYTE = BLUE_BYTE;
+ BLUE_BYTE = red;
+ }
+
+ // Flip vertically (Blender stores it upside-down)
+ unsigned int LineSize = width * 4;
+ char *FlippedImage = new char[BlockSize];
+ for (int i = 0; i < height; i++) {
+ if (0 != memcpy_s(&FlippedImage[(height - i - 1) * LineSize],
+ LineSize,
+ &pRGBA[i * LineSize],
+ LineSize)) {
+ return E_UNEXPECTED;
+ }
+ }
+ delete[] pRGBA;
+ pRGBA = FlippedImage;
+
+ // Create image
+ *phbmp = CreateBitmap(width, height, 1, 32, pRGBA);
+ if (!*phbmp) {
+ return E_FAIL;
+ }
+ *pdwAlpha = WTSAT_ARGB; // it's actually BGRA, not sure why this works
+
+ // Scale down if required
+ if ((unsigned)width > cx || (unsigned)height > cx) {
+ float scale = 1.0f / (max(width, height) / (float)cx);
+ LONG NewWidth = (LONG)(width * scale);
+ LONG NewHeight = (LONG)(height * scale);
+
+#ifdef _DEBUG
+# if 0
+ MessageBox(0, "Attach now", "Debugging", MB_OK);
+# endif
+#endif
+ IWICImagingFactory *pImgFac;
+ hr = CoCreateInstance(
+ CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pImgFac));
+
+ IWICBitmap *WICBmp;
+ hr = pImgFac->CreateBitmapFromHBITMAP(*phbmp, 0, WICBitmapUseAlpha, &WICBmp);
+
+ BITMAPINFO bmi = {};
+ bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
+ bmi.bmiHeader.biWidth = NewWidth;
+ bmi.bmiHeader.biHeight = -NewHeight;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+
+ BYTE *pBits;
+ HBITMAP ResizedHBmp = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void **)&pBits, NULL, 0);
+ hr = ResizedHBmp ? S_OK : E_OUTOFMEMORY;
+ if (SUCCEEDED(hr)) {
+ IWICBitmapScaler *pIScaler;
+ hr = pImgFac->CreateBitmapScaler(&pIScaler);
+ hr = pIScaler->Initialize(WICBmp, NewWidth, NewHeight, WICBitmapInterpolationModeFant);
+
+ WICRect rect = {0, 0, NewWidth, NewHeight};
+ hr = pIScaler->CopyPixels(&rect, NewWidth * 4, NewWidth * NewHeight * 4, pBits);
+
+ if (SUCCEEDED(hr)) {
+ DeleteObject(*phbmp);
+ *phbmp = ResizedHBmp;
+ }
+ else {
+ DeleteObject(ResizedHBmp);
+ }
+
+ pIScaler->Release();
+ }
+ WICBmp->Release();
+ pImgFac->Release();
+ }
+ else {
+ hr = S_OK;
+ }
+ break;
+ }
+ return hr;
+}
diff --git a/source/blender/blendthumb/src/Dll.cpp b/source/blender/blendthumb/src/Dll.cpp
new file mode 100644
index 00000000000..08b3d253be8
--- /dev/null
+++ b/source/blender/blendthumb/src/Dll.cpp
@@ -0,0 +1,280 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <objbase.h>
+#include <shlwapi.h>
+#include <thumbcache.h> // For IThumbnailProvider.
+#include <shlobj.h> // For SHChangeNotify
+#include <new>
+
+extern HRESULT CBlendThumb_CreateInstance(REFIID riid, void **ppv);
+
+#define SZ_CLSID_BLENDTHUMBHANDLER L"{D45F043D-F17F-4e8a-8435-70971D9FA46D}"
+#define SZ_BLENDTHUMBHANDLER L"Blender Thumbnail Handler"
+const CLSID CLSID_BlendThumbHandler = {
+ 0xd45f043d, 0xf17f, 0x4e8a, {0x84, 0x35, 0x70, 0x97, 0x1d, 0x9f, 0xa4, 0x6d}};
+
+typedef HRESULT (*PFNCREATEINSTANCE)(REFIID riid, void **ppvObject);
+struct CLASS_OBJECT_INIT {
+ const CLSID *pClsid;
+ PFNCREATEINSTANCE pfnCreate;
+};
+
+// add classes supported by this module here
+const CLASS_OBJECT_INIT c_rgClassObjectInit[] = {
+ {&CLSID_BlendThumbHandler, CBlendThumb_CreateInstance}};
+
+long g_cRefModule = 0;
+
+// Handle the DLL's module
+HINSTANCE g_hInst = NULL;
+
+// Standard DLL functions
+STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, void *)
+{
+ if (dwReason == DLL_PROCESS_ATTACH) {
+ g_hInst = hInstance;
+ DisableThreadLibraryCalls(hInstance);
+ }
+ return TRUE;
+}
+
+STDAPI DllCanUnloadNow()
+{
+ // Only allow the DLL to be unloaded after all outstanding references have been released
+ return (g_cRefModule == 0) ? S_OK : S_FALSE;
+}
+
+void DllAddRef()
+{
+ InterlockedIncrement(&g_cRefModule);
+}
+
+void DllRelease()
+{
+ InterlockedDecrement(&g_cRefModule);
+}
+
+class CClassFactory : public IClassFactory {
+ public:
+ static HRESULT CreateInstance(REFCLSID clsid,
+ const CLASS_OBJECT_INIT *pClassObjectInits,
+ size_t cClassObjectInits,
+ REFIID riid,
+ void **ppv)
+ {
+ *ppv = NULL;
+ HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
+ for (size_t i = 0; i < cClassObjectInits; i++) {
+ if (clsid == *pClassObjectInits[i].pClsid) {
+ IClassFactory *pClassFactory = new (std::nothrow)
+ CClassFactory(pClassObjectInits[i].pfnCreate);
+ hr = pClassFactory ? S_OK : E_OUTOFMEMORY;
+ if (SUCCEEDED(hr)) {
+ hr = pClassFactory->QueryInterface(riid, ppv);
+ pClassFactory->Release();
+ }
+ break; // match found
+ }
+ }
+ return hr;
+ }
+
+ CClassFactory(PFNCREATEINSTANCE pfnCreate) : _cRef(1), _pfnCreate(pfnCreate)
+ {
+ DllAddRef();
+ }
+
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv)
+ {
+ static const QITAB qit[] = {QITABENT(CClassFactory, IClassFactory), {0}};
+ return QISearch(this, qit, riid, ppv);
+ }
+
+ IFACEMETHODIMP_(ULONG) AddRef()
+ {
+ return InterlockedIncrement(&_cRef);
+ }
+
+ IFACEMETHODIMP_(ULONG) Release()
+ {
+ long cRef = InterlockedDecrement(&_cRef);
+ if (cRef == 0) {
+ delete this;
+ }
+ return cRef;
+ }
+
+ // IClassFactory
+ IFACEMETHODIMP CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
+ {
+ return punkOuter ? CLASS_E_NOAGGREGATION : _pfnCreate(riid, ppv);
+ }
+
+ IFACEMETHODIMP LockServer(BOOL fLock)
+ {
+ if (fLock) {
+ DllAddRef();
+ }
+ else {
+ DllRelease();
+ }
+ return S_OK;
+ }
+
+ private:
+ ~CClassFactory()
+ {
+ DllRelease();
+ }
+
+ long _cRef;
+ PFNCREATEINSTANCE _pfnCreate;
+};
+
+STDAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **ppv)
+{
+ return CClassFactory::CreateInstance(
+ clsid, c_rgClassObjectInit, ARRAYSIZE(c_rgClassObjectInit), riid, ppv);
+}
+
+// A struct to hold the information required for a registry entry
+
+struct REGISTRY_ENTRY {
+ HKEY hkeyRoot;
+ PCWSTR pszKeyName;
+ PCWSTR pszValueName;
+ DWORD dwValueType;
+ PCWSTR pszData;
+};
+
+// Creates a registry key (if needed) and sets the default value of the key
+
+HRESULT CreateRegKeyAndSetValue(const REGISTRY_ENTRY *pRegistryEntry)
+{
+ HKEY hKey;
+ HRESULT hr = HRESULT_FROM_WIN32(RegCreateKeyExW(pRegistryEntry->hkeyRoot,
+ pRegistryEntry->pszKeyName,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_SET_VALUE,
+ NULL,
+ &hKey,
+ NULL));
+ if (SUCCEEDED(hr)) {
+ // All this just to support REG_DWORD...
+ DWORD size;
+ DWORD data;
+ BYTE *lpData = (LPBYTE)pRegistryEntry->pszData;
+ switch (pRegistryEntry->dwValueType) {
+ case REG_SZ:
+ size = ((DWORD)wcslen(pRegistryEntry->pszData) + 1) * sizeof(WCHAR);
+ break;
+ case REG_DWORD:
+ size = sizeof(DWORD);
+ data = (DWORD)pRegistryEntry->pszData;
+ lpData = (BYTE *)&data;
+ break;
+ default:
+ return E_INVALIDARG;
+ }
+
+ hr = HRESULT_FROM_WIN32(RegSetValueExW(
+ hKey, pRegistryEntry->pszValueName, 0, pRegistryEntry->dwValueType, lpData, size));
+ RegCloseKey(hKey);
+ }
+ return hr;
+}
+
+//
+// Registers this COM server
+//
+STDAPI DllRegisterServer()
+{
+ HRESULT hr;
+
+ WCHAR szModuleName[MAX_PATH];
+
+ if (!GetModuleFileNameW(g_hInst, szModuleName, ARRAYSIZE(szModuleName))) {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ else {
+ const REGISTRY_ENTRY rgRegistryEntries[] = {
+ // RootKey KeyName ValueName ValueType Data
+ {HKEY_CURRENT_USER,
+ L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER,
+ NULL,
+ REG_SZ,
+ SZ_BLENDTHUMBHANDLER},
+ {HKEY_CURRENT_USER,
+ L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER L"\\InProcServer32",
+ NULL,
+ REG_SZ,
+ szModuleName},
+ {HKEY_CURRENT_USER,
+ L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER L"\\InProcServer32",
+ L"ThreadingModel",
+ REG_SZ,
+ L"Apartment"},
+ {HKEY_CURRENT_USER,
+ L"Software\\Classes\\.blend\\",
+ L"Treatment",
+ REG_DWORD,
+ 0}, // doesn't appear to do anything...
+ {HKEY_CURRENT_USER,
+ L"Software\\Classes\\.blend\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}",
+ NULL,
+ REG_SZ,
+ SZ_CLSID_BLENDTHUMBHANDLER},
+ };
+
+ hr = S_OK;
+ for (int i = 0; i < ARRAYSIZE(rgRegistryEntries) && SUCCEEDED(hr); i++) {
+ hr = CreateRegKeyAndSetValue(&rgRegistryEntries[i]);
+ }
+ }
+ if (SUCCEEDED(hr)) {
+ // This tells the shell to invalidate the thumbnail cache. This is important because any
+ // .blend files viewed before registering this handler would otherwise show cached blank
+ // thumbnails.
+ SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
+ }
+ return hr;
+}
+
+//
+// Unregisters this COM server
+//
+STDAPI DllUnregisterServer()
+{
+ HRESULT hr = S_OK;
+
+ const PCWSTR rgpszKeys[] = {
+ L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER,
+ L"Software\\Classes\\.blend\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}"};
+
+ // Delete the registry entries
+ for (int i = 0; i < ARRAYSIZE(rgpszKeys) && SUCCEEDED(hr); i++) {
+ hr = HRESULT_FROM_WIN32(RegDeleteTreeW(HKEY_CURRENT_USER, rgpszKeys[i]));
+ if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) {
+ // If the registry entry has already been deleted, say S_OK.
+ hr = S_OK;
+ }
+ }
+ return hr;
+}
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index 793e9805899..8e1ff77b1c7 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -608,7 +608,7 @@ void BLF_draw_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_in
BLF_RESULT_CHECK_INIT(r_info);
- if (font && font->glyph_cache) {
+ if (font) {
blf_draw_gl__start(font);
if (font->flags & BLF_WORD_WRAP) {
blf_font_draw__wrap(font, str, len, r_info);
@@ -634,7 +634,7 @@ void BLF_draw_ascii_ex(int fontid, const char *str, size_t len, struct ResultBLF
BLF_RESULT_CHECK_INIT(r_info);
- if (font && font->glyph_cache) {
+ if (font) {
blf_draw_gl__start(font);
if (font->flags & BLF_WORD_WRAP) {
/* use non-ascii draw function for word-wrap */
@@ -646,6 +646,7 @@ void BLF_draw_ascii_ex(int fontid, const char *str, size_t len, struct ResultBLF
blf_draw_gl__end(font);
}
}
+
void BLF_draw_ascii(int fontid, const char *str, size_t len)
{
if (len == 0 || str[0] == '\0') {
@@ -664,7 +665,7 @@ int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth)
FontBLF *font = blf_get(fontid);
int columns = 0;
- if (font && font->glyph_cache) {
+ if (font) {
blf_draw_gl__start(font);
columns = blf_font_draw_mono(font, str, len, cwidth);
blf_draw_gl__end(font);
@@ -729,6 +730,7 @@ void BLF_boundbox_ex(
}
}
}
+
void BLF_boundbox(int fontid, const char *str, size_t len, rctf *r_box)
{
BLF_boundbox_ex(fontid, str, len, r_box, NULL);
@@ -738,7 +740,7 @@ void BLF_width_and_height(int fontid, const char *str, size_t len, float *r_widt
{
FontBLF *font = blf_get(fontid);
- if (font && font->glyph_cache) {
+ if (font) {
blf_font_width_and_height(font, str, len, r_width, r_height, NULL);
}
else {
@@ -752,12 +754,13 @@ float BLF_width_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_
BLF_RESULT_CHECK_INIT(r_info);
- if (font && font->glyph_cache) {
+ if (font) {
return blf_font_width(font, str, len, r_info);
}
return 0.0f;
}
+
float BLF_width(int fontid, const char *str, size_t len)
{
return BLF_width_ex(fontid, str, len, NULL);
@@ -767,7 +770,7 @@ float BLF_fixed_width(int fontid)
{
FontBLF *font = blf_get(fontid);
- if (font && font->glyph_cache) {
+ if (font) {
return blf_font_fixed_width(font);
}
@@ -780,12 +783,13 @@ float BLF_height_ex(int fontid, const char *str, size_t len, struct ResultBLF *r
BLF_RESULT_CHECK_INIT(r_info);
- if (font && font->glyph_cache) {
+ if (font) {
return blf_font_height(font, str, len, r_info);
}
return 0.0f;
}
+
float BLF_height(int fontid, const char *str, size_t len)
{
return BLF_height_ex(fontid, str, len, NULL);
@@ -795,8 +799,8 @@ int BLF_height_max(int fontid)
{
FontBLF *font = blf_get(fontid);
- if (font && font->glyph_cache) {
- return font->glyph_cache->glyph_height_max;
+ if (font) {
+ return blf_font_height_max(font);
}
return 0;
@@ -806,8 +810,8 @@ float BLF_width_max(int fontid)
{
FontBLF *font = blf_get(fontid);
- if (font && font->glyph_cache) {
- return font->glyph_cache->glyph_width_max;
+ if (font) {
+ return blf_font_width_max(font);
}
return 0.0f;
@@ -817,8 +821,8 @@ float BLF_descender(int fontid)
{
FontBLF *font = blf_get(fontid);
- if (font && font->glyph_cache) {
- return font->glyph_cache->descender;
+ if (font) {
+ return blf_font_descender(font);
}
return 0.0f;
@@ -828,8 +832,8 @@ float BLF_ascender(int fontid)
{
FontBLF *font = blf_get(fontid);
- if (font && font->glyph_cache) {
- return font->glyph_cache->ascender;
+ if (font) {
+ return blf_font_ascender(font);
}
return 0.0f;
@@ -939,7 +943,7 @@ void BLF_draw_buffer_ex(int fontid, const char *str, size_t len, struct ResultBL
{
FontBLF *font = blf_get(fontid);
- if (font && font->glyph_cache && (font->buf_info.fbuf || font->buf_info.cbuf)) {
+ if (font && (font->buf_info.fbuf || font->buf_info.cbuf)) {
blf_draw_buffer__start(font);
if (font->flags & BLF_WORD_WRAP) {
blf_font_draw_buffer__wrap(font, str, len, r_info);
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index 6748a5324ac..e0dfa6a2223 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -50,7 +50,6 @@
#include "UI_interface.h"
-#include "GPU_immediate.h"
#include "GPU_matrix.h"
#include "GPU_batch.h"
@@ -69,6 +68,7 @@ BatchBLF g_batch;
/* freetype2 handle ONLY for this file!. */
static FT_Library ft_lib;
static SpinLock ft_lib_mutex;
+static SpinLock blf_glyph_cache_mutex;
/* -------------------------------------------------------------------- */
/** \name Glyph Batching
@@ -217,6 +217,7 @@ int blf_font_init(void)
{
memset(&g_batch, 0, sizeof(g_batch));
BLI_spin_init(&ft_lib_mutex);
+ BLI_spin_init(&blf_glyph_cache_mutex);
return FT_Init_FreeType(&ft_lib);
}
@@ -224,6 +225,7 @@ void blf_font_exit(void)
{
FT_Done_FreeType(ft_lib);
BLI_spin_end(&ft_lib_mutex);
+ BLI_spin_end(&blf_glyph_cache_mutex);
blf_batch_draw_exit();
}
@@ -232,11 +234,14 @@ void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi)
GlyphCacheBLF *gc;
FT_Error err;
+ blf_glyph_cache_acquire(font);
+
gc = blf_glyph_cache_find(font, size, dpi);
if (gc) {
font->glyph_cache = gc;
/* Optimization: do not call FT_Set_Char_Size if size did not change. */
if (font->size == size && font->dpi == dpi) {
+ blf_glyph_cache_release(font);
return;
}
}
@@ -245,6 +250,8 @@ void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi)
if (err) {
/* FIXME: here we can go through the fixed size and choice a close one */
printf("The current font don't support the size, %u and dpi, %u\n", size, dpi);
+
+ blf_glyph_cache_release(font);
return;
}
@@ -260,28 +267,35 @@ void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi)
font->glyph_cache = NULL;
}
}
+ blf_glyph_cache_release(font);
}
-static void blf_font_ensure_ascii_table(FontBLF *font)
+static GlyphBLF **blf_font_ensure_ascii_table(FontBLF *font, GlyphCacheBLF *gc)
{
- GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
+ GlyphBLF **glyph_ascii_table;
+
+ glyph_ascii_table = gc->glyph_ascii_table;
/* build ascii on demand */
if (glyph_ascii_table['0'] == NULL) {
GlyphBLF *g;
unsigned int i;
for (i = 0; i < 256; i++) {
- g = blf_glyph_search(font->glyph_cache, i);
+ g = blf_glyph_search(gc, i);
if (!g) {
FT_UInt glyph_index = FT_Get_Char_Index(font->face, i);
- g = blf_glyph_add(font, glyph_index, i);
+ g = blf_glyph_add(font, gc, glyph_index, i);
}
glyph_ascii_table[i] = g;
}
}
+
+ return glyph_ascii_table;
}
-static void blf_font_ensure_ascii_kerning(FontBLF *font, const FT_UInt kern_mode)
+static void blf_font_ensure_ascii_kerning(FontBLF *font,
+ GlyphCacheBLF *gc,
+ const FT_UInt kern_mode)
{
KerningCacheBLF *kc = font->kerning_cache;
@@ -290,7 +304,7 @@ static void blf_font_ensure_ascii_kerning(FontBLF *font, const FT_UInt kern_mode
if (!kc || kc->mode != kern_mode) {
font->kerning_cache = kc = blf_kerning_cache_find(font);
if (!kc) {
- font->kerning_cache = kc = blf_kerning_cache_new(font);
+ font->kerning_cache = kc = blf_kerning_cache_new(font, gc);
}
}
}
@@ -301,18 +315,21 @@ static void blf_font_ensure_ascii_kerning(FontBLF *font, const FT_UInt kern_mode
*/
/* Note,
- * blf_font_ensure_ascii_table(font); must be called before this macro */
+ * blf_font_ensure_ascii_table(font, gc); must be called before this macro */
-#define BLF_UTF8_NEXT_FAST(_font, _g, _str, _i, _c, _glyph_ascii_table) \
+#define BLF_UTF8_NEXT_FAST(_font, _gc, _g, _str, _i, _c, _glyph_ascii_table) \
if (((_c) = (_str)[_i]) < 0x80) { \
_g = (_glyph_ascii_table)[_c]; \
_i++; \
} \
else if ((_c = BLI_str_utf8_as_unicode_step(_str, &(_i))) != BLI_UTF8_ERR) { \
- if ((_g = blf_glyph_search((_font)->glyph_cache, _c)) == NULL) { \
- _g = blf_glyph_add(_font, FT_Get_Char_Index((_font)->face, _c), _c); \
+ if ((_g = blf_glyph_search(_gc, _c)) == NULL) { \
+ _g = blf_glyph_add(_font, _gc, FT_Get_Char_Index((_font)->face, _c), _c); \
} \
} \
+ else { \
+ _g = NULL; \
+ } \
(void)0
#define BLF_KERNING_VARS(_font, _has_kerning, _kern_mode) \
@@ -323,7 +340,7 @@ static void blf_font_ensure_ascii_kerning(FontBLF *font, const FT_UInt kern_mode
(FT_UInt)FT_KERNING_UNFITTED)
/* Note,
- * blf_font_ensure_ascii_kerning(font, kern_mode); must be called before this macro */
+ * blf_font_ensure_ascii_kerning(font, gc, kern_mode); must be called before this macro */
#define BLF_KERNING_STEP_FAST(_font, _kern_mode, _g_prev, _g, _c_prev, _c, _pen_x) \
{ \
@@ -351,29 +368,33 @@ static void blf_font_ensure_ascii_kerning(FontBLF *font, const FT_UInt kern_mode
} \
(void)0
-static void blf_font_draw_ex(
- FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info, int pen_y)
+static void blf_font_draw_ex(FontBLF *font,
+ GlyphCacheBLF *gc,
+ const char *str,
+ size_t len,
+ struct ResultBLF *r_info,
+ int pen_y)
{
unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
int pen_x = 0;
size_t i = 0;
- GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
if (len == 0) {
/* early output, don't do any IMM OpenGL. */
return;
}
+ GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
+
BLF_KERNING_VARS(font, has_kerning, kern_mode);
- blf_font_ensure_ascii_table(font);
- blf_font_ensure_ascii_kerning(font, kern_mode);
+ blf_font_ensure_ascii_kerning(font, gc, kern_mode);
blf_batch_draw_begin(font);
while ((i < len) && str[i]) {
- BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
+ BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
if (UNLIKELY(c == BLI_UTF8_ERR)) {
break;
@@ -386,7 +407,7 @@ static void blf_font_draw_ex(
}
/* do not return this loop if clipped, we want every character tested */
- blf_glyph_render(font, g, (float)pen_x, (float)pen_y);
+ blf_glyph_render(font, gc, g, (float)pen_x, (float)pen_y);
pen_x += g->advance_i;
g_prev = g;
@@ -402,7 +423,9 @@ static void blf_font_draw_ex(
}
void blf_font_draw(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info)
{
- blf_font_draw_ex(font, str, len, r_info, 0);
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ blf_font_draw_ex(font, gc, str, len, r_info, 0);
+ blf_glyph_cache_release(font);
}
/* faster version of blf_font_draw, ascii only for view dimensions */
@@ -412,12 +435,13 @@ static void blf_font_draw_ascii_ex(
unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
int pen_x = 0;
- GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
+
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
BLF_KERNING_VARS(font, has_kerning, kern_mode);
- blf_font_ensure_ascii_table(font);
- blf_font_ensure_ascii_kerning(font, kern_mode);
+ blf_font_ensure_ascii_kerning(font, gc, kern_mode);
blf_batch_draw_begin(font);
@@ -431,7 +455,7 @@ static void blf_font_draw_ascii_ex(
}
/* do not return this loop if clipped, we want every character tested */
- blf_glyph_render(font, g, (float)pen_x, (float)pen_y);
+ blf_glyph_render(font, gc, g, (float)pen_x, (float)pen_y);
pen_x += g->advance_i;
g_prev = g;
@@ -444,7 +468,10 @@ static void blf_font_draw_ascii_ex(
r_info->lines = 1;
r_info->width = pen_x;
}
+
+ blf_glyph_cache_release(font);
}
+
void blf_font_draw_ascii(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info)
{
blf_font_draw_ascii_ex(font, str, len, r_info, 0);
@@ -458,14 +485,14 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth)
int col, columns = 0;
int pen_x = 0, pen_y = 0;
size_t i = 0;
- GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
- blf_font_ensure_ascii_table(font);
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
blf_batch_draw_begin(font);
while ((i < len) && str[i]) {
- BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
+ BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
if (UNLIKELY(c == BLI_UTF8_ERR)) {
break;
@@ -475,7 +502,7 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth)
}
/* do not return this loop if clipped, we want every character tested */
- blf_glyph_render(font, g, (float)pen_x, (float)pen_y);
+ blf_glyph_render(font, gc, g, (float)pen_x, (float)pen_y);
col = BLI_wcwidth((wchar_t)c);
if (col < 0) {
@@ -488,19 +515,25 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth)
blf_batch_draw_end();
+ blf_glyph_cache_release(font);
return columns;
}
/* Sanity checks are done by BLF_draw_buffer() */
-static void blf_font_draw_buffer_ex(
- FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info, int pen_y)
+static void blf_font_draw_buffer_ex(FontBLF *font,
+ GlyphCacheBLF *gc,
+ const char *str,
+ size_t len,
+ struct ResultBLF *r_info,
+ int pen_y)
{
unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
int pen_x = (int)font->pos[0];
int pen_y_basis = (int)font->pos[1] + pen_y;
size_t i = 0;
- GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
+
+ GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
/* buffer specific vars */
FontBufInfoBLF *buf_info = &font->buf_info;
@@ -511,13 +544,12 @@ static void blf_font_draw_buffer_ex(
BLF_KERNING_VARS(font, has_kerning, kern_mode);
- blf_font_ensure_ascii_table(font);
- blf_font_ensure_ascii_kerning(font, kern_mode);
+ blf_font_ensure_ascii_kerning(font, gc, kern_mode);
/* another buffer specific call for color conversion */
while ((i < len) && str[i]) {
- BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
+ BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
if (UNLIKELY(c == BLI_UTF8_ERR)) {
break;
@@ -645,9 +677,12 @@ static void blf_font_draw_buffer_ex(
r_info->width = pen_x;
}
}
+
void blf_font_draw_buffer(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info)
{
- blf_font_draw_buffer_ex(font, str, len, r_info, 0);
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ blf_font_draw_buffer_ex(font, gc, str, len, r_info, 0);
+ blf_glyph_cache_release(font);
}
static bool blf_font_width_to_strlen_glyph_process(FontBLF *font,
@@ -678,23 +713,24 @@ static bool blf_font_width_to_strlen_glyph_process(FontBLF *font,
size_t blf_font_width_to_strlen(
FontBLF *font, const char *str, size_t len, float width, float *r_width)
{
- unsigned int c, c_prev;
+ unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev;
int pen_x, width_new;
size_t i, i_prev;
- GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
+
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
const int width_i = (int)width;
BLF_KERNING_VARS(font, has_kerning, kern_mode);
- blf_font_ensure_ascii_table(font);
if (has_kerning) {
- blf_font_ensure_ascii_kerning(font, kern_mode);
+ blf_font_ensure_ascii_kerning(font, gc, kern_mode);
}
for (i_prev = i = 0, width_new = pen_x = 0, g_prev = NULL, c_prev = 0; (i < len) && str[i];
i_prev = i, width_new = pen_x, c_prev = c, g_prev = g) {
- BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
+ BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
if (blf_font_width_to_strlen_glyph_process(
font, has_kerning, kern_mode, c_prev, c, g_prev, g, &pen_x, width_i)) {
@@ -706,25 +742,27 @@ size_t blf_font_width_to_strlen(
*r_width = (float)width_new;
}
+ blf_glyph_cache_release(font);
return i_prev;
}
size_t blf_font_width_to_rstrlen(
FontBLF *font, const char *str, size_t len, float width, float *r_width)
{
- unsigned int c, c_prev;
+ unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev;
int pen_x, width_new;
size_t i, i_prev, i_tmp;
char *s, *s_prev;
- GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
+
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
const int width_i = (int)width;
BLF_KERNING_VARS(font, has_kerning, kern_mode);
- blf_font_ensure_ascii_table(font);
if (has_kerning) {
- blf_font_ensure_ascii_kerning(font, kern_mode);
+ blf_font_ensure_ascii_kerning(font, gc, kern_mode);
}
i = BLI_strnlen(str, len);
@@ -734,7 +772,7 @@ size_t blf_font_width_to_rstrlen(
i_prev = (size_t)((s_prev != NULL) ? s_prev - str : 0);
i_tmp = i;
- BLF_UTF8_NEXT_FAST(font, g, str, i_tmp, c, glyph_ascii_table);
+ BLF_UTF8_NEXT_FAST(font, gc, g, str, i_tmp, c, glyph_ascii_table);
for (width_new = pen_x = 0; (s != NULL);
i = i_prev, s = s_prev, c = c_prev, g = g_prev, g_prev = NULL, width_new = pen_x) {
s_prev = BLI_str_find_prev_char_utf8(str, s);
@@ -742,7 +780,7 @@ size_t blf_font_width_to_rstrlen(
if (s_prev != NULL) {
i_tmp = i_prev;
- BLF_UTF8_NEXT_FAST(font, g_prev, str, i_tmp, c_prev, glyph_ascii_table);
+ BLF_UTF8_NEXT_FAST(font, gc, g_prev, str, i_tmp, c_prev, glyph_ascii_table);
BLI_assert(i_tmp == i);
}
@@ -756,17 +794,24 @@ size_t blf_font_width_to_rstrlen(
*r_width = (float)width_new;
}
+ blf_glyph_cache_release(font);
return i;
}
-static void blf_font_boundbox_ex(
- FontBLF *font, const char *str, size_t len, rctf *box, struct ResultBLF *r_info, int pen_y)
+static void blf_font_boundbox_ex(FontBLF *font,
+ GlyphCacheBLF *gc,
+ const char *str,
+ size_t len,
+ rctf *box,
+ struct ResultBLF *r_info,
+ int pen_y)
{
unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
int pen_x = 0;
size_t i = 0;
- GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
+
+ GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
rctf gbox;
@@ -777,11 +822,10 @@ static void blf_font_boundbox_ex(
box->ymin = 32000.0f;
box->ymax = -32000.0f;
- blf_font_ensure_ascii_table(font);
- blf_font_ensure_ascii_kerning(font, kern_mode);
+ blf_font_ensure_ascii_kerning(font, gc, kern_mode);
while ((i < len) && str[i]) {
- BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
+ BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
if (UNLIKELY(c == BLI_UTF8_ERR)) {
break;
@@ -832,7 +876,9 @@ static void blf_font_boundbox_ex(
void blf_font_boundbox(
FontBLF *font, const char *str, size_t len, rctf *r_box, struct ResultBLF *r_info)
{
- blf_font_boundbox_ex(font, str, len, r_box, r_info, 0);
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ blf_font_boundbox_ex(font, gc, str, len, r_box, r_info, 0);
+ blf_glyph_cache_release(font);
}
/* -------------------------------------------------------------------- */
@@ -848,23 +894,29 @@ void blf_font_boundbox(
* \note If we want rich text - we better have a higher level API to handle that
* (color, bold, switching fonts... etc).
*/
-static void blf_font_wrap_apply(
- FontBLF *font,
- const char *str,
- size_t len,
- struct ResultBLF *r_info,
- void (*callback)(FontBLF *font, const char *str, size_t len, int pen_y, void *userdata),
- void *userdata)
+static void blf_font_wrap_apply(FontBLF *font,
+ const char *str,
+ size_t len,
+ struct ResultBLF *r_info,
+ void (*callback)(FontBLF *font,
+ GlyphCacheBLF *gc,
+ const char *str,
+ size_t len,
+ int pen_y,
+ void *userdata),
+ void *userdata)
{
unsigned int c;
GlyphBLF *g, *g_prev = NULL;
FT_Vector delta;
int pen_x = 0, pen_y = 0;
size_t i = 0;
- GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
int lines = 0;
int pen_x_next = 0;
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
+
BLF_KERNING_VARS(font, has_kerning, kern_mode);
struct WordWrapVars {
@@ -872,7 +924,6 @@ static void blf_font_wrap_apply(
size_t start, last[2];
} wrap = {font->wrap_width != -1 ? font->wrap_width : INT_MAX, 0, {0, 0}};
- blf_font_ensure_ascii_table(font);
// printf("%s wrapping (%d, %d) `%s`:\n", __func__, len, strlen(str), str);
while ((i < len) && str[i]) {
@@ -880,7 +931,7 @@ static void blf_font_wrap_apply(
size_t i_curr = i;
bool do_draw = false;
- BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
+ BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
if (UNLIKELY(c == BLI_UTF8_ERR)) {
break;
@@ -924,11 +975,11 @@ static void blf_font_wrap_apply(
// printf("(%03d..%03d) `%.*s`\n",
// wrap.start, wrap.last[0], (wrap.last[0] - wrap.start) - 1, &str[wrap.start]);
- callback(font, &str[wrap.start], (wrap.last[0] - wrap.start) - 1, pen_y, userdata);
+ callback(font, gc, &str[wrap.start], (wrap.last[0] - wrap.start) - 1, pen_y, userdata);
wrap.start = wrap.last[0];
i = wrap.last[1];
pen_x = 0;
- pen_y -= font->glyph_cache->glyph_height_max;
+ pen_y -= gc->glyph_height_max;
g_prev = NULL;
lines += 1;
continue;
@@ -945,13 +996,19 @@ static void blf_font_wrap_apply(
/* width of last line only (with wrapped lines) */
r_info->width = pen_x_next;
}
+
+ blf_glyph_cache_release(font);
}
/* blf_font_draw__wrap */
-static void blf_font_draw__wrap_cb(
- FontBLF *font, const char *str, size_t len, int pen_y, void *UNUSED(userdata))
+static void blf_font_draw__wrap_cb(FontBLF *font,
+ GlyphCacheBLF *gc,
+ const char *str,
+ size_t len,
+ int pen_y,
+ void *UNUSED(userdata))
{
- blf_font_draw_ex(font, str, len, NULL, pen_y);
+ blf_font_draw_ex(font, gc, str, len, NULL, pen_y);
}
void blf_font_draw__wrap(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info)
{
@@ -960,12 +1017,12 @@ void blf_font_draw__wrap(FontBLF *font, const char *str, size_t len, struct Resu
/* blf_font_boundbox__wrap */
static void blf_font_boundbox_wrap_cb(
- FontBLF *font, const char *str, size_t len, int pen_y, void *userdata)
+ FontBLF *font, GlyphCacheBLF *gc, const char *str, size_t len, int pen_y, void *userdata)
{
rctf *box = userdata;
rctf box_single;
- blf_font_boundbox_ex(font, str, len, &box_single, NULL, pen_y);
+ blf_font_boundbox_ex(font, gc, str, len, &box_single, NULL, pen_y);
BLI_rctf_union(box, &box_single);
}
void blf_font_boundbox__wrap(
@@ -980,10 +1037,14 @@ void blf_font_boundbox__wrap(
}
/* blf_font_draw_buffer__wrap */
-static void blf_font_draw_buffer__wrap_cb(
- FontBLF *font, const char *str, size_t len, int pen_y, void *UNUSED(userdata))
+static void blf_font_draw_buffer__wrap_cb(FontBLF *font,
+ GlyphCacheBLF *gc,
+ const char *str,
+ size_t len,
+ int pen_y,
+ void *UNUSED(userdata))
{
- blf_font_draw_buffer_ex(font, str, len, NULL, pen_y);
+ blf_font_draw_buffer_ex(font, gc, str, len, NULL, pen_y);
}
void blf_font_draw_buffer__wrap(FontBLF *font,
const char *str,
@@ -1069,16 +1130,22 @@ float blf_font_height(FontBLF *font, const char *str, size_t len, struct ResultB
float blf_font_fixed_width(FontBLF *font)
{
const unsigned int c = ' ';
- GlyphBLF *g = blf_glyph_search(font->glyph_cache, c);
+
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ blf_font_ensure_ascii_table(font, gc);
+
+ GlyphBLF *g = blf_glyph_search(gc, c);
if (!g) {
- g = blf_glyph_add(font, FT_Get_Char_Index(font->face, c), c);
+ g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, c), c);
/* if we don't find the glyph. */
if (!g) {
+ blf_glyph_cache_release(font);
return 0.0f;
}
}
+ blf_glyph_cache_release(font);
return g->advance;
}
@@ -1109,6 +1176,7 @@ int blf_font_count_missing_chars(FontBLF *font,
void blf_font_free(FontBLF *font)
{
+ BLI_spin_lock(&blf_glyph_cache_mutex);
GlyphCacheBLF *gc;
font->glyph_cache = NULL;
@@ -1126,6 +1194,8 @@ void blf_font_free(FontBLF *font)
MEM_freeN(font->name);
}
MEM_freeN(font);
+
+ BLI_spin_unlock(&blf_glyph_cache_mutex);
}
static void blf_font_fill(FontBLF *font)
@@ -1175,6 +1245,7 @@ static void blf_font_fill(FontBLF *font)
font->ft_lib = ft_lib;
font->ft_lib_mutex = &ft_lib_mutex;
+ font->glyph_cache_mutex = &blf_glyph_cache_mutex;
}
FontBLF *blf_font_new(const char *name, const char *filename)
@@ -1248,3 +1319,51 @@ FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int m
blf_font_fill(font);
return font;
}
+
+int blf_font_height_max(FontBLF *font)
+{
+ int height_max;
+
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ blf_font_ensure_ascii_table(font, gc);
+ height_max = gc->glyph_height_max;
+
+ blf_glyph_cache_release(font);
+ return height_max;
+}
+
+int blf_font_width_max(FontBLF *font)
+{
+ int width_max;
+
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ blf_font_ensure_ascii_table(font, gc);
+ width_max = gc->glyph_width_max;
+
+ blf_glyph_cache_release(font);
+ return width_max;
+}
+
+float blf_font_descender(FontBLF *font)
+{
+ float descender;
+
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ blf_font_ensure_ascii_table(font, gc);
+ descender = gc->descender;
+
+ blf_glyph_cache_release(font);
+ return descender;
+}
+
+float blf_font_ascender(FontBLF *font)
+{
+ float ascender;
+
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ blf_font_ensure_ascii_table(font, gc);
+ ascender = gc->ascender;
+
+ blf_glyph_cache_release(font);
+ return ascender;
+}
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index c0a53cbf282..535366b78fa 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -72,7 +72,7 @@ KerningCacheBLF *blf_kerning_cache_find(FontBLF *font)
}
/* Create a new glyph cache for the current kerning mode. */
-KerningCacheBLF *blf_kerning_cache_new(FontBLF *font)
+KerningCacheBLF *blf_kerning_cache_new(FontBLF *font, GlyphCacheBLF *gc)
{
KerningCacheBLF *kc;
@@ -84,13 +84,13 @@ KerningCacheBLF *blf_kerning_cache_new(FontBLF *font)
unsigned int i, j;
for (i = 0; i < 0x80; i++) {
for (j = 0; j < 0x80; j++) {
- GlyphBLF *g = blf_glyph_search(font->glyph_cache, i);
+ GlyphBLF *g = blf_glyph_search(gc, i);
if (!g) {
FT_UInt glyph_index = FT_Get_Char_Index(font->face, i);
- g = blf_glyph_add(font, glyph_index, i);
+ g = blf_glyph_add(font, gc, glyph_index, i);
}
/* Can fail on certain fonts */
- GlyphBLF *g_prev = blf_glyph_search(font->glyph_cache, j);
+ GlyphBLF *g_prev = blf_glyph_search(gc, j);
FT_Vector delta = {
.x = 0,
@@ -180,14 +180,43 @@ GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
return gc;
}
+GlyphCacheBLF *blf_glyph_cache_acquire(FontBLF *font)
+{
+ BLI_spin_lock(font->glyph_cache_mutex);
+
+ GlyphCacheBLF *gc;
+
+ if (!font->glyph_cache) {
+ gc = blf_glyph_cache_new(font);
+ if (gc) {
+ font->glyph_cache = gc;
+ }
+ else {
+ font->glyph_cache = NULL;
+ return NULL;
+ }
+ }
+
+ return font->glyph_cache;
+}
+
+void blf_glyph_cache_release(FontBLF *font)
+{
+ BLI_spin_unlock(font->glyph_cache_mutex);
+}
+
void blf_glyph_cache_clear(FontBLF *font)
{
GlyphCacheBLF *gc;
+ BLI_spin_lock(font->glyph_cache_mutex);
+
while ((gc = BLI_pophead(&font->cache))) {
blf_glyph_cache_free(gc);
}
font->glyph_cache = NULL;
+
+ BLI_spin_unlock(font->glyph_cache_mutex);
}
void blf_glyph_cache_free(GlyphCacheBLF *gc)
@@ -264,7 +293,7 @@ GlyphBLF *blf_glyph_search(GlyphCacheBLF *gc, unsigned int c)
return NULL;
}
-GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
+GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, unsigned int c)
{
FT_GlyphSlot slot;
GlyphBLF *g;
@@ -273,7 +302,7 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
FT_BBox bbox;
unsigned int key;
- g = blf_glyph_search(font->glyph_cache, c);
+ g = blf_glyph_search(gc, c);
if (g) {
return g;
}
@@ -285,7 +314,7 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
BLI_spin_lock(font->ft_lib_mutex);
/* search again after locking */
- g = blf_glyph_search(font->glyph_cache, c);
+ g = blf_glyph_search(gc, c);
if (g) {
BLI_spin_unlock(font->ft_lib_mutex);
return g;
@@ -380,7 +409,7 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
g->box.ymax = ((float)bbox.yMax) / 64.0f;
key = blf_hash(g->c);
- BLI_addhead(&(font->glyph_cache->bucket[key]), g);
+ BLI_addhead(&(gc->bucket[key]), g);
BLI_spin_unlock(font->ft_lib_mutex);
@@ -483,15 +512,13 @@ static void blf_glyph_calc_rect_shadow(rctf *rect, GlyphBLF *g, float x, float y
blf_glyph_calc_rect(rect, g, x + (float)font->shadow_x, y + (float)font->shadow_y);
}
-void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
+void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, float y)
{
if ((!g->width) || (!g->height)) {
return;
}
if (g->build_tex == 0) {
- GlyphCacheBLF *gc = font->glyph_cache;
-
if (font->tex_size_max == -1) {
font->tex_size_max = GPU_max_texture_size();
}
@@ -578,8 +605,8 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
}
else if (font->shadow <= 4) {
blf_texture3_draw(font->shadow_color,
- font->glyph_cache->p2_width,
- font->glyph_cache->p2_height,
+ gc->p2_width,
+ gc->p2_height,
g->uv,
rect_ofs.xmin,
rect_ofs.ymin,
@@ -588,8 +615,8 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
}
else {
blf_texture5_draw(font->shadow_color,
- font->glyph_cache->p2_width,
- font->glyph_cache->p2_height,
+ gc->p2_width,
+ gc->p2_height,
g->uv,
rect_ofs.xmin,
rect_ofs.ymin,
@@ -605,8 +632,8 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
switch (font->blur) {
case 3:
blf_texture3_draw(font->color,
- font->glyph_cache->p2_width,
- font->glyph_cache->p2_height,
+ gc->p2_width,
+ gc->p2_height,
g->uv,
rect.xmin,
rect.ymin,
@@ -615,8 +642,8 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
break;
case 5:
blf_texture5_draw(font->color,
- font->glyph_cache->p2_width,
- font->glyph_cache->p2_height,
+ gc->p2_width,
+ gc->p2_height,
g->uv,
rect.xmin,
rect.ymin,
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index cfc1d245a11..efcf9e15100 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -93,6 +93,10 @@ void blf_font_width_and_height(struct FontBLF *font,
float blf_font_width(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info);
float blf_font_height(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info);
float blf_font_fixed_width(struct FontBLF *font);
+int blf_font_height_max(struct FontBLF *font);
+int blf_font_width_max(struct FontBLF *font);
+float blf_font_descender(struct FontBLF *font);
+float blf_font_ascender(struct FontBLF *font);
int blf_font_count_missing_chars(struct FontBLF *font,
const char *str,
@@ -102,21 +106,27 @@ int blf_font_count_missing_chars(struct FontBLF *font,
void blf_font_free(struct FontBLF *font);
struct KerningCacheBLF *blf_kerning_cache_find(struct FontBLF *font);
-struct KerningCacheBLF *blf_kerning_cache_new(struct FontBLF *font);
+struct KerningCacheBLF *blf_kerning_cache_new(struct FontBLF *font, struct GlyphCacheBLF *gc);
void blf_kerning_cache_clear(struct FontBLF *font);
struct GlyphCacheBLF *blf_glyph_cache_find(struct FontBLF *font,
unsigned int size,
unsigned int dpi);
struct GlyphCacheBLF *blf_glyph_cache_new(struct FontBLF *font);
+struct GlyphCacheBLF *blf_glyph_cache_acquire(struct FontBLF *font);
+void blf_glyph_cache_release(struct FontBLF *font);
void blf_glyph_cache_clear(struct FontBLF *font);
void blf_glyph_cache_free(struct GlyphCacheBLF *gc);
struct GlyphBLF *blf_glyph_search(struct GlyphCacheBLF *gc, unsigned int c);
-struct GlyphBLF *blf_glyph_add(struct FontBLF *font, unsigned int index, unsigned int c);
+struct GlyphBLF *blf_glyph_add(struct FontBLF *font,
+ struct GlyphCacheBLF *gc,
+ unsigned int index,
+ unsigned int c);
void blf_glyph_free(struct GlyphBLF *g);
-void blf_glyph_render(struct FontBLF *font, struct GlyphBLF *g, float x, float y);
+void blf_glyph_render(
+ struct FontBLF *font, struct GlyphCacheBLF *gc, struct GlyphBLF *g, float x, float y);
#ifdef WIN32
/* blf_font_win32_compat.c */
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index 22950c26b6b..0294a6219b9 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -249,7 +249,9 @@ typedef struct FontBLF {
/* list of glyph cache for this font. */
ListBase cache;
- /* current glyph cache, size and dpi. */
+ /* current glyph cache, size and dpi.
+ * Use blf_glyph_cache_acquire(font) and blf_glyph_cache_release(font) to access cache!
+ */
GlyphCacheBLF *glyph_cache;
/* list of kerning cache for this font. */
@@ -272,6 +274,9 @@ typedef struct FontBLF {
/* data for buffer usage (drawing into a texture buffer) */
FontBufInfoBLF buf_info;
+
+ /* Mutex lock for glyph cache. */
+ SpinLock *glyph_cache_mutex;
} FontBLF;
typedef struct DirBLF {
diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c
index d6710b91539..4e44a85443d 100644
--- a/source/blender/blenfont/intern/blf_thumbs.c
+++ b/source/blender/blenfont/intern/blf_thumbs.c
@@ -109,7 +109,7 @@ void BLF_thumb_preview(const char *filename,
font->pos[1] -= font->glyph_cache->ascender * 1.1f;
/* We fallback to default english strings in case not enough chars are available in current
- * font for given translated string (useful in non-latin i18n context, like chinese,
+ * font for given translated string (useful in non-latin i18n context, like Chinese,
* since many fonts will then show nothing but ugly 'missing char' in their preview).
* Does not handle all cases, but much better than nothing.
*/
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index a4863780d2e..868c5a69593 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -19,6 +19,7 @@
#ifndef __BKE_ACTION_H__
#define __BKE_ACTION_H__
+
/** \file
* \ingroup bke
* \brief Blender kernel action and pose functionality.
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index a2a14011595..4e4528ff92b 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -25,7 +25,6 @@
*/
struct AnimData;
-struct ChannelDriver;
struct Depsgraph;
struct FCurve;
struct ID;
@@ -289,7 +288,7 @@ void BKE_animsys_eval_animdata(struct Depsgraph *depsgraph, struct ID *id);
void BKE_animsys_eval_driver(struct Depsgraph *depsgraph,
struct ID *id,
int driver_index,
- struct ChannelDriver *driver_orig);
+ struct FCurve *fcu_orig);
void BKE_animsys_update_driver_array(struct ID *id);
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index 3beae7a1f9d..b255500272a 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -182,6 +182,7 @@ void BKE_bone_parent_transform_apply(const struct BoneParentTransform *bpt,
void BKE_bone_parent_transform_calc_from_pchan(const struct bPoseChannel *pchan,
struct BoneParentTransform *r_bpt);
void BKE_bone_parent_transform_calc_from_matrices(int bone_flag,
+ int inherit_scale_mode,
const float offs_bone[4][4],
const float parent_arm_mat[4][4],
const float parent_pose_mat[4][4],
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 09900651dad..21ef70b7bcd 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -27,7 +27,7 @@
* \note Use #STRINGIFY() rather than defining with quotes.
*/
#define BLENDER_VERSION 281
-#define BLENDER_SUBVERSION 3
+#define BLENDER_SUBVERSION 12
/** Several breakages with 280, e.g. collections vs layers. */
#define BLENDER_MINVERSION 280
#define BLENDER_MINSUBVERSION 0
@@ -37,6 +37,8 @@
#define BLENDER_VERSION_CHAR
/** alpha/beta/rc/release, docs use this. */
#define BLENDER_VERSION_CYCLE alpha
+/** Optionally set to 1,2,... for example to to get alpha1 or rc2. */
+#define BLENDER_VERSION_CYCLE_NUMBER
/** Defined in from blender.c */
extern char versionstr[];
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 26ab7f8ba0c..891247f8127 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -56,7 +56,7 @@ void BKE_brush_make_local(struct Main *bmain, struct Brush *brush, const bool li
void BKE_brush_free(struct Brush *brush);
void BKE_brush_sculpt_reset(struct Brush *brush);
-void BKE_brush_gpencil_presets(struct bContext *C);
+void BKE_brush_gpencil_presets(struct Main *bmain, struct ToolSettings *ts);
/* image icon function */
struct ImBuf *get_brush_icon(struct Brush *brush);
@@ -90,7 +90,9 @@ float BKE_brush_sample_masktex(const struct Scene *scene,
unsigned int *BKE_brush_gen_texture_cache(struct Brush *br, int half_side, bool use_secondary);
/* radial control */
-struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br, bool secondary);
+struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br,
+ bool secondary,
+ bool display_gradient);
/* unified strength size and color */
diff --git a/source/blender/blenkernel/BKE_callbacks.h b/source/blender/blenkernel/BKE_callbacks.h
new file mode 100644
index 00000000000..e15cf7fed18
--- /dev/null
+++ b/source/blender/blenkernel/BKE_callbacks.h
@@ -0,0 +1,84 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifndef __BKE_CALLBACKS_H__
+#define __BKE_CALLBACKS_H__
+
+struct Depsgraph;
+struct ID;
+struct Main;
+struct PointerRNA;
+
+/**
+ * Common suffix uses:
+ * - ``_PRE/_POST``:
+ * For handling discrete non-interactive events.
+ * - ``_INIT/_COMPLETE/_CANCEL``:
+ * For handling jobs (which may in turn cause other handlers to be called).
+ */
+typedef enum {
+ BKE_CB_EVT_FRAME_CHANGE_PRE,
+ BKE_CB_EVT_FRAME_CHANGE_POST,
+ BKE_CB_EVT_RENDER_PRE,
+ BKE_CB_EVT_RENDER_POST,
+ BKE_CB_EVT_RENDER_WRITE,
+ BKE_CB_EVT_RENDER_STATS,
+ BKE_CB_EVT_RENDER_INIT,
+ BKE_CB_EVT_RENDER_COMPLETE,
+ BKE_CB_EVT_RENDER_CANCEL,
+ BKE_CB_EVT_LOAD_PRE,
+ BKE_CB_EVT_LOAD_POST,
+ BKE_CB_EVT_SAVE_PRE,
+ BKE_CB_EVT_SAVE_POST,
+ BKE_CB_EVT_UNDO_PRE,
+ BKE_CB_EVT_UNDO_POST,
+ BKE_CB_EVT_REDO_PRE,
+ BKE_CB_EVT_REDO_POST,
+ BKE_CB_EVT_DEPSGRAPH_UPDATE_PRE,
+ BKE_CB_EVT_DEPSGRAPH_UPDATE_POST,
+ BKE_CB_EVT_VERSION_UPDATE,
+ BKE_CB_EVT_LOAD_FACTORY_USERDEF_POST,
+ BKE_CB_EVT_LOAD_FACTORY_STARTUP_POST,
+ BKE_CB_EVT_TOT,
+} eCbEvent;
+
+typedef struct bCallbackFuncStore {
+ struct bCallbackFuncStore *next, *prev;
+ void (*func)(struct Main *, struct PointerRNA **, const int num_pointers, void *arg);
+ void *arg;
+ short alloc;
+} bCallbackFuncStore;
+
+void BKE_callback_exec(struct Main *bmain,
+ struct PointerRNA **pointers,
+ const int num_pointers,
+ eCbEvent evt);
+void BKE_callback_exec_null(struct Main *bmain, eCbEvent evt);
+void BKE_callback_exec_id(struct Main *bmain, struct ID *id, eCbEvent evt);
+void BKE_callback_exec_id_depsgraph(struct Main *bmain,
+ struct ID *id,
+ struct Depsgraph *depsgraph,
+ eCbEvent evt);
+void BKE_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt);
+
+void BKE_callback_global_init(void);
+void BKE_callback_global_finalize(void);
+
+#endif /* __BKE_CALLBACKS_H__ */
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index da80b3d5032..d1c133c79b5 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -28,8 +28,6 @@
extern "C" {
#endif
-#include "DNA_vec_types.h"
-
struct Camera;
struct Depsgraph;
struct Main;
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h
index 757b1c64db3..0d33d86ec16 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -70,13 +70,9 @@ struct Collection *BKE_collection_duplicate(struct Main *bmain,
const bool do_hierarchy,
const bool do_objects,
const bool do_obdata);
-struct Collection *BKE_collection_copy_master(struct Main *bmain,
- struct Collection *collection,
- const int flag);
/* Master Collection for Scene */
-struct Collection *BKE_collection_master(const struct Scene *scene);
struct Collection *BKE_collection_master_add(void);
struct Scene *BKE_collection_master_scene_search(const struct Main *bmain,
const struct Collection *master_collection);
@@ -225,7 +221,7 @@ void BKE_scene_objects_iterator_end(struct BLI_Iterator *iter);
bool is_scene_collection = (_scene) != NULL; \
\
if (_scene) { \
- _instance_next = BKE_collection_master(_scene); \
+ _instance_next = _scene->master_collection; \
} \
else { \
_instance_next = (_bmain)->collections.first; \
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index 6bd7440eeea..105f8e82343 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -96,7 +96,7 @@ typedef struct bContextStore {
/* for the context's rna mode enum
* keep aligned with data_mode_strings in context.c */
-enum eContextObjectMode {
+typedef enum eContextObjectMode {
CTX_MODE_EDIT_MESH = 0,
CTX_MODE_EDIT_CURVE,
CTX_MODE_EDIT_SURFACE,
@@ -115,7 +115,7 @@ enum eContextObjectMode {
CTX_MODE_EDIT_GPENCIL,
CTX_MODE_SCULPT_GPENCIL,
CTX_MODE_WEIGHT_GPENCIL,
-};
+} eContextObjectMode;
#define CTX_MODE_NUM (CTX_MODE_WEIGHT_GPENCIL + 1)
/* Context */
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index be49ca150b2..630c5fa1856 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -72,7 +72,7 @@ typedef struct CVKeyIndex {
/* ** Curve ** */
void BKE_curve_free(struct Curve *cu);
void BKE_curve_editfont_free(struct Curve *cu);
-void BKE_curve_init(struct Curve *cu);
+void BKE_curve_init(struct Curve *cu, const short curve_type);
struct Curve *BKE_curve_add(struct Main *bmain, const char *name, int type);
void BKE_curve_copy_data(struct Main *bmain,
struct Curve *cu_dst,
@@ -86,11 +86,10 @@ void BKE_curve_curve_dimension_update(struct Curve *cu);
void BKE_curve_boundbox_calc(struct Curve *cu, float r_loc[3], float r_size[3]);
struct BoundBox *BKE_curve_boundbox_get(struct Object *ob);
+
void BKE_curve_texspace_calc(struct Curve *cu);
-struct BoundBox *BKE_curve_texspace_get(struct Curve *cu,
- float r_loc[3],
- float r_rot[3],
- float r_size[3]);
+void BKE_curve_texspace_ensure(struct Curve *cu);
+void BKE_curve_texspace_get(struct Curve *cu, float r_loc[3], float r_size[3]);
bool BKE_curve_minmax(struct Curve *cu, bool use_radius, float min[3], float max[3]);
bool BKE_curve_center_median(struct Curve *cu, float cent[3]);
diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h
index 062968eddfc..47c8f31ead3 100644
--- a/source/blender/blenkernel/BKE_editmesh.h
+++ b/source/blender/blenkernel/BKE_editmesh.h
@@ -30,6 +30,7 @@
struct BMLoop;
struct BMesh;
+struct BoundBox;
struct Depsgraph;
struct EditMeshData;
struct Mesh;
@@ -59,6 +60,9 @@ typedef struct BMEditMesh {
struct Mesh *mesh_eval_final, *mesh_eval_cage;
+ /** Cached cage bounding box for selection. */
+ struct BoundBox *bb_cage;
+
/*derivedmesh stuff*/
CustomData_MeshMasks lastDataMask;
unsigned char (*derivedVertColor)[4];
@@ -90,6 +94,7 @@ void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype);
float (*BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em, int *r_vert_len))[3];
void BKE_editmesh_lnorspace_update(BMEditMesh *em);
void BKE_editmesh_ensure_autosmooth(BMEditMesh *em);
+struct BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em);
/* editderivedmesh.c */
/* should really be defined in editmesh.c, but they use 'EditDerivedBMesh' */
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index 4c1a115eb23..5be9a35b168 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -89,6 +89,9 @@ struct ChannelDriver *fcurve_copy_driver(const struct ChannelDriver *driver);
void driver_variables_copy(struct ListBase *dst_list, const struct ListBase *src_list);
+void BKE_driver_target_matrix_to_rot_channels(
+ float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4]);
+
void driver_free_variable(struct ListBase *variables, struct DriverVar *dvar);
void driver_free_variable_ex(struct ChannelDriver *driver, struct DriverVar *dvar);
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index f1cf87ea1b5..d09917a9e41 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -32,6 +32,7 @@ struct ListBase;
struct Main;
struct Material;
struct Object;
+struct Scene;
struct ToolSettings;
struct bDeformGroup;
struct bGPDframe;
@@ -58,6 +59,9 @@ struct MDeformVert;
#define GPENCIL_SIMPLIFY_BLEND(scene, playing) \
((GPENCIL_SIMPLIFY_ONPLAY(playing) && (GPENCIL_SIMPLIFY(scene)) && \
(scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_BLEND)))
+#define GPENCIL_SIMPLIFY_TINT(scene, playing) \
+ ((GPENCIL_SIMPLIFY_ONPLAY(playing) && (GPENCIL_SIMPLIFY(scene)) && \
+ (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_TINT)))
/* ------------ Grease-Pencil API ------------------ */
@@ -149,13 +153,14 @@ bool BKE_gpencil_layer_delframe(struct bGPDlayer *gpl, struct bGPDframe *gpf);
struct bGPDlayer *BKE_gpencil_layer_getactive(struct bGPdata *gpd);
void BKE_gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active);
void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
+void BKE_gpencil_layer_autolock_set(struct bGPdata *gpd, const bool unlock);
/* Brush */
struct Material *BKE_gpencil_brush_material_get(struct Brush *brush);
void BKE_gpencil_brush_material_set(struct Brush *brush, struct Material *material);
/* Object */
-struct Material *BKE_gpencil_object_material_ensure_active(struct Main *bmain, struct Object *ob);
+struct Material *BKE_gpencil_object_material_ensure_active(struct Object *ob);
struct Material *BKE_gpencil_object_material_ensure_from_brush(struct Main *bmain,
struct Object *ob,
struct Brush *brush);
@@ -179,8 +184,7 @@ struct Material *BKE_gpencil_object_material_ensure_from_active_input_toolsettin
struct Material *BKE_gpencil_object_material_ensure_from_active_input_brush(struct Main *bmain,
struct Object *ob,
struct Brush *brush);
-struct Material *BKE_gpencil_object_material_ensure_from_active_input_material(struct Main *bmain,
- struct Object *ob);
+struct Material *BKE_gpencil_object_material_ensure_from_active_input_material(struct Object *ob);
/* object boundbox */
bool BKE_gpencil_data_minmax(const struct bGPdata *gpd, float r_min[3], float r_max[3]);
@@ -238,6 +242,14 @@ void BKE_gpencil_get_range_selected(struct bGPDlayer *gpl, int *r_initframe, int
float BKE_gpencil_multiframe_falloff_calc(
struct bGPDframe *gpf, int actnum, int f_init, int f_end, struct CurveMapping *cur_falloff);
+void BKE_gpencil_convert_curve(struct Main *bmain,
+ struct Scene *scene,
+ struct Object *ob_gp,
+ struct Object *ob_cu,
+ const bool gpencil_lines,
+ const bool use_collections,
+ const bool only_stroke);
+
extern void (*BKE_gpencil_batch_cache_dirty_tag_cb)(struct bGPdata *gpd);
extern void (*BKE_gpencil_batch_cache_free_cb)(struct bGPdata *gpd);
diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h
index 36f38996c36..918f85d146c 100644
--- a/source/blender/blenkernel/BKE_gpencil_modifier.h
+++ b/source/blender/blenkernel/BKE_gpencil_modifier.h
@@ -21,8 +21,6 @@
*/
#include "DNA_gpencil_modifier_types.h" /* needed for all enum typdefs */
-#include "BLI_compiler_attrs.h"
-#include "BKE_customdata.h"
struct Depsgraph;
struct GpencilModifierData;
@@ -33,7 +31,7 @@ struct ModifierUpdateDepsgraphContext;
struct Object;
struct Scene;
/* NOTE: bakeModifier() called from UI:
- * needs to create new databloc-ks, hence the need for this. */
+ * needs to create new data-blocks, hence the need for this. */
struct bGPDframe;
struct bGPDlayer;
struct bGPDstroke;
@@ -299,6 +297,7 @@ void BKE_gpencil_modifiers_foreachTexLink(struct Object *ob,
bool BKE_gpencil_has_geometry_modifiers(struct Object *ob);
bool BKE_gpencil_has_time_modifiers(struct Object *ob);
+bool BKE_gpencil_has_transform_modifiers(struct Object *ob);
void BKE_gpencil_stroke_modifiers(struct Depsgraph *depsgraph,
struct Object *ob,
diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
index eb65b7641e1..535980840c1 100644
--- a/source/blender/blenkernel/BKE_layer.h
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -90,6 +90,7 @@ int BKE_layer_collection_findindex(struct ViewLayer *view_layer, const struct La
void BKE_main_collection_sync(const struct Main *bmain);
void BKE_scene_collection_sync(const struct Scene *scene);
void BKE_layer_collection_sync(const struct Scene *scene, struct ViewLayer *view_layer);
+void BKE_layer_collection_local_sync(struct ViewLayer *view_layer, struct View3D *v3d);
void BKE_main_collection_sync_remap(const struct Main *bmain);
@@ -117,6 +118,10 @@ void BKE_layer_collection_isolate(struct Scene *scene,
struct ViewLayer *view_layer,
struct LayerCollection *lc,
bool extend);
+void BKE_layer_collection_local_isolate(struct ViewLayer *view_layer,
+ struct View3D *v3d,
+ struct LayerCollection *lc,
+ bool extend);
void BKE_layer_collection_set_visible(struct ViewLayer *view_layer,
struct LayerCollection *lc,
const bool visible,
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index c8d85cd0c87..71799bf74f6 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -117,7 +117,7 @@ enum {
void BKE_libblock_copy_ex(struct Main *bmain,
const struct ID *id,
struct ID **r_newid,
- const int flag);
+ const int orig_flag);
void *BKE_libblock_copy(struct Main *bmain, const struct ID *id) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
/* Special version. sued by datablock localization. */
@@ -175,6 +175,7 @@ void BKE_libblock_management_usercounts_clear(struct Main *bmain, void *idv);
void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id);
void id_lib_extern(struct ID *id);
+void id_lib_indirect_weak_link(struct ID *id);
void BKE_library_filepath_set(struct Main *bmain, struct Library *lib, const char *filepath);
void id_us_ensure_real(struct ID *id);
void id_us_clear_real(struct ID *id);
diff --git a/source/blender/blenkernel/BKE_library_override.h b/source/blender/blenkernel/BKE_library_override.h
index 5440b0ebe63..5cffabd333f 100644
--- a/source/blender/blenkernel/BKE_library_override.h
+++ b/source/blender/blenkernel/BKE_library_override.h
@@ -35,10 +35,12 @@ bool BKE_override_library_is_enabled(void);
struct IDOverrideLibrary *BKE_override_library_init(struct ID *local_id, struct ID *reference_id);
void BKE_override_library_copy(struct ID *dst_id, const struct ID *src_id);
-void BKE_override_library_clear(struct IDOverrideLibrary *override);
-void BKE_override_library_free(struct IDOverrideLibrary **override);
+void BKE_override_library_clear(struct IDOverrideLibrary *override, const bool do_id_user);
+void BKE_override_library_free(struct IDOverrideLibrary **override, const bool do_id_user);
-struct ID *BKE_override_library_create_from_id(struct Main *bmain, struct ID *reference_id);
+struct ID *BKE_override_library_create_from_id(struct Main *bmain,
+ struct ID *reference_id,
+ const bool do_tagged_remap);
bool BKE_override_library_create_from_tag(struct Main *bmain);
struct IDOverrideLibraryProperty *BKE_override_library_property_find(
diff --git a/source/blender/blenkernel/BKE_library_remap.h b/source/blender/blenkernel/BKE_library_remap.h
index 917582e385a..784e1a570c5 100644
--- a/source/blender/blenkernel/BKE_library_remap.h
+++ b/source/blender/blenkernel/BKE_library_remap.h
@@ -85,7 +85,7 @@ void BKE_libblock_relink_ex(struct Main *bmain,
void *idv,
void *old_idv,
void *new_idv,
- const bool us_min_never_null) ATTR_NONNULL(1, 2);
+ const short remap_flags) ATTR_NONNULL(1, 2);
void BKE_libblock_relink_to_newid(struct ID *id) ATTR_NONNULL();
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index 44a8f98e994..7ff9c4e6376 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -38,6 +38,7 @@ struct bNode;
/* materials */
void init_def_material(void);
+void BKE_material_gpencil_default_free(void);
void BKE_material_free(struct Material *ma);
void test_object_materials(struct Main *bmain, struct Object *ob, struct ID *id);
void test_all_objects_materials(struct Main *bmain, struct ID *id);
@@ -46,6 +47,7 @@ void BKE_material_resize_object(struct Main *bmain,
const short totcol,
bool do_id_user);
void BKE_material_init(struct Material *ma);
+void BKE_material_gpencil_init(struct Material *ma);
void BKE_material_remap_object(struct Object *ob, const unsigned int *remap);
void BKE_material_remap_object_calc(struct Object *ob_dst,
struct Object *ob_src,
@@ -92,6 +94,7 @@ bool BKE_object_material_slot_add(struct Main *bmain, struct Object *ob);
bool BKE_object_material_slot_remove(struct Main *bmain, struct Object *ob);
bool BKE_object_material_slot_used(struct ID *id, short actcol);
+struct Material *BKE_material_gpencil_get(struct Object *ob, short act);
struct MaterialGPencilStyle *BKE_material_gpencil_settings_get(struct Object *ob, short act);
void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma);
@@ -123,6 +126,7 @@ struct Depsgraph;
void BKE_material_eval(struct Depsgraph *depsgraph, struct Material *material);
extern struct Material defmaterial;
+extern struct Material defgpencil_material;
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 15df0cff6fc..90afec54561 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -26,9 +26,6 @@
/* defines BLI_INLINE */
#include "BLI_compiler_compat.h"
-/* defines CustomDataMask */
-//#include "BKE_customdata.h"
-
struct BLI_Stack;
struct BMEditMesh;
struct BMesh;
@@ -81,12 +78,18 @@ struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me,
const bool add_key_index,
const struct BMeshCreateParams *params);
-struct Mesh *BKE_mesh_from_bmesh_nomain(struct BMesh *bm, const struct BMeshToMeshParams *params);
+struct Mesh *BKE_mesh_from_bmesh_nomain(struct BMesh *bm,
+ const struct BMeshToMeshParams *params,
+ const struct Mesh *me_settings);
struct Mesh *BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm,
- const struct CustomData_MeshMasks *cd_mask_extra);
+ const struct CustomData_MeshMasks *cd_mask_extra,
+ const struct Mesh *me_settings);
struct Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(
- struct BMEditMesh *em, const struct CustomData_MeshMasks *data_mask, float (*vertexCos)[3]);
+ struct BMEditMesh *em,
+ const struct CustomData_MeshMasks *data_mask,
+ float (*vertexCos)[3],
+ const struct Mesh *me_settings);
int poly_find_loop_from_vert(const struct MPoly *poly,
const struct MLoop *loopstart,
@@ -110,6 +113,7 @@ void BKE_mesh_copy_data(struct Main *bmain,
const struct Mesh *me_src,
const int flag);
struct Mesh *BKE_mesh_copy(struct Main *bmain, const struct Mesh *me);
+void BKE_mesh_copy_settings(struct Mesh *me_dst, const struct Mesh *me_src);
void BKE_mesh_update_customdata_pointers(struct Mesh *me, const bool do_ensure_tess_cd);
void BKE_mesh_ensure_skin_customdata(struct Mesh *me);
@@ -121,6 +125,13 @@ struct Mesh *BKE_mesh_new_nomain_from_template(const struct Mesh *me_src,
int tessface_len,
int loops_len,
int polys_len);
+struct Mesh *BKE_mesh_new_nomain_from_template_ex(const struct Mesh *me_src,
+ int verts_len,
+ int edges_len,
+ int tessface_len,
+ int loops_len,
+ int polys_len,
+ CustomData_MeshMasks mask);
void BKE_mesh_eval_delete(struct Mesh *me_eval);
@@ -137,8 +148,6 @@ bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me);
bool BKE_mesh_clear_facemap_customdata(struct Mesh *me);
void BKE_mesh_make_local(struct Main *bmain, struct Mesh *me, const bool lib_local);
-void BKE_mesh_boundbox_calc(struct Mesh *me, float r_loc[3], float r_size[3]);
-void BKE_mesh_texspace_calc(struct Mesh *me);
float (*BKE_mesh_orco_verts_get(struct Object *ob))[3];
void BKE_mesh_orco_verts_transform(struct Mesh *me, float (*orco)[3], int totvert, int invert);
int test_index_face(struct MFace *mface, struct CustomData *mfdata, int mfindex, int nr);
@@ -188,12 +197,14 @@ void BKE_mesh_smooth_flag_set(struct Mesh *me, const bool use_smooth);
const char *BKE_mesh_cmp(struct Mesh *me1, struct Mesh *me2, float thresh);
struct BoundBox *BKE_mesh_boundbox_get(struct Object *ob);
-struct BoundBox *BKE_mesh_texspace_get(struct Mesh *me,
- float r_loc[3],
- float r_rot[3],
- float r_size[3]);
-void BKE_mesh_texspace_get_reference(
- struct Mesh *me, short **r_texflag, float **r_loc, float **r_rot, float **r_size);
+
+void BKE_mesh_texspace_calc(struct Mesh *me);
+void BKE_mesh_texspace_ensure(struct Mesh *me);
+void BKE_mesh_texspace_get(struct Mesh *me, float r_loc[3], float r_size[3]);
+void BKE_mesh_texspace_get_reference(struct Mesh *me,
+ short **r_texflag,
+ float **r_loc,
+ float **r_size);
void BKE_mesh_texspace_copy_from_object(struct Mesh *me, struct Object *ob);
void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals);
@@ -473,6 +484,7 @@ void BKE_mesh_calc_poly_center(const struct MPoly *mpoly,
float BKE_mesh_calc_poly_area(const struct MPoly *mpoly,
const struct MLoop *loopstart,
const struct MVert *mvarray);
+float BKE_mesh_calc_area(const struct Mesh *me);
float BKE_mesh_calc_poly_uv_area(const struct MPoly *mpoly, const struct MLoopUV *uv_array);
void BKE_mesh_calc_poly_angles(const struct MPoly *mpoly,
const struct MLoop *loopstart,
diff --git a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h
index 089e4de4709..cc4a3a01892 100644
--- a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h
+++ b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h
@@ -16,8 +16,9 @@
* The Original Code is Copyright (C) 2019 by Blender Foundation
* All rights reserved.
*/
-#ifndef __BKE_REMESH_H__
-#define __BKE_REMESH_H__
+
+#ifndef __BKE_MESH_REMESH_VOXEL_H__
+#define __BKE_MESH_REMESH_VOXEL_H__
/** \file
* \ingroup bke
@@ -38,9 +39,21 @@ struct Mesh *BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(struct OpenVDBLeve
double adaptivity,
bool relax_disoriented_triangles);
#endif
-struct Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(struct Mesh *mesh, float voxel_size);
+
+struct Mesh *BKE_mesh_remesh_voxel_fix_poles(struct Mesh *mesh);
+struct Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(struct Mesh *mesh,
+ float voxel_size,
+ float adaptivity);
+struct Mesh *BKE_mesh_remesh_quadriflow_to_mesh_nomain(struct Mesh *mesh,
+ int target_faces,
+ int seed,
+ bool preserve_sharp,
+ bool preserve_boundary,
+ bool adaptive_scale,
+ void *update_cb,
+ void *update_cb_data);
/* Data reprojection functions */
void BKE_remesh_reproject_paint_mask(struct Mesh *target, struct Mesh *source);
-#endif /* __BKE_REMESH_H__ */
+#endif /* __BKE_MESH_REMESH_VOXEL_H__ */
diff --git a/source/blender/blenkernel/BKE_mirror.h b/source/blender/blenkernel/BKE_mirror.h
new file mode 100644
index 00000000000..20eb8a920fc
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mirror.h
@@ -0,0 +1,45 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+#ifndef __BKE_MIRROR_H__
+#define __BKE_MIRROR_H__
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BLI_utildefines.h"
+
+struct MirrorModifierData;
+struct ModifierEvalContext;
+struct Object;
+
+struct Mesh *BKE_mirror_bisect_on_mirror_plane(struct MirrorModifierData *mmd,
+ const struct Mesh *mesh,
+ int axis,
+ const float plane_co[3],
+ float plane_no[3]);
+
+struct Mesh *BKE_mirror_apply_mirror_on_axis(struct MirrorModifierData *mmd,
+ const struct ModifierEvalContext *UNUSED(ctx),
+ struct Object *ob,
+ const struct Mesh *mesh,
+ int axis);
+
+#endif /* __BKE_MIRROR_H__ */
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h
index c5955a9af8d..7513717df41 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -53,8 +53,8 @@ void multires_mark_as_modified(struct Depsgraph *depsgraph,
struct Object *object,
enum MultiresModifiedFlags flags);
-void multires_force_update(struct Object *ob);
-void multires_force_render_update(struct Object *ob);
+void multires_flush_sculpt_updates(struct Object *ob);
+void multires_force_sculpt_rebuild(struct Object *ob);
void multires_force_external_reload(struct Object *ob);
/* internal, only called in subsurf_ccg.c */
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index efc4e4fdc12..06fd7915476 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -30,13 +30,7 @@
#include "DNA_listBase.h"
/* for FOREACH_NODETREE_BEGIN */
-#include "DNA_light_types.h"
-#include "DNA_material_types.h"
#include "DNA_node_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_texture_types.h"
-#include "DNA_world_types.h"
-#include "DNA_linestyle_types.h"
#include "RNA_types.h"
@@ -46,19 +40,23 @@
struct ARegion;
struct ColorManagedDisplaySettings;
struct ColorManagedViewSettings;
+struct FreestyleLineStyle;
struct GPUMaterial;
struct GPUNodeStack;
struct ID;
struct ImBuf;
struct ImageFormatData;
+struct Light;
struct ListBase;
struct MTex;
struct Main;
+struct Material;
struct PointerRNA;
struct RenderData;
struct Scene;
struct SpaceNode;
struct Tex;
+struct World;
struct bContext;
struct bNode;
struct bNodeExecContext;
@@ -384,6 +382,7 @@ void ntreeUserIncrefID(struct bNodeTree *ntree);
void ntreeUserDecrefID(struct bNodeTree *ntree);
struct bNodeTree *ntreeFromID(const struct ID *id);
+struct ID *BKE_node_tree_find_owner_ID(struct Main *bmain, struct bNodeTree *ntree);
void ntreeMakeLocal(struct Main *bmain,
struct bNodeTree *ntree,
@@ -592,6 +591,10 @@ void nodeChainIter(const bNodeTree *ntree,
bool (*callback)(bNode *, bNode *, void *, const bool),
void *userdata,
const bool reversed);
+void nodeChainIterBackwards(const bNodeTree *ntree,
+ const bNode *node_start,
+ bool (*callback)(bNode *, bNode *, void *),
+ void *userdata);
void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata);
struct bNodeLink *nodeFindLink(struct bNodeTree *ntree,
@@ -831,11 +834,11 @@ void BKE_node_tree_unlink_id(ID *id, struct bNodeTree *ntree);
struct NodeTreeIterStore {
bNodeTree *ngroup;
Scene *scene;
- Material *mat;
+ struct Material *mat;
Tex *tex;
- Light *light;
- World *world;
- FreestyleLineStyle *linestyle;
+ struct Light *light;
+ struct World *world;
+ struct FreestyleLineStyle *linestyle;
};
void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *bmain);
@@ -979,6 +982,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
#define SH_NODE_CLAMP 703
#define SH_NODE_TEX_WHITE_NOISE 704
#define SH_NODE_VOLUME_INFO 705
+#define SH_NODE_VERTEX_COLOR 706
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index cf4bce3a209..ffdcb9cd2c0 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -110,7 +110,7 @@ typedef enum eObjectVisibilityResult {
int BKE_object_visibility(const struct Object *ob, const int dag_eval_mode);
-void BKE_object_init(struct Object *ob);
+void BKE_object_init(struct Object *ob, const short ob_type);
struct Object *BKE_object_add_only_object(struct Main *bmain, int type, const char *name)
ATTR_NONNULL(1) ATTR_RETURNS_NONNULL;
struct Object *BKE_object_add(struct Main *bmain,
@@ -222,7 +222,13 @@ void BKE_boundbox_minmax(const struct BoundBox *bb,
struct BoundBox *BKE_object_boundbox_get(struct Object *ob);
void BKE_object_dimensions_get(struct Object *ob, float vec[3]);
+void BKE_object_dimensions_set_ex(struct Object *ob,
+ const float value[3],
+ int axis_mask,
+ const float ob_scale_orig[3],
+ const float ob_obmat_orig[4][4]);
void BKE_object_dimensions_set(struct Object *ob, const float value[3], int axis_mask);
+
void BKE_object_empty_draw_type_set(struct Object *ob, const int value);
void BKE_object_boundbox_flag(struct Object *ob, int flag, const bool set);
void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval);
@@ -315,8 +321,10 @@ void BKE_object_handle_update_ex(struct Depsgraph *depsgraph,
void BKE_object_sculpt_data_create(struct Object *ob);
-int BKE_object_obdata_texspace_get(
- struct Object *ob, short **r_texflag, float **r_loc, float **r_size, float **r_rot);
+int BKE_object_obdata_texspace_get(struct Object *ob,
+ short **r_texflag,
+ float **r_loc,
+ float **r_size);
struct Mesh *BKE_object_get_evaluated_mesh(const struct Depsgraph *depsgraph, struct Object *ob);
struct Mesh *BKE_object_get_final_mesh(struct Object *object);
diff --git a/source/blender/blenkernel/BKE_object_facemap.h b/source/blender/blenkernel/BKE_object_facemap.h
index ef0cbaa2ae6..83780d8fad5 100644
--- a/source/blender/blenkernel/BKE_object_facemap.h
+++ b/source/blender/blenkernel/BKE_object_facemap.h
@@ -40,6 +40,11 @@ void BKE_object_facemap_unique_name(struct Object *ob, struct bFaceMap *fmap);
struct bFaceMap *BKE_object_facemap_find_name(struct Object *ob, const char *name);
void BKE_object_facemap_copy_list(struct ListBase *outbase, const struct ListBase *inbase);
+int *BKE_object_facemap_index_map_create(struct Object *ob_src,
+ struct Object *ob_dst,
+ int *r_map_len);
+void BKE_object_facemap_index_map_apply(int *fmap, int fmap_len, const int *map, int map_len);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 8db27bd4118..8580aefcfbc 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -256,9 +256,31 @@ typedef struct SculptSession {
float (*layer_co)[3]; /* Copy of the mesh vertices' locations */
struct StrokeCache *cache;
+ struct FilterCache *filter_cache;
+ /* Cursor data and active vertex for tools */
int active_vertex_index;
+ float cursor_radius;
+ float cursor_location[3];
+ float cursor_normal[3];
+ float cursor_view_normal[3];
+ struct RegionView3D *rv3d;
+
+ /* Dynamic mesh preview */
+ int *preview_vert_index_list;
+ int preview_vert_index_count;
+ float pose_origin[3];
+
+ /* Transform operator */
+ float pivot_pos[3];
+ float pivot_rot[4];
+ float pivot_scale[3];
+
+ float init_pivot_pos[3];
+ float init_pivot_rot[4];
+ float init_pivot_scale[3];
+
union {
struct {
struct SculptVertexPaintGeomMap gmap;
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 93a826f3324..dedf76ee839 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -24,7 +24,9 @@
#include "BLI_bitmap.h"
#include "BLI_ghash.h"
-#include "BLI_utildefines.h"
+
+/* For embedding CCGKey in iterator. */
+#include "BKE_ccg.h"
struct BMLog;
struct BMesh;
@@ -41,6 +43,7 @@ struct MVert;
struct PBVH;
struct PBVHNode;
struct SubdivCCG;
+struct TaskParallelSettings;
typedef struct PBVH PBVH;
typedef struct PBVHNode PBVHNode;
@@ -50,20 +53,28 @@ typedef struct {
} PBVHProxyNode;
typedef enum {
- PBVH_Leaf = 1,
+ PBVH_Leaf = 1 << 0,
- PBVH_UpdateNormals = 2,
- PBVH_UpdateBB = 4,
- PBVH_UpdateOriginalBB = 8,
- PBVH_UpdateDrawBuffers = 16,
- PBVH_UpdateRedraw = 32,
+ PBVH_UpdateNormals = 1 << 1,
+ PBVH_UpdateBB = 1 << 2,
+ PBVH_UpdateOriginalBB = 1 << 3,
+ PBVH_UpdateDrawBuffers = 1 << 4,
+ PBVH_UpdateRedraw = 1 << 5,
+ PBVH_UpdateMask = 1 << 6,
- PBVH_RebuildDrawBuffers = 64,
- PBVH_FullyHidden = 128,
+ PBVH_RebuildDrawBuffers = 1 << 7,
+ PBVH_FullyHidden = 1 << 8,
+ PBVH_FullyMasked = 1 << 9,
+ PBVH_FullyUnmasked = 1 << 10,
- PBVH_UpdateTopology = 256,
+ PBVH_UpdateTopology = 1 << 11,
} PBVHNodeFlags;
+typedef struct PBVHFrustumPlanes {
+ float (*planes)[4];
+ int num_planes;
+} PBVHFrustumPlanes;
+
/* Callbacks */
/* returns 1 if the search should continue from this node, 0 otherwise */
@@ -132,8 +143,11 @@ bool BKE_pbvh_node_raycast(PBVH *bvh,
float (*origco)[3],
bool use_origco,
const float ray_start[3],
+ const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
- float *depth);
+ float *depth,
+ int *active_vertex_index,
+ float *face_normal);
bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
const float ray_start[3],
@@ -165,7 +179,9 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *bvh,
/* Drawing */
void BKE_pbvh_draw_cb(PBVH *bvh,
- float (*planes)[4],
+ bool show_vcol,
+ bool update_only_visible,
+ PBVHFrustumPlanes *frustum,
void (*draw_fn)(void *user_data, struct GPU_PBVH_Buffers *buffers),
void *user_data);
@@ -196,9 +212,10 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
int gridsize);
/* multires level, only valid for type == PBVH_GRIDS */
-void BKE_pbvh_get_grid_key(const PBVH *pbvh, struct CCGKey *key);
+const struct CCGKey *BKE_pbvh_get_grid_key(const PBVH *pbvh);
-struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh, int *num_grids);
+struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh);
+int BKE_pbvh_get_grid_num_vertices(const PBVH *pbvh);
/* Only valid for type == PBVH_BMESH */
struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh);
@@ -219,11 +236,16 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh,
/* Node Access */
void BKE_pbvh_node_mark_update(PBVHNode *node);
+void BKE_pbvh_node_mark_update_mask(PBVHNode *node);
void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node);
void BKE_pbvh_node_mark_redraw(PBVHNode *node);
void BKE_pbvh_node_mark_normals_update(PBVHNode *node);
void BKE_pbvh_node_mark_topology_update(PBVHNode *node);
void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden);
+void BKE_pbvh_node_fully_masked_set(PBVHNode *node, int fully_masked);
+bool BKE_pbvh_node_fully_masked_get(PBVHNode *node);
+void BKE_pbvh_node_fully_unmasked_set(PBVHNode *node, int fully_masked);
+bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node);
void BKE_pbvh_node_get_grids(PBVH *bvh,
PBVHNode *node,
@@ -243,10 +265,10 @@ void BKE_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max
float BKE_pbvh_node_get_tmin(PBVHNode *node);
-/* test if AABB is at least partially inside the planes' volume */
-bool BKE_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data);
-/* test if AABB is at least partially outside the planes' volume */
-bool BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data);
+/* test if AABB is at least partially inside the PBVHFrustumPlanes volume */
+bool BKE_pbvh_node_frustum_contain_AABB(PBVHNode *node, void *frustum);
+/* test if AABB is at least partially outside the PBVHFrustumPlanes volume */
+bool BKE_pbvh_node_frustum_exclude_AABB(PBVHNode *node, void *frustum);
struct GSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node);
struct GSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node);
@@ -257,8 +279,8 @@ void BKE_pbvh_bmesh_after_stroke(PBVH *bvh);
/* Update Bounding Box/Redraw and clear flags */
void BKE_pbvh_update_bounds(PBVH *bvh, int flags);
+void BKE_pbvh_update_vertex_data(PBVH *bvh, int flags);
void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg);
-void BKE_pbvh_update_draw_buffers(PBVH *bvh, bool show_vcol);
void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]);
void BKE_pbvh_get_grid_updates(PBVH *bvh, bool clear, void ***r_gridfaces, int *r_totface);
void BKE_pbvh_grids_update(PBVH *bvh,
@@ -302,9 +324,9 @@ typedef struct PBVHVertexIter {
int index;
/* grid */
+ struct CCGKey key;
struct CCGElem **grids;
struct CCGElem *grid;
- struct CCGKey *key;
BLI_bitmap **grid_hidden, *gh;
int *grid_indices;
int totgrid;
@@ -341,6 +363,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo
if (vi.grids) { \
vi.width = vi.gridsize; \
vi.height = vi.gridsize; \
+ vi.index = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \
vi.grid = vi.grids[vi.grid_indices[vi.g]]; \
if (mode == PBVH_ITER_UNIQUE) \
vi.gh = vi.grid_hidden[vi.grid_indices[vi.g]]; \
@@ -353,10 +376,11 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo
for (vi.gy = 0; vi.gy < vi.height; vi.gy++) { \
for (vi.gx = 0; vi.gx < vi.width; vi.gx++, vi.i++) { \
if (vi.grid) { \
- vi.co = CCG_elem_co(vi.key, vi.grid); \
- vi.fno = CCG_elem_no(vi.key, vi.grid); \
- vi.mask = vi.key->has_mask ? CCG_elem_mask(vi.key, vi.grid) : NULL; \
- vi.grid = CCG_elem_next(vi.key, vi.grid); \
+ vi.co = CCG_elem_co(&vi.key, vi.grid); \
+ vi.fno = CCG_elem_no(&vi.key, vi.grid); \
+ vi.mask = vi.key.has_mask ? CCG_elem_mask(&vi.key, vi.grid) : NULL; \
+ vi.grid = CCG_elem_next(&vi.key, vi.grid); \
+ vi.index++; \
if (vi.gh) { \
if (BLI_BITMAP_TEST(vi.gh, vi.gy * vi.gridsize + vi.gx)) \
continue; \
@@ -406,6 +430,10 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node);
+void BKE_pbvh_parallel_range_settings(struct TaskParallelSettings *settings,
+ bool use_threading,
+ int totnode);
+
// void BKE_pbvh_node_BB_reset(PBVHNode *node);
// void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]);
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index d25288fc240..846b8d21f28 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -220,7 +220,8 @@ void BKE_scene_allocate_depsgraph_hash(struct Scene *scene);
void BKE_scene_ensure_depsgraph_hash(struct Scene *scene);
void BKE_scene_free_depsgraph_hash(struct Scene *scene);
-struct Depsgraph *BKE_scene_get_depsgraph(struct Scene *scene,
+struct Depsgraph *BKE_scene_get_depsgraph(struct Main *bmain,
+ struct Scene *scene,
struct ViewLayer *view_layer,
bool allocate);
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index e1bc16702d5..16f766ae8bb 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -82,6 +82,11 @@ void BKE_sequence_iterator_end(SeqIterator *iter);
} \
((void)0)
+typedef enum eSeqTaskId {
+ SEQ_TASK_MAIN_RENDER,
+ SEQ_TASK_PREFETCH_RENDER,
+} eSeqTaskId;
+
typedef struct SeqRenderData {
struct Main *bmain;
struct Depsgraph *depsgraph;
@@ -94,7 +99,10 @@ typedef struct SeqRenderData {
float motion_blur_shutter;
bool skip_cache;
bool is_proxy_render;
+ bool is_prefetch_render;
int view_id;
+ /* ID of task for asigning temp cache entries to particular task(thread, etc.) */
+ eSeqTaskId task_id;
/* special case for OpenGL render */
struct GPUOffScreen *gpu_offscreen;
@@ -290,7 +298,7 @@ void BKE_sequencer_proxy_rebuild_context(struct Main *bmain,
void BKE_sequencer_proxy_rebuild(struct SeqIndexBuildContext *context,
short *stop,
short *do_update,
- float *progress);
+ float *num_frames_prefetched);
void BKE_sequencer_proxy_rebuild_finish(struct SeqIndexBuildContext *context, bool stop);
void BKE_sequencer_proxy_set(struct Sequence *seq, bool value);
@@ -318,6 +326,7 @@ bool BKE_sequencer_cache_put_if_possible(const SeqRenderData *context,
int type,
struct ImBuf *nval,
float cost);
+bool BKE_sequencer_cache_recycle_item(struct Scene *scene);
void BKE_sequencer_cache_free_temp_cache(struct Scene *scene, short id, int cfra);
void BKE_sequencer_cache_destruct(struct Scene *scene);
void BKE_sequencer_cache_cleanup_all(struct Main *bmain);
@@ -330,6 +339,22 @@ void BKE_sequencer_cache_iterate(
struct Scene *scene,
void *userdata,
bool callback(void *userdata, struct Sequence *seq, int cfra, int cache_type, float cost));
+bool BKE_sequencer_cache_is_full(struct Scene *scene);
+
+/* **********************************************************************
+ * seqprefetch.c
+ *
+ * Sequencer frame prefetching
+ * ********************************************************************** */
+
+void BKE_sequencer_prefetch_start(const SeqRenderData *context, float cfra, float cost);
+void BKE_sequencer_prefetch_stop(struct Scene *scene);
+void BKE_sequencer_prefetch_free(struct Scene *scene);
+bool BKE_sequencer_prefetch_need_redraw(struct Main *bmain, struct Scene *scene);
+void BKE_sequencer_prefetch_get_time_range(struct Scene *scene, int *start, int *end);
+SeqRenderData *BKE_sequencer_prefetch_get_original_context(const SeqRenderData *context);
+struct Sequence *BKE_sequencer_prefetch_get_original_sequence(struct Sequence *seq,
+ struct Scene *scene);
/* **********************************************************************
* seqeffects.c
diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h
index 9ec75c39fcf..e90b1429c9d 100644
--- a/source/blender/blenkernel/BKE_shrinkwrap.h
+++ b/source/blender/blenkernel/BKE_shrinkwrap.h
@@ -110,6 +110,16 @@ void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd,
float (*vertexCos)[3],
int numVerts);
+/* Used in editmesh_mask_extract.c to shrinkwrap the extracted mesh to the sculpt */
+void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C,
+ struct Object *ob_source,
+ struct Object *ob_target);
+
+/* Used in object_remesh.c to preserve the details and volume in the voxel remesher */
+void BKE_shrinkwrap_remesh_target_project(struct Mesh *src_me,
+ struct Mesh *target_me,
+ struct Object *ob_target);
+
/*
* This function casts a ray in the given BVHTree.
* but it takes into consideration the space_transform, that is:
diff --git a/source/blender/blenkernel/BKE_studiolight.h b/source/blender/blenkernel/BKE_studiolight.h
index d6fff528348..c6d1e61fb47 100644
--- a/source/blender/blenkernel/BKE_studiolight.h
+++ b/source/blender/blenkernel/BKE_studiolight.h
@@ -26,14 +26,13 @@
* Studio lighting for the 3dview
*/
-#include "BKE_context.h"
-
#include "BLI_sys_types.h"
-#include "DNA_space_types.h"
+#include "BLI_path_util.h"
+
#include "DNA_userdef_types.h"
-#include "IMB_imbuf_types.h"
+struct ImBuf;
/*
* These defines are the indexes in the StudioLight.diffuse_light
@@ -87,6 +86,11 @@ enum StudioLightFlag {
STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED = (1 << 11),
STUDIOLIGHT_USER_DEFINED = (1 << 12),
STUDIOLIGHT_UI_EXPANDED = (1 << 13),
+
+ STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE = (1 << 14),
+ STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE = (1 << 15),
+ /* Is set for studio lights and matcaps with specular highlight pass. */
+ STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS = (1 << 16),
};
#define STUDIOLIGHT_FLAG_ALL (STUDIOLIGHT_INTERNAL | STUDIOLIGHT_EXTERNAL_FILE)
@@ -97,6 +101,11 @@ enum StudioLightFlag {
typedef void StudioLightFreeFunction(struct StudioLight *, void *data);
+typedef struct StudioLightImage {
+ struct ImBuf *ibuf;
+ struct GPUTexture *gputexture;
+} StudioLightImage;
+
typedef struct StudioLight {
struct StudioLight *next, *prev;
@@ -112,9 +121,11 @@ typedef struct StudioLight {
int icon_id_matcap_flipped;
float spherical_harmonics_coefs[STUDIOLIGHT_SH_EFFECTIVE_COEFS_LEN][3];
float light_direction[3];
- ImBuf *equirect_radiance_buffer;
- ImBuf *equirect_irradiance_buffer;
- ImBuf *radiance_cubemap_buffers[6];
+ StudioLightImage matcap_diffuse;
+ StudioLightImage matcap_specular;
+ struct ImBuf *equirect_radiance_buffer;
+ struct ImBuf *equirect_irradiance_buffer;
+ struct ImBuf *radiance_cubemap_buffers[6];
struct GPUTexture *equirect_radiance_gputexture;
struct GPUTexture *equirect_irradiance_gputexture;
SolidLight light[STUDIOLIGHT_MAX_LIGHT];
diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h
index 700bf5139e0..267a03da25c 100644
--- a/source/blender/blenkernel/BKE_subdiv.h
+++ b/source/blender/blenkernel/BKE_subdiv.h
@@ -140,7 +140,7 @@ typedef struct SubdivDisplacement {
/* This structure contains everything needed to construct subdivided surface.
* It does not specify storage, memory layout or anything else.
- * It is possible to create different storages (like, grid based CPU side
+ * It is possible to create different storage's (like, grid based CPU side
* buffers, GPU subdivision mesh, CPU side fully qualified mesh) from the same
* Subdiv structure. */
typedef struct Subdiv {
diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h
index 2e9ccb8b39d..e235193a486 100644
--- a/source/blender/blenkernel/BKE_subdiv_ccg.h
+++ b/source/blender/blenkernel/BKE_subdiv_ccg.h
@@ -150,7 +150,7 @@ typedef struct SubdivCCG {
struct CCGElem **edges;
int num_edges;
/* Loose vertices. Every element corresponds to a loose vertex from a coarse
- * mesh, every coarse loose vertex corresponds to a single sundivided
+ * mesh, every coarse loose vertex corresponds to a single subdivided
* element. */
struct CCGElem *vertices;
int num_vertices;
diff --git a/source/blender/blenkernel/BKE_subdiv_deform.h b/source/blender/blenkernel/BKE_subdiv_deform.h
new file mode 100644
index 00000000000..f1a56aa9cde
--- /dev/null
+++ b/source/blender/blenkernel/BKE_subdiv_deform.h
@@ -0,0 +1,40 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifndef __BKE_SUBDIV_DEFORM_H__
+#define __BKE_SUBDIV_DEFORM_H__
+
+#include "BLI_sys_types.h"
+
+struct Mesh;
+struct Subdiv;
+
+/* Special version of subdivision surface which calculates final positions for coarse vertices.
+ *
+ * vertex_cos are supposed to hold coordinates of the coarse mesh. */
+void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv,
+ const struct Mesh *coarse_mesh,
+ float (*vertex_cos)[3],
+ int num_verts);
+
+#endif /* __BKE_SUBDIV_DEFORM_H__ */
diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h
index 1d794e4d61a..c8d672c2524 100644
--- a/source/blender/blenkernel/BKE_subdiv_eval.h
+++ b/source/blender/blenkernel/BKE_subdiv_eval.h
@@ -31,7 +31,12 @@ struct Subdiv;
/* Returns true if evaluator is ready for use. */
bool BKE_subdiv_eval_begin(struct Subdiv *subdiv);
-bool BKE_subdiv_eval_update_from_mesh(struct Subdiv *subdiv, const struct Mesh *mesh);
+
+/* coarse_vertex_cos is an optional argument which allows to override coordinates of the coarse
+ * mesh. */
+bool BKE_subdiv_eval_update_from_mesh(struct Subdiv *subdiv,
+ const struct Mesh *mesh,
+ const float (*coarse_vertex_cos)[3]);
/* Makes sure displacement evaluator is initialized.
*
diff --git a/source/blender/blenkernel/BKE_subdiv_topology.h b/source/blender/blenkernel/BKE_subdiv_topology.h
new file mode 100644
index 00000000000..dd057d88fb6
--- /dev/null
+++ b/source/blender/blenkernel/BKE_subdiv_topology.h
@@ -0,0 +1,31 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifndef __BKE_SUBDIV_TOPOLOGY_H__
+#define __BKE_SUBDIV_TOPOLOGY_H__
+
+struct Subdiv;
+
+int BKE_subdiv_topology_num_fvar_layers_get(const struct Subdiv *subdiv);
+
+#endif /* __BKE_SUBDIV_TOPOLOGY_H__ */
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 669abff6599..47b44c3828a 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -50,6 +50,9 @@ set(INC
../../../intern/opensubdiv
../../../extern/curve_fit_nd
../../../intern/smoke/extern
+
+ # dna_type_offsets.h
+ ${CMAKE_CURRENT_BINARY_DIR}/../makesdna/intern
)
set(INC_SYS
@@ -83,6 +86,7 @@ set(SRC
intern/brush.c
intern/bvhutils.c
intern/cachefile.c
+ intern/callbacks.c
intern/camera.c
intern/cdderivedmesh.c
intern/cloth.c
@@ -155,6 +159,7 @@ set(SRC
intern/mesh_runtime.c
intern/mesh_tangent.c
intern/mesh_validate.c
+ intern/mirror.c
intern/modifier.c
intern/movieclip.c
intern/multires.c
@@ -186,6 +191,7 @@ set(SRC
intern/seqcache.c
intern/seqeffects.c
intern/seqmodifier.c
+ intern/seqprefetch.c
intern/sequencer.c
intern/shader_fx.c
intern/shrinkwrap.c
@@ -200,12 +206,14 @@ set(SRC
intern/subdiv_ccg_material.c
intern/subdiv_converter.c
intern/subdiv_converter_mesh.c
+ intern/subdiv_deform.c
intern/subdiv_displacement.c
intern/subdiv_displacement_multires.c
intern/subdiv_eval.c
intern/subdiv_foreach.c
intern/subdiv_mesh.c
intern/subdiv_stats.c
+ intern/subdiv_topology.c
intern/subsurf_ccg.c
intern/suggestions.c
intern/text.c
@@ -243,6 +251,7 @@ set(SRC
BKE_brush.h
BKE_bvhutils.h
BKE_cachefile.h
+ BKE_callbacks.h
BKE_camera.h
BKE_ccg.h
BKE_cdderivedmesh.h
@@ -304,6 +313,7 @@ set(SRC
BKE_mesh_remesh_voxel.h
BKE_mesh_runtime.h
BKE_mesh_tangent.h
+ BKE_mirror.h
BKE_modifier.h
BKE_movieclip.h
BKE_multires.h
@@ -333,9 +343,11 @@ set(SRC
BKE_studiolight.h
BKE_subdiv.h
BKE_subdiv_ccg.h
+ BKE_subdiv_deform.h
BKE_subdiv_eval.h
BKE_subdiv_foreach.h
BKE_subdiv_mesh.h
+ BKE_subdiv_topology.h
BKE_subsurf.h
BKE_suggestions.h
BKE_text.h
@@ -615,9 +627,22 @@ if(WITH_OPENVDB)
endif()
endif()
+if(WITH_QUADRIFLOW)
+ list(APPEND INC
+ ../../../intern/quadriflow
+ )
+ list(APPEND LIB
+ bf_intern_quadriflow
+ )
+ add_definitions(-DWITH_QUADRIFLOW)
+endif()
+
## Warnings as errors, this is too strict!
#if(MSVC)
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
#endif()
blender_add_lib(bf_blenkernel "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+# Needed so we can use dna_type_offsets.h for defaults initialization.
+add_dependencies(bf_blenkernel bf_dna)
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
index 973d5415567..699075f6cff 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
@@ -697,7 +697,7 @@ static void opensubdiv_evaluateNGonFaceGrids(CCGSubSurf *ss,
int x, S0 = 0, S1 = 0;
bool flip;
- for (x = 0; x < face->numVerts; ++x) {
+ for (x = 0; x < face->numVerts; x++) {
if (all_verts[x] == edge->v0) {
S0 = x;
}
@@ -806,7 +806,7 @@ void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, DerivedMesh *dm)
const MPoly *mpoly = dm->getPolyArray(dm);
int poly;
ss->numGrids = 0;
- for (poly = 0; poly < num_polys; ++poly) {
+ for (poly = 0; poly < num_polys; poly++) {
ss->numGrids += mpoly[poly].totloop;
}
}
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
index eb04d13d4a0..e77b65eca25 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
@@ -172,7 +172,7 @@ static int conv_dm_get_num_edge_faces(const OpenSubdiv_Converter *converter, int
for (loop = 0; loop < mpoly->totloop; loop++) {
const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
if (mloop->e == edge) {
- ++num;
+ num++;
break;
}
}
@@ -226,7 +226,7 @@ static int conv_dm_get_num_vert_edges(const OpenSubdiv_Converter *converter, int
for (edge = 0; edge < dm->getNumEdges(dm); edge++) {
const MEdge *medge = &user_data->medge[edge];
if (medge->v1 == vert || medge->v2 == vert) {
- ++num;
+ num++;
}
}
return num;
@@ -268,7 +268,7 @@ static int conv_dm_get_num_vert_faces(const OpenSubdiv_Converter *converter, int
for (loop = 0; loop < mpoly->totloop; loop++) {
const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
if (mloop->v == vert) {
- ++num;
+ num++;
break;
}
}
@@ -357,23 +357,23 @@ static void conv_dm_precalc_uv_layer(const OpenSubdiv_Converter *converter, int
* The idea here is that we need to pass individual islands to OpenSubdiv.
*/
storage->num_uvs = 0;
- for (int island = 0; island < storage->island_store.islands_num; ++island) {
+ for (int island = 0; island < storage->island_store.islands_num; island++) {
MeshElemMap *island_poly_map = storage->island_store.islands[island];
- for (int poly = 0; poly < island_poly_map->count; ++poly) {
+ for (int poly = 0; poly < island_poly_map->count; poly++) {
int poly_index = island_poly_map->indices[poly];
/* Within the same UV island we should share UV points across
* loops. Otherwise each poly will be subdivided individually
* which we don't really want.
*/
const MPoly *mpoly = &storage->mpoly[poly_index];
- for (int loop = 0; loop < mpoly->totloop; ++loop) {
+ for (int loop = 0; loop < mpoly->totloop; loop++) {
const MLoopUV *luv = &mloopuv[mpoly->loopstart + loop];
bool found = false;
/* TODO(sergey): Quite bad loop, which gives us O(N^2)
* complexity here. But how can we do it smarter, hopefully
* without requiring lots of additional memory.
*/
- for (int i = 0; i < storage->num_uvs; ++i) {
+ for (int i = 0; i < storage->num_uvs; i++) {
if (equals_v2v2(luv->uv, &storage->uvs[2 * i])) {
storage->face_uvs[mpoly->loopstart + loop] = i;
found = true;
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 010e162f49d..4849d631493 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -729,7 +729,7 @@ static Mesh *create_orco_mesh(Object *ob, Mesh *me, BMEditMesh *em, int layer)
int free;
if (em) {
- mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL);
+ mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, me);
}
else {
mesh = BKE_mesh_copy_for_eval(me, true);
@@ -797,14 +797,6 @@ static void editmesh_update_statvis_color(const Scene *scene, Object *ob)
BKE_editmesh_statvis_calc(em, me->runtime.edit_data, &scene->toolsettings->statvis);
}
-static void mesh_copy_autosmooth(Mesh *me, Mesh *me_orig)
-{
- if (me_orig->flag & ME_AUTOSMOOTH) {
- me->flag |= ME_AUTOSMOOTH;
- me->smoothresh = me_orig->smoothresh;
- }
-}
-
static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
const CustomData_MeshMasks *final_datamask,
const bool sculpt_dyntopo,
@@ -881,18 +873,8 @@ static void mesh_calc_finalize(const Mesh *mesh_input, Mesh *mesh_eval)
/* Make sure the name is the same. This is because mesh allocation from template does not
* take care of naming. */
BLI_strncpy(mesh_eval->id.name, mesh_input->id.name, sizeof(mesh_eval->id.name));
- /* Make sure materials are preserved from the input. */
- if (mesh_eval->mat != NULL) {
- MEM_freeN(mesh_eval->mat);
- }
- mesh_eval->mat = MEM_dupallocN(mesh_input->mat);
- mesh_eval->totcol = mesh_input->totcol;
/* Make evaluated mesh to share same edit mesh pointer as original and copied meshes. */
mesh_eval->edit_mesh = mesh_input->edit_mesh;
- /* Copy auth-smooth settings which are also not taken care about by mesh allocation from a
- * template. */
- mesh_eval->flag |= (mesh_input->flag & ME_AUTOSMOOTH);
- mesh_eval->smoothresh = mesh_input->smoothresh;
}
static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
@@ -1220,8 +1202,6 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
MEM_freeN(deformed_verts);
deformed_verts = NULL;
}
-
- mesh_copy_autosmooth(mesh_final, mesh_input);
}
/* create an orco mesh in parallel */
@@ -1533,8 +1513,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Evaluate modifiers up to certain index to get the mesh cage. */
int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
if (r_cage && cageIndex == -1) {
- mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(em_input, &final_datamask, NULL);
- mesh_copy_autosmooth(mesh_cage, mesh_input);
+ mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(
+ em_input, &final_datamask, NULL, mesh_input);
}
/* Clear errors before evaluation. */
@@ -1574,9 +1554,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
if (mesh_final == NULL) {
- mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL);
+ mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL, mesh_input);
ASSERT_IS_VALID_MESH(mesh_final);
- mesh_copy_autosmooth(mesh_final, mesh_input);
}
BLI_assert(deformed_verts != NULL);
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
@@ -1607,11 +1586,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
}
else {
- mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL);
+ mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL, mesh_input);
ASSERT_IS_VALID_MESH(mesh_final);
- mesh_copy_autosmooth(mesh_final, mesh_input);
-
if (deformed_verts) {
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
}
@@ -1674,8 +1651,6 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
MEM_freeN(deformed_verts);
deformed_verts = NULL;
}
-
- mesh_copy_autosmooth(mesh_final, mesh_input);
}
mesh_final->runtime.deformed_only = false;
}
@@ -1695,8 +1670,10 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
me_orig->runtime.edit_data->vertexCos = MEM_dupallocN(deformed_verts);
}
mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(
- em_input, &final_datamask, deformed_verts ? MEM_dupallocN(deformed_verts) : NULL);
- mesh_copy_autosmooth(mesh_cage, mesh_input);
+ em_input,
+ &final_datamask,
+ deformed_verts ? MEM_dupallocN(deformed_verts) : NULL,
+ mesh_input);
}
}
@@ -1730,11 +1707,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
else {
/* this is just a copy of the editmesh, no need to calc normals */
mesh_final = BKE_mesh_from_editmesh_with_coords_thin_wrap(
- em_input, &final_datamask, deformed_verts);
+ em_input, &final_datamask, deformed_verts, mesh_input);
deformed_verts = NULL;
- mesh_copy_autosmooth(mesh_final, mesh_input);
-
/* In this case, we should never have weight-modifying modifiers in stack... */
if (do_init_statvis) {
editmesh_update_statvis_color(scene, ob);
@@ -1854,11 +1829,6 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
&ob->runtime.mesh_eval);
BKE_object_boundbox_calc_from_mesh(ob, ob->runtime.mesh_eval);
- /* Only copy texspace from orig mesh if some modifier (hint: smoke sim, see T58492)
- * did not re-enable that flag (which always get disabled for eval mesh as a start). */
- if (!(ob->runtime.mesh_eval->texflag & ME_AUTOSPACE)) {
- BKE_mesh_texspace_copy_from_object(ob->runtime.mesh_eval, ob);
- }
assign_object_mesh_eval(ob);
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index ab8ea37377d..2e655452a21 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -305,8 +305,9 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
/* make a copy of action - at worst, user has to delete copies... */
if (do_action) {
BLI_assert(bmain != NULL);
- BKE_id_copy(bmain, (ID *)dadt->action, (ID **)&dadt->action);
- BKE_id_copy(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact);
+ BLI_assert(dadt->action == NULL || dadt->action != dadt->tmpact);
+ BKE_id_copy_ex(bmain, (ID *)dadt->action, (ID **)&dadt->action, flag);
+ BKE_id_copy_ex(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact, flag);
}
else if (do_id_user) {
id_us_plus((ID *)dadt->action);
@@ -4081,11 +4082,10 @@ void BKE_animsys_update_driver_array(ID *id)
}
}
-void BKE_animsys_eval_driver(Depsgraph *depsgraph,
- ID *id,
- int driver_index,
- ChannelDriver *driver_orig)
+void BKE_animsys_eval_driver(Depsgraph *depsgraph, ID *id, int driver_index, FCurve *fcu_orig)
{
+ BLI_assert(fcu_orig != NULL);
+
/* TODO(sergey): De-duplicate with BKE animsys. */
PointerRNA id_ptr;
bool ok = false;
@@ -4110,6 +4110,7 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph,
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
/* check if driver itself is tagged for recalculation */
/* XXX driver recalc flag is not set yet by depsgraph! */
+ ChannelDriver *driver_orig = fcu_orig->driver;
if ((driver_orig) && !(driver_orig->flag & DRIVER_FLAG_INVALID)) {
/* evaluate this using values set already in other places
* NOTE: for 'layering' option later on, we should check if we should remove old value before
@@ -4120,7 +4121,7 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph,
if (animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
/* Evaluate driver, and write results to COW-domain destination */
const float ctime = DEG_get_ctime(depsgraph);
- const float curval = evaluate_fcurve_driver(&anim_rna, fcu, driver_orig, ctime);
+ const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
ok = animsys_write_rna_setting(&anim_rna, curval);
/* Flush results & status codes to original data for UI (T59984) */
@@ -4128,6 +4129,7 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph,
animsys_write_orig_anim_rna(&id_ptr, fcu->rna_path, fcu->array_index, curval);
/* curval is displayed in the UI, and flag contains error-status codes */
+ fcu_orig->curval = fcu->curval;
driver_orig->curval = fcu->driver->curval;
driver_orig->flag = fcu->driver->flag;
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index 3b64a9520ca..fbac9e6b773 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -110,7 +110,7 @@ const char *BKE_appdir_folder_default(void)
// #define PATH_DEBUG
-/* returns a formatted representation of the specified version number. Non-reentrant! */
+/* returns a formatted representation of the specified version number. Non-re-entrant! */
static char *blender_version_decimal(const int ver)
{
static char version_str[5];
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 168422a4454..3215b3d7b40 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -1005,9 +1005,9 @@ void BKE_pchan_bbone_handles_compute(const BBoneSplineParameters *param,
}
static void make_bbone_spline_matrix(BBoneSplineParameters *param,
- float scalemats[2][4][4],
- float pos[3],
- float axis[3],
+ const float scalemats[2][4][4],
+ const float pos[3],
+ const float axis[3],
float roll,
float scalex,
float scaley,
@@ -1257,9 +1257,9 @@ void BKE_pchan_bbone_deform_segment_index(const bPoseChannel *pchan,
float pre_blend = pos * (float)segments;
int index = (int)floorf(pre_blend);
- float blend = pre_blend - index;
+ CLAMP(index, 0, segments - 1);
- CLAMP(index, 0, segments);
+ float blend = pre_blend - index;
CLAMP(blend, 0.0f, 1.0f);
*r_index = index;
@@ -1867,11 +1867,16 @@ void BKE_bone_parent_transform_calc_from_pchan(const bPoseChannel *pchan,
/* yoffs(b-1) + root(b) + bonemat(b). */
BKE_bone_offset_matrix_get(bone, offs_bone);
- BKE_bone_parent_transform_calc_from_matrices(
- bone->flag, offs_bone, parbone->arm_mat, parchan->pose_mat, r_bpt);
+ BKE_bone_parent_transform_calc_from_matrices(bone->flag,
+ bone->inherit_scale_mode,
+ offs_bone,
+ parbone->arm_mat,
+ parchan->pose_mat,
+ r_bpt);
}
else {
- BKE_bone_parent_transform_calc_from_matrices(bone->flag, bone->arm_mat, NULL, NULL, r_bpt);
+ BKE_bone_parent_transform_calc_from_matrices(
+ bone->flag, bone->inherit_scale_mode, bone->arm_mat, NULL, NULL, r_bpt);
}
}
@@ -1882,39 +1887,90 @@ void BKE_bone_parent_transform_calc_from_pchan(const bPoseChannel *pchan,
* parent_arm_mat, parent_pose_mat: arm_mat and pose_mat of parent, or NULL
* r_bpt: OUTPUT parent transform */
void BKE_bone_parent_transform_calc_from_matrices(int bone_flag,
+ int inherit_scale_mode,
const float offs_bone[4][4],
const float parent_arm_mat[4][4],
const float parent_pose_mat[4][4],
BoneParentTransform *r_bpt)
{
if (parent_pose_mat) {
+ const bool use_rotation = (bone_flag & BONE_HINGE) == 0;
+ const bool full_transform = use_rotation && inherit_scale_mode == BONE_INHERIT_SCALE_FULL;
+
/* Compose the rotscale matrix for this bone. */
- if ((bone_flag & BONE_HINGE) && (bone_flag & BONE_NO_SCALE)) {
- /* Parent rest rotation and scale. */
- mul_m4_m4m4(r_bpt->rotscale_mat, parent_arm_mat, offs_bone);
+ if (full_transform) {
+ /* Parent pose rotation and scale. */
+ mul_m4_m4m4(r_bpt->rotscale_mat, parent_pose_mat, offs_bone);
}
- else if (bone_flag & BONE_HINGE) {
- /* Parent rest rotation and pose scale. */
+ else {
float tmat[4][4], tscale[3];
- /* Extract the scale of the parent pose matrix. */
- mat4_to_size(tscale, parent_pose_mat);
- size_to_mat4(tmat, tscale);
+ /* If using parent pose rotation: */
+ if (use_rotation) {
+ copy_m4_m4(tmat, parent_pose_mat);
+
+ /* Normalize the matrix when needed. */
+ switch (inherit_scale_mode) {
+ case BONE_INHERIT_SCALE_FULL:
+ case BONE_INHERIT_SCALE_FIX_SHEAR:
+ /* Keep scale and shear. */
+ break;
+
+ case BONE_INHERIT_SCALE_NONE:
+ case BONE_INHERIT_SCALE_AVERAGE:
+ /* Remove scale and shear from parent. */
+ orthogonalize_m4_stable(tmat, 1, true);
+ break;
+
+ case BONE_INHERIT_SCALE_NONE_LEGACY:
+ /* Remove only scale - bad legacy way. */
+ normalize_m4(tmat);
+ break;
+
+ default:
+ BLI_assert(false);
+ }
+ }
+ /* If removing parent pose rotation: */
+ else {
+ copy_m4_m4(tmat, parent_arm_mat);
+
+ /* Copy the parent scale when needed. */
+ switch (inherit_scale_mode) {
+ case BONE_INHERIT_SCALE_FULL:
+ /* Ignore effects of shear. */
+ mat4_to_size(tscale, parent_pose_mat);
+ rescale_m4(tmat, tscale);
+ break;
+
+ case BONE_INHERIT_SCALE_FIX_SHEAR:
+ /* Take the effects of parent shear into account to get exact volume. */
+ mat4_to_size_fix_shear(tscale, parent_pose_mat);
+ rescale_m4(tmat, tscale);
+ break;
+
+ case BONE_INHERIT_SCALE_NONE:
+ case BONE_INHERIT_SCALE_AVERAGE:
+ case BONE_INHERIT_SCALE_NONE_LEGACY:
+ /* Keep unscaled. */
+ break;
+
+ default:
+ BLI_assert(false);
+ }
+ }
- /* Applies the parent pose scale to the rest matrix. */
- mul_m4_m4m4(tmat, tmat, parent_arm_mat);
+ /* Apply the average parent scale when needed. */
+ if (inherit_scale_mode == BONE_INHERIT_SCALE_AVERAGE) {
+ mul_mat3_m4_fl(tmat, cbrtf(fabsf(mat4_to_volume_scale(parent_pose_mat))));
+ }
mul_m4_m4m4(r_bpt->rotscale_mat, tmat, offs_bone);
- }
- else if (bone_flag & BONE_NO_SCALE) {
- /* Parent pose rotation and rest scale (i.e. no scaling). */
- float tmat[4][4];
- copy_m4_m4(tmat, parent_pose_mat);
- normalize_m4(tmat);
- mul_m4_m4m4(r_bpt->rotscale_mat, tmat, offs_bone);
- }
- else {
- mul_m4_m4m4(r_bpt->rotscale_mat, parent_pose_mat, offs_bone);
+
+ /* Remove remaining shear when needed, preserving volume. */
+ if (inherit_scale_mode == BONE_INHERIT_SCALE_FIX_SHEAR) {
+ orthogonalize_m4_stable(r_bpt->rotscale_mat, 1, false);
+ }
}
/* Compose the loc matrix for this bone. */
@@ -1938,7 +1994,7 @@ void BKE_bone_parent_transform_calc_from_matrices(int bone_flag,
mul_m4_m4m4(r_bpt->loc_mat, bone_loc, tmat4);
}
/* Those flags do not affect position, use plain parent transform space! */
- else if (bone_flag & (BONE_HINGE | BONE_NO_SCALE)) {
+ else if (!full_transform) {
mul_m4_m4m4(r_bpt->loc_mat, parent_pose_mat, offs_bone);
}
/* Else (i.e. default, usual case),
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index 805c098d238..ac432bf0b64 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -32,7 +32,6 @@
#include "BLI_string.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
-#include "BLI_callbacks.h"
#include "IMB_imbuf.h"
#include "IMB_moviecache.h"
@@ -44,6 +43,7 @@
#include "BKE_blendfile.h"
#include "BKE_brush.h"
#include "BKE_cachefile.h"
+#include "BKE_callbacks.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
@@ -95,7 +95,7 @@ void BKE_blender_free(void)
BKE_brush_system_exit();
RE_texture_rng_exit();
- BLI_callback_global_finalize();
+ BKE_callback_global_finalize();
IMB_moviecache_destruct();
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index b2d3ccfebc3..4187dfa68ad 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -24,7 +24,9 @@
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_defaults.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rand.h"
@@ -35,6 +37,7 @@
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
#include "BKE_main.h"
+#include "BKE_material.h"
#include "BKE_paint.h"
#include "BKE_texture.h"
#include "BKE_icons.h"
@@ -60,73 +63,48 @@ void BKE_brush_system_exit(void)
static void brush_defaults(Brush *brush)
{
- brush->blend = 0;
- brush->flag = 0;
-
- brush->ob_mode = OB_MODE_ALL_PAINT;
-
- /* BRUSH SCULPT TOOL SETTINGS */
- brush->weight = 1.0f; /* weight of brush 0 - 1.0 */
- brush->size = 35; /* radius of the brush in pixels */
- brush->alpha = 0.5f; /* brush strength/intensity probably variable should be renamed? */
- brush->autosmooth_factor = 0.0f;
- brush->topology_rake_factor = 0.0f;
- brush->crease_pinch_factor = 0.5f;
- brush->sculpt_plane = SCULPT_DISP_DIR_AREA;
- /* How far above or below the plane that is found by averaging the faces. */
- brush->plane_offset = 0.0f;
- brush->plane_trim = 0.5f;
- brush->clone.alpha = 0.5f;
- brush->normal_weight = 0.0f;
- brush->fill_threshold = 0.2f;
- brush->flag |= BRUSH_ALPHA_PRESSURE;
-
- /* BRUSH PAINT TOOL SETTINGS */
- /* Default rgb color of the brush when painting - white. */
- brush->rgb[0] = 1.0f;
- brush->rgb[1] = 1.0f;
- brush->rgb[2] = 1.0f;
-
- zero_v3(brush->secondary_rgb);
-
- /* BRUSH STROKE SETTINGS */
- brush->flag |= (BRUSH_SPACE | BRUSH_SPACE_ATTEN);
- /* How far each brush dot should be spaced as a percentage of brush diameter. */
- brush->spacing = 10;
-
- brush->smooth_stroke_radius = 75;
- brush->smooth_stroke_factor = 0.9f;
-
- /* Time delay between dots of paint or sculpting when doing airbrush mode. */
- brush->rate = 0.1f;
-
- brush->jitter = 0.0f;
-
- /* BRUSH TEXTURE SETTINGS */
- BKE_texture_mtex_default(&brush->mtex);
- BKE_texture_mtex_default(&brush->mask_mtex);
-
- brush->texture_sample_bias = 0; /* value to added to texture samples */
- brush->texture_overlay_alpha = 33;
- brush->mask_overlay_alpha = 33;
- brush->cursor_overlay_alpha = 33;
- brush->overlay_flags = 0;
-
- /* brush appearance */
-
- brush->add_col[0] = 1.00; /* add mode color is light red */
- brush->add_col[1] = 0.39;
- brush->add_col[2] = 0.39;
-
- brush->sub_col[0] = 0.39; /* subtract mode color is light blue */
- brush->sub_col[1] = 0.39;
- brush->sub_col[2] = 1.00;
-
- brush->stencil_pos[0] = 256;
- brush->stencil_pos[1] = 256;
-
- brush->stencil_dimension[0] = 256;
- brush->stencil_dimension[1] = 256;
+
+ const Brush *brush_def = DNA_struct_default_get(Brush);
+
+#define FROM_DEFAULT(member) memcpy(&brush->member, &brush_def->member, sizeof(brush->member))
+#define FROM_DEFAULT_PTR(member) memcpy(brush->member, brush_def->member, sizeof(brush->member))
+
+ FROM_DEFAULT(blend);
+ FROM_DEFAULT(flag);
+ FROM_DEFAULT(weight);
+ FROM_DEFAULT(size);
+ FROM_DEFAULT(alpha);
+ FROM_DEFAULT(autosmooth_factor);
+ FROM_DEFAULT(topology_rake_factor);
+ FROM_DEFAULT(crease_pinch_factor);
+ FROM_DEFAULT(normal_radius_factor);
+ FROM_DEFAULT(sculpt_plane);
+ FROM_DEFAULT(plane_offset);
+ FROM_DEFAULT(clone.alpha);
+ FROM_DEFAULT(normal_weight);
+ FROM_DEFAULT(fill_threshold);
+ FROM_DEFAULT(flag);
+ FROM_DEFAULT_PTR(rgb);
+ FROM_DEFAULT_PTR(secondary_rgb);
+ FROM_DEFAULT(spacing);
+ FROM_DEFAULT(smooth_stroke_radius);
+ FROM_DEFAULT(smooth_stroke_factor);
+ FROM_DEFAULT(rate);
+ FROM_DEFAULT(jitter);
+ FROM_DEFAULT(texture_sample_bias);
+ FROM_DEFAULT(texture_overlay_alpha);
+ FROM_DEFAULT(mask_overlay_alpha);
+ FROM_DEFAULT(cursor_overlay_alpha);
+ FROM_DEFAULT(overlay_flags);
+ FROM_DEFAULT_PTR(add_col);
+ FROM_DEFAULT_PTR(sub_col);
+ FROM_DEFAULT(stencil_pos);
+ FROM_DEFAULT(stencil_dimension);
+ FROM_DEFAULT(mtex);
+ FROM_DEFAULT(mask_mtex);
+
+#undef FROM_DEFAULT
+#undef FROM_DEFAULT_PTR
}
/* Datablock add/copy/free/make_local */
@@ -135,16 +113,11 @@ void BKE_brush_init(Brush *brush)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(brush, id));
+ MEMCPY_STRUCT_AFTER(brush, DNA_struct_default_get(Brush), id);
+
/* enable fake user by default */
id_fake_user_set(&brush->id);
- brush_defaults(brush);
-
- brush->sculpt_tool = SCULPT_TOOL_DRAW; /* sculpting defaults to the draw tool for new brushes */
-
- /* A kernel radius of 1 has almost no effect (T63233). */
- brush->blur_kernel_radius = 2;
-
/* the default alpha falloff curve */
BKE_brush_curve_preset(brush, CURVE_PRESET_SMOOTH);
}
@@ -268,306 +241,383 @@ static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset)
}
}
-/* create a set of grease pencil presets */
-void BKE_brush_gpencil_presets(bContext *C)
+/* create a set of grease pencil presets. */
+void BKE_brush_gpencil_presets(Main *bmain, ToolSettings *ts)
{
#define SMOOTH_STROKE_RADIUS 40
#define SMOOTH_STROKE_FACTOR 0.9f
- ToolSettings *ts = CTX_data_tool_settings(C);
Paint *paint = &ts->gp_paint->paint;
- Main *bmain = CTX_data_main(C);
Brush *brush, *deft;
CurveMapping *custom_curve;
- /* Pencil brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pencil");
- brush->size = 25.0f;
+ /* Airbrush brush. */
+ brush = BLI_findstring(&bmain->brushes, "Airbrush", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Airbrush");
+ }
+
+ brush->size = 300.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.0f;
- brush->gpencil_settings->draw_strength = 0.6f;
+ brush->gpencil_settings->draw_strength = 0.4f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
- brush->gpencil_settings->draw_random_press = 0.0f;
-
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.98f;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
+ brush->gpencil_settings->gradient_f = 0.211f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
+
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
- brush->gpencil_settings->draw_smoothfac = 0.1f;
- brush->gpencil_settings->draw_smoothlvl = 1;
- brush->gpencil_settings->thick_smoothfac = 1.0f;
- brush->gpencil_settings->thick_smoothlvl = 3;
- brush->gpencil_settings->draw_subdivide = 1;
- brush->gpencil_settings->draw_random_sub = 0.0f;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL;
brush->gpencil_tool = GPAINT_TOOL_DRAW;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_AIRBRUSH;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Pen brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pen");
- deft = brush; /* save default brush */
- brush->size = 30.0f;
+ /* Create and link Black Dots material to brush.
+ * This material is required because the brush uses the material to define how the stroke is
+ * drawn. */
+ Material *ma = BLI_findstring(&bmain->materials, "Black Dots", offsetof(ID, name) + 2);
+ if (ma == NULL) {
+ ma = BKE_material_add_gpencil(bmain, "Black Dots");
+ }
+ brush->gpencil_settings->material = ma;
+ /* Pin the matterial to the brush. */
+ brush->gpencil_settings->flag |= GP_BRUSH_MATERIAL_PINNED;
+
+ /* Ink Pen brush. */
+ brush = BLI_findstring(&bmain->brushes, "Ink Pen", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Ink Pen");
+ }
+ brush->size = 60.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.0f;
brush->gpencil_settings->draw_strength = 1.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
-
- brush->gpencil_settings->draw_random_press = 0.0f;
- brush->gpencil_settings->draw_random_strength = 0.0f;
-
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.7f;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
brush->gpencil_settings->draw_smoothfac = 0.1f;
brush->gpencil_settings->draw_smoothlvl = 1;
- brush->gpencil_settings->draw_subdivide = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 0;
brush->gpencil_settings->draw_random_sub = 0.0f;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
- brush->gpencil_tool = GPAINT_TOOL_DRAW;
-
- brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
- brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
-
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Ink brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Ink");
- brush->size = 60.0f;
- brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.6f;
-
- brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->simplify_f = 0.002f;
brush->gpencil_settings->draw_random_press = 0.0f;
-
brush->gpencil_settings->draw_jitter = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
- brush->gpencil_settings->draw_angle = 0.0f;
- brush->gpencil_settings->draw_angle_factor = 0.0f;
+ /* Curve. */
+ custom_curve = brush->gpencil_settings->curve_sensitivity;
+ BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
+ BKE_curvemapping_initialize(custom_curve);
+ brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INK);
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
- brush->gpencil_settings->draw_smoothfac = 0.1f;
- brush->gpencil_settings->draw_smoothlvl = 1;
- brush->gpencil_settings->thick_smoothfac = 1.0f;
- brush->gpencil_settings->thick_smoothlvl = 3;
- brush->gpencil_settings->draw_subdivide = 1;
- brush->gpencil_settings->draw_random_sub = 0.0f;
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INK;
brush->gpencil_tool = GPAINT_TOOL_DRAW;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Curve */
- custom_curve = brush->gpencil_settings->curve_sensitivity;
- BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
- BKE_curvemapping_initialize(custom_curve);
- brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INK);
+ /* Ink Pen Rough brush. */
+ brush = BLI_findstring(&bmain->brushes, "Ink Pen Rough", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Ink Pen Rough");
+ }
- /* Ink Noise brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Noise");
brush->size = 60.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.0f;
brush->gpencil_settings->draw_strength = 1.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
- brush->gpencil_settings->draw_random_press = 0.7f;
- brush->gpencil_settings->draw_random_strength = 0.0f;
-
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.5f;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
- brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.0f;
brush->gpencil_settings->draw_smoothlvl = 2;
- brush->gpencil_settings->thick_smoothfac = 0.5f;
+ brush->gpencil_settings->thick_smoothfac = 0.0f;
brush->gpencil_settings->thick_smoothlvl = 2;
- brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_subdivide = 0;
brush->gpencil_settings->draw_random_sub = 0.0f;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE;
- brush->gpencil_tool = GPAINT_TOOL_DRAW;
+ brush->gpencil_settings->simplify_f = 0.000f;
- brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
- brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
+ brush->gpencil_settings->draw_random_press = 1.0f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
- /* Curve */
+ /* Curve. */
custom_curve = brush->gpencil_settings->curve_sensitivity;
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemapping_initialize(custom_curve);
brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INKNOISE);
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Block Basic brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Block");
- brush->size = 150.0f;
- brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
- brush->gpencil_settings->draw_strength = 1.0f;
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- brush->gpencil_settings->draw_random_press = 0.0f;
+ /* Marker Bold brush. */
+ brush = BLI_findstring(&bmain->brushes, "Marker Bold", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Marker Bold");
+ }
+ brush->size = 150.0f;
+ brush->gpencil_settings->flag &= ~GP_BRUSH_USE_PRESSURE;
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_strength = 0.3f;
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.6f;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
brush->gpencil_settings->draw_smoothfac = 0.1f;
brush->gpencil_settings->draw_smoothlvl = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
brush->gpencil_settings->draw_subdivide = 0;
- brush->gpencil_settings->draw_random_sub = 0;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_BLOCK;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->simplify_f = 0.002f;
+
+ brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_RANDOM;
+ brush->gpencil_settings->draw_random_press = 0.0f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ /* Curve. */
+ custom_curve = brush->gpencil_settings->curve_sensitivity;
+ BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
+ BKE_curvemapping_initialize(custom_curve);
+ brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_MARKER);
+
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER;
brush->gpencil_tool = GPAINT_TOOL_DRAW;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Marker brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Marker");
+ /* Marker Chisel brush. */
+ brush = BLI_findstring(&bmain->brushes, "Marker Chisel", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Marker Chisel");
+ }
brush->size = 80.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.0f;
brush->gpencil_settings->draw_strength = 1.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
- brush->gpencil_settings->draw_random_press = 0.374f;
- brush->gpencil_settings->draw_random_strength = 0.0f;
-
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.5f;
brush->gpencil_settings->draw_angle = DEG2RAD(20.0f);
brush->gpencil_settings->draw_angle_factor = 1.0f;
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
- brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothfac = 0.0f;
brush->gpencil_settings->draw_smoothlvl = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
- brush->gpencil_settings->draw_subdivide = 1;
- brush->gpencil_settings->draw_random_sub = 0.0f;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER;
+ brush->gpencil_settings->draw_subdivide = 0;
+ brush->gpencil_settings->draw_random_sub = 0;
+ brush->gpencil_settings->simplify_f = 0.002f;
+
+ brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_RANDOM;
+ brush->gpencil_settings->draw_random_press = 0.0f;
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_CHISEL;
brush->gpencil_tool = GPAINT_TOOL_DRAW;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- /* Curve */
- custom_curve = brush->gpencil_settings->curve_sensitivity;
- BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
- BKE_curvemapping_initialize(custom_curve);
- brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_MARKER);
+ /* Pen brush. */
+ brush = BLI_findstring(&bmain->brushes, "Pen", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Pen");
+ }
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.3f;
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
brush->gpencil_settings->gradient_f = 1.0f;
brush->gpencil_settings->gradient_s[0] = 1.0f;
brush->gpencil_settings->gradient_s[1] = 1.0f;
- /* Soft brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Soft");
- deft = brush; /* save default brush */
- brush->size = 300.0f;
- brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.0f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 1;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->simplify_f = 0.002f;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
brush->gpencil_settings->draw_sensitivity = 1.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Pencil Soft brush. */
+ brush = BLI_findstring(&bmain->brushes, "Pencil Soft", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Pencil Soft");
+ }
+
+ brush->size = 80.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+
brush->gpencil_settings->draw_strength = 0.4f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.64f;
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+ brush->gpencil_settings->gradient_f = 0.8f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.0f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 0;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->simplify_f = 0.000f;
+
brush->gpencil_settings->draw_random_press = 0.0f;
brush->gpencil_settings->draw_random_strength = 0.0f;
-
brush->gpencil_settings->draw_jitter = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Pencil brush. */
+ brush = BLI_findstring(&bmain->brushes, "Pencil", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Pencil");
+ }
+ deft = brush; /* save default brush. */
+
+ brush->size = 25.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+
+ brush->gpencil_settings->draw_strength = 0.6f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.55f;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
- brush->gpencil_settings->input_samples = 10;
- brush->gpencil_settings->active_smooth = 0.98f;
- brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.0f;
brush->gpencil_settings->draw_smoothlvl = 1;
- brush->gpencil_settings->draw_subdivide = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 0;
brush->gpencil_settings->draw_random_sub = 0.0f;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER;
+ brush->gpencil_settings->simplify_f = 0.002f;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL;
brush->gpencil_tool = GPAINT_TOOL_DRAW;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- brush->gpencil_settings->gradient_f = 0.211f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 0.91f;
-
- /* Fill brush */
+ /* Fill brush. */
brush = BKE_brush_add_gpencil(bmain, ts, "Fill Area");
brush->size = 20.0f;
brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
- brush->gpencil_settings->draw_sensitivity = 1.0f;
+
brush->gpencil_settings->fill_leak = 3;
brush->gpencil_settings->fill_threshold = 0.1f;
brush->gpencil_settings->fill_simplylvl = 1;
brush->gpencil_settings->fill_factor = 1;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL;
- brush->gpencil_tool = GPAINT_TOOL_FILL;
+ brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
brush->gpencil_settings->draw_smoothfac = 0.1f;
brush->gpencil_settings->draw_smoothlvl = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
brush->gpencil_settings->draw_subdivide = 1;
- brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
- brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
- brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL;
+ brush->gpencil_tool = GPAINT_TOOL_FILL;
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- /* Soft Eraser brush */
+ /* Soft Eraser brush. */
brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Soft");
brush->size = 30.0f;
brush->gpencil_settings->draw_strength = 0.5f;
@@ -580,34 +630,37 @@ void BKE_brush_gpencil_presets(bContext *C)
brush->gpencil_settings->era_strength_f = 100.0f;
brush->gpencil_settings->era_thickness_f = 10.0f;
- /* Hard Eraser brush */
+ /* Hard Eraser brush. */
brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Hard");
brush->size = 30.0f;
brush->gpencil_settings->draw_strength = 1.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
- brush->gpencil_tool = GPAINT_TOOL_ERASE;
brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
brush->gpencil_settings->era_strength_f = 100.0f;
brush->gpencil_settings->era_thickness_f = 50.0f;
- /* Point Eraser brush */
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
+ brush->gpencil_tool = GPAINT_TOOL_ERASE;
+
+ /* Point Eraser brush. */
brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Point");
brush->size = 30.0f;
brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD;
+
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
brush->gpencil_tool = GPAINT_TOOL_ERASE;
- brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD;
- /* Stroke Eraser brush */
+ /* Stroke Eraser brush. */
brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Stroke");
brush->size = 30.0f;
brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE;
+
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE;
brush->gpencil_tool = GPAINT_TOOL_ERASE;
- brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE;
- /* set default brush */
+ /* set default brush. */
BKE_paint_brush_set(paint, deft);
}
@@ -839,7 +892,20 @@ void BKE_brush_sculpt_reset(Brush *br)
brush_defaults(br);
BKE_brush_curve_preset(br, CURVE_PRESET_SMOOTH);
+ /* Use the curve presets by default */
+ br->curve_preset = BRUSH_CURVE_SMOOTH;
+
+ /* Note that sculpt defaults where set when 0.5 was the default (now it's 1.0)
+ * assign this so logic below can remain the same. */
+ br->alpha = 0.5f;
+
+ /* Brush settings */
switch (br->sculpt_tool) {
+ case SCULPT_TOOL_DRAW_SHARP:
+ br->flag |= BRUSH_DIR_IN;
+ br->curve_preset = BRUSH_CURVE_POW4;
+ br->spacing = 5;
+ break;
case SCULPT_TOOL_CLAY:
br->flag |= BRUSH_FRONTFACE;
break;
@@ -847,41 +913,10 @@ void BKE_brush_sculpt_reset(Brush *br)
br->flag |= BRUSH_DIR_IN;
br->alpha = 0.25;
break;
- case SCULPT_TOOL_FILL:
- br->add_col[1] = 1;
- br->sub_col[0] = 0.25;
- br->sub_col[1] = 1;
- break;
- case SCULPT_TOOL_FLATTEN:
- br->add_col[1] = 1;
- br->sub_col[0] = 0.25;
- br->sub_col[1] = 1;
- break;
- case SCULPT_TOOL_INFLATE:
- br->add_col[0] = 0.750000;
- br->add_col[1] = 0.750000;
- br->add_col[2] = 0.750000;
- br->sub_col[0] = 0.250000;
- br->sub_col[1] = 0.250000;
- br->sub_col[2] = 0.250000;
- break;
- case SCULPT_TOOL_NUDGE:
- br->add_col[0] = 0.250000;
- br->add_col[1] = 1.000000;
- br->add_col[2] = 0.250000;
- break;
- case SCULPT_TOOL_PINCH:
- br->add_col[0] = 0.750000;
- br->add_col[1] = 0.750000;
- br->add_col[2] = 0.750000;
- br->sub_col[0] = 0.250000;
- br->sub_col[1] = 0.250000;
- br->sub_col[2] = 0.250000;
- break;
case SCULPT_TOOL_SCRAPE:
- br->add_col[1] = 1.000000;
- br->sub_col[0] = 0.250000;
- br->sub_col[1] = 1.000000;
+ br->alpha = 1.0f;
+ br->spacing = 7;
+ br->flag |= BRUSH_ACCUMULATE;
break;
case SCULPT_TOOL_ROTATE:
br->alpha = 1.0;
@@ -889,20 +924,94 @@ void BKE_brush_sculpt_reset(Brush *br)
case SCULPT_TOOL_SMOOTH:
br->flag &= ~BRUSH_SPACE_ATTEN;
br->spacing = 5;
- br->add_col[0] = 0.750000;
- br->add_col[1] = 0.750000;
- br->add_col[2] = 0.750000;
+ br->alpha = 0.7f;
break;
- case SCULPT_TOOL_GRAB:
case SCULPT_TOOL_SNAKE_HOOK:
+ br->alpha = 1.0f;
+ break;
case SCULPT_TOOL_THUMB:
br->size = 75;
br->flag &= ~BRUSH_ALPHA_PRESSURE;
br->flag &= ~BRUSH_SPACE;
br->flag &= ~BRUSH_SPACE_ATTEN;
- br->add_col[0] = 0.250000;
- br->add_col[1] = 1.000000;
- br->add_col[2] = 0.250000;
+ break;
+ case SCULPT_TOOL_ELASTIC_DEFORM:
+ br->elastic_deform_volume_preservation = 0.4f;
+ br->elastic_deform_type = BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE;
+ br->flag &= ~BRUSH_ALPHA_PRESSURE;
+ br->flag &= ~BRUSH_SPACE;
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ break;
+ case SCULPT_TOOL_POSE:
+ br->flag &= ~BRUSH_ALPHA_PRESSURE;
+ br->flag &= ~BRUSH_SPACE;
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ break;
+ case SCULPT_TOOL_GRAB:
+ br->alpha = 0.4f;
+ br->size = 75;
+ br->flag &= ~BRUSH_ALPHA_PRESSURE;
+ br->flag &= ~BRUSH_SPACE;
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ break;
+ default:
+ break;
+ }
+
+ /* Cursor colors */
+ switch (br->sculpt_tool) {
+ case SCULPT_TOOL_DRAW:
+ case SCULPT_TOOL_DRAW_SHARP:
+ case SCULPT_TOOL_CLAY:
+ case SCULPT_TOOL_CLAY_STRIPS:
+ case SCULPT_TOOL_LAYER:
+ case SCULPT_TOOL_INFLATE:
+ case SCULPT_TOOL_BLOB:
+ case SCULPT_TOOL_CREASE:
+ br->add_col[0] = 0.65f;
+ br->add_col[1] = 0.85f;
+ br->add_col[2] = 0.9f;
+ br->sub_col[0] = 0.65f;
+ br->sub_col[1] = 0.85f;
+ br->sub_col[2] = 0.9f;
+ break;
+
+ case SCULPT_TOOL_SMOOTH:
+ case SCULPT_TOOL_FLATTEN:
+ case SCULPT_TOOL_FILL:
+ case SCULPT_TOOL_SCRAPE:
+ br->add_col[0] = 1.0f;
+ br->add_col[1] = 0.39f;
+ br->add_col[2] = 0.39f;
+ br->sub_col[0] = 1.0f;
+ br->sub_col[1] = 0.39f;
+ br->sub_col[2] = 0.39f;
+ break;
+
+ case SCULPT_TOOL_PINCH:
+ case SCULPT_TOOL_GRAB:
+ case SCULPT_TOOL_SNAKE_HOOK:
+ case SCULPT_TOOL_THUMB:
+ case SCULPT_TOOL_NUDGE:
+ case SCULPT_TOOL_ROTATE:
+ case SCULPT_TOOL_ELASTIC_DEFORM:
+ case SCULPT_TOOL_POSE:
+ br->add_col[0] = 1.0f;
+ br->add_col[1] = 1.0f;
+ br->add_col[2] = 0.39f;
+ br->sub_col[0] = 1.0f;
+ br->sub_col[1] = 1.0f;
+ br->sub_col[2] = 0.39f;
+ break;
+
+ case SCULPT_TOOL_SIMPLIFY:
+ case SCULPT_TOOL_MASK:
+ br->add_col[0] = 0.750000;
+ br->add_col[1] = 0.750000;
+ br->add_col[2] = 0.750000;
+ br->sub_col[0] = 0.750000;
+ br->sub_col[1] = 0.750000;
+ br->sub_col[2] = 0.750000;
break;
default:
break;
@@ -1264,6 +1373,7 @@ bool BKE_brush_sculpt_has_secondary_color(const Brush *brush)
return ELEM(brush->sculpt_tool,
SCULPT_TOOL_BLOB,
SCULPT_TOOL_DRAW,
+ SCULPT_TOOL_DRAW_SHARP,
SCULPT_TOOL_INFLATE,
SCULPT_TOOL_CLAY,
SCULPT_TOOL_CLAY_STRIPS,
@@ -1490,11 +1600,11 @@ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_sec
}
/**** Radial Control ****/
-struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary)
+struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary, bool display_gradient)
{
ImBuf *im = MEM_callocN(sizeof(ImBuf), "radial control texture");
unsigned int *texcache;
- int side = 128;
+ int side = 512;
int half = side / 2;
int i, j;
@@ -1503,24 +1613,25 @@ struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary)
im->rect_float = MEM_callocN(sizeof(float) * side * side, "radial control rect");
im->x = im->y = side;
- for (i = 0; i < side; ++i) {
- for (j = 0; j < side; ++j) {
- float magn = sqrtf(pow2f(i - half) + pow2f(j - half));
- im->rect_float[i * side + j] = BKE_brush_curve_strength_clamped(br, magn, half);
+ if (display_gradient || texcache) {
+ for (i = 0; i < side; i++) {
+ for (j = 0; j < side; j++) {
+ float magn = sqrtf(pow2f(i - half) + pow2f(j - half));
+ im->rect_float[i * side + j] = BKE_brush_curve_strength_clamped(br, magn, half);
+ }
}
}
- /* Modulate curve with texture */
if (texcache) {
- for (i = 0; i < side; ++i) {
- for (j = 0; j < side; ++j) {
+ /* Modulate curve with texture */
+ for (i = 0; i < side; i++) {
+ for (j = 0; j < side; j++) {
const int col = texcache[i * side + j];
im->rect_float[i * side + j] *= (((char *)&col)[0] + ((char *)&col)[1] +
((char *)&col)[2]) /
3.0f / 255.0f;
}
}
-
MEM_freeN(texcache);
}
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index 85a12027bf2..0a5952e1b47 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -1395,7 +1395,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
else {
/* Setup BVHTreeFromMesh */
bvhtree_from_mesh_edges_setup_data(
- data, tree, false, mesh->mvert, false, mesh->medge, false);
+ data, tree, true, mesh->mvert, false, mesh->medge, false);
}
break;
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index 2d6256f12e2..3b0f4d9c2aa 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -246,7 +246,7 @@ void BKE_cachefile_eval(Main *bmain, Depsgraph *depsgraph, CacheFile *cache_file
BLI_freelistN(&cache_file->object_paths);
#ifdef WITH_ALEMBIC
- cache_file->handle = ABC_create_handle(filepath, &cache_file->object_paths);
+ cache_file->handle = ABC_create_handle(bmain, filepath, &cache_file->object_paths);
BLI_strncpy(cache_file->handle_filepath, filepath, FILE_MAX);
#endif
diff --git a/source/blender/blenlib/intern/callbacks.c b/source/blender/blenkernel/intern/callbacks.c
index c4f93a9831d..367fed818af 100644
--- a/source/blender/blenlib/intern/callbacks.c
+++ b/source/blender/blenkernel/intern/callbacks.c
@@ -15,43 +15,81 @@
*/
/** \file
- * \ingroup bli
+ * \ingroup bke
*/
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
-#include "BLI_callbacks.h"
+
+#include "BKE_callbacks.h"
#include "MEM_guardedalloc.h"
-static ListBase callback_slots[BLI_CB_EVT_TOT] = {{NULL}};
+#include "RNA_types.h"
+#include "RNA_access.h"
+
+static ListBase callback_slots[BKE_CB_EVT_TOT] = {{NULL}};
-void BLI_callback_exec(struct Main *bmain, struct ID *self, eCbEvent evt)
+void BKE_callback_exec(struct Main *bmain,
+ struct PointerRNA **pointers,
+ const int num_pointers,
+ eCbEvent evt)
{
ListBase *lb = &callback_slots[evt];
bCallbackFuncStore *funcstore;
for (funcstore = lb->first; funcstore; funcstore = funcstore->next) {
- funcstore->func(bmain, self, funcstore->arg);
+ funcstore->func(bmain, pointers, num_pointers, funcstore->arg);
}
}
-void BLI_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt)
+void BKE_callback_exec_null(struct Main *bmain, eCbEvent evt)
+{
+ BKE_callback_exec(bmain, NULL, 0, evt);
+}
+
+void BKE_callback_exec_id(struct Main *bmain, struct ID *id, eCbEvent evt)
+{
+ PointerRNA id_ptr;
+ RNA_id_pointer_create(id, &id_ptr);
+
+ PointerRNA *pointers[1] = {&id_ptr};
+
+ BKE_callback_exec(bmain, pointers, 1, evt);
+}
+
+void BKE_callback_exec_id_depsgraph(struct Main *bmain,
+ struct ID *id,
+ struct Depsgraph *depsgraph,
+ eCbEvent evt)
+{
+ PointerRNA id_ptr;
+ RNA_id_pointer_create(id, &id_ptr);
+
+ PointerRNA depsgraph_ptr;
+ RNA_pointer_create(NULL, &RNA_Depsgraph, depsgraph, &depsgraph_ptr);
+
+ PointerRNA *pointers[2] = {&id_ptr, &depsgraph_ptr};
+
+ BKE_callback_exec(bmain, pointers, 2, evt);
+}
+
+void BKE_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt)
{
ListBase *lb = &callback_slots[evt];
BLI_addtail(lb, funcstore);
}
-void BLI_callback_global_init(void)
+void BKE_callback_global_init(void)
{
/* do nothing */
}
/* call on application exit */
-void BLI_callback_global_finalize(void)
+void BKE_callback_global_finalize(void)
{
eCbEvent evt;
- for (evt = 0; evt < BLI_CB_EVT_TOT; evt++) {
+ for (evt = 0; evt < BKE_CB_EVT_TOT; evt++) {
ListBase *lb = &callback_slots[evt];
bCallbackFuncStore *funcstore;
bCallbackFuncStore *funcstore_next;
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index a563a8d581c..f70c5bb99d6 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -30,6 +30,7 @@
#include "DNA_scene_types.h"
#include "DNA_view3d_types.h"
#include "DNA_ID.h"
+#include "DNA_defaults.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
@@ -56,25 +57,7 @@ void BKE_camera_init(Camera *cam)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(cam, id));
- cam->lens = 50.0f;
- cam->sensor_x = DEFAULT_SENSOR_WIDTH;
- cam->sensor_y = DEFAULT_SENSOR_HEIGHT;
- cam->clip_start = 0.1f;
- cam->clip_end = 1000.0f;
- cam->drawsize = 1.0f;
- cam->ortho_scale = 6.0;
- cam->flag |= CAM_SHOWPASSEPARTOUT;
- cam->passepartalpha = 0.5f;
-
- cam->dof.aperture_fstop = 2.8f;
- cam->dof.aperture_ratio = 1.0f;
- cam->dof.focus_distance = 10.0f;
-
- /* stereoscopy 3d */
- cam->stereo.interocular_distance = 0.065f;
- cam->stereo.convergence_distance = 30.f * 0.065f;
- cam->stereo.pole_merge_angle_from = DEG2RADF(60.0f);
- cam->stereo.pole_merge_angle_to = DEG2RADF(75.0f);
+ MEMCPY_STRUCT_AFTER(cam, DNA_struct_default_get(Camera), id);
}
void *BKE_camera_add(Main *bmain, const char *name)
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 2031576190e..f2098cc2430 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -203,6 +203,9 @@ void BKE_collection_copy_data(Main *bmain,
const Collection *collection_src,
const int flag)
{
+ BLI_assert(((collection_src->flag & COLLECTION_IS_MASTER) != 0) ==
+ ((collection_src->id.flag & LIB_PRIVATE_DATA) != 0));
+
/* Do not copy collection's preview (same behavior as for objects). */
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */
BKE_previewimg_id_copy(&collection_dst->id, &collection_src->id);
@@ -338,8 +341,9 @@ Collection *BKE_collection_duplicate(Main *bmain,
const bool do_obdata)
{
/* It's not allowed to copy the master collection. */
+ BLI_assert((collection->id.flag & LIB_PRIVATE_DATA) == 0);
+ BLI_assert((collection->flag & COLLECTION_IS_MASTER) == 0);
if (collection->flag & COLLECTION_IS_MASTER) {
- BLI_assert("!Master collection can't be duplicated");
return NULL;
}
@@ -365,15 +369,6 @@ Collection *BKE_collection_duplicate(Main *bmain,
return collection_new;
}
-Collection *BKE_collection_copy_master(Main *bmain, Collection *collection, const int flag)
-{
- BLI_assert(collection->flag & COLLECTION_IS_MASTER);
-
- Collection *collection_dst = MEM_dupallocN(collection);
- BKE_collection_copy_data(bmain, collection_dst, collection, flag);
- return collection_dst;
-}
-
void BKE_collection_make_local(Main *bmain, Collection *collection, const bool lib_local)
{
BKE_id_make_local_generic(bmain, &collection->id, true, lib_local);
@@ -499,15 +494,11 @@ Collection *BKE_collection_master_add()
/* Not an actual datablock, but owned by scene. */
Collection *master_collection = MEM_callocN(sizeof(Collection), "Master Collection");
STRNCPY(master_collection->id.name, "GRMaster Collection");
+ master_collection->id.flag |= LIB_PRIVATE_DATA;
master_collection->flag |= COLLECTION_IS_MASTER;
return master_collection;
}
-Collection *BKE_collection_master(const Scene *scene)
-{
- return scene->master_collection;
-}
-
Scene *BKE_collection_master_scene_search(const Main *bmain, const Collection *master_collection)
{
BLI_assert((master_collection->flag & COLLECTION_IS_MASTER) != 0);
@@ -584,7 +575,7 @@ bool BKE_collection_has_object_recursive(Collection *collection, Object *ob)
static Collection *collection_next_find(Main *bmain, Scene *scene, Collection *collection)
{
- if (scene && collection == BKE_collection_master(scene)) {
+ if (scene && collection == scene->master_collection) {
return bmain->collections.first;
}
else {
@@ -601,7 +592,7 @@ Collection *BKE_collection_object_find(Main *bmain,
collection = collection_next_find(bmain, scene, collection);
}
else if (scene) {
- collection = BKE_collection_master(scene);
+ collection = scene->master_collection;
}
else {
collection = bmain->collections.first;
@@ -743,7 +734,7 @@ void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, O
if (!is_instantiated) {
/* In case we could not find any non-linked collections in which instantiate our ob_dst,
* fallback to scene's master collection... */
- collection_object_add(bmain, BKE_collection_master(scene), ob_dst, 0, true);
+ collection_object_add(bmain, scene->master_collection, ob_dst, 0, true);
}
BKE_main_collection_sync(bmain);
@@ -885,7 +876,7 @@ void BKE_collections_child_remove_nulls(Main *bmain, Collection *collection)
collection_null_children_remove(collection);
}
for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
- collection_null_children_remove(BKE_collection_master(scene));
+ collection_null_children_remove(scene->master_collection);
}
for (collection = bmain->collections.first; collection != NULL;
@@ -893,7 +884,7 @@ void BKE_collections_child_remove_nulls(Main *bmain, Collection *collection)
collection_missing_parents_remove(collection);
}
for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
- collection_missing_parents_remove(BKE_collection_master(scene));
+ collection_missing_parents_remove(scene->master_collection);
}
}
else {
@@ -1169,7 +1160,7 @@ static Collection *collection_from_index_recursive(Collection *collection,
Collection *BKE_collection_from_index(Scene *scene, const int index)
{
int index_current = 0;
- Collection *master_collection = BKE_collection_master(scene);
+ Collection *master_collection = scene->master_collection;
return collection_from_index_recursive(master_collection, index, &index_current);
}
@@ -1363,7 +1354,7 @@ static void scene_collections_array(Scene *scene, Collection ***collections_arra
return;
}
- collection = BKE_collection_master(scene);
+ collection = scene->master_collection;
BLI_assert(collection != NULL);
scene_collection_callback(collection, scene_collections_count, tot);
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 69afda9997a..91d66e16dde 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -188,11 +188,11 @@ BLI_INLINE int next_ind(int i)
}
static float compute_collision_point(float a1[3],
- float a2[3],
- float a3[3],
- float b1[3],
- float b2[3],
- float b3[3],
+ const float a2[3],
+ const float a3[3],
+ const float b1[3],
+ const float b2[3],
+ const float b3[3],
bool culling,
bool use_normal,
float r_a[3],
@@ -419,7 +419,7 @@ static float compute_collision_point(float a1[3],
// w3 is not perfect
static void collision_compute_barycentric(
- float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3)
+ const float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3)
{
/* dot_v3v3 */
#define INPR(v1, v2) ((v1)[0] * (v2)[0] + (v1)[1] * (v2)[1] + (v1)[2] * (v2)[2])
@@ -1499,7 +1499,7 @@ BLI_INLINE bool cloth_point_face_collision_params(const float p1[3],
}
static CollPair *cloth_point_collpair(float p1[3],
- float p2[3],
+ const float p2[3],
const MVert *mverts,
int bp1,
int bp2,
@@ -1742,7 +1742,7 @@ void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders)
{
if (collider_contacts) {
int i;
- for (i = 0; i < totcolliders; ++i) {
+ for (i = 0; i < totcolliders; i++) {
ColliderContacts *ct = collider_contacts + i;
if (ct->collisions) {
MEM_freeN(ct->collisions);
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index e1e4d138fd9..d59849695ff 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -62,6 +62,7 @@
#include "BKE_deform.h"
#include "BKE_displist.h"
#include "BKE_editmesh.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
@@ -1801,25 +1802,47 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
bConstraintTarget *ct = targets->first;
if (VALID_CONS_TARGET(ct)) {
- float loc[3];
- float eul[3], obeul[3];
- float size[3];
+ float loc[3], size[3], oldrot[3][3], newrot[3][3];
+ float eul[3], obeul[3], defeul[3];
- copy_v3_v3(loc, cob->matrix[3]);
- mat4_to_size(size, cob->matrix);
+ mat4_to_loc_rot_size(loc, oldrot, size, cob->matrix);
+
+ /* Select the Euler rotation order, defaulting to the owner. */
+ short rot_order = cob->rotOrder;
+
+ if (data->euler_order != CONSTRAINT_EULER_AUTO) {
+ rot_order = data->euler_order;
+ }
/* To allow compatible rotations, must get both rotations in the order of the owner... */
- mat4_to_eulO(obeul, cob->rotOrder, cob->matrix);
+ mat4_to_eulO(obeul, rot_order, cob->matrix);
/* We must get compatible eulers from the beginning because
* some of them can be modified below (see bug T21875). */
- mat4_to_compatible_eulO(eul, obeul, cob->rotOrder, ct->matrix);
+ mat4_to_compatible_eulO(eul, obeul, rot_order, ct->matrix);
+
+ /* Prepare the copied euler rotation. */
+ bool legacy_offset = false;
+
+ switch (data->mix_mode) {
+ case ROTLIKE_MIX_OFFSET:
+ legacy_offset = true;
+ copy_v3_v3(defeul, obeul);
+ break;
+
+ case ROTLIKE_MIX_REPLACE:
+ copy_v3_v3(defeul, obeul);
+ break;
+
+ default:
+ zero_v3(defeul);
+ }
if ((data->flag & ROTLIKE_X) == 0) {
- eul[0] = obeul[0];
+ eul[0] = defeul[0];
}
else {
- if (data->flag & ROTLIKE_OFFSET) {
- rotate_eulO(eul, cob->rotOrder, 'X', obeul[0]);
+ if (legacy_offset) {
+ rotate_eulO(eul, rot_order, 'X', obeul[0]);
}
if (data->flag & ROTLIKE_X_INVERT) {
@@ -1828,11 +1851,11 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
}
if ((data->flag & ROTLIKE_Y) == 0) {
- eul[1] = obeul[1];
+ eul[1] = defeul[1];
}
else {
- if (data->flag & ROTLIKE_OFFSET) {
- rotate_eulO(eul, cob->rotOrder, 'Y', obeul[1]);
+ if (legacy_offset) {
+ rotate_eulO(eul, rot_order, 'Y', obeul[1]);
}
if (data->flag & ROTLIKE_Y_INVERT) {
@@ -1841,11 +1864,11 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
}
if ((data->flag & ROTLIKE_Z) == 0) {
- eul[2] = obeul[2];
+ eul[2] = defeul[2];
}
else {
- if (data->flag & ROTLIKE_OFFSET) {
- rotate_eulO(eul, cob->rotOrder, 'Z', obeul[2]);
+ if (legacy_offset) {
+ rotate_eulO(eul, rot_order, 'Z', obeul[2]);
}
if (data->flag & ROTLIKE_Z_INVERT) {
@@ -1853,10 +1876,36 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
}
}
+ /* Add the euler components together if needed. */
+ if (data->mix_mode == ROTLIKE_MIX_ADD) {
+ add_v3_v3(eul, obeul);
+ }
+
/* Good to make eulers compatible again,
* since we don't know how much they were changed above. */
compatible_eul(eul, obeul);
- loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, cob->rotOrder);
+ eulO_to_mat3(newrot, eul, rot_order);
+
+ /* Mix the rotation matrices: */
+ switch (data->mix_mode) {
+ case ROTLIKE_MIX_REPLACE:
+ case ROTLIKE_MIX_OFFSET:
+ case ROTLIKE_MIX_ADD:
+ break;
+
+ case ROTLIKE_MIX_BEFORE:
+ mul_m3_m3m3(newrot, newrot, oldrot);
+ break;
+
+ case ROTLIKE_MIX_AFTER:
+ mul_m3_m3m3(newrot, oldrot, newrot);
+ break;
+
+ default:
+ BLI_assert(false);
+ }
+
+ loc_rot_size_to_mat4(cob->matrix, loc, newrot, size);
}
}
@@ -1927,9 +1976,39 @@ static void sizelike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *ta
if (VALID_CONS_TARGET(ct)) {
float obsize[3], size[3];
- mat4_to_size(size, ct->matrix);
mat4_to_size(obsize, cob->matrix);
+ /* Compute one uniform scale factor to apply to all three axes. */
+ if (data->flag & SIZELIKE_UNIFORM) {
+ const int all_axes = SIZELIKE_X | SIZELIKE_Y | SIZELIKE_Z;
+ float total = 1.0f;
+
+ /* If all axes are selected, use the determinant. */
+ if ((data->flag & all_axes) == all_axes) {
+ total = fabsf(mat4_to_volume_scale(ct->matrix));
+ }
+ /* Otherwise multiply individual values. */
+ else {
+ mat4_to_size(size, ct->matrix);
+
+ if (data->flag & SIZELIKE_X) {
+ total *= size[0];
+ }
+ if (data->flag & SIZELIKE_Y) {
+ total *= size[1];
+ }
+ if (data->flag & SIZELIKE_Z) {
+ total *= size[2];
+ }
+ }
+
+ copy_v3_fl(size, cbrt(total));
+ }
+ /* Regular per-axis scaling. */
+ else {
+ mat4_to_size(size, ct->matrix);
+ }
+
for (int i = 0; i < 3; i++) {
size[i] = powf(size[i], data->power);
}
@@ -1948,13 +2027,13 @@ static void sizelike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *ta
}
}
- if ((data->flag & SIZELIKE_X) && (obsize[0] != 0)) {
+ if ((data->flag & (SIZELIKE_X | SIZELIKE_UNIFORM)) && (obsize[0] != 0)) {
mul_v3_fl(cob->matrix[0], size[0] / obsize[0]);
}
- if ((data->flag & SIZELIKE_Y) && (obsize[1] != 0)) {
+ if ((data->flag & (SIZELIKE_Y | SIZELIKE_UNIFORM)) && (obsize[1] != 0)) {
mul_v3_fl(cob->matrix[1], size[1] / obsize[1]);
}
- if ((data->flag & SIZELIKE_Z) && (obsize[2] != 0)) {
+ if ((data->flag & (SIZELIKE_Z | SIZELIKE_UNIFORM)) && (obsize[2] != 0)) {
mul_v3_fl(cob->matrix[2], size[2] / obsize[2]);
}
}
@@ -2011,13 +2090,43 @@ static void translike_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
}
}
-static void translike_evaluate(bConstraint *UNUSED(con), bConstraintOb *cob, ListBase *targets)
+static void translike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
+ bTransLikeConstraint *data = con->data;
bConstraintTarget *ct = targets->first;
if (VALID_CONS_TARGET(ct)) {
- /* just copy the entire transform matrix of the target */
- copy_m4_m4(cob->matrix, ct->matrix);
+ if (data->mix_mode == TRANSLIKE_MIX_REPLACE) {
+ /* just copy the entire transform matrix of the target */
+ copy_m4_m4(cob->matrix, ct->matrix);
+ }
+ else {
+ float old_loc[3], old_rot[3][3], old_size[3];
+ float new_loc[3], new_rot[3][3], new_size[3];
+
+ /* Separate matrices so they can be combined in a way that avoids shear. */
+ mat4_to_loc_rot_size(old_loc, old_rot, old_size, cob->matrix);
+ mat4_to_loc_rot_size(new_loc, new_rot, new_size, ct->matrix);
+
+ switch (data->mix_mode) {
+ case TRANSLIKE_MIX_BEFORE:
+ mul_v3_m4v3(new_loc, ct->matrix, old_loc);
+ mul_m3_m3m3(new_rot, new_rot, old_rot);
+ mul_v3_v3(new_size, old_size);
+ break;
+
+ case TRANSLIKE_MIX_AFTER:
+ mul_v3_m4v3(new_loc, cob->matrix, new_loc);
+ mul_m3_m3m3(new_rot, old_rot, new_rot);
+ mul_v3_v3(new_size, old_size);
+ break;
+
+ default:
+ BLI_assert(false);
+ }
+
+ loc_rot_size_to_mat4(cob->matrix, new_loc, new_rot, new_size);
+ }
}
}
@@ -2301,9 +2410,9 @@ static void armdef_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
}
static void armdef_accumulate_matrix(float obmat[4][4],
- float iobmat[4][4],
- float basemat[4][4],
- float bonemat[4][4],
+ const float iobmat[4][4],
+ const float basemat[4][4],
+ const float bonemat[4][4],
float weight,
float r_sum_mat[4][4],
DualQuat *r_sum_dq)
@@ -3644,6 +3753,11 @@ static void transform_new_data(void *cdata)
data->map[0] = 0;
data->map[1] = 1;
data->map[2] = 2;
+
+ for (int i = 0; i < 3; i++) {
+ data->from_min_scale[i] = data->from_max_scale[i] = 1.0f;
+ data->to_min_scale[i] = data->to_max_scale[i] = 1.0f;
+ }
}
static void transform_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
@@ -3688,8 +3802,10 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
/* only evaluate if there is a target */
if (VALID_CONS_TARGET(ct)) {
float *from_min, *from_max, *to_min, *to_max;
- float loc[3], eul[3], size[3];
- float dvec[3], sval[3];
+ float loc[3], rot[3][3], oldeul[3], size[3];
+ float newloc[3], newrot[3][3], neweul[3], newsize[3];
+ float dbuf[4], sval[3];
+ float *const dvec = dbuf + 1;
int i;
/* obtain target effect */
@@ -3708,7 +3824,8 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
from_max = data->from_max_scale;
break;
case TRANS_ROTATION:
- mat4_to_eulO(dvec, cob->rotOrder, ct->matrix);
+ BKE_driver_target_matrix_to_rot_channels(
+ ct->matrix, cob->rotOrder, data->from_rotation_mode, -1, true, dbuf);
from_min = data->from_min_rot;
from_max = data->from_max_rot;
break;
@@ -3720,10 +3837,15 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
break;
}
+ /* Select the output Euler rotation order, defaulting to the owner. */
+ short rot_order = cob->rotOrder;
+
+ if (data->to == TRANS_ROTATION && data->to_euler_order != CONSTRAINT_EULER_AUTO) {
+ rot_order = data->to_euler_order;
+ }
+
/* extract components of owner's matrix */
- copy_v3_v3(loc, cob->matrix[3]);
- mat4_to_eulO(eul, cob->rotOrder, cob->matrix);
- mat4_to_size(size, cob->matrix);
+ mat4_to_loc_rot_size(loc, rot, size, cob->matrix);
/* determine where in range current transforms lie */
if (data->expo) {
@@ -3755,18 +3877,42 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
to_min = data->to_min_scale;
to_max = data->to_max_scale;
for (i = 0; i < 3; i++) {
- /* multiply with original scale (so that it can still be scaled) */
- /* size[i] *= to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])); */
- /* Stay absolute, else it breaks existing rigs... sigh. */
- size[i] = to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]));
+ newsize[i] = to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]));
+ }
+ switch (data->mix_mode_scale) {
+ case TRANS_MIXSCALE_MULTIPLY:
+ mul_v3_v3(size, newsize);
+ break;
+ case TRANS_MIXSCALE_REPLACE:
+ default:
+ copy_v3_v3(size, newsize);
+ break;
}
break;
case TRANS_ROTATION:
to_min = data->to_min_rot;
to_max = data->to_max_rot;
for (i = 0; i < 3; i++) {
- /* add to original rotation (so that it can still be rotated) */
- eul[i] += to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]));
+ neweul[i] = to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]));
+ }
+ switch (data->mix_mode_rot) {
+ case TRANS_MIXROT_REPLACE:
+ eulO_to_mat3(rot, neweul, rot_order);
+ break;
+ case TRANS_MIXROT_BEFORE:
+ eulO_to_mat3(newrot, neweul, rot_order);
+ mul_m3_m3m3(rot, newrot, rot);
+ break;
+ case TRANS_MIXROT_AFTER:
+ eulO_to_mat3(newrot, neweul, rot_order);
+ mul_m3_m3m3(rot, rot, newrot);
+ break;
+ case TRANS_MIXROT_ADD:
+ default:
+ mat3_to_eulO(oldeul, rot_order, rot);
+ add_v3_v3(neweul, oldeul);
+ eulO_to_mat3(rot, neweul, rot_order);
+ break;
}
break;
case TRANS_LOCATION:
@@ -3774,14 +3920,22 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
to_min = data->to_min;
to_max = data->to_max;
for (i = 0; i < 3; i++) {
- /* add to original location (so that it can still be moved) */
- loc[i] += (to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])));
+ newloc[i] = (to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])));
+ }
+ switch (data->mix_mode_loc) {
+ case TRANS_MIXLOC_REPLACE:
+ copy_v3_v3(loc, newloc);
+ break;
+ case TRANS_MIXLOC_ADD:
+ default:
+ add_v3_v3(loc, newloc);
+ break;
}
break;
}
/* apply to matrix */
- loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, cob->rotOrder);
+ loc_rot_size_to_mat4(cob->matrix, loc, rot, size);
}
}
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index f536f21c3e5..7f2f04d7eb5 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -1053,7 +1053,7 @@ Collection *CTX_data_collection(const bContext *C)
/* fallback */
Scene *scene = CTX_data_scene(C);
- return BKE_collection_master(scene);
+ return scene->master_collection;
}
enum eContextObjectMode CTX_data_mode_enum_ex(const Object *obedit,
@@ -1351,9 +1351,10 @@ int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list)
Depsgraph *CTX_data_depsgraph_pointer(const bContext *C)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
/* Dependency graph might have been just allocated, and hence it will not be marked.
* This confuses redo system due to the lack of flushing changes back to the original data.
* In the future we would need to check whether the CTX_wm_window(C) is in editing mode (as an
@@ -1381,7 +1382,8 @@ Depsgraph *CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Depsgraph *CTX_data_depsgraph_on_load(const bContext *C)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- return BKE_scene_get_depsgraph(scene, view_layer, false);
+ return BKE_scene_get_depsgraph(bmain, scene, view_layer, false);
}
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index fcbebd24b4a..6740fc985e9 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -261,7 +261,8 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra
float (**deformcos)[3])
{
ModifierData *md;
- Mesh *me;
+ Mesh *me_input = ob->data;
+ Mesh *me = NULL;
int i, a, numleft = 0, numVerts = 0;
int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
float(*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
@@ -270,7 +271,6 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra
modifiers_clearErrors(ob);
- me = NULL;
md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
/* compute the deformation matrices and coordinates for the first
@@ -292,7 +292,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra
data_mask = datamasks->mask;
BLI_linklist_free((LinkNode *)datamasks, NULL);
- me = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, &data_mask, NULL);
+ me = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, &data_mask, NULL, me_input);
deformedVerts = editbmesh_vert_coords_alloc(em, &numVerts);
defmats = MEM_mallocN(sizeof(*defmats) * numVerts, "defmats");
@@ -342,6 +342,28 @@ static void crazyspace_init_object_for_eval(struct Depsgraph *depsgraph,
}
}
+static void crazyspace_init_verts_and_matrices(const Mesh *mesh,
+ float (**deformmats)[3][3],
+ float (**deformcos)[3])
+{
+ int num_verts;
+ *deformcos = BKE_mesh_vert_coords_alloc(mesh, &num_verts);
+ *deformmats = MEM_callocN(sizeof(**deformmats) * num_verts, "defmats");
+ for (int a = 0; a < num_verts; a++) {
+ unit_m3((*deformmats)[a]);
+ }
+ BLI_assert(num_verts == mesh->totvert);
+}
+
+static bool crazyspace_modifier_supports_deform(ModifierData *md)
+{
+ if (ELEM(md->type, eModifierType_Subsurf, eModifierType_Multires)) {
+ return true;
+ }
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ return (mti->type == eModifierTypeType_OnlyDeform);
+}
+
int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph,
Scene *scene,
Object *object,
@@ -349,25 +371,23 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph,
float (**deformcos)[3])
{
ModifierData *md;
- Mesh *me_eval;
- int a, numVerts = 0;
+ Mesh *me_eval = NULL;
float(*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
int numleft = 0;
VirtualModifierData virtualModifierData;
Object object_eval;
crazyspace_init_object_for_eval(depsgraph, object, &object_eval);
MultiresModifierData *mmd = get_multires_modifier(scene, &object_eval, 0);
+ const bool is_sculpt_mode = (object->mode & OB_MODE_SCULPT) != 0;
const bool has_multires = mmd != NULL && mmd->sculptlvl > 0;
const ModifierEvalContext mectx = {depsgraph, &object_eval, 0};
- if (has_multires) {
+ if (is_sculpt_mode && has_multires) {
*deformmats = NULL;
*deformcos = NULL;
return numleft;
}
- me_eval = NULL;
-
md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData);
for (; md; md = md->next) {
@@ -378,41 +398,37 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph,
}
if (mti->type == eModifierTypeType_OnlyDeform) {
- if (!defmats) {
+ if (defmats == NULL) {
/* NOTE: Evaluated object si re-set to its original undeformed
* state. */
Mesh *me = object_eval.data;
me_eval = BKE_mesh_copy_for_eval(me, true);
- deformedVerts = BKE_mesh_vert_coords_alloc(me, &numVerts);
- defmats = MEM_callocN(sizeof(*defmats) * numVerts, "defmats");
-
- for (a = 0; a < numVerts; a++) {
- unit_m3(defmats[a]);
- }
+ crazyspace_init_verts_and_matrices(me_eval, &defmats, &deformedVerts);
}
if (mti->deformMatrices) {
- mti->deformMatrices(md, &mectx, me_eval, deformedVerts, defmats, numVerts);
+ mti->deformMatrices(md, &mectx, me_eval, deformedVerts, defmats, me_eval->totvert);
}
else {
break;
}
}
+ else {
+ break;
+ }
}
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
continue;
}
- if (mti->type == eModifierTypeType_OnlyDeform) {
+ if (crazyspace_modifier_supports_deform(md)) {
numleft++;
}
}
- if (me_eval) {
+ if (me_eval != NULL) {
BKE_id_free(NULL, me_eval);
}
@@ -435,6 +451,13 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
/* there are deformation modifier which doesn't support deformation matrices
* calculation. Need additional crazyspace correction */
+ Mesh *mesh = (Mesh *)object->data;
+ Mesh *mesh_eval = NULL;
+
+ if (*deformcos == NULL) {
+ crazyspace_init_verts_and_matrices(mesh, deformmats, deformcos);
+ }
+
float(*deformedVerts)[3] = *deformcos;
float(*origVerts)[3] = MEM_dupallocN(deformedVerts);
float(*quats)[4];
@@ -444,23 +467,26 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
crazyspace_init_object_for_eval(depsgraph, object, &object_eval);
ModifierData *md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData);
const ModifierEvalContext mectx = {depsgraph, &object_eval, 0};
- Mesh *mesh = (Mesh *)object->data;
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
continue;
}
- if (mti->type == eModifierTypeType_OnlyDeform) {
+ if (crazyspace_modifier_supports_deform(md)) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
/* skip leading modifiers which have been already
* handled in sculpt_get_first_deform_matrices */
if (mti->deformMatrices && !deformed) {
continue;
}
- mti->deformVerts(md, &mectx, NULL, deformedVerts, mesh->totvert);
+ if (mesh_eval == NULL) {
+ mesh_eval = BKE_mesh_copy_for_eval(mesh, true);
+ }
+
+ mti->deformVerts(md, &mectx, mesh_eval, deformedVerts, mesh_eval->totvert);
deformed = 1;
}
}
@@ -479,6 +505,10 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
MEM_freeN(origVerts);
MEM_freeN(quats);
+
+ if (mesh_eval != NULL) {
+ BKE_id_free(NULL, mesh_eval);
+ }
}
if (*deformmats == NULL) {
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 0126c261fa1..d81d250a305 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -36,6 +36,7 @@
#include "DNA_anim_types.h"
#include "DNA_curve_types.h"
#include "DNA_material_types.h"
+#include "DNA_defaults.h"
/* for dereferencing pointers */
#include "DNA_key_types.h"
@@ -141,34 +142,16 @@ void BKE_curve_free(Curve *cu)
MEM_SAFE_FREE(cu->mat);
MEM_SAFE_FREE(cu->str);
MEM_SAFE_FREE(cu->strinfo);
- MEM_SAFE_FREE(cu->bb);
MEM_SAFE_FREE(cu->tb);
}
-void BKE_curve_init(Curve *cu)
+void BKE_curve_init(Curve *cu, const short curve_type)
{
- /* BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(cu, id)); */ /* cu->type is already initialized... */
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(cu, id));
- copy_v3_fl(cu->size, 1.0f);
- cu->flag = CU_DEFORM_BOUNDS_OFF | CU_PATH_RADIUS;
- cu->pathlen = 100;
- cu->resolu = cu->resolv = (cu->type == OB_SURF) ? 4 : 12;
- cu->width = 1.0;
- cu->wordspace = 1.0;
- cu->spacing = cu->linedist = 1.0;
- cu->fsize = 1.0;
- cu->ulheight = 0.05;
- cu->texflag = CU_AUTOSPACE;
- cu->smallcaps_scale = 0.75f;
- /* XXX: this one seems to be the best one in most cases, at least for curve deform... */
- cu->twist_mode = CU_TWIST_MINIMUM;
- cu->bevfac1 = 0.0f;
- cu->bevfac2 = 1.0f;
- cu->bevfac1_mapping = CU_BEVFAC_MAP_RESOLU;
- cu->bevfac2_mapping = CU_BEVFAC_MAP_RESOLU;
- cu->bevresol = 4;
+ MEMCPY_STRUCT_AFTER(cu, DNA_struct_default_get(Curve), id);
- cu->bb = BKE_boundbox_alloc_unit();
+ cu->type = curve_type;
if (cu->type == OB_FONT) {
cu->flag |= CU_FRONT | CU_BACK;
@@ -182,6 +165,9 @@ void BKE_curve_init(Curve *cu)
cu->tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "textbox");
cu->tb[0].w = cu->tb[0].h = 0.0;
}
+ else if (cu->type == OB_SURF) {
+ cu->resolv = 4;
+ }
}
Curve *BKE_curve_add(Main *bmain, const char *name, int type)
@@ -189,9 +175,8 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type)
Curve *cu;
cu = BKE_libblock_alloc(bmain, ID_CU, name, 0);
- cu->type = type;
- BKE_curve_init(cu);
+ BKE_curve_init(cu, type);
return cu;
}
@@ -216,7 +201,6 @@ void BKE_curve_copy_data(Main *bmain, Curve *cu_dst, const Curve *cu_src, const
cu_dst->str = MEM_dupallocN(cu_src->str);
cu_dst->strinfo = MEM_dupallocN(cu_src->strinfo);
cu_dst->tb = MEM_dupallocN(cu_src->tb);
- cu_dst->bb = MEM_dupallocN(cu_src->bb);
cu_dst->batch_cache = NULL;
if (cu_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
@@ -303,41 +287,6 @@ void BKE_curve_type_test(Object *ob)
}
}
-void BKE_curve_boundbox_calc(Curve *cu, float r_loc[3], float r_size[3])
-{
- BoundBox *bb;
- float min[3], max[3];
- float mloc[3], msize[3];
-
- if (cu->bb == NULL) {
- cu->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
- }
- bb = cu->bb;
-
- if (!r_loc) {
- r_loc = mloc;
- }
- if (!r_size) {
- r_size = msize;
- }
-
- INIT_MINMAX(min, max);
- if (!BKE_curve_minmax(cu, true, min, max)) {
- min[0] = min[1] = min[2] = -1.0f;
- max[0] = max[1] = max[2] = 1.0f;
- }
-
- mid_v3_v3v3(r_loc, min, max);
-
- r_size[0] = (max[0] - min[0]) / 2.0f;
- r_size[1] = (max[1] - min[1]) / 2.0f;
- r_size[2] = (max[2] - min[2]) / 2.0f;
-
- BKE_boundbox_init_from_minmax(bb, min, max);
-
- bb->flag &= ~BOUNDBOX_DIRTY;
-}
-
BoundBox *BKE_curve_boundbox_get(Object *ob)
{
/* This is Object-level data access,
@@ -361,13 +310,23 @@ BoundBox *BKE_curve_boundbox_get(Object *ob)
void BKE_curve_texspace_calc(Curve *cu)
{
- float loc[3], size[3];
- int a;
+ if (cu->texflag & CU_AUTOSPACE) {
+ float min[3], max[3];
- BKE_curve_boundbox_calc(cu, loc, size);
+ INIT_MINMAX(min, max);
+ if (!BKE_curve_minmax(cu, true, min, max)) {
+ min[0] = min[1] = min[2] = -1.0f;
+ max[0] = max[1] = max[2] = 1.0f;
+ }
- if (cu->texflag & CU_AUTOSPACE) {
- for (a = 0; a < 3; a++) {
+ float loc[3], size[3];
+ mid_v3_v3v3(loc, min, max);
+
+ size[0] = (max[0] - min[0]) / 2.0f;
+ size[1] = (max[1] - min[1]) / 2.0f;
+ size[2] = (max[2] - min[2]) / 2.0f;
+
+ for (int a = 0; a < 3; a++) {
if (size[a] == 0.0f) {
size[a] = 1.0f;
}
@@ -381,27 +340,28 @@ void BKE_curve_texspace_calc(Curve *cu)
copy_v3_v3(cu->loc, loc);
copy_v3_v3(cu->size, size);
- zero_v3(cu->rot);
+
+ cu->texflag |= CU_AUTOSPACE_EVALUATED;
}
}
-BoundBox *BKE_curve_texspace_get(Curve *cu, float r_loc[3], float r_rot[3], float r_size[3])
+void BKE_curve_texspace_ensure(Curve *cu)
{
- if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
+ if ((cu->texflag & CU_AUTOSPACE) && !(cu->texflag & CU_AUTOSPACE_EVALUATED)) {
BKE_curve_texspace_calc(cu);
}
+}
+
+void BKE_curve_texspace_get(Curve *cu, float r_loc[3], float r_size[3])
+{
+ BKE_curve_texspace_ensure(cu);
if (r_loc) {
copy_v3_v3(r_loc, cu->loc);
}
- if (r_rot) {
- copy_v3_v3(r_rot, cu->rot);
- }
if (r_size) {
copy_v3_v3(r_size, cu->size);
}
-
- return cu->bb;
}
bool BKE_nurbList_index_get_co(ListBase *nurb, const int index, float r_co[3])
@@ -697,7 +657,7 @@ float BKE_nurb_calc_length(const Nurb *nu, int resolution)
a = nu->pntsu - 1;
bp = nu->bp;
if (nu->flagu & CU_NURB_CYCLIC) {
- ++a;
+ a++;
prevbp = nu->bp + (nu->pntsu - 1);
}
else {
@@ -708,7 +668,7 @@ float BKE_nurb_calc_length(const Nurb *nu, int resolution)
while (a--) {
length += len_v3v3(prevbp->vec, bp->vec);
prevbp = bp;
- ++bp;
+ bp++;
}
}
else if (nu->type == CU_BEZIER) {
@@ -716,12 +676,12 @@ float BKE_nurb_calc_length(const Nurb *nu, int resolution)
a = nu->pntsu - 1;
bezt = nu->bezt;
if (nu->flagu & CU_NURB_CYCLIC) {
- ++a;
+ a++;
prevbezt = nu->bezt + (nu->pntsu - 1);
}
else {
prevbezt = bezt;
- ++bezt;
+ bezt++;
}
while (a--) {
@@ -748,7 +708,7 @@ float BKE_nurb_calc_length(const Nurb *nu, int resolution)
}
}
prevbezt = bezt;
- ++bezt;
+ bezt++;
}
MEM_freeN(points);
@@ -2157,8 +2117,8 @@ static void tilt_bezpart(BezTriple *prevbezt,
for (a = 0; a < resolu; a++, fac += dfac) {
if (tilt_array) {
- if (nu->tilt_interp ==
- KEY_CU_EASE) { /* May as well support for tilt also 2.47 ease interp */
+ if (nu->tilt_interp == KEY_CU_EASE) {
+ /* May as well support for tilt also 2.47 ease interp. */
*tilt_array = prevbezt->tilt +
(bezt->tilt - prevbezt->tilt) * (3.0f * fac * fac - 2.0f * fac * fac * fac);
}
@@ -2382,7 +2342,7 @@ static void make_bevel_list_3D_minimum_twist(BevList *bl)
nr = bl->nr;
while (nr--) {
- if (nr + 4 > bl->nr) { /* first time and second time, otherwise first point adjusts last */
+ if (nr + 3 > bl->nr) { /* first time and second time, otherwise first point adjusts last */
vec_to_quat(bevp1->quat, bevp1->dir, 5, 1);
}
else {
@@ -4630,6 +4590,7 @@ void BKE_curve_nurbs_vert_coords_get(ListBase *lb, float (*vert_coords)[3], int
}
}
BLI_assert(co == vert_coords[vert_len]);
+ UNUSED_VARS_NDEBUG(vert_len);
}
float (*BKE_curve_nurbs_vert_coords_alloc(ListBase *lb, int *r_vert_len))[3]
@@ -5512,15 +5473,10 @@ void BKE_curve_eval_geometry(Depsgraph *depsgraph, Curve *curve)
BKE_curve_texspace_calc(curve);
if (DEG_is_active(depsgraph)) {
Curve *curve_orig = (Curve *)DEG_get_original_id(&curve->id);
- BoundBox *bb = curve->bb;
- if (bb != NULL) {
- if (curve_orig->bb == NULL) {
- curve_orig->bb = MEM_mallocN(sizeof(*curve_orig->bb), __func__);
- }
- *curve_orig->bb = *bb;
+ if (curve->texflag & CU_AUTOSPACE_EVALUATED) {
+ curve_orig->texflag |= CU_AUTOSPACE_EVALUATED;
copy_v3_v3(curve_orig->loc, curve->loc);
copy_v3_v3(curve_orig->size, curve->size);
- copy_v3_v3(curve_orig->rot, curve->rot);
}
}
}
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index db0ed0dc0fb..8ac0f71cd7e 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -173,7 +173,7 @@ static void layerCopy_mdeformvert(const void *source, void *dest, int count)
memcpy(dest, source, count * size);
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
MDeformVert *dvert = POINTER_OFFSET(dest, i * size);
if (dvert->totweight) {
@@ -193,7 +193,7 @@ static void layerFree_mdeformvert(void *data, int count, int size)
{
int i;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
MDeformVert *dvert = POINTER_OFFSET(data, i * size);
if (dvert->dw) {
@@ -209,7 +209,7 @@ static void layerCopy_bmesh_elem_py_ptr(const void *UNUSED(source), void *dest,
{
int i, size = sizeof(void *);
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
void **ptr = POINTER_OFFSET(dest, i * size);
*ptr = NULL;
}
@@ -226,7 +226,7 @@ static void layerFree_bmesh_elem_py_ptr(void *data, int count, int size)
{
int i;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
void **ptr = POINTER_OFFSET(data, i * size);
if (*ptr) {
bpy_bm_generic_invalidate(*ptr);
@@ -258,11 +258,11 @@ static void layerInterp_mdeformvert(const void **sources,
/* build a list of unique def_nrs for dest */
totweight = 0;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
const MDeformVert *source = sources[i];
float interp_weight = weights ? weights[i] : 1.0f;
- for (j = 0; j < source->totweight; ++j) {
+ for (j = 0; j < source->totweight; j++) {
MDeformWeight *dw = &source->dw[j];
float weight = dw->weight * interp_weight;
@@ -407,7 +407,7 @@ static void layerCopy_tface(const void *source, void *dest, int count)
MTFace *dest_tf = (MTFace *)dest;
int i;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
dest_tf[i] = source_tf[i];
}
}
@@ -425,13 +425,13 @@ static void layerInterp_tface(
}
sub_weight = sub_weights;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
float weight = weights ? weights[i] : 1;
const MTFace *src = sources[i];
- for (j = 0; j < 4; ++j) {
+ for (j = 0; j < 4; j++) {
if (sub_weights) {
- for (k = 0; k < 4; ++k, ++sub_weight) {
+ for (k = 0; k < 4; k++, sub_weight++) {
madd_v2_v2fl(uv[j], src->uv[k], (*sub_weight) * weight);
}
}
@@ -452,7 +452,7 @@ static void layerSwap_tface(void *data, const int *corner_indices)
float uv[4][2];
int j;
- for (j = 0; j < 4; ++j) {
+ for (j = 0; j < 4; j++) {
const int source_index = corner_indices[j];
copy_v2_v2(uv[j], tf->uv[source_index]);
}
@@ -514,7 +514,7 @@ static void layerCopy_origspace_face(const void *source, void *dest, int count)
OrigSpaceFace *dest_tf = (OrigSpaceFace *)dest;
int i;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
dest_tf[i] = source_tf[i];
}
}
@@ -532,13 +532,13 @@ static void layerInterp_origspace_face(
}
sub_weight = sub_weights;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
float weight = weights ? weights[i] : 1;
const OrigSpaceFace *src = sources[i];
- for (j = 0; j < 4; ++j) {
+ for (j = 0; j < 4; j++) {
if (sub_weights) {
- for (k = 0; k < 4; ++k, ++sub_weight) {
+ for (k = 0; k < 4; k++, sub_weight++) {
madd_v2_v2fl(uv[j], src->uv[k], (*sub_weight) * weight);
}
}
@@ -558,7 +558,7 @@ static void layerSwap_origspace_face(void *data, const int *corner_indices)
float uv[4][2];
int j;
- for (j = 0; j < 4; ++j) {
+ for (j = 0; j < 4; j++) {
copy_v2_v2(uv[j], osf->uv[corner_indices[j]]);
}
memcpy(osf->uv, uv, sizeof(osf->uv));
@@ -613,7 +613,7 @@ static void layerCopy_mdisps(const void *source, void *dest, int count)
const MDisps *s = source;
MDisps *d = dest;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
if (s[i].disps) {
d[i].disps = MEM_dupallocN(s[i].disps);
d[i].hidden = MEM_dupallocN(s[i].hidden);
@@ -634,7 +634,7 @@ static void layerFree_mdisps(void *data, int count, int UNUSED(size))
int i;
MDisps *d = data;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
if (d[i].disps) {
MEM_freeN(d[i].disps);
}
@@ -653,7 +653,7 @@ static int layerRead_mdisps(CDataFile *cdf, void *data, int count)
MDisps *d = data;
int i;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
if (!d[i].disps) {
d[i].disps = MEM_calloc_arrayN(d[i].totdisp, 3 * sizeof(float), "mdisps read");
}
@@ -672,7 +672,7 @@ static int layerWrite_mdisps(CDataFile *cdf, const void *data, int count)
const MDisps *d = data;
int i;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
if (!cdf_write_data(cdf, d[i].totdisp * 3 * sizeof(float), d[i].disps)) {
CLOG_ERROR(&LOG, "failed to write multires displacement %d/%d %d", i, count, d[i].totdisp);
return 0;
@@ -688,7 +688,7 @@ static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), const void *data, int
size_t size = 0;
int i;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
size += d[i].totdisp * 3 * sizeof(float);
}
@@ -701,7 +701,7 @@ static void layerCopy_grid_paint_mask(const void *source, void *dest, int count)
const GridPaintMask *s = source;
GridPaintMask *d = dest;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
if (s[i].data) {
d[i].data = MEM_dupallocN(s[i].data);
d[i].level = s[i].level;
@@ -718,7 +718,7 @@ static void layerFree_grid_paint_mask(void *data, int count, int UNUSED(size))
int i;
GridPaintMask *gpm = data;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
if (gpm[i].data) {
MEM_freeN(gpm[i].data);
}
@@ -887,7 +887,7 @@ static void layerInterp_mloopcol(
} col = {0};
const float *sub_weight = sub_weights;
- for (int i = 0; i < count; ++i) {
+ for (int i = 0; i < count; i++) {
float weight = weights ? weights[i] : 1;
const MLoopCol *src = sources[i];
if (sub_weights) {
@@ -1128,13 +1128,13 @@ static void layerInterp_mcol(
}
sub_weight = sub_weights;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
float weight = weights ? weights[i] : 1;
- for (j = 0; j < 4; ++j) {
+ for (j = 0; j < 4; j++) {
if (sub_weights) {
const MCol *src = sources[i];
- for (k = 0; k < 4; ++k, ++sub_weight, ++src) {
+ for (k = 0; k < 4; k++, sub_weight++, src++) {
const float w = (*sub_weight) * weight;
col[j].a += src->a * w;
col[j].r += src->r * w;
@@ -1153,7 +1153,7 @@ static void layerInterp_mcol(
}
/* Delay writing to the destination in case dest is in sources. */
- for (j = 0; j < 4; ++j) {
+ for (j = 0; j < 4; j++) {
/* Subdivide smooth or fractal can cause problems without clamping
* although weights should also not cause this situation */
@@ -1170,7 +1170,7 @@ static void layerSwap_mcol(void *data, const int *corner_indices)
MCol col[4];
int j;
- for (j = 0; j < 4; ++j) {
+ for (j = 0; j < 4; j++) {
col[j] = mcol[corner_indices[j]];
}
@@ -1210,12 +1210,12 @@ static void layerInterp_bweight(const void **sources,
f = 0.0f;
if (weights) {
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
f += *in[i] * weights[i];
}
}
else {
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
f += *in[i];
}
}
@@ -1241,12 +1241,12 @@ static void layerInterp_shapekey(const void **sources,
zero_v3(co);
if (weights) {
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
madd_v3_v3fl(co, in[i], weights[i]);
}
}
else {
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
add_v3_v3(co, in[i]);
}
}
@@ -1862,7 +1862,7 @@ bool CustomData_merge(const struct CustomData *source,
int number = 0, maxnumber = -1;
bool changed = false;
- for (i = 0; i < source->totlayer; ++i) {
+ for (i = 0; i < source->totlayer; i++) {
layer = &source->layers[i];
/*typeInfo = layerType_getInfo(layer->type);*/ /*UNUSED*/
@@ -1934,7 +1934,7 @@ bool CustomData_merge(const struct CustomData *source,
void CustomData_realloc(CustomData *data, int totelem)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
CustomDataLayer *layer = &data->layers[i];
const LayerTypeInfo *typeInfo;
if (layer->flag & CD_FLAG_NOFREE) {
@@ -1995,7 +1995,7 @@ void CustomData_free(CustomData *data, int totelem)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
customData_free_layer__internal(&data->layers[i], totelem);
}
@@ -2011,7 +2011,7 @@ void CustomData_free_typemask(struct CustomData *data, int totelem, CustomDataMa
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
CustomDataLayer *layer = &data->layers[i];
if (!(mask & CD_TYPE_AS_MASK(layer->type))) {
continue;
@@ -2032,7 +2032,7 @@ static void customData_update_offsets(CustomData *data)
const LayerTypeInfo *typeInfo;
int i, offset = 0;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
typeInfo = layerType_getInfo(data->layers[i].type);
data->layers[i].offset = offset;
@@ -2048,7 +2048,7 @@ static int CustomData_get_layer_index__notypemap(const CustomData *data, int typ
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
return i;
}
@@ -2082,7 +2082,7 @@ int CustomData_get_named_layer_index(const CustomData *data, int type, const cha
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
if (STREQ(data->layers[i].name, name)) {
return i;
@@ -2164,7 +2164,7 @@ void CustomData_set_layer_active(CustomData *data, int type, int n)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
data->layers[i].active = n;
}
@@ -2175,7 +2175,7 @@ void CustomData_set_layer_render(CustomData *data, int type, int n)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
data->layers[i].active_rnd = n;
}
@@ -2186,7 +2186,7 @@ void CustomData_set_layer_clone(CustomData *data, int type, int n)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
data->layers[i].active_clone = n;
}
@@ -2197,7 +2197,7 @@ void CustomData_set_layer_stencil(CustomData *data, int type, int n)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
data->layers[i].active_mask = n;
}
@@ -2210,7 +2210,7 @@ void CustomData_set_layer_active_index(CustomData *data, int type, int n)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
data->layers[i].active = n - i;
}
@@ -2221,7 +2221,7 @@ void CustomData_set_layer_render_index(CustomData *data, int type, int n)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
data->layers[i].active_rnd = n - i;
}
@@ -2232,7 +2232,7 @@ void CustomData_set_layer_clone_index(CustomData *data, int type, int n)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
data->layers[i].active_clone = n - i;
}
@@ -2243,7 +2243,7 @@ void CustomData_set_layer_stencil_index(CustomData *data, int type, int n)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
data->layers[i].active_mask = n - i;
}
@@ -2254,7 +2254,7 @@ void CustomData_set_layer_flag(struct CustomData *data, int type, int flag)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
data->layers[i].flag |= flag;
}
@@ -2265,7 +2265,7 @@ void CustomData_clear_layer_flag(struct CustomData *data, int type, int flag)
{
const int nflag = ~flag;
- for (int i = 0; i < data->totlayer; ++i) {
+ for (int i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
data->layers[i].flag &= nflag;
}
@@ -2355,7 +2355,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
data->totlayer++;
/* keep layers ordered by type */
- for (; index > 0 && data->layers[index - 1].type > type; --index) {
+ for (; index > 0 && data->layers[index - 1].type > type; index--) {
data->layers[index] = data->layers[index - 1];
}
@@ -2447,7 +2447,7 @@ bool CustomData_free_layer(CustomData *data, int type, int totelem, int index)
customData_free_layer__internal(&data->layers[index], totelem);
- for (i = index + 1; i < data->totlayer; ++i) {
+ for (i = index + 1; i < data->totlayer; i++) {
data->layers[i - 1] = data->layers[i];
}
@@ -2628,7 +2628,7 @@ void CustomData_free_temporary(CustomData *data, int totelem)
int i, j;
bool changed = false;
- for (i = 0, j = 0; i < data->totlayer; ++i) {
+ for (i = 0, j = 0; i < data->totlayer; i++) {
layer = &data->layers[i];
if (i != j) {
@@ -2660,7 +2660,7 @@ void CustomData_set_only_copy(const struct CustomData *data, CustomDataMask mask
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (!(mask & CD_TYPE_AS_MASK(data->layers[i].type))) {
data->layers[i].flag |= CD_FLAG_NOCOPY;
}
@@ -2725,7 +2725,7 @@ void CustomData_copy_data_named(
int src_i, dest_i;
/* copies a layer at a time */
- for (src_i = 0; src_i < source->totlayer; ++src_i) {
+ for (src_i = 0; src_i < source->totlayer; src_i++) {
dest_i = CustomData_get_named_layer_index(
dest, source->layers[src_i].type, source->layers[src_i].name);
@@ -2744,7 +2744,7 @@ void CustomData_copy_data(
/* copies a layer at a time */
dest_i = 0;
- for (src_i = 0; src_i < source->totlayer; ++src_i) {
+ for (src_i = 0; src_i < source->totlayer; src_i++) {
/* find the first dest layer with type >= the source type
* (this should work because layers are ordered by type)
@@ -2800,7 +2800,7 @@ void CustomData_free_elem(CustomData *data, int index, int count)
int i;
const LayerTypeInfo *typeInfo;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
typeInfo = layerType_getInfo(data->layers[i].type);
@@ -2835,7 +2835,7 @@ void CustomData_interp(const CustomData *source,
/* interpolates a layer at a time */
dest_i = 0;
- for (src_i = 0; src_i < source->totlayer; ++src_i) {
+ for (src_i = 0; src_i < source->totlayer; src_i++) {
const LayerTypeInfo *typeInfo = layerType_getInfo(source->layers[src_i].type);
if (!typeInfo->interp) {
continue;
@@ -2857,7 +2857,7 @@ void CustomData_interp(const CustomData *source,
if (dest->layers[dest_i].type == source->layers[src_i].type) {
void *src_data = source->layers[src_i].data;
- for (j = 0; j < count; ++j) {
+ for (j = 0; j < count; j++) {
sources[j] = POINTER_OFFSET(src_data, (size_t)src_indices[j] * typeInfo->size);
}
@@ -2893,7 +2893,7 @@ void CustomData_swap_corners(struct CustomData *data, int index, const int *corn
const LayerTypeInfo *typeInfo;
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
typeInfo = layerType_getInfo(data->layers[i].type);
if (typeInfo->swap) {
@@ -2916,7 +2916,7 @@ void CustomData_swap(struct CustomData *data, const int index_a, const int index
return;
}
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type);
const size_t size = typeInfo->size;
const size_t offset_a = size * index_a;
@@ -3392,7 +3392,7 @@ void CustomData_bmesh_free_block(CustomData *data, void **block)
return;
}
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
typeInfo = layerType_getInfo(data->layers[i].type);
@@ -3422,7 +3422,7 @@ void CustomData_bmesh_free_block_data(CustomData *data, void *block)
return;
}
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
typeInfo = layerType_getInfo(data->layers[i].type);
@@ -3476,7 +3476,7 @@ void CustomData_bmesh_set_default(CustomData *data, void **block)
CustomData_bmesh_alloc_block(data, block);
}
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
CustomData_bmesh_set_default_n(data, block, i);
}
}
@@ -3498,7 +3498,7 @@ void CustomData_bmesh_copy_data(const CustomData *source,
/* copies a layer at a time */
dest_i = 0;
- for (src_i = 0; src_i < source->totlayer; ++src_i) {
+ for (src_i = 0; src_i < source->totlayer; src_i++) {
/* find the first dest layer with type >= the source type
* (this should work because layers are ordered by type)
@@ -3609,7 +3609,7 @@ bool CustomData_has_math(const struct CustomData *data)
int i;
/* interpolates a layer at a time */
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (CustomData_layer_has_math(data, i)) {
return true;
}
@@ -3624,7 +3624,7 @@ bool CustomData_bmesh_has_free(const struct CustomData *data)
const LayerTypeInfo *typeInfo;
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
typeInfo = layerType_getInfo(data->layers[i].type);
if (typeInfo->free) {
@@ -3640,7 +3640,7 @@ bool CustomData_has_interp(const struct CustomData *data)
int i;
/* interpolates a layer at a time */
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (CustomData_layer_has_interp(data, i)) {
return true;
}
@@ -3652,7 +3652,7 @@ bool CustomData_has_interp(const struct CustomData *data)
bool CustomData_has_referenced(const struct CustomData *data)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].flag & CD_FLAG_NOFREE) {
return true;
}
@@ -3832,11 +3832,11 @@ void CustomData_bmesh_interp(CustomData *data,
}
/* interpolates a layer at a time */
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
CustomDataLayer *layer = &data->layers[i];
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
if (typeInfo->interp) {
- for (j = 0; j < count; ++j) {
+ for (j = 0; j < count; j++) {
sources[j] = POINTER_OFFSET(src_blocks[j], layer->offset);
}
CustomData_bmesh_interp_n(
@@ -3869,7 +3869,7 @@ void CustomData_to_bmesh_block(const CustomData *source,
/* copies a layer at a time */
dest_i = 0;
- for (src_i = 0; src_i < source->totlayer; ++src_i) {
+ for (src_i = 0; src_i < source->totlayer; src_i++) {
/* find the first dest layer with type >= the source type
* (this should work because layers are ordered by type)
@@ -3927,7 +3927,7 @@ void CustomData_from_bmesh_block(const CustomData *source,
/* copies a layer at a time */
dest_i = 0;
- for (src_i = 0; src_i < source->totlayer; ++src_i) {
+ for (src_i = 0; src_i < source->totlayer; src_i++) {
/* find the first dest layer with type >= the source type
* (this should work because layers are ordered by type)
@@ -4181,7 +4181,7 @@ bool CustomData_verify_versions(struct CustomData *data, int index)
if (!typeInfo->defaultname && (index > 0) && data->layers[index - 1].type == layer->type) {
keeplayer = false; /* multiple layers of which we only support one */
}
- /* This is a pre-emptive fix for cases that should not happen
+ /* This is a preemptive fix for cases that should not happen
* (layers that should not be written in .blend files),
* but can happen due to bugs (see e.g. T62318).
* Also for forward compatibility, in future,
@@ -4198,7 +4198,7 @@ bool CustomData_verify_versions(struct CustomData *data, int index)
}
if (!keeplayer) {
- for (i = index + 1; i < data->totlayer; ++i) {
+ for (i = index + 1; i < data->totlayer; i++) {
data->layers[i - 1] = data->layers[i];
}
data->totlayer--;
diff --git a/source/blender/blenkernel/intern/editlattice.c b/source/blender/blenkernel/intern/editlattice.c
index 12e737bbaa8..2d71b847b5b 100644
--- a/source/blender/blenkernel/intern/editlattice.c
+++ b/source/blender/blenkernel/intern/editlattice.c
@@ -92,6 +92,21 @@ void BKE_editlattice_load(Object *obedit)
lt = obedit->data;
editlt = lt->editlatt->latt;
+ MEM_freeN(lt->def);
+
+ lt->def = MEM_dupallocN(editlt->def);
+
+ lt->flag = editlt->flag;
+
+ lt->pntsu = editlt->pntsu;
+ lt->pntsv = editlt->pntsv;
+ lt->pntsw = editlt->pntsw;
+
+ lt->typeu = editlt->typeu;
+ lt->typev = editlt->typev;
+ lt->typew = editlt->typew;
+ lt->actbp = editlt->actbp;
+
if (lt->editlatt->shapenr) {
actkey = BLI_findlink(&lt->key->block, lt->editlatt->shapenr - 1);
@@ -112,22 +127,6 @@ void BKE_editlattice_load(Object *obedit)
bp++;
}
}
- else {
- MEM_freeN(lt->def);
-
- lt->def = MEM_dupallocN(editlt->def);
-
- lt->flag = editlt->flag;
-
- lt->pntsu = editlt->pntsu;
- lt->pntsv = editlt->pntsv;
- lt->pntsw = editlt->pntsw;
-
- lt->typeu = editlt->typeu;
- lt->typev = editlt->typev;
- lt->typew = editlt->typew;
- lt->actbp = editlt->actbp;
- }
if (lt->dvert) {
BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index 866c494d354..d929c953b89 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -32,6 +32,8 @@
#include "BKE_editmesh.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate)
{
@@ -51,6 +53,7 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
*em_copy = *em;
em_copy->mesh_eval_cage = em_copy->mesh_eval_final = NULL;
+ em_copy->bb_cage = NULL;
em_copy->derivedVertColor = NULL;
em_copy->derivedVertColorLen = 0;
@@ -151,6 +154,8 @@ void BKE_editmesh_free_derivedmesh(BMEditMesh *em)
BKE_id_free(NULL, em->mesh_eval_final);
}
em->mesh_eval_cage = em->mesh_eval_final = NULL;
+
+ MEM_SAFE_FREE(em->bb_cage);
}
/*does not free the BMEditMesh struct itself*/
@@ -257,3 +262,19 @@ void BKE_editmesh_ensure_autosmooth(BMEditMesh *em)
BKE_editmesh_lnorspace_update(em);
}
}
+
+BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em)
+{
+ if (em->bb_cage == NULL) {
+ float min[3], max[3];
+ INIT_MINMAX(min, max);
+ if (em->mesh_eval_cage) {
+ BKE_mesh_minmax(em->mesh_eval_cage, min, max);
+ }
+
+ em->bb_cage = MEM_callocN(sizeof(BoundBox), "BMEditMesh.bb_cage");
+ BKE_boundbox_init_from_minmax(em->bb_cage, min, max);
+ }
+
+ return em->bb_cage;
+}
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 657a08877b0..b596eeb9e35 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -1714,7 +1714,10 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
* of scale over all three axes unless the matrix includes shear. */
return cbrtf(mat4_to_volume_scale(mat));
}
- else if (dtar->transChan >= DTAR_TRANSCHAN_SCALEX) {
+ else if (ELEM(dtar->transChan,
+ DTAR_TRANSCHAN_SCALEX,
+ DTAR_TRANSCHAN_SCALEY,
+ DTAR_TRANSCHAN_SCALEZ)) {
/* Extract scale, and choose the right axis,
* inline 'mat4_to_size'. */
return len_v3(mat[dtar->transChan - DTAR_TRANSCHAN_SCALEX]);
@@ -1728,15 +1731,25 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
* b) [NOT USED] directly use the original values (no decomposition)
* - only an option for "transform space", if quality is really bad with a)
*/
- float eul[3];
+ float quat[4];
+ int channel;
- mat4_to_eulO(eul, rot_order, mat);
+ if (dtar->transChan == DTAR_TRANSCHAN_ROTW) {
+ channel = 0;
+ }
+ else {
+ channel = 1 + dtar->transChan - DTAR_TRANSCHAN_ROTX;
+ BLI_assert(channel < 4);
+ }
- if (use_eulers) {
- compatible_eul(eul, oldEul);
+ BKE_driver_target_matrix_to_rot_channels(
+ mat, rot_order, dtar->rotation_mode, channel, false, quat);
+
+ if (use_eulers && dtar->rotation_mode == DTAR_ROTMODE_AUTO) {
+ compatible_eul(quat + 1, oldEul);
}
- return eul[dtar->transChan - DTAR_TRANSCHAN_ROTX];
+ return quat[channel];
}
else {
/* extract location and choose right axis */
@@ -1744,6 +1757,71 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
}
}
+/* Convert a quaternion to pseudo-angles representing the weighted amount of rotation. */
+static void quaternion_to_angles(float quat[4], int channel)
+{
+ if (channel < 0) {
+ quat[0] = 2.0f * saacosf(quat[0]);
+
+ for (int i = 1; i < 4; i++) {
+ quat[i] = 2.0f * saasinf(quat[i]);
+ }
+ }
+ else if (channel == 0) {
+ quat[0] = 2.0f * saacosf(quat[0]);
+ }
+ else {
+ quat[channel] = 2.0f * saasinf(quat[channel]);
+ }
+}
+
+/* Compute channel values for a rotational Transform Channel driver variable. */
+void BKE_driver_target_matrix_to_rot_channels(
+ float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4])
+{
+ float *const quat = r_buf;
+ float *const eul = r_buf + 1;
+
+ zero_v4(r_buf);
+
+ if (rotation_mode == DTAR_ROTMODE_AUTO) {
+ mat4_to_eulO(eul, auto_order, mat);
+ }
+ else if (rotation_mode >= DTAR_ROTMODE_EULER_MIN && rotation_mode <= DTAR_ROTMODE_EULER_MAX) {
+ mat4_to_eulO(eul, rotation_mode, mat);
+ }
+ else if (rotation_mode == DTAR_ROTMODE_QUATERNION) {
+ mat4_to_quat(quat, mat);
+
+ /* For Transformation constraint convenience, convert to pseudo-angles. */
+ if (angles) {
+ quaternion_to_angles(quat, channel);
+ }
+ }
+ else if (rotation_mode >= DTAR_ROTMODE_SWING_TWIST_X &&
+ rotation_mode <= DTAR_ROTMODE_SWING_TWIST_Z) {
+ int axis = rotation_mode - DTAR_ROTMODE_SWING_TWIST_X;
+ float raw_quat[4], twist;
+
+ mat4_to_quat(raw_quat, mat);
+
+ if (channel == axis + 1) {
+ /* If only the twist angle is needed, skip computing swing. */
+ twist = quat_split_swing_and_twist(raw_quat, axis, NULL, NULL);
+ }
+ else {
+ twist = quat_split_swing_and_twist(raw_quat, axis, quat, NULL);
+
+ quaternion_to_angles(quat, channel);
+ }
+
+ quat[axis + 1] = twist;
+ }
+ else {
+ BLI_assert(false);
+ }
+}
+
/* ......... */
/* Table of Driver Variable Type Info Data */
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index d4bf76ea44a..f78833a0ebe 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -48,14 +48,18 @@
#include "BKE_action.h"
#include "BKE_animsys.h"
+#include "BKE_curve.h"
+#include "BKE_collection.h"
+#include "BKE_colortools.h"
#include "BKE_deform.h"
#include "BKE_gpencil.h"
-#include "BKE_colortools.h"
#include "BKE_icons.h"
#include "BKE_library.h"
#include "BKE_main.h"
-#include "BKE_object.h"
#include "BKE_material.h"
+#include "BKE_object.h"
+
+#include "BLI_math_color.h"
#include "DEG_depsgraph.h"
@@ -263,7 +267,8 @@ bGPDframe *BKE_gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
/* check whether frame was added successfully */
if (state == -1) {
- CLOG_ERROR(&LOG, "Frame (%d) existed already for this layer. Using existing frame", cframe);
+ CLOG_ERROR(
+ &LOG, "Frame (%d) existed already for this layer_active. Using existing frame", cframe);
/* free the newly created one, and use the old one instead */
MEM_freeN(gpf);
@@ -422,9 +427,9 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
/* grid settings */
- ARRAY_SET_ITEMS(gpd->grid.color, 0.5f, 0.5f, 0.5f); // Color
- ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); // Scale
- gpd->grid.lines = GP_DEFAULT_GRID_LINES; // Number of lines
+ ARRAY_SET_ITEMS(gpd->grid.color, 0.5f, 0.5f, 0.5f); /* Color */
+ ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); /* Scale */
+ gpd->grid.lines = GP_DEFAULT_GRID_LINES; /* Number of lines */
/* onion-skinning settings (datablock level) */
gpd->onion_flag |= (GP_ONION_GHOST_PREVCOL | GP_ONION_GHOST_NEXTCOL);
@@ -659,7 +664,7 @@ bGPdata *BKE_gpencil_copy(Main *bmain, const bGPdata *gpd)
}
/* make a copy of a given gpencil datablock */
-// XXX: Should this be deprecated?
+/* XXX: Should this be deprecated? */
bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy)
{
bGPdata *gpd_dst;
@@ -802,7 +807,7 @@ bGPDframe *BKE_gpencil_layer_find_frame(bGPDlayer *gpl, int cframe)
bGPDframe *BKE_gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
{
bGPDframe *gpf = NULL;
- short found = 0;
+ bool found = false;
/* error checking */
if (gpl == NULL) {
@@ -828,11 +833,11 @@ bGPDframe *BKE_gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_M
if (gpf->framenum < cframe) {
for (; gpf; gpf = gpf->next) {
if (gpf->framenum == cframe) {
- found = 1;
+ found = true;
break;
}
else if ((gpf->next) && (gpf->next->framenum > cframe)) {
- found = 1;
+ found = true;
break;
}
}
@@ -859,7 +864,7 @@ bGPDframe *BKE_gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_M
else {
for (; gpf; gpf = gpf->prev) {
if (gpf->framenum <= cframe) {
- found = 1;
+ found = true;
break;
}
}
@@ -893,7 +898,7 @@ bGPDframe *BKE_gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_M
/* find gp-frame which is less than or equal to cframe */
for (gpf = gpl->frames.last; gpf; gpf = gpf->prev) {
if (gpf->framenum <= cframe) {
- found = 1;
+ found = true;
break;
}
}
@@ -902,7 +907,7 @@ bGPDframe *BKE_gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_M
/* find gp-frame which is less than or equal to cframe */
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
if (gpf->framenum <= cframe) {
- found = 1;
+ found = true;
break;
}
}
@@ -1011,6 +1016,39 @@ void BKE_gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active)
}
}
+/* Set locked layers for autolock mode. */
+void BKE_gpencil_layer_autolock_set(bGPdata *gpd, const bool unlock)
+{
+ BLI_assert(gpd != NULL);
+
+ bGPDlayer *gpl;
+
+ if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) {
+ bGPDlayer *layer_active = BKE_gpencil_layer_getactive(gpd);
+
+ /* Lock all other layers */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* unlock active layer */
+ if (gpl == layer_active) {
+ gpl->flag &= ~GP_LAYER_LOCKED;
+ }
+ else {
+ gpl->flag |= GP_LAYER_LOCKED;
+ }
+ }
+ }
+ else {
+ /* If disable is better unlock all layers by default or it looks there is
+ * a problem in the UI because the user expects all layers will be unlocked
+ */
+ if (unlock) {
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpl->flag &= ~GP_LAYER_LOCKED;
+ }
+ }
+ }
+}
+
/* delete the active gp-layer */
void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
{
@@ -1161,38 +1199,34 @@ Material *BKE_gpencil_object_material_ensure_from_active_input_brush(Main *bmain
brush->gpencil_settings->flag &= ~GP_BRUSH_MATERIAL_PINNED;
}
}
- return BKE_gpencil_object_material_ensure_from_active_input_material(bmain, ob);
+ return BKE_gpencil_object_material_ensure_from_active_input_material(ob);
}
/**
* Guaranteed to return a material assigned to object. Returns never NULL.
* Only use this for materials unrelated to user input.
*/
-Material *BKE_gpencil_object_material_ensure_from_active_input_material(Main *bmain, Object *ob)
+Material *BKE_gpencil_object_material_ensure_from_active_input_material(Object *ob)
{
Material *ma = give_current_material(ob, ob->actcol);
if (ma) {
return ma;
}
- /* If the slot is empty, remove because will be added again,
- * if not, we will get an empty slot. */
- if ((ob->totcol > 0) && (ob->actcol == ob->totcol)) {
- BKE_object_material_slot_remove(bmain, ob);
- }
- return BKE_gpencil_object_material_new(bmain, ob, "Material", NULL);
+
+ return &defgpencil_material;
}
/* Get active color, and add all default settings if we don't find anything */
-Material *BKE_gpencil_object_material_ensure_active(Main *bmain, Object *ob)
+Material *BKE_gpencil_object_material_ensure_active(Object *ob)
{
Material *ma = NULL;
/* sanity checks */
- if (ELEM(NULL, bmain, ob)) {
+ if (ob == NULL) {
return NULL;
}
- ma = BKE_gpencil_object_material_ensure_from_active_input_material(bmain, ob);
+ ma = BKE_gpencil_object_material_ensure_from_active_input_material(ob);
if (ma->gp_style == NULL) {
BKE_material_init_gpencil_settings(ma);
}
@@ -1421,11 +1455,11 @@ static void stroke_defvert_create_nr_list(MDeformVert *dv_list,
/* find def_nr in list, if not exist, then create one */
for (j = 0; j < dv->totweight; j++) {
- int found = 0;
+ bool found = false;
dw = &dv->dw[j];
for (ld = result->first; ld; ld = ld->next) {
if (ld->data == POINTER_FROM_INT(dw->def_nr)) {
- found = 1;
+ found = true;
break;
}
}
@@ -1447,10 +1481,9 @@ static MDeformVert *stroke_defvert_new_count(int count, int totweight, ListBase
LinkData *ld;
MDeformVert *dst = MEM_mallocN(count * sizeof(MDeformVert), "new_deformVert");
- dst->totweight = totweight;
-
for (i = 0; i < count; i++) {
dst[i].dw = MEM_mallocN(sizeof(MDeformWeight) * totweight, "new_deformWeight");
+ dst[i].totweight = totweight;
j = 0;
/* re-assign deform groups */
for (ld = def_nr_list->first; ld; ld = ld->next) {
@@ -1640,7 +1673,7 @@ bool BKE_gpencil_sample_stroke(bGPDstroke *gps, const float dist, const bool sel
int result_totweight;
if (gps->dvert != NULL) {
- stroke_defvert_create_nr_list(gps->dvert, count, &def_nr_list, &result_totweight);
+ stroke_defvert_create_nr_list(gps->dvert, gps->totpoints, &def_nr_list, &result_totweight);
new_dv = stroke_defvert_new_count(count, result_totweight, &def_nr_list);
}
@@ -1696,17 +1729,22 @@ bool BKE_gpencil_sample_stroke(bGPDstroke *gps, const float dist, const bool sel
}
gps->points = new_pt;
- gps->totpoints = i;
- MEM_freeN(pt); /* original */
+ /* Free original vertex list. */
+ MEM_freeN(pt);
if (new_dv) {
+ /* Free original weight data. */
BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
while ((ld = BLI_pophead(&def_nr_list))) {
MEM_freeN(ld);
}
+
gps->dvert = new_dv;
}
+ gps->totpoints = i;
+
gps->flag |= GP_STROKE_RECALC_GEOMETRY;
gps->tot_triangles = 0;
@@ -1722,7 +1760,6 @@ bool BKE_gpencil_sample_stroke(bGPDstroke *gps, const float dist, const bool sel
bool BKE_gpencil_smooth_stroke(bGPDstroke *gps, int i, float inf)
{
bGPDspoint *pt = &gps->points[i];
- // float pressure = 0.0f;
float sco[3] = {0.0f};
/* Do nothing if not enough points to smooth out */
@@ -2008,6 +2045,7 @@ void BKE_gpencil_material_index_reassign(bGPdata *gpd, int totcol, int index)
/* reassign strokes */
if ((gps->mat_nr > index) || (gps->mat_nr > totcol - 1)) {
gps->mat_nr--;
+ CLAMP_MIN(gps->mat_nr, 0);
}
}
}
@@ -2575,3 +2613,401 @@ void BKE_gpencil_merge_distance_stroke(bGPDframe *gpf,
BKE_gpencil_dissolve_points(gpf, gps, GP_SPOINT_TAG);
}
}
+
+/* Helper: Check materials with same color. */
+static int gpencil_check_same_material_color(Object *ob_gp, float color[4], Material **r_mat)
+{
+ Material *ma = NULL;
+ float color_cu[4];
+ linearrgb_to_srgb_v3_v3(color_cu, color);
+ float hsv1[4];
+ rgb_to_hsv_v(color_cu, hsv1);
+ hsv1[3] = color[3];
+
+ for (int i = 1; i <= ob_gp->totcol; i++) {
+ ma = give_current_material(ob_gp, i);
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ /* Check color with small tolerance (better in HSV). */
+ float hsv2[4];
+ rgb_to_hsv_v(gp_style->fill_rgba, hsv2);
+ hsv2[3] = gp_style->fill_rgba[3];
+ if ((gp_style->fill_style == GP_STYLE_FILL_STYLE_SOLID) && (compare_v4v4(hsv1, hsv2, 0.01f))) {
+ *r_mat = ma;
+ return i - 1;
+ }
+ }
+
+ *r_mat = NULL;
+ return -1;
+}
+
+/* Helper: Add gpencil material using curve material as base. */
+static Material *gpencil_add_from_curve_material(Main *bmain,
+ Object *ob_gp,
+ const float cu_color[4],
+ const bool gpencil_lines,
+ const bool fill,
+ int *r_idx)
+{
+ Material *mat_gp = BKE_gpencil_object_material_new(
+ bmain, ob_gp, (fill) ? "Material" : "Unassigned", r_idx);
+ MaterialGPencilStyle *gp_style = mat_gp->gp_style;
+
+ /* Stroke color. */
+ if (gpencil_lines) {
+ ARRAY_SET_ITEMS(gp_style->stroke_rgba, 0.0f, 0.0f, 0.0f, 1.0f);
+ gp_style->flag |= GP_STYLE_STROKE_SHOW;
+ }
+ else {
+ linearrgb_to_srgb_v4(gp_style->stroke_rgba, cu_color);
+ gp_style->flag &= ~GP_STYLE_STROKE_SHOW;
+ }
+
+ /* Fill color. */
+ linearrgb_to_srgb_v4(gp_style->fill_rgba, cu_color);
+ /* Fill is false if the original curve hasn't material assigned, so enable it. */
+ if (fill) {
+ gp_style->flag |= GP_STYLE_FILL_SHOW;
+ }
+
+ /* Check at least one is enabled. */
+ if (((gp_style->flag & GP_STYLE_STROKE_SHOW) == 0) &&
+ ((gp_style->flag & GP_STYLE_FILL_SHOW) == 0)) {
+ gp_style->flag |= GP_STYLE_STROKE_SHOW;
+ }
+
+ return mat_gp;
+}
+
+/* Helper: Create new stroke section. */
+static void gpencil_add_new_points(bGPDstroke *gps,
+ float *coord_array,
+ float pressure,
+ int init,
+ int totpoints,
+ const float init_co[3],
+ bool last)
+{
+ for (int i = 0; i < totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i + init];
+ copy_v3_v3(&pt->x, &coord_array[3 * i]);
+ /* Be sure the last point is not on top of the first point of the curve or
+ * the close of the stroke will produce glitches. */
+ if ((last) && (i > 0) && (i == totpoints - 1)) {
+ float dist = len_v3v3(init_co, &pt->x);
+ if (dist < 0.1f) {
+ /* Interpolate between previous point and current to back slightly. */
+ bGPDspoint *pt_prev = &gps->points[i + init - 1];
+ interp_v3_v3v3(&pt->x, &pt_prev->x, &pt->x, 0.95f);
+ }
+ }
+
+ pt->pressure = pressure;
+ pt->strength = 1.0f;
+ }
+}
+
+/* Helper: Get the first collection that includes the object. */
+static Collection *gpencil_get_parent_collection(Scene *scene, Object *ob)
+{
+ Collection *mycol = NULL;
+ FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ if ((mycol == NULL) && (cob->ob == ob)) {
+ mycol = collection;
+ }
+ }
+ }
+ FOREACH_SCENE_COLLECTION_END;
+
+ return mycol;
+}
+
+/* Helper: Convert one spline to grease pencil stroke. */
+static void gpencil_convert_spline(Main *bmain,
+ Object *ob_gp,
+ Object *ob_cu,
+ const bool gpencil_lines,
+ const bool only_stroke,
+ bGPDframe *gpf,
+ Nurb *nu)
+{
+ Curve *cu = (Curve *)ob_cu->data;
+ bool cyclic = true;
+
+ /* Create Stroke. */
+ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
+ gps->thickness = 1.0f;
+ gps->gradient_f = 1.0f;
+ ARRAY_SET_ITEMS(gps->gradient_s, 1.0f, 1.0f);
+ ARRAY_SET_ITEMS(gps->caps, GP_STROKE_CAP_ROUND, GP_STROKE_CAP_ROUND);
+ gps->inittime = 0.0f;
+
+ /* Enable recalculation flag by default. */
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps->flag &= ~GP_STROKE_SELECT;
+ gps->flag |= GP_STROKE_3DSPACE;
+
+ gps->mat_nr = 0;
+ /* Count total points
+ * The total of points must consider that last point of each segment is equal to the first
+ * point of next segment.
+ */
+ int totpoints = 0;
+ int segments = 0;
+ int resolu = nu->resolu + 1;
+ segments = nu->pntsu;
+ if (((nu->flagu & CU_NURB_CYCLIC) == 0) || (nu->pntsu == 2)) {
+ segments--;
+ cyclic = false;
+ }
+ totpoints = (resolu * segments) - (segments - 1);
+
+ /* Initialize triangle memory to dummy data. */
+ gps->tot_triangles = 0;
+ gps->triangles = NULL;
+
+ /* Materials
+ * Notice: The color of the material is the color of viewport and not the final shader color.
+ */
+ Material *mat_gp = NULL;
+ bool fill = true;
+ /* Check if grease pencil has a material with same color.*/
+ float color[4];
+ if ((cu->mat) && (*cu->mat)) {
+ Material *mat_cu = *cu->mat;
+ copy_v4_v4(color, &mat_cu->r);
+ }
+ else {
+ /* Gray (unassigned from SVG add-on) */
+ zero_v4(color);
+ add_v3_fl(color, 0.6f);
+ color[3] = 1.0f;
+ fill = false;
+ }
+
+ /* Special case: If the color was created by the SVG add-on and the name contains '_stroke' and
+ * there is only one color, the stroke must not be closed, fill to false and use for
+ * stroke the fill color.
+ */
+ bool do_stroke = false;
+ if (ob_cu->totcol == 1) {
+ Material *ma_stroke = give_current_material(ob_cu, 1);
+ if ((ma_stroke) && (strstr(ma_stroke->id.name, "_stroke") != NULL)) {
+ do_stroke = true;
+ }
+ }
+
+ int r_idx = gpencil_check_same_material_color(ob_gp, color, &mat_gp);
+ if ((ob_cu->totcol > 0) && (r_idx < 0)) {
+ Material *mat_curve = give_current_material(ob_cu, 1);
+ mat_gp = gpencil_add_from_curve_material(bmain, ob_gp, color, gpencil_lines, fill, &r_idx);
+
+ if ((mat_curve) && (mat_curve->gp_style != NULL)) {
+ MaterialGPencilStyle *gp_style_cur = mat_curve->gp_style;
+ MaterialGPencilStyle *gp_style_gp = mat_gp->gp_style;
+
+ copy_v4_v4(gp_style_gp->mix_rgba, gp_style_cur->mix_rgba);
+ gp_style_gp->fill_style = gp_style_cur->fill_style;
+ gp_style_gp->mix_factor = gp_style_cur->mix_factor;
+ gp_style_gp->gradient_angle = gp_style_cur->gradient_angle;
+ }
+
+ /* If object has more than 1 material, use second material for stroke color. */
+ if ((!only_stroke) && (ob_cu->totcol > 1) && (give_current_material(ob_cu, 2))) {
+ mat_curve = give_current_material(ob_cu, 2);
+ if (mat_curve) {
+ linearrgb_to_srgb_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r);
+ mat_gp->gp_style->stroke_rgba[3] = mat_curve->a;
+ }
+ }
+ else if ((only_stroke) || (do_stroke)) {
+ /* Also use the first color if the fill is none for stroke color. */
+ if (ob_cu->totcol > 0) {
+ mat_curve = give_current_material(ob_cu, 1);
+ if (mat_curve) {
+ linearrgb_to_srgb_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r);
+ mat_gp->gp_style->stroke_rgba[3] = mat_curve->a;
+ /* Set fill and stroke depending of curve type (3D or 2D). */
+ if ((cu->flag & CU_3D) || ((cu->flag & (CU_FRONT | CU_BACK)) == 0)) {
+ mat_gp->gp_style->flag |= GP_STYLE_STROKE_SHOW;
+ mat_gp->gp_style->flag &= ~GP_STYLE_FILL_SHOW;
+ }
+ else {
+ mat_gp->gp_style->flag &= ~GP_STYLE_STROKE_SHOW;
+ mat_gp->gp_style->flag |= GP_STYLE_FILL_SHOW;
+ }
+ }
+ }
+ }
+ }
+ CLAMP_MIN(r_idx, 0);
+
+ /* Assign material index to stroke. */
+ gps->mat_nr = r_idx;
+
+ /* Add stroke to frame.*/
+ BLI_addtail(&gpf->strokes, gps);
+
+ float *coord_array = NULL;
+ float init_co[3];
+
+ switch (nu->type) {
+ case CU_POLY: {
+ /* Allocate memory for storage points. */
+ gps->totpoints = nu->pntsu;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ /* Increase thickness for this type. */
+ gps->thickness = 10.0f;
+
+ /* Get all curve points */
+ for (int s = 0; s < gps->totpoints; s++) {
+ BPoint *bp = &nu->bp[s];
+ bGPDspoint *pt = &gps->points[s];
+ copy_v3_v3(&pt->x, bp->vec);
+ pt->pressure = bp->radius;
+ pt->strength = 1.0f;
+ }
+ break;
+ }
+ case CU_BEZIER: {
+ /* Allocate memory for storage points. */
+ gps->totpoints = totpoints;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+
+ int init = 0;
+ resolu = nu->resolu + 1;
+ segments = nu->pntsu;
+ if (((nu->flagu & CU_NURB_CYCLIC) == 0) || (nu->pntsu == 2)) {
+ segments--;
+ }
+ /* Get all interpolated curve points of Beziert */
+ for (int s = 0; s < segments; s++) {
+ int inext = (s + 1) % nu->pntsu;
+ BezTriple *prevbezt = &nu->bezt[s];
+ BezTriple *bezt = &nu->bezt[inext];
+ bool last = (bool)(s == segments - 1);
+
+ coord_array = MEM_callocN((size_t)3 * resolu * sizeof(float), __func__);
+
+ for (int j = 0; j < 3; j++) {
+ BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
+ prevbezt->vec[2][j],
+ bezt->vec[0][j],
+ bezt->vec[1][j],
+ coord_array + j,
+ resolu - 1,
+ 3 * sizeof(float));
+ }
+ /* Save first point coordinates. */
+ if (s == 0) {
+ copy_v3_v3(init_co, &coord_array[0]);
+ }
+ /* Add points to the stroke */
+ gpencil_add_new_points(gps, coord_array, bezt->radius, init, resolu, init_co, last);
+ /* Free memory. */
+ MEM_SAFE_FREE(coord_array);
+
+ /* As the last point of segment is the first point of next segment, back one array
+ * element to avoid duplicated points on the same location.
+ */
+ init += resolu - 1;
+ }
+ break;
+ }
+ case CU_NURBS: {
+ if (nu->pntsv == 1) {
+
+ int nurb_points;
+ if (nu->flagu & CU_NURB_CYCLIC) {
+ resolu++;
+ nurb_points = nu->pntsu * resolu;
+ }
+ else {
+ nurb_points = (nu->pntsu - 1) * resolu;
+ }
+ /* Get all curve points. */
+ coord_array = MEM_callocN(sizeof(float[3]) * nurb_points, __func__);
+ BKE_nurb_makeCurve(nu, coord_array, NULL, NULL, NULL, resolu, sizeof(float[3]));
+
+ /* Allocate memory for storage points. */
+ gps->totpoints = nurb_points - 1;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+
+ /* Add points. */
+ gpencil_add_new_points(gps, coord_array, 1.0f, 0, gps->totpoints, init_co, false);
+
+ MEM_SAFE_FREE(coord_array);
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ /* Cyclic curve, close stroke. */
+ if ((cyclic) && (!do_stroke)) {
+ BKE_gpencil_close_stroke(gps);
+ }
+}
+
+/* Convert a curve object to grease pencil stroke.
+ *
+ * \param bmain: Main thread pointer
+ * \param scene: Original scene.
+ * \param ob_gp: Grease pencil object to add strokes.
+ * \param ob_cu: Curve to convert.
+ * \param gpencil_lines: Use lines for strokes.
+ * \param use_collections: Create layers using collection names.
+ * \param only_stroke: The material must be only stroke without fill.
+ */
+void BKE_gpencil_convert_curve(Main *bmain,
+ Scene *scene,
+ Object *ob_gp,
+ Object *ob_cu,
+ const bool gpencil_lines,
+ const bool use_collections,
+ const bool only_stroke)
+{
+ if (ELEM(NULL, ob_gp, ob_cu) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == NULL)) {
+ return;
+ }
+
+ Curve *cu = (Curve *)ob_cu->data;
+ bGPdata *gpd = (bGPdata *)ob_gp->data;
+ bGPDlayer *gpl = NULL;
+
+ /* If the curve is empty, cancel. */
+ if (cu->nurb.first == NULL) {
+ return;
+ }
+
+ /* Check if there is an active layer. */
+ if (use_collections) {
+ Collection *collection = gpencil_get_parent_collection(scene, ob_cu);
+ if (collection != NULL) {
+ gpl = BLI_findstring(&gpd->layers, collection->id.name + 2, offsetof(bGPDlayer, info));
+ if (gpl == NULL) {
+ gpl = BKE_gpencil_layer_addnew(gpd, collection->id.name + 2, true);
+ }
+ }
+ }
+
+ if (gpl == NULL) {
+ gpl = BKE_gpencil_layer_getactive(gpd);
+ if (gpl == NULL) {
+ gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
+ }
+ }
+
+ /* Check if there is an active frame and add if needed. */
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+
+ /* Read all splines of the curve and create a stroke for each. */
+ for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) {
+ gpencil_convert_spline(bmain, ob_gp, ob_cu, gpencil_lines, only_stroke, gpf, nu);
+ }
+
+ /* Tag for recalculation */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+}
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index daa63515c3d..fe087256d25 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -340,6 +340,23 @@ bool BKE_gpencil_has_time_modifiers(Object *ob)
return false;
}
+/* Check if exist transform stroke modifiers (to rotate sculpt or edit). */
+bool BKE_gpencil_has_transform_modifiers(Object *ob)
+{
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ /* Only if enabled in edit mode. */
+ if (!GPENCIL_MODIFIER_EDIT(md, true) && GPENCIL_MODIFIER_ACTIVE(md, false)) {
+ if ((md->type == eGpencilModifierType_Armature) || (md->type == eGpencilModifierType_Hook) ||
+ (md->type == eGpencilModifierType_Lattice) ||
+ (md->type == eGpencilModifierType_Offset)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
/* apply stroke modifiers */
void BKE_gpencil_stroke_modifiers(Depsgraph *depsgraph,
Object *ob,
@@ -797,8 +814,10 @@ static void gpencil_frame_copy_noalloc(Object *ob, bGPDframe *gpf, bGPDframe *gp
/* copy color to temp fields to apply temporal changes in the stroke */
MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps_src->mat_nr + 1);
- copy_v4_v4(gps_dst->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
- copy_v4_v4(gps_dst->runtime.tmp_fill_rgba, gp_style->fill_rgba);
+ if (gp_style) {
+ copy_v4_v4(gps_dst->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
+ copy_v4_v4(gps_dst->runtime.tmp_fill_rgba, gp_style->fill_rgba);
+ }
/* Save original pointers for using in edit and select operators. */
gps_dst->runtime.gps_orig = gps_src;
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index 8a5a36481cf..90dba4bc737 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -224,7 +224,7 @@ static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
prv_img->tag |= PRV_TAG_DEFFERED;
}
- for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ for (i = 0; i < NUM_ICON_SIZES; i++) {
prv_img->flag[i] |= PRV_CHANGED;
prv_img->changed_timestamp[i] = 0;
}
@@ -242,7 +242,7 @@ void BKE_previewimg_freefunc(void *link)
if (prv) {
int i;
- for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ for (i = 0; i < NUM_ICON_SIZES; i++) {
if (prv->rect[i]) {
MEM_freeN(prv->rect[i]);
}
@@ -278,7 +278,7 @@ void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size)
void BKE_previewimg_clear(struct PreviewImage *prv)
{
int i;
- for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ for (i = 0; i < NUM_ICON_SIZES; i++) {
BKE_previewimg_clear_single(prv, i);
}
}
@@ -290,7 +290,7 @@ PreviewImage *BKE_previewimg_copy(const PreviewImage *prv)
if (prv) {
prv_img = MEM_dupallocN(prv);
- for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ for (i = 0; i < NUM_ICON_SIZES; i++) {
if (prv->rect[i]) {
prv_img->rect[i] = MEM_dupallocN(prv->rect[i]);
}
@@ -545,7 +545,7 @@ void BKE_icon_changed(const int icon_id)
/* If we have previews, they all are now invalid changed. */
if (p_prv && *p_prv) {
int i;
- for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ for (i = 0; i < NUM_ICON_SIZES; i++) {
(*p_prv)->flag[i] |= PRV_CHANGED;
(*p_prv)->changed_timestamp[i]++;
}
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index a99407b9bf9..bc682ffb8c8 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -55,6 +55,9 @@
#include "DNA_brush_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_light_types.h"
+#include "DNA_world_types.h"
+#include "DNA_defaults.h"
#include "BLI_blenlib.h"
#include "BLI_math_vector.h"
@@ -294,12 +297,9 @@ static void image_init(Image *ima, short source, short type)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(ima, id));
- ima->ok = IMA_OK;
+ MEMCPY_STRUCT_AFTER(ima, DNA_struct_default_get(Image), id);
- ima->aspx = ima->aspy = 1.0;
- ima->gen_x = 1024;
- ima->gen_y = 1024;
- ima->gen_type = IMA_GENTYPE_GRID;
+ ima->ok = IMA_OK;
ima->source = source;
ima->type = type;
@@ -316,8 +316,6 @@ static void image_init(Image *ima, short source, short type)
BKE_color_managed_colorspace_settings_init(&ima->colorspace_settings);
ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo Format");
-
- ima->gpuframenr = INT_MAX;
}
void BKE_image_init(struct Image *image)
@@ -1863,13 +1861,13 @@ static void stampdata(
}
}
-/* Will always add prefix. */
static void stampdata_from_template(StampData *stamp_data,
const Scene *scene,
- const StampData *stamp_data_template)
+ const StampData *stamp_data_template,
+ bool do_prefix)
{
if (scene->r.stamp & R_STAMP_FILENAME) {
- SNPRINTF(stamp_data->file, "File %s", stamp_data_template->file);
+ SNPRINTF(stamp_data->file, do_prefix ? "File %s" : "%s", stamp_data_template->file);
}
else {
stamp_data->file[0] = '\0';
@@ -1881,67 +1879,71 @@ static void stampdata_from_template(StampData *stamp_data,
stamp_data->note[0] = '\0';
}
if (scene->r.stamp & R_STAMP_DATE) {
- SNPRINTF(stamp_data->date, "Date %s", stamp_data_template->date);
+ SNPRINTF(stamp_data->date, do_prefix ? "Date %s" : "%s", stamp_data_template->date);
}
else {
stamp_data->date[0] = '\0';
}
if (scene->r.stamp & R_STAMP_MARKER) {
- SNPRINTF(stamp_data->marker, "Marker %s", stamp_data_template->marker);
+ SNPRINTF(stamp_data->marker, do_prefix ? "Marker %s" : "%s", stamp_data_template->marker);
}
else {
stamp_data->marker[0] = '\0';
}
if (scene->r.stamp & R_STAMP_TIME) {
- SNPRINTF(stamp_data->time, "Timecode %s", stamp_data_template->time);
+ SNPRINTF(stamp_data->time, do_prefix ? "Timecode %s" : "%s", stamp_data_template->time);
}
else {
stamp_data->time[0] = '\0';
}
if (scene->r.stamp & R_STAMP_FRAME) {
- SNPRINTF(stamp_data->frame, "Frame %s", stamp_data_template->frame);
+ SNPRINTF(stamp_data->frame, do_prefix ? "Frame %s" : "%s", stamp_data_template->frame);
}
else {
stamp_data->frame[0] = '\0';
}
if (scene->r.stamp & R_STAMP_CAMERA) {
- SNPRINTF(stamp_data->camera, "Camera %s", stamp_data_template->camera);
+ SNPRINTF(stamp_data->camera, do_prefix ? "Camera %s" : "%s", stamp_data_template->camera);
}
else {
stamp_data->camera[0] = '\0';
}
if (scene->r.stamp & R_STAMP_CAMERALENS) {
- SNPRINTF(stamp_data->cameralens, "Lens %s", stamp_data_template->cameralens);
+ SNPRINTF(
+ stamp_data->cameralens, do_prefix ? "Lens %s" : "%s", stamp_data_template->cameralens);
}
else {
stamp_data->cameralens[0] = '\0';
}
if (scene->r.stamp & R_STAMP_SCENE) {
- SNPRINTF(stamp_data->scene, "Scene %s", stamp_data_template->scene);
+ SNPRINTF(stamp_data->scene, do_prefix ? "Scene %s" : "%s", stamp_data_template->scene);
}
else {
stamp_data->scene[0] = '\0';
}
if (scene->r.stamp & R_STAMP_SEQSTRIP) {
- SNPRINTF(stamp_data->strip, "Strip %s", stamp_data_template->strip);
+ SNPRINTF(stamp_data->strip, do_prefix ? "Strip %s" : "%s", stamp_data_template->strip);
}
else {
stamp_data->strip[0] = '\0';
}
if (scene->r.stamp & R_STAMP_RENDERTIME) {
- SNPRINTF(stamp_data->rendertime, "RenderTime %s", stamp_data_template->rendertime);
+ SNPRINTF(stamp_data->rendertime,
+ do_prefix ? "RenderTime %s" : "%s",
+ stamp_data_template->rendertime);
}
else {
stamp_data->rendertime[0] = '\0';
}
if (scene->r.stamp & R_STAMP_MEMORY) {
- SNPRINTF(stamp_data->memory, "Peak Memory %s", stamp_data_template->memory);
+ SNPRINTF(stamp_data->memory, do_prefix ? "Peak Memory %s" : "%s", stamp_data_template->memory);
}
else {
stamp_data->memory[0] = '\0';
}
if (scene->r.stamp & R_STAMP_HOSTNAME) {
- SNPRINTF(stamp_data->hostname, "Hostname %s", stamp_data_template->hostname);
+ SNPRINTF(
+ stamp_data->hostname, do_prefix ? "Hostname %s" : "%s", stamp_data_template->hostname);
}
else {
stamp_data->hostname[0] = '\0';
@@ -1993,11 +1995,12 @@ void BKE_image_stamp_buf(Scene *scene,
display_device = scene->display_settings.display_device;
display = IMB_colormanagement_display_get_named(display_device);
+ bool do_prefix = (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0;
if (stamp_data_template == NULL) {
- stampdata(scene, camera, &stamp_data, (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0, true);
+ stampdata(scene, camera, &stamp_data, do_prefix, true);
}
else {
- stampdata_from_template(&stamp_data, scene, stamp_data_template);
+ stampdata_from_template(&stamp_data, scene, stamp_data_template, do_prefix);
}
/* TODO, do_versions */
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index e46b7ca5130..72b531c446a 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -41,6 +41,7 @@
#include "DNA_lattice_types.h"
#include "DNA_curve_types.h"
#include "DNA_key_types.h"
+#include "DNA_defaults.h"
#include "BKE_animsys.h"
#include "BKE_anim.h"
@@ -248,13 +249,10 @@ void BKE_lattice_init(Lattice *lt)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(lt, id));
- lt->flag = LT_GRID;
-
- lt->typeu = lt->typev = lt->typew = KEY_BSPLINE;
+ MEMCPY_STRUCT_AFTER(lt, DNA_struct_default_get(Lattice), id);
lt->def = MEM_callocN(sizeof(BPoint), "lattvert"); /* temporary */
BKE_lattice_resize(lt, 2, 2, 2, NULL); /* creates a uniform lattice */
- lt->actbp = LT_ACTBP_NONE;
}
Lattice *BKE_lattice_add(Main *bmain, const char *name)
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index de105b9b62a..9b18052ef1e 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -32,6 +32,7 @@
#include "BKE_freestyle.h"
#include "BKE_idprop.h"
#include "BKE_layer.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_object.h"
@@ -68,6 +69,7 @@ static LayerCollection *layer_collection_add(ListBase *lb_parent, Collection *co
{
LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base");
lc->collection = collection;
+ lc->local_collections_bits = ~(0);
BLI_addtail(lb_parent, lc);
return lc;
@@ -90,6 +92,7 @@ static Base *object_base_new(Object *ob)
{
Base *base = MEM_callocN(sizeof(Base), "Object Base");
base->object = ob;
+ base->local_view_bits = ~(0);
if (ob->base_flag & BASE_SELECTED) {
base->flag |= BASE_SELECTED;
}
@@ -651,7 +654,8 @@ static short layer_collection_sync(ViewLayer *view_layer,
ListBase *new_object_bases,
short parent_exclude,
short parent_restrict,
- short parent_layer_restrict)
+ short parent_layer_restrict,
+ unsigned short parent_local_collections_bits)
{
/* TODO: support recovery after removal of intermediate collections, reordering, ..
* For local edits we can make editing operating do the appropriate thing, but for
@@ -697,6 +701,13 @@ static short layer_collection_sync(ViewLayer *view_layer,
lc->flag = parent_exclude;
}
+ unsigned short local_collections_bits = parent_local_collections_bits &
+ lc->local_collections_bits;
+
+ /* Tag linked collection as a weak reference so we keep the layer
+ * collection pointer on file load and remember exclude state. */
+ id_lib_indirect_weak_link(&collection->id);
+
/* Collection restrict is inherited. */
short child_restrict = parent_restrict;
short child_layer_restrict = parent_layer_restrict;
@@ -712,7 +723,8 @@ static short layer_collection_sync(ViewLayer *view_layer,
new_object_bases,
lc->flag,
child_restrict,
- child_layer_restrict);
+ child_layer_restrict,
+ local_collections_bits);
/* Layer collection exclude is not inherited. */
if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
@@ -734,6 +746,10 @@ static short layer_collection_sync(ViewLayer *view_layer,
continue;
}
+ /* Tag linked object as a weak reference so we keep the object
+ * base pointer on file load and remember hidden state. */
+ id_lib_indirect_weak_link(&cob->ob->id);
+
void **base_p;
Base *base;
if (BLI_ghash_ensure_p(view_layer->object_bases_hash, cob->ob, &base_p)) {
@@ -749,6 +765,7 @@ static short layer_collection_sync(ViewLayer *view_layer,
else {
/* Create new base. */
base = object_base_new(cob->ob);
+ base->local_collections_bits = local_collections_bits;
*base_p = base;
BLI_addtail(new_object_bases, base);
}
@@ -826,7 +843,8 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
&new_object_bases,
parent_exclude,
parent_restrict,
- parent_layer_restrict);
+ parent_layer_restrict,
+ ~(0));
/* Any remaining object bases are to be removed. */
for (Base *base = view_layer->object_bases.first; base; base = base->next) {
@@ -1083,6 +1101,119 @@ void BKE_layer_collection_isolate(Scene *scene,
BKE_layer_collection_sync(scene, view_layer);
}
+static void layer_collection_local_visibility_set_recursive(LayerCollection *layer_collection,
+ const int local_collections_uuid)
+{
+ layer_collection->local_collections_bits |= local_collections_uuid;
+ for (LayerCollection *child = layer_collection->layer_collections.first; child;
+ child = child->next) {
+ layer_collection_local_visibility_set_recursive(child, local_collections_uuid);
+ }
+}
+
+static void layer_collection_local_visibility_unset_recursive(LayerCollection *layer_collection,
+ const int local_collections_uuid)
+{
+ layer_collection->local_collections_bits &= ~local_collections_uuid;
+ for (LayerCollection *child = layer_collection->layer_collections.first; child;
+ child = child->next) {
+ layer_collection_local_visibility_unset_recursive(child, local_collections_uuid);
+ }
+}
+
+static void layer_collection_local_sync(ViewLayer *view_layer,
+ LayerCollection *layer_collection,
+ const unsigned short local_collections_uuid,
+ bool visible)
+{
+ if ((layer_collection->local_collections_bits & local_collections_uuid) == 0) {
+ visible = false;
+ }
+
+ if (visible) {
+ for (CollectionObject *cob = layer_collection->collection->gobject.first; cob;
+ cob = cob->next) {
+ BLI_assert(cob->ob);
+ Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
+ base->local_collections_bits |= local_collections_uuid;
+ }
+ }
+
+ LISTBASE_FOREACH (LayerCollection *, child, &layer_collection->layer_collections) {
+ if ((child->flag & LAYER_COLLECTION_EXCLUDE) == 0) {
+ layer_collection_local_sync(view_layer, child, local_collections_uuid, visible);
+ }
+ }
+}
+
+void BKE_layer_collection_local_sync(ViewLayer *view_layer, View3D *v3d)
+{
+ const unsigned short local_collections_uuid = v3d->local_collections_uuid;
+
+ /* Reset flags and set the bases visible by default. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ base->local_collections_bits &= ~local_collections_uuid;
+ }
+
+ LISTBASE_FOREACH (LayerCollection *, layer_collection, &view_layer->layer_collections) {
+ layer_collection_local_sync(view_layer, layer_collection, local_collections_uuid, true);
+ }
+}
+
+/**
+ * Isolate the collection locally
+ *
+ * Same as BKE_layer_collection_local_isolate but for a viewport
+ */
+void BKE_layer_collection_local_isolate(ViewLayer *view_layer,
+ View3D *v3d,
+ LayerCollection *lc,
+ bool extend)
+{
+ LayerCollection *lc_master = view_layer->layer_collections.first;
+ bool hide_it = extend && ((v3d->local_collections_uuid & lc->local_collections_bits) != 0);
+
+ if (!extend) {
+ /* Hide all collections. */
+ for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter;
+ lc_iter = lc_iter->next) {
+ layer_collection_local_visibility_unset_recursive(lc_iter, v3d->local_collections_uuid);
+ }
+ }
+
+ /* Make all the direct parents visible. */
+ if (hide_it) {
+ lc->local_collections_bits &= ~(v3d->local_collections_uuid);
+ }
+ else {
+ LayerCollection *lc_parent = lc;
+ for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter;
+ lc_iter = lc_iter->next) {
+ if (BKE_layer_collection_has_layer_collection(lc_iter, lc)) {
+ lc_parent = lc_iter;
+ break;
+ }
+ }
+
+ while (lc_parent != lc) {
+ lc_parent->local_collections_bits |= v3d->local_collections_uuid;
+
+ for (LayerCollection *lc_iter = lc_parent->layer_collections.first; lc_iter;
+ lc_iter = lc_iter->next) {
+ if (BKE_layer_collection_has_layer_collection(lc_iter, lc)) {
+ lc_parent = lc_iter;
+ break;
+ }
+ }
+ }
+
+ /* Make all the children visible. */
+ layer_collection_local_visibility_set_recursive(lc, v3d->local_collections_uuid);
+ }
+
+ BKE_layer_collection_local_sync(view_layer, v3d);
+}
+
static void layer_collection_bases_show_recursive(ViewLayer *view_layer, LayerCollection *lc)
{
if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) {
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 2dbca3b4db1..468d0e97ece 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -165,12 +165,23 @@ void id_lib_extern(ID *id)
BLI_assert(BKE_idcode_is_linkable(GS(id->name)));
if (id->tag & LIB_TAG_INDIRECT) {
id->tag &= ~LIB_TAG_INDIRECT;
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
id->tag |= LIB_TAG_EXTERN;
id->lib->parent = NULL;
}
}
}
+void id_lib_indirect_weak_link(ID *id)
+{
+ if (id && ID_IS_LINKED(id)) {
+ BLI_assert(BKE_idcode_is_linkable(GS(id->name)));
+ if (id->tag & LIB_TAG_INDIRECT) {
+ id->flag |= LIB_INDIRECT_WEAK_LINK;
+ }
+ }
+}
+
/**
* Ensure we have a real user
*
@@ -851,8 +862,8 @@ void BKE_id_swap(Main *bmain, ID *id_a, ID *id_b)
id_b->properties = id_a_back.properties;
/* Swap will have broken internal references to itself, restore them. */
- BKE_libblock_relink_ex(bmain, id_a, id_b, id_a, false);
- BKE_libblock_relink_ex(bmain, id_b, id_a, id_b, false);
+ BKE_libblock_relink_ex(bmain, id_a, id_b, id_a, ID_REMAP_SKIP_NEVER_NULL_USAGE);
+ BKE_libblock_relink_ex(bmain, id_b, id_a, id_b, ID_REMAP_SKIP_NEVER_NULL_USAGE);
}
/** Does *not* set ID->newid pointer. */
@@ -1264,15 +1275,14 @@ void BKE_libblock_init_empty(ID *id)
break;
case ID_OB: {
Object *ob = (Object *)id;
- ob->type = OB_EMPTY;
- BKE_object_init(ob);
+ BKE_object_init(ob, OB_EMPTY);
break;
}
case ID_ME:
BKE_mesh_init((Mesh *)id);
break;
case ID_CU:
- BKE_curve_init((Curve *)id);
+ BKE_curve_init((Curve *)id, 0);
break;
case ID_MB:
BKE_mball_init((MetaBall *)id);
@@ -1408,21 +1418,32 @@ void *BKE_id_new_nomain(const short type, const char *name)
return id;
}
-void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
+void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int orig_flag)
{
ID *new_id = *r_newid;
+ int flag = orig_flag;
- /* Grrrrrrrrr... Not adding 'root' nodetrees to bmain.... grrrrrrrrrrrrrrrrrrrr! */
- /* This is taken from original ntree copy code, might be weak actually? */
- const bool use_nodetree_alloc_exception = ((GS(id->name) == ID_NT) && (bmain != NULL) &&
- (BLI_findindex(&bmain->nodetrees, id) < 0));
+ const bool is_private_id_data = (id->flag & LIB_PRIVATE_DATA) != 0;
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || bmain != NULL);
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || (flag & LIB_ID_CREATE_NO_ALLOCATE) == 0);
- BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 || (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) != 0);
+ if (!is_private_id_data) {
+ /* When we are handling private ID data, we might still want to manage usercounts, even though
+ * that ID data-block is actually outside of Main... */
+ BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 ||
+ (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) != 0);
+ }
/* Never implicitly copy shapekeys when generating temp data outside of Main database. */
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 || (flag & LIB_ID_COPY_SHAPEKEY) == 0);
+ /* 'Private ID' data handling. */
+ if ((bmain != NULL) && is_private_id_data) {
+ flag |= LIB_ID_CREATE_NO_MAIN;
+ }
+
+ /* The id->flag bits to copy over. */
+ const int copy_idflag_mask = LIB_PRIVATE_DATA;
+
if ((flag & LIB_ID_CREATE_NO_ALLOCATE) != 0) {
/* r_newid already contains pointer to allocated memory. */
/* TODO do we want to memset(0) whole mem before filling it? */
@@ -1432,10 +1453,7 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int fla
/* TODO Do we want/need to copy more from ID struct itself? */
}
else {
- new_id = BKE_libblock_alloc(bmain,
- GS(id->name),
- id->name + 2,
- flag | (use_nodetree_alloc_exception ? LIB_ID_CREATE_NO_MAIN : 0));
+ new_id = BKE_libblock_alloc(bmain, GS(id->name), id->name + 2, flag);
}
BLI_assert(new_id != NULL);
@@ -1448,6 +1466,8 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int fla
memcpy(cpn + id_offset, cp + id_offset, id_len - id_offset);
}
+ new_id->flag = (new_id->flag & ~copy_idflag_mask) | (id->flag & copy_idflag_mask);
+
if (id->properties) {
new_id->properties = IDP_CopyProperty_ex(id->properties, flag);
}
@@ -1466,8 +1486,12 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int fla
/* the duplicate should get a copy of the animdata */
if ((flag & LIB_ID_COPY_NO_ANIMDATA) == 0) {
- BLI_assert((flag & LIB_ID_COPY_ACTIONS) == 0 || (flag & LIB_ID_CREATE_NO_MAIN) == 0);
- iat->adt = BKE_animdata_copy(bmain, iat->adt, flag);
+ /* Note that even though horrors like root nodetrees are not in bmain, the actions they use
+ * in their anim data *are* in bmain... super-mega-hooray. */
+ int animdata_flag = orig_flag;
+ BLI_assert((animdata_flag & LIB_ID_COPY_ACTIONS) == 0 ||
+ (animdata_flag & LIB_ID_CREATE_NO_MAIN) == 0);
+ iat->adt = BKE_animdata_copy(bmain, iat->adt, animdata_flag);
}
else {
iat->adt = NULL;
@@ -1755,6 +1779,7 @@ void id_clear_lib_data_ex(Main *bmain, ID *id, const bool id_in_mainlist)
id->lib = NULL;
id->tag &= ~(LIB_TAG_INDIRECT | LIB_TAG_EXTERN);
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
if (id_in_mainlist) {
if (BKE_id_new_name_validate(which_libbase(bmain, GS(id->name)), id, NULL)) {
bmain->is_memfile_undo_written = false;
@@ -1968,6 +1993,7 @@ void BKE_library_make_local(Main *bmain,
if (id->lib == NULL) {
id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
}
/* The check on the fourth line (LIB_TAG_PRE_EXISTING) is done so it's possible to tag data
* you don't want to be made local, used for appending data,
diff --git a/source/blender/blenkernel/intern/library_override.c b/source/blender/blenkernel/intern/library_override.c
index ce368575492..4f10a5bca6b 100644
--- a/source/blender/blenkernel/intern/library_override.c
+++ b/source/blender/blenkernel/intern/library_override.c
@@ -57,7 +57,7 @@ static void bke_override_property_operation_clear(IDOverrideLibraryPropertyOpera
/* Temp, for until library override is ready and tested enough to go 'public',
* we hide it by default in UI and such. */
-static bool _override_library_enabled = false;
+static bool _override_library_enabled = true;
void BKE_override_library_enable(const bool do_enable)
{
@@ -111,11 +111,11 @@ void BKE_override_library_copy(ID *dst_id, const ID *src_id)
if (dst_id->override_library != NULL) {
if (src_id->override_library == NULL) {
- BKE_override_library_free(&dst_id->override_library);
+ BKE_override_library_free(&dst_id->override_library, true);
return;
}
else {
- BKE_override_library_clear(dst_id->override_library);
+ BKE_override_library_clear(dst_id->override_library, true);
}
}
else if (src_id->override_library == NULL) {
@@ -144,7 +144,7 @@ void BKE_override_library_copy(ID *dst_id, const ID *src_id)
}
/** Clear any overriding data from given \a override. */
-void BKE_override_library_clear(IDOverrideLibrary *override)
+void BKE_override_library_clear(IDOverrideLibrary *override, const bool do_id_user)
{
BLI_assert(override != NULL);
@@ -153,16 +153,18 @@ void BKE_override_library_clear(IDOverrideLibrary *override)
}
BLI_freelistN(&override->properties);
- id_us_min(override->reference);
- /* override->storage should never be refcounted... */
+ if (do_id_user) {
+ id_us_min(override->reference);
+ /* override->storage should never be refcounted... */
+ }
}
/** Free given \a override. */
-void BKE_override_library_free(struct IDOverrideLibrary **override)
+void BKE_override_library_free(struct IDOverrideLibrary **override, const bool do_id_user)
{
BLI_assert(*override != NULL);
- BKE_override_library_clear(*override);
+ BKE_override_library_clear(*override, do_id_user);
MEM_freeN(*override);
*override = NULL;
}
@@ -183,19 +185,28 @@ static ID *override_library_create_from(Main *bmain, ID *reference_id)
}
/** Create an overridden local copy of linked reference. */
-ID *BKE_override_library_create_from_id(Main *bmain, ID *reference_id)
+ID *BKE_override_library_create_from_id(Main *bmain, ID *reference_id, const bool do_tagged_remap)
{
BLI_assert(reference_id != NULL);
BLI_assert(reference_id->lib != NULL);
ID *local_id = override_library_create_from(bmain, reference_id);
- /* Remapping, we obviously only want to affect local data
- * (and not our own reference pointer to overridden ID). */
- BKE_libblock_remap(bmain,
- reference_id,
- local_id,
- ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY);
+ if (do_tagged_remap) {
+ ID *other_id;
+ FOREACH_MAIN_ID_BEGIN (bmain, other_id) {
+ if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib == NULL) {
+ /* Note that using ID_REMAP_SKIP_INDIRECT_USAGE below is superfluous, as we only remap
+ * local IDs usages anyway... */
+ BKE_libblock_relink_ex(bmain,
+ other_id,
+ reference_id,
+ local_id,
+ ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY);
+ }
+ }
+ FOREACH_MAIN_ID_END;
+ }
return local_id;
}
@@ -205,6 +216,11 @@ ID *BKE_override_library_create_from_id(Main *bmain, ID *reference_id)
* \note Set id->newid of overridden libs with newly created overrides,
* caller is responsible to clean those pointers before/after usage as needed.
*
+ * \note By default, it will only remap newly created local overriding data-blocks between
+ * themselves, to avoid 'enforcing' those overrides into all other usages of the linked data in
+ * main. You can add more local IDs to be remapped to use new overriding ones by setting their
+ * LIB_TAG_DOIT tag.
+ *
* \return \a true on success, \a false otherwise.
*/
bool BKE_override_library_create_from_tag(Main *bmain)
@@ -212,26 +228,59 @@ bool BKE_override_library_create_from_tag(Main *bmain)
ID *reference_id;
bool ret = true;
+ ListBase todo_ids = {NULL};
+ LinkData *todo_id_iter;
+
+ /* Get all IDs we want to override. */
FOREACH_MAIN_ID_BEGIN (bmain, reference_id) {
if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL) {
- if ((reference_id->newid = override_library_create_from(bmain, reference_id)) == NULL) {
- ret = false;
- }
+ todo_id_iter = MEM_callocN(sizeof(*todo_id_iter), __func__);
+ todo_id_iter->data = reference_id;
+ BLI_addtail(&todo_ids, todo_id_iter);
}
}
FOREACH_MAIN_ID_END;
- FOREACH_MAIN_ID_BEGIN (bmain, reference_id) {
- if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL &&
- reference_id->newid != NULL) {
- ID *local_id = reference_id->newid;
- BKE_libblock_remap(bmain,
- reference_id,
- local_id,
- ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY);
+ /* Override the IDs. */
+ for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) {
+ reference_id = todo_id_iter->data;
+ if ((reference_id->newid = override_library_create_from(bmain, reference_id)) == NULL) {
+ ret = false;
+ }
+ else {
+ /* We also tag the new IDs so that in next step we can remap their pointers too. */
+ reference_id->newid->tag |= LIB_TAG_DOIT;
}
}
- FOREACH_MAIN_ID_END;
+
+ /* Only remap new local ID's pointers, we don't want to force our new overrides onto our whole
+ * existing linked IDs usages. */
+ for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) {
+ ID *other_id;
+ reference_id = todo_id_iter->data;
+
+ if (reference_id->newid == NULL) {
+ continue;
+ }
+
+ /* Still checking the whole Main, that way we can tag other local IDs as needing to be remapped
+ * to use newly created overriding IDs, if needed. */
+ FOREACH_MAIN_ID_BEGIN (bmain, other_id) {
+ if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib == NULL) {
+ ID *local_id = reference_id->newid;
+ /* Note that using ID_REMAP_SKIP_INDIRECT_USAGE below is superfluous, as we only remap
+ * local IDs usages anyway... */
+ BKE_libblock_relink_ex(bmain,
+ other_id,
+ reference_id,
+ local_id,
+ ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY);
+ }
+ }
+ FOREACH_MAIN_ID_END;
+ }
+
+ BLI_freelistN(&todo_ids);
return ret;
}
@@ -592,6 +641,13 @@ bool BKE_override_library_operations_create(Main *bmain, ID *local, const bool f
bool ret = false;
if (!is_template && (force_auto || local->override_library->flag & OVERRIDE_LIBRARY_AUTO)) {
+ /* Do not attempt to generate overriding rules from an empty place-holder generated by link
+ * code when it cannot find to actual library/ID. Much better to keep the local datablock as
+ * is in the file in that case, until broken lib is fixed. */
+ if (ID_MISSING(local->override_library->reference)) {
+ return ret;
+ }
+
PointerRNA rnaptr_local, rnaptr_reference;
RNA_id_pointer_create(local, &rnaptr_local);
RNA_id_pointer_create(local->override_library->reference, &rnaptr_reference);
@@ -644,6 +700,13 @@ void BKE_override_library_update(Main *bmain, ID *local)
return;
}
+ /* Do not attempt to apply overriding rules over an empty place-holder generated by link code
+ * when it cannot find to actual library/ID. Much better to keep the local datablock as loaded
+ * from the file in that case, until broken lib is fixed. */
+ if (ID_MISSING(local->override_library->reference)) {
+ return;
+ }
+
/* Recursively do 'ancestors' overrides first, if any. */
if (local->override_library->reference->override_library &&
(local->override_library->reference->tag & LIB_TAG_OVERRIDE_LIBRARY_REFOK) == 0) {
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index 8fe2552c03f..45dbb4b6ec1 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -389,7 +389,7 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *o
if (ob->data == new_id) {
switch (GS(new_id->name)) {
case ID_ME:
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
break;
case ID_CU:
BKE_curve_type_test(ob);
@@ -497,6 +497,7 @@ static void libblock_remap_data(
if (new_id && (new_id->tag & LIB_TAG_INDIRECT) &&
(r_id_remap_data->status & ID_REMAP_IS_LINKED_DIRECT)) {
new_id->tag &= ~LIB_TAG_INDIRECT;
+ new_id->flag &= ~LIB_INDIRECT_WEAK_LINK;
new_id->tag |= LIB_TAG_EXTERN;
}
@@ -652,12 +653,11 @@ void BKE_libblock_unlink(Main *bmain,
* ... sigh
*/
void BKE_libblock_relink_ex(
- Main *bmain, void *idv, void *old_idv, void *new_idv, const bool us_min_never_null)
+ Main *bmain, void *idv, void *old_idv, void *new_idv, const short remap_flags)
{
ID *id = idv;
ID *old_id = old_idv;
ID *new_id = new_idv;
- int remap_flags = us_min_never_null ? 0 : ID_REMAP_SKIP_NEVER_NULL_USAGE;
/* No need to lock here, we are only affecting given ID, not bmain database. */
@@ -757,7 +757,7 @@ void BKE_libblock_free_data(ID *id, const bool do_id_user)
}
if (id->override_library) {
- BKE_override_library_free(&id->override_library);
+ BKE_override_library_free(&id->override_library, do_id_user);
}
/* XXX TODO remove animdata handling from each type's freeing func,
@@ -945,7 +945,7 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
#endif
if ((flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0) {
- BKE_libblock_relink_ex(bmain, id, NULL, NULL, true);
+ BKE_libblock_relink_ex(bmain, id, NULL, NULL, 0);
}
BKE_libblock_free_datablock(id, flag);
@@ -1091,7 +1091,7 @@ static void id_delete(Main *bmain, const bool do_tagged_deletion)
bmain, id, NULL, ID_REMAP_FLAG_NEVER_NULL_USAGE | ID_REMAP_FORCE_NEVER_NULL_USAGE);
/* Since we removed ID from Main,
* we also need to unlink its own other IDs usages ourself. */
- BKE_libblock_relink_ex(bmain, id, NULL, NULL, true);
+ BKE_libblock_relink_ex(bmain, id, NULL, NULL, 0);
/* Now we can safely mark that ID as not being in Main database anymore. */
id->tag |= LIB_TAG_NO_MAIN;
/* This is needed because we may not have remapped usages
diff --git a/source/blender/blenkernel/intern/light.c b/source/blender/blenkernel/intern/light.c
index 75c9e0e42a5..ea728f61733 100644
--- a/source/blender/blenkernel/intern/light.c
+++ b/source/blender/blenkernel/intern/light.c
@@ -32,6 +32,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_texture_types.h"
+#include "DNA_defaults.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -48,40 +49,9 @@ void BKE_light_init(Light *la)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(la, id));
- la->r = la->g = la->b = la->k = 1.0f;
- la->energy = 10.0f;
- la->dist = 25.0f;
- la->spotsize = DEG2RADF(45.0f);
- la->spotblend = 0.15f;
- la->att2 = 1.0f;
- la->mode = LA_SHADOW;
- la->bufsize = 512;
- la->clipsta = 0.05f;
- la->clipend = 40.0f;
- la->bleedexp = 2.5f;
- la->samp = 3;
- la->bias = 1.0f;
- la->soft = 3.0f;
- la->area_size = la->area_sizey = la->area_sizez = 0.25f;
- la->buffers = 1;
- la->preview = NULL;
- la->falloff_type = LA_FALLOFF_INVSQUARE;
- la->coeff_const = 1.0f;
- la->coeff_lin = 0.0f;
- la->coeff_quad = 0.0f;
- la->curfalloff = BKE_curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f);
- la->cascade_max_dist = 200.0f;
- la->cascade_count = 4;
- la->cascade_exponent = 0.8f;
- la->cascade_fade = 0.1f;
- la->contact_dist = 0.2f;
- la->contact_bias = 0.03f;
- la->contact_spread = 0.2f;
- la->contact_thickness = 0.2f;
- la->spec_fac = 1.0f;
- la->att_dist = 40.0f;
- la->sun_angle = DEG2RADF(0.526f);
+ MEMCPY_STRUCT_AFTER(la, DNA_struct_default_get(Light), id);
+ la->curfalloff = BKE_curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f);
BKE_curvemapping_initialize(la->curfalloff);
}
@@ -108,12 +78,13 @@ Light *BKE_light_add(Main *bmain, const char *name)
*/
void BKE_light_copy_data(Main *bmain, Light *la_dst, const Light *la_src, const int flag)
{
+ /* We always need allocation of our private ID data. */
+ const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
+
la_dst->curfalloff = BKE_curvemapping_copy(la_src->curfalloff);
if (la_src->nodetree) {
- /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
- * (see BKE_libblock_copy_ex()). */
- BKE_id_copy_ex(bmain, (ID *)la_src->nodetree, (ID **)&la_dst->nodetree, flag);
+ BKE_id_copy_ex(bmain, (ID *)la_src->nodetree, (ID **)&la_dst->nodetree, flag_private_id_data);
}
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c
index 1c2f8d22f3e..06f1ee5050b 100644
--- a/source/blender/blenkernel/intern/lightprobe.c
+++ b/source/blender/blenkernel/intern/lightprobe.c
@@ -21,8 +21,11 @@
* \ingroup bke
*/
+#include <string.h>
+
#include "DNA_object_types.h"
#include "DNA_lightprobe_types.h"
+#include "DNA_defaults.h"
#include "BLI_utildefines.h"
@@ -35,17 +38,7 @@ void BKE_lightprobe_init(LightProbe *probe)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(probe, id));
- probe->grid_resolution_x = probe->grid_resolution_y = probe->grid_resolution_z = 4;
- probe->distinf = 2.5f;
- probe->distpar = 2.5f;
- probe->falloff = 0.2f;
- probe->clipsta = 0.8f;
- probe->clipend = 40.0f;
- probe->vis_bias = 1.0f;
- probe->vis_blur = 0.2f;
- probe->intensity = 1.0f;
-
- probe->flag = LIGHTPROBE_FLAG_SHOW_INFLUENCE;
+ MEMCPY_STRUCT_AFTER(probe, DNA_struct_default_get(LightProbe), id);
}
void *BKE_lightprobe_add(Main *bmain, const char *name)
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index 7bfe5a7c8ff..3efc493b43e 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -30,6 +30,7 @@
#include "DNA_object_types.h"
#include "DNA_material_types.h" /* for ramp blend */
#include "DNA_texture_types.h"
+#include "DNA_defaults.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
@@ -76,34 +77,9 @@ void BKE_linestyle_init(FreestyleLineStyle *linestyle)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(linestyle, id));
- linestyle->panel = LS_PANEL_STROKES;
- linestyle->r = linestyle->g = linestyle->b = 0.0f;
- linestyle->alpha = 1.0f;
- linestyle->thickness = 3.0f;
- linestyle->thickness_position = LS_THICKNESS_CENTER;
- linestyle->thickness_ratio = 0.5f;
- linestyle->flag = LS_SAME_OBJECT | LS_NO_SORTING | LS_TEXTURE;
- linestyle->chaining = LS_CHAINING_PLAIN;
- linestyle->rounds = 3;
- linestyle->min_angle = DEG2RADF(0.0f);
- linestyle->max_angle = DEG2RADF(0.0f);
- linestyle->min_length = 0.0f;
- linestyle->max_length = 10000.0f;
- linestyle->split_length = 100;
- linestyle->chain_count = 10;
- linestyle->sort_key = LS_SORT_KEY_DISTANCE_FROM_CAMERA;
- linestyle->integration_type = LS_INTEGRATION_MEAN;
- linestyle->texstep = 1.0f;
- linestyle->pr_texture = TEX_PR_TEXTURE;
-
- BLI_listbase_clear(&linestyle->color_modifiers);
- BLI_listbase_clear(&linestyle->alpha_modifiers);
- BLI_listbase_clear(&linestyle->thickness_modifiers);
- BLI_listbase_clear(&linestyle->geometry_modifiers);
+ MEMCPY_STRUCT_AFTER(linestyle, DNA_struct_default_get(FreestyleLineStyle), id);
BKE_linestyle_geometry_modifier_add(linestyle, NULL, LS_MODIFIER_SAMPLING);
-
- linestyle->caps = LS_CAPS_BUTT;
}
FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name)
@@ -167,6 +143,8 @@ void BKE_linestyle_copy_data(struct Main *bmain,
{
/* We never handle usercount here for own data. */
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
+ /* We always need allocation of our private ID data. */
+ const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
for (int a = 0; a < MAX_MTEX; a++) {
if (linestyle_src->mtex[a]) {
@@ -176,9 +154,10 @@ void BKE_linestyle_copy_data(struct Main *bmain,
}
if (linestyle_src->nodetree) {
- /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
- * (see BKE_libblock_copy_ex()). */
- BKE_id_copy_ex(bmain, (ID *)linestyle_src->nodetree, (ID **)&linestyle_dst->nodetree, flag);
+ BKE_id_copy_ex(bmain,
+ (ID *)linestyle_src->nodetree,
+ (ID **)&linestyle_dst->nodetree,
+ flag_private_id_data);
}
LineStyleModifier *m;
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 1545ae4f48f..73c278a0ab6 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -42,6 +42,7 @@
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_defaults.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
@@ -71,6 +72,7 @@
/* used in UI and render */
Material defmaterial;
+Material defgpencil_material;
static CLG_LogRef LOG = {"bke.material"};
@@ -78,6 +80,13 @@ static CLG_LogRef LOG = {"bke.material"};
void init_def_material(void)
{
BKE_material_init(&defmaterial);
+ BKE_material_gpencil_init(&defgpencil_material);
+}
+
+/* Free the GPencil data of the default material, creator.c */
+void BKE_material_gpencil_default_free(void)
+{
+ MEM_SAFE_FREE(defgpencil_material.gp_style);
}
/** Free (or release) any data used by this material (does not free the material itself). */
@@ -128,20 +137,17 @@ void BKE_material_init(Material *ma)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(ma, id));
- ma->r = ma->g = ma->b = 0.8;
- ma->specr = ma->specg = ma->specb = 1.0;
- ma->a = 1.0f;
- ma->spec = 0.5;
-
- ma->roughness = 0.4f;
-
- ma->pr_type = MA_SPHERE;
-
- ma->preview = NULL;
+ MEMCPY_STRUCT_AFTER(ma, DNA_struct_default_get(Material), id);
+}
- ma->alpha_threshold = 0.5f;
+void BKE_material_gpencil_init(Material *ma)
+{
+ BKE_material_init(ma);
- ma->blend_shadow = MA_BS_SOLID;
+ /* grease pencil settings */
+ strcpy(ma->id.name, "MADefault GPencil");
+ BKE_material_init_gpencil_settings(ma);
+ add_v3_fl(&ma->gp_style->stroke_rgba[0], 0.6f);
}
Material *BKE_material_add(Main *bmain, const char *name)
@@ -180,10 +186,11 @@ Material *BKE_material_add_gpencil(Main *bmain, const char *name)
*/
void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_src, const int flag)
{
+ /* We always need allocation of our private ID data. */
+ const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
+
if (ma_src->nodetree) {
- /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
- * (see BKE_libblock_copy_ex()). */
- BKE_id_copy_ex(bmain, (ID *)ma_src->nodetree, (ID **)&ma_dst->nodetree, flag);
+ BKE_id_copy_ex(bmain, (ID *)ma_src->nodetree, (ID **)&ma_dst->nodetree, flag_private_id_data);
}
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
@@ -580,6 +587,17 @@ Material *give_current_material(Object *ob, short act)
return ma_p ? *ma_p : NULL;
}
+Material *BKE_material_gpencil_get(Object *ob, short act)
+{
+ Material *ma = give_current_material(ob, act);
+ if (ma != NULL) {
+ return ma;
+ }
+ else {
+ return &defgpencil_material;
+ }
+}
+
MaterialGPencilStyle *BKE_material_gpencil_settings_get(Object *ob, short act)
{
Material *ma = give_current_material(ob, act);
@@ -591,7 +609,7 @@ MaterialGPencilStyle *BKE_material_gpencil_settings_get(Object *ob, short act)
return ma->gp_style;
}
else {
- return NULL;
+ return defgpencil_material.gp_style;
}
}
@@ -1070,10 +1088,6 @@ bool BKE_object_material_slot_remove(Main *bmain, Object *ob)
}
/* check indices from gpencil */
else if (ob->type == OB_GPENCIL) {
- /* need one color */
- if (ob->totcol == 0) {
- BKE_gpencil_object_material_ensure_from_active_input_material(bmain, ob);
- }
BKE_gpencil_material_index_reassign((bGPdata *)ob->data, ob->totcol, actcol - 1);
}
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 19009322975..b127d5d4d0e 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -39,6 +39,7 @@
#include "DNA_object_types.h"
#include "DNA_meta_types.h"
#include "DNA_scene_types.h"
+#include "DNA_defaults.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
@@ -79,12 +80,7 @@ void BKE_mball_init(MetaBall *mb)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(mb, id));
- mb->size[0] = mb->size[1] = mb->size[2] = 1.0;
- mb->texflag = MB_AUTOSPACE;
-
- mb->wiresize = 0.4f;
- mb->rendersize = 0.2f;
- mb->thresh = 0.6f;
+ MEMCPY_STRUCT_AFTER(mb, DNA_struct_default_get(MetaBall), id);
}
MetaBall *BKE_mball_add(Main *bmain, const char *name)
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index 687bd0a32c5..ca1ca2618d8 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -1405,7 +1405,7 @@ void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBa
process.converge_res = 2;
}
- if (is_render && (mb->flag == MB_UPDATE_NEVER)) {
+ if (!is_render && (mb->flag == MB_UPDATE_NEVER)) {
return;
}
if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_FAST) {
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 71fd65d1f23..ba139c654d3 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -27,6 +27,7 @@
#include "DNA_key_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_defaults.h"
#include "BLI_utildefines.h"
#include "BLI_bitmap.h"
@@ -495,7 +496,6 @@ void BKE_mesh_clear_geometry(Mesh *mesh)
CustomData_free(&mesh->ldata, mesh->totloop);
CustomData_free(&mesh->pdata, mesh->totpoly);
- MEM_SAFE_FREE(mesh->bb);
MEM_SAFE_FREE(mesh->mselect);
MEM_SAFE_FREE(mesh->edit_mesh);
@@ -533,10 +533,7 @@ void BKE_mesh_init(Mesh *me)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(me, id));
- me->size[0] = me->size[1] = me->size[2] = 1.0;
- me->smoothresh = DEG2RADF(30);
- me->texflag = ME_AUTOSPACE;
- me->remesh_voxel_size = 0.1f;
+ MEMCPY_STRUCT_AFTER(me, DNA_struct_default_get(Mesh), id);
CustomData_reset(&me->vdata);
CustomData_reset(&me->edata);
@@ -607,7 +604,6 @@ void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int
me_dst->edit_mesh = NULL;
me_dst->mselect = MEM_dupallocN(me_dst->mselect);
- me_dst->bb = MEM_dupallocN(me_dst->bb);
/* TODO Do we want to add flag to prevent this? */
if (me_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
@@ -661,20 +657,44 @@ Mesh *BKE_mesh_new_nomain(
return mesh;
}
-static Mesh *mesh_new_nomain_from_template_ex(const Mesh *me_src,
- int verts_len,
- int edges_len,
- int tessface_len,
- int loops_len,
- int polys_len,
- CustomData_MeshMasks mask)
+/* Copy user editable settings that we want to preserve through the modifier stack
+ * or operations where a mesh with new topology is created based on another mesh. */
+void BKE_mesh_copy_settings(Mesh *me_dst, const Mesh *me_src)
+{
+ /* Copy general settings. */
+ me_dst->editflag = me_src->editflag;
+ me_dst->flag = me_src->flag;
+ me_dst->smoothresh = me_src->smoothresh;
+ me_dst->remesh_voxel_size = me_src->remesh_voxel_size;
+ me_dst->remesh_voxel_adaptivity = me_src->remesh_voxel_adaptivity;
+ me_dst->remesh_mode = me_src->remesh_mode;
+
+ /* Copy texture space. */
+ me_dst->texflag = me_src->texflag;
+ copy_v3_v3(me_dst->loc, me_src->loc);
+ copy_v3_v3(me_dst->size, me_src->size);
+
+ /* Copy materials. */
+ if (me_dst->mat != NULL) {
+ MEM_freeN(me_dst->mat);
+ }
+ me_dst->mat = MEM_dupallocN(me_src->mat);
+ me_dst->totcol = me_src->totcol;
+}
+
+Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src,
+ int verts_len,
+ int edges_len,
+ int tessface_len,
+ int loops_len,
+ int polys_len,
+ CustomData_MeshMasks mask)
{
/* Only do tessface if we are creating tessfaces or copying from mesh with only tessfaces. */
const bool do_tessface = (tessface_len || ((me_src->totface != 0) && (me_src->totpoly == 0)));
Mesh *me_dst = BKE_id_new_nomain(ID_ME, NULL);
- me_dst->mat = MEM_dupallocN(me_src->mat);
me_dst->mselect = MEM_dupallocN(me_dst->mselect);
me_dst->totvert = verts_len;
@@ -684,8 +704,7 @@ static Mesh *mesh_new_nomain_from_template_ex(const Mesh *me_src,
me_dst->totpoly = polys_len;
me_dst->cd_flag = me_src->cd_flag;
- me_dst->editflag = me_src->editflag;
- me_dst->texflag = me_src->texflag;
+ BKE_mesh_copy_settings(me_dst, me_src);
CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_CALLOC, verts_len);
CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, CD_CALLOC, edges_len);
@@ -713,7 +732,7 @@ Mesh *BKE_mesh_new_nomain_from_template(const Mesh *me_src,
int loops_len,
int polys_len)
{
- return mesh_new_nomain_from_template_ex(
+ return BKE_mesh_new_nomain_from_template_ex(
me_src, verts_len, edges_len, tessface_len, loops_len, polys_len, CD_MASK_EVERYTHING);
}
@@ -774,18 +793,24 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me,
});
}
-Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm, const struct BMeshToMeshParams *params)
+Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm,
+ const struct BMeshToMeshParams *params,
+ const Mesh *me_settings)
{
BLI_assert(params->calc_object_remap == false);
Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
BM_mesh_bm_to_me(NULL, bm, mesh, params);
+ BKE_mesh_copy_settings(mesh, me_settings);
return mesh;
}
-Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks *cd_mask_extra)
+Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm,
+ const CustomData_MeshMasks *cd_mask_extra,
+ const Mesh *me_settings)
{
Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
BM_mesh_bm_to_me_for_eval(bm, mesh, cd_mask_extra);
+ BKE_mesh_copy_settings(mesh, me_settings);
return mesh;
}
@@ -794,9 +819,10 @@ Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks
*/
Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(BMEditMesh *em,
const CustomData_MeshMasks *data_mask,
- float (*vertexCos)[3])
+ float (*vertexCos)[3],
+ const Mesh *me_settings)
{
- Mesh *me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, data_mask);
+ Mesh *me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, data_mask, me_settings);
/* Use editmesh directly where possible. */
me->runtime.is_original = true;
if (vertexCos) {
@@ -813,50 +839,49 @@ void BKE_mesh_make_local(Main *bmain, Mesh *me, const bool lib_local)
BKE_id_make_local_generic(bmain, &me->id, true, lib_local);
}
-void BKE_mesh_boundbox_calc(Mesh *me, float r_loc[3], float r_size[3])
+BoundBox *BKE_mesh_boundbox_get(Object *ob)
{
- BoundBox *bb;
- float min[3], max[3];
- float mloc[3], msize[3];
-
- if (me->bb == NULL) {
- me->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
- }
- bb = me->bb;
+ /* This is Object-level data access,
+ * DO NOT touch to Mesh's bb, would be totally thread-unsafe. */
+ if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
+ Mesh *me = ob->data;
+ float min[3], max[3];
- if (!r_loc) {
- r_loc = mloc;
- }
- if (!r_size) {
- r_size = msize;
- }
+ INIT_MINMAX(min, max);
+ if (!BKE_mesh_minmax(me, min, max)) {
+ min[0] = min[1] = min[2] = -1.0f;
+ max[0] = max[1] = max[2] = 1.0f;
+ }
- INIT_MINMAX(min, max);
- if (!BKE_mesh_minmax(me, min, max)) {
- min[0] = min[1] = min[2] = -1.0f;
- max[0] = max[1] = max[2] = 1.0f;
+ if (ob->runtime.bb == NULL) {
+ ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
+ }
+ BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
+ ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
}
- mid_v3_v3v3(r_loc, min, max);
-
- r_size[0] = (max[0] - min[0]) / 2.0f;
- r_size[1] = (max[1] - min[1]) / 2.0f;
- r_size[2] = (max[2] - min[2]) / 2.0f;
-
- BKE_boundbox_init_from_minmax(bb, min, max);
-
- bb->flag &= ~BOUNDBOX_DIRTY;
+ return ob->runtime.bb;
}
void BKE_mesh_texspace_calc(Mesh *me)
{
- float loc[3], size[3];
- int a;
+ if (me->texflag & ME_AUTOSPACE) {
+ float min[3], max[3];
- BKE_mesh_boundbox_calc(me, loc, size);
+ INIT_MINMAX(min, max);
+ if (!BKE_mesh_minmax(me, min, max)) {
+ min[0] = min[1] = min[2] = -1.0f;
+ max[0] = max[1] = max[2] = 1.0f;
+ }
- if (me->texflag & ME_AUTOSPACE) {
- for (a = 0; a < 3; a++) {
+ float loc[3], size[3];
+ mid_v3_v3v3(loc, min, max);
+
+ size[0] = (max[0] - min[0]) / 2.0f;
+ size[1] = (max[1] - min[1]) / 2.0f;
+ size[2] = (max[2] - min[2]) / 2.0f;
+
+ for (int a = 0; a < 3; a++) {
if (size[a] == 0.0f) {
size[a] = 1.0f;
}
@@ -870,59 +895,33 @@ void BKE_mesh_texspace_calc(Mesh *me)
copy_v3_v3(me->loc, loc);
copy_v3_v3(me->size, size);
- zero_v3(me->rot);
+
+ me->texflag |= ME_AUTOSPACE_EVALUATED;
}
}
-BoundBox *BKE_mesh_boundbox_get(Object *ob)
+void BKE_mesh_texspace_ensure(Mesh *me)
{
- /* This is Object-level data access,
- * DO NOT touch to Mesh's bb, would be totally thread-unsafe. */
- if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
- Mesh *me = ob->data;
- float min[3], max[3];
-
- INIT_MINMAX(min, max);
- if (!BKE_mesh_minmax(me, min, max)) {
- min[0] = min[1] = min[2] = -1.0f;
- max[0] = max[1] = max[2] = 1.0f;
- }
-
- if (ob->runtime.bb == NULL) {
- ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
- }
- BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
- ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
+ if ((me->texflag & ME_AUTOSPACE) && !(me->texflag & ME_AUTOSPACE_EVALUATED)) {
+ BKE_mesh_texspace_calc(me);
}
-
- return ob->runtime.bb;
}
-BoundBox *BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_rot[3], float r_size[3])
+void BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_size[3])
{
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
+ BKE_mesh_texspace_ensure(me);
if (r_loc) {
copy_v3_v3(r_loc, me->loc);
}
- if (r_rot) {
- copy_v3_v3(r_rot, me->rot);
- }
if (r_size) {
copy_v3_v3(r_size, me->size);
}
-
- return me->bb;
}
-void BKE_mesh_texspace_get_reference(
- Mesh *me, short **r_texflag, float **r_loc, float **r_rot, float **r_size)
+void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc, float **r_size)
{
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
+ BKE_mesh_texspace_ensure(me);
if (r_texflag != NULL) {
*r_texflag = &me->texflag;
@@ -930,9 +929,6 @@ void BKE_mesh_texspace_get_reference(
if (r_loc != NULL) {
*r_loc = me->loc;
}
- if (r_rot != NULL) {
- *r_rot = me->rot;
- }
if (r_size != NULL) {
*r_size = me->size;
}
@@ -940,14 +936,13 @@ void BKE_mesh_texspace_get_reference(
void BKE_mesh_texspace_copy_from_object(Mesh *me, Object *ob)
{
- float *texloc, *texrot, *texsize;
+ float *texloc, *texsize;
short *texflag;
- if (BKE_object_obdata_texspace_get(ob, &texflag, &texloc, &texsize, &texrot)) {
+ if (BKE_object_obdata_texspace_get(ob, &texflag, &texloc, &texsize)) {
me->texflag = *texflag;
copy_v3_v3(me->loc, texloc);
copy_v3_v3(me->size, texsize);
- copy_v3_v3(me->rot, texrot);
}
}
@@ -976,7 +971,7 @@ void BKE_mesh_orco_verts_transform(Mesh *me, float (*orco)[3], int totvert, int
float loc[3], size[3];
int a;
- BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, NULL, size);
+ BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, size);
if (invert) {
for (a = 0; a < totvert; a++) {
@@ -1082,12 +1077,12 @@ void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me)
{
Mesh *old = NULL;
- multires_force_update(ob);
-
if (ob == NULL) {
return;
}
+ multires_force_sculpt_rebuild(ob);
+
if (ob->type == OB_MESH) {
old = ob->data;
if (old) {
@@ -1951,9 +1946,6 @@ void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh)
{
DEG_debug_print_eval(depsgraph, __func__, mesh->id.name, mesh);
BKE_mesh_texspace_calc(mesh);
- /* Clear autospace flag in evaluated mesh, so that texspace does not get recomputed when bbox is
- * (e.g. after modifiers, etc.) */
- mesh->texflag &= ~ME_AUTOSPACE;
/* We are here because something did change in the mesh. This means we can not trust the existing
* evaluated mesh, and we don't know what parts of the mesh did change. So we simply delete the
* evaluated mesh and let objects to re-create it with updated settings. */
@@ -1964,15 +1956,10 @@ void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh)
}
if (DEG_is_active(depsgraph)) {
Mesh *mesh_orig = (Mesh *)DEG_get_original_id(&mesh->id);
- BoundBox *bb = mesh->bb;
- if (bb != NULL) {
- if (mesh_orig->bb == NULL) {
- mesh_orig->bb = MEM_mallocN(sizeof(*mesh_orig->bb), __func__);
- }
- *mesh_orig->bb = *bb;
+ if (mesh->texflag & ME_AUTOSPACE_EVALUATED) {
+ mesh_orig->texflag |= ME_AUTOSPACE_EVALUATED;
copy_v3_v3(mesh_orig->loc, mesh->loc);
copy_v3_v3(mesh_orig->size, mesh->size);
- copy_v3_v3(mesh_orig->rot, mesh->rot);
}
}
}
diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c
index e072a37acee..2ade368284c 100644
--- a/source/blender/blenkernel/intern/mesh_convert.c
+++ b/source/blender/blenkernel/intern/mesh_convert.c
@@ -265,9 +265,11 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob,
const float *data;
int a, b, ofs, vertcount, startvert, totvert = 0, totedge = 0, totloop = 0, totpoly = 0;
int p1, p2, p3, p4, *index;
- const bool conv_polys = ((CU_DO_2DFILL(cu) ==
- false) || /* 2d polys are filled with DL_INDEX3 displists */
- (ob->type == OB_SURF)); /* surf polys are never filled */
+ const bool conv_polys = (
+ /* 2d polys are filled with DL_INDEX3 displists */
+ (CU_DO_2DFILL(cu) == false) ||
+ /* surf polys are never filled */
+ (ob->type == OB_SURF));
/* count */
dl = dispbase->first;
@@ -554,7 +556,7 @@ Mesh *BKE_mesh_new_nomain_from_curve_displist(Object *ob, ListBase *dispbase)
memcpy(mesh->mpoly, allpoly, totpoly * sizeof(MPoly));
if (alluv) {
- const char *uvname = "Orco";
+ const char *uvname = "UVMap";
CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, totloop, uvname);
}
@@ -633,7 +635,7 @@ void BKE_mesh_from_nurbs_displist(Main *bmain,
me->mpoly = CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, allpoly, me->totpoly);
if (alluv) {
- const char *uvname = "Orco";
+ const char *uvname = "UVMap";
me->mloopuv = CustomData_add_layer_named(
&me->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, me->totloop, uvname);
}
@@ -665,7 +667,6 @@ void BKE_mesh_from_nurbs_displist(Main *bmain,
me->texflag = cu->texflag & ~CU_AUTOSPACE;
copy_v3_v3(me->loc, cu->loc);
copy_v3_v3(me->size, cu->size);
- copy_v3_v3(me->rot, cu->rot);
BKE_mesh_texspace_calc(me);
cu->mat = NULL;
@@ -1078,6 +1079,7 @@ static Mesh *mesh_new_from_mball_object(Object *object)
Mesh *mesh_result = BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2);
BKE_mesh_from_metaball(&object->runtime.curve_cache->disp, mesh_result);
+ BKE_mesh_texspace_copy_from_object(mesh_result, object);
/* Copy materials. */
mesh_result->totcol = mball->totcol;
@@ -1573,11 +1575,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
/* Clear selection history */
MEM_SAFE_FREE(tmp.mselect);
tmp.totselect = 0;
- BLI_assert(ELEM(tmp.bb, NULL, mesh_dst->bb));
- if (mesh_dst->bb) {
- MEM_freeN(mesh_dst->bb);
- tmp.bb = NULL;
- }
+ tmp.texflag &= ~ME_AUTOSPACE_EVALUATED;
/* skip the listbase */
MEMCPY_STRUCT_AFTER(mesh_dst, &tmp, id.prev);
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 38762109167..7a1dcb4a5fd 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -2320,6 +2320,24 @@ float BKE_mesh_calc_poly_area(const MPoly *mpoly, const MLoop *loopstart, const
}
}
+float BKE_mesh_calc_area(const Mesh *me)
+{
+ MVert *mvert = me->mvert;
+ MLoop *mloop = me->mloop;
+ MPoly *mpoly = me->mpoly;
+
+ MPoly *mp;
+ int i = me->totpoly;
+ float total_area = 0;
+
+ for (mp = mpoly; i--; mp++) {
+ MLoop *ml_start = &mloop[mp->loopstart];
+
+ total_area += BKE_mesh_calc_poly_area(mp, ml_start, mvert);
+ }
+ return total_area;
+}
+
float BKE_mesh_calc_poly_uv_area(const MPoly *mpoly, const MLoopUV *uv_array)
{
diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.c b/source/blender/blenkernel/intern/mesh_remesh_voxel.c
index a5136311a22..8419a72f97e 100644
--- a/source/blender/blenkernel/intern/mesh_remesh_voxel.c
+++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.c
@@ -38,6 +38,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BKE_editmesh.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_library.h"
@@ -45,10 +46,16 @@
#include "BKE_bvhutils.h"
#include "BKE_mesh_remesh_voxel.h" /* own include */
+#include "bmesh_tools.h"
+
#ifdef WITH_OPENVDB
# include "openvdb_capi.h"
#endif
+#ifdef WITH_QUADRIFLOW
+# include "quadriflow_capi.hpp"
+#endif
+
#ifdef WITH_OPENVDB
struct OpenVDBLevelSet *BKE_mesh_remesh_voxel_ovdb_mesh_to_level_set_create(
Mesh *mesh, struct OpenVDBTransform *transform)
@@ -146,7 +153,149 @@ Mesh *BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(struct OpenVDBLevelSet *l
}
#endif
-Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(Mesh *mesh, float voxel_size)
+#ifdef WITH_QUADRIFLOW
+static Mesh *BKE_mesh_remesh_quadriflow(Mesh *input_mesh,
+ int target_faces,
+ int seed,
+ bool preserve_sharp,
+ bool preserve_boundary,
+ bool adaptive_scale,
+ void *update_cb,
+ void *update_cb_data)
+{
+ /* Ensure that the triangulated mesh data is up to data */
+ BKE_mesh_runtime_looptri_recalc(input_mesh);
+ const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(input_mesh);
+
+ /* Gather the required data for export to the internal quadiflow mesh format */
+ MVertTri *verttri = MEM_callocN(sizeof(*verttri) * BKE_mesh_runtime_looptri_len(input_mesh),
+ "remesh_looptri");
+ BKE_mesh_runtime_verttri_from_looptri(
+ verttri, input_mesh->mloop, looptri, BKE_mesh_runtime_looptri_len(input_mesh));
+
+ unsigned int totfaces = BKE_mesh_runtime_looptri_len(input_mesh);
+ unsigned int totverts = input_mesh->totvert;
+ float *verts = (float *)MEM_malloc_arrayN(totverts * 3, sizeof(float), "remesh_input_verts");
+ unsigned int *faces = (unsigned int *)MEM_malloc_arrayN(
+ totfaces * 3, sizeof(unsigned int), "remesh_intput_faces");
+
+ for (unsigned int i = 0; i < totverts; i++) {
+ MVert *mvert = &input_mesh->mvert[i];
+ verts[i * 3] = mvert->co[0];
+ verts[i * 3 + 1] = mvert->co[1];
+ verts[i * 3 + 2] = mvert->co[2];
+ }
+
+ for (unsigned int i = 0; i < totfaces; i++) {
+ MVertTri *vt = &verttri[i];
+ faces[i * 3] = vt->tri[0];
+ faces[i * 3 + 1] = vt->tri[1];
+ faces[i * 3 + 2] = vt->tri[2];
+ }
+
+ /* Fill out the required input data */
+ QuadriflowRemeshData qrd;
+
+ qrd.totfaces = totfaces;
+ qrd.totverts = totverts;
+ qrd.verts = verts;
+ qrd.faces = faces;
+ qrd.target_faces = target_faces;
+
+ qrd.preserve_sharp = preserve_sharp;
+ qrd.preserve_boundary = preserve_boundary;
+ qrd.adaptive_scale = adaptive_scale;
+ qrd.minimum_cost_flow = 0;
+ qrd.aggresive_sat = 0;
+ qrd.rng_seed = seed;
+
+ qrd.out_faces = NULL;
+
+ /* Run the remesher */
+ QFLOW_quadriflow_remesh(&qrd, update_cb, update_cb_data);
+
+ MEM_freeN(verts);
+ MEM_freeN(faces);
+ MEM_freeN(verttri);
+
+ if (qrd.out_faces == NULL) {
+ /* The remeshing was canceled */
+ return NULL;
+ }
+
+ if (qrd.out_totfaces == 0) {
+ /* Meshing failed */
+ MEM_freeN(qrd.out_faces);
+ MEM_freeN(qrd.out_verts);
+ return NULL;
+ }
+
+ /* Construct the new output mesh */
+ Mesh *mesh = BKE_mesh_new_nomain(
+ qrd.out_totverts, 0, 0, (qrd.out_totfaces * 4), qrd.out_totfaces);
+
+ for (int i = 0; i < qrd.out_totverts; i++) {
+ copy_v3_v3(mesh->mvert[i].co, &qrd.out_verts[i * 3]);
+ }
+
+ MPoly *mp = mesh->mpoly;
+ MLoop *ml = mesh->mloop;
+ for (int i = 0; i < qrd.out_totfaces; i++, mp++, ml += 4) {
+ mp->loopstart = (int)(ml - mesh->mloop);
+ mp->totloop = 4;
+
+ ml[0].v = qrd.out_faces[i * 4];
+ ml[1].v = qrd.out_faces[i * 4 + 1];
+ ml[2].v = qrd.out_faces[i * 4 + 2];
+ ml[3].v = qrd.out_faces[i * 4 + 3];
+ }
+
+ BKE_mesh_calc_edges(mesh, false, false);
+ BKE_mesh_calc_normals(mesh);
+
+ MEM_freeN(qrd.out_faces);
+ MEM_freeN(qrd.out_verts);
+
+ return mesh;
+}
+#endif
+
+Mesh *BKE_mesh_remesh_quadriflow_to_mesh_nomain(Mesh *mesh,
+ int target_faces,
+ int seed,
+ bool preserve_sharp,
+ bool preserve_boundary,
+ bool adaptive_scale,
+ void *update_cb,
+ void *update_cb_data)
+{
+ Mesh *new_mesh = NULL;
+#ifdef WITH_QUADRIFLOW
+ if (target_faces <= 0) {
+ target_faces = -1;
+ }
+ new_mesh = BKE_mesh_remesh_quadriflow(mesh,
+ target_faces,
+ seed,
+ preserve_sharp,
+ preserve_boundary,
+ adaptive_scale,
+ update_cb,
+ update_cb_data);
+#else
+ UNUSED_VARS(mesh,
+ target_faces,
+ seed,
+ preserve_sharp,
+ preserve_boundary,
+ adaptive_scale,
+ update_cb,
+ update_cb_data);
+#endif
+ return new_mesh;
+}
+
+Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(Mesh *mesh, float voxel_size, float adaptivity)
{
Mesh *new_mesh = NULL;
#ifdef WITH_OPENVDB
@@ -154,11 +303,12 @@ Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(Mesh *mesh, float voxel_size)
struct OpenVDBTransform *xform = OpenVDBTransform_create();
OpenVDBTransform_create_linear_transform(xform, (double)voxel_size);
level_set = BKE_mesh_remesh_voxel_ovdb_mesh_to_level_set_create(mesh, xform);
- new_mesh = BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(level_set, 0.0, 0.0, false);
+ new_mesh = BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(
+ level_set, 0.0, (float)adaptivity, false);
OpenVDBLevelSet_free(level_set);
OpenVDBTransform_free(xform);
#else
- UNUSED_VARS(mesh, voxel_size);
+ UNUSED_VARS(mesh, voxel_size, adaptivity);
#endif
return new_mesh;
}
@@ -202,3 +352,106 @@ void BKE_remesh_reproject_paint_mask(Mesh *target, Mesh *source)
}
free_bvhtree_from_mesh(&bvhtree);
}
+
+struct Mesh *BKE_mesh_remesh_voxel_fix_poles(struct Mesh *mesh)
+{
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
+ BMesh *bm;
+ bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = true,
+ }));
+
+ BM_mesh_bm_from_me(bm,
+ mesh,
+ (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
+
+ BMVert *v;
+ BMEdge *ed, *ed_next;
+ BMFace *f, *f_next;
+ BMIter iter_a, iter_b;
+
+ /* Merge 3 edge poles vertices that exist in the same face */
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ BM_ITER_MESH_MUTABLE (f, f_next, &iter_a, bm, BM_FACES_OF_MESH) {
+ BMVert *v1, *v2;
+ v1 = NULL;
+ v2 = NULL;
+ BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) {
+ if (BM_vert_edge_count(v) == 3) {
+ if (v1) {
+ v2 = v;
+ }
+ else {
+ v1 = v;
+ }
+ }
+ }
+ if (v1 && v2 && (v1 != v2) && !BM_edge_exists(v1, v2)) {
+ BM_face_kill(bm, f);
+ BMEdge *e = BM_edge_create(bm, v1, v2, NULL, BM_CREATE_NOP);
+ BM_elem_flag_set(e, BM_ELEM_TAG, true);
+ }
+ }
+
+ BM_ITER_MESH_MUTABLE (ed, ed_next, &iter_a, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(ed, BM_ELEM_TAG)) {
+ float co[3];
+ mid_v3_v3v3(co, ed->v1->co, ed->v2->co);
+ BMVert *vc = BM_edge_collapse(bm, ed, ed->v1, true, true);
+ copy_v3_v3(vc->co, co);
+ }
+ }
+
+ /* Delete faces with a 3 edge pole in all their vertices */
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ BM_ITER_MESH (f, &iter_a, bm, BM_FACES_OF_MESH) {
+ bool dissolve = true;
+ BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) {
+ if (BM_vert_edge_count(v) != 3) {
+ dissolve = false;
+ }
+ }
+ if (dissolve) {
+ BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) {
+ BM_elem_flag_set(v, BM_ELEM_TAG, true);
+ }
+ }
+ }
+ BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_VERTS);
+
+ BM_ITER_MESH (ed, &iter_a, bm, BM_EDGES_OF_MESH) {
+ if (BM_edge_face_count(ed) != 2) {
+ BM_elem_flag_set(ed, BM_ELEM_TAG, true);
+ }
+ }
+ BM_mesh_edgenet(bm, false, true);
+
+ /* Smooth the result */
+ for (int i = 0; i < 4; i++) {
+ BM_ITER_MESH (v, &iter_a, bm, BM_VERTS_OF_MESH) {
+ float co[3];
+ zero_v3(co);
+ BM_ITER_ELEM (ed, &iter_b, v, BM_EDGES_OF_VERT) {
+ BMVert *vert = BM_edge_other_vert(ed, v);
+ add_v3_v3(co, vert->co);
+ }
+ mul_v3_fl(co, 1.0f / (float)BM_vert_edge_count(v));
+ mid_v3_v3v3(v->co, v->co, co);
+ }
+ }
+
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+
+ Mesh *result = BKE_mesh_from_bmesh_nomain(bm,
+ (&(struct BMeshToMeshParams){
+ .calc_object_remap = false,
+ }),
+ mesh);
+
+ BKE_id_free(NULL, mesh);
+ BM_mesh_free(bm);
+ return result;
+}
diff --git a/source/blender/blenkernel/intern/mirror.c b/source/blender/blenkernel/intern/mirror.c
new file mode 100644
index 00000000000..c429b953015
--- /dev/null
+++ b/source/blender/blenkernel/intern/mirror.c
@@ -0,0 +1,413 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BLI_math.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_mesh.h"
+#include "BKE_mirror.h"
+#include "BKE_modifier.h"
+#include "BKE_deform.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "MOD_modifiertypes.h"
+
+Mesh *BKE_mirror_bisect_on_mirror_plane(MirrorModifierData *mmd,
+ const Mesh *mesh,
+ int axis,
+ const float plane_co[3],
+ float plane_no[3])
+{
+ bool do_bisect_flip_axis = ((axis == 0 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_X) ||
+ (axis == 1 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Y) ||
+ (axis == 2 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Z));
+
+ const float bisect_distance = 0.001f;
+
+ Mesh *result;
+ BMesh *bm;
+ BMIter viter;
+ BMVert *v, *v_next;
+
+ bm = BKE_mesh_to_bmesh_ex(mesh,
+ &(struct BMeshCreateParams){0},
+ &(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX,
+ .emask = CD_MASK_ORIGINDEX,
+ .pmask = CD_MASK_ORIGINDEX},
+ });
+
+ /* Define bisecting plane (aka mirror plane). */
+ float plane[4];
+ if (!do_bisect_flip_axis) {
+ /* That reversed condition is a tad weird, but for some reason that's how you keep
+ * the part of the mesh which is on the non-mirrored side when flip option is disabled,
+ * think that that is the expected behavior. */
+ negate_v3(plane_no);
+ }
+ plane_from_point_normal_v3(plane, plane_co, plane_no);
+
+ BM_mesh_bisect_plane(bm, plane, false, false, 0, 0, bisect_distance);
+
+ /* Plane definitions for vert killing. */
+ float plane_offset[4];
+ copy_v3_v3(plane_offset, plane);
+ plane_offset[3] = plane[3] - bisect_distance;
+
+ /* Delete verts across the mirror plane. */
+ BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) {
+ if (plane_point_side_v3(plane_offset, v->co) > 0.0f) {
+ BM_vert_kill(bm, v);
+ }
+ }
+
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
+ BM_mesh_free(bm);
+
+ return result;
+}
+
+Mesh *BKE_mirror_apply_mirror_on_axis(MirrorModifierData *mmd,
+ const ModifierEvalContext *UNUSED(ctx),
+ Object *ob,
+ const Mesh *mesh,
+ int axis)
+{
+ const float tolerance_sq = mmd->tolerance * mmd->tolerance;
+ const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0;
+ int tot_vtargetmap = 0; /* total merge vertices */
+
+ const bool do_bisect = ((axis == 0 && mmd->flag & MOD_MIR_BISECT_AXIS_X) ||
+ (axis == 1 && mmd->flag & MOD_MIR_BISECT_AXIS_Y) ||
+ (axis == 2 && mmd->flag & MOD_MIR_BISECT_AXIS_Z));
+
+ Mesh *result;
+ MVert *mv, *mv_prev;
+ MEdge *me;
+ MLoop *ml;
+ MPoly *mp;
+ float mtx[4][4];
+ float plane_co[3], plane_no[3];
+ int i;
+ int a, totshape;
+ int *vtargetmap = NULL, *vtmap_a = NULL, *vtmap_b = NULL;
+
+ /* mtx is the mirror transformation */
+ unit_m4(mtx);
+ mtx[axis][axis] = -1.0f;
+
+ Object *mirror_ob = mmd->mirror_ob;
+ if (mirror_ob != NULL) {
+ float tmp[4][4];
+ float itmp[4][4];
+
+ /* tmp is a transform from coords relative to the object's own origin,
+ * to coords relative to the mirror object origin */
+ invert_m4_m4(tmp, mirror_ob->obmat);
+ mul_m4_m4m4(tmp, tmp, ob->obmat);
+
+ /* itmp is the reverse transform back to origin-relative coordinates */
+ invert_m4_m4(itmp, tmp);
+
+ /* combine matrices to get a single matrix that translates coordinates into
+ * mirror-object-relative space, does the mirror, and translates back to
+ * origin-relative space */
+ mul_m4_series(mtx, itmp, mtx, tmp);
+
+ if (do_bisect) {
+ copy_v3_v3(plane_co, itmp[3]);
+ copy_v3_v3(plane_no, itmp[axis]);
+ }
+ }
+ else if (do_bisect) {
+ copy_v3_v3(plane_co, mtx[3]);
+ /* Need to negate here, since that axis is inverted (for mirror transform). */
+ negate_v3_v3(plane_no, mtx[axis]);
+ }
+
+ Mesh *mesh_bisect = NULL;
+ if (do_bisect) {
+ mesh_bisect = BKE_mirror_bisect_on_mirror_plane(mmd, mesh, axis, plane_co, plane_no);
+ mesh = mesh_bisect;
+ }
+
+ const int maxVerts = mesh->totvert;
+ const int maxEdges = mesh->totedge;
+ const int maxLoops = mesh->totloop;
+ const int maxPolys = mesh->totpoly;
+
+ result = BKE_mesh_new_nomain_from_template(
+ mesh, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2);
+
+ /*copy customdata to original geometry*/
+ CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, maxVerts);
+ CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, maxEdges);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, maxLoops);
+ CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, maxPolys);
+
+ /* Subsurf for eg won't have mesh data in the custom data arrays.
+ * now add mvert/medge/mpoly layers. */
+ if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) {
+ memcpy(result->mvert, mesh->mvert, sizeof(*result->mvert) * mesh->totvert);
+ }
+ if (!CustomData_has_layer(&mesh->edata, CD_MEDGE)) {
+ memcpy(result->medge, mesh->medge, sizeof(*result->medge) * mesh->totedge);
+ }
+ if (!CustomData_has_layer(&mesh->pdata, CD_MPOLY)) {
+ memcpy(result->mloop, mesh->mloop, sizeof(*result->mloop) * mesh->totloop);
+ memcpy(result->mpoly, mesh->mpoly, sizeof(*result->mpoly) * mesh->totpoly);
+ }
+
+ /* copy customdata to new geometry,
+ * copy from its self because this data may have been created in the checks above */
+ CustomData_copy_data(&result->vdata, &result->vdata, 0, maxVerts, maxVerts);
+ CustomData_copy_data(&result->edata, &result->edata, 0, maxEdges, maxEdges);
+ /* loops are copied later */
+ CustomData_copy_data(&result->pdata, &result->pdata, 0, maxPolys, maxPolys);
+
+ if (do_vtargetmap) {
+ /* second half is filled with -1 */
+ vtargetmap = MEM_malloc_arrayN(maxVerts, 2 * sizeof(int), "MOD_mirror tarmap");
+
+ vtmap_a = vtargetmap;
+ vtmap_b = vtargetmap + maxVerts;
+ }
+
+ /* mirror vertex coordinates */
+ mv_prev = result->mvert;
+ mv = mv_prev + maxVerts;
+ for (i = 0; i < maxVerts; i++, mv++, mv_prev++) {
+ mul_m4_v3(mtx, mv->co);
+
+ if (do_vtargetmap) {
+ /* compare location of the original and mirrored vertex, to see if they
+ * should be mapped for merging */
+ if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
+ *vtmap_a = maxVerts + i;
+ tot_vtargetmap++;
+
+ /* average location */
+ mid_v3_v3v3(mv->co, mv_prev->co, mv->co);
+ copy_v3_v3(mv_prev->co, mv->co);
+ }
+ else {
+ *vtmap_a = -1;
+ }
+
+ *vtmap_b = -1; /* fill here to avoid 2x loops */
+
+ vtmap_a++;
+ vtmap_b++;
+ }
+ }
+
+ /* handle shape keys */
+ totshape = CustomData_number_of_layers(&result->vdata, CD_SHAPEKEY);
+ for (a = 0; a < totshape; a++) {
+ float(*cos)[3] = CustomData_get_layer_n(&result->vdata, CD_SHAPEKEY, a);
+ for (i = maxVerts; i < result->totvert; i++) {
+ mul_m4_v3(mtx, cos[i]);
+ }
+ }
+
+ /* adjust mirrored edge vertex indices */
+ me = result->medge + maxEdges;
+ for (i = 0; i < maxEdges; i++, me++) {
+ me->v1 += maxVerts;
+ me->v2 += maxVerts;
+ }
+
+ /* adjust mirrored poly loopstart indices, and reverse loop order (normals) */
+ mp = result->mpoly + maxPolys;
+ ml = result->mloop;
+ for (i = 0; i < maxPolys; i++, mp++) {
+ MLoop *ml2;
+ int j, e;
+
+ /* reverse the loop, but we keep the first vertex in the face the same,
+ * to ensure that quads are split the same way as on the other side */
+ CustomData_copy_data(
+ &result->ldata, &result->ldata, mp->loopstart, mp->loopstart + maxLoops, 1);
+
+ for (j = 1; j < mp->totloop; j++) {
+ CustomData_copy_data(&result->ldata,
+ &result->ldata,
+ mp->loopstart + j,
+ mp->loopstart + maxLoops + mp->totloop - j,
+ 1);
+ }
+
+ ml2 = ml + mp->loopstart + maxLoops;
+ e = ml2[0].e;
+ for (j = 0; j < mp->totloop - 1; j++) {
+ ml2[j].e = ml2[j + 1].e;
+ }
+ ml2[mp->totloop - 1].e = e;
+
+ mp->loopstart += maxLoops;
+ }
+
+ /* adjust mirrored loop vertex and edge indices */
+ ml = result->mloop + maxLoops;
+ for (i = 0; i < maxLoops; i++, ml++) {
+ ml->v += maxVerts;
+ ml->e += maxEdges;
+ }
+
+ /* handle uvs,
+ * let tessface recalc handle updating the MTFace data */
+ if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V) ||
+ (is_zero_v2(mmd->uv_offset_copy) == false)) {
+ const bool do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0;
+ const bool do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0;
+
+ const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV);
+
+ for (a = 0; a < totuv; a++) {
+ MLoopUV *dmloopuv = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, a);
+ int j = maxLoops;
+ dmloopuv += j; /* second set of loops only */
+ for (; j-- > 0; dmloopuv++) {
+ if (do_mirr_u) {
+ dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0] + mmd->uv_offset[0];
+ }
+ if (do_mirr_v) {
+ dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1] + mmd->uv_offset[1];
+ }
+ dmloopuv->uv[0] += mmd->uv_offset_copy[0];
+ dmloopuv->uv[1] += mmd->uv_offset_copy[1];
+ }
+ }
+ }
+
+ /* handle custom split normals */
+ if (ob->type == OB_MESH && (((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) &&
+ CustomData_has_layer(&result->ldata, CD_CUSTOMLOOPNORMAL)) {
+ const int totloop = result->totloop;
+ const int totpoly = result->totpoly;
+ float(*loop_normals)[3] = MEM_calloc_arrayN((size_t)totloop, sizeof(*loop_normals), __func__);
+ CustomData *ldata = &result->ldata;
+ short(*clnors)[2] = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
+ MLoopNorSpaceArray lnors_spacearr = {NULL};
+ float(*poly_normals)[3] = MEM_mallocN(sizeof(*poly_normals) * totpoly, __func__);
+
+ /* calculate custom normals into loop_normals, then mirror first half into second half */
+
+ BKE_mesh_calc_normals_poly(result->mvert,
+ NULL,
+ result->totvert,
+ result->mloop,
+ result->mpoly,
+ totloop,
+ totpoly,
+ poly_normals,
+ false);
+
+ BKE_mesh_normals_loop_split(result->mvert,
+ result->totvert,
+ result->medge,
+ result->totedge,
+ result->mloop,
+ loop_normals,
+ totloop,
+ result->mpoly,
+ poly_normals,
+ totpoly,
+ true,
+ mesh->smoothresh,
+ &lnors_spacearr,
+ clnors,
+ NULL);
+
+ /* mirroring has to account for loops being reversed in polys in second half */
+ mp = result->mpoly;
+ for (i = 0; i < maxPolys; i++, mp++) {
+ MPoly *mpmirror = result->mpoly + maxPolys + i;
+ int j;
+
+ for (j = mp->loopstart; j < mp->loopstart + mp->totloop; j++) {
+ int mirrorj = mpmirror->loopstart;
+ if (j > mp->loopstart) {
+ mirrorj += mpmirror->totloop - (j - mp->loopstart);
+ }
+ copy_v3_v3(loop_normals[mirrorj], loop_normals[j]);
+ loop_normals[mirrorj][axis] = -loop_normals[j][axis];
+ BKE_lnor_space_custom_normal_to_data(
+ lnors_spacearr.lspacearr[mirrorj], loop_normals[mirrorj], clnors[mirrorj]);
+ }
+ }
+
+ MEM_freeN(poly_normals);
+ MEM_freeN(loop_normals);
+ BKE_lnor_spacearr_free(&lnors_spacearr);
+ }
+
+ /* handle vgroup stuff */
+ if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&result->vdata, CD_MDEFORMVERT)) {
+ MDeformVert *dvert = (MDeformVert *)CustomData_get_layer(&result->vdata, CD_MDEFORMVERT) +
+ maxVerts;
+ int *flip_map = NULL, flip_map_len = 0;
+
+ flip_map = defgroup_flip_map(ob, &flip_map_len, false);
+
+ if (flip_map) {
+ for (i = 0; i < maxVerts; dvert++, i++) {
+ /* merged vertices get both groups, others get flipped */
+ if (do_vtargetmap && (vtargetmap[i] != -1)) {
+ defvert_flip_merged(dvert, flip_map, flip_map_len);
+ }
+ else {
+ defvert_flip(dvert, flip_map, flip_map_len);
+ }
+ }
+
+ MEM_freeN(flip_map);
+ }
+ }
+
+ if (do_vtargetmap) {
+ /* slow - so only call if one or more merge verts are found,
+ * users may leave this on and not realize there is nothing to merge - campbell */
+ if (tot_vtargetmap) {
+ result = BKE_mesh_merge_verts(
+ result, vtargetmap, tot_vtargetmap, MESH_MERGE_VERTS_DUMP_IF_MAPPED);
+ }
+ MEM_freeN(vtargetmap);
+ }
+
+ if (mesh_bisect != NULL) {
+ BKE_id_free(NULL, mesh_bisect);
+ }
+
+ return result;
+}
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index bbae1f4d3bc..6a5e31bd2a2 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -406,25 +406,38 @@ void multires_mark_as_modified(Depsgraph *depsgraph, Object *object, MultiresMod
multires_ccg_mark_as_modified(subdiv_ccg, flags);
}
-void multires_force_update(Object *ob)
+void multires_flush_sculpt_updates(Object *ob)
{
- if (ob == NULL) {
- return;
- }
- SculptSession *sculpt_session = ob->sculpt;
- if (sculpt_session != NULL && sculpt_session->pbvh != NULL) {
- PBVH *pbvh = sculpt_session->pbvh;
- if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) {
+ if (ob && ob->sculpt && ob->sculpt->pbvh != NULL) {
+ SculptSession *sculpt_session = ob->sculpt;
+ if (BKE_pbvh_type(sculpt_session->pbvh) == PBVH_GRIDS) {
Mesh *mesh = ob->data;
multiresModifier_reshapeFromCCG(
sculpt_session->multires->totlvl, mesh, sculpt_session->subdiv_ccg);
}
- else {
- /* NOTE: Disabled for until OpenSubdiv is enabled by default. */
- // BLI_assert(!"multires_force_update is used on non-grids PBVH");
+ }
+}
+
+void multires_force_sculpt_rebuild(Object *ob)
+{
+ multires_flush_sculpt_updates(ob);
+
+ if (ob && ob->sculpt) {
+ SculptSession *ss = ob->sculpt;
+ if (ss->pbvh) {
+ BKE_pbvh_free(ss->pbvh);
+ ob->sculpt->pbvh = NULL;
+ }
+
+ if (ss->pmap) {
+ MEM_freeN(ss->pmap);
+ ss->pmap = NULL;
+ }
+
+ if (ss->pmap_mem) {
+ MEM_freeN(ss->pmap_mem);
+ ss->pmap_mem = NULL;
}
- BKE_pbvh_free(pbvh);
- ob->sculpt->pbvh = NULL;
}
}
@@ -433,14 +446,7 @@ void multires_force_external_reload(Object *ob)
Mesh *me = BKE_mesh_from_object(ob);
CustomData_external_reload(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
- multires_force_update(ob);
-}
-
-void multires_force_render_update(Object *ob)
-{
- if (ob && (ob->mode & OB_MODE_SCULPT) && modifiers_findByType(ob, eModifierType_Multires)) {
- multires_force_update(ob);
- }
+ multires_force_sculpt_rebuild(ob);
}
/* reset the multires levels to match the number of mdisps */
@@ -452,7 +458,7 @@ static int get_levels_from_disps(Object *ob)
mdisp = CustomData_get_layer(&me->ldata, CD_MDISPS);
- for (i = 0; i < me->totpoly; ++i) {
+ for (i = 0; i < me->totpoly; i++) {
md = mdisp + me->mpoly[i].loopstart;
for (j = 0; j < me->mpoly[i].totloop; j++, md++) {
@@ -520,7 +526,7 @@ static void multires_reallocate_mdisps(int totloop, MDisps *mdisps, int lvl)
int i;
/* reallocate displacements to be filled in */
- for (i = 0; i < totloop; ++i) {
+ for (i = 0; i < totloop; i++) {
int totdisp = multires_grid_tot[lvl];
float(*disps)[3] = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disps");
@@ -624,7 +630,7 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl)
mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
gpm = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK);
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
if (mdisps && levels > 0) {
if (lvl > 0) {
@@ -633,7 +639,7 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl)
int hsize = multires_side_tot[mmd->totlvl];
int i, j;
- for (i = 0; i < me->totpoly; ++i) {
+ for (i = 0; i < me->totpoly; i++) {
for (j = 0; j < me->mpoly[i].totloop; j++) {
int g = me->mpoly[i].loopstart + j;
MDisps *mdisp = &mdisps[g];
@@ -689,7 +695,7 @@ void multiresModifier_del_levels(MultiresModifierData *mmd,
CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
if (mdisps && levels > 0 && direction == 1) {
multires_del_higher(mmd, ob, lvl);
@@ -781,7 +787,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object
float(*origco)[3];
int i, j, k, offset, totlvl;
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
me = BKE_mesh_from_object(ob);
totlvl = mmd->totlvl;
@@ -802,7 +808,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object
/* copy the new locations of the base verts into the mesh */
offset = dispdm->getNumVerts(dispdm) - me->totvert;
- for (i = 0; i < me->totvert; ++i) {
+ for (i = 0; i < me->totvert; i++) {
dispdm->getVertCo(dispdm, offset + i, me->mvert[i].co);
}
@@ -811,11 +817,11 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object
cddm = CDDM_from_mesh(me);
pmap = cddm->getPolyMap(ob, cddm);
origco = MEM_calloc_arrayN(me->totvert, 3 * sizeof(float), "multires apply base origco");
- for (i = 0; i < me->totvert; ++i) {
+ for (i = 0; i < me->totvert; i++) {
copy_v3_v3(origco[i], me->mvert[i].co);
}
- for (i = 0; i < me->totvert; ++i) {
+ for (i = 0; i < me->totvert; i++) {
float avg_no[3] = {0, 0, 0}, center[3] = {0, 0, 0}, push[3];
float dist;
int tot = 0;
@@ -830,7 +836,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object
const MPoly *p = &me->mpoly[pmap[i].indices[j]];
/* this double counts, not sure if that's bad or good */
- for (k = 0; k < p->totloop; ++k) {
+ for (k = 0; k < p->totloop; k++) {
int vndx = me->mloop[p->loopstart + k].v;
if (vndx != i) {
add_v3_v3(center, origco[vndx]);
@@ -855,7 +861,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object
fake_loops = MEM_malloc_arrayN(p->totloop, sizeof(MLoop), "fake_loops");
fake_co = MEM_malloc_arrayN(p->totloop, 3 * sizeof(float), "fake_co");
- for (k = 0; k < p->totloop; ++k) {
+ for (k = 0; k < p->totloop; k++) {
int vndx = me->mloop[p->loopstart + k].v;
fake_loops[k].v = k;
@@ -928,7 +934,7 @@ static void multires_subdivide(
BLI_assert(totlvl > lvl);
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
if (!mdisps) {
@@ -975,7 +981,7 @@ static void multires_subdivide(
subGridData = MEM_calloc_arrayN(numGrids, sizeof(float *), "subGridData*");
- for (i = 0; i < numGrids; ++i) {
+ for (i = 0; i < numGrids; i++) {
/* backup subsurf grids */
subGridData[i] = MEM_calloc_arrayN(
highGridKey.elem_size, highGridSize * highGridSize, "subGridData");
@@ -1000,7 +1006,7 @@ static void multires_subdivide(
/* free */
highdm->release(highdm);
- for (i = 0; i < numGrids; ++i) {
+ for (i = 0; i < numGrids; i++) {
MEM_freeN(subGridData[i]);
}
MEM_freeN(subGridData);
@@ -1097,7 +1103,7 @@ static void multires_disp_run_cb(void *__restrict userdata,
const int numVerts = mpoly[pidx].totloop;
int S, x, y, gIndex = gridOffset[pidx];
- for (S = 0; S < numVerts; ++S, ++gIndex) {
+ for (S = 0; S < numVerts; S++, gIndex++) {
GridPaintMask *gpm = grid_paint_mask ? &grid_paint_mask[gIndex] : NULL;
MDisps *mdisp = &mdisps[mpoly[pidx].loopstart + S];
CCGElem *grid = gridData[gIndex];
@@ -1223,7 +1229,7 @@ static void multiresModifier_disp_run(
}
/* when adding new faces in edit mode, need to allocate disps */
- for (i = 0; i < totloop; ++i) {
+ for (i = 0; i < totloop; i++) {
if (mdisps[i].disps == NULL) {
multires_reallocate_mdisps(totloop, mdisps, totlvl);
break;
@@ -1324,7 +1330,7 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene)
subGridData = MEM_calloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*");
diffGrid = MEM_calloc_arrayN(lowGridKey.elem_size, lowGridSize * lowGridSize, "diff");
- for (i = 0; i < numGrids; ++i) {
+ for (i = 0; i < numGrids; i++) {
/* backup subsurf grids */
subGridData[i] = MEM_calloc_arrayN(
highGridKey.elem_size, highGridSize * highGridSize, "subGridData");
@@ -1332,7 +1338,7 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene)
subGridData[i], highGridData[i], highGridKey.elem_size * highGridSize * highGridSize);
/* write difference of subsurf and displaced low level into high subsurf */
- for (j = 0; j < lowGridSize * lowGridSize; ++j) {
+ for (j = 0; j < lowGridSize * lowGridSize; j++) {
sub_v4_v4v4(CCG_elem_offset_co(&lowGridKey, diffGrid, j),
CCG_elem_offset_co(&lowGridKey, gridData[i], j),
CCG_elem_offset_co(&lowGridKey, lowGridData[i], j));
@@ -1354,7 +1360,7 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene)
/* free */
highdm->release(highdm);
- for (i = 0; i < numGrids; ++i) {
+ for (i = 0; i < numGrids; i++) {
MEM_freeN(subGridData[i]);
}
MEM_freeN(subGridData);
@@ -1617,8 +1623,8 @@ static void old_mdisps_convert(MFace *mface, MDisps *mdisp)
out = disps;
for (S = 0; S < nvert; S++) {
- for (y = 0; y < newside; ++y) {
- for (x = 0; x < newside; ++x, ++out) {
+ for (y = 0; y < newside; y++) {
+ for (x = 0; x < newside; x++, out++) {
old_mdisps_rotate(S, newside, oldside, x, y, &u, &v);
old_mdisps_bilinear(*out, mdisp->disps, oldside, u, v);
@@ -1749,8 +1755,8 @@ static void create_old_vert_face_map(ListBase **map,
node = *mem;
/* Find the users */
- for (i = 0; i < totface; ++i) {
- for (j = 0; j < (mface[i].v[3] ? 4 : 3); ++j, ++node) {
+ for (i = 0; i < totface; i++) {
+ for (j = 0; j < (mface[i].v[3] ? 4 : 3); j++, node++) {
node->index = i;
BLI_addtail(&(*map)[mface[i].v[j]], node);
}
@@ -1771,8 +1777,8 @@ static void create_old_vert_edge_map(ListBase **map,
node = *mem;
/* Find the users */
- for (i = 0; i < totedge; ++i) {
- for (j = 0; j < 2; ++j, ++node) {
+ for (i = 0; i < totedge; i++) {
+ for (j = 0; j < 2; j++, node++) {
node->index = i;
BLI_addtail(&(*map)[medge[i].v[j]], node);
}
@@ -1793,8 +1799,8 @@ static MultiresFace *find_old_face(
for (n1 = map[v1].first; n1; n1 = n1->next) {
int fnd[4] = {0, 0, 0, 0};
- for (i = 0; i < 4; ++i) {
- for (j = 0; j < 4; ++j) {
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
if (v[i] == faces[n1->index].v[j]) {
fnd[i] = 1;
}
@@ -2006,24 +2012,24 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
lvl1 = mr->levels.first;
/* Load base verts */
- for (i = 0; i < lvl1->totvert; ++i) {
+ for (i = 0; i < lvl1->totvert; i++) {
vvmap[totvert - lvl1->totvert + i] = src;
src++;
}
/* Original edges */
dst = totvert - lvl1->totvert - extedgelen * lvl1->totedge;
- for (i = 0; i < lvl1->totedge; ++i) {
+ for (i = 0; i < lvl1->totedge; i++) {
int ldst = dst + extedgelen * i;
int lsrc = src;
lvl = lvl1->next;
- for (j = 2; j <= mr->level_count; ++j) {
+ for (j = 2; j <= mr->level_count; j++) {
int base = multires_side_tot[totlvl - j + 1] - 2;
int skip = multires_side_tot[totlvl - j + 2] - 1;
int st = multires_side_tot[j - 1] - 1;
- for (x = 0; x < st; ++x) {
+ for (x = 0; x < st; x++) {
vvmap[ldst + base + x * skip] = lsrc + st * i + x;
}
@@ -2034,7 +2040,7 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
/* Center points */
dst = 0;
- for (i = 0; i < lvl1->totface; ++i) {
+ for (i = 0; i < lvl1->totface; i++) {
int sides = lvl1->faces[i].v[3] ? 4 : 3;
vvmap[dst] = src + lvl1->totedge + i;
@@ -2050,13 +2056,13 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
tottri = totquad = 0;
crossedgelen = multires_side_tot[totlvl - 1] - 2;
dst = 0;
- for (i = 0; i < lvl1->totface; ++i) {
+ for (i = 0; i < lvl1->totface; i++) {
int sides = lvl1->faces[i].v[3] ? 4 : 3;
lvl = lvl1->next->next;
dst++;
- for (j = 3; j <= mr->level_count; ++j) {
+ for (j = 3; j <= mr->level_count; j++) {
int base = multires_side_tot[totlvl - j + 1] - 2;
int skip = multires_side_tot[totlvl - j + 2] - 1;
int st = pow(2, j - 2);
@@ -2069,8 +2075,8 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
/* Skip earlier face edge crosses */
lsrc += st2 * (tottri * 3 + totquad * 4);
- for (s = 0; s < sides; ++s) {
- for (x = 0; x < st2; ++x) {
+ for (s = 0; s < sides; s++) {
+ for (x = 0; x < st2; x++) {
vvmap[dst + crossedgelen * (s + 1) - base - x * skip - 1] = lsrc;
lsrc++;
}
@@ -2082,10 +2088,10 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
dst += sides * (st_last - 1) * st_last;
if (sides == 4) {
- ++totquad;
+ totquad++;
}
else {
- ++tottri;
+ tottri++;
}
}
@@ -2095,7 +2101,7 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
fmem = MEM_calloc_arrayN((mr->level_count - 1), sizeof(IndexNode *), "multires fmem");
emem = MEM_calloc_arrayN((mr->level_count - 1), sizeof(IndexNode *), "multires emem");
lvl = lvl1;
- for (i = 0; i < (unsigned int)mr->level_count - 1; ++i) {
+ for (i = 0; i < (unsigned int)mr->level_count - 1; i++) {
create_old_vert_face_map(fmap + i, fmem + i, lvl->faces, lvl->totvert, lvl->totface);
create_old_vert_edge_map(emap + i, emem + i, lvl->edges, lvl->totvert, lvl->totedge);
lvl = lvl->next;
@@ -2104,11 +2110,11 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
/* Interior face verts */
/* lvl = lvl1->next->next; */ /* UNUSED */
dst = 0;
- for (j = 0; j < lvl1->totface; ++j) {
+ for (j = 0; j < lvl1->totface; j++) {
int sides = lvl1->faces[j].v[3] ? 4 : 3;
int ldst = dst + 1 + sides * (st_last - 1);
- for (s = 0; s < sides; ++s) {
+ for (s = 0; s < sides; s++) {
int st2 = multires_side_tot[totlvl - 1] - 2;
int st3 = multires_side_tot[totlvl - 2] - 2;
int st4 = st3 == 0 ? 1 : (st3 + 1) / 2;
@@ -2137,7 +2143,7 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
/*lvl = lvl->next;*/ /*UNUSED*/
- for (i = 0; i < (unsigned int)(mr->level_count - 1); ++i) {
+ for (i = 0; i < (unsigned int)(mr->level_count - 1); i++) {
MEM_freeN(fmap[i]);
MEM_freeN(fmem[i]);
MEM_freeN(emap[i]);
@@ -2151,7 +2157,7 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
}
/* Transfer verts */
- for (i = 0; i < totvert; ++i) {
+ for (i = 0; i < totvert; i++) {
copy_v3_v3(vdst[i].co, vsrc[vvmap[i]].co);
}
@@ -2183,8 +2189,8 @@ static void multires_load_old_vcols(Mesh *me)
return;
}
- for (i = 0; i < me->totface; ++i) {
- for (j = 0; j < 4; ++j) {
+ for (i = 0; i < me->totface; i++) {
+ for (j = 0; j < 4; j++) {
mcol[i * 4 + j].a = colface[i].col[j].a;
mcol[i * 4 + j].r = colface[i].col[j].r;
mcol[i * 4 + j].g = colface[i].col[j].g;
@@ -2208,7 +2214,7 @@ static void multires_load_old_face_flags(Mesh *me)
return;
}
- for (i = 0; i < me->totface; ++i) {
+ for (i = 0; i < me->totface; i++) {
me->mface[i].flag = faces[i].flag;
}
}
@@ -2234,11 +2240,11 @@ void multires_load_old(Object *ob, Mesh *me)
me->medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, me->totedge);
me->mface = CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface);
memcpy(me->mvert, me->mr->verts, sizeof(MVert) * me->totvert);
- for (i = 0; i < me->totedge; ++i) {
+ for (i = 0; i < me->totedge; i++) {
me->medge[i].v1 = lvl->edges[i].v[0];
me->medge[i].v2 = lvl->edges[i].v[1];
}
- for (i = 0; i < me->totface; ++i) {
+ for (i = 0; i < me->totface; i++) {
me->mface[i].v1 = lvl->faces[i].v[0];
me->mface[i].v2 = lvl->faces[i].v[1];
me->mface[i].v3 = lvl->faces[i].v[2];
@@ -2248,10 +2254,10 @@ void multires_load_old(Object *ob, Mesh *me)
/* Copy the first-level data to the mesh */
/* XXX We must do this before converting tessfaces to polys/lopps! */
- for (i = 0, l = me->mr->vdata.layers; i < me->mr->vdata.totlayer; ++i, ++l) {
+ for (i = 0, l = me->mr->vdata.layers; i < me->mr->vdata.totlayer; i++, l++) {
CustomData_add_layer(&me->vdata, l->type, CD_REFERENCE, l->data, me->totvert);
}
- for (i = 0, l = me->mr->fdata.layers; i < me->mr->fdata.totlayer; ++i, ++l) {
+ for (i = 0, l = me->mr->fdata.layers; i < me->mr->fdata.totlayer; i++, l++) {
CustomData_add_layer(&me->fdata, l->type, CD_REFERENCE, l->data, me->totface);
}
CustomData_reset(&me->mr->vdata);
@@ -2271,7 +2277,7 @@ void multires_load_old(Object *ob, Mesh *me)
mmd = (MultiresModifierData *)modifier_new(eModifierType_Multires);
BLI_insertlinkbefore(&ob->modifiers, md, mmd);
- for (i = 0; i < me->mr->level_count - 1; ++i) {
+ for (i = 0; i < me->mr->level_count - 1; i++) {
multiresModifier_subdivide(mmd, NULL, ob, 1, 0);
}
@@ -2337,9 +2343,9 @@ static void multires_apply_uniform_scale(Object *object, const float scale)
{
Mesh *mesh = (Mesh *)object->data;
MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS);
- for (int i = 0; i < mesh->totloop; ++i) {
+ for (int i = 0; i < mesh->totloop; i++) {
MDisps *grid = &mdisps[i];
- for (int j = 0; j < grid->totdisp; ++j) {
+ for (int j = 0; j < grid->totdisp; j++) {
mul_v3_fl(grid->disps[j], scale);
}
}
@@ -2348,7 +2354,7 @@ static void multires_apply_uniform_scale(Object *object, const float scale)
static void multires_apply_smat(struct Depsgraph *UNUSED(depsgraph),
Scene *scene,
Object *object,
- float smat[3][3])
+ const float smat[3][3])
{
const MultiresModifierData *mmd = get_multires_modifier(scene, object, true);
if (mmd == NULL || mmd->totlvl == 0) {
diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c
index 9947b96105d..4e4a8831518 100644
--- a/source/blender/blenkernel/intern/multires_reshape.c
+++ b/source/blender/blenkernel/intern/multires_reshape.c
@@ -650,7 +650,7 @@ static void multires_reshape_neighour_boundary_vertices(MultiresReshapeContext *
const int start_ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
const bool is_quad = (coarse_poly->totloop == 4);
if (corner_u == 1.0f && corner_v == 1.0f) {
- for (int current_corner = 0; current_corner < num_corners; ++current_corner) {
+ for (int current_corner = 0; current_corner < num_corners; current_corner++) {
if (current_corner == coarse_corner) {
continue;
}
@@ -795,7 +795,7 @@ static Subdiv *multires_create_subdiv_for_reshape(struct Depsgraph *depsgraph,
SubdivSettings subdiv_settings;
BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, deformed_mesh);
- if (!BKE_subdiv_eval_update_from_mesh(subdiv, deformed_mesh)) {
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, deformed_mesh, NULL)) {
BKE_subdiv_free(subdiv);
return NULL;
}
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 206c59c110a..0ef35bd3d06 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -947,6 +947,57 @@ void nodeChainIter(const bNodeTree *ntree,
}
}
+static void iter_backwards_ex(const bNodeTree *ntree,
+ const bNode *node_start,
+ bool (*callback)(bNode *, bNode *, void *),
+ void *userdata)
+{
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node_start->inputs) {
+ bNodeLink *link = sock->link;
+ if (link == NULL) {
+ continue;
+ }
+ if ((link->flag & NODE_LINK_VALID) == 0) {
+ /* Skip links marked as cyclic. */
+ continue;
+ }
+ if (link->fromnode->iter_flag) {
+ /* Only iter on nodes once. */
+ continue;
+ }
+ else {
+ link->fromnode->iter_flag = 1;
+ }
+
+ if (!callback(link->fromnode, link->tonode, userdata)) {
+ return;
+ }
+ iter_backwards_ex(ntree, link->fromnode, callback, userdata);
+ }
+}
+
+/**
+ * Iterate over a chain of nodes, starting with \a node_start, executing
+ * \a callback for each node (which can return false to end iterator).
+ *
+ * Faster than nodeChainIter. Iter only once per node.
+ *
+ * \note Needs updated socket links (ntreeUpdateTree).
+ * \note Recursive
+ */
+void nodeChainIterBackwards(const bNodeTree *ntree,
+ const bNode *node_start,
+ bool (*callback)(bNode *, bNode *, void *),
+ void *userdata)
+{
+ /* Reset flag. */
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ node->iter_flag = 0;
+ }
+
+ iter_backwards_ex(ntree, node_start, callback, userdata);
+}
+
/**
* Iterate over all parents of \a node, executing \a callback for each parent
* (which can return false to end iterator)
@@ -1406,6 +1457,7 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
}
else {
ntree = MEM_callocN(sizeof(bNodeTree), "new node tree");
+ ntree->id.flag |= LIB_PRIVATE_DATA;
*((short *)ntree->id.name) = ID_NT;
BLI_strncpy(ntree->id.name + 2, name, sizeof(ntree->id.name));
}
@@ -2172,6 +2224,7 @@ void ntreeSetOutput(bNodeTree *ntree)
* might be different for editor or for "real" use... */
}
+/* Returns the private NodeTree object of the datablock, if it has one. */
bNodeTree *ntreeFromID(const ID *id)
{
switch (GS(id->name)) {
@@ -2192,6 +2245,28 @@ bNodeTree *ntreeFromID(const ID *id)
}
}
+/* Finds and returns the datablock that privately owns the given tree, or NULL. */
+ID *BKE_node_tree_find_owner_ID(Main *bmain, struct bNodeTree *ntree)
+{
+ ListBase *lists[] = {&bmain->materials,
+ &bmain->lights,
+ &bmain->worlds,
+ &bmain->textures,
+ &bmain->scenes,
+ &bmain->linestyles,
+ NULL};
+
+ for (int i = 0; lists[i] != NULL; i++) {
+ LISTBASE_FOREACH (ID *, id, lists[i]) {
+ if (ntreeFromID(id) == ntree) {
+ return id;
+ }
+ }
+ }
+
+ return NULL;
+}
+
void ntreeMakeLocal(Main *bmain, bNodeTree *ntree, bool id_in_mainlist, const bool lib_local)
{
BKE_id_make_local_generic(bmain, &ntree->id, id_in_mainlist, lib_local);
@@ -3122,7 +3197,7 @@ void BKE_node_instance_hash_remove_untagged(bNodeInstanceHash *hash,
}
}
- for (i = 0; i < num_untagged; ++i) {
+ for (i = 0; i < num_untagged; i++) {
BKE_node_instance_hash_remove(hash, untagged[i], valfreefp);
}
@@ -3324,7 +3399,7 @@ void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
return;
}
- /* avoid reentrant updates, can be caused by RNA update callbacks */
+ /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
if (ntree->is_updating) {
return;
}
@@ -3385,7 +3460,7 @@ void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
void nodeUpdate(bNodeTree *ntree, bNode *node)
{
- /* avoid reentrant updates, can be caused by RNA update callbacks */
+ /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
if (ntree->is_updating) {
return;
}
@@ -3412,7 +3487,7 @@ bool nodeUpdateID(bNodeTree *ntree, ID *id)
return changed;
}
- /* avoid reentrant updates, can be caused by RNA update callbacks */
+ /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
if (ntree->is_updating) {
return changed;
}
@@ -3547,7 +3622,7 @@ static bool unique_socket_template_identifier_check(void *arg, const char *name)
bNodeSocketTemplate *ntemp;
} *data = arg;
- for (ntemp = data->list; ntemp->type >= 0; ++ntemp) {
+ for (ntemp = data->list; ntemp->type >= 0; ntemp++) {
if (ntemp != data->ntemp) {
if (STREQ(ntemp->identifier, name)) {
return true;
@@ -3590,22 +3665,22 @@ void node_type_socket_templates(struct bNodeType *ntype,
/* automatically generate unique identifiers */
if (inputs) {
/* clear identifier strings (uninitialized memory) */
- for (ntemp = inputs; ntemp->type >= 0; ++ntemp) {
+ for (ntemp = inputs; ntemp->type >= 0; ntemp++) {
ntemp->identifier[0] = '\0';
}
- for (ntemp = inputs; ntemp->type >= 0; ++ntemp) {
+ for (ntemp = inputs; ntemp->type >= 0; ntemp++) {
BLI_strncpy(ntemp->identifier, ntemp->name, sizeof(ntemp->identifier));
unique_socket_template_identifier(inputs, ntemp, ntemp->identifier, '_');
}
}
if (outputs) {
/* clear identifier strings (uninitialized memory) */
- for (ntemp = outputs; ntemp->type >= 0; ++ntemp) {
+ for (ntemp = outputs; ntemp->type >= 0; ntemp++) {
ntemp->identifier[0] = '\0';
}
- for (ntemp = outputs; ntemp->type >= 0; ++ntemp) {
+ for (ntemp = outputs; ntemp->type >= 0; ntemp++) {
BLI_strncpy(ntemp->identifier, ntemp->name, sizeof(ntemp->identifier));
unique_socket_template_identifier(outputs, ntemp, ntemp->identifier, '_');
}
@@ -3890,6 +3965,7 @@ static void registerShaderNodes(void)
register_node_type_sh_tex_coord();
register_node_type_sh_particle_info();
register_node_type_sh_bump();
+ register_node_type_sh_vertex_color();
register_node_type_sh_background();
register_node_type_sh_bsdf_anisotropic();
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index ae091f32fbf..f10930a2ba7 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -55,6 +55,7 @@
#include "DNA_object_types.h"
#include "DNA_lightprobe_types.h"
#include "DNA_rigidbody_types.h"
+#include "DNA_defaults.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
@@ -803,38 +804,16 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name)
}
}
-void BKE_object_init(Object *ob)
+void BKE_object_init(Object *ob, const short ob_type)
{
- /* BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(ob, id)); */ /* ob->type is already initialized... */
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(ob, id));
- copy_v4_fl(ob->color, 1.0f);
+ MEMCPY_STRUCT_AFTER(ob, DNA_struct_default_get(Object), id);
- ob->scale[0] = ob->scale[1] = ob->scale[2] = 1.0;
- ob->dscale[0] = ob->dscale[1] = ob->dscale[2] = 1.0;
+ ob->type = ob_type;
- /* objects should default to having Euler XYZ rotations,
- * but rotations default to quaternions
- */
- ob->rotmode = ROT_MODE_EUL;
-
- unit_axis_angle(ob->rotAxis, &ob->rotAngle);
- unit_axis_angle(ob->drotAxis, &ob->drotAngle);
-
- unit_qt(ob->quat);
- unit_qt(ob->dquat);
-
- /* rotation locks should be 4D for 4 component rotations by default... */
- ob->protectflag = OB_LOCK_ROT4D;
-
- unit_m4(ob->constinv);
- unit_m4(ob->parentinv);
- unit_m4(ob->obmat);
- ob->dt = OB_TEXTURE;
- ob->empty_drawtype = OB_PLAINAXES;
- ob->empty_drawsize = 1.0;
- ob->empty_image_depth = OB_EMPTY_IMAGE_DEPTH_DEFAULT;
- if (ob->type == OB_EMPTY) {
- copy_v2_fl(ob->ima_ofs, -0.5f);
+ if (ob->type != OB_EMPTY) {
+ zero_v2(ob->ima_ofs);
}
if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
@@ -846,18 +825,6 @@ void BKE_object_init(Object *ob)
ob->upflag = OB_POSZ;
}
- ob->instance_faces_scale = 1.0;
-
- ob->col_group = 0x01;
- ob->col_mask = 0xffff;
- ob->preview = NULL;
- ob->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER;
-
- /* NT fluid sim defaults */
- ob->fluidsimSettings = NULL;
-
- BLI_listbase_clear(&ob->pc_ids);
-
/* Animation Visualization defaults */
animviz_settings_init(&ob->avs);
}
@@ -877,9 +844,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
id_us_min(&ob->id);
/* default object vars */
- ob->type = type;
-
- BKE_object_init(ob);
+ BKE_object_init(ob, type);
return ob;
}
@@ -2799,6 +2764,12 @@ void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval)
ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
}
+/* -------------------------------------------------------------------- */
+/** \name Object Dimension Get/Set
+ *
+ * \warning Setting dimensions is prone to feedback loops in evaluation.
+ * \{ */
+
void BKE_object_dimensions_get(Object *ob, float vec[3])
{
BoundBox *bb = NULL;
@@ -2818,7 +2789,19 @@ void BKE_object_dimensions_get(Object *ob, float vec[3])
}
}
-void BKE_object_dimensions_set(Object *ob, const float value[3], int axis_mask)
+/**
+ * The original scale and object matrix can be passed in so any difference
+ * of the objects matrix and the final matrix can be accounted for,
+ * typically this caused by parenting, constraints or delta-scale.
+ *
+ * Re-using these values from the object causes a feedback loop
+ * when multiple values are modified at once in some situations. see: T69536.
+ */
+void BKE_object_dimensions_set_ex(Object *ob,
+ const float value[3],
+ int axis_mask,
+ const float ob_scale_orig[3],
+ const float ob_obmat_orig[4][4])
{
BoundBox *bb = NULL;
@@ -2832,7 +2815,16 @@ void BKE_object_dimensions_set(Object *ob, const float value[3], int axis_mask)
for (int i = 0; i < 3; i++) {
if (((1 << i) & axis_mask) == 0) {
+
+ if (ob_scale_orig != NULL) {
+ const float scale_delta = len_v3(ob_obmat_orig[i]) / ob_scale_orig[i];
+ if (isfinite(scale_delta)) {
+ len[i] *= scale_delta;
+ }
+ }
+
if (len[i] > 0.0f) {
+
ob->scale[i] = copysignf(value[i] / len[i], ob->scale[i]);
}
}
@@ -2840,6 +2832,11 @@ void BKE_object_dimensions_set(Object *ob, const float value[3], int axis_mask)
}
}
+void BKE_object_dimensions_set(Object *ob, const float value[3], int axis_mask)
+{
+ BKE_object_dimensions_set_ex(ob, value, axis_mask, NULL, NULL);
+}
+
void BKE_object_minmax(Object *ob, float min_r[3], float max_r[3], const bool use_hidden)
{
BoundBox bb;
@@ -2985,6 +2982,15 @@ bool BKE_object_empty_image_data_is_visible_in_view3d(const Object *ob, const Re
}
}
+ if (visibility_flag & OB_EMPTY_IMAGE_HIDE_NON_AXIS_ALIGNED) {
+ float proj[3];
+ project_plane_v3_v3v3(proj, ob->obmat[2], rv3d->viewinv[2]);
+ const float proj_length_sq = len_squared_v3(proj);
+ if (proj_length_sq > 1e-5f) {
+ return false;
+ }
+ }
+
return true;
}
@@ -3263,8 +3269,7 @@ void BKE_object_sculpt_data_create(Object *ob)
ob->sculpt->mode_type = ob->mode;
}
-int BKE_object_obdata_texspace_get(
- Object *ob, short **r_texflag, float **r_loc, float **r_size, float **r_rot)
+int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc, float **r_size)
{
if (ob->data == NULL) {
@@ -3273,14 +3278,12 @@ int BKE_object_obdata_texspace_get(
switch (GS(((ID *)ob->data)->name)) {
case ID_ME: {
- BKE_mesh_texspace_get_reference((Mesh *)ob->data, r_texflag, r_loc, r_rot, r_size);
+ BKE_mesh_texspace_get_reference((Mesh *)ob->data, r_texflag, r_loc, r_size);
break;
}
case ID_CU: {
Curve *cu = ob->data;
- if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_curve_texspace_calc(cu);
- }
+ BKE_curve_texspace_ensure(cu);
if (r_texflag) {
*r_texflag = &cu->texflag;
}
@@ -3290,9 +3293,6 @@ int BKE_object_obdata_texspace_get(
if (r_size) {
*r_size = cu->size;
}
- if (r_rot) {
- *r_rot = cu->rot;
- }
break;
}
case ID_MB: {
@@ -3306,9 +3306,6 @@ int BKE_object_obdata_texspace_get(
if (r_size) {
*r_size = mb->size;
}
- if (r_rot) {
- *r_rot = mb->rot;
- }
break;
}
default:
@@ -3871,7 +3868,7 @@ int BKE_object_scenes_users_get(Main *bmain, Object *ob)
{
int num_scenes = 0;
for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
- if (BKE_collection_has_object_recursive(BKE_collection_master(scene), ob)) {
+ if (BKE_collection_has_object_recursive(scene->master_collection, ob)) {
num_scenes++;
}
}
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 7983fe54be5..6b6c68b197e 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -93,8 +93,11 @@ typedef struct DupliGenerator {
static const DupliGenerator *get_dupli_generator(const DupliContext *ctx);
/* create initial context for root object */
-static void init_context(
- DupliContext *r_ctx, Depsgraph *depsgraph, Scene *scene, Object *ob, float space_mat[4][4])
+static void init_context(DupliContext *r_ctx,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ const float space_mat[4][4])
{
r_ctx->depsgraph = depsgraph;
r_ctx->scene = scene;
@@ -118,7 +121,7 @@ static void init_context(
/* create sub-context for recursive duplis */
static void copy_dupli_context(
- DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index)
+ DupliContext *r_ctx, const DupliContext *ctx, Object *ob, const float mat[4][4], int index)
{
*r_ctx = *ctx;
@@ -204,7 +207,7 @@ static DupliObject *make_dupli(const DupliContext *ctx, Object *ob, float mat[4]
*/
static void make_recursive_duplis(const DupliContext *ctx,
Object *ob,
- float space_mat[4][4],
+ const float space_mat[4][4],
int index)
{
/* simple preventing of too deep nested collections with MAX_DUPLI_RECUR */
@@ -398,12 +401,8 @@ static void make_child_duplis_verts(const DupliContext *ctx, void *userdata, Obj
mul_m4_m4m4(vdd->child_imat, child->imat, ctx->object->obmat);
const MVert *mvert = me_eval->mvert;
- const int *origindex = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
-
- for (int i = 0, j = 0; i < me_eval->totvert; i++) {
- if (origindex == NULL || origindex[i] != ORIGINDEX_NONE) {
- vertex_dupli(vdd, j++, mvert[i].co, mvert[i].no);
- }
+ for (int i = 0; i < me_eval->totvert; i++) {
+ vertex_dupli(vdd, i, mvert[i].co, mvert[i].no);
}
}
@@ -822,8 +821,10 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
/* gather list of objects or single object */
int totcollection = 0;
+ const bool use_whole_collection = part->draw & PART_DRAW_WHOLE_GR;
+ const bool use_collection_count = part->draw & PART_DRAW_COUNT_GR && !use_whole_collection;
if (part->ren_as == PART_DRAW_GR) {
- if (part->draw & PART_DRAW_COUNT_GR) {
+ if (use_collection_count) {
psys_find_group_weights(part);
for (dw = part->instance_weights.first; dw; dw = dw->next) {
@@ -848,7 +849,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
oblist = MEM_callocN((size_t)totcollection * sizeof(Object *), "dupcollection object list");
- if (part->draw & PART_DRAW_COUNT_GR) {
+ if (use_collection_count) {
a = 0;
for (dw = part->instance_weights.first; dw; dw = dw->next) {
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (
@@ -916,7 +917,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
}
/* for collections, pick the object based on settings */
- if (part->draw & PART_DRAW_RAND_GR) {
+ if (part->draw & PART_DRAW_RAND_GR && !use_whole_collection) {
b = BLI_rng_get_int(rng) % totcollection;
}
else {
diff --git a/source/blender/blenkernel/intern/object_facemap.c b/source/blender/blenkernel/intern/object_facemap.c
index b3ebe9b5ffa..be96927ed63 100644
--- a/source/blender/blenkernel/intern/object_facemap.c
+++ b/source/blender/blenkernel/intern/object_facemap.c
@@ -261,3 +261,41 @@ bFaceMap *BKE_object_facemap_find_name(Object *ob, const char *name)
{
return BLI_findstring(&ob->fmaps, name, offsetof(bFaceMap, name));
}
+
+int *BKE_object_facemap_index_map_create(Object *ob_src, Object *ob_dst, int *r_map_len)
+{
+ /* Build src to merged mapping of facemap indices. */
+ if (BLI_listbase_is_empty(&ob_src->fmaps) || BLI_listbase_is_empty(&ob_dst->fmaps)) {
+ *r_map_len = 0;
+ return NULL;
+ }
+
+ *r_map_len = BLI_listbase_count(&ob_src->fmaps);
+ int *fmap_index_map = MEM_malloc_arrayN(
+ *r_map_len, sizeof(*fmap_index_map), "defgroup index map create");
+ bool is_fmap_remap_needed = false;
+
+ int i = 0;
+ for (bFaceMap *fmap_src = ob_src->fmaps.first; fmap_src; fmap_src = fmap_src->next, i++) {
+ fmap_index_map[i] = BKE_object_facemap_name_index(ob_dst, fmap_src->name);
+ is_fmap_remap_needed = is_fmap_remap_needed || (fmap_index_map[i] != i);
+ }
+
+ if (!is_fmap_remap_needed) {
+ MEM_freeN(fmap_index_map);
+ fmap_index_map = NULL;
+ *r_map_len = 0;
+ }
+
+ return fmap_index_map;
+}
+
+void BKE_object_facemap_index_map_apply(int *fmap, int fmap_len, const int *map, int map_len)
+{
+ if (map == NULL || map_len == 0) {
+ return;
+ }
+ for (int i = 0; i < fmap_len; i++, fmap++) {
+ *fmap = (*fmap < map_len && *fmap != -1) ? map[*fmap] : -1;
+ }
+}
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 3a330ea0d5a..01f3f2e309b 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -453,6 +453,7 @@ void BKE_object_eval_eval_base_flags(Depsgraph *depsgraph,
object->base_flag &= ~(BASE_SELECTED | BASE_SELECTABLE);
}
object->base_local_view_bits = base->local_view_bits;
+ object->runtime.local_collections_bits = base->local_collections_bits;
if (object->mode == OB_MODE_PARTICLE_EDIT) {
for (ParticleSystem *psys = object->particlesystem.first; psys != NULL; psys = psys->next) {
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index fcceebc3913..9faa61f986d 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -521,7 +521,7 @@ static void ocean_compute_htilda(void *__restrict userdata,
/* Note the <= _N/2 here, see the FFTW documentation
* about the mechanics of the complex->real fft storage. */
- for (j = 0; j <= o->_N / 2; ++j) {
+ for (j = 0; j <= o->_N / 2; j++) {
fftw_complex exp_param1;
fftw_complex exp_param2;
fftw_complex conj_param;
@@ -560,8 +560,8 @@ static void ocean_compute_displacement_x(TaskPool *__restrict pool,
const float chop_amount = osd->chop_amount;
int i, j;
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j <= o->_N / 2; j++) {
fftw_complex mul_param;
fftw_complex minus_i;
@@ -591,8 +591,8 @@ static void ocean_compute_displacement_z(TaskPool *__restrict pool,
const float chop_amount = osd->chop_amount;
int i, j;
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j <= o->_N / 2; j++) {
fftw_complex mul_param;
fftw_complex minus_i;
@@ -621,8 +621,8 @@ static void ocean_compute_jacobian_jxx(TaskPool *__restrict pool,
const float chop_amount = osd->chop_amount;
int i, j;
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j <= o->_N / 2; j++) {
fftw_complex mul_param;
/* init_complex(mul_param, -scale, 0); */
@@ -640,8 +640,8 @@ static void ocean_compute_jacobian_jxx(TaskPool *__restrict pool,
}
fftw_execute(o->_Jxx_plan);
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j < o->_N; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j < o->_N; j++) {
o->_Jxx[i * o->_N + j] += 1.0;
}
}
@@ -656,8 +656,8 @@ static void ocean_compute_jacobian_jzz(TaskPool *__restrict pool,
const float chop_amount = osd->chop_amount;
int i, j;
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j <= o->_N / 2; j++) {
fftw_complex mul_param;
/* init_complex(mul_param, -scale, 0); */
@@ -675,8 +675,8 @@ static void ocean_compute_jacobian_jzz(TaskPool *__restrict pool,
}
fftw_execute(o->_Jzz_plan);
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j < o->_N; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j < o->_N; j++) {
o->_Jzz[i * o->_N + j] += 1.0;
}
}
@@ -691,8 +691,8 @@ static void ocean_compute_jacobian_jxz(TaskPool *__restrict pool,
const float chop_amount = osd->chop_amount;
int i, j;
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j <= o->_N / 2; j++) {
fftw_complex mul_param;
/* init_complex(mul_param, -scale, 0); */
@@ -719,8 +719,8 @@ static void ocean_compute_normal_x(TaskPool *__restrict pool,
const Ocean *o = osd->o;
int i, j;
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j <= o->_N / 2; j++) {
fftw_complex mul_param;
init_complex(mul_param, 0.0, -1.0);
@@ -740,8 +740,8 @@ static void ocean_compute_normal_z(TaskPool *__restrict pool,
const Ocean *o = osd->o;
int i, j;
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j <= o->_N / 2; j++) {
fftw_complex mul_param;
init_complex(mul_param, 0.0, -1.0);
@@ -829,8 +829,8 @@ static void set_height_normalize_factor(struct Ocean *oc)
BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ);
- for (i = 0; i < oc->_M; ++i) {
- for (j = 0; j < oc->_N; ++j) {
+ for (i = 0; i < oc->_M; i++) {
+ for (j = 0; j < oc->_N; j++) {
if (max_h < fabs(oc->_disp_y[i * oc->_N + j])) {
max_h = fabs(oc->_disp_y[i * oc->_N + j]);
}
@@ -959,28 +959,28 @@ void BKE_ocean_init(struct Ocean *o,
}
/* the +ve components and DC */
- for (i = 0; i <= o->_M / 2; ++i) {
+ for (i = 0; i <= o->_M / 2; i++) {
o->_kx[i] = 2.0f * (float)M_PI * i / o->_Lx;
}
/* the -ve components */
- for (i = o->_M - 1, ii = 0; i > o->_M / 2; --i, ++ii) {
+ for (i = o->_M - 1, ii = 0; i > o->_M / 2; i--, ii++) {
o->_kx[i] = -2.0f * (float)M_PI * ii / o->_Lx;
}
/* the +ve components and DC */
- for (i = 0; i <= o->_N / 2; ++i) {
+ for (i = 0; i <= o->_N / 2; i++) {
o->_kz[i] = 2.0f * (float)M_PI * i / o->_Lz;
}
/* the -ve components */
- for (i = o->_N - 1, ii = 0; i > o->_N / 2; --i, ++ii) {
+ for (i = o->_N - 1, ii = 0; i > o->_N / 2; i--, ii++) {
o->_kz[i] = -2.0f * (float)M_PI * ii / o->_Lz;
}
/* pre-calculate the k matrix */
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j <= o->_N / 2; j++) {
o->_k[i * (1 + o->_N / 2) + j] = sqrt(o->_kx[i] * o->_kx[i] + o->_kz[j] * o->_kz[j]);
}
}
@@ -988,8 +988,8 @@ void BKE_ocean_init(struct Ocean *o,
/*srand(seed);*/
rng = BLI_rng_new(seed);
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j < o->_N; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j < o->_N; j++) {
float r1 = gaussRand(rng);
float r2 = gaussRand(rng);
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 8e647757b40..cc3b10b1207 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -141,7 +141,9 @@ int BKE_packedfile_count_all(Main *bmain)
void BKE_packedfile_free(PackedFile *pf)
{
if (pf) {
- MEM_freeN(pf->data);
+ BLI_assert(pf->data != NULL);
+
+ MEM_SAFE_FREE(pf->data);
MEM_freeN(pf);
}
else {
@@ -151,6 +153,9 @@ void BKE_packedfile_free(PackedFile *pf)
PackedFile *BKE_packedfile_duplicate(const PackedFile *pf_src)
{
+ BLI_assert(pf_src != NULL);
+ BLI_assert(pf_src->data != NULL);
+
PackedFile *pf_dst;
pf_dst = MEM_dupallocN(pf_src);
@@ -161,6 +166,8 @@ PackedFile *BKE_packedfile_duplicate(const PackedFile *pf_src)
PackedFile *BKE_packedfile_new_from_memory(void *mem, int memlen)
{
+ BLI_assert(mem != NULL);
+
PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
pf->data = mem;
pf->size = memlen;
@@ -178,7 +185,7 @@ PackedFile *BKE_packedfile_new(ReportList *reports, const char *filename, const
/* render result has no filename and can be ignored
* any other files with no name can be ignored too */
if (filename[0] == '\0') {
- return NULL;
+ return pf;
}
// XXX waitcursor(1);
@@ -260,7 +267,11 @@ void BKE_packedfile_pack_all(Main *bmain, ReportList *reports, bool verbose)
}
if (tot > 0) {
- BKE_reportf(reports, RPT_INFO, "Packed %d files", tot);
+ BKE_reportf(reports,
+ RPT_INFO,
+ tot == 1 ? "Packed %d file" :
+ "Packed %d files",
+ tot);
}
else if (verbose) {
BKE_report(reports, RPT_INFO, "No new files have been packed");
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index a46bb36c883..983127372ca 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -992,10 +992,24 @@ static void sculptsession_free_pbvh(Object *object)
{
SculptSession *ss = object->sculpt;
- if (ss && ss->pbvh) {
+ if (!ss) {
+ return;
+ }
+
+ if (ss->pbvh) {
BKE_pbvh_free(ss->pbvh);
ss->pbvh = NULL;
}
+
+ if (ss->pmap) {
+ MEM_freeN(ss->pmap);
+ ss->pmap = NULL;
+ }
+
+ if (ss->pmap_mem) {
+ MEM_freeN(ss->pmap_mem);
+ ss->pmap_mem = NULL;
+ }
}
void BKE_sculptsession_bm_to_me_for_render(Object *object)
@@ -1060,6 +1074,10 @@ void BKE_sculptsession_free(Object *ob)
MEM_freeN(ss->deform_imats);
}
+ if (ss->preview_vert_index_list) {
+ MEM_freeN(ss->preview_vert_index_list);
+ }
+
BKE_sculptsession_free_vwpaint_data(ob->sculpt);
MEM_freeN(ss);
@@ -1086,6 +1104,12 @@ MultiresModifierData *BKE_sculpt_multires_active(Scene *scene, Object *ob)
return NULL;
}
+ /* Weight paint operates on original vertices, and needs to treat multires as regular modifier
+ * to make it so that PBVH vertices are at the multires surface. */
+ if ((ob->mode & OB_MODE_SCULPT) == 0) {
+ return NULL;
+ }
+
for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); md; md = md->next) {
if (md->type == eModifierType_Multires) {
MultiresModifierData *mmd = (MultiresModifierData *)md;
@@ -1131,7 +1155,10 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
continue;
}
- if (ELEM(md->type, eModifierType_ShapeKey, eModifierType_Multires)) {
+ if (md->type == eModifierType_Multires && (ob->mode & OB_MODE_SCULPT)) {
+ continue;
+ }
+ if (md->type == eModifierType_ShapeKey) {
continue;
}
@@ -1181,8 +1208,9 @@ static void sculpt_update_object(
ss->kb = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL;
- /* VWPaint require mesh info for loop lookup, so require sculpt mode here */
- if (mmd && ob->mode & OB_MODE_SCULPT) {
+ /* NOTE: Weight pPaint require mesh info for loop lookup, but it never uses multires code path,
+ * so no extra checks is needed here. */
+ if (mmd) {
ss->multires = mmd;
ss->totvert = me_eval->totvert;
ss->totpoly = me_eval->totpoly;
@@ -1206,9 +1234,7 @@ static void sculpt_update_object(
BLI_assert(pbvh == ss->pbvh);
UNUSED_VARS_NDEBUG(pbvh);
- MEM_SAFE_FREE(ss->pmap);
- MEM_SAFE_FREE(ss->pmap_mem);
- if (need_pmap && ob->type == OB_MESH) {
+ if (need_pmap && ob->type == OB_MESH && !ss->pmap) {
BKE_mesh_vert_poly_map_create(
&ss->pmap, &ss->pmap_mem, me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop);
}
@@ -1227,7 +1253,7 @@ static void sculpt_update_object(
BKE_crazyspace_build_sculpt(depsgraph, scene, ob, &ss->deform_imats, &ss->deform_cos);
BKE_pbvh_vert_coords_apply(ss->pbvh, ss->deform_cos, me->totvert);
- for (a = 0; a < me->totvert; ++a) {
+ for (a = 0; a < me->totvert; a++) {
invert_m3(ss->deform_imats[a]);
}
}
@@ -1268,7 +1294,7 @@ void BKE_sculpt_update_object_before_eval(Object *ob)
SculptSession *ss = ob->sculpt;
if (ss && ss->building_vp_handle == false) {
- if (!ss->cache) {
+ if (!ss->cache && !ss->filter_cache) {
/* We free pbvh on changes, except in the middle of drawing a stroke
* since it can't deal with changing PVBH node organization, we hope
* topology does not change in the meantime .. weak. */
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index ffeba0148a2..74fbfc318a8 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -88,7 +88,7 @@ float PSYS_FRAND_BASE[PSYS_FRAND_COUNT];
void psys_init_rng(void)
{
RNG *rng = BLI_rng_new_srandom(5831); /* arbitrary */
- for (int i = 0; i < PSYS_FRAND_COUNT; ++i) {
+ for (int i = 0; i < PSYS_FRAND_COUNT; i++) {
PSYS_FRAND_BASE[i] = BLI_rng_get_float(rng);
PSYS_FRAND_SEED_OFFSET[i] = (unsigned int)BLI_rng_get_int(rng);
PSYS_FRAND_SEED_MULTIPLIER[i] = (unsigned int)BLI_rng_get_int(rng);
@@ -2691,7 +2691,7 @@ static void psys_thread_create_path(ParticleTask *task,
pa = &psys->particles[cpa->parent];
par = pcache[cpa->parent];
- /* If particle is unexisting, try to pick a viable parent from particles
+ /* If particle is non-existing, try to pick a viable parent from particles
* used for interpolation. */
for (k = 0; k < 4 && pa && (pa->flag & PARS_UNEXIST); k++) {
if (cpa->pa[k] >= 0) {
@@ -2747,7 +2747,7 @@ static void exec_child_path_cache(TaskPool *__restrict UNUSED(pool),
int i;
cpa = psys->child + task->begin;
- for (i = task->begin; i < task->end; ++i, ++cpa) {
+ for (i = task->begin; i < task->end; i++, cpa++) {
BLI_assert(i < psys->totchildcache);
psys_thread_create_path(task, cpa, cache[i], i);
}
@@ -2794,7 +2794,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim,
/* cache parent paths */
ctx.parent_pass = 1;
psys_tasks_create(&ctx, 0, totparent, &tasks_parent, &numtasks_parent);
- for (i = 0; i < numtasks_parent; ++i) {
+ for (i = 0; i < numtasks_parent; i++) {
ParticleTask *task = &tasks_parent[i];
psys_task_init_path(task, sim);
@@ -2805,7 +2805,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim,
/* cache child paths */
ctx.parent_pass = 0;
psys_tasks_create(&ctx, totparent, totchild, &tasks_child, &numtasks_child);
- for (i = 0; i < numtasks_child; ++i) {
+ for (i = 0; i < numtasks_child; i++) {
ParticleTask *task = &tasks_child[i];
psys_task_init_path(task, sim);
@@ -3011,7 +3011,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
if (part->type == PART_HAIR) {
HairKey *hkey;
- for (k = 0, hkey = pa->hair; k < pa->totkey; ++k, ++hkey) {
+ for (k = 0, hkey = pa->hair; k < pa->totkey; k++, hkey++) {
mul_v3_m4v3(hkey->world_co, hairmat, hkey->co);
}
}
@@ -4068,9 +4068,7 @@ void psys_get_texture(
0,
texvec);
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
+ BKE_mesh_texspace_ensure(me);
sub_v3_v3(texvec, me->loc);
if (me->size[0] != 0.0f) {
texvec[0] /= me->size[0];
diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c
index 3b02e010e7f..dcd2a0b8fae 100644
--- a/source/blender/blenkernel/intern/particle_child.c
+++ b/source/blender/blenkernel/intern/particle_child.c
@@ -381,7 +381,7 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx,
}
/* we have to correct velocity because of kink & clump */
- for (k = 0, key = keys; k < totkeys; ++k, ++key) {
+ for (k = 0, key = keys; k < totkeys; k++, key++) {
if (k >= 2) {
sub_v3_v3v3((key - 1)->vel, key->co, (key - 2)->co);
mul_v3_fl((key - 1)->vel, 0.5);
@@ -657,7 +657,7 @@ float do_clump(ParticleKey *state,
}
static void do_rough(const float loc[3],
- float mat[4][4],
+ const float mat[4][4],
float t,
float fac,
float size,
@@ -701,7 +701,7 @@ static void do_rough_end(
}
static void do_rough_curve(const float loc[3],
- float mat[4][4],
+ const float mat[4][4],
float time,
float fac,
float size,
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 27d85b91ba4..1189785ce0f 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -787,17 +787,17 @@ static void exec_distribute_parent(TaskPool *__restrict UNUSED(pool),
pa = psys->particles + task->begin;
switch (psys->part->from) {
case PART_FROM_FACE:
- for (p = task->begin; p < task->end; ++p, ++pa) {
+ for (p = task->begin; p < task->end; p++, pa++) {
distribute_from_faces_exec(task, pa, p);
}
break;
case PART_FROM_VOLUME:
- for (p = task->begin; p < task->end; ++p, ++pa) {
+ for (p = task->begin; p < task->end; p++, pa++) {
distribute_from_volume_exec(task, pa, p);
}
break;
case PART_FROM_VERT:
- for (p = task->begin; p < task->end; ++p, ++pa) {
+ for (p = task->begin; p < task->end; p++, pa++) {
distribute_from_verts_exec(task, pa, p);
}
break;
@@ -815,11 +815,11 @@ static void exec_distribute_child(TaskPool *__restrict UNUSED(pool),
/* RNG skipping at the beginning */
cpa = psys->child;
- for (p = 0; p < task->begin; ++p, ++cpa) {
+ for (p = 0; p < task->begin; p++, cpa++) {
BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP);
}
- for (; p < task->end; ++p, ++cpa) {
+ for (; p < task->end; p++, cpa++) {
distribute_children_exec(task, cpa, p);
}
}
@@ -1341,7 +1341,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
totpart = (from == PART_FROM_CHILD ? sim->psys->totchild : sim->psys->totpart);
psys_tasks_create(&ctx, 0, totpart, &tasks, &numtasks);
- for (i = 0; i < numtasks; ++i) {
+ for (i = 0; i < numtasks; i++) {
ParticleTask *task = &tasks[i];
psys_task_init_distribute(task, sim);
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index e328ae8952e..43484a57f1c 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -501,7 +501,7 @@ void psys_tasks_free(ParticleTask *tasks, int numtasks)
int i;
/* threads */
- for (i = 0; i < numtasks; ++i) {
+ for (i = 0; i < numtasks; i++) {
if (tasks[i].rng) {
BLI_rng_free(tasks[i].rng);
}
@@ -1695,7 +1695,7 @@ typedef struct SPHRangeData {
static void sph_evaluate_func(BVHTree *tree,
ParticleSystem **psys,
- float co[3],
+ const float co[3],
SPHRangeData *pfr,
float interaction_radius,
BVHTree_RangeQuery callback)
@@ -2497,7 +2497,7 @@ static float collision_point_distance_with_normal(
return 0;
}
static void collision_point_on_surface(
- float p[3], ParticleCollisionElement *pce, float fac, ParticleCollision *col, float *co)
+ const float p[3], ParticleCollisionElement *pce, float fac, ParticleCollision *col, float *co)
{
collision_interpolate_element(pce, 0.f, fac, col);
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index cea68a0c525..7ed986204d5 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -36,7 +36,6 @@
#include "BKE_paint.h"
#include "GPU_buffers.h"
-#include "GPU_immediate.h"
#include "bmesh.h"
@@ -52,8 +51,6 @@
#define STACK_FIXED_DEPTH 100
-#define PBVH_THREADED_LIMIT 4
-
typedef struct PBVHStack {
PBVHNode *node;
bool revisiting;
@@ -80,7 +77,7 @@ void BB_reset(BB *bb)
/* Expand the bounding box to include a new coordinate */
void BB_expand(BB *bb, const float co[3])
{
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
bb->bmin[i] = min_ff(bb->bmin[i], co[i]);
bb->bmax[i] = max_ff(bb->bmax[i], co[i]);
}
@@ -89,7 +86,7 @@ void BB_expand(BB *bb, const float co[3])
/* Expand the bounding box to include another bounding box */
void BB_expand_with_bb(BB *bb, BB *bb2)
{
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
bb->bmin[i] = min_ff(bb->bmin[i], bb2->bmin[i]);
bb->bmax[i] = max_ff(bb->bmax[i], bb2->bmax[i]);
}
@@ -100,7 +97,7 @@ int BB_widest_axis(const BB *bb)
{
float dim[3];
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
dim[i] = bb->bmax[i] - bb->bmin[i];
}
@@ -124,7 +121,7 @@ int BB_widest_axis(const BB *bb)
void BBC_update_centroid(BBC *bbc)
{
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
bbc->bcentroid[i] = (bbc->bmin[i] + bbc->bmax[i]) * 0.5f;
}
}
@@ -294,9 +291,9 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
node->face_vert_indices = (const int(*)[3])face_vert_indices;
- for (int i = 0; i < totface; ++i) {
+ for (int i = 0; i < totface; i++) {
const MLoopTri *lt = &bvh->looptri[node->prim_indices[i]];
- for (int j = 0; j < 3; ++j) {
+ for (int j = 0; j < 3; j++) {
face_vert_indices[i][j] = map_insert_vert(
bvh, map, &node->face_verts, &node->uniq_verts, bvh->mloop[lt->tri[j]].v);
}
@@ -323,10 +320,10 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
vert_indices[ndx] = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter));
}
- for (int i = 0; i < totface; ++i) {
+ for (int i = 0; i < totface; i++) {
const int sides = 3;
- for (int j = 0; j < sides; ++j) {
+ for (int j = 0; j < sides; j++) {
if (face_vert_indices[i][j] < 0) {
face_vert_indices[i][j] = -face_vert_indices[i][j] + node->uniq_verts - 1;
}
@@ -343,7 +340,7 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
static void update_vb(PBVH *bvh, PBVHNode *node, BBC *prim_bbc, int offset, int count)
{
BB_reset(&node->vb);
- for (int i = offset + count - 1; i >= offset; --i) {
+ for (int i = offset + count - 1; i >= offset; i--) {
BB_expand_with_bb(&node->vb, (BB *)(&prim_bbc[bvh->prim_indices[i]]));
}
node->orig_vb = node->vb;
@@ -420,7 +417,7 @@ static bool leaf_needs_material_split(PBVH *bvh, int offset, int count)
const MLoopTri *first = &bvh->looptri[bvh->prim_indices[offset]];
const MPoly *mp = &bvh->mpoly[first->poly];
- for (int i = offset + count - 1; i > offset; --i) {
+ for (int i = offset + count - 1; i > offset; i--) {
int prim = bvh->prim_indices[i];
const MPoly *mp_other = &bvh->mpoly[bvh->looptri[prim].poly];
if (!face_materials_match(mp, mp_other)) {
@@ -431,7 +428,7 @@ static bool leaf_needs_material_split(PBVH *bvh, int offset, int count)
else {
const DMFlagMat *first = &bvh->grid_flag_mats[bvh->prim_indices[offset]];
- for (int i = offset + count - 1; i > offset; --i) {
+ for (int i = offset + count - 1; i > offset; i--) {
int prim = bvh->prim_indices[i];
if (!grid_materials_match(first, &bvh->grid_flag_mats[prim])) {
return true;
@@ -479,7 +476,7 @@ static void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, int offs
if (!cb) {
cb = &cb_backing;
BB_reset(cb);
- for (int i = offset + count - 1; i >= offset; --i) {
+ for (int i = offset + count - 1; i >= offset; i--) {
BB_expand(cb, prim_bbc[bvh->prim_indices[i]].bcentroid);
}
}
@@ -515,7 +512,7 @@ static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim)
MEM_freeN(bvh->prim_indices);
}
bvh->prim_indices = MEM_mallocN(sizeof(int) * totprim, "bvh prim indices");
- for (int i = 0; i < totprim; ++i) {
+ for (int i = 0; i < totprim; i++) {
bvh->prim_indices[i] = i;
}
bvh->totnode = 0;
@@ -564,14 +561,14 @@ void BKE_pbvh_build_mesh(PBVH *bvh,
/* For each face, store the AABB and the AABB centroid */
prim_bbc = MEM_mallocN(sizeof(BBC) * looptri_num, "prim_bbc");
- for (int i = 0; i < looptri_num; ++i) {
+ for (int i = 0; i < looptri_num; i++) {
const MLoopTri *lt = &looptri[i];
const int sides = 3;
BBC *bbc = prim_bbc + i;
BB_reset((BB *)bbc);
- for (int j = 0; j < sides; ++j) {
+ for (int j = 0; j < sides; j++) {
BB_expand((BB *)bbc, verts[bvh->mloop[lt->tri[j]].v].co);
}
@@ -614,13 +611,13 @@ void BKE_pbvh_build_grids(PBVH *bvh,
/* For each grid, store the AABB and the AABB centroid */
BBC *prim_bbc = MEM_mallocN(sizeof(BBC) * totgrid, "prim_bbc");
- for (int i = 0; i < totgrid; ++i) {
+ for (int i = 0; i < totgrid; i++) {
CCGElem *grid = grids[i];
BBC *bbc = prim_bbc + i;
BB_reset((BB *)bbc);
- for (int j = 0; j < gridsize * gridsize; ++j) {
+ for (int j = 0; j < gridsize * gridsize; j++) {
BB_expand((BB *)bbc, CCG_elem_offset_co(key, grid, j));
}
@@ -645,7 +642,7 @@ PBVH *BKE_pbvh_new(void)
void BKE_pbvh_free(PBVH *bvh)
{
- for (int i = 0; i < bvh->totnode; ++i) {
+ for (int i = 0; i < bvh->totnode; i++) {
PBVHNode *node = &bvh->nodes[i];
if (node->flag & PBVH_Leaf) {
@@ -697,7 +694,7 @@ void BKE_pbvh_free(PBVH *bvh)
void BKE_pbvh_free_layer_disp(PBVH *bvh)
{
- for (int i = 0; i < bvh->totnode; ++i) {
+ for (int i = 0; i < bvh->totnode; i++) {
BKE_pbvh_node_layer_disp_free(&bvh->nodes[i]);
}
}
@@ -991,6 +988,7 @@ typedef struct PBVHUpdateData {
float (*vnors)[3];
int flag;
+ bool show_vcol;
} PBVHUpdateData;
static void pbvh_update_normals_accum_task_cb(void *__restrict userdata,
@@ -1010,7 +1008,7 @@ static void pbvh_update_normals_accum_task_cb(void *__restrict userdata,
const int *faces = node->prim_indices;
const int totface = node->totprim;
- for (int i = 0; i < totface; ++i) {
+ for (int i = 0; i < totface; i++) {
const MLoopTri *lt = &bvh->looptri[faces[i]];
const unsigned int vtri[3] = {
bvh->mloop[lt->tri[0]].v,
@@ -1056,15 +1054,16 @@ static void pbvh_update_normals_store_task_cb(void *__restrict userdata,
const int *verts = node->vert_indices;
const int totvert = node->uniq_verts;
- for (int i = 0; i < totvert; ++i) {
+ for (int i = 0; i < totvert; i++) {
const int v = verts[i];
MVert *mvert = &bvh->verts[v];
- /* mvert is shared between nodes, hence between threads. */
- if (atomic_fetch_and_and_char(&mvert->flag, (char)~ME_VERT_PBVH_UPDATE) &
- ME_VERT_PBVH_UPDATE) {
+ /* No atomics necessary because we are iterating over uniq_verts only,
+ * so we know only this thread will handle this vertex. */
+ if (mvert->flag & ME_VERT_PBVH_UPDATE) {
normalize_v3(vnors[v]);
normal_float_to_short_v3(mvert->no, vnors[v]);
+ mvert->flag &= ~ME_VERT_PBVH_UPDATE;
}
}
@@ -1095,8 +1094,7 @@ static void pbvh_faces_update_normals(PBVH *bvh, PBVHNode **nodes, int totnode)
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (totnode > PBVH_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings);
@@ -1105,6 +1103,56 @@ static void pbvh_faces_update_normals(PBVH *bvh, PBVHNode **nodes, int totnode)
MEM_freeN(vnors);
}
+static void pbvh_update_mask_redraw_task_cb(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+
+ PBVHUpdateData *data = userdata;
+ PBVH *bvh = data->bvh;
+ PBVHNode *node = data->nodes[n];
+ if (node->flag & PBVH_UpdateMask) {
+
+ bool has_unmasked = false;
+ bool has_masked = true;
+ if (node->flag & PBVH_Leaf) {
+ PBVHVertexIter vd;
+
+ BKE_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ if (vd.mask && *vd.mask < 1.0f) {
+ has_unmasked = true;
+ }
+ if (vd.mask && *vd.mask > 0.0f) {
+ has_masked = false;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+ else {
+ has_unmasked = true;
+ has_masked = true;
+ }
+ BKE_pbvh_node_fully_masked_set(node, !has_unmasked);
+ BKE_pbvh_node_fully_unmasked_set(node, has_masked);
+
+ node->flag &= ~PBVH_UpdateMask;
+ }
+}
+
+static void pbvh_update_mask_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag)
+{
+ PBVHUpdateData data = {
+ .bvh = bvh,
+ .nodes = nodes,
+ .flag = flag,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_mask_redraw_task_cb, &settings);
+}
+
static void pbvh_update_BB_redraw_task_cb(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict UNUSED(tls))
@@ -1139,8 +1187,7 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag)
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (totnode > PBVH_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings);
}
@@ -1152,71 +1199,105 @@ static int pbvh_get_buffers_update_flags(PBVH *bvh, bool show_vcol)
return update_flags;
}
-static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode, bool show_vcol)
-{
- /* can't be done in parallel with OpenGL */
- for (int n = 0; n < totnode; n++) {
- PBVHNode *node = nodes[n];
-
- if (node->flag & PBVH_RebuildDrawBuffers) {
- GPU_pbvh_buffers_free(node->draw_buffers);
- switch (bvh->type) {
- case PBVH_GRIDS:
- node->draw_buffers = GPU_pbvh_grid_buffers_build(node->totprim, bvh->grid_hidden);
- break;
- case PBVH_FACES:
- node->draw_buffers = GPU_pbvh_mesh_buffers_build(node->face_vert_indices,
- bvh->mpoly,
- bvh->mloop,
- bvh->looptri,
- bvh->verts,
- node->prim_indices,
- node->totprim);
- break;
- case PBVH_BMESH:
- node->draw_buffers = GPU_pbvh_bmesh_buffers_build(bvh->flags &
- PBVH_DYNTOPO_SMOOTH_SHADING);
- break;
- }
-
- node->flag &= ~PBVH_RebuildDrawBuffers;
- }
+static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ /* Create and update draw buffers. The functions called here must not
+ * do any OpenGL calls. Flags are not cleared immediately, that happens
+ * after GPU_pbvh_buffer_flush() which does the final OpenGL calls. */
+ PBVHUpdateData *data = userdata;
+ PBVH *bvh = data->bvh;
+ PBVHNode *node = data->nodes[n];
- if (node->flag & PBVH_UpdateDrawBuffers) {
- const int update_flags = pbvh_get_buffers_update_flags(bvh, show_vcol);
- switch (bvh->type) {
- case PBVH_GRIDS:
- GPU_pbvh_grid_buffers_update(node->draw_buffers,
- bvh->grids,
- bvh->grid_flag_mats,
- node->prim_indices,
- node->totprim,
- &bvh->gridkey,
- update_flags);
- break;
- case PBVH_FACES:
- GPU_pbvh_mesh_buffers_update(node->draw_buffers,
- bvh->verts,
- node->vert_indices,
- node->uniq_verts + node->face_verts,
- CustomData_get_layer(bvh->vdata, CD_PAINT_MASK),
- CustomData_get_layer(bvh->ldata, CD_MLOOPCOL),
- node->face_vert_indices,
- update_flags);
- break;
- case PBVH_BMESH:
- GPU_pbvh_bmesh_buffers_update(node->draw_buffers,
- bvh->bm,
- node->bm_faces,
- node->bm_unique_verts,
- node->bm_other_verts,
- update_flags);
- break;
+ if (node->flag & PBVH_RebuildDrawBuffers) {
+ switch (bvh->type) {
+ case PBVH_GRIDS:
+ node->draw_buffers = GPU_pbvh_grid_buffers_build(node->totprim, bvh->grid_hidden);
+ break;
+ case PBVH_FACES:
+ node->draw_buffers = GPU_pbvh_mesh_buffers_build(node->face_vert_indices,
+ bvh->mpoly,
+ bvh->mloop,
+ bvh->looptri,
+ bvh->verts,
+ node->prim_indices,
+ node->totprim);
+ break;
+ case PBVH_BMESH:
+ node->draw_buffers = GPU_pbvh_bmesh_buffers_build(bvh->flags &
+ PBVH_DYNTOPO_SMOOTH_SHADING);
+ break;
+ }
+ }
+
+ if (node->flag & PBVH_UpdateDrawBuffers) {
+ const int update_flags = pbvh_get_buffers_update_flags(bvh, data->show_vcol);
+ switch (bvh->type) {
+ case PBVH_GRIDS:
+ GPU_pbvh_grid_buffers_update(node->draw_buffers,
+ bvh->grids,
+ bvh->grid_flag_mats,
+ node->prim_indices,
+ node->totprim,
+ &bvh->gridkey,
+ update_flags);
+ break;
+ case PBVH_FACES:
+ GPU_pbvh_mesh_buffers_update(node->draw_buffers,
+ bvh->verts,
+ node->vert_indices,
+ node->uniq_verts + node->face_verts,
+ CustomData_get_layer(bvh->vdata, CD_PAINT_MASK),
+ CustomData_get_layer(bvh->ldata, CD_MLOOPCOL),
+ node->face_vert_indices,
+ update_flags);
+ break;
+ case PBVH_BMESH:
+ GPU_pbvh_bmesh_buffers_update(node->draw_buffers,
+ bvh->bm,
+ node->bm_faces,
+ node->bm_unique_verts,
+ node->bm_other_verts,
+ update_flags);
+ break;
+ }
+ }
+}
+
+static void pbvh_update_draw_buffers(
+ PBVH *bvh, PBVHNode **nodes, int totnode, bool show_vcol, int update_flag)
+{
+ if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(bvh->type, PBVH_GRIDS, PBVH_BMESH)) {
+ /* Free buffers uses OpenGL, so not in parallel. */
+ for (int n = 0; n < totnode; n++) {
+ PBVHNode *node = nodes[n];
+ if (node->flag & PBVH_RebuildDrawBuffers) {
+ GPU_pbvh_buffers_free(node->draw_buffers);
+ node->draw_buffers = NULL;
+ }
+ else if ((node->flag & PBVH_UpdateDrawBuffers) && node->draw_buffers) {
+ if (bvh->type == PBVH_GRIDS) {
+ GPU_pbvh_grid_buffers_update_free(
+ node->draw_buffers, bvh->grid_flag_mats, node->prim_indices);
+ }
+ else if (bvh->type == PBVH_BMESH) {
+ GPU_pbvh_bmesh_buffers_update_free(node->draw_buffers);
+ }
}
-
- node->flag &= ~PBVH_UpdateDrawBuffers;
}
}
+
+ /* Parallel creation and update of draw buffers. */
+ PBVHUpdateData data = {
+ .bvh = bvh,
+ .nodes = nodes,
+ .show_vcol = show_vcol,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_draw_buffer_cb, &settings);
}
static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag)
@@ -1271,6 +1352,24 @@ void BKE_pbvh_update_bounds(PBVH *bvh, int flag)
pbvh_flush_bb(bvh, bvh->nodes, flag);
}
+ MEM_SAFE_FREE(nodes);
+}
+
+void BKE_pbvh_update_vertex_data(PBVH *bvh, int flag)
+{
+ if (!bvh->nodes) {
+ return;
+ }
+
+ PBVHNode **nodes;
+ int totnode;
+
+ BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(flag), &nodes, &totnode);
+
+ if (flag & (PBVH_UpdateMask)) {
+ pbvh_update_mask_redraw(bvh, nodes, totnode, flag);
+ }
+
if (nodes) {
MEM_freeN(nodes);
}
@@ -1308,7 +1407,7 @@ void BKE_pbvh_get_grid_updates(PBVH *bvh, bool clear, void ***r_gridfaces, int *
while ((node = pbvh_iter_next(&iter))) {
if (node->flag & PBVH_UpdateNormals) {
- for (unsigned i = 0; i < node->totprim; ++i) {
+ for (unsigned i = 0; i < node->totprim; i++) {
void *face = bvh->gridfaces[node->prim_indices[i]];
BLI_gset_add(face_set, face);
}
@@ -1379,19 +1478,24 @@ BLI_bitmap **BKE_pbvh_grid_hidden(const PBVH *bvh)
return bvh->grid_hidden;
}
-void BKE_pbvh_get_grid_key(const PBVH *bvh, CCGKey *key)
+const CCGKey *BKE_pbvh_get_grid_key(const PBVH *bvh)
{
BLI_assert(bvh->type == PBVH_GRIDS);
- *key = bvh->gridkey;
+ return &bvh->gridkey;
}
-struct CCGElem **BKE_pbvh_get_grids(const PBVH *bvh, int *num_grids)
+struct CCGElem **BKE_pbvh_get_grids(const PBVH *bvh)
{
BLI_assert(bvh->type == PBVH_GRIDS);
- *num_grids = bvh->totgrid;
return bvh->grids;
}
+int BKE_pbvh_get_grid_num_vertices(const PBVH *bvh)
+{
+ BLI_assert(bvh->type == PBVH_GRIDS);
+ return bvh->totgrid * bvh->gridkey.grid_area;
+}
+
BMesh *BKE_pbvh_get_bmesh(PBVH *bvh)
{
BLI_assert(bvh->type == PBVH_BMESH);
@@ -1406,6 +1510,11 @@ void BKE_pbvh_node_mark_update(PBVHNode *node)
PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
}
+void BKE_pbvh_node_mark_update_mask(PBVHNode *node)
+{
+ node->flag |= PBVH_UpdateMask | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
+}
+
void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node)
{
node->flag |= PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
@@ -1433,6 +1542,40 @@ void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden)
}
}
+void BKE_pbvh_node_fully_masked_set(PBVHNode *node, int fully_masked)
+{
+ BLI_assert(node->flag & PBVH_Leaf);
+
+ if (fully_masked) {
+ node->flag |= PBVH_FullyMasked;
+ }
+ else {
+ node->flag &= ~PBVH_FullyMasked;
+ }
+}
+
+bool BKE_pbvh_node_fully_masked_get(PBVHNode *node)
+{
+ return (node->flag & PBVH_Leaf) && (node->flag & PBVH_FullyMasked);
+}
+
+void BKE_pbvh_node_fully_unmasked_set(PBVHNode *node, int fully_masked)
+{
+ BLI_assert(node->flag & PBVH_Leaf);
+
+ if (fully_masked) {
+ node->flag |= PBVH_FullyUnmasked;
+ }
+ else {
+ node->flag &= ~PBVH_FullyUnmasked;
+ }
+}
+
+bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node)
+{
+ return (node->flag & PBVH_Leaf) && (node->flag & PBVH_FullyUnmasked);
+}
+
void BKE_pbvh_node_get_verts(PBVH *bvh,
PBVHNode *node,
const int **r_vert_indices,
@@ -1572,8 +1715,8 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
/**
* \note doing a full search on all vertices here seems expensive,
- * however this is important to avoid having to recalculate boundbox & sync the buffers to the GPU
- * (which is far more expensive!) See: T47232.
+ * however this is important to avoid having to recalculate boundbox & sync the buffers to the
+ * GPU (which is far more expensive!) See: T47232.
*/
bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node)
{
@@ -1581,7 +1724,7 @@ bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node)
const int *verts = node->vert_indices;
const int totvert = node->uniq_verts + node->face_verts;
- for (int i = 0; i < totvert; ++i) {
+ for (int i = 0; i < totvert; i++) {
const int v = verts[i];
const MVert *mvert = &bvh->verts[v];
@@ -1753,16 +1896,23 @@ static bool pbvh_faces_node_raycast(PBVH *bvh,
const PBVHNode *node,
float (*origco)[3],
const float ray_start[3],
+ const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
- float *depth)
+ float *depth,
+ int *r_active_vertex_index,
+ float *r_face_normal)
{
const MVert *vert = bvh->verts;
const MLoop *mloop = bvh->mloop;
const int *faces = node->prim_indices;
int i, totface = node->totprim;
bool hit = false;
+ float min_depth = FLT_MAX;
+ float location[3] = {0.0f};
+ float nearest_vertex_co[3];
+ copy_v3_fl(nearest_vertex_co, 0.0f);
- for (i = 0; i < totface; ++i) {
+ for (i = 0; i < totface; i++) {
const MLoopTri *lt = &bvh->looptri[faces[i]];
const int *face_verts = node->face_vert_indices[i];
@@ -1787,6 +1937,22 @@ static bool pbvh_faces_node_raycast(PBVH *bvh,
vert[mloop[lt->tri[1]].v].co,
vert[mloop[lt->tri[2]].v].co,
depth);
+
+ if (hit && *depth < min_depth) {
+ min_depth = *depth;
+ normal_tri_v3(r_face_normal,
+ vert[mloop[lt->tri[0]].v].co,
+ vert[mloop[lt->tri[1]].v].co,
+ vert[mloop[lt->tri[2]].v].co);
+ madd_v3_v3v3fl(location, ray_start, ray_normal, *depth);
+ for (int j = 0; j < 3; j++) {
+ if (len_squared_v3v3(location, vert[mloop[lt->tri[j]].v].co) <
+ len_squared_v3v3(location, nearest_vertex_co)) {
+ copy_v3_v3(nearest_vertex_co, vert[mloop[lt->tri[j]].v].co);
+ *r_active_vertex_index = mloop[lt->tri[j]].v;
+ }
+ }
+ }
}
}
@@ -1804,7 +1970,7 @@ static bool pbvh_grids_node_raycast(PBVH *bvh,
const int gridsize = bvh->gridkey.grid_size;
bool hit = false;
- for (int i = 0; i < totgrid; ++i) {
+ for (int i = 0; i < totgrid; i++) {
CCGElem *grid = bvh->grids[node->prim_indices[i]];
BLI_bitmap *gh;
@@ -1814,8 +1980,8 @@ static bool pbvh_grids_node_raycast(PBVH *bvh,
gh = bvh->grid_hidden[node->prim_indices[i]];
- for (int y = 0; y < gridsize - 1; ++y) {
- for (int x = 0; x < gridsize - 1; ++x) {
+ for (int y = 0; y < gridsize - 1; y++) {
+ for (int x = 0; x < gridsize - 1; x++) {
/* check if grid face is hidden */
if (gh) {
if (paint_is_grid_face_hidden(gh, gridsize, x, y)) {
@@ -1857,8 +2023,11 @@ bool BKE_pbvh_node_raycast(PBVH *bvh,
float (*origco)[3],
bool use_origco,
const float ray_start[3],
+ const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
- float *depth)
+ float *depth,
+ int *active_vertex_index,
+ float *face_normal)
{
bool hit = false;
@@ -1868,13 +2037,29 @@ bool BKE_pbvh_node_raycast(PBVH *bvh,
switch (bvh->type) {
case PBVH_FACES:
- hit |= pbvh_faces_node_raycast(bvh, node, origco, ray_start, isect_precalc, depth);
+ hit |= pbvh_faces_node_raycast(bvh,
+ node,
+ origco,
+ ray_start,
+ ray_normal,
+ isect_precalc,
+ depth,
+ active_vertex_index,
+ face_normal);
break;
case PBVH_GRIDS:
hit |= pbvh_grids_node_raycast(bvh, node, origco, ray_start, isect_precalc, depth);
break;
case PBVH_BMESH:
- hit = pbvh_bmesh_node_raycast(node, ray_start, isect_precalc, depth, use_origco);
+ BM_mesh_elem_index_ensure(bvh->bm, BM_VERT);
+ hit = pbvh_bmesh_node_raycast(node,
+ ray_start,
+ ray_normal,
+ isect_precalc,
+ depth,
+ use_origco,
+ active_vertex_index,
+ face_normal);
break;
}
@@ -1987,7 +2172,7 @@ static bool pbvh_faces_node_nearest_to_ray(PBVH *bvh,
int i, totface = node->totprim;
bool hit = false;
- for (i = 0; i < totface; ++i) {
+ for (i = 0; i < totface; i++) {
const MLoopTri *lt = &bvh->looptri[faces[i]];
const int *face_verts = node->face_vert_indices[i];
@@ -2032,7 +2217,7 @@ static bool pbvh_grids_node_nearest_to_ray(PBVH *bvh,
const int gridsize = bvh->gridkey.grid_size;
bool hit = false;
- for (int i = 0; i < totgrid; ++i) {
+ for (int i = 0; i < totgrid; i++) {
CCGElem *grid = bvh->grids[node->prim_indices[i]];
BLI_bitmap *gh;
@@ -2042,8 +2227,8 @@ static bool pbvh_grids_node_nearest_to_ray(PBVH *bvh,
gh = bvh->grid_hidden[node->prim_indices[i]];
- for (int y = 0; y < gridsize - 1; ++y) {
- for (int x = 0; x < gridsize - 1; ++x) {
+ for (int y = 0; y < gridsize - 1; y++) {
+ for (int x = 0; x < gridsize - 1; x++) {
/* check if grid face is hidden */
if (gh) {
if (paint_is_grid_face_hidden(gh, gridsize, x, y)) {
@@ -2126,16 +2311,18 @@ typedef enum {
* Returns true if the AABB is at least partially within the frustum
* (ok, not a real frustum), false otherwise.
*/
-static PlaneAABBIsect test_planes_aabb(const float bb_min[3],
- const float bb_max[3],
- const float (*planes)[4])
+static PlaneAABBIsect test_frustum_aabb(const float bb_min[3],
+ const float bb_max[3],
+ PBVHFrustumPlanes *frustum)
{
- float vmin[3], vmax[3];
PlaneAABBIsect ret = ISECT_INSIDE;
+ float(*planes)[4] = frustum->planes;
- for (int i = 0; i < 4; ++i) {
- for (int axis = 0; axis < 3; ++axis) {
- if (planes[i][axis] > 0) {
+ for (int i = 0; i < frustum->num_planes; i++) {
+ float vmin[3], vmax[3];
+
+ for (int axis = 0; axis < 3; axis++) {
+ if (planes[i][axis] < 0) {
vmin[axis] = bb_min[axis];
vmax[axis] = bb_max[axis];
}
@@ -2145,10 +2332,10 @@ static PlaneAABBIsect test_planes_aabb(const float bb_min[3],
}
}
- if (dot_v3v3(planes[i], vmin) + planes[i][3] > 0) {
+ if (dot_v3v3(planes[i], vmin) + planes[i][3] < 0) {
return ISECT_OUTSIDE;
}
- else if (dot_v3v3(planes[i], vmax) + planes[i][3] >= 0) {
+ else if (dot_v3v3(planes[i], vmax) + planes[i][3] <= 0) {
ret = ISECT_INTERSECT;
}
}
@@ -2156,38 +2343,24 @@ static PlaneAABBIsect test_planes_aabb(const float bb_min[3],
return ret;
}
-bool BKE_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data)
+bool BKE_pbvh_node_frustum_contain_AABB(PBVHNode *node, void *data)
{
const float *bb_min, *bb_max;
/* BKE_pbvh_node_get_BB */
bb_min = node->vb.bmin;
bb_max = node->vb.bmax;
- return test_planes_aabb(bb_min, bb_max, data) != ISECT_OUTSIDE;
+ return test_frustum_aabb(bb_min, bb_max, data) != ISECT_OUTSIDE;
}
-bool BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data)
+bool BKE_pbvh_node_frustum_exclude_AABB(PBVHNode *node, void *data)
{
const float *bb_min, *bb_max;
/* BKE_pbvh_node_get_BB */
bb_min = node->vb.bmin;
bb_max = node->vb.bmax;
- return test_planes_aabb(bb_min, bb_max, data) != ISECT_INSIDE;
-}
-
-typedef struct PBVHNodeDrawCallbackData {
- void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers);
- void *user_data;
-} PBVHNodeDrawCallbackData;
-
-static void pbvh_node_draw_cb(PBVHNode *node, void *data_v)
-{
- PBVHNodeDrawCallbackData *data = data_v;
-
- if (!(node->flag & PBVH_FullyHidden)) {
- data->draw_fn(data->user_data, node->draw_buffers);
- }
+ return test_frustum_aabb(bb_min, bb_max, data) != ISECT_INSIDE;
}
void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg)
@@ -2199,63 +2372,96 @@ void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg)
BKE_pbvh_search_gather(
bvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateNormals), &nodes, &totnode);
- if (bvh->type == PBVH_BMESH) {
- pbvh_bmesh_normals_update(nodes, totnode);
- }
- else if (bvh->type == PBVH_FACES) {
- pbvh_faces_update_normals(bvh, nodes, totnode);
- }
- else if (bvh->type == PBVH_GRIDS) {
- struct CCGFace **faces;
- int num_faces;
- BKE_pbvh_get_grid_updates(bvh, true, (void ***)&faces, &num_faces);
- if (num_faces > 0) {
- BKE_subdiv_ccg_update_normals(subdiv_ccg, faces, num_faces);
- MEM_freeN(faces);
+ if (totnode > 0) {
+ if (bvh->type == PBVH_BMESH) {
+ pbvh_bmesh_normals_update(nodes, totnode);
+ }
+ else if (bvh->type == PBVH_FACES) {
+ pbvh_faces_update_normals(bvh, nodes, totnode);
+ }
+ else if (bvh->type == PBVH_GRIDS) {
+ struct CCGFace **faces;
+ int num_faces;
+ BKE_pbvh_get_grid_updates(bvh, true, (void ***)&faces, &num_faces);
+ if (num_faces > 0) {
+ BKE_subdiv_ccg_update_normals(subdiv_ccg, faces, num_faces);
+ MEM_freeN(faces);
+ }
}
}
- if (nodes) {
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
+}
+
+/**
+ * PBVH drawing, updating draw buffers as needed and culling any nodes outside
+ * the specified frustum.
+ */
+typedef struct PBVHDrawSearchData {
+ PBVHFrustumPlanes *frustum;
+ int accum_update_flag;
+} PBVHDrawSearchData;
+
+static bool pbvh_draw_search_cb(PBVHNode *node, void *data_v)
+{
+ PBVHDrawSearchData *data = data_v;
+ if (data->frustum && !BKE_pbvh_node_frustum_contain_AABB(node, data->frustum)) {
+ return false;
}
+
+ data->accum_update_flag |= node->flag;
+ return true;
}
-void BKE_pbvh_update_draw_buffers(PBVH *bvh, bool show_vcol)
+void BKE_pbvh_draw_cb(PBVH *bvh,
+ bool show_vcol,
+ bool update_only_visible,
+ PBVHFrustumPlanes *frustum,
+ void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers),
+ void *user_data)
{
- /* Update GPU buffers */
PBVHNode **nodes;
int totnode;
- BKE_pbvh_search_gather(
- bvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateDrawBuffers), &nodes, &totnode);
+ const int update_flag = PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers;
- pbvh_update_draw_buffers(bvh, nodes, totnode, show_vcol);
+ if (!update_only_visible) {
+ /* Update all draw buffers, also those outside the view. */
+ BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(update_flag), &nodes, &totnode);
- if (nodes) {
- MEM_freeN(nodes);
+ if (totnode) {
+ pbvh_update_draw_buffers(bvh, nodes, totnode, show_vcol, update_flag);
+ }
+
+ MEM_SAFE_FREE(nodes);
}
-}
-/**
- * Version of #BKE_pbvh_draw that runs a callback.
- */
-void BKE_pbvh_draw_cb(PBVH *bvh,
- float (*planes)[4],
- void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers),
- void *user_data)
-{
- PBVHNodeDrawCallbackData draw_data = {
- .draw_fn = draw_fn,
- .user_data = user_data,
- };
+ /* Gather visible nodes. */
+ PBVHDrawSearchData data = {.frustum = frustum, .accum_update_flag = 0};
+ BKE_pbvh_search_gather(bvh, pbvh_draw_search_cb, &data, &nodes, &totnode);
- if (planes) {
- BKE_pbvh_search_callback(
- bvh, BKE_pbvh_node_planes_contain_AABB, planes, pbvh_node_draw_cb, &draw_data);
+ if (update_only_visible && (data.accum_update_flag & update_flag)) {
+ /* Update draw buffers in visible nodes. */
+ pbvh_update_draw_buffers(bvh, nodes, totnode, show_vcol, data.accum_update_flag);
}
- else {
- BKE_pbvh_search_callback(bvh, NULL, NULL, pbvh_node_draw_cb, &draw_data);
+
+ /* Draw. */
+ for (int a = 0; a < totnode; a++) {
+ PBVHNode *node = nodes[a];
+
+ if (node->flag & PBVH_UpdateDrawBuffers) {
+ /* Flush buffers uses OpenGL, so not in parallel. */
+ GPU_pbvh_buffers_update_flush(node->draw_buffers);
+ }
+
+ node->flag &= ~(PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers);
+
+ if (!(node->flag & PBVH_FullyHidden)) {
+ draw_fn(user_data, node->draw_buffers);
+ }
}
+
+ MEM_SAFE_FREE(nodes);
}
void BKE_pbvh_draw_debug_cb(
@@ -2280,7 +2486,7 @@ void BKE_pbvh_grids_update(
bvh->grid_flag_mats = flagmats;
bvh->grid_hidden = grid_hidden;
- for (int a = 0; a < bvh->totnode; ++a) {
+ for (int a = 0; a < bvh->totnode; a++) {
BKE_pbvh_node_mark_rebuild_draw(&bvh->nodes[a]);
}
}
@@ -2348,7 +2554,7 @@ void BKE_pbvh_vert_coords_apply(PBVH *pbvh, const float (*vertCos)[3], const int
if (pbvh->verts) {
MVert *mvert = pbvh->verts;
/* copy new verts coords */
- for (int a = 0; a < pbvh->totvert; ++a, ++mvert) {
+ for (int a = 0; a < pbvh->totvert; a++, mvert++) {
/* no need for float comparison here (memory is exactly equal or not) */
if (memcmp(mvert->co, vertCos[a], sizeof(float[3])) != 0) {
copy_v3_v3(mvert->co, vertCos[a]);
@@ -2360,7 +2566,7 @@ void BKE_pbvh_vert_coords_apply(PBVH *pbvh, const float (*vertCos)[3], const int
BKE_mesh_calc_normals_looptri(
pbvh->verts, pbvh->totvert, pbvh->mloop, pbvh->looptri, pbvh->totprim, NULL);
- for (int a = 0; a < pbvh->totnode; ++a) {
+ for (int a = 0; a < pbvh->totnode; a++) {
BKE_pbvh_node_mark_update(&pbvh->nodes[a]);
}
@@ -2453,7 +2659,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo
BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids);
BKE_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert);
BKE_pbvh_node_get_verts(bvh, node, &vert_indices, &verts);
- vi->key = &bvh->gridkey;
+ vi->key = bvh->gridkey;
vi->grids = grids;
vi->grid_indices = grid_indices;
@@ -2505,3 +2711,14 @@ void pbvh_show_mask_set(PBVH *bvh, bool show_mask)
{
bvh->show_mask = show_mask;
}
+
+void BKE_pbvh_parallel_range_settings(TaskParallelSettings *settings,
+ bool use_threading,
+ int totnode)
+{
+ const int threaded_limit = 1;
+ BLI_parallel_range_settings_defaults(settings);
+ settings->use_threading = use_threading && (totnode > threaded_limit);
+ settings->min_iter_per_thread = 1;
+ settings->scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+}
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 1d8088c6605..c04e172f116 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -1508,12 +1508,18 @@ static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
bool pbvh_bmesh_node_raycast(PBVHNode *node,
const float ray_start[3],
+ const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
float *depth,
- bool use_original)
+ bool use_original,
+ int *r_active_vertex_index,
+ float *r_face_normal)
{
bool hit = false;
+ float min_depth = FLT_MAX;
+ float nearest_vertex_co[3] = {0.0f};
+ float location[3] = {0.0f};
if (use_original && node->bm_tot_ortri) {
for (int i = 0; i < node->bm_tot_ortri; i++) {
const int *t = node->bm_ortri[i];
@@ -1538,6 +1544,19 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node,
BM_face_as_array_vert_tri(f, v_tri);
hit |= ray_face_intersection_tri(
ray_start, isect_precalc, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth);
+
+ if (hit && *depth < min_depth) {
+ min_depth = *depth;
+ normal_tri_v3(r_face_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co);
+ madd_v3_v3v3fl(location, ray_start, ray_normal, *depth);
+ for (int j = 0; j < 3; j++) {
+ if (len_squared_v3v3(location, v_tri[j]->co) <
+ len_squared_v3v3(location, nearest_vertex_co)) {
+ copy_v3_v3(nearest_vertex_co, v_tri[j]->co);
+ *r_active_vertex_index = BM_elem_index_get(v_tri[j]);
+ }
+ }
+ }
}
}
}
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index e74a8d43c68..bad103743eb 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -206,9 +206,12 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag);
/* pbvh_bmesh.c */
bool pbvh_bmesh_node_raycast(PBVHNode *node,
const float ray_start[3],
+ const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
float *dist,
- bool use_original);
+ bool use_original,
+ int *r_active_vertex_index,
+ float *r_face_normal);
bool pbvh_bmesh_node_nearest_to_ray(PBVHNode *node,
const float ray_start[3],
const float ray_normal[3],
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 13d0f1adb84..7ae5f91c615 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -1831,6 +1831,10 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r
pid->file_type = PTCACHE_FILE_PTCACHE;
}
+/**
+ * \param ob: Optional, may be NULL.
+ * \param scene: Optional may be NULL.
+ */
PTCacheID BKE_ptcache_id_find(Object *ob, Scene *scene, PointCache *cache)
{
PTCacheID result = {0};
@@ -1934,40 +1938,45 @@ static bool foreach_object_ptcache(
Scene *scene, Object *object, int duplis, ForeachPtcacheCb callback, void *callback_user_data)
{
PTCacheID pid;
- /* Soft body. */
- if (object->soft != NULL) {
- BKE_ptcache_id_from_softbody(&pid, object, object->soft);
- if (!callback(&pid, callback_user_data)) {
+
+ if (object != NULL) {
+ /* Soft body. */
+ if (object->soft != NULL) {
+ BKE_ptcache_id_from_softbody(&pid, object, object->soft);
+ if (!callback(&pid, callback_user_data)) {
+ return false;
+ }
+ }
+ /* Particle systems. */
+ if (!foreach_object_particle_ptcache(object, callback, callback_user_data)) {
return false;
}
+ /* Modifiers. */
+ if (!foreach_object_modifier_ptcache(object, callback, callback_user_data)) {
+ return false;
+ }
+ /* Consider all object in dupli groups to be part of the same object,
+ * for baking with linking dupligroups. Once we have better overrides
+ * this can be revisited so users select the local objects directly. */
+ if (scene != NULL && (duplis-- > 0) && (object->instance_collection != NULL)) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (object->instance_collection, current_object) {
+ if (current_object == object) {
+ continue;
+ }
+ foreach_object_ptcache(scene, current_object, duplis, callback, callback_user_data);
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
}
- /* Particle systems. */
- if (!foreach_object_particle_ptcache(object, callback, callback_user_data)) {
- return false;
- }
- /* Modifiers. */
- if (!foreach_object_modifier_ptcache(object, callback, callback_user_data)) {
- return false;
- }
+
/* Rigid body. */
- if (scene != NULL && object->rigidbody_object != NULL && scene->rigidbody_world != NULL) {
+ if (scene != NULL && (object == NULL || object->rigidbody_object != NULL) &&
+ scene->rigidbody_world != NULL) {
BKE_ptcache_id_from_rigidbody(&pid, object, scene->rigidbody_world);
if (!callback(&pid, callback_user_data)) {
return false;
}
}
- /* Consider all object in dupli groups to be part of the same object,
- * for baking with linking dupligroups. Once we have better overrides
- * this can be revisited so users select the local objects directly. */
- if (scene != NULL && (duplis-- > 0) && (object->instance_collection != NULL)) {
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (object->instance_collection, current_object) {
- if (current_object == object) {
- continue;
- }
- foreach_object_ptcache(scene, current_object, duplis, callback, callback_user_data);
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- }
return true;
}
@@ -4537,7 +4546,7 @@ void BKE_ptcache_update_info(PTCacheID *pid)
}
BLI_str_format_int_grouped(formatted_tot, totframes);
- BLI_str_format_byte_unit(formatted_mem, bytes, true);
+ BLI_str_format_byte_unit(formatted_mem, bytes, false);
BLI_snprintf(mem_info,
sizeof(mem_info),
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index ec73406c14c..514f000d73d 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -1452,7 +1452,7 @@ void BKE_rigidbody_remove_object(Main *bmain, Scene *scene, Object *ob)
/* Some users seems to find it funny to use a view-layer instancing collection
* as RBW collection... Despite this being a bad (ab)use of the system, avoid losing objects
* when we remove them from RB simulation. */
- BKE_collection_object_add(bmain, BKE_collection_master(scene), ob);
+ BKE_collection_object_add(bmain, scene->master_collection, ob);
}
BKE_collection_object_remove(bmain, rbw->group, ob, false);
}
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 1ef93427253..4f855bd7d98 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -43,11 +43,13 @@
#include "DNA_windowmanager_types.h"
#include "DNA_workspace_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_world_types.h"
+#include "DNA_defaults.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BLI_callbacks.h"
+#include "BKE_callbacks.h"
#include "BLI_string.h"
#include "BLI_string_utils.h"
#include "BLI_threads.h"
@@ -239,6 +241,8 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
{
/* We never handle usercount here for own data. */
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
+ /* We always need allocation of our private ID data. */
+ const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
sce_dst->ed = NULL;
sce_dst->depsgraph_hash = NULL;
@@ -246,8 +250,10 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
/* Master Collection */
if (sce_src->master_collection) {
- sce_dst->master_collection = BKE_collection_copy_master(
- bmain, sce_src->master_collection, flag);
+ BKE_id_copy_ex(bmain,
+ (ID *)sce_src->master_collection,
+ (ID **)&sce_dst->master_collection,
+ flag_private_id_data);
}
/* View Layers */
@@ -265,10 +271,13 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
BKE_keyingsets_copy(&(sce_dst->keyingsets), &(sce_src->keyingsets));
if (sce_src->nodetree) {
- /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
- * (see BKE_libblock_copy_ex()). */
- BKE_id_copy_ex(bmain, (ID *)sce_src->nodetree, (ID **)&sce_dst->nodetree, flag);
- BKE_libblock_relink_ex(bmain, sce_dst->nodetree, (void *)(&sce_src->id), &sce_dst->id, false);
+ BKE_id_copy_ex(
+ bmain, (ID *)sce_src->nodetree, (ID **)&sce_dst->nodetree, flag_private_id_data);
+ BKE_libblock_relink_ex(bmain,
+ sce_dst->nodetree,
+ (void *)(&sce_src->id),
+ &sce_dst->id,
+ ID_REMAP_SKIP_NEVER_NULL_USAGE);
}
if (sce_src->rigidbody_world) {
@@ -309,6 +318,10 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
flag_subdata);
}
+ if (sce_src->display.shading.prop) {
+ sce_dst->display.shading.prop = IDP_CopyProperty(sce_src->display.shading.prop);
+ }
+
BKE_sound_reset_scene_runtime(sce_dst);
/* Copy sequencer, this is local data! */
@@ -541,6 +554,11 @@ void BKE_scene_free_ex(Scene *sce, const bool do_id_user)
sce->eevee.light_cache = NULL;
}
+ if (sce->display.shading.prop) {
+ IDP_FreeProperty(sce->display.shading.prop);
+ sce->display.shading.prop = NULL;
+ }
+
/* These are freed on doversion. */
BLI_assert(sce->layer_properties == NULL);
}
@@ -550,107 +568,20 @@ void BKE_scene_free(Scene *sce)
BKE_scene_free_ex(sce, true);
}
+/**
+ * \note Use DNA_scene_defaults.h where possible.
+ */
void BKE_scene_init(Scene *sce)
{
- ParticleEditSettings *pset;
- int a;
const char *colorspace_name;
SceneRenderView *srv;
CurveMapping *mblur_shutter_curve;
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(sce, id));
- sce->cursor.rotation_mode = ROT_MODE_XYZ;
- sce->cursor.rotation_quaternion[0] = 1.0f;
- sce->cursor.rotation_axis[1] = 1.0f;
-
- sce->r.mode = 0;
- sce->r.cfra = 1;
- sce->r.sfra = 1;
- sce->r.efra = 250;
- sce->r.frame_step = 1;
- sce->r.xsch = 1920;
- sce->r.ysch = 1080;
- sce->r.xasp = 1;
- sce->r.yasp = 1;
- sce->r.tilex = 256;
- sce->r.tiley = 256;
- sce->r.size = 100;
-
- sce->r.im_format.planes = R_IMF_PLANES_RGBA;
- sce->r.im_format.imtype = R_IMF_IMTYPE_PNG;
- sce->r.im_format.depth = R_IMF_CHAN_DEPTH_8;
- sce->r.im_format.quality = 90;
- sce->r.im_format.compress = 15;
-
- sce->r.displaymode = R_OUTPUT_WINDOW;
- sce->r.framapto = 100;
- sce->r.images = 100;
- sce->r.framelen = 1.0;
- sce->r.blurfac = 0.5;
- sce->r.frs_sec = 24;
- sce->r.frs_sec_base = 1;
-
- /* OCIO_TODO: for forwards compatibility only, so if no tonecurve are used,
- * images would look in the same way as in current blender
- *
- * perhaps at some point should be completely deprecated?
- */
- sce->r.color_mgt_flag |= R_COLOR_MANAGEMENT;
-
- sce->r.gauss = 1.5;
- sce->r.dither_intensity = 1.0f;
-
- sce->r.bake_mode = 0;
- sce->r.bake_filter = 16;
- sce->r.bake_flag = R_BAKE_CLEAR;
- sce->r.bake_samples = 256;
- sce->r.bake_biasdist = 0.001;
-
- sce->r.bake.flag = R_BAKE_CLEAR;
- sce->r.bake.pass_filter = R_BAKE_PASS_FILTER_ALL;
- sce->r.bake.width = 512;
- sce->r.bake.height = 512;
- sce->r.bake.margin = 16;
- sce->r.bake.normal_space = R_BAKE_SPACE_TANGENT;
- sce->r.bake.normal_swizzle[0] = R_BAKE_POSX;
- sce->r.bake.normal_swizzle[1] = R_BAKE_POSY;
- sce->r.bake.normal_swizzle[2] = R_BAKE_POSZ;
- BLI_strncpy(sce->r.bake.filepath, U.renderdir, sizeof(sce->r.bake.filepath));
-
- sce->r.bake.im_format.planes = R_IMF_PLANES_RGBA;
- sce->r.bake.im_format.imtype = R_IMF_IMTYPE_PNG;
- sce->r.bake.im_format.depth = R_IMF_CHAN_DEPTH_8;
- sce->r.bake.im_format.quality = 90;
- sce->r.bake.im_format.compress = 15;
+ MEMCPY_STRUCT_AFTER(sce, DNA_struct_default_get(Scene), id);
- sce->r.scemode = R_DOCOMP | R_DOSEQ | R_EXTENSION;
- sce->r.stamp = R_STAMP_TIME | R_STAMP_FRAME | R_STAMP_DATE | R_STAMP_CAMERA | R_STAMP_SCENE |
- R_STAMP_FILENAME | R_STAMP_RENDERTIME | R_STAMP_MEMORY;
- sce->r.stamp_font_id = 12;
- sce->r.fg_stamp[0] = sce->r.fg_stamp[1] = sce->r.fg_stamp[2] = 0.8f;
- sce->r.fg_stamp[3] = 1.0f;
- sce->r.bg_stamp[0] = sce->r.bg_stamp[1] = sce->r.bg_stamp[2] = 0.0f;
- sce->r.bg_stamp[3] = 0.25f;
-
- sce->r.seq_prev_type = OB_SOLID;
- sce->r.seq_rend_type = OB_SOLID;
- sce->r.seq_flag = 0;
-
- sce->r.threads = 1;
-
- sce->r.simplify_subsurf = 6;
- sce->r.simplify_particles = 1.0f;
-
- sce->r.border.xmin = 0.0f;
- sce->r.border.ymin = 0.0f;
- sce->r.border.xmax = 1.0f;
- sce->r.border.ymax = 1.0f;
-
- sce->r.preview_start_resolution = 64;
-
- sce->r.line_thickness_mode = R_LINE_THICKNESS_ABSOLUTE;
- sce->r.unit_line_thickness = 1.0f;
+ BLI_strncpy(sce->r.bake.filepath, U.renderdir, sizeof(sce->r.bake.filepath));
mblur_shutter_curve = &sce->r.mblur_shutter_curve;
BKE_curvemapping_set_defaults(mblur_shutter_curve, 1, 0.0f, 0.0f, 1.0f, 1.0f);
@@ -660,49 +591,10 @@ void BKE_scene_init(Scene *sce)
CURVE_PRESET_MAX,
CURVEMAP_SLOPE_POS_NEG);
- sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings), "Tool Settings Struct");
+ sce->toolsettings = DNA_struct_default_alloc(ToolSettings);
- sce->toolsettings->object_flag |= SCE_OBJECT_MODE_LOCK;
- sce->toolsettings->doublimit = 0.001;
- sce->toolsettings->vgroup_weight = 1.0f;
- sce->toolsettings->uvcalc_margin = 0.001f;
- sce->toolsettings->uvcalc_flag = UVCALC_TRANSFORM_CORRECT;
- sce->toolsettings->unwrapper = 1;
- sce->toolsettings->select_thresh = 0.01f;
-
- sce->toolsettings->selectmode = SCE_SELECT_VERTEX;
- sce->toolsettings->uv_selectmode = UV_SELECT_VERTEX;
sce->toolsettings->autokey_mode = U.autokey_mode;
- sce->toolsettings->transform_pivot_point = V3D_AROUND_CENTER_MEDIAN;
- sce->toolsettings->snap_mode = SCE_SNAP_MODE_INCREMENT;
- sce->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID;
- sce->toolsettings->snap_uv_mode = SCE_SNAP_MODE_INCREMENT;
- sce->toolsettings->snap_transform_mode_flag = SCE_SNAP_TRANSFORM_MODE_TRANSLATE;
-
- sce->toolsettings->curve_paint_settings.curve_type = CU_BEZIER;
- sce->toolsettings->curve_paint_settings.flag |= CURVE_PAINT_FLAG_CORNERS_DETECT;
- sce->toolsettings->curve_paint_settings.error_threshold = 8;
- sce->toolsettings->curve_paint_settings.radius_max = 1.0f;
- sce->toolsettings->curve_paint_settings.corner_angle = DEG2RADF(70.0f);
-
- sce->toolsettings->statvis.overhang_axis = OB_NEGZ;
- sce->toolsettings->statvis.overhang_min = 0;
- sce->toolsettings->statvis.overhang_max = DEG2RADF(45.0f);
- sce->toolsettings->statvis.thickness_max = 0.1f;
- sce->toolsettings->statvis.thickness_samples = 1;
- sce->toolsettings->statvis.distort_min = DEG2RADF(5.0f);
- sce->toolsettings->statvis.distort_max = DEG2RADF(45.0f);
-
- sce->toolsettings->statvis.sharp_min = DEG2RADF(90.0f);
- sce->toolsettings->statvis.sharp_max = DEG2RADF(180.0f);
-
- sce->toolsettings->proportional_size = 1.0f;
-
- sce->toolsettings->imapaint.paint.flags |= PAINT_SHOW_BRUSH;
- sce->toolsettings->imapaint.normal_angle = 80;
- sce->toolsettings->imapaint.seam_bleed = 2;
-
/* grease pencil multiframe falloff curve */
sce->toolsettings->gp_sculpt.cur_falloff = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
CurveMapping *gp_falloff_curve = sce->toolsettings->gp_sculpt.cur_falloff;
@@ -718,54 +610,25 @@ void BKE_scene_init(Scene *sce)
CURVE_PRESET_BELL,
CURVEMAP_SLOPE_POSITIVE);
- sce->toolsettings->gp_sculpt.guide.spacing = 20.0f;
-
- sce->physics_settings.gravity[0] = 0.0f;
- sce->physics_settings.gravity[1] = 0.0f;
- sce->physics_settings.gravity[2] = -9.81f;
- sce->physics_settings.flag = PHYS_GLOBAL_GRAVITY;
-
sce->unit.system = USER_UNIT_METRIC;
sce->unit.scale_length = 1.0f;
sce->unit.length_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_LENGTH);
sce->unit.mass_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_MASS);
sce->unit.time_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_TIME);
- pset = &sce->toolsettings->particle;
- pset->flag = PE_KEEP_LENGTHS | PE_LOCK_FIRST | PE_DEFLECT_EMITTER | PE_AUTO_VELOCITY;
- pset->emitterdist = 0.25f;
- pset->totrekey = 5;
- pset->totaddkey = 5;
- pset->brushtype = PE_BRUSH_COMB;
- pset->draw_step = 2;
- pset->fade_frames = 2;
- pset->selectmode = SCE_SELECT_PATH;
-
- for (a = 0; a < ARRAY_SIZE(pset->brush); a++) {
- pset->brush[a].strength = 0.5f;
- pset->brush[a].size = 50;
- pset->brush[a].step = 10;
- pset->brush[a].count = 10;
- }
- pset->brush[PE_BRUSH_CUT].strength = 1.0f;
-
- sce->r.ffcodecdata.audio_mixrate = 48000;
- sce->r.ffcodecdata.audio_volume = 1.0f;
- sce->r.ffcodecdata.audio_bitrate = 192;
- sce->r.ffcodecdata.audio_channels = 2;
+ {
+ ParticleEditSettings *pset;
+ pset = &sce->toolsettings->particle;
+ for (int i = 1; i < ARRAY_SIZE(pset->brush); i++) {
+ pset->brush[i] = pset->brush[0];
+ }
+ pset->brush[PE_BRUSH_CUT].strength = 1.0f;
+ }
BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(sce->r.engine));
- sce->audio.distance_model = 2.0f;
- sce->audio.doppler_factor = 1.0f;
- sce->audio.speed_of_sound = 343.3f;
- sce->audio.volume = 1.0f;
- sce->audio.flag = AUDIO_SYNC;
-
BLI_strncpy(sce->r.pic, U.renderdir, sizeof(sce->r.pic));
- BLI_rctf_init(&sce->r.safety, 0.1f, 0.9f, 0.1f, 0.9f);
-
/* Note; in header_info.c the scene copy happens...,
* if you add more to renderdata it has to be checked there. */
@@ -800,14 +663,6 @@ void BKE_scene_init(Scene *sce)
BKE_color_managed_view_settings_init_render(
&sce->r.bake.im_format.view_settings, &sce->r.bake.im_format.display_settings, "Filmic");
- /* Safe Areas */
- copy_v2_fl2(sce->safe_areas.title, 10.0f / 100.0f, 5.0f / 100.0f);
- copy_v2_fl2(sce->safe_areas.action, 3.5f / 100.0f, 3.5f / 100.0f);
- copy_v2_fl2(sce->safe_areas.title_center, 17.5f / 100.0f, 5.0f / 100.0f);
- copy_v2_fl2(sce->safe_areas.action_center, 15.0f / 100.0f, 5.0f / 100.0f);
-
- sce->preview = NULL;
-
/* GP Sculpt brushes */
{
GP_Sculpt_Settings *gset = &sce->toolsettings->gp_sculpt;
@@ -874,16 +729,6 @@ void BKE_scene_init(Scene *sce)
copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
}
- /* GP Stroke Placement */
- sce->toolsettings->gpencil_v3d_align = GP_PROJECT_VIEWSPACE;
- sce->toolsettings->gpencil_v2d_align = GP_PROJECT_VIEWSPACE;
- sce->toolsettings->gpencil_seq_align = GP_PROJECT_VIEWSPACE;
- sce->toolsettings->gpencil_ima_align = GP_PROJECT_VIEWSPACE;
-
- /* Annotations */
- sce->toolsettings->annotate_v3d_align = GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR;
- sce->toolsettings->annotate_thickness = 3;
-
for (int i = 0; i < ARRAY_SIZE(sce->orientation_slots); i++) {
sce->orientation_slots[i].index_custom = -1;
}
@@ -892,80 +737,6 @@ void BKE_scene_init(Scene *sce)
sce->master_collection = BKE_collection_master_add();
BKE_view_layer_add(sce, "View Layer");
-
- /* SceneDisplay */
- copy_v3_v3(sce->display.light_direction, (float[3]){M_SQRT1_3, M_SQRT1_3, M_SQRT1_3});
- sce->display.shadow_shift = 0.1f;
- sce->display.shadow_focus = 0.0f;
-
- sce->display.matcap_ssao_distance = 0.2f;
- sce->display.matcap_ssao_attenuation = 1.0f;
- sce->display.matcap_ssao_samples = 16;
-
- sce->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8;
- sce->display.viewport_aa = SCE_DISPLAY_AA_FXAA;
-
- /* OpenGL Render. */
- BKE_screen_view3d_shading_init(&sce->display.shading);
-
- /* SceneEEVEE */
- sce->eevee.gi_diffuse_bounces = 3;
- sce->eevee.gi_cubemap_resolution = 512;
- sce->eevee.gi_visibility_resolution = 32;
- sce->eevee.gi_cubemap_draw_size = 0.3f;
- sce->eevee.gi_irradiance_draw_size = 0.1f;
- sce->eevee.gi_irradiance_smoothing = 0.1f;
- sce->eevee.gi_filter_quality = 3.0f;
-
- sce->eevee.taa_samples = 16;
- sce->eevee.taa_render_samples = 64;
-
- sce->eevee.sss_samples = 7;
- sce->eevee.sss_jitter_threshold = 0.3f;
-
- sce->eevee.ssr_quality = 0.25f;
- sce->eevee.ssr_max_roughness = 0.5f;
- sce->eevee.ssr_thickness = 0.2f;
- sce->eevee.ssr_border_fade = 0.075f;
- sce->eevee.ssr_firefly_fac = 10.0f;
-
- sce->eevee.volumetric_start = 0.1f;
- sce->eevee.volumetric_end = 100.0f;
- sce->eevee.volumetric_tile_size = 8;
- sce->eevee.volumetric_samples = 64;
- sce->eevee.volumetric_sample_distribution = 0.8f;
- sce->eevee.volumetric_light_clamp = 0.0f;
- sce->eevee.volumetric_shadow_samples = 16;
-
- sce->eevee.gtao_distance = 0.2f;
- sce->eevee.gtao_factor = 1.0f;
- sce->eevee.gtao_quality = 0.25f;
-
- sce->eevee.bokeh_max_size = 100.0f;
- sce->eevee.bokeh_threshold = 1.0f;
-
- copy_v3_fl(sce->eevee.bloom_color, 1.0f);
- sce->eevee.bloom_threshold = 0.8f;
- sce->eevee.bloom_knee = 0.5f;
- sce->eevee.bloom_intensity = 0.05f;
- sce->eevee.bloom_radius = 6.5f;
- sce->eevee.bloom_clamp = 0.0f;
-
- sce->eevee.motion_blur_samples = 8;
- sce->eevee.motion_blur_shutter = 0.5f;
-
- sce->eevee.shadow_method = SHADOW_ESM;
- sce->eevee.shadow_cube_size = 512;
- sce->eevee.shadow_cascade_size = 1024;
-
- sce->eevee.light_cache = NULL;
- sce->eevee.light_threshold = 0.01f;
-
- sce->eevee.overscan = 3.0f;
-
- sce->eevee.flag = SCE_EEVEE_VOLUMETRIC_LIGHTS | SCE_EEVEE_GTAO_BENT_NORMALS |
- SCE_EEVEE_GTAO_BOUNCE | SCE_EEVEE_TAA_REPROJECTION |
- SCE_EEVEE_SSR_HALF_RESOLUTION;
}
Scene *BKE_scene_add(Main *bmain, const char *name)
@@ -1547,34 +1318,41 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on
bool run_callbacks = DEG_id_type_any_updated(depsgraph);
if (run_callbacks) {
- BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_DEPSGRAPH_UPDATE_PRE);
- }
+ BKE_callback_exec_id(bmain, &scene->id, BKE_CB_EVT_DEPSGRAPH_UPDATE_PRE);
+ }
+
+ for (int pass = 0; pass < 2; pass++) {
+ /* (Re-)build dependency graph if needed. */
+ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
+ /* Uncomment this to check if graph was properly tagged for update. */
+ // DEG_debug_graph_relations_validate(depsgraph, bmain, scene);
+ /* Flush editing data if needed. */
+ prepare_mesh_for_viewport_render(bmain, view_layer);
+ /* Update all objects: drivers, matrices, displists, etc. flags set
+ * by depgraph or manual, no layer check here, gets correct flushed.
+ */
+ DEG_evaluate_on_refresh(bmain, depsgraph);
+ /* Update sound system. */
+ BKE_scene_update_sound(depsgraph, bmain);
+ /* Notify python about depsgraph update. */
+ if (run_callbacks) {
+ BKE_callback_exec_id_depsgraph(
+ bmain, &scene->id, depsgraph, BKE_CB_EVT_DEPSGRAPH_UPDATE_POST);
+ }
+ /* Inform editors about possible changes. */
+ DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, false);
+ /* Clear recalc flags. */
+ DEG_ids_clear_recalc(bmain, depsgraph);
+
+ /* If user callback did not tag anything for update we can skip second iteration.
+ * Otherwise we update scene once again, but without running callbacks to bring
+ * scene to a fully evaluated state with user modifications taken into account. */
+ if (DEG_is_fully_evaluated(depsgraph)) {
+ break;
+ }
- /* TODO(sergey): Some functions here are changing global state,
- * for example, clearing update tags from bmain.
- */
- /* (Re-)build dependency graph if needed. */
- DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
- /* Uncomment this to check if graph was properly tagged for update. */
- // DEG_debug_graph_relations_validate(depsgraph, bmain, scene);
- /* Flush editing data if needed. */
- prepare_mesh_for_viewport_render(bmain, view_layer);
- /* Flush recalc flags to dependencies. */
- DEG_graph_flush_update(bmain, depsgraph);
- /* Update all objects: drivers, matrices, displists, etc. flags set
- * by depgraph or manual, no layer check here, gets correct flushed.
- */
- DEG_evaluate_on_refresh(depsgraph);
- /* Update sound system. */
- BKE_scene_update_sound(depsgraph, bmain);
- /* Notify python about depsgraph update. */
- if (run_callbacks) {
- BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_DEPSGRAPH_UPDATE_POST);
+ run_callbacks = false;
}
- /* Inform editors about possible changes. */
- DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, false);
- /* Clear recalc flags. */
- DEG_ids_clear_recalc(bmain, depsgraph);
}
void BKE_scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain)
@@ -1593,33 +1371,52 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph, Main *bmain)
Scene *scene = DEG_get_input_scene(depsgraph);
ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
- /* TODO(sergey): Some functions here are changing global state,
- * for example, clearing update tags from bmain.
- */
- const float ctime = BKE_scene_frame_get(scene);
/* Keep this first. */
- BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_PRE);
- /* Update animated image textures for particles, modifiers, gpu, etc,
- * call this at the start so modifiers with textures don't lag 1 frame.
- */
- BKE_image_editors_update_frame(bmain, scene->r.cfra);
- BKE_sound_set_cfra(scene->r.cfra);
- DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
+ BKE_callback_exec_id(bmain, &scene->id, BKE_CB_EVT_FRAME_CHANGE_PRE);
+
+ for (int pass = 0; pass < 2; pass++) {
+ /* Update animated image textures for particles, modifiers, gpu, etc,
+ * call this at the start so modifiers with textures don't lag 1 frame.
+ */
+ BKE_image_editors_update_frame(bmain, scene->r.cfra);
+ BKE_sound_set_cfra(scene->r.cfra);
+ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
#ifdef POSE_ANIMATION_WORKAROUND
- scene_armature_depsgraph_workaround(bmain, depsgraph);
+ scene_armature_depsgraph_workaround(bmain, depsgraph);
#endif
- /* Update all objects: drivers, matrices, displists, etc. flags set
- * by depgraph or manual, no layer check here, gets correct flushed.
- */
- DEG_evaluate_on_framechange(bmain, depsgraph, ctime);
- /* Update sound system animation. */
- BKE_scene_update_sound(depsgraph, bmain);
- /* Notify editors and python about recalc. */
- BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_POST);
- /* Inform editors about possible changes. */
- DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, true);
- /* clear recalc flags */
- DEG_ids_clear_recalc(bmain, depsgraph);
+ /* Update all objects: drivers, matrices, displists, etc. flags set
+ * by depgraph or manual, no layer check here, gets correct flushed.
+ *
+ * NOTE: Only update for new frame on first iteration. Second iteration is for ensuring user
+ * edits from callback are properly taken into account. Doing a time update on those would
+ * loose any possible unkeyed changes made by the handler. */
+ if (pass == 0) {
+ const float ctime = BKE_scene_frame_get(scene);
+ DEG_evaluate_on_framechange(bmain, depsgraph, ctime);
+ }
+ else {
+ DEG_evaluate_on_refresh(bmain, depsgraph);
+ }
+ /* Update sound system animation. */
+ BKE_scene_update_sound(depsgraph, bmain);
+
+ /* Notify editors and python about recalc. */
+ if (pass == 0) {
+ BKE_callback_exec_id_depsgraph(bmain, &scene->id, depsgraph, BKE_CB_EVT_FRAME_CHANGE_POST);
+ }
+
+ /* Inform editors about possible changes. */
+ DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, true);
+ /* clear recalc flags */
+ DEG_ids_clear_recalc(bmain, depsgraph);
+
+ /* If user callback did not tag anything for update we can skip second iteration.
+ * Otherwise we update scene once again, but without running callbacks to bring
+ * scene to a fully evaluated state with user modifications taken into account. */
+ if (DEG_is_fully_evaluated(depsgraph)) {
+ break;
+ }
+ }
}
/** Ensures given scene/view_layer pair has a valid, up-to-date depsgraph.
@@ -1629,7 +1426,7 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph, Main *bmain)
*/
void BKE_scene_view_layer_graph_evaluated_ensure(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
DEG_make_active(depsgraph);
BKE_scene_graph_update_tagged(depsgraph, bmain);
}
@@ -1877,6 +1674,8 @@ double BKE_scene_unit_scale(const UnitSettings *unit, const int unit_type, doubl
switch (unit_type) {
case B_UNIT_LENGTH:
+ case B_UNIT_VELOCITY:
+ case B_UNIT_ACCELERATION:
return value * (double)unit->scale_length;
case B_UNIT_AREA:
case B_UNIT_POWER:
@@ -2261,7 +2060,7 @@ void BKE_scene_free_depsgraph_hash(Scene *scene)
/* Query depsgraph for a specific contexts. */
-Depsgraph *BKE_scene_get_depsgraph(Scene *scene, ViewLayer *view_layer, bool allocate)
+Depsgraph *BKE_scene_get_depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, bool allocate)
{
BLI_assert(scene != NULL);
BLI_assert(view_layer != NULL);
@@ -2285,7 +2084,7 @@ Depsgraph *BKE_scene_get_depsgraph(Scene *scene, ViewLayer *view_layer, bool all
scene->depsgraph_hash, &key, (void ***)&key_ptr, (void ***)&depsgraph_ptr)) {
*key_ptr = MEM_mallocN(sizeof(DepsgraphKey), __func__);
**key_ptr = key;
- *depsgraph_ptr = DEG_graph_new(scene, view_layer, DAG_EVAL_VIEWPORT);
+ *depsgraph_ptr = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_VIEWPORT);
/* TODO(sergey): Would be cool to avoid string format print,
* but is a bit tricky because we can't know in advance whether
* we will ever enable debug messages for this depsgraph.
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 619845c9ecb..1835fb2a523 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -36,6 +36,7 @@
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_workspace_types.h"
+#include "DNA_defaults.h"
#include "BLI_math_vector.h"
#include "BLI_listbase.h"
@@ -852,22 +853,8 @@ void BKE_screen_view3d_scene_sync(bScreen *sc, Scene *scene)
void BKE_screen_view3d_shading_init(View3DShading *shading)
{
- memset(shading, 0, sizeof(*shading));
-
- shading->type = OB_SOLID;
- shading->prev_type = OB_SOLID;
- shading->flag = V3D_SHADING_SPECULAR_HIGHLIGHT | V3D_SHADING_XRAY_WIREFRAME;
- shading->light = V3D_LIGHTING_STUDIO;
- shading->shadow_intensity = 0.5f;
- shading->xray_alpha = 0.5f;
- shading->xray_alpha_wire = 0.0f;
- shading->cavity_valley_factor = 1.0f;
- shading->cavity_ridge_factor = 1.0f;
- shading->cavity_type = V3D_SHADING_CAVITY_CURVATURE;
- shading->curvature_ridge_factor = 1.0f;
- shading->curvature_valley_factor = 1.0f;
- copy_v3_fl(shading->single_color, 0.8f);
- copy_v3_fl(shading->background_color, 0.05f);
+ const View3DShading *shading_default = DNA_struct_default_get(View3DShading);
+ memcpy(shading, shading_default, sizeof(*shading));
}
/* magic zoom calculation, no idea what
diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c
index ff54327e406..d12710690df 100644
--- a/source/blender/blenkernel/intern/seqcache.c
+++ b/source/blender/blenkernel/intern/seqcache.c
@@ -44,17 +44,6 @@
* Sequencer Cache Design Notes
* ============================
*
- * Cache key members:
- * is_temp_cache - this cache entry will be freed before rendering next frame
- * creator_id - ID of thread that created entry
- * cost - In short: render time divided by playback frame rate
- * link_prev/next - link to another entry created during rendering of the frame
- *
- * Linking: We use links to reduce number of iterations needed to manage cache.
- * Entries are linked in order as they are put into cache.
- * Only permanent (is_temp_cache = 0) cache entries are linked.
- * Putting #SEQ_CACHE_STORE_FINAL_OUT will reset linking
- *
* Function:
* All images created during rendering are added to cache, even if the cache is already full.
* This is because:
@@ -64,6 +53,11 @@
* "holes" in the cache, which can be annoying
* If the cache is full all entries for pending frame will have is_temp_cache set.
*
+ * Linking: We use links to reduce number of iterations over entries needed to manage cache.
+ * Entries are linked in order as they are put into cache.
+ * Only permanent (is_temp_cache = 0) cache entries are linked.
+ * Putting #SEQ_CACHE_STORE_FINAL_OUT will reset linking
+ *
* Only entire frame can be freed to release resources for new entries (recycling).
* Once again, this is to reduce number of iterations, but also more controllable than removing
* entries one by one in reverse order to their creation.
@@ -93,9 +87,10 @@ typedef struct SeqCacheKey {
struct Sequence *seq;
SeqRenderData context;
float nfra;
- float cost;
- bool is_temp_cache;
- short creator_id;
+ float cost; /* In short: render time(s) divided by playback frame duration(s) */
+ bool is_temp_cache; /* this cache entry will be freed before rendering next frame */
+ /* ID of task for asigning temp cache entries to particular task(thread, etc.) */
+ eSeqTaskId task_id;
int type;
} SeqCacheKey;
@@ -172,6 +167,11 @@ static void seq_cache_unlock(Scene *scene)
}
}
+static size_t seq_cache_get_mem_total(void)
+{
+ return ((size_t)U.memcachelimit) * 1024 * 1024;
+}
+
static void seq_cache_keyfree(void *val)
{
SeqCacheKey *key = val;
@@ -228,10 +228,43 @@ static void seq_cache_relink_keys(SeqCacheKey *link_next, SeqCacheKey *link_prev
}
}
+/* Choose a key out of 2 candidates(leftmost and rightmost items)
+ * to recycle based on currently used strategy */
static SeqCacheKey *seq_cache_choose_key(Scene *scene, SeqCacheKey *lkey, SeqCacheKey *rkey)
{
SeqCacheKey *finalkey = NULL;
+ /* Ideally, cache would not need to check the state of prefetching task
+ * that is tricky to do however, because prefetch would need to know,
+ * if a key, that is about to be created would be removed by itself.
+ *
+ * This can happen because only FINAL_OUT item insertion will trigger recycling
+ * but that is also the point, where prefetch can be suspended.
+ *
+ * We could use temp cache as a shield and later make it a non-temporary entry,
+ * but it is not worth of increasing system complexity.
+ */
+ if (scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE) {
+ int pfjob_start, pfjob_end;
+ BKE_sequencer_prefetch_get_time_range(scene, &pfjob_start, &pfjob_end);
+
+ if (lkey) {
+ int lkey_cfra = lkey->seq->start + lkey->nfra;
+ if (lkey_cfra < pfjob_start || lkey_cfra > pfjob_end) {
+ return lkey;
+ }
+ }
+
+ if (rkey) {
+ int rkey_cfra = rkey->seq->start + rkey->nfra;
+ if (rkey_cfra < pfjob_start || rkey_cfra > pfjob_end) {
+ return rkey;
+ }
+ }
+
+ return NULL;
+ }
+
if (rkey && lkey) {
int lkey_cfra = lkey->seq->start + lkey->nfra;
int rkey_cfra = rkey->seq->start + rkey->nfra;
@@ -342,15 +375,16 @@ static SeqCacheKey *seq_cache_get_item_for_removal(Scene *scene)
}
finalkey = seq_cache_choose_key(scene, lkey, rkey);
+
return finalkey;
}
/* Find only "base" keys
* Sources(other types) for a frame must be freed all at once
*/
-static bool seq_cache_recycle_item(Scene *scene)
+bool BKE_sequencer_cache_recycle_item(Scene *scene)
{
- size_t memory_total = ((size_t)U.memcachelimit) * 1024 * 1024;
+ size_t memory_total = seq_cache_get_mem_total();
SeqCache *cache = seq_cache_get_from_scene(scene);
if (!cache) {
return false;
@@ -429,7 +463,7 @@ void BKE_sequencer_cache_free_temp_cache(Scene *scene, short id, int cfra)
SeqCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
BLI_ghashIterator_step(&gh_iter);
- if (key->is_temp_cache && key->creator_id == id && key->seq->start + key->nfra != cfra) {
+ if (key->is_temp_cache && key->task_id == id && key->seq->start + key->nfra != cfra) {
BLI_ghash_remove(cache->hash, key, seq_cache_keyfree, seq_cache_valfree);
}
}
@@ -459,6 +493,8 @@ void BKE_sequencer_cache_cleanup_all(Main *bmain)
}
void BKE_sequencer_cache_cleanup(Scene *scene)
{
+ BKE_sequencer_prefetch_stop(scene);
+
SeqCache *cache = seq_cache_get_from_scene(scene);
if (!cache) {
return;
@@ -542,6 +578,12 @@ struct ImBuf *BKE_sequencer_cache_get(const SeqRenderData *context,
{
Scene *scene = context->scene;
+ if (context->is_prefetch_render) {
+ context = BKE_sequencer_prefetch_get_original_context(context);
+ scene = context->scene;
+ seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene);
+ }
+
if (!scene->ed->cache) {
BKE_sequencer_cache_create(scene);
return NULL;
@@ -571,7 +613,13 @@ bool BKE_sequencer_cache_put_if_possible(
{
Scene *scene = context->scene;
- if (seq_cache_recycle_item(scene)) {
+ if (context->is_prefetch_render) {
+ context = BKE_sequencer_prefetch_get_original_context(context);
+ scene = context->scene;
+ seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene);
+ }
+
+ if (BKE_sequencer_cache_recycle_item(scene)) {
BKE_sequencer_cache_put(context, seq, cfra, type, ibuf, cost);
return true;
}
@@ -586,7 +634,12 @@ void BKE_sequencer_cache_put(
const SeqRenderData *context, Sequence *seq, float cfra, int type, ImBuf *i, float cost)
{
Scene *scene = context->scene;
- short creator_id = 0;
+
+ if (context->is_prefetch_render) {
+ context = BKE_sequencer_prefetch_get_original_context(context);
+ scene = context->scene;
+ seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene);
+ }
if (i == NULL || context->skip_cache || context->is_proxy_render || !seq) {
return;
@@ -632,7 +685,7 @@ void BKE_sequencer_cache_put(
key->link_prev = NULL;
key->link_next = NULL;
key->is_temp_cache = true;
- key->creator_id = creator_id;
+ key->task_id = context->task_id;
/* Item stored for later use */
if (flag & type) {
@@ -688,3 +741,14 @@ void BKE_sequencer_cache_iterate(
cache->last_key = NULL;
seq_cache_unlock(scene);
}
+
+bool BKE_sequencer_cache_is_full(Scene *scene)
+{
+ size_t memory_total = seq_cache_get_mem_total();
+ SeqCache *cache = seq_cache_get_from_scene(scene);
+ if (!cache) {
+ return false;
+ }
+
+ return memory_total < cache->memory_used;
+}
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index 89f3f9ef9fd..dbdaaaa5fc3 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -3434,13 +3434,13 @@ static void do_gaussian_blur_effect_byte_x(Sequence *seq,
float *gausstab_x;
gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x);
- for (i = 0; i < y; ++i) {
- for (j = 0; j < x; ++j) {
+ for (i = 0; i < y; i++) {
+ for (j = 0; j < x; j++) {
int out_index = INDEX(j, i);
float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float accum_weight = 0.0f;
- for (int current_x = j - size_x; current_x <= j + size_x; ++current_x) {
+ for (int current_x = j - size_x; current_x <= j + size_x; current_x++) {
if (current_x < 0 || current_x >= frame_width) {
/* Out of bounds. */
continue;
@@ -3484,12 +3484,12 @@ static void do_gaussian_blur_effect_byte_y(Sequence *seq,
float *gausstab_y;
gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y);
- for (i = 0; i < y; ++i) {
- for (j = 0; j < x; ++j) {
+ for (i = 0; i < y; i++) {
+ for (j = 0; j < x; j++) {
int out_index = INDEX(j, i);
float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float accum_weight = 0.0f;
- for (int current_y = i - size_y; current_y <= i + size_y; ++current_y) {
+ for (int current_y = i - size_y; current_y <= i + size_y; current_y++) {
if (current_y < -start_line || current_y + start_line >= frame_height) {
/* Out of bounds. */
continue;
@@ -3532,12 +3532,12 @@ static void do_gaussian_blur_effect_float_x(Sequence *seq,
float *gausstab_x;
gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x);
- for (i = 0; i < y; ++i) {
- for (j = 0; j < x; ++j) {
+ for (i = 0; i < y; i++) {
+ for (j = 0; j < x; j++) {
int out_index = INDEX(j, i);
float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float accum_weight = 0.0f;
- for (int current_x = j - size_x; current_x <= j + size_x; ++current_x) {
+ for (int current_x = j - size_x; current_x <= j + size_x; current_x++) {
if (current_x < 0 || current_x >= frame_width) {
/* Out of bounds. */
continue;
@@ -3573,12 +3573,12 @@ static void do_gaussian_blur_effect_float_y(Sequence *seq,
float *gausstab_y;
gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y);
- for (i = 0; i < y; ++i) {
- for (j = 0; j < x; ++j) {
+ for (i = 0; i < y; i++) {
+ for (j = 0; j < x; j++) {
int out_index = INDEX(j, i);
float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float accum_weight = 0.0f;
- for (int current_y = i - size_y; current_y <= i + size_y; ++current_y) {
+ for (int current_y = i - size_y; current_y <= i + size_y; current_y++) {
if (current_y < -start_line || current_y + start_line >= frame_height) {
/* Out of bounds. */
continue;
diff --git a/source/blender/blenkernel/intern/seqprefetch.c b/source/blender/blenkernel/intern/seqprefetch.c
new file mode 100644
index 00000000000..c1109347e76
--- /dev/null
+++ b/source/blender/blenkernel/intern/seqprefetch.c
@@ -0,0 +1,453 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_sequence_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_threads.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BKE_animsys.h"
+#include "BKE_library.h"
+#include "BKE_scene.h"
+#include "BKE_main.h"
+#include "BKE_context.h"
+#include "BKE_sequencer.h"
+#include "BKE_layer.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_query.h"
+
+typedef struct PrefetchJob {
+ struct PrefetchJob *next, *prev;
+
+ struct Main *bmain;
+ struct Scene *scene;
+ struct Scene *scene_eval;
+ struct Depsgraph *depsgraph;
+
+ ThreadMutex prefetch_suspend_mutex;
+ ThreadCondition prefetch_suspend_cond;
+
+ ListBase threads;
+
+ /* context */
+ struct SeqRenderData context;
+ struct SeqRenderData context_cpy;
+ struct ListBase *seqbasep;
+ struct ListBase *seqbasep_cpy;
+
+ /* prefetch area */
+ float cfra;
+ int num_frames_prefetched;
+
+ /* control */
+ bool running;
+ bool waiting;
+ bool stop;
+} PrefetchJob;
+
+static bool seq_prefetch_is_playing(Main *bmain)
+{
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ if (screen->animtimer) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool seq_prefetch_is_scrubbing(Main *bmain)
+{
+
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ if (screen->scrubbing) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static PrefetchJob *seq_prefetch_job_get(Scene *scene)
+{
+ if (scene && scene->ed) {
+ return scene->ed->prefetch_job;
+ }
+ return NULL;
+}
+
+static bool seq_prefetch_job_is_running(Scene *scene)
+{
+ PrefetchJob *pfjob = seq_prefetch_job_get(scene);
+
+ if (!pfjob) {
+ return false;
+ }
+
+ return pfjob->running;
+}
+
+static bool seq_prefetch_job_is_waiting(Scene *scene)
+{
+ PrefetchJob *pfjob = seq_prefetch_job_get(scene);
+
+ if (!pfjob) {
+ return false;
+ }
+
+ return pfjob->waiting;
+}
+
+/* for cache context swapping */
+Sequence *BKE_sequencer_prefetch_get_original_sequence(Sequence *seq, Scene *scene)
+{
+ Editing *ed = scene->ed;
+ ListBase *seqbase = &ed->seqbase;
+ Sequence *seq_orig = NULL;
+
+ for (seq_orig = (Sequence *)seqbase->first; seq_orig; seq_orig = seq_orig->next) {
+ if (strcmp(seq->name, seq_orig->name) == 0) {
+ break;
+ }
+ }
+ return seq_orig;
+}
+
+/* for cache context swapping */
+SeqRenderData *BKE_sequencer_prefetch_get_original_context(const SeqRenderData *context)
+{
+ PrefetchJob *pfjob = seq_prefetch_job_get(context->scene);
+
+ return &pfjob->context;
+}
+
+static bool seq_prefetch_is_cache_full(Scene *scene)
+{
+ PrefetchJob *pfjob = seq_prefetch_job_get(scene);
+
+ if (!BKE_sequencer_cache_is_full(pfjob->scene)) {
+ return false;
+ }
+
+ return BKE_sequencer_cache_recycle_item(pfjob->scene) == false;
+}
+
+void BKE_sequencer_prefetch_get_time_range(Scene *scene, int *start, int *end)
+{
+ PrefetchJob *pfjob = seq_prefetch_job_get(scene);
+
+ *start = pfjob->cfra;
+ *end = pfjob->cfra + pfjob->num_frames_prefetched;
+}
+
+static void seq_prefetch_free_depsgraph(PrefetchJob *pfjob)
+{
+ if (pfjob->depsgraph != NULL) {
+ DEG_graph_free(pfjob->depsgraph);
+ }
+ pfjob->depsgraph = NULL;
+ pfjob->scene_eval = NULL;
+}
+
+static void seq_prefetch_update_depsgraph(PrefetchJob *pfjob)
+{
+ DEG_evaluate_on_framechange(
+ pfjob->bmain, pfjob->depsgraph, pfjob->cfra + pfjob->num_frames_prefetched);
+}
+
+static void seq_prefetch_init_depsgraph(PrefetchJob *pfjob)
+{
+ Main *bmain = pfjob->bmain;
+ Scene *scene = pfjob->scene;
+ ViewLayer *view_layer = BKE_view_layer_default_render(scene);
+
+ pfjob->depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
+ DEG_debug_name_set(pfjob->depsgraph, "SEQUENCER PREFETCH");
+
+ /* Make sure there is a correct evaluated scene pointer. */
+ DEG_graph_build_for_render_pipeline(pfjob->depsgraph, pfjob->bmain, scene, view_layer);
+
+ /* Update immediately so we have proper evaluated scene. */
+ seq_prefetch_update_depsgraph(pfjob);
+
+ pfjob->scene_eval = DEG_get_evaluated_scene(pfjob->depsgraph);
+ pfjob->scene_eval->ed->cache_flag = 0;
+}
+
+static void seq_prefetch_update_area(PrefetchJob *pfjob)
+{
+ int cfra = pfjob->scene->r.cfra;
+
+ /* rebase */
+ if (cfra > pfjob->cfra) {
+ int delta = cfra - pfjob->cfra;
+ pfjob->cfra = cfra;
+ pfjob->num_frames_prefetched -= delta;
+
+ if (pfjob->num_frames_prefetched <= 1) {
+ pfjob->num_frames_prefetched = 1;
+ }
+ }
+
+ /* reset */
+ if (cfra < pfjob->cfra) {
+ pfjob->cfra = cfra;
+ pfjob->num_frames_prefetched = 1;
+ }
+}
+
+/* Use also to update scene and context changes */
+void BKE_sequencer_prefetch_stop(Scene *scene)
+{
+ PrefetchJob *pfjob;
+ pfjob = seq_prefetch_job_get(scene);
+
+ if (!pfjob) {
+ return;
+ }
+
+ pfjob->stop = true;
+
+ while (pfjob->running) {
+ BLI_condition_notify_one(&pfjob->prefetch_suspend_cond);
+ }
+}
+
+static void seq_prefetch_update_context(const SeqRenderData *context)
+{
+ PrefetchJob *pfjob;
+ pfjob = seq_prefetch_job_get(context->scene);
+
+ BKE_sequencer_new_render_data(pfjob->bmain,
+ pfjob->depsgraph,
+ pfjob->scene_eval,
+ context->rectx,
+ context->recty,
+ context->preview_render_size,
+ false,
+ &pfjob->context_cpy);
+ pfjob->context_cpy.is_prefetch_render = true;
+ pfjob->context_cpy.task_id = SEQ_TASK_PREFETCH_RENDER;
+
+ BKE_sequencer_new_render_data(pfjob->bmain,
+ pfjob->depsgraph,
+ pfjob->scene,
+ context->rectx,
+ context->recty,
+ context->preview_render_size,
+ false,
+ &pfjob->context);
+ pfjob->context.is_prefetch_render = false;
+
+ /* Same ID as prefetch context, because context will be swapped, but we still
+ * want to assign this ID to cache entries created in this thread.
+ * This is to allow "temp cache" work correctly for both threads.
+ */
+ pfjob->context.task_id = SEQ_TASK_PREFETCH_RENDER;
+}
+
+static void seq_prefetch_update_scene(Scene *scene)
+{
+ PrefetchJob *pfjob = seq_prefetch_job_get(scene);
+
+ if (!pfjob) {
+ return;
+ }
+
+ seq_prefetch_free_depsgraph(pfjob);
+ seq_prefetch_init_depsgraph(pfjob);
+}
+
+static void seq_prefetch_resume(Scene *scene)
+{
+ PrefetchJob *pfjob = seq_prefetch_job_get(scene);
+
+ if (pfjob && pfjob->waiting) {
+ BLI_condition_notify_one(&pfjob->prefetch_suspend_cond);
+ }
+}
+
+void BKE_sequencer_prefetch_free(Scene *scene)
+{
+ PrefetchJob *pfjob = seq_prefetch_job_get(scene);
+ if (!pfjob) {
+ return;
+ }
+
+ BKE_sequencer_prefetch_stop(scene);
+
+ BLI_threadpool_remove(&pfjob->threads, pfjob);
+ BLI_threadpool_end(&pfjob->threads);
+ BLI_mutex_end(&pfjob->prefetch_suspend_mutex);
+ BLI_condition_end(&pfjob->prefetch_suspend_cond);
+ seq_prefetch_free_depsgraph(pfjob);
+ MEM_freeN(pfjob);
+ scene->ed->prefetch_job = NULL;
+}
+
+static void *seq_prefetch_frames(void *job)
+{
+ PrefetchJob *pfjob = (PrefetchJob *)job;
+
+ /* set to NULL before return! */
+ pfjob->scene_eval->ed->prefetch_job = pfjob;
+
+ while (pfjob->cfra + pfjob->num_frames_prefetched < pfjob->scene->r.efra) {
+ BKE_animsys_evaluate_all_animation(pfjob->context_cpy.bmain,
+ pfjob->context_cpy.depsgraph,
+ pfjob->context_cpy.scene,
+ pfjob->cfra + pfjob->num_frames_prefetched);
+ seq_prefetch_update_depsgraph(pfjob);
+
+ ImBuf *ibuf = BKE_sequencer_give_ibuf(
+ &pfjob->context_cpy, pfjob->cfra + pfjob->num_frames_prefetched, 0);
+ BKE_sequencer_cache_free_temp_cache(
+ pfjob->scene, pfjob->context.task_id, pfjob->cfra + pfjob->num_frames_prefetched);
+ IMB_freeImBuf(ibuf);
+
+ /* suspend thread */
+ BLI_mutex_lock(&pfjob->prefetch_suspend_mutex);
+ while ((seq_prefetch_is_cache_full(pfjob->scene) || seq_prefetch_is_scrubbing(pfjob->bmain)) &&
+ pfjob->scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE && !pfjob->stop) {
+ pfjob->waiting = true;
+ BLI_condition_wait(&pfjob->prefetch_suspend_cond, &pfjob->prefetch_suspend_mutex);
+ seq_prefetch_update_area(pfjob);
+ }
+ pfjob->waiting = false;
+ BLI_mutex_unlock(&pfjob->prefetch_suspend_mutex);
+
+ /* Avoid "collision" with main thread, but make sure to fetch at least few frames */
+ if (pfjob->num_frames_prefetched > 5 &&
+ (pfjob->cfra + pfjob->num_frames_prefetched - pfjob->scene->r.cfra) < 2) {
+ break;
+ }
+
+ if (!(pfjob->scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE) || pfjob->stop) {
+ break;
+ }
+
+ seq_prefetch_update_area(pfjob);
+ pfjob->num_frames_prefetched++;
+ }
+
+ BKE_sequencer_cache_free_temp_cache(
+ pfjob->scene, pfjob->context.task_id, pfjob->cfra + pfjob->num_frames_prefetched);
+ pfjob->running = false;
+ pfjob->scene_eval->ed->prefetch_job = NULL;
+
+ return 0;
+}
+
+static PrefetchJob *seq_prefetch_start(const SeqRenderData *context, float cfra)
+{
+ PrefetchJob *pfjob;
+ pfjob = seq_prefetch_job_get(context->scene);
+
+ if (!pfjob) {
+ if (context->scene->ed) {
+ pfjob = (PrefetchJob *)MEM_callocN(sizeof(PrefetchJob), "PrefetchJob");
+ context->scene->ed->prefetch_job = pfjob;
+
+ BLI_threadpool_init(&pfjob->threads, seq_prefetch_frames, 1);
+ BLI_mutex_init(&pfjob->prefetch_suspend_mutex);
+ BLI_condition_init(&pfjob->prefetch_suspend_cond);
+
+ pfjob->bmain = context->bmain;
+
+ pfjob->scene = context->scene;
+ seq_prefetch_init_depsgraph(pfjob);
+ }
+ }
+ seq_prefetch_update_scene(context->scene);
+ seq_prefetch_update_context(context);
+
+ pfjob->cfra = cfra;
+ pfjob->num_frames_prefetched = 1;
+
+ pfjob->waiting = false;
+ pfjob->stop = false;
+ pfjob->running = true;
+
+ if (&pfjob->threads) {
+ BLI_threadpool_remove(&pfjob->threads, pfjob);
+ }
+ BLI_threadpool_insert(&pfjob->threads, pfjob);
+
+ return pfjob;
+}
+
+/* Start or resume prefetching*/
+void BKE_sequencer_prefetch_start(const SeqRenderData *context, float cfra, float cost)
+{
+ Scene *scene = context->scene;
+ Editing *ed = scene->ed;
+ bool has_strips = (bool)ed->seqbasep->first;
+
+ if (!context->is_prefetch_render && !context->is_proxy_render) {
+ bool playing = seq_prefetch_is_playing(context->bmain);
+ bool scrubbing = seq_prefetch_is_scrubbing(context->bmain);
+ bool running = seq_prefetch_job_is_running(scene);
+ seq_prefetch_resume(scene);
+ /* conditions to start:
+ * prefetch enabled, prefetch not running, not scrubbing,
+ * not playing and rendering-expensive footage, cache storage enabled, has strips to render
+ */
+ if ((ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE) && !running && !scrubbing &&
+ !(playing && cost > 0.9) && ed->cache_flag & SEQ_CACHE_ALL_TYPES && has_strips) {
+
+ seq_prefetch_start(context, cfra);
+ }
+ }
+}
+
+bool BKE_sequencer_prefetch_need_redraw(Main *bmain, Scene *scene)
+{
+ bool playing = seq_prefetch_is_playing(bmain);
+ bool scrubbing = seq_prefetch_is_scrubbing(bmain);
+ bool running = seq_prefetch_job_is_running(scene);
+ bool suspended = seq_prefetch_job_is_waiting(scene);
+
+ /* force redraw, when prefetching and using cache view. */
+ if (running && !playing && !suspended && scene->ed->cache_flag & SEQ_CACHE_VIEW_ENABLE) {
+ return true;
+ }
+ /* Sometimes scrubbing flag is set when not scrubbing. In that case I want to catch "event" of
+ * stopping scrubbing */
+ if (scrubbing) {
+ return true;
+ }
+ return false;
+}
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index b29e07bb56d..3e88db787ee 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -112,6 +112,8 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr
static int seq_num_files(Scene *scene, char views_format, const bool is_multiview);
static void seq_anim_add_suffix(Scene *scene, struct anim *anim, const int view_id);
+static ThreadMutex seq_render_mutex = BLI_MUTEX_INITIALIZER;
+
/* **** XXX ******** */
#define SELECT 1
ListBase seqbase_clipboard;
@@ -483,6 +485,7 @@ void BKE_sequencer_editing_free(Scene *scene, const bool do_id_user)
return;
}
+ BKE_sequencer_prefetch_free(scene);
BKE_sequencer_cache_destruct(scene);
SEQ_BEGIN (ed, seq) {
@@ -492,7 +495,6 @@ void BKE_sequencer_editing_free(Scene *scene, const bool do_id_user)
SEQ_END;
BLI_freelistN(&ed->metastack);
-
MEM_freeN(ed);
scene->ed = NULL;
@@ -635,6 +637,8 @@ void BKE_sequencer_new_render_data(Main *bmain,
r_context->is_proxy_render = false;
r_context->view_id = 0;
r_context->gpu_offscreen = NULL;
+ r_context->task_id = SEQ_TASK_MAIN_RENDER;
+ r_context->is_prefetch_render = false;
}
/* ************************* iterator ************************** */
@@ -3534,7 +3538,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
}
/* opengl offscreen render */
- depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ depsgraph = BKE_scene_get_depsgraph(context->bmain, scene, view_layer, true);
BKE_scene_graph_update_for_newframe(depsgraph, context->bmain);
ibuf = sequencer_view3d_cb(
/* set for OpenGL render (NULL when scrubbing) */
@@ -4092,18 +4096,29 @@ ImBuf *BKE_sequencer_give_ibuf(const SeqRenderData *context, float cfra, int cha
out = BKE_sequencer_cache_get(context, seq_arr[count - 1], cfra, SEQ_CACHE_STORE_FINAL_OUT);
}
- BKE_sequencer_cache_free_temp_cache(context->scene, 0, cfra);
+ BKE_sequencer_cache_free_temp_cache(context->scene, context->task_id, cfra);
clock_t begin = seq_estimate_render_cost_begin();
float cost = 0;
if (count && !out) {
+ BLI_mutex_lock(&seq_render_mutex);
out = seq_render_strip_stack(context, &state, seqbasep, cfra, chanshown);
cost = seq_estimate_render_cost_end(context->scene, begin);
- BKE_sequencer_cache_put_if_possible(
- context, seq_arr[count - 1], cfra, SEQ_CACHE_STORE_FINAL_OUT, out, cost);
+
+ if (context->is_prefetch_render) {
+ BKE_sequencer_cache_put(
+ context, seq_arr[count - 1], cfra, SEQ_CACHE_STORE_FINAL_OUT, out, cost);
+ }
+ else {
+ BKE_sequencer_cache_put_if_possible(
+ context, seq_arr[count - 1], cfra, SEQ_CACHE_STORE_FINAL_OUT, out, cost);
+ }
+ BLI_mutex_unlock(&seq_render_mutex);
}
+ BKE_sequencer_prefetch_start(context, cfra, cost);
+
return out;
}
@@ -4334,6 +4349,8 @@ static void sequence_invalidate_cache(Scene *scene,
}
sequence_do_invalidate_dependent(scene, seq, &ed->seqbase);
+ DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
+ BKE_sequencer_prefetch_stop(scene);
}
void BKE_sequence_invalidate_cache_raw(Scene *scene, Sequence *seq)
@@ -4419,6 +4436,7 @@ void BKE_sequencer_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
Sequence *seq;
BKE_sequencer_cache_cleanup(scene);
+ BKE_sequencer_prefetch_stop(scene);
for (seq = seqbase->first; seq; seq = seq->next) {
if (for_render && CFRA >= seq->startdisp && CFRA <= seq->enddisp) {
@@ -4933,7 +4951,7 @@ static bool sequencer_refresh_sound_length_recursive(Main *bmain, Scene *scene,
changed = true;
}
}
- else if (seq->type == SEQ_TYPE_SOUND_RAM) {
+ else if (seq->type == SEQ_TYPE_SOUND_RAM && seq->sound) {
const float length = BKE_sound_get_length(bmain, seq->sound);
int old = seq->len;
float fac;
@@ -5526,7 +5544,7 @@ Sequence *BKE_sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoad
Strip *strip;
seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_IMAGE);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+ seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
/* basic defaults */
seq->len = seq_load->len ? seq_load->len : 1;
@@ -5685,7 +5703,9 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad
seq->views_format = seq_load->views_format;
}
seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+
+ seq->type = SEQ_TYPE_MOVIE;
+ seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
for (i = 0; i < totfiles; i++) {
if (anim_arr[i]) {
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index 9b9fd33f52d..797ae0f0a8a 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -39,6 +39,7 @@
#include "BLI_task.h"
#include "BLI_math_solvers.h"
+#include "BKE_context.h"
#include "BKE_shrinkwrap.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_DerivedMesh.h"
@@ -1408,7 +1409,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd,
Object *ob_target = DEG_get_evaluated_object(ctx->depsgraph, smd->target);
calc.target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false);
- /* TODO there might be several "bugs" on non-uniform scales matrixs
+ /* TODO there might be several "bugs" with non-uniform scales matrices
* because it will no longer be nearest surface, not sphere projection
* because space has been deformed */
BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob, ob_target);
@@ -1480,3 +1481,62 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd,
ss_mesh->release(ss_mesh);
}
}
+
+void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C,
+ Object *ob_source,
+ Object *ob_target)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ struct Scene *sce = CTX_data_scene(C);
+ ShrinkwrapModifierData ssmd = {0};
+ ModifierEvalContext ctx = {depsgraph, ob_source, 0};
+ int totvert;
+
+ ssmd.target = ob_target;
+ ssmd.shrinkType = MOD_SHRINKWRAP_NEAREST_SURFACE;
+ ssmd.shrinkMode = MOD_SHRINKWRAP_ON_SURFACE;
+ ssmd.keepDist = 0.0f;
+
+ Mesh *src_me = ob_source->data;
+ float(*vertexCos)[3] = BKE_mesh_vert_coords_alloc(src_me, &totvert);
+
+ shrinkwrapModifier_deform(&ssmd, &ctx, sce, ob_source, src_me, NULL, -1, vertexCos, totvert);
+
+ BKE_mesh_vert_coords_apply(src_me, vertexCos);
+
+ MEM_freeN(vertexCos);
+}
+
+void BKE_shrinkwrap_remesh_target_project(Mesh *src_me, Mesh *target_me, Object *ob_target)
+{
+ ShrinkwrapModifierData ssmd = {0};
+ int totvert;
+
+ ssmd.target = ob_target;
+ ssmd.shrinkType = MOD_SHRINKWRAP_TARGET_PROJECT;
+ ssmd.shrinkMode = MOD_SHRINKWRAP_ON_SURFACE;
+ ssmd.keepDist = 0.0f;
+
+ float(*vertexCos)[3] = BKE_mesh_vert_coords_alloc(src_me, &totvert);
+
+ ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData;
+
+ calc.smd = &ssmd;
+ calc.numVerts = src_me->totvert;
+ calc.vertexCos = vertexCos;
+ calc.vgroup = -1;
+ calc.target = target_me;
+ calc.keepDist = ssmd.keepDist;
+ BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob_target, ob_target);
+
+ ShrinkwrapTreeData tree;
+ if (BKE_shrinkwrap_init_tree(&tree, calc.target, ssmd.shrinkType, ssmd.shrinkMode, false)) {
+ calc.tree = &tree;
+ TIMEIT_BENCH(shrinkwrap_calc_nearest_surface_point(&calc), deform_surface);
+ BKE_shrinkwrap_free_tree(&tree);
+ }
+
+ BKE_mesh_vert_coords_apply(src_me, vertexCos);
+
+ MEM_freeN(vertexCos);
+}
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 74873db179d..e6c414b92da 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -3352,14 +3352,16 @@ struct Mesh *smokeModifier_do(
if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain &&
smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN && smd->domain->base_res[0]) {
result = createDomainGeometry(smd->domain, ob);
+ BKE_mesh_copy_settings(result, me);
}
else {
result = BKE_mesh_copy_for_eval(me, false);
}
- /* XXX This is really not a nice hack, but until root of the problem is understood,
- * this should be an acceptable workaround I think.
- * See T58492 for details on the issue. */
- result->texflag |= ME_AUTOSPACE;
+
+ /* Smoke simulation needs a texture space relative to the adaptive domain bounds, not the
+ * original mesh. So recompute it at this point in the modifier stack. See T58492. */
+ BKE_mesh_texspace_calc(result);
+
return result;
}
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index d3b72fb295d..b56403dfb6d 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -1049,8 +1049,8 @@ static int sb_detect_aabb_collisionCached(float UNUSED(force[3]),
/* +++ the face external section*/
static int sb_detect_face_pointCached(float face_v1[3],
- float face_v2[3],
- float face_v3[3],
+ const float face_v2[3],
+ const float face_v3[3],
float *damp,
float force[3],
struct Object *vertexowner,
@@ -1147,8 +1147,8 @@ static int sb_detect_face_pointCached(float face_v1[3],
}
static int sb_detect_face_collisionCached(float face_v1[3],
- float face_v2[3],
- float face_v3[3],
+ const float face_v2[3],
+ const float face_v3[3],
float *damp,
float force[3],
struct Object *vertexowner,
@@ -1326,7 +1326,7 @@ static void scan_for_ext_face_forces(Object *ob, float timenow)
/* +++ the spring external section*/
static int sb_detect_edge_collisionCached(float edge_v1[3],
- float edge_v2[3],
+ const float edge_v2[3],
float *damp,
float force[3],
struct Object *vertexowner,
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index c7a0d65a2a9..46a74e25b8b 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -21,6 +21,7 @@
#include "DNA_object_types.h"
#include "DNA_sound_types.h"
#include "DNA_speaker_types.h"
+#include "DNA_defaults.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -34,18 +35,7 @@ void BKE_speaker_init(Speaker *spk)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(spk, id));
- spk->attenuation = 1.0f;
- spk->cone_angle_inner = 360.0f;
- spk->cone_angle_outer = 360.0f;
- spk->cone_volume_outer = 1.0f;
- spk->distance_max = FLT_MAX;
- spk->distance_reference = 1.0f;
- spk->flag = 0;
- spk->pitch = 1.0f;
- spk->sound = NULL;
- spk->volume = 1.0f;
- spk->volume_max = 1.0f;
- spk->volume_min = 0.0f;
+ MEMCPY_STRUCT_AFTER(spk, DNA_struct_default_get(Speaker), id);
}
void *BKE_speaker_add(Main *bmain, const char *name)
diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c
index 6e83f5d75e2..ff92704e2d1 100644
--- a/source/blender/blenkernel/intern/studiolight.c
+++ b/source/blender/blenkernel/intern/studiolight.c
@@ -46,13 +46,16 @@
#include "MEM_guardedalloc.h"
+#include "intern/openexr/openexr_multi.h"
+
/* Statics */
static ListBase studiolights;
static int last_studiolight_id = 0;
#define STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE 96
#define STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT 32
#define STUDIOLIGHT_IRRADIANCE_EQUIRECT_WIDTH (STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT * 2)
-
+#define STUDIOLIGHT_PASSNAME_DIFFUSE "diffuse"
+#define STUDIOLIGHT_PASSNAME_SPECULAR "specular"
/*
* The method to calculate the irradiance buffers
* The irradiance buffer is only shown in the background when in LookDev.
@@ -152,6 +155,10 @@ static void studiolight_free(struct StudioLight *sl)
GPU_TEXTURE_SAFE_FREE(sl->equirect_irradiance_gputexture);
IMB_SAFE_FREE(sl->equirect_radiance_buffer);
IMB_SAFE_FREE(sl->equirect_irradiance_buffer);
+ GPU_TEXTURE_SAFE_FREE(sl->matcap_diffuse.gputexture);
+ GPU_TEXTURE_SAFE_FREE(sl->matcap_specular.gputexture);
+ IMB_SAFE_FREE(sl->matcap_diffuse.ibuf);
+ IMB_SAFE_FREE(sl->matcap_specular.ibuf);
MEM_SAFE_FREE(sl->path_irr_cache);
MEM_SAFE_FREE(sl->path_sh_cache);
MEM_SAFE_FREE(sl);
@@ -342,72 +349,232 @@ static void cube_face_uv_to_direction(float r_dir[3], float x, float y, int face
normalize_v3(r_dir);
}
+typedef struct MultilayerConvertContext {
+ int num_diffuse_channels;
+ float *diffuse_pass;
+ int num_specular_channels;
+ float *specular_pass;
+} MultilayerConvertContext;
+
+static void *studiolight_multilayer_addview(void *UNUSED(base), const char *UNUSED(view_name))
+{
+ return NULL;
+}
+static void *studiolight_multilayer_addlayer(void *base, const char *UNUSED(layer_name))
+{
+ return base;
+}
+
+/* Convert a multilayer pass to ImBuf channel 4 float buffer.
+ * NOTE: Parameter rect will become invalid. Do not use rect after calling this
+ * function */
+static float *studiolight_multilayer_convert_pass(ImBuf *ibuf,
+ float *rect,
+ const unsigned int channels)
+{
+ if (channels == 4) {
+ return rect;
+ }
+ else {
+ float *new_rect = MEM_callocN(sizeof(float[4]) * ibuf->x * ibuf->y, __func__);
+
+ IMB_buffer_float_from_float(new_rect,
+ rect,
+ channels,
+ IB_PROFILE_LINEAR_RGB,
+ IB_PROFILE_LINEAR_RGB,
+ false,
+ ibuf->x,
+ ibuf->y,
+ ibuf->x,
+ ibuf->x);
+
+ MEM_freeN(rect);
+ return new_rect;
+ }
+}
+
+static void studiolight_multilayer_addpass(void *base,
+ void *UNUSED(lay),
+ const char *pass_name,
+ float *rect,
+ int num_channels,
+ const char *UNUSED(chan_id),
+ const char *UNUSED(view_name))
+{
+ MultilayerConvertContext *ctx = base;
+ /* NOTE: This function must free pass pixels data if it is not used, this
+ * is how IMB_exr_multilayer_convert() is working. */
+ /* If we've found a first combined pass, skip all the rest ones. */
+ if (STREQ(pass_name, STUDIOLIGHT_PASSNAME_DIFFUSE)) {
+ ctx->diffuse_pass = rect;
+ ctx->num_diffuse_channels = num_channels;
+ }
+ else if (STREQ(pass_name, STUDIOLIGHT_PASSNAME_SPECULAR)) {
+ ctx->specular_pass = rect;
+ ctx->num_specular_channels = num_channels;
+ }
+ else {
+ MEM_freeN(rect);
+ }
+}
+
static void studiolight_load_equirect_image(StudioLight *sl)
{
if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
- ImBuf *ibuf = NULL;
- ibuf = IMB_loadiffname(sl->path, 0, NULL);
- if (ibuf == NULL) {
- float *colbuf = MEM_mallocN(sizeof(float[4]), __func__);
- copy_v4_fl4(colbuf, 1.0f, 0.0f, 1.0f, 1.0f);
- ibuf = IMB_allocFromBuffer(NULL, colbuf, 1, 1);
+ ImBuf *ibuf = IMB_loadiffname(sl->path, IB_multilayer, NULL);
+ ImBuf *specular_ibuf = NULL;
+ ImBuf *diffuse_ibuf = NULL;
+ const bool failed = (ibuf == NULL);
+
+ if (ibuf) {
+ if (ibuf->ftype == IMB_FTYPE_OPENEXR && ibuf->userdata) {
+ /* the read file is a multilayered openexr file (userdata != NULL)
+ * This file is currently only supported for MATCAPS where
+ * the first found 'diffuse' pass will be used for diffuse lighting
+ * and the first found 'specular' pass will be used for specular lighting */
+ MultilayerConvertContext ctx = {0};
+ IMB_exr_multilayer_convert(ibuf->userdata,
+ &ctx,
+ &studiolight_multilayer_addview,
+ &studiolight_multilayer_addlayer,
+ &studiolight_multilayer_addpass);
+
+ /* `ctx.diffuse_pass` and `ctx.specular_pass` can be freed inside
+ * `studiolight_multilayer_convert_pass` when conversion happens.
+ * When not converted we move the ownership of the buffer to the
+ * `converted_pass`. We only need to free `converted_pass` as it holds
+ * the unmodified allocation from the `ctx.*_pass` or the converted data.
+ */
+ if (ctx.diffuse_pass != NULL) {
+ float *converted_pass = studiolight_multilayer_convert_pass(
+ ibuf, ctx.diffuse_pass, ctx.num_diffuse_channels);
+ diffuse_ibuf = IMB_allocFromBuffer(
+ NULL, converted_pass, ibuf->x, ibuf->y, ctx.num_diffuse_channels);
+ MEM_freeN(converted_pass);
+ }
+
+ if (ctx.specular_pass != NULL) {
+ float *converted_pass = studiolight_multilayer_convert_pass(
+ ibuf, ctx.specular_pass, ctx.num_specular_channels);
+ specular_ibuf = IMB_allocFromBuffer(
+ NULL, converted_pass, ibuf->x, ibuf->y, ctx.num_specular_channels);
+ MEM_freeN(converted_pass);
+ }
+
+ IMB_exr_close(ibuf->userdata);
+ ibuf->userdata = NULL;
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
+ else {
+ /* read file is an single layer openexr file or the read file isn't
+ * an openexr file */
+ IMB_float_from_rect(ibuf);
+ diffuse_ibuf = ibuf;
+ ibuf = NULL;
+ }
+ }
+
+ if (diffuse_ibuf == NULL) {
+ /* Create 1x1 diffuse buffer, in case image failed to load or if there was
+ * only a specular pass in the multilayer file or no passes were found. */
+ const float black[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ const float magenta[4] = {1.0f, 0.0f, 1.0f, 1.0f};
+ diffuse_ibuf = IMB_allocFromBuffer(
+ NULL, (failed || (specular_ibuf == NULL)) ? magenta : black, 1, 1, 4);
+ }
+
+ if ((sl->flag & STUDIOLIGHT_TYPE_MATCAP)) {
+ sl->matcap_diffuse.ibuf = diffuse_ibuf;
+ sl->matcap_specular.ibuf = specular_ibuf;
+ if (specular_ibuf != NULL) {
+ sl->flag |= STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS;
+ }
+ }
+ else {
+ sl->equirect_radiance_buffer = diffuse_ibuf;
+ if (specular_ibuf != NULL) {
+ IMB_freeImBuf(specular_ibuf);
+ }
}
- IMB_float_from_rect(ibuf);
- sl->equirect_radiance_buffer = ibuf;
}
+
sl->flag |= STUDIOLIGHT_EXTERNAL_IMAGE_LOADED;
}
static void studiolight_create_equirect_radiance_gputexture(StudioLight *sl)
{
if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
- char error[256];
BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
ImBuf *ibuf = sl->equirect_radiance_buffer;
- if (sl->flag & STUDIOLIGHT_TYPE_MATCAP) {
- float *gpu_matcap_3components = MEM_callocN(sizeof(float[3]) * ibuf->x * ibuf->y, __func__);
+ sl->equirect_radiance_gputexture = GPU_texture_create_2d(
+ ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, NULL);
+ GPUTexture *tex = sl->equirect_radiance_gputexture;
+ GPU_texture_bind(tex, 0);
+ GPU_texture_filter_mode(tex, true);
+ GPU_texture_wrap_mode(tex, true);
+ GPU_texture_unbind(tex);
+ }
+ sl->flag |= STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE;
+}
- float(*offset4)[4] = (float(*)[4])ibuf->rect_float;
- float(*offset3)[3] = (float(*)[3])gpu_matcap_3components;
- for (int i = 0; i < ibuf->x * ibuf->y; i++, offset4++, offset3++) {
- copy_v3_v3(*offset3, *offset4);
- }
+static void studiolight_create_matcap_gputexture(StudioLightImage *sli)
+{
+ BLI_assert(sli->ibuf);
+ ImBuf *ibuf = sli->ibuf;
+ float *gpu_matcap_3components = MEM_callocN(sizeof(float[3]) * ibuf->x * ibuf->y, __func__);
+
+ float(*offset4)[4] = (float(*)[4])ibuf->rect_float;
+ float(*offset3)[3] = (float(*)[3])gpu_matcap_3components;
+ for (int i = 0; i < ibuf->x * ibuf->y; i++, offset4++, offset3++) {
+ copy_v3_v3(*offset3, *offset4);
+ }
+
+ sli->gputexture = GPU_texture_create_nD(ibuf->x,
+ ibuf->y,
+ 0,
+ 2,
+ gpu_matcap_3components,
+ GPU_R11F_G11F_B10F,
+ GPU_DATA_FLOAT,
+ 0,
+ false,
+ NULL);
+ MEM_SAFE_FREE(gpu_matcap_3components);
+}
- sl->equirect_radiance_gputexture = GPU_texture_create_nD(ibuf->x,
- ibuf->y,
- 0,
- 2,
- gpu_matcap_3components,
- GPU_R11F_G11F_B10F,
- GPU_DATA_FLOAT,
- 0,
- false,
- error);
-
- MEM_SAFE_FREE(gpu_matcap_3components);
+static void studiolight_create_matcap_diffuse_gputexture(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ if (sl->flag & STUDIOLIGHT_TYPE_MATCAP) {
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+ studiolight_create_matcap_gputexture(&sl->matcap_diffuse);
}
- else {
- sl->equirect_radiance_gputexture = GPU_texture_create_2d(
- ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error);
- GPUTexture *tex = sl->equirect_radiance_gputexture;
- GPU_texture_bind(tex, 0);
- GPU_texture_filter_mode(tex, true);
- GPU_texture_wrap_mode(tex, true);
- GPU_texture_unbind(tex);
+ }
+ sl->flag |= STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE;
+}
+static void studiolight_create_matcap_specular_gputexture(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ if (sl->flag & STUDIOLIGHT_TYPE_MATCAP) {
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+ if (sl->matcap_specular.ibuf) {
+ studiolight_create_matcap_gputexture(&sl->matcap_specular);
+ }
}
}
- sl->flag |= STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE;
+ sl->flag |= STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE;
}
static void studiolight_create_equirect_irradiance_gputexture(StudioLight *sl)
{
if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
- char error[256];
BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECT_IRRADIANCE_IMAGE_CALCULATED);
ImBuf *ibuf = sl->equirect_irradiance_buffer;
sl->equirect_irradiance_gputexture = GPU_texture_create_2d(
- ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error);
+ ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, NULL);
GPUTexture *tex = sl->equirect_irradiance_gputexture;
GPU_texture_bind(tex, 0);
GPU_texture_filter_mode(tex, true);
@@ -457,32 +624,32 @@ static void studiolight_calculate_radiance_cubemap_buffers(StudioLight *sl)
/* front */
studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 2, 1, 1, -1, 1);
sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS] = IMB_allocFromBuffer(
- NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, 4);
/* back */
studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 2, 1, 1, 1, -1);
sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG] = IMB_allocFromBuffer(
- NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, 4);
/* left */
studiolight_calculate_radiance_buffer(ibuf, colbuf, 2, 1, 0, 1, -1, 1);
sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS] = IMB_allocFromBuffer(
- NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, 4);
/* right */
studiolight_calculate_radiance_buffer(ibuf, colbuf, 2, 1, 0, -1, -1, -1);
sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG] = IMB_allocFromBuffer(
- NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, 4);
/* top */
studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 1, 2, -1, -1, 1);
sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG] = IMB_allocFromBuffer(
- NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, 4);
/* bottom */
studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 1, 2, 1, -1, -1);
sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS] = IMB_allocFromBuffer(
- NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, 4);
#if 0
IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS],
@@ -595,7 +762,7 @@ static void studiolight_spherical_harmonics_calculate_coefficients(StudioLight *
/* The sum of solid angle should be equal to the solid angle of the sphere (4 PI),
* so normalize in order to make our weightAccum exactly match 4 PI. */
- for (int i = 0; i < STUDIOLIGHT_SH_COEFS_LEN; ++i) {
+ for (int i = 0; i < STUDIOLIGHT_SH_COEFS_LEN; i++) {
mul_v3_fl(sh[i], M_PI * 4.0f / weight_accum);
}
}
@@ -603,7 +770,8 @@ static void studiolight_spherical_harmonics_calculate_coefficients(StudioLight *
/* Take monochrome SH as input */
static float studiolight_spherical_harmonics_lambda_get(float *sh, float max_laplacian)
{
- /* From Peter-Pike Sloan's Stupid SH Tricks http://www.ppsloan.org/publications/StupidSH36.pdf */
+ /* From Peter-Pike Sloan's Stupid SH Tricks http://www.ppsloan.org/publications/StupidSH36.pdf
+ */
float table_l[STUDIOLIGHT_SH_BANDS];
float table_b[STUDIOLIGHT_SH_BANDS];
@@ -633,11 +801,11 @@ static float studiolight_spherical_harmonics_lambda_get(float *sh, float max_lap
}
const int no_iterations = 10000000;
- for (int i = 0; i < no_iterations; ++i) {
+ for (int i = 0; i < no_iterations; i++) {
float f = 0.0f;
float fd = 0.0f;
- for (int level = 1; level < STUDIOLIGHT_SH_BANDS; ++level) {
+ for (int level = 1; level < STUDIOLIGHT_SH_BANDS; level++) {
f += table_l[level] * table_b[level] / SQUARE(1.0f + lambda * table_l[level]);
fd += (2.0f * SQUARE(table_l[level]) * table_b[level]) /
CUBE(1.0f + lambda * table_l[level]);
@@ -714,13 +882,12 @@ BLI_INLINE void studiolight_spherical_harmonics_eval(StudioLight *sl,
{
#if STUDIOLIGHT_SH_BANDS == 2
float(*sh)[3] = (float(*)[3])sl->spherical_harmonics_coefs;
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
color[i] = studiolight_spherical_harmonics_geomerics_eval(
normal, sh[0][i], sh[1][i], sh[2][i], sh[3][i]);
}
return;
#else
-
/* L0 */
mul_v3_v3fl(color, sl->spherical_harmonics_coefs[0], 0.282095f);
# if STUDIOLIGHT_SH_BANDS > 1 /* L1 */
@@ -779,7 +946,7 @@ BLI_INLINE void studiolight_spherical_harmonics_eval(StudioLight *sl,
/* This modify the radiance into irradiance. */
static void studiolight_spherical_harmonics_apply_band_factors(StudioLight *sl, float (*sh)[3])
{
- static float sl_sh_band_factors[5] = {
+ static const float sl_sh_band_factors[5] = {
1.0f,
2.0f / 3.0f,
1.0f / 4.0f,
@@ -907,7 +1074,7 @@ static float wrapped_lighting(float NL, float w)
static float blinn_specular(const float L[3],
const float I[3],
const float N[3],
- float R[3],
+ const float R[3],
float NL,
float roughness,
float wrap)
@@ -951,7 +1118,7 @@ static void studiolight_lights_eval(StudioLight *sl, float color[3], const float
copy_v3_v3(spec_light, sl->light_ambient);
reflect_v3_v3v3(R, I, N);
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
SolidLight *light = &sl->light[i];
if (light->flag) {
/* Diffuse lighting */
@@ -1045,7 +1212,8 @@ static void studiolight_calculate_irradiance_equirect_image(StudioLight *sl)
sl->equirect_irradiance_buffer = IMB_allocFromBuffer(NULL,
colbuf,
STUDIOLIGHT_IRRADIANCE_EQUIRECT_WIDTH,
- STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT);
+ STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT,
+ 4);
MEM_freeN(colbuf);
#ifdef STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
@@ -1196,7 +1364,8 @@ static void studiolight_matcap_preview(uint *icon_buffer, StudioLight *sl, bool
{
BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
- ImBuf *ibuf = sl->equirect_radiance_buffer;
+ ImBuf *diffuse_buffer = sl->matcap_diffuse.ibuf;
+ ImBuf *specular_buffer = sl->matcap_specular.ibuf;
ITER_PIXELS (uint, icon_buffer, 1, STUDIOLIGHT_ICON_SIZE, STUDIOLIGHT_ICON_SIZE) {
float dy = RESCALE_COORD(y);
@@ -1206,7 +1375,15 @@ static void studiolight_matcap_preview(uint *icon_buffer, StudioLight *sl, bool
}
float color[4];
- nearest_interpolation_color(ibuf, NULL, color, dx * ibuf->x - 1.0f, dy * ibuf->y - 1.0f);
+ float u = dx * diffuse_buffer->x - 1.0f;
+ float v = dy * diffuse_buffer->y - 1.0f;
+ nearest_interpolation_color(diffuse_buffer, NULL, color, u, v);
+
+ if (specular_buffer) {
+ float specular[4];
+ nearest_interpolation_color(specular_buffer, NULL, specular, u, v);
+ add_v3_v3(color, specular);
+ }
uint alphamask = alpha_circle_mask(dx, dy, 0.5f - texel_size[0], 0.5f);
@@ -1303,9 +1480,9 @@ void BKE_studiolight_default(SolidLight lights[4], float light_ambient[4])
void BKE_studiolight_init(void)
{
/* Add default studio light */
- StudioLight *sl = studiolight_create(STUDIOLIGHT_INTERNAL |
- STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED |
- STUDIOLIGHT_TYPE_STUDIO);
+ StudioLight *sl = studiolight_create(
+ STUDIOLIGHT_INTERNAL | STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED |
+ STUDIOLIGHT_TYPE_STUDIO | STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS);
BLI_strncpy(sl->name, "Default", FILE_MAXFILE);
BLI_addtail(&studiolights, sl);
@@ -1317,7 +1494,8 @@ void BKE_studiolight_init(void)
if (!BKE_appdir_app_is_portable_install()) {
studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES,
STUDIOLIGHT_LIGHTS_FOLDER,
- STUDIOLIGHT_TYPE_STUDIO | STUDIOLIGHT_USER_DEFINED);
+ STUDIOLIGHT_TYPE_STUDIO | STUDIOLIGHT_USER_DEFINED |
+ STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS);
studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES,
STUDIOLIGHT_WORLD_FOLDER,
STUDIOLIGHT_TYPE_WORLD | STUDIOLIGHT_USER_DEFINED);
@@ -1325,8 +1503,10 @@ void BKE_studiolight_init(void)
STUDIOLIGHT_MATCAP_FOLDER,
STUDIOLIGHT_TYPE_MATCAP | STUDIOLIGHT_USER_DEFINED);
}
- studiolight_add_files_from_datafolder(
- BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_LIGHTS_FOLDER, STUDIOLIGHT_TYPE_STUDIO);
+ studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES,
+ STUDIOLIGHT_LIGHTS_FOLDER,
+ STUDIOLIGHT_TYPE_STUDIO |
+ STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS);
studiolight_add_files_from_datafolder(
BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_TYPE_WORLD);
studiolight_add_files_from_datafolder(
@@ -1456,6 +1636,12 @@ void BKE_studiolight_ensure_flag(StudioLight *sl, int flag)
studiolight_calculate_irradiance_equirect_image(sl);
}
}
+ if ((flag & STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE)) {
+ studiolight_create_matcap_diffuse_gputexture(sl);
+ }
+ if ((flag & STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE)) {
+ studiolight_create_matcap_specular_gputexture(sl);
+ }
}
/*
diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c
index d346d4d6f8d..471cca53900 100644
--- a/source/blender/blenkernel/intern/subdiv_ccg.c
+++ b/source/blender/blenkernel/intern/subdiv_ccg.c
@@ -169,11 +169,11 @@ typedef struct CCGEvalGridsData {
SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator;
} CCGEvalGridsData;
-static void subdiv_ccg_eval_grid_element(CCGEvalGridsData *data,
- const int ptex_face_index,
- const float u,
- const float v,
- unsigned char *element)
+static void subdiv_ccg_eval_grid_element_limit(CCGEvalGridsData *data,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ unsigned char *element)
{
Subdiv *subdiv = data->subdiv;
SubdivCCG *subdiv_ccg = data->subdiv_ccg;
@@ -191,18 +191,37 @@ static void subdiv_ccg_eval_grid_element(CCGEvalGridsData *data,
else {
BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, (float *)element);
}
- if (subdiv_ccg->has_mask) {
- float *mask_value_ptr = (float *)(element + subdiv_ccg->mask_offset);
- if (data->mask_evaluator != NULL) {
- *mask_value_ptr = data->mask_evaluator->eval_mask(
- data->mask_evaluator, ptex_face_index, u, v);
- }
- else {
- *mask_value_ptr = 0.0f;
- }
+}
+
+static void subdiv_ccg_eval_grid_element_mask(CCGEvalGridsData *data,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ unsigned char *element)
+{
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ if (!subdiv_ccg->has_mask) {
+ return;
+ }
+ float *mask_value_ptr = (float *)(element + subdiv_ccg->mask_offset);
+ if (data->mask_evaluator != NULL) {
+ *mask_value_ptr = data->mask_evaluator->eval_mask(data->mask_evaluator, ptex_face_index, u, v);
+ }
+ else {
+ *mask_value_ptr = 0.0f;
}
}
+static void subdiv_ccg_eval_grid_element(CCGEvalGridsData *data,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ unsigned char *element)
+{
+ subdiv_ccg_eval_grid_element_limit(data, ptex_face_index, u, v, element);
+ subdiv_ccg_eval_grid_element_mask(data, ptex_face_index, u, v, element);
+}
+
static void subdiv_ccg_eval_regular_grid(CCGEvalGridsData *data, const int face_index)
{
SubdivCCG *subdiv_ccg = data->subdiv_ccg;
@@ -572,7 +591,7 @@ Mesh *BKE_subdiv_to_ccg_mesh(Subdiv *subdiv,
{
/* Make sure evaluator is ready. */
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
- if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh)) {
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh, NULL)) {
if (coarse_mesh->totpoly) {
return false;
}
diff --git a/source/blender/blenkernel/intern/subdiv_converter_mesh.c b/source/blender/blenkernel/intern/subdiv_converter_mesh.c
index 37ca6d0e485..60f80628f5a 100644
--- a/source/blender/blenkernel/intern/subdiv_converter_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_converter_mesh.c
@@ -221,7 +221,7 @@ static void precalc_uv_layer(const OpenSubdiv_Converter *converter, const int la
mpoly, mloop, mloopuv, num_poly, num_vert, limit, false, true);
/* NOTE: First UV vertex is supposed to be always marked as separate. */
storage->num_uv_coordinates = -1;
- for (int vertex_index = 0; vertex_index < num_vert; ++vertex_index) {
+ for (int vertex_index = 0; vertex_index < num_vert; vertex_index++) {
const UvMapVert *uv_vert = BKE_mesh_uv_vert_map_get_vert(uv_vert_map, vertex_index);
while (uv_vert != NULL) {
if (uv_vert->separate) {
diff --git a/source/blender/blenkernel/intern/subdiv_deform.c b/source/blender/blenkernel/intern/subdiv_deform.c
new file mode 100644
index 00000000000..9c7949e7bdb
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_deform.c
@@ -0,0 +1,237 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv_deform.h"
+
+#include <string.h>
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_customdata.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_eval.h"
+#include "BKE_subdiv_foreach.h"
+#include "BKE_subdiv_mesh.h"
+
+#include "MEM_guardedalloc.h"
+
+/* ================================================================================================
+ * Subdivision context.
+ */
+
+typedef struct SubdivDeformContext {
+ const Mesh *coarse_mesh;
+ Subdiv *subdiv;
+
+ float (*vertex_cos)[3];
+ int num_verts;
+
+ /* Accumulated values.
+ *
+ * Averaging is happening for vertices which correspond to the coarse ones.
+ * This is needed for displacement.
+ *
+ * Displacement is being accumulated to a vertices coordinates, since those
+ * are not needed during traversal of face-vertices vertices. */
+ /* Per-subdivided vertex counter of averaged values. */
+ int *accumulated_counters;
+
+ bool have_displacement;
+} SubdivDeformContext;
+
+static void subdiv_mesh_prepare_accumulator(SubdivDeformContext *ctx, int num_vertices)
+{
+ if (!ctx->have_displacement) {
+ return;
+ }
+ ctx->accumulated_counters = MEM_calloc_arrayN(
+ sizeof(*ctx->accumulated_counters), num_vertices, "subdiv accumulated counters");
+}
+
+static void subdiv_mesh_context_free(SubdivDeformContext *ctx)
+{
+ MEM_SAFE_FREE(ctx->accumulated_counters);
+}
+
+/* ================================================================================================
+ * Accumulation helpers.
+ */
+
+static void subdiv_accumulate_vertex_displacement(SubdivDeformContext *ctx,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ int vertex_index)
+{
+ Subdiv *subdiv = ctx->subdiv;
+ float dummy_P[3], dPdu[3], dPdv[3], D[3];
+ BKE_subdiv_eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
+ /* Accumulate displacement if needed. */
+ if (ctx->have_displacement) {
+ BKE_subdiv_eval_displacement(subdiv, ptex_face_index, u, v, dPdu, dPdv, D);
+ /* NOTE: The storage for vertex coordinates is coming from an external world, not necessarily
+ * initialized to zeroes. */
+ if (ctx->accumulated_counters[vertex_index] == 0) {
+ copy_v3_v3(ctx->vertex_cos[vertex_index], D);
+ }
+ else {
+ add_v3_v3(ctx->vertex_cos[vertex_index], D);
+ }
+ }
+ ++ctx->accumulated_counters[vertex_index];
+}
+
+/* ================================================================================================
+ * Subdivision callbacks.
+ */
+
+static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_context,
+ const int UNUSED(num_vertices),
+ const int UNUSED(num_edges),
+ const int UNUSED(num_loops),
+ const int UNUSED(num_polygons))
+{
+ SubdivDeformContext *subdiv_context = foreach_context->user_data;
+ subdiv_mesh_prepare_accumulator(subdiv_context, subdiv_context->coarse_mesh->totvert);
+ return true;
+}
+
+static void subdiv_mesh_vertex_every_corner(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int coarse_vertex_index,
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int UNUSED(subdiv_vertex_index))
+{
+ SubdivDeformContext *ctx = foreach_context->user_data;
+ subdiv_accumulate_vertex_displacement(ctx, ptex_face_index, u, v, coarse_vertex_index);
+}
+
+static void subdiv_mesh_vertex_corner(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int coarse_vertex_index,
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int UNUSED(subdiv_vertex_index))
+{
+ SubdivDeformContext *ctx = foreach_context->user_data;
+ BLI_assert(coarse_vertex_index != ORIGINDEX_NONE);
+ BLI_assert(coarse_vertex_index < ctx->num_verts);
+ float inv_num_accumulated = 1.0f;
+ if (ctx->accumulated_counters != NULL) {
+ inv_num_accumulated = 1.0f / ctx->accumulated_counters[coarse_vertex_index];
+ }
+ /* Displacement is accumulated in subdiv vertex position.
+ * Needs to be backed up before copying data from original vertex. */
+ float D[3] = {0.0f, 0.0f, 0.0f};
+ float *vertex_co = ctx->vertex_cos[coarse_vertex_index];
+ if (ctx->have_displacement) {
+ copy_v3_v3(D, vertex_co);
+ mul_v3_fl(D, inv_num_accumulated);
+ }
+ /* Copy custom data and evaluate position. */
+ BKE_subdiv_eval_limit_point(ctx->subdiv, ptex_face_index, u, v, vertex_co);
+ /* Apply displacement. */
+ add_v3_v3(vertex_co, D);
+}
+
+/* ================================================================================================
+ * Initialization.
+ */
+
+static void setup_foreach_callbacks(const SubdivDeformContext *subdiv_context,
+ SubdivForeachContext *foreach_context)
+{
+ memset(foreach_context, 0, sizeof(*foreach_context));
+ /* General information. */
+ foreach_context->topology_info = subdiv_mesh_topology_info;
+ /* Every boundary geometry. Used for displacement and normals averaging. */
+ if (subdiv_context->have_displacement) {
+ foreach_context->vertex_every_corner = subdiv_mesh_vertex_every_corner;
+ }
+ foreach_context->vertex_corner = subdiv_mesh_vertex_corner;
+}
+
+/* ================================================================================================
+ * Public entry point.
+ */
+
+void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv,
+ const struct Mesh *coarse_mesh,
+ float (*vertex_cos)[3],
+ int num_verts)
+{
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
+ /* Make sure evaluator is up to date with possible new topology, and that
+ * is is refined for the new positions of coarse vertices.
+ */
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh, vertex_cos)) {
+ /* This could happen in two situations:
+ * - OpenSubdiv is disabled.
+ * - Something totally bad happened, and OpenSubdiv rejected our
+ * topology.
+ * In either way, we can't safely continue. */
+ if (coarse_mesh->totpoly) {
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
+ return;
+ }
+ }
+
+ /* Initialize subdivion mesh creation context. */
+ SubdivDeformContext subdiv_context = {0};
+ subdiv_context.coarse_mesh = coarse_mesh;
+ subdiv_context.subdiv = subdiv;
+ subdiv_context.vertex_cos = vertex_cos;
+ subdiv_context.num_verts = num_verts;
+ subdiv_context.have_displacement = (subdiv->displacement_evaluator != NULL);
+
+ SubdivForeachContext foreach_context;
+ setup_foreach_callbacks(&subdiv_context, &foreach_context);
+ foreach_context.user_data = &subdiv_context;
+
+ /* Dummy mesh rasterization settings. */
+ SubdivToMeshSettings mesh_settings;
+ mesh_settings.resolution = 1;
+ mesh_settings.use_optimal_display = false;
+
+ /* Multi-threaded traversal/evaluation. */
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
+ BKE_subdiv_foreach_subdiv_geometry(subdiv, &foreach_context, &mesh_settings, coarse_mesh);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
+
+ // BKE_mesh_validate(result, true, true);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
+
+ /* Free used memory. */
+ subdiv_mesh_context_free(&subdiv_context);
+}
diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c
index cb042e087d5..bf5e886dd22 100644
--- a/source/blender/blenkernel/intern/subdiv_eval.c
+++ b/source/blender/blenkernel/intern/subdiv_eval.c
@@ -61,7 +61,9 @@ bool BKE_subdiv_eval_begin(Subdiv *subdiv)
return true;
}
-static void set_coarse_positions(Subdiv *subdiv, const Mesh *mesh)
+static void set_coarse_positions(Subdiv *subdiv,
+ const Mesh *mesh,
+ const float (*coarse_vertex_cos)[3])
{
const MVert *mvert = mesh->mvert;
const MLoop *mloop = mesh->mloop;
@@ -83,8 +85,15 @@ static void set_coarse_positions(Subdiv *subdiv, const Mesh *mesh)
if (!BLI_BITMAP_TEST_BOOL(vertex_used_map, vertex_index)) {
continue;
}
- const MVert *vertex = &mvert[vertex_index];
- subdiv->evaluator->setCoarsePositions(subdiv->evaluator, vertex->co, manifold_veretx_index, 1);
+ const float *vertex_co;
+ if (coarse_vertex_cos != NULL) {
+ vertex_co = coarse_vertex_cos[vertex_index];
+ }
+ else {
+ const MVert *vertex = &mvert[vertex_index];
+ vertex_co = vertex->co;
+ }
+ subdiv->evaluator->setCoarsePositions(subdiv->evaluator, vertex_co, manifold_veretx_index, 1);
manifold_veretx_index++;
}
MEM_freeN(vertex_used_map);
@@ -101,7 +110,7 @@ static void set_face_varying_data_from_uv(Subdiv *subdiv,
/* TODO(sergey): OpenSubdiv's C-API converter can change winding of
* loops of a face, need to watch for that, to prevent wrong UVs assigned.
*/
- for (int face_index = 0; face_index < num_faces; ++face_index) {
+ for (int face_index = 0; face_index < num_faces; face_index++) {
const int num_face_vertices = topology_refiner->getNumFaceVertices(topology_refiner,
face_index);
const int *uv_indices = topology_refiner->getFaceFVarValueIndices(
@@ -112,7 +121,9 @@ static void set_face_varying_data_from_uv(Subdiv *subdiv,
}
}
-bool BKE_subdiv_eval_update_from_mesh(Subdiv *subdiv, const Mesh *mesh)
+bool BKE_subdiv_eval_update_from_mesh(Subdiv *subdiv,
+ const Mesh *mesh,
+ const float (*coarse_vertex_cos)[3])
{
if (!BKE_subdiv_eval_begin(subdiv)) {
return false;
@@ -123,7 +134,7 @@ bool BKE_subdiv_eval_update_from_mesh(Subdiv *subdiv, const Mesh *mesh)
return false;
}
/* Set coordinates of base mesh vertices. */
- set_coarse_positions(subdiv, mesh);
+ set_coarse_positions(subdiv, mesh, coarse_vertex_cos);
/* Set face-varyign data to UV maps. */
const int num_uv_layers = CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
for (int layer_index = 0; layer_index < num_uv_layers; layer_index++) {
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
index 1ff9140681f..a30dde6284b 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -82,7 +82,7 @@ static void subdiv_mesh_ctx_cache_uv_layers(SubdivMeshContext *ctx)
{
Mesh *subdiv_mesh = ctx->subdiv_mesh;
ctx->num_uv_layers = CustomData_number_of_layers(&subdiv_mesh->ldata, CD_MLOOPUV);
- for (int layer_index = 0; layer_index < ctx->num_uv_layers; ++layer_index) {
+ for (int layer_index = 0; layer_index < ctx->num_uv_layers; layer_index++) {
ctx->uv_layers[layer_index] = CustomData_get_layer_n(
&subdiv_mesh->ldata, CD_MLOOPUV, layer_index);
}
@@ -220,7 +220,7 @@ static void vertex_interpolation_init(const SubdivMeshContext *ctx,
const float weight = 1.0f / (float)coarse_poly->totloop;
float *weights = BLI_array_alloca(weights, coarse_poly->totloop);
int *indices = BLI_array_alloca(indices, coarse_poly->totloop);
- for (int i = 0; i < coarse_poly->totloop; ++i) {
+ for (int i = 0; i < coarse_poly->totloop; i++) {
weights[i] = weight;
indices[i] = coarse_mloop[coarse_poly->loopstart + i].v;
}
@@ -352,7 +352,7 @@ static void loop_interpolation_init(const SubdivMeshContext *ctx,
const float weight = 1.0f / (float)coarse_poly->totloop;
float *weights = BLI_array_alloca(weights, coarse_poly->totloop);
int *indices = BLI_array_alloca(indices, coarse_poly->totloop);
- for (int i = 0; i < coarse_poly->totloop; ++i) {
+ for (int i = 0; i < coarse_poly->totloop; i++) {
weights[i] = weight;
indices[i] = coarse_poly->loopstart + i;
}
@@ -482,6 +482,8 @@ static void subdiv_accumulate_vertex_normal_and_displacement(SubdivMeshContext *
}
/* Accumulate displacement if needed. */
if (ctx->have_displacement) {
+ /* NOTE: The subdivided mesh is allocated in this module, and its vertices are kept at zero
+ * locations as a default calloc(). */
BKE_subdiv_eval_displacement(subdiv, ptex_face_index, u, v, dPdu, dPdv, D);
add_v3_v3(subdiv_vert->co, D);
}
@@ -498,9 +500,14 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex
const int num_loops,
const int num_polygons)
{
+ /* Multires grid data will be applied or become invalid after subdivision,
+ * so don't try to preserve it and use memory. */
+ CustomData_MeshMasks mask = CD_MASK_EVERYTHING;
+ mask.lmask &= ~CD_MASK_MULTIRES_GRIDS;
+
SubdivMeshContext *subdiv_context = foreach_context->user_data;
- subdiv_context->subdiv_mesh = BKE_mesh_new_nomain_from_template(
- subdiv_context->coarse_mesh, num_vertices, num_edges, 0, num_loops, num_polygons);
+ subdiv_context->subdiv_mesh = BKE_mesh_new_nomain_from_template_ex(
+ subdiv_context->coarse_mesh, num_vertices, num_edges, 0, num_loops, num_polygons, mask);
subdiv_mesh_ctx_cache_custom_data_layers(subdiv_context);
subdiv_mesh_prepare_accumulator(subdiv_context, num_vertices);
return true;
@@ -1159,7 +1166,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
/* Make sure evaluator is up to date with possible new topology, and that
* is is refined for the new positions of coarse vertices.
*/
- if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh)) {
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh, NULL)) {
/* This could happen in two situations:
* - OpenSubdiv is disabled.
* - Something totally bad happened, and OpenSubdiv rejected our
@@ -1170,7 +1177,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
return NULL;
}
}
- /* Initialize subdivion mesh creation context/ */
+ /* Initialize subdivion mesh creation context. */
SubdivMeshContext subdiv_context = {0};
subdiv_context.settings = settings;
subdiv_context.coarse_mesh = coarse_mesh;
@@ -1193,7 +1200,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
if (!subdiv_context.can_evaluate_normals) {
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
- /* Free used memoty. */
+ /* Free used memory. */
subdiv_mesh_context_free(&subdiv_context);
return result;
}
diff --git a/source/blender/blenkernel/intern/subdiv_topology.c b/source/blender/blenkernel/intern/subdiv_topology.c
new file mode 100644
index 00000000000..455fa2cf28f
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_topology.c
@@ -0,0 +1,34 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv_topology.h"
+
+#include "BKE_subdiv.h"
+
+#include "opensubdiv_topology_refiner_capi.h"
+
+int BKE_subdiv_topology_num_fvar_layers_get(const struct Subdiv *subdiv)
+{
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ return topology_refiner->getNumFVarChannels(topology_refiner);
+}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 77dc438cd04..11d2314ace3 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -1784,7 +1784,7 @@ static void *ccgDM_get_tessface_data_layer(DerivedMesh *dm, int type)
/* With ccgdm, we have a simple one to one mapping between loops
* and tessellated face corners. */
- for (i = 0; i < numLoops; ++i, ++tlnors_it, ++lnors) {
+ for (i = 0; i < numLoops; i++, tlnors_it++, lnors++) {
normal_float_to_short_v3(*tlnors_it, *lnors);
}
}
@@ -2263,7 +2263,7 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
}
if (edgeOrigIndex) {
- for (i = 0; i < numFinalEdges; ++i) {
+ for (i = 0; i < numFinalEdges; i++) {
edgeOrigIndex[edgeNum + i] = ORIGINDEX_NONE;
}
}
@@ -2321,7 +2321,7 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
edgeNum += numFinalEdges;
}
- for (index = 0; index < totedge; ++index) {
+ for (index = 0; index < totedge; index++) {
CCGEdge *e = ccgdm->edgeMap[index].edge;
int numFinalEdges = edgeSize - 1;
int mapIndex = ccgDM_getEdgeMapIndex(ss, e);
@@ -2359,13 +2359,13 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
if (has_edge_cd) {
BLI_assert(edgeIdx >= 0 && edgeIdx < dm->getNumEdges(dm));
- for (i = 0; i < numFinalEdges; ++i) {
+ for (i = 0; i < numFinalEdges; i++) {
CustomData_copy_data(&dm->edgeData, &ccgdm->dm.edgeData, edgeIdx, edgeNum + i, 1);
}
}
if (edgeOrigIndex) {
- for (i = 0; i < numFinalEdges; ++i) {
+ for (i = 0; i < numFinalEdges; i++) {
edgeOrigIndex[edgeNum + i] = mapIndex;
}
}
@@ -2384,7 +2384,7 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
}
}
- for (index = 0; index < totvert; ++index) {
+ for (index = 0; index < totvert; index++) {
CCGVert *v = ccgdm->vertMap[index].vert;
int mapIndex = ccgDM_getVertMapIndex(ccgdm->ss, v);
int vertIdx;
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index ad7c5e3f660..f4e89160487 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -41,6 +41,7 @@
#include "DNA_color_types.h"
#include "DNA_particle_types.h"
#include "DNA_linestyle_types.h"
+#include "DNA_defaults.h"
#include "IMB_imbuf.h"
@@ -214,56 +215,11 @@ void BKE_texture_free(Tex *tex)
void BKE_texture_default(Tex *tex)
{
- /* Not here, can be called with some pointers set. :/ */
- /* BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(tex, id)); */
-
- tex->type = TEX_IMAGE;
- tex->ima = NULL;
- tex->stype = 0;
- tex->flag = TEX_CHECKER_ODD;
- tex->imaflag = TEX_INTERPOL | TEX_MIPMAP | TEX_USEALPHA;
- tex->extend = TEX_REPEAT;
- tex->cropxmin = tex->cropymin = 0.0;
- tex->cropxmax = tex->cropymax = 1.0;
- tex->texfilter = TXF_EWA;
- tex->afmax = 8;
- tex->xrepeat = tex->yrepeat = 1;
- tex->sfra = 1;
- tex->frames = 0;
- tex->offset = 0;
- tex->noisesize = 0.25;
- tex->noisedepth = 2;
- tex->turbul = 5.0;
- tex->nabla = 0.025; // also in do_versions
- tex->bright = 1.0;
- tex->contrast = 1.0;
- tex->saturation = 1.0;
- tex->filtersize = 1.0;
- tex->rfac = 1.0;
- tex->gfac = 1.0;
- tex->bfac = 1.0;
- /* newnoise: init. */
- tex->noisebasis = 0;
- tex->noisebasis2 = 0;
- /* musgrave */
- tex->mg_H = 1.0;
- tex->mg_lacunarity = 2.0;
- tex->mg_octaves = 2.0;
- tex->mg_offset = 1.0;
- tex->mg_gain = 1.0;
- tex->ns_outscale = 1.0;
- /* distnoise */
- tex->dist_amount = 1.0;
- /* voronoi */
- tex->vn_w1 = 1.0;
- tex->vn_w2 = tex->vn_w3 = tex->vn_w4 = 0.0;
- tex->vn_mexp = 2.5;
- tex->vn_distm = 0;
- tex->vn_coltype = 0;
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(tex, id));
- BKE_imageuser_default(&tex->iuser);
+ MEMCPY_STRUCT_AFTER(tex, DNA_struct_default_get(Tex), id);
- tex->preview = NULL;
+ BKE_imageuser_default(&tex->iuser);
}
void BKE_texture_type_set(Tex *tex, int type)
@@ -288,69 +244,7 @@ Tex *BKE_texture_add(Main *bmain, const char *name)
void BKE_texture_mtex_default(MTex *mtex)
{
- mtex->texco = TEXCO_UV;
- mtex->mapto = MAP_COL;
- mtex->object = NULL;
- mtex->projx = PROJ_X;
- mtex->projy = PROJ_Y;
- mtex->projz = PROJ_Z;
- mtex->mapping = MTEX_FLAT;
- mtex->ofs[0] = 0.0;
- mtex->ofs[1] = 0.0;
- mtex->ofs[2] = 0.0;
- mtex->size[0] = 1.0;
- mtex->size[1] = 1.0;
- mtex->size[2] = 1.0;
- mtex->tex = NULL;
- mtex->colormodel = 0;
- mtex->r = 1.0;
- mtex->g = 0.0;
- mtex->b = 1.0;
- mtex->k = 1.0;
- mtex->def_var = 1.0;
- mtex->blendtype = MTEX_BLEND;
- mtex->colfac = 1.0;
- mtex->norfac = 1.0;
- mtex->varfac = 1.0;
- mtex->dispfac = 0.2;
- mtex->colspecfac = 1.0f;
- mtex->mirrfac = 1.0f;
- mtex->alphafac = 1.0f;
- mtex->difffac = 1.0f;
- mtex->specfac = 1.0f;
- mtex->emitfac = 1.0f;
- mtex->hardfac = 1.0f;
- mtex->raymirrfac = 1.0f;
- mtex->translfac = 1.0f;
- mtex->ambfac = 1.0f;
- mtex->colemitfac = 1.0f;
- mtex->colreflfac = 1.0f;
- mtex->coltransfac = 1.0f;
- mtex->densfac = 1.0f;
- mtex->scatterfac = 1.0f;
- mtex->reflfac = 1.0f;
- mtex->shadowfac = 1.0f;
- mtex->zenupfac = 1.0f;
- mtex->zendownfac = 1.0f;
- mtex->blendfac = 1.0f;
- mtex->timefac = 1.0f;
- mtex->lengthfac = 1.0f;
- mtex->clumpfac = 1.0f;
- mtex->kinkfac = 1.0f;
- mtex->kinkampfac = 1.0f;
- mtex->roughfac = 1.0f;
- mtex->twistfac = 1.0f;
- mtex->padensfac = 1.0f;
- mtex->lifefac = 1.0f;
- mtex->sizefac = 1.0f;
- mtex->ivelfac = 1.0f;
- mtex->dampfac = 1.0f;
- mtex->gravityfac = 1.0f;
- mtex->fieldfac = 1.0f;
- mtex->normapspace = MTEX_NSPACE_TANGENT;
- mtex->brush_map_mode = MTEX_MAP_MODE_TILED;
- mtex->random_angle = 2.0f * (float)M_PI;
- mtex->brush_angle_mode = 0;
+ memcpy(mtex, DNA_struct_default_get(MTex), sizeof(*mtex));
}
/* ------------------------------------------------------------------------- */
@@ -423,6 +317,9 @@ MTex *BKE_texture_mtex_add_id(ID *id, int slot)
*/
void BKE_texture_copy_data(Main *bmain, Tex *tex_dst, const Tex *tex_src, const int flag)
{
+ /* We always need allocation of our private ID data. */
+ const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
+
if (!BKE_texture_is_image_user(tex_src)) {
tex_dst->ima = NULL;
}
@@ -434,9 +331,8 @@ void BKE_texture_copy_data(Main *bmain, Tex *tex_dst, const Tex *tex_src, const
if (tex_src->nodetree->execdata) {
ntreeTexEndExecTree(tex_src->nodetree->execdata);
}
- /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
- * (see BKE_libblock_copy_ex()). */
- BKE_id_copy_ex(bmain, (ID *)tex_src->nodetree, (ID **)&tex_dst->nodetree, flag);
+ BKE_id_copy_ex(
+ bmain, (ID *)tex_src->nodetree, (ID **)&tex_dst->nodetree, flag_private_id_data);
}
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index a5445be7ce5..1e7b3af53d5 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -1843,18 +1843,18 @@ void BKE_tracking_plane_marker_get_subframe_corners(MovieTrackingPlaneTrack *pla
MovieTrackingPlaneMarker *marker_next = marker + 1;
if (marker_next->framenr == marker->framenr + 1) {
float fac = (framenr - (int)framenr) / (marker_next->framenr - marker->framenr);
- for (i = 0; i < 4; ++i) {
+ for (i = 0; i < 4; i++) {
interp_v2_v2v2(corners[i], marker->corners[i], marker_next->corners[i], fac);
}
}
else {
- for (i = 0; i < 4; ++i) {
+ for (i = 0; i < 4; i++) {
copy_v2_v2(corners[i], marker->corners[i]);
}
}
}
else {
- for (i = 0; i < 4; ++i) {
+ for (i = 0; i < 4; i++) {
copy_v2_v2(corners[i], marker->corners[i]);
}
}
diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c
index 47c12b329dc..fad928c12fe 100644
--- a/source/blender/blenkernel/intern/tracking_auto.c
+++ b/source/blender/blenkernel/intern/tracking_auto.c
@@ -133,7 +133,7 @@ static void dna_marker_to_libmv_marker(/*const*/ MovieTrackingTrack *track,
libmv_marker->track = track_index;
normalized_to_libmv_frame(marker->pos, frame_dimensions, libmv_marker->center);
- for (i = 0; i < 4; ++i) {
+ for (i = 0; i < 4; i++) {
normalized_relative_to_libmv_frame(
marker->pattern_corners[i], marker->pos, frame_dimensions, libmv_marker->patch[i]);
}
@@ -187,7 +187,7 @@ static void libmv_marker_to_dna_marker(libmv_Marker *libmv_marker,
marker->framenr = libmv_marker->frame;
libmv_frame_to_normalized(libmv_marker->center, frame_dimensions, marker->pos);
- for (i = 0; i < 4; ++i) {
+ for (i = 0; i < 4; i++) {
libmv_frame_to_normalized_relative(libmv_marker->patch[i],
libmv_marker->center,
frame_dimensions,
@@ -261,7 +261,7 @@ static void fill_autotrack_tracks(const int frame_width,
/* Count number of markers to be put to a context. */
size_t num_trackable_markers = 0;
for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
- for (int i = 0; i < track->markersnr; ++i) {
+ for (int i = 0; i < track->markersnr; i++) {
const MovieTrackingMarker *marker = track->markers + i;
if ((marker->flag & MARKER_DISABLED) == 0) {
num_trackable_markers++;
@@ -278,7 +278,7 @@ static void fill_autotrack_tracks(const int frame_width,
/* Fill in markers array. */
int track_index = 0, num_filled_libmv_markers = 0;
for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
- for (int i = 0; i < track->markersnr; ++i) {
+ for (int i = 0; i < track->markersnr; i++) {
MovieTrackingMarker *marker = track->markers + i;
if ((marker->flag & MARKER_DISABLED) != 0) {
continue;
@@ -319,7 +319,7 @@ static void create_per_track_tracking_options(const MovieClip *clip,
int i = 0, track_index = 0;
for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
if (!check_track_trackable(clip, track, user)) {
- ++track_index;
+ track_index++;
continue;
}
AutoTrackOptions *options = &context->options[i++];
@@ -330,7 +330,7 @@ static void create_per_track_tracking_options(const MovieClip *clip,
tracking_configure_tracker(track, NULL, &options->track_region_options);
options->use_keyframe_match = track->pattern_match == TRACK_MATCH_KEYFRAME;
context->tracks[track_index] = track;
- ++track_index;
+ track_index++;
}
}
@@ -471,7 +471,7 @@ void BKE_autotrack_context_sync(AutoTrackContext *context)
libmv_Marker libmv_marker;
int clip = 0;
int track;
- for (track = 0; track < context->num_tracks; ++track) {
+ for (track = 0; track < context->num_tracks; track++) {
AutoTrackOptions *options = &context->options[track];
int track_frame = BKE_movieclip_remap_scene_to_clip_frame(
context->clips[options->clip_index], frame);
@@ -506,7 +506,7 @@ void BKE_autotrack_context_sync(AutoTrackContext *context)
}
BLI_spin_unlock(&context->spin_lock);
- for (int clip = 0; clip < context->num_clips; ++clip) {
+ for (int clip = 0; clip < context->num_clips; clip++) {
MovieTracking *tracking = &context->clips[clip]->tracking;
BKE_tracking_dopesheet_tag_update(tracking);
}
@@ -524,7 +524,7 @@ void BKE_autotrack_context_finish(AutoTrackContext *context)
{
int clip_index;
- for (clip_index = 0; clip_index < context->num_clips; ++clip_index) {
+ for (clip_index = 0; clip_index < context->num_clips; clip_index++) {
MovieClip *clip = context->clips[clip_index];
ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
MovieTrackingPlaneTrack *plane_track;
@@ -532,7 +532,7 @@ void BKE_autotrack_context_finish(AutoTrackContext *context)
for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
int track;
- for (track = 0; track < context->num_tracks; ++track) {
+ for (track = 0; track < context->num_tracks; track++) {
if (BKE_tracking_plane_track_has_point_track(plane_track,
context->options[track].track)) {
BKE_tracking_track_plane_from_existing_motion(plane_track, context->first_frame);
diff --git a/source/blender/blenkernel/intern/tracking_solver.c b/source/blender/blenkernel/intern/tracking_solver.c
index 7e7a839b645..ab741eed410 100644
--- a/source/blender/blenkernel/intern/tracking_solver.c
+++ b/source/blender/blenkernel/intern/tracking_solver.c
@@ -221,7 +221,7 @@ static bool reconstruct_retrieve_libmv_tracks(MovieReconstructContext *context,
*
* There's one weak part tho, which is requirement object
* motion starts at the same frame as camera motion does,
- * otherwise that;' be a russian roulette whether object is
+ * otherwise that;' be a Russian roulette whether object is
* aligned correct or not.
*/
if (!origin_set) {
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index 03229c654fb..2c270f10908 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -274,10 +274,10 @@ static int search_closest_marker_index(MovieTrackingTrack *track, int ref_frame)
i = MAX2(0, i);
i = MIN2(i, end - 1);
- for (; i < end - 1 && markers[i].framenr <= ref_frame; ++i) {
+ for (; i < end - 1 && markers[i].framenr <= ref_frame; i++) {
/* pass */
}
- for (; 0 < i && markers[i].framenr > ref_frame; --i) {
+ for (; 0 < i && markers[i].framenr > ref_frame; i--) {
/* pass */
}
@@ -294,7 +294,7 @@ static void retrieve_next_higher_usable_frame(
while (i < end &&
(markers[i].framenr < ref_frame || is_effectively_disabled(ctx, track, &markers[i]))) {
- ++i;
+ i++;
}
if (i < end && markers[i].framenr < *next_higher) {
BLI_assert(markers[i].framenr >= ref_frame);
@@ -309,7 +309,7 @@ static void retrieve_next_lower_usable_frame(
BLI_assert(0 <= i && i < track->markersnr);
while (i >= 0 &&
(markers[i].framenr > ref_frame || is_effectively_disabled(ctx, track, &markers[i]))) {
- --i;
+ i--;
}
if (0 <= i && markers[i].framenr > *next_lower) {
BLI_assert(markers[i].framenr <= ref_frame);
@@ -782,7 +782,7 @@ static int establish_track_initialization_order(StabContext *ctx, TrackInitOrder
if (marker != NULL && (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT))) {
order[tracknr].sort_value = abs(marker->framenr - anchor_frame);
order[tracknr].reference_frame = marker->framenr;
- ++tracknr;
+ tracknr++;
}
}
if (tracknr) {
@@ -907,7 +907,7 @@ static void initialize_all_tracks(StabContext *ctx, float aspect)
local_data->track_weight_curve = retrieve_track_weight_animation(clip, track);
local_data->is_init_for_stabilization = false;
- ++track_len;
+ track_len++;
}
if (!track_len) {
return;
@@ -927,7 +927,7 @@ static void initialize_all_tracks(StabContext *ctx, float aspect)
average_marker_positions(ctx, reference_frame, average_pos);
setup_pivot(average_pos, pivot);
- for (i = 0; i < track_len; ++i) {
+ for (i = 0; i < track_len; i++) {
track = order[i].data;
if (reference_frame != order[i].reference_frame) {
reference_frame = order[i].reference_frame;
@@ -1129,8 +1129,8 @@ static void stabilization_data_to_mat4(float pixel_aspect,
}
/* Calculate scale factor necessary to eliminate black image areas
- * caused by the compensating movements of the stabilizator.
- * This function visits every frame where stabilisation data is
+ * caused by the compensating movements of the stabilizer.
+ * This function visits every frame where stabilization data is
* available and determines the factor for this frame. The overall
* largest factor found is returned as result.
*
diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index 358d8fa0a3e..ed582dc5b94 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -688,7 +688,7 @@ static ImBuf *make_grayscale_ibuf_copy(ImBuf *ibuf)
grayscale->mall |= IB_rectfloat;
grayscale->flags |= IB_rectfloat;
- for (i = 0; i < grayscale->x * grayscale->y; ++i) {
+ for (i = 0; i < grayscale->x * grayscale->y; i++) {
const float *pixel = ibuf->rect_float + ibuf->channels * i;
grayscale->rect_float[i] = 0.2126f * pixel[0] + 0.7152f * pixel[1] + 0.0722f * pixel[2];
@@ -790,9 +790,9 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor,
* here. Probably Libmv is better to work in the linear space,
* but keep sRGB space here for compatibility for now.
*/
- for (y = 0; y < clamped_height; ++y) {
+ for (y = 0; y < clamped_height; y++) {
int x;
- for (x = 0; x < clamped_width; ++x) {
+ for (x = 0; x < clamped_width; x++) {
int src_x = x + clamped_origin_x, src_y = y + clamped_origin_y;
int dst_x = x + dst_offset_x, dst_y = y + dst_offset_y;
int dst_index = (dst_y * width + dst_x) * 4,
diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c
index 36b950fb8f9..ecae1650a51 100644
--- a/source/blender/blenkernel/intern/undo_system.c
+++ b/source/blender/blenkernel/intern/undo_system.c
@@ -503,7 +503,7 @@ bool BKE_undosys_step_push_with_type(UndoStack *ustack,
/* Might not be final place for this to be called - probably only want to call it from some
* undo handlers, not all of them? */
if (BKE_override_library_is_enabled()) {
- BKE_main_override_library_operations_create(CTX_data_main(C), false);
+ BKE_main_override_library_operations_create(G_MAIN, false);
}
/* Remove all undos after (also when 'ustack->step_active == NULL'). */
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 109d615ae83..992e4333049 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -30,6 +30,7 @@
#include "DNA_world_types.h"
#include "DNA_scene_types.h"
#include "DNA_texture_types.h"
+#include "DNA_defaults.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
@@ -71,16 +72,7 @@ void BKE_world_init(World *wrld)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(wrld, id));
- wrld->horr = 0.05f;
- wrld->horg = 0.05f;
- wrld->horb = 0.05f;
-
- wrld->aodist = 10.0f;
- wrld->aoenergy = 1.0f;
-
- wrld->preview = NULL;
- wrld->miststa = 5.0f;
- wrld->mistdist = 25.0f;
+ MEMCPY_STRUCT_AFTER(wrld, DNA_struct_default_get(World), id);
}
World *BKE_world_add(Main *bmain, const char *name)
@@ -106,10 +98,12 @@ World *BKE_world_add(Main *bmain, const char *name)
*/
void BKE_world_copy_data(Main *bmain, World *wrld_dst, const World *wrld_src, const int flag)
{
+ /* We always need allocation of our private ID data. */
+ const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
+
if (wrld_src->nodetree) {
- /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
- * (see BKE_libblock_copy_ex()). */
- BKE_id_copy_ex(bmain, (ID *)wrld_src->nodetree, (ID **)&wrld_dst->nodetree, flag);
+ BKE_id_copy_ex(
+ bmain, (ID *)wrld_src->nodetree, (ID **)&wrld_dst->nodetree, flag_private_id_data);
}
BLI_listbase_clear(&wrld_dst->gpumaterial);
diff --git a/source/blender/blenlib/BLI_allocator.h b/source/blender/blenlib/BLI_allocator.h
new file mode 100644
index 00000000000..52fa8d2b705
--- /dev/null
+++ b/source/blender/blenlib/BLI_allocator.h
@@ -0,0 +1,129 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef __BLI_ALLOCATOR_H__
+#define __BLI_ALLOCATOR_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * This file offers a couple of memory allocators that can be used with containers such as Vector
+ * and Map. Note that these allocators are not designed to work with standard containers like
+ * std::vector.
+ *
+ * Also see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2271.html for why the standard
+ * allocators are not a good fit applications like Blender. The current implementations in this
+ * file are fairly simple still, more complexity can be added when necessary. For now they do their
+ * job good enough.
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math_base.h"
+#include "BLI_temporary_allocator.h"
+
+namespace BLI {
+
+/**
+ * Use Blenders guarded allocator (aka MEM_malloc). This should always be used except there is a
+ * good reason not to use it.
+ */
+class GuardedAllocator {
+ public:
+ void *allocate(uint size, const char *name)
+ {
+ return MEM_mallocN(size, name);
+ }
+
+ void *allocate_aligned(uint size, uint alignment, const char *name)
+ {
+ alignment = std::max<uint>(alignment, 8);
+ return MEM_mallocN_aligned(size, alignment, name);
+ }
+
+ void deallocate(void *ptr)
+ {
+ MEM_freeN(ptr);
+ }
+};
+
+/**
+ * This is a simple wrapper around malloc/free. Only use this when the GuardedAllocator cannot be
+ * used. This can be the case when the allocated element might live longer than Blenders Allocator.
+ */
+class RawAllocator {
+ private:
+ struct MemHead {
+ int offset;
+ };
+
+ public:
+ void *allocate(uint size, const char *UNUSED(name))
+ {
+ void *ptr = malloc(size + sizeof(MemHead));
+ ((MemHead *)ptr)->offset = sizeof(MemHead);
+ return POINTER_OFFSET(ptr, sizeof(MemHead));
+ }
+
+ void *allocate_aligned(uint size, uint alignment, const char *UNUSED(name))
+ {
+ BLI_assert(is_power_of_2_i((int)alignment));
+ void *ptr = malloc(size + alignment + sizeof(MemHead));
+ void *used_ptr = (void *)((uintptr_t)POINTER_OFFSET(ptr, alignment + sizeof(MemHead)) &
+ ~((uintptr_t)alignment - 1));
+ uint offset = (uint)((uintptr_t)used_ptr - (uintptr_t)ptr);
+ BLI_assert(offset >= sizeof(MemHead));
+ ((MemHead *)used_ptr - 1)->offset = (int)offset;
+ return used_ptr;
+ }
+
+ void deallocate(void *ptr)
+ {
+ MemHead *head = (MemHead *)ptr - 1;
+ int offset = -head->offset;
+ void *actual_pointer = POINTER_OFFSET(ptr, offset);
+ free(actual_pointer);
+ }
+};
+
+/**
+ * Use this only under specific circumstances as described in BLI_temporary_allocator.h.
+ */
+class TemporaryAllocator {
+ public:
+ void *allocate(uint size, const char *UNUSED(name))
+ {
+ return BLI_temporary_allocate(size);
+ }
+
+ void *allocate_aligned(uint size, uint alignment, const char *UNUSED(name))
+ {
+ BLI_assert(alignment <= 64);
+ UNUSED_VARS_NDEBUG(alignment);
+ return BLI_temporary_allocate(size);
+ }
+
+ void deallocate(void *ptr)
+ {
+ BLI_temporary_deallocate(ptr);
+ }
+};
+
+} // namespace BLI
+
+#endif /* __BLI_ALLOCATOR_H__ */
diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h
index a61eff7329e..57e1790fdfd 100644
--- a/source/blender/blenlib/BLI_array.h
+++ b/source/blender/blenlib/BLI_array.h
@@ -83,9 +83,10 @@ void _bli_array_grow_func(void **arr_p,
((void *)(_##arr##_static) != \
NULL) && /* don't add _##arr##_len below because it must be zero */ \
(_bli_array_totalsize_static(arr) >= \
- _##arr##_len + (num))) ? /* we have an empty array and a static var big enough */ \
+ (size_t)(_##arr##_len + \
+ (num)))) ? /* we have an empty array and a static var big enough */ \
(void)(arr = (void *)_##arr##_static) : /* use existing static array or allocate */ \
- (LIKELY(_bli_array_totalsize(arr) >= _##arr##_len + (num)) ? \
+ (LIKELY(_bli_array_totalsize(arr) >= (size_t)(_##arr##_len + (num))) ? \
(void)0 /* do nothing */ : \
_bli_array_grow_func((void **)&(arr), \
_##arr##_static, \
diff --git a/source/blender/blenlib/BLI_array_cxx.h b/source/blender/blenlib/BLI_array_cxx.h
new file mode 100644
index 00000000000..c7704e20fb1
--- /dev/null
+++ b/source/blender/blenlib/BLI_array_cxx.h
@@ -0,0 +1,197 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef __BLI_ARRAY_CXX_H__
+#define __BLI_ARRAY_CXX_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * This is a container that contains a fixed size array. Note however, the size of the array is not
+ * a template argument. Instead it can be specified at the construction time.
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_allocator.h"
+#include "BLI_array_ref.h"
+#include "BLI_memory_utils_cxx.h"
+
+namespace BLI {
+
+template<typename T, typename Allocator = GuardedAllocator> class Array {
+ private:
+ T *m_data;
+ uint m_size;
+ Allocator m_allocator;
+
+ public:
+ Array()
+ {
+ m_data = nullptr;
+ m_size = 0;
+ }
+
+ Array(ArrayRef<T> values)
+ {
+ m_size = values.size();
+ m_data = this->allocate(m_size);
+ uninitialized_copy_n(values.begin(), m_size, m_data);
+ }
+
+ Array(const std::initializer_list<T> &values) : Array(ArrayRef<T>(values))
+ {
+ }
+
+ explicit Array(uint size)
+ {
+ m_data = this->allocate(size);
+ m_size = size;
+
+ for (uint i = 0; i < m_size; i++) {
+ new (m_data + i) T();
+ }
+ }
+
+ Array(uint size, const T &value)
+ {
+ m_data = this->allocate(size);
+ m_size = size;
+ uninitialized_fill_n(m_data, m_size, value);
+ }
+
+ Array(const Array &other)
+ {
+ m_size = other.size();
+ m_allocator = other.m_allocator;
+
+ if (m_size == 0) {
+ m_data = nullptr;
+ return;
+ }
+ else {
+ m_data = this->allocate(m_size);
+ copy_n(other.begin(), m_size, m_data);
+ }
+ }
+
+ Array(Array &&other) noexcept
+ {
+ m_data = other.m_data;
+ m_size = other.m_size;
+ m_allocator = other.m_allocator;
+
+ other.m_data = nullptr;
+ other.m_size = 0;
+ }
+
+ ~Array()
+ {
+ destruct_n(m_data, m_size);
+ if (m_data != nullptr) {
+ m_allocator.deallocate((void *)m_data);
+ }
+ }
+
+ Array &operator=(const Array &other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+
+ this->~Array();
+ new (this) Array(other);
+ return *this;
+ }
+
+ Array &operator=(Array &&other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+
+ this->~Array();
+ new (this) Array(std::move(other));
+ return *this;
+ }
+
+ operator ArrayRef<T>() const
+ {
+ return ArrayRef<T>(m_data, m_size);
+ }
+
+ operator MutableArrayRef<T>()
+ {
+ return MutableArrayRef<T>(m_data, m_size);
+ }
+
+ ArrayRef<T> as_ref() const
+ {
+ return *this;
+ }
+
+ T &operator[](uint index)
+ {
+ BLI_assert(index < m_size);
+ return m_data[index];
+ }
+
+ uint size() const
+ {
+ return m_size;
+ }
+
+ void fill(const T &value)
+ {
+ MutableArrayRef<T>(*this).fill(value);
+ }
+
+ void fill_indices(ArrayRef<uint> indices, const T &value)
+ {
+ MutableArrayRef<T>(*this).fill_indices(indices, value);
+ }
+
+ const T *begin() const
+ {
+ return m_data;
+ }
+
+ const T *end() const
+ {
+ return m_data + m_size;
+ }
+
+ T *begin()
+ {
+ return m_data;
+ }
+
+ T *end()
+ {
+ return m_data + m_size;
+ }
+
+ private:
+ T *allocate(uint size)
+ {
+ return (T *)m_allocator.allocate_aligned(
+ size * sizeof(T), std::alignment_of<T>::value, __func__);
+ }
+};
+
+template<typename T> using TemporaryArray = Array<T, TemporaryAllocator>;
+
+} // namespace BLI
+
+#endif /* __BLI_ARRAY_CXX_H__ */
diff --git a/source/blender/blenlib/BLI_array_ref.h b/source/blender/blenlib/BLI_array_ref.h
new file mode 100644
index 00000000000..e34647676d8
--- /dev/null
+++ b/source/blender/blenlib/BLI_array_ref.h
@@ -0,0 +1,426 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_ARRAY_REF_H__
+#define __BLI_ARRAY_REF_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * These classes offer a convenient way to work with continuous chunks of memory of a certain type.
+ * We differentiate #ArrayRef and #MutableArrayRef. The elements in the former are const while the
+ * elements in the other are not.
+ *
+ * Passing array references as parameters has multiple benefits:
+ * - Less templates are used because the function does not have to work with different
+ * container types.
+ * - It encourages an Struct-of-Arrays data layout which is often beneficial when
+ * writing high performance code. Also it makes it easier to reuse code.
+ * - Array references offer convenient ways of slicing and other operations.
+ *
+ * The instances of #ArrayRef and #MutableArrayRef are very small and should be passed by value.
+ * Since array references do not own any memory, it is generally not save to store them.
+ */
+
+#include <vector>
+#include <array>
+#include <algorithm>
+#include <iostream>
+#include <string>
+
+#include "BLI_utildefines.h"
+#include "BLI_memory_utils_cxx.h"
+#include "BLI_index_range.h"
+
+namespace BLI {
+
+/**
+ * References an array of data. The elements in the array should not be changed.
+ */
+template<typename T> class ArrayRef {
+ private:
+ const T *m_start = nullptr;
+ uint m_size = 0;
+
+ public:
+ /**
+ * Create a reference to an empty array.
+ * The pointer is allowed to be nullptr.
+ */
+ ArrayRef() = default;
+
+ ArrayRef(const T *start, uint size) : m_start(start), m_size(size)
+ {
+ }
+
+ ArrayRef(const std::initializer_list<T> &list) : ArrayRef(list.begin(), list.size())
+ {
+ }
+
+ ArrayRef(const std::vector<T> &vector) : ArrayRef(vector.data(), vector.size())
+ {
+ }
+
+ template<std::size_t N> ArrayRef(const std::array<T, N> &array) : ArrayRef(array.data(), N)
+ {
+ }
+
+ /**
+ * Return a continuous part of the array.
+ * Asserts that the slice stays within the array.
+ */
+ ArrayRef slice(uint start, uint size) const
+ {
+ BLI_assert(start + size <= this->size() || size == 0);
+ return ArrayRef(m_start + start, size);
+ }
+
+ ArrayRef slice(IndexRange range) const
+ {
+ return this->slice(range.start(), range.size());
+ }
+
+ /**
+ * Return a new ArrayRef with n elements removed from the beginning.
+ * Asserts that the array contains enough elements.
+ */
+ ArrayRef drop_front(uint n = 1) const
+ {
+ BLI_assert(n <= this->size());
+ return this->slice(n, this->size() - n);
+ }
+
+ /**
+ * Return a new ArrayRef with n elements removed from the beginning.
+ * Asserts that the array contains enough elements.
+ */
+ ArrayRef drop_back(uint n = 1) const
+ {
+ BLI_assert(n <= this->size());
+ return this->slice(0, this->size() - n);
+ }
+
+ /**
+ * Return a new ArrayRef that only contains the first n elements.
+ * Asserts that the array contains enough elements.
+ */
+ ArrayRef take_front(uint n) const
+ {
+ BLI_assert(n <= this->size());
+ return this->slice(0, n);
+ }
+
+ /**
+ * Return a new ArrayRef that only contains the last n elements.
+ * Asserts that the array contains enough elements.
+ */
+ ArrayRef take_back(uint n) const
+ {
+ BLI_assert(n <= this->size());
+ return this->slice(this->size() - n, n);
+ }
+
+ /**
+ * Copy the values in this array to another array.
+ */
+ void copy_to(T *ptr) const
+ {
+ BLI::copy_n(m_start, m_size, ptr);
+ }
+
+ const T *begin() const
+ {
+ return m_start;
+ }
+
+ const T *end() const
+ {
+ return m_start + m_size;
+ }
+
+ /**
+ * Access an element in the array.
+ * Asserts that the index is in the bounds of the array.
+ */
+ const T &operator[](uint index) const
+ {
+ BLI_assert(index < m_size);
+ return m_start[index];
+ }
+
+ /**
+ * Return the number of elements in the referenced array.
+ */
+ uint size() const
+ {
+ return m_size;
+ }
+
+ /**
+ * Return the number of bytes referenced by this ArrayRef.
+ */
+ uint byte_size() const
+ {
+ return sizeof(T) * m_size;
+ }
+
+ /**
+ * Does a linear search to see of the value is in the array.
+ * Return true if it is, otherwise false.
+ */
+ bool contains(const T &value) const
+ {
+ for (const T &element : *this) {
+ if (element == value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Does a constant time check to see if the pointer is within the referenced array.
+ * Return true if it is, otherwise false.
+ */
+ bool contains_ptr(const T *ptr) const
+ {
+ return (this->begin() <= ptr) && (ptr < this->end());
+ }
+
+ /**
+ * Does a linear search to count how often the value is in the array.
+ * Returns the number of occurrences.
+ */
+ uint count(const T &value) const
+ {
+ uint counter = 0;
+ for (const T &element : *this) {
+ if (element == value) {
+ counter++;
+ }
+ }
+ return counter;
+ }
+
+ /**
+ * Return a reference to the first element in the array.
+ * Asserts that the array is not empty.
+ */
+ const T &first() const
+ {
+ BLI_assert(m_size > 0);
+ return m_start[0];
+ }
+
+ /**
+ * Return a reference to the last element in the array.
+ * Asserts that the array is not empty.
+ */
+ const T &last() const
+ {
+ BLI_assert(m_size > 0);
+ return m_start[m_size - 1];
+ }
+
+ /**
+ * Get element at the given index. If the index is out of range, return the fallback value.
+ */
+ T get(uint index, const T &fallback) const
+ {
+ if (index < m_size) {
+ return m_start[index];
+ }
+ return fallback;
+ }
+
+ /**
+ * Get a new array ref to the same underlying memory buffer. No conversions are done.
+ * Asserts when the sizes of the types don't match.
+ */
+ template<typename NewT> ArrayRef<NewT> cast() const
+ {
+ /* Can be adjusted to allow different type sizes when necessary. */
+ BLI_STATIC_ASSERT(sizeof(T) == sizeof(NewT), "");
+ return ArrayRef<NewT>((NewT *)m_start, m_size);
+ }
+
+ /**
+ * A debug utility to print the content of the array ref. Every element will be printed on a
+ * separate line using the given callback.
+ */
+ template<typename PrintLineF> void print_as_lines(std::string name, PrintLineF print_line) const
+ {
+ std::cout << "ArrayRef: " << name << " \tSize:" << m_size << '\n';
+ for (const T &value : *this) {
+ std::cout << " ";
+ print_line(value);
+ std::cout << '\n';
+ }
+ }
+};
+
+/**
+ * Mostly the same as ArrayRef, except that one can change the array elements via this reference.
+ */
+template<typename T> class MutableArrayRef {
+ private:
+ T *m_start;
+ uint m_size;
+
+ public:
+ MutableArrayRef() = default;
+
+ MutableArrayRef(T *start, uint size) : m_start(start), m_size(size)
+ {
+ }
+
+ MutableArrayRef(std::initializer_list<T> &list) : MutableArrayRef(list.begin(), list.size())
+ {
+ }
+
+ MutableArrayRef(std::vector<T> &vector) : MutableArrayRef(vector.data(), vector.size())
+ {
+ }
+
+ template<std::size_t N>
+ MutableArrayRef(std::array<T, N> &array) : MutableArrayRef(array.data(), N)
+ {
+ }
+
+ operator ArrayRef<T>()
+ {
+ return ArrayRef<T>(m_start, m_size);
+ }
+
+ /**
+ * Get the number of elements in the array.
+ */
+ uint size() const
+ {
+ return m_size;
+ }
+
+ /**
+ * Replace all elements in the referenced array with the given value.
+ */
+ void fill(const T &element)
+ {
+ std::fill_n(m_start, m_size, element);
+ }
+
+ /**
+ * Replace a subset of all elements with the given value.
+ */
+ void fill_indices(ArrayRef<uint> indices, const T &element)
+ {
+ for (uint i : indices) {
+ m_start[i] = element;
+ }
+ }
+
+ /**
+ * Copy the values from another array into the references array.
+ */
+ void copy_from(const T *ptr)
+ {
+ BLI::copy_n(ptr, m_size, m_start);
+ }
+
+ void copy_from(ArrayRef<T> other)
+ {
+ BLI_assert(this->size() == other.size());
+ this->copy_from(other.begin());
+ }
+
+ T *begin() const
+ {
+ return m_start;
+ }
+
+ T *end() const
+ {
+ return m_start + m_size;
+ }
+
+ T &operator[](uint index) const
+ {
+ BLI_assert(index < this->size());
+ return m_start[index];
+ }
+
+ /**
+ * Return a continuous part of the array.
+ * Asserts that the slice stays in the array bounds.
+ */
+ MutableArrayRef slice(uint start, uint length) const
+ {
+ BLI_assert(start + length <= this->size());
+ return MutableArrayRef(m_start + start, length);
+ }
+
+ /**
+ * Return a new MutableArrayRef with n elements removed from the beginning.
+ */
+ MutableArrayRef drop_front(uint n = 1) const
+ {
+ BLI_assert(n <= this->size());
+ return this->slice(n, this->size() - n);
+ }
+
+ /**
+ * Return a new MutableArrayRef with n elements removed from the beginning.
+ */
+ MutableArrayRef drop_back(uint n = 1) const
+ {
+ BLI_assert(n <= this->size());
+ return this->slice(0, this->size() - n);
+ }
+
+ /**
+ * Return a new MutableArrayRef that only contains the first n elements.
+ */
+ MutableArrayRef take_front(uint n) const
+ {
+ BLI_assert(n <= this->size());
+ return this->slice(0, n);
+ }
+
+ /**
+ * Return a new MutableArrayRef that only contains the last n elements.
+ */
+ MutableArrayRef take_back(uint n) const
+ {
+ BLI_assert(n <= this->size());
+ return this->slice(this->size() - n, n);
+ }
+
+ ArrayRef<T> as_ref() const
+ {
+ return ArrayRef<T>(m_start, m_size);
+ }
+};
+
+/**
+ * Shorthand to make use of automatic template parameter deduction.
+ */
+template<typename T> ArrayRef<T> ref_c_array(const T *array, uint size)
+{
+ return ArrayRef<T>(array, size);
+}
+
+} /* namespace BLI */
+
+#endif /* __BLI_ARRAY_REF_H__ */
diff --git a/source/blender/blenlib/BLI_callbacks.h b/source/blender/blenlib/BLI_callbacks.h
deleted file mode 100644
index 4d9fc66a806..00000000000
--- a/source/blender/blenlib/BLI_callbacks.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/** \file
- * \ingroup bli
- */
-
-#ifndef __BLI_CALLBACKS_H__
-#define __BLI_CALLBACKS_H__
-
-struct ID;
-struct Main;
-
-/**
- * Common suffix uses:
- * - ``_PRE/_POST``:
- * For handling discrete non-interactive events.
- * - ``_INIT/_COMPLETE/_CANCEL``:
- * For handling jobs (which may in turn cause other handlers to be called).
- */
-typedef enum {
- BLI_CB_EVT_FRAME_CHANGE_PRE,
- BLI_CB_EVT_FRAME_CHANGE_POST,
- BLI_CB_EVT_RENDER_PRE,
- BLI_CB_EVT_RENDER_POST,
- BLI_CB_EVT_RENDER_WRITE,
- BLI_CB_EVT_RENDER_STATS,
- BLI_CB_EVT_RENDER_INIT,
- BLI_CB_EVT_RENDER_COMPLETE,
- BLI_CB_EVT_RENDER_CANCEL,
- BLI_CB_EVT_LOAD_PRE,
- BLI_CB_EVT_LOAD_POST,
- BLI_CB_EVT_SAVE_PRE,
- BLI_CB_EVT_SAVE_POST,
- BLI_CB_EVT_UNDO_PRE,
- BLI_CB_EVT_UNDO_POST,
- BLI_CB_EVT_REDO_PRE,
- BLI_CB_EVT_REDO_POST,
- BLI_CB_EVT_DEPSGRAPH_UPDATE_PRE,
- BLI_CB_EVT_DEPSGRAPH_UPDATE_POST,
- BLI_CB_EVT_VERSION_UPDATE,
- BLI_CB_EVT_LOAD_FACTORY_USERDEF_POST,
- BLI_CB_EVT_LOAD_FACTORY_STARTUP_POST,
- BLI_CB_EVT_TOT,
-} eCbEvent;
-
-typedef struct bCallbackFuncStore {
- struct bCallbackFuncStore *next, *prev;
- void (*func)(struct Main *, struct ID *, void *arg);
- void *arg;
- short alloc;
-} bCallbackFuncStore;
-
-void BLI_callback_exec(struct Main *bmain, struct ID *self, eCbEvent evt);
-void BLI_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt);
-
-void BLI_callback_global_init(void);
-void BLI_callback_global_finalize(void);
-
-#endif /* __BLI_CALLBACKS_H__ */
diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h
index d8daa81b58d..d78f167a8fd 100644
--- a/source/blender/blenlib/BLI_fileops.h
+++ b/source/blender/blenlib/BLI_fileops.h
@@ -99,8 +99,13 @@ void BLI_filelist_entry_size_to_string(const struct stat *st,
void BLI_filelist_entry_mode_to_string(
const struct stat *st, const bool compact, char r_mode1[], char r_mode2[], char r_mode3[]);
void BLI_filelist_entry_owner_to_string(const struct stat *st, const bool compact, char r_owner[]);
-void BLI_filelist_entry_datetime_to_string(
- const struct stat *st, const int64_t ts, const bool compact, char r_time[], char r_date[]);
+void BLI_filelist_entry_datetime_to_string(const struct stat *st,
+ const int64_t ts,
+ const bool compact,
+ char r_time[],
+ char r_date[],
+ bool *r_is_today,
+ bool *r_is_yesterday);
/* Files */
diff --git a/source/blender/blenlib/BLI_gsqueue.h b/source/blender/blenlib/BLI_gsqueue.h
index 72cd5c7f4ec..4bd53dfddbe 100644
--- a/source/blender/blenlib/BLI_gsqueue.h
+++ b/source/blender/blenlib/BLI_gsqueue.h
@@ -27,12 +27,10 @@
typedef struct _GSQueue GSQueue;
GSQueue *BLI_gsqueue_new(size_t elem_size);
-bool BLI_gsqueue_is_empty(GSQueue *gq);
-int BLI_gsqueue_len(GSQueue *gq);
-void BLI_gsqueue_peek(GSQueue *gq, void *r_item);
+bool BLI_gsqueue_is_empty(const GSQueue *gq);
+size_t BLI_gsqueue_len(const GSQueue *gq);
void BLI_gsqueue_pop(GSQueue *gq, void *r_item);
void BLI_gsqueue_push(GSQueue *gq, const void *item);
-void BLI_gsqueue_push_back(GSQueue *gq, const void *item);
void BLI_gsqueue_free(GSQueue *gq);
#endif /* __BLI_GSQUEUE_H__ */
diff --git a/source/blender/blenlib/BLI_hash_cxx.h b/source/blender/blenlib/BLI_hash_cxx.h
new file mode 100644
index 00000000000..e899f27c9ee
--- /dev/null
+++ b/source/blender/blenlib/BLI_hash_cxx.h
@@ -0,0 +1,111 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_HASH_CXX_H__
+#define __BLI_HASH_CXX_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * This file provides default hash functions for some primitive types. The hash functions can be
+ * used by containers such as Map and Set.
+ */
+
+#include <functional>
+#include <string>
+#include <utility>
+#include <memory>
+
+#include "BLI_utildefines.h"
+#include "BLI_math_base.h"
+
+namespace BLI {
+
+template<typename T> struct DefaultHash {
+};
+
+#define TRIVIAL_DEFAULT_INT_HASH(TYPE) \
+ template<> struct DefaultHash<TYPE> { \
+ uint32_t operator()(TYPE value) const \
+ { \
+ return (uint32_t)value; \
+ } \
+ }
+
+/**
+ * Cannot make any assumptions about the distribution of keys, so use a trivial hash function by
+ * default. The hash table implementations are designed to take all bits of the hash into account
+ * to avoid really bad behavior when the lower bits are all zero. Special hash functions can be
+ * implemented when more knowledge about a specific key distribution is available.
+ */
+TRIVIAL_DEFAULT_INT_HASH(int8_t);
+TRIVIAL_DEFAULT_INT_HASH(uint8_t);
+TRIVIAL_DEFAULT_INT_HASH(int16_t);
+TRIVIAL_DEFAULT_INT_HASH(uint16_t);
+TRIVIAL_DEFAULT_INT_HASH(int32_t);
+TRIVIAL_DEFAULT_INT_HASH(uint32_t);
+TRIVIAL_DEFAULT_INT_HASH(int64_t);
+
+template<> struct DefaultHash<float> {
+ uint32_t operator()(float value) const
+ {
+ return *(uint32_t *)&value;
+ }
+};
+
+template<> struct DefaultHash<std::string> {
+ uint32_t operator()(const std::string &value) const
+ {
+ uint32_t hash = 5381;
+ for (char c : value) {
+ hash = hash * 33 + c;
+ }
+ return hash;
+ }
+};
+
+/**
+ * While we cannot guarantee that the lower 3 bits or a pointer are zero, it is safe to assume
+ * this in the general case. MEM_malloc only returns 8 byte aligned addresses on 64-bit systems.
+ */
+template<typename T> struct DefaultHash<T *> {
+ uint32_t operator()(const T *value) const
+ {
+ uintptr_t ptr = POINTER_AS_UINT(value);
+ uint32_t hash = (uint32_t)(ptr >> 3);
+ return hash;
+ }
+};
+
+template<typename T> struct DefaultHash<std::unique_ptr<T>> {
+ uint32_t operator()(const std::unique_ptr<T> &value) const
+ {
+ return DefaultHash<T *>{}(value.get());
+ }
+};
+
+template<typename T1, typename T2> struct DefaultHash<std::pair<T1, T2>> {
+ uint32_t operator()(const std::pair<T1, T2> &value) const
+ {
+ uint32_t hash1 = DefaultHash<T1>{}(value.first);
+ uint32_t hash2 = DefaultHash<T2>{}(value.second);
+ return hash1 ^ (hash2 * 33);
+ }
+};
+
+} // namespace BLI
+
+#endif /* __BLI_HASH_CXX_H__ */
diff --git a/source/blender/blenlib/BLI_index_range.h b/source/blender/blenlib/BLI_index_range.h
new file mode 100644
index 00000000000..a1fed5bd97c
--- /dev/null
+++ b/source/blender/blenlib/BLI_index_range.h
@@ -0,0 +1,196 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_INDEX_RANGE_H__
+#define __BLI_INDEX_RANGE_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * Allows passing iterators over ranges of integers without actually allocating an array or passing
+ * separate values. A range always has a step of one. If other step sizes are required in some
+ * cases, a separate data structure should be used.
+ */
+
+#include <cmath>
+#include <algorithm>
+#include <iostream>
+
+#include "BLI_utildefines.h"
+
+namespace BLI {
+
+template<typename T> class ArrayRef;
+
+class IndexRange {
+ private:
+ uint m_start = 0;
+ uint m_size = 0;
+
+ public:
+ IndexRange() = default;
+
+ explicit IndexRange(uint size) : m_start(0), m_size(size)
+ {
+ }
+
+ IndexRange(uint start, uint size) : m_start(start), m_size(size)
+ {
+ }
+
+ class Iterator {
+ private:
+ uint m_current;
+
+ public:
+ Iterator(uint current) : m_current(current)
+ {
+ }
+
+ Iterator &operator++()
+ {
+ m_current++;
+ return *this;
+ }
+
+ bool operator!=(const Iterator &iterator) const
+ {
+ return m_current != iterator.m_current;
+ }
+
+ uint operator*() const
+ {
+ return m_current;
+ }
+ };
+
+ Iterator begin() const
+ {
+ return Iterator(m_start);
+ }
+
+ Iterator end() const
+ {
+ return Iterator(m_start + m_size);
+ }
+
+ /**
+ * Access an element in the range.
+ */
+ uint operator[](uint index) const
+ {
+ BLI_assert(index < this->size());
+ return m_start + index;
+ }
+
+ /**
+ * Two ranges compare equal when they contain the same numbers.
+ */
+ friend bool operator==(IndexRange a, IndexRange b)
+ {
+ return (a.m_size == b.m_size) && (a.m_start == b.m_start || a.m_size == 0);
+ }
+
+ /**
+ * Get the amount of numbers in the range.
+ */
+ uint size() const
+ {
+ return m_size;
+ }
+
+ /**
+ * Create a new range starting at the end of the current one.
+ */
+ IndexRange after(uint n) const
+ {
+ return IndexRange(m_start + m_size, n);
+ }
+
+ /**
+ * Create a new range that ends at the start of the current one.
+ */
+ IndexRange before(uint n) const
+ {
+ return IndexRange(m_start - n, n);
+ }
+
+ /**
+ * Get the first element in the range.
+ * Asserts when the range is empty.
+ */
+ uint first() const
+ {
+ BLI_assert(this->size() > 0);
+ return m_start;
+ }
+
+ /**
+ * Get the last element in the range.
+ * Asserts when the range is empty.
+ */
+ uint last() const
+ {
+ BLI_assert(this->size() > 0);
+ return m_start + m_size - 1;
+ }
+
+ /**
+ * Get the element one after the end. The returned value is undefined when the range is empty.
+ */
+ uint one_after_last() const
+ {
+ return m_start + m_size;
+ }
+
+ /**
+ * Get the first element in the range. The returned value is undefined when the range is empty.
+ */
+ uint start() const
+ {
+ return m_start;
+ }
+
+ /**
+ * Returns true when the range contains a certain number, otherwise false.
+ */
+ bool contains(uint value) const
+ {
+ return value >= m_start && value < m_start + m_size;
+ }
+
+ IndexRange slice(uint start, uint size) const
+ {
+ uint new_start = m_start + start;
+ BLI_assert(new_start + size <= m_start + m_size || size == 0);
+ return IndexRange(new_start, size);
+ }
+
+ /**
+ * Get read-only access to a memory buffer that contains the range as actual numbers.
+ */
+ ArrayRef<uint> as_array_ref() const;
+
+ friend std::ostream &operator<<(std::ostream &stream, IndexRange range)
+ {
+ stream << "[" << range.start() << ", " << range.one_after_last() << ")";
+ return stream;
+ }
+};
+
+} // namespace BLI
+
+#endif /* __BLI_INDEX_RANGE_H__ */
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index a348694c4da..b305e919e76 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -24,6 +24,8 @@
* \ingroup bli
*/
+#include "BLI_sys_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -89,6 +91,12 @@ typedef struct BVHTreeRayHit {
enum {
/* Use a priority queue to process nodes in the optimal order (for slow callbacks) */
+ BVH_OVERLAP_USE_THREADING = (1 << 0),
+ BVH_OVERLAP_RETURN_PAIRS = (1 << 1),
+ BVH_OVERLAP_BREAK_ON_FIRST = (1 << 2),
+};
+enum {
+ /* Use a priority queue to process nodes in the optimal order (for slow callbacks) */
BVH_NEAREST_OPTIMAL_ORDER = (1 << 0),
};
enum {
@@ -152,6 +160,14 @@ int BLI_bvhtree_overlap_thread_num(const BVHTree *tree);
/* collision/overlap: check two trees if they overlap,
* alloc's *overlap with length of the int return value */
+BVHTreeOverlap *BLI_bvhtree_overlap_ex(
+ const BVHTree *tree1,
+ const BVHTree *tree2,
+ uint *r_overlap_tot,
+ /* optional callback to test the overlap before adding (must be thread-safe!) */
+ BVHTree_OverlapCallback callback,
+ void *userdata,
+ int flag);
BVHTreeOverlap *BLI_bvhtree_overlap(const BVHTree *tree1,
const BVHTree *tree2,
unsigned int *r_overlap_tot,
@@ -177,6 +193,12 @@ int BLI_bvhtree_find_nearest(BVHTree *tree,
BVHTree_NearestPointCallback callback,
void *userdata);
+int BLI_bvhtree_find_nearest_first(BVHTree *tree,
+ const float co[3],
+ const float dist_sq,
+ BVHTree_NearestPointCallback callback,
+ void *userdata);
+
int BLI_bvhtree_ray_cast_ex(BVHTree *tree,
const float co[3],
const float dir[3],
diff --git a/source/blender/blenlib/BLI_kdtree_impl.h b/source/blender/blenlib/BLI_kdtree_impl.h
index e442bd7a99d..c028266ef64 100644
--- a/source/blender/blenlib/BLI_kdtree_impl.h
+++ b/source/blender/blenlib/BLI_kdtree_impl.h
@@ -21,9 +21,9 @@
#include "BLI_compiler_attrs.h"
-#define _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1##MACRO_ARG2
-#define _CONCAT(MACRO_ARG1, MACRO_ARG2) _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2)
-#define BLI_kdtree_nd_(id) _CONCAT(KDTREE_PREFIX_ID, _##id)
+#define _BLI_CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1##MACRO_ARG2
+#define _BLI_CONCAT(MACRO_ARG1, MACRO_ARG2) _BLI_CONCAT_AUX(MACRO_ARG1, MACRO_ARG2)
+#define BLI_kdtree_nd_(id) _BLI_CONCAT(KDTREE_PREFIX_ID, _##id)
struct KDTree;
typedef struct KDTree KDTree;
@@ -93,6 +93,6 @@ int BLI_kdtree_nd_(range_search_with_len_squared_cb)(
const void *user_data),
const void *user_data) ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
-#undef _CONCAT_AUX
-#undef _CONCAT
+#undef _BLI_CONCAT_AUX
+#undef _BLI_CONCAT
#undef BLI_kdtree_nd_
diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h
index b8b62dd3451..b027acb88da 100644
--- a/source/blender/blenlib/BLI_listbase.h
+++ b/source/blender/blenlib/BLI_listbase.h
@@ -93,6 +93,7 @@ void BLI_listbase_sort_r(ListBase *listbase,
int (*cmp)(void *, const void *, const void *),
void *thunk) ATTR_NONNULL(1, 2);
bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL();
+bool BLI_listbase_move_index(ListBase *listbase, int from, int to) ATTR_NONNULL();
void BLI_freelist(struct ListBase *listbase) ATTR_NONNULL(1);
int BLI_listbase_count_at_most(const struct ListBase *listbase,
const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
diff --git a/source/blender/blenlib/BLI_listbase_wrapper.h b/source/blender/blenlib/BLI_listbase_wrapper.h
new file mode 100644
index 00000000000..34197fe9c45
--- /dev/null
+++ b/source/blender/blenlib/BLI_listbase_wrapper.h
@@ -0,0 +1,100 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_LISTBASE_WRAPPER_H__
+#define __BLI_LISTBASE_WRAPPER_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * The purpose of this wrapper is just to make it more comfortable to iterate of ListBase
+ * instances, that are used in many places in Blender.
+ */
+
+#include "BLI_listbase.h"
+#include "DNA_listBase.h"
+
+namespace BLI {
+
+template<typename T> class IntrusiveListBaseWrapper {
+ private:
+ ListBase *m_listbase;
+
+ public:
+ IntrusiveListBaseWrapper(ListBase *listbase) : m_listbase(listbase)
+ {
+ BLI_assert(listbase);
+ }
+
+ IntrusiveListBaseWrapper(ListBase &listbase) : IntrusiveListBaseWrapper(&listbase)
+ {
+ }
+
+ class Iterator {
+ private:
+ ListBase *m_listbase;
+ T *m_current;
+
+ public:
+ Iterator(ListBase *listbase, T *current) : m_listbase(listbase), m_current(current)
+ {
+ }
+
+ Iterator &operator++()
+ {
+ m_current = m_current->next;
+ return *this;
+ }
+
+ Iterator operator++(int)
+ {
+ Iterator iterator = *this;
+ ++*this;
+ return iterator;
+ }
+
+ bool operator!=(const Iterator &iterator) const
+ {
+ return m_current != iterator.m_current;
+ }
+
+ T *operator*() const
+ {
+ return m_current;
+ }
+ };
+
+ Iterator begin() const
+ {
+ return Iterator(m_listbase, (T *)m_listbase->first);
+ }
+
+ Iterator end() const
+ {
+ return Iterator(m_listbase, nullptr);
+ }
+
+ T get(uint index) const
+ {
+ void *ptr = BLI_findlink(m_listbase, index);
+ BLI_assert(ptr);
+ return (T *)ptr;
+ }
+};
+
+} /* namespace BLI */
+
+#endif /* __BLI_LISTBASE_WRAPPER_H__ */
diff --git a/source/blender/blenlib/BLI_map.h b/source/blender/blenlib/BLI_map.h
new file mode 100644
index 00000000000..1edf7653c71
--- /dev/null
+++ b/source/blender/blenlib/BLI_map.h
@@ -0,0 +1,724 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_MAP_H__
+#define __BLI_MAP_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * This file provides a map implementation that uses open addressing with probing.
+ *
+ * The key and value objects are stored directly in the hash table to avoid indirect memory
+ * lookups. Keys and values are stored in groups of four to avoid wasting memory due to padding.
+ */
+
+#include "BLI_hash_cxx.h"
+#include "BLI_array_ref.h"
+#include "BLI_open_addressing.h"
+
+namespace BLI {
+
+// clang-format off
+
+#define ITER_SLOTS_BEGIN(KEY, ARRAY, OPTIONAL_CONST, R_ITEM, R_OFFSET) \
+ uint32_t hash = DefaultHash<KeyT>{}(KEY); \
+ uint32_t perturb = hash; \
+ while (true) { \
+ uint32_t item_index = (hash & ARRAY.slot_mask()) >> OFFSET_SHIFT; \
+ uint8_t R_OFFSET = hash & OFFSET_MASK; \
+ uint8_t initial_offset = R_OFFSET; \
+ OPTIONAL_CONST Item &R_ITEM = ARRAY.item(item_index); \
+ do {
+
+#define ITER_SLOTS_END(R_OFFSET) \
+ R_OFFSET = (R_OFFSET + 1u) & OFFSET_MASK; \
+ } while (R_OFFSET != initial_offset); \
+ perturb >>= 5; \
+ hash = hash * 5 + 1 + perturb; \
+ } ((void)0)
+
+// clang-format on
+
+template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator> class Map {
+ private:
+ static constexpr uint OFFSET_MASK = 3;
+ static constexpr uint OFFSET_SHIFT = 2;
+
+ class Item {
+ private:
+ static constexpr uint8_t IS_EMPTY = 0;
+ static constexpr uint8_t IS_SET = 1;
+ static constexpr uint8_t IS_DUMMY = 2;
+
+ uint8_t m_status[4];
+ char m_keys[4 * sizeof(KeyT)];
+ char m_values[4 * sizeof(ValueT)];
+
+ public:
+ static constexpr uint slots_per_item = 4;
+
+ Item()
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ m_status[offset] = IS_EMPTY;
+ }
+ }
+
+ ~Item()
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ if (m_status[offset] == IS_SET) {
+ this->key(offset)->~KeyT();
+ this->value(offset)->~ValueT();
+ }
+ }
+ }
+
+ Item(const Item &other)
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ uint8_t status = other.m_status[offset];
+ m_status[offset] = status;
+ if (status == IS_SET) {
+ new (this->key(offset)) KeyT(*other.key(offset));
+ new (this->value(offset)) ValueT(*other.value(offset));
+ }
+ }
+ }
+
+ Item(Item &&other) noexcept
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ uint8_t status = other.m_status[offset];
+ m_status[offset] = status;
+ if (status == IS_SET) {
+ new (this->key(offset)) KeyT(std::move(*other.key(offset)));
+ new (this->value(offset)) ValueT(std::move(*other.value(offset)));
+ }
+ }
+ }
+
+ bool has_key(uint offset, const KeyT &key) const
+ {
+ return m_status[offset] == IS_SET && key == *this->key(offset);
+ }
+
+ bool is_set(uint offset) const
+ {
+ return m_status[offset] == IS_SET;
+ }
+
+ bool is_empty(uint offset) const
+ {
+ return m_status[offset] == IS_EMPTY;
+ }
+
+ bool is_dummy(uint offset) const
+ {
+ return m_status[offset] == IS_DUMMY;
+ }
+
+ KeyT *key(uint offset) const
+ {
+ return (KeyT *)(m_keys + offset * sizeof(KeyT));
+ }
+
+ ValueT *value(uint offset) const
+ {
+ return (ValueT *)(m_values + offset * sizeof(ValueT));
+ }
+
+ template<typename ForwardKeyT, typename ForwardValueT>
+ void store(uint offset, ForwardKeyT &&key, ForwardValueT &&value)
+ {
+ BLI_assert(m_status[offset] != IS_SET);
+ m_status[offset] = IS_SET;
+ new (this->key(offset)) KeyT(std::forward<ForwardKeyT>(key));
+ new (this->value(offset)) ValueT(std::forward<ForwardValueT>(value));
+ }
+
+ template<typename ForwardKeyT> void store_without_value(uint offset, ForwardKeyT &&key)
+ {
+ BLI_assert(m_status[offset] != IS_SET);
+ m_status[offset] = IS_SET;
+ new (this->key(offset)) KeyT(std::forward<ForwardKeyT>(key));
+ }
+
+ void set_dummy(uint offset)
+ {
+ BLI_assert(m_status[offset] == IS_SET);
+ m_status[offset] = IS_DUMMY;
+ destruct(this->key(offset));
+ destruct(this->value(offset));
+ }
+ };
+
+ using ArrayType = OpenAddressingArray<Item, 1, Allocator>;
+ ArrayType m_array;
+
+ public:
+ Map() = default;
+
+ /**
+ * Allocate memory such that at least min_usable_slots can be added before the map has to grow
+ * again.
+ */
+ void reserve(uint min_usable_slots)
+ {
+ if (m_array.slots_usable() < min_usable_slots) {
+ this->grow(min_usable_slots);
+ }
+ }
+
+ /**
+ * Remove all elements from the map.
+ */
+ void clear()
+ {
+ this->~Map();
+ new (this) Map();
+ }
+
+ /**
+ * Insert a new key-value-pair in the map.
+ * Asserts when the key existed before.
+ */
+ void add_new(const KeyT &key, const ValueT &value)
+ {
+ this->add_new__impl(key, value);
+ }
+ void add_new(const KeyT &key, ValueT &&value)
+ {
+ this->add_new__impl(key, std::move(value));
+ }
+ void add_new(KeyT &&key, const ValueT &value)
+ {
+ this->add_new__impl(std::move(key), value);
+ }
+ void add_new(KeyT &&key, ValueT &&value)
+ {
+ this->add_new__impl(std::move(key), std::move(value));
+ }
+
+ /**
+ * Insert a new key-value-pair in the map if the key does not exist yet.
+ * Returns true when the pair was newly inserted, otherwise false.
+ */
+ bool add(const KeyT &key, const ValueT &value)
+ {
+ return this->add__impl(key, value);
+ }
+ bool add(const KeyT &key, ValueT &&value)
+ {
+ return this->add__impl(key, std::move(value));
+ }
+ bool add(KeyT &&key, const ValueT &value)
+ {
+ return this->add__impl(std::move(key), value);
+ }
+ bool add(KeyT &&key, ValueT &&value)
+ {
+ return this->add__impl(std::move(key), std::move(value));
+ }
+
+ /**
+ * Remove the key from the map.
+ * Asserts when the key does not exist in the map.
+ */
+ void remove(const KeyT &key)
+ {
+ BLI_assert(this->contains(key));
+ ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
+ if (item.has_key(offset, key)) {
+ item.set_dummy(offset);
+ m_array.update__set_to_dummy();
+ return;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ /**
+ * Get the value for the given key and remove it from the map.
+ * Asserts when the key does not exist in the map.
+ */
+ ValueT pop(const KeyT &key)
+ {
+ BLI_assert(this->contains(key));
+ ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
+ if (item.has_key(offset, key)) {
+ ValueT value = std::move(*item.value(offset));
+ item.set_dummy(offset);
+ m_array.update__set_to_dummy();
+ return value;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ /**
+ * Returns true when the key exists in the map, otherwise false.
+ */
+ bool contains(const KeyT &key) const
+ {
+ ITER_SLOTS_BEGIN (key, m_array, const, item, offset) {
+ if (item.is_empty(offset)) {
+ return false;
+ }
+ else if (item.has_key(offset, key)) {
+ return true;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ /**
+ * First, checks if the key exists in the map.
+ * If it does exist, call the modify function with a pointer to the corresponding value.
+ * If it does not exist, call the create function with a pointer to where the value should be
+ * created.
+ *
+ * Returns whatever is returned from one of the callback functions. Both callbacks have to return
+ * the same type.
+ *
+ * CreateValueF: Takes a pointer to where the value should be created.
+ * ModifyValueF: Takes a pointer to the value that should be modified.
+ */
+ template<typename CreateValueF, typename ModifyValueF>
+ auto add_or_modify(const KeyT &key,
+ const CreateValueF &create_value,
+ const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
+ {
+ return this->add_or_modify__impl(key, create_value, modify_value);
+ }
+ template<typename CreateValueF, typename ModifyValueF>
+ auto add_or_modify(KeyT &&key,
+ const CreateValueF &create_value,
+ const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
+ {
+ return this->add_or_modify__impl(std::move(key), create_value, modify_value);
+ }
+
+ /**
+ * Similar to add, but overrides the value for the key when it exists already.
+ */
+ bool add_override(const KeyT &key, const ValueT &value)
+ {
+ return this->add_override__impl(key, value);
+ }
+ bool add_override(const KeyT &key, ValueT &&value)
+ {
+ return this->add_override__impl(key, std::move(value));
+ }
+ bool add_override(KeyT &&key, const ValueT &value)
+ {
+ return this->add_override__impl(std::move(key), value);
+ }
+ bool add_override(KeyT &&key, ValueT &&value)
+ {
+ return this->add_override__impl(std::move(key), std::move(value));
+ }
+
+ /**
+ * Check if the key exists in the map.
+ * Return a pointer to the value, when it exists.
+ * Otherwise return nullptr.
+ */
+ const ValueT *lookup_ptr(const KeyT &key) const
+ {
+ ITER_SLOTS_BEGIN (key, m_array, const, item, offset) {
+ if (item.is_empty(offset)) {
+ return nullptr;
+ }
+ else if (item.has_key(offset, key)) {
+ return item.value(offset);
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ /**
+ * Lookup the value that corresponds to the key.
+ * Asserts when the key does not exist.
+ */
+ const ValueT &lookup(const KeyT &key) const
+ {
+ const ValueT *ptr = this->lookup_ptr(key);
+ BLI_assert(ptr != nullptr);
+ return *ptr;
+ }
+
+ ValueT *lookup_ptr(const KeyT &key)
+ {
+ const Map *const_this = this;
+ return const_cast<ValueT *>(const_this->lookup_ptr(key));
+ }
+
+ ValueT &lookup(const KeyT &key)
+ {
+ const Map *const_this = this;
+ return const_cast<ValueT &>(const_this->lookup(key));
+ }
+
+ /**
+ * Check if the key exists in the map.
+ * If it does, return a copy of the value.
+ * Otherwise, return the default value.
+ */
+ ValueT lookup_default(const KeyT &key, ValueT default_value) const
+ {
+ const ValueT *ptr = this->lookup_ptr(key);
+ if (ptr != nullptr) {
+ return *ptr;
+ }
+ else {
+ return default_value;
+ }
+ }
+
+ /**
+ * Return the value that corresponds to the given key.
+ * If it does not exist yet, create and insert it first.
+ */
+ template<typename CreateValueF>
+ ValueT &lookup_or_add(const KeyT &key, const CreateValueF &create_value)
+ {
+ return this->lookup_or_add__impl(key, create_value);
+ }
+ template<typename CreateValueF>
+ ValueT &lookup_or_add(KeyT &&key, const CreateValueF &create_value)
+ {
+ return this->lookup_or_add__impl(std::move(key), create_value);
+ }
+
+ /**
+ * Get the number of elements in the map.
+ */
+ uint32_t size() const
+ {
+ return m_array.slots_set();
+ }
+
+ void print_table() const
+ {
+ std::cout << "Hash Table:\n";
+ std::cout << " Size: " << m_array.slots_set() << '\n';
+ std::cout << " Capacity: " << m_array.slots_total() << '\n';
+ uint32_t item_index = 0;
+ for (const Item &item : m_array) {
+ std::cout << " Item: " << item_index++ << '\n';
+ for (uint offset = 0; offset < 4; offset++) {
+ std::cout << " " << offset << " \t";
+ if (item.is_empty(offset)) {
+ std::cout << " <empty>\n";
+ }
+ else if (item.is_set(offset)) {
+ const KeyT &key = *item.key(offset);
+ const ValueT &value = *item.value(offset);
+ uint32_t collisions = this->count_collisions(key);
+ std::cout << " " << key << " -> " << value << " \t Collisions: " << collisions
+ << '\n';
+ }
+ else if (item.is_dummy(offset)) {
+ std::cout << " <dummy>\n";
+ }
+ }
+ }
+ }
+
+ template<typename SubIterator> class BaseIterator {
+ protected:
+ const Map *m_map;
+ uint32_t m_slot;
+
+ public:
+ BaseIterator(const Map *map, uint32_t slot) : m_map(map), m_slot(slot)
+ {
+ }
+
+ BaseIterator &operator++()
+ {
+ m_slot = m_map->next_slot(m_slot + 1);
+ return *this;
+ }
+
+ friend bool operator==(const BaseIterator &a, const BaseIterator &b)
+ {
+ BLI_assert(a.m_map == b.m_map);
+ return a.m_slot == b.m_slot;
+ }
+
+ friend bool operator!=(const BaseIterator &a, const BaseIterator &b)
+ {
+ return !(a == b);
+ }
+
+ SubIterator begin() const
+ {
+ return SubIterator(m_map, m_map->next_slot(0));
+ }
+
+ SubIterator end() const
+ {
+ return SubIterator(m_map, m_map->m_array.slots_total());
+ }
+ };
+
+ class KeyIterator final : public BaseIterator<KeyIterator> {
+ public:
+ KeyIterator(const Map *map, uint32_t slot) : BaseIterator<KeyIterator>(map, slot)
+ {
+ }
+
+ const KeyT &operator*() const
+ {
+ uint32_t item_index = this->m_slot >> OFFSET_SHIFT;
+ uint offset = this->m_slot & OFFSET_MASK;
+ const Item &item = this->m_map->m_array.item(item_index);
+ BLI_assert(item.is_set(offset));
+ return *item.key(offset);
+ }
+ };
+
+ class ValueIterator final : public BaseIterator<ValueIterator> {
+ public:
+ ValueIterator(const Map *map, uint32_t slot) : BaseIterator<ValueIterator>(map, slot)
+ {
+ }
+
+ ValueT &operator*() const
+ {
+ uint32_t item_index = this->m_slot >> OFFSET_SHIFT;
+ uint offset = this->m_slot & OFFSET_MASK;
+ const Item &item = this->m_map->m_array.item(item_index);
+ BLI_assert(item.is_set(offset));
+ return *item.value(offset);
+ }
+ };
+
+ class ItemIterator final : public BaseIterator<ItemIterator> {
+ public:
+ ItemIterator(const Map *map, uint32_t slot) : BaseIterator<ItemIterator>(map, slot)
+ {
+ }
+
+ struct UserItem {
+ const KeyT &key;
+ ValueT &value;
+
+ friend std::ostream &operator<<(std::ostream &stream, const Item &item)
+ {
+ stream << item.key << " -> " << item.value;
+ return stream;
+ }
+ };
+
+ UserItem operator*() const
+ {
+ uint32_t item_index = this->m_slot >> OFFSET_SHIFT;
+ uint offset = this->m_slot & OFFSET_MASK;
+ const Item &item = this->m_map->m_array.item(item_index);
+ BLI_assert(item.is_set(offset));
+ return {*item.key(offset), *item.value(offset)};
+ }
+ };
+
+ template<typename SubIterator> friend class BaseIterator;
+
+ /**
+ * Iterate over all keys in the map.
+ */
+ KeyIterator keys() const
+ {
+ return KeyIterator(this, 0);
+ }
+
+ /**
+ * Iterate over all values in the map.
+ */
+ ValueIterator values() const
+ {
+ return ValueIterator(this, 0);
+ }
+
+ /**
+ * Iterate over all key-value-pairs in the map.
+ * They can be accessed with item.key and item.value.
+ */
+ ItemIterator items() const
+ {
+ return ItemIterator(this, 0);
+ }
+
+ private:
+ uint32_t next_slot(uint32_t slot) const
+ {
+ for (; slot < m_array.slots_total(); slot++) {
+ uint32_t item_index = slot >> OFFSET_SHIFT;
+ uint offset = slot & OFFSET_MASK;
+ const Item &item = m_array.item(item_index);
+ if (item.is_set(offset)) {
+ return slot;
+ }
+ }
+ return slot;
+ }
+
+ uint32_t count_collisions(const KeyT &key) const
+ {
+ uint32_t collisions = 0;
+ ITER_SLOTS_BEGIN (key, m_array, const, item, offset) {
+ if (item.is_empty(offset) || item.has_key(offset, key)) {
+ return collisions;
+ }
+ collisions++;
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ void ensure_can_add()
+ {
+ if (UNLIKELY(m_array.should_grow())) {
+ this->grow(this->size() + 1);
+ }
+ }
+
+ BLI_NOINLINE void grow(uint32_t min_usable_slots)
+ {
+ ArrayType new_array = m_array.init_reserved(min_usable_slots);
+ for (Item &old_item : m_array) {
+ for (uint offset = 0; offset < 4; offset++) {
+ if (old_item.is_set(offset)) {
+ this->add_after_grow(*old_item.key(offset), *old_item.value(offset), new_array);
+ }
+ }
+ }
+ m_array = std::move(new_array);
+ }
+
+ void add_after_grow(KeyT &key, ValueT &value, ArrayType &new_array)
+ {
+ ITER_SLOTS_BEGIN (key, new_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, std::move(key), std::move(value));
+ return;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ template<typename ForwardKeyT, typename ForwardValueT>
+ bool add_override__impl(ForwardKeyT &&key, ForwardValueT &&value)
+ {
+ return this->add_or_modify(
+ std::forward<ForwardKeyT>(key),
+ [&](ValueT *dst) {
+ new (dst) ValueT(std::forward<ForwardValueT>(value));
+ return true;
+ },
+ [&](ValueT *old_value) {
+ *old_value = std::forward<ForwardValueT>(value);
+ return false;
+ });
+ }
+
+ template<typename ForwardKeyT, typename ForwardValueT>
+ bool add__impl(ForwardKeyT &&key, ForwardValueT &&value)
+ {
+ this->ensure_can_add();
+
+ ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, std::forward<ForwardKeyT>(key), std::forward<ForwardValueT>(value));
+ m_array.update__empty_to_set();
+ return true;
+ }
+ else if (item.has_key(offset, key)) {
+ return false;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ template<typename ForwardKeyT, typename ForwardValueT>
+ void add_new__impl(ForwardKeyT &&key, ForwardValueT &&value)
+ {
+ BLI_assert(!this->contains(key));
+ this->ensure_can_add();
+
+ ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, std::forward<ForwardKeyT>(key), std::forward<ForwardValueT>(value));
+ m_array.update__empty_to_set();
+ return;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ template<typename ForwardKeyT, typename CreateValueF, typename ModifyValueF>
+ auto add_or_modify__impl(ForwardKeyT &&key,
+ const CreateValueF &create_value,
+ const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
+ {
+ using CreateReturnT = decltype(create_value(nullptr));
+ using ModifyReturnT = decltype(modify_value(nullptr));
+ BLI_STATIC_ASSERT((std::is_same<CreateReturnT, ModifyReturnT>::value),
+ "Both callbacks should return the same type.");
+
+ this->ensure_can_add();
+
+ ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ m_array.update__empty_to_set();
+ item.store_without_value(offset, std::forward<ForwardKeyT>(key));
+ ValueT *value_ptr = item.value(offset);
+ return create_value(value_ptr);
+ }
+ else if (item.has_key(offset, key)) {
+ ValueT *value_ptr = item.value(offset);
+ return modify_value(value_ptr);
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ template<typename ForwardKeyT, typename CreateValueF>
+ ValueT &lookup_or_add__impl(ForwardKeyT &&key, const CreateValueF &create_value)
+ {
+ this->ensure_can_add();
+
+ ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, std::forward<ForwardKeyT>(key), create_value());
+ m_array.update__empty_to_set();
+ return *item.value(offset);
+ }
+ else if (item.has_key(offset, key)) {
+ return *item.value(offset);
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+};
+
+#undef ITER_SLOTS_BEGIN
+#undef ITER_SLOTS_END
+
+} // namespace BLI
+
+#endif /* __BLI_MAP_H__ */
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index deb29605552..4f841f75d3a 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -121,6 +121,9 @@ MINLINE float max_fff(float a, float b, float c);
MINLINE float min_ffff(float a, float b, float c, float d);
MINLINE float max_ffff(float a, float b, float c, float d);
+MINLINE double min_dd(double a, double b);
+MINLINE double max_dd(double a, double b);
+
MINLINE int min_ii(int a, int b);
MINLINE int max_ii(int a, int b);
MINLINE int min_iii(int a, int b, int c);
@@ -155,6 +158,8 @@ MINLINE int power_of_2_min_i(int n);
MINLINE unsigned int power_of_2_max_u(unsigned int x);
MINLINE unsigned int power_of_2_min_u(unsigned int x);
+MINLINE unsigned int log2_floor_u(unsigned int x);
+MINLINE unsigned int log2_ceil_u(unsigned int x);
MINLINE int divide_round_i(int a, int b);
MINLINE int mod_i(int i, int n);
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 39b1b96d009..87517ebe060 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -188,6 +188,10 @@ float dist_squared_to_projected_aabb_simple(const float projmat[4][4],
const float bbmax[3]);
float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2]);
+double closest_to_line_v2_db(double r_close[2],
+ const double p[2],
+ const double l1[2],
+ const double l2[2]);
float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3]);
void closest_to_line_segment_v2(float r_close[2],
const float p[2],
@@ -267,7 +271,12 @@ bool isect_seg_seg_v2_simple(const float v1[2],
const float v2[2],
const float v3[2],
const float v4[2]);
-
+int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
+ const double v2[2],
+ const double v3[2],
+ const double v4[2],
+ double *r_lambda,
+ double *r_mu);
int isect_line_sphere_v3(const float l1[3],
const float l2[3],
const float sp[3],
@@ -302,7 +311,13 @@ bool isect_line_line_strict_v3(const float v1[3],
const float v4[3],
float vi[3],
float *r_lambda);
-
+bool isect_ray_ray_epsilon_v3(const float ray_origin_a[3],
+ const float ray_direction_a[3],
+ const float ray_origin_b[3],
+ const float ray_direction_b[3],
+ const float epsilon,
+ float *r_lambda_a,
+ float *r_lambda_b);
bool isect_ray_ray_v3(const float ray_origin_a[3],
const float ray_direction_a[3],
const float ray_origin_b[3],
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index f5d87667b73..814b13fa47f 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -252,6 +252,9 @@ void normalize_m4_m4(float R[4][4], const float A[4][4]) ATTR_NONNULL();
void orthogonalize_m3(float R[3][3], int axis);
void orthogonalize_m4(float R[4][4], int axis);
+void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize);
+void orthogonalize_m4_stable(float R[4][4], int axis, bool normalize);
+
bool is_orthogonal_m3(const float mat[3][3]);
bool is_orthogonal_m4(const float mat[4][4]);
bool is_orthonormal_m3(const float mat[3][3]);
@@ -303,8 +306,11 @@ void size_to_mat4(float R[4][4], const float size[3]);
void mat3_to_size(float r[3], const float M[3][3]);
void mat4_to_size(float r[3], const float M[4][4]);
+void mat4_to_size_fix_shear(float r[3], const float M[4][4]);
+
void translate_m4(float mat[4][4], float tx, float ty, float tz);
void rotate_m4(float mat[4][4], const char axis, const float angle);
+void rescale_m4(float mat[4][4], const float scale[3]);
void transform_pivot_set_m4(float mat[4][4], const float pivot[3]);
void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]);
@@ -314,6 +320,10 @@ void mat4_decompose(float loc[3], float quat[4], float size[3], const float wmat
void mat3_polar_decompose(const float mat3[3][3], float r_U[3][3], float r_P[3][3]);
+void loc_rot_size_to_mat4(float R[4][4],
+ const float loc[3],
+ const float rot[3][3],
+ const float size[3]);
void loc_eul_size_to_mat4(float R[4][4],
const float loc[3],
const float eul[3],
diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h
index 7a4ac14970f..1e56b80bcf2 100644
--- a/source/blender/blenlib/BLI_math_rotation.h
+++ b/source/blender/blenlib/BLI_math_rotation.h
@@ -96,6 +96,8 @@ void rotation_between_vecs_to_mat3(float m[3][3], const float v1[3], const float
void rotation_between_vecs_to_quat(float q[4], const float v1[3], const float v2[3]);
void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q2[4]);
+float quat_split_swing_and_twist(const float q[4], int axis, float r_swing[4], float r_twist[4]);
+
float angle_normalized_qt(const float q[4]);
float angle_normalized_qtqt(const float q1[4], const float q2[4]);
float angle_qt(const float q[4]);
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index ccb42683d5a..31d725af5ad 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -103,6 +103,7 @@ MINLINE void add_v2_fl(float r[2], float f);
MINLINE void add_v3_fl(float r[3], float f);
MINLINE void add_v4_fl(float r[4], float f);
MINLINE void add_v2_v2(float r[2], const float a[2]);
+MINLINE void add_v2_v2_db(double r[2], const double a[2]);
MINLINE void add_v2_v2v2(float r[2], const float a[2], const float b[2]);
MINLINE void add_v2_v2v2_int(int r[2], const int a[2], const int b[2]);
MINLINE void add_v3_v3(float r[3], const float a[3]);
@@ -116,6 +117,7 @@ MINLINE void add_v3fl_v3fl_v3s(float r[3], const float a[3], const short b[3]);
MINLINE void sub_v2_v2(float r[2], const float a[2]);
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2]);
+MINLINE void sub_v2_v2v2_db(double r[2], const double a[2], const double b[2]);
MINLINE void sub_v2_v2v2_int(int r[2], const int a[2], const int b[2]);
MINLINE void sub_v3_v3(float r[3], const float a[3]);
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3]);
@@ -184,6 +186,7 @@ MINLINE void abs_v4(float r[4]);
MINLINE void abs_v4_v4(float r[4], const float a[4]);
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
+MINLINE double dot_v2v2_db(const double a[2], const double b[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_v3v3v3(const float p[3],
const float a[3],
@@ -212,8 +215,10 @@ MINLINE int len_manhattan_v2_int(const int v[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE float len_manhattan_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float len_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE float len_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
+MINLINE double len_v2v2_db(const double a[2], const double b[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE float len_v2v2_int(const int v1[2], const int v2[2]);
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
+MINLINE double len_squared_v2v2_db(const double a[2], const double b[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float len_squared_v4v4(const float a[4], const float b[4]) ATTR_WARN_UNUSED_RESULT;
MINLINE float len_manhattan_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/blenlib/BLI_memblock.h b/source/blender/blenlib/BLI_memblock.h
index c5ef26ffb91..8bd8642a4e8 100644
--- a/source/blender/blenlib/BLI_memblock.h
+++ b/source/blender/blenlib/BLI_memblock.h
@@ -30,16 +30,20 @@ extern "C" {
#include "BLI_compiler_attrs.h"
+#define BLI_MEM_BLOCK_CHUNK_SIZE (1 << 15) /* 32KiB */
+
struct BLI_memblock;
typedef struct BLI_memblock BLI_memblock;
typedef void (*MemblockValFreeFP)(void *val);
-BLI_memblock *BLI_memblock_create(uint elem_size) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-void *BLI_memblock_alloc(BLI_memblock *mblk) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+BLI_memblock *BLI_memblock_create_ex(uint elem_size, uint chunk_size) ATTR_WARN_UNUSED_RESULT;
+void *BLI_memblock_alloc(BLI_memblock *mblk) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void BLI_memblock_clear(BLI_memblock *mblk, MemblockValFreeFP valfreefp) ATTR_NONNULL(1);
void BLI_memblock_destroy(BLI_memblock *mblk, MemblockValFreeFP free_callback) ATTR_NONNULL(1);
+#define BLI_memblock_create(elem_size) BLI_memblock_create_ex(elem_size, BLI_MEM_BLOCK_CHUNK_SIZE)
+
typedef struct BLI_memblock_iter {
void **chunk_list;
int cur_index;
@@ -53,6 +57,9 @@ typedef struct BLI_memblock_iter {
void BLI_memblock_iternew(BLI_memblock *pool, BLI_memblock_iter *iter) ATTR_NONNULL();
void *BLI_memblock_iterstep(BLI_memblock_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL();
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_memory_utils_cxx.h b/source/blender/blenlib/BLI_memory_utils_cxx.h
new file mode 100644
index 00000000000..22f333c6303
--- /dev/null
+++ b/source/blender/blenlib/BLI_memory_utils_cxx.h
@@ -0,0 +1,84 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_MEMORY_UTILS_CXX_H__
+#define __BLI_MEMORY_UTILS_CXX_H__
+
+/** \file
+ * \ingroup bli
+ */
+
+#include <memory>
+#include <algorithm>
+
+namespace BLI {
+
+using std::copy;
+using std::copy_n;
+using std::uninitialized_copy;
+using std::uninitialized_copy_n;
+using std::uninitialized_fill;
+using std::uninitialized_fill_n;
+
+template<typename T> void destruct(T *ptr)
+{
+ ptr->~T();
+}
+
+template<typename T> void destruct_n(T *ptr, uint n)
+{
+ for (uint i = 0; i < n; i++) {
+ ptr[i].~T();
+ }
+}
+
+template<typename T> void uninitialized_move_n(T *src, uint n, T *dst)
+{
+ std::uninitialized_copy_n(std::make_move_iterator(src), n, dst);
+}
+
+template<typename T> void move_n(T *src, uint n, T *dst)
+{
+ std::copy_n(std::make_move_iterator(src), n, dst);
+}
+
+template<typename T> void uninitialized_relocate(T *src, T *dst)
+{
+ new (dst) T(std::move(*src));
+ destruct(src);
+}
+
+template<typename T> void uninitialized_relocate_n(T *src, uint n, T *dst)
+{
+ uninitialized_move_n(src, n, dst);
+ destruct_n(src, n);
+}
+
+template<typename T> void relocate(T *src, T *dst)
+{
+ *dst = std::move(*src);
+ destruct(src);
+}
+
+template<typename T> void relocate_n(T *src, uint n, T *dst)
+{
+ move_n(src, n, dst);
+ destruct_n(src, n);
+}
+
+} // namespace BLI
+
+#endif /* __BLI_MEMORY_UTILS_CXX_H__ */
diff --git a/source/blender/blenlib/BLI_open_addressing.h b/source/blender/blenlib/BLI_open_addressing.h
new file mode 100644
index 00000000000..8ca5156a952
--- /dev/null
+++ b/source/blender/blenlib/BLI_open_addressing.h
@@ -0,0 +1,305 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_OPEN_ADDRESSING_H__
+#define __BLI_OPEN_ADDRESSING_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * This class offers a useful abstraction for other containers that implement hash tables using
+ * open addressing. It handles the following aspects:
+ * - Allocation and deallocation of the open addressing array.
+ * - Optional small object optimization.
+ * - Keeps track of how many elements and dummies are in the table.
+ *
+ * The nice thing about this abstraction is that it does not get in the way of any performance
+ * optimizations. The data that is actually stored in the table is still fully defined by the
+ * actual hash table implementation.
+ */
+
+#include <cmath>
+
+#include "BLI_utildefines.h"
+#include "BLI_memory_utils_cxx.h"
+#include "BLI_math_base.h"
+#include "BLI_allocator.h"
+
+namespace BLI {
+
+template<typename Item, uint32_t ItemsInSmallStorage = 1, typename Allocator = GuardedAllocator>
+class OpenAddressingArray {
+ private:
+ static constexpr uint32_t slots_per_item = Item::slots_per_item;
+ static constexpr float max_load_factor = 0.5f;
+
+ /* Invariants:
+ * 2^m_item_exponent = m_item_amount
+ * m_item_amount * slots_per_item = m_slots_total
+ * m_slot_mask = m_slots_total - 1
+ * m_slots_set_or_dummy < m_slots_total
+ */
+
+ /* Array containing the actual hash table. Might be a pointer to the inlined storage. */
+ Item *m_items;
+ /* Number of items in the hash table. Must be a power of two. */
+ uint32_t m_item_amount;
+ /* Exponent of the current item amount. */
+ uint8_t m_item_exponent;
+ /* Number of elements that could be stored in the table when the load factor is 1. */
+ uint32_t m_slots_total;
+ /* Number of elements that are not empty. */
+ uint32_t m_slots_set_or_dummy;
+ /* Number of dummy entries. */
+ uint32_t m_slots_dummy;
+ /* Max number of slots that can be non-empty according to the load factor. */
+ uint32_t m_slots_usable;
+ /* Can be used to map a hash value into the range of valid slot indices. */
+ uint32_t m_slot_mask;
+ Allocator m_allocator;
+ char m_local_storage[sizeof(Item) * ItemsInSmallStorage];
+
+ public:
+ explicit OpenAddressingArray(uint8_t item_exponent = 0)
+ {
+ m_slots_total = ((uint32_t)1 << item_exponent) * slots_per_item;
+ m_slots_set_or_dummy = 0;
+ m_slots_dummy = 0;
+ m_slots_usable = (uint32_t)((float)m_slots_total * max_load_factor);
+ m_slot_mask = m_slots_total - 1;
+ m_item_amount = m_slots_total / slots_per_item;
+ m_item_exponent = item_exponent;
+
+ if (m_item_amount <= ItemsInSmallStorage) {
+ m_items = this->small_storage();
+ }
+ else {
+ m_items = (Item *)m_allocator.allocate_aligned(
+ (uint32_t)sizeof(Item) * m_item_amount, std::alignment_of<Item>::value, __func__);
+ }
+
+ for (uint32_t i = 0; i < m_item_amount; i++) {
+ new (m_items + i) Item();
+ }
+ }
+
+ ~OpenAddressingArray()
+ {
+ if (m_items != nullptr) {
+ for (uint32_t i = 0; i < m_item_amount; i++) {
+ m_items[i].~Item();
+ }
+ if (!this->is_in_small_storage()) {
+ m_allocator.deallocate((void *)m_items);
+ }
+ }
+ }
+
+ OpenAddressingArray(const OpenAddressingArray &other)
+ {
+ m_slots_total = other.m_slots_total;
+ m_slots_set_or_dummy = other.m_slots_set_or_dummy;
+ m_slots_dummy = other.m_slots_dummy;
+ m_slots_usable = other.m_slots_usable;
+ m_slot_mask = other.m_slot_mask;
+ m_item_amount = other.m_item_amount;
+ m_item_exponent = other.m_item_exponent;
+
+ if (m_item_amount <= ItemsInSmallStorage) {
+ m_items = this->small_storage();
+ }
+ else {
+ m_items = (Item *)m_allocator.allocate_aligned(
+ sizeof(Item) * m_item_amount, std::alignment_of<Item>::value, __func__);
+ }
+
+ uninitialized_copy_n(other.m_items, m_item_amount, m_items);
+ }
+
+ OpenAddressingArray(OpenAddressingArray &&other) noexcept
+ {
+ m_slots_total = other.m_slots_total;
+ m_slots_set_or_dummy = other.m_slots_set_or_dummy;
+ m_slots_dummy = other.m_slots_dummy;
+ m_slots_usable = other.m_slots_usable;
+ m_slot_mask = other.m_slot_mask;
+ m_item_amount = other.m_item_amount;
+ m_item_exponent = other.m_item_exponent;
+ if (other.is_in_small_storage()) {
+ m_items = this->small_storage();
+ uninitialized_relocate_n(other.m_items, m_item_amount, m_items);
+ }
+ else {
+ m_items = other.m_items;
+ }
+
+ other.m_items = nullptr;
+ other.~OpenAddressingArray();
+ new (&other) OpenAddressingArray();
+ }
+
+ OpenAddressingArray &operator=(const OpenAddressingArray &other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+ this->~OpenAddressingArray();
+ new (this) OpenAddressingArray(other);
+ return *this;
+ }
+
+ OpenAddressingArray &operator=(OpenAddressingArray &&other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+ this->~OpenAddressingArray();
+ new (this) OpenAddressingArray(std::move(other));
+ return *this;
+ }
+
+ /* Prepare a new array that can hold a minimum of min_usable_slots elements. All entries are
+ * empty. */
+ OpenAddressingArray init_reserved(uint32_t min_usable_slots) const
+ {
+ float min_total_slots = (float)min_usable_slots / max_load_factor;
+ uint32_t min_total_items = (uint32_t)std::ceil(min_total_slots / (float)slots_per_item);
+ uint8_t item_exponent = (uint8_t)log2_ceil_u(min_total_items);
+ OpenAddressingArray grown(item_exponent);
+ grown.m_slots_set_or_dummy = this->slots_set();
+ return grown;
+ }
+
+ /**
+ * Amount of items in the array times the number of slots per item.
+ */
+ uint32_t slots_total() const
+ {
+ return m_slots_total;
+ }
+
+ /**
+ * Amount of slots that are initialized with some value that is not empty or dummy.
+ */
+ uint32_t slots_set() const
+ {
+ return m_slots_set_or_dummy - m_slots_dummy;
+ }
+
+ /**
+ * Amount of slots that can be used before the array should grow.
+ */
+ uint32_t slots_usable() const
+ {
+ return m_slots_usable;
+ }
+
+ /**
+ * Update the counters after one empty element is used for a newly added element.
+ */
+ void update__empty_to_set()
+ {
+ m_slots_set_or_dummy++;
+ }
+
+ /**
+ * Update the counters after one previously dummy element becomes set.
+ */
+ void update__dummy_to_set()
+ {
+ m_slots_dummy--;
+ }
+
+ /**
+ * Update the counters after one previously set element becomes a dummy.
+ */
+ void update__set_to_dummy()
+ {
+ m_slots_dummy++;
+ }
+
+ /**
+ * Access the current slot mask for this array.
+ */
+ uint32_t slot_mask() const
+ {
+ return m_slot_mask;
+ }
+
+ /**
+ * Access the item for a specific item index.
+ * Note: The item index is not necessarily the slot index.
+ */
+ const Item &item(uint32_t item_index) const
+ {
+ return m_items[item_index];
+ }
+
+ Item &item(uint32_t item_index)
+ {
+ return m_items[item_index];
+ }
+
+ uint8_t item_exponent() const
+ {
+ return m_item_exponent;
+ }
+
+ uint32_t item_amount() const
+ {
+ return m_item_amount;
+ }
+
+ bool should_grow() const
+ {
+ return m_slots_set_or_dummy >= m_slots_usable;
+ }
+
+ Item *begin()
+ {
+ return m_items;
+ }
+
+ Item *end()
+ {
+ return m_items + m_item_amount;
+ }
+
+ const Item *begin() const
+ {
+ return m_items;
+ }
+
+ const Item *end() const
+ {
+ return m_items + m_item_amount;
+ }
+
+ private:
+ Item *small_storage() const
+ {
+ return reinterpret_cast<Item *>((char *)m_local_storage);
+ }
+
+ bool is_in_small_storage() const
+ {
+ return m_items == this->small_storage();
+ }
+};
+
+} // namespace BLI
+
+#endif /* __BLI_OPEN_ADDRESSING_H__ */
diff --git a/source/blender/blenlib/BLI_polyfill_2d_beautify.h b/source/blender/blenlib/BLI_polyfill_2d_beautify.h
index f815459fdf5..042cb7e0ea9 100644
--- a/source/blender/blenlib/BLI_polyfill_2d_beautify.h
+++ b/source/blender/blenlib/BLI_polyfill_2d_beautify.h
@@ -36,9 +36,10 @@ float BLI_polyfill_beautify_quad_rotate_calc_ex(const float v1[2],
const float v2[2],
const float v3[2],
const float v4[2],
- const bool lock_degenerate);
+ const bool lock_degenerate,
+ float *r_area);
#define BLI_polyfill_beautify_quad_rotate_calc(v1, v2, v3, v4) \
- BLI_polyfill_beautify_quad_rotate_calc_ex(v1, v2, v3, v4, false)
+ BLI_polyfill_beautify_quad_rotate_calc_ex(v1, v2, v3, v4, false, NULL)
/* avoid realloc's when creating new structures for polyfill ngons */
#define BLI_POLYFILL_ALLOC_NGON_RESERVE 64
diff --git a/source/blender/blenlib/BLI_set.h b/source/blender/blenlib/BLI_set.h
new file mode 100644
index 00000000000..dc101add1a7
--- /dev/null
+++ b/source/blender/blenlib/BLI_set.h
@@ -0,0 +1,483 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_SET_H__
+#define __BLI_SET_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * This file provides a set implementation that uses open addressing with probing.
+ */
+
+#include "BLI_hash_cxx.h"
+#include "BLI_open_addressing.h"
+#include "BLI_vector.h"
+
+namespace BLI {
+
+// clang-format off
+
+#define ITER_SLOTS_BEGIN(VALUE, ARRAY, OPTIONAL_CONST, R_ITEM, R_OFFSET) \
+ uint32_t hash = DefaultHash<T>{}(VALUE); \
+ uint32_t perturb = hash; \
+ while (true) { \
+ uint32_t item_index = (hash & ARRAY.slot_mask()) >> OFFSET_SHIFT; \
+ uint8_t R_OFFSET = hash & OFFSET_MASK; \
+ uint8_t initial_offset = R_OFFSET; \
+ OPTIONAL_CONST Item &R_ITEM = ARRAY.item(item_index); \
+ do {
+
+#define ITER_SLOTS_END(R_OFFSET) \
+ R_OFFSET = (R_OFFSET + 1) & OFFSET_MASK; \
+ } while (R_OFFSET != initial_offset); \
+ perturb >>= 5; \
+ hash = hash * 5 + 1 + perturb; \
+ } ((void)0)
+
+// clang-format on
+
+template<typename T, typename Allocator = GuardedAllocator> class Set {
+ private:
+ static constexpr uint OFFSET_MASK = 3;
+ static constexpr uint OFFSET_SHIFT = 2;
+
+ class Item {
+ private:
+ static constexpr uint8_t IS_EMPTY = 0;
+ static constexpr uint8_t IS_SET = 1;
+ static constexpr uint8_t IS_DUMMY = 2;
+
+ uint8_t m_status[4];
+ char m_values[4 * sizeof(T)];
+
+ public:
+ static constexpr uint slots_per_item = 4;
+
+ Item()
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ m_status[offset] = IS_EMPTY;
+ }
+ }
+
+ ~Item()
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ if (m_status[offset] == IS_SET) {
+ destruct(this->value(offset));
+ }
+ }
+ }
+
+ Item(const Item &other)
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ uint8_t status = other.m_status[offset];
+ m_status[offset] = status;
+ if (status == IS_SET) {
+ T *src = other.value(offset);
+ T *dst = this->value(offset);
+ new (dst) T(*src);
+ }
+ }
+ }
+
+ Item(Item &&other) noexcept
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ uint8_t status = other.m_status[offset];
+ m_status[offset] = status;
+ if (status == IS_SET) {
+ T *src = other.value(offset);
+ T *dst = this->value(offset);
+ new (dst) T(std::move(*src));
+ }
+ }
+ }
+
+ Item &operator=(const Item &other) = delete;
+ Item &operator=(Item &&other) = delete;
+
+ T *value(uint offset) const
+ {
+ return (T *)(m_values + offset * sizeof(T));
+ }
+
+ template<typename ForwardT> void store(uint offset, ForwardT &&value)
+ {
+ BLI_assert(m_status[offset] != IS_SET);
+ m_status[offset] = IS_SET;
+ T *dst = this->value(offset);
+ new (dst) T(std::forward<ForwardT>(value));
+ }
+
+ void set_dummy(uint offset)
+ {
+ BLI_assert(m_status[offset] == IS_SET);
+ m_status[offset] = IS_DUMMY;
+ destruct(this->value(offset));
+ }
+
+ bool is_empty(uint offset) const
+ {
+ return m_status[offset] == IS_EMPTY;
+ }
+
+ bool is_set(uint offset) const
+ {
+ return m_status[offset] == IS_SET;
+ }
+
+ bool is_dummy(uint offset) const
+ {
+ return m_status[offset] == IS_DUMMY;
+ }
+
+ bool has_value(uint offset, const T &value) const
+ {
+ return m_status[offset] == IS_SET && *this->value(offset) == value;
+ }
+ };
+
+ using ArrayType = OpenAddressingArray<Item, 1, Allocator>;
+ ArrayType m_array = OpenAddressingArray<Item>();
+
+ public:
+ Set() = default;
+
+ /**
+ * Create a new set that contains the given elements.
+ */
+ Set(ArrayRef<T> values)
+ {
+ this->reserve(values.size());
+ for (const T &value : values) {
+ this->add(value);
+ }
+ }
+
+ /**
+ * Create a new set from an initializer list.
+ */
+ Set(std::initializer_list<T> values) : Set(ArrayRef<T>(values))
+ {
+ }
+
+ /**
+ * Make the set large enough to hold the given amount of elements.
+ */
+ void reserve(uint32_t min_usable_slots)
+ {
+ if (m_array.slots_usable() < min_usable_slots) {
+ this->grow(min_usable_slots);
+ }
+ }
+
+ /**
+ * Add a new element to the set.
+ * Asserts that the element did not exist in the set before.
+ */
+ void add_new(const T &value)
+ {
+ this->add_new__impl(value);
+ }
+ void add_new(T &&value)
+ {
+ this->add_new__impl(std::move(value));
+ }
+
+ /**
+ * Add a new value to the set if it does not exist yet.
+ */
+ bool add(const T &value)
+ {
+ return this->add__impl(value);
+ }
+ bool add(T &&value)
+ {
+ return this->add__impl(std::move(value));
+ }
+
+ /**
+ * Add multiple elements to the set.
+ */
+ void add_multiple(ArrayRef<T> values)
+ {
+ for (const T &value : values) {
+ this->add(value);
+ }
+ }
+
+ /**
+ * Add multiple new elements to the set.
+ * Asserts that none of the elements existed in the set before.
+ */
+ void add_multiple_new(ArrayRef<T> values)
+ {
+ for (const T &value : values) {
+ this->add_new(value);
+ }
+ }
+
+ /**
+ * Returns true when the value is in the set, otherwise false.
+ */
+ bool contains(const T &value) const
+ {
+ ITER_SLOTS_BEGIN (value, m_array, const, item, offset) {
+ if (item.is_empty(offset)) {
+ return false;
+ }
+ else if (item.has_value(offset, value)) {
+ return true;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ /**
+ * Remove the value from the set.
+ * Asserts that the value exists in the set currently.
+ */
+ void remove(const T &value)
+ {
+ BLI_assert(this->contains(value));
+ ITER_SLOTS_BEGIN (value, m_array, , item, offset) {
+ if (item.has_value(offset, value)) {
+ item.set_dummy(offset);
+ m_array.update__set_to_dummy();
+ return;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ Vector<T> to_small_vector() const
+ {
+ Vector<T> vector;
+ vector.reserve(this->size());
+ for (const T &value : *this) {
+ vector.append(value);
+ }
+ return vector;
+ }
+
+ uint32_t size() const
+ {
+ return m_array.slots_set();
+ }
+
+ /**
+ * Returns true when there is at least one element that is in both sets.
+ * Otherwise false.
+ */
+ static bool Intersects(const Set &a, const Set &b)
+ {
+ /* Make sure we iterate over the shorter set. */
+ if (a.size() > b.size()) {
+ return Intersects(b, a);
+ }
+
+ for (const T &value : a) {
+ if (b.contains(value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true when there is no value that is in both sets.
+ * Otherwise false.
+ */
+ static bool Disjoint(const Set &a, const Set &b)
+ {
+ return !Intersects(a, b);
+ }
+
+ void print_table() const
+ {
+ std::cout << "Hash Table:\n";
+ std::cout << " Size: " << m_array.slots_set() << '\n';
+ std::cout << " Capacity: " << m_array.slots_total() << '\n';
+ uint32_t item_index = 0;
+ for (const Item &item : m_array) {
+ std::cout << " Item: " << item_index++ << '\n';
+ for (uint offset = 0; offset < 4; offset++) {
+ std::cout << " " << offset << " \t";
+ if (item.is_empty(offset)) {
+ std::cout << " <empty>\n";
+ }
+ else if (item.is_set(offset)) {
+ const T &value = *item.value(offset);
+ uint32_t collisions = this->count_collisions(value);
+ std::cout << " " << value << " \t Collisions: " << collisions << '\n';
+ }
+ else if (item.is_dummy(offset)) {
+ std::cout << " <dummy>\n";
+ }
+ }
+ }
+ }
+
+ class Iterator {
+ private:
+ const Set *m_set;
+ uint32_t m_slot;
+
+ public:
+ Iterator(const Set *set, uint32_t slot) : m_set(set), m_slot(slot)
+ {
+ }
+
+ Iterator &operator++()
+ {
+ m_slot = m_set->next_slot(m_slot + 1);
+ return *this;
+ }
+
+ const T &operator*() const
+ {
+ uint32_t item_index = m_slot >> OFFSET_SHIFT;
+ uint offset = m_slot & OFFSET_MASK;
+ const Item &item = m_set->m_array.item(item_index);
+ BLI_assert(item.is_set(offset));
+ return *item.value(offset);
+ }
+
+ friend bool operator==(const Iterator &a, const Iterator &b)
+ {
+ BLI_assert(a.m_set == b.m_set);
+ return a.m_slot == b.m_slot;
+ }
+
+ friend bool operator!=(const Iterator &a, const Iterator &b)
+ {
+ return !(a == b);
+ }
+ };
+
+ friend Iterator;
+
+ Iterator begin() const
+ {
+ return Iterator(this, this->next_slot(0));
+ }
+
+ Iterator end() const
+ {
+ return Iterator(this, m_array.slots_total());
+ }
+
+ private:
+ uint32_t next_slot(uint32_t slot) const
+ {
+ for (; slot < m_array.slots_total(); slot++) {
+ uint32_t item_index = slot >> OFFSET_SHIFT;
+ uint offset = slot & OFFSET_MASK;
+ const Item &item = m_array.item(item_index);
+ if (item.is_set(offset)) {
+ return slot;
+ }
+ }
+ return slot;
+ }
+
+ void ensure_can_add()
+ {
+ if (UNLIKELY(m_array.should_grow())) {
+ this->grow(this->size() + 1);
+ }
+ }
+
+ BLI_NOINLINE void grow(uint32_t min_usable_slots)
+ {
+ ArrayType new_array = m_array.init_reserved(min_usable_slots);
+
+ for (Item &old_item : m_array) {
+ for (uint8_t offset = 0; offset < 4; offset++) {
+ if (old_item.is_set(offset)) {
+ this->add_after_grow(*old_item.value(offset), new_array);
+ }
+ }
+ }
+
+ m_array = std::move(new_array);
+ }
+
+ void add_after_grow(T &old_value, ArrayType &new_array)
+ {
+ ITER_SLOTS_BEGIN (old_value, new_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, std::move(old_value));
+ return;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ uint32_t count_collisions(const T &value) const
+ {
+ uint32_t collisions = 0;
+ ITER_SLOTS_BEGIN (value, m_array, const, item, offset) {
+ if (item.is_empty(offset) || item.has_value(offset, value)) {
+ return collisions;
+ }
+ collisions++;
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ template<typename ForwardT> void add_new__impl(ForwardT &&value)
+ {
+ BLI_assert(!this->contains(value));
+ this->ensure_can_add();
+
+ ITER_SLOTS_BEGIN (value, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, std::forward<ForwardT>(value));
+ m_array.update__empty_to_set();
+ return;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ template<typename ForwardT> bool add__impl(ForwardT &&value)
+ {
+ this->ensure_can_add();
+
+ ITER_SLOTS_BEGIN (value, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, std::forward<ForwardT>(value));
+ m_array.update__empty_to_set();
+ return true;
+ }
+ else if (item.has_value(offset, value)) {
+ return false;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+};
+
+#undef ITER_SLOTS_BEGIN
+#undef ITER_SLOTS_END
+
+} // namespace BLI
+
+#endif /* __BLI_SET_H__ */
diff --git a/source/blender/blenlib/BLI_sort.h b/source/blender/blenlib/BLI_sort.h
index b6250afdee0..08e61915a83 100644
--- a/source/blender/blenlib/BLI_sort.h
+++ b/source/blender/blenlib/BLI_sort.h
@@ -31,7 +31,7 @@
# define BLI_qsort_r qsort_r
#endif
-/* Quick sort reentrant */
+/* Quick sort re-entrant */
typedef int (*BLI_sort_cmp_t)(const void *a, const void *b, void *ctx);
void BLI_qsort_r(void *a, size_t n, size_t es, BLI_sort_cmp_t cmp, void *thunk)
diff --git a/source/blender/blenlib/BLI_stack_cxx.h b/source/blender/blenlib/BLI_stack_cxx.h
new file mode 100644
index 00000000000..7915acadfac
--- /dev/null
+++ b/source/blender/blenlib/BLI_stack_cxx.h
@@ -0,0 +1,145 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_STACK_CXX_H__
+#define __BLI_STACK_CXX_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * Basic stack implementation with support for small object optimization.
+ */
+
+#include "BLI_vector.h"
+
+namespace BLI {
+
+template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Stack {
+ private:
+ Vector<T, N, Allocator> m_elements;
+
+ public:
+ Stack() = default;
+
+ /**
+ * Construct a stack from an array ref. The elements will be pushed in the same order they are in
+ * the array.
+ */
+ Stack(ArrayRef<T> values) : m_elements(values)
+ {
+ }
+
+ operator ArrayRef<T>()
+ {
+ return m_elements;
+ }
+
+ /**
+ * Return the number of elements in the stack.
+ */
+ uint size() const
+ {
+ return m_elements.size();
+ }
+
+ /**
+ * Return true when the stack is empty, otherwise false.
+ */
+ bool empty() const
+ {
+ return this->size() == 0;
+ }
+
+ /**
+ * Add a new element to the top of the stack.
+ */
+ void push(const T &value)
+ {
+ m_elements.append(value);
+ }
+
+ void push(T &&value)
+ {
+ m_elements.append(std::move(value));
+ }
+
+ /**
+ * Remove the element from the top of the stack and return it.
+ * This will assert when the stack is empty.
+ */
+ T pop()
+ {
+ return m_elements.pop_last();
+ }
+
+ /**
+ * Return a reference to the value a the top of the stack.
+ * This will assert when the stack is empty.
+ */
+ T &peek()
+ {
+ BLI_assert(!this->empty());
+ return m_elements[this->size() - 1];
+ }
+
+ T *begin()
+ {
+ return m_elements.begin();
+ }
+
+ T *end()
+ {
+ return m_elements.end();
+ }
+
+ const T *begin() const
+ {
+ return m_elements.begin();
+ }
+
+ const T *end() const
+ {
+ return m_elements.end();
+ }
+
+ /**
+ * Remove all elements from the stack but keep the memory.
+ */
+ void clear()
+ {
+ m_elements.clear();
+ }
+
+ /**
+ * Remove all elements and free any allocated memory.
+ */
+ void clear_and_make_small()
+ {
+ m_elements.clear_and_make_small();
+ }
+
+ /**
+ * Does a linear search to check if the value is in the stack.
+ */
+ bool contains(const T &value)
+ {
+ return m_elements.contains(value);
+ }
+};
+
+} /* namespace BLI */
+
+#endif /* __BLI_STACK_CXX_H__ */
diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h
index 70ffb46e952..cab2e68ca2b 100644
--- a/source/blender/blenlib/BLI_string.h
+++ b/source/blender/blenlib/BLI_string.h
@@ -100,7 +100,7 @@ char *BLI_strncasestr(const char *s, const char *find, size_t len) ATTR_WARN_UNU
int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_strncasecmp(const char *s1, const char *s2, size_t len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-int BLI_natstrcmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_strcmp_ignore_pad(const char *str1,
const char *str2,
const char pad) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
diff --git a/source/blender/blenlib/BLI_string_map.h b/source/blender/blenlib/BLI_string_map.h
new file mode 100644
index 00000000000..ba870eb878a
--- /dev/null
+++ b/source/blender/blenlib/BLI_string_map.h
@@ -0,0 +1,425 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_STRING_MAP_H__
+#define __BLI_STRING_MAP_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * This tries to solve the issue that a normal map with std::string as key might do many
+ * allocations when the keys are longer than 16 bytes (the usual small string optimization size).
+ *
+ * For now this still uses std::string, but having this abstraction in place will make it easier to
+ * make it more efficient later on. Also, even if we will never implement this optimization, having
+ * a special map with string keys can be quite handy. */
+
+#include "BLI_map.h"
+#include "BLI_string_ref.h"
+#include "BLI_vector.h"
+
+namespace BLI {
+
+// clang-format off
+
+#define ITER_SLOTS_BEGIN(HASH, ARRAY, OPTIONAL_CONST, R_ITEM, R_OFFSET) \
+ uint32_t hash_copy = HASH; \
+ uint32_t perturb = HASH; \
+ while (true) { \
+ uint32_t item_index = (hash_copy & ARRAY.slot_mask()) >> OFFSET_SHIFT; \
+ uint8_t R_OFFSET = hash_copy & OFFSET_MASK; \
+ uint8_t initial_offset = R_OFFSET; \
+ OPTIONAL_CONST Item &R_ITEM = ARRAY.item(item_index); \
+ do {
+
+#define ITER_SLOTS_END(R_OFFSET) \
+ R_OFFSET = (R_OFFSET + 1) & OFFSET_MASK; \
+ } while (R_OFFSET != initial_offset); \
+ perturb >>= 5; \
+ hash_copy = hash_copy * 5 + 1 + perturb; \
+ } ((void)0)
+
+// clang-format on
+
+template<typename T, typename Allocator = GuardedAllocator> class StringMap {
+ private:
+ static constexpr uint32_t OFFSET_MASK = 3;
+ static constexpr uint32_t OFFSET_SHIFT = 2;
+
+ class Item {
+ private:
+ static constexpr int32_t IS_EMPTY = -1;
+
+ uint32_t m_hashes[4];
+ int32_t m_indices[4];
+ char m_values[sizeof(T) * 4];
+
+ public:
+ static constexpr uint slots_per_item = 4;
+
+ Item()
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ m_indices[offset] = IS_EMPTY;
+ }
+ }
+
+ ~Item()
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ if (this->is_set(offset)) {
+ destruct(this->value(offset));
+ }
+ }
+ }
+
+ Item(const Item &other)
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ m_indices[offset] = other.m_indices[offset];
+ if (other.is_set(offset)) {
+ m_hashes[offset] = other.m_hashes[offset];
+ new (this->value(offset)) T(*other.value(offset));
+ }
+ }
+ }
+
+ Item(Item &&other) noexcept
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ m_indices[offset] = other.m_indices[offset];
+ if (other.is_set(offset)) {
+ m_hashes[offset] = other.m_hashes[offset];
+ new (this->value(offset)) T(std::move(*other.value(offset)));
+ }
+ }
+ }
+
+ uint32_t index(uint offset) const
+ {
+ return m_indices[offset];
+ }
+
+ uint32_t hash(uint offset) const
+ {
+ return m_hashes[offset];
+ }
+
+ T *value(uint offset) const
+ {
+ return (T *)POINTER_OFFSET(m_values, offset * sizeof(T));
+ }
+
+ bool is_set(uint offset) const
+ {
+ return m_indices[offset] >= 0;
+ }
+
+ bool is_empty(uint offset) const
+ {
+ return m_indices[offset] == IS_EMPTY;
+ }
+
+ bool has_hash(uint offset, uint32_t hash) const
+ {
+ BLI_assert(this->is_set(offset));
+ return m_hashes[offset] == hash;
+ }
+
+ bool has_exact_key(uint offset, StringRef key, const Vector<char> &chars) const
+ {
+ return key == this->get_key(offset, chars);
+ }
+
+ StringRefNull get_key(uint offset, const Vector<char> &chars) const
+ {
+ const char *ptr = chars.begin() + m_indices[offset];
+ uint length = *(uint *)ptr;
+ const char *start = ptr + sizeof(uint);
+ return StringRefNull(start, length);
+ }
+
+ template<typename ForwardT>
+ void store(uint offset, uint32_t hash, uint32_t index, ForwardT &&value)
+ {
+ BLI_assert(!this->is_set(offset));
+ m_hashes[offset] = hash;
+ m_indices[offset] = index;
+ new (this->value(offset)) T(std::forward<ForwardT>(value));
+ }
+ };
+
+ using ArrayType = OpenAddressingArray<Item, 1, Allocator>;
+ ArrayType m_array;
+ Vector<char> m_chars;
+
+ public:
+ StringMap() = default;
+
+ /**
+ * Get the number of key-value pairs in the map.
+ */
+ uint size() const
+ {
+ return m_array.slots_set();
+ }
+
+ /**
+ * Add a new element to the map. It is assumed that the key did not exist before.
+ */
+ void add_new(StringRef key, const T &value)
+ {
+ this->add_new__impl(key, value);
+ }
+ void add_new(StringRef key, T &&value)
+ {
+ this->add_new__impl(key, std::move(value));
+ }
+
+ /**
+ * Return true when the key exists in the map, otherwise false.
+ */
+ bool contains(StringRef key) const
+ {
+ uint32_t hash = this->compute_string_hash(key);
+ ITER_SLOTS_BEGIN (hash, m_array, const, item, offset) {
+ if (item.is_empty(offset)) {
+ return false;
+ }
+ else if (item.has_hash(offset, hash) && item.has_exact_key(offset, key, m_chars)) {
+ return true;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ /**
+ * Get a reference to the value corresponding to a key. It is assumed that the key does exist.
+ */
+ const T &lookup(StringRef key) const
+ {
+ BLI_assert(this->contains(key));
+ T *found_value = nullptr;
+ uint32_t hash = this->compute_string_hash(key);
+ ITER_SLOTS_BEGIN (hash, m_array, const, item, offset) {
+ if (item.is_empty(offset)) {
+ return *found_value;
+ }
+ else if (item.has_hash(offset, hash)) {
+ if (found_value == nullptr) {
+ /* Common case: the first slot with the correct hash contains the key.
+ * However, still need to iterate until the next empty slot to make sure there is no
+ * other key with the exact same hash. */
+ /* TODO: Check if we can guarantee that every hash only exists once in some cases. */
+ found_value = item.value(offset);
+ }
+ else if (item.has_exact_key(offset, key, m_chars)) {
+ /* Found the hash more than once, now check for actual string equality. */
+ return *item.value(offset);
+ }
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ T &lookup(StringRef key)
+ {
+ return const_cast<T &>(const_cast<const StringMap *>(this)->lookup(key));
+ }
+
+ /**
+ * Get a pointer to the value corresponding to the key. Return nullptr, if the key does not
+ * exist.
+ */
+ const T *lookup_ptr(StringRef key) const
+ {
+ uint32_t hash = this->compute_string_hash(key);
+ ITER_SLOTS_BEGIN (hash, m_array, const, item, offset) {
+ if (item.is_empty(offset)) {
+ return nullptr;
+ }
+ else if (item.has_hash(offset, hash) && item.has_exact_key(offset, key, m_chars)) {
+ return item.value(offset);
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ T *lookup_ptr(StringRef key)
+ {
+ return const_cast<T *>(const_cast<const StringMap *>(this)->lookup_ptr(key));
+ }
+
+ /**
+ * Get a copy of the value corresponding to the key. If the key does not exist, return the
+ * default value.
+ */
+ T lookup_default(StringRef key, const T &default_value) const
+ {
+ const T *ptr = this->lookup_ptr(key);
+ if (ptr != nullptr) {
+ return *ptr;
+ }
+ else {
+ return default_value;
+ }
+ }
+
+ /**
+ * Do a linear search over all items to find a key for a value.
+ */
+ StringRefNull find_key_for_value(const T &value) const
+ {
+ for (const Item &item : m_array) {
+ for (uint offset = 0; offset < 4; offset++) {
+ if (item.is_set(offset) && value == *item.value(offset)) {
+ return item.get_key(offset, m_chars);
+ }
+ }
+ }
+ BLI_assert(false);
+ return {};
+ }
+
+ /**
+ * Run a function for every value in the map.
+ */
+ template<typename FuncT> void foreach_value(const FuncT &func)
+ {
+ for (Item &item : m_array) {
+ for (uint offset = 0; offset < 4; offset++) {
+ if (item.is_set(offset)) {
+ func(*item.value(offset));
+ }
+ }
+ }
+ }
+
+ /**
+ * Run a function for every key in the map.
+ */
+ template<typename FuncT> void foreach_key(const FuncT &func)
+ {
+ for (Item &item : m_array) {
+ for (uint offset = 0; offset < 4; offset++) {
+ if (item.is_set(offset)) {
+ StringRefNull key = item.get_key(offset, m_chars);
+ func(key);
+ }
+ }
+ }
+ }
+
+ /**
+ * Run a function for every key-value-pair in the map.
+ */
+ template<typename FuncT> void foreach_key_value_pair(const FuncT &func)
+ {
+ for (Item &item : m_array) {
+ for (uint offset = 0; offset < 4; offset++) {
+ if (item.is_set(offset)) {
+ StringRefNull key = item.get_key(offset, m_chars);
+ T &value = *item.value(offset);
+ func(key, value);
+ }
+ }
+ }
+ }
+
+ private:
+ uint32_t compute_string_hash(StringRef key) const
+ {
+ /* TODO: check if this can be optimized more because we know the key length already. */
+ uint32_t hash = 5381;
+ for (char c : key) {
+ hash = hash * 33 + c;
+ }
+ return hash;
+ }
+
+ uint32_t save_key_in_array(StringRef key)
+ {
+ uint index = m_chars.size();
+ uint string_size = key.size();
+ m_chars.extend(ArrayRef<char>((char *)&string_size, sizeof(uint)));
+ m_chars.extend(key);
+ m_chars.append('\0');
+ return index;
+ }
+
+ StringRefNull key_from_index(uint32_t index) const
+ {
+ const char *ptr = m_chars.begin() + index;
+ uint length = *(uint *)ptr;
+ const char *start = ptr + sizeof(uint);
+ return StringRefNull(start, length);
+ }
+
+ void ensure_can_add()
+ {
+ if (UNLIKELY(m_array.should_grow())) {
+ this->grow(this->size() + 1);
+ }
+ }
+
+ BLI_NOINLINE void grow(uint min_usable_slots)
+ {
+ ArrayType new_array = m_array.init_reserved(min_usable_slots);
+ for (Item &old_item : m_array) {
+ for (uint offset = 0; offset < 4; offset++) {
+ if (old_item.is_set(offset)) {
+ this->add_after_grow(
+ *old_item.value(offset), old_item.hash(offset), old_item.index(offset), new_array);
+ }
+ }
+ }
+ m_array = std::move(new_array);
+ }
+
+ void add_after_grow(T &value, uint32_t hash, uint32_t index, ArrayType &new_array)
+ {
+ ITER_SLOTS_BEGIN (hash, new_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, hash, index, std::move(value));
+ return;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ template<typename ForwardT> void add_new__impl(StringRef key, ForwardT &&value)
+ {
+ BLI_assert(!this->contains(key));
+ this->ensure_can_add();
+ uint32_t hash = this->compute_string_hash(key);
+ ITER_SLOTS_BEGIN (hash, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ uint32_t index = this->save_key_in_array(key);
+ item.store(offset, hash, index, std::forward<ForwardT>(value));
+ m_array.update__empty_to_set();
+ return;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+};
+
+#undef ITER_SLOTS_BEGIN
+#undef ITER_SLOTS_END
+
+} // namespace BLI
+
+#endif /* __BLI_STRING_MAP_H__ */
diff --git a/source/blender/blenlib/BLI_string_ref.h b/source/blender/blenlib/BLI_string_ref.h
new file mode 100644
index 00000000000..76163a2754c
--- /dev/null
+++ b/source/blender/blenlib/BLI_string_ref.h
@@ -0,0 +1,247 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_STRING_REF_H__
+#define __BLI_STRING_REF_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * A StringRef is a pointer to a string somewhere in memory. It should not be used to transfer
+ * ownership of that string. When a function gets a StringRef as input, it cannot expect, that
+ * the string will still exist after the function ends.
+ *
+ * There are two types of string references: One that guarantees null termination and one that does
+ * not.
+ */
+
+#include <cstring>
+#include <string>
+#include <sstream>
+
+#include "BLI_utildefines.h"
+#include "BLI_array_ref.h"
+
+namespace BLI {
+
+class StringRef;
+
+class StringRefBase {
+ public:
+ using size_type = size_t;
+
+ protected:
+ const char *m_data;
+ size_type m_size;
+
+ StringRefBase(const char *data, size_type size) : m_data(data), m_size(size)
+ {
+ }
+
+ public:
+ /**
+ * Return the (byte-)length of the referenced string, without any null-terminator.
+ */
+ size_type size() const
+ {
+ return m_size;
+ }
+
+ /**
+ * Return a pointer to the start of the string.
+ */
+ const char *data() const
+ {
+ return m_data;
+ }
+
+ char operator[](size_type index) const
+ {
+ BLI_assert(index <= m_size);
+ return m_data[index];
+ }
+
+ operator ArrayRef<char>() const
+ {
+ return ArrayRef<char>(m_data, m_size);
+ }
+
+ operator std::string() const
+ {
+ return std::string(m_data, m_size);
+ }
+
+ const char *begin() const
+ {
+ return m_data;
+ }
+
+ const char *end() const
+ {
+ return m_data + m_size;
+ }
+
+ void copy_to__with_null(char *dst) const
+ {
+ memcpy(dst, m_data, m_size);
+ dst[m_size] = '\0';
+ }
+
+ /**
+ * Returns true when the string begins with the given prefix. Otherwise false.
+ */
+ bool startswith(StringRef prefix) const;
+
+ /**
+ * Returns true when the string ends with the given suffix. Otherwise false.
+ */
+ bool endswith(StringRef suffix) const;
+};
+
+/**
+ * References a null-terminated char array.
+ */
+class StringRefNull : public StringRefBase {
+
+ public:
+ StringRefNull() : StringRefBase("", 0)
+ {
+ }
+
+ StringRefNull(const char *str) : StringRefBase(str, strlen(str))
+ {
+ BLI_assert(str != NULL);
+ BLI_assert(m_data[m_size] == '\0');
+ }
+
+ StringRefNull(const char *str, size_type size) : StringRefBase(str, size)
+ {
+ BLI_assert(str[size] == '\0');
+ }
+
+ StringRefNull(const std::string &str) : StringRefNull(str.data())
+ {
+ }
+};
+
+/**
+ * References a char array. It might not be null terminated.
+ */
+class StringRef : public StringRefBase {
+ public:
+ StringRef() : StringRefBase(nullptr, 0)
+ {
+ }
+
+ StringRef(StringRefNull other) : StringRefBase(other.data(), other.size())
+ {
+ }
+
+ StringRef(const char *str) : StringRefBase(str, str ? strlen(str) : 0)
+ {
+ }
+
+ StringRef(const char *str, size_type length) : StringRefBase(str, length)
+ {
+ }
+
+ StringRef(const std::string &str) : StringRefBase(str.data(), str.size())
+ {
+ }
+
+ /**
+ * Return a new StringRef that does not contain the first n chars.
+ */
+ StringRef drop_prefix(uint n) const
+ {
+ BLI_assert(n <= m_size);
+ return StringRef(m_data + n, m_size - n);
+ }
+
+ /**
+ * Return a new StringRef that with the given prefix being skipped.
+ * Asserts that the string begins with the given prefix.
+ */
+ StringRef drop_prefix(StringRef prefix) const
+ {
+ BLI_assert(this->startswith(prefix));
+ return this->drop_prefix(prefix.size());
+ }
+};
+
+/* More inline functions
+ ***************************************/
+
+inline std::ostream &operator<<(std::ostream &stream, StringRef ref)
+{
+ stream << std::string(ref);
+ return stream;
+}
+
+inline std::ostream &operator<<(std::ostream &stream, StringRefNull ref)
+{
+ stream << std::string(ref.data(), ref.size());
+ return stream;
+}
+
+inline std::string operator+(StringRef a, StringRef b)
+{
+ return std::string(a) + std::string(b);
+}
+
+inline bool operator==(StringRef a, StringRef b)
+{
+ if (a.size() != b.size()) {
+ return false;
+ }
+ return STREQLEN(a.data(), b.data(), a.size());
+}
+
+inline bool operator!=(StringRef a, StringRef b)
+{
+ return !(a == b);
+}
+
+inline bool StringRefBase::startswith(StringRef prefix) const
+{
+ if (m_size < prefix.m_size) {
+ return false;
+ }
+ for (uint i = 0; i < prefix.m_size; i++) {
+ if (m_data[i] != prefix.m_data[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline bool StringRefBase::endswith(StringRef suffix) const
+{
+ if (m_size < suffix.m_size) {
+ return false;
+ }
+ uint offset = m_size - suffix.m_size;
+ for (uint i = 0; i < suffix.m_size; i++) {
+ if (m_data[offset + i] != suffix.m_data[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace BLI
+
+#endif /* __BLI_STRING_REF_H__ */
diff --git a/source/blender/blenlib/BLI_system.h b/source/blender/blenlib/BLI_system.h
index f4c0399e959..8c0c9ad99bf 100644
--- a/source/blender/blenlib/BLI_system.h
+++ b/source/blender/blenlib/BLI_system.h
@@ -19,11 +19,16 @@
#include <stdio.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/** \file
* \ingroup bli
*/
int BLI_cpu_support_sse2(void);
+int BLI_cpu_support_sse41(void);
void BLI_system_backtrace(FILE *fp);
/* Get CPU brand, result is to be MEM_freeN()-ed. */
@@ -52,4 +57,8 @@ int BLI_system_memory_max_in_megabytes_int(void);
# define BLI_SYSTEM_PID_H <unistd.h>
#endif
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __BLI_SYSTEM_H__ */
diff --git a/source/blender/blenlib/BLI_temporary_allocator.h b/source/blender/blenlib/BLI_temporary_allocator.h
new file mode 100644
index 00000000000..b378e5869c0
--- /dev/null
+++ b/source/blender/blenlib/BLI_temporary_allocator.h
@@ -0,0 +1,64 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bli
+ *
+ * This allocation method assumes
+ * 1. The allocations are short-lived.
+ * 2. The total number of allocations is bound by a constant per thread.
+ *
+ * These two assumptions make it possible to cache and reuse relatively large buffers. They allow
+ * to hand out buffers that are much larger than the requested size, without the fear of running
+ * out of memory.
+ *
+ * The assumptions might feel a bit limiting at first, but hold true in many cases. For example,
+ * many algorithms need to store temporary data. With this allocator, the allocation can become
+ * very cheap for common cases.
+ *
+ * Many cpu-bound algorithms can benefit from being split up into several stages, whereby the
+ * output of one stage is written into an array that is read by the next stage. This makes them
+ * easier to debug, profile and optimize. Often a reason this is not done is that the memory
+ * allocation might be expensive. The goal of this allocator is to make this a non-issue, by
+ * reusing the same long buffers over and over again.
+ *
+ * All allocated buffers are 64 byte aligned, to make them as reusable as possible.
+ * If the requested size is too large, there is a fallback to normal allocation. The allocation
+ * overhead is probably very small in these cases anyway.
+ *
+ * The best way to use this allocator is to use one of the prepared containers like TemporaryVector
+ * and TemporaryArray.
+ */
+
+#ifndef __BLI_TEMPORARY_ALLOCATOR_H__
+#define __BLI_TEMPORARY_ALLOCATOR_H__
+
+#include "BLI_utildefines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BLI_TEMPORARY_BUFFER_ALIGNMENT 64
+
+void *BLI_temporary_allocate(uint size);
+void BLI_temporary_deallocate(void *buffer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BLI_TEMPORARY_ALLOCATOR_H__ */
diff --git a/source/blender/blenlib/BLI_temporary_allocator_cxx.h b/source/blender/blenlib/BLI_temporary_allocator_cxx.h
new file mode 100644
index 00000000000..06159f68059
--- /dev/null
+++ b/source/blender/blenlib/BLI_temporary_allocator_cxx.h
@@ -0,0 +1,38 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_TEMPORARY_ALLOCATOR_CXX_H__
+#define __BLI_TEMPORARY_ALLOCATOR_CXX_H__
+
+/** \file
+ * \ingroup bli
+ */
+
+#include "BLI_temporary_allocator.h"
+
+namespace BLI {
+
+template<typename T> class MutableArrayRef;
+
+template<typename T> MutableArrayRef<T> temporary_allocate_array(uint size)
+{
+ void *ptr = BLI_temporary_allocate(sizeof(T) * size);
+ return MutableArrayRef<T>((T *)ptr, size);
+}
+
+}; // namespace BLI
+
+#endif /* __BLI_TEMPORARY_ALLOCATOR_CXX_H__ */
diff --git a/source/blender/blenlib/BLI_timer.h b/source/blender/blenlib/BLI_timer.h
index dc47aefa090..56cafb1bd36 100644
--- a/source/blender/blenlib/BLI_timer.h
+++ b/source/blender/blenlib/BLI_timer.h
@@ -50,4 +50,8 @@ void BLI_timer_execute(void);
void BLI_timer_free(void);
+/* This function is to be called next to BKE_CB_EVT_LOAD_PRE, to make sure the module
+ * is properly configured for the new file. */
+void BLI_timer_on_file_load(void);
+
#endif /* __BLI_TIMER_H__ */
diff --git a/source/blender/blenlib/BLI_vector.h b/source/blender/blenlib/BLI_vector.h
new file mode 100644
index 00000000000..46c46a1440f
--- /dev/null
+++ b/source/blender/blenlib/BLI_vector.h
@@ -0,0 +1,607 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_VECTOR_H__
+#define __BLI_VECTOR_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * This vector wraps a dynamically sized array of a specific type. It supports small object
+ * optimization. That means, when the vector only contains a few elements, no memory allocation is
+ * performed. Instead, those elements are stored directly in the vector.
+ */
+
+#include <algorithm>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <memory>
+
+#include "BLI_utildefines.h"
+#include "BLI_memory_utils_cxx.h"
+#include "BLI_array_ref.h"
+#include "BLI_listbase_wrapper.h"
+#include "BLI_math_base.h"
+#include "BLI_allocator.h"
+
+#include "MEM_guardedalloc.h"
+
+namespace BLI {
+
+template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Vector {
+ private:
+ T *m_begin;
+ T *m_end;
+ T *m_capacity_end;
+ Allocator m_allocator;
+ char m_small_buffer[sizeof(T) * N];
+
+#ifndef NDEBUG
+ /* Storing size in debug builds, because it makes debugging much easier sometimes. */
+ uint m_debug_size;
+# define UPDATE_VECTOR_SIZE(ptr) (ptr)->m_debug_size = (uint)((ptr)->m_end - (ptr)->m_begin)
+#else
+# define UPDATE_VECTOR_SIZE(ptr) ((void)0)
+#endif
+
+ template<typename OtherT, uint OtherN, typename OtherAllocator> friend class Vector;
+
+ public:
+ /**
+ * Create an empty vector.
+ * This does not do any memory allocation.
+ */
+ Vector()
+ {
+ m_begin = this->small_buffer();
+ m_end = m_begin;
+ m_capacity_end = m_begin + N;
+ UPDATE_VECTOR_SIZE(this);
+ }
+
+ /**
+ * Create a vector with a specific size.
+ * The elements will be default initialized.
+ */
+ explicit Vector(uint size) : Vector()
+ {
+ this->reserve(size);
+ this->increase_size_unchecked(size);
+ for (T *current = m_begin; current != m_end; current++) {
+ new (current) T();
+ }
+ }
+
+ /**
+ * Create a vector filled with a specific value.
+ */
+ Vector(uint size, const T &value) : Vector()
+ {
+ this->reserve(size);
+ this->increase_size_unchecked(size);
+ BLI::uninitialized_fill_n(m_begin, size, value);
+ }
+
+ /**
+ * Create a vector from an initializer list.
+ */
+ Vector(std::initializer_list<T> values) : Vector(ArrayRef<T>(values))
+ {
+ }
+
+ /**
+ * Create a vector from an array ref.
+ */
+ Vector(ArrayRef<T> values) : Vector()
+ {
+ this->reserve(values.size());
+ this->increase_size_unchecked(values.size());
+ BLI::uninitialized_copy_n(values.begin(), values.size(), this->begin());
+ }
+
+ /**
+ * Create a vector from any container. It must be possible to use the container in a range-for
+ * loop.
+ */
+ template<typename ContainerT> static Vector FromContainer(const ContainerT &container)
+ {
+ Vector vector;
+ for (const auto &value : container) {
+ vector.append(value);
+ }
+ return vector;
+ }
+
+ /**
+ * Create a vector from a ListBase.
+ */
+ Vector(ListBase &values, bool intrusive_next_and_prev_pointers) : Vector()
+ {
+ BLI_assert(intrusive_next_and_prev_pointers);
+ if (intrusive_next_and_prev_pointers) {
+ for (T value : IntrusiveListBaseWrapper<typename std::remove_pointer<T>::type>(values)) {
+ this->append(value);
+ }
+ }
+ }
+
+ /**
+ * Create a copy of another vector.
+ * The other vector will not be changed.
+ * If the other vector has less than N elements, no allocation will be made.
+ */
+ Vector(const Vector &other) : m_allocator(other.m_allocator)
+ {
+ this->init_copy_from_other_vector(other);
+ }
+
+ template<uint OtherN>
+ Vector(const Vector<T, OtherN, Allocator> &other) : m_allocator(other.m_allocator)
+ {
+ this->init_copy_from_other_vector(other);
+ }
+
+ /**
+ * Steal the elements from another vector.
+ * This does not do an allocation.
+ * The other vector will have zero elements afterwards.
+ */
+ template<uint OtherN>
+ Vector(Vector<T, OtherN, Allocator> &&other) noexcept : m_allocator(other.m_allocator)
+ {
+ uint size = other.size();
+
+ if (other.is_small()) {
+ if (size <= N) {
+ /* Copy between inline buffers. */
+ m_begin = this->small_buffer();
+ m_end = m_begin + size;
+ m_capacity_end = m_begin + N;
+ uninitialized_relocate_n(other.m_begin, size, m_begin);
+ }
+ else {
+ /* Copy from inline buffer to newly allocated buffer. */
+ uint capacity = size;
+ m_begin = (T *)m_allocator.allocate_aligned(
+ sizeof(T) * capacity, std::alignment_of<T>::value, __func__);
+ m_end = m_begin + size;
+ m_capacity_end = m_begin + capacity;
+ uninitialized_relocate_n(other.m_begin, size, m_begin);
+ }
+ }
+ else {
+ /* Steal the pointer. */
+ m_begin = other.m_begin;
+ m_end = other.m_end;
+ m_capacity_end = other.m_capacity_end;
+ }
+
+ other.m_begin = other.small_buffer();
+ other.m_end = other.m_begin;
+ other.m_capacity_end = other.m_begin + OtherN;
+ UPDATE_VECTOR_SIZE(this);
+ UPDATE_VECTOR_SIZE(&other);
+ }
+
+ ~Vector()
+ {
+ destruct_n(m_begin, this->size());
+ if (!this->is_small()) {
+ m_allocator.deallocate(m_begin);
+ }
+ }
+
+ operator ArrayRef<T>() const
+ {
+ return ArrayRef<T>(m_begin, this->size());
+ }
+
+ operator MutableArrayRef<T>()
+ {
+ return MutableArrayRef<T>(m_begin, this->size());
+ }
+
+ Vector &operator=(const Vector &other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+
+ this->~Vector();
+ new (this) Vector(other);
+
+ return *this;
+ }
+
+ Vector &operator=(Vector &&other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+
+ this->~Vector();
+ new (this) Vector(std::move(other));
+
+ return *this;
+ }
+
+ /**
+ * Make sure that enough memory is allocated to hold size elements.
+ * This won't necessarily make an allocation when size is small.
+ * The actual size of the vector does not change.
+ */
+ void reserve(uint size)
+ {
+ this->grow(size);
+ }
+
+ /**
+ * Afterwards the vector has 0 elements, but will still have
+ * memory to be refilled again.
+ */
+ void clear()
+ {
+ destruct_n(m_begin, this->size());
+ m_end = m_begin;
+ UPDATE_VECTOR_SIZE(this);
+ }
+
+ /**
+ * Afterwards the vector has 0 elements and any allocated memory
+ * will be freed.
+ */
+ void clear_and_make_small()
+ {
+ destruct_n(m_begin, this->size());
+ if (!this->is_small()) {
+ m_allocator.deallocate(m_begin);
+ }
+
+ m_begin = this->small_buffer();
+ m_end = m_begin;
+ m_capacity_end = m_begin + N;
+ UPDATE_VECTOR_SIZE(this);
+ }
+
+ /**
+ * Insert a new element at the end of the vector.
+ * This might cause a reallocation with the capacity is exceeded.
+ */
+ void append(const T &value)
+ {
+ this->ensure_space_for_one();
+ this->append_unchecked(value);
+ }
+
+ void append(T &&value)
+ {
+ this->ensure_space_for_one();
+ this->append_unchecked(std::move(value));
+ }
+
+ void append_unchecked(const T &value)
+ {
+ BLI_assert(m_end < m_capacity_end);
+ new (m_end) T(value);
+ m_end++;
+ UPDATE_VECTOR_SIZE(this);
+ }
+
+ void append_unchecked(T &&value)
+ {
+ BLI_assert(m_end < m_capacity_end);
+ new (m_end) T(std::move(value));
+ m_end++;
+ UPDATE_VECTOR_SIZE(this);
+ }
+
+ /**
+ * Insert the same element n times at the end of the vector.
+ * This might result in a reallocation internally.
+ */
+ void append_n_times(const T &value, uint n)
+ {
+ this->reserve(this->size() + n);
+ BLI::uninitialized_fill_n(m_end, n, value);
+ this->increase_size_unchecked(n);
+ }
+
+ void increase_size_unchecked(uint n)
+ {
+ BLI_assert(m_end + n <= m_capacity_end);
+ m_end += n;
+ UPDATE_VECTOR_SIZE(this);
+ }
+
+ /**
+ * Copy the elements of another array to the end of this vector.
+ */
+ void extend(ArrayRef<T> array)
+ {
+ this->extend(array.begin(), array.size());
+ }
+
+ void extend(const T *start, uint amount)
+ {
+ this->reserve(this->size() + amount);
+ this->extend_unchecked(start, amount);
+ }
+
+ void extend_unchecked(ArrayRef<T> array)
+ {
+ this->extend_unchecked(array.begin(), array.size());
+ }
+
+ void extend_unchecked(const T *start, uint amount)
+ {
+ BLI_assert(m_begin + amount <= m_capacity_end);
+ BLI::uninitialized_copy_n(start, amount, m_end);
+ m_end += amount;
+ UPDATE_VECTOR_SIZE(this);
+ }
+
+ /**
+ * Return a reference to the last element in the vector.
+ * This will assert when the vector is empty.
+ */
+ const T &last() const
+ {
+ BLI_assert(this->size() > 0);
+ return *(m_end - 1);
+ }
+
+ T &last()
+ {
+ BLI_assert(this->size() > 0);
+ return *(m_end - 1);
+ }
+
+ /**
+ * Replace every element with a new value.
+ */
+ void fill(const T &value)
+ {
+ std::fill(m_begin, m_end, value);
+ }
+
+ void fill_indices(ArrayRef<uint> indices, const T &value)
+ {
+ MutableArrayRef<T>(*this).fill_indices(indices, value);
+ }
+
+ /**
+ * Return how many values are currently stored in the vector.
+ */
+ uint size() const
+ {
+ BLI_assert(m_debug_size == (uint)(m_end - m_begin));
+ return (uint)(m_end - m_begin);
+ }
+
+ /**
+ * Returns true when the vector contains no elements, otherwise false.
+ */
+ bool empty() const
+ {
+ return m_begin == m_end;
+ }
+
+ /**
+ * Deconstructs the last element and decreases the size by one.
+ * This will assert when the vector is empty.
+ */
+ void remove_last()
+ {
+ BLI_assert(!this->empty());
+ m_end--;
+ destruct(m_end);
+ UPDATE_VECTOR_SIZE(this);
+ }
+
+ /**
+ * Remove the last element from the vector and return it.
+ */
+ T pop_last()
+ {
+ BLI_assert(!this->empty());
+ m_end--;
+ T value = std::move(*m_end);
+ destruct(m_end);
+ UPDATE_VECTOR_SIZE(this);
+ return value;
+ }
+
+ /**
+ * Delete any element in the vector.
+ * The empty space will be filled by the previously last element.
+ */
+ void remove_and_reorder(uint index)
+ {
+ BLI_assert(index < this->size());
+ T *element_to_remove = m_begin + index;
+ m_end--;
+ if (element_to_remove < m_end) {
+ *element_to_remove = std::move(*m_end);
+ }
+ destruct(m_end);
+ UPDATE_VECTOR_SIZE(this);
+ }
+
+ /**
+ * Do a linear search to find the value in the vector.
+ * When found, return the first index, otherwise return -1.
+ */
+ int index(const T &value) const
+ {
+ for (T *current = m_begin; current != m_end; current++) {
+ if (*current == value) {
+ return current - m_begin;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Do a linear search to see of the value is in the vector.
+ * Return true when it exists, otherwise false.
+ */
+ bool contains(const T &value) const
+ {
+ return this->index(value) != -1;
+ }
+
+ /**
+ * Compare vectors element-wise.
+ * Return true when they have the same length and all elements
+ * compare equal, otherwise false.
+ */
+ static bool all_equal(const Vector &a, const Vector &b)
+ {
+ if (a.size() != b.size()) {
+ return false;
+ }
+ for (uint i = 0; i < a.size(); i++) {
+ if (a[i] != b[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ const T &operator[](uint index) const
+ {
+ BLI_assert(index < this->size());
+ return m_begin[index];
+ }
+
+ T &operator[](uint index)
+ {
+ BLI_assert(index < this->size());
+ return m_begin[index];
+ }
+
+ T *begin()
+ {
+ return m_begin;
+ }
+ T *end()
+ {
+ return m_end;
+ }
+
+ const T *begin() const
+ {
+ return m_begin;
+ }
+ const T *end() const
+ {
+ return m_end;
+ }
+
+ /**
+ * Get the current capacity of the vector.
+ */
+ uint capacity() const
+ {
+ return (uint)(m_capacity_end - m_begin);
+ }
+
+ void print_stats() const
+ {
+ std::cout << "Small Vector at " << (void *)this << ":" << std::endl;
+ std::cout << " Elements: " << this->size() << std::endl;
+ std::cout << " Capacity: " << (m_capacity_end - m_begin) << std::endl;
+ std::cout << " Small Elements: " << N << " Size on Stack: " << sizeof(*this) << std::endl;
+ }
+
+ private:
+ T *small_buffer() const
+ {
+ return (T *)m_small_buffer;
+ }
+
+ bool is_small() const
+ {
+ return m_begin == this->small_buffer();
+ }
+
+ void ensure_space_for_one()
+ {
+ if (UNLIKELY(m_end >= m_capacity_end)) {
+ this->grow(std::max(this->size() * 2, (uint)1));
+ }
+ }
+
+ BLI_NOINLINE void grow(uint min_capacity)
+ {
+ if (this->capacity() >= min_capacity) {
+ return;
+ }
+
+ /* Round up to the next power of two. Otherwise consecutive calls to grow can cause a
+ * reallocation every time even though the min_capacity only increments. */
+ min_capacity = power_of_2_max_u(min_capacity);
+ uint size = this->size();
+
+ T *new_array = (T *)m_allocator.allocate_aligned(
+ min_capacity * (uint)sizeof(T), std::alignment_of<T>::value, __func__);
+ uninitialized_relocate_n(m_begin, size, new_array);
+
+ if (!this->is_small()) {
+ m_allocator.deallocate(m_begin);
+ }
+
+ m_begin = new_array;
+ m_end = m_begin + size;
+ m_capacity_end = m_begin + min_capacity;
+ }
+
+ /**
+ * Initialize all properties, except for m_allocator, which has to be initialized beforehand.
+ */
+ template<uint OtherN> void init_copy_from_other_vector(const Vector<T, OtherN, Allocator> &other)
+ {
+ m_allocator = other.m_allocator;
+
+ uint size = other.size();
+ uint capacity = size;
+
+ if (size <= N) {
+ m_begin = this->small_buffer();
+ capacity = N;
+ }
+ else {
+ m_begin = (T *)m_allocator.allocate_aligned(
+ sizeof(T) * size, std::alignment_of<T>::value, __func__);
+ capacity = size;
+ }
+
+ m_end = m_begin + size;
+ m_capacity_end = m_begin + capacity;
+
+ uninitialized_copy(other.begin(), other.end(), m_begin);
+ UPDATE_VECTOR_SIZE(this);
+ }
+};
+
+#undef UPDATE_VECTOR_SIZE
+
+template<typename T, uint N = 4> using TemporaryVector = Vector<T, N, TemporaryAllocator>;
+
+} /* namespace BLI */
+
+#endif /* __BLI_VECTOR_H__ */
diff --git a/source/blender/blenlib/BLI_vector_set.h b/source/blender/blenlib/BLI_vector_set.h
new file mode 100644
index 00000000000..fb21f7ed987
--- /dev/null
+++ b/source/blender/blenlib/BLI_vector_set.h
@@ -0,0 +1,425 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_VECTOR_SET_H__
+#define __BLI_VECTOR_SET_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * A VectorSet is a set built on top of a vector. The elements are stored in a continuous array,
+ * but every element exists at most once. The insertion order is maintained, as long as there are
+ * no deletes. The expected time to check if a value is in the VectorSet is O(1).
+ */
+
+#include "BLI_hash_cxx.h"
+#include "BLI_open_addressing.h"
+#include "BLI_vector.h"
+
+namespace BLI {
+
+// clang-format off
+
+#define ITER_SLOTS_BEGIN(VALUE, ARRAY, OPTIONAL_CONST, R_SLOT) \
+ uint32_t hash = DefaultHash<T>{}(VALUE); \
+ uint32_t perturb = hash; \
+ while (true) { \
+ for (uint i = 0; i < 4; i++) {\
+ uint32_t slot_index = (hash + i) & ARRAY.slot_mask(); \
+ OPTIONAL_CONST Slot &R_SLOT = ARRAY.item(slot_index);
+
+#define ITER_SLOTS_END \
+ } \
+ perturb >>= 5; \
+ hash = hash * 5 + 1 + perturb; \
+ } ((void)0)
+
+// clang-format on
+
+template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
+ private:
+ static constexpr int32_t IS_EMPTY = -1;
+ static constexpr int32_t IS_DUMMY = -2;
+
+ class Slot {
+ private:
+ int32_t m_value = IS_EMPTY;
+
+ public:
+ static constexpr uint slots_per_item = 1;
+
+ bool is_set() const
+ {
+ return m_value >= 0;
+ }
+
+ bool is_empty() const
+ {
+ return m_value == IS_EMPTY;
+ }
+
+ bool is_dummy() const
+ {
+ return m_value == IS_DUMMY;
+ }
+
+ bool has_value(const T &value, const Vector<T> &elements) const
+ {
+ return this->is_set() && elements[this->index()] == value;
+ }
+
+ bool has_index(uint index) const
+ {
+ return m_value == (int32_t)index;
+ }
+
+ uint index() const
+ {
+ BLI_assert(this->is_set());
+ return (uint)m_value;
+ }
+
+ int32_t &index_ref()
+ {
+ return m_value;
+ }
+
+ void set_index(uint index)
+ {
+ BLI_assert(!this->is_set());
+ m_value = (int32_t)index;
+ }
+
+ void set_dummy()
+ {
+ BLI_assert(this->is_set());
+ m_value = IS_DUMMY;
+ }
+ };
+
+ using ArrayType = OpenAddressingArray<Slot, 4, Allocator>;
+ ArrayType m_array;
+ Vector<T, 4, Allocator> m_elements;
+
+ public:
+ VectorSet()
+ {
+ BLI_assert(m_array.slots_usable() <= m_elements.capacity());
+ }
+
+ VectorSet(ArrayRef<T> values) : VectorSet()
+ {
+ this->add_multiple(values);
+ }
+
+ VectorSet(const std::initializer_list<T> &values) : VectorSet()
+ {
+ this->add_multiple(values);
+ }
+
+ VectorSet(const Vector<T> &values) : VectorSet()
+ {
+ this->add_multiple(values);
+ }
+
+ /**
+ * Allocate memory such that at least min_usable_slots can be added without having to grow again.
+ */
+ void reserve(uint min_usable_slots)
+ {
+ if (m_array.slots_usable() < min_usable_slots) {
+ this->grow(min_usable_slots);
+ }
+ }
+
+ /**
+ * Add a new element. The method assumes that the value did not exist before.
+ */
+ void add_new(const T &value)
+ {
+ this->add_new__impl(value);
+ }
+ void add_new(T &&value)
+ {
+ this->add_new__impl(std::move(value));
+ }
+
+ /**
+ * Add a new element if it does not exist yet. Does not add the value again if it exists already.
+ */
+ bool add(const T &value)
+ {
+ return this->add__impl(value);
+ }
+ bool add(T &&value)
+ {
+ return this->add__impl(std::move(value));
+ }
+
+ /**
+ * Add multiple values. Duplicates will not be inserted.
+ */
+ void add_multiple(ArrayRef<T> values)
+ {
+ for (const T &value : values) {
+ this->add(value);
+ }
+ }
+
+ /**
+ * Returns true when the value is in the set-vector, otherwise false.
+ */
+ bool contains(const T &value) const
+ {
+ ITER_SLOTS_BEGIN (value, m_array, const, slot) {
+ if (slot.is_empty()) {
+ return false;
+ }
+ else if (slot.has_value(value, m_elements)) {
+ return true;
+ }
+ }
+ ITER_SLOTS_END;
+ }
+
+ /**
+ * Remove a value from the set-vector. The method assumes that the value exists.
+ */
+ void remove(const T &value)
+ {
+ BLI_assert(this->contains(value));
+ ITER_SLOTS_BEGIN (value, m_array, , slot) {
+ if (slot.has_value(value, m_elements)) {
+ uint old_index = m_elements.size() - 1;
+ uint new_index = slot.index();
+
+ m_elements.remove_and_reorder(new_index);
+ slot.set_dummy();
+ m_array.update__set_to_dummy();
+
+ if (old_index != new_index) {
+ T &moved_value = m_elements[new_index];
+ this->update_slot_index(moved_value, old_index, new_index);
+ }
+ return;
+ }
+ }
+ ITER_SLOTS_END;
+ }
+
+ /**
+ * Get and remove the last element of the vector.
+ */
+ T pop()
+ {
+ BLI_assert(this->size() > 0);
+ T value = m_elements.pop_last();
+ uint old_index = m_elements.size();
+
+ ITER_SLOTS_BEGIN (value, m_array, , slot) {
+ if (slot.has_index(old_index)) {
+ slot.set_dummy();
+ m_array.update__set_to_dummy();
+ return value;
+ }
+ }
+ ITER_SLOTS_END;
+ }
+
+ /**
+ * Get the index of the value in the vector. It is assumed that the value is in the vector.
+ */
+ uint index(const T &value) const
+ {
+ BLI_assert(this->contains(value));
+ ITER_SLOTS_BEGIN (value, m_array, const, slot) {
+ if (slot.has_value(value, m_elements)) {
+ return slot.index();
+ }
+ }
+ ITER_SLOTS_END;
+ }
+
+ /**
+ * Get the index of the value in the vector. If it does not exist return -1.
+ */
+ int index_try(const T &value) const
+ {
+ ITER_SLOTS_BEGIN (value, m_array, const, slot) {
+ if (slot.has_value(value, m_elements)) {
+ return slot.index();
+ }
+ else if (slot.is_empty()) {
+ return -1;
+ }
+ }
+ ITER_SLOTS_END;
+ }
+
+ /**
+ * Get the number of elements in the set-vector.
+ */
+ uint size() const
+ {
+ return m_array.slots_set();
+ }
+
+ const T *begin() const
+ {
+ return m_elements.begin();
+ }
+
+ const T *end() const
+ {
+ return m_elements.end();
+ }
+
+ const T &operator[](uint index) const
+ {
+ return m_elements[index];
+ }
+
+ operator ArrayRef<T>() const
+ {
+ return m_elements;
+ }
+
+ operator MutableArrayRef<T>()
+ {
+ return m_elements;
+ }
+
+ void print_stats() const
+ {
+ std::cout << "VectorSet at " << (void *)this << ":\n";
+ std::cout << " Size: " << this->size() << "\n";
+ std::cout << " Usable Slots: " << m_array.slots_usable() << "\n";
+ std::cout << " Total Slots: " << m_array.slots_total() << "\n";
+ std::cout << " Average Collisions: " << this->compute_average_collisions() << "\n";
+ }
+
+ private:
+ void update_slot_index(T &value, uint old_index, uint new_index)
+ {
+ ITER_SLOTS_BEGIN (value, m_array, , slot) {
+ int32_t &stored_index = slot.index_ref();
+ if (stored_index == old_index) {
+ stored_index = new_index;
+ return;
+ }
+ }
+ ITER_SLOTS_END;
+ }
+
+ template<typename ForwardT> void add_new_in_slot(Slot &slot, ForwardT &&value)
+ {
+ uint index = m_elements.size();
+ slot.set_index(index);
+ m_elements.append_unchecked(std::forward<ForwardT>(value));
+ m_array.update__empty_to_set();
+ }
+
+ void ensure_can_add()
+ {
+ if (UNLIKELY(m_array.should_grow())) {
+ this->grow(this->size() + 1);
+ }
+ }
+
+ BLI_NOINLINE void grow(uint min_usable_slots)
+ {
+ ArrayType new_array = m_array.init_reserved(min_usable_slots);
+
+ for (uint i = 0; i < m_elements.size(); i++) {
+ this->add_after_grow(i, new_array);
+ }
+
+ m_array = std::move(new_array);
+ m_elements.reserve(m_array.slots_usable());
+ }
+
+ void add_after_grow(uint index, ArrayType &new_array)
+ {
+ const T &value = m_elements[index];
+ ITER_SLOTS_BEGIN (value, new_array, , slot) {
+ if (slot.is_empty()) {
+ slot.set_index(index);
+ return;
+ }
+ }
+ ITER_SLOTS_END;
+ }
+
+ float compute_average_collisions() const
+ {
+ if (m_elements.size() == 0) {
+ return 0.0f;
+ }
+
+ uint collisions_sum = 0;
+ for (const T &value : m_elements) {
+ collisions_sum += this->count_collisions(value);
+ }
+ return (float)collisions_sum / (float)m_elements.size();
+ }
+
+ uint count_collisions(const T &value) const
+ {
+ uint collisions = 0;
+ ITER_SLOTS_BEGIN (value, m_array, const, slot) {
+ if (slot.is_empty() || slot.has_value(value, m_elements)) {
+ return collisions;
+ }
+ collisions++;
+ }
+ ITER_SLOTS_END;
+ }
+
+ template<typename ForwardT> void add_new__impl(ForwardT &&value)
+ {
+ BLI_assert(!this->contains(value));
+ this->ensure_can_add();
+ ITER_SLOTS_BEGIN (value, m_array, , slot) {
+ if (slot.is_empty()) {
+ this->add_new_in_slot(slot, std::forward<ForwardT>(value));
+ return;
+ }
+ }
+ ITER_SLOTS_END;
+ }
+
+ template<typename ForwardT> bool add__impl(ForwardT &&value)
+ {
+ this->ensure_can_add();
+ ITER_SLOTS_BEGIN (value, m_array, , slot) {
+ if (slot.is_empty()) {
+ this->add_new_in_slot(slot, std::forward<ForwardT>(value));
+ return true;
+ }
+ else if (slot.has_value(value, m_elements)) {
+ return false;
+ }
+ }
+ ITER_SLOTS_END;
+ }
+};
+
+#undef ITER_SLOTS_BEGIN
+#undef ITER_SLOTS_END
+
+} // namespace BLI
+
+#endif /* __BLI_VECTOR_SET_H__ */
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 7f6e9d49b17..f3740b5d39f 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -44,6 +44,7 @@ set(SRC
intern/BLI_ghash_utils.c
intern/BLI_heap.c
intern/BLI_heap_simple.c
+ intern/BLI_index_range.cc
intern/BLI_kdopbvh.c
intern/BLI_linklist.c
intern/BLI_linklist_lockfree.c
@@ -51,6 +52,7 @@ set(SRC
intern/BLI_memblock.c
intern/BLI_memiter.c
intern/BLI_mempool.c
+ intern/BLI_temporary_allocator.cc
intern/BLI_timer.c
intern/DLRB_tree.c
intern/array_store.c
@@ -61,7 +63,6 @@ set(SRC
intern/bitmap_draw_2d.c
intern/boxpack_2d.c
intern/buffer.c
- intern/callbacks.c
intern/convexhull_2d.c
intern/delaunay_2d.c
intern/dynlib.c
@@ -132,9 +133,14 @@ set(SRC
intern/kdtree_impl.h
intern/list_sort_impl.h
+
+
BLI_alloca.h
+ BLI_allocator.h
BLI_args.h
BLI_array.h
+ BLI_array_cxx.h
+ BLI_array_ref.h
BLI_array_store.h
BLI_array_store_utils.h
BLI_array_utils.h
@@ -145,7 +151,6 @@ set(SRC
BLI_blenlib.h
BLI_boxpack_2d.h
BLI_buffer.h
- BLI_callbacks.h
BLI_compiler_attrs.h
BLI_compiler_compat.h
BLI_compiler_typecheck.h
@@ -167,11 +172,13 @@ set(SRC
BLI_ghash.h
BLI_gsqueue.h
BLI_hash.h
+ BLI_hash_cxx.h
BLI_hash_md5.h
BLI_hash_mm2a.h
BLI_hash_mm3.h
BLI_heap.h
BLI_heap_simple.h
+ BLI_index_range.h
BLI_iterator.h
BLI_jitter_2d.h
BLI_kdopbvh.h
@@ -183,6 +190,8 @@ set(SRC
BLI_linklist_lockfree.h
BLI_linklist_stack.h
BLI_listbase.h
+ BLI_listbase_wrapper.h
+ BLI_map.h
BLI_math.h
BLI_math_base.h
BLI_math_bits.h
@@ -200,8 +209,10 @@ set(SRC
BLI_memblock.h
BLI_memiter.h
BLI_memory_utils.h
+ BLI_memory_utils_cxx.h
BLI_mempool.h
BLI_noise.h
+ BLI_open_addressing.h
BLI_path_util.h
BLI_polyfill_2d.h
BLI_polyfill_2d_beautify.h
@@ -209,18 +220,24 @@ set(SRC
BLI_rand.h
BLI_rect.h
BLI_scanfill.h
+ BLI_set.h
BLI_smallhash.h
BLI_sort.h
BLI_sort_utils.h
BLI_stack.h
+ BLI_stack_cxx.h
BLI_strict_flags.h
BLI_string.h
BLI_string_cursor_utf8.h
+ BLI_string_map.h
+ BLI_string_ref.h
BLI_string_utf8.h
BLI_string_utils.h
BLI_sys_types.h
BLI_system.h
BLI_task.h
+ BLI_temporary_allocator.h
+ BLI_temporary_allocator_cxx.h
BLI_threads.h
BLI_timecode.h
BLI_timer.h
@@ -229,6 +246,8 @@ set(SRC
BLI_utildefines_stack.h
BLI_utildefines_variadic.h
BLI_uvproject.h
+ BLI_vector.h
+ BLI_vector_set.h
BLI_vfontdata.h
BLI_voronoi_2d.h
BLI_voxel.h
diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c
index 91f16ca9b7b..a3b745fd63e 100644
--- a/source/blender/blenlib/intern/BLI_filelist.c
+++ b/source/blender/blenlib/intern/BLI_filelist.c
@@ -107,7 +107,7 @@ static int bli_compare(struct direntry *entry1, struct direntry *entry2)
return 1;
}
- return (BLI_natstrcmp(entry1->relname, entry2->relname));
+ return (BLI_strcasecmp_natural(entry1->relname, entry2->relname));
}
struct BuildDirCtx {
@@ -261,36 +261,21 @@ unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_
*/
void BLI_filelist_entry_size_to_string(const struct stat *st,
const uint64_t sz,
- const bool compact,
+ /* Used to change MB -> M, etc. - is that really useful? */
+ const bool UNUSED(compact),
char r_size[FILELIST_DIRENTRY_SIZE_LEN])
{
- double size;
- const char *fmt;
- const char *units[] = {"KiB", "MiB", "GiB", "TiB", NULL};
- const char *units_compact[] = {"K", "M", "G", "T", NULL};
- const char *unit = "B";
-
/*
* Seems st_size is signed 32-bit value in *nix and Windows. This
* will buy us some time until files get bigger than 4GB or until
* everyone starts using __USE_FILE_OFFSET64 or equivalent.
*/
- size = (double)(st ? st->st_size : sz);
-
- if (size > 1024.0) {
- const char **u;
- for (u = compact ? units_compact : units, size /= 1024.0; size > 1024.0 && *(u + 1);
- u++, size /= 1024.0) {
- /* pass */
- }
- fmt = size > 100.0 ? "%.0f %s" : (size > 10.0 ? "%.1f %s" : "%.2f %s");
- unit = *u;
- }
- else {
- fmt = "%.0f %s";
- }
-
- BLI_snprintf(r_size, sizeof(*r_size) * FILELIST_DIRENTRY_SIZE_LEN, fmt, size, unit);
+ double size = (double)(st ? st->st_size : sz);
+#ifdef WIN32
+ BLI_str_format_byte_unit(r_size, size, false);
+#else
+ BLI_str_format_byte_unit(r_size, size, true);
+#endif
}
/**
@@ -366,14 +351,45 @@ void BLI_filelist_entry_owner_to_string(const struct stat *st,
/**
* Convert given entry's time into human-readable strings.
+ *
+ * \param r_is_today: optional, returns true if the date matches today's.
+ * \param r_is_yesterday: optional, returns true if the date matches yesterday's.
*/
void BLI_filelist_entry_datetime_to_string(const struct stat *st,
const int64_t ts,
const bool compact,
char r_time[FILELIST_DIRENTRY_TIME_LEN],
- char r_date[FILELIST_DIRENTRY_DATE_LEN])
+ char r_date[FILELIST_DIRENTRY_DATE_LEN],
+ bool *r_is_today,
+ bool *r_is_yesterday)
{
- time_t ts_mtime = ts;
+ int today_year = 0;
+ int today_yday = 0;
+ int yesterday_year = 0;
+ int yesterday_yday = 0;
+
+ if (r_is_today || r_is_yesterday) {
+ /* Localtime() has only one buffer so need to get data out before called again. */
+ const time_t ts_now = time(NULL);
+ struct tm *today = localtime(&ts_now);
+
+ today_year = today->tm_year;
+ today_yday = today->tm_yday;
+ /* Handle a yesterday that spans a year */
+ today->tm_mday--;
+ mktime(today);
+ yesterday_year = today->tm_year;
+ yesterday_yday = today->tm_yday;
+
+ if (r_is_today) {
+ *r_is_today = false;
+ }
+ if (r_is_yesterday) {
+ *r_is_yesterday = false;
+ }
+ }
+
+ const time_t ts_mtime = ts;
const struct tm *tm = localtime(st ? &st->st_mtime : &ts_mtime);
const time_t zero = 0;
@@ -385,12 +401,20 @@ void BLI_filelist_entry_datetime_to_string(const struct stat *st,
if (r_time) {
strftime(r_time, sizeof(*r_time) * FILELIST_DIRENTRY_TIME_LEN, "%H:%M", tm);
}
+
if (r_date) {
strftime(r_date,
sizeof(*r_date) * FILELIST_DIRENTRY_DATE_LEN,
- compact ? "%d/%m/%y" : "%d-%b-%y",
+ compact ? "%d/%m/%y" : "%d %b %Y",
tm);
}
+
+ if (r_is_today && (tm->tm_year == today_year) && (tm->tm_yday == today_yday)) {
+ *r_is_today = true;
+ }
+ else if (r_is_yesterday && (tm->tm_year == yesterday_year) && (tm->tm_yday == yesterday_yday)) {
+ *r_is_yesterday = true;
+ }
}
/**
@@ -417,7 +441,7 @@ void BLI_filelist_duplicate(struct direntry **dest_filelist,
unsigned int i;
*dest_filelist = MEM_mallocN(sizeof(**dest_filelist) * (size_t)(nrentries), __func__);
- for (i = 0; i < nrentries; ++i) {
+ for (i = 0; i < nrentries; i++) {
struct direntry *const src = &src_filelist[i];
struct direntry *dst = &(*dest_filelist)[i];
BLI_filelist_entry_duplicate(dst, src);
@@ -443,7 +467,7 @@ void BLI_filelist_entry_free(struct direntry *entry)
void BLI_filelist_free(struct direntry *filelist, const unsigned int nrentries)
{
unsigned int i;
- for (i = 0; i < nrentries; ++i) {
+ for (i = 0; i < nrentries; i++) {
BLI_filelist_entry_free(&filelist[i]);
}
diff --git a/source/blender/blenlib/intern/BLI_index_range.cc b/source/blender/blenlib/intern/BLI_index_range.cc
new file mode 100644
index 00000000000..fde4dcf6d41
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_index_range.cc
@@ -0,0 +1,60 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <atomic>
+#include <mutex>
+
+#include "BLI_index_range.h"
+#include "BLI_array_ref.h"
+#include "BLI_array_cxx.h"
+#include "BLI_vector.h"
+
+namespace BLI {
+
+static Vector<Array<uint, RawAllocator>, 1, RawAllocator> arrays;
+static uint current_array_size = 0;
+static uint *current_array = nullptr;
+static std::mutex current_array_mutex;
+
+ArrayRef<uint> IndexRange::as_array_ref() const
+{
+ uint min_required_size = m_start + m_size;
+
+ if (min_required_size <= current_array_size) {
+ return ArrayRef<uint>(current_array + m_start, m_size);
+ }
+
+ std::lock_guard<std::mutex> lock(current_array_mutex);
+
+ if (min_required_size <= current_array_size) {
+ return ArrayRef<uint>(current_array + m_start, m_size);
+ }
+
+ uint new_size = std::max<uint>(1000, power_of_2_max_u(min_required_size));
+ Array<uint, RawAllocator> new_array(new_size);
+ for (uint i = 0; i < new_size; i++) {
+ new_array[i] = i;
+ }
+ arrays.append(std::move(new_array));
+
+ current_array = arrays.last().begin();
+ std::atomic_thread_fence(std::memory_order_seq_cst);
+ current_array_size = new_size;
+
+ return ArrayRef<uint>(current_array + m_start, m_size);
+}
+
+} // namespace BLI
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index 0e93fd8e13b..ae862c5ece5 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -1184,6 +1184,56 @@ static void tree_overlap_traverse_cb(BVHOverlapData_Thread *data_thread,
}
/**
+ * a version of #tree_overlap_traverse_cb that that break on first true return.
+ */
+static bool tree_overlap_traverse_first_cb(BVHOverlapData_Thread *data_thread,
+ const BVHNode *node1,
+ const BVHNode *node2)
+{
+ BVHOverlapData_Shared *data = data_thread->shared;
+ int j;
+
+ if (tree_overlap_test(node1, node2, data->start_axis, data->stop_axis)) {
+ /* check if node1 is a leaf */
+ if (!node1->totnode) {
+ /* check if node2 is a leaf */
+ if (!node2->totnode) {
+ BVHTreeOverlap *overlap;
+
+ if (UNLIKELY(node1 == node2)) {
+ return false;
+ }
+
+ /* only difference to tree_overlap_traverse! */
+ if (!data->callback ||
+ data->callback(data->userdata, node1->index, node2->index, data_thread->thread)) {
+ /* both leafs, insert overlap! */
+ if (data_thread->overlap) {
+ overlap = BLI_stack_push_r(data_thread->overlap);
+ overlap->indexA = node1->index;
+ overlap->indexB = node2->index;
+ }
+ return true;
+ }
+ }
+ else {
+ for (j = 0; j < node2->totnode; j++) {
+ if (tree_overlap_traverse_first_cb(data_thread, node1, node2->children[j])) {
+ return true;
+ }
+ }
+ }
+ }
+ else {
+ for (j = 0; j < node1->totnode; j++) {
+ tree_overlap_traverse_first_cb(data_thread, node1->children[j], node2);
+ }
+ }
+ }
+ return false;
+}
+
+/**
* Use to check the total number of threads #BLI_bvhtree_overlap will use.
*
* \warning Must be the first tree passed to #BLI_bvhtree_overlap!
@@ -1212,14 +1262,35 @@ static void bvhtree_overlap_task_cb(void *__restrict userdata,
}
}
-BVHTreeOverlap *BLI_bvhtree_overlap(
+static void bvhtree_overlap_first_task_cb(void *__restrict userdata,
+ const int j,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ BVHOverlapData_Thread *data = &((BVHOverlapData_Thread *)userdata)[j];
+ BVHOverlapData_Shared *data_shared = data->shared;
+
+ tree_overlap_traverse_first_cb(
+ data,
+ data_shared->tree1->nodes[data_shared->tree1->totleaf]->children[j],
+ data_shared->tree2->nodes[data_shared->tree2->totleaf]);
+}
+
+BVHTreeOverlap *BLI_bvhtree_overlap_ex(
const BVHTree *tree1,
const BVHTree *tree2,
uint *r_overlap_tot,
/* optional callback to test the overlap before adding (must be thread-safe!) */
BVHTree_OverlapCallback callback,
- void *userdata)
+ void *userdata,
+ int flag)
{
+ bool use_threading = (flag & BVH_OVERLAP_USE_THREADING) != 0;
+ bool overlap_pairs = (flag & BVH_OVERLAP_RETURN_PAIRS) != 0;
+ bool break_on_first = (flag & BVH_OVERLAP_BREAK_ON_FIRST) != 0;
+
+ /* `RETURN_PAIRS` was not implemented without `BREAK_ON_FIRST`. */
+ BLI_assert(overlap_pairs || break_on_first);
+
const int thread_num = BLI_bvhtree_overlap_thread_num(tree1);
int j;
size_t total = 0;
@@ -1256,7 +1327,7 @@ BVHTreeOverlap *BLI_bvhtree_overlap(
for (j = 0; j < thread_num; j++) {
/* init BVHOverlapData_Thread */
data[j].shared = &data_shared;
- data[j].overlap = BLI_stack_new(sizeof(BVHTreeOverlap), __func__);
+ data[j].overlap = overlap_pairs ? BLI_stack_new(sizeof(BVHTreeOverlap), __func__) : NULL;
/* for callback */
data[j].thread = j;
@@ -1264,26 +1335,48 @@ BVHTreeOverlap *BLI_bvhtree_overlap(
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (tree1->totleaf > KDOPBVH_THREAD_LEAF_THRESHOLD);
- BLI_task_parallel_range(0, thread_num, data, bvhtree_overlap_task_cb, &settings);
+ settings.use_threading = use_threading && (tree1->totleaf > KDOPBVH_THREAD_LEAF_THRESHOLD);
+ BLI_task_parallel_range(0,
+ thread_num,
+ data,
+ break_on_first ? bvhtree_overlap_first_task_cb : bvhtree_overlap_task_cb,
+ &settings);
- for (j = 0; j < thread_num; j++) {
- total += BLI_stack_count(data[j].overlap);
- }
+ if (overlap_pairs) {
+ for (j = 0; j < thread_num; j++) {
+ total += BLI_stack_count(data[j].overlap);
+ }
- to = overlap = MEM_mallocN(sizeof(BVHTreeOverlap) * total, "BVHTreeOverlap");
+ to = overlap = MEM_mallocN(sizeof(BVHTreeOverlap) * total, "BVHTreeOverlap");
- for (j = 0; j < thread_num; j++) {
- uint count = (uint)BLI_stack_count(data[j].overlap);
- BLI_stack_pop_n(data[j].overlap, to, count);
- BLI_stack_free(data[j].overlap);
- to += count;
+ for (j = 0; j < thread_num; j++) {
+ uint count = (uint)BLI_stack_count(data[j].overlap);
+ BLI_stack_pop_n(data[j].overlap, to, count);
+ BLI_stack_free(data[j].overlap);
+ to += count;
+ }
+ *r_overlap_tot = (uint)total;
}
- *r_overlap_tot = (uint)total;
return overlap;
}
+BVHTreeOverlap *BLI_bvhtree_overlap(
+ const BVHTree *tree1,
+ const BVHTree *tree2,
+ uint *r_overlap_tot,
+ /* optional callback to test the overlap before adding (must be thread-safe!) */
+ BVHTree_OverlapCallback callback,
+ void *userdata)
+{
+ return BLI_bvhtree_overlap_ex(tree1,
+ tree2,
+ r_overlap_tot,
+ callback,
+ userdata,
+ BVH_OVERLAP_USE_THREADING | BVH_OVERLAP_RETURN_PAIRS);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1467,6 +1560,95 @@ int BLI_bvhtree_find_nearest(BVHTree *tree,
/** \} */
/* -------------------------------------------------------------------- */
+/** \name BLI_bvhtree_find_nearest_first
+ * \{ */
+
+static bool isect_aabb_v3(BVHNode *node, const float co[3])
+{
+ const BVHTreeAxisRange *bv = (const BVHTreeAxisRange *)node->bv;
+
+ if (co[0] > bv[0].min && co[0] < bv[0].max && co[1] > bv[1].min && co[1] < bv[1].max &&
+ co[2] > bv[2].min && co[2] < bv[2].max) {
+ return true;
+ }
+
+ return false;
+}
+
+static bool dfs_find_duplicate_fast_dfs(BVHNearestData *data, BVHNode *node)
+{
+ if (node->totnode == 0) {
+ if (isect_aabb_v3(node, data->co)) {
+ if (data->callback) {
+ const float dist_sq = data->nearest.dist_sq;
+ data->callback(data->userdata, node->index, data->co, &data->nearest);
+ return (data->nearest.dist_sq < dist_sq);
+ }
+ else {
+ data->nearest.index = node->index;
+ return true;
+ }
+ }
+ }
+ else {
+ /* Better heuristic to pick the closest node to dive on */
+ int i;
+
+ if (data->proj[node->main_axis] <= node->children[0]->bv[node->main_axis * 2 + 1]) {
+ for (i = 0; i != node->totnode; i++) {
+ if (isect_aabb_v3(node->children[i], data->co)) {
+ if (dfs_find_duplicate_fast_dfs(data, node->children[i])) {
+ return true;
+ }
+ }
+ }
+ }
+ else {
+ for (i = node->totnode; i--;) {
+ if (isect_aabb_v3(node->children[i], data->co)) {
+ if (dfs_find_duplicate_fast_dfs(data, node->children[i])) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+/**
+ * Find the first node nearby.
+ * Favors speed over quality since it doesn't find the best target node.
+ */
+int BLI_bvhtree_find_nearest_first(BVHTree *tree,
+ const float co[3],
+ const float dist_sq,
+ BVHTree_NearestPointCallback callback,
+ void *userdata)
+{
+ BVHNearestData data;
+ BVHNode *root = tree->nodes[tree->totleaf];
+
+ /* init data to search */
+ data.tree = tree;
+ data.co = co;
+
+ data.callback = callback;
+ data.userdata = userdata;
+ data.nearest.index = -1;
+ data.nearest.dist_sq = dist_sq;
+
+ /* dfs search */
+ if (root) {
+ dfs_find_duplicate_fast_dfs(&data, root);
+ }
+
+ return data.nearest.index;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name BLI_bvhtree_ray_cast
*
* raycast is done by performing a DFS on the BVHTree and saving the closest hit.
diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c
index ae4f5dcebcf..0fe9fd62198 100644
--- a/source/blender/blenlib/intern/BLI_linklist.c
+++ b/source/blender/blenlib/intern/BLI_linklist.c
@@ -325,7 +325,7 @@ void BLI_linklist_apply(LinkNode *list, LinkNodeApplyFP applyfunc, void *userdat
#include "list_sort_impl.h"
#undef SORT_IMPL_FUNC
-/* reentrant call */
+/* re-entrant call */
#define SORT_IMPL_USE_THUNK
#define SORT_IMPL_FUNC linklist_sort_fn_r
#include "list_sort_impl.h"
diff --git a/source/blender/blenlib/intern/BLI_memblock.c b/source/blender/blenlib/intern/BLI_memblock.c
index f26860afe77..f7239f1b9d1 100644
--- a/source/blender/blenlib/intern/BLI_memblock.c
+++ b/source/blender/blenlib/intern/BLI_memblock.c
@@ -37,7 +37,6 @@
#include "BLI_strict_flags.h" /* keep last */
-#define BLI_MEM_BLOCK_CHUNK_SIZE (1 << 15) /* 32KiB */
#define CHUNK_LIST_SIZE 16
struct BLI_memblock {
@@ -61,18 +60,19 @@ struct BLI_memblock {
int chunk_len;
};
-BLI_memblock *BLI_memblock_create(uint elem_size)
+BLI_memblock *BLI_memblock_create_ex(uint elem_size, uint chunk_size)
{
- BLI_assert(elem_size < BLI_MEM_BLOCK_CHUNK_SIZE);
+ BLI_assert(elem_size < chunk_size);
BLI_memblock *mblk = MEM_mallocN(sizeof(BLI_memblock), "BLI_memblock");
mblk->elem_size = (int)elem_size;
mblk->elem_next = 0;
mblk->elem_last = -1;
- mblk->chunk_size = BLI_MEM_BLOCK_CHUNK_SIZE;
+ mblk->chunk_size = (int)chunk_size;
mblk->chunk_len = CHUNK_LIST_SIZE;
mblk->chunk_list = MEM_callocN(sizeof(void *) * (uint)mblk->chunk_len, "chunk list");
- mblk->chunk_list[0] = MEM_callocN((uint)mblk->chunk_size, "BLI_memblock chunk");
+ mblk->chunk_list[0] = MEM_mallocN_aligned((uint)mblk->chunk_size, 32, "BLI_memblock chunk");
+ memset(mblk->chunk_list[0], 0x0, (uint)mblk->chunk_size);
mblk->chunk_max_ofs = (mblk->chunk_size / mblk->elem_size) * mblk->elem_size;
mblk->elem_next_ofs = 0;
mblk->chunk_next = 0;
@@ -143,8 +143,9 @@ void *BLI_memblock_alloc(BLI_memblock *mblk)
}
if (UNLIKELY(mblk->chunk_list[mblk->chunk_next] == NULL)) {
- mblk->chunk_list[mblk->chunk_next] = MEM_callocN((uint)mblk->chunk_size,
- "BLI_memblock chunk");
+ mblk->chunk_list[mblk->chunk_next] = MEM_mallocN_aligned(
+ (uint)mblk->chunk_size, 32, "BLI_memblock chunk");
+ memset(mblk->chunk_list[mblk->chunk_next], 0x0, (uint)mblk->chunk_size);
}
}
return ptr;
@@ -180,3 +181,11 @@ void *BLI_memblock_iterstep(BLI_memblock_iter *iter)
}
return ptr;
}
+
+/* Direct access. elem is element index inside the chosen chunk. */
+void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem)
+{
+ BLI_assert(chunk < mblk->chunk_len);
+ BLI_assert(elem < (mblk->chunk_size / mblk->elem_size));
+ return (char *)(mblk->chunk_list[chunk]) + mblk->elem_size * elem;
+}
diff --git a/source/blender/blenlib/intern/BLI_temporary_allocator.cc b/source/blender/blenlib/intern/BLI_temporary_allocator.cc
new file mode 100644
index 00000000000..e41cf36f66d
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_temporary_allocator.cc
@@ -0,0 +1,115 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <mutex>
+#include <stack>
+
+#include "BLI_temporary_allocator.h"
+#include "BLI_stack_cxx.h"
+
+using namespace BLI;
+
+constexpr uint ALIGNMENT = BLI_TEMPORARY_BUFFER_ALIGNMENT;
+constexpr uint SMALL_BUFFER_SIZE = 64 * 1024;
+constexpr uintptr_t ALIGNMENT_MASK = ~(uintptr_t)(ALIGNMENT - 1);
+
+enum TemporaryBufferType {
+ Small,
+ Large,
+};
+
+struct MemHead {
+ void *raw_ptr;
+ TemporaryBufferType type;
+};
+
+static MemHead &get_memhead(void *aligned_ptr)
+{
+ return *((MemHead *)aligned_ptr - 1);
+}
+
+static void *raw_allocate(uint size)
+{
+ uint total_allocation_size = size + ALIGNMENT + sizeof(MemHead);
+
+ uintptr_t raw_ptr = (uintptr_t)malloc(total_allocation_size);
+ uintptr_t aligned_ptr = (raw_ptr + ALIGNMENT + sizeof(MemHead)) & ALIGNMENT_MASK;
+
+ MemHead &memhead = get_memhead((void *)aligned_ptr);
+ memhead.raw_ptr = (void *)raw_ptr;
+ return (void *)aligned_ptr;
+}
+
+static void raw_deallocate(void *ptr)
+{
+ BLI_assert(((uintptr_t)ptr & ~ALIGNMENT_MASK) == 0);
+ MemHead &memhead = get_memhead(ptr);
+ void *raw_ptr = memhead.raw_ptr;
+ free(raw_ptr);
+}
+
+struct ThreadLocalBuffers {
+ uint allocated_amount = 0;
+ Stack<void *, 32, RawAllocator> buffers;
+
+ ~ThreadLocalBuffers()
+ {
+ for (void *ptr : buffers) {
+ raw_deallocate(ptr);
+ }
+ }
+};
+
+thread_local ThreadLocalBuffers local_storage;
+
+void *BLI_temporary_allocate(uint size)
+{
+ /* The total amount of allocated buffers using this allocator should be limited by a constant. If
+ * it grows unbounded, there is likely a memory leak somewhere. */
+ BLI_assert(local_storage.allocated_amount < 100);
+
+ if (size <= SMALL_BUFFER_SIZE) {
+ auto &buffers = local_storage.buffers;
+ if (buffers.empty()) {
+ void *ptr = raw_allocate(SMALL_BUFFER_SIZE);
+ MemHead &memhead = get_memhead(ptr);
+ memhead.type = TemporaryBufferType::Small;
+ local_storage.allocated_amount++;
+ return ptr;
+ }
+ else {
+ return buffers.pop();
+ }
+ }
+ else {
+ void *ptr = raw_allocate(size);
+ MemHead &memhead = get_memhead(ptr);
+ memhead.type = TemporaryBufferType::Large;
+ return ptr;
+ }
+}
+
+void BLI_temporary_deallocate(void *buffer)
+{
+ MemHead &memhead = get_memhead(buffer);
+ if (memhead.type == TemporaryBufferType::Small) {
+ auto &buffers = local_storage.buffers;
+ buffers.push(buffer);
+ }
+ else {
+ raw_deallocate(buffer);
+ }
+}
diff --git a/source/blender/blenlib/intern/BLI_timer.c b/source/blender/blenlib/intern/BLI_timer.c
index bf9fd1b57f8..0443dea9a2e 100644
--- a/source/blender/blenlib/intern/BLI_timer.c
+++ b/source/blender/blenlib/intern/BLI_timer.c
@@ -23,7 +23,6 @@
#include "BLI_timer.h"
#include "BLI_listbase.h"
-#include "BLI_callbacks.h"
#include "MEM_guardedalloc.h"
#include "PIL_time.h"
@@ -48,8 +47,6 @@ typedef struct TimerContainer {
static TimerContainer GlobalTimer = {{0}};
-static void ensure_callback_is_registered(void);
-
void BLI_timer_register(uintptr_t uuid,
BLI_timer_func func,
void *user_data,
@@ -57,8 +54,6 @@ void BLI_timer_register(uintptr_t uuid,
double first_interval,
bool persistent)
{
- ensure_callback_is_registered();
-
TimedFunction *timed_func = MEM_callocN(sizeof(TimedFunction), __func__);
timed_func->func = func;
timed_func->user_data_free = user_data_free;
@@ -82,15 +77,10 @@ static void clear_user_data(TimedFunction *timed_func)
bool BLI_timer_unregister(uintptr_t uuid)
{
LISTBASE_FOREACH (TimedFunction *, timed_func, &GlobalTimer.funcs) {
- if (timed_func->uuid == uuid) {
- if (timed_func->tag_removal) {
- return false;
- }
- else {
- timed_func->tag_removal = true;
- clear_user_data(timed_func);
- return true;
- }
+ if (timed_func->uuid == uuid && !timed_func->tag_removal) {
+ timed_func->tag_removal = true;
+ clear_user_data(timed_func);
+ return true;
}
}
return false;
@@ -156,11 +146,7 @@ void BLI_timer_free()
remove_tagged_functions();
}
-struct ID;
-struct Main;
-static void remove_non_persistent_functions(struct Main *UNUSED(_1),
- struct ID *UNUSED(_2),
- void *UNUSED(_3))
+static void remove_non_persistent_functions(void)
{
LISTBASE_FOREACH (TimedFunction *, timed_func, &GlobalTimer.funcs) {
if (!timed_func->persistent) {
@@ -169,18 +155,7 @@ static void remove_non_persistent_functions(struct Main *UNUSED(_1),
}
}
-static bCallbackFuncStore load_pre_callback = {
- NULL,
- NULL, /* next, prev */
- remove_non_persistent_functions, /* func */
- NULL, /* arg */
- 0, /* alloc */
-};
-
-static void ensure_callback_is_registered()
+void BLI_timer_on_file_load(void)
{
- if (!GlobalTimer.file_load_cb_registered) {
- BLI_callback_add(&load_pre_callback, BLI_CB_EVT_LOAD_PRE);
- GlobalTimer.file_load_cb_registered = true;
- }
+ remove_non_persistent_functions();
}
diff --git a/source/blender/blenlib/intern/delaunay_2d.c b/source/blender/blenlib/intern/delaunay_2d.c
index 23f560c5463..d5dcd40346f 100644
--- a/source/blender/blenlib/intern/delaunay_2d.c
+++ b/source/blender/blenlib/intern/delaunay_2d.c
@@ -115,101 +115,9 @@ static void validate_face_centroid(SymEdge *se);
static void validate_cdt(CDT_state *cdt, bool check_all_tris);
#endif
-/* TODO: move these to BLI_vector... and BLI_math... */
-static double max_dd(const double a, const double b)
-{
- return (a > b) ? a : b;
-}
-
-static double len_v2v2_db(const double a[2], const double b[2])
-{
- return sqrt((b[0] - a[0]) * (b[0] - a[0]) + (b[1] - a[1]) * (b[1] - a[1]));
-}
-
-static double len_squared_v2v2_db(const double a[2], const double b[2])
-{
- return (b[0] - a[0]) * (b[0] - a[0]) + (b[1] - a[1]) * (b[1] - a[1]);
-}
-
-static void add_v2_v2_db(double a[2], const double b[2])
-{
- a[0] += b[0];
- a[1] += b[1];
-}
-
-static void sub_v2_v2v2_db(double *a, const double *b, const double *c)
-{
- a[0] = b[0] - c[0];
- a[1] = b[1] - c[1];
-}
-
-static double dot_v2v2_db(const double *a, const double *b)
-{
- return a[0] * b[0] + a[1] * b[1];
-}
-
-static double closest_to_line_v2_db(double r_close[2],
- const double p[2],
- const double l1[2],
- const double l2[2])
-{
- double h[2], u[2], lambda, denom;
- sub_v2_v2v2_db(u, l2, l1);
- sub_v2_v2v2_db(h, p, l1);
- denom = dot_v2v2_db(u, u);
- if (denom < DBL_EPSILON) {
- r_close[0] = l1[0];
- r_close[1] = l1[1];
- return 0.0;
- }
- lambda = dot_v2v2_db(u, h) / dot_v2v2_db(u, u);
- r_close[0] = l1[0] + u[0] * lambda;
- r_close[1] = l1[1] + u[1] * lambda;
- return lambda;
-}
-
-/**
- * If intersection == ISECT_LINE_LINE_CROSS or ISECT_LINE_LINE_NONE:
- * <pre>
- * pt = v1 + lamba * (v2 - v1) = v3 + mu * (v4 - v3)
- * </pre>
- */
-static int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
- const double v2[2],
- const double v3[2],
- const double v4[2],
- double *r_lambda,
- double *r_mu)
-{
- double div, lambda, mu;
-
- div = (v2[0] - v1[0]) * (v4[1] - v3[1]) - (v2[1] - v1[1]) * (v4[0] - v3[0]);
- if (fabs(div) < DBL_EPSILON) {
- return ISECT_LINE_LINE_COLINEAR;
- }
-
- lambda = ((v1[1] - v3[1]) * (v4[0] - v3[0]) - (v1[0] - v3[0]) * (v4[1] - v3[1])) / div;
-
- mu = ((v1[1] - v3[1]) * (v2[0] - v1[0]) - (v1[0] - v3[0]) * (v2[1] - v1[1])) / div;
-
- if (r_lambda) {
- *r_lambda = lambda;
- }
- if (r_mu) {
- *r_mu = mu;
- }
-
- if (lambda >= 0.0 && lambda <= 1.0 && mu >= 0.0 && mu <= 1.0) {
- if (lambda == 0.0 || lambda == 1.0 || mu == 0.0 || mu == 1.0) {
- return ISECT_LINE_LINE_EXACT;
- }
- return ISECT_LINE_LINE_CROSS;
- }
- return ISECT_LINE_LINE_NONE;
-}
-
-/** return 1 if a,b,c forms CCW angle, -1 if a CW angle, 0 if straight */
-static int CCW_test(const double a[2], const double b[2], const double c[2])
+/** return 1 if a,b,c forms CCW angle, -1 if a CW angle, 0 if straight.
+ * For straight test, allow b to be withing eps of line. */
+static int CCW_test(const double a[2], const double b[2], const double c[2], const double eps)
{
double det;
double ab;
@@ -217,14 +125,14 @@ static int CCW_test(const double a[2], const double b[2], const double c[2])
/* This is twice the signed area of triangle abc. */
det = (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]);
ab = len_v2v2_db(a, b);
- if (ab < DBL_EPSILON) {
+ if (ab <= eps) {
return 0;
}
det /= ab;
- if (det > DBL_EPSILON) {
+ if (det > eps) {
return 1;
}
- else if (det < -DBL_EPSILON) {
+ else if (det < -eps) {
return -1;
}
return 0;
@@ -755,7 +663,7 @@ static bool locate_point_final(const double p[2],
}
else {
dist_inside[i] = len_close_p;
- dist_inside[i] = CCW_test(a, b, p) >= 0 ? len_close_p : -len_close_p;
+ dist_inside[i] = CCW_test(a, b, p, epsilon) >= 0 ? len_close_p : -len_close_p;
}
i++;
se = se->next;
@@ -906,7 +814,8 @@ static LocateResult locate_point(CDT_state *cdt, const double p[2])
a = cur_se->vert->co;
b = cur_se->next->vert->co;
c = cur_se->next->next->vert->co;
- if (CCW_test(a, b, p) >= 0 && CCW_test(b, c, p) >= 0 && CCW_test(c, a, p) >= 0) {
+ if (CCW_test(a, b, p, epsilon) >= 0 && CCW_test(b, c, p, epsilon) >= 0 &&
+ CCW_test(c, a, p, epsilon) >= 0) {
#ifdef DEBUG_CDT
if (dbglevel > 1) {
fprintf(stderr, "p in current triangle\n");
@@ -930,7 +839,7 @@ static LocateResult locate_point(CDT_state *cdt, const double p[2])
}
#endif
next_se_sym = sym(next_se);
- if (CCW_test(a, b, p) <= 0 && next_se->face != cdt->outer_face) {
+ if (CCW_test(a, b, p, epsilon) <= 0 && next_se->face != cdt->outer_face) {
#ifdef DEBUG_CDT
if (dbglevel > 1) {
fprintf(stderr, "CCW_test(a, b, p) <= 0\n");
@@ -1524,6 +1433,7 @@ static void add_edge_constraint(
int ccw1, ccw2, isect;
int i, search_count;
double lambda;
+ const double epsilon = cdt->epsilon;
bool done, state_through_vert;
LinkNodePair edge_list = {NULL, NULL};
typedef struct CrossData {
@@ -1634,8 +1544,8 @@ static void add_edge_constraint(
do {
va = t->next->vert;
vb = t->next->next->vert;
- ccw1 = CCW_test(t->vert->co, va->co, v2->co);
- ccw2 = CCW_test(t->vert->co, vb->co, v2->co);
+ ccw1 = CCW_test(t->vert->co, va->co, v2->co, epsilon);
+ ccw2 = CCW_test(t->vert->co, vb->co, v2->co, epsilon);
#ifdef DEBUG_CDT
if (dbg_level > 1) {
fprintf(stderr, "non-final through vert case\n");
@@ -1684,7 +1594,7 @@ static void add_edge_constraint(
}
#endif
} while (t != tstart);
- BLI_assert(tout != NULL); /* TODO: something sensivle for "this can't happen" */
+ BLI_assert(tout != NULL); /* TODO: something sensible for "this can't happen" */
crossings[BLI_array_len(crossings) - 1].out = tout;
}
}
@@ -1727,7 +1637,7 @@ static void add_edge_constraint(
/* 'tout' is 'symedge' from 'vb' to third vertex, 'vc'. */
BLI_assert(tout->vert == va);
vc = tout->next->vert;
- ccw1 = CCW_test(v1->co, v2->co, vc->co);
+ ccw1 = CCW_test(v1->co, v2->co, vc->co, epsilon);
#ifdef DEBUG_CDT
if (dbg_level > 1) {
fprintf(stderr, "now searching with third vertex ");
@@ -2004,7 +1914,7 @@ static void remove_non_constraint_edges(CDT_state *cdt, const bool valid_bmesh)
dissolve = !is_deleted_edge(e) && !is_constrained_edge(e);
if (dissolve) {
se = &e->symedges[0];
- if (valid_bmesh) {
+ if (valid_bmesh && !edge_touches_frame(e)) {
fleft = se->face;
fright = sym(se)->face;
if (fleft != cdt->outer_face && fright != cdt->outer_face &&
@@ -2320,7 +2230,7 @@ CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_ty
CDTEdge *face_edge;
SymEdge *face_symedge;
#ifdef DEBUG_CDT
- int dbg_level = 1;
+ int dbg_level = 0;
#endif
if ((nv > 0 && input->vert_coords == NULL) || (ne > 0 && input->edges == NULL) ||
@@ -2378,6 +2288,13 @@ CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_ty
}
add_edge_constraint(cdt, verts[v1], verts[v2], i, NULL);
}
+#ifdef DEBUG_CDT
+ if (dbg_level > 2) {
+ cdt_draw(cdt, "after edge constraints");
+ dump_cdt(cdt, "after edge constraints");
+ validate_cdt(cdt, true);
+ }
+#endif
cdt->face_edge_offset = ne;
for (f = 0; f < nf; f++) {
int flen = input->faces_len_table[f];
@@ -2410,6 +2327,11 @@ CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_ty
F2(cdt_e->symedges[1].vert->co));
}
}
+ if (dbg_level > 2) {
+ cdt_draw(cdt, "after a face edge");
+ dump_cdt(cdt, "after a face edge");
+ validate_cdt(cdt, true);
+ }
#endif
if (i == 0) {
face_edge = (CDTEdge *)edge_list->link;
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index 0e3987eefc9..99149f5ea42 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -35,7 +35,6 @@
#ifdef WIN32
# include <io.h>
# include "BLI_winstuff.h"
-# include "BLI_callbacks.h"
# include "BLI_fileops_types.h"
# include "utf_winfunc.h"
# include "utfconv.h"
@@ -343,7 +342,7 @@ static bool delete_recursive(const char *dir)
err = true;
}
}
- ++fl;
+ fl++;
}
if (!err && delete_unique(dir, true)) {
@@ -771,7 +770,7 @@ int BLI_delete(const char *file, bool dir, bool recursive)
}
/**
- * Do the two paths denote the same filesystem object?
+ * Do the two paths denote the same file-system object?
*/
static bool check_the_same(const char *path_a, const char *path_b)
{
diff --git a/source/blender/blenlib/intern/gsqueue.c b/source/blender/blenlib/intern/gsqueue.c
index 6d0fdfacb10..5e1fbf6eade 100644
--- a/source/blender/blenlib/intern/gsqueue.c
+++ b/source/blender/blenlib/intern/gsqueue.c
@@ -12,9 +12,6 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
*/
/** \file
@@ -22,9 +19,6 @@
*
* \brief A generic structure queue
* (a queue for fixed length generally small) structures.
- *
- * \note Only use this if you need (first-in-first-out),
- * otherwise #BLI_Stack is more efficient (first-in-last-out).
*/
#include <string.h>
@@ -35,148 +29,168 @@
#include "BLI_gsqueue.h"
#include "BLI_strict_flags.h"
-typedef struct _GSQueueElem GSQueueElem;
-struct _GSQueueElem {
- GSQueueElem *next;
+/* target chunk size: 64kb */
+#define CHUNK_SIZE_DEFAULT (1 << 16)
+/* ensure we get at least this many elems per chunk */
+#define CHUNK_ELEM_MIN 32
+
+struct QueueChunk {
+ struct QueueChunk *next;
char data[0];
};
struct _GSQueue {
- GSQueueElem *head;
- GSQueueElem *tail;
- size_t elem_size;
+ struct QueueChunk *chunk_first; /* first active chunk to pop from */
+ struct QueueChunk *chunk_last; /* flast active chunk to push onto */
+ struct QueueChunk *chunk_free; /* free chunks to reuse */
+ size_t chunk_first_index; /* index into 'chunk_first' */
+ size_t chunk_last_index; /* index into 'chunk_last' */
+ size_t chunk_elem_max; /* number of elements per chunk */
+ size_t elem_size; /* memory size of elements */
+ size_t totelem; /* total number of elements */
};
-/**
- * Create a new GSQueue.
- *
- * \param elem_size: The size of the structures in the queue.
- * \retval The new queue
- */
-GSQueue *BLI_gsqueue_new(size_t elem_size)
+static void *queue_get_first_elem(GSQueue *queue)
{
- GSQueue *gq = MEM_mallocN(sizeof(*gq), "gqueue_new");
- gq->head = gq->tail = NULL;
- gq->elem_size = elem_size;
-
- return gq;
+ return ((char *)(queue)->chunk_first->data) + ((queue)->elem_size * (queue)->chunk_first_index);
}
-/**
- * Query if the queue is empty
- */
-bool BLI_gsqueue_is_empty(GSQueue *gq)
+static void *queue_get_last_elem(GSQueue *queue)
{
- return (gq->head == NULL);
+ return ((char *)(queue)->chunk_last->data) + ((queue)->elem_size * (queue)->chunk_last_index);
}
/**
- * Query number elements in the queue
+ * \return number of elements per chunk, optimized for slop-space.
*/
-int BLI_gsqueue_len(GSQueue *gq)
+static size_t queue_chunk_elem_max_calc(const size_t elem_size, size_t chunk_size)
{
- GSQueueElem *elem;
- int size = 0;
+ /* get at least this number of elems per chunk */
+ const size_t elem_size_min = elem_size * CHUNK_ELEM_MIN;
- for (elem = gq->head; elem; elem = elem->next) {
- size++;
+ BLI_assert((elem_size != 0) && (chunk_size != 0));
+
+ while (UNLIKELY(chunk_size <= elem_size_min)) {
+ chunk_size <<= 1;
}
- return size;
+ /* account for slop-space */
+ chunk_size -= (sizeof(struct QueueChunk) + MEM_SIZE_OVERHEAD);
+
+ return chunk_size / elem_size;
}
-/**
- * Access the item at the head of the queue
- * without removing it.
- *
- * \param r_item: A pointer to an appropriately
- * sized structure (the size passed to #BLI_gsqueue_new)
- */
-void BLI_gsqueue_peek(GSQueue *gq, void *r_item)
+GSQueue *BLI_gsqueue_new(const size_t elem_size)
{
- memcpy(r_item, &gq->head->data, gq->elem_size);
+ GSQueue *queue = MEM_callocN(sizeof(*queue), "BLI_gsqueue_new");
+
+ queue->chunk_elem_max = queue_chunk_elem_max_calc(elem_size, CHUNK_SIZE_DEFAULT);
+ queue->elem_size = elem_size;
+ /* force init */
+ queue->chunk_last_index = queue->chunk_elem_max - 1;
+
+ return queue;
}
-/**
- * Access the item at the head of the queue
- * and remove it.
- *
- * \param r_item: A pointer to an appropriately
- * sized structure (the size passed to #BLI_gsqueue_new).
- * Can be NULL if desired.
- */
-void BLI_gsqueue_pop(GSQueue *gq, void *r_item)
+static void queue_free_chunk(struct QueueChunk *data)
{
- GSQueueElem *elem = gq->head;
- if (elem == gq->tail) {
- gq->head = gq->tail = NULL;
- }
- else {
- gq->head = gq->head->next;
+ while (data) {
+ struct QueueChunk *data_next = data->next;
+ MEM_freeN(data);
+ data = data_next;
}
+}
- if (r_item) {
- memcpy(r_item, elem->data, gq->elem_size);
- }
- MEM_freeN(elem);
+/**
+ * Free the queue's data and the queue itself
+ */
+void BLI_gsqueue_free(GSQueue *queue)
+{
+ queue_free_chunk(queue->chunk_first);
+ queue_free_chunk(queue->chunk_free);
+ MEM_freeN(queue);
}
/**
- * Push an element onto the tail of the queue.
+ * Copies the source value onto the end of the queue
*
- * \param item: A pointer to an appropriately
- * sized structure (the size passed to BLI_gsqueue_new).
+ * \note This copies #GSQueue.elem_size bytes from \a src,
+ * (the pointer itself is not stored).
+ *
+ * \param src: source data to be copied to the queue.
*/
-void BLI_gsqueue_push(GSQueue *gq, const void *item)
+void BLI_gsqueue_push(GSQueue *queue, const void *src)
{
- GSQueueElem *elem;
+ queue->chunk_last_index++;
+ queue->totelem++;
+
+ if (UNLIKELY(queue->chunk_last_index == queue->chunk_elem_max)) {
+ struct QueueChunk *chunk;
+ if (queue->chunk_free) {
+ chunk = queue->chunk_free;
+ queue->chunk_free = chunk->next;
+ }
+ else {
+ chunk = MEM_mallocN(sizeof(*chunk) + (queue->elem_size * queue->chunk_elem_max), __func__);
+ }
- /* compare: prevent events added double in row */
- if (!BLI_gsqueue_is_empty(gq)) {
- if (0 == memcmp(item, gq->head->data, gq->elem_size)) {
- return;
+ chunk->next = NULL;
+
+ if (queue->chunk_last == NULL) {
+ queue->chunk_first = chunk;
+ }
+ else {
+ queue->chunk_last->next = chunk;
}
- }
- elem = MEM_mallocN(sizeof(*elem) + gq->elem_size, "gqueue_push");
- memcpy(elem->data, item, gq->elem_size);
- elem->next = NULL;
- if (BLI_gsqueue_is_empty(gq)) {
- gq->tail = gq->head = elem;
- }
- else {
- gq->tail = gq->tail->next = elem;
+ queue->chunk_last = chunk;
+ queue->chunk_last_index = 0;
}
+
+ BLI_assert(queue->chunk_last_index < queue->chunk_elem_max);
+
+ /* Return last of queue */
+ memcpy(queue_get_last_elem(queue), src, queue->elem_size);
}
/**
- * Push an element back onto the head of the queue (so
- * it would be returned from the next call to BLI_gsqueue_pop).
+ * Retrieves and removes the first element from the queue.
+ * The value is copies to \a dst, which must be at least \a elem_size bytes.
*
- * \param item: A pointer to an appropriately
- * sized structure (the size passed to BLI_gsqueue_new).
+ * Does not reduce amount of allocated memory.
*/
-void BLI_gsqueue_push_back(GSQueue *gq, const void *item)
+void BLI_gsqueue_pop(GSQueue *queue, void *dst)
{
- GSQueueElem *elem = MEM_mallocN(sizeof(*elem) + gq->elem_size, "gqueue_push");
- memcpy(elem->data, item, gq->elem_size);
- elem->next = gq->head;
+ BLI_assert(BLI_gsqueue_is_empty(queue) == false);
- if (BLI_gsqueue_is_empty(gq)) {
- gq->head = gq->tail = elem;
- }
- else {
- gq->head = elem;
+ memcpy(dst, queue_get_first_elem(queue), queue->elem_size);
+ queue->chunk_first_index++;
+ queue->totelem--;
+
+ if (UNLIKELY(queue->chunk_first_index == queue->chunk_elem_max || queue->totelem == 0)) {
+ struct QueueChunk *chunk_free = queue->chunk_first;
+
+ queue->chunk_first = queue->chunk_first->next;
+ queue->chunk_first_index = 0;
+ if (queue->chunk_first == NULL) {
+ queue->chunk_last = NULL;
+ queue->chunk_last_index = queue->chunk_elem_max - 1;
+ }
+
+ chunk_free->next = queue->chunk_free;
+ queue->chunk_free = chunk_free;
}
}
+size_t BLI_gsqueue_len(const GSQueue *queue)
+{
+ return queue->totelem;
+}
+
/**
- * Free the queue
+ * Returns true if the queue is empty, false otherwise
*/
-void BLI_gsqueue_free(GSQueue *gq)
+bool BLI_gsqueue_is_empty(const GSQueue *queue)
{
- while (gq->head) {
- BLI_gsqueue_pop(gq, NULL);
- }
- MEM_freeN(gq);
+ return (queue->chunk_first == NULL);
}
diff --git a/source/blender/blenlib/intern/hash_md5.c b/source/blender/blenlib/intern/hash_md5.c
index 44a9348c5d3..f9e9b3bfbf9 100644
--- a/source/blender/blenlib/intern/hash_md5.c
+++ b/source/blender/blenlib/intern/hash_md5.c
@@ -151,7 +151,7 @@ static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ct
*/
#define OP(a, b, c, d, s, T) \
a += FF(b, c, d) + (*cwp++ = SWAP(*words)) + T; \
- ++words; \
+ words++; \
CYCLIC(a, s); \
a += b; \
(void)0
@@ -408,7 +408,7 @@ char *BLI_hash_md5_to_hexdigest(void *resblock, char r_hex_digest[33])
char *q;
short len;
- for (q = r_hex_digest, p = (const unsigned char *)resblock, len = 0; len < 16; ++p, ++len) {
+ for (q = r_hex_digest, p = (const unsigned char *)resblock, len = 0; len < 16; p++, len++) {
const unsigned char c = *p;
*q++ = hex_map[c >> 4];
*q++ = hex_map[c & 15];
diff --git a/source/blender/blenlib/intern/list_sort_impl.h b/source/blender/blenlib/intern/list_sort_impl.h
index fac1ca8e983..458ace3a712 100644
--- a/source/blender/blenlib/intern/list_sort_impl.h
+++ b/source/blender/blenlib/intern/list_sort_impl.h
@@ -240,7 +240,7 @@ BLI_INLINE void insert_list(struct SortInfo *si, list_node *list, unsigned int r
rank = MAX_RANKS;
}
list = merge_lists(sweep_up(si, NULL, si->n_ranks), list, THUNK_APPEND1(si->func, si->thunk));
- for (i = si->n_ranks; i < rank; ++i) {
+ for (i = si->n_ranks; i < rank; i++) {
si->ranks[i] = NULL;
}
}
@@ -248,7 +248,7 @@ BLI_INLINE void insert_list(struct SortInfo *si, list_node *list, unsigned int r
if (rank) {
list = merge_lists(sweep_up(si, NULL, rank), list, THUNK_APPEND1(si->func, si->thunk));
}
- for (i = rank; i < si->n_ranks && si->ranks[i]; ++i) {
+ for (i = rank; i < si->n_ranks && si->ranks[i]; i++) {
list = merge_lists(si->ranks[i], list, THUNK_APPEND1(si->func, si->thunk));
si->ranks[i] = NULL;
}
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index 31d372945c6..fe5f9f7673f 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -312,7 +312,7 @@ static void listbase_double_from_single(Link *iter, ListBase *listbase)
#include "list_sort_impl.h"
#undef SORT_IMPL_FUNC
-/* reentrant call */
+/* re-entrant call */
#define SORT_IMPL_USE_THUNK
#define SORT_IMPL_FUNC listbase_sort_fn_r
#include "list_sort_impl.h"
@@ -504,6 +504,27 @@ bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step)
}
/**
+ * Move the link at the index \a from to the position at index \a to.
+ *
+ * \return If the move was successful.
+ */
+bool BLI_listbase_move_index(ListBase *listbase, int from, int to)
+{
+ if (from == to) {
+ return false;
+ }
+
+ /* Find the link to move. */
+ void *link = BLI_findlink(listbase, from);
+
+ if (!link) {
+ return false;
+ }
+
+ return BLI_listbase_link_move(listbase, link, to - from);
+}
+
+/**
* Removes and disposes of the entire contents of listbase using direct free(3).
*/
void BLI_freelist(ListBase *listbase)
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index 320f8a0f1ab..0309876d8fb 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -230,6 +230,21 @@ MINLINE unsigned power_of_2_min_u(unsigned x)
return x - (x >> 1);
}
+MINLINE unsigned int log2_floor_u(unsigned int x)
+{
+ return x <= 1 ? 0 : 1 + log2_floor_u(x >> 1);
+}
+
+MINLINE unsigned int log2_ceil_u(unsigned int x)
+{
+ if (is_power_of_2_i((int)x)) {
+ return log2_floor_u(x);
+ }
+ else {
+ return log2_floor_u(x) + 1;
+ }
+}
+
/* rounding and clamping */
#define _round_clamp_fl_impl(arg, ty, min, max) \
@@ -353,6 +368,15 @@ MINLINE float max_ff(float a, float b)
return (a > b) ? a : b;
}
+MINLINE double min_dd(double a, double b)
+{
+ return (a < b) ? a : b;
+}
+MINLINE double max_dd(double a, double b)
+{
+ return (a > b) ? a : b;
+}
+
MINLINE int min_ii(int a, int b)
{
return (a < b) ? a : b;
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index c4bdc73e0e3..6d8193e7675 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -1356,6 +1356,52 @@ bool isect_seg_seg_v2_simple(const float v1[2],
}
/**
+ * If intersection == ISECT_LINE_LINE_CROSS or ISECT_LINE_LINE_NONE:
+ * <pre>
+ * pt = v1 + lambda * (v2 - v1) = v3 + mu * (v4 - v3)
+ * </pre>
+ * \returns intersection type:
+ * - ISECT_LINE_LINE_COLINEAR: collinear.
+ * - ISECT_LINE_LINE_EXACT: intersection at an endpoint of either.
+ * - ISECT_LINE_LINE_CROSS: interaction, not at an endpoint.
+ * - ISECT_LINE_LINE_NONE: no intersection.
+ * Also returns lambda and mu in r_lambda and r_mu.
+ */
+int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
+ const double v2[2],
+ const double v3[2],
+ const double v4[2],
+ double *r_lambda,
+ double *r_mu)
+{
+ double div, lambda, mu;
+
+ div = (v2[0] - v1[0]) * (v4[1] - v3[1]) - (v2[1] - v1[1]) * (v4[0] - v3[0]);
+ if (fabs(div) < DBL_EPSILON) {
+ return ISECT_LINE_LINE_COLINEAR;
+ }
+
+ lambda = ((v1[1] - v3[1]) * (v4[0] - v3[0]) - (v1[0] - v3[0]) * (v4[1] - v3[1])) / div;
+
+ mu = ((v1[1] - v3[1]) * (v2[0] - v1[0]) - (v1[0] - v3[0]) * (v2[1] - v1[1])) / div;
+
+ if (r_lambda) {
+ *r_lambda = lambda;
+ }
+ if (r_mu) {
+ *r_mu = mu;
+ }
+
+ if (lambda >= 0.0 && lambda <= 1.0 && mu >= 0.0 && mu <= 1.0) {
+ if (lambda == 0.0 || lambda == 1.0 || mu == 0.0 || mu == 1.0) {
+ return ISECT_LINE_LINE_EXACT;
+ }
+ return ISECT_LINE_LINE_CROSS;
+ }
+ return ISECT_LINE_LINE_NONE;
+}
+
+/**
* \param l1, l2: Coordinates (point of line).
* \param sp, r: Coordinate and radius (sphere).
* \return r_p1, r_p2: Intersection coordinates.
@@ -3011,19 +3057,21 @@ bool isect_line_line_strict_v3(const float v1[3],
*
* \note Neither directions need to be normalized.
*/
-bool isect_ray_ray_v3(const float ray_origin_a[3],
- const float ray_direction_a[3],
- const float ray_origin_b[3],
- const float ray_direction_b[3],
- float *r_lambda_a,
- float *r_lambda_b)
+bool isect_ray_ray_epsilon_v3(const float ray_origin_a[3],
+ const float ray_direction_a[3],
+ const float ray_origin_b[3],
+ const float ray_direction_b[3],
+ const float epsilon,
+ float *r_lambda_a,
+ float *r_lambda_b)
{
BLI_assert(r_lambda_a || r_lambda_b);
float n[3];
cross_v3_v3v3(n, ray_direction_b, ray_direction_a);
const float nlen = len_squared_v3(n);
- if (UNLIKELY(nlen == 0.0f)) {
+ /* `nlen` is the the square of the area formed by the two vectors. */
+ if (UNLIKELY(nlen < epsilon)) {
/* The lines are parallel. */
return false;
}
@@ -3045,6 +3093,22 @@ bool isect_ray_ray_v3(const float ray_origin_a[3],
return true;
}
+bool isect_ray_ray_v3(const float ray_origin_a[3],
+ const float ray_direction_a[3],
+ const float ray_origin_b[3],
+ const float ray_direction_b[3],
+ float *r_lambda_a,
+ float *r_lambda_b)
+{
+ return isect_ray_ray_epsilon_v3(ray_origin_a,
+ ray_direction_a,
+ ray_origin_b,
+ ray_direction_b,
+ FLT_MIN,
+ r_lambda_a,
+ r_lambda_b);
+}
+
bool isect_aabb_aabb_v3(const float min1[3],
const float max1[3],
const float min2[3],
@@ -3187,6 +3251,26 @@ float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2],
return lambda;
}
+double closest_to_line_v2_db(double r_close[2],
+ const double p[2],
+ const double l1[2],
+ const double l2[2])
+{
+ double h[2], u[2], lambda, denom;
+ sub_v2_v2v2_db(u, l2, l1);
+ sub_v2_v2v2_db(h, p, l1);
+ denom = dot_v2v2_db(u, u);
+ if (denom < DBL_EPSILON) {
+ r_close[0] = l1[0];
+ r_close[1] = l1[1];
+ return 0.0;
+ }
+ lambda = dot_v2v2_db(u, h) / dot_v2v2_db(u, u);
+ r_close[0] = l1[0] + u[0] * lambda;
+ r_close[1] = l1[1] + u[1] * lambda;
+ return lambda;
+}
+
float ray_point_factor_v3_ex(const float p[3],
const float ray_origin[3],
const float ray_direction[3],
@@ -4707,29 +4791,24 @@ void projmat_from_subregion(const float projmat[4][4],
float rect_width = (float)(x_max - x_min);
float rect_height = (float)(y_max - y_min);
+ float x_sca = (float)win_size[0] / rect_width;
+ float y_sca = (float)win_size[1] / rect_height;
+
float x_fac = (float)((x_min + x_max) - win_size[0]) / rect_width;
float y_fac = (float)((y_min + y_max) - win_size[1]) / rect_height;
copy_m4_m4(r_projmat, projmat);
- r_projmat[0][0] *= (float)win_size[0] / rect_width;
- r_projmat[1][1] *= (float)win_size[1] / rect_height;
+ r_projmat[0][0] *= x_sca;
+ r_projmat[1][1] *= y_sca;
-#if 0 /* TODO: check if this is more efficient. */
- r_projmat[2][0] -= x_fac * r_projmat[2][3];
- r_projmat[2][1] -= y_fac * r_projmat[2][3];
-
- r_projmat[3][0] -= x_fac * r_projmat[3][3];
- r_projmat[3][1] -= y_fac * r_projmat[3][3];
-#else
if (projmat[3][3] == 0.0f) {
- r_projmat[2][0] += x_fac;
- r_projmat[2][1] += y_fac;
+ r_projmat[2][0] = r_projmat[2][0] * x_sca + x_fac;
+ r_projmat[2][1] = r_projmat[2][1] * y_sca + y_fac;
}
else {
- r_projmat[3][0] -= x_fac;
- r_projmat[3][1] -= y_fac;
+ r_projmat[3][0] = r_projmat[3][0] * x_sca - x_fac;
+ r_projmat[3][1] = r_projmat[3][1] * y_sca - y_fac;
}
-#endif
}
static void i_multmatrix(float icand[4][4], float Vm[4][4])
diff --git a/source/blender/blenlib/intern/math_interp.c b/source/blender/blenlib/intern/math_interp.c
index 14fde18aa52..6277b1cd9dc 100644
--- a/source/blender/blenlib/intern/math_interp.c
+++ b/source/blender/blenlib/intern/math_interp.c
@@ -687,11 +687,11 @@ void BLI_ewa_filter(const int width,
d = 0.0f;
zero_v4(result);
- for (v = v1; v <= v2; ++v) {
+ for (v = v1; v <= v2; v++) {
const float V = (float)v - V0;
float DQ = ac1 + B * V;
float Q = (C * V + BU) * V + ac2;
- for (u = u1; u <= u2; ++u) {
+ for (u = u1; u <= u2; u++) {
if (Q < (float)(EWA_MAXIDX + 1)) {
float tc[4];
const float wt = EWA_WTS[(Q < 0.0f) ? 0 : (unsigned int)Q];
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index 2568d42566c..33e272ed7eb 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -1146,8 +1146,8 @@ bool invert_m4(float m[4][4])
* \return true on success (i.e. can always find a pivot) and false on failure.
* Mark Segal - 1992.
*
- * \note this is less performant than #EIG_invert_m4_m4 (Eigen), but e.g.
- * for non-invertible scale matrices, findinging a partial solution can
+ * \note this has worse performance than #EIG_invert_m4_m4 (Eigen), but e.g.
+ * for non-invertible scale matrices, finding a partial solution can
* be useful to have a valid local transform center, see T57767.
*/
bool invert_m4_m4_fallback(float inverse[4][4], const float mat[4][4])
@@ -1516,6 +1516,111 @@ void orthogonalize_m4(float mat[4][4], int axis)
mul_v3_fl(mat[2], size[2]);
}
+/** Make an orthonormal basis around v1 in a way that is stable and symmetric. */
+static void orthogonalize_stable(float v1[3], float v2[3], float v3[3], bool normalize)
+{
+ /* Make secondary axis vectors orthogonal to the primary via
+ * plane projection, which preserves the determinant. */
+ float len_sq_v1 = len_squared_v3(v1);
+
+ if (len_sq_v1 > 0.0f) {
+ madd_v3_v3fl(v2, v1, -dot_v3v3(v2, v1) / len_sq_v1);
+ madd_v3_v3fl(v3, v1, -dot_v3v3(v3, v1) / len_sq_v1);
+
+ if (normalize) {
+ mul_v3_fl(v1, 1.0f / sqrtf(len_sq_v1));
+ }
+ }
+
+ /* Make secondary axis vectors orthogonal relative to each other. */
+ float norm_v2[3], norm_v3[3], tmp[3];
+ float length_v2 = normalize_v3_v3(norm_v2, v2);
+ float length_v3 = normalize_v3_v3(norm_v3, v3);
+ float cos_angle = dot_v3v3(norm_v2, norm_v3);
+ float abs_cos_angle = fabsf(cos_angle);
+
+ /* Apply correction if the shear angle is significant, and not degenerate. */
+ if (abs_cos_angle > 1e-4f && abs_cos_angle < 1.0f - FLT_EPSILON) {
+ /* Adjust v2 by half of the necessary angle correction.
+ * Thus the angle change is the same for both axis directions. */
+ float angle = acosf(cos_angle);
+ float target_angle = angle + ((float)M_PI_2 - angle) / 2;
+
+ madd_v3_v3fl(norm_v2, norm_v3, -cos_angle);
+ mul_v3_fl(norm_v2, sinf(target_angle) / len_v3(norm_v2));
+ madd_v3_v3fl(norm_v2, norm_v3, cosf(target_angle));
+
+ /* Make v3 orthogonal. */
+ cross_v3_v3v3(tmp, norm_v2, norm_v3);
+ cross_v3_v3v3(norm_v3, tmp, norm_v2);
+ normalize_v3(norm_v3);
+
+ /* Re-apply scale, preserving area and proportion. */
+ if (!normalize) {
+ float scale_fac = sqrtf(sinf(angle));
+ mul_v3_v3fl(v2, norm_v2, length_v2 * scale_fac);
+ mul_v3_v3fl(v3, norm_v3, length_v3 * scale_fac);
+ }
+ }
+
+ if (normalize) {
+ copy_v3_v3(v2, norm_v2);
+ copy_v3_v3(v3, norm_v3);
+ }
+}
+
+/**
+ * Make an orthonormal matrix around the selected axis of the given matrix,
+ * in a way that is symmetric and stable to variations in the input, and
+ * preserving the value of the determinant, i.e. the overall volume change.
+ *
+ * \param axis: Axis to build the orthonormal basis around.
+ * \param normalize: Normalize the matrix instead of preserving volume.
+ */
+void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize)
+{
+ switch (axis) {
+ case 0:
+ orthogonalize_stable(R[0], R[1], R[2], normalize);
+ break;
+ case 1:
+ orthogonalize_stable(R[1], R[0], R[2], normalize);
+ break;
+ case 2:
+ orthogonalize_stable(R[2], R[0], R[1], normalize);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+}
+
+/**
+ * Make an orthonormal matrix around the selected axis of the given matrix,
+ * in a way that is symmetric and stable to variations in the input, and
+ * preserving the value of the determinant, i.e. the overall volume change.
+ *
+ * \param axis: Axis to build the orthonormal basis around.
+ * \param normalize: Normalize the matrix instead of preserving volume.
+ */
+void orthogonalize_m4_stable(float R[4][4], int axis, bool normalize)
+{
+ switch (axis) {
+ case 0:
+ orthogonalize_stable(R[0], R[1], R[2], normalize);
+ break;
+ case 1:
+ orthogonalize_stable(R[1], R[0], R[2], normalize);
+ break;
+ case 2:
+ orthogonalize_stable(R[2], R[0], R[1], normalize);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+}
+
bool is_orthogonal_m3(const float m[3][3])
{
int i, j;
@@ -1851,6 +1956,19 @@ void mat4_to_size(float size[3], const float mat[4][4])
size[2] = len_v3(mat[2]);
}
+/** Extract scale factors from the matrix, with correction to ensure
+ * exact volume in case of a sheared matrix. */
+void mat4_to_size_fix_shear(float size[3], const float mat[4][4])
+{
+ mat4_to_size(size, mat);
+
+ float volume = size[0] * size[1] * size[2];
+
+ if (volume != 0.0f) {
+ mul_v3_fl(size, cbrtf(fabsf(mat4_to_volume_scale(mat) / volume)));
+ }
+}
+
/**
* This computes the overall volume scale factor of a transformation matrix.
* For an orthogonal matrix, it is the product of all three scale values.
@@ -2045,6 +2163,14 @@ void rotate_m4(float mat[4][4], const char axis, const float angle)
}
}
+/** Scale a matrix in-place. */
+void rescale_m4(float mat[4][4], const float scale[3])
+{
+ mul_v3_fl(mat[0], scale[0]);
+ mul_v3_fl(mat[1], scale[1]);
+ mul_v3_fl(mat[2], scale[2]);
+}
+
/**
* Scale or rotate around a pivot point,
* a convenience function to avoid having to do inline.
@@ -2233,6 +2359,20 @@ bool equals_m4m4(const float mat1[4][4], const float mat2[4][4])
/**
* Make a 4x4 matrix out of 3 transform components.
* Matrices are made in the order: `scale * rot * loc`
+ */
+void loc_rot_size_to_mat4(float mat[4][4],
+ const float loc[3],
+ const float rot[3][3],
+ const float size[3])
+{
+ copy_m4_m3(mat, rot);
+ rescale_m4(mat, size);
+ copy_v3_v3(mat[3], loc);
+}
+
+/**
+ * Make a 4x4 matrix out of 3 transform components.
+ * Matrices are made in the order: `scale * rot * loc`
*
* TODO: need to have a version that allows for rotation order...
*/
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index e4b44240272..37c0c05b061 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -535,6 +535,50 @@ void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q
mul_qt_qtqt(q, tquat, q2);
}
+/**
+ * Decompose a quaternion into a swing rotation (quaternion with the selected
+ * axis component locked at zero), followed by a twist rotation around the axis.
+ *
+ * \param q: input quaternion.
+ * \param axis: twist axis in [0,1,2]
+ * \param r_swing[out]: if not NULL, receives the swing quaternion.
+ * \param r_twist[out]: if not NULL, receives the twist quaternion.
+ * \returns twist angle.
+ */
+float quat_split_swing_and_twist(const float q[4], int axis, float r_swing[4], float r_twist[4])
+{
+ BLI_assert(axis >= 0 && axis <= 2);
+
+ /* Half-twist angle can be computed directly. */
+ float t = atan2f(q[axis + 1], q[0]);
+
+ if (r_swing || r_twist) {
+ float sin_t = sinf(t), cos_t = cosf(t);
+
+ /* Compute swing by multiplying the original quaternion by inverted twist. */
+ if (r_swing) {
+ float twist_inv[4];
+
+ twist_inv[0] = cos_t;
+ zero_v3(twist_inv + 1);
+ twist_inv[axis + 1] = -sin_t;
+
+ mul_qt_qtqt(r_swing, q, twist_inv);
+
+ BLI_assert(fabsf(r_swing[axis + 1]) < BLI_ASSERT_UNIT_EPSILON);
+ }
+
+ /* Output twist last just in case q ovelaps r_twist. */
+ if (r_twist) {
+ r_twist[0] = cos_t;
+ zero_v3(r_twist + 1);
+ r_twist[axis + 1] = sin_t;
+ }
+ }
+
+ return 2.0f * t;
+}
+
/* -------------------------------------------------------------------- */
/** \name Quaternion Angle
*
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index 8cb618ae14e..b4b53a1dd58 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -355,6 +355,12 @@ MINLINE void add_v2_v2(float r[2], const float a[2])
r[1] += a[1];
}
+MINLINE void add_v2_v2_db(double r[2], const double a[2])
+{
+ r[0] += a[0];
+ r[1] += a[1];
+}
+
MINLINE void add_v2_v2v2(float r[2], const float a[2], const float b[2])
{
r[0] = a[0] + b[0];
@@ -430,6 +436,12 @@ MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
r[1] = a[1] - b[1];
}
+MINLINE void sub_v2_v2v2_db(double r[2], const double a[2], const double b[2])
+{
+ r[0] = a[0] - b[0];
+ r[1] = a[1] - b[1];
+}
+
MINLINE void sub_v2_v2v2_int(int r[2], const int a[2], const int b[2])
{
r[0] = a[0] - b[0];
@@ -830,6 +842,11 @@ MINLINE float dot_v2v2(const float a[2], const float b[2])
return a[0] * b[0] + a[1] * b[1];
}
+MINLINE double dot_v2v2_db(const double a[2], const double b[2])
+{
+ return a[0] * b[0] + a[1] * b[1];
+}
+
MINLINE float dot_v3v3(const float a[3], const float b[3])
{
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
@@ -956,6 +973,15 @@ MINLINE float len_v2v2(const float v1[2], const float v2[2])
return sqrtf(x * x + y * y);
}
+MINLINE double len_v2v2_db(const double v1[2], const double v2[2])
+{
+ double x, y;
+
+ x = v1[0] - v2[0];
+ y = v1[1] - v2[1];
+ return sqrt(x * x + y * y);
+}
+
MINLINE float len_v2v2_int(const int v1[2], const int v2[2])
{
float x, y;
@@ -978,6 +1004,14 @@ MINLINE float len_squared_v2v2(const float a[2], const float b[2])
return dot_v2v2(d, d);
}
+MINLINE double len_squared_v2v2_db(const double a[2], const double b[2])
+{
+ double d[2];
+
+ sub_v2_v2v2_db(d, b, a);
+ return dot_v2v2_db(d, d);
+}
+
MINLINE float len_squared_v3v3(const float a[3], const float b[3])
{
float d[3];
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 18acbca00a1..725b6f8937a 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -618,14 +618,14 @@ void BLI_path_rel(char *file, const char *relfile)
*/
if (*q != '/') {
while ((q >= file) && (*q != '/')) {
- --q;
- --p;
+ q--;
+ p--;
}
}
else if (*p != '/') {
while ((p >= temp) && (*p != '/')) {
- --p;
- --q;
+ p--;
+ q--;
}
}
diff --git a/source/blender/blenlib/intern/polyfill_2d_beautify.c b/source/blender/blenlib/intern/polyfill_2d_beautify.c
index 3e94ae8de1f..ab397b86b1a 100644
--- a/source/blender/blenlib/intern/polyfill_2d_beautify.c
+++ b/source/blender/blenlib/intern/polyfill_2d_beautify.c
@@ -75,7 +75,7 @@ static int oedge_cmp(const void *a1, const void *a2)
return -1;
}
- /* only for pradictability */
+ /* Only for predictability. */
if (x1->e_half > x2->e_half) {
return 1;
}
@@ -100,6 +100,10 @@ BLI_INLINE bool is_boundary_edge(uint i_a, uint i_b, const uint coord_last)
* - When true, an existing zero area face on either side of the (2 - 4
* split will return a positive value.
* - When false, the check must be non-biased towards either split direction.
+ * \param r_area: Return the area of the quad,
+ * This can be useful when comparing the return value with near zero epsilons.
+ * In this case the epsilon can be scaled by the area to avoid the return value
+ * of very large faces not having a reliable way to detect near-zero output.
*
* \return (negative number means the edge can be rotated, lager == better).
*/
@@ -107,7 +111,8 @@ float BLI_polyfill_beautify_quad_rotate_calc_ex(const float v1[2],
const float v2[2],
const float v3[2],
const float v4[2],
- const bool lock_degenerate)
+ const bool lock_degenerate,
+ float *r_area)
{
/* not a loop (only to be able to break out) */
do {
@@ -121,6 +126,13 @@ float BLI_polyfill_beautify_quad_rotate_calc_ex(const float v1[2],
BLI_assert((ELEM(v1, v2, v3, v4) == false) && (ELEM(v2, v1, v3, v4) == false) &&
(ELEM(v3, v1, v2, v4) == false) && (ELEM(v4, v1, v2, v3) == false));
+
+ if (r_area) {
+ *r_area = fabsf(area_2x_234) + fabsf(area_2x_241) +
+ /* Include both pairs for predictable results. */
+ fabsf(area_2x_123) + fabsf(area_2x_134) / 8.0f;
+ }
+
/*
* Test for unusable (1-3) state.
* - Area sign flipping to check faces aren't going to point in opposite directions.
@@ -191,7 +203,8 @@ float BLI_polyfill_beautify_quad_rotate_calc_ex(const float v1[2],
static float polyedge_rotate_beauty_calc(const float (*coords)[2],
const struct HalfEdge *edges,
- const struct HalfEdge *e_a)
+ const struct HalfEdge *e_a,
+ float *r_area)
{
const struct HalfEdge *e_b = &edges[e_a->e_radial];
@@ -205,7 +218,7 @@ static float polyedge_rotate_beauty_calc(const float (*coords)[2],
v3 = coords[e_b_other->v];
v4 = coords[e_b->v];
- return BLI_polyfill_beautify_quad_rotate_calc(v1, v2, v3, v4);
+ return BLI_polyfill_beautify_quad_rotate_calc_ex(v1, v2, v3, v4, false, r_area);
}
static void polyedge_beauty_cost_update_single(const float (*coords)[2],
@@ -216,13 +229,18 @@ static void polyedge_beauty_cost_update_single(const float (*coords)[2],
{
const uint i = e->base_index;
/* recalculate edge */
- const float cost = polyedge_rotate_beauty_calc(coords, edges, e);
+ float area;
+ const float cost = polyedge_rotate_beauty_calc(coords, edges, e, &area);
/* We can get cases where both choices generate very small negative costs,
* which leads to infinite loop. Anyway, costs above that are not worth recomputing,
* maybe we could even optimize it to a smaller limit?
* Actually, FLT_EPSILON is too small in some cases, 1e-6f seems to work OK hopefully?
- * See T43578, T49478. */
- if (cost < -1e-6f) {
+ * See T43578, T49478.
+ *
+ * In fact a larger epsilon can still fail when the area of the face is very large,
+ * now the epsilon is scaled by the face area.
+ * See T56532. */
+ if (cost < -1e-6f * max_ff(area, 1.0f)) {
BLI_heap_insert_or_update(eheap, &eheap_table[i], cost, e);
}
else {
@@ -381,7 +399,7 @@ void BLI_polyfill_beautify(const float (*coords)[2],
for (uint i = 0; i < half_edges_len; i++, e++) {
/* Accounts for boundary edged too (UINT_MAX). */
if (e->e_radial < i) {
- const float cost = polyedge_rotate_beauty_calc(coords, half_edges, e);
+ const float cost = polyedge_rotate_beauty_calc(coords, half_edges, e, NULL);
if (cost < 0.0f) {
eheap_table[e->base_index] = BLI_heap_insert(eheap, cost, e);
}
diff --git a/source/blender/blenlib/intern/sort.c b/source/blender/blenlib/intern/sort.c
index 225015db00d..4ae87fff535 100644
--- a/source/blender/blenlib/intern/sort.c
+++ b/source/blender/blenlib/intern/sort.c
@@ -90,7 +90,7 @@ BLI_INLINE char *med3(char *a, char *b, char *c, BLI_sort_cmp_t cmp, void *thunk
}
/**
- * Quick sort reentrant.
+ * Quick sort re-entrant.
*/
void BLI_qsort_r(void *a, size_t n, size_t es, BLI_sort_cmp_t cmp, void *thunk)
{
diff --git a/source/blender/blenlib/intern/stack.c b/source/blender/blenlib/intern/stack.c
index 76aef3761ae..301675c026e 100644
--- a/source/blender/blenlib/intern/stack.c
+++ b/source/blender/blenlib/intern/stack.c
@@ -36,10 +36,6 @@
/* ensure we get at least this many elems per chunk */
#define CHUNK_ELEM_MIN 32
-/* Gets the last element in the stack */
-#define CHUNK_LAST_ELEM(_stack) \
- ((void)0, (((char *)(_stack)->chunk_curr->data) + ((_stack)->elem_size * (_stack)->chunk_index)))
-
struct StackChunk {
struct StackChunk *next;
char data[0];
@@ -56,6 +52,11 @@ struct BLI_Stack {
#endif
};
+static void *stack_get_last_elem(BLI_Stack *stack)
+{
+ return ((char *)(stack)->chunk_curr->data) + ((stack)->elem_size * (stack)->chunk_index);
+}
+
/**
* \return number of elements per chunk, optimized for slop-space.
*/
@@ -148,7 +149,7 @@ void *BLI_stack_push_r(BLI_Stack *stack)
#endif
/* Return end of stack */
- return CHUNK_LAST_ELEM(stack);
+ return stack_get_last_elem(stack);
}
/**
@@ -175,7 +176,7 @@ void BLI_stack_pop(BLI_Stack *stack, void *dst)
{
BLI_assert(BLI_stack_is_empty(stack) == false);
- memcpy(dst, CHUNK_LAST_ELEM(stack), stack->elem_size);
+ memcpy(dst, stack_get_last_elem(stack), stack->elem_size);
BLI_stack_discard(stack);
}
@@ -220,7 +221,7 @@ void *BLI_stack_peek(BLI_Stack *stack)
{
BLI_assert(BLI_stack_is_empty(stack) == false);
- return CHUNK_LAST_ELEM(stack);
+ return stack_get_last_elem(stack);
}
/**
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index 8d921b062dc..05a2d766fe0 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -230,14 +230,8 @@ int BLI_exists(const char *name)
tmp_16[3] = L'\0';
}
- /* change error mode so user does not get a "no disk in drive" popup
- * when looking for a file on an empty CD/DVD drive */
- old_error_mode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
-
res = BLI_wstat(tmp_16, &st);
- SetErrorMode(old_error_mode);
-
free(tmp_16);
if (res == -1) {
return (0);
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c
index 3b69e257f45..0b8ec44cbcd 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -663,8 +663,11 @@ static int left_number_strcmp(const char *s1, const char *s2, int *tiebreaker)
return 0;
}
-/* natural string compare, keeping numbers in order */
-int BLI_natstrcmp(const char *s1, const char *s2)
+/**
+ * Case insensitive, *natural* string comparison,
+ * keeping numbers in order.
+ */
+int BLI_strcasecmp_natural(const char *s1, const char *s2)
{
register int d1 = 0, d2 = 0;
register char c1, c2;
@@ -675,10 +678,7 @@ int BLI_natstrcmp(const char *s1, const char *s2)
* numeric, else do a tolower and char compare */
while (1) {
- c1 = tolower(s1[d1]);
- c2 = tolower(s2[d2]);
-
- if (isdigit(c1) && isdigit(c2)) {
+ if (isdigit(s1[d1]) && isdigit(s2[d2])) {
int numcompare = left_number_strcmp(s1 + d1, s2 + d2, &tiebreaker);
if (numcompare != 0) {
@@ -693,11 +693,11 @@ int BLI_natstrcmp(const char *s1, const char *s2)
while (isdigit(s2[d2])) {
d2++;
}
-
- c1 = tolower(s1[d1]);
- c2 = tolower(s2[d2]);
}
+ c1 = tolower(s1[d1]);
+ c2 = tolower(s2[d2]);
+
/* first check for '.' so "foo.bar" comes before "foo 1.bar" */
if (c1 == '.' && c2 != '.') {
return -1;
@@ -978,7 +978,7 @@ size_t BLI_str_partition_ex(const char *str,
*sep = *suf = NULL;
- for (d = delim; *d != '\0'; ++d) {
+ for (d = delim; *d != '\0'; d++) {
const char *tmp;
if (end) {
diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c
index 22c23727d76..92c4ec73768 100644
--- a/source/blender/blenlib/intern/string_utf8.c
+++ b/source/blender/blenlib/intern/string_utf8.c
@@ -716,7 +716,7 @@ size_t BLI_str_utf8_from_unicode(uint c, char *outbuf)
}
if (outbuf) {
- for (i = len - 1; i > 0; --i) {
+ for (i = len - 1; i > 0; i--) {
outbuf[i] = (c & 0x3f) | 0x80;
c >>= 6;
}
@@ -744,7 +744,7 @@ size_t BLI_str_utf8_from_unicode(uint c, char *outbuf)
*/
char *BLI_str_find_prev_char_utf8(const char *str, const char *p)
{
- for (--p; p >= str; --p) {
+ for (--p; p >= str; p--) {
if ((*p & 0xc0) != 0x80) {
return (char *)p;
}
@@ -771,12 +771,12 @@ char *BLI_str_find_next_char_utf8(const char *p, const char *end)
{
if (*p) {
if (end) {
- for (++p; p < end && (*p & 0xc0) == 0x80; ++p) {
+ for (++p; p < end && (*p & 0xc0) == 0x80; p++) {
/* do nothing */
}
}
else {
- for (++p; (*p & 0xc0) == 0x80; ++p) {
+ for (++p; (*p & 0xc0) == 0x80; p++) {
/* do nothing */
}
}
@@ -852,7 +852,7 @@ size_t BLI_str_partition_ex_utf8(const char *str,
break;
}
- for (d = delim; *d != '\0'; ++d) {
+ for (d = delim; *d != '\0'; d++) {
if (*d == c) {
/* *suf is already correct in case from_right is true. */
if (!from_right) {
diff --git a/source/blender/blenlib/intern/system.c b/source/blender/blenlib/intern/system.c
index 88f2e2625e8..941c2b608e6 100644
--- a/source/blender/blenlib/intern/system.c
+++ b/source/blender/blenlib/intern/system.c
@@ -179,6 +179,19 @@ char *BLI_cpu_brand_string(void)
return NULL;
}
+int BLI_cpu_support_sse41(void)
+{
+ int result[4], num;
+ __cpuid(result, 0);
+ num = result[0];
+
+ if (num >= 1) {
+ __cpuid(result, 0x00000001);
+ return (result[2] & ((int)1 << 19)) != 0;
+ }
+ return 0;
+}
+
void BLI_hostname_get(char *buffer, size_t bufsize)
{
#ifndef WIN32
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index 034a6d4017e..6cdaec97d9a 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -266,7 +266,7 @@ BLI_INLINE TaskThreadLocalStorage *get_task_tls(TaskPool *pool, const int thread
BLI_INLINE void free_task_tls(TaskThreadLocalStorage *tls)
{
TaskMemPool *task_mempool = &tls->task_mempool;
- for (int i = 0; i < task_mempool->num_tasks; ++i) {
+ for (int i = 0; i < task_mempool->num_tasks; i++) {
MEM_freeN(task_mempool->tasks[i]);
}
}
@@ -561,7 +561,7 @@ void BLI_task_scheduler_free(TaskScheduler *scheduler)
/* Delete task thread data */
if (scheduler->task_threads) {
- for (int i = 0; i < scheduler->num_threads + 1; ++i) {
+ for (int i = 0; i < scheduler->num_threads + 1; i++) {
TaskThreadLocalStorage *tls = &scheduler->task_threads[i].tls;
free_task_tls(tls);
}
@@ -732,9 +732,7 @@ static TaskPool *task_pool_create_ex(TaskScheduler *scheduler,
}
/**
- * Create a normal task pool.
- * This means that in single-threaded context, it will not be executed at all until you call
- * \a BLI_task_pool_work_and_wait() on it.
+ * Create a normal task pool. Tasks will be executed as soon as they are added.
*/
TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata)
{
@@ -779,7 +777,7 @@ void BLI_task_pool_free(TaskPool *pool)
#ifdef DEBUG_STATS
printf("Thread ID Allocated Reused Discarded\n");
- for (int i = 0; i < pool->scheduler->num_threads + 1; ++i) {
+ for (int i = 0; i < pool->scheduler->num_threads + 1; i++) {
printf("%02d %05d %05d %05d\n",
i,
pool->mempool_stats[i].num_alloc,
@@ -1066,22 +1064,28 @@ BLI_INLINE void task_parallel_range_calc_chunk_size(const TaskParallelSettings *
chunk_size = settings->min_iter_per_thread;
}
else {
- /* Basic heuristic to avoid threading on low amount of items. We could make that limit
- * configurable in settings too... */
- if (tot_items > 0 && tot_items < 256) {
- chunk_size = tot_items;
- }
- /* NOTE: The idea here is to compensate for rather measurable threading
+ /* Multiplier used in heuristics below to define "optimal" chunk size.
+ * The idea here is to increase the chunk size to compensate for a rather measurable threading
* overhead caused by fetching tasks. With too many CPU threads we are starting
- * to spend too much time in those overheads. */
- else if (num_tasks > 32) {
- chunk_size = 128;
- }
- else if (num_tasks > 16) {
- chunk_size = 64;
- }
- else {
- chunk_size = 32;
+ * to spend too much time in those overheads.
+ * First values are: 1 if num_tasks < 16;
+ * else 2 if num_tasks < 32;
+ * else 3 if num_tasks < 48;
+ * else 4 if num_tasks < 64;
+ * etc.
+ * Note: If we wanted to keep the 'power of two' multiplier, we'd need something like:
+ * 1 << max_ii(0, (int)(sizeof(int) * 8) - 1 - bitscan_reverse_i(num_tasks) - 3)
+ */
+ const int num_tasks_factor = max_ii(1, num_tasks >> 3);
+
+ /* We could make that 'base' 32 number configurable in TaskParallelSettings too, or maybe just
+ * always use that heuristic using TaskParallelSettings.min_iter_per_thread as basis? */
+ chunk_size = 32 * num_tasks_factor;
+
+ /* Basic heuristic to avoid threading on low amount of items.
+ * We could make that limit configurable in settings too. */
+ if (tot_items > 0 && tot_items < max_ii(256, chunk_size * 2)) {
+ chunk_size = tot_items;
}
}
@@ -1118,7 +1122,7 @@ static void parallel_range_func(TaskPool *__restrict pool, void *userdata_chunk,
};
int iter, count;
while (parallel_range_next_iter_get(state, &iter, &count)) {
- for (int i = 0; i < count; ++i) {
+ for (int i = 0; i < count; i++) {
state->func(state->userdata, iter + i, &tls);
}
}
@@ -1142,7 +1146,7 @@ static void parallel_range_single_thread(const int start,
.thread_id = 0,
.userdata_chunk = userdata_chunk_local,
};
- for (int i = start; i < stop; ++i) {
+ for (int i = start; i < stop; i++) {
func(userdata, i, &tls);
}
if (settings->func_finalize != NULL) {
@@ -1275,7 +1279,7 @@ BLI_INLINE Link *parallel_listbase_next_iter_get(ParallelListState *__restrict s
if (LIKELY(result != NULL)) {
*index = state->index;
while (state->link != NULL && task_count < state->chunk_size) {
- ++task_count;
+ task_count++;
state->link = state->link->next;
}
state->index += task_count;
@@ -1294,7 +1298,7 @@ static void parallel_listbase_func(TaskPool *__restrict pool,
int index, count;
while ((link = parallel_listbase_next_iter_get(state, &index, &count)) != NULL) {
- for (int i = 0; i < count; ++i) {
+ for (int i = 0; i < count; i++) {
state->func(state->userdata, link, index + i);
link = link->next;
}
@@ -1306,7 +1310,7 @@ static void task_parallel_listbase_no_threads(struct ListBase *listbase,
TaskParallelListbaseFunc func)
{
int i = 0;
- for (Link *link = listbase->first; link != NULL; link = link->next, ++i) {
+ for (Link *link = listbase->first; link != NULL; link = link->next, i++) {
func(userdata, link, i);
}
}
diff --git a/source/blender/blenlib/intern/voronoi_2d.c b/source/blender/blenlib/intern/voronoi_2d.c
index 29beb93159a..eb718c5e8c6 100644
--- a/source/blender/blenlib/intern/voronoi_2d.c
+++ b/source/blender/blenlib/intern/voronoi_2d.c
@@ -581,7 +581,7 @@ static void voronoi_clampEdges(ListBase *edges, int width, int height, ListBase
}
static int voronoi_getNextSideCoord(
- ListBase *edges, float coord[2], int dim, int dir, float next_coord[2])
+ ListBase *edges, const float coord[2], int dim, int dir, float next_coord[2])
{
VoronoiEdge *edge = edges->first;
float distance = FLT_MAX;
diff --git a/source/blender/blenlib/intern/winstuff.c b/source/blender/blenlib/intern/winstuff.c
index 9e6ea0bb6ee..724f27f4667 100644
--- a/source/blender/blenlib/intern/winstuff.c
+++ b/source/blender/blenlib/intern/winstuff.c
@@ -172,17 +172,7 @@ void RegisterBlendExtension(void)
BLI_getInstallationDir(InstallDir);
GetSystemDirectory(SysDir, FILE_MAXDIR);
-# ifdef _WIN64
- ThumbHandlerDLL = "BlendThumb64.dll";
-# else
- IsWow64Process(GetCurrentProcess(), &IsWOW64);
- if (IsWOW64 == true) {
- ThumbHandlerDLL = "BlendThumb64.dll";
- }
- else {
- ThumbHandlerDLL = "BlendThumb.dll";
- }
-# endif
+ ThumbHandlerDLL = "BlendThumb.dll";
snprintf(
RegCmd, MAX_PATH * 2, "%s\\regsvr32 /s \"%s\\%s\"", SysDir, InstallDir, ThumbHandlerDLL);
system(RegCmd);
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 2a036d7f4ea..545659d06c2 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -24,15 +24,12 @@
#include "zlib.h"
#include <limits.h>
-#include <stdio.h> // for printf fopen fwrite fclose sprintf FILE
-#include <stdlib.h> // for getenv atoi
-#include <stddef.h> // for offsetof
-#include <fcntl.h> // for open
-#include <string.h> // for strrchr strncmp strstr
-#include <math.h> // for fabs
-#include <stdarg.h> /* for va_start/end */
-#include <time.h> /* for gmtime */
-#include <ctype.h> /* for isdigit */
+#include <stdlib.h> /* for atoi. */
+#include <stddef.h> /* for offsetof. */
+#include <fcntl.h> /* for open flags (O_BINARY, O_RDONLY). */
+#include <stdarg.h> /* for va_start/end. */
+#include <time.h> /* for gmtime. */
+#include <ctype.h> /* for isdigit. */
#include "BLI_utildefines.h"
#ifndef WIN32
@@ -95,8 +92,6 @@
#include "DNA_movieclip_types.h"
#include "DNA_mask_types.h"
-#include "RNA_access.h"
-
#include "MEM_guardedalloc.h"
#include "BLI_endian_switch.h"
@@ -111,8 +106,6 @@
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_brush.h"
-#include "BKE_cachefile.h"
-#include "BKE_cloth.h"
#include "BKE_collection.h"
#include "BKE_colortools.h"
#include "BKE_constraint.h"
@@ -120,7 +113,6 @@
#include "BKE_effect.h"
#include "BKE_fcurve.h"
#include "BKE_global.h" // for G
-#include "BKE_gpencil.h"
#include "BKE_gpencil_modifier.h"
#include "BKE_idcode.h"
#include "BKE_idprop.h"
@@ -137,8 +129,6 @@
#include "BKE_multires.h"
#include "BKE_node.h" // for tree type defines
#include "BKE_object.h"
-#include "BKE_ocean.h"
-#include "BKE_outliner_treehash.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
@@ -184,7 +174,7 @@
* - read associated 'direct data'
* - link direct data (internal and to LibBlock)
* - read #FileGlobal
- * - read #USER data, only when indicated (file is ``~/X.XX/startup.blend``)
+ * - read #USER data, only when indicated (file is `~/.config/blender/X.XX/config/userpref.blend`)
* - free file
* - per Library (per #Main)
* - read file
@@ -233,7 +223,7 @@
#define USE_GHASH_RESTORE_POINTER
/* Define this to have verbose debug prints. */
-#define USE_DEBUG_PRINT
+//#define USE_DEBUG_PRINT
#ifdef USE_DEBUG_PRINT
# define DEBUG_PRINTF(...) printf(__VA_ARGS__)
@@ -2597,7 +2587,7 @@ static PreviewImage *direct_link_preview_image(FileData *fd, PreviewImage *old_p
if (prv) {
int i;
- for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ for (i = 0; i < NUM_ICON_SIZES; i++) {
if (prv->rect[i]) {
prv->rect[i] = newdataadr(fd, prv->rect[i]);
}
@@ -2667,6 +2657,7 @@ static void direct_link_id(FileData *fd, ID *id)
* function are still in a clear tag state.
* (glowering at certain nodetree fake data-lock here...). */
id->tag = 0;
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
/* Link direct data of overrides. */
if (id->override_library) {
@@ -2838,6 +2829,12 @@ static PackedFile *direct_link_packedfile(FileData *fd, PackedFile *oldpf)
if (pf) {
pf->data = newpackedadr(fd, pf->data);
+ if (pf->data == NULL) {
+ /* We cannot allow a PackedFile with a NULL data field,
+ * the whole code assumes this is not possible. See T70315. */
+ printf("%s: NULL packedfile data, cleaning up...\n", __func__);
+ MEM_SAFE_FREE(pf);
+ }
}
return pf;
@@ -4382,7 +4379,7 @@ static void direct_link_curve(FileData *fd, Curve *cu)
switch_endian_knots(nu);
}
}
- cu->bb = NULL;
+ cu->texflag &= ~CU_AUTOSPACE_EVALUATED;
}
/** \} */
@@ -4938,7 +4935,7 @@ static void direct_link_mdisps(FileData *fd, int count, MDisps *mdisps, int exte
if (mdisps) {
int i;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
mdisps[i].disps = newdataadr(fd, mdisps[i].disps);
mdisps[i].hidden = newdataadr(fd, mdisps[i].hidden);
@@ -4968,7 +4965,7 @@ static void direct_link_grid_paint_mask(FileData *fd, int count, GridPaintMask *
if (grid_paint_mask) {
int i;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
GridPaintMask *gpm = &grid_paint_mask[i];
if (gpm->data) {
gpm->data = newdataadr(fd, gpm->data);
@@ -5049,7 +5046,7 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
direct_link_customdata(fd, &mesh->ldata, mesh->totloop);
direct_link_customdata(fd, &mesh->pdata, mesh->totpoly);
- mesh->bb = NULL;
+ mesh->texflag &= ~ME_AUTOSPACE_EVALUATED;
mesh->edit_mesh = NULL;
BKE_mesh_runtime_reset(mesh);
@@ -5339,8 +5336,8 @@ static void lib_link_object(FileData *fd, Main *main)
eModifierType_Smoke);
if (smd && (smd->type == MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
- smd->domain->flags |=
- MOD_SMOKE_FILE_LOAD; /* flag for refreshing the simulation after loading */
+ /* Flag for refreshing the simulation after loading. */
+ smd->domain->flags |= MOD_SMOKE_FILE_LOAD;
}
}
@@ -5753,8 +5750,8 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
}
/* runtime only */
- csmd->delta_cache = NULL;
- csmd->delta_cache_num = 0;
+ csmd->delta_cache.deltas = NULL;
+ csmd->delta_cache.totverts = 0;
}
else if (md->type == eModifierType_MeshSequenceCache) {
MeshSeqCacheModifierData *msmcd = (MeshSeqCacheModifierData *)md;
@@ -6344,7 +6341,7 @@ static void direct_link_lightcache(FileData *fd, LightCache *cache)
if (cache->cube_mips) {
cache->cube_mips = newdataadr(fd, cache->cube_mips);
- for (int i = 0; i < cache->mips_len; ++i) {
+ for (int i = 0; i < cache->mips_len; i++) {
direct_link_lightcache_texture(fd, &cache->cube_mips[i]);
}
}
@@ -6353,6 +6350,14 @@ static void direct_link_lightcache(FileData *fd, LightCache *cache)
cache->grid_data = newdataadr(fd, cache->grid_data);
}
+static void direct_link_view3dshading(FileData *fd, View3DShading *shading)
+{
+ if (shading->prop) {
+ shading->prop = newdataadr(fd, shading->prop);
+ IDP_DirectLinkGroup_OrFree(&shading->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ }
+}
+
/* check for cyclic set-scene,
* libs can cause this case which is normally prevented, see (T#####) */
#define USE_SETSCENE_CHECK
@@ -6755,6 +6760,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
ed->act_seq = newdataadr(fd, ed->act_seq);
ed->cache = NULL;
+ ed->prefetch_job = NULL;
/* recursive link sequences, lb will be correctly initialized */
link_recurs_seq(fd, &ed->seqbase);
@@ -6987,6 +6993,8 @@ static void direct_link_scene(FileData *fd, Scene *sce)
}
}
+ direct_link_view3dshading(fd, &sce->display.shading);
+
sce->layer_properties = newdataadr(fd, sce->layer_properties);
IDP_DirectLinkGroup_OrFree(&sce->layer_properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
@@ -7150,6 +7158,8 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype)
rv3d->render_engine = NULL;
rv3d->sms = NULL;
rv3d->smooth_timer = NULL;
+
+ rv3d->rflag &= ~(RV3D_NAVIGATING | RV3D_PAINTING);
}
}
}
@@ -7255,6 +7265,8 @@ static void direct_link_area(FileData *fd, ScrArea *area)
v3d->fx_settings.ssao = newdataadr(fd, v3d->fx_settings.ssao);
}
+ direct_link_view3dshading(fd, &v3d->shading);
+
blo_do_versions_view3d_split_250(v3d, &sl->regionbase);
}
else if (sl->spacetype == SPACE_GRAPH) {
@@ -7859,6 +7871,45 @@ static void lib_link_clipboard_restore(struct IDNameLib_Map *id_map)
BKE_sequencer_base_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, id_map);
}
+static int lib_link_main_data_restore_cb(void *user_data,
+ ID *UNUSED(id_self),
+ ID **id_pointer,
+ int cb_flag)
+{
+ if (cb_flag & IDWALK_CB_PRIVATE || *id_pointer == NULL) {
+ return IDWALK_RET_NOP;
+ }
+
+ /* Special ugly case here, thanks again for those non-IDs IDs... */
+ /* We probably need to add more cases here (hint: nodetrees),
+ * but will wait for changes from D5559 to get in first. */
+ if (GS((*id_pointer)->name) == ID_GR) {
+ Collection *collection = (Collection *)*id_pointer;
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ return IDWALK_RET_NOP;
+ }
+ }
+
+ struct IDNameLib_Map *id_map = user_data;
+
+ /* Note: Handling of usercount here is really bad, defining its own system...
+ * Will have to be refactored at some point, but that is not top priority task for now.
+ * And all usercounts are properly recomputed at the end of the undo management code anyway. */
+ *id_pointer = restore_pointer_by_name(
+ id_map, *id_pointer, (cb_flag & IDWALK_CB_USER_ONE) ? USER_REAL : USER_IGNORE);
+
+ return IDWALK_RET_NOP;
+}
+
+static void lib_link_main_data_restore(struct IDNameLib_Map *id_map, Main *newmain)
+{
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (newmain, id) {
+ BKE_library_foreach_ID_link(newmain, id, lib_link_main_data_restore_cb, id_map, IDWALK_NOP);
+ }
+ FOREACH_MAIN_ID_END;
+}
+
static void lib_link_window_scene_data_restore(wmWindow *win, Scene *scene, ViewLayer *view_layer)
{
bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
@@ -8178,11 +8229,24 @@ void blo_lib_link_restore(Main *oldmain,
/* keep cursor location through undo */
memcpy(&win->scene->cursor, &oldscene->cursor, sizeof(win->scene->cursor));
+ /* Note: even though that function seems to redo part of what is done by
+ * `lib_link_workspace_layout_restore()` above, it seems to have a slightly different scope:
+ * while the former updates the whole UI pointers from Main db (going over all layouts of
+ * all workspaces), that one only focuses one current active screen, takes care of
+ * potential local view, and needs window's scene pointer to be final... */
lib_link_window_scene_data_restore(win, win->scene, cur_view_layer);
BLI_assert(win->screen == NULL);
}
+ /* Restore all ID pointers in Main database itself
+ * (especially IDProperties might point to some worspace of other 'weirdly unchanged' ID
+ * pointers, see T69146).
+ * Note that this will re;ap again a few pointers in workspaces or so,
+ * but since we are remapping final ones already set above,
+ * that is just some minor harmless double-processing. */
+ lib_link_main_data_restore(id_map, newmain);
+
/* update IDs stored in all possible clipboards */
lib_link_clipboard_restore(id_map);
@@ -9070,7 +9134,12 @@ static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *a
return bhead;
}
-static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const int tag, ID **r_id)
+static BHead *read_libblock(FileData *fd,
+ Main *main,
+ BHead *bhead,
+ const int tag,
+ const bool placeholder_set_indirect_extern,
+ ID **r_id)
{
/* this routine reads a libblock and its direct data. Use link functions to connect it all
*/
@@ -9190,7 +9259,16 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const int ta
/* this case cannot be direct_linked: it's just the ID part */
if (bhead->code == ID_LINK_PLACEHOLDER) {
/* That way, we know which data-lock needs do_versions (required currently for linking). */
- id->tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW;
+ id->tag = tag | LIB_TAG_ID_LINK_PLACEHOLDER | LIB_TAG_NEED_LINK | LIB_TAG_NEW;
+
+ if (placeholder_set_indirect_extern) {
+ if (id->flag & LIB_INDIRECT_WEAK_LINK) {
+ id->tag |= LIB_TAG_INDIRECT;
+ }
+ else {
+ id->tag |= LIB_TAG_EXTERN;
+ }
+ }
return blo_bhead_next(fd, bhead);
}
@@ -9753,8 +9831,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
* to the file format definition. So we can use the entry at the
* end of mainlist, added in direct_link_library. */
Main *libmain = mainlist.last;
- bhead = read_libblock(
- fd, libmain, bhead, LIB_TAG_ID_LINK_PLACEHOLDER | LIB_TAG_EXTERN, NULL);
+ bhead = read_libblock(fd, libmain, bhead, 0, true, NULL);
}
break;
/* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
@@ -9767,7 +9844,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
bhead = blo_bhead_next(fd, bhead);
}
else {
- bhead = read_libblock(fd, bfd->main, bhead, LIB_TAG_LOCAL, NULL);
+ bhead = read_libblock(fd, bfd->main, bhead, LIB_TAG_LOCAL, false, NULL);
}
}
}
@@ -10015,7 +10092,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
if (id == NULL) {
/* ID has not been read yet, add placeholder to the main of the
* library it belongs to, so that it will be read later. */
- read_libblock(fd, libmain, bhead, LIB_TAG_ID_LINK_PLACEHOLDER | LIB_TAG_INDIRECT, NULL);
+ read_libblock(fd, libmain, bhead, LIB_TAG_INDIRECT, false, NULL);
// commented because this can print way too much
// if (G.debug & G_DEBUG) printf("expand_doit: other lib %s\n", lib->name);
@@ -10023,6 +10100,12 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
libmain->curlib->parent = mainvar->curlib;
}
else {
+ /* Convert any previously read weak link to regular link
+ * to signal that we want to read this datablock. */
+ if (id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) {
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
+ }
+
/* "id" is either a placeholder or real ID that is already in the
* main of the library (A) it belongs to. However it might have been
* put there by another library (C) which only updated its own
@@ -10064,9 +10147,15 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
ID *id = is_yet_read(fd, mainvar, bhead);
if (id == NULL) {
- read_libblock(fd, mainvar, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, NULL);
+ read_libblock(fd, mainvar, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, false, NULL);
}
else {
+ /* Convert any previously read weak link to regular link
+ * to signal that we want to read this datablock. */
+ if (id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) {
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
+ }
+
/* this is actually only needed on UI call? when ID was already read before,
* and another append happens which invokes same ID...
* in that case the lookup table needs this entry */
@@ -11200,6 +11289,7 @@ static void add_loose_objects_to_scene(Main *mainvar,
BKE_scene_object_base_flag_sync_from_base(base);
ob->id.tag &= ~LIB_TAG_INDIRECT;
+ ob->id.flag &= ~LIB_INDIRECT_WEAK_LINK;
ob->id.tag |= LIB_TAG_EXTERN;
}
}
@@ -11292,6 +11382,7 @@ static void add_collections_to_scene(Main *mainvar,
/* Those are kept for safety and consistency, but should not be needed anymore? */
collection->id.tag &= ~LIB_TAG_INDIRECT;
+ collection->id.flag &= ~LIB_INDIRECT_WEAK_LINK;
collection->id.tag |= LIB_TAG_EXTERN;
}
}
@@ -11316,7 +11407,7 @@ static ID *link_named_part(
if (id == NULL) {
/* not read yet */
const int tag = force_indirect ? LIB_TAG_INDIRECT : LIB_TAG_EXTERN;
- read_libblock(fd, mainl, bhead, tag | LIB_TAG_NEED_EXPAND, &id);
+ read_libblock(fd, mainl, bhead, tag | LIB_TAG_NEED_EXPAND, false, &id);
if (id) {
/* sort by name in list */
@@ -11332,6 +11423,7 @@ static ID *link_named_part(
oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code);
if (!force_indirect && (id->tag & LIB_TAG_INDIRECT)) {
id->tag &= ~LIB_TAG_INDIRECT;
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
id->tag |= LIB_TAG_EXTERN;
}
}
@@ -11370,7 +11462,7 @@ int BLO_library_link_copypaste(Main *mainl, BlendHandle *bh, const unsigned int
if (BKE_idcode_is_valid(bhead->code) && BKE_idcode_is_linkable(bhead->code) &&
(id_types_mask == 0 ||
(BKE_idcode_to_idfilter((short)bhead->code) & id_types_mask) != 0)) {
- read_libblock(fd, mainl, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, &id);
+ read_libblock(fd, mainl, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, false, &id);
num_directly_linked++;
}
@@ -11656,7 +11748,7 @@ static int has_linked_ids_to_read(Main *mainvar)
while (a--) {
for (ID *id = lbarray[a]->first; id; id = id->next) {
- if (id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) {
+ if ((id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) && !(id->flag & LIB_INDIRECT_WEAK_LINK)) {
return true;
}
}
@@ -11687,11 +11779,12 @@ static void read_library_linked_id(
}
id->tag &= ~LIB_TAG_ID_LINK_PLACEHOLDER;
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
if (bhead) {
id->tag |= LIB_TAG_NEED_EXPAND;
// printf("read lib block %s\n", id->name);
- read_libblock(fd, mainvar, bhead, id->tag, r_id);
+ read_libblock(fd, mainvar, bhead, id->tag, false, r_id);
}
else {
blo_reportf_wrap(reports,
@@ -11725,7 +11818,7 @@ static void read_library_linked_ids(FileData *basefd,
while (id) {
ID *id_next = id->next;
- if (id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) {
+ if ((id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) && !(id->flag & LIB_INDIRECT_WEAK_LINK)) {
BLI_remlink(lbarray[a], id);
/* When playing with lib renaming and such, you may end with cases where
@@ -11761,6 +11854,28 @@ static void read_library_linked_ids(FileData *basefd,
BLI_ghash_free(loaded_ids, NULL, NULL);
}
+static void read_library_clear_weak_links(FileData *basefd, ListBase *mainlist, Main *mainvar)
+{
+ /* Any remaining weak links at this point have been lost, silently drop
+ * those by setting them to NULL pointers. */
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a = set_listbasepointers(mainvar, lbarray);
+
+ while (a--) {
+ ID *id = lbarray[a]->first;
+
+ while (id) {
+ ID *id_next = id->next;
+ if ((id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) && (id->flag & LIB_INDIRECT_WEAK_LINK)) {
+ /* printf("Dropping weak link to %s\n", id->name); */
+ change_link_placeholder_to_real_ID_pointer(mainlist, basefd, id, NULL);
+ BLI_freelinkN(lbarray[a], id);
+ }
+ id = id_next;
+ }
+ }
+}
+
static FileData *read_library_file_data(FileData *basefd,
ListBase *mainlist,
Main *mainl,
@@ -11887,6 +12002,9 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
Main *main_newid = BKE_main_new();
for (Main *mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
+ /* Drop weak links for which no datablock was found. */
+ read_library_clear_weak_links(basefd, mainlist, mainptr);
+
/* Do versioning for newly added linked data-locks. If no data-locks
* were read from a library versionfile will still be zero and we can
* skip it. */
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index ba4dc2d33c7..72013bc6eed 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -67,7 +67,6 @@
#include "BKE_global.h" // for G
#include "BKE_library.h"
#include "BKE_main.h"
-#include "BKE_mesh.h" // for ME_ defines (patching)
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_particle.h"
@@ -1697,7 +1696,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
/* will have no effect */
if (brush->alpha == 0) {
- brush->alpha = 0.5f;
+ brush->alpha = 1.0f;
}
/* bad radius */
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 6f5c37d716e..4e0be8ceb9c 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -41,6 +41,8 @@
#include "DNA_sdna_types.h"
#include "DNA_smoke_types.h"
#include "DNA_space_types.h"
+#include "DNA_world_types.h"
+#include "DNA_light_types.h"
#include "MEM_guardedalloc.h"
@@ -63,7 +65,10 @@
#include "BKE_text.h" // for txt_extended_ascii_as_utf8
#include "BKE_texture.h"
#include "BKE_tracking.h"
-#include "BKE_writeffmpeg.h"
+
+#ifdef WITH_FFMPEG
+# include "BKE_writeffmpeg.h"
+#endif
#include "IMB_imbuf.h" // for proxy / timecode versioning stuff
@@ -2606,7 +2611,7 @@ void do_versions_after_linking_260(Main *bmain)
if (input_node) {
link->fromnode = input_node;
link->fromsock = node_group_input_find_socket(input_node, link->fromsock->identifier);
- ++num_inputs;
+ num_inputs++;
if (link->tonode) {
if (input_locx > link->tonode->locx - offsetx) {
@@ -2624,7 +2629,7 @@ void do_versions_after_linking_260(Main *bmain)
if (output_node) {
link->tonode = output_node;
link->tosock = node_group_output_find_socket(output_node, link->tosock->identifier);
- ++num_outputs;
+ num_outputs++;
if (link->fromnode) {
if (output_locx < link->fromnode->locx + offsetx) {
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index b61692799ed..a3dc177262e 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -48,14 +48,13 @@
#include "DNA_view3d_types.h"
#include "DNA_smoke_types.h"
#include "DNA_rigidbody_types.h"
+#include "DNA_light_types.h"
#include "DNA_genfile.h"
#include "BKE_animsys.h"
-#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_fcurve.h"
-#include "BKE_gpencil.h"
#include "BKE_main.h"
#include "BKE_mask.h"
#include "BKE_modifier.h"
@@ -1747,8 +1746,9 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!DNA_struct_elem_find(fd->filesdna, "Brush", "float", "falloff_angle")) {
for (Brush *br = bmain->brushes.first; br; br = br->id.next) {
br->falloff_angle = DEG2RADF(80);
- br->flag &= ~(BRUSH_FLAG_UNUSED_1 | BRUSH_FLAG_UNUSED_6 | BRUSH_FLAG_UNUSED_7 |
- BRUSH_FLAG_UNUSED_17 | BRUSH_FRONTFACE_FALLOFF);
+ /* These flags are used for new feautres. They are not related to falloff_angle */
+ br->flag &= ~(BRUSH_FLAG_UNUSED_1 | BRUSH_ORIGINAL_PLANE | BRUSH_GRAB_ACTIVE_VERTEX |
+ BRUSH_SCENE_SPACING | BRUSH_FRONTFACE_FALLOFF);
}
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index d2017864192..7ea1d25f86d 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -55,8 +55,8 @@
#include "DNA_curve_types.h"
#include "DNA_armature_types.h"
#include "DNA_text_types.h"
+#include "DNA_world_types.h"
-#include "BKE_action.h"
#include "BKE_animsys.h"
#include "BKE_cloth.h"
#include "BKE_collection.h"
@@ -65,22 +65,17 @@
#include "BKE_customdata.h"
#include "BKE_fcurve.h"
#include "BKE_freestyle.h"
-#include "BKE_gpencil.h"
#include "BKE_idprop.h"
-#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_library.h"
#include "BKE_layer.h"
#include "BKE_main.h"
-#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_node.h"
-#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_pointcache.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
-#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_sequencer.h"
#include "BKE_studiolight.h"
@@ -406,7 +401,7 @@ static void do_version_layers_to_collections(Main *bmain, Scene *scene)
}
/* Create collections from layers. */
- Collection *collection_master = BKE_collection_master(scene);
+ Collection *collection_master = scene->master_collection;
Collection *collections[20] = {NULL};
for (int layer = 0; layer < 20; layer++) {
@@ -637,6 +632,18 @@ static void do_version_bones_split_bbone_scale(ListBase *lb)
}
}
+static void do_version_bones_inherit_scale(ListBase *lb)
+{
+ for (Bone *bone = lb->first; bone; bone = bone->next) {
+ if (bone->flag & BONE_NO_SCALE) {
+ bone->inherit_scale_mode = BONE_INHERIT_SCALE_NONE_LEGACY;
+ bone->flag &= ~BONE_NO_SCALE;
+ }
+
+ do_version_bones_inherit_scale(&bone->childbase);
+ }
+}
+
static bool replace_bbone_scale_rnapath(char **p_old_path)
{
char *old_path = *p_old_path;
@@ -715,6 +722,17 @@ static void do_version_constraints_copy_scale_power(ListBase *lb)
}
}
+static void do_version_constraints_copy_rotation_mix_mode(ListBase *lb)
+{
+ for (bConstraint *con = lb->first; con; con = con->next) {
+ if (con->type == CONSTRAINT_TYPE_ROTLIKE) {
+ bRotateLikeConstraint *data = (bRotateLikeConstraint *)con->data;
+ data->mix_mode = (data->flag & ROTLIKE_OFFSET) ? ROTLIKE_MIX_OFFSET : ROTLIKE_MIX_REPLACE;
+ data->flag &= ~ROTLIKE_OFFSET;
+ }
+ }
+}
+
static void do_versions_seq_alloc_transform_and_crop(ListBase *seqbase)
{
for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) {
@@ -825,6 +843,14 @@ static void do_versions_material_convert_legacy_blend_mode(bNodeTree *ntree, cha
}
}
+static void do_versions_local_collection_bits_set(LayerCollection *layer_collection)
+{
+ layer_collection->local_collections_bits = ~(0);
+ LISTBASE_FOREACH (LayerCollection *, child, &layer_collection->layer_collections) {
+ do_versions_local_collection_bits_set(child);
+ }
+}
+
void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
{
bool use_collection_compat_28 = true;
@@ -1430,7 +1456,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
ToolSettings *ts = scene->toolsettings;
/* sculpt brushes */
GP_Sculpt_Settings *gset = &ts->gp_sculpt;
- for (int i = 0; i < GP_SCULPT_TYPE_MAX; ++i) {
+ for (int i = 0; i < GP_SCULPT_TYPE_MAX; i++) {
gp_brush = &gset->brush[i];
gp_brush->flag |= GP_SCULPT_FLAG_ENABLE_CURSOR;
copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
@@ -1842,7 +1868,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
EEVEE_GET_BOOL(props, shadow_high_bitdepth, SCE_EEVEE_SHADOW_HIGH_BITDEPTH);
EEVEE_GET_BOOL(props, taa_reprojection, SCE_EEVEE_TAA_REPROJECTION);
// EEVEE_GET_BOOL(props, sss_enable, SCE_EEVEE_SSS_ENABLED);
- EEVEE_GET_BOOL(props, sss_separate_albedo, SCE_EEVEE_SSS_SEPARATE_ALBEDO);
+ // EEVEE_GET_BOOL(props, sss_separate_albedo, SCE_EEVEE_SSS_SEPARATE_ALBEDO);
EEVEE_GET_BOOL(props, ssr_enable, SCE_EEVEE_SSR_ENABLED);
EEVEE_GET_BOOL(props, ssr_refraction, SCE_EEVEE_SSR_REFRACTION);
EEVEE_GET_BOOL(props, ssr_halfres, SCE_EEVEE_SSR_HALF_RESOLUTION);
@@ -2895,7 +2921,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
case SPACE_VIEW3D: {
View3D *v3d = (View3D *)sl;
- v3d->flag &= ~(V3D_FLAG_UNUSED_0 | V3D_FLAG_UNUSED_1 | V3D_FLAG_UNUSED_10 |
+ v3d->flag &= ~(V3D_LOCAL_COLLECTIONS | V3D_FLAG_UNUSED_1 | V3D_FLAG_UNUSED_10 |
V3D_FLAG_UNUSED_12);
v3d->flag2 &= ~(V3D_FLAG2_UNUSED_3 | V3D_FLAG2_UNUSED_6 | V3D_FLAG2_UNUSED_12 |
V3D_FLAG2_UNUSED_13 | V3D_FLAG2_UNUSED_14 | V3D_FLAG2_UNUSED_15);
@@ -3693,7 +3719,188 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 4)) {
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ bNodeTree *ntree = ntreeFromID(id);
+ if (ntree) {
+ ntree->id.flag |= LIB_PRIVATE_DATA;
+ }
+ }
+ FOREACH_MAIN_ID_END;
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 5)) {
+ for (Brush *br = bmain->brushes.first; br; br = br->id.next) {
+ if (br->ob_mode & OB_MODE_SCULPT && br->normal_radius_factor == 0.0f) {
+ br->normal_radius_factor = 0.5f;
+ }
+ }
+
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ /* Older files do not have a master collection, which is then added through
+ * `BKE_collection_master_add()`, so everything is fine. */
+ if (scene->master_collection != NULL) {
+ scene->master_collection->id.flag |= LIB_PRIVATE_DATA;
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 6)) {
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->shading.flag |= V3D_SHADING_SCENE_LIGHTS_RENDER | V3D_SHADING_SCENE_WORLD_RENDER;
+
+ /* files by default don't have studio lights selected unless interacted
+ * with the shading popover. When no studiolight could be read, we will
+ * select the default world one. */
+ StudioLight *studio_light = BKE_studiolight_find(v3d->shading.lookdev_light,
+ STUDIOLIGHT_TYPE_WORLD);
+ if (studio_light != NULL) {
+ STRNCPY(v3d->shading.lookdev_light, studio_light->name);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 9)) {
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = (SpaceFile *)sl;
+ ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ ARegion *ar_ui = do_versions_find_region(regionbase, RGN_TYPE_UI);
+ ARegion *ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER);
+ ARegion *ar_toolprops = do_versions_find_region_or_null(regionbase,
+ RGN_TYPE_TOOL_PROPS);
+
+ /* Reinsert UI region so that it spawns entire area width */
+ BLI_remlink(regionbase, ar_ui);
+ BLI_insertlinkafter(regionbase, ar_header, ar_ui);
+
+ ar_ui->flag |= RGN_FLAG_DYNAMIC_SIZE;
+
+ if (ar_toolprops && (ar_toolprops->alignment == (RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV))) {
+ SpaceType *stype = BKE_spacetype_from_id(sl->spacetype);
+
+ /* Remove empty region at old location. */
+ BLI_assert(sfile->op == NULL);
+ BKE_area_region_free(stype, ar_toolprops);
+ BLI_freelinkN(regionbase, ar_toolprops);
+ }
+
+ if (sfile->params) {
+ sfile->params->details_flags |= FILE_DETAILS_SIZE | FILE_DETAILS_DATETIME;
+ }
+ }
+ }
+ }
+ }
+
+ /* Convert the BONE_NO_SCALE flag to inherit_scale_mode enum. */
+ if (!DNA_struct_elem_find(fd->filesdna, "Bone", "char", "inherit_scale_mode")) {
+ LISTBASE_FOREACH (bArmature *, arm, &bmain->armatures) {
+ do_version_bones_inherit_scale(&arm->bonebase);
+ }
+ }
+
+ /* Convert the Offset flag to the mix mode enum. */
+ if (!DNA_struct_elem_find(fd->filesdna, "bRotateLikeConstraint", "char", "mix_mode")) {
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ do_version_constraints_copy_rotation_mix_mode(&ob->constraints);
+ if (ob->pose) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+ do_version_constraints_copy_rotation_mix_mode(&pchan->constraints);
+ }
+ }
+ }
+ }
+
+ /* Added studiolight intensity */
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "studiolight_intensity")) {
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->shading.studiolight_intensity = 1.0f;
+ }
+ }
+ }
+ }
+ }
+
+ /* Elatic deform brush */
+ for (Brush *br = bmain->brushes.first; br; br = br->id.next) {
+ if (br->ob_mode & OB_MODE_SCULPT && br->elastic_deform_volume_preservation == 0.0f) {
+ br->elastic_deform_volume_preservation = 0.5f;
+ }
+ }
+ }
+
{
/* Versioning code until next subversion bump goes here. */
+ if (!DNA_struct_elem_find(
+ fd->filesdna, "LayerCollection", "short", "local_collections_bits")) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ LISTBASE_FOREACH (LayerCollection *, layer_collection, &view_layer->layer_collections) {
+ do_versions_local_collection_bits_set(layer_collection);
+ }
+ }
+ }
+ }
+
+ /* Fix wrong 3D viewport copying causing corrupt pointers (T69974). */
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+
+ for (ScrArea *sa_other = screen->areabase.first; sa_other; sa_other = sa_other->next) {
+ for (SpaceLink *sl_other = sa_other->spacedata.first; sl_other;
+ sl_other = sl_other->next) {
+ if (sl != sl_other && sl_other->spacetype == SPACE_VIEW3D) {
+ View3D *v3d_other = (View3D *)sl_other;
+
+ if (v3d->shading.prop == v3d_other->shading.prop) {
+ v3d_other->shading.prop = NULL;
+ }
+ }
+ }
+ }
+ }
+ else if (sl->spacetype == SPACE_FILE) {
+ ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ ARegion *ar_tools = do_versions_find_region_or_null(regionbase, RGN_TYPE_TOOLS);
+ ARegion *ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER);
+
+ if (ar_tools) {
+ ARegion *ar_next = ar_tools->next;
+
+ /* We temporarily had two tools regions, get rid of the second one. */
+ if (ar_next && ar_next->regiontype == RGN_TYPE_TOOLS) {
+ do_versions_remove_region(regionbase, RGN_TYPE_TOOLS);
+ }
+
+ BLI_remlink(regionbase, ar_tools);
+ BLI_insertlinkafter(regionbase, ar_header, ar_tools);
+ }
+ else {
+ ar_tools = do_versions_add_region(RGN_TYPE_TOOLS, "versioning file tools region");
+ BLI_insertlinkafter(regionbase, ar_header, ar_tools);
+ ar_tools->alignment = RGN_ALIGN_LEFT;
+ }
+ }
+ }
+ }
+ }
}
}
diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c
index a3e9b8dc206..2c4ba4a1102 100644
--- a/source/blender/blenloader/intern/versioning_cycles.c
+++ b/source/blender/blenloader/intern/versioning_cycles.c
@@ -34,12 +34,16 @@
#include "DNA_node_types.h"
#include "DNA_particle_types.h"
#include "DNA_camera_types.h"
+#include "DNA_anim_types.h"
#include "BKE_colortools.h"
+#include "BKE_animsys.h"
#include "BKE_idprop.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "MEM_guardedalloc.h"
+
#include "IMB_colormanagement.h"
#include "BLO_readfile.h"
@@ -756,6 +760,424 @@ static void update_vector_math_node_average_operator(bNodeTree *ntree)
}
}
+/* The Noise node now have a dimension property. This property should be
+ * initialized to 3 by default.
+ */
+static void update_noise_node_dimensions(bNodeTree *ntree)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_NOISE) {
+ NodeTexNoise *tex = (NodeTexNoise *)node->storage;
+ tex->dimensions = 3;
+ }
+ }
+}
+
+/* The Mapping node has been rewritten to support dynamic inputs. Previously,
+ * the transformation information was stored in a TexMapping struct in the
+ * node->storage member of bNode. Currently, the transformation information
+ * is stored in input sockets. To correct this, we transfer the information
+ * from the TexMapping struct to the input sockets.
+ *
+ * Additionally, the Minimum and Maximum properties are no longer available
+ * in the node. To correct this, a Vector Minimum and/or a Vector Maximum
+ * nodes are added if needed.
+ *
+ * Finally, the TexMapping struct is freed and node->storage is set to NULL.
+ *
+ * Since the RNA paths of the properties changed, we also have to update the
+ * rna_path of the FCurves if they exist. To do that, we loop over FCurves
+ * and check if they control a property of the node, if they do, we update
+ * the path to be that of the corresponding socket in the node or the added
+ * minimum/maximum node.
+ *
+ */
+static void update_mapping_node_inputs_and_properties(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ /* If node->storage is NULL, then conversion has already taken place.
+ * This can happen if a file with the new mapping node [saved from (2, 81, 8) or newer]
+ * is opened in a blender version prior to (2, 81, 8) and saved from there again. */
+ if (node->type == SH_NODE_MAPPING && node->storage) {
+ TexMapping *mapping = (TexMapping *)node->storage;
+ node->custom1 = mapping->type;
+ node->width = 140.0f;
+
+ bNodeSocket *sockLocation = nodeFindSocket(node, SOCK_IN, "Location");
+ copy_v3_v3(cycles_node_socket_vector_value(sockLocation), mapping->loc);
+ bNodeSocket *sockRotation = nodeFindSocket(node, SOCK_IN, "Rotation");
+ copy_v3_v3(cycles_node_socket_vector_value(sockRotation), mapping->rot);
+ bNodeSocket *sockScale = nodeFindSocket(node, SOCK_IN, "Scale");
+ copy_v3_v3(cycles_node_socket_vector_value(sockScale), mapping->size);
+
+ bNode *maximumNode = NULL;
+ if (mapping->flag & TEXMAP_CLIP_MIN) {
+ maximumNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+ maximumNode->custom1 = NODE_VECTOR_MATH_MAXIMUM;
+ if (mapping->flag & TEXMAP_CLIP_MAX) {
+ maximumNode->locx = node->locx + (node->width + 20.0f) * 2.0f;
+ }
+ else {
+ maximumNode->locx = node->locx + node->width + 20.0f;
+ }
+ maximumNode->locy = node->locy;
+ bNodeSocket *sockMaximumB = BLI_findlink(&maximumNode->inputs, 1);
+ copy_v3_v3(cycles_node_socket_vector_value(sockMaximumB), mapping->min);
+ bNodeSocket *sockMappingResult = nodeFindSocket(node, SOCK_OUT, "Vector");
+
+ LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+ if (link->fromsock == sockMappingResult) {
+ bNodeSocket *sockMaximumResult = nodeFindSocket(maximumNode, SOCK_OUT, "Vector");
+ nodeAddLink(ntree, maximumNode, sockMaximumResult, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ }
+ }
+ if (!(mapping->flag & TEXMAP_CLIP_MAX)) {
+ bNodeSocket *sockMaximumA = BLI_findlink(&maximumNode->inputs, 0);
+ nodeAddLink(ntree, node, sockMappingResult, maximumNode, sockMaximumA);
+ }
+
+ need_update = true;
+ }
+
+ bNode *minimumNode = NULL;
+ if (mapping->flag & TEXMAP_CLIP_MAX) {
+ minimumNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+ minimumNode->custom1 = NODE_VECTOR_MATH_MINIMUM;
+ minimumNode->locx = node->locx + node->width + 20.0f;
+ minimumNode->locy = node->locy;
+ bNodeSocket *sockMinimumB = BLI_findlink(&minimumNode->inputs, 1);
+ copy_v3_v3(cycles_node_socket_vector_value(sockMinimumB), mapping->max);
+
+ bNodeSocket *sockMinimumResult = nodeFindSocket(minimumNode, SOCK_OUT, "Vector");
+ bNodeSocket *sockMappingResult = nodeFindSocket(node, SOCK_OUT, "Vector");
+
+ if (maximumNode) {
+ bNodeSocket *sockMaximumA = BLI_findlink(&maximumNode->inputs, 0);
+ nodeAddLink(ntree, minimumNode, sockMinimumResult, maximumNode, sockMaximumA);
+ }
+ else {
+ LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+ if (link->fromsock == sockMappingResult) {
+ nodeAddLink(ntree, minimumNode, sockMinimumResult, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ }
+ }
+ }
+ bNodeSocket *sockMinimumA = BLI_findlink(&minimumNode->inputs, 0);
+ nodeAddLink(ntree, node, sockMappingResult, minimumNode, sockMinimumA);
+
+ need_update = true;
+ }
+
+ MEM_freeN(node->storage);
+ node->storage = NULL;
+
+ AnimData *animData = BKE_animdata_from_id(&ntree->id);
+ if (animData && animData->action) {
+ char *nodePath = BLI_sprintfN("nodes[\"%s\"]", node->name);
+ for (FCurve *fcu = animData->action->curves.first; fcu; fcu = fcu->next) {
+ if (STRPREFIX(fcu->rna_path, nodePath) &&
+ !BLI_str_endswith(fcu->rna_path, "default_value")) {
+ char *old_fcu_rna_path = fcu->rna_path;
+
+ if (BLI_str_endswith(old_fcu_rna_path, "translation")) {
+ fcu->rna_path = BLI_sprintfN("%s.%s", nodePath, "inputs[1].default_value");
+ }
+ else if (BLI_str_endswith(old_fcu_rna_path, "rotation")) {
+ fcu->rna_path = BLI_sprintfN("%s.%s", nodePath, "inputs[2].default_value");
+ }
+ else if (BLI_str_endswith(old_fcu_rna_path, "scale")) {
+ fcu->rna_path = BLI_sprintfN("%s.%s", nodePath, "inputs[3].default_value");
+ }
+ else if (minimumNode && BLI_str_endswith(old_fcu_rna_path, "max")) {
+ fcu->rna_path = BLI_sprintfN(
+ "nodes[\"%s\"].%s", minimumNode->name, "inputs[1].default_value");
+ }
+ else if (maximumNode && BLI_str_endswith(old_fcu_rna_path, "min")) {
+ fcu->rna_path = BLI_sprintfN(
+ "nodes[\"%s\"].%s", maximumNode->name, "inputs[1].default_value");
+ }
+
+ if (fcu->rna_path != old_fcu_rna_path) {
+ MEM_freeN(old_fcu_rna_path);
+ }
+ }
+ }
+
+ MEM_freeN(nodePath);
+ }
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
+/* The Musgrave node now has a dimension property. This property should
+ * be initialized to 3 by default.
+ */
+static void update_musgrave_node_dimensions(bNodeTree *ntree)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_MUSGRAVE) {
+ NodeTexMusgrave *tex = (NodeTexMusgrave *)node->storage;
+ tex->dimensions = 3;
+ }
+ }
+}
+
+/* The Color output of the Musgrave node has been removed. Previously, this
+ * output was just equal to the Fac output. To correct this, we move links
+ * from the Color output to the Fac output if they exist.
+ */
+static void update_musgrave_node_color_output(bNodeTree *ntree)
+{
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ if (link->fromnode && link->fromnode->type == SH_NODE_TEX_MUSGRAVE) {
+ if (link->fromsock->type == SOCK_RGBA) {
+ link->fromsock = link->fromsock->next;
+ }
+ }
+ }
+}
+
+/* The Voronoi node now have a dimension property. This property should be
+ * initialized to 3 by default.
+ */
+static void update_voronoi_node_dimensions(bNodeTree *ntree)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_VORONOI) {
+ NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
+ tex->dimensions = 3;
+ }
+ }
+}
+
+/* The F3 and F4 features of the Voronoi node have been removed.
+ * To correct this, we set the feature type to be F2 if it is F3
+ * or F4. The SHD_VORONOI_F3 and SHD_VORONOI_F4 enum values were
+ * 2 and 3 respectively.
+ */
+static void update_voronoi_node_f3_and_f4(bNodeTree *ntree)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_VORONOI) {
+ NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
+ if (ELEM(tex->feature, 2, 3)) {
+ tex->feature = SHD_VORONOI_F2;
+ }
+ }
+ }
+}
+
+/* The Fac output of the Voronoi node has been removed. Previously, this
+ * output was the voronoi distance in the Intensity mode and the Cell ID
+ * in the Cell mode. To correct this, we update the identifier and name
+ * of the Fac socket such that it gets mapped to the Distance socket.
+ * This is supposed to work with update_voronoi_node_coloring.
+ */
+static void update_voronoi_node_fac_output(bNodeTree *ntree)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_VORONOI) {
+ bNodeSocket *facOutput = BLI_findlink(&node->outputs, 1);
+ strcpy(facOutput->identifier, "Distance");
+ strcpy(facOutput->name, "Distance");
+ }
+ }
+}
+
+/* The Crackle feature of the Voronoi node has been removed. Previously,
+ * this feature returned the F2 distance minus the F1 distance. The
+ * crackle feature had an enum value of 4. To fix this we do the
+ * following:
+ *
+ * 1. The node feature is set to F1.
+ * 2. A new Voronoi node is added and its feature is set to F2.
+ * 3. The properties, input values, and connections are copied
+ * from the node to the new Voronoi node so that they match
+ * exactly.
+ * 4. A Subtract node is added.
+ * 5. The outputs of the F1 and F2 voronoi are connected to
+ * the inputs of the subtract node.
+ * 6. The output of the subtract node is connected to the
+ * appropriate sockets.
+ *
+ */
+static void update_voronoi_node_crackle(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_VORONOI) {
+ NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
+ bNodeSocket *sockDistance = nodeFindSocket(node, SOCK_OUT, "Distance");
+ bNodeSocket *sockColor = nodeFindSocket(node, SOCK_OUT, "Color");
+ if (tex->feature == 4 && (socket_is_used(sockDistance) || socket_is_used(sockColor))) {
+ tex->feature = SHD_VORONOI_F1;
+
+ bNode *voronoiNode = nodeAddStaticNode(NULL, ntree, SH_NODE_TEX_VORONOI);
+ NodeTexVoronoi *texVoronoi = (NodeTexVoronoi *)voronoiNode->storage;
+ texVoronoi->feature = SHD_VORONOI_F2;
+ texVoronoi->distance = tex->distance;
+ texVoronoi->dimensions = 3;
+ voronoiNode->locx = node->locx + node->width + 20.0f;
+ voronoiNode->locy = node->locy;
+
+ bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector");
+ bNodeSocket *sockScale = nodeFindSocket(node, SOCK_IN, "Scale");
+ bNodeSocket *sockExponent = nodeFindSocket(node, SOCK_IN, "Exponent");
+ bNodeSocket *sockVoronoiVector = nodeFindSocket(voronoiNode, SOCK_IN, "Vector");
+ bNodeSocket *sockVoronoiScale = nodeFindSocket(voronoiNode, SOCK_IN, "Scale");
+ bNodeSocket *sockVoronoiExponent = nodeFindSocket(voronoiNode, SOCK_IN, "Exponent");
+ if (sockVector->link) {
+ nodeAddLink(ntree,
+ sockVector->link->fromnode,
+ sockVector->link->fromsock,
+ voronoiNode,
+ sockVoronoiVector);
+ }
+ *cycles_node_socket_float_value(sockVoronoiScale) = *cycles_node_socket_float_value(
+ sockScale);
+ if (sockScale->link) {
+ nodeAddLink(ntree,
+ sockScale->link->fromnode,
+ sockScale->link->fromsock,
+ voronoiNode,
+ sockVoronoiScale);
+ }
+ *cycles_node_socket_float_value(sockVoronoiExponent) = *cycles_node_socket_float_value(
+ sockExponent);
+ if (sockExponent->link) {
+ nodeAddLink(ntree,
+ sockExponent->link->fromnode,
+ sockExponent->link->fromsock,
+ voronoiNode,
+ sockVoronoiExponent);
+ }
+
+ bNode *subtractNode = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH);
+ subtractNode->custom1 = NODE_MATH_SUBTRACT;
+ subtractNode->locx = voronoiNode->locx + voronoiNode->width + 20.0f;
+ subtractNode->locy = voronoiNode->locy;
+ bNodeSocket *sockSubtractOutValue = nodeFindSocket(subtractNode, SOCK_OUT, "Value");
+
+ LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+ if (link->fromnode == node) {
+ nodeAddLink(ntree, subtractNode, sockSubtractOutValue, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ }
+ }
+
+ bNodeSocket *sockDistanceF1 = nodeFindSocket(node, SOCK_OUT, "Distance");
+ bNodeSocket *sockDistanceF2 = nodeFindSocket(voronoiNode, SOCK_OUT, "Distance");
+ bNodeSocket *sockSubtractA = BLI_findlink(&subtractNode->inputs, 0);
+ bNodeSocket *sockSubtractB = BLI_findlink(&subtractNode->inputs, 1);
+
+ nodeAddLink(ntree, node, sockDistanceF1, subtractNode, sockSubtractB);
+ nodeAddLink(ntree, voronoiNode, sockDistanceF2, subtractNode, sockSubtractA);
+
+ need_update = true;
+ }
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
+/**
+ * The coloring property of the Voronoi node was removed. Previously,
+ * if the coloring enum was set to Intensity (0), the voronoi distance
+ * was returned in all outputs, otherwise, the Cell ID was returned.
+ * Since we remapped the Fac output in update_voronoi_node_fac_output,
+ * then to fix this, we relink the Color output to the Distance
+ * output if coloring was set to 0, and the other way around otherwise.
+ */
+static void update_voronoi_node_coloring(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+ bNode *node = link->fromnode;
+ if (node && node->type == SH_NODE_TEX_VORONOI) {
+ NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
+ if (tex->coloring == 0) {
+ bNodeSocket *sockColor = nodeFindSocket(node, SOCK_OUT, "Color");
+ if (link->fromsock == sockColor) {
+ bNodeSocket *sockDistance = nodeFindSocket(node, SOCK_OUT, "Distance");
+ nodeAddLink(ntree, node, sockDistance, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ need_update = true;
+ }
+ }
+ else {
+ bNodeSocket *sockDistance = nodeFindSocket(node, SOCK_OUT, "Distance");
+ if (link->fromsock == sockDistance) {
+ bNodeSocket *sockColor = nodeFindSocket(node, SOCK_OUT, "Color");
+ nodeAddLink(ntree, node, sockColor, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ need_update = true;
+ }
+ }
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
+/* Previously, the output euclidean distance was actually the squared
+ * euclidean distance. To fix this, we square the the output distance
+ * socket if the distance metric is set to SHD_VORONOI_EUCLIDEAN.
+ */
+static void update_voronoi_node_square_distance(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_VORONOI) {
+ NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
+ bNodeSocket *sockDistance = nodeFindSocket(node, SOCK_OUT, "Distance");
+ if (tex->distance == SHD_VORONOI_EUCLIDEAN &&
+ (tex->feature == SHD_VORONOI_F1 || tex->feature == SHD_VORONOI_F2) &&
+ socket_is_used(sockDistance)) {
+ bNode *multiplyNode = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH);
+ multiplyNode->custom1 = NODE_MATH_MULTIPLY;
+ multiplyNode->locx = node->locx + node->width + 20.0f;
+ multiplyNode->locy = node->locy;
+
+ bNodeSocket *sockValue = nodeFindSocket(multiplyNode, SOCK_OUT, "Value");
+ LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+ if (link->fromsock == sockDistance) {
+ nodeAddLink(ntree, multiplyNode, sockValue, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ }
+ }
+
+ bNodeSocket *sockMultiplyA = BLI_findlink(&multiplyNode->inputs, 0);
+ bNodeSocket *sockMultiplyB = BLI_findlink(&multiplyNode->inputs, 1);
+
+ nodeAddLink(ntree, node, sockDistance, multiplyNode, sockMultiplyA);
+ nodeAddLink(ntree, node, sockDistance, multiplyNode, sockMultiplyB);
+
+ need_update = true;
+ }
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bmain)
{
/* Particle shape shared with Eevee. */
@@ -797,6 +1219,25 @@ void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bm
}
FOREACH_NODETREE_END;
}
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 10)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ update_musgrave_node_color_output(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 11)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ update_voronoi_node_f3_and_f4(ntree);
+ update_voronoi_node_fac_output(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
}
void do_versions_after_linking_cycles(Main *bmain)
@@ -928,4 +1369,43 @@ void do_versions_after_linking_cycles(Main *bmain)
}
FOREACH_NODETREE_END;
}
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 7)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ update_noise_node_dimensions(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 8)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ update_mapping_node_inputs_and_properties(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 10)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ update_musgrave_node_dimensions(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 11)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ update_voronoi_node_dimensions(ntree);
+ update_voronoi_node_crackle(ntree);
+ update_voronoi_node_coloring(ntree);
+ update_voronoi_node_square_distance(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index fa69892584a..c9fb8b6990b 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -38,13 +38,16 @@
#include "DNA_workspace_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_light_types.h"
#include "BKE_appdir.h"
+#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_paint.h"
#include "BKE_screen.h"
#include "BKE_workspace.h"
@@ -195,18 +198,13 @@ static void blo_update_defaults_screen(bScreen *screen,
}
}
- /* Show toopbar for sculpt/paint modes. */
- const bool show_tool_header = STR_ELEM(
- workspace_name, "Sculpting", "Texture Paint", "2D Animation", "2D Full Canvas");
-
- if (show_tool_header) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
- ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
- for (ARegion *ar = regionbase->first; ar; ar = ar->next) {
- if (ar->regiontype == RGN_TYPE_TOOL_HEADER) {
- ar->flag &= ~(RGN_FLAG_HIDDEN | RGN_FLAG_HIDDEN_BY_USER);
- }
+ /* Show top-bar by default. */
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ for (ARegion *ar = regionbase->first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_TOOL_HEADER) {
+ ar->flag &= ~(RGN_FLAG_HIDDEN | RGN_FLAG_HIDDEN_BY_USER);
}
}
}
@@ -265,6 +263,9 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
/* Change default cubemap quality. */
scene->eevee.gi_filter_quality = 3.0f;
+ /* Enable Soft Shadows by default. */
+ scene->eevee.flag |= SCE_EEVEE_SHADOW_SOFT;
+
/* Be sure curfalloff and primitive are initializated */
ToolSettings *ts = scene->toolsettings;
if (ts->gp_sculpt.cur_falloff == NULL) {
@@ -286,6 +287,10 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
CURVEMAP_SLOPE_POSITIVE);
}
+ if (ts->sculpt) {
+ ts->sculpt->paint.symmetry_flags |= PAINT_SYMMETRY_FEATHER;
+ }
+
/* Correct default startup UV's. */
Mesh *me = BLI_findstring(&bmain->meshes, "Cube", offsetof(ID, name) + 2);
if (me && (me->totloop == 24) && (me->mloopuv != NULL)) {
@@ -329,6 +334,14 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
BLI_strncpy(screen->id.name + 2, workspace->id.name + 2, sizeof(screen->id.name) - 2);
BLI_libblock_ensure_unique_name(bmain, screen->id.name);
}
+
+ /* For some reason we have unused screens, needed until re-saving.
+ * Clear unused layouts because they're visible in the outliner & Python API. */
+ LISTBASE_FOREACH_MUTABLE (WorkSpaceLayout *, layout_iter, &workspace->layouts) {
+ if (layout != layout_iter) {
+ BKE_workspace_layout_remove(bmain, workspace, layout_iter);
+ }
+ }
}
/* Scenes */
@@ -345,6 +358,12 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
scene->audio.flag &= ~AUDIO_SYNC;
scene->flag &= ~SCE_FRAME_DROP;
}
+
+ /* Change default selection mode for Grease Pencil. */
+ if (app_template && STREQ(app_template, "2D_Animation")) {
+ ToolSettings *ts = scene->toolsettings;
+ ts->gpencil_selectmode_edit = GP_SELECTMODE_STROKE;
+ }
}
/* Objects */
@@ -400,7 +419,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
{
/* Enable for UV sculpt (other brush types will be created as needed),
* without this the grab brush will be active but not selectable from the list. */
- Brush *brush = BLI_findstring(&bmain->brushes, "Grab", offsetof(ID, name) + 2);
+ const char *brush_name = "Grab";
+ Brush *brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
if (brush) {
brush->ob_mode |= OB_MODE_EDIT;
}
@@ -408,13 +428,103 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) {
brush->blur_kernel_radius = 2;
+
+ /* Use full strength for all non-sculpt brushes,
+ * when painting we want to use full color/weight always.
+ *
+ * Note that sculpt is an exception,
+ * it's values are overwritten by #BKE_brush_sculpt_reset below. */
+ brush->alpha = 1.0;
}
{
/* Change the spacing of the Smear brush to 3.0% */
- Brush *brush = BLI_findstring(&bmain->brushes, "Smear", offsetof(ID, name) + 2);
+ const char *brush_name;
+ Brush *brush;
+
+ brush_name = "Smear";
+ brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
if (brush) {
brush->spacing = 3.0;
}
+
+ brush_name = "Draw Sharp";
+ brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ if (!brush) {
+ brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
+ id_us_min(&brush->id);
+ brush->sculpt_tool = SCULPT_TOOL_DRAW_SHARP;
+ }
+
+ brush_name = "Elastic Deform";
+ brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ if (!brush) {
+ brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
+ id_us_min(&brush->id);
+ brush->sculpt_tool = SCULPT_TOOL_ELASTIC_DEFORM;
+ }
+
+ brush_name = "Pose";
+ brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ if (!brush) {
+ brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
+ id_us_min(&brush->id);
+ brush->sculpt_tool = SCULPT_TOOL_POSE;
+ }
+
+ brush_name = "Simplify";
+ brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ if (!brush) {
+ brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
+ id_us_min(&brush->id);
+ brush->sculpt_tool = SCULPT_TOOL_SIMPLIFY;
+ }
+
+ /* Use the same tool icon color in the brush cursor */
+ for (brush = bmain->brushes.first; brush; brush = brush->id.next) {
+ if (brush->ob_mode & OB_MODE_SCULPT) {
+ BLI_assert(brush->sculpt_tool != 0);
+ BKE_brush_sculpt_reset(brush);
+ }
+ }
+ }
+
+ if (app_template && STREQ(app_template, "2D_Animation")) {
+ /* Update Grease Pencil brushes. */
+ Brush *brush;
+
+ /* Pencil brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Pencil", "Pencil");
+
+ /* Pen brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Pen", "Pen");
+
+ /* Pen Soft brush. */
+ brush = (Brush *)rename_id_for_versioning(bmain, ID_BR, "Draw Soft", "Pencil Soft");
+ if (brush) {
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
+ }
+
+ /* Ink Pen brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Ink", "Ink Pen");
+
+ /* Ink Pen Rough brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Noise", "Ink Pen Rough");
+
+ /* Marker Bold brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Marker", "Marker Bold");
+
+ /* Marker Chisel brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Block", "Marker Chisel");
+
+ /* Remove useless Fill Area.001 brush. */
+ brush = BLI_findstring(&bmain->brushes, "Fill Area.001", offsetof(ID, name) + 2);
+ if (brush) {
+ BKE_id_delete(bmain, brush);
+ }
+
+ /* Reset all grease pencil brushes. */
+ Scene *scene = bmain->scenes.first;
+ BKE_brush_gpencil_presets(bmain, scene->toolsettings);
}
}
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index 9b6f252f62d..62bd605a2c2 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -71,14 +71,12 @@
#include "BKE_constraint.h"
#include "BKE_deform.h"
#include "BKE_fcurve.h"
-#include "BKE_image.h"
#include "BKE_lattice.h"
#include "BKE_main.h" // for Main
#include "BKE_mesh.h" // for ME_ defines (patching)
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
-#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "NOD_socket.h"
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index 8bbfc29131e..bbae1c8e85e 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -29,10 +29,10 @@
#include "DNA_curve_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
#include "BKE_addon.h"
#include "BKE_colorband.h"
-#include "BKE_idprop.h"
#include "BKE_main.h"
#include "BKE_keyconfig.h"
@@ -150,6 +150,10 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
* Include next version bump.
*/
{
+ FROM_DEFAULT_V4_UCHAR(space_file.execution_buts);
+ FROM_DEFAULT_V4_UCHAR(tui.icon_folder);
+ FROM_DEFAULT_V4_UCHAR(space_clip.path_keyframe_before);
+ FROM_DEFAULT_V4_UCHAR(space_clip.path_keyframe_after);
}
#undef FROM_DEFAULT_V4_UCHAR
@@ -609,11 +613,25 @@ void BLO_version_defaults_userpref_blend(Main *bmain, UserDef *userdef)
userdef->drag_threshold_tablet = 10;
}
+ if (!USER_VERSION_ATLEAST(281, 9)) {
+ /* X3D is no longer enabled by default. */
+ BKE_addon_remove_safe(&userdef->addons, "io_scene_x3d");
+ }
+
+ if (!USER_VERSION_ATLEAST(281, 12)) {
+ userdef->render_display_type = USER_RENDER_DISPLAY_WINDOW;
+ userdef->filebrowser_display_type = USER_TEMP_SPACE_DISPLAY_WINDOW;
+ }
+
/**
* Include next version bump.
*/
{
/* pass */
+ if (userdef->file_space_data.display_type == FILE_DEFAULTDISPLAY) {
+ memcpy(
+ &userdef->file_space_data, &U_default.file_space_data, sizeof(userdef->file_space_data));
+ }
}
if (userdef->pixelsize == 0.0f) {
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 0ff7ba0034f..aae5072c8de 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -157,7 +157,6 @@
#include "BKE_layer.h"
#include "BKE_library_override.h"
#include "BKE_main.h"
-#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
#include "BKE_pointcache.h"
@@ -2014,7 +2013,7 @@ static void write_mdisps(WriteData *wd, int count, MDisps *mdlist, int external)
int i;
writestruct(wd, DATA, MDisps, count, mdlist);
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
MDisps *md = &mdlist[i];
if (md->disps) {
if (!external) {
@@ -2035,7 +2034,7 @@ static void write_grid_paint_mask(WriteData *wd, int count, GridPaintMask *grid_
int i;
writestruct(wd, DATA, GridPaintMask, count, grid_paint_mask);
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
GridPaintMask *gpm = &grid_paint_mask[i];
if (gpm->data) {
const int gridsize = BKE_ccg_gridsize(gpm->level);
@@ -2413,6 +2412,13 @@ static void write_view_settings(WriteData *wd, ColorManagedViewSettings *view_se
}
}
+static void write_view3dshading(WriteData *wd, View3DShading *shading)
+{
+ if (shading->prop) {
+ IDP_WriteProperty(shading->prop, wd);
+ }
+}
+
static void write_paint(WriteData *wd, Paint *p)
{
if (p->cavity_curve) {
@@ -2471,7 +2477,7 @@ static void write_lightcache(WriteData *wd, LightCache *cache)
if (cache->cube_mips) {
writestruct(wd, DATA, LightCacheTexture, cache->mips_len, cache->cube_mips);
- for (int i = 0; i < cache->mips_len; ++i) {
+ for (int i = 0; i < cache->mips_len; i++) {
write_lightcache_texture(wd, &cache->cube_mips[i]);
}
}
@@ -2684,6 +2690,8 @@ static void write_scene(WriteData *wd, Scene *sce)
write_lightcache(wd, sce->eevee.light_cache);
}
+ write_view3dshading(wd, &sce->display.shading);
+
/* Freed on doversion. */
BLI_assert(sce->layer_properties == NULL);
}
@@ -2850,6 +2858,7 @@ static void write_area_regions(WriteData *wd, ScrArea *area)
if (v3d->fx_settings.dof) {
writestruct(wd, DATA, GPUDOFSettings, 1, v3d->fx_settings.dof);
}
+ write_view3dshading(wd, &v3d->shading);
}
else if (sl->spacetype == SPACE_GRAPH) {
SpaceGraph *sipo = (SpaceGraph *)sl;
@@ -3627,7 +3636,9 @@ static void write_libraries(WriteData *wd, Main *main)
found_one = false;
while (!found_one && tot--) {
for (id = lbarray[tot]->first; id; id = id->next) {
- if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) {
+ if (id->us > 0 &&
+ ((id->tag & LIB_TAG_EXTERN) ||
+ ((id->tag & LIB_TAG_INDIRECT) && (id->flag & LIB_INDIRECT_WEAK_LINK)))) {
found_one = true;
break;
}
@@ -3657,7 +3668,9 @@ static void write_libraries(WriteData *wd, Main *main)
/* Write link placeholders for all direct linked IDs. */
while (a--) {
for (id = lbarray[a]->first; id; id = id->next) {
- if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) {
+ if (id->us > 0 &&
+ ((id->tag & LIB_TAG_EXTERN) ||
+ ((id->tag & LIB_TAG_INDIRECT) && (id->flag & LIB_INDIRECT_WEAK_LINK)))) {
if (!BKE_idcode_is_linkable(GS(id->name))) {
printf(
"ERROR: write file: data-block '%s' from lib '%s' is not linkable "
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index f5095ca2b5f..599871a505a 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -143,6 +143,8 @@ set(SRC
tools/bmesh_edgesplit.h
tools/bmesh_intersect.c
tools/bmesh_intersect.h
+ tools/bmesh_intersect_edges.c
+ tools/bmesh_intersect_edges.h
tools/bmesh_path.c
tools/bmesh_path.h
tools/bmesh_path_region.c
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
index 48d6bcd7b03..27c03f0a84f 100644
--- a/source/blender/bmesh/intern/bmesh_interp.c
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -330,9 +330,9 @@ static bool quad_co(const float v1[3],
}
static void mdisp_axis_from_quad(float v1[3],
- float v2[3],
+ const float v2[3],
float UNUSED(v3[3]),
- float v4[3],
+ const float v4[3],
float r_axis_x[3],
float r_axis_y[3])
{
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index 788edc348d9..58a7d423d67 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -1026,8 +1026,8 @@ bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
ese->next = ese->prev = NULL;
if (ese_last) {
- if (ese_last->htype ==
- BM_FACE) { /* if there is an active face, use it over the last selected face */
+ /* If there is an active face, use it over the last selected face. */
+ if (ese_last->htype == BM_FACE) {
if (efa) {
ese->ele = (BMElem *)efa;
}
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index b9f0bcc05f0..7086cea1ace 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -369,28 +369,6 @@ static BMOpDefine bmo_remove_doubles_def = {
};
/*
- * Auto Merge.
- *
- * Finds groups of vertices closer then **dist** and merges them together,
- * using the weld verts bmop. The merges must go from a vert not in
- * **verts** to one in **verts**.
- */
-static BMOpDefine bmo_automerge_def = {
- "automerge",
- /* slots_in */
- {{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* input verts */
- {"dist", BMO_OP_SLOT_FLT}, /* maximum distance */
- {{'\0'}},
- },
- {{{'\0'}}}, /* no output */
- bmo_automerge_exec,
- (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
- BMO_OPTYPE_FLAG_NORMALS_CALC |
- BMO_OPTYPE_FLAG_SELECT_FLUSH |
- BMO_OPTYPE_FLAG_SELECT_VALIDATE),
-};
-
-/*
* Collapse Connected.
*
* Collapses connected vertices
@@ -2073,7 +2051,6 @@ static BMOpDefine bmo_symmetrize_def = {
/* clang-format on */
const BMOpDefine *bmo_opdefines[] = {
- &bmo_automerge_def,
&bmo_average_vert_facedata_def,
&bmo_beautify_fill_def,
&bmo_bevel_def,
diff --git a/source/blender/bmesh/intern/bmesh_operators_private.h b/source/blender/bmesh/intern/bmesh_operators_private.h
index 8658f6c233c..137c5aa338e 100644
--- a/source/blender/bmesh/intern/bmesh_operators_private.h
+++ b/source/blender/bmesh/intern/bmesh_operators_private.h
@@ -24,7 +24,6 @@
struct BMOperator;
struct BMesh;
-void bmo_automerge_exec(BMesh *bm, BMOperator *op);
void bmo_average_vert_facedata_exec(BMesh *bm, BMOperator *op);
void bmo_beautify_fill_exec(BMesh *bm, BMOperator *op);
void bmo_bevel_exec(BMesh *bm, BMOperator *op);
diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
index 83ac7df058a..374c912e3f5 100644
--- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
+++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
@@ -94,7 +94,7 @@ static BMLoop *bm_edge_flagged_radial_first(BMEdge *e)
}
static void normalize_v2_m3_v3v3(float out[2],
- float axis_mat[3][3],
+ const float axis_mat[3][3],
const float v1[3],
const float v2[3])
{
@@ -110,7 +110,7 @@ static void normalize_v2_m3_v3v3(float out[2],
*/
static bool bm_face_split_edgenet_find_loop_pair(BMVert *v_init,
const float face_normal[3],
- float face_normal_matrix[3][3],
+ const float face_normal_matrix[3][3],
BMEdge *e_pair[2])
{
/* Always find one boundary edge (to determine winding)
@@ -420,7 +420,7 @@ finally:
static bool bm_face_split_edgenet_find_loop(BMVert *v_init,
const float face_normal[3],
- float face_normal_matrix[3][3],
+ const float face_normal_matrix[3][3],
/* cache to avoid realloc every time */
struct VertOrder *edge_order,
const uint edge_order_len,
diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c
index 51bc86e40eb..219bec15e5b 100644
--- a/source/blender/bmesh/intern/bmesh_query.c
+++ b/source/blender/bmesh/intern/bmesh_query.c
@@ -207,6 +207,34 @@ bool BM_vert_pair_share_face_check_cb(BMVert *v_a,
return false;
}
+BMFace *BM_vert_pair_shared_face_cb(BMVert *v_a,
+ BMVert *v_b,
+ const bool allow_adjacent,
+ bool (*callback)(BMFace *, BMLoop *, BMLoop *, void *userdata),
+ void *user_data,
+ BMLoop **r_l_a,
+ BMLoop **r_l_b)
+{
+ if (v_a->e && v_b->e) {
+ BMIter iter;
+ BMLoop *l_a, *l_b;
+
+ BM_ITER_ELEM (l_a, &iter, v_a, BM_LOOPS_OF_VERT) {
+ BMFace *f = l_a->f;
+ l_b = BM_face_vert_share_loop(f, v_b);
+ if (l_b && (allow_adjacent || !BM_loop_is_adjacent(l_a, l_b)) &&
+ callback(f, l_a, l_b, user_data)) {
+ *r_l_a = l_a;
+ *r_l_b = l_b;
+
+ return f;
+ }
+ }
+ }
+
+ return NULL;
+}
+
/**
* Given 2 verts, find the smallest face they share and give back both loops.
*/
diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h
index e96984490c0..3a864fbb5dd 100644
--- a/source/blender/bmesh/intern/bmesh_query.h
+++ b/source/blender/bmesh/intern/bmesh_query.h
@@ -62,6 +62,13 @@ bool BM_vert_pair_share_face_check_cb(BMVert *v_a,
bool (*test_fn)(BMFace *f, void *user_data),
void *user_data) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2, 3);
+BMFace *BM_vert_pair_shared_face_cb(BMVert *v_a,
+ BMVert *v_b,
+ const bool allow_adjacent,
+ bool (*callback)(BMFace *, BMLoop *, BMLoop *, void *userdata),
+ void *user_data,
+ BMLoop **r_l_a,
+ BMLoop **r_l_b) ATTR_NONNULL(1, 2, 4, 6, 7);
BMFace *BM_vert_pair_share_face_by_len(BMVert *v_a,
BMVert *v_b,
BMLoop **r_l_a,
diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c
index 5403043efb4..bad5036f6cf 100644
--- a/source/blender/bmesh/operators/bmo_bridge.c
+++ b/source/blender/bmesh/operators/bmo_bridge.c
@@ -400,7 +400,7 @@ static void bridge_loop_pair(BMesh *bm,
f_example = l_a ? l_a->f : (l_b ? l_b->f : NULL);
if (v_b != v_b_next) {
- BMVert *v_arr[4] = {v_a, v_b, v_b_next, v_a_next};
+ BMVert *v_arr[4] = {v_b, v_b_next, v_a_next, v_a};
f = BM_face_exists(v_arr, 4);
if (f == NULL) {
/* copy if loop data if its is missing on one ring */
@@ -425,7 +425,7 @@ static void bridge_loop_pair(BMesh *bm,
}
}
else {
- BMVert *v_arr[3] = {v_a, v_b, v_a_next};
+ BMVert *v_arr[3] = {v_b, v_a_next, v_a};
f = BM_face_exists(v_arr, 3);
if (f == NULL) {
/* fan-fill a triangle */
diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c
index f23c420295b..1570c802bee 100644
--- a/source/blender/bmesh/operators/bmo_inset.c
+++ b/source/blender/bmesh/operators/bmo_inset.c
@@ -588,7 +588,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
/* tag if boundary is enabled */
(use_boundary && BM_edge_is_boundary(e) && BM_elem_flag_test(e->l->f, BM_ELEM_TAG)) ||
- /* tag if edge is an interior edge inbetween a tagged and untagged face */
+ /* tag if edge is an interior edge in between a tagged and untagged face */
(bm_edge_is_mixed_face_tag(e->l))) {
/* tag */
BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c
index d783842c017..1d28d8223cd 100644
--- a/source/blender/bmesh/operators/bmo_removedoubles.c
+++ b/source/blender/bmesh/operators/bmo_removedoubles.c
@@ -706,34 +706,3 @@ void bmo_find_doubles_exec(BMesh *bm, BMOperator *op)
slot_targetmap_out = BMO_slot_get(op->slots_out, "targetmap.out");
bmesh_find_doubles_common(bm, op, op, slot_targetmap_out);
}
-
-void bmo_automerge_exec(BMesh *bm, BMOperator *op)
-{
- BMOperator findop, weldop;
- BMIter viter;
- BMVert *v;
-
- /* The "verts" input sent to this op is the set of verts that
- * can be merged away into any other verts. Mark all other verts
- * as VERT_KEEP. */
- BMO_slot_buffer_flag_enable(bm, op->slots_in, "verts", BM_VERT, VERT_IN);
- BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
- if (!BMO_vert_flag_test(bm, v, VERT_IN)) {
- BMO_vert_flag_enable(bm, v, VERT_KEEP);
- }
- }
-
- /* Search for doubles among all vertices, but only merge non-VERT_KEEP
- * vertices into VERT_KEEP vertices. */
- BMO_op_initf(bm, &findop, op->flag, "find_doubles verts=%av keep_verts=%fv", VERT_KEEP);
- BMO_slot_copy(op, slots_in, "dist", &findop, slots_in, "dist");
- BMO_op_exec(bm, &findop);
-
- /* weld the vertices */
- BMO_op_init(bm, &weldop, op->flag, "weld_verts");
- BMO_slot_copy(&findop, slots_out, "targetmap.out", &weldop, slots_in, "targetmap");
- BMO_op_exec(bm, &weldop);
-
- BMO_op_finish(bm, &findop);
- BMO_op_finish(bm, &weldop);
-}
diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c
index 5d511374989..dabdbc3c97a 100644
--- a/source/blender/bmesh/tools/bmesh_beautify.c
+++ b/source/blender/bmesh/tools/bmesh_beautify.c
@@ -199,7 +199,7 @@ static float bm_edge_calc_rotate_beauty__area(const float v1[3],
* Allowing to rotate out of a degenerate state can flip the faces
* (when performed iteratively).
*/
- return BLI_polyfill_beautify_quad_rotate_calc_ex(v1_xy, v2_xy, v3_xy, v4_xy, true);
+ return BLI_polyfill_beautify_quad_rotate_calc_ex(v1_xy, v2_xy, v3_xy, v4_xy, true, NULL);
} while (false);
return FLT_MAX;
diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.c b/source/blender/bmesh/tools/bmesh_intersect_edges.c
new file mode 100644
index 00000000000..ffdcf179491
--- /dev/null
+++ b/source/blender/bmesh/tools/bmesh_intersect_edges.c
@@ -0,0 +1,911 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bmesh
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_sort.h"
+#include "BLI_stack.h"
+
+#include "BKE_bvhutils.h"
+
+#include "bmesh.h"
+
+#include "bmesh_intersect_edges.h" /* own include */
+
+#define KDOP_AXIS_LEN 14
+
+/* -------------------------------------------------------------------- */
+/** \name Weld Linked Wire Edges into Linked Faces
+ *
+ * Used with the merge vertices option.
+ * \{ */
+
+/* Callbacks for `BM_vert_pair_shared_face_cb` */
+
+struct EDBMSplitBestFaceData {
+ BMEdge **edgenet;
+ int edgenet_len;
+
+ /**
+ * Track the range of vertices in edgenet along the faces normal,
+ * find the lowest since it's most likely to be most co-planar with the face.
+ */
+ float best_face_range_on_normal_axis;
+ BMFace *r_best_face;
+};
+
+static bool bm_vert_pair_share_best_splittable_face_cb(BMFace *f,
+ BMLoop *l_a,
+ BMLoop *l_b,
+ void *userdata)
+{
+ struct EDBMSplitBestFaceData *data = userdata;
+ float no[3];
+ copy_v3_v3(no, f->no);
+
+ float min = dot_v3v3(l_a->v->co, no);
+ float max = dot_v3v3(l_b->v->co, no);
+ if (min > max) {
+ SWAP(float, min, max);
+ }
+
+ BMVert *v_test = l_b->v;
+ BMEdge **e_iter = &data->edgenet[0];
+ int verts_len = data->edgenet_len - 1;
+ for (int i = verts_len; i--; e_iter++) {
+ v_test = BM_edge_other_vert(*e_iter, v_test);
+ if (!BM_face_point_inside_test(f, v_test->co)) {
+ return false;
+ }
+ float dot = dot_v3v3(v_test->co, no);
+ if (dot < min) {
+ min = dot;
+ }
+ if (dot > max) {
+ max = dot;
+ }
+ }
+
+ const float test_face_range_on_normal_axis = max - min;
+ if (test_face_range_on_normal_axis < data->best_face_range_on_normal_axis) {
+ data->best_face_range_on_normal_axis = test_face_range_on_normal_axis;
+ data->r_best_face = f;
+ }
+
+ return false;
+}
+
+/* find the best splittable face between the two vertices. */
+static bool bm_vert_pair_share_splittable_face_cb(BMFace *UNUSED(f),
+ BMLoop *l_a,
+ BMLoop *l_b,
+ void *userdata)
+{
+ float(*data)[3] = userdata;
+ float *v_a_co = data[0];
+ float *v_a_b_dir = data[1];
+
+ float lambda;
+ if (isect_ray_seg_v3(v_a_co, v_a_b_dir, l_a->prev->v->co, l_a->next->v->co, &lambda)) {
+ if (IN_RANGE(lambda, 0.0f, 1.0f)) {
+ return true;
+ }
+ else if (isect_ray_seg_v3(v_a_co, v_a_b_dir, l_b->prev->v->co, l_b->next->v->co, &lambda)) {
+ return IN_RANGE(lambda, 0.0f, 1.0f);
+ }
+ }
+ return false;
+}
+
+void BM_vert_weld_linked_wire_edges_into_linked_faces(
+ BMesh *bm, BMVert *v, const float epsilon, BMEdge **r_edgenet[], int *r_edgenet_alloc_len)
+{
+ BMEdge **edgenet = *r_edgenet;
+ int edgenet_alloc_len = *r_edgenet_alloc_len;
+
+ BMIter iter;
+ BMEdge *e;
+ BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
+ int edgenet_len = 0;
+ BMVert *v_other = v;
+ while (BM_edge_is_wire(e)) {
+ if (edgenet_alloc_len == edgenet_len) {
+ edgenet_alloc_len = (edgenet_alloc_len + 1) * 2;
+ edgenet = MEM_reallocN(edgenet, (edgenet_alloc_len) * sizeof(*edgenet));
+ }
+ edgenet[edgenet_len++] = e;
+ v_other = BM_edge_other_vert(e, v_other);
+ if (v_other == v) {
+ /* Endless loop. */
+ break;
+ }
+
+ BMEdge *e_next = BM_DISK_EDGE_NEXT(e, v_other);
+ if (e_next == e) {
+ /* Vert is wire_endpoint. */
+ edgenet_len = 0;
+ break;
+ }
+
+ BMEdge *e_test = e_next;
+ while ((e_test = BM_DISK_EDGE_NEXT(e_test, v_other)) != e) {
+ if (e_test->l) {
+ /* Vert is linked to a face. */
+ goto l_break;
+ }
+ }
+
+ e = e_next;
+ }
+
+ BMLoop *dummy;
+ BMFace *best_face;
+
+ l_break:
+ if (edgenet_len == 0) {
+ /* Nothing to do. */
+ continue;
+ }
+ if (edgenet_len == 1) {
+ float data[2][3];
+ copy_v3_v3(data[0], v_other->co);
+ sub_v3_v3v3(data[1], v->co, data[0]);
+ best_face = BM_vert_pair_shared_face_cb(
+ v_other, v, true, bm_vert_pair_share_splittable_face_cb, &data, &dummy, &dummy);
+ }
+ else {
+ struct EDBMSplitBestFaceData data = {
+ .edgenet = edgenet,
+ .edgenet_len = edgenet_len,
+ .best_face_range_on_normal_axis = FLT_MAX,
+ .r_best_face = NULL,
+ };
+ BM_vert_pair_shared_face_cb(
+ v_other, v, true, bm_vert_pair_share_best_splittable_face_cb, &data, &dummy, &dummy);
+
+ if (data.r_best_face) {
+ float no[3], min = FLT_MAX, max = -FLT_MAX;
+ copy_v3_v3(no, data.r_best_face->no);
+ BMVert *v_test;
+ BMIter f_iter;
+ BM_ITER_ELEM (v_test, &f_iter, data.r_best_face, BM_VERTS_OF_FACE) {
+ float dot = dot_v3v3(v_test->co, no);
+ if (dot < min) {
+ min = dot;
+ }
+ if (dot > max) {
+ max = dot;
+ }
+ }
+ float range = max - min + 2 * epsilon;
+ if (range < data.best_face_range_on_normal_axis) {
+ data.r_best_face = NULL;
+ }
+ }
+ best_face = data.r_best_face;
+ }
+
+ if (best_face) {
+ BM_face_split_edgenet(bm, best_face, edgenet, edgenet_len, NULL, NULL);
+ }
+ }
+
+ *r_edgenet = edgenet;
+ *r_edgenet_alloc_len = edgenet_alloc_len;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Auto-Merge & Split Selection
+ *
+ * Used after transform operations.
+ * \{ */
+
+struct EDBMSplitElem {
+ union {
+ BMElem *elem;
+ BMVert *vert;
+ struct {
+ BMEdge *edge;
+ float lambda;
+ };
+ };
+};
+
+/* -------------------------------------------------------------------- */
+/* Overlap Callbacks */
+
+struct EDBMSplitData {
+ BMesh *bm;
+ BLI_Stack *pair_stack;
+ int cut_edges_a_len;
+ int cut_edges_b_len;
+ float dist_sq;
+ float dist_sq_sq;
+};
+
+/* Utils */
+
+static void bm_vert_pair_elem_setup_ex(BMVert *v,
+ float edge_index,
+ struct EDBMSplitElem *r_pair_elem)
+{
+ BLI_assert(v->head.index == -1);
+ v->head.index = edge_index;
+ r_pair_elem->vert = v;
+}
+
+static void bm_edge_pair_elem_setup(BMEdge *e,
+ float lambda,
+ int *r_data_cut_edges_len,
+ struct EDBMSplitElem *r_pair_elem)
+{
+ r_pair_elem->edge = e;
+ r_pair_elem->lambda = lambda;
+
+ e->head.index++;
+ /* Obs: Check Multithread. */
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
+ (*r_data_cut_edges_len)++;
+ }
+}
+
+/* Util for Vert x Edge and Edge x Edge callbacks */
+static bool bm_vertxedge_isect_impl_ex(BMVert *v,
+ BMEdge *e,
+ int edge_index,
+ const float co[3],
+ const float dir[3],
+ float lambda,
+ float data_dist_sq,
+ int *data_cut_edges_len,
+ struct EDBMSplitElem r_pair[2])
+{
+ BLI_assert(v->head.index == -1);
+
+ BMVert *e_v;
+ float dist_sq_vert_factor;
+
+ if (lambda < 0.5f) {
+ e_v = e->v1;
+ dist_sq_vert_factor = lambda;
+ }
+ else {
+ e_v = e->v2;
+ dist_sq_vert_factor = 1.0f - lambda;
+ }
+
+ if (v != e_v) {
+ CLAMP(lambda, 0.0f, 1.0f);
+
+ float near[3];
+ madd_v3_v3v3fl(near, co, dir, lambda);
+
+ float dist_sq = len_squared_v3v3(v->co, near);
+ if (dist_sq < data_dist_sq) {
+ float dist_sq_vert = SQUARE(dist_sq_vert_factor) * len_squared_v3(dir);
+ if (dist_sq_vert < data_dist_sq) {
+ if (e_v->head.index != -1) {
+ /* Vertex already has an intersection. */
+ return false;
+ }
+
+ bm_vert_pair_elem_setup_ex(e_v, -2, &r_pair[1]);
+ }
+ else {
+ bm_edge_pair_elem_setup(e, lambda, data_cut_edges_len, &r_pair[1]);
+ }
+
+ bm_vert_pair_elem_setup_ex(v, edge_index, &r_pair[0]);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Vertex x Vertex Callback */
+
+static bool bm_vertxvert_isect_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
+{
+ struct EDBMSplitData *data = userdata;
+ BMVert *v_a = BM_vert_at_index(data->bm, index_a);
+ BMVert *v_b = BM_vert_at_index(data->bm, index_b);
+
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
+
+ BLI_assert(v_a->head.index == -1);
+
+ /* Set index -2 for sure that it will not repeat keys in `targetmap`. */
+ bm_vert_pair_elem_setup_ex(v_a, -2, &pair[0]);
+ bm_vert_pair_elem_setup_ex(v_b, -1, &pair[1]);
+
+ return true;
+}
+
+/* Vertex x Edge and Edge x Vertex Callbacks */
+
+static int bm_vertxedge_isect_impl(BMesh *bm,
+ int vert_index,
+ int edge_index,
+ float data_dist_sq,
+ int *data_cut_edges_len,
+ struct EDBMSplitElem r_pair[2])
+{
+ BMVert *v = BM_vert_at_index(bm, vert_index);
+ BMEdge *e = BM_edge_at_index(bm, edge_index);
+
+ if (v->head.index != -1) {
+ /* Only one vertex per edge. */
+ return false;
+ }
+
+ float co[3], dir[3], lambda;
+ copy_v3_v3(co, e->v1->co);
+ sub_v3_v3v3(dir, e->v2->co, co);
+ lambda = ray_point_factor_v3_ex(v->co, co, dir, 0.0f, -1.0f);
+
+ return bm_vertxedge_isect_impl_ex(
+ v, e, edge_index, co, dir, lambda, data_dist_sq, data_cut_edges_len, r_pair);
+}
+
+static bool bm_vertxedge_isect_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
+{
+ struct EDBMSplitData *data = userdata;
+ struct EDBMSplitElem pair_tmp[2];
+ if (bm_vertxedge_isect_impl(
+ data->bm, index_a, index_b, data->dist_sq, &data->cut_edges_b_len, pair_tmp)) {
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
+ pair[0] = pair_tmp[0];
+ pair[1] = pair_tmp[1];
+
+ return true;
+ }
+
+ return false;
+}
+
+static bool bm_edgexvert_isect_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
+{
+ struct EDBMSplitData *data = userdata;
+ struct EDBMSplitElem pair_tmp[2];
+ if (bm_vertxedge_isect_impl(
+ data->bm, index_b, index_a, data->dist_sq, &data->cut_edges_a_len, pair_tmp)) {
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
+ pair[0] = pair_tmp[1];
+ pair[1] = pair_tmp[0];
+
+ return true;
+ }
+
+ return false;
+}
+
+/* Edge x Edge Callbacks */
+
+static void bm_edgexedge_isect_impl(struct EDBMSplitData *data,
+ int index_a,
+ int index_b,
+ BMEdge *e_a,
+ BMEdge *e_b,
+ const float co_a[3],
+ const float dir_a[3],
+ const float co_b[3],
+ const float dir_b[3],
+ float lambda_a,
+ float lambda_b)
+{
+ float dist_sq_va_factor, dist_sq_vb_factor;
+ BMVert *e_a_v, *e_b_v;
+ if (lambda_a < 0.5f) {
+ e_a_v = e_a->v1;
+ dist_sq_va_factor = lambda_a;
+ }
+ else {
+ e_a_v = e_a->v2;
+ dist_sq_va_factor = 1.0f - lambda_a;
+ }
+
+ if (lambda_b < 0.5f) {
+ e_b_v = e_b->v1;
+ dist_sq_vb_factor = lambda_b;
+ }
+ else {
+ e_b_v = e_b->v2;
+ dist_sq_vb_factor = 1.0f - lambda_b;
+ }
+
+ if (e_a_v != e_b_v) {
+ CLAMP(lambda_a, 0.0f, 1.0f);
+ CLAMP(lambda_b, 0.0f, 1.0f);
+
+ float near_a[3], near_b[3];
+ madd_v3_v3v3fl(near_a, co_a, dir_a, lambda_a);
+ madd_v3_v3v3fl(near_b, co_b, dir_b, lambda_b);
+
+ float dist_sq = len_squared_v3v3(near_a, near_b);
+ if (dist_sq < data->dist_sq) {
+ struct EDBMSplitElem pair_tmp[2];
+
+ float dist_sq_va = SQUARE(dist_sq_va_factor) * len_squared_v3(dir_a);
+ float dist_sq_vb = SQUARE(dist_sq_vb_factor) * len_squared_v3(dir_b);
+
+ if (dist_sq_va < data->dist_sq) {
+ if (e_a_v->head.index != -1) {
+ /* Only one vertex per edge. */
+ return;
+ }
+ bm_vert_pair_elem_setup_ex(e_a_v, index_b, &pair_tmp[0]);
+ }
+
+ if (dist_sq_vb < data->dist_sq) {
+ if (e_b_v->head.index != -1) {
+ /* Only one vertex per edge. */
+ return;
+ }
+ bm_vert_pair_elem_setup_ex(e_b_v, index_a, &pair_tmp[1]);
+ }
+ else {
+ bm_edge_pair_elem_setup(e_b, lambda_b, &data->cut_edges_b_len, &pair_tmp[1]);
+ }
+
+ /* Don't setup edges before a return. */
+ if (dist_sq_va >= data->dist_sq) {
+ bm_edge_pair_elem_setup(e_a, lambda_a, &data->cut_edges_a_len, &pair_tmp[0]);
+ }
+
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
+ pair[0] = pair_tmp[0];
+ pair[1] = pair_tmp[1];
+ }
+ }
+}
+
+static bool bm_edgexedge_isect_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
+{
+ bool ret = false;
+ struct EDBMSplitData *data = userdata;
+ BMEdge *e_a = BM_edge_at_index(data->bm, index_a);
+ BMEdge *e_b = BM_edge_at_index(data->bm, index_b);
+
+ float co_a[3], dir_a[3], co_b[3], dir_b[3];
+ copy_v3_v3(co_a, e_a->v1->co);
+ sub_v3_v3v3(dir_a, e_a->v2->co, co_a);
+
+ copy_v3_v3(co_b, e_b->v1->co);
+ sub_v3_v3v3(dir_b, e_b->v2->co, co_b);
+
+ float lambda_a, lambda_b;
+ /* Using with dist^4 as `epsilon` is not the best solution, but it fits in most cases. */
+ if (isect_ray_ray_epsilon_v3(co_a, dir_a, co_b, dir_b, data->dist_sq_sq, &lambda_a, &lambda_b)) {
+ if (ELEM(index_b, e_a->v1->head.index, e_a->v2->head.index) ||
+ ELEM(index_a, e_b->v1->head.index, e_b->v2->head.index)) {
+ return ret;
+ }
+
+ /* Edge x Edge returns always false. */
+ bm_edgexedge_isect_impl(
+ data, index_a, index_b, e_a, e_b, co_a, dir_a, co_b, dir_b, lambda_a, lambda_b);
+ }
+ else {
+ /* Parallel */
+ struct EDBMSplitElem pair_tmp[2];
+ float vec[3], len_sq_a, len_sq_b, lambda;
+ sub_v3_v3v3(vec, co_b, co_a);
+ len_sq_a = len_squared_v3(dir_a);
+ len_sq_b = len_squared_v3(dir_b);
+
+ if (!ELEM(e_b->v1, e_a->v1, e_a->v2) && e_b->v1->head.index == -1) {
+ lambda = dot_v3v3(vec, dir_a) / len_sq_a;
+ if (bm_vertxedge_isect_impl_ex(e_b->v1,
+ e_a,
+ index_a,
+ co_a,
+ dir_a,
+ lambda,
+ data->dist_sq,
+ &data->cut_edges_a_len,
+ pair_tmp)) {
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
+ pair[0] = pair_tmp[1];
+ pair[1] = pair_tmp[0];
+ ret |= true;
+ }
+ }
+
+ if (!ELEM(e_a->v1, e_b->v1, e_b->v2) && e_a->v1->head.index == -1) {
+ lambda = -dot_v3v3(vec, dir_b) / len_sq_b;
+ if (bm_vertxedge_isect_impl_ex(e_a->v1,
+ e_b,
+ index_b,
+ co_b,
+ dir_b,
+ lambda,
+ data->dist_sq,
+ &data->cut_edges_b_len,
+ pair_tmp)) {
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
+ pair[0] = pair_tmp[0];
+ pair[1] = pair_tmp[1];
+ ret |= true;
+ }
+ }
+
+ add_v3_v3(vec, dir_b);
+ if (!ELEM(e_b->v2, e_a->v1, e_a->v2) && e_b->v2->head.index == -1) {
+ lambda = dot_v3v3(vec, dir_a) / len_sq_a;
+ if (bm_vertxedge_isect_impl_ex(e_b->v2,
+ e_a,
+ index_a,
+ co_a,
+ dir_a,
+ lambda,
+ data->dist_sq,
+ &data->cut_edges_a_len,
+ pair_tmp)) {
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
+ pair[0] = pair_tmp[1];
+ pair[1] = pair_tmp[0];
+ ret |= true;
+ }
+ }
+
+ sub_v3_v3(vec, dir_a);
+ if (!ELEM(e_a->v2, e_b->v1, e_b->v2) && e_a->v2->head.index == -1) {
+ lambda = 1.0f - dot_v3v3(vec, dir_b) / len_sq_b;
+ if (bm_vertxedge_isect_impl_ex(e_a->v2,
+ e_b,
+ index_b,
+ co_b,
+ dir_b,
+ lambda,
+ data->dist_sq,
+ &data->cut_edges_b_len,
+ pair_tmp)) {
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
+ pair[0] = pair_tmp[0];
+ pair[1] = pair_tmp[1];
+ ret |= true;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/* -------------------------------------------------------------------- */
+/* BVHTree Overlap Function */
+
+static void bvhtree_overlap_thread_safe(const BVHTree *tree1,
+ const BVHTree *tree2,
+ BVHTree_OverlapCallback callback,
+ void *userdata)
+{
+ BLI_bvhtree_overlap_ex(tree1, tree2, NULL, callback, userdata, BVH_OVERLAP_BREAK_ON_FIRST);
+}
+
+/* -------------------------------------------------------------------- */
+/* Callbacks for `BLI_qsort_r` */
+
+static int sort_cmp_by_lambda_a_cb(const void *index1_v, const void *index2_v, void *keys_v)
+{
+ const struct EDBMSplitElem(*pair_array)[2] = keys_v;
+ const int index1 = *(int *)index1_v;
+ const int index2 = *(int *)index2_v;
+
+ if (pair_array[index1][0].lambda > pair_array[index2][0].lambda) {
+ return 1;
+ }
+ else {
+ return -1;
+ }
+}
+
+static int sort_cmp_by_lambda_b_cb(const void *index1_v, const void *index2_v, void *keys_v)
+{
+ const struct EDBMSplitElem(*pair_array)[2] = keys_v;
+ const int index1 = *(int *)index1_v;
+ const int index2 = *(int *)index2_v;
+
+ if (pair_array[index1][1].lambda > pair_array[index2][1].lambda) {
+ return 1;
+ }
+ else {
+ return -1;
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/* Main API */
+
+bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHash *r_targetmap)
+{
+ bool ok = false;
+
+ BMIter iter;
+ BMVert *v;
+ BMEdge *e;
+ int i;
+
+ BM_mesh_elem_table_ensure(bm, BM_VERT | BM_EDGE);
+
+ /* Store all intersections in this array. */
+ struct EDBMSplitElem(*pair_iter)[2], (*pair_array)[2] = NULL;
+ BLI_Stack *pair_stack = BLI_stack_new(sizeof(*pair_array), __func__);
+ int pair_len = 0;
+
+ float dist_sq = SQUARE(dist);
+ struct EDBMSplitData data = {
+ .bm = bm,
+ .pair_stack = pair_stack,
+ .cut_edges_a_len = 0,
+ .cut_edges_b_len = 0,
+ .dist_sq = dist_sq,
+ .dist_sq_sq = SQUARE(dist_sq),
+ };
+
+ /* tag and count the verts to be tested. */
+ int verts_act_len = 0, verts_remain_len = 0;
+ int loose_verts_act_len = 0, loose_verts_remain_len = 0;
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, hflag)) {
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ v->head.index = -1;
+ verts_act_len++;
+ if (!v->e) {
+ loose_verts_act_len++;
+ }
+ }
+ else {
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
+ v->head.index = -1;
+ verts_remain_len++;
+ if (!v->e) {
+ loose_verts_remain_len++;
+ }
+ }
+ }
+ }
+ bm->elem_index_dirty |= BM_VERT;
+
+ /* Start the creation of BVHTrees. */
+ BVHTree *tree_loose_verts_act = NULL, *tree_loose_verts_remain = NULL;
+ if (loose_verts_act_len) {
+ tree_loose_verts_act = BLI_bvhtree_new(loose_verts_act_len, dist, 2, KDOP_AXIS_LEN);
+ }
+ if (loose_verts_remain_len) {
+ tree_loose_verts_remain = BLI_bvhtree_new(loose_verts_remain_len, 0.0f, 2, KDOP_AXIS_LEN);
+ }
+
+ if (tree_loose_verts_act || tree_loose_verts_remain) {
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ if (tree_loose_verts_act && !v->e) {
+ BLI_bvhtree_insert(tree_loose_verts_act, i, v->co, 1);
+ }
+ }
+ else if (tree_loose_verts_remain && !v->e && !BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
+ BLI_bvhtree_insert(tree_loose_verts_remain, i, v->co, 1);
+ }
+ }
+ if (tree_loose_verts_act) {
+ BLI_bvhtree_balance(tree_loose_verts_act);
+ }
+
+ if (tree_loose_verts_remain) {
+ BLI_bvhtree_balance(tree_loose_verts_remain);
+ }
+
+ if (tree_loose_verts_act && tree_loose_verts_remain) {
+ /* First pair search. */
+ bvhtree_overlap_thread_safe(
+ tree_loose_verts_act, tree_loose_verts_remain, bm_vertxvert_isect_cb, &data);
+ }
+ }
+
+ /* Tag and count the edges. */
+ int edges_act_len = 0, edges_remain_len = 0;
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e->v1, BM_ELEM_TAG) || BM_elem_flag_test(e->v2, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ edges_act_len++;
+ }
+ else {
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ edges_remain_len++;
+ }
+ }
+ }
+
+ if (edges_remain_len) {
+ BVHTree *tree_edges_act = NULL, *tree_edges_remain = NULL;
+ tree_edges_remain = BLI_bvhtree_new(edges_remain_len, 0.0f, 2, KDOP_AXIS_LEN);
+ if (edges_act_len) {
+ tree_edges_act = BLI_bvhtree_new(edges_act_len, dist, 2, KDOP_AXIS_LEN);
+ }
+
+ BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
+ float co[2][3];
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ if (tree_edges_act) {
+ e->head.index = 0;
+ copy_v3_v3(co[0], e->v1->co);
+ copy_v3_v3(co[1], e->v2->co);
+ BLI_bvhtree_insert(tree_edges_act, i, co[0], 2);
+ }
+ }
+ else if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ /* Tag used in the overlap callbacks. */
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ e->head.index = 0;
+ copy_v3_v3(co[0], e->v1->co);
+ copy_v3_v3(co[1], e->v2->co);
+ BLI_bvhtree_insert(tree_edges_remain, i, co[0], 2);
+ }
+ }
+ /* Use `e->head.index` to count intersections. */
+ bm->elem_index_dirty |= BM_EDGE;
+
+ BLI_bvhtree_balance(tree_edges_remain);
+ if (tree_edges_act) {
+ BLI_bvhtree_balance(tree_edges_act);
+ }
+
+ if (tree_edges_act) {
+ /* Edge x Edge */
+ bvhtree_overlap_thread_safe(tree_edges_act, tree_edges_remain, bm_edgexedge_isect_cb, &data);
+
+ if (tree_loose_verts_remain) {
+ /* Edge x Vert */
+ bvhtree_overlap_thread_safe(
+ tree_edges_act, tree_loose_verts_remain, bm_edgexvert_isect_cb, &data);
+ }
+
+ BLI_bvhtree_free(tree_edges_act);
+ }
+
+ if (tree_loose_verts_act) {
+ /* Vert x Edge */
+ bvhtree_overlap_thread_safe(
+ tree_loose_verts_act, tree_edges_remain, bm_vertxedge_isect_cb, &data);
+ }
+
+ BLI_bvhtree_free(tree_edges_remain);
+
+ pair_len = BLI_stack_count(pair_stack);
+ if (pair_len) {
+ pair_array = MEM_mallocN(sizeof(*pair_array) * pair_len, __func__);
+ BLI_stack_pop_n_reverse(pair_stack, pair_array, pair_len);
+
+ /* Map intersections per edge. */
+ union {
+ struct {
+ int cuts_len;
+ int cuts_index[];
+ };
+ int as_int[0];
+ } * e_map_iter, *e_map;
+
+ size_t e_map_size = (max_ii(data.cut_edges_a_len, data.cut_edges_b_len) * sizeof(*e_map)) +
+ (pair_len * sizeof(*(e_map->cuts_index)));
+
+ e_map = MEM_mallocN(e_map_size, __func__);
+
+ /* Convert every pair to Vert x Vert. */
+ for (int pair = 0; pair < 2; pair++) {
+ int map_len = 0;
+ pair_iter = &pair_array[0];
+ for (i = 0; i < pair_len; i++, pair_iter++) {
+ if ((*pair_iter)[pair].elem->head.htype != BM_EDGE) {
+ /* Take the opportunity to set all vert indices to -1 again. */
+ (*pair_iter)[pair].elem->head.index = -1;
+ continue;
+ }
+ e = (*pair_iter)[pair].edge;
+ if (!BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ int e_cuts_len = e->head.index;
+
+ e_map_iter = (void *)&e_map->as_int[map_len];
+ e_map_iter->cuts_len = e_cuts_len;
+ e_map_iter->cuts_index[0] = i;
+
+ /* Use `e->head.index` to indicate which slot to fill with the `cut` index. */
+ e->head.index = map_len + 1;
+ map_len += 1 + e_cuts_len;
+ }
+ else {
+ e_map->as_int[++e->head.index] = i;
+ }
+ }
+
+ /* Split Edges A to set all Vert x Edge. */
+ for (i = 0; i < map_len;
+ e_map_iter = (void *)&e_map->as_int[i], i += 1 + e_map_iter->cuts_len) {
+
+ /* sort by lambda. */
+ BLI_qsort_r(e_map_iter->cuts_index,
+ e_map_iter->cuts_len,
+ sizeof(*(e_map->cuts_index)),
+ pair == 0 ? sort_cmp_by_lambda_a_cb : sort_cmp_by_lambda_b_cb,
+ pair_array);
+
+ float lambda, lambda_prev = 0.0f;
+ for (int j = 0; j < e_map_iter->cuts_len; j++) {
+ struct EDBMSplitElem *pair_elem = &pair_array[e_map_iter->cuts_index[j]][pair];
+ lambda = (pair_elem->lambda - lambda_prev) / (1.0f - lambda_prev);
+ lambda_prev = pair_elem->lambda;
+ e = pair_elem->edge;
+
+ BMVert *v_new = BM_edge_split(bm, e, e->v1, NULL, lambda);
+ v_new->head.index = -1;
+ pair_elem->vert = v_new;
+ }
+ }
+ }
+
+ MEM_freeN(e_map);
+ }
+ }
+
+ BLI_bvhtree_free(tree_loose_verts_act);
+ BLI_bvhtree_free(tree_loose_verts_remain);
+
+ if (r_targetmap) {
+ if (pair_array == NULL) {
+ pair_len = BLI_stack_count(pair_stack);
+ if (pair_len) {
+ pair_array = MEM_mallocN(sizeof(*pair_array) * pair_len, __func__);
+ BLI_stack_pop_n_reverse(pair_stack, pair_array, pair_len);
+ }
+ }
+
+ if (pair_array) {
+ /* Organize the vertices in the order they will be merged. */
+ pair_iter = &pair_array[0];
+ for (i = 0; i < pair_len; i++, pair_iter++) {
+ BLI_assert((*pair_iter)[0].elem->head.htype == BM_VERT);
+ BLI_assert((*pair_iter)[1].elem->head.htype == BM_VERT);
+ BLI_assert((*pair_iter)[0].elem != (*pair_iter)[1].elem);
+
+ BLI_ghash_insert(r_targetmap, (*pair_iter)[0].vert, (*pair_iter)[1].vert);
+ }
+
+ ok = true;
+ }
+ }
+
+ BLI_stack_free(pair_stack);
+ if (pair_array) {
+ MEM_freeN(pair_array);
+ }
+
+ return ok;
+}
+
+/** \} */
diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.h b/source/blender/bmesh/tools/bmesh_intersect_edges.h
new file mode 100644
index 00000000000..a22a1ca1e1d
--- /dev/null
+++ b/source/blender/bmesh/tools/bmesh_intersect_edges.h
@@ -0,0 +1,29 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bmesh
+ */
+
+#ifndef __BMESH_INTERSECT_EDGES_H__
+#define __BMESH_INTERSECT_EDGES_H__
+
+void BM_vert_weld_linked_wire_edges_into_linked_faces(
+ BMesh *bm, BMVert *v, const float epsilon, BMEdge **r_edgenet[], int *r_edgenet_alloc_len);
+
+bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHash *r_targetmap);
+
+#endif /* __BMESH_INTERSECT_EDGES_H__ */
diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp
index a15c215d2e2..9d0d075cade 100644
--- a/source/blender/collada/AnimationExporter.cpp
+++ b/source/blender/collada/AnimationExporter.cpp
@@ -594,7 +594,7 @@ std::string AnimationExporter::collada_tangent_from_curve(
const FCurve *fcu = curve.get_fcurve();
int tangent = (semantic == COLLADASW::InputSemantic::IN_TANGENT) ? 0 : 2;
- for (int i = 0; i < fcu->totvert; ++i) {
+ for (int i = 0; i < fcu->totvert; i++) {
BezTriple &bezt = fcu->bezt[i];
float sampled_time = bezt.vec[tangent][0];
diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp
index 54177560eb5..79593f07383 100644
--- a/source/blender/collada/AnimationImporter.cpp
+++ b/source/blender/collada/AnimationImporter.cpp
@@ -733,7 +733,7 @@ void AnimationImporter::Assign_float_animations(const COLLADAFW::UniqueId &listi
* Reason: old blender versions stored spot_size in radians (was a bug)
*/
if (this->import_from_version == "" ||
- BLI_natstrcmp(this->import_from_version.c_str(), "2.69.10") != -1) {
+ BLI_strcasecmp_natural(this->import_from_version.c_str(), "2.69.10") != -1) {
fcurve_deg_to_rad(fcu);
}
}
diff --git a/source/blender/collada/BCAnimationCurve.cpp b/source/blender/collada/BCAnimationCurve.cpp
index b494c749fe3..bf32ec9148c 100644
--- a/source/blender/collada/BCAnimationCurve.cpp
+++ b/source/blender/collada/BCAnimationCurve.cpp
@@ -249,7 +249,7 @@ const int BCAnimationCurve::closest_index_below(const float sample_frame) const
int lower_index = 0;
int upper_index = 0;
- for (int fcu_index = 0; fcu_index < fcurve->totvert; ++fcu_index) {
+ for (int fcu_index = 0; fcu_index < fcurve->totvert; fcu_index++) {
upper_index = fcu_index;
const int cframe = fcurve->bezt[fcu_index].vec[1][0]; // inacurate!
@@ -537,7 +537,7 @@ bool BCAnimationCurve::is_keyframe(int frame)
return false;
}
- for (int i = 0; i < fcurve->totvert; ++i) {
+ for (int i = 0; i < fcurve->totvert; i++) {
const int cframe = nearbyint(fcurve->bezt[i].vec[1][0]);
if (cframe == frame) {
return true;
diff --git a/source/blender/collada/BCAnimationSampler.cpp b/source/blender/collada/BCAnimationSampler.cpp
index 49d87f92fda..5262d0b3672 100644
--- a/source/blender/collada/BCAnimationSampler.cpp
+++ b/source/blender/collada/BCAnimationSampler.cpp
@@ -129,7 +129,7 @@ static void add_keyframes_from(bAction *action, BCFrameSet &frameset)
void BCAnimationSampler::check_property_is_animated(
BCAnimation &animation, float *ref, float *val, std::string data_path, int length)
{
- for (int array_index = 0; array_index < length; ++array_index) {
+ for (int array_index = 0; array_index < length; array_index++) {
if (!bc_in_range(ref[length], val[length], 0.00001)) {
BCCurveKey key(BC_ANIMATION_TYPE_OBJECT, data_path, array_index);
BCAnimationCurveMap::iterator it = animation.curve_map.find(key);
@@ -195,7 +195,7 @@ void BCAnimationSampler::sample_scene(BCExportSettings &export_settings, bool ke
int startframe = scene->r.sfra;
int endframe = scene->r.efra;
- for (int frame_index = startframe; frame_index <= endframe; ++frame_index) {
+ for (int frame_index = startframe; frame_index <= endframe; frame_index++) {
/* Loop over all frames and decide for each frame if sampling is necessary */
bool is_scene_sample_frame = false;
bool needs_update = true;
diff --git a/source/blender/collada/BlenderContext.cpp b/source/blender/collada/BlenderContext.cpp
index 709f84c3f77..8735d71ec40 100644
--- a/source/blender/collada/BlenderContext.cpp
+++ b/source/blender/collada/BlenderContext.cpp
@@ -121,7 +121,7 @@ bContext *BlenderContext::get_context()
Depsgraph *BlenderContext::get_depsgraph()
{
if (!depsgraph) {
- depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ depsgraph = BKE_scene_get_depsgraph(main, scene, view_layer, true);
}
return depsgraph;
}
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index 98b166716c3..9d838406101 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -333,7 +333,7 @@ std::string DocumentImporter::get_import_version(const COLLADAFW::FileInfo *asse
const char AUTORING_TOOL[] = "authoring_tool";
const std::string BLENDER("Blender ");
const COLLADAFW::FileInfo::ValuePairPointerArray &valuePairs = asset->getValuePairArray();
- for (size_t i = 0, count = valuePairs.getCount(); i < count; ++i) {
+ for (size_t i = 0, count = valuePairs.getCount(); i < count; i++) {
const COLLADAFW::FileInfo::ValuePair *valuePair = valuePairs[i];
const COLLADAFW::String &key = valuePair->first;
const COLLADAFW::String &value = valuePair->second;
@@ -567,7 +567,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node,
root_objects->push_back(ob);
}
}
- ++geom_done;
+ geom_done++;
}
while (camera_done < camera.getCount()) {
ob = create_camera_object(camera[camera_done], sce);
@@ -580,7 +580,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node,
root_objects->push_back(ob);
}
}
- ++camera_done;
+ camera_done++;
}
while (lamp_done < lamp.getCount()) {
ob = create_light_object(lamp[lamp_done], sce);
@@ -593,7 +593,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node,
root_objects->push_back(ob);
}
}
- ++lamp_done;
+ lamp_done++;
}
while (controller_done < controller.getCount()) {
COLLADAFW::InstanceGeometry *geometry = (COLLADAFW::InstanceGeometry *)
@@ -608,7 +608,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node,
root_objects->push_back(ob);
}
}
- ++controller_done;
+ controller_done++;
}
/* XXX instance_node is not supported yet */
while (inst_done < inst_node.getCount()) {
@@ -635,7 +635,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node,
}
}
}
- ++inst_done;
+ inst_done++;
read_transform = false;
}
diff --git a/source/blender/collada/SceneExporter.cpp b/source/blender/collada/SceneExporter.cpp
index 01854bef328..24449de0ddd 100644
--- a/source/blender/collada/SceneExporter.cpp
+++ b/source/blender/collada/SceneExporter.cpp
@@ -88,7 +88,7 @@ void SceneExporter::writeNodeList(std::vector<Object *> &child_objects, Object *
* I really prefer to enforce the export of hidden
* elements in an object hierarchy. When the children of
* the hidden elements are exported as well. */
- for (int i = 0; i < child_objects.size(); ++i) {
+ for (int i = 0; i < child_objects.size(); i++) {
Object *child = child_objects[i];
writeNode(child);
if (bc_is_marked(child)) {
diff --git a/source/blender/compositor/intern/COM_Debug.cpp b/source/blender/compositor/intern/COM_Debug.cpp
index 72c1e0cf316..c2ef7d37a59 100644
--- a/source/blender/compositor/intern/COM_Debug.cpp
+++ b/source/blender/compositor/intern/COM_Debug.cpp
@@ -335,7 +335,7 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
int totops = system->m_operations.size();
int totgroups = system->m_groups.size();
std::map<NodeOperation *, std::vector<std::string>> op_groups;
- for (int i = 0; i < totgroups; ++i) {
+ for (int i = 0; i < totgroups; i++) {
const ExecutionGroup *group = system->m_groups[i];
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "// GROUP: %d\r\n", i);
@@ -377,7 +377,7 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
}
/* operations not included in any group */
- for (int j = 0; j < totops; ++j) {
+ for (int j = 0; j < totops; j++) {
NodeOperation *operation = system->m_operations[j];
if (op_groups.find(operation) != op_groups.end()) {
continue;
@@ -397,8 +397,8 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
std::vector<std::string> &read_groups = op_groups[read];
std::vector<std::string> &write_groups = op_groups[write];
- for (int k = 0; k < write_groups.size(); ++k) {
- for (int l = 0; l < read_groups.size(); ++l) {
+ for (int k = 0; k < write_groups.size(); k++) {
+ for (int l = 0; l < read_groups.size(); l++) {
len += snprintf(str + len,
maxlen > len ? maxlen - len : 0,
"\"O_%p%s\" -> \"O_%p%s\" [style=dotted]\r\n",
@@ -448,8 +448,8 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
from,
to_op,
to);
- for (int k = 0; k < from_groups.size(); ++k) {
- for (int l = 0; l < to_groups.size(); ++l) {
+ for (int k = 0; k < from_groups.size(); k++) {
+ for (int l = 0; l < to_groups.size(); l++) {
len += snprintf(str + len,
maxlen > len ? maxlen - len : 0,
"\"O_%p%s\":\"OUT_%p\":e -> \"O_%p%s\":\"IN_%p\":w",
@@ -483,7 +483,7 @@ void DebugInfo::graphviz(const ExecutionSystem *system)
BLI_snprintf(basename, sizeof(basename), "compositor_%d.dot", m_file_index);
BLI_join_dirfile(filename, sizeof(filename), BKE_tempdir_session(), basename);
- ++m_file_index;
+ m_file_index++;
FILE *fp = BLI_fopen(filename, "wb");
fputs(str, fp);
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
index 198385649da..a00c613d1e2 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
@@ -608,7 +608,7 @@ static void find_reachable_operations_recursive(Tags &reachable, NodeOperation *
}
reachable.insert(op);
- for (int i = 0; i < op->getNumberOfInputSockets(); ++i) {
+ for (int i = 0; i < op->getNumberOfInputSockets(); i++) {
NodeOperationInput *input = op->getInputSocket(i);
if (input->isConnected()) {
find_reachable_operations_recursive(reachable, &input->getLink()->getOperation());
@@ -661,7 +661,7 @@ static void sort_operations_recursive(NodeOperationBuilder::Operations &sorted,
}
visited.insert(op);
- for (int i = 0; i < op->getNumberOfInputSockets(); ++i) {
+ for (int i = 0; i < op->getNumberOfInputSockets(); i++) {
NodeOperationInput *input = op->getInputSocket(i);
if (input->isConnected()) {
sort_operations_recursive(sorted, visited, &input->getLink()->getOperation());
@@ -696,7 +696,7 @@ static void add_group_operations_recursive(Tags &visited, NodeOperation *op, Exe
}
/* add all eligible input ops to the group */
- for (int i = 0; i < op->getNumberOfInputSockets(); ++i) {
+ for (int i = 0; i < op->getNumberOfInputSockets(); i++) {
NodeOperationInput *input = op->getInputSocket(i);
if (input->isConnected()) {
add_group_operations_recursive(visited, &input->getLink()->getOperation(), group);
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cpp
index 48af823f8f5..5ed2af0c11d 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.cpp
+++ b/source/blender/compositor/intern/COM_WorkScheduler.cpp
@@ -239,8 +239,8 @@ void WorkScheduler::initialize(bool use_opencl, int num_cpu_threads)
g_context = NULL;
g_program = NULL;
- if (clewInit() !=
- CLEW_SUCCESS) { /* this will check for errors and skip if already initialized */
+ /* This will check for errors and skip if already initialized. */
+ if (clewInit() != CLEW_SUCCESS) {
return;
}
diff --git a/source/blender/compositor/nodes/COM_CornerPinNode.cpp b/source/blender/compositor/nodes/COM_CornerPinNode.cpp
index 9a9ecb755af..efe847bbfbf 100644
--- a/source/blender/compositor/nodes/COM_CornerPinNode.cpp
+++ b/source/blender/compositor/nodes/COM_CornerPinNode.cpp
@@ -45,7 +45,7 @@ void CornerPinNode::convertToOperations(NodeConverter &converter,
converter.addOperation(plane_mask_operation);
converter.mapInputSocket(input_image, warp_image_operation->getInputSocket(0));
- for (int i = 0; i < 4; ++i) {
+ for (int i = 0; i < 4; i++) {
NodeInput *corner_input = getInputSocket(node_corner_index[i]);
converter.mapInputSocket(corner_input, warp_image_operation->getInputSocket(i + 1));
converter.mapInputSocket(corner_input, plane_mask_operation->getInputSocket(i));
diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp b/source/blender/compositor/nodes/COM_CryptomatteNode.cpp
index 4219fd49d44..da80ef697c1 100644
--- a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cpp
@@ -90,7 +90,7 @@ void CryptomatteNode::convertToOperations(NodeConverter &converter,
converter.addOperation(operation);
- for (int i = 0; i < getNumberOfInputSockets() - 1; ++i) {
+ for (int i = 0; i < getNumberOfInputSockets() - 1; i++) {
converter.mapInputSocket(this->getInputSocket(i + 1), operation->getInputSocket(i));
}
diff --git a/source/blender/compositor/nodes/COM_ImageNode.cpp b/source/blender/compositor/nodes/COM_ImageNode.cpp
index 6bce56ffd52..8e2590a9d92 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.cpp
+++ b/source/blender/compositor/nodes/COM_ImageNode.cpp
@@ -206,7 +206,7 @@ void ImageNode::convertToOperations(NodeConverter &converter,
/* without this, multilayer that fail to load will crash blender [#32490] */
if (is_multilayer_ok == false) {
- for (int i = 0; i < getNumberOfOutputSockets(); ++i) {
+ for (int i = 0; i < getNumberOfOutputSockets(); i++) {
converter.setInvalidOutput(getOutputSocket(i));
}
}
diff --git a/source/blender/compositor/nodes/COM_ImageNode.h b/source/blender/compositor/nodes/COM_ImageNode.h
index 781fef37355..cde9f997f85 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.h
+++ b/source/blender/compositor/nodes/COM_ImageNode.h
@@ -16,6 +16,9 @@
* Copyright 2011, Blender Foundation.
*/
+#ifndef __COM_IMAGENODE_H__
+#define __COM_IMAGENODE_H__
+
#include "COM_defines.h"
#include "COM_Node.h"
#include "DNA_node_types.h"
@@ -44,3 +47,5 @@ class ImageNode : public Node {
ImageNode(bNode *editorNode);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
};
+
+#endif /* __COM_IMAGENODE_H__ */
diff --git a/source/blender/compositor/nodes/COM_KeyingNode.h b/source/blender/compositor/nodes/COM_KeyingNode.h
index 9ae1d04b03f..fc5f55e33ae 100644
--- a/source/blender/compositor/nodes/COM_KeyingNode.h
+++ b/source/blender/compositor/nodes/COM_KeyingNode.h
@@ -16,6 +16,9 @@
* Copyright 2012, Blender Foundation.
*/
+#ifndef __COM_KEYINGNODE_H__
+#define __COM_KEYINGNODE_H__
+
#include "COM_Node.h"
/**
@@ -55,3 +58,5 @@ class KeyingNode : public Node {
KeyingNode(bNode *editorNode);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
};
+
+#endif /* __COM_KEYINGNODE_H__ */
diff --git a/source/blender/compositor/nodes/COM_KeyingScreenNode.h b/source/blender/compositor/nodes/COM_KeyingScreenNode.h
index edaf0238667..12db2ed8889 100644
--- a/source/blender/compositor/nodes/COM_KeyingScreenNode.h
+++ b/source/blender/compositor/nodes/COM_KeyingScreenNode.h
@@ -16,6 +16,9 @@
* Copyright 2012, Blender Foundation.
*/
+#ifndef __COM_KEYINGSCREENNODE_H__
+#define __COM_KEYINGSCREENNODE_H__
+
#include "COM_Node.h"
#include "DNA_node_types.h"
@@ -28,3 +31,5 @@ class KeyingScreenNode : public Node {
KeyingScreenNode(bNode *editorNode);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
};
+
+#endif /* __COM_KEYINGSCREENNODE_H__ */
diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.cpp b/source/blender/compositor/nodes/COM_OutputFileNode.cpp
index 822359771f3..d40f822eb55 100644
--- a/source/blender/compositor/nodes/COM_OutputFileNode.cpp
+++ b/source/blender/compositor/nodes/COM_OutputFileNode.cpp
@@ -69,7 +69,7 @@ void OutputFileNode::convertToOperations(NodeConverter &converter,
int num_inputs = getNumberOfInputSockets();
bool previewAdded = false;
- for (int i = 0; i < num_inputs; ++i) {
+ for (int i = 0; i < num_inputs; i++) {
NodeInput *input = getInputSocket(i);
NodeImageMultiFileSocket *sockdata =
(NodeImageMultiFileSocket *)input->getbNodeSocket()->storage;
@@ -88,7 +88,7 @@ void OutputFileNode::convertToOperations(NodeConverter &converter,
else { /* single layer format */
int num_inputs = getNumberOfInputSockets();
bool previewAdded = false;
- for (int i = 0; i < num_inputs; ++i) {
+ for (int i = 0; i < num_inputs; i++) {
NodeInput *input = getInputSocket(i);
if (input->isLinked()) {
NodeImageMultiFileSocket *sockdata =
diff --git a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h
index 0d57163dc97..6ee73e22af0 100644
--- a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h
+++ b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h
@@ -16,6 +16,9 @@
* Copyright 2013, Blender Foundation.
*/
+#ifndef __COM_PLANETRACKDEFORMNODE_H__
+#define __COM_PLANETRACKDEFORMNODE_H__
+
#include "COM_Node.h"
extern "C" {
@@ -32,3 +35,5 @@ class PlaneTrackDeformNode : public Node {
PlaneTrackDeformNode(bNode *editorNode);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
};
+
+#endif /* __COM_PLANETRACKDEFORMNODE_H__ */
diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.h b/source/blender/compositor/nodes/COM_RenderLayersNode.h
index 7e574678f2b..f6822f98fd9 100644
--- a/source/blender/compositor/nodes/COM_RenderLayersNode.h
+++ b/source/blender/compositor/nodes/COM_RenderLayersNode.h
@@ -16,6 +16,9 @@
* Copyright 2011, Blender Foundation.
*/
+#ifndef __COM_RENDERLAYERSNODE_H__
+#define __COM_RENDERLAYERSNODE_H__
+
#include "COM_Node.h"
#include "DNA_node_types.h"
#include "COM_RenderLayersProg.h"
@@ -46,3 +49,5 @@ class RenderLayersNode : public Node {
void missingSocketLink(NodeConverter &converter, NodeOutput *output) const;
void missingRenderLink(NodeConverter &converter) const;
};
+
+#endif /* __COM_RENDERLAYERSNODE_H__ */
diff --git a/source/blender/compositor/nodes/COM_TextureNode.h b/source/blender/compositor/nodes/COM_TextureNode.h
index 026d42ce2c3..8fe620a89b3 100644
--- a/source/blender/compositor/nodes/COM_TextureNode.h
+++ b/source/blender/compositor/nodes/COM_TextureNode.h
@@ -16,6 +16,9 @@
* Copyright 2011, Blender Foundation.
*/
+#ifndef __COM_TEXTURENODE_H__
+#define __COM_TEXTURENODE_H__
+
#include "COM_Node.h"
#include "DNA_node_types.h"
@@ -28,3 +31,5 @@ class TextureNode : public Node {
TextureNode(bNode *editorNode);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
};
+
+#endif /* __COM_TEXTURENODE_H__ */
diff --git a/source/blender/compositor/nodes/COM_TrackPositionNode.h b/source/blender/compositor/nodes/COM_TrackPositionNode.h
index c9420764598..7136077a123 100644
--- a/source/blender/compositor/nodes/COM_TrackPositionNode.h
+++ b/source/blender/compositor/nodes/COM_TrackPositionNode.h
@@ -16,6 +16,9 @@
* Copyright 2012, Blender Foundation.
*/
+#ifndef __COM_TRACKPOSITIONNODE_H__
+#define __COM_TRACKPOSITIONNODE_H__
+
#include "COM_Node.h"
#include "DNA_node_types.h"
@@ -28,3 +31,5 @@ class TrackPositionNode : public Node {
TrackPositionNode(bNode *editorNode);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
};
+
+#endif /* __COM_TRACKPOSITIONNODE_H__ */
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp b/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
index 84c41134b89..1b2e3b2821e 100644
--- a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
@@ -93,7 +93,7 @@ __m128 *BlurBaseOperation::convert_gausstab_sse(const float *gausstab, int size)
{
int n = 2 * size + 1;
__m128 *gausstab_sse = (__m128 *)MEM_mallocN_aligned(sizeof(__m128) * n, 16, "gausstab sse");
- for (int i = 0; i < n; ++i) {
+ for (int i = 0; i < n; i++) {
gausstab_sse[i] = _mm_set1_ps(gausstab[i]);
}
return gausstab_sse;
diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.cpp b/source/blender/compositor/operations/COM_DenoiseOperation.cpp
index ad53ab13def..8235c296c5a 100644
--- a/source/blender/compositor/operations/COM_DenoiseOperation.cpp
+++ b/source/blender/compositor/operations/COM_DenoiseOperation.cpp
@@ -21,16 +21,19 @@
#include "COM_DenoiseOperation.h"
#include "BLI_math.h"
+#include "BLI_system.h"
#ifdef WITH_OPENIMAGEDENOISE
+# include "BLI_threads.h"
# include <OpenImageDenoise/oidn.hpp>
+static pthread_mutex_t oidn_lock = BLI_MUTEX_INITIALIZER;
#endif
#include <iostream>
DenoiseOperation::DenoiseOperation() : SingleThreadedOperation()
{
this->addInputSocket(COM_DT_COLOR);
- this->addInputSocket(COM_DT_COLOR);
this->addInputSocket(COM_DT_VECTOR);
+ this->addInputSocket(COM_DT_COLOR);
this->addOutputSocket(COM_DT_COLOR);
this->m_settings = NULL;
}
@@ -38,23 +41,23 @@ void DenoiseOperation::initExecution()
{
SingleThreadedOperation::initExecution();
this->m_inputProgramColor = getInputSocketReader(0);
- this->m_inputProgramAlbedo = getInputSocketReader(1);
- this->m_inputProgramNormal = getInputSocketReader(2);
+ this->m_inputProgramNormal = getInputSocketReader(1);
+ this->m_inputProgramAlbedo = getInputSocketReader(2);
}
void DenoiseOperation::deinitExecution()
{
this->m_inputProgramColor = NULL;
- this->m_inputProgramAlbedo = NULL;
this->m_inputProgramNormal = NULL;
+ this->m_inputProgramAlbedo = NULL;
SingleThreadedOperation::deinitExecution();
}
MemoryBuffer *DenoiseOperation::createMemoryBuffer(rcti *rect2)
{
MemoryBuffer *tileColor = (MemoryBuffer *)this->m_inputProgramColor->initializeTileData(rect2);
- MemoryBuffer *tileAlbedo = (MemoryBuffer *)this->m_inputProgramAlbedo->initializeTileData(rect2);
MemoryBuffer *tileNormal = (MemoryBuffer *)this->m_inputProgramNormal->initializeTileData(rect2);
+ MemoryBuffer *tileAlbedo = (MemoryBuffer *)this->m_inputProgramAlbedo->initializeTileData(rect2);
rcti rect;
rect.xmin = 0;
rect.ymin = 0;
@@ -62,7 +65,7 @@ MemoryBuffer *DenoiseOperation::createMemoryBuffer(rcti *rect2)
rect.ymax = getHeight();
MemoryBuffer *result = new MemoryBuffer(COM_DT_COLOR, &rect);
float *data = result->getBuffer();
- this->generateDenoise(data, tileColor, tileAlbedo, tileNormal, this->m_settings);
+ this->generateDenoise(data, tileColor, tileNormal, tileAlbedo, this->m_settings);
return result;
}
@@ -85,8 +88,8 @@ bool DenoiseOperation::determineDependingAreaOfInterest(rcti * /*input*/,
void DenoiseOperation::generateDenoise(float *data,
MemoryBuffer *inputTileColor,
- MemoryBuffer *inputTileAlbedo,
MemoryBuffer *inputTileNormal,
+ MemoryBuffer *inputTileAlbedo,
NodeDenoise *settings)
{
float *inputBufferColor = inputTileColor->getBuffer();
@@ -95,61 +98,69 @@ void DenoiseOperation::generateDenoise(float *data,
return;
}
#ifdef WITH_OPENIMAGEDENOISE
- oidn::DeviceRef device = oidn::newDevice();
- device.commit();
+ if (BLI_cpu_support_sse41()) {
+ oidn::DeviceRef device = oidn::newDevice();
+ device.commit();
- oidn::FilterRef filter = device.newFilter("RT");
- filter.setImage("color",
- inputBufferColor,
- oidn::Format::Float3,
- inputTileColor->getWidth(),
- inputTileColor->getHeight(),
- 0,
- 4 * sizeof(float));
- if (inputTileAlbedo && inputTileAlbedo->getBuffer()) {
- filter.setImage("albedo",
- inputTileAlbedo->getBuffer(),
+ oidn::FilterRef filter = device.newFilter("RT");
+ filter.setImage("color",
+ inputBufferColor,
oidn::Format::Float3,
- inputTileAlbedo->getWidth(),
- inputTileAlbedo->getHeight(),
+ inputTileColor->getWidth(),
+ inputTileColor->getHeight(),
0,
4 * sizeof(float));
- }
- if (inputTileNormal && inputTileNormal->getBuffer()) {
- filter.setImage("normal",
- inputTileNormal->getBuffer(),
+ if (inputTileNormal && inputTileNormal->getBuffer()) {
+ filter.setImage("normal",
+ inputTileNormal->getBuffer(),
+ oidn::Format::Float3,
+ inputTileNormal->getWidth(),
+ inputTileNormal->getHeight(),
+ 0,
+ 3 * sizeof(float));
+ }
+ if (inputTileAlbedo && inputTileAlbedo->getBuffer()) {
+ filter.setImage("albedo",
+ inputTileAlbedo->getBuffer(),
+ oidn::Format::Float3,
+ inputTileAlbedo->getWidth(),
+ inputTileAlbedo->getHeight(),
+ 0,
+ 4 * sizeof(float));
+ }
+ filter.setImage("output",
+ data,
oidn::Format::Float3,
- inputTileNormal->getWidth(),
- inputTileNormal->getHeight(),
+ inputTileColor->getWidth(),
+ inputTileColor->getHeight(),
0,
- 3 * sizeof(float));
- }
- filter.setImage("output",
- data,
- oidn::Format::Float3,
- inputTileColor->getWidth(),
- inputTileColor->getHeight(),
- 0,
- 4 * sizeof(float));
+ 4 * sizeof(float));
- BLI_assert(settings);
- if (settings) {
- filter.set("hdr", settings->hdr);
- filter.set("srgb", false);
- }
+ BLI_assert(settings);
+ if (settings) {
+ filter.set("hdr", settings->hdr);
+ filter.set("srgb", false);
+ }
- filter.commit();
- filter.execute();
+ filter.commit();
+ /* Since it's memory intensive, it's better to run only one instance of OIDN at a time.
+ * OpenImageDenoise is multithreaded internally and should use all available cores nonetheless.
+ */
+ BLI_mutex_lock(&oidn_lock);
+ filter.execute();
+ BLI_mutex_unlock(&oidn_lock);
- /* copy the alpha channel, OpenImageDenoise currently only supports RGB */
- size_t numPixels = inputTileColor->getWidth() * inputTileColor->getHeight();
- for (size_t i = 0; i < numPixels; ++i) {
- data[i * 4 + 3] = inputBufferColor[i * 4 + 3];
+ /* copy the alpha channel, OpenImageDenoise currently only supports RGB */
+ size_t numPixels = inputTileColor->getWidth() * inputTileColor->getHeight();
+ for (size_t i = 0; i < numPixels; i++) {
+ data[i * 4 + 3] = inputBufferColor[i * 4 + 3];
+ }
+ return;
}
-#else
+#endif
+ /* If built without OIDN or running on an unsupported CPU, just pass through. */
UNUSED_VARS(inputTileAlbedo, inputTileNormal, settings);
::memcpy(data,
inputBufferColor,
inputTileColor->getWidth() * inputTileColor->getHeight() * sizeof(float) * 4);
-#endif
}
diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.h b/source/blender/compositor/operations/COM_DenoiseOperation.h
index 6e19bd6034a..fc06bb81a97 100644
--- a/source/blender/compositor/operations/COM_DenoiseOperation.h
+++ b/source/blender/compositor/operations/COM_DenoiseOperation.h
@@ -19,8 +19,8 @@
* Stefan Werner
*/
-#ifndef __COM_DENOISEBASEOPERATION_H__
-#define __COM_DENOISEBASEOPERATION_H__
+#ifndef __COM_DENOISEOPERATION_H__
+#define __COM_DENOISEOPERATION_H__
#include "COM_SingleThreadedOperation.h"
#include "DNA_node_types.h"
@@ -62,10 +62,11 @@ class DenoiseOperation : public SingleThreadedOperation {
protected:
void generateDenoise(float *data,
MemoryBuffer *inputTileColor,
- MemoryBuffer *inputTileAlbedo,
MemoryBuffer *inputTileNormal,
+ MemoryBuffer *inputTileAlbedo,
NodeDenoise *settings);
MemoryBuffer *createMemoryBuffer(rcti *rect);
};
-#endif
+
+#endif /* __COM_DENOISEOPERATION_H__ */
diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp
index 7cf1086dca1..52bc00e9b84 100644
--- a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp
+++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp
@@ -387,7 +387,7 @@ void *DilateStepOperation::initializeTileData(rcti *rect)
for (x = 0; x < bwidth + 5 * half_window; x++) {
buf[x] = -FLT_MAX;
}
- for (x = xmin; x < xmax; ++x) {
+ for (x = xmin; x < xmax; x++) {
buf[x - rect->xmin + window - 1] = buffer[(y * width + x)];
}
@@ -516,7 +516,7 @@ void *ErodeStepOperation::initializeTileData(rcti *rect)
for (x = 0; x < bwidth + 5 * half_window; x++) {
buf[x] = FLT_MAX;
}
- for (x = xmin; x < xmax; ++x) {
+ for (x = xmin; x < xmax; x++) {
buf[x - rect->xmin + window - 1] = buffer[(y * width + x)];
}
diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp
index 59a397ab32d..1b590c0c392 100644
--- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp
@@ -72,7 +72,7 @@ void DirectionalBlurOperation::executePixel(float output[4], int x, int y, void
float lsc = this->m_sc;
float lrot = this->m_rot;
/* blur the image */
- for (int i = 0; i < iterations; ++i) {
+ for (int i = 0; i < iterations; i++) {
const float cs = cosf(lrot), ss = sinf(lrot);
const float isc = 1.0f / (1.0f + lsc);
diff --git a/source/blender/compositor/operations/COM_DisplaceOperation.cpp b/source/blender/compositor/operations/COM_DisplaceOperation.cpp
index 3efc566cb4e..b775bfdee4c 100644
--- a/source/blender/compositor/operations/COM_DisplaceOperation.cpp
+++ b/source/blender/compositor/operations/COM_DisplaceOperation.cpp
@@ -111,12 +111,12 @@ void DisplaceOperation::pixelTransform(const float xy[2], float r_uv[2], float r
if (read_displacement(xy[0] + epsilon[0], xy[1], xs, ys, xy, uv[0], uv[1])) {
r_deriv[0][0] += uv[0] - r_uv[0];
r_deriv[1][0] += uv[1] - r_uv[1];
- ++num;
+ num++;
}
if (read_displacement(xy[0] - epsilon[0], xy[1], xs, ys, xy, uv[0], uv[1])) {
r_deriv[0][0] += r_uv[0] - uv[0];
r_deriv[1][0] += r_uv[1] - uv[1];
- ++num;
+ num++;
}
if (num > 0) {
float numinv = 1.0f / (float)num;
@@ -128,12 +128,12 @@ void DisplaceOperation::pixelTransform(const float xy[2], float r_uv[2], float r
if (read_displacement(xy[0], xy[1] + epsilon[1], xs, ys, xy, uv[0], uv[1])) {
r_deriv[0][1] += uv[0] - r_uv[0];
r_deriv[1][1] += uv[1] - r_uv[1];
- ++num;
+ num++;
}
if (read_displacement(xy[0], xy[1] - epsilon[1], xs, ys, xy, uv[0], uv[1])) {
r_deriv[0][1] += r_uv[0] - uv[0];
r_deriv[1][1] += r_uv[1] - uv[1];
- ++num;
+ num++;
}
if (num > 0) {
float numinv = 1.0f / (float)num;
diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
index 2c12091c458..3058a5990c6 100644
--- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
@@ -89,18 +89,18 @@ void *FastGaussianBlurOperation::initializeTileData(rcti *rect)
this->m_sy = this->m_data.sizey * this->m_size / 2.0f;
if ((this->m_sx == this->m_sy) && (this->m_sx > 0.0f)) {
- for (c = 0; c < COM_NUM_CHANNELS_COLOR; ++c) {
+ for (c = 0; c < COM_NUM_CHANNELS_COLOR; c++) {
IIR_gauss(copy, this->m_sx, c, 3);
}
}
else {
if (this->m_sx > 0.0f) {
- for (c = 0; c < COM_NUM_CHANNELS_COLOR; ++c) {
+ for (c = 0; c < COM_NUM_CHANNELS_COLOR; c++) {
IIR_gauss(copy, this->m_sx, c, 1);
}
}
if (this->m_sy > 0.0f) {
- for (c = 0; c < COM_NUM_CHANNELS_COLOR; ++c) {
+ for (c = 0; c < COM_NUM_CHANNELS_COLOR; c++) {
IIR_gauss(copy, this->m_sy, c, 2);
}
}
@@ -216,16 +216,16 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src,
W = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss W buf");
if (xy & 1) { // H
int offset;
- for (y = 0; y < src_height; ++y) {
+ for (y = 0; y < src_height; y++) {
const int yx = y * src_width;
offset = yx * num_channels + chan;
- for (x = 0; x < src_width; ++x) {
+ for (x = 0; x < src_width; x++) {
X[x] = buffer[offset];
offset += num_channels;
}
YVV(src_width);
offset = yx * num_channels + chan;
- for (x = 0; x < src_width; ++x) {
+ for (x = 0; x < src_width; x++) {
buffer[offset] = Y[x];
offset += num_channels;
}
@@ -235,15 +235,15 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src,
int offset;
const int add = src_width * num_channels;
- for (x = 0; x < src_width; ++x) {
+ for (x = 0; x < src_width; x++) {
offset = x * num_channels + chan;
- for (y = 0; y < src_height; ++y) {
+ for (y = 0; y < src_height; y++) {
X[y] = buffer[offset];
offset += add;
}
YVV(src_height);
offset = x * num_channels + chan;
- for (y = 0; y < src_height; ++y) {
+ for (y = 0; y < src_height; y++) {
buffer[offset] = Y[y];
offset += add;
}
diff --git a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp
index 30a6a05ed2c..b43b94af06a 100644
--- a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp
@@ -61,7 +61,7 @@ static void FHT(fREAL *data, unsigned int M, unsigned int inverse)
int i, j = 0;
unsigned int Nh = len >> 1;
- for (i = 1; i < (len - 1); ++i) {
+ for (i = 1; i < (len - 1); i++) {
j = revbin_upd(j, Nh);
if (j > i) {
t1 = data[i];
@@ -117,7 +117,7 @@ static void FHT(fREAL *data, unsigned int M, unsigned int inverse)
if (inverse) {
fREAL sc = (fREAL)1 / (fREAL)len;
- for (k = 0; k < len; ++k) {
+ for (k = 0; k < len; k++) {
data[k] *= sc;
}
}
@@ -136,14 +136,14 @@ static void FHT2D(
// rows (forward transform skips 0 pad data)
maxy = inverse ? Ny : nzp;
- for (j = 0; j < maxy; ++j) {
+ for (j = 0; j < maxy; j++) {
FHT(&data[Nx * j], Mx, inverse);
}
// transpose data
if (Nx == Ny) { // square
- for (j = 0; j < Ny; ++j) {
- for (i = j + 1; i < Nx; ++i) {
+ for (j = 0; j < Ny; j++) {
+ for (i = j + 1; i < Nx; i++) {
unsigned int op = i + (j << Mx), np = j + (i << My);
SWAP(fREAL, data[op], data[np]);
}
@@ -171,7 +171,7 @@ static void FHT2D(
SWAP(unsigned int, Mx, My);
// now columns == transposed rows
- for (j = 0; j < Ny; ++j) {
+ for (j = 0; j < Ny; j++) {
FHT(&data[Nx * j], Mx, inverse);
}
@@ -421,9 +421,9 @@ void GlareFogGlowOperation::generateGlare(float *data,
scale = 0.25f * sqrtf((float)(sz * sz));
- for (y = 0; y < sz; ++y) {
+ for (y = 0; y < sz; y++) {
v = 2.0f * (y / (float)sz) - 1.0f;
- for (x = 0; x < sz; ++x) {
+ for (x = 0; x < sz; x++) {
u = 2.0f * (x / (float)sz) - 1.0f;
r = (u * u + v * v) * scale;
d = -sqrtf(sqrtf(sqrtf(r))) * 9.0f;
diff --git a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp b/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
index 951dec9281e..4fccb62e3df 100644
--- a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
@@ -41,7 +41,7 @@ void GlareStreaksOperation::generateGlare(float *data,
for (a = 0.0f; a < DEG2RADF(360.0f) && (!breaked); a += ang) {
const float an = a + settings->angle_ofs;
const float vx = cos((double)an), vy = sin((double)an);
- for (n = 0; n < settings->iter && (!breaked); ++n) {
+ for (n = 0; n < settings->iter && (!breaked); n++) {
const float p4 = pow(4.0, (double)n);
const float vxp = vx * p4, vyp = vy * p4;
const float wt = pow((double)settings->fade, (double)p4);
@@ -50,8 +50,8 @@ void GlareStreaksOperation::generateGlare(float *data,
(double)n +
1); // colormodulation amount relative to current pass
float *tdstcol = tdst->getBuffer();
- for (y = 0; y < tsrc->getHeight() && (!breaked); ++y) {
- for (x = 0; x < tsrc->getWidth(); ++x, tdstcol += 4) {
+ for (y = 0; y < tsrc->getHeight() && (!breaked); y++) {
+ for (x = 0; x < tsrc->getWidth(); x++, tdstcol += 4) {
// first pass no offset, always same for every pass, exact copy,
// otherwise results in uneven brightness, only need once
if (n == 0) {
diff --git a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp b/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp
index 300d122589f..83dd90ef08b 100644
--- a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp
@@ -51,7 +51,7 @@ void KeyingBlurOperation::executePixel(float output[4], int x, int y, void *data
if (this->m_axis == 0) {
const int start = max(0, x - this->m_size + 1), end = min(bufferWidth, x + this->m_size);
- for (int cx = start; cx < end; ++cx) {
+ for (int cx = start; cx < end; cx++) {
int bufferIndex = (y * bufferWidth + cx);
average += buffer[bufferIndex];
count++;
@@ -60,7 +60,7 @@ void KeyingBlurOperation::executePixel(float output[4], int x, int y, void *data
else {
const int start = max(0, y - this->m_size + 1),
end = min(inputBuffer->getHeight(), y + this->m_size);
- for (int cy = start; cy < end; ++cy) {
+ for (int cy = start; cy < end; cy++) {
int bufferIndex = (cy * bufferWidth + x);
average += buffer[bufferIndex];
count++;
diff --git a/source/blender/compositor/operations/COM_KeyingClipOperation.cpp b/source/blender/compositor/operations/COM_KeyingClipOperation.cpp
index b11bd54a190..eafd1e671f8 100644
--- a/source/blender/compositor/operations/COM_KeyingClipOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingClipOperation.cpp
@@ -71,8 +71,8 @@ void KeyingClipOperation::executePixel(float output[4], int x, int y, void *data
ok = true;
}
- for (int cx = start_x; ok == false && cx <= end_x; ++cx) {
- for (int cy = start_y; ok == false && cy <= end_y; ++cy) {
+ for (int cx = start_x; ok == false && cx <= end_x; cx++) {
+ for (int cy = start_y; ok == false && cy <= end_y; cy++) {
if (UNLIKELY(cx == x && cy == y)) {
continue;
}
diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cpp b/source/blender/compositor/operations/COM_MapUVOperation.cpp
index 21d432b9222..de55c9fb4b8 100644
--- a/source/blender/compositor/operations/COM_MapUVOperation.cpp
+++ b/source/blender/compositor/operations/COM_MapUVOperation.cpp
@@ -117,12 +117,12 @@ void MapUVOperation::pixelTransform(const float xy[2],
if (read_uv(xy[0] + epsilon[0], xy[1], uv[0], uv[1], alpha)) {
r_deriv[0][0] += uv[0] - r_uv[0];
r_deriv[1][0] += uv[1] - r_uv[1];
- ++num;
+ num++;
}
if (read_uv(xy[0] - epsilon[0], xy[1], uv[0], uv[1], alpha)) {
r_deriv[0][0] += r_uv[0] - uv[0];
r_deriv[1][0] += r_uv[1] - uv[1];
- ++num;
+ num++;
}
if (num > 0) {
float numinv = 1.0f / (float)num;
@@ -134,12 +134,12 @@ void MapUVOperation::pixelTransform(const float xy[2],
if (read_uv(xy[0], xy[1] + epsilon[1], uv[0], uv[1], alpha)) {
r_deriv[0][1] += uv[0] - r_uv[0];
r_deriv[1][1] += uv[1] - r_uv[1];
- ++num;
+ num++;
}
if (read_uv(xy[0], xy[1] - epsilon[1], uv[0], uv[1], alpha)) {
r_deriv[0][1] += r_uv[0] - uv[0];
r_deriv[1][1] += r_uv[1] - uv[1];
- ++num;
+ num++;
}
if (num > 0) {
float numinv = 1.0f / (float)num;
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
index 9d1be09de0e..444af5c4cf7 100644
--- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
@@ -183,7 +183,7 @@ void *OutputOpenExrMultiLayerMultiViewOperation::get_handle(const char *filename
IMB_exr_add_view(exrhandle, srv->name);
- for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
+ for (unsigned int i = 0; i < this->m_layers.size(); i++) {
add_exr_channels(exrhandle,
this->m_layers[i].name,
this->m_layers[i].datatype,
@@ -229,7 +229,7 @@ void OutputOpenExrMultiLayerMultiViewOperation::deinitExecution()
exrhandle = this->get_handle(filename);
- for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
+ for (unsigned int i = 0; i < this->m_layers.size(); i++) {
add_exr_channels(exrhandle,
this->m_layers[i].name,
this->m_layers[i].datatype,
@@ -239,7 +239,7 @@ void OutputOpenExrMultiLayerMultiViewOperation::deinitExecution()
this->m_layers[i].outputBuffer);
}
- for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
+ for (unsigned int i = 0; i < this->m_layers.size(); i++) {
/* memory can only be freed after we write all views to the file */
this->m_layers[i].outputBuffer = NULL;
this->m_layers[i].imageInput = NULL;
@@ -250,7 +250,7 @@ void OutputOpenExrMultiLayerMultiViewOperation::deinitExecution()
IMB_exr_write_channels(exrhandle);
/* free buffer memory for all the views */
- for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
+ for (unsigned int i = 0; i < this->m_layers.size(); i++) {
free_exr_channels(
exrhandle, this->m_rd, this->m_layers[i].name, this->m_layers[i].datatype);
}
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cpp
index 79e3b2f1108..c06994d7cdb 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.cpp
@@ -162,7 +162,7 @@ static void write_buffer_rect(rcti *rect,
for (x = x1; x < x2 && (!breaked); x++) {
reader->readSampled(color, x, y, COM_PS_NEAREST);
- for (i = 0; i < size; ++i) {
+ for (i = 0; i < size; i++) {
buffer[offset + i] = color[i];
}
offset += size;
@@ -298,7 +298,7 @@ void OutputOpenExrMultiLayerOperation::add_layer(const char *name,
void OutputOpenExrMultiLayerOperation::initExecution()
{
- for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
+ for (unsigned int i = 0; i < this->m_layers.size(); i++) {
if (this->m_layers[i].use_layer) {
SocketReader *reader = getInputSocketReader(i);
this->m_layers[i].imageInput = reader;
@@ -310,7 +310,7 @@ void OutputOpenExrMultiLayerOperation::initExecution()
void OutputOpenExrMultiLayerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
{
- for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
+ for (unsigned int i = 0; i < this->m_layers.size(); i++) {
OutputOpenExrLayer &layer = this->m_layers[i];
if (layer.imageInput) {
write_buffer_rect(rect,
@@ -343,7 +343,7 @@ void OutputOpenExrMultiLayerOperation::deinitExecution()
suffix);
BLI_make_existing_file(filename);
- for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
+ for (unsigned int i = 0; i < this->m_layers.size(); i++) {
OutputOpenExrLayer &layer = this->m_layers[i];
if (!layer.imageInput) {
continue; /* skip unconnected sockets */
@@ -369,7 +369,7 @@ void OutputOpenExrMultiLayerOperation::deinitExecution()
}
IMB_exr_close(exrhandle);
- for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
+ for (unsigned int i = 0; i < this->m_layers.size(); i++) {
if (this->m_layers[i].outputBuffer) {
MEM_freeN(this->m_layers[i].outputBuffer);
this->m_layers[i].outputBuffer = NULL;
diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
index 313be2f5ecf..676601d82da 100644
--- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
@@ -60,7 +60,7 @@ static bool check_corners(float corners[4][2])
static void readCornersFromSockets(rcti *rect, SocketReader *readers[4], float corners[4][2])
{
- for (int i = 0; i < 4; ++i) {
+ for (int i = 0; i < 4; i++) {
float result[4] = {0.0f, 0.0f, 0.0f, 0.0f};
readers[i]->readSampled(result, rect->xmin, rect->ymin, COM_PS_NEAREST);
corners[i][0] = result[0];
@@ -208,7 +208,7 @@ void *PlaneCornerPinWarpImageOperation::initializeTileData(rcti *rect)
bool PlaneCornerPinWarpImageOperation::determineDependingAreaOfInterest(
rcti *input, ReadBufferOperation *readOperation, rcti *output)
{
- for (int i = 0; i < 4; ++i) {
+ for (int i = 0; i < 4; i++) {
if (getInputOperation(i + 1)->determineDependingAreaOfInterest(input, readOperation, output)) {
return true;
}
diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
index ef7dfbd4116..78a83391ed1 100644
--- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
@@ -105,7 +105,7 @@ void PlaneDistortWarpImageOperation::executePixelSampled(float output[4],
}
else {
zero_v4(output);
- for (int sample = 0; sample < this->m_motion_blur_samples; ++sample) {
+ for (int sample = 0; sample < this->m_motion_blur_samples; sample++) {
float color[4];
warpCoord(x, y, this->m_samples[sample].perspectiveMatrix, uv, deriv);
m_pixelReader->readFiltered(color, uv[0], uv[1], deriv[0], deriv[1]);
@@ -121,7 +121,7 @@ bool PlaneDistortWarpImageOperation::determineDependingAreaOfInterest(
float min[2], max[2];
INIT_MINMAX2(min, max);
- for (int sample = 0; sample < this->m_motion_blur_samples; ++sample) {
+ for (int sample = 0; sample < this->m_motion_blur_samples; sample++) {
float UVs[4][2];
float deriv[2][2];
MotionSample *sample_data = &this->m_samples[sample];
@@ -208,9 +208,9 @@ void PlaneDistortMaskOperation::executePixelSampled(float output[4],
output[0] = (float)inside_counter / this->m_osa;
}
else {
- for (int motion_sample = 0; motion_sample < this->m_motion_blur_samples; ++motion_sample) {
+ for (int motion_sample = 0; motion_sample < this->m_motion_blur_samples; motion_sample++) {
MotionSample *sample_data = &this->m_samples[motion_sample];
- for (int osa_sample = 0; osa_sample < this->m_osa; ++osa_sample) {
+ for (int osa_sample = 0; osa_sample < this->m_osa; osa_sample++) {
point[0] = x + this->m_jitter[osa_sample][0];
point[1] = y + this->m_jitter[osa_sample][1];
if (isect_point_tri_v2(point,
diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
index c2fe41eea1d..cbf5a25fa31 100644
--- a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
@@ -93,7 +93,7 @@ void PlaneTrackMaskOperation::initExecution()
const float frame = (float)this->m_framenumber - this->m_motion_blur_shutter;
const float frame_step = (this->m_motion_blur_shutter * 2.0f) / this->m_motion_blur_samples;
float frame_iter = frame;
- for (int sample = 0; sample < this->m_motion_blur_samples; ++sample) {
+ for (int sample = 0; sample < this->m_motion_blur_samples; sample++) {
readCornersFromTrack(corners, frame_iter);
calculateCorners(corners, true, sample);
frame_iter += frame_step;
@@ -116,7 +116,7 @@ void PlaneTrackWarpImageOperation::initExecution()
const float frame = (float)this->m_framenumber - this->m_motion_blur_shutter;
const float frame_step = (this->m_motion_blur_shutter * 2.0f) / this->m_motion_blur_samples;
float frame_iter = frame;
- for (int sample = 0; sample < this->m_motion_blur_samples; ++sample) {
+ for (int sample = 0; sample < this->m_motion_blur_samples; sample++) {
readCornersFromTrack(corners, frame_iter);
calculateCorners(corners, true, sample);
frame_iter += frame_step;
diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
index 738f7ed31ba..94224ac77a6 100644
--- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
@@ -148,7 +148,7 @@ void ScreenLensDistortionOperation::accumulate(MemoryBuffer *buffer,
float k4 = m_k4[a];
float dk4 = m_dk4[a];
- for (float z = 0; z < ds; ++z) {
+ for (float z = 0; z < ds; z++) {
float tz = (z + (m_jitter ? BLI_rng_get_float(m_rng) : 0.5f)) * sd;
float t = 1.0f - (k4 + tz * dk4) * r_sq;
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index 49c510d9d3e..21ab148496c 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -73,6 +73,7 @@ set(SRC
intern/depsgraph_query.cc
intern/depsgraph_query_foreach.cc
intern/depsgraph_query_iter.cc
+ intern/depsgraph_registry.cc
intern/depsgraph_tag.cc
intern/depsgraph_type.cc
intern/depsgraph_update.cc
@@ -107,6 +108,7 @@ set(SRC
intern/node/deg_node_time.h
intern/depsgraph.h
intern/depsgraph_physics.h
+ intern/depsgraph_registry.h
intern/depsgraph_tag.h
intern/depsgraph_type.h
intern/depsgraph_update.h
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index fd12f90016b..e44dddbcf54 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -87,7 +87,10 @@ extern "C" {
/* Create new Depsgraph instance */
// TODO: what args are needed here? What's the building-graph entry point?
-Depsgraph *DEG_graph_new(struct Scene *scene, struct ViewLayer *view_layer, eEvaluationMode mode);
+Depsgraph *DEG_graph_new(struct Main *bmain,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ eEvaluationMode mode);
/* Free Depsgraph itself and all its data */
void DEG_graph_free(Depsgraph *graph);
@@ -108,6 +111,8 @@ void DEG_graph_on_visible_update(struct Main *bmain, Depsgraph *depsgraph, const
/* Update all dependency graphs when visible scenes/layers changes. */
void DEG_on_visible_update(struct Main *bmain, const bool do_time);
+/* NOTE: Will return NULL if the flag is not known, allowing to gracefully handle situations
+ * when recalc flag has been removed. */
const char *DEG_update_tag_as_string(IDRecalcFlag flag);
void DEG_id_tag_update(struct ID *id, int flag);
@@ -126,11 +131,6 @@ void DEG_id_type_tag(struct Main *bmain, short id_type);
void DEG_ids_clear_recalc(struct Main *bmain, Depsgraph *depsgraph);
-/* Update Flushing ------------------------------- */
-
-/* Flush updates for IDs in a single scene. */
-void DEG_graph_flush_update(struct Main *bmain, Depsgraph *depsgraph);
-
/* Check if something was changed in the database and inform
* editors about this.
*/
@@ -154,7 +154,7 @@ void DEG_evaluate_on_framechange(struct Main *bmain, Depsgraph *graph, float cti
/* Data changed recalculation entry point.
* < context_type: context to perform evaluation for
*/
-void DEG_evaluate_on_refresh(Depsgraph *graph);
+void DEG_evaluate_on_refresh(struct Main *bmain, Depsgraph *graph);
bool DEG_needs_eval(Depsgraph *graph);
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index 37dfaf2c3e2..e24fa9e8996 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -74,6 +74,13 @@ void DEG_graph_build_for_compositor_preview(struct Depsgraph *graph,
struct ViewLayer *view_layer,
struct bNodeTree *nodetree);
+void DEG_graph_build_from_ids(struct Depsgraph *graph,
+ struct Main *bmain,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ struct ID **ids,
+ const int num_ids);
+
/* Tag relations from the given graph for update. */
void DEG_graph_tag_relations_update(struct Depsgraph *graph);
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index 82f7f33411a..fb456611b15 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -236,9 +236,21 @@ void DEG_foreach_dependent_ID(const Depsgraph *depsgraph,
/* Starts traversal from given component of the given ID, invokes callback for every other
* component which is directly on indirectly dependent on the source one. */
+enum {
+ /* Ignore transform solvers which depends on multiple inputs and affects final transform.
+ * Is used for cases like snapping objects which are part of a rigid body simulation:
+ * without this there will be "false-positive" dependencies between transform components of
+ * objects:
+ *
+ * object 1 transform before solver ---> solver ------> object 1 final transform
+ * object 2 transform before solver -----^ \------> object 2 final transform
+ */
+ DEG_FOREACH_COMPONENT_IGNORE_TRANSFORM_SOLVERS,
+};
void DEG_foreach_dependent_ID_component(const Depsgraph *depsgraph,
const ID *id,
eDepsObjectComponentType source_component_type,
+ int flags,
DEGForeachIDComponentCallback callback,
void *user_data);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index 4cbdd169980..4ca7240abd1 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -74,6 +74,10 @@ DepsgraphBuilder::DepsgraphBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuild
{
}
+DepsgraphBuilder::~DepsgraphBuilder()
+{
+}
+
bool DepsgraphBuilder::need_pull_base_into_graph(Base *base)
{
/* Simple check: enabled bases are always part of dependency graph. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h
index 040bb6cfeea..97e12e9ceb2 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder.h
@@ -35,11 +35,13 @@ class DepsgraphBuilderCache;
class DepsgraphBuilder {
public:
- bool need_pull_base_into_graph(Base *base);
+ virtual ~DepsgraphBuilder();
- bool check_pchan_has_bbone(Object *object, const bPoseChannel *pchan);
- bool check_pchan_has_bbone_segments(Object *object, const bPoseChannel *pchan);
- bool check_pchan_has_bbone_segments(Object *object, const char *bone_name);
+ virtual bool need_pull_base_into_graph(Base *base);
+
+ virtual bool check_pchan_has_bbone(Object *object, const bPoseChannel *pchan);
+ virtual bool check_pchan_has_bbone_segments(Object *object, const bPoseChannel *pchan);
+ virtual bool check_pchan_has_bbone_segments(Object *object, const char *bone_name);
protected:
/* NOTE: The builder does NOT take ownership over any of those resources. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
index d11a60b77dd..bea59eceea2 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
@@ -149,7 +149,7 @@ bool check_relation_can_murder(Relation *relation)
Relation *select_relation_to_murder(Relation *relation, StackEntry *cycle_start_entry)
{
- /* More or less russian roulette solver, which will make sure only
+ /* More or less Russian roulette solver, which will make sure only
* specially marked relations are kept alive.
*
* TODO(sergey): There might be better strategies here. */
@@ -176,7 +176,7 @@ void solve_cycles(CyclesSolverState *state)
OperationNode *node = entry->node;
bool all_child_traversed = true;
const int num_visited = get_node_num_visited_children(node);
- for (int i = num_visited; i < node->outlinks.size(); ++i) {
+ for (int i = num_visited; i < node->outlinks.size(); i++) {
Relation *rel = node->outlinks[i];
if (rel->to->type == NodeType::OPERATION) {
OperationNode *to = (OperationNode *)rel->to;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index fd4c1e251e4..7dfc863b847 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -609,12 +609,8 @@ void DepsgraphNodeBuilder::build_object(int base_index,
build_particle_systems(object, is_visible);
}
/* Proxy object to copy from. */
- if (object->proxy_from != NULL) {
- build_object(-1, object->proxy_from, DEG_ID_LINKED_INDIRECTLY, is_visible);
- }
- if (object->proxy_group != NULL) {
- build_object(-1, object->proxy_group, DEG_ID_LINKED_INDIRECTLY, is_visible);
- }
+ build_object_proxy_from(object, is_visible);
+ build_object_proxy_group(object, is_visible);
/* Object dupligroup. */
if (object->instance_collection != NULL) {
const bool is_current_parent_collection_visible = is_parent_collection_visible_;
@@ -653,6 +649,22 @@ void DepsgraphNodeBuilder::build_object_flags(int base_index,
is_from_set));
}
+void DepsgraphNodeBuilder::build_object_proxy_from(Object *object, bool is_visible)
+{
+ if (object->proxy_from == NULL) {
+ return;
+ }
+ build_object(-1, object->proxy_from, DEG_ID_LINKED_INDIRECTLY, is_visible);
+}
+
+void DepsgraphNodeBuilder::build_object_proxy_group(Object *object, bool is_visible)
+{
+ if (object->proxy_group == NULL) {
+ return;
+ }
+ build_object(-1, object->proxy_group, DEG_ID_LINKED_INDIRECTLY, is_visible);
+}
+
void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visible)
{
if (object->data == NULL) {
@@ -900,19 +912,17 @@ void DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcurve, int driver_index
{
/* Create data node for this driver */
ID *id_cow = get_cow_id(id);
- ChannelDriver *driver_orig = fcurve->driver;
/* TODO(sergey): ideally we could pass the COW of fcu, but since it
* has not yet been allocated at this point we can't. As a workaround
* the animation systems allocates an array so we can do a fast lookup
* with the driver index. */
- ensure_operation_node(
- id,
- NodeType::PARAMETERS,
- OperationCode::DRIVER,
- function_bind(BKE_animsys_eval_driver, _1, id_cow, driver_index, driver_orig),
- fcurve->rna_path ? fcurve->rna_path : "",
- fcurve->array_index);
+ ensure_operation_node(id,
+ NodeType::PARAMETERS,
+ OperationCode::DRIVER,
+ function_bind(BKE_animsys_eval_driver, _1, id_cow, driver_index, fcurve),
+ fcurve->rna_path ? fcurve->rna_path : "",
+ fcurve->array_index);
build_driver_variables(id, fcurve);
}
@@ -1155,7 +1165,7 @@ void DepsgraphNodeBuilder::build_particle_settings(ParticleSettings *particle_se
&particle_settings->id, NodeType::PARTICLE_SETTINGS, OperationCode::PARTICLE_SETTINGS_EVAL);
op_node->set_as_exit();
/* Texture slots. */
- for (int mtex_index = 0; mtex_index < MAX_MTEX; ++mtex_index) {
+ for (int mtex_index = 0; mtex_index < MAX_MTEX; mtex_index++) {
MTex *mtex = particle_settings->mtex[mtex_index];
if (mtex == NULL || mtex->tex == NULL) {
continue;
@@ -1436,7 +1446,7 @@ void DepsgraphNodeBuilder::build_material(Material *material)
void DepsgraphNodeBuilder::build_materials(Material **materials, int num_materials)
{
- for (int i = 0; i < num_materials; ++i) {
+ for (int i = 0; i < num_materials; i++) {
if (materials[i] == NULL) {
continue;
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index 65f3521b556..865f60432c1 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -93,8 +93,8 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
return (T *)cow->id.orig_id;
}
- void begin_build();
- void end_build();
+ virtual void begin_build();
+ virtual void end_build();
IDNode *add_id_node(ID *id);
IDNode *find_id_node(ID *id);
@@ -145,71 +145,75 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
OperationNode *find_operation_node(
ID *id, NodeType comp_type, OperationCode opcode, const char *name = "", int name_tag = -1);
- void build_id(ID *id);
+ virtual void build_id(ID *id);
- void build_scene_render(Scene *scene, ViewLayer *view_layer);
- void build_scene_parameters(Scene *scene);
- void build_scene_compositor(Scene *scene);
+ virtual void build_scene_render(Scene *scene, ViewLayer *view_layer);
+ virtual void build_scene_parameters(Scene *scene);
+ virtual void build_scene_compositor(Scene *scene);
- void build_layer_collections(ListBase *lb);
- void build_view_layer(Scene *scene,
- ViewLayer *view_layer,
- eDepsNode_LinkedState_Type linked_state);
- void build_collection(LayerCollection *from_layer_collection, Collection *collection);
- void build_object(int base_index,
- Object *object,
- eDepsNode_LinkedState_Type linked_state,
- bool is_visible);
- void build_object_flags(int base_index, Object *object, eDepsNode_LinkedState_Type linked_state);
- void build_object_data(Object *object, bool is_object_visible);
- void build_object_data_camera(Object *object);
- void build_object_data_geometry(Object *object, bool is_object_visible);
- void build_object_data_geometry_datablock(ID *obdata, bool is_object_visible);
- void build_object_data_light(Object *object);
- void build_object_data_lightprobe(Object *object);
- void build_object_data_speaker(Object *object);
- void build_object_transform(Object *object);
- void build_object_constraints(Object *object);
- void build_object_pointcache(Object *object);
- void build_pose_constraints(Object *object,
- bPoseChannel *pchan,
- int pchan_index,
- bool is_object_visible);
- void build_rigidbody(Scene *scene);
- void build_particle_systems(Object *object, bool is_object_visible);
- void build_particle_settings(ParticleSettings *part);
- void build_animdata(ID *id);
- void build_animdata_nlastrip_targets(ListBase *strips);
- void build_animation_images(ID *id);
- void build_action(bAction *action);
- void build_driver(ID *id, FCurve *fcurve, int driver_index);
- void build_driver_variables(ID *id, FCurve *fcurve);
- void build_driver_id_property(ID *id, const char *rna_path);
- void build_parameters(ID *id);
- void build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
- void build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
- void build_rig(Object *object, bool is_object_visible);
- void build_proxy_rig(Object *object);
- void build_armature(bArmature *armature);
- void build_shapekeys(Key *key);
- void build_camera(Camera *camera);
- void build_light(Light *lamp);
- void build_nodetree(bNodeTree *ntree);
- void build_material(Material *ma);
- void build_materials(Material **materials, int num_materials);
- void build_texture(Tex *tex);
- void build_image(Image *image);
- void build_world(World *world);
- void build_gpencil(bGPdata *gpd);
- void build_cachefile(CacheFile *cache_file);
- void build_mask(Mask *mask);
- void build_movieclip(MovieClip *clip);
- void build_lightprobe(LightProbe *probe);
- void build_speaker(Speaker *speaker);
- void build_sound(bSound *sound);
- void build_scene_sequencer(Scene *scene);
- void build_scene_audio(Scene *scene);
- void build_scene_speakers(Scene *scene, ViewLayer *view_layer);
+ virtual void build_layer_collections(ListBase *lb);
+ virtual void build_view_layer(Scene *scene,
+ ViewLayer *view_layer,
+ eDepsNode_LinkedState_Type linked_state);
+ virtual void build_collection(LayerCollection *from_layer_collection, Collection *collection);
+ virtual void build_object(int base_index,
+ Object *object,
+ eDepsNode_LinkedState_Type linked_state,
+ bool is_visible);
+ virtual void build_object_proxy_from(Object *object, bool is_object_visible);
+ virtual void build_object_proxy_group(Object *object, bool is_object_visible);
+ virtual void build_object_flags(int base_index,
+ Object *object,
+ eDepsNode_LinkedState_Type linked_state);
+ virtual void build_object_data(Object *object, bool is_object_visible);
+ virtual void build_object_data_camera(Object *object);
+ virtual void build_object_data_geometry(Object *object, bool is_object_visible);
+ virtual void build_object_data_geometry_datablock(ID *obdata, bool is_object_visible);
+ virtual void build_object_data_light(Object *object);
+ virtual void build_object_data_lightprobe(Object *object);
+ virtual void build_object_data_speaker(Object *object);
+ virtual void build_object_transform(Object *object);
+ virtual void build_object_constraints(Object *object);
+ virtual void build_object_pointcache(Object *object);
+ virtual void build_pose_constraints(Object *object,
+ bPoseChannel *pchan,
+ int pchan_index,
+ bool is_object_visible);
+ virtual void build_rigidbody(Scene *scene);
+ virtual void build_particle_systems(Object *object, bool is_object_visible);
+ virtual void build_particle_settings(ParticleSettings *part);
+ virtual void build_animdata(ID *id);
+ virtual void build_animdata_nlastrip_targets(ListBase *strips);
+ virtual void build_animation_images(ID *id);
+ virtual void build_action(bAction *action);
+ virtual void build_driver(ID *id, FCurve *fcurve, int driver_index);
+ virtual void build_driver_variables(ID *id, FCurve *fcurve);
+ virtual void build_driver_id_property(ID *id, const char *rna_path);
+ virtual void build_parameters(ID *id);
+ virtual void build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
+ virtual void build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
+ virtual void build_rig(Object *object, bool is_object_visible);
+ virtual void build_proxy_rig(Object *object);
+ virtual void build_armature(bArmature *armature);
+ virtual void build_shapekeys(Key *key);
+ virtual void build_camera(Camera *camera);
+ virtual void build_light(Light *lamp);
+ virtual void build_nodetree(bNodeTree *ntree);
+ virtual void build_material(Material *ma);
+ virtual void build_materials(Material **materials, int num_materials);
+ virtual void build_texture(Tex *tex);
+ virtual void build_image(Image *image);
+ virtual void build_world(World *world);
+ virtual void build_gpencil(bGPdata *gpd);
+ virtual void build_cachefile(CacheFile *cache_file);
+ virtual void build_mask(Mask *mask);
+ virtual void build_movieclip(MovieClip *clip);
+ virtual void build_lightprobe(LightProbe *probe);
+ virtual void build_speaker(Speaker *speaker);
+ virtual void build_sound(bSound *sound);
+ virtual void build_scene_sequencer(Scene *scene);
+ virtual void build_scene_audio(Scene *scene);
+ virtual void build_scene_speakers(Scene *scene, ViewLayer *view_layer);
/* Per-ID information about what was already in the dependency graph.
* Allows to re-use certain values, to speed up following evaluation. */
@@ -259,7 +263,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
/* NOTE: Collection are possibly built recursively, so be careful when
* setting the current state. */
Collection *collection_;
- /* Accumulated flag over the hierarchy opf currently building collections.
+ /* Accumulated flag over the hierarchy of currently building collections.
* Denotes whether all the hierarchy from parent of collection_ to the
* very root is visible (aka not restricted.). */
bool is_parent_collection_visible_;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
index 2f6b8c0ba6b..88ebf1c9b50 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
@@ -105,7 +105,7 @@ void DepsgraphNodeBuilder::build_view_layer(Scene *scene,
*
* TODO(sergey): Need to go more granular on visibility checks. */
build_object(base_index, base->object, linked_state, true);
- ++base_index;
+ base_index++;
}
}
build_layer_collections(&view_layer->layer_collections);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index ba6a4756313..f1e7278ffdb 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -657,20 +657,8 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
build_particle_systems(object);
}
/* Proxy object to copy from. */
- if (object->proxy_from != NULL) {
- /* Object is linked here (comes from the library). */
- build_object(NULL, object->proxy_from);
- ComponentKey ob_transform_key(&object->proxy_from->id, NodeType::TRANSFORM);
- ComponentKey proxy_transform_key(&object->id, NodeType::TRANSFORM);
- add_relation(ob_transform_key, proxy_transform_key, "Proxy Transform");
- }
- if (object->proxy_group != NULL && object->proxy_group != object->proxy) {
- /* Object is local here (local in .blend file, users interacts with it). */
- build_object(NULL, object->proxy_group);
- OperationKey proxy_group_eval_key(
- &object->proxy_group->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL);
- add_relation(proxy_group_eval_key, transform_eval_key, "Proxy Group Transform");
- }
+ build_object_proxy_from(object);
+ build_object_proxy_group(object);
/* Object dupligroup. */
if (object->instance_collection != NULL) {
build_collection(NULL, object, object->instance_collection);
@@ -685,6 +673,31 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
build_parameters(&object->id);
}
+void DepsgraphRelationBuilder::build_object_proxy_from(Object *object)
+{
+ if (object->proxy_from == NULL) {
+ return;
+ }
+ /* Object is linked here (comes from the library). */
+ build_object(NULL, object->proxy_from);
+ ComponentKey ob_transform_key(&object->proxy_from->id, NodeType::TRANSFORM);
+ ComponentKey proxy_transform_key(&object->id, NodeType::TRANSFORM);
+ add_relation(ob_transform_key, proxy_transform_key, "Proxy Transform");
+}
+
+void DepsgraphRelationBuilder::build_object_proxy_group(Object *object)
+{
+ if (object->proxy_group == NULL || object->proxy_group == object->proxy) {
+ return;
+ }
+ /* Object is local here (local in .blend file, users interacts with it). */
+ build_object(NULL, object->proxy_group);
+ OperationKey proxy_group_eval_key(
+ &object->proxy_group->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL);
+ OperationKey transform_eval_key(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL);
+ add_relation(proxy_group_eval_key, transform_eval_key, "Proxy Group Transform");
+}
+
void DepsgraphRelationBuilder::build_object_flags(Base *base, Object *object)
{
if (base == NULL) {
@@ -807,13 +820,25 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object)
{
Object *parent = object->parent;
ID *parent_id = &object->parent->id;
- ComponentKey ob_key(&object->id, NodeType::TRANSFORM);
- /* Type-specific links/ */
+ ComponentKey object_transform_key(&object->id, NodeType::TRANSFORM);
+ /* Type-specific links. */
switch (object->partype) {
/* Armature Deform (Virtual Modifier) */
case PARSKEL: {
- ComponentKey parent_key(parent_id, NodeType::TRANSFORM);
- add_relation(parent_key, ob_key, "Armature Deform Parent");
+ ComponentKey parent_transform_key(parent_id, NodeType::TRANSFORM);
+ add_relation(parent_transform_key, object_transform_key, "Parent Armature Transform");
+
+ if (parent->type == OB_ARMATURE) {
+ ComponentKey object_geometry_key(&object->id, NodeType::GEOMETRY);
+ ComponentKey parent_pose_key(parent_id, NodeType::EVAL_POSE);
+ add_relation(
+ parent_transform_key, object_geometry_key, "Parent Armature Transform -> Geometry");
+ add_relation(parent_pose_key, object_geometry_key, "Parent Armature Pose -> Geometry");
+
+ add_depends_on_transform_relation(
+ &object->id, object_geometry_key, "Virtual Armature Modifier");
+ }
+
break;
}
@@ -821,7 +846,7 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object)
case PARVERT1:
case PARVERT3: {
ComponentKey parent_key(parent_id, NodeType::GEOMETRY);
- add_relation(parent_key, ob_key, "Vertex Parent");
+ add_relation(parent_key, object_transform_key, "Vertex Parent");
/* Original index is used for optimizations of lookups for subdiv
* only meshes.
* TODO(sergey): This optimization got lost at 2.8, so either verify
@@ -833,7 +858,7 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object)
DEGCustomDataMeshMasks::MaskFace(CD_MASK_ORIGINDEX) |
DEGCustomDataMeshMasks::MaskPoly(CD_MASK_ORIGINDEX));
ComponentKey transform_key(parent_id, NodeType::TRANSFORM);
- add_relation(transform_key, ob_key, "Vertex Parent TFM");
+ add_relation(transform_key, object_transform_key, "Vertex Parent TFM");
break;
}
@@ -842,8 +867,8 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object)
ComponentKey parent_bone_key(parent_id, NodeType::BONE, object->parsubstr);
OperationKey parent_transform_key(
parent_id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL);
- add_relation(parent_bone_key, ob_key, "Bone Parent");
- add_relation(parent_transform_key, ob_key, "Armature Parent");
+ add_relation(parent_bone_key, object_transform_key, "Bone Parent");
+ add_relation(parent_transform_key, object_transform_key, "Armature Parent");
break;
}
@@ -852,8 +877,8 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object)
/* Lattice Deform Parent - Virtual Modifier. */
ComponentKey parent_key(parent_id, NodeType::TRANSFORM);
ComponentKey geom_key(parent_id, NodeType::GEOMETRY);
- add_relation(parent_key, ob_key, "Lattice Deform Parent");
- add_relation(geom_key, ob_key, "Lattice Deform Parent Geom");
+ add_relation(parent_key, object_transform_key, "Lattice Deform Parent");
+ add_relation(geom_key, object_transform_key, "Lattice Deform Parent Geom");
}
else if (object->parent->type == OB_CURVE) {
Curve *cu = (Curve *)object->parent->data;
@@ -861,20 +886,20 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object)
if (cu->flag & CU_PATH) {
/* Follow Path. */
ComponentKey parent_key(parent_id, NodeType::GEOMETRY);
- add_relation(parent_key, ob_key, "Curve Follow Parent");
+ add_relation(parent_key, object_transform_key, "Curve Follow Parent");
ComponentKey transform_key(parent_id, NodeType::TRANSFORM);
- add_relation(transform_key, ob_key, "Curve Follow TFM");
+ add_relation(transform_key, object_transform_key, "Curve Follow TFM");
}
else {
/* Standard Parent. */
ComponentKey parent_key(parent_id, NodeType::TRANSFORM);
- add_relation(parent_key, ob_key, "Curve Parent");
+ add_relation(parent_key, object_transform_key, "Curve Parent");
}
}
else {
/* Standard Parent. */
ComponentKey parent_key(parent_id, NodeType::TRANSFORM);
- add_relation(parent_key, ob_key, "Parent");
+ add_relation(parent_key, object_transform_key, "Parent");
}
break;
}
@@ -887,7 +912,7 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object)
ComponentKey parent_geometry_key(parent_id, NodeType::GEOMETRY);
/* NOTE: Metaballs are evaluating geometry only after their transform,
* so we only hook up to transform channel here. */
- add_relation(parent_geometry_key, ob_key, "Parent");
+ add_relation(parent_geometry_key, object_transform_key, "Parent");
}
/* Dupliverts uses original vertex index. */
@@ -1797,7 +1822,7 @@ void DepsgraphRelationBuilder::build_particle_settings(ParticleSettings *part)
particle_settings_init_key, particle_settings_eval_key, "Particle Settings Init Order");
add_relation(particle_settings_reset_key, particle_settings_eval_key, "Particle Settings Reset");
/* Texture slots. */
- for (int mtex_index = 0; mtex_index < MAX_MTEX; ++mtex_index) {
+ for (int mtex_index = 0; mtex_index < MAX_MTEX; mtex_index++) {
MTex *mtex = part->mtex[mtex_index];
if (mtex == NULL || mtex->tex == NULL) {
continue;
@@ -2246,7 +2271,7 @@ void DepsgraphRelationBuilder::build_material(Material *material)
void DepsgraphRelationBuilder::build_materials(Material **materials, int num_materials)
{
- for (int i = 0; i < num_materials; ++i) {
+ for (int i = 0; i < num_materials; i++) {
if (materials[i] == NULL) {
continue;
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index e58ef989ac9..c6a0014577f 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -191,93 +191,95 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
void add_customdata_mask(Object *object, const DEGCustomDataMeshMasks &customdata_masks);
void add_special_eval_flag(ID *object, uint32_t flag);
- void build_id(ID *id);
-
- void build_scene_render(Scene *scene, ViewLayer *view_layer);
- void build_scene_parameters(Scene *scene);
- void build_scene_compositor(Scene *scene);
-
- void build_layer_collections(ListBase *lb);
- void build_view_layer(Scene *scene,
- ViewLayer *view_layer,
- eDepsNode_LinkedState_Type linked_state);
- void build_collection(LayerCollection *from_layer_collection,
- Object *object,
- Collection *collection);
- void build_object(Base *base, Object *object);
- void build_object_flags(Base *base, Object *object);
- void build_object_data(Object *object);
- void build_object_data_camera(Object *object);
- void build_object_data_geometry(Object *object);
- void build_object_data_geometry_datablock(ID *obdata);
- void build_object_data_light(Object *object);
- void build_object_data_lightprobe(Object *object);
- void build_object_data_speaker(Object *object);
- void build_object_parent(Object *object);
- void build_object_pointcache(Object *object);
- void build_constraints(ID *id,
- NodeType component_type,
- const char *component_subdata,
- ListBase *constraints,
- RootPChanMap *root_map);
- void build_animdata(ID *id);
- void build_animdata_curves(ID *id);
- void build_animdata_curves_targets(ID *id,
- ComponentKey &adt_key,
- OperationNode *operation_from,
- ListBase *curves);
- void build_animdata_nlastrip_targets(ID *id,
- ComponentKey &adt_key,
- OperationNode *operation_from,
- ListBase *strips);
- void build_animdata_drivers(ID *id);
- void build_animation_images(ID *id);
- void build_action(bAction *action);
- void build_driver(ID *id, FCurve *fcurve);
- void build_driver_data(ID *id, FCurve *fcurve);
- void build_driver_variables(ID *id, FCurve *fcurve);
- void build_driver_id_property(ID *id, const char *rna_path);
- void build_parameters(ID *id);
- void build_world(World *world);
- void build_rigidbody(Scene *scene);
- void build_particle_systems(Object *object);
- void build_particle_settings(ParticleSettings *part);
- void build_particle_system_visualization_object(Object *object,
- ParticleSystem *psys,
- Object *draw_object);
- void build_ik_pose(Object *object,
- bPoseChannel *pchan,
- bConstraint *con,
- RootPChanMap *root_map);
- void build_splineik_pose(Object *object,
- bPoseChannel *pchan,
- bConstraint *con,
- RootPChanMap *root_map);
- void build_rig(Object *object);
- void build_proxy_rig(Object *object);
- void build_shapekeys(Key *key);
- void build_armature(bArmature *armature);
- void build_camera(Camera *camera);
- void build_light(Light *lamp);
- void build_nodetree(bNodeTree *ntree);
- void build_material(Material *ma);
- void build_materials(Material **materials, int num_materials);
- void build_texture(Tex *tex);
- void build_image(Image *image);
- void build_gpencil(bGPdata *gpd);
- void build_cachefile(CacheFile *cache_file);
- void build_mask(Mask *mask);
- void build_movieclip(MovieClip *clip);
- void build_lightprobe(LightProbe *probe);
- void build_speaker(Speaker *speaker);
- void build_sound(bSound *sound);
- void build_scene_sequencer(Scene *scene);
- void build_scene_audio(Scene *scene);
- void build_scene_speakers(Scene *scene, ViewLayer *view_layer);
-
- void build_nested_datablock(ID *owner, ID *id);
- void build_nested_nodetree(ID *owner, bNodeTree *ntree);
- void build_nested_shapekey(ID *owner, Key *key);
+ virtual void build_id(ID *id);
+
+ virtual void build_scene_render(Scene *scene, ViewLayer *view_layer);
+ virtual void build_scene_parameters(Scene *scene);
+ virtual void build_scene_compositor(Scene *scene);
+
+ virtual void build_layer_collections(ListBase *lb);
+ virtual void build_view_layer(Scene *scene,
+ ViewLayer *view_layer,
+ eDepsNode_LinkedState_Type linked_state);
+ virtual void build_collection(LayerCollection *from_layer_collection,
+ Object *object,
+ Collection *collection);
+ virtual void build_object(Base *base, Object *object);
+ virtual void build_object_proxy_from(Object *object);
+ virtual void build_object_proxy_group(Object *object);
+ virtual void build_object_flags(Base *base, Object *object);
+ virtual void build_object_data(Object *object);
+ virtual void build_object_data_camera(Object *object);
+ virtual void build_object_data_geometry(Object *object);
+ virtual void build_object_data_geometry_datablock(ID *obdata);
+ virtual void build_object_data_light(Object *object);
+ virtual void build_object_data_lightprobe(Object *object);
+ virtual void build_object_data_speaker(Object *object);
+ virtual void build_object_parent(Object *object);
+ virtual void build_object_pointcache(Object *object);
+ virtual void build_constraints(ID *id,
+ NodeType component_type,
+ const char *component_subdata,
+ ListBase *constraints,
+ RootPChanMap *root_map);
+ virtual void build_animdata(ID *id);
+ virtual void build_animdata_curves(ID *id);
+ virtual void build_animdata_curves_targets(ID *id,
+ ComponentKey &adt_key,
+ OperationNode *operation_from,
+ ListBase *curves);
+ virtual void build_animdata_nlastrip_targets(ID *id,
+ ComponentKey &adt_key,
+ OperationNode *operation_from,
+ ListBase *strips);
+ virtual void build_animdata_drivers(ID *id);
+ virtual void build_animation_images(ID *id);
+ virtual void build_action(bAction *action);
+ virtual void build_driver(ID *id, FCurve *fcurve);
+ virtual void build_driver_data(ID *id, FCurve *fcurve);
+ virtual void build_driver_variables(ID *id, FCurve *fcurve);
+ virtual void build_driver_id_property(ID *id, const char *rna_path);
+ virtual void build_parameters(ID *id);
+ virtual void build_world(World *world);
+ virtual void build_rigidbody(Scene *scene);
+ virtual void build_particle_systems(Object *object);
+ virtual void build_particle_settings(ParticleSettings *part);
+ virtual void build_particle_system_visualization_object(Object *object,
+ ParticleSystem *psys,
+ Object *draw_object);
+ virtual void build_ik_pose(Object *object,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ RootPChanMap *root_map);
+ virtual void build_splineik_pose(Object *object,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ RootPChanMap *root_map);
+ virtual void build_rig(Object *object);
+ virtual void build_proxy_rig(Object *object);
+ virtual void build_shapekeys(Key *key);
+ virtual void build_armature(bArmature *armature);
+ virtual void build_camera(Camera *camera);
+ virtual void build_light(Light *lamp);
+ virtual void build_nodetree(bNodeTree *ntree);
+ virtual void build_material(Material *ma);
+ virtual void build_materials(Material **materials, int num_materials);
+ virtual void build_texture(Tex *tex);
+ virtual void build_image(Image *image);
+ virtual void build_gpencil(bGPdata *gpd);
+ virtual void build_cachefile(CacheFile *cache_file);
+ virtual void build_mask(Mask *mask);
+ virtual void build_movieclip(MovieClip *clip);
+ virtual void build_lightprobe(LightProbe *probe);
+ virtual void build_speaker(Speaker *speaker);
+ virtual void build_sound(bSound *sound);
+ virtual void build_scene_sequencer(Scene *scene);
+ virtual void build_scene_audio(Scene *scene);
+ virtual void build_scene_speakers(Scene *scene, ViewLayer *view_layer);
+
+ virtual void build_nested_datablock(ID *owner, ID *id);
+ virtual void build_nested_nodetree(ID *owner, bNodeTree *ntree);
+ virtual void build_nested_shapekey(ID *owner, Key *key);
void add_particle_collision_relations(const OperationKey &key,
Object *object,
@@ -290,8 +292,8 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
bool add_absorption,
const char *name);
- void build_copy_on_write_relations();
- void build_copy_on_write_relations(IDNode *id_node);
+ virtual void build_copy_on_write_relations();
+ virtual void build_copy_on_write_relations(IDNode *id_node);
template<typename KeyType> OperationNode *find_operation_node(const KeyType &key);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
index d3ae3da9b56..180499519f6 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
@@ -211,7 +211,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
}
/* Final transform properties go to the Done node for the exit. */
else if (STREQ(prop_name, "head") || STREQ(prop_name, "tail") ||
- STRPREFIX(prop_name, "matrix")) {
+ STREQ(prop_name, "length") || STRPREFIX(prop_name, "matrix")) {
if (source == RNAPointerSource::EXIT) {
node_identifier.operation_code = OperationCode::BONE_DONE;
}
@@ -280,7 +280,11 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
else if (RNA_struct_is_a(ptr->type, &RNA_Mesh) || RNA_struct_is_a(ptr->type, &RNA_Modifier) ||
RNA_struct_is_a(ptr->type, &RNA_GpencilModifier) ||
RNA_struct_is_a(ptr->type, &RNA_Spline) || RNA_struct_is_a(ptr->type, &RNA_TextBox) ||
- RNA_struct_is_a(ptr->type, &RNA_GPencilLayer)) {
+ RNA_struct_is_a(ptr->type, &RNA_GPencilLayer) ||
+ RNA_struct_is_a(ptr->type, &RNA_LatticePoint) ||
+ RNA_struct_is_a(ptr->type, &RNA_MeshUVLoop) ||
+ RNA_struct_is_a(ptr->type, &RNA_MeshLoopColor) ||
+ RNA_struct_is_a(ptr->type, &RNA_VertexGroupElement)) {
/* When modifier is used as FROM operation this is likely referencing to
* the property (for example, modifier's influence).
* But when it's used as TO operation, this is geometry component. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
index 3e5e96d30ff..13cf8e63832 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
@@ -97,7 +97,7 @@ void deg_graph_transitive_reduction(Depsgraph *graph)
else if (rel->from->custom_flags & OP_REACHABLE) {
rel->unlink();
OBJECT_GUARDED_DELETE(rel, Relation);
- ++num_removed_relations;
+ num_removed_relations++;
}
else {
++it_rel;
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
index 9c4a672b805..ee3959a0861 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
@@ -144,7 +144,7 @@ static int deg_debug_node_color_index(const Node *node)
#ifdef COLOR_SCHEME_NODE_TYPE
const int(*pair)[2];
- for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
+ for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; pair++) {
if ((*pair)[0] == node->type) {
return (*pair)[1];
}
@@ -197,7 +197,7 @@ static void deg_debug_graphviz_legend(const DebugContext &ctx)
#ifdef COLOR_SCHEME_NODE_TYPE
const int(*pair)[2];
- for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
+ for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; pair++) {
DepsNodeFactory *nti = type_get_factory((NodeType)(*pair)[0]);
deg_debug_graphviz_legend_color(
ctx, nti->tname().c_str(), deg_debug_colors_light[(*pair)[1] % deg_debug_max_colors]);
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc
index b4cf30685a2..4a668e817fe 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc
@@ -85,7 +85,7 @@ string gnuplotify_name(const string &name)
{
string result = "";
const int length = name.length();
- for (int i = 0; i < length; ++i) {
+ for (int i = 0; i < length; i++) {
const char ch = name[i];
if (ch == '_') {
result += "\\\\\\";
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 6d3aed65a14..dcdea87fe1a 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -45,6 +45,8 @@ extern "C" {
#include "DEG_depsgraph_debug.h"
#include "intern/depsgraph_update.h"
+#include "intern/depsgraph_physics.h"
+#include "intern/depsgraph_registry.h"
#include "intern/eval/deg_eval_copy_on_write.h"
@@ -55,8 +57,6 @@ extern "C" {
#include "intern/node/deg_node_operation.h"
#include "intern/node/deg_node_time.h"
-#include "intern/depsgraph_physics.h"
-
namespace DEG {
/* TODO(sergey): Find a better place for this. */
@@ -65,10 +65,11 @@ template<typename T> static void remove_from_vector(vector<T> *vector, const T &
vector->erase(std::remove(vector->begin(), vector->end(), value), vector->end());
}
-Depsgraph::Depsgraph(Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
+Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
: time_source(NULL),
need_update(true),
need_update_time(false),
+ bmain(bmain),
scene(scene),
view_layer(view_layer),
mode(mode),
@@ -313,17 +314,23 @@ ID *Depsgraph::get_cow_id(const ID *id_orig) const
/* Public Graph API */
/* Initialize a new Depsgraph */
-Depsgraph *DEG_graph_new(Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
+Depsgraph *DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
{
- DEG::Depsgraph *deg_depsgraph = OBJECT_GUARDED_NEW(DEG::Depsgraph, scene, view_layer, mode);
+ DEG::Depsgraph *deg_depsgraph = OBJECT_GUARDED_NEW(
+ DEG::Depsgraph, bmain, scene, view_layer, mode);
+ DEG::register_graph(deg_depsgraph);
return reinterpret_cast<Depsgraph *>(deg_depsgraph);
}
/* Free graph's contents and graph itself */
void DEG_graph_free(Depsgraph *graph)
{
+ if (graph == NULL) {
+ return;
+ }
using DEG::Depsgraph;
DEG::Depsgraph *deg_depsgraph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ DEG::unregister_graph(deg_depsgraph);
OBJECT_GUARDED_DELETE(deg_depsgraph, Depsgraph);
}
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index 96b1a2a1f8a..30ae4edde34 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -100,7 +100,7 @@ struct Depsgraph {
typedef vector<OperationNode *> OperationNodes;
typedef vector<IDNode *> IDDepsNodes;
- Depsgraph(Scene *scene, ViewLayer *view_layer, eEvaluationMode mode);
+ Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode);
~Depsgraph();
TimeSourceNode *add_time_source();
@@ -172,7 +172,8 @@ struct Depsgraph {
* Mainly used by graph evaluation. */
SpinLock lock;
- /* Scene, layer, mode this dependency graph is built for. */
+ /* Main, scene, layer, mode this dependency graph is built for. */
+ Main *bmain;
Scene *scene;
ViewLayer *view_layer;
eEvaluationMode mode;
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index dd2d7f70ed5..f67ab381c79 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -59,6 +59,7 @@ extern "C" {
#include "intern/node/deg_node_id.h"
#include "intern/node/deg_node_operation.h"
+#include "intern/depsgraph_registry.h"
#include "intern/depsgraph_type.h"
/* ****************** */
@@ -323,6 +324,147 @@ void DEG_graph_build_for_compositor_preview(
}
}
+/* Optimized builders for dependency graph built from a given set of IDs.
+ *
+ * General notes:
+ *
+ * - We pull in all bases if their objects are in the set of IDs. This allows to have proper
+ * visibility and other flags assigned to the objects.
+ * All other bases (the ones which points to object which is outside of the set of IDs) are
+ * completely ignored.
+ *
+ * - Proxy groups pointing to objects which are outside of the IDs set are also ignored.
+ * This way we avoid high-poly character body pulled into the dependency graph when it's coming
+ * from a library into an animation file and the dependency graph constructed for a proxy rig. */
+
+namespace DEG {
+namespace {
+
+class DepsgraphFromIDsFilter {
+ public:
+ DepsgraphFromIDsFilter(ID **ids, const int num_ids)
+ {
+ for (int i = 0; i < num_ids; ++i) {
+ ids_.insert(ids[0]);
+ }
+ }
+
+ bool contains(ID *id)
+ {
+ return ids_.find(id) != ids_.end();
+ }
+
+ protected:
+ set<ID *> ids_;
+};
+
+class DepsgraphFromIDsNodeBuilder : public DepsgraphNodeBuilder {
+ public:
+ DepsgraphFromIDsNodeBuilder(
+ Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache, ID **ids, const int num_ids)
+ : DepsgraphNodeBuilder(bmain, graph, cache), filter_(ids, num_ids)
+ {
+ }
+
+ virtual bool need_pull_base_into_graph(Base *base) override
+ {
+ if (!filter_.contains(&base->object->id)) {
+ return false;
+ }
+ return DepsgraphNodeBuilder::need_pull_base_into_graph(base);
+ }
+
+ virtual void build_object_proxy_group(Object *object, bool is_visible) override
+ {
+ if (object->proxy_group == NULL) {
+ return;
+ }
+ if (!filter_.contains(&object->proxy_group->id)) {
+ return;
+ }
+ DepsgraphNodeBuilder::build_object_proxy_group(object, is_visible);
+ }
+
+ protected:
+ DepsgraphFromIDsFilter filter_;
+};
+
+class DepsgraphFromIDsRelationBuilder : public DepsgraphRelationBuilder {
+ public:
+ DepsgraphFromIDsRelationBuilder(
+ Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache, ID **ids, const int num_ids)
+ : DepsgraphRelationBuilder(bmain, graph, cache), filter_(ids, num_ids)
+ {
+ }
+
+ virtual bool need_pull_base_into_graph(Base *base) override
+ {
+ if (!filter_.contains(&base->object->id)) {
+ return false;
+ }
+ return DepsgraphRelationBuilder::need_pull_base_into_graph(base);
+ }
+
+ virtual void build_object_proxy_group(Object *object) override
+ {
+ if (object->proxy_group == NULL) {
+ return;
+ }
+ if (!filter_.contains(&object->proxy_group->id)) {
+ return;
+ }
+ DepsgraphRelationBuilder::build_object_proxy_group(object);
+ }
+
+ protected:
+ DepsgraphFromIDsFilter filter_;
+};
+
+} // namespace
+} // namespace DEG
+
+void DEG_graph_build_from_ids(Depsgraph *graph,
+ Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ ID **ids,
+ const int num_ids)
+{
+ double start_time = 0.0;
+ if (G.debug & (G_DEBUG_DEPSGRAPH_BUILD | G_DEBUG_DEPSGRAPH_TIME)) {
+ start_time = PIL_check_seconds_timer();
+ }
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ /* Perform sanity checks. */
+ BLI_assert(BLI_findindex(&scene->view_layers, view_layer) != -1);
+ BLI_assert(deg_graph->scene == scene);
+ BLI_assert(deg_graph->view_layer == view_layer);
+ DEG::DepsgraphBuilderCache builder_cache;
+ /* Generate all the nodes in the graph first */
+ DEG::DepsgraphFromIDsNodeBuilder node_builder(bmain, deg_graph, &builder_cache, ids, num_ids);
+ node_builder.begin_build();
+ node_builder.build_view_layer(scene, view_layer, DEG::DEG_ID_LINKED_DIRECTLY);
+ for (int i = 0; i < num_ids; ++i) {
+ node_builder.build_id(ids[i]);
+ }
+ node_builder.end_build();
+ /* Hook up relationships between operations - to determine evaluation order. */
+ DEG::DepsgraphFromIDsRelationBuilder relation_builder(
+ bmain, deg_graph, &builder_cache, ids, num_ids);
+ relation_builder.begin_build();
+ relation_builder.build_view_layer(scene, view_layer, DEG::DEG_ID_LINKED_DIRECTLY);
+ for (int i = 0; i < num_ids; ++i) {
+ relation_builder.build_id(ids[i]);
+ }
+ relation_builder.build_copy_on_write_relations();
+ /* Finalize building. */
+ graph_build_finalize_common(deg_graph, bmain);
+ /* Finish statistics. */
+ if (G.debug & (G_DEBUG_DEPSGRAPH_BUILD | G_DEBUG_DEPSGRAPH_TIME)) {
+ printf("Depsgraph built in %f seconds.\n", PIL_check_seconds_timer() - start_time);
+ }
+}
+
/* Tag graph relations for update. */
void DEG_graph_tag_relations_update(Depsgraph *graph)
{
@@ -356,12 +498,7 @@ void DEG_graph_relations_update(Depsgraph *graph, Main *bmain, Scene *scene, Vie
void DEG_relations_tag_update(Main *bmain)
{
DEG_GLOBAL_DEBUG_PRINTF(TAG, "%s: Tagging relations for update.\n", __func__);
- LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
- LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
- Depsgraph *depsgraph = (Depsgraph *)BKE_scene_get_depsgraph(scene, view_layer, false);
- if (depsgraph != NULL) {
- DEG_graph_tag_relations_update(depsgraph);
- }
- }
+ for (DEG::Depsgraph *depsgraph : DEG::get_all_registered_graphs(bmain)) {
+ DEG_graph_tag_relations_update(reinterpret_cast<Depsgraph *>(depsgraph));
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc
index 6253d31b8aa..d079c958e04 100644
--- a/source/blender/depsgraph/intern/depsgraph_debug.cc
+++ b/source/blender/depsgraph/intern/depsgraph_debug.cc
@@ -91,7 +91,7 @@ bool DEG_debug_graph_relations_validate(Depsgraph *graph,
Scene *scene,
ViewLayer *view_layer)
{
- Depsgraph *temp_depsgraph = DEG_graph_new(scene, view_layer, DEG_get_mode(graph));
+ Depsgraph *temp_depsgraph = DEG_graph_new(bmain, scene, view_layer, DEG_get_mode(graph));
bool valid = true;
DEG_graph_build_from_view_layer(temp_depsgraph, bmain, scene, view_layer);
if (!DEG_debug_compare(temp_depsgraph, graph)) {
@@ -112,13 +112,13 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
int counter1 = 0;
for (DEG::Relation *tmp_rel : node->outlinks) {
if (tmp_rel == rel) {
- ++counter1;
+ counter1++;
}
}
int counter2 = 0;
for (DEG::Relation *tmp_rel : rel->to->inlinks) {
if (tmp_rel == rel) {
- ++counter2;
+ counter2++;
}
}
if (counter1 != counter2) {
@@ -137,13 +137,13 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
int counter1 = 0;
for (DEG::Relation *tmp_rel : node->inlinks) {
if (tmp_rel == rel) {
- ++counter1;
+ counter1++;
}
}
int counter2 = 0;
for (DEG::Relation *tmp_rel : rel->from->outlinks) {
if (tmp_rel == rel) {
- ++counter2;
+ counter2++;
}
}
if (counter1 != counter2) {
@@ -179,7 +179,7 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
int num_links_pending = 0;
for (DEG::Relation *rel : node->inlinks) {
if (rel->from->type == DEG::NodeType::OPERATION) {
- ++num_links_pending;
+ num_links_pending++;
}
}
if (node->num_links_pending != num_links_pending) {
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
index 55241d03e94..b2b7d2a9d00 100644
--- a/source/blender/depsgraph/intern/depsgraph_eval.cc
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -49,7 +49,7 @@ extern "C" {
#include "intern/depsgraph.h"
/* Evaluate all nodes tagged for updating. */
-void DEG_evaluate_on_refresh(Depsgraph *graph)
+void DEG_evaluate_on_refresh(Main *bmain, Depsgraph *graph)
{
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
deg_graph->ctime = BKE_scene_frame_get(deg_graph->scene);
@@ -60,6 +60,7 @@ void DEG_evaluate_on_refresh(Depsgraph *graph)
if (deg_graph->scene_cow) {
BKE_scene_frame_set(deg_graph->scene_cow, deg_graph->ctime);
}
+ DEG::deg_graph_flush_updates(bmain, deg_graph);
DEG::deg_evaluate_on_refresh(deg_graph);
deg_graph->need_update_time = false;
}
diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
index 33cb1ba7416..b7a40fb69bd 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
@@ -68,9 +68,20 @@ void deg_foreach_clear_flags(const Depsgraph *graph)
}
}
+bool deg_foreach_needs_visit(const OperationNode *op_node, const int flags)
+{
+ if (flags & DEG_FOREACH_COMPONENT_IGNORE_TRANSFORM_SOLVERS) {
+ if (op_node->opcode == OperationCode::RIGIDBODY_SIM) {
+ return false;
+ }
+ }
+ return true;
+}
+
void deg_foreach_dependent_operation(const Depsgraph *graph,
const ID *id,
eDepsObjectComponentType source_component_type,
+ int flags,
DEGForeachOperation callback,
void *user_data)
{
@@ -91,6 +102,9 @@ void deg_foreach_dependent_operation(const Depsgraph *graph,
continue;
}
for (OperationNode *op_node : comp_node->operations) {
+ if (!deg_foreach_needs_visit(op_node, flags)) {
+ continue;
+ }
queue.push_back(op_node);
op_node->scheduled = true;
op_node->owner->custom_flags |= DEG_NODE_VISITED;
@@ -108,7 +122,7 @@ void deg_foreach_dependent_operation(const Depsgraph *graph,
/* Schedule outgoing operation nodes. */
if (op_node->outlinks.size() == 1) {
OperationNode *to_node = (OperationNode *)op_node->outlinks[0]->to;
- if (to_node->scheduled == false) {
+ if (to_node->scheduled == false && deg_foreach_needs_visit(to_node, flags)) {
to_node->scheduled = true;
op_node = to_node;
}
@@ -119,7 +133,7 @@ void deg_foreach_dependent_operation(const Depsgraph *graph,
else {
for (Relation *rel : op_node->outlinks) {
OperationNode *to_node = (OperationNode *)rel->to;
- if (to_node->scheduled == false) {
+ if (to_node->scheduled == false && deg_foreach_needs_visit(to_node, flags)) {
queue.push_front(to_node);
to_node->scheduled = true;
}
@@ -150,6 +164,7 @@ void deg_foreach_dependent_component_callback(OperationNode *op_node, void *user
void deg_foreach_dependent_ID_component(const Depsgraph *graph,
const ID *id,
eDepsObjectComponentType source_component_type,
+ int flags,
DEGForeachIDComponentCallback callback,
void *user_data)
{
@@ -157,7 +172,7 @@ void deg_foreach_dependent_ID_component(const Depsgraph *graph,
data.callback = callback;
data.user_data = user_data;
deg_foreach_dependent_operation(
- graph, id, source_component_type, deg_foreach_dependent_component_callback, &data);
+ graph, id, source_component_type, flags, deg_foreach_dependent_component_callback, &data);
}
struct ForeachIDData {
@@ -185,7 +200,7 @@ void deg_foreach_dependent_ID(const Depsgraph *graph,
data.callback = callback;
data.user_data = user_data;
deg_foreach_dependent_operation(
- graph, id, DEG_OB_COMP_ANY, deg_foreach_dependent_ID_callback, &data);
+ graph, id, DEG_OB_COMP_ANY, 0, deg_foreach_dependent_ID_callback, &data);
}
void deg_foreach_ancestor_ID(const Depsgraph *graph,
@@ -278,11 +293,12 @@ void DEG_foreach_dependent_ID(const Depsgraph *depsgraph,
void DEG_foreach_dependent_ID_component(const Depsgraph *depsgraph,
const ID *id,
eDepsObjectComponentType source_component_type,
+ int flags,
DEGForeachIDComponentCallback callback,
void *user_data)
{
DEG::deg_foreach_dependent_ID_component(
- (const DEG::Depsgraph *)depsgraph, id, source_component_type, callback, user_data);
+ (const DEG::Depsgraph *)depsgraph, id, source_component_type, flags, callback, user_data);
}
void DEG_foreach_ancestor_ID(const Depsgraph *depsgraph,
diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
index 251857b58c9..28789968286 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
@@ -146,6 +146,8 @@ bool deg_objects_dupli_iterator_next(BLI_Iterator *iter)
*temp_dupli_object = *dob->ob;
temp_dupli_object->base_flag = dupli_parent->base_flag | BASE_FROM_DUPLI;
temp_dupli_object->base_local_view_bits = dupli_parent->base_local_view_bits;
+ temp_dupli_object->runtime.local_collections_bits =
+ dupli_parent->runtime.local_collections_bits;
temp_dupli_object->dt = MIN2(temp_dupli_object->dt, dupli_parent->dt);
copy_v4_v4(temp_dupli_object->color, dupli_parent->color);
diff --git a/source/blender/depsgraph/intern/depsgraph_registry.cc b/source/blender/depsgraph/intern/depsgraph_registry.cc
new file mode 100644
index 00000000000..ad60b1bc4cf
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_registry.cc
@@ -0,0 +1,74 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/depsgraph_registry.h"
+
+#include "BLI_utildefines.h"
+
+#include "intern/depsgraph.h"
+
+namespace DEG {
+
+typedef set<Depsgraph *> DepsgraphStorage;
+typedef map<Main *, DepsgraphStorage> MainDepsgraphMap;
+
+static MainDepsgraphMap g_graph_registry;
+
+void register_graph(Depsgraph *depsgraph)
+{
+ Main *bmain = depsgraph->bmain;
+ MainDepsgraphMap::iterator it = g_graph_registry.find(bmain);
+ if (it == g_graph_registry.end()) {
+ it = g_graph_registry.insert(make_pair(bmain, DepsgraphStorage())).first;
+ }
+ DepsgraphStorage &storage = it->second;
+ storage.insert(depsgraph);
+}
+
+void unregister_graph(Depsgraph *depsgraph)
+{
+ Main *bmain = depsgraph->bmain;
+ MainDepsgraphMap::iterator it = g_graph_registry.find(bmain);
+ BLI_assert(it != g_graph_registry.end());
+
+ // Remove dependency graph from storage.
+ DepsgraphStorage &storage = it->second;
+ storage.erase(depsgraph);
+
+ // If this was the last depsgraph associated with the main, remove the main entry as well.
+ if (storage.empty()) {
+ g_graph_registry.erase(bmain);
+ }
+}
+
+const set<Depsgraph *> &get_all_registered_graphs(Main *bmain)
+{
+ MainDepsgraphMap::iterator it = g_graph_registry.find(bmain);
+ if (it == g_graph_registry.end()) {
+ static DepsgraphStorage empty_storage;
+ return empty_storage;
+ }
+ return it->second;
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_registry.h b/source/blender/depsgraph/intern/depsgraph_registry.h
new file mode 100644
index 00000000000..7517b6a0b2a
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_registry.h
@@ -0,0 +1,38 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "intern/depsgraph_type.h"
+
+struct Main;
+
+namespace DEG {
+
+struct Depsgraph;
+
+void register_graph(Depsgraph *depsgraph);
+void unregister_graph(Depsgraph *depsgraph);
+const set<Depsgraph *> &get_all_registered_graphs(Main *bmain);
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index b73a3c08e10..2fdce0e30a5 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -30,7 +30,6 @@
#include <queue>
#include "BLI_utildefines.h"
-#include "BLI_listbase.h"
#include "BLI_math_bits.h"
#include "BLI_task.h"
@@ -64,6 +63,7 @@ extern "C" {
#include "intern/builder/deg_builder.h"
#include "intern/depsgraph.h"
#include "intern/depsgraph_update.h"
+#include "intern/depsgraph_registry.h"
#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/eval/deg_eval_flush.h"
#include "intern/node/deg_node.h"
@@ -412,11 +412,15 @@ static void graph_id_tag_update_single_flag(Main *bmain,
string stringify_append_bit(const string &str, IDRecalcFlag tag)
{
+ const char *tag_name = DEG_update_tag_as_string(tag);
+ if (tag_name == NULL) {
+ return str;
+ }
string result = str;
if (!result.empty()) {
result += ", ";
}
- result += DEG_update_tag_as_string(tag);
+ result += tag_name;
return result;
}
@@ -601,13 +605,8 @@ NodeType geometry_tag_to_component(const ID *id)
void id_tag_update(Main *bmain, ID *id, int flag, eUpdateSource update_source)
{
graph_id_tag_update(bmain, NULL, id, flag, update_source);
- LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
- LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
- Depsgraph *depsgraph = (Depsgraph *)BKE_scene_get_depsgraph(scene, view_layer, false);
- if (depsgraph != NULL) {
- graph_id_tag_update(bmain, depsgraph, id, flag, update_source);
- }
- }
+ for (DEG::Depsgraph *depsgraph : DEG::get_all_registered_graphs(bmain)) {
+ graph_id_tag_update(bmain, depsgraph, id, flag, update_source);
}
}
@@ -717,8 +716,7 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag)
case ID_RECALC_ALL:
return "ALL";
}
- BLI_assert(!"Unhandled update flag, should never happen!");
- return "UNKNOWN";
+ return NULL;
}
/* Data-Based Tagging */
@@ -766,24 +764,11 @@ void DEG_graph_id_type_tag(Depsgraph *depsgraph, short id_type)
void DEG_id_type_tag(Main *bmain, short id_type)
{
- LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
- LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
- Depsgraph *depsgraph = (Depsgraph *)BKE_scene_get_depsgraph(scene, view_layer, false);
- if (depsgraph != NULL) {
- DEG_graph_id_type_tag(depsgraph, id_type);
- }
- }
+ for (DEG::Depsgraph *depsgraph : DEG::get_all_registered_graphs(bmain)) {
+ DEG_graph_id_type_tag(reinterpret_cast<::Depsgraph *>(depsgraph), id_type);
}
}
-void DEG_graph_flush_update(Main *bmain, Depsgraph *depsgraph)
-{
- if (depsgraph == NULL) {
- return;
- }
- DEG::deg_graph_flush_updates(bmain, (DEG::Depsgraph *)depsgraph);
-}
-
/* Update dependency graph when visible scenes/layers changes. */
void DEG_graph_on_visible_update(Main *bmain, Depsgraph *depsgraph, const bool do_time)
{
@@ -793,13 +778,8 @@ void DEG_graph_on_visible_update(Main *bmain, Depsgraph *depsgraph, const bool d
void DEG_on_visible_update(Main *bmain, const bool do_time)
{
- LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
- LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
- Depsgraph *depsgraph = (Depsgraph *)BKE_scene_get_depsgraph(scene, view_layer, false);
- if (depsgraph != NULL) {
- DEG_graph_on_visible_update(bmain, depsgraph, do_time);
- }
- }
+ for (DEG::Depsgraph *depsgraph : DEG::get_all_registered_graphs(bmain)) {
+ DEG_graph_on_visible_update(bmain, reinterpret_cast<::Depsgraph *>(depsgraph), do_time);
}
}
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 138523c7208..27adcfca808 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -102,8 +102,12 @@ set(SRC
engines/eevee/eevee_motion_blur.c
engines/eevee/eevee_occlusion.c
engines/eevee/eevee_render.c
+ engines/eevee/eevee_sampling.c
engines/eevee/eevee_screen_raytrace.c
engines/eevee/eevee_shaders.c
+ engines/eevee/eevee_shadows.c
+ engines/eevee/eevee_shadows_cascade.c
+ engines/eevee/eevee_shadows_cube.c
engines/eevee/eevee_subsurface.c
engines/eevee/eevee_temporal_sampling.c
engines/eevee/eevee_volumes.c
@@ -201,6 +205,7 @@ data_to_c_simple(engines/eevee/shaders/effect_mist_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_motion_blur_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_ssr_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_subsurface_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_translucency_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_temporal_aa.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl SRC)
@@ -209,10 +214,6 @@ data_to_c_simple(engines/eevee/shaders/prepass_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/prepass_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/shadow_process_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/shadow_process_geom.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/shadow_store_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/shadow_copy_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/bsdf_lut_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/btdf_lut_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/bsdf_common_lib.glsl SRC)
@@ -307,6 +308,7 @@ data_to_c_simple(modes/shaders/overlay_face_wireframe_geom.glsl SRC)
data_to_c_simple(modes/shaders/overlay_face_wireframe_frag.glsl SRC)
data_to_c_simple(modes/shaders/object_camera_image_frag.glsl SRC)
data_to_c_simple(modes/shaders/object_camera_image_vert.glsl SRC)
+data_to_c_simple(modes/shaders/object_color_axes_vert.glsl SRC)
data_to_c_simple(modes/shaders/object_empty_axes_vert.glsl SRC)
data_to_c_simple(modes/shaders/object_empty_image_frag.glsl SRC)
data_to_c_simple(modes/shaders/object_empty_image_vert.glsl SRC)
diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c
index f548bd15bf4..188e252a285 100644
--- a/source/blender/draw/engines/basic/basic_engine.c
+++ b/source/blender/draw/engines/basic/basic_engine.c
@@ -162,7 +162,8 @@ static void basic_cache_populate(void *vedata, Object *ob)
}
}
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+ const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
const bool do_cull = (draw_ctx->v3d &&
(draw_ctx->v3d->shading.flag & V3D_SHADING_BACKFACE_CULLING));
DRWShadingGroup *shgrp = (do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp;
diff --git a/source/blender/draw/engines/eevee/eevee_bloom.c b/source/blender/draw/engines/eevee/eevee_bloom.c
index 14faa827be5..c6cc336db56 100644
--- a/source/blender/draw/engines/eevee/eevee_bloom.c
+++ b/source/blender/draw/engines/eevee/eevee_bloom.c
@@ -128,7 +128,7 @@ int EEVEE_bloom_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
/* Downsample buffers */
copy_v2_v2_int(texsize, blitsize);
- for (int i = 0; i < effects->bloom_iteration_len; ++i) {
+ for (int i = 0; i < effects->bloom_iteration_len; i++) {
texsize[0] /= 2;
texsize[1] /= 2;
@@ -147,7 +147,7 @@ int EEVEE_bloom_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
/* Upsample buffers */
copy_v2_v2_int(texsize, blitsize);
- for (int i = 0; i < effects->bloom_iteration_len - 1; ++i) {
+ for (int i = 0; i < effects->bloom_iteration_len - 1; i++) {
texsize[0] /= 2;
texsize[1] /= 2;
@@ -167,7 +167,7 @@ int EEVEE_bloom_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
/* Cleanup to release memory */
GPU_FRAMEBUFFER_FREE_SAFE(fbl->bloom_blit_fb);
- for (int i = 0; i < MAX_BLOOM_STEP - 1; ++i) {
+ for (int i = 0; i < MAX_BLOOM_STEP - 1; i++) {
GPU_FRAMEBUFFER_FREE_SAFE(fbl->bloom_down_fb[i]);
GPU_FRAMEBUFFER_FREE_SAFE(fbl->bloom_accum_fb[i]);
}
@@ -288,7 +288,7 @@ void EEVEE_bloom_draw(EEVEE_Data *vedata)
last = effects->bloom_downsample[0];
- for (int i = 1; i < effects->bloom_iteration_len; ++i) {
+ for (int i = 1; i < effects->bloom_iteration_len; i++) {
copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[i - 1]);
effects->unf_source_buffer = last;
@@ -300,7 +300,7 @@ void EEVEE_bloom_draw(EEVEE_Data *vedata)
}
/* Upsample and accumulate */
- for (int i = effects->bloom_iteration_len - 2; i >= 0; --i) {
+ for (int i = effects->bloom_iteration_len - 2; i >= 0; i--) {
copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[i]);
effects->unf_source_buffer = effects->bloom_downsample[i];
effects->unf_base_buffer = last;
@@ -324,7 +324,7 @@ void EEVEE_bloom_draw(EEVEE_Data *vedata)
void EEVEE_bloom_free(void)
{
- for (int i = 0; i < 2; ++i) {
+ for (int i = 0; i < 2; i++) {
DRW_SHADER_FREE_SAFE(e_data.bloom_blit_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.bloom_downsample_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.bloom_upsample_sh[i]);
diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c
index b792f93ced2..dd70ee1bd4b 100644
--- a/source/blender/draw/engines/eevee/eevee_data.c
+++ b/source/blender/draw/engines/eevee/eevee_data.c
@@ -35,23 +35,13 @@ void EEVEE_view_layer_data_free(void *storage)
MEM_SAFE_FREE(sldata->lights);
DRW_UBO_FREE_SAFE(sldata->light_ubo);
DRW_UBO_FREE_SAFE(sldata->shadow_ubo);
- DRW_UBO_FREE_SAFE(sldata->shadow_render_ubo);
- GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cube_target_fb);
- GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cube_store_fb);
- GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cube_copy_fb);
- GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cascade_target_fb);
- GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cascade_store_fb);
- GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cascade_copy_fb);
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_target);
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_blur);
+ GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_fb);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool);
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_target);
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_blur);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool);
- MEM_SAFE_FREE(sldata->shcasters_buffers[0].shadow_casters);
- MEM_SAFE_FREE(sldata->shcasters_buffers[0].flags);
- MEM_SAFE_FREE(sldata->shcasters_buffers[1].shadow_casters);
- MEM_SAFE_FREE(sldata->shcasters_buffers[1].flags);
+ for (int i = 0; i < 2; i++) {
+ MEM_SAFE_FREE(sldata->shcasters_buffers[i].bbox);
+ MEM_SAFE_FREE(sldata->shcasters_buffers[i].update);
+ }
if (sldata->fallback_lightcache) {
EEVEE_lightcache_free(sldata->fallback_lightcache);
@@ -153,7 +143,6 @@ static void eevee_light_data_init(DrawData *dd)
{
EEVEE_LightEngineData *led = (EEVEE_LightEngineData *)dd;
led->need_update = true;
- led->prev_cube_shadow_id = -1;
}
EEVEE_LightEngineData *EEVEE_light_data_get(Object *ob)
diff --git a/source/blender/draw/engines/eevee/eevee_depth_of_field.c b/source/blender/draw/engines/eevee/eevee_depth_of_field.c
index 12d70131031..572e38a9395 100644
--- a/source/blender/draw/engines/eevee/eevee_depth_of_field.c
+++ b/source/blender/draw/engines/eevee/eevee_depth_of_field.c
@@ -269,7 +269,7 @@ void EEVEE_depth_of_field_draw(EEVEE_Data *vedata)
void EEVEE_depth_of_field_free(void)
{
- for (int i = 0; i < 2; ++i) {
+ for (int i = 0; i < 2; i++) {
DRW_SHADER_FREE_SAFE(e_data.dof_downsample_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.dof_scatter_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.dof_resolve_sh[i]);
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c
index 0ca1e0b2858..7df1c299454 100644
--- a/source/blender/draw/engines/eevee/eevee_effects.c
+++ b/source/blender/draw/engines/eevee/eevee_effects.c
@@ -206,7 +206,7 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata,
/**
* Compute Mipmap texel alignment.
*/
- for (int i = 0; i < 10; ++i) {
+ for (int i = 0; i < 10; i++) {
int mip_size[2];
GPU_texture_get_mipmap_size(txl->color, i, mip_size);
common_data->mip_ratio[i][0] = viewport_size[0] / (mip_size[0] * powf(2.0f, i));
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index ab4eb7b8532..a1096390bce 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -84,7 +84,7 @@ static void eevee_engine_init(void *ved)
/* EEVEE_effects_init needs to go first for TAA */
EEVEE_effects_init(sldata, vedata, camera, false);
EEVEE_materials_init(sldata, stl, fbl);
- EEVEE_lights_init(sldata);
+ EEVEE_shadows_init(sldata);
EEVEE_lightprobes_init(sldata, vedata);
}
@@ -139,7 +139,7 @@ void EEVEE_cache_populate(void *vedata, Object *ob)
}
if (cast_shadow) {
- EEVEE_lights_cache_shcaster_object_add(sldata, ob);
+ EEVEE_shadows_caster_register(sldata, ob);
}
}
@@ -223,7 +223,7 @@ static void eevee_draw_background(void *vedata)
/* Refresh shadows */
DRW_stats_group_start("Shadows");
- EEVEE_draw_shadows(sldata, vedata, stl->effects->taa_view);
+ EEVEE_shadows_draw(sldata, vedata, stl->effects->taa_view);
DRW_stats_group_end();
if (((stl->effects->enabled_effects & EFFECT_TAA) != 0) &&
@@ -269,9 +269,7 @@ static void eevee_draw_background(void *vedata)
if (DRW_state_draw_background()) {
DRW_draw_pass(psl->background_pass);
}
- EEVEE_draw_default_passes(psl);
- DRW_draw_pass(psl->material_pass);
- DRW_draw_pass(psl->material_pass_cull);
+ EEVEE_materials_draw_opaque(sldata, psl);
EEVEE_subsurface_data_render(sldata, vedata);
DRW_stats_group_end();
@@ -368,11 +366,21 @@ static void eevee_draw_background(void *vedata)
}
break;
case 8:
- if (effects->sss_data) {
- DRW_transform_to_display(effects->sss_data, false, false);
+ if (effects->sss_irradiance) {
+ DRW_transform_to_display(effects->sss_irradiance, false, false);
}
break;
case 9:
+ if (effects->sss_radius) {
+ DRW_transform_to_display(effects->sss_radius, false, false);
+ }
+ break;
+ case 10:
+ if (effects->sss_albedo) {
+ DRW_transform_to_display(effects->sss_albedo, false, false);
+ }
+ break;
+ case 11:
if (effects->velocity_tx) {
DRW_transform_to_display(effects->velocity_tx, false, false);
}
@@ -467,7 +475,7 @@ static void eevee_engine_free(void)
EEVEE_depth_of_field_free();
EEVEE_effects_free();
EEVEE_lightprobes_free();
- EEVEE_lights_free();
+ EEVEE_shadows_free();
EEVEE_materials_free();
EEVEE_mist_free();
EEVEE_motion_blur_free();
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c
index 05aea652591..261b7f00e42 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.c
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.c
@@ -188,7 +188,7 @@ static uint eevee_lightcache_memsize_get(LightCache *lcache)
}
if (lcache->cube_tx.data) {
size += MEM_allocN_len(lcache->cube_tx.data);
- for (int mip = 0; mip < lcache->mips_len; ++mip) {
+ for (int mip = 0; mip < lcache->mips_len; mip++) {
size += MEM_allocN_len(lcache->cube_mips[mip].data);
}
}
@@ -199,7 +199,7 @@ static int eevee_lightcache_irradiance_sample_count(LightCache *lcache)
{
int total_irr_samples = 0;
- for (int i = 1; i < lcache->grid_len; ++i) {
+ for (int i = 1; i < lcache->grid_len; i++) {
EEVEE_LightGrid *egrid = lcache->grid_data + i;
total_irr_samples += egrid->resolution[0] * egrid->resolution[1] * egrid->resolution[2];
}
@@ -218,7 +218,7 @@ void EEVEE_lightcache_info_update(SceneEEVEE *eevee)
}
char formatted_mem[15];
- BLI_str_format_byte_unit(formatted_mem, eevee_lightcache_memsize_get(lcache), true);
+ BLI_str_format_byte_unit(formatted_mem, eevee_lightcache_memsize_get(lcache), false);
int irr_samples = eevee_lightcache_irradiance_sample_count(lcache);
@@ -305,7 +305,7 @@ LightCache *EEVEE_lightcache_create(const int grid_len,
light_cache->cube_mips = MEM_callocN(sizeof(LightCacheTexture) * light_cache->mips_len,
"LightCacheTexture");
- for (int mip = 0; mip < light_cache->mips_len; ++mip) {
+ for (int mip = 0; mip < light_cache->mips_len; mip++) {
GPU_texture_get_mipmap_size(
light_cache->cube_tx.tex, mip + 1, light_cache->cube_mips[mip].tex_size);
}
@@ -346,7 +346,7 @@ void EEVEE_lightcache_load(LightCache *lcache)
NULL);
GPU_texture_bind(lcache->cube_tx.tex, 0);
GPU_texture_mipmap_mode(lcache->cube_tx.tex, true, true);
- for (int mip = 0; mip < lcache->mips_len; ++mip) {
+ for (int mip = 0; mip < lcache->mips_len; mip++) {
GPU_texture_add_mipmap(
lcache->cube_tx.tex, GPU_DATA_10_11_11_REV, mip + 1, lcache->cube_mips[mip].data);
}
@@ -369,7 +369,7 @@ static void eevee_lightbake_readback_reflections(LightCache *lcache)
lcache->cube_tx.data_type = LIGHTCACHETEX_UINT;
lcache->cube_tx.components = 1;
- for (int mip = 0; mip < lcache->mips_len; ++mip) {
+ for (int mip = 0; mip < lcache->mips_len; mip++) {
LightCacheTexture *cube_mip = lcache->cube_mips + mip;
MEM_SAFE_FREE(cube_mip->data);
GPU_texture_get_mipmap_size(lcache->cube_tx.tex, mip + 1, cube_mip->tex_size);
@@ -388,7 +388,7 @@ void EEVEE_lightcache_free(LightCache *lcache)
MEM_SAFE_FREE(lcache->grid_tx.data);
if (lcache->cube_mips) {
- for (int i = 0; i < lcache->mips_len; ++i) {
+ for (int i = 0; i < lcache->mips_len; i++) {
MEM_SAFE_FREE(lcache->cube_mips[i].data);
}
MEM_SAFE_FREE(lcache->cube_mips);
@@ -471,7 +471,7 @@ static void eevee_lightbake_create_render_target(EEVEE_LightBake *lbake, int rt_
lbake->rt_color = DRW_texture_create_cube(
rt_res, GPU_RGBA16F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
- for (int i = 0; i < 6; ++i) {
+ for (int i = 0; i < 6; i++) {
GPU_framebuffer_ensure_config(&lbake->rt_fb[i],
{GPU_ATTACHMENT_TEXTURE_CUBEFACE(lbake->rt_depth, i),
GPU_ATTACHMENT_TEXTURE_CUBEFACE(lbake->rt_color, i)});
@@ -561,7 +561,7 @@ wmJob *EEVEE_lightbake_job_create(struct wmWindowManager *wm,
/* Cannot reuse depsgraph for now because we cannot get the update from the
* main database directly. TODO reuse depsgraph and only update positions. */
/* lbake->depsgraph = old_lbake->depsgraph; */
- lbake->depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
+ lbake->depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
lbake->mutex = BLI_mutex_alloc();
@@ -612,7 +612,7 @@ void *EEVEE_lightbake_job_data_alloc(struct Main *bmain,
EEVEE_LightBake *lbake = MEM_callocN(sizeof(EEVEE_LightBake), "EEVEE_LightBake");
- lbake->depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
+ lbake->depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
lbake->scene = scene;
lbake->bmain = bmain;
lbake->view_layer_input = view_layer;
@@ -670,7 +670,7 @@ static void eevee_lightbake_delete_resources(EEVEE_LightBake *lbake)
DRW_TEXTURE_FREE_SAFE(lbake->rt_color);
DRW_TEXTURE_FREE_SAFE(lbake->grid_prev);
GPU_FRAMEBUFFER_FREE_SAFE(lbake->store_fb);
- for (int i = 0; i < 6; ++i) {
+ for (int i = 0; i < 6; i++) {
GPU_FRAMEBUFFER_FREE_SAFE(lbake->rt_fb[i]);
}
@@ -743,7 +743,7 @@ static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lb
EEVEE_effects_init(sldata, vedata, NULL, true);
EEVEE_materials_init(sldata, stl, fbl);
- EEVEE_lights_init(sldata);
+ EEVEE_shadows_init(sldata);
EEVEE_lightprobes_init(sldata, vedata);
EEVEE_effects_cache_init(sldata, vedata);
@@ -875,10 +875,10 @@ static void compute_cell_id(EEVEE_LightGrid *egrid,
*r_stride = 0;
*r_final_idx = 0;
r_local_cell[0] = r_local_cell[1] = r_local_cell[2] = 0;
- for (int lvl = max_lvl; lvl >= 0; --lvl) {
+ for (int lvl = max_lvl; lvl >= 0; lvl--) {
*r_stride = 1 << lvl;
int prev_stride = *r_stride << 1;
- for (int i = 0; i < cell_count; ++i) {
+ for (int i = 0; i < cell_count; i++) {
*r_final_idx = i;
cell_id_to_grid_loc(egrid, *r_final_idx, r_local_cell);
if (((r_local_cell[0] % *r_stride) == 0) && ((r_local_cell[1] % *r_stride) == 0) &&
@@ -1210,12 +1210,12 @@ void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float
/* Render irradiance grids */
if (lcache->flag & LIGHTCACHE_UPDATE_GRID) {
- for (lbake->bounce_curr = 0; lbake->bounce_curr < lbake->bounce_len; ++lbake->bounce_curr) {
+ for (lbake->bounce_curr = 0; lbake->bounce_curr < lbake->bounce_len; lbake->bounce_curr++) {
/* Bypass world, start at 1. */
lbake->probe = lbake->grid_prb + 1;
lbake->grid = lcache->grid_data + 1;
for (lbake->grid_curr = 1; lbake->grid_curr < lbake->grid_len;
- ++lbake->grid_curr, ++lbake->probe, ++lbake->grid) {
+ lbake->grid_curr++, lbake->probe++, lbake->grid++) {
LightProbe *prb = *lbake->probe;
lbake->grid_sample_len = prb->grid_resolution_x * prb->grid_resolution_y *
prb->grid_resolution_z;
@@ -1233,7 +1233,7 @@ void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float
lbake->probe = lbake->cube_prb + 1;
lbake->cube = lcache->cube_data + 1;
for (lbake->cube_offset = 1; lbake->cube_offset < lbake->cube_len;
- ++lbake->cube_offset, ++lbake->probe, ++lbake->cube) {
+ lbake->cube_offset++, lbake->probe++, lbake->cube++) {
lightbake_do_sample(lbake, eevee_lightbake_render_probe_sample);
}
}
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
index 8b1309e8537..19f3983998e 100644
--- a/source/blender/draw/engines/eevee/eevee_lightprobes.c
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -410,7 +410,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
/* Grid Display */
if (scene_eval->eevee.flag & SCE_EEVEE_SHOW_IRRADIANCE) {
EEVEE_LightGrid *egrid = lcache->grid_data + 1;
- for (int p = 1; p < lcache->grid_len; ++p, egrid++) {
+ for (int p = 1; p < lcache->grid_len; p++, egrid++) {
DRWShadingGroup *shgrp = DRW_shgroup_create(EEVEE_shaders_probe_grid_display_sh_get(),
psl->probe_display);
@@ -471,7 +471,7 @@ static bool eevee_lightprobes_culling_test(Object *ob)
normalize_v3(tmp[2]);
mul_v3_fl(tmp[2], probe->distinf);
- for (int v = 0; v < 8; ++v) {
+ for (int v = 0; v < 8; v++) {
mul_m4_v3(tmp, bbox.vec[v]);
}
const DRWView *default_view = DRW_view_default_get();
@@ -845,7 +845,7 @@ static void render_cubemap(void (*callback)(int face, EEVEE_BakeRenderData *user
}
}
- for (int i = 0; i < 6; ++i) {
+ for (int i = 0; i < 6; i++) {
DRW_view_set_active(views[i]);
callback(i, user_data);
}
@@ -860,11 +860,11 @@ static void render_reflections(void (*callback)(int face, EEVEE_BakeRenderData *
DRWView *main_view = stl->effects->taa_view;
DRWView **views = stl->g_data->planar_views;
/* Prepare views at the same time for faster culling. */
- for (int i = 0; i < ref_count; ++i) {
+ for (int i = 0; i < ref_count; i++) {
lightbake_planar_ensure_view(&planar_data[i], main_view, &views[i]);
}
- for (int i = 0; i < ref_count; ++i) {
+ for (int i = 0; i < ref_count; i++) {
DRW_view_set_active(views[i]);
callback(i, user_data);
}
@@ -904,7 +904,7 @@ static void lightbake_render_scene_face(int face, EEVEE_BakeRenderData *user_dat
struct GPUFrameBuffer **face_fb = user_data->face_fb;
/* Be sure that cascaded shadow maps are updated. */
- EEVEE_draw_shadows(sldata, user_data->vedata, views[face]);
+ EEVEE_shadows_draw(sldata, user_data->vedata, views[face]);
GPU_framebuffer_bind(face_fb[face]);
GPU_framebuffer_clear_depth(face_fb[face], 1.0f);
@@ -912,11 +912,9 @@ static void lightbake_render_scene_face(int face, EEVEE_BakeRenderData *user_dat
DRW_draw_pass(psl->depth_pass);
DRW_draw_pass(psl->depth_pass_cull);
DRW_draw_pass(psl->probe_background);
- DRW_draw_pass(psl->material_pass);
- DRW_draw_pass(psl->material_pass_cull);
+ EEVEE_materials_draw_opaque(sldata, psl);
DRW_draw_pass(psl->sss_pass); /* Only output standard pass */
DRW_draw_pass(psl->sss_pass_cull);
- EEVEE_draw_default_passes(psl);
DRW_draw_pass(psl->transparent_pass);
}
@@ -964,7 +962,7 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us
DRW_stats_group_start("Planar Reflection");
/* Be sure that cascaded shadow maps are updated. */
- EEVEE_draw_shadows(sldata, vedata, stl->g_data->planar_views[layer]);
+ EEVEE_shadows_draw(sldata, vedata, stl->g_data->planar_views[layer]);
GPU_framebuffer_bind(fbl->planarref_fb);
GPU_framebuffer_clear_depth(fbl->planarref_fb, 1.0);
@@ -987,9 +985,7 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us
GPU_framebuffer_bind(fbl->planarref_fb);
/* Shading pass */
- EEVEE_draw_default_passes(psl);
- DRW_draw_pass(psl->material_pass);
- DRW_draw_pass(psl->material_pass_cull);
+ EEVEE_materials_draw_opaque(sldata, psl);
DRW_draw_pass(psl->sss_pass); /* Only output standard pass */
DRW_draw_pass(psl->sss_pass_cull);
DRW_draw_pass(psl->refract_pass);
@@ -1221,7 +1217,7 @@ static void downsample_planar(void *vedata, int level)
const float *size = DRW_viewport_size_get();
copy_v2_v2(stl->g_data->planar_texel_size, size);
- for (int i = 0; i < level - 1; ++i) {
+ for (int i = 0; i < level - 1; i++) {
stl->g_data->planar_texel_size[0] /= 2.0f;
stl->g_data->planar_texel_size[1] /= 2.0f;
min_ff(floorf(stl->g_data->planar_texel_size[0]), 1.0f);
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c
index 0bfc23b8354..126ec8d81c4 100644
--- a/source/blender/draw/engines/eevee/eevee_lights.c
+++ b/source/blender/draw/engines/eevee/eevee_lights.c
@@ -20,11 +20,7 @@
* \ingroup DNA
*/
-#include "DRW_render.h"
-
-#include "BLI_dynstr.h"
-#include "BLI_rand.h"
-#include "BLI_rect.h"
+#include "BLI_sys_types.h" /* bool */
#include "BKE_object.h"
@@ -32,623 +28,20 @@
#include "eevee_private.h"
-#define SHADOW_CASTER_ALLOC_CHUNK 16
-
-// #define DEBUG_CSM
-// #define DEBUG_SHADOW_DISTRIBUTION
-
-static struct {
- struct GPUShader *shadow_sh;
- struct GPUShader *shadow_store_cube_sh[SHADOW_METHOD_MAX];
- struct GPUShader *shadow_store_cube_high_sh[SHADOW_METHOD_MAX];
- struct GPUShader *shadow_store_cascade_sh[SHADOW_METHOD_MAX];
- struct GPUShader *shadow_store_cascade_high_sh[SHADOW_METHOD_MAX];
- struct GPUShader *shadow_copy_cube_sh[SHADOW_METHOD_MAX];
- struct GPUShader *shadow_copy_cascade_sh[SHADOW_METHOD_MAX];
-} e_data = {NULL}; /* Engine data */
-
-extern char datatoc_shadow_vert_glsl[];
-extern char datatoc_shadow_frag_glsl[];
-extern char datatoc_shadow_process_vert_glsl[];
-extern char datatoc_shadow_process_geom_glsl[];
-extern char datatoc_shadow_store_frag_glsl[];
-extern char datatoc_shadow_copy_frag_glsl[];
-extern char datatoc_concentric_samples_lib_glsl[];
-
-extern char datatoc_common_view_lib_glsl[];
-
-/* Prototypes */
-static void eevee_light_setup(Object *ob, EEVEE_Light *evli);
-static float light_attenuation_radius_get(Light *la, float light_threshold);
-
-/* *********** LIGHT BITS *********** */
-static void lightbits_set_single(EEVEE_LightBits *bitf, uint idx, bool val)
-{
- if (val) {
- bitf->fields[idx / 8] |= (1 << (idx % 8));
- }
- else {
- bitf->fields[idx / 8] &= ~(1 << (idx % 8));
- }
-}
-
-static void lightbits_set_all(EEVEE_LightBits *bitf, bool val)
-{
- memset(bitf, (val) ? 0xFF : 0x00, sizeof(EEVEE_LightBits));
-}
-
-static void lightbits_or(EEVEE_LightBits *r, const EEVEE_LightBits *v)
-{
- for (int i = 0; i < MAX_LIGHTBITS_FIELDS; ++i) {
- r->fields[i] |= v->fields[i];
- }
-}
-
-static bool lightbits_get(const EEVEE_LightBits *r, uint idx)
-{
- return r->fields[idx / 8] & (1 << (idx % 8));
-}
-
-static void lightbits_convert(EEVEE_LightBits *r,
- const EEVEE_LightBits *bitf,
- const int *light_bit_conv_table,
- uint table_length)
-{
- for (int i = 0; i < table_length; ++i) {
- if (lightbits_get(bitf, i) != 0) {
- if (light_bit_conv_table[i] >= 0) {
- r->fields[i / 8] |= (1 << (i % 8));
- }
- }
- }
-}
-
-/* *********** FUNCTIONS *********** */
-
-void EEVEE_lights_init(EEVEE_ViewLayerData *sldata)
-{
- const uint shadow_ubo_size = sizeof(EEVEE_Shadow) * MAX_SHADOW +
- sizeof(EEVEE_ShadowCube) * MAX_SHADOW_CUBE +
- sizeof(EEVEE_ShadowCascade) * MAX_SHADOW_CASCADE;
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
-
- if (!e_data.shadow_sh) {
- e_data.shadow_sh = DRW_shader_create_with_lib(datatoc_shadow_vert_glsl,
- NULL,
- datatoc_shadow_frag_glsl,
- datatoc_common_view_lib_glsl,
- NULL);
- }
-
- if (!sldata->lights) {
- sldata->lights = MEM_callocN(sizeof(EEVEE_LightsInfo), "EEVEE_LightsInfo");
- sldata->light_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_Light) * MAX_LIGHT, NULL);
- sldata->shadow_ubo = DRW_uniformbuffer_create(shadow_ubo_size, NULL);
- sldata->shadow_render_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_ShadowRender), NULL);
-
- for (int i = 0; i < 2; ++i) {
- sldata->shcasters_buffers[i].shadow_casters = MEM_callocN(
- sizeof(EEVEE_ShadowCaster) * SHADOW_CASTER_ALLOC_CHUNK, "EEVEE_ShadowCaster buf");
- sldata->shcasters_buffers[i].flags = MEM_callocN(sizeof(sldata->shcasters_buffers[0].flags) *
- SHADOW_CASTER_ALLOC_CHUNK,
- "EEVEE_shcast_buffer flags buf");
- sldata->shcasters_buffers[i].alloc_count = SHADOW_CASTER_ALLOC_CHUNK;
- sldata->shcasters_buffers[i].count = 0;
- }
-
- sldata->lights->shcaster_frontbuffer = &sldata->shcasters_buffers[0];
- sldata->lights->shcaster_backbuffer = &sldata->shcasters_buffers[1];
- }
-
- /* Flip buffers */
- SWAP(EEVEE_ShadowCasterBuffer *,
- sldata->lights->shcaster_frontbuffer,
- sldata->lights->shcaster_backbuffer);
-
- const int sh_method = scene_eval->eevee.shadow_method;
- int sh_cube_size = scene_eval->eevee.shadow_cube_size;
- int sh_cascade_size = scene_eval->eevee.shadow_cascade_size;
- const bool sh_high_bitdepth = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_HIGH_BITDEPTH) != 0;
- sldata->lights->soft_shadows = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_SOFT) != 0;
-
- EEVEE_LightsInfo *linfo = sldata->lights;
- if ((linfo->shadow_cube_size != sh_cube_size) || (linfo->shadow_method != sh_method) ||
- (linfo->shadow_high_bitdepth != sh_high_bitdepth)) {
- BLI_assert((sh_cube_size > 0) && (sh_cube_size <= 4096));
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool);
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_target);
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_blur);
-
- /* Compute adequate size for the octahedral map. */
- linfo->shadow_cube_store_size = OCTAHEDRAL_SIZE_FROM_CUBESIZE(sh_cube_size);
-
- CLAMP(linfo->shadow_cube_store_size, 1, 4096);
- CLAMP(sh_cube_size, 1, 4096);
-
- linfo->shadow_render_data.cube_texel_size = 1.0f / sh_cube_size;
- }
-
- if ((linfo->shadow_cascade_size != sh_cascade_size) || (linfo->shadow_method != sh_method) ||
- (linfo->shadow_high_bitdepth != sh_high_bitdepth)) {
- BLI_assert((sh_cascade_size > 0) && (sh_cascade_size <= 4096));
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool);
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_target);
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_blur);
-
- CLAMP(sh_cascade_size, 1, 4096);
- }
-
- linfo->shadow_high_bitdepth = sh_high_bitdepth;
- linfo->shadow_method = sh_method;
- linfo->shadow_cube_size = sh_cube_size;
- linfo->shadow_cascade_size = sh_cascade_size;
-
- /* only compile the ones needed. reduce startup time. */
- if ((sh_method == SHADOW_ESM) && !e_data.shadow_copy_cube_sh[SHADOW_ESM]) {
- e_data.shadow_copy_cube_sh[SHADOW_ESM] = DRW_shader_create(datatoc_shadow_process_vert_glsl,
- datatoc_shadow_process_geom_glsl,
- datatoc_shadow_copy_frag_glsl,
- "#define ESM\n"
- "#define COPY\n");
- e_data.shadow_copy_cascade_sh[SHADOW_ESM] = DRW_shader_create(datatoc_shadow_process_vert_glsl,
- datatoc_shadow_process_geom_glsl,
- datatoc_shadow_copy_frag_glsl,
- "#define ESM\n"
- "#define COPY\n"
- "#define CSM\n");
- }
- else if ((sh_method == SHADOW_VSM) && !e_data.shadow_copy_cube_sh[SHADOW_VSM]) {
- e_data.shadow_copy_cube_sh[SHADOW_VSM] = DRW_shader_create(datatoc_shadow_process_vert_glsl,
- datatoc_shadow_process_geom_glsl,
- datatoc_shadow_copy_frag_glsl,
- "#define VSM\n"
- "#define COPY\n");
- e_data.shadow_copy_cascade_sh[SHADOW_VSM] = DRW_shader_create(datatoc_shadow_process_vert_glsl,
- datatoc_shadow_process_geom_glsl,
- datatoc_shadow_copy_frag_glsl,
- "#define VSM\n"
- "#define COPY\n"
- "#define CSM\n");
- }
-}
-
-static GPUShader *eevee_lights_get_store_sh(int shadow_method, bool high_blur, bool cascade)
-{
- GPUShader **shader;
-
- if (cascade) {
- shader = (high_blur) ? &e_data.shadow_store_cascade_high_sh[shadow_method] :
- &e_data.shadow_store_cascade_sh[shadow_method];
- }
- else {
- shader = (high_blur) ? &e_data.shadow_store_cube_high_sh[shadow_method] :
- &e_data.shadow_store_cube_sh[shadow_method];
- }
-
- if (*shader == NULL) {
- DynStr *ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, datatoc_concentric_samples_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_shadow_store_frag_glsl);
- char *store_shadow_shader_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
-
- ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, (shadow_method == SHADOW_VSM) ? "#define VSM\n" : "#define ESM\n");
- if (high_blur) {
- BLI_dynstr_append(ds_frag, "#define HIGH_BLUR\n");
- }
- if (cascade) {
- BLI_dynstr_append(ds_frag, "#define CSM\n");
- }
- char *define_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
-
- *shader = DRW_shader_create(datatoc_shadow_process_vert_glsl,
- datatoc_shadow_process_geom_glsl,
- store_shadow_shader_str,
- define_str);
-
- MEM_freeN(store_shadow_shader_str);
- MEM_freeN(define_str);
- }
-
- return *shader;
-}
-
-static DRWPass *eevee_lights_cube_store_pass_get(EEVEE_PassList *psl,
- EEVEE_ViewLayerData *sldata,
- int shadow_method,
- int shadow_samples_len)
-{
- bool high_blur = shadow_samples_len > 16;
- DRWPass **pass = (high_blur) ? &psl->shadow_cube_store_pass : &psl->shadow_cube_store_high_pass;
- if (*pass == NULL) {
- *pass = DRW_pass_create("Shadow Cube Storage Pass", DRW_STATE_WRITE_COLOR);
- GPUShader *shader = eevee_lights_get_store_sh(shadow_method, high_blur, false);
- DRWShadingGroup *grp = DRW_shgroup_create(shader, *pass);
- DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cube_blur);
- DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
-
- DRW_shgroup_call_procedural_triangles(grp, NULL, 6);
- }
- return *pass;
-}
-
-static DRWPass *eevee_lights_cascade_store_pass_get(EEVEE_PassList *psl,
- EEVEE_ViewLayerData *sldata,
- int shadow_method,
- int shadow_samples_len)
-{
- bool high_blur = shadow_samples_len > 16;
- DRWPass **pass = (high_blur) ? &psl->shadow_cascade_store_pass :
- &psl->shadow_cascade_store_high_pass;
- if (*pass == NULL) {
- *pass = DRW_pass_create("Shadow Cascade Storage Pass", DRW_STATE_WRITE_COLOR);
- GPUShader *shader = eevee_lights_get_store_sh(shadow_method, high_blur, true);
- DRWShadingGroup *grp = DRW_shgroup_create(shader, *pass);
- DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cascade_blur);
- DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
-
- DRW_shgroup_call_procedural_triangles(grp, NULL, MAX_CASCADE_NUM);
- }
- return *pass;
-}
-
-void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
-{
- EEVEE_LightsInfo *linfo = sldata->lights;
- EEVEE_StorageList *stl = vedata->stl;
- EEVEE_PassList *psl = vedata->psl;
-
- linfo->shcaster_frontbuffer->count = 0;
- linfo->num_light = 0;
- linfo->num_cube_layer = 0;
- linfo->num_cascade_layer = 0;
- linfo->gpu_cube_len = linfo->gpu_cascade_len = linfo->gpu_shadow_len = 0;
- linfo->cpu_cube_len = linfo->cpu_cascade_len = 0;
- memset(linfo->light_ref, 0, sizeof(linfo->light_ref));
- memset(linfo->shadow_cube_ref, 0, sizeof(linfo->shadow_cube_ref));
- memset(linfo->shadow_cascade_ref, 0, sizeof(linfo->shadow_cascade_ref));
- memset(linfo->new_shadow_id, -1, sizeof(linfo->new_shadow_id));
-
- /* Shadow Casters: Reset flags. */
- memset(linfo->shcaster_backbuffer->flags,
- (char)SHADOW_CASTER_PRUNED,
- linfo->shcaster_backbuffer->alloc_count);
- memset(linfo->shcaster_frontbuffer->flags, 0x00, linfo->shcaster_frontbuffer->alloc_count);
-
- psl->shadow_cube_store_pass = NULL;
- psl->shadow_cube_store_high_pass = NULL;
- psl->shadow_cascade_store_pass = NULL;
- psl->shadow_cascade_store_high_pass = NULL;
-
- {
- DRW_PASS_CREATE(psl->shadow_cube_copy_pass, DRW_STATE_WRITE_COLOR);
-
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_copy_cube_sh[linfo->shadow_method],
- psl->shadow_cube_copy_pass);
- DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cube_target);
- DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
-
- DRW_shgroup_call_procedural_triangles(grp, NULL, 6);
- }
-
- {
- DRW_PASS_CREATE(psl->shadow_cascade_copy_pass, DRW_STATE_WRITE_COLOR);
-
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_copy_cascade_sh[linfo->shadow_method],
- psl->shadow_cascade_copy_pass);
- DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cascade_target);
- DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
-
- DRW_shgroup_call_procedural_triangles(grp, NULL, MAX_CASCADE_NUM);
- }
-
- {
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- DRW_PASS_CREATE(psl->shadow_pass, state);
-
- stl->g_data->shadow_shgrp = DRW_shgroup_create(e_data.shadow_sh, psl->shadow_pass);
- }
-}
-
-void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
+/* Reconstruct local obmat from EEVEE_light. (normalized) */
+void eevee_light_matrix_get(const EEVEE_Light *evli, float r_mat[4][4])
{
- EEVEE_LightsInfo *linfo = sldata->lights;
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const float threshold = draw_ctx->scene->eevee.light_threshold;
- /* Step 1 find all lights in the scene and setup them */
- if (linfo->num_light >= MAX_LIGHT) {
- printf("Too many lights in the scene !!!\n");
- }
- else {
- Light *la = (Light *)ob->data;
-
- /* Early out if light has no power. */
- if (la->energy == 0.0f || is_zero_v3(&la->r)) {
- return;
- }
-
- EEVEE_Light *evli = linfo->light_data + linfo->num_light;
- eevee_light_setup(ob, evli);
-
- /* We do not support shadowmaps for dupli lights. */
- if ((ob->base_flag & BASE_FROM_DUPLI) != 0) {
- linfo->num_light++;
- return;
- }
-
- EEVEE_LightEngineData *led = EEVEE_light_data_ensure(ob);
-
- /* Save previous shadow id. */
- int prev_cube_sh_id = led->prev_cube_shadow_id;
-
- /* Default light without shadows */
- led->data.ld.shadow_id = -1;
- led->prev_cube_shadow_id = -1;
-
- if (la->mode & LA_SHADOW) {
- if (la->type == LA_SUN) {
- int cascade_nbr = la->cascade_count;
-
- if ((linfo->gpu_cascade_len + 1) <= MAX_SHADOW_CASCADE) {
- /* Save Light object. */
- linfo->shadow_cascade_ref[linfo->cpu_cascade_len] = ob;
-
- /* Store indices. */
- EEVEE_ShadowCascadeData *data = &led->data.scad;
- data->shadow_id = linfo->gpu_shadow_len;
- data->cascade_id = linfo->gpu_cascade_len;
- data->layer_id = linfo->num_cascade_layer;
-
- /* Increment indices. */
- linfo->gpu_shadow_len += 1;
- linfo->gpu_cascade_len += 1;
- linfo->num_cascade_layer += cascade_nbr;
-
- linfo->cpu_cascade_len += 1;
- }
- }
- else if (la->type == LA_SPOT || la->type == LA_LOCAL || la->type == LA_AREA) {
- if ((linfo->gpu_cube_len + 1) <= MAX_SHADOW_CUBE) {
- /* Save Light object. */
- linfo->shadow_cube_ref[linfo->cpu_cube_len] = ob;
-
- /* For light update tracking. */
- if ((prev_cube_sh_id >= 0) && (prev_cube_sh_id < linfo->shcaster_backbuffer->count)) {
- linfo->new_shadow_id[prev_cube_sh_id] = linfo->cpu_cube_len;
- }
- led->prev_cube_shadow_id = linfo->cpu_cube_len;
-
- /* Saving light bounds for later. */
- BLI_assert(linfo->cpu_cube_len >= 0 && linfo->cpu_cube_len < MAX_LIGHT);
- copy_v3_v3(linfo->shadow_bounds[linfo->cpu_cube_len].center, ob->obmat[3]);
- linfo->shadow_bounds[linfo->cpu_cube_len].radius = light_attenuation_radius_get(
- la, threshold);
-
- EEVEE_ShadowCubeData *data = &led->data.scd;
- /* Store indices. */
- data->shadow_id = linfo->gpu_shadow_len;
- data->cube_id = linfo->gpu_cube_len;
- data->layer_id = linfo->num_cube_layer;
-
- /* Increment indices. */
- linfo->gpu_shadow_len += 1;
- linfo->gpu_cube_len += 1;
- linfo->num_cube_layer += 1;
-
- linfo->cpu_cube_len += 1;
- }
- }
- }
-
- led->data.ld.light_id = linfo->num_light;
- linfo->light_ref[linfo->num_light] = ob;
- linfo->num_light++;
- }
-}
-
-/* Add a shadow caster to the shadowpasses */
-void EEVEE_lights_cache_shcaster_add(EEVEE_ViewLayerData *UNUSED(sldata),
- EEVEE_StorageList *stl,
- struct GPUBatch *geom,
- Object *ob)
-{
- DRW_shgroup_call(stl->g_data->shadow_shgrp, geom, ob);
-}
-
-void EEVEE_lights_cache_shcaster_material_add(EEVEE_ViewLayerData *sldata,
- EEVEE_PassList *psl,
- struct GPUMaterial *gpumat,
- struct GPUBatch *geom,
- struct Object *ob,
- const float *alpha_threshold)
-{
- /* TODO / PERF : reuse the same shading group for objects with the same material */
- DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, psl->shadow_pass);
-
- if (grp == NULL) {
- return;
- }
-
- /* Grrr needed for correctness but not 99% of the time not needed.
- * TODO detect when needed? */
- DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
- DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
- DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
- DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
- DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
- DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
-
- if (alpha_threshold != NULL) {
- DRW_shgroup_uniform_float(grp, "alphaThreshold", alpha_threshold, 1);
- }
-
- DRW_shgroup_call(grp, geom, ob);
+ copy_v3_v3(r_mat[0], evli->rightvec);
+ copy_v3_v3(r_mat[1], evli->upvec);
+ negate_v3_v3(r_mat[2], evli->forwardvec);
+ copy_v3_v3(r_mat[3], evli->position);
+ r_mat[0][3] = 0.0f;
+ r_mat[1][3] = 0.0f;
+ r_mat[2][3] = 0.0f;
+ r_mat[3][3] = 1.0f;
}
-/* Make that object update shadow casting lights inside its influence bounding box. */
-void EEVEE_lights_cache_shcaster_object_add(EEVEE_ViewLayerData *sldata, Object *ob)
-{
- if ((ob->base_flag & BASE_FROM_DUPLI) != 0) {
- /* TODO: Special case for dupli objects because we cannot save the object pointer. */
- return;
- }
-
- EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob);
- EEVEE_LightsInfo *linfo = sldata->lights;
- EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
- EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
- int past_id = oedata->shadow_caster_id;
-
- /* Update flags in backbuffer. */
- if (past_id > -1 && past_id < backbuffer->count) {
- backbuffer->flags[past_id] &= ~SHADOW_CASTER_PRUNED;
-
- if (oedata->need_update) {
- backbuffer->flags[past_id] |= SHADOW_CASTER_UPDATED;
- }
- }
-
- /* Update id. */
- oedata->shadow_caster_id = frontbuffer->count++;
-
- /* Make sure shadow_casters is big enough. */
- if (oedata->shadow_caster_id >= frontbuffer->alloc_count) {
- frontbuffer->alloc_count += SHADOW_CASTER_ALLOC_CHUNK;
- frontbuffer->shadow_casters = MEM_reallocN(
- frontbuffer->shadow_casters, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count);
- frontbuffer->flags = MEM_reallocN(frontbuffer->flags,
- sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count);
- }
-
- EEVEE_ShadowCaster *shcaster = frontbuffer->shadow_casters + oedata->shadow_caster_id;
-
- if (oedata->need_update) {
- frontbuffer->flags[oedata->shadow_caster_id] = SHADOW_CASTER_UPDATED;
- }
-
- /* Update World AABB in frontbuffer. */
- BoundBox *bb = BKE_object_boundbox_get(ob);
- float min[3], max[3];
- INIT_MINMAX(min, max);
- for (int i = 0; i < 8; ++i) {
- float vec[3];
- copy_v3_v3(vec, bb->vec[i]);
- mul_m4_v3(ob->obmat, vec);
- minmax_v3v3_v3(min, max, vec);
- }
-
- EEVEE_BoundBox *aabb = &shcaster->bbox;
- add_v3_v3v3(aabb->center, min, max);
- mul_v3_fl(aabb->center, 0.5f);
- sub_v3_v3v3(aabb->halfdim, aabb->center, max);
-
- aabb->halfdim[0] = fabsf(aabb->halfdim[0]);
- aabb->halfdim[1] = fabsf(aabb->halfdim[1]);
- aabb->halfdim[2] = fabsf(aabb->halfdim[2]);
-
- oedata->need_update = false;
-}
-
-void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
-{
- EEVEE_LightsInfo *linfo = sldata->lights;
- eGPUTextureFormat shadow_pool_format = GPU_R32F;
-
- sldata->common_data.la_num_light = linfo->num_light;
-
- /* Setup enough layers. */
- /* Free textures if number mismatch. */
- if (linfo->num_cube_layer != linfo->cache_num_cube_layer) {
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool);
- linfo->cache_num_cube_layer = linfo->num_cube_layer;
- linfo->update_flag |= LIGHT_UPDATE_SHADOW_CUBE;
- }
-
- if (linfo->num_cascade_layer != linfo->cache_num_cascade_layer) {
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool);
- linfo->cache_num_cascade_layer = linfo->num_cascade_layer;
- }
-
- switch (linfo->shadow_method) {
- case SHADOW_ESM:
- shadow_pool_format = ((linfo->shadow_high_bitdepth) ? GPU_R32F : GPU_R16F);
- break;
- case SHADOW_VSM:
- shadow_pool_format = ((linfo->shadow_high_bitdepth) ? GPU_RG32F : GPU_RG16F);
- break;
- default:
- BLI_assert(!"Incorrect Shadow Method");
- break;
- }
-
- /* Cubemaps */
- if (!sldata->shadow_cube_target) {
- sldata->shadow_cube_target = DRW_texture_create_cube(
- linfo->shadow_cube_size, GPU_DEPTH_COMPONENT24, 0, NULL);
- sldata->shadow_cube_blur = DRW_texture_create_cube(
- linfo->shadow_cube_size, shadow_pool_format, DRW_TEX_FILTER, NULL);
- }
- GPU_framebuffer_ensure_config(
- &sldata->shadow_cube_copy_fb,
- {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(sldata->shadow_cube_blur)});
-
- if (!sldata->shadow_cube_pool) {
- sldata->shadow_cube_pool = DRW_texture_create_2d_array(linfo->shadow_cube_store_size,
- linfo->shadow_cube_store_size,
- max_ii(1, linfo->num_cube_layer),
- shadow_pool_format,
- DRW_TEX_FILTER,
- NULL);
- }
- GPU_framebuffer_ensure_config(&sldata->shadow_cube_target_fb,
- {GPU_ATTACHMENT_TEXTURE(sldata->shadow_cube_target)});
- GPU_framebuffer_ensure_config(
- &sldata->shadow_cube_store_fb,
- {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(sldata->shadow_cube_pool)});
-
- /* CSM */
- if (!sldata->shadow_cascade_target) {
- sldata->shadow_cascade_target = DRW_texture_create_2d_array(linfo->shadow_cascade_size,
- linfo->shadow_cascade_size,
- MAX_CASCADE_NUM,
- GPU_DEPTH_COMPONENT24,
- 0,
- NULL);
- sldata->shadow_cascade_blur = DRW_texture_create_2d_array(linfo->shadow_cascade_size,
- linfo->shadow_cascade_size,
- MAX_CASCADE_NUM,
- shadow_pool_format,
- DRW_TEX_FILTER,
- NULL);
- }
- GPU_framebuffer_ensure_config(
- &sldata->shadow_cascade_copy_fb,
- {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(sldata->shadow_cascade_blur)});
-
- if (!sldata->shadow_cascade_pool) {
- sldata->shadow_cascade_pool = DRW_texture_create_2d_array(linfo->shadow_cascade_size,
- linfo->shadow_cascade_size,
- max_ii(1, linfo->num_cascade_layer),
- shadow_pool_format,
- DRW_TEX_FILTER,
- NULL);
- }
- GPU_framebuffer_ensure_config(&sldata->shadow_cascade_target_fb,
- {GPU_ATTACHMENT_TEXTURE(sldata->shadow_cascade_target)});
- GPU_framebuffer_ensure_config(
- &sldata->shadow_cascade_store_fb,
- {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(sldata->shadow_cascade_pool)});
-
- /* Update Lights UBOs. */
- EEVEE_lights_update(sldata, vedata);
-}
-
-float light_attenuation_radius_get(Light *la, float light_threshold)
+static float light_attenuation_radius_get(const Light *la, float light_threshold)
{
if (la->mode & LA_CUSTOM_ATTENUATION) {
return la->att_dist;
@@ -664,7 +57,7 @@ float light_attenuation_radius_get(Light *la, float light_threshold)
return distance;
}
-static void light_shape_parameters_set(EEVEE_Light *evli, const Light *la, float scale[3])
+static void light_shape_parameters_set(EEVEE_Light *evli, const Light *la, const float scale[3])
{
if (la->type == LA_SPOT) {
/* Spot size & blend */
@@ -684,7 +77,7 @@ static void light_shape_parameters_set(EEVEE_Light *evli, const Light *la, float
}
}
else if (la->type == LA_SUN) {
- evli->radius = max_ff(0.001f, tanf(la->sun_angle / 2.0f));
+ evli->radius = max_ff(0.001f, tanf(min_ff(la->sun_angle, DEG2RADF(179.9f)) / 2.0f));
}
else {
evli->radius = max_ff(0.001f, la->area_size);
@@ -774,809 +167,54 @@ static void eevee_light_setup(Object *ob, EEVEE_Light *evli)
mul_v3_fl(evli->color, power * la->energy);
/* No shadow by default */
- evli->shadowid = -1.0f;
-}
-
-/**
- * Special ball distribution:
- * Point are distributed in a way that when they are orthogonally
- * projected into any plane, the resulting distribution is (close to)
- * a uniform disc distribution.
- */
-static void sample_ball(int sample_ofs, float radius, float rsample[3])
-{
- double ht_point[3];
- double ht_offset[3] = {0.0, 0.0, 0.0};
- uint ht_primes[3] = {2, 3, 7};
-
- BLI_halton_3d(ht_primes, ht_offset, sample_ofs, ht_point);
-
- float omega = ht_point[1] * 2.0f * M_PI;
-
- rsample[2] = ht_point[0] * 2.0f - 1.0f; /* cos theta */
-
- float r = sqrtf(fmaxf(0.0f, 1.0f - rsample[2] * rsample[2])); /* sin theta */
-
- rsample[0] = r * cosf(omega);
- rsample[1] = r * sinf(omega);
-
- radius *= sqrt(sqrt(ht_point[2]));
- mul_v3_fl(rsample, radius);
-}
-
-static void sample_rectangle(
- int sample_ofs, float x_axis[3], float y_axis[3], float size_x, float size_y, float rsample[3])
-{
- double ht_point[2];
- double ht_offset[2] = {0.0, 0.0};
- uint ht_primes[2] = {2, 3};
-
- BLI_halton_2d(ht_primes, ht_offset, sample_ofs, ht_point);
-
- /* Change ditribution center to be 0,0 */
- ht_point[0] = (ht_point[0] > 0.5f) ? ht_point[0] - 1.0f : ht_point[0];
- ht_point[1] = (ht_point[1] > 0.5f) ? ht_point[1] - 1.0f : ht_point[1];
-
- zero_v3(rsample);
- madd_v3_v3fl(rsample, x_axis, (ht_point[0] * 2.0f) * size_x);
- madd_v3_v3fl(rsample, y_axis, (ht_point[1] * 2.0f) * size_y);
-}
-
-static void sample_ellipse(
- int sample_ofs, float x_axis[3], float y_axis[3], float size_x, float size_y, float rsample[3])
-{
- double ht_point[2];
- double ht_offset[2] = {0.0, 0.0};
- uint ht_primes[2] = {2, 3};
-
- BLI_halton_2d(ht_primes, ht_offset, sample_ofs, ht_point);
-
- /* Uniform disc sampling. */
- float omega = ht_point[1] * 2.0f * M_PI;
- float r = sqrtf(ht_point[0]);
- ht_point[0] = r * cosf(omega) * size_x;
- ht_point[1] = r * sinf(omega) * size_y;
-
- zero_v3(rsample);
- madd_v3_v3fl(rsample, x_axis, ht_point[0]);
- madd_v3_v3fl(rsample, y_axis, ht_point[1]);
-}
-
-static void shadow_cube_random_position_set(EEVEE_Light *evli,
- Light *la,
- int sample_ofs,
- float ws_sample_pos[3])
-{
- float jitter[3];
-
-#ifndef DEBUG_SHADOW_DISTRIBUTION
- int i = sample_ofs;
-#else
- for (int i = 0; i <= sample_ofs; ++i) {
-#endif
- switch (la->type) {
- case LA_AREA:
- if (ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_SQUARE)) {
- sample_rectangle(i, evli->rightvec, evli->upvec, evli->sizex, evli->sizey, jitter);
- }
- else {
- sample_ellipse(i, evli->rightvec, evli->upvec, evli->sizex, evli->sizey, jitter);
- }
- break;
- default:
- sample_ball(i, evli->radius, jitter);
- }
-#ifdef DEBUG_SHADOW_DISTRIBUTION
- float p[3];
- add_v3_v3v3(p, jitter, ws_sample_pos);
- DRW_debug_sphere(p, 0.01f, (float[4]){1.0f, (sample_ofs == i) ? 1.0f : 0.0f, 0.0f, 1.0f});
-}
-#endif
-add_v3_v3(ws_sample_pos, jitter);
-}
-
-static void eevee_shadow_cube_setup(Object *ob,
- EEVEE_LightsInfo *linfo,
- EEVEE_LightEngineData *led,
- int sample_ofs)
-{
- EEVEE_ShadowCubeData *sh_data = &led->data.scd;
- EEVEE_Light *evli = linfo->light_data + sh_data->light_id;
- EEVEE_Shadow *ubo_data = linfo->shadow_data + sh_data->shadow_id;
- EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + sh_data->cube_id;
- Light *la = (Light *)ob->data;
-
- copy_v3_v3(cube_data->position, ob->obmat[3]);
-
- if (linfo->soft_shadows) {
- shadow_cube_random_position_set(evli, la, sample_ofs, cube_data->position);
- }
-
- ubo_data->bias = 0.05f * la->bias;
- ubo_data->near = la->clipsta;
- ubo_data->far = 1.0f / (evli->invsqrdist * evli->invsqrdist);
- ubo_data->exp = (linfo->shadow_method == SHADOW_VSM) ? la->bleedbias : la->bleedexp;
-
- evli->shadowid = (float)(sh_data->shadow_id);
- ubo_data->shadow_start = (float)(sh_data->layer_id);
- ubo_data->data_start = (float)(sh_data->cube_id);
- ubo_data->shadow_blur = la->soft * 0.02f; /* Used by translucence shadowmap blur */
-
- ubo_data->contact_dist = (la->mode & LA_SHAD_CONTACT) ? la->contact_dist : 0.0f;
- ubo_data->contact_bias = 0.05f * la->contact_bias;
- ubo_data->contact_spread = la->contact_spread;
- ubo_data->contact_thickness = la->contact_thickness;
-}
-
-static void shadow_cascade_random_matrix_set(float mat[4][4], float radius, int sample_ofs)
-{
- float jitter[3];
-
-#ifndef DEBUG_SHADOW_DISTRIBUTION
- int i = sample_ofs;
-#else
- for (int i = 0; i <= sample_ofs; ++i) {
-#endif
- sample_ellipse(i, mat[0], mat[1], radius, radius, jitter);
-#ifdef DEBUG_SHADOW_DISTRIBUTION
- float p[3];
- add_v3_v3v3(p, jitter, mat[2]);
- DRW_debug_sphere(p, 0.01f, (float[4]){1.0f, (sample_ofs == i) ? 1.0f : 0.0f, 0.0f, 1.0f});
-}
-#endif
-
-add_v3_v3(mat[2], jitter);
-orthogonalize_m4(mat, 2);
-}
-
-#define LERP(t, a, b) ((a) + (t) * ((b) - (a)))
-
-static double round_to_digits(double value, int digits)
-{
- double factor = pow(10.0, digits - ceil(log10(fabs(value))));
- return round(value * factor) / factor;
-}
-
-static void frustum_min_bounding_sphere(const float corners[8][3],
- float r_center[3],
- float *r_radius)
-{
-#if 0 /* Simple solution but waste too much space. */
- float minvec[3], maxvec[3];
-
- /* compute the bounding box */
- INIT_MINMAX(minvec, maxvec);
- for (int i = 0; i < 8; ++i) {
- minmax_v3v3_v3(minvec, maxvec, corners[i]);
- }
-
- /* compute the bounding sphere of this box */
- r_radius = len_v3v3(minvec, maxvec) * 0.5f;
- add_v3_v3v3(r_center, minvec, maxvec);
- mul_v3_fl(r_center, 0.5f);
-#else
- /* Find averaged center. */
- zero_v3(r_center);
- for (int i = 0; i < 8; ++i) {
- add_v3_v3(r_center, corners[i]);
- }
- mul_v3_fl(r_center, 1.0f / 8.0f);
-
- /* Search the largest distance from the sphere center. */
- *r_radius = 0.0f;
- for (int i = 0; i < 8; ++i) {
- float rad = len_squared_v3v3(corners[i], r_center);
- if (rad > *r_radius) {
- *r_radius = rad;
- }
- }
-
- /* TODO try to reduce the radius further by moving the center.
- * Remember we need a __stable__ solution! */
-
- /* Try to reduce float imprecision leading to shimmering. */
- *r_radius = (float)round_to_digits(sqrtf(*r_radius), 3);
-#endif
-}
-
-static void eevee_shadow_cascade_setup(Object *ob,
- EEVEE_LightsInfo *linfo,
- EEVEE_LightEngineData *led,
- DRWView *view,
- float view_near,
- float view_far,
- int sample_ofs)
-{
- Light *la = (Light *)ob->data;
-
- /* Camera Matrices */
- float persinv[4][4], vp_projmat[4][4];
- DRW_view_persmat_get(view, persinv, true);
- DRW_view_winmat_get(view, vp_projmat, false);
- bool is_persp = DRW_view_is_persp_get(view);
-
- /* Lights Matrices */
- int cascade_nbr = la->cascade_count;
-
- EEVEE_ShadowCascadeData *sh_data = &led->data.scad;
- EEVEE_Light *evli = linfo->light_data + sh_data->light_id;
- EEVEE_Shadow *ubo_data = linfo->shadow_data + sh_data->shadow_id;
- EEVEE_ShadowCascade *cascade_data = linfo->shadow_cascade_data + sh_data->cascade_id;
-
- /* obmat = Object Space > World Space */
- /* viewmat = World Space > View Space */
- float(*viewmat)[4] = sh_data->viewmat;
-#if 0 /* done at culling time */
- normalize_m4_m4(viewmat, ob->obmat);
-#endif
-
- if (linfo->soft_shadows) {
- shadow_cascade_random_matrix_set(viewmat, evli->radius, sample_ofs);
- }
-
- copy_m4_m4(sh_data->viewinv, viewmat);
- invert_m4(viewmat);
-
- /* The technique consists into splitting
- * the view frustum into several sub-frustum
- * that are individually receiving one shadow map */
-
- float csm_start, csm_end;
-
- if (is_persp) {
- csm_start = view_near;
- csm_end = max_ff(view_far, -la->cascade_max_dist);
- /* Avoid artifacts */
- csm_end = min_ff(view_near, csm_end);
- }
- else {
- csm_start = -view_far;
- csm_end = view_far;
- }
-
- /* init near/far */
- for (int c = 0; c < MAX_CASCADE_NUM; ++c) {
- cascade_data->split_start[c] = csm_end;
- cascade_data->split_end[c] = csm_end;
- }
-
- /* Compute split planes */
- float splits_start_ndc[MAX_CASCADE_NUM];
- float splits_end_ndc[MAX_CASCADE_NUM];
-
- {
- /* Nearest plane */
- float p[4] = {1.0f, 1.0f, csm_start, 1.0f};
- /* TODO: we don't need full m4 multiply here */
- mul_m4_v4(vp_projmat, p);
- splits_start_ndc[0] = p[2];
- if (is_persp) {
- splits_start_ndc[0] /= p[3];
- }
- }
-
- {
- /* Farthest plane */
- float p[4] = {1.0f, 1.0f, csm_end, 1.0f};
- /* TODO: we don't need full m4 multiply here */
- mul_m4_v4(vp_projmat, p);
- splits_end_ndc[cascade_nbr - 1] = p[2];
- if (is_persp) {
- splits_end_ndc[cascade_nbr - 1] /= p[3];
- }
- }
-
- cascade_data->split_start[0] = csm_start;
- cascade_data->split_end[cascade_nbr - 1] = csm_end;
-
- for (int c = 1; c < cascade_nbr; ++c) {
- /* View Space */
- float linear_split = LERP(((float)(c) / (float)cascade_nbr), csm_start, csm_end);
- float exp_split = csm_start * powf(csm_end / csm_start, (float)(c) / (float)cascade_nbr);
-
- if (is_persp) {
- cascade_data->split_start[c] = LERP(la->cascade_exponent, linear_split, exp_split);
- }
- else {
- cascade_data->split_start[c] = linear_split;
- }
- cascade_data->split_end[c - 1] = cascade_data->split_start[c];
-
- /* Add some overlap for smooth transition */
- cascade_data->split_start[c] = LERP(la->cascade_fade,
- cascade_data->split_end[c - 1],
- (c > 1) ? cascade_data->split_end[c - 2] :
- cascade_data->split_start[0]);
-
- /* NDC Space */
- {
- float p[4] = {1.0f, 1.0f, cascade_data->split_start[c], 1.0f};
- /* TODO: we don't need full m4 multiply here */
- mul_m4_v4(vp_projmat, p);
- splits_start_ndc[c] = p[2];
-
- if (is_persp) {
- splits_start_ndc[c] /= p[3];
- }
- }
-
- {
- float p[4] = {1.0f, 1.0f, cascade_data->split_end[c - 1], 1.0f};
- /* TODO: we don't need full m4 multiply here */
- mul_m4_v4(vp_projmat, p);
- splits_end_ndc[c - 1] = p[2];
-
- if (is_persp) {
- splits_end_ndc[c - 1] /= p[3];
- }
- }
- }
-
- /* Set last cascade split fade distance into the first split_start. */
- float prev_split = (cascade_nbr > 1) ? cascade_data->split_end[cascade_nbr - 2] :
- cascade_data->split_start[0];
- cascade_data->split_start[0] = LERP(
- la->cascade_fade, cascade_data->split_end[cascade_nbr - 1], prev_split);
-
- /* For each cascade */
- for (int c = 0; c < cascade_nbr; ++c) {
- float(*projmat)[4] = sh_data->projmat[c];
- /* Given 8 frustum corners */
- float corners[8][3] = {
- /* Near Cap */
- {1.0f, -1.0f, splits_start_ndc[c]},
- {-1.0f, -1.0f, splits_start_ndc[c]},
- {-1.0f, 1.0f, splits_start_ndc[c]},
- {1.0f, 1.0f, splits_start_ndc[c]},
- /* Far Cap */
- {1.0f, -1.0f, splits_end_ndc[c]},
- {-1.0f, -1.0f, splits_end_ndc[c]},
- {-1.0f, 1.0f, splits_end_ndc[c]},
- {1.0f, 1.0f, splits_end_ndc[c]},
- };
-
- /* Transform them into world space */
- for (int i = 0; i < 8; ++i) {
- mul_project_m4_v3(persinv, corners[i]);
- }
-
- float center[3];
- frustum_min_bounding_sphere(corners, center, &(sh_data->radius[c]));
-
-#ifdef DEBUG_CSM
- float dbg_col[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- if (c < 3) {
- dbg_col[c] = 1.0f;
- }
- DRW_debug_bbox((BoundBox *)&corners, dbg_col);
- DRW_debug_sphere(center, sh_data->radius[c], dbg_col);
-#endif
-
- /* Project into lightspace */
- mul_m4_v3(viewmat, center);
-
- /* Snap projection center to nearest texel to cancel shimmering. */
- float shadow_origin[2], shadow_texco[2];
- /* Light to texture space. */
- mul_v2_v2fl(shadow_origin, center, linfo->shadow_cascade_size / (2.0f * sh_data->radius[c]));
-
- /* Find the nearest texel. */
- shadow_texco[0] = roundf(shadow_origin[0]);
- shadow_texco[1] = roundf(shadow_origin[1]);
-
- /* Compute offset. */
- sub_v2_v2(shadow_texco, shadow_origin);
- /* Texture to light space. */
- mul_v2_fl(shadow_texco, (2.0f * sh_data->radius[c]) / linfo->shadow_cascade_size);
-
- /* Apply offset. */
- add_v2_v2(center, shadow_texco);
-
- /* Expand the projection to cover frustum range */
- rctf rect_cascade;
- BLI_rctf_init_pt_radius(&rect_cascade, center, sh_data->radius[c]);
- orthographic_m4(projmat,
- rect_cascade.xmin,
- rect_cascade.xmax,
- rect_cascade.ymin,
- rect_cascade.ymax,
- la->clipsta,
- la->clipend);
-
- mul_m4_m4m4(sh_data->viewprojmat[c], projmat, viewmat);
- mul_m4_m4m4(cascade_data->shadowmat[c], texcomat, sh_data->viewprojmat[c]);
-
-#ifdef DEBUG_CSM
- DRW_debug_m4_as_bbox(sh_data->viewprojmat[c], dbg_col, true);
-#endif
- }
-
- ubo_data->bias = 0.05f * la->bias;
- ubo_data->near = la->clipsta;
- ubo_data->far = la->clipend;
- ubo_data->exp = (linfo->shadow_method == SHADOW_VSM) ? la->bleedbias : la->bleedexp;
-
- evli->shadowid = (float)(sh_data->shadow_id);
- ubo_data->shadow_start = (float)(sh_data->layer_id);
- ubo_data->data_start = (float)(sh_data->cascade_id);
- ubo_data->shadow_blur = la->soft * 0.02f; /* Used by translucence shadowmap blur */
-
- ubo_data->contact_dist = (la->mode & LA_SHAD_CONTACT) ? la->contact_dist : 0.0f;
- ubo_data->contact_bias = 0.05f * la->contact_bias;
- ubo_data->contact_spread = la->contact_spread;
- ubo_data->contact_thickness = la->contact_thickness;
+ evli->shadow_id = -1.0f;
}
-/* Used for checking if object is inside the shadow volume. */
-static bool sphere_bbox_intersect(const EEVEE_BoundSphere *bs, const EEVEE_BoundBox *bb)
+void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
- /* We are testing using a rougher AABB vs AABB test instead of full AABB vs Sphere. */
- /* TODO test speed with AABB vs Sphere. */
- bool x = fabsf(bb->center[0] - bs->center[0]) <= (bb->halfdim[0] + bs->radius);
- bool y = fabsf(bb->center[1] - bs->center[1]) <= (bb->halfdim[1] + bs->radius);
- bool z = fabsf(bb->center[2] - bs->center[2]) <= (bb->halfdim[2] + bs->radius);
+ EEVEE_LightsInfo *linfo = sldata->lights;
+ linfo->num_light = 0;
- return x && y && z;
+ EEVEE_shadows_cache_init(sldata, vedata);
}
-void EEVEE_lights_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
{
- EEVEE_StorageList *stl = vedata->stl;
- EEVEE_EffectsInfo *effects = stl->effects;
EEVEE_LightsInfo *linfo = sldata->lights;
- Object *ob;
- int i;
- char *flag;
- EEVEE_ShadowCaster *shcaster;
- EEVEE_BoundSphere *bsphere;
- EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
- EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
-
- EEVEE_LightBits update_bits = {{0}};
- if ((linfo->update_flag & LIGHT_UPDATE_SHADOW_CUBE) != 0) {
- /* Update all lights. */
- lightbits_set_all(&update_bits, true);
- }
- else {
- /* Search for deleted shadow casters and if shcaster WAS in shadow radius. */
- /* No need to run this if we already update all lights. */
- EEVEE_LightBits past_bits = {{0}};
- EEVEE_LightBits curr_bits = {{0}};
- shcaster = backbuffer->shadow_casters;
- flag = backbuffer->flags;
- for (i = 0; i < backbuffer->count; ++i, ++flag, ++shcaster) {
- /* If the shadowcaster has been deleted or updated. */
- if (*flag != 0) {
- /* Add the lights that were intersecting with its BBox. */
- lightbits_or(&past_bits, &shcaster->bits);
- }
- }
- /* Convert old bits to new bits and add result to final update bits. */
- /* NOTE: This might be overkill since all lights are tagged to refresh if
- * the light count changes. */
- lightbits_convert(&curr_bits, &past_bits, linfo->new_shadow_id, MAX_LIGHT);
- lightbits_or(&update_bits, &curr_bits);
- }
-
- /* Search for updates in current shadow casters. */
- shcaster = frontbuffer->shadow_casters;
- flag = frontbuffer->flags;
- for (i = 0; i < frontbuffer->count; i++, flag++, shcaster++) {
- /* Run intersection checks to fill the bitfields. */
- bsphere = linfo->shadow_bounds;
- for (int j = 0; j < linfo->cpu_cube_len; j++, bsphere++) {
- bool iter = sphere_bbox_intersect(bsphere, &shcaster->bbox);
- lightbits_set_single(&shcaster->bits, j, iter);
- }
- /* Only add to final bits if objects has been updated. */
- if (*flag != 0) {
- lightbits_or(&update_bits, &shcaster->bits);
- }
- }
+ const Light *la = (Light *)ob->data;
- /* Setup shadow cube in UBO and tag for update if necessary. */
- for (i = 0; (i < MAX_SHADOW_CUBE) && (ob = linfo->shadow_cube_ref[i]); i++) {
- EEVEE_LightEngineData *led = EEVEE_light_data_ensure(ob);
-
- eevee_shadow_cube_setup(ob, linfo, led, effects->taa_current_sample - 1);
- if (lightbits_get(&update_bits, i) != 0 || linfo->soft_shadows) {
- led->need_update = true;
- }
+ if (linfo->num_light >= MAX_LIGHT) {
+ printf("Too many lights in the scene !!!\n");
+ return;
}
- /* Resize shcasters buffers if too big. */
- if (frontbuffer->alloc_count - frontbuffer->count > SHADOW_CASTER_ALLOC_CHUNK) {
- frontbuffer->alloc_count = (frontbuffer->count / SHADOW_CASTER_ALLOC_CHUNK) *
- SHADOW_CASTER_ALLOC_CHUNK;
- frontbuffer->alloc_count += (frontbuffer->count % SHADOW_CASTER_ALLOC_CHUNK != 0) ?
- SHADOW_CASTER_ALLOC_CHUNK :
- 0;
- frontbuffer->shadow_casters = MEM_reallocN(
- frontbuffer->shadow_casters, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count);
- frontbuffer->flags = MEM_reallocN(frontbuffer->flags,
- sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count);
+ /* Early out if light has no power. */
+ if (la->energy == 0.0f || is_zero_v3(&la->r)) {
+ return;
}
-}
-
-static void eevee_ensure_cube_views(float near, float far, const float pos[3], DRWView *view[6])
-{
- float winmat[4][4], viewmat[4][4];
- perspective_m4(winmat, -near, near, -near, near, near, far);
- for (int i = 0; i < 6; i++) {
- unit_m4(viewmat);
- negate_v3_v3(viewmat[3], pos);
- mul_m4_m4m4(viewmat, cubefacemat[i], viewmat);
+ EEVEE_Light *evli = linfo->light_data + linfo->num_light;
+ eevee_light_setup(ob, evli);
- if (view[i] == NULL) {
- view[i] = DRW_view_create(viewmat, winmat, NULL, NULL, NULL);
+ if (la->mode & LA_SHADOW) {
+ if (la->type == LA_SUN) {
+ EEVEE_shadows_cascade_add(linfo, evli, ob);
}
- else {
- DRW_view_update(view[i], viewmat, winmat, NULL, NULL);
+ else if (ELEM(la->type, LA_SPOT, LA_LOCAL, LA_AREA)) {
+ EEVEE_shadows_cube_add(linfo, evli, ob);
}
}
-}
-static void eevee_ensure_cascade_views(EEVEE_ShadowCascadeData *cascade_data,
- int cascade_count,
- DRWView *view[4])
-{
- for (int i = 0; i < cascade_count; i++) {
- if (view[i] == NULL) {
- view[i] = DRW_view_create(cascade_data->viewmat, cascade_data->projmat[i], NULL, NULL, NULL);
- }
- else {
- DRW_view_update(view[i], cascade_data->viewmat, cascade_data->projmat[i], NULL, NULL);
- }
- }
+ linfo->num_light++;
}
-/* this refresh lights shadow buffers */
-void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWView *view)
+void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
- EEVEE_PassList *psl = vedata->psl;
- EEVEE_StorageList *stl = vedata->stl;
- EEVEE_EffectsInfo *effects = stl->effects;
- EEVEE_PrivateData *g_data = stl->g_data;
EEVEE_LightsInfo *linfo = sldata->lights;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const float light_threshold = draw_ctx->scene->eevee.light_threshold;
- Object *ob;
- int i;
-
- int saved_ray_type = sldata->common_data.ray_type;
-
- /* TODO: make it optional if we don't draw shadows. */
- sldata->common_data.ray_type = EEVEE_RAY_SHADOW;
- DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
-
- /* Precompute all shadow/view test before rendering and trashing the culling cache. */
- bool cube_visible[MAX_SHADOW_CUBE];
- for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
- Light *la = (Light *)ob->data;
- BoundSphere bsphere = {
- .center = {ob->obmat[3][0], ob->obmat[3][1], ob->obmat[3][2]},
- .radius = light_attenuation_radius_get(la, light_threshold),
- };
- cube_visible[i] = DRW_culling_sphere_test(view, &bsphere);
- }
-
- bool cascade_visible[MAX_SHADOW_CASCADE];
- for (i = 0; (ob = linfo->shadow_cascade_ref[i]) && (i < MAX_SHADOW_CASCADE); i++) {
- EEVEE_LightEngineData *led = EEVEE_light_data_get(ob);
- EEVEE_ShadowCascadeData *sh_data = &led->data.scad;
- float plane[4];
- normalize_m4_m4(sh_data->viewmat, ob->obmat);
- plane_from_point_normal_v3(plane, sh_data->viewmat[3], sh_data->viewmat[2]);
- /* TODO: check against near/far instead of "local Z = 0" plane.
- * Or even the cascades AABB. */
- cascade_visible[i] = DRW_culling_plane_test(view, plane);
- }
-
- /* Cube Shadow Maps */
- DRW_stats_group_start("Cube Shadow Maps");
- /* Render each shadow to one layer of the array */
- for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
- EEVEE_LightEngineData *led = EEVEE_light_data_ensure(ob);
- Light *la = (Light *)ob->data;
-
- if (!led->need_update || !cube_visible[i]) {
- continue;
- }
-
- EEVEE_ShadowRender *srd = &linfo->shadow_render_data;
- EEVEE_ShadowCubeData *evscd = &led->data.scd;
- EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + evscd->cube_id;
-
- srd->clip_near = la->clipsta;
- srd->clip_far = light_attenuation_radius_get(la, light_threshold);
- srd->stored_texel_size = 1.0 / (float)linfo->shadow_cube_store_size;
- srd->exponent = la->bleedexp;
-
- eevee_ensure_cube_views(
- srd->clip_near, srd->clip_far, cube_data->position, g_data->cube_views);
-
- /* Render shadow cube */
- /* Render 6 faces separately: seems to be faster for the general case.
- * The only time it's more beneficial is when the CPU culling overhead
- * outweigh the instancing overhead. which is rarely the case. */
- for (int j = 0; j < 6; j++) {
- DRW_view_set_active(g_data->cube_views[j]);
-
- GPU_framebuffer_texture_cubeface_attach(
- sldata->shadow_cube_target_fb, sldata->shadow_cube_target, 0, j, 0);
- GPU_framebuffer_bind(sldata->shadow_cube_target_fb);
- GPU_framebuffer_clear_depth(sldata->shadow_cube_target_fb, 1.0f);
- DRW_draw_pass(psl->shadow_pass);
- }
-
- /* 0.001f is arbitrary, but it should be relatively small so that filter size is not too big.
- */
- float filter_texture_size = la->soft * 0.001f;
- float filter_pixel_size = ceil(filter_texture_size / srd->cube_texel_size);
-
- /* TODO: OPTI: Don't do this intermediate step if no filter is needed. */
- {
- srd->filter_size[0] = srd->cube_texel_size * ((filter_pixel_size > 1.0f) ? 1.5f : 0.0f);
- srd->view_count = 6;
- srd->base_id = 0;
- DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd);
-
- /* Copy using a small 3x3 box filter */
- GPU_framebuffer_bind(sldata->shadow_cube_copy_fb);
- DRW_draw_pass(psl->shadow_cube_copy_pass);
- }
- /* Push it to shadowmap array */
- {
- /* Adjust constants if concentric samples change. */
- const float max_filter_size = 7.5f;
- const float magic = 4.5f; /* Dunno why but that works. */
- const int max_sample = 256;
-
- if (filter_pixel_size > 2.0f) {
- srd->filter_size[0] = srd->cube_texel_size * max_filter_size * magic;
- filter_pixel_size = max_ff(0.0f, filter_pixel_size - 3.0f);
- /* Compute number of concentric samples. Depends directly on filter size. */
- float pix_size_sqr = filter_pixel_size * filter_pixel_size;
- srd->shadow_samples_len[0] = min_ii(
- max_sample, 4 + 8 * (int)filter_pixel_size + 4 * (int)(pix_size_sqr));
- }
- else {
- srd->filter_size[0] = 0.0f;
- srd->shadow_samples_len[0] = 4;
- }
- srd->view_count = 1;
- srd->base_id = evscd->layer_id;
- srd->shadow_samples_len_inv[0] = 1.0f / (float)srd->shadow_samples_len[0];
- DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd);
-
- DRWPass *store_pass = eevee_lights_cube_store_pass_get(
- psl, sldata, linfo->shadow_method, srd->shadow_samples_len[0]);
-
- GPU_framebuffer_bind(sldata->shadow_cube_store_fb);
- DRW_draw_pass(store_pass);
- }
-
- if (linfo->soft_shadows == false) {
- led->need_update = false;
- }
- }
- linfo->update_flag &= ~LIGHT_UPDATE_SHADOW_CUBE;
- DRW_stats_group_end();
-
- float near = DRW_view_near_distance_get(view);
- float far = DRW_view_far_distance_get(view);
-
- /* Cascaded Shadow Maps */
- DRW_stats_group_start("Cascaded Shadow Maps");
- for (i = 0; (ob = linfo->shadow_cascade_ref[i]) && (i < MAX_SHADOW_CASCADE); i++) {
- if (!cascade_visible[i]) {
- continue;
- }
-
- EEVEE_LightEngineData *led = EEVEE_light_data_ensure(ob);
- Light *la = (Light *)ob->data;
-
- EEVEE_ShadowCascadeData *evscd = &led->data.scad;
- EEVEE_ShadowRender *srd = &linfo->shadow_render_data;
-
- srd->clip_near = la->clipsta;
- srd->clip_far = la->clipend;
- srd->view_count = la->cascade_count;
- srd->stored_texel_size = 1.0 / (float)linfo->shadow_cascade_size;
-
- DRW_uniformbuffer_update(sldata->shadow_render_ubo, &linfo->shadow_render_data);
-
- eevee_shadow_cascade_setup(ob, linfo, led, view, near, far, effects->taa_current_sample - 1);
-
- /* Meh, Reusing the cube views. */
- BLI_assert(MAX_CASCADE_NUM <= 6);
- eevee_ensure_cascade_views(evscd, la->cascade_count, g_data->cube_views);
-
- /* Render shadow cascades */
- /* Render cascade separately: seems to be faster for the general case.
- * The only time it's more beneficial is when the CPU culling overhead
- * outweigh the instancing overhead. which is rarely the case. */
- for (int j = 0; j < la->cascade_count; j++) {
- DRW_view_set_active(g_data->cube_views[j]);
-
- GPU_framebuffer_texture_layer_attach(
- sldata->shadow_cascade_target_fb, sldata->shadow_cascade_target, 0, j, 0);
- GPU_framebuffer_bind(sldata->shadow_cascade_target_fb);
- GPU_framebuffer_clear_depth(sldata->shadow_cascade_target_fb, 1.0f);
- DRW_draw_pass(psl->shadow_pass);
- }
- /* Copy using a small 3x3 box filter */
- {
- /* NOTE: We always do it in the case of CSM because of artifacts in the farthest cascade. */
- copy_v4_fl(srd->filter_size, srd->stored_texel_size);
- srd->base_id = 0;
- DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd);
-
- GPU_framebuffer_bind(sldata->shadow_cascade_copy_fb);
- DRW_draw_pass(psl->shadow_cascade_copy_pass);
- }
- /* Push it to shadowmap array and blur more */
- {
- int max_pass_sample = 0;
-
- for (int j = 0; j < la->cascade_count; j++) {
- /* 0.01f factor to convert to percentage */
- float filter_texture_size = la->soft * 0.01f / evscd->radius[j];
- float filter_pixel_size = ceil(linfo->shadow_cascade_size * filter_texture_size);
- /* Adjust constants if concentric samples change. */
- const float max_filter_size = 7.5f;
- const float magic = 3.2f; /* Arbitrary: less banding */
- const int max_sample = 256;
-
- if (filter_pixel_size > 2.0f) {
- srd->filter_size[j] = srd->stored_texel_size * max_filter_size * magic;
- filter_pixel_size = max_ff(0.0f, filter_pixel_size - 3.0f);
- /* Compute number of concentric samples. Depends directly on filter size. */
- float pix_size_sqr = filter_pixel_size * filter_pixel_size;
- srd->shadow_samples_len[j] = min_ii(
- max_sample, 4 + 8 * (int)filter_pixel_size + 4 * (int)(pix_size_sqr));
- }
- else {
- srd->filter_size[j] = 0.0f;
- srd->shadow_samples_len[j] = 4;
- }
- srd->shadow_samples_len_inv[j] = 1.0f / (float)srd->shadow_samples_len[j];
- max_pass_sample = max_ii(max_pass_sample, srd->shadow_samples_len[j]);
- }
- srd->base_id = evscd->layer_id;
- DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd);
-
- /* XXX(fclem) this create drawcalls outside of cache generation. */
- DRWPass *store_pass = eevee_lights_cascade_store_pass_get(
- psl, sldata, linfo->shadow_method, max_pass_sample);
-
- GPU_framebuffer_bind(sldata->shadow_cascade_store_fb);
- DRW_draw_pass(store_pass);
- }
- }
-
- DRW_stats_group_end();
-
- DRW_view_set_active(view);
+ sldata->common_data.la_num_light = linfo->num_light;
DRW_uniformbuffer_update(sldata->light_ubo, &linfo->light_data);
- DRW_uniformbuffer_update(sldata->shadow_ubo, &linfo->shadow_data); /* Update all data at once */
-
- sldata->common_data.ray_type = saved_ray_type;
- DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
-}
-void EEVEE_lights_free(void)
-{
- DRW_SHADER_FREE_SAFE(e_data.shadow_sh);
- for (int i = 0; i < SHADOW_METHOD_MAX; ++i) {
- DRW_SHADER_FREE_SAFE(e_data.shadow_store_cube_sh[i]);
- DRW_SHADER_FREE_SAFE(e_data.shadow_store_cube_high_sh[i]);
- DRW_SHADER_FREE_SAFE(e_data.shadow_store_cascade_sh[i]);
- DRW_SHADER_FREE_SAFE(e_data.shadow_store_cascade_high_sh[i]);
- DRW_SHADER_FREE_SAFE(e_data.shadow_copy_cube_sh[i]);
- DRW_SHADER_FREE_SAFE(e_data.shadow_copy_cascade_sh[i]);
- }
+ EEVEE_shadows_update(sldata, vedata);
}
diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c
index f52fcf31267..94d61a81fcc 100644
--- a/source/blender/draw/engines/eevee/eevee_lookdev.c
+++ b/source/blender/draw/engines/eevee/eevee_lookdev.c
@@ -151,6 +151,9 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata,
stl->g_data->studiolight_matrix, 'Z', v3d->shading.studiolight_rot_z);
DRW_shgroup_uniform_mat3(*grp, "StudioLightMatrix", stl->g_data->studiolight_matrix);
DRW_shgroup_uniform_float_copy(*grp, "backgroundAlpha", background_alpha);
+ DRW_shgroup_uniform_float(
+ *grp, "studioLightIntensity", &v3d->shading.studiolight_intensity, 1);
+
DRW_shgroup_uniform_vec3(*grp, "color", background_color, 1);
DRW_shgroup_call(*grp, geom, NULL);
if (!pinfo) {
@@ -170,12 +173,14 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata,
/* Do we need to recalc the lightprobes? */
if (g_data->studiolight_index != sl->index ||
g_data->studiolight_rot_z != v3d->shading.studiolight_rot_z ||
+ g_data->studiolight_intensity != v3d->shading.studiolight_intensity ||
g_data->studiolight_cubemap_res != scene->eevee.gi_cubemap_resolution ||
g_data->studiolight_glossy_clamp != scene->eevee.gi_glossy_clamp ||
g_data->studiolight_filter_quality != scene->eevee.gi_filter_quality) {
stl->lookdev_lightcache->flag |= LIGHTCACHE_UPDATE_WORLD;
g_data->studiolight_index = sl->index;
g_data->studiolight_rot_z = v3d->shading.studiolight_rot_z;
+ g_data->studiolight_intensity = v3d->shading.studiolight_intensity;
g_data->studiolight_cubemap_res = scene->eevee.gi_cubemap_resolution;
g_data->studiolight_glossy_clamp = scene->eevee.gi_glossy_clamp;
g_data->studiolight_filter_quality = scene->eevee.gi_filter_quality;
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 738745f3072..f01c6363ccb 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -48,6 +48,9 @@ static struct {
char *frag_shader_lib;
char *vert_shader_str;
char *vert_shadow_shader_str;
+ char *vert_background_shader_str;
+ char *vert_volume_shader_str;
+ char *geom_volume_shader_str;
char *volume_shader_lib;
struct GPUShader *default_prepass_sh;
@@ -63,8 +66,6 @@ static struct {
struct GPUTexture *util_tex;
struct GPUTexture *noise_tex;
- struct GPUUniformBuffer *dummy_sss_profile;
-
uint sss_count;
float alpha_hash_offset;
@@ -273,21 +274,6 @@ struct GPUTexture *EEVEE_materials_get_util_tex(void)
return e_data.util_tex;
}
-static int eevee_material_shadow_option(int shadow_method)
-{
- switch (shadow_method) {
- case SHADOW_ESM:
- return VAR_MAT_ESM;
- case SHADOW_VSM:
- return VAR_MAT_VSM;
- default:
- BLI_assert(!"Incorrect Shadow Method");
- break;
- }
-
- return 0;
-}
-
static char *eevee_get_defines(int options)
{
char *str = NULL;
@@ -322,23 +308,8 @@ static char *eevee_get_defines(int options)
if ((options & VAR_MAT_REFRACT) != 0) {
BLI_dynstr_append(ds, "#define USE_REFRACTION\n");
}
- if ((options & VAR_MAT_SSSALBED) != 0) {
- BLI_dynstr_append(ds, "#define USE_SSS_ALBEDO\n");
- }
- if ((options & VAR_MAT_TRANSLUC) != 0) {
- BLI_dynstr_append(ds, "#define USE_TRANSLUCENCY\n");
- }
- if ((options & VAR_MAT_VSM) != 0) {
- BLI_dynstr_append(ds, "#define SHADOW_VSM\n");
- }
- if ((options & VAR_MAT_ESM) != 0) {
- BLI_dynstr_append(ds, "#define SHADOW_ESM\n");
- }
if ((options & VAR_MAT_LOOKDEV) != 0) {
- /* Auto config shadow method. Avoid more permutation. */
- BLI_assert((options & (VAR_MAT_VSM | VAR_MAT_ESM)) == 0);
BLI_dynstr_append(ds, "#define LOOKDEV\n");
- BLI_dynstr_append(ds, "#define SHADOW_ESM\n");
}
str = BLI_dynstr_get_cstring(ds);
@@ -435,11 +406,6 @@ static void create_default_shader(int options)
MEM_freeN(frag_str);
}
-static void eevee_init_dummys(void)
-{
- e_data.dummy_sss_profile = GPU_material_create_sss_profile_ubo();
-}
-
static void eevee_init_noise_texture(void)
{
e_data.noise_tex = DRW_texture_create_2d(64, 64, GPU_RGBA16F, 0, (float *)blue_noise);
@@ -484,7 +450,7 @@ static void eevee_init_util_texture(void)
texels_layer += 64 * 64;
/* Copy Refraction GGX LUT in layer 5 - 21 */
- for (int j = 0; j < 16; ++j) {
+ for (int j = 0; j < 16; j++) {
for (int i = 0; i < 64 * 64; i++) {
texels_layer[i][0] = btdf_split_sum_ggx[j * 2][i];
texels_layer[i][1] = 0.0; /* UNUSED */
@@ -602,6 +568,15 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
e_data.vert_shadow_shader_str = BLI_string_joinN(
datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_shadow_vert_glsl);
+ e_data.vert_background_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_background_vert_glsl);
+
+ e_data.vert_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_volumetric_vert_glsl);
+
+ e_data.geom_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_volumetric_geom_glsl);
+
e_data.default_background = DRW_shader_create_with_lib(datatoc_background_vert_glsl,
NULL,
datatoc_default_world_frag_glsl,
@@ -631,7 +606,6 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
eevee_init_util_texture();
eevee_init_noise_texture();
- eevee_init_dummys();
}
if (!DRW_state_is_image_render() && ((stl->effects->enabled_effects & EFFECT_TAA) == 0)) {
@@ -675,7 +649,7 @@ struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, Wor
wo,
engine,
options,
- datatoc_background_vert_glsl,
+ e_data.vert_background_shader_str,
NULL,
e_data.frag_shader_lib,
SHADER_DEFINES "#define PROBE_CAPTURE\n",
@@ -695,7 +669,7 @@ struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, Wor
wo,
engine,
options,
- datatoc_background_vert_glsl,
+ e_data.vert_background_shader_str,
NULL,
e_data.frag_shader_lib,
SHADER_DEFINES "#define WORLD_BACKGROUND\n",
@@ -718,8 +692,8 @@ struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World *
wo,
engine,
options,
- datatoc_volumetric_vert_glsl,
- datatoc_volumetric_geom_glsl,
+ e_data.vert_volume_shader_str,
+ e_data.geom_volume_shader_str,
e_data.volume_shader_lib,
defines,
true);
@@ -731,22 +705,15 @@ struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World *
struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene,
Material *ma,
- EEVEE_Data *vedata,
+ EEVEE_Data *UNUSED(vedata),
bool use_blend,
- bool use_refract,
- bool use_translucency,
- int shadow_method)
+ bool use_refract)
{
- EEVEE_EffectsInfo *effects = vedata->stl->effects;
const void *engine = &DRW_engine_viewport_eevee_type;
int options = VAR_MAT_MESH;
SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND);
SET_FLAG_FROM_TEST(options, use_refract, VAR_MAT_REFRACT);
- SET_FLAG_FROM_TEST(options, effects->sss_separate_albedo, VAR_MAT_SSSALBED);
- SET_FLAG_FROM_TEST(options, use_translucency, VAR_MAT_TRANSLUC);
-
- options |= eevee_material_shadow_option(shadow_method);
GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true);
if (mat) {
@@ -786,8 +753,8 @@ struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material
ma,
engine,
options,
- datatoc_volumetric_vert_glsl,
- datatoc_volumetric_geom_glsl,
+ e_data.vert_volume_shader_str,
+ e_data.geom_volume_shader_str,
e_data.volume_shader_lib,
defines,
true);
@@ -835,13 +802,11 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene,
return mat;
}
-struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma, int shadow_method)
+struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma)
{
const void *engine = &DRW_engine_viewport_eevee_type;
int options = VAR_MAT_MESH | VAR_MAT_HAIR;
- options |= eevee_material_shadow_option(shadow_method);
-
GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true);
if (mat) {
return mat;
@@ -872,8 +837,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create(EEVEE_ViewLaye
DRWPass *pass,
bool is_hair,
bool use_blend,
- bool use_ssr,
- int shadow_method)
+ bool use_ssr)
{
static int ssr_id;
ssr_id = (use_ssr) ? 1 : -1;
@@ -882,8 +846,6 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create(EEVEE_ViewLaye
SET_FLAG_FROM_TEST(options, is_hair, VAR_MAT_HAIR);
SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND);
- options |= eevee_material_shadow_option(shadow_method);
-
if (e_data.default_lit[options] == NULL) {
create_default_shader(options);
}
@@ -903,8 +865,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get(EEVEE_ViewLayerDa
ParticleSystem *psys,
ModifierData *md,
bool is_hair,
- bool use_ssr,
- int shadow_method)
+ bool use_ssr)
{
static int ssr_id;
ssr_id = (use_ssr) ? 1 : -1;
@@ -916,8 +877,6 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get(EEVEE_ViewLayerDa
SET_FLAG_FROM_TEST(options, is_hair, VAR_MAT_HAIR);
- options |= eevee_material_shadow_option(shadow_method);
-
if (e_data.default_lit[options] == NULL) {
create_default_shader(options);
}
@@ -1164,7 +1123,6 @@ static void material_opaque(Material *ma,
Scene *scene = draw_ctx->scene;
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
- EEVEE_LightsInfo *linfo = sldata->lights;
bool use_diffuse, use_glossy, use_refract;
float *color_p = &ma->r;
@@ -1186,11 +1144,8 @@ static void material_opaque(Material *ma,
*shgrp_depth_clip = emsg->depth_clip_grp;
/* This will have been created already, just perform a lookup. */
- *gpumat =
- (use_gpumat) ?
- EEVEE_material_mesh_get(
- scene, ma, vedata, false, use_ssrefract, use_translucency, linfo->shadow_method) :
- NULL;
+ *gpumat = (use_gpumat) ? EEVEE_material_mesh_get(scene, ma, vedata, false, use_ssrefract) :
+ NULL;
*gpumat_depth = (use_gpumat) ? EEVEE_material_mesh_depth_get(
scene, ma, (ma->blend_method == MA_BM_HASHED), false) :
NULL;
@@ -1203,8 +1158,7 @@ static void material_opaque(Material *ma,
static float half = 0.5f;
/* Shading */
- *gpumat = EEVEE_material_mesh_get(
- scene, ma, vedata, false, use_ssrefract, use_translucency, linfo->shadow_method);
+ *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, false, use_ssrefract);
eGPUMaterialStatus status_mat_surface = GPU_material_status(*gpumat);
@@ -1311,15 +1265,15 @@ static void material_opaque(Material *ma,
*gpumat, stl->effects->sss_sample_count, &sss_tex_profile);
if (sss_profile) {
- if (use_translucency) {
- DRW_shgroup_uniform_block(*shgrp, "sssProfile", sss_profile);
- DRW_shgroup_uniform_texture(*shgrp, "sssTexProfile", sss_tex_profile);
- }
-
/* Limit of 8 bit stencil buffer. ID 255 is refraction. */
if (e_data.sss_count < 254) {
- DRW_shgroup_stencil_mask(*shgrp, e_data.sss_count + 1);
- EEVEE_subsurface_add_pass(sldata, vedata, e_data.sss_count + 1, sss_profile);
+ int sss_id = e_data.sss_count + 1;
+ DRW_shgroup_stencil_mask(*shgrp, sss_id);
+ EEVEE_subsurface_add_pass(sldata, vedata, sss_id, sss_profile);
+ if (use_translucency) {
+ EEVEE_subsurface_translucency_add_pass(
+ sldata, vedata, sss_id, sss_profile, sss_tex_profile);
+ }
e_data.sss_count++;
}
else {
@@ -1327,19 +1281,6 @@ static void material_opaque(Material *ma,
printf("Error: Too many different Subsurface shader in the scene.\n");
}
}
- else {
- if (use_translucency) {
- /* NOTE: This is a nasty workaround, because the sss profile might not have been
- * generated but the UBO is still declared in this case even if not used.
- * But rendering without a bound UBO might result in crashes on certain platform. */
- DRW_shgroup_uniform_block(*shgrp, "sssProfile", e_data.dummy_sss_profile);
- }
- }
- }
- else {
- if (use_translucency) {
- DRW_shgroup_uniform_block(*shgrp, "sssProfile", e_data.dummy_sss_profile);
- }
}
break;
}
@@ -1360,8 +1301,7 @@ static void material_opaque(Material *ma,
/* Fallback to default shader */
if (*shgrp == NULL) {
bool use_ssr = ((effects->enabled_effects & EFFECT_SSR) != 0);
- *shgrp = EEVEE_default_shading_group_get(
- sldata, vedata, NULL, NULL, NULL, false, use_ssr, linfo->shadow_method);
+ *shgrp = EEVEE_default_shading_group_get(sldata, vedata, NULL, NULL, NULL, false, use_ssr);
DRW_shgroup_uniform_vec3(*shgrp, "basecol", color_p, 1);
DRW_shgroup_uniform_float(*shgrp, "metallic", metal_p, 1);
DRW_shgroup_uniform_float(*shgrp, "specular", spec_p, 1);
@@ -1401,7 +1341,6 @@ static void material_transparent(Material *ma,
Scene *scene = draw_ctx->scene;
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
- EEVEE_LightsInfo *linfo = sldata->lights;
const bool do_cull = (ma->blend_flag & MA_BL_CULL_BACKFACE) != 0;
const bool use_ssrefract = (((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) &&
@@ -1411,14 +1350,31 @@ static void material_transparent(Material *ma,
const float *spec_p = &ma->spec;
const float *rough_p = &ma->roughness;
+ const bool use_prepass = ((ma->blend_flag & MA_BL_HIDE_BACKFACE) != 0);
+
+ DRWState cur_state;
+ DRWState all_state = (DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_CULL_BACK |
+ DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_DEPTH_EQUAL |
+ DRW_STATE_BLEND_CUSTOM);
+
+ /* Depth prepass */
+ if (use_prepass) {
+ *shgrp_depth = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->transparent_pass);
+
+ cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0;
+
+ DRW_shgroup_state_disable(*shgrp_depth, all_state);
+ DRW_shgroup_state_enable(*shgrp_depth, cur_state);
+ }
+
if (ma->use_nodes && ma->nodetree) {
static float error_col[3] = {1.0f, 0.0f, 1.0f};
static float compile_col[3] = {0.5f, 0.5f, 0.5f};
static float half = 0.5f;
/* Shading */
- *gpumat = EEVEE_material_mesh_get(
- scene, ma, vedata, true, use_ssrefract, false, linfo->shadow_method);
+ *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, true, use_ssrefract);
switch (GPU_material_status(*gpumat)) {
case GPU_MAT_SUCCESS: {
@@ -1461,37 +1417,20 @@ static void material_transparent(Material *ma,
/* Fallback to default shader */
if (*shgrp == NULL) {
*shgrp = EEVEE_default_shading_group_create(
- sldata, vedata, psl->transparent_pass, false, true, false, linfo->shadow_method);
+ sldata, vedata, psl->transparent_pass, false, true, false);
DRW_shgroup_uniform_vec3(*shgrp, "basecol", color_p, 1);
DRW_shgroup_uniform_float(*shgrp, "metallic", metal_p, 1);
DRW_shgroup_uniform_float(*shgrp, "specular", spec_p, 1);
DRW_shgroup_uniform_float(*shgrp, "roughness", rough_p, 1);
}
- const bool use_prepass = ((ma->blend_flag & MA_BL_HIDE_BACKFACE) != 0);
-
- DRWState all_state = (DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_CULL_BACK |
- DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_DEPTH_EQUAL |
- DRW_STATE_BLEND_CUSTOM);
-
- DRWState cur_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM;
+ cur_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM;
cur_state |= (use_prepass) ? DRW_STATE_DEPTH_EQUAL : DRW_STATE_DEPTH_LESS_EQUAL;
cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0;
/* Disable other blend modes and use the one we want. */
DRW_shgroup_state_disable(*shgrp, all_state);
DRW_shgroup_state_enable(*shgrp, cur_state);
-
- /* Depth prepass */
- if (use_prepass) {
- *shgrp_depth = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->transparent_pass);
-
- cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0;
-
- DRW_shgroup_state_disable(*shgrp_depth, all_state);
- DRW_shgroup_state_enable(*shgrp_depth, cur_state);
- }
}
/* Return correct material or &defmaterial if slot is empty. */
@@ -1515,7 +1454,8 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
Scene *scene = draw_ctx->scene;
GHash *material_hash = stl->g_data->material_hash;
- bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+ bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
/* First get materials for this mesh. */
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
@@ -1531,7 +1471,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
struct GPUMaterial **gpumat_depth_array = BLI_array_alloca(gpumat_array, materials_len);
struct Material **ma_array = BLI_array_alloca(ma_array, materials_len);
- for (int i = 0; i < materials_len; ++i) {
+ for (int i = 0; i < materials_len; i++) {
ma_array[i] = eevee_object_material_get(ob, i);
gpumat_array[i] = NULL;
gpumat_depth_array[i] = NULL;
@@ -1599,7 +1539,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
/* TODO(fclem): Support shadows in sculpt mode. */
}
else if (mat_geom) {
- for (int i = 0; i < materials_len; ++i) {
+ for (int i = 0; i < materials_len; i++) {
if (mat_geom[i] == NULL) {
continue;
}
@@ -1625,7 +1565,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
ADD_SHGROUP_CALL_SAFE(shgrp_depth_clip_array[i], ob, mat_geom[i], oedata);
char *name = auto_layer_names;
- for (int j = 0; j < auto_layer_count; ++j) {
+ for (int j = 0; j < auto_layer_count; j++) {
/* TODO don't add these uniform when not needed (default pass shaders). */
/* FIXME: This is broken, as it overrides any autolayers srgb bool of the previous mesh
* that shares the same material. */
@@ -1650,18 +1590,18 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
struct GPUMaterial *gpumat;
switch (ma_array[i]->blend_shadow) {
case MA_BS_SOLID:
- EEVEE_lights_cache_shcaster_add(sldata, stl, mat_geom[i], ob);
+ EEVEE_shadows_caster_add(sldata, stl, mat_geom[i], ob);
*cast_shadow = true;
break;
case MA_BS_CLIP:
gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], false, true);
- EEVEE_lights_cache_shcaster_material_add(
+ EEVEE_shadows_caster_material_add(
sldata, psl, gpumat, mat_geom[i], ob, &ma_array[i]->alpha_threshold);
*cast_shadow = true;
break;
case MA_BS_HASHED:
gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], true, true);
- EEVEE_lights_cache_shcaster_material_add(sldata, psl, gpumat, mat_geom[i], ob, NULL);
+ EEVEE_shadows_caster_material_add(sldata, psl, gpumat, mat_geom[i], ob, NULL);
*cast_shadow = true;
break;
case MA_BS_NONE:
@@ -1728,8 +1668,7 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata,
static float half = 0.5f;
static float error_col[3] = {1.0f, 0.0f, 1.0f};
static float compile_col[3] = {0.5f, 0.5f, 0.5f};
- struct GPUMaterial *gpumat = EEVEE_material_hair_get(
- scene, ma, sldata->lights->shadow_method);
+ struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma);
switch (GPU_material_status(gpumat)) {
case GPU_MAT_SUCCESS: {
@@ -1774,8 +1713,7 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata,
/* Fallback to default shader */
if (shgrp == NULL) {
- shgrp = EEVEE_default_shading_group_get(
- sldata, vedata, ob, psys, md, true, use_ssr, sldata->lights->shadow_method);
+ shgrp = EEVEE_default_shading_group_get(sldata, vedata, ob, psys, md, true, use_ssr);
DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1);
DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1);
DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1);
@@ -1804,12 +1742,15 @@ void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
void EEVEE_materials_free(void)
{
- for (int i = 0; i < VAR_MAT_MAX; ++i) {
+ for (int i = 0; i < VAR_MAT_MAX; i++) {
DRW_SHADER_FREE_SAFE(e_data.default_lit[i]);
}
MEM_SAFE_FREE(e_data.frag_shader_lib);
MEM_SAFE_FREE(e_data.vert_shader_str);
MEM_SAFE_FREE(e_data.vert_shadow_shader_str);
+ MEM_SAFE_FREE(e_data.vert_background_shader_str);
+ MEM_SAFE_FREE(e_data.vert_volume_shader_str);
+ MEM_SAFE_FREE(e_data.geom_volume_shader_str);
MEM_SAFE_FREE(e_data.volume_shader_lib);
DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_sh);
DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_clip_sh);
@@ -1819,14 +1760,16 @@ void EEVEE_materials_free(void)
DRW_SHADER_FREE_SAFE(e_data.update_noise_sh);
DRW_TEXTURE_FREE_SAFE(e_data.util_tex);
DRW_TEXTURE_FREE_SAFE(e_data.noise_tex);
- DRW_UBO_FREE_SAFE(e_data.dummy_sss_profile);
}
-void EEVEE_draw_default_passes(EEVEE_PassList *psl)
+void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_PassList *psl)
{
- for (int i = 0; i < VAR_MAT_MAX; ++i) {
+ for (int i = 0; i < VAR_MAT_MAX; i++) {
if (psl->default_pass[i]) {
DRW_draw_pass(psl->default_pass[i]);
}
}
+
+ DRW_draw_pass(psl->material_pass);
+ DRW_draw_pass(psl->material_pass_cull);
}
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 3cdafee95a2..f4f40d40de6 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -23,9 +23,12 @@
#ifndef __EEVEE_PRIVATE_H__
#define __EEVEE_PRIVATE_H__
+#include "DRW_render.h"
+
+#include "BLI_bitmap.h"
+
#include "DNA_lightprobe_types.h"
-struct EEVEE_BoundSphere;
struct EEVEE_ShadowCasterBuffer;
struct GPUFrameBuffer;
struct Object;
@@ -39,11 +42,13 @@ extern struct DrawEngineType draw_engine_eevee_type;
#define MAX_PLANAR 16 /* TODO : find size by dividing UBO max size by grid data size */
#define MAX_LIGHT 128 /* TODO : find size by dividing UBO max size by light data size */
#define MAX_CASCADE_NUM 4
-#define MAX_SHADOW 256 /* TODO : Make this depends on GL_MAX_ARRAY_TEXTURE_LAYERS */
+#define MAX_SHADOW 128 /* TODO : Make this depends on GL_MAX_ARRAY_TEXTURE_LAYERS */
#define MAX_SHADOW_CASCADE 8
#define MAX_SHADOW_CUBE (MAX_SHADOW - MAX_CASCADE_NUM * MAX_SHADOW_CASCADE)
#define MAX_BLOOM_STEP 16
+// #define DEBUG_SHADOW_DISTRIBUTION
+
/* Only define one of these. */
// #define IRRADIANCE_SH_L2
// #define IRRADIANCE_CUBEMAP
@@ -118,16 +123,19 @@ extern struct DrawEngineType draw_engine_eevee_type;
} \
((void)0)
-#define OVERLAY_ENABLED(v3d) ((v3d) && (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0)
-#define LOOK_DEV_MODE_ENABLED(v3d) ((v3d) && (v3d->shading.type == OB_MATERIAL))
+#define MATERIAL_PREVIEW_MODE_ENABLED(v3d) ((v3d) && (v3d->shading.type == OB_MATERIAL))
#define LOOK_DEV_OVERLAY_ENABLED(v3d) \
- (LOOK_DEV_MODE_ENABLED(v3d) && OVERLAY_ENABLED(v3d) && \
+ ((v3d) && (v3d->shading.type == OB_MATERIAL) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && \
(v3d->overlay.flag & V3D_OVERLAY_LOOK_DEV))
#define USE_SCENE_LIGHT(v3d) \
- ((!v3d) || (!LOOK_DEV_MODE_ENABLED(v3d)) || \
- ((LOOK_DEV_MODE_ENABLED(v3d) && (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS))))
+ ((!v3d) || \
+ ((v3d->shading.type == OB_MATERIAL) && (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS)) || \
+ ((v3d->shading.type == OB_RENDER) && (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS_RENDER)))
#define LOOK_DEV_STUDIO_LIGHT_ENABLED(v3d) \
- (LOOK_DEV_MODE_ENABLED(v3d) && !(v3d->shading.flag & V3D_SHADING_SCENE_WORLD))
+ ((v3d) && (((v3d->shading.type == OB_MATERIAL) && \
+ ((v3d->shading.flag & V3D_SHADING_SCENE_WORLD) == 0)) || \
+ ((v3d->shading.type == OB_RENDER) && \
+ ((v3d->shading.flag & V3D_SHADING_SCENE_WORLD_RENDER) == 0))))
#define OCTAHEDRAL_SIZE_FROM_CUBESIZE(cube_size) \
((int)ceilf(sqrtf((cube_size * cube_size) * 6.0f)))
@@ -147,14 +155,12 @@ enum {
VAR_MAT_PROBE = (1 << 1),
VAR_MAT_HAIR = (1 << 2),
VAR_MAT_BLEND = (1 << 3),
- VAR_MAT_VSM = (1 << 4),
- VAR_MAT_ESM = (1 << 5),
- VAR_MAT_VOLUME = (1 << 6),
- VAR_MAT_LOOKDEV = (1 << 7),
+ VAR_MAT_VOLUME = (1 << 4),
+ VAR_MAT_LOOKDEV = (1 << 5),
/* Max number of variation */
/* IMPORTANT : Leave it last and set
* it's value accordingly. */
- VAR_MAT_MAX = (1 << 8),
+ VAR_MAT_MAX = (1 << 6),
/* These are options that are not counted in VAR_MAT_MAX
* because they are not cumulative with the others above. */
VAR_MAT_CLIP = (1 << 9),
@@ -162,8 +168,6 @@ enum {
VAR_MAT_MULT = (1 << 11),
VAR_MAT_SHADOW = (1 << 12),
VAR_MAT_REFRACT = (1 << 13),
- VAR_MAT_TRANSLUC = (1 << 15),
- VAR_MAT_SSSALBED = (1 << 16),
};
/* ************ PROBE UBO ************* */
@@ -187,10 +191,6 @@ typedef struct EEVEE_PlanarReflection {
/* --------------------------------------- */
-typedef struct EEVEE_BoundSphere {
- float center[3], radius;
-} EEVEE_BoundSphere;
-
typedef struct EEVEE_BoundBox {
float center[3], halfdim[3];
} EEVEE_BoundBox;
@@ -198,12 +198,6 @@ typedef struct EEVEE_BoundBox {
typedef struct EEVEE_PassList {
/* Shadows */
struct DRWPass *shadow_pass;
- struct DRWPass *shadow_cube_copy_pass;
- struct DRWPass *shadow_cube_store_pass;
- struct DRWPass *shadow_cube_store_high_pass;
- struct DRWPass *shadow_cascade_copy_pass;
- struct DRWPass *shadow_cascade_store_pass;
- struct DRWPass *shadow_cascade_store_high_pass;
/* Probes */
struct DRWPass *probe_background;
@@ -239,6 +233,7 @@ typedef struct EEVEE_PassList {
struct DRWPass *sss_blur_ps;
struct DRWPass *sss_resolve_ps;
struct DRWPass *sss_accum_ps;
+ struct DRWPass *sss_translucency_ps;
struct DRWPass *color_downsample_ps;
struct DRWPass *color_downsample_cube_ps;
struct DRWPass *velocity_resolve;
@@ -289,6 +284,7 @@ typedef struct EEVEE_FramebufferList {
struct GPUFrameBuffer *sss_blit_fb;
struct GPUFrameBuffer *sss_resolve_fb;
struct GPUFrameBuffer *sss_clear_fb;
+ struct GPUFrameBuffer *sss_translucency_fb;
struct GPUFrameBuffer *sss_accum_fb;
struct GPUFrameBuffer *dof_down_fb;
struct GPUFrameBuffer *dof_scatter_fb;
@@ -365,7 +361,7 @@ typedef struct EEVEE_StorageList {
typedef struct EEVEE_Light {
float position[3], invsqrdist;
float color[3], spec;
- float spotsize, spotblend, radius, shadowid;
+ float spotsize, spotblend, radius, shadow_id;
float rightvec[3], sizex;
float upvec[3], sizey;
float forwardvec[3], light_type;
@@ -375,13 +371,13 @@ typedef struct EEVEE_Light {
#define LAMPTYPE_AREA_ELLIPSE 100.0f
typedef struct EEVEE_Shadow {
- float near, far, bias, exp;
- float shadow_start, data_start, multi_shadow_count, shadow_blur;
+ float near, far, bias, type_data_id;
float contact_dist, contact_bias, contact_spread, contact_thickness;
} EEVEE_Shadow;
typedef struct EEVEE_ShadowCube {
- float position[3], pad;
+ float shadowmat[4][4];
+ float position[3], _pad0[1];
} EEVEE_ShadowCube;
typedef struct EEVEE_ShadowCascade {
@@ -389,42 +385,34 @@ typedef struct EEVEE_ShadowCascade {
float shadowmat[MAX_CASCADE_NUM][4][4];
float split_start[4];
float split_end[4];
+ float shadow_vec[3], tex_id;
} EEVEE_ShadowCascade;
-typedef struct EEVEE_ShadowRender {
- int shadow_samples_len[MAX_CASCADE_NUM];
- float shadow_samples_len_inv[MAX_CASCADE_NUM];
- float filter_size[MAX_CASCADE_NUM];
- int view_count;
- int base_id;
- float cube_texel_size;
- float stored_texel_size;
- float clip_near;
- float clip_far;
- float exponent;
- float pad;
-} EEVEE_ShadowRender;
+typedef struct EEVEE_ShadowCascadeRender {
+ /* World->Light->NDC : used for rendering the shadow map. */
+ float projmat[MAX_CASCADE_NUM][4][4];
+ float viewmat[4][4], viewinv[4][4];
+ float radius[MAX_CASCADE_NUM];
+ float cascade_max_dist;
+ float cascade_exponent;
+ float cascade_fade;
+ int cascade_count;
+} EEVEE_ShadowCascadeRender;
BLI_STATIC_ASSERT_ALIGN(EEVEE_Light, 16)
BLI_STATIC_ASSERT_ALIGN(EEVEE_Shadow, 16)
BLI_STATIC_ASSERT_ALIGN(EEVEE_ShadowCube, 16)
BLI_STATIC_ASSERT_ALIGN(EEVEE_ShadowCascade, 16)
-BLI_STATIC_ASSERT_ALIGN(EEVEE_ShadowRender, 16)
-
-/* This is just a really long bitflag with special function to access it. */
-#define MAX_LIGHTBITS_FIELDS (MAX_LIGHT / 8)
-typedef struct EEVEE_LightBits {
- uchar fields[MAX_LIGHTBITS_FIELDS];
-} EEVEE_LightBits;
-typedef struct EEVEE_ShadowCaster {
- struct EEVEE_LightBits bits;
- struct EEVEE_BoundBox bbox;
-} EEVEE_ShadowCaster;
+BLI_STATIC_ASSERT(sizeof(EEVEE_Shadow) * MAX_SHADOW +
+ sizeof(EEVEE_ShadowCascade) * MAX_SHADOW_CASCADE +
+ sizeof(EEVEE_ShadowCube) * MAX_SHADOW_CUBE <
+ 16384,
+ "Shadow UBO is too big!!!")
typedef struct EEVEE_ShadowCasterBuffer {
- struct EEVEE_ShadowCaster *shadow_casters;
- char *flags;
+ struct EEVEE_BoundBox *bbox;
+ BLI_bitmap *update;
uint alloc_count;
uint count;
} EEVEE_ShadowCasterBuffer;
@@ -434,42 +422,31 @@ typedef struct EEVEE_LightsInfo {
int num_light, cache_num_light;
int num_cube_layer, cache_num_cube_layer;
int num_cascade_layer, cache_num_cascade_layer;
- int gpu_cube_len, gpu_cascade_len, gpu_shadow_len;
- int cpu_cube_len, cpu_cascade_len;
- int update_flag;
- int shadow_cube_size, shadow_cascade_size, shadow_method;
+ int cube_len, cascade_len, shadow_len;
+ int shadow_cube_size, shadow_cascade_size;
bool shadow_high_bitdepth, soft_shadows;
- int shadow_cube_store_size;
- /* List of lights in the scene. */
- /* XXX This is fragile, can get out of sync quickly. */
- struct Object *light_ref[MAX_LIGHT];
- struct Object *shadow_cube_ref[MAX_SHADOW_CUBE];
- struct Object *shadow_cascade_ref[MAX_SHADOW_CASCADE];
/* UBO Storage : data used by UBO */
struct EEVEE_Light light_data[MAX_LIGHT];
- struct EEVEE_ShadowRender shadow_render_data;
struct EEVEE_Shadow shadow_data[MAX_SHADOW];
struct EEVEE_ShadowCube shadow_cube_data[MAX_SHADOW_CUBE];
struct EEVEE_ShadowCascade shadow_cascade_data[MAX_SHADOW_CASCADE];
+ /* Additionnal rendering info for cascade. */
+ struct EEVEE_ShadowCascadeRender shadow_cascade_render[MAX_SHADOW_CASCADE];
+ /* Back index in light_data. */
+ uchar shadow_cube_light_indices[MAX_SHADOW_CUBE];
+ uchar shadow_cascade_light_indices[MAX_SHADOW_CASCADE];
+ /* Update bitmap. */
+ BLI_bitmap sh_cube_update[BLI_BITMAP_SIZE(MAX_SHADOW_CUBE)];
/* Lights tracking */
- int new_shadow_id[MAX_LIGHT]; /* To be able to convert old bitfield to new bitfield */
- struct EEVEE_BoundSphere shadow_bounds[MAX_LIGHT]; /* Tightly packed light bounds */
- /* Pointers only. */
- struct EEVEE_ShadowCasterBuffer *shcaster_frontbuffer;
- struct EEVEE_ShadowCasterBuffer *shcaster_backbuffer;
+ struct BoundSphere shadow_bounds[MAX_LIGHT]; /* Tightly packed light bounds */
+ /* List of bbox and update bitmap. Double buffered. */
+ struct EEVEE_ShadowCasterBuffer *shcaster_frontbuffer, *shcaster_backbuffer;
+ /* AABB of all shadow casters combined. */
+ struct {
+ float min[3], max[3];
+ } shcaster_aabb;
} EEVEE_LightsInfo;
-/* EEVEE_LightsInfo->shadow_casters_flag */
-enum {
- SHADOW_CASTER_PRUNED = (1 << 0),
- SHADOW_CASTER_UPDATED = (1 << 1),
-};
-
-/* EEVEE_LightsInfo->update_flag */
-enum {
- LIGHT_UPDATE_SHADOW_CUBE = (1 << 0),
-};
-
/* ************ PROBE DATA ************* */
typedef struct EEVEE_LightProbeVisTest {
struct Collection *collection; /* Skip test if NULL */
@@ -549,8 +526,8 @@ typedef struct EEVEE_EffectsInfo {
bool swap_double_buffer;
/* SSSS */
int sss_sample_count;
- bool sss_separate_albedo;
- struct GPUTexture *sss_data; /* Textures from pool */
+ struct GPUTexture *sss_irradiance; /* Textures from pool */
+ struct GPUTexture *sss_radius;
struct GPUTexture *sss_albedo;
struct GPUTexture *sss_blur;
struct GPUTexture *sss_stencil;
@@ -708,20 +685,10 @@ typedef struct EEVEE_ViewLayerData {
struct GPUUniformBuffer *light_ubo;
struct GPUUniformBuffer *shadow_ubo;
- struct GPUUniformBuffer *shadow_render_ubo;
struct GPUUniformBuffer *shadow_samples_ubo;
- struct GPUFrameBuffer *shadow_cube_target_fb;
- struct GPUFrameBuffer *shadow_cube_store_fb;
- struct GPUFrameBuffer *shadow_cube_copy_fb;
- struct GPUFrameBuffer *shadow_cascade_target_fb;
- struct GPUFrameBuffer *shadow_cascade_store_fb;
- struct GPUFrameBuffer *shadow_cascade_copy_fb;
-
- struct GPUTexture *shadow_cube_target;
- struct GPUTexture *shadow_cube_blur;
- struct GPUTexture *shadow_cascade_target;
- struct GPUTexture *shadow_cascade_blur;
+ struct GPUFrameBuffer *shadow_fb;
+
struct GPUTexture *shadow_cube_pool;
struct GPUTexture *shadow_cascade_pool;
@@ -743,23 +710,6 @@ typedef struct EEVEE_ViewLayerData {
/* ************ OBJECT DATA ************ */
-typedef struct EEVEE_LightData {
- short light_id, shadow_id;
-} EEVEE_LightData;
-
-typedef struct EEVEE_ShadowCubeData {
- short light_id, shadow_id, cube_id, layer_id;
-} EEVEE_ShadowCubeData;
-
-typedef struct EEVEE_ShadowCascadeData {
- short light_id, shadow_id, cascade_id, layer_id;
- /* World->Light->NDC : used for rendering the shadow map. */
- float viewprojmat[MAX_CASCADE_NUM][4][4]; /* Could be removed. */
- float projmat[MAX_CASCADE_NUM][4][4];
- float viewmat[4][4], viewinv[4][4];
- float radius[MAX_CASCADE_NUM];
-} EEVEE_ShadowCascadeData;
-
/* These are the structs stored inside Objects.
* It works even if the object is in multiple layers
* because we don't get the same "Object *" for each layer. */
@@ -767,13 +717,6 @@ typedef struct EEVEE_LightEngineData {
DrawData dd;
bool need_update;
- /* This needs to be out of the union to avoid undefined behavior. */
- short prev_cube_shadow_id;
- union {
- struct EEVEE_LightData ld;
- struct EEVEE_ShadowCubeData scd;
- struct EEVEE_ShadowCascadeData scad;
- } data;
} EEVEE_LightEngineData;
typedef struct EEVEE_LightProbeEngineData {
@@ -846,6 +789,7 @@ typedef struct EEVEE_PrivateData {
/* LookDev Settings */
int studiolight_index;
float studiolight_rot_z;
+ float studiolight_intensity;
int studiolight_cubemap_res;
float studiolight_glossy_clamp;
float studiolight_filter_quality;
@@ -892,43 +836,67 @@ void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, struct World *wo);
struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, struct World *wo);
struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, struct World *wo);
-struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene,
- Material *ma,
- EEVEE_Data *vedata,
- bool use_blend,
- bool use_refract,
- bool use_translucency,
- int shadow_method);
+struct GPUMaterial *EEVEE_material_mesh_get(
+ struct Scene *scene, Material *ma, EEVEE_Data *vedata, bool use_blend, bool use_refract);
struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material *ma);
struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene,
Material *ma,
bool use_hashed_alpha,
bool is_shadow);
-struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma, int shadow_method);
+struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma);
void EEVEE_materials_free(void);
-void EEVEE_draw_default_passes(EEVEE_PassList *psl);
+void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl);
void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const double offsets[3]);
void EEVEE_update_viewvecs(float invproj[4][4], float winmat[4][4], float (*r_viewvecs)[4]);
/* eevee_lights.c */
-void EEVEE_lights_init(EEVEE_ViewLayerData *sldata);
+void eevee_light_matrix_get(const EEVEE_Light *evli, float r_mat[4][4]);
void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, struct Object *ob);
-void EEVEE_lights_cache_shcaster_add(EEVEE_ViewLayerData *sldata,
- EEVEE_StorageList *stl,
- struct GPUBatch *geom,
- Object *ob);
-void EEVEE_lights_cache_shcaster_material_add(EEVEE_ViewLayerData *sldata,
- EEVEE_PassList *psl,
- struct GPUMaterial *gpumat,
- struct GPUBatch *geom,
- struct Object *ob,
- const float *alpha_threshold);
-void EEVEE_lights_cache_shcaster_object_add(EEVEE_ViewLayerData *sldata, struct Object *ob);
void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
-void EEVEE_lights_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
-void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct DRWView *view);
-void EEVEE_lights_free(void);
+
+/* eevee_shadows.c */
+void eevee_contact_shadow_setup(const Light *la, EEVEE_Shadow *evsh);
+void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata);
+void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_shadows_caster_add(EEVEE_ViewLayerData *sldata,
+ EEVEE_StorageList *stl,
+ struct GPUBatch *geom,
+ Object *ob);
+void EEVEE_shadows_caster_material_add(EEVEE_ViewLayerData *sldata,
+ EEVEE_PassList *psl,
+ struct GPUMaterial *gpumat,
+ struct GPUBatch *geom,
+ struct Object *ob,
+ const float *alpha_threshold);
+void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, struct Object *ob);
+void EEVEE_shadows_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_shadows_cube_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, struct Object *ob);
+bool EEVEE_shadows_cube_setup(EEVEE_LightsInfo *linfo, const EEVEE_Light *evli, int sample_ofs);
+void EEVEE_shadows_cascade_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, struct Object *ob);
+void EEVEE_shadows_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct DRWView *view);
+void EEVEE_shadows_draw_cubemap(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, int cube_index);
+void EEVEE_shadows_draw_cascades(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ DRWView *view,
+ int cascade_index);
+void EEVEE_shadows_free(void);
+
+/* eevee_sampling.c */
+void EEVEE_sample_ball(int sample_ofs, float radius, float rsample[3]);
+void EEVEE_sample_rectangle(int sample_ofs,
+ const float x_axis[3],
+ const float y_axis[3],
+ float size_x,
+ float size_y,
+ float rsample[3]);
+void EEVEE_sample_ellipse(int sample_ofs,
+ const float x_axis[3],
+ const float y_axis[3],
+ float size_x,
+ float size_y,
+ float rsample[3]);
+void EEVEE_random_rotation_m4(int sample_ofs, float scale, float r_mat[4][4]);
/* eevee_shaders.c */
void EEVEE_shaders_lightprobe_shaders_init(void);
@@ -1041,6 +1009,11 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
uint sss_id,
struct GPUUniformBuffer *sss_profile);
+void EEVEE_subsurface_translucency_add_pass(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ uint sss_id,
+ struct GPUUniformBuffer *sss_profile,
+ struct GPUTexture *sss_tex_profile);
void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_subsurface_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c
index f840fa23bd2..75e837f140b 100644
--- a/source/blender/draw/engines/eevee/eevee_render.c
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -133,7 +133,7 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *
/* EEVEE_effects_init needs to go first for TAA */
EEVEE_effects_init(sldata, vedata, ob_camera_eval, false);
EEVEE_materials_init(sldata, stl, fbl);
- EEVEE_lights_init(sldata);
+ EEVEE_shadows_init(sldata);
EEVEE_lightprobes_init(sldata, vedata);
/* INIT CACHE */
@@ -198,7 +198,7 @@ void EEVEE_render_cache(void *vedata,
}
if (cast_shadow) {
- EEVEE_lights_cache_shcaster_object_add(sldata, ob);
+ EEVEE_shadows_caster_register(sldata, ob);
}
}
@@ -369,7 +369,7 @@ static void eevee_render_result_z(RenderLayer *rl,
DRW_view_winmat_get(NULL, winmat, false);
/* Convert ogl depth [0..1] to view Z [near..far] */
- for (int i = 0; i < rp->rectx * rp->recty; ++i) {
+ for (int i = 0; i < rp->rectx * rp->recty; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
}
@@ -478,7 +478,8 @@ static void eevee_render_draw_background(EEVEE_Data *vedata)
GPU_ATTACHMENT_LEAVE,
GPU_ATTACHMENT_TEXTURE(stl->effects->ssr_normal_input),
GPU_ATTACHMENT_TEXTURE(stl->effects->ssr_specrough_input),
- GPU_ATTACHMENT_TEXTURE(stl->effects->sss_data),
+ GPU_ATTACHMENT_TEXTURE(stl->effects->sss_irradiance),
+ GPU_ATTACHMENT_TEXTURE(stl->effects->sss_radius),
GPU_ATTACHMENT_TEXTURE(stl->effects->sss_albedo)});
GPU_framebuffer_bind(fbl->main_fb);
}
@@ -582,8 +583,8 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
EEVEE_lightprobes_refresh_planar(sldata, vedata);
/* Refresh Shadows */
- EEVEE_lights_update(sldata, vedata);
- EEVEE_draw_shadows(sldata, vedata, stl->effects->taa_view);
+ EEVEE_shadows_update(sldata, vedata);
+ EEVEE_shadows_draw(sldata, vedata, stl->effects->taa_view);
/* Set matrices. */
DRW_view_set_active(stl->effects->taa_view);
@@ -605,9 +606,7 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
/* Shading pass */
eevee_render_draw_background(vedata);
GPU_framebuffer_bind(fbl->main_fb);
- EEVEE_draw_default_passes(psl);
- DRW_draw_pass(psl->material_pass);
- DRW_draw_pass(psl->material_pass_cull);
+ EEVEE_materials_draw_opaque(sldata, psl);
EEVEE_subsurface_data_render(sldata, vedata);
/* Effects pre-transparency */
EEVEE_subsurface_compute(sldata, vedata);
diff --git a/source/blender/draw/engines/eevee/eevee_sampling.c b/source/blender/draw/engines/eevee/eevee_sampling.c
new file mode 100644
index 00000000000..5e951928c5a
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_sampling.c
@@ -0,0 +1,129 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup EEVEE
+ */
+
+#include "eevee_private.h"
+
+#include "BLI_rand.h"
+
+/**
+ * Special ball distribution:
+ * Point are distributed in a way that when they are orthogonally
+ * projected into any plane, the resulting distribution is (close to)
+ * a uniform disc distribution.
+ */
+void EEVEE_sample_ball(int sample_ofs, float radius, float rsample[3])
+{
+ double ht_point[3];
+ double ht_offset[3] = {0.0, 0.0, 0.0};
+ uint ht_primes[3] = {2, 3, 7};
+
+ BLI_halton_3d(ht_primes, ht_offset, sample_ofs, ht_point);
+
+ /* Decorelate AA and shadow samples. (see T68594) */
+ ht_point[0] = fmod(ht_point[0] * 1151.0, 1.0);
+ ht_point[1] = fmod(ht_point[1] * 1069.0, 1.0);
+ ht_point[2] = fmod(ht_point[2] * 1151.0, 1.0);
+
+ float omega = ht_point[1] * 2.0f * M_PI;
+
+ rsample[2] = ht_point[0] * 2.0f - 1.0f; /* cos theta */
+
+ float r = sqrtf(fmaxf(0.0f, 1.0f - rsample[2] * rsample[2])); /* sin theta */
+
+ rsample[0] = r * cosf(omega);
+ rsample[1] = r * sinf(omega);
+
+ radius *= sqrt(sqrt(ht_point[2]));
+ mul_v3_fl(rsample, radius);
+}
+
+void EEVEE_sample_rectangle(int sample_ofs,
+ const float x_axis[3],
+ const float y_axis[3],
+ float size_x,
+ float size_y,
+ float rsample[3])
+{
+ double ht_point[2];
+ double ht_offset[2] = {0.0, 0.0};
+ uint ht_primes[2] = {2, 3};
+
+ BLI_halton_2d(ht_primes, ht_offset, sample_ofs, ht_point);
+
+ /* Decorelate AA and shadow samples. (see T68594) */
+ ht_point[0] = fmod(ht_point[0] * 1151.0, 1.0);
+ ht_point[1] = fmod(ht_point[1] * 1069.0, 1.0);
+
+ /* Change ditribution center to be 0,0 */
+ ht_point[0] = (ht_point[0] > 0.5f) ? ht_point[0] - 1.0f : ht_point[0];
+ ht_point[1] = (ht_point[1] > 0.5f) ? ht_point[1] - 1.0f : ht_point[1];
+
+ zero_v3(rsample);
+ madd_v3_v3fl(rsample, x_axis, (ht_point[0] * 2.0f) * size_x);
+ madd_v3_v3fl(rsample, y_axis, (ht_point[1] * 2.0f) * size_y);
+}
+
+void EEVEE_sample_ellipse(int sample_ofs,
+ const float x_axis[3],
+ const float y_axis[3],
+ float size_x,
+ float size_y,
+ float rsample[3])
+{
+ double ht_point[2];
+ double ht_offset[2] = {0.0, 0.0};
+ uint ht_primes[2] = {2, 3};
+
+ BLI_halton_2d(ht_primes, ht_offset, sample_ofs, ht_point);
+
+ /* Decorelate AA and shadow samples. (see T68594) */
+ ht_point[0] = fmod(ht_point[0] * 1151.0, 1.0);
+ ht_point[1] = fmod(ht_point[1] * 1069.0, 1.0);
+
+ /* Uniform disc sampling. */
+ float omega = ht_point[1] * 2.0f * M_PI;
+ float r = sqrtf(ht_point[0]);
+ ht_point[0] = r * cosf(omega) * size_x;
+ ht_point[1] = r * sinf(omega) * size_y;
+
+ zero_v3(rsample);
+ madd_v3_v3fl(rsample, x_axis, ht_point[0]);
+ madd_v3_v3fl(rsample, y_axis, ht_point[1]);
+}
+
+void EEVEE_random_rotation_m4(int sample_ofs, float scale, float r_mat[4][4])
+{
+ double ht_point[3];
+ double ht_offset[3] = {0.0, 0.0, 0.0};
+ uint ht_primes[3] = {2, 3, 5};
+
+ BLI_halton_3d(ht_primes, ht_offset, sample_ofs, ht_point);
+
+ /* Decorelate AA and shadow samples. (see T68594) */
+ ht_point[0] = fmod(ht_point[0] * 1151.0, 1.0);
+ ht_point[1] = fmod(ht_point[1] * 1069.0, 1.0);
+ ht_point[2] = fmod(ht_point[2] * 1151.0, 1.0);
+
+ rotate_m4(r_mat, 'X', ht_point[0] * scale);
+ rotate_m4(r_mat, 'Y', ht_point[1] * scale);
+ rotate_m4(r_mat, 'Z', ht_point[2] * scale);
+}
diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
index 3d1b64422a4..2daf2388d63 100644
--- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
+++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
@@ -338,7 +338,7 @@ void EEVEE_reflection_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
void EEVEE_screen_raytrace_free(void)
{
- for (int i = 0; i < SSR_MAX_SHADER; ++i) {
+ for (int i = 0; i < SSR_MAX_SHADER; i++) {
DRW_SHADER_FREE_SAFE(e_data.ssr_sh[i]);
}
}
diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c
new file mode 100644
index 00000000000..46fc6e07c1c
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_shadows.c
@@ -0,0 +1,412 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup EEVEE
+ */
+
+#include "BLI_sys_types.h" /* bool */
+
+// #include "BLI_dynstr.h"
+// #include "BLI_rand.h"
+
+#include "BKE_object.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "eevee_private.h"
+
+#define SH_CASTER_ALLOC_CHUNK 32
+
+static struct {
+ struct GPUShader *shadow_sh;
+} e_data = {NULL}; /* Engine data */
+
+extern char datatoc_shadow_vert_glsl[];
+extern char datatoc_shadow_frag_glsl[];
+extern char datatoc_common_view_lib_glsl[];
+
+void eevee_contact_shadow_setup(const Light *la, EEVEE_Shadow *evsh)
+{
+ evsh->contact_dist = (la->mode & LA_SHAD_CONTACT) ? la->contact_dist : 0.0f;
+ evsh->contact_bias = 0.05f * la->contact_bias;
+ evsh->contact_thickness = la->contact_thickness;
+}
+
+void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata)
+{
+ const uint shadow_ubo_size = sizeof(EEVEE_Shadow) * MAX_SHADOW +
+ sizeof(EEVEE_ShadowCube) * MAX_SHADOW_CUBE +
+ sizeof(EEVEE_ShadowCascade) * MAX_SHADOW_CASCADE;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+
+ if (!e_data.shadow_sh) {
+ e_data.shadow_sh = DRW_shader_create_with_lib(datatoc_shadow_vert_glsl,
+ NULL,
+ datatoc_shadow_frag_glsl,
+ datatoc_common_view_lib_glsl,
+ NULL);
+ }
+
+ if (!sldata->lights) {
+ sldata->lights = MEM_callocN(sizeof(EEVEE_LightsInfo), "EEVEE_LightsInfo");
+ sldata->light_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_Light) * MAX_LIGHT, NULL);
+ sldata->shadow_ubo = DRW_uniformbuffer_create(shadow_ubo_size, NULL);
+
+ for (int i = 0; i < 2; i++) {
+ sldata->shcasters_buffers[i].bbox = MEM_callocN(
+ sizeof(EEVEE_BoundBox) * SH_CASTER_ALLOC_CHUNK, __func__);
+ sldata->shcasters_buffers[i].update = BLI_BITMAP_NEW(SH_CASTER_ALLOC_CHUNK, __func__);
+ sldata->shcasters_buffers[i].alloc_count = SH_CASTER_ALLOC_CHUNK;
+ sldata->shcasters_buffers[i].count = 0;
+ }
+ sldata->lights->shcaster_frontbuffer = &sldata->shcasters_buffers[0];
+ sldata->lights->shcaster_backbuffer = &sldata->shcasters_buffers[1];
+ }
+
+ /* Flip buffers */
+ SWAP(EEVEE_ShadowCasterBuffer *,
+ sldata->lights->shcaster_frontbuffer,
+ sldata->lights->shcaster_backbuffer);
+
+ int sh_cube_size = scene_eval->eevee.shadow_cube_size;
+ int sh_cascade_size = scene_eval->eevee.shadow_cascade_size;
+ const bool sh_high_bitdepth = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_HIGH_BITDEPTH) != 0;
+ sldata->lights->soft_shadows = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_SOFT) != 0;
+
+ EEVEE_LightsInfo *linfo = sldata->lights;
+ if ((linfo->shadow_cube_size != sh_cube_size) ||
+ (linfo->shadow_high_bitdepth != sh_high_bitdepth)) {
+ BLI_assert((sh_cube_size > 0) && (sh_cube_size <= 4096));
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool);
+ CLAMP(sh_cube_size, 1, 4096);
+ }
+
+ if ((linfo->shadow_cascade_size != sh_cascade_size) ||
+ (linfo->shadow_high_bitdepth != sh_high_bitdepth)) {
+ BLI_assert((sh_cascade_size > 0) && (sh_cascade_size <= 4096));
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool);
+ CLAMP(sh_cascade_size, 1, 4096);
+ }
+
+ linfo->shadow_high_bitdepth = sh_high_bitdepth;
+ linfo->shadow_cube_size = sh_cube_size;
+ linfo->shadow_cascade_size = sh_cascade_size;
+}
+
+void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_LightsInfo *linfo = sldata->lights;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PassList *psl = vedata->psl;
+
+ EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
+ EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
+
+ frontbuffer->count = 0;
+ linfo->num_cube_layer = 0;
+ linfo->num_cascade_layer = 0;
+ linfo->cube_len = linfo->cascade_len = linfo->shadow_len = 0;
+
+ /* Shadow Casters: Reset flags. */
+ BLI_bitmap_set_all(backbuffer->update, true, backbuffer->alloc_count);
+ /* Is this one needed? */
+ BLI_bitmap_set_all(frontbuffer->update, false, frontbuffer->alloc_count);
+
+ INIT_MINMAX(linfo->shcaster_aabb.min, linfo->shcaster_aabb.max);
+
+ {
+ DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_SHADOW_OFFSET;
+ DRW_PASS_CREATE(psl->shadow_pass, state);
+
+ stl->g_data->shadow_shgrp = DRW_shgroup_create(e_data.shadow_sh, psl->shadow_pass);
+ }
+}
+
+/* Add a shadow caster to the shadowpasses */
+void EEVEE_shadows_caster_add(EEVEE_ViewLayerData *UNUSED(sldata),
+ EEVEE_StorageList *stl,
+ struct GPUBatch *geom,
+ Object *ob)
+{
+ DRW_shgroup_call(stl->g_data->shadow_shgrp, geom, ob);
+}
+
+void EEVEE_shadows_caster_material_add(EEVEE_ViewLayerData *sldata,
+ EEVEE_PassList *psl,
+ struct GPUMaterial *gpumat,
+ struct GPUBatch *geom,
+ struct Object *ob,
+ const float *alpha_threshold)
+{
+ /* TODO / PERF : reuse the same shading group for objects with the same material */
+ DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, psl->shadow_pass);
+
+ if (grp == NULL) {
+ return;
+ }
+
+ /* Unfortunately needed for correctness but not 99% of the time not needed.
+ * TODO detect when needed? */
+ DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
+ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
+ DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+
+ if (alpha_threshold != NULL) {
+ DRW_shgroup_uniform_float(grp, "alphaThreshold", alpha_threshold, 1);
+ }
+
+ DRW_shgroup_call(grp, geom, ob);
+}
+
+/* Make that object update shadow casting lights inside its influence bounding box. */
+void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob)
+{
+ EEVEE_LightsInfo *linfo = sldata->lights;
+ EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
+ EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
+ bool update = true;
+ int id = frontbuffer->count;
+
+ /* Make sure shadow_casters is big enough. */
+ if (id + 1 >= frontbuffer->alloc_count) {
+ frontbuffer->alloc_count += SH_CASTER_ALLOC_CHUNK;
+ frontbuffer->bbox = MEM_reallocN(frontbuffer->bbox,
+ sizeof(EEVEE_BoundBox) * frontbuffer->alloc_count);
+ BLI_BITMAP_RESIZE(frontbuffer->update, frontbuffer->alloc_count);
+ }
+
+ if (ob->base_flag & BASE_FROM_DUPLI) {
+ /* Duplis will always refresh the shadowmaps as if they were deleted each frame. */
+ /* TODO(fclem) fix this. */
+ update = true;
+ }
+ else {
+ EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob);
+ int past_id = oedata->shadow_caster_id;
+ oedata->shadow_caster_id = id;
+ /* Update flags in backbuffer. */
+ if (past_id > -1 && past_id < backbuffer->count) {
+ BLI_BITMAP_SET(backbuffer->update, past_id, oedata->need_update);
+ }
+ update = oedata->need_update;
+ oedata->need_update = false;
+ }
+
+ if (update) {
+ BLI_BITMAP_ENABLE(frontbuffer->update, id);
+ }
+
+ /* Update World AABB in frontbuffer. */
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ float min[3], max[3];
+ INIT_MINMAX(min, max);
+ for (int i = 0; i < 8; i++) {
+ float vec[3];
+ copy_v3_v3(vec, bb->vec[i]);
+ mul_m4_v3(ob->obmat, vec);
+ minmax_v3v3_v3(min, max, vec);
+ }
+
+ EEVEE_BoundBox *aabb = &frontbuffer->bbox[id];
+ add_v3_v3v3(aabb->center, min, max);
+ mul_v3_fl(aabb->center, 0.5f);
+ sub_v3_v3v3(aabb->halfdim, aabb->center, max);
+
+ aabb->halfdim[0] = fabsf(aabb->halfdim[0]);
+ aabb->halfdim[1] = fabsf(aabb->halfdim[1]);
+ aabb->halfdim[2] = fabsf(aabb->halfdim[2]);
+
+ minmax_v3v3_v3(linfo->shcaster_aabb.min, linfo->shcaster_aabb.max, min);
+ minmax_v3v3_v3(linfo->shcaster_aabb.min, linfo->shcaster_aabb.max, max);
+
+ frontbuffer->count++;
+}
+
+/* Used for checking if object is inside the shadow volume. */
+static bool sphere_bbox_intersect(const BoundSphere *bs, const EEVEE_BoundBox *bb)
+{
+ /* We are testing using a rougher AABB vs AABB test instead of full AABB vs Sphere. */
+ /* TODO test speed with AABB vs Sphere. */
+ bool x = fabsf(bb->center[0] - bs->center[0]) <= (bb->halfdim[0] + bs->radius);
+ bool y = fabsf(bb->center[1] - bs->center[1]) <= (bb->halfdim[1] + bs->radius);
+ bool z = fabsf(bb->center[2] - bs->center[2]) <= (bb->halfdim[2] + bs->radius);
+
+ return x && y && z;
+}
+
+void EEVEE_shadows_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ EEVEE_LightsInfo *linfo = sldata->lights;
+ EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
+ EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
+
+ eGPUTextureFormat shadow_pool_format = (linfo->shadow_high_bitdepth) ? GPU_DEPTH_COMPONENT24 :
+ GPU_DEPTH_COMPONENT16;
+ /* Setup enough layers. */
+ /* Free textures if number mismatch. */
+ if (linfo->num_cube_layer != linfo->cache_num_cube_layer) {
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool);
+ linfo->cache_num_cube_layer = linfo->num_cube_layer;
+ /* Update all lights. */
+ BLI_bitmap_set_all(&linfo->sh_cube_update[0], true, MAX_LIGHT);
+ }
+
+ if (linfo->num_cascade_layer != linfo->cache_num_cascade_layer) {
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool);
+ linfo->cache_num_cascade_layer = linfo->num_cascade_layer;
+ }
+
+ if (!sldata->shadow_cube_pool) {
+ /* TODO shadowcube array. */
+ int cube_size = linfo->shadow_cube_size + ((true) ? 2 : 0);
+ sldata->shadow_cube_pool = DRW_texture_create_2d_array(cube_size,
+ cube_size,
+ max_ii(1, linfo->num_cube_layer * 6),
+ shadow_pool_format,
+ DRW_TEX_FILTER | DRW_TEX_COMPARE,
+ NULL);
+ }
+
+ if (!sldata->shadow_cascade_pool) {
+ sldata->shadow_cascade_pool = DRW_texture_create_2d_array(linfo->shadow_cascade_size,
+ linfo->shadow_cascade_size,
+ max_ii(1, linfo->num_cascade_layer),
+ shadow_pool_format,
+ DRW_TEX_FILTER | DRW_TEX_COMPARE,
+ NULL);
+ }
+
+ if (sldata->shadow_fb == NULL) {
+ sldata->shadow_fb = GPU_framebuffer_create();
+ }
+
+ /* Gather all light own update bits. to avoid costly intersection check. */
+ for (int j = 0; j < linfo->cube_len; j++) {
+ const EEVEE_Light *evli = linfo->light_data + linfo->shadow_cube_light_indices[j];
+ /* Setup shadow cube in UBO and tag for update if necessary. */
+ if (EEVEE_shadows_cube_setup(linfo, evli, effects->taa_current_sample - 1)) {
+ BLI_BITMAP_ENABLE(&linfo->sh_cube_update[0], j);
+ }
+ }
+
+ /* TODO(fclem) This part can be slow, optimize it. */
+ EEVEE_BoundBox *bbox = backbuffer->bbox;
+ BoundSphere *bsphere = linfo->shadow_bounds;
+ /* Search for deleted shadow casters or if shcaster WAS in shadow radius. */
+ for (int i = 0; i < backbuffer->count; i++) {
+ /* If the shadowcaster has been deleted or updated. */
+ if (BLI_BITMAP_TEST(backbuffer->update, i)) {
+ for (int j = 0; j < linfo->cube_len; j++) {
+ if (!BLI_BITMAP_TEST(&linfo->sh_cube_update[0], j)) {
+ if (sphere_bbox_intersect(&bsphere[j], &bbox[i])) {
+ BLI_BITMAP_ENABLE(&linfo->sh_cube_update[0], j);
+ }
+ }
+ }
+ }
+ }
+ /* Search for updates in current shadow casters. */
+ bbox = frontbuffer->bbox;
+ for (int i = 0; i < frontbuffer->count; i++) {
+ /* If the shadowcaster has been updated. */
+ if (BLI_BITMAP_TEST(frontbuffer->update, i)) {
+ for (int j = 0; j < linfo->cube_len; j++) {
+ if (!BLI_BITMAP_TEST(&linfo->sh_cube_update[0], j)) {
+ if (sphere_bbox_intersect(&bsphere[j], &bbox[i])) {
+ BLI_BITMAP_ENABLE(&linfo->sh_cube_update[0], j);
+ }
+ }
+ }
+ }
+ }
+
+ /* Resize shcasters buffers if too big. */
+ if (frontbuffer->alloc_count - frontbuffer->count > SH_CASTER_ALLOC_CHUNK) {
+ frontbuffer->alloc_count = (frontbuffer->count / SH_CASTER_ALLOC_CHUNK) *
+ SH_CASTER_ALLOC_CHUNK;
+ frontbuffer->alloc_count += (frontbuffer->count % SH_CASTER_ALLOC_CHUNK != 0) ?
+ SH_CASTER_ALLOC_CHUNK :
+ 0;
+ frontbuffer->bbox = MEM_reallocN(frontbuffer->bbox,
+ sizeof(EEVEE_BoundBox) * frontbuffer->alloc_count);
+ BLI_BITMAP_RESIZE(frontbuffer->update, frontbuffer->alloc_count);
+ }
+}
+
+/* this refresh lights shadow buffers */
+void EEVEE_shadows_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWView *view)
+{
+ EEVEE_LightsInfo *linfo = sldata->lights;
+
+ int saved_ray_type = sldata->common_data.ray_type;
+
+ /* Precompute all shadow/view test before rendering and trashing the culling cache. */
+ BLI_bitmap *cube_visible = BLI_BITMAP_NEW_ALLOCA(MAX_SHADOW_CUBE);
+ bool any_visible = false;
+ for (int cube = 0; cube < linfo->cube_len; cube++) {
+ if (DRW_culling_sphere_test(view, linfo->shadow_bounds + cube)) {
+ BLI_BITMAP_ENABLE(cube_visible, cube);
+ any_visible = true;
+ }
+ }
+
+ if (!any_visible && linfo->cascade_len == 0) {
+ sldata->common_data.ray_type = EEVEE_RAY_SHADOW;
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+ }
+
+ DRW_stats_group_start("Cube Shadow Maps");
+ {
+ for (int cube = 0; cube < linfo->cube_len; cube++) {
+ if (BLI_BITMAP_TEST(cube_visible, cube) && BLI_BITMAP_TEST(linfo->sh_cube_update, cube)) {
+ EEVEE_shadows_draw_cubemap(sldata, vedata, cube);
+ }
+ }
+ }
+ DRW_stats_group_end();
+
+ DRW_stats_group_start("Cascaded Shadow Maps");
+ {
+ for (int cascade = 0; cascade < linfo->cascade_len; cascade++) {
+ EEVEE_shadows_draw_cascades(sldata, vedata, view, cascade);
+ }
+ }
+ DRW_stats_group_end();
+
+ DRW_view_set_active(view);
+
+ DRW_uniformbuffer_update(sldata->shadow_ubo, &linfo->shadow_data); /* Update all data at once */
+
+ if (!any_visible && linfo->cascade_len == 0) {
+ sldata->common_data.ray_type = saved_ray_type;
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+ }
+}
+
+void EEVEE_shadows_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.shadow_sh);
+}
diff --git a/source/blender/draw/engines/eevee/eevee_shadows_cascade.c b/source/blender/draw/engines/eevee/eevee_shadows_cascade.c
new file mode 100644
index 00000000000..b2dc8103df2
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_shadows_cascade.c
@@ -0,0 +1,439 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup EEVEE
+ */
+
+#include "BLI_rect.h"
+#include "BLI_sys_types.h" /* bool */
+
+#include "BKE_object.h"
+
+#include "eevee_private.h"
+
+#include "BLI_rand.h" /* needs to be after for some reason. */
+
+void EEVEE_shadows_cascade_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, Object *ob)
+{
+ if (linfo->cascade_len >= MAX_SHADOW_CASCADE) {
+ return;
+ }
+
+ const Light *la = (Light *)ob->data;
+ EEVEE_Shadow *sh_data = linfo->shadow_data + linfo->shadow_len;
+ EEVEE_ShadowCascade *csm_data = linfo->shadow_cascade_data + linfo->cascade_len;
+ EEVEE_ShadowCascadeRender *csm_render = linfo->shadow_cascade_render + linfo->cascade_len;
+
+ sh_data->bias = max_ff(la->bias * 0.00002f, 0.0f);
+ eevee_contact_shadow_setup(la, sh_data);
+
+ linfo->shadow_cascade_light_indices[linfo->cascade_len] = linfo->num_light;
+ evli->shadow_id = linfo->shadow_len++;
+ sh_data->type_data_id = linfo->cascade_len++;
+ csm_data->tex_id = linfo->num_cascade_layer;
+ csm_render->cascade_fade = la->cascade_fade;
+ csm_render->cascade_count = la->cascade_count;
+ csm_render->cascade_exponent = la->cascade_exponent;
+ csm_render->cascade_max_dist = la->cascade_max_dist;
+
+ linfo->num_cascade_layer += la->cascade_count;
+}
+
+static void shadow_cascade_random_matrix_set(float mat[4][4], float radius, int sample_ofs)
+{
+ float jitter[3];
+#ifndef DEBUG_SHADOW_DISTRIBUTION
+ EEVEE_sample_ellipse(sample_ofs, mat[0], mat[1], radius, radius, jitter);
+#else
+ for (int i = 0; i <= sample_ofs; i++) {
+ EEVEE_sample_ellipse(i, mat[0], mat[1], radius, radius, jitter);
+ float p[3];
+ add_v3_v3v3(p, jitter, mat[2]);
+ DRW_debug_sphere(p, 0.01f, (float[4]){1.0f, (sample_ofs == i) ? 1.0f : 0.0f, 0.0f, 1.0f});
+ }
+#endif
+ add_v3_v3(mat[2], jitter);
+ orthogonalize_m4(mat, 2);
+}
+
+static double round_to_digits(double value, int digits)
+{
+ double factor = pow(10.0, digits - ceil(log10(fabs(value))));
+ return round(value * factor) / factor;
+}
+
+static void frustum_min_bounding_sphere(const float corners[8][3],
+ float r_center[3],
+ float *r_radius)
+{
+#if 0 /* Simple solution but waste too much space. */
+ float minvec[3], maxvec[3];
+
+ /* compute the bounding box */
+ INIT_MINMAX(minvec, maxvec);
+ for (int i = 0; i < 8; i++) {
+ minmax_v3v3_v3(minvec, maxvec, corners[i]);
+ }
+
+ /* compute the bounding sphere of this box */
+ r_radius = len_v3v3(minvec, maxvec) * 0.5f;
+ add_v3_v3v3(r_center, minvec, maxvec);
+ mul_v3_fl(r_center, 0.5f);
+#else
+ /* Find averaged center. */
+ zero_v3(r_center);
+ for (int i = 0; i < 8; i++) {
+ add_v3_v3(r_center, corners[i]);
+ }
+ mul_v3_fl(r_center, 1.0f / 8.0f);
+
+ /* Search the largest distance from the sphere center. */
+ *r_radius = 0.0f;
+ for (int i = 0; i < 8; i++) {
+ float rad = len_squared_v3v3(corners[i], r_center);
+ if (rad > *r_radius) {
+ *r_radius = rad;
+ }
+ }
+
+ /* TODO try to reduce the radius further by moving the center.
+ * Remember we need a __stable__ solution! */
+
+ /* Try to reduce float imprecision leading to shimmering. */
+ *r_radius = (float)round_to_digits(sqrtf(*r_radius), 3);
+#endif
+}
+
+BLI_INLINE float lerp(float t, float a, float b)
+{
+ return ((a) + (t) * ((b) - (a)));
+}
+
+static void eevee_shadow_cascade_setup(EEVEE_LightsInfo *linfo,
+ EEVEE_Light *evli,
+ DRWView *view,
+ float view_near,
+ float view_far,
+ int sample_ofs)
+{
+ EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id;
+ EEVEE_ShadowCascade *csm_data = linfo->shadow_cascade_data + (int)shdw_data->type_data_id;
+ EEVEE_ShadowCascadeRender *csm_render = linfo->shadow_cascade_render +
+ (int)shdw_data->type_data_id;
+ int cascade_nbr = csm_render->cascade_count;
+ float cascade_fade = csm_render->cascade_fade;
+ float cascade_max_dist = csm_render->cascade_max_dist;
+ float cascade_exponent = csm_render->cascade_exponent;
+
+ float jitter_ofs[2];
+ double ht_point[2];
+ double ht_offset[2] = {0.0, 0.0};
+ uint ht_primes[2] = {2, 3};
+
+ BLI_halton_2d(ht_primes, ht_offset, sample_ofs, ht_point);
+
+ /* Not really sure why we need 4.0 factor here. */
+ jitter_ofs[0] = (ht_point[0] * 2.0 - 1.0) * 4.0 / linfo->shadow_cascade_size;
+ jitter_ofs[1] = (ht_point[1] * 2.0 - 1.0) * 4.0 / linfo->shadow_cascade_size;
+
+ /* Camera Matrices */
+ float persinv[4][4], vp_projmat[4][4];
+ DRW_view_persmat_get(view, persinv, true);
+ DRW_view_winmat_get(view, vp_projmat, false);
+ bool is_persp = DRW_view_is_persp_get(view);
+
+ /* obmat = Object Space > World Space */
+ /* viewmat = World Space > View Space */
+ float(*viewmat)[4] = csm_render->viewmat;
+ eevee_light_matrix_get(evli, viewmat);
+ /* At this point, viewmat == normalize_m4(obmat) */
+
+ if (linfo->soft_shadows) {
+ shadow_cascade_random_matrix_set(viewmat, evli->radius, sample_ofs);
+ }
+
+ copy_m4_m4(csm_render->viewinv, viewmat);
+ invert_m4(viewmat);
+
+ copy_v3_v3(csm_data->shadow_vec, csm_render->viewinv[2]);
+
+ /* Compute near and far value based on all shadow casters cumulated AABBs. */
+ float sh_near = -1.0e30f, sh_far = 1.0e30f;
+ BoundBox shcaster_bounds;
+ BKE_boundbox_init_from_minmax(
+ &shcaster_bounds, linfo->shcaster_aabb.min, linfo->shcaster_aabb.max);
+#ifdef DEBUG_CSM
+ float dbg_col1[4] = {1.0f, 0.5f, 0.6f, 1.0f};
+ DRW_debug_bbox(&shcaster_bounds, dbg_col1);
+#endif
+ for (int i = 0; i < 8; i++) {
+ mul_m4_v3(viewmat, shcaster_bounds.vec[i]);
+ sh_near = max_ff(sh_near, shcaster_bounds.vec[i][2]);
+ sh_far = min_ff(sh_far, shcaster_bounds.vec[i][2]);
+ }
+#ifdef DEBUG_CSM
+ float dbg_col2[4] = {0.5f, 1.0f, 0.6f, 1.0f};
+ float pts[2][3] = {{0.0, 0.0, sh_near}, {0.0, 0.0, sh_far}};
+ mul_m4_v3(csm_render->viewinv, pts[0]);
+ mul_m4_v3(csm_render->viewinv, pts[1]);
+ DRW_debug_sphere(pts[0], 1.0f, dbg_col1);
+ DRW_debug_sphere(pts[1], 1.0f, dbg_col2);
+#endif
+ /* The rest of the function is assuming inverted Z. */
+ /* Add a little bias to avoid invalid matrices. */
+ sh_far = -(sh_far - 1e-3);
+ sh_near = -sh_near;
+
+ /* The technique consists into splitting
+ * the view frustum into several sub-frustum
+ * that are individually receiving one shadow map */
+
+ float csm_start, csm_end;
+
+ if (is_persp) {
+ csm_start = view_near;
+ csm_end = max_ff(view_far, -cascade_max_dist);
+ /* Avoid artifacts */
+ csm_end = min_ff(view_near, csm_end);
+ }
+ else {
+ csm_start = -view_far;
+ csm_end = view_far;
+ }
+
+ /* init near/far */
+ for (int c = 0; c < MAX_CASCADE_NUM; c++) {
+ csm_data->split_start[c] = csm_end;
+ csm_data->split_end[c] = csm_end;
+ }
+
+ /* Compute split planes */
+ float splits_start_ndc[MAX_CASCADE_NUM];
+ float splits_end_ndc[MAX_CASCADE_NUM];
+
+ {
+ /* Nearest plane */
+ float p[4] = {1.0f, 1.0f, csm_start, 1.0f};
+ /* TODO: we don't need full m4 multiply here */
+ mul_m4_v4(vp_projmat, p);
+ splits_start_ndc[0] = p[2];
+ if (is_persp) {
+ splits_start_ndc[0] /= p[3];
+ }
+ }
+
+ {
+ /* Farthest plane */
+ float p[4] = {1.0f, 1.0f, csm_end, 1.0f};
+ /* TODO: we don't need full m4 multiply here */
+ mul_m4_v4(vp_projmat, p);
+ splits_end_ndc[cascade_nbr - 1] = p[2];
+ if (is_persp) {
+ splits_end_ndc[cascade_nbr - 1] /= p[3];
+ }
+ }
+
+ csm_data->split_start[0] = csm_start;
+ csm_data->split_end[cascade_nbr - 1] = csm_end;
+
+ for (int c = 1; c < cascade_nbr; c++) {
+ /* View Space */
+ float linear_split = lerp(((float)(c) / (float)cascade_nbr), csm_start, csm_end);
+ float exp_split = csm_start * powf(csm_end / csm_start, (float)(c) / (float)cascade_nbr);
+
+ if (is_persp) {
+ csm_data->split_start[c] = lerp(cascade_exponent, linear_split, exp_split);
+ }
+ else {
+ csm_data->split_start[c] = linear_split;
+ }
+ csm_data->split_end[c - 1] = csm_data->split_start[c];
+
+ /* Add some overlap for smooth transition */
+ csm_data->split_start[c] = lerp(cascade_fade,
+ csm_data->split_end[c - 1],
+ (c > 1) ? csm_data->split_end[c - 2] :
+ csm_data->split_start[0]);
+
+ /* NDC Space */
+ {
+ float p[4] = {1.0f, 1.0f, csm_data->split_start[c], 1.0f};
+ /* TODO: we don't need full m4 multiply here */
+ mul_m4_v4(vp_projmat, p);
+ splits_start_ndc[c] = p[2];
+
+ if (is_persp) {
+ splits_start_ndc[c] /= p[3];
+ }
+ }
+
+ {
+ float p[4] = {1.0f, 1.0f, csm_data->split_end[c - 1], 1.0f};
+ /* TODO: we don't need full m4 multiply here */
+ mul_m4_v4(vp_projmat, p);
+ splits_end_ndc[c - 1] = p[2];
+
+ if (is_persp) {
+ splits_end_ndc[c - 1] /= p[3];
+ }
+ }
+ }
+
+ /* Set last cascade split fade distance into the first split_start. */
+ float prev_split = (cascade_nbr > 1) ? csm_data->split_end[cascade_nbr - 2] :
+ csm_data->split_start[0];
+ csm_data->split_start[0] = lerp(cascade_fade, csm_data->split_end[cascade_nbr - 1], prev_split);
+
+ /* For each cascade */
+ for (int c = 0; c < cascade_nbr; c++) {
+ float(*projmat)[4] = csm_render->projmat[c];
+ /* Given 8 frustum corners */
+ float corners[8][3] = {
+ /* Near Cap */
+ {1.0f, -1.0f, splits_start_ndc[c]},
+ {-1.0f, -1.0f, splits_start_ndc[c]},
+ {-1.0f, 1.0f, splits_start_ndc[c]},
+ {1.0f, 1.0f, splits_start_ndc[c]},
+ /* Far Cap */
+ {1.0f, -1.0f, splits_end_ndc[c]},
+ {-1.0f, -1.0f, splits_end_ndc[c]},
+ {-1.0f, 1.0f, splits_end_ndc[c]},
+ {1.0f, 1.0f, splits_end_ndc[c]},
+ };
+
+ /* Transform them into world space */
+ for (int i = 0; i < 8; i++) {
+ mul_project_m4_v3(persinv, corners[i]);
+ }
+
+ float center[3];
+ frustum_min_bounding_sphere(corners, center, &(csm_render->radius[c]));
+
+#ifdef DEBUG_CSM
+ float dbg_col[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ if (c < 3) {
+ dbg_col[c] = 1.0f;
+ }
+ DRW_debug_bbox((BoundBox *)&corners, dbg_col);
+ DRW_debug_sphere(center, csm_render->radius[c], dbg_col);
+#endif
+
+ /* Project into lightspace */
+ mul_m4_v3(viewmat, center);
+
+ /* Snap projection center to nearest texel to cancel shimmering. */
+ float shadow_origin[2], shadow_texco[2];
+ /* Light to texture space. */
+ mul_v2_v2fl(
+ shadow_origin, center, linfo->shadow_cascade_size / (2.0f * csm_render->radius[c]));
+
+ /* Find the nearest texel. */
+ shadow_texco[0] = roundf(shadow_origin[0]);
+ shadow_texco[1] = roundf(shadow_origin[1]);
+
+ /* Compute offset. */
+ sub_v2_v2(shadow_texco, shadow_origin);
+ /* Texture to light space. */
+ mul_v2_fl(shadow_texco, (2.0f * csm_render->radius[c]) / linfo->shadow_cascade_size);
+
+ /* Apply offset. */
+ add_v2_v2(center, shadow_texco);
+
+ /* Expand the projection to cover frustum range */
+ rctf rect_cascade;
+ BLI_rctf_init_pt_radius(&rect_cascade, center, csm_render->radius[c]);
+ orthographic_m4(projmat,
+ rect_cascade.xmin,
+ rect_cascade.xmax,
+ rect_cascade.ymin,
+ rect_cascade.ymax,
+ sh_near,
+ sh_far);
+
+ /* Anti-Aliasing */
+ if (linfo->soft_shadows) {
+ add_v2_v2(projmat[3], jitter_ofs);
+ }
+
+ float viewprojmat[4][4];
+ mul_m4_m4m4(viewprojmat, projmat, viewmat);
+ mul_m4_m4m4(csm_data->shadowmat[c], texcomat, viewprojmat);
+
+#ifdef DEBUG_CSM
+ DRW_debug_m4_as_bbox(viewprojmat, dbg_col, true);
+#endif
+ }
+
+ shdw_data->near = sh_near;
+ shdw_data->far = sh_far;
+}
+
+static void eevee_ensure_cascade_views(EEVEE_ShadowCascadeRender *csm_render,
+ DRWView *view[MAX_CASCADE_NUM])
+{
+ for (int i = 0; i < csm_render->cascade_count; i++) {
+ if (view[i] == NULL) {
+ view[i] = DRW_view_create(csm_render->viewmat, csm_render->projmat[i], NULL, NULL, NULL);
+ }
+ else {
+ DRW_view_update(view[i], csm_render->viewmat, csm_render->projmat[i], NULL, NULL);
+ }
+ }
+}
+
+void EEVEE_shadows_draw_cascades(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ DRWView *view,
+ int cascade_index)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ EEVEE_PrivateData *g_data = stl->g_data;
+ EEVEE_LightsInfo *linfo = sldata->lights;
+
+ EEVEE_Light *evli = linfo->light_data + linfo->shadow_cascade_light_indices[cascade_index];
+ EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id;
+ EEVEE_ShadowCascade *csm_data = linfo->shadow_cascade_data + (int)shdw_data->type_data_id;
+ EEVEE_ShadowCascadeRender *csm_render = linfo->shadow_cascade_render +
+ (int)shdw_data->type_data_id;
+
+ float near = DRW_view_near_distance_get(view);
+ float far = DRW_view_far_distance_get(view);
+
+ eevee_shadow_cascade_setup(linfo, evli, view, near, far, effects->taa_current_sample - 1);
+
+ /* Meh, Reusing the cube views. */
+ BLI_assert(MAX_CASCADE_NUM <= 6);
+ eevee_ensure_cascade_views(csm_render, g_data->cube_views);
+
+ /* Render shadow cascades */
+ /* Render cascade separately: seems to be faster for the general case.
+ * The only time it's more beneficial is when the CPU culling overhead
+ * outweigh the instancing overhead. which is rarely the case. */
+ for (int j = 0; j < csm_render->cascade_count; j++) {
+ DRW_view_set_active(g_data->cube_views[j]);
+ int layer = csm_data->tex_id + j;
+ GPU_framebuffer_texture_layer_attach(
+ sldata->shadow_fb, sldata->shadow_cascade_pool, 0, layer, 0);
+ GPU_framebuffer_bind(sldata->shadow_fb);
+ GPU_framebuffer_clear_depth(sldata->shadow_fb, 1.0f);
+ DRW_draw_pass(psl->shadow_pass);
+ }
+}
diff --git a/source/blender/draw/engines/eevee/eevee_shadows_cube.c b/source/blender/draw/engines/eevee/eevee_shadows_cube.c
new file mode 100644
index 00000000000..a355e7e0792
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_shadows_cube.c
@@ -0,0 +1,225 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup EEVEE
+ */
+
+#include "eevee_private.h"
+
+void EEVEE_shadows_cube_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, Object *ob)
+{
+ if (linfo->cube_len >= MAX_SHADOW_CUBE) {
+ return;
+ }
+
+ const Light *la = (Light *)ob->data;
+ EEVEE_Shadow *sh_data = linfo->shadow_data + linfo->shadow_len;
+
+ /* Always update dupli lights as EEVEE_LightEngineData is not saved.
+ * Same issue with dupli shadow casters. */
+ bool update = (ob->base_flag & BASE_FROM_DUPLI) != 0;
+ if (!update) {
+ EEVEE_LightEngineData *led = EEVEE_light_data_ensure(ob);
+ if (led->need_update) {
+ update = true;
+ led->need_update = false;
+ }
+ }
+
+ if (update) {
+ BLI_BITMAP_ENABLE(&linfo->sh_cube_update[0], linfo->cube_len);
+ }
+
+ sh_data->near = max_ff(la->clipsta, 1e-8f);
+ sh_data->bias = max_ff(la->bias * 0.05f, 0.0f);
+ eevee_contact_shadow_setup(la, sh_data);
+
+ /* Saving light bounds for later. */
+ BoundSphere *cube_bound = linfo->shadow_bounds + linfo->cube_len;
+ copy_v3_v3(cube_bound->center, evli->position);
+ cube_bound->radius = sqrt(1.0f / evli->invsqrdist);
+
+ linfo->shadow_cube_light_indices[linfo->cube_len] = linfo->num_light;
+ evli->shadow_id = linfo->shadow_len++;
+ sh_data->type_data_id = linfo->cube_len++;
+
+ /* Same as linfo->cube_len, no need to save. */
+ linfo->num_cube_layer++;
+}
+
+static void shadow_cube_random_position_set(const EEVEE_Light *evli,
+ int sample_ofs,
+ float ws_sample_pos[3])
+{
+ float jitter[3];
+#ifdef DEBUG_SHADOW_DISTRIBUTION
+ int i = 0;
+start:
+#else
+ int i = sample_ofs;
+#endif
+ switch ((int)evli->light_type) {
+ case LA_AREA:
+ EEVEE_sample_rectangle(i, evli->rightvec, evli->upvec, evli->sizex, evli->sizey, jitter);
+ break;
+ case (int)LAMPTYPE_AREA_ELLIPSE:
+ EEVEE_sample_ellipse(i, evli->rightvec, evli->upvec, evli->sizex, evli->sizey, jitter);
+ break;
+ default:
+ EEVEE_sample_ball(i, evli->radius, jitter);
+ }
+#ifdef DEBUG_SHADOW_DISTRIBUTION
+ float p[3];
+ add_v3_v3v3(p, jitter, ws_sample_pos);
+ DRW_debug_sphere(p, 0.01f, (float[4]){1.0f, (sample_ofs == i) ? 1.0f : 0.0f, 0.0f, 1.0f});
+ if (i++ < sample_ofs) {
+ goto start;
+ }
+#endif
+ add_v3_v3(ws_sample_pos, jitter);
+}
+
+/* Return true if sample has changed and light needs to be updated. */
+bool EEVEE_shadows_cube_setup(EEVEE_LightsInfo *linfo, const EEVEE_Light *evli, int sample_ofs)
+{
+ EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id;
+ EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + (int)shdw_data->type_data_id;
+
+ eevee_light_matrix_get(evli, cube_data->shadowmat);
+
+ shdw_data->far = max_ff(sqrt(1.0f / evli->invsqrdist), 3e-4);
+ shdw_data->near = min_ff(shdw_data->near, shdw_data->far - 1e-4);
+
+ bool update = false;
+
+ if (linfo->soft_shadows) {
+ shadow_cube_random_position_set(evli, sample_ofs, cube_data->shadowmat[3]);
+ /* Update if position changes (avoid infinite update if soft shadows does not move).
+ * Other changes are caught by depsgraph tagging. This one is for update between samples. */
+ update = !compare_v3v3(cube_data->shadowmat[3], cube_data->position, 1e-10f);
+ /**
+ * Anti-Aliasing jitter: Add random rotation.
+ *
+ * The 2.0 factor is because texel angular size is not even across the cube-map,
+ * so we make the rotation range a bit bigger.
+ * This will not blur the shadow even if the spread is too big since we are just
+ * rotating the shadow cube-map.
+ * Note that this may be a rough approximation an may not converge to a perfectly
+ * smooth shadow (because sample distribution is quite non-uniform) but is enough
+ * in practice.
+ **/
+ /* NOTE: this has implication for spotlight rendering optimization
+ * (see EEVEE_shadows_draw_cubemap). */
+ float angular_texel_size = 2.0f * DEG2RADF(90) / (float)linfo->shadow_cube_size;
+ EEVEE_random_rotation_m4(sample_ofs, angular_texel_size, cube_data->shadowmat);
+ }
+
+ copy_v3_v3(cube_data->position, cube_data->shadowmat[3]);
+ invert_m4(cube_data->shadowmat);
+
+ return update;
+}
+
+static void eevee_ensure_cube_views(
+ float near, float far, int cube_res, const float viewmat[4][4], DRWView *view[6])
+{
+ float winmat[4][4];
+ float side = near;
+
+ /* TODO shadowcube array. */
+ if (true) {
+ /* This half texel offset is used to ensure correct filtering between faces. */
+ /* FIXME: This exhibit float precision issue with lower cube_res.
+ * But it seems to be caused by the perspective_m4. */
+ side *= ((float)cube_res + 1.0f) / (float)(cube_res);
+ }
+
+ perspective_m4(winmat, -side, side, -side, side, near, far);
+
+ for (int i = 0; i < 6; i++) {
+ float tmp[4][4];
+ mul_m4_m4m4(tmp, cubefacemat[i], viewmat);
+
+ if (view[i] == NULL) {
+ view[i] = DRW_view_create(tmp, winmat, NULL, NULL, NULL);
+ }
+ else {
+ DRW_view_update(view[i], tmp, winmat, NULL, NULL);
+ }
+ }
+}
+
+/* Does a spot angle fits a single cubeface. */
+static bool spot_angle_fit_single_face(const EEVEE_Light *evli)
+{
+ /* alpha = spot/cone half angle. */
+ /* beta = scaled spot/cone half angle. */
+ float cos_alpha = evli->spotsize;
+ float sin_alpha = sqrtf(max_ff(0.0f, 1.0f - cos_alpha * cos_alpha));
+ float cos_beta = min_ff(cos_alpha / hypotf(cos_alpha, sin_alpha * evli->sizex),
+ cos_alpha / hypotf(cos_alpha, sin_alpha * evli->sizey));
+ /* Don't use 45 degrees because AA jitter can offset the face. */
+ return cos_beta > cosf(DEG2RADF(42.0f));
+}
+
+void EEVEE_shadows_draw_cubemap(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, int cube_index)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PrivateData *g_data = stl->g_data;
+ EEVEE_LightsInfo *linfo = sldata->lights;
+
+ EEVEE_Light *evli = linfo->light_data + linfo->shadow_cube_light_indices[cube_index];
+ EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id;
+ EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + (int)shdw_data->type_data_id;
+
+ eevee_ensure_cube_views(shdw_data->near,
+ shdw_data->far,
+ linfo->shadow_cube_size,
+ cube_data->shadowmat,
+ g_data->cube_views);
+
+ /* Render shadow cube */
+ /* Render 6 faces separately: seems to be faster for the general case.
+ * The only time it's more beneficial is when the CPU culling overhead
+ * outweigh the instancing overhead. which is rarely the case. */
+ for (int j = 0; j < 6; j++) {
+ /* Optimization: Only render the needed faces. */
+ /* Skip all but -Z face. */
+ if (evli->light_type == LA_SPOT && j != 5 && spot_angle_fit_single_face(evli)) {
+ continue;
+ }
+ /* Skip +Z face. */
+ if (evli->light_type != LA_LOCAL && j == 4) {
+ continue;
+ }
+ /* TODO(fclem) some cube sides can be invisible in the main views. Cull them. */
+ // if (frustum_intersect(g_data->cube_views[j], main_view))
+ // continue;
+
+ DRW_view_set_active(g_data->cube_views[j]);
+ int layer = cube_index * 6 + j;
+ GPU_framebuffer_texture_layer_attach(sldata->shadow_fb, sldata->shadow_cube_pool, 0, layer, 0);
+ GPU_framebuffer_bind(sldata->shadow_fb);
+ GPU_framebuffer_clear_depth(sldata->shadow_fb, 1.0f);
+ DRW_draw_pass(psl->shadow_pass);
+ }
+
+ BLI_BITMAP_SET(&linfo->sh_cube_update[0], cube_index, false);
+}
diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c
index 24956239508..8376b8c67b8 100644
--- a/source/blender/draw/engines/eevee/eevee_subsurface.c
+++ b/source/blender/draw/engines/eevee/eevee_subsurface.c
@@ -38,7 +38,13 @@ static struct {
extern char datatoc_common_view_lib_glsl[];
extern char datatoc_common_uniforms_lib_glsl[];
+extern char datatoc_lights_lib_glsl[];
+extern char datatoc_raytrace_lib_glsl[];
+extern char datatoc_octahedron_lib_glsl[];
+extern char datatoc_bsdf_sampling_lib_glsl[];
+extern char datatoc_bsdf_common_lib_glsl[];
extern char datatoc_effect_subsurface_frag_glsl[];
+extern char datatoc_effect_translucency_frag_glsl[];
static void eevee_create_shader_subsurface(void)
{
@@ -46,16 +52,23 @@ static void eevee_create_shader_subsurface(void)
datatoc_common_uniforms_lib_glsl,
datatoc_effect_subsurface_frag_glsl);
+ /* TODO(fclem) remove some of these dependencies. */
+ char *frag_translucent_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_bsdf_sampling_lib_glsl,
+ datatoc_raytrace_lib_glsl,
+ datatoc_octahedron_lib_glsl,
+ datatoc_lights_lib_glsl,
+ datatoc_effect_translucency_frag_glsl);
+
e_data.sss_sh[0] = DRW_shader_create_fullscreen(frag_str, "#define FIRST_PASS\n");
e_data.sss_sh[1] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n");
- e_data.sss_sh[2] = DRW_shader_create_fullscreen(frag_str,
- "#define SECOND_PASS\n"
- "#define USE_SEP_ALBEDO\n");
- e_data.sss_sh[3] = DRW_shader_create_fullscreen(frag_str,
- "#define SECOND_PASS\n"
- "#define USE_SEP_ALBEDO\n"
- "#define RESULT_ACCUM\n");
+ e_data.sss_sh[2] = DRW_shader_create_fullscreen(frag_str, "#define RESULT_ACCUM\n");
+ e_data.sss_sh[3] = DRW_shader_create_fullscreen(frag_translucent_str,
+ "#define EEVEE_TRANSLUCENCY\n" SHADER_DEFINES);
+ MEM_freeN(frag_translucent_str);
MEM_freeN(frag_str);
}
@@ -69,7 +82,6 @@ void EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
effects->sss_sample_count = 1 + scene_eval->eevee.sss_samples * 2;
- effects->sss_separate_albedo = (scene_eval->eevee.flag & SCE_EEVEE_SSS_SEPARATE_ALBEDO) != 0;
common_data->sss_jitter_threshold = scene_eval->eevee.sss_jitter_threshold;
}
@@ -90,9 +102,13 @@ void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
effects->sss_stencil = DRW_texture_pool_query_2d(
fs_size[0], fs_size[1], GPU_DEPTH24_STENCIL8, &draw_engine_eevee_type);
effects->sss_blur = DRW_texture_pool_query_2d(
- fs_size[0], fs_size[1], GPU_RGBA16F, &draw_engine_eevee_type);
- effects->sss_data = DRW_texture_pool_query_2d(
- fs_size[0], fs_size[1], GPU_RGBA16F, &draw_engine_eevee_type);
+ fs_size[0], fs_size[1], GPU_R11F_G11F_B10F, &draw_engine_eevee_type);
+ effects->sss_irradiance = DRW_texture_pool_query_2d(
+ fs_size[0], fs_size[1], GPU_R11F_G11F_B10F, &draw_engine_eevee_type);
+ effects->sss_radius = DRW_texture_pool_query_2d(
+ fs_size[0], fs_size[1], GPU_R16F, &draw_engine_eevee_type);
+ effects->sss_albedo = DRW_texture_pool_query_2d(
+ fs_size[0], fs_size[1], GPU_R11F_G11F_B10F, &draw_engine_eevee_type);
GPUTexture *stencil_tex = effects->sss_stencil;
@@ -115,15 +131,13 @@ void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
{GPU_ATTACHMENT_TEXTURE(stencil_tex), GPU_ATTACHMENT_TEXTURE(txl->color)});
GPU_framebuffer_ensure_config(
- &fbl->sss_clear_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(effects->sss_data)});
+ &fbl->sss_translucency_fb,
+ {GPU_ATTACHMENT_TEXTURE(stencil_tex), GPU_ATTACHMENT_TEXTURE(effects->sss_irradiance)});
- if (effects->sss_separate_albedo) {
- effects->sss_albedo = DRW_texture_pool_query_2d(
- fs_size[0], fs_size[1], GPU_R11F_G11F_B10F, &draw_engine_eevee_type);
- }
- else {
- effects->sss_albedo = NULL;
- }
+ GPU_framebuffer_ensure_config(&fbl->sss_clear_fb,
+ {GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(effects->sss_irradiance),
+ GPU_ATTACHMENT_TEXTURE(effects->sss_radius)});
}
else {
/* Cleanup to release memory */
@@ -132,7 +146,8 @@ void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_clear_fb);
effects->sss_stencil = NULL;
effects->sss_blur = NULL;
- effects->sss_data = NULL;
+ effects->sss_irradiance = NULL;
+ effects->sss_radius = NULL;
}
}
@@ -202,6 +217,7 @@ void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
DRW_PASS_CREATE(psl->sss_blur_ps, state);
DRW_PASS_CREATE(psl->sss_resolve_ps, state | DRW_STATE_BLEND_ADD);
DRW_PASS_CREATE(psl->sss_accum_ps, state | DRW_STATE_BLEND_ADD);
+ DRW_PASS_CREATE(psl->sss_translucency_ps, state | DRW_STATE_BLEND_ADD);
}
void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata,
@@ -219,42 +235,66 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata,
DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[0], psl->sss_blur_ps);
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
- DRW_shgroup_uniform_texture_ref(grp, "sssData", &effects->sss_data);
+ DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_irradiance);
+ DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius);
DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_stencil_mask(grp, sss_id);
DRW_shgroup_call(grp, quad, NULL);
- struct GPUShader *sh = (effects->sss_separate_albedo) ? e_data.sss_sh[2] : e_data.sss_sh[1];
- grp = DRW_shgroup_create(sh, psl->sss_resolve_ps);
+ grp = DRW_shgroup_create(e_data.sss_sh[1], psl->sss_resolve_ps);
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
- DRW_shgroup_uniform_texture_ref(grp, "sssData", &effects->sss_blur);
+ DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_blur);
+ DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo);
+ DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius);
DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_stencil_mask(grp, sss_id);
DRW_shgroup_call(grp, quad, NULL);
- if (effects->sss_separate_albedo) {
- DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo);
- }
-
if (DRW_state_is_image_render()) {
- grp = DRW_shgroup_create(e_data.sss_sh[3], psl->sss_accum_ps);
+ grp = DRW_shgroup_create(e_data.sss_sh[2], psl->sss_accum_ps);
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
- DRW_shgroup_uniform_texture_ref(grp, "sssData", &effects->sss_blur);
+ DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_blur);
+ DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo);
+ DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius);
DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_stencil_mask(grp, sss_id);
DRW_shgroup_call(grp, quad, NULL);
-
- if (effects->sss_separate_albedo) {
- DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo);
- }
}
}
+void EEVEE_subsurface_translucency_add_pass(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ uint sss_id,
+ struct GPUUniformBuffer *sss_profile,
+ GPUTexture *sss_tex_profile)
+{
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
+ GPUTexture **depth_src = GPU_depth_blitting_workaround() ? &effects->sss_stencil : &dtxl->depth;
+
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[3], psl->sss_translucency_ps);
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_texture(grp, "sssTexProfile", sss_tex_profile);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
+ DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius);
+ DRW_shgroup_uniform_texture_ref(grp, "sssShadowCubes", &sldata->shadow_cube_pool);
+ DRW_shgroup_uniform_texture_ref(grp, "sssShadowCascades", &sldata->shadow_cascade_pool);
+ DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
+ DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_stencil_mask(grp, sss_id);
+ DRW_shgroup_call(grp, quad, NULL);
+}
+
void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
{
EEVEE_PassList *psl = vedata->psl;
@@ -273,7 +313,8 @@ void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat
GPU_ATTACHMENT_LEAVE,
GPU_ATTACHMENT_LEAVE,
GPU_ATTACHMENT_LEAVE,
- GPU_ATTACHMENT_TEXTURE(effects->sss_data),
+ GPU_ATTACHMENT_TEXTURE(effects->sss_irradiance),
+ GPU_ATTACHMENT_TEXTURE(effects->sss_radius),
GPU_ATTACHMENT_TEXTURE(effects->sss_albedo)});
GPU_framebuffer_bind(fbl->main_fb);
@@ -287,11 +328,12 @@ void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat
GPU_ATTACHMENT_LEAVE,
GPU_ATTACHMENT_LEAVE,
GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_NONE,
GPU_ATTACHMENT_NONE});
}
}
-void EEVEE_subsurface_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_StorageList *stl = vedata->stl;
@@ -313,6 +355,28 @@ void EEVEE_subsurface_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
GPU_framebuffer_blit(fbl->main_fb, 0, fbl->sss_blur_fb, 0, GPU_STENCIL_BIT);
}
+ if (!DRW_pass_is_empty(psl->sss_translucency_ps)) {
+ /* We sample the shadow-maps using normal sampler. We need to disable Comparison mode.
+ * TODO(fclem) avoid this by using sampler objects.*/
+ GPU_texture_bind(sldata->shadow_cube_pool, 0);
+ GPU_texture_compare_mode(sldata->shadow_cube_pool, false);
+ GPU_texture_unbind(sldata->shadow_cube_pool);
+ GPU_texture_bind(sldata->shadow_cascade_pool, 0);
+ GPU_texture_compare_mode(sldata->shadow_cascade_pool, false);
+ GPU_texture_unbind(sldata->shadow_cascade_pool);
+
+ GPU_framebuffer_bind(fbl->sss_translucency_fb);
+ DRW_draw_pass(psl->sss_translucency_ps);
+
+ /* Reset original state. */
+ GPU_texture_bind(sldata->shadow_cube_pool, 0);
+ GPU_texture_compare_mode(sldata->shadow_cube_pool, true);
+ GPU_texture_unbind(sldata->shadow_cube_pool);
+ GPU_texture_bind(sldata->shadow_cascade_pool, 0);
+ GPU_texture_compare_mode(sldata->shadow_cascade_pool, true);
+ GPU_texture_unbind(sldata->shadow_cascade_pool);
+ }
+
/* 1. horizontal pass */
GPU_framebuffer_bind(fbl->sss_blur_fb);
GPU_framebuffer_clear_color(fbl->sss_blur_fb, clear);
diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
index 96924efa8bc..e5f89aab4d1 100644
--- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
+++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
@@ -63,7 +63,7 @@ static void compute_cdf(float (*func)(float x), float cdf[FILTER_CDF_TABLE_SIZE]
{
cdf[0] = 0.0f;
/* Actual CDF evaluation. */
- for (int u = 0; u < FILTER_CDF_TABLE_SIZE - 1; ++u) {
+ for (int u = 0; u < FILTER_CDF_TABLE_SIZE - 1; u++) {
float x = (float)(u + 1) / (float)(FILTER_CDF_TABLE_SIZE - 1);
cdf[u + 1] = cdf[u] + func(x - 0.5f); /* [-0.5..0.5]. We resize later. */
}
@@ -80,7 +80,7 @@ static void invert_cdf(const float cdf[FILTER_CDF_TABLE_SIZE],
{
for (int u = 0; u < FILTER_CDF_TABLE_SIZE; u++) {
float x = (float)u / (float)(FILTER_CDF_TABLE_SIZE - 1);
- for (int i = 0; i < FILTER_CDF_TABLE_SIZE; ++i) {
+ for (int i = 0; i < FILTER_CDF_TABLE_SIZE; i++) {
if (cdf[i] >= x) {
if (i == FILTER_CDF_TABLE_SIZE - 1) {
invert_cdf[u] = 1.0f;
@@ -123,7 +123,7 @@ static void eevee_create_cdf_table_temporal_sampling(void)
invert_cdf(cdf_table, e_data.inverted_cdf);
/* Scale and offset table. */
- for (int i = 0; i < FILTER_CDF_TABLE_SIZE; ++i) {
+ for (int i = 0; i < FILTER_CDF_TABLE_SIZE; i++) {
e_data.inverted_cdf[i] = (e_data.inverted_cdf[i] - 0.5f) * filter_width;
}
diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c
index 7fb5c25ffc6..fac87bad41a 100644
--- a/source/blender/draw/engines/eevee/eevee_volumes.c
+++ b/source/blender/draw/engines/eevee/eevee_volumes.c
@@ -82,6 +82,8 @@ extern char datatoc_volumetric_integration_frag_glsl[];
extern char datatoc_volumetric_lib_glsl[];
extern char datatoc_common_fullscreen_vert_glsl[];
+#define USE_VOLUME_OPTI (GLEW_ARB_shader_image_load_store && GLEW_ARB_shading_language_420pack)
+
static void eevee_create_shader_volumes(void)
{
e_data.volumetric_common_lib = BLI_string_joinN(datatoc_common_view_lib_glsl,
@@ -123,7 +125,10 @@ static void eevee_create_shader_volumes(void)
datatoc_volumetric_geom_glsl,
datatoc_volumetric_integration_frag_glsl,
e_data.volumetric_common_lib,
- NULL);
+ USE_VOLUME_OPTI ? "#extension GL_ARB_shader_image_load_store: enable\n"
+ "#extension GL_ARB_shading_language_420pack: enable\n"
+ "#define USE_VOLUME_OPTI\n" :
+ NULL);
e_data.volumetric_resolve_sh = DRW_shader_create_with_lib(datatoc_common_fullscreen_vert_glsl,
NULL,
datatoc_volumetric_resolve_frag_glsl,
@@ -250,7 +255,7 @@ void EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
if (DRW_view_is_persp_get(NULL)) {
float sample_distribution = scene_eval->eevee.volumetric_sample_distribution;
- sample_distribution = 4.0f * (1.00001f - sample_distribution);
+ sample_distribution = 4.0f * (max_ff(1.0f - sample_distribution, 1e-2f));
const float clip_start = common_data->view_vecs[0][2];
/* Negate */
@@ -408,7 +413,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
DRWShadingGroup *grp = DRW_shgroup_material_create(mat, vedata->psl->volumetric_objects_ps);
- BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texcoloc, NULL, &texcosize);
+ BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texcoloc, &texcosize);
/* TODO(fclem) remove those "unnecessary" UBOs */
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
@@ -509,7 +514,8 @@ void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_shgroup_uniform_texture_ref(grp, "volumeExtinction", &txl->volume_transmit);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]);
+ DRW_shgroup_call_procedural_triangles(
+ grp, NULL, USE_VOLUME_OPTI ? 1 : common_data->vol_tex_size[2]);
DRW_PASS_CREATE(psl->volumetric_resolve_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM);
grp = DRW_shgroup_create(e_data.volumetric_resolve_sh, psl->volumetric_resolve_ps);
@@ -595,7 +601,7 @@ void EEVEE_volumes_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
effects->volume_transmit = e_data.dummy_transmit;
}
-void EEVEE_volumes_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+void EEVEE_volumes_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_TextureList *txl = vedata->txl;
@@ -605,6 +611,15 @@ void EEVEE_volumes_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda
if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) {
DRW_stats_group_start("Volumetrics");
+ /* We sample the shadow-maps using shadow sampler. We need to enable Comparison mode.
+ * TODO(fclem) avoid this by using sampler objects.*/
+ GPU_texture_bind(sldata->shadow_cube_pool, 0);
+ GPU_texture_compare_mode(sldata->shadow_cube_pool, true);
+ GPU_texture_unbind(sldata->shadow_cube_pool);
+ GPU_texture_bind(sldata->shadow_cascade_pool, 0);
+ GPU_texture_compare_mode(sldata->shadow_cascade_pool, true);
+ GPU_texture_unbind(sldata->shadow_cascade_pool);
+
GPU_framebuffer_bind(fbl->volumetric_fb);
DRW_draw_pass(psl->volumetric_world_ps);
DRW_draw_pass(psl->volumetric_objects_ps);
@@ -612,9 +627,31 @@ void EEVEE_volumes_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda
GPU_framebuffer_bind(fbl->volumetric_scat_fb);
DRW_draw_pass(psl->volumetric_scatter_ps);
- GPU_framebuffer_bind(fbl->volumetric_integ_fb);
+ if (USE_VOLUME_OPTI) {
+ int tex_scatter = GPU_texture_opengl_bindcode(txl->volume_scatter_history);
+ int tex_transmit = GPU_texture_opengl_bindcode(txl->volume_transmit_history);
+ /* TODO(fclem) Encapsulate these GL calls into DRWManager. */
+ glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
+ /* Subtlety here! we need to tell the GL that the texture is layered (GL_TRUE)
+ * in order to bind the full 3D texture and not just a 2D slice. */
+ glBindImageTexture(0, tex_scatter, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R11F_G11F_B10F);
+ glBindImageTexture(1, tex_transmit, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R11F_G11F_B10F);
+
+ GPU_framebuffer_bind(fbl->volumetric_fb);
+ }
+ else {
+ GPU_framebuffer_bind(fbl->volumetric_integ_fb);
+ }
+
DRW_draw_pass(psl->volumetric_integration_ps);
+ if (USE_VOLUME_OPTI) {
+ glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
+
+ glBindImageTexture(0, 0, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R11F_G11F_B10F);
+ glBindImageTexture(1, 0, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R11F_G11F_B10F);
+ }
+
SWAP(struct GPUFrameBuffer *, fbl->volumetric_scat_fb, fbl->volumetric_integ_fb);
SWAP(GPUTexture *, txl->volume_scatter, txl->volume_scatter_history);
SWAP(GPUTexture *, txl->volume_transmit, txl->volume_transmit_history);
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
index 7f795eaac2b..98012aea303 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -56,12 +56,12 @@ struct LightData {
#endif
struct ShadowData {
- vec4 near_far_bias_exp;
- vec4 shadow_data_start_end;
+ vec4 near_far_bias_id;
vec4 contact_shadow_data;
};
struct ShadowCubeData {
+ mat4 shadowmat;
vec4 position;
};
@@ -69,22 +69,20 @@ struct ShadowCascadeData {
mat4 shadowmat[MAX_CASCADE_NUM];
vec4 split_start_distances;
vec4 split_end_distances;
+ vec4 shadow_vec_id;
};
/* convenience aliases */
-#define sh_near near_far_bias_exp.x
-#define sh_far near_far_bias_exp.y
-#define sh_bias near_far_bias_exp.z
-#define sh_exp near_far_bias_exp.w
-#define sh_bleed near_far_bias_exp.w
-#define sh_tex_start shadow_data_start_end.x
-#define sh_data_start shadow_data_start_end.y
-#define sh_multi_nbr shadow_data_start_end.z
-#define sh_blur shadow_data_start_end.w
+#define sh_near near_far_bias_id.x
+#define sh_far near_far_bias_id.y
+#define sh_bias near_far_bias_id.z
+#define sh_data_index near_far_bias_id.w
#define sh_contact_dist contact_shadow_data.x
#define sh_contact_offset contact_shadow_data.y
#define sh_contact_spread contact_shadow_data.z
#define sh_contact_thickness contact_shadow_data.w
+#define sh_shadow_vec shadow_vec_id.xyz
+#define sh_tex_index shadow_vec_id.w
/* ------- Convenience functions --------- */
@@ -777,10 +775,9 @@ struct Closure {
vec3 transmittance;
float holdout;
# ifdef USE_SSS
- vec4 sss_data;
-# ifdef USE_SSS_ALBEDO
+ vec3 sss_irradiance;
vec3 sss_albedo;
-# endif
+ float sss_radius;
# endif
vec4 ssr_data;
vec2 ssr_normal;
@@ -796,13 +793,8 @@ Closure nodetree_exec(void); /* Prototype */
# define CLOSURE_HOLDOUT_FLAG 4
# ifdef USE_SSS
-# ifdef USE_SSS_ALBEDO
-# define CLOSURE_DEFAULT \
- Closure(vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec3(0.0), vec4(0.0), vec2(0.0), 0)
-# else
-# define CLOSURE_DEFAULT \
- Closure(vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec4(0.0), vec2(0.0), 0)
-# endif
+# define CLOSURE_DEFAULT \
+ Closure(vec3(0.0), vec3(0.0), 0.0, vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec2(0.0), 0)
# else
# define CLOSURE_DEFAULT Closure(vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec2(0.0), 0)
# endif
@@ -823,30 +815,22 @@ void closure_load_ssr_data(
}
}
-# ifdef USE_SSS
-void closure_load_sss_data(float radius,
- vec3 sss_radiance,
-# ifdef USE_SSS_ALBEDO
- vec3 sss_albedo,
-# endif
- int sss_id,
- inout Closure cl)
+void closure_load_sss_data(
+ float radius, vec3 sss_irradiance, vec3 sss_albedo, int sss_id, inout Closure cl)
{
+# ifdef USE_SSS
if (sss_id == outputSssId) {
- cl.sss_data = vec4(sss_radiance, radius);
-# ifdef USE_SSS_ALBEDO
+ cl.sss_irradiance = sss_irradiance;
+ cl.sss_radius = radius;
cl.sss_albedo = sss_albedo;
-# endif
cl.flag |= CLOSURE_SSS_FLAG;
}
- else {
- cl.radiance += sss_radiance;
-# ifdef USE_SSS_ALBEDO
- cl.radiance += sss_radiance * sss_albedo;
-# endif
+ else
+# endif
+ {
+ cl.radiance += sss_irradiance * sss_albedo;
}
}
-# endif
Closure closure_mix(Closure cl1, Closure cl2, float fac)
{
@@ -862,13 +846,11 @@ Closure closure_mix(Closure cl1, Closure cl2, float fac)
cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal;
# ifdef USE_SSS
- cl.sss_data = mix(cl1.sss_data, cl2.sss_data, fac);
+ cl.sss_albedo = mix(cl1.sss_albedo, cl2.sss_albedo, fac);
bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG);
- /* It also does not make sense to mix SSS radius or albedo. */
- cl.sss_data.w = (use_cl1_sss) ? cl1.sss_data.w : cl2.sss_data.w;
-# ifdef USE_SSS_ALBEDO
- cl.sss_albedo = (use_cl1_sss) ? cl1.sss_albedo : cl2.sss_albedo;
-# endif
+ /* It also does not make sense to mix SSS radius or irradiance. */
+ cl.sss_radius = (use_cl1_sss) ? cl1.sss_radius : cl2.sss_radius;
+ cl.sss_irradiance = (use_cl1_sss) ? cl1.sss_irradiance : cl2.sss_irradiance;
# endif
return cl;
}
@@ -887,13 +869,11 @@ Closure closure_add(Closure cl1, Closure cl2)
cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal;
# ifdef USE_SSS
- cl.sss_data = cl1.sss_data + cl2.sss_data;
+ cl.sss_albedo = cl1.sss_albedo + cl2.sss_albedo;
bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG);
- /* It also does not make sense to mix SSS radius or albedo. */
- cl.sss_data.w = (use_cl1_sss) ? cl1.sss_data.w : cl2.sss_data.w;
-# ifdef USE_SSS_ALBEDO
- cl.sss_albedo = (use_cl1_sss) ? cl1.sss_albedo : cl2.sss_albedo;
-# endif
+ /* It also does not make sense to mix SSS radius or irradiance. */
+ cl.sss_radius = (use_cl1_sss) ? cl1.sss_radius : cl2.sss_radius;
+ cl.sss_irradiance = (use_cl1_sss) ? cl1.sss_irradiance : cl2.sss_irradiance;
# endif
return cl;
}
@@ -914,10 +894,9 @@ layout(location = 0) out vec4 outRadiance;
layout(location = 1) out vec2 ssrNormals;
layout(location = 2) out vec4 ssrData;
# ifdef USE_SSS
-layout(location = 3) out vec4 sssData;
-# ifdef USE_SSS_ALBEDO
-layout(location = 4) out vec4 sssAlbedo;
-# endif
+layout(location = 3) out vec3 sssIrradiance;
+layout(location = 4) out float sssRadius;
+layout(location = 5) out vec3 sssAlbedo;
# endif
# else /* USE_ALPHA_BLEND */
/* Use dual source blending to be able to make a whole range of effects. */
@@ -953,10 +932,9 @@ void main()
ssrNormals = cl.ssr_normal;
ssrData = cl.ssr_data;
# ifdef USE_SSS
- sssData = cl.sss_data;
-# ifdef USE_SSS_ALBEDO
- sssAlbedo = cl.sss_albedo.rgbb;
-# endif
+ sssIrradiance = cl.sss_irradiance;
+ sssRadius = cl.sss_radius;
+ sssAlbedo = cl.sss_albedo;
# endif
# endif
@@ -964,6 +942,8 @@ void main()
# ifdef USE_SSS
float fac = float(!sssToggle);
+ /* TODO(fclem) we shouldn't need this.
+ * Just disable USE_SSS when USE_REFRACTION is enabled. */
# ifdef USE_REFRACTION
/* SSRefraction pass is done after the SSS pass.
* In order to not loose the diffuse light totally we
@@ -971,11 +951,7 @@ void main()
fac = 1.0;
# endif
-# ifdef USE_SSS_ALBEDO
- outRadiance.rgb += cl.sss_data.rgb * cl.sss_albedo.rgb * fac;
-# else
- outRadiance.rgb += cl.sss_data.rgb * fac;
-# endif
+ outRadiance.rgb += cl.sss_irradiance.rgb * cl.sss_albedo.rgb * fac;
# endif
}
diff --git a/source/blender/draw/engines/eevee/shaders/default_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_frag.glsl
index 1f60661d234..ca06d458f6e 100644
--- a/source/blender/draw/engines/eevee/shaders/default_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/default_frag.glsl
@@ -31,7 +31,7 @@ Closure nodetree_exec(void)
vec3 f0 = mix(dielectric, basecol, metallic);
vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic);
vec3 out_diff, out_spec, ssr_spec;
- eevee_closure_default(N, albedo, f0, f90, 1, roughness, 1.0, out_diff, out_spec, ssr_spec);
+ eevee_closure_default(N, albedo, f0, f90, 1, roughness, 1.0, true, out_diff, out_spec, ssr_spec);
Closure cl = CLOSURE_DEFAULT;
cl.radiance = out_spec + out_diff * albedo;
diff --git a/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl
index 70466479a29..41e103609f3 100644
--- a/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl
@@ -8,6 +8,7 @@ out vec4 FragColor;
uniform mat3 StudioLightMatrix;
uniform sampler2D image;
uniform float studioLightBackground = 1.0;
+uniform float studioLightIntensity = 1.0;
in vec3 viewPosition;
# define M_PI 3.14159265358979323846
@@ -51,6 +52,7 @@ void main()
#ifdef LOOKDEV
vec3 worldvec = background_transform_to_world(viewPosition);
background_color = node_tex_environment_equirectangular(StudioLightMatrix * worldvec, image).rgb;
+ background_color *= studioLightIntensity;
background_color = mix(color, background_color, studioLightBackground);
#else
background_color = color;
diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
index 44f22848c2f..598cc3e5183 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
@@ -147,7 +147,7 @@ void main()
make_orthonormal_basis(N, T, B); /* Generate tangent space */
/* Planar Reflections */
- for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; ++i) {
+ for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) {
PlanarData pd = planars_data[i];
float fade = probe_attenuation_planar(pd, worldPosition, wN, 0.0);
@@ -504,7 +504,7 @@ void main()
/* Find Planar Reflections affecting this pixel */
PlanarData pd;
float planar_index;
- for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; ++i) {
+ for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) {
pd = planars_data[i];
float fade = probe_attenuation_planar(pd, worldPosition, N, 0.0);
diff --git a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
index 4260c601543..1241cf0e387 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
@@ -10,7 +10,8 @@ layout(std140) uniform sssProfile
};
uniform sampler2D depthBuffer;
-uniform sampler2D sssData;
+uniform sampler2D sssIrradiance;
+uniform sampler2D sssRadius;
uniform sampler2D sssAlbedo;
#ifndef UTIL_TEX
@@ -19,9 +20,12 @@ uniform sampler2DArray utilTex;
# define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
#endif /* UTIL_TEX */
-layout(location = 0) out vec4 FragColor;
#ifdef RESULT_ACCUM
+/* Render Passes Accumulation */
+layout(location = 0) out vec4 sssDirect;
layout(location = 1) out vec4 sssColor;
+#else
+layout(location = 0) out vec4 sssRadiance;
#endif
float get_view_z_from_depth(float depth)
@@ -43,7 +47,8 @@ void main(void)
{
vec2 pixel_size = 1.0 / vec2(textureSize(depthBuffer, 0).xy); /* TODO precompute */
vec2 uvs = gl_FragCoord.xy * pixel_size;
- vec4 sss_data = texture(sssData, uvs).rgba;
+ vec3 sss_irradiance = texture(sssIrradiance, uvs).rgb;
+ float sss_radius = texture(sssRadius, uvs).r;
float depth_view = get_view_z_from_depth(texture(depthBuffer, uvs).r);
float rand = texelfetch_noise_tex(gl_FragCoord.xy).r;
@@ -58,44 +63,36 @@ void main(void)
/* Compute kernel bounds in 2D. */
float homcoord = ProjectionMatrix[2][3] * depth_view + ProjectionMatrix[3][3];
- vec2 scale = vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) * sss_data.aa / homcoord;
+ vec2 scale = vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) * sss_radius / homcoord;
vec2 finalStep = scale * radii_max_radius.w;
finalStep *= 0.5; /* samples range -1..1 */
/* Center sample */
- vec3 accum = sss_data.rgb * kernel[0].rgb;
+ vec3 accum = sss_irradiance * kernel[0].rgb;
for (int i = 1; i < sss_samples && i < MAX_SSS_SAMPLES; i++) {
vec2 sample_uv = uvs + kernel[i].a * finalStep *
((abs(kernel[i].a) > sssJitterThreshold) ? dir : dir_rand);
- vec3 color = texture(sssData, sample_uv).rgb;
+ vec3 color = texture(sssIrradiance, sample_uv).rgb;
float sample_depth = texture(depthBuffer, sample_uv).r;
sample_depth = get_view_z_from_depth(sample_depth);
-
/* Depth correction factor. */
float depth_delta = depth_view - sample_depth;
- float s = clamp(1.0 - exp(-(depth_delta * depth_delta) / (2.0 * sss_data.a)), 0.0, 1.0);
-
+ float s = clamp(1.0 - exp(-(depth_delta * depth_delta) / (2.0 * sss_radius)), 0.0, 1.0);
/* Out of view samples. */
if (any(lessThan(sample_uv, vec2(0.0))) || any(greaterThan(sample_uv, vec2(1.0)))) {
s = 1.0;
}
-
- accum += kernel[i].rgb * mix(color, sss_data.rgb, s);
+ /* Mix with first sample in failure case and apply kernel color. */
+ accum += kernel[i].rgb * mix(color, sss_irradiance, s);
}
-#ifdef FIRST_PASS
- FragColor = vec4(accum, sss_data.a);
+#ifdef RESULT_ACCUM
+ sssDirect = vec4(accum, 1.0);
+ sssColor = vec4(texture(sssAlbedo, uvs).rgb, 1.0);
+#elif defined(FIRST_PASS)
+ sssRadiance = vec4(accum, 1.0);
#else /* SECOND_PASS */
-# ifdef USE_SEP_ALBEDO
-# ifdef RESULT_ACCUM
- FragColor = vec4(accum, 1.0);
- sssColor = texture(sssAlbedo, uvs);
-# else
- FragColor = vec4(accum * texture(sssAlbedo, uvs).rgb, 1.0);
-# endif
-# else
- FragColor = vec4(accum, 1.0);
-# endif
+ sssRadiance = vec4(accum * texture(sssAlbedo, uvs).rgb, 1.0);
#endif
}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl
new file mode 100644
index 00000000000..86f53522bc6
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl
@@ -0,0 +1,165 @@
+
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+uniform sampler1D sssTexProfile;
+uniform sampler2D sssRadius;
+
+uniform sampler2DArray sssShadowCubes;
+uniform sampler2DArray sssShadowCascades;
+
+#define MAX_SSS_SAMPLES 65
+#define SSS_LUT_SIZE 64.0
+#define SSS_LUT_SCALE ((SSS_LUT_SIZE - 1.0) / float(SSS_LUT_SIZE))
+#define SSS_LUT_BIAS (0.5 / float(SSS_LUT_SIZE))
+
+layout(std140) uniform sssProfile
+{
+ vec4 kernel[MAX_SSS_SAMPLES];
+ vec4 radii_max_radius;
+ int sss_samples;
+};
+
+vec3 sss_profile(float s)
+{
+ s /= radii_max_radius.w;
+ return texture(sssTexProfile, saturate(s) * SSS_LUT_SCALE + SSS_LUT_BIAS).rgb;
+}
+
+#ifndef UTIL_TEX
+# define UTIL_TEX
+uniform sampler2DArray utilTex;
+# define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
+#endif /* UTIL_TEX */
+
+float light_translucent_power_with_falloff(LightData ld, vec3 N, vec4 l_vector)
+{
+ float power, falloff;
+ /* XXX : Removing Area Power. */
+ /* TODO : put this out of the shader. */
+ if (ld.l_type >= AREA_RECT) {
+ power = (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0);
+ if (ld.l_type == AREA_ELLIPSE) {
+ power *= M_PI * 0.25;
+ }
+ power *= 0.3 * 20.0 *
+ max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */
+ power /= (l_vector.w * l_vector.w);
+ falloff = dot(N, l_vector.xyz / l_vector.w);
+ }
+ else if (ld.l_type == SUN) {
+ power = 1.0 / (1.0 + (ld.l_radius * ld.l_radius * 0.5));
+ power *= ld.l_radius * ld.l_radius * M_PI; /* Removing area light power*/
+ power *= M_2PI * 0.78; /* Matching cycles with point light. */
+ power *= 0.082; /* XXX ad hoc, empirical */
+ falloff = dot(N, -ld.l_forward);
+ }
+ else {
+ power = (4.0 * ld.l_radius * ld.l_radius) * (1.0 / 10.0);
+ power *= 1.5; /* XXX ad hoc, empirical */
+ power /= (l_vector.w * l_vector.w);
+ falloff = dot(N, l_vector.xyz / l_vector.w);
+ }
+ /* No transmittance at grazing angle (hide artifacts) */
+ return power * saturate(falloff * 2.0);
+}
+
+/* Some driver poorly optimize this code. Use direct reference to matrices. */
+#define sd(x) shadows_data[x]
+#define scube(x) shadows_cube_data[x]
+#define scascade(x) shadows_cascade_data[x]
+
+vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, vec2 rand, float sss_scale)
+{
+ int shadow_id = int(ld.l_shadowid);
+
+ vec4 L = (ld.l_type != SUN) ? l_vector : vec4(-ld.l_forward, 1.0);
+
+ /* We use the full l_vector.xyz so that the spread is minimize
+ * if the shading point is further away from the light source */
+ /* TODO(fclem) do something better than this. */
+ // vec3 T, B;
+ // make_orthonormal_basis(L.xyz / L.w, T, B);
+ // rand.xy *= data.sh_blur;
+ // W = W + T * rand.x + B * rand.y;
+
+ float s, dist;
+ int data_id = int(sd(shadow_id).sh_data_index);
+ if (ld.l_type == SUN) {
+ vec4 view_z = vec4(dot(W - cameraPos, cameraForward));
+
+ vec4 weights = step(scascade(data_id).split_end_distances, view_z);
+ float id = abs(4.0 - dot(weights, weights));
+ if (id > 3.0) {
+ return vec3(0.0);
+ }
+
+ /* Same factor as in get_cascade_world_distance(). */
+ float range = abs(sd(shadow_id).sh_far - sd(shadow_id).sh_near);
+
+ vec4 shpos = scascade(data_id).shadowmat[int(id)] * vec4(W, 1.0);
+ dist = shpos.z * range;
+
+ if (shpos.z > 1.0 || shpos.z < 0.0) {
+ return vec3(0.0);
+ }
+
+ float tex_id = scascade(data_id).sh_tex_index;
+ s = sample_cascade(sssShadowCascades, shpos.xy, tex_id + id).r;
+ s *= range;
+ }
+ else {
+ vec3 cubevec = transform_point(scube(data_id).shadowmat, W);
+ dist = length(cubevec);
+ cubevec /= dist;
+ /* tex_id == data_id for cube shadowmap */
+ float tex_id = float(data_id);
+ s = sample_cube(sssShadowCubes, cubevec, tex_id).r;
+ s = length(cubevec / max_v3(abs(cubevec))) *
+ linear_depth(true, s, sd(shadow_id).sh_far, sd(shadow_id).sh_near);
+ }
+ float delta = dist - s;
+
+ float power = light_translucent_power_with_falloff(ld, N, l_vector);
+
+ return power * sss_profile(abs(delta) / sss_scale);
+}
+
+#undef sd
+#undef scube
+#undef scsmd
+
+void main(void)
+{
+ vec2 uvs = uvcoordsvar.xy;
+ float sss_scale = texture(sssRadius, uvs).r;
+ vec3 W = get_world_space_from_depth(uvs, texture(depthBuffer, uvs).r);
+ vec3 N = normalize(cross(dFdx(W), dFdy(W)));
+
+ vec3 rand = texelfetch_noise_tex(gl_FragCoord.xy).zwy;
+ rand.xy *= fast_sqrt(rand.z);
+
+ vec3 accum = vec3(0.0);
+ for (int i = 0; i < MAX_LIGHT && i < laNumLight; i++) {
+ LightData ld = lights_data[i];
+
+ /* Only shadowed light can produce translucency */
+ if (ld.l_shadowid < 0.0) {
+ continue;
+ }
+
+ vec4 l_vector; /* Non-Normalized Light Vector with length in last component. */
+ l_vector.xyz = ld.l_position - W;
+ l_vector.w = length(l_vector.xyz);
+
+ float att = light_attenuation(ld, l_vector);
+ if (att < 1e-8) {
+ continue;
+ }
+
+ accum += att * ld.l_color * light_translucent(ld, W, -N, l_vector, rand.xy, sss_scale);
+ }
+
+ FragColor = vec4(accum, 1.0);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
index 37b02a2130f..296c1581545 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
@@ -64,7 +64,7 @@ void main()
float weight_accum = 0.0;
vec3 sh = vec3(0.0);
- for (int face = 0; face < 6; ++face) {
+ for (int face = 0; face < 6; face++) {
for (float x = halfpix; x < 1.0; x += pixstep) {
for (float y = halfpix; y < 1.0; y += pixstep) {
float weight, coef;
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl
index e10cb5f4999..f8bc1703c66 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl
@@ -37,7 +37,7 @@ void main()
fFace = face[0];
gl_Layer = Layer + fFace;
- for (int v = 0; v < 3; ++v) {
+ for (int v = 0; v < 3; v++) {
gl_Position = vPos[v];
worldPosition = x_axis[fFace] * vPos[v].x + y_axis[fFace] * vPos[v].y + maj_axes[fFace];
#ifdef USE_ATTR
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
index 56c05e3c036..ab205b78274 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
@@ -233,7 +233,7 @@ void fallback_cubemap(vec3 N,
#endif
/* Starts at 1 because 0 is world probe */
- for (int i = 1; i < MAX_PROBE && i < prbNumRenderCube && spec_accum.a < 0.999; ++i) {
+ for (int i = 1; i < MAX_PROBE && i < prbNumRenderCube && spec_accum.a < 0.999; i++) {
float fade = probe_attenuation_cube(i, W);
if (fade > 0.0) {
@@ -262,7 +262,7 @@ vec3 probe_evaluate_grid(GridData gd, vec3 W, vec3 N, vec3 localpos)
vec3 irradiance_accum = vec3(0.0);
/* For each neighbor cells */
- for (int i = 0; i < 8; ++i) {
+ for (int i = 0; i < 8; i++) {
ivec3 offset = ivec3(i, i >> 1, i >> 2) & ivec3(1);
vec3 cell_cos = clamp(localpos_floored + vec3(offset), vec3(0.0), vec3(gd.g_resolution) - 1.0);
diff --git a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
index c3643cccbfc..b1c78cae54f 100644
--- a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
@@ -1,6 +1,6 @@
-uniform sampler2DArray shadowCubeTexture;
-uniform sampler2DArray shadowCascadeTexture;
+uniform sampler2DArrayShadow shadowCubeTexture;
+uniform sampler2DArrayShadow shadowCascadeTexture;
#define LAMPS_LIB
@@ -24,129 +24,115 @@ layout(std140) uniform light_block
/* Used to define the area light shape, doesn't directly correspond to a Blender light type. */
#define AREA_ELLIPSE 100.0
-#if defined(SHADOW_VSM)
-# define ShadowSample vec2
-# define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).rg
-# define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).rg
-#elif defined(SHADOW_ESM)
-# define ShadowSample float
-# define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).r
-# define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).r
-#else
-# define ShadowSample float
-# define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).r
-# define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).r
-#endif
-
-#if defined(SHADOW_VSM)
-# define get_depth_delta(dist, s) (dist - s.x)
-#else
-# define get_depth_delta(dist, s) (dist - s)
-#endif
-
- /* ----------------------------------------------------------- */
- /* ----------------------- Shadow tests ---------------------- */
- /* ----------------------------------------------------------- */
-
-#if defined(SHADOW_VSM)
-
-float shadow_test(ShadowSample moments, float dist, ShadowData sd)
+float cubeFaceIndexEEVEE(vec3 P)
{
- float p = 0.0;
-
- if (dist <= moments.x) {
- p = 1.0;
+ vec3 aP = abs(P);
+ if (all(greaterThan(aP.xx, aP.yz))) {
+ return (P.x > 0.0) ? 0.0 : 1.0;
+ }
+ else if (all(greaterThan(aP.yy, aP.xz))) {
+ return (P.y > 0.0) ? 2.0 : 3.0;
+ }
+ else {
+ return (P.z > 0.0) ? 4.0 : 5.0;
}
-
- float variance = moments.y - (moments.x * moments.x);
- variance = max(variance, sd.sh_bias / 10.0);
-
- float d = moments.x - dist;
- float p_max = variance / (variance + d * d);
-
- /* Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1] */
- p_max = clamp((p_max - sd.sh_bleed) / (1.0 - sd.sh_bleed), 0.0, 1.0);
-
- return max(p, p_max);
}
-#elif defined(SHADOW_ESM)
-
-float shadow_test(ShadowSample z, float dist, ShadowData sd)
+vec2 cubeFaceCoordEEVEE(vec3 P, float face, float scale)
{
- return saturate(exp(sd.sh_exp * (z - dist + sd.sh_bias)));
+ if (face < 2.0) {
+ return (P.zy / P.x) * scale * vec2(-0.5, -sign(P.x) * 0.5) + 0.5;
+ }
+ else if (face < 4.0) {
+ return (P.xz / P.y) * scale * vec2(sign(P.y) * 0.5, 0.5) + 0.5;
+ }
+ else {
+ return (P.xy / P.z) * scale * vec2(0.5, -sign(P.z) * 0.5) + 0.5;
+ }
}
-#else
-
-float shadow_test(ShadowSample z, float dist, ShadowData sd)
+vec2 cubeFaceCoordEEVEE(vec3 P, float face, sampler2DArray tex)
{
- return step(0, z - dist + sd.sh_bias);
+ /* Scaling to compensate the 1px border around the face. */
+ float cube_res = float(textureSize(tex, 0).x);
+ float scale = (cube_res) / (cube_res + 1.0);
+ return cubeFaceCoordEEVEE(P, face, scale);
}
-#endif
-
-/* ----------------------------------------------------------- */
-/* ----------------------- Shadow types ---------------------- */
-/* ----------------------------------------------------------- */
-
-float shadow_cubemap(ShadowData sd, ShadowCubeData scd, float texid, vec3 W)
+vec2 cubeFaceCoordEEVEE(vec3 P, float face, sampler2DArrayShadow tex)
{
- vec3 cubevec = W - scd.position.xyz;
- float dist = length(cubevec);
+ /* Scaling to compensate the 1px border around the face. */
+ float cube_res = float(textureSize(tex, 0).x);
+ float scale = (cube_res) / (cube_res + 1.0);
+ return cubeFaceCoordEEVEE(P, face, scale);
+}
- cubevec /= dist;
+vec4 sample_cube(sampler2DArray tex, vec3 cubevec, float cube)
+{
+ /* Manual Shadow Cube Layer indexing. */
+ /* TODO Shadow Cube Array. */
+ float face = cubeFaceIndexEEVEE(cubevec);
+ vec2 uv = cubeFaceCoordEEVEE(cubevec, face, tex);
- ShadowSample s = sample_cube(cubevec, texid);
- return shadow_test(s, dist, sd);
+ vec3 coord = vec3(uv, cube * 6.0 + face);
+ return texture(tex, coord);
}
-float evaluate_cascade(ShadowData sd, mat4 shadowmat, vec3 W, float range, float texid)
+vec4 sample_cascade(sampler2DArray tex, vec2 co, float cascade_id)
{
- vec4 shpos = shadowmat * vec4(W, 1.0);
- float dist = shpos.z * range;
+ return texture(tex, vec3(co, cascade_id));
+}
- ShadowSample s = sample_cascade(shpos.xy, texid);
- float vis = shadow_test(s, dist, sd);
+/* Some driver poorly optimize this code. Use direct reference to matrices. */
+#define sd(x) shadows_data[x]
+#define scube(x) shadows_cube_data[x]
+#define scascade(x) shadows_cascade_data[x]
- /* If fragment is out of shadowmap range, do not occlude */
- if (shpos.z < 1.0 && shpos.z > 0.0) {
- return vis;
- }
- else {
- return 1.0;
- }
+float sample_cube_shadow(int shadow_id, vec3 W)
+{
+ int data_id = int(sd(shadow_id).sh_data_index);
+ vec3 cubevec = transform_point(scube(data_id).shadowmat, W);
+ float dist = max(sd(shadow_id).sh_near, max_v3(abs(cubevec)) - sd(shadow_id).sh_bias);
+ dist = buffer_depth(true, dist, sd(shadow_id).sh_far, sd(shadow_id).sh_near);
+ /* Manual Shadow Cube Layer indexing. */
+ /* TODO Shadow Cube Array. */
+ float face = cubeFaceIndexEEVEE(cubevec);
+ vec2 coord = cubeFaceCoordEEVEE(cubevec, face, shadowCubeTexture);
+ /* tex_id == data_id for cube shadowmap */
+ float tex_id = float(data_id);
+ return texture(shadowCubeTexture, vec4(coord, tex_id * 6.0 + face, dist));
}
-float shadow_cascade(ShadowData sd, int scd_id, float texid, vec3 W)
+float sample_cascade_shadow(int shadow_id, vec3 W)
{
+ int data_id = int(sd(shadow_id).sh_data_index);
+ float tex_id = scascade(data_id).sh_tex_index;
vec4 view_z = vec4(dot(W - cameraPos, cameraForward));
- vec4 weights = smoothstep(shadows_cascade_data[scd_id].split_end_distances,
- shadows_cascade_data[scd_id].split_start_distances.yzwx,
- view_z);
-
- weights.yzw -= weights.xyz;
-
- vec4 vis = vec4(1.0);
- float range = abs(sd.sh_far - sd.sh_near); /* Same factor as in get_cascade_world_distance(). */
-
- /* Branching using (weights > 0.0) is reaally slooow on intel so avoid it for now. */
- /* TODO OPTI: Only do 2 samples and blend. */
- vis.x = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[0], W, range, texid + 0);
- vis.y = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[1], W, range, texid + 1);
- vis.z = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[2], W, range, texid + 2);
- vis.w = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[3], W, range, texid + 3);
-
- float weight_sum = dot(vec4(1.0), weights);
- if (weight_sum > 0.9999) {
- float vis_sum = dot(vec4(1.0), vis * weights);
- return vis_sum / weight_sum;
- }
- else {
- float vis_sum = dot(vec4(1.0), vis * step(0.001, weights));
- return mix(1.0, vis_sum, weight_sum);
- }
+ vec4 weights = 1.0 - smoothstep(scascade(data_id).split_end_distances,
+ scascade(data_id).split_start_distances.yzwx,
+ view_z);
+ float tot_weight = dot(weights.xyz, vec3(1.0));
+
+ int cascade = int(clamp(tot_weight, 0.0, 3.0));
+ float blend = fract(tot_weight);
+ float vis = weights.w;
+ vec4 coord, shpos;
+ /* Main cascade. */
+ shpos = scascade(data_id).shadowmat[cascade] * vec4(W, 1.0);
+ coord = vec4(shpos.xy, tex_id + float(cascade), shpos.z - sd(shadow_id).sh_bias);
+ vis += texture(shadowCascadeTexture, coord) * (1.0 - blend);
+
+ cascade = min(3, cascade + 1);
+ /* Second cascade. */
+ shpos = scascade(data_id).shadowmat[cascade] * vec4(W, 1.0);
+ coord = vec4(shpos.xy, tex_id + float(cascade), shpos.z - sd(shadow_id).sh_bias);
+ vis += texture(shadowCascadeTexture, coord) * blend;
+
+ return saturate(vis);
}
+#undef sd
+#undef scube
+#undef scsmd
/* ----------------------------------------------------------- */
/* --------------------- Light Functions --------------------- */
@@ -173,16 +159,9 @@ float spot_attenuation(LightData ld, vec3 l_vector)
return spotmask;
}
-float light_visibility(LightData ld,
- vec3 W,
-#ifndef VOLUMETRICS
- vec3 viewPosition,
- vec3 vN,
-#endif
- vec4 l_vector)
+float light_attenuation(LightData ld, vec4 l_vector)
{
float vis = 1.0;
-
if (ld.l_type == SPOT) {
vis *= spot_attenuation(ld, l_vector.xyz);
}
@@ -192,69 +171,66 @@ float light_visibility(LightData ld,
if (ld.l_type != SUN) {
vis *= distance_attenuation(l_vector.w * l_vector.w, ld.l_influence);
}
+ return vis;
+}
+
+float light_visibility(LightData ld,
+ vec3 W,
+#ifndef VOLUMETRICS
+ vec3 viewPosition,
+ float tracing_depth,
+ vec3 true_normal,
+ float rand_x,
+ const bool use_contact_shadows,
+#endif
+ vec4 l_vector)
+{
+ float vis = light_attenuation(ld, l_vector);
#if !defined(VOLUMETRICS) || defined(VOLUME_SHADOW)
/* shadowing */
if (ld.l_shadowid >= 0.0 && vis > 0.001) {
- ShadowData data = shadows_data[int(ld.l_shadowid)];
if (ld.l_type == SUN) {
- vis *= shadow_cascade(data, int(data.sh_data_start), data.sh_tex_start, W);
+ vis *= sample_cascade_shadow(int(ld.l_shadowid), W);
}
else {
- vis *= shadow_cubemap(
- data, shadows_cube_data[int(data.sh_data_start)], data.sh_tex_start, W);
+ vis *= sample_cube_shadow(int(ld.l_shadowid), W);
}
# ifndef VOLUMETRICS
+ ShadowData sd = shadows_data[int(ld.l_shadowid)];
/* Only compute if not already in shadow. */
- if (data.sh_contact_dist > 0.0) {
- vec4 L = (ld.l_type != SUN) ? l_vector : vec4(-ld.l_forward, 1.0);
- float trace_distance = (ld.l_type != SUN) ? min(data.sh_contact_dist, l_vector.w) :
- data.sh_contact_dist;
-
- vec3 T, B;
- make_orthonormal_basis(L.xyz / L.w, T, B);
-
- vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
- rand.zw *= fast_sqrt(rand.y) * data.sh_contact_spread;
-
- /* We use the full l_vector.xyz so that the spread is minimize
- * if the shading point is further away from the light source */
- vec3 ray_dir = L.xyz + T * rand.z + B * rand.w;
- ray_dir = transform_direction(ViewMatrix, ray_dir);
- ray_dir = normalize(ray_dir);
-
- vec3 ray_ori = viewPosition;
-
- /* Fix translucency shadowed by contact shadows. */
- vN = (gl_FrontFacing) ? vN : -vN;
-
- if (dot(vN, ray_dir) <= 0.0) {
- return vis;
+ if (use_contact_shadows && sd.sh_contact_dist > 0.0 && vis > 1e-8) {
+ /* Contact Shadows. */
+ vec3 ray_ori, ray_dir;
+ float trace_distance;
+
+ if (ld.l_type == SUN) {
+ trace_distance = sd.sh_contact_dist;
+ ray_dir = shadows_cascade_data[int(sd.sh_data_index)].sh_shadow_vec * trace_distance;
+ }
+ else {
+ ray_dir = shadows_cube_data[int(sd.sh_data_index)].position.xyz - W;
+ float len = length(ray_dir);
+ trace_distance = min(sd.sh_contact_dist, len);
+ ray_dir *= trace_distance / len;
}
- float bias = 0.5; /* Constant Bias */
- bias += 1.0 - abs(dot(vN, ray_dir)); /* Angle dependent bias */
- bias *= gl_FrontFacing ? data.sh_contact_offset : -data.sh_contact_offset;
-
- vec3 nor_bias = vN * bias;
- ray_ori += nor_bias;
-
- ray_dir *= trace_distance;
- ray_dir -= nor_bias;
+ ray_dir = transform_direction(ViewMatrix, ray_dir);
+ ray_ori = vec3(viewPosition.xy, tracing_depth) + true_normal * sd.sh_contact_offset;
vec3 hit_pos = raycast(
- -1, ray_ori, ray_dir, data.sh_contact_thickness, rand.x, 0.1, 0.001, false);
+ -1, ray_ori, ray_dir, sd.sh_contact_thickness, rand_x, 0.1, 0.001, false);
if (hit_pos.z > 0.0) {
hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z);
float hit_dist = distance(viewPosition, hit_pos);
float dist_ratio = hit_dist / trace_distance;
- return vis * saturate(dist_ratio * dist_ratio * dist_ratio);
+ return vis * saturate(dist_ratio * 3.0 - 2.0);
}
}
-# endif
+# endif /* VOLUMETRICS */
}
#endif
@@ -325,134 +301,3 @@ float light_specular(LightData ld, vec4 ltc_mat, vec3 N, vec3 V, vec4 l_vector)
}
}
#endif
-
-#define MAX_SSS_SAMPLES 65
-#define SSS_LUT_SIZE 64.0
-#define SSS_LUT_SCALE ((SSS_LUT_SIZE - 1.0) / float(SSS_LUT_SIZE))
-#define SSS_LUT_BIAS (0.5 / float(SSS_LUT_SIZE))
-
-#ifdef USE_TRANSLUCENCY
-layout(std140) uniform sssProfile
-{
- vec4 kernel[MAX_SSS_SAMPLES];
- vec4 radii_max_radius;
- int sss_samples;
-};
-
-uniform sampler1D sssTexProfile;
-
-vec3 sss_profile(float s)
-{
- s /= radii_max_radius.w;
- return texture(sssTexProfile, saturate(s) * SSS_LUT_SCALE + SSS_LUT_BIAS).rgb;
-}
-#endif
-
-vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale)
-{
-#if !defined(USE_TRANSLUCENCY) || defined(VOLUMETRICS)
- return vec3(0.0);
-#else
- vec3 vis = vec3(1.0);
-
- if (ld.l_type == SPOT) {
- vis *= spot_attenuation(ld, l_vector.xyz);
- }
- if (ld.l_type >= SPOT) {
- vis *= step(0.0, -dot(l_vector.xyz, ld.l_forward));
- }
- if (ld.l_type != SUN) {
- vis *= distance_attenuation(l_vector.w * l_vector.w, ld.l_influence);
- }
-
- /* Only shadowed light can produce translucency */
- if (ld.l_shadowid >= 0.0 && vis.x > 0.001) {
- ShadowData data = shadows_data[int(ld.l_shadowid)];
- float delta;
-
- vec4 L = (ld.l_type != SUN) ? l_vector : vec4(-ld.l_forward, 1.0);
-
- vec3 T, B;
- make_orthonormal_basis(L.xyz / L.w, T, B);
-
- vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
- rand.zw *= fast_sqrt(rand.y) * data.sh_blur;
-
- /* We use the full l_vector.xyz so that the spread is minimize
- * if the shading point is further away from the light source */
- W = W + T * rand.z + B * rand.w;
-
- if (ld.l_type == SUN) {
- int scd_id = int(data.sh_data_start);
- vec4 view_z = vec4(dot(W - cameraPos, cameraForward));
-
- vec4 weights = step(shadows_cascade_data[scd_id].split_end_distances, view_z);
- float id = abs(4.0 - dot(weights, weights));
-
- if (id > 3.0) {
- return vec3(0.0);
- }
-
- /* Same factor as in get_cascade_world_distance(). */
- float range = abs(data.sh_far - data.sh_near);
-
- vec4 shpos = shadows_cascade_data[scd_id].shadowmat[int(id)] * vec4(W, 1.0);
- float dist = shpos.z * range;
-
- if (shpos.z > 1.0 || shpos.z < 0.0) {
- return vec3(0.0);
- }
-
- ShadowSample s = sample_cascade(shpos.xy, data.sh_tex_start + id);
- delta = get_depth_delta(dist, s);
- }
- else {
- vec3 cubevec = W - shadows_cube_data[int(data.sh_data_start)].position.xyz;
- float dist = length(cubevec);
- cubevec /= dist;
-
- ShadowSample s = sample_cube(cubevec, data.sh_tex_start);
- delta = get_depth_delta(dist, s);
- }
-
- /* XXX : Removing Area Power. */
- /* TODO : put this out of the shader. */
- float falloff;
- if (ld.l_type == AREA_RECT || ld.l_type == AREA_ELLIPSE) {
- vis *= (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0);
- if (ld.l_type == AREA_ELLIPSE) {
- vis *= M_PI * 0.25;
- }
- vis *= 0.3 * 20.0 *
- max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */
- vis /= (l_vector.w * l_vector.w);
- falloff = dot(N, l_vector.xyz / l_vector.w);
- }
- else if (ld.l_type == SUN) {
- vis /= 1.0f + (ld.l_radius * ld.l_radius * 0.5f);
- vis *= ld.l_radius * ld.l_radius * M_PI; /* Removing area light power*/
- vis *= M_2PI * 0.78; /* Matching cycles with point light. */
- vis *= 0.082; /* XXX ad hoc, empirical */
- falloff = dot(N, -ld.l_forward);
- }
- else {
- vis *= (4.0 * ld.l_radius * ld.l_radius) * (1.0 / 10.0);
- vis *= 1.5; /* XXX ad hoc, empirical */
- vis /= (l_vector.w * l_vector.w);
- falloff = dot(N, l_vector.xyz / l_vector.w);
- }
- // vis *= M_1_PI; /* Normalize */
-
- /* Applying profile */
- vis *= sss_profile(abs(delta) / scale);
-
- /* No transmittance at grazing angle (hide artifacts) */
- vis *= saturate(falloff * 2.0);
- }
- else {
- vis = vec3(0.0);
- }
-
- return vis;
-#endif
-}
diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
index 53f1517505c..3774054659d 100644
--- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
@@ -144,14 +144,12 @@ void CLOSURE_NAME(vec3 N
,
float ior
#endif
+ ,
+ const bool use_contact_shadows
#ifdef CLOSURE_DIFFUSE
,
out vec3 out_diff
#endif
-#ifdef CLOSURE_SUBSURFACE
- ,
- out vec3 out_trans
-#endif
#ifdef CLOSURE_GLOSSY
,
out vec3 out_spec
@@ -170,10 +168,6 @@ void CLOSURE_NAME(vec3 N
out_diff = vec3(0.0);
#endif
-#ifdef CLOSURE_SUBSURFACE
- out_trans = vec3(0.0);
-#endif
-
#ifdef CLOSURE_GLOSSY
out_spec = vec3(0.0);
#endif
@@ -230,14 +224,31 @@ void CLOSURE_NAME(vec3 N
vec3 out_spec_clear = vec3(0.0);
# endif
- for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) {
+ float tracing_depth = gl_FragCoord.z;
+ /* Constant bias (due to depth buffer precision) */
+ /* Magic numbers for 24bits of precision.
+ * From http://terathon.com/gdc07_lengyel.pdf (slide 26) */
+ tracing_depth -= mix(2.4e-7, 4.8e-7, gl_FragCoord.z);
+ /* Convert to view Z. */
+ tracing_depth = get_view_z_from_depth(tracing_depth);
+
+ vec3 true_normal = normalize(cross(dFdx(viewPosition), dFdy(viewPosition)));
+
+ for (int i = 0; i < MAX_LIGHT && i < laNumLight; i++) {
LightData ld = lights_data[i];
vec4 l_vector; /* Non-Normalized Light Vector with length in last component. */
l_vector.xyz = ld.l_position - worldPosition;
l_vector.w = length(l_vector.xyz);
- float l_vis = light_visibility(ld, worldPosition, viewPosition, viewNormal, l_vector);
+ float l_vis = light_visibility(ld,
+ worldPosition,
+ viewPosition,
+ tracing_depth,
+ true_normal,
+ rand.x,
+ use_contact_shadows,
+ l_vector);
if (l_vis < 1e-8) {
continue;
@@ -249,10 +260,6 @@ void CLOSURE_NAME(vec3 N
out_diff += l_color_vis * light_diffuse(ld, N, V, l_vector);
# endif
-# ifdef CLOSURE_SUBSURFACE
- out_trans += ld.l_color * light_translucent(ld, worldPosition, -N, l_vector, sss_scale);
-# endif
-
# ifdef CLOSURE_GLOSSY
out_spec += l_color_vis * light_specular(ld, ltc_mat, N, V, l_vector) * ld.l_spec;
# endif
@@ -297,7 +304,7 @@ void CLOSURE_NAME(vec3 N
/* Planar Reflections */
/* ---------------------------- */
- for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar && spec_accum.a < 0.999; ++i) {
+ for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar && spec_accum.a < 0.999; i++) {
PlanarData pd = planars_data[i];
/* Fade on geometric normal. */
@@ -373,7 +380,7 @@ void CLOSURE_NAME(vec3 N
# endif
/* Starts at 1 because 0 is world probe */
- for (int i = 1; ACCUM < 0.999 && i < prbNumRenderCube && i < MAX_PROBE; ++i) {
+ for (int i = 1; ACCUM < 0.999 && i < prbNumRenderCube && i < MAX_PROBE; i++) {
float fade = probe_attenuation_cube(i, worldPosition);
if (fade > 0.0) {
@@ -441,10 +448,17 @@ void CLOSURE_NAME(vec3 N
/* Ambient Occlusion */
/* ---------------------------- */
# if defined(CLOSURE_GLOSSY) || defined(CLOSURE_DIFFUSE)
- /* HACK: Fix for translucent BSDF. (see T65631) */
- bool same_side = dot((gl_FrontFacing) ? worldNormal : -worldNormal, N) > 0.0;
+ if (!use_contact_shadows) {
+ /* HACK: Fix for translucent BSDF. (see T65631) */
+ N = -N;
+ }
vec3 bent_normal;
- float final_ao = occlusion_compute(same_side ? N : -N, viewPosition, ao, rand, bent_normal);
+ float final_ao = occlusion_compute(N, viewPosition, ao, rand, bent_normal);
+ if (!use_contact_shadows) {
+ N = -N;
+ /* Bypass bent normal. */
+ bent_normal = N;
+ }
# endif
/* ---------------------------- */
@@ -501,7 +515,7 @@ void CLOSURE_NAME(vec3 N
/* Irradiance Grids */
/* ---------------------------- */
/* Start at 1 because 0 is world irradiance */
- for (int i = 1; i < MAX_GRID && i < prbNumRenderGrid && diff_accum.a < 0.999; ++i) {
+ for (int i = 1; i < MAX_GRID && i < prbNumRenderGrid && diff_accum.a < 0.999; i++) {
GridData gd = grids_data[i];
vec3 localpos;
diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
index 14e0c947b47..f88cfdf3787 100644
--- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
@@ -120,7 +120,8 @@ void prepare_raycast(vec3 ray_origin,
ss_ray = ss_start * m.xyyy + 0.5;
ss_step *= m.xyyy;
- ss_ray.xy += m * ssrPixelSize * 2.0; /* take the center of the texel. * 2 because halfres. */
+ /* take the center of the texel. */
+ // ss_ray.xy += sign(ss_ray.xy) * m * ssrPixelSize * (1.0 + hizMipOffset);
}
/* See times_and_deltas. */
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl
deleted file mode 100644
index 5646c257562..00000000000
--- a/source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl
+++ /dev/null
@@ -1,199 +0,0 @@
-/* Copy the depth only shadowmap into another texture while converting
- * to linear depth (or other storage method) and doing a 3x3 box filter. */
-
-layout(std140) uniform shadow_render_block
-{
- /* Use vectors to avoid alignment padding. */
- ivec4 shadowSampleCount;
- vec4 shadowInvSampleCount;
- vec4 filterSize;
- int viewCount;
- int baseId;
- float cubeTexelSize;
- float storedTexelSize;
- float nearClip;
- float farClip;
- float exponent;
-};
-
-#ifdef CSM
-uniform sampler2DArray shadowTexture;
-#else
-uniform samplerCube shadowTexture;
-#endif
-
-flat in int layerID;
-
-#ifdef CSM
-# define cascadeID layerID
-#else
-# define cascadeID 0
-#endif
-
-out vec4 FragColor;
-
-#define linear_depth(z) \
- ((nearClip * farClip) / (clamp(z, 0.0, 0.999999) * (nearClip - farClip) + farClip))
-
-/* add bias so background filtering does not bleed into shadow map */
-#define BACKGROUND_BIAS 0.05
-
-#ifdef CSM
-vec4 get_world_distance(vec4 depths, vec3 cos[4])
-{
- depths += step(vec4(0.9999), depths) * BACKGROUND_BIAS;
- return clamp(
- depths * abs(farClip - nearClip), 0.0, 1e10); /* Same factor as in shadow_cascade(). */
-}
-
-float get_world_distance(float depth, vec3 cos)
-{
- depth += step(0.9999, depth) * BACKGROUND_BIAS;
- return clamp(
- depth * abs(farClip - nearClip), 0.0, 1e10); /* Same factor as in shadow_cascade(). */
-}
-
-#else /* CUBEMAP */
-vec4 get_world_distance(vec4 depths, vec3 cos[4])
-{
- depths = linear_depth(depths);
- cos[0] = normalize(abs(cos[0]));
- cos[1] = normalize(abs(cos[1]));
- cos[2] = normalize(abs(cos[2]));
- cos[3] = normalize(abs(cos[3]));
- vec4 cos_vec;
- cos_vec.x = max(cos[0].x, max(cos[0].y, cos[0].z));
- cos_vec.y = max(cos[1].x, max(cos[1].y, cos[1].z));
- cos_vec.z = max(cos[2].x, max(cos[2].y, cos[2].z));
- cos_vec.w = max(cos[3].x, max(cos[3].y, cos[3].z));
- return depths / cos_vec;
-}
-
-float get_world_distance(float depth, vec3 cos)
-{
- depth = linear_depth(depth);
- cos = normalize(abs(cos));
- float cos_vec = max(cos.x, max(cos.y, cos.z));
- return depth / cos_vec;
-}
-#endif
-
-/* Marco Salvi's GDC 2008 presentation about shadow maps pre-filtering techniques slide 24 */
-#define ln_space_prefilter_step(ref, sample) exp(sample - ref)
-#define ln_space_prefilter_finalize(ref, sum) (ref + log(SAMPLE_WEIGHT * sum))
-
-#define SAMPLE_WEIGHT 0.11111
-
-#ifdef ESM
-void prefilter(vec4 depths, float ref, inout float accum)
-{
- accum += dot(ln_space_prefilter_step(ref, depths), vec4(1.0));
-}
-#else /* VSM */
-void prefilter(vec4 depths, float ref, inout vec2 accum)
-{
- vec4 depths_sqr = depths * depths;
- accum += vec2(dot(vec4(1.0), depths), dot(vec4(1.0), depths_sqr)) * SAMPLE_WEIGHT;
-}
-#endif
-
-#ifdef CSM
-vec3 get_texco(vec2 uvs, vec2 ofs)
-{
- return vec3(uvs + ofs, float(cascadeID));
-}
-#else /* CUBEMAP */
-const vec3 minorAxisX[6] = vec3[6](vec3(0.0f, 0.0f, -1.0f),
- vec3(0.0f, 0.0f, 1.0f),
- vec3(1.0f, 0.0f, 0.0f),
- vec3(1.0f, 0.0f, 0.0f),
- vec3(1.0f, 0.0f, 0.0f),
- vec3(-1.0f, 0.0f, 0.0f));
-
-const vec3 minorAxisY[6] = vec3[6](vec3(0.0f, -1.0f, 0.0f),
- vec3(0.0f, -1.0f, 0.0f),
- vec3(0.0f, 0.0f, 1.0f),
- vec3(0.0f, 0.0f, -1.0f),
- vec3(0.0f, -1.0f, 0.0f),
- vec3(0.0f, -1.0f, 0.0f));
-
-const vec3 majorAxis[6] = vec3[6](vec3(1.0f, 0.0f, 0.0f),
- vec3(-1.0f, 0.0f, 0.0f),
- vec3(0.0f, 1.0f, 0.0f),
- vec3(0.0f, -1.0f, 0.0f),
- vec3(0.0f, 0.0f, 1.0f),
- vec3(0.0f, 0.0f, -1.0f));
-
-vec3 get_texco(vec2 uvs, vec2 ofs)
-{
- uvs += ofs;
- return majorAxis[layerID] + uvs.x * minorAxisX[layerID] + uvs.y * minorAxisY[layerID];
-}
-#endif
-
-void main()
-{
- /* Copy the depth only shadowmap into another texture while converting
- * to linear depth and do a 3x3 box blur. */
-
-#ifdef CSM
- vec2 uvs = gl_FragCoord.xy * storedTexelSize;
-#else /* CUBEMAP */
- vec2 uvs = gl_FragCoord.xy * cubeTexelSize * 2.0 - 1.0;
-#endif
-
- /* Center texel */
- vec3 co = get_texco(uvs, vec2(0.0));
- float depth = texture(shadowTexture, co).r;
- depth = get_world_distance(depth, co);
-
- if (filterSize[cascadeID] == 0.0) {
-#ifdef ESM
- FragColor = vec4(depth);
-#else /* VSM */
- FragColor = vec2(depth, depth * depth).xyxy;
-#endif
- return;
- }
-
-#ifdef ESM
- float ref = depth;
- float accum = 1.0;
-#else /* VSM */
- float ref = 0.0; /* UNUSED */
- vec2 accum = vec2(depth, depth * depth) * SAMPLE_WEIGHT;
-#endif
-
- vec3 ofs = vec3(1.0, 0.0, -1.0) * filterSize[cascadeID];
-
- vec3 cos[4];
- cos[0] = get_texco(uvs, ofs.zz);
- cos[1] = get_texco(uvs, ofs.yz);
- cos[2] = get_texco(uvs, ofs.xz);
- cos[3] = get_texco(uvs, ofs.zy);
-
- vec4 depths;
- depths.x = texture(shadowTexture, cos[0]).r;
- depths.y = texture(shadowTexture, cos[1]).r;
- depths.z = texture(shadowTexture, cos[2]).r;
- depths.w = texture(shadowTexture, cos[3]).r;
- depths = get_world_distance(depths, cos);
- prefilter(depths, ref, accum);
-
- cos[0] = get_texco(uvs, ofs.xy);
- cos[1] = get_texco(uvs, ofs.zx);
- cos[2] = get_texco(uvs, ofs.yx);
- cos[3] = get_texco(uvs, ofs.xx);
- depths.x = texture(shadowTexture, cos[0]).r;
- depths.y = texture(shadowTexture, cos[1]).r;
- depths.z = texture(shadowTexture, cos[2]).r;
- depths.w = texture(shadowTexture, cos[3]).r;
- depths = get_world_distance(depths, cos);
- prefilter(depths, ref, accum);
-
-#ifdef ESM
- accum = ln_space_prefilter_finalize(ref, accum);
-#endif
- /* Clamp infinite sum. */
- FragColor = vec2(clamp(accum, 0.0, 1e16)).xyxy;
-}
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_process_geom.glsl b/source/blender/draw/engines/eevee/shaders/shadow_process_geom.glsl
deleted file mode 100644
index 591666560c4..00000000000
--- a/source/blender/draw/engines/eevee/shaders/shadow_process_geom.glsl
+++ /dev/null
@@ -1,36 +0,0 @@
-
-layout(triangles) in;
-layout(triangle_strip, max_vertices = 3) out;
-
-layout(std140) uniform shadow_render_block
-{
- /* Use vectors to avoid alignment padding. */
- ivec4 shadowSampleCount;
- vec4 shadowInvSampleCount;
- vec4 filterSize;
- int viewCount;
- int baseId;
- float cubeTexelSize;
- float storedTexelSize;
- float nearClip;
- float farClip;
- float exponent;
-};
-
-in int layerID_g[];
-
-flat out int layerID;
-
-void main()
-{
- gl_Layer = layerID_g[0];
- layerID = gl_Layer - baseId;
-
- gl_Position = gl_in[0].gl_Position;
- EmitVertex();
- gl_Position = gl_in[1].gl_Position;
- EmitVertex();
- gl_Position = gl_in[2].gl_Position;
- EmitVertex();
- EndPrimitive();
-}
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_process_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_process_vert.glsl
deleted file mode 100644
index 95e6a48b81f..00000000000
--- a/source/blender/draw/engines/eevee/shaders/shadow_process_vert.glsl
+++ /dev/null
@@ -1,32 +0,0 @@
-
-layout(std140) uniform shadow_render_block
-{
- /* Use vectors to avoid alignment padding. */
- ivec4 shadowSampleCount;
- vec4 shadowInvSampleCount;
- vec4 filterSize;
- int viewCount;
- int baseId;
- float cubeTexelSize;
- float storedTexelSize;
- float nearClip;
- float farClip;
- float exponent;
-};
-
-out int layerID_g;
-
-void main()
-{
- int v = gl_VertexID % 3;
- layerID_g = gl_VertexID / 3;
- float x = -1.0 + float((v & 1) << 2);
- float y = -1.0 + float((v & 2) << 1);
- gl_Position = vec4(x, y, 1.0, 1.0);
-
- /* HACK avoid changing drawcall parameters. */
- if (layerID_g >= viewCount) {
- gl_Position = vec4(0.0);
- }
- layerID_g += baseId;
-}
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl
deleted file mode 100644
index 5c19ccd5ce1..00000000000
--- a/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl
+++ /dev/null
@@ -1,322 +0,0 @@
-
-layout(std140) uniform shadow_render_block
-{
- /* Use vectors to avoid alignment padding. */
- ivec4 shadowSampleCount;
- vec4 shadowInvSampleCount;
- vec4 filterSize;
- int viewCount;
- int baseId;
- float cubeTexelSize;
- float storedTexelSize;
- float nearClip;
- float farClip;
- float exponent;
-};
-
-#ifdef CSM
-uniform sampler2DArray shadowTexture;
-#else
-uniform samplerCube shadowTexture;
-#endif
-
-flat in int layerID;
-
-#ifdef CSM
-# define cascadeID layerID
-#else
-# define cascadeID 0
-#endif
-
-out vec4 FragColor;
-
-vec3 octahedral_to_cubemap_proj(vec2 co)
-{
- co = co * 2.0 - 1.0;
-
- vec2 abs_co = abs(co);
- vec3 v = vec3(co, 1.0 - (abs_co.x + abs_co.y));
-
- if (abs_co.x + abs_co.y > 1.0) {
- v.xy = (abs(co.yx) - 1.0) * -sign(co.xy);
- }
-
- return v;
-}
-
-/* Marco Salvi's GDC 2008 presentation about shadow maps pre-filtering techniques slide 24 */
-/* http://advances.realtimerendering.com/s2009/SIGGRAPH%202009%20-%20Lighting%20Research%20at%20Bungie.pdf
- * Slide 55. */
-#define ln_space_prefilter_step(ref, sample) exp(sample - ref)
-#define ln_space_prefilter_finalize(ref, sum) (ref + log(shadowInvSampleCount[cascadeID] * sum))
-
-#ifdef CSM
-vec3 get_texco(vec3 cos, const vec2 ofs)
-{
- cos.xy += ofs * filterSize[cascadeID];
- return cos;
-}
-#else /* CUBEMAP */
-/* global vars */
-vec3 T = vec3(0.0);
-vec3 B = vec3(0.0);
-
-void make_orthonormal_basis(vec3 N)
-{
- vec3 UpVector = (abs(N.z) < 0.999) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
- T = normalize(cross(UpVector, N));
- B = cross(N, T);
-}
-
-vec3 get_texco(vec3 cos, const vec2 ofs)
-{
- return cos + ofs.x * T + ofs.y * B;
-}
-
-#endif
-
-#ifdef ESM
-void grouped_samples_accum(vec3 cos,
- const vec2 co1,
- const vec2 co2,
- const vec2 co3,
- const vec2 co4,
- float ref,
- inout vec4 accum)
-{
- vec4 depths;
- depths.x = texture(shadowTexture, get_texco(cos, co1)).r;
- depths.y = texture(shadowTexture, get_texco(cos, co2)).r;
- depths.z = texture(shadowTexture, get_texco(cos, co3)).r;
- depths.w = texture(shadowTexture, get_texco(cos, co4)).r;
-
- accum += ln_space_prefilter_step(ref, depths);
-}
-#else /* VSM */
-void grouped_samples_accum(vec3 cos,
- const vec2 co1,
- const vec2 co2,
- const vec2 co3,
- const vec2 co4,
- float ref,
- inout vec2 accum)
-{
- vec4 depths1, depths2;
- depths1.xy = texture(shadowTexture, get_texco(cos, co1)).rg;
- depths1.zw = texture(shadowTexture, get_texco(cos, co2)).rg;
- depths2.xy = texture(shadowTexture, get_texco(cos, co3)).rg;
- depths2.zw = texture(shadowTexture, get_texco(cos, co4)).rg;
-
- accum += depths1.xy + depths1.zw + depths2.xy + depths2.zw;
-}
-#endif
-
-void main()
-{
- vec3 cos;
-
- cos.xy = gl_FragCoord.xy * storedTexelSize;
-
-#ifdef CSM
- cos.z = float(cascadeID);
-#else /* CUBEMAP */
- /* add a 2 pixel border to ensure filtering is correct */
- cos.xy *= 1.0 + storedTexelSize * 2.0;
- cos.xy -= storedTexelSize;
-
- float pattern = 1.0;
-
- /* edge mirroring : only mirror if directly adjacent
- * (not diagonally adjacent) */
- vec2 m = abs(cos.xy - 0.5) + 0.5;
- vec2 f = floor(m);
- if (f.x - f.y != 0.0) {
- cos.xy = 1.0 - cos.xy;
- }
-
- /* clamp to [0-1] */
- cos.xy = fract(cos.xy);
-
- /* get cubemap vector */
- cos = normalize(octahedral_to_cubemap_proj(cos.xy));
- make_orthonormal_basis(cos);
-
- T *= filterSize[cascadeID];
- B *= filterSize[cascadeID];
-#endif
-
-#ifdef ESM
- /* disc blur in log space. */
- vec4 depths;
- depths.x = texture(shadowTexture, get_texco(cos, concentric[0])).r;
- depths.y = texture(shadowTexture, get_texco(cos, concentric[1])).r;
- depths.z = texture(shadowTexture, get_texco(cos, concentric[2])).r;
- depths.w = texture(shadowTexture, get_texco(cos, concentric[3])).r;
- float ref = depths.x;
- vec4 accum = ln_space_prefilter_step(ref, depths);
-
-#else /* VSM */
- float ref = 0.0; /* UNUSED */
- vec2 accum = vec2(0.0);
- grouped_samples_accum(
- cos, concentric[0], concentric[1], concentric[2], concentric[3], ref, accum);
-#endif
-
- /**
- * Making the `grouped_samples_accum` be called within a loop would be
- * the most conventional solution, however in some older gpus, transverse the huge
- * `const vec2 concentric[]` array with variable indices is extremely slow.
- * The solution is to use constant indices to access the array.
- */
- if (shadowSampleCount[cascadeID] > 4) {
- grouped_samples_accum(
- cos, concentric[4], concentric[5], concentric[6], concentric[7], ref, accum);
- grouped_samples_accum(
- cos, concentric[8], concentric[9], concentric[10], concentric[11], ref, accum);
- grouped_samples_accum(
- cos, concentric[12], concentric[13], concentric[14], concentric[15], ref, accum);
- }
- if (shadowSampleCount[cascadeID] > 16) {
- grouped_samples_accum(
- cos, concentric[16], concentric[17], concentric[18], concentric[19], ref, accum);
- grouped_samples_accum(
- cos, concentric[20], concentric[21], concentric[22], concentric[23], ref, accum);
- grouped_samples_accum(
- cos, concentric[24], concentric[25], concentric[26], concentric[27], ref, accum);
- grouped_samples_accum(
- cos, concentric[28], concentric[29], concentric[30], concentric[31], ref, accum);
- grouped_samples_accum(
- cos, concentric[32], concentric[33], concentric[34], concentric[35], ref, accum);
- }
-#ifdef HIGH_BLUR
- if (shadowSampleCount[cascadeID] > 36) {
- grouped_samples_accum(
- cos, concentric[36], concentric[37], concentric[38], concentric[39], ref, accum);
- grouped_samples_accum(
- cos, concentric[40], concentric[41], concentric[42], concentric[43], ref, accum);
- grouped_samples_accum(
- cos, concentric[44], concentric[45], concentric[46], concentric[47], ref, accum);
- grouped_samples_accum(
- cos, concentric[48], concentric[49], concentric[50], concentric[51], ref, accum);
- grouped_samples_accum(
- cos, concentric[52], concentric[53], concentric[54], concentric[55], ref, accum);
- grouped_samples_accum(
- cos, concentric[56], concentric[57], concentric[58], concentric[59], ref, accum);
- grouped_samples_accum(
- cos, concentric[60], concentric[61], concentric[62], concentric[63], ref, accum);
- }
- if (shadowSampleCount[cascadeID] > 64) {
- grouped_samples_accum(
- cos, concentric[64], concentric[65], concentric[66], concentric[67], ref, accum);
- grouped_samples_accum(
- cos, concentric[68], concentric[69], concentric[70], concentric[71], ref, accum);
- grouped_samples_accum(
- cos, concentric[72], concentric[73], concentric[74], concentric[75], ref, accum);
- grouped_samples_accum(
- cos, concentric[76], concentric[77], concentric[78], concentric[79], ref, accum);
- grouped_samples_accum(
- cos, concentric[80], concentric[81], concentric[82], concentric[83], ref, accum);
- grouped_samples_accum(
- cos, concentric[84], concentric[85], concentric[86], concentric[87], ref, accum);
- grouped_samples_accum(
- cos, concentric[88], concentric[89], concentric[90], concentric[91], ref, accum);
- grouped_samples_accum(
- cos, concentric[92], concentric[93], concentric[94], concentric[95], ref, accum);
- grouped_samples_accum(
- cos, concentric[96], concentric[97], concentric[98], concentric[99], ref, accum);
- }
- if (shadowSampleCount[cascadeID] > 100) {
- grouped_samples_accum(
- cos, concentric[100], concentric[101], concentric[102], concentric[103], ref, accum);
- grouped_samples_accum(
- cos, concentric[104], concentric[105], concentric[106], concentric[107], ref, accum);
- grouped_samples_accum(
- cos, concentric[108], concentric[109], concentric[110], concentric[111], ref, accum);
- grouped_samples_accum(
- cos, concentric[112], concentric[113], concentric[114], concentric[115], ref, accum);
- grouped_samples_accum(
- cos, concentric[116], concentric[117], concentric[118], concentric[119], ref, accum);
- grouped_samples_accum(
- cos, concentric[120], concentric[121], concentric[122], concentric[123], ref, accum);
- grouped_samples_accum(
- cos, concentric[124], concentric[125], concentric[126], concentric[127], ref, accum);
- grouped_samples_accum(
- cos, concentric[128], concentric[129], concentric[130], concentric[131], ref, accum);
- grouped_samples_accum(
- cos, concentric[132], concentric[133], concentric[134], concentric[135], ref, accum);
- grouped_samples_accum(
- cos, concentric[136], concentric[137], concentric[138], concentric[139], ref, accum);
- grouped_samples_accum(
- cos, concentric[140], concentric[141], concentric[142], concentric[143], ref, accum);
- }
- if (shadowSampleCount[cascadeID] > 144) {
- grouped_samples_accum(
- cos, concentric[144], concentric[145], concentric[146], concentric[147], ref, accum);
- grouped_samples_accum(
- cos, concentric[148], concentric[149], concentric[150], concentric[151], ref, accum);
- grouped_samples_accum(
- cos, concentric[152], concentric[153], concentric[154], concentric[155], ref, accum);
- grouped_samples_accum(
- cos, concentric[156], concentric[157], concentric[158], concentric[159], ref, accum);
- grouped_samples_accum(
- cos, concentric[160], concentric[161], concentric[162], concentric[163], ref, accum);
- grouped_samples_accum(
- cos, concentric[164], concentric[165], concentric[166], concentric[167], ref, accum);
- grouped_samples_accum(
- cos, concentric[168], concentric[169], concentric[170], concentric[171], ref, accum);
- grouped_samples_accum(
- cos, concentric[172], concentric[173], concentric[174], concentric[175], ref, accum);
- grouped_samples_accum(
- cos, concentric[176], concentric[177], concentric[178], concentric[179], ref, accum);
- grouped_samples_accum(
- cos, concentric[180], concentric[181], concentric[182], concentric[183], ref, accum);
- grouped_samples_accum(
- cos, concentric[184], concentric[185], concentric[186], concentric[187], ref, accum);
- grouped_samples_accum(
- cos, concentric[188], concentric[189], concentric[190], concentric[191], ref, accum);
- grouped_samples_accum(
- cos, concentric[192], concentric[193], concentric[194], concentric[195], ref, accum);
- }
- if (shadowSampleCount[cascadeID] > 196) {
- grouped_samples_accum(
- cos, concentric[196], concentric[197], concentric[198], concentric[199], ref, accum);
- grouped_samples_accum(
- cos, concentric[200], concentric[201], concentric[202], concentric[203], ref, accum);
- grouped_samples_accum(
- cos, concentric[204], concentric[205], concentric[206], concentric[207], ref, accum);
- grouped_samples_accum(
- cos, concentric[208], concentric[209], concentric[210], concentric[211], ref, accum);
- grouped_samples_accum(
- cos, concentric[212], concentric[213], concentric[114], concentric[215], ref, accum);
- grouped_samples_accum(
- cos, concentric[216], concentric[217], concentric[218], concentric[219], ref, accum);
- grouped_samples_accum(
- cos, concentric[220], concentric[221], concentric[222], concentric[223], ref, accum);
- grouped_samples_accum(
- cos, concentric[224], concentric[225], concentric[226], concentric[227], ref, accum);
- grouped_samples_accum(
- cos, concentric[228], concentric[229], concentric[230], concentric[231], ref, accum);
- grouped_samples_accum(
- cos, concentric[232], concentric[233], concentric[234], concentric[235], ref, accum);
- grouped_samples_accum(
- cos, concentric[236], concentric[237], concentric[238], concentric[239], ref, accum);
- grouped_samples_accum(
- cos, concentric[240], concentric[241], concentric[242], concentric[243], ref, accum);
- grouped_samples_accum(
- cos, concentric[244], concentric[245], concentric[246], concentric[247], ref, accum);
- grouped_samples_accum(
- cos, concentric[248], concentric[249], concentric[250], concentric[251], ref, accum);
- grouped_samples_accum(
- cos, concentric[252], concentric[253], concentric[254], concentric[255], ref, accum);
- }
-#endif
-
-#ifdef ESM
- accum.x = dot(vec4(1.0), accum);
- accum.x = ln_space_prefilter_finalize(ref, accum.x);
- FragColor = accum.xxxx;
-
-#else /* VSM */
- FragColor = accum.xyxy * shadowInvSampleCount[cascadeID];
-#endif
-}
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
index acd1e58ff97..c3c442e7b69 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
@@ -8,10 +8,17 @@
uniform sampler3D volumeScattering; /* Result of the scatter step */
uniform sampler3D volumeExtinction;
+#ifdef USE_VOLUME_OPTI
+uniform layout(binding = 0, r11f_g11f_b10f) writeonly restrict image3D finalScattering_img;
+uniform layout(binding = 1, r11f_g11f_b10f) writeonly restrict image3D finalTransmittance_img;
+vec3 finalScattering;
+vec3 finalTransmittance;
+#else
flat in int slice;
layout(location = 0) out vec3 finalScattering;
layout(location = 1) out vec3 finalTransmittance;
+#endif
void main()
{
@@ -36,10 +43,11 @@ void main()
orig_ray_len = prev_ray_len / view_cell.z;
}
- /* Without compute shader and arbitrary write we need to
- * accumulate from the beginning of the ray for each cell. */
- float integration_end = float(slice);
- for (int i = 0; i < slice; ++i) {
+#ifdef USE_VOLUME_OPTI
+ int slice = textureSize(volumeScattering, 0).z;
+ ivec2 texco = ivec2(gl_FragCoord.xy);
+#endif
+ for (int i = 0; i <= slice; i++) {
ivec3 volume_cell = ivec3(gl_FragCoord.xy, i);
vec3 Lscat = texelFetch(volumeScattering, volume_cell, 0).rgb;
@@ -63,5 +71,11 @@ void main()
finalScattering += finalTransmittance * Lscat;
finalTransmittance *= Tr;
+
+#ifdef USE_VOLUME_OPTI
+ ivec3 coord = ivec3(texco, i);
+ imageStore(finalScattering_img, coord, vec4(finalScattering, 0.0));
+ imageStore(finalTransmittance_img, coord, vec4(finalTransmittance, 0.0));
+#endif
}
}
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl
index d345cd5c808..9621fa1cc0d 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl
@@ -38,7 +38,7 @@ void main()
phase_function_isotropic();
#ifdef VOLUME_LIGHTING /* Lights */
- for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) {
+ for (int i = 0; i < MAX_LIGHT && i < laNumLight; i++) {
LightData ld = lights_data[i];
diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c
index f6646ca575e..704e16b2907 100644
--- a/source/blender/draw/engines/external/external_engine.c
+++ b/source/blender/draw/engines/external/external_engine.c
@@ -28,6 +28,8 @@
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
+#include "BKE_object.h"
+
#include "ED_screen.h"
#include "GPU_matrix.h"
@@ -156,7 +158,8 @@ static void external_cache_populate(void *vedata, Object *ob)
{
EXTERNAL_StorageList *stl = ((EXTERNAL_Data *)vedata)->stl;
- if (!DRW_object_is_renderable(ob)) {
+ if (!(DRW_object_is_renderable(ob) &&
+ DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) {
return;
}
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
index 541a9e31586..8006c784190 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
@@ -80,7 +80,7 @@ static void gpencil_set_buffer_stroke_point(GPUVertBuf *vbo,
uint thickness_id,
uint uvdata_id,
uint prev_pos_id,
- float ref_pt[3],
+ const float ref_pt[3],
short thickness,
const float ink[4])
{
@@ -110,7 +110,7 @@ static void gpencil_set_fill_point(GPUVertBuf *vbo,
int idx,
bGPDspoint *pt,
const float fcolor[4],
- float uv[2],
+ const float uv[2],
uint pos_id,
uint color_id,
uint text_id)
@@ -886,7 +886,7 @@ void gpencil_get_edlin_geom(struct GpencilBatchCacheElem *be,
static void set_grid_point(GPUVertBuf *vbo,
int idx,
- float col_grid[4],
+ const float col_grid[4],
uint pos_id,
uint color_id,
float v1,
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
index 93040afe2c7..ce5d8cbf732 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
@@ -61,13 +61,81 @@
#define TEXTURE 4
#define PATTERN 5
+/* Verify if must fade object or not. */
+static bool gpencil_fade_object_check(GPENCIL_StorageList *stl, Object *ob)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ const bool is_overlay = (bool)((v3d) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) &&
+ (v3d->gp_flag & V3D_GP_SHOW_PAPER));
+
+ if ((!is_overlay) || (ob == draw_ctx->obact) ||
+ ((v3d->gp_flag & V3D_GP_FADE_NOACTIVE_GPENCIL) == 0) ||
+ (v3d->overlay.gpencil_paper_opacity == 1.0f)) {
+ return false;
+ }
+
+ const bool playing = stl->storage->is_playing;
+ const bool is_render = (bool)stl->storage->is_render;
+ const bool is_mat_preview = (bool)stl->storage->is_mat_preview;
+ const bool is_select = (bool)(DRW_state_is_select() || DRW_state_is_depth());
+
+ return (bool)((!is_render) && (!playing) && (!is_mat_preview) && (!is_select));
+}
+
+/* Define Fade layer uniforms. */
+static void gpencil_set_fade_layer_uniforms(
+ GPENCIL_StorageList *stl, DRWShadingGroup *grp, Object *ob, bGPDlayer *gpl, const bool skip)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) : true;
+ const bool is_fade = (v3d) && (v3d->gp_flag & V3D_GP_FADE_NOACTIVE_LAYERS) &&
+ (draw_ctx->obact) && (draw_ctx->obact == ob) &&
+ ((gpl->flag & GP_LAYER_ACTIVE) == 0);
+
+ const bool playing = stl->storage->is_playing;
+ const bool is_render = (bool)stl->storage->is_render;
+ const bool is_mat_preview = (bool)stl->storage->is_mat_preview;
+ const bool is_select = (bool)(DRW_state_is_select() || DRW_state_is_depth());
+
+ /* If drawing or not fading layer, skip. */
+ if ((!overlay) || (skip) || (!is_fade) || (is_render) || (playing) || (is_mat_preview) ||
+ (is_select)) {
+ DRW_shgroup_uniform_int_copy(grp, "fade_layer", 0);
+ return;
+ }
+
+ /* If layer is above active, use alpha (2) if below use mix with background (1). */
+ if (stl->storage->is_ontop) {
+ DRW_shgroup_uniform_int_copy(grp, "fade_layer", 2);
+ }
+ else {
+ DRW_shgroup_uniform_int_copy(grp, "fade_layer", 1);
+ }
+ if (v3d) {
+ DRW_shgroup_uniform_vec3(grp, "fade_color", v3d->shading.background_color, 1);
+ DRW_shgroup_uniform_float(grp, "fade_layer_factor", &v3d->overlay.gpencil_fade_layer, 1);
+ }
+}
+
+/* Define Fade object uniforms. */
+static void gpencil_set_fade_ob_uniforms(View3D *v3d, DRWShadingGroup *grp, bool status)
+{
+ DRW_shgroup_uniform_bool_copy(grp, "fade_ob", status);
+ if (v3d) {
+ DRW_shgroup_uniform_vec3(grp, "fade_color", v3d->shading.background_color, 1);
+ DRW_shgroup_uniform_float(grp, "fade_ob_factor", &v3d->overlay.gpencil_paper_opacity, 1);
+ }
+}
+
/* Get number of vertex for using in GPU VBOs */
static void gpencil_calc_vertex(GPENCIL_StorageList *stl,
tGPencilObjectCache *cache_ob,
GpencilBatchCache *cache,
bGPdata *gpd)
{
- if (!cache->is_dirty) {
+ if ((!cache->is_dirty) || (gpd == NULL)) {
return;
}
@@ -81,10 +149,15 @@ static void gpencil_calc_vertex(GPENCIL_StorageList *stl,
(bool)((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) :
true;
const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay &&
- main_onion && gpencil_onion_active(gpd) && !playing;
+ main_onion && !playing && gpencil_onion_active(gpd);
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ /* Onion skining. */
+ const int step = gpd->gstep;
+ const int mode = gpd->onion_mode;
+ const short onion_keytype = gpd->onion_keytype;
+
cache_ob->tot_vertex = 0;
cache_ob->tot_triangles = 0;
int idx_eval = 0;
@@ -97,7 +170,7 @@ static void gpencil_calc_vertex(GPENCIL_StorageList *stl,
continue;
}
- /* if multiedit or onion skin need to count all frames of the layer */
+ /* If multiedit or onion skin need to count all frames of the layer. */
if ((is_multiedit) || (is_onion)) {
init_gpf = gpl->frames.first;
}
@@ -111,9 +184,35 @@ static void gpencil_calc_vertex(GPENCIL_StorageList *stl,
for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- cache_ob->tot_vertex += gps->totpoints + 3;
- cache_ob->tot_triangles += gps->totpoints - 1;
+ if (!is_onion) {
+ if ((!is_multiedit) ||
+ ((is_multiedit) && ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)))) {
+ cache_ob->tot_vertex += gps->totpoints + 3;
+ cache_ob->tot_triangles += gps->totpoints - 1;
+ }
+ }
+ else {
+ /* Only selected frames. */
+ if ((mode == GP_ONION_MODE_SELECTED) && ((gpf->flag & GP_FRAME_SELECT) == 0)) {
+ continue;
+ }
+ /* Verify keyframe type. */
+ if ((onion_keytype > -1) && (gpf->key_type != onion_keytype)) {
+ continue;
+ }
+ /* Absolute range. */
+ if (mode == GP_ONION_MODE_ABSOLUTE) {
+ if ((gpl->actframe) && (abs(gpl->actframe->framenum - gpf->framenum) > step)) {
+ continue;
+ }
+ }
+ /* For relative range it takes too much time compute, so use all frames. */
+ cache_ob->tot_vertex += gps->totpoints + 3;
+ cache_ob->tot_triangles += gps->totpoints - 1;
+ }
}
+
+ /* If not multiframe nor Onion skin, don't need follow counting. */
if ((!is_multiedit) && (!is_onion)) {
break;
}
@@ -208,8 +307,11 @@ static void gpencil_calc_2d_bounding_box(const float (*points2d)[2],
}
/* calc texture coordinates using flat projected points */
-static void gpencil_calc_stroke_fill_uv(
- const float (*points2d)[2], int totpoints, float minv[2], float maxv[2], float (*r_uv)[2])
+static void gpencil_calc_stroke_fill_uv(const float (*points2d)[2],
+ int totpoints,
+ const float minv[2],
+ float maxv[2],
+ float (*r_uv)[2])
{
float d[2];
d[0] = maxv[0] - minv[0];
@@ -264,7 +366,6 @@ static void set_wireframe_color(Object *ob,
else {
copy_v4_v4(color, gp_style->stroke_rgba);
}
- float alpha = color[3];
/* wire color */
if ((v3d) && (id > -1)) {
@@ -301,13 +402,13 @@ static void set_wireframe_color(Object *ob,
else {
copy_v3_v3(color, v3d->shading.single_color);
}
- color[3] = alpha;
+ color[3] = 1.0f;
linearrgb_to_srgb_v4(stl->shgroups[id].wire_color, color);
break;
}
case V3D_SHADING_OBJECT_COLOR: {
copy_v4_v4(color, ob->color);
- color[3] = alpha;
+ color[3] = 1.0f;
linearrgb_to_srgb_v4(stl->shgroups[id].wire_color, color);
break;
}
@@ -324,7 +425,7 @@ static void set_wireframe_color(Object *ob,
hsv_to_rgb_v(hsv, &wire_col[0]);
copy_v3_v3(stl->shgroups[id].wire_color, wire_col);
- stl->shgroups[id].wire_color[3] = alpha;
+ stl->shgroups[id].wire_color[3] = 1.0f;
break;
}
default: {
@@ -337,22 +438,24 @@ static void set_wireframe_color(Object *ob,
copy_v4_v4(stl->shgroups[id].wire_color, color);
}
- /* if solid, the alpha must be set to 1.0 */
+ /* if solid, the alpha must be set to alpha */
if (stl->shgroups[id].shading_type[0] == OB_SOLID) {
stl->shgroups[id].wire_color[3] = 1.0f;
}
}
/* create shading group for filling */
-static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_Data *vedata,
+static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_e_data *e_data,
+ GPENCIL_Data *vedata,
DRWPass *pass,
GPUShader *shader,
Object *ob,
+ float (*obmat)[4],
bGPdata *gpd,
bGPDlayer *gpl,
MaterialGPencilStyle *gp_style,
int id,
- int shading_type[2])
+ const int shading_type[2])
{
GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
const DRWContextState *draw_ctx = DRW_context_state_get();
@@ -361,6 +464,8 @@ static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_Data *vedata,
/* e_data.gpencil_fill_sh */
DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
+ DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat);
+
DRW_shgroup_uniform_vec4(grp, "color2", gp_style->mix_rgba, 1);
/* set style type */
@@ -431,6 +536,12 @@ static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_Data *vedata,
DRW_shgroup_uniform_int(grp, "shading_type", &stl->shgroups[id].shading_type[0], 2);
+ /* Fade layer uniforms. */
+ gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, false);
+
+ /* Fade object uniforms. */
+ gpencil_set_fade_ob_uniforms(v3d, grp, gpencil_fade_object_check(stl, ob));
+
/* wire color */
set_wireframe_color(ob, gpl, v3d, stl, gp_style, id, true);
DRW_shgroup_uniform_vec4(grp, "wire_color", stl->shgroups[id].wire_color, 1);
@@ -464,7 +575,7 @@ static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_Data *vedata,
}
else {
/* if no texture defined, need a blank texture to avoid errors in draw manager */
- DRW_shgroup_uniform_texture(grp, "myTexture", stl->g_data->gpencil_blank_texture);
+ DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
stl->shgroups[id].texture_clamp = 0;
DRW_shgroup_uniform_int(grp, "texture_clamp", &stl->shgroups[id].texture_clamp, 1);
}
@@ -484,10 +595,12 @@ bool gpencil_onion_active(bGPdata *gpd)
}
/* create shading group for strokes */
-DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_Data *vedata,
+DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_e_data *e_data,
+ GPENCIL_Data *vedata,
DRWPass *pass,
GPUShader *shader,
Object *ob,
+ float (*obmat)[4],
bGPdata *gpd,
bGPDlayer *gpl,
bGPDstroke *gps,
@@ -509,6 +622,8 @@ DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_Data *vedata,
DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat);
+
/* avoid wrong values */
if ((gpd) && (gpd->pixfactor == 0.0f)) {
gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
@@ -553,6 +668,12 @@ DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_Data *vedata,
}
DRW_shgroup_uniform_int(grp, "shading_type", &stl->shgroups[id].shading_type[0], 2);
+ /* Fade layer uniforms. */
+ gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, false);
+
+ /* Fade object uniforms. */
+ gpencil_set_fade_ob_uniforms(v3d, grp, gpencil_fade_object_check(stl, ob));
+
/* wire color */
set_wireframe_color(ob, gpl, v3d, stl, gp_style, id, false);
DRW_shgroup_uniform_vec4(grp, "wire_color", stl->shgroups[id].wire_color, 1);
@@ -603,6 +724,12 @@ DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_Data *vedata,
DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1);
}
+ /* Fade layer uniforms. */
+ gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, true);
+
+ /* Fade object uniforms. */
+ gpencil_set_fade_ob_uniforms(v3d, grp, false);
+
/* image texture for pattern */
if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
ImBuf *ibuf;
@@ -628,17 +755,19 @@ DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_Data *vedata,
}
else {
/* if no texture defined, need a blank texture to avoid errors in draw manager */
- DRW_shgroup_uniform_texture(grp, "myTexture", stl->g_data->gpencil_blank_texture);
+ DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
}
return grp;
}
/* create shading group for points */
-static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_Data *vedata,
+static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_e_data *e_data,
+ GPENCIL_Data *vedata,
DRWPass *pass,
GPUShader *shader,
Object *ob,
+ float (*obmat)[4],
bGPdata *gpd,
bGPDlayer *gpl,
bGPDstroke *gps,
@@ -659,6 +788,8 @@ static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_Data *vedata,
DRW_shgroup_uniform_vec2(grp, "Viewport", viewport_size, 1);
DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat);
+
/* avoid wrong values */
if ((gpd) && (gpd->pixfactor == 0.0f)) {
gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
@@ -702,6 +833,12 @@ static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_Data *vedata,
}
DRW_shgroup_uniform_int(grp, "shading_type", &stl->shgroups[id].shading_type[0], 2);
+ /* Fade layer uniforms. */
+ gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, false);
+
+ /* Fade object uniforms. */
+ gpencil_set_fade_ob_uniforms(v3d, grp, gpencil_fade_object_check(stl, ob));
+
/* wire color */
set_wireframe_color(ob, gpl, v3d, stl, gp_style, id, false);
DRW_shgroup_uniform_vec4(grp, "wire_color", stl->shgroups[id].wire_color, 1);
@@ -760,6 +897,12 @@ static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_Data *vedata,
DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1);
}
+ /* Fade layer uniforms. */
+ gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, true);
+
+ /* Fade object uniforms. */
+ gpencil_set_fade_ob_uniforms(v3d, grp, false);
+
/* image texture */
if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
ImBuf *ibuf;
@@ -785,7 +928,7 @@ static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_Data *vedata,
}
else {
/* if no texture defined, need a blank texture to avoid errors in draw manager */
- DRW_shgroup_uniform_texture(grp, "myTexture", stl->g_data->gpencil_blank_texture);
+ DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
}
return grp;
@@ -944,6 +1087,11 @@ static void gpencil_add_editpoints_vertexdata(GpencilBatchCache *cache,
GP_SCULPT_MASK_SELECTMODE_STROKE |
GP_SCULPT_MASK_SELECTMODE_SEGMENT)));
+ const bool show_sculpt_points = (GPENCIL_SCULPT_MODE(gpd) &&
+ (ts->gpencil_selectmode_sculpt &
+ (GP_SCULPT_MASK_SELECTMODE_POINT |
+ GP_SCULPT_MASK_SELECTMODE_SEGMENT)));
+
MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
/* alpha factor for edit points/line to make them more subtle */
@@ -955,8 +1103,19 @@ static void gpencil_add_editpoints_vertexdata(GpencilBatchCache *cache,
return;
}
const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
+
+ /* If Sculpt mode and the mask is disabled, the select must be hidden. */
const bool hide_select = GPENCIL_SCULPT_MODE(gpd) && !use_sculpt_mask;
+ /* Show Edit points if:
+ * Edit mode: Not in Stroke selection mode
+ * Sculpt mode: Not in Stroke mask mode and any other mask mode enabled
+ * Weight mode: Always
+ */
+ const bool show_points = (show_sculpt_points) || (is_weight_paint) ||
+ (GPENCIL_EDIT_MODE(gpd) &&
+ (ts->gpencil_selectmode_edit != GP_SELECTMODE_STROKE));
+
if (cache->is_dirty) {
if ((obact == ob) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) &&
(v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES)) {
@@ -976,8 +1135,8 @@ static void gpencil_add_editpoints_vertexdata(GpencilBatchCache *cache,
&cache->grp_used);
}
- /* In sculpt mode, the point are only visible if masking is enabled. */
- if (hide_select) {
+ /* If the points are hidden return. */
+ if ((!show_points) || (hide_select)) {
return;
}
@@ -1028,7 +1187,8 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache,
const bool playing = stl->storage->is_playing;
const bool is_render = (bool)stl->storage->is_render;
const bool is_mat_preview = (bool)stl->storage->is_mat_preview;
- const bool overlay_multiedit = v3d != NULL ? (v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) : true;
+ const bool overlay_multiedit = v3d != NULL ? !(v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) :
+ true;
/* Get evaluation context */
/* NOTE: We must check if C is valid, otherwise we get crashes when trying to save files
@@ -1052,6 +1212,12 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache,
continue;
}
+ /* Copy color to temp fields. */
+ if ((is_multiedit) && (gp_style)) {
+ copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
+ copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
+ }
+
/* be sure recalc all cache in source stroke to avoid recalculation when frame change
* and improve fps */
gpencil_recalc_geometry_caches(
@@ -1069,7 +1235,8 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache,
}
}
- if ((gpl->actframe->framenum == gpf->framenum) || (!is_multiedit) || (overlay_multiedit)) {
+ if ((gpl->actframe && (gpl->actframe->framenum == gpf->framenum)) || (!is_multiedit) ||
+ (overlay_multiedit)) {
/* hide any blend layer */
if ((!stl->storage->simplify_blend) || (gpl->blend_mode == eGplBlendMode_Regular)) {
/* fill */
@@ -1188,19 +1355,19 @@ static void gpencil_draw_onionskins(GpencilBatchCache *cache,
int idx;
float fac = 1.0f;
int step = 0;
- int mode = 0;
bool colflag = false;
- bGPDframe *gpf_loop = NULL;
+ const int mode = gpd->onion_mode;
+ bGPDframe *gpf_loop = ((gpd->onion_flag & GP_ONION_LOOP) && (mode != GP_ONION_MODE_SELECTED)) ?
+ gpl->frames.first :
+ NULL;
int last = gpf->framenum;
colflag = (bool)gpd->onion_flag & GP_ONION_GHOST_PREVCOL;
const short onion_keytype = gpd->onion_keytype;
-
/* -------------------------------
* 1) Draw Previous Frames First
* ------------------------------- */
step = gpd->gstep;
- mode = gpd->onion_mode;
if (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) {
copy_v3_v3(color, gpd->gcolor_prev);
@@ -1249,7 +1416,7 @@ static void gpencil_draw_onionskins(GpencilBatchCache *cache,
}
/* if loop option, save the frame to use later */
- if ((mode != GP_ONION_MODE_ABSOLUTE) && (gpd->onion_flag & GP_ONION_LOOP)) {
+ if ((mode == GP_ONION_MODE_SELECTED) && (gpd->onion_flag & GP_ONION_LOOP)) {
gpf_loop = gf;
}
@@ -1260,7 +1427,6 @@ static void gpencil_draw_onionskins(GpencilBatchCache *cache,
* 2) Now draw next frames
* ------------------------------- */
step = gpd->gstep_next;
- mode = gpd->onion_mode;
if (gpd->onion_flag & GP_ONION_GHOST_NEXTCOL) {
copy_v3_v3(color, gpd->gcolor_next);
@@ -1439,6 +1605,9 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data,
gp_style = BKE_material_gpencil_settings_get(ob, ob->actcol);
}
+ static float unit_mat[4][4] = {
+ {1.0, 0.0, 0.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, 0.0, 0.0, 1.0}};
+
/* drawing strokes */
/* Check if may need to draw the active stroke cache, only if this layer is the active layer
* that is being edited. (Stroke buffer is currently stored in gp-data)
@@ -1459,10 +1628,12 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data,
if (gpd->runtime.sbuffer_used > 1) {
if ((gp_style) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
stl->g_data->shgrps_drawing_stroke = gpencil_shgroup_stroke_create(
+ e_data,
vedata,
psl->drawing_pass,
e_data->gpencil_stroke_sh,
NULL,
+ unit_mat,
gpd,
NULL,
NULL,
@@ -1483,10 +1654,12 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data,
}
else {
stl->g_data->shgrps_drawing_stroke = gpencil_shgroup_point_create(
+ e_data,
vedata,
psl->drawing_pass,
e_data->gpencil_point_sh,
NULL,
+ unit_mat,
gpd,
NULL,
NULL,
@@ -1546,6 +1719,8 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data,
DRWShadingGroup *shgrp = DRW_shgroup_create(e_data->gpencil_edit_point_sh, psl->drawing_pass);
const float *viewport_size = DRW_viewport_size_get();
DRW_shgroup_uniform_vec2(shgrp, "Viewport", viewport_size, 1);
+ DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", unit_mat);
+
/* Disable stencil for this type */
DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
stl->g_data->batch_buffer_ctrlpoint = gpencil_get_buffer_ctrlpoint_geom(gpd);
@@ -1555,7 +1730,7 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data,
}
/* create all missing batches */
-static void gpencil_create_batches(GpencilBatchCache *cache)
+static void gpencil_batches_ensure(GpencilBatchCache *cache)
{
if ((cache->b_point.vbo) && (cache->b_point.batch == NULL)) {
cache->b_point.batch = GPU_batch_create_ex(
@@ -1608,7 +1783,7 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
true;
const bool main_onion = v3d != NULL ? (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) : true;
const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && main_onion &&
- gpencil_onion_active(gpd) && overlay;
+ overlay && gpencil_onion_active(gpd);
int start_stroke = 0;
int start_point = 0;
@@ -1617,6 +1792,8 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
int start_edlin = 0;
uint stencil_id = 1;
+ /* Flag to determine if the layer is above active layer. */
+ stl->storage->is_ontop = false;
for (int i = 0; i < cache->grp_used; i++) {
elm = &cache->grp_cache[i];
array_elm = &cache_ob->shgrp_array[idx];
@@ -1644,6 +1821,10 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
}
gpl = elm->gpl;
+ if ((!stl->storage->is_ontop) && (gpl->flag & GP_LAYER_ACTIVE)) {
+ stl->storage->is_ontop = true;
+ }
+
bGPDframe *gpf = elm->gpf;
bGPDstroke *gps = elm->gps;
MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
@@ -1663,10 +1844,12 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
case eGpencilBatchGroupType_Stroke: {
const int len = elm->vertex_idx - start_stroke;
- shgrp = gpencil_shgroup_stroke_create(vedata,
+ shgrp = gpencil_shgroup_stroke_create(e_data,
+ vedata,
stroke_pass,
e_data->gpencil_stroke_sh,
ob,
+ obmat,
gpd,
gpl,
gps,
@@ -1675,32 +1858,37 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
elm->onion,
scale,
cache_ob->shading_type);
- if ((do_onion) || (elm->onion == false)) {
- DRW_shgroup_call_range_obmat(shgrp, cache->b_stroke.batch, obmat, start_stroke, len);
- }
- stl->storage->shgroup_id++;
- start_stroke = elm->vertex_idx;
/* set stencil mask id */
if (gpencil_is_stencil_required(gp_style)) {
+ if (stencil_id == 1) {
+ /* Clear previous stencils. */
+ DRW_shgroup_clear_framebuffer(shgrp, GPU_STENCIL_BIT, 0, 0, 0, 0, 0.0f, 0x0);
+ }
DRW_shgroup_stencil_mask(shgrp, stencil_id);
stencil_id++;
}
else {
/* Disable stencil for this type */
DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- /* set stencil mask id as not used */
- DRW_shgroup_stencil_mask(shgrp, 0x0);
}
+
+ if ((do_onion) || (elm->onion == false)) {
+ DRW_shgroup_call_range(shgrp, cache->b_stroke.batch, start_stroke, len);
+ }
+ stl->storage->shgroup_id++;
+ start_stroke = elm->vertex_idx;
break;
}
case eGpencilBatchGroupType_Point: {
const int len = elm->vertex_idx - start_point;
- shgrp = gpencil_shgroup_point_create(vedata,
+ shgrp = gpencil_shgroup_point_create(e_data,
+ vedata,
stroke_pass,
e_data->gpencil_point_sh,
ob,
+ obmat,
gpd,
gpl,
gps,
@@ -1710,49 +1898,50 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
scale,
cache_ob->shading_type);
+ /* Disable stencil for this type */
+ DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
+
if ((do_onion) || (elm->onion == false)) {
- DRW_shgroup_call_range_obmat(shgrp, cache->b_point.batch, obmat, start_point, len);
+ DRW_shgroup_call_range(shgrp, cache->b_point.batch, start_point, len);
}
stl->storage->shgroup_id++;
start_point = elm->vertex_idx;
-
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- /* set stencil mask id as not used */
- DRW_shgroup_stencil_mask(shgrp, 0x0);
break;
}
case eGpencilBatchGroupType_Fill: {
const int len = elm->vertex_idx - start_fill;
- shgrp = gpencil_shgroup_fill_create(vedata,
+ shgrp = gpencil_shgroup_fill_create(e_data,
+ vedata,
stroke_pass,
e_data->gpencil_fill_sh,
ob,
+ obmat,
gpd,
gpl,
gp_style,
stl->storage->shgroup_id,
cache_ob->shading_type);
+ /* Disable stencil for this type */
+ DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
+
if ((do_onion) || (elm->onion == false)) {
- DRW_shgroup_call_range_obmat(shgrp, cache->b_fill.batch, obmat, start_fill, len);
+ DRW_shgroup_call_range(shgrp, cache->b_fill.batch, start_fill, len);
}
stl->storage->shgroup_id++;
start_fill = elm->vertex_idx;
-
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- /* set stencil mask id as not used */
- DRW_shgroup_stencil_mask(shgrp, 0x0);
break;
}
case eGpencilBatchGroupType_Edit: {
if (stl->g_data->shgrps_edit_point) {
const int len = elm->vertex_idx - start_edit;
+
+ shgrp = DRW_shgroup_create_sub(stl->g_data->shgrps_edit_point);
+ DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", obmat);
/* use always the same group */
- DRW_shgroup_call_range_obmat(
- stl->g_data->shgrps_edit_point, cache->b_edit.batch, obmat, start_edit, len);
+ DRW_shgroup_call_range(
+ stl->g_data->shgrps_edit_point, cache->b_edit.batch, start_edit, len);
start_edit = elm->vertex_idx;
}
@@ -1761,9 +1950,12 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
case eGpencilBatchGroupType_Edlin: {
if (stl->g_data->shgrps_edit_line) {
const int len = elm->vertex_idx - start_edlin;
+
+ shgrp = DRW_shgroup_create_sub(stl->g_data->shgrps_edit_line);
+ DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", obmat);
/* use always the same group */
- DRW_shgroup_call_range_obmat(
- stl->g_data->shgrps_edit_line, cache->b_edlin.batch, obmat, start_edlin, len);
+ DRW_shgroup_call_range(
+ stl->g_data->shgrps_edit_line, cache->b_edlin.batch, start_edlin, len);
start_edlin = elm->vertex_idx;
}
@@ -1803,6 +1995,7 @@ void gpencil_populate_multiedit(GPENCIL_e_data *e_data,
GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph);
GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval);
@@ -1818,45 +2011,29 @@ void gpencil_populate_multiedit(GPENCIL_e_data *e_data,
if (gpl->flag & GP_LAYER_HIDE) {
continue;
}
+ const float alpha = GPENCIL_SIMPLIFY_TINT(scene, playing) ? 0.0f : gpl->tintcolor[3];
+ const float tintcolor[4] = {gpl->tintcolor[0], gpl->tintcolor[1], gpl->tintcolor[2], alpha};
/* list of frames to draw */
if (!playing) {
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
- gpencil_draw_strokes(cache,
- e_data,
- vedata,
- ob,
- gpd,
- gpl,
- gpf,
- gpl->opacity,
- gpl->tintcolor,
- false,
- cache_ob);
+ gpencil_draw_strokes(
+ cache, e_data, vedata, ob, gpd, gpl, gpf, gpl->opacity, tintcolor, false, cache_ob);
}
}
}
else {
gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
if (gpf) {
- gpencil_draw_strokes(cache,
- e_data,
- vedata,
- ob,
- gpd,
- gpl,
- gpf,
- gpl->opacity,
- gpl->tintcolor,
- false,
- cache_ob);
+ gpencil_draw_strokes(
+ cache, e_data, vedata, ob, gpd, gpl, gpf, gpl->opacity, tintcolor, false, cache_ob);
}
}
}
/* create batchs and shading groups */
- gpencil_create_batches(cache);
+ gpencil_batches_ensure(cache);
gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
cache->is_dirty = false;
@@ -1873,23 +2050,36 @@ void gpencil_populate_datablock(GPENCIL_e_data *e_data,
const ViewLayer *view_layer = DEG_get_evaluated_view_layer(draw_ctx->depsgraph);
Scene *scene = draw_ctx->scene;
+ /* TODO: Review why is needed this recalc when render cycles + GP object in background.
+ * We need these lines to keep running the background render, but asap we get an alternative
+ * solution, we must remove it and keep all logic inside gpencil_modifier module. (antoniov)
+ */
+ if (ob->runtime.gpencil_tot_layers == 0) {
+ BKE_gpencil_modifiers_calc(draw_ctx->depsgraph, draw_ctx->scene, ob);
+ }
+
/* Use original data to shared in edit/transform operators */
bGPdata *gpd_eval = (bGPdata *)ob->data;
bGPdata *gpd = (bGPdata *)DEG_get_original_id(&gpd_eval->id);
+ const bool main_onion = draw_ctx->v3d != NULL ?
+ (draw_ctx->v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) :
+ true;
+ const bool playing = stl->storage->is_playing;
+ const bool overlay = draw_ctx->v3d != NULL ?
+ (bool)((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) :
+ true;
+ const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay &&
+ main_onion && !playing && gpencil_onion_active(gpd);
+
View3D *v3d = draw_ctx->v3d;
int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph);
bGPDframe *gpf_eval = NULL;
- const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) : true;
const bool time_remap = BKE_gpencil_has_time_modifiers(ob);
float opacity;
bGPDframe *gpf = NULL;
- bGPDlayer *gpl_active = BKE_gpencil_layer_getactive(gpd);
-
- /* check if playing animation */
- const bool playing = stl->storage->is_playing;
GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval);
@@ -1942,12 +2132,6 @@ void gpencil_populate_datablock(GPENCIL_e_data *e_data,
(v3d->overlay.flag & V3D_OVERLAY_BONE_SELECT)) {
opacity = opacity * v3d->overlay.xray_alpha_bone;
}
- /* fade no active layers */
- if ((overlay) && (draw_ctx->object_mode == OB_MODE_PAINT_GPENCIL) &&
- (v3d->gp_flag & V3D_GP_FADE_NOACTIVE_LAYERS) && (draw_ctx->obact) &&
- (draw_ctx->obact == ob) && (gpl != gpl_active)) {
- opacity = opacity * v3d->overlay.gpencil_fade_layer;
- }
/* Get evaluated frames array data */
int idx_eval = BLI_findindex(&gpd->layers, gpl);
@@ -1955,7 +2139,7 @@ void gpencil_populate_datablock(GPENCIL_e_data *e_data,
/* draw onion skins */
if (!ID_IS_LINKED(&gpd->id)) {
- if ((gpl->onion_flag & GP_LAYER_ONIONSKIN) &&
+ if ((do_onion) && (gpl->onion_flag & GP_LAYER_ONIONSKIN) &&
((!playing) || (gpd->onion_flag & GP_ONION_GHOST_ALWAYS)) && (!cache_ob->is_dup_ob) &&
(gpd->id.us <= 1)) {
if ((!stl->storage->is_render) ||
@@ -1965,12 +2149,14 @@ void gpencil_populate_datablock(GPENCIL_e_data *e_data,
}
}
/* draw normal strokes */
+ const float alpha = GPENCIL_SIMPLIFY_TINT(scene, playing) ? 0.0f : gpl->tintcolor[3];
+ const float tintcolor[4] = {gpl->tintcolor[0], gpl->tintcolor[1], gpl->tintcolor[2], alpha};
gpencil_draw_strokes(
- cache, e_data, vedata, ob, gpd, gpl, gpf_eval, opacity, gpl->tintcolor, false, cache_ob);
+ cache, e_data, vedata, ob, gpd, gpl, gpf_eval, opacity, tintcolor, false, cache_ob);
}
/* create batchs and shading groups */
- gpencil_create_batches(cache);
+ gpencil_batches_ensure(cache);
gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
cache->is_dirty = false;
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index aa5918feaa8..7d9f2d1fdf3 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -62,6 +62,8 @@ extern char datatoc_gpencil_edit_point_frag_glsl[];
extern char datatoc_gpencil_blend_frag_glsl[];
extern char datatoc_gpencil_merge_depth_frag_glsl[];
+extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
+
extern char datatoc_common_colormanagement_lib_glsl[];
extern char datatoc_common_view_lib_glsl[];
@@ -112,7 +114,7 @@ static void GPENCIL_create_framebuffers(void *vedata)
const float *viewport_size = DRW_viewport_size_get();
const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
- /* create multiframe framebuffer for AA */
+ /* create multisample framebuffer for AA */
if ((stl->storage->framebuffer_flag & GP_FRAMEBUFFER_MULTISAMPLE) &&
(stl->storage->multisamples > 0)) {
gpencil_multisample_ensure(vedata, size[0], size[1]);
@@ -177,6 +179,12 @@ static void GPENCIL_create_framebuffers(void *vedata)
static void GPENCIL_create_shaders(void)
{
+ /* blank texture used if no texture defined for fill shader */
+ if (!e_data.gpencil_blank_texture) {
+ float rect[1][1][4] = {{{0.0f}}};
+ e_data.gpencil_blank_texture = DRW_texture_create_2d(
+ 1, 1, GPU_RGBA8, DRW_TEX_FILTER, (float *)rect);
+ }
/* normal fill shader */
if (!e_data.gpencil_fill_sh) {
e_data.gpencil_fill_sh = GPU_shader_create_from_arrays({
@@ -222,7 +230,12 @@ static void GPENCIL_create_shaders(void)
/* used for edit lines for edit modes */
if (!e_data.gpencil_line_sh) {
- e_data.gpencil_line_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_FLAT_COLOR);
+ e_data.gpencil_line_sh = DRW_shader_create_with_lib(
+ datatoc_gpencil_edit_point_vert_glsl,
+ NULL,
+ datatoc_gpu_shader_3D_smooth_color_frag_glsl,
+ datatoc_common_view_lib_glsl,
+ NULL);
}
/* used to filling during drawing */
@@ -283,6 +296,7 @@ static void GPENCIL_engine_free(void)
DRW_SHADER_FREE_SAFE(e_data.gpencil_stroke_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_point_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_edit_point_sh);
+ DRW_SHADER_FREE_SAFE(e_data.gpencil_line_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_fullscreen_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_simple_fullscreen_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_blend_fullscreen_sh);
@@ -290,6 +304,8 @@ static void GPENCIL_engine_free(void)
DRW_SHADER_FREE_SAFE(e_data.gpencil_background_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_paper_sh);
+ DRW_TEXTURE_FREE_SAFE(e_data.gpencil_blank_texture);
+
/* effects */
GPENCIL_delete_fx_shaders(&e_data);
}
@@ -335,17 +351,11 @@ void GPENCIL_cache_init(void *vedata)
stl->g_data->shgrps_edit_point = NULL;
/* reset textures */
- stl->g_data->gpencil_blank_texture = NULL;
stl->g_data->batch_buffer_stroke = NULL;
stl->g_data->batch_buffer_fill = NULL;
stl->g_data->batch_buffer_ctrlpoint = NULL;
stl->g_data->batch_grid = NULL;
- /* blank texture used if no texture defined for fill shader */
- float rect[1][1][4] = {{{0.0f}}};
- stl->g_data->gpencil_blank_texture = DRW_texture_create_2d(
- 1, 1, GPU_RGBA8, DRW_TEX_FILTER, (float *)rect);
-
if (!stl->shgroups) {
/* Alloc maximum size because count strokes is very slow and can be very complex due onion
* skinning.
@@ -799,8 +809,6 @@ void DRW_gpencil_free_runtime_data(void *ved)
GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
/* free gpu data */
- DRW_TEXTURE_FREE_SAFE(stl->g_data->gpencil_blank_texture);
-
GPU_BATCH_DISCARD_SAFE(stl->g_data->batch_buffer_stroke);
MEM_SAFE_FREE(stl->g_data->batch_buffer_stroke);
@@ -847,66 +855,18 @@ static void gpencil_draw_pass_range(GPENCIL_StorageList *stl,
return;
}
- DRWShadingGroup *shgrp = init_shgrp;
- DRWShadingGroup *from_shgrp = init_shgrp;
- DRWShadingGroup *to_shgrp = init_shgrp;
- int stencil_tot = 0;
- bool do_last = true;
-
- /* Loop all shading groups to separate by stencil groups. */
- while ((shgrp) && (shgrp != end_shgrp)) {
- do_last = true;
- /* Count number of groups using stencil. */
- if (DRW_shgroup_stencil_mask_get(shgrp) != 0) {
- stencil_tot++;
- }
+ const bool do_antialiasing = ((!stl->storage->is_mat_preview) && (multi));
- /* Draw stencil group and clear stencil bit. This is required because the number of
- * shading groups can be greater than the limit of 255 stencil values.
- * Only count as stencil if the shading group has an stencil value assigned. This reduces
- * the number of clears because Dots, Fills and some Line strokes don't need stencil.
- */
- if (stencil_tot == 255) {
- DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d :
- psl->stroke_pass_2d,
- from_shgrp,
- to_shgrp);
- /* Clear Stencil and prepare for next group. */
- GPU_framebuffer_clear_stencil(fb, 0x0);
-
- /* Set new init group and reset. */
- do_last = false;
-
- shgrp = DRW_shgroup_get_next(shgrp);
- if (shgrp) {
- from_shgrp = to_shgrp = shgrp;
- stencil_tot = 0;
- if (shgrp != end_shgrp) {
- continue;
- }
- else {
- do_last = true;
- break;
- }
- }
- else {
- /* No more groups. */
- break;
- }
- }
-
- /* Still below stencil group limit. */
- shgrp = DRW_shgroup_get_next(shgrp);
- if (shgrp) {
- to_shgrp = shgrp;
- }
+ if (do_antialiasing) {
+ MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl);
}
- /* Draw last pending groups. */
- if (do_last) {
- DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d : psl->stroke_pass_2d,
- from_shgrp,
- to_shgrp);
+ DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d : psl->stroke_pass_2d,
+ init_shgrp,
+ end_shgrp);
+
+ if (do_antialiasing) {
+ MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fb, txl);
}
}
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index f723bd16634..c475c343d22 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -147,6 +147,7 @@ typedef struct GPENCIL_Storage {
bool is_mat_preview;
bool background_ready;
int is_xray;
+ bool is_ontop;
bool reset_cache;
const float *pixsize;
float render_pixsize;
@@ -267,9 +268,6 @@ typedef struct g_data {
/* grid geometry */
GPUBatch *batch_grid;
- /* textures */
- struct GPUTexture *gpencil_blank_texture;
-
/* runtime pointers texture */
struct GPUTexture *input_depth_tx;
struct GPUTexture *input_color_tx;
@@ -299,6 +297,9 @@ typedef enum eGPsession_Flag {
} eGPsession_Flag;
typedef struct GPENCIL_e_data {
+ /* textures */
+ struct GPUTexture *gpencil_blank_texture;
+
/* general drawing shaders */
struct GPUShader *gpencil_fill_sh;
struct GPUShader *gpencil_stroke_sh;
@@ -389,10 +390,12 @@ typedef struct GpencilBatchCache {
} GpencilBatchCache;
/* general drawing functions */
-struct DRWShadingGroup *gpencil_shgroup_stroke_create(struct GPENCIL_Data *vedata,
+struct DRWShadingGroup *gpencil_shgroup_stroke_create(struct GPENCIL_e_data *e_data,
+ struct GPENCIL_Data *vedata,
struct DRWPass *pass,
struct GPUShader *shader,
struct Object *ob,
+ float (*obmat)[4],
struct bGPdata *gpd,
struct bGPDlayer *gpl,
struct bGPDstroke *gps,
diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c
index 56ba90067cf..f1d704a72a3 100644
--- a/source/blender/draw/engines/gpencil/gpencil_render.c
+++ b/source/blender/draw/engines/gpencil/gpencil_render.c
@@ -73,7 +73,7 @@ void GPENCIL_render_init(GPENCIL_Data *ved, RenderEngine *engine, struct Depsgra
* because there is no viewport. So we need to manually create one
* NOTE : use 32 bit format for precision in render mode.
*/
- /* create multiframe framebuffer for AA */
+ /* create multisample framebuffer for AA */
if (U.gpencil_multisamples > 0) {
int rect_w = (int)viewport_size[0];
int rect_h = (int)viewport_size[1];
@@ -131,7 +131,7 @@ static void GPENCIL_render_cache(void *vedata,
/* TODO: Reuse Eevee code in shared module instead to duplicate here */
static void GPENCIL_render_update_viewvecs(float invproj[4][4],
- float winmat[4][4],
+ const float winmat[4][4],
float (*r_viewvecs)[4])
{
/* view vectors for the corners of the view frustum.
@@ -308,6 +308,9 @@ void GPENCIL_render_to_image(void *vedata,
DRW_render_object_iter(vedata, engine, draw_ctx->depsgraph, GPENCIL_render_cache);
GPENCIL_cache_finish(vedata);
+
+ DRW_render_instance_buffer_finish();
+
GPENCIL_draw_scene(vedata);
/* combined data */
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl
index a1cfb2ae4ae..f75322f90e2 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl
@@ -1,4 +1,6 @@
+uniform mat4 gpModelMatrix;
+
in vec3 pos;
in vec4 color;
in float size;
@@ -8,7 +10,7 @@ out float finalThickness;
void main()
{
- gl_Position = point_object_to_ndc(pos);
+ gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
finalColor = color;
finalThickness = size;
}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
index 64bb70f2a3f..0c290260b20 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
@@ -26,6 +26,12 @@ uniform int viewport_xray;
uniform int shading_type[2];
uniform vec4 wire_color;
+uniform int fade_layer;
+uniform float fade_layer_factor;
+uniform bool fade_ob;
+uniform vec3 fade_color;
+uniform float fade_ob_factor;
+
/* keep this list synchronized with list in gpencil_draw_utils.c */
#define SOLID 0
#define GRADIENT 1
@@ -211,4 +217,16 @@ void main()
fragColor.a *= 0.5;
}
}
+ /* Apply paper opacity */
+ if (fade_layer == 1) {
+ /* Layer is below, mix with background. */
+ fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_layer_factor);
+ }
+ else if (fade_layer == 2) {
+ /* Layer is above, change opacity. */
+ fragColor.a *= fade_layer_factor;
+ }
+ else if (fade_ob == true) {
+ fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_ob_factor);
+ }
}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl
index eb452f4c660..263dc570423 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl
@@ -1,4 +1,6 @@
+uniform mat4 gpModelMatrix;
+
in vec3 pos;
in vec4 color;
in vec2 texCoord;
@@ -8,7 +10,7 @@ out vec2 texCoord_interp;
void main(void)
{
- gl_Position = point_object_to_ndc(pos);
+ gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
finalColor = color;
texCoord_interp = texCoord;
}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl
index 34777018a73..d79b8fb4d8a 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl
@@ -14,6 +14,12 @@ in vec4 mColor;
in vec2 mTexCoord;
out vec4 fragColor;
+uniform int fade_layer;
+uniform float fade_layer_factor;
+uniform bool fade_ob;
+uniform vec3 fade_color;
+uniform float fade_ob_factor;
+
#define texture2D texture
#define GPENCIL_MODE_LINE 0
@@ -104,4 +110,17 @@ void main()
if (fragColor.a < 0.0035) {
discard;
}
+
+ /* Apply paper opacity */
+ if (fade_layer == 1) {
+ /* Layer is below, mix with background. */
+ fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_layer_factor);
+ }
+ else if (fade_layer == 2) {
+ /* Layer is above, change opacity. */
+ fragColor.a *= fade_layer_factor;
+ }
+ else if (fade_ob == true) {
+ fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_ob_factor);
+ }
}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
index ef8b361373f..87963c66858 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
@@ -6,6 +6,7 @@ uniform float pixfactor;
uniform int viewport_xray;
uniform int shading_type[2];
uniform vec4 wire_color;
+uniform mat4 gpModelMatrix;
in vec3 pos;
in vec4 color;
@@ -30,8 +31,8 @@ float defaultpixsize = pixsize * (1000.0 / pixfactor);
void main()
{
- gl_Position = point_object_to_ndc(pos);
- finalprev_pos = point_object_to_ndc(prev_pos);
+ gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
+ finalprev_pos = point_world_to_ndc((gpModelMatrix * vec4(prev_pos, 1.0)).xyz);
finalColor = color;
if (keep_size == TRUE) {
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl
index 73baacb35d4..0f1665b73c2 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl
@@ -8,6 +8,12 @@ uniform vec4 colormix;
uniform float mix_stroke_factor;
uniform int shading_type[2];
+uniform int fade_layer;
+uniform float fade_layer_factor;
+uniform bool fade_ob;
+uniform vec3 fade_color;
+uniform float fade_ob_factor;
+
in vec4 mColor;
in vec2 mTexCoord;
in vec2 uvfac;
@@ -88,4 +94,17 @@ void main()
if (fragColor.a < 0.0035) {
discard;
}
+
+ /* Apply paper opacity */
+ if (fade_layer == 1) {
+ /* Layer is below, mix with background. */
+ fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_layer_factor);
+ }
+ else if (fade_layer == 2) {
+ /* Layer is above, change opacity. */
+ fragColor.a *= fade_layer_factor;
+ }
+ else if (fade_ob == true) {
+ fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_ob_factor);
+ }
}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
index c7089f357f9..582b9a7f249 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
@@ -6,6 +6,7 @@ uniform float pixfactor;
uniform int viewport_xray;
uniform int shading_type[2];
uniform vec4 wire_color;
+uniform mat4 gpModelMatrix;
in vec3 pos;
in vec4 color;
@@ -28,7 +29,7 @@ float defaultpixsize = pixsize * (1000.0 / pixfactor);
void main(void)
{
- gl_Position = point_object_to_ndc(pos);
+ gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
finalColor = color;
if (keep_size == TRUE) {
diff --git a/source/blender/draw/engines/select/select_draw_utils.c b/source/blender/draw/engines/select/select_draw_utils.c
index ec47d6ea8eb..f1d008c29c7 100644
--- a/source/blender/draw/engines/select/select_draw_utils.c
+++ b/source/blender/draw/engines/select/select_draw_utils.c
@@ -49,8 +49,7 @@ void select_id_object_min_max(Object *obj, float r_min[3], float r_max[3])
BoundBox *bb;
BMEditMesh *em = BKE_editmesh_from_object(obj);
if (em) {
- /* Use Object Texture Space. */
- bb = BKE_mesh_texspace_get(em->mesh_eval_cage, NULL, NULL, NULL);
+ bb = BKE_editmesh_cage_boundbox_get(em);
}
else {
bb = BKE_object_boundbox_get(obj);
@@ -63,12 +62,18 @@ short select_id_get_object_select_mode(Scene *scene, Object *ob)
{
short r_select_mode = 0;
if (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT)) {
+ /* In order to sample flat colors for vertex weights / texture-paint / vertex-paint
+ * we need to be in SCE_SELECT_FACE mode so select_cache_init() correctly sets up
+ * a shgroup with select_id_flat.
+ * Note this is not working correctly for vertex-paint (yet), but has been discussed
+ * in T66645 and there is a solution by @mano-wii in P1032.
+ * So OB_MODE_VERTEX_PAINT is already included here [required for P1032 I guess]. */
Mesh *me_orig = DEG_get_original_object(ob)->data;
- if (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL) {
- r_select_mode = SCE_SELECT_FACE;
- }
if (me_orig->editflag & ME_EDIT_PAINT_VERT_SEL) {
- r_select_mode |= SCE_SELECT_VERTEX;
+ r_select_mode = SCE_SELECT_VERTEX;
+ }
+ else {
+ r_select_mode = SCE_SELECT_FACE;
}
}
else {
@@ -123,7 +128,11 @@ static void draw_select_id_edit_mesh(SELECTID_StorageList *stl,
}
else {
if (ob->dt >= OB_SOLID) {
+#ifdef USE_CAGE_OCCLUSION
+ struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me);
+#else
struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_surface(me);
+#endif
DRWShadingGroup *face_shgrp = stl->g_data->shgrp_face_unif;
DRW_shgroup_call_no_cull(face_shgrp, geom_faces, ob);
}
diff --git a/source/blender/draw/engines/select/select_engine.c b/source/blender/draw/engines/select/select_engine.c
index 5dc20a589f0..abfa57dd218 100644
--- a/source/blender/draw/engines/select/select_engine.c
+++ b/source/blender/draw/engines/select/select_engine.c
@@ -252,7 +252,11 @@ static void select_cache_populate(void *vedata, Object *ob)
DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_faces, ob->obmat);
}
else if (ob->dt >= OB_SOLID) {
+#ifdef USE_CAGE_OCCLUSION
+ struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me);
+#else
struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_surface(me);
+#endif
DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_faces, ob->obmat);
}
diff --git a/source/blender/draw/engines/select/select_private.h b/source/blender/draw/engines/select/select_private.h
index 642cd6ffc56..1e99a49252e 100644
--- a/source/blender/draw/engines/select/select_private.h
+++ b/source/blender/draw/engines/select/select_private.h
@@ -23,6 +23,8 @@
#ifndef __SELECT_PRIVATE_H__
#define __SELECT_PRIVATE_H__
+#define USE_CAGE_OCCLUSION
+
#include "DRW_render.h"
/* GPUViewport.storage
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl
index a1f80440404..fd4cea4279a 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl
@@ -5,7 +5,8 @@ uniform sampler2D materialBuffer;
uniform sampler2D normalBuffer;
/* normalBuffer contains viewport normals */
uniform sampler2D cavityBuffer;
-uniform sampler2D matcapImage;
+uniform sampler2D matcapDiffuseImage;
+uniform sampler2D matcapSpecularImage;
uniform vec2 invertedViewportSize;
uniform vec4 viewvecs[3];
@@ -55,8 +56,15 @@ void main()
normal_viewport = (metallic > 0.0) ? normal_viewport : -normal_viewport;
bool flipped = world_data.matcap_orientation != 0;
vec2 matcap_uv = matcap_uv_compute(I_vs, normal_viewport, flipped);
- vec3 matcap = textureLod(matcapImage, matcap_uv, 0.0).rgb;
- vec3 shaded_color = matcap * base_color;
+ vec3 matcap_diffuse = textureLod(matcapDiffuseImage, matcap_uv, 0.0).rgb;
+
+# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
+ vec3 matcap_specular = textureLod(matcapSpecularImage, matcap_uv, 0.0).rgb;
+# else
+ vec3 matcap_specular = vec3(0.0);
+# endif
+
+ vec3 shaded_color = matcap_diffuse * base_color + matcap_specular;
#elif defined(V3D_LIGHTING_STUDIO)
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
index 0428b0d408c..bd16189db32 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
@@ -256,7 +256,7 @@ void main()
float coc = decode_coc(texelFetch(inputCocTex, texel, 0).rg);
float max_radius = coc;
vec2 noise = get_random_vector(noiseOffset) * 0.2 * clamp(max_radius * 0.2 - 4.0, 0.0, 1.0);
- for (int i = 0; i < NUM_SAMPLES; ++i) {
+ for (int i = 0; i < NUM_SAMPLES; i++) {
vec2 tc = uv + (noise + samples[i].xy) * invertedViewportSize * max_radius;
/* decode_signed_coc return biggest coc. */
@@ -359,8 +359,8 @@ void main()
vec v[9];
/* Add the pixels which make up our window to the pixel array. */
- for (int dX = -1; dX <= 1; ++dX) {
- for (int dY = -1; dY <= 1; ++dY) {
+ for (int dX = -1; dX <= 1; dX++) {
+ for (int dY = -1; dY <= 1; dY++) {
vec2 offset = vec2(float(dX), float(dY));
/* If a pixel in the window is located at (x+dX, y+dY), put it at index (dX + R)(2R + 1) +
* (dY + R) of the pixel array. This will fill the pixel array, with the top left pixel of
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl
index 505b4822ad6..abd8c1f6579 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl
@@ -1,5 +1,6 @@
-uniform int object_id = 0;
+
layout(location = 0) out uint objectId;
+
uniform float ImageTransparencyCutoff = 0.1;
#ifdef V3D_SHADING_TEXTURE_COLOR
uniform sampler2D image;
@@ -10,11 +11,10 @@ in vec2 uv_interp;
void main()
{
#ifdef V3D_SHADING_TEXTURE_COLOR
- vec4 diffuse_color = texture(image, uv_interp);
- if (diffuse_color.a < ImageTransparencyCutoff) {
+ if (texture(image, uv_interp).a < ImageTransparencyCutoff) {
discard;
}
#endif
- objectId = uint(object_id);
+ objectId = uint(resource_id + 1) & 0xFFu;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
index c78b2182d04..f799ce41cb2 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
@@ -8,8 +8,7 @@ uniform float alpha = 0.5;
uniform vec2 invertedViewportSize;
uniform vec4 viewvecs[3];
-uniform vec3 materialDiffuseColor;
-uniform vec3 materialSpecularColor;
+uniform vec4 materialColorAndMetal;
uniform float materialRoughness;
uniform float shadowMultiplier = 0.5;
@@ -27,7 +26,8 @@ in vec2 uv_interp;
in vec3 vertexColor;
#endif
#ifdef V3D_LIGHTING_MATCAP
-uniform sampler2D matcapImage;
+uniform sampler2D matcapDiffuseImage;
+uniform sampler2D matcapSpecularImage;
#endif
layout(std140) uniform world_block
@@ -41,17 +41,17 @@ layout(location = 1) out
void main()
{
- vec4 diffuse_color;
+ vec4 base_color;
#if defined(V3D_SHADING_TEXTURE_COLOR)
- diffuse_color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied);
- if (diffuse_color.a < ImageTransparencyCutoff) {
+ base_color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied);
+ if (base_color.a < ImageTransparencyCutoff) {
discard;
}
#elif defined(V3D_SHADING_VERTEX_COLOR)
- diffuse_color = vec4(vertexColor, 1.0);
+ base_color.rgb = vertexColor;
#else
- diffuse_color = vec4(materialDiffuseColor, 1.0);
+ base_color.rgb = materialColorAndMetal.rgb;
#endif /* V3D_SHADING_TEXTURE_COLOR */
vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize;
@@ -63,17 +63,31 @@ void main()
/* -------- SHADING --------- */
#ifdef V3D_LIGHTING_FLAT
- vec3 shaded_color = diffuse_color.rgb;
+ vec3 shaded_color = base_color.rgb;
#elif defined(V3D_LIGHTING_MATCAP)
bool flipped = world_data.matcap_orientation != 0;
vec2 matcap_uv = matcap_uv_compute(I_vs, nor, flipped);
- vec3 matcap = textureLod(matcapImage, matcap_uv, 0.0).rgb;
- vec3 shaded_color = matcap * diffuse_color.rgb;
+ vec3 matcap_diffuse = textureLod(matcapDiffuseImage, matcap_uv, 0.0).rgb;
+# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
+ vec3 matcap_specular = textureLod(matcapSpecularImage, matcap_uv, 0.0).rgb;
+# else
+ vec3 matcap_specular = vec3(0.0);
+# endif
+ vec3 shaded_color = matcap_diffuse * base_color.rgb + matcap_specular;
#elif defined(V3D_LIGHTING_STUDIO)
+# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
+ float metallic = materialColorAndMetal.a;
+ vec3 specular_color = mix(vec3(0.05), base_color.rgb, metallic);
+ vec3 diffuse_color = mix(base_color.rgb, vec3(0.0), metallic);
+# else
+ vec3 specular_color = vec3(0.0);
+ vec3 diffuse_color = base_color.rgb;
+# endif
+
vec3 shaded_color = get_world_lighting(
- world_data, diffuse_color.rgb, materialSpecularColor, materialRoughness, nor, I_vs);
+ world_data, diffuse_color, specular_color, materialRoughness, nor, I_vs);
#endif
#ifdef V3D_SHADING_SHADOW
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
index c673b2484de..b5f95f2dcf8 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
@@ -1,7 +1,5 @@
-uniform int object_id = 0;
-uniform vec3 materialDiffuseColor;
-uniform float materialMetallic;
+uniform vec4 materialColorAndMetal;
uniform float materialRoughness;
uniform sampler2D image;
@@ -48,7 +46,7 @@ void main()
# elif defined(V3D_SHADING_VERTEX_COLOR)
color.rgb = vertexColor;
# else
- color.rgb = materialDiffuseColor;
+ color.rgb = materialColorAndMetal.rgb;
# endif
# ifdef V3D_LIGHTING_MATCAP
@@ -56,7 +54,7 @@ void main()
metallic = float(gl_FrontFacing);
roughness = 0.0;
# else
- metallic = materialMetallic;
+ metallic = materialColorAndMetal.a;
roughness = materialRoughness;
# endif
@@ -64,7 +62,7 @@ void main()
/* Add some variation to the hairs to avoid uniform look. */
float hair_variation = hair_rand * 0.1;
color = clamp(color - hair_variation, 0.0, 1.0);
- metallic = clamp(materialMetallic - hair_variation, 0.0, 1.0);
+ metallic = clamp(materialColorAndMetal.a - hair_variation, 0.0, 1.0);
roughness = clamp(materialRoughness - hair_variation, 0.0, 1.0);
# endif
@@ -73,7 +71,7 @@ void main()
#endif /* MATDATA_PASS_ENABLED */
#ifdef OBJECT_ID_PASS_ENABLED
- objectId = uint(object_id);
+ objectId = uint(resource_id + 1) & 0xFFu;
#endif
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
index 7eb12dbdeb9..04dd9ab85bb 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
@@ -25,6 +25,10 @@ out vec2 uv_interp;
out vec3 vertexColor;
#endif
+#ifdef OBJECT_ID_PASS_ENABLED
+RESOURCE_ID_VARYING
+#endif
+
/* From http://libnoise.sourceforge.net/noisegen/index.html */
float integer_noise(int n)
{
@@ -91,12 +95,18 @@ void main()
#endif
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
- normal_viewport = normal_object_to_view(nor);
# ifndef HAIR_SHADER
+ normal_viewport = normal_object_to_view(nor);
normal_viewport = normalize(normal_viewport);
+# else
+ normal_viewport = normal_world_to_view(nor);
# endif
#endif
+#ifdef OBJECT_ID_PASS_ENABLED
+ PASS_RESOURCE_ID
+#endif
+
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
#endif
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
index fd06c85747f..c24c335189e 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
@@ -1,6 +1,4 @@
-uniform vec3 OrcoTexCoFactors[2];
-
uniform sampler2D depthBuffer;
uniform sampler3D densityTexture;
@@ -172,7 +170,7 @@ vec4 volume_integration(vec3 ray_ori, vec3 ray_dir, float ray_inc, float ray_max
float noise = fract(dither_mat[tx.x][tx.y] + noiseOfs);
float ray_len = noise * ray_inc;
- for (int i = 0; i < samplesLen && ray_len < ray_max; ++i, ray_len += ray_inc) {
+ for (int i = 0; i < samplesLen && ray_len < ray_max; i++, ray_len += ray_inc) {
vec3 ls_pos = ray_ori + ray_dir * ray_len;
vec3 Lscat;
@@ -216,13 +214,13 @@ void main()
vs_ray_dir /= abs(vs_ray_dir.z);
/* TODO(fclem) Precompute the matrix/ */
- vec3 ls_ray_dir = mat3(ViewMatrixInverse) * vs_ray_dir * OrcoTexCoFactors[1] * 2.0;
+ vec3 ls_ray_dir = mat3(ViewMatrixInverse) * vs_ray_dir * OrcoTexCoFactors[1].xyz * 2.0;
ls_ray_dir = mat3(ModelMatrixInverse) * ls_ray_dir;
vec3 ls_ray_ori = point_view_to_object(vs_ray_ori);
vec3 ls_ray_end = point_view_to_object(vs_ray_end);
- ls_ray_ori = (OrcoTexCoFactors[0] + ls_ray_ori * OrcoTexCoFactors[1]) * 2.0 - 1.0;
- ls_ray_end = (OrcoTexCoFactors[0] + ls_ray_end * OrcoTexCoFactors[1]) * 2.0 - 1.0;
+ ls_ray_ori = (OrcoTexCoFactors[0].xyz + ls_ray_ori * OrcoTexCoFactors[1].xyz) * 2.0 - 1.0;
+ ls_ray_end = (OrcoTexCoFactors[0].xyz + ls_ray_end * OrcoTexCoFactors[1].xyz) * 2.0 - 1.0;
/* TODO: Align rays to volume center so that it mimics old behaviour of slicing the volume. */
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
index 6f0bb56fafd..3542a1a91fc 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
@@ -1,10 +1,11 @@
-uniform vec3 OrcoTexCoFactors[2];
uniform float slicePosition;
uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */
in vec3 pos;
+RESOURCE_ID_VARYING
+
#ifdef VOLUME_SLICE
in vec3 uvs;
@@ -27,6 +28,8 @@ void main()
#else
vec3 final_pos = pos;
#endif
- final_pos = ((final_pos * 0.5 + 0.5) - OrcoTexCoFactors[0]) / OrcoTexCoFactors[1];
+ final_pos = ((final_pos * 0.5 + 0.5) - OrcoTexCoFactors[0].xyz) / OrcoTexCoFactors[1].xyz;
gl_Position = point_object_to_ndc(final_pos);
+
+ PASS_RESOURCE_ID
}
diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c
index add49462de1..15522ba0dfb 100644
--- a/source/blender/draw/engines/workbench/workbench_deferred.c
+++ b/source/blender/draw/engines/workbench/workbench_deferred.c
@@ -83,7 +83,6 @@ static struct {
struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */
SceneDisplay display; /* world light direction for shadows */
- int next_object_id;
struct GPUUniformBuffer *sampling_ubo;
struct GPUTexture *jitter_tx;
@@ -147,6 +146,7 @@ static char *workbench_build_prepass_frag(void)
{
DynStr *ds = BLI_dynstr_new();
+ BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl);
BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
BLI_dynstr_append(ds, datatoc_workbench_prepass_frag_glsl);
@@ -330,7 +330,6 @@ static struct GPUTexture *create_jitter_texture(int num_samples)
static void workbench_init_object_data(DrawData *dd)
{
WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd;
- data->object_id = ((e_data.next_object_id++) & 0xff) + 1;
data->shadow_bbox_dirty = true;
}
@@ -379,11 +378,10 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
workbench_effect_info_init(stl->effects);
}
- if (!e_data.next_object_id) {
+ if (!e_data.shadow_pass_sh) {
WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
memset(sh_data->prepass_sh_cache, 0, sizeof(sh_data->prepass_sh_cache));
memset(e_data.composite_sh_cache, 0, sizeof(e_data.composite_sh_cache));
- e_data.next_object_id = 1;
#ifdef DEBUG_SHADOW_VOLUME
const char *shadow_frag = datatoc_workbench_shadow_debug_frag_glsl;
#else
@@ -652,7 +650,7 @@ void workbench_deferred_engine_free(void)
for (int index = 0; index < MAX_COMPOSITE_SHADERS; index++) {
DRW_SHADER_FREE_SAFE(e_data.composite_sh_cache[index]);
}
- for (int index = 0; index < MAX_CAVITY_SHADERS; ++index) {
+ for (int index = 0; index < MAX_CAVITY_SHADERS; index++) {
DRW_SHADER_FREE_SAFE(e_data.cavity_sh[index]);
}
DRW_SHADER_FREE_SAFE(e_data.ghost_resolve_sh);
@@ -694,16 +692,22 @@ static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingG
if (CAVITY_ENABLED(wpd)) {
DRW_shgroup_uniform_texture_ref(grp, "cavityBuffer", &e_data.cavity_buffer_tx);
}
- if (SPECULAR_HIGHLIGHT_ENABLED(wpd) || STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
+ if (workbench_is_specular_highlight_enabled(wpd) || STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
}
- if (SPECULAR_HIGHLIGHT_ENABLED(wpd) || STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
+ if (workbench_is_specular_highlight_enabled(wpd) || STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
}
if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
- BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE);
+ BKE_studiolight_ensure_flag(wpd->studio_light,
+ STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE |
+ STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE);
DRW_shgroup_uniform_texture(
- grp, "matcapImage", wpd->studio_light->equirect_radiance_gputexture);
+ grp, "matcapDiffuseImage", wpd->studio_light->matcap_diffuse.gputexture);
+ if (workbench_is_specular_highlight_enabled(wpd)) {
+ DRW_shgroup_uniform_texture(
+ grp, "matcapSpecularImage", wpd->studio_light->matcap_specular.gputexture);
+ }
}
}
@@ -862,18 +866,11 @@ static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedat
WORKBENCH_PassList *psl = vedata->psl;
WORKBENCH_PrivateData *wpd = stl->g_data;
WORKBENCH_MaterialData *material;
- WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure(
- &ob->id,
- &draw_engine_workbench_solid,
- sizeof(WORKBENCH_ObjectData),
- &workbench_init_object_data,
- NULL);
WORKBENCH_MaterialData material_template;
const bool is_ghost = (ob->dtx & OB_DRAWXRAY);
/* Solid */
workbench_material_update_data(wpd, ob, mat, &material_template, color_type);
- material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1;
material_template.color_type = color_type;
material_template.ima = ima;
material_template.iuser = iuser;
@@ -893,8 +890,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedat
shader, (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_pass : psl->prepass_pass);
workbench_material_copy(material, &material_template);
DRW_shgroup_stencil_mask(material->shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF);
- DRW_shgroup_uniform_int(material->shgrp, "object_id", &material->object_id, 1);
- workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob, true, true, interp);
+ workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob, true, interp);
BLI_ghash_insert(wpd->material_hash, POINTER_FROM_UINT(hash), material);
}
return material;
@@ -937,8 +933,7 @@ static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *o
(ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_hair_pass : psl->prepass_hair_pass,
shader);
DRW_shgroup_stencil_mask(shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF);
- DRW_shgroup_uniform_int(shgrp, "object_id", &material->object_id, 1);
- workbench_material_shgroup_uniform(wpd, shgrp, material, ob, true, true, interp);
+ workbench_material_shgroup_uniform(wpd, shgrp, material, ob, true, interp);
}
}
}
@@ -950,7 +945,8 @@ static void workbench_cache_populate_texture_paint_mode(WORKBENCH_Data *vedata,
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+ const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
WORKBENCH_MaterialData *material;
/* Force workbench to render active object textured when in texture paint mode */
@@ -1099,7 +1095,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
if (use_sculpt_pbvh) {
struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len);
- for (int i = 0; i < materials_len; ++i) {
+ for (int i = 0; i < materials_len; i++) {
struct Material *mat = give_current_material(ob, i + 1);
if (mat != NULL && mat->a < 1.0f) {
material = workbench_forward_get_or_create_material_data(
@@ -1121,7 +1117,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
geoms = DRW_cache_object_surface_material_get(
ob, gpumat_array, materials_len, NULL, NULL, NULL);
- for (int i = 0; i < materials_len; ++i) {
+ for (int i = 0; i < materials_len; i++) {
if (geoms != NULL && geoms[i] != NULL) {
Material *mat = give_current_material(ob, i + 1);
if (mat != NULL && mat->a < 1.0f) {
diff --git a/source/blender/draw/engines/workbench/workbench_effect_dof.c b/source/blender/draw/engines/workbench/workbench_effect_dof.c
index 22840a2a756..169b91a6474 100644
--- a/source/blender/draw/engines/workbench/workbench_effect_dof.c
+++ b/source/blender/draw/engines/workbench/workbench_effect_dof.c
@@ -94,9 +94,9 @@ static void workbench_dof_setup_samples(struct GPUUniformBuffer **ubo,
}
float *samp = *data;
- for (int i = 0; i <= KERNEL_RAD; ++i) {
- for (int j = -KERNEL_RAD; j <= KERNEL_RAD; ++j) {
- for (int k = -KERNEL_RAD; k <= KERNEL_RAD; ++k) {
+ for (int i = 0; i <= KERNEL_RAD; i++) {
+ for (int j = -KERNEL_RAD; j <= KERNEL_RAD; j++) {
+ for (int k = -KERNEL_RAD; k <= KERNEL_RAD; k++) {
if (abs(j) > i || abs(k) > i) {
continue;
}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_taa.c b/source/blender/draw/engines/workbench/workbench_effect_taa.c
index 06442060623..772d859392b 100644
--- a/source/blender/draw/engines/workbench/workbench_effect_taa.c
+++ b/source/blender/draw/engines/workbench/workbench_effect_taa.c
@@ -139,7 +139,7 @@ void workbench_taa_engine_init(WORKBENCH_Data *vedata)
/* reset complete drawing when navigating. */
if (effect_info->jitter_index != 0) {
- if (rv3d && rv3d->rflag & RV3D_NAVIGATING) {
+ if (rv3d && rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING)) {
effect_info->jitter_index = 0;
}
}
diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c
index 4c1fce550e8..d731b167c06 100644
--- a/source/blender/draw/engines/workbench/workbench_forward.c
+++ b/source/blender/draw/engines/workbench/workbench_forward.c
@@ -63,8 +63,6 @@ static struct {
struct GPUTexture *transparent_accum_tx; /* ref only, not alloced */
struct GPUTexture *transparent_revealage_tx; /* ref only, not alloced */
struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */
-
- int next_object_id;
} e_data = {{{{NULL}}}};
/* Shaders */
@@ -98,6 +96,18 @@ static char *workbench_build_forward_vert(bool is_hair)
return str;
}
+static char *workbench_build_forward_outline_frag(void)
+{
+ DynStr *ds = BLI_dynstr_new();
+
+ BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_forward_depth_frag_glsl);
+
+ char *str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ return str;
+}
+
static char *workbench_build_forward_transparent_accum_frag(void)
{
DynStr *ds = BLI_dynstr_new();
@@ -129,12 +139,6 @@ static char *workbench_build_forward_composite_frag(void)
return str;
}
-static void workbench_init_object_data(DrawData *dd)
-{
- WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd;
- data->object_id = ((e_data.next_object_id++) & 0xff) + 1;
-}
-
WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_Data *vedata,
Object *ob,
Material *mat,
@@ -149,18 +153,11 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_
WORKBENCH_PassList *psl = vedata->psl;
WORKBENCH_PrivateData *wpd = stl->g_data;
WORKBENCH_MaterialData *material;
- WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure(
- &ob->id,
- &draw_engine_workbench_solid,
- sizeof(WORKBENCH_ObjectData),
- &workbench_init_object_data,
- NULL);
WORKBENCH_MaterialData material_template;
DRWShadingGroup *grp;
/* Solid */
workbench_material_update_data(wpd, ob, mat, &material_template, color_type);
- material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1;
material_template.color_type = color_type;
material_template.ima = ima;
material_template.iuser = iuser;
@@ -186,11 +183,17 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_
DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
workbench_material_copy(material, &material_template);
if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
- BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE);
+ BKE_studiolight_ensure_flag(wpd->studio_light,
+ STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE |
+ STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE);
DRW_shgroup_uniform_texture(
- grp, "matcapImage", wpd->studio_light->equirect_radiance_gputexture);
+ grp, "matcapDiffuseImage", wpd->studio_light->matcap_diffuse.gputexture);
+ if (workbench_is_specular_highlight_enabled(wpd)) {
+ DRW_shgroup_uniform_texture(
+ grp, "matcapSpecularImage", wpd->studio_light->matcap_specular.gputexture);
+ }
}
- if (SPECULAR_HIGHLIGHT_ENABLED(wpd) || MATCAP_ENABLED(wpd)) {
+ if (workbench_is_specular_highlight_enabled(wpd) || MATCAP_ENABLED(wpd)) {
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
}
if (SHADOW_ENABLED(wpd)) {
@@ -199,7 +202,7 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_
DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus);
}
- workbench_material_shgroup_uniform(wpd, grp, material, ob, false, false, interp);
+ workbench_material_shgroup_uniform(wpd, grp, material, ob, false, interp);
material->shgrp = grp;
/* Depth */
@@ -213,8 +216,6 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_
material->shgrp_object_outline = DRW_shgroup_create(sh_data->object_outline_sh,
psl->object_outline_pass);
}
- material->object_id = engine_object_data->object_id;
- DRW_shgroup_uniform_int(material->shgrp_object_outline, "object_id", &material->object_id, 1);
if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
DRW_shgroup_state_enable(material->shgrp_object_outline, DRW_STATE_CLIP_PLANES);
}
@@ -286,26 +287,30 @@ void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUSh
char *defines_texture = workbench_material_build_defines(wpd, true, false, false);
char *defines_hair = workbench_material_build_defines(wpd, false, true, false);
char *forward_vert = workbench_build_forward_vert(false);
+ char *forward_frag = workbench_build_forward_outline_frag();
char *forward_hair_vert = workbench_build_forward_vert(true);
+ const char *define_id_pass = "#define OBJECT_ID_PASS_ENABLED\n";
+
sh_data->object_outline_sh = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg_data->lib, forward_vert, NULL},
- .frag = (const char *[]){datatoc_workbench_forward_depth_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines, NULL},
+ .frag = (const char *[]){forward_frag, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, defines, define_id_pass, NULL},
});
sh_data->object_outline_texture_sh = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg_data->lib, forward_vert, NULL},
- .frag = (const char *[]){datatoc_workbench_forward_depth_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines_texture, NULL},
+ .frag = (const char *[]){forward_frag, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, defines_texture, define_id_pass, NULL},
});
sh_data->object_outline_hair_sh = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg_data->lib, forward_hair_vert, NULL},
- .frag = (const char *[]){datatoc_workbench_forward_depth_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines_hair, NULL},
+ .frag = (const char *[]){forward_frag, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, defines_hair, define_id_pass, NULL},
});
MEM_freeN(forward_hair_vert);
MEM_freeN(forward_vert);
+ MEM_freeN(forward_frag);
MEM_freeN(defines);
MEM_freeN(defines_texture);
MEM_freeN(defines_hair);
@@ -521,25 +526,30 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O
DRWShadingGroup *shgrp = DRW_shgroup_hair_create(
ob, psys, md, psl->transparent_accum_pass, shader);
DRW_shgroup_uniform_block(shgrp, "world_block", wpd->world_ubo);
- workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, false, interp);
+ workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, interp);
DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
/* Hairs have lots of layer and can rapidly become the most prominent surface.
* So lower their alpha artificially. */
float hair_alpha = XRAY_ALPHA(wpd) * 0.33f;
DRW_shgroup_uniform_float_copy(shgrp, "alpha", hair_alpha);
if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
- BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE);
+ BKE_studiolight_ensure_flag(wpd->studio_light,
+ STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE |
+ STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE);
DRW_shgroup_uniform_texture(
- shgrp, "matcapImage", wpd->studio_light->equirect_radiance_gputexture);
+ shgrp, "matcapDiffuseImage", wpd->studio_light->matcap_diffuse.gputexture);
+ if (workbench_is_specular_highlight_enabled(wpd)) {
+ DRW_shgroup_uniform_texture(
+ shgrp, "matcapSpecularImage", wpd->studio_light->matcap_specular.gputexture);
+ }
}
- if (SPECULAR_HIGHLIGHT_ENABLED(wpd) || MATCAP_ENABLED(wpd)) {
+ if (workbench_is_specular_highlight_enabled(wpd) || MATCAP_ENABLED(wpd)) {
DRW_shgroup_uniform_vec2(shgrp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
}
WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
shgrp = DRW_shgroup_hair_create(
ob, psys, md, vedata->psl->object_outline_pass, sh_data->object_outline_hair_sh);
- DRW_shgroup_uniform_int(shgrp, "object_id", &material->object_id, 1);
}
}
}
@@ -550,7 +560,8 @@ static void workbench_forward_cache_populate_texture_paint_mode(WORKBENCH_Data *
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+ const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
WORKBENCH_MaterialData *material;
/* Force workbench to render active object textured when in texture paint mode */
@@ -625,7 +636,8 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
WORKBENCH_MaterialData *material;
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+ const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
const int materials_len = MAX2(1, ob->totcol);
const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
const bool use_texture_paint_drawing = !(DRW_state_is_image_render() &&
@@ -689,7 +701,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
if (use_sculpt_pbvh) {
struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len);
- for (int i = 0; i < materials_len; ++i) {
+ for (int i = 0; i < materials_len; i++) {
struct Material *mat = give_current_material(ob, i + 1);
material = workbench_forward_get_or_create_material_data(
vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
@@ -708,7 +720,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
struct GPUBatch **mat_geom = DRW_cache_object_surface_material_get(
ob, gpumat_array, materials_len, NULL, NULL, NULL);
if (mat_geom) {
- for (int i = 0; i < materials_len; ++i) {
+ for (int i = 0; i < materials_len; i++) {
if (mat_geom[i] == NULL) {
continue;
}
diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c
index 6699a1954ba..0f9551a8cc9 100644
--- a/source/blender/draw/engines/workbench/workbench_materials.c
+++ b/source/blender/draw/engines/workbench/workbench_materials.c
@@ -44,20 +44,15 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd,
WORKBENCH_MaterialData *data,
int color_type)
{
- copy_v3_fl3(data->diffuse_color, 0.8f, 0.8f, 0.8f);
- copy_v3_v3(data->base_color, data->diffuse_color);
- copy_v3_fl3(data->specular_color, 0.05f, 0.05f, 0.05f); /* Dielectric: 5% reflective. */
data->metallic = 0.0f;
data->roughness = 0.632455532f; /* sqrtf(0.4f); */
data->alpha = wpd->shading.xray_alpha;
if (color_type == V3D_SHADING_SINGLE_COLOR) {
- copy_v3_v3(data->diffuse_color, wpd->shading.single_color);
- copy_v3_v3(data->base_color, data->diffuse_color);
+ copy_v3_v3(data->base_color, wpd->shading.single_color);
}
else if (color_type == V3D_SHADING_ERROR_COLOR) {
- copy_v3_fl3(data->diffuse_color, 0.8, 0.0, 0.8);
- copy_v3_v3(data->base_color, data->diffuse_color);
+ copy_v3_fl3(data->base_color, 0.8, 0.0, 0.8);
}
else if (color_type == V3D_SHADING_RANDOM_COLOR) {
uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name);
@@ -67,30 +62,24 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd,
float hue = BLI_hash_int_01(hash);
float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE};
- hsv_to_rgb_v(hsv, data->diffuse_color);
- copy_v3_v3(data->base_color, data->diffuse_color);
+ hsv_to_rgb_v(hsv, data->base_color);
}
else if (ELEM(color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_VERTEX_COLOR)) {
- copy_v3_v3(data->diffuse_color, ob->color);
- copy_v3_v3(data->base_color, data->diffuse_color);
data->alpha *= ob->color[3];
+ copy_v3_v3(data->base_color, ob->color);
}
else {
/* V3D_SHADING_MATERIAL_COLOR or V3D_SHADING_TEXTURE_COLOR */
if (mat) {
data->alpha *= mat->a;
- if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) {
- copy_v3_v3(data->base_color, &mat->r);
- mul_v3_v3fl(data->diffuse_color, &mat->r, 1.0f - mat->metallic);
- mul_v3_v3fl(data->specular_color, &mat->r, mat->metallic);
- add_v3_fl(data->specular_color, 0.05f * (1.0f - mat->metallic));
+ copy_v3_v3(data->base_color, &mat->r);
+ if (workbench_is_specular_highlight_enabled(wpd)) {
data->metallic = mat->metallic;
data->roughness = sqrtf(mat->roughness); /* Remap to disney roughness. */
}
- else {
- copy_v3_v3(data->base_color, &mat->r);
- copy_v3_v3(data->diffuse_color, &mat->r);
- }
+ }
+ else {
+ copy_v3_fl(data->base_color, 0.8f);
}
}
}
@@ -121,7 +110,7 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd,
if (SSAO_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) {
BLI_dynstr_append(ds, "#define WB_CAVITY\n");
}
- if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) {
+ if (workbench_is_specular_highlight_enabled(wpd)) {
BLI_dynstr_append(ds, "#define V3D_SHADING_SPECULAR_HIGHLIGHT\n");
}
if (STUDIOLIGHT_ENABLED(wpd)) {
@@ -160,34 +149,40 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd,
return str;
}
-uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template, bool is_ghost)
+uint workbench_material_get_hash(WORKBENCH_MaterialData *mat, bool is_ghost)
{
- uint input[4];
- uint result;
- float *color = material_template->diffuse_color;
- input[0] = (uint)(color[0] * 512);
- input[1] = (uint)(color[1] * 512);
- input[2] = (uint)(color[2] * 512);
- input[3] = material_template->object_id;
- result = BLI_ghashutil_uinthash_v4_murmur(input);
-
- color = material_template->specular_color;
- input[0] = (uint)(color[0] * 512);
- input[1] = (uint)(color[1] * 512);
- input[2] = (uint)(color[2] * 512);
- input[3] = (uint)(material_template->roughness * 512);
- result += BLI_ghashutil_uinthash_v4_murmur(input);
-
- result += BLI_ghashutil_uinthash((uint)(material_template->alpha * 512));
- result += BLI_ghashutil_uinthash((uint)is_ghost);
- result += BLI_ghashutil_uinthash(material_template->color_type);
-
- /* add texture reference */
- if (material_template->ima) {
- result += BLI_ghashutil_inthash_p_murmur(material_template->ima);
- }
-
- return result;
+ union {
+ struct {
+ /* WHATCH: Keep in sync with View3DShading.color_type max value. */
+ uchar color_type;
+ uchar diff_r;
+ uchar diff_g;
+ uchar diff_b;
+
+ uchar alpha;
+ uchar ghost;
+ uchar metal;
+ uchar roughness;
+
+ void *ima;
+ };
+ /* HACK to ensure input is 4 uint long. */
+ uint a[4];
+ } input = {.color_type = (uchar)(mat->color_type),
+ .diff_r = (uchar)(mat->base_color[0] * 0xFF),
+ .diff_g = (uchar)(mat->base_color[1] * 0xFF),
+ .diff_b = (uchar)(mat->base_color[2] * 0xFF),
+
+ .alpha = (uint)(mat->alpha * 0xFF),
+ .ghost = (uchar)is_ghost,
+ .metal = (uchar)(mat->metallic * 0xFF),
+ .roughness = (uchar)(mat->roughness * 0xFF),
+
+ .ima = mat->ima};
+
+ BLI_assert(sizeof(input) == sizeof(uint) * 4);
+
+ return BLI_ghashutil_uinthash_v4((uint *)&input);
}
int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd)
@@ -195,11 +190,12 @@ int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd)
/* NOTE: change MAX_COMPOSITE_SHADERS accordingly when modifying this function. */
int index = 0;
/* 2 bits FLAT/STUDIO/MATCAP + Specular highlight */
- index = SPECULAR_HIGHLIGHT_ENABLED(wpd) ? 3 : wpd->shading.light;
+ index = wpd->shading.light;
SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_SHADOW, 1 << 2);
SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_CAVITY, 1 << 3);
SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE, 1 << 4);
SET_FLAG_FROM_TEST(index, workbench_is_matdata_pass_enabled(wpd), 1 << 5);
+ SET_FLAG_FROM_TEST(index, workbench_is_specular_highlight_enabled(wpd), 1 << 6);
BLI_assert(index < MAX_COMPOSITE_SHADERS);
return index;
}
@@ -246,12 +242,13 @@ int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd,
/* NOTE: change MAX_ACCUM_SHADERS accordingly when modifying this function. */
int index = 0;
/* 2 bits FLAT/STUDIO/MATCAP + Specular highlight */
- index = SPECULAR_HIGHLIGHT_ENABLED(wpd) ? 3 : wpd->shading.light;
+ index = wpd->shading.light;
SET_FLAG_FROM_TEST(index, use_textures, 1 << 2);
SET_FLAG_FROM_TEST(index, use_vertex_colors, 1 << 3);
SET_FLAG_FROM_TEST(index, is_hair, 1 << 4);
/* 1 bits SHADOWS (only facing factor) */
SET_FLAG_FROM_TEST(index, SHADOW_ENABLED(wpd), 1 << 5);
+ SET_FLAG_FROM_TEST(index, workbench_is_specular_highlight_enabled(wpd), 1 << 6);
BLI_assert(index < MAX_ACCUM_SHADERS);
return index;
}
@@ -264,8 +261,8 @@ int workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd,
int color_type = wpd->shading.color_type;
const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
- if ((color_type == V3D_SHADING_TEXTURE_COLOR && (ima == NULL || use_sculpt_pbvh)) ||
- (ob->dt < OB_TEXTURE)) {
+ if ((color_type == V3D_SHADING_TEXTURE_COLOR) &&
+ (ima == NULL || use_sculpt_pbvh || (ob->dt < OB_TEXTURE))) {
color_type = V3D_SHADING_MATERIAL_COLOR;
}
if (color_type == V3D_SHADING_VERTEX_COLOR && (me == NULL || me->mloopcol == NULL)) {
@@ -313,35 +310,28 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
DRWShadingGroup *grp,
WORKBENCH_MaterialData *material,
Object *ob,
- const bool use_metallic,
const bool deferred,
const int interp)
{
- if (!deferred || workbench_is_matdata_pass_enabled(wpd)) {
- if (workbench_material_determine_color_type(wpd, material->ima, ob, false) ==
- V3D_SHADING_TEXTURE_COLOR) {
- GPUTexture *tex = GPU_texture_from_blender(material->ima, material->iuser, GL_TEXTURE_2D);
- DRW_shgroup_uniform_texture(grp, "image", tex);
- DRW_shgroup_uniform_bool_copy(
- grp, "imagePremultiplied", (material->ima->alpha_mode == IMA_ALPHA_PREMUL));
- DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST));
- }
- else {
- DRW_shgroup_uniform_vec3(grp,
- "materialDiffuseColor",
- (use_metallic) ? material->base_color : material->diffuse_color,
- 1);
- }
+ if (!(!deferred || workbench_is_matdata_pass_enabled(wpd))) {
+ return;
+ }
- if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) {
- if (use_metallic) {
- DRW_shgroup_uniform_float(grp, "materialMetallic", &material->metallic, 1);
- }
- else {
- DRW_shgroup_uniform_vec3(grp, "materialSpecularColor", material->specular_color, 1);
- }
- DRW_shgroup_uniform_float(grp, "materialRoughness", &material->roughness, 1);
- }
+ const bool use_highlight = workbench_is_specular_highlight_enabled(wpd);
+ const bool use_texture = (V3D_SHADING_TEXTURE_COLOR == workbench_material_determine_color_type(
+ wpd, material->ima, ob, false));
+ if (use_texture) {
+ GPUTexture *tex = GPU_texture_from_blender(material->ima, material->iuser, GL_TEXTURE_2D);
+ DRW_shgroup_uniform_texture(grp, "image", tex);
+ DRW_shgroup_uniform_bool_copy(
+ grp, "imagePremultiplied", (material->ima->alpha_mode == IMA_ALPHA_PREMUL));
+ DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST));
+ }
+
+ DRW_shgroup_uniform_vec4(grp, "materialColorAndMetal", material->base_color, 1);
+
+ if (use_highlight) {
+ DRW_shgroup_uniform_float(grp, "materialRoughness", &material->roughness, 1);
}
if (WORLD_CLIPPING_ENABLED(wpd)) {
@@ -352,10 +342,7 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
void workbench_material_copy(WORKBENCH_MaterialData *dest_material,
const WORKBENCH_MaterialData *source_material)
{
- dest_material->object_id = source_material->object_id;
copy_v3_v3(dest_material->base_color, source_material->base_color);
- copy_v3_v3(dest_material->diffuse_color, source_material->diffuse_color);
- copy_v3_v3(dest_material->specular_color, source_material->specular_color);
dest_material->metallic = source_material->metallic;
dest_material->roughness = source_material->roughness;
dest_material->ima = source_material->ima;
diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h
index 255b036eebb..252be3570d7 100644
--- a/source/blender/draw/engines/workbench/workbench_private.h
+++ b/source/blender/draw/engines/workbench/workbench_private.h
@@ -36,9 +36,9 @@
#define WORKBENCH_ENGINE "BLENDER_WORKBENCH"
#define M_GOLDEN_RATION_CONJUGATE 0.618033988749895
-#define MAX_COMPOSITE_SHADERS (1 << 6)
+#define MAX_COMPOSITE_SHADERS (1 << 7)
#define MAX_PREPASS_SHADERS (1 << 7)
-#define MAX_ACCUM_SHADERS (1 << 6)
+#define MAX_ACCUM_SHADERS (1 << 7)
#define MAX_CAVITY_SHADERS (1 << 3)
#define TEXTURE_DRAWING_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR)
@@ -75,11 +75,9 @@
V3D_SHADING_VERTEX_COLOR))
#define IS_NAVIGATING(wpd) \
- ((DRW_context_state_get()->rv3d) && (DRW_context_state_get()->rv3d->rflag & RV3D_NAVIGATING))
+ ((DRW_context_state_get()->rv3d) && \
+ (DRW_context_state_get()->rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING)))
-#define SPECULAR_HIGHLIGHT_ENABLED(wpd) \
- (STUDIOLIGHT_ENABLED(wpd) && (wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT) && \
- (!STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)))
#define OBJECT_OUTLINE_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE)
#define OBJECT_ID_PASS_ENABLED(wpd) (OBJECT_OUTLINE_ENABLED(wpd) || CURVATURE_ENABLED(wpd))
#define NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) \
@@ -284,13 +282,8 @@ typedef struct WORKBENCH_EffectInfo {
} WORKBENCH_EffectInfo;
typedef struct WORKBENCH_MaterialData {
- float base_color[3];
- float diffuse_color[3];
- float specular_color[3];
- float alpha;
- float metallic;
- float roughness;
- int object_id;
+ float base_color[3], metallic;
+ float roughness, alpha;
int color_type;
int interp;
Image *ima;
@@ -311,11 +304,19 @@ typedef struct WORKBENCH_ObjectData {
float shadow_min[3], shadow_max[3];
BoundBox shadow_bbox;
bool shadow_bbox_dirty;
-
- int object_id;
} WORKBENCH_ObjectData;
/* inline helper functions */
+BLI_INLINE bool workbench_is_specular_highlight_enabled(WORKBENCH_PrivateData *wpd)
+{
+ if ((wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT)) {
+ if (STUDIOLIGHT_ENABLED(wpd) || MATCAP_ENABLED(wpd)) {
+ return (wpd->studio_light->flag & STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS) != 0;
+ }
+ }
+ return false;
+}
+
BLI_INLINE bool workbench_is_taa_enabled(WORKBENCH_PrivateData *wpd)
{
if (DRW_state_is_image_render()) {
@@ -493,7 +494,6 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
DRWShadingGroup *grp,
WORKBENCH_MaterialData *material,
Object *ob,
- const bool use_metallic,
const bool deferred,
const int interp);
void workbench_material_copy(WORKBENCH_MaterialData *dest_material,
diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c
index b4e5e98c92b..899fbdc9b71 100644
--- a/source/blender/draw/engines/workbench/workbench_render.c
+++ b/source/blender/draw/engines/workbench/workbench_render.c
@@ -24,6 +24,8 @@
#include "BLI_rect.h"
+#include "DNA_node_types.h"
+
#include "BKE_report.h"
#include "DRW_render.h"
diff --git a/source/blender/draw/engines/workbench/workbench_studiolight.c b/source/blender/draw/engines/workbench/workbench_studiolight.c
index 1a09498b228..ac27ff0b736 100644
--- a/source/blender/draw/engines/workbench/workbench_studiolight.c
+++ b/source/blender/draw/engines/workbench/workbench_studiolight.c
@@ -77,7 +77,7 @@ void studiolight_update_world(WORKBENCH_PrivateData *wpd,
/* Use Geomerics non-linear SH. */
mul_v3_v3fl(wd->spherical_harmonics_coefs[0], sl->spherical_harmonics_coefs[0], M_1_PI);
/* Swizzle to make shader code simpler. */
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
copy_v3_fl3(wd->spherical_harmonics_coefs[i + 1],
-sl->spherical_harmonics_coefs[3][i],
sl->spherical_harmonics_coefs[2][i],
@@ -89,7 +89,7 @@ void studiolight_update_world(WORKBENCH_PrivateData *wpd,
/* Precompute as much as we can. See shader code for derivation. */
float len_r1[3], lr1_r0[3], p[3], a[3];
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
mul_v3_fl(wd->spherical_harmonics_coefs[i + 1], 0.5f);
len_r1[i] = len_v3(wd->spherical_harmonics_coefs[i + 1]);
mul_v3_fl(wd->spherical_harmonics_coefs[i + 1], 1.0f / len_r1[i]);
@@ -179,7 +179,7 @@ void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_dire
mul_v3_mat3_m4v3(wpd->shadow_near_corners[3], wpd->shadow_inv, frustum_corners.vec[4]);
INIT_MINMAX(wpd->shadow_near_min, wpd->shadow_near_max);
- for (int i = 0; i < 4; ++i) {
+ for (int i = 0; i < 4; i++) {
minmax_v3v3_v3(wpd->shadow_near_min, wpd->shadow_near_max, wpd->shadow_near_corners[i]);
}
@@ -206,7 +206,7 @@ static BoundBox *studiolight_object_shadow_bbox_get(WORKBENCH_PrivateData *wpd,
/* From object space to shadow space */
BoundBox *bbox = BKE_object_boundbox_get(ob);
- for (int i = 0; i < 8; ++i) {
+ for (int i = 0; i < 8; i++) {
float corner[3];
mul_v3_m4v3(corner, tmp_mat, bbox->vec[i]);
minmax_v3v3_v3(oed->shadow_min, oed->shadow_max, corner);
@@ -217,7 +217,7 @@ static BoundBox *studiolight_object_shadow_bbox_get(WORKBENCH_PrivateData *wpd,
/* Get extended AABB in world space. */
BKE_boundbox_init_from_minmax(&oed->shadow_bbox, oed->shadow_min, oed->shadow_max);
- for (int i = 0; i < 8; ++i) {
+ for (int i = 0; i < 8; i++) {
mul_m4_v3(wpd->shadow_mat, oed->shadow_bbox.vec[i]);
}
oed->shadow_bbox_dirty = false;
@@ -243,7 +243,7 @@ float studiolight_object_shadow_distance(WORKBENCH_PrivateData *wpd,
int corners[4] = {0, 3, 4, 7};
float dist = 1e4f, dist_isect;
- for (int i = 0; i < 4; ++i) {
+ for (int i = 0; i < 4; i++) {
if (isect_ray_plane_v3(shadow_bbox->vec[corners[i]],
wpd->cached_shadow_direction,
wpd->shadow_far_plane,
@@ -284,16 +284,16 @@ bool studiolight_camera_in_object_shadow(WORKBENCH_PrivateData *wpd,
}
/* Test projected near rectangle sides */
- float pts[4][2] = {
+ const float pts[4][2] = {
{oed->shadow_min[0], oed->shadow_min[1]},
{oed->shadow_min[0], oed->shadow_max[1]},
{oed->shadow_max[0], oed->shadow_min[1]},
{oed->shadow_max[0], oed->shadow_max[1]},
};
- for (int i = 0; i < 2; ++i) {
+ for (int i = 0; i < 2; i++) {
float min_dst = FLT_MAX, max_dst = -FLT_MAX;
- for (int j = 0; j < 4; ++j) {
+ for (int j = 0; j < 4; j++) {
float dst = dot_v2v2(wpd->shadow_near_sides[i], pts[j]);
/* Do min max */
if (min_dst > dst) {
diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c
index 1beb02ea3a0..e017661b6cd 100644
--- a/source/blender/draw/engines/workbench/workbench_volume.c
+++ b/source/blender/draw/engines/workbench/workbench_volume.c
@@ -27,6 +27,7 @@
#include "BLI_rand.h"
#include "BLI_dynstr.h"
+#include "BLI_string_utils.h"
#include "DNA_modifier_types.h"
#include "DNA_object_force_types.h"
@@ -54,6 +55,7 @@ static struct {
extern char datatoc_workbench_volume_vert_glsl[];
extern char datatoc_workbench_volume_frag_glsl[];
extern char datatoc_common_view_lib_glsl[];
+extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic)
{
@@ -78,12 +80,16 @@ static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic)
char *defines = BLI_dynstr_get_cstring(ds);
BLI_dynstr_free(ds);
+ char *libs = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_gpu_shader_common_obinfos_lib_glsl);
+
e_data.volume_sh[id] = DRW_shader_create_with_lib(datatoc_workbench_volume_vert_glsl,
NULL,
datatoc_workbench_volume_frag_glsl,
- datatoc_common_view_lib_glsl,
+ libs,
defines);
+ MEM_freeN(libs);
MEM_freeN(defines);
}
@@ -101,7 +107,7 @@ void workbench_volume_engine_init(void)
void workbench_volume_engine_free(void)
{
- for (int i = 0; i < VOLUME_SH_MAX; ++i) {
+ for (int i = 0; i < VOLUME_SH_MAX; i++) {
DRW_SHADER_FREE_SAFE(e_data.volume_sh[i]);
}
DRW_TEXTURE_FREE_SAFE(e_data.dummy_tex);
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 10ab7c13631..2c51eb8b7f8 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -75,15 +75,13 @@ struct RenderEngineType;
struct bContext;
struct rcti;
+typedef struct DRWCallBuffer DRWCallBuffer;
typedef struct DRWInterface DRWInterface;
typedef struct DRWPass DRWPass;
typedef struct DRWShadingGroup DRWShadingGroup;
typedef struct DRWUniform DRWUniform;
typedef struct DRWView DRWView;
-/* Opaque type to avoid usage as a DRWCall but it is exactly the same thing. */
-typedef struct DRWCallBuffer DRWCallBuffer;
-
/* TODO Put it somewhere else? */
typedef struct BoundSphere {
float center[3], radius;
@@ -346,6 +344,7 @@ typedef enum {
/** Use dual source blending. WARNING: Only one color buffer allowed. */
DRW_STATE_BLEND_CUSTOM = (1 << 23),
+ DRW_STATE_SHADOW_OFFSET = (1 << 27),
DRW_STATE_CLIP_PLANES = (1 << 28),
DRW_STATE_WIRE_SMOOTH = (1 << 29),
DRW_STATE_FIRST_VERTEX_CONVENTION = (1 << 30),
@@ -403,35 +402,29 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
Object *ob,
float (*obmat)[4],
struct GPUBatch *geom,
- uint v_sta,
- uint v_ct,
bool bypass_culling,
void *user_data);
/* If ob is NULL, unit modelmatrix is assumed and culling is bypassed. */
-#define DRW_shgroup_call(shgrp, geom, ob) \
- DRW_shgroup_call_ex(shgrp, ob, NULL, geom, 0, 0, false, NULL)
+#define DRW_shgroup_call(shgrp, geom, ob) DRW_shgroup_call_ex(shgrp, ob, NULL, geom, false, NULL)
/* Same as DRW_shgroup_call but override the obmat. Not culled. */
#define DRW_shgroup_call_obmat(shgrp, geom, obmat) \
- DRW_shgroup_call_ex(shgrp, NULL, obmat, geom, 0, 0, false, NULL)
+ DRW_shgroup_call_ex(shgrp, NULL, obmat, geom, false, NULL)
/* TODO(fclem) remove this when we have DRWView */
/* user_data is used by DRWCallVisibilityFn defined in DRWView. */
#define DRW_shgroup_call_with_callback(shgrp, geom, ob, user_data) \
- DRW_shgroup_call_ex(shgrp, ob, NULL, geom, 0, 0, false, user_data)
+ DRW_shgroup_call_ex(shgrp, ob, NULL, geom, false, user_data)
/* Same as DRW_shgroup_call but bypass culling even if ob is not NULL. */
#define DRW_shgroup_call_no_cull(shgrp, geom, ob) \
- DRW_shgroup_call_ex(shgrp, ob, NULL, geom, 0, 0, true, NULL)
+ DRW_shgroup_call_ex(shgrp, ob, NULL, geom, true, NULL)
-/* Only draw a certain range of geom. */
-#define DRW_shgroup_call_range(shgrp, geom, ob, v_sta, v_ct) \
- DRW_shgroup_call_ex(shgrp, ob, NULL, geom, v_sta, v_ct, false, NULL)
-
-/* Same as DRW_shgroup_call_range but override the obmat. Special for gpencil. */
-#define DRW_shgroup_call_range_obmat(shgrp, geom, obmat, v_sta, v_ct) \
- DRW_shgroup_call_ex(shgrp, NULL, obmat, geom, v_sta, v_ct, false, NULL)
+void DRW_shgroup_call_range(DRWShadingGroup *shgroup,
+ struct GPUBatch *geom,
+ uint v_sta,
+ uint v_ct);
void DRW_shgroup_call_procedural_points(DRWShadingGroup *sh, Object *ob, uint point_ct);
void DRW_shgroup_call_procedural_lines(DRWShadingGroup *sh, Object *ob, uint line_ct);
@@ -468,6 +461,16 @@ void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state);
void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state);
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask);
+/* Issue a clear command. */
+void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup,
+ eGPUFrameBufferBits channels,
+ uchar r,
+ uchar g,
+ uchar b,
+ uchar a,
+ float depth,
+ uchar stencil);
+
void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup,
const char *name,
const struct GPUTexture *tex);
@@ -524,17 +527,17 @@ void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const
void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float (*value)[4]);
/* Store value instead of referencing it. */
void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value);
+void DRW_shgroup_uniform_ivec2_copy(DRWShadingGroup *shgrp, const char *name, const int *value);
+void DRW_shgroup_uniform_ivec3_copy(DRWShadingGroup *shgrp, const char *name, const int *value);
+void DRW_shgroup_uniform_ivec4_copy(DRWShadingGroup *shgrp, const char *name, const int *value);
void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value);
void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, const float value);
void DRW_shgroup_uniform_vec2_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
+void DRW_shgroup_uniform_vec3_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
+void DRW_shgroup_uniform_vec4_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup);
-/* TODO: workaround functions waiting for the clearing operation to be available inside the
- * shgroups. */
-DRWShadingGroup *DRW_shgroup_get_next(DRWShadingGroup *shgroup);
-uint DRW_shgroup_stencil_mask_get(DRWShadingGroup *shgroup);
-
/* Passes */
DRWPass *DRW_pass_create(const char *name, DRWState state);
/* TODO Replace with passes inheritance. */
diff --git a/source/blender/draw/intern/draw_anim_viz.c b/source/blender/draw/intern/draw_anim_viz.c
index 72459309133..7e0110cbb99 100644
--- a/source/blender/draw/intern/draw_anim_viz.c
+++ b/source/blender/draw/intern/draw_anim_viz.c
@@ -215,7 +215,7 @@ static void MPATH_cache_motion_path(MPATH_PassList *psl,
DRW_shgroup_uniform_vec3(shgrp, "customColor", mpath->color, 1);
}
/* Only draw the required range. */
- DRW_shgroup_call_range(shgrp, mpath_batch_line_get(mpath), NULL, start_index, len);
+ DRW_shgroup_call_range(shgrp, mpath_batch_line_get(mpath), start_index, len);
}
/* Draw points. */
@@ -231,7 +231,7 @@ static void MPATH_cache_motion_path(MPATH_PassList *psl,
DRW_shgroup_uniform_vec3(shgrp, "customColor", mpath->color, 1);
}
/* Only draw the required range. */
- DRW_shgroup_call_range(shgrp, mpath_batch_points_get(mpath), NULL, start_index, len);
+ DRW_shgroup_call_range(shgrp, mpath_batch_points_get(mpath), start_index, len);
/* Draw frame numbers at each framestep value */
bool show_kf_no = (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) != 0;
@@ -289,10 +289,9 @@ static void MPATH_cache_populate(void *vedata, Object *ob)
}
}
}
- else {
- if (ob->mpath) {
- MPATH_cache_motion_path(psl, ob, NULL, &ob->avs, ob->mpath);
- }
+
+ if (ob->mpath) {
+ MPATH_cache_motion_path(psl, ob, NULL, &ob->avs, ob->mpath);
}
}
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 520932bc429..019098e5b90 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -296,15 +296,15 @@ static GPUVertBuf *sphere_wire_vbo(const float rad)
/* a single ring of vertices */
float p[NSEGMENTS][2];
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
p[i][0] = rad * cosf(angle);
p[i][1] = rad * sinf(angle);
}
- for (int axis = 0; axis < 3; ++axis) {
- for (int i = 0; i < NSEGMENTS; ++i) {
- for (int j = 0; j < 2; ++j) {
+ for (int axis = 0; axis < 3; axis++) {
+ for (int i = 0; i < NSEGMENTS; i++) {
+ for (int j = 0; j < 2; j++) {
float cv[2], v[3];
cv[0] = p[(i + j) % NSEGMENTS][0];
@@ -347,12 +347,13 @@ GPUBatch *DRW_cache_fullscreen_quad_get(void)
attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
attr_id.uvs = GPU_vertformat_attr_add(&format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
GPU_vertformat_alias_add(&format, "texCoord");
+ GPU_vertformat_alias_add(&format, "orco"); /* Fix driver bug (see T70004) */
}
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, 3);
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
GPU_vertbuf_attr_set(vbo, attr_id.pos, i, pos[i]);
GPU_vertbuf_attr_set(vbo, attr_id.uvs, i, uvs[i]);
}
@@ -382,7 +383,7 @@ GPUBatch *DRW_cache_quad_get(void)
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, 4);
- for (int i = 0; i < 4; ++i) {
+ for (int i = 0; i < 4; i++) {
GPU_vertbuf_attr_set(vbo, attr_id.pos, i, pos[i]);
GPU_vertbuf_attr_set(vbo, attr_id.uvs, i, uvs[i]);
}
@@ -437,8 +438,8 @@ GPUBatch *DRW_cache_grid_get(void)
GPU_vertbuf_data_alloc(vbo, 8 * 8 * 2 * 3);
uint v_idx = 0;
- for (int i = 0; i < 8; ++i) {
- for (int j = 0; j < 8; ++j) {
+ for (int i = 0; i < 8; i++) {
+ for (int j = 0; j < 8; j++) {
float pos0[2] = {(float)i / 8.0f, (float)j / 8.0f};
float pos1[2] = {(float)(i + 1) / 8.0f, (float)j / 8.0f};
float pos2[2] = {(float)i / 8.0f, (float)(j + 1) / 8.0f};
@@ -510,7 +511,7 @@ GPUBatch *DRW_cache_cube_get(void)
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, 36);
- for (int i = 0; i < 36; ++i) {
+ for (int i = 0; i < 36; i++) {
GPU_vertbuf_attr_set(vbo, attr_id.pos, i, verts[indices[i]]);
}
@@ -549,7 +550,7 @@ GPUBatch *DRW_cache_empty_cube_get(void)
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, 24);
- for (int i = 0; i < 24; ++i) {
+ for (int i = 0; i < 24; i++) {
GPU_vertbuf_attr_set(vbo, attr_id.pos, i, verts[indices[i]]);
}
@@ -592,7 +593,7 @@ GPUBatch *DRW_cache_circle_get(void)
GPUBatch *DRW_cache_square_get(void)
{
if (!SHC.drw_square) {
- float p[4][3] = {
+ const float p[4][3] = {
{1.0f, 0.0f, 1.0f}, {1.0f, 0.0f, -1.0f}, {-1.0f, 0.0f, -1.0f}, {-1.0f, 0.0f, 1.0f}};
/* Position Only 3D format */
@@ -751,7 +752,7 @@ GPUBatch *DRW_cache_gpencil_axes_get(void)
}
/* draw cube */
- for (int i = 0; i < 24; ++i) {
+ for (int i = 0; i < 24; i++) {
GPU_vertbuf_attr_set(vbo, pos_id, i + 6, verts[indices[i]]);
}
@@ -982,7 +983,7 @@ GPUBatch *DRW_cache_empty_cone_get(void)
if (!SHC.drw_empty_cone) {
/* a single ring of vertices */
float p[NSEGMENTS][2];
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
p[i][0] = cosf(angle);
p[i][1] = sinf(angle);
@@ -1000,7 +1001,7 @@ GPUBatch *DRW_cache_empty_cone_get(void)
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 4);
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float cv[2], v[3];
cv[0] = p[(i) % NSEGMENTS][0];
cv[1] = p[(i) % NSEGMENTS][1];
@@ -1032,7 +1033,7 @@ GPUBatch *DRW_cache_empty_cylinder_get(void)
if (!SHC.drw_empty_cylinder) {
/* a single ring of vertices */
float p[NSEGMENTS][2];
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
p[i][0] = cosf(angle);
p[i][1] = sinf(angle);
@@ -1050,7 +1051,7 @@ GPUBatch *DRW_cache_empty_cylinder_get(void)
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 6);
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float cv[2], pv[2], v[3];
cv[0] = p[(i) % NSEGMENTS][0];
cv[1] = p[(i) % NSEGMENTS][1];
@@ -1121,7 +1122,7 @@ GPUBatch *DRW_cache_empty_capsule_cap_get(void)
if (!SHC.drw_empty_capsule_cap) {
/* a single ring of vertices */
float p[NSEGMENTS][2];
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
p[i][0] = cosf(angle);
p[i][1] = sinf(angle);
@@ -1141,7 +1142,7 @@ GPUBatch *DRW_cache_empty_capsule_cap_get(void)
/* Base circle */
int vidx = 0;
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float v[3] = {0.0f, 0.0f, 0.0f};
copy_v2_v2(v, p[(i) % NSEGMENTS]);
GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
@@ -1149,7 +1150,7 @@ GPUBatch *DRW_cache_empty_capsule_cap_get(void)
GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
}
- for (int i = 0; i < NSEGMENTS / 2; ++i) {
+ for (int i = 0; i < NSEGMENTS / 2; i++) {
float v[3] = {0.0f, 0.0f, 0.0f};
int ci = i % NSEGMENTS;
int pi = (i + 1) % NSEGMENTS;
@@ -1690,7 +1691,7 @@ GPUBatch *DRW_cache_light_spot_get(void)
float n[NSEGMENTS][3];
float neg[NSEGMENTS][3];
float half_angle = 2 * M_PI / ((float)NSEGMENTS * 2);
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
p[i][0] = cosf(angle);
p[i][1] = sinf(angle);
@@ -1715,7 +1716,7 @@ GPUBatch *DRW_cache_light_spot_get(void)
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 4);
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float cv[2], v[3];
cv[0] = p[i % NSEGMENTS][0];
cv[1] = p[i % NSEGMENTS][1];
@@ -1757,7 +1758,7 @@ GPUBatch *DRW_cache_light_spot_volume_get(void)
if (!SHC.drw_light_spot_volume) {
/* a single ring of vertices */
float p[NSEGMENTS][2];
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
p[i][0] = cosf(angle);
p[i][1] = sinf(angle);
@@ -1775,7 +1776,7 @@ GPUBatch *DRW_cache_light_spot_volume_get(void)
GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 3);
uint v_idx = 0;
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float cv[2], v[3];
ARRAY_SET_ITEMS(v, 0.0f, 0.0f, 0.0f);
@@ -1801,7 +1802,7 @@ GPUBatch *DRW_cache_light_spot_volume_get(void)
GPUBatch *DRW_cache_light_spot_square_get(void)
{
if (!SHC.drw_light_spot_square) {
- float p[5][3] = {
+ const float p[5][3] = {
{0.0f, 0.0f, 0.0f},
{1.0f, 1.0f, -1.0f},
{1.0f, -1.0f, -1.0f},
@@ -1824,7 +1825,7 @@ GPUBatch *DRW_cache_light_spot_square_get(void)
GPU_vertbuf_data_alloc(vbo, 16);
/* piramid sides */
- for (int i = 1; i <= 4; ++i) {
+ for (int i = 1; i <= 4; i++) {
GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[0]);
GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[i]);
@@ -1840,7 +1841,7 @@ GPUBatch *DRW_cache_light_spot_square_get(void)
GPUBatch *DRW_cache_light_spot_square_volume_get(void)
{
if (!SHC.drw_light_spot_square_volume) {
- float p[5][3] = {
+ const float p[5][3] = {
{0.0f, 0.0f, 0.0f},
{1.0f, 1.0f, -1.0f},
{1.0f, -1.0f, -1.0f},
@@ -1863,7 +1864,7 @@ GPUBatch *DRW_cache_light_spot_square_volume_get(void)
GPU_vertbuf_data_alloc(vbo, 12);
/* piramid sides */
- for (int i = 1; i <= 4; ++i) {
+ for (int i = 1; i <= 4; i++) {
GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[0]);
GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[((i + 1) % 4) + 1]);
GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[(i % 4) + 1]);
@@ -1952,7 +1953,7 @@ GPUBatch *DRW_cache_lightprobe_cube_get(void)
int v_idx = 0;
const float sin_pi_3 = 0.86602540378f;
const float cos_pi_3 = 0.5f;
- float v[7][3] = {
+ const float v[7][3] = {
{0.0f, 1.0f, 0.0f},
{sin_pi_3, cos_pi_3, 0.0f},
{sin_pi_3, -cos_pi_3, 0.0f},
@@ -1974,7 +1975,7 @@ GPUBatch *DRW_cache_lightprobe_cube_get(void)
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, (6 + 3) * 2);
- for (int i = 0; i < 6; ++i) {
+ for (int i = 0; i < 6; i++) {
GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[i]);
GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[(i + 1) % 6]);
}
@@ -2021,7 +2022,7 @@ GPUBatch *DRW_cache_lightprobe_grid_get(void)
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, (6 * 2 + 3) * 2);
- for (int i = 0; i < 6; ++i) {
+ for (int i = 0; i < 6; i++) {
float tmp_v1[3], tmp_v2[3], tmp_tr[3];
copy_v3_v3(tmp_v1, v[i]);
copy_v3_v3(tmp_v2, v[(i + 1) % 6]);
@@ -2029,7 +2030,7 @@ GPUBatch *DRW_cache_lightprobe_grid_get(void)
GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v2);
/* Internal wires. */
- for (int j = 1; j < 2; ++j) {
+ for (int j = 1; j < 2; j++) {
mul_v3_v3fl(tmp_tr, v[(i / 2) * 2 + 1], -0.5f * j);
add_v3_v3v3(tmp_v1, v[i], tmp_tr);
add_v3_v3v3(tmp_v2, v[(i + 1) % 6], tmp_tr);
@@ -2057,7 +2058,7 @@ GPUBatch *DRW_cache_lightprobe_planar_get(void)
if (!SHC.drw_lightprobe_planar) {
int v_idx = 0;
const float sin_pi_3 = 0.86602540378f;
- float v[4][3] = {
+ const float v[4][3] = {
{0.0f, 0.5f, 0.0f},
{sin_pi_3, 0.0f, 0.0f},
{0.0f, -0.5f, 0.0f},
@@ -2076,7 +2077,7 @@ GPUBatch *DRW_cache_lightprobe_planar_get(void)
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, 4 * 2);
- for (int i = 0; i < 4; ++i) {
+ for (int i = 0; i < 4; i++) {
GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[i]);
GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[(i + 1) % 4]);
}
@@ -2214,7 +2215,7 @@ GPUBatch *DRW_cache_bone_octahedral_get(void)
GPU_vertbuf_data_alloc(vbo, 24);
for (int i = 0; i < 8; i++) {
- for (int j = 0; j < 3; ++j) {
+ for (int j = 0; j < 3; j++) {
GPU_vertbuf_attr_set(vbo, attr_id.nor, v_idx, bone_octahedral_solid_normals[i]);
GPU_vertbuf_attr_set(vbo,
attr_id.snor,
@@ -2710,7 +2711,7 @@ GPUBatch *DRW_cache_bone_stick_get(void)
GPU_indexbuf_init_ex(&elb, GPU_PRIM_TRI_FAN, (CIRCLE_RESOL + 2) * 2 + 6 + 2, vcount);
/* head/tail points */
- for (int i = 0; i < 2; ++i) {
+ for (int i = 0; i < 2; i++) {
/* center vertex */
copy_v2_fl(pos, 0.0f);
flag = (i == 0) ? POS_HEAD : POS_TAIL;
@@ -2735,7 +2736,7 @@ GPUBatch *DRW_cache_bone_stick_get(void)
/* Bone rectangle */
pos[0] = 0.0f;
- for (int i = 0; i < 6; ++i) {
+ for (int i = 0; i < 6; i++) {
pos[1] = (i == 0 || i == 3) ? 0.0f : ((i < 3) ? 1.0f : -1.0f);
flag = ((i < 2 || i > 4) ? POS_HEAD : POS_TAIL) | ((i == 0 || i == 3) ? 0 : COL_WIRE) |
COL_BONE | POS_BONE;
@@ -2896,8 +2897,8 @@ GPUBatch *DRW_cache_bone_arrows_get(void)
set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, pos, c);
/* Axis end marker */
- for (int j = 1; j < MARKER_FILL_LAYER + 1; ++j) {
- for (int i = 0; i < MARKER_LEN; ++i) {
+ for (int j = 1; j < MARKER_FILL_LAYER + 1; j++) {
+ for (int i = 0; i < MARKER_LEN; i++) {
float tmp[2];
mul_v2_v2fl(tmp, axis_marker[i], j / (float)MARKER_FILL_LAYER);
set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, tmp, c);
@@ -2924,8 +2925,8 @@ GPUBatch *DRW_cache_bone_arrows_get(void)
/* Axis name shadows */
copy_v3_fl(c, 0.0f);
c[axis] = 0.3f;
- for (int j = 0; j < SHADOW_RES; ++j) {
- for (int i = 0; i < axis_v_len; ++i) {
+ for (int j = 0; j < SHADOW_RES; j++) {
+ for (int i = 0; i < axis_v_len; i++) {
float tmp[2];
add_v2_v2v2(tmp, axis_verts[i], axis_name_shadow[j]);
set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, tmp, c);
@@ -2935,7 +2936,7 @@ GPUBatch *DRW_cache_bone_arrows_get(void)
/* Axis name */
copy_v3_fl(c, 0.1f);
c[axis] = 1.0f;
- for (int i = 0; i < axis_v_len; ++i) {
+ for (int i = 0; i < axis_v_len; i++) {
set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, axis_verts[i], c);
}
}
@@ -2990,12 +2991,12 @@ GPUBatch *DRW_cache_bone_dof_sphere_get(void)
GPU_vertbuf_data_alloc(vbo, n * n * 6 * 4);
uint v = 0;
- for (q = 0; q < 4; ++q) {
+ for (q = 0; q < 4; q++) {
pz = 0.0f;
- for (i = 1; i < n; ++i) {
+ for (i = 1; i < n; i++) {
z = staticSine[i];
px = 0.0f;
- for (j = 1; j <= (n - i); ++j) {
+ for (j = 1; j <= (n - i); j++) {
x = staticSine[j];
if (j == n - i) {
set_vert(px, z, q);
@@ -3937,7 +3938,7 @@ GPUBatch *DRW_cache_cursor_get(bool crosshair_lines)
GPU_vertbuf_data_alloc(vbo, vert_len);
int v = 0;
- for (int i = 0; i < segments; ++i) {
+ for (int i = 0; i < segments; i++) {
float angle = (float)(2 * M_PI) * ((float)i / (float)segments);
float x = f10 * cosf(angle);
float y = f10 * sinf(angle);
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index 9305dc6eef7..75b8d820884 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -20,8 +20,8 @@
* \ingroup draw
*/
-#ifndef __DRAW_CACHE_EXTRACT_MESH_H__
-#define __DRAW_CACHE_EXTRACT_MESH_H__
+#ifndef __DRAW_CACHE_EXTRACT_H__
+#define __DRAW_CACHE_EXTRACT_H__
/* Vertex Group Selection and display options */
typedef struct DRW_MeshWeightState {
@@ -136,8 +136,8 @@ typedef enum DRWBatchFlag {
MBC_EDIT_LNOR = (1 << 6),
MBC_EDIT_FACEDOTS = (1 << 7),
MBC_EDIT_MESH_ANALYSIS = (1 << 8),
- MBC_EDITUV_FACES_STRECH_AREA = (1 << 9),
- MBC_EDITUV_FACES_STRECH_ANGLE = (1 << 10),
+ MBC_EDITUV_FACES_STRETCH_AREA = (1 << 9),
+ MBC_EDITUV_FACES_STRETCH_ANGLE = (1 << 10),
MBC_EDITUV_FACES = (1 << 11),
MBC_EDITUV_EDGES = (1 << 12),
MBC_EDITUV_VERTS = (1 << 13),
@@ -157,7 +157,7 @@ typedef enum DRWBatchFlag {
} DRWBatchFlag;
#define MBC_EDITUV \
- (MBC_EDITUV_FACES_STRECH_AREA | MBC_EDITUV_FACES_STRECH_ANGLE | MBC_EDITUV_FACES | \
+ (MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | \
MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_EDITUV_FACEDOTS | MBC_WIRE_LOOPS_UVS)
#define FOREACH_MESH_BUFFER_CACHE(batch_cache, mbc) \
@@ -183,8 +183,8 @@ typedef struct MeshBatchCache {
GPUBatch *edit_fdots;
GPUBatch *edit_mesh_analysis;
/* Edit UVs */
- GPUBatch *edituv_faces_strech_area;
- GPUBatch *edituv_faces_strech_angle;
+ GPUBatch *edituv_faces_stretch_area;
+ GPUBatch *edituv_faces_stretch_angle;
GPUBatch *edituv_faces;
GPUBatch *edituv_edges;
GPUBatch *edituv_verts;
@@ -234,6 +234,12 @@ typedef struct MeshBatchCache {
/* Valid only if edge_detection is up to date. */
bool is_manifold;
+ /* Total areas for drawing UV Stretching. Contains the summed area in mesh
+ * space (`tot_area`) and the summed area in uv space (`tot_uvarea`).
+ *
+ * Only valid after `DRW_mesh_batch_cache_create_requested` has been called. */
+ float tot_area, tot_uv_area;
+
bool no_loose_wire;
} MeshBatchCache;
@@ -247,4 +253,4 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
const ToolSettings *ts,
const bool use_hide);
-#endif /* __DRAW_CACHE_EXTRACT_MESH_H__ */
+#endif /* __DRAW_CACHE_EXTRACT_H__ */
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c
index b0a0766eedb..40a36acc3d9 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.c
@@ -60,7 +60,6 @@
#include "GPU_batch.h"
#include "GPU_extensions.h"
-#include "GPU_material.h"
#include "DRW_render.h"
@@ -523,7 +522,7 @@ static void extract_tris_finish(const MeshRenderData *mr, void *ibo, void *_data
/* HACK Create ibo subranges and assign them to each GPUBatch. */
if (mr->use_final_mesh && mr->cache->surface_per_mat && mr->cache->surface_per_mat[0]) {
BLI_assert(mr->cache->surface_per_mat[0]->elem == ibo);
- for (int i = 0; i < mr->mat_len; ++i) {
+ for (int i = 0; i < mr->mat_len; i++) {
/* Multiply by 3 because these are triangle indices. */
int start = data->tri_mat_start[i] * 3;
int len = data->tri_mat_end[i] * 3 - data->tri_mat_start[i] * 3;
@@ -950,10 +949,8 @@ BLI_INLINE void lines_adjacency_triangle(
GPUIndexBufBuilder *elb = &data->elb;
/* Iter around the triangle's edges. */
for (int e = 0; e < 3; e++) {
- uint tmp = v1;
- v1 = v2, v2 = v3, v3 = tmp;
- tmp = l1;
- l1 = l2, l2 = l3, l3 = tmp;
+ SHIFT3(uint, v3, v2, v1);
+ SHIFT3(uint, l3, l2, l1);
bool inv_indices = (v2 > v3);
void **pval;
@@ -1186,8 +1183,7 @@ static void extract_edituv_lines_loop_mesh(const MeshRenderData *mr,
{
int loopend = mpoly->totloop + mpoly->loopstart - 1;
int loop_next_idx = (loop_idx == loopend) ? mpoly->loopstart : (loop_idx + 1);
- const bool real_edge = (mr->extract_type == MR_EXTRACT_MAPPED &&
- mr->e_origindex[mloop->e] != ORIGINDEX_NONE);
+ const bool real_edge = (mr->e_origindex == NULL || mr->e_origindex[mloop->e] != ORIGINDEX_NONE);
edituv_edge_add(data,
(mpoly->flag & ME_HIDE) != 0 || !real_edge,
(mpoly->flag & ME_FACE_SEL) != 0,
@@ -1433,7 +1429,7 @@ static void extract_pos_nor_loop_mesh(const MeshRenderData *mr,
int l,
const MLoop *mloop,
int UNUSED(p),
- const MPoly *mpoly,
+ const MPoly *UNUSED(mpoly),
void *_data)
{
MeshExtract_PosNor_Data *data = _data;
@@ -1442,12 +1438,15 @@ static void extract_pos_nor_loop_mesh(const MeshRenderData *mr,
copy_v3_v3(vert->pos, mvert->co);
vert->nor = data->packed_nor[mloop->v];
/* Flag for paint mode overlay. */
- if (mpoly->flag & ME_HIDE)
+ if (mvert->flag & ME_HIDE) {
vert->nor.w = -1;
- else if (mpoly->flag & ME_FACE_SEL)
+ }
+ else if (mvert->flag & SELECT) {
vert->nor.w = 1;
- else
+ }
+ else {
vert->nor.w = 0;
+ }
}
static void extract_pos_nor_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *_data)
@@ -1526,7 +1525,7 @@ static void *extract_lnor_init(const MeshRenderData *mr, void *buf)
{
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
- GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
GPU_vertformat_alias_add(&format, "lnor");
}
GPUVertBuf *vbo = buf;
@@ -1561,6 +1560,16 @@ static void extract_lnor_loop_mesh(
else {
((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(mr->poly_normals[p]);
}
+ /* Flag for paint mode overlay. */
+ if (mpoly->flag & ME_HIDE) {
+ ((GPUPackedNormal *)data)[l].w = -1;
+ }
+ else if (mpoly->flag & ME_FACE_SEL) {
+ ((GPUPackedNormal *)data)[l].w = 1;
+ }
+ else {
+ ((GPUPackedNormal *)data)[l].w = 0;
+ }
}
static const MeshExtract extract_lnor = {
@@ -2577,7 +2586,7 @@ static void *extract_edituv_data_init(const MeshRenderData *mr, void *buf)
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
- CustomData *cd_ldata = &mr->me->ldata;
+ CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
MeshExtract_EditUVData_Data *data = MEM_callocN(sizeof(*data), __func__);
data->vbo_data = (EditLoopData *)vbo->data;
@@ -2663,7 +2672,7 @@ static void *extract_stretch_area_init(const MeshRenderData *mr, void *buf)
{
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
- GPU_vertformat_attr_add(&format, "stretch", GPU_COMP_U16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ GPU_vertformat_attr_add(&format, "ratio", GPU_COMP_U16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
GPUVertBuf *vbo = buf;
@@ -2690,7 +2699,7 @@ BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_t
static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void *UNUSED(data))
{
- float totarea = 0, totuvarea = 0;
+ float tot_area = 0.0f, tot_uv_area = 0.0f;
float *area_ratio = MEM_mallocN(sizeof(float) * mr->poly_len, __func__);
if (mr->extract_type == MR_EXTRACT_BMESH) {
@@ -2703,8 +2712,8 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void *
BM_ITER_MESH_INDEX (efa, &f_iter, mr->bm, BM_FACES_OF_MESH, f) {
float area = BM_face_calc_area(efa);
float uvarea = BM_face_calc_area_uv(efa, uv_ofs);
- totarea += area;
- totuvarea += uvarea;
+ tot_area += area;
+ tot_uv_area += uvarea;
area_ratio[f] = area_ratio_get(area, uvarea);
}
}
@@ -2714,8 +2723,8 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void *
for (int p = 0; p < mr->poly_len; p++, mpoly++) {
float area = BKE_mesh_calc_poly_area(mpoly, &mr->mloop[mpoly->loopstart], mr->mvert);
float uvarea = BKE_mesh_calc_poly_uv_area(mpoly, uv_data);
- totarea += area;
- totuvarea += uvarea;
+ tot_area += area;
+ tot_uv_area += uvarea;
area_ratio[p] = area_ratio_get(area, uvarea);
}
}
@@ -2724,21 +2733,13 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void *
BLI_assert(0);
}
- float tot_ratio, inv_tot_ratio;
- if (totarea < FLT_EPSILON || totuvarea < FLT_EPSILON) {
- tot_ratio = 0.0f;
- inv_tot_ratio = 0.0f;
- }
- else {
- tot_ratio = totarea / totuvarea;
- inv_tot_ratio = totuvarea / totarea;
- }
+ mr->cache->tot_area = tot_area;
+ mr->cache->tot_uv_area = tot_uv_area;
/* Convert in place to avoid an extra allocation */
uint16_t *poly_stretch = (uint16_t *)area_ratio;
for (int p = 0; p < mr->poly_len; p++) {
- float stretch = area_ratio_to_stretch(area_ratio[p], tot_ratio, inv_tot_ratio);
- poly_stretch[p] = (1.0f - stretch) * 65534.0f;
+ poly_stretch[p] = area_ratio[p] * 65534.0f;
}
/* Copy face data for each loop. */
@@ -2809,8 +2810,8 @@ static void compute_normalize_edge_vectors(float auv[2][2],
float av[2][3],
const float uv[2],
const float uv_prev[2],
- const float co[2],
- const float co_prev[2])
+ const float co[3],
+ const float co_prev[3])
{
/* Move previous edge. */
copy_v2_v2(auv[0], auv[1]);
@@ -2973,7 +2974,7 @@ static const MeshExtract extract_stretch_angle = {
NULL,
extract_stretch_angle_finish,
0,
- true,
+ false,
};
/** \} */
@@ -4315,7 +4316,7 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
TaskPool *task_pool;
task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create(task_scheduler, NULL);
+ task_pool = BLI_task_pool_create_suspended(task_scheduler, NULL);
size_t counters_size = (sizeof(mbc) / sizeof(void *)) * sizeof(int32_t);
int32_t *task_counters = MEM_callocN(counters_size, __func__);
@@ -4325,7 +4326,8 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
if (mbc.buf.name) { \
extract_task_create( \
task_pool, mr, &extract_##name, mbc.buf.name, &task_counters[counter_used++]); \
- }
+ } \
+ ((void)0)
EXTRACT(vbo, pos_nor);
EXTRACT(vbo, lnor);
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index 3e33346c7d8..cdc1791b153 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -150,8 +150,10 @@ struct GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(struct Mesh *me);
/* Object mode Wireframe overlays */
struct GPUBatch *DRW_mesh_batch_cache_get_wireframes_face(struct Mesh *me);
/* edit-mesh UV editor */
-struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_area(struct Mesh *me);
-struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_angle(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(struct Mesh *me,
+ float **tot_area,
+ float **tot_uv_area);
+struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(struct Mesh *me);
diff --git a/source/blender/draw/intern/draw_cache_impl_curve.c b/source/blender/draw/intern/draw_cache_impl_curve.c
index 241cd68bc3a..ab800e42cc0 100644
--- a/source/blender/draw/intern/draw_cache_impl_curve.c
+++ b/source/blender/draw/intern/draw_cache_impl_curve.c
@@ -464,7 +464,7 @@ static void curve_batch_cache_init(Curve *cu)
cache->surf_per_mat = MEM_mallocN(sizeof(*cache->surf_per_mat) * cache->mat_len, __func__);
/* TODO Might be wiser to alloc in one chunk. */
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
cache->surf_per_mat_tris[i] = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf");
cache->surf_per_mat[i] = MEM_callocN(sizeof(GPUBatch), "GPUBatch");
}
@@ -516,24 +516,24 @@ static void curve_batch_cache_clear(Curve *cu)
return;
}
- for (int i = 0; i < sizeof(cache->ordered) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->ordered) / sizeof(void *); i++) {
GPUVertBuf **vbo = (GPUVertBuf **)&cache->ordered;
GPU_VERTBUF_DISCARD_SAFE(vbo[i]);
}
- for (int i = 0; i < sizeof(cache->edit) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->edit) / sizeof(void *); i++) {
GPUVertBuf **vbo = (GPUVertBuf **)&cache->edit;
GPU_VERTBUF_DISCARD_SAFE(vbo[i]);
}
- for (int i = 0; i < sizeof(cache->ibo) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->ibo) / sizeof(void *); i++) {
GPUIndexBuf **ibo = (GPUIndexBuf **)&cache->ibo;
GPU_INDEXBUF_DISCARD_SAFE(ibo[i]);
}
- for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); i++) {
GPUBatch **batch = (GPUBatch **)&cache->batch;
GPU_BATCH_DISCARD_SAFE(batch[i]);
}
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
GPU_INDEXBUF_DISCARD_SAFE(cache->surf_per_mat_tris[i]);
GPU_BATCH_DISCARD_SAFE(cache->surf_per_mat[i]);
}
@@ -772,7 +772,7 @@ static void curve_create_edit_data_and_handles(CurveRenderData *rdata,
GPU_indexbuf_add_line_verts(elbp_lines, vbo_len_used + 1, vbo_len_used + 2);
}
if (vbo_data) {
- char vflag[3] = {
+ const char vflag[3] = {
beztriple_vflag_get(rdata, bezt->f1, bezt->h1, a, nu_id),
beztriple_vflag_get(rdata, bezt->f2, bezt->h1, a, nu_id),
beztriple_vflag_get(rdata, bezt->f3, bezt->h2, a, nu_id),
@@ -891,7 +891,7 @@ GPUBatch **DRW_curve_batch_cache_get_surface_shaded(struct Curve *cu,
curve_cd_calc_used_gpu_layers(&cache->cd_needed, gpumat_array, gpumat_array_len);
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
DRW_batch_request(&cache->surf_per_mat[i]);
}
return cache->surf_per_mat;
@@ -929,7 +929,7 @@ void DRW_curve_batch_cache_create_requested(Object *ob)
/* Verify that all surface batches have needed attribute layers. */
/* TODO(fclem): We could be a bit smarter here and only do it per material. */
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
if ((cache->cd_used & cache->cd_needed) != cache->cd_needed) {
/* We can't discard batches at this point as they have been
* referenced for drawing. Just clear them in place. */
@@ -979,7 +979,7 @@ void DRW_curve_batch_cache_create_requested(Object *ob)
if (DRW_batch_requested(cache->batch.edit_normals, GPU_PRIM_LINES)) {
DRW_vbo_request(cache->batch.edit_normals, &cache->edit.curves_nor);
}
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
if (DRW_batch_requested(cache->surf_per_mat[i], GPU_PRIM_TRIS)) {
if (cache->mat_len > 1) {
DRW_ibo_request(cache->surf_per_mat[i], &cache->surf_per_mat_tris[i]);
@@ -1014,7 +1014,7 @@ void DRW_curve_batch_cache_create_requested(Object *ob)
DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.edit_verts_points, CU_DATATYPE_OVERLAY);
DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.edit_lines, CU_DATATYPE_OVERLAY);
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->surf_per_mat_tris[i], CU_DATATYPE_SURFACE);
}
@@ -1080,7 +1080,7 @@ void DRW_curve_batch_cache_create_requested(Object *ob)
#ifdef DEBUG
/* Make sure all requested batches have been setup. */
- for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); i++) {
BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0));
}
#endif
diff --git a/source/blender/draw/intern/draw_cache_impl_lattice.c b/source/blender/draw/intern/draw_cache_impl_lattice.c
index 8b3864684b5..01cd2b52ae3 100644
--- a/source/blender/draw/intern/draw_cache_impl_lattice.c
+++ b/source/blender/draw/intern/draw_cache_impl_lattice.c
@@ -420,7 +420,7 @@ static GPUVertBuf *lattice_batch_cache_get_pos(LatticeRenderData *rdata,
cache->pos = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(cache->pos, vert_len);
- for (int i = 0; i < vert_len; ++i) {
+ for (int i = 0; i < vert_len; i++) {
const BPoint *bp = lattice_render_data_vert_bpoint(rdata, i);
GPU_vertbuf_attr_set(cache->pos, attr_id.pos, i, bp->vec);
@@ -516,7 +516,7 @@ static void lattice_batch_cache_create_overlay_batches(Lattice *lt)
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, vert_len);
- for (int i = 0; i < vert_len; ++i) {
+ for (int i = 0; i < vert_len; i++) {
const BPoint *bp = lattice_render_data_vert_bpoint(rdata, i);
char vflag = 0;
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 884d39343c6..4a69aa3e008 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -55,7 +55,6 @@
#include "bmesh.h"
#include "GPU_batch.h"
-#include "GPU_extensions.h"
#include "GPU_material.h"
#include "DRW_render.h"
@@ -502,14 +501,17 @@ static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache)
GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_points);
GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_fdots);
}
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_strech_area);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_strech_angle);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_area);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_angle);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_edges);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_verts);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_fdots);
GPU_BATCH_DISCARD_SAFE(cache->batch.wire_loops_uvs);
+ cache->tot_area = 0.0f;
+ cache->tot_uv_area = 0.0f;
+
cache->batch_ready &= ~MBC_EDITUV;
}
@@ -549,6 +551,7 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode)
{
GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.lines_paint_mask);
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.pos_nor);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.lnor);
}
GPU_BATCH_DISCARD_SAFE(cache->batch.surface);
GPU_BATCH_DISCARD_SAFE(cache->batch.wire_loops);
@@ -576,8 +579,8 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode)
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edituv_data);
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_edituv_data);
}
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_strech_area);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_strech_angle);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_area);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_angle);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_edges);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_verts);
@@ -599,14 +602,14 @@ static void mesh_batch_cache_clear(Mesh *me)
{
GPUVertBuf **vbos = (GPUVertBuf **)&mbufcache->vbo;
GPUIndexBuf **ibos = (GPUIndexBuf **)&mbufcache->ibo;
- for (int i = 0; i < sizeof(mbufcache->vbo) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(mbufcache->vbo) / sizeof(void *); i++) {
GPU_VERTBUF_DISCARD_SAFE(vbos[i]);
}
- for (int i = 0; i < sizeof(mbufcache->ibo) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(mbufcache->ibo) / sizeof(void *); i++) {
GPU_INDEXBUF_DISCARD_SAFE(ibos[i]);
}
}
- for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); i++) {
GPUBatch **batch = (GPUBatch **)&cache->batch;
GPU_BATCH_DISCARD_SAFE(batch[i]);
}
@@ -752,7 +755,7 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me,
*auto_layer_is_srgb = cache->auto_layer_is_srgb;
*auto_layer_count = cache->auto_layer_len;
}
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
DRW_batch_request(&cache->surface_per_mat[i]);
}
return cache->surface_per_mat;
@@ -763,7 +766,7 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(Mesh *me)
MeshBatchCache *cache = mesh_batch_cache_get(me);
mesh_batch_cache_add_request(cache, MBC_SURF_PER_MAT);
texpaint_request_active_uv(cache, me);
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
DRW_batch_request(&cache->surface_per_mat[i]);
}
return cache->surface_per_mat;
@@ -873,20 +876,34 @@ GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(Mesh *me)
/** \name UV Image editor API
* \{ */
-GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_area(Mesh *me)
+/* Creates the GPUBatch for drawing the UV Stretching Area Overlay.
+ * Optional retrieves the total area or total uv area of the mesh.
+ *
+ * The `cache->tot_area` and cache->tot_uv_area` update are calculation are
+ * only valid after calling `DRW_mesh_batch_cache_create_requested`. */
+GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Mesh *me,
+ float **tot_area,
+ float **tot_uv_area)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
texpaint_request_active_uv(cache, me);
- mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRECH_AREA);
- return DRW_batch_request(&cache->batch.edituv_faces_strech_area);
+ mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_AREA);
+
+ if (tot_area != NULL) {
+ *tot_area = &cache->tot_area;
+ }
+ if (tot_uv_area != NULL) {
+ *tot_uv_area = &cache->tot_uv_area;
+ }
+ return DRW_batch_request(&cache->batch.edituv_faces_stretch_area);
}
-GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_angle(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
texpaint_request_active_uv(cache, me);
- mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRECH_ANGLE);
- return DRW_batch_request(&cache->batch.edituv_faces_strech_angle);
+ mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_ANGLE);
+ return DRW_batch_request(&cache->batch.edituv_faces_stretch_angle);
}
GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(Mesh *me)
@@ -999,12 +1016,37 @@ void DRW_mesh_batch_cache_create_requested(
}
}
+ /* HACK: if MBC_SURF_PER_MAT is requested and ibo.tris is already available, it won't have it's
+ * index ranges initialized. So discard ibo.tris in order to recreate it.
+ * This needs to happen before saved_elem_ranges is populated. */
+ if ((batch_requested & MBC_SURF_PER_MAT) != 0 && (cache->batch_ready & MBC_SURF_PER_MAT) == 0) {
+ FOREACH_MESH_BUFFER_CACHE(cache, mbuffercache)
+ {
+ GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.tris);
+ }
+ /* Clear all batches that reference ibo.tris. */
+ GPU_BATCH_CLEAR_SAFE(cache->batch.surface);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.surface_weights);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edit_mesh_analysis);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edit_triangles);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edit_lnor);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edit_selection_faces);
+ for (int i = 0; i < cache->mat_len; i++) {
+ GPU_BATCH_CLEAR_SAFE(cache->surface_per_mat[i]);
+ }
+
+ cache->batch_ready &= ~(MBC_SURFACE | MBC_SURFACE_WEIGHTS | MBC_EDIT_MESH_ANALYSIS |
+ MBC_EDIT_TRIANGLES | MBC_EDIT_LNOR | MBC_EDIT_SELECTION_FACES);
+ }
+
if (batch_requested &
- (MBC_SURFACE | MBC_SURF_PER_MAT | MBC_WIRE_LOOPS_UVS | MBC_EDITUV_FACES_STRECH_AREA |
- MBC_EDITUV_FACES_STRECH_ANGLE | MBC_EDITUV_FACES | MBC_EDITUV_EDGES | MBC_EDITUV_VERTS)) {
+ (MBC_SURFACE | MBC_SURF_PER_MAT | MBC_WIRE_LOOPS_UVS | MBC_EDITUV_FACES_STRETCH_AREA |
+ MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | MBC_EDITUV_EDGES | MBC_EDITUV_VERTS)) {
/* Modifiers will only generate an orco layer if the mesh is deformed. */
if (cache->cd_needed.orco != 0) {
- if (CustomData_get_layer(&me->vdata, CD_ORCO) == NULL) {
+ /* Orco is always extracted from final mesh. */
+ Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me;
+ if (CustomData_get_layer(&me_final->vdata, CD_ORCO) == NULL) {
/* Skip orco calculation */
cache->cd_needed.orco = 0;
}
@@ -1036,7 +1078,7 @@ void DRW_mesh_batch_cache_create_requested(
* This is only if the cd_needed changes so it is ok to keep them.*/
if (cache->surface_per_mat[0] && cache->surface_per_mat[0]->elem) {
saved_elem_ranges = MEM_callocN(sizeof(saved_elem_ranges) * cache->mat_len, __func__);
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
saved_elem_ranges[i] = cache->surface_per_mat[i]->elem;
/* Avoid deletion as the batch is owner. */
cache->surface_per_mat[i]->elem = NULL;
@@ -1045,7 +1087,7 @@ void DRW_mesh_batch_cache_create_requested(
}
/* We can't discard batches at this point as they have been
* referenced for drawing. Just clear them in place. */
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
GPU_BATCH_CLEAR_SAFE(cache->surface_per_mat[i]);
}
GPU_BATCH_CLEAR_SAFE(cache->batch.surface);
@@ -1077,8 +1119,8 @@ void DRW_mesh_batch_cache_create_requested(
/* We only clear the batches as they may already have been
* referenced. */
GPU_BATCH_CLEAR_SAFE(cache->batch.wire_loops_uvs);
- GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_strech_area);
- GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_strech_angle);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_stretch_area);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_stretch_angle);
GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces);
GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_edges);
GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_verts);
@@ -1140,6 +1182,8 @@ void DRW_mesh_batch_cache_create_requested(
}
if (DRW_batch_requested(cache->batch.wire_loops, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.wire_loops, &mbufcache->ibo.lines_paint_mask);
+ /* Order matters. First ones override latest vbos' attribs. */
+ DRW_vbo_request(cache->batch.wire_loops, &mbufcache->vbo.lnor);
DRW_vbo_request(cache->batch.wire_loops, &mbufcache->vbo.pos_nor);
}
if (DRW_batch_requested(cache->batch.wire_edges, GPU_PRIM_LINES)) {
@@ -1161,7 +1205,7 @@ void DRW_mesh_batch_cache_create_requested(
}
/* Per Material */
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
if (DRW_batch_requested(cache->surface_per_mat[i], GPU_PRIM_TRIS)) {
if (saved_elem_ranges && saved_elem_ranges[i]) {
/* XXX assign old element buffer range (it did not change).*/
@@ -1258,17 +1302,17 @@ void DRW_mesh_batch_cache_create_requested(
DRW_vbo_request(cache->batch.edituv_faces, &mbufcache->vbo.uv);
DRW_vbo_request(cache->batch.edituv_faces, &mbufcache->vbo.edituv_data);
}
- if (DRW_batch_requested(cache->batch.edituv_faces_strech_area, GPU_PRIM_TRIS)) {
- DRW_ibo_request(cache->batch.edituv_faces_strech_area, &mbufcache->ibo.edituv_tris);
- DRW_vbo_request(cache->batch.edituv_faces_strech_area, &mbufcache->vbo.uv);
- DRW_vbo_request(cache->batch.edituv_faces_strech_area, &mbufcache->vbo.edituv_data);
- DRW_vbo_request(cache->batch.edituv_faces_strech_area, &mbufcache->vbo.stretch_area);
+ if (DRW_batch_requested(cache->batch.edituv_faces_stretch_area, GPU_PRIM_TRIS)) {
+ DRW_ibo_request(cache->batch.edituv_faces_stretch_area, &mbufcache->ibo.edituv_tris);
+ DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbufcache->vbo.uv);
+ DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbufcache->vbo.edituv_data);
+ DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbufcache->vbo.stretch_area);
}
- if (DRW_batch_requested(cache->batch.edituv_faces_strech_angle, GPU_PRIM_TRIS)) {
- DRW_ibo_request(cache->batch.edituv_faces_strech_angle, &mbufcache->ibo.edituv_tris);
- DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &mbufcache->vbo.uv);
- DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &mbufcache->vbo.edituv_data);
- DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &mbufcache->vbo.stretch_angle);
+ if (DRW_batch_requested(cache->batch.edituv_faces_stretch_angle, GPU_PRIM_TRIS)) {
+ DRW_ibo_request(cache->batch.edituv_faces_stretch_angle, &mbufcache->ibo.edituv_tris);
+ DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbufcache->vbo.uv);
+ DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbufcache->vbo.edituv_data);
+ DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbufcache->vbo.stretch_angle);
}
if (DRW_batch_requested(cache->batch.edituv_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.edituv_edges, &mbufcache->ibo.edituv_lines);
@@ -1305,25 +1349,25 @@ void DRW_mesh_batch_cache_create_requested(
#ifdef DEBUG
check:
/* Make sure all requested batches have been setup. */
- for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); i++) {
BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0));
}
- for (int i = 0; i < sizeof(cache->final.vbo) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->final.vbo) / sizeof(void *); i++) {
BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->final.vbo)[i]));
}
- for (int i = 0; i < sizeof(cache->final.ibo) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->final.ibo) / sizeof(void *); i++) {
BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->final.ibo)[i]));
}
- for (int i = 0; i < sizeof(cache->cage.vbo) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->cage.vbo) / sizeof(void *); i++) {
BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->cage.vbo)[i]));
}
- for (int i = 0; i < sizeof(cache->cage.ibo) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->cage.ibo) / sizeof(void *); i++) {
BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->cage.ibo)[i]));
}
- for (int i = 0; i < sizeof(cache->uv_cage.vbo) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->uv_cage.vbo) / sizeof(void *); i++) {
BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->uv_cage.vbo)[i]));
}
- for (int i = 0; i < sizeof(cache->uv_cage.ibo) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->uv_cage.ibo) / sizeof(void *); i++) {
BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->uv_cage.ibo)[i]));
}
#endif
diff --git a/source/blender/draw/intern/draw_cache_impl_metaball.c b/source/blender/draw/intern/draw_cache_impl_metaball.c
index 60f15338412..e3bfcbde3ef 100644
--- a/source/blender/draw/intern/draw_cache_impl_metaball.c
+++ b/source/blender/draw/intern/draw_cache_impl_metaball.c
@@ -212,7 +212,7 @@ GPUBatch **DRW_metaball_batch_cache_get_surface_shaded(Object *ob,
cache->shaded_triangles = MEM_callocN(sizeof(*cache->shaded_triangles) * cache->mat_len,
__func__);
cache->shaded_triangles[0] = DRW_metaball_batch_cache_get_triangles_with_normals(ob);
- for (int i = 1; i < cache->mat_len; ++i) {
+ for (int i = 1; i < cache->mat_len; i++) {
cache->shaded_triangles[i] = NULL;
}
}
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
index 6cd03d14bfd..3c586e6daec 100644
--- a/source/blender/draw/intern/draw_cache_impl_particles.c
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -190,18 +190,18 @@ static void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache)
DRW_TEXTURE_FREE_SAFE(hair_cache->strand_tex);
DRW_TEXTURE_FREE_SAFE(hair_cache->strand_seg_tex);
- for (int i = 0; i < MAX_MTFACE; ++i) {
+ for (int i = 0; i < MAX_MTFACE; i++) {
GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_uv_buf[i]);
DRW_TEXTURE_FREE_SAFE(hair_cache->uv_tex[i]);
}
- for (int i = 0; i < MAX_MCOL; ++i) {
+ for (int i = 0; i < MAX_MCOL; i++) {
GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_col_buf[i]);
DRW_TEXTURE_FREE_SAFE(hair_cache->col_tex[i]);
}
- for (int i = 0; i < MAX_HAIR_SUBDIV; ++i) {
+ for (int i = 0; i < MAX_HAIR_SUBDIV; i++) {
GPU_VERTBUF_DISCARD_SAFE(hair_cache->final[i].proc_buf);
DRW_TEXTURE_FREE_SAFE(hair_cache->final[i].proc_tex);
- for (int j = 0; j < MAX_THICKRES; ++j) {
+ for (int j = 0; j < MAX_THICKRES; j++) {
GPU_BATCH_DISCARD_SAFE(hair_cache->final[i].proc_hairs[j]);
}
}
@@ -1335,15 +1335,6 @@ static void particle_batch_cache_ensure_pos(Object *object,
sim.psmd = psys_get_modifier(object, psys);
sim.psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
- if (psys->part->phystype == PART_PHYS_KEYED) {
- if (psys->flag & PSYS_KEYED) {
- psys_count_keyed_targets(&sim);
- if (psys->totkeyed == 0) {
- return;
- }
- }
- }
-
GPU_VERTBUF_DISCARD_SAFE(point_cache->pos);
if (format.attr_len == 0) {
@@ -1551,6 +1542,9 @@ static void ensure_edit_inner_points_count(const PTCacheEdit *edit, ParticleBatc
cache->edit_inner_point_len = 0;
for (int point_index = 0; point_index < edit->totpoint; point_index++) {
const PTCacheEditPoint *point = &edit->points[point_index];
+ if (point->flag & PEP_HIDE) {
+ continue;
+ }
BLI_assert(point->totkey >= 1);
cache->edit_inner_point_len += (point->totkey - 1);
}
@@ -1572,6 +1566,9 @@ static void particle_batch_cache_ensure_edit_inner_pos(PTCacheEdit *edit,
int global_key_index = 0;
for (int point_index = 0; point_index < edit->totpoint; point_index++) {
const PTCacheEditPoint *point = &edit->points[point_index];
+ if (point->flag & PEP_HIDE) {
+ continue;
+ }
for (int key_index = 0; key_index < point->totkey - 1; key_index++) {
PTCacheEditKey *key = &point->keys[key_index];
float color = (key->flag & PEK_SELECT) ? 1.0f : 0.0f;
@@ -1602,7 +1599,14 @@ static void ensure_edit_tip_points_count(const PTCacheEdit *edit, ParticleBatchC
if (cache->edit_tip_pos != NULL) {
return;
}
- cache->edit_tip_point_len = edit->totpoint;
+ cache->edit_tip_point_len = 0;
+ for (int point_index = 0; point_index < edit->totpoint; point_index++) {
+ const PTCacheEditPoint *point = &edit->points[point_index];
+ if (point->flag & PEP_HIDE) {
+ continue;
+ }
+ cache->edit_tip_point_len += 1;
+ }
}
static void particle_batch_cache_ensure_edit_tip_pos(PTCacheEdit *edit, ParticleBatchCache *cache)
@@ -1617,13 +1621,18 @@ static void particle_batch_cache_ensure_edit_tip_pos(PTCacheEdit *edit, Particle
cache->edit_tip_pos = GPU_vertbuf_create_with_format(edit_point_format);
GPU_vertbuf_data_alloc(cache->edit_tip_pos, cache->edit_tip_point_len);
+ int global_point_index = 0;
for (int point_index = 0; point_index < edit->totpoint; point_index++) {
const PTCacheEditPoint *point = &edit->points[point_index];
+ if (point->flag & PEP_HIDE) {
+ continue;
+ }
PTCacheEditKey *key = &point->keys[point->totkey - 1];
float color = (key->flag & PEK_SELECT) ? 1.0f : 0.0f;
- GPU_vertbuf_attr_set(cache->edit_tip_pos, pos_id, point_index, key->world_co);
- GPU_vertbuf_attr_set(cache->edit_tip_pos, color_id, point_index, &color);
+ GPU_vertbuf_attr_set(cache->edit_tip_pos, pos_id, global_point_index, key->world_co);
+ GPU_vertbuf_attr_set(cache->edit_tip_pos, color_id, global_point_index, &color);
+ global_point_index++;
}
}
diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c
index ac3e7e4ce67..7f679dd5581 100644
--- a/source/blender/draw/intern/draw_common.c
+++ b/source/blender/draw/intern/draw_common.c
@@ -243,6 +243,7 @@ extern char datatoc_gpu_shader_point_varying_color_frag_glsl[];
extern char datatoc_object_mball_handles_vert_glsl[];
extern char datatoc_object_empty_axes_vert_glsl[];
+extern char datatoc_object_color_axes_vert_glsl[];
typedef struct COMMON_Shaders {
struct GPUShader *shape_outline;
@@ -262,6 +263,7 @@ typedef struct COMMON_Shaders {
struct GPUShader *volume_velocity_needle_sh;
struct GPUShader *volume_velocity_sh;
struct GPUShader *empty_axes_sh;
+ struct GPUShader *color_axes_sh;
struct GPUShader *mball_handles;
} COMMON_Shaders;
@@ -294,13 +296,13 @@ static struct {
void DRW_globals_free(void)
{
struct GPUVertFormat **format = &g_formats.instance_screenspace;
- for (int i = 0; i < sizeof(g_formats) / sizeof(void *); ++i, ++format) {
+ for (int i = 0; i < sizeof(g_formats) / sizeof(void *); i++, format++) {
MEM_SAFE_FREE(*format);
}
for (int j = 0; j < GPU_SHADER_CFG_LEN; j++) {
struct GPUShader **shader = &g_shaders[j].shape_outline;
- for (int i = 0; i < sizeof(g_shaders[j]) / sizeof(void *); ++i, ++shader) {
+ for (int i = 0; i < sizeof(g_shaders[j]) / sizeof(void *); i++, shader++) {
DRW_SHADER_FREE_SAFE(*shader);
}
}
@@ -549,6 +551,37 @@ struct DRWCallBuffer *buffer_instance_empty_axes(DRWPass *pass,
return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_sized, geom);
}
+struct DRWCallBuffer *buffer_instance_color_axes(DRWPass *pass,
+ struct GPUBatch *geom,
+ DRWShadingGroup **r_grp,
+ eGPUShaderConfig sh_cfg)
+{
+ COMMON_Shaders *sh_data = &g_shaders[sh_cfg];
+ if (sh_data->color_axes_sh == NULL) {
+ const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
+ sh_data->color_axes_sh = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg_data->lib, datatoc_object_color_axes_vert_glsl, NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, NULL},
+ });
+ }
+
+ DRW_shgroup_instance_format(g_formats.instance_sized,
+ {
+ {"color", DRW_ATTR_FLOAT, 3},
+ {"size", DRW_ATTR_FLOAT, 1},
+ {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16},
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_create(sh_data->color_axes_sh, pass);
+ DRW_shgroup_uniform_vec3(grp, "screenVecs[0]", DRW_viewport_screenvecs_get(), 2);
+ if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
+ DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
+ }
+ *r_grp = grp;
+ return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_sized, geom);
+}
+
struct DRWCallBuffer *buffer_instance_outline(DRWPass *pass,
struct GPUBatch *geom,
const int *baseid,
@@ -1062,7 +1095,7 @@ struct GPUShader *volume_velocity_shader_get(bool use_needle)
NULL,
datatoc_gpu_shader_flat_color_frag_glsl,
datatoc_common_view_lib_glsl,
- "#define USE_NEEDLE");
+ "#define USE_NEEDLE\n");
}
return sh_data->volume_velocity_needle_sh;
}
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index 8e6b8895dd3..9899b6c0194 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -160,6 +160,10 @@ struct DRWCallBuffer *buffer_instance_screen_aligned(struct DRWPass *pass,
struct DRWCallBuffer *buffer_instance_empty_axes(struct DRWPass *pass,
struct GPUBatch *geom,
eGPUShaderConfig sh_cfg);
+struct DRWCallBuffer *buffer_instance_color_axes(struct DRWPass *pass,
+ struct GPUBatch *geom,
+ struct DRWShadingGroup **r_grp,
+ eGPUShaderConfig sh_cfg);
struct DRWCallBuffer *buffer_instance_scaled(struct DRWPass *pass,
struct GPUBatch *geom,
eGPUShaderConfig sh_cfg);
diff --git a/source/blender/draw/intern/draw_debug.c b/source/blender/draw/intern/draw_debug.c
index 9681ffd9d3d..6b05bb07c0f 100644
--- a/source/blender/draw/intern/draw_debug.c
+++ b/source/blender/draw/intern/draw_debug.c
@@ -63,7 +63,7 @@ void DRW_debug_polygon_v3(const float (*v)[3], const int vert_len, const float c
{
BLI_assert(vert_len > 1);
- for (int i = 0; i < vert_len; ++i) {
+ for (int i = 0; i < vert_len; i++) {
DRW_debug_line_v3v3(v[i], v[(i + 1) % vert_len], color);
}
}
@@ -117,7 +117,7 @@ void DRW_debug_m4_as_bbox(const float m[4][4], const float color[4], const bool
}
BKE_boundbox_init_from_minmax(&bb, min, max);
- for (int i = 0; i < 8; ++i) {
+ for (int i = 0; i < 8; i++) {
mul_project_m4_v3(project_matrix, bb.vec[i]);
}
DRW_debug_bbox(&bb, color);
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
index 44ed01c47aa..58085cf08c6 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.c
@@ -151,13 +151,13 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
}
/* TODO optimize this. Only bind the ones GPUMaterial needs. */
- for (int i = 0; i < hair_cache->num_uv_layers; ++i) {
- for (int n = 0; n < MAX_LAYER_NAME_CT && hair_cache->uv_layer_names[i][n][0] != '\0'; ++n) {
+ for (int i = 0; i < hair_cache->num_uv_layers; i++) {
+ for (int n = 0; n < MAX_LAYER_NAME_CT && hair_cache->uv_layer_names[i][n][0] != '\0'; n++) {
DRW_shgroup_uniform_texture(shgrp, hair_cache->uv_layer_names[i][n], hair_cache->uv_tex[i]);
}
}
- for (int i = 0; i < hair_cache->num_col_layers; ++i) {
- for (int n = 0; n < MAX_LAYER_NAME_CT && hair_cache->col_layer_names[i][n][0] != '\0'; ++n) {
+ for (int i = 0; i < hair_cache->num_col_layers; i++) {
+ for (int n = 0; n < MAX_LAYER_NAME_CT && hair_cache->col_layer_names[i][n][0] != '\0'; n++) {
DRW_shgroup_uniform_texture(
shgrp, hair_cache->col_layer_names[i][n], hair_cache->col_tex[i]);
}
@@ -201,30 +201,33 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
/* Transform Feedback subdiv. */
if (need_ft_update) {
int final_points_len = hair_cache->final[subdiv].strands_res * hair_cache->strands_len;
- GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM);
+ if (final_points_len) {
+ GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM);
#ifdef USE_TRANSFORM_FEEDBACK
- DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create(
- tf_shader, g_tf_pass, hair_cache->final[subdiv].proc_buf);
+ DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create(
+ tf_shader, g_tf_pass, hair_cache->final[subdiv].proc_buf);
#else
- DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass);
-
- ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__);
- pr_call->next = g_tf_calls;
- pr_call->vbo = hair_cache->final[subdiv].proc_buf;
- pr_call->shgrp = tf_shgrp;
- pr_call->vert_len = final_points_len;
- g_tf_calls = pr_call;
- DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1);
- DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1);
- DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1);
+ DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass);
+
+ ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__);
+ pr_call->next = g_tf_calls;
+ pr_call->vbo = hair_cache->final[subdiv].proc_buf;
+ pr_call->shgrp = tf_shgrp;
+ pr_call->vert_len = final_points_len;
+ g_tf_calls = pr_call;
+ DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1);
+ DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1);
+ DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1);
#endif
- DRW_shgroup_uniform_texture(tf_shgrp, "hairPointBuffer", hair_cache->point_tex);
- DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", hair_cache->strand_tex);
- DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandSegBuffer", hair_cache->strand_seg_tex);
- DRW_shgroup_uniform_int(tf_shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1);
- DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len);
+ DRW_shgroup_uniform_texture(tf_shgrp, "hairPointBuffer", hair_cache->point_tex);
+ DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", hair_cache->strand_tex);
+ DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandSegBuffer", hair_cache->strand_seg_tex);
+ DRW_shgroup_uniform_int(
+ tf_shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1);
+ DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len);
+ }
}
return shgrp;
@@ -323,7 +326,7 @@ void DRW_hair_update(void)
void DRW_hair_free(void)
{
- for (int i = 0; i < PART_REFINE_MAX_SHADER; ++i) {
+ for (int i = 0; i < PART_REFINE_MAX_SHADER; i++) {
DRW_SHADER_FREE_SAFE(g_refine_shaders[i]);
}
}
diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c
index 8f26cc72a02..81b10e095c3 100644
--- a/source/blender/draw/intern/draw_instance_data.c
+++ b/source/blender/draw/intern/draw_instance_data.c
@@ -64,7 +64,7 @@ typedef struct DRWTempBufferHandle {
/** Format pointer for reuse. */
GPUVertFormat *format;
/** Touched vertex length for resize. */
- uint *vert_len;
+ int *vert_len;
} DRWTempBufferHandle;
static ListBase g_idatalists = {NULL, NULL};
@@ -112,7 +112,7 @@ static void instance_batch_free(GPUBatch *geom, void *UNUSED(user_data))
*/
GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist,
GPUVertFormat *format,
- uint *vert_len)
+ int *vert_len)
{
BLI_assert(format != NULL);
BLI_assert(vert_len != NULL);
@@ -298,7 +298,7 @@ void DRW_instance_data_list_free(DRWInstanceDataList *idatalist)
{
DRWInstanceData *idata, *next_idata;
- for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) {
+ for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; i++) {
for (idata = idatalist->idata_head[i]; idata; idata = next_idata) {
next_idata = idata->next;
DRW_instance_data_free(idata);
@@ -319,7 +319,7 @@ void DRW_instance_data_list_reset(DRWInstanceDataList *idatalist)
{
DRWInstanceData *idata;
- for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) {
+ for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; i++) {
for (idata = idatalist->idata_head[i]; idata; idata = idata->next) {
idata->used = false;
}
@@ -331,7 +331,7 @@ void DRW_instance_data_list_free_unused(DRWInstanceDataList *idatalist)
DRWInstanceData *idata, *next_idata;
/* Remove unused data blocks and sanitize each list. */
- for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) {
+ for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; i++) {
idatalist->idata_tail[i] = NULL;
for (idata = idatalist->idata_head[i]; idata; idata = next_idata) {
next_idata = idata->next;
@@ -360,7 +360,7 @@ void DRW_instance_data_list_resize(DRWInstanceDataList *idatalist)
{
DRWInstanceData *idata;
- for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) {
+ for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; i++) {
for (idata = idatalist->idata_head[i]; idata; idata = idata->next) {
BLI_mempool_clear_ex(idata->mempool, BLI_mempool_len(idata->mempool));
}
diff --git a/source/blender/draw/intern/draw_instance_data.h b/source/blender/draw/intern/draw_instance_data.h
index 2ede68e16d8..524c4cd96d8 100644
--- a/source/blender/draw/intern/draw_instance_data.h
+++ b/source/blender/draw/intern/draw_instance_data.h
@@ -40,7 +40,7 @@ DRWInstanceData *DRW_instance_data_request(DRWInstanceDataList *idatalist, uint
GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist,
GPUVertFormat *format,
- uint *vert_len);
+ int *vert_len);
GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist,
GPUVertBuf *buf,
GPUBatch *geom);
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 3d8a7bb1e30..6387cecc01f 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -33,6 +33,7 @@
#include "BKE_anim.h"
#include "BKE_colortools.h"
+#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_editmesh.h"
#include "BKE_global.h"
@@ -41,6 +42,7 @@
#include "BKE_main.h"
#include "BKE_mball.h"
#include "BKE_mesh.h"
+#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_paint.h"
@@ -65,7 +67,6 @@
#include "GPU_uniformbuffer.h"
#include "GPU_viewport.h"
#include "GPU_matrix.h"
-#include "GPU_select.h"
#include "IMB_colormanagement.h"
@@ -98,10 +99,6 @@
#include "DRW_select_buffer.h"
-#ifdef USE_GPU_SELECT
-# include "GPU_select.h"
-#endif
-
/** Render State: No persistent data between draw calls. */
DRWManager DST = {NULL};
@@ -540,8 +537,11 @@ static void drw_viewport_cache_resize(void)
GPU_texture_free(*tex);
}
- BLI_memblock_clear(DST.vmempool->calls, NULL);
- BLI_memblock_clear(DST.vmempool->states, NULL);
+ BLI_memblock_clear(DST.vmempool->commands, NULL);
+ BLI_memblock_clear(DST.vmempool->commands_small, NULL);
+ BLI_memblock_clear(DST.vmempool->callbuffers, NULL);
+ BLI_memblock_clear(DST.vmempool->obmats, NULL);
+ BLI_memblock_clear(DST.vmempool->obinfos, NULL);
BLI_memblock_clear(DST.vmempool->cullstates, NULL);
BLI_memblock_clear(DST.vmempool->shgroups, NULL);
BLI_memblock_clear(DST.vmempool->uniforms, NULL);
@@ -589,28 +589,28 @@ static void drw_context_state_init(void)
}
}
-static DRWCallState *draw_unit_state_create(void)
+static void draw_unit_state_create(void)
{
- DRWCallState *state = BLI_memblock_alloc(DST.vmempool->states);
- state->flag = 0;
- state->matflag = 0;
+ DRWObjectInfos *infos = BLI_memblock_alloc(DST.vmempool->obinfos);
+ DRWObjectMatrix *mats = BLI_memblock_alloc(DST.vmempool->obmats);
+ DRWCullingState *culling = BLI_memblock_alloc(DST.vmempool->cullstates);
- unit_m4(state->model);
- unit_m4(state->modelinverse);
+ unit_m4(mats->model);
+ unit_m4(mats->modelinverse);
- copy_v3_fl(state->orcotexfac[0], 0.0f);
- copy_v3_fl(state->orcotexfac[1], 1.0f);
+ copy_v3_fl(infos->orcotexfac[0], 0.0f);
+ copy_v3_fl(infos->orcotexfac[1], 1.0f);
- state->ob_index = 0;
- state->ob_random = 0.0f;
- copy_v3_fl(state->ob_color, 1.0f);
+ infos->ob_index = 0;
+ infos->ob_random = 0.0f;
+ infos->ob_neg_scale = 1.0f;
+ copy_v3_fl(infos->ob_color, 1.0f);
/* TODO(fclem) get rid of this. */
- state->culling = BLI_memblock_alloc(DST.vmempool->cullstates);
- state->culling->bsphere.radius = -1.0f;
- state->culling->user_data = NULL;
+ culling->bsphere.radius = -1.0f;
+ culling->user_data = NULL;
- return state;
+ DRW_handle_increment(&DST.resource_handle);
}
/* It also stores viewport variable to an immutable place: DST
@@ -635,33 +635,48 @@ static void drw_viewport_var_init(void)
DST.vmempool = GPU_viewport_mempool_get(DST.viewport);
- if (DST.vmempool->calls == NULL) {
- DST.vmempool->calls = BLI_memblock_create(sizeof(DRWCall));
+ if (DST.vmempool->commands == NULL) {
+ DST.vmempool->commands = BLI_memblock_create(sizeof(DRWCommandChunk));
+ }
+ if (DST.vmempool->commands_small == NULL) {
+ DST.vmempool->commands_small = BLI_memblock_create(sizeof(DRWCommandSmallChunk));
+ }
+ if (DST.vmempool->callbuffers == NULL) {
+ DST.vmempool->callbuffers = BLI_memblock_create(sizeof(DRWCallBuffer));
+ }
+ if (DST.vmempool->obmats == NULL) {
+ uint chunk_len = sizeof(DRWObjectMatrix) * DRW_RESOURCE_CHUNK_LEN;
+ DST.vmempool->obmats = BLI_memblock_create_ex(sizeof(DRWObjectMatrix), chunk_len);
}
- if (DST.vmempool->states == NULL) {
- DST.vmempool->states = BLI_memblock_create(sizeof(DRWCallState));
+ if (DST.vmempool->obinfos == NULL) {
+ uint chunk_len = sizeof(DRWObjectInfos) * DRW_RESOURCE_CHUNK_LEN;
+ DST.vmempool->obinfos = BLI_memblock_create_ex(sizeof(DRWObjectInfos), chunk_len);
}
if (DST.vmempool->cullstates == NULL) {
- DST.vmempool->cullstates = BLI_memblock_create(sizeof(DRWCullingState));
+ uint chunk_len = sizeof(DRWCullingState) * DRW_RESOURCE_CHUNK_LEN;
+ DST.vmempool->cullstates = BLI_memblock_create_ex(sizeof(DRWCullingState), chunk_len);
}
if (DST.vmempool->shgroups == NULL) {
DST.vmempool->shgroups = BLI_memblock_create(sizeof(DRWShadingGroup));
}
if (DST.vmempool->uniforms == NULL) {
- DST.vmempool->uniforms = BLI_memblock_create(sizeof(DRWUniform));
+ DST.vmempool->uniforms = BLI_memblock_create(sizeof(DRWUniformChunk));
}
if (DST.vmempool->views == NULL) {
DST.vmempool->views = BLI_memblock_create(sizeof(DRWView));
}
if (DST.vmempool->passes == NULL) {
- DST.vmempool->passes = BLI_memblock_create(sizeof(DRWPass));
+ uint chunk_len = sizeof(DRWPass) * DRW_RESOURCE_CHUNK_LEN;
+ DST.vmempool->passes = BLI_memblock_create_ex(sizeof(DRWPass), chunk_len);
}
if (DST.vmempool->images == NULL) {
DST.vmempool->images = BLI_memblock_create(sizeof(GPUTexture *));
}
- /* Alloc default unit state */
- DST.unit_state = draw_unit_state_create();
+ DST.resource_handle = 0;
+ DST.pass_handle = 0;
+
+ draw_unit_state_create();
DST.idatalist = GPU_viewport_instance_data_list_get(DST.viewport);
DRW_instance_data_list_reset(DST.idatalist);
@@ -675,8 +690,6 @@ static void drw_viewport_var_init(void)
DST.default_framebuffer = NULL;
DST.vmempool = NULL;
-
- DST.unit_state = NULL;
}
DST.primary_view_ct = 0;
@@ -719,6 +732,10 @@ static void drw_viewport_var_init(void)
G_draw.view_ubo = DRW_uniformbuffer_create(sizeof(DRWViewUboStorage), NULL);
}
+ if (DST.draw_list == NULL) {
+ DST.draw_list = GPU_draw_list_create(DRW_DRAWLIST_LEN);
+ }
+
memset(DST.object_instance_data, 0x0, sizeof(DST.object_instance_data));
}
@@ -1023,7 +1040,7 @@ void DRW_cache_free_old_batches(Main *bmain)
for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, false);
if (depsgraph == NULL) {
continue;
}
@@ -1102,7 +1119,7 @@ static void drw_engines_world_update(Scene *scene)
static void drw_engines_cache_populate(Object *ob)
{
- DST.ob_state = NULL;
+ DST.ob_handle = 0;
/* HACK: DrawData is copied by COW from the duplicated object.
* This is valid for IDs that cannot be instantiated but this
@@ -1548,6 +1565,20 @@ void DRW_draw_view(const bContext *C)
DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, viewport, C);
}
+static bool is_object_visible_in_viewport(View3D *v3d, Object *ob)
+{
+ if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) {
+ return false;
+ }
+
+ if ((v3d->flag & V3D_LOCAL_COLLECTIONS) &&
+ ((v3d->local_collections_uuid & ob->runtime.local_collections_bits) == 0)) {
+ return false;
+ }
+
+ return true;
+}
+
/**
* Used for both regular and off-screen drawing.
* Need to reset DST before calling this function
@@ -1623,7 +1654,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
if ((object_type_exclude_viewport & (1 << ob->type)) != 0) {
continue;
}
- if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) {
+ if (!is_object_visible_in_viewport(v3d, ob)) {
continue;
}
DST.dupli_parent = data_.dupli_parent;
@@ -1766,7 +1797,9 @@ void DRW_draw_render_loop(struct Depsgraph *depsgraph,
DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, viewport, NULL);
}
-/* @viewport CAN be NULL, in this case we create one. */
+/**
+ * \param viewport: can be NULL, in this case we create one.
+ */
void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
RenderEngineType *engine_type,
ARegion *ar,
@@ -1904,6 +1937,8 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph
RenderResult *render_result = RE_engine_get_result(engine);
RenderLayer *render_layer = RE_GetRenderLayer(render_result, view_layer->name);
+ DST.buffer_finish_called = false;
+
DRW_render_gpencil_to_image(engine, render_layer, &render_rect);
/* Force cache to reset. */
@@ -2014,13 +2049,15 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
RE_SetActiveRenderView(render, render_view->name);
drw_view_reset();
engine_type->draw_engine->render_to_image(data, engine, render_layer, &render_rect);
+ DST.buffer_finish_called = false;
+
/* grease pencil: render result is merged in the previous render result. */
if (DRW_render_check_grease_pencil(depsgraph)) {
DRW_state_reset();
drw_view_reset();
DRW_render_gpencil_to_image(engine, render_layer, &render_rect);
+ DST.buffer_finish_called = false;
}
- DST.buffer_finish_called = false;
}
RE_engine_end_result(engine, render_result, false, false, false);
@@ -2066,7 +2103,7 @@ void DRW_render_object_iter(
if ((object_type_exclude_viewport & (1 << ob->type)) == 0) {
DST.dupli_parent = data_.dupli_parent;
DST.dupli_source = data_.dupli_object_current;
- DST.ob_state = NULL;
+ DST.ob_handle = 0;
drw_duplidata_load(DST.dupli_source);
if (!DST.dupli_source) {
@@ -2173,6 +2210,7 @@ void DRW_render_instance_buffer_finish(void)
BLI_assert(!DST.buffer_finish_called && "DRW_render_instance_buffer_finish called twice!");
DST.buffer_finish_called = true;
DRW_instance_buffer_finish(DST.idatalist);
+ drw_resource_buffer_finish(DST.vmempool);
}
/**
@@ -2196,7 +2234,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
Object *obact = OBACT(view_layer);
Object *obedit = OBEDIT_FROM_OBACT(obact);
#ifndef USE_GPU_SELECT
- UNUSED_VARS(vc, scene, view_layer, v3d, ar, rect);
+ UNUSED_VARS(scene, view_layer, v3d, ar, rect);
#else
RegionView3D *rv3d = ar->regiondata;
@@ -2204,24 +2242,43 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
drw_state_prepare_clean_for_draw(&DST);
bool use_obedit = false;
- int obedit_mode = 0;
+ /* obedit_ctx_mode is used for selecting the right draw engines */
+ eContextObjectMode obedit_ctx_mode;
+ /* object_mode is used for filtering objects in the depsgraph */
+ eObjectMode object_mode;
+ int object_type = 0;
if (obedit != NULL) {
+ object_type = obedit->type;
+ object_mode = obedit->mode;
if (obedit->type == OB_MBALL) {
use_obedit = true;
- obedit_mode = CTX_MODE_EDIT_METABALL;
+ obedit_ctx_mode = CTX_MODE_EDIT_METABALL;
}
else if (obedit->type == OB_ARMATURE) {
use_obedit = true;
- obedit_mode = CTX_MODE_EDIT_ARMATURE;
+ obedit_ctx_mode = CTX_MODE_EDIT_ARMATURE;
}
}
if (v3d->overlay.flag & V3D_OVERLAY_BONE_SELECT) {
if (!(v3d->flag2 & V3D_HIDE_OVERLAYS)) {
/* Note: don't use "BKE_object_pose_armature_get" here, it breaks selection. */
Object *obpose = OBPOSE_FROM_OBACT(obact);
+ if (obpose == NULL) {
+ Object *obweight = OBWEIGHTPAINT_FROM_OBACT(obact);
+ if (obweight) {
+ /* Only use Armature pose selection, when connected armature is in pose mode. */
+ Object *ob_armature = modifiers_isDeformedByArmature(obweight);
+ if (ob_armature && ob_armature->mode == OB_MODE_POSE) {
+ obpose = ob_armature;
+ }
+ }
+ }
+
if (obpose) {
use_obedit = true;
- obedit_mode = CTX_MODE_POSE;
+ object_type = obpose->type;
+ object_mode = obpose->mode;
+ obedit_ctx_mode = CTX_MODE_POSE;
}
}
}
@@ -2235,8 +2292,8 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
/* Get list of enabled engines */
if (use_obedit) {
- drw_engines_enable_from_paint_mode(obedit_mode);
- drw_engines_enable_from_mode(obedit_mode);
+ drw_engines_enable_from_paint_mode(obedit_ctx_mode);
+ drw_engines_enable_from_mode(obedit_ctx_mode);
}
else if (!draw_surface) {
/* grease pencil selection */
@@ -2283,7 +2340,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
drw_engines_world_update(scene);
if (use_obedit) {
- FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, obact->type, obact->mode, ob_iter) {
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, object_type, object_mode, ob_iter) {
drw_engines_cache_populate(ob_iter);
}
FOREACH_OBJECT_IN_MODE_END;
@@ -2293,10 +2350,9 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
v3d->object_type_exclude_select);
bool filter_exclude = false;
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob) {
- if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) {
+ if (!is_object_visible_in_viewport(v3d, ob)) {
continue;
}
-
if ((ob->base_flag & BASE_SELECTABLE) &&
(object_type_exclude_select & (1 << ob->type)) == 0) {
if (object_filter_fn != NULL) {
@@ -2386,8 +2442,38 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
/**
* object mode select-loop, see: ED_view3d_draw_depth_loop (legacy drawing).
*/
-static void drw_draw_depth_loop_imp(void)
+static void drw_draw_depth_loop_imp(struct Depsgraph *depsgraph,
+ ARegion *ar,
+ View3D *v3d,
+ GPUViewport *viewport,
+ const bool use_opengl_context)
{
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ RegionView3D *rv3d = ar->regiondata;
+
+ if (use_opengl_context) {
+ DRW_opengl_context_enable();
+ }
+
+ DST.viewport = viewport;
+ DST.options.is_depth = true;
+
+ /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */
+ DST.draw_ctx = (DRWContextState){
+ .ar = ar,
+ .rv3d = rv3d,
+ .v3d = v3d,
+ .scene = scene,
+ .view_layer = view_layer,
+ .obact = OBACT(view_layer),
+ .engine_type = engine_type,
+ .depsgraph = depsgraph,
+ };
+
+ drw_engines_data_validate();
+
/* Setup framebuffer */
DefaultFramebufferList *fbl = (DefaultFramebufferList *)GPU_viewport_framebuffer_list_get(
DST.viewport);
@@ -2409,17 +2495,14 @@ static void drw_draw_depth_loop_imp(void)
drw_engines_cache_init();
drw_engines_world_update(DST.draw_ctx.scene);
- View3D *v3d = DST.draw_ctx.v3d;
const int object_type_exclude_viewport = v3d->object_type_exclude_viewport;
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (DST.draw_ctx.depsgraph, ob) {
if ((object_type_exclude_viewport & (1 << ob->type)) != 0) {
continue;
}
-
- if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) {
+ if (!is_object_visible_in_viewport(v3d, ob)) {
continue;
}
-
DST.dupli_parent = data_.dupli_parent;
DST.dupli_source = data_.dupli_object_current;
drw_duplidata_load(DST.dupli_source);
@@ -2447,6 +2530,20 @@ static void drw_draw_depth_loop_imp(void)
/* TODO: Reading depth for operators should be done here. */
GPU_framebuffer_restore();
+
+ drw_engines_disable();
+
+ drw_viewport_cache_resize();
+
+#ifdef DEBUG
+ /* Avoid accidental reuse. */
+ drw_state_ensure_not_reused(&DST);
+#endif
+
+ /* Changin context */
+ if (use_opengl_context) {
+ DRW_opengl_context_disable();
+ }
}
/**
@@ -2458,55 +2555,18 @@ void DRW_draw_depth_loop(struct Depsgraph *depsgraph,
GPUViewport *viewport,
bool use_opengl_context)
{
- Scene *scene = DEG_get_evaluated_scene(depsgraph);
- RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
- ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
- RegionView3D *rv3d = ar->regiondata;
-
- if (use_opengl_context) {
- DRW_opengl_context_enable();
- }
-
/* Reset before using it. */
drw_state_prepare_clean_for_draw(&DST);
- DST.viewport = viewport;
- DST.options.is_depth = true;
-
- /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */
- DST.draw_ctx = (DRWContextState){
- .ar = ar,
- .rv3d = rv3d,
- .v3d = v3d,
- .scene = scene,
- .view_layer = view_layer,
- .obact = OBACT(view_layer),
- .engine_type = engine_type,
- .depsgraph = depsgraph,
- };
-
/* Get list of enabled engines */
{
drw_engines_enable_basic();
if (DRW_state_draw_support()) {
drw_engines_enable_from_object_mode();
}
- drw_engines_data_validate();
}
- drw_draw_depth_loop_imp();
-
- drw_engines_disable();
-
-#ifdef DEBUG
- /* Avoid accidental reuse. */
- drw_state_ensure_not_reused(&DST);
-#endif
-
- /* Changin context */
- if (use_opengl_context) {
- DRW_opengl_context_disable();
- }
+ drw_draw_depth_loop_imp(depsgraph, ar, v3d, viewport, use_opengl_context);
}
/**
@@ -2517,43 +2577,12 @@ void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph,
View3D *v3d,
GPUViewport *viewport)
{
- Scene *scene = DEG_get_evaluated_scene(depsgraph);
- ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
- RegionView3D *rv3d = ar->regiondata;
-
- DRW_opengl_context_enable();
-
/* Reset before using it. */
drw_state_prepare_clean_for_draw(&DST);
- DST.viewport = viewport;
- DST.options.is_depth = true;
-
- /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */
- DST.draw_ctx = (DRWContextState){
- .ar = ar,
- .rv3d = rv3d,
- .v3d = v3d,
- .scene = scene,
- .view_layer = view_layer,
- .obact = OBACT(view_layer),
- .depsgraph = depsgraph,
- };
-
use_drw_engine(&draw_engine_gpencil_type);
- drw_engines_data_validate();
-
- drw_draw_depth_loop_imp();
-
- drw_engines_disable();
-
-#ifdef DEBUG
- /* Avoid accidental reuse. */
- drw_state_ensure_not_reused(&DST);
-#endif
- /* Changin context */
- DRW_opengl_context_disable();
+ drw_draw_depth_loop_imp(depsgraph, ar, v3d, viewport, true);
}
void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *ar, View3D *v3d, const rcti *rect)
@@ -2601,7 +2630,13 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *ar, View3D *v3d, const rc
drw_engines_cache_finish();
+#if 0 /* This is a workaround to a nasty bug that seems to be a nasty driver bug. (See T69377) */
DRW_render_instance_buffer_finish();
+#else
+ DST.buffer_finish_called = true;
+ // DRW_instance_buffer_finish(DST.idatalist);
+ drw_resource_buffer_finish(DST.vmempool);
+#endif
}
/* Start Drawing */
@@ -2905,6 +2940,10 @@ void DRW_engines_free(void)
MEM_SAFE_FREE(DST.uniform_names.buffer);
+ if (DST.draw_list) {
+ GPU_draw_list_discard(DST.draw_list);
+ }
+
DRW_opengl_context_disable();
}
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 85f6cf05e83..709116c78e5 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -28,8 +28,10 @@
#include "DRW_engine.h"
#include "DRW_render.h"
+#include "BLI_assert.h"
#include "BLI_linklist.h"
#include "BLI_threads.h"
+#include "BLI_memblock.h"
#include "GPU_batch.h"
#include "GPU_context.h"
@@ -43,6 +45,9 @@
/* Use draw manager to call GPU_select, see: DRW_draw_select_loop */
#define USE_GPU_SELECT
+/* Use drawcall batching using instanced rendering. */
+#define USE_BATCHING 1
+
// #define DRW_DEBUG_CULLING
#define DRW_DEBUG_USE_UNIFORM_NAME 0
#define DRW_UNIFORM_BUFFER_NAME 64
@@ -90,20 +95,6 @@
* > DRWUniform
*/
-/* Used by DRWCallState.flag */
-enum {
- DRW_CALL_NEGSCALE = (1 << 1),
-};
-
-/* Used by DRWCallState.matflag */
-enum {
- DRW_CALL_MODELINVERSE = (1 << 0),
- DRW_CALL_MODELVIEWPROJECTION = (1 << 1),
- DRW_CALL_ORCOTEXFAC = (1 << 2),
- DRW_CALL_OBJECTINFO = (1 << 3),
- DRW_CALL_OBJECTCOLOR = (1 << 4),
-};
-
typedef struct DRWCullingState {
uint32_t mask;
/* Culling: Using Bounding Sphere for now for faster culling.
@@ -113,38 +104,161 @@ typedef struct DRWCullingState {
void *user_data;
} DRWCullingState;
-typedef struct DRWCallState {
- DRWCullingState *culling;
- uchar flag;
- uchar matflag; /* Which matrices to compute. */
- short ob_index;
- /* Matrices */
+/* Minimum max UBO size is 64KiB. We take the largest
+ * UBO struct and alloc the max number.
+ * ((1 << 16) / sizeof(DRWObjectMatrix)) = 512
+ * Keep in sync with common_view_lib.glsl */
+#define DRW_RESOURCE_CHUNK_LEN 512
+
+/**
+ * Identifier used to sort similar drawcalls together.
+ * Also used to reference elements inside memory blocks.
+ *
+ * From MSB to LSB
+ * 1 bit for negative scale.
+ * 22 bits for chunk id.
+ * 9 bits for resource id inside the chunk. (can go up to 511)
+ * |-|----------------------|---------|
+ *
+ * Use manual bit-shift and mask instead of bit-fields to avoid
+ * compiler dependent behavior that would mess the ordering of
+ * the members thus changing the sorting order.
+ */
+typedef uint32_t DRWResourceHandle;
+
+BLI_INLINE uint32_t DRW_handle_negative_scale_get(const DRWResourceHandle *handle)
+{
+ return (*handle & 0x80000000) != 0;
+}
+
+BLI_INLINE uint32_t DRW_handle_chunk_get(const DRWResourceHandle *handle)
+{
+ return (*handle & 0x7FFFFFFF) >> 9;
+}
+
+BLI_INLINE uint32_t DRW_handle_id_get(const DRWResourceHandle *handle)
+{
+ return (*handle & 0x000001FF);
+}
+
+BLI_INLINE void DRW_handle_increment(DRWResourceHandle *handle)
+{
+ *handle += 1;
+}
+
+BLI_INLINE void DRW_handle_negative_scale_enable(DRWResourceHandle *handle)
+{
+ *handle |= 0x80000000;
+}
+
+BLI_INLINE void *DRW_memblock_elem_from_handle(struct BLI_memblock *memblock,
+ const DRWResourceHandle *handle)
+{
+ int elem = DRW_handle_id_get(handle);
+ int chunk = DRW_handle_chunk_get(handle);
+ return BLI_memblock_elem_get(memblock, chunk, elem);
+}
+
+typedef struct DRWObjectMatrix {
float model[4][4];
float modelinverse[4][4];
- float orcotexfac[2][3];
- float ob_random;
+} DRWObjectMatrix;
+
+typedef struct DRWObjectInfos {
+ float orcotexfac[2][4];
float ob_color[4];
-} DRWCallState;
+ float ob_index;
+ float pad; /* UNUSED*/
+ float ob_random;
+ float ob_neg_scale;
+} DRWObjectInfos;
+
+BLI_STATIC_ASSERT_ALIGN(DRWObjectMatrix, 16)
+BLI_STATIC_ASSERT_ALIGN(DRWObjectInfos, 16)
-typedef struct DRWCall {
- struct DRWCall *next;
- DRWCallState *state;
+typedef enum {
+ /* Draw Commands */
+ DRW_CMD_DRAW = 0, /* Only sortable type. Must be 0. */
+ DRW_CMD_DRAW_RANGE = 1,
+ DRW_CMD_DRAW_INSTANCE = 2,
+ DRW_CMD_DRAW_PROCEDURAL = 3,
+ /* Other Commands */
+ DRW_CMD_CLEAR = 12,
+ DRW_CMD_DRWSTATE = 13,
+ DRW_CMD_STENCIL = 14,
+ DRW_CMD_SELECTID = 15,
+ /* Needs to fit in 4bits */
+} eDRWCommandType;
+
+#define DRW_MAX_DRAW_CMD_TYPE DRW_CMD_DRAW_PROCEDURAL
+
+typedef struct DRWCommandDraw {
+ GPUBatch *batch;
+ DRWResourceHandle handle;
+} DRWCommandDraw;
+/* Assume DRWResourceHandle to be 0. */
+typedef struct DRWCommandDrawRange {
GPUBatch *batch;
uint vert_first;
uint vert_count;
+} DRWCommandDrawRange;
+
+typedef struct DRWCommandDrawInstance {
+ GPUBatch *batch;
+ DRWResourceHandle handle;
uint inst_count;
+} DRWCommandDrawInstance;
-#ifdef USE_GPU_SELECT
- /* TODO(fclem) remove once we have a dedicated selection engine. */
- int select_id;
- GPUVertBuf *inst_selectid;
-#endif
-} DRWCall;
+typedef struct DRWCommandDrawProcedural {
+ GPUBatch *batch;
+ DRWResourceHandle handle;
+ uint vert_count;
+} DRWCommandDrawProcedural;
+
+typedef struct DRWCommandSetMutableState {
+ /** State changes (or'd or and'd with the pass's state) */
+ DRWState enable;
+ DRWState disable;
+} DRWCommandSetMutableState;
+
+typedef struct DRWCommandSetStencil {
+ uint mask;
+} DRWCommandSetStencil;
+
+typedef struct DRWCommandSetSelectID {
+ GPUVertBuf *select_buf;
+ uint select_id;
+} DRWCommandSetSelectID;
+
+typedef struct DRWCommandClear {
+ eGPUFrameBufferBits clear_channels;
+ uchar r, g, b, a; /* [0..1] for each channels. Normalized. */
+ float depth; /* [0..1] for depth. Normalized. */
+ uchar stencil; /* Stencil value [0..255] */
+} DRWCommandClear;
+
+typedef union DRWCommand {
+ DRWCommandDraw draw;
+ DRWCommandDrawRange range;
+ DRWCommandDrawInstance instance;
+ DRWCommandDrawProcedural procedural;
+ DRWCommandSetMutableState state;
+ DRWCommandSetStencil stencil;
+ DRWCommandSetSelectID select_id;
+ DRWCommandClear clear;
+} DRWCommand;
+
+/* Used for agregating calls into GPUVertBufs. */
+struct DRWCallBuffer {
+ GPUVertBuf *buf;
+ GPUVertBuf *buf_select;
+ int count;
+};
/* Used by DRWUniform.type */
typedef enum {
- DRW_UNIFORM_INT,
+ DRW_UNIFORM_INT = 0,
DRW_UNIFORM_INT_COPY,
DRW_UNIFORM_FLOAT,
DRW_UNIFORM_FLOAT_COPY,
@@ -153,55 +267,56 @@ typedef enum {
DRW_UNIFORM_TEXTURE_REF,
DRW_UNIFORM_BLOCK,
DRW_UNIFORM_BLOCK_PERSIST,
+ DRW_UNIFORM_TFEEDBACK_TARGET,
+ /** Per drawcall uniforms/UBO */
+ DRW_UNIFORM_BLOCK_OBMATS,
+ DRW_UNIFORM_BLOCK_OBINFOS,
+ DRW_UNIFORM_RESOURCE_CHUNK,
+ /** Legacy / Fallback */
+ DRW_UNIFORM_BASE_INSTANCE,
+ DRW_UNIFORM_MODEL_MATRIX,
+ DRW_UNIFORM_MODEL_MATRIX_INVERSE,
+ DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX,
+ /* WARNING: set DRWUniform->type
+ * bit length accordingly. */
} DRWUniformType;
struct DRWUniform {
- DRWUniform *next; /* single-linked list */
union {
/* For reference or array/vector types. */
const void *pvalue;
/* Single values. */
- float fvalue[2];
- int ivalue[2];
+ float fvalue[4];
+ int ivalue[4];
};
- int name_ofs; /* name offset in name buffer. */
int location;
- char type; /* DRWUniformType */
- char length; /* cannot be more than 16 */
- char arraysize; /* cannot be more than 16 too */
+ uint32_t type : 5; /* DRWUniformType */
+ uint32_t length : 5; /* cannot be more than 16 */
+ uint32_t arraysize : 5; /* cannot be more than 16 too */
+ uint32_t name_ofs : 17; /* name offset in name buffer. */
};
struct DRWShadingGroup {
DRWShadingGroup *next;
- GPUShader *shader; /* Shader to bind */
- DRWUniform *uniforms; /* Uniforms pointers */
+ GPUShader *shader; /* Shader to bind */
+ struct DRWUniformChunk *uniforms; /* Uniforms pointers */
struct {
- DRWCall *first, *last; /* Linked list of DRWCall */
- } calls;
+ /* Chunks of draw calls. */
+ struct DRWCommandChunk *first, *last;
+ } cmd;
- /** TODO Maybe remove from here */
- struct GPUVertBuf *tfeedback_target;
-
- /** State changes for this batch only (or'd with the pass's state) */
- DRWState state_extra;
- /** State changes for this batch only (and'd with the pass's state) */
- DRWState state_extra_disable;
- /** Stencil mask to use for stencil test / write operations */
- uint stencil_mask;
-
- /* Builtin matrices locations */
- int model;
- int modelinverse;
- int modelviewprojection;
- int orcotexfac;
- int callid;
- int objectinfo;
- int objectcolor;
- uchar matflag; /* Matrices needed, same as DRWCall.flag */
-
- DRWPass *pass_parent; /* backlink to pass we're in */
+ union {
+ struct {
+ int objectinfo; /* Equal to 1 if the shader needs obinfos. */
+ DRWResourceHandle pass_handle; /* Memblock key to parent pass. */
+ };
+ struct {
+ float distance; /* Distance from camera. */
+ uint original_index; /* Original position inside the shgroup list. */
+ } z_sorting;
+ };
};
#define MAX_PASS_NAME 32
@@ -213,6 +328,7 @@ struct DRWPass {
DRWShadingGroup *last;
} shgroups;
+ DRWResourceHandle handle;
DRWState state;
char name[MAX_PASS_NAME];
};
@@ -232,6 +348,8 @@ typedef struct DRWViewUboStorage {
float viewcamtexcofac[4];
} DRWViewUboStorage;
+BLI_STATIC_ASSERT_ALIGN(DRWViewUboStorage, 16)
+
#define MAX_CULLED_VIEWS 32
struct DRWView {
@@ -253,13 +371,45 @@ struct DRWView {
void *user_data;
};
-/* TODO(fclem): Future awaits */
-#if 0
-typedef struct ModelUboStorage {
- float model[4][4];
- float modelinverse[4][4];
-} ModelUboStorage;
-#endif
+/* ------------ Data Chunks --------------- */
+/**
+ * In order to keep a cache friendly data structure,
+ * we alloc most of our little data into chunks of multiple item.
+ * Iteration, allocation and memory usage are better.
+ * We loose a bit of memory by allocating more than what we need
+ * but it's counterbalanced by not needing the linked-list pointers
+ * for each item.
+ **/
+
+typedef struct DRWUniformChunk {
+ struct DRWUniformChunk *next; /* single-linked list */
+ uint32_t uniform_len;
+ uint32_t uniform_used;
+ DRWUniform uniforms[10];
+} DRWUniformChunk;
+
+typedef struct DRWCommandChunk {
+ struct DRWCommandChunk *next;
+ uint32_t command_len;
+ uint32_t command_used;
+ /* 4bits for each command. */
+ uint64_t command_type[6];
+ /* -- 64 bytes aligned -- */
+ DRWCommand commands[96];
+ /* -- 64 bytes aligned -- */
+} DRWCommandChunk;
+
+typedef struct DRWCommandSmallChunk {
+ struct DRWCommandChunk *next;
+ uint32_t command_len;
+ uint32_t command_used;
+ /* 4bits for each command. */
+ /* TODO reduce size of command_type. */
+ uint64_t command_type[6];
+ DRWCommand commands[6];
+} DRWCommandSmallChunk;
+
+BLI_STATIC_ASSERT_ALIGN(DRWCommandChunk, 16);
/* ------------- DRAW DEBUG ------------ */
@@ -280,21 +430,31 @@ typedef struct DRWDebugSphere {
#define DST_MAX_SLOTS 64 /* Cannot be changed without modifying RST.bound_tex_slots */
#define MAX_CLIP_PLANES 6 /* GL_MAX_CLIP_PLANES is at least 6 */
#define STENCIL_UNDEFINED 256
+#define DRW_DRAWLIST_LEN 256
typedef struct DRWManager {
/* TODO clean up this struct a bit */
/* Cache generation */
ViewportMemoryPool *vmempool;
DRWInstanceDataList *idatalist;
- DRWInstanceData *object_instance_data[MAX_INSTANCE_DATA_SIZE];
- /* Default Unit model matrix state without culling. */
- DRWCallState *unit_state;
/* State of the object being evaluated if already allocated. */
- DRWCallState *ob_state;
+ DRWResourceHandle ob_handle;
+ /** True if current DST.ob_state has its matching DRWObjectInfos init. */
+ bool ob_state_obinfo_init;
+ /** Handle of current object resource in object resource arrays (DRWObjectMatrices/Infos). */
+ DRWResourceHandle resource_handle;
+ /** Handle of next DRWPass to be allocated. */
+ DRWResourceHandle pass_handle;
+
+ /** Dupli state. NULL if not dupli. */
struct DupliObject *dupli_source;
struct Object *dupli_parent;
struct Object *dupli_origin;
+ /** Ghash containing original objects. */
struct GHash *dupli_ghash;
- void **dupli_datas; /* Array of dupli_data (one for each enabled engine) to handle duplis. */
+ /** TODO(fclem) try to remove usage of this. */
+ DRWInstanceData *object_instance_data[MAX_INSTANCE_DATA_SIZE];
+ /* Array of dupli_data (one for each enabled engine) to handle duplis. */
+ void **dupli_datas;
/* Rendering state */
GPUShader *shader;
@@ -357,6 +517,8 @@ typedef struct DRWManager {
/** Mutex to lock the drw manager and avoid concurrent context usage. */
TicketMutex *gl_context_mutex;
+ GPUDrawList *draw_list;
+
/** GPU Resource State: Memory storage between drawing. */
struct {
/* High end GPUs supports up to 32 binds per shader stage.
@@ -397,9 +559,13 @@ void drw_state_set(DRWState state);
void drw_debug_draw(void);
void drw_debug_init(void);
+eDRWCommandType command_type_get(uint64_t *command_type_bits, int index);
+
void drw_batch_cache_validate(Object *ob);
void drw_batch_cache_generate_requested(struct Object *ob);
+void drw_resource_buffer_finish(ViewportMemoryPool *vmempool);
+
/* Procedural Drawing */
GPUBatch *drw_cache_procedural_points_get(void);
GPUBatch *drw_cache_procedural_lines_get(void);
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index 8b7cb9c1dad..dcf526679bf 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -34,6 +34,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
+#include "BLI_alloca.h"
#include "BLI_hash.h"
#include "BLI_link_utils.h"
#include "BLI_mempool.h"
@@ -51,6 +52,36 @@
/** \name Uniform Buffer Object (DRW_uniformbuffer)
* \{ */
+static void draw_call_sort(DRWCommand *array, DRWCommand *array_tmp, int array_len)
+{
+ /* Count unique batches. Tt's not really important if
+ * there is collisions. If there is a lot of different batches,
+ * the sorting benefit will be negligible.
+ * So at least sort fast! */
+ uchar idx[128] = {0};
+ /* Shift by 6 positions knowing each GPUBatch is > 64 bytes */
+#define KEY(a) ((((size_t)((a).draw.batch)) >> 6) % ARRAY_SIZE(idx))
+ BLI_assert(array_len <= ARRAY_SIZE(idx));
+
+ for (int i = 0; i < array_len; i++) {
+ /* Early out if nothing to sort. */
+ if (++idx[KEY(array[i])] == array_len) {
+ return;
+ }
+ }
+ /* Cumulate batch indices */
+ for (int i = 1; i < ARRAY_SIZE(idx); i++) {
+ idx[i] += idx[i - 1];
+ }
+ /* Traverse in reverse to not change the order of the resource ids. */
+ for (int src = array_len - 1; src >= 0; src--) {
+ array_tmp[--idx[KEY(array[src])]] = array[src];
+ }
+#undef KEY
+
+ memcpy(array, array_tmp, sizeof(*array) * array_len);
+}
+
GPUUniformBuffer *DRW_uniformbuffer_create(int size, const void *data)
{
return GPU_uniformbuffer_create(size, data, NULL);
@@ -66,20 +97,94 @@ void DRW_uniformbuffer_free(GPUUniformBuffer *ubo)
GPU_uniformbuffer_free(ubo);
}
+void drw_resource_buffer_finish(ViewportMemoryPool *vmempool)
+{
+ int chunk_id = DRW_handle_chunk_get(&DST.resource_handle);
+ int elem_id = DRW_handle_id_get(&DST.resource_handle);
+ int ubo_len = 1 + chunk_id - ((elem_id == 0) ? 1 : 0);
+ size_t list_size = sizeof(GPUUniformBuffer *) * ubo_len;
+
+ /* TODO find a better system. currently a lot of obinfos UBO are going to be unused
+ * if not rendering with Eevee. */
+
+ if (vmempool->matrices_ubo == NULL) {
+ vmempool->matrices_ubo = MEM_callocN(list_size, __func__);
+ vmempool->obinfos_ubo = MEM_callocN(list_size, __func__);
+ vmempool->ubo_len = ubo_len;
+ }
+
+ /* Remove unecessary buffers */
+ for (int i = ubo_len; i < vmempool->ubo_len; i++) {
+ GPU_uniformbuffer_free(vmempool->matrices_ubo[i]);
+ GPU_uniformbuffer_free(vmempool->obinfos_ubo[i]);
+ }
+
+ if (ubo_len != vmempool->ubo_len) {
+ vmempool->matrices_ubo = MEM_recallocN(vmempool->matrices_ubo, list_size);
+ vmempool->obinfos_ubo = MEM_recallocN(vmempool->obinfos_ubo, list_size);
+ vmempool->ubo_len = ubo_len;
+ }
+
+ /* Create/Update buffers. */
+ for (int i = 0; i < ubo_len; i++) {
+ void *data_obmat = BLI_memblock_elem_get(vmempool->obmats, i, 0);
+ void *data_infos = BLI_memblock_elem_get(vmempool->obinfos, i, 0);
+ if (vmempool->matrices_ubo[i] == NULL) {
+ vmempool->matrices_ubo[i] = GPU_uniformbuffer_create(
+ sizeof(DRWObjectMatrix) * DRW_RESOURCE_CHUNK_LEN, data_obmat, NULL);
+ vmempool->obinfos_ubo[i] = GPU_uniformbuffer_create(
+ sizeof(DRWObjectInfos) * DRW_RESOURCE_CHUNK_LEN, data_infos, NULL);
+ }
+ else {
+ GPU_uniformbuffer_update(vmempool->matrices_ubo[i], data_obmat);
+ GPU_uniformbuffer_update(vmempool->obinfos_ubo[i], data_infos);
+ }
+ }
+
+ /* Aligned alloc to avoid unaligned memcpy. */
+ DRWCommandChunk *chunk_tmp = MEM_mallocN_aligned(sizeof(DRWCommandChunk), 16, "tmp call chunk");
+ DRWCommandChunk *chunk;
+ BLI_memblock_iter iter;
+ BLI_memblock_iternew(vmempool->commands, &iter);
+ while ((chunk = BLI_memblock_iterstep(&iter))) {
+ bool sortable = true;
+ /* We can only sort chunks that contain DRWCommandDraw only. */
+ for (int i = 0; i < ARRAY_SIZE(chunk->command_type) && sortable; i++) {
+ if (chunk->command_type[i] != 0) {
+ sortable = false;
+ }
+ }
+ if (sortable) {
+ draw_call_sort(chunk->commands, chunk_tmp->commands, chunk->command_used);
+ }
+ }
+ MEM_freeN(chunk_tmp);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Uniforms (DRW_shgroup_uniform)
* \{ */
-static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup,
- int loc,
- DRWUniformType type,
- const void *value,
- int length,
- int arraysize)
+static DRWUniform *drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup,
+ int loc,
+ DRWUniformType type,
+ const void *value,
+ int length,
+ int arraysize)
{
- DRWUniform *uni = BLI_memblock_alloc(DST.vmempool->uniforms);
+ DRWUniformChunk *unichunk = shgroup->uniforms;
+ /* Happens on first uniform or if chunk is full. */
+ if (!unichunk || unichunk->uniform_used == unichunk->uniform_len) {
+ unichunk = BLI_memblock_alloc(DST.vmempool->uniforms);
+ unichunk->uniform_len = ARRAY_SIZE(shgroup->uniforms->uniforms);
+ unichunk->uniform_used = 0;
+ BLI_LINKS_PREPEND(shgroup->uniforms, unichunk);
+ }
+
+ DRWUniform *uni = unichunk->uniforms + unichunk->uniform_used++;
+
uni->location = loc;
uni->type = type;
uni->length = length;
@@ -87,11 +192,11 @@ static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup,
switch (type) {
case DRW_UNIFORM_INT_COPY:
- BLI_assert(length <= 2);
+ BLI_assert(length <= 4);
memcpy(uni->ivalue, value, sizeof(int) * length);
break;
case DRW_UNIFORM_FLOAT_COPY:
- BLI_assert(length <= 2);
+ BLI_assert(length <= 4);
memcpy(uni->fvalue, value, sizeof(float) * length);
break;
default:
@@ -99,7 +204,7 @@ static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup,
break;
}
- BLI_LINKS_PREPEND(shgroup->uniforms, uni);
+ return uni;
}
static void drw_shgroup_builtin_uniform(
@@ -136,7 +241,8 @@ static void drw_shgroup_uniform(DRWShadingGroup *shgroup,
BLI_assert(arraysize > 0 && arraysize <= 16);
BLI_assert(length >= 0 && length <= 16);
- drw_shgroup_uniform_create_ex(shgroup, location, type, value, length, arraysize);
+ DRWUniform *uni = drw_shgroup_uniform_create_ex(
+ shgroup, location, type, value, length, arraysize);
/* If location is -2, the uniform has not yet been queried.
* We save the name for query just before drawing. */
@@ -155,7 +261,7 @@ static void drw_shgroup_uniform(DRWShadingGroup *shgroup,
memcpy(dst, name, len); /* Copies NULL terminator. */
DST.uniform_names.buffer_ofs += len;
- shgroup->uniforms->name_ofs = ofs;
+ uni->name_ofs = ofs;
}
}
@@ -286,6 +392,21 @@ void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, co
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, &value, 1, 1);
}
+void DRW_shgroup_uniform_ivec2_copy(DRWShadingGroup *shgroup, const char *name, const int *value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, value, 2, 1);
+}
+
+void DRW_shgroup_uniform_ivec3_copy(DRWShadingGroup *shgroup, const char *name, const int *value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, value, 3, 1);
+}
+
+void DRW_shgroup_uniform_ivec4_copy(DRWShadingGroup *shgroup, const char *name, const int *value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, value, 4, 1);
+}
+
void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value)
{
int ival = value;
@@ -302,13 +423,23 @@ void DRW_shgroup_uniform_vec2_copy(DRWShadingGroup *shgroup, const char *name, c
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, value, 2, 1);
}
+void DRW_shgroup_uniform_vec3_copy(DRWShadingGroup *shgroup, const char *name, const float *value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, value, 3, 1);
+}
+
+void DRW_shgroup_uniform_vec4_copy(DRWShadingGroup *shgroup, const char *name, const float *value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, value, 4, 1);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Draw Call (DRW_calls)
* \{ */
-static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[3])
+static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[4])
{
ID *ob_data = (ob) ? ob->data : NULL;
float *texcoloc = NULL;
@@ -316,13 +447,11 @@ static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[3])
if (ob_data != NULL) {
switch (GS(ob_data->name)) {
case ID_ME:
- BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize);
+ BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, &texcosize);
break;
case ID_CU: {
Curve *cu = (Curve *)ob_data;
- if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_curve_texspace_calc(cu);
- }
+ BKE_curve_texspace_ensure(cu);
texcoloc = cu->loc;
texcosize = cu->size;
break;
@@ -351,159 +480,283 @@ static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[3])
}
}
-static void drw_call_state_update_matflag(DRWCallState *state,
- DRWShadingGroup *shgroup,
- Object *ob)
+BLI_INLINE void drw_call_matrix_init(DRWObjectMatrix *ob_mats, Object *ob, float (*obmat)[4])
{
- uchar new_flags = ((state->matflag ^ shgroup->matflag) & shgroup->matflag);
-
- /* HACK: Here we set the matflags bit to 1 when computing the value
- * so that it's not recomputed for other drawcalls.
- * This is the opposite of what draw_matrices_model_prepare() does. */
- state->matflag |= shgroup->matflag;
-
- if (new_flags & DRW_CALL_MODELINVERSE) {
- if (ob) {
- copy_m4_m4(state->modelinverse, ob->imat);
- }
- else {
- invert_m4_m4(state->modelinverse, state->model);
- }
+ copy_m4_m4(ob_mats->model, obmat);
+ if (ob) {
+ copy_m4_m4(ob_mats->modelinverse, ob->imat);
}
-
- /* Orco factors: We compute this at creation to not have to save the *ob_data */
- if (new_flags & DRW_CALL_ORCOTEXFAC) {
- drw_call_calc_orco(ob, state->orcotexfac);
- }
-
- if (new_flags & DRW_CALL_OBJECTINFO) {
- state->ob_index = ob ? ob->index : 0;
- uint random;
- if (DST.dupli_source) {
- random = DST.dupli_source->random_id;
- }
- else {
- random = BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
- }
- state->ob_random = random * (1.0f / (float)0xFFFFFFFF);
- }
-
- if (new_flags & DRW_CALL_OBJECTCOLOR) {
- copy_v4_v4(state->ob_color, ob->color);
+ else {
+ /* WATCH: Can be costly. */
+ invert_m4_m4(ob_mats->modelinverse, ob_mats->model);
}
}
-static DRWCallState *drw_call_state_create(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob)
+static void drw_call_obinfos_init(DRWObjectInfos *ob_infos, Object *ob)
{
- DRWCallState *state = BLI_memblock_alloc(DST.vmempool->states);
- state->flag = 0;
- state->matflag = 0;
-
- /* Matrices */
- copy_m4_m4(state->model, obmat);
-
- if (ob && (ob->transflag & OB_NEG_SCALE)) {
- state->flag |= DRW_CALL_NEGSCALE;
- }
-
- drw_call_state_update_matflag(state, shgroup, ob);
-
- DRWCullingState *cull = BLI_memblock_alloc(DST.vmempool->cullstates);
- state->culling = cull;
+ BLI_assert(ob);
+ /* Index. */
+ ob_infos->ob_index = ob->index;
+ /* Orco factors. */
+ drw_call_calc_orco(ob, ob_infos->orcotexfac);
+ /* Random float value. */
+ uint random = (DST.dupli_source) ?
+ DST.dupli_source->random_id :
+ /* TODO(fclem) this is rather costly to do at runtime. Maybe we can
+ * put it in ob->runtime and make depsgraph ensure it is up to date. */
+ BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
+ ob_infos->ob_random = random * (1.0f / (float)0xFFFFFFFF);
+ /* Negative scalling. */
+ ob_infos->ob_neg_scale = (ob->transflag & OB_NEG_SCALE) ? -1.0f : 1.0f;
+ /* Object Color. */
+ copy_v4_v4(ob_infos->ob_color, ob->color);
+}
+static void drw_call_culling_init(DRWCullingState *cull, Object *ob)
+{
BoundBox *bbox;
if (ob != NULL && (bbox = BKE_object_boundbox_get(ob))) {
float corner[3];
/* Get BoundSphere center and radius from the BoundBox. */
mid_v3_v3v3(cull->bsphere.center, bbox->vec[0], bbox->vec[6]);
- mul_v3_m4v3(corner, obmat, bbox->vec[0]);
- mul_m4_v3(obmat, cull->bsphere.center);
+ mul_v3_m4v3(corner, ob->obmat, bbox->vec[0]);
+ mul_m4_v3(ob->obmat, cull->bsphere.center);
cull->bsphere.radius = len_v3v3(cull->bsphere.center, corner);
}
else {
- /* TODO(fclem) Bypass alloc if we can (see if eevee's
- * probe visibility collection still works). */
/* Bypass test. */
cull->bsphere.radius = -1.0f;
}
+ /* Reset user data */
+ cull->user_data = NULL;
+}
+
+static DRWResourceHandle drw_resource_handle_new(float (*obmat)[4], Object *ob)
+{
+ DRWCullingState *culling = BLI_memblock_alloc(DST.vmempool->cullstates);
+ DRWObjectMatrix *ob_mats = BLI_memblock_alloc(DST.vmempool->obmats);
+ /* FIXME Meh, not always needed but can be accessed after creation.
+ * Also it needs to have the same resource handle. */
+ DRWObjectInfos *ob_infos = BLI_memblock_alloc(DST.vmempool->obinfos);
+ UNUSED_VARS(ob_infos);
+
+ DRWResourceHandle handle = DST.resource_handle;
+ DRW_handle_increment(&DST.resource_handle);
+
+ if (ob && (ob->transflag & OB_NEG_SCALE)) {
+ DRW_handle_negative_scale_enable(&handle);
+ }
+
+ drw_call_matrix_init(ob_mats, ob, obmat);
+ drw_call_culling_init(culling, ob);
+ /* ob_infos is init only if needed. */
- return state;
+ return handle;
}
-static DRWCallState *drw_call_state_object(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob)
+static DRWResourceHandle drw_resource_handle(DRWShadingGroup *shgroup,
+ float (*obmat)[4],
+ Object *ob)
{
if (ob == NULL) {
if (obmat == NULL) {
- BLI_assert(DST.unit_state);
- return DST.unit_state;
+ DRWResourceHandle handle = 0;
+ return handle;
}
else {
- return drw_call_state_create(shgroup, obmat, ob);
+ return drw_resource_handle_new(obmat, NULL);
}
}
else {
- if (DST.ob_state == NULL) {
- DST.ob_state = drw_call_state_create(shgroup, obmat, ob);
+ if (DST.ob_handle == 0) {
+ DST.ob_handle = drw_resource_handle_new(obmat, ob);
+ DST.ob_state_obinfo_init = false;
}
- else {
- /* If the DRWCallState is reused, add necessary matrices. */
- drw_call_state_update_matflag(DST.ob_state, shgroup, ob);
+
+ if (shgroup->objectinfo) {
+ if (!DST.ob_state_obinfo_init) {
+ DST.ob_state_obinfo_init = true;
+ DRWObjectInfos *ob_infos = DRW_memblock_elem_from_handle(DST.vmempool->obinfos,
+ &DST.ob_handle);
+
+ drw_call_obinfos_init(ob_infos, ob);
+ }
}
- return DST.ob_state;
+ return DST.ob_handle;
}
}
+static void command_type_set(uint64_t *command_type_bits, int index, eDRWCommandType type)
+{
+ command_type_bits[index / 16] |= ((uint64_t)type) << ((index % 16) * 4);
+}
+
+eDRWCommandType command_type_get(uint64_t *command_type_bits, int index)
+{
+ return ((command_type_bits[index / 16] >> ((index % 16) * 4)) & 0xF);
+}
+
+static void *drw_command_create(DRWShadingGroup *shgroup, eDRWCommandType type)
+{
+ DRWCommandChunk *chunk = shgroup->cmd.last;
+
+ if (chunk == NULL) {
+ DRWCommandSmallChunk *smallchunk = BLI_memblock_alloc(DST.vmempool->commands_small);
+ smallchunk->command_len = ARRAY_SIZE(smallchunk->commands);
+ smallchunk->command_used = 0;
+ smallchunk->command_type[0] = 0x0lu;
+ chunk = (DRWCommandChunk *)smallchunk;
+ BLI_LINKS_APPEND(&shgroup->cmd, chunk);
+ }
+ else if (chunk->command_used == chunk->command_len) {
+ chunk = BLI_memblock_alloc(DST.vmempool->commands);
+ chunk->command_len = ARRAY_SIZE(chunk->commands);
+ chunk->command_used = 0;
+ memset(chunk->command_type, 0x0, sizeof(chunk->command_type));
+ BLI_LINKS_APPEND(&shgroup->cmd, chunk);
+ }
+
+ command_type_set(chunk->command_type, chunk->command_used, type);
+
+ return chunk->commands + chunk->command_used++;
+}
+
+static void drw_command_draw(DRWShadingGroup *shgroup, GPUBatch *batch, DRWResourceHandle handle)
+{
+ DRWCommandDraw *cmd = drw_command_create(shgroup, DRW_CMD_DRAW);
+ cmd->batch = batch;
+ cmd->handle = handle;
+}
+
+static void drw_command_draw_range(DRWShadingGroup *shgroup,
+ GPUBatch *batch,
+ uint start,
+ uint count)
+{
+ DRWCommandDrawRange *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_RANGE);
+ cmd->batch = batch;
+ cmd->vert_first = start;
+ cmd->vert_count = count;
+}
+
+static void drw_command_draw_instance(DRWShadingGroup *shgroup,
+ GPUBatch *batch,
+ DRWResourceHandle handle,
+ uint count)
+{
+ DRWCommandDrawInstance *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_INSTANCE);
+ cmd->batch = batch;
+ cmd->handle = handle;
+ cmd->inst_count = count;
+}
+
+static void drw_command_draw_procedural(DRWShadingGroup *shgroup,
+ GPUBatch *batch,
+ DRWResourceHandle handle,
+ uint vert_count)
+{
+ DRWCommandDrawProcedural *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_PROCEDURAL);
+ cmd->batch = batch;
+ cmd->handle = handle;
+ cmd->vert_count = vert_count;
+}
+
+static void drw_command_set_select_id(DRWShadingGroup *shgroup, GPUVertBuf *buf, uint select_id)
+{
+ /* Only one can be valid. */
+ BLI_assert(buf == NULL || select_id == -1);
+ DRWCommandSetSelectID *cmd = drw_command_create(shgroup, DRW_CMD_SELECTID);
+ cmd->select_buf = buf;
+ cmd->select_id = select_id;
+}
+
+static void drw_command_set_stencil_mask(DRWShadingGroup *shgroup, uint mask)
+{
+ BLI_assert(mask <= 0xFF);
+ DRWCommandSetStencil *cmd = drw_command_create(shgroup, DRW_CMD_STENCIL);
+ cmd->mask = mask;
+}
+
+static void drw_command_clear(DRWShadingGroup *shgroup,
+ eGPUFrameBufferBits channels,
+ uchar r,
+ uchar g,
+ uchar b,
+ uchar a,
+ float depth,
+ uchar stencil)
+{
+ DRWCommandClear *cmd = drw_command_create(shgroup, DRW_CMD_CLEAR);
+ cmd->clear_channels = channels;
+ cmd->r = r;
+ cmd->g = g;
+ cmd->b = b;
+ cmd->a = a;
+ cmd->depth = depth;
+ cmd->stencil = stencil;
+}
+
+static void drw_command_set_mutable_state(DRWShadingGroup *shgroup,
+ DRWState enable,
+ DRWState disable)
+{
+ /* TODO Restrict what state can be changed. */
+ DRWCommandSetMutableState *cmd = drw_command_create(shgroup, DRW_CMD_DRWSTATE);
+ cmd->enable = enable;
+ cmd->disable = disable;
+}
+
void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
Object *ob,
float (*obmat)[4],
struct GPUBatch *geom,
- uint v_sta,
- uint v_ct,
bool bypass_culling,
void *user_data)
{
BLI_assert(geom != NULL);
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : obmat, ob);
+ drw_command_draw(shgroup, geom, handle);
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
-
- call->state = drw_call_state_object(shgroup, ob ? ob->obmat : obmat, ob);
- call->batch = geom;
- call->vert_first = v_sta;
- call->vert_count = v_ct; /* 0 means auto from batch. */
- call->inst_count = 0;
-#ifdef USE_GPU_SELECT
- call->select_id = DST.select_id;
- call->inst_selectid = NULL;
-#endif
- if (call->state->culling) {
- call->state->culling->user_data = user_data;
+ /* Culling data. */
+ if (user_data || bypass_culling) {
+ DRWCullingState *culling = DRW_memblock_elem_from_handle(DST.vmempool->cullstates,
+ &DST.ob_handle);
+
+ if (user_data) {
+ culling->user_data = user_data;
+ }
if (bypass_culling) {
/* NOTE this will disable culling for the whole object. */
- call->state->culling->bsphere.radius = -1.0f;
+ culling->bsphere.radius = -1.0f;
}
}
}
+void DRW_shgroup_call_range(DRWShadingGroup *shgroup, struct GPUBatch *geom, uint v_sta, uint v_ct)
+{
+ BLI_assert(geom != NULL);
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ drw_command_draw_range(shgroup, geom, v_sta, v_ct);
+}
+
static void drw_shgroup_call_procedural_add_ex(DRWShadingGroup *shgroup,
GPUBatch *geom,
Object *ob,
uint vert_count)
{
-
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
-
- call->state = drw_call_state_object(shgroup, ob ? ob->obmat : NULL, ob);
- call->batch = geom;
- call->vert_first = 0;
- call->vert_count = vert_count;
- call->inst_count = 0;
-#ifdef USE_GPU_SELECT
- call->select_id = DST.select_id;
- call->inst_selectid = NULL;
-#endif
+ BLI_assert(vert_count > 0);
+ BLI_assert(geom != NULL);
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob);
+ drw_command_draw_procedural(shgroup, geom, handle, vert_count);
}
void DRW_shgroup_call_procedural_points(DRWShadingGroup *shgroup, Object *ob, uint point_len)
@@ -524,25 +777,18 @@ void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *shgroup, Object *ob,
drw_shgroup_call_procedural_add_ex(shgroup, geom, ob, tria_count * 3);
}
+/* Should be removed */
void DRW_shgroup_call_instances(DRWShadingGroup *shgroup,
Object *ob,
struct GPUBatch *geom,
uint count)
{
BLI_assert(geom != NULL);
-
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
-
- call->state = drw_call_state_object(shgroup, ob ? ob->obmat : NULL, ob);
- call->batch = geom;
- call->vert_first = 0;
- call->vert_count = 0; /* Auto from batch. */
- call->inst_count = count;
-#ifdef USE_GPU_SELECT
- call->select_id = DST.select_id;
- call->inst_selectid = NULL;
-#endif
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob);
+ drw_command_draw_instance(shgroup, geom, handle, count);
}
void DRW_shgroup_call_instances_with_attribs(DRWShadingGroup *shgroup,
@@ -552,25 +798,16 @@ void DRW_shgroup_call_instances_with_attribs(DRWShadingGroup *shgroup,
{
BLI_assert(geom != NULL);
BLI_assert(inst_attributes->verts[0] != NULL);
-
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob);
GPUVertBuf *buf_inst = inst_attributes->verts[0];
-
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
-
- call->state = drw_call_state_object(shgroup, ob ? ob->obmat : NULL, ob);
- call->batch = DRW_temp_batch_instance_request(DST.idatalist, buf_inst, geom);
- call->vert_first = 0;
- call->vert_count = 0; /* Auto from batch. */
- call->inst_count = buf_inst->vertex_len;
-#ifdef USE_GPU_SELECT
- call->select_id = DST.select_id;
- call->inst_selectid = NULL;
-#endif
+ GPUBatch *batch = DRW_temp_batch_instance_request(DST.idatalist, buf_inst, geom);
+ drw_command_draw(shgroup, batch, handle);
}
-// #define SCULPT_DEBUG_BUFFERS
-
+#define SCULPT_DEBUG_BUFFERS (G.debug_value == 889)
typedef struct DRWSculptCallbackData {
Object *ob;
DRWShadingGroup **shading_groups;
@@ -578,13 +815,11 @@ typedef struct DRWSculptCallbackData {
bool use_mats;
bool use_mask;
bool fast_mode; /* Set by draw manager. Do not init. */
-#ifdef SCULPT_DEBUG_BUFFERS
- int node_nr;
-#endif
+
+ int debug_node_nr;
} DRWSculptCallbackData;
-#ifdef SCULPT_DEBUG_BUFFERS
-# define SCULPT_DEBUG_COLOR(id) (sculpt_debug_colors[id % 9])
+#define SCULPT_DEBUG_COLOR(id) (sculpt_debug_colors[id % 9])
static float sculpt_debug_colors[9][4] = {
{1.0f, 0.2f, 0.2f, 1.0f},
{0.2f, 1.0f, 0.2f, 1.0f},
@@ -596,59 +831,72 @@ static float sculpt_debug_colors[9][4] = {
{0.2f, 1.0f, 0.7f, 1.0f},
{0.7f, 0.2f, 1.0f, 1.0f},
};
-#endif
static void sculpt_draw_cb(DRWSculptCallbackData *scd, GPU_PBVH_Buffers *buffers)
{
- GPUBatch *geom = GPU_pbvh_buffers_batch_get(buffers, scd->fast_mode, scd->use_wire);
- short index = 0;
-
/* Meh... use_mask is a bit misleading here. */
if (scd->use_mask && !GPU_pbvh_buffers_has_mask(buffers)) {
return;
}
+ GPUBatch *geom = GPU_pbvh_buffers_batch_get(buffers, scd->fast_mode, scd->use_wire);
+ short index = 0;
+
if (scd->use_mats) {
index = GPU_pbvh_buffers_material_index_get(buffers);
}
DRWShadingGroup *shgrp = scd->shading_groups[index];
if (geom != NULL && shgrp != NULL) {
-#ifdef SCULPT_DEBUG_BUFFERS
- /* Color each buffers in different colors. Only work in solid/Xray mode. */
- shgrp = DRW_shgroup_create_sub(shgrp);
- DRW_shgroup_uniform_vec3(shgrp, "materialDiffuseColor", SCULPT_DEBUG_COLOR(scd->node_nr++), 1);
-#endif
+ if (SCULPT_DEBUG_BUFFERS) {
+ /* Color each buffers in different colors. Only work in solid/Xray mode. */
+ shgrp = DRW_shgroup_create_sub(shgrp);
+ DRW_shgroup_uniform_vec3(
+ shgrp, "materialDiffuseColor", SCULPT_DEBUG_COLOR(scd->debug_node_nr++), 1);
+ }
/* DRW_shgroup_call_no_cull reuses matrices calculations for all the drawcalls of this
* object. */
DRW_shgroup_call_no_cull(shgrp, geom, scd->ob);
}
}
-#ifdef SCULPT_DEBUG_BUFFERS
static void sculpt_debug_cb(void *user_data,
const float bmin[3],
const float bmax[3],
PBVHNodeFlags flag)
{
- int *node_nr = (int *)user_data;
+ int *debug_node_nr = (int *)user_data;
BoundBox bb;
BKE_boundbox_init_from_minmax(&bb, bmin, bmax);
-# if 0 /* Nodes hierarchy. */
+#if 0 /* Nodes hierarchy. */
if (flag & PBVH_Leaf) {
DRW_debug_bbox(&bb, (float[4]){0.0f, 1.0f, 0.0f, 1.0f});
}
else {
DRW_debug_bbox(&bb, (float[4]){0.5f, 0.5f, 0.5f, 0.6f});
}
-# else /* Color coded leaf bounds. */
+#else /* Color coded leaf bounds. */
if (flag & PBVH_Leaf) {
- DRW_debug_bbox(&bb, SCULPT_DEBUG_COLOR((*node_nr)++));
+ DRW_debug_bbox(&bb, SCULPT_DEBUG_COLOR((*debug_node_nr)++));
}
-# endif
-}
#endif
+}
+
+static void drw_sculpt_get_frustum_planes(Object *ob, float planes[6][4])
+{
+ /* TODO: take into account partial redraw for clipping planes. */
+ DRW_view_frustum_planes_get(DRW_view_default_get(), planes);
+
+ /* Transform clipping planes to object space. Transforming a plane with a
+ * 4x4 matrix is done by multiplying with the transpose inverse.
+ * The inverse cancels out here since we transform by inverse(obmat). */
+ float tmat[4][4];
+ transpose_m4_m4(tmat, ob->obmat);
+ for (int i = 0; i < 6; i++) {
+ mul_m4_v4(tmat, planes[i]);
+ }
+}
static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd, bool use_vcol)
{
@@ -658,31 +906,46 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd, bool use_vcol)
return;
}
- float(*planes)[4] = NULL; /* TODO proper culling. */
- scd->fast_mode = false;
-
const DRWContextState *drwctx = DRW_context_state_get();
+ RegionView3D *rv3d = drwctx->rv3d;
+
+ /* Frustum planes to show only visible PBVH nodes. */
+ float planes[6][4];
+ drw_sculpt_get_frustum_planes(scd->ob, planes);
+ PBVHFrustumPlanes frustum = {.planes = planes, .num_planes = 6};
+
+ /* Fast mode to show low poly multires while navigating. */
+ scd->fast_mode = false;
if (drwctx->evil_C != NULL) {
Paint *p = BKE_paint_get_active_from_context(drwctx->evil_C);
if (p && (p->flags & PAINT_FAST_NAVIGATE)) {
- scd->fast_mode = (drwctx->rv3d->rflag & RV3D_NAVIGATING) != 0;
+ scd->fast_mode = rv3d && (rv3d->rflag & RV3D_NAVIGATING);
}
}
+ /* Update draw buffers only for visible nodes while painting.
+ * But do update them otherwise so navigating stays smooth. */
+ const bool update_only_visible = rv3d && (rv3d->rflag & RV3D_PAINTING);
+
Mesh *mesh = scd->ob->data;
BKE_pbvh_update_normals(pbvh, mesh->runtime.subdiv_ccg);
- BKE_pbvh_update_draw_buffers(pbvh, use_vcol);
- BKE_pbvh_draw_cb(pbvh, planes, (void (*)(void *, GPU_PBVH_Buffers *))sculpt_draw_cb, scd);
+ BKE_pbvh_draw_cb(pbvh,
+ use_vcol,
+ update_only_visible,
+ &frustum,
+ (void (*)(void *, GPU_PBVH_Buffers *))sculpt_draw_cb,
+ scd);
-#ifdef SCULPT_DEBUG_BUFFERS
- int node_nr = 0;
- DRW_debug_modelmat(scd->ob->obmat);
- BKE_pbvh_draw_debug_cb(
- pbvh,
- (void (*)(void *d, const float min[3], const float max[3], PBVHNodeFlags f))sculpt_debug_cb,
- &node_nr);
-#endif
+ if (SCULPT_DEBUG_BUFFERS) {
+ int debug_node_nr = 0;
+ DRW_debug_modelmat(scd->ob->obmat);
+ BKE_pbvh_draw_debug_cb(
+ pbvh,
+ (void (*)(
+ void *d, const float min[3], const float max[3], PBVHNodeFlags f))sculpt_debug_cb,
+ &debug_node_nr);
+ }
}
void DRW_shgroup_call_sculpt(
@@ -719,27 +982,26 @@ DRWCallBuffer *DRW_shgroup_call_buffer(DRWShadingGroup *shgroup,
BLI_assert(ELEM(prim_type, GPU_PRIM_POINTS, GPU_PRIM_LINES, GPU_PRIM_TRI_FAN));
BLI_assert(format != NULL);
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
-
- call->state = drw_call_state_object(shgroup, NULL, NULL);
- GPUVertBuf *buf = DRW_temp_buffer_request(DST.idatalist, format, &call->vert_count);
- call->batch = DRW_temp_batch_request(DST.idatalist, buf, prim_type);
- call->vert_first = 0;
- call->vert_count = 0;
- call->inst_count = 0;
+ DRWCallBuffer *callbuf = BLI_memblock_alloc(DST.vmempool->callbuffers);
+ callbuf->buf = DRW_temp_buffer_request(DST.idatalist, format, &callbuf->count);
+ callbuf->buf_select = NULL;
+ callbuf->count = 0;
-#ifdef USE_GPU_SELECT
if (G.f & G_FLAG_PICKSEL) {
/* Not actually used for rendering but alloced in one chunk. */
if (inst_select_format.attr_len == 0) {
GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT);
}
- call->inst_selectid = DRW_temp_buffer_request(
- DST.idatalist, &inst_select_format, &call->vert_count);
+ callbuf->buf_select = DRW_temp_buffer_request(
+ DST.idatalist, &inst_select_format, &callbuf->count);
+ drw_command_set_select_id(shgroup, callbuf->buf_select, -1);
}
-#endif
- return (DRWCallBuffer *)call;
+
+ DRWResourceHandle handle = drw_resource_handle(shgroup, NULL, NULL);
+ GPUBatch *batch = DRW_temp_batch_request(DST.idatalist, callbuf->buf, prim_type);
+ drw_command_draw(shgroup, batch, handle);
+
+ return callbuf;
}
DRWCallBuffer *DRW_shgroup_call_buffer_instance(DRWShadingGroup *shgroup,
@@ -749,56 +1011,52 @@ DRWCallBuffer *DRW_shgroup_call_buffer_instance(DRWShadingGroup *shgroup,
BLI_assert(geom != NULL);
BLI_assert(format != NULL);
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
-
- call->state = drw_call_state_object(shgroup, NULL, NULL);
- GPUVertBuf *buf = DRW_temp_buffer_request(DST.idatalist, format, &call->inst_count);
- call->batch = DRW_temp_batch_instance_request(DST.idatalist, buf, geom);
- call->vert_first = 0;
- call->vert_count = 0; /* Auto from batch. */
- call->inst_count = 0;
+ DRWCallBuffer *callbuf = BLI_memblock_alloc(DST.vmempool->callbuffers);
+ callbuf->buf = DRW_temp_buffer_request(DST.idatalist, format, &callbuf->count);
+ callbuf->buf_select = NULL;
+ callbuf->count = 0;
-#ifdef USE_GPU_SELECT
if (G.f & G_FLAG_PICKSEL) {
/* Not actually used for rendering but alloced in one chunk. */
if (inst_select_format.attr_len == 0) {
GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT);
}
- call->inst_selectid = DRW_temp_buffer_request(
- DST.idatalist, &inst_select_format, &call->inst_count);
+ callbuf->buf_select = DRW_temp_buffer_request(
+ DST.idatalist, &inst_select_format, &callbuf->count);
+ drw_command_set_select_id(shgroup, callbuf->buf_select, -1);
}
-#endif
- return (DRWCallBuffer *)call;
+
+ DRWResourceHandle handle = drw_resource_handle(shgroup, NULL, NULL);
+ GPUBatch *batch = DRW_temp_batch_instance_request(DST.idatalist, callbuf->buf, geom);
+ drw_command_draw(shgroup, batch, handle);
+
+ return callbuf;
}
void DRW_buffer_add_entry_array(DRWCallBuffer *callbuf, const void *attr[], uint attr_len)
{
- DRWCall *call = (DRWCall *)callbuf;
- const bool is_instance = call->batch->inst != NULL;
- GPUVertBuf *buf = is_instance ? call->batch->inst : call->batch->verts[0];
- uint count = is_instance ? call->inst_count++ : call->vert_count++;
- const bool resize = (count == buf->vertex_alloc);
+ GPUVertBuf *buf = callbuf->buf;
+ const bool resize = (callbuf->count == buf->vertex_alloc);
BLI_assert(attr_len == buf->format.attr_len);
UNUSED_VARS_NDEBUG(attr_len);
if (UNLIKELY(resize)) {
- GPU_vertbuf_data_resize(buf, count + DRW_BUFFER_VERTS_CHUNK);
+ GPU_vertbuf_data_resize(buf, callbuf->count + DRW_BUFFER_VERTS_CHUNK);
}
- for (int i = 0; i < attr_len; ++i) {
- GPU_vertbuf_attr_set(buf, i, count, attr[i]);
+ for (int i = 0; i < attr_len; i++) {
+ GPU_vertbuf_attr_set(buf, i, callbuf->count, attr[i]);
}
-#ifdef USE_GPU_SELECT
if (G.f & G_FLAG_PICKSEL) {
if (UNLIKELY(resize)) {
- GPU_vertbuf_data_resize(call->inst_selectid, count + DRW_BUFFER_VERTS_CHUNK);
+ GPU_vertbuf_data_resize(callbuf->buf_select, callbuf->count + DRW_BUFFER_VERTS_CHUNK);
}
- GPU_vertbuf_attr_set(call->inst_selectid, 0, count, &DST.select_id);
+ GPU_vertbuf_attr_set(callbuf->buf_select, 0, callbuf->count, &DST.select_id);
}
-#endif
+
+ callbuf->count++;
}
/** \} */
@@ -811,7 +1069,54 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
{
shgroup->uniforms = NULL;
+ /* TODO(fclem) make them builtin. */
int view_ubo_location = GPU_shader_get_uniform_block(shader, "viewBlock");
+ int model_ubo_location = GPU_shader_get_uniform_block(shader, "modelBlock");
+ int info_ubo_location = GPU_shader_get_uniform_block(shader, "infoBlock");
+ int baseinst_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_BASE_INSTANCE);
+ int chunkid_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_RESOURCE_CHUNK);
+
+ if (chunkid_location != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, chunkid_location, DRW_UNIFORM_RESOURCE_CHUNK, NULL, 0, 1);
+ }
+
+ if (baseinst_location != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, baseinst_location, DRW_UNIFORM_BASE_INSTANCE, NULL, 0, 1);
+ }
+
+ if (model_ubo_location != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, model_ubo_location, DRW_UNIFORM_BLOCK_OBMATS, NULL, 0, 1);
+ }
+ else {
+ int model = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL);
+ int modelinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL_INV);
+ int modelviewprojection = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP);
+ if (model != -1) {
+ drw_shgroup_uniform_create_ex(shgroup, model, DRW_UNIFORM_MODEL_MATRIX, NULL, 0, 1);
+ }
+ if (modelinverse != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, modelinverse, DRW_UNIFORM_MODEL_MATRIX_INVERSE, NULL, 0, 1);
+ }
+ if (modelviewprojection != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, modelviewprojection, DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX, NULL, 0, 1);
+ }
+ }
+
+ if (info_ubo_location != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, info_ubo_location, DRW_UNIFORM_BLOCK_OBINFOS, NULL, 0, 1);
+
+ /* Abusing this loc to tell shgroup we need the obinfos. */
+ shgroup->objectinfo = 1;
+ }
+ else {
+ shgroup->objectinfo = 0;
+ }
if (view_ubo_location != -1) {
drw_shgroup_uniform_create_ex(
@@ -834,31 +1139,6 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW_INV) == -1);
BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW) == -1);
BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_NORMAL) == -1);
-
- shgroup->model = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL);
- shgroup->modelinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL_INV);
- shgroup->modelviewprojection = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP);
- shgroup->orcotexfac = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_ORCO);
- shgroup->objectinfo = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_OBJECT_INFO);
- shgroup->objectcolor = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_OBJECT_COLOR);
- shgroup->callid = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_CALLID);
-
- shgroup->matflag = 0;
- if (shgroup->modelinverse > -1) {
- shgroup->matflag |= DRW_CALL_MODELINVERSE;
- }
- if (shgroup->modelviewprojection > -1) {
- shgroup->matflag |= DRW_CALL_MODELVIEWPROJECTION;
- }
- if (shgroup->orcotexfac > -1) {
- shgroup->matflag |= DRW_CALL_ORCOTEXFAC;
- }
- if (shgroup->objectinfo > -1) {
- shgroup->matflag |= DRW_CALL_OBJECTINFO;
- }
- if (shgroup->objectcolor > -1) {
- shgroup->matflag |= DRW_CALL_OBJECTCOLOR;
- }
}
static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass *pass)
@@ -868,13 +1148,9 @@ static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass
BLI_LINKS_APPEND(&pass->shgroups, shgroup);
shgroup->shader = shader;
- shgroup->state_extra = 0;
- shgroup->state_extra_disable = ~0x0;
- shgroup->stencil_mask = 0;
- shgroup->calls.first = NULL;
- shgroup->calls.last = NULL;
- shgroup->tfeedback_target = NULL;
- shgroup->pass_parent = pass;
+ shgroup->cmd.first = NULL;
+ shgroup->cmd.last = NULL;
+ shgroup->pass_handle = pass->handle;
return shgroup;
}
@@ -939,7 +1215,7 @@ GPUVertFormat *DRW_shgroup_instance_format_array(const DRWInstanceAttrFormat att
{
GPUVertFormat *format = MEM_callocN(sizeof(GPUVertFormat), "GPUVertFormat");
- for (int i = 0; i < arraysize; ++i) {
+ for (int i = 0; i < arraysize; i++) {
GPU_vertformat_attr_add(format,
attrs[i].name,
(attrs[i].type == DRW_ATTR_INT) ? GPU_COMP_I32 : GPU_COMP_F32,
@@ -975,7 +1251,7 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader,
BLI_assert(tf_target != NULL);
DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
drw_shgroup_init(shgroup, shader);
- shgroup->tfeedback_target = tf_target;
+ drw_shgroup_uniform_create_ex(shgroup, 0, DRW_UNIFORM_TFEEDBACK_TARGET, tf_target, 0, 1);
return shgroup;
}
@@ -985,37 +1261,42 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader,
*/
void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state)
{
- shgroup->state_extra |= state;
+ drw_command_set_mutable_state(shgroup, state, 0x0);
}
void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state)
{
- shgroup->state_extra_disable &= ~state;
+ drw_command_set_mutable_state(shgroup, 0x0, state);
}
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask)
{
- BLI_assert(mask <= 255);
- shgroup->stencil_mask = mask;
-}
-
-bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup)
-{
- return shgroup->calls.first == NULL;
+ drw_command_set_stencil_mask(shgroup, mask);
}
-/* This is a workaround function waiting for the clearing operation to be available inside the
- * shgroups. */
-DRWShadingGroup *DRW_shgroup_get_next(DRWShadingGroup *shgroup)
+void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup,
+ eGPUFrameBufferBits channels,
+ uchar r,
+ uchar g,
+ uchar b,
+ uchar a,
+ float depth,
+ uchar stencil)
{
- return shgroup->next;
+ drw_command_clear(shgroup, channels, r, g, b, a, depth, stencil);
}
-/* This is a workaround function waiting for the clearing operation to be available inside the
- * shgroups. */
-uint DRW_shgroup_stencil_mask_get(DRWShadingGroup *shgroup)
+bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup)
{
- return shgroup->stencil_mask;
+ DRWCommandChunk *chunk = shgroup->cmd.first;
+ for (; chunk; chunk = chunk->next) {
+ for (int i = 0; i < chunk->command_used; i++) {
+ if (command_type_get(chunk->command_type, i) <= DRW_MAX_DRAW_CMD_TYPE) {
+ return false;
+ }
+ }
+ }
+ return true;
}
DRWShadingGroup *DRW_shgroup_create_sub(DRWShadingGroup *shgroup)
@@ -1023,11 +1304,14 @@ DRWShadingGroup *DRW_shgroup_create_sub(DRWShadingGroup *shgroup)
DRWShadingGroup *shgroup_new = BLI_memblock_alloc(DST.vmempool->shgroups);
*shgroup_new = *shgroup;
- shgroup_new->uniforms = NULL;
- shgroup_new->calls.first = NULL;
- shgroup_new->calls.last = NULL;
+ drw_shgroup_init(shgroup_new, shgroup_new->shader);
+ shgroup_new->cmd.first = NULL;
+ shgroup_new->cmd.last = NULL;
- BLI_LINKS_INSERT_AFTER(&shgroup->pass_parent->shgroups, shgroup, shgroup_new);
+ DRWPass *parent_pass = DRW_memblock_elem_from_handle(DST.vmempool->passes,
+ &shgroup->pass_handle);
+
+ BLI_LINKS_INSERT_AFTER(&parent_pass->shgroups, shgroup, shgroup_new);
return shgroup_new;
}
@@ -1522,6 +1806,8 @@ DRWPass *DRW_pass_create(const char *name, DRWState state)
pass->shgroups.first = NULL;
pass->shgroups.last = NULL;
+ pass->handle = DST.pass_handle;
+ DRW_handle_increment(&DST.pass_handle);
return pass;
}
@@ -1565,42 +1851,22 @@ typedef struct ZSortData {
const float *origin;
} ZSortData;
-static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b)
+static int pass_shgroup_dist_sort(const void *a, const void *b)
{
- const ZSortData *zsortdata = (ZSortData *)thunk;
const DRWShadingGroup *shgrp_a = (const DRWShadingGroup *)a;
const DRWShadingGroup *shgrp_b = (const DRWShadingGroup *)b;
- const DRWCall *call_a = (DRWCall *)shgrp_a->calls.first;
- const DRWCall *call_b = (DRWCall *)shgrp_b->calls.first;
-
- if (call_a == NULL) {
- return -1;
- }
- if (call_b == NULL) {
- return -1;
- }
-
- float tmp[3];
- sub_v3_v3v3(tmp, zsortdata->origin, call_a->state->model[3]);
- const float a_sq = dot_v3v3(zsortdata->axis, tmp);
- sub_v3_v3v3(tmp, zsortdata->origin, call_b->state->model[3]);
- const float b_sq = dot_v3v3(zsortdata->axis, tmp);
-
- if (a_sq < b_sq) {
+ if (shgrp_a->z_sorting.distance < shgrp_b->z_sorting.distance) {
return 1;
}
- else if (a_sq > b_sq) {
+ else if (shgrp_a->z_sorting.distance > shgrp_b->z_sorting.distance) {
return -1;
}
else {
- /* If there is a depth prepass put it before */
- if ((shgrp_a->state_extra & DRW_STATE_WRITE_DEPTH) != 0) {
+ /* If distances are the same, keep original order. */
+ if (shgrp_a->z_sorting.original_index > shgrp_b->z_sorting.original_index) {
return -1;
}
- else if ((shgrp_b->state_extra & DRW_STATE_WRITE_DEPTH) != 0) {
- return 1;
- }
else {
return 0;
}
@@ -1611,35 +1877,61 @@ static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b)
#define SORT_IMPL_LINKTYPE DRWShadingGroup
-#define SORT_IMPL_USE_THUNK
#define SORT_IMPL_FUNC shgroup_sort_fn_r
#include "../../blenlib/intern/list_sort_impl.h"
#undef SORT_IMPL_FUNC
-#undef SORT_IMPL_USE_THUNK
#undef SORT_IMPL_LINKTYPE
/**
* Sort Shading groups by decreasing Z of their first draw call.
- * This is useful for order dependent effect such as transparency.
+ * This is useful for order dependent effect such as alpha-blending.
*/
void DRW_pass_sort_shgroup_z(DRWPass *pass)
{
const float(*viewinv)[4] = DST.view_active->storage.viewinv;
- ZSortData zsortdata = {viewinv[2], viewinv[3]};
-
- if (pass->shgroups.first && pass->shgroups.first->next) {
- pass->shgroups.first = shgroup_sort_fn_r(
- pass->shgroups.first, pass_shgroup_dist_sort, &zsortdata);
+ if (!(pass->shgroups.first && pass->shgroups.first->next)) {
+ /* Nothing to sort */
+ return;
+ }
- /* Find the next last */
- DRWShadingGroup *last = pass->shgroups.first;
- while ((last = last->next)) {
- /* Do nothing */
+ uint index = 0;
+ DRWShadingGroup *shgroup = pass->shgroups.first;
+ do {
+ DRWResourceHandle handle = 0;
+ /* Find first DRWCommandDraw. */
+ DRWCommandChunk *cmd_chunk = shgroup->cmd.first;
+ for (; cmd_chunk && handle == 0; cmd_chunk = cmd_chunk->next) {
+ for (int i = 0; i < cmd_chunk->command_used && handle == 0; i++) {
+ if (DRW_CMD_DRAW == command_type_get(cmd_chunk->command_type, i)) {
+ handle = cmd_chunk->commands[i].draw.handle;
+ }
+ }
}
- pass->shgroups.last = last;
+ /* To be sorted a shgroup needs to have at least one draw command. */
+ BLI_assert(handle != 0);
+
+ DRWObjectMatrix *obmats = DRW_memblock_elem_from_handle(DST.vmempool->obmats, &handle);
+
+ /* Compute distance to camera. */
+ float tmp[3];
+ sub_v3_v3v3(tmp, viewinv[3], obmats->model[3]);
+ shgroup->z_sorting.distance = dot_v3v3(viewinv[2], tmp);
+ shgroup->z_sorting.original_index = index++;
+
+ } while ((shgroup = shgroup->next));
+
+ /* Sort using computed distances. */
+ pass->shgroups.first = shgroup_sort_fn_r(pass->shgroups.first, pass_shgroup_dist_sort);
+
+ /* Find the new last */
+ DRWShadingGroup *last = pass->shgroups.first;
+ while ((last = last->next)) {
+ /* Reset the pass id for debugging. */
+ last->pass_handle = pass->handle;
}
+ pass->shgroups.last = last;
}
/** \} */
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index 50408015fbc..3de9ce74dbc 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -28,7 +28,6 @@
#include "BKE_global.h"
-#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "intern/gpu_shader_private.h"
#include "intern/gpu_primitive_private.h"
@@ -37,16 +36,41 @@
# include "GPU_select.h"
#endif
-#ifdef USE_GPU_SELECT
void DRW_select_load_id(uint id)
{
+#ifdef USE_GPU_SELECT
BLI_assert(G.f & G_FLAG_PICKSEL);
DST.select_id = id;
-}
#endif
+}
#define DEBUG_UBO_BINDING
+typedef struct DRWCommandsState {
+ GPUBatch *batch;
+ int resource_chunk;
+ int base_inst;
+ int inst_count;
+ int v_first;
+ int v_count;
+ bool neg_scale;
+ /* Resource location. */
+ int obmats_loc;
+ int obinfos_loc;
+ int baseinst_loc;
+ int chunkid_loc;
+ /* Legacy matrix support. */
+ int obmat_loc;
+ int obinv_loc;
+ int mvp_loc;
+ /* Selection ID state. */
+ GPUVertBuf *select_buf;
+ uint select_id;
+ /* Drawing State */
+ DRWState drw_state_enabled;
+ DRWState drw_state_disabled;
+} DRWCommandsState;
+
/* -------------------------------------------------------------------- */
/** \name Draw State (DRW_state)
* \{ */
@@ -279,17 +303,34 @@ void drw_state_set(DRWState state)
}
}
+ /* Shadow Bias */
+ {
+ int test;
+ if ((test = CHANGED_TO(DRW_STATE_SHADOW_OFFSET))) {
+ if (test == 1) {
+ glEnable(GL_POLYGON_OFFSET_FILL);
+ glEnable(GL_POLYGON_OFFSET_LINE);
+ /* 2.0 Seems to be the lowest possible slope bias that works in every case. */
+ glPolygonOffset(2.0f, 1.0f);
+ }
+ else {
+ glDisable(GL_POLYGON_OFFSET_FILL);
+ glDisable(GL_POLYGON_OFFSET_LINE);
+ }
+ }
+ }
+
/* Clip Planes */
{
int test;
if ((test = CHANGED_TO(DRW_STATE_CLIP_PLANES))) {
if (test == 1) {
- for (int i = 0; i < DST.view_active->clip_planes_len; ++i) {
+ for (int i = 0; i < DST.view_active->clip_planes_len; i++) {
glEnable(GL_CLIP_DISTANCE0 + i);
}
}
else {
- for (int i = 0; i < MAX_CLIP_PLANES; ++i) {
+ for (int i = 0; i < MAX_CLIP_PLANES; i++) {
glDisable(GL_CLIP_DISTANCE0 + i);
}
}
@@ -391,9 +432,10 @@ void DRW_state_reset(void)
/** \name Culling (DRW_culling)
* \{ */
-static bool draw_call_is_culled(DRWCall *call, DRWView *view)
+static bool draw_call_is_culled(const DRWResourceHandle *handle, DRWView *view)
{
- return (call->state->culling->mask & view->culling_mask) != 0;
+ DRWCullingState *culling = DRW_memblock_elem_from_handle(DST.vmempool->cullstates, handle);
+ return (culling->mask & view->culling_mask) != 0;
}
/* Set active view for rendering. */
@@ -572,66 +614,96 @@ static void draw_compute_culling(DRWView *view)
/** \name Draw (DRW_draw)
* \{ */
-static void draw_geometry_prepare(DRWShadingGroup *shgroup, DRWCall *call)
+BLI_INLINE void draw_legacy_matrix_update(DRWShadingGroup *shgroup,
+ DRWResourceHandle *handle,
+ float obmat_loc,
+ float obinv_loc,
+ float mvp_loc)
{
- BLI_assert(call);
- DRWCallState *state = call->state;
-
- if (shgroup->model != -1) {
- GPU_shader_uniform_vector(shgroup->shader, shgroup->model, 16, 1, (float *)state->model);
+ /* Still supported for compatibility with gpu_shader_* but should be forbidden. */
+ DRWObjectMatrix *ob_mats = DRW_memblock_elem_from_handle(DST.vmempool->obmats, handle);
+ if (obmat_loc != -1) {
+ GPU_shader_uniform_vector(shgroup->shader, obmat_loc, 16, 1, (float *)ob_mats->model);
}
- if (shgroup->modelinverse != -1) {
- GPU_shader_uniform_vector(
- shgroup->shader, shgroup->modelinverse, 16, 1, (float *)state->modelinverse);
- }
- if (shgroup->objectinfo != -1) {
- float infos[4];
- infos[0] = state->ob_index;
- // infos[1]; /* UNUSED. */
- infos[2] = state->ob_random;
- infos[3] = (state->flag & DRW_CALL_NEGSCALE) ? -1.0f : 1.0f;
- GPU_shader_uniform_vector(shgroup->shader, shgroup->objectinfo, 4, 1, (float *)infos);
- }
- if (shgroup->objectcolor != -1) {
- GPU_shader_uniform_vector(
- shgroup->shader, shgroup->objectcolor, 4, 1, (float *)state->ob_color);
- }
- if (shgroup->orcotexfac != -1) {
- GPU_shader_uniform_vector(
- shgroup->shader, shgroup->orcotexfac, 3, 2, (float *)state->orcotexfac);
+ if (obinv_loc != -1) {
+ GPU_shader_uniform_vector(shgroup->shader, obinv_loc, 16, 1, (float *)ob_mats->modelinverse);
}
/* Still supported for compatibility with gpu_shader_* but should be forbidden
* and is slow (since it does not cache the result). */
- if (shgroup->modelviewprojection != -1) {
+ if (mvp_loc != -1) {
float mvp[4][4];
- mul_m4_m4m4(mvp, DST.view_active->storage.persmat, state->model);
- GPU_shader_uniform_vector(shgroup->shader, shgroup->modelviewprojection, 16, 1, (float *)mvp);
+ mul_m4_m4m4(mvp, DST.view_active->storage.persmat, ob_mats->model);
+ GPU_shader_uniform_vector(shgroup->shader, mvp_loc, 16, 1, (float *)mvp);
}
}
+BLI_INLINE void draw_geometry_bind(DRWShadingGroup *shgroup, GPUBatch *geom)
+{
+ /* XXX hacking #GPUBatch. we don't want to call glUseProgram! (huge performance loss) */
+ if (DST.batch) {
+ DST.batch->program_in_use = false;
+ }
+
+ DST.batch = geom;
+
+ GPU_batch_program_set_no_use(
+ geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader));
+
+ geom->program_in_use = true; /* XXX hacking #GPUBatch */
+
+ GPU_batch_bind(geom);
+}
+
BLI_INLINE void draw_geometry_execute(DRWShadingGroup *shgroup,
GPUBatch *geom,
- uint vert_first,
- uint vert_count,
- uint inst_first,
- uint inst_count)
+ int vert_first,
+ int vert_count,
+ int inst_first,
+ int inst_count,
+ int baseinst_loc)
{
+ /* inst_count can be -1. */
+ inst_count = max_ii(0, inst_count);
+
+ if (baseinst_loc != -1) {
+ /* Fallback when ARB_shader_draw_parameters is not supported. */
+ GPU_shader_uniform_vector_int(shgroup->shader, baseinst_loc, 1, 1, (int *)&inst_first);
+ /* Avoids VAO reconfiguration on older hardware. (see GPU_batch_draw_advanced) */
+ inst_first = 0;
+ }
+
/* bind vertex array */
if (DST.batch != geom) {
- DST.batch = geom;
-
- GPU_batch_program_set_no_use(
- geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader));
-
- GPU_batch_bind(geom);
+ draw_geometry_bind(shgroup, geom);
}
- /* XXX hacking #GPUBatch. we don't want to call glUseProgram! (huge performance loss) */
- geom->program_in_use = true;
-
GPU_batch_draw_advanced(geom, vert_first, vert_count, inst_first, inst_count);
+}
- geom->program_in_use = false; /* XXX hacking #GPUBatch */
+BLI_INLINE void draw_indirect_call(DRWShadingGroup *shgroup, DRWCommandsState *state)
+{
+ if (state->inst_count == 0) {
+ return;
+ }
+ if (state->baseinst_loc == -1) {
+ /* bind vertex array */
+ if (DST.batch != state->batch) {
+ GPU_draw_list_submit(DST.draw_list);
+ draw_geometry_bind(shgroup, state->batch);
+ }
+ GPU_draw_list_command_add(
+ DST.draw_list, state->v_first, state->v_count, state->base_inst, state->inst_count);
+ }
+ /* Fallback when unsupported */
+ else {
+ draw_geometry_execute(shgroup,
+ state->batch,
+ state->v_first,
+ state->v_count,
+ state->base_inst,
+ state->inst_count,
+ state->baseinst_loc);
+ }
}
enum {
@@ -703,6 +775,9 @@ static void bind_ubo(GPUUniformBuffer *ubo, char bind_type)
/* UBO isn't bound yet. Find an empty slot and bind it. */
idx = get_empty_slot_index(DST.RST.bound_ubo_slots);
+ /* [0..1] are reserved ubo slots. */
+ idx += 2;
+
if (idx < GPU_max_ubo_binds()) {
GPUUniformBuffer **gpu_ubo_slot = &DST.RST.bound_ubos[idx];
/* Unbind any previous UBO. */
@@ -722,10 +797,13 @@ static void bind_ubo(GPUUniformBuffer *ubo, char bind_type)
}
}
else {
+ BLI_assert(idx < 64);
/* This UBO slot was released but the UBO is
* still bound here. Just flag the slot again. */
BLI_assert(DST.RST.bound_ubos[idx] == ubo);
}
+ /* Remove offset for flag bitfield. */
+ idx -= 2;
set_bound_flags(&DST.RST.bound_ubo_slots, &DST.RST.bound_ubo_slots_persist, idx, bind_type);
}
@@ -754,7 +832,7 @@ static bool ubo_bindings_validate(DRWShadingGroup *shgroup)
glGetIntegerv(GL_CURRENT_PROGRAM, &program);
glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &active_blocks);
- for (uint i = 0; i < active_blocks; ++i) {
+ for (uint i = 0; i < active_blocks; i++) {
int binding = 0;
int buffer = 0;
@@ -769,8 +847,12 @@ static bool ubo_bindings_validate(DRWShadingGroup *shgroup)
printf("Trying to draw with missing UBO binding.\n");
valid = false;
}
+
+ DRWPass *parent_pass = DRW_memblock_elem_from_handle(DST.vmempool->passes,
+ &shgroup->pass_handle);
+
printf("Pass : %s, Shader : %s, Block : %s\n",
- shgroup->pass_parent->name,
+ parent_pass->name,
shgroup->shader->name,
blockname);
}
@@ -802,119 +884,331 @@ static void release_ubo_slots(bool with_persist)
}
}
-static void draw_update_uniforms(DRWShadingGroup *shgroup)
+static void draw_update_uniforms(DRWShadingGroup *shgroup,
+ DRWCommandsState *state,
+ bool *use_tfeedback)
{
- for (DRWUniform *uni = shgroup->uniforms; uni; uni = uni->next) {
- GPUTexture *tex;
- GPUUniformBuffer *ubo;
- if (uni->location == -2) {
- uni->location = GPU_shader_get_uniform_ensure(shgroup->shader,
- DST.uniform_names.buffer + uni->name_ofs);
- if (uni->location == -1) {
- continue;
+ for (DRWUniformChunk *unichunk = shgroup->uniforms; unichunk; unichunk = unichunk->next) {
+ DRWUniform *uni = unichunk->uniforms;
+ for (int i = 0; i < unichunk->uniform_used; i++, uni++) {
+ GPUTexture *tex;
+ GPUUniformBuffer *ubo;
+ if (uni->location == -2) {
+ uni->location = GPU_shader_get_uniform_ensure(shgroup->shader,
+ DST.uniform_names.buffer + uni->name_ofs);
+ if (uni->location == -1) {
+ continue;
+ }
+ }
+ const void *data = uni->pvalue;
+ if (ELEM(uni->type, DRW_UNIFORM_INT_COPY, DRW_UNIFORM_FLOAT_COPY)) {
+ data = uni->fvalue;
+ }
+ switch (uni->type) {
+ case DRW_UNIFORM_INT_COPY:
+ case DRW_UNIFORM_INT:
+ GPU_shader_uniform_vector_int(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, data);
+ break;
+ case DRW_UNIFORM_FLOAT_COPY:
+ case DRW_UNIFORM_FLOAT:
+ GPU_shader_uniform_vector(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, data);
+ break;
+ case DRW_UNIFORM_TEXTURE:
+ tex = (GPUTexture *)uni->pvalue;
+ BLI_assert(tex);
+ bind_texture(tex, BIND_TEMP);
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_TEXTURE_PERSIST:
+ tex = (GPUTexture *)uni->pvalue;
+ BLI_assert(tex);
+ bind_texture(tex, BIND_PERSIST);
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_TEXTURE_REF:
+ tex = *((GPUTexture **)uni->pvalue);
+ BLI_assert(tex);
+ bind_texture(tex, BIND_TEMP);
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_BLOCK:
+ ubo = (GPUUniformBuffer *)uni->pvalue;
+ bind_ubo(ubo, BIND_TEMP);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ case DRW_UNIFORM_BLOCK_PERSIST:
+ ubo = (GPUUniformBuffer *)uni->pvalue;
+ bind_ubo(ubo, BIND_PERSIST);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ case DRW_UNIFORM_BLOCK_OBMATS:
+ state->obmats_loc = uni->location;
+ ubo = DST.vmempool->matrices_ubo[0];
+ GPU_uniformbuffer_bind(ubo, 0);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ case DRW_UNIFORM_BLOCK_OBINFOS:
+ state->obinfos_loc = uni->location;
+ ubo = DST.vmempool->obinfos_ubo[0];
+ GPU_uniformbuffer_bind(ubo, 1);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ case DRW_UNIFORM_RESOURCE_CHUNK:
+ state->chunkid_loc = uni->location;
+ GPU_shader_uniform_int(shgroup->shader, uni->location, 0);
+ break;
+ case DRW_UNIFORM_TFEEDBACK_TARGET:
+ BLI_assert(data && (*use_tfeedback == false));
+ *use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader,
+ ((GPUVertBuf *)data)->vbo_id);
+ break;
+ /* Legacy/Fallback support. */
+ case DRW_UNIFORM_BASE_INSTANCE:
+ state->baseinst_loc = uni->location;
+ break;
+ case DRW_UNIFORM_MODEL_MATRIX:
+ state->obmat_loc = uni->location;
+ break;
+ case DRW_UNIFORM_MODEL_MATRIX_INVERSE:
+ state->obinv_loc = uni->location;
+ break;
+ case DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX:
+ state->mvp_loc = uni->location;
+ break;
}
- }
- const void *data = uni->pvalue;
- if (ELEM(uni->type, DRW_UNIFORM_INT_COPY, DRW_UNIFORM_FLOAT_COPY)) {
- data = uni->fvalue;
- }
- switch (uni->type) {
- case DRW_UNIFORM_INT_COPY:
- case DRW_UNIFORM_INT:
- GPU_shader_uniform_vector_int(
- shgroup->shader, uni->location, uni->length, uni->arraysize, data);
- break;
- case DRW_UNIFORM_FLOAT_COPY:
- case DRW_UNIFORM_FLOAT:
- GPU_shader_uniform_vector(
- shgroup->shader, uni->location, uni->length, uni->arraysize, data);
- break;
- case DRW_UNIFORM_TEXTURE:
- tex = (GPUTexture *)uni->pvalue;
- BLI_assert(tex);
- bind_texture(tex, BIND_TEMP);
- GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
- break;
- case DRW_UNIFORM_TEXTURE_PERSIST:
- tex = (GPUTexture *)uni->pvalue;
- BLI_assert(tex);
- bind_texture(tex, BIND_PERSIST);
- GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
- break;
- case DRW_UNIFORM_TEXTURE_REF:
- tex = *((GPUTexture **)uni->pvalue);
- BLI_assert(tex);
- bind_texture(tex, BIND_TEMP);
- GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
- break;
- case DRW_UNIFORM_BLOCK:
- ubo = (GPUUniformBuffer *)uni->pvalue;
- bind_ubo(ubo, BIND_TEMP);
- GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
- break;
- case DRW_UNIFORM_BLOCK_PERSIST:
- ubo = (GPUUniformBuffer *)uni->pvalue;
- bind_ubo(ubo, BIND_PERSIST);
- GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
- break;
}
}
BLI_assert(ubo_bindings_validate(shgroup));
}
-BLI_INLINE bool draw_select_do_call(DRWShadingGroup *shgroup, DRWCall *call)
+BLI_INLINE void draw_select_buffer(DRWShadingGroup *shgroup,
+ DRWCommandsState *state,
+ GPUBatch *batch,
+ const DRWResourceHandle *handle)
{
-#ifdef USE_GPU_SELECT
- if ((G.f & G_FLAG_PICKSEL) == 0) {
- return false;
+ const bool is_instancing = (batch->inst != NULL);
+ int start = 0;
+ int count = 1;
+ int tot = is_instancing ? batch->inst->vertex_len : batch->verts[0]->vertex_len;
+ /* Hack : get "vbo" data without actually drawing. */
+ int *select_id = (void *)state->select_buf->data;
+
+ /* Batching */
+ if (!is_instancing) {
+ /* FIXME: Meh a bit nasty. */
+ if (batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_TRIS)) {
+ count = 3;
+ }
+ else if (batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_LINES)) {
+ count = 2;
+ }
}
- if (call->inst_selectid != NULL) {
- const bool is_instancing = (call->inst_count != 0);
- uint start = 0;
- uint count = 1;
- uint tot = is_instancing ? call->inst_count : call->vert_count;
- /* Hack : get vbo data without actually drawing. */
- GPUVertBufRaw raw;
- GPU_vertbuf_attr_get_raw_data(call->inst_selectid, 0, &raw);
- int *select_id = GPU_vertbuf_raw_step(&raw);
-
- /* Batching */
- if (!is_instancing) {
- /* FIXME: Meh a bit nasty. */
- if (call->batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_TRIS)) {
- count = 3;
- }
- else if (call->batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_LINES)) {
- count = 2;
- }
+
+ while (start < tot) {
+ GPU_select_load_id(select_id[start]);
+ if (is_instancing) {
+ draw_geometry_execute(shgroup, batch, 0, 0, start, count, state->baseinst_loc);
+ }
+ else {
+ draw_geometry_execute(
+ shgroup, batch, start, count, DRW_handle_id_get(handle), 0, state->baseinst_loc);
}
+ start += count;
+ }
+}
- while (start < tot) {
- GPU_select_load_id(select_id[start]);
- if (is_instancing) {
- draw_geometry_execute(shgroup, call->batch, 0, 0, start, count);
- }
- else {
- draw_geometry_execute(shgroup, call->batch, start, count, 0, 0);
+typedef struct DRWCommandIterator {
+ int cmd_index;
+ DRWCommandChunk *curr_chunk;
+} DRWCommandIterator;
+
+static void draw_command_iter_begin(DRWCommandIterator *iter, DRWShadingGroup *shgroup)
+{
+ iter->curr_chunk = shgroup->cmd.first;
+ iter->cmd_index = 0;
+}
+
+static DRWCommand *draw_command_iter_step(DRWCommandIterator *iter, eDRWCommandType *cmd_type)
+{
+ if (iter->curr_chunk) {
+ if (iter->cmd_index == iter->curr_chunk->command_len) {
+ iter->curr_chunk = iter->curr_chunk->next;
+ iter->cmd_index = 0;
+ }
+ if (iter->curr_chunk) {
+ *cmd_type = command_type_get(iter->curr_chunk->command_type, iter->cmd_index);
+ if (iter->cmd_index < iter->curr_chunk->command_used) {
+ return iter->curr_chunk->commands + iter->cmd_index++;
}
- start += count;
}
- return true;
}
+ return NULL;
+}
+
+static void draw_call_resource_bind(DRWCommandsState *state, const DRWResourceHandle *handle)
+{
+ /* Front face is not a resource but it is inside the resource handle. */
+ bool neg_scale = DRW_handle_negative_scale_get(handle);
+ if (neg_scale != state->neg_scale) {
+ glFrontFace((neg_scale) ? GL_CW : GL_CCW);
+ state->neg_scale = neg_scale;
+ }
+
+ int chunk = DRW_handle_chunk_get(handle);
+ if (state->resource_chunk != chunk) {
+ if (state->chunkid_loc != -1) {
+ GPU_shader_uniform_int(NULL, state->chunkid_loc, chunk);
+ }
+ if (state->obmats_loc != -1) {
+ GPU_uniformbuffer_unbind(DST.vmempool->matrices_ubo[state->resource_chunk]);
+ GPU_uniformbuffer_bind(DST.vmempool->matrices_ubo[chunk], 0);
+ }
+ if (state->obinfos_loc != -1) {
+ GPU_uniformbuffer_unbind(DST.vmempool->obinfos_ubo[state->resource_chunk]);
+ GPU_uniformbuffer_bind(DST.vmempool->obinfos_ubo[chunk], 1);
+ }
+ state->resource_chunk = chunk;
+ }
+}
+
+static void draw_call_batching_flush(DRWShadingGroup *shgroup, DRWCommandsState *state)
+{
+ draw_indirect_call(shgroup, state);
+ GPU_draw_list_submit(DST.draw_list);
+
+ state->batch = NULL;
+ state->inst_count = 0;
+ state->base_inst = -1;
+}
+
+static void draw_call_single_do(DRWShadingGroup *shgroup,
+ DRWCommandsState *state,
+ GPUBatch *batch,
+ DRWResourceHandle handle,
+ int vert_first,
+ int vert_count,
+ int inst_count)
+{
+ draw_call_batching_flush(shgroup, state);
+
+ draw_call_resource_bind(state, &handle);
+
+ /* TODO This is Legacy. Need to be removed. */
+ if (state->obmats_loc == -1 &&
+ (state->obmat_loc != -1 || state->obinv_loc != -1 || state->mvp_loc != -1)) {
+ draw_legacy_matrix_update(
+ shgroup, &handle, state->obmat_loc, state->obinv_loc, state->mvp_loc);
+ }
+
+ if (G.f & G_FLAG_PICKSEL) {
+ if (state->select_buf != NULL) {
+ draw_select_buffer(shgroup, state, batch, &handle);
+ return;
+ }
+ else {
+ GPU_select_load_id(state->select_id);
+ }
+ }
+
+ draw_geometry_execute(shgroup,
+ batch,
+ vert_first,
+ vert_count,
+ DRW_handle_id_get(&handle),
+ inst_count,
+ state->baseinst_loc);
+}
+
+static void draw_call_batching_start(DRWCommandsState *state)
+{
+ state->neg_scale = false;
+ state->resource_chunk = 0;
+ state->base_inst = 0;
+ state->inst_count = 0;
+ state->v_first = 0;
+ state->v_count = 0;
+ state->batch = NULL;
+
+ state->select_id = -1;
+ state->select_buf = NULL;
+}
+
+/* NOTE: Does not support batches with instancing VBOs. */
+static void draw_call_batching_do(DRWShadingGroup *shgroup,
+ DRWCommandsState *state,
+ DRWCommandDraw *call)
+{
+ /* If any condition requires to interupt the merging. */
+ bool neg_scale = DRW_handle_negative_scale_get(&call->handle);
+ int chunk = DRW_handle_chunk_get(&call->handle);
+ int id = DRW_handle_id_get(&call->handle);
+ if ((state->neg_scale != neg_scale) || /* Need to change state. */
+ (state->resource_chunk != chunk) || /* Need to change UBOs. */
+ (state->batch != call->batch) /* Need to change VAO. */
+ ) {
+ draw_call_batching_flush(shgroup, state);
+
+ state->batch = call->batch;
+ state->v_first = (call->batch->elem) ? call->batch->elem->index_start : 0;
+ state->v_count = (call->batch->elem) ? call->batch->elem->index_len :
+ call->batch->verts[0]->vertex_len;
+ state->inst_count = 1;
+ state->base_inst = id;
+
+ draw_call_resource_bind(state, &call->handle);
+
+ GPU_draw_list_init(DST.draw_list, state->batch);
+ }
+ /* Is the id consecutive? */
+ else if (id != state->base_inst + state->inst_count) {
+ /* We need to add a draw command for the pending instances. */
+ draw_indirect_call(shgroup, state);
+ state->inst_count = 1;
+ state->base_inst = id;
+ }
+ /* We avoid a drawcall by merging with the precedent
+ * drawcall using instancing. */
else {
- GPU_select_load_id(call->select_id);
- return false;
+ state->inst_count++;
+ }
+}
+
+/* Flush remaining pending drawcalls. */
+static void draw_call_batching_finish(DRWShadingGroup *shgroup, DRWCommandsState *state)
+{
+ draw_call_batching_flush(shgroup, state);
+
+ /* Reset state */
+ if (state->neg_scale) {
+ glFrontFace(GL_CCW);
+ }
+ if (state->obmats_loc != -1) {
+ GPU_uniformbuffer_unbind(DST.vmempool->matrices_ubo[state->resource_chunk]);
+ }
+ if (state->obinfos_loc != -1) {
+ GPU_uniformbuffer_unbind(DST.vmempool->obinfos_ubo[state->resource_chunk]);
}
-#else
- return false;
-#endif
}
static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
{
BLI_assert(shgroup->shader);
+ DRWCommandsState state = {
+ .obmats_loc = -1,
+ .obinfos_loc = -1,
+ .baseinst_loc = -1,
+ .chunkid_loc = -1,
+ .obmat_loc = -1,
+ .obinv_loc = -1,
+ .mvp_loc = -1,
+ .drw_state_enabled = 0,
+ .drw_state_disabled = 0,
+ };
+
const bool shader_changed = (DST.shader != shgroup->shader);
bool use_tfeedback = false;
@@ -924,56 +1218,116 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
}
GPU_shader_bind(shgroup->shader);
DST.shader = shgroup->shader;
+ /* XXX hacking gawain */
+ if (DST.batch) {
+ DST.batch->program_in_use = false;
+ }
DST.batch = NULL;
}
- if (shgroup->tfeedback_target != NULL) {
- use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader,
- shgroup->tfeedback_target->vbo_id);
- }
-
release_ubo_slots(shader_changed);
release_texture_slots(shader_changed);
- drw_state_set((pass_state & shgroup->state_extra_disable) | shgroup->state_extra);
- drw_stencil_set(shgroup->stencil_mask);
+ draw_update_uniforms(shgroup, &state, &use_tfeedback);
- draw_update_uniforms(shgroup);
+ drw_state_set(pass_state);
/* Rendering Calls */
{
- bool prev_neg_scale = false;
- int callid = 0;
- for (DRWCall *call = shgroup->calls.first; call; call = call->next) {
-
- if (draw_call_is_culled(call, DST.view_active)) {
- continue;
- }
-
- /* XXX small exception/optimisation for outline rendering. */
- if (shgroup->callid != -1) {
- GPU_shader_uniform_vector_int(shgroup->shader, shgroup->callid, 1, 1, &callid);
- callid += 1;
- }
-
- /* Negative scale objects */
- bool neg_scale = call->state->flag & DRW_CALL_NEGSCALE;
- if (neg_scale != prev_neg_scale) {
- glFrontFace((neg_scale) ? GL_CW : GL_CCW);
- prev_neg_scale = neg_scale;
+ DRWCommandIterator iter;
+ DRWCommand *cmd;
+ eDRWCommandType cmd_type;
+
+ draw_command_iter_begin(&iter, shgroup);
+
+ draw_call_batching_start(&state);
+
+ while ((cmd = draw_command_iter_step(&iter, &cmd_type))) {
+
+ switch (cmd_type) {
+ case DRW_CMD_DRWSTATE:
+ case DRW_CMD_STENCIL:
+ draw_call_batching_flush(shgroup, &state);
+ break;
+ case DRW_CMD_DRAW:
+ case DRW_CMD_DRAW_PROCEDURAL:
+ case DRW_CMD_DRAW_INSTANCE:
+ if (draw_call_is_culled(&cmd->instance.handle, DST.view_active)) {
+ continue;
+ }
+ break;
+ default:
+ break;
}
- draw_geometry_prepare(shgroup, call);
-
- if (draw_select_do_call(shgroup, call)) {
- continue;
+ switch (cmd_type) {
+ case DRW_CMD_CLEAR:
+ GPU_framebuffer_clear(
+#ifndef NDEBUG
+ GPU_framebuffer_active_get(),
+#else
+ NULL,
+#endif
+ cmd->clear.clear_channels,
+ (float[4]){cmd->clear.r / 255.0f,
+ cmd->clear.g / 255.0f,
+ cmd->clear.b / 255.0f,
+ cmd->clear.a / 255.0f},
+ cmd->clear.depth,
+ cmd->clear.stencil);
+ break;
+ case DRW_CMD_DRWSTATE:
+ state.drw_state_enabled |= cmd->state.enable;
+ state.drw_state_disabled |= cmd->state.disable;
+ drw_state_set((pass_state & ~state.drw_state_disabled) | state.drw_state_enabled);
+ break;
+ case DRW_CMD_STENCIL:
+ drw_stencil_set(cmd->stencil.mask);
+ break;
+ case DRW_CMD_SELECTID:
+ state.select_id = cmd->select_id.select_id;
+ state.select_buf = cmd->select_id.select_buf;
+ break;
+ case DRW_CMD_DRAW:
+ if (!USE_BATCHING || state.obmats_loc == -1 || (G.f & G_FLAG_PICKSEL) ||
+ cmd->draw.batch->inst) {
+ draw_call_single_do(shgroup, &state, cmd->draw.batch, cmd->draw.handle, 0, 0, 0);
+ }
+ else {
+ draw_call_batching_do(shgroup, &state, &cmd->draw);
+ }
+ break;
+ case DRW_CMD_DRAW_PROCEDURAL:
+ draw_call_single_do(shgroup,
+ &state,
+ cmd->procedural.batch,
+ cmd->procedural.handle,
+ 0,
+ cmd->procedural.vert_count,
+ 1);
+ break;
+ case DRW_CMD_DRAW_INSTANCE:
+ draw_call_single_do(shgroup,
+ &state,
+ cmd->instance.batch,
+ cmd->instance.handle,
+ 0,
+ 0,
+ cmd->instance.inst_count);
+ break;
+ case DRW_CMD_DRAW_RANGE:
+ draw_call_single_do(shgroup,
+ &state,
+ cmd->range.batch,
+ (DRWResourceHandle)0,
+ cmd->range.vert_first,
+ cmd->range.vert_count,
+ 1);
+ break;
}
-
- draw_geometry_execute(
- shgroup, call->batch, call->vert_first, call->vert_count, 0, call->inst_count);
}
- /* Reset state */
- glFrontFace(GL_CCW);
+
+ draw_call_batching_finish(shgroup, &state);
}
if (use_tfeedback) {
@@ -1049,6 +1403,17 @@ static void drw_draw_pass_ex(DRWPass *pass,
DST.shader = NULL;
}
+ if (DST.batch) {
+ DST.batch->program_in_use = false;
+ DST.batch = NULL;
+ }
+
+ /* Fix T67342 for some reason. AMD Pro driver bug. */
+ if ((DST.state & DRW_STATE_BLEND_CUSTOM) != 0 &&
+ GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_OFFICIAL)) {
+ drw_state_set(DST.state & ~DRW_STATE_BLEND_CUSTOM);
+ }
+
/* HACK: Rasterized discard can affect clear commands which are not
* part of a DRWPass (as of now). So disable rasterized discard here
* if it has been enabled. */
diff --git a/source/blender/draw/intern/draw_manager_profiling.c b/source/blender/draw/intern/draw_manager_profiling.c
index bab69cf7a57..76382132230 100644
--- a/source/blender/draw/intern/draw_manager_profiling.c
+++ b/source/blender/draw/intern/draw_manager_profiling.c
@@ -63,7 +63,7 @@ static struct DRWTimerPool {
void DRW_stats_free(void)
{
if (DTP.timers != NULL) {
- for (int i = 0; i < DTP.timer_count; ++i) {
+ for (int i = 0; i < DTP.timer_count; i++) {
DRWTimer *timer = &DTP.timers[i];
glDeleteQueries(2, timer->query);
}
@@ -169,7 +169,7 @@ void DRW_stats_reset(void)
GLuint64 lvl_time[MAX_NESTED_TIMER] = {0};
/* Swap queries for the next frame and sum up each lvl time. */
- for (int i = DTP.timer_increment - 1; i >= 0; --i) {
+ for (int i = DTP.timer_increment - 1; i >= 0; i--) {
DRWTimer *timer = &DTP.timers[i];
SWAP(GLuint, timer->query[0], timer->query[1]);
@@ -323,7 +323,7 @@ void DRW_stats_draw(const rcti *rect)
BLI_strncpy(stat_string, "GPU Render Timings", sizeof(stat_string));
draw_stat(rect, 0, v++, stat_string, sizeof(stat_string));
- for (int i = 0; i < DTP.timer_increment; ++i) {
+ for (int i = 0; i < DTP.timer_increment; i++) {
double time_ms, time_percent;
DRWTimer *timer = &DTP.timers[i];
DRWTimer *timer_parent = (timer->lvl > 0) ? &DTP.timers[lvl_index[timer->lvl - 1]] : NULL;
diff --git a/source/blender/draw/modes/edit_armature_mode.c b/source/blender/draw/modes/edit_armature_mode.c
index dfe5a4b7a2f..20195b7d9f9 100644
--- a/source/blender/draw/modes/edit_armature_mode.c
+++ b/source/blender/draw/modes/edit_armature_mode.c
@@ -74,7 +74,7 @@ static void EDIT_ARMATURE_cache_init(void *vedata)
}
stl->g_data->transparent_bones = (draw_ctx->v3d->shading.type == OB_WIRE);
- for (int i = 0; i < 2; ++i) {
+ for (int i = 0; i < 2; i++) {
/* Solid bones */
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK;
psl->bone_solid[i] = DRW_pass_create("Bone Solid Pass", state | DRW_STATE_WRITE_DEPTH);
diff --git a/source/blender/draw/modes/edit_curve_mode.c b/source/blender/draw/modes/edit_curve_mode.c
index e68e03c2438..afaaba0712f 100644
--- a/source/blender/draw/modes/edit_curve_mode.c
+++ b/source/blender/draw/modes/edit_curve_mode.c
@@ -126,7 +126,7 @@ static void EDIT_CURVE_engine_init(void *UNUSED(vedata))
datatoc_edit_curve_overlay_normals_vert_glsl,
NULL},
.frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, "#define IN_PLACE_INSTANCES\n", NULL},
});
}
@@ -270,7 +270,7 @@ static void EDIT_CURVE_cache_populate(void *vedata, Object *ob)
geom = DRW_cache_curve_edge_wire_get(ob);
if (geom) {
- DRW_shgroup_call(wire_shgrp, geom, ob);
+ DRW_shgroup_call_no_cull(wire_shgrp, geom, ob);
}
if ((cu->flag & CU_3D) && (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_NORMALS) != 0) {
@@ -280,12 +280,12 @@ static void EDIT_CURVE_cache_populate(void *vedata, Object *ob)
geom = DRW_cache_curve_edge_overlay_get(ob);
if (geom) {
- DRW_shgroup_call(stl->g_data->overlay_edge_shgrp, geom, ob);
+ DRW_shgroup_call_no_cull(stl->g_data->overlay_edge_shgrp, geom, ob);
}
geom = DRW_cache_curve_vert_overlay_get(ob, stl->g_data->show_handles);
if (geom) {
- DRW_shgroup_call(stl->g_data->overlay_vert_shgrp, geom, ob);
+ DRW_shgroup_call_no_cull(stl->g_data->overlay_vert_shgrp, geom, ob);
}
}
}
@@ -294,12 +294,12 @@ static void EDIT_CURVE_cache_populate(void *vedata, Object *ob)
if (BKE_object_is_in_editmode(ob)) {
struct GPUBatch *geom = DRW_cache_curve_edge_overlay_get(ob);
if (geom) {
- DRW_shgroup_call(stl->g_data->overlay_edge_shgrp, geom, ob);
+ DRW_shgroup_call_no_cull(stl->g_data->overlay_edge_shgrp, geom, ob);
}
geom = DRW_cache_curve_vert_overlay_get(ob, false);
if (geom) {
- DRW_shgroup_call(stl->g_data->overlay_vert_shgrp, geom, ob);
+ DRW_shgroup_call_no_cull(stl->g_data->overlay_vert_shgrp, geom, ob);
}
}
}
diff --git a/source/blender/draw/modes/edit_mesh_mode.c b/source/blender/draw/modes/edit_mesh_mode.c
index f8247d7929e..30fb6c9845c 100644
--- a/source/blender/draw/modes/edit_mesh_mode.c
+++ b/source/blender/draw/modes/edit_mesh_mode.c
@@ -23,8 +23,6 @@
#include "DRW_engine.h"
#include "DRW_render.h"
-#include "GPU_extensions.h"
-
#include "DNA_mesh_types.h"
#include "DNA_view3d_types.h"
@@ -91,7 +89,6 @@ typedef struct EDIT_MESH_PassList {
typedef struct EDIT_MESH_FramebufferList {
struct GPUFrameBuffer *occlude_wire_fb;
- struct GPUFrameBuffer *ghost_wire_fb;
} EDIT_MESH_FramebufferList;
typedef struct EDIT_MESH_StorageList {
@@ -106,8 +103,6 @@ typedef struct EDIT_MESH_Data {
EDIT_MESH_StorageList *stl;
} EDIT_MESH_Data;
-#define MAX_SHADERS 16
-
/** Can only contain shaders (freed as array). */
typedef struct EDIT_MESH_Shaders {
/* weight */
@@ -161,12 +156,6 @@ typedef struct EDIT_MESH_PrivateData {
EDIT_MESH_ComponentShadingGroupList edit_shgrps;
EDIT_MESH_ComponentShadingGroupList edit_in_front_shgrps;
- DRWShadingGroup *vert_shgrp_in_front;
- DRWShadingGroup *edge_shgrp_in_front;
- DRWShadingGroup *face_shgrp_in_front;
- DRWShadingGroup *face_cage_shgrp_in_front;
- DRWShadingGroup *facedot_shgrp_in_front;
-
DRWShadingGroup *facefill_occluded_shgrp;
DRWShadingGroup *facefill_occluded_cage_shgrp;
DRWShadingGroup *mesh_analysis_shgrp;
@@ -459,7 +448,12 @@ static void EDIT_MESH_cache_init(void *vedata)
}
if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGES) == 0) {
if ((tsettings->selectmode & SCE_SELECT_EDGE) == 0) {
- g_data->do_edges = false;
+ if ((v3d->shading.type < OB_SOLID) || (v3d->shading.flag & V3D_SHADING_XRAY)) {
+ /* Special case, when drawing wire, draw edges, see: T67637. */
+ }
+ else {
+ g_data->do_edges = false;
+ }
}
}
if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CREASES) == 0) {
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c
index 06e5b521514..05a915185df 100644
--- a/source/blender/draw/modes/object_mode.c
+++ b/source/blender/draw/modes/object_mode.c
@@ -234,6 +234,7 @@ typedef struct OBJECT_ShadingGroupList {
/* Helpers */
DRWCallBuffer *relationship_lines;
DRWCallBuffer *constraint_lines;
+ DRWCallBuffer *origin_xform;
/* Camera */
DRWCallBuffer *camera;
@@ -285,15 +286,10 @@ typedef struct OBJECT_PrivateData {
DRWShadingGroup *outlines_transform;
/* Lightprobes */
- DRWCallBuffer *lightprobes_cube_select;
- DRWCallBuffer *lightprobes_cube_select_dupli;
- DRWCallBuffer *lightprobes_cube_active;
- DRWCallBuffer *lightprobes_cube_transform;
-
- DRWCallBuffer *lightprobes_planar_select;
- DRWCallBuffer *lightprobes_planar_select_dupli;
- DRWCallBuffer *lightprobes_planar_active;
- DRWCallBuffer *lightprobes_planar_transform;
+ DRWShadingGroup *probe_outlines_transform;
+ DRWShadingGroup *probe_outlines_select;
+ DRWShadingGroup *probe_outlines_select_dupli;
+ DRWShadingGroup *probe_outlines_active;
/* Objects Centers */
DRWCallBuffer *center_active;
@@ -302,17 +298,6 @@ typedef struct OBJECT_PrivateData {
DRWCallBuffer *center_selected_lib;
DRWCallBuffer *center_deselected_lib;
- /* Outlines id offset (accessed as an array) */
- int id_ofs_active;
- int id_ofs_select;
- int id_ofs_select_dupli;
- int id_ofs_transform;
-
- int id_ofs_prb_active;
- int id_ofs_prb_select;
- int id_ofs_prb_select_dupli;
- int id_ofs_prb_transform;
-
bool xray_enabled;
bool xray_enabled_and_not_wire;
} OBJECT_PrivateData; /* Transient data */
@@ -416,7 +401,10 @@ static void OBJECT_engine_init(void *vedata)
if (!sh_data->outline_resolve) {
/* Outline */
sh_data->outline_prepass = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, datatoc_gpu_shader_3D_vert_glsl, NULL},
+ .vert = (const char *[]){sh_cfg_data->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_object_outline_prepass_vert_glsl,
+ NULL},
.frag = (const char *[]){datatoc_object_outline_prepass_frag_glsl, NULL},
.defs = (const char *[]){sh_cfg_data->def, NULL},
});
@@ -430,7 +418,7 @@ static void OBJECT_engine_init(void *vedata)
datatoc_object_outline_prepass_geom_glsl,
NULL},
.frag = (const char *[]){datatoc_object_outline_prepass_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, "#define USE_GEOM\n", NULL},
});
sh_data->outline_resolve = DRW_shader_create_fullscreen(
@@ -538,10 +526,11 @@ static void OBJECT_engine_init(void *vedata)
/* Lightprobes */
sh_data->lightprobe_grid = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg_data->lib,
+ datatoc_common_view_lib_glsl,
datatoc_common_globals_lib_glsl,
datatoc_object_lightprobe_grid_vert_glsl,
NULL},
- .frag = (const char *[]){datatoc_gpu_shader_flat_id_frag_glsl, NULL},
+ .frag = (const char *[]){datatoc_object_outline_prepass_frag_glsl, NULL},
.defs = (const char *[]){sh_cfg_data->def, NULL},
});
@@ -696,12 +685,12 @@ static void OBJECT_engine_free(void)
}
static DRWShadingGroup *shgroup_outline(DRWPass *pass,
- const int *ofs,
+ int outline_id,
GPUShader *sh,
eGPUShaderConfig sh_cfg)
{
DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_int(grp, "baseId", ofs, 1);
+ DRW_shgroup_uniform_int_copy(grp, "outlineId", outline_id);
if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
@@ -740,128 +729,89 @@ static DRWShadingGroup *shgroup_points(DRWPass *pass,
return grp;
}
-static int *shgroup_theme_id_to_probe_outline_counter(OBJECT_StorageList *stl,
- int theme_id,
- const int base_flag)
-{
- if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
- switch (theme_id) {
- case TH_ACTIVE:
- case TH_SELECT:
- return &stl->g_data->id_ofs_prb_select_dupli;
- case TH_TRANSFORM:
- default:
- return &stl->g_data->id_ofs_prb_transform;
- }
- }
-
- switch (theme_id) {
- case TH_ACTIVE:
- return &stl->g_data->id_ofs_prb_active;
- case TH_SELECT:
- return &stl->g_data->id_ofs_prb_select;
- case TH_TRANSFORM:
- default:
- return &stl->g_data->id_ofs_prb_transform;
- }
-}
-
-static int *shgroup_theme_id_to_outline_counter(OBJECT_StorageList *stl,
- int theme_id,
- const int base_flag)
+static DRWShadingGroup *shgroup_theme_id_to_outline_or_null(OBJECT_StorageList *stl,
+ int theme_id,
+ const int base_flag)
{
if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
switch (theme_id) {
case TH_ACTIVE:
case TH_SELECT:
- return &stl->g_data->id_ofs_select_dupli;
+ return stl->g_data->outlines_select_dupli;
case TH_TRANSFORM:
+ return stl->g_data->outlines_transform;
default:
- return &stl->g_data->id_ofs_transform;
+ return NULL;
}
}
switch (theme_id) {
case TH_ACTIVE:
- return &stl->g_data->id_ofs_active;
- case TH_SELECT:
- return &stl->g_data->id_ofs_select;
- case TH_TRANSFORM:
- default:
- return &stl->g_data->id_ofs_transform;
- }
-}
-
-static DRWCallBuffer *buffer_theme_id_to_probe_planar_outline_shgrp(OBJECT_StorageList *stl,
- int theme_id)
-{
- /* does not increment counter */
- switch (theme_id) {
- case TH_ACTIVE:
- return stl->g_data->lightprobes_planar_active;
+ return stl->g_data->outlines_active;
case TH_SELECT:
- return stl->g_data->lightprobes_planar_select;
+ return stl->g_data->outlines_select;
case TH_TRANSFORM:
+ return stl->g_data->outlines_transform;
default:
- return stl->g_data->lightprobes_planar_transform;
+ return NULL;
}
}
-static DRWCallBuffer *buffer_theme_id_to_probe_cube_outline_shgrp(OBJECT_StorageList *stl,
+static DRWShadingGroup *shgroup_theme_id_to_probe_outline_or_null(OBJECT_StorageList *stl,
int theme_id,
const int base_flag)
{
- /* does not increment counter */
+ if (UNLIKELY(DRW_state_is_select())) {
+ return stl->g_data->probe_outlines_select;
+ }
+
if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
switch (theme_id) {
case TH_ACTIVE:
case TH_SELECT:
- return stl->g_data->lightprobes_cube_select_dupli;
+ return stl->g_data->probe_outlines_select_dupli;
case TH_TRANSFORM:
+ return stl->g_data->probe_outlines_transform;
default:
- return stl->g_data->lightprobes_cube_transform;
+ return NULL;
}
}
switch (theme_id) {
case TH_ACTIVE:
- return stl->g_data->lightprobes_cube_active;
+ return stl->g_data->probe_outlines_active;
case TH_SELECT:
- return stl->g_data->lightprobes_cube_select;
+ return stl->g_data->probe_outlines_select;
case TH_TRANSFORM:
+ return stl->g_data->probe_outlines_transform;
default:
- return stl->g_data->lightprobes_cube_transform;
+ return NULL;
}
}
-static DRWShadingGroup *shgroup_theme_id_to_outline_or_null(OBJECT_StorageList *stl,
- int theme_id,
- const int base_flag)
+static int shgroup_theme_id_to_outline_id(int theme_id, const int base_flag)
{
- int *counter = shgroup_theme_id_to_outline_counter(stl, theme_id, base_flag);
- *counter += 1;
-
if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
switch (theme_id) {
case TH_ACTIVE:
case TH_SELECT:
- return stl->g_data->outlines_select_dupli;
+ return 2;
case TH_TRANSFORM:
- return stl->g_data->outlines_transform;
+ return 0;
default:
- return NULL;
+ return -1;
}
}
switch (theme_id) {
case TH_ACTIVE:
- return stl->g_data->outlines_active;
+ return 3;
case TH_SELECT:
- return stl->g_data->outlines_select;
+ return 1;
case TH_TRANSFORM:
- return stl->g_data->outlines_transform;
+ return 0;
default:
- return NULL;
+ return -1;
}
}
@@ -1345,7 +1295,8 @@ static void OBJECT_cache_init(void *vedata)
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
OBJECT_PrivateData *g_data;
const DRWContextState *draw_ctx = DRW_context_state_get();
- OBJECT_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ eGPUShaderConfig cfg = draw_ctx->sh_cfg;
+ OBJECT_Shaders *sh_data = &e_data.sh_data[cfg];
const float outline_width = UI_GetThemeValuef(TH_OUTLINE_WIDTH);
const bool do_outline_expand = (U.pixelsize > 1.0) || (outline_width > 2.0f);
@@ -1366,59 +1317,25 @@ static void OBJECT_cache_init(void *vedata)
{
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- psl->outlines = DRW_pass_create("Outlines Depth Pass", state);
+ psl->lightprobes = DRW_pass_create("Outlines Probe Pass", state);
GPUShader *sh = sh_data->outline_prepass;
+ g_data->probe_outlines_transform = shgroup_outline(psl->lightprobes, 0, sh, cfg);
+ g_data->probe_outlines_select = shgroup_outline(psl->lightprobes, 1, sh, cfg);
+ g_data->probe_outlines_select_dupli = shgroup_outline(psl->lightprobes, 2, sh, cfg);
+ g_data->probe_outlines_active = shgroup_outline(psl->lightprobes, 3, sh, cfg);
+
+ psl->outlines = DRW_pass_create("Outlines Depth Pass", state);
+
if (g_data->xray_enabled_and_not_wire) {
sh = sh_data->outline_prepass_wire;
}
- g_data->outlines_select = shgroup_outline(
- psl->outlines, &g_data->id_ofs_select, sh, draw_ctx->sh_cfg);
- g_data->outlines_select_dupli = shgroup_outline(
- psl->outlines, &g_data->id_ofs_select_dupli, sh, draw_ctx->sh_cfg);
- g_data->outlines_transform = shgroup_outline(
- psl->outlines, &g_data->id_ofs_transform, sh, draw_ctx->sh_cfg);
- g_data->outlines_active = shgroup_outline(
- psl->outlines, &g_data->id_ofs_active, sh, draw_ctx->sh_cfg);
-
- g_data->id_ofs_select = 0;
- g_data->id_ofs_select_dupli = 0;
- g_data->id_ofs_active = 0;
- g_data->id_ofs_transform = 0;
- }
-
- {
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- DRWPass *pass = psl->lightprobes = DRW_pass_create("Object Probe Pass", state);
- struct GPUBatch *sphere = DRW_cache_sphere_get();
- struct GPUBatch *quad = DRW_cache_quad_get();
-
- /* Cubemap */
- g_data->lightprobes_cube_select = buffer_instance_outline(
- pass, sphere, &g_data->id_ofs_prb_select, draw_ctx->sh_cfg);
- g_data->lightprobes_cube_select_dupli = buffer_instance_outline(
- pass, sphere, &g_data->id_ofs_prb_select_dupli, draw_ctx->sh_cfg);
- g_data->lightprobes_cube_active = buffer_instance_outline(
- pass, sphere, &g_data->id_ofs_prb_active, draw_ctx->sh_cfg);
- g_data->lightprobes_cube_transform = buffer_instance_outline(
- pass, sphere, &g_data->id_ofs_prb_transform, draw_ctx->sh_cfg);
-
- /* Planar */
- g_data->lightprobes_planar_select = buffer_instance_outline(
- pass, quad, &g_data->id_ofs_prb_select, draw_ctx->sh_cfg);
- g_data->lightprobes_planar_select_dupli = buffer_instance_outline(
- pass, quad, &g_data->id_ofs_prb_select_dupli, draw_ctx->sh_cfg);
- g_data->lightprobes_planar_active = buffer_instance_outline(
- pass, quad, &g_data->id_ofs_prb_active, draw_ctx->sh_cfg);
- g_data->lightprobes_planar_transform = buffer_instance_outline(
- pass, quad, &g_data->id_ofs_prb_transform, draw_ctx->sh_cfg);
-
- g_data->id_ofs_prb_select = 0;
- g_data->id_ofs_prb_select_dupli = 0;
- g_data->id_ofs_prb_active = 0;
- g_data->id_ofs_prb_transform = 0;
+ g_data->outlines_transform = shgroup_outline(psl->outlines, 0, sh, cfg);
+ g_data->outlines_select = shgroup_outline(psl->outlines, 1, sh, cfg);
+ g_data->outlines_select_dupli = shgroup_outline(psl->outlines, 2, sh, cfg);
+ g_data->outlines_active = shgroup_outline(psl->outlines, 3, sh, cfg);
}
{
@@ -1437,7 +1354,6 @@ static void OBJECT_cache_init(void *vedata)
DRW_shgroup_uniform_texture_ref(grp, "sceneDepth", &dtxl->depth);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_float_copy(grp, "alphaOcclu", alphaOcclu);
- DRW_shgroup_uniform_int(grp, "idOffsets", &stl->g_data->id_ofs_active, 4);
DRW_shgroup_call(grp, quad, NULL);
/* This is the bleed pass if do_outline_expand is false. */
@@ -1516,7 +1432,7 @@ static void OBJECT_cache_init(void *vedata)
psl->camera_images_front = DRW_pass_create("Camera Images Front", state);
}
- for (int i = 0; i < 2; ++i) {
+ for (int i = 0; i < 2; i++) {
OBJECT_ShadingGroupList *sgl = (i == 1) ? &stl->g_data->sgl_ghost : &stl->g_data->sgl;
/* Solid bones */
@@ -1539,7 +1455,7 @@ static void OBJECT_cache_init(void *vedata)
sgl->bone_axes = psl->bone_axes[i] = DRW_pass_create("Bone Axes Pass", state);
}
- for (int i = 0; i < 2; ++i) {
+ for (int i = 0; i < 2; i++) {
OBJECT_ShadingGroupList *sgl = (i == 1) ? &stl->g_data->sgl_ghost : &stl->g_data->sgl;
/* Non Meshes Pass (Camera, empties, lights ...) */
@@ -1735,6 +1651,16 @@ static void OBJECT_cache_init(void *vedata)
sgl->constraint_lines = buffer_dynlines_dashed_uniform_color(
sgl->non_meshes, gb->colorGridAxisZ, draw_ctx->sh_cfg);
+ {
+ DRWShadingGroup *grp_axes;
+ sgl->origin_xform = buffer_instance_color_axes(
+ sgl->non_meshes, DRW_cache_bone_arrows_get(), &grp_axes, draw_ctx->sh_cfg);
+
+ DRW_shgroup_state_disable(grp_axes, DRW_STATE_DEPTH_LESS_EQUAL);
+ DRW_shgroup_state_enable(grp_axes, DRW_STATE_DEPTH_ALWAYS);
+ DRW_shgroup_state_enable(grp_axes, DRW_STATE_WIRE_SMOOTH);
+ }
+
/* Force Field Curve Guide End (here because of stipple) */
/* TODO port to shader stipple */
geom = DRW_cache_screenspace_circle_get();
@@ -1954,9 +1880,10 @@ static void DRW_shgroup_light(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLaye
}
if (la->mode & LA_SHOW_CONE) {
-
- DRW_buffer_add_entry(sgl->light_spot_volume_rect, cone_inside, &one, shapemat);
- DRW_buffer_add_entry(sgl->light_spot_volume_rect_outside, cone_outside, &one, shapemat);
+ if (!DRW_state_is_select()) {
+ DRW_buffer_add_entry(sgl->light_spot_volume_rect, cone_inside, &one, shapemat);
+ DRW_buffer_add_entry(sgl->light_spot_volume_rect_outside, cone_outside, &one, shapemat);
+ }
}
}
else {
@@ -1970,8 +1897,10 @@ static void DRW_shgroup_light(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLaye
}
if (la->mode & LA_SHOW_CONE) {
- DRW_buffer_add_entry(sgl->light_spot_volume, cone_inside, &one, shapemat);
- DRW_buffer_add_entry(sgl->light_spot_volume_outside, cone_outside, &one, shapemat);
+ if (!DRW_state_is_select()) {
+ DRW_buffer_add_entry(sgl->light_spot_volume, cone_inside, &one, shapemat);
+ DRW_buffer_add_entry(sgl->light_spot_volume_outside, cone_outside, &one, shapemat);
+ }
}
}
@@ -2143,7 +2072,7 @@ static void camera_view3d_stereoscopy_display_extra(OBJECT_ShadingGroupList *sgl
static float one = 1.0f;
float plane_mat[4][4], scale_mat[4][4];
float scale_factor[3] = {1.0f, 1.0f, 1.0f};
- float color_plane[2][4] = {
+ const float color_plane[2][4] = {
{0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha},
{0.0f, 0.0f, 0.0f, 1.0f},
};
@@ -2169,7 +2098,7 @@ static void camera_view3d_stereoscopy_display_extra(OBJECT_ShadingGroupList *sgl
/* Draw convergence volume. */
if (is_stereo3d_volume && !is_select) {
static float one = 1.0f;
- float color_volume[3][4] = {
+ const float color_volume[3][4] = {
{0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha},
{1.0f, 0.0f, 0.0f, v3d->stereo3d_volume_alpha},
{0.0f, 0.0f, 0.0f, 1.0f},
@@ -2295,7 +2224,7 @@ static void camera_view3d_reconstruction(OBJECT_ShadingGroupList *sgl,
DRW_shgroup_empty_ex(sgl, bundle_mat, &v3d->bundle_size, v3d->bundle_drawtype, color);
}
- float bundle_color_v4[4] = {
+ const float bundle_color_v4[4] = {
bundle_color[0],
bundle_color[1],
bundle_color[2],
@@ -2755,15 +2684,6 @@ static void DRW_shgroup_speaker(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLa
DRW_buffer_add_entry(sgl->speaker, color, &one, ob->obmat);
}
-typedef struct OBJECT_LightProbeEngineData {
- DrawData dd;
-
- float increment_x[3];
- float increment_y[3];
- float increment_z[3];
- float corner[3];
-} OBJECT_LightProbeEngineData;
-
static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data,
OBJECT_StorageList *stl,
OBJECT_PassList *psl,
@@ -2780,13 +2700,10 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data,
OBJECT_ShadingGroupList *sgl = (ob->dtx & OB_DRAWXRAY) ? &stl->g_data->sgl_ghost :
&stl->g_data->sgl;
- OBJECT_LightProbeEngineData *prb_data = (OBJECT_LightProbeEngineData *)DRW_drawdata_ensure(
- &ob->id, &draw_engine_object_type, sizeof(OBJECT_LightProbeEngineData), NULL, NULL);
-
if (DRW_state_is_select() || do_outlines) {
- int *call_id = shgroup_theme_id_to_probe_outline_counter(stl, theme_id, ob->base_flag);
-
if (prb->type == LIGHTPROBE_TYPE_GRID) {
+ float corner[3];
+ float increment[3][3];
/* Update transforms */
float cell_dim[3], half_cell_dim[3];
cell_dim[0] = 2.0f / (float)(prb->grid_resolution_x);
@@ -2796,65 +2713,41 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data,
mul_v3_v3fl(half_cell_dim, cell_dim, 0.5f);
/* First cell. */
- copy_v3_fl(prb_data->corner, -1.0f);
- add_v3_v3(prb_data->corner, half_cell_dim);
- mul_m4_v3(ob->obmat, prb_data->corner);
+ copy_v3_fl(corner, -1.0f);
+ add_v3_v3(corner, half_cell_dim);
+ mul_m4_v3(ob->obmat, corner);
/* Opposite neighbor cell. */
- copy_v3_fl3(prb_data->increment_x, cell_dim[0], 0.0f, 0.0f);
- add_v3_v3(prb_data->increment_x, half_cell_dim);
- add_v3_fl(prb_data->increment_x, -1.0f);
- mul_m4_v3(ob->obmat, prb_data->increment_x);
- sub_v3_v3(prb_data->increment_x, prb_data->corner);
-
- copy_v3_fl3(prb_data->increment_y, 0.0f, cell_dim[1], 0.0f);
- add_v3_v3(prb_data->increment_y, half_cell_dim);
- add_v3_fl(prb_data->increment_y, -1.0f);
- mul_m4_v3(ob->obmat, prb_data->increment_y);
- sub_v3_v3(prb_data->increment_y, prb_data->corner);
-
- copy_v3_fl3(prb_data->increment_z, 0.0f, 0.0f, cell_dim[2]);
- add_v3_v3(prb_data->increment_z, half_cell_dim);
- add_v3_fl(prb_data->increment_z, -1.0f);
- mul_m4_v3(ob->obmat, prb_data->increment_z);
- sub_v3_v3(prb_data->increment_z, prb_data->corner);
+ copy_v3_fl3(increment[0], cell_dim[0], 0.0f, 0.0f);
+ copy_v3_fl3(increment[1], 0.0f, cell_dim[1], 0.0f);
+ copy_v3_fl3(increment[2], 0.0f, 0.0f, cell_dim[2]);
+
+ for (int i = 0; i < 3; i++) {
+ add_v3_v3(increment[i], half_cell_dim);
+ add_v3_fl(increment[i], -1.0f);
+ mul_m4_v3(ob->obmat, increment[i]);
+ sub_v3_v3(increment[i], corner);
+ }
+ int outline_id = shgroup_theme_id_to_outline_id(theme_id, ob->base_flag);
uint cell_count = prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z;
DRWShadingGroup *grp = DRW_shgroup_create(sh_data->lightprobe_grid, psl->lightprobes);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_int_copy(grp, "call_id", *call_id);
- DRW_shgroup_uniform_int(grp, "baseId", call_id, 1); /* that's correct */
- DRW_shgroup_uniform_vec3(grp, "corner", prb_data->corner, 1);
- DRW_shgroup_uniform_vec3(grp, "increment_x", prb_data->increment_x, 1);
- DRW_shgroup_uniform_vec3(grp, "increment_y", prb_data->increment_y, 1);
- DRW_shgroup_uniform_vec3(grp, "increment_z", prb_data->increment_z, 1);
- DRW_shgroup_uniform_ivec3(grp, "grid_resolution", &prb->grid_resolution_x, 1);
+ DRW_shgroup_uniform_int_copy(grp, "outlineId", outline_id);
+ DRW_shgroup_uniform_vec3_copy(grp, "corner", corner);
+ DRW_shgroup_uniform_vec3_copy(grp, "increment_x", increment[0]);
+ DRW_shgroup_uniform_vec3_copy(grp, "increment_y", increment[1]);
+ DRW_shgroup_uniform_vec3_copy(grp, "increment_z", increment[2]);
+ DRW_shgroup_uniform_ivec3_copy(grp, "grid_resolution", &prb->grid_resolution_x);
if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
}
DRW_shgroup_call_procedural_points(grp, NULL, cell_count);
- *call_id += 1;
}
- else if (prb->type == LIGHTPROBE_TYPE_CUBE) {
- float draw_size = 1.0f;
- float probe_cube_mat[4][4];
- // prb_data->draw_size = prb->data_draw_size * 0.1f;
- // unit_m4(prb_data->probe_cube_mat);
- // copy_v3_v3(prb_data->probe_cube_mat[3], ob->obmat[3]);
-
- DRWCallBuffer *buf = buffer_theme_id_to_probe_cube_outline_shgrp(
+ else if (prb->type == LIGHTPROBE_TYPE_PLANAR && (prb->flag & LIGHTPROBE_FLAG_SHOW_DATA)) {
+ DRWShadingGroup *grp = shgroup_theme_id_to_probe_outline_or_null(
stl, theme_id, ob->base_flag);
- /* TODO remove or change the drawing of the cube probes. This line draws nothing on purpose
- * to keep the call ids correct. */
- zero_m4(probe_cube_mat);
- DRW_buffer_add_entry(buf, call_id, &draw_size, probe_cube_mat);
- *call_id += 1;
- }
- else if (prb->flag & LIGHTPROBE_FLAG_SHOW_DATA) {
- float draw_size = 1.0f;
- DRWCallBuffer *buf = buffer_theme_id_to_probe_planar_outline_shgrp(stl, theme_id);
- DRW_buffer_add_entry(buf, call_id, &draw_size, ob->obmat);
- *call_id += 1;
+ DRW_shgroup_call_no_cull(grp, DRW_cache_quad_get(), ob);
}
}
@@ -2971,7 +2864,7 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data,
{0.0, 0.0, 0.0, 1.0}},
};
- for (int i = 0; i < 6; ++i) {
+ for (int i = 0; i < 6; i++) {
float clipmat[4][4];
normalize_m4_m4(clipmat, ob->obmat);
mul_m4_m4m4(clipmat, clipmat, cubefacemat[i]);
@@ -3127,13 +3020,11 @@ static void DRW_shgroup_texture_space(OBJECT_ShadingGroupList *sgl, Object *ob,
switch (GS(ob_data->name)) {
case ID_ME:
- BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize);
+ BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, &texcosize);
break;
case ID_CU: {
Curve *cu = (Curve *)ob_data;
- if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_curve_texspace_calc(cu);
- }
+ BKE_curve_texspace_ensure(cu);
texcoloc = cu->loc;
texcosize = cu->size;
break;
@@ -3675,6 +3566,19 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
DRW_shgroup_bounds(sgl, ob, theme_id);
}
+ /* Helpers for when we're transforming origins. */
+ if (draw_ctx->object_mode == OB_MODE_OBJECT) {
+ if (scene->toolsettings->transform_flag & SCE_XFORM_DATA_ORIGIN) {
+ if (ob->base_flag & BASE_SELECTED) {
+ if (!DRW_state_is_select()) {
+ const float color[4] = {0.75, 0.75, 0.75, 0.5};
+ float axes_size = 1.0f;
+ DRW_buffer_add_entry(sgl->origin_xform, color, &axes_size, ob->obmat);
+ }
+ }
+ }
+ }
+
/* don't show object extras in set's */
if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) {
if ((draw_ctx->object_mode & (OB_MODE_ALL_PAINT | OB_MODE_ALL_PAINT_GPENCIL)) == 0) {
@@ -3685,7 +3589,7 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
DRW_shgroup_relationship_lines(sgl, draw_ctx->depsgraph, scene, ob);
}
- const bool draw_extra = (ob->dtx != 0);
+ const bool draw_extra = ob->dtx & (OB_DRAWNAME | OB_TEXSPACE | OB_DRAWBOUNDOX);
if (draw_extra && (theme_id == TH_UNDEFINED)) {
theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
}
@@ -3758,19 +3662,7 @@ static void OBJECT_draw_scene(void *vedata)
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
- int id_len_select = g_data->id_ofs_select;
- int id_len_select_dupli = g_data->id_ofs_select_dupli;
- int id_len_active = g_data->id_ofs_active;
- int id_len_transform = g_data->id_ofs_transform;
-
- int id_len_prb_select = g_data->id_ofs_prb_select;
- int id_len_prb_select_dupli = g_data->id_ofs_prb_select_dupli;
- int id_len_prb_active = g_data->id_ofs_prb_active;
- int id_len_prb_transform = g_data->id_ofs_prb_transform;
-
- int outline_calls = id_len_select + id_len_select_dupli + id_len_active + id_len_transform;
- outline_calls += id_len_prb_select + id_len_prb_select_dupli + id_len_prb_active +
- id_len_prb_transform;
+ int do_outlines = !DRW_pass_is_empty(psl->outlines) || !DRW_pass_is_empty(psl->lightprobes);
float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
@@ -3778,35 +3670,24 @@ static void OBJECT_draw_scene(void *vedata)
/* Don't draw Transparent passes in MSAA buffer. */
// DRW_draw_pass(psl->bone_envelope); /* Never drawn in Object mode currently. */
- DRW_draw_pass(stl->g_data->sgl.transp_shapes);
+ DRW_draw_pass(g_data->sgl.transp_shapes);
MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl);
- DRW_draw_pass(stl->g_data->sgl.bone_solid);
- DRW_draw_pass(stl->g_data->sgl.bone_wire);
- DRW_draw_pass(stl->g_data->sgl.bone_outline);
- DRW_draw_pass(stl->g_data->sgl.non_meshes);
+ DRW_draw_pass(g_data->sgl.bone_solid);
+ DRW_draw_pass(g_data->sgl.bone_wire);
+ DRW_draw_pass(g_data->sgl.bone_outline);
+ DRW_draw_pass(g_data->sgl.non_meshes);
DRW_draw_pass(psl->particle);
- DRW_draw_pass(stl->g_data->sgl.bone_axes);
+ DRW_draw_pass(g_data->sgl.bone_axes);
MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl);
- DRW_draw_pass(stl->g_data->sgl.image_empties);
+ DRW_draw_pass(g_data->sgl.image_empties);
- if (DRW_state_is_fbo() && outline_calls > 0) {
+ if (DRW_state_is_fbo() && do_outlines) {
DRW_stats_group_start("Outlines");
- g_data->id_ofs_active = 1;
- g_data->id_ofs_select = g_data->id_ofs_active + id_len_active + id_len_prb_active + 1;
- g_data->id_ofs_select_dupli = g_data->id_ofs_select + id_len_select + id_len_prb_select + 1;
- g_data->id_ofs_transform = g_data->id_ofs_select_dupli + id_len_select_dupli +
- id_len_prb_select_dupli + 1;
-
- g_data->id_ofs_prb_active = g_data->id_ofs_active + id_len_active;
- g_data->id_ofs_prb_select = g_data->id_ofs_select + id_len_select;
- g_data->id_ofs_prb_select_dupli = g_data->id_ofs_select_dupli + id_len_select_dupli;
- g_data->id_ofs_prb_transform = g_data->id_ofs_transform + id_len_transform;
-
/* Render filled polygon on a separate framebuffer */
GPU_framebuffer_bind(fbl->outlines_fb);
GPU_framebuffer_clear_color_depth(fbl->outlines_fb, clearcol, 1.0f);
@@ -3841,7 +3722,7 @@ static void OBJECT_draw_scene(void *vedata)
}
/* Combine with scene buffer last */
- if (outline_calls > 0) {
+ if (do_outlines) {
DRW_draw_pass(psl->outlines_resolve);
}
}
diff --git a/source/blender/draw/modes/overlay_mode.c b/source/blender/draw/modes/overlay_mode.c
index a5b1133abf4..9106e89663d 100644
--- a/source/blender/draw/modes/overlay_mode.c
+++ b/source/blender/draw/modes/overlay_mode.c
@@ -23,8 +23,6 @@
#include "DNA_mesh_types.h"
#include "DNA_view3d_types.h"
-#include "BIF_glutil.h"
-
#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_object.h"
@@ -77,7 +75,6 @@ typedef struct OVERLAY_PrivateData {
DRWShadingGroup *face_wires_shgrp;
DRWShadingGroup *face_wires_xray_shgrp;
DRWView *view_wires;
- BLI_mempool *wire_color_mempool;
View3DOverlay overlay;
float wire_step_param;
bool clear_stencil;
@@ -208,10 +205,6 @@ static void overlay_cache_init(void *vedata)
if (v3d->shading.type == OB_WIRE) {
g_data->overlay.flag |= V3D_OVERLAY_WIREFRAMES;
-
- if (ELEM(v3d->shading.wire_color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_RANDOM_COLOR)) {
- g_data->wire_color_mempool = BLI_mempool_create(sizeof(float[3]), 0, 512, 0);
- }
}
{
@@ -246,17 +239,11 @@ static void overlay_cache_init(void *vedata)
geometry_shader_uniforms(g_data->face_wires_shgrp);
geometry_shader_uniforms(g_data->face_wires_xray_shgrp);
}
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(g_data->face_wires_shgrp, DRW_STATE_CLIP_PLANES);
- DRW_shgroup_state_enable(g_data->face_wires_xray_shgrp, DRW_STATE_CLIP_PLANES);
- }
-
g_data->wire_step_param = stl->g_data->overlay.wireframe_threshold - 254.0f / 255.0f;
}
}
static void overlay_wire_color_get(const View3D *v3d,
- const OVERLAY_PrivateData *pd,
const Object *ob,
const bool use_coloring,
float **rim_col,
@@ -305,8 +292,10 @@ static void overlay_wire_color_get(const View3D *v3d,
if (v3d->shading.type == OB_WIRE) {
if (ELEM(v3d->shading.wire_color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_RANDOM_COLOR)) {
- *wire_col = BLI_mempool_alloc(pd->wire_color_mempool);
- *rim_col = BLI_mempool_alloc(pd->wire_color_mempool);
+ /* Theses stays valid until next call. So we need to copy them when using them as uniform. */
+ static float wire_col_val[3], rim_col_val[3];
+ *wire_col = wire_col_val;
+ *rim_col = rim_col_val;
if (v3d->shading.wire_color_type == V3D_SHADING_OBJECT_COLOR) {
linearrgb_to_srgb_v3_v3(*wire_col, ob->color);
@@ -400,7 +389,8 @@ static void overlay_cache_populate(void *vedata, Object *ob)
if ((!pd->show_overlays) ||
(((ob != draw_ctx->object_edit) && !is_edit_mode) || has_edit_mesh_cage) ||
ob->type != OB_MESH) {
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+ const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
const bool all_wires = (ob->dtx & OB_DRAW_ALL_EDGES);
const bool is_wire = (ob->dt < OB_SOLID);
const bool is_xray = (ob->dtx & OB_DRAWXRAY);
@@ -419,6 +409,10 @@ static void overlay_cache_populate(void *vedata, Object *ob)
shgrp = DRW_shgroup_create_sub(pd->face_wires_shgrp);
}
+ if (draw_ctx->rv3d->rflag & RV3D_CLIPPING) {
+ DRW_shgroup_state_enable(shgrp, DRW_STATE_CLIP_PLANES);
+ }
+
float wire_step_param = 10.0f;
if (!use_sculpt_pbvh) {
wire_step_param = (all_wires) ? 1.0f : pd->wire_step_param;
@@ -427,9 +421,9 @@ static void overlay_cache_populate(void *vedata, Object *ob)
if (!(DRW_state_is_select() || DRW_state_is_depth())) {
float *rim_col, *wire_col;
- overlay_wire_color_get(v3d, pd, ob, use_coloring, &rim_col, &wire_col);
- DRW_shgroup_uniform_vec3(shgrp, "wireColor", wire_col, 1);
- DRW_shgroup_uniform_vec3(shgrp, "rimColor", rim_col, 1);
+ overlay_wire_color_get(v3d, ob, use_coloring, &rim_col, &wire_col);
+ DRW_shgroup_uniform_vec3_copy(shgrp, "wireColor", wire_col);
+ DRW_shgroup_uniform_vec3_copy(shgrp, "rimColor", rim_col);
DRW_shgroup_stencil_mask(shgrp,
(is_xray && (is_wire || !pd->clear_stencil)) ? 0x00 : 0xFF);
}
@@ -506,12 +500,6 @@ static void overlay_draw_scene(void *vedata)
/* TODO(fclem): find a way to unify the multisample pass together
* (non meshes + armature + wireframe) */
MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl);
-
- /* XXX TODO(fclem) do not discard data after drawing! Store them per viewport. */
- if (stl->g_data->wire_color_mempool) {
- BLI_mempool_destroy(stl->g_data->wire_color_mempool);
- stl->g_data->wire_color_mempool = NULL;
- }
}
static void overlay_engine_free(void)
diff --git a/source/blender/draw/modes/pose_mode.c b/source/blender/draw/modes/pose_mode.c
index 3a5c87688fe..91e4e2335de 100644
--- a/source/blender/draw/modes/pose_mode.c
+++ b/source/blender/draw/modes/pose_mode.c
@@ -127,7 +127,7 @@ static void POSE_cache_init(void *vedata)
POSE_PrivateData *ppd = stl->g_data;
ppd->transparent_bones = (draw_ctx->v3d->shading.type == OB_WIRE);
- for (int i = 0; i < 2; ++i) {
+ for (int i = 0; i < 2; i++) {
/* Solid bones */
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK;
psl->bone_solid[i] = DRW_pass_create("Bone Solid Pass", state | DRW_STATE_WRITE_DEPTH);
diff --git a/source/blender/draw/modes/shaders/common_view_lib.glsl b/source/blender/draw/modes/shaders/common_view_lib.glsl
index 20a54947db7..76089d1ae41 100644
--- a/source/blender/draw/modes/shaders/common_view_lib.glsl
+++ b/source/blender/draw/modes/shaders/common_view_lib.glsl
@@ -1,4 +1,5 @@
#define COMMON_VIEW_LIB
+#define DRW_RESOURCE_CHUNK_LEN 512
/* keep in sync with DRWManager.view_data */
layout(std140) uniform viewBlock
@@ -23,8 +24,77 @@ layout(std140) uniform viewBlock
_world_clip_planes_calc_clip_distance(p, clipPlanes)
#endif
+uniform int resourceChunk;
+
+#ifdef GPU_VERTEX_SHADER
+# ifdef GL_ARB_shader_draw_parameters
+# define baseInstance gl_BaseInstanceARB
+# else /* no ARB_shader_draw_parameters */
+uniform int baseInstance;
+# endif
+
+# ifdef IN_PLACE_INSTANCES
+/* When drawing instances of an object at the same position. */
+# define instanceId 0
+# elif defined(GPU_DEPRECATED_AMD_DRIVER)
+/* A driver bug make it so that when using an attribute with GL_INT_2_10_10_10_REV as format,
+ * the gl_InstanceID is incremented by the 2 bit component of the attrib.
+ * Ignore gl_InstanceID then. */
+# define instanceId 0
+# else
+# define instanceId gl_InstanceID
+# endif
+
+# define resource_id (baseInstance + instanceId)
+
+/* Use this to declare and pass the value if
+ * the fragment shader uses the resource_id. */
+# define RESOURCE_ID_VARYING flat out int resourceIDFrag;
+# define RESOURCE_ID_VARYING_GEOM flat out int resourceIDGeom;
+# define PASS_RESOURCE_ID resourceIDFrag = resource_id;
+# define PASS_RESOURCE_ID_GEOM resourceIDGeom = resource_id;
+#endif
+
+/* If used in a fragment / geometry shader, we pass
+ * resource_id as varying. */
+#ifdef GPU_GEOMETRY_SHADER
+# define RESOURCE_ID_VARYING \
+ flat out int resourceIDFrag; \
+ flat in int resourceIDGeom[];
+
+# define resource_id resourceIDGeom
+# define PASS_RESOURCE_ID(i) resourceIDFrag = resource_id[i];
+#endif
+
+#ifdef GPU_FRAGMENT_SHADER
+flat in int resourceIDFrag;
+# define resource_id resourceIDFrag
+#endif
+
+#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && !defined(OS_MAC)
+struct ObjectMatrices {
+ mat4 drw_modelMatrix;
+ mat4 drw_modelMatrixInverse;
+};
+
+layout(std140) uniform modelBlock
+{
+ ObjectMatrices drw_matrices[DRW_RESOURCE_CHUNK_LEN];
+};
+
+# define ModelMatrix (drw_matrices[resource_id].drw_modelMatrix)
+# define ModelMatrixInverse (drw_matrices[resource_id].drw_modelMatrixInverse)
+
+#else /* GPU_INTEL */
+/* Intel GPU seems to suffer performance impact when the model matrix is in UBO storage.
+ * So for now we just force using the legacy path. */
+/* Note that this is also a workaround of a problem on osx (amd or nvidia)
+ * and older amd driver on windows. */
uniform mat4 ModelMatrix;
uniform mat4 ModelMatrixInverse;
+#endif
+
+#define resource_handle (resourceChunk * DRW_RESOURCE_CHUNK_LEN + resource_id)
/** Transform shortcuts. */
/* Rule of thumb: Try to reuse world positions and normals because converting though viewspace
diff --git a/source/blender/draw/modes/shaders/object_color_axes_vert.glsl b/source/blender/draw/modes/shaders/object_color_axes_vert.glsl
new file mode 100644
index 00000000000..239dec30c42
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_color_axes_vert.glsl
@@ -0,0 +1,35 @@
+
+uniform mat4 ViewProjectionMatrix;
+uniform vec3 screenVecs[3];
+
+/* ---- Instantiated Attrs ---- */
+in float axis; /* position on the axis. [0.0-1.0] is X axis, [1.0-2.0] is Y, etc... */
+in vec2 screenPos;
+in vec3 colorAxis;
+
+/* ---- Per instance Attrs ---- */
+in mat4 InstanceModelMatrix;
+in vec4 color;
+
+flat out vec4 finalColor;
+
+void main()
+{
+ float draw_size = 4.0;
+ vec3 chosen_axis = InstanceModelMatrix[int(axis)].xyz;
+ vec3 loc = InstanceModelMatrix[3].xyz;
+ vec3 wpos = loc + chosen_axis * fract(axis) * draw_size;
+ vec3 spos = screenVecs[0].xyz * screenPos.x + screenVecs[1].xyz * screenPos.y;
+ /* Scale uniformly by axis length */
+ spos *= length(chosen_axis) * draw_size;
+
+ vec4 pos_4d = vec4(wpos + spos, 1.0);
+ gl_Position = ViewProjectionMatrix * pos_4d;
+
+ finalColor.rgb = mix(colorAxis, color.rgb, color.a);
+ finalColor.a = 1.0;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(pos_4d.xyz);
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/object_empty_image_frag.glsl b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl
index 7dfbf469adc..e33aa6cdcc1 100644
--- a/source/blender/draw/modes/shaders/object_empty_image_frag.glsl
+++ b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl
@@ -37,9 +37,15 @@ void main()
if (depthMode == DEPTH_BACK) {
gl_FragDepth = 0.999999;
+#ifdef USE_WIRE
+ gl_FragDepth -= 1e-5;
+#endif
}
else if (depthMode == DEPTH_FRONT) {
gl_FragDepth = 0.000001;
+#ifdef USE_WIRE
+ gl_FragDepth -= 1e-5;
+#endif
}
else if (depthMode == DEPTH_UNCHANGED) {
gl_FragDepth = gl_FragCoord.z;
diff --git a/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl b/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
index d27d55c3fd6..144024a7d5d 100644
--- a/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
+++ b/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
@@ -1,18 +1,11 @@
-uniform mat4 ViewProjectionMatrix;
-
-uniform float sphere_size;
uniform ivec3 grid_resolution;
uniform vec3 corner;
uniform vec3 increment_x;
uniform vec3 increment_y;
uniform vec3 increment_z;
-uniform vec3 screen_vecs[2];
-
-uniform int call_id; /* we don't want the builtin callId which would be 0. */
-uniform int baseId;
-flat out uint finalId;
+flat out int objectId;
void main()
{
@@ -29,7 +22,8 @@ void main()
gl_Position = ViewProjectionMatrix * vec4(ws_cell_location, 1.0);
gl_PointSize = 2.0f;
- finalId = uint(baseId + call_id);
+ /* ID 0 is nothing (background) */
+ objectId = resource_handle + 1;
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(ws_cell_location);
diff --git a/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl b/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl
index 7668a0c2c94..7b86d477a39 100644
--- a/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl
+++ b/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl
@@ -7,30 +7,9 @@ uniform usampler2D outlineId;
uniform sampler2D outlineDepth;
uniform sampler2D sceneDepth;
-uniform int idOffsets[4];
-
uniform float alphaOcclu;
uniform vec2 viewportSize;
-vec4 convert_id_to_color(int id)
-{
- if (id == 0) {
- return vec4(0.0);
- }
- if (id < idOffsets[1]) {
- return colorActive;
- }
- else if (id < idOffsets[2]) {
- return colorSelect;
- }
- else if (id < idOffsets[3]) {
- return colorDupliSelect;
- }
- else {
- return colorTransform;
- }
-}
-
void main()
{
ivec2 texel = ivec2(gl_FragCoord.xy);
@@ -85,7 +64,24 @@ void main()
const float epsilon = 3.0 / 8388608.0;
bool occluded = (ref_depth > scene_depth + epsilon);
- FragColor = convert_id_to_color(int(ref_id));
+ /* WATCH: Keep in sync with outlineId of the prepass. */
+ uint color_id = ref_id >> 14u;
+ if (ref_id == 0u) {
+ FragColor = vec4(0.0);
+ }
+ else if (color_id == 1u) {
+ FragColor = colorSelect;
+ }
+ else if (color_id == 2u) {
+ FragColor = colorDupliSelect;
+ }
+ else if (color_id == 3u) {
+ FragColor = colorActive;
+ }
+ else {
+ FragColor = colorTransform;
+ }
+
FragColor.a *= (occluded) ? alphaOcclu : 1.0;
FragColor.a = (outline) ? FragColor.a : 0.0;
}
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl
index c3447456ea6..5d6c4881b5b 100644
--- a/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl
+++ b/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl
@@ -1,10 +1,18 @@
-uniform int callId;
-uniform int baseId;
+
+/* Should be 2 bits only [0..3]. */
+uniform int outlineId;
+
+flat in int objectId;
/* using uint because 16bit uint can contain more ids than int. */
out uint outId;
+/* Replace top 2 bits (of the 16bit output) by outlineId.
+ * This leaves 16K different IDs to create outlines between objects.
+ * SHIFT = (32 - (16 - 2)) */
+#define SHIFT 18u
+
void main()
{
- outId = uint(baseId + callId);
+ outId = (uint(outlineId) << 14u) | ((uint(objectId) << SHIFT) >> SHIFT);
}
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl
index 5a3eb38fb6b..b32913dcd60 100644
--- a/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl
+++ b/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl
@@ -2,12 +2,15 @@
layout(lines_adjacency) in;
layout(line_strip, max_vertices = 2) out;
-in vec4 pPos[];
in vec3 vPos[];
+in int objectId_g[];
+
+flat out int objectId;
void vert_from_gl_in(int v)
{
- gl_Position = pPos[v];
+ gl_Position = gl_in[v].gl_Position;
+ objectId = objectId_g[v];
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_set_clip_distance(gl_in[v].gl_ClipDistance);
#endif
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl
index e34afe95b5e..7740f9a4af2 100644
--- a/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl
+++ b/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl
@@ -1,16 +1,27 @@
in vec3 pos;
-out vec4 pPos;
+#ifdef USE_GEOM
out vec3 vPos;
+out int objectId_g;
+# define objectId objectId_g
+#else
+
+flat out int objectId;
+#endif
void main()
{
vec3 world_pos = point_object_to_world(pos);
+#ifdef USE_GEOM
vPos = point_world_to_view(world_pos);
- pPos = point_world_to_ndc(world_pos);
+#endif
+ gl_Position = point_world_to_ndc(world_pos);
/* Small bias to always be on top of the geom. */
- pPos.z -= 1e-3;
+ gl_Position.z -= 1e-3;
+
+ /* ID 0 is nothing (background) */
+ objectId = resource_handle + 1;
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
diff --git a/source/blender/draw/modes/shaders/paint_face_vert.glsl b/source/blender/draw/modes/shaders/paint_face_vert.glsl
index d135071c15c..af362f24a85 100644
--- a/source/blender/draw/modes/shaders/paint_face_vert.glsl
+++ b/source/blender/draw/modes/shaders/paint_face_vert.glsl
@@ -8,4 +8,4 @@ void main()
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
#endif
-} \ No newline at end of file
+}
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 7e913014a87..0fc137295d0 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -3114,6 +3114,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, gpl, ANIMTYPE_GPLAYER);
/* update other layer status */
BKE_gpencil_layer_setactive(gpd, gpl);
+ BKE_gpencil_layer_autolock_set(gpd, false);
}
/* Grease Pencil updates */
@@ -3338,7 +3339,7 @@ static void ANIM_OT_channel_select_keys(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Select Channel keyframes";
+ ot->name = "Select Channel Keyframes";
ot->idname = "ANIM_OT_channel_select_keys";
ot->description = "Select all keyframes of channel under mouse";
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index 7ab50afe3a1..40b2706cc75 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -442,7 +442,7 @@ static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, flo
}
else {
float step_size = (bezt->vec[1][0] - prev_bezt->vec[1][0]) / resol;
- for (int j = 0; j <= resol; ++j) {
+ for (int j = 0; j <= resol; j++) {
float eval_time = prev_bezt->vec[1][0] + step_size * j;
float eval_value = evaluate_fcurve_only_curve(fcu, eval_time);
max_coord = max_ff(max_coord, eval_value);
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index a78a63f1347..48493c9e961 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -630,9 +630,8 @@ static bAnimListElem *make_new_animlistelem(void *data,
/* do specifics */
switch (datatype) {
case ANIMTYPE_SUMMARY: {
- /* nothing to include for now... this is just a dummy wrappy around all the other channels
- * in the DopeSheet, and gets included at the start of the list
- */
+ /* Nothing to include for now... this is just a dummy wrapper around
+ * all the other channels in the DopeSheet, and gets included at the start of the list. */
ale->key_data = NULL;
ale->datatype = ALE_ALL;
break;
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index ded59466370..2a35acdefcb 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -486,7 +486,7 @@ static void draw_marker(
float name_y = UI_DPI_FAC * 18;
/* Give an offset to the marker name when selected,
* or when near the current frame (5 frames range, starting from the current one). */
- if ((marker->flag & SELECT) || (IN_RANGE_INCL(marker->frame, cfra, cfra - 4))) {
+ if ((marker->flag & SELECT) || (cfra - 4 <= marker->frame && marker->frame <= cfra)) {
name_y += UI_DPI_FAC * 10;
}
draw_marker_name(fstyle, marker, xpos, name_y);
diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c
index bd4886817cd..30bf837f6c0 100644
--- a/source/blender/editors/animation/anim_motion_paths.c
+++ b/source/blender/editors/animation/anim_motion_paths.c
@@ -36,6 +36,7 @@
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_query.h"
#include "GPU_batch.h"
@@ -67,6 +68,37 @@ typedef struct MPathTarget {
/* ........ */
+/* update scene for current frame */
+static void motionpaths_calc_update_scene(Main *bmain, struct Depsgraph *depsgraph)
+{
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+}
+
+Depsgraph *animviz_depsgraph_build(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ ListBase *targets)
+{
+ /* Allocate dependency graph. */
+ Depsgraph *depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_VIEWPORT);
+
+ /* Make a flat array of IDs for the DEG API. */
+ const int num_ids = BLI_listbase_count(targets);
+ ID **ids = MEM_malloc_arrayN(sizeof(ID *), num_ids, "animviz IDS");
+ int current_id_index = 0;
+ for (MPathTarget *mpt = targets->first; mpt != NULL; mpt = mpt->next) {
+ ids[current_id_index++] = &mpt->ob->id;
+ }
+
+ /* Build graph from all requested IDs. */
+ DEG_graph_build_from_ids(depsgraph, bmain, scene, view_layer, ids, num_ids);
+ MEM_freeN(ids);
+
+ /* Update once so we can access pointers of evaluated animation data. */
+ motionpaths_calc_update_scene(bmain, depsgraph);
+ return depsgraph;
+}
+
/* get list of motion paths to be baked for the given object
* - assumes the given list is ready to be used
*/
@@ -106,24 +138,6 @@ void animviz_get_object_motionpaths(Object *ob, ListBase *targets)
/* ........ */
-/* update scene for current frame */
-static void motionpaths_calc_update_scene(Main *bmain, struct Depsgraph *depsgraph)
-{
- /* Do all updates
- * - if this is too slow, resort to using a more efficient way
- * that doesn't force complete update, but for now, this is the
- * most accurate way!
- *
- * TODO(segey): Bring back partial updates, which became impossible
- * with the new depsgraph due to unsorted nature of bases.
- *
- * TODO(sergey): Use evaluation context dedicated to motion paths.
- */
- BKE_scene_graph_update_for_newframe(depsgraph, bmain);
-}
-
-/* ........ */
-
/* perform baking for the targets on the current frame */
static void motionpaths_calc_bake_targets(ListBase *targets, int cframe)
{
@@ -201,6 +215,135 @@ static void motionpaths_calc_bake_targets(ListBase *targets, int cframe)
}
}
+/* Get pointer to animviz settings for the given target. */
+static bAnimVizSettings *animviz_target_settings_get(MPathTarget *mpt)
+{
+ if (mpt->pchan != NULL) {
+ return &mpt->ob->pose->avs;
+ }
+ return &mpt->ob->avs;
+}
+
+static void motionpath_get_global_framerange(ListBase *targets, int *r_sfra, int *r_efra)
+{
+ *r_sfra = INT_MAX;
+ *r_efra = INT_MIN;
+ for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
+ *r_sfra = min_ii(*r_sfra, mpt->mpath->start_frame);
+ *r_efra = max_ii(*r_efra, mpt->mpath->end_frame);
+ }
+}
+
+static int motionpath_get_prev_keyframe(MPathTarget *mpt, DLRBT_Tree *fcu_keys, int current_frame)
+{
+ /* If the current frame is outside of the configured motion path range we ignore update of this
+ * motion path by using invalid frame range where start frame is above the end frame. */
+ if (current_frame <= mpt->mpath->start_frame) {
+ return INT_MAX;
+ }
+
+ float current_frame_float = current_frame;
+ DLRBT_Node *node = BLI_dlrbTree_search_prev(fcu_keys, compare_ak_cfraPtr, &current_frame_float);
+ if (node == NULL) {
+ return mpt->mpath->start_frame;
+ }
+
+ ActKeyColumn *key_data = (ActKeyColumn *)node;
+ return key_data->cfra;
+}
+
+static int motionpath_get_prev_prev_keyframe(MPathTarget *mpt,
+ DLRBT_Tree *fcu_keys,
+ int current_frame)
+{
+ int frame = motionpath_get_prev_keyframe(mpt, fcu_keys, current_frame);
+ return motionpath_get_prev_keyframe(mpt, fcu_keys, frame);
+}
+
+static int motionpath_get_next_keyframe(MPathTarget *mpt, DLRBT_Tree *fcu_keys, int current_frame)
+{
+ /* If the current frame is outside of the configured motion path range we ignore update of this
+ * motion path by using invalid frame range where start frame is above the end frame. */
+ if (current_frame >= mpt->mpath->end_frame) {
+ return INT_MIN;
+ }
+
+ float current_frame_float = current_frame;
+ DLRBT_Node *node = BLI_dlrbTree_search_next(fcu_keys, compare_ak_cfraPtr, &current_frame_float);
+ if (node == NULL) {
+ return mpt->mpath->end_frame;
+ }
+
+ ActKeyColumn *key_data = (ActKeyColumn *)node;
+ return key_data->cfra;
+}
+
+static int motionpath_get_next_next_keyframe(MPathTarget *mpt,
+ DLRBT_Tree *fcu_keys,
+ int current_frame)
+{
+ int frame = motionpath_get_next_keyframe(mpt, fcu_keys, current_frame);
+ return motionpath_get_next_keyframe(mpt, fcu_keys, frame);
+}
+
+static bool motionpath_check_can_use_keyframe_range(MPathTarget *UNUSED(mpt),
+ AnimData *adt,
+ ListBase *fcurve_list)
+{
+ if (adt == NULL || fcurve_list == NULL) {
+ return false;
+ }
+ /* NOTE: We might needed to do a full frame range update if there is a specific setup of NLA
+ * or drivers or modifiers on the f-curves. */
+ return true;
+}
+
+static void motionpath_calculate_update_range(MPathTarget *mpt,
+ AnimData *adt,
+ ListBase *fcurve_list,
+ int current_frame,
+ int *r_sfra,
+ int *r_efra)
+{
+ /* Similar to the case when there is only a single keyframe: need to update en entire range to
+ * a constant value. */
+ if (!motionpath_check_can_use_keyframe_range(mpt, adt, fcurve_list)) {
+ *r_sfra = mpt->mpath->start_frame;
+ *r_efra = mpt->mpath->end_frame;
+ return;
+ }
+
+ *r_sfra = INT_MAX;
+ *r_efra = INT_MIN;
+
+ /* NOTE: Iterate over individual f-curves, and check their keyframes individually and pick a
+ * widest range from them. This is because it's possible to have more narrow keyframe on a
+ * channel which wasn't edited.
+ * Could be optimized further by storing some flags about which channels has been modified so
+ * we ignore all others (which can potentially make an update range unnecessary wide). */
+ for (FCurve *fcu = fcurve_list->first; fcu != NULL; fcu = fcu->next) {
+ DLRBT_Tree fcu_keys;
+ BLI_dlrbTree_init(&fcu_keys);
+ fcurve_to_keylist(adt, fcu, &fcu_keys, 0);
+
+ int fcu_sfra = motionpath_get_prev_prev_keyframe(mpt, &fcu_keys, current_frame);
+ int fcu_efra = motionpath_get_next_next_keyframe(mpt, &fcu_keys, current_frame);
+
+ /* Extend range furher, since accelleration compensation propagates even further away. */
+ if (fcu->auto_smoothing != FCURVE_SMOOTH_NONE) {
+ fcu_sfra = motionpath_get_prev_prev_keyframe(mpt, &fcu_keys, fcu_sfra);
+ fcu_efra = motionpath_get_next_next_keyframe(mpt, &fcu_keys, fcu_efra);
+ }
+
+ if (fcu_sfra <= fcu_efra) {
+ *r_sfra = min_ii(*r_sfra, fcu_sfra);
+ *r_efra = max_ii(*r_efra, fcu_efra);
+ }
+
+ BLI_dlrbTree_free(&fcu_keys);
+ }
+}
+
/* Perform baking of the given object's and/or its bones' transforms to motion paths
* - scene: current scene
* - ob: object whose flagged motionpaths should get calculated
@@ -211,39 +354,36 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
Main *bmain,
Scene *scene,
ListBase *targets,
- bool restore,
- bool current_frame_only)
+ eAnimvizCalcRange range,
+ bool restore)
{
- /* sanity check */
+ /* Sanity check. */
if (ELEM(NULL, targets, targets->first)) {
return;
}
- /* Compute frame range to bake within.
- * TODO: this method could be improved...
- * 1) max range for standard baking
- * 2) minimum range for recalc baking (i.e. between keyframes, but how?) */
- int sfra = INT_MAX;
- int efra = INT_MIN;
-
- for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
- /* try to increase area to do (only as much as needed) */
- sfra = MIN2(sfra, mpt->mpath->start_frame);
- efra = MAX2(efra, mpt->mpath->end_frame);
- }
-
- if (efra <= sfra) {
- return;
- }
-
- /* Limit frame range if we are updating just the current frame. */
- /* set frame values */
- int cfra = CFRA;
- if (current_frame_only) {
- if (cfra < sfra || cfra > efra) {
- return;
- }
- sfra = efra = cfra;
+ const int cfra = CFRA;
+ int sfra = INT_MAX, efra = INT_MIN;
+ switch (range) {
+ case ANIMVIZ_CALC_RANGE_CURRENT_FRAME:
+ motionpath_get_global_framerange(targets, &sfra, &efra);
+ if (sfra > efra) {
+ return;
+ }
+ if (cfra < sfra || cfra > efra) {
+ return;
+ }
+ sfra = efra = cfra;
+ break;
+ case ANIMVIZ_CALC_RANGE_CHANGED:
+ /* Nothing to do here, will be handled later when iterating through the targets. */
+ break;
+ case ANIMVIZ_CALC_RANGE_FULL:
+ motionpath_get_global_framerange(targets, &sfra, &efra);
+ if (sfra > efra) {
+ return;
+ }
+ break;
}
/* get copies of objects/bones to get the calculated results from
@@ -271,16 +411,10 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
/* build list of all keyframes in active action for object or pchan */
BLI_dlrbTree_init(&mpt->keys);
+ ListBase *fcurve_list = NULL;
if (adt) {
- bAnimVizSettings *avs;
-
/* get pointer to animviz settings for each target */
- if (mpt->pchan) {
- avs = &mpt->ob->pose->avs;
- }
- else {
- avs = &mpt->ob->avs;
- }
+ bAnimVizSettings *avs = animviz_target_settings_get(mpt);
/* it is assumed that keyframes for bones are all grouped in a single group
* unless an option is set to always use the whole action
@@ -289,13 +423,28 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
bActionGroup *agrp = BKE_action_group_find_name(adt->action, mpt->pchan->name);
if (agrp) {
+ fcurve_list = &agrp->channels;
agroup_to_keylist(adt, agrp, &mpt->keys, 0);
}
}
else {
+ fcurve_list = &adt->action->curves;
action_to_keylist(adt, adt->action, &mpt->keys, 0);
}
}
+
+ if (range == ANIMVIZ_CALC_RANGE_CHANGED) {
+ int mpt_sfra, mpt_efra;
+ motionpath_calculate_update_range(mpt, adt, fcurve_list, cfra, &mpt_sfra, &mpt_efra);
+ if (mpt_sfra <= mpt_efra) {
+ sfra = min_ii(sfra, mpt_sfra);
+ efra = max_ii(efra, mpt_efra);
+ }
+ }
+ }
+
+ if (sfra > efra) {
+ return;
}
/* calculate path over requested range */
@@ -306,7 +455,7 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
efra,
efra - sfra + 1);
for (CFRA = sfra; CFRA <= efra; CFRA++) {
- if (current_frame_only) {
+ if (range == ANIMVIZ_CALC_RANGE_CURRENT_FRAME) {
/* For current frame, only update tagged. */
BKE_scene_graph_update_tagged(depsgraph, bmain);
}
@@ -324,7 +473,7 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
* may be a temporary one that works on a subset of the data.
* We always have to restore the current frame though. */
CFRA = cfra;
- if (!current_frame_only && restore) {
+ if (range != ANIMVIZ_CALC_RANGE_CURRENT_FRAME && restore) {
motionpaths_calc_update_scene(bmain, depsgraph);
}
@@ -334,16 +483,10 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
/* clear recalc flags from targets */
for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
- bAnimVizSettings *avs;
bMotionPath *mpath = mpt->mpath;
/* get pointer to animviz settings for each target */
- if (mpt->pchan) {
- avs = &mpt->ob->pose->avs;
- }
- else {
- avs = &mpt->ob->avs;
- }
+ bAnimVizSettings *avs = animviz_target_settings_get(mpt);
/* clear the flag requesting recalculation of targets */
avs->recalc &= ~ANIMVIZ_RECALC_PATHS;
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 7b9e6a10f44..61c8da08954 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -62,13 +62,11 @@
/* Get (or add relevant data to be able to do so) F-Curve from the driver stack,
* for the given Animation Data block. This assumes that all the destinations are valid.
- *
- * - add: 0 - don't add anything if not found,
- * 1 - add new Driver FCurve (with keyframes for visual tweaking),
- * 2 - add new Driver FCurve (with generator, for script backwards compatibility)
- * -1 - add new Driver FCurve without driver stuff (for pasting)
*/
-FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_index, short add)
+FCurve *verify_driver_fcurve(ID *id,
+ const char rna_path[],
+ const int array_index,
+ eDriverFCurveCreationMode creation_mode)
{
AnimData *adt;
FCurve *fcu;
@@ -80,7 +78,7 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
/* init animdata if none available yet */
adt = BKE_animdata_from_id(id);
- if ((adt == NULL) && (add)) {
+ if (adt == NULL && creation_mode != DRIVER_FCURVE_LOOKUP_ONLY) {
adt = BKE_animdata_add_id(id);
}
if (adt == NULL) {
@@ -94,9 +92,9 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
*/
fcu = list_find_fcurve(&adt->drivers, rna_path, array_index);
- if ((fcu == NULL) && (add)) {
+ if (fcu == NULL && creation_mode != DRIVER_FCURVE_LOOKUP_ONLY) {
/* use default settings to make a F-Curve */
- fcu = alloc_driver_fcurve(rna_path, array_index, add);
+ fcu = alloc_driver_fcurve(rna_path, array_index, creation_mode);
/* just add F-Curve to end of driver list */
BLI_addtail(&adt->drivers, fcu);
@@ -106,7 +104,9 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
return fcu;
}
-struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index, short add)
+struct FCurve *alloc_driver_fcurve(const char rna_path[],
+ const int array_index,
+ eDriverFCurveCreationMode creation_mode)
{
FCurve *fcu = MEM_callocN(sizeof(FCurve), "FCurve");
@@ -119,18 +119,12 @@ struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index,
}
fcu->array_index = array_index;
- /* If add is negative, don't init this data yet,
- * since it will be filled in by the pasted driver. */
- if (add > 0) {
- BezTriple *bezt;
- size_t i;
-
+ if (!ELEM(creation_mode, DRIVER_FCURVE_LOOKUP_ONLY, DRIVER_FCURVE_EMPTY)) {
/* add some new driver data */
fcu->driver = MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
/* F-Modifier or Keyframes? */
- // FIXME: replace these magic numbers with defines
- if (add == 2) {
+ if (creation_mode == DRIVER_FCURVE_GENERATOR) {
/* Python API Backwards compatibility hack:
* Create FModifier so that old scripts won't break
* for now before 2.7 series -- (September 4, 2013)
@@ -142,14 +136,10 @@ struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index,
* - These are configured to 0,0 and 1,1 to give a 1-1 mapping
* which can be easily tweaked from there.
*/
- insert_vert_fcurve(fcu, 0.0f, 0.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
- insert_vert_fcurve(fcu, 1.0f, 1.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
-
- /* configure this curve to extrapolate */
- for (i = 0, bezt = fcu->bezt; (i < fcu->totvert) && bezt; i++, bezt++) {
- bezt->h1 = bezt->h2 = HD_VECT;
- }
-
+ insert_vert_fcurve(
+ fcu, 0.0f, 0.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST | INSERTKEY_NO_USERPREF);
+ insert_vert_fcurve(
+ fcu, 1.0f, 1.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST | INSERTKEY_NO_USERPREF);
fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
calchandles_fcurve(fcu);
}
@@ -177,7 +167,8 @@ static int add_driver_with_target(ReportList *UNUSED(reports),
int driver_type)
{
FCurve *fcu;
- short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? 2 : 1;
+ short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? DRIVER_FCURVE_GENERATOR :
+ DRIVER_FCURVE_KEYFRAMES;
const char *prop_name = RNA_property_identifier(src_prop);
/* Create F-Curve with Driver */
@@ -593,7 +584,7 @@ bool ANIM_remove_driver(ReportList *UNUSED(reports),
* Note: here is one of the places where we don't want new F-Curve + Driver added!
* so 'add' var must be 0
*/
- fcu = verify_driver_fcurve(id, rna_path, array_index, 0);
+ fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_LOOKUP_ONLY);
if (fcu) {
BLI_remlink(&adt->drivers, fcu);
free_fcurve(fcu);
@@ -653,7 +644,7 @@ bool ANIM_copy_driver(
}
/* try to get F-Curve with Driver */
- fcu = verify_driver_fcurve(id, rna_path, array_index, 0);
+ fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_LOOKUP_ONLY);
/* clear copy/paste buffer first (for consistency with other copy/paste buffers) */
ANIM_drivers_copybuf_free();
@@ -711,7 +702,7 @@ bool ANIM_paste_driver(
}
/* create Driver F-Curve, but without data which will be copied across... */
- fcu = verify_driver_fcurve(id, rna_path, array_index, -1);
+ fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_EMPTY);
if (fcu) {
/* copy across the curve data from the buffer curve
@@ -855,7 +846,7 @@ void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const ch
ANIM_driver_vars_copybuf_free();
/* Create a dummy driver F-Curve. */
- FCurve *fcu = alloc_driver_fcurve(NULL, 0, 1);
+ FCurve *fcu = alloc_driver_fcurve(NULL, 0, DRIVER_FCURVE_KEYFRAMES);
ChannelDriver *driver = fcu->driver;
/* Create a variable. */
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index b42e8102c5b..705351522f8 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -197,7 +197,7 @@ static void draw_modifier__generator(uiLayout *layout,
&data->poly_order,
1,
100,
- 0,
+ 1,
0,
TIP_("'Order' of the Polynomial (for a polynomial with n terms, 'order' is n-1)"));
UI_but_func_set(but, validate_fmodifier_cb, fcm, fcurve_owner_id);
@@ -335,7 +335,7 @@ static void draw_modifier__generator(uiLayout *layout,
&data->poly_order,
1,
100,
- 0,
+ 1,
0,
TIP_("'Order' of the Polynomial (for a polynomial with n terms, 'order' is n-1)"));
UI_but_func_set(but, validate_fmodifier_cb, fcm, fcurve_owner_id);
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index ca7e0eae136..c174ce83bea 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -45,7 +45,6 @@
#include "BKE_fcurve.h"
-#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_state.h"
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index c4c10549da3..64857dd1874 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -908,8 +908,10 @@ static void bones_merge(
newbone->parent = start->parent;
/* TODO, copy more things to the new bone */
- newbone->flag = start->flag & (BONE_HINGE | BONE_NO_DEFORM | BONE_NO_SCALE |
- BONE_NO_CYCLICOFFSET | BONE_NO_LOCAL_LOCATION | BONE_DONE);
+ newbone->flag = start->flag & (BONE_HINGE | BONE_NO_DEFORM | BONE_NO_CYCLICOFFSET |
+ BONE_NO_LOCAL_LOCATION | BONE_DONE);
+
+ newbone->inherit_scale_mode = start->inherit_scale_mode;
/* Step 2a: reparent any side chains which may be parented to any bone in the chain
* of bones to merge - potentially several tips for side chains leading to some tree exist.
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index eff621d7b71..c37f9ce126b 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -251,12 +251,13 @@ void *get_bone_from_selectbuffer(Base **bases,
/* x and y are mouse coords (area space) */
void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel, Base **r_base)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
rcti rect;
unsigned int buffer[MAXPICKBUF];
short hits;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
// rect.xmin = ... mouseco!
rect.xmin = rect.xmax = xy[0];
@@ -648,8 +649,9 @@ bool ED_armature_edit_deselect_all_visible_multi_ex(struct Base **bases, uint ba
bool ED_armature_edit_deselect_all_visible_multi(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &bases_len);
@@ -674,12 +676,13 @@ static int ebone_select_flag(EditBone *ebone)
bool ED_armature_edit_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
EditBone *nearBone = NULL;
int selmask;
Base *basact = NULL;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
vc.mval[0] = mval[0];
vc.mval[1] = mval[1];
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
index 08de699a70b..c772590ed21 100644
--- a/source/blender/editors/armature/armature_skinning.c
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -234,7 +234,7 @@ static void envelope_bone_weighting(Object *ob,
iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, NULL, i, use_topology) : -1;
/* for each skinnable bone */
- for (j = 0; j < numbones; ++j) {
+ for (j = 0; j < numbones; j++) {
if (!selected[j]) {
continue;
}
@@ -346,7 +346,7 @@ static void add_verts_to_dgroups(ReportList *reports,
tip = MEM_callocN(numbones * sizeof(float) * 3, "tip");
selected = MEM_callocN(numbones * sizeof(int), "selected");
- for (j = 0; j < numbones; ++j) {
+ for (j = 0; j < numbones; j++) {
bone = bonelist[j];
dgroup = dgrouplist[j];
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index cd299906b4c..2b18fc15f63 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -491,6 +491,7 @@ static EditBone *make_boneList_rec(ListBase *edbo,
eBone->parent = parent;
BLI_strncpy(eBone->name, curBone->name, sizeof(eBone->name));
eBone->flag = curBone->flag;
+ eBone->inherit_scale_mode = curBone->inherit_scale_mode;
/* fix selection flags */
if (eBone->flag & BONE_SELECTED) {
@@ -719,6 +720,7 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm)
newBone->arm_roll = eBone->roll;
newBone->flag = eBone->flag;
+ newBone->inherit_scale_mode = eBone->inherit_scale_mode;
if (eBone == arm->act_edbone) {
/* don't change active selection, this messes up separate which uses
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 8f4896c0b82..ad115896a43 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -182,12 +182,25 @@ static bool pose_has_protected_selected(Object *ob, short warn)
/* ********************************************** */
/* Motion Paths */
+static eAnimvizCalcRange pose_path_convert_range(ePosePathCalcRange range)
+{
+ switch (range) {
+ case POSE_PATH_CALC_RANGE_CURRENT_FRAME:
+ return ANIMVIZ_CALC_RANGE_CURRENT_FRAME;
+ case POSE_PATH_CALC_RANGE_CHANGED:
+ return ANIMVIZ_CALC_RANGE_CHANGED;
+ case POSE_PATH_CALC_RANGE_FULL:
+ return ANIMVIZ_CALC_RANGE_FULL;
+ }
+ return ANIMVIZ_CALC_RANGE_FULL;
+}
+
/* For the object with pose/action: update paths for those that have got them
* This should selectively update paths that exist...
*
* To be called from various tools that do incremental updates
*/
-void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool current_frame_only)
+void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, ePosePathCalcRange range)
{
/* Transform doesn't always have context available to do update. */
if (C == NULL) {
@@ -195,12 +208,12 @@ void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool curre
}
Main *bmain = CTX_data_main(C);
- /* NOTE: Dependency graph will be evaluated at all the frames, but we first need to access some
- * nested pointers, like animation data. */
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- ListBase targets = {NULL, NULL};
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ Depsgraph *depsgraph;
bool free_depsgraph = false;
+ ListBase targets = {NULL, NULL};
/* set flag to force recalc, then grab the relevant bones to target */
ob->pose->avs.recalc |= ANIMVIZ_RECALC_PATHS;
animviz_get_object_motionpaths(ob, &targets);
@@ -210,7 +223,21 @@ void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool curre
TIMEIT_START(pose_path_calc);
#endif
- animviz_calc_motionpaths(depsgraph, bmain, scene, &targets, !free_depsgraph, current_frame_only);
+ /* For a single frame update it's faster to re-use existing dependency graph and avoid overhead
+ * of building all the relations and so on for a temporary one. */
+ if (range == POSE_PATH_CALC_RANGE_CURRENT_FRAME) {
+ /* NOTE: Dependency graph will be evaluated at all the frames, but we first need to access some
+ * nested pointers, like animation data. */
+ depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ free_depsgraph = false;
+ }
+ else {
+ depsgraph = animviz_depsgraph_build(bmain, scene, view_layer, &targets);
+ free_depsgraph = true;
+ }
+
+ animviz_calc_motionpaths(
+ depsgraph, bmain, scene, &targets, pose_path_convert_range(range), !free_depsgraph);
#ifdef DEBUG_TIME
TIMEIT_END(pose_path_calc);
@@ -218,13 +245,13 @@ void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool curre
BLI_freelistN(&targets);
- if (!current_frame_only) {
+ if (range != POSE_PATH_CALC_RANGE_CURRENT_FRAME) {
/* Tag armature object for copy on write - so paths will draw/redraw.
* For currently frame only we update evaluated object directly. */
DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
- /* Free temporary depsgraph instance */
+ /* Free temporary depsgraph. */
if (free_depsgraph) {
DEG_graph_free(depsgraph);
}
@@ -293,7 +320,7 @@ static int pose_calculate_paths_exec(bContext *C, wmOperator *op)
/* calculate the bones that now have motionpaths... */
/* TODO: only make for the selected bones? */
- ED_pose_recalculate_paths(C, scene, ob, false);
+ ED_pose_recalculate_paths(C, scene, ob, POSE_PATH_CALC_RANGE_FULL);
#ifdef DEBUG_TIME
TIMEIT_END(recalc_pose_paths);
@@ -371,7 +398,7 @@ static int pose_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
/* calculate the bones that now have motionpaths... */
/* TODO: only make for the selected bones? */
- ED_pose_recalculate_paths(C, scene, ob, false);
+ ED_pose_recalculate_paths(C, scene, ob, POSE_PATH_CALC_RANGE_FULL);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index a59067e60c1..c3a7d45f598 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -368,8 +368,9 @@ bool ED_pose_deselect_all_multi_ex(Base **bases,
bool ED_pose_deselect_all_multi(bContext *C, int select_mode, const bool ignore_visibility)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_mode(vc.view_layer,
vc.v3d,
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 6274eb549da..616daf94e57 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -1003,7 +1003,7 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p
pose_slide_refresh(C, pso);
/* set cursor to indicate modal */
- WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_EW_SCROLL);
/* header print */
pose_slide_draw_status(pso);
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 854fb237929..55c9b661074 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -241,13 +241,21 @@ static void applyarmature_process_selected_rec(bArmature *arm,
/* Parent effects on the bone transform that have to be removed. */
BKE_bone_offset_matrix_get(bone, offs_bone);
- BKE_bone_parent_transform_calc_from_matrices(
- bone->flag, offs_bone, bone->parent->arm_mat, pchan_eval->parent->pose_mat, &old_bpt);
+ BKE_bone_parent_transform_calc_from_matrices(bone->flag,
+ bone->inherit_scale_mode,
+ offs_bone,
+ bone->parent->arm_mat,
+ pchan_eval->parent->pose_mat,
+ &old_bpt);
/* Applied parent effects that have to be kept, if any. */
float(*new_parent_pose)[4] = pstate ? pstate->new_rest_mat : bone->parent->arm_mat;
- BKE_bone_parent_transform_calc_from_matrices(
- bone->flag, offs_bone, bone->parent->arm_mat, new_parent_pose, &new_bpt);
+ BKE_bone_parent_transform_calc_from_matrices(bone->flag,
+ bone->inherit_scale_mode,
+ offs_bone,
+ bone->parent->arm_mat,
+ new_parent_pose,
+ &new_bpt);
BKE_bone_parent_transform_invert(&old_bpt);
BKE_bone_parent_transform_combine(&new_bpt, &old_bpt, &invparent);
@@ -283,8 +291,12 @@ static void applyarmature_process_selected_rec(bArmature *arm,
/* Include applied parent effects. */
BKE_bone_offset_matrix_get(bone, offs_bone);
- BKE_bone_parent_transform_calc_from_matrices(
- bone->flag, offs_bone, pstate->bone->arm_mat, pstate->new_rest_mat, &bpt);
+ BKE_bone_parent_transform_calc_from_matrices(bone->flag,
+ bone->inherit_scale_mode,
+ offs_bone,
+ pstate->bone->arm_mat,
+ pstate->new_rest_mat,
+ &bpt);
unit_m4(new_pstate.new_rest_mat);
BKE_bone_parent_transform_apply(&bpt, new_pstate.new_rest_mat, new_pstate.new_rest_mat);
@@ -306,8 +318,12 @@ static void applyarmature_process_selected_rec(bArmature *arm,
/* Compute the channel coordinate space matrices for the new rest state. */
invert_m4_m4(inv_parent_arm, pstate->new_arm_mat);
mul_m4_m4m4(offs_bone, inv_parent_arm, new_pstate.new_arm_mat);
- BKE_bone_parent_transform_calc_from_matrices(
- bone->flag, offs_bone, pstate->new_arm_mat, pstate->new_arm_mat, &bpt);
+ BKE_bone_parent_transform_calc_from_matrices(bone->flag,
+ bone->inherit_scale_mode,
+ offs_bone,
+ pstate->new_arm_mat,
+ pstate->new_arm_mat,
+ &bpt);
/* Re-apply the location to keep the final effect. */
invert_m4(bpt.loc_mat);
@@ -527,16 +543,14 @@ static void set_pose_keys(Object *ob)
* \param chan: Bone that pose to paste comes from
* \param selOnly: Only paste on selected bones
* \param flip: Flip on x-axis
- * \return Whether the bone that we pasted to if we succeeded
+ * \return The channel of the bone that was pasted to, or NULL if no paste was performed.
*/
static bPoseChannel *pose_bone_do_paste(Object *ob,
bPoseChannel *chan,
const bool selOnly,
const bool flip)
{
- bPoseChannel *pchan;
char name[MAXBONENAME];
- short paste_ok;
/* get the name - if flipping, we must flip this first */
if (flip) {
@@ -551,131 +565,126 @@ static bPoseChannel *pose_bone_do_paste(Object *ob,
* 2) if selection-masking is on, channel is selected -
* only selected bones get pasted on, allowing making both sides symmetrical.
*/
- pchan = BKE_pose_channel_find_name(ob->pose, name);
-
- if (selOnly) {
- paste_ok = ((pchan) && (pchan->bone->flag & BONE_SELECTED));
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, name);
+ if (pchan == NULL) {
+ return NULL;
}
- else {
- paste_ok = (pchan != NULL);
+ if (selOnly && (pchan->bone->flag & BONE_SELECTED) == 0) {
+ return NULL;
}
- /* continue? */
- if (paste_ok) {
- /* only loc rot size
- * - only copies transform info for the pose
- */
- copy_v3_v3(pchan->loc, chan->loc);
- copy_v3_v3(pchan->size, chan->size);
- pchan->flag = chan->flag;
-
- /* check if rotation modes are compatible (i.e. do they need any conversions) */
- if (pchan->rotmode == chan->rotmode) {
- /* copy the type of rotation in use */
- if (pchan->rotmode > 0) {
- copy_v3_v3(pchan->eul, chan->eul);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- copy_v3_v3(pchan->rotAxis, chan->rotAxis);
- pchan->rotAngle = chan->rotAngle;
- }
- else {
- copy_qt_qt(pchan->quat, chan->quat);
- }
- }
- else if (pchan->rotmode > 0) {
- /* quat/axis-angle to euler */
- if (chan->rotmode == ROT_MODE_AXISANGLE) {
- axis_angle_to_eulO(pchan->eul, pchan->rotmode, chan->rotAxis, chan->rotAngle);
- }
- else {
- quat_to_eulO(pchan->eul, pchan->rotmode, chan->quat);
- }
+ /* only loc rot size
+ * - only copies transform info for the pose
+ */
+ copy_v3_v3(pchan->loc, chan->loc);
+ copy_v3_v3(pchan->size, chan->size);
+ pchan->flag = chan->flag;
+
+ /* check if rotation modes are compatible (i.e. do they need any conversions) */
+ if (pchan->rotmode == chan->rotmode) {
+ /* copy the type of rotation in use */
+ if (pchan->rotmode > 0) {
+ copy_v3_v3(pchan->eul, chan->eul);
}
else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- /* quat/euler to axis angle */
- if (chan->rotmode > 0) {
- eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode);
- }
- else {
- quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat);
- }
+ copy_v3_v3(pchan->rotAxis, chan->rotAxis);
+ pchan->rotAngle = chan->rotAngle;
}
else {
- /* euler/axis-angle to quat */
- if (chan->rotmode > 0) {
- eulO_to_quat(pchan->quat, chan->eul, chan->rotmode);
- }
- else {
- axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
- }
+ copy_qt_qt(pchan->quat, chan->quat);
+ }
+ }
+ else if (pchan->rotmode > 0) {
+ /* quat/axis-angle to euler */
+ if (chan->rotmode == ROT_MODE_AXISANGLE) {
+ axis_angle_to_eulO(pchan->eul, pchan->rotmode, chan->rotAxis, chan->rotAngle);
+ }
+ else {
+ quat_to_eulO(pchan->eul, pchan->rotmode, chan->quat);
+ }
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ /* quat/euler to axis angle */
+ if (chan->rotmode > 0) {
+ eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode);
+ }
+ else {
+ quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat);
+ }
+ }
+ else {
+ /* euler/axis-angle to quat */
+ if (chan->rotmode > 0) {
+ eulO_to_quat(pchan->quat, chan->eul, chan->rotmode);
}
+ else {
+ axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
+ }
+ }
- /* B-Bone posing options should also be included... */
- pchan->curve_in_x = chan->curve_in_x;
- pchan->curve_in_y = chan->curve_in_y;
- pchan->curve_out_x = chan->curve_out_x;
- pchan->curve_out_y = chan->curve_out_y;
-
- pchan->roll1 = chan->roll1;
- pchan->roll2 = chan->roll2;
- pchan->ease1 = chan->ease1;
- pchan->ease2 = chan->ease2;
- pchan->scale_in_x = chan->scale_in_x;
- pchan->scale_in_y = chan->scale_in_y;
- pchan->scale_out_x = chan->scale_out_x;
- pchan->scale_out_y = chan->scale_out_y;
-
- /* paste flipped pose? */
- if (flip) {
- pchan->loc[0] *= -1;
-
- pchan->curve_in_x *= -1;
- pchan->curve_out_x *= -1;
- pchan->roll1 *= -1; // XXX?
- pchan->roll2 *= -1; // XXX?
-
- /* has to be done as eulers... */
- if (pchan->rotmode > 0) {
- pchan->eul[1] *= -1;
- pchan->eul[2] *= -1;
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- float eul[3];
+ /* B-Bone posing options should also be included... */
+ pchan->curve_in_x = chan->curve_in_x;
+ pchan->curve_in_y = chan->curve_in_y;
+ pchan->curve_out_x = chan->curve_out_x;
+ pchan->curve_out_y = chan->curve_out_y;
+
+ pchan->roll1 = chan->roll1;
+ pchan->roll2 = chan->roll2;
+ pchan->ease1 = chan->ease1;
+ pchan->ease2 = chan->ease2;
+ pchan->scale_in_x = chan->scale_in_x;
+ pchan->scale_in_y = chan->scale_in_y;
+ pchan->scale_out_x = chan->scale_out_x;
+ pchan->scale_out_y = chan->scale_out_y;
+
+ /* paste flipped pose? */
+ if (flip) {
+ pchan->loc[0] *= -1;
- axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
- eul[1] *= -1;
- eul[2] *= -1;
- eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
- }
- else {
- float eul[3];
+ pchan->curve_in_x *= -1;
+ pchan->curve_out_x *= -1;
+ pchan->roll1 *= -1; // XXX?
+ pchan->roll2 *= -1; // XXX?
- normalize_qt(pchan->quat);
- quat_to_eul(eul, pchan->quat);
- eul[1] *= -1;
- eul[2] *= -1;
- eul_to_quat(pchan->quat, eul);
- }
+ /* has to be done as eulers... */
+ if (pchan->rotmode > 0) {
+ pchan->eul[1] *= -1;
+ pchan->eul[2] *= -1;
}
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ float eul[3];
- /* ID properties */
- if (chan->prop) {
- if (pchan->prop) {
- /* if we have existing properties on a bone, just copy over the values of
- * matching properties (i.e. ones which will have some impact) on to the
- * target instead of just blinding replacing all [
- */
- IDP_SyncGroupValues(pchan->prop, chan->prop);
- }
- else {
- /* no existing properties, so assume that we want copies too? */
- pchan->prop = IDP_CopyProperty(chan->prop);
- }
+ axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
+ eul[1] *= -1;
+ eul[2] *= -1;
+ eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
+ }
+ else {
+ float eul[3];
+
+ normalize_qt(pchan->quat);
+ quat_to_eul(eul, pchan->quat);
+ eul[1] *= -1;
+ eul[2] *= -1;
+ eul_to_quat(pchan->quat, eul);
+ }
+ }
+
+ /* ID properties */
+ if (chan->prop) {
+ if (pchan->prop) {
+ /* if we have existing properties on a bone, just copy over the values of
+ * matching properties (i.e. ones which will have some impact) on to the
+ * target instead of just blinding replacing all [
+ */
+ IDP_SyncGroupValues(pchan->prop, chan->prop);
+ }
+ else {
+ /* no existing properties, so assume that we want copies too? */
+ pchan->prop = IDP_CopyProperty(chan->prop);
}
}
- /* return whether paste went ahead */
return pchan;
}
@@ -815,7 +824,7 @@ static int pose_paste_exec(bContext *C, wmOperator *op)
/* Recalculate paths if any of the bones have paths... */
if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
- ED_pose_recalculate_paths(C, scene, ob, false);
+ ED_pose_recalculate_paths(C, scene, ob, POSE_PATH_CALC_RANGE_FULL);
}
/* Notifiers for updates, */
@@ -1096,7 +1105,7 @@ static int pose_clear_transform_generic_exec(bContext *C,
/* now recalculate paths */
if ((ob_iter->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
- ED_pose_recalculate_paths(C, scene, ob_iter, false);
+ ED_pose_recalculate_paths(C, scene, ob_iter, POSE_PATH_CALC_RANGE_FULL);
}
BLI_freelistN(&dsources);
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index fbaf2c896d0..3f6db956643 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -327,7 +327,8 @@ void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks,
if (ob->id.tag & LIB_TAG_DOIT) {
if (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) {
// ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear
- ED_pose_recalculate_paths(C, scene, ob, false);
+ /* TODO(sergey): Should ensure we can use more narrow update range here. */
+ ED_pose_recalculate_paths(C, scene, ob, POSE_PATH_CALC_RANGE_FULL);
}
}
}
diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c
index 3d2ac009072..81c9c759188 100644
--- a/source/blender/editors/curve/curve_ops.c
+++ b/source/blender/editors/curve/curve_ops.c
@@ -33,10 +33,7 @@
#include "WM_types.h"
#include "ED_curve.h"
-#include "ED_object.h"
#include "ED_screen.h"
-#include "ED_select_utils.h"
-#include "ED_transform.h"
#include "curve_intern.h"
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index d7650db546d..994d844287c 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -56,13 +56,11 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "ED_keyframes_edit.h"
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_transform_snap_object_context.h"
#include "ED_types.h"
-#include "ED_util.h"
#include "ED_view3d.h"
#include "ED_curve.h"
@@ -692,7 +690,7 @@ static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
if (oldbezt) {
int j;
- for (j = 0; j < 3; ++j) {
+ for (j = 0; j < 3; j++) {
sub_v3_v3v3(ofs[i], bezt->vec[j], oldbezt->vec[j]);
i++;
}
@@ -4876,6 +4874,7 @@ void CURVE_OT_make_segment(wmOperatorType *ot)
bool ED_curve_editnurb_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
Nurb *nu;
BezTriple *bezt = NULL;
@@ -4884,7 +4883,7 @@ bool ED_curve_editnurb_select_pick(
short hand;
view3d_operator_needs_opengl(C);
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
copy_v2_v2_int(vc.mval, mval);
if (ED_curve_pick_vert(&vc, 1, &nu, &bezt, &bp, &hand, &basact)) {
@@ -5635,9 +5634,10 @@ static int add_vertex_exec(bContext *C, wmOperator *op)
static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
if (vc.rv3d && !RNA_struct_property_is_set(op->ptr, "location")) {
Curve *cu;
@@ -7136,7 +7136,6 @@ static int match_texture_space_exec(bContext *C, wmOperator *UNUSED(op))
copy_v3_v3(curve->loc, loc);
copy_v3_v3(curve->size, size);
- zero_v3(curve->rot);
curve->texflag &= ~CU_AUTOSPACE;
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index 4912ae5451d..d97223de9b8 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -44,7 +44,6 @@
#include "ED_object.h"
#include "ED_screen.h"
-#include "ED_undo.h"
#include "ED_view3d.h"
#include "ED_curve.h"
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index c7c19aa2d02..4c4bac6a249 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -31,7 +31,6 @@
#include "BKE_curve.h"
#include "BKE_fcurve.h"
#include "BKE_report.h"
-#include "BKE_layer.h"
#include "DEG_depsgraph.h"
@@ -575,9 +574,10 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
BLI_assert(op->customdata == NULL);
struct CurveDrawData *cdd = MEM_callocN(sizeof(*cdd), __func__);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
if (is_invoke) {
- ED_view3d_viewcontext_init(C, &cdd->vc);
+ ED_view3d_viewcontext_init(C, &cdd->vc, depsgraph);
if (ELEM(NULL, cdd->vc.ar, cdd->vc.rv3d, cdd->vc.v3d, cdd->vc.win, cdd->vc.scene)) {
MEM_freeN(cdd);
BKE_report(op->reports, RPT_ERROR, "Unable to access 3D viewport");
@@ -586,7 +586,7 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
}
else {
cdd->vc.bmain = CTX_data_main(C);
- cdd->vc.depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ cdd->vc.depsgraph = depsgraph;
cdd->vc.scene = CTX_data_scene(C);
cdd->vc.view_layer = CTX_data_view_layer(C);
cdd->vc.obedit = CTX_data_edit_object(C);
@@ -1064,7 +1064,7 @@ static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
cdd->draw_handle_view = ED_region_draw_cb_activate(
cdd->vc.ar->type, curve_draw_stroke_3d, op, REGION_DRAW_POST_VIEW);
- WM_cursor_modal_set(cdd->vc.win, BC_PAINTBRUSHCURSOR);
+ WM_cursor_modal_set(cdd->vc.win, WM_CURSOR_PAINT_BRUSH);
{
View3D *v3d = cdd->vc.v3d;
diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c
index f67ccf1e4bd..9df79a082e1 100644
--- a/source/blender/editors/curve/editcurve_select.c
+++ b/source/blender/editors/curve/editcurve_select.c
@@ -37,7 +37,6 @@
#include "BKE_fcurve.h"
#include "BKE_layer.h"
#include "BKE_report.h"
-#include "BKE_object.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -278,8 +277,9 @@ bool ED_curve_deselect_all_multi_ex(Base **bases, int bases_len)
bool ED_curve_deselect_all_multi(struct bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &bases_len);
@@ -684,6 +684,7 @@ void CURVE_OT_select_linked(wmOperatorType *ot)
static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
Nurb *nu;
BezTriple *bezt;
@@ -693,7 +694,7 @@ static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent
Base *basact = NULL;
view3d_operator_needs_opengl(C);
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
copy_v2_v2_int(vc.mval, event->mval);
if (!ED_curve_pick_vert(&vc, 1, &nu, &bezt, &bp, NULL, &basact)) {
@@ -1311,7 +1312,7 @@ static void select_nth_bezt(Nurb *nu, BezTriple *bezt, const struct CheckerInter
while (a--) {
const int depth = abs(start - a);
- if (WM_operator_properties_checker_interval_test(params, depth)) {
+ if (!WM_operator_properties_checker_interval_test(params, depth)) {
select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
}
@@ -1334,7 +1335,7 @@ static void select_nth_bp(Nurb *nu, BPoint *bp, const struct CheckerIntervalPara
while (a--) {
const int depth = abs(pnt - startpnt) + abs(row - startrow);
- if (WM_operator_properties_checker_interval_test(params, depth)) {
+ if (!WM_operator_properties_checker_interval_test(params, depth)) {
select_bpoint(bp, DESELECT, SELECT, HIDDEN);
}
@@ -1960,6 +1961,7 @@ static void curve_select_shortest_path_surf(Nurb *nu, int vert_src, int vert_dst
static int edcu_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
Nurb *nu_dst;
BezTriple *bezt_dst;
@@ -1969,7 +1971,7 @@ static int edcu_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE
Base *basact = NULL;
view3d_operator_needs_opengl(C);
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
copy_v2_v2_int(vc.mval, event->mval);
if (!ED_curve_pick_vert(&vc, 1, &nu_dst, &bezt_dst, &bp_dst, NULL, &basact)) {
diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c
index 835abd1a630..f21b4f06246 100644
--- a/source/blender/editors/curve/editcurve_undo.c
+++ b/source/blender/editors/curve/editcurve_undo.c
@@ -40,9 +40,7 @@
#include "DEG_depsgraph.h"
-#include "ED_object.h"
#include "ED_undo.h"
-#include "ED_util.h"
#include "ED_curve.h"
#include "WM_types.h"
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 781eb2634fb..603b0967ace 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -60,7 +60,6 @@
#include "ED_curve.h"
#include "ED_object.h"
#include "ED_screen.h"
-#include "ED_util.h"
#include "ED_view3d.h"
#include "UI_interface.h"
@@ -2201,6 +2200,7 @@ void FONT_OT_unlink(wmOperatorType *ot)
bool ED_curve_editfont_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *obedit = CTX_data_edit_object(C);
Curve *cu = obedit->data;
ViewContext vc;
@@ -2212,7 +2212,7 @@ bool ED_curve_editfont_select_pick(
const float dist = ED_view3d_select_dist_px();
float dist_sq_best = dist * dist;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c
index 2f8f15bc6c7..ae858ec4c24 100644
--- a/source/blender/editors/curve/editfont_undo.c
+++ b/source/blender/editors/curve/editfont_undo.c
@@ -29,7 +29,6 @@
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
#include "BKE_context.h"
#include "BKE_font.h"
@@ -39,7 +38,6 @@
#include "ED_object.h"
#include "ED_curve.h"
-#include "ED_util.h"
#include "WM_types.h"
#include "WM_api.h"
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 69738d2e008..8a3a078bdd2 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -645,6 +645,8 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
brush.sculpt.clay_strips
brush.sculpt.crease
brush.sculpt.draw
+ brush.sculpt.draw_sharp
+ brush.sculpt.elastic_deform
brush.sculpt.fill
brush.sculpt.flatten
brush.sculpt.grab
@@ -653,6 +655,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
brush.sculpt.mask
brush.sculpt.nudge
brush.sculpt.pinch
+ brush.sculpt.pose
brush.sculpt.rotate
brush.sculpt.scrape
brush.sculpt.simplify
@@ -736,6 +739,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.sculpt.border_hide
ops.sculpt.border_mask
ops.sculpt.lasso_mask
+ ops.sculpt.mesh_filter
ops.transform.bone_envelope
ops.transform.bone_size
ops.transform.edge_slide
@@ -836,6 +840,8 @@ if(WITH_BLENDER)
data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_block.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_marker.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_fill.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_airbrush.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_chisel.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_soft.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_hard.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_stroke.png SRC)
diff --git a/source/blender/editors/gizmo_library/gizmo_draw_utils.c b/source/blender/editors/gizmo_library/gizmo_draw_utils.c
index f1d8c1ac6b0..cffafc56693 100644
--- a/source/blender/editors/gizmo_library/gizmo_draw_utils.c
+++ b/source/blender/editors/gizmo_library/gizmo_draw_utils.c
@@ -31,7 +31,6 @@
#include "GPU_batch.h"
#include "GPU_glew.h"
#include "GPU_immediate.h"
-#include "GPU_state.h"
#include "MEM_guardedalloc.h"
@@ -66,7 +65,7 @@ void wm_gizmo_geometryinfo_draw(const GizmoGeomInfo *info,
/* Elements */
GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, info->ntris, info->nverts);
- for (int i = 0; i < info->ntris; ++i) {
+ for (int i = 0; i < info->ntris; i++) {
const unsigned short *idx = &info->indices[i * 3];
GPU_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]);
}
diff --git a/source/blender/editors/gizmo_library/gizmo_library_presets.c b/source/blender/editors/gizmo_library/gizmo_library_presets.c
index ae43894b7b6..fe0893ae3ff 100644
--- a/source/blender/editors/gizmo_library/gizmo_library_presets.c
+++ b/source/blender/editors/gizmo_library/gizmo_library_presets.c
@@ -31,9 +31,6 @@
#include "BKE_context.h"
-#include "GPU_draw.h"
-#include "GPU_immediate.h"
-#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
#include "GPU_select.h"
@@ -57,7 +54,7 @@
* Given a single axis, orient the matrix to a different direction.
*/
static void single_axis_convert(int src_axis,
- float src_mat[4][4],
+ const float src_mat[4][4],
int dst_axis,
float dst_mat[4][4])
{
@@ -76,7 +73,7 @@ static void single_axis_convert(int src_axis,
* Use for all geometry.
*/
static void ed_gizmo_draw_preset_geometry(const struct wmGizmo *gz,
- float mat[4][4],
+ const float mat[4][4],
int select_id,
const GizmoGeomInfo *info)
{
diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c
index c175bfb90ab..24571f67fdb 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c
@@ -31,7 +31,6 @@
#include "BKE_context.h"
-#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
#include "GPU_state.h"
diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
index fa9c0f1fbb2..6a28c626a81 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
@@ -38,7 +38,6 @@
#include "BKE_context.h"
-#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
diff --git a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
index 1a132c2957a..ecbc503e084 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
@@ -258,9 +258,9 @@ static int gizmo_button2d_test_select(bContext *C, wmGizmo *gz, const int mval[2
static int gizmo_button2d_cursor_get(wmGizmo *gz)
{
if (RNA_boolean_get(gz->ptr, "show_drag")) {
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
- return CURSOR_STD;
+ return WM_CURSOR_DEFAULT;
}
static void gizmo_button2d_free(wmGizmo *gz)
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
index ba3b8c2602e..ef4fd23b64d 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
@@ -752,30 +752,30 @@ static int gizmo_cage2d_get_cursor(wmGizmo *gz)
int highlight_part = gz->highlight_part;
if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
switch (highlight_part) {
case ED_GIZMO_CAGE2D_PART_TRANSLATE:
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X:
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X:
- return CURSOR_X_MOVE;
+ return WM_CURSOR_X_MOVE;
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y:
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y:
- return CURSOR_Y_MOVE;
+ return WM_CURSOR_Y_MOVE;
/* TODO diagonal cursor */
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y:
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y:
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y:
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y:
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
case ED_GIZMO_CAGE2D_PART_ROTATE:
- return BC_CROSSCURSOR;
+ return WM_CURSOR_CROSS;
default:
- return CURSOR_STD;
+ return WM_CURSOR_DEFAULT;
}
}
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
index 406f76bc65e..723be3cfe6b 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
@@ -424,10 +424,10 @@ static void gizmo_cage3d_draw(const bContext *C, wmGizmo *gz)
static int gizmo_cage3d_get_cursor(wmGizmo *gz)
{
if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
- return CURSOR_STD;
+ return WM_CURSOR_DEFAULT;
}
typedef struct RectTransformInteraction {
diff --git a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
index 6d8ab096a26..d3121711e28 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
@@ -273,7 +273,7 @@ static void dial_ghostarc_draw(const float angle_ofs,
static void dial_ghostarc_get_angles(const wmGizmo *gz,
const wmEvent *event,
const ARegion *ar,
- float mat[4][4],
+ const float mat[4][4],
const float co_outer[3],
float *r_start,
float *r_delta)
diff --git a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
index 37ee95d5058..5342f8695b2 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
@@ -412,7 +412,7 @@ static void gizmo_move_property_update(wmGizmo *gz, wmGizmoProperty *gz_prop)
static int gizmo_move_cursor_get(wmGizmo *UNUSED(gz))
{
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c
index 697d06aa098..67bf64a2903 100644
--- a/source/blender/editors/gpencil/annotate_draw.c
+++ b/source/blender/editors/gpencil/annotate_draw.c
@@ -55,7 +55,6 @@
#include "BIF_glutil.h"
#include "GPU_immediate.h"
-#include "GPU_draw.h"
#include "GPU_state.h"
#include "ED_gpencil.h"
@@ -96,7 +95,7 @@ static void annotation_draw_stroke_buffer(const tGPspoint *points,
short thickness,
short dflag,
short sflag,
- float ink[4])
+ const float ink[4])
{
int draw_points = 0;
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index 22f1753a810..7a10547f35c 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -1560,10 +1560,10 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
static void gpencil_draw_cursor_set(tGPsdata *p)
{
if (p->paintmode == GP_PAINTMODE_ERASER) {
- WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */
+ WM_cursor_modal_set(p->win, WM_CURSOR_ERASER);
}
else {
- WM_cursor_modal_set(p->win, BC_PAINTBRUSHCURSOR);
+ WM_cursor_modal_set(p->win, WM_CURSOR_PAINT_BRUSH);
}
}
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 7c76f3aeab6..80795b825b0 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -62,7 +62,6 @@
#include "BIF_glutil.h"
#include "GPU_immediate.h"
-#include "GPU_draw.h"
#include "GPU_state.h"
#include "ED_gpencil.h"
@@ -268,8 +267,11 @@ static void gp_calc_2d_bounding_box(
}
/* calc texture coordinates using flat projected points */
-static void gp_calc_stroke_text_coordinates(
- const float (*points2d)[2], int totpoints, float minv[2], float maxv[2], float (*r_uv)[2])
+static void gp_calc_stroke_text_coordinates(const float (*points2d)[2],
+ int totpoints,
+ const float minv[2],
+ float maxv[2],
+ float (*r_uv)[2])
{
float d[2];
d[0] = maxv[0] - minv[0];
diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c
index c4528518009..139697ad0e3 100644
--- a/source/blender/editors/gpencil/gpencil_add_monkey.c
+++ b/source/blender/editors/gpencil/gpencil_add_monkey.c
@@ -54,7 +54,7 @@ static int gpencil_monkey_color(
short *totcol = give_totcolp(ob);
Material *ma = NULL;
for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
+ ma = BKE_material_gpencil_get(ob, i + 1);
if (STREQ(ma->id.name, pct->name)) {
return i;
}
diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c
index 80e239c9ae5..74617599eaa 100644
--- a/source/blender/editors/gpencil/gpencil_add_stroke.c
+++ b/source/blender/editors/gpencil/gpencil_add_stroke.c
@@ -53,7 +53,7 @@ static int gp_stroke_material(Main *bmain, Object *ob, const ColorTemplate *pct,
short *totcol = give_totcolp(ob);
Material *ma = NULL;
for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
+ ma = BKE_material_gpencil_get(ob, i + 1);
if (STREQ(ma->id.name, pct->name)) {
return i;
}
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c
index d1c4f271321..af9cadfb938 100644
--- a/source/blender/editors/gpencil/gpencil_brush.c
+++ b/source/blender/editors/gpencil/gpencil_brush.c
@@ -52,6 +52,7 @@
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_material.h"
#include "BKE_object_deform.h"
#include "BKE_report.h"
@@ -71,10 +72,6 @@
#include "ED_screen.h"
#include "ED_view3d.h"
-#include "GPU_immediate.h"
-#include "GPU_immediate_util.h"
-#include "GPU_state.h"
-
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -113,6 +110,7 @@ typedef struct tGP_BrushEditData {
/* Is the brush currently painting? */
bool is_painting;
bool is_weight_mode;
+ bool is_transformed;
/* Start of new sculpt stroke */
bool first;
@@ -536,7 +534,7 @@ static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso)
// XXX: screen-space strokes in 3D space will suffer!
if (gso->sa->spacetype == SPACE_VIEW3D) {
RegionView3D *rv3d = gso->ar->regiondata;
- float *rvec = gso->scene->cursor.location;
+ float *rvec = gso->object->loc;
float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
float mval_f[2];
@@ -569,7 +567,7 @@ static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso)
/* Apply grab transform to all relevant points of the affected strokes */
static void gp_brush_grab_apply_cached(tGP_BrushEditData *gso,
bGPDstroke *gps,
- float diff_mat[4][4])
+ const float diff_mat[4][4])
{
tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
int i;
@@ -661,7 +659,7 @@ static void gp_brush_calc_midpoint(tGP_BrushEditData *gso)
* See: gpencil_paint.c :: gp_stroke_convertcoords()
*/
RegionView3D *rv3d = gso->ar->regiondata;
- const float *rvec = gso->scene->cursor.location;
+ const float *rvec = gso->object->loc;
float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
float mval_f[2];
@@ -1330,9 +1328,12 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
if (!BLI_findlink(&ob->defbase, gso->vrgroup)) {
gso->vrgroup = -1;
}
+ /* Check if some modifier can transform the stroke. */
+ gso->is_transformed = BKE_gpencil_has_transform_modifiers(ob);
}
else {
gso->vrgroup = -1;
+ gso->is_transformed = false;
}
gso->sa = CTX_wm_area(C);
@@ -1401,7 +1402,7 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
gpsculpt_brush_header_set(C, gso);
/* setup cursor drawing */
- // WM_cursor_modal_set(CTX_wm_window(C), BC_CROSSCURSOR);
+ // WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_CROSS);
if (gso->sa->spacetype != SPACE_VIEW3D) {
ED_gpencil_toggle_brush_cursor(C, true, NULL);
}
@@ -1467,7 +1468,7 @@ static bool gpsculpt_brush_poll(bContext *C)
/* Init Sculpt Stroke ---------------------------------- */
-static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
+static void gpsculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso)
{
bGPdata *gpd = gso->gpd;
@@ -1491,9 +1492,11 @@ static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
* - This is useful when animating as it saves that "uh-oh" moment when you realize you've
* spent too much time editing the wrong frame.
*/
- // XXX: should this be allowed when framelock is enabled?
if (gpf->framenum != cfra) {
BKE_gpencil_frame_addcopy(gpl, cfra);
+ /* Need tag to recalculate evaluated data to avoid crashes. */
+ DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
}
}
@@ -1508,12 +1511,17 @@ static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
* For strokes with one point only this is impossible to calculate because there isn't a
* valid reference point.
*/
-static float gpsculpt_rotation_eval_get(GP_SpaceConversion *gsc,
+static float gpsculpt_rotation_eval_get(tGP_BrushEditData *gso,
bGPDstroke *gps_eval,
bGPDspoint *pt_eval,
int idx_eval)
{
+ /* If multiframe or no modifiers, return 0. */
+ if ((GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd)) || (!gso->is_transformed)) {
+ return 0.0f;
+ }
+ GP_SpaceConversion *gsc = &gso->gsc;
bGPDstroke *gps_orig = gps_eval->runtime.gps_orig;
bGPDspoint *pt_orig = &gps_orig->points[pt_eval->runtime.idx_orig];
bGPDspoint *pt_prev_eval = NULL;
@@ -1559,7 +1567,7 @@ static float gpsculpt_rotation_eval_get(GP_SpaceConversion *gsc,
/* Apply brush operation to points in this stroke */
static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
bGPDstroke *gps,
- float diff_mat[4][4],
+ const float diff_mat[4][4],
GP_BrushApplyCb apply)
{
GP_SpaceConversion *gsc = &gso->gsc;
@@ -1568,12 +1576,16 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
const int radius = (gp_brush->flag & GP_SCULPT_FLAG_PRESSURE_RADIUS) ?
gso->gp_brush->size * gso->pressure :
gso->gp_brush->size;
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd);
+ bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
+ bGPDspoint *pt_active = NULL;
bGPDspoint *pt1, *pt2;
bGPDspoint *pt = NULL;
int pc1[2] = {0};
int pc2[2] = {0};
int i;
+ int index;
bool include_last = false;
bool changed = false;
float rot_eval = 0.0f;
@@ -1583,6 +1595,7 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
+ pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
/* do boundbox check first */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
@@ -1590,9 +1603,9 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
round_v2i_v2fl(mval_i, gso->mval);
if (len_v2v2_int(mval_i, pc1) <= radius) {
/* apply operation to this point */
- if (pt->runtime.pt_orig != NULL) {
- rot_eval = gpsculpt_rotation_eval_get(&gso->gsc, gps, pt, 0);
- changed = apply(gso, gps->runtime.gps_orig, rot_eval, pt->runtime.idx_orig, radius, pc1);
+ if (pt_active != NULL) {
+ rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, 0);
+ changed = apply(gso, gps_active, rot_eval, 0, radius, pc1);
}
}
}
@@ -1635,9 +1648,11 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
/* To each point individually... */
pt = &gps->points[i];
- if (pt->runtime.pt_orig != NULL) {
- rot_eval = gpsculpt_rotation_eval_get(&gso->gsc, gps, pt, i);
- ok = apply(gso, gps->runtime.gps_orig, rot_eval, pt->runtime.idx_orig, radius, pc1);
+ pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
+ index = (!is_multiedit) ? pt->runtime.idx_orig : i;
+ if (pt_active != NULL) {
+ rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i);
+ ok = apply(gso, gps_active, rot_eval, index, radius, pc1);
}
/* Only do the second point if this is the last segment,
@@ -1650,9 +1665,11 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
*/
if (i + 1 == gps->totpoints - 1) {
pt = &gps->points[i + 1];
- if (pt->runtime.pt_orig != NULL) {
- rot_eval = gpsculpt_rotation_eval_get(&gso->gsc, gps, pt, i + 1);
- ok |= apply(gso, gps->runtime.gps_orig, rot_eval, pt->runtime.idx_orig, radius, pc2);
+ pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
+ index = (!is_multiedit) ? pt->runtime.idx_orig : i + 1;
+ if (pt_active != NULL) {
+ rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i + 1);
+ ok |= apply(gso, gps_active, rot_eval, index, radius, pc2);
include_last = false;
}
}
@@ -1669,10 +1686,11 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
* (but wasn't added then, to avoid double-ups).
*/
pt = &gps->points[i];
- if (pt->runtime.pt_orig != NULL) {
- rot_eval = gpsculpt_rotation_eval_get(&gso->gsc, gps, pt, i);
- changed |= apply(
- gso, gps->runtime.gps_orig, rot_eval, pt->runtime.idx_orig, radius, pc1);
+ pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
+ index = (!is_multiedit) ? pt->runtime.idx_orig : i;
+ if (pt_active != NULL) {
+ rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i);
+ changed |= apply(gso, gps_active, rot_eval, index, radius, pc1);
include_last = false;
}
}
@@ -1684,11 +1702,15 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
}
/* Apply sculpt brushes to strokes in the given frame */
-static bool gpsculpt_brush_do_frame(
- bContext *C, tGP_BrushEditData *gso, bGPDlayer *gpl, bGPDframe *gpf, float diff_mat[4][4])
+static bool gpsculpt_brush_do_frame(bContext *C,
+ tGP_BrushEditData *gso,
+ bGPDlayer *gpl,
+ bGPDframe *gpf,
+ const float diff_mat[4][4])
{
bool changed = false;
Object *ob = CTX_data_active_object(C);
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd);
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
/* skip strokes that are invalid for current view */
@@ -1721,18 +1743,19 @@ static bool gpsculpt_brush_do_frame(
case GP_SCULPT_TYPE_GRAB: /* Grab points */
{
- if (gps->runtime.gps_orig != NULL) {
+ bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
+ if (gps_active != NULL) {
if (gso->first) {
/* First time this brush stroke is being applied:
* 1) Prepare data buffers (init/clear) for this stroke
* 2) Use the points now under the cursor
*/
- gp_brush_grab_stroke_init(gso, gps->runtime.gps_orig);
+ gp_brush_grab_stroke_init(gso, gps_active);
changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_grab_store_points);
}
else {
/* Apply effect to the stored points */
- gp_brush_grab_apply_cached(gso, gps->runtime.gps_orig, diff_mat);
+ gp_brush_grab_apply_cached(gso, gps_active, diff_mat);
changed |= true;
}
}
@@ -1863,8 +1886,7 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
}
/* affect strokes in this frame */
- changed |= gpsculpt_brush_do_frame(
- C, gso, gpl, (gpf == gpl->actframe) ? gpf_eval : gpf, diff_mat);
+ changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpf, diff_mat);
}
}
}
@@ -2080,7 +2102,7 @@ static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *eve
ARegion *ar = CTX_wm_region(C);
/* ensure that we'll have a new frame to draw on */
- gpsculpt_brush_init_stroke(gso);
+ gpsculpt_brush_init_stroke(C, gso);
/* apply first dab... */
gso->is_painting = true;
@@ -2195,7 +2217,7 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even
gso->is_painting = true;
gso->first = true;
- gpsculpt_brush_init_stroke(gso);
+ gpsculpt_brush_init_stroke(C, gso);
gpsculpt_brush_apply_event(C, op, event);
break;
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index c22e3bda0b1..67ffc6adc9f 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -492,58 +492,53 @@ static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op)
bGPdata *gpd_src = (bGPdata *)ob_src->data;
bGPDlayer *gpl_src = BKE_gpencil_layer_getactive(gpd_src);
- /* sanity checks */
+ /* Sanity checks. */
if (ELEM(NULL, gpd_src, gpl_src, ob_dst)) {
return OPERATOR_CANCELLED;
}
- /* cannot copy itself and check destination type */
+ /* Cannot copy itself and check destination type. */
if ((ob_src == ob_dst) || (ob_dst->type != OB_GPENCIL)) {
return OPERATOR_CANCELLED;
}
bGPdata *gpd_dst = (bGPdata *)ob_dst->data;
- /* make copy of layer */
- bGPDlayer *gpl_dst = MEM_dupallocN(gpl_src);
- gpl_dst->prev = gpl_dst->next = NULL;
- BLI_addtail(&gpd_dst->layers, gpl_dst);
- BLI_uniquename(&gpd_dst->layers,
- gpl_dst,
- DATA_("GP_Layer"),
- '.',
- offsetof(bGPDlayer, info),
- sizeof(gpl_dst->info));
+ /* Create new layer. */
+ bGPDlayer *gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl_src->info, true);
+ /* Need to copy some variables (not all). */
+ gpl_dst->onion_flag = gpl_src->onion_flag;
+ gpl_dst->thickness = gpl_src->thickness;
+ gpl_dst->line_change = gpl_src->line_change;
+ copy_v4_v4(gpl_dst->tintcolor, gpl_src->tintcolor);
+ gpl_dst->opacity = gpl_src->opacity;
- /* copy frames */
- BLI_listbase_clear(&gpl_dst->frames);
+ /* Create all frames. */
for (bGPDframe *gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
if ((mode == GP_LAYER_COPY_OBJECT_ACT_FRAME) && (gpf_src != gpl_src->actframe)) {
continue;
}
- /* make a copy of source frame */
- bGPDframe *gpf_dst = MEM_dupallocN(gpf_src);
- gpf_dst->prev = gpf_dst->next = NULL;
- BLI_addtail(&gpl_dst->frames, gpf_dst);
+ /* Create new frame. */
+ bGPDframe *gpf_dst = BKE_gpencil_frame_addnew(gpl_dst, gpf_src->framenum);
- /* copy strokes */
- BLI_listbase_clear(&gpf_dst->strokes);
+ /* Copy strokes. */
for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
- /* make copy of source stroke */
+ /* Make copy of source stroke. */
bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
- /* check if material is in destination object,
- * otherwise add the slot with the material
- */
+ /* Check if material is in destination object,
+ * otherwise add the slot with the material. */
Material *ma_src = give_current_material(ob_src, gps_src->mat_nr + 1);
- int idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
+ if (ma_src != NULL) {
+ int idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
- /* Reassign the stroke material to the right slot in destination object. */
- gps_dst->mat_nr = idx;
+ /* Reassign the stroke material to the right slot in destination object. */
+ gps_dst->mat_nr = idx;
+ }
- /* add new stroke to frame */
+ /* Add new stroke to frame. */
BLI_addtail(&gpf_dst->strokes, gps_dst);
}
}
@@ -566,7 +561,7 @@ void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot)
};
/* identifiers */
- ot->name = "Duplicate Layer to new Object";
+ ot->name = "Duplicate Layer to New Object";
ot->idname = "GPENCIL_OT_layer_duplicate_object";
ot->description = "Make a copy of the active Grease Pencil layer to new object";
@@ -797,7 +792,7 @@ static int gp_frame_clean_loose_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_frame_clean_loose(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Clean Loose points";
+ ot->name = "Clean Loose Points";
ot->idname = "GPENCIL_OT_frame_clean_loose";
ot->description = "Remove loose points";
@@ -840,6 +835,10 @@ static int gp_hide_exec(bContext *C, wmOperator *op)
if (gpl != layer) {
gpl->flag |= GP_LAYER_HIDE;
}
+ else {
+ /* Be sure the active layer is unhidden. */
+ gpl->flag &= ~GP_LAYER_HIDE;
+ }
}
}
else {
@@ -1385,9 +1384,9 @@ static int gp_stroke_arrange_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_stroke_arrange(wmOperatorType *ot)
{
static const EnumPropertyItem slot_move[] = {
+ {GP_STROKE_MOVE_TOP, "TOP", 0, "Bring to Front", ""},
{GP_STROKE_MOVE_UP, "UP", 0, "Bring Forward", ""},
{GP_STROKE_MOVE_DOWN, "DOWN", 0, "Send Backward", ""},
- {GP_STROKE_MOVE_TOP, "TOP", 0, "Bring to Front", ""},
{GP_STROKE_MOVE_BOTTOM, "BOTTOM", 0, "Send to Back", ""},
{0, NULL, 0, NULL, NULL}};
@@ -1419,7 +1418,7 @@ static int gp_stroke_change_color_exec(bContext *C, wmOperator *op)
bGPdata *gpd = ED_gpencil_data_get_active(C);
Object *ob = CTX_data_active_object(C);
if (name[0] == '\0') {
- ma = give_current_material(ob, ob->actcol);
+ ma = BKE_material_gpencil_get(ob, ob->actcol);
}
else {
ma = (Material *)BKE_libblock_find_name(bmain, ID_MA, name);
@@ -1539,9 +1538,10 @@ static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op))
}
/* unlock color */
Material *tmp_ma = give_current_material(ob, gps->mat_nr + 1);
-
- tmp_ma->gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
- DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE);
+ if (tmp_ma) {
+ tmp_ma->gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
+ DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE);
+ }
}
}
}
@@ -1580,7 +1580,9 @@ void GPENCIL_OT_stroke_lock_color(wmOperatorType *ot)
/* ******************* Brush create presets ************************** */
static int gp_brush_presets_create_exec(bContext *C, wmOperator *UNUSED(op))
{
- BKE_brush_gpencil_presets(C);
+ Main *bmain = CTX_data_main(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ BKE_brush_gpencil_presets(bmain, ts);
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -2291,7 +2293,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
short *totcol = give_totcolp(ob_src);
for (short i = 0; i < *totcol; i++) {
- Material *tmp_ma = give_current_material(ob_src, i + 1);
+ Material *tmp_ma = BKE_material_gpencil_get(ob_src, i + 1);
BKE_gpencil_object_material_ensure(bmain, ob_dst, tmp_ma);
}
@@ -2325,7 +2327,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
/* Reassign material. Look old material and try to find in destination. */
- ma_src = give_current_material(ob_src, gps->mat_nr + 1);
+ ma_src = BKE_material_gpencil_get(ob_src, gps->mat_nr + 1);
gps->mat_nr = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
bGPDspoint *pt;
@@ -2433,7 +2435,7 @@ static int gpencil_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
}
for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
+ ma = BKE_material_gpencil_get(ob, i + 1);
if (ma) {
gp_style = ma->gp_style;
gp_style->flag |= GP_STYLE_COLOR_LOCKED;
@@ -2453,7 +2455,7 @@ static int gpencil_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
continue;
}
- ma = give_current_material(ob, gps->mat_nr + 1);
+ ma = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
gp_style = ma->gp_style;
@@ -2496,7 +2498,7 @@ static int gpencil_color_isolate_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
Object *ob = CTX_data_active_object(C);
- Material *active_ma = give_current_material(ob, ob->actcol);
+ Material *active_ma = BKE_material_gpencil_get(ob, ob->actcol);
MaterialGPencilStyle *active_color = BKE_material_gpencil_settings_get(ob, ob->actcol);
MaterialGPencilStyle *gp_style;
@@ -2516,7 +2518,7 @@ static int gpencil_color_isolate_exec(bContext *C, wmOperator *op)
Material *ma = NULL;
short *totcol = give_totcolp(ob);
for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
+ ma = BKE_material_gpencil_get(ob, i + 1);
/* Skip if this is the active one */
if ((ma == NULL) || (ma == active_ma)) {
continue;
@@ -2536,7 +2538,7 @@ static int gpencil_color_isolate_exec(bContext *C, wmOperator *op)
if (isolate) {
/* Set flags on all "other" colors */
for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
+ ma = BKE_material_gpencil_get(ob, i + 1);
if (ma == NULL) {
continue;
}
@@ -2553,7 +2555,7 @@ static int gpencil_color_isolate_exec(bContext *C, wmOperator *op)
else {
/* Clear flags - Restore everything else */
for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
+ ma = BKE_material_gpencil_get(ob, i + 1);
if (ma == NULL) {
continue;
}
@@ -2618,7 +2620,7 @@ static int gpencil_color_hide_exec(bContext *C, wmOperator *op)
/* hide unselected */
MaterialGPencilStyle *color = NULL;
for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
+ ma = BKE_material_gpencil_get(ob, i + 1);
if (ma) {
color = ma->gp_style;
if (active_color != color) {
@@ -2681,7 +2683,7 @@ static int gpencil_color_reveal_exec(bContext *C, wmOperator *UNUSED(op))
MaterialGPencilStyle *gp_style = NULL;
for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
+ ma = BKE_material_gpencil_get(ob, i + 1);
if (ma) {
gp_style = ma->gp_style;
gp_style->flag &= ~GP_STYLE_COLOR_HIDE;
@@ -2734,7 +2736,7 @@ static int gpencil_color_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
MaterialGPencilStyle *gp_style = NULL;
for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
+ ma = BKE_material_gpencil_get(ob, i + 1);
if (ma) {
gp_style = ma->gp_style;
gp_style->flag |= GP_STYLE_COLOR_LOCKED;
@@ -2787,7 +2789,7 @@ static int gpencil_color_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
MaterialGPencilStyle *gp_style = NULL;
for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
+ ma = BKE_material_gpencil_get(ob, i + 1);
if (ma) {
gp_style = ma->gp_style;
gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
@@ -2913,6 +2915,54 @@ void GPENCIL_OT_color_select(wmOperatorType *ot)
RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
+/* ***************** Set selected stroke material the active material ************************ */
+
+static int gpencil_set_active_material_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bool changed = false;
+
+ /* Sanity checks. */
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Loop all selected strokes. */
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* Change Active material. */
+ ob->actcol = gps->mat_nr + 1;
+ changed = true;
+ break;
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+
+ /* notifiers */
+ if (changed) {
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_set_active_material(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set active material";
+ ot->idname = "GPENCIL_OT_set_active_material";
+ ot->description = "Set the selected stroke material as the active material";
+
+ /* callbacks */
+ ot->exec = gpencil_set_active_material_exec;
+ ot->poll = gpencil_active_color_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* Parent GPencil object to Lattice */
bool ED_gpencil_add_lattice_modifier(const bContext *C,
ReportList *reports,
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 9fd1d031bb1..c4f18c60f4d 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -237,11 +237,38 @@ static int gpencil_selectmode_toggle_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
const int mode = RNA_int_get(op->ptr, "mode");
+ bool changed = false;
+
+ if (ts->gpencil_selectmode_edit == mode) {
+ return OPERATOR_FINISHED;
+ }
/* Just set mode */
ts->gpencil_selectmode_edit = mode;
+ /* If the mode is Stroke, extend selection. */
+ if ((ob) && (ts->gpencil_selectmode_edit == GP_SELECTMODE_STROKE)) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ /* Extend selection to all points in all selected strokes. */
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ if ((gps->flag & GP_STROKE_SELECT) && (gps->totpoints > 1)) {
+ changed = true;
+ bGPDspoint *pt;
+ for (int i = 0; i < gps->totpoints; i++) {
+ pt = &gps->points[i];
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ }
+ }
+ CTX_DATA_END;
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ }
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
@@ -328,7 +355,7 @@ static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op)
Paint *paint = &ts->gp_paint->paint;
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
- BKE_brush_gpencil_presets(C);
+ BKE_brush_gpencil_presets(bmain, ts);
}
BKE_paint_toolslots_brush_validate(bmain, &ts->gp_paint->paint);
}
@@ -1191,10 +1218,15 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
GHash *ma_to_name = gp_strokes_copypastebuf_colors_material_to_name_create(bmain);
for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
if (ED_gpencil_stroke_can_use(C, gps)) {
+ Material *ma = give_current_material(ob, gps->mat_nr + 1);
+ /* Avoid default material. */
+ if (ma == NULL) {
+ continue;
+ }
+
char **ma_name_val;
if (!BLI_ghash_ensure_p(
gp_strokes_copypastebuf_colors, &gps->mat_nr, (void ***)&ma_name_val)) {
- Material *ma = give_current_material(ob, gps->mat_nr + 1);
char *ma_name = BLI_ghash_lookup(ma_to_name, ma);
*ma_name_val = MEM_dupallocN(ma_name);
}
@@ -1241,8 +1273,8 @@ static bool gp_strokes_paste_poll(bContext *C)
}
typedef enum eGP_PasteMode {
- GP_COPY_ONLY = -1,
- GP_COPY_MERGE = 1,
+ GP_COPY_BY_LAYER = -1,
+ GP_COPY_TO_ACTIVE = 1,
} eGP_PasteMode;
static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
@@ -1275,7 +1307,7 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
/* no active layer - let's just create one */
gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
}
- else if ((gpencil_layer_is_editable(gpl) == false) && (type == GP_COPY_MERGE)) {
+ else if ((gpencil_layer_is_editable(gpl) == false) && (type == GP_COPY_TO_ACTIVE)) {
BKE_report(
op->reports, RPT_ERROR, "Can not paste strokes when active layer is hidden or locked");
return OPERATOR_CANCELLED;
@@ -1328,7 +1360,7 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
if (ED_gpencil_stroke_can_use(C, gps)) {
/* Need to verify if layer exists */
- if (type != GP_COPY_MERGE) {
+ if (type != GP_COPY_TO_ACTIVE) {
gpl = BLI_findstring(&gpd->layers, gps->runtime.tmp_layerinfo, offsetof(bGPDlayer, info));
if (gpl == NULL) {
/* no layer - use active (only if layer deleted before paste) */
@@ -1361,7 +1393,7 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
/* Remap material */
Material *ma = BLI_ghash_lookup(new_colors, POINTER_FROM_INT(new_stroke->mat_nr));
new_stroke->mat_nr = BKE_gpencil_object_material_get_index(ob, ma);
- BLI_assert(new_stroke->mat_nr >= 0); /* have to add the material first */
+ CLAMP_MIN(new_stroke->mat_nr, 0);
}
}
}
@@ -1379,15 +1411,15 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_paste(wmOperatorType *ot)
{
static const EnumPropertyItem copy_type[] = {
- {GP_COPY_ONLY, "COPY", 0, "Copy", ""},
- {GP_COPY_MERGE, "MERGE", 0, "Merge", ""},
+ {GP_COPY_TO_ACTIVE, "ACTIVE", 0, "Paste to Active", ""},
+ {GP_COPY_BY_LAYER, "LAYER", 0, "Paste by Layer", ""},
{0, NULL, 0, NULL, NULL},
};
/* identifiers */
ot->name = "Paste Strokes";
ot->idname = "GPENCIL_OT_paste";
- ot->description = "Paste previously copied strokes or copy and merge in active layer";
+ ot->description = "Paste previously copied strokes to active layer or to original layer";
/* callbacks */
ot->exec = gp_strokes_paste_exec;
@@ -1397,33 +1429,18 @@ void GPENCIL_OT_paste(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", copy_type, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", copy_type, GP_COPY_TO_ACTIVE, "Type", "");
}
/* ******************* Move To Layer ****************************** */
-static int gp_move_to_layer_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
-{
- uiPopupMenu *pup;
- uiLayout *layout;
-
- /* call the menu, which will call this operator again, hence the canceled */
- pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
- layout = UI_popup_menu_layout(pup);
- uiItemsEnumO(layout, "GPENCIL_OT_move_to_layer", "layer");
- UI_popup_menu_end(C, pup);
-
- return OPERATOR_INTERFACE;
-}
-
-// FIXME: allow moving partial strokes
static int gp_move_to_layer_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = CTX_data_gpencil_data(C);
Scene *scene = CTX_data_scene(C);
bGPDlayer *target_layer = NULL;
ListBase strokes = {NULL, NULL};
- int layer_num = RNA_enum_get(op->ptr, "layer");
+ int layer_num = RNA_int_get(op->ptr, "layer");
const bool use_autolock = (bool)(gpd->flag & GP_DATA_AUTOLOCK_LAYERS);
if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
@@ -1436,23 +1453,16 @@ static int gp_move_to_layer_exec(bContext *C, wmOperator *op)
gpd->flag &= ~GP_DATA_AUTOLOCK_LAYERS;
}
- /* Get layer or create new one */
- if (layer_num == -1) {
- /* Create layer */
- target_layer = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
- }
- else {
- /* Try to get layer */
- target_layer = BLI_findlink(&gpd->layers, layer_num);
+ /* Try to get layer */
+ target_layer = BLI_findlink(&gpd->layers, layer_num);
- if (target_layer == NULL) {
- /* back autolock status */
- if (use_autolock) {
- gpd->flag |= GP_DATA_AUTOLOCK_LAYERS;
- }
- BKE_reportf(op->reports, RPT_ERROR, "There is no layer number %d", layer_num);
- return OPERATOR_CANCELLED;
+ if (target_layer == NULL) {
+ /* back autolock status */
+ if (use_autolock) {
+ gpd->flag |= GP_DATA_AUTOLOCK_LAYERS;
}
+ BKE_reportf(op->reports, RPT_ERROR, "There is no layer number %d", layer_num);
+ return OPERATOR_CANCELLED;
}
/* Extract all strokes to move to this layer
@@ -1520,16 +1530,14 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot)
"Move selected strokes to another layer"; // XXX: allow moving individual points too?
/* callbacks */
- ot->invoke = gp_move_to_layer_invoke;
ot->exec = gp_move_to_layer_exec;
ot->poll = gp_stroke_edit_poll; // XXX?
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* gp layer to use (dynamic enum) */
- ot->prop = RNA_def_enum(ot->srna, "layer", DummyRNA_DEFAULT_items, 0, "Grease Pencil Layer", "");
- RNA_def_enum_funcs(ot->prop, ED_gpencil_layers_with_new_enum_itemf);
+ /* GPencil layer to use. */
+ ot->prop = RNA_def_int(ot->srna, "layer", 0, 0, INT_MAX, "Grease Pencil Layer", "", 0, INT_MAX);
}
/* ********************* Add Blank Frame *************************** */
@@ -3040,7 +3048,7 @@ static void gpencil_flip_stroke(bGPDstroke *gps)
static void gpencil_stroke_copy_point(bGPDstroke *gps,
bGPDspoint *point,
int idx,
- float delta[3],
+ const float delta[3],
float pressure,
float strength,
float deltatime)
@@ -4092,7 +4100,7 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
/* add duplicate materials */
/* XXX same material can be in multiple slots. */
- ma = give_current_material(ob, gps->mat_nr + 1);
+ ma = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma);
@@ -4165,7 +4173,7 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
}
- ma = give_current_material(ob, gps->mat_nr + 1);
+ ma = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
gps->mat_nr = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma);
}
}
@@ -4508,6 +4516,10 @@ static int gpencil_cutter_lasso_select(bContext *C,
/* dissolve selected points */
bGPDstroke *gpsn;
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl->flag & GP_LAYER_LOCKED) {
+ continue;
+ }
+
bGPDframe *gpf = gpl->actframe;
if (gpf == NULL) {
continue;
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index 5637e755198..993ec15248f 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -48,6 +48,7 @@
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_paint.h"
+#include "BKE_report.h"
#include "ED_gpencil.h"
#include "ED_screen.h"
@@ -61,7 +62,6 @@
#include "IMB_imbuf_types.h"
#include "GPU_immediate.h"
-#include "GPU_draw.h"
#include "GPU_matrix.h"
#include "GPU_framebuffer.h"
#include "GPU_state.h"
@@ -1038,7 +1038,15 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
gps->flag |= GP_STROKE_CYCLIC;
gps->flag |= GP_STROKE_3DSPACE;
- gps->mat_nr = BKE_gpencil_object_material_ensure(tgpf->bmain, tgpf->ob, tgpf->mat);
+ gps->mat_nr = BKE_gpencil_object_material_get_index_from_brush(tgpf->ob, brush);
+ if (gps->mat_nr < 0) {
+ if (tgpf->ob->actcol - 1 < 0) {
+ gps->mat_nr = 0;
+ }
+ else {
+ gps->mat_nr = tgpf->ob->actcol - 1;
+ }
+ }
/* allocate memory for storage points */
gps->totpoints = tgpf->sbuffer_used;
@@ -1346,8 +1354,28 @@ static int gpencil_fill_init(bContext *C, wmOperator *op)
/* start of interactive part of operator */
static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
+ Object *ob = CTX_data_active_object(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
tGPDfill *tgpf = NULL;
+ /* Fill tool needs a material (cannot use default material) */
+ bool valid = true;
+ if ((brush) && (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED)) {
+ if (brush->gpencil_settings->material == NULL) {
+ valid = false;
+ }
+ }
+ else {
+ if (give_current_material(ob, ob->actcol) == NULL) {
+ valid = false;
+ }
+ }
+ if (!valid) {
+ BKE_report(op->reports, RPT_ERROR, "Fill tool needs active material.");
+ return OPERATOR_CANCELLED;
+ }
+
/* try to initialize context data needed */
if (!gpencil_fill_init(C, op)) {
gpencil_fill_exit(C, op);
@@ -1366,7 +1394,7 @@ static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
tgpf->ar->type, gpencil_fill_draw_3d, tgpf, REGION_DRAW_POST_VIEW);
}
- WM_cursor_modal_set(CTX_wm_window(C), BC_PAINTBRUSHCURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_PAINT_BRUSH);
gpencil_fill_status_indicators(C, tgpf);
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index c2a9eae272f..a8f8ec0e8c5 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -528,6 +528,7 @@ void GPENCIL_OT_color_reveal(struct wmOperatorType *ot);
void GPENCIL_OT_color_lock_all(struct wmOperatorType *ot);
void GPENCIL_OT_color_unlock_all(struct wmOperatorType *ot);
void GPENCIL_OT_color_select(struct wmOperatorType *ot);
+void GPENCIL_OT_set_active_material(struct wmOperatorType *ot);
/* convert old 2.7 files to 2.8 */
void GPENCIL_OT_convert_old_files(struct wmOperatorType *ot);
@@ -669,7 +670,9 @@ struct GP_EditableStrokes_Iter {
ED_gpencil_parent_location(depsgraph_, obact_, gpd_, gpl, gpstroke_iter.diff_mat); \
invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \
/* get evaluated frame with modifiers applied */ \
- bGPDframe *gpf_eval_ = &obeval_->runtime.gpencil_evaluated_frames[idx_eval]; \
+ bGPDframe *gpf_eval_ = (!is_multiedit_) ? \
+ &obeval_->runtime.gpencil_evaluated_frames[idx_eval] : \
+ gpf_; \
/* loop over strokes */ \
for (bGPDstroke *gps = gpf_eval_->strokes.first; gps; gps = gps->next) { \
/* skip strokes that are invalid for current view */ \
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index 86de9a75a56..1438c33a972 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -560,7 +560,7 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent
tgpi->ar->type, gpencil_interpolate_draw_3d, tgpi, REGION_DRAW_POST_VIEW);
/* set cursor to indicate modal */
- WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_EW_SCROLL);
/* update shift indicator in header */
gpencil_interpolate_status_indicators(C, tgpi);
diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c
index cb11bb4cd63..36cef3ccdc0 100644
--- a/source/blender/editors/gpencil/gpencil_merge.c
+++ b/source/blender/editors/gpencil/gpencil_merge.c
@@ -35,6 +35,7 @@
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_gpencil.h"
+#include "BKE_main.h"
#include "BKE_material.h"
#include "WM_api.h"
@@ -97,6 +98,7 @@ static void gpencil_insert_points_to_stroke(bGPDstroke *gps,
static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpoints)
{
+ Main *bmain = CTX_data_main(C);
ToolSettings *ts = CTX_data_tool_settings(C);
Object *ob = CTX_data_active_object(C);
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
@@ -111,7 +113,7 @@ static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpo
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
/* create new brushes */
- BKE_brush_gpencil_presets(C);
+ BKE_brush_gpencil_presets(bmain, ts);
}
Brush *brush = paint->brush;
@@ -449,7 +451,7 @@ static bool gp_strokes_merge_poll(bContext *C)
/* check material */
Material *ma = NULL;
- ma = give_current_material(ob, ob->actcol);
+ ma = BKE_material_gpencil_get(ob, ob->actcol);
if ((ma == NULL) || (ma->gp_style == NULL)) {
return false;
}
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index acdf5c2be4f..ce410f3e52d 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -264,6 +264,8 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_move_to_layer);
WM_operatortype_append(GPENCIL_OT_layer_change);
+ WM_operatortype_append(GPENCIL_OT_set_active_material);
+
WM_operatortype_append(GPENCIL_OT_snap_to_grid);
WM_operatortype_append(GPENCIL_OT_snap_to_cursor);
WM_operatortype_append(GPENCIL_OT_snap_cursor_to_selected);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 900883bd0af..f29e782c618 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -113,6 +113,28 @@ typedef enum eGPencil_PaintFlags {
GP_PAINTFLAG_REQ_VECTOR = (1 << 6),
} eGPencil_PaintFlags;
+/* Temporary Guide data */
+typedef struct tGPguide {
+ /** guide spacing */
+ float spacing;
+ /** half guide spacing */
+ float half_spacing;
+ /** origin */
+ float origin[2];
+ /** rotated point */
+ float rot_point[2];
+ /** rotated point */
+ float rot_angle;
+ /** initial stroke direction */
+ float stroke_angle;
+ /** initial origin direction */
+ float origin_angle;
+ /** initial origin distance */
+ float origin_distance;
+ /** initial line for guides */
+ float unit[2];
+} tGPguide;
+
/* Temporary 'Stroke' Operation data
* "p" = op->customdata
*/
@@ -224,12 +246,7 @@ typedef struct tGPsdata {
float totpixlen;
/* guide */
- /** guide spacing */
- float guide_spacing;
- /** half guide spacing */
- float half_spacing;
- /** origin */
- float origin[2];
+ tGPguide guide;
ReportList *reports;
} tGPsdata;
@@ -581,6 +598,7 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
float sco[2] = {0.0f};
float a[2], b[2], c[2], d[2];
float pressure = 0.0f;
+ float strength = 0.0f;
const float average_fac = 1.0f / steps;
/* Compute smoothed coordinate by taking the ones nearby */
@@ -588,21 +606,25 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
copy_v2_v2(a, &pta->x);
madd_v2_v2fl(sco, a, average_fac);
pressure += pta->pressure * average_fac;
+ strength += pta->strength * average_fac;
}
if (ptb) {
copy_v2_v2(b, &ptb->x);
madd_v2_v2fl(sco, b, average_fac);
pressure += ptb->pressure * average_fac;
+ strength += ptb->strength * average_fac;
}
if (ptc) {
copy_v2_v2(c, &ptc->x);
madd_v2_v2fl(sco, c, average_fac);
pressure += ptc->pressure * average_fac;
+ strength += ptc->strength * average_fac;
}
if (ptd) {
copy_v2_v2(d, &ptd->x);
madd_v2_v2fl(sco, d, average_fac);
pressure += ptd->pressure * average_fac;
+ strength += ptd->strength * average_fac;
}
/* Based on influence factor, blend between original and optimal smoothed coordinate. */
@@ -610,10 +632,156 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
copy_v2_v2(&ptc->x, c);
/* Interpolate pressure. */
ptc->pressure = interpf(ptc->pressure, pressure, inf);
+ /* Interpolate strength. */
+ ptc->strength = interpf(ptc->strength, strength, inf);
+}
+
+/* Helper: Apply smooth to segment from Index to Index */
+static void gp_smooth_segment(bGPdata *gpd, const float inf, int from_idx, int to_idx)
+{
+ const short num_points = to_idx - from_idx;
+ /* Do nothing if not enough points to smooth out */
+ if ((num_points < 3) || (inf == 0.0f)) {
+ return;
+ }
+
+ if (from_idx <= 2) {
+ return;
+ }
+
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ const float average_fac = 0.25f;
+
+ for (int i = from_idx; i < to_idx + 1; i++) {
+
+ tGPspoint *pta = i >= 3 ? &points[i - 3] : NULL;
+ tGPspoint *ptb = i >= 2 ? &points[i - 2] : NULL;
+ tGPspoint *ptc = i >= 1 ? &points[i - 1] : &points[i];
+ tGPspoint *ptd = &points[i];
+
+ float sco[2] = {0.0f};
+
+ /* Compute smoothed coordinate by taking the ones nearby */
+ if (pta) {
+ madd_v2_v2fl(sco, &pta->x, average_fac);
+ }
+ else {
+ madd_v2_v2fl(sco, &ptc->x, average_fac);
+ }
+
+ if (ptb) {
+ madd_v2_v2fl(sco, &ptb->x, average_fac);
+ }
+ else {
+ madd_v2_v2fl(sco, &ptc->x, average_fac);
+ }
+
+ madd_v2_v2fl(sco, &ptc->x, average_fac);
+
+ madd_v2_v2fl(sco, &ptd->x, average_fac);
+
+ /* Based on influence factor, blend between original and optimal smoothed coordinate. */
+ interp_v2_v2v2(&ptc->x, &ptc->x, sco, inf);
+ }
+}
+
+/* Smooth all the sections created with fake events to avoid abrupt transitions.
+ *
+ * As the fake events add points between two real events, this produces a straight line, but if
+ * there is 3 or more real points that used fakes, the stroke is not smooth and produces abrupt
+ * angles.
+ * This function reads these segments and finds the real points and smooth with the surrounding
+ * points. */
+static void gp_smooth_fake_segments(tGPsdata *p)
+{
+ bGPdata *gpd = p->gpd;
+ Brush *brush = p->brush;
+
+ if (brush->gpencil_settings->input_samples < 2) {
+ return;
+ }
+
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ tGPspoint *pt = NULL;
+ /* Index where segment starts. */
+ int from_idx = 0;
+ /* Index where segment ends. */
+ int to_idx = 0;
+
+ bool doit = false;
+ /* Loop all points except the extremes. */
+ for (int i = 1; i < gpd->runtime.sbuffer_used - 1; i++) {
+ pt = &points[i];
+ bool is_fake = (bool)(pt->tflag & GP_TPOINT_FAKE);
+ to_idx = i;
+
+ /* Detect fake points in the stroke. */
+ if ((!doit) && (is_fake)) {
+ from_idx = i;
+ doit = true;
+ }
+ /* If detect control point after fake points, select a segment with same length in both sides,
+ * except if it is more than stroke length. */
+ if ((doit) && (!is_fake)) {
+ if (i + (i - from_idx) < gpd->runtime.sbuffer_used - 1) {
+ to_idx = i + (i - from_idx);
+ /* Smooth this segments (need loop to get cumulative smooth). */
+ for (int r = 0; r < 5; r++) {
+ gp_smooth_segment(gpd, 0.1f, from_idx, to_idx);
+ }
+ }
+ else {
+ break;
+ }
+ /* Reset to new segments. */
+ from_idx = i;
+ doit = false;
+ }
+ }
+}
+
+/* Smooth the section added with fake events when pen moves very fast. */
+static void gp_smooth_fake_events(tGPsdata *p, int size_before, int size_after)
+{
+ bGPdata *gpd = p->gpd;
+ const short totpoints = size_after - size_before - 1;
+ /* Do nothing if not enough data to smooth out. */
+ if (totpoints < 1) {
+ return;
+ }
+
+ /* Back two points to get smoother effect. */
+ size_before -= 2;
+ CLAMP_MIN(size_before, 1);
+
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ /* Extreme points. */
+ const tGPspoint *pta = &points[size_before - 1];
+ const tGPspoint *ptb = &points[size_after - 1];
+ tGPspoint *pt1, *pt2;
+ int i;
+
+ /* Get total length of the segment to smooth. */
+ float totlen = 0.0f;
+ for (i = size_before; i < size_after; i++) {
+ pt1 = &points[i - 1];
+ pt2 = &points[i];
+ totlen += len_v2v2(&pt1->x, &pt2->x);
+ }
+ /* Smooth interpolating the position of the points. */
+ float pointlen = 0.0f;
+ for (i = size_before; i < size_after - 1; i++) {
+ pt1 = &points[i - 1];
+ pt2 = &points[i];
+ pointlen += len_v2v2(&pt1->x, &pt2->x);
+ pt2->pressure = interpf(ptb->pressure, pta->pressure, pointlen / totlen);
+ pt2->strength = interpf(ptb->strength, pta->strength, pointlen / totlen);
+ }
}
/* add current stroke-point to buffer (returns whether point was successfully added) */
-static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure, double curtime)
+static short gp_stroke_addpoint(
+ tGPsdata *p, const float mval[2], float pressure, double curtime, bool is_fake)
{
bGPdata *gpd = p->gpd;
Brush *brush = p->brush;
@@ -672,6 +840,14 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
/* get pointer to destination point */
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_used);
+ /* Set if point was created by fake events. */
+ if (is_fake) {
+ pt->tflag |= GP_TPOINT_FAKE;
+ }
+ else {
+ pt->tflag &= ~GP_TPOINT_FAKE;
+ }
+
/* store settings */
/* pressure */
if (brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE) {
@@ -829,7 +1005,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
bGPDspoint *pts;
MDeformVert *dvert = NULL;
- /* first time point is adding to temporary buffer -- need to allocate new point in stroke */
+ /* First time point is adding to temporary buffer (need to allocate new point in stroke) */
if (gpd->runtime.sbuffer_used == 0) {
gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
if (gps->dvert != NULL) {
@@ -920,6 +1096,22 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
(!is_depth);
int i, totelem;
+ /* For very low pressure at the end, truncate stroke. */
+ if (p->paintmode == GP_PAINTMODE_DRAW) {
+ int last_i = gpd->runtime.sbuffer_used - 1;
+ while (last_i > 0) {
+ ptc = (tGPspoint *)gpd->runtime.sbuffer + last_i;
+ if (ptc->pressure > 0.001f) {
+ break;
+ }
+ else {
+ gpd->runtime.sbuffer_used = last_i - 1;
+ CLAMP_MIN(gpd->runtime.sbuffer_used, 1);
+ }
+
+ last_i--;
+ }
+ }
/* Since strokes are so fine,
* when using their depth we need a margin otherwise they might get missed. */
int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
@@ -1170,6 +1362,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
}
}
+ /* Smooth any point created with fake events when the mouse/pen move very fast. */
+ gp_smooth_fake_segments(p);
+
pt = gps->points;
dvert = gps->dvert;
@@ -1218,6 +1413,13 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
reduce += 0.25f; /* reduce the factor */
}
}
+
+ /* Simplify adaptive */
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
+ (brush->gpencil_settings->simplify_f > 0.0f)) {
+ BKE_gpencil_simplify_stroke(gps, brush->gpencil_settings->simplify_f);
+ }
+
/* smooth thickness */
if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
(brush->gpencil_settings->thick_smoothfac > 0.0f)) {
@@ -1244,6 +1446,14 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* Save material index */
gps->mat_nr = BKE_gpencil_object_material_get_index_from_brush(p->ob, p->brush);
+ if (gps->mat_nr < 0) {
+ if (p->ob->actcol - 1 < 0) {
+ gps->mat_nr = 0;
+ }
+ else {
+ gps->mat_nr = p->ob->actcol - 1;
+ }
+ }
/* calculate UVs along the stroke */
ED_gpencil_calc_stroke_uv(obact, gps);
@@ -1802,6 +2012,7 @@ static void gp_set_default_eraser(Main *bmain, Brush *brush_dft)
/* initialize a drawing brush */
static void gp_init_drawing_brush(bContext *C, tGPsdata *p)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = CTX_data_tool_settings(C);
@@ -1810,7 +2021,7 @@ static void gp_init_drawing_brush(bContext *C, tGPsdata *p)
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
/* create new brushes */
- BKE_brush_gpencil_presets(C);
+ BKE_brush_gpencil_presets(bmain, ts);
changed = true;
}
/* be sure curves are initializated */
@@ -2457,10 +2668,10 @@ static void gpencil_draw_cursor_set(tGPsdata *p)
#if 0
Brush *brush = p->brush;
if ((p->paintmode == GP_PAINTMODE_ERASER) || (brush->gpencil_tool == GPAINT_TOOL_ERASE)) {
- WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */
+ WM_cursor_modal_set(p->win, WM_CURSOR_CROSS); /* XXX need a better cursor */
}
else {
- WM_cursor_modal_set(p->win, CURSOR_NONE);
+ WM_cursor_modal_set(p->win, WM_CURSOR_NONE);
}
#endif
}
@@ -2537,7 +2748,8 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
/* ------------------------------- */
/* create a new stroke point at the point indicated by the painting context */
-static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgraph *depsgraph)
+static void gpencil_draw_apply(
+ bContext *C, wmOperator *op, tGPsdata *p, Depsgraph *depsgraph, bool is_fake)
{
bGPdata *gpd = p->gpd;
tGPspoint *pt = NULL;
@@ -2566,7 +2778,7 @@ static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgra
}
/* try to add point */
- short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
+ short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime, is_fake);
/* handle errors while adding point */
if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) {
@@ -2580,12 +2792,12 @@ static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgra
/* XXX We only need to reuse previous point if overflow! */
if (ok == GP_STROKEADD_OVERFLOW) {
p->inittime = p->ocurtime;
- gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime);
+ gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime, is_fake);
}
else {
p->inittime = p->curtime;
}
- gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
+ gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime, is_fake);
}
else if (ok == GP_STROKEADD_INVALID) {
/* the painting operation cannot continue... */
@@ -2634,19 +2846,26 @@ static void gp_rotate_v2_v2v2fl(float v[2],
static float gp_snap_to_grid_fl(float v, const float offset, const float spacing)
{
if (spacing > 0.0f) {
- return roundf(v / spacing) * spacing + fmodf(offset, spacing);
+ v -= spacing * 0.5f;
+ v -= offset;
+ v = roundf((v + spacing * 0.5f) / spacing) * spacing;
+ v += offset;
+ return v;
}
else {
return v;
}
}
-static void UNUSED_FUNCTION(gp_snap_to_grid_v2)(float v[2],
- const float offset[2],
- const float spacing)
+/* Helper to snap value to grid */
+static void gp_snap_to_rotated_grid_fl(float v[2],
+ const float origin[2],
+ const float spacing,
+ const float angle)
{
- v[0] = gp_snap_to_grid_fl(v[0], offset[0], spacing);
- v[1] = gp_snap_to_grid_fl(v[1], offset[1], spacing);
+ gp_rotate_v2_v2v2fl(v, v, origin, -angle);
+ v[1] = gp_snap_to_grid_fl(v[1], origin[1], spacing);
+ gp_rotate_v2_v2v2fl(v, v, origin, angle);
}
/* get reference point - screen coords to buffer coords */
@@ -2684,9 +2903,113 @@ static void gp_origin_get(tGPsdata *p, float origin[2])
gp_point_3d_to_xy(gsc, p->gpd->runtime.sbuffer_sflag, location, origin);
}
+/* speed guide initial values */
+static void gpencil_speed_guide_init(tGPsdata *p, GP_Sculpt_Guide *guide)
+{
+ /* calculate initial guide values */
+ RegionView3D *rv3d = p->ar->regiondata;
+ float scale = 1.0f;
+ if (rv3d->is_persp) {
+ float vec[3];
+ gp_get_3d_reference(p, vec);
+ mul_m4_v3(rv3d->persmat, vec);
+ scale = vec[2] * rv3d->pixsize;
+ }
+ else {
+ scale = rv3d->pixsize;
+ }
+ p->guide.spacing = guide->spacing / scale;
+ p->guide.half_spacing = p->guide.spacing * 0.5f;
+ gp_origin_get(p, p->guide.origin);
+
+ /* reference for angled snap */
+ copy_v2_v2(p->guide.unit, p->mvali);
+ p->guide.unit[0] += 1.0f;
+
+ float xy[2];
+ sub_v2_v2v2(xy, p->mvali, p->guide.origin);
+ p->guide.origin_angle = atan2f(xy[1], xy[0]) + (M_PI * 2.0f);
+
+ p->guide.origin_distance = len_v2v2(p->mvali, p->guide.origin);
+ if (guide->use_snapping && (guide->spacing > 0.0f)) {
+ p->guide.origin_distance = gp_snap_to_grid_fl(
+ p->guide.origin_distance, 0.0f, p->guide.spacing);
+ }
+
+ if (ELEM(guide->type, GP_GUIDE_RADIAL)) {
+ float angle;
+ float half_angle = guide->angle_snap * 0.5f;
+ angle = p->guide.origin_angle + guide->angle;
+ angle = fmodf(angle + half_angle, guide->angle_snap);
+ angle -= half_angle;
+ gp_rotate_v2_v2v2fl(p->guide.rot_point, p->mvali, p->guide.origin, -angle);
+ }
+ else {
+ gp_rotate_v2_v2v2fl(p->guide.rot_point, p->guide.unit, p->mvali, guide->angle);
+ }
+}
+
+/* apply speed guide */
+static void gpencil_speed_guide(tGPsdata *p, GP_Sculpt_Guide *guide)
+{
+ switch (guide->type) {
+ default:
+ case GP_GUIDE_CIRCULAR: {
+ dist_ensure_v2_v2fl(p->mval, p->guide.origin, p->guide.origin_distance);
+ break;
+ }
+ case GP_GUIDE_RADIAL: {
+ if (guide->use_snapping && (guide->angle_snap > 0.0f)) {
+ closest_to_line_v2(p->mval, p->mval, p->guide.rot_point, p->guide.origin);
+ }
+ else {
+ closest_to_line_v2(p->mval, p->mval, p->mvali, p->guide.origin);
+ }
+ break;
+ }
+ case GP_GUIDE_PARALLEL: {
+ closest_to_line_v2(p->mval, p->mval, p->mvali, p->guide.rot_point);
+ if (guide->use_snapping && (guide->spacing > 0.0f)) {
+ gp_snap_to_rotated_grid_fl(p->mval, p->guide.origin, p->guide.spacing, guide->angle);
+ }
+ break;
+ }
+ case GP_GUIDE_ISO: {
+ closest_to_line_v2(p->mval, p->mval, p->mvali, p->guide.rot_point);
+ if (guide->use_snapping && (guide->spacing > 0.0f)) {
+ gp_snap_to_rotated_grid_fl(p->mval, p->guide.origin, p->guide.spacing, p->guide.rot_angle);
+ }
+ break;
+ }
+ case GP_GUIDE_GRID: {
+ if (guide->use_snapping && (guide->spacing > 0.0f)) {
+ closest_to_line_v2(p->mval, p->mval, p->mvali, p->guide.rot_point);
+ if (p->straight == STROKE_HORIZONTAL) {
+ p->mval[1] = gp_snap_to_grid_fl(p->mval[1], p->guide.origin[1], p->guide.spacing);
+ }
+ else {
+ p->mval[0] = gp_snap_to_grid_fl(p->mval[0], p->guide.origin[0], p->guide.spacing);
+ }
+ }
+ else if (p->straight == STROKE_HORIZONTAL) {
+ p->mval[1] = p->mvali[1]; /* replace y */
+ }
+ else {
+ p->mval[0] = p->mvali[0]; /* replace x */
+ }
+ break;
+ }
+ }
+}
+
/* handle draw event */
-static void gpencil_draw_apply_event(
- bContext *C, wmOperator *op, const wmEvent *event, Depsgraph *depsgraph, float x, float y)
+static void gpencil_draw_apply_event(bContext *C,
+ wmOperator *op,
+ const wmEvent *event,
+ Depsgraph *depsgraph,
+ float x,
+ float y,
+ const bool is_fake)
{
tGPsdata *p = op->customdata;
GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
@@ -2718,6 +3041,10 @@ static void gpencil_draw_apply_event(
p->straight = STROKE_VERTICAL;
}
}
+ /* reset if a stroke angle is required */
+ if ((p->flags & GP_PAINTFLAG_REQ_VECTOR) && ((dx == 0) || (dy == 0))) {
+ p->straight = 0;
+ }
}
}
@@ -2765,6 +3092,14 @@ static void gpencil_draw_apply_event(
/* special exception for start of strokes (i.e. maybe for just a dot) */
if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
+
+ /* special exception here for too high pressure values on first touch in
+ * windows for some tablets, then we just skip first touch...
+ */
+ if (tablet && (p->pressure >= 0.99f)) {
+ return;
+ }
+
p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
/* set values */
@@ -2776,55 +3111,61 @@ static void gpencil_draw_apply_event(
/* save initial mouse */
copy_v2_v2(p->mvali, p->mval);
- /* calculate once and store snapping distance and origin */
- RegionView3D *rv3d = p->ar->regiondata;
- float scale = 1.0f;
- if (rv3d->is_persp) {
- float vec[3];
- gp_get_3d_reference(p, vec);
- mul_m4_v3(rv3d->persmat, vec);
- scale = vec[2] * rv3d->pixsize;
- }
- else {
- scale = rv3d->pixsize;
- }
- p->guide_spacing = guide->spacing / scale;
- p->half_spacing = p->guide_spacing * 0.5f;
- gp_origin_get(p, p->origin);
-
- /* special exception here for too high pressure values on first touch in
- * windows for some tablets, then we just skip first touch...
- */
- if (tablet && (p->pressure >= 0.99f)) {
- return;
+ if (is_speed_guide && !ELEM(p->paintmode, GP_PAINTMODE_ERASER, GP_PAINTMODE_SET_CP) &&
+ ((guide->use_snapping && (guide->type == GP_GUIDE_GRID)) ||
+ (guide->type == GP_GUIDE_ISO))) {
+ p->flags |= GP_PAINTFLAG_REQ_VECTOR;
}
- /* special exception for grid snapping
- * it requires direction which needs at least two points
- */
- if (!ELEM(p->paintmode, GP_PAINTMODE_ERASER, GP_PAINTMODE_SET_CP) && is_speed_guide &&
- guide->use_snapping && (guide->type == GP_GUIDE_GRID)) {
- p->flags |= GP_PAINTFLAG_REQ_VECTOR;
+ /* calculate initial guide values */
+ if (is_speed_guide) {
+ gpencil_speed_guide_init(p, guide);
}
}
/* wait for vector then add initial point */
- if (p->flags & GP_PAINTFLAG_REQ_VECTOR) {
+ if (is_speed_guide && p->flags & GP_PAINTFLAG_REQ_VECTOR) {
if (p->straight == 0) {
return;
}
p->flags &= ~GP_PAINTFLAG_REQ_VECTOR;
+ /* get initial point */
+ float pt[2];
+ sub_v2_v2v2(pt, p->mval, p->mvali);
+
+ /* get stroke angle for grids */
+ if (ELEM(guide->type, GP_GUIDE_ISO)) {
+ p->guide.stroke_angle = atan2f(pt[1], pt[0]);
+ /* determine iso angle, less weight is given for vertical strokes */
+ if (((p->guide.stroke_angle >= 0.0f) && (p->guide.stroke_angle < DEG2RAD(75))) ||
+ (p->guide.stroke_angle < DEG2RAD(-105))) {
+ p->guide.rot_angle = guide->angle;
+ }
+ else if (((p->guide.stroke_angle < 0.0f) && (p->guide.stroke_angle > DEG2RAD(-75))) ||
+ (p->guide.stroke_angle > DEG2RAD(105))) {
+ p->guide.rot_angle = -guide->angle;
+ }
+ else {
+ p->guide.rot_angle = DEG2RAD(90);
+ }
+ gp_rotate_v2_v2v2fl(p->guide.rot_point, p->guide.unit, p->mvali, p->guide.rot_angle);
+ }
+ else if (ELEM(guide->type, GP_GUIDE_GRID)) {
+ gp_rotate_v2_v2v2fl(p->guide.rot_point,
+ p->guide.unit,
+ p->mvali,
+ (p->straight == STROKE_VERTICAL) ? M_PI_2 : 0.0f);
+ }
+
/* create fake events */
float tmp[2];
- float pt[2];
copy_v2_v2(tmp, p->mval);
- sub_v2_v2v2(pt, p->mval, p->mvali);
- gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]);
+ gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], false);
if (len_v2v2(p->mval, p->mvalo)) {
sub_v2_v2v2(pt, p->mval, p->mvalo);
- gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]);
+ gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], false);
}
copy_v2_v2(p->mval, tmp);
}
@@ -2833,83 +3174,7 @@ static void gpencil_draw_apply_event(
if ((p->paintmode != GP_PAINTMODE_ERASER) && ((p->straight) || (is_speed_guide))) {
/* guided stroke */
if (is_speed_guide) {
- switch (guide->type) {
- default:
- case GP_GUIDE_CIRCULAR: {
- float distance;
- distance = len_v2v2(p->mvali, p->origin);
-
- if (guide->use_snapping && (guide->spacing > 0.0f)) {
- distance = gp_snap_to_grid_fl(distance, 0.0f, p->guide_spacing);
- }
-
- dist_ensure_v2_v2fl(p->mval, p->origin, distance);
- break;
- }
- case GP_GUIDE_RADIAL: {
- if (guide->use_snapping && (guide->angle_snap > 0.0f)) {
- float point[2];
- float xy[2];
- float angle;
- float half_angle = guide->angle_snap * 0.5f;
- sub_v2_v2v2(xy, p->mvali, p->origin);
- angle = atan2f(xy[1], xy[0]);
- angle += (M_PI * 2.0f);
- angle = fmodf(angle + half_angle, guide->angle_snap);
- angle -= half_angle;
- gp_rotate_v2_v2v2fl(point, p->mvali, p->origin, -angle);
- closest_to_line_v2(p->mval, p->mval, point, p->origin);
- }
- else {
- closest_to_line_v2(p->mval, p->mval, p->mvali, p->origin);
- }
- break;
- }
- case GP_GUIDE_PARALLEL: {
- float point[2];
- float unit[2];
- copy_v2_v2(unit, p->mvali);
- unit[0] += 1.0f; /* start from horizontal */
- gp_rotate_v2_v2v2fl(point, unit, p->mvali, guide->angle);
- closest_to_line_v2(p->mval, p->mval, p->mvali, point);
-
- if (guide->use_snapping && (guide->spacing > 0.0f)) {
- gp_rotate_v2_v2v2fl(p->mval, p->mval, p->origin, -guide->angle);
- p->mval[1] = gp_snap_to_grid_fl(
- p->mval[1] - p->half_spacing, p->origin[1], p->guide_spacing);
- gp_rotate_v2_v2v2fl(p->mval, p->mval, p->origin, guide->angle);
- }
- break;
- }
- case GP_GUIDE_GRID: {
- if (guide->use_snapping && (guide->spacing > 0.0f)) {
- float point[2];
- float unit[2];
- float angle;
- copy_v2_v2(unit, p->mvali);
- unit[0] += 1.0f; /* start from horizontal */
- angle = (p->straight == STROKE_VERTICAL) ? M_PI_2 : 0.0f;
- gp_rotate_v2_v2v2fl(point, unit, p->mvali, angle);
- closest_to_line_v2(p->mval, p->mval, p->mvali, point);
-
- if (p->straight == STROKE_HORIZONTAL) {
- p->mval[1] = gp_snap_to_grid_fl(
- p->mval[1] - p->half_spacing, p->origin[1], p->guide_spacing);
- }
- else {
- p->mval[0] = gp_snap_to_grid_fl(
- p->mval[0] - p->half_spacing, p->origin[0], p->guide_spacing);
- }
- }
- else if (p->straight == STROKE_HORIZONTAL) {
- p->mval[1] = p->mvali[1]; /* replace y */
- }
- else {
- p->mval[0] = p->mvali[0]; /* replace x */
- }
- break;
- }
- }
+ gpencil_speed_guide(p, guide);
}
else if (p->straight == STROKE_HORIZONTAL) {
p->mval[1] = p->mvali[1]; /* replace y */
@@ -2931,7 +3196,7 @@ static void gpencil_draw_apply_event(
RNA_float_set(&itemptr, "time", p->curtime - p->inittime);
/* apply the current latest drawing point */
- gpencil_draw_apply(C, op, p, depsgraph);
+ gpencil_draw_apply(C, op, p, depsgraph, is_fake);
/* force refresh */
/* just active area for now, since doing whole screen is too slow */
@@ -2997,7 +3262,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
}
/* apply this data as necessary now (as per usual) */
- gpencil_draw_apply(C, op, p, depsgraph);
+ gpencil_draw_apply(C, op, p, depsgraph, false);
}
RNA_END;
@@ -3131,7 +3396,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
if (paintmode != GP_PAINTMODE_ERASER) {
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
if ((gpl) && ((gpl->flag & GP_LAYER_LOCKED) || (gpl->flag & GP_LAYER_HIDE))) {
- BKE_report(op->reports, RPT_ERROR, "Active layer is locked or hide");
+ BKE_report(op->reports, RPT_ERROR, "Active layer is locked or hidden");
return OPERATOR_CANCELLED;
}
}
@@ -3170,8 +3435,6 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
/* TODO: set any additional settings that we can take from the events?
* TODO? if tablet is erasing, force eraser to be on? */
- /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */
-
/* if eraser is on, draw radial aid */
if (p->paintmode == GP_PAINTMODE_ERASER) {
gpencil_draw_toggle_eraser_cursor(C, p, true);
@@ -3192,7 +3455,8 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
p->status = GP_STATUS_PAINTING;
/* handle the initial drawing - i.e. for just doing a simple dot */
- gpencil_draw_apply_event(C, op, event, CTX_data_ensure_evaluated_depsgraph(C), 0.0f, 0.0f);
+ gpencil_draw_apply_event(
+ C, op, event, CTX_data_ensure_evaluated_depsgraph(C), 0.0f, 0.0f, false);
op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
else {
@@ -3309,24 +3573,21 @@ static void gpencil_move_last_stroke_to_back(bContext *C)
BLI_insertlinkbefore(&gpf->strokes, gpf->strokes.first, gps);
}
-/* add events for missing mouse movements when the artist draw very fast */
-static void gpencil_add_missing_events(bContext *C,
- wmOperator *op,
- const wmEvent *event,
- tGPsdata *p)
+/* Add fake events for missing mouse movements when the artist draw very fast */
+static bool gpencil_add_fake_events(bContext *C, wmOperator *op, const wmEvent *event, tGPsdata *p)
{
Brush *brush = p->brush;
GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
int input_samples = brush->gpencil_settings->input_samples;
-
+ bool added_events = false;
/* ensure sampling when using circular guide */
if (guide->use_guide && (guide->type == GP_GUIDE_CIRCULAR)) {
input_samples = GP_MAX_INPUT_SAMPLES;
}
if (input_samples == 0) {
- return;
+ return added_events;
}
RegionView3D *rv3d = p->ar->regiondata;
@@ -3376,7 +3637,8 @@ static void gpencil_add_missing_events(bContext *C,
interp_v2_v2v2(pt, a, b, 0.5f);
sub_v2_v2v2(pt, b, pt);
/* create fake event */
- gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]);
+ gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], true);
+ added_events = true;
}
else if (dist >= factor) {
int slices = 2 + (int)((dist - 1.0) / factor);
@@ -3385,9 +3647,11 @@ static void gpencil_add_missing_events(bContext *C,
interp_v2_v2v2(pt, a, b, n * i);
sub_v2_v2v2(pt, b, pt);
/* create fake event */
- gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]);
+ gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], true);
+ added_events = true;
}
}
+ return added_events;
}
/* events handling during interactive drawing part of operator */
@@ -3396,6 +3660,8 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
tGPsdata *p = op->customdata;
ToolSettings *ts = CTX_data_tool_settings(C);
GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
+ tGPspoint *points = (tGPspoint *)p->gpd->runtime.sbuffer;
+
/* default exit state - pass through to support MMB view nav, etc. */
int estate = OPERATOR_PASS_THROUGH;
@@ -3420,7 +3686,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* special mode for editing control points */
if (p->paintmode == GP_PAINTMODE_SET_CP) {
wmWindow *win = p->win;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
bool drawmode = false;
switch (event->type) {
@@ -3518,7 +3784,8 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
/* toggle painting mode upon mouse-button movement
- * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox only)
+ * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox
+ * only)
* - RIGHTMOUSE = polyline (hotkey) / eraser (all)
* (Disabling RIGHTMOUSE case here results in bugs like [#32647])
* also making sure we have a valid event value, to not exit too early
@@ -3692,11 +3959,23 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* handle drawing event */
/* printf("\t\tGP - add point\n"); */
+ int size_before = p->gpd->runtime.sbuffer_used;
+ bool added_events = false;
if (((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) && (p->paintmode != GP_PAINTMODE_ERASER)) {
- gpencil_add_missing_events(C, op, event, p);
+ added_events = gpencil_add_fake_events(C, op, event, p);
}
- gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph_pointer(C), 0.0f, 0.0f);
+ gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph_pointer(C), 0.0f, 0.0f, false);
+ int size_after = p->gpd->runtime.sbuffer_used;
+
+ /* Last point of the event is always real (not fake). */
+ tGPspoint *pt = &points[size_after - 1];
+ pt->tflag &= ~GP_TPOINT_FAKE;
+
+ /* Smooth the fake events to get smoother strokes, specially at ends. */
+ if (added_events) {
+ gp_smooth_fake_events(p, size_before, size_after);
+ }
/* finish painting operation if anything went wrong just now */
if (p->status == GP_STATUS_ERROR) {
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index e4b2e5540ea..c42c1c4d4c0 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -330,7 +330,15 @@ static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi)
gps->flag |= GP_STROKE_3DSPACE;
- gps->mat_nr = BKE_gpencil_object_material_get_index(tgpi->ob, tgpi->mat);
+ gps->mat_nr = BKE_gpencil_object_material_get_index_from_brush(tgpi->ob, tgpi->brush);
+ if (gps->mat_nr < 0) {
+ if (tgpi->ob->actcol - 1 < 0) {
+ gps->mat_nr = 0;
+ }
+ else {
+ gps->mat_nr = tgpi->ob->actcol - 1;
+ }
+ }
/* allocate memory for storage points, but keep empty */
gps->totpoints = 0;
@@ -1126,7 +1134,7 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
/* if brush doesn't exist, create a new set (fix damaged files from old versions) */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
- BKE_brush_gpencil_presets(C);
+ BKE_brush_gpencil_presets(bmain, ts);
}
/* Set Draw brush. */
@@ -1206,7 +1214,7 @@ static int gpencil_primitive_invoke(bContext *C, wmOperator *op, const wmEvent *
op->flag |= OP_IS_MODAL_CURSOR_REGION;
/* set cursor to indicate modal */
- WM_cursor_modal_set(win, BC_CROSSCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_CROSS);
/* update sindicator in header */
gpencil_primitive_status_indicators(C, tgpi);
@@ -1311,18 +1319,18 @@ static void gpencil_primitive_edit_event_handling(
if (tgpi->flag == IN_CURVE_EDIT) {
if ((a < BIG_SIZE_CTL && tgpi->tot_stored_edges == 0) || b < BIG_SIZE_CTL) {
move = MOVE_ENDS;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
else if (tgpi->curve) {
move = MOVE_CP;
- WM_cursor_modal_set(win, BC_HANDCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_HAND);
}
else {
- WM_cursor_modal_set(win, BC_CROSSCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_CROSS);
}
}
else if (tgpi->flag == IN_PROGRESS) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
switch (event->type) {
@@ -1394,7 +1402,7 @@ static void gpencil_primitive_edit_event_handling(
case EKEY: {
if (tgpi->flag == IN_CURVE_EDIT && !ELEM(tgpi->type, GP_STROKE_BOX, GP_STROKE_CIRCLE)) {
tgpi->flag = IN_PROGRESS;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
gpencil_primitive_add_segment(tgpi);
copy_v2_v2(tgpi->start, tgpi->end);
copy_v2_v2(tgpi->origin, tgpi->start);
@@ -1657,7 +1665,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
{
if ((event->val == KM_PRESS)) {
tgpi->flag = IN_MOVE;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
break;
}
@@ -1670,7 +1678,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
else {
tgpi->flag = IN_BRUSH_SIZE;
}
- WM_cursor_modal_set(win, BC_NS_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NS_SCROLL);
}
break;
}
@@ -1696,7 +1704,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case TABKEY: {
if (tgpi->flag == IN_CURVE_EDIT) {
tgpi->flag = IN_PROGRESS;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
gp_primitive_update_cps(tgpi);
gpencil_primitive_update(C, op, tgpi);
}
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index f4484624d5a..be265ed4bd5 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -832,7 +832,8 @@ void GPENCIL_OT_select_less(wmOperatorType *ot)
* from gpencil_paint.c #gp_stroke_eraser_dostroke().
* It would be great to de-duplicate the logic here sometime, but that can wait.
*/
-static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
+static bool gp_stroke_do_circle_sel(bGPdata *gpd,
+ bGPDlayer *gpl,
bGPDstroke *gps,
GP_SpaceConversion *gsc,
const int mx,
@@ -840,16 +841,18 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
const int radius,
const bool select,
rcti *rect,
- float diff_mat[4][4],
+ const float diff_mat[4][4],
const int selectmode,
const float scale)
{
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
bGPDspoint *pt1 = NULL;
bGPDspoint *pt2 = NULL;
- bGPDstroke *gps_orig = gps->runtime.gps_orig;
int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
int i;
bool changed = false;
+ bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
+ bGPDspoint *pt_active = NULL;
if (gps->totpoints == 1) {
bGPDspoint pt_temp;
@@ -862,12 +865,12 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius * radius) {
/* change selection */
if (select) {
- gps_orig->points->flag |= GP_SPOINT_SELECT;
- gps_orig->flag |= GP_STROKE_SELECT;
+ gps_active->points->flag |= GP_SPOINT_SELECT;
+ gps_active->flag |= GP_STROKE_SELECT;
}
else {
- gps_orig->points->flag &= ~GP_SPOINT_SELECT;
- gps_orig->flag &= ~GP_STROKE_SELECT;
+ gps_active->points->flag &= ~GP_SPOINT_SELECT;
+ gps_active->flag &= ~GP_STROKE_SELECT;
}
return true;
@@ -907,20 +910,24 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
*/
hit = true;
if (select) {
- if (pt1->runtime.pt_orig != NULL) {
- pt1->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
+ pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1;
+ if (pt_active != NULL) {
+ pt_active->flag |= GP_SPOINT_SELECT;
}
- if (pt2->runtime.pt_orig != NULL) {
- pt2->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
+ pt_active = (!is_multiedit) ? pt2->runtime.pt_orig : pt2;
+ if (pt_active != NULL) {
+ pt_active->flag |= GP_SPOINT_SELECT;
}
changed = true;
}
else {
- if (pt1->runtime.pt_orig != NULL) {
- pt1->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
+ pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1;
+ if (pt_active != NULL) {
+ pt_active->flag &= ~GP_SPOINT_SELECT;
}
- if (pt2->runtime.pt_orig != NULL) {
- pt2->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
+ pt_active = (!is_multiedit) ? pt2->runtime.pt_orig : pt2;
+ if (pt_active != NULL) {
+ pt_active->flag &= ~GP_SPOINT_SELECT;
}
changed = true;
}
@@ -935,28 +942,29 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
/* if stroke mode expand selection */
if ((hit) && (selectmode == GP_SELECTMODE_STROKE)) {
for (i = 0, pt1 = gps->points; i < gps->totpoints; i++, pt1++) {
- if (pt1->runtime.pt_orig != NULL) {
+ pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1;
+ if (pt_active != NULL) {
if (select) {
- pt1->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
+ pt_active->flag |= GP_SPOINT_SELECT;
}
else {
- pt1->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
+ pt_active->flag &= ~GP_SPOINT_SELECT;
}
}
}
}
/* expand selection to segment */
- if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select) &&
- (pt1->runtime.pt_orig != NULL)) {
+ pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1;
+ if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select) && (pt_active != NULL)) {
float r_hita[3], r_hitb[3];
bool hit_select = (bool)(pt1->flag & GP_SPOINT_SELECT);
ED_gpencil_select_stroke_segment(
- gpl, gps_orig, pt1->runtime.pt_orig, hit_select, false, scale, r_hita, r_hitb);
+ gpl, gps_active, pt_active, hit_select, false, scale, r_hita, r_hitb);
}
/* Ensure that stroke selection is in sync with its points */
- BKE_gpencil_stroke_sync_selection(gps_orig);
+ BKE_gpencil_stroke_sync_selection(gps_active);
}
return changed;
@@ -1016,8 +1024,18 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
/* find visible strokes, and select if hit */
GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
{
- changed |= gp_stroke_do_circle_sel(
- gpl, gps, &gsc, mx, my, radius, select, &rect, gpstroke_iter.diff_mat, selectmode, scale);
+ changed |= gp_stroke_do_circle_sel(gpd,
+ gpl,
+ gps,
+ &gsc,
+ mx,
+ my,
+ radius,
+ select,
+ &rect,
+ gpstroke_iter.diff_mat,
+ selectmode,
+ scale);
}
GP_EVALUATED_STROKES_END(gpstroke_iter);
@@ -1090,6 +1108,8 @@ static int gpencil_generic_select_exec(bContext *C,
((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0));
const bool segmentmode = ((selectmode == GP_SELECTMODE_SEGMENT) &&
((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0));
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
const float scale = ts->gp_sculpt.isect_threshold;
@@ -1125,36 +1145,32 @@ static int gpencil_generic_select_exec(bContext *C,
/* select/deselect points */
GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
{
+ bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
bGPDspoint *pt;
int i;
bool hit = false;
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->runtime.pt_orig == NULL) {
+ if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) {
continue;
}
+ bGPDspoint *pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
/* convert point coords to screenspace */
const bool is_inside = is_inside_fn(gps, pt, &gsc, gpstroke_iter.diff_mat, user_data);
if (strokemode == false) {
- const bool is_select = (pt->runtime.pt_orig->flag & GP_SPOINT_SELECT) != 0;
+ const bool is_select = (pt_active->flag & GP_SPOINT_SELECT) != 0;
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(pt->runtime.pt_orig->flag, sel_op_result, GP_SPOINT_SELECT);
+ SET_FLAG_FROM_TEST(pt_active->flag, sel_op_result, GP_SPOINT_SELECT);
changed = true;
/* expand selection to segment */
if ((sel_op_result != -1) && (segmentmode)) {
- bool hit_select = (bool)(pt->runtime.pt_orig->flag & GP_SPOINT_SELECT);
+ bool hit_select = (bool)(pt_active->flag & GP_SPOINT_SELECT);
float r_hita[3], r_hitb[3];
- ED_gpencil_select_stroke_segment(gpl,
- gps->runtime.gps_orig,
- pt->runtime.pt_orig,
- hit_select,
- false,
- scale,
- r_hita,
- r_hitb);
+ ED_gpencil_select_stroke_segment(
+ gpl, gps_active, pt_active, hit_select, false, scale, r_hita, r_hitb);
}
}
}
@@ -1168,19 +1184,21 @@ static int gpencil_generic_select_exec(bContext *C,
/* if stroke mode expand selection */
if (strokemode) {
- const bool is_select = BKE_gpencil_stroke_select_check(gps->runtime.gps_orig);
+ const bool is_select = BKE_gpencil_stroke_select_check(gps_active);
const bool is_inside = hit;
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->runtime.pt_orig == NULL) {
+ if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) {
continue;
}
+ bGPDspoint *pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
+
if (sel_op_result) {
- pt->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
+ pt_active->flag |= GP_SPOINT_SELECT;
}
else {
- pt->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
+ pt_active->flag &= ~GP_SPOINT_SELECT;
}
}
changed = true;
@@ -1188,7 +1206,7 @@ static int gpencil_generic_select_exec(bContext *C,
}
/* Ensure that stroke selection is in sync with its points */
- BKE_gpencil_stroke_sync_selection(gps->runtime.gps_orig);
+ BKE_gpencil_stroke_sync_selection(gps_active);
}
GP_EVALUATED_STROKES_END(gpstroke_iter);
@@ -1369,6 +1387,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
bGPdata *gpd = ED_gpencil_data_get_active(C);
ToolSettings *ts = CTX_data_tool_settings(C);
const float scale = ts->gp_sculpt.isect_threshold;
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
/* "radius" is simply a threshold (screen space) to make it easier to test with a tolerance */
const float radius = 0.50f * U.widget_unit;
@@ -1414,13 +1433,14 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
/* XXX: maybe we should go from the top of the stack down instead... */
GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
{
+ bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
bGPDspoint *pt;
int i;
/* firstly, check for hit-point */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
int xy[2];
- if (pt->runtime.pt_orig == NULL) {
+ if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) {
continue;
}
@@ -1437,8 +1457,8 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
/* only use this point if it is a better match than the current hit - T44685 */
if (pt_distance < hit_distance) {
hit_layer = gpl;
- hit_stroke = gps->runtime.gps_orig;
- hit_point = pt->runtime.pt_orig;
+ hit_stroke = gps_active;
+ hit_point = (!is_multiedit) ? pt->runtime.pt_orig : pt;
hit_distance = pt_distance;
}
}
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 2a0f16a4bbf..b194d28a8b8 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -46,6 +46,7 @@
#include "BKE_action.h"
#include "BKE_colortools.h"
+#include "BKE_collection.h"
#include "BKE_deform.h"
#include "BKE_main.h"
#include "BKE_brush.h"
@@ -57,6 +58,7 @@
#include "BKE_tracking.h"
#include "WM_api.h"
+#include "WM_types.h"
#include "WM_toolsystem.h"
#include "RNA_access.h"
@@ -401,17 +403,7 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
/* Create new layer */
/* TODO: have some way of specifying that we don't want this? */
- {
- /* "New Layer" entry */
- item_tmp.identifier = "__CREATE__";
- item_tmp.name = "New Layer";
- item_tmp.value = -1;
- item_tmp.icon = ICON_ADD;
- RNA_enum_item_add(&item, &totitem, &item_tmp);
- /* separator */
- RNA_enum_item_add_separator(&item, &totitem);
- }
const int tot = BLI_listbase_count(&gpd->layers);
/* Existing layers */
for (gpl = gpd->layers.last, i = 0; gpl; gpl = gpl->prev, i++) {
@@ -428,6 +420,17 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
RNA_enum_item_add(&item, &totitem, &item_tmp);
}
+ {
+ /* separator */
+ RNA_enum_item_add_separator(&item, &totitem);
+
+ /* "New Layer" entry */
+ item_tmp.identifier = "__CREATE__";
+ item_tmp.name = "New Layer";
+ item_tmp.value = -1;
+ item_tmp.icon = ICON_ADD;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -1388,7 +1391,7 @@ void ED_gpencil_add_defaults(bContext *C, Object *ob)
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
/* create new brushes */
- BKE_brush_gpencil_presets(C);
+ BKE_brush_gpencil_presets(bmain, ts);
}
/* ensure a color exists and is assigned to object */
@@ -1949,7 +1952,7 @@ void ED_gpencil_setup_modes(bContext *C, bGPdata *gpd, int newmode)
/* helper to convert 2d to 3d for simple drawing buffer */
static void gpencil_stroke_convertcoords(ARegion *ar,
const tGPspoint *point2D,
- float origin[3],
+ const float origin[3],
float out[3])
{
float mval_f[2] = {(float)point2D->x, (float)point2D->y};
@@ -2063,7 +2066,7 @@ void ED_gpencil_update_color_uv(Main *bmain, Material *mat)
if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
continue;
}
- gps_ma = give_current_material(ob, gps->mat_nr + 1);
+ gps_ma = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
/* update */
if ((gps_ma) && (gps_ma == mat)) {
ED_gpencil_calc_stroke_uv(ob, gps);
@@ -2081,8 +2084,8 @@ static bool gpencil_check_collision(bGPDstroke *gps,
bGPDstroke **gps_array,
GHash *all_2d,
int totstrokes,
- float p2d_a1[2],
- float p2d_a2[2],
+ const float p2d_a1[2],
+ const float p2d_a2[2],
float r_hit[2])
{
bool hit = false;
@@ -2161,7 +2164,7 @@ static void gp_copy_points(bGPDstroke *gps, bGPDspoint *pt, bGPDspoint *pt_final
}
static void gp_insert_point(
- bGPDstroke *gps, bGPDspoint *a_pt, bGPDspoint *b_pt, float co_a[3], float co_b[3])
+ bGPDstroke *gps, bGPDspoint *a_pt, bGPDspoint *b_pt, const float co_a[3], float co_b[3])
{
bGPDspoint *temp_points;
int totnewpoints, oldtotpoints;
@@ -2558,3 +2561,24 @@ tGPspoint *ED_gpencil_sbuffer_ensure(tGPspoint *buffer_array,
return buffer_array;
}
+
+/* Tag all scene grease pencil object to update. */
+void ED_gpencil_tag_scene_gpencil(Scene *scene)
+{
+ /* mark all grease pencil datablocks of the scene */
+ FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, ob) {
+ if (ob->type == OB_GPENCIL) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
+ FOREACH_SCENE_COLLECTION_END;
+
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+
+ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
+}
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index cb6c66ed795..bf9b69f12e1 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -834,12 +834,28 @@ void ED_drivers_editor_init(struct bContext *C, struct ScrArea *sa);
/* ************************************************ */
+typedef enum eAnimvizCalcRange {
+ /* Update motion paths at the current frame only. */
+ ANIMVIZ_CALC_RANGE_CURRENT_FRAME,
+
+ /* Try to limit updates to a close neighborhood of the current frame. */
+ ANIMVIZ_CALC_RANGE_CHANGED,
+
+ /* Update an entire range of the motion paths. */
+ ANIMVIZ_CALC_RANGE_FULL,
+} eAnimvizCalcRange;
+
+struct Depsgraph *animviz_depsgraph_build(struct Main *bmain,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ struct ListBase *targets);
+
void animviz_calc_motionpaths(struct Depsgraph *depsgraph,
struct Main *bmain,
struct Scene *scene,
ListBase *targets,
- bool restore,
- bool current_frame_only);
+ eAnimvizCalcRange range,
+ bool restore);
void animviz_get_object_motionpaths(struct Object *ob, ListBase *targets);
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 48d0a5fe8be..7ac42967dda 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -73,6 +73,7 @@ typedef struct EditBone {
* animation are automatically relative to the bones' rest positions*/
int flag;
int layer;
+ char inherit_scale_mode;
/* Envelope distance & weight */
float dist, weight;
@@ -283,10 +284,18 @@ bool ED_pose_deselect_all_multi(struct bContext *C, int select_mode, const bool
bool ED_pose_deselect_all(struct Object *ob, int select_mode, const bool ignore_visibility);
void ED_pose_bone_select_tag_update(struct Object *ob);
void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select);
+
+/* Corresponds to eAnimvizCalcRange. */
+typedef enum ePosePathCalcRange {
+ POSE_PATH_CALC_RANGE_CURRENT_FRAME,
+ POSE_PATH_CALC_RANGE_CHANGED,
+ POSE_PATH_CALC_RANGE_FULL,
+} ePosePathCalcRange;
void ED_pose_recalculate_paths(struct bContext *C,
struct Scene *scene,
struct Object *ob,
- bool current_frame_only);
+ ePosePathCalcRange range);
+
struct Object *ED_pose_object_from_context(struct bContext *C);
/* meshlaplacian.c */
diff --git a/source/blender/editors/include/ED_datafiles.h b/source/blender/editors/include/ED_datafiles.h
index 43d7117a1b2..ada90205b4a 100644
--- a/source/blender/editors/include/ED_datafiles.h
+++ b/source/blender/editors/include/ED_datafiles.h
@@ -285,6 +285,12 @@ extern char datatoc_gp_brush_marker_png[];
extern int datatoc_gp_brush_fill_png_size;
extern char datatoc_gp_brush_fill_png[];
+extern int datatoc_gp_brush_airbrush_png_size;
+extern char datatoc_gp_brush_airbrush_png[];
+
+extern int datatoc_gp_brush_chisel_png_size;
+extern char datatoc_gp_brush_chisel_png[];
+
extern int datatoc_gp_brush_erase_soft_png_size;
extern char datatoc_gp_brush_erase_soft_png[];
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 7273f857a41..83890c1621c 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -29,22 +29,39 @@ struct FileSelectParams;
struct ScrArea;
struct SpaceFile;
struct bContext;
+struct bScreen;
+struct uiBlock;
struct wmWindowManager;
#define FILE_LAYOUT_HOR 1
#define FILE_LAYOUT_VER 2
-#define MAX_FILE_COLUMN 4
-
-typedef enum FileListColumns {
+typedef enum FileAttributeColumnType {
+ COLUMN_NONE = -1,
COLUMN_NAME = 0,
- COLUMN_DATE,
- COLUMN_TIME,
+ COLUMN_DATETIME,
COLUMN_SIZE,
-} FileListColumns;
+
+ ATTRIBUTE_COLUMN_MAX
+} FileAttributeColumnType;
+
+typedef struct FileAttributeColumn {
+ /** UI name for this column */
+ const char *name;
+
+ float width;
+ /* The sort type to use when sorting by this column. */
+ int sort_type; /* eFileSortType */
+
+ /* Alignment of column texts, header text is always left aligned */
+ int text_align; /* eFontStyle_Align */
+} FileAttributeColumn;
typedef struct FileLayout {
/* view settings - XXX - move into own struct */
+ int offset_top;
+ /* Height of the header for the different FileAttributeColumn's. */
+ int attribute_column_header_h;
int prv_w;
int prv_h;
int tile_w;
@@ -54,13 +71,17 @@ typedef struct FileLayout {
int prv_border_x;
int prv_border_y;
int rows;
- int columns;
+ /* Those are the major layout columns the files are distributed across, not to be confused with
+ * 'attribute_columns' array below. */
+ int flow_columns;
int width;
int height;
int flag;
int dirty;
int textheight;
- float column_widths[MAX_FILE_COLUMN];
+ /* The columns for each item (name, modification date/time, size). Not to be confused with the
+ * 'flow_columns' above. */
+ FileAttributeColumn attribute_columns[ATTRIBUTE_COLUMN_MAX];
/* When we change display size, we may have to update static strings like size of files... */
short curr_size;
@@ -71,11 +92,14 @@ typedef struct FileSelection {
int last;
} FileSelection;
+struct View2D;
struct rcti;
struct FileSelectParams *ED_fileselect_get_params(struct SpaceFile *sfile);
short ED_fileselect_set_params(struct SpaceFile *sfile);
+void ED_fileselect_set_params_from_userdef(struct SpaceFile *sfile);
+void ED_fileselect_params_to_userdef(struct SpaceFile *sfile, int temp_win_size[]);
void ED_fileselect_reset_params(struct SpaceFile *sfile);
@@ -87,6 +111,17 @@ int ED_fileselect_layout_numfiles(FileLayout *layout, struct ARegion *ar);
int ED_fileselect_layout_offset(FileLayout *layout, int x, int y);
FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const struct rcti *rect);
+void ED_fileselect_layout_maskrect(const FileLayout *layout,
+ const struct View2D *v2d,
+ struct rcti *r_rect);
+bool ED_fileselect_layout_is_inside_pt(const FileLayout *layout,
+ const struct View2D *v2d,
+ int x,
+ int y);
+bool ED_fileselect_layout_isect_rect(const FileLayout *layout,
+ const struct View2D *v2d,
+ const struct rcti *rect,
+ struct rcti *r_dst);
void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y);
void ED_operatormacros_file(void);
@@ -102,6 +137,11 @@ void ED_file_read_bookmarks(void);
void ED_file_change_dir(struct bContext *C);
+void ED_file_path_button(struct bScreen *screen,
+ const struct SpaceFile *sfile,
+ struct FileSelectParams *params,
+ struct uiBlock *block);
+
/* File menu stuff */
/* FSMenuEntry's without paths indicate separators */
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 470eb58c72b..0ff1b8bb40b 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -71,8 +71,15 @@ typedef struct tGPspoint {
float uv_rot; /* uv rotation for dor mode */
float rnd[3]; /* rnd value */
bool rnd_dirty; /* rnd flag */
+ short tflag; /* Internal flag */
} tGPspoint;
+/* tGPspoint->flag */
+typedef enum etGPspoint_tFlag {
+ /* Created by Fake event (used when mouse/pen move very fast while drawing). */
+ GP_TPOINT_FAKE = (1 << 0),
+} etGPspoint_tFlag;
+
/* used to sort by zdepth gpencil objects in viewport */
/* TODO: this could be a system parameter in userprefs screen */
#define GP_CACHE_BLOCK_SIZE 16
@@ -288,4 +295,7 @@ struct tGPspoint *ED_gpencil_sbuffer_ensure(struct tGPspoint *buffer_array,
short *buffer_size,
short *buffer_used,
const bool clear);
+/* Tag all scene grease pencil object to update. */
+void ED_gpencil_tag_scene_gpencil(struct Scene *scene);
+
#endif /* __ED_GPENCIL_H__ */
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index 7d69f86dbf8..69742af9f50 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -77,6 +77,7 @@ void ED_image_mouse_pos(struct SpaceImage *sima,
struct ARegion *ar,
const int mval[2],
float co[2]);
+void ED_image_view_center_to_point(struct SpaceImage *sima, float x, float y);
void ED_image_point_pos(
struct SpaceImage *sima, struct ARegion *ar, float x, float y, float *xr, float *yr);
void ED_image_point_pos__reverse(struct SpaceImage *sima,
@@ -94,6 +95,7 @@ bool ED_space_image_paint_curve(const struct bContext *C);
bool ED_space_image_check_show_maskedit(struct SpaceImage *sima, struct ViewLayer *view_layer);
bool ED_space_image_maskedit_poll(struct bContext *C);
bool ED_space_image_maskedit_mask_poll(struct bContext *C);
+bool ED_space_image_cursor_poll(struct bContext *C);
void ED_image_draw_info(struct Scene *scene,
struct ARegion *ar,
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 42e5add2ef0..16b3c9c240a 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -310,15 +310,24 @@ extern EnumPropertyItem prop_driver_create_mapping_types[];
/* -------- */
+typedef enum eDriverFCurveCreationMode {
+ DRIVER_FCURVE_LOOKUP_ONLY = 0, /* Don't add anything if not found. */
+ DRIVER_FCURVE_KEYFRAMES = 1, /* Add with keyframes, for visual tweaking. */
+ DRIVER_FCURVE_GENERATOR = 2, /* Add with generator, for script backwards compatibility. */
+ DRIVER_FCURVE_EMPTY = 3 /* Add without data, for pasting. */
+} eDriverFCurveCreationMode;
+
/* Low-level call to add a new driver F-Curve. This shouldn't be used directly for most tools,
* although there are special cases where this approach is preferable.
*/
struct FCurve *verify_driver_fcurve(struct ID *id,
const char rna_path[],
const int array_index,
- short add);
+ eDriverFCurveCreationMode creation_mode);
-struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index, short add);
+struct FCurve *alloc_driver_fcurve(const char rna_path[],
+ const int array_index,
+ eDriverFCurveCreationMode creation_mode);
/* -------- */
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 0b2adfed531..d8d62ad6f08 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -138,13 +138,21 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree,
struct View3D *v3d,
struct Object *obedit);
+/* editmesh_automerge.c */
+void EDBM_automerge(struct Object *ob, bool update, const char hflag, const float dist);
+void EDBM_automerge_and_split(struct Object *ob,
+ bool split_edges,
+ bool split_faces,
+ bool update,
+ const char hflag,
+ const float dist);
+
/* editmesh_undo.c */
void ED_mesh_undosys_type(struct UndoType *ut);
/* editmesh_select.c */
void EDBM_select_mirrored(
struct BMEditMesh *em, const int axis, const bool extend, int *r_totmirr, int *r_totfail);
-void EDBM_automerge(struct Scene *scene, struct Object *ob, bool update, const char hflag);
struct BMVert *EDBM_vert_find_nearest_ex(struct ViewContext *vc,
float *r_dist,
@@ -188,8 +196,11 @@ bool EDBM_unified_findnearest(struct ViewContext *vc,
bool EDBM_unified_findnearest_from_raycast(struct ViewContext *vc,
struct Base **bases,
const uint bases_len,
- bool use_boundary,
- int *r_base_index,
+ bool use_boundary_vertices,
+ bool use_boundary_edges,
+ int *r_base_index_vert,
+ int *r_base_index_edge,
+ int *r_base_index_face,
struct BMVert **r_eve,
struct BMEdge **r_eed,
struct BMFace **r_efa);
@@ -203,11 +214,12 @@ void EDBM_selectmode_convert(struct BMEditMesh *em,
const short selectmode_new);
/* user access this */
-bool EDBM_selectmode_toggle(struct bContext *C,
- const short selectmode_new,
- const int action,
- const bool use_extend,
- const bool use_expand);
+bool EDBM_selectmode_set_multi(struct bContext *C, const short selectmode);
+bool EDBM_selectmode_toggle_multi(struct bContext *C,
+ const short selectmode_new,
+ const int action,
+ const bool use_extend,
+ const bool use_expand);
bool EDBM_selectmode_disable(struct Scene *scene,
struct BMEditMesh *em,
@@ -239,15 +251,30 @@ void EDBM_preselect_edgering_update_from_edge(struct EditMesh_PreSelEdgeRing *ps
/* editmesh_preselect_elem.c */
struct EditMesh_PreSelElem;
+typedef enum eEditMesh_PreSelPreviewAction {
+ PRESELECT_ACTION_TRANSFORM = 1,
+ PRESELECT_ACTION_CREATE = 2,
+ PRESELECT_ACTION_DELETE = 3,
+} eEditMesh_PreSelPreviewAction;
+
struct EditMesh_PreSelElem *EDBM_preselect_elem_create(void);
void EDBM_preselect_elem_destroy(struct EditMesh_PreSelElem *psel);
void EDBM_preselect_elem_clear(struct EditMesh_PreSelElem *psel);
+void EDBM_preselect_preview_clear(struct EditMesh_PreSelElem *psel);
void EDBM_preselect_elem_draw(struct EditMesh_PreSelElem *psel, const float matrix[4][4]);
void EDBM_preselect_elem_update_from_single(struct EditMesh_PreSelElem *psel,
struct BMesh *bm,
struct BMElem *ele,
const float (*coords)[3]);
+void EDBM_preselect_elem_update_preview(struct EditMesh_PreSelElem *psel,
+ struct ViewContext *vc,
+ struct BMesh *bm,
+ struct BMElem *ele,
+ const int mval[2]);
+void EDBM_preselect_action_set(struct EditMesh_PreSelElem *psel,
+ eEditMesh_PreSelPreviewAction action);
+eEditMesh_PreSelPreviewAction EDBM_preselect_action_get(struct EditMesh_PreSelElem *psel);
/* mesh_ops.c */
void ED_operatortypes_mesh(void);
void ED_operatormacros_mesh(void);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index c481c19a552..38d75aa57e9 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -238,9 +238,17 @@ void ED_object_single_user(struct Main *bmain, struct Scene *scene, struct Objec
/* object motion paths */
void ED_objects_clear_paths(struct bContext *C, bool only_selected);
+
+/* Corresponds to eAnimvizCalcRange. */
+typedef enum eObjectPathCalcRange {
+ OBJECT_PATH_CALC_RANGE_CURRENT_FRAME,
+ OBJECT_PATH_CALC_RANGE_CHANGED,
+ OBJECT_PATH_CALC_RANGE_FULL,
+} eObjectPathCalcRange;
+
void ED_objects_recalculate_paths(struct bContext *C,
struct Scene *scene,
- bool current_frame_only);
+ eObjectPathCalcRange range);
/* constraints */
struct ListBase *get_active_constraints(struct Object *ob);
diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h
index 88cc8a85897..fec4beea809 100644
--- a/source/blender/editors/include/ED_paint.h
+++ b/source/blender/editors/include/ED_paint.h
@@ -40,13 +40,44 @@ void ED_imapaint_dirty_region(
struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h, bool find_old);
void ED_imapaint_bucket_fill(struct bContext *C, float color[3], struct wmOperator *op);
-/* paint_image_undo.c */
+/* image_undo.c */
void ED_image_undo_push_begin(const char *name, int paint_mode);
+void ED_image_undo_push_begin_with_image(const char *name,
+ struct Image *image,
+ struct ImBuf *ibuf);
+
void ED_image_undo_push_end(void);
void ED_image_undo_restore(struct UndoStep *us);
void ED_image_undosys_type(struct UndoType *ut);
+void *ED_image_paint_tile_find(struct ListBase *undo_tiles,
+ struct Image *ima,
+ struct ImBuf *ibuf,
+ int x_tile,
+ int y_tile,
+ unsigned short **r_mask,
+ bool validate);
+void *ED_image_paint_tile_push(struct ListBase *undo_tiles,
+ struct Image *ima,
+ struct ImBuf *ibuf,
+ struct ImBuf **tmpibuf,
+ int x_tile,
+ int y_tile,
+ unsigned short **r_mask,
+ bool **r_valid,
+ bool use_thread_lock,
+ bool find_prev);
+void ED_image_paint_tile_lock_init(void);
+void ED_image_paint_tile_lock_end(void);
+
+struct ListBase *ED_image_paint_tile_list_get(void);
+
+#define ED_IMAGE_UNDO_TILE_BITS 6
+#define ED_IMAGE_UNDO_TILE_SIZE (1 << ED_IMAGE_UNDO_TILE_BITS)
+#define ED_IMAGE_UNDO_TILE_NUMBER(size) \
+ (((size) + ED_IMAGE_UNDO_TILE_SIZE - 1) >> ED_IMAGE_UNDO_TILE_BITS)
+
/* paint_curve_undo.c */
void ED_paintcurve_undo_push_begin(const char *name);
void ED_paintcurve_undo_push_end(void);
diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h
index 3ef3c0ba937..0c973f4ca88 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -40,12 +40,18 @@ int PE_start_edit(struct PTCacheEdit *edit);
/* access */
struct PTCacheEdit *PE_get_current_from_psys(struct ParticleSystem *psys);
-struct PTCacheEdit *PE_get_current(struct Scene *scene, struct Object *ob);
+struct PTCacheEdit *PE_get_current(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob);
struct PTCacheEdit *PE_create_current(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
void PE_current_changed(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
-int PE_minmax(struct Scene *scene, struct ViewLayer *view_layer, float min[3], float max[3]);
+int PE_minmax(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ float min[3],
+ float max[3]);
struct ParticleEditSettings *PE_settings(struct Scene *scene);
/* update calls */
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index d0fab134dcc..7c3aac6c688 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -66,6 +66,7 @@ void ED_region_do_listen(struct wmWindow *win,
void ED_region_do_layout(struct bContext *C, struct ARegion *ar);
void ED_region_do_draw(struct bContext *C, struct ARegion *ar);
void ED_region_exit(struct bContext *C, struct ARegion *ar);
+void ED_region_remove(struct bContext *C, struct ScrArea *sa, struct ARegion *ar);
void ED_region_pixelspace(struct ARegion *ar);
void ED_region_update_rect(struct ARegion *ar);
void ED_region_init(struct ARegion *ar);
@@ -238,6 +239,14 @@ struct ScrArea *ED_screen_state_toggle(struct bContext *C,
struct wmWindow *win,
struct ScrArea *sa,
const short state);
+ScrArea *ED_screen_temp_space_open(struct bContext *C,
+ const char *title,
+ int x,
+ int y,
+ int sizex,
+ int sizey,
+ eSpace_Type space_type,
+ int display_type);
void ED_screens_header_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg);
void ED_screens_footer_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg);
void ED_screens_navigation_bar_tools_menu_create(struct bContext *C,
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index d907ba4e581..0273c8c73ab 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -39,6 +39,11 @@ bool ED_sculpt_mask_box_select(struct bContext *C,
const struct rcti *rect,
bool select);
+/* transform */
+void ED_sculpt_update_modal_transform(struct bContext *C);
+void ED_sculpt_init_transform(struct bContext *C);
+void ED_sculpt_end_transform(struct bContext *C);
+
/* sculpt_undo.c */
void ED_sculpt_undosys_type(struct UndoType *ut);
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index 192af8f5273..8c70fc9a157 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -90,6 +90,11 @@ enum TfmMode {
#define CTX_PAINT_CURVE (1 << 8)
#define CTX_GPENCIL_STROKES (1 << 9)
#define CTX_CURSOR (1 << 10)
+/** When transforming object's, adjust the object data so it stays in the same place. */
+#define CTX_OBMODE_XFORM_OBDATA (1 << 11)
+/** Transform object parents without moving their children. */
+#define CTX_OBMODE_XFORM_SKIP_CHILDREN (1 << 12)
+#define CTX_SCULPT (1 << 13)
/* Standalone call to get the transformation center corresponding to the current situation
* returns 1 if successful, 0 otherwise (usually means there's no selection)
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 139b306b533..28280fae3a8 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -521,7 +521,9 @@ int view3d_opengl_select(struct ViewContext *vc,
/* view3d_select.c */
float ED_view3d_select_dist_px(void);
-void ED_view3d_viewcontext_init(struct bContext *C, struct ViewContext *vc);
+void ED_view3d_viewcontext_init(struct bContext *C,
+ struct ViewContext *vc,
+ struct Depsgraph *depsgraph);
void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact);
void view3d_operator_needs_opengl(const struct bContext *C);
void view3d_region_operator_needs_opengl(struct wmWindow *win, struct ARegion *ar);
@@ -741,4 +743,8 @@ void ED_view3d_buttons_region_layout_ex(const struct bContext *C,
struct ARegion *ar,
const char *category_override);
+/* view3d_view.c */
+bool ED_view3d_local_collections_set(struct Main *bmain, struct View3D *v3d);
+void ED_view3d_local_collections_reset(struct bContext *C, const bool reset_all);
+
#endif /* __ED_VIEW3D_H__ */
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 41ac1b6b452..4e4db46adf6 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -42,6 +42,9 @@
#ifndef DEF_ICON_SHADING
# define DEF_ICON_SHADING DEF_ICON
#endif
+#ifndef DEF_ICON_FOLDER
+# define DEF_ICON_FOLDER DEF_ICON
+#endif
#ifndef DEF_ICON_COLOR
# define DEF_ICON_COLOR DEF_ICON
#endif
@@ -88,7 +91,7 @@ DEF_ICON(REMOVE)
DEF_ICON(PANEL_CLOSE)
DEF_ICON(COPY_ID)
DEF_ICON(EYEDROPPER)
-DEF_ICON_BLANK(92)
+DEF_ICON(CHECKMARK)
DEF_ICON(AUTO)
DEF_ICON(CHECKBOX_DEHLT) /* de-Highlight - Checkbox OFF */
DEF_ICON(CHECKBOX_HLT) /* Highlight - Checkbox ON */
@@ -666,7 +669,7 @@ DEF_ICON(PARTICLE_PATH)
/* EDITING */
DEF_ICON_BLANK(669)
-DEF_ICON_BLANK(670)
+DEF_ICON(SNAP_FACE_CENTER)
DEF_ICON(SNAP_PERPENDICULAR)
DEF_ICON(SNAP_MIDPOINT)
DEF_ICON(SNAP_OFF)
@@ -713,7 +716,7 @@ DEF_ICON(UV_SYNC_SELECT)
DEF_ICON_BLANK(240)
DEF_ICON_BLANK(241)
DEF_ICON_BLANK(242)
-DEF_ICON_BLANK(243)
+DEF_ICON(TRANSFORM_ORIGINS)
DEF_ICON(GIZMO)
DEF_ICON(ORIENTATION_CURSOR)
DEF_ICON(NORMALS_VERTEX)
@@ -793,7 +796,7 @@ DEF_ICON(NEWFOLDER)
DEF_ICON_BLANK(794)
DEF_ICON(FILE_PARENT)
DEF_ICON(FILE_REFRESH)
-DEF_ICON(FILE_FOLDER)
+DEF_ICON_FOLDER(FILE_FOLDER)
DEF_ICON(FILE_BLANK)
DEF_ICON(FILE_BLEND)
DEF_ICON(FILE_IMAGE)
@@ -823,7 +826,7 @@ DEF_ICON(BACK)
DEF_ICON(FORWARD)
DEF_ICON_BLANK(825)
DEF_ICON_BLANK(826)
-DEF_ICON_BLANK(827)
+DEF_ICON(FILE_ARCHIVE)
DEF_ICON(FILE_CACHE)
DEF_ICON(FILE_VOLUME)
DEF_ICON(FILE_3D)
@@ -855,9 +858,9 @@ DEF_ICON_BLANK(855)
DEF_ICON_BLANK(856)
DEF_ICON_BLANK(857)
DEF_ICON_BLANK(858)
-DEF_ICON_BLANK(859)
-DEF_ICON_BLANK(860)
-DEF_ICON_BLANK(861)
+DEF_ICON(DESKTOP)
+DEF_ICON(EXTERNAL_DRIVE)
+DEF_ICON(NETWORK_DRIVE)
/* SEQUENCE / IMAGE EDITOR */
DEF_ICON(SEQ_SEQUENCER)
@@ -934,6 +937,8 @@ DEF_ICON_COLOR(GPBRUSH_INKNOISE)
DEF_ICON_COLOR(GPBRUSH_BLOCK)
DEF_ICON_COLOR(GPBRUSH_MARKER)
DEF_ICON_COLOR(GPBRUSH_FILL)
+DEF_ICON_COLOR(GPBRUSH_AIRBRUSH)
+DEF_ICON_COLOR(GPBRUSH_CHISEL)
DEF_ICON_COLOR(GPBRUSH_ERASE_SOFT)
DEF_ICON_COLOR(GPBRUSH_ERASE_HARD)
DEF_ICON_COLOR(GPBRUSH_ERASE_STROKE)
@@ -1034,6 +1039,7 @@ DEF_ICON_COLOR(EVENT_RETURN)
#undef DEF_ICON_OBJECT_DATA
#undef DEF_ICON_MODIFIER
#undef DEF_ICON_SHADING
+#undef DEF_ICON_FOLDER
#undef DEF_ICON_VECTOR
#undef DEF_ICON_COLOR
#undef DEF_ICON_FUND
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index a61daa11c36..f5721c008b2 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -32,6 +32,7 @@
struct ARegion;
struct AutoComplete;
+struct FileSelectParams;
struct ID;
struct IDProperty;
struct ImBuf;
@@ -89,7 +90,7 @@ typedef struct uiPopupBlockHandle uiPopupBlockHandle;
* For #ARegion.overlap regions, pass events though if they don't overlap
* the regions contents (the usable part of the #View2D and buttons).
*
- * The margin is needed so it's not possible to accidentally click inbetween buttons.
+ * The margin is needed so it's not possible to accidentally click in between buttons.
*/
#define UI_REGION_OVERLAP_MARGIN (U.widget_unit / 3)
@@ -520,8 +521,10 @@ typedef bool (*uiMenuStepFunc)(struct bContext *C, int direction, void *arg1);
/* interface_query.c */
bool UI_but_has_tooltip_label(const uiBut *but);
bool UI_but_is_tool(const uiBut *but);
+bool UI_but_is_utf8(const uiBut *but);
#define UI_but_is_decorator(but) ((but)->func == ui_but_anim_decorate_cb)
+bool UI_block_is_empty_ex(const uiBlock *block, const bool skip_title);
bool UI_block_is_empty(const uiBlock *block);
bool UI_block_can_add_separator(const uiBlock *block);
@@ -1596,6 +1599,11 @@ void UI_but_func_hold_set(uiBut *but, uiButHandleHoldFunc func, void *argN);
void UI_but_func_pushed_state_set(uiBut *but, uiButPushedStateFunc func, void *arg);
+PointerRNA *UI_but_extra_operator_icon_add(uiBut *but,
+ const char *opname,
+ short opcontext,
+ int icon);
+
/* Autocomplete
*
* Tab complete helper functions, for use in uiButCompleteFunc callbacks.
@@ -1803,6 +1811,7 @@ void uiLayoutSetActivateInit(uiLayout *layout, bool active);
void uiLayoutSetEnabled(uiLayout *layout, bool enabled);
void uiLayoutSetRedAlert(uiLayout *layout, bool redalert);
void uiLayoutSetAlignment(uiLayout *layout, char alignment);
+void uiLayoutSetFixedSize(uiLayout *layout, bool fixed_size);
void uiLayoutSetKeepAspect(uiLayout *layout, bool keepaspect);
void uiLayoutSetScaleX(uiLayout *layout, float scale);
void uiLayoutSetScaleY(uiLayout *layout, float scale);
@@ -1820,6 +1829,7 @@ bool uiLayoutGetActivateInit(uiLayout *layout);
bool uiLayoutGetEnabled(uiLayout *layout);
bool uiLayoutGetRedAlert(uiLayout *layout);
int uiLayoutGetAlignment(uiLayout *layout);
+bool uiLayoutGetFixedSize(uiLayout *layout);
bool uiLayoutGetKeepAspect(uiLayout *layout);
int uiLayoutGetWidth(uiLayout *layout);
float uiLayoutGetScaleX(uiLayout *layout);
@@ -2081,6 +2091,9 @@ void uiTemplateColormanagedViewSettings(struct uiLayout *layout,
const char *propname);
int uiTemplateRecentFiles(struct uiLayout *layout, int rows);
+void uiTemplateFileSelectPath(uiLayout *layout,
+ struct bContext *C,
+ struct FileSelectParams *params);
/* items */
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname);
@@ -2441,6 +2454,8 @@ void UI_widgetbase_draw_cache_end(void);
void UI_theme_init_default(void);
void UI_style_init_default(void);
+void UI_interface_tag_script_reload(void);
+
/* Special drawing for toolbar, mainly workarounds for inflexible icon sizing. */
#define USE_UI_TOOLBAR_HACK
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index 29022adac6c..76ab4a53eb8 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -234,6 +234,8 @@ typedef enum ThemeColorID {
TH_DIS_MARKER,
TH_PATH_BEFORE,
TH_PATH_AFTER,
+ TH_PATH_KEYFRAME_BEFORE,
+ TH_PATH_KEYFRAME_AFTER,
TH_CAMERA_PATH,
TH_LOCK_MARKER,
@@ -273,6 +275,7 @@ typedef enum ThemeColorID {
TH_ICON_OBJECT_DATA,
TH_ICON_MODIFIER,
TH_ICON_SHADING,
+ TH_ICON_FOLDER,
TH_ICON_FUND,
TH_SCROLL_TEXT,
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 66c8eadbd74..f05100e9065 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -1469,6 +1469,187 @@ void ui_but_override_flag(uiBut *but)
}
}
+/** \name Button Extra Operator Icons
+ *
+ * Extra icons are shown on the right hand side of buttons. They can be clicked to invoke custom
+ * operators.
+ * There are some predefined here, which get added to buttons automatically based on button data
+ * (type, flags, state, etc).
+ * \{ */
+
+/**
+ * Predefined types for generic extra operator icons (uiButExtraOpIcon).
+ */
+typedef enum PredefinedExtraOpIconType {
+ PREDEFINED_EXTRA_OP_ICON_NONE = 1,
+ PREDEFINED_EXTRA_OP_ICON_CLEAR,
+ PREDEFINED_EXTRA_OP_ICON_EYEDROPPER,
+} PredefinedExtraOpIconType;
+
+static PointerRNA *ui_but_extra_operator_icon_add_ptr(uiBut *but,
+ wmOperatorType *optype,
+ short opcontext,
+ int icon)
+{
+ uiButExtraOpIcon *extra_op_icon = MEM_mallocN(sizeof(*extra_op_icon), __func__);
+
+ extra_op_icon->icon = (BIFIconID)icon;
+ extra_op_icon->optype_params = MEM_callocN(sizeof(*extra_op_icon->optype_params),
+ "uiButExtraOpIcon.optype_hook");
+ extra_op_icon->optype_params->optype = optype;
+ extra_op_icon->optype_params->opptr = MEM_callocN(sizeof(*extra_op_icon->optype_params->opptr),
+ "uiButExtraOpIcon.optype_hook.opptr");
+ WM_operator_properties_create_ptr(extra_op_icon->optype_params->opptr,
+ extra_op_icon->optype_params->optype);
+ extra_op_icon->optype_params->opcontext = opcontext;
+
+ BLI_addtail(&but->extra_op_icons, extra_op_icon);
+
+ return extra_op_icon->optype_params->opptr;
+}
+
+static void ui_but_extra_operator_icon_free(uiButExtraOpIcon *extra_icon)
+{
+ WM_operator_properties_free(extra_icon->optype_params->opptr);
+ MEM_freeN(extra_icon->optype_params->opptr);
+ MEM_freeN(extra_icon->optype_params);
+ MEM_freeN(extra_icon);
+}
+
+void ui_but_extra_operator_icons_free(uiBut *but)
+{
+
+ for (uiButExtraOpIcon *op_icon = but->extra_op_icons.first, *op_icon_next; op_icon;
+ op_icon = op_icon_next) {
+ op_icon_next = op_icon->next;
+ ui_but_extra_operator_icon_free(op_icon);
+ }
+ BLI_listbase_clear(&but->extra_op_icons);
+}
+
+PointerRNA *UI_but_extra_operator_icon_add(uiBut *but,
+ const char *opname,
+ short opcontext,
+ int icon)
+{
+ wmOperatorType *optype = WM_operatortype_find(opname, false);
+
+ if (optype) {
+ return ui_but_extra_operator_icon_add_ptr(but, optype, opcontext, icon);
+ }
+
+ return NULL;
+}
+
+static bool ui_but_icon_extra_is_visible_text_clear(const uiBut *but)
+{
+ BLI_assert(but->type == UI_BTYPE_TEXT);
+ return ((but->flag & UI_BUT_VALUE_CLEAR) && but->drawstr[0]);
+}
+
+static bool ui_but_icon_extra_is_visible_search_unlink(const uiBut *but)
+{
+ BLI_assert(ELEM(but->type, UI_BTYPE_SEARCH_MENU));
+ return ((but->editstr == NULL) && (but->drawstr[0] != '\0') && (but->flag & UI_BUT_VALUE_CLEAR));
+}
+
+static bool ui_but_icon_extra_is_visible_search_eyedropper(uiBut *but)
+{
+ StructRNA *type;
+ short idcode;
+
+ BLI_assert(but->type == UI_BTYPE_SEARCH_MENU && (but->flag & UI_BUT_VALUE_CLEAR));
+
+ if (but->rnaprop == NULL) {
+ return false;
+ }
+
+ type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop);
+ idcode = RNA_type_to_ID_code(type);
+
+ return ((but->editstr == NULL) && (idcode == ID_OB || OB_DATA_SUPPORT_ID(idcode)));
+}
+
+static PredefinedExtraOpIconType ui_but_icon_extra_get(uiBut *but)
+{
+ switch (but->type) {
+ case UI_BTYPE_TEXT:
+ if (ui_but_icon_extra_is_visible_text_clear(but)) {
+ return PREDEFINED_EXTRA_OP_ICON_CLEAR;
+ }
+ break;
+ case UI_BTYPE_SEARCH_MENU:
+ if ((but->flag & UI_BUT_VALUE_CLEAR) == 0) {
+ /* pass */
+ }
+ else if (ui_but_icon_extra_is_visible_search_unlink(but)) {
+ return PREDEFINED_EXTRA_OP_ICON_CLEAR;
+ }
+ else if (ui_but_icon_extra_is_visible_search_eyedropper(but)) {
+ return PREDEFINED_EXTRA_OP_ICON_EYEDROPPER;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return PREDEFINED_EXTRA_OP_ICON_NONE;
+}
+
+/**
+ * While some extra operator icons have to be set explicitly upon button creating, this code adds
+ * some generic ones based on button data. Currently these are mutually exclusive, so there's only
+ * ever one predefined extra icon.
+ */
+static void ui_but_predefined_extra_operator_icons_add(uiBut *but)
+{
+ PredefinedExtraOpIconType extra_icon = ui_but_icon_extra_get(but);
+ wmOperatorType *optype = NULL;
+ BIFIconID icon = ICON_NONE;
+
+ switch (extra_icon) {
+ case PREDEFINED_EXTRA_OP_ICON_EYEDROPPER: {
+ static wmOperatorType *id_eyedropper_ot = NULL;
+ if (!id_eyedropper_ot) {
+ id_eyedropper_ot = WM_operatortype_find("UI_OT_eyedropper_id", false);
+ }
+ BLI_assert(id_eyedropper_ot);
+
+ optype = id_eyedropper_ot;
+ icon = ICON_EYEDROPPER;
+
+ break;
+ }
+ case PREDEFINED_EXTRA_OP_ICON_CLEAR: {
+ static wmOperatorType *clear_ot = NULL;
+ if (!clear_ot) {
+ clear_ot = WM_operatortype_find("UI_OT_button_string_clear", false);
+ }
+ BLI_assert(clear_ot);
+
+ optype = clear_ot;
+ icon = ICON_PANEL_CLOSE;
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (optype) {
+ for (uiButExtraOpIcon *op_icon = but->extra_op_icons.first; op_icon; op_icon = op_icon->next) {
+ if ((op_icon->optype_params->optype == optype) && (op_icon->icon == icon)) {
+ /* Don't add the same operator icon twice (happens if button is kept alive while active).
+ */
+ return;
+ }
+ }
+ ui_but_extra_operator_icon_add_ptr(but, optype, WM_OP_INVOKE_DEFAULT, (int)icon);
+ }
+}
+
+/** \} */
+
void UI_block_update_from_old(const bContext *C, uiBlock *block)
{
uiBut *but_old;
@@ -1541,6 +1722,7 @@ void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2], int r_x
if (UI_but_is_decorator(but)) {
ui_but_anim_decorate_update_from_flag(but);
}
+ ui_but_predefined_extra_operator_icons_add(but);
}
/* handle pending stuff */
@@ -2281,69 +2463,6 @@ uiBut *ui_but_drag_multi_edit_get(uiBut *but)
return but_iter;
}
-/** \name Check to show extra icons
- *
- * Extra icons are shown on the right hand side of buttons.
- * This could (should!) definitely become more generic, but for now this is good enough.
- * \{ */
-
-static bool ui_but_icon_extra_is_visible_text_clear(const uiBut *but)
-{
- BLI_assert(but->type == UI_BTYPE_TEXT);
- return ((but->flag & UI_BUT_VALUE_CLEAR) && but->drawstr[0]);
-}
-
-static bool ui_but_icon_extra_is_visible_search_unlink(const uiBut *but)
-{
- BLI_assert(ELEM(but->type, UI_BTYPE_SEARCH_MENU));
- return ((but->editstr == NULL) && (but->drawstr[0] != '\0') && (but->flag & UI_BUT_VALUE_CLEAR));
-}
-
-static bool ui_but_icon_extra_is_visible_search_eyedropper(uiBut *but)
-{
- StructRNA *type;
- short idcode;
-
- BLI_assert(but->type == UI_BTYPE_SEARCH_MENU && (but->flag & UI_BUT_VALUE_CLEAR));
-
- if (but->rnaprop == NULL) {
- return false;
- }
-
- type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop);
- idcode = RNA_type_to_ID_code(type);
-
- return ((but->editstr == NULL) && (idcode == ID_OB || OB_DATA_SUPPORT_ID(idcode)));
-}
-
-uiButExtraIconType ui_but_icon_extra_get(uiBut *but)
-{
- switch (but->type) {
- case UI_BTYPE_TEXT:
- if (ui_but_icon_extra_is_visible_text_clear(but)) {
- return UI_BUT_ICONEXTRA_CLEAR;
- }
- break;
- case UI_BTYPE_SEARCH_MENU:
- if ((but->flag & UI_BUT_VALUE_CLEAR) == 0) {
- /* pass */
- }
- else if (ui_but_icon_extra_is_visible_search_unlink(but)) {
- return UI_BUT_ICONEXTRA_CLEAR;
- }
- else if (ui_but_icon_extra_is_visible_search_eyedropper(but)) {
- return UI_BUT_ICONEXTRA_EYEDROPPER;
- }
- break;
- default:
- break;
- }
-
- return UI_BUT_ICONEXTRA_NONE;
-}
-
-/** \} */
-
static double ui_get_but_scale_unit(uiBut *but, double value)
{
UnitSettings *unit = but->block->unit;
@@ -2509,7 +2628,7 @@ void ui_but_string_get_ex(uiBut *but,
else if (buf && buf != str) {
BLI_assert(maxlen <= buf_len + 1);
/* string was too long, we have to truncate */
- if (ui_but_is_utf8(but)) {
+ if (UI_but_is_utf8(but)) {
BLI_strncpy_utf8(str, buf, maxlen);
}
else {
@@ -2834,7 +2953,7 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str)
if (!but->poin) {
str = "";
}
- else if (ui_but_is_utf8(but)) {
+ else if (UI_but_is_utf8(but)) {
BLI_strncpy_utf8(but->poin, str, but->hardmax);
}
else {
@@ -3087,6 +3206,7 @@ static void ui_but_free(const bContext *C, uiBut *but)
if (but->dragpoin && (but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
MEM_freeN(but->dragpoin);
}
+ ui_but_extra_operator_icons_free(but);
BLI_assert(UI_butstore_is_registered(but->block, but) == false);
@@ -3586,6 +3706,14 @@ static uiBut *ui_def_but(uiBlock *block,
(a1 != 0.0f && a1 != 1.0f)) == false);
}
+ /* Number buttons must have a click-step,
+ * assert instead of correcting the value to ensure the caller knows what they're doing. */
+ if ((type & BUTTYPE) == UI_BTYPE_NUM) {
+ if (ELEM((type & UI_BUT_POIN_TYPES), UI_BUT_POIN_CHAR, UI_BUT_POIN_SHORT, UI_BUT_POIN_INT)) {
+ BLI_assert((int)a1 > 0);
+ }
+ }
+
if (type & UI_BUT_POIN_TYPES) { /* a pointer is required */
if (poin == NULL) {
BLI_assert(0);
@@ -4242,7 +4370,7 @@ static uiBut *ui_def_but_operator_ptr(uiBlock *block,
}
}
- if ((!tip || tip[0] == '\0') && ot && ot->srna) {
+ if ((!tip || tip[0] == '\0') && ot && ot->srna && !ot->get_description) {
tip = RNA_struct_ui_description(ot->srna);
}
@@ -6342,6 +6470,9 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
else if (but->tip && but->tip[0]) {
tmp = BLI_strdup(but->tip);
}
+ else if (but->optype && but->optype->get_description) {
+ tmp = WM_operatortype_description(C, but->optype, but->opptr);
+ }
else {
type = BUT_GET_RNA_TIP; /* Fail-safe solution... */
}
@@ -6558,3 +6689,8 @@ void UI_exit(void)
ui_resources_free();
ui_but_clipboard_free();
}
+
+void UI_interface_tag_script_reload(void)
+{
+ ui_interface_tag_script_reload_queries();
+}
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 168c6051327..c8baa1a7c7b 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -243,7 +243,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str)
}
/* create driver */
- fcu = verify_driver_fcurve(id, path, but->rnaindex, 1);
+ fcu = verify_driver_fcurve(id, path, but->rnaindex, DRIVER_FCURVE_KEYFRAMES);
if (fcu) {
ChannelDriver *driver = fcu->driver;
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index 0884a9ea470..b84b07adba5 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -176,11 +176,21 @@ static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg)
UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT);
UI_block_direction_set(block, UI_DIR_CENTER_Y);
- layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, 200, 20, 0, style);
-
+ layout = UI_block_layout(block,
+ UI_LAYOUT_VERTICAL,
+ UI_LAYOUT_PANEL,
+ 0,
+ 0,
+ U.widget_unit * 10,
+ U.widget_unit * 2,
+ 0,
+ style);
+
+ uiItemL(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Change Shortcut"), ICON_HAND);
uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT | UI_ITEM_R_IMMEDIATE, "", ICON_NONE);
- UI_block_bounds_set_popup(block, 6, (const int[2]){-50, 26});
+ UI_block_bounds_set_popup(
+ block, 6 * U.dpi_fac, (const int[2]){-100 * U.dpi_fac, 36 * U.dpi_fac});
shortcut_free_operator_property(prop);
@@ -227,11 +237,21 @@ static uiBlock *menu_add_shortcut(bContext *C, ARegion *ar, void *arg)
UI_block_func_handle_set(block, but_shortcut_name_func, but);
UI_block_direction_set(block, UI_DIR_CENTER_Y);
- layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, 200, 20, 0, style);
-
+ layout = UI_block_layout(block,
+ UI_LAYOUT_VERTICAL,
+ UI_LAYOUT_PANEL,
+ 0,
+ 0,
+ U.widget_unit * 10,
+ U.widget_unit * 2,
+ 0,
+ style);
+
+ uiItemL(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Assign Shortcut"), ICON_HAND);
uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT | UI_ITEM_R_IMMEDIATE, "", ICON_NONE);
- UI_block_bounds_set_popup(block, 6, (const int[2]){-50, 26});
+ UI_block_bounds_set_popup(
+ block, 6 * U.dpi_fac, (const int[2]){-100 * U.dpi_fac, 36 * U.dpi_fac});
#ifdef USE_KEYMAP_ADD_HACK
g_kmi_id_hack = kmi_id;
@@ -470,8 +490,9 @@ static void ui_but_menu_add_path_operators(uiLayout *layout, PointerRNA *ptr, Pr
bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
{
- /* having this menu for some buttons makes no sense */
- if (but->type == UI_BTYPE_IMAGE) {
+ /* ui_but_is_interactive() may let some buttons through that should not get a context menu - it
+ * doesn't make sense for them. */
+ if (ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_IMAGE)) {
return false;
}
@@ -878,13 +899,13 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
if (is_array_component) {
uiItemBooleanO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy All To Selected"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy All to Selected"),
ICON_NONE,
"UI_OT_copy_to_selected_button",
"all",
true);
uiItemBooleanO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Single To Selected"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Single to Selected"),
ICON_NONE,
"UI_OT_copy_to_selected_button",
"all",
@@ -892,7 +913,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
}
else {
uiItemBooleanO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy To Selected"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy to Selected"),
ICON_NONE,
"UI_OT_copy_to_selected_button",
"all",
@@ -907,7 +928,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
if (ptr->owner_id && !is_whole_array &&
ELEM(type, PROP_BOOLEAN, PROP_INT, PROP_FLOAT, PROP_ENUM)) {
uiItemO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy As New Driver"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy as New Driver"),
ICON_NONE,
"UI_OT_copy_as_driver_button");
}
@@ -929,7 +950,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
but->search_func == ui_rna_collection_search_cb)) &&
ui_jump_to_target_button_poll(C)) {
uiItemO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Jump To Target"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Jump to Target"),
ICON_NONE,
"UI_OT_jump_to_target_button");
uiItemS(layout);
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 76630de96db..72c31c7b39e 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -750,7 +750,7 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(ar),
/**
* Draw title and text safe areas.
*
- * \Note This functionn is to be used with the 2D dashed shader enabled.
+ * \note This function is to be used with the 2D dashed shader enabled.
*
* \param pos: is a PRIM_FLOAT, 2, GPU_FETCH_FLOAT vertex attribute.
* \param line_origin: is a PRIM_FLOAT, 2, GPU_FETCH_FLOAT vertex attribute.
@@ -1849,9 +1849,17 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, const uiWidgetColors *wcol, cons
cumap = (CurveMapping *)but->poin;
}
+ float clip_size_x = BLI_rctf_size_x(&cumap->curr);
+ float clip_size_y = BLI_rctf_size_y(&cumap->curr);
+
+ /* zero-sized curve */
+ if (clip_size_x == 0.0f || clip_size_y == 0.0f) {
+ return;
+ }
+
/* calculate offset and zoom */
- float zoomx = (BLI_rcti_size_x(rect) - 2.0f) / BLI_rctf_size_x(&cumap->curr);
- float zoomy = (BLI_rcti_size_y(rect) - 2.0f) / BLI_rctf_size_y(&cumap->curr);
+ float zoomx = (BLI_rcti_size_x(rect) - 2.0f) / clip_size_x;
+ float zoomy = (BLI_rcti_size_y(rect) - 2.0f) / clip_size_y;
float offsx = cumap->curr.xmin - (1.0f / zoomx);
float offsy = cumap->curr.ymin - (1.0f / zoomy);
@@ -2220,8 +2228,8 @@ void ui_draw_but_TRACKPREVIEW(ARegion *UNUSED(ar),
/* Do stipple cross with geometry */
immBegin(GPU_PRIM_LINES, 7 * 2 * 2);
float pos_sel[8] = {-10.0f, -7.0f, -4.0f, -1.0f, 2.0f, 5.0f, 8.0f, 11.0f};
- for (int axe = 0; axe < 2; ++axe) {
- for (int i = 0; i < 7; ++i) {
+ for (int axe = 0; axe < 2; axe++) {
+ for (int i = 0; i < 7; i++) {
float x1 = pos_sel[i] * (1 - axe);
float y1 = pos_sel[i] * axe;
float x2 = pos_sel[i + 1] * (1 - axe);
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 68c12fe7652..0cf357c508b 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -290,7 +290,7 @@ static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
{
/* init */
if (eyedropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
@@ -332,7 +332,7 @@ void UI_OT_eyedropper_color(wmOperatorType *ot)
/* identifiers */
ot->name = "Eyedropper";
ot->idname = "UI_OT_eyedropper_color";
- ot->description = "Sample a color from the Blender Window to store in a property";
+ ot->description = "Sample a color from the Blender window to store in a property";
/* api callbacks */
ot->invoke = eyedropper_invoke;
diff --git a/source/blender/editors/interface/interface_eyedropper_colorband.c b/source/blender/editors/interface/interface_eyedropper_colorband.c
index ffe93e48936..479cf9ccffe 100644
--- a/source/blender/editors/interface/interface_eyedropper_colorband.c
+++ b/source/blender/editors/interface/interface_eyedropper_colorband.c
@@ -304,7 +304,7 @@ static int eyedropper_colorband_invoke(bContext *C, wmOperator *op, const wmEven
{
/* init */
if (eyedropper_colorband_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c
index 336fae45895..fd5a46e7716 100644
--- a/source/blender/editors/interface/interface_eyedropper_datablock.c
+++ b/source/blender/editors/interface/interface_eyedropper_datablock.c
@@ -314,7 +314,7 @@ static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED
{
/* init */
if (datadropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c
index 2e51701e01d..8a48ca19db2 100644
--- a/source/blender/editors/interface/interface_eyedropper_depth.c
+++ b/source/blender/editors/interface/interface_eyedropper_depth.c
@@ -311,7 +311,7 @@ static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
{
/* init */
if (depthdropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/interface_eyedropper_driver.c
index e6fc52bc3bc..cc13367c190 100644
--- a/source/blender/editors/interface/interface_eyedropper_driver.c
+++ b/source/blender/editors/interface/interface_eyedropper_driver.c
@@ -180,7 +180,7 @@ static int driverdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
{
/* init */
if (driverdropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 13bfaa95077..e0442ebcca2 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -153,6 +153,13 @@ typedef enum uiHandleButtonState {
BUTTON_STATE_EXIT,
} uiHandleButtonState;
+typedef enum uiMenuScrollType {
+ MENU_SCROLL_UP,
+ MENU_SCROLL_DOWN,
+ MENU_SCROLL_TOP,
+ MENU_SCROLL_BOTTOM,
+} uiMenuScrollType;
+
#ifdef USE_ALLSELECT
/* Unfortunately there's no good way handle more generally:
@@ -2673,15 +2680,19 @@ void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR],
/** \name Button Text Selection/Editing
* \{ */
-static void ui_textedit_string_clear_and_exit(bContext *C, uiBut *but, uiHandleButtonData *data)
+void ui_but_active_string_clear_and_exit(bContext *C, uiBut *but)
{
+ if (!but->active) {
+ return;
+ }
+
/* most likely NULL, but let's check, and give it temp zero string */
- if (!data->str) {
- data->str = MEM_callocN(1, "temp str");
+ if (!but->active->str) {
+ but->active->str = MEM_callocN(1, "temp str");
}
- data->str[0] = 0;
+ but->active->str[0] = 0;
- ui_apply_but_TEX(C, but, data);
+ ui_apply_but_TEX(C, but, but->active);
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
@@ -2702,7 +2713,7 @@ static void ui_textedit_string_set(uiBut *but, uiHandleButtonData *data, const c
ui_textedit_string_ensure_max_length(but, data, strlen(str) + 1);
}
- if (ui_but_is_utf8(but)) {
+ if (UI_but_is_utf8(but)) {
BLI_strncpy_utf8(data->str, str, data->maxlen);
}
else {
@@ -2760,7 +2771,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
startx += UI_DPI_ICON_SIZE / aspect;
}
}
- /* but this extra .05 makes clicks inbetween characters feel nicer */
+ /* But this extra .05 makes clicks in between characters feel nicer. */
startx += ((UI_TEXT_MARGIN_X + 0.05f) * U.widget_unit) / aspect;
/* mouse dragged outside the widget to the left */
@@ -2887,7 +2898,7 @@ static bool ui_textedit_insert_buf(uiBut *but,
}
if ((len + step >= data->maxlen) && (data->maxlen - (len + 1) > 0)) {
- if (ui_but_is_utf8(but)) {
+ if (UI_but_is_utf8(but)) {
/* shorten 'step' to a utf8 aligned size that fits */
BLI_strnlen_utf8_ex(buf, data->maxlen - (len + 1), &step);
}
@@ -2911,7 +2922,7 @@ static bool ui_textedit_insert_ascii(uiBut *but, uiHandleButtonData *data, char
{
char buf[2] = {ascii, '\0'};
- if (ui_but_is_utf8(but) && (BLI_str_utf8_size(buf) == -1)) {
+ if (UI_but_is_utf8(but) && (BLI_str_utf8_size(buf) == -1)) {
printf(
"%s: entering invalid ascii char into an ascii key (%d)\n", __func__, (int)(uchar)ascii);
@@ -3092,7 +3103,7 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in
pbuf = WM_clipboard_text_get_firstline(false, &buf_len);
if (pbuf) {
- if (ui_but_is_utf8(but)) {
+ if (UI_but_is_utf8(but)) {
buf_len -= BLI_utf8_invalid_strip(pbuf, (size_t)buf_len);
}
@@ -3247,7 +3258,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
ui_but_update(but);
- WM_cursor_modal_set(win, BC_TEXTEDITCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_TEXT_EDIT);
#ifdef WITH_INPUT_IME
if (is_num_but == false && BLT_lang_is_ime_supported()) {
@@ -3261,7 +3272,7 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
wmWindow *win = CTX_wm_window(C);
if (but) {
- if (ui_but_is_utf8(but)) {
+ if (UI_but_is_utf8(but)) {
int strip = BLI_utf8_invalid_strip(but->editstr, strlen(but->editstr));
/* not a file?, strip non utf-8 chars */
if (strip) {
@@ -3768,6 +3779,19 @@ static void ui_numedit_apply(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
ED_region_tag_redraw(data->region);
}
+static void ui_but_extra_operator_icon_apply(bContext *C, uiBut *but, uiButExtraOpIcon *op_icon)
+{
+ WM_operator_name_call_ptr(C,
+ op_icon->optype_params->optype,
+ op_icon->optype_params->opcontext,
+ op_icon->optype_params->opptr);
+
+ /* Force recreation of extra operator icons (pseudo update). */
+ ui_but_extra_operator_icons_free(but);
+
+ WM_event_add_mousemove(C);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -3911,6 +3935,46 @@ static uiBut *ui_but_list_row_text_activate(bContext *C,
/** \name Events for Various Button Types
* \{ */
+static uiButExtraOpIcon *ui_but_extra_operator_icon_mouse_over_get(uiBut *but,
+ uiHandleButtonData *data,
+ const wmEvent *event)
+{
+ float xmax = but->rect.xmax;
+ const float icon_size = BLI_rctf_size_y(&but->rect);
+ int x = event->x, y = event->y;
+
+ ui_window_to_block(data->region, but->block, &x, &y);
+ if (!BLI_rctf_isect_pt(&but->rect, x, y)) {
+ return NULL;
+ }
+
+ /* Inverse order, from right to left. */
+ for (uiButExtraOpIcon *op_icon = but->extra_op_icons.last; op_icon; op_icon = op_icon->prev) {
+ if ((x > (xmax - icon_size)) && x < xmax) {
+ return op_icon;
+ }
+ xmax -= icon_size;
+ }
+
+ return NULL;
+}
+
+static bool ui_do_but_extra_operator_icon(bContext *C,
+ uiBut *but,
+ uiHandleButtonData *data,
+ const wmEvent *event)
+{
+ uiButExtraOpIcon *op_icon = ui_but_extra_operator_icon_mouse_over_get(but, data, event);
+
+ if (op_icon) {
+ ui_but_extra_operator_icon_apply(C, but, op_icon);
+ button_activate_exit(C, but, data, false, false);
+ return true;
+ }
+
+ return false;
+}
+
#ifdef USE_DRAG_TOGGLE
/* Shared by any button that supports drag-toggle. */
static bool ui_do_but_ANY_drag_toggle(
@@ -4098,23 +4162,6 @@ static int ui_do_but_KEYEVT(bContext *C,
return WM_UI_HANDLER_CONTINUE;
}
-static bool ui_but_is_mouse_over_icon_extra(const ARegion *region,
- uiBut *but,
- const int mouse_xy[2])
-{
- int x = mouse_xy[0], y = mouse_xy[1];
- rcti icon_rect;
-
- BLI_assert(ui_but_icon_extra_get(but) != UI_BUT_ICONEXTRA_NONE);
-
- ui_window_to_block(region, but->block, &x, &y);
-
- BLI_rcti_rctf_copy(&icon_rect, &but->rect);
- icon_rect.xmin = icon_rect.xmax - (BLI_rcti_size_y(&icon_rect));
-
- return BLI_rcti_isect_pt(&icon_rect, x, y);
-}
-
static int ui_do_but_TAB(
bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
@@ -4162,21 +4209,14 @@ static int ui_do_but_TEX(
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS) {
- if (ELEM(event->type, PADENTER, RETKEY) && (!ui_but_is_utf8(but))) {
+ if (ELEM(event->type, PADENTER, RETKEY) && (!UI_but_is_utf8(but))) {
/* pass - allow filesel, enter to execute */
}
else if (but->dt == UI_EMBOSS_NONE && !event->ctrl) {
/* pass */
}
- else {
- const bool has_icon_extra = ui_but_icon_extra_get(but) == UI_BUT_ICONEXTRA_CLEAR;
-
- if (has_icon_extra && ui_but_is_mouse_over_icon_extra(data->region, but, &event->x)) {
- ui_textedit_string_clear_and_exit(C, but, data);
- }
- else {
- button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
- }
+ else if (!ui_but_extra_operator_icon_mouse_over_get(but, data, event)) {
+ button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
return WM_UI_HANDLER_BREAK;
}
}
@@ -4196,27 +4236,12 @@ static int ui_do_but_TEX(
static int ui_do_but_SEARCH_UNLINK(
bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
- const uiButExtraIconType extra_icon_type = ui_but_icon_extra_get(but);
- const bool has_icon_extra = (extra_icon_type != UI_BUT_ICONEXTRA_NONE);
-
/* unlink icon is on right */
- if ((ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY)) && (has_icon_extra == true) &&
- (ui_but_is_mouse_over_icon_extra(data->region, but, &event->x) == true)) {
+ if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY)) {
/* doing this on KM_PRESS calls eyedropper after clicking unlink icon */
- if (event->val == KM_RELEASE) {
- /* unlink */
- if (extra_icon_type == UI_BUT_ICONEXTRA_CLEAR) {
- ui_textedit_string_clear_and_exit(C, but, data);
- }
- /* eyedropper */
- else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {
- WM_operator_name_call(C, "UI_OT_eyedropper_id", WM_OP_INVOKE_DEFAULT, NULL);
- }
- else {
- BLI_assert(0);
- }
+ if ((event->val == KM_RELEASE) && ui_do_but_extra_operator_icon(C, but, data, event)) {
+ return WM_UI_HANDLER_BREAK;
}
- return WM_UI_HANDLER_BREAK;
}
return ui_do_but_TEX(C, block, but, data, event);
}
@@ -4299,7 +4324,7 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
if (data->state == BUTTON_STATE_HIGHLIGHT) {
/* first handle click on icondrag type button */
- if (event->type == LEFTMOUSE && but->dragpoin) {
+ if ((event->type == LEFTMOUSE) && (event->val == KM_PRESS) && but->dragpoin) {
if (ui_but_contains_point_px_icon(but, data->region, event)) {
/* tell the button to wait and keep checking further events to
@@ -4311,7 +4336,7 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
}
}
#ifdef USE_DRAG_TOGGLE
- if (event->type == LEFTMOUSE && ui_but_is_drag_toggle(but)) {
+ if ((event->type == LEFTMOUSE) && (event->val == KM_PRESS) && ui_but_is_drag_toggle(but)) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
data->dragstartx = event->x;
data->dragstarty = event->y;
@@ -4660,7 +4685,7 @@ static void ui_numedit_set_active(uiBut *but)
}
else {
if (data->changed_cursor == false) {
- WM_cursor_modal_set(data->window, CURSOR_X_MOVE);
+ WM_cursor_modal_set(data->window, WM_CURSOR_X_MOVE);
data->changed_cursor = true;
}
}
@@ -6976,6 +7001,14 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
if (event->type == EVT_DROP) {
ui_but_drop(C, event, but, data);
}
+
+ if ((data->state == BUTTON_STATE_HIGHLIGHT) &&
+ ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) &&
+ (event->val == KM_RELEASE) &&
+ /* Only returns true if the event was handled. */
+ ui_do_but_extra_operator_icon(C, but, data, event)) {
+ return WM_UI_HANDLER_BREAK;
+ }
}
if (but->flag & UI_BUT_DISABLED) {
@@ -7531,7 +7564,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
if (but->type == UI_BTYPE_GRIP) {
const bool horizontal = (BLI_rctf_size_x(&but->rect) < BLI_rctf_size_y(&but->rect));
- WM_cursor_modal_set(data->window, horizontal ? CURSOR_X_MOVE : CURSOR_Y_MOVE);
+ WM_cursor_modal_set(data->window, horizontal ? WM_CURSOR_X_MOVE : WM_CURSOR_Y_MOVE);
}
else if (but->type == UI_BTYPE_NUM) {
ui_numedit_set_active(but);
@@ -9095,6 +9128,10 @@ static int ui_handle_menu_event(bContext *C,
}
case UPARROWKEY:
case DOWNARROWKEY:
+ case PAGEUPKEY:
+ case PAGEDOWNKEY:
+ case HOMEKEY:
+ case ENDKEY:
case MOUSEPAN:
/* arrowkeys: only handle for block_loop blocks */
if (IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) {
@@ -9110,8 +9147,22 @@ static int ui_handle_menu_event(bContext *C,
}
if (val == KM_PRESS) {
- const bool is_next = (ELEM(type, DOWNARROWKEY, WHEELDOWNMOUSE) ==
- ((block->flag & UI_BLOCK_IS_FLIP) != 0));
+ /* Determine scroll operation. */
+ uiMenuScrollType scrolltype;
+ bool ui_block_flipped = (block->flag & UI_BLOCK_IS_FLIP) != 0;
+
+ if (ELEM(type, PAGEUPKEY, HOMEKEY)) {
+ scrolltype = ui_block_flipped ? MENU_SCROLL_TOP : MENU_SCROLL_BOTTOM;
+ }
+ else if (ELEM(type, PAGEDOWNKEY, ENDKEY)) {
+ scrolltype = ui_block_flipped ? MENU_SCROLL_BOTTOM : MENU_SCROLL_TOP;
+ }
+ else if (ELEM(type, UPARROWKEY, WHEELUPMOUSE)) {
+ scrolltype = ui_block_flipped ? MENU_SCROLL_UP : MENU_SCROLL_DOWN;
+ }
+ else {
+ scrolltype = ui_block_flipped ? MENU_SCROLL_DOWN : MENU_SCROLL_UP;
+ }
if (ui_menu_pass_event_to_parent_if_nonactive(menu, but, level, retval)) {
break;
@@ -9123,16 +9174,24 @@ static int ui_handle_menu_event(bContext *C,
but = ui_region_find_active_but(ar);
if (but) {
- /* next button */
- but = is_next ? ui_but_next(but) : ui_but_prev(but);
- }
-
- if (!but) {
- /* wrap button */
- uiBut *but_wrap;
- but_wrap = is_next ? ui_but_first(block) : ui_but_last(block);
- if (but_wrap) {
- but = but_wrap;
+ /* Apply scroll operation. */
+ if (scrolltype == MENU_SCROLL_DOWN) {
+ but = ui_but_next(but);
+ if (but == NULL) {
+ but = ui_but_first(block);
+ }
+ }
+ else if (scrolltype == MENU_SCROLL_UP) {
+ but = ui_but_prev(but);
+ if (but == NULL) {
+ but = ui_but_last(block);
+ }
+ }
+ else if (scrolltype == MENU_SCROLL_TOP) {
+ but = ui_but_first(block);
+ }
+ else if (scrolltype == MENU_SCROLL_BOTTOM) {
+ but = ui_but_last(block);
}
}
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 1674374396f..b844e237366 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -27,7 +27,6 @@
#include "MEM_guardedalloc.h"
-#include "GPU_draw.h"
#include "GPU_matrix.h"
#include "GPU_batch.h"
#include "GPU_immediate.h"
@@ -154,8 +153,8 @@ typedef struct IconType {
} IconType;
/* ******************* STATIC LOCAL VARS ******************* */
-/* static here to cache results of icon directory scan, so it's not
- * scanning the filesystem each time the menu is drawn */
+/* Static here to cache results of icon directory scan, so it's not
+ * scanning the file-system each time the menu is drawn. */
static struct ListBase iconfilelist = {NULL, NULL};
static IconTexture icongltex = {{0, 0}, 0, 0, 0, 0.0f, 0.0f};
@@ -169,6 +168,7 @@ static const IconType icontypes[] = {
# define DEF_ICON_OBJECT_DATA(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_OBJECT_DATA},
# define DEF_ICON_MODIFIER(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_MODIFIER},
# define DEF_ICON_SHADING(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_SHADING},
+# define DEF_ICON_FOLDER(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_FOLDER},
# define DEF_ICON_FUND(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_FUND},
# define DEF_ICON_VECTOR(name) {ICON_TYPE_VECTOR, 0},
# define DEF_ICON_COLOR(name) {ICON_TYPE_COLOR_TEXTURE, 0},
@@ -553,6 +553,8 @@ static void init_brush_icons(void)
INIT_BRUSH_ICON(ICON_GPBRUSH_BLOCK, gp_brush_block);
INIT_BRUSH_ICON(ICON_GPBRUSH_MARKER, gp_brush_marker);
INIT_BRUSH_ICON(ICON_GPBRUSH_FILL, gp_brush_fill);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_AIRBRUSH, gp_brush_airbrush);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_CHISEL, gp_brush_chisel);
INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_SOFT, gp_brush_erase_soft);
INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_HARD, gp_brush_erase_hard);
INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_STROKE, gp_brush_erase_stroke);
@@ -775,7 +777,7 @@ static ImBuf *create_mono_icon_with_border(ImBuf *buf,
const int blurred_alpha_offset = by * (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) + bx;
const int offset_write = (sy + by) * buf->x + (sx + bx);
const float blurred_alpha = blurred_alpha_buffer[blurred_alpha_offset];
- float border_srgb[4] = {
+ const float border_srgb[4] = {
0, 0, 0, MIN2(1.0, blurred_alpha * border_sharpness) * border_intensity};
const unsigned int color_read = buf->rect[offset_write];
@@ -2059,6 +2061,12 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
case GP_BRUSH_ICON_FILL:
br->id.icon_id = ICON_GPBRUSH_FILL;
break;
+ case GP_BRUSH_ICON_AIRBRUSH:
+ br->id.icon_id = ICON_GPBRUSH_AIRBRUSH;
+ break;
+ case GP_BRUSH_ICON_CHISEL:
+ br->id.icon_id = ICON_GPBRUSH_CHISEL;
+ break;
case GP_BRUSH_ICON_ERASE_SOFT:
br->id.icon_id = ICON_GPBRUSH_ERASE_SOFT;
break;
@@ -2244,6 +2252,8 @@ int UI_idcode_icon_get(const int idcode)
return ICON_FONT_DATA;
case ID_WO:
return ICON_WORLD_DATA;
+ case ID_WS:
+ return ICON_WORKSPACE;
default:
return ICON_NONE;
}
diff --git a/source/blender/editors/interface/interface_icons_event.c b/source/blender/editors/interface/interface_icons_event.c
index 0992ee95fd7..e1ce77b8b61 100644
--- a/source/blender/editors/interface/interface_icons_event.c
+++ b/source/blender/editors/interface/interface_icons_event.c
@@ -29,8 +29,6 @@
#include "MEM_guardedalloc.h"
-#include "GPU_draw.h"
-#include "GPU_matrix.h"
#include "GPU_batch.h"
#include "GPU_immediate.h"
#include "GPU_state.h"
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index a5d9d35e2fe..4351b75eb86 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -78,14 +78,6 @@ enum {
/* warn: rest of uiBut->flag in UI_interface.h */
};
-/* some buttons display icons only under special conditions
- * (e.g. 'x' icon in search menu) - used with ui_but_icon_extra_get */
-typedef enum uiButExtraIconType {
- UI_BUT_ICONEXTRA_NONE = 1,
- UI_BUT_ICONEXTRA_CLEAR,
- UI_BUT_ICONEXTRA_EYEDROPPER,
-} uiButExtraIconType;
-
/* uiBut->dragflag */
enum {
UI_BUT_DRAGPOIN_FREE = (1 << 0),
@@ -262,6 +254,8 @@ struct uiBut {
short opcontext;
uchar menu_key; /* 'a'-'z', always lower case */
+ ListBase extra_op_icons; /* uiButExtraOpIcon */
+
/* Draggable data, type is WM_DRAG_... */
char dragtype;
short dragflag;
@@ -293,6 +287,16 @@ typedef struct uiButTab {
struct MenuType *menu;
} uiButTab;
+/**
+ * Additional, superimposed icon for a button, invoking an operator.
+ */
+typedef struct uiButExtraOpIcon {
+ struct uiButExtraOpIcon *next, *prev;
+
+ BIFIconID icon;
+ struct wmOperatorCallParams *optype_params;
+} uiButExtraOpIcon;
+
typedef struct ColorPicker {
struct ColorPicker *next, *prev;
/** Color data, may be HSV or HSL. */
@@ -497,14 +501,17 @@ extern bool ui_but_string_set_eval_num(struct bContext *C,
const char *str,
double *value) ATTR_NONNULL();
extern int ui_but_string_get_max_length(uiBut *but);
+/* Clear & exit the active button's string. */
+extern void ui_but_active_string_clear_and_exit(struct bContext *C, uiBut *but) ATTR_NONNULL();
extern uiBut *ui_but_drag_multi_edit_get(uiBut *but);
void ui_def_but_icon(uiBut *but, const int icon, const int flag);
void ui_def_but_icon_clear(uiBut *but);
-extern uiButExtraIconType ui_but_icon_extra_get(uiBut *but);
extern void ui_but_default_set(struct bContext *C, const bool all, const bool use_afterfunc);
+void ui_but_extra_operator_icons_free(uiBut *but);
+
extern void ui_but_rna_menu_convert_to_panel_type(struct uiBut *but, const char *panel_type);
extern void ui_but_rna_menu_convert_to_menu_type(struct uiBut *but, const char *menu_type);
extern bool ui_but_menu_draw_as_popover(const uiBut *but);
@@ -892,7 +899,6 @@ bool ui_but_is_editable(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_editable_as_text(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_toggle(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_interactive(const uiBut *but, const bool labeledit) ATTR_WARN_UNUSED_RESULT;
-bool ui_but_is_utf8(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_popover_once_compat(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_has_array_value(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
void ui_but_pie_dir(RadialDirection dir, float vec[2]);
@@ -987,4 +993,7 @@ void ui_rna_collection_search_cb(const struct bContext *C,
/* interface_ops.c */
bool ui_jump_to_target_button_poll(struct bContext *C);
+/* interface_queries.c */
+void ui_interface_tag_script_reload_queries(void);
+
#endif /* __INTERFACE_INTERN_H__ */
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 529cb0712df..a6f8ba4560d 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -63,7 +63,9 @@
* giving more room for the text at the expense of nicely aligned text. */
#define UI_PROP_SEP_ICON_WIDTH_EXCEPTION
-/************************ Structs and Defines *************************/
+/* -------------------------------------------------------------------- */
+/** \name Structs and Defines
+ * \{ */
#define UI_OPERATOR_ERROR_RET(_ot, _opname, return_statement) \
if (ot == NULL) { \
@@ -128,8 +130,8 @@ typedef struct uiItem {
} uiItem;
enum {
- UI_ITEM_FIXED = 1 << 0,
- UI_ITEM_MIN = 1 << 1,
+ UI_ITEM_AUTO_FIXED_SIZE = 1 << 0,
+ UI_ITEM_FIXED_SIZE = 1 << 1,
UI_ITEM_BOX_ITEM = 1 << 2, /* The item is "inside" a box item */
UI_ITEM_PROP_SEP = 1 << 3,
@@ -211,7 +213,11 @@ typedef struct uiLayoutItemRoot {
uiLayout litem;
} uiLayoutItemRoot;
-/************************** Item ***************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Item
+ * \{ */
static const char *ui_item_name_add_colon(const char *name, char namestr[UI_MAX_NAME_STR])
{
@@ -301,7 +307,7 @@ static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool
return unit_x; /* No icon or name. */
}
if (layout->alignment != UI_LAYOUT_ALIGN_EXPAND) {
- layout->item.flag |= UI_ITEM_MIN;
+ layout->item.flag |= UI_ITEM_FIXED_SIZE;
}
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
float margin = compact ? 1.25 : 1.50;
@@ -408,7 +414,11 @@ static void ui_item_move(uiItem *item, int delta_xmin, int delta_xmax)
}
}
-/******************** Special RNA Items *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Special RNA Items
+ * \{ */
int uiLayoutGetLocalDir(const uiLayout *layout)
{
@@ -1088,7 +1098,11 @@ void UI_context_active_but_prop_get_filebrowser(const bContext *C,
}
}
-/********************* Button Items *************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Button Items
+ * \{ */
/**
* Update a buttons tip with an enum's description if possible.
@@ -1096,7 +1110,8 @@ void UI_context_active_but_prop_get_filebrowser(const bContext *C,
static void ui_but_tip_from_enum_item(uiBut *but, const EnumPropertyItem *item)
{
if (but->tip == NULL || but->tip[0] == '\0') {
- if (item->description && item->description[0]) {
+ if (item->description && item->description[0] &&
+ !(but->optype && but->optype->get_description)) {
but->tip = item->description;
}
}
@@ -3235,7 +3250,11 @@ void uiItemTabsEnumR_prop(
ui_item_enum_expand_tabs(layout, C, block, ptr, prop, NULL, UI_UNIT_Y, icon_only);
}
-/**************************** Layout Items ***************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Layout Items
+ * \{ */
/* single-row layout */
static void ui_litem_estimate_row(uiLayout *litem)
@@ -3250,7 +3269,7 @@ static void ui_litem_estimate_row(uiLayout *litem)
for (item = litem->items.first; item; item = item->next) {
ui_item_size(item, &itemw, &itemh);
- min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN);
+ min_size_flag = min_size_flag && (item->flag & UI_ITEM_FIXED_SIZE);
litem->w += itemw;
litem->h = MAX2(itemh, litem->h);
@@ -3261,7 +3280,7 @@ static void ui_litem_estimate_row(uiLayout *litem)
}
if (min_size_flag) {
- litem->item.flag |= UI_ITEM_MIN;
+ litem->item.flag |= UI_ITEM_FIXED_SIZE;
}
}
@@ -3307,7 +3326,7 @@ static void ui_litem_layout_row(uiLayout *litem)
extra_pixel = 0.0f;
for (item = litem->items.first; item; item = item->next) {
- if (item->flag & UI_ITEM_FIXED) {
+ if (item->flag & UI_ITEM_AUTO_FIXED_SIZE) {
continue;
}
@@ -3323,18 +3342,19 @@ static void ui_litem_layout_row(uiLayout *litem)
x += neww;
- bool min_flag = item->flag & UI_ITEM_MIN;
+ bool min_flag = item->flag & UI_ITEM_FIXED_SIZE;
/* ignore min flag for rows with right or center alignment */
if (item->type != ITEM_BUTTON &&
ELEM(((uiLayout *)item)->alignment, UI_LAYOUT_ALIGN_RIGHT, UI_LAYOUT_ALIGN_CENTER) &&
- litem->alignment == UI_LAYOUT_ALIGN_EXPAND && ((uiItem *)litem)->flag & UI_ITEM_MIN) {
+ litem->alignment == UI_LAYOUT_ALIGN_EXPAND &&
+ ((uiItem *)litem)->flag & UI_ITEM_FIXED_SIZE) {
min_flag = false;
}
if ((neww < minw || min_flag) && w != 0) {
/* fixed size */
- item->flag |= UI_ITEM_FIXED;
- if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_MIN) {
+ item->flag |= UI_ITEM_AUTO_FIXED_SIZE;
+ if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_FIXED_SIZE) {
minw = itemw;
}
fixedw += minw;
@@ -3343,7 +3363,7 @@ static void ui_litem_layout_row(uiLayout *litem)
}
else {
/* keep free size */
- item->flag &= ~UI_ITEM_FIXED;
+ item->flag &= ~UI_ITEM_AUTO_FIXED_SIZE;
freew += itemw;
}
}
@@ -3361,9 +3381,9 @@ static void ui_litem_layout_row(uiLayout *litem)
ui_item_size(item, &itemw, &itemh);
minw = ui_litem_min_width(itemw);
- if (item->flag & UI_ITEM_FIXED) {
+ if (item->flag & UI_ITEM_AUTO_FIXED_SIZE) {
/* fixed minimum size items */
- if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_MIN) {
+ if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_FIXED_SIZE) {
minw = itemw;
}
itemw = ui_item_fit(
@@ -3404,7 +3424,7 @@ static void ui_litem_layout_row(uiLayout *litem)
uiItem *last_item = litem->items.last;
extra_pixel = litem->w - (x - litem->x);
if (extra_pixel > 0 && litem->alignment == UI_LAYOUT_ALIGN_EXPAND && last_free_item &&
- last_item && last_item->flag & UI_ITEM_FIXED) {
+ last_item && last_item->flag & UI_ITEM_AUTO_FIXED_SIZE) {
ui_item_move(last_free_item, 0, extra_pixel);
for (item = last_free_item->next; item; item = item->next) {
ui_item_move(item, extra_pixel, extra_pixel);
@@ -3430,7 +3450,7 @@ static void ui_litem_estimate_column(uiLayout *litem, bool is_box)
for (item = litem->items.first; item; item = item->next) {
ui_item_size(item, &itemw, &itemh);
- min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN);
+ min_size_flag = min_size_flag && (item->flag & UI_ITEM_FIXED_SIZE);
litem->w = MAX2(litem->w, itemw);
litem->h += itemh;
@@ -3441,7 +3461,7 @@ static void ui_litem_estimate_column(uiLayout *litem, bool is_box)
}
if (min_size_flag) {
- litem->item.flag |= UI_ITEM_MIN;
+ litem->item.flag |= UI_ITEM_FIXED_SIZE;
}
}
@@ -4260,7 +4280,7 @@ static void ui_litem_layout_absolute(uiLayout *litem)
static void ui_litem_estimate_split(uiLayout *litem)
{
ui_litem_estimate_row(litem);
- litem->item.flag &= ~UI_ITEM_MIN;
+ litem->item.flag &= ~UI_ITEM_FIXED_SIZE;
}
static void ui_litem_layout_split(uiLayout *litem)
@@ -4733,7 +4753,11 @@ int uiLayoutGetEmboss(uiLayout *layout)
}
}
-/********************** Layout *******************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Layout
+ * \{ */
static void ui_item_scale(uiLayout *litem, const float scale[2])
{
@@ -5076,7 +5100,7 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but)
/* XXX uiBut hasn't scaled yet
* we can flag the button as not expandable, depending on its size */
if (w <= 2 * UI_UNIT_X && (!but->str || but->str[0] == '\0')) {
- bitem->item.flag |= UI_ITEM_MIN;
+ bitem->item.flag |= UI_ITEM_FIXED_SIZE;
}
if (layout->child_items_layout) {
@@ -5096,6 +5120,21 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but)
}
}
+void uiLayoutSetFixedSize(uiLayout *layout, bool fixed_size)
+{
+ if (fixed_size) {
+ layout->item.flag |= UI_ITEM_FIXED_SIZE;
+ }
+ else {
+ layout->item.flag &= ~UI_ITEM_FIXED_SIZE;
+ }
+}
+
+bool uiLayoutGetFixedSize(uiLayout *layout)
+{
+ return (layout->item.flag & UI_ITEM_FIXED_SIZE) != 0;
+}
+
void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext)
{
layout->root->opcontext = opcontext;
@@ -5267,3 +5306,5 @@ void UI_paneltype_draw(bContext *C, PanelType *pt, uiLayout *layout)
CTX_store_set(C, NULL);
}
}
+
+/** \} */
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 0afd67e5e66..4e56a02997b 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -100,10 +100,12 @@ static bool copy_data_path_button_poll(bContext *C)
static int copy_data_path_button_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
PointerRNA ptr;
PropertyRNA *prop;
char *path;
int index;
+ ID *id;
const bool full_path = RNA_boolean_get(op->ptr, "full_path");
@@ -111,18 +113,20 @@ static int copy_data_path_button_exec(bContext *C, wmOperator *op)
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.owner_id != NULL) {
-
if (full_path) {
-
if (prop) {
- path = RNA_path_full_property_py_ex(&ptr, prop, index, true);
+ path = RNA_path_full_property_py_ex(bmain, &ptr, prop, index, true);
}
else {
- path = RNA_path_full_struct_py(&ptr);
+ path = RNA_path_full_struct_py(bmain, &ptr);
}
}
else {
- path = RNA_path_from_ID_to_property(&ptr, prop);
+ path = RNA_path_from_real_ID_to_property_index(bmain, &ptr, prop, 0, -1, &id);
+
+ if (!path) {
+ path = RNA_path_from_ID_to_property(&ptr, prop);
+ }
}
if (path) {
@@ -185,8 +189,9 @@ static bool copy_as_driver_button_poll(bContext *C)
return 0;
}
-static int copy_as_driver_button_exec(bContext *C, wmOperator *UNUSED(op))
+static int copy_as_driver_button_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
PointerRNA ptr;
PropertyRNA *prop;
int index;
@@ -195,14 +200,19 @@ static int copy_as_driver_button_exec(bContext *C, wmOperator *UNUSED(op))
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.owner_id && ptr.data && prop) {
+ ID *id;
int dim = RNA_property_array_dimension(&ptr, prop, NULL);
- char *path = RNA_path_from_ID_to_property_index(&ptr, prop, dim, index);
+ char *path = RNA_path_from_real_ID_to_property_index(bmain, &ptr, prop, dim, index, &id);
if (path) {
- ANIM_copy_as_driver(ptr.owner_id, path, RNA_property_identifier(prop));
+ ANIM_copy_as_driver(id, path, RNA_property_identifier(prop));
MEM_freeN(path);
return OPERATOR_FINISHED;
}
+ else {
+ BKE_reportf(op->reports, RPT_ERROR, "Could not compute a valid data path");
+ return OPERATOR_CANCELLED;
+ }
}
return OPERATOR_CANCELLED;
@@ -211,7 +221,7 @@ static int copy_as_driver_button_exec(bContext *C, wmOperator *UNUSED(op))
static void UI_OT_copy_as_driver_button(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Copy As New Driver";
+ ot->name = "Copy as New Driver";
ot->idname = "UI_OT_copy_as_driver_button";
ot->description =
"Create a new driver with this property as input, and copy it to the "
@@ -443,7 +453,7 @@ static int unset_property_button_exec(bContext *C, wmOperator *UNUSED(op))
static void UI_OT_unset_property_button(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Unset property";
+ ot->name = "Unset Property";
ot->idname = "UI_OT_unset_property_button";
ot->description = "Clear the property and use default or generated value in operators";
@@ -934,7 +944,7 @@ static int copy_to_selected_button_exec(bContext *C, wmOperator *op)
static void UI_OT_copy_to_selected_button(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Copy To Selected";
+ ot->name = "Copy to Selected";
ot->idname = "UI_OT_copy_to_selected_button";
ot->description = "Copy property from this object to selected objects or bones";
@@ -1082,7 +1092,7 @@ static int jump_to_target_button_exec(bContext *C, wmOperator *UNUSED(op))
static void UI_OT_jump_to_target_button(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Jump To Target";
+ ot->name = "Jump to Target";
ot->idname = "UI_OT_jump_to_target_button";
ot->description = "Switch to the target object or bone";
@@ -1580,6 +1590,34 @@ static void UI_OT_button_execute(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Text Button Clear Operator
+ * \{ */
+
+static int button_string_clear_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ uiBut *but = UI_context_active_but_get(C);
+
+ if (but) {
+ ui_but_active_string_clear_and_exit(C, but);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void UI_OT_button_string_clear(wmOperatorType *ot)
+{
+ ot->name = "Clear Button String";
+ ot->idname = "UI_OT_button_string_clear";
+ ot->description = "Unsets the text of the active button";
+
+ ot->poll = ED_operator_regionactive;
+ ot->exec = button_string_clear_exec;
+ ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Drop Color Operator
* \{ */
@@ -1704,6 +1742,7 @@ void ED_operatortypes_ui(void)
#endif
WM_operatortype_append(UI_OT_reloadtranslation);
WM_operatortype_append(UI_OT_button_execute);
+ WM_operatortype_append(UI_OT_button_string_clear);
/* external */
WM_operatortype_append(UI_OT_eyedropper_color);
diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c
index d0efb3714bc..34b1070f8b4 100644
--- a/source/blender/editors/interface/interface_query.c
+++ b/source/blender/editors/interface/interface_query.c
@@ -100,7 +100,7 @@ bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
}
/* file selectors are exempt from utf-8 checks */
-bool ui_but_is_utf8(const uiBut *but)
+bool UI_but_is_utf8(const uiBut *but)
{
if (but->rnaprop) {
const int subtype = RNA_property_subtype(but->rnaprop);
@@ -137,15 +137,15 @@ bool ui_but_has_array_value(const uiBut *but)
PROP_COORDS));
}
+static wmOperatorType *g_ot_tool_set_by_id = NULL;
bool UI_but_is_tool(const uiBut *but)
{
/* very evil! */
if (but->optype != NULL) {
- static wmOperatorType *ot = NULL;
- if (ot == NULL) {
- ot = WM_operatortype_find("WM_OT_tool_set_by_id", false);
+ if (g_ot_tool_set_by_id == NULL) {
+ g_ot_tool_set_by_id = WM_operatortype_find("WM_OT_tool_set_by_id", false);
}
- if (but->optype == ot) {
+ if (but->optype == g_ot_tool_set_by_id) {
return true;
}
}
@@ -463,14 +463,33 @@ bool ui_block_is_popup_any(const uiBlock *block)
return (ui_block_is_menu(block) || ui_block_is_popover(block) || ui_block_is_pie_menu(block));
}
-bool UI_block_is_empty(const uiBlock *block)
+static const uiBut *ui_but_next_non_separator(const uiBut *but)
{
- for (const uiBut *but = block->buttons.first; but; but = but->next) {
+ for (; but; but = but->next) {
if (!ELEM(but->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE)) {
- return false;
+ return but;
}
}
- return true;
+ return NULL;
+}
+
+bool UI_block_is_empty_ex(const uiBlock *block, const bool skip_title)
+{
+ const uiBut *but = block->buttons.first;
+ if (skip_title) {
+ /* Skip the first label, since popups often have a title,
+ * we may want to consider the block empty in this case. */
+ but = ui_but_next_non_separator(but);
+ if (but && but->type == UI_BTYPE_LABEL) {
+ but = but->next;
+ }
+ }
+ return (ui_but_next_non_separator(but) == NULL);
+}
+
+bool UI_block_is_empty(const uiBlock *block)
+{
+ return UI_block_is_empty_ex(block, false);
}
bool UI_block_can_add_separator(const uiBlock *block)
@@ -596,3 +615,14 @@ ARegion *ui_screen_region_find_mouse_over(bScreen *screen, const wmEvent *event)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Manage Internal State
+ * \{ */
+
+void ui_interface_tag_script_reload_queries(void)
+{
+ g_ot_tool_set_by_id = NULL;
+}
+
+/** \} */
diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c
index ab3a86ec9e1..fed3c0b3d11 100644
--- a/source/blender/editors/interface/interface_region_menu_popup.c
+++ b/source/blender/editors/interface/interface_region_menu_popup.c
@@ -474,7 +474,7 @@ void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
bool UI_popup_menu_end_or_cancel(bContext *C, uiPopupMenu *pup)
{
- if (!UI_block_is_empty(pup->block)) {
+ if (!UI_block_is_empty_ex(pup->block, true)) {
UI_popup_menu_end(C, pup);
return true;
}
diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c
index 2073117d51c..63dee77e90e 100644
--- a/source/blender/editors/interface/interface_region_popup.c
+++ b/source/blender/editors/interface/interface_region_popup.c
@@ -765,7 +765,7 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C,
UI_but_tooltip_timer_remove(C, activebut);
}
/* standard cursor by default */
- WM_cursor_set(window, CURSOR_STD);
+ WM_cursor_set(window, WM_CURSOR_DEFAULT);
/* create handle */
handle = MEM_callocN(sizeof(uiPopupBlockHandle), "uiPopupBlockHandle");
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index f2ca9cebf7b..3f20e8247b9 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -860,10 +860,10 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
/* move ownership (no need for re-alloc) */
if (but->rnaprop) {
field->text = RNA_path_full_property_py_ex(
- &but->rnapoin, but->rnaprop, but->rnaindex, true);
+ CTX_data_main(C), &but->rnapoin, but->rnaprop, but->rnaindex, true);
}
else {
- field->text = RNA_path_full_struct_py(&but->rnapoin);
+ field->text = RNA_path_full_struct_py(CTX_data_main(C), &but->rnapoin);
}
}
}
@@ -932,18 +932,14 @@ static uiTooltipData *ui_tooltip_data_from_gizmo(bContext *C, wmGizmo *gz)
NULL;
if (gzop != NULL) {
/* Description */
- const char *info = RNA_struct_ui_description(gzop->type->srna);
- if (!(info && info[0])) {
- info = RNA_struct_ui_name(gzop->type->srna);
- }
+ char *info = WM_operatortype_description(C, gzop->type, &gzop->ptr);
+
+ if (info != NULL) {
+ char *text = info;
- if (info && info[0]) {
- char *text = NULL;
if (gzop_actions[i].prefix != NULL) {
text = BLI_sprintfN("%s: %s", gzop_actions[i].prefix, info);
- }
- else {
- text = BLI_strdup(info);
+ MEM_freeN(info);
}
if (text != NULL) {
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 1c6618bc509..fe484676ddd 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -76,6 +76,7 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
+#include "ED_fileselect.h"
#include "ED_screen.h"
#include "ED_object.h"
#include "ED_render.h"
@@ -104,6 +105,24 @@ void UI_template_fix_linking(void)
{
}
+/* -------------------------------------------------------------------- */
+/** \name Header Template
+ * \{ */
+
+void uiTemplateHeader(uiLayout *layout, bContext *C)
+{
+ uiBlock *block;
+
+ block = uiLayoutAbsoluteBlock(layout);
+ ED_area_header_switchbutton(C, block, 0);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Search Menu Helpers
+ * \{ */
+
/**
* Add a block button for the search menu for templateID and templateSearch.
*/
@@ -264,17 +283,11 @@ static uiBlock *template_common_search_menu(const bContext *C,
return block;
}
-/********************** Header Template *************************/
-
-void uiTemplateHeader(uiLayout *layout, bContext *C)
-{
- uiBlock *block;
-
- block = uiLayoutAbsoluteBlock(layout);
- ED_area_header_switchbutton(C, block, 0);
-}
+/** \} */
-/********************** Search Callbacks *************************/
+/* -------------------------------------------------------------------- */
+/** \name Search Callbacks
+ * \{ */
typedef struct TemplateID {
PointerRNA ptr;
@@ -450,7 +463,12 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
template_ui.scale);
}
-/************************ ID Template ***************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID Template
+ * \{ */
+
/* This is for browsing and editing the ID-blocks used */
/* for new/open operators */
@@ -516,12 +534,15 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
if (id) {
Main *bmain = CTX_data_main(C);
if (BKE_override_library_is_enabled() && CTX_wm_window(C)->eventstate->shift) {
- ID *override_id = BKE_override_library_create_from_id(bmain, id);
- if (override_id != NULL) {
- BKE_main_id_clear_newpoins(bmain);
-
- /* Assign new pointer, takes care of updates/notifiers */
- RNA_id_pointer_create(override_id, &idptr);
+ if (ID_IS_OVERRIDABLE_LIBRARY(id)) {
+ /* Only remap that specific ID usage to overriding local data-block. */
+ ID *override_id = BKE_override_library_create_from_id(bmain, id, false);
+ if (override_id != NULL) {
+ BKE_main_id_clear_newpoins(bmain);
+
+ /* Assign new pointer, takes care of updates/notifiers */
+ RNA_id_pointer_create(override_id, &idptr);
+ }
}
}
else {
@@ -538,7 +559,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
break;
case UI_ID_OVERRIDE:
if (id && id->override_library) {
- BKE_override_library_free(&id->override_library);
+ BKE_override_library_free(&id->override_library, true);
/* reassign to get get proper updates/notifiers */
idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL);
@@ -1364,7 +1385,11 @@ void uiTemplateIDTabs(uiLayout *layout,
false);
}
-/************************ ID Chooser Template ***************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID Chooser Template
+ * \{ */
/**
* This is for selecting the type of ID-block to use,
@@ -1437,7 +1462,11 @@ void uiTemplateAnyID(uiLayout *layout,
uiItemFullR(sub, ptr, propID, 0, 0, 0, "", ICON_NONE);
}
-/********************* Search Template ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Search Template
+ * \{ */
typedef struct TemplateSearch {
uiRNACollectionSearch search_data;
@@ -1683,7 +1712,11 @@ void uiTemplateSearchPreview(uiLayout *layout,
}
}
-/********************* RNA Path Builder Template ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name RNA Path Builder Template
+ * \{ */
/* ---------- */
@@ -1720,7 +1753,11 @@ void uiTemplatePathBuilder(uiLayout *layout,
* searching of nested properties to 'build' the path */
}
-/************************ Modifier Template *************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Modifier Template
+ * \{ */
#define ERROR_LIBDATA_MESSAGE TIP_("Can't edit external library data")
@@ -2065,7 +2102,11 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr)
return NULL;
}
-/************************ Grease Pencil Modifier Template *************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Grease Pencil Modifier Template
+ * \{ */
static uiLayout *gpencil_draw_modifier(uiLayout *layout, Object *ob, GpencilModifierData *md)
{
@@ -2200,7 +2241,11 @@ uiLayout *uiTemplateGpencilModifier(uiLayout *layout, bContext *UNUSED(C), Point
return NULL;
}
-/************************ Shader FX Template *************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Grease Pencil Shader FX Template
+ * \{ */
static uiLayout *gpencil_draw_shaderfx(uiLayout *layout, Object *ob, ShaderFxData *md)
{
@@ -2318,7 +2363,11 @@ uiLayout *uiTemplateShaderFx(uiLayout *layout, bContext *UNUSED(C), PointerRNA *
return NULL;
}
-/************************ Redo Buttons Template *************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Redo Buttons Template
+ * \{ */
static void template_operator_redo_property_buts_draw(
const bContext *C, wmOperator *op, uiLayout *layout, int layout_flags, bool *r_has_advanced)
@@ -2384,7 +2433,11 @@ void uiTemplateOperatorRedoProperties(uiLayout *layout, const bContext *C)
}
}
-/************************ Constraint Template *************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Constraint Template
+ * \{ */
static void constraint_active_func(bContext *UNUSED(C), void *ob_v, void *con_v)
{
@@ -2600,7 +2653,11 @@ uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr)
return draw_constraint(layout, ob, con);
}
-/************************* Preview Template ***************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Preview Template
+ * \{ */
#include "DNA_light_types.h"
#include "DNA_material_types.h"
@@ -2862,7 +2919,11 @@ void uiTemplatePreview(uiLayout *layout,
}
}
-/********************** ColorRamp Template **************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ColorRamp Template
+ * \{ */
typedef struct RNAUpdateCb {
PointerRNA ptr;
@@ -3207,7 +3268,7 @@ static void colorband_buttons_layout(uiLayout *layout,
&coba->cur,
0.0,
(float)(MAX2(0, coba->tot - 1)),
- 0,
+ 1,
0,
TIP_("Choose active color stop"));
row = uiLayoutRow(split, false);
@@ -3237,7 +3298,7 @@ static void colorband_buttons_layout(uiLayout *layout,
&coba->cur,
0.0,
(float)(MAX2(0, coba->tot - 1)),
- 0,
+ 1,
0,
TIP_("Choose active color stop"));
row = uiLayoutRow(subsplit, false);
@@ -3293,7 +3354,12 @@ void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname
MEM_freeN(cb);
}
-/********************* Icon Template ************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Icon Template
+ * \{ */
+
/**
* \param icon_scale: Scale of the icon, 1x == button height.
*/
@@ -3320,7 +3386,12 @@ void uiTemplateIcon(uiLayout *layout, int icon_value, float icon_scale)
ui_def_but_icon(but, icon_value, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
}
-/********************* Icon viewer Template ************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Icon viewer Template
+ * \{ */
+
typedef struct IconViewMenuArgs {
PointerRNA ptr;
PropertyRNA *prop;
@@ -3480,7 +3551,11 @@ void uiTemplateIconView(uiLayout *layout,
}
}
-/********************* Histogram Template ************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Histogram Template
+ * \{ */
void uiTemplateHistogram(uiLayout *layout, PointerRNA *ptr, const char *propname)
{
@@ -3530,7 +3605,11 @@ void uiTemplateHistogram(uiLayout *layout, PointerRNA *ptr, const char *propname
"");
}
-/********************* Waveform Template ************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Waveform Template
+ * \{ */
void uiTemplateWaveform(uiLayout *layout, PointerRNA *ptr, const char *propname)
{
@@ -3592,7 +3671,11 @@ void uiTemplateWaveform(uiLayout *layout, PointerRNA *ptr, const char *propname)
"");
}
-/********************* Vectorscope Template ************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector-Scope Template
+ * \{ */
void uiTemplateVectorscope(uiLayout *layout, PointerRNA *ptr, const char *propname)
{
@@ -3654,7 +3737,11 @@ void uiTemplateVectorscope(uiLayout *layout, PointerRNA *ptr, const char *propna
"");
}
-/********************* CurveMapping Template ************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name CurveMapping Template
+ * \{ */
static void curvemap_buttons_zoom_in(bContext *C, void *cumap_v, void *UNUSED(arg))
{
@@ -3745,12 +3832,11 @@ static uiBlock *curvemap_clipping_func(bContext *C, ARegion *ar, void *cumap_v)
float width = 8 * UI_UNIT_X;
block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
-
- /* use this for a fake extra empty space around the buttons */
- uiDefBut(block, UI_BTYPE_LABEL, 0, "", -4, 16, width + 8, 6 * UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
+ UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_MOVEMOUSE_QUIT);
+ UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
bt = uiDefButBitI(block,
- UI_BTYPE_TOGGLE,
+ UI_BTYPE_CHECKBOX,
CUMA_DO_CLIP,
1,
IFACE_("Use Clipping"),
@@ -3770,7 +3856,7 @@ static uiBlock *curvemap_clipping_func(bContext *C, ARegion *ar, void *cumap_v)
uiDefButF(block,
UI_BTYPE_NUM,
0,
- IFACE_("Min X "),
+ IFACE_("Min X:"),
0,
4 * UI_UNIT_Y,
width,
@@ -3784,7 +3870,7 @@ static uiBlock *curvemap_clipping_func(bContext *C, ARegion *ar, void *cumap_v)
uiDefButF(block,
UI_BTYPE_NUM,
0,
- IFACE_("Min Y "),
+ IFACE_("Min Y:"),
0,
3 * UI_UNIT_Y,
width,
@@ -3798,7 +3884,7 @@ static uiBlock *curvemap_clipping_func(bContext *C, ARegion *ar, void *cumap_v)
uiDefButF(block,
UI_BTYPE_NUM,
0,
- IFACE_("Max X "),
+ IFACE_("Max X:"),
0,
2 * UI_UNIT_Y,
width,
@@ -3812,7 +3898,7 @@ static uiBlock *curvemap_clipping_func(bContext *C, ARegion *ar, void *cumap_v)
uiDefButF(block,
UI_BTYPE_NUM,
0,
- IFACE_("Max Y "),
+ IFACE_("Max Y:"),
0,
UI_UNIT_Y,
width,
@@ -3824,7 +3910,8 @@ static uiBlock *curvemap_clipping_func(bContext *C, ARegion *ar, void *cumap_v)
2,
"");
- UI_block_direction_set(block, UI_DIR_RIGHT);
+ UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
+ UI_block_direction_set(block, UI_DIR_DOWN);
return block;
}
@@ -4415,7 +4502,11 @@ void uiTemplateCurveMapping(uiLayout *layout,
MEM_freeN(cb);
}
-/********************* ColorPicker Template ************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ColorPicker Template
+ * \{ */
#define WHEEL_SIZE (5 * U.widget_unit)
@@ -4762,7 +4853,11 @@ void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, const char *propn
RNA_boolean_set(opptr, "use_accumulate", false);
}
-/********************* Layer Buttons Template ************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Layer Buttons Template
+ * \{ */
static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
{
@@ -4776,7 +4871,7 @@ static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
/* Normally clicking only selects one layer */
RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, cur, true);
- for (i = 0; i < tot; ++i) {
+ for (i = 0; i < tot; i++) {
if (i != cur) {
RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, i, false);
}
@@ -4867,7 +4962,12 @@ void uiTemplateLayers(uiLayout *layout,
}
}
-/************************* List Template **************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name List Template
+ * \{ */
+
static void uilist_draw_item_default(struct uiList *ui_list,
struct bContext *UNUSED(C),
struct uiLayout *layout,
@@ -5752,7 +5852,11 @@ void uiTemplateList(uiLayout *layout,
}
}
-/************************* Operator Search Template **************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Search Template
+ * \{ */
static void operator_call_cb(bContext *C, void *UNUSED(arg1), void *arg2)
{
@@ -5857,7 +5961,11 @@ void uiTemplateOperatorSearch(uiLayout *layout)
UI_but_func_operator_search(but);
}
-/************************* Operator Redo Properties Template **************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Redo Properties Template
+ * \{ */
#ifdef USE_OP_RESET_BUT
static void ui_layout_operator_buts__reset_cb(bContext *UNUSED(C),
@@ -5961,6 +6069,7 @@ eAutoPropButsReturn uiTemplateOperatorPropertyButs(const bContext *C,
RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
/* main draw call */
return_info = uiDefAutoButsRNA(
@@ -6033,7 +6142,11 @@ eAutoPropButsReturn uiTemplateOperatorPropertyButs(const bContext *C,
return return_info;
}
-/************************* Running Jobs Template **************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Running Jobs Template
+ * \{ */
#define B_STOPRENDER 1
#define B_STOPCAST 2
@@ -6308,7 +6421,11 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
}
}
-/************************* Reports for Last Operator Template **************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reports for Last Operator Template
+ * \{ */
void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
{
@@ -6444,7 +6561,11 @@ void uiTemplateInputStatus(uiLayout *layout, struct bContext *C)
}
}
-/********************************* Keymap *************************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Keymap Template
+ * \{ */
static void keymap_item_modified(bContext *UNUSED(C), void *kmi_p, void *UNUSED(unused))
{
@@ -6533,7 +6654,11 @@ void uiTemplateKeymapItemProperties(uiLayout *layout, PointerRNA *ptr)
}
}
-/********************************* Color management *************************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Management Template
+ * \{ */
void uiTemplateColorspaceSettings(uiLayout *layout, PointerRNA *ptr, const char *propname)
{
@@ -6593,7 +6718,11 @@ void uiTemplateColormanagedViewSettings(uiLayout *layout,
}
}
-/********************************* Component Menu *************************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Component Menu
+ * \{ */
typedef struct ComponentMenuArgs {
PointerRNA ptr;
@@ -6622,7 +6751,7 @@ static uiBlock *component_menu(bContext *C, ARegion *ar, void *args_v)
uiItemR(layout, &args->ptr, args->propname, UI_ITEM_R_EXPAND, "", ICON_NONE);
- UI_block_bounds_set_normal(block, 6);
+ UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
UI_block_direction_set(block, UI_DIR_DOWN);
return block;
@@ -6651,7 +6780,11 @@ void uiTemplateComponentMenu(uiLayout *layout,
UI_block_align_end(block);
}
-/************************* Node Socket Icon **************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Socket Icon Template
+ * \{ */
void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float *color)
{
@@ -6672,7 +6805,11 @@ void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float *color)
UI_block_align_end(block);
}
-/********************************* Cache File *********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cache File Template
+ * \{ */
void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname)
{
@@ -6752,7 +6889,11 @@ void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const c
#endif
}
-/******************************* Recent Files *******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Recent Files Template
+ * \{ */
int uiTemplateRecentFiles(uiLayout *layout, int rows)
{
@@ -6776,3 +6917,19 @@ int uiTemplateRecentFiles(uiLayout *layout, int rows)
return i;
}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name FileSelectParams Path Button Template
+ * \{ */
+
+void uiTemplateFileSelectPath(uiLayout *layout, bContext *C, FileSelectParams *params)
+{
+ bScreen *screen = CTX_wm_screen(C);
+ SpaceFile *sfile = CTX_wm_space_file(C);
+
+ ED_file_path_button(screen, sfile, params, uiLayoutGetBlock(layout));
+}
+
+/** \} */
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index d16986ede8f..9f1b11d1354 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -58,6 +58,10 @@
# include "WM_types.h"
#endif
+/* -------------------------------------------------------------------- */
+/** \name Local Enums/Defines
+ * \{ */
+
/* icons are 80% of height of button (16 pixels inside 20 height) */
#define ICON_SIZE_FROM_BUTRECT(rect) (0.8f * BLI_rcti_size_y(rect))
@@ -126,7 +130,66 @@ enum {
#define UI_BUT_UPDATE_DELAY ((void)0)
#define UI_BUT_UNDO ((void)0)
-/* ************** widget base functions ************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Color Utilities
+ * \{ */
+
+static void color_blend_v3_v3(uchar cp[3], const uchar cpstate[3], const float fac)
+{
+ if (fac != 0.0f) {
+ cp[0] = (int)((1.0f - fac) * cp[0] + fac * cpstate[0]);
+ cp[1] = (int)((1.0f - fac) * cp[1] + fac * cpstate[1]);
+ cp[2] = (int)((1.0f - fac) * cp[2] + fac * cpstate[2]);
+ }
+}
+
+static void color_blend_v4_v4v4(uchar r_col[4],
+ const uchar col1[4],
+ const uchar col2[4],
+ const float fac)
+{
+ const int faci = unit_float_to_uchar_clamp(fac);
+ const int facm = 255 - faci;
+
+ r_col[0] = (faci * col1[0] + facm * col2[0]) / 256;
+ r_col[1] = (faci * col1[1] + facm * col2[1]) / 256;
+ r_col[2] = (faci * col1[2] + facm * col2[2]) / 256;
+ r_col[3] = (faci * col1[3] + facm * col2[3]) / 256;
+}
+
+static void color_add_v3_i(uchar cp[3], int tint)
+{
+ cp[0] = clamp_i(cp[0] + tint, 0, 255);
+ cp[1] = clamp_i(cp[1] + tint, 0, 255);
+ cp[2] = clamp_i(cp[2] + tint, 0, 255);
+}
+
+static void color_ensure_contrast_v3(uchar cp[3], const uchar cp_other[3], int contrast)
+{
+ BLI_assert(contrast > 0);
+ const int item_value = rgb_to_grayscale_byte(cp);
+ const int inner_value = rgb_to_grayscale_byte(cp_other);
+ const int delta = item_value - inner_value;
+ if (delta >= 0) {
+ if (contrast > delta) {
+ color_add_v3_i(cp, contrast - delta);
+ }
+ }
+ else {
+ if (contrast > -delta) {
+ color_add_v3_i(cp, -contrast - delta);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Widget Base Type
+ * \{ */
+
/**
* - in: roundbox codes for corner types and radius
* - return: array of `[size][2][x, y]` points, the edges of the roundbox, + UV coords
@@ -193,7 +256,11 @@ typedef struct uiWidgetType {
} uiWidgetType;
-/* *********************** draw data ************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Shape Preset Data
+ * \{ */
static const float cornervec[WIDGET_CURVE_RESOLU][2] = {
{0.0, 0.0},
@@ -220,10 +287,6 @@ const float ui_pixel_jitter[UI_PIXEL_AA_JITTER][2] = {
#define WIDGET_AA_JITTER UI_PIXEL_AA_JITTER
#define jit ui_pixel_jitter
-/* -------------------------------------------------------------------- */
-/** \name Shape Preset Data
- * \{ */
-
static const float g_shape_preset_number_arrow_vert[3][2] = {
{-0.352077, 0.532607},
{-0.352077, -0.549313},
@@ -307,12 +370,14 @@ static const uint g_shape_preset_hold_action_face[2][3] = {{2, 0, 1}, {3, 5, 4}}
/** \} */
-/* **************** Batch creations ****************** */
-/**
+/* -------------------------------------------------------------------- */
+/** \name #GPUBatch Creation
+ *
* In order to speed up UI drawing we create some batches that are then
* modified by specialized shaders to draw certain elements really fast.
* TODO: find a better place. Maybe it's own file?
- */
+ *
+ * \{ */
/* offset in triavec[] in shader per type */
static const int tria_ofs[ROUNDBOX_TRIA_MAX] = {
@@ -402,7 +467,7 @@ static void roundbox_batch_add_tria(GPUVertBufRaw *vflag_step, int tria, uint32_
const int tria_num =
ELEM(tria, ROUNDBOX_TRIA_CHECK, ROUNDBOX_TRIA_HOLD_ACTION_ARROW, ROUNDBOX_TRIA_MENU) ? 1 : 2;
/* for each tria */
- for (int t = 0; t < tria_num; ++t) {
+ for (int t = 0; t < tria_num; t++) {
for (int j = 0; j < WIDGET_AA_JITTER; j++) {
/* restart */
set_roundbox_vertex_data(vflag_step, last_data);
@@ -596,7 +661,11 @@ GPUBatch *ui_batch_roundbox_shadow_get(void)
#undef EMBOSS
#undef NO_AA
-/* ************************************************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw Triangle Arrow
+ * \{ */
void UI_draw_anti_tria(
float x1, float y1, float x2, float y2, float x3, float y3, const float color[4])
@@ -696,6 +765,12 @@ static void widget_init(uiWidgetBase *wtb)
wtb->uniform_params.alpha_discard = 1.0f;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw Round Box
+ * \{ */
+
/* helper call, makes shadow rect, with 'sun' above menu, so only shadow to left/right/bottom */
/* return tot */
static int round_box_shadow_edges(
@@ -954,6 +1029,8 @@ static void round_box_edges(uiWidgetBase *wt, int roundboxalign, const rcti *rec
round_box__edges(wt, roundboxalign, rect, rad, rad - U.pixelsize);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Shape Preset Mini API
* \{ */
@@ -1075,7 +1152,7 @@ static void widget_draw_vertex_buffer(uint pos,
uint totvert)
{
immBegin(mode, totvert);
- for (int i = 0; i < totvert; ++i) {
+ for (int i = 0; i < totvert; i++) {
if (quads_col) {
immAttr4ubv(col, quads_col[i]);
}
@@ -1133,6 +1210,10 @@ static void shape_preset_trias_from_rect_checkmark(uiWidgetTrias *tria, const rc
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Widget Base Drawing
+ * \{ */
+
/* prepares shade colors */
static void shadecolors4(
uchar coltop[4], uchar coldown[4], const uchar *color, short shadetop, short shadedown)
@@ -1148,20 +1229,6 @@ static void shadecolors4(
coldown[3] = color[3];
}
-static void round_box_shade_col4_r(uchar r_col[4],
- const uchar col1[4],
- const uchar col2[4],
- const float fac)
-{
- const int faci = unit_float_to_uchar_clamp(fac);
- const int facm = 255 - faci;
-
- r_col[0] = (faci * col1[0] + facm * col2[0]) / 256;
- r_col[1] = (faci * col1[1] + facm * col2[1]) / 256;
- r_col[2] = (faci * col1[2] + facm * col2[2]) / 256;
- r_col[3] = (faci * col1[3] + facm * col2[3]) / 256;
-}
-
static void widget_verts_to_triangle_strip(uiWidgetBase *wtb,
const int totvert,
float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2])
@@ -1225,6 +1292,12 @@ static void widgetbase_set_uniform_colors_ubv(uiWidgetBase *wtb,
rgba_float_args_set_ch(wtb->uniform_params.color_tria, tria[0], tria[1], tria[2], tria[3]);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Widget Base Drawing #GPUBatch Cache
+ * \{ */
+
/* keep in sync with shader */
#define MAX_WIDGET_BASE_BATCH 6
#define MAX_WIDGET_PARAMETERS 11
@@ -1238,7 +1311,7 @@ static struct {
void UI_widgetbase_draw_cache_flush(void)
{
- float checker_params[3] = {
+ const float checker_params[3] = {
UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 8.0f};
if (g_widget_base_batch.count == 0) {
@@ -1321,7 +1394,7 @@ static void draw_widgetbase_batch(GPUBatch *batch, uiWidgetBase *wtb)
}
}
else {
- float checker_params[3] = {
+ const float checker_params[3] = {
UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 8.0f};
/* draw single */
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
@@ -1400,7 +1473,11 @@ static void widgetbase_draw(uiWidgetBase *wtb, const uiWidgetColors *wcol)
widgetbase_draw_ex(wtb, wcol, false);
}
-/* *********************** text/icon ************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Text/Icon Drawing
+ * \{ */
#define UI_TEXT_CLIP_MARGIN (0.25f * U.widget_unit / but->block->aspect)
@@ -2188,7 +2265,7 @@ static void widget_draw_text(const uiFontStyle *fstyle,
drawstr_right = strrchr(drawstr + but->ofs, ':');
if (drawstr_right) {
drawstr_right++;
- drawstr_left_len = (drawstr_right - drawstr);
+ drawstr_left_len = (drawstr_right - drawstr - 1);
while (*drawstr_right == ' ') {
drawstr_right++;
@@ -2294,13 +2371,29 @@ static BIFIconID widget_icon_id(uiBut *but)
}
}
+static void widget_draw_extra_icons(const uiWidgetColors *wcol,
+ uiBut *but,
+ rcti *rect,
+ float alpha)
+{
+ /* inverse order, from right to left. */
+ for (uiButExtraOpIcon *op_icon = but->extra_op_icons.last; op_icon; op_icon = op_icon->prev) {
+ rcti temp = *rect;
+
+ temp.xmin = temp.xmax - (BLI_rcti_size_y(rect) * 1.08f);
+
+ widget_draw_icon(but, op_icon->icon, alpha, &temp, wcol->text);
+
+ rect->xmax -= ICON_SIZE_FROM_BUTRECT(rect);
+ }
+}
+
/* draws text and icons for buttons */
static void widget_draw_text_icon(const uiFontStyle *fstyle,
const uiWidgetColors *wcol,
uiBut *but,
rcti *rect)
{
- const uiButExtraIconType extra_icon_type = ui_but_icon_extra_get(but);
const bool show_menu_icon = ui_but_draw_menu_icon(but);
float alpha = (float)wcol->text[3] / 255.0f;
char password_str[UI_MAX_DRAW_STR];
@@ -2422,23 +2515,7 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
}
/* extra icons, e.g. 'x' icon to clear text or icon for eyedropper */
- if (extra_icon_type != UI_BUT_ICONEXTRA_NONE) {
- rcti temp = *rect;
-
- temp.xmin = temp.xmax - (BLI_rcti_size_y(rect) * 1.08f);
-
- if (extra_icon_type == UI_BUT_ICONEXTRA_CLEAR) {
- widget_draw_icon(but, ICON_PANEL_CLOSE, alpha, &temp, wcol->text);
- }
- else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {
- widget_draw_icon(but, ICON_EYEDROPPER, alpha, &temp, wcol->text);
- }
- else {
- BLI_assert(0);
- }
-
- rect->xmax -= ICON_SIZE_FROM_BUTRECT(rect);
- }
+ widget_draw_extra_icons(wcol, but, rect, alpha);
/* clip but->drawstr to fit in available space */
if (but->editstr && but->pos >= 0) {
@@ -2471,18 +2548,13 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
#undef UI_TEXT_CLIP_MARGIN
-/* *********************** widget types ************************************* */
-
-/* ************ button callbacks, state ***************** */
+/** \} */
-static void widget_state_blend(uchar cp[3], const uchar cpstate[3], const float fac)
-{
- if (fac != 0.0f) {
- cp[0] = (int)((1.0f - fac) * cp[0] + fac * cpstate[0]);
- cp[1] = (int)((1.0f - fac) * cp[1] + fac * cpstate[1]);
- cp[2] = (int)((1.0f - fac) * cp[2] + fac * cpstate[2]);
- }
-}
+/* -------------------------------------------------------------------- */
+/** \name Widget State Management
+ *
+ * Adjust widget display based on animated, driven, overridden ... etc.
+ * \{ */
/* put all widget colors on half alpha, use local storage */
static void ui_widget_color_disabled(uiWidgetType *wt)
@@ -2501,31 +2573,6 @@ static void ui_widget_color_disabled(uiWidgetType *wt)
wt->wcol_theme = &wcol_theme_s;
}
-static void rgb_tint(uchar cp[3], int tint)
-{
- cp[0] = clamp_i(cp[0] + tint, 0, 255);
- cp[1] = clamp_i(cp[1] + tint, 0, 255);
- cp[2] = clamp_i(cp[2] + tint, 0, 255);
-}
-
-static void rgb_ensure_contrast(uchar cp[3], const uchar cp_other[3], int contrast)
-{
- BLI_assert(contrast > 0);
- const int item_value = rgb_to_grayscale_byte(cp);
- const int inner_value = rgb_to_grayscale_byte(cp_other);
- const int delta = item_value - inner_value;
- if (delta >= 0) {
- if (contrast > delta) {
- rgb_tint(cp, contrast - delta);
- }
- }
- else {
- if (contrast > -delta) {
- rgb_tint(cp, -contrast - delta);
- }
- }
-}
-
static void widget_active_color(uchar cp[3])
{
cp[0] = cp[0] >= 240 ? 255 : cp[0] + 15;
@@ -2577,7 +2624,7 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag)
if (state & UI_SELECT) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
if (color_blend != NULL) {
- widget_state_blend(wt->wcol.inner, color_blend, wcol_state->blend);
+ color_blend_v3_v3(wt->wcol.inner, color_blend, wcol_state->blend);
}
copy_v3_v3_uchar(wt->wcol.text, wt->wcol.text_sel);
@@ -2587,8 +2634,12 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag)
}
}
else {
+ if (state & UI_BUT_ACTIVE_DEFAULT) {
+ copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
+ copy_v4_v4_uchar(wt->wcol.text, wt->wcol.text_sel);
+ }
if (color_blend != NULL) {
- widget_state_blend(wt->wcol.inner, color_blend, wcol_state->blend);
+ color_blend_v3_v3(wt->wcol.inner, color_blend, wcol_state->blend);
}
if (state & UI_ACTIVE) { /* mouse over? */
@@ -2599,10 +2650,10 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag)
if (state & UI_BUT_REDALERT) {
uchar red[4] = {255, 0, 0};
if (wt->draw) {
- widget_state_blend(wt->wcol.inner, red, 0.4f);
+ color_blend_v3_v3(wt->wcol.inner, red, 0.4f);
}
else {
- widget_state_blend(wt->wcol.text, red, 0.4f);
+ color_blend_v3_v3(wt->wcol.text, red, 0.4f);
}
}
@@ -2610,15 +2661,21 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag)
/* the button isn't SELECT but we're editing this so draw with sel color */
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
- widget_state_blend(wt->wcol.text, wt->wcol.text_sel, 0.85f);
+ color_blend_v3_v3(wt->wcol.text, wt->wcol.text_sel, 0.85f);
}
if (state & UI_BUT_NODE_ACTIVE) {
uchar blue[4] = {86, 128, 194};
- widget_state_blend(wt->wcol.inner, blue, 0.3f);
+ color_blend_v3_v3(wt->wcol.inner, blue, 0.3f);
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Widget Types
+ * \{ */
+
/* sliders use special hack which sets 'item' as inner when drawing filling */
static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag)
{
@@ -2633,8 +2690,8 @@ static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag)
* De-saturate so the color of the slider doesn't conflict with the blend color,
* which can make the color hard to see when the slider is set to full (see T66102). */
wt->wcol.item[0] = wt->wcol.item[1] = wt->wcol.item[2] = rgb_to_grayscale_byte(wt->wcol.item);
- widget_state_blend(wt->wcol.item, color_blend, wcol_state->blend);
- rgb_ensure_contrast(wt->wcol.item, wt->wcol.inner, 30);
+ color_blend_v3_v3(wt->wcol.item, color_blend, wcol_state->blend);
+ color_ensure_contrast_v3(wt->wcol.item, wt->wcol.inner, 30);
}
if (state & UI_SELECT) {
@@ -2677,7 +2734,7 @@ static void widget_state_pie_menu_item(uiWidgetType *wt, int state, int UNUSED(d
/* active and disabled (not so common) */
if ((state & UI_BUT_DISABLED) && (state & UI_ACTIVE)) {
- widget_state_blend(wt->wcol.text, wt->wcol.text_sel, 0.5f);
+ color_blend_v3_v3(wt->wcol.text, wt->wcol.text_sel, 0.5f);
/* draw the backdrop at low alpha, helps navigating with keys
* when disabled items are active */
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.item);
@@ -2690,7 +2747,7 @@ static void widget_state_pie_menu_item(uiWidgetType *wt, int state, int UNUSED(d
}
else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
/* regular disabled */
- widget_state_blend(wt->wcol.text, wt->wcol.inner, 0.5f);
+ color_blend_v3_v3(wt->wcol.text, wt->wcol.inner, 0.5f);
}
if (state & UI_SELECT) {
@@ -2712,7 +2769,7 @@ static void widget_state_menu_item(uiWidgetType *wt, int state, int UNUSED(drawf
/* draw the backdrop at low alpha, helps navigating with keys
* when disabled items are active */
wt->wcol.text[3] = 128;
- widget_state_blend(wt->wcol.inner, wt->wcol.text, 0.5f);
+ color_blend_v3_v3(wt->wcol.inner, wt->wcol.text, 0.5f);
wt->wcol.inner[3] = 64;
}
else {
@@ -2722,7 +2779,7 @@ static void widget_state_menu_item(uiWidgetType *wt, int state, int UNUSED(drawf
}
else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
/* regular disabled */
- widget_state_blend(wt->wcol.text, wt->wcol.inner, 0.5f);
+ color_blend_v3_v3(wt->wcol.text, wt->wcol.inner, 0.5f);
}
if (state & UI_ACTIVE) {
@@ -2731,7 +2788,11 @@ static void widget_state_menu_item(uiWidgetType *wt, int state, int UNUSED(drawf
}
}
-/* ************ menu backdrop ************************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw Menu Backdrop
+ * \{ */
/* outside of rect, rad to left/bottom/right */
static void widget_softshadow(const rcti *rect, int roundboxalign, const float radin)
@@ -2982,7 +3043,11 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const
ui_hsv_cursor(xpos, ypos);
}
-/* ************ custom buttons, old stuff ************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw Custom Buttons
+ * \{ */
/* draws in resolution of 48x4 colors */
void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, const float alpha)
@@ -3268,25 +3333,11 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
ui_hsv_cursor(x, y);
}
-/* Generic round-box drawing. */
-static void ui_draw_roundbox(const rcti *rect, const float rad, const uiWidgetColors *wcol)
-{
- uiWidgetBase wtb;
- widget_init(&wtb);
- round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
- widgetbase_draw(&wtb, wcol);
-
- /* We are drawing on top of widget bases. Flush cache. */
- GPU_blend(true);
- UI_widgetbase_draw_cache_flush();
- GPU_blend(false);
-}
-
-/* ************ separator, for menus etc ***************** */
+/** Separator for menus. */
static void ui_draw_separator(const rcti *rect, const uiWidgetColors *wcol)
{
int y = rect->ymin + BLI_rcti_size_y(rect) / 2 - 1;
- uchar col[4] = {
+ const uchar col[4] = {
wcol->text[0],
wcol->text[1],
wcol->text[2],
@@ -3310,7 +3361,12 @@ static void ui_draw_separator(const rcti *rect, const uiWidgetColors *wcol)
immUnbindProgram();
}
-/* ************ button callbacks, draw ***************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Button Draw Callbacks
+ * \{ */
+
static void widget_numbut_draw(
uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, bool emboss)
{
@@ -4068,7 +4124,7 @@ static void widget_state_label(uiWidgetType *wt, int state, int drawflag)
if (state & UI_BUT_REDALERT) {
uchar red[4] = {255, 0, 0};
- widget_state_blend(wt->wcol.text, red, 0.4f);
+ color_blend_v3_v3(wt->wcol.text, red, 0.4f);
}
}
@@ -4465,7 +4521,7 @@ static int widget_roundbox_set(uiBut *but, rcti *rect)
}
/* align with open menu */
- if (but->active && (but->type != UI_BTYPE_POPOVER)) {
+ if (but->active && (but->type != UI_BTYPE_POPOVER) && !ui_but_menu_draw_as_popover(but)) {
int direction = ui_but_menu_direction(but);
if (direction == UI_DIR_UP) {
@@ -4497,10 +4553,6 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
const uiFontStyle *fstyle = &style->widget;
uiWidgetType *wt = NULL;
-#ifdef USE_UI_POPOVER_ONCE
- const rcti rect_orig = *rect;
-#endif
-
/* handle menus separately */
if (but->dt == UI_EMBOSS_PULLDOWN) {
switch (but->type) {
@@ -4786,6 +4838,14 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
ui_widget_color_disabled(wt);
}
+#ifdef USE_UI_POPOVER_ONCE
+ if (but->block->flag & UI_BLOCK_POPOVER_ONCE) {
+ if ((state & UI_ACTIVE) && ui_but_is_popover_once_compat(but)) {
+ state |= UI_BUT_ACTIVE_DEFAULT;
+ }
+ }
+#endif
+
wt->state(wt, state, drawflag);
if (wt->custom) {
wt->custom(but, &wt->wcol, rect, state, roundboxalign);
@@ -4798,42 +4858,10 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
GPU_blend(true);
}
- bool show_semi_highlight = false;
-
-#ifdef USE_UI_POPOVER_ONCE
- if (but->block->flag & UI_BLOCK_POPOVER_ONCE) {
- if ((state & UI_ACTIVE) && ui_but_is_popover_once_compat(but)) {
- show_semi_highlight = true;
- }
- }
-#endif
- if (but->flag & UI_BUT_ACTIVE_DEFAULT) {
- show_semi_highlight = true;
- }
-
- if (show_semi_highlight) {
- uiWidgetType wt_back = *wt;
- uiWidgetType *wt_temp = widget_type(UI_WTYPE_MENU_ITEM);
- wt_temp->state(wt_temp, state, drawflag);
- copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
- wt->wcol.inner[3] = 128;
- wt->wcol.roundness = 0.5f;
- ui_draw_roundbox(&rect_orig,
- 0.25f * min_ff(BLI_rcti_size_x(&rect_orig), BLI_rcti_size_y(&rect_orig)),
- &wt_temp->wcol);
- *wt = wt_back;
- }
-
wt->text(fstyle, &wt->wcol, but, rect);
if (disabled) {
GPU_blend(false);
}
-
- // if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
- // if (but->dt != UI_EMBOSS_PULLDOWN) {
- // widget_disabled(&disablerect);
- // }
- // }
}
}
@@ -4886,7 +4914,9 @@ static void ui_draw_popover_back_impl(const uiWidgetColors *wcol,
{
/* tsk, this isn't nice. */
const float unit_half = unit_size / 2;
- const float cent_x = mval_origin ? mval_origin[0] : BLI_rcti_cent_x(rect);
+ const float cent_x = mval_origin ?
+ CLAMPIS(mval_origin[0], rect->xmin + unit_size, rect->xmax - unit_size) :
+ BLI_rcti_cent_x(rect);
rect->ymax -= unit_half;
rect->ymin += unit_half;
@@ -4990,14 +5020,14 @@ static void draw_disk_shaded(float start,
if (shaded) {
fac = (y1 + radius_ext) * radius_ext_scale;
- round_box_shade_col4_r(r_col, col1, col2, fac);
+ color_blend_v4_v4v4(r_col, col1, col2, fac);
immAttr4ubv(col, r_col);
}
immVertex2f(pos, c * radius_int, s * radius_int);
if (shaded) {
fac = (y2 + radius_ext) * radius_ext_scale;
- round_box_shade_col4_r(r_col, col1, col2, fac);
+ color_blend_v4_v4v4(r_col, col1, col2, fac);
immAttr4ubv(col, r_col);
}
immVertex2f(pos, c * radius_ext, s * radius_ext);
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 7c5d5401d08..8a570933a33 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -779,6 +779,12 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_PATH_AFTER:
cp = ts->path_after;
break;
+ case TH_PATH_KEYFRAME_BEFORE:
+ cp = ts->path_keyframe_before;
+ break;
+ case TH_PATH_KEYFRAME_AFTER:
+ cp = ts->path_keyframe_after;
+ break;
case TH_CAMERA_PATH:
cp = ts->camera_path;
break;
@@ -905,6 +911,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_ICON_SHADING:
cp = btheme->tui.icon_shading;
break;
+ case TH_ICON_FOLDER:
+ cp = btheme->tui.icon_folder;
+ break;
case TH_ICON_FUND: {
/* Development fund icon color is not part of theme. */
static const uchar red[4] = {204, 48, 72, 255};
@@ -1391,8 +1400,9 @@ bool UI_GetIconThemeColor4ubv(int colorid, uchar col[4])
/* Always color development fund icon. */
}
else if (!((theme_spacetype == SPACE_OUTLINER && theme_regionid == RGN_TYPE_WINDOW) ||
- (theme_spacetype == SPACE_PROPERTIES && theme_regionid == RGN_TYPE_NAV_BAR))) {
- /* Only colored icons in outliner and popups, overall UI is intended
+ (theme_spacetype == SPACE_PROPERTIES && theme_regionid == RGN_TYPE_NAV_BAR) ||
+ (theme_spacetype == SPACE_FILE && theme_regionid == RGN_TYPE_WINDOW))) {
+ /* Only colored icons in specific places, overall UI is intended
* to stay monochrome and out of the way except a few places where it
* is important to communicate different data types. */
return false;
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index c760ddcca6f..b1a060089ee 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -61,7 +61,9 @@
static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mask_scrollers);
-/* *********************************************************************** */
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
BLI_INLINE int clamp_float_to_int(const float f)
{
@@ -94,6 +96,12 @@ BLI_INLINE void clamp_rctf_to_rcti(rcti *dst, const rctf *src)
/* XXX still unresolved: scrolls hide/unhide vs region mask handling */
/* XXX there's V2D_SCROLL_HORIZONTAL_HIDE and V2D_SCROLL_HORIZONTAL_FULLR ... */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Scroll & Mask Utilities
+ * \{ */
+
/**
* helper to allow scrollbars to dynamically hide
* - returns a copy of the scrollbar settings with the flags to display
@@ -219,7 +227,11 @@ static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scr
}
}
-/* Refresh and Validation */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View2D Refresh and Validation (Spatial)
+ * \{ */
/**
* Initialize all relevant View2D data (including view rects if first time)
@@ -1123,8 +1135,11 @@ void UI_view2d_zoom_cache_reset(void)
BLF_cache_clear();
}
-/* *********************************************************************** */
-/* View Matrix Setup */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View2D Matrix Setup
+ * \{ */
/* mapping function to ensure 'cur' draws extended over the area where sliders are */
static void view2d_map_cur_using_mask(const View2D *v2d, rctf *r_curmasked)
@@ -1245,8 +1260,11 @@ void UI_view2d_view_restore(const bContext *C)
// ED_region_pixelspace(CTX_wm_region(C));
}
-/* *********************************************************************** */
-/* Gridlines */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Grid-Line Drawing
+ * \{ */
/* Draw a constant grid in given 2d-region */
void UI_view2d_constant_grid_draw(View2D *v2d, float step)
@@ -1347,7 +1365,7 @@ void UI_view2d_multi_grid_draw(View2D *v2d, int colorid, float step, int level_s
immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
immBeginAtMost(GPU_PRIM_LINES, vertex_count);
- for (int level = 0; level < totlevels; ++level) {
+ for (int level = 0; level < totlevels; level++) {
UI_GetThemeColorShade3ubv(colorid, offset, grid_line_color);
int i = (int)(v2d->cur.xmin / lstep);
@@ -1356,7 +1374,7 @@ void UI_view2d_multi_grid_draw(View2D *v2d, int colorid, float step, int level_s
}
float start = i * lstep;
- for (; start < v2d->cur.xmax; start += lstep, ++i) {
+ for (; start < v2d->cur.xmax; start += lstep, i++) {
if (i == 0 || (level < totlevels - 1 && i % level_size == 0)) {
continue;
}
@@ -1373,7 +1391,7 @@ void UI_view2d_multi_grid_draw(View2D *v2d, int colorid, float step, int level_s
}
start = i * lstep;
- for (; start < v2d->cur.ymax; start += lstep, ++i) {
+ for (; start < v2d->cur.ymax; start += lstep, i++) {
if (i == 0 || (level < totlevels - 1 && i % level_size == 0)) {
continue;
}
@@ -1405,8 +1423,11 @@ void UI_view2d_multi_grid_draw(View2D *v2d, int colorid, float step, int level_s
immUnbindProgram();
}
-/* *********************************************************************** */
-/* Scrollers */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Scrollers
+ * \{ */
/**
* View2DScrollers is typedef'd in UI_view2d.h
@@ -1648,8 +1669,11 @@ void UI_view2d_scrollers_free(View2DScrollers *scrollers)
MEM_freeN(scrollers);
}
-/* *********************************************************************** */
-/* List View Utilities */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name List View Utilities
+ * \{ */
/**
* Get the 'cell' (row, column) that the given 2D-view coordinates
@@ -1693,8 +1717,11 @@ void UI_view2d_listview_view_to_cell(float columnwidth,
}
}
-/* *********************************************************************** */
-/* Coordinate Conversions */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Coordinate Conversions
+ * \{ */
float UI_view2d_region_to_view_x(const struct View2D *v2d, float x)
{
@@ -1872,8 +1899,11 @@ bool UI_view2d_view_to_region_rcti_clip(View2D *v2d, const rctf *rect_src, rcti
}
}
-/* *********************************************************************** */
-/* Utilities */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
/* View2D data by default resides in region, so get from region stored in context */
View2D *UI_view2d_fromcontext(const bContext *C)
@@ -2075,7 +2105,11 @@ char UI_view2d_rect_in_scrollers(const ARegion *ar, const View2D *v2d, const rct
return UI_view2d_rect_in_scrollers_ex(ar, v2d, rect, &scroll_dummy);
}
-/* ******************* view2d text drawing cache ******************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View2D Text Drawing Cache
+ * \{ */
typedef struct View2DString {
struct View2DString *next;
@@ -2205,4 +2239,4 @@ void UI_view2d_text_cache_draw(ARegion *ar)
}
}
-/* ******************************************************** */
+/** \} */
diff --git a/source/blender/editors/interface/view2d_gizmo_navigate.c b/source/blender/editors/interface/view2d_gizmo_navigate.c
index 9b15f2309a1..d0281ad1eef 100644
--- a/source/blender/editors/interface/view2d_gizmo_navigate.c
+++ b/source/blender/editors/interface/view2d_gizmo_navigate.c
@@ -227,13 +227,13 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
int icon_mini_slot = 0;
gz = navgroup->gz_array[GZ_INDEX_ZOOM];
- gz->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++);
- gz->matrix_basis[3][1] = co[1];
+ gz->matrix_basis[3][0] = co[0];
+ gz->matrix_basis[3][1] = co[1] - (icon_offset_mini * icon_mini_slot++);
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
gz = navgroup->gz_array[GZ_INDEX_MOVE];
- gz->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++);
- gz->matrix_basis[3][1] = co[1];
+ gz->matrix_basis[3][0] = co[0];
+ gz->matrix_basis[3][1] = co[1] - (icon_offset_mini * icon_mini_slot++);
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
}
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 032fb7e4cc2..5cf7cb4e7c4 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -256,13 +256,13 @@ static int view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
RNA_int_set(op->ptr, "deltay", 0);
if (v2d->keepofs & V2D_LOCKOFS_X) {
- WM_cursor_modal_set(window, BC_NS_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_NS_SCROLL);
}
else if (v2d->keepofs & V2D_LOCKOFS_Y) {
- WM_cursor_modal_set(window, BC_EW_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_EW_SCROLL);
}
else {
- WM_cursor_modal_set(window, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_NSEW_SCROLL);
}
/* add temp handler */
@@ -1113,13 +1113,13 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, const wmEvent *even
}
if (v2d->keepofs & V2D_LOCKOFS_X) {
- WM_cursor_modal_set(window, BC_NS_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_NS_SCROLL);
}
else if (v2d->keepofs & V2D_LOCKOFS_Y) {
- WM_cursor_modal_set(window, BC_EW_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_EW_SCROLL);
}
else {
- WM_cursor_modal_set(window, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_NSEW_SCROLL);
}
/* add temp handler */
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index 2f3e73f32d5..573dfcde88a 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -576,7 +576,7 @@ static int get_sequence_len(char *filename, int *ofs)
(*ofs) = frame_curr;
while (cache_frame && (cache_frame->framenr == frame_curr)) {
- ++frame_curr;
+ frame_curr++;
cache_frame = cache_frame->next;
}
@@ -604,6 +604,9 @@ static void ui_alembic_import_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemL(row, IFACE_("Options:"), ICON_NONE);
row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "relative_path", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "set_frame_range", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
@@ -691,7 +694,7 @@ void WM_OT_alembic_import(wmOperatorType *ot)
FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
FILE_BLENDER,
FILE_SAVE,
- WM_FILESEL_FILEPATH,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
diff --git a/source/blender/editors/lattice/editlattice_select.c b/source/blender/editors/lattice/editlattice_select.c
index 7e89ed9511f..837c5b1c6bd 100644
--- a/source/blender/editors/lattice/editlattice_select.c
+++ b/source/blender/editors/lattice/editlattice_select.c
@@ -89,8 +89,9 @@ bool ED_lattice_deselect_all_multi_ex(struct Base **bases, const uint bases_len)
bool ED_lattice_deselect_all_multi(struct bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &bases_len);
@@ -634,11 +635,12 @@ static BPoint *findnearestLattvert(ViewContext *vc, int sel, Base **r_base)
bool ED_lattice_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
BPoint *bp = NULL;
Base *basact = NULL;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
vc.mval[0] = mval[0];
vc.mval[1] = mval[1];
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index 683e6d8a2b0..4624611419e 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -230,7 +230,7 @@ static void setup_vertex_point(Mask *mask,
int point_index = reference_point - spline->points;
int delta = new_point == spline->points ? 1 : -1;
int i = 0;
- for (i = 0; i < spline->tot_point - 1; ++i) {
+ for (i = 0; i < spline->tot_point - 1; i++) {
MaskSplinePoint *current_point;
point_index += delta;
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index c00223a3c49..7247697dcb7 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -43,7 +43,6 @@
#include "BIF_glutil.h"
#include "GPU_immediate.h"
-#include "GPU_draw.h"
#include "GPU_shader.h"
#include "GPU_matrix.h"
#include "GPU_state.h"
@@ -391,7 +390,7 @@ static void mask_draw_array(unsigned int pos,
unsigned int vertex_len)
{
immBegin(prim_type, vertex_len);
- for (unsigned int i = 0; i < vertex_len; ++i) {
+ for (unsigned int i = 0; i < vertex_len; i++) {
immVertex2fv(pos, points[i]);
}
immEnd();
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index 9a779db4812..88da40b947f 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -43,6 +43,7 @@ set(SRC
editface.c
editmesh_add.c
editmesh_add_gizmo.c
+ editmesh_automerge.c
editmesh_bevel.c
editmesh_bisect.c
editmesh_extrude.c
@@ -54,6 +55,7 @@ set(SRC
editmesh_knife.c
editmesh_knife_project.c
editmesh_loopcut.c
+ editmesh_mask_extract.c
editmesh_path.c
editmesh_polybuild.c
editmesh_preselect_edgering.c
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 9a70b0a8d36..b7f506a8a41 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -46,8 +46,6 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "GPU_draw.h"
-
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
diff --git a/source/blender/editors/mesh/editmesh_add_gizmo.c b/source/blender/editors/mesh/editmesh_add_gizmo.c
index f6729fb56e1..66832ceba7f 100644
--- a/source/blender/editors/mesh/editmesh_add_gizmo.c
+++ b/source/blender/editors/mesh/editmesh_add_gizmo.c
@@ -78,7 +78,7 @@ static void calc_initial_placement_point_from_view(bContext *C,
float orient_matrix[3][3];
BKE_scene_cursor_to_mat4(&scene->cursor, cursor_matrix);
- float dots[3] = {
+ const float dots[3] = {
dot_v3v3(rv3d->viewinv[2], cursor_matrix[0]),
dot_v3v3(rv3d->viewinv[2], cursor_matrix[1]),
dot_v3v3(rv3d->viewinv[2], cursor_matrix[2]),
diff --git a/source/blender/editors/mesh/editmesh_automerge.c b/source/blender/editors/mesh/editmesh_automerge.c
new file mode 100644
index 00000000000..fb8ee85f9db
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_automerge.c
@@ -0,0 +1,160 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edmesh
+ *
+ * Utility functions for merging geometry once transform has finished:
+ *
+ * - #EDBM_automerge
+ * - #EDBM_automerge_and_split
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_editmesh.h"
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "ED_mesh.h"
+
+#include "tools/bmesh_intersect_edges.h"
+
+//#define DEBUG_TIME
+#ifdef DEBUG_TIME
+# include "PIL_time.h"
+#endif
+
+/* use bmesh operator flags for a few operators */
+#define BMO_ELE_TAG 1
+
+/* -------------------------------------------------------------------- */
+/** \name Auto-Merge Selection
+ *
+ * Used after transform operations.
+ * \{ */
+
+void EDBM_automerge(Object *obedit, bool update, const char hflag, const float dist)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ int totvert_prev = bm->totvert;
+
+ BMOperator findop, weldop;
+
+ /* Search for doubles among all vertices, but only merge non-VERT_KEEP
+ * vertices into VERT_KEEP vertices. */
+ BMO_op_initf(bm,
+ &findop,
+ BMO_FLAG_DEFAULTS,
+ "find_doubles verts=%av keep_verts=%Hv dist=%f",
+ hflag,
+ dist);
+
+ BMO_op_exec(bm, &findop);
+
+ /* weld the vertices */
+ BMO_op_init(bm, &weldop, BMO_FLAG_DEFAULTS, "weld_verts");
+ BMO_slot_copy(&findop, slots_out, "targetmap.out", &weldop, slots_in, "targetmap");
+ BMO_op_exec(bm, &weldop);
+
+ BMO_op_finish(bm, &findop);
+ BMO_op_finish(bm, &weldop);
+
+ if ((totvert_prev != bm->totvert) && update) {
+ EDBM_update_generic(em, true, true);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Auto-Merge & Split Selection
+ *
+ * Used after transform operations.
+ * \{ */
+
+void EDBM_automerge_and_split(Object *obedit,
+ bool UNUSED(split_edges),
+ bool split_faces,
+ bool update,
+ const char hflag,
+ const float dist)
+{
+ bool ok = false;
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+
+#ifdef DEBUG_TIME
+ em->bm = BM_mesh_copy(bm);
+
+ double t1 = PIL_check_seconds_timer();
+ EDBM_automerge(obedit, false, hflag, dist);
+ t1 = PIL_check_seconds_timer() - t1;
+
+ BM_mesh_free(em->bm);
+ em->bm = bm;
+ double t2 = PIL_check_seconds_timer();
+#endif
+
+ BMOperator weldop;
+ BMOpSlot *slot_targetmap;
+
+ BMO_op_init(bm, &weldop, BMO_FLAG_DEFAULTS, "weld_verts");
+ slot_targetmap = BMO_slot_get(weldop.slots_in, "targetmap");
+
+ GHash *ghash_targetmap = BMO_SLOT_AS_GHASH(slot_targetmap);
+
+ ok = BM_mesh_intersect_edges(bm, hflag, dist, ghash_targetmap);
+
+ if (ok) {
+ BMO_op_exec(bm, &weldop);
+
+ BMEdge **edgenet = NULL;
+ int edgenet_alloc_len = 0;
+ if (split_faces) {
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, ghash_targetmap) {
+ BMVert *v = BLI_ghashIterator_getValue(&gh_iter);
+ // BLI_assert(BM_elem_flag_test(v, hflag) || hflag == BM_ELEM_TAG);
+ BM_vert_weld_linked_wire_edges_into_linked_faces(
+ bm, v, dist, &edgenet, &edgenet_alloc_len);
+ }
+ }
+
+ if (edgenet) {
+ MEM_freeN(edgenet);
+ }
+ }
+
+ BMO_op_finish(bm, &weldop);
+
+#ifdef DEBUG_TIME
+ t2 = PIL_check_seconds_timer() - t2;
+ printf("t1: %lf; t2: %lf; fac: %lf\n", t1, t2, t1 / t2);
+#endif
+
+ if (LIKELY(ok) && update) {
+ EDBM_update_generic(em, true, true);
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index b4ef2620895..7afd72f33c9 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -148,9 +148,10 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op)
BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%.1f%%", RNA_float_get(op->ptr, "offset_pct"));
}
else {
+ double offset_val = (double)RNA_float_get(op->ptr, "offset");
bUnit_AsString2(offset_str,
NUM_STR_REP_LEN,
- (double)RNA_float_get(op->ptr, "offset"),
+ offset_val * sce->unit.scale_length,
3,
B_UNIT_LENGTH,
&sce->unit,
diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c
index 283e147b77b..4a511bbb5a2 100644
--- a/source/blender/editors/mesh/editmesh_bisect.c
+++ b/source/blender/editors/mesh/editmesh_bisect.c
@@ -455,7 +455,7 @@ void MESH_OT_bisect(struct wmOperatorType *ot)
0.00001,
0.1);
- WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
+ WM_operator_properties_gesture_straightline(ot, WM_CURSOR_EDIT);
#ifdef USE_GIZMO
WM_gizmogrouptype_append(MESH_GGT_bisect);
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 5b16cfd00f5..c1c8a208471 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -145,10 +145,10 @@ static bool edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const ch
}
/* extrudes individual edges */
-static bool edbm_extrude_edges_indiv(BMEditMesh *em,
- wmOperator *op,
- const char hflag,
- const bool use_normal_flip)
+bool edbm_extrude_edges_indiv(BMEditMesh *em,
+ wmOperator *op,
+ const char hflag,
+ const bool use_normal_flip)
{
BMesh *bm = em->bm;
BMOperator bmop;
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index 370cc6a2a6d..ec740447f93 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -101,17 +101,19 @@ static int bm_face_isect_pair_swap(BMFace *f, void *UNUSED(user_data))
/**
* Use for intersect and boolean.
*/
-static void edbm_intersect_select(BMEditMesh *em)
+static void edbm_intersect_select(BMEditMesh *em, bool do_select)
{
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+ if (do_select) {
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
- if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
- BMIter iter;
- BMEdge *e;
+ if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
+ BMIter iter;
+ BMEdge *e;
- BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- BM_edge_select_set(em->bm, e, true);
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BM_edge_select_set(em->bm, e, true);
+ }
}
}
}
@@ -210,10 +212,9 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op)
em->bm, BM_elem_cb_check_hflag_enabled_simple(const BMFace *, BM_ELEM_SELECT));
}
- if (has_isect) {
- edbm_intersect_select(em);
- }
- else {
+ edbm_intersect_select(em, has_isect);
+
+ if (!has_isect) {
isect_len++;
}
}
@@ -317,10 +318,9 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op)
boolean_operation,
eps);
- if (has_isect) {
- edbm_intersect_select(em);
- }
- else {
+ edbm_intersect_select(em, has_isect);
+
+ if (!has_isect) {
isect_len++;
}
}
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 61f9dc43c0f..395c614f328 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -2777,7 +2777,7 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
op->flag |= OP_IS_MODAL_CURSOR_REGION;
/* add a modal handler for this operator - handles loop selection */
- WM_cursor_modal_set(CTX_wm_window(C), BC_KNIFECURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_KNIFE);
WM_event_add_modal_handler(C, op);
knifetool_update_mval_i(kcd, event->mval);
@@ -2804,8 +2804,8 @@ wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf)
static const EnumPropertyItem modal_items[] = {
{KNF_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
{KNF_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
- {KNF_MODAL_MIDPOINT_ON, "SNAP_MIDPOINTS_ON", 0, "Snap To Midpoints On", ""},
- {KNF_MODAL_MIDPOINT_OFF, "SNAP_MIDPOINTS_OFF", 0, "Snap To Midpoints Off", ""},
+ {KNF_MODAL_MIDPOINT_ON, "SNAP_MIDPOINTS_ON", 0, "Snap to Midpoints On", ""},
+ {KNF_MODAL_MIDPOINT_OFF, "SNAP_MIDPOINTS_OFF", 0, "Snap to Midpoints Off", ""},
{KNF_MODEL_IGNORE_SNAP_ON, "IGNORE_SNAP_ON", 0, "Ignore Snapping On", ""},
{KNF_MODEL_IGNORE_SNAP_OFF, "IGNORE_SNAP_OFF", 0, "Ignore Snapping Off", ""},
{KNF_MODAL_ANGLE_SNAP_TOGGLE, "ANGLE_SNAP_TOGGLE", 0, "Toggle Angle Snapping", ""},
diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c
index 3d34a4ad3b5..a709bd010aa 100644
--- a/source/blender/editors/mesh/editmesh_knife_project.c
+++ b/source/blender/editors/mesh/editmesh_knife_project.c
@@ -22,6 +22,7 @@
*/
#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "BLI_math.h"
@@ -142,10 +143,21 @@ static int knifeproject_exec(bContext *C, wmOperator *op)
/* select only tagged faces */
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
- /* not essential, but switch out of vertex mode since the
- * selected regions wont be nicely isolated after flushing.
- * note: call after de-select to avoid selection flushing */
- EDBM_selectmode_disable(scene, em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
+ CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
+ if (ob->type == OB_MESH) {
+ Mesh *me = (Mesh *)ob->data;
+ BMEditMesh *embm = me->edit_mesh;
+ if (embm) {
+ /* not essential, but switch out of vertex mode since the
+ * selected regions wont be nicely isolated after flushing.
+ * note: call after de-select to avoid selection flushing.
+ * note: do this on all participating meshes so this is in sync
+ * e.g. for later selection picking, see T68852.*/
+ EDBM_selectmode_disable(scene, embm, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
+ }
+ }
+ }
+ CTX_DATA_END;
BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index 2ddd654f824..3be94cf99c1 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -39,10 +39,6 @@
#include "BKE_unit.h"
#include "BKE_layer.h"
-#include "GPU_immediate.h"
-#include "GPU_matrix.h"
-#include "GPU_state.h"
-
#include "UI_interface.h"
#include "ED_screen.h"
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
new file mode 100644
index 00000000000..d066e9ecddc
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -0,0 +1,273 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edmesh
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_editmesh.h"
+#include "BKE_layer.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_paint.h"
+#include "BKE_report.h"
+#include "BKE_shrinkwrap.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+#include "WM_types.h"
+#include "WM_api.h"
+
+#include "ED_mesh.h"
+#include "ED_screen.h"
+#include "ED_object.h"
+#include "ED_sculpt.h"
+#include "ED_view3d.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "mesh_intern.h" /* own include */
+
+static bool paint_mask_extract_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ if (ob->mode == OB_MODE_SCULPT) {
+ if (ob->sculpt->bm) {
+ CTX_wm_operator_poll_msg_set(C, "The mask can not be extracted with dyntopo activated.");
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+ return ED_operator_object_active_editable_mesh(C);
+}
+
+static int paint_mask_extract_exec(bContext *C, wmOperator *op)
+{
+ struct Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ Scene *scene = CTX_data_scene(C);
+
+ Mesh *mesh = ob->data;
+ Mesh *new_mesh = BKE_mesh_copy(bmain, mesh);
+
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(new_mesh);
+ BMesh *bm;
+ bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = true,
+ }));
+
+ BM_mesh_bm_from_me(bm,
+ new_mesh,
+ (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
+
+ BMEditMesh *em = BKE_editmesh_create(bm, false);
+ BMVert *v;
+ BMEdge *ed;
+ BMFace *f;
+ BMIter iter;
+ BMIter face_iter;
+
+ /* Delete all unmasked faces */
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+
+ float mask_threshold = RNA_float_get(op->ptr, "mask_threshold");
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ bool delete_face = false;
+ BM_ITER_ELEM (v, &face_iter, f, BM_VERTS_OF_FACE) {
+ float mask = BM_elem_float_data_get(&bm->vdata, v, CD_PAINT_MASK);
+ delete_face = mask < mask_threshold;
+ }
+ BM_elem_flag_set(f, BM_ELEM_TAG, delete_face);
+ }
+
+ BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_FACES);
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+
+ if (RNA_boolean_get(op->ptr, "add_boundary_loop")) {
+ BM_ITER_MESH (ed, &iter, bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_set(ed, BM_ELEM_TAG, BM_edge_is_boundary(ed));
+ }
+ edbm_extrude_edges_indiv(em, op, BM_ELEM_TAG, false);
+
+ int smooth_iterations = RNA_int_get(op->ptr, "smooth_iterations");
+ for (int repeat = 0; repeat < smooth_iterations; repeat++) {
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_elem_flag_set(v, BM_ELEM_TAG, !BM_vert_is_boundary(v));
+ }
+ for (int i = 0; i < 3; i++) {
+ if (!EDBM_op_callf(em,
+ op,
+ "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b "
+ "mirror_clip_z=%b "
+ "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b",
+ BM_ELEM_TAG,
+ 1.0,
+ false,
+ false,
+ false,
+ 0.1,
+ true,
+ true,
+ true)) {
+ continue;
+ }
+ }
+
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_elem_flag_set(v, BM_ELEM_TAG, BM_vert_is_boundary(v));
+ }
+ for (int i = 0; i < 1; i++) {
+ if (!EDBM_op_callf(em,
+ op,
+ "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b "
+ "mirror_clip_z=%b "
+ "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b",
+ BM_ELEM_TAG,
+ 0.5,
+ false,
+ false,
+ false,
+ 0.1,
+ true,
+ true,
+ true)) {
+ continue;
+ }
+ }
+ }
+ }
+
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+ BKE_editmesh_free_derivedmesh(em);
+
+ BKE_mesh_free(new_mesh);
+ new_mesh = BKE_mesh_from_bmesh_nomain(bm,
+ (&(struct BMeshToMeshParams){
+ .calc_object_remap = false,
+ }),
+ mesh);
+
+ BM_mesh_free(bm);
+
+ if (new_mesh->totvert == 0) {
+ BKE_mesh_free(new_mesh);
+ return OPERATOR_FINISHED;
+ }
+
+ ushort local_view_bits = 0;
+ if (v3d && v3d->localvd) {
+ local_view_bits = v3d->local_view_uuid;
+ }
+ Object *new_ob = ED_object_add_type(C, OB_MESH, NULL, ob->loc, ob->rot, false, local_view_bits);
+ BKE_mesh_nomain_to_mesh(new_mesh, new_ob->data, new_ob, &CD_MASK_EVERYTHING, true);
+
+ BKE_mesh_free(new_mesh);
+
+ if (RNA_boolean_get(op->ptr, "apply_shrinkwrap")) {
+ BKE_shrinkwrap_mesh_nearest_surface_deform(C, new_ob, ob);
+ }
+
+ if (RNA_boolean_get(op->ptr, "add_solidify")) {
+ ED_object_modifier_add(
+ op->reports, bmain, scene, new_ob, "mask_extract_solidify", eModifierType_Solidify);
+ SolidifyModifierData *sfmd = (SolidifyModifierData *)modifiers_findByName(
+ new_ob, "mask_extract_solidify");
+ if (sfmd) {
+ sfmd->offset = -0.05f;
+ }
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, new_ob);
+ BKE_mesh_batch_cache_dirty_tag(new_ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&new_ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, new_ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_paint_mask_extract(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Mask Extract";
+ ot->description = "Create a new mesh object from the current paint mask";
+ ot->idname = "MESH_OT_paint_mask_extract";
+
+ /* api callbacks */
+ ot->poll = paint_mask_extract_poll;
+ ot->invoke = WM_operator_props_popup_confirm;
+ ot->exec = paint_mask_extract_exec;
+
+ ot->flag = OPTYPE_REGISTER;
+
+ RNA_def_float(
+ ot->srna,
+ "mask_threshold",
+ 0.5f,
+ 0.0f,
+ 1.0f,
+ "Threshold",
+ "Minimum mask value to consider the vertex valid to extract a face from the original mesh",
+ 0.0f,
+ 1.0f);
+ RNA_def_boolean(ot->srna,
+ "add_boundary_loop",
+ true,
+ "Add Boundary Loop",
+ "Add an extra edge loop to better preserve the shape when applying a "
+ "subdivision surface modifier");
+ RNA_def_int(ot->srna,
+ "smooth_iterations",
+ 4,
+ 0,
+ INT_MAX,
+ "Smooth Iterations",
+ "Smooth iterations applied to the extracted mesh",
+ 0,
+ 20);
+ RNA_def_boolean(ot->srna,
+ "apply_shrinkwrap",
+ true,
+ "Project to Sculpt",
+ "Project the extracted mesh into the original sculpt");
+ RNA_def_boolean(ot->srna,
+ "add_solidify",
+ true,
+ "Extract as Solid",
+ "Extract the mask as a solid object with a solidify modifier");
+}
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index 6fd0ee83b6c..06c41b78c37 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -239,8 +239,7 @@ static void mouse_mesh_shortest_path_vert(Scene *UNUSED(scene),
}
} while ((node = node->next));
- /* We need to start as if just *after* a 'skip' block... */
- int depth = op_params->interval_params.skip;
+ int depth = -1;
node = path;
do {
if ((is_path_ordered == false) ||
@@ -430,8 +429,7 @@ static void mouse_mesh_shortest_path_edge(Scene *scene,
}
} while ((node = node->next));
- /* We need to start as if just *after* a 'skip' block... */
- int depth = op_params->interval_params.skip;
+ int depth = -1;
node = path;
do {
if ((is_path_ordered == false) ||
@@ -561,8 +559,7 @@ static void mouse_mesh_shortest_path_face(Scene *UNUSED(scene),
}
} while ((node = node->next));
- /* We need to start as if just *after* a 'skip' block... */
- int depth = op_params->interval_params.skip;
+ int depth = -1;
node = path;
do {
if ((is_path_ordered == false) ||
diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c
index 088d1672cc9..21c850160dd 100644
--- a/source/blender/editors/mesh/editmesh_polybuild.c
+++ b/source/blender/editors/mesh/editmesh_polybuild.c
@@ -122,15 +122,160 @@ static bool edbm_preselect_or_active_init_viewcontext(bContext *C,
return ok;
}
+static int edbm_polybuild_transform_at_cursor_invoke(bContext *C,
+ wmOperator *UNUSED(op),
+ const wmEvent *UNUSED(event))
+{
+ ViewContext vc;
+ Base *basact = NULL;
+ BMElem *ele_act = NULL;
+ edbm_preselect_or_active_init_viewcontext(C, &vc, &basact, &ele_act);
+ BMEditMesh *em = vc.em;
+ BMesh *bm = em->bm;
+
+ invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
+ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
+
+ if (!ele_act) {
+ return OPERATOR_CANCELLED;
+ }
+
+ edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX);
+
+ edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
+
+ if (ele_act->head.htype == BM_VERT) {
+ BM_vert_select_set(bm, (BMVert *)ele_act, true);
+ }
+ if (ele_act->head.htype == BM_EDGE) {
+ BM_edge_select_set(bm, (BMEdge *)ele_act, true);
+ }
+ if (ele_act->head.htype == BM_FACE) {
+ BM_face_select_set(bm, (BMFace *)ele_act, true);
+ }
+
+ EDBM_mesh_normals_update(em);
+ EDBM_update_generic(em, true, true);
+ if (basact != NULL) {
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
+ }
+ }
+ BM_select_history_store(bm, ele_act);
+ WM_event_add_mousemove(C);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_polybuild_transform_at_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Poly Build Transform at Cursor";
+ ot->idname = "MESH_OT_polybuild_transform_at_cursor";
+
+ /* api callbacks */
+ ot->invoke = edbm_polybuild_transform_at_cursor_invoke;
+ ot->poll = EDBM_view3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* to give to transform */
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
+}
+
+static int edbm_polybuild_delete_at_cursor_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ bool changed = false;
+
+ ViewContext vc;
+ Base *basact = NULL;
+ BMElem *ele_act = NULL;
+ edbm_preselect_or_active_init_viewcontext(C, &vc, &basact, &ele_act);
+ BMEditMesh *em = vc.em;
+ BMesh *bm = em->bm;
+
+ invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
+ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
+
+ if (!ele_act) {
+ return OPERATOR_CANCELLED;
+ }
+
+ edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX);
+
+ if (ele_act->head.htype == BM_FACE) {
+ BMFace *f_act = (BMFace *)ele_act;
+ EDBM_flag_disable_all(em, BM_ELEM_TAG);
+ BM_elem_flag_enable(f_act, BM_ELEM_TAG);
+ if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_TAG, DEL_FACES)) {
+ return OPERATOR_CANCELLED;
+ }
+ changed = true;
+ }
+ if (ele_act->head.htype == BM_VERT) {
+ BMVert *v_act = (BMVert *)ele_act;
+ if (BM_vert_is_edge_pair(v_act)) {
+ BM_edge_collapse(bm, v_act->e, v_act, true, true);
+ changed = true;
+ }
+ else {
+ EDBM_flag_disable_all(em, BM_ELEM_TAG);
+ BM_elem_flag_enable(v_act, BM_ELEM_TAG);
+
+ if (!EDBM_op_callf(em,
+ op,
+ "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
+ BM_ELEM_TAG,
+ false,
+ false)) {
+ return OPERATOR_CANCELLED;
+ }
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ EDBM_mesh_normals_update(em);
+ EDBM_update_generic(em, true, true);
+ if (basact != NULL) {
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
+ }
+ }
+ WM_event_add_mousemove(C);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void MESH_OT_polybuild_delete_at_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Poly Build Delete at Cursor";
+ ot->idname = "MESH_OT_polybuild_delete_at_cursor";
+
+ /* api callbacks */
+ ot->invoke = edbm_polybuild_delete_at_cursor_invoke;
+ ot->poll = EDBM_view3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* to give to transform */
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Face at Cursor
* \{ */
-static int edbm_polybuild_face_at_cursor_invoke(bContext *C,
- wmOperator *UNUSED(op),
- const wmEvent *event)
+static int edbm_polybuild_face_at_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
float center[3];
bool changed = false;
@@ -168,20 +313,27 @@ static int edbm_polybuild_face_at_cursor_invoke(bContext *C,
mul_m4_v3(vc.obedit->obmat, center);
ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
mul_m4_v3(vc.obedit->imat, center);
-
- BMVert *v_tri[3];
- v_tri[0] = e_act->v1;
- v_tri[1] = e_act->v2;
- v_tri[2] = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
- if (e_act->l && e_act->l->v == v_tri[0]) {
- SWAP(BMVert *, v_tri[0], v_tri[1]);
+ if (f_reference->len == 3 && RNA_boolean_get(op->ptr, "create_quads")) {
+ const float fac = line_point_factor_v3(center, e_act->v1->co, e_act->v2->co);
+ BMVert *v_new = BM_edge_split(bm, e_act, e_act->v1, NULL, CLAMPIS(fac, 0.0f, 1.0f));
+ copy_v3_v3(v_new->co, center);
+ edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
+ BM_vert_select_set(bm, v_new, true);
+ BM_select_history_store(bm, v_new);
+ }
+ else {
+ BMVert *v_tri[3];
+ v_tri[0] = e_act->v1;
+ v_tri[1] = e_act->v2;
+ v_tri[2] = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
+ if (e_act->l && e_act->l->v == v_tri[0]) {
+ SWAP(BMVert *, v_tri[0], v_tri[1]);
+ }
+ BM_face_create_verts(bm, v_tri, 3, f_reference, BM_CREATE_NOP, true);
+ edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
+ BM_vert_select_set(bm, v_tri[2], true);
+ BM_select_history_store(bm, v_tri[2]);
}
- // BMFace *f_new =
- BM_face_create_verts(bm, v_tri, 3, f_reference, BM_CREATE_NOP, true);
-
- edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
- BM_vert_select_set(bm, v_tri[2], true);
- BM_select_history_store(bm, v_tri[2]);
changed = true;
}
else if (ele_act->head.htype == BM_VERT) {
@@ -281,6 +433,11 @@ void MESH_OT_polybuild_face_at_cursor(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ RNA_def_boolean(ot->srna,
+ "create_quads",
+ true,
+ "Create quads",
+ "Automatically split edges in triangles to maintain quad topology");
/* to give to transform */
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
}
diff --git a/source/blender/editors/mesh/editmesh_preselect_elem.c b/source/blender/editors/mesh/editmesh_preselect_elem.c
index a3e684a5493..05c4da68355 100644
--- a/source/blender/editors/mesh/editmesh_preselect_elem.c
+++ b/source/blender/editors/mesh/editmesh_preselect_elem.c
@@ -75,20 +75,49 @@ struct EditMesh_PreSelElem {
float (*verts)[3];
int verts_len;
+
+ float (*preview_tris)[3][3];
+ int preview_tris_len;
+ float (*preview_lines)[2][3];
+ int preview_lines_len;
+
+ eEditMesh_PreSelPreviewAction preview_action;
};
+void EDBM_preselect_action_set(struct EditMesh_PreSelElem *psel,
+ eEditMesh_PreSelPreviewAction action)
+{
+ psel->preview_action = action;
+}
+
+eEditMesh_PreSelPreviewAction EDBM_preselect_action_get(struct EditMesh_PreSelElem *psel)
+{
+ return psel->preview_action;
+}
+
struct EditMesh_PreSelElem *EDBM_preselect_elem_create(void)
{
struct EditMesh_PreSelElem *psel = MEM_callocN(sizeof(*psel), __func__);
+ psel->preview_action = PRESELECT_ACTION_TRANSFORM;
return psel;
}
void EDBM_preselect_elem_destroy(struct EditMesh_PreSelElem *psel)
{
EDBM_preselect_elem_clear(psel);
+ EDBM_preselect_preview_clear(psel);
MEM_freeN(psel);
}
+void EDBM_preselect_preview_clear(struct EditMesh_PreSelElem *psel)
+{
+ MEM_SAFE_FREE(psel->preview_tris);
+ psel->preview_tris_len = 0;
+
+ MEM_SAFE_FREE(psel->preview_lines);
+ psel->preview_lines_len = 0;
+}
+
void EDBM_preselect_elem_clear(struct EditMesh_PreSelElem *psel)
{
MEM_SAFE_FREE(psel->edges);
@@ -112,9 +141,42 @@ void EDBM_preselect_elem_draw(struct EditMesh_PreSelElem *psel, const float matr
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- immUniformColor3ub(255, 0, 255);
+
+ immUniformColor4ub(141, 171, 186, 100);
+ if (psel->preview_action != PRESELECT_ACTION_TRANSFORM) {
+ if (psel->preview_tris_len > 0) {
+ immBegin(GPU_PRIM_TRIS, psel->preview_tris_len * 3);
+
+ for (int i = 0; i < psel->preview_tris_len; i++) {
+ immVertex3fv(pos, psel->preview_tris[i][0]);
+ immVertex3fv(pos, psel->preview_tris[i][1]);
+ immVertex3fv(pos, psel->preview_tris[i][2]);
+ }
+ immEnd();
+ }
+
+ if (psel->preview_lines_len > 0) {
+
+ immUniformColor4ub(3, 161, 252, 200);
+ GPU_line_width(2.0f);
+ immBegin(GPU_PRIM_LINES, psel->preview_lines_len * 2);
+ for (int i = 0; i < psel->preview_lines_len; i++) {
+ immVertex3fv(pos, psel->preview_lines[i][0]);
+ immVertex3fv(pos, psel->preview_lines[i][1]);
+ }
+ immEnd();
+ }
+ }
+
+ if (psel->preview_action == PRESELECT_ACTION_DELETE) {
+ immUniformColor4ub(252, 49, 10, 200);
+ }
+ else {
+ immUniformColor4ub(3, 161, 252, 200);
+ }
if (psel->edges_len > 0) {
+ GPU_line_width(3.0f);
immBegin(GPU_PRIM_LINES, psel->edges_len * 2);
for (int i = 0; i < psel->edges_len; i++) {
@@ -126,7 +188,7 @@ void EDBM_preselect_elem_draw(struct EditMesh_PreSelElem *psel, const float matr
}
if (psel->verts_len > 0) {
- GPU_point_size(3.0f);
+ GPU_point_size(4.0f);
immBegin(GPU_PRIM_POINTS, psel->verts_len);
@@ -167,6 +229,122 @@ static void view3d_preselect_mesh_elem_update_from_edge(struct EditMesh_PreSelEl
psel->edges_len = 1;
}
+static void view3d_preselect_update_preview_triangle_from_vert(struct EditMesh_PreSelElem *psel,
+ ViewContext *vc,
+ BMesh *UNUSED(bm),
+ BMVert *eed,
+ const int mval[2])
+{
+ BMVert *v_act = eed;
+ BMEdge *e_pair[2] = {NULL};
+ float center[3];
+
+ if (v_act->e != NULL) {
+ for (uint allow_wire = 0; allow_wire < 2 && (e_pair[1] == NULL); allow_wire++) {
+ int i = 0;
+ BMEdge *e_iter = v_act->e;
+ do {
+ if ((BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == false) &&
+ (allow_wire ? BM_edge_is_wire(e_iter) : BM_edge_is_boundary(e_iter))) {
+ if (i == 2) {
+ e_pair[0] = e_pair[1] = NULL;
+ break;
+ }
+ e_pair[i++] = e_iter;
+ }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v_act)) != v_act->e);
+ }
+ }
+
+ if (e_pair[1] != NULL) {
+ mul_v3_m4v3(center, vc->obedit->obmat, v_act->co);
+ ED_view3d_win_to_3d_int(vc->v3d, vc->ar, center, mval, center);
+ mul_m4_v3(vc->obedit->imat, center);
+
+ psel->preview_tris = MEM_mallocN(sizeof(*psel->preview_tris) * 2, __func__);
+ psel->preview_lines = MEM_mallocN(sizeof(*psel->preview_lines) * 4, __func__);
+
+ copy_v3_v3(psel->preview_tris[0][0], e_pair[0]->v1->co);
+ copy_v3_v3(psel->preview_tris[0][1], e_pair[0]->v2->co);
+ copy_v3_v3(psel->preview_tris[0][2], center);
+
+ copy_v3_v3(psel->preview_tris[1][0], e_pair[1]->v1->co);
+ copy_v3_v3(psel->preview_tris[1][1], e_pair[1]->v2->co);
+ copy_v3_v3(psel->preview_tris[1][2], center);
+
+ copy_v3_v3(psel->preview_lines[0][0], e_pair[0]->v1->co);
+ copy_v3_v3(psel->preview_lines[0][1], e_pair[0]->v2->co);
+
+ copy_v3_v3(psel->preview_lines[1][0], e_pair[1]->v1->co);
+ copy_v3_v3(psel->preview_lines[1][1], e_pair[1]->v2->co);
+
+ copy_v3_v3(psel->preview_lines[2][0], center);
+ if (e_pair[0]->v1 == v_act) {
+ copy_v3_v3(psel->preview_lines[2][1], e_pair[0]->v2->co);
+ }
+ else {
+ copy_v3_v3(psel->preview_lines[2][1], e_pair[0]->v1->co);
+ }
+
+ copy_v3_v3(psel->preview_lines[3][0], center);
+ if (e_pair[1]->v1 == v_act) {
+ copy_v3_v3(psel->preview_lines[3][1], e_pair[1]->v2->co);
+ }
+ else {
+ copy_v3_v3(psel->preview_lines[3][1], e_pair[1]->v1->co);
+ }
+ psel->preview_tris_len = 2;
+ psel->preview_lines_len = 4;
+ }
+}
+
+static void view3d_preselect_update_preview_triangle_from_face(struct EditMesh_PreSelElem *psel,
+ ViewContext *UNUSED(vc),
+ BMesh *UNUSED(bm),
+ BMFace *efa,
+ const int UNUSED(mval[2]))
+{
+ float(*preview_lines)[2][3] = MEM_mallocN(sizeof(*psel->edges) * efa->len, __func__);
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ int i = 0;
+ do {
+ vcos_get_pair(&l_iter->e->v1, preview_lines[i++], NULL);
+ } while ((l_iter = l_iter->next) != l_first);
+ psel->preview_lines = preview_lines;
+ psel->preview_lines_len = efa->len;
+}
+
+static void view3d_preselect_update_preview_triangle_from_edge(struct EditMesh_PreSelElem *psel,
+ ViewContext *vc,
+ BMesh *UNUSED(bm),
+ BMEdge *eed,
+ const int mval[2])
+{
+ float center[3];
+ psel->preview_tris = MEM_mallocN(sizeof(*psel->preview_tris), __func__);
+ psel->preview_lines = MEM_mallocN(sizeof(*psel->preview_lines) * 3, __func__);
+ mid_v3_v3v3(center, eed->v1->co, eed->v2->co);
+ mul_m4_v3(vc->obedit->obmat, center);
+ ED_view3d_win_to_3d_int(vc->v3d, vc->ar, center, mval, center);
+ mul_m4_v3(vc->obedit->imat, center);
+
+ copy_v3_v3(psel->preview_tris[0][0], eed->v1->co);
+ copy_v3_v3(psel->preview_tris[0][1], eed->v2->co);
+ copy_v3_v3(psel->preview_tris[0][2], center);
+
+ copy_v3_v3(psel->preview_lines[0][0], eed->v1->co);
+ copy_v3_v3(psel->preview_lines[0][1], eed->v2->co);
+
+ copy_v3_v3(psel->preview_lines[1][0], eed->v2->co);
+ copy_v3_v3(psel->preview_lines[1][1], center);
+
+ copy_v3_v3(psel->preview_lines[2][0], center);
+ copy_v3_v3(psel->preview_lines[2][1], eed->v1->co);
+ psel->preview_tris_len = 1;
+ psel->preview_lines_len = 3;
+}
+
static void view3d_preselect_mesh_elem_update_from_face(struct EditMesh_PreSelElem *psel,
BMesh *UNUSED(bm),
BMFace *efa,
@@ -209,4 +387,28 @@ void EDBM_preselect_elem_update_from_single(struct EditMesh_PreSelElem *psel,
}
}
+void EDBM_preselect_elem_update_preview(struct EditMesh_PreSelElem *psel,
+ struct ViewContext *vc,
+ struct BMesh *bm,
+ struct BMElem *ele,
+ const int mval[2])
+{
+ EDBM_preselect_preview_clear(psel);
+
+ switch (ele->head.htype) {
+ case BM_VERT:
+ if (EDBM_preselect_action_get(psel) == PRESELECT_ACTION_CREATE) {
+ view3d_preselect_update_preview_triangle_from_vert(psel, vc, bm, (BMVert *)ele, mval);
+ }
+ break;
+ case BM_EDGE:
+ view3d_preselect_update_preview_triangle_from_edge(psel, vc, bm, (BMEdge *)ele, mval);
+ break;
+ case BM_FACE:
+ view3d_preselect_update_preview_triangle_from_face(psel, vc, bm, (BMFace *)ele, mval);
+ break;
+ default:
+ BLI_assert(0);
+ }
+}
/** \} */
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 94ffd9a34d6..3e59a884696 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -24,7 +24,6 @@
#include "MEM_guardedalloc.h"
#include "BLI_bitmap.h"
-#include "BLI_bitmap_draw_2d.h"
#include "BLI_listbase.h"
#include "BLI_linklist.h"
#include "BLI_linklist_stack.h"
@@ -32,16 +31,14 @@
#include "BLI_math_bits.h"
#include "BLI_rand.h"
#include "BLI_array.h"
+#include "BLI_heap.h"
+#include "BLI_utildefines_stack.h"
#include "BKE_context.h"
#include "BKE_report.h"
-#include "BKE_paint.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
-#include "IMB_imbuf_types.h"
-#include "IMB_imbuf.h"
-
#include "WM_api.h"
#include "WM_types.h"
@@ -67,7 +64,6 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
-#include "DRW_engine.h"
#include "DRW_select_buffer.h"
#include "mesh_intern.h" /* own include */
@@ -172,30 +168,6 @@ void EDBM_select_mirrored(
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Select Auto-Merge
- *
- * Used after transform operations.
- * \{ */
-
-void EDBM_automerge(Scene *scene, Object *obedit, bool update, const char hflag)
-{
- bool ok;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- ok = BMO_op_callf(em->bm,
- BMO_FLAG_DEFAULTS,
- "automerge verts=%hv dist=%f",
- hflag,
- scene->toolsettings->doublimit);
-
- if (LIKELY(ok) && update) {
- EDBM_update_generic(em, true, true);
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Back-Buffer OpenGL Selection
* \{ */
@@ -1031,8 +1003,11 @@ bool EDBM_unified_findnearest(ViewContext *vc,
bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
Base **bases,
const uint bases_len,
- bool use_boundary,
- int *r_base_index,
+ bool use_boundary_vertices,
+ bool use_boundary_edges,
+ int *r_base_index_vert,
+ int *r_base_index_edge,
+ int *r_base_index_face,
struct BMVert **r_eve,
struct BMEdge **r_eed,
struct BMFace **r_efa)
@@ -1045,10 +1020,30 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
uint base_index;
BMElem *ele;
} best = {0, NULL};
+ /* Currently unused, keep since we may want to pick the best. */
+ UNUSED_VARS(best);
+
+ struct {
+ uint base_index;
+ BMElem *ele;
+ } best_vert = {0, NULL};
+
+ struct {
+ uint base_index;
+ BMElem *ele;
+ } best_edge = {0, NULL};
+
+ struct {
+ uint base_index;
+ BMElem *ele;
+ } best_face = {0, NULL};
if (ED_view3d_win_to_ray_clipped(
vc->depsgraph, vc->ar, vc->v3d, mval_fl, ray_origin, ray_direction, true)) {
float dist_sq_best = FLT_MAX;
+ float dist_sq_best_vert = FLT_MAX;
+ float dist_sq_best_edge = FLT_MAX;
+ float dist_sq_best_face = FLT_MAX;
const bool use_vert = (r_eve != NULL);
const bool use_edge = (r_eed != NULL);
@@ -1078,18 +1073,23 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
BM_mesh_elem_index_ensure(bm, BM_VERT);
}
- if (use_boundary && (use_vert || use_edge)) {
+ if ((use_boundary_vertices || use_boundary_edges) && (use_vert || use_edge)) {
BMEdge *e;
BMIter eiter;
BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
if ((BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) && (BM_edge_is_boundary(e))) {
- if (use_vert) {
+ if (use_vert && use_boundary_vertices) {
for (uint j = 0; j < 2; j++) {
BMVert *v = *((&e->v1) + j);
float point[3];
mul_v3_m4v3(point, obedit->obmat, coords ? coords[BM_elem_index_get(v)] : v->co);
const float dist_sq_test = dist_squared_to_ray_v3_normalized(
ray_origin, ray_direction, point);
+ if (dist_sq_test < dist_sq_best_vert) {
+ dist_sq_best_vert = dist_sq_test;
+ best_vert.base_index = base_index;
+ best_vert.ele = (BMElem *)v;
+ }
if (dist_sq_test < dist_sq_best) {
dist_sq_best = dist_sq_test;
best.base_index = base_index;
@@ -1098,7 +1098,7 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
}
}
- if (use_edge) {
+ if (use_edge && use_boundary_edges) {
float point[3];
#if 0
const float dist_sq_test = dist_squared_ray_to_seg_v3(
@@ -1114,6 +1114,11 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
mul_m4_v3(obedit->obmat, point);
const float dist_sq_test = dist_squared_to_ray_v3_normalized(
ray_origin, ray_direction, point);
+ if (dist_sq_test < dist_sq_best_edge) {
+ dist_sq_best_edge = dist_sq_test;
+ best_edge.base_index = base_index;
+ best_edge.ele = (BMElem *)e;
+ }
if (dist_sq_test < dist_sq_best) {
dist_sq_best = dist_sq_test;
best.base_index = base_index;
@@ -1124,46 +1129,55 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
}
}
}
- else {
- /* Non boundary case. */
- if (use_vert) {
- BMVert *v;
- BMIter viter;
- BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == false) {
- float point[3];
- mul_v3_m4v3(point, obedit->obmat, v->co);
- const float dist_sq_test = dist_squared_to_ray_v3_normalized(
- ray_origin, ray_direction, v->co);
- if (dist_sq_test < dist_sq_best) {
- dist_sq_best = dist_sq_test;
- best.base_index = base_index;
- best.ele = (BMElem *)v;
- }
+ /* Non boundary case. */
+ if (use_vert && !use_boundary_vertices) {
+ BMVert *v;
+ BMIter viter;
+ BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == false) {
+ float point[3];
+ mul_v3_m4v3(point, obedit->obmat, coords ? coords[BM_elem_index_get(v)] : v->co);
+ const float dist_sq_test = dist_squared_to_ray_v3_normalized(
+ ray_origin, ray_direction, point);
+ if (dist_sq_test < dist_sq_best_vert) {
+ dist_sq_best_vert = dist_sq_test;
+ best_vert.base_index = base_index;
+ best_vert.ele = (BMElem *)v;
+ }
+ if (dist_sq_test < dist_sq_best) {
+ dist_sq_best = dist_sq_test;
+ best.base_index = base_index;
+ best.ele = (BMElem *)v;
}
}
}
- if (use_edge) {
- BMEdge *e;
- BMIter eiter;
- BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) {
- float point[3];
- if (coords) {
- mid_v3_v3v3(
- point, coords[BM_elem_index_get(e->v1)], coords[BM_elem_index_get(e->v2)]);
- }
- else {
- mid_v3_v3v3(point, e->v1->co, e->v2->co);
- }
- mul_m4_v3(obedit->obmat, point);
- const float dist_sq_test = dist_squared_to_ray_v3_normalized(
- ray_origin, ray_direction, point);
- if (dist_sq_test < dist_sq_best) {
- dist_sq_best = dist_sq_test;
- best.base_index = base_index;
- best.ele = (BMElem *)e;
- }
+ }
+
+ if (use_edge && !use_boundary_edges) {
+ BMEdge *e;
+ BMIter eiter;
+ BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) {
+ float point[3];
+ if (coords) {
+ mid_v3_v3v3(
+ point, coords[BM_elem_index_get(e->v1)], coords[BM_elem_index_get(e->v2)]);
+ }
+ else {
+ mid_v3_v3v3(point, e->v1->co, e->v2->co);
+ }
+ mul_m4_v3(obedit->obmat, point);
+ const float dist_sq_test = dist_squared_to_ray_v3_normalized(
+ ray_origin, ray_direction, point);
+ if (dist_sq_test < dist_sq_best_edge) {
+ dist_sq_best_edge = dist_sq_test;
+ best_edge.base_index = base_index;
+ best_edge.ele = (BMElem *)e;
+ }
+ if (dist_sq_test < dist_sq_best) {
+ dist_sq_best = dist_sq_test;
+ best.base_index = base_index;
+ best.ele = (BMElem *)e;
}
}
}
@@ -1184,6 +1198,11 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
mul_m4_v3(obedit->obmat, point);
const float dist_sq_test = dist_squared_to_ray_v3_normalized(
ray_origin, ray_direction, point);
+ if (dist_sq_test < dist_sq_best_face) {
+ dist_sq_best_face = dist_sq_test;
+ best_face.base_index = base_index;
+ best_face.ele = (BMElem *)f;
+ }
if (dist_sq_test < dist_sq_best) {
dist_sq_best = dist_sq_test;
best.base_index = base_index;
@@ -1195,7 +1214,10 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
}
}
- *r_base_index = best.base_index;
+ *r_base_index_vert = best_vert.base_index;
+ *r_base_index_edge = best_edge.base_index;
+ *r_base_index_face = best_face.base_index;
+
if (r_eve) {
*r_eve = NULL;
}
@@ -1206,22 +1228,17 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
*r_efa = NULL;
}
- if (best.ele) {
- switch (best.ele->head.htype) {
- case BM_VERT:
- *r_eve = (BMVert *)best.ele;
- break;
- case BM_EDGE:
- *r_eed = (BMEdge *)best.ele;
- break;
- case BM_FACE:
- *r_efa = (BMFace *)best.ele;
- break;
- default:
- BLI_assert(0);
- }
+ if (best_vert.ele) {
+ *r_eve = (BMVert *)best_vert.ele;
}
- return (best.ele != NULL);
+ if (best_edge.ele) {
+ *r_eed = (BMEdge *)best_edge.ele;
+ }
+ if (best_face.ele) {
+ *r_efa = (BMFace *)best_face.ele;
+ }
+
+ return (best_vert.ele != NULL || best_edge.ele != NULL || best_face.ele != NULL);
}
/** \} */
@@ -1328,7 +1345,7 @@ static int edbm_select_mode_exec(bContext *C, wmOperator *op)
const bool use_extend = RNA_boolean_get(op->ptr, "use_extend");
const bool use_expand = RNA_boolean_get(op->ptr, "use_expand");
- if (EDBM_selectmode_toggle(C, type, action, use_extend, use_expand)) {
+ if (EDBM_selectmode_toggle_multi(C, type, action, use_extend, use_expand)) {
return OPERATOR_FINISHED;
}
else {
@@ -1366,13 +1383,6 @@ void MESH_OT_select_mode(wmOperatorType *ot)
{
PropertyRNA *prop;
- static const EnumPropertyItem elem_items[] = {
- {SCE_SELECT_VERTEX, "VERT", ICON_VERTEXSEL, "Vertices", ""},
- {SCE_SELECT_EDGE, "EDGE", ICON_EDGESEL, "Edges", ""},
- {SCE_SELECT_FACE, "FACE", ICON_FACESEL, "Faces", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
static const EnumPropertyItem actions_items[] = {
{0, "DISABLE", 0, "Disable", "Disable selected markers"},
{1, "ENABLE", 0, "Enable", "Enable selected markers"},
@@ -1399,7 +1409,7 @@ void MESH_OT_select_mode(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "use_expand", false, "Expand", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- ot->prop = prop = RNA_def_enum(ot->srna, "type", elem_items, 0, "Type", "");
+ ot->prop = prop = RNA_def_enum(ot->srna, "type", rna_enum_mesh_select_mode_items, 0, "Type", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_enum(
@@ -2338,11 +2348,11 @@ void EDBM_selectmode_convert(BMEditMesh *em,
}
/* user facing function, does notification */
-bool EDBM_selectmode_toggle(bContext *C,
- const short selectmode_new,
- const int action,
- const bool use_extend,
- const bool use_expand)
+bool EDBM_selectmode_toggle_multi(bContext *C,
+ const short selectmode_new,
+ const int action,
+ const bool use_extend,
+ const bool use_expand)
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -2464,6 +2474,54 @@ bool EDBM_selectmode_toggle(bContext *C,
return ret;
}
+bool EDBM_selectmode_set_multi(bContext *C, const short selectmode)
+{
+ BLI_assert(selectmode != 0);
+ bool changed = false;
+
+ {
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = NULL;
+ if (obedit && obedit->type == OB_MESH) {
+ em = BKE_editmesh_from_object(obedit);
+ }
+ if (em == NULL) {
+ return changed;
+ }
+ }
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+
+ if (ts->selectmode != selectmode) {
+ ts->selectmode = selectmode;
+ changed = true;
+ }
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
+ if (em_iter->selectmode != ts->selectmode) {
+ em_iter->selectmode = ts->selectmode;
+ EDBM_selectmode_set(em_iter);
+ DEG_id_tag_update(ob_iter->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data);
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+ }
+ return changed;
+}
+
/**
* Use to disable a selectmode if its enabled, Using another mode as a fallback
* if the disabled mode is the only mode set.
@@ -2584,8 +2642,9 @@ bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, const uint bases_len)
bool EDBM_mesh_deselect_all_multi(struct bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &bases_len);
@@ -2599,39 +2658,334 @@ bool EDBM_mesh_deselect_all_multi(struct bContext *C)
/* -------------------------------------------------------------------- */
/** \name Select Interior Faces
*
- * \note This algorithm is limited to single faces and could be improved, see:
- * https://blender.stackexchange.com/questions/18916
+ * Overview of the algorithm:
+ * - Groups faces surrounded by edges with 3+ faces using them.
+ * - Calculates a cost of each face group comparing it's angle with the faces
+ * connected to it's non-manifold edges.
+ * - Mark the face group as interior, and mark connected face groups for recalculation.
+ * - Continue to remove the face groups with the highest 'cost'.
+ *
* \{ */
+struct BMFaceLink {
+ struct BMFaceLink *next, *prev;
+ BMFace *face;
+ float area;
+};
+
+static bool bm_interior_loop_filter_fn(const BMLoop *l, void *UNUSED(user_data))
+{
+ if (BM_elem_flag_test(l->e, BM_ELEM_TAG)) {
+ return false;
+ }
+ return true;
+}
+static bool bm_interior_edge_is_manifold_except_face_index(BMEdge *e,
+ int face_index,
+ BMLoop *r_l_pair[2])
+{
+
+ BMLoop *l_iter = e->l;
+ int loop_index = 0;
+ do {
+ BMFace *f = l_iter->f;
+ int i = BM_elem_index_get(f);
+ if (!ELEM(i, -1, face_index)) {
+ if (loop_index == 2) {
+ return false;
+ }
+ r_l_pair[loop_index++] = l_iter;
+ }
+ } while ((l_iter = l_iter->radial_next) != e->l);
+ return (loop_index == 2);
+}
+
+/**
+ * Calculate the cost of the face group.
+ * A higher value means it's more likely to remove first.
+ */
+static float bm_interior_face_group_calc_cost(ListBase *ls, const float *edge_lengths)
+{
+ /* Dividing by the area is important so larger face groups (which will become the outer shell)
+ * aren't detected as having a high cost. */
+ float area = 0.0f;
+ float cost = 0.0f;
+ bool found = false;
+ LISTBASE_FOREACH (struct BMFaceLink *, f_link, ls) {
+ BMFace *f = f_link->face;
+ area += f_link->area;
+ int i = BM_elem_index_get(f);
+ BLI_assert(i != -1);
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (BM_elem_flag_test(l_iter->e, BM_ELEM_TAG)) {
+ float cost_test = 0.0f;
+ int cost_count = 0;
+ /* All other faces. */
+ BMLoop *l_radial_iter = l_iter;
+ do {
+ int i_other = BM_elem_index_get(l_radial_iter->f);
+ if (!ELEM(i_other, -1, i)) {
+ float angle = angle_normalized_v3v3(f->no, l_radial_iter->f->no);
+ /* Ignore face direction since in the case on non-manifold faces connecting edges,
+ * the face flipping may not be meaningful. */
+ if (angle > DEG2RADF(90)) {
+ angle = DEG2RADF(180) - angle;
+ }
+ /* Avoid calculating it inline, pass in pre-calculated edge lengths. */
+#if 0
+ cost_test += BM_edge_calc_length(l_iter->e) * angle;
+#else
+ BLI_assert(edge_lengths[BM_elem_index_get(l_iter->e)] != -1.0f);
+ cost_test += edge_lengths[BM_elem_index_get(l_iter->e)] * angle;
+#endif
+ cost_count += 1;
+ }
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
+
+ if (cost_count >= 2) {
+ cost += cost_test;
+ found = true;
+ }
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ return found ? cost / area : FLT_MAX;
+}
+
bool EDBM_select_interior_faces(BMEditMesh *em)
{
BMesh *bm = em->bm;
BMIter iter;
- BMIter eiter;
- BMFace *efa;
- BMEdge *eed;
- bool ok;
bool changed = false;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- continue;
+ float *edge_lengths = MEM_mallocN(sizeof(*edge_lengths) * bm->totedge, __func__);
+
+ {
+ bool has_nonmanifold = false;
+ BMEdge *e;
+ int i;
+ BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
+ const bool is_over = BM_edge_face_count_is_over(e, 2);
+ if (is_over) {
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ has_nonmanifold = true;
+ edge_lengths[i] = BM_edge_calc_length(e);
+ }
+ else {
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
+ edge_lengths[i] = -1.0;
+ }
+
+ BM_elem_index_set(e, i); /* set_inline */
}
+ bm->elem_index_dirty &= ~BM_EDGE;
- ok = true;
- BM_ITER_ELEM (eed, &eiter, efa, BM_EDGES_OF_FACE) {
- if (!BM_edge_face_count_is_over(eed, 2)) {
- ok = false;
+ if (has_nonmanifold == false) {
+ MEM_freeN(edge_lengths);
+ return false;
+ }
+ }
+
+ /* group vars */
+ int *fgroup_array;
+ int(*fgroup_index)[2];
+ int fgroup_len;
+
+ fgroup_array = MEM_mallocN(sizeof(*fgroup_array) * bm->totface, __func__);
+ fgroup_len = BM_mesh_calc_face_groups(
+ bm, fgroup_array, &fgroup_index, bm_interior_loop_filter_fn, NULL, 0, BM_EDGE);
+
+ int *fgroup_recalc_stack = MEM_mallocN(sizeof(*fgroup_recalc_stack) * fgroup_len, __func__);
+ STACK_DECLARE(fgroup_recalc_stack);
+ STACK_INIT(fgroup_recalc_stack, fgroup_len);
+
+ BM_mesh_elem_table_ensure(bm, BM_FACE);
+
+ {
+ BMFace *f;
+ BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_index_set(f, -1); /* set_dirty! */
+ }
+ }
+ bm->elem_index_dirty |= BM_FACE;
+
+ ListBase *fgroup_listbase = MEM_callocN(sizeof(*fgroup_listbase) * fgroup_len, __func__);
+ struct BMFaceLink *f_link_array = MEM_callocN(sizeof(*f_link_array) * bm->totface, __func__);
+
+ for (int i = 0; i < fgroup_len; i++) {
+ const int fg_sta = fgroup_index[i][0];
+ const int fg_len = fgroup_index[i][1];
+ for (int j = 0; j < fg_len; j++) {
+ const int face_index = fgroup_array[fg_sta + j];
+ BMFace *f = BM_face_at_index(bm, face_index);
+ BM_elem_index_set(f, i);
+
+ struct BMFaceLink *f_link = &f_link_array[face_index];
+ f_link->face = f;
+ f_link->area = BM_face_calc_area(f);
+ BLI_addtail(&fgroup_listbase[i], f_link);
+ }
+ }
+
+ MEM_freeN(fgroup_array);
+ MEM_freeN(fgroup_index);
+
+ Heap *fgroup_heap = BLI_heap_new_ex(fgroup_len);
+ HeapNode **fgroup_table = MEM_mallocN(sizeof(*fgroup_table) * fgroup_len, __func__);
+ bool *fgroup_dirty = MEM_callocN(sizeof(*fgroup_dirty) * fgroup_len, __func__);
+
+ for (int i = 0; i < fgroup_len; i++) {
+ const float cost = bm_interior_face_group_calc_cost(&fgroup_listbase[i], edge_lengths);
+ if (cost != FLT_MAX) {
+ fgroup_table[i] = BLI_heap_insert(fgroup_heap, -cost, POINTER_FROM_INT(i));
+ }
+ else {
+ fgroup_table[i] = NULL;
+ }
+ }
+
+ /* Avoid re-running cost calculations for large face-groups which will end up forming the
+ * outer shell and not be considered interior.
+ * As these face groups become increasingly bigger - their chance of being considered
+ * interior reduces as does the time to calculate their cost.
+ *
+ * This delays recalculating them until they are considered can dates to remove
+ * which becomes less and less likely as they increase in area. */
+
+#define USE_DELAY_FACE_GROUP_COST_CALC
+
+ while (true) {
+
+#if defined(USE_DELAY_FACE_GROUP_COST_CALC)
+ while (!BLI_heap_is_empty(fgroup_heap)) {
+ HeapNode *node_min = BLI_heap_top(fgroup_heap);
+ const int i = POINTER_AS_INT(BLI_heap_node_ptr(node_min));
+ if (fgroup_dirty[i]) {
+ const float cost = bm_interior_face_group_calc_cost(&fgroup_listbase[i], edge_lengths);
+ if (cost != FLT_MAX) {
+ /* The cost may have improves (we may be able to skip this),
+ * however the cost should _never_ make this a choice. */
+ BLI_assert(-BLI_heap_node_value(node_min) >= cost);
+ BLI_heap_node_value_update(fgroup_heap, fgroup_table[i], -cost);
+ }
+ else {
+ BLI_heap_remove(fgroup_heap, fgroup_table[i]);
+ fgroup_table[i] = NULL;
+ }
+ fgroup_dirty[i] = false;
+ }
+ else {
break;
}
}
+#endif
- if (ok) {
- BM_face_select_set(bm, efa, true);
- changed = true;
+ if (BLI_heap_is_empty(fgroup_heap)) {
+ break;
}
+
+ const int i_min = POINTER_AS_INT(BLI_heap_pop_min(fgroup_heap));
+ BLI_assert(fgroup_table[i_min] != NULL);
+ BLI_assert(fgroup_dirty[i_min] == false);
+ fgroup_table[i_min] = NULL;
+ changed = true;
+
+ struct BMFaceLink *f_link;
+ while ((f_link = BLI_pophead(&fgroup_listbase[i_min]))) {
+ BMFace *f = f_link->face;
+ BM_face_select_set(bm, f, true);
+ BM_elem_index_set(f, -1); /* set-dirty */
+
+ BMLoop *l_iter, *l_first;
+
+ /* Loop over edges face edges, merging groups which are no longer separated
+ * by non-manifold edges (when manifold check ignores faces from this group). */
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BMLoop *l_pair[2];
+ if (bm_interior_edge_is_manifold_except_face_index(l_iter->e, i_min, l_pair)) {
+ BM_elem_flag_disable(l_iter->e, BM_ELEM_TAG);
+
+ int i_a = BM_elem_index_get(l_pair[0]->f);
+ int i_b = BM_elem_index_get(l_pair[1]->f);
+ if (i_a != i_b) {
+ /* Only for predictable results that don't depend on the order of radial loops,
+ * not essential. */
+ if (i_a > i_b) {
+ SWAP(int, i_a, i_b);
+ }
+
+ /* Merge the the groups. */
+ LISTBASE_FOREACH (LinkData *, n, &fgroup_listbase[i_b]) {
+ BMFace *f_iter = n->data;
+ BM_elem_index_set(f_iter, i_a);
+ }
+ BLI_movelisttolist(&fgroup_listbase[i_a], &fgroup_listbase[i_b]);
+
+ /* This may have been added to 'fgroup_recalc_stack', instead of removing it,
+ * just check the heap node isn't NULL before recalculating. */
+ BLI_heap_remove(fgroup_heap, fgroup_table[i_b]);
+ fgroup_table[i_b] = NULL;
+ /* Keep the dirty flag as-is for 'i_b', because it may be in the 'fgroup_recalc_stack'
+ * and we don't want to add it again.
+ * Instead rely on the 'fgroup_table[i_b]' being NULL as a secondary check. */
+
+ if (fgroup_dirty[i_a] == false) {
+ BLI_assert(fgroup_table[i_a] != NULL);
+ STACK_PUSH(fgroup_recalc_stack, i_a);
+ fgroup_dirty[i_a] = true;
+ }
+ }
+ }
+
+ /* Mark all connected groups for re-calculation. */
+ BMLoop *l_radial_iter = l_iter->radial_next;
+ if (l_radial_iter != l_iter) {
+ do {
+ int i_other = BM_elem_index_get(l_radial_iter->f);
+ if (!ELEM(i_other, -1, i_min)) {
+ if ((fgroup_table[i_other] != NULL) && (fgroup_dirty[i_other] == false)) {
+#if !defined(USE_DELAY_FACE_GROUP_COST_CALC)
+ STACK_PUSH(fgroup_recalc_stack, i_other);
+#endif
+ fgroup_dirty[i_other] = true;
+ }
+ }
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
+ }
+
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ for (int index = 0; index < STACK_SIZE(fgroup_recalc_stack); index++) {
+ const int i = fgroup_recalc_stack[index];
+ if (fgroup_table[i] != NULL && fgroup_dirty[i] == true) {
+ /* First update edge tags. */
+ const float cost = bm_interior_face_group_calc_cost(&fgroup_listbase[i], edge_lengths);
+ if (cost != FLT_MAX) {
+ BLI_heap_node_value_update(fgroup_heap, fgroup_table[i], -cost);
+ }
+ else {
+ BLI_heap_remove(fgroup_heap, fgroup_table[i]);
+ fgroup_table[i] = NULL;
+ }
+ }
+ fgroup_dirty[i] = false;
+ }
+ STACK_CLEAR(fgroup_recalc_stack);
}
+ MEM_freeN(edge_lengths);
+ MEM_freeN(f_link_array);
+ MEM_freeN(fgroup_listbase);
+ MEM_freeN(fgroup_recalc_stack);
+ MEM_freeN(fgroup_table);
+ MEM_freeN(fgroup_dirty);
+
+ BLI_heap_free(fgroup_heap, NULL);
+
return changed;
}
@@ -3719,7 +4073,7 @@ static void walker_deselect_nth(BMEditMesh *em,
if (!BM_elem_flag_test(ele, BM_ELEM_TAG)) {
/* Deselect elements that aren't at "nth" depth from active */
const int depth = BMW_current_depth(&walker) - 1;
- if (WM_operator_properties_checker_interval_test(op_params, depth)) {
+ if (!WM_operator_properties_checker_interval_test(op_params, depth)) {
BM_elem_select_set(bm, ele, false);
}
BM_elem_flag_enable(ele, BM_ELEM_TAG);
@@ -3866,7 +4220,8 @@ void MESH_OT_select_nth(wmOperatorType *ot)
void em_setup_viewcontext(bContext *C, ViewContext *vc)
{
- ED_view3d_viewcontext_init(C, vc);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ED_view3d_viewcontext_init(C, vc, depsgraph);
if (vc->obedit) {
vc->em = BKE_editmesh_from_object(vc->obedit);
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 2b0213dc1ef..4636d1ee71e 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -2044,7 +2044,11 @@ static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op)
}
if (tot_failed_all != 0) {
- BKE_reportf(op->reports, RPT_WARNING, "Unable to rotate %d edge(s)", tot_failed_all);
+ BKE_reportf(op->reports,
+ RPT_WARNING,
+ tot_failed_all == 1 ? "Unable to rotate %d edge" :
+ "Unable to rotate %d edges",
+ tot_failed_all);
}
return OPERATOR_FINISHED;
@@ -3131,12 +3135,7 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
BM_mesh_elem_hflag_enable_test(em->bm, htype_select, BM_ELEM_TAG, true, true, BM_ELEM_SELECT);
if (use_unselected) {
- EDBM_op_init(em, &bmop, op, "automerge verts=%hv dist=%f", BM_ELEM_SELECT, threshold);
- BMO_op_exec(em->bm, &bmop);
-
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- continue;
- }
+ EDBM_automerge(obedit, false, BM_ELEM_SELECT, threshold);
}
else {
EDBM_op_init(em, &bmop, op, "find_doubles verts=%hv dist=%f", BM_ELEM_SELECT, threshold);
@@ -3166,7 +3165,11 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
}
MEM_freeN(objects);
- BKE_reportf(op->reports, RPT_INFO, "Removed %d vertices", count_multi);
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ count_multi == 1 ? "Removed %d vertex" :
+ "Removed %d vertices",
+ count_multi);
return OPERATOR_FINISHED;
}
@@ -3877,7 +3880,7 @@ void MESH_OT_knife_cut(wmOperatorType *ot)
/* internal */
RNA_def_int(
- ot->srna, "cursor", BC_KNIFECURSOR, 0, BC_NUMCURSORS, "Cursor", "", 0, BC_NUMCURSORS);
+ ot->srna, "cursor", WM_CURSOR_KNIFE, 0, WM_CURSOR_NUM, "Cursor", "", 0, WM_CURSOR_NUM);
}
/** \} */
@@ -5711,7 +5714,7 @@ void MESH_OT_dissolve_limited(wmOperatorType *ot)
"use_dissolve_boundaries",
false,
"All Boundaries",
- "Dissolve all vertices inbetween face boundaries");
+ "Dissolve all vertices in between face boundaries");
RNA_def_enum_flag(ot->srna,
"delimit",
rna_enum_mesh_delimit_mode_items,
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 1a03879ed17..8d340d93c0a 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -79,6 +79,11 @@ struct BMElem *EDBM_elem_from_selectmode(struct BMEditMesh *em,
int EDBM_elem_to_index_any(struct BMEditMesh *em, struct BMElem *ele);
struct BMElem *EDBM_elem_from_index_any(struct BMEditMesh *em, int index);
+bool edbm_extrude_edges_indiv(struct BMEditMesh *em,
+ struct wmOperator *op,
+ const char hflag,
+ const bool use_normal_flip);
+
/* *** editmesh_add.c *** */
void MESH_OT_primitive_plane_add(struct wmOperatorType *ot);
void MESH_OT_primitive_cube_add(struct wmOperatorType *ot);
@@ -122,6 +127,8 @@ void MESH_GGT_spin_redo(struct wmGizmoGroupType *gzgt);
void MESH_OT_polybuild_face_at_cursor(struct wmOperatorType *ot);
void MESH_OT_polybuild_split_at_cursor(struct wmOperatorType *ot);
void MESH_OT_polybuild_dissolve_at_cursor(struct wmOperatorType *ot);
+void MESH_OT_polybuild_transform_at_cursor(struct wmOperatorType *ot);
+void MESH_OT_polybuild_delete_at_cursor(struct wmOperatorType *ot);
/* *** editmesh_inset.c *** */
void MESH_OT_inset(struct wmOperatorType *ot);
@@ -244,6 +251,9 @@ void MESH_OT_average_normals(struct wmOperatorType *ot);
void MESH_OT_smoothen_normals(struct wmOperatorType *ot);
void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot);
+/* *** editmesh_mask_extract.c *** */
+void MESH_OT_paint_mask_extract(struct wmOperatorType *ot);
+
struct wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf);
#ifdef WITH_FREESTYLE
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 102ce3efc22..4105f853868 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -148,6 +148,8 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_polybuild_face_at_cursor);
WM_operatortype_append(MESH_OT_polybuild_split_at_cursor);
WM_operatortype_append(MESH_OT_polybuild_dissolve_at_cursor);
+ WM_operatortype_append(MESH_OT_polybuild_transform_at_cursor);
+ WM_operatortype_append(MESH_OT_polybuild_delete_at_cursor);
WM_operatortype_append(MESH_OT_uv_texture_add);
WM_operatortype_append(MESH_OT_uv_texture_remove);
@@ -192,6 +194,8 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_symmetrize);
WM_operatortype_append(MESH_OT_symmetry_snap);
+ WM_operatortype_append(MESH_OT_paint_mask_extract);
+
WM_operatortype_append(MESH_OT_point_normals);
WM_operatortype_append(MESH_OT_merge_normals);
WM_operatortype_append(MESH_OT_split_normals);
@@ -334,6 +338,25 @@ void ED_operatormacros_mesh(void)
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
RNA_boolean_set(otmacro->ptr, "mirror", false);
+
+ ot = WM_operatortype_append_macro("MESH_OT_polybuild_transform_at_cursor_move",
+ "Transform at Cursor Move",
+ "",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ WM_operatortype_macro_define(ot, "MESH_OT_polybuild_transform_at_cursor");
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
+ RNA_boolean_set(otmacro->ptr, "mirror", false);
+
+ ot = WM_operatortype_append_macro("MESH_OT_polybuild_extrude_at_cursor_move",
+ "Extrude at Cursor Move",
+ "",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ WM_operatortype_macro_define(ot, "MESH_OT_polybuild_transform_at_cursor");
+ otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_edges_indiv");
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
+ RNA_boolean_set(otmacro->ptr, "mirror", false);
}
/* note mesh keymap also for other space? */
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 8d9d0e40f44..a918996563f 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -54,6 +54,7 @@
#include "BKE_multires.h"
#include "BKE_object.h"
#include "BKE_object_deform.h"
+#include "BKE_object_facemap.h"
#include "BKE_report.h"
#include "DEG_depsgraph.h"
@@ -81,7 +82,7 @@ static void join_mesh_single(Depsgraph *depsgraph,
Scene *scene,
Object *ob_dst,
Object *ob_src,
- float imat[4][4],
+ const float imat[4][4],
MVert **mvert_pp,
MEdge **medge_pp,
MLoop **mloop_pp,
@@ -267,6 +268,22 @@ static void join_mesh_single(Depsgraph *depsgraph,
mpoly->loopstart += *loopofs;
mpoly->mat_nr = matmap ? matmap[mpoly->mat_nr] : 0;
}
+
+ /* Face maps. */
+ int *fmap = CustomData_get(pdata, *polyofs, CD_FACEMAP);
+ int *fmap_src = CustomData_get(&me->pdata, 0, CD_FACEMAP);
+
+ /* Remap to correct new face-map indices, if needed. */
+ if (fmap_src) {
+ BLI_assert(fmap != NULL);
+ int *fmap_index_map;
+ int fmap_index_map_len;
+ fmap_index_map = BKE_object_facemap_index_map_create(ob_src, ob_dst, &fmap_index_map_len);
+ BKE_object_facemap_index_map_apply(fmap, me->totpoly, fmap_index_map, fmap_index_map_len);
+ if (fmap_index_map != NULL) {
+ MEM_freeN(fmap_index_map);
+ }
+ }
}
/* these are used for relinking (cannot be set earlier, or else reattaching goes wrong) */
@@ -403,7 +420,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
key->type = KEY_RELATIVE;
}
- /* first pass over objects - copying materials and vertexgroups across */
+ /* First pass over objects: Copying materials, vertex-groups & face-maps across. */
CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
/* only act if a mesh, and not the one we're joining to */
if ((ob != ob_iter) && (ob_iter->type == OB_MESH)) {
@@ -422,6 +439,19 @@ int join_mesh_exec(bContext *C, wmOperator *op)
ob->actdef = 1;
}
+ /* Join this object's face maps to the base one's. */
+ for (bFaceMap *fmap = ob_iter->fmaps.first; fmap; fmap = fmap->next) {
+ /* See if this group exists in the object (if it doesn't, add it to the end) */
+ if (BKE_object_facemap_find_name(ob, fmap->name) == NULL) {
+ bFaceMap *fmap_new = MEM_callocN(sizeof(bFaceMap), "join faceMap");
+ memcpy(fmap_new, fmap, sizeof(bFaceMap));
+ BLI_addtail(&ob->fmaps, fmap_new);
+ }
+ }
+ if (ob->fmaps.first && ob->actfmap == 0) {
+ ob->actfmap = 1;
+ }
+
if (me->totvert) {
/* Add this object's materials to the base one's if they don't exist already
* (but only if limits not exceeded yet) */
@@ -1110,7 +1140,8 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px,
return false;
}
- ED_view3d_viewcontext_init(C, &vc);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ED_view3d_select_id_validate(&vc);
if (dist_px) {
@@ -1291,7 +1322,8 @@ bool ED_mesh_pick_vert(
return false;
}
- ED_view3d_viewcontext_init(C, &vc);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ED_view3d_select_id_validate(&vc);
if (use_zbuf) {
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index 18ff7ae1a5e..64ae75a0ee8 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -693,13 +693,14 @@ void MBALL_OT_reveal_metaelems(wmOperatorType *ot)
* stiffness circle) */
bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
static MetaElem *startelem = NULL;
ViewContext vc;
int a, hits;
unsigned int buffer[MAXPICKBUF];
rcti rect;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
BLI_rcti_init_pt_radius(&rect, mval, 12);
@@ -835,8 +836,9 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese
bool ED_mball_deselect_all_multi(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &bases_len);
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 80d150506ad..d6816ddbe73 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -1071,7 +1071,7 @@ void OBJECT_OT_drop_named_image(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Add Empty Image/Drop Image To Empty";
+ ot->name = "Add Empty Image/Drop Image to Empty";
ot->description = "Add an empty image type to scene with data";
ot->idname = "OBJECT_OT_drop_named_image";
@@ -1581,7 +1581,11 @@ static int object_delete_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- BKE_reportf(op->reports, RPT_INFO, "Deleted %u object(s)", changed_count);
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ changed_count == 1 ? "Deleted %u object" :
+ "Deleted %u objects",
+ changed_count);
if (changed_count == 0) {
return OPERATOR_CANCELLED;
@@ -2009,6 +2013,7 @@ void OBJECT_OT_duplicates_make_real(wmOperatorType *ot)
static const EnumPropertyItem convert_target_items[] = {
{OB_CURVE, "CURVE", ICON_OUTLINER_OB_CURVE, "Curve from Mesh/Text", ""},
{OB_MESH, "MESH", ICON_OUTLINER_OB_MESH, "Mesh from Curve/Meta/Surf/Text", ""},
+ {OB_GPENCIL, "GPENCIL", ICON_OUTLINER_OB_GREASEPENCIL, "Grease Pencil from Curve", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -2133,12 +2138,14 @@ static int convert_exec(bContext *C, wmOperator *op)
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
Base *basen = NULL, *basact = NULL;
Object *ob1, *obact = CTX_data_active_object(C);
Curve *cu;
Nurb *nu;
MetaBall *mb;
Mesh *me;
+ Object *gpencil_ob = NULL;
const short target = RNA_enum_get(op->ptr, "target");
bool keep_original = RNA_boolean_get(op->ptr, "keep_original");
int a, mballConverted = 0;
@@ -2380,6 +2387,24 @@ static int convert_exec(bContext *C, wmOperator *op)
/* meshes doesn't use displist */
BKE_object_free_curve_cache(newob);
}
+ else if (target == OB_GPENCIL) {
+ if (ob->type != OB_CURVE) {
+ BKE_report(
+ op->reports, RPT_ERROR, "Convert Surfaces to Grease Pencil is not supported.");
+ }
+ else {
+ /* Create a new grease pencil object only if it was not created before.
+ * All curves selected are converted as strokes of the same grease pencil object.
+ * Nurbs Surface are not supported.
+ */
+ if (gpencil_ob == NULL) {
+ const float *cur = scene->cursor.location;
+ ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0;
+ gpencil_ob = ED_gpencil_add_object(C, scene, cur, local_view_bits);
+ }
+ BKE_gpencil_convert_curve(bmain, scene, gpencil_ob, ob, false, false, true);
+ }
+ }
}
else if (ob->type == OB_MBALL && target == OB_MESH) {
Object *baseob;
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index 70a9870e6ae..bc79521ee9b 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -371,7 +371,7 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op)
ob = base->object;
- multires_force_update(ob);
+ multires_flush_sculpt_updates(ob);
/* copy data stored in job descriptor */
bkr.scene = scene;
@@ -435,7 +435,7 @@ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj)
ob = base->object;
- multires_force_update(ob);
+ multires_flush_sculpt_updates(ob);
data = MEM_callocN(sizeof(MultiresBakerJobData), "multiresBaker derivedMesh_data");
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 410ccccbd0d..d9baec7c3ca 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -745,7 +745,7 @@ static int bake(Render *re,
{
/* We build a depsgraph for the baking,
* so we don't need to change the original data to adjust visibility and modifiers. */
- Depsgraph *depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
+ Depsgraph *depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
DEG_graph_build_from_view_layer(depsgraph, bmain, scene, view_layer);
int op_result = OPERATOR_CANCELLED;
diff --git a/source/blender/editors/object/object_collection.c b/source/blender/editors/object/object_collection.c
index fcaefaf220d..a00e5e7b198 100644
--- a/source/blender/editors/object/object_collection.c
+++ b/source/blender/editors/object/object_collection.c
@@ -186,7 +186,7 @@ void COLLECTION_OT_objects_add_active(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Add Selected To Active Collection";
+ ot->name = "Add Selected to Active Collection";
ot->description = "Add the object to an object collection that contains the active object";
ot->idname = "COLLECTION_OT_objects_add_active";
@@ -259,7 +259,7 @@ void COLLECTION_OT_objects_remove_active(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Remove Selected From Active Collection";
+ ot->name = "Remove Selected from Active Collection";
ot->description = "Remove the object from an object collection that contains the active object";
ot->idname = "COLLECTION_OT_objects_remove_active";
@@ -302,7 +302,7 @@ static int collection_objects_remove_all_exec(bContext *C, wmOperator *UNUSED(op
void COLLECTION_OT_objects_remove_all(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Remove From All Unlinked Collections";
+ ot->name = "Remove from All Unlinked Collections";
ot->description = "Remove selected objects from all collections not used in a scene";
ot->idname = "COLLECTION_OT_objects_remove_all";
@@ -361,7 +361,7 @@ void COLLECTION_OT_objects_remove(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Remove From Collection";
+ ot->name = "Remove from Collection";
ot->description = "Remove selected objects from a collection";
ot->idname = "COLLECTION_OT_objects_remove";
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 14813f9a936..8981221cb9c 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -496,7 +496,7 @@ static void test_constraint(
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the curve is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
if (ct->tar->type != OB_CURVE) {
con->flag |= CONSTRAINT_DISABLE;
@@ -514,7 +514,7 @@ static void test_constraint(
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the armature is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
if (ct->tar->type != OB_ARMATURE) {
con->flag |= CONSTRAINT_DISABLE;
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 0c2b5292716..4759a3cb0db 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -271,9 +271,11 @@ void OBJECT_OT_hide_view_set(wmOperatorType *ot)
static int object_hide_collection_exec(bContext *C, wmOperator *op)
{
wmWindow *win = CTX_wm_window(C);
+ View3D *v3d = CTX_wm_view3d(C);
int index = RNA_int_get(op->ptr, "collection_index");
- const bool extend = (win->eventstate->shift != 0) || RNA_boolean_get(op->ptr, "toggle");
+ const bool extend = (win->eventstate->shift != 0);
+ const bool toggle = RNA_boolean_get(op->ptr, "toggle");
if (win->eventstate->alt != 0) {
index += 10;
@@ -289,7 +291,21 @@ static int object_hide_collection_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
- BKE_layer_collection_isolate(scene, view_layer, lc, extend);
+ if (v3d->flag & V3D_LOCAL_COLLECTIONS) {
+ if ((lc->runtime_flag & LAYER_COLLECTION_VISIBLE) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+ if (toggle) {
+ lc->local_collections_bits ^= v3d->local_collections_uuid;
+ BKE_layer_collection_local_sync(view_layer, v3d);
+ }
+ else {
+ BKE_layer_collection_local_isolate(view_layer, v3d, lc, extend);
+ }
+ }
+ else {
+ BKE_layer_collection_isolate(scene, view_layer, lc, extend);
+ }
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -894,12 +910,25 @@ void OBJECT_OT_forcefield_toggle(wmOperatorType *ot)
/* ********************************************** */
/* Motion Paths */
+static eAnimvizCalcRange object_path_convert_range(eObjectPathCalcRange range)
+{
+ switch (range) {
+ case OBJECT_PATH_CALC_RANGE_CURRENT_FRAME:
+ return ANIMVIZ_CALC_RANGE_CURRENT_FRAME;
+ case OBJECT_PATH_CALC_RANGE_CHANGED:
+ return ANIMVIZ_CALC_RANGE_CHANGED;
+ case OBJECT_PATH_CALC_RANGE_FULL:
+ return ANIMVIZ_CALC_RANGE_FULL;
+ }
+ return ANIMVIZ_CALC_RANGE_FULL;
+}
+
/* For the objects with animation: update paths for those that have got them
* This should selectively update paths that exist...
*
* To be called from various tools that do incremental updates
*/
-void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_only)
+void ED_objects_recalculate_paths(bContext *C, Scene *scene, eObjectPathCalcRange range)
{
/* Transform doesn't always have context available to do update. */
if (C == NULL) {
@@ -907,11 +936,9 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_
}
Main *bmain = CTX_data_main(C);
- /* NOTE: Dependency graph will be evaluated at all the frames, but we first need to access some
- * nested pointers, like animation data. */
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- ListBase targets = {NULL, NULL};
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ListBase targets = {NULL, NULL};
/* loop over objects in scene */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
/* set flag to force recalc, then grab path(s) from object */
@@ -920,11 +947,27 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_
}
CTX_DATA_END;
+ Depsgraph *depsgraph;
+ bool free_depsgraph = false;
+ /* For a single frame update it's faster to re-use existing dependency graph and avoid overhead
+ * of building all the relations and so on for a temporary one. */
+ if (range == OBJECT_PATH_CALC_RANGE_CURRENT_FRAME) {
+ /* NOTE: Dependency graph will be evaluated at all the frames, but we first need to access some
+ * nested pointers, like animation data. */
+ depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ free_depsgraph = false;
+ }
+ else {
+ depsgraph = animviz_depsgraph_build(bmain, scene, view_layer, &targets);
+ free_depsgraph = true;
+ }
+
/* recalculate paths, then free */
- animviz_calc_motionpaths(depsgraph, bmain, scene, &targets, true, current_frame_only);
+ animviz_calc_motionpaths(
+ depsgraph, bmain, scene, &targets, object_path_convert_range(range), true);
BLI_freelistN(&targets);
- if (!current_frame_only) {
+ if (range != OBJECT_PATH_CALC_RANGE_CURRENT_FRAME) {
/* Tag objects for copy on write - so paths will draw/redraw
* For currently frame only we update evaluated object directly. */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
@@ -934,6 +977,11 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_
}
CTX_DATA_END;
}
+
+ /* Free temporary depsgraph. */
+ if (free_depsgraph) {
+ DEG_graph_free(depsgraph);
+ }
}
/* show popup to determine settings */
@@ -979,7 +1027,7 @@ static int object_calculate_paths_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* calculate the paths for objects that have them (and are tagged to get refreshed) */
- ED_objects_recalculate_paths(C, scene, false);
+ ED_objects_recalculate_paths(C, scene, OBJECT_PATH_CALC_RANGE_FULL);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -1044,7 +1092,7 @@ static int object_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
}
/* calculate the paths for objects that have them (and are tagged to get refreshed) */
- ED_objects_recalculate_paths(C, scene, false);
+ ED_objects_recalculate_paths(C, scene, OBJECT_PATH_CALC_RANGE_FULL);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -1342,27 +1390,12 @@ static bool object_mode_set_poll(bContext *C)
static int object_mode_set_exec(bContext *C, wmOperator *op)
{
- bool use_submode = STREQ(op->idname, "OBJECT_OT_mode_set_or_submode");
+ bool use_submode = STREQ(op->idname, "OBJECT_OT_mode_set_with_submode");
Object *ob = CTX_data_active_object(C);
eObjectMode mode = RNA_enum_get(op->ptr, "mode");
eObjectMode restore_mode = (ob) ? ob->mode : OB_MODE_OBJECT;
const bool toggle = RNA_boolean_get(op->ptr, "toggle");
- if (use_submode) {
- /* When not changing modes use submodes, see: T55162. */
- if (toggle == false) {
- if (mode == restore_mode) {
- switch (mode) {
- case OB_MODE_EDIT:
- WM_menu_name_call(C, "VIEW3D_MT_edit_mesh_select_mode", WM_OP_INVOKE_REGION_WIN);
- return OPERATOR_INTERFACE;
- default:
- break;
- }
- }
- }
- }
-
/* by default the operator assume is a mesh, but if gp object change mode */
if ((ob != NULL) && (ob->type == OB_GPENCIL) && (mode == OB_MODE_EDIT)) {
mode = OB_MODE_EDIT_GPENCIL;
@@ -1406,6 +1439,20 @@ static int object_mode_set_exec(bContext *C, wmOperator *op)
}
}
+ if (use_submode) {
+ if (ob->type == OB_MESH) {
+ if (ob->mode & OB_MODE_EDIT) {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "mesh_select_mode");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ int mesh_select_mode = RNA_property_enum_get(op->ptr, prop);
+ if (mesh_select_mode != 0) {
+ EDBM_selectmode_set_multi(C, mesh_select_mode);
+ }
+ }
+ }
+ }
+ }
+
return OPERATOR_FINISHED;
}
@@ -1435,30 +1482,20 @@ void OBJECT_OT_mode_set(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-void OBJECT_OT_mode_set_or_submode(wmOperatorType *ot)
+void OBJECT_OT_mode_set_with_submode(wmOperatorType *ot)
{
- PropertyRNA *prop;
+ OBJECT_OT_mode_set(ot);
/* identifiers */
- ot->name = "Set Object Mode or Submode";
- ot->description = "Sets the object interaction mode";
- ot->idname = "OBJECT_OT_mode_set_or_submode";
+ ot->name = "Set Object Mode with Submode";
+ ot->idname = "OBJECT_OT_mode_set_with_submode";
- /* api callbacks */
- ot->exec = object_mode_set_exec;
-
- ot->poll = object_mode_set_poll; // ED_operator_object_active_editable;
-
- /* flags */
- ot->flag = 0; /* no register/undo here, leave it to operators being called */
-
- ot->prop = RNA_def_enum(
- ot->srna, "mode", rna_enum_object_mode_items, OB_MODE_OBJECT, "Mode", "");
- RNA_def_enum_funcs(ot->prop, object_mode_set_itemsf);
- RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
-
- prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ /* properties */
+ /* we could add other types - particle for eg. */
+ PropertyRNA *prop;
+ prop = RNA_def_enum_flag(
+ ot->srna, "mesh_select_mode", rna_enum_mesh_select_mode_items, 0, "Mesh Mode", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
static ListBase selected_objects_get(bContext *C)
@@ -1691,7 +1728,7 @@ static int move_to_collection_invoke(bContext *C, wmOperator *op, const wmEvent
return move_to_collection_exec(C, op);
}
- Collection *master_collection = BKE_collection_master(scene);
+ Collection *master_collection = scene->master_collection;
/* We need the data to be allocated so it's available during menu drawing.
* Technically we could use wmOperator->customdata. However there is no free callback
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 4b369c10e4d..41205bc8778 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -71,7 +71,7 @@ void OBJECT_OT_hide_view_set(struct wmOperatorType *ot);
void OBJECT_OT_hide_view_clear(struct wmOperatorType *ot);
void OBJECT_OT_hide_collection(struct wmOperatorType *ot);
void OBJECT_OT_mode_set(struct wmOperatorType *ot);
-void OBJECT_OT_mode_set_or_submode(struct wmOperatorType *ot);
+void OBJECT_OT_mode_set_with_submode(struct wmOperatorType *ot);
void OBJECT_OT_editmode_toggle(struct wmOperatorType *ot);
void OBJECT_OT_posemode_toggle(struct wmOperatorType *ot);
void OBJECT_OT_proxy_make(struct wmOperatorType *ot);
@@ -281,6 +281,7 @@ void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot);
/* object_remesh.c */
void OBJECT_OT_voxel_remesh(struct wmOperatorType *ot);
+void OBJECT_OT_quadriflow_remesh(struct wmOperatorType *ot);
/* object_transfer_data.c */
void OBJECT_OT_data_transfer(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index f77d9874c06..abcb4afa37d 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -52,6 +52,7 @@
#include "BKE_editmesh.h"
#include "BKE_effect.h"
#include "BKE_global.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
@@ -110,6 +111,9 @@ static void object_force_modifier_update_for_bind(Depsgraph *depsgraph, Object *
else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
BKE_displist_make_curveTypes(depsgraph, scene_eval, ob_eval, false, false);
}
+ else if (ob->type == OB_GPENCIL) {
+ BKE_gpencil_modifiers_calc(depsgraph, scene_eval, ob_eval);
+ }
}
static void object_force_modifier_bind_simple_options(Depsgraph *depsgraph,
@@ -673,7 +677,7 @@ static int modifier_apply_obdata(
/* Multires: ensure that recent sculpting is applied */
if (md_eval->type == eModifierType_Multires) {
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
}
if (mmd && mmd->totlvl && mti->type == eModifierTypeType_OnlyDeform) {
@@ -2018,7 +2022,7 @@ static int correctivesmooth_bind_exec(bContext *C, wmOperator *op)
is_bind = (csmd->bind_coords != NULL);
MEM_SAFE_FREE(csmd->bind_coords);
- MEM_SAFE_FREE(csmd->delta_cache);
+ MEM_SAFE_FREE(csmd->delta_cache.deltas);
if (is_bind) {
/* toggle off */
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 38c06319450..f6b08b953a4 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -59,7 +59,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_origin_set);
WM_operatortype_append(OBJECT_OT_mode_set);
- WM_operatortype_append(OBJECT_OT_mode_set_or_submode);
+ WM_operatortype_append(OBJECT_OT_mode_set_with_submode);
WM_operatortype_append(OBJECT_OT_editmode_toggle);
WM_operatortype_append(OBJECT_OT_posemode_toggle);
WM_operatortype_append(OBJECT_OT_proxy_make);
@@ -259,6 +259,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_hide_collection);
WM_operatortype_append(OBJECT_OT_voxel_remesh);
+ WM_operatortype_append(OBJECT_OT_quadriflow_remesh);
}
void ED_operatormacros_object(void)
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 67364f275dd..d56791e5da0 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -1434,7 +1434,7 @@ static int make_links_scene_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- Collection *collection_to = BKE_collection_master(scene_to);
+ Collection *collection_to = scene_to->master_collection;
CTX_DATA_BEGIN (C, Base *, base, selected_bases) {
BKE_collection_object_add(bmain, collection_to, base->object);
}
@@ -1771,7 +1771,7 @@ static void single_object_users(
Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_collections)
{
/* duplicate all the objects of the scene (and matching collections, if required). */
- Collection *master_collection = BKE_collection_master(scene);
+ Collection *master_collection = scene->master_collection;
single_object_users_collection(bmain, scene, master_collection, flag, copy_collections, true);
/* duplicate collections that consist entirely of duplicated objects */
@@ -1817,6 +1817,10 @@ static void single_object_users(
if (v3d) {
ID_NEW_REMAP(v3d->camera);
}
+ /* Camera pointers of markers. */
+ for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) {
+ ID_NEW_REMAP(marker->camera);
+ }
/* Making single user may affect other scenes if they share
* with current one some collections in their ViewLayer. */
@@ -2046,6 +2050,13 @@ void ED_object_single_users(Main *bmain,
single_obdata_users(bmain, scene, NULL, NULL, 0);
single_object_action_users(bmain, scene, NULL, NULL, 0);
single_mat_users_expand(bmain);
+ /* Duplicating obdata and other IDs may require another update of the collections and objects
+ * pointers, especially reguarding drivers and custom props, see T66641.
+ * Note that this whole scene duplication code and 'make single user' functions have te be
+ * rewritten at some point to make use of proper modern ID management code,
+ * but that is no small task.
+ * For now we are doomed to that kind of band-aid to try to cover most of remapping cases. */
+ libblock_relink_collection(scene->master_collection);
}
/* Relink nodetrees' pointers that have been duplicated. */
@@ -2426,6 +2437,16 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
if (!ID_IS_LINKED(obact) && obact->instance_collection != NULL &&
ID_IS_LINKED(obact->instance_collection)) {
+ if (!ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection)) {
+ BKE_reportf(op->reports,
+ RPT_ERROR_INVALID_INPUT,
+ "Collection '%s' (instantiated by the active object) is not overridable",
+ obact->instance_collection->id.name + 2);
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+
Object *obcollection = obact;
Collection *collection = obcollection->instance_collection;
@@ -2503,7 +2524,14 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
/* Cleanup. */
BKE_main_id_clear_newpoins(bmain);
- BKE_main_id_tag_listbase(&bmain->objects, LIB_TAG_DOIT, false);
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ }
+ else if (!ID_IS_OVERRIDABLE_LIBRARY(obact)) {
+ BKE_reportf(op->reports,
+ RPT_ERROR_INVALID_INPUT,
+ "Active object '%s' is not overridable",
+ obact->id.name + 2);
+ return OPERATOR_CANCELLED;
}
/* Else, poll func ensures us that ID_IS_LINKED(obact) is true. */
else if (obact->type == OB_ARMATURE) {
@@ -2522,11 +2550,14 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
/* Cleanup. */
BKE_main_id_clear_newpoins(bmain);
- BKE_main_id_tag_listbase(&bmain->objects, LIB_TAG_DOIT, false);
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
}
/* TODO: probably more cases where we want to do automated smart things in the future! */
else {
- success = (BKE_override_library_create_from_id(bmain, &obact->id) != NULL);
+ /* For now, remapp all local usages of linked ID to local override one here. */
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, true);
+ success = (BKE_override_library_create_from_id(bmain, &obact->id, true) != NULL);
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
}
WM_event_add_notifier(C, NC_WINDOW, NULL);
diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c
index 5f464084a9b..2c05ae14f2e 100644
--- a/source/blender/editors/object/object_remesh.c
+++ b/source/blender/editors/object/object_remesh.c
@@ -40,12 +40,17 @@
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_mirror.h"
+#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_shrinkwrap.h"
#include "BKE_customdata.h"
#include "BKE_mesh_remesh_voxel.h"
@@ -73,13 +78,18 @@ static bool object_remesh_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
+ if (ob == NULL) {
+ return false;
+ }
+
if (BKE_object_is_in_editmode(ob)) {
- CTX_wm_operator_poll_msg_set(C, "The voxel remesher cannot run from edit mode.");
+ CTX_wm_operator_poll_msg_set(C, "The remesher cannot run from edit mode.");
return false;
}
if (ob->mode == OB_MODE_SCULPT && ob->sculpt->bm) {
- CTX_wm_operator_poll_msg_set(C, "The voxel remesher cannot run with dyntopo activated.");
+ CTX_wm_operator_poll_msg_set(C, "The remesher cannot run with dyntopo activated.");
+ return false;
}
return ED_operator_object_active_editable_mesh(C);
@@ -88,7 +98,6 @@ static bool object_remesh_poll(bContext *C)
static int voxel_remesh_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
- Main *bmain = CTX_data_main(C);
Mesh *mesh = ob->data;
Mesh *new_mesh;
@@ -102,29 +111,30 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
ED_sculpt_undo_geometry_begin(ob);
}
- new_mesh = BKE_mesh_remesh_voxel_to_mesh_nomain(mesh, mesh->remesh_voxel_size);
+ new_mesh = BKE_mesh_remesh_voxel_to_mesh_nomain(
+ mesh, mesh->remesh_voxel_size, mesh->remesh_voxel_adaptivity);
if (!new_mesh) {
return OPERATOR_CANCELLED;
}
- Mesh *obj_mesh_copy = NULL;
- if (mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK) {
- obj_mesh_copy = BKE_mesh_new_nomain_from_template(mesh, mesh->totvert, 0, 0, 0, 0);
- CustomData_copy(
- &mesh->vdata, &obj_mesh_copy->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, mesh->totvert);
- for (int i = 0; i < mesh->totvert; i++) {
- copy_v3_v3(obj_mesh_copy->mvert[i].co, mesh->mvert[i].co);
- }
+ if (mesh->flag & ME_REMESH_FIX_POLES && mesh->remesh_voxel_adaptivity <= 0.0f) {
+ new_mesh = BKE_mesh_remesh_voxel_fix_poles(new_mesh);
+ BKE_mesh_calc_normals(new_mesh);
}
- BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
+ if (mesh->flag & ME_REMESH_REPROJECT_VOLUME) {
+ BKE_mesh_runtime_clear_geometry(mesh);
+ BKE_shrinkwrap_remesh_target_project(new_mesh, mesh, ob);
+ }
if (mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK) {
- BKE_remesh_reproject_paint_mask(mesh, obj_mesh_copy);
- BKE_mesh_free(obj_mesh_copy);
+ BKE_mesh_runtime_clear_geometry(mesh);
+ BKE_remesh_reproject_paint_mask(new_mesh, mesh);
}
+ BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
+
if (mesh->flag & ME_REMESH_SMOOTH_NORMALS) {
BKE_mesh_smooth_flag_set(ob->data, true);
}
@@ -134,7 +144,6 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
}
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
- DEG_relations_tag_update(bmain);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
@@ -156,3 +165,497 @@ void OBJECT_OT_voxel_remesh(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+enum {
+ QUADRIFLOW_REMESH_RATIO = 1,
+ QUADRIFLOW_REMESH_EDGE_LENGTH,
+ QUADRIFLOW_REMESH_FACES,
+};
+
+/****************** quadriflow remesh operator *********************/
+
+#define QUADRIFLOW_MIRROR_BISECT_TOLERANCE 0.005f
+
+typedef enum eSymmetryAxes {
+ SYMMETRY_AXES_X = (1 << 0),
+ SYMMETRY_AXES_Y = (1 << 1),
+ SYMMETRY_AXES_Z = (1 << 2),
+} eSymmetryAxes;
+
+typedef struct QuadriFlowJob {
+ /* from wmJob */
+ struct Object *owner;
+ struct Main *bmain;
+ short *stop, *do_update;
+ float *progress;
+
+ int target_faces;
+ int seed;
+ bool use_paint_symmetry;
+ eSymmetryAxes symmetry_axes;
+
+ bool use_preserve_sharp;
+ bool use_preserve_boundary;
+ bool use_mesh_curvature;
+
+ bool preserve_paint_mask;
+ bool smooth_normals;
+
+ int success;
+} QuadriFlowJob;
+
+static void quadriflow_free_job(void *customdata)
+{
+ QuadriFlowJob *qj = customdata;
+ MEM_freeN(qj);
+}
+
+/* called by quadriflowjob, only to check job 'stop' value */
+static int quadriflow_break_job(void *customdata)
+{
+ QuadriFlowJob *qj = (QuadriFlowJob *)customdata;
+ // return *(qj->stop);
+
+ /* this is not nice yet, need to make the jobs list template better
+ * for identifying/acting upon various different jobs */
+ /* but for now we'll reuse the render break... */
+ bool should_break = (G.is_break);
+
+ if (should_break) {
+ qj->success = -1;
+ }
+
+ return should_break;
+}
+
+/* called by oceanbake, wmJob sends notifier */
+static void quadriflow_update_job(void *customdata, float progress, int *cancel)
+{
+ QuadriFlowJob *qj = customdata;
+
+ if (quadriflow_break_job(qj)) {
+ *cancel = 1;
+ }
+ else {
+ *cancel = 0;
+ }
+
+ *(qj->do_update) = true;
+ *(qj->progress) = progress;
+}
+
+static Mesh *remesh_symmetry_bisect(Main *bmain, Mesh *mesh, eSymmetryAxes symmetry_axes)
+{
+ MirrorModifierData mmd = {0};
+ mmd.tolerance = QUADRIFLOW_MIRROR_BISECT_TOLERANCE;
+
+ Mesh *mesh_bisect, *mesh_bisect_temp;
+ mesh_bisect = BKE_mesh_copy(bmain, mesh);
+
+ int axis;
+ float plane_co[3], plane_no[3];
+ zero_v3(plane_co);
+
+ for (char i = 0; i < 3; i++) {
+ eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
+ if (symmetry_axes & symm_it) {
+ axis = i;
+ mmd.flag = 0;
+ mmd.flag &= MOD_MIR_BISECT_AXIS_X << i;
+ zero_v3(plane_no);
+ plane_no[axis] = -1.0f;
+ mesh_bisect_temp = mesh_bisect;
+ mesh_bisect = BKE_mirror_bisect_on_mirror_plane(&mmd, mesh_bisect, axis, plane_co, plane_no);
+ if (mesh_bisect_temp != mesh_bisect) {
+ BKE_id_free(bmain, mesh_bisect_temp);
+ }
+ }
+ }
+
+ BKE_id_free(bmain, mesh);
+
+ return mesh_bisect;
+}
+
+static Mesh *remesh_symmetry_mirror(Object *ob, Mesh *mesh, eSymmetryAxes symmetry_axes)
+{
+ MirrorModifierData mmd = {0};
+ mmd.tolerance = QUADRIFLOW_MIRROR_BISECT_TOLERANCE;
+ Mesh *mesh_mirror, *mesh_mirror_temp;
+
+ mesh_mirror = mesh;
+
+ int axis;
+
+ for (char i = 0; i < 3; i++) {
+ eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
+ if (symmetry_axes & symm_it) {
+ axis = i;
+ mmd.flag = 0;
+ mmd.flag &= MOD_MIR_AXIS_X << i;
+ mesh_mirror_temp = mesh_mirror;
+ mesh_mirror = BKE_mirror_apply_mirror_on_axis(&mmd, NULL, ob, mesh_mirror, axis);
+ if (mesh_mirror_temp != mesh_mirror) {
+ BKE_id_free(NULL, mesh_mirror_temp);
+ }
+ }
+ }
+
+ return mesh_mirror;
+}
+
+static void quadriflow_start_job(void *customdata, short *stop, short *do_update, float *progress)
+{
+ QuadriFlowJob *qj = customdata;
+
+ qj->stop = stop;
+ qj->do_update = do_update;
+ qj->progress = progress;
+ qj->success = 1;
+
+ G.is_break = false; /* XXX shared with render - replace with job 'stop' switch */
+
+ Object *ob = qj->owner;
+ Mesh *mesh = ob->data;
+ Mesh *new_mesh;
+ Mesh *bisect_mesh;
+
+ /* Run Quadriflow bisect operations on a copy of the mesh to keep the code readable without
+ * freeing the original ID */
+ bisect_mesh = BKE_mesh_copy(qj->bmain, mesh);
+
+ /* Bisect the input mesh using the paint symmetry settings */
+ bisect_mesh = remesh_symmetry_bisect(qj->bmain, bisect_mesh, qj->symmetry_axes);
+
+ new_mesh = BKE_mesh_remesh_quadriflow_to_mesh_nomain(bisect_mesh,
+ qj->target_faces,
+ qj->seed,
+ qj->use_preserve_sharp,
+ qj->use_preserve_boundary ||
+ qj->use_paint_symmetry,
+ qj->use_mesh_curvature,
+ quadriflow_update_job,
+ (void *)qj);
+
+ BKE_id_free(qj->bmain, bisect_mesh);
+
+ if (!new_mesh) {
+ *do_update = true;
+ *stop = 0;
+ if (qj->success == 1) {
+ /* This is not a user cancelation event */
+ qj->success = 0;
+ }
+ return;
+ }
+
+ /* Mirror the Quadriflow result to build the final mesh */
+ if (new_mesh) {
+ new_mesh = remesh_symmetry_mirror(qj->owner, new_mesh, qj->symmetry_axes);
+ }
+
+ if (ob->mode == OB_MODE_SCULPT) {
+ ED_sculpt_undo_geometry_begin(ob);
+ }
+
+ if (qj->preserve_paint_mask) {
+ BKE_mesh_runtime_clear_geometry(mesh);
+ BKE_remesh_reproject_paint_mask(new_mesh, mesh);
+ }
+
+ BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
+
+ if (qj->smooth_normals) {
+ if (qj->use_paint_symmetry) {
+ BKE_mesh_calc_normals(ob->data);
+ }
+ BKE_mesh_smooth_flag_set(ob->data, true);
+ }
+
+ if (ob->mode == OB_MODE_SCULPT) {
+ ED_sculpt_undo_geometry_end(ob);
+ }
+
+ BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+
+ *do_update = true;
+ *stop = 0;
+}
+
+static void quadriflow_end_job(void *customdata)
+{
+ QuadriFlowJob *qj = customdata;
+
+ Object *ob = qj->owner;
+
+ WM_set_locked_interface(G_MAIN->wm.first, false);
+
+ if (qj->success > 0) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_reportf(RPT_INFO, "QuadriFlow: Completed remeshing!");
+ }
+ else {
+ if (qj->success == 0) {
+ WM_reportf(RPT_ERROR, "QuadriFlow: remeshing failed!");
+ }
+ else {
+ WM_report(RPT_WARNING, "QuadriFlow: remeshing canceled!");
+ }
+ }
+}
+
+static int quadriflow_remesh_exec(bContext *C, wmOperator *op)
+{
+ QuadriFlowJob *job = MEM_mallocN(sizeof(QuadriFlowJob), "QuadriFlowJob");
+
+ job->owner = CTX_data_active_object(C);
+ job->bmain = CTX_data_main(C);
+
+ job->target_faces = RNA_int_get(op->ptr, "target_faces");
+ job->seed = RNA_int_get(op->ptr, "seed");
+
+ job->use_paint_symmetry = RNA_boolean_get(op->ptr, "use_paint_symmetry");
+
+ job->use_preserve_sharp = RNA_boolean_get(op->ptr, "use_preserve_sharp");
+ job->use_preserve_boundary = RNA_boolean_get(op->ptr, "use_preserve_boundary");
+
+ job->use_mesh_curvature = RNA_boolean_get(op->ptr, "use_mesh_curvature");
+
+ job->preserve_paint_mask = RNA_boolean_get(op->ptr, "preserve_paint_mask");
+ job->smooth_normals = RNA_boolean_get(op->ptr, "smooth_normals");
+
+ /* Update the target face count if symmetry is enabled */
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ if (sd && job->use_paint_symmetry) {
+ job->symmetry_axes = (eSymmetryAxes)(sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL);
+ for (char i = 0; i < 3; i++) {
+ eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
+ if (job->symmetry_axes & symm_it) {
+ job->target_faces = job->target_faces / 2;
+ }
+ }
+ }
+ else {
+ job->use_paint_symmetry = false;
+ job->symmetry_axes = 0;
+ }
+
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ CTX_data_scene(C),
+ "QuadriFlow Remesh",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_QUADRIFLOW_REMESH);
+
+ WM_jobs_customdata_set(wm_job, job, quadriflow_free_job);
+ WM_jobs_timer(wm_job, 0.1, NC_GEOM | ND_DATA, NC_GEOM | ND_DATA);
+ WM_jobs_callbacks(wm_job, quadriflow_start_job, NULL, NULL, quadriflow_end_job);
+
+ WM_set_locked_interface(CTX_wm_manager(C), true);
+
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool quadriflow_check(bContext *C, wmOperator *op)
+{
+ int mode = RNA_enum_get(op->ptr, "mode");
+
+ if (mode == QUADRIFLOW_REMESH_EDGE_LENGTH) {
+ float area = RNA_float_get(op->ptr, "mesh_area");
+ if (area < 0.0f) {
+ Object *ob = CTX_data_active_object(C);
+ area = BKE_mesh_calc_area(ob->data);
+ RNA_float_set(op->ptr, "mesh_area", area);
+ }
+ int num_faces;
+ float edge_len = RNA_float_get(op->ptr, "target_edge_length");
+
+ num_faces = area / (edge_len * edge_len);
+ RNA_int_set(op->ptr, "target_faces", num_faces);
+ }
+ else if (mode == QUADRIFLOW_REMESH_RATIO) {
+ Object *ob = CTX_data_active_object(C);
+ Mesh *mesh = ob->data;
+
+ int num_faces;
+ float ratio = RNA_float_get(op->ptr, "target_ratio");
+
+ num_faces = mesh->totpoly * ratio;
+
+ RNA_int_set(op->ptr, "target_faces", num_faces);
+ }
+
+ return true;
+}
+
+/* Hide the target variables if they are not active */
+static bool quadriflow_poll_property(const bContext *C, wmOperator *op, const PropertyRNA *prop)
+{
+ const char *prop_id = RNA_property_identifier(prop);
+
+ if (STRPREFIX(prop_id, "target")) {
+ int mode = RNA_enum_get(op->ptr, "mode");
+
+ if (STREQ(prop_id, "target_edge_length") && mode != QUADRIFLOW_REMESH_EDGE_LENGTH) {
+ return false;
+ }
+ else if (STREQ(prop_id, "target_faces")) {
+ if (mode != QUADRIFLOW_REMESH_FACES) {
+ /* Make sure we can edit the target_faces value even if it doesn't start as EDITABLE */
+ float area = RNA_float_get(op->ptr, "mesh_area");
+ if (area < -0.8f) {
+ area += 0.2f;
+ /* Make sure we have up to date values from the start */
+ RNA_def_property_flag((PropertyRNA *)prop, PROP_EDITABLE);
+ quadriflow_check((bContext *)C, op);
+ }
+
+ /* Only disable input */
+ RNA_def_property_clear_flag((PropertyRNA *)prop, PROP_EDITABLE);
+ }
+ else {
+ RNA_def_property_flag((PropertyRNA *)prop, PROP_EDITABLE);
+ }
+ }
+ else if (STREQ(prop_id, "target_ratio") && mode != QUADRIFLOW_REMESH_RATIO) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static const EnumPropertyItem mode_type_items[] = {
+ {QUADRIFLOW_REMESH_RATIO,
+ "RATIO",
+ 0,
+ "Ratio",
+ "Specify target number of faces relative to the current mesh"},
+ {QUADRIFLOW_REMESH_EDGE_LENGTH,
+ "EDGE",
+ 0,
+ "Edge Length",
+ "Input target edge length in the new mesh"},
+ {QUADRIFLOW_REMESH_FACES, "FACES", 0, "Faces", "Input target number of faces in the new mesh"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "QuadriFlow Remesh";
+ ot->description =
+ "Create a new quad based mesh using the surface data of the current mesh. All data "
+ "layers will be lost";
+ ot->idname = "OBJECT_OT_quadriflow_remesh";
+
+ /* api callbacks */
+ ot->poll = object_remesh_poll;
+ ot->poll_property = quadriflow_poll_property;
+ ot->check = quadriflow_check;
+ ot->invoke = WM_operator_props_popup_confirm;
+ ot->exec = quadriflow_remesh_exec;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ PropertyRNA *prop;
+
+ /* properties */
+ RNA_def_boolean(ot->srna,
+ "use_paint_symmetry",
+ true,
+ "Use Paint Symmetry",
+ "Generates a symmetrycal mesh using the paint symmetry configuration");
+
+ RNA_def_boolean(ot->srna,
+ "use_preserve_sharp",
+ false,
+ "Preserve Sharp",
+ "Try to preserve sharp features on the mesh");
+
+ RNA_def_boolean(ot->srna,
+ "use_preserve_boundary",
+ false,
+ "Preserve Mesh Boundary",
+ "Try to preserve mesh boundary on the mesh");
+
+ RNA_def_boolean(ot->srna,
+ "use_mesh_curvature",
+ false,
+ "Use Mesh Curvature",
+ "Take the mesh curvature into account when remeshing");
+
+ RNA_def_boolean(ot->srna,
+ "preserve_paint_mask",
+ false,
+ "Preserve Paint Mask",
+ "Reproject the paint mask onto the new mesh");
+
+ RNA_def_boolean(ot->srna,
+ "smooth_normals",
+ false,
+ "Smooth Normals",
+ "Set the output mesh normals to smooth");
+
+ RNA_def_enum(ot->srna,
+ "mode",
+ mode_type_items,
+ 0,
+ "Mode",
+ "How to specify the amount of detail for the new mesh");
+
+ prop = RNA_def_float(ot->srna,
+ "target_ratio",
+ 1,
+ 0,
+ FLT_MAX,
+ "Ratio",
+ "Relative number of faces compared to the current mesh",
+ 0.0f,
+ 1.0f);
+
+ prop = RNA_def_float(ot->srna,
+ "target_edge_length",
+ 0.1f,
+ 0.0000001f,
+ FLT_MAX,
+ "Edge Length",
+ "Target edge length in the new mesh",
+ 0.00001f,
+ 1.0f);
+
+ prop = RNA_def_int(ot->srna,
+ "target_faces",
+ 1,
+ 1,
+ INT_MAX,
+ "Number of Faces",
+ "Approximate number of faces (quads) in the new mesh",
+ 1,
+ INT_MAX);
+
+ prop = RNA_def_float(
+ ot->srna,
+ "mesh_area",
+ -1.0f,
+ -FLT_MAX,
+ FLT_MAX,
+ "Old Object Face Area",
+ "This property is only used to cache the object area for later calculations",
+ 0.0f,
+ FLT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ RNA_def_int(ot->srna,
+ "seed",
+ 0,
+ 0,
+ INT_MAX,
+ "Seed",
+ "Random seed to use with the solver. Different seeds will cause the remesher to "
+ "come up with different quad layouts on the mesh",
+ 0,
+ 255);
+}
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 2a8b306b085..b534e1b9683 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -711,7 +711,7 @@ static int apply_objects_internal(bContext *C,
return OPERATOR_CANCELLED;
}
- for (int object_index = 0; object_index < num_objects; ++object_index) {
+ for (int object_index = 0; object_index < num_objects; object_index++) {
Object *ob = objects[object_index];
/* calculate rotation/scale matrix */
@@ -1086,7 +1086,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
/* reset flags */
- for (int object_index = 0; object_index < num_objects; ++object_index) {
+ for (int object_index = 0; object_index < num_objects; object_index++) {
Object *ob = objects[object_index];
ob->flag &= ~OB_DONE;
@@ -1106,7 +1106,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
}
- for (int object_index = 0; object_index < num_objects; ++object_index) {
+ for (int object_index = 0; object_index < num_objects; object_index++) {
Object *ob = objects[object_index];
if ((ob->flag & OB_DONE) == 0) {
@@ -1411,7 +1411,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
//{
/* use existing context looper */
- for (int other_object_index = 0; other_object_index < num_objects; ++other_object_index) {
+ for (int other_object_index = 0; other_object_index < num_objects; other_object_index++) {
Object *ob_other = objects[other_object_index];
if ((ob_other->flag & OB_DONE) == 0 &&
@@ -1679,7 +1679,7 @@ static void object_apply_location(Object *ob, const float loc[3])
}
static void object_orient_to_location(Object *ob,
- float rot_orig[3][3],
+ const float rot_orig[3][3],
const float axis[3],
const float location[3])
{
@@ -1715,8 +1715,9 @@ static void object_transform_axis_target_cancel(bContext *C, wmOperator *op)
static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
if (vc.obact == NULL || !object_is_target_compat(vc.obact)) {
/* Falls back to texture space transform. */
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 08fe5e818b2..d703cdfecb3 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -1319,8 +1319,8 @@ static void moveCloserToDistanceFromPlane(Depsgraph *depsgraph,
Object *ob,
Mesh *me,
int index,
- float norm[3],
- float coord[3],
+ const float norm[3],
+ const float coord[3],
float d,
float distToBe,
float strength,
@@ -3794,7 +3794,7 @@ static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr)
const bDeformGroup *def_a = def_a_ptr;
const bDeformGroup *def_b = def_b_ptr;
- return BLI_natstrcmp(def_a->name, def_b->name);
+ return BLI_strcasecmp_natural(def_a->name, def_b->name);
}
/**
diff --git a/source/blender/editors/object/object_warp.c b/source/blender/editors/object/object_warp.c
index 3a089acb330..836e38e3676 100644
--- a/source/blender/editors/object/object_warp.c
+++ b/source/blender/editors/object/object_warp.c
@@ -43,7 +43,7 @@
static void object_warp_calc_view_matrix(float r_mat_view[4][4],
float r_center_view[3],
Object *obedit,
- float viewmat[4][4],
+ const float viewmat[4][4],
const float center[3],
const float offset_angle)
{
@@ -62,7 +62,7 @@ static void object_warp_calc_view_matrix(float r_mat_view[4][4],
}
static void object_warp_transverts_minmax_x(TransVertStore *tvs,
- float mat_view[4][4],
+ const float mat_view[4][4],
const float center_view[3],
float *r_min,
float *r_max)
@@ -90,7 +90,7 @@ static void object_warp_transverts_minmax_x(TransVertStore *tvs,
}
static void object_warp_transverts(TransVertStore *tvs,
- float mat_view[4][4],
+ const float mat_view[4][4],
const float center_view[3],
const float angle_,
const float min,
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 68506c8addb..2ea0e9dc018 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -93,6 +93,7 @@
bool PE_poll(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
@@ -100,7 +101,7 @@ bool PE_poll(bContext *C)
return false;
}
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (edit == NULL) {
return false;
}
@@ -113,6 +114,7 @@ bool PE_poll(bContext *C)
bool PE_hair_poll(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
@@ -120,7 +122,7 @@ bool PE_hair_poll(bContext *C)
return false;
}
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (edit == NULL || edit->psys == NULL) {
return false;
}
@@ -149,8 +151,7 @@ void PE_free_ptcache_edit(PTCacheEdit *edit)
}
if (edit->points) {
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (point->keys) {
MEM_freeN(point->keys);
}
@@ -356,9 +357,9 @@ static PTCacheEdit *pe_get_current(Depsgraph *depsgraph, Scene *scene, Object *o
return edit;
}
-PTCacheEdit *PE_get_current(Scene *scene, Object *ob)
+PTCacheEdit *PE_get_current(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- return pe_get_current(NULL, scene, ob, 0);
+ return pe_get_current(depsgraph, scene, ob, 0);
}
PTCacheEdit *PE_create_current(Depsgraph *depsgraph, Scene *scene, Object *ob)
@@ -380,10 +381,8 @@ void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
KEY_K;
if (pset->flag & PE_FADE_TIME && pset->selectmode == SCE_SELECT_POINT) {
- LOOP_POINTS
- {
- LOOP_KEYS
- {
+ LOOP_POINTS {
+ LOOP_KEYS {
if (fabsf(cfra - *key->time) < pset->fade_frames) {
key->flag &= ~PEK_HIDE;
}
@@ -395,10 +394,8 @@ void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
}
}
else {
- LOOP_POINTS
- {
- LOOP_KEYS
- {
+ LOOP_POINTS {
+ LOOP_KEYS {
key->flag &= ~PEK_HIDE;
}
}
@@ -466,14 +463,15 @@ static void PE_set_data(bContext *C, PEData *data)
data->view_layer = CTX_data_view_layer(C);
data->ob = CTX_data_active_object(C);
data->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- data->edit = PE_get_current(data->scene, data->ob);
+ data->edit = PE_get_current(data->depsgraph, data->scene, data->ob);
}
static void PE_set_view3d_data(bContext *C, PEData *data)
{
PE_set_data(C, data);
- ED_view3d_viewcontext_init(C, &data->vc);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ED_view3d_viewcontext_init(C, &data->vc, depsgraph);
if (!XRAY_ENABLED(data->vc.v3d)) {
if (data->vc.v3d->flag & V3D_INVALID_BACKBUF) {
@@ -633,8 +631,7 @@ static bool point_is_selected(PTCacheEditPoint *point)
return 0;
}
- LOOP_SELECTED_KEYS
- {
+ LOOP_SELECTED_KEYS {
return 1;
}
@@ -649,8 +646,8 @@ typedef void (*ForHitPointFunc)(PEData *data, int point_index, float mouse_dista
typedef void (*ForKeyFunc)(PEData *data, int point_index, int key_index, bool is_inside);
typedef void (*ForKeyMatFunc)(PEData *data,
- float mat[4][4],
- float imat[4][4],
+ const float mat[4][4],
+ const float imat[4][4],
int point_index,
int key_index,
PTCacheEditKey *key);
@@ -684,8 +681,7 @@ static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, const enum ePartic
nearest_point = -1;
nearest_key = -1;
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
if (pset->selectmode == SCE_SELECT_END) {
if (point->totkey) {
/* only do end keys */
@@ -707,8 +703,7 @@ static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, const enum ePartic
}
else {
/* do all keys */
- LOOP_VISIBLE_KEYS
- {
+ LOOP_VISIBLE_KEYS {
if (flag & PSEL_NEAREST) {
if (key_inside_circle(data, dist, KEY_WCO, &dist)) {
nearest_point = p;
@@ -745,8 +740,7 @@ static void foreach_mouse_hit_point(PEData *data, ForHitPointFunc func, int sele
selected = 0;
}
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
if (pset->selectmode == SCE_SELECT_END) {
if (point->totkey) {
/* only do end keys */
@@ -762,8 +756,7 @@ static void foreach_mouse_hit_point(PEData *data, ForHitPointFunc func, int sele
}
else {
/* do all keys */
- LOOP_VISIBLE_KEYS
- {
+ LOOP_VISIBLE_KEYS {
if (selected == 0 || key->flag & PEK_SELECT) {
float mouse_distance;
if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) {
@@ -823,8 +816,7 @@ static void foreach_mouse_hit_key_iter(void *__restrict iter_data_v,
/* do all keys */
PTCacheEditKey *key;
int k;
- LOOP_VISIBLE_KEYS
- {
+ LOOP_VISIBLE_KEYS {
if (selected == 0 || key->flag & PEK_SELECT) {
float mouse_distance;
if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) {
@@ -866,8 +858,7 @@ static void foreach_selected_point(PEData *data, ForPointFunc func)
PTCacheEdit *edit = data->edit;
POINT_P;
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
func(data, p);
}
}
@@ -878,10 +869,8 @@ static void foreach_selected_key(PEData *data, ForKeyFunc func)
POINT_P;
KEY_K;
- LOOP_VISIBLE_POINTS
- {
- LOOP_SELECTED_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_SELECTED_KEYS {
func(data, p, k, true);
}
}
@@ -892,8 +881,7 @@ static void foreach_point(PEData *data, ForPointFunc func)
PTCacheEdit *edit = data->edit;
POINT_P;
- LOOP_POINTS
- {
+ LOOP_POINTS {
func(data, p);
}
}
@@ -905,11 +893,9 @@ static int count_selected_keys(Scene *scene, PTCacheEdit *edit)
KEY_K;
int sel = 0;
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
if (pset->selectmode == SCE_SELECT_POINT) {
- LOOP_SELECTED_KEYS
- {
+ LOOP_SELECTED_KEYS {
sel++;
}
}
@@ -1117,8 +1103,7 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
/* we delay settings the PARS_EDIT_RECALC for mirrored particles
* to avoid doing mirror twice */
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (point->flag & PEP_EDIT_RECALC) {
PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
@@ -1128,8 +1113,7 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
}
}
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (point->flag & PEP_EDIT_RECALC) {
if (edit->mirror_cache[p] != -1) {
edit->points[edit->mirror_cache[p]].flag |= PEP_EDIT_RECALC;
@@ -1173,13 +1157,11 @@ static void deflect_emitter_iter(void *__restrict iter_data_v,
psys_mat_hair_to_object(
object, psmd_eval->mesh_final, psys->part->from, psys->particles + iter, hairmat);
- LOOP_KEYS
- {
+ LOOP_KEYS {
mul_m4_v3(hairmat, key->co);
}
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (k == 0) {
dist_1st = len_v3v3((key + 1)->co, key->co);
dist_1st *= dist * emitterdist;
@@ -1215,8 +1197,7 @@ static void deflect_emitter_iter(void *__restrict iter_data_v,
invert_m4_m4(hairimat, hairmat);
- LOOP_KEYS
- {
+ LOOP_KEYS {
mul_m4_v3(hairimat, key->co);
}
}
@@ -1268,8 +1249,7 @@ static void apply_lengths_iter(void *__restrict iter_data_v,
}
PTCacheEditKey *key;
int k;
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (k) {
float dv1[3];
sub_v3_v3v3(dv1, key->co, (key - 1)->co);
@@ -1377,7 +1357,7 @@ static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
BLI_task_parallel_range(0, edit->totpoint, &iter_data, iterate_lengths_iter, &settings);
}
-/* set current distances to be kept between neighbouting keys */
+/* set current distances to be kept between neighboring keys */
void recalc_lengths(PTCacheEdit *edit)
{
POINT_P;
@@ -1387,8 +1367,7 @@ void recalc_lengths(PTCacheEdit *edit)
return;
}
- LOOP_EDITED_POINTS
- {
+ LOOP_EDITED_POINTS {
key = point->keys;
for (k = 0; k < point->totkey - 1; k++, key++) {
key->length = len_v3v3(key->co, (key + 1)->co);
@@ -1461,15 +1440,14 @@ void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), Part
static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob, int useflag)
{
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
HairKey *hkey;
POINT_P;
KEY_K;
/* flag all particles to be updated if not using flag */
if (!useflag) {
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->flag |= PEP_EDIT_RECALC;
}
}
@@ -1477,11 +1455,9 @@ static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob,
/* flush edit key flag to hair key flag to preserve selection
* on save */
if (edit->psys) {
- LOOP_POINTS
- {
+ LOOP_POINTS {
hkey = edit->psys->particles[p].hair;
- LOOP_KEYS
- {
+ LOOP_KEYS {
hkey->editflag = key->flag;
hkey++;
}
@@ -1491,8 +1467,7 @@ static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob,
psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering);
/* disable update flag */
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->flag &= ~PEP_EDIT_RECALC;
}
@@ -1511,15 +1486,13 @@ void update_world_cos(Object *ob, PTCacheEdit *edit)
return;
}
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
psys_mat_hair_to_global(
ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, hairmat);
}
- LOOP_KEYS
- {
+ LOOP_KEYS {
copy_v3_v3(key->world_co, key->co);
if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
mul_m4_v3(hairmat, key->world_co);
@@ -1541,10 +1514,8 @@ static void update_velocities(PTCacheEdit *edit)
frs_sec = edit->pid.flag & PTCACHE_VEL_PER_SEC ? 25.0f : 1.0f;
- LOOP_EDITED_POINTS
- {
- LOOP_KEYS
- {
+ LOOP_EDITED_POINTS {
+ LOOP_KEYS {
if (k == 0) {
dfra = *(key + 1)->time - *key->time;
@@ -1596,7 +1567,7 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla
/* use this to do partial particle updates, not usable when adding or
* removing, then a full redo is necessary and calling this may crash */
ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
POINT_P;
if (!edit) {
@@ -1605,8 +1576,7 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla
/* flag all particles to be updated if not using flag */
if (!useflag) {
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->flag |= PEP_EDIT_RECALC;
}
}
@@ -1624,14 +1594,19 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla
if (pset->flag & PE_AUTO_VELOCITY) {
update_velocities(edit);
}
- PE_hide_keys_time(scene, edit, CFRA);
+
+ /* Only do this for emitter particles because drawing PE_FADE_TIME is not respected in 2.8 yet
+ * and flagging with PEK_HIDE will prevent selection. This might get restored once this is
+ * supported in drawing (but doesn't make much sense for hair anyways). */
+ if (edit->psys->part->type == PART_EMITTER) {
+ PE_hide_keys_time(scene, edit, CFRA);
+ }
/* regenerate path caches */
psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering);
/* disable update flag */
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->flag &= ~PEP_EDIT_RECALC;
}
@@ -1686,8 +1661,7 @@ static void select_keys(PEData *data,
PTCacheEditPoint *point = edit->points + point_index;
KEY_K;
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (data->select) {
key->flag |= PEK_SELECT;
}
@@ -1780,17 +1754,15 @@ static int pe_select_all_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
POINT_P;
KEY_K;
int action = RNA_enum_get(op->ptr, "action");
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
- LOOP_VISIBLE_POINTS
- {
- LOOP_SELECTED_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_SELECTED_KEYS {
action = SEL_DESELECT;
break;
}
@@ -1802,10 +1774,8 @@ static int pe_select_all_exec(bContext *C, wmOperator *op)
}
bool changed = false;
- LOOP_VISIBLE_POINTS
- {
- LOOP_VISIBLE_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_VISIBLE_KEYS {
changed |= select_action_apply(point, key, action);
}
}
@@ -1841,7 +1811,7 @@ bool PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool desele
PEData data;
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(data.depsgraph, scene, ob);
POINT_P;
KEY_K;
@@ -1850,10 +1820,8 @@ bool PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool desele
}
if (!extend && !deselect && !toggle) {
- LOOP_VISIBLE_POINTS
- {
- LOOP_SELECTED_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_SELECTED_KEYS {
key->flag &= ~PEK_SELECT;
point->flag |= PEP_EDIT_RECALC;
}
@@ -2029,6 +1997,7 @@ static const EnumPropertyItem select_random_type_items[] = {
static int select_random_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
PEData data;
int type;
@@ -2048,26 +2017,22 @@ static int select_random_exec(bContext *C, wmOperator *op)
PE_set_data(C, &data);
data.select_action = SEL_SELECT;
- edit = PE_get_current(data.scene, data.ob);
+ edit = PE_get_current(depsgraph, data.scene, data.ob);
rng = BLI_rng_new_srandom(seed);
switch (type) {
case RAN_HAIR:
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT;
- LOOP_KEYS
- {
+ LOOP_KEYS {
data.is_changed |= select_action_apply(point, key, flag);
}
}
break;
case RAN_POINTS:
- LOOP_VISIBLE_POINTS
- {
- LOOP_VISIBLE_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_VISIBLE_KEYS {
int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT;
data.is_changed |= select_action_apply(point, key, flag);
}
@@ -2166,10 +2131,8 @@ bool PE_deselect_all_visible_ex(PTCacheEdit *edit)
POINT_P;
KEY_K;
- LOOP_VISIBLE_POINTS
- {
- LOOP_SELECTED_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_SELECTED_KEYS {
if ((key->flag & PEK_SELECT) != 0) {
key->flag &= ~PEK_SELECT;
point->flag |= PEP_EDIT_RECALC;
@@ -2182,9 +2145,10 @@ bool PE_deselect_all_visible_ex(PTCacheEdit *edit)
bool PE_deselect_all_visible(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (!PE_start_edit(edit)) {
return false;
}
@@ -2193,9 +2157,10 @@ bool PE_deselect_all_visible(bContext *C)
bool PE_box_select(bContext *C, const rcti *rect, const int sel_op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
PEData data;
if (!PE_start_edit(edit)) {
@@ -2229,9 +2194,10 @@ bool PE_box_select(bContext *C, const rcti *rect, const int sel_op)
bool PE_circle_select(bContext *C, const int sel_op, const int mval[2], float rad)
{
BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB));
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
PEData data;
if (!PE_start_edit(edit)) {
@@ -2260,11 +2226,12 @@ bool PE_circle_select(bContext *C, const int sel_op, const int mval[2], float ra
int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const int sel_op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
ARegion *ar = CTX_wm_region(C);
ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
POINT_P;
@@ -2287,16 +2254,14 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const
data.is_changed |= PE_deselect_all_visible_ex(edit);
}
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
if (edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
psys_mat_hair_to_global(
ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
}
if (pset->selectmode == SCE_SELECT_POINT) {
- LOOP_KEYS
- {
+ LOOP_VISIBLE_KEYS {
copy_v3_v3(co, key->co);
mul_m4_v3(mat, co);
const bool is_select = key->flag & PEK_SELECT;
@@ -2350,30 +2315,26 @@ static int hide_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
POINT_P;
KEY_K;
- if (RNA_enum_get(op->ptr, "unselected")) {
- LOOP_UNSELECTED_POINTS
- {
+ if (RNA_boolean_get(op->ptr, "unselected")) {
+ LOOP_UNSELECTED_POINTS {
point->flag |= PEP_HIDE;
point->flag |= PEP_EDIT_RECALC;
- LOOP_KEYS
- {
+ LOOP_KEYS {
key->flag &= ~PEK_SELECT;
}
}
}
else {
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
point->flag |= PEP_HIDE;
point->flag |= PEP_EDIT_RECALC;
- LOOP_KEYS
- {
+ LOOP_KEYS {
key->flag &= ~PEK_SELECT;
}
}
@@ -2410,19 +2371,17 @@ static int reveal_exec(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
const bool select = RNA_boolean_get(op->ptr, "select");
POINT_P;
KEY_K;
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (point->flag & PEP_HIDE) {
point->flag &= ~PEP_HIDE;
point->flag |= PEP_EDIT_RECALC;
- LOOP_KEYS
- {
+ LOOP_KEYS {
SET_FLAG_FROM_TEST(key->flag, select, PEK_SELECT);
}
}
@@ -2460,8 +2419,7 @@ static void select_less_keys(PEData *data, int point_index)
PTCacheEditPoint *point = edit->points + point_index;
KEY_K;
- LOOP_SELECTED_KEYS
- {
+ LOOP_SELECTED_KEYS {
if (k == 0) {
if (((key + 1)->flag & PEK_SELECT) == 0) {
key->flag |= PEK_TAG;
@@ -2479,8 +2437,7 @@ static void select_less_keys(PEData *data, int point_index)
}
}
- LOOP_KEYS
- {
+ LOOP_KEYS {
if ((key->flag & PEK_TAG) && (key->flag & PEK_SELECT)) {
key->flag &= ~(PEK_TAG | PEK_SELECT);
point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
@@ -2525,8 +2482,7 @@ static void select_more_keys(PEData *data, int point_index)
PTCacheEditPoint *point = edit->points + point_index;
KEY_K;
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (key->flag & PEK_SELECT) {
continue;
}
@@ -2548,8 +2504,7 @@ static void select_more_keys(PEData *data, int point_index)
}
}
- LOOP_KEYS
- {
+ LOOP_KEYS {
if ((key->flag & PEK_TAG) && (key->flag & PEK_SELECT) == 0) {
key->flag &= ~PEK_TAG;
key->flag |= PEK_SELECT;
@@ -2694,7 +2649,8 @@ void PARTICLE_OT_rekey(wmOperatorType *ot)
static void rekey_particle_to_time(
const bContext *C, Scene *scene, Object *ob, int pa_index, float path_time)
{
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys;
ParticleSimulationData sim = {0};
ParticleData *pa;
@@ -2709,7 +2665,7 @@ static void rekey_particle_to_time(
psys = edit->psys;
- sim.depsgraph = CTX_data_depsgraph_pointer(C);
+ sim.depsgraph = depsgraph;
sim.scene = scene;
sim.ob = ob;
sim.psys = psys;
@@ -2758,14 +2714,12 @@ static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror)
/* mirror tags */
psmd_eval = edit->psmd_eval;
- LOOP_TAGGED_POINTS
- {
+ LOOP_TAGGED_POINTS {
PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
}
}
- LOOP_TAGGED_POINTS
- {
+ LOOP_TAGGED_POINTS {
new_totpart--;
removed++;
}
@@ -2850,21 +2804,17 @@ static void remove_tagged_keys(Depsgraph *depsgraph, Object *ob, ParticleSystem
ParticleSystemModifierData *psmd_eval = (ParticleSystemModifierData *)modifier_get_evaluated(
depsgraph, ob, &psmd->modifier);
- LOOP_POINTS
- {
- LOOP_TAGGED_KEYS
- {
+ LOOP_POINTS {
+ LOOP_TAGGED_KEYS {
PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
break;
}
}
}
- LOOP_POINTS
- {
+ LOOP_POINTS {
new_totkey = point->totkey;
- LOOP_TAGGED_KEYS
- {
+ LOOP_TAGGED_KEYS {
new_totkey--;
}
/* we can't have elements with less than two keys*/
@@ -2874,13 +2824,11 @@ static void remove_tagged_keys(Depsgraph *depsgraph, Object *ob, ParticleSystem
}
remove_tagged_particles(ob, psys, pe_x_mirror(ob));
- LOOP_POINTS
- {
+ LOOP_POINTS {
pa = psys->particles + p;
new_totkey = pa->totkey;
- LOOP_TAGGED_KEYS
- {
+ LOOP_TAGGED_KEYS {
new_totkey--;
}
@@ -2889,8 +2837,7 @@ static void remove_tagged_keys(Depsgraph *depsgraph, Object *ob, ParticleSystem
nkey = new_keys = MEM_callocN(new_totkey * sizeof(PTCacheEditKey), "particle edit keys");
hkey = pa->hair;
- LOOP_KEYS
- {
+ LOOP_KEYS {
while (key->flag & PEK_TAG && hkey < pa->hair + pa->totkey) {
key++;
hkey++;
@@ -3062,9 +3009,10 @@ void PARTICLE_OT_subdivide(wmOperatorType *ot)
static int remove_doubles_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd_eval;
KDTree_3d *tree;
@@ -3087,8 +3035,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
tree = BLI_kdtree_3d_new(psys->totpart);
/* insert particles into kd tree */
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
psys_mat_hair_to_object(
ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
copy_v3_v3(co, point->keys->co);
@@ -3099,8 +3046,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
BLI_kdtree_3d_balance(tree);
/* tag particles to be removed */
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
psys_mat_hair_to_object(
ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
copy_v3_v3(co, point->keys->co);
@@ -3130,7 +3076,11 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BKE_reportf(op->reports, RPT_INFO, "Removed %d double particles", totremoved);
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ totremoved == 1 ? "Removed %d double particle" :
+ "Removed %d double particles",
+ totremoved);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
@@ -3166,10 +3116,11 @@ void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
static int weight_set_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ParticleEditSettings *pset = PE_settings(scene);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys = edit->psys;
POINT_P;
KEY_K;
@@ -3181,12 +3132,10 @@ static int weight_set_exec(bContext *C, wmOperator *op)
weight = brush->strength;
edit = psys->edit;
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
ParticleData *pa = psys->particles + p;
- LOOP_SELECTED_KEYS
- {
+ LOOP_SELECTED_KEYS {
hkey = pa->hair + k;
hkey->weight = interpf(weight, hkey->weight, factor);
}
@@ -3315,6 +3264,7 @@ static int delete_exec(bContext *C, wmOperator *op)
}
DEG_id_tag_update(&data.ob->id, ID_RECALC_GEOMETRY);
+ BKE_particle_batch_cache_dirty_tag(data.edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, data.ob);
return OPERATOR_FINISHED;
@@ -3346,11 +3296,11 @@ void PARTICLE_OT_delete(wmOperatorType *ot)
/*************************** mirror operator **************************/
-static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
+static void PE_mirror_x(Depsgraph *depsgraph, Scene *scene, Object *ob, int tagged)
{
Mesh *me = (Mesh *)(ob->data);
ParticleSystemModifierData *psmd_eval;
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys = edit->psys;
ParticleData *pa, *newpa, *new_pars;
PTCacheEditPoint *newpoint, *new_points;
@@ -3386,8 +3336,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
totpart = psys->totpart;
newtotpart = psys->totpart;
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
pa = psys->particles + p;
if (!tagged) {
@@ -3503,8 +3452,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
}
}
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->flag &= ~PEP_TAG;
}
@@ -3513,14 +3461,18 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
static int mirror_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
- PE_mirror_x(scene, ob, 0);
+ PE_mirror_x(depsgraph, scene, ob, 0);
update_world_cos(ob, edit);
+ psys_free_path_cache(NULL, edit);
+
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
+ BKE_particle_batch_cache_dirty_tag(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
return OPERATOR_FINISHED;
@@ -3681,8 +3633,7 @@ static void brush_length(PEData *data, int point_index, float UNUSED(mouse_dista
KEY_K;
float dvec[3], pvec[3] = {0.0f, 0.0f, 0.0f};
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (k == 0) {
copy_v3_v3(pvec, key->co);
}
@@ -3731,8 +3682,7 @@ static void brush_puff(PEData *data, int point_index, float mouse_distance)
unit_m4(imat);
}
- LOOP_KEYS
- {
+ LOOP_KEYS {
float kco[3];
if (k == 0) {
@@ -4504,10 +4454,11 @@ typedef struct BrushEdit {
static int brush_edit_init(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ARegion *ar = CTX_wm_region(C);
BrushEdit *bedit;
float min[3], max[3];
@@ -4518,7 +4469,7 @@ static int brush_edit_init(bContext *C, wmOperator *op)
/* set the 'distance factor' for grabbing (used in comb etc) */
INIT_MINMAX(min, max);
- PE_minmax(scene, view_layer, min, max);
+ PE_minmax(depsgraph, scene, view_layer, min, max);
mid_v3_v3v3(min, min, max);
bedit = MEM_callocN(sizeof(BrushEdit), "BrushEdit");
@@ -4744,7 +4695,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
if (ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_CUT) && (added || removed)) {
if (pset->brushtype == PE_BRUSH_ADD && pe_x_mirror(ob)) {
- PE_mirror_x(scene, ob, 1);
+ PE_mirror_x(depsgraph, scene, ob, 1);
}
update_world_cos(ob, edit);
@@ -4993,10 +4944,11 @@ static void shape_cut(PEData *data, int pa_index)
static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
Object *shapeob = pset->shape_object;
int selected = count_selected_keys(scene, edit);
int lock_root = pset->flag & PE_LOCK_FIRST;
@@ -5074,10 +5026,11 @@ void PARTICLE_OT_shape_cut(wmOperatorType *ot)
/************************ utilities ******************************/
-int PE_minmax(Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
+int PE_minmax(
+ Depsgraph *depsgraph, Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
{
Object *ob = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys;
ParticleSystemModifierData *psmd_eval = NULL;
POINT_P;
@@ -5096,15 +5049,13 @@ int PE_minmax(Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
unit_m4(mat);
}
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
if (psys) {
psys_mat_hair_to_global(
ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
}
- LOOP_SELECTED_KEYS
- {
+ LOOP_SELECTED_KEYS {
copy_v3_v3(co, key->co);
mul_m4_v3(mat, co);
DO_MINMAX(co, min, max);
@@ -5181,15 +5132,13 @@ void PE_create_particle_edit(
BLI_listbase_clear(&edit->pathcachebufs);
pa = psys->particles;
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->totkey = pa->totkey;
point->keys = MEM_callocN(point->totkey * sizeof(PTCacheEditKey), "ParticleEditKeys");
point->flag |= PEP_EDIT_RECALC;
hkey = pa->hair;
- LOOP_KEYS
- {
+ LOOP_KEYS {
key->co = hkey->co;
key->time = &hkey->time;
key->flag = hkey->editflag;
@@ -5217,8 +5166,7 @@ void PE_create_particle_edit(
}
for (pm = cache->mem_cache.first; pm; pm = pm->next) {
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (BKE_ptcache_mem_pointers_seek(p, pm) == 0) {
continue;
}
@@ -5421,8 +5369,7 @@ static float calculate_point_length(PTCacheEditPoint *point)
{
float length = 0.0f;
KEY_K;
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (k > 0) {
length += len_v3v3((key - 1)->co, key->co);
}
@@ -5435,10 +5382,9 @@ static float calculate_average_length(PTCacheEdit *edit)
int num_selected = 0;
float total_length = 0;
POINT_P;
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
total_length += calculate_point_length(point);
- ++num_selected;
+ num_selected++;
}
if (num_selected == 0) {
return 0.0f;
@@ -5450,8 +5396,7 @@ static void scale_point_factor(PTCacheEditPoint *point, float factor)
{
float orig_prev_co[3], prev_co[3];
KEY_K;
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (k == 0) {
copy_v3_v3(orig_prev_co, key->co);
copy_v3_v3(prev_co, key->co);
@@ -5484,8 +5429,7 @@ static void scale_point_to_length(PTCacheEditPoint *point, float length)
static void scale_points_to_length(PTCacheEdit *edit, float length)
{
POINT_P;
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
scale_point_to_length(point, length);
}
recalc_lengths(edit);
@@ -5497,7 +5441,7 @@ static int unify_length_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
float average_length = calculate_average_length(edit);
if (average_length == 0.0f) {
diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c
index 40d90676487..aee79523c87 100644
--- a/source/blender/editors/physics/particle_edit_undo.c
+++ b/source/blender/editors/physics/particle_edit_undo.c
@@ -109,8 +109,7 @@ static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
POINT_P;
KEY_K;
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (psys && psys->particles[p].hair) {
MEM_freeN(psys->particles[p].hair);
}
@@ -133,8 +132,7 @@ static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
edit->points = MEM_dupallocN(undo->points);
edit->totpoint = undo->totpoint;
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->keys = MEM_dupallocN(point->keys);
}
@@ -143,13 +141,11 @@ static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
psys->totpart = undo->totpoint;
- LOOP_POINTS
- {
+ LOOP_POINTS {
pa = psys->particles + p;
hkey = pa->hair = MEM_dupallocN(pa->hair);
- LOOP_KEYS
- {
+ LOOP_KEYS {
key->co = hkey->co;
key->time = &hkey->time;
hkey++;
@@ -174,10 +170,8 @@ static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
}
BKE_ptcache_mem_pointers_init(pm);
- LOOP_POINTS
- {
- LOOP_KEYS
- {
+ LOOP_POINTS {
+ LOOP_KEYS {
if ((int)key->ftime == (int)pm->frame) {
key->co = pm->cur[BPHYS_DATA_LOCATION];
key->vel = pm->cur[BPHYS_DATA_VELOCITY];
@@ -228,10 +222,11 @@ typedef struct ParticleUndoStep {
static bool particle_undosys_poll(struct bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
return (edit != NULL);
}
@@ -240,11 +235,12 @@ static bool particle_undosys_step_encode(struct bContext *C,
struct Main *UNUSED(bmain),
UndoStep *us_p)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
ParticleUndoStep *us = (ParticleUndoStep *)us_p;
ViewLayer *view_layer = CTX_data_view_layer(C);
us->scene_ref.ptr = CTX_data_scene(C);
us->object_ref.ptr = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(us->scene_ref.ptr, us->object_ref.ptr);
+ PTCacheEdit *edit = PE_get_current(depsgraph, us->scene_ref.ptr, us->object_ref.ptr);
undoptcache_from_editcache(&us->data, edit);
return true;
}
@@ -255,6 +251,7 @@ static void particle_undosys_step_decode(struct bContext *C,
int UNUSED(dir),
bool UNUSED(is_final))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
/* TODO(campbell): undo_system: use low-level API to set mode. */
ED_object_mode_set(C, OB_MODE_PARTICLE_EDIT);
BLI_assert(particle_undosys_poll(C));
@@ -262,7 +259,7 @@ static void particle_undosys_step_decode(struct bContext *C,
ParticleUndoStep *us = (ParticleUndoStep *)us_p;
Scene *scene = us->scene_ref.ptr;
Object *ob = us->object_ref.ptr;
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (edit) {
undoptcache_to_editcache(&us->data, edit);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index bb8a31966ef..cfb3a400f47 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -704,8 +704,8 @@ static bool remap_hair_emitter(Depsgraph *depsgraph,
Object *target_ob,
ParticleSystem *target_psys,
PTCacheEdit *target_edit,
- float from_mat[4][4],
- float to_mat[4][4],
+ const float from_mat[4][4],
+ const float to_mat[4][4],
bool from_global,
bool to_global)
{
@@ -1017,13 +1017,11 @@ static void copy_particle_edit(Depsgraph *depsgraph,
edit->points = MEM_dupallocN(edit_from->points);
pa = psys->particles;
- LOOP_POINTS
- {
+ LOOP_POINTS {
HairKey *hkey = pa->hair;
point->keys = MEM_dupallocN(point->keys);
- LOOP_KEYS
- {
+ LOOP_KEYS {
key->co = hkey->co;
key->time = &hkey->time;
key->flag = hkey->editflag;
@@ -1116,7 +1114,7 @@ static bool copy_particle_systems_to_object(const bContext *C,
tmp_psys = MEM_mallocN(sizeof(ParticleSystem *) * totpsys, "temporary particle system array");
- for (psys_from = PSYS_FROM_FIRST, i = 0; psys_from; psys_from = PSYS_FROM_NEXT(psys_from), ++i) {
+ for (psys_from = PSYS_FROM_FIRST, i = 0; psys_from; psys_from = PSYS_FROM_NEXT(psys_from), i++) {
psys = BKE_object_copy_particlesystem(psys_from, 0);
tmp_psys[i] = psys;
@@ -1140,6 +1138,7 @@ static bool copy_particle_systems_to_object(const bContext *C,
/* append to the object */
BLI_addtail(&ob_to->particlesystem, psys);
+ psys_unique_name(ob_to, psys, psys->name);
/* add a particle system modifier for each system */
md = modifier_new(eModifierType_ParticleSystem);
@@ -1167,7 +1166,7 @@ static bool copy_particle_systems_to_object(const bContext *C,
* the remapping otherwise makes final_dm invalid!
*/
for (psys = psys_start, psys_from = PSYS_FROM_FIRST, i = 0; psys;
- psys = psys->next, psys_from = PSYS_FROM_NEXT(psys_from), ++i) {
+ psys = psys->next, psys_from = PSYS_FROM_NEXT(psys_from), i++) {
float(*from_mat)[4], (*to_mat)[4];
switch (space) {
diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c
index a1d76174cc8..4b1d51ee6c2 100644
--- a/source/blender/editors/physics/rigidbody_constraint.c
+++ b/source/blender/editors/physics/rigidbody_constraint.c
@@ -81,14 +81,7 @@ static bool ED_operator_rigidbody_con_add_poll(bContext *C)
ID_IS_LINKED(&scene->rigidbody_world->constraints->id))) {
return false;
}
-
- if (ED_operator_object_active_editable(C)) {
- Object *ob = ED_object_active_context(C);
- return (ob && ob->type == OB_MESH);
- }
- else {
- return false;
- }
+ return ED_operator_object_active_editable(C);
}
bool ED_rigidbody_constraint_add(
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 55a71ee8989..053ca3d8f9f 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -80,8 +80,6 @@
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
-#include "GPU_shader.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index b6601807443..3e001ef25b5 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -1296,7 +1296,7 @@ static void icon_preview_endjob(void *customdata)
int i;
/* signal to gpu texture */
- for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ for (i = 0; i < NUM_ICON_SIZES; i++) {
if (prv_img->gputexture[i]) {
GPU_texture_free(prv_img->gputexture[i]);
prv_img->gputexture[i] = NULL;
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index 82e4d577777..3918737d560 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -194,7 +194,7 @@ void ED_render_engine_changed(Main *bmain)
update_ctx.scene = scene;
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
/* TDODO(sergey): Iterate over depsgraphs instead? */
- update_ctx.depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ update_ctx.depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
update_ctx.view_layer = view_layer;
ED_render_id_flush_update(&update_ctx, &scene->id);
}
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index 3154d5d0985..6873495e962 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -36,6 +36,8 @@
#include "BKE_screen.h"
#include "BKE_report.h"
+#include "BLT_translation.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -137,11 +139,11 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
SpaceImage *sima;
bool area_was_image = false;
- if (scene->r.displaymode == R_OUTPUT_NONE) {
+ if (U.render_display_type == USER_RENDER_DISPLAY_NONE) {
return NULL;
}
- if (scene->r.displaymode == R_OUTPUT_WINDOW) {
+ if (U.render_display_type == USER_RENDER_DISPLAY_WINDOW) {
int sizex = 30 * UI_DPI_FAC + (scene->r.xsch * scene->r.size) / 100;
int sizey = 60 * UI_DPI_FAC + (scene->r.ysch * scene->r.size) / 100;
@@ -154,14 +156,15 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
}
/* changes context! */
- if (WM_window_open_temp(C, mx, my, sizex, sizey, WM_WINDOW_RENDER) == NULL) {
+ if (WM_window_open_temp(C, IFACE_("Blender Render"), mx, my, sizex, sizey, SPACE_IMAGE) ==
+ NULL) {
BKE_report(reports, RPT_ERROR, "Failed to open window!");
return NULL;
}
sa = CTX_wm_area(C);
}
- else if (scene->r.displaymode == R_OUTPUT_SCREEN) {
+ else if (U.render_display_type == USER_RENDER_DISPLAY_SCREEN) {
sa = CTX_wm_area(C);
/* if the active screen is already in fullscreen mode, skip this and
diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c
index b04719d7782..7705278443f 100644
--- a/source/blender/editors/scene/scene_edit.c
+++ b/source/blender/editors/scene/scene_edit.c
@@ -29,21 +29,16 @@
#include "BKE_global.h"
#include "BKE_layer.h"
#include "BKE_library.h"
-#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_scene.h"
-#include "BKE_workspace.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "BLT_translation.h"
-#include "DNA_object_types.h"
-#include "DNA_workspace_types.h"
-
#include "ED_object.h"
#include "ED_render.h"
#include "ED_scene.h"
@@ -121,7 +116,7 @@ bool ED_scene_delete(bContext *C, Main *bmain, Scene *scene)
/* Depsgraph updates after scene becomes active in a window. */
void ED_scene_change_update(Main *bmain, Scene *scene, ViewLayer *layer)
{
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, layer, true);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, layer, true);
BKE_scene_set_background(bmain, scene);
DEG_graph_relations_update(depsgraph, bmain, scene, layer);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index a0f493d0011..c068fbdf7cb 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -30,6 +30,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_rand.h"
#include "BLI_utildefines.h"
#include "BLI_linklist_stack.h"
@@ -55,13 +56,11 @@
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
-#include "GPU_draw.h"
#include "GPU_state.h"
#include "GPU_framebuffer.h"
#include "BLF_api.h"
-#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_metadata.h"
@@ -544,20 +543,20 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
region_draw_azones(sa, ar);
/* for debugging unneeded area redraws and partial redraw */
-#if 0
- GPU_blend(true);
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor4f(drand48(), drand48(), drand48(), 0.1f);
- immRectf(pos,
- ar->drawrct.xmin - ar->winrct.xmin,
- ar->drawrct.ymin - ar->winrct.ymin,
- ar->drawrct.xmax - ar->winrct.xmin,
- ar->drawrct.ymax - ar->winrct.ymin);
- immUnbindProgram();
- GPU_blend(false);
-#endif
+ if (G.debug_value == 888) {
+ GPU_blend(true);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4f(BLI_thread_frand(0), BLI_thread_frand(0), BLI_thread_frand(0), 0.1f);
+ immRectf(pos,
+ ar->drawrct.xmin - ar->winrct.xmin,
+ ar->drawrct.ymin - ar->winrct.ymin,
+ ar->drawrct.xmax - ar->winrct.xmin,
+ ar->drawrct.ymax - ar->winrct.ymin);
+ immUnbindProgram();
+ GPU_blend(false);
+ }
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
@@ -813,7 +812,7 @@ static void area_azone_initialize(wmWindow *win, const bScreen *screen, ScrArea
return;
}
- float coords[4][4] = {
+ const float coords[4][4] = {
/* Bottom-left. */
{sa->totrct.xmin - U.pixelsize,
sa->totrct.ymin - U.pixelsize,
@@ -1265,9 +1264,6 @@ static void region_rect_recursive(
else if (ED_area_is_global(sa)) {
prefsizey = ED_region_global_size_y();
}
- else if (ar->regiontype == RGN_TYPE_UI && sa->spacetype == SPACE_FILE) {
- prefsizey = UI_UNIT_Y * 2 + (UI_UNIT_Y / 2);
- }
else {
prefsizey = UI_DPI_FAC * (ar->sizey > 1 ? ar->sizey + 0.5f : ar->type->prefsizey);
}
@@ -1831,7 +1827,7 @@ void ED_region_cursor_set(wmWindow *win, ScrArea *sa, ARegion *ar)
if (WM_cursor_set_from_tool(win, sa, ar)) {
return;
}
- WM_cursor_set(win, CURSOR_STD);
+ WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
}
@@ -2438,7 +2434,7 @@ void ED_region_panels_layout_ex(const bContext *C,
* instead they calculate offsets for the next panel to start drawing. */
Panel *panel = ar->panels.last;
if (panel != NULL) {
- int size_dyn[2] = {
+ const int size_dyn[2] = {
UI_UNIT_X * ((panel->flag & PNL_CLOSED) ? 8 : 14) / UI_DPI_FAC,
UI_panel_size_y(panel) / UI_DPI_FAC,
};
diff --git a/source/blender/editors/screen/area_query.c b/source/blender/editors/screen/area_query.c
index 420d70e63fb..46559efc614 100644
--- a/source/blender/editors/screen/area_query.c
+++ b/source/blender/editors/screen/area_query.c
@@ -28,8 +28,6 @@
#include "RNA_types.h"
-#include "WM_api.h"
-
#include "ED_screen.h"
#include "UI_interface.h"
diff --git a/source/blender/editors/screen/area_utils.c b/source/blender/editors/screen/area_utils.c
index 1a99210b73d..61fb9d5a3a8 100644
--- a/source/blender/editors/screen/area_utils.c
+++ b/source/blender/editors/screen/area_utils.c
@@ -28,7 +28,6 @@
#include "RNA_access.h"
#include "RNA_types.h"
-#include "WM_api.h"
#include "WM_message.h"
#include "ED_screen.h"
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index af1e0eeed79..dc435efd86b 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -24,8 +24,6 @@
#include <stdio.h>
#include <string.h>
-#include "MEM_guardedalloc.h"
-
#include "DNA_userdef_types.h"
#include "DNA_vec_types.h"
@@ -41,7 +39,10 @@
#include "GPU_immediate.h"
#include "GPU_matrix.h"
-#include "GPU_state.h"
+
+#ifdef __APPLE__
+# include "GPU_state.h"
+#endif
#include "UI_interface.h"
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 6f8b25f782b..f7742c5e50a 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -29,36 +29,28 @@
#include "DNA_object_types.h"
#include "DNA_armature_types.h"
-#include "DNA_brush_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_sequence_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
-#include "DNA_workspace_types.h"
#include "BLI_utildefines.h"
-#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_object.h"
#include "BKE_action.h"
#include "BKE_armature.h"
-#include "BKE_paint.h"
#include "BKE_gpencil.h"
#include "BKE_layer.h"
#include "BKE_sequencer.h"
-#include "BKE_workspace.h"
-
-#include "DEG_depsgraph.h"
#include "RNA_access.h"
#include "ED_armature.h"
#include "ED_gpencil.h"
#include "ED_anim_api.h"
-#include "ED_uvedit.h"
#include "WM_api.h"
#include "UI_interface.h"
diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c
index 1124070486f..316604156de 100644
--- a/source/blender/editors/screen/screen_draw.c
+++ b/source/blender/editors/screen/screen_draw.c
@@ -32,9 +32,7 @@
#include "BLI_rect.h"
#include "WM_api.h"
-#include "WM_types.h"
-#include "UI_interface.h"
#include "UI_resources.h"
#include "screen_intern.h"
@@ -273,8 +271,8 @@ static GPUBatch *batch_screen_edges_get(int *corner_len)
GPU_vertbuf_data_alloc(vbo, CORNER_RESOLUTION * 2 * 4 + 2);
uint vidx = 0;
- for (int corner = 0; corner < 4; ++corner) {
- for (int c = 0; c < CORNER_RESOLUTION; ++c) {
+ for (int corner = 0; corner < 4; corner++) {
+ for (int c = 0; c < CORNER_RESOLUTION; c++) {
do_vert_pair(vbo, pos, &vidx, corner, c);
}
}
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 326bbbd8770..c8008fe3cc7 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -41,20 +41,18 @@
#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
-#include "BKE_node.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
+#include "BKE_sound.h"
#include "BKE_workspace.h"
#include "WM_api.h"
#include "WM_types.h"
-#include "ED_object.h"
#include "ED_screen.h"
#include "ED_screen_types.h"
#include "ED_clip.h"
#include "ED_node.h"
-#include "ED_render.h"
#include "UI_interface.h"
@@ -292,33 +290,45 @@ void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new)
/* used with join operator */
int area_getorientation(ScrArea *sa, ScrArea *sb)
{
- ScrVert *sav1, *sav2, *sav3, *sav4;
- ScrVert *sbv1, *sbv2, *sbv3, *sbv4;
-
if (sa == NULL || sb == NULL) {
return -1;
}
- sav1 = sa->v1;
- sav2 = sa->v2;
- sav3 = sa->v3;
- sav4 = sa->v4;
- sbv1 = sb->v1;
- sbv2 = sb->v2;
- sbv3 = sb->v3;
- sbv4 = sb->v4;
+ ScrVert *saBL = sa->v1;
+ ScrVert *saTL = sa->v2;
+ ScrVert *saTR = sa->v3;
+ ScrVert *saBR = sa->v4;
- if (sav1 == sbv4 && sav2 == sbv3) { /* sa to right of sb = W */
- return 0;
+ ScrVert *sbBL = sb->v1;
+ ScrVert *sbTL = sb->v2;
+ ScrVert *sbTR = sb->v3;
+ ScrVert *sbBR = sb->v4;
+
+ int tolerance = U.pixelsize * 4;
+
+ if (saBL->vec.x == sbBR->vec.x && saTL->vec.x == sbTR->vec.x) { /* sa to right of sb = W */
+ if ((ABS(saBL->vec.y - sbBR->vec.y) <= tolerance) &&
+ (ABS(saTL->vec.y - sbTR->vec.y) <= tolerance)) {
+ return 0;
+ }
}
- else if (sav2 == sbv1 && sav3 == sbv4) { /* sa to bottom of sb = N */
- return 1;
+ else if (saTL->vec.y == sbBL->vec.y && saTR->vec.y == sbBR->vec.y) { /* sa to bottom of sb = N */
+ if ((ABS(saTL->vec.x - sbBL->vec.x) <= tolerance) &&
+ (ABS(saTR->vec.x - sbBR->vec.x) <= tolerance)) {
+ return 1;
+ }
}
- else if (sav3 == sbv2 && sav4 == sbv1) { /* sa to left of sb = E */
- return 2;
+ else if (saTR->vec.x == sbTL->vec.x && saBR->vec.x == sbBL->vec.x) { /* sa to left of sb = E */
+ if ((ABS(saTR->vec.y - sbTL->vec.y) <= tolerance) &&
+ (ABS(saBR->vec.y - sbBL->vec.y) <= tolerance)) {
+ return 2;
+ }
}
- else if (sav1 == sbv2 && sav4 == sbv3) { /* sa on top of sb = S*/
- return 3;
+ else if (saBL->vec.y == sbTL->vec.y && saBR->vec.y == sbTR->vec.y) { /* sa on top of sb = S*/
+ if ((ABS(saBL->vec.x - sbTL->vec.x) <= tolerance) &&
+ (ABS(saBR->vec.x - sbTR->vec.x) <= tolerance)) {
+ return 3;
+ }
}
return -1;
@@ -329,36 +339,50 @@ int area_getorientation(ScrArea *sa, ScrArea *sb)
*/
int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2)
{
- int dir;
-
- dir = area_getorientation(sa1, sa2);
- /*printf("dir is : %i\n", dir);*/
+ int dir = area_getorientation(sa1, sa2);
if (dir == -1) {
return 0;
}
- if (dir == 0) {
- sa1->v1 = sa2->v1;
- sa1->v2 = sa2->v2;
+ /* Align areas if they are not. Do sanity checking before getting here. */
+
+ if (dir == 0 || dir == 2) {
+ /* horizontal join, so vertically align source vert to target */
+ sa2->v1->vec.y = sa1->v1->vec.y; /* vertical align sa1 BL */
+ sa2->v2->vec.y = sa1->v2->vec.y; /* vertical align sa1 TL */
+ sa2->v3->vec.y = sa1->v3->vec.y; /* vertical align sa1 TR */
+ sa2->v4->vec.y = sa1->v4->vec.y; /* vertical align sa1 BR */
+ }
+ else {
+ /* vertical join, so horizontally align source verts to target */
+ sa2->v1->vec.x = sa1->v1->vec.x; /* vertical align sa1 BL */
+ sa2->v2->vec.x = sa1->v2->vec.x; /* vertical align sa1 TL */
+ sa2->v3->vec.x = sa1->v3->vec.x; /* vertical align sa1 TR */
+ sa2->v4->vec.x = sa1->v4->vec.x; /* vertical align sa1 BR */
+ }
+
+ if (dir == 0) { /* sa1 to right of sa2 = W */
+ sa1->v1 = sa2->v1; /* BL */
+ sa1->v2 = sa2->v2; /* TL */
screen_geom_edge_add(scr, sa1->v2, sa1->v3);
screen_geom_edge_add(scr, sa1->v1, sa1->v4);
}
- else if (dir == 1) {
- sa1->v2 = sa2->v2;
- sa1->v3 = sa2->v3;
+ else if (dir == 1) { /* sa1 to bottom of sa2 = N */
+ sa1->v2 = sa2->v2; /* TL */
+ sa1->v3 = sa2->v3; /* TR */
screen_geom_edge_add(scr, sa1->v1, sa1->v2);
screen_geom_edge_add(scr, sa1->v3, sa1->v4);
}
- else if (dir == 2) {
- sa1->v3 = sa2->v3;
- sa1->v4 = sa2->v4;
+ else if (dir == 2) { /* sa1 to left of sa2 = E */
+ sa1->v3 = sa2->v3; /* TR */
+ sa1->v4 = sa2->v4; /* BR */
screen_geom_edge_add(scr, sa1->v2, sa1->v3);
screen_geom_edge_add(scr, sa1->v1, sa1->v4);
}
- else if (dir == 3) {
- sa1->v1 = sa2->v1;
- sa1->v4 = sa2->v4;
+ else if (dir == 3) { /* sa1 on top of sa2 = S */
+ sa1->v1 = sa2->v1; /* BL */
+ sa1->v4 = sa2->v4; /* BR */
screen_geom_edge_add(scr, sa1->v1, sa1->v2);
screen_geom_edge_add(scr, sa1->v3, sa1->v4);
}
@@ -492,6 +516,17 @@ void ED_screen_ensure_updated(wmWindowManager *wm, wmWindow *win, bScreen *scree
}
}
+/**
+ * Utility to exit and free an area-region. Screen level regions (menus/popups) need to be treated
+ * slightly differently, see #ui_region_temp_remove().
+ */
+void ED_region_remove(bContext *C, ScrArea *sa, ARegion *ar)
+{
+ ED_region_exit(C, ar);
+ BKE_area_region_free(sa->type, ar);
+ BLI_freelinkN(&sa->regionbase, ar);
+}
+
/* *********** exit calls are for closing running stuff ******** */
void ED_region_exit(bContext *C, ARegion *ar)
@@ -557,6 +592,11 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
if (screen->animtimer) {
WM_event_remove_timer(wm, window, screen->animtimer);
+
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Scene *scene = WM_window_get_active_scene(prevwin);
+ Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id);
+ BKE_sound_stop_scene(scene_eval);
}
screen->animtimer = NULL;
screen->scrubbing = false;
@@ -604,14 +644,14 @@ static void screen_cursor_set(wmWindow *win, const int xy[2])
if (sa) {
if (az->type == AZONE_AREA) {
- WM_cursor_set(win, CURSOR_EDIT);
+ WM_cursor_set(win, WM_CURSOR_EDIT);
}
else if (az->type == AZONE_REGION) {
if (az->edge == AE_LEFT_TO_TOPRIGHT || az->edge == AE_RIGHT_TO_TOPLEFT) {
- WM_cursor_set(win, CURSOR_X_MOVE);
+ WM_cursor_set(win, WM_CURSOR_X_MOVE);
}
else {
- WM_cursor_set(win, CURSOR_Y_MOVE);
+ WM_cursor_set(win, WM_CURSOR_Y_MOVE);
}
}
}
@@ -620,14 +660,14 @@ static void screen_cursor_set(wmWindow *win, const int xy[2])
if (actedge) {
if (screen_geom_edge_is_horizontal(actedge)) {
- WM_cursor_set(win, CURSOR_Y_MOVE);
+ WM_cursor_set(win, WM_CURSOR_Y_MOVE);
}
else {
- WM_cursor_set(win, CURSOR_X_MOVE);
+ WM_cursor_set(win, WM_CURSOR_X_MOVE);
}
}
else {
- WM_cursor_set(win, CURSOR_STD);
+ WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
}
}
@@ -1320,6 +1360,53 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
return sc->areabase.first;
}
+/**
+ * Wrapper to open a temporary space either as fullscreen space, or as separate window, as defined
+ * by \a display_type.
+ *
+ * \param title: Title to set for the window, if a window is spawned.
+ * \param x, y: Position of the window, if a window is spawned.
+ * \param sizex, sizey: Dimensions of the window, if a window is spawned.
+ */
+ScrArea *ED_screen_temp_space_open(bContext *C,
+ const char *title,
+ int x,
+ int y,
+ int sizex,
+ int sizey,
+ eSpace_Type space_type,
+ int display_type)
+{
+ ScrArea *sa = NULL;
+
+ switch (display_type) {
+ case USER_TEMP_SPACE_DISPLAY_WINDOW:
+ if (WM_window_open_temp(C, title, x, y, sizex, sizey, (int)space_type)) {
+ sa = CTX_wm_area(C);
+ }
+ break;
+ case USER_TEMP_SPACE_DISPLAY_FULLSCREEN: {
+ ScrArea *ctx_sa = CTX_wm_area(C);
+
+ if (ctx_sa->full) {
+ sa = ctx_sa;
+ ED_area_newspace(C, ctx_sa, space_type, true);
+ /* we already had a fullscreen here -> mark new space as a stacked fullscreen */
+ sa->flag |= (AREA_FLAG_STACKED_FULLSCREEN | AREA_FLAG_TEMP_TYPE);
+ }
+ else if (ctx_sa->spacetype == space_type) {
+ sa = ED_screen_state_toggle(C, CTX_wm_window(C), ctx_sa, SCREENMAXIMIZED);
+ }
+ else {
+ sa = ED_screen_full_newspace(C, ctx_sa, (int)space_type);
+ }
+ break;
+ }
+ }
+
+ return sa;
+}
+
/* update frame rate info for viewport drawing */
void ED_refresh_viewport_fps(bContext *C)
{
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 417bdf84232..0b374617cce 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -38,7 +38,6 @@
#include "DNA_lattice_types.h"
#include "DNA_object_types.h"
#include "DNA_curve_types.h"
-#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
#include "DNA_meta_types.h"
#include "DNA_mesh_types.h"
@@ -48,7 +47,6 @@
#include "DNA_userdef_types.h"
#include "BKE_context.h"
-#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
@@ -1043,28 +1041,28 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, event->x, event->y) == sad->sa1) {
/* Same area, so possible split. */
WM_cursor_set(
- win, (ELEM(sad->gesture_dir, 'n', 's')) ? BC_V_SPLITCURSOR : BC_H_SPLITCURSOR);
+ win, (ELEM(sad->gesture_dir, 'n', 's')) ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT);
is_gesture = (delta_max > split_threshold);
}
else {
/* Different area, so possible join. */
if (sad->gesture_dir == 'n') {
- WM_cursor_set(win, BC_N_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_N_ARROW);
}
else if (sad->gesture_dir == 's') {
- WM_cursor_set(win, BC_S_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_S_ARROW);
}
else if (sad->gesture_dir == 'e') {
- WM_cursor_set(win, BC_E_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_E_ARROW);
}
else {
- WM_cursor_set(win, BC_W_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_W_ARROW);
}
is_gesture = (delta_max > join_threshold);
}
}
else {
- WM_cursor_set(CTX_wm_window(C), BC_CROSSCURSOR);
+ WM_cursor_set(CTX_wm_window(C), WM_CURSOR_CROSS);
is_gesture = false;
}
}
@@ -1229,7 +1227,7 @@ static int area_swap_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
/* add modal handler */
- WM_cursor_modal_set(CTX_wm_window(C), BC_SWAPAREA_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_SWAP_AREA);
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -2121,7 +2119,7 @@ static void area_split_preview_update_cursor(bContext *C, wmOperator *op)
{
wmWindow *win = CTX_wm_window(C);
int dir = RNA_enum_get(op->ptr, "direction");
- WM_cursor_set(win, (dir == 'n' || dir == 's') ? BC_V_SPLITCURSOR : BC_H_SPLITCURSOR);
+ WM_cursor_set(win, (dir == 'n' || dir == 's') ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT);
}
/* UI callback, adds new handler */
@@ -3363,7 +3361,9 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
sAreaJoinData *jd;
if (op->customdata == NULL) {
- area_join_init(C, op, NULL, NULL);
+ if (!area_join_init(C, op, NULL, NULL)) {
+ return OPERATOR_CANCELLED;
+ }
}
jd = (sAreaJoinData *)op->customdata;
@@ -3418,19 +3418,19 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (dir == 1) {
- WM_cursor_set(win, BC_N_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_N_ARROW);
}
else if (dir == 3) {
- WM_cursor_set(win, BC_S_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_S_ARROW);
}
else if (dir == 2) {
- WM_cursor_set(win, BC_E_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_E_ARROW);
}
else if (dir == 0) {
- WM_cursor_set(win, BC_W_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_W_ARROW);
}
else {
- WM_cursor_set(win, BC_STOPCURSOR);
+ WM_cursor_set(win, WM_CURSOR_STOP);
}
break;
@@ -3846,10 +3846,7 @@ static int region_quadview_exec(bContext *C, wmOperator *op)
for (ar = sa->regionbase.first; ar; ar = arn) {
arn = ar->next;
if (ar->alignment == RGN_ALIGN_QSPLIT) {
- ED_region_exit(C, ar);
- BKE_area_region_free(sa->type, ar);
- BLI_remlink(&sa->regionbase, ar);
- MEM_freeN(ar);
+ ED_region_remove(C, sa, ar);
}
}
ED_area_tag_redraw(sa);
@@ -3934,6 +3931,65 @@ static void SCREEN_OT_region_quadview(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Region Toggle Operator
+ * \{ */
+
+static int region_toggle_exec(bContext *C, wmOperator *op)
+{
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "region_type");
+ ARegion *region;
+
+ if (RNA_property_is_set(op->ptr, prop)) {
+ region = BKE_area_find_region_type(CTX_wm_area(C), RNA_property_enum_get(op->ptr, prop));
+ }
+ else {
+ region = CTX_wm_region(C);
+ }
+
+ if (region) {
+ ED_region_toggle_hidden(C, region);
+ }
+ ED_region_tag_redraw(region);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool region_toggle_poll(bContext *C)
+{
+ ScrArea *area = CTX_wm_area(C);
+
+ /* don't flip anything around in topbar */
+ if (area && area->spacetype == SPACE_TOPBAR) {
+ CTX_wm_operator_poll_msg_set(C, "Toggling regions in the Top-bar is not allowed");
+ return 0;
+ }
+
+ return ED_operator_areaactive(C);
+}
+
+static void SCREEN_OT_region_toggle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Toggle Region";
+ ot->idname = "SCREEN_OT_region_toggle";
+ ot->description = "Hide or unhide the region";
+
+ /* api callbacks */
+ ot->exec = region_toggle_exec;
+ ot->poll = region_toggle_poll;
+ ot->flag = 0;
+
+ RNA_def_enum(ot->srna,
+ "region_type",
+ rna_enum_region_type_items,
+ 0,
+ "Region Type",
+ "Type of the region to toggle");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Region Flip Operator
* \{ */
@@ -4298,7 +4354,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, false);
Scene *scene_eval = (depsgraph != NULL) ? DEG_get_evaluated_scene(depsgraph) : NULL;
wmTimer *wt = screen->animtimer;
ScreenAnimData *sad = wt->customdata;
@@ -4772,7 +4828,9 @@ static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *even
int sizey = 520 * UI_DPI_FAC;
/* changes context! */
- if (WM_window_open_temp(C, event->x, event->y, sizex, sizey, WM_WINDOW_USERPREFS) != NULL) {
+ if (WM_window_open_temp(
+ C, IFACE_("Blender Preferences"), event->x, event->y, sizex, sizey, SPACE_USERPREF) !=
+ NULL) {
/* The header only contains the editor switcher and looks empty.
* So hiding in the temp window makes sense. */
ScrArea *area = CTX_wm_area(C);
@@ -4821,7 +4879,11 @@ static int drivers_editor_show_invoke(bContext *C, wmOperator *op, const wmEvent
but = UI_context_active_but_prop_get(C, &ptr, &prop, &index);
/* changes context! */
- if (WM_window_open_temp(C, event->x, event->y, sizex, sizey, WM_WINDOW_DRIVERS) != NULL) {
+ if (WM_window_open_temp(
+ C, IFACE_("Blender Drivers Editor"), event->x, event->y, sizex, sizey, SPACE_GRAPH) !=
+ NULL) {
+ ED_drivers_editor_init(C, CTX_wm_area(C));
+
/* activate driver F-Curve for the property under the cursor */
if (but) {
FCurve *fcu;
@@ -4877,7 +4939,9 @@ static int info_log_show_invoke(bContext *C, wmOperator *op, const wmEvent *even
int shift_y = 480;
/* changes context! */
- if (WM_window_open_temp(C, event->x, event->y + shift_y, sizex, sizey, WM_WINDOW_INFO) != NULL) {
+ if (WM_window_open_temp(
+ C, IFACE_("Blender Info Log"), event->x, event->y + shift_y, sizex, sizey, SPACE_INFO) !=
+ NULL) {
return OPERATOR_FINISHED;
}
else {
@@ -5359,6 +5423,7 @@ void ED_operatortypes_screen(void)
WM_operatortype_append(SCREEN_OT_area_swap);
WM_operatortype_append(SCREEN_OT_region_quadview);
WM_operatortype_append(SCREEN_OT_region_scale);
+ WM_operatortype_append(SCREEN_OT_region_toggle);
WM_operatortype_append(SCREEN_OT_region_flip);
WM_operatortype_append(SCREEN_OT_header_toggle_menus);
WM_operatortype_append(SCREEN_OT_region_context_menu);
diff --git a/source/blender/editors/screen/screen_user_menu.c b/source/blender/editors/screen/screen_user_menu.c
index 26849edeb44..661c17f55d2 100644
--- a/source/blender/editors/screen/screen_user_menu.c
+++ b/source/blender/editors/screen/screen_user_menu.c
@@ -52,27 +52,43 @@
#include "RNA_access.h"
/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
+
+static const char *screen_menu_context_string(const bContext *C, const SpaceLink *sl)
+{
+ if (sl->spacetype == SPACE_NODE) {
+ const SpaceNode *snode = (const SpaceNode *)sl;
+ return snode->tree_idname;
+ }
+ return CTX_data_mode_string(C);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Menu Type
* \{ */
bUserMenu **ED_screen_user_menus_find(const bContext *C, uint *r_len)
{
SpaceLink *sl = CTX_wm_space_data(C);
- const char *context = CTX_data_mode_string(C);
if (sl == NULL) {
*r_len = 0;
return NULL;
}
+ const char *context_mode = CTX_data_mode_string(C);
+ const char *context = screen_menu_context_string(C, sl);
uint array_len = 3;
bUserMenu **um_array = MEM_calloc_arrayN(array_len, sizeof(*um_array), __func__);
um_array[0] = BKE_blender_user_menu_find(&U.user_menus, sl->spacetype, context);
um_array[1] = (sl->spacetype != SPACE_TOPBAR) ?
- BKE_blender_user_menu_find(&U.user_menus, SPACE_TOPBAR, context) :
+ BKE_blender_user_menu_find(&U.user_menus, SPACE_TOPBAR, context_mode) :
NULL;
um_array[2] = (sl->spacetype == SPACE_VIEW3D) ?
- BKE_blender_user_menu_find(&U.user_menus, SPACE_PROPERTIES, context) :
+ BKE_blender_user_menu_find(&U.user_menus, SPACE_PROPERTIES, context_mode) :
NULL;
*r_len = array_len;
@@ -82,7 +98,7 @@ bUserMenu **ED_screen_user_menus_find(const bContext *C, uint *r_len)
bUserMenu *ED_screen_user_menu_ensure(bContext *C)
{
SpaceLink *sl = CTX_wm_space_data(C);
- const char *context = CTX_data_mode_string(C);
+ const char *context = screen_menu_context_string(C, sl);
return BKE_blender_user_menu_ensure(&U.user_menus, sl->spacetype, context);
}
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
index 61b737589c8..bbb959c27ff 100644
--- a/source/blender/editors/screen/workspace_edit.c
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -29,18 +29,13 @@
#include "BKE_appdir.h"
#include "BKE_blendfile.h"
#include "BKE_context.h"
-#include "BKE_idcode.h"
-#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
-#include "BKE_report.h"
-#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_workspace.h"
#include "BLO_readfile.h"
-#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_workspace_types.h"
@@ -49,13 +44,9 @@
#include "ED_object.h"
#include "ED_screen.h"
-#include "MEM_guardedalloc.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
-#include "DEG_depsgraph.h"
-
#include "UI_interface.h"
#include "UI_resources.h"
@@ -63,7 +54,6 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "WM_toolsystem.h"
#include "screen_intern.h"
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 752a5c36010..a5cc262ddcd 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -31,6 +31,7 @@ set(INC
../../render/extern/include
../../windowmanager
../../../../intern/atomic
+ ../../../../intern/clog
../../../../intern/glew-mx
../../../../intern/guardedalloc
)
@@ -47,7 +48,6 @@ set(SRC
paint_image.c
paint_image_2d.c
paint_image_proj.c
- paint_image_undo.c
paint_mask.c
paint_ops.c
paint_stroke.c
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 65e10f98753..774d4ef09b1 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -45,13 +45,17 @@
#include "BKE_node.h"
#include "BKE_paint.h"
#include "BKE_colortools.h"
+#include "BKE_object.h"
#include "WM_api.h"
+#include "wm_cursors.h"
#include "IMB_imbuf_types.h"
#include "ED_view3d.h"
+#include "DEG_depsgraph.h"
+
#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
@@ -87,6 +91,7 @@ typedef struct CursorSnapshot {
GLuint overlay_texture;
int size;
int zoom;
+ int curve_preset;
} CursorSnapshot;
static TexSnapshot primary_snap = {0};
@@ -422,7 +427,8 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
int size;
const bool refresh = !cursor_snap.overlay_texture ||
- (overlay_flags & PAINT_OVERLAY_INVALID_CURVE) || cursor_snap.zoom != zoom;
+ (overlay_flags & PAINT_OVERLAY_INVALID_CURVE) || cursor_snap.zoom != zoom ||
+ cursor_snap.curve_preset != br->curve_preset;
init = (cursor_snap.overlay_texture != 0);
@@ -502,6 +508,7 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ cursor_snap.curve_preset = br->curve_preset;
BKE_paint_reset_overlay_invalid(PAINT_OVERLAY_INVALID_CURVE);
return 1;
@@ -602,7 +609,7 @@ static bool sculpt_get_brush_geometry(bContext *C,
/* Draw an overlay that shows what effect the brush's texture will
* have on brush strength */
-static void paint_draw_tex_overlay(UnifiedPaintSettings *ups,
+static bool paint_draw_tex_overlay(UnifiedPaintSettings *ups,
Brush *brush,
ViewContext *vc,
int x,
@@ -622,7 +629,7 @@ static void paint_draw_tex_overlay(UnifiedPaintSettings *ups,
if (!(mtex->tex) ||
!((mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) ||
(valid && ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_TILED)))) {
- return;
+ return false;
}
if (load_tex(brush, vc, zoom, col, primary)) {
@@ -728,18 +735,19 @@ static void paint_draw_tex_overlay(UnifiedPaintSettings *ups,
GPU_matrix_pop();
}
}
+ return true;
}
/* Draw an overlay that shows what effect the brush's texture will
* have on brush strength */
-static void paint_draw_cursor_overlay(
+static bool paint_draw_cursor_overlay(
UnifiedPaintSettings *ups, Brush *brush, ViewContext *vc, int x, int y, float zoom)
{
rctf quad;
/* check for overlay mode */
if (!(brush->overlay_flags & BRUSH_OVERLAY_CURSOR)) {
- return;
+ return false;
}
if (load_tex_cursor(brush, vc, zoom)) {
@@ -811,9 +819,10 @@ static void paint_draw_cursor_overlay(
GPU_matrix_pop();
}
}
+ return true;
}
-static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups,
+static bool paint_draw_alpha_overlay(UnifiedPaintSettings *ups,
Brush *brush,
ViewContext *vc,
int x,
@@ -824,6 +833,9 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups,
/* Color means that primary brush texture is colored and
* secondary is used for alpha/mask control. */
bool col = ELEM(mode, PAINT_MODE_TEXTURE_3D, PAINT_MODE_TEXTURE_2D, PAINT_MODE_VERTEX);
+
+ bool alpha_overlay_active = false;
+
eOverlayControlFlags flags = BKE_paint_get_overlay_flags();
gpuPushAttr(GPU_DEPTH_BUFFER_BIT | GPU_BLEND_BIT);
@@ -836,37 +848,43 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups,
/* Colored overlay should be drawn separately. */
if (col) {
if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY)) {
- paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, true, true);
+ alpha_overlay_active = paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, true, true);
}
if (!(flags & PAINT_OVERLAY_OVERRIDE_SECONDARY)) {
- paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, false);
+ alpha_overlay_active = paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, false);
}
if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR)) {
- paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
+ alpha_overlay_active = paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
}
}
else {
if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY) && (mode != PAINT_MODE_WEIGHT)) {
- paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, true);
+ alpha_overlay_active = paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, true);
}
if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR)) {
- paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
+ alpha_overlay_active = paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
}
}
GPU_matrix_pop();
gpuPopAttr();
+
+ return alpha_overlay_active;
}
-BLI_INLINE void draw_tri_point(
- unsigned int pos, float sel_col[4], float pivot_col[4], float *co, float width, bool selected)
+BLI_INLINE void draw_tri_point(unsigned int pos,
+ const float sel_col[4],
+ float pivot_col[4],
+ float *co,
+ float width,
+ bool selected)
{
immUniformColor4fv(selected ? sel_col : pivot_col);
GPU_line_width(3.0f);
float w = width / 2.0f;
- float tri[3][2] = {
+ const float tri[3][2] = {
{co[0], co[1] + w},
{co[0] - w, co[1] - w},
{co[0] + w, co[1] - w},
@@ -888,8 +906,12 @@ BLI_INLINE void draw_tri_point(
immEnd();
}
-BLI_INLINE void draw_rect_point(
- unsigned int pos, float sel_col[4], float handle_col[4], float *co, float width, bool selected)
+BLI_INLINE void draw_rect_point(unsigned int pos,
+ const float sel_col[4],
+ float handle_col[4],
+ float *co,
+ float width,
+ bool selected)
{
immUniformColor4fv(selected ? sel_col : handle_col);
@@ -1074,8 +1096,135 @@ static bool ommit_cursor_drawing(Paint *paint, ePaintMode mode, Brush *brush)
return true;
}
+static void cursor_draw_point_screen_space(
+ const uint gpuattr, const ARegion *ar, float true_location[3], float obmat[4][4], int size)
+{
+ float translation_vertex_cursor[3], location[3];
+ copy_v3_v3(location, true_location);
+ mul_m4_v3(obmat, location);
+ ED_view3d_project(ar, location, translation_vertex_cursor);
+ imm_draw_circle_fill_3d(
+ gpuattr, translation_vertex_cursor[0], translation_vertex_cursor[1], size, 10);
+}
+
+static void cursor_draw_tiling_preview(const uint gpuattr,
+ const ARegion *ar,
+ const float true_location[3],
+ Sculpt *sd,
+ Object *ob,
+ float radius)
+{
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ float orgLoc[3], location[3];
+ int dim, tile_pass = 0;
+ int start[3];
+ int end[3];
+ int cur[3];
+ const float *bbMin = bb->vec[0];
+ const float *bbMax = bb->vec[6];
+ const float *step = sd->paint.tile_offset;
+
+ copy_v3_v3(orgLoc, true_location);
+ for (dim = 0; dim < 3; dim++) {
+ if ((sd->paint.symmetry_flags & (PAINT_TILE_X << dim)) && step[dim] > 0) {
+ start[dim] = (bbMin[dim] - orgLoc[dim] - radius) / step[dim];
+ end[dim] = (bbMax[dim] - orgLoc[dim] + radius) / step[dim];
+ }
+ else {
+ start[dim] = end[dim] = 0;
+ }
+ }
+ copy_v3_v3_int(cur, start);
+ for (cur[0] = start[0]; cur[0] <= end[0]; cur[0]++) {
+ for (cur[1] = start[1]; cur[1] <= end[1]; cur[1]++) {
+ for (cur[2] = start[2]; cur[2] <= end[2]; cur[2]++) {
+ if (!cur[0] && !cur[1] && !cur[2]) {
+ /* skip tile at orgLoc, this was already handled before all others */
+ continue;
+ }
+ tile_pass++;
+ for (dim = 0; dim < 3; dim++) {
+ location[dim] = cur[dim] * step[dim] + orgLoc[dim];
+ }
+ cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3);
+ }
+ }
+ }
+}
+
+static void cursor_draw_point_with_symmetry(const uint gpuattr,
+ const ARegion *ar,
+ const float true_location[3],
+ Sculpt *sd,
+ Object *ob,
+ float radius)
+{
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ float location[3], symm_rot_mat[4][4];
+
+ for (int i = 0; i <= symm; i++) {
+ if (i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
+
+ /* Axis Symmetry */
+ flip_v3_v3(location, true_location, (char)i);
+ cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3);
+
+ /* Tiling */
+ cursor_draw_tiling_preview(gpuattr, ar, location, sd, ob, radius);
+
+ /* Radial Symmetry */
+ for (char raxis = 0; raxis < 3; raxis++) {
+ for (int r = 1; r < sd->radial_symm[raxis]; r++) {
+ float angle = 2 * M_PI * r / sd->radial_symm[(int)raxis];
+ flip_v3_v3(location, true_location, (char)i);
+ unit_m4(symm_rot_mat);
+ rotate_m4(symm_rot_mat, raxis + 'X', angle);
+ mul_m4_v3(symm_rot_mat, location);
+
+ cursor_draw_tiling_preview(gpuattr, ar, location, sd, ob, radius);
+ cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3);
+ }
+ }
+ }
+ }
+}
+
+static void sculpt_geometry_preview_lines_draw(const uint gpuattr, SculptSession *ss)
+{
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.6f);
+
+ /* Cursor normally draws on top, but for this part we need depth tests. */
+ const bool depth_test = GPU_depth_test_enabled();
+ if (!depth_test) {
+ GPU_depth_test(true);
+ }
+
+ GPU_line_width(1.0f);
+ if (ss->preview_vert_index_count > 0) {
+ immBegin(GPU_PRIM_LINES, ss->preview_vert_index_count);
+ for (int i = 0; i < ss->preview_vert_index_count; i++) {
+ immVertex3fv(gpuattr, sculpt_vertex_co_get(ss, ss->preview_vert_index_list[i]));
+ }
+ immEnd();
+ }
+
+ /* Restore depth test value. */
+ if (!depth_test) {
+ GPU_depth_test(false);
+ }
+}
+
+static bool paint_use_2d_cursor(ePaintMode mode)
+{
+ if (mode >= PAINT_MODE_TEXTURE_3D) {
+ return true;
+ }
+ return false;
+}
+
static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
@@ -1083,6 +1232,9 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
Brush *brush = BKE_paint_brush(paint);
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+ /* 2d or 3d painting? */
+ const bool use_2d_cursor = paint_use_2d_cursor(mode);
+
/* check that brush drawing is enabled */
if (ommit_cursor_drawing(paint, mode, brush)) {
return;
@@ -1091,7 +1243,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* can't use stroke vc here because this will be called during
* mouse over too, not just during a stroke */
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
if (vc.rv3d && (vc.rv3d->rflag & RV3D_NAVIGATING)) {
return;
@@ -1109,7 +1261,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* set various defaults */
const float *outline_col = brush->add_col;
- const float outline_alpha = 0.5f;
+ const float outline_alpha = 0.7f;
float translation[2] = {x, y};
float final_radius = (BKE_brush_size_get(scene, brush) * zoomx);
@@ -1121,34 +1273,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
}
/* draw overlay */
- paint_draw_alpha_overlay(ups, brush, &vc, x, y, zoomx, mode);
-
- /* TODO: as sculpt and other paint modes are unified, this
- * special mode of drawing will go away */
- if ((mode == PAINT_MODE_SCULPT) && vc.obact->sculpt) {
- float location[3];
- int pixel_radius;
-
- /* test if brush is over the mesh */
- bool hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location, ups);
-
- if (BKE_brush_use_locked_size(scene, brush)) {
- BKE_brush_size_set(scene, brush, pixel_radius);
- }
-
- /* check if brush is subtracting, use different color then */
- /* TODO: no way currently to know state of pen flip or
- * invert key modifier without starting a stroke */
- if (((ups->draw_inverted == 0) ^ ((brush->flag & BRUSH_DIR_IN) == 0)) &&
- BKE_brush_sculpt_has_secondary_color(brush)) {
- outline_col = brush->sub_col;
- }
-
- /* only do if brush is over the mesh */
- if (hit) {
- paint_cursor_on_hit(ups, brush, &vc, location);
- }
- }
+ bool alpha_overlay_active = paint_draw_alpha_overlay(ups, brush, &vc, x, y, zoomx, mode);
if (ups->draw_anchored) {
final_radius = ups->anchored_size;
@@ -1158,25 +1283,243 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
}
/* make lines pretty */
- GPU_line_width(1.0f);
+ GPU_line_width(2.0f);
GPU_blend(true); /* TODO: also set blend mode? */
GPU_line_smooth(true);
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ if (use_2d_cursor) {
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3fvAlpha(outline_col, outline_alpha);
+
+ /* draw brush outline */
+ if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) {
+ imm_draw_circle_wire_2d(
+ pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
+ /* outer at half alpha */
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
+ }
+
+ GPU_line_width(1.0f);
+ imm_draw_circle_wire_2d(pos, translation[0], translation[1], final_radius, 40);
+ }
+ else { /* 3d painting */
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ /* TODO: as sculpt and other paint modes are unified, this
+ * special mode of drawing will go away */
+ Object *obact = vc.obact;
+ SculptSession *ss = obact ? obact->sculpt : NULL;
+ if ((mode == PAINT_MODE_SCULPT) && ss) {
+ float location[3];
+ int pixel_radius;
+
+ /* test if brush is over the mesh */
+ bool hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location, ups);
+
+ if (BKE_brush_use_locked_size(scene, brush)) {
+ BKE_brush_size_set(scene, brush, pixel_radius);
+ }
+
+ /* check if brush is subtracting, use different color then */
+ /* TODO: no way currently to know state of pen flip or
+ * invert key modifier without starting a stroke */
+ if (((ups->draw_inverted == 0) ^ ((brush->flag & BRUSH_DIR_IN) == 0)) &&
+ BKE_brush_sculpt_has_secondary_color(brush)) {
+ outline_col = brush->sub_col;
+ }
+
+ /* only do if brush is over the mesh */
+ if (hit) {
+ paint_cursor_on_hit(ups, brush, &vc, location);
+ }
+ }
+
+ immUniformColor3fvAlpha(outline_col, outline_alpha);
+
+ if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) {
+ imm_draw_circle_wire_3d(
+ pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
+ /* outer at half alpha */
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
+ }
+
+ /* Only sculpt mode cursor for now */
+ /* Disable for PBVH_GRIDS */
+ bool is_multires = ss && ss->pbvh && BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS;
- /* set brush color */
- immUniformColor3fvAlpha(outline_col, outline_alpha);
+ SculptCursorGeometryInfo gi;
+ float mouse[2] = {x - ar->winrct.xmin, y - ar->winrct.ymin};
+ int prev_active_vertex_index = -1;
+ bool is_cursor_over_mesh = false;
- /* draw brush outline */
- if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) {
- /* inner at full alpha */
- imm_draw_circle_wire_2d(
- pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
- /* outer at half alpha */
- immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
+ /* Update the active vertex */
+ if ((mode == PAINT_MODE_SCULPT) && ss && !ups->stroke_active) {
+ prev_active_vertex_index = ss->active_vertex_index;
+ is_cursor_over_mesh = sculpt_cursor_geometry_info_update(
+ C, &gi, mouse, !(brush->falloff_shape & BRUSH_AIRBRUSH));
+ }
+ /* Use special paint crosshair cursor in all paint modes*/
+ wmWindow *win = CTX_wm_window(C);
+ WM_cursor_set(win, WM_CURSOR_PAINT);
+
+ if ((mode == PAINT_MODE_SCULPT) && ss && !(brush->falloff_shape & BRUSH_AIRBRUSH)) {
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+
+ if (!ups->stroke_active) {
+ bool update_previews = false;
+ if (is_cursor_over_mesh && !alpha_overlay_active) {
+
+ if (prev_active_vertex_index != ss->active_vertex_index) {
+ update_previews = true;
+ }
+
+ float rds;
+ if (!BKE_brush_use_locked_size(scene, brush)) {
+ rds = paint_calc_object_space_radius(
+ &vc, gi.location, BKE_brush_size_get(scene, brush));
+ }
+ else {
+ rds = BKE_brush_unprojected_radius_get(scene, brush);
+ }
+
+ wmViewport(&ar->winrct);
+
+ /* Draw 3D active vertex preview with symmetry*/
+ if (len_v3v3(gi.active_vertex_co, gi.location) < rds) {
+ cursor_draw_point_with_symmetry(pos, ar, gi.active_vertex_co, sd, vc.obact, rds);
+ }
+
+ /* Draw pose brush origin */
+ if (brush->sculpt_tool == SCULPT_TOOL_POSE && !is_multires) {
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
+ if (update_previews) {
+ BKE_sculpt_update_object_for_edit(depsgraph, vc.obact, true, false);
+ sculpt_pose_calc_pose_data(
+ sd, vc.obact, ss, gi.location, rds, brush->pose_offset, ss->pose_origin, NULL);
+ }
+ cursor_draw_point_screen_space(pos, ar, ss->pose_origin, vc.obact->obmat, 5);
+ }
+
+ /* Draw 3D brush cursor */
+ GPU_matrix_push_projection();
+ ED_view3d_draw_setup_view(CTX_wm_window(C),
+ CTX_data_depsgraph_pointer(C),
+ CTX_data_scene(C),
+ ar,
+ CTX_wm_view3d(C),
+ NULL,
+ NULL,
+ NULL);
+
+ float cursor_trans[4][4], cursor_rot[4][4];
+ float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
+ float quat[4];
+
+ copy_m4_m4(cursor_trans, vc.obact->obmat);
+ translate_m4(cursor_trans, gi.location[0], gi.location[1], gi.location[2]);
+ rotation_between_vecs_to_quat(quat, z_axis, gi.normal);
+ quat_to_mat4(cursor_rot, quat);
+
+ GPU_matrix_push();
+ GPU_matrix_mul(cursor_trans);
+ GPU_matrix_mul(cursor_rot);
+ immUniformColor3fvAlpha(outline_col, outline_alpha);
+ GPU_line_width(2.0f);
+ imm_draw_circle_wire_3d(pos, 0, 0, rds, 80);
+ GPU_line_width(1.0f);
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
+ imm_draw_circle_wire_3d(pos, 0, 0, rds * clamp_f(brush->alpha, 0.0f, 1.0f), 80);
+ GPU_matrix_pop();
+
+ /* Update and draw dynamic mesh preview lines */
+ GPU_matrix_push();
+ GPU_matrix_mul(vc.obact->obmat);
+ if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) &&
+ !is_multires) {
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->modifiers_active) {
+ sculpt_geometry_preview_lines_update(C, ss, rds);
+ sculpt_geometry_preview_lines_draw(pos, ss);
+ }
+ }
+
+ /* Draw pose brush line preview */
+ if (brush->sculpt_tool == SCULPT_TOOL_POSE && !is_multires) {
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
+ GPU_line_width(2.0f);
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(pos, ss->pose_origin);
+ immVertex3fv(pos, gi.location);
+ immEnd();
+ }
+
+ GPU_matrix_pop();
+
+ GPU_matrix_pop_projection();
+
+ wmWindowViewport(win);
+ }
+ else {
+ /* Draw default cursor when the mouse is not over the mesh or there are no supported
+ * overlays active */
+ GPU_line_width(1.0f);
+ /* Reduce alpha to increase the contrast when the cursor is over the mesh */
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.8);
+ imm_draw_circle_wire_3d(pos, translation[0], translation[1], final_radius, 80);
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.35f);
+ imm_draw_circle_wire_3d(pos,
+ translation[0],
+ translation[1],
+ final_radius * clamp_f(brush->alpha, 0.0f, 1.0f),
+ 80);
+ }
+ }
+ else {
+ if (vc.obact->sculpt->cache && !vc.obact->sculpt->cache->first_time) {
+ /* Draw cursor location preview when the stroke is active using the data from StrokeCache
+ */
+ float cursor_location[3];
+ wmViewport(&ar->winrct);
+ copy_v3_v3(cursor_location, ss->cache->true_location);
+ if (ss->cache->brush->sculpt_tool == SCULPT_TOOL_GRAB) {
+ add_v3_v3(cursor_location, ss->cache->grab_delta);
+ }
+ cursor_draw_point_with_symmetry(
+ pos, ar, cursor_location, sd, vc.obact, ss->cache->radius);
+
+ /* Draw cached dynamic mesh preview lines */
+ if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) &&
+ !is_multires) {
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->modifiers_active) {
+ GPU_matrix_push_projection();
+ ED_view3d_draw_setup_view(CTX_wm_window(C),
+ CTX_data_depsgraph_pointer(C),
+ CTX_data_scene(C),
+ ar,
+ CTX_wm_view3d(C),
+ NULL,
+ NULL,
+ NULL);
+ GPU_matrix_push();
+ GPU_matrix_mul(vc.obact->obmat);
+ sculpt_geometry_preview_lines_draw(pos, ss);
+ GPU_matrix_pop();
+ GPU_matrix_pop_projection();
+ }
+ }
+
+ wmWindowViewport(win);
+ }
+ }
+ }
+ else {
+ /* Draw default cursor in unsupported modes */
+ GPU_line_width(1.0f);
+ imm_draw_circle_wire_3d(pos, translation[0], translation[1], final_radius, 40);
+ }
}
- imm_draw_circle_wire_2d(pos, translation[0], translation[1], final_radius, 40);
immUnbindProgram();
diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c
index d9fd194e96f..62c31c91f8d 100644
--- a/source/blender/editors/sculpt_paint/paint_curve.c
+++ b/source/blender/editors/sculpt_paint/paint_curve.c
@@ -35,8 +35,6 @@
#include "BKE_main.h"
#include "BKE_paint.h"
-#include "DEG_depsgraph.h"
-
#include "ED_view3d.h"
#include "ED_paint.h"
diff --git a/source/blender/editors/sculpt_paint/paint_curve_undo.c b/source/blender/editors/sculpt_paint/paint_curve_undo.c
index bd62a59e73f..c14ccd27804 100644
--- a/source/blender/editors/sculpt_paint/paint_curve_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_curve_undo.c
@@ -35,7 +35,6 @@
#include "ED_undo.h"
#include "WM_api.h"
-#include "WM_types.h"
#include "paint_intern.h"
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index 5852012891d..026dc39c668 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -37,7 +37,6 @@
#include "BKE_ccg.h"
#include "BKE_context.h"
#include "BKE_mesh.h"
-#include "BKE_mesh_runtime.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BKE_subsurf.h"
@@ -135,7 +134,6 @@ static void partialvis_update_grids(Depsgraph *depsgraph,
float planes[4][4])
{
CCGElem **grids;
- CCGKey key;
BLI_bitmap **grid_hidden;
int *grid_indices, totgrid, i;
bool any_changed = false, any_visible = false;
@@ -143,7 +141,7 @@ static void partialvis_update_grids(Depsgraph *depsgraph,
/* get PBVH data */
BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, NULL, &grids);
grid_hidden = BKE_pbvh_grid_hidden(pbvh);
- BKE_pbvh_get_grid_key(pbvh, &key);
+ CCGKey key = *BKE_pbvh_get_grid_key(pbvh);
sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
@@ -299,15 +297,17 @@ static void rect_from_props(rcti *rect, PointerRNA *ptr)
rect->ymax = RNA_int_get(ptr, "ymax");
}
-static void clip_planes_from_rect(bContext *C, float clip_planes[4][4], const rcti *rect)
+static void clip_planes_from_rect(bContext *C,
+ Depsgraph *depsgraph,
+ float clip_planes[4][4],
+ const rcti *rect)
{
ViewContext vc;
BoundBox bb;
view3d_operator_needs_opengl(C);
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ED_view3d_clipping_calc(&bb, clip_planes, vc.ar, vc.obact, rect);
- negate_m4(clip_planes);
}
/* If mode is inside, get all PBVH nodes that lie at least partially
@@ -322,17 +322,18 @@ static void get_pbvh_nodes(
/* select search callback */
switch (mode) {
case PARTIALVIS_INSIDE:
- cb = BKE_pbvh_node_planes_contain_AABB;
+ cb = BKE_pbvh_node_frustum_contain_AABB;
break;
case PARTIALVIS_OUTSIDE:
- cb = BKE_pbvh_node_planes_exclude_AABB;
+ cb = BKE_pbvh_node_frustum_exclude_AABB;
break;
case PARTIALVIS_ALL:
case PARTIALVIS_MASKED:
break;
}
- BKE_pbvh_search_gather(pbvh, cb, clip_planes, nodes, totnode);
+ PBVHFrustumPlanes frustum = {.planes = clip_planes, .num_planes = 4};
+ BKE_pbvh_search_gather(pbvh, cb, &frustum, nodes, totnode);
}
static int hide_show_exec(bContext *C, wmOperator *op)
@@ -355,7 +356,7 @@ static int hide_show_exec(bContext *C, wmOperator *op)
area = RNA_enum_get(op->ptr, "area");
rect_from_props(&rect, op->ptr);
- clip_planes_from_rect(C, clip_planes, &rect);
+ clip_planes_from_rect(C, depsgraph, clip_planes, &rect);
pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob);
BLI_assert(ob->sculpt->pbvh == pbvh);
@@ -363,6 +364,8 @@ static int hide_show_exec(bContext *C, wmOperator *op)
get_pbvh_nodes(pbvh, &nodes, &totnode, clip_planes, area);
pbvh_type = BKE_pbvh_type(pbvh);
+ negate_m4(clip_planes);
+
/* start undo */
switch (action) {
case PARTIALVIS_HIDE:
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index f3a6cfa0d5c..24c2dfb6c6b 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -113,10 +113,10 @@ void imapaint_region_tiles(
IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
- *tw = ((x + w - 1) >> IMAPAINT_TILE_BITS);
- *th = ((y + h - 1) >> IMAPAINT_TILE_BITS);
- *tx = (x >> IMAPAINT_TILE_BITS);
- *ty = (y >> IMAPAINT_TILE_BITS);
+ *tw = ((x + w - 1) >> ED_IMAGE_UNDO_TILE_BITS);
+ *th = ((y + h - 1) >> ED_IMAGE_UNDO_TILE_BITS);
+ *tx = (x >> ED_IMAGE_UNDO_TILE_BITS);
+ *ty = (y >> ED_IMAGE_UNDO_TILE_BITS);
}
void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h, bool find_old)
@@ -147,11 +147,12 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int
imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh);
- ListBase *undo_tiles = ED_image_undo_get_tiles();
+ ListBase *undo_tiles = ED_image_paint_tile_list_get();
for (ty = tiley; ty <= tileh; ty++) {
for (tx = tilex; tx <= tilew; tx++) {
- image_undo_push_tile(undo_tiles, ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
+ ED_image_paint_tile_push(
+ undo_tiles, ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
}
}
@@ -467,12 +468,13 @@ static void gradient_draw_line(bContext *UNUSED(C), int x, int y, void *customda
static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const float mouse[2])
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *settings = scene->toolsettings;
PaintOperation *pop = MEM_callocN(sizeof(PaintOperation), "PaintOperation"); /* caller frees */
Brush *brush = BKE_paint_brush(&settings->imapaint.paint);
int mode = RNA_enum_get(op->ptr, "mode");
- ED_view3d_viewcontext_init(C, &pop->vc);
+ ED_view3d_viewcontext_init(C, &pop->vc, depsgraph);
copy_v2_v2(pop->prevmouse, mouse);
copy_v2_v2(pop->startmouse, mouse);
@@ -699,7 +701,7 @@ static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
event->type);
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
return OPERATOR_FINISHED;
}
/* add modal handler */
@@ -1022,7 +1024,7 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event
!RNA_boolean_get(op->ptr, "merged");
paint_sample_color(C, ar, event->mval[0], event->mval[1], use_sample_texture, false);
- WM_cursor_modal_set(win, BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER);
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 8f1156295a3..4f1ae10aa62 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -1197,23 +1197,24 @@ static void paint_2d_do_making_brush(ImagePaintState *s,
int tileh)
{
ImBuf tmpbuf;
- IMB_initImBuf(&tmpbuf, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0);
+ IMB_initImBuf(&tmpbuf, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE, 32, 0);
- ListBase *undo_tiles = ED_image_undo_get_tiles();
+ ListBase *undo_tiles = ED_image_paint_tile_list_get();
for (int ty = tiley; ty <= tileh; ty++) {
for (int tx = tilex; tx <= tilew; tx++) {
/* retrieve original pixels + mask from undo buffer */
unsigned short *mask;
- int origx = region->destx - tx * IMAPAINT_TILE_SIZE;
- int origy = region->desty - ty * IMAPAINT_TILE_SIZE;
+ int origx = region->destx - tx * ED_IMAGE_UNDO_TILE_SIZE;
+ int origy = region->desty - ty * ED_IMAGE_UNDO_TILE_SIZE;
if (s->canvas->rect_float) {
- tmpbuf.rect_float = image_undo_find_tile(
+ tmpbuf.rect_float = ED_image_paint_tile_find(
undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
}
else {
- tmpbuf.rect = image_undo_find_tile(undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
+ tmpbuf.rect = ED_image_paint_tile_find(
+ undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
}
IMB_rectblend(s->canvas,
@@ -1454,8 +1455,6 @@ static void paint_2d_canvas_free(ImagePaintState *s)
paint_delete_blur_kernel(s->blurkernel);
MEM_freeN(s->blurkernel);
}
-
- image_undo_remove_masks();
}
void paint_2d_stroke(void *ps,
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 397b2981ace..5e004c7d675 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -77,15 +77,11 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
-#include "BKE_texture.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
-#include "UI_interface.h"
-
#include "ED_object.h"
-#include "ED_mesh.h"
#include "ED_node.h"
#include "ED_paint.h"
#include "ED_screen.h"
@@ -105,7 +101,6 @@
#include "IMB_colormanagement.h"
-#include "bmesh.h"
//#include "bmesh_tools.h"
#include "paint_intern.h"
@@ -1812,31 +1807,31 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
}
if (generate_tile) {
- ListBase *undo_tiles = ED_image_undo_get_tiles();
+ ListBase *undo_tiles = ED_image_paint_tile_list_get();
volatile void *undorect;
if (tinf->masked) {
- undorect = image_undo_push_tile(undo_tiles,
- pjIma->ima,
- pjIma->ibuf,
- tinf->tmpibuf,
- tx,
- ty,
- &pjIma->maskRect[tile_index],
- &pjIma->valid[tile_index],
- true,
- false);
+ undorect = ED_image_paint_tile_push(undo_tiles,
+ pjIma->ima,
+ pjIma->ibuf,
+ tinf->tmpibuf,
+ tx,
+ ty,
+ &pjIma->maskRect[tile_index],
+ &pjIma->valid[tile_index],
+ true,
+ false);
}
else {
- undorect = image_undo_push_tile(undo_tiles,
- pjIma->ima,
- pjIma->ibuf,
- tinf->tmpibuf,
- tx,
- ty,
- NULL,
- &pjIma->valid[tile_index],
- true,
- false);
+ undorect = ED_image_paint_tile_push(undo_tiles,
+ pjIma->ima,
+ pjIma->ibuf,
+ tinf->tmpibuf,
+ tx,
+ ty,
+ NULL,
+ &pjIma->valid[tile_index],
+ true,
+ false);
}
BKE_image_mark_dirty(pjIma->ima, pjIma->ibuf);
@@ -1885,14 +1880,14 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
/* calculate the undo tile offset of the pixel, used to store the original
* pixel color and accumulated mask if any */
- x_tile = x_px >> IMAPAINT_TILE_BITS;
- y_tile = y_px >> IMAPAINT_TILE_BITS;
+ x_tile = x_px >> ED_IMAGE_UNDO_TILE_BITS;
+ y_tile = y_px >> ED_IMAGE_UNDO_TILE_BITS;
- x_round = x_tile * IMAPAINT_TILE_SIZE;
- y_round = y_tile * IMAPAINT_TILE_SIZE;
+ x_round = x_tile * ED_IMAGE_UNDO_TILE_SIZE;
+ y_round = y_tile * ED_IMAGE_UNDO_TILE_SIZE;
// memset(projPixel, 0, size);
- tile_offset = (x_px - x_round) + (y_px - y_round) * IMAPAINT_TILE_SIZE;
+ tile_offset = (x_px - x_round) + (y_px - y_round) * ED_IMAGE_UNDO_TILE_SIZE;
tile_index = project_paint_undo_subtiles(tinf, x_tile, y_tile);
/* other thread may be initializing the tile so wait here */
@@ -1900,8 +1895,9 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
/* pass */
}
- BLI_assert(tile_index < (IMAPAINT_TILE_NUMBER(ibuf->x) * IMAPAINT_TILE_NUMBER(ibuf->y)));
- BLI_assert(tile_offset < (IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE));
+ BLI_assert(tile_index <
+ (ED_IMAGE_UNDO_TILE_NUMBER(ibuf->x) * ED_IMAGE_UNDO_TILE_NUMBER(ibuf->y)));
+ BLI_assert(tile_offset < (ED_IMAGE_UNDO_TILE_SIZE * ED_IMAGE_UNDO_TILE_SIZE));
projPixel->valid = projima->valid[tile_index];
@@ -2979,7 +2975,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
TileInfo tinf = {
ps->tile_lock,
ps->do_masking,
- IMAPAINT_TILE_NUMBER(ibuf->x),
+ ED_IMAGE_UNDO_TILE_NUMBER(ibuf->x),
tmpibuf,
ps->projImages + image_index,
};
@@ -3931,7 +3927,7 @@ static void proj_paint_state_thread_init(ProjPaintState *ps, const bool reset_th
BLI_spin_init(ps->tile_lock);
}
- image_undo_init_locks();
+ ED_image_paint_tile_lock_init();
}
for (a = 0; a < ps->thread_tot; a++) {
@@ -4249,8 +4245,8 @@ static void project_paint_build_proj_ima(ProjPaintState *ps,
projIma->ima = node->link;
projIma->touch = 0;
projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL);
- size = sizeof(void **) * IMAPAINT_TILE_NUMBER(projIma->ibuf->x) *
- IMAPAINT_TILE_NUMBER(projIma->ibuf->y);
+ size = sizeof(void **) * ED_IMAGE_UNDO_TILE_NUMBER(projIma->ibuf->x) *
+ ED_IMAGE_UNDO_TILE_NUMBER(projIma->ibuf->y);
projIma->partRedrawRect = BLI_memarena_alloc(
arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
partial_redraw_array_init(projIma->partRedrawRect);
@@ -4540,8 +4536,6 @@ static void project_paint_end(ProjPaintState *ps)
{
int a;
- image_undo_remove_masks();
-
/* dereference used image buffers */
if (ps->is_shared_user == false) {
ProjPaintImage *projIma;
@@ -4583,7 +4577,7 @@ static void project_paint_end(ProjPaintState *ps)
MEM_freeN((void *)ps->tile_lock);
}
- image_undo_end_locks();
+ ED_image_paint_tile_lock_end();
#ifndef PROJ_DEBUG_NOSEAMBLEED
if (ps->seam_bleed_px > 0.0f) {
@@ -5212,8 +5206,10 @@ static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool),
float line_len_sq_inv, line_len;
float f;
float color_f[4];
- float p[2] = {projPixel->projCoSS[0] - lastpos[0],
- projPixel->projCoSS[1] - lastpos[1]};
+ const float p[2] = {
+ projPixel->projCoSS[0] - lastpos[0],
+ projPixel->projCoSS[1] - lastpos[1],
+ };
sub_v2_v2v2(tangent, pos, lastpos);
line_len = len_squared_v2(tangent);
diff --git a/source/blender/editors/sculpt_paint/paint_image_undo.c b/source/blender/editors/sculpt_paint/paint_image_undo.c
deleted file mode 100644
index 93dcd3ad0f6..00000000000
--- a/source/blender/editors/sculpt_paint/paint_image_undo.c
+++ /dev/null
@@ -1,625 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/** \file
- * \ingroup edsculpt
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-#include "BLI_threads.h"
-
-#include "DNA_image_types.h"
-#include "DNA_windowmanager_types.h"
-#include "DNA_object_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_space_types.h"
-#include "DNA_workspace_types.h"
-
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-
-#include "BKE_context.h"
-#include "BKE_image.h"
-#include "BKE_paint.h"
-#include "BKE_undo_system.h"
-
-#include "DEG_depsgraph.h"
-
-#include "ED_paint.h"
-#include "ED_undo.h"
-#include "ED_util.h"
-#include "ED_object.h"
-
-#include "GPU_draw.h"
-
-#include "WM_api.h"
-
-#include "paint_intern.h"
-
-/* -------------------------------------------------------------------- */
-/** \name Undo Conversion
- * \{ */
-
-typedef struct UndoImageTile {
- struct UndoImageTile *next, *prev;
-
- char ibufname[IMB_FILENAME_SIZE];
-
- union {
- float *fp;
- unsigned int *uint;
- void *pt;
- } rect;
-
- unsigned short *mask;
-
- int x, y;
-
- /* TODO(campbell): avoid storing the ID per tile,
- * adds unnecessary overhead restoring undo steps when most tiles share the same image. */
- UndoRefID_Image image_ref;
-
- short source;
- bool use_float;
- char gen_type;
- bool valid;
-
- size_t undo_size;
-} UndoImageTile;
-
-/* this is a static resource for non-globality,
- * Maybe it should be exposed as part of the
- * paint operation, but for now just give a public interface */
-static SpinLock undolock;
-
-void image_undo_init_locks(void)
-{
- BLI_spin_init(&undolock);
-}
-
-void image_undo_end_locks(void)
-{
- BLI_spin_end(&undolock);
-}
-
-/* UNDO */
-typedef enum {
- COPY = 0,
- RESTORE = 1,
- RESTORE_COPY = 2,
-} CopyMode;
-
-static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, CopyMode mode)
-{
- if (mode == COPY) {
- /* copy or swap contents of tile->rect and region in ibuf->rect */
- IMB_rectcpy(tmpibuf,
- ibuf,
- 0,
- 0,
- tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE,
- IMAPAINT_TILE_SIZE,
- IMAPAINT_TILE_SIZE);
-
- if (ibuf->rect_float) {
- SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
- }
- else {
- SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
- }
- }
- else {
- if (mode == RESTORE_COPY) {
- IMB_rectcpy(tmpibuf,
- ibuf,
- 0,
- 0,
- tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE,
- IMAPAINT_TILE_SIZE,
- IMAPAINT_TILE_SIZE);
- }
- /* swap to the tmpbuf for easy copying */
- if (ibuf->rect_float) {
- SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
- }
- else {
- SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
- }
-
- IMB_rectcpy(ibuf,
- tmpibuf,
- tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE,
- 0,
- 0,
- IMAPAINT_TILE_SIZE,
- IMAPAINT_TILE_SIZE);
-
- if (mode == RESTORE) {
- if (ibuf->rect_float) {
- SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
- }
- else {
- SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
- }
- }
- }
-}
-
-void *image_undo_find_tile(ListBase *undo_tiles,
- Image *ima,
- ImBuf *ibuf,
- int x_tile,
- int y_tile,
- unsigned short **mask,
- bool validate)
-{
- UndoImageTile *tile;
- const bool use_float = (ibuf->rect_float != NULL);
-
- for (tile = undo_tiles->first; tile; tile = tile->next) {
- if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type &&
- ima->source == tile->source) {
- if (tile->use_float == use_float) {
- if (STREQ(tile->ibufname, ibuf->name)) {
- if (mask) {
- /* allocate mask if requested */
- if (!tile->mask) {
- tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE *
- IMAPAINT_TILE_SIZE,
- "UndoImageTile.mask");
- }
-
- *mask = tile->mask;
- }
- if (validate) {
- tile->valid = true;
- }
- return tile->rect.pt;
- }
- }
- }
- }
-
- return NULL;
-}
-
-void *image_undo_push_tile(ListBase *undo_tiles,
- Image *ima,
- ImBuf *ibuf,
- ImBuf **tmpibuf,
- int x_tile,
- int y_tile,
- unsigned short **mask,
- bool **valid,
- bool proj,
- bool find_prev)
-{
- UndoImageTile *tile;
- int allocsize;
- const bool use_float = (ibuf->rect_float != NULL);
- void *data;
-
- /* check if tile is already pushed */
-
- /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
- if (find_prev) {
- data = image_undo_find_tile(undo_tiles, ima, ibuf, x_tile, y_tile, mask, true);
- if (data) {
- return data;
- }
- }
-
- if (*tmpibuf == NULL) {
- *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
- }
-
- tile = MEM_callocN(sizeof(UndoImageTile), "UndoImageTile");
- tile->x = x_tile;
- tile->y = y_tile;
-
- /* add mask explicitly here */
- if (mask) {
- *mask = tile->mask = MEM_callocN(
- sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE, "UndoImageTile.mask");
- }
- allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
- allocsize *= (ibuf->rect_float) ? sizeof(float) : sizeof(char);
- tile->rect.pt = MEM_mapallocN(allocsize, "UndeImageTile.rect");
-
- BLI_strncpy(tile->ibufname, ibuf->name, sizeof(tile->ibufname));
-
- tile->gen_type = ima->gen_type;
- tile->source = ima->source;
- tile->use_float = use_float;
- tile->valid = true;
- tile->image_ref.ptr = ima;
-
- if (valid) {
- *valid = &tile->valid;
- }
- undo_copy_tile(tile, *tmpibuf, ibuf, COPY);
-
- if (proj) {
- BLI_spin_lock(&undolock);
- }
- BLI_addtail(undo_tiles, tile);
-
- if (proj) {
- BLI_spin_unlock(&undolock);
- }
- return tile->rect.pt;
-}
-
-void image_undo_remove_masks(void)
-{
- ListBase *undo_tiles = ED_image_undo_get_tiles();
- UndoImageTile *tile;
-
- for (tile = undo_tiles->first; tile; tile = tile->next) {
- if (tile->mask) {
- MEM_freeN(tile->mask);
- tile->mask = NULL;
- }
- }
-}
-
-static void image_undo_restore_runtime(ListBase *lb)
-{
- ImBuf *ibuf, *tmpibuf;
- UndoImageTile *tile;
-
- tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
-
- for (tile = lb->first; tile; tile = tile->next) {
- Image *ima = tile->image_ref.ptr;
- ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
-
- undo_copy_tile(tile, tmpibuf, ibuf, RESTORE);
-
- GPU_free_image(ima); /* force OpenGL reload (maybe partial update will operate better?) */
- if (ibuf->rect_float) {
- ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
- }
- if (ibuf->mipmap[0]) {
- ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
- }
- ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
-
- IMB_freeImBuf(tmpibuf);
-}
-
-static void image_undo_restore_list(ListBase *lb)
-{
- ImBuf *tmpibuf = IMB_allocImBuf(
- IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
-
- for (UndoImageTile *tile = lb->first; tile; tile = tile->next) {
-
- Image *ima = tile->image_ref.ptr;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
-
- if (ima && ibuf && !STREQ(tile->ibufname, ibuf->name)) {
- /* current ImBuf filename was changed, probably current frame
- * was changed when painting on image sequence, rather than storing
- * full image user (which isn't so obvious, btw) try to find ImBuf with
- * matched file name in list of already loaded images */
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
-
- ibuf = BKE_image_get_ibuf_with_name(ima, tile->ibufname);
- }
-
- if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- if (ima->gen_type != tile->gen_type || ima->source != tile->source) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- const bool use_float = (ibuf->rect_float != NULL);
-
- if (use_float != tile->use_float) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- undo_copy_tile(tile, tmpibuf, ibuf, RESTORE_COPY);
-
- BKE_image_mark_dirty(ima, ibuf);
- GPU_free_image(ima); /* force OpenGL reload */
-
- if (ibuf->rect_float) {
- ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
- }
- if (ibuf->mipmap[0]) {
- ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
- }
- ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
-
- DEG_id_tag_update(&ima->id, 0);
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
-
- IMB_freeImBuf(tmpibuf);
-}
-
-static void image_undo_free_list(ListBase *lb)
-{
- for (UndoImageTile *tile = lb->first, *tile_next; tile; tile = tile_next) {
- tile_next = tile->next;
- MEM_freeN(tile->rect.pt);
- MEM_freeN(tile);
- }
-}
-
-static void image_undo_invalidate(void)
-{
- UndoImageTile *tile;
- ListBase *lb = ED_image_undo_get_tiles();
-
- for (tile = lb->first; tile; tile = tile->next) {
- tile->valid = false;
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Implements ED Undo System
- * \{ */
-
-typedef struct ImageUndoStep {
- UndoStep step;
- ListBase tiles;
- bool is_encode_init;
- ePaintMode paint_mode;
-} ImageUndoStep;
-
-static bool image_undosys_poll(bContext *C)
-{
- Object *obact = CTX_data_active_object(C);
-
- ScrArea *sa = CTX_wm_area(C);
- if (sa && (sa->spacetype == SPACE_IMAGE)) {
- SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
- if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
- return true;
- }
- }
- else {
- if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) {
- return true;
- }
- }
- return false;
-}
-
-static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
-{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- /* dummy, memory is cleared anyway. */
- us->is_encode_init = true;
- BLI_listbase_clear(&us->tiles);
-}
-
-static bool image_undosys_step_encode(struct bContext *C,
- struct Main *UNUSED(bmain),
- UndoStep *us_p)
-{
- /* dummy, encoding is done along the way by adding tiles
- * to the current 'ImageUndoStep' added by encode_init. */
- ImageUndoStep *us = (ImageUndoStep *)us_p;
-
- BLI_assert(us->step.data_size == 0);
-
- int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
-
- if (us->is_encode_init) {
- /* first dispose of invalid tiles (may happen due to drag dot for instance) */
- for (UndoImageTile *tile = us->tiles.first; tile;) {
- if (!tile->valid) {
- UndoImageTile *tmp_tile = tile->next;
- MEM_freeN(tile->rect.pt);
- BLI_freelinkN(&us->tiles, tile);
- tile = tmp_tile;
- }
- else {
- us->step.data_size += allocsize * (tile->use_float ? sizeof(float) : sizeof(char));
- tile = tile->next;
- }
- }
- }
- else {
- /* Happens when switching modes. */
- ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C);
- BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
- us->paint_mode = paint_mode;
- }
-
- us_p->is_applied = true;
-
- return true;
-}
-
-static void image_undosys_step_decode_undo_impl(ImageUndoStep *us)
-{
- BLI_assert(us->step.is_applied == true);
- image_undo_restore_list(&us->tiles);
- us->step.is_applied = false;
-}
-
-static void image_undosys_step_decode_redo_impl(ImageUndoStep *us)
-{
- BLI_assert(us->step.is_applied == false);
- image_undo_restore_list(&us->tiles);
- us->step.is_applied = true;
-}
-
-static void image_undosys_step_decode_undo(ImageUndoStep *us, bool is_final)
-{
- ImageUndoStep *us_iter = us;
- while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) {
- if (us_iter->step.next->is_applied == false) {
- break;
- }
- us_iter = (ImageUndoStep *)us_iter->step.next;
- }
- while (us_iter != us || (!is_final && us_iter == us)) {
- image_undosys_step_decode_undo_impl(us_iter);
- if (us_iter == us) {
- break;
- }
- us_iter = (ImageUndoStep *)us_iter->step.prev;
- }
-}
-
-static void image_undosys_step_decode_redo(ImageUndoStep *us)
-{
- ImageUndoStep *us_iter = us;
- while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) {
- if (us_iter->step.prev->is_applied == true) {
- break;
- }
- us_iter = (ImageUndoStep *)us_iter->step.prev;
- }
- while (us_iter && (us_iter->step.is_applied == false)) {
- image_undosys_step_decode_redo_impl(us_iter);
- if (us_iter == us) {
- break;
- }
- us_iter = (ImageUndoStep *)us_iter->step.next;
- }
-}
-
-static void image_undosys_step_decode(
- struct bContext *C, struct Main *bmain, UndoStep *us_p, int dir, bool is_final)
-{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- if (dir < 0) {
- image_undosys_step_decode_undo(us, is_final);
- }
- else {
- image_undosys_step_decode_redo(us);
- }
-
- if (us->paint_mode == PAINT_MODE_TEXTURE_3D) {
- ED_object_mode_set(C, OB_MODE_TEXTURE_PAINT);
- }
-
- /* Refresh texture slots. */
- ED_editors_init_for_undo(bmain);
-}
-
-static void image_undosys_step_free(UndoStep *us_p)
-{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- image_undo_free_list(&us->tiles);
-}
-
-static void image_undosys_foreach_ID_ref(UndoStep *us_p,
- UndoTypeForEachIDRefFn foreach_ID_ref_fn,
- void *user_data)
-{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- for (UndoImageTile *tile = us->tiles.first; tile; tile = tile->next) {
- foreach_ID_ref_fn(user_data, ((UndoRefID *)&tile->image_ref));
- }
-}
-
-/* Export for ED_undo_sys. */
-void ED_image_undosys_type(UndoType *ut)
-{
- ut->name = "Image";
- ut->poll = image_undosys_poll;
- ut->step_encode_init = image_undosys_step_encode_init;
- ut->step_encode = image_undosys_step_encode;
- ut->step_decode = image_undosys_step_decode;
- ut->step_free = image_undosys_step_free;
-
- ut->step_foreach_ID_ref = image_undosys_foreach_ID_ref;
-
- ut->use_context = true;
-
- ut->step_size = sizeof(ImageUndoStep);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Utilities
- * \{ */
-
-ListBase *ED_image_undosys_step_get_tiles(UndoStep *us_p)
-{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- return &us->tiles;
-}
-
-ListBase *ED_image_undo_get_tiles(void)
-{
- UndoStack *ustack = ED_undo_stack_get();
- UndoStep *us_prev = ustack->step_init;
- UndoStep *us_p = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_IMAGE);
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- /* We should always have an undo push started when accessing tiles,
- * not doing this means we won't have paint_mode correctly set. */
- BLI_assert(us_p == us_prev);
- if (us_p != us_prev) {
- /* Fallback value until we can be sure this never happens. */
- us->paint_mode = PAINT_MODE_TEXTURE_2D;
- }
- return ED_image_undosys_step_get_tiles(us_p);
-}
-
-/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/
-void ED_image_undo_restore(UndoStep *us)
-{
- ListBase *lb = ED_image_undosys_step_get_tiles(us);
- image_undo_restore_runtime(lb);
- image_undo_invalidate();
-}
-
-void ED_image_undo_push_begin(const char *name, int paint_mode)
-{
- UndoStack *ustack = ED_undo_stack_get();
- bContext *C = NULL; /* special case, we never read from this. */
- UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE);
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
- us->paint_mode = paint_mode;
-}
-
-void ED_image_undo_push_end(void)
-{
- UndoStack *ustack = ED_undo_stack_get();
- BKE_undosys_step_push(ustack, NULL, NULL);
- WM_file_tag_modified();
-}
-
-/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 5efedf69fe4..69eed84fe2b 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -70,7 +70,7 @@ struct PaintStroke *paint_stroke_new(struct bContext *C,
StrokeRedraw redraw,
StrokeDone done,
int event_type);
-void paint_stroke_data_free(struct wmOperator *op);
+void paint_stroke_free(struct bContext *C, struct wmOperator *op);
bool paint_space_stroke_enabled(struct Brush *br, enum ePaintMode mode);
bool paint_supports_dynamic_size(struct Brush *br, enum ePaintMode mode);
@@ -184,10 +184,6 @@ typedef struct ImagePaintPartialRedraw {
int enabled;
} ImagePaintPartialRedraw;
-#define IMAPAINT_TILE_BITS 6
-#define IMAPAINT_TILE_SIZE (1 << IMAPAINT_TILE_BITS)
-#define IMAPAINT_TILE_NUMBER(size) (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS)
-
bool image_texture_paint_poll(struct bContext *C);
void imapaint_image_update(struct SpaceImage *sima,
struct Image *image,
@@ -252,31 +248,6 @@ void PAINT_OT_add_texture_paint_slot(struct wmOperatorType *ot);
void PAINT_OT_image_paint(struct wmOperatorType *ot);
void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot);
-/* paint_image_undo.c */
-void *image_undo_find_tile(ListBase *undo_tiles,
- struct Image *ima,
- struct ImBuf *ibuf,
- int x_tile,
- int y_tile,
- unsigned short **mask,
- bool validate);
-void *image_undo_push_tile(ListBase *undo_tiles,
- struct Image *ima,
- struct ImBuf *ibuf,
- struct ImBuf **tmpibuf,
- int x_tile,
- int y_tile,
- unsigned short **,
- bool **valid,
- bool proj,
- bool find_prev);
-void image_undo_remove_masks(void);
-void image_undo_init_locks(void);
-void image_undo_end_locks(void);
-
-struct ListBase *ED_image_undosys_step_get_tiles(struct UndoStep *us_p);
-struct ListBase *ED_image_undo_get_tiles(void);
-
/* sculpt_uv.c */
void SCULPT_OT_uv_sculpt_stroke(struct wmOperatorType *ot);
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 74212058fc7..a93e55685d2 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -109,6 +109,7 @@ static void mask_flood_fill_task_cb(void *__restrict userdata,
const PaintMaskFloodMode mode = data->mode;
const float value = data->value;
+ bool redraw = false;
PBVHVertexIter vi;
@@ -116,13 +117,19 @@ static void mask_flood_fill_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE)
{
+ float prevmask = *vi.mask;
mask_flood_fill_set_elem(vi.mask, mode, value);
+ if (prevmask != *vi.mask) {
+ redraw = true;
+ }
}
BKE_pbvh_vertex_iter_end;
- BKE_pbvh_node_mark_redraw(node);
- if (data->multires) {
- BKE_pbvh_node_mark_normals_update(node);
+ if (redraw) {
+ BKE_pbvh_node_mark_update_mask(node);
+ if (data->multires) {
+ BKE_pbvh_node_mark_normals_update(node);
+ }
}
}
@@ -160,16 +167,15 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
-
- 0, totnode, &data, mask_flood_fill_task_cb, &settings);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BLI_task_parallel_range(0, totnode, &data, mask_flood_fill_task_cb, &settings);
if (multires) {
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
}
+ BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask);
+
sculpt_undo_push_end();
if (nodes) {
@@ -255,24 +261,32 @@ static void mask_box_select_task_cb(void *__restrict userdata,
PBVHVertexIter vi;
bool any_masked = false;
+ bool redraw = false;
BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE)
{
if (is_effected(clip_planes_final, vi.co)) {
+ float prevmask = *vi.mask;
if (!any_masked) {
any_masked = true;
sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_MASK);
- BKE_pbvh_node_mark_redraw(node);
if (data->multires) {
BKE_pbvh_node_mark_normals_update(node);
}
}
mask_flood_fill_set_elem(vi.mask, mode, value);
+ if (prevmask != *vi.mask) {
+ redraw = true;
+ }
}
}
BKE_pbvh_vertex_iter_end;
+
+ if (redraw) {
+ BKE_pbvh_node_mark_update_mask(node);
+ }
}
bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *rect, bool select)
@@ -297,7 +311,6 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
/* transform the clip planes in object space */
ED_view3d_clipping_calc(&bb, clip_planes, vc->ar, vc->obact, rect);
- negate_m4(clip_planes);
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true);
pbvh = ob->sculpt->pbvh;
@@ -305,7 +318,7 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
sculpt_undo_push_begin("Mask box fill");
- for (symmpass = 0; symmpass <= symm; ++symmpass) {
+ for (symmpass = 0; symmpass <= symm; symmpass++) {
if (symmpass == 0 || (symm & symmpass && (symm != 5 || symmpass != 3) &&
(symm != 6 || (symmpass != 3 && symmpass != 5)))) {
int j = 0;
@@ -315,8 +328,10 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
flip_plane(clip_planes_final[j], clip_planes[j], symmpass);
}
- BKE_pbvh_search_gather(
- pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode);
+ PBVHFrustumPlanes frustum = {.planes = clip_planes_final, .num_planes = 4};
+ BKE_pbvh_search_gather(pbvh, BKE_pbvh_node_frustum_contain_AABB, &frustum, &nodes, &totnode);
+
+ negate_m4(clip_planes_final);
MaskTaskData data = {
.ob = ob,
@@ -329,9 +344,7 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
- totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings);
if (nodes) {
@@ -344,6 +357,8 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
}
+ BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask);
+
sculpt_undo_push_end();
ED_region_tag_redraw(ar);
@@ -462,7 +477,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
/* Calculations of individual vertices are done in 2D screen space to diminish the amount of
* calculations done. Bounding box PBVH collision is not computed against enclosing rectangle
* of lasso */
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
/* lasso data calculations */
data.vc = &vc;
@@ -483,7 +498,6 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
&data);
ED_view3d_clipping_calc(&bb, clip_planes, vc.ar, vc.obact, &data.rect);
- negate_m4(clip_planes);
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true);
pbvh = ob->sculpt->pbvh;
@@ -491,7 +505,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
sculpt_undo_push_begin("Mask lasso fill");
- for (symmpass = 0; symmpass <= symm; ++symmpass) {
+ for (symmpass = 0; symmpass <= symm; symmpass++) {
if ((symmpass == 0) || (symm & symmpass && (symm != 5 || symmpass != 3) &&
(symm != 6 || (symmpass != 3 && symmpass != 5)))) {
int j = 0;
@@ -505,8 +519,11 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
/* gather nodes inside lasso's enclosing rectangle
* (should greatly help with bigger meshes) */
+ PBVHFrustumPlanes frustum = {.planes = clip_planes_final, .num_planes = 4};
BKE_pbvh_search_gather(
- pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode);
+ pbvh, BKE_pbvh_node_frustum_contain_AABB, &frustum, &nodes, &totnode);
+
+ negate_m4(clip_planes_final);
data.task_data.ob = ob;
data.task_data.pbvh = pbvh;
@@ -516,9 +533,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
data.task_data.value = value;
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
- (totnode > SCULPT_THREADED_LIMIT));
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings);
if (nodes) {
@@ -531,6 +546,8 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
}
+ BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask);
+
sculpt_undo_push_end();
ED_region_tag_redraw(vc.ar);
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index f58afcdadc1..97455d479dc 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -29,32 +29,22 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
-#include "DNA_gpencil_types.h"
#include "BKE_brush.h"
#include "BKE_context.h"
-#include "BKE_gpencil.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_paint.h"
-#include "BKE_report.h"
-
-#include "DEG_depsgraph.h"
#include "ED_paint.h"
#include "ED_screen.h"
-#include "ED_select_utils.h"
#include "ED_image.h"
-#include "ED_gpencil.h"
-#include "UI_resources.h"
#include "WM_api.h"
#include "WM_types.h"
-#include "WM_toolsystem.h"
#include "RNA_access.h"
#include "RNA_define.h"
-#include "RNA_enum_types.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 694dae49d30..d8be345cc84 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -43,7 +43,6 @@
#include "BKE_curve.h"
#include "BKE_colortools.h"
#include "BKE_image.h"
-#include "BKE_mesh.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -57,6 +56,7 @@
#include "IMB_imbuf_types.h"
#include "paint_intern.h"
+#include "sculpt_intern.h"
#include <float.h>
#include <math.h>
@@ -93,6 +93,8 @@ typedef struct PaintStroke {
int cur_sample;
float last_mouse_position[2];
+ float last_world_space_position[3];
+ bool stroke_over_mesh;
/* space distance covered so far */
float stroke_distance;
@@ -218,6 +220,8 @@ static bool paint_tool_require_location(Brush *brush, ePaintMode mode)
case PAINT_MODE_SCULPT:
if (ELEM(brush->sculpt_tool,
SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ELASTIC_DEFORM,
+ SCULPT_TOOL_POSE,
SCULPT_TOOL_ROTATE,
SCULPT_TOOL_SNAKE_HOOK,
SCULPT_TOOL_THUMB)) {
@@ -233,11 +237,27 @@ static bool paint_tool_require_location(Brush *brush, ePaintMode mode)
return true;
}
+static bool paint_stroke_use_scene_spacing(Brush *brush, ePaintMode mode)
+{
+ switch (mode) {
+ case PAINT_MODE_SCULPT:
+ return brush->flag & BRUSH_SCENE_SPACING;
+ default:
+ break;
+ }
+ return false;
+}
+
static bool paint_tool_require_inbetween_mouse_events(Brush *brush, ePaintMode mode)
{
switch (mode) {
case PAINT_MODE_SCULPT:
- if (ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB)) {
+ if (ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_ELASTIC_DEFORM,
+ SCULPT_TOOL_POSE)) {
return false;
}
else {
@@ -523,6 +543,11 @@ static void paint_brush_stroke_add_step(bContext *C,
copy_v2_v2(stroke->last_mouse_position, mouse_in);
stroke->last_pressure = pressure;
+ if (paint_stroke_use_scene_spacing(brush, mode)) {
+ sculpt_stroke_get_location(C, stroke->last_world_space_position, stroke->last_mouse_position);
+ mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position);
+ }
+
if (paint_stroke_use_jitter(mode, brush, stroke->stroke_mode == BRUSH_STROKE_INVERT)) {
float delta[2];
float factor = stroke->zoom_2d;
@@ -600,14 +625,34 @@ static bool paint_smooth_stroke(PaintStroke *stroke,
return true;
}
-static float paint_space_stroke_spacing(const Scene *scene,
+static float paint_space_stroke_spacing(bContext *C,
+ const Scene *scene,
PaintStroke *stroke,
float size_pressure,
float spacing_pressure)
{
- /* brushes can have a minimum size of 1.0 but with pressure it can be smaller then a pixel
- * causing very high step sizes, hanging blender [#32381] */
- const float size_clamp = max_ff(1.0f, BKE_brush_size_get(scene, stroke->brush) * size_pressure);
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+ Brush *brush = BKE_paint_brush(paint);
+ float size_clamp = 0.0f;
+ float size = BKE_brush_size_get(scene, stroke->brush) * size_pressure;
+ if (paint_stroke_use_scene_spacing(brush, mode)) {
+ if (!BKE_brush_use_locked_size(scene, brush)) {
+ float last_object_space_position[3];
+ mul_v3_m4v3(
+ last_object_space_position, stroke->vc.obact->imat, stroke->last_world_space_position);
+ size_clamp = paint_calc_object_space_radius(&stroke->vc, last_object_space_position, size);
+ }
+ else {
+ size_clamp = BKE_brush_unprojected_radius_get(scene, brush) * size_pressure;
+ }
+ }
+ else {
+ /* brushes can have a minimum size of 1.0 but with pressure it can be smaller then a pixel
+ * causing very high step sizes, hanging blender [#32381] */
+ size_clamp = max_ff(1.0f, size);
+ }
+
float spacing = stroke->brush->spacing;
/* apply spacing pressure */
@@ -619,7 +664,12 @@ static float paint_space_stroke_spacing(const Scene *scene,
* the fact that brush can be scaled there. */
spacing *= stroke->zoom_2d;
- return max_ff(1.0, size_clamp * spacing / 50.0f);
+ if (paint_stroke_use_scene_spacing(brush, mode)) {
+ return max_ff(0.001f, size_clamp * spacing / 50.f);
+ }
+ else {
+ return max_ff(1.0, size_clamp * spacing / 50.0f);
+ }
}
static float paint_stroke_overlapped_curve(Brush *br, float x, float spacing)
@@ -677,14 +727,18 @@ static float paint_stroke_integrate_overlap(Brush *br, float factor)
}
}
-static float paint_space_stroke_spacing_variable(
- const Scene *scene, PaintStroke *stroke, float pressure, float dpressure, float length)
+static float paint_space_stroke_spacing_variable(bContext *C,
+ const Scene *scene,
+ PaintStroke *stroke,
+ float pressure,
+ float dpressure,
+ float length)
{
if (BKE_brush_use_size_pressure(scene, stroke->brush)) {
/* use pressure to modify size. set spacing so that at 100%, the circles
* are aligned nicely with no overlap. for this the spacing needs to be
* the average of the previous and next size. */
- float s = paint_space_stroke_spacing(scene, stroke, 1.0f, pressure);
+ float s = paint_space_stroke_spacing(C, scene, stroke, 1.0f, pressure);
float q = s * dpressure / (2.0f * length);
float pressure_fac = (1.0f + q) / (1.0f - q);
@@ -692,14 +746,15 @@ static float paint_space_stroke_spacing_variable(
float new_size_pressure = stroke->last_pressure * pressure_fac;
/* average spacing */
- float last_spacing = paint_space_stroke_spacing(scene, stroke, last_size_pressure, pressure);
- float new_spacing = paint_space_stroke_spacing(scene, stroke, new_size_pressure, pressure);
+ float last_spacing = paint_space_stroke_spacing(
+ C, scene, stroke, last_size_pressure, pressure);
+ float new_spacing = paint_space_stroke_spacing(C, scene, stroke, new_size_pressure, pressure);
return 0.5f * (last_spacing + new_spacing);
}
else {
/* no size pressure */
- return paint_space_stroke_spacing(scene, stroke, 1.0f, pressure);
+ return paint_space_stroke_spacing(C, scene, stroke, 1.0f, pressure);
}
}
@@ -711,29 +766,63 @@ static int paint_space_stroke(bContext *C,
float final_pressure)
{
const Scene *scene = CTX_data_scene(C);
+ ARegion *ar = CTX_wm_region(C);
PaintStroke *stroke = op->customdata;
UnifiedPaintSettings *ups = stroke->ups;
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+ Brush *brush = BKE_paint_brush(paint);
int cnt = 0;
- float pressure, dpressure;
- float mouse[2], dmouse[2];
- float length;
- float no_pressure_spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f);
-
- sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position);
+ const bool use_scene_spacing = paint_stroke_use_scene_spacing(brush, mode);
+ float d_world_space_position[3] = {0.0f};
- pressure = stroke->last_pressure;
- dpressure = final_pressure - stroke->last_pressure;
+ float no_pressure_spacing = paint_space_stroke_spacing(C, scene, stroke, 1.0f, 1.0f);
+ float pressure = stroke->last_pressure;
+ float dpressure = final_pressure - stroke->last_pressure;
- length = normalize_v2(dmouse);
+ float dmouse[2];
+ sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position);
+ float length = normalize_v2(dmouse);
+
+ if (use_scene_spacing) {
+ float world_space_position[3];
+ bool hit = sculpt_stroke_get_location(C, world_space_position, final_mouse);
+ mul_m4_v3(stroke->vc.obact->obmat, world_space_position);
+ if (hit && stroke->stroke_over_mesh) {
+ sub_v3_v3v3(d_world_space_position, world_space_position, stroke->last_world_space_position);
+ length = len_v3(d_world_space_position);
+ stroke->stroke_over_mesh = true;
+ }
+ else {
+ length = 0.0f;
+ zero_v3(d_world_space_position);
+ stroke->stroke_over_mesh = hit;
+ if (stroke->stroke_over_mesh) {
+ copy_v3_v3(stroke->last_world_space_position, world_space_position);
+ }
+ }
+ }
while (length > 0.0f) {
float spacing = paint_space_stroke_spacing_variable(
- scene, stroke, pressure, dpressure, length);
+ C, scene, stroke, pressure, dpressure, length);
+ float mouse[3];
if (length >= spacing) {
- mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing;
- mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing;
+ if (use_scene_spacing) {
+ float final_world_space_position[3];
+ normalize_v3(d_world_space_position);
+ mul_v3_v3fl(final_world_space_position, d_world_space_position, spacing);
+ add_v3_v3v3(final_world_space_position,
+ stroke->last_world_space_position,
+ final_world_space_position);
+ ED_view3d_project(ar, final_world_space_position, mouse);
+ }
+ else {
+ mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing;
+ mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing;
+ }
pressure = stroke->last_pressure + (spacing / length) * dpressure;
ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush,
@@ -767,14 +856,16 @@ PaintStroke *paint_stroke_new(bContext *C,
StrokeDone done,
int event_type)
{
+ struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke");
ToolSettings *toolsettings = CTX_data_tool_settings(C);
UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings;
Paint *p = BKE_paint_get_active_from_context(C);
Brush *br = stroke->brush = BKE_paint_brush(p);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
float zoomx, zoomy;
- ED_view3d_viewcontext_init(C, &stroke->vc);
+ ED_view3d_viewcontext_init(C, &stroke->vc, depsgraph);
stroke->get_location = get_location;
stroke->test_start = test_start;
@@ -797,6 +888,10 @@ PaintStroke *paint_stroke_new(bContext *C,
ups->overlap_factor = 1.0;
ups->stroke_active = true;
+ if (rv3d) {
+ rv3d->rflag |= RV3D_PAINTING;
+ }
+
zero_v3(ups->average_stroke_accum);
ups->average_stroke_counter = 0;
@@ -811,20 +906,42 @@ PaintStroke *paint_stroke_new(bContext *C,
return stroke;
}
-void paint_stroke_data_free(struct wmOperator *op)
+void paint_stroke_free(bContext *C, wmOperator *op)
{
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ PaintStroke *stroke = op->customdata;
+ UnifiedPaintSettings *ups = stroke->ups;
+
+ ups->draw_anchored = false;
+ ups->stroke_active = false;
+
+ if (rv3d) {
+ rv3d->rflag &= ~RV3D_PAINTING;
+ }
+
+ if (stroke->timer) {
+ WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), stroke->timer);
+ }
+
+ if (stroke->rng) {
+ BLI_rng_free(stroke->rng);
+ }
+
+ if (stroke->stroke_cursor) {
+ WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor);
+ }
+
+ BLI_freelistN(&stroke->line);
+
BKE_paint_set_overlay_override(0);
MEM_SAFE_FREE(op->customdata);
}
-static void stroke_done(struct bContext *C, struct wmOperator *op)
+static void stroke_done(bContext *C, wmOperator *op)
{
- struct PaintStroke *stroke = op->customdata;
+ PaintStroke *stroke = op->customdata;
UnifiedPaintSettings *ups = stroke->ups;
- ups->draw_anchored = false;
- ups->stroke_active = false;
-
/* reset rotation here to avoid doing so in cursor display */
if (!(stroke->brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
ups->brush_rotation = 0.0f;
@@ -844,21 +961,7 @@ static void stroke_done(struct bContext *C, struct wmOperator *op)
}
}
- if (stroke->timer) {
- WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), stroke->timer);
- }
-
- if (stroke->rng) {
- BLI_rng_free(stroke->rng);
- }
-
- if (stroke->stroke_cursor) {
- WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor);
- }
-
- BLI_freelistN(&stroke->line);
-
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
}
/* Returns zero if the stroke dots should not be spaced, non-zero otherwise */
@@ -871,6 +974,8 @@ static bool sculpt_is_grab_tool(Brush *br)
{
return ELEM(br->sculpt_tool,
SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ELASTIC_DEFORM,
+ SCULPT_TOOL_POSE,
SCULPT_TOOL_THUMB,
SCULPT_TOOL_ROTATE,
SCULPT_TOOL_SNAKE_HOOK);
@@ -1079,7 +1184,7 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
if (br->flag & BRUSH_CURVE) {
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
const Scene *scene = CTX_data_scene(C);
- const float spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f);
+ const float spacing = paint_space_stroke_spacing(C, scene, stroke, 1.0f, 1.0f);
PaintCurve *pc = br->paint_curve;
PaintCurvePoint *pcp;
float length_residue = 0.0f;
@@ -1250,6 +1355,11 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (!stroke->stroke_started) {
stroke->last_pressure = sample_average.pressure;
copy_v2_v2(stroke->last_mouse_position, sample_average.mouse);
+ if (paint_stroke_use_scene_spacing(br, mode)) {
+ stroke->stroke_over_mesh = sculpt_stroke_get_location(
+ C, stroke->last_world_space_position, sample_average.mouse);
+ mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position);
+ }
stroke->stroke_started = stroke->test_start(C, op, sample_average.mouse);
BLI_assert((stroke->stroke_started & ~1) == 0); /* 0/1 */
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 4b9d9a2cc01..a014fe7fdff 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -46,7 +46,6 @@
#include "BKE_image.h"
#include "BKE_material.h"
#include "BKE_mesh_runtime.h"
-#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_report.h"
@@ -101,9 +100,9 @@ bool paint_convert_bb_to_rect(rcti *rect,
ED_view3d_ob_project_mat_get(rv3d, ob, projection_mat);
- for (i = 0; i < 2; ++i) {
- for (j = 0; j < 2; ++j) {
- for (k = 0; k < 2; ++k) {
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 2; j++) {
+ for (k = 0; k < 2; k++) {
float vec[3], proj[2];
int proj_i[2];
vec[0] = i ? bb_min[0] : bb_max[0];
@@ -145,7 +144,6 @@ void paint_calc_redraw_planes(float planes[4][4],
rect.ymax += 2;
ED_view3d_clipping_calc(&bb, planes, ar, ob, &rect);
- negate_m4(planes);
}
float paint_calc_object_space_radius(ViewContext *vc, const float center[3], float pixel_radius)
@@ -251,7 +249,7 @@ static void imapaint_project(float matrix[4][4], const float co[3], float pco[4]
}
static void imapaint_tri_weights(float matrix[4][4],
- GLint view[4],
+ const GLint view[4],
const float v1[3],
const float v2[3],
const float v3[3],
@@ -506,7 +504,7 @@ void paint_sample_color(
unsigned int totpoly = me->totpoly;
if (CustomData_has_layer(&me_eval->ldata, CD_MLOOPUV)) {
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
view3d_operator_needs_opengl(C);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 12da8790b91..3554a6cc546 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -34,7 +34,6 @@
#include "BLI_array_utils.h"
#include "BLI_task.h"
-#include "DNA_armature_types.h"
#include "DNA_mesh_types.h"
#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
@@ -42,7 +41,6 @@
#include "DNA_object_types.h"
#include "RNA_access.h"
-#include "RNA_define.h"
#include "BKE_brush.h"
#include "BKE_context.h"
@@ -195,17 +193,12 @@ static bool vertex_paint_use_fast_update_check(Object *ob)
return false;
}
-static void paint_last_stroke_update(Scene *scene, ARegion *ar, const float mval[2])
+static void paint_last_stroke_update(Scene *scene, const float location[3])
{
- const int mval_i[2] = {mval[0], mval[1]};
- float world[3];
-
- if (ED_view3d_autodist_simple(ar, mval_i, world, 0, NULL)) {
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- ups->average_stroke_counter++;
- add_v3_v3(ups->average_stroke_accum, world);
- ups->last_stroke_valid = true;
- }
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ ups->average_stroke_counter++;
+ add_v3_v3(ups->average_stroke_accum, location);
+ ups->last_stroke_valid = true;
}
/* polling - retrieve whether cursor should be set or operator should be done */
@@ -260,7 +253,7 @@ static bool weight_paint_poll_ex(bContext *C, bool check_tool)
(BKE_paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != NULL) &&
(sa = CTX_wm_area(C)) && (sa->spacetype == SPACE_VIEW3D)) {
ARegion *ar = CTX_wm_region(C);
- if (ar->regiontype == RGN_TYPE_WINDOW) {
+ if (ELEM(ar->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_HUD)) {
if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
return 1;
}
@@ -1610,7 +1603,7 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
/* make mode data storage */
wpd = MEM_callocN(sizeof(struct WPaintData), "WPaintData");
paint_stroke_set_mode_data(stroke, wpd);
- ED_view3d_viewcontext_init(C, &wpd->vc);
+ ED_view3d_viewcontext_init(C, &wpd->vc, depsgraph);
view_angle_limits_init(&wpd->normal_angle_precalc,
vp->paint.brush->falloff_angle,
(vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
@@ -2080,9 +2073,7 @@ static void calculate_average_weight(SculptThreadedTaskData *data,
data->custom_data = accum;
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((data->sd->flags & SCULPT_USE_OPENMP) &&
- totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (data->sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings);
uint accum_len = 0;
@@ -2128,10 +2119,9 @@ static void wpaint_paint_leaves(bContext *C,
/* Use this so average can modify its weight without touching the brush. */
data.strength = BKE_brush_weight_get(scene, brush);
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
/* NOTE: current mirroring code cannot be run in parallel */
- settings.use_threading = !(me->editflag & ME_EDIT_MIRROR_X);
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, !(me->editflag & ME_EDIT_MIRROR_X), totnode);
switch ((eBrushWeightPaintTool)brush->weightpaint_tool) {
case WPAINT_TOOL_AVERAGE:
@@ -2351,7 +2341,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* calculate pivot for rotation around seletion if needed */
/* also needed for "View Selected" on last stroke */
- paint_last_stroke_update(scene, vc->ar, ss->cache->mouse);
+ paint_last_stroke_update(scene, ss->cache->location);
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
@@ -2446,7 +2436,7 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
event->type);
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
return OPERATOR_FINISHED;
}
/* add modal handler */
@@ -2655,7 +2645,7 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
/* make mode data storage */
vpd = MEM_callocN(sizeof(*vpd), "VPaintData");
paint_stroke_set_mode_data(stroke, vpd);
- ED_view3d_viewcontext_init(C, &vpd->vc);
+ ED_view3d_viewcontext_init(C, &vpd->vc, depsgraph);
view_angle_limits_init(&vpd->normal_angle_precalc,
vp->paint.brush->falloff_angle,
(vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
@@ -3142,7 +3132,7 @@ static void calculate_average_color(SculptThreadedTaskData *data,
data->custom_data = accum;
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings);
uint accum_len = 0;
@@ -3188,7 +3178,7 @@ static void vpaint_paint_leaves(bContext *C,
.me = me,
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
switch ((eBrushVertexPaintTool)brush->vertexpaint_tool) {
case VPAINT_TOOL_AVERAGE:
calculate_average_color(&data, nodes, totnode);
@@ -3331,7 +3321,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* calculate pivot for rotation around seletion if needed */
/* also needed for "View Selected" on last stroke */
- paint_last_stroke_update(scene, vc->ar, ss->cache->mouse);
+ paint_last_stroke_update(scene, ss->cache->location);
ED_region_tag_redraw(vc->ar);
@@ -3388,7 +3378,7 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
event->type);
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
index 9a6251e2f98..266c130d12a 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
@@ -272,7 +272,6 @@ static bool vertex_color_smooth(Object *ob)
{
Mesh *me;
const MPoly *mp;
-
int i, j;
bool *mlooptag;
@@ -282,6 +281,7 @@ static bool vertex_color_smooth(Object *ob)
}
const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
mlooptag = MEM_callocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
@@ -289,15 +289,19 @@ static bool vertex_color_smooth(Object *ob)
mp = me->mpoly;
for (i = 0; i < me->totpoly; i++, mp++) {
const MLoop *ml = me->mloop + mp->loopstart;
- int ml_index = mp->loopstart;
if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
continue;
}
- for (j = 0; j < mp->totloop; j++, ml_index++, ml++) {
- mlooptag[ml_index] = true;
- }
+ j = 0;
+ do {
+ if (!(use_vert_sel && !(me->mvert[ml->v].flag & SELECT))) {
+ mlooptag[mp->loopstart + j] = true;
+ }
+ ml++;
+ j++;
+ } while (j < mp->totloop);
}
/* remove stale me->mcol, will be added later */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
index 6511c90f5e1..71865d0de73 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
@@ -20,13 +20,9 @@
* Intended for use by `paint_vertex.c` & `paint_vertex_color_ops.c`.
*/
-#include "MEM_guardedalloc.h"
-
-#include "DNA_brush_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
#include "BLI_math_base.h"
#include "BLI_math_color.h"
@@ -54,29 +50,37 @@ bool ED_vpaint_color_transform(struct Object *ob,
{
Mesh *me;
const MPoly *mp;
+ int i, j;
if (((me = BKE_mesh_from_object(ob)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) {
return false;
}
const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- mp = me->mpoly;
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
- for (int i = 0; i < me->totpoly; i++, mp++) {
- MLoopCol *lcol = &me->mloopcol[mp->loopstart];
+ mp = me->mpoly;
+ for (i = 0; i < me->totpoly; i++, mp++) {
+ MLoopCol *lcol = me->mloopcol + mp->loopstart;
if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
continue;
}
- for (int j = 0; j < mp->totloop; j++, lcol++) {
- float col_mix[3];
- rgb_uchar_to_float(col_mix, &lcol->r);
+ j = 0;
+ do {
+ uint vidx = me->mloop[mp->loopstart + j].v;
+ if (!(use_vert_sel && !(me->mvert[vidx].flag & SELECT))) {
+ float col_mix[3];
+ rgb_uchar_to_float(col_mix, &lcol->r);
- vpaint_tx_fn(col_mix, user_data, col_mix);
+ vpaint_tx_fn(col_mix, user_data, col_mix);
- rgb_float_to_uchar(&lcol->r, col_mix);
- }
+ rgb_float_to_uchar(&lcol->r, col_mix);
+ }
+ lcol++;
+ j++;
+ } while (j < mp->totloop);
}
/* remove stale me->mcol, will be added later */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
index 4aa9dc8a295..f0fe2d4ebdc 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -24,13 +24,8 @@
#include "BLI_math.h"
#include "BLI_bitmap.h"
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-#include "IMB_colormanagement.h"
-
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "DNA_particle_types.h"
#include "DNA_brush_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -44,7 +39,6 @@
#include "BKE_deform.h"
#include "BKE_mesh.h"
#include "BKE_mesh_iterators.h"
-#include "BKE_mesh_mapping.h"
#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object_deform.h"
@@ -178,11 +172,12 @@ void PAINT_OT_weight_from_bones(wmOperatorType *ot)
/* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */
static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
Mesh *me;
bool changed = false;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
me = BKE_mesh_from_object(vc.obact);
if (me && me->dvert && vc.v3d && vc.rv3d && (vc.obact->actdef != 0)) {
@@ -308,10 +303,11 @@ static const EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C,
if (C) {
wmWindow *win = CTX_wm_window(C);
if (win && win->eventstate) {
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
ViewContext vc;
Mesh *me;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
me = BKE_mesh_from_object(vc.obact);
if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) {
@@ -379,8 +375,9 @@ static const EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C,
static int weight_sample_group_exec(bContext *C, wmOperator *op)
{
int type = RNA_enum_get(op->ptr, "group");
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
BLI_assert(type + 1 >= 0);
vc.obact->actdef = type + 1;
@@ -885,7 +882,7 @@ void PAINT_OT_weight_gradient(wmOperatorType *ot)
prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
+ WM_operator_properties_gesture_straightline(ot, WM_CURSOR_EDIT);
}
/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
index c71315872f6..28699b45add 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
@@ -20,16 +20,12 @@
* Intended for use by `paint_vertex.c` & `paint_vertex_weight_ops.c`.
*/
-#include "MEM_guardedalloc.h"
-
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string_utils.h"
#include "DNA_armature_types.h"
#include "DNA_mesh_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_brush_types.h"
#include "DNA_object_types.h"
#include "BKE_action.h"
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 08febfcc470..b9d621fc1fb 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -27,9 +27,11 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_dial_2d.h"
+#include "BLI_gsqueue.h"
+#include "BLI_ghash.h"
+#include "BLI_hash.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
#include "BLT_translation.h"
@@ -65,7 +67,6 @@
#include "BKE_subsurf.h"
#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -92,22 +93,18 @@
#include <stdlib.h>
#include <string.h>
-/* Sculpt PBVH abstraction API */
-
-/* Do not use these functions while working with PBVH_GRIDS data in SculptSession */
-
-/* TODO: why is this kept, should it be removed? */
-#if 0 /* UNUSED */
+/* Sculpt PBVH abstraction API
+ *
+ * This is read-only, for writing use PBVH vertex iterators. There vd.index matches
+ * the indices used here.
+ *
+ * For multires, the same vertex in multiple grids is counted multiple times, with
+ * different index for each grid. */
-static int sculpt_active_vertex_get(SculptSession *ss)
+static void sculpt_vertex_random_access_init(SculptSession *ss)
{
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- return ss->active_vertex_index;
- case PBVH_BMESH:
- return ss->active_vertex_index;
- default:
- return 0;
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ BM_mesh_elem_index_ensure(ss->bm, BM_VERT);
}
}
@@ -118,65 +115,48 @@ static int sculpt_vertex_count_get(SculptSession *ss)
return ss->totvert;
case PBVH_BMESH:
return BM_mesh_elem_count(BKE_pbvh_get_bmesh(ss->pbvh), BM_VERT);
- default:
- return 0;
+ case PBVH_GRIDS:
+ return BKE_pbvh_get_grid_num_vertices(ss->pbvh);
}
-}
-static void sculpt_vertex_normal_get(SculptSession *ss, int index, float no[3])
-{
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- normal_short_to_float_v3(no, ss->mvert[index].no);
- return;
- case PBVH_BMESH:
- copy_v3_v3(no, BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->no);
- default:
- return;
- }
+ return 0;
}
-static float *sculpt_vertex_co_get(SculptSession *ss, int index)
+const float *sculpt_vertex_co_get(SculptSession *ss, int index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
return ss->mvert[index].co;
case PBVH_BMESH:
return BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->co;
- default:
- return NULL;
- }
-}
-
-static void sculpt_vertex_co_set(SculptSession *ss, int index, float co[3])
-{
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- copy_v3_v3(ss->mvert[index].co, co);
- return;
- case PBVH_BMESH:
- copy_v3_v3(BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->co, co);
- return;
- default:
- return;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int vertex_index = index - grid_index * key->grid_area;
+ CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index];
+ return CCG_elem_co(key, CCG_elem_offset(key, elem, vertex_index));
+ }
}
+ return NULL;
}
-static void sculpt_vertex_mask_set(SculptSession *ss, int index, float mask)
+static void sculpt_vertex_normal_get(SculptSession *ss, int index, float no[3])
{
- BMVert *v;
- float *mask_p;
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- ss->vmask[index] = mask;
+ normal_short_to_float_v3(no, ss->mvert[index].no);
return;
case PBVH_BMESH:
- v = BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index);
- mask_p = BM_ELEM_CD_GET_VOID_P(v, CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK));
- *(mask_p) = mask;
- return;
- default:
- return;
+ copy_v3_v3(no, BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->no);
+ break;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int vertex_index = index - grid_index * key->grid_area;
+ CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index];
+ copy_v3_v3(no, CCG_elem_no(key, CCG_elem_offset(key, elem, vertex_index)));
+ break;
+ }
}
}
@@ -191,25 +171,44 @@ static float sculpt_vertex_mask_get(SculptSession *ss, int index)
v = BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index);
mask = BM_ELEM_CD_GET_VOID_P(v, CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK));
return *mask;
- default:
- return 0;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int vertex_index = index - grid_index * key->grid_area;
+ CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index];
+ return *CCG_elem_mask(key, CCG_elem_offset(key, elem, vertex_index));
+ }
}
+
+ return 0.0f;
}
-static void sculpt_vertex_tag_update(SculptSession *ss, int index)
+static int sculpt_active_vertex_get(SculptSession *ss)
{
+ BLI_assert(BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS);
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- ss->mvert[index].flag |= ME_VERT_PBVH_UPDATE;
- return;
+ return ss->active_vertex_index;
case PBVH_BMESH:
- return;
- default:
- return;
+ return ss->active_vertex_index;
+ case PBVH_GRIDS:
+ return ss->active_vertex_index;
}
+
+ return 0;
}
-# define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256
+static const float *sculpt_active_vertex_co_get(SculptSession *ss)
+{
+ return sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss));
+}
+
+static void sculpt_active_vertex_normal_get(SculptSession *ss, float normal[3])
+{
+ sculpt_vertex_normal_get(ss, sculpt_active_vertex_get(ss), normal);
+}
+
+#define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256
typedef struct SculptVertexNeighborIter {
int *neighbors;
@@ -286,16 +285,26 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
if (poly_get_adj_loops_from_vert(p, ss->mloop, (int)index, f_adj_v) != -1) {
int j;
for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
- if (vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2) {
- if (f_adj_v[j] != (int)index) {
- sculpt_vertex_neighbor_add(iter, f_adj_v[j]);
- }
+ if (f_adj_v[j] != (int)index) {
+ sculpt_vertex_neighbor_add(iter, f_adj_v[j]);
}
}
}
}
}
+static void sculpt_vertex_neighbors_get_grids(SculptSession *UNUSED(ss),
+ int UNUSED(index),
+ SculptVertexNeighborIter *iter)
+{
+ /* TODO: implement this for multires. It might also be worth changing this
+ * iterator to provide a coordinate and mask pointer directly for effiency,
+ * rather than converting back and forth between CCGElem and global index. */
+ iter->size = 0;
+ iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
+ iter->neighbors = iter->neighbors_fixed;
+}
+
static void sculpt_vertex_neighbors_get(SculptSession *ss,
int index,
SculptVertexNeighborIter *iter)
@@ -307,24 +316,247 @@ static void sculpt_vertex_neighbors_get(SculptSession *ss,
case PBVH_BMESH:
sculpt_vertex_neighbors_get_bmesh(ss, index, iter);
return;
- default:
- break;
+ case PBVH_GRIDS:
+ sculpt_vertex_neighbors_get_grids(ss, index, iter);
+ return;
+ }
+}
+
+#define sculpt_vertex_neighbors_iter_begin(ss, v_index, neighbor_iterator) \
+ sculpt_vertex_neighbors_get(ss, v_index, &neighbor_iterator); \
+ for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \
+ neighbor_iterator.i++) { \
+ neighbor_iterator.index = ni.neighbors[ni.i];
+
+#define sculpt_vertex_neighbors_iter_end(neighbor_iterator) \
+ } \
+ if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \
+ MEM_freeN(neighbor_iterator.neighbors); \
+ } \
+ ((void)0)
+
+/* Utils */
+static bool check_vertex_pivot_symmetry(const float vco[3], const float pco[3], const char symm)
+{
+ bool is_in_symmetry_area = true;
+ for (int i = 0; i < 3; i++) {
+ char symm_it = 1 << i;
+ if (symm & symm_it) {
+ if (pco[i] == 0.0f) {
+ if (vco[i] > 0.0f) {
+ is_in_symmetry_area = false;
+ }
+ }
+ if (vco[i] * pco[i] < 0.0f) {
+ is_in_symmetry_area = false;
+ }
+ }
}
+ return is_in_symmetry_area;
}
-# define sculpt_vertex_neighbors_iter_begin(ss, v_index, neighbor_iterator) \
- sculpt_vertex_neighbors_get(ss, v_index, &neighbor_iterator); \
- for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \
- neighbor_iterator.i++) { \
- neighbor_iterator.index = ni.neighbors[ni.i];
+typedef struct NearestVertexTLSData {
+ int nearest_vertex_index;
+ float nearest_vertex_distance_squared;
+} NearestVertexTLSData;
+
+static void do_nearest_vertex_get_task_cb(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ NearestVertexTLSData *nvtd = tls->userdata_chunk;
+ PBVHVertexIter vd;
-# define sculpt_vertex_neighbors_iter_end(neighbor_iterator) \
- } \
- if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \
- MEM_freeN(neighbor_iterator.neighbors); \
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ float distance_squared = len_squared_v3v3(vd.co, data->nearest_vertex_search_co);
+ if (distance_squared < nvtd->nearest_vertex_distance_squared &&
+ distance_squared < data->max_distance_squared) {
+ nvtd->nearest_vertex_index = vd.index;
+ nvtd->nearest_vertex_distance_squared = distance_squared;
}
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void nearest_vertex_get_finalize(void *__restrict userdata, void *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ NearestVertexTLSData *nvtd = tls;
+ if (data->nearest_vertex_index == -1) {
+ data->nearest_vertex_index = nvtd->nearest_vertex_index;
+ }
+ else if (nvtd->nearest_vertex_distance_squared < data->nearest_vertex_distance_squared) {
+ data->nearest_vertex_index = nvtd->nearest_vertex_index;
+ data->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared;
+ }
+}
+
+static int sculpt_nearest_vertex_get(
+ Sculpt *sd, Object *ob, float co[3], float max_distance, bool use_original)
+{
+ SculptSession *ss = ob->sculpt;
+ PBVHNode **nodes = NULL;
+ int totnode;
+ SculptSearchSphereData data = {
+ .ss = ss,
+ .sd = sd,
+ .radius_squared = max_distance * max_distance,
+ .original = use_original,
+ .center = co,
+ };
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
+ if (totnode == 0) {
+ return -1;
+ }
+
+ SculptThreadedTaskData task_data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .max_distance_squared = max_distance * max_distance,
+ .nearest_vertex_index = -1,
+ };
-#endif /* UNUSED */
+ copy_v3_v3(task_data.nearest_vertex_search_co, co);
+ task_data.nearest_vertex_distance_squared = FLT_MAX;
+ NearestVertexTLSData nvtd;
+ nvtd.nearest_vertex_index = -1;
+ nvtd.nearest_vertex_distance_squared = FLT_MAX;
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ settings.func_finalize = nearest_vertex_get_finalize;
+ settings.userdata_chunk = &nvtd;
+ settings.userdata_chunk_size = sizeof(NearestVertexTLSData);
+ BLI_task_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings);
+
+ MEM_SAFE_FREE(nodes);
+
+ return task_data.nearest_vertex_index;
+}
+
+static bool is_symmetry_iteration_valid(char i, char symm)
+{
+ return i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)));
+}
+
+/* Checks if a vertex is inside the brush radius from any of its mirrored axis */
+static bool sculpt_is_vertex_inside_brush_radius_symm(const float vertex[3],
+ const float br_co[3],
+ float radius,
+ char symm)
+{
+ for (char i = 0; i <= symm; ++i) {
+ if (is_symmetry_iteration_valid(i, symm)) {
+ float location[3];
+ flip_v3_v3(location, br_co, (char)i);
+ if (len_squared_v3v3(location, vertex) < radius * radius) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/* Sculpt Flood Fill API
+ *
+ * Iterate over connected vertices, starting from one or more initial vertices. */
+
+typedef struct SculptFloodFill {
+ GSQueue *queue;
+ char *visited_vertices;
+} SculptFloodFill;
+
+typedef struct SculptFloodFillIterator {
+ int v;
+ int it;
+ float edge_factor;
+} SculptFloodFillIterator;
+
+static void sculpt_floodfill_init(SculptSession *ss, SculptFloodFill *flood)
+{
+ int vertex_count = sculpt_vertex_count_get(ss);
+ sculpt_vertex_random_access_init(ss);
+
+ flood->queue = BLI_gsqueue_new(sizeof(SculptFloodFillIterator));
+ flood->visited_vertices = MEM_callocN(vertex_count * sizeof(char), "visited vertices");
+}
+
+static void sculpt_floodfill_add_initial(SculptFloodFill *flood, int index)
+{
+ SculptFloodFillIterator mevit;
+ mevit.v = index;
+ mevit.it = 0;
+ mevit.edge_factor = 1.0f;
+ BLI_gsqueue_push(flood->queue, &mevit);
+}
+
+static void sculpt_floodfill_add_active(
+ Sculpt *sd, Object *ob, SculptSession *ss, SculptFloodFill *flood, float radius)
+{
+ /* Add active vertex and symmetric vertices to the queue. */
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ for (char i = 0; i <= symm; ++i) {
+ if (is_symmetry_iteration_valid(i, symm)) {
+ int v = -1;
+ if (i == 0) {
+ v = sculpt_active_vertex_get(ss);
+ }
+ else if (radius > 0.0f) {
+ float radius_squared = (radius == FLT_MAX) ? FLT_MAX : radius * radius;
+ float location[3];
+ flip_v3_v3(location, sculpt_active_vertex_co_get(ss), i);
+ v = sculpt_nearest_vertex_get(sd, ob, location, radius_squared, false);
+ }
+ if (v != -1) {
+ sculpt_floodfill_add_initial(flood, v);
+ }
+ }
+ }
+}
+
+static void sculpt_floodfill_execute(SculptSession *ss,
+ SculptFloodFill *flood,
+ bool (*func)(SculptSession *ss,
+ const SculptFloodFillIterator *from,
+ SculptFloodFillIterator *to,
+ void *userdata),
+ void *userdata)
+{
+ /* TODO: multires support, taking into account duplicate vertices and
+ * correctly handling them in the pose, automask and mask expand callbacks. */
+ while (!BLI_gsqueue_is_empty(flood->queue)) {
+ SculptFloodFillIterator from;
+ BLI_gsqueue_pop(flood->queue, &from);
+ SculptVertexNeighborIter ni;
+ sculpt_vertex_neighbors_iter_begin(ss, from.v, ni)
+ {
+ if (flood->visited_vertices[ni.index] == 0) {
+ flood->visited_vertices[ni.index] = 1;
+
+ SculptFloodFillIterator to;
+ to.v = ni.index;
+ to.it = from.it + 1;
+ to.edge_factor = 0.0f;
+
+ if (func(ss, &from, &to, userdata)) {
+ BLI_gsqueue_push(flood->queue, &to);
+ }
+ }
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+ }
+}
+
+static void sculpt_floodfill_free(SculptFloodFill *flood)
+{
+ MEM_SAFE_FREE(flood->visited_vertices);
+ BLI_gsqueue_free(flood->queue);
+ flood->queue = NULL;
+}
/** \name Tool Capabilities
*
@@ -354,13 +586,19 @@ static bool sculpt_has_active_modifiers(Scene *scene, Object *ob)
static bool sculpt_tool_needs_original(const char sculpt_tool)
{
- return ELEM(
- sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB, SCULPT_TOOL_LAYER);
+ return ELEM(sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_LAYER,
+ SCULPT_TOOL_DRAW_SHARP,
+ SCULPT_TOOL_ELASTIC_DEFORM,
+ SCULPT_TOOL_POSE);
}
static bool sculpt_tool_is_proxy_used(const char sculpt_tool)
{
- return ELEM(sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER);
+ return ELEM(sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER, SCULPT_TOOL_POSE);
}
static bool sculpt_brush_use_topology_rake(const SculptSession *ss, const Brush *brush)
@@ -381,9 +619,11 @@ static int sculpt_brush_needs_normal(const SculptSession *ss, const Brush *brush
SCULPT_TOOL_BLOB,
SCULPT_TOOL_CREASE,
SCULPT_TOOL_DRAW,
+ SCULPT_TOOL_DRAW_SHARP,
SCULPT_TOOL_LAYER,
SCULPT_TOOL_NUDGE,
SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_ELASTIC_DEFORM,
SCULPT_TOOL_THUMB) ||
(brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)) ||
@@ -673,14 +913,10 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm &&
- totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP) && !ss->bm, totnode);
BLI_task_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings);
- if (nodes) {
- MEM_freeN(nodes);
- }
+ MEM_SAFE_FREE(nodes);
}
/*** BVH Tree ***/
@@ -748,17 +984,26 @@ void ED_sculpt_redraw_planes_get(float planes[4][4], ARegion *ar, Object *ob)
void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
{
- RegionView3D *rv3d = ss->cache->vc->rv3d;
+ RegionView3D *rv3d = ss->cache ? ss->cache->vc->rv3d : ss->rv3d;
+
+ test->radius_squared = ss->cache ? ss->cache->radius_squared :
+ ss->cursor_radius * ss->cursor_radius;
+ if (ss->cache) {
+ copy_v3_v3(test->location, ss->cache->location);
+ test->mirror_symmetry_pass = ss->cache->mirror_symmetry_pass;
+ }
+ else {
+ copy_v3_v3(test->location, ss->cursor_location);
+ test->mirror_symmetry_pass = 0;
+ }
- test->radius_squared = ss->cache->radius_squared;
- copy_v3_v3(test->location, ss->cache->location);
test->dist = 0.0f; /* just for initialize */
/* Only for 2D projection. */
zero_v4(test->plane_view);
zero_v4(test->plane_tool);
- test->mirror_symmetry_pass = ss->cache->mirror_symmetry_pass;
+ test->mirror_symmetry_pass = ss->cache ? ss->cache->mirror_symmetry_pass : 0;
if (rv3d->rflag & RV3D_CLIPPING) {
test->clip_rv3d = rv3d;
@@ -945,6 +1190,123 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test,
#endif
+/* Automasking */
+
+static bool sculpt_automasking_enabled(SculptSession *ss, const Brush *br)
+{
+ // REMOVE WITH PBVH_GRIDS
+ if (ss->pbvh && BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ return false;
+ }
+
+ if (sculpt_stroke_is_dynamic_topology(ss, br)) {
+ return false;
+ }
+ if (br->automasking_flags & BRUSH_AUTOMASKING_TOPOLOGY) {
+ return true;
+ }
+ return false;
+}
+
+static float sculpt_automasking_factor_get(SculptSession *ss, int vert)
+{
+ if (ss->cache->automask) {
+ return ss->cache->automask[vert];
+ }
+ else {
+ return 1.0f;
+ }
+}
+
+static void sculpt_automasking_end(Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ if (ss->cache && ss->cache->automask) {
+ MEM_freeN(ss->cache->automask);
+ }
+}
+
+static bool sculpt_automasking_is_constrained_by_radius(Brush *br)
+{
+ /* 2D falloff is not constrained by radius */
+ if (br->falloff_shape & BRUSH_AIRBRUSH) {
+ return false;
+ }
+
+ if (ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB)) {
+ return true;
+ }
+ return false;
+}
+
+typedef struct AutomaskFloodFillData {
+ float *automask_factor;
+ float radius;
+ bool use_radius;
+ float location[3];
+ char symm;
+} AutomaskFloodFillData;
+
+static bool automask_floodfill_cb(SculptSession *ss,
+ const SculptFloodFillIterator *UNUSED(from),
+ SculptFloodFillIterator *to,
+ void *userdata)
+{
+ AutomaskFloodFillData *data = userdata;
+
+ data->automask_factor[to->v] = 1.0f;
+ return (!data->use_radius ||
+ sculpt_is_vertex_inside_brush_radius_symm(
+ sculpt_vertex_co_get(ss, to->v), data->location, data->radius, data->symm));
+}
+
+static float *sculpt_topology_automasking_init(Sculpt *sd, Object *ob, float *automask_factor)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ if (!sculpt_automasking_enabled(ss, brush)) {
+ return NULL;
+ }
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
+ BLI_assert(!"Topology masking: pmap missing");
+ return NULL;
+ }
+
+ /* Flood fill automask to connected vertices. Limited to vertices inside
+ * the brush radius if the tool requires it */
+ SculptFloodFill flood;
+ sculpt_floodfill_init(ss, &flood);
+ sculpt_floodfill_add_active(sd, ob, ss, &flood, ss->cache->radius);
+
+ AutomaskFloodFillData fdata = {
+ .automask_factor = automask_factor,
+ .radius = ss->cache->radius,
+ .use_radius = sculpt_automasking_is_constrained_by_radius(brush),
+ .symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL,
+ };
+ copy_v3_v3(fdata.location, sculpt_active_vertex_co_get(ss));
+ sculpt_floodfill_execute(ss, &flood, automask_floodfill_cb, &fdata);
+ sculpt_floodfill_free(&flood);
+
+ return automask_factor;
+}
+
+static void sculpt_automasking_init(Sculpt *sd, Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ ss->cache->automask = MEM_callocN(sizeof(float) * sculpt_vertex_count_get(ss),
+ "automask_factor");
+
+ if (brush->automasking_flags & BRUSH_AUTOMASKING_TOPOLOGY) {
+ sculpt_vertex_random_access_init(ss);
+ sculpt_topology_automasking_init(sd, ob, ss->cache->automask);
+ }
+}
+
/* ===== Sculpting =====
*/
static void flip_v3(float v[3], const char symm)
@@ -986,7 +1348,7 @@ static float calc_radial_symmetry_feather(Sculpt *sd,
float overlap;
overlap = 0;
- for (i = 1; i < sd->radial_symm[axis - 'X']; ++i) {
+ for (i = 1; i < sd->radial_symm[axis - 'X']; i++) {
const float angle = 2 * M_PI * i / sd->radial_symm[axis - 'X'];
overlap += calc_overlap(cache, symm, axis, angle);
}
@@ -1033,24 +1395,28 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
* \note These are all _very_ similar, when changing one, check others.
* \{ */
+typedef struct AreaNormalCenterTLSData {
+ float private_co[2][3];
+ float private_no[2][3];
+ int private_count[2];
+} AreaNormalCenterTLSData;
+
static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
+ const TaskParallelTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
+ AreaNormalCenterTLSData *anctd = tls->userdata_chunk;
float(*area_nos)[3] = data->area_nos;
float(*area_cos)[3] = data->area_cos;
PBVHVertexIter vd;
SculptUndoNode *unode = NULL;
- float private_co[2][3] = {{0.0f}};
- float private_no[2][3] = {{0.0f}};
- int private_count[2] = {0};
bool use_original = false;
- if (ss->cache->original) {
+ if (ss->cache && ss->cache->original) {
unode = sculpt_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
use_original = (unode->co || unode->bm_entry);
}
@@ -1059,6 +1425,13 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ /* Update the test radius to sample the normal using the normal radius of the brush */
+ if (data->brush->ob_mode == OB_MODE_SCULPT) {
+ float test_radius = sqrtf(test.radius_squared);
+ test_radius *= data->brush->normal_radius_factor;
+ test.radius_squared = test_radius * test_radius;
+ }
+
/* when the mesh is edited we can't rely on original coords
* (original mesh may not even have verts in brush radius) */
if (use_original && data->has_bm_orco) {
@@ -1087,12 +1460,12 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
if (area_cos) {
- add_v3_v3(private_co[flip_index], co);
+ add_v3_v3(anctd->private_co[flip_index], co);
}
if (area_nos) {
- add_v3_v3(private_no[flip_index], no);
+ add_v3_v3(anctd->private_no[flip_index], no);
}
- private_count[flip_index] += 1;
+ anctd->private_count[flip_index] += 1;
}
}
}
@@ -1120,6 +1493,8 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
const float *no;
int flip_index;
+ data->any_vertex_sampled = true;
+
if (use_original) {
normal_short_to_float_v3(no_buf, no_s);
no = no_buf;
@@ -1134,38 +1509,42 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
}
}
- flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ flip_index = (dot_v3v3(ss->cache ? ss->cache->view_normal : ss->cursor_view_normal, no) <=
+ 0.0f);
if (area_cos) {
- add_v3_v3(private_co[flip_index], co);
+ add_v3_v3(anctd->private_co[flip_index], co);
}
if (area_nos) {
- add_v3_v3(private_no[flip_index], no);
+ add_v3_v3(anctd->private_no[flip_index], no);
}
- private_count[flip_index] += 1;
+ anctd->private_count[flip_index] += 1;
}
}
BKE_pbvh_vertex_iter_end;
}
+}
- BLI_mutex_lock(&data->mutex);
-
+static void calc_area_normal_and_center_finalize(void *__restrict userdata, void *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ AreaNormalCenterTLSData *anctd = tls;
+ float(*area_nos)[3] = data->area_nos;
+ float(*area_cos)[3] = data->area_cos;
/* for flatten center */
if (area_cos) {
- add_v3_v3(area_cos[0], private_co[0]);
- add_v3_v3(area_cos[1], private_co[1]);
+ add_v3_v3(area_cos[0], anctd->private_co[0]);
+ add_v3_v3(area_cos[1], anctd->private_co[1]);
}
/* for area normal */
if (area_nos) {
- add_v3_v3(area_nos[0], private_no[0]);
- add_v3_v3(area_nos[1], private_no[1]);
+ add_v3_v3(area_nos[0], anctd->private_no[0]);
+ add_v3_v3(area_nos[1], anctd->private_no[1]);
}
/* weights */
- data->count[0] += private_count[0];
- data->count[1] += private_count[1];
-
- BLI_mutex_unlock(&data->mutex);
+ data->count[0] += anctd->private_count[0];
+ data->count[1] += anctd->private_count[1];
}
static void calc_area_center(
@@ -1193,15 +1572,16 @@ static void calc_area_center(
.area_nos = NULL,
.count = count,
};
- BLI_mutex_init(&data.mutex);
+
+ AreaNormalCenterTLSData anctd = {{{0}}};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ settings.func_finalize = calc_area_normal_and_center_finalize;
+ settings.userdata_chunk = &anctd;
+ settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData);
BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
- BLI_mutex_end(&data.mutex);
-
/* for flatten center */
for (n = 0; n < ARRAY_SIZE(area_cos); n++) {
if (count[n] != 0) {
@@ -1218,12 +1598,12 @@ static void calc_area_normal(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3])
{
const Brush *brush = BKE_paint_brush(&sd->paint);
- bool use_threading = (sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT;
+ bool use_threading = (sd->flags & SCULPT_USE_OPENMP);
sculpt_pbvh_calc_area_normal(brush, ob, nodes, totnode, use_threading, r_area_no);
}
/* expose 'calc_area_normal' externally. */
-void sculpt_pbvh_calc_area_normal(const Brush *brush,
+bool sculpt_pbvh_calc_area_normal(const Brush *brush,
Object *ob,
PBVHNode **nodes,
int totnode,
@@ -1249,22 +1629,26 @@ void sculpt_pbvh_calc_area_normal(const Brush *brush,
.area_cos = NULL,
.area_nos = area_nos,
.count = count,
+ .any_vertex_sampled = false,
};
- BLI_mutex_init(&data.mutex);
+
+ AreaNormalCenterTLSData anctd = {{{0}}};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = use_threading;
+ BKE_pbvh_parallel_range_settings(&settings, use_threading, totnode);
+ settings.func_finalize = calc_area_normal_and_center_finalize;
+ settings.userdata_chunk = &anctd;
+ settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData);
BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
- BLI_mutex_end(&data.mutex);
-
/* for area normal */
for (int i = 0; i < ARRAY_SIZE(area_nos); i++) {
if (normalize_v3_v3(r_area_no, area_nos[i]) != 0.0f) {
break;
}
}
+
+ return data.any_vertex_sampled;
}
/* this calculates flatten center and area normal together,
@@ -1295,15 +1679,16 @@ static void calc_area_normal_and_center(
.area_nos = area_nos,
.count = count,
};
- BLI_mutex_init(&data.mutex);
+
+ AreaNormalCenterTLSData anctd = {{{0}}};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ settings.func_finalize = calc_area_normal_and_center_finalize;
+ settings.userdata_chunk = &anctd;
+ settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData);
BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
- BLI_mutex_end(&data.mutex);
-
/* for flatten center */
for (n = 0; n < ARRAY_SIZE(area_cos); n++) {
if (count[n] != 0) {
@@ -1353,6 +1738,7 @@ static float brush_strength(const Sculpt *sd,
case SCULPT_TOOL_CLAY:
case SCULPT_TOOL_CLAY_STRIPS:
case SCULPT_TOOL_DRAW:
+ case SCULPT_TOOL_DRAW_SHARP:
case SCULPT_TOOL_LAYER:
return alpha * flip * pressure * overlap * feather;
@@ -1418,6 +1804,10 @@ static float brush_strength(const Sculpt *sd,
case SCULPT_TOOL_ROTATE:
return alpha * pressure * feather;
+ case SCULPT_TOOL_ELASTIC_DEFORM:
+ case SCULPT_TOOL_POSE:
+ return root_alpha * feather;
+
default:
return 0;
}
@@ -1431,6 +1821,7 @@ float tex_strength(SculptSession *ss,
const short vno[3],
const float fno[3],
const float mask,
+ const int vertex_index,
const int thread_id)
{
StrokeCache *cache = ss->cache;
@@ -1501,6 +1892,9 @@ float tex_strength(SculptSession *ss,
/* Paint mask */
avg *= 1.0f - mask;
+ /* Automasking */
+ avg *= sculpt_automasking_factor_get(ss, vertex_index);
+
return avg;
}
@@ -1508,10 +1902,22 @@ float tex_strength(SculptSession *ss,
bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v)
{
SculptSearchSphereData *data = data_v;
- float *center = data->ss->cache->location, nearest[3];
+ float *center, nearest[3];
+ if (data->center) {
+ center = data->center;
+ }
+ else {
+ center = data->ss->cache ? data->ss->cache->location : data->ss->cursor_location;
+ }
float t[3], bb_min[3], bb_max[3];
int i;
+ if (data->ignore_fully_masked) {
+ if (BKE_pbvh_node_fully_masked_get(node)) {
+ return false;
+ }
+ }
+
if (data->original) {
BKE_pbvh_node_get_original_BB(node, bb_min, bb_max);
}
@@ -1519,7 +1925,7 @@ bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v)
BKE_pbvh_node_get_BB(node, bb_min, bb_max);
}
- for (i = 0; i < 3; ++i) {
+ for (i = 0; i < 3; i++) {
if (bb_min[i] > center[i]) {
nearest[i] = bb_min[i];
}
@@ -1542,6 +1948,12 @@ bool sculpt_search_circle_cb(PBVHNode *node, void *data_v)
SculptSearchCircleData *data = data_v;
float bb_min[3], bb_max[3];
+ if (data->ignore_fully_masked) {
+ if (BKE_pbvh_node_fully_masked_get(node)) {
+ return false;
+ }
+ }
+
if (data->original) {
BKE_pbvh_node_get_original_BB(node, bb_min, bb_max);
}
@@ -1561,7 +1973,7 @@ static void sculpt_clip(Sculpt *sd, SculptSession *ss, float co[3], const float
{
int i;
- for (i = 0; i < 3; ++i) {
+ for (i = 0; i < 3; i++) {
if (sd->flags & (SCULPT_LOCK_X << i)) {
continue;
}
@@ -1575,6 +1987,25 @@ static void sculpt_clip(Sculpt *sd, SculptSession *ss, float co[3], const float
}
}
+static PBVHNode **sculpt_pbvh_gather_cursor_update(Object *ob,
+ Sculpt *sd,
+ bool use_original,
+ int *r_totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ PBVHNode **nodes = NULL;
+ SculptSearchSphereData data = {
+ .ss = ss,
+ .sd = sd,
+ .radius_squared = ss->cursor_radius,
+ .original = use_original,
+ .ignore_fully_masked = false,
+ .center = NULL,
+ };
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, r_totnode);
+ return nodes;
+}
+
static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
Sculpt *sd,
const Brush *brush,
@@ -1585,13 +2016,16 @@ static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
SculptSession *ss = ob->sculpt;
PBVHNode **nodes = NULL;
- /* Build a list of all nodes that are potentially within the brush's area of influence */
+ /* Build a list of all nodes that are potentially within the cursor or brush's area of influence
+ */
if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
SculptSearchSphereData data = {
.ss = ss,
.sd = sd,
.radius_squared = SQUARE(ss->cache->radius * radius_scale),
.original = use_original,
+ .ignore_fully_masked = brush->sculpt_tool != SCULPT_TOOL_MASK,
+ .center = NULL,
};
BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, r_totnode);
}
@@ -1602,9 +2036,10 @@ static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
SculptSearchCircleData data = {
.ss = ss,
.sd = sd,
- .radius_squared = SQUARE(ss->cache->radius * radius_scale),
+ .radius_squared = ss->cache ? SQUARE(ss->cache->radius * radius_scale) : ss->cursor_radius,
.original = use_original,
.dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc,
+ .ignore_fully_masked = brush->sculpt_tool != SCULPT_TOOL_MASK,
};
BKE_pbvh_search_gather(ss->pbvh, sculpt_search_circle_cb, &data, &nodes, r_totnode);
}
@@ -1839,92 +2274,51 @@ static void bmesh_neighbor_average(float avg[3], BMVert *v)
copy_v3_v3(avg, v->co);
}
-/* For bmesh: average only the four most aligned (parallel and perpendicular) edges
- * relative to a direction. Naturally converges to a quad-like tessellation. */
+/* For bmesh: Average surrounding verts based on an orthogonality measure.
+ * Naturally converges to a quad-like structure. */
static void bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert *v)
{
- /* Logic for 3 or more is identical. */
- const int vfcount = BM_vert_face_count_at_most(v, 3);
-
- /* Don't modify corner vertices. */
- if (vfcount < 2) {
- copy_v3_v3(avg, v->co);
- return;
- }
-
- /* Project the direction to the vertex normal and create an additional
- * parallel vector. */
- float dir_a[3], dir_b[3];
- cross_v3_v3v3(dir_a, direction, v->no);
- cross_v3_v3v3(dir_b, dir_a, v->no);
-
- /* The four vectors which will be used for smoothing.
- * Occasionally less than 4 verts match the requirements in that case
- * use 'v' as fallback. */
- BMVert *pos_a = v;
- BMVert *neg_a = v;
- BMVert *pos_b = v;
- BMVert *neg_b = v;
-
- float pos_score_a = 0.0f;
- float neg_score_a = 0.0f;
- float pos_score_b = 0.0f;
- float neg_score_b = 0.0f;
-
- BMIter liter;
- BMLoop *l;
-
- BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- BMVert *adj_v[2] = {l->prev->v, l->next->v};
- for (int i = 0; i < ARRAY_SIZE(adj_v); i++) {
- BMVert *v_other = adj_v[i];
+ float avg_co[3] = {0, 0, 0};
+ float tot_co = 0;
- if (vfcount != 2 || BM_vert_face_count_at_most(v_other, 2) <= 2) {
- float vec[3];
- sub_v3_v3v3(vec, v_other->co, v->co);
- normalize_v3(vec);
+ BMIter eiter;
+ BMEdge *e;
- /* The score is a measure of how orthogonal the edge is. */
- float score = dot_v3v3(vec, dir_a);
-
- if (score >= pos_score_a) {
- pos_a = v_other;
- pos_score_a = score;
- }
- else if (score < neg_score_a) {
- neg_a = v_other;
- neg_score_a = score;
- }
- /* The same scoring but for the perpendicular direction. */
- score = dot_v3v3(vec, dir_b);
-
- if (score >= pos_score_b) {
- pos_b = v_other;
- pos_score_b = score;
- }
- else if (score < neg_score_b) {
- neg_b = v_other;
- neg_score_b = score;
- }
- }
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ if (BM_edge_is_boundary(e)) {
+ copy_v3_v3(avg, v->co);
+ return;
}
+ BMVert *v_other = (e->v1 == v) ? e->v2 : e->v1;
+ float vec[3];
+ sub_v3_v3v3(vec, v_other->co, v->co);
+ madd_v3_v3fl(vec, v->no, -dot_v3v3(vec, v->no));
+ normalize_v3(vec);
+
+ /* fac is a measure of how orthogonal or parallel the edge is
+ * relative to the direction */
+ float fac = dot_v3v3(vec, direction);
+ fac = fac * fac - 0.5f;
+ fac *= fac;
+ madd_v3_v3fl(avg_co, v_other->co, fac);
+ tot_co += fac;
}
- /* Average everything together. */
- zero_v3(avg);
- add_v3_v3(avg, pos_a->co);
- add_v3_v3(avg, neg_a->co);
- add_v3_v3(avg, pos_b->co);
- add_v3_v3(avg, neg_b->co);
- mul_v3_fl(avg, 0.25f);
+ /* In case vert has no Edge s */
+ if (tot_co > 0) {
+ mul_v3_v3fl(avg, avg_co, 1.0f / tot_co);
- /* Preserve volume. */
- float vec[3];
- sub_v3_v3(avg, v->co);
- mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no));
- sub_v3_v3(avg, vec);
- add_v3_v3(avg, v->co);
+ /* Preserve volume. */
+ float vec[3];
+ sub_v3_v3(avg, v->co);
+ mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no));
+ sub_v3_v3(avg, vec);
+ add_v3_v3(avg, v->co);
+ }
+ else {
+ zero_v3(avg);
+ }
}
/* Same logic as neighbor_average_mask(), but for bmesh rather than mesh */
@@ -1956,6 +2350,48 @@ static float bmesh_neighbor_average_mask(BMVert *v, const int cd_vert_mask_offse
}
}
+static void grids_neighbor_average(SculptSession *ss, float result[3], int index)
+{
+ float avg[3] = {0.0f, 0.0f, 0.0f};
+ int total = 0;
+
+ SculptVertexNeighborIter ni;
+ sculpt_vertex_neighbors_iter_begin(ss, index, ni)
+ {
+ add_v3_v3(avg, sculpt_vertex_co_get(ss, ni.index));
+ total++;
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+
+ if (total > 0) {
+ mul_v3_v3fl(result, avg, 1.0f / (float)total);
+ }
+ else {
+ copy_v3_v3(result, sculpt_vertex_co_get(ss, index));
+ }
+}
+
+static float grids_neighbor_average_mask(SculptSession *ss, int index)
+{
+ float avg = 0.0f;
+ int total = 0;
+
+ SculptVertexNeighborIter ni;
+ sculpt_vertex_neighbors_iter_begin(ss, index, ni)
+ {
+ avg += sculpt_vertex_mask_get(ss, ni.index);
+ total++;
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+
+ if (total > 0) {
+ return avg / (float)total;
+ }
+ else {
+ return sculpt_vertex_mask_get(ss, index);
+ }
+}
+
/* Note: uses after-struct allocated mem to store actual cache... */
typedef struct SculptDoBrushSmoothGridDataChunk {
size_t tmpgrid_size;
@@ -1964,10 +2400,14 @@ typedef struct SculptDoBrushSmoothGridDataChunk {
typedef struct {
SculptSession *ss;
const float *ray_start;
+ const float *ray_normal;
bool hit;
float depth;
bool original;
+ int active_vertex_index;
+ float *face_normal;
+
struct IsectRayPrecalc isect_precalc;
} SculptRaycastData;
@@ -2018,6 +2458,7 @@ static void do_smooth_brush_mesh_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
+ vd.index,
tls->thread_id);
if (smooth_mask) {
float val = neighbor_average_mask(ss, vd.vert_indices[vd.i]) - *vd.mask;
@@ -2073,6 +2514,7 @@ static void do_smooth_brush_bmesh_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
smooth_mask ? 0.0f : *vd.mask,
+ vd.index,
tls->thread_id);
if (smooth_mask) {
float val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask;
@@ -2115,6 +2557,7 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
mul_v3_v3fl(
tmp, ss->cache->sculpt_normal_symm, dot_v3v3(ss->cache->sculpt_normal_symm, direction));
sub_v3_v3(direction, tmp);
+ normalize_v3(direction);
/* Cancel if there's no grab data. */
if (is_zero_v3(direction)) {
@@ -2132,11 +2575,17 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade =
- bstrength *
- tex_strength(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, tls->thread_id) *
- ss->cache->pressure;
+ const float fade = bstrength *
+ tex_strength(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ *vd.mask,
+ vd.index,
+ tls->thread_id) *
+ ss->cache->pressure;
float avg[3], val[3];
@@ -2169,7 +2618,6 @@ static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata,
float bstrength = data->strength;
CCGElem **griddata, *gddata;
- CCGKey key;
float(*tmpgrid_co)[3] = NULL;
float tmprow_co[2][3];
@@ -2188,7 +2636,7 @@ static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata,
BKE_pbvh_node_get_grids(
ss->pbvh, data->nodes[n], &grid_indices, &totgrid, NULL, &gridsize, &griddata);
- BKE_pbvh_get_grid_key(ss->pbvh, &key);
+ CCGKey key = *BKE_pbvh_get_grid_key(ss->pbvh);
grid_hidden = BKE_pbvh_grid_hidden(ss->pbvh);
@@ -2280,7 +2728,7 @@ static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata,
const float fade =
bstrength *
tex_strength(
- ss, brush, co, sqrtf(test.dist), NULL, fno, strength_mask, tls->thread_id);
+ ss, brush, co, sqrtf(test.dist), NULL, fno, strength_mask, 0, tls->thread_id);
float f = 1.0f / 16.0f;
if (x == 0 || x == gridsize - 1) {
@@ -2336,7 +2784,7 @@ static void smooth(Sculpt *sd,
return;
}
- for (iteration = 0; iteration <= count; ++iteration) {
+ for (iteration = 0; iteration <= count; iteration++) {
const float strength = (iteration != count) ? 1.0f : last;
SculptThreadedTaskData data = {
@@ -2349,8 +2797,7 @@ static void smooth(Sculpt *sd,
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
switch (type) {
case PBVH_GRIDS: {
@@ -2399,7 +2846,7 @@ static void bmesh_topology_rake(
const int count = iterations * bstrength + 1;
const float factor = iterations * bstrength / count;
- for (iteration = 0; iteration <= count; ++iteration) {
+ for (iteration = 0; iteration <= count; iteration++) {
SculptThreadedTaskData data = {
.sd = sd,
@@ -2409,8 +2856,7 @@ static void bmesh_topology_rake(
.strength = factor,
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
}
@@ -2441,7 +2887,7 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
{
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = tex_strength(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, tls->thread_id);
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, tls->thread_id);
(*vd.mask) += fade * bstrength;
CLAMP(*vd.mask, 0, 1);
@@ -2467,8 +2913,7 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings);
}
@@ -2516,6 +2961,7 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -2554,11 +3000,86 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings);
}
+static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *offset = data->offset;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+ if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ /* offset vertex */
+ const float fade = tex_strength(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ tls->thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], offset, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float offset[3];
+ const float bstrength = ss->cache->bstrength;
+
+ /* offset with as much as possible factored in already */
+ mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
+ mul_v3_v3(offset, ss->cache->scale);
+ mul_v3_fl(offset, bstrength);
+
+ /* XXX - this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
+ * initialize before threads so they can do curve mapping */
+ BKE_curvemapping_initialize(brush->curve);
+
+ /* threaded loop over nodes */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .offset = offset,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
+}
+
/**
* Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB'
*/
@@ -2593,6 +3114,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
float val1[3];
float val2[3];
@@ -2670,8 +3192,7 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings);
}
@@ -2703,6 +3224,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
float val[3];
@@ -2732,8 +3254,7 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings);
}
@@ -2771,6 +3292,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
orig_data.no,
NULL,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -2804,11 +3326,613 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
}
+/* Regularized Kelvinlets: Sculpting Brushes based on Fundamental Solutions of Elasticity
+ * Pixar Technical Memo #17-03 */
+
+typedef struct KelvinletParams {
+ float f;
+ float a;
+ float b;
+ float c;
+ float radius_scaled;
+} KelvinletParams;
+
+static int sculpt_kelvinlet_get_scale_iteration_count(eBrushElasticDeformType type)
+{
+ if (type == BRUSH_ELASTIC_DEFORM_GRAB) {
+ return 1;
+ }
+ if (type == BRUSH_ELASTIC_DEFORM_GRAB_BISCALE) {
+ return 2;
+ }
+ if (type == BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE) {
+ return 3;
+ }
+ return 0;
+}
+
+static void sculpt_kelvinet_integrate(void (*kelvinlet)(float disp[3],
+ const float vertex_co[3],
+ const float location[3],
+ float normal[3],
+ KelvinletParams *p),
+ float r_disp[3],
+ const float vertex_co[3],
+ const float location[3],
+ float normal[3],
+ KelvinletParams *p)
+{
+ float k[4][3], k_it[4][3];
+ kelvinlet(k[0], vertex_co, location, normal, p);
+ copy_v3_v3(k_it[0], k[0]);
+ mul_v3_fl(k_it[0], 0.5f);
+ add_v3_v3v3(k_it[0], vertex_co, k_it[0]);
+ kelvinlet(k[1], k_it[0], location, normal, p);
+ copy_v3_v3(k_it[1], k[1]);
+ mul_v3_fl(k_it[1], 0.5f);
+ add_v3_v3v3(k_it[1], vertex_co, k_it[1]);
+ kelvinlet(k[2], k_it[1], location, normal, p);
+ copy_v3_v3(k_it[2], k[2]);
+ add_v3_v3v3(k_it[2], vertex_co, k_it[2]);
+ sub_v3_v3v3(k_it[2], k_it[2], location);
+ kelvinlet(k[3], k_it[2], location, normal, p);
+ copy_v3_v3(r_disp, k[0]);
+ madd_v3_v3fl(r_disp, k[1], 2);
+ madd_v3_v3fl(r_disp, k[2], 2);
+ add_v3_v3(r_disp, k[3]);
+ mul_v3_fl(r_disp, 1.0f / 6.0f);
+}
+
+/* Regularized Kelvinlets: Formula (16) */
+static void sculpt_kelvinlet_scale(float disp[3],
+ const float vertex_co[3],
+ const float location[3],
+ float UNUSED(normal[3]),
+ KelvinletParams *p)
+{
+ float r_v[3];
+ sub_v3_v3v3(r_v, vertex_co, location);
+ float r = len_v3(r_v);
+ float r_e = sqrtf(r * r + p->radius_scaled * p->radius_scaled);
+ float u = (2.0f * p->b - p->a) * ((1.0f / (r_e * r_e * r_e))) +
+ ((3.0f * p->radius_scaled * p->radius_scaled) / (2.0f * r_e * r_e * r_e * r_e * r_e));
+ float fade = u * p->c;
+ mul_v3_v3fl(disp, r_v, fade * p->f);
+}
+
+/* Regularized Kelvinlets: Formula (15) */
+static void sculpt_kelvinlet_twist(float disp[3],
+ const float vertex_co[3],
+ const float location[3],
+ float normal[3],
+ KelvinletParams *p)
+{
+ float r_v[3], q_r[3];
+ sub_v3_v3v3(r_v, vertex_co, location);
+ float r = len_v3(r_v);
+ float r_e = sqrtf(r * r + p->radius_scaled * p->radius_scaled);
+ float u = -p->a * ((1.0f / (r_e * r_e * r_e))) +
+ ((3.0f * p->radius_scaled * p->radius_scaled) / (2.0f * r_e * r_e * r_e * r_e * r_e));
+ float fade = u * p->c;
+ cross_v3_v3v3(q_r, normal, r_v);
+ mul_v3_v3fl(disp, q_r, fade * p->f);
+}
+
+static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *grab_delta = data->grab_delta;
+ const float *location = ss->cache->location;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+
+ const float bstrength = ss->cache->bstrength;
+
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ /* Maybe this can be exposed to the user */
+ float radius_e[3] = {1.0f, 2.0f, 2.0f};
+ float r_e[3];
+ float kvl[3];
+ float radius_scaled[3];
+
+ radius_scaled[0] = ss->cache->radius * radius_e[0];
+ radius_scaled[1] = radius_scaled[0] * radius_e[1];
+ radius_scaled[2] = radius_scaled[1] * radius_e[2];
+
+ float shear_modulus = 1.0f;
+ float poisson_ratio = brush->elastic_deform_volume_preservation;
+
+ float a = 1.0f / (4.0f * (float)M_PI * shear_modulus);
+ float b = a / (4.0f * (1.0f - poisson_ratio));
+ float c = 2 * (3.0f * a - 2.0f * b);
+
+ float dir;
+ if (ss->cache->mouse[0] > ss->cache->initial_mouse[0]) {
+ dir = 1.0f;
+ }
+ else {
+ dir = -1.0f;
+ }
+
+ if (brush->elastic_deform_type == BRUSH_ELASTIC_DEFORM_TWIST) {
+ int symm = ss->cache->mirror_symmetry_pass;
+ if (symm == 1 || symm == 2 || symm == 4 || symm == 7) {
+ dir = -dir;
+ }
+ }
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+ float fade, final_disp[3], weights[3];
+ float r = len_v3v3(location, orig_data.co);
+ KelvinletParams params;
+ params.a = a;
+ params.b = b;
+ params.c = c;
+ params.radius_scaled = radius_scaled[0];
+
+ int multi_scale_it = sculpt_kelvinlet_get_scale_iteration_count(brush->elastic_deform_type);
+ for (int it = 0; it < max_ii(1, multi_scale_it); it++) {
+ r_e[it] = sqrtf(r * r + radius_scaled[it] * radius_scaled[it]);
+ }
+
+ /* Regularized Kelvinlets: Formula (6) */
+ for (int s_it = 0; s_it < multi_scale_it; s_it++) {
+ kvl[s_it] = ((a - b) / r_e[s_it]) + ((b * r * r) / (r_e[s_it] * r_e[s_it] * r_e[s_it])) +
+ ((a * radius_scaled[s_it] * radius_scaled[s_it]) /
+ (2.0f * r_e[s_it] * r_e[s_it] * r_e[s_it]));
+ }
+
+ switch (brush->elastic_deform_type) {
+ /* Regularized Kelvinlets: Multi-scale extrapolation. Formula (11) */
+ case BRUSH_ELASTIC_DEFORM_GRAB:
+ fade = kvl[0] * c;
+ mul_v3_v3fl(final_disp, grab_delta, fade * bstrength * 20.f);
+ break;
+ case BRUSH_ELASTIC_DEFORM_GRAB_BISCALE: {
+ const float u = kvl[0] - kvl[1];
+ fade = u * c / ((1.0f / radius_scaled[0]) - (1.0f / radius_scaled[1]));
+ mul_v3_v3fl(final_disp, grab_delta, fade * bstrength * 20.0f);
+ break;
+ }
+ case BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE: {
+ weights[0] = 1.0f;
+ weights[1] = -(
+ (radius_scaled[2] * radius_scaled[2] - radius_scaled[0] * radius_scaled[0]) /
+ (radius_scaled[2] * radius_scaled[2] - radius_scaled[1] * radius_scaled[1]));
+ weights[2] = ((radius_scaled[1] * radius_scaled[1] - radius_scaled[0] * radius_scaled[0]) /
+ (radius_scaled[2] * radius_scaled[2] - radius_scaled[1] * radius_scaled[1]));
+
+ const float u = weights[0] * kvl[0] + weights[1] * kvl[1] + weights[2] * kvl[2];
+ fade = u * c /
+ (weights[0] / radius_scaled[0] + weights[1] / radius_scaled[1] +
+ weights[2] / radius_scaled[2]);
+ mul_v3_v3fl(final_disp, grab_delta, fade * bstrength * 20.0f);
+ break;
+ }
+ case BRUSH_ELASTIC_DEFORM_SCALE:
+ params.f = len_v3(grab_delta) * dir * bstrength;
+ sculpt_kelvinet_integrate(sculpt_kelvinlet_scale,
+ final_disp,
+ orig_data.co,
+ location,
+ ss->cache->sculpt_normal_symm,
+ &params);
+ break;
+ case BRUSH_ELASTIC_DEFORM_TWIST:
+ params.f = len_v3(grab_delta) * dir * bstrength;
+ sculpt_kelvinet_integrate(sculpt_kelvinlet_twist,
+ final_disp,
+ orig_data.co,
+ location,
+ ss->cache->sculpt_normal_symm,
+ &params);
+ break;
+ }
+
+ if (vd.mask) {
+ mul_v3_fl(final_disp, 1.0f - *vd.mask);
+ }
+
+ mul_v3_fl(final_disp, sculpt_automasking_factor_get(ss, vd.index));
+
+ copy_v3_v3(proxy[vd.i], final_disp);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .grab_delta = grab_delta,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
+}
+
+static void do_pose_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+
+ PBVHVertexIter vd;
+ float disp[3], val[3];
+ float final_pos[3];
+
+ SculptOrigVertData orig_data;
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+ if (check_vertex_pivot_symmetry(
+ orig_data.co, data->pose_initial_co, ss->cache->mirror_symmetry_pass)) {
+ copy_v3_v3(val, orig_data.co);
+ mul_m4_v3(data->transform_trans_inv, val);
+ mul_m4_v3(data->transform_rot, val);
+ mul_m4_v3(data->transform_trans, val);
+ sub_v3_v3v3(disp, val, orig_data.co);
+
+ mul_v3_fl(disp, ss->cache->pose_factor[vd.index]);
+ float mask = vd.mask ? *vd.mask : 0.0f;
+ mul_v3_fl(disp, 1.0f - mask);
+ add_v3_v3v3(final_pos, orig_data.co, disp);
+ copy_v3_v3(vd.co, final_pos);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3], rot_quat[4], initial_v[3], current_v[3], temp[3];
+ float pose_origin[3];
+ float pose_initial_co[3];
+ float transform_rot[4][4], transform_trans[4][4], transform_trans_inv[4][4];
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ return;
+ }
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ copy_v3_v3(pose_origin, ss->cache->pose_origin);
+ flip_v3(pose_origin, (char)ss->cache->mirror_symmetry_pass);
+
+ copy_v3_v3(pose_initial_co, ss->cache->pose_initial_co);
+ flip_v3(pose_initial_co, (char)ss->cache->mirror_symmetry_pass);
+
+ sub_v3_v3v3(initial_v, pose_initial_co, pose_origin);
+ normalize_v3(initial_v);
+
+ add_v3_v3v3(temp, pose_initial_co, grab_delta);
+ sub_v3_v3v3(current_v, temp, pose_origin);
+ normalize_v3(current_v);
+
+ rotation_between_vecs_to_quat(rot_quat, initial_v, current_v);
+ unit_m4(transform_rot);
+ unit_m4(transform_trans);
+ quat_to_mat4(transform_rot, rot_quat);
+ translate_m4(transform_trans, pose_origin[0], pose_origin[1], pose_origin[2]);
+ invert_m4_m4(transform_trans_inv, transform_trans);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .grab_delta = grab_delta,
+ .pose_origin = pose_origin,
+ .pose_initial_co = pose_initial_co,
+ .transform_rot = transform_rot,
+ .transform_trans = transform_trans,
+ .transform_trans_inv = transform_trans_inv,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings);
+}
+
+typedef struct PoseGrowFactorTLSData {
+ float pos_avg[3];
+ int tot_pos_avg;
+} PoseGrowFactorTLSData;
+
+static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ PoseGrowFactorTLSData *gftd = tls->userdata_chunk;
+ SculptSession *ss = data->ob->sculpt;
+ const char symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ const float *active_co = sculpt_active_vertex_co_get(ss);
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ SculptVertexNeighborIter ni;
+ float max = 0.0f;
+ sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
+ {
+ float vmask_f = data->prev_mask[ni.index];
+ if (vmask_f > max) {
+ max = vmask_f;
+ }
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+ if (max != data->prev_mask[vd.index]) {
+ data->pose_factor[vd.index] = max;
+ if (check_vertex_pivot_symmetry(vd.co, active_co, symm)) {
+ add_v3_v3(gftd->pos_avg, vd.co);
+ gftd->tot_pos_avg++;
+ }
+ }
+ }
+
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void pose_brush_grow_factor_finalize(void *__restrict userdata, void *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ PoseGrowFactorTLSData *gftd = tls;
+ add_v3_v3(data->tot_pos_avg, gftd->pos_avg);
+ data->tot_pos_count += gftd->tot_pos_avg;
+}
+
+/* Grow the factor until its boundary is near to the offset pose origin */
+static void sculpt_pose_grow_pose_factor(
+ Sculpt *sd, Object *ob, SculptSession *ss, float pose_origin[3], float *pose_factor)
+{
+ PBVHNode **nodes;
+ PBVH *pbvh = ob->sculpt->pbvh;
+ int totnode;
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .totnode = totnode,
+ .pose_factor = pose_factor,
+ };
+ TaskParallelSettings settings;
+ PoseGrowFactorTLSData gftd;
+ gftd.tot_pos_avg = 0;
+ zero_v3(gftd.pos_avg);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ settings.func_finalize = pose_brush_grow_factor_finalize;
+ settings.userdata_chunk = &gftd;
+ settings.userdata_chunk_size = sizeof(PoseGrowFactorTLSData);
+
+ bool grow_next_iteration = true;
+ float prev_len = FLT_MAX;
+ data.prev_mask = MEM_mallocN(sculpt_vertex_count_get(ss) * sizeof(float), "prev mask");
+ while (grow_next_iteration) {
+ zero_v3(data.tot_pos_avg);
+ data.tot_pos_count = 0;
+ zero_v3(gftd.pos_avg);
+ gftd.tot_pos_avg = 0;
+ memcpy(data.prev_mask, pose_factor, sculpt_vertex_count_get(ss) * sizeof(float));
+ BLI_task_parallel_range(0, totnode, &data, pose_brush_grow_factor_task_cb_ex, &settings);
+ if (data.tot_pos_count != 0) {
+ mul_v3_fl(data.tot_pos_avg, 1.0f / (float)data.tot_pos_count);
+ float len = len_v3v3(data.tot_pos_avg, pose_origin);
+ if (len < prev_len) {
+ prev_len = len;
+ grow_next_iteration = true;
+ }
+ else {
+ grow_next_iteration = false;
+ memcpy(pose_factor, data.prev_mask, sculpt_vertex_count_get(ss) * sizeof(float));
+ }
+ }
+ else {
+ grow_next_iteration = false;
+ }
+ }
+ MEM_freeN(data.prev_mask);
+
+ MEM_SAFE_FREE(nodes);
+}
+
+static bool sculpt_pose_brush_is_vertex_inside_brush_radius(const float vertex[3],
+ const float br_co[3],
+ float radius,
+ char symm)
+{
+ for (char i = 0; i <= symm; ++i) {
+ if (is_symmetry_iteration_valid(i, symm)) {
+ float location[3];
+ flip_v3_v3(location, br_co, (char)i);
+ if (len_v3v3(location, vertex) < radius) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/* Calculate the pose origin and (Optionaly the pose factor) that is used when using the pose brush
+ *
+ * r_pose_origin must be a valid pointer. the r_pose_factor is optional. When set to NULL it won't
+ * be calculated. */
+typedef struct PoseFloodFillData {
+ float pose_initial_co[3];
+ float radius;
+ int symm;
+
+ float *pose_factor;
+ float pose_origin[3];
+ int tot_co;
+} PoseFloodFillData;
+
+static bool pose_floodfill_cb(SculptSession *ss,
+ const SculptFloodFillIterator *UNUSED(from),
+ SculptFloodFillIterator *to,
+ void *userdata)
+{
+ PoseFloodFillData *data = userdata;
+
+ if (data->pose_factor) {
+ data->pose_factor[to->v] = 1.0f;
+ }
+
+ const float *co = sculpt_vertex_co_get(ss, to->v);
+ if (sculpt_pose_brush_is_vertex_inside_brush_radius(
+ co, data->pose_initial_co, data->radius, data->symm)) {
+ return true;
+ }
+ else if (check_vertex_pivot_symmetry(co, data->pose_initial_co, data->symm)) {
+ add_v3_v3(data->pose_origin, co);
+ data->tot_co++;
+ }
+
+ return false;
+}
+
+void sculpt_pose_calc_pose_data(Sculpt *sd,
+ Object *ob,
+ SculptSession *ss,
+ float initial_location[3],
+ float radius,
+ float pose_offset,
+ float *r_pose_origin,
+ float *r_pose_factor)
+{
+ sculpt_vertex_random_access_init(ss);
+
+ /* Calculate the pose rotation point based on the boundaries of the brush factor. */
+ SculptFloodFill flood;
+ sculpt_floodfill_init(ss, &flood);
+ sculpt_floodfill_add_active(sd, ob, ss, &flood, (r_pose_factor) ? radius : 0.0f);
+
+ PoseFloodFillData fdata = {
+ .radius = radius,
+ .symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL,
+ .pose_factor = r_pose_factor,
+ .tot_co = 0,
+ };
+ zero_v3(fdata.pose_origin);
+ copy_v3_v3(fdata.pose_initial_co, initial_location);
+ sculpt_floodfill_execute(ss, &flood, pose_floodfill_cb, &fdata);
+ sculpt_floodfill_free(&flood);
+
+ if (fdata.tot_co > 0) {
+ mul_v3_fl(fdata.pose_origin, 1.0f / (float)fdata.tot_co);
+ }
+
+ /* Offset the pose origin */
+ float pose_d[3];
+ sub_v3_v3v3(pose_d, fdata.pose_origin, fdata.pose_initial_co);
+ normalize_v3(pose_d);
+ madd_v3_v3fl(fdata.pose_origin, pose_d, radius * pose_offset);
+ copy_v3_v3(r_pose_origin, fdata.pose_origin);
+
+ if (pose_offset != 0.0f && r_pose_factor) {
+ sculpt_pose_grow_pose_factor(sd, ob, ss, fdata.pose_origin, r_pose_factor);
+ }
+}
+
+static void pose_brush_init_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ SculptVertexNeighborIter ni;
+ float avg = 0;
+ int total = 0;
+ sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
+ {
+ avg += ss->cache->pose_factor[ni.index];
+ total++;
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+
+ if (total > 0) {
+ ss->cache->pose_factor[vd.index] = avg / (float)total;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void sculpt_pose_brush_init(
+ Sculpt *sd, Object *ob, SculptSession *ss, Brush *br, float initial_location[3], float radius)
+{
+ float *pose_factor = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(float), "Pose factor");
+
+ sculpt_pose_calc_pose_data(
+ sd, ob, ss, initial_location, radius, br->pose_offset, ss->cache->pose_origin, pose_factor);
+
+ copy_v3_v3(ss->cache->pose_initial_co, initial_location);
+ ss->cache->pose_factor = pose_factor;
+
+ PBVHNode **nodes;
+ PBVH *pbvh = ob->sculpt->pbvh;
+ int totnode;
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = br,
+ .nodes = nodes,
+ };
+
+ /* Smooth the pose brush factor for cleaner deformation */
+ for (int i = 0; i < 4; i++) {
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BLI_task_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings);
+ }
+
+ MEM_SAFE_FREE(nodes);
+}
+
static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
@@ -2838,6 +3962,7 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -2871,8 +3996,7 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings);
}
@@ -2911,6 +4035,7 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -2992,8 +4117,7 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings);
}
@@ -3031,6 +4155,7 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
orig_data.no,
NULL,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -3064,8 +4189,7 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings);
}
@@ -3104,6 +4228,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
orig_data.no,
NULL,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
@@ -3137,8 +4262,7 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings);
}
@@ -3183,6 +4307,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
float *disp = &layer_disp[vd.i];
float val[3];
@@ -3234,8 +4359,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
BLI_mutex_init(&data.mutex);
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
BLI_mutex_end(&data.mutex);
@@ -3269,6 +4393,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
float val[3];
@@ -3302,8 +4427,7 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings);
}
@@ -3315,7 +4439,8 @@ static void calc_sculpt_plane(
if (ss->cache->mirror_symmetry_pass == 0 && ss->cache->radial_symmetry_pass == 0 &&
ss->cache->tile_pass == 0 &&
- (ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) {
+ (ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_PLANE) ||
+ !(brush->flag & BRUSH_ORIGINAL_NORMAL))) {
switch (brush->sculpt_plane) {
case SCULPT_DISP_DIR_VIEW:
copy_v3_v3(r_area_no, ss->cache->true_view_normal);
@@ -3352,10 +4477,20 @@ static void calc_sculpt_plane(
}
/* for area normal */
- copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
+ if ((!ss->cache->first_time) && (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
+ copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
+ }
+ else {
+ copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
+ }
/* for flatten center */
- copy_v3_v3(ss->cache->last_center, r_area_co);
+ if ((!ss->cache->first_time) && (brush->flag & BRUSH_ORIGINAL_PLANE)) {
+ copy_v3_v3(r_area_co, ss->cache->last_center);
+ }
+ else {
+ copy_v3_v3(ss->cache->last_center, r_area_co);
+ }
}
else {
/* for area normal */
@@ -3455,6 +4590,7 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -3500,8 +4636,7 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
}
@@ -3549,6 +4684,7 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -3598,8 +4734,7 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
}
@@ -3646,6 +4781,7 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -3728,8 +4864,7 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings);
}
@@ -3774,6 +4909,7 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -3821,8 +4957,7 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings);
}
@@ -3866,6 +5001,7 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -3913,8 +5049,7 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
}
@@ -3946,6 +5081,7 @@ static void do_gravity_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -3982,8 +5118,7 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings);
}
@@ -4085,7 +5220,7 @@ static void sculpt_topology_update(Sculpt *sd,
(brush->falloff_shape != PAINT_FALLOFF_SHAPE_SPHERE));
}
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
/* update average stroke position */
copy_v3_v3(location, ss->cache->true_location);
@@ -4103,20 +5238,42 @@ static void do_brush_action_task_cb(void *__restrict userdata,
data->nodes[n],
data->brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK :
SCULPT_UNDO_COORDS);
- BKE_pbvh_node_mark_update(data->nodes[n]);
+ if (data->brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ BKE_pbvh_node_mark_update_mask(data->nodes[n]);
+ }
+ else {
+ BKE_pbvh_node_mark_update(data->nodes[n]);
+ }
}
static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups)
{
SculptSession *ss = ob->sculpt;
int totnode;
+ PBVHNode **nodes;
/* Build a list of all nodes that are potentially within the brush's area of influence */
- const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
- ss->cache->original;
- const float radius_scale = 1.0f;
- PBVHNode **nodes = sculpt_pbvh_gather_generic(
- ob, sd, brush, use_original, radius_scale, &totnode);
+
+ /* These brushes need to update all nodes as they are not constrained by the brush radius */
+ if (brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) {
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+ }
+ else if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
+ float final_radius = ss->cache->radius * (1 + brush->pose_offset);
+ SculptSearchSphereData data = {
+ .ss = ss,
+ .sd = sd,
+ .radius_squared = final_radius * final_radius,
+ .original = true,
+ };
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
+ }
+ else {
+ const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
+ ss->cache->original;
+ const float radius_scale = 1.0f;
+ nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale, &totnode);
+ }
/* Only act if some verts are inside the brush area */
if (totnode) {
@@ -4130,8 +5287,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings);
if (sculpt_brush_needs_normal(ss, brush)) {
@@ -4142,6 +5298,19 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
update_brush_local_mat(sd, ob);
}
+ if (ss->cache->first_time && ss->cache->mirror_symmetry_pass == 0) {
+ if (sculpt_automasking_enabled(ss, brush)) {
+ sculpt_automasking_init(sd, ob);
+ }
+ }
+
+ if (brush->sculpt_tool == SCULPT_TOOL_POSE && ss->cache->first_time &&
+ ss->cache->mirror_symmetry_pass == 0) {
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS) {
+ sculpt_pose_brush_init(sd, ob, ss, brush, ss->cache->location, ss->cache->radius);
+ }
+ }
+
/* Apply one type of brush action */
switch (brush->sculpt_tool) {
case SCULPT_TOOL_DRAW:
@@ -4198,6 +5367,15 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
case SCULPT_TOOL_MASK:
do_mask_brush(sd, ob, nodes, totnode);
break;
+ case SCULPT_TOOL_POSE:
+ do_pose_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_DRAW_SHARP:
+ do_draw_sharp_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_ELASTIC_DEFORM:
+ do_elastic_deform_brush(sd, ob, nodes, totnode);
+ break;
}
if (!ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_MASK) &&
@@ -4219,7 +5397,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
do_gravity(sd, ob, nodes, totnode, sd->gravity_factor);
}
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
/* update average stroke position */
copy_v3_v3(location, ss->cache->true_location);
@@ -4262,8 +5440,12 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata,
Object *ob = data->ob;
/* these brushes start from original coordinates */
- const bool use_orco = ELEM(
- data->brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB);
+ const bool use_orco = ELEM(data->brush->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_ELASTIC_DEFORM,
+ SCULPT_TOOL_POSE);
PBVHVertexIter vd;
PBVHProxyNode *proxies;
@@ -4327,14 +5509,11 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings);
}
- if (nodes) {
- MEM_freeN(nodes);
- }
+ MEM_SAFE_FREE(nodes);
}
/* copy the modified vertices from bvh to the active key */
@@ -4385,12 +5564,12 @@ static void sculpt_flush_stroke_deform_task_cb(void *__restrict userdata,
}
/* flush displacement from deformed PBVH to original layer */
-static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
+static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- if (sculpt_tool_is_proxy_used(brush->sculpt_tool)) {
+ if (is_proxy_used) {
/* this brushes aren't using proxies, so sculpt_combine_proxies() wouldn't
* propagate needed deformation to original base */
@@ -4420,8 +5599,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, sculpt_flush_stroke_deform_task_cb, &settings);
if (vertCos) {
@@ -4429,7 +5607,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
MEM_freeN(vertCos);
}
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
/* Modifiers could depend on mesh normals, so we should update them/
* Note, then if sculpting happens on locked key, normals should be re-calculated
@@ -4513,7 +5691,7 @@ static void do_tiled(
float orgLoc[3]; /* position of the "prototype" stroke for tiling */
copy_v3_v3(orgLoc, cache->location);
- for (dim = 0; dim < 3; ++dim) {
+ for (dim = 0; dim < 3; dim++) {
if ((sd->paint.symmetry_flags & (PAINT_TILE_X << dim)) && step[dim] > 0) {
start[dim] = (bbMin[dim] - orgLoc[dim] - radius) / step[dim];
end[dim] = (bbMax[dim] - orgLoc[dim] + radius) / step[dim];
@@ -4529,16 +5707,16 @@ static void do_tiled(
/* now do it for all the tiles */
copy_v3_v3_int(cur, start);
- for (cur[0] = start[0]; cur[0] <= end[0]; ++cur[0]) {
- for (cur[1] = start[1]; cur[1] <= end[1]; ++cur[1]) {
- for (cur[2] = start[2]; cur[2] <= end[2]; ++cur[2]) {
+ for (cur[0] = start[0]; cur[0] <= end[0]; cur[0]++) {
+ for (cur[1] = start[1]; cur[1] <= end[1]; cur[1]++) {
+ for (cur[2] = start[2]; cur[2] <= end[2]; cur[2]++) {
if (!cur[0] && !cur[1] && !cur[2]) {
continue; /* skip tile at orgLoc, this was already handled before all others */
}
++cache->tile_pass;
- for (dim = 0; dim < 3; ++dim) {
+ for (dim = 0; dim < 3; dim++) {
cache->location[dim] = cur[dim] * step[dim] + orgLoc[dim];
cache->plane_offset[dim] = cur[dim] * step[dim];
}
@@ -4560,7 +5738,7 @@ static void do_radial_symmetry(Sculpt *sd,
SculptSession *ss = ob->sculpt;
int i;
- for (i = 1; i < sd->radial_symm[axis - 'X']; ++i) {
+ for (i = 1; i < sd->radial_symm[axis - 'X']; i++) {
const float angle = 2 * M_PI * i / sd->radial_symm[axis - 'X'];
ss->cache->radial_symmetry_pass = i;
sculpt_cache_calc_brushdata_symm(ss->cache, symm, axis, angle);
@@ -4600,7 +5778,7 @@ static void do_symmetrical_brush_actions(Sculpt *sd,
/* symm is a bit combination of XYZ -
* 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
- for (i = 0; i <= symm; ++i) {
+ for (i = 0; i <= symm; i++) {
if (i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
cache->mirror_symmetry_pass = i;
cache->radial_symmetry_pass = 0;
@@ -4703,6 +5881,12 @@ static const char *sculpt_tool_name(Sculpt *sd)
return "Mask Brush";
case SCULPT_TOOL_SIMPLIFY:
return "Simplify Brush";
+ case SCULPT_TOOL_DRAW_SHARP:
+ return "Draw Sharp Brush";
+ case SCULPT_TOOL_ELASTIC_DEFORM:
+ return "Elastic Deform Brush";
+ case SCULPT_TOOL_POSE:
+ return "Pose Brush";
}
return "Sculpting";
@@ -4717,6 +5901,9 @@ void sculpt_cache_free(StrokeCache *cache)
if (cache->dial) {
MEM_freeN(cache->dial);
}
+ if (cache->pose_factor) {
+ MEM_freeN(cache->pose_factor);
+ }
MEM_freeN(cache);
}
@@ -4732,7 +5919,7 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss)
if (mmd->flag & MOD_MIR_CLIPPING) {
/* check each axis for mirroring */
- for (i = 0; i < 3; ++i) {
+ for (i = 0; i < 3; i++) {
if (mmd->flag & (MOD_MIR_AXIS_X << i)) {
/* enable sculpt clipping */
ss->cache->flag |= CLIP_X << i;
@@ -4894,7 +6081,7 @@ static void sculpt_update_cache_invariants(
memcpy(ss->layer_co, ss->deform_cos, ss->totvert);
}
else {
- for (i = 0; i < ss->totvert; ++i) {
+ for (i = 0; i < ss->totvert; i++) {
copy_v3_v3(ss->layer_co[i], ss->mvert[i].co);
}
}
@@ -4910,12 +6097,21 @@ static void sculpt_update_cache_invariants(
/* Make copies of the mesh vertex locations and normals for some tools */
if (brush->flag & BRUSH_ANCHORED) {
- cache->original = 1;
+ cache->original = true;
+ }
+
+ /* Draw sharp does not need the original coordinates to produce the accumulate effect, so it
+ * should work the opposite way. */
+ if (brush->sculpt_tool == SCULPT_TOOL_DRAW_SHARP) {
+ cache->original = true;
}
if (SCULPT_TOOL_HAS_ACCUMULATE(brush->sculpt_tool)) {
if (!(brush->flag & BRUSH_ACCUMULATE)) {
- cache->original = 1;
+ cache->original = true;
+ if (brush->sculpt_tool == SCULPT_TOOL_DRAW_SHARP) {
+ cache->original = false;
+ }
}
}
@@ -4941,15 +6137,22 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
if (ELEM(tool,
SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ELASTIC_DEFORM,
SCULPT_TOOL_NUDGE,
SCULPT_TOOL_CLAY_STRIPS,
SCULPT_TOOL_SNAKE_HOOK,
+ SCULPT_TOOL_POSE,
SCULPT_TOOL_THUMB) ||
sculpt_brush_use_topology_rake(ss, brush)) {
float grab_location[3], imat[4][4], delta[3], loc[3];
if (cache->first_time) {
- copy_v3_v3(cache->orig_grab_location, cache->true_location);
+ if (tool == SCULPT_TOOL_GRAB && brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) {
+ copy_v3_v3(cache->orig_grab_location, sculpt_active_vertex_co_get(ss));
+ }
+ else {
+ copy_v3_v3(cache->orig_grab_location, cache->true_location);
+ }
}
else if (tool == SCULPT_TOOL_SNAKE_HOOK) {
add_v3_v3(cache->true_location, cache->grab_delta);
@@ -4963,7 +6166,9 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
if (!cache->first_time) {
switch (tool) {
case SCULPT_TOOL_GRAB:
+ case SCULPT_TOOL_POSE:
case SCULPT_TOOL_THUMB:
+ case SCULPT_TOOL_ELASTIC_DEFORM:
sub_v3_v3v3(delta, grab_location, cache->old_grab_location);
invert_m4_m4(imat, ob->obmat);
mul_mat3_m4_v3(imat, delta);
@@ -5000,13 +6205,25 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
copy_v3_v3(cache->old_grab_location, grab_location);
if (tool == SCULPT_TOOL_GRAB) {
+ if (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) {
+ copy_v3_v3(cache->anchored_location, cache->orig_grab_location);
+ }
+ else {
+ copy_v3_v3(cache->anchored_location, cache->true_location);
+ }
+ }
+ else if (tool == SCULPT_TOOL_ELASTIC_DEFORM) {
copy_v3_v3(cache->anchored_location, cache->true_location);
}
else if (tool == SCULPT_TOOL_THUMB) {
copy_v3_v3(cache->anchored_location, cache->orig_grab_location);
}
- if (ELEM(tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB)) {
+ if (ELEM(tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_ELASTIC_DEFORM,
+ SCULPT_TOOL_POSE)) {
/* location stays the same for finding vertices in brush radius */
copy_v3_v3(cache->true_location, cache->orig_grab_location);
@@ -5144,20 +6361,25 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
/* Returns true if any of the smoothing modes are active (currently
* one of smooth brush, autosmooth, mask smooth, or shift-key
* smooth) */
-static bool sculpt_any_smooth_mode(const Brush *brush, StrokeCache *cache, int stroke_mode)
+static bool sculpt_needs_conectivity_info(const Brush *brush, SculptSession *ss, int stroke_mode)
{
- return ((stroke_mode == BRUSH_STROKE_SMOOTH) || (cache && cache->alt_smooth) ||
+ if (ss && sculpt_automasking_enabled(ss, brush)) {
+ return true;
+ }
+ return ((stroke_mode == BRUSH_STROKE_SMOOTH) || (ss && ss->cache && ss->cache->alt_smooth) ||
(brush->sculpt_tool == SCULPT_TOOL_SMOOTH) || (brush->autosmooth_factor > 0) ||
- ((brush->sculpt_tool == SCULPT_TOOL_MASK) && (brush->mask_tool == BRUSH_MASK_SMOOTH)));
+ ((brush->sculpt_tool == SCULPT_TOOL_MASK) && (brush->mask_tool == BRUSH_MASK_SMOOTH)) ||
+ (brush->sculpt_tool == SCULPT_TOOL_POSE));
}
static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush)
{
SculptSession *ss = ob->sculpt;
+ View3D *v3d = CTX_wm_view3d(C);
- if (ss->kb || ss->modifiers_active) {
+ bool need_pmap = sculpt_needs_conectivity_info(brush, ss, 0);
+ if (ss->kb || ss->modifiers_active || (!BKE_sculptsession_use_pbvh_draw(ob, v3d) && need_pmap)) {
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- bool need_pmap = sculpt_any_smooth_mode(brush, ss->cache, 0);
BKE_sculpt_update_object_for_edit(depsgraph, ob, need_pmap, false);
}
}
@@ -5186,8 +6408,11 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
origco,
use_origco,
srd->ray_start,
+ srd->ray_normal,
&srd->isect_precalc,
- &srd->depth)) {
+ &srd->depth,
+ &srd->active_vertex_index,
+ srd->face_normal)) {
srd->hit = 1;
*tmin = srd->depth;
}
@@ -5275,26 +6500,147 @@ static float sculpt_raycast_init(ViewContext *vc,
return dist;
}
+/* Gets the normal, location and active vertex location of the geometry under the cursor. This also
+ * updates
+ * the active vertex and cursor related data of the SculptSession using the mouse position */
+bool sculpt_cursor_geometry_info_update(bContext *C,
+ SculptCursorGeometryInfo *out,
+ const float mouse[2],
+ bool use_sampled_normal)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Scene *scene = CTX_data_scene(C);
+ Sculpt *sd = scene->toolsettings->sculpt;
+ Object *ob;
+ SculptSession *ss;
+ ViewContext vc;
+ const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
+ float ray_start[3], ray_end[3], ray_normal[3], depth, face_normal[3], sampled_normal[3],
+ mat[3][3];
+ float viewDir[3] = {0.0f, 0.0f, 1.0f};
+ int totnode;
+ bool original = false, hit = false;
+
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
+
+ ob = vc.obact;
+ ss = ob->sculpt;
+
+ if (!ss->pbvh) {
+ zero_v3(out->location);
+ zero_v3(out->normal);
+ zero_v3(out->active_vertex_co);
+ return false;
+ }
+
+ /* PBVH raycast to get active vertex and face normal */
+ depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
+ sculpt_stroke_modifiers_check(C, ob, brush);
+
+ SculptRaycastData srd = {
+ .original = original,
+ .ss = ob->sculpt,
+ .hit = 0,
+ .ray_start = ray_start,
+ .ray_normal = ray_normal,
+ .depth = depth,
+ .face_normal = face_normal,
+ };
+ isect_ray_tri_watertight_v3_precalc(&srd.isect_precalc, ray_normal);
+ BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd, ray_start, ray_normal, srd.original);
+
+ /* Cursor is not over the mesh, return default values */
+ if (!srd.hit) {
+ zero_v3(out->location);
+ zero_v3(out->normal);
+ zero_v3(out->active_vertex_co);
+ return false;
+ }
+
+ /* Update the active vertex of the SculptSession */
+ ss->active_vertex_index = srd.active_vertex_index;
+
+ if (!ss->multires) {
+ copy_v3_v3(out->active_vertex_co, sculpt_active_vertex_co_get(ss));
+ }
+ else {
+ zero_v3(out->active_vertex_co);
+ }
+
+ copy_v3_v3(out->location, ray_normal);
+ mul_v3_fl(out->location, srd.depth);
+ add_v3_v3(out->location, ray_start);
+
+ /* Option to return the face normal directly for performance o accuracy reasons */
+ if (!use_sampled_normal) {
+ copy_v3_v3(out->normal, srd.face_normal);
+ return hit;
+ }
+
+ /* Sampled normal calculation */
+ float radius;
+
+ /* Update cursor data in SculptSession */
+ invert_m4_m4(ob->imat, ob->obmat);
+ copy_m3_m4(mat, vc.rv3d->viewinv);
+ mul_m3_v3(mat, viewDir);
+ copy_m3_m4(mat, ob->imat);
+ mul_m3_v3(mat, viewDir);
+ normalize_v3_v3(ss->cursor_view_normal, viewDir);
+ copy_v3_v3(ss->cursor_normal, srd.face_normal);
+ copy_v3_v3(ss->cursor_location, out->location);
+ ss->rv3d = vc.rv3d;
+
+ if (!BKE_brush_use_locked_size(scene, brush)) {
+ radius = paint_calc_object_space_radius(&vc, out->location, BKE_brush_size_get(scene, brush));
+ }
+ else {
+ radius = BKE_brush_unprojected_radius_get(scene, brush);
+ }
+ ss->cursor_radius = radius;
+
+ PBVHNode **nodes = sculpt_pbvh_gather_cursor_update(ob, sd, original, &totnode);
+
+ /* In case there are no nodes under the cursor, return the face normal */
+ if (!totnode) {
+ MEM_SAFE_FREE(nodes);
+ copy_v3_v3(out->normal, srd.face_normal);
+ return true;
+ }
+
+ /* Calculate the sampled normal */
+ if (sculpt_pbvh_calc_area_normal(brush, ob, nodes, totnode, true, sampled_normal)) {
+ copy_v3_v3(out->normal, sampled_normal);
+ }
+ else {
+ /* Use face normal when there are no vertices to sample inside the cursor radius */
+ copy_v3_v3(out->normal, srd.face_normal);
+ }
+ MEM_SAFE_FREE(nodes);
+ return true;
+}
+
/* Do a raycast in the tree to find the 3d brush location
* (This allows us to ignore the GL depth buffer)
* Returns 0 if the ray doesn't hit the mesh, non-zero otherwise
*/
bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob;
SculptSession *ss;
StrokeCache *cache;
- float ray_start[3], ray_end[3], ray_normal[3], depth;
+ float ray_start[3], ray_end[3], ray_normal[3], depth, face_normal[3];
bool original;
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ob = vc.obact;
ss = ob->sculpt;
cache = ss->cache;
- original = (cache) ? cache->original : 0;
+ original = (cache) ? cache->original : false;
const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
@@ -5302,14 +6648,21 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ BM_mesh_elem_table_ensure(ss->bm, BM_VERT);
+ BM_mesh_elem_index_ensure(ss->bm, BM_VERT);
+ }
+
bool hit = false;
{
SculptRaycastData srd;
srd.ss = ob->sculpt;
srd.ray_start = ray_start;
+ srd.ray_normal = ray_normal;
srd.hit = 0;
srd.depth = depth;
srd.original = original;
+ srd.face_normal = face_normal;
isect_ray_tri_watertight_v3_precalc(&srd.isect_precalc, ray_normal);
BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd, ray_start, ray_normal, srd.original);
@@ -5343,10 +6696,6 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
}
}
- if (cache && hit) {
- copy_v3_v3(cache->true_location, out);
- }
-
return hit;
}
@@ -5386,7 +6735,7 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op)
view3d_operator_needs_opengl(C);
sculpt_brush_init_tex(scene, sd, ss);
- is_smooth = sculpt_any_smooth_mode(brush, NULL, mode);
+ is_smooth = sculpt_needs_conectivity_info(brush, ss, mode);
BKE_sculpt_update_object_for_edit(depsgraph, ob, is_smooth, need_mask);
}
@@ -5397,7 +6746,8 @@ static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
/* Restore the mesh before continuing with anchored stroke */
if ((brush->flag & BRUSH_ANCHORED) ||
- (brush->sculpt_tool == SCULPT_TOOL_GRAB &&
+ ((brush->sculpt_tool == SCULPT_TOOL_GRAB ||
+ brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) &&
BKE_brush_use_size_pressure(ss->cache->vc->scene, brush)) ||
(brush->flag & BRUSH_DRAG_DOT)) {
paint_mesh_restore_co(sd, ob);
@@ -5415,7 +6765,7 @@ void sculpt_update_object_bounding_box(Object *ob)
}
}
-static void sculpt_flush_update_step(bContext *C)
+static void sculpt_flush_update_step(bContext *C, SculptUpdateType update_flags)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob = CTX_data_active_object(C);
@@ -5423,6 +6773,12 @@ static void sculpt_flush_update_step(bContext *C)
ARegion *ar = CTX_wm_region(C);
MultiresModifierData *mmd = ss->multires;
View3D *v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+
+ if (rv3d) {
+ /* Mark for faster 3D viewport redraws. */
+ rv3d->rflag |= RV3D_PAINTING;
+ }
if (mmd != NULL) {
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
@@ -5443,11 +6799,13 @@ static void sculpt_flush_update_step(bContext *C)
* only the part of the 3D viewport where changes happened. */
rcti r;
- BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB);
- /* Update the object's bounding box too so that the object
- * doesn't get incorrectly clipped during drawing in
- * draw_mesh_object(). [#33790] */
- sculpt_update_object_bounding_box(ob);
+ if (update_flags & SCULPT_UPDATE_COORDS) {
+ BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB);
+ /* Update the object's bounding box too so that the object
+ * doesn't get incorrectly clipped during drawing in
+ * draw_mesh_object(). [#33790] */
+ sculpt_update_object_bounding_box(ob);
+ }
if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) {
if (ss->cache) {
@@ -5467,16 +6825,21 @@ static void sculpt_flush_update_step(bContext *C)
}
}
-static void sculpt_flush_update_done(const bContext *C, Object *ob)
+static void sculpt_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags)
{
/* After we are done drawing the stroke, check if we need to do a more
* expensive depsgraph tag to update geometry. */
wmWindowManager *wm = CTX_wm_manager(C);
View3D *current_v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
SculptSession *ss = ob->sculpt;
Mesh *mesh = ob->data;
bool need_tag = (mesh->id.us > 1); /* Always needed for linked duplicates. */
+ if (rv3d) {
+ rv3d->rflag &= ~RV3D_PAINTING;
+ }
+
for (wmWindow *win = wm->windows.first; win; win = win->next) {
bScreen *screen = WM_window_get_active_screen(win);
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
@@ -5486,11 +6849,26 @@ static void sculpt_flush_update_done(const bContext *C, Object *ob)
if (v3d != current_v3d) {
need_tag |= !BKE_sculptsession_use_pbvh_draw(ob, v3d);
}
+
+ /* Tag all 3D viewports for redraw now that we are done. Others
+ * viewports did not get a full redraw, and anti-aliasing for the
+ * current viewport was deactivated. */
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ ED_region_tag_redraw(ar);
+ }
+ }
}
}
}
- BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateOriginalBB);
+ if (update_flags & SCULPT_UPDATE_COORDS) {
+ BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateOriginalBB);
+ }
+
+ if (update_flags & SCULPT_UPDATE_MASK) {
+ BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask);
+ }
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
BKE_pbvh_bmesh_after_stroke(ss->pbvh);
@@ -5577,7 +6955,6 @@ static void sculpt_stroke_update_step(bContext *C,
}
do_symmetrical_brush_actions(sd, ob, do_brush_action, ups);
-
sculpt_combine_proxies(sd, ob);
/* hack to fix noise texture tearing mesh */
@@ -5594,7 +6971,7 @@ static void sculpt_stroke_update_step(bContext *C,
* sculpt_flush_update_step().
*/
if (ss->modifiers_active) {
- sculpt_flush_stroke_deform(sd, ob);
+ sculpt_flush_stroke_deform(sd, ob, sculpt_tool_is_proxy_used(brush->sculpt_tool));
}
else if (ss->kb) {
sculpt_update_keyblock(ob);
@@ -5603,7 +6980,12 @@ static void sculpt_stroke_update_step(bContext *C,
ss->cache->first_time = false;
/* Cleanup */
- sculpt_flush_update_step(C);
+ if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
+ }
+ else {
+ sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS);
+ }
}
static void sculpt_brush_exit_tex(Sculpt *sd)
@@ -5647,12 +7029,21 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
}
}
+ if (sculpt_automasking_enabled(ss, brush)) {
+ sculpt_automasking_end(ob);
+ }
+
sculpt_cache_free(ss->cache);
ss->cache = NULL;
sculpt_undo_push_end();
- sculpt_flush_update_done(C, ob);
+ if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
+ }
+ else {
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
+ }
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
}
@@ -5683,12 +7074,12 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent
ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click");
if (ignore_background_click && !over_mesh(C, op, event->x, event->y)) {
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
return OPERATOR_PASS_THROUGH;
}
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
return OPERATOR_FINISHED;
}
/* add modal handler */
@@ -5817,8 +7208,19 @@ void sculpt_pbvh_clear(Object *ob)
/* Clear out any existing DM and PBVH */
if (ss->pbvh) {
BKE_pbvh_free(ss->pbvh);
+ ss->pbvh = NULL;
+ }
+
+ if (ss->pmap) {
+ MEM_freeN(ss->pmap);
+ ss->pmap = NULL;
}
- ss->pbvh = NULL;
+
+ if (ss->pmap_mem) {
+ MEM_freeN(ss->pmap_mem);
+ ss->pmap_mem = NULL;
+ }
+
BKE_object_free_derived_caches(ob);
/* Tag to rebuild PBVH in depsgraph. */
@@ -6388,13 +7790,11 @@ void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scen
const int mode_flag = OB_MODE_SCULPT;
Mesh *me = BKE_mesh_from_object(ob);
- MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
- if (mmd) {
- multires_force_update(ob);
- }
+ multires_flush_sculpt_updates(ob);
/* Not needed for now. */
#if 0
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
#endif
@@ -6539,7 +7939,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
sculpt_undo_push_end();
/* force rebuild of pbvh for better BB placement */
@@ -6580,8 +7980,9 @@ static void sample_detail(bContext *C, int mx, int my)
CTX_wm_area_set(C, sa);
CTX_wm_region_set(C, ar);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
/* Pick sample detail. */
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -6624,7 +8025,7 @@ static int sculpt_sample_detail_size_exec(bContext *C, wmOperator *op)
static int sculpt_sample_detail_size_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e))
{
ED_workspace_status_text(C, TIP_("Click on the mesh to set the detail"));
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
@@ -6740,6 +8141,1630 @@ static void SCULPT_OT_set_detail_size(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static void filter_cache_init_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ if (!vd.mask || (vd.mask && *vd.mask < 1.0f)) {
+ data->node_mask[i] = 1;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ if (data->node_mask[i] == 1) {
+ sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
+ }
+}
+
+static void sculpt_filter_cache_init(Object *ob, Sculpt *sd)
+{
+ SculptSession *ss = ob->sculpt;
+ PBVH *pbvh = ob->sculpt->pbvh;
+ PBVHNode **nodes;
+ int totnode;
+
+ ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache");
+
+ ss->filter_cache->random_seed = rand();
+
+ SculptSearchSphereData search_data = {
+ .original = true,
+ };
+ BKE_pbvh_search_gather(pbvh, NULL, &search_data, &nodes, &totnode);
+
+ int *node_mask = MEM_callocN((unsigned int)totnode * sizeof(int), "node mask");
+
+ for (int i = 0; i < totnode; i++) {
+ BKE_pbvh_node_mark_normals_update(nodes[i]);
+ }
+
+ /* mesh->runtime.subdiv_ccg is not available. Updating of the normals is done during drawing.
+ * Filters can't use normals in multires. */
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS) {
+ BKE_pbvh_update_normals(ss->pbvh, NULL);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .node_mask = node_mask,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BLI_task_parallel_range(0, totnode, &data, filter_cache_init_task_cb, &settings);
+
+ int tot_active_nodes = 0;
+ int active_node_index = 0;
+ PBVHNode **active_nodes;
+
+ /* Count number of PBVH nodes that are not fully masked */
+ for (int i = 0; i < totnode; i++) {
+ if (node_mask[i] == 1) {
+ tot_active_nodes++;
+ }
+ }
+
+ /* Create the final list of nodes that is going to be processed in the filter */
+ active_nodes = MEM_callocN(tot_active_nodes * sizeof(PBVHNode *), "active nodes");
+
+ for (int i = 0; i < totnode; i++) {
+ if (node_mask[i] == 1) {
+ active_nodes[active_node_index] = nodes[i];
+ active_node_index++;
+ }
+ }
+
+ ss->filter_cache->nodes = active_nodes;
+ ss->filter_cache->totnode = tot_active_nodes;
+
+ MEM_SAFE_FREE(nodes);
+ MEM_SAFE_FREE(node_mask);
+}
+
+static void sculpt_filter_cache_free(SculptSession *ss)
+{
+ if (ss->filter_cache->nodes) {
+ MEM_freeN(ss->filter_cache->nodes);
+ }
+ if (ss->filter_cache->mask_update_it) {
+ MEM_freeN(ss->filter_cache->mask_update_it);
+ }
+ if (ss->filter_cache->prev_mask) {
+ MEM_freeN(ss->filter_cache->prev_mask);
+ }
+ if (ss->filter_cache->normal_factor) {
+ MEM_freeN(ss->filter_cache->normal_factor);
+ }
+ MEM_freeN(ss->filter_cache);
+ ss->filter_cache = NULL;
+}
+
+typedef enum eSculptMeshFilterTypes {
+ MESH_FILTER_SMOOTH = 0,
+ MESH_FILTER_SCALE = 1,
+ MESH_FILTER_INFLATE = 2,
+ MESH_FILTER_SPHERE = 3,
+ MESH_FILTER_RANDOM = 4,
+} eSculptMeshFilterTypes;
+
+static EnumPropertyItem prop_mesh_filter_types[] = {
+ {MESH_FILTER_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth mesh"},
+ {MESH_FILTER_SCALE, "SCALE", 0, "Scale", "Scale mesh"},
+ {MESH_FILTER_INFLATE, "INFLATE", 0, "Inflate", "Inflate mesh"},
+ {MESH_FILTER_SPHERE, "SPHERE", 0, "Sphere", "Morph into sphere"},
+ {MESH_FILTER_RANDOM, "RANDOM", 0, "Random", "Randomize vertex positions"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+typedef enum eMeshFilterDeformAxis {
+ MESH_FILTER_DEFORM_X = 1 << 0,
+ MESH_FILTER_DEFORM_Y = 1 << 1,
+ MESH_FILTER_DEFORM_Z = 1 << 2,
+} eMeshFilterDeformAxis;
+
+static EnumPropertyItem prop_mesh_filter_deform_axis_items[] = {
+ {MESH_FILTER_DEFORM_X, "X", 0, "X", "Deform in the X axis"},
+ {MESH_FILTER_DEFORM_Y, "Y", 0, "Y", "Deform in the Y axis"},
+ {MESH_FILTER_DEFORM_Z, "Z", 0, "Z", "Deform in the Z axis"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static void mesh_filter_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+
+ const int filter_type = data->filter_type;
+
+ SculptOrigVertData orig_data;
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+ float orig_co[3], val[3], avg[3], normal[3], disp[3], disp2[3], transform[3][3], final_pos[3];
+ float fade = vd.mask ? *vd.mask : 0.0f;
+ fade = 1 - fade;
+ fade *= data->filter_strength;
+ copy_v3_v3(orig_co, orig_data.co);
+ switch (filter_type) {
+ case MESH_FILTER_SMOOTH:
+ CLAMP(fade, -1.0f, 1.0f);
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES:
+ neighbor_average(ss, avg, vd.index);
+ break;
+ case PBVH_BMESH:
+ bmesh_neighbor_average(avg, vd.bm_vert);
+ break;
+ case PBVH_GRIDS:
+ grids_neighbor_average(ss, avg, vd.index);
+ break;
+ }
+ sub_v3_v3v3(val, avg, orig_co);
+ madd_v3_v3v3fl(val, orig_co, val, fade);
+ sub_v3_v3v3(disp, val, orig_co);
+ break;
+ case MESH_FILTER_INFLATE:
+ normal_short_to_float_v3(normal, orig_data.no);
+ mul_v3_v3fl(disp, normal, fade);
+ break;
+ case MESH_FILTER_SCALE:
+ unit_m3(transform);
+ scale_m3_fl(transform, 1 + fade);
+ copy_v3_v3(val, orig_co);
+ mul_m3_v3(transform, val);
+ sub_v3_v3v3(disp, val, orig_co);
+ break;
+ case MESH_FILTER_SPHERE:
+ normalize_v3_v3(disp, orig_co);
+ if (fade > 0) {
+ mul_v3_v3fl(disp, disp, fade);
+ }
+ else {
+ mul_v3_v3fl(disp, disp, -fade);
+ }
+
+ unit_m3(transform);
+ if (fade > 0) {
+ scale_m3_fl(transform, 1 - fade);
+ }
+ else {
+ scale_m3_fl(transform, 1 + fade);
+ }
+ copy_v3_v3(val, orig_co);
+ mul_m3_v3(transform, val);
+ sub_v3_v3v3(disp2, val, orig_co);
+
+ mid_v3_v3v3(disp, disp, disp2);
+ break;
+ case MESH_FILTER_RANDOM: {
+ normal_short_to_float_v3(normal, orig_data.no);
+ /* Index is not unique for multires, so hash by vertex coordinates. */
+ const uint *hash_co = (const uint *)orig_co;
+ const uint hash = BLI_hash_int_2d(hash_co[0], hash_co[1]) ^
+ BLI_hash_int_2d(hash_co[2], ss->filter_cache->random_seed);
+ mul_v3_fl(normal, hash * (1.0f / (float)0xFFFFFFFF) - 0.5f);
+ mul_v3_v3fl(disp, normal, fade);
+ break;
+ }
+ }
+
+ for (int it = 0; it < 3; it++) {
+ if (!ss->filter_cache->enabled_axis[it]) {
+ disp[it] = 0.0f;
+ }
+ }
+
+ add_v3_v3v3(final_pos, orig_co, disp);
+ copy_v3_v3(vd.co, final_pos);
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ BKE_pbvh_node_mark_redraw(node);
+ BKE_pbvh_node_mark_normals_update(node);
+}
+
+static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ int filter_type = RNA_enum_get(op->ptr, "type");
+ float filter_strength = RNA_float_get(op->ptr, "strength");
+
+ if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
+ sculpt_filter_cache_free(ss);
+ sculpt_undo_push_end();
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
+ return OPERATOR_FINISHED;
+ }
+
+ if (event->type != MOUSEMOVE) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ float len = event->prevclickx - event->mval[0];
+ filter_strength = filter_strength * -len * 0.001f * UI_DPI_FAC;
+
+ sculpt_vertex_random_access_init(ss);
+
+ bool needs_pmap = (filter_type == MESH_FILTER_SMOOTH);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .filter_type = filter_type,
+ .filter_strength = filter_strength,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings);
+
+ if (ss->modifiers_active || ss->kb) {
+ sculpt_flush_stroke_deform(sd, ob, true);
+ }
+
+ sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ int filter_type = RNA_enum_get(op->ptr, "type");
+ SculptSession *ss = ob->sculpt;
+ PBVH *pbvh = ob->sculpt->pbvh;
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ return OPERATOR_CANCELLED;
+ }
+
+ int deform_axis = RNA_enum_get(op->ptr, "deform_axis");
+ if (deform_axis == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ sculpt_vertex_random_access_init(ss);
+
+ bool needs_pmap = (filter_type == MESH_FILTER_SMOOTH);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false);
+
+ if (BKE_pbvh_type(pbvh) == PBVH_FACES && needs_pmap && !ob->sculpt->pmap) {
+ return OPERATOR_CANCELLED;
+ }
+
+ sculpt_undo_push_begin("Mesh filter");
+
+ sculpt_filter_cache_init(ob, sd);
+
+ ss->filter_cache->enabled_axis[0] = deform_axis & MESH_FILTER_DEFORM_X;
+ ss->filter_cache->enabled_axis[1] = deform_axis & MESH_FILTER_DEFORM_Y;
+ ss->filter_cache->enabled_axis[2] = deform_axis & MESH_FILTER_DEFORM_Z;
+
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void SCULPT_OT_mesh_filter(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Filter mesh";
+ ot->idname = "SCULPT_OT_mesh_filter";
+ ot->description = "Applies a filter to modify the current mesh";
+
+ /* api callbacks */
+ ot->invoke = sculpt_mesh_filter_invoke;
+ ot->modal = sculpt_mesh_filter_modal;
+ ot->poll = sculpt_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* rna */
+ RNA_def_enum(ot->srna,
+ "type",
+ prop_mesh_filter_types,
+ MESH_FILTER_INFLATE,
+ "Filter type",
+ "Operation that is going to be applied to the mesh");
+ RNA_def_float(
+ ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter Strength", -10.0f, 10.0f);
+ RNA_def_enum_flag(ot->srna,
+ "deform_axis",
+ prop_mesh_filter_deform_axis_items,
+ MESH_FILTER_DEFORM_X | MESH_FILTER_DEFORM_Y | MESH_FILTER_DEFORM_Z,
+ "Deform axis",
+ "Apply the deformation in the selected axis");
+}
+
+typedef enum eSculptMaskFilterTypes {
+ MASK_FILTER_SMOOTH = 0,
+ MASK_FILTER_SHARPEN = 1,
+ MASK_FILTER_GROW = 2,
+ MASK_FILTER_SHRINK = 3,
+ MASK_FILTER_CONTRAST_INCREASE = 5,
+ MASK_FILTER_CONTRAST_DECREASE = 6,
+} eSculptMaskFilterTypes;
+
+static EnumPropertyItem prop_mask_filter_types[] = {
+ {MASK_FILTER_SMOOTH, "SMOOTH", 0, "Smooth Mask", "Smooth mask"},
+ {MASK_FILTER_SHARPEN, "SHARPEN", 0, "Sharpen Mask", "Sharpen mask"},
+ {MASK_FILTER_GROW, "GROW", 0, "Grow Mask", "Grow mask"},
+ {MASK_FILTER_SHRINK, "SHRINK", 0, "Shrink Mask", "Shrink mask"},
+ {MASK_FILTER_CONTRAST_INCREASE,
+ "CONTRAST_INCREASE",
+ 0,
+ "Increase contrast",
+ "Increase the contrast of the paint mask"},
+ {MASK_FILTER_CONTRAST_DECREASE,
+ "CONTRAST_DECREASE",
+ 0,
+ "Decrease contrast",
+ "Decrease the contrast of the paint mask"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static void mask_filter_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+ bool update = false;
+
+ const int mode = data->filter_type;
+ float contrast = 0.0f;
+
+ PBVHVertexIter vd;
+
+ if (mode == MASK_FILTER_CONTRAST_INCREASE) {
+ contrast = 0.1f;
+ }
+
+ if (mode == MASK_FILTER_CONTRAST_DECREASE) {
+ contrast = -0.1f;
+ }
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ float delta, gain, offset, max, min;
+ float prev_val = *vd.mask;
+ SculptVertexNeighborIter ni;
+ switch (mode) {
+ case MASK_FILTER_SMOOTH:
+ case MASK_FILTER_SHARPEN: {
+ float val = 0.0f;
+
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES:
+ val = neighbor_average_mask(ss, vd.index);
+ break;
+ case PBVH_BMESH:
+ val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset);
+ break;
+ case PBVH_GRIDS:
+ val = grids_neighbor_average_mask(ss, vd.index);
+ break;
+ }
+
+ val -= *vd.mask;
+
+ if (mode == MASK_FILTER_SMOOTH) {
+ *vd.mask += val;
+ }
+ else if (mode == MASK_FILTER_SHARPEN) {
+ if (*vd.mask > 0.5f) {
+ *vd.mask += 0.05f;
+ }
+ else {
+ *vd.mask -= 0.05f;
+ }
+ *vd.mask += val / 2;
+ }
+ break;
+ }
+ case MASK_FILTER_GROW:
+ max = 0.0f;
+ sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
+ {
+ float vmask_f = data->prev_mask[ni.index];
+ if (vmask_f > max) {
+ max = vmask_f;
+ }
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+ *vd.mask = max;
+ break;
+ case MASK_FILTER_SHRINK:
+ min = 1.0f;
+ sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
+ {
+ float vmask_f = data->prev_mask[ni.index];
+ if (vmask_f < min) {
+ min = vmask_f;
+ }
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+ *vd.mask = min;
+ break;
+ case MASK_FILTER_CONTRAST_INCREASE:
+ case MASK_FILTER_CONTRAST_DECREASE:
+ delta = contrast / 2.0f;
+ gain = 1.0f - delta * 2.0f;
+ if (contrast > 0) {
+ gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON);
+ offset = gain * (-delta);
+ }
+ else {
+ delta *= -1;
+ offset = gain * (delta);
+ }
+ *vd.mask = gain * (*vd.mask) + offset;
+ break;
+ }
+ CLAMP(*vd.mask, 0.0f, 1.0f);
+ if (*vd.mask != prev_val) {
+ update = true;
+ }
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ if (update) {
+ BKE_pbvh_node_mark_update_mask(node);
+ }
+}
+
+static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
+{
+ ARegion *ar = CTX_wm_region(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ PBVH *pbvh = ob->sculpt->pbvh;
+ PBVHNode **nodes;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ int totnode;
+ int filter_type = RNA_enum_get(op->ptr, "filter_type");
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ sculpt_vertex_random_access_init(ss);
+
+ if (!ob->sculpt->pmap) {
+ return OPERATOR_CANCELLED;
+ }
+
+ int num_verts = sculpt_vertex_count_get(ss);
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+ sculpt_undo_push_begin("Mask filter");
+
+ for (int i = 0; i < totnode; i++) {
+ sculpt_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
+ }
+
+ float *prev_mask = NULL;
+ int iterations = RNA_int_get(op->ptr, "iterations");
+
+ /* Auto iteration count calculates the number of iteration based on the vertices of the mesh to
+ * avoid adding an unnecessary amount of undo steps when using the operator from a shortcut.
+ * One iteration per 50000 vertices in the mesh should be fine in most cases.
+ * Maybe we want this to be configurable. */
+ if (RNA_boolean_get(op->ptr, "auto_iteration_count")) {
+ iterations = (int)(num_verts / 50000.0f) + 1;
+ }
+
+ for (int i = 0; i < iterations; i++) {
+ if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) {
+ prev_mask = MEM_mallocN(num_verts * sizeof(float), "prevmask");
+ for (int j = 0; j < num_verts; j++) {
+ prev_mask[j] = sculpt_vertex_mask_get(ss, j);
+ }
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .filter_type = filter_type,
+ .prev_mask = prev_mask,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BLI_task_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings);
+
+ if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) {
+ MEM_freeN(prev_mask);
+ }
+ }
+
+ MEM_SAFE_FREE(nodes);
+
+ sculpt_undo_push_end();
+
+ ED_region_tag_redraw(ar);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_mask_filter(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Mask Filter";
+ ot->idname = "SCULPT_OT_mask_filter";
+ ot->description = "Applies a filter to modify the current mask";
+
+ /* api callbacks */
+ ot->exec = sculpt_mask_filter_exec;
+ ot->poll = sculpt_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER;
+
+ /* rna */
+ RNA_def_enum(ot->srna,
+ "filter_type",
+ prop_mask_filter_types,
+ MASK_FILTER_SMOOTH,
+ "Type",
+ "Filter that is going to be applied to the mask");
+ RNA_def_int(ot->srna,
+ "iterations",
+ 1,
+ 1,
+ 100,
+ "Iterations",
+ "Number of times that the filter is going to be applied",
+ 1,
+ 100);
+ RNA_def_boolean(
+ ot->srna,
+ "auto_iteration_count",
+ false,
+ "Auto Iteration Count",
+ "Use a automatic number of iterations based on the number of vertices of the sculpt");
+}
+
+static float neighbor_dirty_mask(SculptSession *ss, PBVHVertexIter *vd)
+{
+ int total = 0;
+ float avg[3];
+ zero_v3(avg);
+
+ SculptVertexNeighborIter ni;
+ sculpt_vertex_neighbors_iter_begin(ss, vd->index, ni)
+ {
+ float normalized[3];
+ sub_v3_v3v3(normalized, sculpt_vertex_co_get(ss, ni.index), vd->co);
+ normalize_v3(normalized);
+ add_v3_v3(avg, normalized);
+ total++;
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ float normal[3];
+ if (vd->no) {
+ normal_short_to_float_v3(normal, vd->no);
+ }
+ else {
+ copy_v3_v3(normal, vd->fno);
+ }
+ float dot = dot_v3v3(avg, normal);
+ float angle = max_ff(saacosf(dot), 0.0f);
+ return angle;
+ }
+ return 0;
+}
+
+typedef struct DirtyMaskRangeData {
+ float min, max;
+} DirtyMaskRangeData;
+
+static void dirty_mask_compute_range_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+ DirtyMaskRangeData *range = tls->userdata_chunk;
+ PBVHVertexIter vd;
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ float dirty_mask = neighbor_dirty_mask(ss, &vd);
+ range->min = min_ff(dirty_mask, range->min);
+ range->max = max_ff(dirty_mask, range->max);
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void dirty_mask_compute_range_finalize(void *__restrict userdata, void *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ DirtyMaskRangeData *range = tls;
+
+ data->dirty_mask_min = min_ff(range->min, data->dirty_mask_min);
+ data->dirty_mask_max = max_ff(range->max, data->dirty_mask_max);
+}
+
+static void dirty_mask_apply_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+ PBVHVertexIter vd;
+
+ const bool dirty_only = data->dirty_mask_dirty_only;
+ const float min = data->dirty_mask_min;
+ const float max = data->dirty_mask_max;
+
+ float range = max - min;
+ if (range < 0.0001f) {
+ range = 0;
+ }
+ else {
+ range = 1.0f / range;
+ }
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ float dirty_mask = neighbor_dirty_mask(ss, &vd);
+ float mask = *vd.mask + (1 - ((dirty_mask - min) * range));
+ if (dirty_only) {
+ mask = fminf(mask, 0.5f) * 2.0f;
+ }
+ *vd.mask = CLAMPIS(mask, 0.0f, 1.0f);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ BKE_pbvh_node_mark_update_mask(node);
+}
+
+static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op)
+{
+ ARegion *ar = CTX_wm_region(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ PBVH *pbvh = ob->sculpt->pbvh;
+ PBVHNode **nodes;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ int totnode;
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ sculpt_vertex_random_access_init(ss);
+
+ if (!ob->sculpt->pmap) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+ sculpt_undo_push_begin("Dirty Mask");
+
+ for (int i = 0; i < totnode; i++) {
+ sculpt_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .dirty_mask_min = FLT_MAX,
+ .dirty_mask_max = -FLT_MAX,
+ .dirty_mask_dirty_only = RNA_boolean_get(op->ptr, "dirty_only"),
+ };
+ DirtyMaskRangeData range = {
+ .min = FLT_MAX,
+ .max = -FLT_MAX,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+
+ settings.func_finalize = dirty_mask_compute_range_finalize;
+ settings.userdata_chunk = &range;
+ settings.userdata_chunk_size = sizeof(DirtyMaskRangeData);
+
+ BLI_task_parallel_range(0, totnode, &data, dirty_mask_compute_range_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, dirty_mask_apply_task_cb, &settings);
+
+ MEM_SAFE_FREE(nodes);
+
+ BKE_pbvh_update_vertex_data(pbvh, SCULPT_UPDATE_MASK);
+
+ sculpt_undo_push_end();
+
+ ED_region_tag_redraw(ar);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_dirty_mask(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Dirty Mask";
+ ot->idname = "SCULPT_OT_dirty_mask";
+ ot->description = "Generates a mask based on the geometry cavity and pointiness";
+
+ /* api callbacks */
+ ot->exec = sculpt_dirty_mask_exec;
+ ot->poll = sculpt_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER;
+
+ /* rna */
+ RNA_def_boolean(
+ ot->srna, "dirty_only", false, "Dirty Only", "Don't calculate cleans for convex areas");
+}
+
+static void sculpt_mask_expand_cancel(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ MEM_freeN(op->customdata);
+
+ for (int n = 0; n < ss->filter_cache->totnode; n++) {
+ PBVHNode *node = ss->filter_cache->nodes[n];
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ *vd.mask = ss->filter_cache->prev_mask[vd.index];
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ BKE_pbvh_node_mark_redraw(node);
+ }
+
+ sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
+ sculpt_filter_cache_free(ss);
+ sculpt_undo_push_end();
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
+ ED_workspace_status_text(C, NULL);
+}
+
+static void sculpt_expand_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+ PBVHVertexIter vd;
+ int update_it = data->mask_expand_update_it;
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
+ {
+ int vi = vd.index;
+ float final_mask = *vd.mask;
+ if (data->mask_expand_use_normals) {
+ if (ss->filter_cache->normal_factor[sculpt_active_vertex_get(ss)] <
+ ss->filter_cache->normal_factor[vd.index]) {
+ final_mask = 1.0f;
+ }
+ else {
+ final_mask = 0.0f;
+ }
+ }
+ else {
+ if (ss->filter_cache->mask_update_it[vi] <= update_it &&
+ ss->filter_cache->mask_update_it[vi] != 0) {
+ final_mask = 1.0f;
+ }
+ else {
+ final_mask = 0.0f;
+ }
+ }
+
+ if (data->mask_expand_keep_prev_mask) {
+ final_mask = MAX2(ss->filter_cache->prev_mask[vd.index], final_mask);
+ }
+
+ if (data->mask_expand_invert_mask) {
+ final_mask = 1.0f - final_mask;
+ }
+
+ if (*vd.mask != final_mask) {
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ *vd.mask = final_mask;
+ BKE_pbvh_node_mark_update_mask(node);
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ float prevclick_f[2];
+ copy_v2_v2(prevclick_f, op->customdata);
+ int prevclick[2] = {(int)prevclick_f[0], (int)prevclick_f[1]};
+ int len = (int)len_v2v2_int(prevclick, event->mval);
+ len = ABS(len);
+ int mask_speed = RNA_int_get(op->ptr, "mask_speed");
+ int mask_expand_update_it = len / mask_speed;
+ mask_expand_update_it = mask_expand_update_it + 1;
+
+ if (RNA_boolean_get(op->ptr, "use_cursor")) {
+ SculptCursorGeometryInfo sgi;
+ float mouse[2];
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+ sculpt_cursor_geometry_info_update(C, &sgi, mouse, false);
+ mask_expand_update_it = ss->filter_cache->mask_update_it[(int)sculpt_active_vertex_get(ss)];
+ }
+
+ if ((event->type == ESCKEY && event->val == KM_PRESS) ||
+ (event->type == RIGHTMOUSE && event->val == KM_PRESS)) {
+ /* Returning OPERATOR_CANCELLED will leak memory due to not finishing
+ * undo. Better solution could be to make paint_mesh_restore_co work
+ * for this case. */
+ sculpt_mask_expand_cancel(C, op);
+ return OPERATOR_FINISHED;
+ }
+
+ if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) ||
+ (event->type == RETKEY && event->val == KM_PRESS) ||
+ (event->type == PADENTER && event->val == KM_PRESS)) {
+
+ /* Smooth iterations */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .filter_type = MASK_FILTER_SMOOTH,
+ };
+
+ int smooth_iterations = RNA_int_get(op->ptr, "smooth_iterations");
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false);
+ for (int i = 0; i < smooth_iterations; i++) {
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mask_filter_task_cb, &settings);
+ }
+
+ /* Pivot position */
+ if (RNA_boolean_get(op->ptr, "update_pivot")) {
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ const float threshold = 0.2f;
+ float avg[3];
+ int total = 0;
+ zero_v3(avg);
+
+ for (int n = 0; n < ss->filter_cache->totnode; n++) {
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, ss->filter_cache->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float mask = (vd.mask) ? *vd.mask : 0.0f;
+ if (mask < (0.5f + threshold) && mask > (0.5f - threshold)) {
+ if (check_vertex_pivot_symmetry(
+ vd.co, ss->filter_cache->mask_expand_initial_co, symm)) {
+ add_v3_v3(avg, vd.co);
+ total++;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ copy_v3_v3(ss->pivot_pos, avg);
+ }
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
+ }
+
+ MEM_freeN(op->customdata);
+
+ for (int i = 0; i < ss->filter_cache->totnode; i++) {
+ BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
+ }
+
+ sculpt_filter_cache_free(ss);
+
+ sculpt_undo_push_end();
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
+ ED_workspace_status_text(C, NULL);
+ return OPERATOR_FINISHED;
+ }
+
+ if (event->type != MOUSEMOVE) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ if (mask_expand_update_it == ss->filter_cache->mask_update_current_it) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ if (mask_expand_update_it < ss->filter_cache->mask_update_last_it) {
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .mask_expand_update_it = mask_expand_update_it,
+ .mask_expand_use_normals = RNA_boolean_get(op->ptr, "use_normals"),
+ .mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"),
+ .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"),
+ };
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
+ ss->filter_cache->mask_update_current_it = mask_expand_update_it;
+ }
+
+ sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+typedef struct MaskExpandFloodFillData {
+ float original_normal[3];
+ float edge_sensitivity;
+ bool use_normals;
+} MaskExpandFloodFillData;
+
+static bool mask_expand_floodfill_cb(SculptSession *ss,
+ const SculptFloodFillIterator *from,
+ SculptFloodFillIterator *to,
+ void *userdata)
+{
+ MaskExpandFloodFillData *data = userdata;
+
+ ss->filter_cache->mask_update_it[to->v] = to->it;
+ if (to->it > ss->filter_cache->mask_update_last_it) {
+ ss->filter_cache->mask_update_last_it = to->it;
+ }
+
+ if (data->use_normals) {
+ float current_normal[3], prev_normal[3];
+ sculpt_vertex_normal_get(ss, to->v, current_normal);
+ sculpt_vertex_normal_get(ss, from->v, prev_normal);
+ to->edge_factor = dot_v3v3(current_normal, prev_normal) * from->edge_factor;
+ ss->filter_cache->normal_factor[to->v] = dot_v3v3(data->original_normal, current_normal) *
+ powf(from->edge_factor, data->edge_sensitivity);
+ CLAMP(ss->filter_cache->normal_factor[to->v], 0.0f, 1.0f);
+ }
+
+ return true;
+}
+
+static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ PBVH *pbvh = ob->sculpt->pbvh;
+
+ bool use_normals = RNA_boolean_get(op->ptr, "use_normals");
+
+ SculptCursorGeometryInfo sgi;
+ float mouse[2];
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ return OPERATOR_CANCELLED;
+ }
+
+ sculpt_vertex_random_access_init(ss);
+
+ op->customdata = MEM_mallocN(2 * sizeof(float), "initial mouse position");
+ copy_v2_v2(op->customdata, mouse);
+
+ sculpt_cursor_geometry_info_update(C, &sgi, mouse, false);
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ int vertex_count = sculpt_vertex_count_get(ss);
+
+ ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache");
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &ss->filter_cache->nodes, &ss->filter_cache->totnode);
+
+ sculpt_undo_push_begin("Mask Expand");
+
+ for (int i = 0; i < ss->filter_cache->totnode; i++) {
+ sculpt_undo_push_node(ob, ss->filter_cache->nodes[i], SCULPT_UNDO_MASK);
+ BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
+ }
+
+ ss->filter_cache->mask_update_it = MEM_callocN(sizeof(int) * vertex_count,
+ "mask update iteration");
+ if (use_normals) {
+ ss->filter_cache->normal_factor = MEM_callocN(sizeof(float) * vertex_count,
+ "mask update normal factor");
+ }
+
+ ss->filter_cache->prev_mask = MEM_callocN(sizeof(float) * vertex_count, "prev mask");
+ for (int i = 0; i < vertex_count; i++) {
+ ss->filter_cache->prev_mask[i] = sculpt_vertex_mask_get(ss, i);
+ }
+
+ ss->filter_cache->mask_update_last_it = 1;
+ ss->filter_cache->mask_update_current_it = 1;
+ ss->filter_cache->mask_update_it[sculpt_active_vertex_get(ss)] = 1;
+
+ copy_v3_v3(ss->filter_cache->mask_expand_initial_co, sculpt_active_vertex_co_get(ss));
+
+ SculptFloodFill flood;
+ sculpt_floodfill_init(ss, &flood);
+ sculpt_floodfill_add_active(sd, ob, ss, &flood, FLT_MAX);
+
+ MaskExpandFloodFillData fdata = {
+ .use_normals = use_normals,
+ .edge_sensitivity = RNA_int_get(op->ptr, "edge_sensitivity"),
+ };
+ sculpt_active_vertex_normal_get(ss, fdata.original_normal);
+ sculpt_floodfill_execute(ss, &flood, mask_expand_floodfill_cb, &fdata);
+ sculpt_floodfill_free(&flood);
+
+ if (use_normals) {
+ for (int repeat = 0; repeat < 2; repeat++) {
+ for (int i = 0; i < vertex_count; i++) {
+ float avg = 0;
+ SculptVertexNeighborIter ni;
+ sculpt_vertex_neighbors_iter_begin(ss, i, ni)
+ {
+ avg += ss->filter_cache->normal_factor[ni.index];
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+ ss->filter_cache->normal_factor[i] = avg / ni.size;
+ }
+ }
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .mask_expand_update_it = 0,
+ .mask_expand_use_normals = RNA_boolean_get(op->ptr, "use_normals"),
+ .mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"),
+ .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"),
+ };
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
+
+ const char *status_str = TIP_(
+ "Move the mouse to expand the mask from the active vertex. LBM: confirm mask, ESC/RMB: "
+ "cancel");
+ ED_workspace_status_text(C, status_str);
+
+ sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void SCULPT_OT_mask_expand(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Mask Expand";
+ ot->idname = "SCULPT_OT_mask_expand";
+ ot->description = "Expands a mask from the initial active vertex under the cursor";
+
+ /* api callbacks */
+ ot->invoke = sculpt_mask_expand_invoke;
+ ot->modal = sculpt_mask_expand_modal;
+ ot->cancel = sculpt_mask_expand_cancel;
+ ot->poll = sculpt_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->prop = RNA_def_boolean(ot->srna, "invert", true, "Invert", "Invert the new mask");
+ ot->prop = RNA_def_boolean(
+ ot->srna, "use_cursor", true, "Use Cursor", "Expand the mask to the cursor position");
+ ot->prop = RNA_def_boolean(ot->srna,
+ "update_pivot",
+ true,
+ "Update Pivot Position",
+ "Set the pivot position to the mask border after creating the mask");
+ ot->prop = RNA_def_int(ot->srna, "smooth_iterations", 2, 0, 10, "Smooth iterations", "", 0, 10);
+ ot->prop = RNA_def_int(ot->srna, "mask_speed", 5, 1, 10, "Mask speed", "", 1, 10);
+
+ ot->prop = RNA_def_boolean(ot->srna,
+ "use_normals",
+ true,
+ "Use Normals",
+ "Generate the mask using the normals and curvature of the model");
+ ot->prop = RNA_def_boolean(ot->srna,
+ "keep_previous_mask",
+ false,
+ "Keep Previous Mask",
+ "Generate the new mask on top of the current one");
+ ot->prop = RNA_def_int(ot->srna,
+ "edge_sensitivity",
+ 300,
+ 0,
+ 2000,
+ "Edge Detection Sensitivity",
+ "Sensitivity for expanding the mask across sculpted sharp edges when "
+ "using normals to generate the mask",
+ 0,
+ 2000);
+}
+
+void sculpt_geometry_preview_lines_update(bContext *C, SculptSession *ss, float radius)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+
+ ss->preview_vert_index_count = 0;
+ int totpoints = 0;
+
+ /* This function is called from the cursor drawing code, so the PBVH may not be build yet */
+ if (!ss->pbvh) {
+ return;
+ }
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ if (!ss->pmap) {
+ return;
+ }
+
+ float brush_co[3];
+ copy_v3_v3(brush_co, sculpt_active_vertex_co_get(ss));
+
+ char *visited_vertices = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(char),
+ "visited vertices");
+
+ /* Assuming an average of 6 edges per vertex in a triangulated mesh */
+ const int max_preview_vertices = sculpt_vertex_count_get(ss) * 3 * 2;
+
+ if (ss->preview_vert_index_list == NULL) {
+ ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines");
+ }
+
+ GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int));
+ int active_v = sculpt_active_vertex_get(ss);
+ BLI_gsqueue_push(not_visited_vertices, &active_v);
+
+ while (!BLI_gsqueue_is_empty(not_visited_vertices)) {
+ int from_v;
+ BLI_gsqueue_pop(not_visited_vertices, &from_v);
+ SculptVertexNeighborIter ni;
+ sculpt_vertex_neighbors_iter_begin(ss, from_v, ni)
+ {
+ if (totpoints + (ni.size * 2) < max_preview_vertices) {
+ int to_v = ni.index;
+ ss->preview_vert_index_list[totpoints] = from_v;
+ totpoints++;
+ ss->preview_vert_index_list[totpoints] = to_v;
+ totpoints++;
+ if (visited_vertices[to_v] == 0) {
+ visited_vertices[to_v] = 1;
+ const float *co = sculpt_vertex_co_get(ss, to_v);
+ if (len_squared_v3v3(brush_co, co) < radius * radius) {
+ BLI_gsqueue_push(not_visited_vertices, &to_v);
+ }
+ }
+ }
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+ }
+
+ BLI_gsqueue_free(not_visited_vertices);
+
+ MEM_freeN(visited_vertices);
+
+ ss->preview_vert_index_count = totpoints;
+}
+void ED_sculpt_init_transform(struct bContext *C)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+
+ copy_v3_v3(ss->init_pivot_pos, ss->pivot_pos);
+ copy_v4_v4(ss->init_pivot_rot, ss->pivot_rot);
+
+ sculpt_undo_push_begin("Transform");
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false);
+
+ ss->pivot_rot[3] = 1.0f;
+
+ sculpt_vertex_random_access_init(ss);
+ sculpt_filter_cache_init(ob, sd);
+}
+
+typedef enum PaintSymmetryAreas {
+ AREA_SYMM_X = (1 << 0),
+ AREA_SYMM_Y = (1 << 1),
+ AREA_SYMM_Z = (1 << 2),
+} PaintSymmetryAreas;
+
+static char sculpt_get_vertex_symm_area(float co[3])
+{
+ float vco[3];
+ char symm_area = 0;
+ copy_v3_v3(vco, co);
+ if (vco[0] < 0) {
+ symm_area |= AREA_SYMM_X;
+ }
+ if (vco[1] < 0) {
+ symm_area |= AREA_SYMM_Y;
+ }
+ if (vco[2] < 0) {
+ symm_area |= AREA_SYMM_Z;
+ }
+ return symm_area;
+}
+
+static void flip_qt(float qt[4], char symm)
+{
+ float euler[3];
+ if (symm & PAINT_SYMM_X) {
+ quat_to_eul(euler, qt);
+ euler[1] = -euler[1];
+ euler[2] = -euler[2];
+ eul_to_quat(qt, euler);
+ }
+ if (symm & PAINT_SYMM_Y) {
+ quat_to_eul(euler, qt);
+ euler[0] = -euler[0];
+ euler[2] = -euler[2];
+ eul_to_quat(qt, euler);
+ }
+ if (symm & PAINT_SYMM_Z) {
+ quat_to_eul(euler, qt);
+ euler[0] = -euler[0];
+ euler[1] = -euler[1];
+ eul_to_quat(qt, euler);
+ }
+}
+
+static void sculpt_flip_transform_by_symm_area(
+ float disp[3], float rot[4], char symm, char symmarea, float pivot[3])
+{
+
+ for (char i = 0; i < 3; i++) {
+ char symm_it = 1 << i;
+ if (symm & symm_it) {
+ if (symmarea & symm_it) {
+ if (disp) {
+ flip_v3(disp, symm_it);
+ }
+ if (rot) {
+ flip_qt(rot, symm_it);
+ }
+ }
+ if (pivot[0] < 0) {
+ if (disp) {
+ flip_v3(disp, symm_it);
+ }
+ if (rot) {
+ flip_qt(rot, symm_it);
+ }
+ }
+ }
+ }
+}
+
+static void sculpt_transform_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+
+ SculptOrigVertData orig_data;
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
+
+ PBVHVertexIter vd;
+
+ sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+ float transformed_co[3], orig_co[3], disp[3];
+ float fade = vd.mask ? *vd.mask : 0.0f;
+ copy_v3_v3(orig_co, orig_data.co);
+ char symm_area = sculpt_get_vertex_symm_area(orig_co);
+
+ copy_v3_v3(transformed_co, orig_co);
+ mul_m4_v3(data->transform_mats[(int)symm_area], transformed_co);
+ sub_v3_v3v3(disp, transformed_co, orig_co);
+ mul_v3_fl(disp, 1.0f - fade);
+
+ add_v3_v3v3(vd.co, orig_co, disp);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ BKE_pbvh_node_mark_redraw(node);
+ BKE_pbvh_node_mark_normals_update(node);
+}
+
+void ED_sculpt_update_modal_transform(struct bContext *C)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+
+ sculpt_vertex_random_access_init(ss);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ };
+
+ float final_pivot_pos[3], d_t[3], d_r[4];
+ float t_mat[4][4], r_mat[4][4], s_mat[4][4], pivot_mat[4][4], pivot_imat[4][4],
+ transform_mat[4][4];
+
+ copy_v3_v3(final_pivot_pos, ss->pivot_pos);
+ for (int i = 0; i < 8; i++) {
+ copy_v3_v3(final_pivot_pos, ss->pivot_pos);
+
+ unit_m4(pivot_mat);
+
+ unit_m4(t_mat);
+ unit_m4(r_mat);
+ unit_m4(s_mat);
+
+ /* Translation matrix */
+ sub_v3_v3v3(d_t, ss->pivot_pos, ss->init_pivot_pos);
+ sculpt_flip_transform_by_symm_area(d_t, NULL, symm, (char)i, ss->init_pivot_pos);
+ translate_m4(t_mat, d_t[0], d_t[1], d_t[2]);
+
+ /* Rotation matrix */
+ sub_qt_qtqt(d_r, ss->pivot_rot, ss->init_pivot_rot);
+ normalize_qt(d_r);
+ sculpt_flip_transform_by_symm_area(NULL, d_r, symm, (char)i, ss->init_pivot_pos);
+ quat_to_mat4(r_mat, d_r);
+
+ /* Scale matrix */
+ size_to_mat4(s_mat, ss->pivot_scale);
+
+ /* Pivot matrix */
+ sculpt_flip_transform_by_symm_area(final_pivot_pos, NULL, symm, (char)i, ss->init_pivot_pos);
+ translate_m4(pivot_mat, final_pivot_pos[0], final_pivot_pos[1], final_pivot_pos[2]);
+ invert_m4_m4(pivot_imat, pivot_mat);
+
+ /* Final transform matrix */
+ mul_m4_m4m4(transform_mat, r_mat, t_mat);
+ mul_m4_m4m4(transform_mat, transform_mat, s_mat);
+ mul_m4_m4m4(data.transform_mats[i], transform_mat, pivot_imat);
+ mul_m4_m4m4(data.transform_mats[i], pivot_mat, data.transform_mats[i]);
+ }
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(
+ 0, ss->filter_cache->totnode, &data, sculpt_transform_task_cb, &settings);
+
+ if (ss->modifiers_active || ss->kb) {
+ sculpt_flush_stroke_deform(sd, ob, true);
+ }
+
+ sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS);
+}
+
+void ED_sculpt_end_transform(struct bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ if (ss->filter_cache) {
+ sculpt_filter_cache_free(ss);
+ }
+ sculpt_undo_push_end();
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
+}
+
+typedef enum eSculptPivotPositionModes {
+ SCULPT_PIVOT_POSITION_ORIGIN = 0,
+ SCULPT_PIVOT_POSITION_UNMASKED = 1,
+ SCULPT_PIVOT_POSITION_MASK_BORDER = 2,
+ SCULPT_PIVOT_POSITION_ACTIVE_VERTEX = 3,
+ SCULPT_PIVOT_POSITION_CURSOR_SURFACE = 4,
+} eSculptPivotPositionModes;
+
+static EnumPropertyItem prop_sculpt_pivot_position_types[] = {
+ {SCULPT_PIVOT_POSITION_ORIGIN,
+ "ORIGIN",
+ 0,
+ "Origin",
+ "Sets the pivot to the origin of the sculpt"},
+ {SCULPT_PIVOT_POSITION_UNMASKED,
+ "UNMASKED",
+ 0,
+ "Unmasked",
+ "Sets the pivot position to the average position of the unmasked vertices"},
+ {SCULPT_PIVOT_POSITION_MASK_BORDER,
+ "BORDER",
+ 0,
+ "Mask border",
+ "Sets the pivot position to the center of the border of the mask"},
+ {SCULPT_PIVOT_POSITION_ACTIVE_VERTEX,
+ "ACTIVE",
+ 0,
+ "Active vertex",
+ "Sets the pivot position to the active vertex position"},
+ {SCULPT_PIVOT_POSITION_CURSOR_SURFACE,
+ "SURFACE",
+ 0,
+ "Surface",
+ "Sets the pivot position to the surface under the cursor"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static int sculpt_set_pivot_position_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ ARegion *ar = CTX_wm_region(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+
+ int mode = RNA_enum_get(op->ptr, "mode");
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true);
+
+ /* Pivot to center */
+ if (mode == SCULPT_PIVOT_POSITION_ORIGIN) {
+ zero_v3(ss->pivot_pos);
+ }
+ /* Pivot to active vertex */
+ else if (mode == SCULPT_PIVOT_POSITION_ACTIVE_VERTEX) {
+ copy_v3_v3(ss->pivot_pos, sculpt_active_vertex_co_get(ss));
+ }
+ /* Pivot to raycast surface */
+ else if (mode == SCULPT_PIVOT_POSITION_CURSOR_SURFACE) {
+ float stroke_location[3];
+ float mouse[2];
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+ if (sculpt_stroke_get_location(C, stroke_location, mouse)) {
+ copy_v3_v3(ss->pivot_pos, stroke_location);
+ }
+ }
+ else {
+ PBVHNode **nodes;
+ int totnode;
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+
+ float avg[3];
+ int total = 0;
+ zero_v3(avg);
+
+ /* Pivot to unmasked */
+ if (mode == SCULPT_PIVOT_POSITION_UNMASKED) {
+ for (int n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float mask = (vd.mask) ? *vd.mask : 0.0f;
+ if (mask < 1.0f) {
+ if (check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) {
+ add_v3_v3(avg, vd.co);
+ total++;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+ }
+ /* Pivot to mask border */
+ else if (mode == SCULPT_PIVOT_POSITION_MASK_BORDER) {
+ const float threshold = 0.2f;
+
+ for (int n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float mask = (vd.mask) ? *vd.mask : 0.0f;
+ if (mask < (0.5f + threshold) && mask > (0.5f - threshold)) {
+ if (check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) {
+ add_v3_v3(avg, vd.co);
+ total++;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+ }
+
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ copy_v3_v3(ss->pivot_pos, avg);
+ }
+
+ MEM_SAFE_FREE(nodes);
+ }
+
+ ED_region_tag_redraw(ar);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_set_pivot_position(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Pivot Position";
+ ot->idname = "SCULPT_OT_set_pivot_position";
+ ot->description = "Sets the sculpt transform pivot position";
+
+ /* api callbacks */
+ ot->invoke = sculpt_set_pivot_position_invoke;
+ ot->poll = sculpt_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ RNA_def_enum(ot->srna,
+ "mode",
+ prop_sculpt_pivot_position_types,
+ SCULPT_PIVOT_POSITION_UNMASKED,
+ "Mode",
+ "");
+}
void ED_operatortypes_sculpt(void)
{
@@ -6752,4 +9777,9 @@ void ED_operatortypes_sculpt(void)
WM_operatortype_append(SCULPT_OT_detail_flood_fill);
WM_operatortype_append(SCULPT_OT_sample_detail_size);
WM_operatortype_append(SCULPT_OT_set_detail_size);
+ WM_operatortype_append(SCULPT_OT_mesh_filter);
+ WM_operatortype_append(SCULPT_OT_mask_filter);
+ WM_operatortype_append(SCULPT_OT_dirty_mask);
+ WM_operatortype_append(SCULPT_OT_mask_expand);
+ WM_operatortype_append(SCULPT_OT_set_pivot_position);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index bc9a4c1d85b..e9af49a0b5a 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -44,8 +44,38 @@ bool sculpt_mode_poll_view3d(struct bContext *C);
bool sculpt_poll(struct bContext *C);
bool sculpt_poll_view3d(struct bContext *C);
+/* Updates */
+
+typedef enum SculptUpdateType {
+ SCULPT_UPDATE_COORDS = 1 << 0,
+ SCULPT_UPDATE_MASK = 1 << 1,
+} SculptUpdateType;
+
/* Stroke */
+
+typedef struct SculptCursorGeometryInfo {
+ float location[3];
+ float normal[3];
+ float active_vertex_co[3];
+} SculptCursorGeometryInfo;
+
bool sculpt_stroke_get_location(struct bContext *C, float out[3], const float mouse[2]);
+bool sculpt_cursor_geometry_info_update(bContext *C,
+ SculptCursorGeometryInfo *out,
+ const float mouse[2],
+ bool use_sampled_normal);
+void sculpt_geometry_preview_lines_update(bContext *C, struct SculptSession *ss, float radius);
+void sculpt_pose_calc_pose_data(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ float initial_location[3],
+ float radius,
+ float pose_offset,
+ float *r_pose_origin,
+ float *r_pose_factor);
+
+/* Sculpt PBVH abstraction API */
+const float *sculpt_vertex_co_get(struct SculptSession *ss, int index);
/* Dynamic topology */
void sculpt_pbvh_clear(Object *ob);
@@ -107,6 +137,10 @@ typedef struct SculptUndoNode {
int geom_totloop;
int geom_totpoly;
+ /* pivot */
+ float pivot_pos[3];
+ float pivot_rot[4];
+
size_t undo_size;
} SculptUndoNode;
@@ -158,10 +192,41 @@ typedef struct SculptThreadedTaskData {
float (*mat)[4];
float (*vertCos)[3];
+ int filter_type;
+ float filter_strength;
+ int *node_mask;
+
/* 0=towards view, 1=flipped */
float (*area_cos)[3];
float (*area_nos)[3];
int *count;
+ bool any_vertex_sampled;
+
+ float *prev_mask;
+
+ float *pose_origin;
+ float *pose_initial_co;
+ float *pose_factor;
+ float (*transform_rot)[4], (*transform_trans)[4], (*transform_trans_inv)[4];
+
+ float tot_pos_avg[3];
+ int tot_pos_count;
+
+ float max_distance_squared;
+ float nearest_vertex_search_co[3];
+ int nearest_vertex_index;
+ float nearest_vertex_distance_squared;
+
+ int mask_expand_update_it;
+ bool mask_expand_invert_mask;
+ bool mask_expand_use_normals;
+ bool mask_expand_keep_prev_mask;
+
+ float transform_mats[8][4][4];
+
+ float dirty_mask_min;
+ float dirty_mask_max;
+ bool dirty_mask_dirty_only;
ThreadMutex mutex;
@@ -190,7 +255,9 @@ typedef struct {
struct Sculpt *sd;
struct SculptSession *ss;
float radius_squared;
+ float *center;
bool original;
+ bool ignore_fully_masked;
} SculptSearchSphereData;
typedef struct {
@@ -198,6 +265,7 @@ typedef struct {
struct SculptSession *ss;
float radius_squared;
bool original;
+ bool ignore_fully_masked;
struct DistRayAABB_Precalc *dist_ray_to_aabb_precalc;
} SculptSearchCircleData;
@@ -223,10 +291,11 @@ float tex_strength(struct SculptSession *ss,
const short vno[3],
const float fno[3],
const float mask,
+ const int vertex_index,
const int thread_id);
/* just for vertex paint. */
-void sculpt_pbvh_calc_area_normal(const struct Brush *brush,
+bool sculpt_pbvh_calc_area_normal(const struct Brush *brush,
Object *ob,
PBVHNode **nodes,
int totnode,
@@ -310,6 +379,11 @@ typedef struct StrokeCache {
bool original;
float anchored_location[3];
+ /* Pose brush */
+ float *pose_factor;
+ float pose_initial_co[3];
+ float pose_origin[3];
+
float vertex_rotation; /* amount to rotate the vertices when using rotate brush */
struct Dial *dial;
@@ -324,11 +398,30 @@ typedef struct StrokeCache {
float true_gravity_direction[3];
float gravity_direction[3];
+ float *automask;
+
rcti previous_r; /* previous redraw rectangle */
rcti current_r; /* current redraw rectangle */
} StrokeCache;
+typedef struct FilterCache {
+ bool enabled_axis[3];
+ int random_seed;
+
+ /* unmasked nodes */
+ PBVHNode **nodes;
+ int totnode;
+
+ /* mask expand iteration caches */
+ int mask_update_current_it;
+ int mask_update_last_it;
+ int *mask_update_it;
+ float *normal_factor;
+ float *prev_mask;
+ float mask_expand_initial_co[3];
+} FilterCache;
+
void sculpt_cache_calc_brushdata_symm(StrokeCache *cache,
const char symm,
const char axis,
@@ -346,6 +439,4 @@ void sculpt_update_object_bounding_box(struct Object *ob);
bool sculpt_get_redraw_rect(struct ARegion *ar, struct RegionView3D *rv3d, Object *ob, rcti *rect);
-#define SCULPT_THREADED_LIMIT 4
-
#endif
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index cb8afd5d7fa..788d07f6e78 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -39,8 +39,6 @@
#include "DNA_scene_types.h"
#include "DNA_mesh_types.h"
#include "DNA_screen_types.h"
-#include "DNA_space_types.h"
-#include "DNA_workspace_types.h"
#include "BKE_ccg.h"
#include "BKE_context.h"
@@ -49,7 +47,6 @@
#include "BKE_paint.h"
#include "BKE_key.h"
#include "BKE_mesh.h"
-#include "BKE_mesh_runtime.h"
#include "BKE_scene.h"
#include "BKE_subsurf.h"
#include "BKE_subdiv_ccg.h"
@@ -62,13 +59,11 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "ED_paint.h"
#include "ED_object.h"
#include "ED_sculpt.h"
#include "ED_undo.h"
#include "bmesh.h"
-#include "paint_intern.h"
#include "sculpt_intern.h"
typedef struct UndoSculpt {
@@ -352,8 +347,7 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C,
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(
0, totnode, nodes, sculpt_undo_bmesh_restore_generic_task_cb, &settings);
@@ -494,6 +488,9 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
bool partial_update = true;
for (unode = lb->first; unode; unode = unode->next) {
+ /* restore pivot */
+ copy_v3_v3(ss->pivot_pos, unode->pivot_pos);
+ copy_v3_v3(ss->pivot_rot, unode->pivot_rot);
if (STREQ(unode->idname, ob->id.name)) {
if (unode->type == SCULPT_UNDO_MASK) {
/* is possible that we can't do the mask undo (below)
@@ -1055,6 +1052,10 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
break;
}
+ /* store sculpt pivot */
+ copy_v3_v3(unode->pivot_pos, ss->pivot_pos);
+ copy_v3_v3(unode->pivot_rot, ss->pivot_rot);
+
/* store active shape key */
if (ss->kb) {
BLI_strncpy(unode->shapeName, ss->kb->name, sizeof(ss->kb->name));
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index 91ed9057667..8fbaf3396bd 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -38,7 +38,6 @@
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
-#include "BKE_main.h"
#include "BKE_mesh_mapping.h"
#include "BKE_paint.h"
@@ -48,10 +47,6 @@
#include "ED_image.h"
#include "ED_mesh.h"
-#include "GPU_immediate.h"
-#include "GPU_immediate_util.h"
-#include "GPU_state.h"
-
#include "WM_api.h"
#include "WM_types.h"
@@ -151,7 +146,7 @@ typedef struct Temp_UvData {
static void HC_relaxation_iteration_uv(BMEditMesh *em,
UvSculptData *sculptdata,
- float mouse_coord[2],
+ const float mouse_coord[2],
float alpha,
float radius,
float aspectRatio)
@@ -239,7 +234,7 @@ static void HC_relaxation_iteration_uv(BMEditMesh *em,
static void laplacian_relaxation_iteration_uv(BMEditMesh *em,
UvSculptData *sculptdata,
- float mouse_coord[2],
+ const float mouse_coord[2],
float alpha,
float radius,
float aspectRatio)
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index 51231ccf634..4e710d31cbb 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -710,7 +710,7 @@ static void SOUND_OT_mixdown(wmOperatorType *ot)
FILE_TYPE_FOLDER | FILE_TYPE_SOUND,
FILE_SPECIAL,
FILE_SAVE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
#ifdef WITH_AUDASPACE
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 944a0c74f4c..242acfd0261 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -1663,7 +1663,7 @@ static const EnumPropertyItem prop_actkeys_snap_types[] = {
{ACTKEYS_SNAP_CFRA,
"CFRA",
0,
- "Current frame",
+ "Current Frame",
"Snap selected keyframes to the current frame"},
{ACTKEYS_SNAP_NEAREST_FRAME,
"NEAREST_FRAME",
@@ -1789,17 +1789,17 @@ static const EnumPropertyItem prop_actkeys_mirror_types[] = {
{ACTKEYS_MIRROR_CFRA,
"CFRA",
0,
- "By Times over Current frame",
+ "By Times Over Current Frame",
"Flip times of selected keyframes using the current frame as the mirror line"},
{ACTKEYS_MIRROR_XAXIS,
"XAXIS",
0,
- "By Values over Value=0",
+ "By Values Over Value=0",
"Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"},
{ACTKEYS_MIRROR_MARKER,
"MARKER",
0,
- "By Times over First Selected Marker",
+ "By Times Over First Selected Marker",
"Flip times of selected keyframes using the first selected marker as the reference point"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 9e2634b183a..4a4ff5f5605 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -339,7 +339,9 @@ static int actkeys_deselectall_exec(bContext *C, wmOperator *op)
/* set notifier that keyframe selection have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -572,7 +574,9 @@ static int actkeys_box_select_exec(bContext *C, wmOperator *op)
/* set notifier that keyframe selection have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -805,7 +809,9 @@ static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -871,7 +877,9 @@ static int action_circle_select_exec(bContext *C, wmOperator *op)
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1099,7 +1107,9 @@ static int actkeys_columnselect_exec(bContext *C, wmOperator *op)
/* set notifier that keyframe selection have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1159,7 +1169,9 @@ static int actkeys_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
/* set notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1243,7 +1255,9 @@ static int actkeys_select_more_exec(bContext *C, wmOperator *UNUSED(op))
/* set notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1278,7 +1292,9 @@ static int actkeys_select_less_exec(bContext *C, wmOperator *UNUSED(op))
/* set notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1717,22 +1733,26 @@ static void mouse_action_keys(bAnimContext *ac,
/* Highlight GPencil Layer */
if (ale != NULL && ale->data != NULL && ale->type == ANIMTYPE_GPLAYER) {
+ bGPdata *gpd = (bGPdata *)ale->id;
bGPDlayer *gpl = ale->data;
gpl->flag |= GP_LAYER_SELECT;
- // gpencil_layer_setactive(gpd, gpl);
+ /* Update other layer status. */
+ if (BKE_gpencil_layer_getactive(gpd) != gpl) {
+ BKE_gpencil_layer_setactive(gpd, gpl);
+ BKE_gpencil_layer_autolock_set(gpd, false);
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
}
}
else if (ac->datatype == ANIMCONT_MASK) {
/* deselect all other channels first */
ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
- /* Highlight GPencil Layer */
if (ale != NULL && ale->data != NULL && ale->type == ANIMTYPE_MASKLAYER) {
MaskLayer *masklay = ale->data;
masklay->flag |= MASK_LAYERFLAG_SELECT;
- // gpencil_layer_setactive(gpd, gpl);
}
}
}
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 23c224f5ae0..b26c3113fbd 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -364,6 +364,7 @@ static void buttons_area_listener(wmWindow *UNUSED(win),
switch (wmn->data) {
case ND_RENDER_OPTIONS:
buttons_area_redraw(sa, BCONTEXT_RENDER);
+ buttons_area_redraw(sa, BCONTEXT_OUTPUT);
buttons_area_redraw(sa, BCONTEXT_VIEW_LAYER);
break;
case ND_WORLD:
diff --git a/source/blender/editors/space_clip/clip_dopesheet_draw.c b/source/blender/editors/space_clip/clip_dopesheet_draw.c
index 3c2d3eb1d97..e64f21f9307 100644
--- a/source/blender/editors/space_clip/clip_dopesheet_draw.c
+++ b/source/blender/editors/space_clip/clip_dopesheet_draw.c
@@ -44,7 +44,6 @@
#include "RNA_access.h"
-#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_state.h"
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index e3fa8edd714..80b58954c8f 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -161,7 +161,7 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc
/* cache background */
ED_region_cache_draw_background(ar);
- /* cached segments -- could be usefu lto debug caching strategies */
+ /* cached segments -- could be useful to debug caching strategies */
BKE_movieclip_get_cache_segments(clip, &sc->user, &totseg, &points);
ED_region_cache_draw_cached_segments(ar, totseg, points, sfra, efra);
@@ -404,177 +404,185 @@ static void draw_stabilization_border(
}
}
-static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackingTrack *track)
-{
-#define MAX_STATIC_PATH 64
- int count = sc->path_length;
- int i, a, b, curindex = -1;
- float path_static[(MAX_STATIC_PATH + 1) * 2][2];
- float(*path)[2];
- int tiny = sc->flag & SC_SHOW_TINY_MARKER, framenr, start_frame;
- MovieTrackingMarker *marker;
+enum {
+ PATH_POINT_FLAG_KEYFRAME = (1 << 0),
+};
- if (count == 0) {
- return;
- }
+typedef struct TrachPathPoint {
+ float co[2];
+ uchar flag;
+} TrackPathPoint;
- start_frame = framenr = ED_space_clip_get_clip_frame_number(sc);
-
- marker = BKE_tracking_marker_get(track, framenr);
- if (marker->framenr != framenr || marker->flag & MARKER_DISABLED) {
- return;
- }
-
- if (count < MAX_STATIC_PATH) {
- path = path_static;
- }
- else {
- path = MEM_mallocN(sizeof(*path) * (count + 1) * 2, "path");
+static void marker_to_path_point(SpaceClip *sc,
+ const MovieTrackingTrack *track,
+ const MovieTrackingMarker *marker,
+ TrackPathPoint *point)
+{
+ add_v2_v2v2(point->co, marker->pos, track->offset);
+ ED_clip_point_undistorted_pos(sc, point->co, point->co);
+ point->flag = 0;
+ if ((marker->flag & MARKER_TRACKED) == 0) {
+ point->flag |= PATH_POINT_FLAG_KEYFRAME;
}
+}
- a = count;
- i = framenr - 1;
- while (i >= framenr - count) {
- marker = BKE_tracking_marker_get(track, i);
-
- if (!marker || marker->flag & MARKER_DISABLED) {
+static int track_to_path_segment(SpaceClip *sc,
+ MovieTrackingTrack *track,
+ int direction,
+ TrackPathPoint *path)
+{
+ const int count = sc->path_length;
+ int current_frame = ED_space_clip_get_clip_frame_number(sc);
+ const MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, current_frame);
+ /* Check whether there is marker at exact current frame.
+ * If not, we don't have anything to be put to path. */
+ if (marker == NULL || (marker->flag & MARKER_DISABLED)) {
+ return 0;
+ }
+ /* Index inside of path array where we write data to. */
+ int point_index = count;
+ int path_length = 0;
+ for (int i = 0; i < count; ++i) {
+ marker_to_path_point(sc, track, marker, &path[point_index]);
+ /* Move to the next marker along the path segment. */
+ path_length++;
+ point_index += direction;
+ current_frame += direction;
+ marker = BKE_tracking_marker_get_exact(track, current_frame);
+ if (marker == NULL || (marker->flag & MARKER_DISABLED)) {
+ /* Reached end of tracked segment. */
break;
}
+ }
+ return path_length;
+}
- if (marker->framenr == i) {
- add_v2_v2v2(path[--a], marker->pos, track->offset);
- ED_clip_point_undistorted_pos(sc, path[a], path[a]);
+static void draw_track_path_points(const TrackPathPoint *path,
+ uint position_attribute,
+ const int start_point,
+ const int num_points)
+{
+ if (num_points == 0) {
+ return;
+ }
+ immBegin(GPU_PRIM_POINTS, num_points);
+ for (int i = 0; i < num_points; i++) {
+ const TrackPathPoint *point = &path[i + start_point];
+ immVertex2fv(position_attribute, point->co);
+ }
+ immEnd();
+}
- if (marker->framenr == start_frame) {
- curindex = a;
- }
- }
- else {
- break;
+static void draw_track_path_keyframe_points(const TrackPathPoint *path,
+ uint position_attribute,
+ const int start_point,
+ const int num_points)
+{
+ immBeginAtMost(GPU_PRIM_POINTS, num_points);
+ for (int i = 0; i < num_points; i++) {
+ const TrackPathPoint *point = &path[i + start_point];
+ if (point->flag & PATH_POINT_FLAG_KEYFRAME) {
+ immVertex2fv(position_attribute, point->co);
}
+ }
+ immEnd();
+}
- i--;
+static void draw_track_path_lines(const TrackPathPoint *path,
+ uint position_attribute,
+ const int start_point,
+ const int num_points)
+{
+ if (num_points < 2) {
+ return;
+ }
+ immBegin(GPU_PRIM_LINE_STRIP, num_points);
+ for (int i = 0; i < num_points; i++) {
+ const TrackPathPoint *point = &path[i + start_point];
+ immVertex2fv(position_attribute, point->co);
}
+ immEnd();
+}
- b = count;
- i = framenr;
- while (i <= framenr + count) {
- marker = BKE_tracking_marker_get(track, i);
+static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackingTrack *track)
+{
+#define MAX_STATIC_PATH 64
- if (!marker || marker->flag & MARKER_DISABLED) {
- break;
- }
+ const int count = sc->path_length;
+ TrackPathPoint path_static[(MAX_STATIC_PATH + 1) * 2];
+ TrackPathPoint *path;
+ const bool tiny = (sc->flag & SC_SHOW_TINY_MARKER) != 0;
- if (marker->framenr == i) {
- if (marker->framenr == start_frame) {
- curindex = b;
- }
+ if (count == 0) {
+ /* Early output, nothing to bother about here. */
+ return;
+ }
- add_v2_v2v2(path[b++], marker->pos, track->offset);
- ED_clip_point_undistorted_pos(sc, path[b - 1], path[b - 1]);
- }
- else {
- break;
- }
+ /* Try to use stack allocated memory when possibly, only use heap allocation
+ * for really long paths. */
+ path = (count < MAX_STATIC_PATH) ? path_static :
+ MEM_mallocN(sizeof(*path) * (count + 1) * 2, "path");
+ /* Collect path information. */
+ const int num_points_before = track_to_path_segment(sc, track, -1, path);
+ const int num_points_after = track_to_path_segment(sc, track, 1, path);
+ if (num_points_before == 0 && num_points_after == 0) {
+ return;
+ }
- i++;
+ int num_all_points = num_points_before + num_points_after;
+ /* If both leading and trailing parts of the path are there the center point is counted twice. */
+ if (num_points_before != 0 && num_points_after != 0) {
+ num_all_points -= 1;
}
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ const int path_start_index = count - num_points_before + 1;
+ const int path_center_index = count;
+ const uint position_attribute = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ /* Draw path outline. */
if (!tiny) {
immUniformThemeColor(TH_MARKER_OUTLINE);
-
if (TRACK_VIEW_SELECTED(sc, track)) {
- if ((b - a - 1) >= 1) {
- GPU_point_size(5.0f);
-
- immBegin(GPU_PRIM_POINTS, b - a - 1);
-
- for (i = a; i < b; i++) {
- if (i != curindex) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
- }
-
- immEnd();
- }
- }
-
- if ((b - a) >= 2) {
- GPU_line_width(3.0f);
-
- immBegin(GPU_PRIM_LINE_STRIP, b - a);
-
- for (i = a; i < b; i++) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
-
- immEnd();
+ GPU_point_size(5.0f);
+ draw_track_path_points(path, position_attribute, path_start_index, num_all_points);
+ GPU_point_size(7.0f);
+ draw_track_path_keyframe_points(path, position_attribute, path_start_index, num_all_points);
}
+ /* Draw darker outline for actual path, all line segments at once. */
+ GPU_line_width(3.0f);
+ draw_track_path_lines(path, position_attribute, path_start_index, num_all_points);
}
- if (TRACK_VIEW_SELECTED(sc, track)) {
- GPU_point_size(3.0f);
-
- if ((curindex - a) >= 1) {
- immUniformThemeColor(TH_PATH_BEFORE);
-
- immBegin(GPU_PRIM_POINTS, curindex - a);
-
- for (i = a; i < curindex; i++) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
-
- immEnd();
- }
-
- if ((b - curindex - 1) >= 1) {
- immUniformThemeColor(TH_PATH_AFTER);
-
- immBegin(GPU_PRIM_POINTS, b - curindex - 1);
-
- for (i = curindex + 1; i < b; i++) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
-
- immEnd();
- }
- }
+ /* Draw all points. */
+ GPU_point_size(3.0f);
+ immUniformThemeColor(TH_PATH_BEFORE);
+ draw_track_path_points(path, position_attribute, path_start_index, num_points_before);
+ immUniformThemeColor(TH_PATH_AFTER);
+ draw_track_path_points(path, position_attribute, path_center_index, num_points_after);
+ /* Connect points with color coded segments. */
GPU_line_width(1);
+ immUniformThemeColor(TH_PATH_BEFORE);
+ draw_track_path_lines(path, position_attribute, path_start_index, num_points_before);
+ immUniformThemeColor(TH_PATH_AFTER);
+ draw_track_path_lines(path, position_attribute, path_center_index, num_points_after);
+
+ /* Draw all bigger points corresponding to keyframes. */
+ GPU_point_size(5.0f);
+ immUniformThemeColor(TH_PATH_KEYFRAME_BEFORE);
+ draw_track_path_keyframe_points(path, position_attribute, path_start_index, num_points_before);
+ immUniformThemeColor(TH_PATH_KEYFRAME_AFTER);
+ draw_track_path_keyframe_points(path, position_attribute, path_center_index, num_points_after);
- if ((curindex - a + 1) >= 2) {
- immUniformThemeColor(TH_PATH_BEFORE);
-
- immBegin(GPU_PRIM_LINE_STRIP, curindex - a + 1);
-
- for (i = a; i <= curindex; i++) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
-
- immEnd();
- }
-
- if ((b - curindex) >= 2) {
- immUniformThemeColor(TH_PATH_AFTER);
-
- immBegin(GPU_PRIM_LINE_STRIP, b - curindex);
-
- for (i = curindex; i < b; i++) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
-
- immEnd();
+ if (path != path_static) {
+ MEM_freeN(path);
}
immUnbindProgram();
- if (path != path_static) {
- MEM_freeN(path);
- }
#undef MAX_STATIC_PATH
}
@@ -887,7 +895,7 @@ static float get_shortest_pattern_side(MovieTrackingMarker *marker)
}
static void draw_marker_slide_square(
- float x, float y, float dx, float dy, int outline, float px[2], unsigned int pos)
+ float x, float y, float dx, float dy, int outline, const float px[2], unsigned int pos)
{
float tdx, tdy;
@@ -903,7 +911,7 @@ static void draw_marker_slide_square(
}
static void draw_marker_slide_triangle(
- float x, float y, float dx, float dy, int outline, float px[2], unsigned int pos)
+ float x, float y, float dx, float dy, int outline, const float px[2], unsigned int pos)
{
float tdx, tdy;
diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h
index 8599de9f16f..bd54d4f0016 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -94,6 +94,7 @@ void CLIP_OT_view_zoom_out(struct wmOperatorType *ot);
void CLIP_OT_view_zoom_ratio(struct wmOperatorType *ot);
void CLIP_OT_view_all(struct wmOperatorType *ot);
void CLIP_OT_view_selected(struct wmOperatorType *ot);
+void CLIP_OT_view_center_cursor(struct wmOperatorType *ot);
void CLIP_OT_change_frame(wmOperatorType *ot);
void CLIP_OT_rebuild_proxy(struct wmOperatorType *ot);
void CLIP_OT_mode_set(struct wmOperatorType *ot);
@@ -108,6 +109,8 @@ void CLIP_OT_set_scene_frames(wmOperatorType *ot);
void CLIP_OT_cursor_set(struct wmOperatorType *ot);
+void CLIP_OT_lock_selection_toggle(struct wmOperatorType *ot);
+
/* clip_toolbar.c */
struct ARegion *ED_clip_has_properties_region(struct ScrArea *sa);
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index cf899773822..192449a219d 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -78,7 +78,9 @@
#include "clip_intern.h" // own include
-/******************** view navigation utilities *********************/
+/* -------------------------------------------------------------------- */
+/** \name View Navigation Utilities
+ * \{ */
static void sclip_zoom_set(const bContext *C,
float zoom,
@@ -162,7 +164,11 @@ static void sclip_zoom_set_factor_exec(bContext *C, const wmEvent *event, float
ED_region_tag_redraw(ar);
}
-/******************** open clip operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Open Clip Operator
+ * \{ */
static void clip_filesel(bContext *C, wmOperator *op, const char *path)
{
@@ -326,7 +332,11 @@ void CLIP_OT_open(wmOperatorType *ot)
FILE_SORT_ALPHA);
}
-/******************* reload clip operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reload Clip Operator
+ * \{ */
static int reload_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -355,7 +365,11 @@ void CLIP_OT_reload(wmOperatorType *ot)
ot->exec = reload_exec;
}
-/********************** view pan operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Pan Operator
+ * \{ */
typedef struct ViewPanData {
float x, y;
@@ -376,7 +390,7 @@ static void view_pan_init(bContext *C, wmOperator *op, const wmEvent *event)
/* Grab will be set when running from gizmo. */
vpd->own_cursor = (win->grabcursor == 0);
if (vpd->own_cursor) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
vpd->x = event->x;
@@ -510,7 +524,7 @@ void CLIP_OT_view_pan(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY | OPTYPE_LOCK_BYPASS;
/* properties */
RNA_def_float_vector(ot->srna,
@@ -525,7 +539,11 @@ void CLIP_OT_view_pan(wmOperatorType *ot)
FLT_MAX);
}
-/********************** view zoom operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom Operator
+ * \{ */
typedef struct ViewZoomData {
float x, y;
@@ -549,7 +567,7 @@ static void view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event)
/* Grab will be set when running from gizmo. */
vpd->own_cursor = (win->grabcursor == 0);
if (vpd->own_cursor) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
if (U.viewzoom == USER_ZOOM_CONT) {
@@ -712,7 +730,7 @@ void CLIP_OT_view_zoom(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY | OPTYPE_LOCK_BYPASS;
/* properties */
prop = RNA_def_float(ot->srna,
@@ -729,7 +747,11 @@ void CLIP_OT_view_zoom(wmOperatorType *ot)
WM_operator_properties_use_cursor_init(ot);
}
-/********************** view zoom in/out operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom In/Out Operator
+ * \{ */
static int view_zoom_in_exec(bContext *C, wmOperator *op)
{
@@ -771,6 +793,9 @@ void CLIP_OT_view_zoom_in(wmOperatorType *ot)
ot->invoke = view_zoom_in_invoke;
ot->poll = ED_space_clip_view_clip_poll;
+ /* flags */
+ ot->flag |= OPTYPE_LOCK_BYPASS;
+
/* properties */
prop = RNA_def_float_vector(ot->srna,
"location",
@@ -825,6 +850,9 @@ void CLIP_OT_view_zoom_out(wmOperatorType *ot)
ot->invoke = view_zoom_out_invoke;
ot->poll = ED_space_clip_view_clip_poll;
+ /* flags */
+ ot->flag |= OPTYPE_LOCK_BYPASS;
+
/* properties */
prop = RNA_def_float_vector(ot->srna,
"location",
@@ -839,7 +867,11 @@ void CLIP_OT_view_zoom_out(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
-/********************** view zoom ratio operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom Ratio Operator
+ * \{ */
static int view_zoom_ratio_exec(bContext *C, wmOperator *op)
{
@@ -867,6 +899,9 @@ void CLIP_OT_view_zoom_ratio(wmOperatorType *ot)
ot->exec = view_zoom_ratio_exec;
ot->poll = ED_space_clip_view_clip_poll;
+ /* flags */
+ ot->flag |= OPTYPE_LOCK_BYPASS;
+
/* properties */
RNA_def_float(ot->srna,
"ratio",
@@ -878,8 +913,11 @@ void CLIP_OT_view_zoom_ratio(wmOperatorType *ot)
-FLT_MAX,
FLT_MAX);
}
+/** \} */
-/********************** view all operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name View All Operator
+ * \{ */
static int view_all_exec(bContext *C, wmOperator *op)
{
@@ -945,12 +983,48 @@ void CLIP_OT_view_all(wmOperatorType *ot)
ot->exec = view_all_exec;
ot->poll = ED_space_clip_view_clip_poll;
+ /* flags */
+ ot->flag = OPTYPE_LOCK_BYPASS;
+
/* properties */
prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Center View To Cursor Operator
+ * \{ */
+
+static int view_center_cursor_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ clip_view_center_to_point(sc, sc->cursor[0], sc->cursor[1]);
+
+ ED_region_tag_redraw(ar);
+
+ return OPERATOR_FINISHED;
+}
-/********************** view selected operator *********************/
+void CLIP_OT_view_center_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Center View to Cursor";
+ ot->description = "Center the view so that the cursor is in the middle of the view";
+ ot->idname = "CLIP_OT_view_center_cursor";
+
+ /* api callbacks */
+ ot->exec = view_center_cursor_exec;
+ ot->poll = ED_space_clip_maskedit_poll;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Selected Operator
+ * \{ */
static int view_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -976,9 +1050,15 @@ void CLIP_OT_view_selected(wmOperatorType *ot)
/* api callbacks */
ot->exec = view_selected_exec;
ot->poll = ED_space_clip_view_clip_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_LOCK_BYPASS;
}
+/** \} */
-/********************** change frame operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name Change Frame Operator
+ * \{ */
static bool change_frame_poll(bContext *C)
{
@@ -1094,8 +1174,11 @@ void CLIP_OT_change_frame(wmOperatorType *ot)
/* rna */
RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
}
+/** \} */
-/********************** rebuild proxies operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name Rebuild Proxies Operator
+ * \{ */
typedef struct ProxyBuildJob {
Scene *scene;
@@ -1116,7 +1199,7 @@ static void proxy_freejob(void *pjv)
static int proxy_bitflag_to_array(int size_flag, int build_sizes[4], int undistort)
{
int build_count = 0;
- int size_flags[2][4] = {
+ const int size_flags[2][4] = {
{MCLIP_PROXY_SIZE_25, MCLIP_PROXY_SIZE_50, MCLIP_PROXY_SIZE_75, MCLIP_PROXY_SIZE_100},
{MCLIP_PROXY_UNDISTORTED_SIZE_25,
MCLIP_PROXY_UNDISTORTED_SIZE_50,
@@ -1506,8 +1589,11 @@ void CLIP_OT_rebuild_proxy(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER;
}
+/** \} */
-/********************** mode set operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name Mode Set Operator
+ * \{ */
static int mode_set_exec(bContext *C, wmOperator *op)
{
@@ -1543,7 +1629,12 @@ void CLIP_OT_mode_set(wmOperatorType *ot)
}
#ifdef WITH_INPUT_NDOF
-/********************** NDOF operator *********************/
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NDOF Operator
+ * \{ */
/* Combined pan/zoom from a 3D mouse device.
* Z zooms, XY pans
@@ -1589,10 +1680,18 @@ void CLIP_OT_view_ndof(wmOperatorType *ot)
/* api callbacks */
ot->invoke = clip_view_ndof_invoke;
ot->poll = ED_space_clip_view_clip_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_LOCK_BYPASS;
}
+
+/** \} */
+
#endif /* WITH_INPUT_NDOF */
-/********************** Prefetch operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name Prefetch Operator
+ * \{ */
static int clip_prefetch_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
@@ -1632,8 +1731,11 @@ void CLIP_OT_prefetch(wmOperatorType *ot)
ot->invoke = clip_prefetch_invoke;
ot->modal = clip_prefetch_modal;
}
+/** \} */
-/********************** Set scene frames *********************/
+/* -------------------------------------------------------------------- */
+/** \name Set Scene Frames Operator
+ * \{ */
static int clip_set_scene_frames_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -1668,8 +1770,11 @@ void CLIP_OT_set_scene_frames(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
ot->exec = clip_set_scene_frames_exec;
}
+/** \} */
-/******************** set 3d cursor operator ********************/
+/* -------------------------------------------------------------------- */
+/** \name Set 3d Cursor Operator
+ * \{ */
static int clip_set_2d_cursor_exec(bContext *C, wmOperator *op)
{
@@ -1730,7 +1835,40 @@ void CLIP_OT_cursor_set(wmOperatorType *ot)
10.0f);
}
-/********************** macros *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Lock To Selection Operator
+ * \{ */
+
+static int lock_selection_togglee_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+ space_clip->flag ^= SC_LOCK_SELECTION;
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CLIP, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_lock_selection_toggle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Toggle Lock Selection";
+ ot->description = "Toggle Lock Selection option of the current clip editor";
+ ot->idname = "CLIP_OT_lock_selection_toggle";
+
+ /* api callbacks */
+ ot->poll = ED_space_clip_poll;
+ ot->exec = lock_selection_togglee_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_LOCK_BYPASS;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Macros
+ * \{ */
void ED_operatormacros_clip(void)
{
@@ -1754,3 +1892,5 @@ void ED_operatormacros_clip(void)
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_boolean_set(otmacro->ptr, "release_confirm", true);
}
+
+/** \} */
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index 48f788e2e3a..902229c0bba 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -38,7 +38,6 @@
#include "DEG_depsgraph_build.h"
#include "GPU_immediate.h"
-#include "GPU_matrix.h"
#include "GPU_state.h"
#include "WM_api.h"
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index c1cb975447f..16305a9b17b 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -443,6 +443,7 @@ static void clip_operatortypes(void)
WM_operatortype_append(CLIP_OT_view_zoom_ratio);
WM_operatortype_append(CLIP_OT_view_all);
WM_operatortype_append(CLIP_OT_view_selected);
+ WM_operatortype_append(CLIP_OT_view_center_cursor);
WM_operatortype_append(CLIP_OT_change_frame);
WM_operatortype_append(CLIP_OT_rebuild_proxy);
WM_operatortype_append(CLIP_OT_mode_set);
@@ -452,6 +453,7 @@ static void clip_operatortypes(void)
WM_operatortype_append(CLIP_OT_prefetch);
WM_operatortype_append(CLIP_OT_set_scene_frames);
WM_operatortype_append(CLIP_OT_cursor_set);
+ WM_operatortype_append(CLIP_OT_lock_selection_toggle);
/* ** tracking_ops.c ** */
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index 1375b99bdaa..f1bce00ea0b 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -448,8 +448,8 @@ static float mouse_to_slide_zone_distance_squared(const float co[2],
int width,
int height)
{
- float pixel_co[2] = {co[0] * width, co[1] * height},
- pixel_slide_zone[2] = {slide_zone[0] * width, slide_zone[1] * height};
+ const float pixel_co[2] = {co[0] * width, co[1] * height},
+ pixel_slide_zone[2] = {slide_zone[0] * width, slide_zone[1] * height};
return SQUARE(pixel_co[0] - pixel_slide_zone[0]) + SQUARE(pixel_co[1] - pixel_slide_zone[1]);
}
@@ -2090,7 +2090,7 @@ static int keyframe_insert_exec(bContext *C, wmOperator *UNUSED(op))
void CLIP_OT_keyframe_insert(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Insert keyframe";
+ ot->name = "Insert Keyframe";
ot->description = "Insert a keyframe to selected tracks at current frame";
ot->idname = "CLIP_OT_keyframe_insert";
@@ -2113,7 +2113,7 @@ static int keyframe_delete_exec(bContext *C, wmOperator *UNUSED(op))
void CLIP_OT_keyframe_delete(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Delete keyframe";
+ ot->name = "Delete Keyframe";
ot->description = "Delete a keyframe from selected tracks at current frame";
ot->idname = "CLIP_OT_keyframe_delete";
diff --git a/source/blender/editors/space_clip/tracking_ops_plane.c b/source/blender/editors/space_clip/tracking_ops_plane.c
index b1bf88634bc..7d2324d3f48 100644
--- a/source/blender/editors/space_clip/tracking_ops_plane.c
+++ b/source/blender/editors/space_clip/tracking_ops_plane.c
@@ -115,8 +115,8 @@ static float mouse_to_plane_slide_zone_distance_squared(const float co[2],
int width,
int height)
{
- float pixel_co[2] = {co[0] * width, co[1] * height},
- pixel_slide_zone[2] = {slide_zone[0] * width, slide_zone[1] * height};
+ const float pixel_co[2] = {co[0] * width, co[1] * height},
+ pixel_slide_zone[2] = {slide_zone[0] * width, slide_zone[1] * height};
return SQUARE(pixel_co[0] - pixel_slide_zone[0]) + SQUARE(pixel_co[1] - pixel_slide_zone[1]);
}
diff --git a/source/blender/editors/space_clip/tracking_ops_solve.c b/source/blender/editors/space_clip/tracking_ops_solve.c
index 96b00ec5463..1d2fc239a89 100644
--- a/source/blender/editors/space_clip/tracking_ops_solve.c
+++ b/source/blender/editors/space_clip/tracking_ops_solve.c
@@ -50,6 +50,7 @@
/********************** solve camera operator *********************/
typedef struct {
+ struct wmWindowManager *wm;
Scene *scene;
MovieClip *clip;
MovieClipUser user;
@@ -78,6 +79,7 @@ static bool solve_camera_initjob(
/* Could fail if footage uses images with different sizes. */
BKE_movieclip_get_size(clip, &sc->user, &width, &height);
+ scj->wm = CTX_wm_manager(C);
scj->clip = clip;
scj->scene = scene;
scj->reports = op->reports;
@@ -88,6 +90,8 @@ static bool solve_camera_initjob(
tracking->stats = MEM_callocN(sizeof(MovieTrackingStats), "solve camera stats");
+ WM_set_locked_interface(scj->wm, true);
+
return true;
}
@@ -114,6 +118,8 @@ static void solve_camera_freejob(void *scv)
MovieClip *clip = scj->clip;
int solved;
+ WM_set_locked_interface(scj->wm, false);
+
if (!scj->context) {
/* job weren't fully initialized due to some error */
MEM_freeN(scj);
diff --git a/source/blender/editors/space_clip/tracking_ops_track.c b/source/blender/editors/space_clip/tracking_ops_track.c
index 9536c64c415..adbb3e30850 100644
--- a/source/blender/editors/space_clip/tracking_ops_track.c
+++ b/source/blender/editors/space_clip/tracking_ops_track.c
@@ -59,6 +59,7 @@ typedef struct TrackMarkersJob {
float delay; /* Delay in milliseconds to allow
* tracking at fixed FPS */
+ struct wmWindowManager *wm;
struct Main *main;
struct Scene *scene;
struct bScreen *screen;
@@ -127,7 +128,7 @@ static bool track_markers_check_direction(int backwards, int curfra, int efra)
return true;
}
-static int track_markers_initjob(bContext *C, TrackMarkersJob *tmj, bool backwards, bool sequence)
+static bool track_markers_initjob(bContext *C, TrackMarkersJob *tmj, bool backwards, bool sequence)
{
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -202,7 +203,15 @@ static int track_markers_initjob(bContext *C, TrackMarkersJob *tmj, bool backwar
tmj->main = CTX_data_main(C);
tmj->screen = CTX_wm_screen(C);
- return track_markers_check_direction(backwards, tmj->sfra, tmj->efra);
+ tmj->wm = CTX_wm_manager(C);
+
+ if (!track_markers_check_direction(backwards, tmj->sfra, tmj->efra)) {
+ return false;
+ }
+
+ WM_set_locked_interface(tmj->wm, true);
+
+ return true;
}
static void track_markers_startjob(void *tmv, short *stop, short *do_update, float *progress)
@@ -281,6 +290,7 @@ static void track_markers_freejob(void *tmv)
{
TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
tmj->clip->tracking_context = NULL;
+ WM_set_locked_interface(tmj->wm, false);
BKE_autotrack_context_free(tmj->context);
MEM_freeN(tmj);
}
diff --git a/source/blender/editors/space_clip/tracking_ops_utils.c b/source/blender/editors/space_clip/tracking_ops_utils.c
index 3970f1381bf..7579c9a49c6 100644
--- a/source/blender/editors/space_clip/tracking_ops_utils.c
+++ b/source/blender/editors/space_clip/tracking_ops_utils.c
@@ -57,11 +57,11 @@ void clip_tracking_clear_invisible_track_selection(SpaceClip *sc, MovieClip *cli
void clip_tracking_hide_cursor(bContext *C)
{
wmWindow *win = CTX_wm_window(C);
- WM_cursor_set(win, CURSOR_NONE);
+ WM_cursor_set(win, WM_CURSOR_NONE);
}
void clip_tracking_show_cursor(bContext *C)
{
wmWindow *win = CTX_wm_window(C);
- WM_cursor_set(win, CURSOR_STD);
+ WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index 4532b61f291..f6063b49005 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -57,7 +57,7 @@ static float dist_to_crns(float co[2], float pos[2], float crns[4][2]);
/********************** mouse select operator *********************/
static int mouse_on_side(
- float co[2], float x1, float y1, float x2, float y2, float epsx, float epsy)
+ const float co[2], float x1, float y1, float x2, float y2, float epsx, float epsy)
{
if (x1 > x2) {
SWAP(float, x1, x2);
@@ -71,7 +71,7 @@ static int mouse_on_side(
}
static int mouse_on_rect(
- float co[2], float pos[2], float min[2], float max[2], float epsx, float epsy)
+ const float co[2], float pos[2], float min[2], float max[2], float epsx, float epsy)
{
return mouse_on_side(
co, pos[0] + min[0], pos[1] + min[1], pos[0] + max[0], pos[1] + min[1], epsx, epsy) ||
diff --git a/source/blender/editors/space_console/console_ops.c b/source/blender/editors/space_console/console_ops.c
index faf613482a3..bc18a6cfb56 100644
--- a/source/blender/editors/space_console/console_ops.c
+++ b/source/blender/editors/space_console/console_ops.c
@@ -1082,7 +1082,7 @@ typedef struct SetConsoleCursor {
// TODO, cursor placement without selection
static void console_cursor_set_to_pos(
- SpaceConsole *sc, ARegion *ar, SetConsoleCursor *scu, int mval[2], int UNUSED(sel))
+ SpaceConsole *sc, ARegion *ar, SetConsoleCursor *scu, const int mval[2], int UNUSED(sel))
{
int pos;
pos = console_char_pick(sc, ar, mval);
diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c
index 999255aef88..5cc2f00413a 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -26,6 +26,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BKE_global.h"
#include "BKE_context.h"
#include "BKE_screen.h"
@@ -148,11 +149,11 @@ static void console_main_region_init(wmWindowManager *wm, ARegion *ar)
static void console_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
{
SpaceText *st = sa->spacedata.first;
- int wmcursor = BC_TEXTEDITCURSOR;
+ int wmcursor = WM_CURSOR_TEXT_EDIT;
if (st->text &&
BLI_rcti_isect_pt(&st->txtbar, win->eventstate->x - ar->winrct.xmin, st->txtbar.ymin)) {
- wmcursor = CURSOR_STD;
+ wmcursor = WM_CURSOR_DEFAULT;
}
WM_cursor_set(win, wmcursor);
@@ -173,7 +174,7 @@ static void id_drop_copy(wmDrag *drag, wmDropBox *drop)
ID *id = WM_drag_ID(drag, 0);
/* copy drag path to properties */
- char *text = RNA_path_full_ID_py(id);
+ char *text = RNA_path_full_ID_py(G_MAIN, id);
RNA_string_set(drop->ptr, "text", text);
MEM_freeN(text);
}
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 3a6d59c1dbf..0aec6d5e6a0 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -26,6 +26,7 @@
#include <errno.h>
#include "BLI_blenlib.h"
+#include "BLI_fileops_types.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
@@ -70,239 +71,57 @@
#include "file_intern.h" // own include
-/* Dummy helper - we need dynamic tooltips here. */
-static char *file_draw_tooltip_func(bContext *UNUSED(C), void *argN, const char *UNUSED(tip))
+void ED_file_path_button(bScreen *screen,
+ const SpaceFile *sfile,
+ FileSelectParams *params,
+ uiBlock *block)
{
- char *dyn_tooltip = argN;
- return BLI_strdup(dyn_tooltip);
-}
-
-/* Note: This function uses pixelspace (0, 0, winx, winy), not view2d.
- * The controls are laid out as follows:
- *
- * -------------------------------------------
- * | Directory input | execute |
- * -------------------------------------------
- * | Filename input | + | - | cancel |
- * -------------------------------------------
- *
- * The input widgets will stretch to fill any excess space.
- * When there isn't enough space for all controls to be shown, they are
- * hidden in this order: x/-, execute/cancel, input widgets.
- */
-void file_draw_buttons(const bContext *C, ARegion *ar)
-{
- /* Button layout. */
- const int max_x = ar->winx - 10;
- const int line1_y = ar->winy - (IMASEL_BUTTONS_HEIGHT / 2 + IMASEL_BUTTONS_MARGIN);
- const int line2_y = line1_y - (IMASEL_BUTTONS_HEIGHT / 2 + IMASEL_BUTTONS_MARGIN);
- const int input_minw = 20;
- const int btn_h = UI_UNIT_Y;
- const int btn_fn_w = UI_UNIT_X;
- const int btn_minw = 80;
- const int btn_margin = 20;
- const int separator = 4;
-
- /* Additional locals. */
- char uiblockstr[32];
- int loadbutton;
- int fnumbuttons;
- int min_x = 10;
- int chan_offs = 0;
- int available_w = max_x - min_x;
- int line1_w = available_w;
- int line2_w = available_w;
-
+ PointerRNA params_rna_ptr;
uiBut *but;
- uiBlock *block;
- SpaceFile *sfile = CTX_wm_space_file(C);
- FileSelectParams *params = ED_fileselect_get_params(sfile);
- ARegion *artmp;
- const bool is_browse_only = (sfile->op == NULL);
-
- /* Initialize UI block. */
- BLI_snprintf(uiblockstr, sizeof(uiblockstr), "win %p", (void *)ar);
- block = UI_block_begin(C, ar, uiblockstr, UI_EMBOSS);
-
- /* exception to make space for collapsed region icon */
- for (artmp = CTX_wm_area(C)->regionbase.first; artmp; artmp = artmp->next) {
- if (artmp->regiontype == RGN_TYPE_TOOLS && artmp->flag & RGN_FLAG_HIDDEN) {
- chan_offs = 16;
- min_x += chan_offs;
- available_w -= chan_offs;
- }
- }
-
- /* Is there enough space for the execute / cancel buttons? */
- if (is_browse_only) {
- loadbutton = 0;
- }
- else {
- const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
- loadbutton = UI_fontstyle_string_width(fstyle, params->title) + btn_margin;
- CLAMP_MIN(loadbutton, btn_minw);
- if (available_w <= loadbutton + separator + input_minw) {
- loadbutton = 0;
- }
+ RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, &params_rna_ptr);
+
+ /* callbacks for operator check functions */
+ UI_block_func_set(block, file_draw_check_cb, NULL, NULL);
+
+ but = uiDefButR(block,
+ UI_BTYPE_TEXT,
+ -1,
+ "",
+ 0,
+ 0,
+ UI_UNIT_X * 10,
+ UI_UNIT_Y,
+ &params_rna_ptr,
+ "directory",
+ 0,
+ 0.0f,
+ (float)FILE_MAX,
+ 0.0f,
+ 0.0f,
+ TIP_("File path"));
+
+ BLI_assert(!UI_but_flag_is_set(but, UI_BUT_UNDO));
+ BLI_assert(!UI_but_is_utf8(but));
+
+ UI_but_func_complete_set(but, autocomplete_directory, NULL);
+ UI_but_funcN_set(but, file_directory_enter_handle, NULL, but);
+
+ /* TODO, directory editing is non-functional while a library is loaded
+ * until this is properly supported just disable it. */
+ if (sfile && sfile->files && filelist_lib(sfile->files)) {
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
}
- if (loadbutton) {
- line1_w -= (loadbutton + separator);
- line2_w = line1_w;
- }
-
- /* Is there enough space for file number increment/decrement buttons? */
- fnumbuttons = 2 * btn_fn_w;
- if (!loadbutton || line2_w <= fnumbuttons + separator + input_minw) {
- fnumbuttons = 0;
- }
- else {
- line2_w -= (fnumbuttons + separator);
- }
-
- /* Text input fields for directory and file. */
- if (available_w > 0) {
- const struct FileDirEntry *file = sfile->files ?
- filelist_file(sfile->files, params->active_file) :
- NULL;
- int overwrite_alert = file_draw_check_exists(sfile);
- const bool is_active_dir = file && (file->typeflag & FILE_TYPE_FOLDER);
-
- /* callbacks for operator check functions */
- UI_block_func_set(block, file_draw_check_cb, NULL, NULL);
-
- but = uiDefBut(block,
- UI_BTYPE_TEXT,
- -1,
- "",
- min_x,
- line1_y,
- line1_w - chan_offs,
- btn_h,
- params->dir,
- 0.0,
- (float)FILE_MAX,
- 0,
- 0,
- TIP_("File path"));
- UI_but_func_complete_set(but, autocomplete_directory, NULL);
- UI_but_flag_enable(but, UI_BUT_NO_UTF8);
- UI_but_flag_disable(but, UI_BUT_UNDO);
- UI_but_funcN_set(but, file_directory_enter_handle, NULL, but);
-
- /* TODO, directory editing is non-functional while a library is loaded
- * until this is properly supported just disable it. */
- if (sfile->files && filelist_lib(sfile->files)) {
- UI_but_flag_enable(but, UI_BUT_DISABLED);
- }
-
- if ((params->flag & FILE_DIRSEL_ONLY) == 0) {
- but = uiDefBut(
- block,
- UI_BTYPE_TEXT,
- -1,
- "",
- min_x,
- line2_y,
- line2_w - chan_offs,
- btn_h,
- is_active_dir ? (char *)"" : params->file,
- 0.0,
- (float)FILE_MAXFILE,
- 0,
- 0,
- TIP_(overwrite_alert ? N_("File name, overwrite existing") : N_("File name")));
- UI_but_func_complete_set(but, autocomplete_file, NULL);
- UI_but_flag_enable(but, UI_BUT_NO_UTF8);
- UI_but_flag_disable(but, UI_BUT_UNDO);
- /* silly workaround calling NFunc to ensure this does not get called
- * immediate ui_apply_but_func but only after button deactivates */
- UI_but_funcN_set(but, file_filename_enter_handle, NULL, but);
-
- /* check if this overrides a file and if the operator option is used */
- if (overwrite_alert) {
- UI_but_flag_enable(but, UI_BUT_REDALERT);
- }
- }
-
- /* clear func */
- UI_block_func_set(block, NULL, NULL, NULL);
- }
-
- /* Filename number increment / decrement buttons. */
- if (fnumbuttons && (params->flag & FILE_DIRSEL_ONLY) == 0) {
- UI_block_align_begin(block);
- but = uiDefIconButO(block,
- UI_BTYPE_BUT,
- "FILE_OT_filenum",
- 0,
- ICON_REMOVE,
- min_x + line2_w + separator - chan_offs,
- line2_y,
- btn_fn_w,
- btn_h,
- TIP_("Decrement the filename number"));
- RNA_int_set(UI_but_operator_ptr_get(but), "increment", -1);
-
- but = uiDefIconButO(block,
- UI_BTYPE_BUT,
- "FILE_OT_filenum",
- 0,
- ICON_ADD,
- min_x + line2_w + separator + btn_fn_w - chan_offs,
- line2_y,
- btn_fn_w,
- btn_h,
- TIP_("Increment the filename number"));
- RNA_int_set(UI_but_operator_ptr_get(but), "increment", 1);
- UI_block_align_end(block);
- }
-
- /* Execute / cancel buttons. */
- if (loadbutton) {
- const struct FileDirEntry *file = sfile->files ?
- filelist_file(sfile->files, params->active_file) :
- NULL;
- char const *str_exec;
-
- if (file && FILENAME_IS_PARENT(file->relpath)) {
- str_exec = IFACE_("Parent Directory");
- }
- else if (file && file->typeflag & FILE_TYPE_DIR) {
- str_exec = IFACE_("Open Directory");
- }
- else {
- str_exec = params->title; /* params->title is already translated! */
- }
-
- but = uiDefButO(block,
- UI_BTYPE_BUT,
- "FILE_OT_execute",
- WM_OP_EXEC_REGION_WIN,
- str_exec,
- max_x - loadbutton,
- line1_y,
- loadbutton,
- btn_h,
- "");
- /* Just a display hint. */
- UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT);
-
- uiDefButO(block,
- UI_BTYPE_BUT,
- "FILE_OT_cancel",
- WM_OP_EXEC_REGION_WIN,
- IFACE_("Cancel"),
- max_x - loadbutton,
- line2_y,
- loadbutton,
- btn_h,
- "");
- }
+ /* clear func */
+ UI_block_func_set(block, NULL, NULL, NULL);
+}
- UI_block_end(C, block);
- UI_block_draw(C, block);
+/* Dummy helper - we need dynamic tooltips here. */
+static char *file_draw_tooltip_func(bContext *UNUSED(C), void *argN, const char *UNUSED(tip))
+{
+ char *dyn_tooltip = argN;
+ return BLI_strdup(dyn_tooltip);
}
static void draw_tile(int sx, int sy, int width, int height, int colorid, int shade)
@@ -319,13 +138,10 @@ static void file_draw_icon(
{
uiBut *but;
int x, y;
- // float alpha = 1.0f;
x = sx;
y = sy - height;
- /*if (icon == ICON_FILE_BLANK) alpha = 0.375f;*/
-
but = uiDefIconBut(
block, UI_BTYPE_LABEL, 0, icon, x, y, width, height, NULL, 0.0f, 0.0f, 0.0f, 0.0f, NULL);
UI_but_func_tooltip_set(but, file_draw_tooltip_func, BLI_strdup(path));
@@ -349,7 +165,7 @@ static void file_draw_string(int sx,
rcti rect;
char fname[FILE_MAXFILE];
- if (string[0] == '\0') {
+ if (string[0] == '\0' || width < 1) {
return;
}
@@ -362,7 +178,7 @@ static void file_draw_string(int sx,
/* no text clipping needed, UI_fontstyle_draw does it but is a bit too strict
* (for buttons it works) */
rect.xmin = sx;
- rect.xmax = (int)(sx + ceil(width + 5.0f / UI_DPI_FAC));
+ rect.xmax = sx + round_fl_to_int(width);
rect.ymin = sy - height;
rect.ymax = sy;
@@ -404,8 +220,8 @@ static void file_draw_preview(uiBlock *block,
float scaledx, scaledy;
float scale;
int ex, ey;
- bool use_dropshadow = !is_icon && (typeflags & FILE_TYPE_IMAGE);
- float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ bool show_outline = !is_icon &&
+ (typeflags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_BLENDER));
BLI_assert(imb != NULL);
@@ -440,15 +256,20 @@ static void file_draw_preview(uiBlock *block,
xco = sx + (int)dx;
yco = sy - layout->prv_h + (int)dy;
- /* shadow */
- if (use_dropshadow) {
- UI_draw_box_shadow(220, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey));
- }
-
GPU_blend(true);
- /* the image */
- if (!is_icon && typeflags & FILE_TYPE_FTFONT) {
+ /* the large image */
+
+ float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ if (is_icon) {
+ if (typeflags & FILE_TYPE_DIR) {
+ UI_GetThemeColor4fv(TH_ICON_FOLDER, col);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_TEXT, col);
+ }
+ }
+ else if (typeflags & FILE_TYPE_FTFONT) {
UI_GetThemeColor4fv(TH_TEXT, col);
}
@@ -477,30 +298,58 @@ static void file_draw_preview(uiBlock *block,
GPU_blend_set_func_separate(
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- if (icon) {
- UI_icon_draw_ex((float)xco + (7 * UI_DPI_FAC),
- (float)yco + (7 * UI_DPI_FAC),
- icon,
- icon_aspect,
- 1.0f,
- 0.0f,
- NULL,
- false);
+ if (icon && (icon != ICON_FILE_FONT)) {
+ /* size of center icon is scaled to fit container and UI scale */
+ float icon_x, icon_y;
+
+ if (is_icon) {
+ const float icon_size = 16.0f / icon_aspect * U.dpi_fac;
+ float icon_opacity = 0.3f;
+ uchar icon_color[4] = {0, 0, 0, 255};
+ float bgcolor[4];
+ UI_GetThemeColor4fv(TH_ICON_FOLDER, bgcolor);
+ if (rgb_to_grayscale(bgcolor) < 0.5f) {
+ icon_color[0] = 255;
+ icon_color[1] = 255;
+ icon_color[2] = 255;
+ }
+ icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f);
+ icon_y = yco + (ey / 2.0f) - (icon_size * ((typeflags & FILE_TYPE_DIR) ? 0.78f : 0.75f));
+ UI_icon_draw_ex(
+ icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false);
+ }
+ else {
+ const uchar dark[4] = {0, 0, 0, 255};
+ const uchar light[4] = {255, 255, 255, 255};
+
+ /* Smaller, fainter icon for preview image thumbnail. */
+ icon_x = xco + (2.0f * UI_DPI_FAC);
+ icon_y = yco + (2.0f * UI_DPI_FAC);
+
+ UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false);
+ UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
+ }
}
- /* border */
- if (use_dropshadow) {
+ /* Contrasting outline around some preview types. */
+ if (show_outline) {
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
+ float border_color[4] = {1.0f, 1.0f, 1.0f, 0.4f};
+ float bgcolor[4];
+ UI_GetThemeColor4fv(TH_BACK, bgcolor);
+ if (rgb_to_grayscale(bgcolor) > 0.5f) {
+ border_color[0] = 0.0f;
+ border_color[1] = 0.0f;
+ border_color[2] = 0.0f;
+ }
+ immUniformColor4fv(border_color);
imm_draw_box_wire_2d(pos, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey));
immUnbindProgram();
}
but = uiDefBut(block, UI_BTYPE_LABEL, 0, "", xco, yco, ex, ey, NULL, 0.0, 0.0, 0, 0, NULL);
- UI_but_func_tooltip_set(but, file_draw_tooltip_func, BLI_strdup(path));
/* dragregion */
if (drag) {
@@ -557,6 +406,7 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
static void draw_background(FileLayout *layout, View2D *v2d)
{
+ const int item_height = layout->tile_h + (2 * layout->tile_border_y);
int i;
int sy;
@@ -565,9 +415,11 @@ static void draw_background(FileLayout *layout, View2D *v2d)
immUniformThemeColorShade(TH_BACK, -7);
/* alternating flat shade background */
- for (i = 0; (i <= layout->rows); i += 2) {
- sy = (int)v2d->cur.ymax - i * (layout->tile_h + 2 * layout->tile_border_y) -
- layout->tile_border_y;
+ for (i = 2; (i <= layout->rows + 1); i += 2) {
+ sy = (int)v2d->cur.ymax - layout->offset_top - i * item_height - layout->tile_border_y;
+
+ /* Offsett pattern slightly to add scroll effect. */
+ sy += round_fl_to_int(item_height * (v2d->tot.ymax - v2d->cur.ymax) / item_height);
immRectf(pos,
v2d->cur.xmin,
@@ -632,6 +484,176 @@ static void draw_dividers(FileLayout *layout, View2D *v2d)
}
}
+static void draw_columnheader_background(const FileLayout *layout, const View2D *v2d)
+{
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShade(TH_BACK, 11);
+
+ immRectf(pos,
+ v2d->cur.xmin,
+ v2d->cur.ymax - layout->attribute_column_header_h,
+ v2d->cur.xmax,
+ v2d->cur.ymax);
+
+ immUnbindProgram();
+}
+
+static void draw_columnheader_columns(const FileSelectParams *params,
+ FileLayout *layout,
+ const View2D *v2d,
+ const uchar text_col[4])
+{
+ const float divider_pad = 0.2 * layout->attribute_column_header_h;
+ int sx = v2d->cur.xmin, sy = v2d->cur.ymax;
+
+ for (FileAttributeColumnType column_type = 0; column_type < ATTRIBUTE_COLUMN_MAX;
+ column_type++) {
+ if (!file_attribute_column_type_enabled(params, column_type)) {
+ continue;
+ }
+ const FileAttributeColumn *column = &layout->attribute_columns[column_type];
+
+ /* Active sort type triangle */
+ if (params->sort == column->sort_type) {
+ float tri_color[4];
+
+ rgba_uchar_to_float(tri_color, text_col);
+ UI_draw_icon_tri(sx + column->width - (0.3f * U.widget_unit) -
+ ATTRIBUTE_COLUMN_PADDING / 2.0f,
+ sy + (0.1f * U.widget_unit) - (layout->attribute_column_header_h / 2),
+ (params->flag & FILE_SORT_INVERT) ? 't' : 'v',
+ tri_color);
+ }
+
+ file_draw_string(sx + ATTRIBUTE_COLUMN_PADDING,
+ sy - layout->tile_border_y,
+ IFACE_(column->name),
+ column->width - 2 * ATTRIBUTE_COLUMN_PADDING,
+ layout->attribute_column_header_h - layout->tile_border_y,
+ UI_STYLE_TEXT_LEFT,
+ text_col);
+
+ /* Separator line */
+ if (column_type != COLUMN_NAME) {
+ uint pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShade(TH_BACK, -10);
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, sx - 1, sy - divider_pad);
+ immVertex2f(pos, sx - 1, sy - layout->attribute_column_header_h + divider_pad);
+ immEnd();
+ immUnbindProgram();
+ }
+
+ sx += column->width;
+ }
+
+ /* Vertical separator lines line */
+ {
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShade(TH_BACK, -10);
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex2f(pos, v2d->cur.xmin, sy);
+ immVertex2f(pos, v2d->cur.xmax, sy);
+ immVertex2f(pos, v2d->cur.xmin, sy - layout->attribute_column_header_h);
+ immVertex2f(pos, v2d->cur.xmax, sy - layout->attribute_column_header_h);
+ immEnd();
+ immUnbindProgram();
+ }
+}
+
+/**
+ * Updates the stat string stored in file->entry if necessary.
+ */
+static const char *filelist_get_details_column_string(FileAttributeColumnType column,
+ const FileDirEntry *file,
+ const bool small_size,
+ const bool update_stat_strings)
+{
+ switch (column) {
+ case COLUMN_DATETIME:
+ if (!(file->typeflag & FILE_TYPE_BLENDERLIB) && !FILENAME_IS_CURRPAR(file->relpath)) {
+ if ((file->entry->datetime_str[0] == '\0') || update_stat_strings) {
+ char date[FILELIST_DIRENTRY_DATE_LEN], time[FILELIST_DIRENTRY_TIME_LEN];
+ bool is_today, is_yesterday;
+
+ BLI_filelist_entry_datetime_to_string(
+ NULL, file->entry->time, small_size, time, date, &is_today, &is_yesterday);
+
+ if (is_today || is_yesterday) {
+ BLI_strncpy(date, is_today ? N_("Today") : N_("Yesterday"), sizeof(date));
+ }
+ BLI_snprintf(
+ file->entry->datetime_str, sizeof(file->entry->datetime_str), "%s %s", date, time);
+ }
+
+ return file->entry->datetime_str;
+ }
+ break;
+ case COLUMN_SIZE:
+ if ((file->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) ||
+ !(file->typeflag & (FILE_TYPE_DIR | FILE_TYPE_BLENDERLIB))) {
+ if ((file->entry->size_str[0] == '\0') || update_stat_strings) {
+ BLI_filelist_entry_size_to_string(
+ NULL, file->entry->size, small_size, file->entry->size_str);
+ }
+
+ return file->entry->size_str;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static void draw_details_columns(const FileSelectParams *params,
+ const FileLayout *layout,
+ const FileDirEntry *file,
+ const int pos_x,
+ const int pos_y,
+ const uchar text_col[4])
+{
+ const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size);
+ const bool update_stat_strings = small_size != SMALL_SIZE_CHECK(layout->curr_size);
+ int sx = pos_x - layout->tile_border_x - (UI_UNIT_X * 0.1f), sy = pos_y;
+
+ for (FileAttributeColumnType column_type = 0; column_type < ATTRIBUTE_COLUMN_MAX;
+ column_type++) {
+ const FileAttributeColumn *column = &layout->attribute_columns[column_type];
+
+ /* Name column is not a detail column (should already be drawn), always skip here. */
+ if (column_type == COLUMN_NAME) {
+ sx += column->width;
+ continue;
+ }
+ if (!file_attribute_column_type_enabled(params, column_type)) {
+ continue;
+ }
+
+ const char *str = filelist_get_details_column_string(
+ column_type, file, small_size, update_stat_strings);
+
+ if (str) {
+ file_draw_string(sx + ATTRIBUTE_COLUMN_PADDING,
+ sy - layout->tile_border_y,
+ IFACE_(str),
+ column->width - 2 * ATTRIBUTE_COLUMN_PADDING,
+ layout->tile_h,
+ column->text_align,
+ text_col);
+ }
+
+ sx += column->width;
+ }
+}
+
void file_draw_list(const bContext *C, ARegion *ar)
{
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -652,18 +674,14 @@ void file_draw_list(const bContext *C, ARegion *ar)
bool is_icon;
eFontStyle_Align align;
bool do_drag;
- int column_space = 0.6f * UI_UNIT_X;
unsigned char text_col[4];
- const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size);
- const bool update_stat_strings = small_size != SMALL_SIZE_CHECK(layout->curr_size);
- const float thumb_icon_aspect = sqrtf(64.0f / (float)(params->thumbnail_size));
+ const bool draw_columnheader = (params->display == FILE_VERTICALDISPLAY);
+ const float thumb_icon_aspect = MIN2(64.0f / (float)(params->thumbnail_size), 1.0f);
numfiles = filelist_files_ensure(files);
if (params->display != FILE_IMGDISPLAY) {
-
draw_background(layout, v2d);
-
draw_dividers(layout, v2d);
}
@@ -679,13 +697,14 @@ void file_draw_list(const bContext *C, ARegion *ar)
numfiles_layout += layout->rows;
}
else {
- numfiles_layout += layout->columns;
+ numfiles_layout += layout->flow_columns;
}
filelist_file_cache_slidingwindow_set(files, numfiles_layout);
- textwidth = (FILE_IMGDISPLAY == params->display) ? layout->tile_w :
- (int)layout->column_widths[COLUMN_NAME];
+ textwidth = (FILE_IMGDISPLAY == params->display) ?
+ layout->tile_w :
+ round_fl_to_int(layout->attribute_columns[COLUMN_NAME].width);
textheight = (int)(layout->textheight * 3.0 / 2.0 + 0.5);
align = (FILE_IMGDISPLAY == params->display) ? UI_STYLE_TEXT_CENTER : UI_STYLE_TEXT_LEFT;
@@ -719,11 +738,16 @@ void file_draw_list(const bContext *C, ARegion *ar)
BLF_batch_draw_begin();
+ UI_GetThemeColor4ubv(TH_TEXT, text_col);
+
for (i = offset; (i < numfiles) && (i < offset + numfiles_layout); i++) {
unsigned int file_selflag;
char path[FILE_MAX_LIBEXTRA];
+ int padx = 0.1f * UI_UNIT_X;
+ int icon_ofs = 0;
+
ED_fileselect_layout_tilepos(layout, i, &sx, &sy);
- sx += (int)(v2d->tot.xmin + 0.1f * UI_UNIT_X);
+ sx += (int)(v2d->tot.xmin + padx);
sy = (int)(v2d->tot.ymax - sy);
file = filelist_file(files, i);
@@ -737,15 +761,14 @@ void file_draw_list(const bContext *C, ARegion *ar)
int colorid = (file_selflag & FILE_SEL_SELECTED) ? TH_HILITE : TH_BACK;
int shade = (params->highlight_file == i) || (file_selflag & FILE_SEL_HIGHLIGHTED) ? 35 :
0;
+ const short width = ELEM(params->display, FILE_VERTICALDISPLAY, FILE_HORIZONTALDISPLAY) ?
+ layout->tile_w - (2 * padx) :
+ layout->tile_w;
BLI_assert(i == 0 || !FILENAME_IS_CURRPAR(file->relpath));
- draw_tile(sx,
- sy - 1,
- layout->tile_w + 4,
- sfile->layout->tile_h + layout->tile_border_y,
- colorid,
- shade);
+ draw_tile(
+ sx, sy - 1, width, sfile->layout->tile_h + layout->tile_border_y, colorid, shade);
}
}
UI_draw_roundbox_corner_set(UI_CNR_NONE);
@@ -778,38 +801,28 @@ void file_draw_list(const bContext *C, ARegion *ar)
file_draw_icon(block,
path,
sx,
- sy - (UI_UNIT_Y / 6),
+ sy - layout->tile_border_y,
filelist_geticon(files, i, true),
ICON_DEFAULT_WIDTH_SCALE,
ICON_DEFAULT_HEIGHT_SCALE,
do_drag);
- sx += ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X;
+ icon_ofs += ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X;
}
- UI_GetThemeColor4ubv(TH_TEXT, text_col);
-
if (file_selflag & FILE_SEL_EDITING) {
uiBut *but;
- short width;
-
- if (params->display == FILE_SHORTDISPLAY) {
- width = layout->tile_w - (ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X);
- }
- else if (params->display == FILE_LONGDISPLAY) {
- width = layout->column_widths[COLUMN_NAME] + (column_space * 3.5f);
- }
- else {
- BLI_assert(params->display == FILE_IMGDISPLAY);
- width = textwidth;
- }
+ const short width = (params->display == FILE_IMGDISPLAY) ?
+ textwidth :
+ layout->attribute_columns[COLUMN_NAME].width -
+ ATTRIBUTE_COLUMN_PADDING;
but = uiDefBut(block,
UI_BTYPE_TEXT,
1,
"",
- sx,
+ sx + icon_ofs,
sy - layout->tile_h - 0.15f * UI_UNIT_X,
- width,
+ width - icon_ofs,
textheight,
sfile->params->renamefile,
1.0f,
@@ -825,74 +838,19 @@ void file_draw_list(const bContext *C, ARegion *ar)
sfile->files, file, FILE_SEL_REMOVE, FILE_SEL_EDITING, CHECK_ALL);
}
}
-
- if (!(file_selflag & FILE_SEL_EDITING)) {
- int tpos = (FILE_IMGDISPLAY == params->display) ? sy - layout->tile_h + layout->textheight :
- sy;
- file_draw_string(sx + 1, tpos, file->name, (float)textwidth, textheight, align, text_col);
- }
-
- sx += (int)layout->column_widths[COLUMN_NAME] + column_space;
- if (params->display == FILE_SHORTDISPLAY) {
- if ((file->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) ||
- !(file->typeflag & (FILE_TYPE_DIR | FILE_TYPE_BLENDERLIB))) {
- if ((file->entry->size_str[0] == '\0') || update_stat_strings) {
- BLI_filelist_entry_size_to_string(
- NULL, file->entry->size, small_size, file->entry->size_str);
- }
- file_draw_string(sx,
- sy,
- file->entry->size_str,
- layout->column_widths[COLUMN_SIZE],
- layout->tile_h,
- align,
- text_col);
- }
- sx += (int)layout->column_widths[COLUMN_SIZE] + column_space;
+ else {
+ const int txpos = (params->display == FILE_IMGDISPLAY) ? sx : sx + 1 + icon_ofs;
+ const int typos = (params->display == FILE_IMGDISPLAY) ?
+ sy - layout->tile_h + layout->textheight :
+ sy - layout->tile_border_y;
+ const int twidth = (params->display == FILE_IMGDISPLAY) ?
+ textwidth :
+ textwidth - 1 - icon_ofs - padx - layout->tile_border_x;
+ file_draw_string(txpos, typos, file->name, (float)twidth, textheight, align, text_col);
}
- else if (params->display == FILE_LONGDISPLAY) {
- if (!(file->typeflag & FILE_TYPE_BLENDERLIB) && !FILENAME_IS_CURRPAR(file->relpath)) {
- if ((file->entry->date_str[0] == '\0') || update_stat_strings) {
- BLI_filelist_entry_datetime_to_string(
- NULL, file->entry->time, small_size, file->entry->time_str, file->entry->date_str);
- }
- file_draw_string(sx,
- sy,
- file->entry->date_str,
- layout->column_widths[COLUMN_DATE],
- layout->tile_h,
- align,
- text_col);
- sx += (int)layout->column_widths[COLUMN_DATE] + column_space;
- file_draw_string(sx,
- sy,
- file->entry->time_str,
- layout->column_widths[COLUMN_TIME],
- layout->tile_h,
- align,
- text_col);
- sx += (int)layout->column_widths[COLUMN_TIME] + column_space;
- }
- else {
- sx += (int)layout->column_widths[COLUMN_DATE] + column_space;
- sx += (int)layout->column_widths[COLUMN_TIME] + column_space;
- }
- if ((file->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) ||
- !(file->typeflag & (FILE_TYPE_DIR | FILE_TYPE_BLENDERLIB))) {
- if ((file->entry->size_str[0] == '\0') || update_stat_strings) {
- BLI_filelist_entry_size_to_string(
- NULL, file->entry->size, small_size, file->entry->size_str);
- }
- file_draw_string(sx,
- sy,
- file->entry->size_str,
- layout->column_widths[COLUMN_SIZE],
- layout->tile_h,
- align,
- text_col);
- }
- sx += (int)layout->column_widths[COLUMN_SIZE] + column_space;
+ if (params->display != FILE_IMGDISPLAY) {
+ draw_details_columns(params, layout, file, sx, sy, text_col);
}
}
@@ -901,5 +859,11 @@ void file_draw_list(const bContext *C, ARegion *ar)
UI_block_end(C, block);
UI_block_draw(C, block);
+ /* Draw last, on top of file list. */
+ if (draw_columnheader) {
+ draw_columnheader_background(layout, v2d);
+ draw_columnheader_columns(params, layout, v2d, text_col);
+ }
+
layout->curr_size = params->thumbnail_size;
}
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index bad25511dd5..b0ff67844d8 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -30,9 +30,7 @@ struct ARegion;
struct ARegionType;
struct FileSelectParams;
struct SpaceFile;
-
-/* file_ops.c */
-struct ARegion *file_tools_region(struct ScrArea *sa);
+struct View2D;
/* file_draw.c */
#define TILE_BORDER_X (UI_UNIT_X / 4)
@@ -42,9 +40,10 @@ struct ARegion *file_tools_region(struct ScrArea *sa);
#define IMASEL_BUTTONS_HEIGHT (UI_UNIT_Y * 2)
#define IMASEL_BUTTONS_MARGIN (UI_UNIT_Y / 6)
+#define ATTRIBUTE_COLUMN_PADDING (0.5f * UI_UNIT_X)
+
#define SMALL_SIZE_CHECK(_size) ((_size) < 64) /* Related to FileSelectParams.thumbnail_size. */
-void file_draw_buttons(const bContext *C, ARegion *ar);
void file_calc_previews(const bContext *C, ARegion *ar);
void file_draw_list(const bContext *C, ARegion *ar);
@@ -64,6 +63,7 @@ typedef enum WalkSelectDirection {
} WalkSelectDirections;
void FILE_OT_highlight(struct wmOperatorType *ot);
+void FILE_OT_sort_column_ui_context(struct wmOperatorType *ot);
void FILE_OT_select(struct wmOperatorType *ot);
void FILE_OT_select_walk(struct wmOperatorType *ot);
void FILE_OT_select_all(struct wmOperatorType *ot);
@@ -82,7 +82,6 @@ void FILE_OT_directory_new(struct wmOperatorType *ot);
void FILE_OT_previous(struct wmOperatorType *ot);
void FILE_OT_next(struct wmOperatorType *ot);
void FILE_OT_refresh(struct wmOperatorType *ot);
-void FILE_OT_bookmark_toggle(struct wmOperatorType *ot);
void FILE_OT_filenum(struct wmOperatorType *ot);
void FILE_OT_delete(struct wmOperatorType *ot);
void FILE_OT_rename(struct wmOperatorType *ot);
@@ -108,10 +107,21 @@ void file_sfile_to_operator_ex(bContext *C,
struct SpaceFile *sfile,
char *filepath);
void file_sfile_to_operator(bContext *C, struct wmOperator *op, struct SpaceFile *sfile);
+
void file_operator_to_sfile(bContext *C, struct SpaceFile *sfile, struct wmOperator *op);
/* filesel.c */
void fileselect_file_set(SpaceFile *sfile, const int index);
+bool file_attribute_column_type_enabled(const FileSelectParams *params,
+ FileAttributeColumnType column);
+bool file_attribute_column_header_is_inside(const struct View2D *v2d,
+ const FileLayout *layout,
+ int x,
+ int y);
+FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d,
+ const FileSelectParams *params,
+ FileLayout *layout,
+ int x);
float file_string_width(const char *str);
float file_font_pointsize(void);
@@ -122,7 +132,8 @@ int autocomplete_file(struct bContext *C, char *str, void *arg_v);
void file_params_renamefile_activate(struct SpaceFile *sfile, struct FileSelectParams *params);
/* file_panels.c */
-void file_panels_register(struct ARegionType *art);
+void file_tool_props_region_panels_register(struct ARegionType *art);
+void file_execute_region_panels_register(struct ARegionType *art);
/* file_utils.c */
void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds);
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index eb5f02b6e13..b4b51de302d 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -78,7 +78,12 @@ static FileSelection find_file_mouse_rect(SpaceFile *sfile, ARegion *ar, const r
BLI_rctf_rcti_copy(&rect_region_fl, rect_region);
+ /* Okay, manipulating v2d rects here is hacky... */
+ v2d->mask.ymax -= sfile->layout->offset_top;
+ v2d->cur.ymax -= sfile->layout->offset_top;
UI_view2d_region_to_view_rctf(v2d, &rect_region_fl, &rect_view_fl);
+ v2d->mask.ymax += sfile->layout->offset_top;
+ v2d->cur.ymax += sfile->layout->offset_top;
BLI_rcti_init(&rect_view,
(int)(v2d->tot.xmin + rect_view_fl.xmin),
@@ -190,7 +195,6 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
const bool is_parent_dir = FILENAME_IS_PARENT(file->relpath);
if (do_diropen == false) {
- params->file[0] = '\0';
retval = FILE_SELECT_DIR;
}
/* the path is too long and we are not going up! */
@@ -235,7 +239,7 @@ static bool file_is_any_selected(struct FileList *files)
int i;
/* Is any file selected ? */
- for (i = 0; i < numfiles; ++i) {
+ for (i = 0; i < numfiles; i++) {
if (filelist_entry_select_index_get(files, i, CHECK_ALL)) {
return true;
}
@@ -262,8 +266,8 @@ static void file_ensure_inside_viewbounds(ARegion *ar, SpaceFile *sfile, const i
cur->ymax = cur->ymin + ar->winy;
}
/* up */
- else if (cur->ymax < rect.ymax) {
- cur->ymax = rect.ymax + layout->tile_border_y;
+ else if ((cur->ymax - layout->offset_top) < rect.ymax) {
+ cur->ymax = rect.ymax + layout->tile_border_y + layout->offset_top;
cur->ymin = cur->ymax - ar->winy;
}
/* left - also use if tile is wider than viewbounds so view is aligned to file name */
@@ -278,7 +282,7 @@ static void file_ensure_inside_viewbounds(ARegion *ar, SpaceFile *sfile, const i
}
else {
BLI_assert(cur->xmin <= rect.xmin && cur->xmax >= rect.xmax && cur->ymin <= rect.ymin &&
- cur->ymax >= rect.ymax);
+ (cur->ymax - layout->offset_top) >= rect.ymax);
changed = false;
}
@@ -384,7 +388,7 @@ static int file_box_select_modal(bContext *C, wmOperator *op, const wmEvent *eve
if (result == OPERATOR_RUNNING_MODAL) {
WM_operator_properties_border_to_rcti(op, &rect);
- BLI_rcti_isect(&(ar->v2d.mask), &rect, &rect);
+ ED_fileselect_layout_isect_rect(sfile->layout, &ar->v2d, &rect, &rect);
sel = file_selection_get(C, &rect, 0);
if ((sel.first != params->sel_first) || (sel.last != params->sel_last)) {
@@ -440,13 +444,13 @@ static int file_box_select_exec(bContext *C, wmOperator *op)
file_deselect_all(sfile, FILE_SEL_SELECTED);
}
- BLI_rcti_isect(&(ar->v2d.mask), &rect, &rect);
+ ED_fileselect_layout_isect_rect(sfile->layout, &ar->v2d, &rect, &rect);
ret = file_select(C, &rect, select ? FILE_SEL_ADD : FILE_SEL_REMOVE, false, false);
/* unselect '..' parent entry - it's not supposed to be selected if more than
* one file is selected */
- filelist_entry_select_index_set(sfile->files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
+ filelist_entry_parent_select_set(sfile->files, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
if (FILE_SELECT_DIR == ret) {
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -485,6 +489,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const bool extend = RNA_boolean_get(op->ptr, "extend");
const bool fill = RNA_boolean_get(op->ptr, "fill");
const bool do_diropen = RNA_boolean_get(op->ptr, "open");
+ const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
if (ar->regiontype != RGN_TYPE_WINDOW) {
return OPERATOR_CANCELLED;
@@ -493,7 +498,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
rect.xmin = rect.xmax = event->mval[0];
rect.ymin = rect.ymax = event->mval[1];
- if (!BLI_rcti_isect_pt(&ar->v2d.mask, rect.xmin, rect.ymin)) {
+ if (!ED_fileselect_layout_is_inside_pt(sfile->layout, &ar->v2d, rect.xmin, rect.ymin)) {
return OPERATOR_CANCELLED;
}
@@ -514,14 +519,18 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (extend) {
/* unselect '..' parent entry - it's not supposed to be selected if more
* than one file is selected */
- filelist_entry_select_index_set(
- sfile->files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
+ filelist_entry_parent_select_set(sfile->files, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
}
- if (FILE_SELECT_DIR == ret) {
+ if (ret == FILE_SELECT_NOTHING) {
+ if (deselect_all) {
+ file_deselect_all(sfile, FILE_SEL_SELECTED);
+ }
+ }
+ else if (ret == FILE_SELECT_DIR) {
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
- else if (FILE_SELECT_FILE == ret) {
+ else if (ret == FILE_SELECT_FILE) {
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
}
@@ -537,8 +546,8 @@ void FILE_OT_select(wmOperatorType *ot)
/* identifiers */
ot->name = "Select";
- ot->description = "Activate/select file";
ot->idname = "FILE_OT_select";
+ ot->description = "Handle mouse clicks to select and activate items";
/* api callbacks */
ot->invoke = file_select_invoke;
@@ -556,6 +565,12 @@ void FILE_OT_select(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "open", true, "Open", "Open a directory when selecting it");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna,
+ "deselect_all",
+ false,
+ "Deselect On Nothing",
+ "Deselect all when nothing under the cursor");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/**
@@ -580,6 +595,11 @@ static bool file_walk_select_selection_set(bContext *C,
BLI_assert(params);
+ if (numfiles == 0) {
+ /* No files visible, nothing to do. */
+ return false;
+ }
+
if (has_selection) {
if (extend && filelist_entry_select_index_get(files, active_old, CHECK_ALL) &&
filelist_entry_select_index_get(files, active_new, CHECK_ALL)) {
@@ -609,7 +629,7 @@ static bool file_walk_select_selection_set(bContext *C,
}
/* select first file */
else if (ELEM(direction, FILE_SELECT_WALK_DOWN, FILE_SELECT_WALK_RIGHT)) {
- params->active_file = active = extend ? 1 : 0;
+ params->active_file = active = 0;
}
else {
BLI_assert(0);
@@ -626,7 +646,7 @@ static bool file_walk_select_selection_set(bContext *C,
/* unselect '..' parent entry - it's not supposed to be selected if more
* than one file is selected */
- filelist_entry_select_index_set(files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
+ filelist_entry_parent_select_set(files, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
}
else {
/* deselect all first */
@@ -641,11 +661,6 @@ static bool file_walk_select_selection_set(bContext *C,
if (fill) {
FileSelection sel = {MIN2(active, last_sel), MAX2(active, last_sel)};
- /* clamping selection to not include '..' parent entry */
- if (sel.first == 0) {
- sel.first = 1;
- }
-
/* fill selection between last and first selected file */
filelist_entries_select_index_range_set(
files, &sel, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
@@ -653,6 +668,12 @@ static bool file_walk_select_selection_set(bContext *C,
if (deselect) {
filelist_entry_select_index_set(files, active, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
}
+
+ /* unselect '..' parent entry - it's not supposed to be selected if more
+ * than one file is selected */
+ if ((sel.last - sel.first) > 1) {
+ filelist_entry_parent_select_set(files, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
+ }
}
else {
filelist_entry_select_index_set(
@@ -688,10 +709,15 @@ static bool file_walk_select_do(bContext *C,
/* *** get all needed files for handling selection *** */
+ if (numfiles == 0) {
+ /* No files visible, nothing to do. */
+ return false;
+ }
+
if (has_selection) {
ARegion *ar = CTX_wm_region(C);
FileLayout *layout = ED_fileselect_get_layout(sfile, ar);
- const int idx_shift = (layout->flag & FILE_LAYOUT_HOR) ? layout->rows : layout->columns;
+ const int idx_shift = (layout->flag & FILE_LAYOUT_HOR) ? layout->rows : layout->flow_columns;
if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_UP) ||
(layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_LEFT)) {
@@ -718,7 +744,7 @@ static bool file_walk_select_do(bContext *C,
BLI_assert(0);
}
- if (!IN_RANGE(active_new, 0, numfiles)) {
+ if (!IN_RANGE(active_new, -1, numfiles)) {
if (extend) {
/* extend to invalid file -> abort */
return false;
@@ -1185,7 +1211,7 @@ int file_highlight_set(SpaceFile *sfile, ARegion *ar, int mx, int my)
mx -= ar->winrct.xmin;
my -= ar->winrct.ymin;
- if (BLI_rcti_isect_pt(&ar->v2d.mask, mx, my)) {
+ if (ED_fileselect_layout_is_inside_pt(sfile->layout, v2d, mx, my)) {
float fx, fy;
int highlight_file;
@@ -1234,6 +1260,53 @@ void FILE_OT_highlight(struct wmOperatorType *ot)
ot->poll = ED_operator_file_active;
}
+static int file_column_sort_ui_context_invoke(bContext *C,
+ wmOperator *UNUSED(op),
+ const wmEvent *event)
+{
+ const ARegion *ar = CTX_wm_region(C);
+ SpaceFile *sfile = CTX_wm_space_file(C);
+
+ if (file_attribute_column_header_is_inside(
+ &ar->v2d, sfile->layout, event->mval[0], event->mval[1])) {
+ const FileAttributeColumnType column_type = file_attribute_column_type_find_isect(
+ &ar->v2d, sfile->params, sfile->layout, event->mval[0]);
+
+ if (column_type != COLUMN_NONE) {
+ const FileAttributeColumn *column = &sfile->layout->attribute_columns[column_type];
+
+ if (column->sort_type != FILE_SORT_NONE) {
+ if (sfile->params->sort == column->sort_type) {
+ /* Already sorting by selected column -> toggle sort invert (three state logic). */
+ sfile->params->flag ^= FILE_SORT_INVERT;
+ }
+ else {
+ sfile->params->sort = column->sort_type;
+ sfile->params->flag &= ~FILE_SORT_INVERT;
+ }
+
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+ }
+ }
+ }
+
+ return OPERATOR_PASS_THROUGH;
+}
+
+void FILE_OT_sort_column_ui_context(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Sort from Column";
+ ot->description = "Change sorting to use column under cursor";
+ ot->idname = "FILE_OT_sort_column_ui_context";
+
+ /* api callbacks */
+ ot->invoke = file_column_sort_ui_context_invoke;
+ ot->poll = ED_operator_file_active;
+
+ ot->flag = OPTYPE_INTERNAL;
+}
+
int file_cancel_exec(bContext *C, wmOperator *UNUSED(unused))
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -1433,14 +1506,11 @@ void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
bool file_draw_check_exists(SpaceFile *sfile)
{
if (sfile->op) { /* fails on reload */
- PropertyRNA *prop;
- if ((prop = RNA_struct_find_property(sfile->op->ptr, "check_existing"))) {
- if (RNA_property_boolean_get(sfile->op->ptr, prop)) {
- char filepath[FILE_MAX];
- BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file);
- if (BLI_is_file(filepath)) {
- return true;
- }
+ if (sfile->params && (sfile->params->flag & FILE_CHECK_EXISTING)) {
+ char filepath[FILE_MAX];
+ BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file);
+ if (BLI_is_file(filepath)) {
+ return true;
}
}
}
@@ -1683,7 +1753,7 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w
/* check if we are editing a name */
int edit_idx = -1;
- for (i = 0; i < numfiles; ++i) {
+ for (i = 0; i < numfiles; i++) {
if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL) &
(FILE_SEL_EDITING | FILE_SEL_HIGHLIGHTED)) {
edit_idx = i;
@@ -1713,7 +1783,7 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w
/* Number of items in a block (i.e. lines in a column in horizontal layout, or columns in a line
* in vertical layout).
*/
- const int items_block_size = is_horizontal ? sfile->layout->rows : sfile->layout->columns;
+ const int items_block_size = is_horizontal ? sfile->layout->rows : sfile->layout->flow_columns;
/* Scroll offset is the first file in the row/column we are editing in. */
if (sfile->scroll_offset == 0) {
@@ -1915,6 +1985,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
ScrArea *sa = CTX_wm_area(C);
+ const bool do_diropen = RNA_boolean_get(op->ptr, "open");
if (!sfile->params) {
BKE_report(op->reports, RPT_WARNING, "No parent directory given");
@@ -1963,9 +2034,11 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* now remember file to jump into editing */
- BLI_strncpy(sfile->params->renamefile, name, FILE_MAXFILE);
- sfile->params->rename_flag = FILE_PARAMS_RENAME_PENDING;
+ /* If we don't enter the directory directly, remember file to jump into editing. */
+ if (do_diropen == false) {
+ BLI_strncpy(sfile->params->renamefile, name, FILE_MAXFILE);
+ sfile->params->rename_flag = FILE_PARAMS_RENAME_PENDING;
+ }
/* set timer to smoothly view newly generated file */
/* max 30 frs/sec */
@@ -1978,7 +2051,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
/* reload dir to make sure we're seeing what's in the directory */
ED_fileselect_clear(wm, sa, sfile);
- if (RNA_boolean_get(op->ptr, "open")) {
+ if (do_diropen) {
BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir));
ED_file_change_dir(C);
}
@@ -1998,7 +2071,7 @@ void FILE_OT_directory_new(struct wmOperatorType *ot)
ot->idname = "FILE_OT_directory_new";
/* api callbacks */
- ot->invoke = WM_operator_confirm;
+ ot->invoke = WM_operator_confirm_or_exec;
ot->exec = file_directory_new_exec;
ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
@@ -2007,6 +2080,7 @@ void FILE_OT_directory_new(struct wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "open", false, "Open", "Open new directory");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ WM_operator_properties_confirm_or_exec(ot);
}
/* TODO This should go to BLI_path_utils. */
@@ -2075,6 +2149,10 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile->params) {
+ char old_dir[sizeof(sfile->params->dir)];
+
+ BLI_strncpy(old_dir, sfile->params->dir, sizeof(old_dir));
+
file_expand_directory(C);
/* special case, user may have pasted a filepath into the directory */
@@ -2108,8 +2186,10 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
BLI_cleanup_dir(BKE_main_blendfile_path(bmain), sfile->params->dir);
if (filelist_is_dir(sfile->files, sfile->params->dir)) {
- /* if directory exists, enter it immediately */
- ED_file_change_dir(C);
+ if (!STREQ(sfile->params->dir, old_dir)) { /* Avoids flickering when nothing's changed. */
+ /* if directory exists, enter it immediately */
+ ED_file_change_dir(C);
+ }
/* don't do for now because it selects entire text instead of
* placing cursor at the end */
@@ -2138,6 +2218,8 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
WM_operator_properties_create_ptr(&ptr, ot);
RNA_string_set(&ptr, "directory", sfile->params->dir);
RNA_boolean_set(&ptr, "open", true);
+ /* Enable confirmation prompt, else it's too easy to accidentaly create new directories. */
+ RNA_boolean_set(&ptr, "confirm", true);
if (lastdir) {
BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir));
@@ -2239,57 +2321,15 @@ void FILE_OT_hidedot(struct wmOperatorType *ot)
ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
}
-ARegion *file_tools_region(ScrArea *sa)
+static bool file_filenum_poll(bContext *C)
{
- ARegion *ar, *arnew;
-
- if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS)) != NULL) {
- return ar;
- }
-
- /* add subdiv level; after header */
- ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
-
- /* is error! */
- if (ar == NULL) {
- return NULL;
- }
-
- arnew = MEM_callocN(sizeof(ARegion), "tools for file");
- BLI_insertlinkafter(&sa->regionbase, ar, arnew);
- arnew->regiontype = RGN_TYPE_TOOLS;
- arnew->alignment = RGN_ALIGN_LEFT;
-
- ar = MEM_callocN(sizeof(ARegion), "tool props for file");
- BLI_insertlinkafter(&sa->regionbase, arnew, ar);
- ar->regiontype = RGN_TYPE_TOOL_PROPS;
- ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
-
- return arnew;
-}
-
-static int file_bookmark_toggle_exec(bContext *C, wmOperator *UNUSED(unused))
-{
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = file_tools_region(sa);
+ SpaceFile *sfile = CTX_wm_space_file(C);
- if (ar) {
- ED_region_toggle_hidden(C, ar);
+ if (!ED_operator_file_active(C)) {
+ return false;
}
- return OPERATOR_FINISHED;
-}
-
-void FILE_OT_bookmark_toggle(struct wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Toggle Bookmarks";
- ot->description = "Toggle bookmarks display";
- ot->idname = "FILE_OT_bookmark_toggle";
-
- /* api callbacks */
- ot->exec = file_bookmark_toggle_exec;
- ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
+ return sfile->params && (sfile->params->flag & FILE_CHECK_EXISTING);
}
/**
@@ -2349,7 +2389,7 @@ void FILE_OT_filenum(struct wmOperatorType *ot)
/* api callbacks */
ot->exec = file_filenum_exec;
- ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
+ ot->poll = file_filenum_poll;
/* props */
RNA_def_int(ot->srna, "increment", 1, -100, 100, "Increment", "", -100, 100);
diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c
index d9a6e70121f..9ba098fcf45 100644
--- a/source/blender/editors/space_file/file_panels.c
+++ b/source/blender/editors/space_file/file_panels.c
@@ -95,7 +95,7 @@ static void file_panel_operator(const bContext *C, Panel *pa)
UI_block_func_set(uiLayoutGetBlock(pa->layout), NULL, NULL, NULL);
}
-void file_panels_register(ARegionType *art)
+void file_tool_props_region_panels_register(ARegionType *art)
{
PanelType *pt;
@@ -103,8 +103,122 @@ void file_panels_register(ARegionType *art)
strcpy(pt->idname, "FILE_PT_operator");
strcpy(pt->label, N_("Operator"));
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ pt->flag = PNL_NO_HEADER;
pt->poll = file_panel_operator_poll;
pt->draw_header = file_panel_operator_header;
pt->draw = file_panel_operator;
BLI_addtail(&art->paneltypes, pt);
}
+
+static void file_panel_execution_cancel_button(uiLayout *layout)
+{
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiLayoutSetScaleX(row, 0.8f);
+ uiLayoutSetFixedSize(row, true);
+ uiItemO(row, IFACE_("Cancel"), ICON_NONE, "FILE_OT_cancel");
+}
+
+static void file_panel_execution_execute_button(uiLayout *layout, const char *title)
+{
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiLayoutSetScaleX(row, 0.8f);
+ uiLayoutSetFixedSize(row, true);
+ /* Just a display hint. */
+ uiLayoutSetActiveDefault(row, true);
+ uiItemO(row, title, ICON_NONE, "FILE_OT_execute");
+}
+
+static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa)
+{
+ bScreen *screen = CTX_wm_screen(C);
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ FileSelectParams *params = ED_fileselect_get_params(sfile);
+ uiBlock *block = uiLayoutGetBlock(pa->layout);
+ uiBut *but;
+ uiLayout *row;
+ PointerRNA params_rna_ptr, *but_extra_rna_ptr;
+
+ const bool overwrite_alert = file_draw_check_exists(sfile);
+ const bool windows_layout =
+#ifdef _WIN32
+ true;
+#else
+ false;
+#endif
+
+ RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, &params_rna_ptr);
+
+ row = uiLayoutRow(pa->layout, false);
+ uiLayoutSetScaleY(row, 1.3f);
+
+ /* callbacks for operator check functions */
+ UI_block_func_set(block, file_draw_check_cb, NULL, NULL);
+
+ but = uiDefButR(block,
+ UI_BTYPE_TEXT,
+ -1,
+ "",
+ 0,
+ 0,
+ UI_UNIT_X * 5,
+ UI_UNIT_Y,
+ &params_rna_ptr,
+ "filename",
+ 0,
+ 0.0f,
+ (float)FILE_MAXFILE,
+ 0,
+ 0,
+ TIP_(overwrite_alert ? N_("File name, overwrite existing") : N_("File name")));
+
+ BLI_assert(!UI_but_flag_is_set(but, UI_BUT_UNDO));
+ BLI_assert(!UI_but_is_utf8(but));
+
+ UI_but_func_complete_set(but, autocomplete_file, NULL);
+ /* silly workaround calling NFunc to ensure this does not get called
+ * immediate ui_apply_but_func but only after button deactivates */
+ UI_but_funcN_set(but, file_filename_enter_handle, NULL, but);
+
+ if (params->flag & FILE_CHECK_EXISTING) {
+ but_extra_rna_ptr = UI_but_extra_operator_icon_add(
+ but, "FILE_OT_filenum", WM_OP_EXEC_REGION_WIN, ICON_ADD);
+ RNA_int_set(but_extra_rna_ptr, "increment", 1);
+ but_extra_rna_ptr = UI_but_extra_operator_icon_add(
+ but, "FILE_OT_filenum", WM_OP_EXEC_REGION_WIN, ICON_REMOVE);
+ RNA_int_set(but_extra_rna_ptr, "increment", -1);
+ }
+
+ /* check if this overrides a file and if the operator option is used */
+ if (overwrite_alert) {
+ UI_but_flag_enable(but, UI_BUT_REDALERT);
+ }
+ UI_block_func_set(block, NULL, NULL, NULL);
+
+ {
+ uiLayout *sub = uiLayoutRow(row, false);
+ uiLayoutSetOperatorContext(sub, WM_OP_EXEC_REGION_WIN);
+
+ if (windows_layout) {
+ file_panel_execution_execute_button(sub, params->title);
+ file_panel_execution_cancel_button(sub);
+ }
+ else {
+ file_panel_execution_cancel_button(sub);
+ file_panel_execution_execute_button(sub, params->title);
+ }
+ }
+}
+
+void file_execute_region_panels_register(ARegionType *art)
+{
+ PanelType *pt;
+
+ pt = MEM_callocN(sizeof(PanelType), "spacetype file execution buttons");
+ strcpy(pt->idname, "FILE_PT_execution_buttons");
+ strcpy(pt->label, N_("Execute Buttons"));
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ pt->flag = PNL_NO_HEADER;
+ pt->poll = file_panel_operator_poll;
+ pt->draw = file_panel_execution_buttons_draw;
+ BLI_addtail(&art->paneltypes, pt);
+}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index f7dda1defe8..27cccf6bab1 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -329,25 +329,21 @@ enum {
FL_IS_PENDING = 1 << 2,
FL_NEED_SORTING = 1 << 3,
FL_NEED_FILTERING = 1 << 4,
+ FL_SORT_INVERT = 1 << 5,
};
-#define SPECIAL_IMG_SIZE 48
-#define SPECIAL_IMG_ROWS 4
-#define SPECIAL_IMG_COLS 4
+#define SPECIAL_IMG_SIZE 256
+#define SPECIAL_IMG_ROWS 1
+#define SPECIAL_IMG_COLS 7
enum {
- SPECIAL_IMG_FOLDER = 0,
- SPECIAL_IMG_PARENT = 1,
- SPECIAL_IMG_REFRESH = 2,
- SPECIAL_IMG_BLENDFILE = 3,
- SPECIAL_IMG_SOUNDFILE = 4,
- SPECIAL_IMG_MOVIEFILE = 5,
- SPECIAL_IMG_PYTHONFILE = 6,
- SPECIAL_IMG_TEXTFILE = 7,
- SPECIAL_IMG_FONTFILE = 8,
- SPECIAL_IMG_UNKNOWNFILE = 9,
- SPECIAL_IMG_LOADING = 10,
- SPECIAL_IMG_BACKUP = 11,
+ SPECIAL_IMG_DOCUMENT = 0,
+ SPECIAL_IMG_UNSUPORTED = 1,
+ SPECIAL_IMG_FOLDER = 2,
+ SPECIAL_IMG_PARENT = 3,
+ SPECIAL_IMG_DRIVE_FIXED = 4,
+ SPECIAL_IMG_DRIVE_ATTACHED = 5,
+ SPECIAL_IMG_DRIVE_REMOTE = 6,
SPECIAL_IMG_MAX,
};
@@ -369,6 +365,19 @@ static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size);
/* ********** Sort helpers ********** */
+struct FileSortData {
+ bool inverted;
+};
+
+static int compare_apply_inverted(int val, const struct FileSortData *sort_data)
+{
+ return sort_data->inverted ? -val : val;
+}
+
+/**
+ * Handles inverted sorting itself (currently there's nothing to invert), so if this returns non-0,
+ * it should be used as-is and not inverted.
+ */
static int compare_direntry_generic(const FileListInternEntry *entry1,
const FileListInternEntry *entry2)
{
@@ -420,10 +429,11 @@ static int compare_direntry_generic(const FileListInternEntry *entry1,
return 0;
}
-static int compare_name(void *UNUSED(user_data), const void *a1, const void *a2)
+static int compare_name(void *user_data, const void *a1, const void *a2)
{
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
+ const struct FileSortData *sort_data = user_data;
char *name1, *name2;
int ret;
@@ -434,13 +444,14 @@ static int compare_name(void *UNUSED(user_data), const void *a1, const void *a2)
name1 = entry1->name;
name2 = entry2->name;
- return BLI_natstrcmp(name1, name2);
+ return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
}
-static int compare_date(void *UNUSED(user_data), const void *a1, const void *a2)
+static int compare_date(void *user_data, const void *a1, const void *a2)
{
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
+ const struct FileSortData *sort_data = user_data;
char *name1, *name2;
int64_t time1, time2;
int ret;
@@ -452,22 +463,23 @@ static int compare_date(void *UNUSED(user_data), const void *a1, const void *a2)
time1 = (int64_t)entry1->st.st_mtime;
time2 = (int64_t)entry2->st.st_mtime;
if (time1 < time2) {
- return 1;
+ return compare_apply_inverted(1, sort_data);
}
if (time1 > time2) {
- return -1;
+ return compare_apply_inverted(-1, sort_data);
}
name1 = entry1->name;
name2 = entry2->name;
- return BLI_natstrcmp(name1, name2);
+ return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
}
-static int compare_size(void *UNUSED(user_data), const void *a1, const void *a2)
+static int compare_size(void *user_data, const void *a1, const void *a2)
{
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
+ const struct FileSortData *sort_data = user_data;
char *name1, *name2;
uint64_t size1, size2;
int ret;
@@ -479,22 +491,23 @@ static int compare_size(void *UNUSED(user_data), const void *a1, const void *a2)
size1 = entry1->st.st_size;
size2 = entry2->st.st_size;
if (size1 < size2) {
- return 1;
+ return compare_apply_inverted(1, sort_data);
}
if (size1 > size2) {
- return -1;
+ return compare_apply_inverted(-1, sort_data);
}
name1 = entry1->name;
name2 = entry2->name;
- return BLI_natstrcmp(name1, name2);
+ return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
}
-static int compare_extension(void *UNUSED(user_data), const void *a1, const void *a2)
+static int compare_extension(void *user_data, const void *a1, const void *a2)
{
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
+ const struct FileSortData *sort_data = user_data;
char *name1, *name2;
int ret;
@@ -516,10 +529,10 @@ static int compare_extension(void *UNUSED(user_data), const void *a1, const void
return -1;
}
if (entry1->blentype < entry2->blentype) {
- return -1;
+ return compare_apply_inverted(-1, sort_data);
}
if (entry1->blentype > entry2->blentype) {
- return 1;
+ return compare_apply_inverted(1, sort_data);
}
}
else {
@@ -539,48 +552,58 @@ static int compare_extension(void *UNUSED(user_data), const void *a1, const void
}
if ((ret = BLI_strcasecmp(sufix1, sufix2))) {
- return ret;
+ return compare_apply_inverted(ret, sort_data);
}
}
name1 = entry1->name;
name2 = entry2->name;
- return BLI_natstrcmp(name1, name2);
+ return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
}
void filelist_sort(struct FileList *filelist)
{
if ((filelist->flags & FL_NEED_SORTING) && (filelist->sort != FILE_SORT_NONE)) {
+ void *sort_cb = NULL;
+
switch (filelist->sort) {
case FILE_SORT_ALPHA:
- BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_name, NULL);
+ sort_cb = compare_name;
break;
case FILE_SORT_TIME:
- BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_date, NULL);
+ sort_cb = compare_date;
break;
case FILE_SORT_SIZE:
- BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_size, NULL);
+ sort_cb = compare_size;
break;
case FILE_SORT_EXTENSION:
- BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_extension, NULL);
+ sort_cb = compare_extension;
break;
case FILE_SORT_NONE: /* Should never reach this point! */
default:
BLI_assert(0);
break;
}
+ BLI_listbase_sort_r(
+ &filelist->filelist_intern.entries,
+ sort_cb,
+ &(struct FileSortData){.inverted = (filelist->flags & FL_SORT_INVERT) != 0});
filelist_filter_clear(filelist);
filelist->flags &= ~FL_NEED_SORTING;
}
}
-void filelist_setsorting(struct FileList *filelist, const short sort)
+void filelist_setsorting(struct FileList *filelist, const short sort, bool invert_sort)
{
- if (filelist->sort != sort) {
+ const bool was_invert_sort = filelist->flags & FL_SORT_INVERT;
+
+ if ((filelist->sort != sort) || (was_invert_sort != invert_sort)) {
filelist->sort = sort;
filelist->flags |= FL_NEED_SORTING;
+ filelist->flags = invert_sort ? (filelist->flags | FL_SORT_INVERT) :
+ (filelist->flags & ~FL_SORT_INVERT);
}
}
@@ -635,9 +658,9 @@ static bool is_filtered_file(FileListInternEntry *file,
{
bool is_filtered = !is_hidden_file(file->relpath, filter);
- if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) {
+ if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) {
/* We only check for types if some type are enabled in filtering. */
- if (filter->filter) {
+ if (filter->filter && (filter->flags & FLF_DO_FILTER)) {
if (file->typeflag & FILE_TYPE_DIR) {
if (file->typeflag &
(FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
@@ -657,6 +680,7 @@ static bool is_filtered_file(FileListInternEntry *file,
}
}
}
+ /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
if (is_filtered && (filter->filter_search[0] != '\0')) {
if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) {
is_filtered = false;
@@ -676,9 +700,9 @@ static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileLis
if (BLO_library_path_explode(path, dir, &group, &name)) {
is_filtered = !is_hidden_file(file->relpath, filter);
- if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) {
+ if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) {
/* We only check for types if some type are enabled in filtering. */
- if (filter->filter || filter->filter_id) {
+ if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) {
if (file->typeflag & FILE_TYPE_DIR) {
if (file->typeflag &
(FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
@@ -704,6 +728,7 @@ static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileLis
}
}
}
+ /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
if (is_filtered && (filter->filter_search[0] != '\0')) {
if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) {
is_filtered = false;
@@ -870,7 +895,7 @@ void filelist_free_icons(void)
BLI_assert(G.background == false);
- for (i = 0; i < SPECIAL_IMG_MAX; ++i) {
+ for (i = 0; i < SPECIAL_IMG_MAX; i++) {
IMB_freeImBuf(gSpecialFileImages[i]);
gSpecialFileImages[i] = NULL;
}
@@ -904,42 +929,12 @@ static ImBuf *filelist_geticon_image_ex(const unsigned int typeflag, const char
if (FILENAME_IS_PARENT(relpath)) {
ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT];
}
- else if (FILENAME_IS_CURRENT(relpath)) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH];
- }
else {
ibuf = gSpecialFileImages[SPECIAL_IMG_FOLDER];
}
}
- else if (typeflag & FILE_TYPE_BLENDER) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE];
- }
- else if (typeflag & FILE_TYPE_BLENDERLIB) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE];
- }
- else if (typeflag & (FILE_TYPE_MOVIE)) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE];
- }
- else if (typeflag & FILE_TYPE_SOUND) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE];
- }
- else if (typeflag & FILE_TYPE_PYSCRIPT) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE];
- }
- else if (typeflag & FILE_TYPE_FTFONT) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE];
- }
- else if (typeflag & FILE_TYPE_TEXT) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE];
- }
- else if (typeflag & FILE_TYPE_IMAGE) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING];
- }
- else if (typeflag & FILE_TYPE_BLENDER_BACKUP) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_BACKUP];
- }
else {
- ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE];
+ ibuf = gSpecialFileImages[SPECIAL_IMG_DOCUMENT];
}
return ibuf;
@@ -1001,14 +996,20 @@ static int filelist_geticon_ex(const int typeflag,
return ICON_FILE_BLANK;
}
else if (typeflag & FILE_TYPE_COLLADA) {
- return ICON_FILE_BLANK;
+ return ICON_FILE_3D;
}
else if (typeflag & FILE_TYPE_ALEMBIC) {
- return ICON_FILE_BLANK;
+ return ICON_FILE_3D;
+ }
+ else if (typeflag & FILE_TYPE_OBJECT_IO) {
+ return ICON_FILE_3D;
}
else if (typeflag & FILE_TYPE_TEXT) {
return ICON_FILE_TEXT;
}
+ else if (typeflag & FILE_TYPE_ARCHIVE) {
+ return ICON_FILE_ARCHIVE;
+ }
else if (typeflag & FILE_TYPE_BLENDERLIB) {
const int ret = UI_idcode_icon_get(blentype);
if (ret != ICON_NONE) {
@@ -1243,7 +1244,8 @@ static void filelist_cache_previews_clear(FileListEntryCache *cache)
BLI_task_pool_cancel(cache->previews_pool);
while ((preview = BLI_thread_queue_pop_timeout(cache->previews_done, 0))) {
- // printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
+ // printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path,
+ // preview->img);
if (preview->img) {
IMB_freeImBuf(preview->img);
}
@@ -2128,6 +2130,12 @@ int ED_path_extension_type(const char *path)
else if (BLI_path_extension_check(path, ".abc")) {
return FILE_TYPE_ALEMBIC;
}
+ else if (BLI_path_extension_check(path, ".zip")) {
+ return FILE_TYPE_ARCHIVE;
+ }
+ else if (BLI_path_extension_check_n(path, ".obj", ".3ds", ".fbx", ".glb", ".gltf", NULL)) {
+ return FILE_TYPE_OBJECT_IO;
+ }
else if (BLI_path_extension_check_array(path, imb_ext_image)) {
return FILE_TYPE_IMAGE;
}
@@ -2177,11 +2185,13 @@ int ED_file_extension_icon(const char *path)
case FILE_TYPE_BTX:
return ICON_FILE_BLANK;
case FILE_TYPE_COLLADA:
- return ICON_FILE_BLANK;
case FILE_TYPE_ALEMBIC:
- return ICON_FILE_BLANK;
+ case FILE_TYPE_OBJECT_IO:
+ return ICON_FILE_3D;
case FILE_TYPE_TEXT:
return ICON_FILE_TEXT;
+ case FILE_TYPE_ARCHIVE:
+ return ICON_FILE_ARCHIVE;
default:
return ICON_FILE_BLANK;
}
@@ -2298,6 +2308,19 @@ unsigned int filelist_entry_select_index_get(FileList *filelist,
return 0;
}
+/**
+ * Set selection of the '..' parent entry, but only if it's actually visible.
+ */
+void filelist_entry_parent_select_set(FileList *filelist,
+ FileSelType select,
+ unsigned int flag,
+ FileCheckType check)
+{
+ if ((filelist->filter_data.flags & FLF_HIDE_PARENT) == 0) {
+ filelist_entry_select_index_set(filelist, 0, select, flag, check);
+ }
+}
+
/* WARNING! dir must be FILE_MAX_LIBEXTRA long! */
bool filelist_islibrary(struct FileList *filelist, char *dir, char **group)
{
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index caf77246797..9b1107294ff 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -55,7 +55,7 @@ void folderlist_pushdir(struct ListBase *folderlist, const char *dir);
const char *folderlist_peeklastdir(struct ListBase *folderdist);
int folderlist_clear_next(struct SpaceFile *sfile);
-void filelist_setsorting(struct FileList *filelist, const short sort);
+void filelist_setsorting(struct FileList *filelist, const short sort, bool invert_sort);
void filelist_sort(struct FileList *filelist);
void filelist_setfilter_options(struct FileList *filelist,
@@ -117,6 +117,10 @@ unsigned int filelist_entry_select_get(struct FileList *filelist,
unsigned int filelist_entry_select_index_get(struct FileList *filelist,
const int index,
FileCheckType check);
+void filelist_entry_parent_select_set(struct FileList *filelist,
+ FileSelType select,
+ unsigned int flag,
+ FileCheckType check);
void filelist_setrecursion(struct FileList *filelist, const int recursion_level);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index db42d007b8e..e2c9bb8d6e5 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -49,6 +49,10 @@
#include "BLI_utildefines.h"
#include "BLI_fnmatch.h"
+#include "BLO_readfile.h"
+
+#include "BLT_translation.h"
+
#include "BKE_appdir.h"
#include "BKE_context.h"
#include "BKE_main.h"
@@ -69,6 +73,8 @@
#include "file_intern.h"
#include "filelist.h"
+#define VERTLIST_MAJORCOLUMN_WIDTH (25 * UI_UNIT_X)
+
FileSelectParams *ED_fileselect_get_params(struct SpaceFile *sfile)
{
if (!sfile->params) {
@@ -98,7 +104,9 @@ short ED_fileselect_set_params(SpaceFile *sfile)
sizeof(sfile->params->file));
sfile->params->filter_glob[0] = '\0';
/* set the default thumbnails size */
- sfile->params->thumbnail_size = 128;
+ sfile->params->thumbnail_size = U_default.file_space_data.thumbnail_size;
+ /* Show size column by default. */
+ sfile->params->details_flags = U_default.file_space_data.details_flags;
}
params = sfile->params;
@@ -161,6 +169,13 @@ short ED_fileselect_set_params(SpaceFile *sfile)
params->flag &= ~FILE_DIRSEL_ONLY;
}
+ if ((prop = RNA_struct_find_property(op->ptr, "check_existing"))) {
+ params->flag |= RNA_property_boolean_get(op->ptr, prop) ? FILE_CHECK_EXISTING : 0;
+ }
+ if ((prop = RNA_struct_find_property(op->ptr, "hide_props_region"))) {
+ params->flag |= RNA_property_boolean_get(op->ptr, prop) ? FILE_HIDE_TOOL_PROPS : 0;
+ }
+
params->filter = 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_blender"))) {
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BLENDER : 0;
@@ -189,6 +204,9 @@ short ED_fileselect_set_params(SpaceFile *sfile)
if ((prop = RNA_struct_find_property(op->ptr, "filter_text"))) {
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_TEXT : 0;
}
+ if ((prop = RNA_struct_find_property(op->ptr, "filter_archive"))) {
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_ARCHIVE : 0;
+ }
if ((prop = RNA_struct_find_property(op->ptr, "filter_folder"))) {
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_FOLDER : 0;
}
@@ -258,26 +276,11 @@ short ED_fileselect_set_params(SpaceFile *sfile)
params->sort = RNA_property_enum_get(op->ptr, prop);
}
else {
- params->sort = FILE_SORT_ALPHA;
+ params->sort = U_default.file_space_data.sort_type;
}
if (params->display == FILE_DEFAULTDISPLAY) {
- if (params->display_previous == FILE_DEFAULTDISPLAY) {
- if (U.uiflag & USER_SHOW_THUMBNAILS) {
- if (params->filter & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT)) {
- params->display = FILE_IMGDISPLAY;
- }
- else {
- params->display = FILE_SHORTDISPLAY;
- }
- }
- else {
- params->display = FILE_SHORTDISPLAY;
- }
- }
- else {
- params->display = params->display_previous;
- }
+ params->display = U_default.file_space_data.display_type;
}
if (is_relative_path) {
@@ -291,10 +294,9 @@ short ED_fileselect_set_params(SpaceFile *sfile)
else {
/* default values, if no operator */
params->type = FILE_UNIX;
- params->flag |= FILE_HIDE_DOT;
+ params->flag |= U_default.file_space_data.flag;
params->flag &= ~FILE_DIRSEL_ONLY;
- params->display = FILE_SHORTDISPLAY;
- params->display_previous = FILE_DEFAULTDISPLAY;
+ params->display = FILE_VERTICALDISPLAY;
params->sort = FILE_SORT_ALPHA;
params->filter = 0;
params->filter_glob[0] = '\0';
@@ -330,6 +332,63 @@ short ED_fileselect_set_params(SpaceFile *sfile)
return 1;
}
+/* The subset of FileSelectParams.flag items we store into preferences. */
+#define PARAMS_FLAGS_REMEMBERED (FILE_HIDE_DOT | FILE_SORT_INVERT)
+
+void ED_fileselect_set_params_from_userdef(SpaceFile *sfile)
+{
+ wmOperator *op = sfile->op;
+ UserDef_FileSpaceData *sfile_udata = &U.file_space_data;
+
+ ED_fileselect_set_params(sfile);
+
+ if (!op) {
+ return;
+ }
+
+ if (!RNA_struct_property_is_set(op->ptr, "display_type")) {
+ sfile->params->display = sfile_udata->display_type;
+ }
+ if (!RNA_struct_property_is_set(op->ptr, "sort_method")) {
+ sfile->params->sort = sfile_udata->sort_type;
+ }
+ sfile->params->thumbnail_size = sfile_udata->thumbnail_size;
+ sfile->params->details_flags = sfile_udata->details_flags;
+
+ /* Combine flags we take from params with the flags we take from userdef. */
+ sfile->params->flag = (sfile->params->flag & ~PARAMS_FLAGS_REMEMBERED) |
+ (sfile_udata->flag & PARAMS_FLAGS_REMEMBERED);
+}
+
+/**
+ * Update the user-preference data for the file space. In fact, this also contains some
+ * non-FileSelectParams data, but it's neglectable.
+ *
+ * \param temp_win_size: If the browser was opened in a temporary window, pass its size here so we
+ * can store that in the preferences. Otherwise NULL.
+ */
+void ED_fileselect_params_to_userdef(SpaceFile *sfile, int temp_win_size[2])
+{
+ UserDef_FileSpaceData *sfile_udata_new = &U.file_space_data;
+ UserDef_FileSpaceData sfile_udata_old = U.file_space_data;
+
+ sfile_udata_new->display_type = sfile->params->display;
+ sfile_udata_new->thumbnail_size = sfile->params->thumbnail_size;
+ sfile_udata_new->sort_type = sfile->params->sort;
+ sfile_udata_new->details_flags = sfile->params->details_flags;
+ sfile_udata_new->flag = sfile->params->flag & PARAMS_FLAGS_REMEMBERED;
+
+ if (temp_win_size) {
+ sfile_udata_new->temp_win_sizex = temp_win_size[0];
+ sfile_udata_new->temp_win_sizey = temp_win_size[1];
+ }
+
+ /* Tag prefs as dirty if something has changed. */
+ if (memcmp(sfile_udata_new, &sfile_udata_old, sizeof(sfile_udata_old)) != 0) {
+ U.runtime.is_dirty = true;
+ }
+}
+
void ED_fileselect_reset_params(SpaceFile *sfile)
{
sfile->params->type = FILE_UNIX;
@@ -344,7 +403,7 @@ void ED_fileselect_reset_params(SpaceFile *sfile)
void fileselect_file_set(SpaceFile *sfile, const int index)
{
const struct FileDirEntry *file = filelist_file(sfile->files, index);
- if (file && file->relpath && file->relpath[0] && !(file->typeflag & FILE_TYPE_FOLDER)) {
+ if (file && file->relpath && file->relpath[0] && !(file->typeflag & FILE_TYPE_DIR)) {
BLI_strncpy(sfile->params->file, file->relpath, FILE_MAXFILE);
}
}
@@ -372,10 +431,10 @@ int ED_fileselect_layout_numfiles(FileLayout *layout, ARegion *ar)
}
else {
const int y_item = layout->tile_h + (2 * layout->tile_border_y);
- const int y_view = (int)(BLI_rctf_size_y(&ar->v2d.cur));
+ const int y_view = (int)(BLI_rctf_size_y(&ar->v2d.cur)) - layout->offset_top;
const int y_over = y_item - (y_view % y_item);
numfiles = (int)((float)(y_view + y_over) / (float)(y_item));
- return numfiles * layout->columns;
+ return numfiles * layout->flow_columns;
}
}
@@ -395,19 +454,19 @@ FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const rcti *r
}
colmin = (rect->xmin) / (layout->tile_w + 2 * layout->tile_border_x);
- rowmin = (rect->ymin) / (layout->tile_h + 2 * layout->tile_border_y);
+ rowmin = (rect->ymin - layout->offset_top) / (layout->tile_h + 2 * layout->tile_border_y);
colmax = (rect->xmax) / (layout->tile_w + 2 * layout->tile_border_x);
- rowmax = (rect->ymax) / (layout->tile_h + 2 * layout->tile_border_y);
+ rowmax = (rect->ymax - layout->offset_top) / (layout->tile_h + 2 * layout->tile_border_y);
- if (is_inside(colmin, rowmin, layout->columns, layout->rows) ||
- is_inside(colmax, rowmax, layout->columns, layout->rows)) {
- CLAMP(colmin, 0, layout->columns - 1);
+ if (is_inside(colmin, rowmin, layout->flow_columns, layout->rows) ||
+ is_inside(colmax, rowmax, layout->flow_columns, layout->rows)) {
+ CLAMP(colmin, 0, layout->flow_columns - 1);
CLAMP(rowmin, 0, layout->rows - 1);
- CLAMP(colmax, 0, layout->columns - 1);
+ CLAMP(colmax, 0, layout->flow_columns - 1);
CLAMP(rowmax, 0, layout->rows - 1);
}
- if ((colmin > layout->columns - 1) || (rowmin > layout->rows - 1)) {
+ if ((colmin > layout->flow_columns - 1) || (rowmin > layout->rows - 1)) {
sel.first = -1;
}
else {
@@ -415,10 +474,10 @@ FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const rcti *r
sel.first = layout->rows * colmin + rowmin;
}
else {
- sel.first = colmin + layout->columns * rowmin;
+ sel.first = colmin + layout->flow_columns * rowmin;
}
}
- if ((colmax > layout->columns - 1) || (rowmax > layout->rows - 1)) {
+ if ((colmax > layout->flow_columns - 1) || (rowmax > layout->rows - 1)) {
sel.last = -1;
}
else {
@@ -426,7 +485,7 @@ FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const rcti *r
sel.last = layout->rows * colmax + rowmax;
}
else {
- sel.last = colmax + layout->columns * rowmax;
+ sel.last = colmax + layout->flow_columns * rowmax;
}
}
@@ -443,9 +502,9 @@ int ED_fileselect_layout_offset(FileLayout *layout, int x, int y)
}
offsetx = (x) / (layout->tile_w + 2 * layout->tile_border_x);
- offsety = (y) / (layout->tile_h + 2 * layout->tile_border_y);
+ offsety = (y - layout->offset_top) / (layout->tile_h + 2 * layout->tile_border_y);
- if (offsetx > layout->columns - 1) {
+ if (offsetx > layout->flow_columns - 1) {
return -1;
}
if (offsety > layout->rows - 1) {
@@ -456,27 +515,123 @@ int ED_fileselect_layout_offset(FileLayout *layout, int x, int y)
active_file = layout->rows * offsetx + offsety;
}
else {
- active_file = offsetx + layout->columns * offsety;
+ active_file = offsetx + layout->flow_columns * offsety;
}
return active_file;
}
+/**
+ * Get the currently visible bounds of the layout in screen space. Matches View2D.mask minus the
+ * top column-header row.
+ */
+void ED_fileselect_layout_maskrect(const FileLayout *layout, const View2D *v2d, rcti *r_rect)
+{
+ *r_rect = v2d->mask;
+ r_rect->ymax -= layout->offset_top;
+}
+
+bool ED_fileselect_layout_is_inside_pt(const FileLayout *layout, const View2D *v2d, int x, int y)
+{
+ rcti maskrect;
+ ED_fileselect_layout_maskrect(layout, v2d, &maskrect);
+ return BLI_rcti_isect_pt(&maskrect, x, y);
+}
+
+bool ED_fileselect_layout_isect_rect(const FileLayout *layout,
+ const View2D *v2d,
+ const rcti *rect,
+ rcti *r_dst)
+{
+ rcti maskrect;
+ ED_fileselect_layout_maskrect(layout, v2d, &maskrect);
+ return BLI_rcti_isect(&maskrect, rect, r_dst);
+}
+
void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y)
{
if (layout->flag == FILE_LAYOUT_HOR) {
*x = layout->tile_border_x +
(tile / layout->rows) * (layout->tile_w + 2 * layout->tile_border_x);
- *y = layout->tile_border_y +
+ *y = layout->offset_top + layout->tile_border_y +
(tile % layout->rows) * (layout->tile_h + 2 * layout->tile_border_y);
}
else {
*x = layout->tile_border_x +
- ((tile) % layout->columns) * (layout->tile_w + 2 * layout->tile_border_x);
- *y = layout->tile_border_y +
- ((tile) / layout->columns) * (layout->tile_h + 2 * layout->tile_border_y);
+ ((tile) % layout->flow_columns) * (layout->tile_w + 2 * layout->tile_border_x);
+ *y = layout->offset_top + layout->tile_border_y +
+ ((tile) / layout->flow_columns) * (layout->tile_h + 2 * layout->tile_border_y);
}
}
+/**
+ * Check if the region coordinate defined by \a x and \a y are inside the column header.
+ */
+bool file_attribute_column_header_is_inside(const View2D *v2d,
+ const FileLayout *layout,
+ int x,
+ int y)
+{
+ rcti header_rect = v2d->mask;
+ header_rect.ymin = header_rect.ymax - layout->attribute_column_header_h;
+ return BLI_rcti_isect_pt(&header_rect, x, y);
+}
+
+bool file_attribute_column_type_enabled(const FileSelectParams *params,
+ FileAttributeColumnType column)
+{
+ switch (column) {
+ case COLUMN_NAME:
+ /* Always enabled */
+ return true;
+ case COLUMN_DATETIME:
+ return (params->details_flags & FILE_DETAILS_DATETIME) != 0;
+ case COLUMN_SIZE:
+ return (params->details_flags & FILE_DETAILS_SIZE) != 0;
+ default:
+ return false;
+ }
+}
+
+/**
+ * Find the column type at region coordinate given by \a x (y doesn't matter for this).
+ */
+FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d,
+ const FileSelectParams *params,
+ FileLayout *layout,
+ int x)
+{
+ float mx, my;
+ int offset_tile;
+
+ UI_view2d_region_to_view(v2d, x, v2d->mask.ymax - layout->offset_top - 1, &mx, &my);
+ offset_tile = ED_fileselect_layout_offset(
+ layout, (int)(v2d->tot.xmin + mx), (int)(v2d->tot.ymax - my));
+ if (offset_tile > -1) {
+ int tile_x, tile_y;
+ int pos_x = 0;
+ int rel_x; /* x relative to the hovered tile */
+
+ ED_fileselect_layout_tilepos(layout, offset_tile, &tile_x, &tile_y);
+ /* Column header drawing doesn't use left tile border, so subtract it. */
+ rel_x = mx - (tile_x - layout->tile_border_x);
+
+ for (FileAttributeColumnType column = 0; column < ATTRIBUTE_COLUMN_MAX; column++) {
+ if (!file_attribute_column_type_enabled(params, column)) {
+ continue;
+ }
+ const int width = layout->attribute_columns[column].width;
+
+ if (IN_RANGE(rel_x, pos_x, pos_x + width)) {
+ return column;
+ }
+
+ pos_x += width;
+ }
+ }
+
+ return COLUMN_NONE;
+}
+
float file_string_width(const char *str)
{
uiStyle *style = UI_style_get();
@@ -512,20 +667,52 @@ float file_font_pointsize(void)
#endif
}
-static void column_widths(FileSelectParams *params, struct FileLayout *layout)
+static void file_attribute_columns_widths(const FileSelectParams *params, FileLayout *layout)
{
- int i;
+ FileAttributeColumn *columns = layout->attribute_columns;
const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size);
+ const int pad = small_size ? 0 : ATTRIBUTE_COLUMN_PADDING * 2;
- for (i = 0; i < MAX_FILE_COLUMN; ++i) {
- layout->column_widths[i] = 0;
+ for (int i = 0; i < ATTRIBUTE_COLUMN_MAX; i++) {
+ layout->attribute_columns[i].width = 0;
}
- layout->column_widths[COLUMN_NAME] = ((float)params->thumbnail_size / 8.0f) * UI_UNIT_X;
/* Biggest possible reasonable values... */
- layout->column_widths[COLUMN_DATE] = file_string_width(small_size ? "23/08/89" : "23-Dec-89");
- layout->column_widths[COLUMN_TIME] = file_string_width("23:59");
- layout->column_widths[COLUMN_SIZE] = file_string_width(small_size ? "98.7 M" : "98.7 MiB");
+ columns[COLUMN_DATETIME].width = file_string_width(small_size ? "23/08/89" :
+ "23 Dec 6789, 23:59") +
+ pad;
+ columns[COLUMN_SIZE].width = file_string_width(small_size ? "98.7 M" : "098.7 MiB") + pad;
+ if (params->display == FILE_IMGDISPLAY) {
+ columns[COLUMN_NAME].width = ((float)params->thumbnail_size / 8.0f) * UI_UNIT_X;
+ }
+ /* Name column uses remaining width */
+ else {
+ int remwidth = layout->tile_w;
+ for (FileAttributeColumnType column_type = ATTRIBUTE_COLUMN_MAX - 1; column_type >= 0;
+ column_type--) {
+ if ((column_type == COLUMN_NAME) ||
+ !file_attribute_column_type_enabled(params, column_type)) {
+ continue;
+ }
+ remwidth -= columns[column_type].width;
+ }
+ columns[COLUMN_NAME].width = remwidth;
+ }
+}
+
+static void file_attribute_columns_init(const FileSelectParams *params, FileLayout *layout)
+{
+ file_attribute_columns_widths(params, layout);
+
+ layout->attribute_columns[COLUMN_NAME].name = N_("Name");
+ layout->attribute_columns[COLUMN_NAME].sort_type = FILE_SORT_ALPHA;
+ layout->attribute_columns[COLUMN_NAME].text_align = UI_STYLE_TEXT_LEFT;
+ layout->attribute_columns[COLUMN_DATETIME].name = N_("Date Modified");
+ layout->attribute_columns[COLUMN_DATETIME].sort_type = FILE_SORT_TIME;
+ layout->attribute_columns[COLUMN_DATETIME].text_align = UI_STYLE_TEXT_LEFT;
+ layout->attribute_columns[COLUMN_SIZE].name = N_("Size");
+ layout->attribute_columns[COLUMN_SIZE].sort_type = FILE_SORT_SIZE;
+ layout->attribute_columns[COLUMN_SIZE].text_align = UI_STYLE_TEXT_RIGHT;
}
void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
@@ -533,7 +720,6 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
FileSelectParams *params = ED_fileselect_get_params(sfile);
FileLayout *layout = NULL;
View2D *v2d = &ar->v2d;
- int maxlen = 0;
int numfiles;
int textheight;
@@ -560,61 +746,69 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
layout->tile_w = layout->prv_w + 2 * layout->prv_border_x;
layout->tile_h = layout->prv_h + 2 * layout->prv_border_y + textheight;
layout->width = (int)(BLI_rctf_size_x(&v2d->cur) - 2 * layout->tile_border_x);
- layout->columns = layout->width / (layout->tile_w + 2 * layout->tile_border_x);
- if (layout->columns > 0) {
- layout->rows = numfiles / layout->columns + 1; // XXX dirty, modulo is zero
+ layout->flow_columns = layout->width / (layout->tile_w + 2 * layout->tile_border_x);
+ layout->attribute_column_header_h = 0;
+ layout->offset_top = 0;
+ if (layout->flow_columns > 0) {
+ layout->rows = numfiles / layout->flow_columns + 1; // XXX dirty, modulo is zero
}
else {
- layout->columns = 1;
+ layout->flow_columns = 1;
layout->rows = numfiles + 1; // XXX dirty, modulo is zero
}
layout->height = sfile->layout->rows * (layout->tile_h + 2 * layout->tile_border_y) +
- layout->tile_border_y * 2;
+ layout->tile_border_y * 2 - layout->offset_top;
layout->flag = FILE_LAYOUT_VER;
}
- else {
- int column_space = 0.6f * UI_UNIT_X;
- int column_icon_space = 0.2f * UI_UNIT_X;
+ else if (params->display == FILE_VERTICALDISPLAY) {
+ int rowcount;
- layout->prv_w = 0;
- layout->prv_h = 0;
+ layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X;
+ layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y;
+ layout->tile_border_x = 0.4f * UI_UNIT_X;
+ layout->tile_border_y = 0.1f * UI_UNIT_Y;
+ layout->tile_h = textheight * 3 / 2;
+ layout->width = (int)(BLI_rctf_size_x(&v2d->cur) - 2 * layout->tile_border_x);
+ layout->tile_w = layout->width;
+ layout->flow_columns = 1;
+ layout->attribute_column_header_h = layout->tile_h * 1.2f + 2 * layout->tile_border_y;
+ layout->offset_top = layout->attribute_column_header_h;
+ rowcount = (int)(BLI_rctf_size_y(&v2d->cur) - layout->offset_top - 2 * layout->tile_border_y) /
+ (layout->tile_h + 2 * layout->tile_border_y);
+ file_attribute_columns_init(params, layout);
+
+ layout->rows = MAX2(rowcount, numfiles);
+ BLI_assert(layout->rows != 0);
+ layout->height = sfile->layout->rows * (layout->tile_h + 2 * layout->tile_border_y) +
+ layout->tile_border_y * 2 + layout->offset_top;
+ layout->flag = FILE_LAYOUT_VER;
+ }
+ else if (params->display == FILE_HORIZONTALDISPLAY) {
+ layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X;
+ layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y;
layout->tile_border_x = 0.4f * UI_UNIT_X;
layout->tile_border_y = 0.1f * UI_UNIT_Y;
- layout->prv_border_x = 0;
- layout->prv_border_y = 0;
layout->tile_h = textheight * 3 / 2;
+ layout->attribute_column_header_h = 0;
+ layout->offset_top = layout->attribute_column_header_h;
layout->height = (int)(BLI_rctf_size_y(&v2d->cur) - 2 * layout->tile_border_y);
/* Padding by full scrollbar H is too much, can overlap tile border Y. */
layout->rows = (layout->height - V2D_SCROLL_HEIGHT + layout->tile_border_y) /
(layout->tile_h + 2 * layout->tile_border_y);
+ layout->tile_w = VERTLIST_MAJORCOLUMN_WIDTH;
+ file_attribute_columns_init(params, layout);
- column_widths(params, layout);
-
- if (params->display == FILE_SHORTDISPLAY) {
- maxlen = ICON_DEFAULT_WIDTH_SCALE + column_icon_space +
- (int)layout->column_widths[COLUMN_NAME] + column_space +
- (int)layout->column_widths[COLUMN_SIZE] + column_space;
- }
- else {
- maxlen = ICON_DEFAULT_WIDTH_SCALE + column_icon_space +
- (int)layout->column_widths[COLUMN_NAME] + column_space +
- (int)layout->column_widths[COLUMN_DATE] + column_space +
- (int)layout->column_widths[COLUMN_TIME] + column_space +
- (int)layout->column_widths[COLUMN_SIZE] + column_space;
- }
- layout->tile_w = maxlen;
if (layout->rows > 0) {
- layout->columns = numfiles / layout->rows + 1; // XXX dirty, modulo is zero
+ layout->flow_columns = numfiles / layout->rows + 1; // XXX dirty, modulo is zero
}
else {
layout->rows = 1;
- layout->columns = numfiles + 1; // XXX dirty, modulo is zero
+ layout->flow_columns = numfiles + 1; // XXX dirty, modulo is zero
}
- layout->width = sfile->layout->columns * (layout->tile_w + 2 * layout->tile_border_x) +
+ layout->width = sfile->layout->flow_columns * (layout->tile_w + 2 * layout->tile_border_x) +
layout->tile_border_x * 2;
layout->flag = FILE_LAYOUT_HOR;
}
- params->display_previous = params->display;
layout->dirty = false;
}
@@ -742,7 +936,7 @@ int autocomplete_file(struct bContext *C, char *str, void *UNUSED(arg_v))
int nentries = filelist_files_ensure(sfile->files);
int i;
- for (i = 0; i < nentries; ++i) {
+ for (i = 0; i < nentries; i++) {
FileDirEntry *file = filelist_file(sfile->files, i);
UI_autocomplete_update_name(autocpl, file->relpath);
}
@@ -771,6 +965,17 @@ void ED_fileselect_exit(wmWindowManager *wm, ScrArea *sa, SpaceFile *sfile)
return;
}
if (sfile->op) {
+ wmWindow *temp_win = WM_window_is_temp_screen(wm->winactive) ? wm->winactive : NULL;
+ int win_size[2];
+
+ if (temp_win) {
+ /* Get DPI/pixelsize independent size to be stored in preferences. */
+ WM_window_set_dpi(temp_win); /* Ensure the DPI is taken from the right window. */
+ win_size[0] = WM_window_pixels_x(temp_win) / UI_DPI_FAC;
+ win_size[1] = WM_window_pixels_y(temp_win) / UI_DPI_FAC;
+ }
+ ED_fileselect_params_to_userdef(sfile, temp_win ? win_size : NULL);
+
WM_event_fileselect_event(wm, sfile->op, EVT_FILESELECT_EXTERNAL_CANCEL);
sfile->op = NULL;
}
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index b50c37baae6..7faa2b883f2 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -404,7 +404,7 @@ void fsmenu_write_file(struct FSMenu *fsmenu, const char *filename)
fprintf(fp, "[Recent]\n");
for (fsm_iter = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_RECENT);
fsm_iter && (nwritten < FSMENU_RECENT_MAX);
- fsm_iter = fsm_iter->next, ++nwritten) {
+ fsm_iter = fsm_iter->next, nwritten++) {
if (fsm_iter->path && fsm_iter->save) {
fsmenu_entry_generate_name(fsm_iter, fsm_name, sizeof(fsm_name));
if (fsm_iter->name[0] && !STREQ(fsm_iter->name, fsm_name)) {
@@ -492,20 +492,17 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
/* Flee from horrible win querying hover floppy drives! */
if (i > 1) {
- /* Try to get volume label as well... */
+ /* Try to get a friendly drive description. */
+ SHFILEINFOW shFile = {0};
BLI_strncpy_wchar_from_utf8(wline, tmps, 4);
- if (GetVolumeInformationW(
- wline, wline + 4, FILE_MAXDIR - 4, NULL, NULL, NULL, NULL, 0)) {
- size_t label_len;
-
- BLI_strncpy_wchar_as_utf8(line, wline + 4, FILE_MAXDIR - 4);
-
- label_len = MIN2(strlen(line), FILE_MAXDIR - 6);
- BLI_snprintf(line + label_len, 6, " (%.2s)", tmps);
-
+ if (SHGetFileInfoW(wline, 0, &shFile, sizeof(SHFILEINFOW), SHGFI_DISPLAYNAME)) {
+ BLI_strncpy_wchar_as_utf8(line, shFile.szDisplayName, FILE_MAXDIR);
name = line;
}
}
+ if (name == NULL) {
+ name = tmps;
+ }
fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, tmps, name, FS_INSERT_SORTED);
}
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 1fd878e4662..d63fcf402de 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -55,6 +55,40 @@
#include "filelist.h"
#include "GPU_framebuffer.h"
+static ARegion *file_execute_region_ensure(ScrArea *sa, ARegion *ar_prev)
+{
+ ARegion *ar;
+
+ if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE)) != NULL) {
+ return ar;
+ }
+
+ ar = MEM_callocN(sizeof(ARegion), "execute region for file");
+ BLI_insertlinkafter(&sa->regionbase, ar_prev, ar);
+ ar->regiontype = RGN_TYPE_EXECUTE;
+ ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->flag = RGN_FLAG_DYNAMIC_SIZE;
+
+ return ar;
+}
+
+static ARegion *file_tool_props_region_ensure(ScrArea *sa, ARegion *ar_prev)
+{
+ ARegion *ar;
+
+ if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS)) != NULL) {
+ return ar;
+ }
+
+ /* add subdiv level; after execute region */
+ ar = MEM_callocN(sizeof(ARegion), "tool props for file");
+ BLI_insertlinkafter(&sa->regionbase, ar_prev, ar);
+ ar->regiontype = RGN_TYPE_TOOL_PROPS;
+ ar->alignment = RGN_ALIGN_RIGHT;
+
+ return ar;
+}
+
/* ******************** default callbacks for file space ***************** */
static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
@@ -78,17 +112,14 @@ static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scen
ar->regiontype = RGN_TYPE_TOOLS;
ar->alignment = RGN_ALIGN_LEFT;
- /* Tool props (aka operator) region */
- ar = MEM_callocN(sizeof(ARegion), "tool props region for file");
- BLI_addtail(&sfile->regionbase, ar);
- ar->regiontype = RGN_TYPE_TOOL_PROPS;
- ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
-
/* ui list region */
ar = MEM_callocN(sizeof(ARegion), "ui region for file");
BLI_addtail(&sfile->regionbase, ar);
ar->regiontype = RGN_TYPE_UI;
ar->alignment = RGN_ALIGN_TOP;
+ ar->flag |= RGN_FLAG_DYNAMIC_SIZE;
+
+ /* Tool props and execute region are added as needed, see file_refresh(). */
/* main region */
ar = MEM_callocN(sizeof(ARegion), "main region for file");
@@ -201,9 +232,50 @@ static SpaceLink *file_duplicate(SpaceLink *sl)
return (SpaceLink *)sfilen;
}
+static void file_ensure_valid_region_state(bContext *C,
+ wmWindowManager *wm,
+ wmWindow *win,
+ ScrArea *sa,
+ SpaceFile *sfile,
+ FileSelectParams *params)
+{
+ ARegion *ar_ui = BKE_area_find_region_type(sa, RGN_TYPE_UI);
+ ARegion *ar_props = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS);
+ ARegion *ar_execute = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE);
+ bool needs_init = false; /* To avoid multiple ED_area_initialize() calls. */
+
+ /* If there's an file-operation, ensure we have the option and execute region */
+ if (sfile->op && (ar_props == NULL)) {
+ ar_execute = file_execute_region_ensure(sa, ar_ui);
+ ar_props = file_tool_props_region_ensure(sa, ar_execute);
+
+ if (params->flag & FILE_HIDE_TOOL_PROPS) {
+ ar_props->flag |= RGN_FLAG_HIDDEN;
+ }
+ else {
+ ar_props->flag &= ~RGN_FLAG_HIDDEN;
+ }
+
+ needs_init = true;
+ }
+ /* If there's _no_ file-operation, ensure we _don't_ have the option and execute region */
+ else if ((sfile->op == NULL) && (ar_props != NULL)) {
+ BLI_assert(ar_execute != NULL);
+
+ ED_region_remove(C, sa, ar_props);
+ ED_region_remove(C, sa, ar_execute);
+ needs_init = true;
+ }
+
+ if (needs_init) {
+ ED_area_initialize(wm, win, sa);
+ }
+}
+
static void file_refresh(const bContext *C, ScrArea *sa)
{
wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelectParams *params = ED_fileselect_get_params(sfile);
struct FSMenu *fsmenu = ED_fsmenu_get();
@@ -217,15 +289,16 @@ static void file_refresh(const bContext *C, ScrArea *sa)
}
filelist_setdir(sfile->files, params->dir);
filelist_setrecursion(sfile->files, params->recursion_level);
- filelist_setsorting(sfile->files, params->sort);
- filelist_setfilter_options(sfile->files,
- (params->flag & FILE_FILTER) != 0,
- (params->flag & FILE_HIDE_DOT) != 0,
- false, /* TODO hide_parent, should be controllable? */
- params->filter,
- params->filter_id,
- params->filter_glob,
- params->filter_search);
+ filelist_setsorting(sfile->files, params->sort, params->flag & FILE_SORT_INVERT);
+ filelist_setfilter_options(
+ sfile->files,
+ (params->flag & FILE_FILTER) != 0,
+ (params->flag & FILE_HIDE_DOT) != 0,
+ true, /* Just always hide parent, prefer to not add an extra user option for this. */
+ params->filter,
+ params->filter_id,
+ params->filter_glob,
+ params->filter_search);
/* Update the active indices of bookmarks & co. */
sfile->systemnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_SYSTEM, params->dir);
@@ -254,7 +327,7 @@ static void file_refresh(const bContext *C, ScrArea *sa)
else {
filelist_cache_previews_set(sfile->files, false);
if (sfile->previews_timer) {
- WM_event_remove_timer_notifier(wm, CTX_wm_window(C), sfile->previews_timer);
+ WM_event_remove_timer_notifier(wm, win, sfile->previews_timer);
sfile->previews_timer = NULL;
}
}
@@ -268,11 +341,8 @@ static void file_refresh(const bContext *C, ScrArea *sa)
}
/* Might be called with NULL sa, see file_main_region_draw() below. */
- if (sa && BKE_area_find_region_type(sa, RGN_TYPE_TOOLS) == NULL) {
- /* Create TOOLS/TOOL_PROPS regions. */
- file_tools_region(sa);
-
- ED_area_initialize(wm, CTX_wm_window(C), sa);
+ if (sa) {
+ file_ensure_valid_region_state((bContext *)C, wm, win, sa, sfile, params);
}
ED_area_tag_redraw(sa);
@@ -406,6 +476,11 @@ static void file_main_region_draw(const bContext *C, ARegion *ar)
v2d->keepofs &= ~V2D_LOCKOFS_Y;
v2d->keepofs |= V2D_LOCKOFS_X;
}
+ else if (params->display == FILE_VERTICALDISPLAY) {
+ v2d->scroll = V2D_SCROLL_RIGHT;
+ v2d->keepofs &= ~V2D_LOCKOFS_Y;
+ v2d->keepofs |= V2D_LOCKOFS_X;
+ }
else {
v2d->scroll = V2D_SCROLL_BOTTOM;
v2d->keepofs &= ~V2D_LOCKOFS_X;
@@ -439,7 +514,9 @@ static void file_main_region_draw(const bContext *C, ARegion *ar)
UI_view2d_view_restore(C);
/* scrollers */
- scrollers = UI_view2d_scrollers_calc(v2d, NULL);
+ rcti view_rect;
+ ED_fileselect_layout_maskrect(sfile->layout, v2d, &view_rect);
+ scrollers = UI_view2d_scrollers_calc(v2d, &view_rect);
UI_view2d_scrollers_draw(v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
}
@@ -452,13 +529,13 @@ static void file_operatortypes(void)
WM_operatortype_append(FILE_OT_select_box);
WM_operatortype_append(FILE_OT_select_bookmark);
WM_operatortype_append(FILE_OT_highlight);
+ WM_operatortype_append(FILE_OT_sort_column_ui_context);
WM_operatortype_append(FILE_OT_execute);
WM_operatortype_append(FILE_OT_cancel);
WM_operatortype_append(FILE_OT_parent);
WM_operatortype_append(FILE_OT_previous);
WM_operatortype_append(FILE_OT_next);
WM_operatortype_append(FILE_OT_refresh);
- WM_operatortype_append(FILE_OT_bookmark_toggle);
WM_operatortype_append(FILE_OT_bookmark_add);
WM_operatortype_append(FILE_OT_bookmark_delete);
WM_operatortype_append(FILE_OT_bookmark_cleanup);
@@ -538,7 +615,8 @@ static void file_ui_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
- UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy);
+ ED_region_panels_init(wm, ar);
+ ar->v2d.keepzoom |= V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y;
/* own keymap */
keymap = WM_keymap_ensure(wm->defaultconf, "File Browser", SPACE_FILE, 0);
@@ -550,22 +628,24 @@ static void file_ui_region_init(wmWindowManager *wm, ARegion *ar)
static void file_ui_region_draw(const bContext *C, ARegion *ar)
{
- float col[3];
- /* clear */
- UI_GetThemeColor3fv(TH_BACK, col);
- GPU_clear_color(col[0], col[1], col[2], 0.0);
- GPU_clear(GPU_COLOR_BIT);
+ ED_region_panels(C, ar);
+}
- /* scrolling here is just annoying, disable it */
- ar->v2d.cur.ymax = BLI_rctf_size_y(&ar->v2d.cur);
- ar->v2d.cur.ymin = 0;
+static void file_execution_region_init(wmWindowManager *wm, ARegion *ar)
+{
+ wmKeyMap *keymap;
- /* set view2d view matrix for scrolling (without scrollers) */
- UI_view2d_view_ortho(&ar->v2d);
+ ED_region_panels_init(wm, ar);
+ ar->v2d.keepzoom |= V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y;
- file_draw_buttons(C, ar);
+ /* own keymap */
+ keymap = WM_keymap_ensure(wm->defaultconf, "File Browser", SPACE_FILE, 0);
+ WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap);
+}
- UI_view2d_view_restore(C);
+static void file_execution_region_draw(const bContext *C, ARegion *ar)
+{
+ ED_region_panels(C, ar);
}
static void file_ui_region_listener(wmWindow *UNUSED(win),
@@ -656,13 +736,22 @@ void ED_spacetype_file(void)
/* regions: ui */
art = MEM_callocN(sizeof(ARegionType), "spacetype file region");
art->regionid = RGN_TYPE_UI;
- art->prefsizey = 60;
art->keymapflag = ED_KEYMAP_UI;
art->listener = file_ui_region_listener;
art->init = file_ui_region_init;
art->draw = file_ui_region_draw;
BLI_addhead(&st->regiontypes, art);
+ /* regions: execution */
+ art = MEM_callocN(sizeof(ARegionType), "spacetype file region");
+ art->regionid = RGN_TYPE_EXECUTE;
+ art->keymapflag = ED_KEYMAP_UI;
+ art->listener = file_ui_region_listener;
+ art->init = file_execution_region_init;
+ art->draw = file_execution_region_draw;
+ BLI_addhead(&st->regiontypes, art);
+ file_execute_region_panels_register(art);
+
/* regions: channels (directories) */
art = MEM_callocN(sizeof(ARegionType), "spacetype file region");
art->regionid = RGN_TYPE_TOOLS;
@@ -677,14 +766,14 @@ void ED_spacetype_file(void)
/* regions: tool properties */
art = MEM_callocN(sizeof(ARegionType), "spacetype file operator region");
art->regionid = RGN_TYPE_TOOL_PROPS;
- art->prefsizex = 0;
- art->prefsizey = 360;
+ art->prefsizex = 240;
+ art->prefsizey = 60;
art->keymapflag = ED_KEYMAP_UI;
art->listener = file_tools_region_listener;
art->init = file_tools_region_init;
art->draw = file_tools_region_draw;
BLI_addhead(&st->regiontypes, art);
- file_panels_register(art);
+ file_tool_props_region_panels_register(art);
BKE_spacetype_register(st);
}
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index b264a5cb260..33cb1cb0075 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -861,6 +861,15 @@ static void graph_panel_driverVar__transChan(uiLayout *layout, ID *id, DriverVar
sub = uiLayoutColumn(layout, true);
uiItemR(sub, &dtar_ptr, "transform_type", 0, NULL, ICON_NONE);
+
+ if (ELEM(dtar->transChan,
+ DTAR_TRANSCHAN_ROTX,
+ DTAR_TRANSCHAN_ROTY,
+ DTAR_TRANSCHAN_ROTZ,
+ DTAR_TRANSCHAN_ROTW)) {
+ uiItemR(sub, &dtar_ptr, "rotation_mode", 0, IFACE_("Mode"), ICON_NONE);
+ }
+
uiItemR(sub, &dtar_ptr, "transform_space", 0, IFACE_("Space"), ICON_NONE);
}
@@ -1147,8 +1156,12 @@ static void graph_draw_driver_settings_panel(uiLayout *layout,
if ((dvar->type == DVAR_TYPE_ROT_DIFF) ||
(dvar->type == DVAR_TYPE_TRANSFORM_CHAN &&
- dvar->targets[0].transChan >= DTAR_TRANSCHAN_ROTX &&
- dvar->targets[0].transChan < DTAR_TRANSCHAN_SCALEX)) {
+ ELEM(dvar->targets[0].transChan,
+ DTAR_TRANSCHAN_ROTX,
+ DTAR_TRANSCHAN_ROTY,
+ DTAR_TRANSCHAN_ROTZ,
+ DTAR_TRANSCHAN_ROTW) &&
+ dvar->targets[0].rotation_mode != DTAR_ROTMODE_QUATERNION)) {
BLI_snprintf(
valBuf, sizeof(valBuf), "%.3f (%4.1f°)", dvar->curval, RAD2DEGF(dvar->curval));
}
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index e7ba498fc11..42a1566629a 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -39,7 +39,6 @@
#include "BKE_curve.h"
#include "BKE_fcurve.h"
-#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
#include "GPU_state.h"
@@ -205,7 +204,7 @@ static void draw_fcurve_keyframe_vertices(FCurve *fcu, View2D *v2d, bool edit, u
{
immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
- immUniform1f("size", UI_GetThemeValuef(TH_VERTEX_SIZE) * U.pixelsize);
+ immUniform1f("size", UI_GetThemeValuef(TH_VERTEX_SIZE) * U.dpi_fac);
draw_fcurve_selected_keyframe_vertices(fcu, v2d, edit, false, pos);
draw_fcurve_selected_keyframe_vertices(fcu, v2d, edit, true, pos);
@@ -269,8 +268,8 @@ static void draw_fcurve_handle_vertices(FCurve *fcu,
immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
/* set handle size */
- immUniform1f("size", (1.4f * UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE)) * U.pixelsize);
- immUniform1f("outlineWidth", 1.5f * U.pixelsize);
+ immUniform1f("size", (1.4f * UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE)) * U.dpi_fac);
+ immUniform1f("outlineWidth", 1.5f * U.dpi_fac);
draw_fcurve_selected_handle_vertices(fcu, v2d, false, sel_handle_only, pos);
draw_fcurve_selected_handle_vertices(fcu, v2d, true, sel_handle_only, pos);
@@ -880,10 +879,6 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
float offset;
float unitfac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset);
- /* for now, only show when debugging driver... */
- // if ((driver->flag & DRIVER_FLAG_SHOWDEBUG) == 0)
- // return;
-
const uint shdr_pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index b624e21937f..59cf5f63de3 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -1538,7 +1538,7 @@ void GRAPH_OT_sound_bake(wmOperatorType *ot)
FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE,
FILE_SPECIAL,
FILE_OPENFILE,
- WM_FILESEL_FILEPATH,
+ WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
RNA_def_float(ot->srna,
@@ -2506,28 +2506,28 @@ static const EnumPropertyItem prop_graphkeys_mirror_types[] = {
{GRAPHKEYS_MIRROR_CFRA,
"CFRA",
0,
- "By Times over Current Frame",
+ "By Times Over Current Frame",
"Flip times of selected keyframes using the current frame as the mirror line"},
{GRAPHKEYS_MIRROR_VALUE,
"VALUE",
0,
- "By Values over Cursor Value",
+ "By Values Over Cursor Value",
"Flip values of selected keyframes using the cursor value (Y/Horizontal component) as the "
"mirror line"},
{GRAPHKEYS_MIRROR_YAXIS,
"YAXIS",
0,
- "By Times over Time=0",
+ "By Times Over Time=0",
"Flip times of selected keyframes, effectively reversing the order they appear in"},
{GRAPHKEYS_MIRROR_XAXIS,
"XAXIS",
0,
- "By Values over Value=0",
+ "By Values Over Value=0",
"Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"},
{GRAPHKEYS_MIRROR_MARKER,
"MARKER",
0,
- "By Times over First Selected Marker",
+ "By Times Over First Selected Marker",
"Flip times of selected keyframes using the first selected marker as the reference point"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt
index 61e6b065cba..5abcff436f1 100644
--- a/source/blender/editors/space_image/CMakeLists.txt
+++ b/source/blender/editors/space_image/CMakeLists.txt
@@ -29,6 +29,7 @@ set(INC
../../makesrna
../../render/extern/include
../../windowmanager
+ ../../../../intern/clog
../../../../intern/glew-mx
../../../../intern/guardedalloc
)
@@ -42,6 +43,7 @@ set(SRC
image_draw.c
image_edit.c
image_ops.c
+ image_undo.c
space_image.c
image_intern.h
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index ccd0a2bfd79..ec2b1cc7fbe 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -301,6 +301,18 @@ void ED_image_mouse_pos(SpaceImage *sima, ARegion *ar, const int mval[2], float
co[1] = ((mval[1] - sy) / zoomy) / height;
}
+void ED_image_view_center_to_point(SpaceImage *sima, float x, float y)
+{
+ int width, height;
+ float aspx, aspy;
+
+ ED_space_image_get_size(sima, &width, &height);
+ ED_space_image_get_aspect(sima, &aspx, &aspy);
+
+ sima->xof = (x - 0.5f) * width * aspx;
+ sima->yof = (y - 0.5f) * height * aspy;
+}
+
void ED_image_point_pos(SpaceImage *sima, ARegion *ar, float x, float y, float *xr, float *yr)
{
int sx, sy, width, height;
@@ -476,3 +488,9 @@ bool ED_space_image_maskedit_mask_poll(bContext *C)
return false;
}
+
+bool ED_space_image_cursor_poll(bContext *C)
+{
+ return ED_operator_uvedit_space_image(C) || ED_space_image_maskedit_poll(C) ||
+ ED_space_image_paint_curve(C);
+}
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index 1abb6715fdb..f8ce065d46c 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -44,10 +44,12 @@ void draw_image_sample_line(struct SpaceImage *sima);
/* image_ops.c */
bool space_image_main_region_poll(struct bContext *C);
+bool space_image_view_center_cursor_poll(struct bContext *C);
void IMAGE_OT_view_all(struct wmOperatorType *ot);
void IMAGE_OT_view_pan(struct wmOperatorType *ot);
void IMAGE_OT_view_selected(struct wmOperatorType *ot);
+void IMAGE_OT_view_center_cursor(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom_in(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom_out(struct wmOperatorType *ot);
@@ -70,6 +72,7 @@ void IMAGE_OT_pack(struct wmOperatorType *ot);
void IMAGE_OT_unpack(struct wmOperatorType *ot);
void IMAGE_OT_invert(struct wmOperatorType *ot);
+void IMAGE_OT_resize(struct wmOperatorType *ot);
void IMAGE_OT_cycle_render_slot(struct wmOperatorType *ot);
void IMAGE_OT_clear_render_slot(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 7ea693f2fd2..39f7bf001f3 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -103,7 +103,9 @@
#include "image_intern.h"
-/******************** view navigation utilities *********************/
+/* -------------------------------------------------------------------- */
+/** \name View Navigation Utilities
+ * \{ */
static void sima_zoom_set(
SpaceImage *sima, ARegion *ar, float zoom, const float location[2], const bool zoom_to_pos)
@@ -211,7 +213,7 @@ static ImageUser *image_user_from_context(const bContext *C)
}
}
-static bool image_buffer_exists_from_context(bContext *C)
+static bool image_from_context_has_data_poll(bContext *C)
{
Image *ima = image_from_context(C);
ImageUser *iuser = image_user_from_context(C);
@@ -227,6 +229,16 @@ static bool image_buffer_exists_from_context(bContext *C)
return has_buffer;
}
+/**
+ * Use this when the image buffer is accessed without the image user.
+ */
+static bool image_from_contect_has_data_poll_no_image_user(bContext *C)
+{
+ Image *ima = image_from_context(C);
+
+ return BKE_image_has_ibuf(ima, NULL);
+}
+
static bool image_not_packed_poll(bContext *C)
{
/* Do not run 'replace' on packed images, it does not give user expected results at all. */
@@ -280,7 +292,12 @@ static bool image_sample_poll(bContext *C)
return true;
}
-/********************** view pan operator *********************/
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Pan Operator
+ * \{ */
typedef struct ViewPanData {
float x, y;
@@ -300,7 +317,7 @@ static void image_view_pan_init(bContext *C, wmOperator *op, const wmEvent *even
/* Grab will be set when running from gizmo. */
vpd->own_cursor = (win->grabcursor == 0);
if (vpd->own_cursor) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
vpd->x = event->x;
@@ -423,7 +440,11 @@ void IMAGE_OT_view_pan(wmOperatorType *ot)
FLT_MAX);
}
-/********************** view zoom operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom Operator
+ * \{ */
typedef struct ViewZoomData {
float origx, origy;
@@ -453,7 +474,7 @@ static void image_view_zoom_init(bContext *C, wmOperator *op, const wmEvent *eve
/* Grab will be set when running from gizmo. */
vpd->own_cursor = (win->grabcursor == 0);
if (vpd->own_cursor) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
vpd->origx = event->x;
@@ -671,7 +692,12 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot)
}
#ifdef WITH_INPUT_NDOF
-/********************** NDOF operator *********************/
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NDOF Operator
+ * \{ */
/* Combined pan/zoom from a 3D mouse device.
* Z zooms, XY pans
@@ -721,9 +747,14 @@ void IMAGE_OT_view_ndof(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_LOCK_BYPASS;
}
+
+/** \} */
+
#endif /* WITH_INPUT_NDOF */
-/********************** view all operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name View All Operator
+ * \{ */
/* Updates the fields of the View2D member of the SpaceImage struct.
* Default behavior is to reset the position of the image and set the zoom to 1
@@ -800,7 +831,41 @@ void IMAGE_OT_view_all(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/********************** view selected operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Center View To Cursor Operator
+ * \{ */
+
+static int view_center_cursor_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ ED_image_view_center_to_point(sima, sima->cursor[0], sima->cursor[1]);
+
+ ED_region_tag_redraw(ar);
+
+ return OPERATOR_FINISHED;
+}
+
+void IMAGE_OT_view_center_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Center View to Cursor";
+ ot->description = "Center the view so that the cursor is in the middle of the view";
+ ot->idname = "IMAGE_OT_view_center_cursor";
+
+ /* api callbacks */
+ ot->exec = view_center_cursor_exec;
+ ot->poll = ED_space_image_cursor_poll;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Selected Operator
+ * \{ */
static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -866,7 +931,11 @@ void IMAGE_OT_view_selected(wmOperatorType *ot)
ot->poll = image_view_selected_poll;
}
-/********************** view zoom in/out operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom In/Out Operator
+ * \{ */
static int image_view_zoom_in_exec(bContext *C, wmOperator *op)
{
@@ -984,7 +1053,11 @@ void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
-/********************** view zoom ratio operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom Ratio Operator
+ * \{ */
static int image_view_zoom_ratio_exec(bContext *C, wmOperator *op)
{
@@ -1028,7 +1101,11 @@ void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot)
FLT_MAX);
}
-/********************** view border-zoom operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Border-Zoom Operator
+ * \{ */
static int image_view_zoom_border_exec(bContext *C, wmOperator *op)
{
@@ -1084,14 +1161,18 @@ void IMAGE_OT_view_zoom_border(wmOperatorType *ot)
WM_operator_properties_gesture_box_zoom(ot);
}
-/**************** load/replace/save callbacks ******************/
+/* load/replace/save callbacks */
static void image_filesel(bContext *C, wmOperator *op, const char *path)
{
RNA_string_set(op->ptr, "filepath", path);
WM_event_add_fileselect(C, op);
}
-/******************** open image operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Open Image Operator
+ * \{ */
typedef struct ImageOpenData {
PropertyPointerRNA pprop;
@@ -1525,7 +1606,12 @@ void IMAGE_OT_open(wmOperatorType *ot)
"Automatically detect animated sequences in selected images (based on file names)");
}
-/******************** Match movie length operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Match Movie Length Operator
+ * \{ */
+
static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -1571,7 +1657,11 @@ void IMAGE_OT_match_movie_length(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL /* | OPTYPE_UNDO */;
}
-/******************** replace image operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Replace Image Operator
+ * \{ */
static int image_replace_exec(bContext *C, wmOperator *op)
{
@@ -1656,7 +1746,11 @@ void IMAGE_OT_replace(wmOperatorType *ot)
FILE_SORT_ALPHA);
}
-/******************** save image as operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Save Image As Operator
+ * \{ */
static char imtype_best_depth(ImBuf *ibuf, const char imtype)
{
@@ -1773,6 +1867,7 @@ static int image_save_options_init(Main *bmain,
}
else {
BLI_snprintf(opts->filepath, sizeof(opts->filepath), "//%s", ima->id.name + 2);
+ BLI_path_make_safe(opts->filepath);
BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain));
}
}
@@ -1969,7 +2064,7 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
static bool image_save_as_poll(bContext *C)
{
- if (!image_buffer_exists_from_context(C)) {
+ if (!image_from_context_has_data_poll(C)) {
return false;
}
@@ -2020,12 +2115,16 @@ void IMAGE_OT_save_as(wmOperatorType *ot)
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
FILE_SPECIAL,
FILE_SAVE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
}
-/******************** save image operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Save Image Operator
+ * \{ */
static bool image_file_path_saveable(bContext *C, Image *ima, ImageUser *iuser)
{
@@ -2066,7 +2165,7 @@ static bool image_file_path_saveable(bContext *C, Image *ima, ImageUser *iuser)
static bool image_save_poll(bContext *C)
{
/* Can't save if there are no pixels. */
- if (image_buffer_exists_from_context(C) == false) {
+ if (image_from_context_has_data_poll(C) == false) {
return false;
}
@@ -2146,7 +2245,11 @@ void IMAGE_OT_save(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/******************* save sequence operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Save Sequence Operator
+ * \{ */
static int image_save_sequence_exec(bContext *C, wmOperator *op)
{
@@ -2195,7 +2298,12 @@ static int image_save_sequence_exec(bContext *C, wmOperator *op)
/* get a filename for menu */
BLI_split_dir_part(first_ibuf->name, di, sizeof(di));
- BKE_reportf(op->reports, RPT_INFO, "%d image(s) will be saved in %s", tot, di);
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ tot == 1 ? "%d image will be saved in %s" :
+ "%d images will be saved in %s",
+ tot,
+ di);
iter = IMB_moviecacheIter_new(image->cache);
while (!IMB_moviecacheIter_done(iter)) {
@@ -2232,13 +2340,17 @@ void IMAGE_OT_save_sequence(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_save_sequence_exec;
- ot->poll = image_buffer_exists_from_context;
+ ot->poll = image_from_context_has_data_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** save all operator **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Save All Operator
+ * \{ */
static bool image_should_be_saved_when_modified(Image *ima)
{
@@ -2388,7 +2500,11 @@ void IMAGE_OT_save_all_modified(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/******************** reload image operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reload Image Operator
+ * \{ */
static int image_reload_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -2425,7 +2541,12 @@ void IMAGE_OT_reload(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER; /* no undo, image buffer is not handled by undo */
}
-/********************** new image operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name New Image Operator
+ * \{ */
+
#define IMA_DEF_NAME N_("Untitled")
enum {
@@ -2641,22 +2762,18 @@ void IMAGE_OT_new(wmOperatorType *ot)
#undef IMA_DEF_NAME
-/********************* invert operators *********************/
-
-static bool image_invert_poll(bContext *C)
-{
- Image *ima = image_from_context(C);
+/** \} */
- return BKE_image_has_ibuf(ima, NULL);
-}
+/* -------------------------------------------------------------------- */
+/** \name Invert Operators
+ * \{ */
static int image_invert_exec(bContext *C, wmOperator *op)
{
Image *ima = image_from_context(C);
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
SpaceImage *sima = CTX_wm_space_image(C);
- /* undo is supported only on image paint mode currently */
- bool support_undo = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
+ const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
/* flags indicate if this channel should be inverted */
const bool r = RNA_boolean_get(op->ptr, "invert_r");
@@ -2671,14 +2788,12 @@ static int image_invert_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (support_undo) {
- ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
- /* not strictly needed, because we only imapaint_dirty_region to invalidate all tiles
- * but better do this right in case someone copies this for a tool that uses partial
- * redraw better */
+ ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf);
+
+ if (is_paint) {
ED_imapaint_clear_partial_redraw();
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
}
+
/* TODO: make this into an IMB_invert_channels(ibuf,r,g,b,a) method!? */
if (ibuf->rect_float) {
@@ -2732,9 +2847,7 @@ static int image_invert_exec(bContext *C, wmOperator *op)
ibuf->userflags |= IB_MIPMAP_INVALID;
}
- if (support_undo) {
- ED_image_undo_push_end();
- }
+ ED_image_undo_push_end();
/* force GPU reupload, all image is invalid */
GPU_free_image(ima);
@@ -2757,7 +2870,7 @@ void IMAGE_OT_invert(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_invert_exec;
- ot->poll = image_invert_poll;
+ ot->poll = image_from_contect_has_data_poll_no_image_user;
/* properties */
prop = RNA_def_boolean(ot->srna, "invert_r", 0, "Red", "Invert Red Channel");
@@ -2770,10 +2883,96 @@ void IMAGE_OT_invert(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Scale Operator
+ * \{ */
+
+static int image_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Image *ima = image_from_context(C);
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ const int size[2] = {ibuf->x, ibuf->y};
+ RNA_property_int_set_array(op->ptr, prop, size);
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
+ return WM_operator_props_dialog_popup(C, op, 200, 200);
+}
+
+static int image_scale_exec(bContext *C, wmOperator *op)
+{
+ Image *ima = image_from_context(C);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
+
+ if (ibuf == NULL) {
+ /* TODO: this should actually never happen, but does for render-results -> cleanup */
+ return OPERATOR_CANCELLED;
+ }
+
+ if (is_paint) {
+ ED_imapaint_clear_partial_redraw();
+ }
+
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
+ int size[2];
+ if (RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_int_get_array(op->ptr, prop, size);
+ }
+ else {
+ size[0] = ibuf->x;
+ size[1] = ibuf->y;
+ RNA_property_int_set_array(op->ptr, prop, size);
+ }
+
+ ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf);
+
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+ IMB_scaleImBuf(ibuf, size[0], size[1]);
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+
+ ED_image_undo_push_end();
+
+ /* force GPU reupload, all image is invalid */
+ GPU_free_image(ima);
+
+ DEG_id_tag_update(&ima->id, 0);
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
+
+ return OPERATOR_FINISHED;
}
-/********************* pack operator *********************/
+void IMAGE_OT_resize(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Resize Image";
+ ot->idname = "IMAGE_OT_resize";
+ ot->description = "Resize the image";
+
+ /* api callbacks */
+ ot->invoke = image_scale_invoke;
+ ot->exec = image_scale_exec;
+ ot->poll = image_from_contect_has_data_poll_no_image_user;
+
+ /* properties */
+ RNA_def_int_vector(ot->srna, "size", 2, NULL, 1, INT_MAX, "Size", "", 1, SHRT_MAX);
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pack Operator
+ * \{ */
static bool image_pack_test(bContext *C, wmOperator *op)
{
@@ -2826,7 +3025,11 @@ void IMAGE_OT_pack(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************* unpack operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Unpack Operator
+ * \{ */
static int image_unpack_exec(bContext *C, wmOperator *op)
{
@@ -2925,7 +3128,11 @@ void IMAGE_OT_unpack(wmOperatorType *ot)
ot->srna, "id", NULL, MAX_ID_NAME - 2, "Image Name", "Image data-block name to unpack");
}
-/******************** sample image operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sample Image Operator
+ * \{ */
typedef struct ImageSampleInfo {
ARegionType *art;
@@ -3338,7 +3545,12 @@ void IMAGE_OT_sample(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/******************** sample line operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sample Line Operator
+ * \{ */
+
static int image_sample_line_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -3420,10 +3632,14 @@ void IMAGE_OT_sample_line(wmOperatorType *ot)
/* flags */
ot->flag = 0; /* no undo/register since this operates on the space */
- WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
+ WM_operator_properties_gesture_straightline(ot, WM_CURSOR_EDIT);
}
-/******************** set curve point operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Curve Point Operator
+ * \{ */
void IMAGE_OT_curves_point_set(wmOperatorType *ot)
{
@@ -3457,7 +3673,11 @@ void IMAGE_OT_curves_point_set(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/********************* cycle render slot operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cycle Render Slot Operator
+ * \{ */
static bool image_cycle_render_slot_poll(bContext *C)
{
@@ -3503,7 +3723,11 @@ void IMAGE_OT_cycle_render_slot(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "reverse", 0, "Cycle in Reverse", "");
}
-/********************* clear render slot operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clear Render Slot Operator
+ * \{ */
static int image_clear_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3534,7 +3758,11 @@ void IMAGE_OT_clear_render_slot(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
}
-/********************* add render slot operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Render Slot Operator
+ * \{ */
static int image_add_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3563,7 +3791,11 @@ void IMAGE_OT_add_render_slot(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
}
-/********************* remove render slot operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Remove Render Slot Operator
+ * \{ */
static int image_remove_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3594,7 +3826,11 @@ void IMAGE_OT_remove_render_slot(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
}
-/********************** change frame operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Change Frame Operator
+ * \{ */
static bool change_frame_poll(bContext *C)
{
@@ -3745,7 +3981,11 @@ void IMAGE_OT_read_viewlayers(wmOperatorType *ot)
ot->flag = 0;
}
-/* ********************* Render border operator ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Render Border Operator
+ * \{ */
static int render_border_exec(bContext *C, wmOperator *op)
{
@@ -3814,7 +4054,11 @@ void IMAGE_OT_render_border(wmOperatorType *ot)
WM_operator_properties_border(ot);
}
-/* ********************* Clear render border operator ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clear Render Border Operator
+ * \{ */
static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3839,3 +4083,5 @@ void IMAGE_OT_clear_render_border(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/** \} */
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
new file mode 100644
index 00000000000..c450d5122eb
--- /dev/null
+++ b/source/blender/editors/space_image/image_undo.c
@@ -0,0 +1,1032 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spimage
+ *
+ * Overview
+ * ========
+ *
+ * - Each undo step is a #ImageUndoStep
+ * - Each #ImageUndoStep stores a list of #UndoImageHandle
+ * - Each #UndoImageHandle stores a list of #UndoImageBuf
+ * (this is the undo systems equivalent of an #ImBuf).
+ * - Each #UndoImageBuf stores an array of #UndoImageTile
+ * The tiles are shared between #UndoImageBuf's to avoid duplication.
+ *
+ * When the undo system manages an image, there will always be a full copy (as a #UndoImageBuf)
+ * each new undo step only stores modified tiles.
+ */
+
+#include "CLG_log.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_threads.h"
+
+#include "DNA_image_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BKE_context.h"
+#include "BKE_image.h"
+#include "BKE_paint.h"
+#include "BKE_undo_system.h"
+
+#include "DEG_depsgraph.h"
+
+#include "ED_paint.h"
+#include "ED_undo.h"
+#include "ED_util.h"
+#include "ED_object.h"
+
+#include "GPU_draw.h"
+
+#include "WM_api.h"
+
+static CLG_LogRef LOG = {"ed.image.undo"};
+
+/* -------------------------------------------------------------------- */
+/** \name Thread Locking
+ * \{ */
+
+/* this is a static resource for non-globality,
+ * Maybe it should be exposed as part of the
+ * paint operation, but for now just give a public interface */
+static SpinLock paint_tiles_lock;
+
+void ED_image_paint_tile_lock_init(void)
+{
+ BLI_spin_init(&paint_tiles_lock);
+}
+
+void ED_image_paint_tile_lock_end(void)
+{
+ BLI_spin_end(&paint_tiles_lock);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Paint Tiles
+ *
+ * Created on demand while painting,
+ * use to access the previous state for some paint operations.
+ *
+ * These buffers are also used for undo when available.
+ *
+ * \{ */
+
+static ImBuf *imbuf_alloc_temp_tile(void)
+{
+ return IMB_allocImBuf(
+ ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE, 32, IB_rectfloat | IB_rect);
+}
+
+typedef struct PaintTile {
+ struct PaintTile *next, *prev;
+ Image *image;
+ ImBuf *ibuf;
+ union {
+ float *fp;
+ uint *uint;
+ void *pt;
+ } rect;
+ ushort *mask;
+ bool valid;
+ bool use_float;
+ int x, y;
+} PaintTile;
+
+static void ptile_free(PaintTile *ptile)
+{
+ if (ptile->rect.pt) {
+ MEM_freeN(ptile->rect.pt);
+ }
+ if (ptile->mask) {
+ MEM_freeN(ptile->mask);
+ }
+ MEM_freeN(ptile);
+}
+
+static void ptile_free_list(ListBase *paint_tiles)
+{
+ for (PaintTile *ptile = paint_tiles->first, *ptile_next; ptile; ptile = ptile_next) {
+ ptile_next = ptile->next;
+ ptile_free(ptile);
+ }
+ BLI_listbase_clear(paint_tiles);
+}
+
+static void ptile_invalidate_list(ListBase *paint_tiles)
+{
+ for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
+ ptile->valid = false;
+ }
+}
+
+void *ED_image_paint_tile_find(ListBase *paint_tiles,
+ Image *image,
+ ImBuf *ibuf,
+ int x_tile,
+ int y_tile,
+ ushort **r_mask,
+ bool validate)
+{
+ for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
+ if (ptile->x == x_tile && ptile->y == y_tile) {
+ if (ptile->image == image && ptile->ibuf == ibuf) {
+ if (r_mask) {
+ /* allocate mask if requested. */
+ if (!ptile->mask) {
+ ptile->mask = MEM_callocN(sizeof(ushort) * SQUARE(ED_IMAGE_UNDO_TILE_SIZE),
+ "UndoImageTile.mask");
+ }
+ *r_mask = ptile->mask;
+ }
+ if (validate) {
+ ptile->valid = true;
+ }
+ return ptile->rect.pt;
+ }
+ }
+ }
+ return NULL;
+}
+
+void *ED_image_paint_tile_push(ListBase *paint_tiles,
+ Image *image,
+ ImBuf *ibuf,
+ ImBuf **tmpibuf,
+ int x_tile,
+ int y_tile,
+ ushort **r_mask,
+ bool **r_valid,
+ bool use_thread_lock,
+ bool find_prev)
+{
+ const bool has_float = (ibuf->rect_float != NULL);
+
+ /* check if tile is already pushed */
+
+ /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
+ if (find_prev) {
+ void *data = ED_image_paint_tile_find(paint_tiles, image, ibuf, x_tile, y_tile, r_mask, true);
+ if (data) {
+ return data;
+ }
+ }
+
+ if (*tmpibuf == NULL) {
+ *tmpibuf = imbuf_alloc_temp_tile();
+ }
+
+ PaintTile *ptile = MEM_callocN(sizeof(PaintTile), "PaintTile");
+
+ ptile->image = image;
+ ptile->ibuf = ibuf;
+
+ ptile->x = x_tile;
+ ptile->y = y_tile;
+
+ /* add mask explicitly here */
+ if (r_mask) {
+ *r_mask = ptile->mask = MEM_callocN(sizeof(ushort) * SQUARE(ED_IMAGE_UNDO_TILE_SIZE),
+ "PaintTile.mask");
+ }
+
+ ptile->rect.pt = MEM_mapallocN((ibuf->rect_float ? sizeof(float[4]) : sizeof(char[4])) *
+ SQUARE(ED_IMAGE_UNDO_TILE_SIZE),
+ "PaintTile.rect");
+
+ ptile->use_float = has_float;
+ ptile->valid = true;
+
+ if (r_valid) {
+ *r_valid = &ptile->valid;
+ }
+
+ IMB_rectcpy(*tmpibuf,
+ ibuf,
+ 0,
+ 0,
+ x_tile * ED_IMAGE_UNDO_TILE_SIZE,
+ y_tile * ED_IMAGE_UNDO_TILE_SIZE,
+ ED_IMAGE_UNDO_TILE_SIZE,
+ ED_IMAGE_UNDO_TILE_SIZE);
+
+ if (has_float) {
+ SWAP(float *, ptile->rect.fp, (*tmpibuf)->rect_float);
+ }
+ else {
+ SWAP(uint *, ptile->rect.uint, (*tmpibuf)->rect);
+ }
+
+ if (use_thread_lock) {
+ BLI_spin_lock(&paint_tiles_lock);
+ }
+ BLI_addtail(paint_tiles, ptile);
+
+ if (use_thread_lock) {
+ BLI_spin_unlock(&paint_tiles_lock);
+ }
+ return ptile->rect.pt;
+}
+
+static void ptile_restore_runtime_list(ListBase *paint_tiles)
+{
+ ImBuf *tmpibuf = imbuf_alloc_temp_tile();
+
+ for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
+ Image *image = ptile->image;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
+ const bool has_float = (ibuf->rect_float != NULL);
+
+ if (has_float) {
+ SWAP(float *, ptile->rect.fp, tmpibuf->rect_float);
+ }
+ else {
+ SWAP(uint *, ptile->rect.uint, tmpibuf->rect);
+ }
+
+ IMB_rectcpy(
+ ibuf, tmpibuf, ptile->x, ptile->y, 0, 0, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE);
+
+ if (has_float) {
+ SWAP(float *, ptile->rect.fp, tmpibuf->rect_float);
+ }
+ else {
+ SWAP(uint *, ptile->rect.uint, tmpibuf->rect);
+ }
+
+ GPU_free_image(image); /* force OpenGL reload (maybe partial update will operate better?) */
+ if (ibuf->rect_float) {
+ ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
+ }
+ if (ibuf->mipmap[0]) {
+ ibuf->userflags |= IB_MIPMAP_INVALID; /* force mip-map recreation. */
+ }
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+
+ IMB_freeImBuf(tmpibuf);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Undo Tile
+ * \{ */
+
+static uint index_from_xy(uint tile_x, uint tile_y, const uint tiles_dims[2])
+{
+ BLI_assert(tile_x < tiles_dims[0] && tile_y < tiles_dims[1]);
+ return (tile_y * tiles_dims[0]) + tile_x;
+}
+
+typedef struct UndoImageTile {
+ union {
+ float *fp;
+ uint *uint;
+ void *pt;
+ } rect;
+ int users;
+} UndoImageTile;
+
+static UndoImageTile *utile_alloc(bool has_float)
+{
+ UndoImageTile *utile = MEM_callocN(sizeof(*utile), "ImageUndoTile");
+ if (has_float) {
+ utile->rect.fp = MEM_mallocN(sizeof(float[4]) * SQUARE(ED_IMAGE_UNDO_TILE_SIZE), __func__);
+ }
+ else {
+ utile->rect.uint = MEM_mallocN(sizeof(uint) * SQUARE(ED_IMAGE_UNDO_TILE_SIZE), __func__);
+ }
+ return utile;
+}
+
+static void utile_init_from_imbuf(
+ UndoImageTile *utile, const uint x, const uint y, const ImBuf *ibuf, ImBuf *tmpibuf)
+{
+ const bool has_float = ibuf->rect_float;
+
+ if (has_float) {
+ SWAP(float *, utile->rect.fp, tmpibuf->rect_float);
+ }
+ else {
+ SWAP(uint *, utile->rect.uint, tmpibuf->rect);
+ }
+
+ IMB_rectcpy(tmpibuf, ibuf, 0, 0, x, y, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE);
+
+ if (has_float) {
+ SWAP(float *, utile->rect.fp, tmpibuf->rect_float);
+ }
+ else {
+ SWAP(uint *, utile->rect.uint, tmpibuf->rect);
+ }
+}
+
+static void utile_restore(
+ const UndoImageTile *utile, const uint x, const uint y, ImBuf *ibuf, ImBuf *tmpibuf)
+{
+ const bool has_float = ibuf->rect_float;
+ float *prev_rect_float = tmpibuf->rect_float;
+ uint *prev_rect = tmpibuf->rect;
+
+ if (has_float) {
+ tmpibuf->rect_float = utile->rect.fp;
+ }
+ else {
+ tmpibuf->rect = utile->rect.uint;
+ }
+
+ IMB_rectcpy(ibuf, tmpibuf, x, y, 0, 0, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE);
+
+ tmpibuf->rect_float = prev_rect_float;
+ tmpibuf->rect = prev_rect;
+}
+
+static void utile_decref(UndoImageTile *utile)
+{
+ utile->users -= 1;
+ BLI_assert(utile->users >= 0);
+ if (utile->users == 0) {
+ MEM_freeN(utile->rect.pt);
+ MEM_freeN(utile);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Undo Buffer
+ * \{ */
+
+typedef struct UndoImageBuf {
+ struct UndoImageBuf *next, *prev;
+
+ /**
+ * The buffer after the undo step has executed.
+ */
+ struct UndoImageBuf *post;
+
+ char ibuf_name[IMB_FILENAME_SIZE];
+
+ UndoImageTile **tiles;
+
+ /** Can calculate these from dims, just for convenience. */
+ uint tiles_len;
+ uint tiles_dims[2];
+
+ uint image_dims[2];
+
+ /** Store variables from the image. */
+ struct {
+ short source;
+ bool use_float;
+ char gen_type;
+ } image_state;
+
+} UndoImageBuf;
+
+static UndoImageBuf *ubuf_from_image_no_tiles(Image *image, const ImBuf *ibuf)
+{
+ UndoImageBuf *ubuf = MEM_callocN(sizeof(*ubuf), __func__);
+
+ ubuf->image_dims[0] = ibuf->x;
+ ubuf->image_dims[1] = ibuf->y;
+
+ ubuf->tiles_dims[0] = ED_IMAGE_UNDO_TILE_NUMBER(ubuf->image_dims[0]);
+ ubuf->tiles_dims[1] = ED_IMAGE_UNDO_TILE_NUMBER(ubuf->image_dims[1]);
+
+ ubuf->tiles_len = ubuf->tiles_dims[0] * ubuf->tiles_dims[1];
+ ubuf->tiles = MEM_callocN(sizeof(*ubuf->tiles) * ubuf->tiles_len, __func__);
+
+ BLI_strncpy(ubuf->ibuf_name, ibuf->name, sizeof(ubuf->ibuf_name));
+ ubuf->image_state.gen_type = image->gen_type;
+ ubuf->image_state.source = image->source;
+ ubuf->image_state.use_float = ibuf->rect_float != NULL;
+
+ return ubuf;
+}
+
+static void ubuf_from_image_all_tiles(UndoImageBuf *ubuf, const ImBuf *ibuf)
+{
+ ImBuf *tmpibuf = imbuf_alloc_temp_tile();
+
+ const bool has_float = ibuf->rect_float;
+ int i = 0;
+ for (uint y_tile = 0; y_tile < ubuf->tiles_dims[1]; y_tile += 1) {
+ uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS;
+ for (uint x_tile = 0; x_tile < ubuf->tiles_dims[0]; x_tile += 1) {
+ uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS;
+
+ BLI_assert(ubuf->tiles[i] == NULL);
+ UndoImageTile *utile = utile_alloc(has_float);
+ utile->users = 1;
+ utile_init_from_imbuf(utile, x, y, ibuf, tmpibuf);
+ ubuf->tiles[i] = utile;
+
+ i += 1;
+ }
+ }
+
+ IMB_freeImBuf(tmpibuf);
+}
+
+static void ubuf_free(UndoImageBuf *ubuf)
+{
+ UndoImageBuf *ubuf_post = ubuf->post;
+ for (uint i = 0; i < ubuf->tiles_len; i++) {
+ UndoImageTile *utile = ubuf->tiles[i];
+ utile_decref(utile);
+ }
+ MEM_freeN(ubuf->tiles);
+ MEM_freeN(ubuf);
+ if (ubuf_post) {
+ ubuf_free(ubuf_post);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Undo Handle
+ * \{ */
+
+typedef struct UndoImageHandle {
+ struct UndoImageHandle *next, *prev;
+
+ /** Each undo handle refers to a single image which may have multiple buffers. */
+ UndoRefID_Image image_ref;
+
+ /**
+ * List of #UndoImageBuf's to support multiple buffers per image.
+ *
+ * \note To properly support multiple buffers per image
+ * we would need to store an #ImageUser for each #UndoImageBuf.
+ * since when restoring the image we use:
+ * `BKE_image_acquire_ibuf(image, NULL, NULL)`.
+ */
+ ListBase buffers;
+
+} UndoImageHandle;
+
+static void uhandle_restore_list(ListBase *undo_handles, bool use_init)
+{
+ ImBuf *tmpibuf = imbuf_alloc_temp_tile();
+
+ for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) {
+ /* Tiles only added to second set of tiles. */
+ Image *image = uh->image_ref.ptr;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
+ if (UNLIKELY(ibuf == NULL)) {
+ CLOG_ERROR(&LOG, "Unable to get buffer for image '%s'", image->id.name + 2);
+ continue;
+ }
+ bool changed = false;
+ for (UndoImageBuf *ubuf_iter = uh->buffers.first; ubuf_iter; ubuf_iter = ubuf_iter->next) {
+ UndoImageBuf *ubuf = use_init ? ubuf_iter : ubuf_iter->post;
+ IMB_rect_size_set(ibuf, ubuf->image_dims);
+ int i = 0;
+ for (uint y_tile = 0; y_tile < ubuf->tiles_dims[1]; y_tile += 1) {
+ uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS;
+ for (uint x_tile = 0; x_tile < ubuf->tiles_dims[0]; x_tile += 1) {
+ uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS;
+ utile_restore(ubuf->tiles[i], x, y, ibuf, tmpibuf);
+ changed = true;
+ i += 1;
+ }
+ }
+ }
+
+ if (changed) {
+ BKE_image_mark_dirty(image, ibuf);
+ GPU_free_image(image); /* force OpenGL reload */
+
+ if (ibuf->rect_float) {
+ ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
+ }
+ if (ibuf->mipmap[0]) {
+ ibuf->userflags |= IB_MIPMAP_INVALID; /* force mip-map recreation. */
+ }
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+
+ DEG_id_tag_update(&image->id, 0);
+ }
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+
+ IMB_freeImBuf(tmpibuf);
+}
+
+static void uhandle_free_list(ListBase *undo_handles)
+{
+ LISTBASE_FOREACH_MUTABLE (UndoImageHandle *, uh, undo_handles) {
+ LISTBASE_FOREACH_MUTABLE (UndoImageBuf *, ubuf, &uh->buffers) {
+ ubuf_free(ubuf);
+ }
+ MEM_freeN(uh);
+ }
+ BLI_listbase_clear(undo_handles);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Undo Internal Utilities
+ * \{ */
+
+/** #UndoImageHandle utilities */
+
+static UndoImageBuf *uhandle_lookup_ubuf(UndoImageHandle *uh,
+ const Image *UNUSED(image),
+ const char *ibuf_name)
+{
+ for (UndoImageBuf *ubuf = uh->buffers.first; ubuf; ubuf = ubuf->next) {
+ if (STREQ(ubuf->ibuf_name, ibuf_name)) {
+ return ubuf;
+ }
+ }
+ return NULL;
+}
+
+static UndoImageBuf *uhandle_add_ubuf(UndoImageHandle *uh, Image *image, ImBuf *ibuf)
+{
+ BLI_assert(uhandle_lookup_ubuf(uh, image, ibuf->name) == NULL);
+ UndoImageBuf *ubuf = ubuf_from_image_no_tiles(image, ibuf);
+ BLI_addtail(&uh->buffers, ubuf);
+
+ ubuf->post = NULL;
+
+ return ubuf;
+}
+
+static UndoImageBuf *uhandle_ensure_ubuf(UndoImageHandle *uh, Image *image, ImBuf *ibuf)
+{
+ UndoImageBuf *ubuf = uhandle_lookup_ubuf(uh, image, ibuf->name);
+ if (ubuf == NULL) {
+ ubuf = uhandle_add_ubuf(uh, image, ibuf);
+ }
+ return ubuf;
+}
+
+static UndoImageHandle *uhandle_lookup_by_name(ListBase *undo_handles, const Image *image)
+{
+ for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) {
+ if (STREQ(image->id.name + 2, uh->image_ref.name + 2)) {
+ return uh;
+ }
+ }
+ return NULL;
+}
+
+static UndoImageHandle *uhandle_lookup(ListBase *undo_handles, const Image *image)
+{
+ for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) {
+ if (image == uh->image_ref.ptr) {
+ return uh;
+ }
+ }
+ return NULL;
+}
+
+static UndoImageHandle *uhandle_add(ListBase *undo_handles, Image *image)
+{
+ BLI_assert(uhandle_lookup(undo_handles, image) == NULL);
+ UndoImageHandle *uh = MEM_callocN(sizeof(*uh), __func__);
+ uh->image_ref.ptr = image;
+ BLI_addtail(undo_handles, uh);
+ return uh;
+}
+
+static UndoImageHandle *uhandle_ensure(ListBase *undo_handles, Image *image)
+{
+ UndoImageHandle *uh = uhandle_lookup(undo_handles, image);
+ if (uh == NULL) {
+ uh = uhandle_add(undo_handles, image);
+ }
+ return uh;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
+
+typedef struct ImageUndoStep {
+ UndoStep step;
+
+ /** #UndoImageHandle */
+ ListBase handles;
+
+ /**
+ * #PaintTile
+ * Run-time only data (active during a paint stroke).
+ */
+ ListBase paint_tiles;
+
+ bool is_encode_init;
+ ePaintMode paint_mode;
+
+} ImageUndoStep;
+
+/**
+ * Find the previous undo buffer from this one.
+ * \note We could look into undo steps even further back.
+ */
+static UndoImageBuf *ubuf_lookup_from_reference(ImageUndoStep *us_prev,
+ const Image *image,
+ const UndoImageBuf *ubuf)
+{
+ /* Use name lookup because because the pointer is cleared for previous steps. */
+ UndoImageHandle *uh_prev = uhandle_lookup_by_name(&us_prev->handles, image);
+ if (uh_prev != NULL) {
+ UndoImageBuf *ubuf_reference = uhandle_lookup_ubuf(uh_prev, image, ubuf->ibuf_name);
+ if (ubuf_reference) {
+ ubuf_reference = ubuf_reference->post;
+ if ((ubuf_reference->image_dims[0] == ubuf->image_dims[0]) &&
+ (ubuf_reference->image_dims[1] == ubuf->image_dims[1])) {
+ return ubuf_reference;
+ }
+ }
+ }
+ return NULL;
+}
+
+static bool image_undosys_poll(bContext *C)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && (sa->spacetype == SPACE_IMAGE)) {
+ SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
+ if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
+ return true;
+ }
+ }
+ else {
+ if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ /* dummy, memory is cleared anyway. */
+ us->is_encode_init = true;
+ BLI_listbase_clear(&us->handles);
+ BLI_listbase_clear(&us->paint_tiles);
+}
+
+static bool image_undosys_step_encode(struct bContext *C,
+ struct Main *UNUSED(bmain),
+ UndoStep *us_p)
+{
+ /* Encoding is done along the way by adding tiles
+ * to the current 'ImageUndoStep' added by encode_init.
+ *
+ * This function ensures there are previous and current states of the image in the undo buffer.
+ */
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+
+ BLI_assert(us->step.data_size == 0);
+
+ if (us->is_encode_init) {
+
+ ImBuf *tmpibuf = imbuf_alloc_temp_tile();
+
+ ImageUndoStep *us_reference = (ImageUndoStep *)ED_undo_stack_get()->step_active;
+ while (us_reference && us_reference->step.type != BKE_UNDOSYS_TYPE_IMAGE) {
+ us_reference = (ImageUndoStep *)us_reference->step.prev;
+ }
+
+ /* Initialize undo tiles from ptiles (if they exist). */
+ for (PaintTile *ptile = us->paint_tiles.first, *ptile_next; ptile; ptile = ptile_next) {
+ if (ptile->valid) {
+ UndoImageHandle *uh = uhandle_ensure(&us->handles, ptile->image);
+ UndoImageBuf *ubuf_pre = uhandle_ensure_ubuf(uh, ptile->image, ptile->ibuf);
+
+ UndoImageTile *utile = MEM_callocN(sizeof(*utile), "UndoImageTile");
+ utile->users = 1;
+ utile->rect.pt = ptile->rect.pt;
+ ptile->rect.pt = NULL;
+ const uint tile_index = index_from_xy(ptile->x, ptile->y, ubuf_pre->tiles_dims);
+
+ BLI_assert(ubuf_pre->tiles[tile_index] == NULL);
+ ubuf_pre->tiles[tile_index] = utile;
+ }
+ ptile_next = ptile->next;
+ ptile_free(ptile);
+ }
+ BLI_listbase_clear(&us->paint_tiles);
+
+ for (UndoImageHandle *uh = us->handles.first; uh; uh = uh->next) {
+ for (UndoImageBuf *ubuf_pre = uh->buffers.first; ubuf_pre; ubuf_pre = ubuf_pre->next) {
+
+ ImBuf *ibuf = BKE_image_acquire_ibuf(uh->image_ref.ptr, NULL, NULL);
+
+ const bool has_float = ibuf->rect_float;
+
+ BLI_assert(ubuf_pre->post == NULL);
+ ubuf_pre->post = ubuf_from_image_no_tiles(uh->image_ref.ptr, ibuf);
+ UndoImageBuf *ubuf_post = ubuf_pre->post;
+
+ if (ubuf_pre->image_dims[0] != ubuf_post->image_dims[0] ||
+ ubuf_pre->image_dims[1] != ubuf_post->image_dims[1]) {
+ ubuf_from_image_all_tiles(ubuf_post, ibuf);
+ }
+ else {
+ /* Search for the previous buffer. */
+ UndoImageBuf *ubuf_reference = (us_reference ?
+ ubuf_lookup_from_reference(
+ us_reference, uh->image_ref.ptr, ubuf_post) :
+ NULL);
+
+ int i = 0;
+ for (uint y_tile = 0; y_tile < ubuf_pre->tiles_dims[1]; y_tile += 1) {
+ uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS;
+ for (uint x_tile = 0; x_tile < ubuf_pre->tiles_dims[0]; x_tile += 1) {
+ uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS;
+
+ if ((ubuf_reference != NULL) && ((ubuf_pre->tiles[i] == NULL) ||
+ /* In this case the paint stroke as has added a tile
+ * which we have a duplicate reference available. */
+ (ubuf_pre->tiles[i]->users == 1))) {
+ if (ubuf_pre->tiles[i] != NULL) {
+ /* If we have a reference, re-use this single use tile for the post state. */
+ BLI_assert(ubuf_pre->tiles[i]->users == 1);
+ ubuf_post->tiles[i] = ubuf_pre->tiles[i];
+ ubuf_pre->tiles[i] = NULL;
+ utile_init_from_imbuf(ubuf_post->tiles[i], x, y, ibuf, tmpibuf);
+ }
+ else {
+ BLI_assert(ubuf_post->tiles[i] == NULL);
+ ubuf_post->tiles[i] = ubuf_reference->tiles[i];
+ ubuf_post->tiles[i]->users += 1;
+ }
+ BLI_assert(ubuf_pre->tiles[i] == NULL);
+ ubuf_pre->tiles[i] = ubuf_reference->tiles[i];
+ ubuf_pre->tiles[i]->users += 1;
+
+ BLI_assert(ubuf_pre->tiles[i] != NULL);
+ BLI_assert(ubuf_post->tiles[i] != NULL);
+ }
+ else {
+ UndoImageTile *utile = utile_alloc(has_float);
+ utile_init_from_imbuf(utile, x, y, ibuf, tmpibuf);
+
+ if (ubuf_pre->tiles[i] != NULL) {
+ ubuf_post->tiles[i] = utile;
+ utile->users = 1;
+ }
+ else {
+ ubuf_pre->tiles[i] = utile;
+ ubuf_post->tiles[i] = utile;
+ utile->users = 2;
+ }
+ }
+ BLI_assert(ubuf_pre->tiles[i] != NULL);
+ BLI_assert(ubuf_post->tiles[i] != NULL);
+ i += 1;
+ }
+ }
+ }
+ BKE_image_release_ibuf(uh->image_ref.ptr, ibuf, NULL);
+ }
+ }
+
+ IMB_freeImBuf(tmpibuf);
+
+ /* Useful to debug tiles are stored correctly. */
+ if (false) {
+ uhandle_restore_list(&us->handles, false);
+ }
+ }
+ else {
+ /* Happens when switching modes. */
+ ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C);
+ BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
+ us->paint_mode = paint_mode;
+ }
+
+ us_p->is_applied = true;
+
+ return true;
+}
+
+static void image_undosys_step_decode_undo_impl(ImageUndoStep *us, bool is_final)
+{
+ BLI_assert(us->step.is_applied == true);
+ uhandle_restore_list(&us->handles, !is_final);
+ us->step.is_applied = false;
+}
+
+static void image_undosys_step_decode_redo_impl(ImageUndoStep *us)
+{
+ BLI_assert(us->step.is_applied == false);
+ uhandle_restore_list(&us->handles, false);
+ us->step.is_applied = true;
+}
+
+static void image_undosys_step_decode_undo(ImageUndoStep *us, bool is_final)
+{
+ ImageUndoStep *us_iter = us;
+ while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) {
+ if (us_iter->step.next->is_applied == false) {
+ break;
+ }
+ us_iter = (ImageUndoStep *)us_iter->step.next;
+ }
+ while (us_iter != us || (!is_final && us_iter == us)) {
+
+ image_undosys_step_decode_undo_impl(us_iter, is_final);
+ if (us_iter == us) {
+ break;
+ }
+ us_iter = (ImageUndoStep *)us_iter->step.prev;
+ }
+}
+
+static void image_undosys_step_decode_redo(ImageUndoStep *us)
+{
+ ImageUndoStep *us_iter = us;
+ while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) {
+ if (us_iter->step.prev->is_applied == true) {
+ break;
+ }
+ us_iter = (ImageUndoStep *)us_iter->step.prev;
+ }
+ while (us_iter && (us_iter->step.is_applied == false)) {
+ image_undosys_step_decode_redo_impl(us_iter);
+ if (us_iter == us) {
+ break;
+ }
+ us_iter = (ImageUndoStep *)us_iter->step.next;
+ }
+}
+
+static void image_undosys_step_decode(
+ struct bContext *C, struct Main *bmain, UndoStep *us_p, int dir, bool is_final)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ if (dir < 0) {
+ image_undosys_step_decode_undo(us, is_final);
+ }
+ else {
+ image_undosys_step_decode_redo(us);
+ }
+
+ if (us->paint_mode == PAINT_MODE_TEXTURE_3D) {
+ ED_object_mode_set(C, OB_MODE_TEXTURE_PAINT);
+ }
+
+ /* Refresh texture slots. */
+ ED_editors_init_for_undo(bmain);
+}
+
+static void image_undosys_step_free(UndoStep *us_p)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ uhandle_free_list(&us->handles);
+
+ /* Typically this list will have been cleared. */
+ ptile_free_list(&us->paint_tiles);
+}
+
+static void image_undosys_foreach_ID_ref(UndoStep *us_p,
+ UndoTypeForEachIDRefFn foreach_ID_ref_fn,
+ void *user_data)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ for (UndoImageHandle *uh = us->handles.first; uh; uh = uh->next) {
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&uh->image_ref));
+ }
+}
+
+/* Export for ED_undo_sys. */
+void ED_image_undosys_type(UndoType *ut)
+{
+ ut->name = "Image";
+ ut->poll = image_undosys_poll;
+ ut->step_encode_init = image_undosys_step_encode_init;
+ ut->step_encode = image_undosys_step_encode;
+ ut->step_decode = image_undosys_step_decode;
+ ut->step_free = image_undosys_step_free;
+
+ ut->step_foreach_ID_ref = image_undosys_foreach_ID_ref;
+
+ ut->use_context = true;
+
+ ut->step_size = sizeof(ImageUndoStep);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+ListBase *ED_image_paint_tile_list_get(void)
+{
+ UndoStack *ustack = ED_undo_stack_get();
+ UndoStep *us_prev = ustack->step_init;
+ UndoStep *us_p = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_IMAGE);
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ /* We should always have an undo push started when accessing tiles,
+ * not doing this means we won't have paint_mode correctly set. */
+ BLI_assert(us_p == us_prev);
+ if (us_p != us_prev) {
+ /* Fallback value until we can be sure this never happens. */
+ us->paint_mode = PAINT_MODE_TEXTURE_2D;
+ }
+ return &us->paint_tiles;
+}
+
+/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/
+void ED_image_undo_restore(UndoStep *us)
+{
+ ListBase *paint_tiles = &((ImageUndoStep *)us)->paint_tiles;
+ ptile_restore_runtime_list(paint_tiles);
+ ptile_invalidate_list(paint_tiles);
+}
+
+static ImageUndoStep *image_undo_push_begin(const char *name, int paint_mode)
+{
+ UndoStack *ustack = ED_undo_stack_get();
+ bContext *C = NULL; /* special case, we never read from this. */
+ UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE);
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
+ us->paint_mode = paint_mode;
+ return us;
+}
+
+void ED_image_undo_push_begin(const char *name, int paint_mode)
+{
+ image_undo_push_begin(name, paint_mode);
+}
+
+void ED_image_undo_push_begin_with_image(const char *name, Image *image, ImBuf *ibuf)
+{
+ ImageUndoStep *us = image_undo_push_begin(name, PAINT_MODE_TEXTURE_2D);
+
+ UndoImageHandle *uh = uhandle_ensure(&us->handles, image);
+ UndoImageBuf *ubuf_pre = uhandle_ensure_ubuf(uh, image, ibuf);
+ BLI_assert(ubuf_pre->post == NULL);
+
+ ImageUndoStep *us_reference = (ImageUndoStep *)ED_undo_stack_get()->step_active;
+ while (us_reference && us_reference->step.type != BKE_UNDOSYS_TYPE_IMAGE) {
+ us_reference = (ImageUndoStep *)us_reference->step.prev;
+ }
+ UndoImageBuf *ubuf_reference = (us_reference ?
+ ubuf_lookup_from_reference(us_reference, image, ubuf_pre) :
+ NULL);
+
+ if (ubuf_reference) {
+ memcpy(ubuf_pre->tiles, ubuf_reference->tiles, sizeof(*ubuf_pre->tiles) * ubuf_pre->tiles_len);
+ for (uint i = 0; i < ubuf_pre->tiles_len; i++) {
+ UndoImageTile *utile = ubuf_pre->tiles[i];
+ utile->users += 1;
+ }
+ }
+ else {
+ ubuf_from_image_all_tiles(ubuf_pre, ibuf);
+ }
+}
+
+void ED_image_undo_push_end(void)
+{
+ UndoStack *ustack = ED_undo_stack_get();
+ BKE_undosys_step_push(ustack, NULL, NULL);
+ WM_file_tag_modified();
+}
+
+/** \} */
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 5fa4fe3e077..a88ecc91868 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -207,6 +207,7 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_view_all);
WM_operatortype_append(IMAGE_OT_view_pan);
WM_operatortype_append(IMAGE_OT_view_selected);
+ WM_operatortype_append(IMAGE_OT_view_center_cursor);
WM_operatortype_append(IMAGE_OT_view_zoom);
WM_operatortype_append(IMAGE_OT_view_zoom_in);
WM_operatortype_append(IMAGE_OT_view_zoom_out);
@@ -229,6 +230,7 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_unpack);
WM_operatortype_append(IMAGE_OT_invert);
+ WM_operatortype_append(IMAGE_OT_resize);
WM_operatortype_append(IMAGE_OT_cycle_render_slot);
WM_operatortype_append(IMAGE_OT_clear_render_slot);
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index 106edc290d5..b51aec90e4f 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -441,11 +441,11 @@ static void stats_string(ViewLayer *view_layer)
#undef SCENE_STATS_FMT_INT
/* get memory statistics */
- BLI_str_format_byte_unit(formatted_mem, mem_in_use - mmap_in_use, true);
+ BLI_str_format_byte_unit(formatted_mem, mem_in_use - mmap_in_use, false);
ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, TIP_(" | Mem: %s"), formatted_mem);
if (mmap_in_use) {
- BLI_str_format_byte_unit(formatted_mem, mmap_in_use, true);
+ BLI_str_format_byte_unit(formatted_mem, mmap_in_use, false);
BLI_snprintf(memstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_(" (%s)"), formatted_mem);
}
@@ -454,11 +454,11 @@ static void stats_string(ViewLayer *view_layer)
GPU_mem_stats_get(&gpu_tot_memory, &gpu_free_mem);
- BLI_str_format_byte_unit(formatted_mem, gpu_free_mem, true);
+ BLI_str_format_byte_unit(formatted_mem, gpu_free_mem, false);
ofs = BLI_snprintf(gpumemstr, MAX_INFO_MEM_LEN, TIP_(" | Free GPU Mem: %s"), formatted_mem);
if (gpu_tot_memory) {
- BLI_str_format_byte_unit(formatted_mem, gpu_tot_memory, true);
+ BLI_str_format_byte_unit(formatted_mem, gpu_tot_memory, false);
BLI_snprintf(gpumemstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_("/%s"), formatted_mem);
}
}
@@ -581,7 +581,7 @@ const char *ED_info_stats_string(Main *bmain, Scene *scene, ViewLayer *view_laye
if (wm->is_interface_locked) {
return "";
}
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
if (!view_layer->stats) {
stats_update(depsgraph, view_layer);
}
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index 9d6ccd6fe35..913d2a06d46 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -47,7 +47,6 @@
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
-#include "GPU_draw.h"
#include "GPU_state.h"
#include "WM_types.h"
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index a69eb254621..3beb12fbb2a 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -24,6 +24,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_system.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
@@ -44,9 +45,9 @@
#include "BIF_glutil.h"
-#include "GPU_draw.h"
#include "GPU_batch.h"
#include "GPU_batch_presets.h"
+#include "GPU_extensions.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
#include "GPU_state.h"
@@ -730,37 +731,7 @@ static void node_buts_image_user(uiLayout *layout,
static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiLayout *row, *col, *sub;
-
- uiItemR(layout, ptr, "vector_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
-
- col = uiLayoutColumn(row, true);
- uiItemL(col, IFACE_("Location:"), ICON_NONE);
- uiItemR(col, ptr, "translation", 0, "", ICON_NONE);
-
- col = uiLayoutColumn(row, true);
- uiItemL(col, IFACE_("Rotation:"), ICON_NONE);
- uiItemR(col, ptr, "rotation", 0, "", ICON_NONE);
-
- col = uiLayoutColumn(row, true);
- uiItemL(col, IFACE_("Scale:"), ICON_NONE);
- uiItemR(col, ptr, "scale", 0, "", ICON_NONE);
-
- row = uiLayoutRow(layout, false);
-
- col = uiLayoutColumn(row, true);
- uiItemR(col, ptr, "use_min", 0, IFACE_("Min"), ICON_NONE);
- sub = uiLayoutColumn(col, true);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min"));
- uiItemR(sub, ptr, "min", 0, "", ICON_NONE);
-
- col = uiLayoutColumn(row, true);
- uiItemR(col, ptr, "use_max", 0, IFACE_("Max"), ICON_NONE);
- sub = uiLayoutColumn(col, true);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max"));
- uiItemR(sub, ptr, "max", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "vector_type", 0, NULL, ICON_NONE);
}
static void node_shader_buts_vect_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -937,14 +908,24 @@ static void node_shader_buts_tex_wave(uiLayout *layout, bContext *UNUSED(C), Poi
static void node_shader_buts_tex_musgrave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "musgrave_dimensions", 0, "", ICON_NONE);
uiItemR(layout, ptr, "musgrave_type", 0, "", ICON_NONE);
}
static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "coloring", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "distance", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "voronoi_dimensions", 0, "", ICON_NONE);
uiItemR(layout, ptr, "feature", 0, "", ICON_NONE);
+ int feature = RNA_enum_get(ptr, "feature");
+ if (!ELEM(feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS) &&
+ RNA_enum_get(ptr, "voronoi_dimensions") != 1) {
+ uiItemR(layout, ptr, "distance", 0, "", ICON_NONE);
+ }
+}
+
+static void node_shader_buts_tex_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "noise_dimensions", 0, "", ICON_NONE);
}
static void node_shader_buts_tex_pointdensity(uiLayout *layout,
@@ -1017,6 +998,18 @@ static void node_shader_buts_uvmap(uiLayout *layout, bContext *C, PointerRNA *pt
}
}
+static void node_shader_buts_vertex_color(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
+ if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
+ PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
+ uiItemPointerR(layout, ptr, "layer_name", &dataptr, "vertex_colors", "", ICON_GROUP_VCOL);
+ }
+ else {
+ uiItemL(layout, "No mesh in active object.", ICON_ERROR);
+ }
+}
+
static void node_shader_buts_uvalongstroke(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "use_tips", 0, NULL, 0);
@@ -1188,7 +1181,7 @@ static void node_shader_buts_ambient_occlusion(uiLayout *layout,
static void node_shader_buts_white_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "dimensions", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "noise_dimensions", 0, "", ICON_NONE);
}
/* only once called */
@@ -1266,6 +1259,9 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_TEX_VORONOI:
ntype->draw_buttons = node_shader_buts_tex_voronoi;
break;
+ case SH_NODE_TEX_NOISE:
+ ntype->draw_buttons = node_shader_buts_tex_noise;
+ break;
case SH_NODE_TEX_POINTDENSITY:
ntype->draw_buttons = node_shader_buts_tex_pointdensity;
break;
@@ -1315,6 +1311,9 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_UVMAP:
ntype->draw_buttons = node_shader_buts_uvmap;
break;
+ case SH_NODE_VERTEX_COLOR:
+ ntype->draw_buttons = node_shader_buts_vertex_color;
+ break;
case SH_NODE_UVALONGSTROKE:
ntype->draw_buttons = node_shader_buts_uvalongstroke;
break;
@@ -2703,6 +2702,10 @@ static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), Po
{
#ifndef WITH_OPENIMAGEDENOISE
uiItemL(layout, IFACE_("Disabled, built without OpenImageDenoise"), ICON_ERROR);
+#else
+ if (!BLI_cpu_support_sse41()) {
+ uiItemL(layout, IFACE_("Disabled, CPU with SSE4.1 is required"), ICON_ERROR);
+ }
#endif
uiItemR(layout, ptr, "use_hdr", 0, NULL, ICON_NONE);
@@ -3143,12 +3146,12 @@ static void node_template_properties_update(bNodeType *ntype)
bNodeSocketTemplate *stemp;
if (ntype->inputs) {
- for (stemp = ntype->inputs; stemp->type >= 0; ++stemp) {
+ for (stemp = ntype->inputs; stemp->type >= 0; stemp++) {
node_socket_template_properties_update(ntype, stemp);
}
}
if (ntype->outputs) {
- for (stemp = ntype->outputs; stemp->type >= 0; ++stemp) {
+ for (stemp = ntype->outputs; stemp->type >= 0; stemp++) {
node_socket_template_properties_update(ntype, stemp);
}
}
@@ -3769,7 +3772,7 @@ static void nodelink_batch_init(void)
GPU_vertbuf_data_alloc(vbo, vcount);
int v = 0;
- for (int k = 0; k < 2; ++k) {
+ for (int k = 0; k < 2; k++) {
unsigned char uv[2] = {0, 0};
float pos[2] = {0.0f, 0.0f};
float exp[2] = {0.0f, 1.0f};
@@ -3780,7 +3783,7 @@ static void nodelink_batch_init(void)
}
/* curve strip */
- for (int i = 0; i < LINK_RESOL; ++i) {
+ for (int i = 0; i < LINK_RESOL; i++) {
uv[0] = 255 * (i / (float)(LINK_RESOL - 1));
uv[1] = 0;
set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
@@ -3796,7 +3799,7 @@ static void nodelink_batch_init(void)
copy_v2_v2(exp, arrow_expand_axis[0]);
set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
/* arrow */
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
uv[1] = 0;
copy_v2_v2(pos, arrow_verts[i]);
copy_v2_v2(exp, arrow_expand_axis[i]);
@@ -3887,7 +3890,9 @@ static void nodelink_batch_draw(SpaceNode *snode)
void nodelink_batch_start(SpaceNode *UNUSED(snode))
{
- g_batch_link.enabled = true;
+ /* TODO: partial workaround for NVIDIA driver bug on recent GTX/RTX cards,
+ * that breaks instancing when using indirect draw-call (see T70011). */
+ g_batch_link.enabled = !GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY);
}
void nodelink_batch_end(SpaceNode *snode)
diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c
index 01a30f677a3..664349b3c3b 100644
--- a/source/blender/editors/space_node/node_add.c
+++ b/source/blender/editors/space_node/node_add.c
@@ -309,7 +309,7 @@ void NODE_OT_add_reroute(wmOperatorType *ot)
prop = RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
/* internal */
- RNA_def_int(ot->srna, "cursor", BC_CROSSCURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
+ RNA_def_int(ot->srna, "cursor", WM_CURSOR_CROSS, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
}
/* ****************** Add File Node Operator ******************* */
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index 6dc2182b684..2081c69a1a4 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -47,7 +47,6 @@
#include "BIF_glutil.h"
-#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
@@ -261,7 +260,7 @@ void ED_node_sort(bNodeTree *ntree)
do {
/* setup first_b pointer */
- for (b = 0; b < k && first_b; ++b) {
+ for (b = 0; b < k && first_b; b++) {
first_b = first_b->next;
}
/* all batches merged? */
@@ -289,7 +288,7 @@ void ED_node_sort(bNodeTree *ntree)
/* setup first pointers for next batch */
first_b = node_b;
- for (; b < k; ++b) {
+ for (; b < k; b++) {
/* all nodes sorted? */
if (first_b == NULL) {
break;
@@ -970,7 +969,7 @@ void node_draw_sockets(View2D *v2d,
continue;
}
if (select_all || (sock->flag & SELECT)) {
- ++selected_input_len;
+ selected_input_len++;
continue;
}
@@ -995,7 +994,7 @@ void node_draw_sockets(View2D *v2d,
continue;
}
if (select_all || (sock->flag & SELECT)) {
- ++selected_output_len;
+ selected_output_len++;
continue;
}
@@ -1457,16 +1456,16 @@ static void node_draw_hidden(const bContext *C,
int node_get_resize_cursor(int directions)
{
if (directions == 0) {
- return CURSOR_STD;
+ return WM_CURSOR_DEFAULT;
}
else if ((directions & ~(NODE_RESIZE_TOP | NODE_RESIZE_BOTTOM)) == 0) {
- return CURSOR_Y_MOVE;
+ return WM_CURSOR_Y_MOVE;
}
else if ((directions & ~(NODE_RESIZE_RIGHT | NODE_RESIZE_LEFT)) == 0) {
- return CURSOR_X_MOVE;
+ return WM_CURSOR_X_MOVE;
}
else {
- return CURSOR_EDIT;
+ return WM_CURSOR_EDIT;
}
}
@@ -1475,7 +1474,7 @@ void node_set_cursor(wmWindow *win, SpaceNode *snode, float cursor[2])
bNodeTree *ntree = snode->edittree;
bNode *node;
bNodeSocket *sock;
- int wmcursor = CURSOR_STD;
+ int wmcursor = WM_CURSOR_DEFAULT;
if (ntree) {
if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN | SOCK_OUT)) {
@@ -1732,11 +1731,11 @@ void drawnodespace(const bContext *C, ARegion *ar)
depth = 0;
while (path->prev && depth < max_depth) {
path = path->prev;
- ++depth;
+ depth++;
}
/* parent node trees in the background */
- for (curdepth = depth; curdepth > 0; path = path->next, --curdepth) {
+ for (curdepth = depth; curdepth > 0; path = path->next, curdepth--) {
ntree = path->nodetree;
if (ntree) {
snode_setup_v2d(snode, ar, path->view_center);
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index dcf901216f5..8811918b552 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -204,14 +204,13 @@ static void compo_initjob(void *cjv)
Scene *scene = cj->scene;
ViewLayer *view_layer = cj->view_layer;
- cj->compositor_depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
+ cj->compositor_depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
DEG_graph_build_for_compositor_preview(
cj->compositor_depsgraph, bmain, scene, view_layer, cj->ntree);
/* NOTE: Don't update animation to preserve unkeyed changes, this means can not use
* evaluate_on_framechange. */
- DEG_graph_flush_update(bmain, cj->compositor_depsgraph);
- DEG_evaluate_on_refresh(cj->compositor_depsgraph);
+ DEG_evaluate_on_refresh(bmain, cj->compositor_depsgraph);
bNodeTree *ntree_eval = (bNodeTree *)DEG_get_evaluated_id(cj->compositor_depsgraph,
&cj->ntree->id);
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index 3fd03bac874..08ac84cbb2f 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -298,7 +298,7 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
tlink->fromsock,
link->tonode->new_node,
link->tosock->new_sock);
- ++num_external_links;
+ num_external_links++;
}
}
@@ -331,7 +331,7 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
tlink->fromsock->new_sock,
link->tonode,
link->tosock);
- ++num_internal_links;
+ num_internal_links++;
}
}
}
@@ -695,7 +695,7 @@ static int node_get_selected_minmax(bNodeTree *ntree, bNode *gnode, float *min,
if (node_group_make_use_node(node, gnode)) {
nodeToView(node, 0.0f, 0.0f, &loc[0], &loc[1]);
minmax_v2v2_v2(min, max, loc);
- ++totselect;
+ totselect++;
}
}
@@ -717,7 +717,7 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
ListBase anim_basepaths = {NULL, NULL};
float min[2], max[2], center[2];
int totselect;
- bool expose_all = false;
+ bool expose_visible = false;
bNode *input_node, *output_node;
/* XXX rough guess, not nice but we don't have access to UI constants here ... */
@@ -735,7 +735,7 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
/* auto-add interface for "solo" nodes */
if (totselect == 1) {
- expose_all = true;
+ expose_visible = true;
}
/* move nodes over */
@@ -879,8 +879,8 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
}
}
- /* expose all unlinked sockets too */
- if (expose_all) {
+ /* expose all unlinked sockets too but only the visible ones*/
+ if (expose_visible) {
for (node = ngroup->nodes.first; node; node = node->next) {
if (node_group_make_use_node(node, gnode)) {
for (sock = node->inputs.first; sock; sock = sock->next) {
@@ -892,6 +892,9 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
break;
}
}
+ if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) {
+ skip = true;
+ }
if (skip) {
continue;
}
@@ -913,6 +916,9 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
skip = true;
}
}
+ if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) {
+ skip = true;
+ }
if (skip) {
continue;
}
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index cf52ca8489f..357ef31c51f 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -572,10 +572,10 @@ static int node_count_links(bNodeTree *ntree, bNodeSocket *sock)
int count = 0;
for (link = ntree->links.first; link; link = link->next) {
if (link->fromsock == sock) {
- ++count;
+ count++;
}
if (link->tosock == sock) {
- ++count;
+ count++;
}
}
return count;
@@ -599,7 +599,7 @@ static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link)
if (from_count > from->limit) {
nodeRemLink(ntree, tlink);
tlink = NULL;
- --from_count;
+ from_count--;
}
}
@@ -607,7 +607,7 @@ static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link)
if (to_count > to->limit) {
nodeRemLink(ntree, tlink);
tlink = NULL;
- --to_count;
+ to_count--;
}
}
}
@@ -1103,7 +1103,7 @@ void NODE_OT_links_cut(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
/* internal */
- RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
+ RNA_def_int(ot->srna, "cursor", WM_CURSOR_KNIFE, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
}
/* ********************** Detach links operator ***************** */
@@ -1567,7 +1567,7 @@ static bNodeSocket *socket_best_match(ListBase *sockets)
}
/* try all types, starting from 'highest' (i.e. colors, vectors, values) */
- for (type = maxtype; type >= 0; --type) {
+ for (type = maxtype; type >= 0; type--) {
for (sock = sockets->first; sock; sock = sock->next) {
if (!nodeSocketIsHidden(sock) && type == sock->type) {
return sock;
@@ -1576,7 +1576,7 @@ static bNodeSocket *socket_best_match(ListBase *sockets)
}
/* no visible sockets, unhide first of highest type */
- for (type = maxtype; type >= 0; --type) {
+ for (type = maxtype; type >= 0; type--) {
for (sock = sockets->first; sock; sock = sock->next) {
if (type == sock->type) {
sock->flag &= ~SOCK_HIDDEN;
diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c
index 78f36719880..b66cd0d3069 100644
--- a/source/blender/editors/space_node/node_select.c
+++ b/source/blender/editors/space_node/node_select.c
@@ -430,11 +430,9 @@ void node_select_single(bContext *C, bNode *node)
}
static int node_mouse_select(bContext *C,
+ wmOperator *op,
const int mval[2],
- const bool extend,
- const bool socket_select,
- const bool deselect_all,
- const bool wait_to_deselect_others)
+ bool wait_to_deselect_others)
{
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
@@ -445,8 +443,15 @@ static int node_mouse_select(bContext *C,
float cursor[2];
int ret_value = OPERATOR_CANCELLED;
- /* Waiting to deselect others is only allowed for basic selection. */
- BLI_assert(!(extend || socket_select) || !wait_to_deselect_others);
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+ /* always do socket_select when extending selection. */
+ const bool socket_select = extend || RNA_boolean_get(op->ptr, "socket_select");
+ const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
+
+ /* These cases are never modal. */
+ if (extend || socket_select) {
+ wait_to_deselect_others = false;
+ }
/* get mouse coordinates in view2d space */
UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &cursor[0], &cursor[1]);
@@ -552,19 +557,13 @@ static int node_mouse_select(bContext *C,
static int node_select_exec(bContext *C, wmOperator *op)
{
- int mval[2];
-
/* get settings from RNA properties for operator */
+ int mval[2];
mval[0] = RNA_int_get(op->ptr, "mouse_x");
mval[1] = RNA_int_get(op->ptr, "mouse_y");
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- /* always do socket_select when extending selection. */
- const bool socket_select = extend || RNA_boolean_get(op->ptr, "socket_select");
- const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
-
/* perform the select */
- const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, false);
+ const int ret_value = node_mouse_select(C, op, mval, false);
/* allow tweak event to work too */
return ret_value | OPERATOR_PASS_THROUGH;
@@ -579,19 +578,9 @@ static int node_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
mval[0] = RNA_int_get(op->ptr, "mouse_x");
mval[1] = RNA_int_get(op->ptr, "mouse_y");
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- /* always do socket_select when extending selection. */
- const bool socket_select = extend || RNA_boolean_get(op->ptr, "socket_select");
- const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
-
- /* These cases are never modal. */
- if (extend || socket_select) {
- return node_select_exec(C, op);
- }
-
if (init_event_type == 0) {
if (event->val == KM_PRESS) {
- const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, true);
+ const int ret_value = node_mouse_select(C, op, mval, true);
op->customdata = POINTER_FROM_INT((int)event->type);
if (ret_value & OPERATOR_RUNNING_MODAL) {
@@ -603,11 +592,12 @@ static int node_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* If we are in init phase, and cannot validate init of modal operations,
* just fall back to basic exec.
*/
- return node_select_exec(C, op);
+ const int ret_value = node_mouse_select(C, op, mval, false);
+ return ret_value | OPERATOR_PASS_THROUGH;
}
}
else if (event->type == init_event_type && event->val == KM_RELEASE) {
- const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, false);
+ const int ret_value = node_mouse_select(C, op, mval, false);
return ret_value | OPERATOR_PASS_THROUGH;
}
else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
@@ -1234,8 +1224,18 @@ static uiBlock *node_find_menu(bContext *C, ARegion *ar, void *arg_op)
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
- but = uiDefSearchBut(
- block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, 9 * UI_UNIT_X, UI_UNIT_Y, 0, 0, "");
+ but = uiDefSearchBut(block,
+ search,
+ 0,
+ ICON_VIEWZOOM,
+ sizeof(search),
+ 10,
+ 10,
+ UI_searchbox_size_x(),
+ UI_UNIT_Y,
+ 0,
+ 0,
+ "");
UI_but_func_search_set(but, NULL, node_find_cb, op->type, false, node_find_call_cb, NULL);
UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
@@ -1256,7 +1256,7 @@ static uiBlock *node_find_menu(bContext *C, ARegion *ar, void *arg_op)
NULL);
/* Move it downwards, mouse over button. */
- UI_block_bounds_set_popup(block, 6, (const int[2]){0, -UI_UNIT_Y});
+ UI_block_bounds_set_popup(block, 0.3f * U.widget_unit, (const int[2]){0, -UI_UNIT_Y});
return block;
}
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index 8cc57a82fe0..c6994dab72d 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -342,7 +342,7 @@ static void ui_node_link_items(NodeLinkArg *arg,
ListBase *lb = (in_out == SOCK_IN ? &ngroup->inputs : &ngroup->outputs);
bNodeSocket *stemp;
int index;
- for (stemp = lb->first, index = 0; stemp; stemp = stemp->next, ++index, ++i) {
+ for (stemp = lb->first, index = 0; stemp; stemp = stemp->next, index++, i++) {
NodeLinkItem *item = &items[i];
item->socket_index = index;
@@ -363,15 +363,15 @@ static void ui_node_link_items(NodeLinkArg *arg,
bNodeSocketTemplate *stemp;
int i;
- for (stemp = socket_templates; stemp && stemp->type != -1; ++stemp) {
- ++totitems;
+ for (stemp = socket_templates; stemp && stemp->type != -1; stemp++) {
+ totitems++;
}
if (totitems > 0) {
items = MEM_callocN(sizeof(NodeLinkItem) * totitems, "ui node link items");
i = 0;
- for (stemp = socket_templates; stemp && stemp->type != -1; ++stemp, ++i) {
+ for (stemp = socket_templates; stemp && stemp->type != -1; stemp++, i++) {
NodeLinkItem *item = &items[i];
item->socket_index = i;
@@ -441,7 +441,7 @@ static int ui_node_item_name_compare(const void *a, const void *b)
{
const bNodeType *type_a = *(const bNodeType **)a;
const bNodeType *type_b = *(const bNodeType **)b;
- return BLI_natstrcmp(type_a->ui_name, type_b->ui_name);
+ return BLI_strcasecmp_natural(type_a->ui_name, type_b->ui_name);
}
static bool ui_node_item_special_poll(const bNodeTree *UNUSED(ntree), const bNodeType *ntype)
@@ -506,13 +506,13 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
ui_node_link_items(arg, SOCK_OUT, &items, &totitems);
- for (i = 0; i < totitems; ++i) {
+ for (i = 0; i < totitems; i++) {
if (ui_compatible_sockets(items[i].socket_type, sock->type)) {
num++;
}
}
- for (i = 0; i < totitems; ++i) {
+ for (i = 0; i < totitems; i++) {
if (!ui_compatible_sockets(items[i].socket_type, sock->type)) {
continue;
}
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index 7183512a5bc..e114c3dbc05 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -158,7 +158,7 @@ bNodeTree *ED_node_tree_get(SpaceNode *snode, int level)
{
bNodeTreePath *path;
int i;
- for (path = snode->treepath.last, i = 0; path; path = path->prev, ++i) {
+ for (path = snode->treepath.last, i = 0; path; path = path->prev, i++) {
if (i == level) {
return path->nodetree;
}
@@ -171,7 +171,7 @@ int ED_node_tree_path_length(SpaceNode *snode)
bNodeTreePath *path;
int length = 0;
int i;
- for (path = snode->treepath.first, i = 0; path; path = path->next, ++i) {
+ for (path = snode->treepath.first, i = 0; path; path = path->next, i++) {
length += strlen(path->node_name);
if (i > 0) {
length += 1; /* for separator char */
@@ -186,7 +186,7 @@ void ED_node_tree_path_get(SpaceNode *snode, char *value)
int i;
value[0] = '\0';
- for (path = snode->treepath.first, i = 0; path; path = path->next, ++i) {
+ for (path = snode->treepath.first, i = 0; path; path = path->next, i++) {
if (i == 0) {
strcpy(value, path->node_name);
value += strlen(path->node_name);
@@ -204,7 +204,7 @@ void ED_node_tree_path_get_fixedbuf(SpaceNode *snode, char *value, int max_lengt
int size, i;
value[0] = '\0';
- for (path = snode->treepath.first, i = 0; path; path = path->next, ++i) {
+ for (path = snode->treepath.first, i = 0; path; path = path->next, i++) {
if (i == 0) {
size = BLI_strncpy_rlen(value, path->node_name, max_length);
}
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c
index 4740c412083..309446db83b 100644
--- a/source/blender/editors/space_outliner/outliner_collections.c
+++ b/source/blender/editors/space_outliner/outliner_collections.c
@@ -89,7 +89,7 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te)
}
else if (ELEM(tselem->type, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
Scene *scene = (Scene *)tselem->id;
- return BKE_collection_master(scene);
+ return scene->master_collection;
}
else if (tselem->type == 0 && te->idcode == ID_GR) {
return (Collection *)tselem->id;
@@ -199,7 +199,7 @@ static int collection_new_exec(bContext *C, wmOperator *op)
}
if (data.collection == NULL || ID_IS_LINKED(data.collection)) {
- data.collection = BKE_collection_master(scene);
+ data.collection = scene->master_collection;
}
if (ID_IS_LINKED(scene)) {
@@ -514,14 +514,14 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op)
* This can happen when a whole scene is linked e.g. */
if (parent != NULL && ID_IS_LINKED(parent)) {
Scene *scene = CTX_data_scene(C);
- parent = ID_IS_LINKED(scene) ? NULL : BKE_collection_master(scene);
+ parent = ID_IS_LINKED(scene) ? NULL : scene->master_collection;
}
else if (parent != NULL && (parent->flag & COLLECTION_IS_MASTER) != 0) {
Scene *scene = BKE_collection_master_scene_search(bmain, parent);
BLI_assert(scene != NULL);
if (ID_IS_LINKED(scene)) {
scene = CTX_data_scene(C);
- parent = ID_IS_LINKED(scene) ? NULL : BKE_collection_master(scene);
+ parent = ID_IS_LINKED(scene) ? NULL : scene->master_collection;
}
}
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c
index 6031ba5cffc..602031a6854 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.c
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.c
@@ -56,8 +56,6 @@
#include "UI_resources.h"
#include "UI_view2d.h"
-#include "GPU_state.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -537,7 +535,7 @@ static int scene_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent
Collection *collection;
if (scene != CTX_data_scene(C)) {
/* when linking to an inactive scene link to the master collection */
- collection = BKE_collection_master(scene);
+ collection = scene->master_collection;
}
else {
collection = CTX_data_collection(C);
@@ -967,7 +965,7 @@ static int outliner_item_drag_drop_invoke(bContext *C,
}
else {
Scene *scene = CTX_data_scene(C);
- parent = BKE_collection_master(scene);
+ parent = scene->master_collection;
}
WM_drag_add_ID(drag, id, &parent->id);
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 943993cb810..c81d292a859 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -674,7 +674,7 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Outliner ID data Remap";
+ ot->name = "Outliner ID Data Remap";
ot->idname = "OUTLINER_OT_id_remap";
/* callbacks */
@@ -770,7 +770,11 @@ static int outliner_id_copy_exec(bContext *C, wmOperator *op)
BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend");
BKE_copybuffer_save(bmain, str, op->reports);
- BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-blocks", num_ids);
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ num_ids == 1 ? "Copied %d selected data-block" :
+ "Copied %d selected data-blocks",
+ num_ids);
return OPERATOR_FINISHED;
}
@@ -804,7 +808,11 @@ static int outliner_id_paste_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_WINDOW, NULL);
- BKE_reportf(op->reports, RPT_INFO, "%d data-blocks pasted", num_pasted);
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ num_pasted == 1 ? "%d data-block pasted" :
+ "%d data-blocks pasted",
+ num_pasted);
return OPERATOR_FINISHED;
}
@@ -2257,7 +2265,11 @@ static int outliner_orphans_purge_exec(bContext *C, wmOperator *op)
BKE_id_multi_tagged_delete(bmain);
- BKE_reportf(op->reports, RPT_INFO, "Deleted %d data-blocks", num_tagged[INDEX_ID_NULL]);
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ num_tagged[INDEX_ID_NULL] == 1 ? "Deleted %d data-block" :
+ "Deleted %d data-blocks",
+ num_tagged[INDEX_ID_NULL]);
/* XXX: tree management normally happens from draw_outliner(), but when
* you're clicking to fast on Delete object from context menu in
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index 4b57d4ad771..9d7efc7fe46 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -27,9 +27,6 @@
#include "BLT_translation.h"
-#include "GPU_immediate.h"
-#include "GPU_state.h"
-
#include "RNA_access.h"
#include "UI_interface.h"
diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.c
index cf734526958..29c820bce92 100644
--- a/source/blender/editors/space_outliner/outliner_sync.c
+++ b/source/blender/editors/space_outliner/outliner_sync.c
@@ -134,7 +134,7 @@ static void outliner_sync_select_from_outliner_set_types(bContext *C,
const bool sequence_view = soops->outlinevis == SO_SEQUENCE;
- sync_types->object = !sequence_view && (obact && obact->mode == OB_MODE_OBJECT);
+ sync_types->object = !sequence_view;
sync_types->edit_bone = !sequence_view && (obedit && obedit->type == OB_ARMATURE);
sync_types->pose_bone = !sequence_view && (obact && obact->mode == OB_MODE_POSE);
sync_types->sequence = sequence_view;
@@ -143,8 +143,9 @@ static void outliner_sync_select_from_outliner_set_types(bContext *C,
/**
* Current dirty flags and outliner display mode determine which type of syncing should occur.
* This is to ensure sync flag data is not lost on sync in the wrong display mode.
+ * Returns true if a sync is needed.
*/
-static void outliner_sync_select_to_outliner_set_types(const bContext *C,
+static bool outliner_sync_select_to_outliner_set_types(const bContext *C,
SpaceOutliner *soops,
SyncSelectTypes *sync_types)
{
@@ -153,7 +154,7 @@ static void outliner_sync_select_to_outliner_set_types(const bContext *C,
const bool sequence_view = soops->outlinevis == SO_SEQUENCE;
- sync_types->object = !sequence_view && (obact && obact->mode == OB_MODE_OBJECT) &&
+ sync_types->object = !sequence_view &&
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_OBJECT);
sync_types->edit_bone = !sequence_view && (obedit && obedit->type == OB_ARMATURE) &&
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE);
@@ -161,6 +162,9 @@ static void outliner_sync_select_to_outliner_set_types(const bContext *C,
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_POSE_BONE);
sync_types->sequence = sequence_view &&
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_SEQUENCE);
+
+ return sync_types->object || sync_types->edit_bone || sync_types->pose_bone ||
+ sync_types->sequence;
}
/**
@@ -366,17 +370,22 @@ void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *soops)
selected_items_free(&selected_items);
- /* Tag for updates */
+ /* Tag for updates and clear dirty flag toprevent a sync to the outliner on draw */
if (sync_types.object) {
+ soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_OBJECT;
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
+ else if (sync_types.edit_bone) {
+ soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE;
+ }
+ else if (sync_types.pose_bone) {
+ soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_POSE_BONE;
+ }
if (sync_types.sequence) {
+ soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_SEQUENCE;
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
}
-
- /* Clear outliner sync select dirty flag to prevent a sync to the outliner on draw */
- soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_ALL;
}
static void outliner_select_sync_from_object(ViewLayer *view_layer,
@@ -393,6 +402,9 @@ static void outliner_select_sync_from_object(ViewLayer *view_layer,
if (base && (ob == obact)) {
outliner_element_activate(soops, tselem);
}
+ else {
+ tselem->flag &= ~TSE_ACTIVE;
+ }
if (is_selected) {
tselem->flag |= TSE_SELECTED;
@@ -412,6 +424,9 @@ static void outliner_select_sync_from_edit_bone(SpaceOutliner *soops,
if (ebone == ebone_active) {
outliner_element_activate(soops, tselem);
}
+ else {
+ tselem->flag &= ~TSE_ACTIVE;
+ }
if (ebone->flag & BONE_SELECTED) {
tselem->flag |= TSE_SELECTED;
@@ -432,6 +447,9 @@ static void outliner_select_sync_from_pose_bone(SpaceOutliner *soops,
if (pchan == pchan_active) {
outliner_element_activate(soops, tselem);
}
+ else {
+ tselem->flag &= ~TSE_ACTIVE;
+ }
if (bone->flag & BONE_SELECTED) {
tselem->flag |= TSE_SELECTED;
@@ -450,6 +468,9 @@ static void outliner_select_sync_from_sequence(SpaceOutliner *soops,
if (seq == sequence_active) {
outliner_element_activate(soops, tselem);
}
+ else {
+ tselem->flag &= ~TSE_ACTIVE;
+ }
if (seq->flag & SELECT) {
tselem->flag |= TSE_SELECTED;
@@ -523,12 +544,12 @@ static void get_sync_select_active_data(const bContext *C, SyncSelectActiveData
/* If outliner is dirty sync selection from view layer and sequwncer */
void outliner_sync_selection(const bContext *C, SpaceOutliner *soops)
{
- if (soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_ALL) {
- ViewLayer *view_layer = CTX_data_view_layer(C);
+ /* Set which types of data to sync from sync dirty flag and outliner display mode */
+ SyncSelectTypes sync_types;
+ const bool sync_required = outliner_sync_select_to_outliner_set_types(C, soops, &sync_types);
- /* Set which types of data to sync from sync dirty flag and outliner display mode */
- SyncSelectTypes sync_types;
- outliner_sync_select_to_outliner_set_types(C, soops, &sync_types);
+ if (sync_required) {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
/* Store active object, bones, and sequence */
SyncSelectActiveData active_data;
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 2c4a648da65..219943d08a6 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -299,7 +299,7 @@ static void unlink_collection_cb(bContext *C,
}
else if (GS(tsep->id->name) == ID_SCE) {
Scene *scene = (Scene *)tsep->id;
- Collection *parent = BKE_collection_master(scene);
+ Collection *parent = scene->master_collection;
id_fake_user_set(&collection->id);
BKE_collection_child_remove(bmain, parent, collection);
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
@@ -338,7 +338,7 @@ static void unlink_object_cb(bContext *C,
}
else if (GS(tsep->id->name) == ID_SCE) {
Scene *scene = (Scene *)tsep->id;
- Collection *parent = BKE_collection_master(scene);
+ Collection *parent = scene->master_collection;
BKE_collection_object_remove(bmain, parent, ob, true);
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
@@ -680,12 +680,7 @@ static void object_delete_cb(bContext *C,
if (ob == CTX_data_edit_object(C)) {
ED_object_editmode_exit(C, EM_FREEDATA);
}
- ED_object_base_free_and_unlink(CTX_data_main(C), scene, ob);
- /* leave for ED_outliner_id_unref to handle */
-#if 0
- te->directdata = NULL;
- tselem->id = NULL;
-#endif
+ BKE_id_delete(bmain, ob);
}
}
@@ -718,12 +713,15 @@ static void id_override_library_cb(bContext *C,
TreeStoreElem *tselem,
void *UNUSED(user_data))
{
- if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) {
+ if (ID_IS_OVERRIDABLE_LIBRARY(tselem->id)) {
Main *bmain = CTX_data_main(C);
- ID *override_id = BKE_override_library_create_from_id(bmain, tselem->id);
+ /* For now, remapp all local usages of linked ID to local override one here. */
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, true);
+ ID *override_id = BKE_override_library_create_from_id(bmain, tselem->id, true);
if (override_id != NULL) {
BKE_main_id_clear_newpoins(bmain);
}
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
}
}
@@ -1204,11 +1202,6 @@ static void object_delete_hierarchy_cb(bContext *C,
}
outline_delete_hierarchy(C, reports, scene, base);
- /* leave for ED_outliner_id_unref to handle */
-#if 0
- te->directdata = NULL;
- tselem->id = NULL;
-#endif
}
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
@@ -1292,11 +1285,6 @@ static void object_batch_delete_hierarchy_cb(bContext *C,
}
outline_batch_delete_hierarchy(reports, CTX_data_main(C), view_layer, scene, base);
- /* leave for ED_outliner_id_unref to handle */
-#if 0
- te->directdata = NULL;
- tselem->id = NULL;
-#endif
}
}
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index c3168a7a532..fd6a052b84d 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -1601,7 +1601,7 @@ typedef struct tTreeSort {
short idcode;
} tTreeSort;
-/* alphabetical comparator, tryping to put objects first */
+/* alphabetical comparator, trying to put objects first */
static int treesort_alpha_ob(const void *v1, const void *v2)
{
const tTreeSort *x1 = v1, *x2 = v2;
@@ -1627,7 +1627,7 @@ static int treesort_alpha_ob(const void *v1, const void *v2)
return (x1->te->flag & TE_CHILD_NOT_IN_COLLECTION) ? 1 : -1;
}
- comp = strcmp(x1->name, x2->name);
+ comp = BLI_strcasecmp_natural(x1->name, x2->name);
if (comp > 0) {
return 1;
@@ -1659,7 +1659,7 @@ static int treesort_alpha(const void *v1, const void *v2)
const tTreeSort *x1 = v1, *x2 = v2;
int comp;
- comp = strcmp(x1->name, x2->name);
+ comp = BLI_strcasecmp_natural(x1->name, x2->name);
if (comp > 0) {
return 1;
@@ -1697,7 +1697,7 @@ static int treesort_obtype_alpha(const void *v1, const void *v2)
}
}
else {
- int comp = strcmp(x1->name, x2->name);
+ int comp = BLI_strcasecmp_natural(x1->name, x2->name);
if (comp > 0) {
return 1;
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index 79880c68120..68eea4f278b 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -229,6 +229,11 @@ static void outliner_main_region_listener(wmWindow *UNUSED(win),
ED_region_tag_redraw(ar);
}
break;
+ case NC_TEXT:
+ if (ELEM(wmn->action, NA_ADDED, NA_REMOVED)) {
+ ED_region_tag_redraw(ar);
+ }
+ break;
}
}
diff --git a/source/blender/editors/space_script/script_edit.c b/source/blender/editors/space_script/script_edit.c
index 48248fe1dd2..2be05785d2b 100644
--- a/source/blender/editors/space_script/script_edit.c
+++ b/source/blender/editors/space_script/script_edit.c
@@ -106,6 +106,7 @@ static bool script_test_modal_operators(bContext *C)
static int script_reload_exec(bContext *C, wmOperator *op)
{
+
#ifdef WITH_PYTHON
/* clear running operators */
@@ -114,6 +115,8 @@ static int script_reload_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ WM_script_tag_reload();
+
/* TODO, this crashes on netrender and keying sets, need to look into why
* disable for now unless running in debug mode */
WM_cursor_wait(1);
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index b24f8e8d00f..8a15c05dd4a 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -336,7 +336,7 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
}
seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_SCENE);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+ seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
seq->scene = sce_seq;
@@ -420,7 +420,7 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op)
}
seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MOVIECLIP);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+ seq->blend_mode = SEQ_TYPE_CROSS;
seq->clip = clip;
id_us_ensure_real(&seq->clip->id);
@@ -504,7 +504,7 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op)
}
seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MASK);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+ seq->blend_mode = SEQ_TYPE_CROSS;
seq->mask = mask;
id_us_ensure_real(&seq->mask->id);
@@ -1091,8 +1091,14 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
if (seq->type == SEQ_TYPE_COLOR) {
SolidColorVars *colvars = (SolidColorVars *)seq->effectdata;
RNA_float_get_array(op->ptr, "color", colvars->col);
+ seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
+ }
+ else if (seq->type == SEQ_TYPE_ADJUSTMENT) {
+ seq->blend_mode = SEQ_TYPE_CROSS;
+ }
+ else if (seq->type == SEQ_TYPE_TEXT) {
+ seq->blend_mode = SEQ_TYPE_ALPHAOVER;
}
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
/* an unset channel is a special case where we automatically go above
* the other strips. */
@@ -1169,7 +1175,7 @@ void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot)
RNA_def_enum(ot->srna,
"type",
sequencer_prop_effect_types,
- SEQ_TYPE_ALPHAOVER,
+ SEQ_TYPE_CROSS,
"Type",
"Sequencer effect type");
RNA_def_float_vector(ot->srna,
diff --git a/source/blender/editors/space_sequencer/sequencer_buttons.c b/source/blender/editors/space_sequencer/sequencer_buttons.c
index 6740c2baad2..7bec913900d 100644
--- a/source/blender/editors/space_sequencer/sequencer_buttons.c
+++ b/source/blender/editors/space_sequencer/sequencer_buttons.c
@@ -117,5 +117,6 @@ void sequencer_buttons_register(ARegionType *art)
pt->poll = metadata_panel_context_poll;
pt->draw = metadata_panel_context_draw;
pt->flag |= PNL_DEFAULT_CLOSED;
+ pt->order = 10;
BLI_addtail(&art->paneltypes, pt);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index b15acb12d00..1a788237e6e 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -72,6 +72,7 @@
#include "UI_view2d.h"
#include "WM_api.h"
+#include "WM_types.h"
#include "MEM_guardedalloc.h"
@@ -333,7 +334,7 @@ static void drawseqwave(View2D *v2d,
value2 = (1.0f - f) * value2 + f * waveform->data[p * 3 + 4];
}
- if (fcu) {
+ if (fcu && !BKE_fcurve_is_empty(fcu)) {
float evaltime = x1_offset + (i * stepsize);
volume = evaluate_fcurve(fcu, evaltime);
}
@@ -1223,6 +1224,14 @@ void sequencer_draw_maskedit(const bContext *C, Scene *scene, ARegion *ar, Space
}
#endif
+/* Force redraw, when prefetching and using cache view. */
+static void seq_prefetch_wm_notify(const bContext *C, Scene *scene)
+{
+ if (BKE_sequencer_prefetch_need_redraw(CTX_data_main(C), scene)) {
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, NULL);
+ }
+}
+
static void *sequencer_OCIO_transform_ibuf(
const bContext *C, ImBuf *ibuf, bool *glsl_used, int *format, int *type)
{
@@ -1612,6 +1621,7 @@ void sequencer_draw_preview(const bContext *C,
}
UI_view2d_view_restore(C);
+ seq_prefetch_wm_notify(C, scene);
}
#if 0
@@ -2004,6 +2014,8 @@ void draw_timeline_seq(const bContext *C, ARegion *ar)
short cfra_flag = 0;
float col[3];
+ seq_prefetch_wm_notify(C, scene);
+
/* clear and setup matrix */
UI_GetThemeColor3fv(TH_BACK, col);
if (ed && ed->metastack.first) {
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 22b73c32bfe..9d7163cd6d9 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -3894,7 +3894,7 @@ void SEQUENCER_OT_change_effect_type(struct wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna,
"type",
sequencer_prop_effect_types,
- SEQ_TYPE_ALPHAOVER,
+ SEQ_TYPE_CROSS,
"Type",
"Sequencer effect type");
}
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index c1a3c79b0d8..088f06e9da8 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -29,6 +29,7 @@
#include "BLI_blenlib.h"
+#include "BKE_global.h"
#include "BKE_context.h"
#include "BKE_library.h"
#include "BKE_screen.h"
@@ -310,11 +311,11 @@ static void text_main_region_draw(const bContext *C, ARegion *ar)
static void text_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
{
SpaceText *st = sa->spacedata.first;
- int wmcursor = BC_TEXTEDITCURSOR;
+ int wmcursor = WM_CURSOR_TEXT_EDIT;
if (st->text &&
BLI_rcti_isect_pt(&st->txtbar, win->eventstate->x - ar->winrct.xmin, st->txtbar.ymin)) {
- wmcursor = CURSOR_STD;
+ wmcursor = WM_CURSOR_DEFAULT;
}
WM_cursor_set(win, wmcursor);
@@ -356,7 +357,7 @@ static void text_drop_paste(wmDrag *drag, wmDropBox *drop)
ID *id = WM_drag_ID(drag, 0);
/* copy drag path to properties */
- text = RNA_path_full_ID_py(id);
+ text = RNA_path_full_ID_py(G_MAIN, id);
RNA_string_set(drop->ptr, "text", text);
MEM_freeN(text);
}
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index e1550deb659..f9557225b6b 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -142,7 +142,7 @@ static char *buf_tabs_to_spaces(const char *in_buf, const int tab_size)
BLI_INLINE int text_pixel_x_to_column(SpaceText *st, const int x)
{
- /* add half the char width so mouse cursor selection is inbetween letters */
+ /* Add half the char width so mouse cursor selection is in between letters. */
return (x + (st->cwidth / 2)) / st->cwidth;
}
@@ -443,6 +443,8 @@ static int text_reload_exec(bContext *C, wmOperator *op)
text_drawcache_tag_update(CTX_wm_space_text(C), 1);
WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text);
+ text->flags &= ~TXT_ISDIRTY;
+
/* return to scroll position */
st->top = orig_top;
txt_screen_clamp(st, ar);
@@ -3482,7 +3484,7 @@ static int text_find_and_replace(bContext *C, wmOperator *op, short mode)
}
else {
if (!found) {
- BKE_reportf(op->reports, RPT_ERROR, "Text not found: %s", st->findstr);
+ BKE_reportf(op->reports, RPT_WARNING, "Text not found: %s", st->findstr);
}
}
diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c
index 4c6f2231cc1..a42ab048907 100644
--- a/source/blender/editors/space_userpref/space_userpref.c
+++ b/source/blender/editors/space_userpref/space_userpref.c
@@ -121,7 +121,7 @@ static void userpref_main_region_init(wmWindowManager *wm, ARegion *ar)
static void userpref_main_region_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels_ex(C, ar, NULL, U.userpref, true);
+ ED_region_panels_ex(C, ar, NULL, U.space_data.section_active, true);
}
static void userpref_operatortypes(void)
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index dc375958eb4..7c75f0ea907 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -33,6 +33,9 @@ set(INC
../../../../intern/glew-mx
../../../../intern/guardedalloc
../../../../intern/smoke/extern
+
+ # dna_type_offsets.h
+ ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern
)
set(INC_SYS
@@ -96,3 +99,6 @@ if(WITH_MOD_SMOKE)
endif()
blender_add_lib(bf_editor_space_view3d "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+# Needed so we can use dna_type_offsets.h for defaults initialization.
+add_dependencies(bf_editor_space_view3d bf_dna)
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index b412a72cce1..2cdfd8039c1 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -35,11 +35,9 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
-#include "GPU_draw.h"
#include "GPU_shader.h"
#include "GPU_immediate.h"
#include "GPU_batch.h"
-#include "GPU_matrix.h"
#include "GPU_state.h"
#include "ED_mesh.h"
@@ -96,7 +94,7 @@ void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], un
circball_array_fill(verts, cent, rad, tmat);
immBegin(GPU_PRIM_LINE_LOOP, CIRCLE_RESOL);
- for (int i = 0; i < CIRCLE_RESOL; ++i) {
+ for (int i = 0; i < CIRCLE_RESOL; i++) {
immVertex3fv(pos, verts[i]);
}
immEnd();
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 5974100b534..fbb6dfb8f8f 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -29,6 +29,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_defaults.h"
#include "MEM_guardedalloc.h"
@@ -39,6 +40,7 @@
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_icons.h"
+#include "BKE_idprop.h"
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_mball.h"
@@ -52,9 +54,6 @@
#include "ED_screen.h"
#include "ED_transform.h"
-#include "GPU_framebuffer.h"
-#include "GPU_material.h"
-#include "GPU_viewport.h"
#include "GPU_matrix.h"
#include "DRW_engine.h"
@@ -246,56 +245,11 @@ static SpaceLink *view3d_new(const ScrArea *UNUSED(sa), const Scene *scene)
View3D *v3d;
RegionView3D *rv3d;
- v3d = MEM_callocN(sizeof(View3D), "initview3d");
- v3d->spacetype = SPACE_VIEW3D;
+ v3d = DNA_struct_default_alloc(View3D);
+
if (scene) {
v3d->camera = scene->camera;
}
- v3d->scenelock = true;
- v3d->grid = 1.0f;
- v3d->gridlines = 16;
- v3d->gridsubdiv = 10;
- BKE_screen_view3d_shading_init(&v3d->shading);
-
- v3d->overlay.wireframe_threshold = 1.0f;
- v3d->overlay.xray_alpha_bone = 0.5f;
- v3d->overlay.texture_paint_mode_opacity = 1.0f;
- v3d->overlay.weight_paint_mode_opacity = 1.0f;
- v3d->overlay.vertex_paint_mode_opacity = 1.0f;
- /* Intentionally different to vertex/paint mode,
- * we typically want to see shading too. */
- v3d->overlay.sculpt_mode_mask_opacity = 0.75f;
-
- v3d->overlay.edit_flag = V3D_OVERLAY_EDIT_FACES | V3D_OVERLAY_EDIT_SEAMS |
- V3D_OVERLAY_EDIT_SHARP | V3D_OVERLAY_EDIT_FREESTYLE_EDGE |
- V3D_OVERLAY_EDIT_FREESTYLE_FACE | V3D_OVERLAY_EDIT_EDGES |
- V3D_OVERLAY_EDIT_CREASES | V3D_OVERLAY_EDIT_BWEIGHTS |
- V3D_OVERLAY_EDIT_CU_HANDLES | V3D_OVERLAY_EDIT_CU_NORMALS;
-
- v3d->gridflag = V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_FLOOR | V3D_SHOW_ORTHO_GRID;
-
- v3d->flag = V3D_SELECT_OUTLINE;
- v3d->flag2 = V3D_SHOW_RECONSTRUCTION | V3D_SHOW_ANNOTATION;
-
- v3d->lens = 50.0f;
- v3d->clip_start = 0.01f;
- v3d->clip_end = 1000.0f;
-
- v3d->overlay.gpencil_paper_opacity = 0.5f;
- v3d->overlay.gpencil_grid_opacity = 0.9f;
-
- v3d->bundle_size = 0.2f;
- v3d->bundle_drawtype = OB_PLAINAXES;
-
- /* stereo */
- v3d->stereo3d_camera = STEREO_3D_ID;
- v3d->stereo3d_flag |= V3D_S3D_DISPPLANE;
- v3d->stereo3d_convergence_alpha = 0.15f;
- v3d->stereo3d_volume_alpha = 0.05f;
-
- /* grease pencil settings */
- v3d->vertex_opacity = 1.0f;
- v3d->gp_flag |= V3D_GP_SHOW_EDIT_LINES;
/* tool header */
ar = MEM_callocN(sizeof(ARegion), "tool header for view3d");
@@ -363,6 +317,11 @@ static void view3d_free(SpaceLink *sl)
if (vd->fx_settings.dof) {
MEM_freeN(vd->fx_settings.dof);
}
+
+ if (vd->shading.prop) {
+ IDP_FreeProperty(vd->shading.prop);
+ vd->shading.prop = NULL;
+ }
}
/* spacetype; init callback */
@@ -386,6 +345,10 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl)
v3dn->shading.type = OB_SOLID;
}
+ if (v3dn->shading.prop) {
+ v3dn->shading.prop = IDP_CopyProperty(v3do->shading.prop);
+ }
+
/* copy or clear inside new stuff */
v3dn->runtime.properties_storage = NULL;
@@ -618,7 +581,7 @@ static void view3d_lightcache_update(bContext *C)
Scene *scene = CTX_data_scene(C);
- if (strcmp(scene->r.engine, RE_engine_id_BLENDER_EEVEE) != 0) {
+ if (!BKE_scene_uses_blender_eevee(scene)) {
/* Only do auto bake if eevee is the active engine */
return;
}
@@ -1079,10 +1042,10 @@ static void view3d_main_region_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
if (obedit) {
- WM_cursor_set(win, CURSOR_EDIT);
+ WM_cursor_set(win, WM_CURSOR_EDIT);
}
else {
- WM_cursor_set(win, CURSOR_STD);
+ WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index 3d3c73ad27c..9ab56dba72d 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -106,7 +106,9 @@ typedef union {
/* temporary struct for storing transform properties */
typedef struct {
+ float ob_obmat_orig[4][4];
float ob_dims_orig[3];
+ float ob_scale_orig[3];
float ob_dims[3];
/* Floats only (treated as an array). */
TransformMedian ve_median, median;
@@ -1050,6 +1052,8 @@ static void v3d_object_dimension_buts(bContext *C, uiLayout *layout, View3D *v3d
BKE_object_dimensions_get(ob, tfp->ob_dims);
copy_v3_v3(tfp->ob_dims_orig, tfp->ob_dims);
+ copy_v3_v3(tfp->ob_scale_orig, ob->scale);
+ copy_m4_m4(tfp->ob_obmat_orig, ob->obmat);
uiDefBut(block,
UI_BTYPE_LABEL,
@@ -1095,7 +1099,8 @@ static void v3d_object_dimension_buts(bContext *C, uiLayout *layout, View3D *v3d
axis_mask |= (1 << i);
}
}
- BKE_object_dimensions_set(ob, tfp->ob_dims, axis_mask);
+ BKE_object_dimensions_set_ex(
+ ob, tfp->ob_dims, axis_mask, tfp->ob_scale_orig, tfp->ob_obmat_orig);
PointerRNA obptr;
RNA_id_pointer_create(&ob->id, &obptr);
@@ -1461,6 +1466,7 @@ static void v3d_editarmature_buts(uiLayout *layout, Object *ob)
uiItemR(col, &eboneptr, "tail_radius", 0, IFACE_("Radius"), ICON_NONE);
uiItemR(col, &eboneptr, "roll", 0, NULL, ICON_NONE);
+ uiItemR(col, &eboneptr, "length", 0, NULL, ICON_NONE);
uiItemR(col, &eboneptr, "envelope_distance", 0, IFACE_("Envelope"), ICON_NONE);
}
diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c
index f8f97848d14..260546738f4 100644
--- a/source/blender/editors/space_view3d/view3d_camera_control.c
+++ b/source/blender/editors/space_view3d/view3d_camera_control.c
@@ -208,8 +208,8 @@ void ED_view3d_cameracontrol_update(View3DCameraControl *vctrl,
const bool do_rotate,
const bool do_translate)
{
- /* we are in camera view so apply the view ofs and quat to the view matrix and set the camera
- * to the view */
+ /* We are in camera view so apply the view offset and rotation to the view matrix
+ * and set the camera to the view. */
Scene *scene = vctrl->ctx_scene;
View3D *v3d = vctrl->ctx_v3d;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index f6afa112f08..aafd36a5bb8 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -39,6 +39,7 @@
#include "BKE_scene.h"
#include "BKE_object.h"
#include "BKE_paint.h"
+#include "BKE_studiolight.h"
#include "BKE_unit.h"
#include "BLF_api.h"
@@ -1088,7 +1089,7 @@ static void draw_rotation_guide(const RegionView3D *rv3d)
color[3] = 63; /* somewhat faint */
immAttr4ubv(col, color);
float angle = 0.0f;
- for (int i = 0; i < ROT_AXIS_DETAIL; ++i, angle += step) {
+ for (int i = 0; i < ROT_AXIS_DETAIL; i++, angle += step) {
float p[3] = {s * cosf(angle), s * sinf(angle), 0.0f};
if (!upright) {
@@ -1860,6 +1861,9 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph,
if (drawtype == OB_MATERIAL) {
v3d.shading.flag = V3D_SHADING_SCENE_WORLD | V3D_SHADING_SCENE_LIGHTS;
}
+ else if (drawtype == OB_RENDER) {
+ v3d.shading.flag = V3D_SHADING_SCENE_WORLD_RENDER | V3D_SHADING_SCENE_LIGHTS_RENDER;
+ }
v3d.flag2 = V3D_HIDE_OVERLAYS;
diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c
index d5772e5052a..acc46935eb5 100644
--- a/source/blender/editors/space_view3d/view3d_draw_legacy.c
+++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c
@@ -88,14 +88,8 @@
#include "UI_interface_icons.h"
#include "UI_resources.h"
-#include "GPU_draw.h"
#include "GPU_framebuffer.h"
-#include "GPU_material.h"
-#include "GPU_extensions.h"
#include "GPU_immediate.h"
-#include "GPU_immediate_util.h"
-#include "GPU_select.h"
-#include "GPU_matrix.h"
#include "GPU_state.h"
#include "GPU_viewport.h"
@@ -389,6 +383,14 @@ void ED_view3d_datamask(const bContext *C,
r_cddata_masks->lmask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
r_cddata_masks->vmask |= CD_MASK_ORCO;
}
+ else if (v3d->shading.type == OB_SOLID) {
+ if (v3d->shading.color_type == V3D_SHADING_TEXTURE_COLOR) {
+ r_cddata_masks->lmask |= CD_MASK_MLOOPUV;
+ }
+ if (v3d->shading.color_type == V3D_SHADING_VERTEX_COLOR) {
+ r_cddata_masks->lmask |= CD_MASK_MLOOPCOL;
+ }
+ }
if ((CTX_data_mode_enum(C) == CTX_MODE_EDIT_MESH) &&
(v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_WEIGHT)) {
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index e76ef2b0458..3ad194a5d2b 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -2997,7 +2997,7 @@ static int viewselected_exec(bContext *C, wmOperator *op)
ok = paintface_minmax(ob_eval, min, max);
}
else if (ob_eval && (ob_eval->mode & OB_MODE_PARTICLE_EDIT)) {
- ok = PE_minmax(scene, view_layer_eval, min, max);
+ ok = PE_minmax(depsgraph, scene, CTX_data_view_layer(C), min, max);
}
else if (ob_eval && (ob_eval->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT |
OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) {
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
index 3c911e266a9..53a5609d437 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
@@ -213,7 +213,7 @@ static void WIDGETGROUP_navigate_setup(const bContext *C, wmGizmoGroup *gzgroup)
{
wmGizmo *gz = navgroup->gz_array[GZ_INDEX_ROTATE];
gz->scale_basis = GIZMO_SIZE / 2;
- char mapping[6] = {
+ const char mapping[6] = {
RV3D_VIEW_LEFT,
RV3D_VIEW_RIGHT,
RV3D_VIEW_FRONT,
@@ -274,7 +274,7 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
float icon_offset_from_axis = 0.0f;
switch ((eUserpref_MiniAxisType)U.mini_axis_type) {
case USER_MINI_AXIS_TYPE_GIZMO:
- icon_offset_from_axis = icon_offset * 2.0f;
+ icon_offset_from_axis = icon_offset * 2.1f;
break;
case USER_MINI_AXIS_TYPE_MINIMAL:
icon_offset_from_axis = (UI_UNIT_X * 2.5) + ((U.rvisize * U.pixelsize * 2.0f));
@@ -285,8 +285,8 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
}
const float co[2] = {
- rect_visible->xmax - icon_offset_from_axis,
- rect_visible->ymax - icon_offset_mini * 0.75f,
+ rect_visible->xmax - icon_offset_mini * 0.75f,
+ rect_visible->ymax - icon_offset_from_axis,
};
wmGizmo *gz;
@@ -307,25 +307,25 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
if (show_navigate) {
int icon_mini_slot = 0;
gz = navgroup->gz_array[GZ_INDEX_ZOOM];
- gz->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++);
- gz->matrix_basis[3][1] = co[1];
+ gz->matrix_basis[3][0] = co[0];
+ gz->matrix_basis[3][1] = co[1] - (icon_offset_mini * icon_mini_slot++);
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
gz = navgroup->gz_array[GZ_INDEX_MOVE];
- gz->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++);
- gz->matrix_basis[3][1] = co[1];
+ gz->matrix_basis[3][0] = co[0];
+ gz->matrix_basis[3][1] = co[1] - (icon_offset_mini * icon_mini_slot++);
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
gz = navgroup->gz_array[GZ_INDEX_CAMERA];
- gz->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++);
- gz->matrix_basis[3][1] = co[1];
+ gz->matrix_basis[3][0] = co[0];
+ gz->matrix_basis[3][1] = co[1] - (icon_offset_mini * icon_mini_slot++);
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
if (navgroup->state.rv3d.is_camera == false) {
gz = navgroup->gz_array[rv3d->is_persp ? GZ_INDEX_PERSP : GZ_INDEX_ORTHO];
- gz->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++);
- gz->matrix_basis[3][1] = co[1];
+ gz->matrix_basis[3][0] = co[0];
+ gz->matrix_basis[3][1] = co[1] - (icon_offset_mini * icon_mini_slot++);
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
index 539b5d93bdf..d6d3a3dc563 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
@@ -479,7 +479,7 @@ static int gizmo_axis_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mv
float i_best_len_sq = FLT_MAX;
for (int i = 0; i < 3; i++) {
for (int is_pos = 0; is_pos < 2; is_pos++) {
- float co[2] = {
+ const float co[2] = {
gz->matrix_offset[i][0] * (is_pos ? 1 : -1),
gz->matrix_offset[i][1] * (is_pos ? 1 : -1),
};
@@ -518,9 +518,9 @@ static int gizmo_axis_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mv
static int gizmo_axis_cursor_get(wmGizmo *gz)
{
if (gz->highlight_part > 0) {
- return CURSOR_EDIT;
+ return WM_CURSOR_EDIT;
}
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
void VIEW3D_GT_navigate_rotate(wmGizmoType *gzt)
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c
index a984e339305..68159e2d684 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c
@@ -77,7 +77,20 @@ static void gizmo_preselect_elem_draw(const bContext *UNUSED(C), wmGizmo *gz)
static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int mval[2])
{
+ wmEvent *event = CTX_wm_window(C)->eventstate;
MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz;
+
+ /* Hack: Switch action mode based on key input */
+ const bool is_ctrl_pressed = WM_event_modifier_flag(event) & KM_CTRL;
+ const bool is_shift_pressed = WM_event_modifier_flag(event) & KM_SHIFT;
+ EDBM_preselect_action_set(gz_ele->psel, PRESELECT_ACTION_TRANSFORM);
+ if (is_ctrl_pressed && !is_shift_pressed) {
+ EDBM_preselect_action_set(gz_ele->psel, PRESELECT_ACTION_CREATE);
+ }
+ if (!is_ctrl_pressed && is_shift_pressed) {
+ EDBM_preselect_action_set(gz_ele->psel, PRESELECT_ACTION_DELETE);
+ }
+
struct {
Object *ob;
BMElem *ele;
@@ -87,18 +100,6 @@ static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int
.dist = ED_view3d_select_dist_px(),
};
- struct {
- int base_index;
- int vert_index;
- int edge_index;
- int face_index;
- } prev = {
- .base_index = gz_ele->base_index,
- .vert_index = gz_ele->vert_index,
- .edge_index = gz_ele->edge_index,
- .face_index = gz_ele->face_index,
- };
-
{
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -115,32 +116,66 @@ static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int
{
/* TODO: support faces. */
- int base_index = -1;
+ int base_index_vert = -1;
+ int base_index_edge = -1;
+ int base_index_face = -1;
BMVert *eve_test;
BMEdge *eed_test;
+ BMFace *efa_test;
if (EDBM_unified_findnearest_from_raycast(&vc,
gz_ele->bases,
gz_ele->bases_len,
+ false,
true,
- &base_index,
+ &base_index_vert,
+ &base_index_edge,
+ &base_index_face,
&eve_test,
&eed_test,
- NULL)) {
- Base *base = gz_ele->bases[base_index];
- best.ob = base->object;
- if (eve_test) {
- best.ele = (BMElem *)eve_test;
- }
- else if (eed_test) {
- best.ele = (BMElem *)eed_test;
+ &efa_test)) {
+ if (EDBM_preselect_action_get(gz_ele->psel) == PRESELECT_ACTION_DELETE) {
+ /* Delete action */
+ if (efa_test) {
+ best.ele = (BMElem *)efa_test;
+ best.base_index = base_index_face;
+ }
}
+
else {
- BLI_assert(0);
+ /* Transform and create action */
+ if (eed_test) {
+ best.ele = (BMElem *)eed_test;
+ best.base_index = base_index_edge;
+ }
+ }
+
+ /* All actions use same vertex pre-selection. */
+ /* Re-topology should always prioritize edge pre-selection.
+ * Only pre-select a vertex when the cursor is really close to it. */
+ if (eve_test) {
+ BMVert *vert = (BMVert *)eve_test;
+ float vert_p_co[3], vert_co[3];
+ float mval_f[2] = {UNPACK2(vc.mval)};
+ mul_v3_m4v3(vert_co, gz_ele->bases[base_index_vert]->object->obmat, vert->co);
+ ED_view3d_project(vc.ar, vert_co, vert_p_co);
+ float len = len_v2v2(vert_p_co, mval_f);
+ if (len < 35) {
+ best.ele = (BMElem *)eve_test;
+ best.base_index = base_index_vert;
+ }
+ if (!BM_vert_is_boundary(vert) &&
+ EDBM_preselect_action_get(gz_ele->psel) != PRESELECT_ACTION_DELETE) {
+ best.ele = (BMElem *)eve_test;
+ best.base_index = base_index_vert;
+ }
}
- best.base_index = base_index;
+
/* Check above should never fail, if it does it's an internal error. */
BLI_assert(best.base_index != -1);
+
+ Base *base = gz_ele->bases[best.base_index];
+ best.ob = base->object;
}
}
@@ -167,32 +202,30 @@ static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int
}
}
- if ((prev.base_index == gz_ele->base_index) && (prev.vert_index == gz_ele->vert_index) &&
- (prev.edge_index == gz_ele->edge_index) && (prev.face_index == gz_ele->face_index)) {
- /* pass (only recalculate on change) */
- }
- else {
- if (best.ele) {
- const float(*coords)[3] = NULL;
- {
- Object *ob = gz_ele->bases[gz_ele->base_index]->object;
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, ob->data);
- if (me_eval->runtime.edit_data) {
- coords = me_eval->runtime.edit_data->vertexCos;
- }
+ if (best.ele) {
+ const float(*coords)[3] = NULL;
+ {
+ Object *ob = gz_ele->bases[gz_ele->base_index]->object;
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, ob->data);
+ if (me_eval->runtime.edit_data) {
+ coords = me_eval->runtime.edit_data->vertexCos;
}
- EDBM_preselect_elem_update_from_single(gz_ele->psel, bm, best.ele, coords);
- }
- else {
- EDBM_preselect_elem_clear(gz_ele->psel);
}
+ EDBM_preselect_elem_update_from_single(gz_ele->psel, bm, best.ele, coords);
+ EDBM_preselect_elem_update_preview(gz_ele->psel, &vc, bm, best.ele, mval);
+ }
+ else {
+ EDBM_preselect_elem_clear(gz_ele->psel);
+ EDBM_preselect_preview_clear(gz_ele->psel);
+ }
- RNA_int_set(gz->ptr, "object_index", gz_ele->base_index);
- RNA_int_set(gz->ptr, "vert_index", gz_ele->vert_index);
- RNA_int_set(gz->ptr, "edge_index", gz_ele->edge_index);
- RNA_int_set(gz->ptr, "face_index", gz_ele->face_index);
+ RNA_int_set(gz->ptr, "object_index", gz_ele->base_index);
+ RNA_int_set(gz->ptr, "vert_index", gz_ele->vert_index);
+ RNA_int_set(gz->ptr, "edge_index", gz_ele->edge_index);
+ RNA_int_set(gz->ptr, "face_index", gz_ele->face_index);
+ if (best.ele) {
ARegion *ar = CTX_wm_region(C);
ED_region_tag_redraw(ar);
}
@@ -471,5 +504,4 @@ void ED_view3d_gizmo_mesh_preselect_get_active(bContext *C,
}
}
}
-
/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
index f4e3dc85447..5625333d837 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
@@ -61,7 +61,6 @@
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
-#include "GPU_select.h"
#include "GPU_state.h"
#include "BLF_api.h"
@@ -1014,9 +1013,9 @@ static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel)
static int gizmo_ruler_cursor_get(wmGizmo *gz)
{
if (gz->highlight_part == PART_LINE) {
- return BC_CROSSCURSOR;
+ return WM_CURSOR_CROSS;
}
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
void VIEW3D_GT_ruler_item(wmGizmoType *gzt)
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 6984562337c..200cc12a6c1 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -109,17 +109,17 @@ static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event)
switch (event) {
case B_SEL_VERT:
- if (EDBM_selectmode_toggle(C, SCE_SELECT_VERTEX, -1, shift, ctrl)) {
+ if (EDBM_selectmode_toggle_multi(C, SCE_SELECT_VERTEX, -1, shift, ctrl)) {
ED_undo_push(C, "Selectmode Set: Vertex");
}
break;
case B_SEL_EDGE:
- if (EDBM_selectmode_toggle(C, SCE_SELECT_EDGE, -1, shift, ctrl)) {
+ if (EDBM_selectmode_toggle_multi(C, SCE_SELECT_EDGE, -1, shift, ctrl)) {
ED_undo_push(C, "Selectmode Set: Edge");
}
break;
case B_SEL_FACE:
- if (EDBM_selectmode_toggle(C, SCE_SELECT_FACE, -1, shift, ctrl)) {
+ if (EDBM_selectmode_toggle_multi(C, SCE_SELECT_FACE, -1, shift, ctrl)) {
ED_undo_push(C, "Selectmode Set: Face");
}
break;
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index e5a145b0411..37eea6b03d7 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -79,7 +79,11 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op)
BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend");
BKE_copybuffer_save(bmain, str, op->reports);
- BKE_reportf(op->reports, RPT_INFO, "Copied %d selected objects", num_copied);
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ num_copied == 1 ? "Copied %d selected object" :
+ "Copied %d selected objects",
+ num_copied);
return OPERATOR_FINISHED;
}
@@ -118,7 +122,11 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_WINDOW, NULL);
- BKE_reportf(op->reports, RPT_INFO, "%d objects pasted", num_pasted);
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ num_pasted == 1 ? "%d object pasted" :
+ "%d objects pasted",
+ num_pasted);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index b81b7e0109e..56c8b4bcbe9 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -116,7 +116,7 @@ eV3DProjStatus ED_view3d_project_base(const struct ARegion *ar, struct Base *bas
* - 'rv3d->persmatob', is_local == true
*/
static eV3DProjStatus ed_view3d_project__internal(const ARegion *ar,
- float perspmat[4][4],
+ const float perspmat[4][4],
const bool is_local, /* normally hidden */
const float co[3],
float r_co[2],
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 1c9ce142165..198b5d05540 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -97,7 +97,6 @@
#include "UI_interface.h"
-#include "GPU_draw.h"
#include "GPU_glew.h"
#include "GPU_matrix.h"
@@ -121,13 +120,13 @@ float ED_view3d_select_dist_px(void)
}
/* TODO: should return whether there is valid context to continue */
-void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc)
+void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc, Depsgraph *depsgraph)
{
memset(vc, 0, sizeof(ViewContext));
vc->C = C;
vc->ar = CTX_wm_region(C);
vc->bmain = CTX_data_main(C);
- vc->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ vc->depsgraph = depsgraph;
vc->scene = CTX_data_scene(C);
vc->view_layer = CTX_data_view_layer(C);
vc->v3d = CTX_wm_view3d(C);
@@ -1345,11 +1344,12 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
if (mcords) {
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
view3d_operator_needs_opengl(C);
BKE_object_update_select_id(CTX_data_main(C));
/* setup view context for argument to callbacks */
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
bool changed_multi = view3d_lasso_select(C, &vc, mcords, mcords_tot, sel_op);
@@ -1890,6 +1890,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
/* mval comes from event->mval, only use within region handlers */
Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
Base *basact = NULL;
uint buffer[MAXPICKBUF];
@@ -1898,7 +1899,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
view3d_operator_needs_opengl(C);
BKE_object_update_select_id(CTX_data_main(C));
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
const bool do_nearest = !XRAY_ACTIVE(vc.v3d);
const int hits = mixed_bones_object_selectbuffer(
@@ -1956,9 +1957,10 @@ static bool ed_object_select_pick(bContext *C,
bool enumerate,
bool object)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
/* setup view context for argument to callbacks */
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
@@ -3204,6 +3206,7 @@ static bool do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const e
static int view3d_box_select_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
rcti rect;
bool changed_multi = false;
@@ -3215,7 +3218,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
BKE_object_update_select_id(CTX_data_main(C));
/* setup view context for argument to callbacks */
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
WM_operator_properties_border_to_rcti(op, &rect);
@@ -4005,6 +4008,7 @@ static bool object_circle_select(ViewContext *vc,
/* not a real operator, only for circle test */
static int view3d_circle_select_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
const int radius = RNA_int_get(op->ptr, "radius");
const int mval[2] = {RNA_int_get(op->ptr, "x"), RNA_int_get(op->ptr, "y")};
@@ -4017,7 +4021,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"),
WM_gesture_is_modal_first(gesture));
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
Object *obact = vc.obact;
Object *obedit = vc.obedit;
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 2515ee6e482..dd8e2e07271 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -27,6 +27,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_utildefines.h"
@@ -195,8 +196,8 @@ void ED_view3d_smooth_view_ex(
sms.to_camera = true; /* restore view3d values in end */
}
- /* skip smooth viewing for render engine draw */
- if (smooth_viewtx && v3d->shading.type != OB_RENDER) {
+ /* skip smooth viewing for external render engine draw */
+ if (smooth_viewtx && !(v3d->shading.type == OB_RENDER && rv3d->render_engine)) {
bool changed = false; /* zero means no difference */
if (sview->camera_old != sview->camera) {
@@ -507,7 +508,7 @@ static bool view3d_camera_to_view_poll(bContext *C)
void VIEW3D_OT_camera_to_view(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Align Camera To View";
+ ot->name = "Align Camera to View";
ot->description = "Set camera view to active view";
ot->idname = "VIEW3D_OT_camera_to_view";
@@ -1187,7 +1188,7 @@ finally:
/** \name Local View Operators
* \{ */
-static uint free_localbit(Main *bmain)
+static uint free_localview_bit(Main *bmain)
{
ScrArea *sa;
bScreen *sc;
@@ -1242,7 +1243,7 @@ static bool view3d_localview_init(const Depsgraph *depsgraph,
INIT_MINMAX(min, max);
- local_view_bit = free_localbit(bmain);
+ local_view_bit = free_localview_bit(bmain);
if (local_view_bit == 0) {
/* TODO(dfelinto): We can kick one of the other 3D views out of local view
@@ -1534,3 +1535,134 @@ void VIEW3D_OT_localview_remove_from(wmOperatorType *ot)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Local Collections
+ * \{ */
+
+static uint free_localcollection_bit(Main *bmain,
+ unsigned short local_collections_uuid,
+ bool *reset)
+{
+ ScrArea *sa;
+ bScreen *sc;
+
+ ushort local_view_bits = 0;
+
+ /* Check all areas: which localviews are in use? */
+ for (sc = bmain->screens.first; sc; sc = sc->id.next) {
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ SpaceLink *sl = sa->spacedata.first;
+ for (; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ if (v3d->flag & V3D_LOCAL_COLLECTIONS) {
+ local_view_bits |= v3d->local_collections_uuid;
+ }
+ }
+ }
+ }
+ }
+
+ /* First try to keep the old uuid. */
+ if (local_collections_uuid && ((local_collections_uuid & local_view_bits) == 0)) {
+ return local_collections_uuid;
+ }
+
+ /* Otherwise get the first free available. */
+ for (int i = 0; i < 16; i++) {
+ if ((local_view_bits & (1 << i)) == 0) {
+ *reset = true;
+ return (1 << i);
+ }
+ }
+
+ return 0;
+}
+
+static void local_collections_reset_uuid(LayerCollection *layer_collection,
+ const unsigned short local_view_bit)
+{
+ layer_collection->local_collections_bits |= local_view_bit;
+ LISTBASE_FOREACH (LayerCollection *, child, &layer_collection->layer_collections) {
+ local_collections_reset_uuid(child, local_view_bit);
+ }
+}
+
+static void view3d_local_collections_reset(Main *bmain, const uint local_view_bit)
+{
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ LISTBASE_FOREACH (LayerCollection *, layer_collection, &view_layer->layer_collections) {
+ local_collections_reset_uuid(layer_collection, local_view_bit);
+ }
+ }
+ }
+}
+
+/**
+ * See if current uuid is valid, otherwise set a valid uuid to v3d,
+ * Try to keep the same uuid previously used to allow users to
+ * quickly toggle back and forth.
+ */
+bool ED_view3d_local_collections_set(Main *bmain, struct View3D *v3d)
+{
+ if ((v3d->flag & V3D_LOCAL_COLLECTIONS) == 0) {
+ return true;
+ }
+
+ bool reset = false;
+ v3d->flag &= ~V3D_LOCAL_COLLECTIONS;
+ uint local_view_bit = free_localcollection_bit(bmain, v3d->local_collections_uuid, &reset);
+
+ if (local_view_bit == 0) {
+ return false;
+ }
+
+ v3d->local_collections_uuid = local_view_bit;
+ v3d->flag |= V3D_LOCAL_COLLECTIONS;
+
+ if (reset) {
+ view3d_local_collections_reset(bmain, local_view_bit);
+ }
+
+ return true;
+}
+
+void ED_view3d_local_collections_reset(struct bContext *C, const bool reset_all)
+{
+ Main *bmain = CTX_data_main(C);
+ uint local_view_bit = ~(0);
+ bool do_reset = false;
+
+ /* Reset only the ones that are not in use. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ if (v3d->local_collections_uuid) {
+ if (v3d->flag & V3D_LOCAL_COLLECTIONS) {
+ local_view_bit &= ~v3d->local_collections_uuid;
+ }
+ else {
+ do_reset = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (do_reset) {
+ view3d_local_collections_reset(bmain, local_view_bit);
+ }
+ else if (reset_all && (do_reset || (local_view_bit != ~(0)))) {
+ view3d_local_collections_reset(bmain, ~(0));
+ View3D v3d = {.local_collections_uuid = ~(0)};
+ BKE_layer_collection_local_sync(CTX_data_view_layer(C), &v3d);
+ DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_BASE_FLAGS);
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 91c05f5cac6..ac9ad30d719 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -577,7 +577,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->ar->winrct.ymin + walk->center_mval[1]);
/* remove the mouse cursor temporarily */
- WM_cursor_modal_set(win, CURSOR_NONE);
+ WM_cursor_modal_set(win, WM_CURSOR_NONE);
return 1;
}
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index 9696f0fb315..e3ff8b92081 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -40,7 +40,25 @@ set(INC_SYS
set(SRC
transform.c
transform_constraints.c
- transform_conversions.c
+ transform_convert.c
+ transform_convert_action.c
+ transform_convert_armature.c
+ transform_convert_cursor.c
+ transform_convert_curve.c
+ transform_convert_gpencil.c
+ transform_convert_graph.c
+ transform_convert_lattice.c
+ transform_convert_mask.c
+ transform_convert_mball.c
+ transform_convert_mesh.c
+ transform_convert_nla.c
+ transform_convert_node.c
+ transform_convert_object.c
+ transform_convert_paintcurve.c
+ transform_convert_particle.c
+ transform_convert_sculpt.c
+ transform_convert_sequencer.c
+ transform_convert_tracking.c
transform_generics.c
transform_gizmo_2d.c
transform_gizmo_3d.c
@@ -52,6 +70,7 @@ set(SRC
transform_snap_object.c
transform.h
+ transform_convert.h
)
set(LIB
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 6478928a6b6..67ea0f255fc 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -65,7 +65,6 @@
#include "DEG_depsgraph.h"
#include "GPU_immediate.h"
-#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
#include "GPU_state.h"
@@ -79,6 +78,7 @@
#include "ED_clip.h"
#include "ED_node.h"
#include "ED_gpencil.h"
+#include "ED_sculpt.h"
#include "WM_types.h"
#include "WM_api.h"
@@ -95,6 +95,7 @@
#include "BLT_translation.h"
#include "transform.h"
+#include "transform_convert.h"
/* Disabling, since when you type you know what you are doing,
* and being able to set it to zero is handy. */
@@ -1793,7 +1794,7 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
if (t->helpline != HLP_NONE) {
float cent[2];
- float mval[3] = {
+ const float mval[3] = {
x,
y,
0.0f,
@@ -2298,16 +2299,14 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
}
+ if ((t->options & CTX_SCULPT) && !(t->options & CTX_PAINT_CURVE)) {
+ ED_sculpt_end_transform(C);
+ }
+
if ((prop = RNA_struct_find_property(op->ptr, "correct_uv"))) {
RNA_property_boolean_set(
op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) != 0);
}
-
- if (t->mode == TFM_SHEAR) {
- prop = RNA_struct_find_property(op->ptr, "shear_axis");
- t->custom.mode.data = POINTER_FROM_INT(RNA_property_enum_get(op->ptr, prop));
- RNA_property_enum_set(op->ptr, prop, POINTER_AS_INT(t->custom.mode.data));
- }
}
/**
@@ -2347,6 +2346,11 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
+ Object *ob = CTX_data_active_object(C);
+ if (ob && ob->mode == OB_MODE_SCULPT && ob->sculpt) {
+ options |= CTX_SCULPT;
+ }
+
t->options = options;
t->mode = mode;
@@ -2409,6 +2413,10 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
createTransData(C, t); // make TransData structs from selection
+ if (t->options & CTX_SCULPT) {
+ ED_sculpt_init_transform(C);
+ }
+
if (t->data_len_all == 0) {
postTrans(C, t);
return 0;
@@ -2517,8 +2525,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
initToSphere(t);
break;
case TFM_SHEAR:
- prop = RNA_struct_find_property(op->ptr, "shear_axis");
- t->custom.mode.data = POINTER_FROM_INT(RNA_property_enum_get(op->ptr, prop));
initShear(t);
break;
case TFM_BEND:
@@ -3515,13 +3521,7 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
static void initShear_mouseInputMode(TransInfo *t)
{
float dir[3];
-
- if (t->custom.mode.data == NULL) {
- copy_v3_v3(dir, t->orient_matrix[t->orient_axis_ortho]);
- }
- else {
- cross_v3_v3v3(dir, t->orient_matrix[t->orient_axis_ortho], t->orient_matrix[t->orient_axis]);
- }
+ copy_v3_v3(dir, t->orient_matrix[t->orient_axis_ortho]);
/* Without this, half the gizmo handles move in the opposite direction. */
if ((t->orient_axis_ortho + 1) % 3 != t->orient_axis) {
@@ -3569,24 +3569,22 @@ static eRedrawFlag handleEventShear(TransInfo *t, const wmEvent *event)
if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) {
/* Use custom.mode.data pointer to signal Shear direction */
- if (t->custom.mode.data == NULL) {
- t->custom.mode.data = (void *)1;
- }
- else {
- t->custom.mode.data = NULL;
- }
+ do {
+ t->orient_axis_ortho = (t->orient_axis_ortho + 1) % 3;
+ } while (t->orient_axis_ortho == t->orient_axis);
+
initShear_mouseInputMode(t);
status = TREDRAW_HARD;
}
else if (event->type == XKEY && event->val == KM_PRESS) {
- t->custom.mode.data = NULL;
+ t->orient_axis_ortho = (t->orient_axis + 1) % 3;
initShear_mouseInputMode(t);
status = TREDRAW_HARD;
}
else if (event->type == YKEY && event->val == KM_PRESS) {
- t->custom.mode.data = (void *)1;
+ t->orient_axis_ortho = (t->orient_axis + 2) % 3;
initShear_mouseInputMode(t);
status = TREDRAW_HARD;
@@ -3630,14 +3628,7 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
}
unit_m3(smat);
-
- // Custom data signals shear direction
- if (t->custom.mode.data == NULL) {
- smat[1][0] = value;
- }
- else {
- smat[0][1] = value;
- }
+ smat[1][0] = value;
copy_v3_v3(axismat_inv[0], t->orient_matrix[t->orient_axis_ortho]);
copy_v3_v3(axismat_inv[2], t->orient_matrix[t->orient_axis]);
@@ -3878,7 +3869,7 @@ static void ElementResize(TransInfo *t, TransDataContainer *tc, TransData *td, f
if (td->ext && td->ext->size) {
float fsize[3];
- if (t->flag & (T_OBJECT | T_TEXTURE | T_POSE)) {
+ if ((t->options & CTX_SCULPT) || t->flag & (T_OBJECT | T_TEXTURE | T_POSE)) {
float obsizemat[3][3];
/* Reorient the size mat to fit the oriented object. */
mul_m3_m3m3(obsizemat, tmat, td->axismtx);
@@ -4331,8 +4322,11 @@ static void headerRotation(TransInfo *t, char str[UI_MAX_DRAW_STR], float final)
*
* Protected axis and other transform settings are taken into account.
*/
-static void ElementRotation_ex(
- TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const float *center)
+static void ElementRotation_ex(TransInfo *t,
+ TransDataContainer *tc,
+ TransData *td,
+ const float mat[3][3],
+ const float *center)
{
float vec[3], totmat[3][3], smat[3][3];
float eul[3], fmat[3][3], quat[4];
@@ -4736,7 +4730,7 @@ static void initTrackball(TransInfo *t)
static void applyTrackballValue(TransInfo *t,
const float axis1[3],
const float axis2[3],
- float angles[2])
+ const float angles[2])
{
float mat[3][3];
float axis[3];
@@ -6398,367 +6392,6 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
/** \} */
/* -------------------------------------------------------------------- */
-/* Original Data Store */
-
-/** \name Orig-Data Store Utility Functions
- * \{ */
-
-static void slide_origdata_init_flag(TransInfo *t, TransDataContainer *tc, SlideOrigData *sod)
-{
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- BMesh *bm = em->bm;
- const bool has_layer_math = CustomData_has_math(&bm->ldata);
- const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
-
- if ((t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) &&
- /* don't do this at all for non-basis shape keys, too easy to
- * accidentally break uv maps or vertex colors then */
- (bm->shapenr <= 1) && (has_layer_math || (cd_loop_mdisp_offset != -1))) {
- sod->use_origfaces = true;
- sod->cd_loop_mdisp_offset = cd_loop_mdisp_offset;
- }
- else {
- sod->use_origfaces = false;
- sod->cd_loop_mdisp_offset = -1;
- }
-}
-
-static void slide_origdata_init_data(TransDataContainer *tc, SlideOrigData *sod)
-{
- if (sod->use_origfaces) {
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- BMesh *bm = em->bm;
-
- sod->origfaces = BLI_ghash_ptr_new(__func__);
- sod->bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default,
- &((struct BMeshCreateParams){
- .use_toolflags = false,
- }));
- /* we need to have matching customdata */
- BM_mesh_copy_init_customdata(sod->bm_origfaces, bm, NULL);
- }
-}
-
-static void slide_origdata_create_data_vert(BMesh *bm,
- SlideOrigData *sod,
- TransDataGenericSlideVert *sv)
-{
- BMIter liter;
- int j, l_num;
- float *loop_weights;
-
- /* copy face data */
- // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) {
- BM_iter_init(&liter, bm, BM_LOOPS_OF_VERT, sv->v);
- l_num = liter.count;
- loop_weights = BLI_array_alloca(loop_weights, l_num);
- for (j = 0; j < l_num; j++) {
- BMLoop *l = BM_iter_step(&liter);
- BMLoop *l_prev, *l_next;
- void **val_p;
- if (!BLI_ghash_ensure_p(sod->origfaces, l->f, &val_p)) {
- BMFace *f_copy = BM_face_copy(sod->bm_origfaces, bm, l->f, true, true);
- *val_p = f_copy;
- }
-
- if ((l_prev = BM_loop_find_prev_nodouble(l, l->next, FLT_EPSILON)) &&
- (l_next = BM_loop_find_next_nodouble(l, l_prev, FLT_EPSILON))) {
- loop_weights[j] = angle_v3v3v3(l_prev->v->co, l->v->co, l_next->v->co);
- }
- else {
- loop_weights[j] = 0.0f;
- }
- }
-
- /* store cd_loop_groups */
- if (sod->layer_math_map_num && (l_num != 0)) {
- sv->cd_loop_groups = BLI_memarena_alloc(sod->arena, sod->layer_math_map_num * sizeof(void *));
- for (j = 0; j < sod->layer_math_map_num; j++) {
- const int layer_nr = sod->layer_math_map[j];
- sv->cd_loop_groups[j] = BM_vert_loop_groups_data_layer_create(
- bm, sv->v, layer_nr, loop_weights, sod->arena);
- }
- }
- else {
- sv->cd_loop_groups = NULL;
- }
-
- BLI_ghash_insert(sod->origverts, sv->v, sv);
-}
-
-static void slide_origdata_create_data(TransDataContainer *tc,
- SlideOrigData *sod,
- TransDataGenericSlideVert *sv_array,
- unsigned int v_stride,
- unsigned int v_num)
-{
- if (sod->use_origfaces) {
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- BMesh *bm = em->bm;
- unsigned int i;
- TransDataGenericSlideVert *sv;
-
- int layer_index_dst;
- int j;
-
- layer_index_dst = 0;
-
- /* TODO: We don't need `sod->layer_math_map` when there are no loops linked
- * to one of the sliding vertices. */
- if (CustomData_has_math(&bm->ldata)) {
- /* over alloc, only 'math' layers are indexed */
- sod->layer_math_map = MEM_mallocN(bm->ldata.totlayer * sizeof(int), __func__);
- for (j = 0; j < bm->ldata.totlayer; j++) {
- if (CustomData_layer_has_math(&bm->ldata, j)) {
- sod->layer_math_map[layer_index_dst++] = j;
- }
- }
- BLI_assert(layer_index_dst != 0);
- }
-
- sod->layer_math_map_num = layer_index_dst;
-
- sod->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
-
- sod->origverts = BLI_ghash_ptr_new_ex(__func__, v_num);
-
- for (i = 0, sv = sv_array; i < v_num; i++, sv = POINTER_OFFSET(sv, v_stride)) {
- slide_origdata_create_data_vert(bm, sod, sv);
- }
-
- if (tc->mirror.axis_flag) {
- TransData *td = tc->data;
- TransDataGenericSlideVert *sv_mirror;
-
- sod->sv_mirror = MEM_callocN(sizeof(*sv_mirror) * tc->data_len, __func__);
- sod->totsv_mirror = tc->data_len;
-
- sv_mirror = sod->sv_mirror;
-
- for (i = 0; i < tc->data_len; i++, td++) {
- BMVert *eve = td->extra;
- /* Check the vertex has been used since both sides
- * of the mirror may be selected & sliding. */
- if (eve && !BLI_ghash_haskey(sod->origverts, eve)) {
- sv_mirror->v = eve;
- copy_v3_v3(sv_mirror->co_orig_3d, eve->co);
-
- slide_origdata_create_data_vert(bm, sod, sv_mirror);
- sv_mirror++;
- }
- else {
- sod->totsv_mirror--;
- }
- }
-
- if (sod->totsv_mirror == 0) {
- MEM_freeN(sod->sv_mirror);
- sod->sv_mirror = NULL;
- }
- }
- }
-}
-
-/**
- * If we're sliding the vert, return its original location, if not, the current location is good.
- */
-static const float *slide_origdata_orig_vert_co(SlideOrigData *sod, BMVert *v)
-{
- TransDataGenericSlideVert *sv = BLI_ghash_lookup(sod->origverts, v);
- return sv ? sv->co_orig_3d : v->co;
-}
-
-static void slide_origdata_interp_data_vert(SlideOrigData *sod,
- BMesh *bm,
- bool is_final,
- TransDataGenericSlideVert *sv)
-{
- BMIter liter;
- int j, l_num;
- float *loop_weights;
- const bool is_moved = (len_squared_v3v3(sv->v->co, sv->co_orig_3d) > FLT_EPSILON);
- const bool do_loop_weight = sod->layer_math_map_num && is_moved;
- const bool do_loop_mdisps = is_final && is_moved && (sod->cd_loop_mdisp_offset != -1);
- const float *v_proj_axis = sv->v->no;
- /* original (l->prev, l, l->next) projections for each loop ('l' remains unchanged) */
- float v_proj[3][3];
-
- if (do_loop_weight || do_loop_mdisps) {
- project_plane_normalized_v3_v3v3(v_proj[1], sv->co_orig_3d, v_proj_axis);
- }
-
- // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT)
- BM_iter_init(&liter, bm, BM_LOOPS_OF_VERT, sv->v);
- l_num = liter.count;
- loop_weights = do_loop_weight ? BLI_array_alloca(loop_weights, l_num) : NULL;
- for (j = 0; j < l_num; j++) {
- BMFace *f_copy; /* the copy of 'f' */
- BMLoop *l = BM_iter_step(&liter);
-
- f_copy = BLI_ghash_lookup(sod->origfaces, l->f);
-
- /* only loop data, no vertex data since that contains shape keys,
- * and we do not want to mess up other shape keys */
- BM_loop_interp_from_face(bm, l, f_copy, false, false);
-
- /* make sure face-attributes are correct (e.g. #MLoopUV, #MLoopCol) */
- BM_elem_attrs_copy_ex(sod->bm_origfaces, bm, f_copy, l->f, 0x0, CD_MASK_NORMAL);
-
- /* weight the loop */
- if (do_loop_weight) {
- const float eps = 1.0e-8f;
- const BMLoop *l_prev = l->prev;
- const BMLoop *l_next = l->next;
- const float *co_prev = slide_origdata_orig_vert_co(sod, l_prev->v);
- const float *co_next = slide_origdata_orig_vert_co(sod, l_next->v);
- bool co_prev_ok;
- bool co_next_ok;
-
- /* In the unlikely case that we're next to a zero length edge -
- * walk around the to the next.
- *
- * Since we only need to check if the vertex is in this corner,
- * its not important _which_ loop - as long as its not overlapping
- * 'sv->co_orig_3d', see: T45096. */
- project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
- while (UNLIKELY(((co_prev_ok = (len_squared_v3v3(v_proj[1], v_proj[0]) > eps)) == false) &&
- ((l_prev = l_prev->prev) != l->next))) {
- co_prev = slide_origdata_orig_vert_co(sod, l_prev->v);
- project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
- }
- project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis);
- while (UNLIKELY(((co_next_ok = (len_squared_v3v3(v_proj[1], v_proj[2]) > eps)) == false) &&
- ((l_next = l_next->next) != l->prev))) {
- co_next = slide_origdata_orig_vert_co(sod, l_next->v);
- project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis);
- }
-
- if (co_prev_ok && co_next_ok) {
- const float dist = dist_signed_squared_to_corner_v3v3v3(
- sv->v->co, UNPACK3(v_proj), v_proj_axis);
-
- loop_weights[j] = (dist >= 0.0f) ? 1.0f : ((dist <= -eps) ? 0.0f : (1.0f + (dist / eps)));
- if (UNLIKELY(!isfinite(loop_weights[j]))) {
- loop_weights[j] = 0.0f;
- }
- }
- else {
- loop_weights[j] = 0.0f;
- }
- }
- }
-
- if (sod->layer_math_map_num && sv->cd_loop_groups) {
- if (do_loop_weight) {
- for (j = 0; j < sod->layer_math_map_num; j++) {
- BM_vert_loop_groups_data_layer_merge_weights(
- bm, sv->cd_loop_groups[j], sod->layer_math_map[j], loop_weights);
- }
- }
- else {
- for (j = 0; j < sod->layer_math_map_num; j++) {
- BM_vert_loop_groups_data_layer_merge(bm, sv->cd_loop_groups[j], sod->layer_math_map[j]);
- }
- }
- }
-
- /* Special handling for multires
- *
- * Interpolate from every other loop (not ideal)
- * However values will only be taken from loops which overlap other mdisps.
- * */
- if (do_loop_mdisps) {
- float(*faces_center)[3] = BLI_array_alloca(faces_center, l_num);
- BMLoop *l;
-
- BM_ITER_ELEM_INDEX (l, &liter, sv->v, BM_LOOPS_OF_VERT, j) {
- BM_face_calc_center_median(l->f, faces_center[j]);
- }
-
- BM_ITER_ELEM_INDEX (l, &liter, sv->v, BM_LOOPS_OF_VERT, j) {
- BMFace *f_copy = BLI_ghash_lookup(sod->origfaces, l->f);
- float f_copy_center[3];
- BMIter liter_other;
- BMLoop *l_other;
- int j_other;
-
- BM_face_calc_center_median(f_copy, f_copy_center);
-
- BM_ITER_ELEM_INDEX (l_other, &liter_other, sv->v, BM_LOOPS_OF_VERT, j_other) {
- BM_face_interp_multires_ex(bm,
- l_other->f,
- f_copy,
- faces_center[j_other],
- f_copy_center,
- sod->cd_loop_mdisp_offset);
- }
- }
- }
-}
-
-static void slide_origdata_interp_data(Object *obedit,
- SlideOrigData *sod,
- TransDataGenericSlideVert *sv,
- unsigned int v_stride,
- unsigned int v_num,
- bool is_final)
-{
- if (sod->use_origfaces) {
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- unsigned int i;
- const bool has_mdisps = (sod->cd_loop_mdisp_offset != -1);
-
- for (i = 0; i < v_num; i++, sv = POINTER_OFFSET(sv, v_stride)) {
-
- if (sv->cd_loop_groups || has_mdisps) {
- slide_origdata_interp_data_vert(sod, bm, is_final, sv);
- }
- }
-
- if (sod->sv_mirror) {
- sv = sod->sv_mirror;
- for (i = 0; i < v_num; i++, sv++) {
- if (sv->cd_loop_groups || has_mdisps) {
- slide_origdata_interp_data_vert(sod, bm, is_final, sv);
- }
- }
- }
- }
-}
-
-static void slide_origdata_free_date(SlideOrigData *sod)
-{
- if (sod->use_origfaces) {
- if (sod->bm_origfaces) {
- BM_mesh_free(sod->bm_origfaces);
- sod->bm_origfaces = NULL;
- }
-
- if (sod->origfaces) {
- BLI_ghash_free(sod->origfaces, NULL, NULL);
- sod->origfaces = NULL;
- }
-
- if (sod->origverts) {
- BLI_ghash_free(sod->origverts, NULL, NULL);
- sod->origverts = NULL;
- }
-
- if (sod->arena) {
- BLI_memarena_free(sod->arena);
- sod->arena = NULL;
- }
-
- MEM_SAFE_FREE(sod->layer_math_map);
-
- MEM_SAFE_FREE(sod->sv_mirror);
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/* Transform (Edge Slide) */
/** \name Transform Edge Slide
@@ -7209,8 +6842,6 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, TransDataContainer *t
View3D *v3d = NULL;
RegionView3D *rv3d = NULL;
- slide_origdata_init_flag(t, tc, &sld->orig_data);
-
sld->curr_sv_index = 0;
/*ensure valid selection*/
@@ -7541,18 +7172,10 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, TransDataContainer *t
calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, true);
- /* create copies of faces for customdata projection */
- bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
- slide_origdata_init_data(tc, &sld->orig_data);
- slide_origdata_create_data(
- tc, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
-
if (rv3d) {
calcEdgeSlide_even(t, tc, sld, mval);
}
- sld->em = em;
-
tc->custom.mode.data = sld;
MEM_freeN(sv_table);
@@ -7586,8 +7209,6 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, TransDataContainer *t
rv3d = t->ar ? t->ar->regiondata : NULL;
}
- slide_origdata_init_flag(t, tc, &sld->orig_data);
-
sld->curr_sv_index = 0;
/* ensure valid selection */
{
@@ -7736,18 +7357,10 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, TransDataContainer *t
calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, false);
- /* create copies of faces for customdata projection */
- bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
- slide_origdata_init_data(tc, &sld->orig_data);
- slide_origdata_create_data(
- tc, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
-
if (rv3d) {
calcEdgeSlide_even(t, tc, sld, mval);
}
- sld->em = em;
-
tc->custom.mode.data = sld;
MEM_freeN(sv_table);
@@ -7764,25 +7377,10 @@ void projectEdgeSlideData(TransInfo *t, bool is_final)
continue;
}
- SlideOrigData *sod = &sld->orig_data;
- if (sod->use_origfaces == false) {
- continue;
- }
-
- slide_origdata_interp_data(tc->obedit,
- sod,
- (TransDataGenericSlideVert *)sld->sv,
- sizeof(*sld->sv),
- sld->totsv,
- is_final);
+ trans_mesh_customdata_correction_apply(tc, is_final);
}
}
-void freeEdgeSlideTempFaces(EdgeSlideData *sld)
-{
- slide_origdata_free_date(&sld->orig_data);
-}
-
void freeEdgeSlideVerts(TransInfo *UNUSED(t),
TransDataContainer *UNUSED(tc),
TransCustomData *custom_data)
@@ -7793,10 +7391,6 @@ void freeEdgeSlideVerts(TransInfo *UNUSED(t),
return;
}
- freeEdgeSlideTempFaces(sld);
-
- bmesh_edit_end(sld->em->bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
-
MEM_freeN(sld->sv);
MEM_freeN(sld);
@@ -7855,6 +7449,8 @@ static void initEdgeSlide_ex(
tc->custom.mode.free_cb = freeEdgeSlideVerts;
}
+ trans_mesh_customdata_correction_init(t);
+
/* set custom point first if you want value to be initialized by init */
calcEdgeSlideCustomPoints(t);
initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO_FLIP);
@@ -8330,8 +7926,6 @@ static bool createVertSlideVerts(TransInfo *t, TransDataContainer *tc)
VertSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
int j;
- slide_origdata_init_flag(t, tc, &sld->orig_data);
-
sld->curr_sv_index = 0;
j = 0;
@@ -8395,13 +7989,6 @@ static bool createVertSlideVerts(TransInfo *t, TransDataContainer *tc)
sld->sv = sv_array;
sld->totsv = j;
- bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
- slide_origdata_init_data(tc, &sld->orig_data);
- slide_origdata_create_data(
- tc, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
-
- sld->em = em;
-
tc->custom.mode.data = sld;
/* most likely will be set below */
@@ -8430,24 +8017,10 @@ static bool createVertSlideVerts(TransInfo *t, TransDataContainer *tc)
void projectVertSlideData(TransInfo *t, bool is_final)
{
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- VertSlideData *sld = tc->custom.mode.data;
- SlideOrigData *sod = &sld->orig_data;
- if (sod->use_origfaces == true) {
- slide_origdata_interp_data(tc->obedit,
- sod,
- (TransDataGenericSlideVert *)sld->sv,
- sizeof(*sld->sv),
- sld->totsv,
- is_final);
- }
+ trans_mesh_customdata_correction_apply(tc, is_final);
}
}
-void freeVertSlideTempFaces(VertSlideData *sld)
-{
- slide_origdata_free_date(&sld->orig_data);
-}
-
void freeVertSlideVerts(TransInfo *UNUSED(t),
TransDataContainer *UNUSED(tc),
TransCustomData *custom_data)
@@ -8458,10 +8031,6 @@ void freeVertSlideVerts(TransInfo *UNUSED(t),
return;
}
- freeVertSlideTempFaces(sld);
-
- bmesh_edit_end(sld->em->bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
-
if (sld->totsv > 0) {
TransDataVertSlideVert *sv = sld->sv;
int i = 0;
@@ -8511,6 +8080,8 @@ static void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use
return;
}
+ trans_mesh_customdata_correction_init(t);
+
/* set custom point first if you want value to be initialized by init */
calcVertSlideCustomPoints(t);
initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO);
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 358e4825278..ff2afbc0cd7 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -267,7 +267,6 @@ typedef struct TransDataNla {
int handle;
} TransDataNla;
-struct GHash;
struct LinkNode;
/* header of TransDataEdgeSlideVert, TransDataEdgeSlideEdge */
@@ -294,38 +293,11 @@ typedef struct TransDataEdgeSlideVert {
int loop_nr;
} TransDataEdgeSlideVert;
-/* store original data so we can correct UV's and similar when sliding */
-typedef struct SlideOrigData {
- /** Set when #origfaces is initialized. */
- bool use_origfaces;
- int cd_loop_mdisp_offset;
-
- /** map {BMVert: TransDataGenericSlideVert} */
- struct GHash *origverts;
- struct GHash *origfaces;
- struct BMesh *bm_origfaces;
-
- struct MemArena *arena;
- /** Number of math BMLoop layers. */
- int layer_math_map_num;
- /** Array size of 'layer_math_map_num'
- * maps TransDataVertSlideVert.cd_group index to absolute CustomData layer index */
- int *layer_math_map;
-
- /** Array of slide vert data especially for mirror verts. */
- TransDataGenericSlideVert *sv_mirror;
- int totsv_mirror;
-} SlideOrigData;
-
typedef struct EdgeSlideData {
TransDataEdgeSlideVert *sv;
int totsv;
int mval_start[2], mval_end[2];
- struct BMEditMesh *em;
-
- SlideOrigData orig_data;
-
int curr_sv_index;
/** when un-clamped - use this index: #TransDataEdgeSlideVert.dir_side */
@@ -354,11 +326,6 @@ typedef struct TransDataVertSlideVert {
typedef struct VertSlideData {
TransDataVertSlideVert *sv;
int totsv;
-
- struct BMEditMesh *em;
-
- SlideOrigData orig_data;
-
int curr_sv_index;
/* result of ED_view3d_ob_project_mat_get */
@@ -449,6 +416,18 @@ typedef struct TransData {
short protectflag;
} TransData;
+typedef struct TransDataMirror {
+ /** location of mirrored reference data. */
+ const float *loc_src;
+ /** Location of the data to transform. */
+ float *loc_dst;
+ void *extra;
+ /* `sign` can be -2, -1, 0 or 1. */
+ int sign_x : 2;
+ int sign_y : 2;
+ int sign_z : 2;
+} TransDataMirror;
+
typedef struct MouseInput {
void (*apply)(struct TransInfo *t, struct MouseInput *mi, const double mval[2], float output[3]);
void (*post)(struct TransInfo *t, float values[3]);
@@ -549,10 +528,18 @@ typedef struct TransDataContainer {
* Mirror option
*/
struct {
- /* Currently for mesh X mirror only. */
- int axis_flag;
- /** Set to -1.0f or 1.0 when use_mirror is set. */
- float sign;
+ union {
+ struct {
+ uint axis_x : 1;
+ uint axis_y : 1;
+ uint axis_z : 1;
+ };
+ /* For easy checking. */
+ char use_mirror_any;
+ };
+ /** Mirror data array. */
+ TransDataMirror *data;
+ int data_len;
} mirror;
TransCustomDataContainer custom;
@@ -721,16 +708,6 @@ typedef struct TransInfo {
/** Typically for mode settings. */
TransCustomDataContainer custom;
-
- /**
- * Object to object data transform table.
- * Don't add these to transform data because we may want to include child objects
- * which aren't being transformed.
- * - The key is object data #ID.
- * - The value is #XFormObjectData_Extra.
- */
- struct GHash *obdata_in_obmode_map;
-
} TransInfo;
/* ******************** Macros & Prototypes *********************** */
@@ -802,10 +779,6 @@ enum {
T_MODAL_CURSOR_SET = 1 << 26,
T_CLNOR_REBUILD = 1 << 27,
-
- /** When transforming object's, adjust the object data so it stays in the same place. */
- T_OBJECT_DATA_IN_OBJECT_MODE = 1 << 28,
-
};
/** #TransInfo.modifiers */
@@ -874,16 +847,18 @@ enum {
/** For Graph Editor - curves that can only have int-values
* need their keyframes tagged with this. */
TD_INTVALUES = 1 << 15,
- /** For editmode mirror, clamp to x = 0 */
- TD_MIRROR_EDGE = 1 << 16,
+ /** For editmode mirror, clamp axis to 0 */
+ TD_MIRROR_EDGE_X = 1 << 16,
+ TD_MIRROR_EDGE_Y = 1 << 17,
+ TD_MIRROR_EDGE_Z = 1 << 18,
/** For fcurve handles, move them along with their keyframes */
- TD_MOVEHANDLE1 = 1 << 17,
- TD_MOVEHANDLE2 = 1 << 18,
+ TD_MOVEHANDLE1 = 1 << 19,
+ TD_MOVEHANDLE2 = 1 << 20,
/** Exceptional case with pose bone rotating when a parent bone has 'Local Location'
* option enabled and rotating also transforms it. */
- TD_PBONE_LOCAL_MTX_P = 1 << 19,
+ TD_PBONE_LOCAL_MTX_P = 1 << 21,
/** Same as above but for a child bone. */
- TD_PBONE_LOCAL_MTX_C = 1 << 20,
+ TD_PBONE_LOCAL_MTX_C = 1 << 22,
};
/** #TransSnap.status */
@@ -923,23 +898,6 @@ void drawPropCircle(const struct bContext *C, TransInfo *t);
struct wmKeyMap *transform_modal_keymap(struct wmKeyConfig *keyconf);
-/*********************** transform_conversions.c ********** */
-
-void flushTransIntFrameActionData(TransInfo *t);
-void flushTransGraphData(TransInfo *t);
-void remake_graph_transdata(TransInfo *t, struct ListBase *anim_data);
-void flushTransUVs(TransInfo *t);
-void flushTransParticles(TransInfo *t);
-bool clipUVTransform(TransInfo *t, float vec[2], const bool resize);
-void clipUVData(TransInfo *t);
-void flushTransNodes(TransInfo *t);
-void flushTransSeq(TransInfo *t);
-void flushTransTracking(TransInfo *t);
-void flushTransMasking(TransInfo *t);
-void flushTransPaintCurve(TransInfo *t);
-void restoreMirrorPoseBones(TransDataContainer *tc);
-void restoreBones(TransDataContainer *tc);
-
/*********************** transform_gizmo.c ********** */
#define GIZMO_AXIS_LINE_WIDTH 2.0f
@@ -949,32 +907,8 @@ bool gimbal_axis(struct Object *ob, float gmat[3][3]);
void drawDial3d(const TransInfo *t);
/*********************** TransData Creation and General Handling *********** */
-void createTransData(struct bContext *C, TransInfo *t);
-void sort_trans_data_dist(TransInfo *t);
-void special_aftertrans_update(struct bContext *C, TransInfo *t);
-int special_transform_moving(TransInfo *t);
-
-void transform_autoik_update(TransInfo *t, short mode);
bool transdata_check_local_islands(TransInfo *t, short around);
-int count_set_pose_transflags(struct Object *ob,
- const int mode,
- const short around,
- bool has_translate_rotate[2]);
-
-/* Auto-keyframe applied after transform, returns true if motion paths need to be updated. */
-void autokeyframe_object(struct bContext *C,
- struct Scene *scene,
- struct ViewLayer *view_layer,
- struct Object *ob,
- int tmode);
-void autokeyframe_pose(
- struct bContext *C, struct Scene *scene, struct Object *ob, int tmode, short targetless_ik);
-
-/* Test if we need to update motion paths for a given object. */
-bool motionpath_need_update_object(struct Scene *scene, struct Object *ob);
-bool motionpath_need_update_pose(struct Scene *scene, struct Object *ob);
-
/*********************** Constraints *****************************/
void drawConstraint(TransInfo *t);
@@ -1146,11 +1080,9 @@ int getTransformOrientation(const struct bContext *C, float normal[3], float pla
void freeCustomNormalArray(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data);
-void freeEdgeSlideTempFaces(EdgeSlideData *sld);
void freeEdgeSlideVerts(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data);
void projectEdgeSlideData(TransInfo *t, bool is_final);
-void freeVertSlideTempFaces(VertSlideData *sld);
void freeVertSlideVerts(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data);
void projectVertSlideData(TransInfo *t, bool is_final);
@@ -1179,7 +1111,4 @@ bool checkUseAxisMatrix(TransInfo *t);
th != tc_end; \
th++, i++)
-void trans_obdata_in_obmode_free_all(struct TransInfo *t);
-void trans_obdata_in_obmode_update_all(struct TransInfo *t);
-
#endif
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
deleted file mode 100644
index dc072d74be6..00000000000
--- a/source/blender/editors/transform/transform_conversions.c
+++ /dev/null
@@ -1,9925 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup edtransform
- */
-
-#include <string.h>
-#include <math.h>
-#include <limits.h>
-
-#include "DNA_anim_types.h"
-#include "DNA_brush_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_lattice_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meta_types.h"
-#include "DNA_node_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_space_types.h"
-#include "DNA_sequence_types.h"
-#include "DNA_view3d_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_gpencil_types.h"
-#include "DNA_movieclip_types.h"
-#include "DNA_mask_types.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-#include "BLI_listbase.h"
-#include "BLI_linklist_stack.h"
-#include "BLI_string.h"
-#include "BLI_bitmap.h"
-#include "BLI_rect.h"
-#include "BLI_kdtree.h"
-
-#include "BKE_action.h"
-#include "BKE_animsys.h"
-#include "BKE_armature.h"
-#include "BKE_constraint.h"
-#include "BKE_context.h"
-#include "BKE_crazyspace.h"
-#include "BKE_curve.h"
-#include "BKE_fcurve.h"
-#include "BKE_global.h"
-#include "BKE_gpencil.h"
-#include "BKE_layer.h"
-#include "BKE_key.h"
-#include "BKE_main.h"
-#include "BKE_mesh.h"
-#include "BKE_mesh_mapping.h"
-#include "BKE_modifier.h"
-#include "BKE_movieclip.h"
-#include "BKE_nla.h"
-#include "BKE_node.h"
-#include "BKE_object.h"
-#include "BKE_particle.h"
-#include "BKE_paint.h"
-#include "BKE_pointcache.h"
-#include "BKE_report.h"
-#include "BKE_rigidbody.h"
-#include "BKE_scene.h"
-#include "BKE_sequencer.h"
-#include "BKE_editmesh.h"
-#include "BKE_tracking.h"
-#include "BKE_mask.h"
-#include "BKE_colortools.h"
-
-#include "BIK_api.h"
-
-#include "ED_anim_api.h"
-#include "ED_armature.h"
-#include "ED_particle.h"
-#include "ED_image.h"
-#include "ED_keyframing.h"
-#include "ED_keyframes_edit.h"
-#include "ED_object.h"
-#include "ED_markers.h"
-#include "ED_mesh.h"
-#include "ED_node.h"
-#include "ED_uvedit.h"
-#include "ED_clip.h"
-#include "ED_mask.h"
-#include "ED_gpencil.h"
-
-#include "WM_api.h" /* for WM_event_add_notifier to deal with stabilization nodes */
-#include "WM_types.h"
-
-#include "UI_view2d.h"
-#include "UI_interface.h"
-
-#include "RNA_access.h"
-
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_build.h"
-#include "DEG_depsgraph_query.h"
-
-#include "transform.h"
-#include "bmesh.h"
-
-/**
- * Transforming around ourselves is no use, fallback to individual origins,
- * useful for curve/armatures.
- */
-static void transform_around_single_fallback(TransInfo *t)
-{
- if ((t->data_len_all == 1) &&
- (ELEM(t->around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEDIAN, V3D_AROUND_ACTIVE)) &&
- (ELEM(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL))) {
- t->around = V3D_AROUND_LOCAL_ORIGINS;
- }
-}
-
-/* when transforming islands */
-struct TransIslandData {
- float co[3];
- float axismtx[3][3];
-};
-
-/* local function prototype - for Object/Bone Constraints */
-static bool constraints_list_needinv(TransInfo *t, ListBase *list);
-
-/* ************************** Functions *************************** */
-
-static int trans_data_compare_dist(const void *a, const void *b)
-{
- const TransData *td_a = (const TransData *)a;
- const TransData *td_b = (const TransData *)b;
-
- if (td_a->dist < td_b->dist) {
- return -1;
- }
- else if (td_a->dist > td_b->dist) {
- return 1;
- }
- else {
- return 0;
- }
-}
-
-static int trans_data_compare_rdist(const void *a, const void *b)
-{
- const TransData *td_a = (const TransData *)a;
- const TransData *td_b = (const TransData *)b;
-
- if (td_a->rdist < td_b->rdist) {
- return -1;
- }
- else if (td_a->rdist > td_b->rdist) {
- return 1;
- }
- else {
- return 0;
- }
-}
-
-static void sort_trans_data_dist_container(const TransInfo *t, TransDataContainer *tc)
-{
- TransData *start = tc->data;
- int i;
-
- for (i = 0; i < tc->data_len && start->flag & TD_SELECTED; i++) {
- start++;
- }
-
- if (i < tc->data_len) {
- if (t->flag & T_PROP_CONNECTED) {
- qsort(start, tc->data_len - i, sizeof(TransData), trans_data_compare_dist);
- }
- else {
- qsort(start, tc->data_len - i, sizeof(TransData), trans_data_compare_rdist);
- }
- }
-}
-void sort_trans_data_dist(TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- sort_trans_data_dist_container(t, tc);
- }
-}
-
-/**
- * Make #TD_SELECTED first in the array.
- */
-static void sort_trans_data_selected_first_container(TransDataContainer *tc)
-{
- TransData *sel, *unsel;
- TransData temp;
- unsel = tc->data;
- sel = tc->data;
- sel += tc->data_len - 1;
- while (sel > unsel) {
- while (unsel->flag & TD_SELECTED) {
- unsel++;
- if (unsel == sel) {
- return;
- }
- }
- while (!(sel->flag & TD_SELECTED)) {
- sel--;
- if (unsel == sel) {
- return;
- }
- }
- temp = *unsel;
- *unsel = *sel;
- *sel = temp;
- sel--;
- unsel++;
- }
-}
-static void sort_trans_data_selected_first(TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- sort_trans_data_selected_first_container(tc);
- }
-}
-
-/**
- * Distance calculated from not-selected vertex to nearest selected vertex.
- */
-static void set_prop_dist(TransInfo *t, const bool with_dist)
-{
- int a;
-
- float _proj_vec[3];
- const float *proj_vec = NULL;
-
- /* support for face-islands */
- const bool use_island = transdata_check_local_islands(t, t->around);
-
- if (t->flag & T_PROP_PROJECTED) {
- if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) {
- RegionView3D *rv3d = t->ar->regiondata;
- normalize_v3_v3(_proj_vec, rv3d->viewinv[2]);
- proj_vec = _proj_vec;
- }
- }
-
- /* Count number of selected. */
- int td_table_len = 0;
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (a = 0; a < tc->data_len; a++, td++) {
- if (td->flag & TD_SELECTED) {
- td_table_len++;
- }
- else {
- /* By definition transform-data has selected items in beginning. */
- break;
- }
- }
- }
-
- /* Pointers to selected's #TransData.
- * Used to find #TransData from the index returned by #BLI_kdtree_find_nearest. */
- TransData **td_table = MEM_mallocN(sizeof(*td_table) * td_table_len, __func__);
-
- /* Create and fill kd-tree of selected's positions - in global or proj_vec space. */
- KDTree_3d *td_tree = BLI_kdtree_3d_new(td_table_len);
-
- int td_table_index = 0;
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (a = 0; a < tc->data_len; a++, td++) {
- if (td->flag & TD_SELECTED) {
- /* Initialize, it was mallocced. */
- float vec[3];
- td->rdist = 0.0f;
-
- if (use_island) {
- if (tc->use_local_mat) {
- mul_v3_m4v3(vec, tc->mat, td->iloc);
- }
- else {
- mul_v3_m3v3(vec, td->mtx, td->iloc);
- }
- }
- else {
- if (tc->use_local_mat) {
- mul_v3_m4v3(vec, tc->mat, td->center);
- }
- else {
- mul_v3_m3v3(vec, td->mtx, td->center);
- }
- }
-
- if (proj_vec) {
- float vec_p[3];
- project_v3_v3v3(vec_p, vec, proj_vec);
- sub_v3_v3(vec, vec_p);
- }
-
- BLI_kdtree_3d_insert(td_tree, td_table_index, vec);
- td_table[td_table_index++] = td;
- }
- else {
- /* By definition transform-data has selected items in beginning. */
- break;
- }
- }
- }
- BLI_assert(td_table_index == td_table_len);
-
- BLI_kdtree_3d_balance(td_tree);
-
- /* For each non-selected vertex, find distance to the nearest selected vertex. */
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (a = 0; a < tc->data_len; a++, td++) {
- if ((td->flag & TD_SELECTED) == 0) {
- float vec[3];
-
- if (use_island) {
- if (tc->use_local_mat) {
- mul_v3_m4v3(vec, tc->mat, td->iloc);
- }
- else {
- mul_v3_m3v3(vec, td->mtx, td->iloc);
- }
- }
- else {
- if (tc->use_local_mat) {
- mul_v3_m4v3(vec, tc->mat, td->center);
- }
- else {
- mul_v3_m3v3(vec, td->mtx, td->center);
- }
- }
-
- if (proj_vec) {
- float vec_p[3];
- project_v3_v3v3(vec_p, vec, proj_vec);
- sub_v3_v3(vec, vec_p);
- }
-
- KDTreeNearest_3d nearest;
- const int td_index = BLI_kdtree_3d_find_nearest(td_tree, vec, &nearest);
-
- td->rdist = -1.0f;
- if (td_index != -1) {
- td->rdist = nearest.dist;
- if (use_island) {
- copy_v3_v3(td->center, td_table[td_index]->center);
- copy_m3_m3(td->axismtx, td_table[td_index]->axismtx);
- }
- }
-
- if (with_dist) {
- td->dist = td->rdist;
- }
- }
- }
- }
-
- BLI_kdtree_3d_free(td_tree);
- MEM_freeN(td_table);
-}
-
-/* ************************** CONVERSIONS ************************* */
-
-/* ********************* texture space ********* */
-
-static void createTransTexspace(TransInfo *t)
-{
- ViewLayer *view_layer = t->view_layer;
- TransData *td;
- Object *ob;
- ID *id;
- short *texflag;
-
- ob = OBACT(view_layer);
-
- if (ob == NULL) { // Shouldn't logically happen, but still...
- return;
- }
-
- id = ob->data;
- if (id == NULL || !ELEM(GS(id->name), ID_ME, ID_CU, ID_MB)) {
- BKE_report(t->reports, RPT_ERROR, "Unsupported object type for text-space transform");
- return;
- }
-
- if (BKE_object_obdata_is_libdata(ob)) {
- BKE_report(t->reports, RPT_ERROR, "Linked data can't text-space transform");
- return;
- }
-
- {
- BLI_assert(t->data_container_len == 1);
- TransDataContainer *tc = t->data_container;
- tc->data_len = 1;
- td = tc->data = MEM_callocN(sizeof(TransData), "TransTexspace");
- td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
- }
-
- td->flag = TD_SELECTED;
- copy_v3_v3(td->center, ob->obmat[3]);
- td->ob = ob;
-
- copy_m3_m4(td->mtx, ob->obmat);
- copy_m3_m4(td->axismtx, ob->obmat);
- normalize_m3(td->axismtx);
- pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
-
- if (BKE_object_obdata_texspace_get(ob, &texflag, &td->loc, &td->ext->size, &td->ext->rot)) {
- ob->dtx |= OB_TEXSPACE;
- *texflag &= ~ME_AUTOSPACE;
- }
-
- copy_v3_v3(td->iloc, td->loc);
- copy_v3_v3(td->ext->irot, td->ext->rot);
- copy_v3_v3(td->ext->isize, td->ext->size);
-}
-
-/* -------------------------------------------------------------------- */
-/** \name Cursor Transform Creation
- *
- * Instead of transforming the selection, move the 2D/3D cursor.
- *
- * \{ */
-
-static void createTransCursor_image(TransInfo *t)
-{
- TransData *td;
- SpaceImage *sima = t->sa->spacedata.first;
- float *cursor_location = sima->cursor;
-
- {
- BLI_assert(t->data_container_len == 1);
- TransDataContainer *tc = t->data_container;
- tc->data_len = 1;
- td = tc->data = MEM_callocN(sizeof(TransData), "TransTexspace");
- td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
- }
-
- td->flag = TD_SELECTED;
- copy_v3_v3(td->center, cursor_location);
- td->ob = NULL;
-
- unit_m3(td->mtx);
- unit_m3(td->axismtx);
- pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
-
- td->loc = cursor_location;
- copy_v3_v3(td->iloc, cursor_location);
-}
-
-static void createTransCursor_view3d(TransInfo *t)
-{
- TransData *td;
-
- Scene *scene = t->scene;
- if (ID_IS_LINKED(scene)) {
- BKE_report(t->reports, RPT_ERROR, "Linked data can't text-space transform");
- return;
- }
-
- View3DCursor *cursor = &scene->cursor;
- {
- BLI_assert(t->data_container_len == 1);
- TransDataContainer *tc = t->data_container;
- tc->data_len = 1;
- td = tc->data = MEM_callocN(sizeof(TransData), "TransTexspace");
- td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
- }
-
- td->flag = TD_SELECTED;
- copy_v3_v3(td->center, cursor->location);
- td->ob = NULL;
-
- unit_m3(td->mtx);
- BKE_scene_cursor_rot_to_mat3(cursor, td->axismtx);
- normalize_m3(td->axismtx);
- pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
-
- td->loc = cursor->location;
- copy_v3_v3(td->iloc, cursor->location);
-
- if (cursor->rotation_mode > 0) {
- td->ext->rot = cursor->rotation_euler;
- td->ext->rotAxis = NULL;
- td->ext->rotAngle = NULL;
- td->ext->quat = NULL;
-
- copy_v3_v3(td->ext->irot, cursor->rotation_euler);
- }
- else if (cursor->rotation_mode == ROT_MODE_AXISANGLE) {
- td->ext->rot = NULL;
- td->ext->rotAxis = cursor->rotation_axis;
- td->ext->rotAngle = &cursor->rotation_angle;
- td->ext->quat = NULL;
-
- td->ext->irotAngle = cursor->rotation_angle;
- copy_v3_v3(td->ext->irotAxis, cursor->rotation_axis);
- }
- else {
- td->ext->rot = NULL;
- td->ext->rotAxis = NULL;
- td->ext->rotAngle = NULL;
- td->ext->quat = cursor->rotation_quaternion;
-
- copy_qt_qt(td->ext->iquat, cursor->rotation_quaternion);
- }
- td->ext->rotOrder = cursor->rotation_mode;
-}
-
-/** \} */
-
-/* ********************* edge (for crease) ***** */
-
-static void createTransEdge(TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
-
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- TransData *td = NULL;
- BMEdge *eed;
- BMIter iter;
- float mtx[3][3], smtx[3][3];
- int count = 0, countsel = 0;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
- int cd_edge_float_offset;
-
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- countsel++;
- }
- if (is_prop_edit) {
- count++;
- }
- }
- }
-
- if (countsel == 0) {
- tc->data_len = 0;
- continue;
- }
-
- if (is_prop_edit) {
- tc->data_len = count;
- }
- else {
- tc->data_len = countsel;
- }
-
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransCrease");
-
- copy_m3_m4(mtx, tc->obedit->obmat);
- pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
-
- /* create data we need */
- if (t->mode == TFM_BWEIGHT) {
- BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_BWEIGHT);
- cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
- }
- else { // if (t->mode == TFM_CREASE) {
- BLI_assert(t->mode == TFM_CREASE);
- BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_CREASE);
- cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
- }
-
- BLI_assert(cd_edge_float_offset != -1);
-
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) &&
- (BM_elem_flag_test(eed, BM_ELEM_SELECT) || is_prop_edit)) {
- float *fl_ptr;
- /* need to set center for center calculations */
- mid_v3_v3v3(td->center, eed->v1->co, eed->v2->co);
-
- td->loc = NULL;
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- td->flag = TD_SELECTED;
- }
- else {
- td->flag = 0;
- }
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
-
- td->ext = NULL;
-
- fl_ptr = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_float_offset);
- td->val = fl_ptr;
- td->ival = *fl_ptr;
-
- td++;
- }
- }
- }
-}
-
-/* ********************* pose mode ************* */
-
-static bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan)
-{
- bConstraint *con = pchan->constraints.first;
-
- for (; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce != 0.0f)) {
- bKinematicConstraint *data = con->data;
-
- if (data->tar == NULL) {
- return data;
- }
- if (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0) {
- return data;
- }
- }
- }
- return NULL;
-}
-
-static short apply_targetless_ik(Object *ob)
-{
- bPoseChannel *pchan, *parchan, *chanlist[256];
- bKinematicConstraint *data;
- int segcount, apply = 0;
-
- /* now we got a difficult situation... we have to find the
- * target-less IK pchans, and apply transformation to the all
- * pchans that were in the chain */
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- data = has_targetless_ik(pchan);
- if (data && (data->flag & CONSTRAINT_IK_AUTO)) {
-
- /* fill the array with the bones of the chain (armature.c does same, keep it synced) */
- segcount = 0;
-
- /* exclude tip from chain? */
- if (!(data->flag & CONSTRAINT_IK_TIP)) {
- parchan = pchan->parent;
- }
- else {
- parchan = pchan;
- }
-
- /* Find the chain's root & count the segments needed */
- for (; parchan; parchan = parchan->parent) {
- chanlist[segcount] = parchan;
- segcount++;
-
- if (segcount == data->rootbone || segcount > 255) {
- break; // 255 is weak
- }
- }
- for (; segcount; segcount--) {
- Bone *bone;
- float rmat[4][4] /*, tmat[4][4], imat[4][4]*/;
-
- /* pose_mat(b) = pose_mat(b-1) * offs_bone * channel * constraint * IK */
- /* we put in channel the entire result of rmat = (channel * constraint * IK) */
- /* pose_mat(b) = pose_mat(b-1) * offs_bone * rmat */
- /* rmat = pose_mat(b) * inv(pose_mat(b-1) * offs_bone ) */
-
- parchan = chanlist[segcount - 1];
- bone = parchan->bone;
- bone->flag |= BONE_TRANSFORM; /* ensures it gets an auto key inserted */
-
- BKE_armature_mat_pose_to_bone(parchan, parchan->pose_mat, rmat);
-
- /* apply and decompose, doesn't work for constraints or non-uniform scale well */
- {
- float rmat3[3][3], qrmat[3][3], imat3[3][3], smat[3][3];
- copy_m3_m4(rmat3, rmat);
-
- /* rotation */
- /* [#22409] is partially caused by this, as slight numeric error introduced during
- * the solving process leads to locked-axis values changing. However, we cannot modify
- * the values here, or else there are huge discrepancies between IK-solver (interactive)
- * and applied poses. */
- BKE_pchan_mat3_to_rot(parchan, rmat3, false);
-
- /* for size, remove rotation */
- /* causes problems with some constraints (so apply only if needed) */
- if (data->flag & CONSTRAINT_IK_STRETCH) {
- BKE_pchan_rot_to_mat3(parchan, qrmat);
- invert_m3_m3(imat3, qrmat);
- mul_m3_m3m3(smat, rmat3, imat3);
- mat3_to_size(parchan->size, smat);
- }
-
- /* causes problems with some constraints (e.g. childof), so disable this */
- /* as it is IK shouldn't affect location directly */
- /* copy_v3_v3(parchan->loc, rmat[3]); */
- }
- }
-
- apply = 1;
- data->flag &= ~CONSTRAINT_IK_AUTO;
- }
- }
-
- return apply;
-}
-
-static void add_pose_transdata(
- TransInfo *t, bPoseChannel *pchan, Object *ob, TransDataContainer *tc, TransData *td)
-{
- Bone *bone = pchan->bone;
- float pmat[3][3], omat[3][3];
- float cmat[3][3], tmat[3][3];
- float vec[3];
-
- copy_v3_v3(vec, pchan->pose_mat[3]);
- copy_v3_v3(td->center, vec);
-
- td->ob = ob;
- td->flag = TD_SELECTED;
- if (bone->flag & BONE_HINGE_CHILD_TRANSFORM) {
- td->flag |= TD_NOCENTER;
- }
-
- if (bone->flag & BONE_TRANSFORM_CHILD) {
- td->flag |= TD_NOCENTER;
- td->flag |= TD_NO_LOC;
- }
-
- td->protectflag = pchan->protectflag;
-
- td->loc = pchan->loc;
- copy_v3_v3(td->iloc, pchan->loc);
-
- td->ext->size = pchan->size;
- copy_v3_v3(td->ext->isize, pchan->size);
-
- if (pchan->rotmode > 0) {
- td->ext->rot = pchan->eul;
- td->ext->rotAxis = NULL;
- td->ext->rotAngle = NULL;
- td->ext->quat = NULL;
-
- copy_v3_v3(td->ext->irot, pchan->eul);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- td->ext->rot = NULL;
- td->ext->rotAxis = pchan->rotAxis;
- td->ext->rotAngle = &pchan->rotAngle;
- td->ext->quat = NULL;
-
- td->ext->irotAngle = pchan->rotAngle;
- copy_v3_v3(td->ext->irotAxis, pchan->rotAxis);
- }
- else {
- td->ext->rot = NULL;
- td->ext->rotAxis = NULL;
- td->ext->rotAngle = NULL;
- td->ext->quat = pchan->quat;
-
- copy_qt_qt(td->ext->iquat, pchan->quat);
- }
- td->ext->rotOrder = pchan->rotmode;
-
- /* proper way to get parent transform + own transform + constraints transform */
- copy_m3_m4(omat, ob->obmat);
-
- /* New code, using "generic" BKE_bone_parent_transform_calc_from_pchan(). */
- {
- BoneParentTransform bpt;
- float rpmat[3][3];
-
- BKE_bone_parent_transform_calc_from_pchan(pchan, &bpt);
- if (t->mode == TFM_TRANSLATION) {
- copy_m3_m4(pmat, bpt.loc_mat);
- }
- else {
- copy_m3_m4(pmat, bpt.rotscale_mat);
- }
-
- /* Grrr! Exceptional case: When translating pose bones that are either Hinge or NoLocal,
- * and want align snapping, we just need both loc_mat and rotscale_mat.
- * So simply always store rotscale mat in td->ext, and always use it to apply rotations...
- * Ugly to need such hacks! :/ */
- copy_m3_m4(rpmat, bpt.rotscale_mat);
-
- if (constraints_list_needinv(t, &pchan->constraints)) {
- copy_m3_m4(tmat, pchan->constinv);
- invert_m3_m3(cmat, tmat);
- mul_m3_series(td->mtx, cmat, omat, pmat);
- mul_m3_series(td->ext->r_mtx, cmat, omat, rpmat);
- }
- else {
- mul_m3_series(td->mtx, omat, pmat);
- mul_m3_series(td->ext->r_mtx, omat, rpmat);
- }
- invert_m3_m3(td->ext->r_smtx, td->ext->r_mtx);
- }
-
- pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
-
- /* exceptional case: rotate the pose bone which also applies transformation
- * when a parentless bone has BONE_NO_LOCAL_LOCATION [] */
- if (!ELEM(t->mode, TFM_TRANSLATION, TFM_RESIZE) &&
- (pchan->bone->flag & BONE_NO_LOCAL_LOCATION)) {
- if (pchan->parent) {
- /* same as td->smtx but without pchan->bone->bone_mat */
- td->flag |= TD_PBONE_LOCAL_MTX_C;
- mul_m3_m3m3(td->ext->l_smtx, pchan->bone->bone_mat, td->smtx);
- }
- else {
- td->flag |= TD_PBONE_LOCAL_MTX_P;
- }
- }
-
- /* for axismat we use bone's own transform */
- copy_m3_m4(pmat, pchan->pose_mat);
- mul_m3_m3m3(td->axismtx, omat, pmat);
- normalize_m3(td->axismtx);
-
- if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
- bArmature *arm = tc->poseobj->data;
-
- if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
- td->loc = NULL;
- td->val = &bone->dist;
- td->ival = bone->dist;
- }
- else {
- // abusive storage of scale in the loc pointer :)
- td->loc = &bone->xwidth;
- copy_v3_v3(td->iloc, td->loc);
- td->val = NULL;
- }
- }
-
- /* in this case we can do target-less IK grabbing */
- if (t->mode == TFM_TRANSLATION) {
- bKinematicConstraint *data = has_targetless_ik(pchan);
- if (data) {
- if (data->flag & CONSTRAINT_IK_TIP) {
- copy_v3_v3(data->grabtarget, pchan->pose_tail);
- }
- else {
- copy_v3_v3(data->grabtarget, pchan->pose_head);
- }
- td->loc = data->grabtarget;
- copy_v3_v3(td->iloc, td->loc);
- data->flag |= CONSTRAINT_IK_AUTO;
-
- /* only object matrix correction */
- copy_m3_m3(td->mtx, omat);
- pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
- }
- }
-
- /* store reference to first constraint */
- td->con = pchan->constraints.first;
-}
-
-static void bone_children_clear_transflag(int mode, short around, ListBase *lb)
-{
- Bone *bone = lb->first;
-
- for (; bone; bone = bone->next) {
- if ((bone->flag & BONE_HINGE) && (bone->flag & BONE_CONNECTED)) {
- bone->flag |= BONE_HINGE_CHILD_TRANSFORM;
- }
- else if ((bone->flag & BONE_TRANSFORM) && (mode == TFM_ROTATION || mode == TFM_TRACKBALL) &&
- (around == V3D_AROUND_LOCAL_ORIGINS)) {
- bone->flag |= BONE_TRANSFORM_CHILD;
- }
- else {
- bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
- }
-
- bone_children_clear_transflag(mode, around, &bone->childbase);
- }
-}
-
-/* sets transform flags in the bones
- * returns total number of bones with BONE_TRANSFORM */
-int count_set_pose_transflags(Object *ob,
- const int mode,
- const short around,
- bool has_translate_rotate[2])
-{
- bArmature *arm = ob->data;
- bPoseChannel *pchan;
- Bone *bone;
- int total = 0;
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- bone = pchan->bone;
- if (PBONE_VISIBLE(arm, bone)) {
- if ((bone->flag & BONE_SELECTED)) {
- bone->flag |= BONE_TRANSFORM;
- }
- else {
- bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
- }
-
- bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM;
- bone->flag &= ~BONE_TRANSFORM_CHILD;
- }
- else {
- bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
- }
- }
-
- /* make sure no bone can be transformed when a parent is transformed */
- /* since pchans are depsgraph sorted, the parents are in beginning of list */
- if (!ELEM(mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- bone = pchan->bone;
- if (bone->flag & BONE_TRANSFORM) {
- bone_children_clear_transflag(mode, around, &bone->childbase);
- }
- }
- }
- /* now count, and check if we have autoIK or have to switch from translate to rotate */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- bone = pchan->bone;
- if (bone->flag & BONE_TRANSFORM) {
- total++;
-
- if (has_translate_rotate != NULL) {
- if (has_targetless_ik(pchan) == NULL) {
- if (pchan->parent && (pchan->bone->flag & BONE_CONNECTED)) {
- if (pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM) {
- has_translate_rotate[0] = true;
- }
- }
- else {
- if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC) {
- has_translate_rotate[0] = true;
- }
- }
- if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT) {
- has_translate_rotate[1] = true;
- }
- }
- else {
- has_translate_rotate[0] = true;
- }
- }
- }
- }
-
- return total;
-}
-
-/* -------- Auto-IK ---------- */
-
-/* adjust pose-channel's auto-ik chainlen */
-static bool pchan_autoik_adjust(bPoseChannel *pchan, short chainlen)
-{
- bConstraint *con;
- bool changed = false;
-
- /* don't bother to search if no valid constraints */
- if ((pchan->constflag & (PCHAN_HAS_IK | PCHAN_HAS_TARGET)) == 0) {
- return changed;
- }
-
- /* check if pchan has ik-constraint */
- for (con = pchan->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce != 0.0f)) {
- bKinematicConstraint *data = con->data;
-
- /* only accept if a temporary one (for auto-ik) */
- if (data->flag & CONSTRAINT_IK_TEMP) {
- /* chainlen is new chainlen, but is limited by maximum chainlen */
- const int old_rootbone = data->rootbone;
- if ((chainlen == 0) || (chainlen > data->max_rootbone)) {
- data->rootbone = data->max_rootbone;
- }
- else {
- data->rootbone = chainlen;
- }
- changed |= (data->rootbone != old_rootbone);
- }
- }
- }
-
- return changed;
-}
-
-/* change the chain-length of auto-ik */
-void transform_autoik_update(TransInfo *t, short mode)
-{
- Main *bmain = CTX_data_main(t->context);
-
- short *chainlen = &t->settings->autoik_chainlen;
- bPoseChannel *pchan;
-
- /* mode determines what change to apply to chainlen */
- if (mode == 1) {
- /* mode=1 is from WHEELMOUSEDOWN... increases len */
- (*chainlen)++;
- }
- else if (mode == -1) {
- /* mode==-1 is from WHEELMOUSEUP... decreases len */
- if (*chainlen > 0) {
- (*chainlen)--;
- }
- else {
- /* IK length did not change, skip updates. */
- return;
- }
- }
-
- /* apply to all pose-channels */
- bool changed = false;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
-
- /* sanity checks (don't assume t->poseobj is set, or that it is an armature) */
- if (ELEM(NULL, tc->poseobj, tc->poseobj->pose)) {
- continue;
- }
-
- for (pchan = tc->poseobj->pose->chanbase.first; pchan; pchan = pchan->next) {
- changed |= pchan_autoik_adjust(pchan, *chainlen);
- }
- }
-
- if (changed) {
- /* TODO(sergey): Consider doing partial update only. */
- DEG_relations_tag_update(bmain);
- }
-}
-
-/* frees temporal IKs */
-static void pose_grab_with_ik_clear(Main *bmain, Object *ob)
-{
- bKinematicConstraint *data;
- bPoseChannel *pchan;
- bConstraint *con, *next;
- bool relations_changed = false;
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- /* clear all temporary lock flags */
- pchan->ikflag &= ~(BONE_IK_NO_XDOF_TEMP | BONE_IK_NO_YDOF_TEMP | BONE_IK_NO_ZDOF_TEMP);
-
- pchan->constflag &= ~(PCHAN_HAS_IK | PCHAN_HAS_TARGET);
-
- /* remove all temporary IK-constraints added */
- for (con = pchan->constraints.first; con; con = next) {
- next = con->next;
- if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
- data = con->data;
- if (data->flag & CONSTRAINT_IK_TEMP) {
- relations_changed = true;
-
- /* iTaSC needs clear for removed constraints */
- BIK_clear_data(ob->pose);
-
- BLI_remlink(&pchan->constraints, con);
- MEM_freeN(con->data);
- MEM_freeN(con);
- continue;
- }
- pchan->constflag |= PCHAN_HAS_IK;
- if (data->tar == NULL || (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0)) {
- pchan->constflag |= PCHAN_HAS_TARGET;
- }
- }
- }
- }
-
- if (relations_changed) {
- /* TODO(sergey): Consider doing partial update only. */
- DEG_relations_tag_update(bmain);
- }
-}
-
-/* adds the IK to pchan - returns if added */
-static short pose_grab_with_ik_add(bPoseChannel *pchan)
-{
- bKinematicConstraint *targetless = NULL;
- bKinematicConstraint *data;
- bConstraint *con;
-
- /* Sanity check */
- if (pchan == NULL) {
- return 0;
- }
-
- /* Rule: not if there's already an IK on this channel */
- for (con = pchan->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
- data = con->data;
-
- if (data->tar == NULL || (data->tar->type == OB_ARMATURE && data->subtarget[0] == '\0')) {
- /* make reference to constraint to base things off later
- * (if it's the last targetless constraint encountered) */
- targetless = (bKinematicConstraint *)con->data;
-
- /* but, if this is a targetless IK, we make it auto anyway (for the children loop) */
- if (con->enforce != 0.0f) {
- data->flag |= CONSTRAINT_IK_AUTO;
-
- /* if no chain length has been specified,
- * just make things obey standard rotation locks too */
- if (data->rootbone == 0) {
- for (; pchan; pchan = pchan->parent) {
- /* here, we set ik-settings for bone from pchan->protectflag */
- // XXX: careful with quats/axis-angle rotations where we're locking 4d components
- if (pchan->protectflag & OB_LOCK_ROTX) {
- pchan->ikflag |= BONE_IK_NO_XDOF_TEMP;
- }
- if (pchan->protectflag & OB_LOCK_ROTY) {
- pchan->ikflag |= BONE_IK_NO_YDOF_TEMP;
- }
- if (pchan->protectflag & OB_LOCK_ROTZ) {
- pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP;
- }
- }
- }
-
- return 0;
- }
- }
-
- if ((con->flag & CONSTRAINT_DISABLE) == 0 && (con->enforce != 0.0f)) {
- return 0;
- }
- }
- }
-
- con = BKE_constraint_add_for_pose(NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC);
-
- /* for draw, but also for detecting while pose solving */
- pchan->constflag |= (PCHAN_HAS_IK | PCHAN_HAS_TARGET);
-
- data = con->data;
- if (targetless) {
- /* if exists, use values from last targetless (but disabled) IK-constraint as base */
- *data = *targetless;
- }
- else {
- data->flag = CONSTRAINT_IK_TIP;
- }
- data->flag |= CONSTRAINT_IK_TEMP | CONSTRAINT_IK_AUTO | CONSTRAINT_IK_POS;
- copy_v3_v3(data->grabtarget, pchan->pose_tail);
-
- /* watch-it! has to be 0 here, since we're still on the
- * same bone for the first time through the loop T25885. */
- data->rootbone = 0;
-
- /* we only include bones that are part of a continual connected chain */
- do {
- /* here, we set ik-settings for bone from pchan->protectflag */
- // XXX: careful with quats/axis-angle rotations where we're locking 4d components
- if (pchan->protectflag & OB_LOCK_ROTX) {
- pchan->ikflag |= BONE_IK_NO_XDOF_TEMP;
- }
- if (pchan->protectflag & OB_LOCK_ROTY) {
- pchan->ikflag |= BONE_IK_NO_YDOF_TEMP;
- }
- if (pchan->protectflag & OB_LOCK_ROTZ) {
- pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP;
- }
-
- /* now we count this pchan as being included */
- data->rootbone++;
-
- /* continue to parent, but only if we're connected to it */
- if (pchan->bone->flag & BONE_CONNECTED) {
- pchan = pchan->parent;
- }
- else {
- pchan = NULL;
- }
- } while (pchan);
-
- /* make a copy of maximum chain-length */
- data->max_rootbone = data->rootbone;
-
- return 1;
-}
-
-/* bone is a candidate to get IK, but we don't do it if it has children connected */
-static short pose_grab_with_ik_children(bPose *pose, Bone *bone)
-{
- Bone *bonec;
- short wentdeeper = 0, added = 0;
-
- /* go deeper if children & children are connected */
- for (bonec = bone->childbase.first; bonec; bonec = bonec->next) {
- if (bonec->flag & BONE_CONNECTED) {
- wentdeeper = 1;
- added += pose_grab_with_ik_children(pose, bonec);
- }
- }
- if (wentdeeper == 0) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(pose, bone->name);
- if (pchan) {
- added += pose_grab_with_ik_add(pchan);
- }
- }
-
- return added;
-}
-
-/* main call which adds temporal IK chains */
-static short pose_grab_with_ik(Main *bmain, Object *ob)
-{
- bArmature *arm;
- bPoseChannel *pchan, *parent;
- Bone *bonec;
- short tot_ik = 0;
-
- if ((ob == NULL) || (ob->pose == NULL) || (ob->mode & OB_MODE_POSE) == 0) {
- return 0;
- }
-
- arm = ob->data;
-
- /* Rule: allow multiple Bones
- * (but they must be selected, and only one ik-solver per chain should get added) */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->layer & arm->layer) {
- if (pchan->bone->flag & BONE_SELECTED) {
- /* Rule: no IK for solitatry (unconnected) bones */
- for (bonec = pchan->bone->childbase.first; bonec; bonec = bonec->next) {
- if (bonec->flag & BONE_CONNECTED) {
- break;
- }
- }
- if ((pchan->bone->flag & BONE_CONNECTED) == 0 && (bonec == NULL)) {
- continue;
- }
-
- /* rule: if selected Bone is not a root bone, it gets a temporal IK */
- if (pchan->parent) {
- /* only adds if there's no IK yet (and no parent bone was selected) */
- for (parent = pchan->parent; parent; parent = parent->parent) {
- if (parent->bone->flag & BONE_SELECTED) {
- break;
- }
- }
- if (parent == NULL) {
- tot_ik += pose_grab_with_ik_add(pchan);
- }
- }
- else {
- /* rule: go over the children and add IK to the tips */
- tot_ik += pose_grab_with_ik_children(ob->pose, pchan->bone);
- }
- }
- }
- }
-
- /* iTaSC needs clear for new IK constraints */
- if (tot_ik) {
- BIK_clear_data(ob->pose);
- /* TODO(sergey): Consider doing partial update only. */
- DEG_relations_tag_update(bmain);
- }
-
- return (tot_ik) ? 1 : 0;
-}
-
-static void pose_mirror_info_init(PoseInitData_Mirror *pid,
- bPoseChannel *pchan,
- bPoseChannel *pchan_orig,
- bool is_mirror_relative)
-{
- pid->pchan = pchan;
- copy_v3_v3(pid->orig.loc, pchan->loc);
- copy_v3_v3(pid->orig.size, pchan->size);
- pid->orig.curve_in_x = pchan->curve_in_x;
- pid->orig.curve_out_x = pchan->curve_out_x;
- pid->orig.roll1 = pchan->roll1;
- pid->orig.roll2 = pchan->roll2;
-
- if (pchan->rotmode > 0) {
- copy_v3_v3(pid->orig.eul, pchan->eul);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- copy_v3_v3(pid->orig.axis_angle, pchan->rotAxis);
- pid->orig.axis_angle[3] = pchan->rotAngle;
- }
- else {
- copy_qt_qt(pid->orig.quat, pchan->quat);
- }
-
- if (is_mirror_relative) {
- float pchan_mtx[4][4];
- float pchan_mtx_mirror[4][4];
-
- float flip_mtx[4][4];
- unit_m4(flip_mtx);
- flip_mtx[0][0] = -1;
-
- BKE_pchan_to_mat4(pchan_orig, pchan_mtx_mirror);
- BKE_pchan_to_mat4(pchan, pchan_mtx);
-
- mul_m4_m4m4(pchan_mtx_mirror, pchan_mtx_mirror, flip_mtx);
- mul_m4_m4m4(pchan_mtx_mirror, flip_mtx, pchan_mtx_mirror);
-
- invert_m4(pchan_mtx_mirror);
- mul_m4_m4m4(pid->offset_mtx, pchan_mtx, pchan_mtx_mirror);
- }
- else {
- unit_m4(pid->offset_mtx);
- }
-}
-
-static void pose_mirror_info_restore(const PoseInitData_Mirror *pid)
-{
- bPoseChannel *pchan = pid->pchan;
- copy_v3_v3(pchan->loc, pid->orig.loc);
- copy_v3_v3(pchan->size, pid->orig.size);
- pchan->curve_in_x = pid->orig.curve_in_x;
- pchan->curve_out_x = pid->orig.curve_out_x;
- pchan->roll1 = pid->orig.roll1;
- pchan->roll2 = pid->orig.roll2;
-
- if (pchan->rotmode > 0) {
- copy_v3_v3(pchan->eul, pid->orig.eul);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- copy_v3_v3(pchan->rotAxis, pid->orig.axis_angle);
- pchan->rotAngle = pid->orig.axis_angle[3];
- }
- else {
- copy_qt_qt(pchan->quat, pid->orig.quat);
- }
-}
-
-/**
- * When objects array is NULL, use 't->data_container' as is.
- */
-static void createTransPose(TransInfo *t)
-{
- Main *bmain = CTX_data_main(t->context);
-
- t->data_len_all = 0;
-
- bool has_translate_rotate_buf[2] = {false, false};
- bool *has_translate_rotate = (t->mode == TFM_TRANSLATION) ? has_translate_rotate_buf : NULL;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- Object *ob = tc->poseobj;
- bPose *pose = ob->pose;
-
- bArmature *arm;
-
- /* check validity of state */
- arm = BKE_armature_from_object(tc->poseobj);
- if ((arm == NULL) || (pose == NULL)) {
- continue;
- }
-
- const bool mirror = ((pose->flag & POSE_MIRROR_EDIT) != 0);
-
- /* set flags and count total */
- tc->data_len = count_set_pose_transflags(ob, t->mode, t->around, has_translate_rotate);
- if (tc->data_len == 0) {
- continue;
- }
-
- if (arm->flag & ARM_RESTPOS) {
- if (ELEM(t->mode, TFM_DUMMY, TFM_BONESIZE) == 0) {
- BKE_report(t->reports, RPT_ERROR, "Cannot change Pose when 'Rest Position' is enabled");
- tc->data_len = 0;
- continue;
- }
- }
-
- /* do we need to add temporal IK chains? */
- if ((pose->flag & POSE_AUTO_IK) && t->mode == TFM_TRANSLATION) {
- if (pose_grab_with_ik(bmain, ob)) {
- t->flag |= T_AUTOIK;
- has_translate_rotate[0] = true;
- }
- }
-
- if (mirror) {
- int total_mirrored = 0;
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if ((pchan->bone->flag & BONE_TRANSFORM) &&
- BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) {
- total_mirrored++;
- }
- }
-
- PoseInitData_Mirror *pid = MEM_mallocN((total_mirrored + 1) * sizeof(PoseInitData_Mirror),
- "PoseInitData_Mirror");
-
- /* Trick to terminate iteration. */
- pid[total_mirrored].pchan = NULL;
-
- tc->custom.type.data = pid;
- tc->custom.type.use_free = true;
- }
- }
-
- /* if there are no translatable bones, do rotation */
- if ((t->mode == TFM_TRANSLATION) && !has_translate_rotate[0]) {
- if (has_translate_rotate[1]) {
- t->mode = TFM_ROTATION;
- }
- else {
- t->mode = TFM_RESIZE;
- }
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- if (tc->data_len == 0) {
- continue;
- }
- Object *ob = tc->poseobj;
- TransData *td;
- TransDataExtension *tdx;
- int i;
-
- PoseInitData_Mirror *pid = tc->custom.type.data;
- int pid_index = 0;
- bPose *pose = ob->pose;
-
- if (pose == NULL) {
- continue;
- }
-
- const bool mirror = ((pose->flag & POSE_MIRROR_EDIT) != 0);
- const bool is_mirror_relative = ((pose->flag & POSE_MIRROR_RELATIVE) != 0);
-
- tc->poseobj = ob; /* we also allow non-active objects to be transformed, in weightpaint */
-
- /* init trans data */
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransPoseBone");
- tdx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension),
- "TransPoseBoneExt");
- for (i = 0; i < tc->data_len; i++, td++, tdx++) {
- td->ext = tdx;
- td->val = NULL;
- }
-
- /* use pose channels to fill trans data */
- td = tc->data;
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->flag & BONE_TRANSFORM) {
- add_pose_transdata(t, pchan, ob, tc, td);
-
- if (mirror) {
- bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name);
- if (pchan_mirror) {
- pose_mirror_info_init(&pid[pid_index], pchan_mirror, pchan, is_mirror_relative);
- pid_index++;
- }
- }
-
- td++;
- }
- }
-
- if (td != (tc->data + tc->data_len)) {
- BKE_report(t->reports, RPT_DEBUG, "Bone selection count error");
- }
-
- /* initialize initial auto=ik chainlen's? */
- if (t->flag & T_AUTOIK) {
- transform_autoik_update(t, 0);
- }
- }
-
- t->flag |= T_POSE;
- /* disable PET, its not usable in pose mode yet [#32444] */
- t->flag &= ~T_PROP_EDIT_ALL;
-}
-
-void restoreMirrorPoseBones(TransDataContainer *tc)
-{
- bPose *pose = tc->poseobj->pose;
-
- if (!(pose->flag & POSE_MIRROR_EDIT)) {
- return;
- }
-
- for (PoseInitData_Mirror *pid = tc->custom.type.data; pid->pchan; pid++) {
- pose_mirror_info_restore(pid);
- }
-}
-
-void restoreBones(TransDataContainer *tc)
-{
- bArmature *arm;
- BoneInitData *bid = tc->custom.type.data;
- EditBone *ebo;
-
- if (tc->obedit) {
- arm = tc->obedit->data;
- }
- else {
- BLI_assert(tc->poseobj != NULL);
- arm = tc->poseobj->data;
- }
-
- while (bid->bone) {
- ebo = bid->bone;
-
- ebo->dist = bid->dist;
- ebo->rad_head = bid->rad_head;
- ebo->rad_tail = bid->rad_tail;
- ebo->roll = bid->roll;
- ebo->xwidth = bid->xwidth;
- ebo->zwidth = bid->zwidth;
- copy_v3_v3(ebo->head, bid->head);
- copy_v3_v3(ebo->tail, bid->tail);
-
- if (arm->flag & ARM_MIRROR_EDIT) {
- EditBone *ebo_child;
-
- /* Also move connected ebo_child, in case ebo_child's name aren't mirrored properly */
- for (ebo_child = arm->edbo->first; ebo_child; ebo_child = ebo_child->next) {
- if ((ebo_child->flag & BONE_CONNECTED) && (ebo_child->parent == ebo)) {
- copy_v3_v3(ebo_child->head, ebo->tail);
- ebo_child->rad_head = ebo->rad_tail;
- }
- }
-
- /* Also move connected parent, in case parent's name isn't mirrored properly */
- if ((ebo->flag & BONE_CONNECTED) && ebo->parent) {
- EditBone *parent = ebo->parent;
- copy_v3_v3(parent->tail, ebo->head);
- parent->rad_tail = ebo->rad_head;
- }
- }
-
- bid++;
- }
-}
-
-/* ********************* armature ************** */
-static void createTransArmatureVerts(TransInfo *t)
-{
- t->data_len_all = 0;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- EditBone *ebo, *eboflip;
- bArmature *arm = tc->obedit->data;
- ListBase *edbo = arm->edbo;
- bool mirror = ((arm->flag & ARM_MIRROR_EDIT) != 0);
- int total_mirrored = 0;
-
- tc->data_len = 0;
- for (ebo = edbo->first; ebo; ebo = ebo->next) {
- const int data_len_prev = tc->data_len;
-
- if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
- if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
- if (ebo->flag & BONE_SELECTED) {
- tc->data_len++;
- }
- }
- else if (t->mode == TFM_BONE_ROLL) {
- if (ebo->flag & BONE_SELECTED) {
- tc->data_len++;
- }
- }
- else {
- if (ebo->flag & BONE_TIPSEL) {
- tc->data_len++;
- }
- if (ebo->flag & BONE_ROOTSEL) {
- tc->data_len++;
- }
- }
- }
-
- if (mirror && (data_len_prev < tc->data_len)) {
- eboflip = ED_armature_ebone_get_mirrored(arm->edbo, ebo);
- if (eboflip) {
- total_mirrored++;
- }
- }
- }
- if (!tc->data_len) {
- continue;
- }
-
- if (mirror) {
- BoneInitData *bid = MEM_mallocN((total_mirrored + 1) * sizeof(BoneInitData), "BoneInitData");
-
- /* trick to terminate iteration */
- bid[total_mirrored].bone = NULL;
-
- tc->custom.type.data = bid;
- tc->custom.type.use_free = true;
- }
- t->data_len_all += tc->data_len;
- }
-
- transform_around_single_fallback(t);
- t->data_len_all = -1;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- if (!tc->data_len) {
- continue;
- }
-
- EditBone *ebo, *eboflip;
- bArmature *arm = tc->obedit->data;
- ListBase *edbo = arm->edbo;
- TransData *td, *td_old;
- float mtx[3][3], smtx[3][3], bonemat[3][3];
- bool mirror = ((arm->flag & ARM_MIRROR_EDIT) != 0);
- BoneInitData *bid = tc->custom.type.data;
-
- copy_m3_m4(mtx, tc->obedit->obmat);
- pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
-
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransEditBone");
- int i = 0;
-
- for (ebo = edbo->first; ebo; ebo = ebo->next) {
- td_old = td;
- ebo->oldlength =
- ebo->length; // length==0.0 on extrude, used for scaling radius of bone points
-
- if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
- if (t->mode == TFM_BONE_ENVELOPE) {
- if (ebo->flag & BONE_ROOTSEL) {
- td->val = &ebo->rad_head;
- td->ival = *td->val;
-
- copy_v3_v3(td->center, ebo->head);
- td->flag = TD_SELECTED;
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
-
- td->loc = NULL;
- td->ext = NULL;
- td->ob = tc->obedit;
-
- td++;
- }
- if (ebo->flag & BONE_TIPSEL) {
- td->val = &ebo->rad_tail;
- td->ival = *td->val;
- copy_v3_v3(td->center, ebo->tail);
- td->flag = TD_SELECTED;
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
-
- td->loc = NULL;
- td->ext = NULL;
- td->ob = tc->obedit;
-
- td++;
- }
- }
- else if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
- if (ebo->flag & BONE_SELECTED) {
- if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
- td->loc = NULL;
- td->val = &ebo->dist;
- td->ival = ebo->dist;
- }
- else {
- // abusive storage of scale in the loc pointer :)
- td->loc = &ebo->xwidth;
- copy_v3_v3(td->iloc, td->loc);
- td->val = NULL;
- }
- copy_v3_v3(td->center, ebo->head);
- td->flag = TD_SELECTED;
-
- /* use local bone matrix */
- ED_armature_ebone_to_mat3(ebo, bonemat);
- mul_m3_m3m3(td->mtx, mtx, bonemat);
- invert_m3_m3(td->smtx, td->mtx);
-
- copy_m3_m3(td->axismtx, td->mtx);
- normalize_m3(td->axismtx);
-
- td->ext = NULL;
- td->ob = tc->obedit;
-
- td++;
- }
- }
- else if (t->mode == TFM_BONE_ROLL) {
- if (ebo->flag & BONE_SELECTED) {
- td->loc = NULL;
- td->val = &(ebo->roll);
- td->ival = ebo->roll;
-
- copy_v3_v3(td->center, ebo->head);
- td->flag = TD_SELECTED;
-
- td->ext = NULL;
- td->ob = tc->obedit;
-
- td++;
- }
- }
- else {
- if (ebo->flag & BONE_TIPSEL) {
- copy_v3_v3(td->iloc, ebo->tail);
-
- /* Don't allow single selected tips to have a modified center,
- * causes problem with snapping (see T45974).
- * However, in rotation mode, we want to keep that 'rotate bone around root with
- * only its tip selected' behavior (see T46325). */
- if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
- ((t->mode == TFM_ROTATION) || (ebo->flag & BONE_ROOTSEL))) {
- copy_v3_v3(td->center, ebo->head);
- }
- else {
- copy_v3_v3(td->center, td->iloc);
- }
-
- td->loc = ebo->tail;
- td->flag = TD_SELECTED;
- if (ebo->flag & BONE_EDITMODE_LOCKED) {
- td->protectflag = OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE;
- }
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
-
- ED_armature_ebone_to_mat3(ebo, td->axismtx);
-
- if ((ebo->flag & BONE_ROOTSEL) == 0) {
- td->extra = ebo;
- td->ival = ebo->roll;
- }
-
- td->ext = NULL;
- td->val = NULL;
- td->ob = tc->obedit;
-
- td++;
- }
- if (ebo->flag & BONE_ROOTSEL) {
- copy_v3_v3(td->iloc, ebo->head);
- copy_v3_v3(td->center, td->iloc);
- td->loc = ebo->head;
- td->flag = TD_SELECTED;
- if (ebo->flag & BONE_EDITMODE_LOCKED) {
- td->protectflag = OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE;
- }
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
-
- ED_armature_ebone_to_mat3(ebo, td->axismtx);
-
- td->extra = ebo; /* to fix roll */
- td->ival = ebo->roll;
-
- td->ext = NULL;
- td->val = NULL;
- td->ob = tc->obedit;
-
- td++;
- }
- }
- }
-
- if (mirror && (td_old != td)) {
- eboflip = ED_armature_ebone_get_mirrored(arm->edbo, ebo);
- if (eboflip) {
- bid[i].bone = eboflip;
- bid[i].dist = eboflip->dist;
- bid[i].rad_head = eboflip->rad_head;
- bid[i].rad_tail = eboflip->rad_tail;
- bid[i].roll = eboflip->roll;
- bid[i].xwidth = eboflip->xwidth;
- bid[i].zwidth = eboflip->zwidth;
- copy_v3_v3(bid[i].head, eboflip->head);
- copy_v3_v3(bid[i].tail, eboflip->tail);
- i++;
- }
- }
- }
-
- if (mirror) {
- /* trick to terminate iteration */
- BLI_assert(i + 1 == (MEM_allocN_len(bid) / sizeof(*bid)));
- bid[i].bone = NULL;
- }
- }
-}
-
-/* ********************* meta elements ********* */
-
-static void createTransMBallVerts(TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- MetaBall *mb = (MetaBall *)tc->obedit->data;
- MetaElem *ml;
- TransData *td;
- TransDataExtension *tx;
- float mtx[3][3], smtx[3][3];
- int count = 0, countsel = 0;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
-
- /* count totals */
- for (ml = mb->editelems->first; ml; ml = ml->next) {
- if (ml->flag & SELECT) {
- countsel++;
- }
- if (is_prop_edit) {
- count++;
- }
- }
-
- /* note: in prop mode we need at least 1 selected */
- if (countsel == 0) {
- continue;
- }
-
- if (is_prop_edit) {
- tc->data_len = count;
- }
- else {
- tc->data_len = countsel;
- }
-
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(MBall EditMode)");
- tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension),
- "MetaElement_TransExtension");
-
- copy_m3_m4(mtx, tc->obedit->obmat);
- pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
-
- for (ml = mb->editelems->first; ml; ml = ml->next) {
- if (is_prop_edit || (ml->flag & SELECT)) {
- td->loc = &ml->x;
- copy_v3_v3(td->iloc, td->loc);
- copy_v3_v3(td->center, td->loc);
-
- quat_to_mat3(td->axismtx, ml->quat);
-
- if (ml->flag & SELECT) {
- td->flag = TD_SELECTED | TD_USEQUAT | TD_SINGLESIZE;
- }
- else {
- td->flag = TD_USEQUAT;
- }
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
-
- td->ext = tx;
-
- /* Radius of MetaElem (mass of MetaElem influence) */
- if (ml->flag & MB_SCALE_RAD) {
- td->val = &ml->rad;
- td->ival = ml->rad;
- }
- else {
- td->val = &ml->s;
- td->ival = ml->s;
- }
-
- /* expx/expy/expz determine "shape" of some MetaElem types */
- tx->size = &ml->expx;
- tx->isize[0] = ml->expx;
- tx->isize[1] = ml->expy;
- tx->isize[2] = ml->expz;
-
- /* quat is used for rotation of MetaElem */
- tx->quat = ml->quat;
- copy_qt_qt(tx->iquat, ml->quat);
-
- tx->rot = NULL;
-
- td++;
- tx++;
- }
- }
- }
-}
-
-/* ********************* curve/surface ********* */
-
-static void calc_distanceCurveVerts(TransData *head, TransData *tail)
-{
- TransData *td, *td_near = NULL;
- for (td = head; td <= tail; td++) {
- if (td->flag & TD_SELECTED) {
- td_near = td;
- td->dist = 0.0f;
- }
- else if (td_near) {
- float dist;
- float vec[3];
-
- sub_v3_v3v3(vec, td_near->center, td->center);
- mul_m3_v3(head->mtx, vec);
- dist = len_v3(vec);
-
- if (dist < (td - 1)->dist) {
- td->dist = (td - 1)->dist;
- }
- else {
- td->dist = dist;
- }
- }
- else {
- td->dist = FLT_MAX;
- td->flag |= TD_NOTCONNECTED;
- }
- }
- td_near = NULL;
- for (td = tail; td >= head; td--) {
- if (td->flag & TD_SELECTED) {
- td_near = td;
- td->dist = 0.0f;
- }
- else if (td_near) {
- float dist;
- float vec[3];
-
- sub_v3_v3v3(vec, td_near->center, td->center);
- mul_m3_v3(head->mtx, vec);
- dist = len_v3(vec);
-
- if (td->flag & TD_NOTCONNECTED || dist < td->dist || (td + 1)->dist < td->dist) {
- td->flag &= ~TD_NOTCONNECTED;
- if (dist < (td + 1)->dist) {
- td->dist = (td + 1)->dist;
- }
- else {
- td->dist = dist;
- }
- }
- }
- }
-}
-
-/* Utility function for getting the handle data from bezier's */
-static TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt)
-{
- TransDataCurveHandleFlags *hdata;
- td->flag |= TD_BEZTRIPLE;
- hdata = td->hdata = MEM_mallocN(sizeof(TransDataCurveHandleFlags), "CuHandle Data");
- hdata->ih1 = bezt->h1;
- hdata->h1 = &bezt->h1;
- hdata->ih2 = bezt->h2; /* in case the second is not selected */
- hdata->h2 = &bezt->h2;
- return hdata;
-}
-
-/**
- * For the purpose of transform code we need to behave as if handles are selected,
- * even when they aren't (see special case below).
- */
-static int bezt_select_to_transform_triple_flag(const BezTriple *bezt, const bool hide_handles)
-{
- int flag = 0;
-
- if (hide_handles) {
- if (bezt->f2 & SELECT) {
- flag = (1 << 0) | (1 << 1) | (1 << 2);
- }
- }
- else {
- flag = (((bezt->f1 & SELECT) ? (1 << 0) : 0) | ((bezt->f2 & SELECT) ? (1 << 1) : 0) |
- ((bezt->f3 & SELECT) ? (1 << 2) : 0));
- }
-
- /* Special case for auto & aligned handles:
- * When a center point is being moved without the handles,
- * leaving the handles stationary makes no sense and only causes strange behavior,
- * where one handle is arbitrarily anchored, the other one is aligned and lengthened
- * based on where the center point is moved. Also a bug when cancelling, see: T52007.
- *
- * A more 'correct' solution could be to store handle locations in 'TransDataCurveHandleFlags'.
- * However that doesn't resolve odd behavior, so best transform the handles in this case.
- */
- if ((flag != ((1 << 0) | (1 << 1) | (1 << 2))) && (flag & (1 << 1))) {
- if (ELEM(bezt->h1, HD_AUTO, HD_ALIGN) && ELEM(bezt->h2, HD_AUTO, HD_ALIGN)) {
- flag = (1 << 0) | (1 << 1) | (1 << 2);
- }
- }
-
- return flag;
-}
-
-static void createTransCurveVerts(TransInfo *t)
-{
-
-#define SEL_F1 (1 << 0)
-#define SEL_F2 (1 << 1)
-#define SEL_F3 (1 << 2)
-
- t->data_len_all = 0;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- Curve *cu = tc->obedit->data;
- BLI_assert(cu->editnurb != NULL);
- BezTriple *bezt;
- BPoint *bp;
- int a;
- int count = 0, countsel = 0;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
- View3D *v3d = t->view;
- short hide_handles = (v3d != NULL) ?
- ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) :
- false;
-
- /* count total of vertices, check identical as in 2nd loop for making transdata! */
- ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- for (Nurb *nu = nurbs->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
- if (bezt->hide == 0) {
- const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
- if (bezt_tx & SEL_F1) {
- countsel++;
- }
- if (bezt_tx & SEL_F2) {
- countsel++;
- }
- if (bezt_tx & SEL_F3) {
- countsel++;
- }
- if (is_prop_edit) {
- count += 3;
- }
- }
- }
- }
- else {
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
- if (bp->hide == 0) {
- if (is_prop_edit) {
- count++;
- }
- if (bp->f1 & SELECT) {
- countsel++;
- }
- }
- }
- }
- }
- /* note: in prop mode we need at least 1 selected */
- if (countsel == 0) {
- tc->data_len = 0;
- continue;
- }
-
- if (is_prop_edit) {
- tc->data_len = count;
- }
- else {
- tc->data_len = countsel;
- }
- tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Curve EditMode)");
-
- t->data_len_all += tc->data_len;
- }
-
- transform_around_single_fallback(t);
- t->data_len_all = -1;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- if (tc->data_len == 0) {
- continue;
- }
-
- Curve *cu = tc->obedit->data;
- BezTriple *bezt;
- BPoint *bp;
- int a;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
- View3D *v3d = t->view;
- short hide_handles = (v3d != NULL) ?
- ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) :
- false;
-
- float mtx[3][3], smtx[3][3];
-
- copy_m3_m4(mtx, tc->obedit->obmat);
- pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
-
- TransData *td = tc->data;
- ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- for (Nurb *nu = nurbs->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- TransData *head, *tail;
- head = tail = td;
- for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
- if (bezt->hide == 0) {
- TransDataCurveHandleFlags *hdata = NULL;
- float axismtx[3][3];
-
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- float normal[3], plane[3];
-
- BKE_nurb_bezt_calc_normal(nu, bezt, normal);
- BKE_nurb_bezt_calc_plane(nu, bezt, plane);
-
- if (createSpaceNormalTangent(axismtx, normal, plane)) {
- /* pass */
- }
- else {
- normalize_v3(normal);
- axis_dominant_v3_to_m3(axismtx, normal);
- invert_m3(axismtx);
- }
- }
-
- /* Elements that will be transform (not always a match to selection). */
- const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
-
- if (is_prop_edit || bezt_tx & SEL_F1) {
- copy_v3_v3(td->iloc, bezt->vec[0]);
- td->loc = bezt->vec[0];
- copy_v3_v3(td->center,
- bezt->vec[(hide_handles || (t->around == V3D_AROUND_LOCAL_ORIGINS) ||
- (bezt->f2 & SELECT)) ?
- 1 :
- 0]);
- if (hide_handles) {
- if (bezt->f2 & SELECT) {
- td->flag = TD_SELECTED;
- }
- else {
- td->flag = 0;
- }
- }
- else {
- if (bezt->f1 & SELECT) {
- td->flag = TD_SELECTED;
- }
- else {
- td->flag = 0;
- }
- }
- td->ext = NULL;
- td->val = NULL;
-
- hdata = initTransDataCurveHandles(td, bezt);
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- copy_m3_m3(td->axismtx, axismtx);
- }
-
- td++;
- tail++;
- }
-
- /* This is the Curve Point, the other two are handles */
- if (is_prop_edit || bezt_tx & SEL_F2) {
- copy_v3_v3(td->iloc, bezt->vec[1]);
- td->loc = bezt->vec[1];
- copy_v3_v3(td->center, td->loc);
- if (bezt->f2 & SELECT) {
- td->flag = TD_SELECTED;
- }
- else {
- td->flag = 0;
- }
- td->ext = NULL;
-
- /* TODO - make points scale */
- if (t->mode == TFM_CURVE_SHRINKFATTEN) { /* || t->mode==TFM_RESIZE) {*/
- td->val = &(bezt->radius);
- td->ival = bezt->radius;
- }
- else if (t->mode == TFM_TILT) {
- td->val = &(bezt->tilt);
- td->ival = bezt->tilt;
- }
- else {
- td->val = NULL;
- }
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- copy_m3_m3(td->axismtx, axismtx);
- }
-
- if ((bezt_tx & SEL_F1) == 0 && (bezt_tx & SEL_F3) == 0) {
- /* If the middle is selected but the sides arnt, this is needed */
- if (hdata == NULL) {
- /* if the handle was not saved by the previous handle */
- hdata = initTransDataCurveHandles(td, bezt);
- }
- }
-
- td++;
- tail++;
- }
- if (is_prop_edit || bezt_tx & SEL_F3) {
- copy_v3_v3(td->iloc, bezt->vec[2]);
- td->loc = bezt->vec[2];
- copy_v3_v3(td->center,
- bezt->vec[(hide_handles || (t->around == V3D_AROUND_LOCAL_ORIGINS) ||
- (bezt->f2 & SELECT)) ?
- 1 :
- 2]);
- if (hide_handles) {
- if (bezt->f2 & SELECT) {
- td->flag = TD_SELECTED;
- }
- else {
- td->flag = 0;
- }
- }
- else {
- if (bezt->f3 & SELECT) {
- td->flag = TD_SELECTED;
- }
- else {
- td->flag = 0;
- }
- }
- td->ext = NULL;
- td->val = NULL;
-
- if (hdata == NULL) {
- /* if the handle was not saved by the previous handle */
- hdata = initTransDataCurveHandles(td, bezt);
- }
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- copy_m3_m3(td->axismtx, axismtx);
- }
-
- td++;
- tail++;
- }
-
- (void)hdata; /* quiet warning */
- }
- else if (is_prop_edit && head != tail) {
- calc_distanceCurveVerts(head, tail - 1);
- head = tail;
- }
- }
- if (is_prop_edit && head != tail) {
- calc_distanceCurveVerts(head, tail - 1);
- }
-
- /* TODO - in the case of tilt and radius we can also avoid allocating the
- * initTransDataCurveHandles but for now just don't change handle types */
- if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT, TFM_DUMMY) == 0) {
- /* sets the handles based on their selection,
- * do this after the data is copied to the TransData */
- BKE_nurb_handles_test(nu, !hide_handles);
- }
- }
- else {
- TransData *head, *tail;
- head = tail = td;
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
- if (bp->hide == 0) {
- if (is_prop_edit || (bp->f1 & SELECT)) {
- float axismtx[3][3];
-
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- if (nu->pntsv == 1) {
- float normal[3], plane[3];
-
- BKE_nurb_bpoint_calc_normal(nu, bp, normal);
- BKE_nurb_bpoint_calc_plane(nu, bp, plane);
-
- if (createSpaceNormalTangent(axismtx, normal, plane)) {
- /* pass */
- }
- else {
- normalize_v3(normal);
- axis_dominant_v3_to_m3(axismtx, normal);
- invert_m3(axismtx);
- }
- }
- }
-
- copy_v3_v3(td->iloc, bp->vec);
- td->loc = bp->vec;
- copy_v3_v3(td->center, td->loc);
- if (bp->f1 & SELECT) {
- td->flag = TD_SELECTED;
- }
- else {
- td->flag = 0;
- }
- td->ext = NULL;
-
- if (t->mode == TFM_CURVE_SHRINKFATTEN || t->mode == TFM_RESIZE) {
- td->val = &(bp->radius);
- td->ival = bp->radius;
- }
- else {
- td->val = &(bp->tilt);
- td->ival = bp->tilt;
- }
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- if (nu->pntsv == 1) {
- copy_m3_m3(td->axismtx, axismtx);
- }
- }
-
- td++;
- tail++;
- }
- }
- else if (is_prop_edit && head != tail) {
- calc_distanceCurveVerts(head, tail - 1);
- head = tail;
- }
- }
- if (is_prop_edit && head != tail) {
- calc_distanceCurveVerts(head, tail - 1);
- }
- }
- }
- }
-#undef SEL_F1
-#undef SEL_F2
-#undef SEL_F3
-}
-
-/* ********************* lattice *************** */
-
-static void createTransLatticeVerts(TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
-
- Lattice *latt = ((Lattice *)tc->obedit->data)->editlatt->latt;
- TransData *td = NULL;
- BPoint *bp;
- float mtx[3][3], smtx[3][3];
- int a;
- int count = 0, countsel = 0;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
-
- bp = latt->def;
- a = latt->pntsu * latt->pntsv * latt->pntsw;
- while (a--) {
- if (bp->hide == 0) {
- if (bp->f1 & SELECT) {
- countsel++;
- }
- if (is_prop_edit) {
- count++;
- }
- }
- bp++;
- }
-
- /* note: in prop mode we need at least 1 selected */
- if (countsel == 0) {
- return;
- }
-
- if (is_prop_edit) {
- tc->data_len = count;
- }
- else {
- tc->data_len = countsel;
- }
- tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Lattice EditMode)");
-
- copy_m3_m4(mtx, tc->obedit->obmat);
- pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
-
- td = tc->data;
- bp = latt->def;
- a = latt->pntsu * latt->pntsv * latt->pntsw;
- while (a--) {
- if (is_prop_edit || (bp->f1 & SELECT)) {
- if (bp->hide == 0) {
- copy_v3_v3(td->iloc, bp->vec);
- td->loc = bp->vec;
- copy_v3_v3(td->center, td->loc);
- if (bp->f1 & SELECT) {
- td->flag = TD_SELECTED;
- }
- else {
- td->flag = 0;
- }
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
-
- td->ext = NULL;
- td->val = NULL;
-
- td++;
- }
- }
- bp++;
- }
- }
-}
-
-/* ******************* particle edit **************** */
-static void createTransParticleVerts(bContext *C, TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
-
- TransData *td = NULL;
- TransDataExtension *tx;
- Object *ob = CTX_data_active_object(C);
- ParticleEditSettings *pset = PE_settings(t->scene);
- PTCacheEdit *edit = PE_get_current(t->scene, ob);
- ParticleSystem *psys = NULL;
- PTCacheEditPoint *point;
- PTCacheEditKey *key;
- float mat[4][4];
- int i, k, transformparticle;
- int count = 0, hasselected = 0;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
-
- if (edit == NULL || t->settings->particle.selectmode == SCE_SELECT_PATH) {
- return;
- }
-
- psys = edit->psys;
-
- for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) {
- point->flag &= ~PEP_TRANSFORM;
- transformparticle = 0;
-
- if ((point->flag & PEP_HIDE) == 0) {
- for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
- if ((key->flag & PEK_HIDE) == 0) {
- if (key->flag & PEK_SELECT) {
- hasselected = 1;
- transformparticle = 1;
- }
- else if (is_prop_edit) {
- transformparticle = 1;
- }
- }
- }
- }
-
- if (transformparticle) {
- count += point->totkey;
- point->flag |= PEP_TRANSFORM;
- }
- }
-
- /* note: in prop mode we need at least 1 selected */
- if (hasselected == 0) {
- return;
- }
-
- tc->data_len = count;
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Particle Mode)");
-
- if (t->mode == TFM_BAKE_TIME) {
- tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension),
- "Particle_TransExtension");
- }
- else {
- tx = tc->data_ext = NULL;
- }
-
- unit_m4(mat);
-
- invert_m4_m4(ob->imat, ob->obmat);
-
- for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) {
- TransData *head, *tail;
- head = tail = td;
-
- if (!(point->flag & PEP_TRANSFORM)) {
- continue;
- }
-
- if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
- ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
- psys_mat_hair_to_global(
- ob, psmd_eval->mesh_final, psys->part->from, psys->particles + i, mat);
- }
-
- for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
- if (key->flag & PEK_USE_WCO) {
- copy_v3_v3(key->world_co, key->co);
- mul_m4_v3(mat, key->world_co);
- td->loc = key->world_co;
- }
- else {
- td->loc = key->co;
- }
-
- copy_v3_v3(td->iloc, td->loc);
- copy_v3_v3(td->center, td->loc);
-
- if (key->flag & PEK_SELECT) {
- td->flag |= TD_SELECTED;
- }
- else if (!is_prop_edit) {
- td->flag |= TD_SKIP;
- }
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-
- /* don't allow moving roots */
- if (k == 0 && pset->flag & PE_LOCK_FIRST && (!psys || !(psys->flag & PSYS_GLOBAL_HAIR))) {
- td->protectflag |= OB_LOCK_LOC;
- }
-
- td->ob = ob;
- td->ext = tx;
- if (t->mode == TFM_BAKE_TIME) {
- td->val = key->time;
- td->ival = *(key->time);
- /* abuse size and quat for min/max values */
- td->flag |= TD_NO_EXT;
- if (k == 0) {
- tx->size = NULL;
- }
- else {
- tx->size = (key - 1)->time;
- }
-
- if (k == point->totkey - 1) {
- tx->quat = NULL;
- }
- else {
- tx->quat = (key + 1)->time;
- }
- }
-
- td++;
- if (tx) {
- tx++;
- }
- tail++;
- }
- if (is_prop_edit && head != tail) {
- calc_distanceCurveVerts(head, tail - 1);
- }
- }
- }
-}
-
-void flushTransParticles(TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- Scene *scene = t->scene;
- ViewLayer *view_layer = t->view_layer;
- Object *ob = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(scene, ob);
- ParticleSystem *psys = edit->psys;
- PTCacheEditPoint *point;
- PTCacheEditKey *key;
- TransData *td;
- float mat[4][4], imat[4][4], co[3];
- int i, k;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
-
- /* we do transform in world space, so flush world space position
- * back to particle local space (only for hair particles) */
- td = tc->data;
- for (i = 0, point = edit->points; i < edit->totpoint; i++, point++, td++) {
- if (!(point->flag & PEP_TRANSFORM)) {
- continue;
- }
-
- if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
- ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
- psys_mat_hair_to_global(
- ob, psmd_eval->mesh_final, psys->part->from, psys->particles + i, mat);
- invert_m4_m4(imat, mat);
-
- for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
- copy_v3_v3(co, key->world_co);
- mul_m4_v3(imat, co);
-
- /* optimization for proportional edit */
- if (!is_prop_edit || !compare_v3v3(key->co, co, 0.0001f)) {
- copy_v3_v3(key->co, co);
- point->flag |= PEP_EDIT_RECALC;
- }
- }
- }
- else {
- point->flag |= PEP_EDIT_RECALC;
- }
- }
-
- PE_update_object(t->depsgraph, scene, OBACT(view_layer), 1);
- BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
- DEG_id_tag_update(&ob->id, ID_RECALC_PSYS_REDO);
- }
-}
-
-/* ********************* mesh ****************** */
-
-static bool bmesh_test_dist_add(BMVert *v,
- BMVert *v_other,
- float *dists,
- const float *dists_prev,
- /* optionally track original index */
- int *index,
- const int *index_prev,
- float mtx[3][3])
-{
- if ((BM_elem_flag_test(v_other, BM_ELEM_SELECT) == 0) &&
- (BM_elem_flag_test(v_other, BM_ELEM_HIDDEN) == 0)) {
- const int i = BM_elem_index_get(v);
- const int i_other = BM_elem_index_get(v_other);
- float vec[3];
- float dist_other;
- sub_v3_v3v3(vec, v->co, v_other->co);
- mul_m3_v3(mtx, vec);
-
- dist_other = dists_prev[i] + len_v3(vec);
- if (dist_other < dists[i_other]) {
- dists[i_other] = dist_other;
- if (index != NULL) {
- index[i_other] = index_prev[i];
- }
- return true;
- }
- }
-
- return false;
-}
-
-/**
- * \param mtx: Measure distance in this space.
- * \param dists: Store the closest connected distance to selected vertices.
- * \param index: Optionally store the original index we're measuring the distance to (can be NULL).
- */
-static void editmesh_set_connectivity_distance(BMesh *bm,
- float mtx[3][3],
- float *dists,
- int *index)
-{
- BLI_LINKSTACK_DECLARE(queue, BMVert *);
-
- /* any BM_ELEM_TAG'd vertex is in 'queue_next', so we don't add in twice */
- BLI_LINKSTACK_DECLARE(queue_next, BMVert *);
-
- BLI_LINKSTACK_INIT(queue);
- BLI_LINKSTACK_INIT(queue_next);
-
- {
- BMIter viter;
- BMVert *v;
- int i;
-
- BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
- float dist;
- BM_elem_index_set(v, i); /* set_inline */
- BM_elem_flag_disable(v, BM_ELEM_TAG);
-
- if (BM_elem_flag_test(v, BM_ELEM_SELECT) == 0 || BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
- dist = FLT_MAX;
- if (index != NULL) {
- index[i] = i;
- }
- }
- else {
- BLI_LINKSTACK_PUSH(queue, v);
- dist = 0.0f;
- if (index != NULL) {
- index[i] = i;
- }
- }
-
- dists[i] = dist;
- }
- bm->elem_index_dirty &= ~BM_VERT;
- }
-
- /* need to be very careful of feedback loops here, store previous dist's to avoid feedback */
- float *dists_prev = MEM_dupallocN(dists);
- int *index_prev = MEM_dupallocN(index); /* may be NULL */
-
- do {
- BMVert *v;
- LinkNode *lnk;
-
- /* this is correct but slow to do each iteration,
- * instead sync the dist's while clearing BM_ELEM_TAG (below) */
-#if 0
- memcpy(dists_prev, dists, sizeof(float) * bm->totvert);
-#endif
-
- while ((v = BLI_LINKSTACK_POP(queue))) {
- BLI_assert(dists[BM_elem_index_get(v)] != FLT_MAX);
-
- /* connected edge-verts */
- if (v->e != NULL) {
- BMEdge *e_iter, *e_first;
-
- e_iter = e_first = v->e;
-
- /* would normally use BM_EDGES_OF_VERT, but this runs so often,
- * its faster to iterate on the data directly */
- do {
-
- if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == 0) {
-
- /* edge distance */
- {
- BMVert *v_other = BM_edge_other_vert(e_iter, v);
- if (bmesh_test_dist_add(v, v_other, dists, dists_prev, index, index_prev, mtx)) {
- if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
- BM_elem_flag_enable(v_other, BM_ELEM_TAG);
- BLI_LINKSTACK_PUSH(queue_next, v_other);
- }
- }
- }
-
- /* face distance */
- if (e_iter->l) {
- BMLoop *l_iter_radial, *l_first_radial;
- /**
- * imaginary edge diagonally across quad,
- * \note, this takes advantage of the rules of winding that we
- * know 2 or more of a verts edges wont reference the same face twice.
- * Also, if the edge is hidden, the face will be hidden too.
- */
- l_iter_radial = l_first_radial = e_iter->l;
-
- do {
- if ((l_iter_radial->v == v) && (l_iter_radial->f->len == 4) &&
- (BM_elem_flag_test(l_iter_radial->f, BM_ELEM_HIDDEN) == 0)) {
- BMVert *v_other = l_iter_radial->next->next->v;
- if (bmesh_test_dist_add(v, v_other, dists, dists_prev, index, index_prev, mtx)) {
- if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
- BM_elem_flag_enable(v_other, BM_ELEM_TAG);
- BLI_LINKSTACK_PUSH(queue_next, v_other);
- }
- }
- }
- } while ((l_iter_radial = l_iter_radial->radial_next) != l_first_radial);
- }
- }
- } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
- }
- }
-
- /* clear for the next loop */
- for (lnk = queue_next; lnk; lnk = lnk->next) {
- BMVert *v_link = lnk->link;
- const int i = BM_elem_index_get(v_link);
-
- BM_elem_flag_disable(v_link, BM_ELEM_TAG);
-
- /* keep in sync, avoid having to do full memcpy each iteration */
- dists_prev[i] = dists[i];
- if (index != NULL) {
- index_prev[i] = index[i];
- }
- }
-
- BLI_LINKSTACK_SWAP(queue, queue_next);
-
- /* none should be tagged now since 'queue_next' is empty */
- BLI_assert(BM_iter_mesh_count_flag(BM_VERTS_OF_MESH, bm, BM_ELEM_TAG, true) == 0);
-
- } while (BLI_LINKSTACK_SIZE(queue));
-
- BLI_LINKSTACK_FREE(queue);
- BLI_LINKSTACK_FREE(queue_next);
-
- MEM_freeN(dists_prev);
- if (index_prev != NULL) {
- MEM_freeN(index_prev);
- }
-}
-
-static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
- int *r_island_tot,
- int **r_island_vert_map,
- bool calc_single_islands)
-{
- BMesh *bm = em->bm;
- struct TransIslandData *trans_islands;
- char htype;
- char itype;
- int i;
-
- /* group vars */
- int *groups_array;
- int(*group_index)[2];
- int group_tot;
- void **ele_array;
-
- int *vert_map;
-
- if (em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
- groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totedgesel, __func__);
- group_tot = BM_mesh_calc_edge_groups(
- bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT);
-
- htype = BM_EDGE;
- itype = BM_VERTS_OF_EDGE;
- }
- else { /* (bm->selectmode & SCE_SELECT_FACE) */
- groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__);
- group_tot = BM_mesh_calc_face_groups(
- bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT, BM_VERT);
-
- htype = BM_FACE;
- itype = BM_VERTS_OF_FACE;
- }
-
- trans_islands = MEM_mallocN(sizeof(*trans_islands) * group_tot, __func__);
-
- vert_map = MEM_mallocN(sizeof(*vert_map) * bm->totvert, __func__);
- /* we shouldn't need this, but with incorrect selection flushing
- * its possible we have a selected vertex that's not in a face,
- * for now best not crash in that case. */
- copy_vn_i(vert_map, bm->totvert, -1);
-
- BM_mesh_elem_table_ensure(bm, htype);
- ele_array = (htype == BM_FACE) ? (void **)bm->ftable : (void **)bm->etable;
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- /* may be an edge OR a face array */
- for (i = 0; i < group_tot; i++) {
- BMEditSelection ese = {NULL};
-
- const int fg_sta = group_index[i][0];
- const int fg_len = group_index[i][1];
- float co[3], no[3], tangent[3];
- int j;
-
- zero_v3(co);
- zero_v3(no);
- zero_v3(tangent);
-
- ese.htype = htype;
-
- /* loop on each face in this group:
- * - assign r_vert_map
- * - calculate (co, no)
- */
- for (j = 0; j < fg_len; j++) {
- float tmp_co[3], tmp_no[3], tmp_tangent[3];
-
- ese.ele = ele_array[groups_array[fg_sta + j]];
-
- BM_editselection_center(&ese, tmp_co);
- BM_editselection_normal(&ese, tmp_no);
- BM_editselection_plane(&ese, tmp_tangent);
-
- add_v3_v3(co, tmp_co);
- add_v3_v3(no, tmp_no);
- add_v3_v3(tangent, tmp_tangent);
-
- {
- /* setup vertex map */
- BMIter iter;
- BMVert *v;
-
- /* connected edge-verts */
- BM_ITER_ELEM (v, &iter, ese.ele, itype) {
- vert_map[BM_elem_index_get(v)] = i;
- }
- }
- }
-
- mul_v3_v3fl(trans_islands[i].co, co, 1.0f / (float)fg_len);
-
- if (createSpaceNormalTangent(trans_islands[i].axismtx, no, tangent)) {
- /* pass */
- }
- else {
- if (normalize_v3(no) != 0.0f) {
- axis_dominant_v3_to_m3(trans_islands[i].axismtx, no);
- invert_m3(trans_islands[i].axismtx);
- }
- else {
- unit_m3(trans_islands[i].axismtx);
- }
- }
- }
-
- MEM_freeN(groups_array);
- MEM_freeN(group_index);
-
- /* for PET we need islands of 1 so connected vertices can use it with V3D_AROUND_LOCAL_ORIGINS */
- if (calc_single_islands) {
- BMIter viter;
- BMVert *v;
- int group_tot_single = 0;
-
- BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
- if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) {
- group_tot_single += 1;
- }
- }
-
- if (group_tot_single != 0) {
- trans_islands = MEM_reallocN(trans_islands,
- sizeof(*trans_islands) * (group_tot + group_tot_single));
-
- BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
- if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) {
- struct TransIslandData *v_island = &trans_islands[group_tot];
- vert_map[i] = group_tot;
-
- copy_v3_v3(v_island->co, v->co);
-
- if (is_zero_v3(v->no) != 0.0f) {
- axis_dominant_v3_to_m3(v_island->axismtx, v->no);
- invert_m3(v_island->axismtx);
- }
- else {
- unit_m3(v_island->axismtx);
- }
-
- group_tot += 1;
- }
- }
- }
- }
-
- *r_island_tot = group_tot;
- *r_island_vert_map = vert_map;
-
- return trans_islands;
-}
-
-/* way to overwrite what data is edited with transform */
-static void VertsToTransData(TransInfo *t,
- TransData *td,
- TransDataExtension *tx,
- BMEditMesh *em,
- BMVert *eve,
- float *bweight,
- struct TransIslandData *v_island,
- const bool no_island_center)
-{
- float *no, _no[3];
- BLI_assert(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) == 0);
-
- td->flag = 0;
- // if (key)
- // td->loc = key->co;
- // else
- td->loc = eve->co;
- copy_v3_v3(td->iloc, td->loc);
-
- if ((t->mode == TFM_SHRINKFATTEN) && (em->selectmode & SCE_SELECT_FACE) &&
- BM_elem_flag_test(eve, BM_ELEM_SELECT) &&
- (BM_vert_calc_normal_ex(eve, BM_ELEM_SELECT, _no))) {
- no = _no;
- }
- else {
- no = eve->no;
- }
-
- if (v_island) {
- if (no_island_center) {
- copy_v3_v3(td->center, td->loc);
- }
- else {
- copy_v3_v3(td->center, v_island->co);
- }
- copy_m3_m3(td->axismtx, v_island->axismtx);
- }
- else if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- copy_v3_v3(td->center, td->loc);
- createSpaceNormal(td->axismtx, no);
- }
- else {
- copy_v3_v3(td->center, td->loc);
-
- /* Setting normals */
- copy_v3_v3(td->axismtx[2], no);
- td->axismtx[0][0] = td->axismtx[0][1] = td->axismtx[0][2] = td->axismtx[1][0] =
- td->axismtx[1][1] = td->axismtx[1][2] = 0.0f;
- }
-
- td->ext = NULL;
- td->val = NULL;
- td->extra = NULL;
- if (t->mode == TFM_BWEIGHT) {
- td->val = bweight;
- td->ival = *bweight;
- }
- else if (t->mode == TFM_SKIN_RESIZE) {
- MVertSkin *vs = CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MVERT_SKIN);
- if (vs) {
- /* skin node size */
- td->ext = tx;
- copy_v3_v3(tx->isize, vs->radius);
- tx->size = vs->radius;
- td->val = vs->radius;
- }
- else {
- td->flag |= TD_SKIP;
- }
- }
- else if (t->mode == TFM_SHRINKFATTEN) {
- td->ext = tx;
- tx->isize[0] = BM_vert_calc_shell_factor_ex(eve, no, BM_ELEM_SELECT);
- }
-}
-
-static void createTransEditVerts(TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *tob = NULL;
- TransDataExtension *tx = NULL;
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- Mesh *me = tc->obedit->data;
- BMesh *bm = em->bm;
- BMVert *eve;
- BMIter iter;
- float(*mappedcos)[3] = NULL, (*quats)[4] = NULL;
- float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL;
- float *dists = NULL;
- int a;
- const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
- int mirror = 0;
- int cd_vert_bweight_offset = -1;
- bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
-
- struct TransIslandData *island_info = NULL;
- int island_info_tot;
- int *island_vert_map = NULL;
-
- /* Snap rotation along normal needs a common axis for whole islands,
- * otherwise one get random crazy results, see T59104.
- * However, we do not want to use the island center for the pivot/translation reference. */
- const bool is_snap_rotate = ((t->mode == TFM_TRANSLATION) &&
- /* There is not guarantee that snapping
- * is initialized yet at this point... */
- (usingSnappingNormal(t) ||
- (t->settings->snap_flag & SCE_SNAP_ROTATE) != 0) &&
- (t->around != V3D_AROUND_LOCAL_ORIGINS));
- /* Even for translation this is needed because of island-orientation, see: T51651. */
- const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS) || is_snap_rotate;
- /* Original index of our connected vertex when connected distances are calculated.
- * Optional, allocate if needed. */
- int *dists_index = NULL;
-
- if (tc->mirror.axis_flag) {
- EDBM_verts_mirror_cache_begin(em, 0, false, (t->flag & T_PROP_EDIT) == 0, use_topology);
- mirror = 1;
- }
-
- /**
- * Quick check if we can transform.
- *
- * \note ignore modes here, even in edge/face modes,
- * transform data is created by selected vertices.
- * \note in prop mode we need at least 1 selected.
- */
- if (bm->totvertsel == 0) {
- goto cleanup;
- }
-
- if (t->mode == TFM_BWEIGHT) {
- BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT);
- cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
- }
-
- if (prop_mode) {
- unsigned int count = 0;
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- count++;
- }
- }
-
- tc->data_len = count;
-
- /* allocating scratch arrays */
- if (prop_mode & T_PROP_CONNECTED) {
- dists = MEM_mallocN(em->bm->totvert * sizeof(float), __func__);
- if (is_island_center) {
- dists_index = MEM_mallocN(em->bm->totvert * sizeof(int), __func__);
- }
- }
- }
- else {
- tc->data_len = bm->totvertsel;
- }
-
- tob = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Mesh EditMode)");
- if (ELEM(t->mode, TFM_SKIN_RESIZE, TFM_SHRINKFATTEN)) {
- /* warning, this is overkill, we only need 2 extra floats,
- * but this stores loads of extra stuff, for TFM_SHRINKFATTEN its even more overkill
- * since we may not use the 'alt' transform mode to maintain shell thickness,
- * but with generic transform code its hard to lazy init vars */
- tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension),
- "TransObData ext");
- }
-
- copy_m3_m4(mtx, tc->obedit->obmat);
- /* we use a pseudo-inverse so that when one of the axes is scaled to 0,
- * matrix inversion still works and we can still moving along the other */
- pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
-
- if (prop_mode & T_PROP_CONNECTED) {
- editmesh_set_connectivity_distance(em->bm, mtx, dists, dists_index);
- }
-
- if (is_island_center) {
- /* In this specific case, near-by vertices will need to know
- * the island of the nearest connected vertex. */
- const bool calc_single_islands = ((prop_mode & T_PROP_CONNECTED) &&
- (t->around == V3D_AROUND_LOCAL_ORIGINS) &&
- (em->selectmode & SCE_SELECT_VERTEX));
-
- island_info = editmesh_islands_info_calc(
- em, &island_info_tot, &island_vert_map, calc_single_islands);
- }
-
- /* detect CrazySpace [tm] */
- if (modifiers_getCageIndex(t->scene, tc->obedit, NULL, 1) != -1) {
- int totleft = -1;
- if (modifiers_isCorrectableDeformed(t->scene, tc->obedit)) {
- BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context));
-
- /* Use evaluated state because we need b-bone cache. */
- Scene *scene_eval = (Scene *)DEG_get_evaluated_id(t->depsgraph, &t->scene->id);
- Object *obedit_eval = (Object *)DEG_get_evaluated_id(t->depsgraph, &tc->obedit->id);
- BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval);
- /* check if we can use deform matrices for modifier from the
- * start up to stack, they are more accurate than quats */
- totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh(
- t->depsgraph, scene_eval, obedit_eval, em_eval, &defmats, &defcos);
- }
-
- /* if we still have more modifiers, also do crazyspace
- * correction with quats, relative to the coordinates after
- * the modifiers that support deform matrices (defcos) */
-
-#if 0 /* TODO, fix crazyspace+extrude so it can be enabled for general use - campbell */
- if ((totleft > 0) || (totleft == -1))
-#else
- if (totleft > 0)
-#endif
- {
- mappedcos = BKE_crazyspace_get_mapped_editverts(t->depsgraph, tc->obedit);
- quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats");
- BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode);
- if (mappedcos) {
- MEM_freeN(mappedcos);
- }
- }
-
- if (defcos) {
- MEM_freeN(defcos);
- }
- }
-
- /* find out which half we do */
- if (mirror) {
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && eve->co[0] != 0.0f) {
- if (eve->co[0] < 0.0f) {
- tc->mirror.sign = -1.0f;
- mirror = -1;
- }
- break;
- }
- }
- }
-
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- struct TransIslandData *v_island = NULL;
- float *bweight = (cd_vert_bweight_offset != -1) ?
- BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) :
- NULL;
-
- if (island_info) {
- const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a;
- v_island = (island_vert_map[connected_index] != -1) ?
- &island_info[island_vert_map[connected_index]] :
- NULL;
- }
-
- /* Do not use the island center in case we are using islands
- * only to get axis for snap/rotate to normal... */
- VertsToTransData(t, tob, tx, em, eve, bweight, v_island, is_snap_rotate);
- if (tx) {
- tx++;
- }
-
- /* selected */
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- tob->flag |= TD_SELECTED;
- }
-
- if (prop_mode) {
- if (prop_mode & T_PROP_CONNECTED) {
- tob->dist = dists[a];
- }
- else {
- tob->flag |= TD_NOTCONNECTED;
- tob->dist = FLT_MAX;
- }
- }
-
- /* CrazySpace */
- const bool use_quats = quats && BM_elem_flag_test(eve, BM_ELEM_TAG);
- if (use_quats || defmats) {
- float mat[3][3], qmat[3][3], imat[3][3];
-
- /* Use both or either quat and defmat correction. */
- if (use_quats) {
- quat_to_mat3(qmat, quats[BM_elem_index_get(eve)]);
-
- if (defmats) {
- mul_m3_series(mat, defmats[a], qmat, mtx);
- }
- else {
- mul_m3_m3m3(mat, mtx, qmat);
- }
- }
- else {
- mul_m3_m3m3(mat, mtx, defmats[a]);
- }
-
- invert_m3_m3(imat, mat);
-
- copy_m3_m3(tob->smtx, imat);
- copy_m3_m3(tob->mtx, mat);
- }
- else {
- copy_m3_m3(tob->smtx, smtx);
- copy_m3_m3(tob->mtx, mtx);
- }
-
- /* Mirror? */
- if ((mirror > 0 && tob->iloc[0] > 0.0f) || (mirror < 0 && tob->iloc[0] < 0.0f)) {
- BMVert *vmir = EDBM_verts_mirror_get(em, eve); // t->obedit, em, eve, tob->iloc, a);
- if (vmir && vmir != eve) {
- tob->extra = vmir;
- }
- }
- tob++;
- }
- }
- }
-
- if (island_info) {
- MEM_freeN(island_info);
- MEM_freeN(island_vert_map);
- }
-
- if (mirror != 0) {
- tob = tc->data;
- for (a = 0; a < tc->data_len; a++, tob++) {
- if (ABS(tob->loc[0]) <= 0.00001f) {
- tob->flag |= TD_MIRROR_EDGE;
- }
- }
- }
-
- cleanup:
- /* crazy space free */
- if (quats) {
- MEM_freeN(quats);
- }
- if (defmats) {
- MEM_freeN(defmats);
- }
- if (dists) {
- MEM_freeN(dists);
- }
- if (dists_index) {
- MEM_freeN(dists_index);
- }
-
- if (tc->mirror.axis_flag) {
- EDBM_verts_mirror_cache_end(em);
- }
- }
-}
-
-/* *** NODE EDITOR *** */
-void flushTransNodes(TransInfo *t)
-{
- const float dpi_fac = UI_DPI_FAC;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- int a;
- TransData *td;
- TransData2D *td2d;
-
- applyGridAbsolute(t);
-
- /* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
- bNode *node = td->extra;
- float locx, locy;
-
- /* weirdo - but the node system is a mix of free 2d elements and dpi sensitive UI */
-#ifdef USE_NODE_CENTER
- locx = (td2d->loc[0] - (BLI_rctf_size_x(&node->totr)) * +0.5f) / dpi_fac;
- locy = (td2d->loc[1] - (BLI_rctf_size_y(&node->totr)) * -0.5f) / dpi_fac;
-#else
- locx = td2d->loc[0] / dpi_fac;
- locy = td2d->loc[1] / dpi_fac;
-#endif
-
- /* account for parents (nested nodes) */
- if (node->parent) {
- nodeFromView(node->parent, locx, locy, &node->locx, &node->locy);
- }
- else {
- node->locx = locx;
- node->locy = locy;
- }
- }
-
- /* handle intersection with noodles */
- if (tc->data_len == 1) {
- ED_node_link_intersect_test(t->sa, 1);
- }
- }
-}
-
-/* *** SEQUENCE EDITOR *** */
-
-/* commented _only_ because the meta may have animation data which
- * needs moving too [#28158] */
-
-#define SEQ_TX_NESTED_METAS
-
-BLI_INLINE void trans_update_seq(Scene *sce, Sequence *seq, int old_start, int sel_flag)
-{
- if (seq->depth == 0) {
- /* Calculate this strip and all nested strips.
- * Children are ALWAYS transformed first so we don't need to do this in another loop.
- */
- BKE_sequence_calc(sce, seq);
- }
- else {
- BKE_sequence_calc_disp(sce, seq);
- }
-
- if (sel_flag == SELECT) {
- BKE_sequencer_offset_animdata(sce, seq, seq->start - old_start);
- }
-}
-
-void flushTransSeq(TransInfo *t)
-{
- /* Editing null check already done */
- ListBase *seqbasep = BKE_sequencer_editing_get(t->scene, false)->seqbasep;
-
- int a, new_frame;
- TransData *td = NULL;
- TransData2D *td2d = NULL;
- TransDataSeq *tdsq = NULL;
- Sequence *seq;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* prevent updating the same seq twice
- * if the transdata order is changed this will mess up
- * but so will TransDataSeq */
- Sequence *seq_prev = NULL;
- int old_start_prev = 0, sel_flag_prev = 0;
-
- /* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
- int old_start;
- tdsq = (TransDataSeq *)td->extra;
- seq = tdsq->seq;
- old_start = seq->start;
- new_frame = round_fl_to_int(td2d->loc[0]);
-
- switch (tdsq->sel_flag) {
- case SELECT:
-#ifdef SEQ_TX_NESTED_METAS
- if ((seq->depth != 0 || BKE_sequence_tx_test(seq))) {
- /* for meta's, their children move */
- seq->start = new_frame - tdsq->start_offset;
- }
-#else
- if (seq->type != SEQ_TYPE_META && (seq->depth != 0 || seq_tx_test(seq))) {
- /* for meta's, their children move */
- seq->start = new_frame - tdsq->start_offset;
- }
-#endif
- if (seq->depth == 0) {
- seq->machine = round_fl_to_int(td2d->loc[1]);
- CLAMP(seq->machine, 1, MAXSEQ);
- }
- break;
- case SEQ_LEFTSEL: /* no vertical transform */
- BKE_sequence_tx_set_final_left(seq, new_frame);
- BKE_sequence_tx_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL);
-
- /* todo - move this into aftertrans update? - old seq tx needed it anyway */
- BKE_sequence_single_fix(seq);
- break;
- case SEQ_RIGHTSEL: /* no vertical transform */
- BKE_sequence_tx_set_final_right(seq, new_frame);
- BKE_sequence_tx_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL);
-
- /* todo - move this into aftertrans update? - old seq tx needed it anyway */
- BKE_sequence_single_fix(seq);
- break;
- }
-
- /* Update *previous* seq! Else, we would update a seq after its first transform,
- * and if it has more than one (like e.g. SEQ_LEFTSEL and SEQ_RIGHTSEL),
- * the others are not updated! See T38469.
- */
- if (seq != seq_prev) {
- if (seq_prev) {
- trans_update_seq(t->scene, seq_prev, old_start_prev, sel_flag_prev);
- }
-
- seq_prev = seq;
- old_start_prev = old_start;
- sel_flag_prev = tdsq->sel_flag;
- }
- else {
- /* We want to accumulate *all* sel_flags for this seq! */
- sel_flag_prev |= tdsq->sel_flag;
- }
- }
-
- /* Don't forget to update the last seq! */
- if (seq_prev) {
- trans_update_seq(t->scene, seq_prev, old_start_prev, sel_flag_prev);
- }
-
- /* originally TFM_TIME_EXTEND, transform changes */
- if (ELEM(t->mode, TFM_SEQ_SLIDE, TFM_TIME_TRANSLATE)) {
- /* Special annoying case here, need to calc metas with TFM_TIME_EXTEND only */
-
- /* calc all meta's then effects [#27953] */
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->type == SEQ_TYPE_META && seq->flag & SELECT) {
- BKE_sequence_calc(t->scene, seq);
- }
- }
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->seq1 || seq->seq2 || seq->seq3) {
- BKE_sequence_calc(t->scene, seq);
- }
- }
-
- /* update effects inside meta's */
- for (a = 0, seq_prev = NULL, td = tc->data, td2d = tc->data_2d; a < tc->data_len;
- a++, td++, td2d++, seq_prev = seq) {
- tdsq = (TransDataSeq *)td->extra;
- seq = tdsq->seq;
- if ((seq != seq_prev) && (seq->depth != 0)) {
- if (seq->seq1 || seq->seq2 || seq->seq3) {
- BKE_sequence_calc(t->scene, seq);
- }
- }
- }
- }
-
- /* need to do the overlap check in a new loop otherwise adjacent strips
- * will not be updated and we'll get false positives */
- seq_prev = NULL;
- for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
-
- tdsq = (TransDataSeq *)td->extra;
- seq = tdsq->seq;
-
- if (seq != seq_prev) {
- if (seq->depth == 0) {
- /* test overlap, displays red outline */
- seq->flag &= ~SEQ_OVERLAP;
- if (BKE_sequence_test_overlap(seqbasep, seq)) {
- seq->flag |= SEQ_OVERLAP;
- }
- }
- }
- seq_prev = seq;
- }
-}
-
-/* ********************* UV ****************** */
-
-static void UVsToTransData(const float aspect[2],
- TransData *td,
- TransData2D *td2d,
- float *uv,
- const float *center,
- bool selected)
-{
- /* uv coords are scaled by aspects. this is needed for rotations and
- * proportional editing to be consistent with the stretched uv coords
- * that are displayed. this also means that for display and numinput,
- * and when the uv coords are flushed, these are converted each time */
- td2d->loc[0] = uv[0] * aspect[0];
- td2d->loc[1] = uv[1] * aspect[1];
- td2d->loc[2] = 0.0f;
- td2d->loc2d = uv;
-
- td->flag = 0;
- td->loc = td2d->loc;
- copy_v2_v2(td->center, center ? center : td->loc);
- td->center[2] = 0.0f;
- copy_v3_v3(td->iloc, td->loc);
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
-
- if (selected) {
- td->flag |= TD_SELECTED;
- td->dist = 0.0;
- }
- else {
- td->dist = FLT_MAX;
- }
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-}
-
-static void createTransUVs(bContext *C, TransInfo *t)
-{
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
- Scene *scene = t->scene;
- ToolSettings *ts = CTX_data_tool_settings(C);
-
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
- const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0;
- const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS);
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
-
- TransData *td = NULL;
- TransData2D *td2d = NULL;
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- BMFace *efa;
- BMIter iter, liter;
- UvElementMap *elementmap = NULL;
- BLI_bitmap *island_enabled = NULL;
- struct {
- float co[2];
- int co_num;
- } *island_center = NULL;
- int count = 0, countsel = 0, count_rejected = 0;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if (!ED_space_image_show_uvedit(sima, tc->obedit)) {
- continue;
- }
-
- /* count */
- if (is_prop_connected || is_island_center) {
- /* create element map with island information */
- const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0;
- elementmap = BM_uv_element_map_create(em->bm, use_facesel, false, true);
- if (elementmap == NULL) {
- return;
- }
-
- if (is_prop_connected) {
- island_enabled = BLI_BITMAP_NEW(elementmap->totalIslands, "TransIslandData(UV Editing)");
- }
-
- if (is_island_center) {
- island_center = MEM_callocN(sizeof(*island_center) * elementmap->totalIslands, __func__);
- }
- }
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BMLoop *l;
-
- if (!uvedit_face_visible_test(scene, tc->obedit, ima, efa)) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- continue;
- }
-
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- countsel++;
-
- if (is_prop_connected || island_center) {
- UvElement *element = BM_uv_element_get(elementmap, efa, l);
-
- if (is_prop_connected) {
- BLI_BITMAP_ENABLE(island_enabled, element->island);
- }
-
- if (is_island_center) {
- if (element->flag == false) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- add_v2_v2(island_center[element->island].co, luv->uv);
- island_center[element->island].co_num++;
- element->flag = true;
- }
- }
- }
- }
-
- if (is_prop_edit) {
- count++;
- }
- }
- }
-
- /* note: in prop mode we need at least 1 selected */
- if (countsel == 0) {
- goto finally;
- }
-
- if (is_island_center) {
- int i;
-
- for (i = 0; i < elementmap->totalIslands; i++) {
- mul_v2_fl(island_center[i].co, 1.0f / island_center[i].co_num);
- mul_v2_v2(island_center[i].co, t->aspect);
- }
- }
-
- tc->data_len = (is_prop_edit) ? count : countsel;
- tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(UV Editing)");
- /* for each 2d uv coord a 3d vector is allocated, so that they can be
- * treated just as if they were 3d verts */
- tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransObData2D(UV Editing)");
-
- if (sima->flag & SI_CLIP_UV) {
- t->flag |= T_CLIP_UV;
- }
-
- td = tc->data;
- td2d = tc->data_2d;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BMLoop *l;
-
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- const bool selected = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
- MLoopUV *luv;
- const float *center = NULL;
-
- if (!is_prop_edit && !selected) {
- continue;
- }
-
- if (is_prop_connected || is_island_center) {
- UvElement *element = BM_uv_element_get(elementmap, efa, l);
-
- if (is_prop_connected) {
- if (!BLI_BITMAP_TEST(island_enabled, element->island)) {
- count_rejected++;
- continue;
- }
- }
-
- if (is_island_center) {
- center = island_center[element->island].co;
- }
- }
-
- BM_elem_flag_enable(l, BM_ELEM_TAG);
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- UVsToTransData(t->aspect, td++, td2d++, luv->uv, center, selected);
- }
- }
-
- if (is_prop_connected) {
- tc->data_len -= count_rejected;
- }
-
- if (sima->flag & SI_LIVE_UNWRAP) {
- ED_uvedit_live_unwrap_begin(t->scene, tc->obedit);
- }
-
- finally:
- if (is_prop_connected || is_island_center) {
- BM_uv_element_map_free(elementmap);
-
- if (is_prop_connected) {
- MEM_freeN(island_enabled);
- }
-
- if (island_center) {
- MEM_freeN(island_center);
- }
- }
- }
-}
-
-void flushTransUVs(TransInfo *t)
-{
- SpaceImage *sima = t->sa->spacedata.first;
- const bool use_pixel_snap = ((sima->pixel_snap_mode != SI_PIXEL_SNAP_DISABLED) &&
- (t->state != TRANS_CANCEL));
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData2D *td;
- int a;
- float aspect_inv[2], size[2];
-
- aspect_inv[0] = 1.0f / t->aspect[0];
- aspect_inv[1] = 1.0f / t->aspect[1];
-
- if (use_pixel_snap) {
- int size_i[2];
- ED_space_image_get_size(sima, &size_i[0], &size_i[1]);
- size[0] = size_i[0];
- size[1] = size_i[1];
- }
-
- /* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = tc->data_2d; a < tc->data_len; a++, td++) {
- td->loc2d[0] = td->loc[0] * aspect_inv[0];
- td->loc2d[1] = td->loc[1] * aspect_inv[1];
-
- if (use_pixel_snap) {
- td->loc2d[0] *= size[0];
- td->loc2d[1] *= size[1];
-
- switch (sima->pixel_snap_mode) {
- case SI_PIXEL_SNAP_CENTER:
- td->loc2d[0] = roundf(td->loc2d[0] - 0.5f) + 0.5f;
- td->loc2d[1] = roundf(td->loc2d[1] - 0.5f) + 0.5f;
- break;
- case SI_PIXEL_SNAP_CORNER:
- td->loc2d[0] = roundf(td->loc2d[0]);
- td->loc2d[1] = roundf(td->loc2d[1]);
- break;
- }
-
- td->loc2d[0] /= size[0];
- td->loc2d[1] /= size[1];
- }
- }
- }
-}
-
-bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
-{
- bool clipx = true, clipy = true;
- float min[2], max[2];
-
- min[0] = min[1] = 0.0f;
- max[0] = t->aspect[0];
- max[1] = t->aspect[1];
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
-
- TransData *td;
- int a;
-
- for (a = 0, td = tc->data; a < tc->data_len; a++, td++) {
- minmax_v2v2_v2(min, max, td->loc);
- }
- }
-
- if (resize) {
- if (min[0] < 0.0f && t->center_global[0] > 0.0f && t->center_global[0] < t->aspect[0] * 0.5f) {
- vec[0] *= t->center_global[0] / (t->center_global[0] - min[0]);
- }
- else if (max[0] > t->aspect[0] && t->center_global[0] < t->aspect[0]) {
- vec[0] *= (t->center_global[0] - t->aspect[0]) / (t->center_global[0] - max[0]);
- }
- else {
- clipx = 0;
- }
-
- if (min[1] < 0.0f && t->center_global[1] > 0.0f && t->center_global[1] < t->aspect[1] * 0.5f) {
- vec[1] *= t->center_global[1] / (t->center_global[1] - min[1]);
- }
- else if (max[1] > t->aspect[1] && t->center_global[1] < t->aspect[1]) {
- vec[1] *= (t->center_global[1] - t->aspect[1]) / (t->center_global[1] - max[1]);
- }
- else {
- clipy = 0;
- }
- }
- else {
- if (min[0] < 0.0f) {
- vec[0] -= min[0];
- }
- else if (max[0] > t->aspect[0]) {
- vec[0] -= max[0] - t->aspect[0];
- }
- else {
- clipx = 0;
- }
-
- if (min[1] < 0.0f) {
- vec[1] -= min[1];
- }
- else if (max[1] > t->aspect[1]) {
- vec[1] -= max[1] - t->aspect[1];
- }
- else {
- clipy = 0;
- }
- }
-
- return (clipx || clipy);
-}
-
-void clipUVData(TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (int a = 0; a < tc->data_len; a++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if ((td->flag & TD_SKIP) || (!td->loc)) {
- continue;
- }
-
- td->loc[0] = min_ff(max_ff(0.0f, td->loc[0]), t->aspect[0]);
- td->loc[1] = min_ff(max_ff(0.0f, td->loc[1]), t->aspect[1]);
- }
- }
-}
-
-/* ********************* ANIMATION EDITORS (GENERAL) ************************* */
-
-/* This function tests if a point is on the "mouse" side of the cursor/frame-marking */
-static bool FrameOnMouseSide(char side, float frame, float cframe)
-{
- /* both sides, so it doesn't matter */
- if (side == 'B') {
- return true;
- }
-
- /* only on the named side */
- if (side == 'R') {
- return (frame >= cframe);
- }
- else {
- return (frame <= cframe);
- }
-}
-
-/* ********************* NLA EDITOR ************************* */
-
-static void createTransNlaData(bContext *C, TransInfo *t)
-{
- Scene *scene = t->scene;
- SpaceNla *snla = NULL;
- TransData *td = NULL;
- TransDataNla *tdn = NULL;
-
- bAnimContext ac;
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
-
- int count = 0;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* determine what type of data we are operating on */
- if (ANIM_animdata_get_context(C, &ac) == 0) {
- return;
- }
- snla = (SpaceNla *)ac.sl;
-
- /* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- /* which side of the current frame should be allowed */
- if (t->mode == TFM_TIME_EXTEND) {
- /* only side on which mouse is gets transformed */
- float xmouse, ymouse;
-
- UI_view2d_region_to_view(&ac.ar->v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse);
- t->frame_side = (xmouse > CFRA) ? 'R' : 'L';
- }
- else {
- /* normal transform - both sides of current frame are considered */
- t->frame_side = 'B';
- }
-
- /* loop 1: count how many strips are selected (consider each strip as 2 points) */
- for (ale = anim_data.first; ale; ale = ale->next) {
- NlaTrack *nlt = (NlaTrack *)ale->data;
- NlaStrip *strip;
-
- /* make some meta-strips for chains of selected strips */
- BKE_nlastrips_make_metas(&nlt->strips, 1);
-
- /* only consider selected strips */
- for (strip = nlt->strips.first; strip; strip = strip->next) {
- // TODO: we can make strips have handles later on...
- /* transition strips can't get directly transformed */
- if (strip->type != NLASTRIP_TYPE_TRANSITION) {
- if (strip->flag & NLASTRIP_FLAG_SELECT) {
- if (FrameOnMouseSide(t->frame_side, strip->start, (float)CFRA)) {
- count++;
- }
- if (FrameOnMouseSide(t->frame_side, strip->end, (float)CFRA)) {
- count++;
- }
- }
- }
- }
- }
-
- /* stop if trying to build list if nothing selected */
- if (count == 0) {
- /* clear temp metas that may have been created but aren't needed now
- * because they fell on the wrong side of CFRA
- */
- for (ale = anim_data.first; ale; ale = ale->next) {
- NlaTrack *nlt = (NlaTrack *)ale->data;
- BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
- }
-
- /* cleanup temp list */
- ANIM_animdata_freelist(&anim_data);
- return;
- }
-
- /* allocate memory for data */
- tc->data_len = count;
-
- tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(NLA Editor)");
- td = tc->data;
- tc->custom.type.data = tdn = MEM_callocN(tc->data_len * sizeof(TransDataNla),
- "TransDataNla (NLA Editor)");
- tc->custom.type.use_free = true;
-
- /* loop 2: build transdata array */
- for (ale = anim_data.first; ale; ale = ale->next) {
- /* only if a real NLA-track */
- if (ale->type == ANIMTYPE_NLATRACK) {
- AnimData *adt = ale->adt;
- NlaTrack *nlt = (NlaTrack *)ale->data;
- NlaStrip *strip;
-
- /* only consider selected strips */
- for (strip = nlt->strips.first; strip; strip = strip->next) {
- // TODO: we can make strips have handles later on...
- /* transition strips can't get directly transformed */
- if (strip->type != NLASTRIP_TYPE_TRANSITION) {
- if (strip->flag & NLASTRIP_FLAG_SELECT) {
- /* our transform data is constructed as follows:
- * - only the handles on the right side of the current-frame get included
- * - td structs are transform-elements operated on by the transform system
- * and represent a single handle. The storage/pointer used (val or loc) depends on
- * whether we're scaling or transforming. Ultimately though, the handles
- * the td writes to will simply be a dummy in tdn
- * - for each strip being transformed, a single tdn struct is used, so in some
- * cases, there will need to be 1 of these tdn elements in the array skipped...
- */
- float center[3], yval;
-
- /* firstly, init tdn settings */
- tdn->id = ale->id;
- tdn->oldTrack = tdn->nlt = nlt;
- tdn->strip = strip;
- tdn->trackIndex = BLI_findindex(&adt->nla_tracks, nlt);
-
- yval = (float)(tdn->trackIndex * NLACHANNEL_STEP(snla));
-
- tdn->h1[0] = strip->start;
- tdn->h1[1] = yval;
- tdn->h2[0] = strip->end;
- tdn->h2[1] = yval;
-
- center[0] = (float)CFRA;
- center[1] = yval;
- center[2] = 0.0f;
-
- /* set td's based on which handles are applicable */
- if (FrameOnMouseSide(t->frame_side, strip->start, (float)CFRA)) {
- /* just set tdn to assume that it only has one handle for now */
- tdn->handle = -1;
-
- /* now, link the transform data up to this data */
- if (ELEM(t->mode, TFM_TRANSLATION, TFM_TIME_EXTEND)) {
- td->loc = tdn->h1;
- copy_v3_v3(td->iloc, tdn->h1);
-
- /* store all the other gunk that is required by transform */
- copy_v3_v3(td->center, center);
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
-
- td->flag |= TD_SELECTED;
- td->dist = 0.0f;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
- }
- else {
- /* time scaling only needs single value */
- td->val = &tdn->h1[0];
- td->ival = tdn->h1[0];
- }
-
- td->extra = tdn;
- td++;
- }
- if (FrameOnMouseSide(t->frame_side, strip->end, (float)CFRA)) {
- /* if tdn is already holding the start handle,
- * then we're doing both, otherwise, only end */
- tdn->handle = (tdn->handle) ? 2 : 1;
-
- /* now, link the transform data up to this data */
- if (ELEM(t->mode, TFM_TRANSLATION, TFM_TIME_EXTEND)) {
- td->loc = tdn->h2;
- copy_v3_v3(td->iloc, tdn->h2);
-
- /* store all the other gunk that is required by transform */
- copy_v3_v3(td->center, center);
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
-
- td->flag |= TD_SELECTED;
- td->dist = 0.0f;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
- }
- else {
- /* time scaling only needs single value */
- td->val = &tdn->h2[0];
- td->ival = tdn->h2[0];
- }
-
- td->extra = tdn;
- td++;
- }
-
- /* If both handles were used, skip the next tdn (i.e. leave it blank)
- * since the counting code is dumb.
- * Otherwise, just advance to the next one.
- */
- if (tdn->handle == 2) {
- tdn += 2;
- }
- else {
- tdn++;
- }
- }
- }
- }
- }
- }
-
- /* cleanup temp list */
- ANIM_animdata_freelist(&anim_data);
-}
-
-/* ********************* ACTION EDITOR ****************** */
-
-static int gpf_cmp_frame(void *thunk, const void *a, const void *b)
-{
- const bGPDframe *frame_a = a;
- const bGPDframe *frame_b = b;
-
- if (frame_a->framenum < frame_b->framenum) {
- return -1;
- }
- if (frame_a->framenum > frame_b->framenum) {
- return 1;
- }
- *((bool *)thunk) = true;
- /* selected last */
- if ((frame_a->flag & GP_FRAME_SELECT) && ((frame_b->flag & GP_FRAME_SELECT) == 0)) {
- return 1;
- }
- return 0;
-}
-
-static int masklay_shape_cmp_frame(void *thunk, const void *a, const void *b)
-{
- const MaskLayerShape *frame_a = a;
- const MaskLayerShape *frame_b = b;
-
- if (frame_a->frame < frame_b->frame) {
- return -1;
- }
- if (frame_a->frame > frame_b->frame) {
- return 1;
- }
- *((bool *)thunk) = true;
- /* selected last */
- if ((frame_a->flag & MASK_SHAPE_SELECT) && ((frame_b->flag & MASK_SHAPE_SELECT) == 0)) {
- return 1;
- }
- return 0;
-}
-
-/* Called by special_aftertrans_update to make sure selected gp-frames replace
- * any other gp-frames which may reside on that frame (that are not selected).
- * It also makes sure gp-frames are still stored in chronological order after
- * transform.
- */
-static void posttrans_gpd_clean(bGPdata *gpd)
-{
- bGPDlayer *gpl;
-
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- bGPDframe *gpf, *gpfn;
- bool is_double = false;
-
- BLI_listbase_sort_r(&gpl->frames, gpf_cmp_frame, &is_double);
-
- if (is_double) {
- for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
- gpfn = gpf->next;
- if (gpfn && gpf->framenum == gpfn->framenum) {
- BKE_gpencil_layer_delframe(gpl, gpf);
- }
- }
- }
-
-#ifdef DEBUG
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- BLI_assert(!gpf->next || gpf->framenum < gpf->next->framenum);
- }
-#endif
- }
- /* set cache flag to dirty */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
-}
-
-static void posttrans_mask_clean(Mask *mask)
-{
- MaskLayer *masklay;
-
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskLayerShape *masklay_shape, *masklay_shape_next;
- bool is_double = false;
-
- BLI_listbase_sort_r(&masklay->splines_shapes, masklay_shape_cmp_frame, &is_double);
-
- if (is_double) {
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
- masklay_shape = masklay_shape_next) {
- masklay_shape_next = masklay_shape->next;
- if (masklay_shape_next && masklay_shape->frame == masklay_shape_next->frame) {
- BKE_mask_layer_shape_unlink(masklay, masklay_shape);
- }
- }
- }
-
-#ifdef DEBUG
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
- masklay_shape = masklay_shape->next) {
- BLI_assert(!masklay_shape->next || masklay_shape->frame < masklay_shape->next->frame);
- }
-#endif
- }
-}
-
-/* Time + Average value */
-typedef struct tRetainedKeyframe {
- struct tRetainedKeyframe *next, *prev;
- float frame; /* frame to cluster around */
- float val; /* average value */
-
- size_t tot_count; /* number of keyframes that have been averaged */
- size_t del_count; /* number of keyframes of this sort that have been deleted so far */
-} tRetainedKeyframe;
-
-/* Called during special_aftertrans_update to make sure selected keyframes replace
- * any other keyframes which may reside on that frame (that is not selected).
- */
-static void posttrans_fcurve_clean(FCurve *fcu, const bool use_handle)
-{
- /* NOTE: We assume that all keys are sorted */
- ListBase retained_keys = {NULL, NULL};
- const bool can_average_points = ((fcu->flag & (FCURVE_INT_VALUES | FCURVE_DISCRETE_VALUES)) ==
- 0);
-
- /* sanity checks */
- if ((fcu->totvert == 0) || (fcu->bezt == NULL)) {
- return;
- }
-
- /* 1) Identify selected keyframes, and average the values on those
- * in case there are collisions due to multiple keys getting scaled
- * to all end up on the same frame
- */
- for (int i = 0; i < fcu->totvert; i++) {
- BezTriple *bezt = &fcu->bezt[i];
-
- if (BEZT_ISSEL_ANY(bezt)) {
- bool found = false;
-
- /* If there's another selected frame here, merge it */
- for (tRetainedKeyframe *rk = retained_keys.last; rk; rk = rk->prev) {
- if (IS_EQT(rk->frame, bezt->vec[1][0], BEZT_BINARYSEARCH_THRESH)) {
- rk->val += bezt->vec[1][1];
- rk->tot_count++;
-
- found = true;
- break;
- }
- else if (rk->frame < bezt->vec[1][0]) {
- /* Terminate early if have passed the supposed insertion point? */
- break;
- }
- }
-
- /* If nothing found yet, create a new one */
- if (found == false) {
- tRetainedKeyframe *rk = MEM_callocN(sizeof(tRetainedKeyframe), "tRetainedKeyframe");
-
- rk->frame = bezt->vec[1][0];
- rk->val = bezt->vec[1][1];
- rk->tot_count = 1;
-
- BLI_addtail(&retained_keys, rk);
- }
- }
- }
-
- if (BLI_listbase_is_empty(&retained_keys)) {
- /* This may happen if none of the points were selected... */
- if (G.debug & G_DEBUG) {
- printf("%s: nothing to do for FCurve %p (rna_path = '%s')\n", __func__, fcu, fcu->rna_path);
- }
- return;
- }
- else {
- /* Compute the average values for each retained keyframe */
- for (tRetainedKeyframe *rk = retained_keys.first; rk; rk = rk->next) {
- rk->val = rk->val / (float)rk->tot_count;
- }
- }
-
- /* 2) Delete all keyframes duplicating the "retained keys" found above
- * - Most of these will be unselected keyframes
- * - Some will be selected keyframes though. For those, we only keep the last one
- * (or else everything is gone), and replace its value with the averaged value.
- */
- for (int i = fcu->totvert - 1; i >= 0; i--) {
- BezTriple *bezt = &fcu->bezt[i];
-
- /* Is this keyframe a candidate for deletion? */
- /* TODO: Replace loop with an O(1) lookup instead */
- for (tRetainedKeyframe *rk = retained_keys.last; rk; rk = rk->prev) {
- if (IS_EQT(bezt->vec[1][0], rk->frame, BEZT_BINARYSEARCH_THRESH)) {
- /* Selected keys are treated with greater care than unselected ones... */
- if (BEZT_ISSEL_ANY(bezt)) {
- /* - If this is the last selected key left (based on rk->del_count) ==> UPDATE IT
- * (or else we wouldn't have any keyframe left here)
- * - Otherwise, there are still other selected keyframes on this frame
- * to be merged down still ==> DELETE IT
- */
- if (rk->del_count == rk->tot_count - 1) {
- /* Update keyframe... */
- if (can_average_points) {
- /* TODO: update handles too? */
- bezt->vec[1][1] = rk->val;
- }
- }
- else {
- /* Delete Keyframe */
- delete_fcurve_key(fcu, i, 0);
- }
-
- /* Update count of how many we've deleted
- * - It should only matter that we're doing this for all but the last one
- */
- rk->del_count++;
- }
- else {
- /* Always delete - Unselected keys don't matter */
- delete_fcurve_key(fcu, i, 0);
- }
-
- /* Stop the RK search... we've found our match now */
- break;
- }
- }
- }
-
- /* 3) Recalculate handles */
- testhandles_fcurve(fcu, use_handle);
-
- /* cleanup */
- BLI_freelistN(&retained_keys);
-}
-
-/* Called by special_aftertrans_update to make sure selected keyframes replace
- * any other keyframes which may reside on that frame (that is not selected).
- * remake_action_ipos should have already been called
- */
-static void posttrans_action_clean(bAnimContext *ac, bAction *act)
-{
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
-
- /* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
- ANIM_animdata_filter(ac, &anim_data, filter, act, ANIMCONT_ACTION);
-
- /* loop through relevant data, removing keyframes as appropriate
- * - all keyframes are converted in/out of global time
- */
- for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(ac, ale);
-
- if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
- posttrans_fcurve_clean(ale->key_data, false); /* only use handles in graph editor */
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
- }
- else {
- posttrans_fcurve_clean(ale->key_data, false); /* only use handles in graph editor */
- }
- }
-
- /* free temp data */
- ANIM_animdata_freelist(&anim_data);
-}
-
-/* ----------------------------- */
-
-/* fully select selected beztriples, but only include if it's on the right side of cfra */
-static int count_fcurve_keys(FCurve *fcu, char side, float cfra, bool is_prop_edit)
-{
- BezTriple *bezt;
- int i, count = 0, count_all = 0;
-
- if (ELEM(NULL, fcu, fcu->bezt)) {
- return count;
- }
-
- /* only include points that occur on the right side of cfra */
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
- /* no need to adjust the handle selection since they are assumed
- * selected (like graph editor with SIPO_NOHANDLES) */
- if (bezt->f2 & SELECT) {
- count++;
- }
-
- count_all++;
- }
- }
-
- if (is_prop_edit && count > 0) {
- return count_all;
- }
- else {
- return count;
- }
-}
-
-/* fully select selected beztriples, but only include if it's on the right side of cfra */
-static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra, bool is_prop_edit)
-{
- bGPDframe *gpf;
- int count = 0, count_all = 0;
-
- if (gpl == NULL) {
- return count;
- }
-
- /* only include points that occur on the right side of cfra */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) {
- if (gpf->flag & GP_FRAME_SELECT) {
- count++;
- }
- count_all++;
- }
- }
-
- if (is_prop_edit && count > 0) {
- return count_all;
- }
- else {
- return count;
- }
-}
-
-/* fully select selected beztriples, but only include if it's on the right side of cfra */
-static int count_masklayer_frames(MaskLayer *masklay, char side, float cfra, bool is_prop_edit)
-{
- MaskLayerShape *masklayer_shape;
- int count = 0, count_all = 0;
-
- if (masklay == NULL) {
- return count;
- }
-
- /* only include points that occur on the right side of cfra */
- for (masklayer_shape = masklay->splines_shapes.first; masklayer_shape;
- masklayer_shape = masklayer_shape->next) {
- if (FrameOnMouseSide(side, (float)masklayer_shape->frame, cfra)) {
- if (masklayer_shape->flag & MASK_SHAPE_SELECT) {
- count++;
- }
- count_all++;
- }
- }
-
- if (is_prop_edit && count > 0) {
- return count_all;
- }
- else {
- return count;
- }
-}
-
-/* This function assigns the information to transdata */
-static void TimeToTransData(TransData *td, float *time, AnimData *adt, float ypos)
-{
- /* memory is calloc'ed, so that should zero everything nicely for us */
- td->val = time;
- td->ival = *(time);
-
- td->center[0] = td->ival;
- td->center[1] = ypos;
-
- /* store the AnimData where this keyframe exists as a keyframe of the
- * active action as td->extra.
- */
- td->extra = adt;
-}
-
-/* This function advances the address to which td points to, so it must return
- * the new address so that the next time new transform data is added, it doesn't
- * overwrite the existing ones... i.e. td = IcuToTransData(td, icu, ob, side, cfra);
- *
- * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
- * on the named side are used.
- */
-static TransData *ActionFCurveToTransData(TransData *td,
- TransData2D **td2dv,
- FCurve *fcu,
- AnimData *adt,
- char side,
- float cfra,
- bool is_prop_edit,
- float ypos)
-{
- BezTriple *bezt;
- TransData2D *td2d = *td2dv;
- int i;
-
- if (ELEM(NULL, fcu, fcu->bezt)) {
- return td;
- }
-
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- /* only add selected keyframes (for now, proportional edit is not enabled) */
- if (is_prop_edit || (bezt->f2 & SELECT)) { /* note this MUST match count_fcurve_keys(),
- * so can't use BEZT_ISSEL_ANY() macro */
- /* only add if on the right 'side' of the current frame */
- if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
- TimeToTransData(td, bezt->vec[1], adt, ypos);
-
- if (bezt->f2 & SELECT) {
- td->flag |= TD_SELECTED;
- }
-
- /*set flags to move handles as necessary*/
- td->flag |= TD_MOVEHANDLE1 | TD_MOVEHANDLE2;
- td2d->h1 = bezt->vec[0];
- td2d->h2 = bezt->vec[2];
-
- copy_v2_v2(td2d->ih1, td2d->h1);
- copy_v2_v2(td2d->ih2, td2d->h2);
-
- td++;
- td2d++;
- }
- }
- }
-
- *td2dv = td2d;
-
- return td;
-}
-
-/* helper struct for gp-frame transforms (only used here) */
-typedef struct tGPFtransdata {
- float val; /* where transdata writes transform */
- int *sdata; /* pointer to gpf->framenum */
-} tGPFtransdata;
-
-/* This function helps flush transdata written to tempdata into the gp-frames */
-void flushTransIntFrameActionData(TransInfo *t)
-{
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
- tGPFtransdata *tfd = tc->custom.type.data;
-
- /* flush data! */
- for (int i = 0; i < tc->data_len; i++, tfd++) {
- *(tfd->sdata) = round_fl_to_int(tfd->val);
- }
-}
-
-/* This function advances the address to which td points to, so it must return
- * the new address so that the next time new transform data is added, it doesn't
- * overwrite the existing ones... i.e. td = GPLayerToTransData(td, ipo, ob, side, cfra);
- *
- * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
- * on the named side are used.
- */
-static int GPLayerToTransData(TransData *td,
- tGPFtransdata *tfd,
- bGPDlayer *gpl,
- char side,
- float cfra,
- bool is_prop_edit,
- float ypos)
-{
- bGPDframe *gpf;
- int count = 0;
-
- /* check for select frames on right side of current frame */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if (is_prop_edit || (gpf->flag & GP_FRAME_SELECT)) {
- if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) {
- /* memory is calloc'ed, so that should zero everything nicely for us */
- td->val = &tfd->val;
- td->ival = (float)gpf->framenum;
-
- td->center[0] = td->ival;
- td->center[1] = ypos;
-
- tfd->val = (float)gpf->framenum;
- tfd->sdata = &gpf->framenum;
-
- /* advance td now */
- td++;
- tfd++;
- count++;
- }
- }
- }
-
- return count;
-}
-
-/* refer to comment above #GPLayerToTransData, this is the same but for masks */
-static int MaskLayerToTransData(TransData *td,
- tGPFtransdata *tfd,
- MaskLayer *masklay,
- char side,
- float cfra,
- bool is_prop_edit,
- float ypos)
-{
- MaskLayerShape *masklay_shape;
- int count = 0;
-
- /* check for select frames on right side of current frame */
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
- masklay_shape = masklay_shape->next) {
- if (is_prop_edit || (masklay_shape->flag & MASK_SHAPE_SELECT)) {
- if (FrameOnMouseSide(side, (float)masklay_shape->frame, cfra)) {
- /* memory is calloc'ed, so that should zero everything nicely for us */
- td->val = &tfd->val;
- td->ival = (float)masklay_shape->frame;
-
- td->center[0] = td->ival;
- td->center[1] = ypos;
-
- tfd->val = (float)masklay_shape->frame;
- tfd->sdata = &masklay_shape->frame;
-
- /* advance td now */
- td++;
- tfd++;
- count++;
- }
- }
- }
-
- return count;
-}
-
-static void createTransActionData(bContext *C, TransInfo *t)
-{
- Scene *scene = t->scene;
- TransData *td = NULL;
- TransData2D *td2d = NULL;
- tGPFtransdata *tfd = NULL;
-
- rcti *mask = &t->ar->v2d.mask;
- rctf *datamask = &t->ar->v2d.cur;
-
- float xsize = BLI_rctf_size_x(datamask);
- float ysize = BLI_rctf_size_y(datamask);
- float xmask = BLI_rcti_size_x(mask);
- float ymask = BLI_rcti_size_y(mask);
-
- bAnimContext ac;
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
-
- int count = 0;
- float cfra;
- float ypos = 1.0f / ((ysize / xsize) * (xmask / ymask)) * BLI_rctf_cent_y(&t->ar->v2d.cur);
-
- /* determine what type of data we are operating on */
- if (ANIM_animdata_get_context(C, &ac) == 0) {
- return;
- }
-
- /* filter data */
- if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT);
- }
- else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
- }
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- /* which side of the current frame should be allowed */
- if (t->mode == TFM_TIME_EXTEND) {
- /* only side on which mouse is gets transformed */
- float xmouse, ymouse;
-
- UI_view2d_region_to_view(&ac.ar->v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse);
- t->frame_side = (xmouse > CFRA) ? 'R' : 'L'; // XXX use t->frame_side
- }
- else {
- /* normal transform - both sides of current frame are considered */
- t->frame_side = 'B';
- }
-
- /* loop 1: fully select ipo-keys and count how many BezTriples are selected */
- for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
- int adt_count = 0;
- /* convert current-frame to action-time (slightly less accurate, especially under
- * higher scaling ratios, but is faster than converting all points)
- */
- if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
- }
- else {
- cfra = (float)CFRA;
- }
-
- if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
- adt_count = count_fcurve_keys(ale->key_data, t->frame_side, cfra, is_prop_edit);
- }
- else if (ale->type == ANIMTYPE_GPLAYER) {
- adt_count = count_gplayer_frames(ale->data, t->frame_side, cfra, is_prop_edit);
- }
- else if (ale->type == ANIMTYPE_MASKLAYER) {
- adt_count = count_masklayer_frames(ale->data, t->frame_side, cfra, is_prop_edit);
- }
- else {
- BLI_assert(0);
- }
-
- if (adt_count > 0) {
- count += adt_count;
- ale->tag = true;
- }
- }
-
- /* stop if trying to build list if nothing selected */
- if (count == 0) {
- /* cleanup temp list */
- ANIM_animdata_freelist(&anim_data);
- return;
- }
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* allocate memory for data */
- tc->data_len = count;
-
- tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(Action Editor)");
- tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "transdata2d");
- td = tc->data;
- td2d = tc->data_2d;
-
- if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- tc->custom.type.data = tfd = MEM_callocN(sizeof(tGPFtransdata) * count, "tGPFtransdata");
- tc->custom.type.use_free = true;
- }
-
- /* loop 2: build transdata array */
- for (ale = anim_data.first; ale; ale = ale->next) {
-
- if (is_prop_edit && !ale->tag) {
- continue;
- }
-
- cfra = (float)CFRA;
-
- {
- AnimData *adt;
- adt = ANIM_nla_mapping_get(&ac, ale);
- if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
- }
- }
-
- if (ale->type == ANIMTYPE_GPLAYER) {
- bGPDlayer *gpl = (bGPDlayer *)ale->data;
- int i;
-
- i = GPLayerToTransData(td, tfd, gpl, t->frame_side, cfra, is_prop_edit, ypos);
- td += i;
- tfd += i;
- }
- else if (ale->type == ANIMTYPE_MASKLAYER) {
- MaskLayer *masklay = (MaskLayer *)ale->data;
- int i;
-
- i = MaskLayerToTransData(td, tfd, masklay, t->frame_side, cfra, is_prop_edit, ypos);
- td += i;
- tfd += i;
- }
- else {
- AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
- FCurve *fcu = (FCurve *)ale->key_data;
-
- td = ActionFCurveToTransData(td, &td2d, fcu, adt, t->frame_side, cfra, is_prop_edit, ypos);
- }
- }
-
- /* calculate distances for proportional editing */
- if (is_prop_edit) {
- td = tc->data;
-
- for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt;
-
- /* F-Curve may not have any keyframes */
- if (!ale->tag) {
- continue;
- }
-
- adt = ANIM_nla_mapping_get(&ac, ale);
- if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
- }
- else {
- cfra = (float)CFRA;
- }
-
- if (ale->type == ANIMTYPE_GPLAYER) {
- bGPDlayer *gpl = (bGPDlayer *)ale->data;
- bGPDframe *gpf;
-
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if (gpf->flag & GP_FRAME_SELECT) {
- td->dist = td->rdist = 0.0f;
- }
- else {
- bGPDframe *gpf_iter;
- int min = INT_MAX;
- for (gpf_iter = gpl->frames.first; gpf_iter; gpf_iter = gpf_iter->next) {
- if (gpf_iter->flag & GP_FRAME_SELECT) {
- if (FrameOnMouseSide(t->frame_side, (float)gpf_iter->framenum, cfra)) {
- int val = abs(gpf->framenum - gpf_iter->framenum);
- if (val < min) {
- min = val;
- }
- }
- }
- }
- td->dist = td->rdist = min;
- }
- td++;
- }
- }
- else if (ale->type == ANIMTYPE_MASKLAYER) {
- MaskLayer *masklay = (MaskLayer *)ale->data;
- MaskLayerShape *masklay_shape;
-
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
- masklay_shape = masklay_shape->next) {
- if (FrameOnMouseSide(t->frame_side, (float)masklay_shape->frame, cfra)) {
- if (masklay_shape->flag & MASK_SHAPE_SELECT) {
- td->dist = td->rdist = 0.0f;
- }
- else {
- MaskLayerShape *masklay_iter;
- int min = INT_MAX;
- for (masklay_iter = masklay->splines_shapes.first; masklay_iter;
- masklay_iter = masklay_iter->next) {
- if (masklay_iter->flag & MASK_SHAPE_SELECT) {
- if (FrameOnMouseSide(t->frame_side, (float)masklay_iter->frame, cfra)) {
- int val = abs(masklay_shape->frame - masklay_iter->frame);
- if (val < min) {
- min = val;
- }
- }
- }
- }
- td->dist = td->rdist = min;
- }
- td++;
- }
- }
- }
- else {
- FCurve *fcu = (FCurve *)ale->key_data;
- BezTriple *bezt;
- int i;
-
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
- if (bezt->f2 & SELECT) {
- td->dist = td->rdist = 0.0f;
- }
- else {
- BezTriple *bezt_iter;
- int j;
- float min = FLT_MAX;
- for (j = 0, bezt_iter = fcu->bezt; j < fcu->totvert; j++, bezt_iter++) {
- if (bezt_iter->f2 & SELECT) {
- if (FrameOnMouseSide(t->frame_side, (float)bezt_iter->vec[1][0], cfra)) {
- float val = fabs(bezt->vec[1][0] - bezt_iter->vec[1][0]);
- if (val < min) {
- min = val;
- }
- }
- }
- }
- td->dist = td->rdist = min;
- }
- td++;
- }
- }
- }
- }
- }
-
- /* cleanup temp list */
- ANIM_animdata_freelist(&anim_data);
-}
-
-/* ********************* GRAPH EDITOR ************************* */
-
-typedef struct TransDataGraph {
- float unit_scale;
- float offset;
-} TransDataGraph;
-
-/* Helper function for createTransGraphEditData, which is responsible for associating
- * source data with transform data
- */
-static void bezt_to_transdata(TransData *td,
- TransData2D *td2d,
- TransDataGraph *tdg,
- AnimData *adt,
- BezTriple *bezt,
- int bi,
- bool selected,
- bool ishandle,
- bool intvals,
- float mtx[3][3],
- float smtx[3][3],
- float unit_scale,
- float offset)
-{
- float *loc = bezt->vec[bi];
- const float *cent = bezt->vec[1];
-
- /* New location from td gets dumped onto the old-location of td2d, which then
- * gets copied to the actual data at td2d->loc2d (bezt->vec[n])
- *
- * Due to NLA mapping, we apply NLA mapping to some of the verts here,
- * and then that mapping will be undone after transform is done.
- */
-
- if (adt) {
- td2d->loc[0] = BKE_nla_tweakedit_remap(adt, loc[0], NLATIME_CONVERT_MAP);
- td2d->loc[1] = (loc[1] + offset) * unit_scale;
- td2d->loc[2] = 0.0f;
- td2d->loc2d = loc;
-
- td->loc = td2d->loc;
- td->center[0] = BKE_nla_tweakedit_remap(adt, cent[0], NLATIME_CONVERT_MAP);
- td->center[1] = (cent[1] + offset) * unit_scale;
- td->center[2] = 0.0f;
-
- copy_v3_v3(td->iloc, td->loc);
- }
- else {
- td2d->loc[0] = loc[0];
- td2d->loc[1] = (loc[1] + offset) * unit_scale;
- td2d->loc[2] = 0.0f;
- td2d->loc2d = loc;
-
- td->loc = td2d->loc;
- copy_v3_v3(td->center, cent);
- td->center[1] = (td->center[1] + offset) * unit_scale;
- copy_v3_v3(td->iloc, td->loc);
- }
-
- if (!ishandle) {
- td2d->h1 = bezt->vec[0];
- td2d->h2 = bezt->vec[2];
- copy_v2_v2(td2d->ih1, td2d->h1);
- copy_v2_v2(td2d->ih2, td2d->h2);
- }
- else {
- td2d->h1 = NULL;
- td2d->h2 = NULL;
- }
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
-
- /* store AnimData info in td->extra, for applying mapping when flushing */
- td->extra = adt;
-
- if (selected) {
- td->flag |= TD_SELECTED;
- td->dist = 0.0f;
- }
- else {
- td->dist = FLT_MAX;
- }
-
- if (ishandle) {
- td->flag |= TD_NOTIMESNAP;
- }
- if (intvals) {
- td->flag |= TD_INTVALUES;
- }
-
- /* copy space-conversion matrices for dealing with non-uniform scales */
- copy_m3_m3(td->mtx, mtx);
- copy_m3_m3(td->smtx, smtx);
-
- tdg->unit_scale = unit_scale;
- tdg->offset = offset;
-}
-
-static bool graph_edit_is_translation_mode(TransInfo *t)
-{
- return ELEM(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE, TFM_TIME_DUPLICATE);
-}
-
-static bool graph_edit_use_local_center(TransInfo *t)
-{
- return ((t->around == V3D_AROUND_LOCAL_ORIGINS) && (graph_edit_is_translation_mode(t) == false));
-}
-
-static void graph_key_shortest_dist(
- TransInfo *t, FCurve *fcu, TransData *td_start, TransData *td, int cfra, bool use_handle)
-{
- int j = 0;
- TransData *td_iter = td_start;
-
- td->dist = FLT_MAX;
- for (; j < fcu->totvert; j++) {
- BezTriple *bezt = fcu->bezt + j;
- if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
- const bool sel2 = (bezt->f2 & SELECT) != 0;
- const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
- const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
-
- if (sel1 || sel2 || sel3) {
- td->dist = td->rdist = min_ff(td->dist, fabs(td_iter->center[0] - td->center[0]));
- }
-
- td_iter += 3;
- }
- }
-}
-
-static void createTransGraphEditData(bContext *C, TransInfo *t)
-{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
- Scene *scene = t->scene;
- ARegion *ar = t->ar;
- View2D *v2d = &ar->v2d;
-
- TransData *td = NULL;
- TransData2D *td2d = NULL;
- TransDataGraph *tdg = NULL;
-
- bAnimContext ac;
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
-
- BezTriple *bezt;
- int count = 0, i;
- float mtx[3][3], smtx[3][3];
- const bool is_translation_mode = graph_edit_is_translation_mode(t);
- const bool use_handle = !(sipo->flag & SIPO_NOHANDLES);
- const bool use_local_center = graph_edit_use_local_center(t);
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
- short anim_map_flag = ANIM_UNITCONV_ONLYSEL | ANIM_UNITCONV_SELVERTS;
-
- /* determine what type of data we are operating on */
- if (ANIM_animdata_get_context(C, &ac) == 0) {
- return;
- }
-
- anim_map_flag |= ANIM_get_normalization_flags(&ac);
-
- /* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- /* which side of the current frame should be allowed */
- // XXX we still want this mode, but how to get this using standard transform too?
- if (t->mode == TFM_TIME_EXTEND) {
- /* only side on which mouse is gets transformed */
- float xmouse, ymouse;
-
- UI_view2d_region_to_view(v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse);
- t->frame_side = (xmouse > CFRA) ? 'R' : 'L'; // XXX use t->frame_side
- }
- else {
- /* normal transform - both sides of current frame are considered */
- t->frame_side = 'B';
- }
-
- /* Loop 1: count how many BezTriples (specifically their verts)
- * are selected (or should be edited). */
- for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
- FCurve *fcu = (FCurve *)ale->key_data;
- float cfra;
- int curvecount = 0;
- bool selected = false;
-
- /* F-Curve may not have any keyframes */
- if (fcu->bezt == NULL) {
- continue;
- }
-
- /* convert current-frame to action-time (slightly less accurate, especially under
- * higher scaling ratios, but is faster than converting all points)
- */
- if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
- }
- else {
- cfra = (float)CFRA;
- }
-
- /* Only include BezTriples whose 'keyframe'
- * occurs on the same side of the current frame as mouse. */
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
- const bool sel2 = (bezt->f2 & SELECT) != 0;
- const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
- const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
-
- if (is_prop_edit) {
- curvecount += 3;
- if (sel2 || sel1 || sel3) {
- selected = true;
- }
- }
- else {
- if (!is_translation_mode || !(sel2)) {
- if (sel1) {
- count++;
- }
-
- if (sel3) {
- count++;
- }
- }
-
- /* only include main vert if selected */
- if (sel2 && !use_local_center) {
- count++;
- }
- }
- }
- }
-
- if (is_prop_edit) {
- if (selected) {
- count += curvecount;
- ale->tag = true;
- }
- }
- }
-
- /* stop if trying to build list if nothing selected */
- if (count == 0) {
- /* cleanup temp list */
- ANIM_animdata_freelist(&anim_data);
- return;
- }
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* allocate memory for data */
- tc->data_len = count;
-
- tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData (Graph Editor)");
- /* For each 2d vert a 3d vector is allocated,
- * so that they can be treated just as if they were 3d verts. */
- tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransData2D (Graph Editor)");
- tc->custom.type.data = MEM_callocN(tc->data_len * sizeof(TransDataGraph), "TransDataGraph");
- tc->custom.type.use_free = true;
-
- td = tc->data;
- td2d = tc->data_2d;
- tdg = tc->custom.type.data;
-
- /* precompute space-conversion matrices for dealing with non-uniform scaling of Graph Editor */
- unit_m3(mtx);
- unit_m3(smtx);
-
- if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) {
- float xscale, yscale;
-
- /* apply scale factors to x and y axes of space-conversion matrices */
- UI_view2d_scale_get(v2d, &xscale, &yscale);
-
- /* mtx is data to global (i.e. view) conversion */
- mul_v3_fl(mtx[0], xscale);
- mul_v3_fl(mtx[1], yscale);
-
- /* smtx is global (i.e. view) to data conversion */
- if (IS_EQF(xscale, 0.0f) == 0) {
- mul_v3_fl(smtx[0], 1.0f / xscale);
- }
- if (IS_EQF(yscale, 0.0f) == 0) {
- mul_v3_fl(smtx[1], 1.0f / yscale);
- }
- }
-
- /* loop 2: build transdata arrays */
- for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
- FCurve *fcu = (FCurve *)ale->key_data;
- bool intvals = (fcu->flag & FCURVE_INT_VALUES) != 0;
- float unit_scale, offset;
- float cfra;
-
- /* F-Curve may not have any keyframes */
- if (fcu->bezt == NULL || (is_prop_edit && ale->tag == 0)) {
- continue;
- }
-
- /* convert current-frame to action-time (slightly less accurate, especially under
- * higher scaling ratios, but is faster than converting all points)
- */
- if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
- }
- else {
- cfra = (float)CFRA;
- }
-
- unit_scale = ANIM_unit_mapping_get_factor(
- ac.scene, ale->id, ale->key_data, anim_map_flag, &offset);
-
- /* only include BezTriples whose 'keyframe' occurs on the same side
- * of the current frame as mouse (if applicable) */
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
- const bool sel2 = (bezt->f2 & SELECT) != 0;
- const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
- const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
-
- TransDataCurveHandleFlags *hdata = NULL;
- /* short h1=1, h2=1; */ /* UNUSED */
-
- if (is_prop_edit) {
- bool is_sel = (sel2 || sel1 || sel3);
- /* we always select all handles for proportional editing if central handle is selected */
- initTransDataCurveHandles(td, bezt);
- bezt_to_transdata(td++,
- td2d++,
- tdg++,
- adt,
- bezt,
- 0,
- is_sel,
- true,
- intvals,
- mtx,
- smtx,
- unit_scale,
- offset);
- initTransDataCurveHandles(td, bezt);
- bezt_to_transdata(td++,
- td2d++,
- tdg++,
- adt,
- bezt,
- 1,
- is_sel,
- false,
- intvals,
- mtx,
- smtx,
- unit_scale,
- offset);
- initTransDataCurveHandles(td, bezt);
- bezt_to_transdata(td++,
- td2d++,
- tdg++,
- adt,
- bezt,
- 2,
- is_sel,
- true,
- intvals,
- mtx,
- smtx,
- unit_scale,
- offset);
- }
- else {
- /* only include handles if selected, irrespective of the interpolation modes.
- * also, only treat handles specially if the center point isn't selected.
- */
- if (!is_translation_mode || !(sel2)) {
- if (sel1) {
- hdata = initTransDataCurveHandles(td, bezt);
- bezt_to_transdata(td++,
- td2d++,
- tdg++,
- adt,
- bezt,
- 0,
- sel1,
- true,
- intvals,
- mtx,
- smtx,
- unit_scale,
- offset);
- }
- else {
- /* h1 = 0; */ /* UNUSED */
- }
-
- if (sel3) {
- if (hdata == NULL) {
- hdata = initTransDataCurveHandles(td, bezt);
- }
- bezt_to_transdata(td++,
- td2d++,
- tdg++,
- adt,
- bezt,
- 2,
- sel3,
- true,
- intvals,
- mtx,
- smtx,
- unit_scale,
- offset);
- }
- else {
- /* h2 = 0; */ /* UNUSED */
- }
- }
-
- /* only include main vert if selected */
- if (sel2 && !use_local_center) {
- /* move handles relative to center */
- if (is_translation_mode) {
- if (sel1) {
- td->flag |= TD_MOVEHANDLE1;
- }
- if (sel3) {
- td->flag |= TD_MOVEHANDLE2;
- }
- }
-
- /* if handles were not selected, store their selection status */
- if (!(sel1) || !(sel3)) {
- if (hdata == NULL) {
- hdata = initTransDataCurveHandles(td, bezt);
- }
- }
-
- bezt_to_transdata(td++,
- td2d++,
- tdg++,
- adt,
- bezt,
- 1,
- sel2,
- false,
- intvals,
- mtx,
- smtx,
- unit_scale,
- offset);
- }
- /* Special hack (must be done after #initTransDataCurveHandles(),
- * as that stores handle settings to restore...):
- *
- * - Check if we've got entire BezTriple selected and we're scaling/rotating that point,
- * then check if we're using auto-handles.
- * - If so, change them auto-handles to aligned handles so that handles get affected too
- */
- if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) && ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM) &&
- ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) {
- if (hdata && (sel1) && (sel3)) {
- bezt->h1 = HD_ALIGN;
- bezt->h2 = HD_ALIGN;
- }
- }
- }
- }
- }
-
- /* Sets handles based on the selection */
- testhandles_fcurve(fcu, use_handle);
- }
-
- if (is_prop_edit) {
- /* loop 2: build transdata arrays */
- td = tc->data;
-
- for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
- FCurve *fcu = (FCurve *)ale->key_data;
- TransData *td_start = td;
- float cfra;
-
- /* F-Curve may not have any keyframes */
- if (fcu->bezt == NULL || (ale->tag == 0)) {
- continue;
- }
-
- /* convert current-frame to action-time (slightly less accurate, especially under
- * higher scaling ratios, but is faster than converting all points)
- */
- if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
- }
- else {
- cfra = (float)CFRA;
- }
-
- /* only include BezTriples whose 'keyframe' occurs on the
- * same side of the current frame as mouse (if applicable) */
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
- const bool sel2 = (bezt->f2 & SELECT) != 0;
- const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
- const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
-
- if (sel1 || sel2) {
- td->dist = td->rdist = 0.0f;
- }
- else {
- graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
- }
- td++;
-
- if (sel2) {
- td->dist = td->rdist = 0.0f;
- }
- else {
- graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
- }
- td++;
-
- if (sel3 || sel2) {
- td->dist = td->rdist = 0.0f;
- }
- else {
- graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
- }
- td++;
- }
- }
- }
- }
-
- /* cleanup temp list */
- ANIM_animdata_freelist(&anim_data);
-}
-
-/* ------------------------ */
-
-/* struct for use in re-sorting BezTriples during Graph Editor transform */
-typedef struct BeztMap {
- BezTriple *bezt;
- unsigned int oldIndex; /* index of bezt in fcu->bezt array before sorting */
- unsigned int newIndex; /* index of bezt in fcu->bezt array after sorting */
- short swapHs; /* swap order of handles (-1=clear; 0=not checked, 1=swap) */
- char pipo, cipo; /* interpolation of current and next segments */
-} BeztMap;
-
-/* This function converts an FCurve's BezTriple array to a BeztMap array
- * NOTE: this allocates memory that will need to get freed later
- */
-static BeztMap *bezt_to_beztmaps(BezTriple *bezts, int totvert, const short UNUSED(use_handle))
-{
- BezTriple *bezt = bezts;
- BezTriple *prevbezt = NULL;
- BeztMap *bezm, *bezms;
- int i;
-
- /* allocate memory for this array */
- if (totvert == 0 || bezts == NULL) {
- return NULL;
- }
- bezm = bezms = MEM_callocN(sizeof(BeztMap) * totvert, "BeztMaps");
-
- /* assign beztriples to beztmaps */
- for (i = 0; i < totvert; i++, bezm++, prevbezt = bezt, bezt++) {
- bezm->bezt = bezt;
-
- bezm->oldIndex = i;
- bezm->newIndex = i;
-
- bezm->pipo = (prevbezt) ? prevbezt->ipo : bezt->ipo;
- bezm->cipo = bezt->ipo;
- }
-
- return bezms;
-}
-
-/* This function copies the code of sort_time_ipocurve, but acts on BeztMap structs instead */
-static void sort_time_beztmaps(BeztMap *bezms, int totvert, const short UNUSED(use_handle))
-{
- BeztMap *bezm;
- int i, ok = 1;
-
- /* keep repeating the process until nothing is out of place anymore */
- while (ok) {
- ok = 0;
-
- bezm = bezms;
- i = totvert;
- while (i--) {
- /* is current bezm out of order (i.e. occurs later than next)? */
- if (i > 0) {
- if (bezm->bezt->vec[1][0] > (bezm + 1)->bezt->vec[1][0]) {
- bezm->newIndex++;
- (bezm + 1)->newIndex--;
-
- SWAP(BeztMap, *bezm, *(bezm + 1));
-
- ok = 1;
- }
- }
-
- /* do we need to check if the handles need to be swapped?
- * optimization: this only needs to be performed in the first loop
- */
- if (bezm->swapHs == 0) {
- if ((bezm->bezt->vec[0][0] > bezm->bezt->vec[1][0]) &&
- (bezm->bezt->vec[2][0] < bezm->bezt->vec[1][0])) {
- /* handles need to be swapped */
- bezm->swapHs = 1;
- }
- else {
- /* handles need to be cleared */
- bezm->swapHs = -1;
- }
- }
-
- bezm++;
- }
- }
-}
-
-/* This function firstly adjusts the pointers that the transdata has to each BezTriple */
-static void beztmap_to_data(
- TransInfo *t, FCurve *fcu, BeztMap *bezms, int totvert, const short UNUSED(use_handle))
-{
- BezTriple *bezts = fcu->bezt;
- BeztMap *bezm;
- TransData2D *td2d;
- TransData *td;
- int i, j;
- char *adjusted;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* dynamically allocate an array of chars to mark whether an TransData's
- * pointers have been fixed already, so that we don't override ones that are
- * already done
- */
- adjusted = MEM_callocN(tc->data_len, "beztmap_adjusted_map");
-
- /* for each beztmap item, find if it is used anywhere */
- bezm = bezms;
- for (i = 0; i < totvert; i++, bezm++) {
- /* loop through transdata, testing if we have a hit
- * for the handles (vec[0]/vec[2]), we must also check if they need to be swapped...
- */
- td2d = tc->data_2d;
- td = tc->data;
- for (j = 0; j < tc->data_len; j++, td2d++, td++) {
- /* skip item if already marked */
- if (adjusted[j] != 0) {
- continue;
- }
-
- /* update all transdata pointers, no need to check for selections etc,
- * since only points that are really needed were created as transdata
- */
- if (td2d->loc2d == bezm->bezt->vec[0]) {
- if (bezm->swapHs == 1) {
- td2d->loc2d = (bezts + bezm->newIndex)->vec[2];
- }
- else {
- td2d->loc2d = (bezts + bezm->newIndex)->vec[0];
- }
- adjusted[j] = 1;
- }
- else if (td2d->loc2d == bezm->bezt->vec[2]) {
- if (bezm->swapHs == 1) {
- td2d->loc2d = (bezts + bezm->newIndex)->vec[0];
- }
- else {
- td2d->loc2d = (bezts + bezm->newIndex)->vec[2];
- }
- adjusted[j] = 1;
- }
- else if (td2d->loc2d == bezm->bezt->vec[1]) {
- td2d->loc2d = (bezts + bezm->newIndex)->vec[1];
-
- /* if only control point is selected, the handle pointers need to be updated as well */
- if (td2d->h1) {
- td2d->h1 = (bezts + bezm->newIndex)->vec[0];
- }
- if (td2d->h2) {
- td2d->h2 = (bezts + bezm->newIndex)->vec[2];
- }
-
- adjusted[j] = 1;
- }
-
- /* the handle type pointer has to be updated too */
- if (adjusted[j] && td->flag & TD_BEZTRIPLE && td->hdata) {
- if (bezm->swapHs == 1) {
- td->hdata->h1 = &(bezts + bezm->newIndex)->h2;
- td->hdata->h2 = &(bezts + bezm->newIndex)->h1;
- }
- else {
- td->hdata->h1 = &(bezts + bezm->newIndex)->h1;
- td->hdata->h2 = &(bezts + bezm->newIndex)->h2;
- }
- }
- }
- }
-
- /* free temp memory used for 'adjusted' array */
- MEM_freeN(adjusted);
-}
-
-/* This function is called by recalcData during the Transform loop to recalculate
- * the handles of curves and sort the keyframes so that the curves draw correctly.
- * It is only called if some keyframes have moved out of order.
- *
- * anim_data is the list of channels (F-Curves) retrieved already containing the
- * channels to work on. It should not be freed here as it may still need to be used.
- */
-void remake_graph_transdata(TransInfo *t, ListBase *anim_data)
-{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
- bAnimListElem *ale;
- const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
-
- /* sort and reassign verts */
- for (ale = anim_data->first; ale; ale = ale->next) {
- FCurve *fcu = (FCurve *)ale->key_data;
-
- if (fcu->bezt) {
- BeztMap *bezm;
-
- /* adjust transform-data pointers */
- /* note, none of these functions use 'use_handle', it could be removed */
- bezm = bezt_to_beztmaps(fcu->bezt, fcu->totvert, use_handle);
- sort_time_beztmaps(bezm, fcu->totvert, use_handle);
- beztmap_to_data(t, fcu, bezm, fcu->totvert, use_handle);
-
- /* free mapping stuff */
- MEM_freeN(bezm);
-
- /* re-sort actual beztriples (perhaps this could be done using the beztmaps to save time?) */
- sort_time_fcurve(fcu);
-
- /* make sure handles are all set correctly */
- testhandles_fcurve(fcu, use_handle);
- }
- }
-}
-
-/* this function is called on recalcData to apply the transforms applied
- * to the transdata on to the actual keyframe data
- */
-void flushTransGraphData(TransInfo *t)
-{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
- TransData *td;
- TransData2D *td2d;
- TransDataGraph *tdg;
- Scene *scene = t->scene;
- double secf = FPS;
- int a;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = tc->data, td2d = tc->data_2d, tdg = tc->custom.type.data; a < tc->data_len;
- a++, td++, td2d++, tdg++) {
- /* pointers to relevant AnimData blocks are stored in the td->extra pointers */
- AnimData *adt = (AnimData *)td->extra;
-
- float inv_unit_scale = 1.0f / tdg->unit_scale;
-
- /* handle snapping for time values
- * - we should still be in NLA-mapping timespace
- * - only apply to keyframes (but never to handles)
- * - don't do this when canceling, or else these changes won't go away
- */
- if ((t->state != TRANS_CANCEL) && (td->flag & TD_NOTIMESNAP) == 0) {
- switch (sipo->autosnap) {
- case SACTSNAP_FRAME: /* snap to nearest frame */
- td2d->loc[0] = floor((double)td2d->loc[0] + 0.5);
- break;
-
- case SACTSNAP_SECOND: /* snap to nearest second */
- td2d->loc[0] = floor(((double)td2d->loc[0] / secf) + 0.5) * secf;
- break;
-
- case SACTSNAP_MARKER: /* snap to nearest marker */
- td2d->loc[0] = (float)ED_markers_find_nearest_marker_time(&t->scene->markers,
- td2d->loc[0]);
- break;
- }
- }
-
- /* we need to unapply the nla-mapping from the time in some situations */
- if (adt) {
- td2d->loc2d[0] = BKE_nla_tweakedit_remap(adt, td2d->loc[0], NLATIME_CONVERT_UNMAP);
- }
- else {
- td2d->loc2d[0] = td2d->loc[0];
- }
-
- /** Time-stepping auto-snapping modes don't get applied for Graph Editor transforms,
- * as these use the generic transform modes which don't account for this sort of thing.
- * These ones aren't affected by NLA mapping, so we do this after the conversion...
- *
- * \note We also have to apply to td->loc,
- * as that's what the handle-adjustment step below looks to,
- * otherwise we get "swimming handles".
- *
- * \note We don't do this when canceling transforms, or else these changes don't go away.
- */
- if ((t->state != TRANS_CANCEL) && (td->flag & TD_NOTIMESNAP) == 0 &&
- ELEM(sipo->autosnap, SACTSNAP_STEP, SACTSNAP_TSTEP)) {
- switch (sipo->autosnap) {
- case SACTSNAP_STEP: /* frame step */
- td2d->loc2d[0] = floor((double)td2d->loc[0] + 0.5);
- td->loc[0] = floor((double)td->loc[0] + 0.5);
- break;
-
- case SACTSNAP_TSTEP: /* second step */
- /* XXX: the handle behavior in this case is still not quite right... */
- td2d->loc[0] = floor(((double)td2d->loc[0] / secf) + 0.5) * secf;
- td->loc[0] = floor(((double)td->loc[0] / secf) + 0.5) * secf;
- break;
- }
- }
-
- /* if int-values only, truncate to integers */
- if (td->flag & TD_INTVALUES) {
- td2d->loc2d[1] = floorf(td2d->loc[1] * inv_unit_scale - tdg->offset + 0.5f);
- }
- else {
- td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale - tdg->offset;
- }
-
- if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) {
- td2d->h1[0] = td2d->ih1[0] + td->loc[0] - td->iloc[0];
- td2d->h1[1] = td2d->ih1[1] + (td->loc[1] - td->iloc[1]) * inv_unit_scale;
- }
-
- if ((td->flag & TD_MOVEHANDLE2) && td2d->h2) {
- td2d->h2[0] = td2d->ih2[0] + td->loc[0] - td->iloc[0];
- td2d->h2[1] = td2d->ih2[1] + (td->loc[1] - td->iloc[1]) * inv_unit_scale;
- }
- }
-}
-
-/* ******************* Sequencer Transform data ******************* */
-
-/* This function applies the rules for transforming a strip so duplicate
- * checks don't need to be added in multiple places.
- *
- * recursive, count and flag MUST be set.
- *
- * seq->depth must be set before running this function so we know if the strips
- * are root level or not
- */
-static void SeqTransInfo(TransInfo *t, Sequence *seq, int *recursive, int *count, int *flag)
-{
- /* for extend we need to do some tricks */
- if (t->mode == TFM_TIME_EXTEND) {
-
- /* *** Extend Transform *** */
-
- Scene *scene = t->scene;
- int cfra = CFRA;
- int left = BKE_sequence_tx_get_final_left(seq, true);
- int right = BKE_sequence_tx_get_final_right(seq, true);
-
- if (seq->depth == 0 && ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK))) {
- *recursive = false;
- *count = 0;
- *flag = 0;
- }
- else if (seq->type == SEQ_TYPE_META) {
-
- /* for meta's we only ever need to extend their children, no matter what depth
- * just check the meta's are in the bounds */
- if (t->frame_side == 'R' && right <= cfra) {
- *recursive = false;
- }
- else if (t->frame_side == 'L' && left >= cfra) {
- *recursive = false;
- }
- else {
- *recursive = true;
- }
-
- *count = 1;
- *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
- }
- else {
-
- *recursive = false; /* not a meta, so no thinking here */
- *count = 1; /* unless its set to 0, extend will never set 2 handles at once */
- *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
-
- if (t->frame_side == 'R') {
- if (right <= cfra) {
- *count = *flag = 0;
- } /* ignore */
- else if (left > cfra) {
- } /* keep the selection */
- else {
- *flag |= SEQ_RIGHTSEL;
- }
- }
- else {
- if (left >= cfra) {
- *count = *flag = 0;
- } /* ignore */
- else if (right < cfra) {
- } /* keep the selection */
- else {
- *flag |= SEQ_LEFTSEL;
- }
- }
- }
- }
- else {
-
- t->frame_side = 'B';
-
- /* *** Normal Transform *** */
-
- if (seq->depth == 0) {
-
- /* Count */
-
- /* Non nested strips (resect selection and handles) */
- if ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK)) {
- *recursive = false;
- *count = 0;
- *flag = 0;
- }
- else {
- if ((seq->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) == (SEQ_LEFTSEL | SEQ_RIGHTSEL)) {
- *flag = seq->flag;
- *count = 2; /* we need 2 transdata's */
- }
- else {
- *flag = seq->flag;
- *count = 1; /* selected or with a handle selected */
- }
-
- /* Recursive */
-
- if ((seq->type == SEQ_TYPE_META) && ((seq->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) == 0)) {
- /* if any handles are selected, don't recurse */
- *recursive = true;
- }
- else {
- *recursive = false;
- }
- }
- }
- else {
- /* Nested, different rules apply */
-
-#ifdef SEQ_TX_NESTED_METAS
- *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
- *count = 1; /* ignore the selection for nested */
- *recursive = (seq->type == SEQ_TYPE_META);
-#else
- if (seq->type == SEQ_TYPE_META) {
- /* Meta's can only directly be moved between channels since they
- * don't have their start and length set directly (children affect that)
- * since this Meta is nested we don't need any of its data in fact.
- * BKE_sequence_calc() will update its settings when run on the toplevel meta */
- *flag = 0;
- *count = 0;
- *recursive = true;
- }
- else {
- *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
- *count = 1; /* ignore the selection for nested */
- *recursive = false;
- }
-#endif
- }
- }
-}
-
-static int SeqTransCount(TransInfo *t, Sequence *parent, ListBase *seqbase, int depth)
-{
- Sequence *seq;
- int tot = 0, recursive, count, flag;
-
- for (seq = seqbase->first; seq; seq = seq->next) {
- seq->depth = depth;
-
- /* 'seq->tmp' is used by seq_tx_get_final_{left, right}
- * to check sequence's range and clamp to it if needed.
- * It's first place where digging into sequences tree, so store link to parent here. */
- seq->tmp = parent;
-
- SeqTransInfo(t, seq, &recursive, &count, &flag); /* ignore the flag */
- tot += count;
-
- if (recursive) {
- tot += SeqTransCount(t, seq, &seq->seqbase, depth + 1);
- }
- }
-
- return tot;
-}
-
-static TransData *SeqToTransData(
- TransData *td, TransData2D *td2d, TransDataSeq *tdsq, Sequence *seq, int flag, int sel_flag)
-{
- int start_left;
-
- switch (sel_flag) {
- case SELECT:
- /* Use seq_tx_get_final_left() and an offset here
- * so transform has the left hand location of the strip.
- * tdsq->start_offset is used when flushing the tx data back */
- start_left = BKE_sequence_tx_get_final_left(seq, false);
- td2d->loc[0] = start_left;
- tdsq->start_offset = start_left - seq->start; /* use to apply the original location */
- break;
- case SEQ_LEFTSEL:
- start_left = BKE_sequence_tx_get_final_left(seq, false);
- td2d->loc[0] = start_left;
- break;
- case SEQ_RIGHTSEL:
- td2d->loc[0] = BKE_sequence_tx_get_final_right(seq, false);
- break;
- }
-
- td2d->loc[1] = seq->machine; /* channel - Y location */
- td2d->loc[2] = 0.0f;
- td2d->loc2d = NULL;
-
- tdsq->seq = seq;
-
- /* Use instead of seq->flag for nested strips and other
- * cases where the selection may need to be modified */
- tdsq->flag = flag;
- tdsq->sel_flag = sel_flag;
-
- td->extra = (void *)tdsq; /* allow us to update the strip from here */
-
- td->flag = 0;
- td->loc = td2d->loc;
- copy_v3_v3(td->center, td->loc);
- copy_v3_v3(td->iloc, td->loc);
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
-
- td->flag |= TD_SELECTED;
- td->dist = 0.0;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-
- /* Time Transform (extend) */
- td->val = td2d->loc;
- td->ival = td2d->loc[0];
-
- return td;
-}
-
-static int SeqToTransData_Recursive(
- TransInfo *t, ListBase *seqbase, TransData *td, TransData2D *td2d, TransDataSeq *tdsq)
-{
- Sequence *seq;
- int recursive, count, flag;
- int tot = 0;
-
- for (seq = seqbase->first; seq; seq = seq->next) {
-
- SeqTransInfo(t, seq, &recursive, &count, &flag);
-
- /* add children first so recalculating metastrips does nested strips first */
- if (recursive) {
- int tot_children = SeqToTransData_Recursive(t, &seq->seqbase, td, td2d, tdsq);
-
- td = td + tot_children;
- td2d = td2d + tot_children;
- tdsq = tdsq + tot_children;
-
- tot += tot_children;
- }
-
- /* use 'flag' which is derived from seq->flag but modified for special cases */
- if (flag & SELECT) {
- if (flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) {
- if (flag & SEQ_LEFTSEL) {
- SeqToTransData(td++, td2d++, tdsq++, seq, flag, SEQ_LEFTSEL);
- tot++;
- }
- if (flag & SEQ_RIGHTSEL) {
- SeqToTransData(td++, td2d++, tdsq++, seq, flag, SEQ_RIGHTSEL);
- tot++;
- }
- }
- else {
- SeqToTransData(td++, td2d++, tdsq++, seq, flag, SELECT);
- tot++;
- }
- }
- }
- return tot;
-}
-
-static void SeqTransDataBounds(TransInfo *t, ListBase *seqbase, TransSeq *ts)
-{
- Sequence *seq;
- int recursive, count, flag;
- int max = INT32_MIN, min = INT32_MAX;
-
- for (seq = seqbase->first; seq; seq = seq->next) {
-
- /* just to get the flag since there are corner cases where this isn't totally obvious */
- SeqTransInfo(t, seq, &recursive, &count, &flag);
-
- /* use 'flag' which is derived from seq->flag but modified for special cases */
- if (flag & SELECT) {
- if (flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) {
- if (flag & SEQ_LEFTSEL) {
- min = min_ii(seq->startdisp, min);
- max = max_ii(seq->startdisp, max);
- }
- if (flag & SEQ_RIGHTSEL) {
- min = min_ii(seq->enddisp, min);
- max = max_ii(seq->enddisp, max);
- }
- }
- else {
- min = min_ii(seq->startdisp, min);
- max = max_ii(seq->enddisp, max);
- }
- }
- }
-
- if (ts) {
- ts->max = max;
- ts->min = min;
- }
-}
-
-static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data)
-{
- Editing *ed = BKE_sequencer_editing_get(t->scene, false);
-
- if (ed != NULL) {
-
- ListBase *seqbasep = ed->seqbasep;
- TransData *td = tc->data;
- int a;
-
- /* prevent updating the same seq twice
- * if the transdata order is changed this will mess up
- * but so will TransDataSeq */
- Sequence *seq_prev = NULL;
- Sequence *seq;
-
- if (!(t->state == TRANS_CANCEL)) {
-
-#if 0 // default 2.4 behavior
-
- /* flush to 2d vector from internally used 3d vector */
- for (a = 0; a < t->total; a++, td++) {
- if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) {
- seq = ((TransDataSeq *)td->extra)->seq;
- BKE_sequence_base_shuffle(seqbasep, seq, t->scene);
- }
-
- seq_prev = seq;
- }
-
-#else // durian hack
- {
- int overlap = 0;
-
- for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
- seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) {
- overlap = 1;
- break;
- }
- }
-
- if (overlap) {
- bool has_effect_root = false, has_effect_any = false;
- for (seq = seqbasep->first; seq; seq = seq->next) {
- seq->tmp = NULL;
- }
-
- td = tc->data;
- for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
- seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev)) {
- /* check effects strips, we cant change their time */
- if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
- has_effect_any = true;
- if (seq->depth == 0) {
- has_effect_root = true;
- }
- }
- else {
- /* Tag seq with a non zero value, used by
- * BKE_sequence_base_shuffle_time to identify the ones to shuffle */
- if (seq->depth == 0) {
- seq->tmp = (void *)1;
- }
- }
- }
- }
-
- if (t->flag & T_ALT_TRANSFORM) {
- int minframe = MAXFRAME;
- td = tc->data;
- for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
- seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev) && (seq->depth == 0)) {
- minframe = min_ii(minframe, seq->startdisp);
- }
- }
-
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (!(seq->flag & SELECT)) {
- if (seq->startdisp >= minframe) {
- seq->machine += MAXSEQ * 2;
- }
- }
- }
-
- BKE_sequence_base_shuffle_time(seqbasep, t->scene);
-
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->machine >= MAXSEQ * 2) {
- seq->machine -= MAXSEQ * 2;
- seq->tmp = (void *)1;
- }
- else {
- seq->tmp = NULL;
- }
- }
-
- BKE_sequence_base_shuffle_time(seqbasep, t->scene);
- }
- else {
- BKE_sequence_base_shuffle_time(seqbasep, t->scene);
- }
-
- if (has_effect_any) {
- /* update effects strips based on strips just moved in time */
- td = tc->data;
- for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
- seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev)) {
- if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
- BKE_sequence_calc(t->scene, seq);
- }
- }
- }
- }
-
- if (has_effect_root) {
- /* now if any effects _still_ overlap, we need to move them up */
- td = tc->data;
- for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
- seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev) && (seq->depth == 0)) {
- if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
- if (BKE_sequence_test_overlap(seqbasep, seq)) {
- BKE_sequence_base_shuffle(seqbasep, seq, t->scene);
- }
- }
- }
- }
- /* done with effects */
- }
- }
- }
-#endif
-
- for (seq = seqbasep->first; seq; seq = seq->next) {
- /* We might want to build a list of effects that need to be updated during transform */
- if (seq->type & SEQ_TYPE_EFFECT) {
- if (seq->seq1 && seq->seq1->flag & SELECT) {
- BKE_sequence_calc(t->scene, seq);
- }
- else if (seq->seq2 && seq->seq2->flag & SELECT) {
- BKE_sequence_calc(t->scene, seq);
- }
- else if (seq->seq3 && seq->seq3->flag & SELECT) {
- BKE_sequence_calc(t->scene, seq);
- }
- }
- }
-
- BKE_sequencer_sort(t->scene);
- }
- else {
- /* Canceled, need to update the strips display */
- for (a = 0; a < tc->data_len; a++, td++) {
- seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev) && (seq->depth == 0)) {
- if (seq->flag & SEQ_OVERLAP) {
- BKE_sequence_base_shuffle(seqbasep, seq, t->scene);
- }
-
- BKE_sequence_calc_disp(t->scene, seq);
- }
- seq_prev = seq;
- }
- }
- }
-
- if ((custom_data->data != NULL) && custom_data->use_free) {
- TransSeq *ts = custom_data->data;
- MEM_freeN(ts->tdseq);
- MEM_freeN(custom_data->data);
- custom_data->data = NULL;
- }
-
- DEG_id_tag_update(&t->scene->id, ID_RECALC_SEQUENCER_STRIPS);
-}
-
-static void createTransSeqData(bContext *C, TransInfo *t)
-{
-#define XXX_DURIAN_ANIM_TX_HACK
-
- View2D *v2d = UI_view2d_fromcontext(C);
- Scene *scene = t->scene;
- Editing *ed = BKE_sequencer_editing_get(t->scene, false);
- TransData *td = NULL;
- TransData2D *td2d = NULL;
- TransDataSeq *tdsq = NULL;
- TransSeq *ts = NULL;
- int xmouse;
-
- int count = 0;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- if (ed == NULL) {
- tc->data_len = 0;
- return;
- }
-
- tc->custom.type.free_cb = freeSeqData;
-
- xmouse = (int)UI_view2d_region_to_view_x(v2d, t->mouse.imval[0]);
-
- /* which side of the current frame should be allowed */
- if (t->mode == TFM_TIME_EXTEND) {
- /* only side on which mouse is gets transformed */
- t->frame_side = (xmouse > CFRA) ? 'R' : 'L';
- }
- else {
- /* normal transform - both sides of current frame are considered */
- t->frame_side = 'B';
- }
-
-#ifdef XXX_DURIAN_ANIM_TX_HACK
- {
- Sequence *seq;
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- /* hack */
- if ((seq->flag & SELECT) == 0 && seq->type & SEQ_TYPE_EFFECT) {
- Sequence *seq_user;
- int i;
- for (i = 0; i < 3; i++) {
- seq_user = *((&seq->seq1) + i);
- if (seq_user && (seq_user->flag & SELECT) && !(seq_user->flag & SEQ_LOCK) &&
- !(seq_user->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL))) {
- seq->flag |= SELECT;
- }
- }
- }
- }
- }
-#endif
-
- count = SeqTransCount(t, NULL, ed->seqbasep, 0);
-
- /* allocate memory for data */
- tc->data_len = count;
-
- /* stop if trying to build list if nothing selected */
- if (count == 0) {
- return;
- }
-
- tc->custom.type.data = ts = MEM_callocN(sizeof(TransSeq), "transseq");
- tc->custom.type.use_free = true;
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransSeq TransData");
- td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransSeq TransData2D");
- ts->tdseq = tdsq = MEM_callocN(tc->data_len * sizeof(TransDataSeq), "TransSeq TransDataSeq");
-
- /* loop 2: build transdata array */
- SeqToTransData_Recursive(t, ed->seqbasep, td, td2d, tdsq);
- SeqTransDataBounds(t, ed->seqbasep, ts);
-
- /* set the snap mode based on how close the mouse is at the end/start points */
- if (abs(xmouse - ts->max) > abs(xmouse - ts->min)) {
- ts->snap_left = true;
- }
-
-#undef XXX_DURIAN_ANIM_TX_HACK
-}
-
-/* *********************** Object Transform data ******************* */
-
-/* Little helper function for ObjectToTransData used to give certain
- * constraints (ChildOf, FollowPath, and others that may be added)
- * inverse corrections for transform, so that they aren't in CrazySpace.
- * These particular constraints benefit from this, but others don't, hence
- * this semi-hack ;-) - Aligorith
- */
-static bool constraints_list_needinv(TransInfo *t, ListBase *list)
-{
- bConstraint *con;
-
- /* loop through constraints, checking if there's one of the mentioned
- * constraints needing special crazyspace corrections
- */
- if (list) {
- for (con = list->first; con; con = con->next) {
- /* only consider constraint if it is enabled, and has influence on result */
- if ((con->flag & CONSTRAINT_DISABLE) == 0 && (con->enforce != 0.0f)) {
- /* (affirmative) returns for specific constraints here... */
- /* constraints that require this regardless */
- if (ELEM(con->type,
- CONSTRAINT_TYPE_FOLLOWPATH,
- CONSTRAINT_TYPE_CLAMPTO,
- CONSTRAINT_TYPE_ARMATURE,
- CONSTRAINT_TYPE_OBJECTSOLVER,
- CONSTRAINT_TYPE_FOLLOWTRACK)) {
- return true;
- }
-
- /* constraints that require this only under special conditions */
- if (con->type == CONSTRAINT_TYPE_CHILDOF) {
- /* ChildOf constraint only works when using all location components, see T42256. */
- bChildOfConstraint *data = (bChildOfConstraint *)con->data;
-
- if ((data->flag & CHILDOF_LOCX) && (data->flag & CHILDOF_LOCY) &&
- (data->flag & CHILDOF_LOCZ)) {
- return true;
- }
- }
- else if (con->type == CONSTRAINT_TYPE_ROTLIKE) {
- /* CopyRot constraint only does this when rotating, and offset is on */
- bRotateLikeConstraint *data = (bRotateLikeConstraint *)con->data;
-
- if ((data->flag & ROTLIKE_OFFSET) && (t->mode == TFM_ROTATION)) {
- return true;
- }
- }
- else if (con->type == CONSTRAINT_TYPE_TRANSFORM) {
- /* Transform constraint needs it for rotation at least (r.57309),
- * but doing so when translating may also mess things up [#36203]
- */
-
- if (t->mode == TFM_ROTATION) {
- return true;
- }
- /* ??? (t->mode == TFM_SCALE) ? */
- }
- }
- }
- }
-
- /* no appropriate candidates found */
- return false;
-}
-
-/* transcribe given object into TransData for Transforming */
-static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
-{
- Scene *scene = t->scene;
- bool constinv;
- bool skip_invert = false;
-
- if (t->mode != TFM_DUMMY && ob->rigidbody_object) {
- float rot[3][3], scale[3];
- float ctime = BKE_scene_frame_get(scene);
-
- /* only use rigid body transform if simulation is running,
- * avoids problems with initial setup of rigid bodies */
- if (BKE_rigidbody_check_sim_running(scene->rigidbody_world, ctime)) {
-
- /* save original object transform */
- copy_v3_v3(td->ext->oloc, ob->loc);
-
- if (ob->rotmode > 0) {
- copy_v3_v3(td->ext->orot, ob->rot);
- }
- else if (ob->rotmode == ROT_MODE_AXISANGLE) {
- td->ext->orotAngle = ob->rotAngle;
- copy_v3_v3(td->ext->orotAxis, ob->rotAxis);
- }
- else {
- copy_qt_qt(td->ext->oquat, ob->quat);
- }
- /* update object's loc/rot to get current rigid body transform */
- mat4_to_loc_rot_size(ob->loc, rot, scale, ob->obmat);
- sub_v3_v3(ob->loc, ob->dloc);
- BKE_object_mat3_to_rot(ob, rot, false); /* drot is already corrected here */
- }
- }
-
- /* axismtx has the real orientation */
- copy_m3_m4(td->axismtx, ob->obmat);
- normalize_m3(td->axismtx);
-
- td->con = ob->constraints.first;
-
- /* hack: temporarily disable tracking and/or constraints when getting
- * object matrix, if tracking is on, or if constraints don't need
- * inverse correction to stop it from screwing up space conversion
- * matrix later
- */
- constinv = constraints_list_needinv(t, &ob->constraints);
-
- /* disable constraints inversion for dummy pass */
- if (t->mode == TFM_DUMMY) {
- skip_invert = true;
- }
-
- /* NOTE: This is not really following copy-on-write design and we should not
- * be re-evaluating the evaluated object. But as the comment above mentioned
- * this is part of a hack.
- * More proper solution would be to make a shallow copy of the object and
- * evaluate that, and access matrix of that evaluated copy of the object.
- * Might be more tricky than it sounds, if some logic later on accesses the
- * object matrix via td->ob->obmat. */
- Object *object_eval = DEG_get_evaluated_object(t->depsgraph, ob);
- if (skip_invert == false && constinv == false) {
- object_eval->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc checks this */
- /* It is possible to have transform data initialization prior to a
- * complete dependency graph evaluated. Happens, for example, when
- * changing transformation mode. */
- BKE_object_tfm_copy(object_eval, ob);
- BKE_object_where_is_calc(t->depsgraph, t->scene, object_eval);
- object_eval->transflag &= ~OB_NO_CONSTRAINTS;
- }
- else {
- BKE_object_where_is_calc(t->depsgraph, t->scene, object_eval);
- }
- /* Copy newly evaluated fields to the original object, similar to how
- * active dependency graph will do it. */
- copy_m4_m4(ob->obmat, object_eval->obmat);
- /* Only copy negative scale flag, this is the only flag which is modified by
- * the BKE_object_where_is_calc(). The rest of the flags we need to keep,
- * otherwise we might loose dupli flags (see T61787). */
- ob->transflag &= ~OB_NEG_SCALE;
- ob->transflag |= (object_eval->transflag & OB_NEG_SCALE);
-
- td->ob = ob;
-
- td->loc = ob->loc;
- copy_v3_v3(td->iloc, td->loc);
-
- if (ob->rotmode > 0) {
- td->ext->rot = ob->rot;
- td->ext->rotAxis = NULL;
- td->ext->rotAngle = NULL;
- td->ext->quat = NULL;
-
- copy_v3_v3(td->ext->irot, ob->rot);
- copy_v3_v3(td->ext->drot, ob->drot);
- }
- else if (ob->rotmode == ROT_MODE_AXISANGLE) {
- td->ext->rot = NULL;
- td->ext->rotAxis = ob->rotAxis;
- td->ext->rotAngle = &ob->rotAngle;
- td->ext->quat = NULL;
-
- td->ext->irotAngle = ob->rotAngle;
- copy_v3_v3(td->ext->irotAxis, ob->rotAxis);
- // td->ext->drotAngle = ob->drotAngle; // XXX, not implemented
- // copy_v3_v3(td->ext->drotAxis, ob->drotAxis); // XXX, not implemented
- }
- else {
- td->ext->rot = NULL;
- td->ext->rotAxis = NULL;
- td->ext->rotAngle = NULL;
- td->ext->quat = ob->quat;
-
- copy_qt_qt(td->ext->iquat, ob->quat);
- copy_qt_qt(td->ext->dquat, ob->dquat);
- }
- td->ext->rotOrder = ob->rotmode;
-
- td->ext->size = ob->scale;
- copy_v3_v3(td->ext->isize, ob->scale);
- copy_v3_v3(td->ext->dscale, ob->dscale);
-
- copy_v3_v3(td->center, ob->obmat[3]);
-
- copy_m4_m4(td->ext->obmat, ob->obmat);
-
- /* is there a need to set the global<->data space conversion matrices? */
- if (ob->parent || constinv) {
- float obmtx[3][3], totmat[3][3], obinv[3][3];
-
- /* Get the effect of parenting, and/or certain constraints.
- * NOTE: some Constraints, and also Tracking should never get this
- * done, as it doesn't work well.
- */
- BKE_object_to_mat3(ob, obmtx);
- copy_m3_m4(totmat, ob->obmat);
- invert_m3_m3(obinv, totmat);
- mul_m3_m3m3(td->smtx, obmtx, obinv);
- invert_m3_m3(td->mtx, td->smtx);
- }
- else {
- /* no conversion to/from dataspace */
- unit_m3(td->smtx);
- unit_m3(td->mtx);
- }
-}
-
-static void trans_object_base_deps_flag_prepare(ViewLayer *view_layer)
-{
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- base->object->id.tag &= ~LIB_TAG_DOIT;
- }
-}
-
-static void set_trans_object_base_deps_flag_cb(ID *id,
- eDepsObjectComponentType component,
- void *UNUSED(user_data))
-{
- /* Here we only handle object IDs. */
- if (GS(id->name) != ID_OB) {
- return;
- }
- if (!ELEM(component, DEG_OB_COMP_TRANSFORM, DEG_OB_COMP_GEOMETRY)) {
- return;
- }
- id->tag |= LIB_TAG_DOIT;
-}
-
-static void flush_trans_object_base_deps_flag(Depsgraph *depsgraph, Object *object)
-{
- object->id.tag |= LIB_TAG_DOIT;
- DEG_foreach_dependent_ID_component(
- depsgraph, &object->id, DEG_OB_COMP_TRANSFORM, set_trans_object_base_deps_flag_cb, NULL);
-}
-
-static void trans_object_base_deps_flag_finish(const TransInfo *t, ViewLayer *view_layer)
-{
-
- if ((t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) == 0) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- if (base->object->id.tag & LIB_TAG_DOIT) {
- base->flag_legacy |= BA_SNAP_FIX_DEPS_FIASCO;
- }
- }
- }
-}
-
-/* sets flags in Bases to define whether they take part in transform */
-/* it deselects Bases, so we have to call the clear function always after */
-static void set_trans_object_base_flags(TransInfo *t)
-{
- Main *bmain = CTX_data_main(t->context);
- ViewLayer *view_layer = t->view_layer;
- View3D *v3d = t->view;
- Scene *scene = t->scene;
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
- /* NOTE: if Base selected and has parent selected:
- * base->flag_legacy = BA_WAS_SEL
- */
- /* Don't do it if we're not actually going to recalculate anything. */
- if (t->mode == TFM_DUMMY) {
- return;
- }
- /* Makes sure base flags and object flags are identical. */
- BKE_scene_base_flag_to_objects(t->view_layer);
- /* Make sure depsgraph is here. */
- DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
- /* Clear all flags we need. It will be used to detect dependencies. */
- trans_object_base_deps_flag_prepare(view_layer);
- /* Traverse all bases and set all possible flags. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- base->flag_legacy &= ~BA_WAS_SEL;
- if (BASE_SELECTED_EDITABLE(v3d, base)) {
- Object *ob = base->object;
- Object *parsel = ob->parent;
- /* If parent selected, deselect. */
- while (parsel != NULL) {
- if (parsel->base_flag & BASE_SELECTED) {
- Base *parbase = BKE_view_layer_base_find(view_layer, parsel);
- if (parbase != NULL) { /* in rare cases this can fail */
- if (BASE_SELECTED_EDITABLE(v3d, parbase)) {
- break;
- }
- }
- }
- parsel = parsel->parent;
- }
- if (parsel != NULL) {
- /* Rotation around local centers are allowed to propagate. */
- if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
- (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)) {
- base->flag_legacy |= BA_TRANSFORM_CHILD;
- }
- else {
- base->flag &= ~BASE_SELECTED;
- base->flag_legacy |= BA_WAS_SEL;
- }
- }
- flush_trans_object_base_deps_flag(depsgraph, ob);
- }
- }
- /* Store temporary bits in base indicating that base is being modified
- * (directly or indirectly) by transforming objects.
- */
- trans_object_base_deps_flag_finish(t, view_layer);
-}
-
-static bool mark_children(Object *ob)
-{
- if (ob->flag & (SELECT | BA_TRANSFORM_CHILD)) {
- return true;
- }
-
- if (ob->parent) {
- if (mark_children(ob->parent)) {
- ob->flag |= BA_TRANSFORM_CHILD;
- return true;
- }
- }
-
- return false;
-}
-
-static int count_proportional_objects(TransInfo *t)
-{
- int total = 0;
- ViewLayer *view_layer = t->view_layer;
- View3D *v3d = t->view;
- Scene *scene = t->scene;
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
- /* Clear all flags we need. It will be used to detect dependencies. */
- trans_object_base_deps_flag_prepare(view_layer);
- /* Rotations around local centers are allowed to propagate, so we take all objects. */
- if (!((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
- (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL))) {
- /* Mark all parents. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- if (BASE_SELECTED_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base)) {
- Object *parent = base->object->parent;
- /* flag all parents */
- while (parent != NULL) {
- parent->flag |= BA_TRANSFORM_PARENT;
- parent = parent->parent;
- }
- }
- }
- /* Mark all children. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- /* all base not already selected or marked that is editable */
- if ((base->object->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
- (base->flag & BASE_SELECTED) == 0 &&
- (BASE_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base))) {
- mark_children(base->object);
- }
- }
- }
- /* Flush changed flags to all dependencies. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- Object *ob = base->object;
- /* If base is not selected, not a parent of selection or not a child of
- * selection and it is editable and selectable.
- */
- if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
- (base->flag & BASE_SELECTED) == 0 &&
- (BASE_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base))) {
- flush_trans_object_base_deps_flag(depsgraph, ob);
- total += 1;
- }
- }
- /* Store temporary bits in base indicating that base is being modified
- * (directly or indirectly) by transforming objects.
- */
- trans_object_base_deps_flag_finish(t, view_layer);
- return total;
-}
-
-static void clear_trans_object_base_flags(TransInfo *t)
-{
- ViewLayer *view_layer = t->view_layer;
- Base *base;
-
- for (base = view_layer->object_bases.first; base; base = base->next) {
- if (base->flag_legacy & BA_WAS_SEL) {
- ED_object_base_select(base, BA_SELECT);
- }
-
- base->flag_legacy &= ~(BA_WAS_SEL | BA_SNAP_FIX_DEPS_FIASCO | BA_TEMP_TAG |
- BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT);
- }
-}
-
-/**
- * Auto-keyframing feature - for objects
- *
- * \param tmode: A transform mode.
- *
- * \note Context may not always be available,
- * so must check before using it as it's a luxury for a few cases.
- */
-void autokeyframe_object(bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, int tmode)
-{
- Main *bmain = CTX_data_main(C);
- ID *id = &ob->id;
- FCurve *fcu;
-
- // TODO: this should probably be done per channel instead...
- if (autokeyframe_cfra_can_key(scene, id)) {
- ReportList *reports = CTX_wm_reports(C);
- ToolSettings *ts = scene->toolsettings;
- KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
- ListBase dsources = {NULL, NULL};
- float cfra = (float)CFRA; // xxx this will do for now
- short flag = 0;
-
- /* get flags used for inserting keyframes */
- flag = ANIM_get_keyframing_flags(scene, 1);
-
- /* add datasource override for the object */
- ANIM_relative_keyingset_add_source(&dsources, id, NULL, NULL);
-
- if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
- /* Only insert into active keyingset
- * NOTE: we assume here that the active Keying Set
- * does not need to have its iterator overridden.
- */
- ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) {
- AnimData *adt = ob->adt;
-
- /* only key on available channels */
- if (adt && adt->action) {
- ListBase nla_cache = {NULL, NULL};
- for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) {
- fcu->flag &= ~FCURVE_SELECTED;
- insert_keyframe(bmain,
- reports,
- id,
- adt->action,
- (fcu->grp ? fcu->grp->name : NULL),
- fcu->rna_path,
- fcu->array_index,
- cfra,
- ts->keyframe_type,
- &nla_cache,
- flag);
- }
-
- BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
- }
- }
- else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
- bool do_loc = false, do_rot = false, do_scale = false;
-
- /* filter the conditions when this happens (assume that curarea->spacetype==SPACE_VIE3D) */
- if (tmode == TFM_TRANSLATION) {
- do_loc = true;
- }
- else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
- if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
- if (ob != OBACT(view_layer)) {
- do_loc = true;
- }
- }
- else if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) {
- do_loc = true;
- }
-
- if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
- do_rot = true;
- }
- }
- else if (tmode == TFM_RESIZE) {
- if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
- if (ob != OBACT(view_layer)) {
- do_loc = true;
- }
- }
- else if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) {
- do_loc = true;
- }
-
- if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
- do_scale = true;
- }
- }
-
- /* insert keyframes for the affected sets of channels using the builtin KeyingSets found */
- if (do_loc) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- if (do_rot) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- if (do_scale) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_SCALING_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- }
- /* insert keyframe in all (transform) channels */
- else {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
-
- /* free temp info */
- BLI_freelistN(&dsources);
- }
-}
-
-/* Return if we need to update motion paths, only if they already exist,
- * and we will insert a keyframe at the end of transform. */
-bool motionpath_need_update_object(Scene *scene, Object *ob)
-{
- /* XXX: there's potential here for problems with unkeyed rotations/scale,
- * but for now (until proper data-locality for baking operations),
- * this should be a better fix for T24451 and T37755
- */
-
- if (autokeyframe_cfra_can_key(scene, &ob->id)) {
- return (ob->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
- }
-
- return false;
-}
-
-/**
- * Auto-keyframing feature - for poses/pose-channels
- *
- * \param tmode: A transform mode.
- *
- * targetless_ik: has targetless ik been done on any channels?
- *
- * \note Context may not always be available,
- * so must check before using it as it's a luxury for a few cases.
- */
-void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, int tmode, short targetless_ik)
-{
- Main *bmain = CTX_data_main(C);
- ID *id = &ob->id;
- AnimData *adt = ob->adt;
- bAction *act = (adt) ? adt->action : NULL;
- bPose *pose = ob->pose;
- bPoseChannel *pchan;
- FCurve *fcu;
-
- // TODO: this should probably be done per channel instead...
- if (autokeyframe_cfra_can_key(scene, id)) {
- ReportList *reports = CTX_wm_reports(C);
- ToolSettings *ts = scene->toolsettings;
- KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
- ListBase nla_cache = {NULL, NULL};
- float cfra = (float)CFRA;
- short flag = 0;
-
- /* flag is initialized from UserPref keyframing settings
- * - special exception for targetless IK - INSERTKEY_MATRIX keyframes should get
- * visual keyframes even if flag not set, as it's not that useful otherwise
- * (for quick animation recording)
- */
- flag = ANIM_get_keyframing_flags(scene, 1);
-
- if (targetless_ik) {
- flag |= INSERTKEY_MATRIX;
- }
-
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->flag & (BONE_TRANSFORM | BONE_TRANSFORM_MIRROR)) {
-
- ListBase dsources = {NULL, NULL};
-
- /* clear any 'unkeyed' flag it may have */
- pchan->bone->flag &= ~BONE_UNKEYED;
-
- /* add datasource override for the camera object */
- ANIM_relative_keyingset_add_source(&dsources, id, &RNA_PoseBone, pchan);
-
- /* only insert into active keyingset? */
- if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
- /* run the active Keying Set on the current datasource */
- ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- /* only insert into available channels? */
- else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) {
- if (act) {
- for (fcu = act->curves.first; fcu; fcu = fcu->next) {
- /* only insert keyframes for this F-Curve if it affects the current bone */
- if (strstr(fcu->rna_path, "bones")) {
- char *pchanName = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
-
- /* only if bone name matches too...
- * NOTE: this will do constraints too, but those are ok to do here too?
- */
- if (pchanName && STREQ(pchanName, pchan->name)) {
- insert_keyframe(bmain,
- reports,
- id,
- act,
- ((fcu->grp) ? (fcu->grp->name) : (NULL)),
- fcu->rna_path,
- fcu->array_index,
- cfra,
- ts->keyframe_type,
- &nla_cache,
- flag);
- }
-
- if (pchanName) {
- MEM_freeN(pchanName);
- }
- }
- }
- }
- }
- /* only insert keyframe if needed? */
- else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
- bool do_loc = false, do_rot = false, do_scale = false;
-
- /* Filter the conditions when this happens
- * (assume that 'curarea->spacetype == SPACE_VIEW3D'). */
- if (tmode == TFM_TRANSLATION) {
- if (targetless_ik) {
- do_rot = true;
- }
- else {
- do_loc = true;
- }
- }
- else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
- if (ELEM(scene->toolsettings->transform_pivot_point,
- V3D_AROUND_CURSOR,
- V3D_AROUND_ACTIVE)) {
- do_loc = true;
- }
-
- if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
- do_rot = true;
- }
- }
- else if (tmode == TFM_RESIZE) {
- if (ELEM(scene->toolsettings->transform_pivot_point,
- V3D_AROUND_CURSOR,
- V3D_AROUND_ACTIVE)) {
- do_loc = true;
- }
-
- if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
- do_scale = true;
- }
- }
-
- if (do_loc) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- if (do_rot) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- if (do_scale) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_SCALING_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- }
- /* insert keyframe in all (transform) channels */
- else {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
-
- /* free temp info */
- BLI_freelistN(&dsources);
- }
- }
-
- BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
- }
- else {
- /* tag channels that should have unkeyed data */
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->flag & BONE_TRANSFORM) {
- /* tag this channel */
- pchan->bone->flag |= BONE_UNKEYED;
- }
- }
- }
-}
-
-/* Return if we need to update motion paths, only if they already exist,
- * and we will insert a keyframe at the end of transform. */
-bool motionpath_need_update_pose(Scene *scene, Object *ob)
-{
- if (autokeyframe_cfra_can_key(scene, &ob->id)) {
- return (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
- }
-
- return false;
-}
-
-static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t)
-{
- SpaceClip *sc = t->sa->spacedata.first;
- MovieClip *clip = ED_space_clip_get_clip(sc);
- ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
- const int framenr = ED_space_clip_get_clip_frame_number(sc);
- /* Update coordinates of modified plane tracks. */
- for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first; plane_track;
- plane_track = plane_track->next) {
- bool do_update = false;
- if (plane_track->flag & PLANE_TRACK_HIDDEN) {
- continue;
- }
- do_update |= PLANE_TRACK_VIEW_SELECTED(plane_track) != 0;
- if (do_update == false) {
- if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
- int i;
- for (i = 0; i < plane_track->point_tracksnr; i++) {
- MovieTrackingTrack *track = plane_track->point_tracks[i];
- if (TRACK_VIEW_SELECTED(sc, track)) {
- do_update = true;
- break;
- }
- }
- }
- }
- if (do_update) {
- BKE_tracking_track_plane_from_existing_motion(plane_track, framenr);
- }
- }
- if (t->scene->nodetree != NULL) {
- /* Tracks can be used for stabilization nodes,
- * flush update for such nodes.
- */
- nodeUpdateID(t->scene->nodetree, &clip->id);
- WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL);
- }
-}
-
-static void special_aftertrans_update__mask(bContext *C, TransInfo *t)
-{
- Mask *mask = NULL;
-
- if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sc = t->sa->spacedata.first;
- mask = ED_space_clip_get_mask(sc);
- }
- else if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = t->sa->spacedata.first;
- mask = ED_space_image_get_mask(sima);
- }
- else {
- BLI_assert(0);
- }
-
- if (t->scene->nodetree) {
- /* tracks can be used for stabilization nodes,
- * flush update for such nodes */
- // if (nodeUpdateID(t->scene->nodetree, &mask->id))
- {
- WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id);
- }
- }
-
- /* TODO - dont key all masks... */
- if (IS_AUTOKEY_ON(t->scene)) {
- Scene *scene = t->scene;
-
- ED_mask_layer_shape_auto_key_select(mask, CFRA);
- }
-}
-
-static void special_aftertrans_update__node(bContext *C, TransInfo *t)
-{
- Main *bmain = CTX_data_main(C);
- const bool canceled = (t->state == TRANS_CANCEL);
-
- if (canceled && t->remove_on_cancel) {
- /* remove selected nodes on cancel */
- SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
- bNodeTree *ntree = snode->edittree;
- if (ntree) {
- bNode *node, *node_next;
- for (node = ntree->nodes.first; node; node = node_next) {
- node_next = node->next;
- if (node->flag & NODE_SELECT) {
- nodeRemoveNode(bmain, ntree, node, true);
- }
- }
- }
- }
-}
-
-static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
-{
- /* so automerge supports mirror */
- if ((t->scene->toolsettings->automerge) && ((t->flag & T_EDIT) && t->obedit_type == OB_MESH)) {
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
-
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- BMesh *bm = em->bm;
- char hflag;
- bool has_face_sel = (bm->totfacesel != 0);
-
- if (tc->mirror.axis_flag) {
- TransData *td;
- int i;
-
- /* Rather then adjusting the selection (which the user would notice)
- * tag all mirrored verts, then auto-merge those. */
- BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false);
-
- for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
- if (td->extra) {
- BM_elem_flag_enable((BMVert *)td->extra, BM_ELEM_TAG);
- }
- }
-
- hflag = BM_ELEM_SELECT | BM_ELEM_TAG;
- }
- else {
- hflag = BM_ELEM_SELECT;
- }
-
- EDBM_automerge(t->scene, tc->obedit, true, hflag);
-
- /* Special case, this is needed or faces won't re-select.
- * Flush selected edges to faces. */
- if (has_face_sel && (em->selectmode == SCE_SELECT_FACE)) {
- EDBM_selectmode_flush_ex(em, SCE_SELECT_EDGE);
- }
- }
- }
-}
-
-/* inserting keys, pointcache, redraw events... */
-/**
- * \note Sequencer freeing has its own function now because of a conflict
- * with transform's order of freeing (campbell).
- * Order changed, the sequencer stuff should go back in here
- */
-void special_aftertrans_update(bContext *C, TransInfo *t)
-{
- Main *bmain = CTX_data_main(t->context);
- BLI_assert(bmain == CTX_data_main(C));
-
- Object *ob;
- // short redrawipo=0, resetslowpar=1;
- const bool canceled = (t->state == TRANS_CANCEL);
- const bool duplicate = (t->mode == TFM_TIME_DUPLICATE);
-
- /* early out when nothing happened */
- if (t->data_len_all == 0 || t->mode == TFM_DUMMY) {
- return;
- }
-
- if (t->spacetype == SPACE_VIEW3D) {
- if (t->flag & T_EDIT) {
- /* Special Exception:
- * We don't normally access 't->custom.mode' here, but its needed in this case. */
-
- if (canceled == 0) {
- /* we need to delete the temporary faces before automerging */
- if (t->mode == TFM_EDGE_SLIDE) {
- /* handle multires re-projection, done
- * on transform completion since it's
- * really slow -joeedh */
- projectEdgeSlideData(t, true);
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- EdgeSlideData *sld = tc->custom.mode.data;
-
- if (sld == NULL) {
- continue;
- }
-
- /* Free temporary faces to avoid auto-merging and deleting
- * during cleanup - psy-fi. */
- freeEdgeSlideTempFaces(sld);
- }
- }
- else if (t->mode == TFM_VERT_SLIDE) {
- /* as above */
- projectVertSlideData(t, true);
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- VertSlideData *sld = tc->custom.mode.data;
- freeVertSlideTempFaces(sld);
- }
- }
-
- if (t->obedit_type == OB_MESH) {
- special_aftertrans_update__mesh(C, t);
- }
- }
- else {
- if (t->mode == TFM_EDGE_SLIDE) {
- EdgeSlideParams *slp = t->custom.mode.data;
- slp->perc = 0.0;
- projectEdgeSlideData(t, false);
- }
- else if (t->mode == TFM_VERT_SLIDE) {
- EdgeSlideParams *slp = t->custom.mode.data;
- slp->perc = 0.0;
- projectVertSlideData(t, false);
- }
- }
- }
- }
-
- if (t->options & CTX_GPENCIL_STROKES) {
- /* pass */
- }
- else if (t->spacetype == SPACE_SEQ) {
- /* freeSeqData in transform_conversions.c does this
- * keep here so the else at the end wont run... */
-
- SpaceSeq *sseq = (SpaceSeq *)t->sa->spacedata.first;
-
- /* marker transform, not especially nice but we may want to move markers
- * at the same time as keyframes in the dope sheet. */
- if ((sseq->flag & SEQ_MARKER_TRANS) && (canceled == 0)) {
- /* cant use TFM_TIME_EXTEND
- * for some reason EXTEND is changed into TRANSLATE, so use frame_side instead */
-
- if (t->mode == TFM_SEQ_SLIDE) {
- if (t->frame_side == 'B') {
- ED_markers_post_apply_transform(
- &t->scene->markers, t->scene, TFM_TIME_TRANSLATE, t->values[0], t->frame_side);
- }
- }
- else if (ELEM(t->frame_side, 'L', 'R')) {
- ED_markers_post_apply_transform(
- &t->scene->markers, t->scene, TFM_TIME_EXTEND, t->values[0], t->frame_side);
- }
- }
- }
- else if (t->spacetype == SPACE_IMAGE) {
- if (t->options & CTX_MASK) {
- special_aftertrans_update__mask(C, t);
- }
- }
- else if (t->spacetype == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
- special_aftertrans_update__node(C, t);
- if (canceled == 0) {
- ED_node_post_apply_transform(C, snode->edittree);
-
- ED_node_link_insert(bmain, t->sa);
- }
-
- /* clear link line */
- ED_node_link_intersect_test(t->sa, 0);
- }
- else if (t->spacetype == SPACE_CLIP) {
- if (t->options & CTX_MOVIECLIP) {
- special_aftertrans_update__movieclip(C, t);
- }
- else if (t->options & CTX_MASK) {
- special_aftertrans_update__mask(C, t);
- }
- }
- else if (t->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
- bAnimContext ac;
-
- /* initialize relevant anim-context 'context' data */
- if (ANIM_animdata_get_context(C, &ac) == 0) {
- return;
- }
-
- ob = ac.obact;
-
- if (ELEM(ac.datatype, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY, ANIMCONT_TIMELINE)) {
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
-
- /* get channels to work on */
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- /* these should all be F-Curves */
- for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
- FCurve *fcu = (FCurve *)ale->key_data;
-
- /* 3 cases here for curve cleanups:
- * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
- * 2) canceled == 0 -> user confirmed the transform,
- * so duplicates should be removed
- * 3) canceled + duplicate -> user canceled the transform,
- * but we made duplicates, so get rid of these
- */
- if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
- if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
- posttrans_fcurve_clean(fcu, false); /* only use handles in graph editor */
- ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
- }
- else {
- posttrans_fcurve_clean(fcu, false); /* only use handles in graph editor */
- }
- }
- }
-
- /* free temp memory */
- ANIM_animdata_freelist(&anim_data);
- }
- else if (ac.datatype == ANIMCONT_ACTION) { // TODO: just integrate into the above...
- /* Depending on the lock status, draw necessary views */
- // fixme... some of this stuff is not good
- if (ob) {
- if (ob->pose || BKE_key_from_object(ob)) {
- DEG_id_tag_update(&ob->id,
- ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
- }
- else {
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
- }
- }
-
- /* 3 cases here for curve cleanups:
- * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
- * 2) canceled == 0 -> user confirmed the transform,
- * so duplicates should be removed.
- * 3) canceled + duplicate -> user canceled the transform,
- * but we made duplicates, so get rid of these.
- */
- if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
- posttrans_action_clean(&ac, (bAction *)ac.data);
- }
- }
- else if (ac.datatype == ANIMCONT_GPENCIL) {
- /* remove duplicate frames and also make sure points are in order! */
- /* 3 cases here for curve cleanups:
- * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
- * 2) canceled == 0 -> user confirmed the transform,
- * so duplicates should be removed
- * 3) canceled + duplicate -> user canceled the transform,
- * but we made duplicates, so get rid of these
- */
- if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
- bGPdata *gpd;
-
- // XXX: BAD! this get gpencil datablocks directly from main db...
- // but that's how this currently works :/
- for (gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) {
- if (ID_REAL_USERS(gpd)) {
- posttrans_gpd_clean(gpd);
- }
- }
- }
- }
- else if (ac.datatype == ANIMCONT_MASK) {
- /* remove duplicate frames and also make sure points are in order! */
- /* 3 cases here for curve cleanups:
- * 1) NOTRANSKEYCULL on:
- * Cleanup of duplicates shouldn't be done.
- * 2) canceled == 0:
- * User confirmed the transform, so duplicates should be removed.
- * 3) Canceled + duplicate:
- * User canceled the transform, but we made duplicates, so get rid of these.
- */
- if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
- Mask *mask;
-
- // XXX: BAD! this get gpencil datablocks directly from main db...
- // but that's how this currently works :/
- for (mask = bmain->masks.first; mask; mask = mask->id.next) {
- if (ID_REAL_USERS(mask)) {
- posttrans_mask_clean(mask);
- }
- }
- }
- }
-
- /* marker transform, not especially nice but we may want to move markers
- * at the same time as keyframes in the dope sheet.
- */
- if ((saction->flag & SACTION_MARKERS_MOVE) && (canceled == 0)) {
- if (t->mode == TFM_TIME_TRANSLATE) {
-#if 0
- if (ELEM(t->frame_side, 'L', 'R')) { /* TFM_TIME_EXTEND */
- /* same as below */
- ED_markers_post_apply_transform(
- ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side);
- }
- else /* TFM_TIME_TRANSLATE */
-#endif
- {
- ED_markers_post_apply_transform(
- ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side);
- }
- }
- else if (t->mode == TFM_TIME_SCALE) {
- ED_markers_post_apply_transform(
- ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side);
- }
- }
-
- /* make sure all F-Curves are set correctly */
- if (!ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- ANIM_editkeyframes_refresh(&ac);
- }
-
- /* clear flag that was set for time-slide drawing */
- saction->flag &= ~SACTION_MOVING;
- }
- else if (t->spacetype == SPACE_GRAPH) {
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
- bAnimContext ac;
- const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
-
- /* initialize relevant anim-context 'context' data */
- if (ANIM_animdata_get_context(C, &ac) == 0) {
- return;
- }
-
- if (ac.datatype) {
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
-
- /* get channels to work on */
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
- FCurve *fcu = (FCurve *)ale->key_data;
-
- /* 3 cases here for curve cleanups:
- * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
- * 2) canceled == 0 -> user confirmed the transform,
- * so duplicates should be removed
- * 3) canceled + duplicate -> user canceled the transform,
- * but we made duplicates, so get rid of these
- */
- if ((sipo->flag & SIPO_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
- if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
- posttrans_fcurve_clean(fcu, use_handle);
- ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
- }
- else {
- posttrans_fcurve_clean(fcu, use_handle);
- }
- }
- }
-
- /* free temp memory */
- ANIM_animdata_freelist(&anim_data);
- }
-
- /* Make sure all F-Curves are set correctly, but not if transform was
- * canceled, since then curves were already restored to initial state.
- * Note: if the refresh is really needed after cancel then some way
- * has to be added to not update handle types (see bug 22289).
- */
- if (!canceled) {
- ANIM_editkeyframes_refresh(&ac);
- }
- }
- else if (t->spacetype == SPACE_NLA) {
- bAnimContext ac;
-
- /* initialize relevant anim-context 'context' data */
- if (ANIM_animdata_get_context(C, &ac) == 0) {
- return;
- }
-
- if (ac.datatype) {
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT);
-
- /* get channels to work on */
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- for (ale = anim_data.first; ale; ale = ale->next) {
- NlaTrack *nlt = (NlaTrack *)ale->data;
-
- /* make sure strips are in order again */
- BKE_nlatrack_sort_strips(nlt);
-
- /* remove the temp metas */
- BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
- }
-
- /* free temp memory */
- ANIM_animdata_freelist(&anim_data);
-
- /* perform after-transfrom validation */
- ED_nla_postop_refresh(&ac);
- }
- }
- else if (t->flag & T_EDIT) {
- if (t->obedit_type == OB_MESH) {
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- /* table needs to be created for each edit command, since vertices can move etc */
- ED_mesh_mirror_spatial_table(tc->obedit, em, NULL, NULL, 'e');
- /* TODO(campbell): xform: We need support for many mirror objects at once! */
- break;
- }
- }
- }
- else if (t->flag & T_POSE && (t->mode == TFM_BONESIZE)) {
- /* Handle the exception where for TFM_BONESIZE in edit mode we pretend to be
- * in pose mode (to use bone orientation matrix),
- * in that case we don't do operations like autokeyframing. */
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- ob = tc->poseobj;
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
- }
- else if (t->flag & T_POSE) {
- GSet *motionpath_updates = BLI_gset_ptr_new("motionpath updates");
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
-
- bPoseChannel *pchan;
- short targetless_ik = 0;
-
- ob = tc->poseobj;
-
- if ((t->flag & T_AUTOIK) && (t->options & CTX_AUTOCONFIRM)) {
- /* when running transform non-interactively (operator exec),
- * we need to update the pose otherwise no updates get called during
- * transform and the auto-ik is not applied. see [#26164] */
- struct Object *pose_ob = tc->poseobj;
- BKE_pose_where_is(t->depsgraph, t->scene, pose_ob);
- }
-
- /* set BONE_TRANSFORM flags for autokey, gizmo draw might have changed them */
- if (!canceled && (t->mode != TFM_DUMMY)) {
- count_set_pose_transflags(ob, t->mode, t->around, NULL);
- }
-
- /* if target-less IK grabbing, we calculate the pchan transforms and clear flag */
- if (!canceled && t->mode == TFM_TRANSLATION) {
- targetless_ik = apply_targetless_ik(ob);
- }
- else {
- /* not forget to clear the auto flag */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- bKinematicConstraint *data = has_targetless_ik(pchan);
- if (data) {
- data->flag &= ~CONSTRAINT_IK_AUTO;
- }
- }
- }
-
- if (t->mode == TFM_TRANSLATION) {
- pose_grab_with_ik_clear(bmain, ob);
- }
-
- /* automatic inserting of keys and unkeyed tagging -
- * only if transform wasn't canceled (or TFM_DUMMY) */
- if (!canceled && (t->mode != TFM_DUMMY)) {
- autokeyframe_pose(C, t->scene, ob, t->mode, targetless_ik);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
- else {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
-
- if (t->mode != TFM_DUMMY && motionpath_need_update_pose(t->scene, ob)) {
- BLI_gset_insert(motionpath_updates, ob);
- }
- }
-
- /* Update motion paths once for all transformed bones in an object. */
- GSetIterator gs_iter;
- GSET_ITER (gs_iter, motionpath_updates) {
- bool current_frame_only = canceled;
- ob = BLI_gsetIterator_getKey(&gs_iter);
- ED_pose_recalculate_paths(C, t->scene, ob, current_frame_only);
- }
- BLI_gset_free(motionpath_updates, NULL);
- }
- else if (t->options & CTX_PAINT_CURVE) {
- /* pass */
- }
- else if ((t->view_layer->basact) && (ob = t->view_layer->basact->object) &&
- (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->scene, ob)) {
- /* do nothing */
- }
- else if (t->flag & T_CURSOR) {
- /* do nothing */
- }
- else { /* Objects */
- BLI_assert(t->flag & (T_OBJECT | T_TEXTURE));
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
- bool motionpath_update = false;
-
- for (int i = 0; i < tc->data_len; i++) {
- TransData *td = tc->data + i;
- ListBase pidlist;
- PTCacheID *pid;
- ob = td->ob;
-
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- /* flag object caches as outdated */
- BKE_ptcache_ids_from_object(&pidlist, ob, t->scene, MAX_DUPLI_RECUR);
- for (pid = pidlist.first; pid; pid = pid->next) {
- if (pid->type != PTCACHE_TYPE_PARTICLES) {
- /* particles don't need reset on geometry change */
- pid->cache->flag |= PTCACHE_OUTDATED;
- }
- }
- BLI_freelistN(&pidlist);
-
- /* pointcache refresh */
- if (BKE_ptcache_object_reset(t->scene, ob, PTCACHE_RESET_OUTDATED)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
-
- /* Needed for proper updating of "quick cached" dynamics. */
- /* Creates troubles for moving animated objects without */
- /* autokey though, probably needed is an anim sys override? */
- /* Please remove if some other solution is found. -jahka */
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
-
- /* Set autokey if necessary */
- if (!canceled) {
- autokeyframe_object(C, t->scene, t->view_layer, ob, t->mode);
- }
-
- motionpath_update |= motionpath_need_update_object(t->scene, ob);
-
- /* restore rigid body transform */
- if (ob->rigidbody_object && canceled) {
- float ctime = BKE_scene_frame_get(t->scene);
- if (BKE_rigidbody_check_sim_running(t->scene->rigidbody_world, ctime)) {
- BKE_rigidbody_aftertrans_update(ob,
- td->ext->oloc,
- td->ext->orot,
- td->ext->oquat,
- td->ext->orotAxis,
- td->ext->orotAngle);
- }
- }
- }
-
- if (motionpath_update) {
- /* Update motion paths once for all transformed objects. */
- bool current_frame_only = canceled;
- ED_objects_recalculate_paths(C, t->scene, current_frame_only);
- }
- }
-
- clear_trans_object_base_flags(t);
-}
-
-int special_transform_moving(TransInfo *t)
-{
- if (t->spacetype == SPACE_SEQ) {
- return G_TRANSFORM_SEQ;
- }
- else if (t->spacetype == SPACE_GRAPH) {
- return G_TRANSFORM_FCURVES;
- }
- else if ((t->flag & T_EDIT) || (t->flag & T_POSE)) {
- return G_TRANSFORM_EDIT;
- }
- else if (t->flag & (T_OBJECT | T_TEXTURE)) {
- return G_TRANSFORM_OBJ;
- }
-
- return 0;
-}
-
-/* -------------------------------------------------------------------- */
-/** \name Object Data in Object Mode
- *
- * Use to implement 'Affect Only Origins' feature.
- * We need this to be detached from transform data because,
- * unlike transforming regular objects, we need to transform the children.
- *
- * \{ */
-
-struct XFormObjectData_Extra {
- Object *ob;
- float obmat_orig[4][4];
- bool ob_dtx_axis_orig;
- struct XFormObjectData *xod;
-};
-
-static void trans_obdata_in_obmode_ensure_object(TransInfo *t, Object *ob)
-{
- if (t->obdata_in_obmode_map == NULL) {
- t->obdata_in_obmode_map = BLI_ghash_ptr_new(__func__);
- }
-
- void **xf_p;
- if (!BLI_ghash_ensure_p(t->obdata_in_obmode_map, ob->data, &xf_p)) {
- struct XFormObjectData_Extra *xf = MEM_mallocN(sizeof(*xf), __func__);
- copy_m4_m4(xf->obmat_orig, ob->obmat);
- xf->ob = ob;
- /* Result may be NULL, that's OK. */
- xf->xod = ED_object_data_xform_create(ob->data);
- if (xf->xod) {
- xf->ob_dtx_axis_orig = ob->dtx & OB_AXIS;
- ob->dtx |= OB_AXIS;
- }
- *xf_p = xf;
- }
-}
-
-void trans_obdata_in_obmode_update_all(TransInfo *t)
-{
- struct Main *bmain = CTX_data_main(t->context);
- BKE_scene_graph_evaluated_ensure(t->depsgraph, bmain);
-
- GHashIterator gh_iter;
- GHASH_ITER (gh_iter, t->obdata_in_obmode_map) {
- ID *id = BLI_ghashIterator_getKey(&gh_iter);
- struct XFormObjectData_Extra *xf = BLI_ghashIterator_getValue(&gh_iter);
- if (xf->xod == NULL) {
- continue;
- }
-
- Object *ob_eval = DEG_get_evaluated_object(t->depsgraph, xf->ob);
- float imat[4][4], dmat[4][4];
- invert_m4_m4(imat, xf->obmat_orig);
- mul_m4_m4m4(dmat, imat, ob_eval->obmat);
- invert_m4(dmat);
-
- ED_object_data_xform_by_mat4(xf->xod, dmat);
- DEG_id_tag_update(id, 0);
- }
-}
-
-/** Callback for #GHash free. */
-static void trans_obdata_in_obmode_free_elem(void *xf_p)
-{
- struct XFormObjectData_Extra *xf = xf_p;
- if (xf->xod) {
- if (!xf->ob_dtx_axis_orig) {
- xf->ob->dtx &= ~OB_AXIS;
- DEG_id_tag_update(&xf->ob->id, ID_RECALC_COPY_ON_WRITE);
- }
- ED_object_data_xform_destroy(xf->xod);
- }
- MEM_freeN(xf);
-}
-
-void trans_obdata_in_obmode_free_all(TransInfo *t)
-{
- if (t->obdata_in_obmode_map != NULL) {
- BLI_ghash_free(t->obdata_in_obmode_map, NULL, trans_obdata_in_obmode_free_elem);
- }
-}
-
-/** \} */
-
-static void createTransObject(bContext *C, TransInfo *t)
-{
- TransData *td = NULL;
- TransDataExtension *tx;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
-
- set_trans_object_base_flags(t);
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* count */
- tc->data_len = CTX_DATA_COUNT(C, selected_bases);
-
- if (!tc->data_len) {
- /* clear here, main transform function escapes too */
- clear_trans_object_base_flags(t);
- return;
- }
-
- if (is_prop_edit) {
- tc->data_len += count_proportional_objects(t);
- }
-
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransOb");
- tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), "TransObExtension");
-
- CTX_DATA_BEGIN (C, Base *, base, selected_bases) {
- Object *ob = base->object;
-
- td->flag = TD_SELECTED;
- td->protectflag = ob->protectflag;
- td->ext = tx;
- td->ext->rotOrder = ob->rotmode;
-
- if (base->flag & BA_TRANSFORM_CHILD) {
- td->flag |= TD_NOCENTER;
- td->flag |= TD_NO_LOC;
- }
-
- /* select linked objects, but skip them later */
- if (ID_IS_LINKED(ob)) {
- td->flag |= TD_SKIP;
- }
-
- if (t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) {
- ID *id = ob->data;
- if (!id || id->lib) {
- td->flag |= TD_SKIP;
- }
- else if (BKE_object_is_in_editmode(ob)) {
- /* The object could have edit-mode data from another view-layer,
- * it's such a corner-case it can be skipped for now - Campbell. */
- td->flag |= TD_SKIP;
- }
- }
-
- if (t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) {
- if ((td->flag & TD_SKIP) == 0) {
- trans_obdata_in_obmode_ensure_object(t, ob);
- }
- }
-
- ObjectToTransData(t, td, ob);
- td->val = NULL;
- td++;
- tx++;
- }
- CTX_DATA_END;
-
- if (is_prop_edit) {
- ViewLayer *view_layer = t->view_layer;
- View3D *v3d = t->view;
- Base *base;
-
- for (base = view_layer->object_bases.first; base; base = base->next) {
- Object *ob = base->object;
-
- /* if base is not selected, not a parent of selection
- * or not a child of selection and it is editable and selectable */
- if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
- (base->flag & BASE_SELECTED) == 0 && BASE_EDITABLE(v3d, base) &&
- BASE_SELECTABLE(v3d, base)) {
- td->protectflag = ob->protectflag;
- td->ext = tx;
- td->ext->rotOrder = ob->rotmode;
-
- ObjectToTransData(t, td, ob);
- td->val = NULL;
- td++;
- tx++;
- }
- }
- }
-
- if (t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) {
- GSet *objects_in_transdata = BLI_gset_ptr_new_ex(__func__, tc->data_len);
- td = tc->data;
- for (int i = 0; i < tc->data_len; i++, td++) {
- if ((td->flag & TD_SKIP) == 0) {
- BLI_gset_add(objects_in_transdata, td->ob);
- }
- }
-
- ViewLayer *view_layer = t->view_layer;
- View3D *v3d = t->view;
-
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- Object *ob = base->object;
-
- /* if base is not selected, not a parent of selection
- * or not a child of selection and it is editable and selectable */
- if ((base->flag & BASE_SELECTED) == 0 && BASE_EDITABLE(v3d, base) &&
- BASE_SELECTABLE(v3d, base)) {
-
- Object *ob_parent = ob->parent;
- if (ob_parent != NULL) {
- if (!BLI_gset_haskey(objects_in_transdata, ob)) {
- bool parent_in_transdata = false;
- while (ob_parent != NULL) {
- if (BLI_gset_haskey(objects_in_transdata, ob_parent)) {
- parent_in_transdata = true;
- break;
- }
- ob_parent = ob_parent->parent;
- }
- if (parent_in_transdata) {
- trans_obdata_in_obmode_ensure_object(t, ob);
- }
- }
- }
- }
- }
- BLI_gset_free(objects_in_transdata, NULL);
- }
-}
-
-/* transcribe given node into TransData2D for Transforming */
-static void NodeToTransData(TransData *td, TransData2D *td2d, bNode *node, const float dpi_fac)
-{
- float locx, locy;
-
- /* account for parents (nested nodes) */
- if (node->parent) {
- nodeToView(node->parent, node->locx, node->locy, &locx, &locy);
- }
- else {
- locx = node->locx;
- locy = node->locy;
- }
-
- /* use top-left corner as the transform origin for nodes */
- /* weirdo - but the node system is a mix of free 2d elements and dpi sensitive UI */
-#ifdef USE_NODE_CENTER
- td2d->loc[0] = (locx * dpi_fac) + (BLI_rctf_size_x(&node->totr) * +0.5f);
- td2d->loc[1] = (locy * dpi_fac) + (BLI_rctf_size_y(&node->totr) * -0.5f);
-#else
- td2d->loc[0] = locx * dpi_fac;
- td2d->loc[1] = locy * dpi_fac;
-#endif
- td2d->loc[2] = 0.0f;
- td2d->loc2d = td2d->loc; /* current location */
-
- td->flag = 0;
-
- td->loc = td2d->loc;
- copy_v3_v3(td->iloc, td->loc);
- /* use node center instead of origin (top-left corner) */
- td->center[0] = td2d->loc[0];
- td->center[1] = td2d->loc[1];
- td->center[2] = 0.0f;
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
-
- td->flag |= TD_SELECTED;
- td->dist = 0.0;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-
- td->extra = node;
-}
-
-static bool is_node_parent_select(bNode *node)
-{
- while ((node = node->parent)) {
- if (node->flag & NODE_TRANSFORM) {
- return true;
- }
- }
- return false;
-}
-
-static void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
-{
- const float dpi_fac = UI_DPI_FAC;
- TransData *td;
- TransData2D *td2d;
- SpaceNode *snode = t->sa->spacedata.first;
- bNode *node;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- tc->data_len = 0;
-
- if (!snode->edittree) {
- return;
- }
-
- /* nodes dont support PET and probably never will */
- t->flag &= ~T_PROP_EDIT_ALL;
-
- /* set transform flags on nodes */
- for (node = snode->edittree->nodes.first; node; node = node->next) {
- if (node->flag & NODE_SELECT && is_node_parent_select(node) == false) {
- node->flag |= NODE_TRANSFORM;
- tc->data_len++;
- }
- else {
- node->flag &= ~NODE_TRANSFORM;
- }
- }
-
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransNode TransData");
- td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransNode TransData2D");
-
- for (node = snode->edittree->nodes.first; node; node = node->next) {
- if (node->flag & NODE_TRANSFORM) {
- NodeToTransData(td++, td2d++, node, dpi_fac);
- }
- }
-}
-
-/* *** CLIP EDITOR *** */
-
-/* * motion tracking * */
-
-enum transDataTracking_Mode {
- transDataTracking_ModeTracks = 0,
- transDataTracking_ModeCurves = 1,
- transDataTracking_ModePlaneTracks = 2,
-};
-
-typedef struct TransDataTracking {
- int mode, flag;
-
- /* tracks transformation from main window */
- int area;
- const float *relative, *loc;
- float soffset[2], srelative[2];
- float offset[2];
-
- float (*smarkers)[2];
- int markersnr;
- MovieTrackingMarker *markers;
-
- /* marker transformation from curves editor */
- float *prev_pos, scale;
- short coord;
-
- MovieTrackingTrack *track;
- MovieTrackingPlaneTrack *plane_track;
-} TransDataTracking;
-
-static void markerToTransDataInit(TransData *td,
- TransData2D *td2d,
- TransDataTracking *tdt,
- MovieTrackingTrack *track,
- MovieTrackingMarker *marker,
- int area,
- float loc[2],
- float rel[2],
- const float off[2],
- const float aspect[2])
-{
- int anchor = area == TRACK_AREA_POINT && off;
-
- tdt->mode = transDataTracking_ModeTracks;
-
- if (anchor) {
- td2d->loc[0] = rel[0] * aspect[0]; /* hold original location */
- td2d->loc[1] = rel[1] * aspect[1];
-
- tdt->loc = loc;
- td2d->loc2d = loc; /* current location */
- }
- else {
- td2d->loc[0] = loc[0] * aspect[0]; /* hold original location */
- td2d->loc[1] = loc[1] * aspect[1];
-
- td2d->loc2d = loc; /* current location */
- }
- td2d->loc[2] = 0.0f;
-
- tdt->relative = rel;
- tdt->area = area;
-
- tdt->markersnr = track->markersnr;
- tdt->markers = track->markers;
- tdt->track = track;
-
- if (rel) {
- if (!anchor) {
- td2d->loc[0] += rel[0] * aspect[0];
- td2d->loc[1] += rel[1] * aspect[1];
- }
-
- copy_v2_v2(tdt->srelative, rel);
- }
-
- if (off) {
- copy_v2_v2(tdt->soffset, off);
- }
-
- td->flag = 0;
- td->loc = td2d->loc;
- copy_v3_v3(td->iloc, td->loc);
-
- // copy_v3_v3(td->center, td->loc);
- td->flag |= TD_INDIVIDUAL_SCALE;
- td->center[0] = marker->pos[0] * aspect[0];
- td->center[1] = marker->pos[1] * aspect[1];
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
-
- td->flag |= TD_SELECTED;
- td->dist = 0.0;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-}
-
-static void trackToTransData(const int framenr,
- TransData *td,
- TransData2D *td2d,
- TransDataTracking *tdt,
- MovieTrackingTrack *track,
- const float aspect[2])
-{
- MovieTrackingMarker *marker = BKE_tracking_marker_ensure(track, framenr);
-
- tdt->flag = marker->flag;
- marker->flag &= ~(MARKER_DISABLED | MARKER_TRACKED);
-
- markerToTransDataInit(td++,
- td2d++,
- tdt++,
- track,
- marker,
- TRACK_AREA_POINT,
- track->offset,
- marker->pos,
- track->offset,
- aspect);
-
- if (track->flag & SELECT) {
- markerToTransDataInit(
- td++, td2d++, tdt++, track, marker, TRACK_AREA_POINT, marker->pos, NULL, NULL, aspect);
- }
-
- if (track->pat_flag & SELECT) {
- int a;
-
- for (a = 0; a < 4; a++) {
- markerToTransDataInit(td++,
- td2d++,
- tdt++,
- track,
- marker,
- TRACK_AREA_PAT,
- marker->pattern_corners[a],
- marker->pos,
- NULL,
- aspect);
- }
- }
-
- if (track->search_flag & SELECT) {
- markerToTransDataInit(td++,
- td2d++,
- tdt++,
- track,
- marker,
- TRACK_AREA_SEARCH,
- marker->search_min,
- marker->pos,
- NULL,
- aspect);
-
- markerToTransDataInit(td++,
- td2d++,
- tdt++,
- track,
- marker,
- TRACK_AREA_SEARCH,
- marker->search_max,
- marker->pos,
- NULL,
- aspect);
- }
-}
-
-static void planeMarkerToTransDataInit(TransData *td,
- TransData2D *td2d,
- TransDataTracking *tdt,
- MovieTrackingPlaneTrack *plane_track,
- float corner[2],
- const float aspect[2])
-{
- tdt->mode = transDataTracking_ModePlaneTracks;
- tdt->plane_track = plane_track;
-
- td2d->loc[0] = corner[0] * aspect[0]; /* hold original location */
- td2d->loc[1] = corner[1] * aspect[1];
-
- td2d->loc2d = corner; /* current location */
- td2d->loc[2] = 0.0f;
-
- td->flag = 0;
- td->loc = td2d->loc;
- copy_v3_v3(td->iloc, td->loc);
- copy_v3_v3(td->center, td->loc);
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
-
- td->flag |= TD_SELECTED;
- td->dist = 0.0;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-}
-
-static void planeTrackToTransData(const int framenr,
- TransData *td,
- TransData2D *td2d,
- TransDataTracking *tdt,
- MovieTrackingPlaneTrack *plane_track,
- const float aspect[2])
-{
- MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr);
- int i;
-
- tdt->flag = plane_marker->flag;
- plane_marker->flag &= ~PLANE_MARKER_TRACKED;
-
- for (i = 0; i < 4; i++) {
- planeMarkerToTransDataInit(td++, td2d++, tdt++, plane_track, plane_marker->corners[i], aspect);
- }
-}
-
-static void transDataTrackingFree(TransInfo *UNUSED(t),
- TransDataContainer *UNUSED(tc),
- TransCustomData *custom_data)
-{
- if (custom_data->data) {
- TransDataTracking *tdt = custom_data->data;
- if (tdt->smarkers) {
- MEM_freeN(tdt->smarkers);
- }
-
- MEM_freeN(tdt);
- custom_data->data = NULL;
- }
-}
-
-static void createTransTrackingTracksData(bContext *C, TransInfo *t)
-{
- TransData *td;
- TransData2D *td2d;
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
- ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
- MovieTrackingTrack *track;
- MovieTrackingPlaneTrack *plane_track;
- TransDataTracking *tdt;
- int framenr = ED_space_clip_get_clip_frame_number(sc);
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* count */
- tc->data_len = 0;
-
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
- tc->data_len++; /* offset */
-
- if (track->flag & SELECT) {
- tc->data_len++;
- }
-
- if (track->pat_flag & SELECT) {
- tc->data_len += 4;
- }
-
- if (track->search_flag & SELECT) {
- tc->data_len += 2;
- }
- }
-
- track = track->next;
- }
-
- for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
- if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
- tc->data_len += 4;
- }
- }
-
- if (tc->data_len == 0) {
- return;
- }
-
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransTracking TransData");
- td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D),
- "TransTracking TransData2D");
- tdt = tc->custom.type.data = MEM_callocN(tc->data_len * sizeof(TransDataTracking),
- "TransTracking TransDataTracking");
-
- tc->custom.type.free_cb = transDataTrackingFree;
-
- /* create actual data */
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
- trackToTransData(framenr, td, td2d, tdt, track, t->aspect);
-
- /* offset */
- td++;
- td2d++;
- tdt++;
-
- if (track->flag & SELECT) {
- td++;
- td2d++;
- tdt++;
- }
-
- if (track->pat_flag & SELECT) {
- td += 4;
- td2d += 4;
- tdt += 4;
- }
-
- if (track->search_flag & SELECT) {
- td += 2;
- td2d += 2;
- tdt += 2;
- }
- }
-
- track = track->next;
- }
-
- for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
- if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
- planeTrackToTransData(framenr, td, td2d, tdt, plane_track, t->aspect);
- td += 4;
- td2d += 4;
- tdt += 4;
- }
- }
-}
-
-static void markerToTransCurveDataInit(TransData *td,
- TransData2D *td2d,
- TransDataTracking *tdt,
- MovieTrackingTrack *track,
- MovieTrackingMarker *marker,
- MovieTrackingMarker *prev_marker,
- short coord,
- float size)
-{
- float frames_delta = (marker->framenr - prev_marker->framenr);
-
- tdt->flag = marker->flag;
- marker->flag &= ~MARKER_TRACKED;
-
- tdt->mode = transDataTracking_ModeCurves;
- tdt->coord = coord;
- tdt->scale = 1.0f / size * frames_delta;
- tdt->prev_pos = prev_marker->pos;
- tdt->track = track;
-
- /* calculate values depending on marker's speed */
- td2d->loc[0] = marker->framenr;
- td2d->loc[1] = (marker->pos[coord] - prev_marker->pos[coord]) * size / frames_delta;
- td2d->loc[2] = 0.0f;
-
- td2d->loc2d = marker->pos; /* current location */
-
- td->flag = 0;
- td->loc = td2d->loc;
- copy_v3_v3(td->center, td->loc);
- copy_v3_v3(td->iloc, td->loc);
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
-
- td->flag |= TD_SELECTED;
- td->dist = 0.0;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-}
-
-static void createTransTrackingCurvesData(bContext *C, TransInfo *t)
-{
- TransData *td;
- TransData2D *td2d;
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
- MovieTrackingTrack *track;
- MovieTrackingMarker *marker, *prev_marker;
- TransDataTracking *tdt;
- int i, width, height;
-
- BKE_movieclip_get_size(clip, &sc->user, &width, &height);
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* count */
- tc->data_len = 0;
-
- if ((sc->flag & SC_SHOW_GRAPH_TRACKS_MOTION) == 0) {
- return;
- }
-
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
- for (i = 1; i < track->markersnr; i++) {
- marker = &track->markers[i];
- prev_marker = &track->markers[i - 1];
-
- if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) {
- continue;
- }
-
- if (marker->flag & MARKER_GRAPH_SEL_X) {
- tc->data_len += 1;
- }
-
- if (marker->flag & MARKER_GRAPH_SEL_Y) {
- tc->data_len += 1;
- }
- }
- }
-
- track = track->next;
- }
-
- if (tc->data_len == 0) {
- return;
- }
-
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransTracking TransData");
- td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D),
- "TransTracking TransData2D");
- tc->custom.type.data = tdt = MEM_callocN(tc->data_len * sizeof(TransDataTracking),
- "TransTracking TransDataTracking");
- tc->custom.type.free_cb = transDataTrackingFree;
-
- /* create actual data */
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
- for (i = 1; i < track->markersnr; i++) {
- marker = &track->markers[i];
- prev_marker = &track->markers[i - 1];
-
- if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) {
- continue;
- }
-
- if (marker->flag & MARKER_GRAPH_SEL_X) {
- markerToTransCurveDataInit(
- td, td2d, tdt, track, marker, &track->markers[i - 1], 0, width);
- td += 1;
- td2d += 1;
- tdt += 1;
- }
-
- if (marker->flag & MARKER_GRAPH_SEL_Y) {
- markerToTransCurveDataInit(
- td, td2d, tdt, track, marker, &track->markers[i - 1], 1, height);
-
- td += 1;
- td2d += 1;
- tdt += 1;
- }
- }
- }
-
- track = track->next;
- }
-}
-
-static void createTransTrackingData(bContext *C, TransInfo *t)
-{
- ARegion *ar = CTX_wm_region(C);
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- int width, height;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- tc->data_len = 0;
-
- if (!clip) {
- return;
- }
-
- BKE_movieclip_get_size(clip, &sc->user, &width, &height);
-
- if (width == 0 || height == 0) {
- return;
- }
-
- if (ar->regiontype == RGN_TYPE_PREVIEW) {
- /* transformation was called from graph editor */
- createTransTrackingCurvesData(C, t);
- }
- else {
- createTransTrackingTracksData(C, t);
- }
-}
-
-static void cancelTransTracking(TransInfo *t)
-{
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
- SpaceClip *sc = t->sa->spacedata.first;
- int i, framenr = ED_space_clip_get_clip_frame_number(sc);
- TransDataTracking *tdt_array = tc->custom.type.data;
-
- i = 0;
- while (i < tc->data_len) {
- TransDataTracking *tdt = &tdt_array[i];
-
- if (tdt->mode == transDataTracking_ModeTracks) {
- MovieTrackingTrack *track = tdt->track;
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
-
- marker->flag = tdt->flag;
-
- if (track->flag & SELECT) {
- i++;
- }
-
- if (track->pat_flag & SELECT) {
- i += 4;
- }
-
- if (track->search_flag & SELECT) {
- i += 2;
- }
- }
- else if (tdt->mode == transDataTracking_ModeCurves) {
- MovieTrackingTrack *track = tdt->track;
- MovieTrackingMarker *marker, *prev_marker;
- int a;
-
- for (a = 1; a < track->markersnr; a++) {
- marker = &track->markers[a];
- prev_marker = &track->markers[a - 1];
-
- if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) {
- continue;
- }
-
- if (marker->flag & (MARKER_GRAPH_SEL_X | MARKER_GRAPH_SEL_Y)) {
- marker->flag = tdt->flag;
- }
- }
- }
- else if (tdt->mode == transDataTracking_ModePlaneTracks) {
- MovieTrackingPlaneTrack *plane_track = tdt->plane_track;
- MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr);
-
- plane_marker->flag = tdt->flag;
- i += 3;
- }
-
- i++;
- }
-}
-
-void flushTransTracking(TransInfo *t)
-{
- TransData *td;
- TransData2D *td2d;
- TransDataTracking *tdt;
- int a;
-
- if (t->state == TRANS_CANCEL) {
- cancelTransTracking(t);
- }
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = tc->data, td2d = tc->data_2d, tdt = tc->custom.type.data; a < tc->data_len;
- a++, td2d++, td++, tdt++) {
- if (tdt->mode == transDataTracking_ModeTracks) {
- float loc2d[2];
-
- if (t->mode == TFM_ROTATION && tdt->area == TRACK_AREA_SEARCH) {
- continue;
- }
-
- loc2d[0] = td2d->loc[0] / t->aspect[0];
- loc2d[1] = td2d->loc[1] / t->aspect[1];
-
- if (t->flag & T_ALT_TRANSFORM) {
- if (t->mode == TFM_RESIZE) {
- if (tdt->area != TRACK_AREA_PAT) {
- continue;
- }
- }
- else if (t->mode == TFM_TRANSLATION) {
- if (tdt->area == TRACK_AREA_POINT && tdt->relative) {
- float d[2], d2[2];
-
- if (!tdt->smarkers) {
- tdt->smarkers = MEM_callocN(sizeof(*tdt->smarkers) * tdt->markersnr,
- "flushTransTracking markers");
- for (a = 0; a < tdt->markersnr; a++) {
- copy_v2_v2(tdt->smarkers[a], tdt->markers[a].pos);
- }
- }
-
- sub_v2_v2v2(d, loc2d, tdt->soffset);
- sub_v2_v2(d, tdt->srelative);
-
- sub_v2_v2v2(d2, loc2d, tdt->srelative);
-
- for (a = 0; a < tdt->markersnr; a++) {
- add_v2_v2v2(tdt->markers[a].pos, tdt->smarkers[a], d2);
- }
-
- negate_v2_v2(td2d->loc2d, d);
- }
- }
- }
-
- if (tdt->area != TRACK_AREA_POINT || tdt->relative == NULL) {
- td2d->loc2d[0] = loc2d[0];
- td2d->loc2d[1] = loc2d[1];
-
- if (tdt->relative) {
- sub_v2_v2(td2d->loc2d, tdt->relative);
- }
- }
- }
- else if (tdt->mode == transDataTracking_ModeCurves) {
- td2d->loc2d[tdt->coord] = tdt->prev_pos[tdt->coord] + td2d->loc[1] * tdt->scale;
- }
- else if (tdt->mode == transDataTracking_ModePlaneTracks) {
- td2d->loc2d[0] = td2d->loc[0] / t->aspect[0];
- td2d->loc2d[1] = td2d->loc[1] / t->aspect[1];
- }
- }
-}
-
-/* * masking * */
-
-typedef struct TransDataMasking {
- bool is_handle;
-
- float handle[2], orig_handle[2];
- float vec[3][3];
- MaskSplinePoint *point;
- float parent_matrix[3][3];
- float parent_inverse_matrix[3][3];
- char orig_handle_type;
-
- eMaskWhichHandle which_handle;
-} TransDataMasking;
-
-static void MaskHandleToTransData(MaskSplinePoint *point,
- eMaskWhichHandle which_handle,
- TransData *td,
- TransData2D *td2d,
- TransDataMasking *tdm,
- const float asp[2],
- /*const*/ float parent_matrix[3][3],
- /*const*/ float parent_inverse_matrix[3][3])
-{
- BezTriple *bezt = &point->bezt;
- const bool is_sel_any = MASKPOINT_ISSEL_ANY(point);
-
- tdm->point = point;
- copy_m3_m3(tdm->vec, bezt->vec);
-
- tdm->is_handle = true;
- copy_m3_m3(tdm->parent_matrix, parent_matrix);
- copy_m3_m3(tdm->parent_inverse_matrix, parent_inverse_matrix);
-
- BKE_mask_point_handle(point, which_handle, tdm->handle);
- tdm->which_handle = which_handle;
-
- copy_v2_v2(tdm->orig_handle, tdm->handle);
-
- mul_v2_m3v2(td2d->loc, parent_matrix, tdm->handle);
- td2d->loc[0] *= asp[0];
- td2d->loc[1] *= asp[1];
- td2d->loc[2] = 0.0f;
-
- td2d->loc2d = tdm->handle;
-
- td->flag = 0;
- td->loc = td2d->loc;
- mul_v2_m3v2(td->center, parent_matrix, bezt->vec[1]);
- td->center[0] *= asp[0];
- td->center[1] *= asp[1];
- copy_v3_v3(td->iloc, td->loc);
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
-
- if (is_sel_any) {
- td->flag |= TD_SELECTED;
- }
-
- td->dist = 0.0;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-
- if (which_handle == MASK_WHICH_HANDLE_LEFT) {
- tdm->orig_handle_type = bezt->h1;
- }
- else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
- tdm->orig_handle_type = bezt->h2;
- }
-}
-
-static void MaskPointToTransData(Scene *scene,
- MaskSplinePoint *point,
- TransData *td,
- TransData2D *td2d,
- TransDataMasking *tdm,
- const bool is_prop_edit,
- const float asp[2])
-{
- BezTriple *bezt = &point->bezt;
- const bool is_sel_point = MASKPOINT_ISSEL_KNOT(point);
- const bool is_sel_any = MASKPOINT_ISSEL_ANY(point);
- float parent_matrix[3][3], parent_inverse_matrix[3][3];
-
- BKE_mask_point_parent_matrix_get(point, CFRA, parent_matrix);
- invert_m3_m3(parent_inverse_matrix, parent_matrix);
-
- if (is_prop_edit || is_sel_point) {
- int i;
-
- tdm->point = point;
- copy_m3_m3(tdm->vec, bezt->vec);
-
- for (i = 0; i < 3; i++) {
- copy_m3_m3(tdm->parent_matrix, parent_matrix);
- copy_m3_m3(tdm->parent_inverse_matrix, parent_inverse_matrix);
-
- /* CV coords are scaled by aspects. this is needed for rotations and
- * proportional editing to be consistent with the stretched CV coords
- * that are displayed. this also means that for display and numinput,
- * and when the CV coords are flushed, these are converted each time */
- mul_v2_m3v2(td2d->loc, parent_matrix, bezt->vec[i]);
- td2d->loc[0] *= asp[0];
- td2d->loc[1] *= asp[1];
- td2d->loc[2] = 0.0f;
-
- td2d->loc2d = bezt->vec[i];
-
- td->flag = 0;
- td->loc = td2d->loc;
- mul_v2_m3v2(td->center, parent_matrix, bezt->vec[1]);
- td->center[0] *= asp[0];
- td->center[1] *= asp[1];
- copy_v3_v3(td->iloc, td->loc);
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
-
- if (i == 1) {
- /* scaling weights */
- td->val = &bezt->weight;
- td->ival = *td->val;
- }
- else {
- td->val = NULL;
- }
-
- if (is_sel_any) {
- td->flag |= TD_SELECTED;
- }
- td->dist = 0.0;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-
- if (i == 0) {
- tdm->orig_handle_type = bezt->h1;
- }
- else if (i == 2) {
- tdm->orig_handle_type = bezt->h2;
- }
-
- td++;
- td2d++;
- tdm++;
- }
- }
- else {
- if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
- MaskHandleToTransData(point,
- MASK_WHICH_HANDLE_STICK,
- td,
- td2d,
- tdm,
- asp,
- parent_matrix,
- parent_inverse_matrix);
-
- td++;
- td2d++;
- tdm++;
- }
- else {
- if (bezt->f1 & SELECT) {
- MaskHandleToTransData(point,
- MASK_WHICH_HANDLE_LEFT,
- td,
- td2d,
- tdm,
- asp,
- parent_matrix,
- parent_inverse_matrix);
-
- if (bezt->h1 == HD_VECT) {
- bezt->h1 = HD_FREE;
- }
- else if (bezt->h1 == HD_AUTO) {
- bezt->h1 = HD_ALIGN_DOUBLESIDE;
- bezt->h2 = HD_ALIGN_DOUBLESIDE;
- }
-
- td++;
- td2d++;
- tdm++;
- }
- if (bezt->f3 & SELECT) {
- MaskHandleToTransData(point,
- MASK_WHICH_HANDLE_RIGHT,
- td,
- td2d,
- tdm,
- asp,
- parent_matrix,
- parent_inverse_matrix);
-
- if (bezt->h2 == HD_VECT) {
- bezt->h2 = HD_FREE;
- }
- else if (bezt->h2 == HD_AUTO) {
- bezt->h1 = HD_ALIGN_DOUBLESIDE;
- bezt->h2 = HD_ALIGN_DOUBLESIDE;
- }
-
- td++;
- td2d++;
- tdm++;
- }
- }
- }
-}
-
-static void createTransMaskingData(bContext *C, TransInfo *t)
-{
- Scene *scene = CTX_data_scene(C);
- Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
- TransData *td = NULL;
- TransData2D *td2d = NULL;
- TransDataMasking *tdm = NULL;
- int count = 0, countsel = 0;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT);
- float asp[2];
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- tc->data_len = 0;
-
- if (!mask) {
- return;
- }
-
- if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sc = t->sa->spacedata.first;
- MovieClip *clip = ED_space_clip_get_clip(sc);
- if (!clip) {
- return;
- }
- }
-
- /* count */
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
-
- if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
- continue;
- }
-
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- int i;
-
- for (i = 0; i < spline->tot_point; i++) {
- MaskSplinePoint *point = &spline->points[i];
-
- if (MASKPOINT_ISSEL_ANY(point)) {
- if (MASKPOINT_ISSEL_KNOT(point)) {
- countsel += 3;
- }
- else {
- if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
- countsel += 1;
- }
- else {
- BezTriple *bezt = &point->bezt;
- if (bezt->f1 & SELECT) {
- countsel++;
- }
- if (bezt->f3 & SELECT) {
- countsel++;
- }
- }
- }
- }
-
- if (is_prop_edit) {
- count += 3;
- }
- }
- }
- }
-
- /* note: in prop mode we need at least 1 selected */
- if (countsel == 0) {
- return;
- }
-
- ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]);
-
- tc->data_len = (is_prop_edit) ? count : countsel;
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Mask Editing)");
- /* for each 2d uv coord a 3d vector is allocated, so that they can be
- * treated just as if they were 3d verts */
- td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D),
- "TransObData2D(Mask Editing)");
- tc->custom.type.data = tdm = MEM_callocN(tc->data_len * sizeof(TransDataMasking),
- "TransDataMasking(Mask Editing)");
- tc->custom.type.use_free = true;
-
- /* create data */
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
-
- if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
- continue;
- }
-
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- int i;
-
- for (i = 0; i < spline->tot_point; i++) {
- MaskSplinePoint *point = &spline->points[i];
-
- if (is_prop_edit || MASKPOINT_ISSEL_ANY(point)) {
- MaskPointToTransData(scene, point, td, td2d, tdm, is_prop_edit, asp);
-
- if (is_prop_edit || MASKPOINT_ISSEL_KNOT(point)) {
- td += 3;
- td2d += 3;
- tdm += 3;
- }
- else {
- if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
- td++;
- td2d++;
- tdm++;
- }
- else {
- BezTriple *bezt = &point->bezt;
- if (bezt->f1 & SELECT) {
- td++;
- td2d++;
- tdm++;
- }
- if (bezt->f3 & SELECT) {
- td++;
- td2d++;
- tdm++;
- }
- }
- }
- }
- }
- }
- }
-}
-
-void flushTransMasking(TransInfo *t)
-{
- TransData2D *td;
- TransDataMasking *tdm;
- int a;
- float asp[2], inv[2];
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]);
- inv[0] = 1.0f / asp[0];
- inv[1] = 1.0f / asp[1];
-
- /* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = tc->data_2d, tdm = tc->custom.type.data; a < tc->data_len; a++, td++, tdm++) {
- td->loc2d[0] = td->loc[0] * inv[0];
- td->loc2d[1] = td->loc[1] * inv[1];
- mul_m3_v2(tdm->parent_inverse_matrix, td->loc2d);
-
- if (tdm->is_handle) {
- BKE_mask_point_set_handle(tdm->point,
- tdm->which_handle,
- td->loc2d,
- (t->flag & T_ALT_TRANSFORM) != 0,
- tdm->orig_handle,
- tdm->vec);
- }
-
- if (t->state == TRANS_CANCEL) {
- if (tdm->which_handle == MASK_WHICH_HANDLE_LEFT) {
- tdm->point->bezt.h1 = tdm->orig_handle_type;
- }
- else if (tdm->which_handle == MASK_WHICH_HANDLE_RIGHT) {
- tdm->point->bezt.h2 = tdm->orig_handle_type;
- }
- }
- }
-}
-
-typedef struct TransDataPaintCurve {
- PaintCurvePoint *pcp; /* initial curve point */
- char id;
-} TransDataPaintCurve;
-
-#define PC_IS_ANY_SEL(pc) (((pc)->bez.f1 | (pc)->bez.f2 | (pc)->bez.f3) & SELECT)
-
-static void PaintCurveConvertHandle(
- PaintCurvePoint *pcp, int id, TransData2D *td2d, TransDataPaintCurve *tdpc, TransData *td)
-{
- BezTriple *bezt = &pcp->bez;
- copy_v2_v2(td2d->loc, bezt->vec[id]);
- td2d->loc[2] = 0.0f;
- td2d->loc2d = bezt->vec[id];
-
- td->flag = 0;
- td->loc = td2d->loc;
- copy_v3_v3(td->center, bezt->vec[1]);
- copy_v3_v3(td->iloc, td->loc);
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
- td->flag |= TD_SELECTED;
- td->dist = 0.0;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-
- tdpc->id = id;
- tdpc->pcp = pcp;
-}
-
-static void PaintCurvePointToTransData(PaintCurvePoint *pcp,
- TransData *td,
- TransData2D *td2d,
- TransDataPaintCurve *tdpc)
-{
- BezTriple *bezt = &pcp->bez;
-
- if (pcp->bez.f2 == SELECT) {
- int i;
- for (i = 0; i < 3; i++) {
- copy_v2_v2(td2d->loc, bezt->vec[i]);
- td2d->loc[2] = 0.0f;
- td2d->loc2d = bezt->vec[i];
-
- td->flag = 0;
- td->loc = td2d->loc;
- copy_v3_v3(td->center, bezt->vec[1]);
- copy_v3_v3(td->iloc, td->loc);
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
- td->flag |= TD_SELECTED;
- td->dist = 0.0;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-
- tdpc->id = i;
- tdpc->pcp = pcp;
-
- td++;
- td2d++;
- tdpc++;
- }
- }
- else {
- if (bezt->f3 & SELECT) {
- PaintCurveConvertHandle(pcp, 2, td2d, tdpc, td);
- td2d++;
- tdpc++;
- td++;
- }
-
- if (bezt->f1 & SELECT) {
- PaintCurveConvertHandle(pcp, 0, td2d, tdpc, td);
- }
- }
-}
-
-static void createTransPaintCurveVerts(bContext *C, TransInfo *t)
-{
- Paint *paint = BKE_paint_get_active_from_context(C);
- PaintCurve *pc;
- PaintCurvePoint *pcp;
- Brush *br;
- TransData *td = NULL;
- TransData2D *td2d = NULL;
- TransDataPaintCurve *tdpc = NULL;
- int i;
- int total = 0;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- tc->data_len = 0;
-
- if (!paint || !paint->brush || !paint->brush->paint_curve) {
- return;
- }
-
- br = paint->brush;
- pc = br->paint_curve;
-
- for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) {
- if (PC_IS_ANY_SEL(pcp)) {
- if (pcp->bez.f2 & SELECT) {
- total += 3;
- continue;
- }
- else {
- if (pcp->bez.f1 & SELECT) {
- total++;
- }
- if (pcp->bez.f3 & SELECT) {
- total++;
- }
- }
- }
- }
-
- if (!total) {
- return;
- }
-
- tc->data_len = total;
- td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransData2D");
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData");
- tc->custom.type.data = tdpc = MEM_callocN(tc->data_len * sizeof(TransDataPaintCurve),
- "TransDataPaintCurve");
- tc->custom.type.use_free = true;
-
- for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) {
- if (PC_IS_ANY_SEL(pcp)) {
- PaintCurvePointToTransData(pcp, td, td2d, tdpc);
-
- if (pcp->bez.f2 & SELECT) {
- td += 3;
- td2d += 3;
- tdpc += 3;
- }
- else {
- if (pcp->bez.f1 & SELECT) {
- td++;
- td2d++;
- tdpc++;
- }
- if (pcp->bez.f3 & SELECT) {
- td++;
- td2d++;
- tdpc++;
- }
- }
- }
- }
-}
-
-void flushTransPaintCurve(TransInfo *t)
-{
- int i;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- TransData2D *td2d = tc->data_2d;
- TransDataPaintCurve *tdpc = tc->custom.type.data;
-
- for (i = 0; i < tc->data_len; i++, tdpc++, td2d++) {
- PaintCurvePoint *pcp = tdpc->pcp;
- copy_v2_v2(pcp->bez.vec[tdpc->id], td2d->loc);
- }
-}
-
-static void createTransGPencil_center_get(bGPDstroke *gps, float r_center[3])
-{
- bGPDspoint *pt;
- int i;
-
- zero_v3(r_center);
- int tot_sel = 0;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- add_v3_v3(r_center, &pt->x);
- tot_sel++;
- }
- }
-
- if (tot_sel > 0) {
- mul_v3_fl(r_center, 1.0f / tot_sel);
- }
-}
-
-static void createTransGPencil(bContext *C, TransInfo *t)
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
-
- bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- bool use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) != 0;
-
- Object *obact = CTX_data_active_object(C);
- bGPDlayer *gpl;
- TransData *td = NULL;
- float mtx[3][3], smtx[3][3];
-
- const Scene *scene = CTX_data_scene(C);
- const int cfra_scene = CFRA;
-
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
- const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* == Grease Pencil Strokes to Transform Data ==
- * Grease Pencil stroke points can be a mixture of 2D (screen-space),
- * or 3D coordinates. However, they're always saved as 3D points.
- * For now, we just do these without creating TransData2D for the 2D
- * strokes. This may cause issues in future though.
- */
- tc->data_len = 0;
-
- if (gpd == NULL) {
- return;
- }
-
- /* initialize falloff curve */
- if (is_multiedit) {
- BKE_curvemapping_initialize(ts->gp_sculpt.cur_falloff);
- }
-
- /* First Pass: Count the number of data-points required for the strokes,
- * (and additional info about the configuration - e.g. 2D/3D?).
- */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
- bGPDframe *gpf;
- bGPDstroke *gps;
- bGPDframe *init_gpf = gpl->actframe;
- if (is_multiedit) {
- init_gpf = gpl->frames.first;
- }
-
- for (gpf = init_gpf; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
- continue;
- }
-
- if (is_prop_edit) {
- /* Proportional Editing... */
- if (is_prop_edit_connected) {
- /* connected only - so only if selected */
- if (gps->flag & GP_STROKE_SELECT) {
- tc->data_len += gps->totpoints;
- }
- }
- else {
- /* everything goes - connection status doesn't matter */
- tc->data_len += gps->totpoints;
- }
- }
- else {
- /* only selected stroke points are considered */
- if (gps->flag & GP_STROKE_SELECT) {
- bGPDspoint *pt;
- int i;
-
- // TODO: 2D vs 3D?
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- tc->data_len++;
- }
- }
- }
- }
- }
- }
- /* if not multiedit out of loop */
- if (!is_multiedit) {
- break;
- }
- }
- }
- }
-
- /* Stop trying if nothing selected */
- if (tc->data_len == 0) {
- return;
- }
-
- /* Allocate memory for data */
- tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(GPencil)");
- td = tc->data;
-
- unit_m3(smtx);
- unit_m3(mtx);
-
- /* Second Pass: Build transdata array */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
- const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene;
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps;
- float diff_mat[4][4];
- float inverse_diff_mat[4][4];
-
- bGPDframe *init_gpf = gpl->actframe;
- if (is_multiedit) {
- init_gpf = gpl->frames.first;
- }
- /* init multiframe falloff options */
- int f_init = 0;
- int f_end = 0;
-
- if (use_multiframe_falloff) {
- BKE_gpencil_get_range_selected(gpl, &f_init, &f_end);
- }
-
- /* calculate difference matrix */
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
- /* undo matrix */
- invert_m4_m4(inverse_diff_mat, diff_mat);
-
- /* Make a new frame to work on if the layer's frame
- * and the current scene frame don't match up.
- *
- * - This is useful when animating as it saves that "uh-oh" moment when you realize you've
- * spent too much time editing the wrong frame...
- */
- // XXX: should this be allowed when framelock is enabled?
- if ((gpf->framenum != cfra) && (!is_multiedit)) {
- gpf = BKE_gpencil_frame_addcopy(gpl, cfra);
- /* in some weird situations (framelock enabled) return NULL */
- if (gpf == NULL) {
- continue;
- }
- if (!is_multiedit) {
- init_gpf = gpf;
- }
- }
-
- /* Loop over strokes, adding TransData for points as needed... */
- for (gpf = init_gpf; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
-
- /* if multiframe and falloff, recalculate and save value */
- float falloff = 1.0f; /* by default no falloff */
- if ((is_multiedit) && (use_multiframe_falloff)) {
- /* Faloff depends on distance to active frame (relative to the overall frame range) */
- falloff = BKE_gpencil_multiframe_falloff_calc(
- gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff);
- }
-
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- TransData *head = td;
- TransData *tail = td;
- bool stroke_ok;
-
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
- continue;
- }
- /* What we need to include depends on proportional editing settings... */
- if (is_prop_edit) {
- if (is_prop_edit_connected) {
- /* A) "Connected" - Only those in selected strokes */
- stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
- }
- else {
- /* B) All points, always */
- stroke_ok = true;
- }
- }
- else {
- /* C) Only selected points in selected strokes */
- stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
- }
-
- /* Do stroke... */
- if (stroke_ok && gps->totpoints) {
- bGPDspoint *pt;
- int i;
-
- /* save falloff factor */
- gps->runtime.multi_frame_falloff = falloff;
-
- /* calculate stroke center */
- float center[3];
- createTransGPencil_center_get(gps, center);
-
- /* add all necessary points... */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- bool point_ok;
-
- /* include point? */
- if (is_prop_edit) {
- /* Always all points in strokes that get included */
- point_ok = true;
- }
- else {
- /* Only selected points in selected strokes */
- point_ok = (pt->flag & GP_SPOINT_SELECT) != 0;
- }
-
- /* do point... */
- if (point_ok) {
- copy_v3_v3(td->iloc, &pt->x);
- /* only copy center in local origins.
- * This allows get interesting effects also when move
- * using proportional editing */
- if ((gps->flag & GP_STROKE_SELECT) &&
- (ts->transform_pivot_point == V3D_AROUND_LOCAL_ORIGINS)) {
- copy_v3_v3(td->center, center);
- }
- else {
- copy_v3_v3(td->center, &pt->x);
- }
-
- td->loc = &pt->x;
-
- td->flag = 0;
-
- if (pt->flag & GP_SPOINT_SELECT) {
- td->flag |= TD_SELECTED;
- }
-
- /* for other transform modes (e.g. shrink-fatten), need to additional data
- * but never for scale or mirror
- */
- if ((t->mode != TFM_RESIZE) && (t->mode != TFM_MIRROR)) {
- if (t->mode != TFM_GPENCIL_OPACITY) {
- td->val = &pt->pressure;
- td->ival = pt->pressure;
- }
- else {
- td->val = &pt->strength;
- td->ival = pt->strength;
- }
- }
-
- /* screenspace needs special matrices... */
- if ((gps->flag & (GP_STROKE_3DSPACE | GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) ==
- 0) {
- /* screenspace */
- td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
- }
- else {
- /* configure 2D dataspace points so that they don't play up... */
- if (gps->flag & (GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) {
- td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
- }
- }
- /* apply parent transformations */
- copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */
- copy_m3_m4(td->mtx, diff_mat); /* display position */
- copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */
-
- /* Triangulation must be calculated again,
- * so save the stroke for recalc function */
- td->extra = gps;
-
- /* save pointer to object */
- td->ob = obact;
-
- td++;
- tail++;
- }
- }
-
- /* March over these points, and calculate the proportional editing distances */
- if (is_prop_edit && (head != tail)) {
- /* XXX: for now, we are similar enough that this works... */
- calc_distanceCurveVerts(head, tail - 1);
- }
- }
- }
- }
- /* if not multiedit out of loop */
- if (!is_multiedit) {
- break;
- }
- }
- }
- }
-}
-
-static int countAndCleanTransDataContainer(TransInfo *t)
-{
- BLI_assert(ELEM(t->data_len_all, 0, -1));
- t->data_len_all = 0;
- uint data_container_len_orig = t->data_container_len;
- for (TransDataContainer *th_end = t->data_container - 1,
- *tc = t->data_container + (t->data_container_len - 1);
- tc != th_end;
- tc--) {
- if (tc->data_len == 0) {
- uint index = tc - t->data_container;
- if (index + 1 != t->data_container_len) {
- SWAP(TransDataContainer,
- t->data_container[index],
- t->data_container[t->data_container_len - 1]);
- }
- t->data_container_len -= 1;
- }
- else {
- t->data_len_all += tc->data_len;
- }
- }
- if (data_container_len_orig != t->data_container_len) {
- t->data_container = MEM_reallocN(t->data_container,
- sizeof(*t->data_container) * t->data_container_len);
- }
- return t->data_len_all;
-}
-
-void createTransData(bContext *C, TransInfo *t)
-{
- Scene *scene = t->scene;
- ViewLayer *view_layer = t->view_layer;
- Object *ob = OBACT(view_layer);
-
- bool has_transform_context = true;
- t->data_len_all = -1;
-
- /* if tests must match recalcData for correct updates */
- if (t->options & CTX_CURSOR) {
- t->flag |= T_CURSOR;
- t->obedit_type = -1;
-
- if (t->spacetype == SPACE_IMAGE) {
- createTransCursor_image(t);
- }
- else {
- createTransCursor_view3d(t);
- }
- countAndCleanTransDataContainer(t);
- }
- else if (t->options & CTX_TEXTURE) {
- t->flag |= T_TEXTURE;
- t->obedit_type = -1;
-
- createTransTexspace(t);
- countAndCleanTransDataContainer(t);
- }
- else if (t->options & CTX_EDGE) {
- /* Multi object editing. */
- initTransDataContainers_FromObjectData(t, ob, NULL, 0);
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- tc->data_ext = NULL;
- }
- t->flag |= T_EDIT;
-
- createTransEdge(t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && t->flag & T_PROP_EDIT) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
- }
- else if (t->options & CTX_GPENCIL_STROKES) {
- t->options |= CTX_GPENCIL_STROKES;
- t->flag |= T_POINTS | T_EDIT;
-
- initTransDataContainers_FromObjectData(t, ob, NULL, 0);
- createTransGPencil(C, t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
- }
- else if (t->spacetype == SPACE_IMAGE) {
- t->flag |= T_POINTS | T_2D_EDIT;
- if (t->options & CTX_MASK) {
-
- /* copied from below */
- createTransMaskingData(C, t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, true);
- sort_trans_data_dist(t);
- }
- }
- else if (t->options & CTX_PAINT_CURVE) {
- if (!ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) {
- createTransPaintCurveVerts(C, t);
- countAndCleanTransDataContainer(t);
- }
- else {
- has_transform_context = false;
- }
- }
- else if (t->obedit_type == OB_MESH) {
-
- initTransDataContainers_FromObjectData(t, ob, NULL, 0);
- createTransUVs(C, t);
- countAndCleanTransDataContainer(t);
-
- t->flag |= T_EDIT;
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
- }
- else {
- has_transform_context = false;
- }
- }
- else if (t->spacetype == SPACE_ACTION) {
- t->flag |= T_POINTS | T_2D_EDIT;
- t->obedit_type = -1;
-
- createTransActionData(C, t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- sort_trans_data_selected_first(t);
- /* don't do that, distance has been set in createTransActionData already */
- // set_prop_dist(t, false);
- sort_trans_data_dist(t);
- }
- }
- else if (t->spacetype == SPACE_NLA) {
- t->flag |= T_POINTS | T_2D_EDIT;
- t->obedit_type = -1;
-
- createTransNlaData(C, t);
- countAndCleanTransDataContainer(t);
- }
- else if (t->spacetype == SPACE_SEQ) {
- t->flag |= T_POINTS | T_2D_EDIT;
- t->obedit_type = -1;
-
- t->num.flag |= NUM_NO_FRACTION; /* sequencer has no use for floating point trasnform */
- createTransSeqData(C, t);
- countAndCleanTransDataContainer(t);
- }
- else if (t->spacetype == SPACE_GRAPH) {
- t->flag |= T_POINTS | T_2D_EDIT;
- t->obedit_type = -1;
-
- createTransGraphEditData(C, t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- /* makes selected become first in array */
- sort_trans_data_selected_first(t);
-
- /* don't do that, distance has been set in createTransGraphEditData already */
- set_prop_dist(t, false);
-
- sort_trans_data_dist(t);
- }
- }
- else if (t->spacetype == SPACE_NODE) {
- t->flag |= T_POINTS | T_2D_EDIT;
- t->obedit_type = -1;
-
- createTransNodeData(C, t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
- }
- else if (t->spacetype == SPACE_CLIP) {
- t->flag |= T_POINTS | T_2D_EDIT;
- t->obedit_type = -1;
-
- if (t->options & CTX_MOVIECLIP) {
- createTransTrackingData(C, t);
- countAndCleanTransDataContainer(t);
- }
- else if (t->options & CTX_MASK) {
- /* copied from above */
- createTransMaskingData(C, t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, true);
- sort_trans_data_dist(t);
- }
- }
- else {
- has_transform_context = false;
- }
- }
- else if (t->obedit_type != -1) {
- /* Multi object editing. */
- initTransDataContainers_FromObjectData(t, ob, NULL, 0);
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- tc->data_ext = NULL;
- }
- if (t->obedit_type == OB_MESH) {
- createTransEditVerts(t);
- }
- else if (ELEM(t->obedit_type, OB_CURVE, OB_SURF)) {
- createTransCurveVerts(t);
- }
- else if (t->obedit_type == OB_LATTICE) {
- createTransLatticeVerts(t);
- }
- else if (t->obedit_type == OB_MBALL) {
- createTransMBallVerts(t);
- }
- else if (t->obedit_type == OB_ARMATURE) {
- t->flag &= ~T_PROP_EDIT;
- createTransArmatureVerts(t);
- }
- else {
- printf("edit type not implemented!\n");
- }
-
- countAndCleanTransDataContainer(t);
-
- t->flag |= T_EDIT | T_POINTS;
-
- if (t->data_len_all) {
- if (t->flag & T_PROP_EDIT) {
- if (ELEM(t->obedit_type, OB_CURVE, OB_MESH)) {
- sort_trans_data_selected_first(t);
- if ((t->obedit_type == OB_MESH) && (t->flag & T_PROP_CONNECTED)) {
- /* already calculated by editmesh_set_connectivity_distance */
- }
- else {
- set_prop_dist(t, 0);
- }
- sort_trans_data_dist(t);
- }
- else {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
- }
- else {
- if (ELEM(t->obedit_type, OB_CURVE)) {
- /* Needed because bezier handles can be partially selected
- * and are still added into transform data. */
- sort_trans_data_selected_first(t);
- }
- }
- }
-
- /* exception... hackish, we want bonesize to use bone orientation matrix (ton) */
- if (t->mode == TFM_BONESIZE) {
- t->flag &= ~(T_EDIT | T_POINTS);
- t->flag |= T_POSE;
- t->obedit_type = -1;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- tc->poseobj = tc->obedit;
- tc->obedit = NULL;
- }
- }
- }
- else if (ob && (ob->mode & OB_MODE_POSE)) {
- /* XXX this is currently limited to active armature only... */
-
- /* XXX active-layer checking isn't done
- * as that should probably be checked through context instead. */
-
- /* Multi object editing. */
- initTransDataContainers_FromObjectData(t, ob, NULL, 0);
- createTransPose(t);
- countAndCleanTransDataContainer(t);
- }
- else if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && !(t->options & CTX_PAINT_CURVE)) {
- /* important that ob_armature can be set even when its not selected [#23412]
- * lines below just check is also visible */
- has_transform_context = false;
- Object *ob_armature = modifiers_isDeformedByArmature(ob);
- if (ob_armature && ob_armature->mode & OB_MODE_POSE) {
- Base *base_arm = BKE_view_layer_base_find(t->view_layer, ob_armature);
- if (base_arm) {
- View3D *v3d = t->view;
- if (BASE_VISIBLE(v3d, base_arm)) {
- Object *objects[1];
- objects[0] = ob_armature;
- uint objects_len = 1;
- initTransDataContainers_FromObjectData(t, ob_armature, objects, objects_len);
- createTransPose(t);
- countAndCleanTransDataContainer(t);
- has_transform_context = true;
- }
- }
- }
- }
- else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_start_edit(PE_get_current(scene, ob))) {
- createTransParticleVerts(C, t);
- countAndCleanTransDataContainer(t);
- t->flag |= T_POINTS;
-
- if (t->data_len_all && t->flag & T_PROP_EDIT) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
- }
- else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
- if ((t->options & CTX_PAINT_CURVE) && !ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) {
- t->flag |= T_POINTS | T_2D_EDIT;
- createTransPaintCurveVerts(C, t);
- countAndCleanTransDataContainer(t);
- }
- else {
- has_transform_context = false;
- }
- }
- else if ((ob) &&
- (ELEM(
- ob->mode, OB_MODE_PAINT_GPENCIL, OB_MODE_SCULPT_GPENCIL, OB_MODE_WEIGHT_GPENCIL))) {
- /* In grease pencil all transformations must be canceled if not Object or Edit. */
- has_transform_context = false;
- }
- else {
- /* Needed for correct Object.obmat after duplication, see: T62135. */
- BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context));
-
- if ((scene->toolsettings->transform_flag & SCE_XFORM_DATA_ORIGIN) != 0) {
- t->flag |= T_OBJECT_DATA_IN_OBJECT_MODE;
- }
-
- createTransObject(C, t);
- countAndCleanTransDataContainer(t);
- t->flag |= T_OBJECT;
-
- if (t->data_len_all && t->flag & T_PROP_EDIT) {
- // selected objects are already first, no need to presort
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
-
- /* Check if we're transforming the camera from the camera */
- if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) {
- View3D *v3d = t->view;
- RegionView3D *rv3d = t->ar->regiondata;
- if ((rv3d->persp == RV3D_CAMOB) && v3d->camera) {
- /* we could have a flag to easily check an object is being transformed */
- if (v3d->camera->id.tag & LIB_TAG_DOIT) {
- t->flag |= T_CAMERA;
- }
- }
- }
- }
-
- /* Check that 'countAndCleanTransDataContainer' ran. */
- if (has_transform_context) {
- BLI_assert(t->data_len_all != -1);
- }
- else {
- BLI_assert(t->data_len_all == -1);
- t->data_len_all = 0;
- }
-
- BLI_assert((!(t->flag & T_EDIT)) == (!(t->obedit_type != -1)));
-}
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
new file mode 100644
index 00000000000..5862faaf667
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert.c
@@ -0,0 +1,2743 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_space_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_mask_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_kdtree.h"
+
+#include "BKE_animsys.h"
+#include "BKE_armature.h"
+#include "BKE_context.h"
+#include "BKE_fcurve.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_layer.h"
+#include "BKE_key.h"
+#include "BKE_main.h"
+#include "BKE_modifier.h"
+#include "BKE_nla.h"
+#include "BKE_node.h"
+#include "BKE_pointcache.h"
+#include "BKE_rigidbody.h"
+#include "BKE_scene.h"
+#include "BKE_editmesh.h"
+#include "BKE_tracking.h"
+#include "BKE_mask.h"
+
+#include "BIK_api.h"
+
+#include "ED_anim_api.h"
+#include "ED_armature.h"
+#include "ED_particle.h"
+#include "ED_image.h"
+#include "ED_keyframing.h"
+#include "ED_keyframes_edit.h"
+#include "ED_object.h"
+#include "ED_markers.h"
+#include "ED_mesh.h"
+#include "ED_node.h"
+#include "ED_clip.h"
+#include "ED_mask.h"
+
+#include "WM_api.h" /* for WM_event_add_notifier to deal with stabilization nodes */
+#include "WM_types.h"
+
+#include "RNA_access.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/**
+ * Transforming around ourselves is no use, fallback to individual origins,
+ * useful for curve/armatures.
+ */
+void transform_around_single_fallback(TransInfo *t)
+{
+ if ((t->data_len_all == 1) &&
+ (ELEM(t->around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEDIAN, V3D_AROUND_ACTIVE)) &&
+ (ELEM(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL))) {
+ t->around = V3D_AROUND_LOCAL_ORIGINS;
+ }
+}
+
+/* ************************** Functions *************************** */
+
+static int trans_data_compare_dist(const void *a, const void *b)
+{
+ const TransData *td_a = (const TransData *)a;
+ const TransData *td_b = (const TransData *)b;
+
+ if (td_a->dist < td_b->dist) {
+ return -1;
+ }
+ else if (td_a->dist > td_b->dist) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+static int trans_data_compare_rdist(const void *a, const void *b)
+{
+ const TransData *td_a = (const TransData *)a;
+ const TransData *td_b = (const TransData *)b;
+
+ if (td_a->rdist < td_b->rdist) {
+ return -1;
+ }
+ else if (td_a->rdist > td_b->rdist) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+static void sort_trans_data_dist_container(const TransInfo *t, TransDataContainer *tc)
+{
+ TransData *start = tc->data;
+ int i;
+
+ for (i = 0; i < tc->data_len && start->flag & TD_SELECTED; i++) {
+ start++;
+ }
+
+ if (i < tc->data_len) {
+ if (t->flag & T_PROP_CONNECTED) {
+ qsort(start, tc->data_len - i, sizeof(TransData), trans_data_compare_dist);
+ }
+ else {
+ qsort(start, tc->data_len - i, sizeof(TransData), trans_data_compare_rdist);
+ }
+ }
+}
+void sort_trans_data_dist(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ sort_trans_data_dist_container(t, tc);
+ }
+}
+
+/**
+ * Make #TD_SELECTED first in the array.
+ */
+static void sort_trans_data_selected_first_container(TransDataContainer *tc)
+{
+ TransData *sel, *unsel;
+ TransData temp;
+ unsel = tc->data;
+ sel = tc->data;
+ sel += tc->data_len - 1;
+ while (sel > unsel) {
+ while (unsel->flag & TD_SELECTED) {
+ unsel++;
+ if (unsel == sel) {
+ return;
+ }
+ }
+ while (!(sel->flag & TD_SELECTED)) {
+ sel--;
+ if (unsel == sel) {
+ return;
+ }
+ }
+ temp = *unsel;
+ *unsel = *sel;
+ *sel = temp;
+ sel--;
+ unsel++;
+ }
+}
+static void sort_trans_data_selected_first(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ sort_trans_data_selected_first_container(tc);
+ }
+}
+
+/**
+ * Distance calculated from not-selected vertex to nearest selected vertex.
+ */
+static void set_prop_dist(TransInfo *t, const bool with_dist)
+{
+ int a;
+
+ float _proj_vec[3];
+ const float *proj_vec = NULL;
+
+ /* support for face-islands */
+ const bool use_island = transdata_check_local_islands(t, t->around);
+
+ if (t->flag & T_PROP_PROJECTED) {
+ if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d = t->ar->regiondata;
+ normalize_v3_v3(_proj_vec, rv3d->viewinv[2]);
+ proj_vec = _proj_vec;
+ }
+ }
+
+ /* Count number of selected. */
+ int td_table_len = 0;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (a = 0; a < tc->data_len; a++, td++) {
+ if (td->flag & TD_SELECTED) {
+ td_table_len++;
+ }
+ else {
+ /* By definition transform-data has selected items in beginning. */
+ break;
+ }
+ }
+ }
+
+ /* Pointers to selected's #TransData.
+ * Used to find #TransData from the index returned by #BLI_kdtree_find_nearest. */
+ TransData **td_table = MEM_mallocN(sizeof(*td_table) * td_table_len, __func__);
+
+ /* Create and fill kd-tree of selected's positions - in global or proj_vec space. */
+ KDTree_3d *td_tree = BLI_kdtree_3d_new(td_table_len);
+
+ int td_table_index = 0;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (a = 0; a < tc->data_len; a++, td++) {
+ if (td->flag & TD_SELECTED) {
+ /* Initialize, it was mallocced. */
+ float vec[3];
+ td->rdist = 0.0f;
+
+ if (use_island) {
+ if (tc->use_local_mat) {
+ mul_v3_m4v3(vec, tc->mat, td->iloc);
+ }
+ else {
+ mul_v3_m3v3(vec, td->mtx, td->iloc);
+ }
+ }
+ else {
+ if (tc->use_local_mat) {
+ mul_v3_m4v3(vec, tc->mat, td->center);
+ }
+ else {
+ mul_v3_m3v3(vec, td->mtx, td->center);
+ }
+ }
+
+ if (proj_vec) {
+ float vec_p[3];
+ project_v3_v3v3(vec_p, vec, proj_vec);
+ sub_v3_v3(vec, vec_p);
+ }
+
+ BLI_kdtree_3d_insert(td_tree, td_table_index, vec);
+ td_table[td_table_index++] = td;
+ }
+ else {
+ /* By definition transform-data has selected items in beginning. */
+ break;
+ }
+ }
+ }
+ BLI_assert(td_table_index == td_table_len);
+
+ BLI_kdtree_3d_balance(td_tree);
+
+ /* For each non-selected vertex, find distance to the nearest selected vertex. */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (a = 0; a < tc->data_len; a++, td++) {
+ if ((td->flag & TD_SELECTED) == 0) {
+ float vec[3];
+
+ if (use_island) {
+ if (tc->use_local_mat) {
+ mul_v3_m4v3(vec, tc->mat, td->iloc);
+ }
+ else {
+ mul_v3_m3v3(vec, td->mtx, td->iloc);
+ }
+ }
+ else {
+ if (tc->use_local_mat) {
+ mul_v3_m4v3(vec, tc->mat, td->center);
+ }
+ else {
+ mul_v3_m3v3(vec, td->mtx, td->center);
+ }
+ }
+
+ if (proj_vec) {
+ float vec_p[3];
+ project_v3_v3v3(vec_p, vec, proj_vec);
+ sub_v3_v3(vec, vec_p);
+ }
+
+ KDTreeNearest_3d nearest;
+ const int td_index = BLI_kdtree_3d_find_nearest(td_tree, vec, &nearest);
+
+ td->rdist = -1.0f;
+ if (td_index != -1) {
+ td->rdist = nearest.dist;
+ if (use_island) {
+ copy_v3_v3(td->center, td_table[td_index]->center);
+ copy_m3_m3(td->axismtx, td_table[td_index]->axismtx);
+ }
+ }
+
+ if (with_dist) {
+ td->dist = td->rdist;
+ }
+ }
+ }
+ }
+
+ BLI_kdtree_3d_free(td_tree);
+ MEM_freeN(td_table);
+}
+
+/* ********************* pose mode ************* */
+
+static short apply_targetless_ik(Object *ob)
+{
+ bPoseChannel *pchan, *parchan, *chanlist[256];
+ bKinematicConstraint *data;
+ int segcount, apply = 0;
+
+ /* now we got a difficult situation... we have to find the
+ * target-less IK pchans, and apply transformation to the all
+ * pchans that were in the chain */
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ data = has_targetless_ik(pchan);
+ if (data && (data->flag & CONSTRAINT_IK_AUTO)) {
+
+ /* fill the array with the bones of the chain (armature.c does same, keep it synced) */
+ segcount = 0;
+
+ /* exclude tip from chain? */
+ if (!(data->flag & CONSTRAINT_IK_TIP)) {
+ parchan = pchan->parent;
+ }
+ else {
+ parchan = pchan;
+ }
+
+ /* Find the chain's root & count the segments needed */
+ for (; parchan; parchan = parchan->parent) {
+ chanlist[segcount] = parchan;
+ segcount++;
+
+ if (segcount == data->rootbone || segcount > 255) {
+ break; // 255 is weak
+ }
+ }
+ for (; segcount; segcount--) {
+ Bone *bone;
+ float rmat[4][4] /*, tmat[4][4], imat[4][4]*/;
+
+ /* pose_mat(b) = pose_mat(b-1) * offs_bone * channel * constraint * IK */
+ /* we put in channel the entire result of rmat = (channel * constraint * IK) */
+ /* pose_mat(b) = pose_mat(b-1) * offs_bone * rmat */
+ /* rmat = pose_mat(b) * inv(pose_mat(b-1) * offs_bone ) */
+
+ parchan = chanlist[segcount - 1];
+ bone = parchan->bone;
+ bone->flag |= BONE_TRANSFORM; /* ensures it gets an auto key inserted */
+
+ BKE_armature_mat_pose_to_bone(parchan, parchan->pose_mat, rmat);
+
+ /* apply and decompose, doesn't work for constraints or non-uniform scale well */
+ {
+ float rmat3[3][3], qrmat[3][3], imat3[3][3], smat[3][3];
+ copy_m3_m4(rmat3, rmat);
+
+ /* rotation */
+ /* [#22409] is partially caused by this, as slight numeric error introduced during
+ * the solving process leads to locked-axis values changing. However, we cannot modify
+ * the values here, or else there are huge discrepancies between IK-solver (interactive)
+ * and applied poses. */
+ BKE_pchan_mat3_to_rot(parchan, rmat3, false);
+
+ /* for size, remove rotation */
+ /* causes problems with some constraints (so apply only if needed) */
+ if (data->flag & CONSTRAINT_IK_STRETCH) {
+ BKE_pchan_rot_to_mat3(parchan, qrmat);
+ invert_m3_m3(imat3, qrmat);
+ mul_m3_m3m3(smat, rmat3, imat3);
+ mat3_to_size(parchan->size, smat);
+ }
+
+ /* causes problems with some constraints (e.g. childof), so disable this */
+ /* as it is IK shouldn't affect location directly */
+ /* copy_v3_v3(parchan->loc, rmat[3]); */
+ }
+ }
+
+ apply = 1;
+ data->flag &= ~CONSTRAINT_IK_AUTO;
+ }
+ }
+
+ return apply;
+}
+
+static void bone_children_clear_transflag(int mode, short around, ListBase *lb)
+{
+ Bone *bone = lb->first;
+
+ for (; bone; bone = bone->next) {
+ if ((bone->flag & BONE_HINGE) && (bone->flag & BONE_CONNECTED)) {
+ bone->flag |= BONE_HINGE_CHILD_TRANSFORM;
+ }
+ else if ((bone->flag & BONE_TRANSFORM) && (mode == TFM_ROTATION || mode == TFM_TRACKBALL) &&
+ (around == V3D_AROUND_LOCAL_ORIGINS)) {
+ bone->flag |= BONE_TRANSFORM_CHILD;
+ }
+ else {
+ bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
+ }
+
+ bone_children_clear_transflag(mode, around, &bone->childbase);
+ }
+}
+
+/* sets transform flags in the bones
+ * returns total number of bones with BONE_TRANSFORM */
+int count_set_pose_transflags(Object *ob,
+ const int mode,
+ const short around,
+ bool has_translate_rotate[2])
+{
+ bArmature *arm = ob->data;
+ bPoseChannel *pchan;
+ Bone *bone;
+ int total = 0;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ bone = pchan->bone;
+ if (PBONE_VISIBLE(arm, bone)) {
+ if ((bone->flag & BONE_SELECTED)) {
+ bone->flag |= BONE_TRANSFORM;
+ }
+ else {
+ bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
+ }
+
+ bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM;
+ bone->flag &= ~BONE_TRANSFORM_CHILD;
+ }
+ else {
+ bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
+ }
+ }
+
+ /* make sure no bone can be transformed when a parent is transformed */
+ /* since pchans are depsgraph sorted, the parents are in beginning of list */
+ if (!ELEM(mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ bone = pchan->bone;
+ if (bone->flag & BONE_TRANSFORM) {
+ bone_children_clear_transflag(mode, around, &bone->childbase);
+ }
+ }
+ }
+ /* now count, and check if we have autoIK or have to switch from translate to rotate */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ bone = pchan->bone;
+ if (bone->flag & BONE_TRANSFORM) {
+ total++;
+
+ if (has_translate_rotate != NULL) {
+ if (has_targetless_ik(pchan) == NULL) {
+ if (pchan->parent && (pchan->bone->flag & BONE_CONNECTED)) {
+ if (pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM) {
+ has_translate_rotate[0] = true;
+ }
+ }
+ else {
+ if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC) {
+ has_translate_rotate[0] = true;
+ }
+ }
+ if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT) {
+ has_translate_rotate[1] = true;
+ }
+ }
+ else {
+ has_translate_rotate[0] = true;
+ }
+ }
+ }
+ }
+
+ return total;
+}
+
+/* -------- Auto-IK ---------- */
+
+/* adjust pose-channel's auto-ik chainlen */
+static bool pchan_autoik_adjust(bPoseChannel *pchan, short chainlen)
+{
+ bConstraint *con;
+ bool changed = false;
+
+ /* don't bother to search if no valid constraints */
+ if ((pchan->constflag & (PCHAN_HAS_IK | PCHAN_HAS_TARGET)) == 0) {
+ return changed;
+ }
+
+ /* check if pchan has ik-constraint */
+ for (con = pchan->constraints.first; con; con = con->next) {
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce != 0.0f)) {
+ bKinematicConstraint *data = con->data;
+
+ /* only accept if a temporary one (for auto-ik) */
+ if (data->flag & CONSTRAINT_IK_TEMP) {
+ /* chainlen is new chainlen, but is limited by maximum chainlen */
+ const int old_rootbone = data->rootbone;
+ if ((chainlen == 0) || (chainlen > data->max_rootbone)) {
+ data->rootbone = data->max_rootbone;
+ }
+ else {
+ data->rootbone = chainlen;
+ }
+ changed |= (data->rootbone != old_rootbone);
+ }
+ }
+ }
+
+ return changed;
+}
+
+/* change the chain-length of auto-ik */
+void transform_autoik_update(TransInfo *t, short mode)
+{
+ Main *bmain = CTX_data_main(t->context);
+
+ short *chainlen = &t->settings->autoik_chainlen;
+ bPoseChannel *pchan;
+
+ /* mode determines what change to apply to chainlen */
+ if (mode == 1) {
+ /* mode=1 is from WHEELMOUSEDOWN... increases len */
+ (*chainlen)++;
+ }
+ else if (mode == -1) {
+ /* mode==-1 is from WHEELMOUSEUP... decreases len */
+ if (*chainlen > 0) {
+ (*chainlen)--;
+ }
+ else {
+ /* IK length did not change, skip updates. */
+ return;
+ }
+ }
+
+ /* apply to all pose-channels */
+ bool changed = false;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ /* sanity checks (don't assume t->poseobj is set, or that it is an armature) */
+ if (ELEM(NULL, tc->poseobj, tc->poseobj->pose)) {
+ continue;
+ }
+
+ for (pchan = tc->poseobj->pose->chanbase.first; pchan; pchan = pchan->next) {
+ changed |= pchan_autoik_adjust(pchan, *chainlen);
+ }
+ }
+
+ if (changed) {
+ /* TODO(sergey): Consider doing partial update only. */
+ DEG_relations_tag_update(bmain);
+ }
+}
+
+/* frees temporal IKs */
+static void pose_grab_with_ik_clear(Main *bmain, Object *ob)
+{
+ bKinematicConstraint *data;
+ bPoseChannel *pchan;
+ bConstraint *con, *next;
+ bool relations_changed = false;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ /* clear all temporary lock flags */
+ pchan->ikflag &= ~(BONE_IK_NO_XDOF_TEMP | BONE_IK_NO_YDOF_TEMP | BONE_IK_NO_ZDOF_TEMP);
+
+ pchan->constflag &= ~(PCHAN_HAS_IK | PCHAN_HAS_TARGET);
+
+ /* remove all temporary IK-constraints added */
+ for (con = pchan->constraints.first; con; con = next) {
+ next = con->next;
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
+ data = con->data;
+ if (data->flag & CONSTRAINT_IK_TEMP) {
+ relations_changed = true;
+
+ /* iTaSC needs clear for removed constraints */
+ BIK_clear_data(ob->pose);
+
+ BLI_remlink(&pchan->constraints, con);
+ MEM_freeN(con->data);
+ MEM_freeN(con);
+ continue;
+ }
+ pchan->constflag |= PCHAN_HAS_IK;
+ if (data->tar == NULL || (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0)) {
+ pchan->constflag |= PCHAN_HAS_TARGET;
+ }
+ }
+ }
+ }
+
+ if (relations_changed) {
+ /* TODO(sergey): Consider doing partial update only. */
+ DEG_relations_tag_update(bmain);
+ }
+}
+
+/* ********************* curve/surface ********* */
+
+void calc_distanceCurveVerts(TransData *head, TransData *tail)
+{
+ TransData *td, *td_near = NULL;
+ for (td = head; td <= tail; td++) {
+ if (td->flag & TD_SELECTED) {
+ td_near = td;
+ td->dist = 0.0f;
+ }
+ else if (td_near) {
+ float dist;
+ float vec[3];
+
+ sub_v3_v3v3(vec, td_near->center, td->center);
+ mul_m3_v3(head->mtx, vec);
+ dist = len_v3(vec);
+
+ if (dist < (td - 1)->dist) {
+ td->dist = (td - 1)->dist;
+ }
+ else {
+ td->dist = dist;
+ }
+ }
+ else {
+ td->dist = FLT_MAX;
+ td->flag |= TD_NOTCONNECTED;
+ }
+ }
+ td_near = NULL;
+ for (td = tail; td >= head; td--) {
+ if (td->flag & TD_SELECTED) {
+ td_near = td;
+ td->dist = 0.0f;
+ }
+ else if (td_near) {
+ float dist;
+ float vec[3];
+
+ sub_v3_v3v3(vec, td_near->center, td->center);
+ mul_m3_v3(head->mtx, vec);
+ dist = len_v3(vec);
+
+ if (td->flag & TD_NOTCONNECTED || dist < td->dist || (td + 1)->dist < td->dist) {
+ td->flag &= ~TD_NOTCONNECTED;
+ if (dist < (td + 1)->dist) {
+ td->dist = (td + 1)->dist;
+ }
+ else {
+ td->dist = dist;
+ }
+ }
+ }
+ }
+}
+
+/* Utility function for getting the handle data from bezier's */
+TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt)
+{
+ TransDataCurveHandleFlags *hdata;
+ td->flag |= TD_BEZTRIPLE;
+ hdata = td->hdata = MEM_mallocN(sizeof(TransDataCurveHandleFlags), "CuHandle Data");
+ hdata->ih1 = bezt->h1;
+ hdata->h1 = &bezt->h1;
+ hdata->ih2 = bezt->h2; /* in case the second is not selected */
+ hdata->h2 = &bezt->h2;
+ return hdata;
+}
+
+/* ********************* UV ****************** */
+
+bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
+{
+ bool clipx = true, clipy = true;
+ float min[2], max[2];
+
+ min[0] = min[1] = 0.0f;
+ max[0] = t->aspect[0];
+ max[1] = t->aspect[1];
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ TransData *td;
+ int a;
+
+ for (a = 0, td = tc->data; a < tc->data_len; a++, td++) {
+ minmax_v2v2_v2(min, max, td->loc);
+ }
+ }
+
+ if (resize) {
+ if (min[0] < 0.0f && t->center_global[0] > 0.0f && t->center_global[0] < t->aspect[0] * 0.5f) {
+ vec[0] *= t->center_global[0] / (t->center_global[0] - min[0]);
+ }
+ else if (max[0] > t->aspect[0] && t->center_global[0] < t->aspect[0]) {
+ vec[0] *= (t->center_global[0] - t->aspect[0]) / (t->center_global[0] - max[0]);
+ }
+ else {
+ clipx = 0;
+ }
+
+ if (min[1] < 0.0f && t->center_global[1] > 0.0f && t->center_global[1] < t->aspect[1] * 0.5f) {
+ vec[1] *= t->center_global[1] / (t->center_global[1] - min[1]);
+ }
+ else if (max[1] > t->aspect[1] && t->center_global[1] < t->aspect[1]) {
+ vec[1] *= (t->center_global[1] - t->aspect[1]) / (t->center_global[1] - max[1]);
+ }
+ else {
+ clipy = 0;
+ }
+ }
+ else {
+ if (min[0] < 0.0f) {
+ vec[0] -= min[0];
+ }
+ else if (max[0] > t->aspect[0]) {
+ vec[0] -= max[0] - t->aspect[0];
+ }
+ else {
+ clipx = 0;
+ }
+
+ if (min[1] < 0.0f) {
+ vec[1] -= min[1];
+ }
+ else if (max[1] > t->aspect[1]) {
+ vec[1] -= max[1] - t->aspect[1];
+ }
+ else {
+ clipy = 0;
+ }
+ }
+
+ return (clipx || clipy);
+}
+
+void clipUVData(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (int a = 0; a < tc->data_len; a++, td++) {
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if ((td->flag & TD_SKIP) || (!td->loc)) {
+ continue;
+ }
+
+ td->loc[0] = min_ff(max_ff(0.0f, td->loc[0]), t->aspect[0]);
+ td->loc[1] = min_ff(max_ff(0.0f, td->loc[1]), t->aspect[1]);
+ }
+ }
+}
+
+/* ********************* ANIMATION EDITORS (GENERAL) ************************* */
+
+/* This function tests if a point is on the "mouse" side of the cursor/frame-marking */
+bool FrameOnMouseSide(char side, float frame, float cframe)
+{
+ /* both sides, so it doesn't matter */
+ if (side == 'B') {
+ return true;
+ }
+
+ /* only on the named side */
+ if (side == 'R') {
+ return (frame >= cframe);
+ }
+ else {
+ return (frame <= cframe);
+ }
+}
+
+/* ********************* ACTION EDITOR ****************** */
+
+static int gpf_cmp_frame(void *thunk, const void *a, const void *b)
+{
+ const bGPDframe *frame_a = a;
+ const bGPDframe *frame_b = b;
+
+ if (frame_a->framenum < frame_b->framenum) {
+ return -1;
+ }
+ if (frame_a->framenum > frame_b->framenum) {
+ return 1;
+ }
+ *((bool *)thunk) = true;
+ /* selected last */
+ if ((frame_a->flag & GP_FRAME_SELECT) && ((frame_b->flag & GP_FRAME_SELECT) == 0)) {
+ return 1;
+ }
+ return 0;
+}
+
+static int masklay_shape_cmp_frame(void *thunk, const void *a, const void *b)
+{
+ const MaskLayerShape *frame_a = a;
+ const MaskLayerShape *frame_b = b;
+
+ if (frame_a->frame < frame_b->frame) {
+ return -1;
+ }
+ if (frame_a->frame > frame_b->frame) {
+ return 1;
+ }
+ *((bool *)thunk) = true;
+ /* selected last */
+ if ((frame_a->flag & MASK_SHAPE_SELECT) && ((frame_b->flag & MASK_SHAPE_SELECT) == 0)) {
+ return 1;
+ }
+ return 0;
+}
+
+/* Called by special_aftertrans_update to make sure selected gp-frames replace
+ * any other gp-frames which may reside on that frame (that are not selected).
+ * It also makes sure gp-frames are still stored in chronological order after
+ * transform.
+ */
+static void posttrans_gpd_clean(bGPdata *gpd)
+{
+ bGPDlayer *gpl;
+
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ bGPDframe *gpf, *gpfn;
+ bool is_double = false;
+
+ BLI_listbase_sort_r(&gpl->frames, gpf_cmp_frame, &is_double);
+
+ if (is_double) {
+ for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
+ gpfn = gpf->next;
+ if (gpfn && gpf->framenum == gpfn->framenum) {
+ BKE_gpencil_layer_delframe(gpl, gpf);
+ }
+ }
+ }
+
+#ifdef DEBUG
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ BLI_assert(!gpf->next || gpf->framenum < gpf->next->framenum);
+ }
+#endif
+ }
+ /* set cache flag to dirty */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+}
+
+static void posttrans_mask_clean(Mask *mask)
+{
+ MaskLayer *masklay;
+
+ for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ MaskLayerShape *masklay_shape, *masklay_shape_next;
+ bool is_double = false;
+
+ BLI_listbase_sort_r(&masklay->splines_shapes, masklay_shape_cmp_frame, &is_double);
+
+ if (is_double) {
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
+ masklay_shape = masklay_shape_next) {
+ masklay_shape_next = masklay_shape->next;
+ if (masklay_shape_next && masklay_shape->frame == masklay_shape_next->frame) {
+ BKE_mask_layer_shape_unlink(masklay, masklay_shape);
+ }
+ }
+ }
+
+#ifdef DEBUG
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
+ masklay_shape = masklay_shape->next) {
+ BLI_assert(!masklay_shape->next || masklay_shape->frame < masklay_shape->next->frame);
+ }
+#endif
+ }
+}
+
+/* Time + Average value */
+typedef struct tRetainedKeyframe {
+ struct tRetainedKeyframe *next, *prev;
+ float frame; /* frame to cluster around */
+ float val; /* average value */
+
+ size_t tot_count; /* number of keyframes that have been averaged */
+ size_t del_count; /* number of keyframes of this sort that have been deleted so far */
+} tRetainedKeyframe;
+
+/* Called during special_aftertrans_update to make sure selected keyframes replace
+ * any other keyframes which may reside on that frame (that is not selected).
+ */
+static void posttrans_fcurve_clean(FCurve *fcu, const bool use_handle)
+{
+ /* NOTE: We assume that all keys are sorted */
+ ListBase retained_keys = {NULL, NULL};
+ const bool can_average_points = ((fcu->flag & (FCURVE_INT_VALUES | FCURVE_DISCRETE_VALUES)) ==
+ 0);
+
+ /* sanity checks */
+ if ((fcu->totvert == 0) || (fcu->bezt == NULL)) {
+ return;
+ }
+
+ /* 1) Identify selected keyframes, and average the values on those
+ * in case there are collisions due to multiple keys getting scaled
+ * to all end up on the same frame
+ */
+ for (int i = 0; i < fcu->totvert; i++) {
+ BezTriple *bezt = &fcu->bezt[i];
+
+ if (BEZT_ISSEL_ANY(bezt)) {
+ bool found = false;
+
+ /* If there's another selected frame here, merge it */
+ for (tRetainedKeyframe *rk = retained_keys.last; rk; rk = rk->prev) {
+ if (IS_EQT(rk->frame, bezt->vec[1][0], BEZT_BINARYSEARCH_THRESH)) {
+ rk->val += bezt->vec[1][1];
+ rk->tot_count++;
+
+ found = true;
+ break;
+ }
+ else if (rk->frame < bezt->vec[1][0]) {
+ /* Terminate early if have passed the supposed insertion point? */
+ break;
+ }
+ }
+
+ /* If nothing found yet, create a new one */
+ if (found == false) {
+ tRetainedKeyframe *rk = MEM_callocN(sizeof(tRetainedKeyframe), "tRetainedKeyframe");
+
+ rk->frame = bezt->vec[1][0];
+ rk->val = bezt->vec[1][1];
+ rk->tot_count = 1;
+
+ BLI_addtail(&retained_keys, rk);
+ }
+ }
+ }
+
+ if (BLI_listbase_is_empty(&retained_keys)) {
+ /* This may happen if none of the points were selected... */
+ if (G.debug & G_DEBUG) {
+ printf("%s: nothing to do for FCurve %p (rna_path = '%s')\n", __func__, fcu, fcu->rna_path);
+ }
+ return;
+ }
+ else {
+ /* Compute the average values for each retained keyframe */
+ for (tRetainedKeyframe *rk = retained_keys.first; rk; rk = rk->next) {
+ rk->val = rk->val / (float)rk->tot_count;
+ }
+ }
+
+ /* 2) Delete all keyframes duplicating the "retained keys" found above
+ * - Most of these will be unselected keyframes
+ * - Some will be selected keyframes though. For those, we only keep the last one
+ * (or else everything is gone), and replace its value with the averaged value.
+ */
+ for (int i = fcu->totvert - 1; i >= 0; i--) {
+ BezTriple *bezt = &fcu->bezt[i];
+
+ /* Is this keyframe a candidate for deletion? */
+ /* TODO: Replace loop with an O(1) lookup instead */
+ for (tRetainedKeyframe *rk = retained_keys.last; rk; rk = rk->prev) {
+ if (IS_EQT(bezt->vec[1][0], rk->frame, BEZT_BINARYSEARCH_THRESH)) {
+ /* Selected keys are treated with greater care than unselected ones... */
+ if (BEZT_ISSEL_ANY(bezt)) {
+ /* - If this is the last selected key left (based on rk->del_count) ==> UPDATE IT
+ * (or else we wouldn't have any keyframe left here)
+ * - Otherwise, there are still other selected keyframes on this frame
+ * to be merged down still ==> DELETE IT
+ */
+ if (rk->del_count == rk->tot_count - 1) {
+ /* Update keyframe... */
+ if (can_average_points) {
+ /* TODO: update handles too? */
+ bezt->vec[1][1] = rk->val;
+ }
+ }
+ else {
+ /* Delete Keyframe */
+ delete_fcurve_key(fcu, i, 0);
+ }
+
+ /* Update count of how many we've deleted
+ * - It should only matter that we're doing this for all but the last one
+ */
+ rk->del_count++;
+ }
+ else {
+ /* Always delete - Unselected keys don't matter */
+ delete_fcurve_key(fcu, i, 0);
+ }
+
+ /* Stop the RK search... we've found our match now */
+ break;
+ }
+ }
+ }
+
+ /* 3) Recalculate handles */
+ testhandles_fcurve(fcu, use_handle);
+
+ /* cleanup */
+ BLI_freelistN(&retained_keys);
+}
+
+/* Called by special_aftertrans_update to make sure selected keyframes replace
+ * any other keyframes which may reside on that frame (that is not selected).
+ * remake_action_ipos should have already been called
+ */
+static void posttrans_action_clean(bAnimContext *ac, bAction *act)
+{
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
+ ANIM_animdata_filter(ac, &anim_data, filter, act, ANIMCONT_ACTION);
+
+ /* loop through relevant data, removing keyframes as appropriate
+ * - all keyframes are converted in/out of global time
+ */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+
+ if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
+ posttrans_fcurve_clean(ale->key_data, false); /* only use handles in graph editor */
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
+ }
+ else {
+ posttrans_fcurve_clean(ale->key_data, false); /* only use handles in graph editor */
+ }
+ }
+
+ /* free temp data */
+ ANIM_animdata_freelist(&anim_data);
+}
+
+/* ********************* GRAPH EDITOR ************************* */
+
+/* struct for use in re-sorting BezTriples during Graph Editor transform */
+typedef struct BeztMap {
+ BezTriple *bezt;
+ unsigned int oldIndex; /* index of bezt in fcu->bezt array before sorting */
+ unsigned int newIndex; /* index of bezt in fcu->bezt array after sorting */
+ short swapHs; /* swap order of handles (-1=clear; 0=not checked, 1=swap) */
+ char pipo, cipo; /* interpolation of current and next segments */
+} BeztMap;
+
+/* This function converts an FCurve's BezTriple array to a BeztMap array
+ * NOTE: this allocates memory that will need to get freed later
+ */
+static BeztMap *bezt_to_beztmaps(BezTriple *bezts, int totvert, const short UNUSED(use_handle))
+{
+ BezTriple *bezt = bezts;
+ BezTriple *prevbezt = NULL;
+ BeztMap *bezm, *bezms;
+ int i;
+
+ /* allocate memory for this array */
+ if (totvert == 0 || bezts == NULL) {
+ return NULL;
+ }
+ bezm = bezms = MEM_callocN(sizeof(BeztMap) * totvert, "BeztMaps");
+
+ /* assign beztriples to beztmaps */
+ for (i = 0; i < totvert; i++, bezm++, prevbezt = bezt, bezt++) {
+ bezm->bezt = bezt;
+
+ bezm->oldIndex = i;
+ bezm->newIndex = i;
+
+ bezm->pipo = (prevbezt) ? prevbezt->ipo : bezt->ipo;
+ bezm->cipo = bezt->ipo;
+ }
+
+ return bezms;
+}
+
+/* This function copies the code of sort_time_ipocurve, but acts on BeztMap structs instead */
+static void sort_time_beztmaps(BeztMap *bezms, int totvert, const short UNUSED(use_handle))
+{
+ BeztMap *bezm;
+ int i, ok = 1;
+
+ /* keep repeating the process until nothing is out of place anymore */
+ while (ok) {
+ ok = 0;
+
+ bezm = bezms;
+ i = totvert;
+ while (i--) {
+ /* is current bezm out of order (i.e. occurs later than next)? */
+ if (i > 0) {
+ if (bezm->bezt->vec[1][0] > (bezm + 1)->bezt->vec[1][0]) {
+ bezm->newIndex++;
+ (bezm + 1)->newIndex--;
+
+ SWAP(BeztMap, *bezm, *(bezm + 1));
+
+ ok = 1;
+ }
+ }
+
+ /* do we need to check if the handles need to be swapped?
+ * optimization: this only needs to be performed in the first loop
+ */
+ if (bezm->swapHs == 0) {
+ if ((bezm->bezt->vec[0][0] > bezm->bezt->vec[1][0]) &&
+ (bezm->bezt->vec[2][0] < bezm->bezt->vec[1][0])) {
+ /* handles need to be swapped */
+ bezm->swapHs = 1;
+ }
+ else {
+ /* handles need to be cleared */
+ bezm->swapHs = -1;
+ }
+ }
+
+ bezm++;
+ }
+ }
+}
+
+/* This function firstly adjusts the pointers that the transdata has to each BezTriple */
+static void beztmap_to_data(
+ TransInfo *t, FCurve *fcu, BeztMap *bezms, int totvert, const short UNUSED(use_handle))
+{
+ BezTriple *bezts = fcu->bezt;
+ BeztMap *bezm;
+ TransData2D *td2d;
+ TransData *td;
+ int i, j;
+ char *adjusted;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* dynamically allocate an array of chars to mark whether an TransData's
+ * pointers have been fixed already, so that we don't override ones that are
+ * already done
+ */
+ adjusted = MEM_callocN(tc->data_len, "beztmap_adjusted_map");
+
+ /* for each beztmap item, find if it is used anywhere */
+ bezm = bezms;
+ for (i = 0; i < totvert; i++, bezm++) {
+ /* loop through transdata, testing if we have a hit
+ * for the handles (vec[0]/vec[2]), we must also check if they need to be swapped...
+ */
+ td2d = tc->data_2d;
+ td = tc->data;
+ for (j = 0; j < tc->data_len; j++, td2d++, td++) {
+ /* skip item if already marked */
+ if (adjusted[j] != 0) {
+ continue;
+ }
+
+ /* update all transdata pointers, no need to check for selections etc,
+ * since only points that are really needed were created as transdata
+ */
+ if (td2d->loc2d == bezm->bezt->vec[0]) {
+ if (bezm->swapHs == 1) {
+ td2d->loc2d = (bezts + bezm->newIndex)->vec[2];
+ }
+ else {
+ td2d->loc2d = (bezts + bezm->newIndex)->vec[0];
+ }
+ adjusted[j] = 1;
+ }
+ else if (td2d->loc2d == bezm->bezt->vec[2]) {
+ if (bezm->swapHs == 1) {
+ td2d->loc2d = (bezts + bezm->newIndex)->vec[0];
+ }
+ else {
+ td2d->loc2d = (bezts + bezm->newIndex)->vec[2];
+ }
+ adjusted[j] = 1;
+ }
+ else if (td2d->loc2d == bezm->bezt->vec[1]) {
+ td2d->loc2d = (bezts + bezm->newIndex)->vec[1];
+
+ /* if only control point is selected, the handle pointers need to be updated as well */
+ if (td2d->h1) {
+ td2d->h1 = (bezts + bezm->newIndex)->vec[0];
+ }
+ if (td2d->h2) {
+ td2d->h2 = (bezts + bezm->newIndex)->vec[2];
+ }
+
+ adjusted[j] = 1;
+ }
+
+ /* the handle type pointer has to be updated too */
+ if (adjusted[j] && td->flag & TD_BEZTRIPLE && td->hdata) {
+ if (bezm->swapHs == 1) {
+ td->hdata->h1 = &(bezts + bezm->newIndex)->h2;
+ td->hdata->h2 = &(bezts + bezm->newIndex)->h1;
+ }
+ else {
+ td->hdata->h1 = &(bezts + bezm->newIndex)->h1;
+ td->hdata->h2 = &(bezts + bezm->newIndex)->h2;
+ }
+ }
+ }
+ }
+
+ /* free temp memory used for 'adjusted' array */
+ MEM_freeN(adjusted);
+}
+
+/* This function is called by recalcData during the Transform loop to recalculate
+ * the handles of curves and sort the keyframes so that the curves draw correctly.
+ * It is only called if some keyframes have moved out of order.
+ *
+ * anim_data is the list of channels (F-Curves) retrieved already containing the
+ * channels to work on. It should not be freed here as it may still need to be used.
+ */
+void remake_graph_transdata(TransInfo *t, ListBase *anim_data)
+{
+ SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ bAnimListElem *ale;
+ const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
+
+ /* sort and reassign verts */
+ for (ale = anim_data->first; ale; ale = ale->next) {
+ FCurve *fcu = (FCurve *)ale->key_data;
+
+ if (fcu->bezt) {
+ BeztMap *bezm;
+
+ /* adjust transform-data pointers */
+ /* note, none of these functions use 'use_handle', it could be removed */
+ bezm = bezt_to_beztmaps(fcu->bezt, fcu->totvert, use_handle);
+ sort_time_beztmaps(bezm, fcu->totvert, use_handle);
+ beztmap_to_data(t, fcu, bezm, fcu->totvert, use_handle);
+
+ /* free mapping stuff */
+ MEM_freeN(bezm);
+
+ /* re-sort actual beztriples (perhaps this could be done using the beztmaps to save time?) */
+ sort_time_fcurve(fcu);
+
+ /* make sure handles are all set correctly */
+ testhandles_fcurve(fcu, use_handle);
+ }
+ }
+}
+
+/* *********************** Transform data ******************* */
+
+/* Little helper function for ObjectToTransData used to give certain
+ * constraints (ChildOf, FollowPath, and others that may be added)
+ * inverse corrections for transform, so that they aren't in CrazySpace.
+ * These particular constraints benefit from this, but others don't, hence
+ * this semi-hack ;-) - Aligorith
+ */
+bool constraints_list_needinv(TransInfo *t, ListBase *list)
+{
+ bConstraint *con;
+
+ /* loop through constraints, checking if there's one of the mentioned
+ * constraints needing special crazyspace corrections
+ */
+ if (list) {
+ for (con = list->first; con; con = con->next) {
+ /* only consider constraint if it is enabled, and has influence on result */
+ if ((con->flag & CONSTRAINT_DISABLE) == 0 && (con->enforce != 0.0f)) {
+ /* (affirmative) returns for specific constraints here... */
+ /* constraints that require this regardless */
+ if (ELEM(con->type,
+ CONSTRAINT_TYPE_FOLLOWPATH,
+ CONSTRAINT_TYPE_CLAMPTO,
+ CONSTRAINT_TYPE_ARMATURE,
+ CONSTRAINT_TYPE_OBJECTSOLVER,
+ CONSTRAINT_TYPE_FOLLOWTRACK)) {
+ return true;
+ }
+
+ /* constraints that require this only under special conditions */
+ if (con->type == CONSTRAINT_TYPE_CHILDOF) {
+ /* ChildOf constraint only works when using all location components, see T42256. */
+ bChildOfConstraint *data = (bChildOfConstraint *)con->data;
+
+ if ((data->flag & CHILDOF_LOCX) && (data->flag & CHILDOF_LOCY) &&
+ (data->flag & CHILDOF_LOCZ)) {
+ return true;
+ }
+ }
+ else if (con->type == CONSTRAINT_TYPE_ROTLIKE) {
+ /* CopyRot constraint only does this when rotating, and offset is on */
+ bRotateLikeConstraint *data = (bRotateLikeConstraint *)con->data;
+
+ if (ELEM(data->mix_mode, ROTLIKE_MIX_OFFSET, ROTLIKE_MIX_BEFORE) &&
+ ELEM(t->mode, TFM_ROTATION)) {
+ return true;
+ }
+ }
+ else if (con->type == CONSTRAINT_TYPE_TRANSLIKE) {
+ /* Copy Transforms constraint only does this in the Before mode. */
+ bTransLikeConstraint *data = (bTransLikeConstraint *)con->data;
+
+ if (ELEM(data->mix_mode, TRANSLIKE_MIX_BEFORE) &&
+ ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION)) {
+ return true;
+ }
+ }
+ else if (con->type == CONSTRAINT_TYPE_TRANSFORM) {
+ /* Transform constraint needs it for rotation at least (r.57309),
+ * but doing so when translating may also mess things up [#36203]
+ */
+ bTransformConstraint *data = (bTransformConstraint *)con->data;
+
+ if (data->to == TRANS_ROTATION) {
+ if (t->mode == TFM_ROTATION && data->mix_mode_rot == TRANS_MIXROT_BEFORE) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* no appropriate candidates found */
+ return false;
+}
+
+/**
+ * Auto-keyframing feature - for objects
+ *
+ * \param tmode: A transform mode.
+ *
+ * \note Context may not always be available,
+ * so must check before using it as it's a luxury for a few cases.
+ */
+void autokeyframe_object(bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, int tmode)
+{
+ Main *bmain = CTX_data_main(C);
+ ID *id = &ob->id;
+ FCurve *fcu;
+
+ // TODO: this should probably be done per channel instead...
+ if (autokeyframe_cfra_can_key(scene, id)) {
+ ReportList *reports = CTX_wm_reports(C);
+ ToolSettings *ts = scene->toolsettings;
+ KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
+ ListBase dsources = {NULL, NULL};
+ float cfra = (float)CFRA; // xxx this will do for now
+ short flag = 0;
+
+ /* get flags used for inserting keyframes */
+ flag = ANIM_get_keyframing_flags(scene, 1);
+
+ /* add datasource override for the object */
+ ANIM_relative_keyingset_add_source(&dsources, id, NULL, NULL);
+
+ if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
+ /* Only insert into active keyingset
+ * NOTE: we assume here that the active Keying Set
+ * does not need to have its iterator overridden.
+ */
+ ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) {
+ AnimData *adt = ob->adt;
+
+ /* only key on available channels */
+ if (adt && adt->action) {
+ ListBase nla_cache = {NULL, NULL};
+ for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) {
+ fcu->flag &= ~FCURVE_SELECTED;
+ insert_keyframe(bmain,
+ reports,
+ id,
+ adt->action,
+ (fcu->grp ? fcu->grp->name : NULL),
+ fcu->rna_path,
+ fcu->array_index,
+ cfra,
+ ts->keyframe_type,
+ &nla_cache,
+ flag);
+ }
+
+ BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
+ }
+ }
+ else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
+ bool do_loc = false, do_rot = false, do_scale = false;
+
+ /* filter the conditions when this happens (assume that curarea->spacetype==SPACE_VIE3D) */
+ if (tmode == TFM_TRANSLATION) {
+ do_loc = true;
+ }
+ else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
+ if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
+ if (ob != OBACT(view_layer)) {
+ do_loc = true;
+ }
+ }
+ else if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) {
+ do_loc = true;
+ }
+
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
+ do_rot = true;
+ }
+ }
+ else if (tmode == TFM_RESIZE) {
+ if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
+ if (ob != OBACT(view_layer)) {
+ do_loc = true;
+ }
+ }
+ else if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) {
+ do_loc = true;
+ }
+
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
+ do_scale = true;
+ }
+ }
+
+ /* insert keyframes for the affected sets of channels using the builtin KeyingSets found */
+ if (do_loc) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ if (do_rot) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ if (do_scale) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_SCALING_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ }
+ /* insert keyframe in all (transform) channels */
+ else {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+
+ /* free temp info */
+ BLI_freelistN(&dsources);
+ }
+}
+
+/* Return if we need to update motion paths, only if they already exist,
+ * and we will insert a keyframe at the end of transform. */
+bool motionpath_need_update_object(Scene *scene, Object *ob)
+{
+ /* XXX: there's potential here for problems with unkeyed rotations/scale,
+ * but for now (until proper data-locality for baking operations),
+ * this should be a better fix for T24451 and T37755
+ */
+
+ if (autokeyframe_cfra_can_key(scene, &ob->id)) {
+ return (ob->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
+ }
+
+ return false;
+}
+
+/**
+ * Auto-keyframing feature - for poses/pose-channels
+ *
+ * \param tmode: A transform mode.
+ *
+ * targetless_ik: has targetless ik been done on any channels?
+ *
+ * \note Context may not always be available,
+ * so must check before using it as it's a luxury for a few cases.
+ */
+void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, int tmode, short targetless_ik)
+{
+ Main *bmain = CTX_data_main(C);
+ ID *id = &ob->id;
+ AnimData *adt = ob->adt;
+ bAction *act = (adt) ? adt->action : NULL;
+ bPose *pose = ob->pose;
+ bPoseChannel *pchan;
+ FCurve *fcu;
+
+ // TODO: this should probably be done per channel instead...
+ if (autokeyframe_cfra_can_key(scene, id)) {
+ ReportList *reports = CTX_wm_reports(C);
+ ToolSettings *ts = scene->toolsettings;
+ KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
+ ListBase nla_cache = {NULL, NULL};
+ float cfra = (float)CFRA;
+ short flag = 0;
+
+ /* flag is initialized from UserPref keyframing settings
+ * - special exception for targetless IK - INSERTKEY_MATRIX keyframes should get
+ * visual keyframes even if flag not set, as it's not that useful otherwise
+ * (for quick animation recording)
+ */
+ flag = ANIM_get_keyframing_flags(scene, 1);
+
+ if (targetless_ik) {
+ flag |= INSERTKEY_MATRIX;
+ }
+
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone->flag & (BONE_TRANSFORM | BONE_TRANSFORM_MIRROR)) {
+
+ ListBase dsources = {NULL, NULL};
+
+ /* clear any 'unkeyed' flag it may have */
+ pchan->bone->flag &= ~BONE_UNKEYED;
+
+ /* add datasource override for the camera object */
+ ANIM_relative_keyingset_add_source(&dsources, id, &RNA_PoseBone, pchan);
+
+ /* only insert into active keyingset? */
+ if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
+ /* run the active Keying Set on the current datasource */
+ ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ /* only insert into available channels? */
+ else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) {
+ if (act) {
+ for (fcu = act->curves.first; fcu; fcu = fcu->next) {
+ /* only insert keyframes for this F-Curve if it affects the current bone */
+ if (strstr(fcu->rna_path, "bones")) {
+ char *pchanName = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
+
+ /* only if bone name matches too...
+ * NOTE: this will do constraints too, but those are ok to do here too?
+ */
+ if (pchanName && STREQ(pchanName, pchan->name)) {
+ insert_keyframe(bmain,
+ reports,
+ id,
+ act,
+ ((fcu->grp) ? (fcu->grp->name) : (NULL)),
+ fcu->rna_path,
+ fcu->array_index,
+ cfra,
+ ts->keyframe_type,
+ &nla_cache,
+ flag);
+ }
+
+ if (pchanName) {
+ MEM_freeN(pchanName);
+ }
+ }
+ }
+ }
+ }
+ /* only insert keyframe if needed? */
+ else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
+ bool do_loc = false, do_rot = false, do_scale = false;
+
+ /* Filter the conditions when this happens
+ * (assume that 'curarea->spacetype == SPACE_VIEW3D'). */
+ if (tmode == TFM_TRANSLATION) {
+ if (targetless_ik) {
+ do_rot = true;
+ }
+ else {
+ do_loc = true;
+ }
+ }
+ else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
+ if (ELEM(scene->toolsettings->transform_pivot_point,
+ V3D_AROUND_CURSOR,
+ V3D_AROUND_ACTIVE)) {
+ do_loc = true;
+ }
+
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
+ do_rot = true;
+ }
+ }
+ else if (tmode == TFM_RESIZE) {
+ if (ELEM(scene->toolsettings->transform_pivot_point,
+ V3D_AROUND_CURSOR,
+ V3D_AROUND_ACTIVE)) {
+ do_loc = true;
+ }
+
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
+ do_scale = true;
+ }
+ }
+
+ if (do_loc) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ if (do_rot) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ if (do_scale) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_SCALING_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ }
+ /* insert keyframe in all (transform) channels */
+ else {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+
+ /* free temp info */
+ BLI_freelistN(&dsources);
+ }
+ }
+
+ BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
+ }
+ else {
+ /* tag channels that should have unkeyed data */
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone->flag & BONE_TRANSFORM) {
+ /* tag this channel */
+ pchan->bone->flag |= BONE_UNKEYED;
+ }
+ }
+ }
+}
+
+/* Return if we need to update motion paths, only if they already exist,
+ * and we will insert a keyframe at the end of transform. */
+bool motionpath_need_update_pose(Scene *scene, Object *ob)
+{
+ if (autokeyframe_cfra_can_key(scene, &ob->id)) {
+ return (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
+ }
+
+ return false;
+}
+
+static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t)
+{
+ SpaceClip *sc = t->sa->spacedata.first;
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
+ const int framenr = ED_space_clip_get_clip_frame_number(sc);
+ /* Update coordinates of modified plane tracks. */
+ for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first; plane_track;
+ plane_track = plane_track->next) {
+ bool do_update = false;
+ if (plane_track->flag & PLANE_TRACK_HIDDEN) {
+ continue;
+ }
+ do_update |= PLANE_TRACK_VIEW_SELECTED(plane_track) != 0;
+ if (do_update == false) {
+ if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
+ int i;
+ for (i = 0; i < plane_track->point_tracksnr; i++) {
+ MovieTrackingTrack *track = plane_track->point_tracks[i];
+ if (TRACK_VIEW_SELECTED(sc, track)) {
+ do_update = true;
+ break;
+ }
+ }
+ }
+ }
+ if (do_update) {
+ BKE_tracking_track_plane_from_existing_motion(plane_track, framenr);
+ }
+ }
+ if (t->scene->nodetree != NULL) {
+ /* Tracks can be used for stabilization nodes,
+ * flush update for such nodes.
+ */
+ nodeUpdateID(t->scene->nodetree, &clip->id);
+ WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL);
+ }
+}
+
+static void special_aftertrans_update__mask(bContext *C, TransInfo *t)
+{
+ Mask *mask = NULL;
+
+ if (t->spacetype == SPACE_CLIP) {
+ SpaceClip *sc = t->sa->spacedata.first;
+ mask = ED_space_clip_get_mask(sc);
+ }
+ else if (t->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = t->sa->spacedata.first;
+ mask = ED_space_image_get_mask(sima);
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ if (t->scene->nodetree) {
+ /* tracks can be used for stabilization nodes,
+ * flush update for such nodes */
+ // if (nodeUpdateID(t->scene->nodetree, &mask->id))
+ {
+ WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id);
+ }
+ }
+
+ /* TODO - dont key all masks... */
+ if (IS_AUTOKEY_ON(t->scene)) {
+ Scene *scene = t->scene;
+
+ ED_mask_layer_shape_auto_key_select(mask, CFRA);
+ }
+}
+
+static void special_aftertrans_update__node(bContext *C, TransInfo *t)
+{
+ Main *bmain = CTX_data_main(C);
+ const bool canceled = (t->state == TRANS_CANCEL);
+
+ if (canceled && t->remove_on_cancel) {
+ /* remove selected nodes on cancel */
+ SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
+ bNodeTree *ntree = snode->edittree;
+ if (ntree) {
+ bNode *node, *node_next;
+ for (node = ntree->nodes.first; node; node = node_next) {
+ node_next = node->next;
+ if (node->flag & NODE_SELECT) {
+ nodeRemoveNode(bmain, ntree, node, true);
+ }
+ }
+ }
+ }
+}
+
+static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
+{
+ /* so automerge supports mirror */
+ if ((t->scene->toolsettings->automerge) && ((t->flag & T_EDIT) && t->obedit_type == OB_MESH)) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BMesh *bm = em->bm;
+ char hflag;
+ bool has_face_sel = (bm->totfacesel != 0);
+
+ if (tc->mirror.use_mirror_any) {
+ TransDataMirror *tdm;
+ int i;
+
+ /* Rather then adjusting the selection (which the user would notice)
+ * tag all mirrored verts, then auto-merge those. */
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false);
+
+ for (i = tc->mirror.data_len, tdm = tc->mirror.data; i--; tdm++) {
+ BM_elem_flag_enable((BMVert *)tdm->extra, BM_ELEM_TAG);
+ }
+
+ hflag = BM_ELEM_SELECT | BM_ELEM_TAG;
+ }
+ else {
+ hflag = BM_ELEM_SELECT;
+ }
+
+ if (t->scene->toolsettings->automerge & AUTO_MERGE) {
+ if (t->scene->toolsettings->automerge & AUTO_MERGE_AND_SPLIT) {
+ EDBM_automerge_and_split(
+ tc->obedit, true, true, true, hflag, t->scene->toolsettings->doublimit);
+ }
+ else {
+ EDBM_automerge(tc->obedit, true, hflag, t->scene->toolsettings->doublimit);
+ }
+ }
+
+ /* Special case, this is needed or faces won't re-select.
+ * Flush selected edges to faces. */
+ if (has_face_sel && (em->selectmode == SCE_SELECT_FACE)) {
+ EDBM_selectmode_flush_ex(em, SCE_SELECT_EDGE);
+ }
+ }
+ }
+}
+
+/* inserting keys, pointcache, redraw events... */
+/**
+ * \note Sequencer freeing has its own function now because of a conflict
+ * with transform's order of freeing (campbell).
+ * Order changed, the sequencer stuff should go back in here
+ */
+void special_aftertrans_update(bContext *C, TransInfo *t)
+{
+ Main *bmain = CTX_data_main(t->context);
+ BLI_assert(bmain == CTX_data_main(C));
+
+ Object *ob;
+ // short redrawipo=0, resetslowpar=1;
+ const bool canceled = (t->state == TRANS_CANCEL);
+ const bool duplicate = (t->mode == TFM_TIME_DUPLICATE);
+
+ /* early out when nothing happened */
+ if (t->data_len_all == 0 || t->mode == TFM_DUMMY) {
+ return;
+ }
+
+ if (t->spacetype == SPACE_VIEW3D) {
+ if (t->flag & T_EDIT) {
+ /* Special Exception:
+ * We don't normally access 't->custom.mode' here, but its needed in this case. */
+
+ if (canceled == 0) {
+ /* we need to delete the temporary faces before automerging */
+ if (t->mode == TFM_EDGE_SLIDE) {
+ /* handle multires re-projection, done
+ * on transform completion since it's
+ * really slow -joeedh */
+ projectEdgeSlideData(t, true);
+ }
+ else if (t->mode == TFM_VERT_SLIDE) {
+ /* as above */
+ projectVertSlideData(t, true);
+ }
+
+ if (t->obedit_type == OB_MESH) {
+ special_aftertrans_update__mesh(C, t);
+ }
+ }
+ else {
+ if (t->mode == TFM_EDGE_SLIDE) {
+ EdgeSlideParams *slp = t->custom.mode.data;
+ slp->perc = 0.0;
+ projectEdgeSlideData(t, false);
+ }
+ else if (t->mode == TFM_VERT_SLIDE) {
+ EdgeSlideParams *slp = t->custom.mode.data;
+ slp->perc = 0.0;
+ projectVertSlideData(t, false);
+ }
+ }
+ }
+ }
+
+ if (t->options & CTX_GPENCIL_STROKES) {
+ /* pass */
+ }
+ else if (t->spacetype == SPACE_SEQ) {
+ /* freeSeqData in transform_conversions.c does this
+ * keep here so the else at the end wont run... */
+
+ SpaceSeq *sseq = (SpaceSeq *)t->sa->spacedata.first;
+
+ /* marker transform, not especially nice but we may want to move markers
+ * at the same time as keyframes in the dope sheet. */
+ if ((sseq->flag & SEQ_MARKER_TRANS) && (canceled == 0)) {
+ /* cant use TFM_TIME_EXTEND
+ * for some reason EXTEND is changed into TRANSLATE, so use frame_side instead */
+
+ if (t->mode == TFM_SEQ_SLIDE) {
+ if (t->frame_side == 'B') {
+ ED_markers_post_apply_transform(
+ &t->scene->markers, t->scene, TFM_TIME_TRANSLATE, t->values[0], t->frame_side);
+ }
+ }
+ else if (ELEM(t->frame_side, 'L', 'R')) {
+ ED_markers_post_apply_transform(
+ &t->scene->markers, t->scene, TFM_TIME_EXTEND, t->values[0], t->frame_side);
+ }
+ }
+ }
+ else if (t->spacetype == SPACE_IMAGE) {
+ if (t->options & CTX_MASK) {
+ special_aftertrans_update__mask(C, t);
+ }
+ }
+ else if (t->spacetype == SPACE_NODE) {
+ SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
+ special_aftertrans_update__node(C, t);
+ if (canceled == 0) {
+ ED_node_post_apply_transform(C, snode->edittree);
+
+ ED_node_link_insert(bmain, t->sa);
+ }
+
+ /* clear link line */
+ ED_node_link_intersect_test(t->sa, 0);
+ }
+ else if (t->spacetype == SPACE_CLIP) {
+ if (t->options & CTX_MOVIECLIP) {
+ special_aftertrans_update__movieclip(C, t);
+ }
+ else if (t->options & CTX_MASK) {
+ special_aftertrans_update__mask(C, t);
+ }
+ }
+ else if (t->spacetype == SPACE_ACTION) {
+ SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
+ bAnimContext ac;
+
+ /* initialize relevant anim-context 'context' data */
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return;
+ }
+
+ ob = ac.obact;
+
+ if (ELEM(ac.datatype, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY, ANIMCONT_TIMELINE)) {
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
+
+ /* get channels to work on */
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* these should all be F-Curves */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ FCurve *fcu = (FCurve *)ale->key_data;
+
+ /* 3 cases here for curve cleanups:
+ * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
+ * 2) canceled == 0 -> user confirmed the transform,
+ * so duplicates should be removed
+ * 3) canceled + duplicate -> user canceled the transform,
+ * but we made duplicates, so get rid of these
+ */
+ if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
+ if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
+ posttrans_fcurve_clean(fcu, false); /* only use handles in graph editor */
+ ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
+ }
+ else {
+ posttrans_fcurve_clean(fcu, false); /* only use handles in graph editor */
+ }
+ }
+ }
+
+ /* free temp memory */
+ ANIM_animdata_freelist(&anim_data);
+ }
+ else if (ac.datatype == ANIMCONT_ACTION) { // TODO: just integrate into the above...
+ /* Depending on the lock status, draw necessary views */
+ // fixme... some of this stuff is not good
+ if (ob) {
+ if (ob->pose || BKE_key_from_object(ob)) {
+ DEG_id_tag_update(&ob->id,
+ ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
+ }
+ else {
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+ }
+ }
+
+ /* 3 cases here for curve cleanups:
+ * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
+ * 2) canceled == 0 -> user confirmed the transform,
+ * so duplicates should be removed.
+ * 3) canceled + duplicate -> user canceled the transform,
+ * but we made duplicates, so get rid of these.
+ */
+ if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
+ posttrans_action_clean(&ac, (bAction *)ac.data);
+ }
+ }
+ else if (ac.datatype == ANIMCONT_GPENCIL) {
+ /* remove duplicate frames and also make sure points are in order! */
+ /* 3 cases here for curve cleanups:
+ * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
+ * 2) canceled == 0 -> user confirmed the transform,
+ * so duplicates should be removed
+ * 3) canceled + duplicate -> user canceled the transform,
+ * but we made duplicates, so get rid of these
+ */
+ if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
+ bGPdata *gpd;
+
+ // XXX: BAD! this get gpencil datablocks directly from main db...
+ // but that's how this currently works :/
+ for (gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) {
+ if (ID_REAL_USERS(gpd)) {
+ posttrans_gpd_clean(gpd);
+ }
+ }
+ }
+ }
+ else if (ac.datatype == ANIMCONT_MASK) {
+ /* remove duplicate frames and also make sure points are in order! */
+ /* 3 cases here for curve cleanups:
+ * 1) NOTRANSKEYCULL on:
+ * Cleanup of duplicates shouldn't be done.
+ * 2) canceled == 0:
+ * User confirmed the transform, so duplicates should be removed.
+ * 3) Canceled + duplicate:
+ * User canceled the transform, but we made duplicates, so get rid of these.
+ */
+ if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
+ Mask *mask;
+
+ // XXX: BAD! this get gpencil datablocks directly from main db...
+ // but that's how this currently works :/
+ for (mask = bmain->masks.first; mask; mask = mask->id.next) {
+ if (ID_REAL_USERS(mask)) {
+ posttrans_mask_clean(mask);
+ }
+ }
+ }
+ }
+
+ /* marker transform, not especially nice but we may want to move markers
+ * at the same time as keyframes in the dope sheet.
+ */
+ if ((saction->flag & SACTION_MARKERS_MOVE) && (canceled == 0)) {
+ if (t->mode == TFM_TIME_TRANSLATE) {
+#if 0
+ if (ELEM(t->frame_side, 'L', 'R')) { /* TFM_TIME_EXTEND */
+ /* same as below */
+ ED_markers_post_apply_transform(
+ ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side);
+ }
+ else /* TFM_TIME_TRANSLATE */
+#endif
+ {
+ ED_markers_post_apply_transform(
+ ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side);
+ }
+ }
+ else if (t->mode == TFM_TIME_SCALE) {
+ ED_markers_post_apply_transform(
+ ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side);
+ }
+ }
+
+ /* make sure all F-Curves are set correctly */
+ if (!ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ ANIM_editkeyframes_refresh(&ac);
+ }
+
+ /* clear flag that was set for time-slide drawing */
+ saction->flag &= ~SACTION_MOVING;
+ }
+ else if (t->spacetype == SPACE_GRAPH) {
+ SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ bAnimContext ac;
+ const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
+
+ /* initialize relevant anim-context 'context' data */
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return;
+ }
+
+ if (ac.datatype) {
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
+
+ /* get channels to work on */
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ FCurve *fcu = (FCurve *)ale->key_data;
+
+ /* 3 cases here for curve cleanups:
+ * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
+ * 2) canceled == 0 -> user confirmed the transform,
+ * so duplicates should be removed
+ * 3) canceled + duplicate -> user canceled the transform,
+ * but we made duplicates, so get rid of these
+ */
+ if ((sipo->flag & SIPO_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
+ if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
+ posttrans_fcurve_clean(fcu, use_handle);
+ ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
+ }
+ else {
+ posttrans_fcurve_clean(fcu, use_handle);
+ }
+ }
+ }
+
+ /* free temp memory */
+ ANIM_animdata_freelist(&anim_data);
+ }
+
+ /* Make sure all F-Curves are set correctly, but not if transform was
+ * canceled, since then curves were already restored to initial state.
+ * Note: if the refresh is really needed after cancel then some way
+ * has to be added to not update handle types (see bug 22289).
+ */
+ if (!canceled) {
+ ANIM_editkeyframes_refresh(&ac);
+ }
+ }
+ else if (t->spacetype == SPACE_NLA) {
+ bAnimContext ac;
+
+ /* initialize relevant anim-context 'context' data */
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return;
+ }
+
+ if (ac.datatype) {
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT);
+
+ /* get channels to work on */
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ NlaTrack *nlt = (NlaTrack *)ale->data;
+
+ /* make sure strips are in order again */
+ BKE_nlatrack_sort_strips(nlt);
+
+ /* remove the temp metas */
+ BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
+ }
+
+ /* free temp memory */
+ ANIM_animdata_freelist(&anim_data);
+
+ /* perform after-transfrom validation */
+ ED_nla_postop_refresh(&ac);
+ }
+ }
+ else if (t->flag & T_EDIT) {
+ if (t->obedit_type == OB_MESH) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ /* table needs to be created for each edit command, since vertices can move etc */
+ ED_mesh_mirror_spatial_table(tc->obedit, em, NULL, NULL, 'e');
+ /* TODO(campbell): xform: We need support for many mirror objects at once! */
+ break;
+ }
+ }
+ }
+ else if (t->flag & T_POSE && (t->mode == TFM_BONESIZE)) {
+ /* Handle the exception where for TFM_BONESIZE in edit mode we pretend to be
+ * in pose mode (to use bone orientation matrix),
+ * in that case we don't do operations like auto-keyframing. */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ ob = tc->poseobj;
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+ }
+ else if (t->flag & T_POSE) {
+ GSet *motionpath_updates = BLI_gset_ptr_new("motionpath updates");
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ bPoseChannel *pchan;
+ short targetless_ik = 0;
+
+ ob = tc->poseobj;
+
+ if ((t->flag & T_AUTOIK) && (t->options & CTX_AUTOCONFIRM)) {
+ /* when running transform non-interactively (operator exec),
+ * we need to update the pose otherwise no updates get called during
+ * transform and the auto-ik is not applied. see [#26164] */
+ struct Object *pose_ob = tc->poseobj;
+ BKE_pose_where_is(t->depsgraph, t->scene, pose_ob);
+ }
+
+ /* set BONE_TRANSFORM flags for autokey, gizmo draw might have changed them */
+ if (!canceled && (t->mode != TFM_DUMMY)) {
+ count_set_pose_transflags(ob, t->mode, t->around, NULL);
+ }
+
+ /* if target-less IK grabbing, we calculate the pchan transforms and clear flag */
+ if (!canceled && t->mode == TFM_TRANSLATION) {
+ targetless_ik = apply_targetless_ik(ob);
+ }
+ else {
+ /* not forget to clear the auto flag */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ bKinematicConstraint *data = has_targetless_ik(pchan);
+ if (data) {
+ data->flag &= ~CONSTRAINT_IK_AUTO;
+ }
+ }
+ }
+
+ if (t->mode == TFM_TRANSLATION) {
+ pose_grab_with_ik_clear(bmain, ob);
+ }
+
+ /* automatic inserting of keys and unkeyed tagging -
+ * only if transform wasn't canceled (or TFM_DUMMY) */
+ if (!canceled && (t->mode != TFM_DUMMY)) {
+ autokeyframe_pose(C, t->scene, ob, t->mode, targetless_ik);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+ else {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+
+ if (t->mode != TFM_DUMMY && motionpath_need_update_pose(t->scene, ob)) {
+ BLI_gset_insert(motionpath_updates, ob);
+ }
+ }
+
+ /* Update motion paths once for all transformed bones in an object. */
+ GSetIterator gs_iter;
+ GSET_ITER (gs_iter, motionpath_updates) {
+ const ePosePathCalcRange range = canceled ? POSE_PATH_CALC_RANGE_CURRENT_FRAME :
+ POSE_PATH_CALC_RANGE_CHANGED;
+ ob = BLI_gsetIterator_getKey(&gs_iter);
+ ED_pose_recalculate_paths(C, t->scene, ob, range);
+ }
+ BLI_gset_free(motionpath_updates, NULL);
+ }
+ else if (t->options & CTX_PAINT_CURVE) {
+ /* pass */
+ }
+ else if (t->options & CTX_SCULPT) {
+ /* pass */
+ }
+ else if ((t->view_layer->basact) && (ob = t->view_layer->basact->object) &&
+ (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->depsgraph, t->scene, ob)) {
+ /* do nothing */
+ }
+ else if (t->flag & T_CURSOR) {
+ /* do nothing */
+ }
+ else { /* Objects */
+ BLI_assert(t->flag & (T_OBJECT | T_TEXTURE));
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+ bool motionpath_update = false;
+
+ for (int i = 0; i < tc->data_len; i++) {
+ TransData *td = tc->data + i;
+ ListBase pidlist;
+ PTCacheID *pid;
+ ob = td->ob;
+
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ /* flag object caches as outdated */
+ BKE_ptcache_ids_from_object(&pidlist, ob, t->scene, MAX_DUPLI_RECUR);
+ for (pid = pidlist.first; pid; pid = pid->next) {
+ if (pid->type != PTCACHE_TYPE_PARTICLES) {
+ /* particles don't need reset on geometry change */
+ pid->cache->flag |= PTCACHE_OUTDATED;
+ }
+ }
+ BLI_freelistN(&pidlist);
+
+ /* pointcache refresh */
+ if (BKE_ptcache_object_reset(t->scene, ob, PTCACHE_RESET_OUTDATED)) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+
+ /* Needed for proper updating of "quick cached" dynamics. */
+ /* Creates troubles for moving animated objects without */
+ /* autokey though, probably needed is an anim sys override? */
+ /* Please remove if some other solution is found. -jahka */
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+
+ /* Set autokey if necessary */
+ if (!canceled) {
+ autokeyframe_object(C, t->scene, t->view_layer, ob, t->mode);
+ }
+
+ motionpath_update |= motionpath_need_update_object(t->scene, ob);
+
+ /* restore rigid body transform */
+ if (ob->rigidbody_object && canceled) {
+ float ctime = BKE_scene_frame_get(t->scene);
+ if (BKE_rigidbody_check_sim_running(t->scene->rigidbody_world, ctime)) {
+ BKE_rigidbody_aftertrans_update(ob,
+ td->ext->oloc,
+ td->ext->orot,
+ td->ext->oquat,
+ td->ext->orotAxis,
+ td->ext->orotAngle);
+ }
+ }
+ }
+
+ if (motionpath_update) {
+ /* Update motion paths once for all transformed objects. */
+ const eObjectPathCalcRange range = canceled ? OBJECT_PATH_CALC_RANGE_CURRENT_FRAME :
+ OBJECT_PATH_CALC_RANGE_CHANGED;
+ ED_objects_recalculate_paths(C, t->scene, range);
+ }
+ }
+
+ clear_trans_object_base_flags(t);
+}
+
+int special_transform_moving(TransInfo *t)
+{
+ if (t->spacetype == SPACE_SEQ) {
+ return G_TRANSFORM_SEQ;
+ }
+ else if (t->spacetype == SPACE_GRAPH) {
+ return G_TRANSFORM_FCURVES;
+ }
+ else if ((t->flag & T_EDIT) || (t->flag & T_POSE)) {
+ return G_TRANSFORM_EDIT;
+ }
+ else if (t->flag & (T_OBJECT | T_TEXTURE)) {
+ return G_TRANSFORM_OBJ;
+ }
+
+ return 0;
+}
+
+/** \} */
+
+static int countAndCleanTransDataContainer(TransInfo *t)
+{
+ BLI_assert(ELEM(t->data_len_all, 0, -1));
+ t->data_len_all = 0;
+ uint data_container_len_orig = t->data_container_len;
+ for (TransDataContainer *th_end = t->data_container - 1,
+ *tc = t->data_container + (t->data_container_len - 1);
+ tc != th_end;
+ tc--) {
+ if (tc->data_len == 0) {
+ uint index = tc - t->data_container;
+ if (index + 1 != t->data_container_len) {
+ SWAP(TransDataContainer,
+ t->data_container[index],
+ t->data_container[t->data_container_len - 1]);
+ }
+ t->data_container_len -= 1;
+ }
+ else {
+ t->data_len_all += tc->data_len;
+ }
+ }
+ if (data_container_len_orig != t->data_container_len) {
+ t->data_container = MEM_reallocN(t->data_container,
+ sizeof(*t->data_container) * t->data_container_len);
+ }
+ return t->data_len_all;
+}
+
+void createTransData(bContext *C, TransInfo *t)
+{
+ Scene *scene = t->scene;
+ ViewLayer *view_layer = t->view_layer;
+ Object *ob = OBACT(view_layer);
+
+ bool has_transform_context = true;
+ t->data_len_all = -1;
+
+ /* if tests must match recalcData for correct updates */
+ if (t->options & CTX_CURSOR) {
+ t->flag |= T_CURSOR;
+ t->obedit_type = -1;
+
+ if (t->spacetype == SPACE_IMAGE) {
+ createTransCursor_image(t);
+ }
+ else {
+ createTransCursor_view3d(t);
+ }
+ countAndCleanTransDataContainer(t);
+ }
+ else if ((t->options & CTX_SCULPT) && !(t->options & CTX_PAINT_CURVE)) {
+ createTransSculpt(t);
+ countAndCleanTransDataContainer(t);
+ }
+ else if (t->options & CTX_TEXTURE) {
+ t->flag |= T_TEXTURE;
+ t->obedit_type = -1;
+
+ createTransTexspace(t);
+ countAndCleanTransDataContainer(t);
+ }
+ else if (t->options & CTX_EDGE) {
+ /* Multi object editing. */
+ initTransDataContainers_FromObjectData(t, ob, NULL, 0);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ tc->data_ext = NULL;
+ }
+ t->flag |= T_EDIT;
+
+ createTransEdge(t);
+ countAndCleanTransDataContainer(t);
+
+ if (t->data_len_all && t->flag & T_PROP_EDIT) {
+ sort_trans_data_selected_first(t);
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+ }
+ else if (t->options & CTX_GPENCIL_STROKES) {
+ t->options |= CTX_GPENCIL_STROKES;
+ t->flag |= T_POINTS | T_EDIT;
+
+ initTransDataContainers_FromObjectData(t, ob, NULL, 0);
+ createTransGPencil(C, t);
+ countAndCleanTransDataContainer(t);
+
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
+ sort_trans_data_selected_first(t);
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+ }
+ else if (t->spacetype == SPACE_IMAGE) {
+ t->flag |= T_POINTS | T_2D_EDIT;
+ if (t->options & CTX_MASK) {
+
+ /* copied from below */
+ createTransMaskingData(C, t);
+ countAndCleanTransDataContainer(t);
+
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
+ sort_trans_data_selected_first(t);
+ set_prop_dist(t, true);
+ sort_trans_data_dist(t);
+ }
+ }
+ else if (t->options & CTX_PAINT_CURVE) {
+ if (!ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) {
+ createTransPaintCurveVerts(C, t);
+ countAndCleanTransDataContainer(t);
+ }
+ else {
+ has_transform_context = false;
+ }
+ }
+ else if (t->obedit_type == OB_MESH) {
+
+ initTransDataContainers_FromObjectData(t, ob, NULL, 0);
+ createTransUVs(C, t);
+ countAndCleanTransDataContainer(t);
+
+ t->flag |= T_EDIT;
+
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
+ sort_trans_data_selected_first(t);
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+ }
+ else {
+ has_transform_context = false;
+ }
+ }
+ else if (t->spacetype == SPACE_ACTION) {
+ t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
+ createTransActionData(C, t);
+ countAndCleanTransDataContainer(t);
+
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
+ sort_trans_data_selected_first(t);
+ /* don't do that, distance has been set in createTransActionData already */
+ // set_prop_dist(t, false);
+ sort_trans_data_dist(t);
+ }
+ }
+ else if (t->spacetype == SPACE_NLA) {
+ t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
+ createTransNlaData(C, t);
+ countAndCleanTransDataContainer(t);
+ }
+ else if (t->spacetype == SPACE_SEQ) {
+ t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
+ t->num.flag |= NUM_NO_FRACTION; /* sequencer has no use for floating point trasnform */
+ createTransSeqData(C, t);
+ countAndCleanTransDataContainer(t);
+ }
+ else if (t->spacetype == SPACE_GRAPH) {
+ t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
+ createTransGraphEditData(C, t);
+ countAndCleanTransDataContainer(t);
+
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
+ /* makes selected become first in array */
+ sort_trans_data_selected_first(t);
+
+ /* don't do that, distance has been set in createTransGraphEditData already */
+ set_prop_dist(t, false);
+
+ sort_trans_data_dist(t);
+ }
+ }
+ else if (t->spacetype == SPACE_NODE) {
+ t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
+ createTransNodeData(C, t);
+ countAndCleanTransDataContainer(t);
+
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
+ sort_trans_data_selected_first(t);
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+ }
+ else if (t->spacetype == SPACE_CLIP) {
+ t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
+ if (t->options & CTX_MOVIECLIP) {
+ createTransTrackingData(C, t);
+ countAndCleanTransDataContainer(t);
+ }
+ else if (t->options & CTX_MASK) {
+ /* copied from above */
+ createTransMaskingData(C, t);
+ countAndCleanTransDataContainer(t);
+
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
+ sort_trans_data_selected_first(t);
+ set_prop_dist(t, true);
+ sort_trans_data_dist(t);
+ }
+ }
+ else {
+ has_transform_context = false;
+ }
+ }
+ else if (t->obedit_type != -1) {
+ /* Multi object editing. */
+ initTransDataContainers_FromObjectData(t, ob, NULL, 0);
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ tc->data_ext = NULL;
+ }
+ if (t->obedit_type == OB_MESH) {
+ createTransEditVerts(t);
+ }
+ else if (ELEM(t->obedit_type, OB_CURVE, OB_SURF)) {
+ createTransCurveVerts(t);
+ }
+ else if (t->obedit_type == OB_LATTICE) {
+ createTransLatticeVerts(t);
+ }
+ else if (t->obedit_type == OB_MBALL) {
+ createTransMBallVerts(t);
+ }
+ else if (t->obedit_type == OB_ARMATURE) {
+ t->flag &= ~T_PROP_EDIT;
+ createTransArmatureVerts(t);
+ }
+ else {
+ printf("edit type not implemented!\n");
+ }
+
+ countAndCleanTransDataContainer(t);
+
+ t->flag |= T_EDIT | T_POINTS;
+
+ if (t->data_len_all) {
+ if (t->flag & T_PROP_EDIT) {
+ if (ELEM(t->obedit_type, OB_CURVE, OB_MESH)) {
+ sort_trans_data_selected_first(t);
+ if ((t->obedit_type == OB_MESH) && (t->flag & T_PROP_CONNECTED)) {
+ /* already calculated by editmesh_set_connectivity_distance */
+ }
+ else {
+ set_prop_dist(t, 0);
+ }
+ sort_trans_data_dist(t);
+ }
+ else {
+ sort_trans_data_selected_first(t);
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+ }
+ else {
+ if (ELEM(t->obedit_type, OB_CURVE)) {
+ /* Needed because bezier handles can be partially selected
+ * and are still added into transform data. */
+ sort_trans_data_selected_first(t);
+ }
+ }
+ }
+
+ /* exception... hackish, we want bonesize to use bone orientation matrix (ton) */
+ if (t->mode == TFM_BONESIZE) {
+ t->flag &= ~(T_EDIT | T_POINTS);
+ t->flag |= T_POSE;
+ t->obedit_type = -1;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ tc->poseobj = tc->obedit;
+ tc->obedit = NULL;
+ }
+ }
+ }
+ else if (ob && (ob->mode & OB_MODE_POSE)) {
+ /* XXX this is currently limited to active armature only... */
+
+ /* XXX active-layer checking isn't done
+ * as that should probably be checked through context instead. */
+
+ /* Multi object editing. */
+ initTransDataContainers_FromObjectData(t, ob, NULL, 0);
+ createTransPose(t);
+ countAndCleanTransDataContainer(t);
+ }
+ else if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && !(t->options & CTX_PAINT_CURVE)) {
+ /* important that ob_armature can be set even when its not selected [#23412]
+ * lines below just check is also visible */
+ has_transform_context = false;
+ Object *ob_armature = modifiers_isDeformedByArmature(ob);
+ if (ob_armature && ob_armature->mode & OB_MODE_POSE) {
+ Base *base_arm = BKE_view_layer_base_find(t->view_layer, ob_armature);
+ if (base_arm) {
+ View3D *v3d = t->view;
+ if (BASE_VISIBLE(v3d, base_arm)) {
+ Object *objects[1];
+ objects[0] = ob_armature;
+ uint objects_len = 1;
+ initTransDataContainers_FromObjectData(t, ob_armature, objects, objects_len);
+ createTransPose(t);
+ countAndCleanTransDataContainer(t);
+ has_transform_context = true;
+ }
+ }
+ }
+ }
+ else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) &&
+ PE_start_edit(PE_get_current(t->depsgraph, scene, ob))) {
+ createTransParticleVerts(C, t);
+ countAndCleanTransDataContainer(t);
+ t->flag |= T_POINTS;
+
+ if (t->data_len_all && t->flag & T_PROP_EDIT) {
+ sort_trans_data_selected_first(t);
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+ }
+ else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
+ if ((t->options & CTX_PAINT_CURVE) && !ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) {
+ t->flag |= T_POINTS | T_2D_EDIT;
+ createTransPaintCurveVerts(C, t);
+ countAndCleanTransDataContainer(t);
+ }
+ else {
+ has_transform_context = false;
+ }
+ }
+ else if ((ob) &&
+ (ELEM(
+ ob->mode, OB_MODE_PAINT_GPENCIL, OB_MODE_SCULPT_GPENCIL, OB_MODE_WEIGHT_GPENCIL))) {
+ /* In grease pencil all transformations must be canceled if not Object or Edit. */
+ has_transform_context = false;
+ }
+ else {
+ /* Needed for correct Object.obmat after duplication, see: T62135. */
+ BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context));
+
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_DATA_ORIGIN) != 0) {
+ t->options |= CTX_OBMODE_XFORM_OBDATA;
+ }
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_SKIP_CHILDREN) != 0) {
+ t->options |= CTX_OBMODE_XFORM_SKIP_CHILDREN;
+ }
+
+ createTransObject(C, t);
+ countAndCleanTransDataContainer(t);
+ t->flag |= T_OBJECT;
+
+ if (t->data_len_all && t->flag & T_PROP_EDIT) {
+ // selected objects are already first, no need to presort
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+
+ /* Check if we're transforming the camera from the camera */
+ if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) {
+ View3D *v3d = t->view;
+ RegionView3D *rv3d = t->ar->regiondata;
+ if ((rv3d->persp == RV3D_CAMOB) && v3d->camera) {
+ /* we could have a flag to easily check an object is being transformed */
+ if (v3d->camera->id.tag & LIB_TAG_DOIT) {
+ t->flag |= T_CAMERA;
+ }
+ }
+ }
+ }
+
+ /* Check that 'countAndCleanTransDataContainer' ran. */
+ if (has_transform_context) {
+ BLI_assert(t->data_len_all != -1);
+ }
+ else {
+ BLI_assert(t->data_len_all == -1);
+ t->data_len_all = 0;
+ }
+
+ BLI_assert((!(t->flag & T_EDIT)) == (!(t->obedit_type != -1)));
+}
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
new file mode 100644
index 00000000000..53ff9952d05
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert.h
@@ -0,0 +1,141 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#ifndef __TRANSFORM_CONVERT_H__
+#define __TRANSFORM_CONVERT_H__
+
+struct BezTriple;
+struct ListBase;
+struct Object;
+struct TransData;
+struct TransDataContainer;
+struct TransDataCurveHandleFlags;
+struct TransInfo;
+struct bContext;
+struct bKinematicConstraint;
+struct bPoseChannel;
+
+/* transform_convert.c */
+int count_set_pose_transflags(Object *ob,
+ const int mode,
+ const short around,
+ bool has_translate_rotate[2]);
+void transform_autoik_update(TransInfo *t, short mode);
+void autokeyframe_object(struct bContext *C,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ struct Object *ob,
+ int tmode);
+void autokeyframe_pose(
+ struct bContext *C, struct Scene *scene, struct Object *ob, int tmode, short targetless_ik);
+bool motionpath_need_update_object(struct Scene *scene, struct Object *ob);
+bool motionpath_need_update_pose(struct Scene *scene, struct Object *ob);
+int special_transform_moving(TransInfo *t);
+void remake_graph_transdata(TransInfo *t, struct ListBase *anim_data);
+void special_aftertrans_update(struct bContext *C, TransInfo *t);
+void sort_trans_data_dist(TransInfo *t);
+void createTransData(struct bContext *C, TransInfo *t);
+bool clipUVTransform(TransInfo *t, float vec[2], const bool resize);
+void clipUVData(TransInfo *t);
+
+/* transform_convert_action.c */
+void flushTransIntFrameActionData(TransInfo *t);
+/* transform_convert_armature.c */
+void restoreMirrorPoseBones(TransDataContainer *tc);
+void restoreBones(TransDataContainer *tc);
+/* transform_convert_graph.c */
+void flushTransGraphData(TransInfo *t);
+/* transform_convert_mask.c */
+void flushTransMasking(TransInfo *t);
+/* transform_convert_mesh.c */
+void flushTransUVs(TransInfo *t);
+void trans_mesh_customdata_correction_init(TransInfo *t);
+void trans_mesh_customdata_correction_apply(struct TransDataContainer *tc, bool is_final);
+/* transform_convert_node.c */
+void flushTransNodes(TransInfo *t);
+/* transform_convert_object.c */
+void trans_obdata_in_obmode_update_all(struct TransInfo *t);
+void trans_obchild_in_obmode_update_all(struct TransInfo *t);
+/* transform_convert_paintcurve.c */
+void flushTransPaintCurve(TransInfo *t);
+/* transform_convert_particle.c */
+void flushTransParticles(TransInfo *t);
+/* transform_convert_sequencer.c */
+void flushTransSeq(TransInfo *t);
+/* transform_convert_tracking.c */
+void flushTransTracking(TransInfo *t);
+
+/********************* intern **********************/
+
+/* transform_convert.c */
+void transform_around_single_fallback(TransInfo *t);
+bool constraints_list_needinv(TransInfo *t, ListBase *list);
+void calc_distanceCurveVerts(TransData *head, TransData *tail);
+struct TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt);
+bool FrameOnMouseSide(char side, float frame, float cframe);
+
+/* transform_convert_action.c */
+void createTransActionData(bContext *C, TransInfo *t);
+/* transform_convert_armature.c */
+struct bKinematicConstraint *has_targetless_ik(struct bPoseChannel *pchan);
+void createTransPose(TransInfo *t);
+void createTransArmatureVerts(TransInfo *t);
+/* transform_convert_cursor.c */
+void createTransCursor_image(TransInfo *t);
+void createTransCursor_view3d(TransInfo *t);
+/* transform_convert_curve.c */
+void createTransCurveVerts(TransInfo *t);
+/* transform_convert_graph.c */
+void createTransGraphEditData(bContext *C, TransInfo *t);
+/* transform_convert_gpencil.c */
+void createTransGPencil(bContext *C, TransInfo *t);
+/* transform_convert_lattice.c */
+void createTransLatticeVerts(TransInfo *t);
+/* transform_convert_mask.c */
+void createTransMaskingData(bContext *C, TransInfo *t);
+/* transform_convert_mball.c */
+void createTransMBallVerts(TransInfo *t);
+/* transform_convert_mesh.c */
+void createTransEditVerts(TransInfo *t);
+void createTransEdge(TransInfo *t);
+void createTransUVs(bContext *C, TransInfo *t);
+/* transform_convert_nla.c */
+void createTransNlaData(bContext *C, TransInfo *t);
+/* transform_convert_node.c */
+void createTransNodeData(bContext *UNUSED(C), TransInfo *t);
+/* transform_convert_object.c */
+void clear_trans_object_base_flags(TransInfo *t);
+void createTransObject(bContext *C, TransInfo *t);
+void createTransTexspace(TransInfo *t);
+/* transform_convert_paintcurve.c */
+void createTransPaintCurveVerts(bContext *C, TransInfo *t);
+/* transform_convert_particle.c */
+void createTransParticleVerts(bContext *C, TransInfo *t);
+/* transform_convert_sculpt.c */
+void createTransSculpt(TransInfo *t);
+/* transform_convert_sequence.c */
+void createTransSeqData(bContext *C, TransInfo *t);
+/* transform_convert_tracking.c */
+void createTransTrackingData(bContext *C, TransInfo *t);
+void cancelTransTracking(TransInfo *t);
+#endif
diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c
new file mode 100644
index 00000000000..0b1d2757435
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_action.c
@@ -0,0 +1,575 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_anim_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_mask_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_rect.h"
+
+#include "BKE_nla.h"
+#include "BKE_context.h"
+#include "BKE_report.h"
+
+#include "ED_anim_api.h"
+
+#include "UI_view2d.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* helper struct for gp-frame transforms */
+typedef struct tGPFtransdata {
+ float val; /* where transdata writes transform */
+ int *sdata; /* pointer to gpf->framenum */
+} tGPFtransdata;
+
+/* -------------------------------------------------------------------- */
+/** \name Action Transform Creation
+ *
+ * \{ */
+
+/* fully select selected beztriples, but only include if it's on the right side of cfra */
+static int count_fcurve_keys(FCurve *fcu, char side, float cfra, bool is_prop_edit)
+{
+ BezTriple *bezt;
+ int i, count = 0, count_all = 0;
+
+ if (ELEM(NULL, fcu, fcu->bezt)) {
+ return count;
+ }
+
+ /* only include points that occur on the right side of cfra */
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
+ /* no need to adjust the handle selection since they are assumed
+ * selected (like graph editor with SIPO_NOHANDLES) */
+ if (bezt->f2 & SELECT) {
+ count++;
+ }
+
+ count_all++;
+ }
+ }
+
+ if (is_prop_edit && count > 0) {
+ return count_all;
+ }
+ else {
+ return count;
+ }
+}
+
+/* fully select selected beztriples, but only include if it's on the right side of cfra */
+static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra, bool is_prop_edit)
+{
+ bGPDframe *gpf;
+ int count = 0, count_all = 0;
+
+ if (gpl == NULL) {
+ return count;
+ }
+
+ /* only include points that occur on the right side of cfra */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) {
+ if (gpf->flag & GP_FRAME_SELECT) {
+ count++;
+ }
+ count_all++;
+ }
+ }
+
+ if (is_prop_edit && count > 0) {
+ return count_all;
+ }
+ else {
+ return count;
+ }
+}
+
+/* fully select selected beztriples, but only include if it's on the right side of cfra */
+static int count_masklayer_frames(MaskLayer *masklay, char side, float cfra, bool is_prop_edit)
+{
+ MaskLayerShape *masklayer_shape;
+ int count = 0, count_all = 0;
+
+ if (masklay == NULL) {
+ return count;
+ }
+
+ /* only include points that occur on the right side of cfra */
+ for (masklayer_shape = masklay->splines_shapes.first; masklayer_shape;
+ masklayer_shape = masklayer_shape->next) {
+ if (FrameOnMouseSide(side, (float)masklayer_shape->frame, cfra)) {
+ if (masklayer_shape->flag & MASK_SHAPE_SELECT) {
+ count++;
+ }
+ count_all++;
+ }
+ }
+
+ if (is_prop_edit && count > 0) {
+ return count_all;
+ }
+ else {
+ return count;
+ }
+}
+
+/* This function assigns the information to transdata */
+static void TimeToTransData(TransData *td, float *time, AnimData *adt, float ypos)
+{
+ /* memory is calloc'ed, so that should zero everything nicely for us */
+ td->val = time;
+ td->ival = *(time);
+
+ td->center[0] = td->ival;
+ td->center[1] = ypos;
+
+ /* store the AnimData where this keyframe exists as a keyframe of the
+ * active action as td->extra.
+ */
+ td->extra = adt;
+}
+
+/* This function advances the address to which td points to, so it must return
+ * the new address so that the next time new transform data is added, it doesn't
+ * overwrite the existing ones... i.e. td = IcuToTransData(td, icu, ob, side, cfra);
+ *
+ * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
+ * on the named side are used.
+ */
+static TransData *ActionFCurveToTransData(TransData *td,
+ TransData2D **td2dv,
+ FCurve *fcu,
+ AnimData *adt,
+ char side,
+ float cfra,
+ bool is_prop_edit,
+ float ypos)
+{
+ BezTriple *bezt;
+ TransData2D *td2d = *td2dv;
+ int i;
+
+ if (ELEM(NULL, fcu, fcu->bezt)) {
+ return td;
+ }
+
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ /* only add selected keyframes (for now, proportional edit is not enabled) */
+ if (is_prop_edit || (bezt->f2 & SELECT)) { /* note this MUST match count_fcurve_keys(),
+ * so can't use BEZT_ISSEL_ANY() macro */
+ /* only add if on the right 'side' of the current frame */
+ if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
+ TimeToTransData(td, bezt->vec[1], adt, ypos);
+
+ if (bezt->f2 & SELECT) {
+ td->flag |= TD_SELECTED;
+ }
+
+ /*set flags to move handles as necessary*/
+ td->flag |= TD_MOVEHANDLE1 | TD_MOVEHANDLE2;
+ td2d->h1 = bezt->vec[0];
+ td2d->h2 = bezt->vec[2];
+
+ copy_v2_v2(td2d->ih1, td2d->h1);
+ copy_v2_v2(td2d->ih2, td2d->h2);
+
+ td++;
+ td2d++;
+ }
+ }
+ }
+
+ *td2dv = td2d;
+
+ return td;
+}
+
+/* This function advances the address to which td points to, so it must return
+ * the new address so that the next time new transform data is added, it doesn't
+ * overwrite the existing ones... i.e. td = GPLayerToTransData(td, ipo, ob, side, cfra);
+ *
+ * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
+ * on the named side are used.
+ */
+static int GPLayerToTransData(TransData *td,
+ tGPFtransdata *tfd,
+ bGPDlayer *gpl,
+ char side,
+ float cfra,
+ bool is_prop_edit,
+ float ypos)
+{
+ bGPDframe *gpf;
+ int count = 0;
+
+ /* check for select frames on right side of current frame */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (is_prop_edit || (gpf->flag & GP_FRAME_SELECT)) {
+ if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) {
+ /* memory is calloc'ed, so that should zero everything nicely for us */
+ td->val = &tfd->val;
+ td->ival = (float)gpf->framenum;
+
+ td->center[0] = td->ival;
+ td->center[1] = ypos;
+
+ tfd->val = (float)gpf->framenum;
+ tfd->sdata = &gpf->framenum;
+
+ /* advance td now */
+ td++;
+ tfd++;
+ count++;
+ }
+ }
+ }
+
+ return count;
+}
+
+/* refer to comment above #GPLayerToTransData, this is the same but for masks */
+static int MaskLayerToTransData(TransData *td,
+ tGPFtransdata *tfd,
+ MaskLayer *masklay,
+ char side,
+ float cfra,
+ bool is_prop_edit,
+ float ypos)
+{
+ MaskLayerShape *masklay_shape;
+ int count = 0;
+
+ /* check for select frames on right side of current frame */
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
+ masklay_shape = masklay_shape->next) {
+ if (is_prop_edit || (masklay_shape->flag & MASK_SHAPE_SELECT)) {
+ if (FrameOnMouseSide(side, (float)masklay_shape->frame, cfra)) {
+ /* memory is calloc'ed, so that should zero everything nicely for us */
+ td->val = &tfd->val;
+ td->ival = (float)masklay_shape->frame;
+
+ td->center[0] = td->ival;
+ td->center[1] = ypos;
+
+ tfd->val = (float)masklay_shape->frame;
+ tfd->sdata = &masklay_shape->frame;
+
+ /* advance td now */
+ td++;
+ tfd++;
+ count++;
+ }
+ }
+ }
+
+ return count;
+}
+
+void createTransActionData(bContext *C, TransInfo *t)
+{
+ Scene *scene = t->scene;
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ tGPFtransdata *tfd = NULL;
+
+ rcti *mask = &t->ar->v2d.mask;
+ rctf *datamask = &t->ar->v2d.cur;
+
+ float xsize = BLI_rctf_size_x(datamask);
+ float ysize = BLI_rctf_size_y(datamask);
+ float xmask = BLI_rcti_size_x(mask);
+ float ymask = BLI_rcti_size_y(mask);
+
+ bAnimContext ac;
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
+ int count = 0;
+ float cfra;
+ float ypos = 1.0f / ((ysize / xsize) * (xmask / ymask)) * BLI_rctf_cent_y(&t->ar->v2d.cur);
+
+ /* determine what type of data we are operating on */
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return;
+ }
+
+ /* filter data */
+ if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT);
+ }
+ else {
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
+ }
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* which side of the current frame should be allowed */
+ if (t->mode == TFM_TIME_EXTEND) {
+ /* only side on which mouse is gets transformed */
+ float xmouse, ymouse;
+
+ UI_view2d_region_to_view(&ac.ar->v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse);
+ t->frame_side = (xmouse > CFRA) ? 'R' : 'L'; // XXX use t->frame_side
+ }
+ else {
+ /* normal transform - both sides of current frame are considered */
+ t->frame_side = 'B';
+ }
+
+ /* loop 1: fully select ipo-keys and count how many BezTriples are selected */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ int adt_count = 0;
+ /* convert current-frame to action-time (slightly less accurate, especially under
+ * higher scaling ratios, but is faster than converting all points)
+ */
+ if (adt) {
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ }
+ else {
+ cfra = (float)CFRA;
+ }
+
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
+ adt_count = count_fcurve_keys(ale->key_data, t->frame_side, cfra, is_prop_edit);
+ }
+ else if (ale->type == ANIMTYPE_GPLAYER) {
+ adt_count = count_gplayer_frames(ale->data, t->frame_side, cfra, is_prop_edit);
+ }
+ else if (ale->type == ANIMTYPE_MASKLAYER) {
+ adt_count = count_masklayer_frames(ale->data, t->frame_side, cfra, is_prop_edit);
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ if (adt_count > 0) {
+ count += adt_count;
+ ale->tag = true;
+ }
+ }
+
+ /* stop if trying to build list if nothing selected */
+ if (count == 0) {
+ /* cleanup temp list */
+ ANIM_animdata_freelist(&anim_data);
+ return;
+ }
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* allocate memory for data */
+ tc->data_len = count;
+
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(Action Editor)");
+ tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "transdata2d");
+ td = tc->data;
+ td2d = tc->data_2d;
+
+ if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ tc->custom.type.data = tfd = MEM_callocN(sizeof(tGPFtransdata) * count, "tGPFtransdata");
+ tc->custom.type.use_free = true;
+ }
+
+ /* loop 2: build transdata array */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+
+ if (is_prop_edit && !ale->tag) {
+ continue;
+ }
+
+ cfra = (float)CFRA;
+
+ {
+ AnimData *adt;
+ adt = ANIM_nla_mapping_get(&ac, ale);
+ if (adt) {
+ cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
+ }
+ }
+
+ if (ale->type == ANIMTYPE_GPLAYER) {
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+ int i;
+
+ i = GPLayerToTransData(td, tfd, gpl, t->frame_side, cfra, is_prop_edit, ypos);
+ td += i;
+ tfd += i;
+ }
+ else if (ale->type == ANIMTYPE_MASKLAYER) {
+ MaskLayer *masklay = (MaskLayer *)ale->data;
+ int i;
+
+ i = MaskLayerToTransData(td, tfd, masklay, t->frame_side, cfra, is_prop_edit, ypos);
+ td += i;
+ tfd += i;
+ }
+ else {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ FCurve *fcu = (FCurve *)ale->key_data;
+
+ td = ActionFCurveToTransData(td, &td2d, fcu, adt, t->frame_side, cfra, is_prop_edit, ypos);
+ }
+ }
+
+ /* calculate distances for proportional editing */
+ if (is_prop_edit) {
+ td = tc->data;
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt;
+
+ /* F-Curve may not have any keyframes */
+ if (!ale->tag) {
+ continue;
+ }
+
+ adt = ANIM_nla_mapping_get(&ac, ale);
+ if (adt) {
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ }
+ else {
+ cfra = (float)CFRA;
+ }
+
+ if (ale->type == ANIMTYPE_GPLAYER) {
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+ bGPDframe *gpf;
+
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (gpf->flag & GP_FRAME_SELECT) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ bGPDframe *gpf_iter;
+ int min = INT_MAX;
+ for (gpf_iter = gpl->frames.first; gpf_iter; gpf_iter = gpf_iter->next) {
+ if (gpf_iter->flag & GP_FRAME_SELECT) {
+ if (FrameOnMouseSide(t->frame_side, (float)gpf_iter->framenum, cfra)) {
+ int val = abs(gpf->framenum - gpf_iter->framenum);
+ if (val < min) {
+ min = val;
+ }
+ }
+ }
+ }
+ td->dist = td->rdist = min;
+ }
+ td++;
+ }
+ }
+ else if (ale->type == ANIMTYPE_MASKLAYER) {
+ MaskLayer *masklay = (MaskLayer *)ale->data;
+ MaskLayerShape *masklay_shape;
+
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
+ masklay_shape = masklay_shape->next) {
+ if (FrameOnMouseSide(t->frame_side, (float)masklay_shape->frame, cfra)) {
+ if (masklay_shape->flag & MASK_SHAPE_SELECT) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ MaskLayerShape *masklay_iter;
+ int min = INT_MAX;
+ for (masklay_iter = masklay->splines_shapes.first; masklay_iter;
+ masklay_iter = masklay_iter->next) {
+ if (masklay_iter->flag & MASK_SHAPE_SELECT) {
+ if (FrameOnMouseSide(t->frame_side, (float)masklay_iter->frame, cfra)) {
+ int val = abs(masklay_shape->frame - masklay_iter->frame);
+ if (val < min) {
+ min = val;
+ }
+ }
+ }
+ }
+ td->dist = td->rdist = min;
+ }
+ td++;
+ }
+ }
+ }
+ else {
+ FCurve *fcu = (FCurve *)ale->key_data;
+ BezTriple *bezt;
+ int i;
+
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ if (bezt->f2 & SELECT) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ BezTriple *bezt_iter;
+ int j;
+ float min = FLT_MAX;
+ for (j = 0, bezt_iter = fcu->bezt; j < fcu->totvert; j++, bezt_iter++) {
+ if (bezt_iter->f2 & SELECT) {
+ if (FrameOnMouseSide(t->frame_side, (float)bezt_iter->vec[1][0], cfra)) {
+ float val = fabs(bezt->vec[1][0] - bezt_iter->vec[1][0]);
+ if (val < min) {
+ min = val;
+ }
+ }
+ }
+ }
+ td->dist = td->rdist = min;
+ }
+ td++;
+ }
+ }
+ }
+ }
+ }
+
+ /* cleanup temp list */
+ ANIM_animdata_freelist(&anim_data);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Action Transform Flush
+ *
+ * \{ */
+
+/* This function helps flush transdata written to tempdata into the gp-frames */
+void flushTransIntFrameActionData(TransInfo *t)
+{
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+ tGPFtransdata *tfd = tc->custom.type.data;
+
+ /* flush data! */
+ for (int i = 0; i < tc->data_len; i++, tfd++) {
+ *(tfd->sdata) = round_fl_to_int(tfd->val);
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
new file mode 100644
index 00000000000..cc023688c8e
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -0,0 +1,933 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+
+#include "BIK_api.h"
+
+#include "ED_armature.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan)
+{
+ bConstraint *con = pchan->constraints.first;
+
+ for (; con; con = con->next) {
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce != 0.0f)) {
+ bKinematicConstraint *data = con->data;
+
+ if (data->tar == NULL) {
+ return data;
+ }
+ if (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0) {
+ return data;
+ }
+ }
+ }
+ return NULL;
+}
+
+static void add_pose_transdata(
+ TransInfo *t, bPoseChannel *pchan, Object *ob, TransDataContainer *tc, TransData *td)
+{
+ Bone *bone = pchan->bone;
+ float pmat[3][3], omat[3][3];
+ float cmat[3][3], tmat[3][3];
+ float vec[3];
+
+ copy_v3_v3(vec, pchan->pose_mat[3]);
+ copy_v3_v3(td->center, vec);
+
+ td->ob = ob;
+ td->flag = TD_SELECTED;
+ if (bone->flag & BONE_HINGE_CHILD_TRANSFORM) {
+ td->flag |= TD_NOCENTER;
+ }
+
+ if (bone->flag & BONE_TRANSFORM_CHILD) {
+ td->flag |= TD_NOCENTER;
+ td->flag |= TD_NO_LOC;
+ }
+
+ td->protectflag = pchan->protectflag;
+
+ td->loc = pchan->loc;
+ copy_v3_v3(td->iloc, pchan->loc);
+
+ td->ext->size = pchan->size;
+ copy_v3_v3(td->ext->isize, pchan->size);
+
+ if (pchan->rotmode > 0) {
+ td->ext->rot = pchan->eul;
+ td->ext->rotAxis = NULL;
+ td->ext->rotAngle = NULL;
+ td->ext->quat = NULL;
+
+ copy_v3_v3(td->ext->irot, pchan->eul);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ td->ext->rot = NULL;
+ td->ext->rotAxis = pchan->rotAxis;
+ td->ext->rotAngle = &pchan->rotAngle;
+ td->ext->quat = NULL;
+
+ td->ext->irotAngle = pchan->rotAngle;
+ copy_v3_v3(td->ext->irotAxis, pchan->rotAxis);
+ }
+ else {
+ td->ext->rot = NULL;
+ td->ext->rotAxis = NULL;
+ td->ext->rotAngle = NULL;
+ td->ext->quat = pchan->quat;
+
+ copy_qt_qt(td->ext->iquat, pchan->quat);
+ }
+ td->ext->rotOrder = pchan->rotmode;
+
+ /* proper way to get parent transform + own transform + constraints transform */
+ copy_m3_m4(omat, ob->obmat);
+
+ /* New code, using "generic" BKE_bone_parent_transform_calc_from_pchan(). */
+ {
+ BoneParentTransform bpt;
+ float rpmat[3][3];
+
+ BKE_bone_parent_transform_calc_from_pchan(pchan, &bpt);
+ if (t->mode == TFM_TRANSLATION) {
+ copy_m3_m4(pmat, bpt.loc_mat);
+ }
+ else {
+ copy_m3_m4(pmat, bpt.rotscale_mat);
+ }
+
+ /* Grrr! Exceptional case: When translating pose bones that are either Hinge or NoLocal,
+ * and want align snapping, we just need both loc_mat and rotscale_mat.
+ * So simply always store rotscale mat in td->ext, and always use it to apply rotations...
+ * Ugly to need such hacks! :/ */
+ copy_m3_m4(rpmat, bpt.rotscale_mat);
+
+ if (constraints_list_needinv(t, &pchan->constraints)) {
+ copy_m3_m4(tmat, pchan->constinv);
+ invert_m3_m3(cmat, tmat);
+ mul_m3_series(td->mtx, cmat, omat, pmat);
+ mul_m3_series(td->ext->r_mtx, cmat, omat, rpmat);
+ }
+ else {
+ mul_m3_series(td->mtx, omat, pmat);
+ mul_m3_series(td->ext->r_mtx, omat, rpmat);
+ }
+ invert_m3_m3(td->ext->r_smtx, td->ext->r_mtx);
+ }
+
+ pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
+
+ /* exceptional case: rotate the pose bone which also applies transformation
+ * when a parentless bone has BONE_NO_LOCAL_LOCATION [] */
+ if (!ELEM(t->mode, TFM_TRANSLATION, TFM_RESIZE) &&
+ (pchan->bone->flag & BONE_NO_LOCAL_LOCATION)) {
+ if (pchan->parent) {
+ /* same as td->smtx but without pchan->bone->bone_mat */
+ td->flag |= TD_PBONE_LOCAL_MTX_C;
+ mul_m3_m3m3(td->ext->l_smtx, pchan->bone->bone_mat, td->smtx);
+ }
+ else {
+ td->flag |= TD_PBONE_LOCAL_MTX_P;
+ }
+ }
+
+ /* for axismat we use bone's own transform */
+ copy_m3_m4(pmat, pchan->pose_mat);
+ mul_m3_m3m3(td->axismtx, omat, pmat);
+ normalize_m3(td->axismtx);
+
+ if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
+ bArmature *arm = tc->poseobj->data;
+
+ if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
+ td->loc = NULL;
+ td->val = &bone->dist;
+ td->ival = bone->dist;
+ }
+ else {
+ // abusive storage of scale in the loc pointer :)
+ td->loc = &bone->xwidth;
+ copy_v3_v3(td->iloc, td->loc);
+ td->val = NULL;
+ }
+ }
+
+ /* in this case we can do target-less IK grabbing */
+ if (t->mode == TFM_TRANSLATION) {
+ bKinematicConstraint *data = has_targetless_ik(pchan);
+ if (data) {
+ if (data->flag & CONSTRAINT_IK_TIP) {
+ copy_v3_v3(data->grabtarget, pchan->pose_tail);
+ }
+ else {
+ copy_v3_v3(data->grabtarget, pchan->pose_head);
+ }
+ td->loc = data->grabtarget;
+ copy_v3_v3(td->iloc, td->loc);
+ data->flag |= CONSTRAINT_IK_AUTO;
+
+ /* only object matrix correction */
+ copy_m3_m3(td->mtx, omat);
+ pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
+ }
+ }
+
+ /* store reference to first constraint */
+ td->con = pchan->constraints.first;
+}
+
+/* adds the IK to pchan - returns if added */
+static short pose_grab_with_ik_add(bPoseChannel *pchan)
+{
+ bKinematicConstraint *targetless = NULL;
+ bKinematicConstraint *data;
+ bConstraint *con;
+
+ /* Sanity check */
+ if (pchan == NULL) {
+ return 0;
+ }
+
+ /* Rule: not if there's already an IK on this channel */
+ for (con = pchan->constraints.first; con; con = con->next) {
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
+ data = con->data;
+
+ if (data->tar == NULL || (data->tar->type == OB_ARMATURE && data->subtarget[0] == '\0')) {
+ /* make reference to constraint to base things off later
+ * (if it's the last targetless constraint encountered) */
+ targetless = (bKinematicConstraint *)con->data;
+
+ /* but, if this is a targetless IK, we make it auto anyway (for the children loop) */
+ if (con->enforce != 0.0f) {
+ data->flag |= CONSTRAINT_IK_AUTO;
+
+ /* if no chain length has been specified,
+ * just make things obey standard rotation locks too */
+ if (data->rootbone == 0) {
+ for (; pchan; pchan = pchan->parent) {
+ /* here, we set ik-settings for bone from pchan->protectflag */
+ // XXX: careful with quats/axis-angle rotations where we're locking 4d components
+ if (pchan->protectflag & OB_LOCK_ROTX) {
+ pchan->ikflag |= BONE_IK_NO_XDOF_TEMP;
+ }
+ if (pchan->protectflag & OB_LOCK_ROTY) {
+ pchan->ikflag |= BONE_IK_NO_YDOF_TEMP;
+ }
+ if (pchan->protectflag & OB_LOCK_ROTZ) {
+ pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP;
+ }
+ }
+ }
+
+ return 0;
+ }
+ }
+
+ if ((con->flag & CONSTRAINT_DISABLE) == 0 && (con->enforce != 0.0f)) {
+ return 0;
+ }
+ }
+ }
+
+ con = BKE_constraint_add_for_pose(NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC);
+
+ /* for draw, but also for detecting while pose solving */
+ pchan->constflag |= (PCHAN_HAS_IK | PCHAN_HAS_TARGET);
+
+ data = con->data;
+ if (targetless) {
+ /* if exists, use values from last targetless (but disabled) IK-constraint as base */
+ *data = *targetless;
+ }
+ else {
+ data->flag = CONSTRAINT_IK_TIP;
+ }
+ data->flag |= CONSTRAINT_IK_TEMP | CONSTRAINT_IK_AUTO | CONSTRAINT_IK_POS;
+ copy_v3_v3(data->grabtarget, pchan->pose_tail);
+
+ /* watch-it! has to be 0 here, since we're still on the
+ * same bone for the first time through the loop T25885. */
+ data->rootbone = 0;
+
+ /* we only include bones that are part of a continual connected chain */
+ do {
+ /* here, we set ik-settings for bone from pchan->protectflag */
+ // XXX: careful with quats/axis-angle rotations where we're locking 4d components
+ if (pchan->protectflag & OB_LOCK_ROTX) {
+ pchan->ikflag |= BONE_IK_NO_XDOF_TEMP;
+ }
+ if (pchan->protectflag & OB_LOCK_ROTY) {
+ pchan->ikflag |= BONE_IK_NO_YDOF_TEMP;
+ }
+ if (pchan->protectflag & OB_LOCK_ROTZ) {
+ pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP;
+ }
+
+ /* now we count this pchan as being included */
+ data->rootbone++;
+
+ /* continue to parent, but only if we're connected to it */
+ if (pchan->bone->flag & BONE_CONNECTED) {
+ pchan = pchan->parent;
+ }
+ else {
+ pchan = NULL;
+ }
+ } while (pchan);
+
+ /* make a copy of maximum chain-length */
+ data->max_rootbone = data->rootbone;
+
+ return 1;
+}
+
+/* bone is a candidate to get IK, but we don't do it if it has children connected */
+static short pose_grab_with_ik_children(bPose *pose, Bone *bone)
+{
+ Bone *bonec;
+ short wentdeeper = 0, added = 0;
+
+ /* go deeper if children & children are connected */
+ for (bonec = bone->childbase.first; bonec; bonec = bonec->next) {
+ if (bonec->flag & BONE_CONNECTED) {
+ wentdeeper = 1;
+ added += pose_grab_with_ik_children(pose, bonec);
+ }
+ }
+ if (wentdeeper == 0) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(pose, bone->name);
+ if (pchan) {
+ added += pose_grab_with_ik_add(pchan);
+ }
+ }
+
+ return added;
+}
+
+/* main call which adds temporal IK chains */
+static short pose_grab_with_ik(Main *bmain, Object *ob)
+{
+ bArmature *arm;
+ bPoseChannel *pchan, *parent;
+ Bone *bonec;
+ short tot_ik = 0;
+
+ if ((ob == NULL) || (ob->pose == NULL) || (ob->mode & OB_MODE_POSE) == 0) {
+ return 0;
+ }
+
+ arm = ob->data;
+
+ /* Rule: allow multiple Bones
+ * (but they must be selected, and only one ik-solver per chain should get added) */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone->layer & arm->layer) {
+ if (pchan->bone->flag & BONE_SELECTED) {
+ /* Rule: no IK for solitatry (unconnected) bones */
+ for (bonec = pchan->bone->childbase.first; bonec; bonec = bonec->next) {
+ if (bonec->flag & BONE_CONNECTED) {
+ break;
+ }
+ }
+ if ((pchan->bone->flag & BONE_CONNECTED) == 0 && (bonec == NULL)) {
+ continue;
+ }
+
+ /* rule: if selected Bone is not a root bone, it gets a temporal IK */
+ if (pchan->parent) {
+ /* only adds if there's no IK yet (and no parent bone was selected) */
+ for (parent = pchan->parent; parent; parent = parent->parent) {
+ if (parent->bone->flag & BONE_SELECTED) {
+ break;
+ }
+ }
+ if (parent == NULL) {
+ tot_ik += pose_grab_with_ik_add(pchan);
+ }
+ }
+ else {
+ /* rule: go over the children and add IK to the tips */
+ tot_ik += pose_grab_with_ik_children(ob->pose, pchan->bone);
+ }
+ }
+ }
+ }
+
+ /* iTaSC needs clear for new IK constraints */
+ if (tot_ik) {
+ BIK_clear_data(ob->pose);
+ /* TODO(sergey): Consider doing partial update only. */
+ DEG_relations_tag_update(bmain);
+ }
+
+ return (tot_ik) ? 1 : 0;
+}
+
+static void pose_mirror_info_init(PoseInitData_Mirror *pid,
+ bPoseChannel *pchan,
+ bPoseChannel *pchan_orig,
+ bool is_mirror_relative)
+{
+ pid->pchan = pchan;
+ copy_v3_v3(pid->orig.loc, pchan->loc);
+ copy_v3_v3(pid->orig.size, pchan->size);
+ pid->orig.curve_in_x = pchan->curve_in_x;
+ pid->orig.curve_out_x = pchan->curve_out_x;
+ pid->orig.roll1 = pchan->roll1;
+ pid->orig.roll2 = pchan->roll2;
+
+ if (pchan->rotmode > 0) {
+ copy_v3_v3(pid->orig.eul, pchan->eul);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ copy_v3_v3(pid->orig.axis_angle, pchan->rotAxis);
+ pid->orig.axis_angle[3] = pchan->rotAngle;
+ }
+ else {
+ copy_qt_qt(pid->orig.quat, pchan->quat);
+ }
+
+ if (is_mirror_relative) {
+ float pchan_mtx[4][4];
+ float pchan_mtx_mirror[4][4];
+
+ float flip_mtx[4][4];
+ unit_m4(flip_mtx);
+ flip_mtx[0][0] = -1;
+
+ BKE_pchan_to_mat4(pchan_orig, pchan_mtx_mirror);
+ BKE_pchan_to_mat4(pchan, pchan_mtx);
+
+ mul_m4_m4m4(pchan_mtx_mirror, pchan_mtx_mirror, flip_mtx);
+ mul_m4_m4m4(pchan_mtx_mirror, flip_mtx, pchan_mtx_mirror);
+
+ invert_m4(pchan_mtx_mirror);
+ mul_m4_m4m4(pid->offset_mtx, pchan_mtx, pchan_mtx_mirror);
+ }
+ else {
+ unit_m4(pid->offset_mtx);
+ }
+}
+
+static void pose_mirror_info_restore(const PoseInitData_Mirror *pid)
+{
+ bPoseChannel *pchan = pid->pchan;
+ copy_v3_v3(pchan->loc, pid->orig.loc);
+ copy_v3_v3(pchan->size, pid->orig.size);
+ pchan->curve_in_x = pid->orig.curve_in_x;
+ pchan->curve_out_x = pid->orig.curve_out_x;
+ pchan->roll1 = pid->orig.roll1;
+ pchan->roll2 = pid->orig.roll2;
+
+ if (pchan->rotmode > 0) {
+ copy_v3_v3(pchan->eul, pid->orig.eul);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ copy_v3_v3(pchan->rotAxis, pid->orig.axis_angle);
+ pchan->rotAngle = pid->orig.axis_angle[3];
+ }
+ else {
+ copy_qt_qt(pchan->quat, pid->orig.quat);
+ }
+}
+
+/**
+ * When objects array is NULL, use 't->data_container' as is.
+ */
+void createTransPose(TransInfo *t)
+{
+ Main *bmain = CTX_data_main(t->context);
+
+ t->data_len_all = 0;
+
+ bool has_translate_rotate_buf[2] = {false, false};
+ bool *has_translate_rotate = (t->mode == TFM_TRANSLATION) ? has_translate_rotate_buf : NULL;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Object *ob = tc->poseobj;
+ bPose *pose = ob->pose;
+
+ bArmature *arm;
+
+ /* check validity of state */
+ arm = BKE_armature_from_object(tc->poseobj);
+ if ((arm == NULL) || (pose == NULL)) {
+ continue;
+ }
+
+ const bool mirror = ((pose->flag & POSE_MIRROR_EDIT) != 0);
+
+ /* set flags and count total */
+ tc->data_len = count_set_pose_transflags(ob, t->mode, t->around, has_translate_rotate);
+ if (tc->data_len == 0) {
+ continue;
+ }
+
+ if (arm->flag & ARM_RESTPOS) {
+ if (ELEM(t->mode, TFM_DUMMY, TFM_BONESIZE) == 0) {
+ BKE_report(t->reports, RPT_ERROR, "Cannot change Pose when 'Rest Position' is enabled");
+ tc->data_len = 0;
+ continue;
+ }
+ }
+
+ /* do we need to add temporal IK chains? */
+ if ((pose->flag & POSE_AUTO_IK) && t->mode == TFM_TRANSLATION) {
+ if (pose_grab_with_ik(bmain, ob)) {
+ t->flag |= T_AUTOIK;
+ has_translate_rotate[0] = true;
+ }
+ }
+
+ if (mirror) {
+ int total_mirrored = 0;
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if ((pchan->bone->flag & BONE_TRANSFORM) &&
+ BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) {
+ total_mirrored++;
+ }
+ }
+
+ PoseInitData_Mirror *pid = MEM_mallocN((total_mirrored + 1) * sizeof(PoseInitData_Mirror),
+ "PoseInitData_Mirror");
+
+ /* Trick to terminate iteration. */
+ pid[total_mirrored].pchan = NULL;
+
+ tc->custom.type.data = pid;
+ tc->custom.type.use_free = true;
+ }
+ }
+
+ /* if there are no translatable bones, do rotation */
+ if ((t->mode == TFM_TRANSLATION) && !has_translate_rotate[0]) {
+ if (has_translate_rotate[1]) {
+ t->mode = TFM_ROTATION;
+ }
+ else {
+ t->mode = TFM_RESIZE;
+ }
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (tc->data_len == 0) {
+ continue;
+ }
+ Object *ob = tc->poseobj;
+ TransData *td;
+ TransDataExtension *tdx;
+ int i;
+
+ PoseInitData_Mirror *pid = tc->custom.type.data;
+ int pid_index = 0;
+ bPose *pose = ob->pose;
+
+ if (pose == NULL) {
+ continue;
+ }
+
+ const bool mirror = ((pose->flag & POSE_MIRROR_EDIT) != 0);
+ const bool is_mirror_relative = ((pose->flag & POSE_MIRROR_RELATIVE) != 0);
+
+ tc->poseobj = ob; /* we also allow non-active objects to be transformed, in weightpaint */
+
+ /* init trans data */
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransPoseBone");
+ tdx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension),
+ "TransPoseBoneExt");
+ for (i = 0; i < tc->data_len; i++, td++, tdx++) {
+ td->ext = tdx;
+ td->val = NULL;
+ }
+
+ /* use pose channels to fill trans data */
+ td = tc->data;
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone->flag & BONE_TRANSFORM) {
+ add_pose_transdata(t, pchan, ob, tc, td);
+
+ if (mirror) {
+ bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name);
+ if (pchan_mirror) {
+ pose_mirror_info_init(&pid[pid_index], pchan_mirror, pchan, is_mirror_relative);
+ pid_index++;
+ }
+ }
+
+ td++;
+ }
+ }
+
+ if (td != (tc->data + tc->data_len)) {
+ BKE_report(t->reports, RPT_DEBUG, "Bone selection count error");
+ }
+
+ /* initialize initial auto=ik chainlen's? */
+ if (t->flag & T_AUTOIK) {
+ transform_autoik_update(t, 0);
+ }
+ }
+
+ t->flag |= T_POSE;
+ /* disable PET, its not usable in pose mode yet [#32444] */
+ t->flag &= ~T_PROP_EDIT_ALL;
+}
+
+void restoreMirrorPoseBones(TransDataContainer *tc)
+{
+ bPose *pose = tc->poseobj->pose;
+
+ if (!(pose->flag & POSE_MIRROR_EDIT)) {
+ return;
+ }
+
+ for (PoseInitData_Mirror *pid = tc->custom.type.data; pid->pchan; pid++) {
+ pose_mirror_info_restore(pid);
+ }
+}
+
+void restoreBones(TransDataContainer *tc)
+{
+ bArmature *arm;
+ BoneInitData *bid = tc->custom.type.data;
+ EditBone *ebo;
+
+ if (tc->obedit) {
+ arm = tc->obedit->data;
+ }
+ else {
+ BLI_assert(tc->poseobj != NULL);
+ arm = tc->poseobj->data;
+ }
+
+ while (bid->bone) {
+ ebo = bid->bone;
+
+ ebo->dist = bid->dist;
+ ebo->rad_head = bid->rad_head;
+ ebo->rad_tail = bid->rad_tail;
+ ebo->roll = bid->roll;
+ ebo->xwidth = bid->xwidth;
+ ebo->zwidth = bid->zwidth;
+ copy_v3_v3(ebo->head, bid->head);
+ copy_v3_v3(ebo->tail, bid->tail);
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ EditBone *ebo_child;
+
+ /* Also move connected ebo_child, in case ebo_child's name aren't mirrored properly */
+ for (ebo_child = arm->edbo->first; ebo_child; ebo_child = ebo_child->next) {
+ if ((ebo_child->flag & BONE_CONNECTED) && (ebo_child->parent == ebo)) {
+ copy_v3_v3(ebo_child->head, ebo->tail);
+ ebo_child->rad_head = ebo->rad_tail;
+ }
+ }
+
+ /* Also move connected parent, in case parent's name isn't mirrored properly */
+ if ((ebo->flag & BONE_CONNECTED) && ebo->parent) {
+ EditBone *parent = ebo->parent;
+ copy_v3_v3(parent->tail, ebo->head);
+ parent->rad_tail = ebo->rad_head;
+ }
+ }
+
+ bid++;
+ }
+}
+
+/* ********************* armature ************** */
+void createTransArmatureVerts(TransInfo *t)
+{
+ t->data_len_all = 0;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ EditBone *ebo, *eboflip;
+ bArmature *arm = tc->obedit->data;
+ ListBase *edbo = arm->edbo;
+ bool mirror = ((arm->flag & ARM_MIRROR_EDIT) != 0);
+ int total_mirrored = 0;
+
+ tc->data_len = 0;
+ for (ebo = edbo->first; ebo; ebo = ebo->next) {
+ const int data_len_prev = tc->data_len;
+
+ if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
+ if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
+ if (ebo->flag & BONE_SELECTED) {
+ tc->data_len++;
+ }
+ }
+ else if (t->mode == TFM_BONE_ROLL) {
+ if (ebo->flag & BONE_SELECTED) {
+ tc->data_len++;
+ }
+ }
+ else {
+ if (ebo->flag & BONE_TIPSEL) {
+ tc->data_len++;
+ }
+ if (ebo->flag & BONE_ROOTSEL) {
+ tc->data_len++;
+ }
+ }
+ }
+
+ if (mirror && (data_len_prev < tc->data_len)) {
+ eboflip = ED_armature_ebone_get_mirrored(arm->edbo, ebo);
+ if (eboflip) {
+ total_mirrored++;
+ }
+ }
+ }
+ if (!tc->data_len) {
+ continue;
+ }
+
+ if (mirror) {
+ BoneInitData *bid = MEM_mallocN((total_mirrored + 1) * sizeof(BoneInitData), "BoneInitData");
+
+ /* trick to terminate iteration */
+ bid[total_mirrored].bone = NULL;
+
+ tc->custom.type.data = bid;
+ tc->custom.type.use_free = true;
+ }
+ t->data_len_all += tc->data_len;
+ }
+
+ transform_around_single_fallback(t);
+ t->data_len_all = -1;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (!tc->data_len) {
+ continue;
+ }
+
+ EditBone *ebo, *eboflip;
+ bArmature *arm = tc->obedit->data;
+ ListBase *edbo = arm->edbo;
+ TransData *td, *td_old;
+ float mtx[3][3], smtx[3][3], bonemat[3][3];
+ bool mirror = ((arm->flag & ARM_MIRROR_EDIT) != 0);
+ BoneInitData *bid = tc->custom.type.data;
+
+ copy_m3_m4(mtx, tc->obedit->obmat);
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransEditBone");
+ int i = 0;
+
+ for (ebo = edbo->first; ebo; ebo = ebo->next) {
+ td_old = td;
+ ebo->oldlength =
+ ebo->length; // length==0.0 on extrude, used for scaling radius of bone points
+
+ if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
+ if (t->mode == TFM_BONE_ENVELOPE) {
+ if (ebo->flag & BONE_ROOTSEL) {
+ td->val = &ebo->rad_head;
+ td->ival = *td->val;
+
+ copy_v3_v3(td->center, ebo->head);
+ td->flag = TD_SELECTED;
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+
+ td->loc = NULL;
+ td->ext = NULL;
+ td->ob = tc->obedit;
+
+ td++;
+ }
+ if (ebo->flag & BONE_TIPSEL) {
+ td->val = &ebo->rad_tail;
+ td->ival = *td->val;
+ copy_v3_v3(td->center, ebo->tail);
+ td->flag = TD_SELECTED;
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+
+ td->loc = NULL;
+ td->ext = NULL;
+ td->ob = tc->obedit;
+
+ td++;
+ }
+ }
+ else if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
+ if (ebo->flag & BONE_SELECTED) {
+ if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
+ td->loc = NULL;
+ td->val = &ebo->dist;
+ td->ival = ebo->dist;
+ }
+ else {
+ // abusive storage of scale in the loc pointer :)
+ td->loc = &ebo->xwidth;
+ copy_v3_v3(td->iloc, td->loc);
+ td->val = NULL;
+ }
+ copy_v3_v3(td->center, ebo->head);
+ td->flag = TD_SELECTED;
+
+ /* use local bone matrix */
+ ED_armature_ebone_to_mat3(ebo, bonemat);
+ mul_m3_m3m3(td->mtx, mtx, bonemat);
+ invert_m3_m3(td->smtx, td->mtx);
+
+ copy_m3_m3(td->axismtx, td->mtx);
+ normalize_m3(td->axismtx);
+
+ td->ext = NULL;
+ td->ob = tc->obedit;
+
+ td++;
+ }
+ }
+ else if (t->mode == TFM_BONE_ROLL) {
+ if (ebo->flag & BONE_SELECTED) {
+ td->loc = NULL;
+ td->val = &(ebo->roll);
+ td->ival = ebo->roll;
+
+ copy_v3_v3(td->center, ebo->head);
+ td->flag = TD_SELECTED;
+
+ td->ext = NULL;
+ td->ob = tc->obedit;
+
+ td++;
+ }
+ }
+ else {
+ if (ebo->flag & BONE_TIPSEL) {
+ copy_v3_v3(td->iloc, ebo->tail);
+
+ /* Don't allow single selected tips to have a modified center,
+ * causes problem with snapping (see T45974).
+ * However, in rotation mode, we want to keep that 'rotate bone around root with
+ * only its tip selected' behavior (see T46325). */
+ if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ ((t->mode == TFM_ROTATION) || (ebo->flag & BONE_ROOTSEL))) {
+ copy_v3_v3(td->center, ebo->head);
+ }
+ else {
+ copy_v3_v3(td->center, td->iloc);
+ }
+
+ td->loc = ebo->tail;
+ td->flag = TD_SELECTED;
+ if (ebo->flag & BONE_EDITMODE_LOCKED) {
+ td->protectflag = OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE;
+ }
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+
+ ED_armature_ebone_to_mat3(ebo, td->axismtx);
+
+ if ((ebo->flag & BONE_ROOTSEL) == 0) {
+ td->extra = ebo;
+ td->ival = ebo->roll;
+ }
+
+ td->ext = NULL;
+ td->val = NULL;
+ td->ob = tc->obedit;
+
+ td++;
+ }
+ if (ebo->flag & BONE_ROOTSEL) {
+ copy_v3_v3(td->iloc, ebo->head);
+ copy_v3_v3(td->center, td->iloc);
+ td->loc = ebo->head;
+ td->flag = TD_SELECTED;
+ if (ebo->flag & BONE_EDITMODE_LOCKED) {
+ td->protectflag = OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE;
+ }
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+
+ ED_armature_ebone_to_mat3(ebo, td->axismtx);
+
+ td->extra = ebo; /* to fix roll */
+ td->ival = ebo->roll;
+
+ td->ext = NULL;
+ td->val = NULL;
+ td->ob = tc->obedit;
+
+ td++;
+ }
+ }
+ }
+
+ if (mirror && (td_old != td)) {
+ eboflip = ED_armature_ebone_get_mirrored(arm->edbo, ebo);
+ if (eboflip) {
+ bid[i].bone = eboflip;
+ bid[i].dist = eboflip->dist;
+ bid[i].rad_head = eboflip->rad_head;
+ bid[i].rad_tail = eboflip->rad_tail;
+ bid[i].roll = eboflip->roll;
+ bid[i].xwidth = eboflip->xwidth;
+ bid[i].zwidth = eboflip->zwidth;
+ copy_v3_v3(bid[i].head, eboflip->head);
+ copy_v3_v3(bid[i].tail, eboflip->tail);
+ i++;
+ }
+ }
+ }
+
+ if (mirror) {
+ /* trick to terminate iteration */
+ BLI_assert(i + 1 == (MEM_allocN_len(bid) / sizeof(*bid)));
+ bid[i].bone = NULL;
+ }
+ }
+}
diff --git a/source/blender/editors/transform/transform_convert_cursor.c b/source/blender/editors/transform/transform_convert_cursor.c
new file mode 100644
index 00000000000..621f9dd63e2
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_cursor.c
@@ -0,0 +1,129 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Cursor Transform Creation
+ *
+ * Instead of transforming the selection, move the 2D/3D cursor.
+ *
+ * \{ */
+
+void createTransCursor_image(TransInfo *t)
+{
+ TransData *td;
+ SpaceImage *sima = t->sa->spacedata.first;
+ float *cursor_location = sima->cursor;
+
+ {
+ BLI_assert(t->data_container_len == 1);
+ TransDataContainer *tc = t->data_container;
+ tc->data_len = 1;
+ td = tc->data = MEM_callocN(sizeof(TransData), "TransTexspace");
+ td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
+ }
+
+ td->flag = TD_SELECTED;
+ copy_v3_v3(td->center, cursor_location);
+ td->ob = NULL;
+
+ unit_m3(td->mtx);
+ unit_m3(td->axismtx);
+ pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
+
+ td->loc = cursor_location;
+ copy_v3_v3(td->iloc, cursor_location);
+}
+
+void createTransCursor_view3d(TransInfo *t)
+{
+ TransData *td;
+
+ Scene *scene = t->scene;
+ if (ID_IS_LINKED(scene)) {
+ BKE_report(t->reports, RPT_ERROR, "Linked data can't text-space transform");
+ return;
+ }
+
+ View3DCursor *cursor = &scene->cursor;
+ {
+ BLI_assert(t->data_container_len == 1);
+ TransDataContainer *tc = t->data_container;
+ tc->data_len = 1;
+ td = tc->data = MEM_callocN(sizeof(TransData), "TransTexspace");
+ td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
+ }
+
+ td->flag = TD_SELECTED;
+ copy_v3_v3(td->center, cursor->location);
+ td->ob = NULL;
+
+ unit_m3(td->mtx);
+ BKE_scene_cursor_rot_to_mat3(cursor, td->axismtx);
+ normalize_m3(td->axismtx);
+ pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
+
+ td->loc = cursor->location;
+ copy_v3_v3(td->iloc, cursor->location);
+
+ if (cursor->rotation_mode > 0) {
+ td->ext->rot = cursor->rotation_euler;
+ td->ext->rotAxis = NULL;
+ td->ext->rotAngle = NULL;
+ td->ext->quat = NULL;
+
+ copy_v3_v3(td->ext->irot, cursor->rotation_euler);
+ }
+ else if (cursor->rotation_mode == ROT_MODE_AXISANGLE) {
+ td->ext->rot = NULL;
+ td->ext->rotAxis = cursor->rotation_axis;
+ td->ext->rotAngle = &cursor->rotation_angle;
+ td->ext->quat = NULL;
+
+ td->ext->irotAngle = cursor->rotation_angle;
+ copy_v3_v3(td->ext->irotAxis, cursor->rotation_axis);
+ }
+ else {
+ td->ext->rot = NULL;
+ td->ext->rotAxis = NULL;
+ td->ext->rotAngle = NULL;
+ td->ext->quat = cursor->rotation_quaternion;
+
+ copy_qt_qt(td->ext->iquat, cursor->rotation_quaternion);
+ }
+ td->ext->rotOrder = cursor->rotation_mode;
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c
new file mode 100644
index 00000000000..487de27aff2
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_curve.c
@@ -0,0 +1,422 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_curve_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_curve.h"
+#include "BKE_report.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Curve/Surfaces Transform Creation
+ *
+ * \{ */
+
+/**
+ * For the purpose of transform code we need to behave as if handles are selected,
+ * even when they aren't (see special case below).
+ */
+static int bezt_select_to_transform_triple_flag(const BezTriple *bezt, const bool hide_handles)
+{
+ int flag = 0;
+
+ if (hide_handles) {
+ if (bezt->f2 & SELECT) {
+ flag = (1 << 0) | (1 << 1) | (1 << 2);
+ }
+ }
+ else {
+ flag = (((bezt->f1 & SELECT) ? (1 << 0) : 0) | ((bezt->f2 & SELECT) ? (1 << 1) : 0) |
+ ((bezt->f3 & SELECT) ? (1 << 2) : 0));
+ }
+
+ /* Special case for auto & aligned handles:
+ * When a center point is being moved without the handles,
+ * leaving the handles stationary makes no sense and only causes strange behavior,
+ * where one handle is arbitrarily anchored, the other one is aligned and lengthened
+ * based on where the center point is moved. Also a bug when cancelling, see: T52007.
+ *
+ * A more 'correct' solution could be to store handle locations in 'TransDataCurveHandleFlags'.
+ * However that doesn't resolve odd behavior, so best transform the handles in this case.
+ */
+ if ((flag != ((1 << 0) | (1 << 1) | (1 << 2))) && (flag & (1 << 1))) {
+ if (ELEM(bezt->h1, HD_AUTO, HD_ALIGN) && ELEM(bezt->h2, HD_AUTO, HD_ALIGN)) {
+ flag = (1 << 0) | (1 << 1) | (1 << 2);
+ }
+ }
+
+ return flag;
+}
+
+void createTransCurveVerts(TransInfo *t)
+{
+
+#define SEL_F1 (1 << 0)
+#define SEL_F2 (1 << 1)
+#define SEL_F3 (1 << 2)
+
+ t->data_len_all = 0;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Curve *cu = tc->obedit->data;
+ BLI_assert(cu->editnurb != NULL);
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+ int count = 0, countsel = 0;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ View3D *v3d = t->view;
+ short hide_handles = (v3d != NULL) ?
+ ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) :
+ false;
+
+ /* count total of vertices, check identical as in 2nd loop for making transdata! */
+ ListBase *nurbs = BKE_curve_editNurbs_get(cu);
+ for (Nurb *nu = nurbs->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
+ if (bezt->hide == 0) {
+ const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
+ if (bezt_tx & SEL_F1) {
+ countsel++;
+ }
+ if (bezt_tx & SEL_F2) {
+ countsel++;
+ }
+ if (bezt_tx & SEL_F3) {
+ countsel++;
+ }
+ if (is_prop_edit) {
+ count += 3;
+ }
+ }
+ }
+ }
+ else {
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
+ if (bp->hide == 0) {
+ if (is_prop_edit) {
+ count++;
+ }
+ if (bp->f1 & SELECT) {
+ countsel++;
+ }
+ }
+ }
+ }
+ }
+ /* note: in prop mode we need at least 1 selected */
+ if (countsel == 0) {
+ tc->data_len = 0;
+ continue;
+ }
+
+ if (is_prop_edit) {
+ tc->data_len = count;
+ }
+ else {
+ tc->data_len = countsel;
+ }
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Curve EditMode)");
+
+ t->data_len_all += tc->data_len;
+ }
+
+ transform_around_single_fallback(t);
+ t->data_len_all = -1;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (tc->data_len == 0) {
+ continue;
+ }
+
+ Curve *cu = tc->obedit->data;
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ View3D *v3d = t->view;
+ short hide_handles = (v3d != NULL) ?
+ ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) :
+ false;
+
+ float mtx[3][3], smtx[3][3];
+
+ copy_m3_m4(mtx, tc->obedit->obmat);
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+
+ TransData *td = tc->data;
+ ListBase *nurbs = BKE_curve_editNurbs_get(cu);
+ for (Nurb *nu = nurbs->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ TransData *head, *tail;
+ head = tail = td;
+ for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
+ if (bezt->hide == 0) {
+ TransDataCurveHandleFlags *hdata = NULL;
+ float axismtx[3][3];
+
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ float normal[3], plane[3];
+
+ BKE_nurb_bezt_calc_normal(nu, bezt, normal);
+ BKE_nurb_bezt_calc_plane(nu, bezt, plane);
+
+ if (createSpaceNormalTangent(axismtx, normal, plane)) {
+ /* pass */
+ }
+ else {
+ normalize_v3(normal);
+ axis_dominant_v3_to_m3(axismtx, normal);
+ invert_m3(axismtx);
+ }
+ }
+
+ /* Elements that will be transform (not always a match to selection). */
+ const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
+
+ if (is_prop_edit || bezt_tx & SEL_F1) {
+ copy_v3_v3(td->iloc, bezt->vec[0]);
+ td->loc = bezt->vec[0];
+ copy_v3_v3(td->center,
+ bezt->vec[(hide_handles || (t->around == V3D_AROUND_LOCAL_ORIGINS) ||
+ (bezt->f2 & SELECT)) ?
+ 1 :
+ 0]);
+ if (hide_handles) {
+ if (bezt->f2 & SELECT) {
+ td->flag = TD_SELECTED;
+ }
+ else {
+ td->flag = 0;
+ }
+ }
+ else {
+ if (bezt->f1 & SELECT) {
+ td->flag = TD_SELECTED;
+ }
+ else {
+ td->flag = 0;
+ }
+ }
+ td->ext = NULL;
+ td->val = NULL;
+
+ hdata = initTransDataCurveHandles(td, bezt);
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ copy_m3_m3(td->axismtx, axismtx);
+ }
+
+ td++;
+ tail++;
+ }
+
+ /* This is the Curve Point, the other two are handles */
+ if (is_prop_edit || bezt_tx & SEL_F2) {
+ copy_v3_v3(td->iloc, bezt->vec[1]);
+ td->loc = bezt->vec[1];
+ copy_v3_v3(td->center, td->loc);
+ if (bezt->f2 & SELECT) {
+ td->flag = TD_SELECTED;
+ }
+ else {
+ td->flag = 0;
+ }
+ td->ext = NULL;
+
+ /* TODO - make points scale */
+ if (t->mode == TFM_CURVE_SHRINKFATTEN) { /* || t->mode==TFM_RESIZE) {*/
+ td->val = &(bezt->radius);
+ td->ival = bezt->radius;
+ }
+ else if (t->mode == TFM_TILT) {
+ td->val = &(bezt->tilt);
+ td->ival = bezt->tilt;
+ }
+ else {
+ td->val = NULL;
+ }
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ copy_m3_m3(td->axismtx, axismtx);
+ }
+
+ if ((bezt_tx & SEL_F1) == 0 && (bezt_tx & SEL_F3) == 0) {
+ /* If the middle is selected but the sides arnt, this is needed */
+ if (hdata == NULL) {
+ /* if the handle was not saved by the previous handle */
+ hdata = initTransDataCurveHandles(td, bezt);
+ }
+ }
+
+ td++;
+ tail++;
+ }
+ if (is_prop_edit || bezt_tx & SEL_F3) {
+ copy_v3_v3(td->iloc, bezt->vec[2]);
+ td->loc = bezt->vec[2];
+ copy_v3_v3(td->center,
+ bezt->vec[(hide_handles || (t->around == V3D_AROUND_LOCAL_ORIGINS) ||
+ (bezt->f2 & SELECT)) ?
+ 1 :
+ 2]);
+ if (hide_handles) {
+ if (bezt->f2 & SELECT) {
+ td->flag = TD_SELECTED;
+ }
+ else {
+ td->flag = 0;
+ }
+ }
+ else {
+ if (bezt->f3 & SELECT) {
+ td->flag = TD_SELECTED;
+ }
+ else {
+ td->flag = 0;
+ }
+ }
+ td->ext = NULL;
+ td->val = NULL;
+
+ if (hdata == NULL) {
+ /* if the handle was not saved by the previous handle */
+ hdata = initTransDataCurveHandles(td, bezt);
+ }
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ copy_m3_m3(td->axismtx, axismtx);
+ }
+
+ td++;
+ tail++;
+ }
+
+ (void)hdata; /* quiet warning */
+ }
+ else if (is_prop_edit && head != tail) {
+ calc_distanceCurveVerts(head, tail - 1);
+ head = tail;
+ }
+ }
+ if (is_prop_edit && head != tail) {
+ calc_distanceCurveVerts(head, tail - 1);
+ }
+
+ /* TODO - in the case of tilt and radius we can also avoid allocating the
+ * initTransDataCurveHandles but for now just don't change handle types */
+ if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT, TFM_DUMMY) == 0) {
+ /* sets the handles based on their selection,
+ * do this after the data is copied to the TransData */
+ BKE_nurb_handles_test(nu, !hide_handles);
+ }
+ }
+ else {
+ TransData *head, *tail;
+ head = tail = td;
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
+ if (bp->hide == 0) {
+ if (is_prop_edit || (bp->f1 & SELECT)) {
+ float axismtx[3][3];
+
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ if (nu->pntsv == 1) {
+ float normal[3], plane[3];
+
+ BKE_nurb_bpoint_calc_normal(nu, bp, normal);
+ BKE_nurb_bpoint_calc_plane(nu, bp, plane);
+
+ if (createSpaceNormalTangent(axismtx, normal, plane)) {
+ /* pass */
+ }
+ else {
+ normalize_v3(normal);
+ axis_dominant_v3_to_m3(axismtx, normal);
+ invert_m3(axismtx);
+ }
+ }
+ }
+
+ copy_v3_v3(td->iloc, bp->vec);
+ td->loc = bp->vec;
+ copy_v3_v3(td->center, td->loc);
+ if (bp->f1 & SELECT) {
+ td->flag = TD_SELECTED;
+ }
+ else {
+ td->flag = 0;
+ }
+ td->ext = NULL;
+
+ if (t->mode == TFM_CURVE_SHRINKFATTEN || t->mode == TFM_RESIZE) {
+ td->val = &(bp->radius);
+ td->ival = bp->radius;
+ }
+ else {
+ td->val = &(bp->tilt);
+ td->ival = bp->tilt;
+ }
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ if (nu->pntsv == 1) {
+ copy_m3_m3(td->axismtx, axismtx);
+ }
+ }
+
+ td++;
+ tail++;
+ }
+ }
+ else if (is_prop_edit && head != tail) {
+ calc_distanceCurveVerts(head, tail - 1);
+ head = tail;
+ }
+ }
+ if (is_prop_edit && head != tail) {
+ calc_distanceCurveVerts(head, tail - 1);
+ }
+ }
+ }
+ }
+#undef SEL_F1
+#undef SEL_F2
+#undef SEL_F3
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c
new file mode 100644
index 00000000000..234e383be5f
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_gpencil.c
@@ -0,0 +1,371 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_gpencil_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_report.h"
+
+#include "ED_gpencil.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Gpencil Transform Creation
+ *
+ * \{ */
+
+static void createTransGPencil_center_get(bGPDstroke *gps, float r_center[3])
+{
+ bGPDspoint *pt;
+ int i;
+
+ zero_v3(r_center);
+ int tot_sel = 0;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ add_v3_v3(r_center, &pt->x);
+ tot_sel++;
+ }
+ }
+
+ if (tot_sel > 0) {
+ mul_v3_fl(r_center, 1.0f / tot_sel);
+ }
+}
+
+void createTransGPencil(bContext *C, TransInfo *t)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ bool use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) != 0;
+
+ Object *obact = CTX_data_active_object(C);
+ bGPDlayer *gpl;
+ TransData *td = NULL;
+ float mtx[3][3], smtx[3][3];
+
+ const Scene *scene = CTX_data_scene(C);
+ const int cfra_scene = CFRA;
+
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* == Grease Pencil Strokes to Transform Data ==
+ * Grease Pencil stroke points can be a mixture of 2D (screen-space),
+ * or 3D coordinates. However, they're always saved as 3D points.
+ * For now, we just do these without creating TransData2D for the 2D
+ * strokes. This may cause issues in future though.
+ */
+ tc->data_len = 0;
+
+ if (gpd == NULL) {
+ return;
+ }
+
+ /* initialize falloff curve */
+ if (is_multiedit) {
+ BKE_curvemapping_initialize(ts->gp_sculpt.cur_falloff);
+ }
+
+ /* First Pass: Count the number of data-points required for the strokes,
+ * (and additional info about the configuration - e.g. 2D/3D?).
+ */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ bGPDframe *gpf;
+ bGPDstroke *gps;
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ continue;
+ }
+
+ if (is_prop_edit) {
+ /* Proportional Editing... */
+ if (is_prop_edit_connected) {
+ /* connected only - so only if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ tc->data_len += gps->totpoints;
+ }
+ }
+ else {
+ /* everything goes - connection status doesn't matter */
+ tc->data_len += gps->totpoints;
+ }
+ }
+ else {
+ /* only selected stroke points are considered */
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+
+ // TODO: 2D vs 3D?
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ tc->data_len++;
+ }
+ }
+ }
+ }
+ }
+ }
+ /* if not multiedit out of loop */
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ }
+
+ /* Stop trying if nothing selected */
+ if (tc->data_len == 0) {
+ return;
+ }
+
+ /* Allocate memory for data */
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(GPencil)");
+ td = tc->data;
+
+ unit_m3(smtx);
+ unit_m3(mtx);
+
+ /* Second Pass: Build transdata array */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene;
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps;
+ float diff_mat[4][4];
+ float inverse_diff_mat[4][4];
+
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+ /* init multiframe falloff options */
+ int f_init = 0;
+ int f_end = 0;
+
+ if (use_multiframe_falloff) {
+ BKE_gpencil_get_range_selected(gpl, &f_init, &f_end);
+ }
+
+ /* calculate difference matrix */
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ /* undo matrix */
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+
+ /* Make a new frame to work on if the layer's frame
+ * and the current scene frame don't match up.
+ *
+ * - This is useful when animating as it saves that "uh-oh" moment when you realize you've
+ * spent too much time editing the wrong frame...
+ */
+ // XXX: should this be allowed when framelock is enabled?
+ if ((gpf->framenum != cfra) && (!is_multiedit)) {
+ gpf = BKE_gpencil_frame_addcopy(gpl, cfra);
+ /* in some weird situations (framelock enabled) return NULL */
+ if (gpf == NULL) {
+ continue;
+ }
+ if (!is_multiedit) {
+ init_gpf = gpf;
+ }
+ }
+
+ /* Loop over strokes, adding TransData for points as needed... */
+ for (gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+
+ /* if multiframe and falloff, recalculate and save value */
+ float falloff = 1.0f; /* by default no falloff */
+ if ((is_multiedit) && (use_multiframe_falloff)) {
+ /* Faloff depends on distance to active frame (relative to the overall frame range) */
+ falloff = BKE_gpencil_multiframe_falloff_calc(
+ gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff);
+ }
+
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ TransData *head = td;
+ TransData *tail = td;
+ bool stroke_ok;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ continue;
+ }
+ /* What we need to include depends on proportional editing settings... */
+ if (is_prop_edit) {
+ if (is_prop_edit_connected) {
+ /* A) "Connected" - Only those in selected strokes */
+ stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
+ }
+ else {
+ /* B) All points, always */
+ stroke_ok = true;
+ }
+ }
+ else {
+ /* C) Only selected points in selected strokes */
+ stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
+ }
+
+ /* Do stroke... */
+ if (stroke_ok && gps->totpoints) {
+ bGPDspoint *pt;
+ int i;
+
+ /* save falloff factor */
+ gps->runtime.multi_frame_falloff = falloff;
+
+ /* calculate stroke center */
+ float center[3];
+ createTransGPencil_center_get(gps, center);
+
+ /* add all necessary points... */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ bool point_ok;
+
+ /* include point? */
+ if (is_prop_edit) {
+ /* Always all points in strokes that get included */
+ point_ok = true;
+ }
+ else {
+ /* Only selected points in selected strokes */
+ point_ok = (pt->flag & GP_SPOINT_SELECT) != 0;
+ }
+
+ /* do point... */
+ if (point_ok) {
+ copy_v3_v3(td->iloc, &pt->x);
+ /* only copy center in local origins.
+ * This allows get interesting effects also when move
+ * using proportional editing */
+ if ((gps->flag & GP_STROKE_SELECT) &&
+ (ts->transform_pivot_point == V3D_AROUND_LOCAL_ORIGINS)) {
+ copy_v3_v3(td->center, center);
+ }
+ else {
+ copy_v3_v3(td->center, &pt->x);
+ }
+
+ td->loc = &pt->x;
+
+ td->flag = 0;
+
+ if (pt->flag & GP_SPOINT_SELECT) {
+ td->flag |= TD_SELECTED;
+ }
+
+ /* for other transform modes (e.g. shrink-fatten), need to additional data
+ * but never for scale or mirror
+ */
+ if ((t->mode != TFM_RESIZE) && (t->mode != TFM_MIRROR)) {
+ if (t->mode != TFM_GPENCIL_OPACITY) {
+ td->val = &pt->pressure;
+ td->ival = pt->pressure;
+ }
+ else {
+ td->val = &pt->strength;
+ td->ival = pt->strength;
+ }
+ }
+
+ /* screenspace needs special matrices... */
+ if ((gps->flag & (GP_STROKE_3DSPACE | GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) ==
+ 0) {
+ /* screenspace */
+ td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
+ }
+ else {
+ /* configure 2D dataspace points so that they don't play up... */
+ if (gps->flag & (GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) {
+ td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
+ }
+ }
+ /* apply parent transformations */
+ copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */
+ copy_m3_m4(td->mtx, diff_mat); /* display position */
+ copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */
+
+ /* Triangulation must be calculated again,
+ * so save the stroke for recalc function */
+ td->extra = gps;
+
+ /* save pointer to object */
+ td->ob = obact;
+
+ td++;
+ tail++;
+ }
+ }
+
+ /* March over these points, and calculate the proportional editing distances */
+ if (is_prop_edit && (head != tail)) {
+ /* XXX: for now, we are similar enough that this works... */
+ calc_distanceCurveVerts(head, tail - 1);
+ }
+ }
+ }
+ }
+ /* if not multiedit out of loop */
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c
new file mode 100644
index 00000000000..f3d7592127c
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_graph.c
@@ -0,0 +1,700 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_anim_types.h"
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_fcurve.h"
+#include "BKE_nla.h"
+#include "BKE_report.h"
+
+#include "ED_anim_api.h"
+#include "ED_markers.h"
+
+#include "UI_view2d.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+typedef struct TransDataGraph {
+ float unit_scale;
+ float offset;
+} TransDataGraph;
+
+/* -------------------------------------------------------------------- */
+/** \name Graph Editor Transform Creation
+ *
+ * \{ */
+
+/* Helper function for createTransGraphEditData, which is responsible for associating
+ * source data with transform data
+ */
+static void bezt_to_transdata(TransData *td,
+ TransData2D *td2d,
+ TransDataGraph *tdg,
+ AnimData *adt,
+ BezTriple *bezt,
+ int bi,
+ bool selected,
+ bool ishandle,
+ bool intvals,
+ const float mtx[3][3],
+ const float smtx[3][3],
+ float unit_scale,
+ float offset)
+{
+ float *loc = bezt->vec[bi];
+ const float *cent = bezt->vec[1];
+
+ /* New location from td gets dumped onto the old-location of td2d, which then
+ * gets copied to the actual data at td2d->loc2d (bezt->vec[n])
+ *
+ * Due to NLA mapping, we apply NLA mapping to some of the verts here,
+ * and then that mapping will be undone after transform is done.
+ */
+
+ if (adt) {
+ td2d->loc[0] = BKE_nla_tweakedit_remap(adt, loc[0], NLATIME_CONVERT_MAP);
+ td2d->loc[1] = (loc[1] + offset) * unit_scale;
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = loc;
+
+ td->loc = td2d->loc;
+ td->center[0] = BKE_nla_tweakedit_remap(adt, cent[0], NLATIME_CONVERT_MAP);
+ td->center[1] = (cent[1] + offset) * unit_scale;
+ td->center[2] = 0.0f;
+
+ copy_v3_v3(td->iloc, td->loc);
+ }
+ else {
+ td2d->loc[0] = loc[0];
+ td2d->loc[1] = (loc[1] + offset) * unit_scale;
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = loc;
+
+ td->loc = td2d->loc;
+ copy_v3_v3(td->center, cent);
+ td->center[1] = (td->center[1] + offset) * unit_scale;
+ copy_v3_v3(td->iloc, td->loc);
+ }
+
+ if (!ishandle) {
+ td2d->h1 = bezt->vec[0];
+ td2d->h2 = bezt->vec[2];
+ copy_v2_v2(td2d->ih1, td2d->h1);
+ copy_v2_v2(td2d->ih2, td2d->h2);
+ }
+ else {
+ td2d->h1 = NULL;
+ td2d->h2 = NULL;
+ }
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ /* store AnimData info in td->extra, for applying mapping when flushing */
+ td->extra = adt;
+
+ if (selected) {
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0f;
+ }
+ else {
+ td->dist = FLT_MAX;
+ }
+
+ if (ishandle) {
+ td->flag |= TD_NOTIMESNAP;
+ }
+ if (intvals) {
+ td->flag |= TD_INTVALUES;
+ }
+
+ /* copy space-conversion matrices for dealing with non-uniform scales */
+ copy_m3_m3(td->mtx, mtx);
+ copy_m3_m3(td->smtx, smtx);
+
+ tdg->unit_scale = unit_scale;
+ tdg->offset = offset;
+}
+
+static bool graph_edit_is_translation_mode(TransInfo *t)
+{
+ return ELEM(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE, TFM_TIME_DUPLICATE);
+}
+
+static bool graph_edit_use_local_center(TransInfo *t)
+{
+ return ((t->around == V3D_AROUND_LOCAL_ORIGINS) && (graph_edit_is_translation_mode(t) == false));
+}
+
+static void graph_key_shortest_dist(
+ TransInfo *t, FCurve *fcu, TransData *td_start, TransData *td, int cfra, bool use_handle)
+{
+ int j = 0;
+ TransData *td_iter = td_start;
+
+ td->dist = FLT_MAX;
+ for (; j < fcu->totvert; j++) {
+ BezTriple *bezt = fcu->bezt + j;
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ const bool sel2 = (bezt->f2 & SELECT) != 0;
+ const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+ const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+
+ if (sel1 || sel2 || sel3) {
+ td->dist = td->rdist = min_ff(td->dist, fabs(td_iter->center[0] - td->center[0]));
+ }
+
+ td_iter += 3;
+ }
+ }
+}
+
+void createTransGraphEditData(bContext *C, TransInfo *t)
+{
+ SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ Scene *scene = t->scene;
+ ARegion *ar = t->ar;
+ View2D *v2d = &ar->v2d;
+
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ TransDataGraph *tdg = NULL;
+
+ bAnimContext ac;
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ BezTriple *bezt;
+ int count = 0, i;
+ float mtx[3][3], smtx[3][3];
+ const bool is_translation_mode = graph_edit_is_translation_mode(t);
+ const bool use_handle = !(sipo->flag & SIPO_NOHANDLES);
+ const bool use_local_center = graph_edit_use_local_center(t);
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ short anim_map_flag = ANIM_UNITCONV_ONLYSEL | ANIM_UNITCONV_SELVERTS;
+
+ /* determine what type of data we are operating on */
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return;
+ }
+
+ anim_map_flag |= ANIM_get_normalization_flags(&ac);
+
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* which side of the current frame should be allowed */
+ // XXX we still want this mode, but how to get this using standard transform too?
+ if (t->mode == TFM_TIME_EXTEND) {
+ /* only side on which mouse is gets transformed */
+ float xmouse, ymouse;
+
+ UI_view2d_region_to_view(v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse);
+ t->frame_side = (xmouse > CFRA) ? 'R' : 'L'; // XXX use t->frame_side
+ }
+ else {
+ /* normal transform - both sides of current frame are considered */
+ t->frame_side = 'B';
+ }
+
+ /* Loop 1: count how many BezTriples (specifically their verts)
+ * are selected (or should be edited). */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ FCurve *fcu = (FCurve *)ale->key_data;
+ float cfra;
+ int curvecount = 0;
+ bool selected = false;
+
+ /* F-Curve may not have any keyframes */
+ if (fcu->bezt == NULL) {
+ continue;
+ }
+
+ /* convert current-frame to action-time (slightly less accurate, especially under
+ * higher scaling ratios, but is faster than converting all points)
+ */
+ if (adt) {
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ }
+ else {
+ cfra = (float)CFRA;
+ }
+
+ /* Only include BezTriples whose 'keyframe'
+ * occurs on the same side of the current frame as mouse. */
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ const bool sel2 = (bezt->f2 & SELECT) != 0;
+ const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+ const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+
+ if (is_prop_edit) {
+ curvecount += 3;
+ if (sel2 || sel1 || sel3) {
+ selected = true;
+ }
+ }
+ else {
+ if (!is_translation_mode || !(sel2)) {
+ if (sel1) {
+ count++;
+ }
+
+ if (sel3) {
+ count++;
+ }
+ }
+
+ /* only include main vert if selected */
+ if (sel2 && !use_local_center) {
+ count++;
+ }
+ }
+ }
+ }
+
+ if (is_prop_edit) {
+ if (selected) {
+ count += curvecount;
+ ale->tag = true;
+ }
+ }
+ }
+
+ /* stop if trying to build list if nothing selected */
+ if (count == 0) {
+ /* cleanup temp list */
+ ANIM_animdata_freelist(&anim_data);
+ return;
+ }
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* allocate memory for data */
+ tc->data_len = count;
+
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData (Graph Editor)");
+ /* For each 2d vert a 3d vector is allocated,
+ * so that they can be treated just as if they were 3d verts. */
+ tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransData2D (Graph Editor)");
+ tc->custom.type.data = MEM_callocN(tc->data_len * sizeof(TransDataGraph), "TransDataGraph");
+ tc->custom.type.use_free = true;
+
+ td = tc->data;
+ td2d = tc->data_2d;
+ tdg = tc->custom.type.data;
+
+ /* precompute space-conversion matrices for dealing with non-uniform scaling of Graph Editor */
+ unit_m3(mtx);
+ unit_m3(smtx);
+
+ if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) {
+ float xscale, yscale;
+
+ /* apply scale factors to x and y axes of space-conversion matrices */
+ UI_view2d_scale_get(v2d, &xscale, &yscale);
+
+ /* mtx is data to global (i.e. view) conversion */
+ mul_v3_fl(mtx[0], xscale);
+ mul_v3_fl(mtx[1], yscale);
+
+ /* smtx is global (i.e. view) to data conversion */
+ if (IS_EQF(xscale, 0.0f) == 0) {
+ mul_v3_fl(smtx[0], 1.0f / xscale);
+ }
+ if (IS_EQF(yscale, 0.0f) == 0) {
+ mul_v3_fl(smtx[1], 1.0f / yscale);
+ }
+ }
+
+ /* loop 2: build transdata arrays */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ FCurve *fcu = (FCurve *)ale->key_data;
+ bool intvals = (fcu->flag & FCURVE_INT_VALUES) != 0;
+ float unit_scale, offset;
+ float cfra;
+
+ /* F-Curve may not have any keyframes */
+ if (fcu->bezt == NULL || (is_prop_edit && ale->tag == 0)) {
+ continue;
+ }
+
+ /* convert current-frame to action-time (slightly less accurate, especially under
+ * higher scaling ratios, but is faster than converting all points)
+ */
+ if (adt) {
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ }
+ else {
+ cfra = (float)CFRA;
+ }
+
+ unit_scale = ANIM_unit_mapping_get_factor(
+ ac.scene, ale->id, ale->key_data, anim_map_flag, &offset);
+
+ /* only include BezTriples whose 'keyframe' occurs on the same side
+ * of the current frame as mouse (if applicable) */
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ const bool sel2 = (bezt->f2 & SELECT) != 0;
+ const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+ const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+
+ TransDataCurveHandleFlags *hdata = NULL;
+ /* short h1=1, h2=1; */ /* UNUSED */
+
+ if (is_prop_edit) {
+ bool is_sel = (sel2 || sel1 || sel3);
+ /* we always select all handles for proportional editing if central handle is selected */
+ initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++,
+ td2d++,
+ tdg++,
+ adt,
+ bezt,
+ 0,
+ is_sel,
+ true,
+ intvals,
+ mtx,
+ smtx,
+ unit_scale,
+ offset);
+ initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++,
+ td2d++,
+ tdg++,
+ adt,
+ bezt,
+ 1,
+ is_sel,
+ false,
+ intvals,
+ mtx,
+ smtx,
+ unit_scale,
+ offset);
+ initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++,
+ td2d++,
+ tdg++,
+ adt,
+ bezt,
+ 2,
+ is_sel,
+ true,
+ intvals,
+ mtx,
+ smtx,
+ unit_scale,
+ offset);
+ }
+ else {
+ /* only include handles if selected, irrespective of the interpolation modes.
+ * also, only treat handles specially if the center point isn't selected.
+ */
+ if (!is_translation_mode || !(sel2)) {
+ if (sel1) {
+ hdata = initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++,
+ td2d++,
+ tdg++,
+ adt,
+ bezt,
+ 0,
+ sel1,
+ true,
+ intvals,
+ mtx,
+ smtx,
+ unit_scale,
+ offset);
+ }
+ else {
+ /* h1 = 0; */ /* UNUSED */
+ }
+
+ if (sel3) {
+ if (hdata == NULL) {
+ hdata = initTransDataCurveHandles(td, bezt);
+ }
+ bezt_to_transdata(td++,
+ td2d++,
+ tdg++,
+ adt,
+ bezt,
+ 2,
+ sel3,
+ true,
+ intvals,
+ mtx,
+ smtx,
+ unit_scale,
+ offset);
+ }
+ else {
+ /* h2 = 0; */ /* UNUSED */
+ }
+ }
+
+ /* only include main vert if selected */
+ if (sel2 && !use_local_center) {
+ /* move handles relative to center */
+ if (is_translation_mode) {
+ if (sel1) {
+ td->flag |= TD_MOVEHANDLE1;
+ }
+ if (sel3) {
+ td->flag |= TD_MOVEHANDLE2;
+ }
+ }
+
+ /* if handles were not selected, store their selection status */
+ if (!(sel1) || !(sel3)) {
+ if (hdata == NULL) {
+ hdata = initTransDataCurveHandles(td, bezt);
+ }
+ }
+
+ bezt_to_transdata(td++,
+ td2d++,
+ tdg++,
+ adt,
+ bezt,
+ 1,
+ sel2,
+ false,
+ intvals,
+ mtx,
+ smtx,
+ unit_scale,
+ offset);
+ }
+ /* Special hack (must be done after #initTransDataCurveHandles(),
+ * as that stores handle settings to restore...):
+ *
+ * - Check if we've got entire BezTriple selected and we're scaling/rotating that point,
+ * then check if we're using auto-handles.
+ * - If so, change them auto-handles to aligned handles so that handles get affected too
+ */
+ if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) && ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM) &&
+ ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) {
+ if (hdata && (sel1) && (sel3)) {
+ bezt->h1 = HD_ALIGN;
+ bezt->h2 = HD_ALIGN;
+ }
+ }
+ }
+ }
+ }
+
+ /* Sets handles based on the selection */
+ testhandles_fcurve(fcu, use_handle);
+ }
+
+ if (is_prop_edit) {
+ /* loop 2: build transdata arrays */
+ td = tc->data;
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ FCurve *fcu = (FCurve *)ale->key_data;
+ TransData *td_start = td;
+ float cfra;
+
+ /* F-Curve may not have any keyframes */
+ if (fcu->bezt == NULL || (ale->tag == 0)) {
+ continue;
+ }
+
+ /* convert current-frame to action-time (slightly less accurate, especially under
+ * higher scaling ratios, but is faster than converting all points)
+ */
+ if (adt) {
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ }
+ else {
+ cfra = (float)CFRA;
+ }
+
+ /* only include BezTriples whose 'keyframe' occurs on the
+ * same side of the current frame as mouse (if applicable) */
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ const bool sel2 = (bezt->f2 & SELECT) != 0;
+ const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+ const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+
+ if (sel1 || sel2) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
+ }
+ td++;
+
+ if (sel2) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
+ }
+ td++;
+
+ if (sel3 || sel2) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
+ }
+ td++;
+ }
+ }
+ }
+ }
+
+ /* cleanup temp list */
+ ANIM_animdata_freelist(&anim_data);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Graph Editor Transform Flush
+ *
+ * \{ */
+
+/* this function is called on recalcData to apply the transforms applied
+ * to the transdata on to the actual keyframe data
+ */
+void flushTransGraphData(TransInfo *t)
+{
+ SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ TransData *td;
+ TransData2D *td2d;
+ TransDataGraph *tdg;
+ Scene *scene = t->scene;
+ double secf = FPS;
+ int a;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* flush to 2d vector from internally used 3d vector */
+ for (a = 0, td = tc->data, td2d = tc->data_2d, tdg = tc->custom.type.data; a < tc->data_len;
+ a++, td++, td2d++, tdg++) {
+ /* pointers to relevant AnimData blocks are stored in the td->extra pointers */
+ AnimData *adt = (AnimData *)td->extra;
+
+ float inv_unit_scale = 1.0f / tdg->unit_scale;
+
+ /* Handle snapping for time values:
+ * - We should still be in NLA-mapping time-space.
+ * - Only apply to keyframes (but never to handles).
+ * - Don't do this when canceling, or else these changes won't go away.
+ */
+ if ((t->state != TRANS_CANCEL) && (td->flag & TD_NOTIMESNAP) == 0) {
+ switch (sipo->autosnap) {
+ case SACTSNAP_FRAME: /* snap to nearest frame */
+ td2d->loc[0] = floor((double)td2d->loc[0] + 0.5);
+ break;
+
+ case SACTSNAP_SECOND: /* snap to nearest second */
+ td2d->loc[0] = floor(((double)td2d->loc[0] / secf) + 0.5) * secf;
+ break;
+
+ case SACTSNAP_MARKER: /* snap to nearest marker */
+ td2d->loc[0] = (float)ED_markers_find_nearest_marker_time(&t->scene->markers,
+ td2d->loc[0]);
+ break;
+ }
+ }
+
+ /* we need to unapply the nla-mapping from the time in some situations */
+ if (adt) {
+ td2d->loc2d[0] = BKE_nla_tweakedit_remap(adt, td2d->loc[0], NLATIME_CONVERT_UNMAP);
+ }
+ else {
+ td2d->loc2d[0] = td2d->loc[0];
+ }
+
+ /** Time-stepping auto-snapping modes don't get applied for Graph Editor transforms,
+ * as these use the generic transform modes which don't account for this sort of thing.
+ * These ones aren't affected by NLA mapping, so we do this after the conversion...
+ *
+ * \note We also have to apply to td->loc,
+ * as that's what the handle-adjustment step below looks to,
+ * otherwise we get "swimming handles".
+ *
+ * \note We don't do this when canceling transforms, or else these changes don't go away.
+ */
+ if ((t->state != TRANS_CANCEL) && (td->flag & TD_NOTIMESNAP) == 0 &&
+ ELEM(sipo->autosnap, SACTSNAP_STEP, SACTSNAP_TSTEP)) {
+ switch (sipo->autosnap) {
+ case SACTSNAP_STEP: /* frame step */
+ td2d->loc2d[0] = floor((double)td2d->loc[0] + 0.5);
+ td->loc[0] = floor((double)td->loc[0] + 0.5);
+ break;
+
+ case SACTSNAP_TSTEP: /* second step */
+ /* XXX: the handle behavior in this case is still not quite right... */
+ td2d->loc[0] = floor(((double)td2d->loc[0] / secf) + 0.5) * secf;
+ td->loc[0] = floor(((double)td->loc[0] / secf) + 0.5) * secf;
+ break;
+ }
+ }
+
+ /* if int-values only, truncate to integers */
+ if (td->flag & TD_INTVALUES) {
+ td2d->loc2d[1] = floorf(td2d->loc[1] * inv_unit_scale - tdg->offset + 0.5f);
+ }
+ else {
+ td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale - tdg->offset;
+ }
+
+ if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) {
+ td2d->h1[0] = td2d->ih1[0] + td->loc[0] - td->iloc[0];
+ td2d->h1[1] = td2d->ih1[1] + (td->loc[1] - td->iloc[1]) * inv_unit_scale;
+ }
+
+ if ((td->flag & TD_MOVEHANDLE2) && td2d->h2) {
+ td2d->h2[0] = td2d->ih2[0] + td->loc[0] - td->iloc[0];
+ td2d->h2[1] = td2d->ih2[1] + (td->loc[1] - td->iloc[1]) * inv_unit_scale;
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_lattice.c b/source/blender/editors/transform/transform_convert_lattice.c
new file mode 100644
index 00000000000..15af24090f0
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_lattice.c
@@ -0,0 +1,113 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_curve_types.h"
+#include "DNA_lattice_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_report.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Curve/Surfaces Transform Creation
+ *
+ * \{ */
+
+void createTransLatticeVerts(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ Lattice *latt = ((Lattice *)tc->obedit->data)->editlatt->latt;
+ TransData *td = NULL;
+ BPoint *bp;
+ float mtx[3][3], smtx[3][3];
+ int a;
+ int count = 0, countsel = 0;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
+ bp = latt->def;
+ a = latt->pntsu * latt->pntsv * latt->pntsw;
+ while (a--) {
+ if (bp->hide == 0) {
+ if (bp->f1 & SELECT) {
+ countsel++;
+ }
+ if (is_prop_edit) {
+ count++;
+ }
+ }
+ bp++;
+ }
+
+ /* note: in prop mode we need at least 1 selected */
+ if (countsel == 0) {
+ return;
+ }
+
+ if (is_prop_edit) {
+ tc->data_len = count;
+ }
+ else {
+ tc->data_len = countsel;
+ }
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Lattice EditMode)");
+
+ copy_m3_m4(mtx, tc->obedit->obmat);
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+
+ td = tc->data;
+ bp = latt->def;
+ a = latt->pntsu * latt->pntsv * latt->pntsw;
+ while (a--) {
+ if (is_prop_edit || (bp->f1 & SELECT)) {
+ if (bp->hide == 0) {
+ copy_v3_v3(td->iloc, bp->vec);
+ td->loc = bp->vec;
+ copy_v3_v3(td->center, td->loc);
+ if (bp->f1 & SELECT) {
+ td->flag = TD_SELECTED;
+ }
+ else {
+ td->flag = 0;
+ }
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ td++;
+ }
+ }
+ bp++;
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_mask.c b/source/blender/editors/transform/transform_convert_mask.c
new file mode 100644
index 00000000000..32152442acf
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_mask.c
@@ -0,0 +1,442 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_mask_types.h"
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_mask.h"
+#include "BKE_report.h"
+
+#include "ED_clip.h"
+#include "ED_mask.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+typedef struct TransDataMasking {
+ bool is_handle;
+
+ float handle[2], orig_handle[2];
+ float vec[3][3];
+ struct MaskSplinePoint *point;
+ float parent_matrix[3][3];
+ float parent_inverse_matrix[3][3];
+ char orig_handle_type;
+
+ eMaskWhichHandle which_handle;
+} TransDataMasking;
+
+/* -------------------------------------------------------------------- */
+/** \name Masking Transform Creation
+ *
+ * \{ */
+
+static void MaskHandleToTransData(MaskSplinePoint *point,
+ eMaskWhichHandle which_handle,
+ TransData *td,
+ TransData2D *td2d,
+ TransDataMasking *tdm,
+ const float asp[2],
+ /*const*/ const float parent_matrix[3][3],
+ /*const*/ const float parent_inverse_matrix[3][3])
+{
+ BezTriple *bezt = &point->bezt;
+ const bool is_sel_any = MASKPOINT_ISSEL_ANY(point);
+
+ tdm->point = point;
+ copy_m3_m3(tdm->vec, bezt->vec);
+
+ tdm->is_handle = true;
+ copy_m3_m3(tdm->parent_matrix, parent_matrix);
+ copy_m3_m3(tdm->parent_inverse_matrix, parent_inverse_matrix);
+
+ BKE_mask_point_handle(point, which_handle, tdm->handle);
+ tdm->which_handle = which_handle;
+
+ copy_v2_v2(tdm->orig_handle, tdm->handle);
+
+ mul_v2_m3v2(td2d->loc, parent_matrix, tdm->handle);
+ td2d->loc[0] *= asp[0];
+ td2d->loc[1] *= asp[1];
+ td2d->loc[2] = 0.0f;
+
+ td2d->loc2d = tdm->handle;
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ mul_v2_m3v2(td->center, parent_matrix, bezt->vec[1]);
+ td->center[0] *= asp[0];
+ td->center[1] *= asp[1];
+ copy_v3_v3(td->iloc, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ if (is_sel_any) {
+ td->flag |= TD_SELECTED;
+ }
+
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+
+ if (which_handle == MASK_WHICH_HANDLE_LEFT) {
+ tdm->orig_handle_type = bezt->h1;
+ }
+ else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
+ tdm->orig_handle_type = bezt->h2;
+ }
+}
+
+static void MaskPointToTransData(Scene *scene,
+ MaskSplinePoint *point,
+ TransData *td,
+ TransData2D *td2d,
+ TransDataMasking *tdm,
+ const bool is_prop_edit,
+ const float asp[2])
+{
+ BezTriple *bezt = &point->bezt;
+ const bool is_sel_point = MASKPOINT_ISSEL_KNOT(point);
+ const bool is_sel_any = MASKPOINT_ISSEL_ANY(point);
+ float parent_matrix[3][3], parent_inverse_matrix[3][3];
+
+ BKE_mask_point_parent_matrix_get(point, CFRA, parent_matrix);
+ invert_m3_m3(parent_inverse_matrix, parent_matrix);
+
+ if (is_prop_edit || is_sel_point) {
+ int i;
+
+ tdm->point = point;
+ copy_m3_m3(tdm->vec, bezt->vec);
+
+ for (i = 0; i < 3; i++) {
+ copy_m3_m3(tdm->parent_matrix, parent_matrix);
+ copy_m3_m3(tdm->parent_inverse_matrix, parent_inverse_matrix);
+
+ /* CV coords are scaled by aspects. this is needed for rotations and
+ * proportional editing to be consistent with the stretched CV coords
+ * that are displayed. this also means that for display and numinput,
+ * and when the CV coords are flushed, these are converted each time */
+ mul_v2_m3v2(td2d->loc, parent_matrix, bezt->vec[i]);
+ td2d->loc[0] *= asp[0];
+ td2d->loc[1] *= asp[1];
+ td2d->loc[2] = 0.0f;
+
+ td2d->loc2d = bezt->vec[i];
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ mul_v2_m3v2(td->center, parent_matrix, bezt->vec[1]);
+ td->center[0] *= asp[0];
+ td->center[1] *= asp[1];
+ copy_v3_v3(td->iloc, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+
+ if (i == 1) {
+ /* scaling weights */
+ td->val = &bezt->weight;
+ td->ival = *td->val;
+ }
+ else {
+ td->val = NULL;
+ }
+
+ if (is_sel_any) {
+ td->flag |= TD_SELECTED;
+ }
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+
+ if (i == 0) {
+ tdm->orig_handle_type = bezt->h1;
+ }
+ else if (i == 2) {
+ tdm->orig_handle_type = bezt->h2;
+ }
+
+ td++;
+ td2d++;
+ tdm++;
+ }
+ }
+ else {
+ if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
+ MaskHandleToTransData(point,
+ MASK_WHICH_HANDLE_STICK,
+ td,
+ td2d,
+ tdm,
+ asp,
+ parent_matrix,
+ parent_inverse_matrix);
+
+ td++;
+ td2d++;
+ tdm++;
+ }
+ else {
+ if (bezt->f1 & SELECT) {
+ MaskHandleToTransData(point,
+ MASK_WHICH_HANDLE_LEFT,
+ td,
+ td2d,
+ tdm,
+ asp,
+ parent_matrix,
+ parent_inverse_matrix);
+
+ if (bezt->h1 == HD_VECT) {
+ bezt->h1 = HD_FREE;
+ }
+ else if (bezt->h1 == HD_AUTO) {
+ bezt->h1 = HD_ALIGN_DOUBLESIDE;
+ bezt->h2 = HD_ALIGN_DOUBLESIDE;
+ }
+
+ td++;
+ td2d++;
+ tdm++;
+ }
+ if (bezt->f3 & SELECT) {
+ MaskHandleToTransData(point,
+ MASK_WHICH_HANDLE_RIGHT,
+ td,
+ td2d,
+ tdm,
+ asp,
+ parent_matrix,
+ parent_inverse_matrix);
+
+ if (bezt->h2 == HD_VECT) {
+ bezt->h2 = HD_FREE;
+ }
+ else if (bezt->h2 == HD_AUTO) {
+ bezt->h1 = HD_ALIGN_DOUBLESIDE;
+ bezt->h2 = HD_ALIGN_DOUBLESIDE;
+ }
+
+ td++;
+ td2d++;
+ tdm++;
+ }
+ }
+ }
+}
+
+void createTransMaskingData(bContext *C, TransInfo *t)
+{
+ Scene *scene = CTX_data_scene(C);
+ Mask *mask = CTX_data_edit_mask(C);
+ MaskLayer *masklay;
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ TransDataMasking *tdm = NULL;
+ int count = 0, countsel = 0;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT);
+ float asp[2];
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ tc->data_len = 0;
+
+ if (!mask) {
+ return;
+ }
+
+ if (t->spacetype == SPACE_CLIP) {
+ SpaceClip *sc = t->sa->spacedata.first;
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ if (!clip) {
+ return;
+ }
+ }
+
+ /* count */
+ for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ MaskSpline *spline;
+
+ if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ continue;
+ }
+
+ for (spline = masklay->splines.first; spline; spline = spline->next) {
+ int i;
+
+ for (i = 0; i < spline->tot_point; i++) {
+ MaskSplinePoint *point = &spline->points[i];
+
+ if (MASKPOINT_ISSEL_ANY(point)) {
+ if (MASKPOINT_ISSEL_KNOT(point)) {
+ countsel += 3;
+ }
+ else {
+ if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
+ countsel += 1;
+ }
+ else {
+ BezTriple *bezt = &point->bezt;
+ if (bezt->f1 & SELECT) {
+ countsel++;
+ }
+ if (bezt->f3 & SELECT) {
+ countsel++;
+ }
+ }
+ }
+ }
+
+ if (is_prop_edit) {
+ count += 3;
+ }
+ }
+ }
+ }
+
+ /* note: in prop mode we need at least 1 selected */
+ if (countsel == 0) {
+ return;
+ }
+
+ ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]);
+
+ tc->data_len = (is_prop_edit) ? count : countsel;
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Mask Editing)");
+ /* for each 2d uv coord a 3d vector is allocated, so that they can be
+ * treated just as if they were 3d verts */
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D),
+ "TransObData2D(Mask Editing)");
+ tc->custom.type.data = tdm = MEM_callocN(tc->data_len * sizeof(TransDataMasking),
+ "TransDataMasking(Mask Editing)");
+ tc->custom.type.use_free = true;
+
+ /* create data */
+ for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ MaskSpline *spline;
+
+ if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ continue;
+ }
+
+ for (spline = masklay->splines.first; spline; spline = spline->next) {
+ int i;
+
+ for (i = 0; i < spline->tot_point; i++) {
+ MaskSplinePoint *point = &spline->points[i];
+
+ if (is_prop_edit || MASKPOINT_ISSEL_ANY(point)) {
+ MaskPointToTransData(scene, point, td, td2d, tdm, is_prop_edit, asp);
+
+ if (is_prop_edit || MASKPOINT_ISSEL_KNOT(point)) {
+ td += 3;
+ td2d += 3;
+ tdm += 3;
+ }
+ else {
+ if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
+ td++;
+ td2d++;
+ tdm++;
+ }
+ else {
+ BezTriple *bezt = &point->bezt;
+ if (bezt->f1 & SELECT) {
+ td++;
+ td2d++;
+ tdm++;
+ }
+ if (bezt->f3 & SELECT) {
+ td++;
+ td2d++;
+ tdm++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Masking Transform Flush
+ *
+ * \{ */
+
+void flushTransMasking(TransInfo *t)
+{
+ TransData2D *td;
+ TransDataMasking *tdm;
+ int a;
+ float asp[2], inv[2];
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]);
+ inv[0] = 1.0f / asp[0];
+ inv[1] = 1.0f / asp[1];
+
+ /* flush to 2d vector from internally used 3d vector */
+ for (a = 0, td = tc->data_2d, tdm = tc->custom.type.data; a < tc->data_len; a++, td++, tdm++) {
+ td->loc2d[0] = td->loc[0] * inv[0];
+ td->loc2d[1] = td->loc[1] * inv[1];
+ mul_m3_v2(tdm->parent_inverse_matrix, td->loc2d);
+
+ if (tdm->is_handle) {
+ BKE_mask_point_set_handle(tdm->point,
+ tdm->which_handle,
+ td->loc2d,
+ (t->flag & T_ALT_TRANSFORM) != 0,
+ tdm->orig_handle,
+ tdm->vec);
+ }
+
+ if (t->state == TRANS_CANCEL) {
+ if (tdm->which_handle == MASK_WHICH_HANDLE_LEFT) {
+ tdm->point->bezt.h1 = tdm->orig_handle_type;
+ }
+ else if (tdm->which_handle == MASK_WHICH_HANDLE_RIGHT) {
+ tdm->point->bezt.h2 = tdm->orig_handle_type;
+ }
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_mball.c b/source/blender/editors/transform/transform_convert_mball.c
new file mode 100644
index 00000000000..5d7e36cc834
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_mball.c
@@ -0,0 +1,130 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_meta_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_report.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Meta Elements Transform Creation
+ *
+ * \{ */
+
+void createTransMBallVerts(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ MetaBall *mb = (MetaBall *)tc->obedit->data;
+ MetaElem *ml;
+ TransData *td;
+ TransDataExtension *tx;
+ float mtx[3][3], smtx[3][3];
+ int count = 0, countsel = 0;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
+ /* count totals */
+ for (ml = mb->editelems->first; ml; ml = ml->next) {
+ if (ml->flag & SELECT) {
+ countsel++;
+ }
+ if (is_prop_edit) {
+ count++;
+ }
+ }
+
+ /* note: in prop mode we need at least 1 selected */
+ if (countsel == 0) {
+ continue;
+ }
+
+ if (is_prop_edit) {
+ tc->data_len = count;
+ }
+ else {
+ tc->data_len = countsel;
+ }
+
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(MBall EditMode)");
+ tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension),
+ "MetaElement_TransExtension");
+
+ copy_m3_m4(mtx, tc->obedit->obmat);
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+
+ for (ml = mb->editelems->first; ml; ml = ml->next) {
+ if (is_prop_edit || (ml->flag & SELECT)) {
+ td->loc = &ml->x;
+ copy_v3_v3(td->iloc, td->loc);
+ copy_v3_v3(td->center, td->loc);
+
+ quat_to_mat3(td->axismtx, ml->quat);
+
+ if (ml->flag & SELECT) {
+ td->flag = TD_SELECTED | TD_USEQUAT | TD_SINGLESIZE;
+ }
+ else {
+ td->flag = TD_USEQUAT;
+ }
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+
+ td->ext = tx;
+
+ /* Radius of MetaElem (mass of MetaElem influence) */
+ if (ml->flag & MB_SCALE_RAD) {
+ td->val = &ml->rad;
+ td->ival = ml->rad;
+ }
+ else {
+ td->val = &ml->s;
+ td->ival = ml->s;
+ }
+
+ /* expx/expy/expz determine "shape" of some MetaElem types */
+ tx->size = &ml->expx;
+ tx->isize[0] = ml->expx;
+ tx->isize[1] = ml->expy;
+ tx->isize[2] = ml->expz;
+
+ /* quat is used for rotation of MetaElem */
+ tx->quat = ml->quat;
+ copy_qt_qt(tx->iquat, ml->quat);
+
+ tx->rot = NULL;
+
+ td++;
+ tx++;
+ }
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
new file mode 100644
index 00000000000..7f9c4ee2fcc
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -0,0 +1,1645 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_alloca.h"
+#include "BLI_bitmap.h"
+#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_linklist_stack.h"
+
+#include "BKE_context.h"
+#include "BKE_crazyspace.h"
+#include "BKE_editmesh.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_modifier.h"
+#include "BKE_scene.h"
+
+#include "ED_image.h"
+#include "ED_mesh.h"
+#include "ED_uvedit.h"
+
+#include "WM_api.h" /* for WM_event_add_notifier to deal with stabilization nodes */
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+#include "bmesh.h"
+
+/* Used for both mirror epsilon and TD_MIRROR_EDGE_ */
+#define TRANSFORM_MAXDIST_MIRROR 0.00002f
+
+/* when transforming islands */
+struct TransIslandData {
+ float co[3];
+ float axismtx[3][3];
+};
+
+/* -------------------------------------------------------------------- */
+/** \name Edit Mesh Verts Transform Creation
+ *
+ * \{ */
+
+static bool bmesh_test_dist_add(BMVert *v,
+ BMVert *v_other,
+ float *dists,
+ const float *dists_prev,
+ /* optionally track original index */
+ int *index,
+ const int *index_prev,
+ const float mtx[3][3])
+{
+ if ((BM_elem_flag_test(v_other, BM_ELEM_SELECT) == 0) &&
+ (BM_elem_flag_test(v_other, BM_ELEM_HIDDEN) == 0)) {
+ const int i = BM_elem_index_get(v);
+ const int i_other = BM_elem_index_get(v_other);
+ float vec[3];
+ float dist_other;
+ sub_v3_v3v3(vec, v->co, v_other->co);
+ mul_m3_v3(mtx, vec);
+
+ dist_other = dists_prev[i] + len_v3(vec);
+ if (dist_other < dists[i_other]) {
+ dists[i_other] = dist_other;
+ if (index != NULL) {
+ index[i_other] = index_prev[i];
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * \param mtx: Measure distance in this space.
+ * \param dists: Store the closest connected distance to selected vertices.
+ * \param index: Optionally store the original index we're measuring the distance to (can be NULL).
+ */
+static void editmesh_set_connectivity_distance(BMesh *bm,
+ const float mtx[3][3],
+ float *dists,
+ int *index)
+{
+ BLI_LINKSTACK_DECLARE(queue, BMVert *);
+
+ /* any BM_ELEM_TAG'd vertex is in 'queue_next', so we don't add in twice */
+ BLI_LINKSTACK_DECLARE(queue_next, BMVert *);
+
+ BLI_LINKSTACK_INIT(queue);
+ BLI_LINKSTACK_INIT(queue_next);
+
+ {
+ BMIter viter;
+ BMVert *v;
+ int i;
+
+ BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
+ float dist;
+ BM_elem_index_set(v, i); /* set_inline */
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT) == 0 || BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
+ dist = FLT_MAX;
+ if (index != NULL) {
+ index[i] = i;
+ }
+ }
+ else {
+ BLI_LINKSTACK_PUSH(queue, v);
+ dist = 0.0f;
+ if (index != NULL) {
+ index[i] = i;
+ }
+ }
+
+ dists[i] = dist;
+ }
+ bm->elem_index_dirty &= ~BM_VERT;
+ }
+
+ /* need to be very careful of feedback loops here, store previous dist's to avoid feedback */
+ float *dists_prev = MEM_dupallocN(dists);
+ int *index_prev = MEM_dupallocN(index); /* may be NULL */
+
+ do {
+ BMVert *v;
+ LinkNode *lnk;
+
+ /* this is correct but slow to do each iteration,
+ * instead sync the dist's while clearing BM_ELEM_TAG (below) */
+#if 0
+ memcpy(dists_prev, dists, sizeof(float) * bm->totvert);
+#endif
+
+ while ((v = BLI_LINKSTACK_POP(queue))) {
+ BLI_assert(dists[BM_elem_index_get(v)] != FLT_MAX);
+
+ /* connected edge-verts */
+ if (v->e != NULL) {
+ BMEdge *e_iter, *e_first;
+
+ e_iter = e_first = v->e;
+
+ /* would normally use BM_EDGES_OF_VERT, but this runs so often,
+ * its faster to iterate on the data directly */
+ do {
+
+ if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == 0) {
+
+ /* edge distance */
+ {
+ BMVert *v_other = BM_edge_other_vert(e_iter, v);
+ if (bmesh_test_dist_add(v, v_other, dists, dists_prev, index, index_prev, mtx)) {
+ if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
+ BM_elem_flag_enable(v_other, BM_ELEM_TAG);
+ BLI_LINKSTACK_PUSH(queue_next, v_other);
+ }
+ }
+ }
+
+ /* face distance */
+ if (e_iter->l) {
+ BMLoop *l_iter_radial, *l_first_radial;
+ /**
+ * imaginary edge diagonally across quad,
+ * \note, this takes advantage of the rules of winding that we
+ * know 2 or more of a verts edges wont reference the same face twice.
+ * Also, if the edge is hidden, the face will be hidden too.
+ */
+ l_iter_radial = l_first_radial = e_iter->l;
+
+ do {
+ if ((l_iter_radial->v == v) && (l_iter_radial->f->len == 4) &&
+ (BM_elem_flag_test(l_iter_radial->f, BM_ELEM_HIDDEN) == 0)) {
+ BMVert *v_other = l_iter_radial->next->next->v;
+ if (bmesh_test_dist_add(v, v_other, dists, dists_prev, index, index_prev, mtx)) {
+ if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
+ BM_elem_flag_enable(v_other, BM_ELEM_TAG);
+ BLI_LINKSTACK_PUSH(queue_next, v_other);
+ }
+ }
+ }
+ } while ((l_iter_radial = l_iter_radial->radial_next) != l_first_radial);
+ }
+ }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
+ }
+ }
+
+ /* clear for the next loop */
+ for (lnk = queue_next; lnk; lnk = lnk->next) {
+ BMVert *v_link = lnk->link;
+ const int i = BM_elem_index_get(v_link);
+
+ BM_elem_flag_disable(v_link, BM_ELEM_TAG);
+
+ /* keep in sync, avoid having to do full memcpy each iteration */
+ dists_prev[i] = dists[i];
+ if (index != NULL) {
+ index_prev[i] = index[i];
+ }
+ }
+
+ BLI_LINKSTACK_SWAP(queue, queue_next);
+
+ /* none should be tagged now since 'queue_next' is empty */
+ BLI_assert(BM_iter_mesh_count_flag(BM_VERTS_OF_MESH, bm, BM_ELEM_TAG, true) == 0);
+
+ } while (BLI_LINKSTACK_SIZE(queue));
+
+ BLI_LINKSTACK_FREE(queue);
+ BLI_LINKSTACK_FREE(queue_next);
+
+ MEM_freeN(dists_prev);
+ if (index_prev != NULL) {
+ MEM_freeN(index_prev);
+ }
+}
+
+static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
+ int *r_island_tot,
+ int **r_island_vert_map,
+ bool calc_single_islands)
+{
+ BMesh *bm = em->bm;
+ struct TransIslandData *trans_islands;
+ char htype;
+ char itype;
+ int i;
+
+ /* group vars */
+ int *groups_array;
+ int(*group_index)[2];
+ int group_tot;
+ void **ele_array;
+
+ int *vert_map;
+
+ if (em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
+ groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totedgesel, __func__);
+ group_tot = BM_mesh_calc_edge_groups(
+ bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT);
+
+ htype = BM_EDGE;
+ itype = BM_VERTS_OF_EDGE;
+ }
+ else { /* (bm->selectmode & SCE_SELECT_FACE) */
+ groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__);
+ group_tot = BM_mesh_calc_face_groups(
+ bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT, BM_VERT);
+
+ htype = BM_FACE;
+ itype = BM_VERTS_OF_FACE;
+ }
+
+ trans_islands = MEM_mallocN(sizeof(*trans_islands) * group_tot, __func__);
+
+ vert_map = MEM_mallocN(sizeof(*vert_map) * bm->totvert, __func__);
+ /* we shouldn't need this, but with incorrect selection flushing
+ * its possible we have a selected vertex that's not in a face,
+ * for now best not crash in that case. */
+ copy_vn_i(vert_map, bm->totvert, -1);
+
+ BM_mesh_elem_table_ensure(bm, htype);
+ ele_array = (htype == BM_FACE) ? (void **)bm->ftable : (void **)bm->etable;
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ /* may be an edge OR a face array */
+ for (i = 0; i < group_tot; i++) {
+ BMEditSelection ese = {NULL};
+
+ const int fg_sta = group_index[i][0];
+ const int fg_len = group_index[i][1];
+ float co[3], no[3], tangent[3];
+ int j;
+
+ zero_v3(co);
+ zero_v3(no);
+ zero_v3(tangent);
+
+ ese.htype = htype;
+
+ /* loop on each face in this group:
+ * - assign r_vert_map
+ * - calculate (co, no)
+ */
+ for (j = 0; j < fg_len; j++) {
+ float tmp_co[3], tmp_no[3], tmp_tangent[3];
+
+ ese.ele = ele_array[groups_array[fg_sta + j]];
+
+ BM_editselection_center(&ese, tmp_co);
+ BM_editselection_normal(&ese, tmp_no);
+ BM_editselection_plane(&ese, tmp_tangent);
+
+ add_v3_v3(co, tmp_co);
+ add_v3_v3(no, tmp_no);
+ add_v3_v3(tangent, tmp_tangent);
+
+ {
+ /* setup vertex map */
+ BMIter iter;
+ BMVert *v;
+
+ /* connected edge-verts */
+ BM_ITER_ELEM (v, &iter, ese.ele, itype) {
+ vert_map[BM_elem_index_get(v)] = i;
+ }
+ }
+ }
+
+ mul_v3_v3fl(trans_islands[i].co, co, 1.0f / (float)fg_len);
+
+ if (createSpaceNormalTangent(trans_islands[i].axismtx, no, tangent)) {
+ /* pass */
+ }
+ else {
+ if (normalize_v3(no) != 0.0f) {
+ axis_dominant_v3_to_m3(trans_islands[i].axismtx, no);
+ invert_m3(trans_islands[i].axismtx);
+ }
+ else {
+ unit_m3(trans_islands[i].axismtx);
+ }
+ }
+ }
+
+ MEM_freeN(groups_array);
+ MEM_freeN(group_index);
+
+ /* for PET we need islands of 1 so connected vertices can use it with V3D_AROUND_LOCAL_ORIGINS */
+ if (calc_single_islands) {
+ BMIter viter;
+ BMVert *v;
+ int group_tot_single = 0;
+
+ BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) {
+ group_tot_single += 1;
+ }
+ }
+
+ if (group_tot_single != 0) {
+ trans_islands = MEM_reallocN(trans_islands,
+ sizeof(*trans_islands) * (group_tot + group_tot_single));
+
+ BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) {
+ struct TransIslandData *v_island = &trans_islands[group_tot];
+ vert_map[i] = group_tot;
+
+ copy_v3_v3(v_island->co, v->co);
+
+ if (is_zero_v3(v->no) != 0.0f) {
+ axis_dominant_v3_to_m3(v_island->axismtx, v->no);
+ invert_m3(v_island->axismtx);
+ }
+ else {
+ unit_m3(v_island->axismtx);
+ }
+
+ group_tot += 1;
+ }
+ }
+ }
+ }
+
+ *r_island_tot = group_tot;
+ *r_island_vert_map = vert_map;
+
+ return trans_islands;
+}
+
+static bool is_in_quadrant_v3(const float co[3], const int quadrant[3], const float epsilon)
+{
+ if (quadrant[0] && ((co[0] * quadrant[0]) < -epsilon)) {
+ return false;
+ }
+ if (quadrant[1] && ((co[1] * quadrant[1]) < -epsilon)) {
+ return false;
+ }
+ if (quadrant[2] && ((co[2] * quadrant[2]) < -epsilon)) {
+ return false;
+ }
+ return true;
+}
+
+static TransDataMirror *editmesh_mirror_data_calc(BMEditMesh *em,
+ bool use_select,
+ const bool use_topology,
+ const bool mirror_axis[3],
+ int *r_mirror_data_len,
+ BLI_bitmap **r_mirror_bitmap)
+{
+ BMesh *bm = em->bm;
+ int *index[3] = {NULL};
+ int i;
+
+ bool test_selected_only = use_select && (mirror_axis[0] + mirror_axis[1] + mirror_axis[2]) == 1;
+ for (i = 0; i < 3; i++) {
+ if (mirror_axis[i]) {
+ index[i] = MEM_mallocN(bm->totvert * sizeof(int), __func__);
+ EDBM_verts_mirror_cache_begin_ex(
+ em, i, false, test_selected_only, use_topology, TRANSFORM_MAXDIST_MIRROR, index[i]);
+ }
+ }
+
+ BMVert *eve;
+ BMIter iter;
+
+ int quadrant[3];
+ {
+ float select_sum[3] = {0};
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ add_v3_v3(select_sum, eve->co);
+ }
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (mirror_axis[i]) {
+ quadrant[i] = select_sum[i] >= 0.0f ? 1 : -1;
+ }
+ else {
+ quadrant[i] = 0;
+ }
+ }
+ }
+
+ /* Tag only elements that will be transformed within the quadrant. */
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+ if ((!use_select || BM_elem_flag_test(eve, BM_ELEM_SELECT)) &&
+ is_in_quadrant_v3(eve->co, quadrant, TRANSFORM_MAXDIST_MIRROR)) {
+ BM_elem_flag_enable(eve, BM_ELEM_TAG);
+ BM_elem_index_set(eve, i);
+ }
+ else {
+ BM_elem_flag_disable(eve, BM_ELEM_TAG);
+ BM_elem_index_set(eve, -1);
+ }
+ }
+
+ for (int a = 0; a < 3; a++) {
+ int *index_iter = index[a];
+ if (index_iter == NULL) {
+ continue;
+ }
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+ if (test_selected_only && !BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ continue;
+ }
+ int elem_index = BM_elem_index_get(eve);
+ if (elem_index != -1) {
+ int i_mirr = index_iter[i];
+ if (i_mirr >= 0) {
+ BMVert *vmir = BM_vert_at_index(bm, i_mirr);
+ BM_elem_index_set(vmir, elem_index);
+
+ /* The slot of this element in the index array no longer needs to be read.
+ * Use to set the mirror sign. */
+ if (index[0] && a > 0) {
+ index[0][i_mirr] = index[0][i];
+ }
+ if (index[1] && a > 1) {
+ index[1][i_mirr] = index[1][i];
+ }
+ /* Use -2 to differ from -1, but both can work. */
+ index_iter[i_mirr] = -2;
+ }
+ }
+ }
+ }
+
+ /* Count mirror elements. */
+ uint mirror_elem_len = 0;
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN | BM_ELEM_TAG)) {
+ /* Not a mirror element. */
+ BM_elem_index_set(eve, -1);
+ continue;
+ }
+ int elem_index = BM_elem_index_get(eve);
+ if (elem_index != -1) {
+ mirror_elem_len++;
+ }
+ }
+
+ TransDataMirror *mirror_data_iter, *mirror_data = NULL;
+ if (mirror_elem_len != 0) {
+ mirror_data = MEM_mallocN(mirror_elem_len * sizeof(*mirror_data), __func__);
+ mirror_data_iter = &mirror_data[0];
+
+ *r_mirror_bitmap = BLI_BITMAP_NEW(bm->totvert, __func__);
+
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ int elem_index = BM_elem_index_get(eve);
+ if (elem_index != -1) {
+ BMVert *v_src = BM_vert_at_index(bm, elem_index);
+
+ mirror_data_iter->loc_src = v_src->co;
+ mirror_data_iter->loc_dst = eve->co;
+ mirror_data_iter->sign_x = index[0] && index[0][i] == -2 ? -1 : 1;
+ mirror_data_iter->sign_y = index[1] && index[1][i] == -2 ? -1 : 1;
+ mirror_data_iter->sign_z = index[2] && index[2][i] == -2 ? -1 : 1;
+ mirror_data_iter->extra = eve;
+
+ mirror_data_iter++;
+
+ BLI_BITMAP_ENABLE(*r_mirror_bitmap, i);
+ }
+ }
+ }
+
+ MEM_SAFE_FREE(index[0]);
+ MEM_SAFE_FREE(index[1]);
+ MEM_SAFE_FREE(index[2]);
+
+ bm->elem_index_dirty |= BM_VERT;
+ *r_mirror_data_len = mirror_elem_len;
+ return mirror_data;
+}
+
+/* way to overwrite what data is edited with transform */
+static void VertsToTransData(TransInfo *t,
+ TransData *td,
+ TransDataExtension *tx,
+ BMEditMesh *em,
+ BMVert *eve,
+ float *bweight,
+ struct TransIslandData *v_island,
+ const bool no_island_center)
+{
+ float *no, _no[3];
+ BLI_assert(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) == 0);
+
+ td->flag = 0;
+ // if (key)
+ // td->loc = key->co;
+ // else
+ td->loc = eve->co;
+ copy_v3_v3(td->iloc, td->loc);
+
+ if ((t->mode == TFM_SHRINKFATTEN) && (em->selectmode & SCE_SELECT_FACE) &&
+ BM_elem_flag_test(eve, BM_ELEM_SELECT) &&
+ (BM_vert_calc_normal_ex(eve, BM_ELEM_SELECT, _no))) {
+ no = _no;
+ }
+ else {
+ no = eve->no;
+ }
+
+ if (v_island) {
+ if (no_island_center) {
+ copy_v3_v3(td->center, td->loc);
+ }
+ else {
+ copy_v3_v3(td->center, v_island->co);
+ }
+ copy_m3_m3(td->axismtx, v_island->axismtx);
+ }
+ else if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ copy_v3_v3(td->center, td->loc);
+ createSpaceNormal(td->axismtx, no);
+ }
+ else {
+ copy_v3_v3(td->center, td->loc);
+
+ /* Setting normals */
+ copy_v3_v3(td->axismtx[2], no);
+ td->axismtx[0][0] = td->axismtx[0][1] = td->axismtx[0][2] = td->axismtx[1][0] =
+ td->axismtx[1][1] = td->axismtx[1][2] = 0.0f;
+ }
+
+ td->ext = NULL;
+ td->val = NULL;
+ td->extra = eve;
+ if (t->mode == TFM_BWEIGHT) {
+ td->val = bweight;
+ td->ival = *bweight;
+ }
+ else if (t->mode == TFM_SKIN_RESIZE) {
+ MVertSkin *vs = CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MVERT_SKIN);
+ if (vs) {
+ /* skin node size */
+ td->ext = tx;
+ copy_v3_v3(tx->isize, vs->radius);
+ tx->size = vs->radius;
+ td->val = vs->radius;
+ }
+ else {
+ td->flag |= TD_SKIP;
+ }
+ }
+ else if (t->mode == TFM_SHRINKFATTEN) {
+ td->ext = tx;
+ tx->isize[0] = BM_vert_calc_shell_factor_ex(eve, no, BM_ELEM_SELECT);
+ }
+}
+
+void createTransEditVerts(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *tob = NULL;
+ TransDataExtension *tx = NULL;
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ Mesh *me = tc->obedit->data;
+ BMesh *bm = em->bm;
+ BMVert *eve;
+ BMIter iter;
+ float(*mappedcos)[3] = NULL, (*quats)[4] = NULL;
+ float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL;
+ float *dists = NULL;
+ int a;
+ const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
+ int cd_vert_bweight_offset = -1;
+
+ struct TransIslandData *island_info = NULL;
+ int island_info_tot;
+ int *island_vert_map = NULL;
+
+ /* Snap rotation along normal needs a common axis for whole islands,
+ * otherwise one get random crazy results, see T59104.
+ * However, we do not want to use the island center for the pivot/translation reference. */
+ const bool is_snap_rotate = ((t->mode == TFM_TRANSLATION) &&
+ /* There is not guarantee that snapping
+ * is initialized yet at this point... */
+ (usingSnappingNormal(t) ||
+ (t->settings->snap_flag & SCE_SNAP_ROTATE) != 0) &&
+ (t->around != V3D_AROUND_LOCAL_ORIGINS));
+ /* Even for translation this is needed because of island-orientation, see: T51651. */
+ const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS) || is_snap_rotate;
+ /* Original index of our connected vertex when connected distances are calculated.
+ * Optional, allocate if needed. */
+ int *dists_index = NULL;
+
+ BLI_bitmap *mirror_bitmap = NULL;
+
+ /**
+ * Quick check if we can transform.
+ *
+ * \note ignore modes here, even in edge/face modes,
+ * transform data is created by selected vertices.
+ * \note in prop mode we need at least 1 selected.
+ */
+ if (bm->totvertsel == 0) {
+ goto cleanup;
+ }
+
+ if (t->mode == TFM_BWEIGHT) {
+ BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT);
+ cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
+ }
+
+ if (tc->mirror.use_mirror_any) {
+ bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+ bool use_select = (t->flag & T_PROP_EDIT) == 0;
+ bool mirror_axis[3] = {tc->mirror.axis_x, tc->mirror.axis_y, tc->mirror.axis_z};
+ tc->mirror.data = editmesh_mirror_data_calc(
+ em, use_select, use_topology, mirror_axis, &tc->mirror.data_len, &mirror_bitmap);
+ }
+
+ int data_len = 0;
+ if (prop_mode) {
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ data_len++;
+ }
+ }
+
+ /* allocating scratch arrays */
+ if (prop_mode & T_PROP_CONNECTED) {
+ dists = MEM_mallocN(em->bm->totvert * sizeof(float), __func__);
+ if (is_island_center) {
+ dists_index = MEM_mallocN(em->bm->totvert * sizeof(int), __func__);
+ }
+ }
+ }
+ else {
+ data_len = bm->totvertsel;
+ }
+
+ if (mirror_bitmap) {
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
+ if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ if (BLI_BITMAP_TEST(mirror_bitmap, a)) {
+ data_len--;
+ }
+ }
+ }
+ }
+
+ BLI_assert(data_len != 0);
+
+ tc->data_len = data_len;
+ tc->data = tob = MEM_callocN(data_len * sizeof(TransData), "TransObData(Mesh EditMode)");
+ if (ELEM(t->mode, TFM_SKIN_RESIZE, TFM_SHRINKFATTEN)) {
+ /* warning, this is overkill, we only need 2 extra floats,
+ * but this stores loads of extra stuff, for TFM_SHRINKFATTEN its even more overkill
+ * since we may not use the 'alt' transform mode to maintain shell thickness,
+ * but with generic transform code its hard to lazy init vars */
+ tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension),
+ "TransObData ext");
+ }
+
+ copy_m3_m4(mtx, tc->obedit->obmat);
+ /* we use a pseudo-inverse so that when one of the axes is scaled to 0,
+ * matrix inversion still works and we can still moving along the other */
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+
+ if (prop_mode & T_PROP_CONNECTED) {
+ editmesh_set_connectivity_distance(em->bm, mtx, dists, dists_index);
+ }
+
+ if (is_island_center) {
+ /* In this specific case, near-by vertices will need to know
+ * the island of the nearest connected vertex. */
+ const bool calc_single_islands = ((prop_mode & T_PROP_CONNECTED) &&
+ (t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ (em->selectmode & SCE_SELECT_VERTEX));
+
+ island_info = editmesh_islands_info_calc(
+ em, &island_info_tot, &island_vert_map, calc_single_islands);
+ }
+
+ /* detect CrazySpace [tm] */
+ if (modifiers_getCageIndex(t->scene, tc->obedit, NULL, 1) != -1) {
+ int totleft = -1;
+ if (modifiers_isCorrectableDeformed(t->scene, tc->obedit)) {
+ BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context));
+
+ /* Use evaluated state because we need b-bone cache. */
+ Scene *scene_eval = (Scene *)DEG_get_evaluated_id(t->depsgraph, &t->scene->id);
+ Object *obedit_eval = (Object *)DEG_get_evaluated_id(t->depsgraph, &tc->obedit->id);
+ BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval);
+ /* check if we can use deform matrices for modifier from the
+ * start up to stack, they are more accurate than quats */
+ totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh(
+ t->depsgraph, scene_eval, obedit_eval, em_eval, &defmats, &defcos);
+ }
+
+ /* if we still have more modifiers, also do crazyspace
+ * correction with quats, relative to the coordinates after
+ * the modifiers that support deform matrices (defcos) */
+
+#if 0 /* TODO, fix crazyspace+extrude so it can be enabled for general use - campbell */
+ if ((totleft > 0) || (totleft == -1))
+#else
+ if (totleft > 0)
+#endif
+ {
+ mappedcos = BKE_crazyspace_get_mapped_editverts(t->depsgraph, tc->obedit);
+ quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats");
+ BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode);
+ if (mappedcos) {
+ MEM_freeN(mappedcos);
+ }
+ }
+
+ if (defcos) {
+ MEM_freeN(defcos);
+ }
+ }
+
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
+ if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+ if (mirror_bitmap && BLI_BITMAP_TEST(mirror_bitmap, a)) {
+ continue;
+ }
+ if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ struct TransIslandData *v_island = NULL;
+ float *bweight = (cd_vert_bweight_offset != -1) ?
+ BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) :
+ NULL;
+
+ if (island_info) {
+ const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a;
+ v_island = (island_vert_map[connected_index] != -1) ?
+ &island_info[island_vert_map[connected_index]] :
+ NULL;
+ }
+
+ /* Do not use the island center in case we are using islands
+ * only to get axis for snap/rotate to normal... */
+ VertsToTransData(t, tob, tx, em, eve, bweight, v_island, is_snap_rotate);
+ if (tx) {
+ tx++;
+ }
+
+ /* selected */
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ tob->flag |= TD_SELECTED;
+ }
+
+ if (prop_mode) {
+ if (prop_mode & T_PROP_CONNECTED) {
+ tob->dist = dists[a];
+ }
+ else {
+ tob->flag |= TD_NOTCONNECTED;
+ tob->dist = FLT_MAX;
+ }
+ }
+
+ /* CrazySpace */
+ const bool use_quats = quats && BM_elem_flag_test(eve, BM_ELEM_TAG);
+ if (use_quats || defmats) {
+ float mat[3][3], qmat[3][3], imat[3][3];
+
+ /* Use both or either quat and defmat correction. */
+ if (use_quats) {
+ quat_to_mat3(qmat, quats[BM_elem_index_get(eve)]);
+
+ if (defmats) {
+ mul_m3_series(mat, defmats[a], qmat, mtx);
+ }
+ else {
+ mul_m3_m3m3(mat, mtx, qmat);
+ }
+ }
+ else {
+ mul_m3_m3m3(mat, mtx, defmats[a]);
+ }
+
+ invert_m3_m3(imat, mat);
+
+ copy_m3_m3(tob->smtx, imat);
+ copy_m3_m3(tob->mtx, mat);
+ }
+ else {
+ copy_m3_m3(tob->smtx, smtx);
+ copy_m3_m3(tob->mtx, mtx);
+ }
+
+ if (tc->mirror.use_mirror_any) {
+ if (tc->mirror.axis_x && fabsf(tob->loc[0]) < TRANSFORM_MAXDIST_MIRROR) {
+ tob->flag |= TD_MIRROR_EDGE_X;
+ }
+ if (tc->mirror.axis_y && fabsf(tob->loc[1]) < TRANSFORM_MAXDIST_MIRROR) {
+ tob->flag |= TD_MIRROR_EDGE_Y;
+ }
+ if (tc->mirror.axis_z && fabsf(tob->loc[2]) < TRANSFORM_MAXDIST_MIRROR) {
+ tob->flag |= TD_MIRROR_EDGE_Z;
+ }
+ }
+
+ tob++;
+ }
+ }
+
+ if (island_info) {
+ MEM_freeN(island_info);
+ MEM_freeN(island_vert_map);
+ }
+
+ cleanup:
+ /* crazy space free */
+ if (quats) {
+ MEM_freeN(quats);
+ }
+ if (defmats) {
+ MEM_freeN(defmats);
+ }
+ if (dists) {
+ MEM_freeN(dists);
+ }
+ if (dists_index) {
+ MEM_freeN(dists_index);
+ }
+ if (mirror_bitmap) {
+ MEM_freeN(mirror_bitmap);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name CustomData Layer Correction (for meshes)
+ *
+ * \{ */
+
+struct TransCustomDataLayerVert {
+ BMVert *v;
+ float co_orig_3d[3];
+ struct LinkNode **cd_loop_groups;
+};
+
+struct TransCustomDataLayer {
+ BMesh *bm;
+
+ int cd_loop_mdisp_offset;
+
+ /** map {BMVert: TransCustomDataLayerVert} */
+ struct GHash *origverts;
+ struct GHash *origfaces;
+ struct BMesh *bm_origfaces;
+
+ struct MemArena *arena;
+ /** Number of math BMLoop layers. */
+ int layer_math_map_num;
+ /** Array size of 'layer_math_map_num'
+ * maps TransCustomDataLayerVert.cd_group index to absolute CustomData layer index */
+ int *layer_math_map;
+
+ /* Array with all elements transformed. */
+ struct TransCustomDataLayerVert *data;
+ int data_len;
+};
+
+static void trans_mesh_customdata_free_cb(struct TransInfo *UNUSED(t),
+ struct TransDataContainer *UNUSED(tc),
+ struct TransCustomData *custom_data)
+{
+ struct TransCustomDataLayer *tcld = custom_data->data;
+ bmesh_edit_end(tcld->bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
+
+ if (tcld->bm_origfaces) {
+ BM_mesh_free(tcld->bm_origfaces);
+ }
+ if (tcld->origfaces) {
+ BLI_ghash_free(tcld->origfaces, NULL, NULL);
+ }
+ if (tcld->origverts) {
+ BLI_ghash_free(tcld->origverts, NULL, NULL);
+ }
+ if (tcld->arena) {
+ BLI_memarena_free(tcld->arena);
+ }
+ if (tcld->layer_math_map) {
+ MEM_freeN(tcld->layer_math_map);
+ }
+
+ MEM_freeN(tcld);
+ custom_data->data = NULL;
+}
+
+static void create_trans_vert_customdata_layer(BMVert *v,
+ struct TransCustomDataLayer *tcld,
+ struct TransCustomDataLayerVert *r_tcld_vert)
+{
+ BMesh *bm = tcld->bm;
+ BMIter liter;
+ int j, l_num;
+ float *loop_weights;
+
+ /* copy face data */
+ // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) {
+ BM_iter_init(&liter, bm, BM_LOOPS_OF_VERT, v);
+ l_num = liter.count;
+ loop_weights = BLI_array_alloca(loop_weights, l_num);
+ for (j = 0; j < l_num; j++) {
+ BMLoop *l = BM_iter_step(&liter);
+ BMLoop *l_prev, *l_next;
+ void **val_p;
+ if (!BLI_ghash_ensure_p(tcld->origfaces, l->f, &val_p)) {
+ BMFace *f_copy = BM_face_copy(tcld->bm_origfaces, bm, l->f, true, true);
+ *val_p = f_copy;
+ }
+
+ if ((l_prev = BM_loop_find_prev_nodouble(l, l->next, FLT_EPSILON)) &&
+ (l_next = BM_loop_find_next_nodouble(l, l_prev, FLT_EPSILON))) {
+ loop_weights[j] = angle_v3v3v3(l_prev->v->co, l->v->co, l_next->v->co);
+ }
+ else {
+ loop_weights[j] = 0.0f;
+ }
+ }
+
+ /* store cd_loop_groups */
+ if (tcld->layer_math_map_num && (l_num != 0)) {
+ r_tcld_vert->cd_loop_groups = BLI_memarena_alloc(tcld->arena,
+ tcld->layer_math_map_num * sizeof(void *));
+ for (j = 0; j < tcld->layer_math_map_num; j++) {
+ const int layer_nr = tcld->layer_math_map[j];
+ r_tcld_vert->cd_loop_groups[j] = BM_vert_loop_groups_data_layer_create(
+ bm, v, layer_nr, loop_weights, tcld->arena);
+ }
+ }
+ else {
+ r_tcld_vert->cd_loop_groups = NULL;
+ }
+
+ r_tcld_vert->v = v;
+ copy_v3_v3(r_tcld_vert->co_orig_3d, v->co);
+ BLI_ghash_insert(tcld->origverts, v, r_tcld_vert);
+}
+
+void trans_mesh_customdata_correction_init(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ BLI_assert(tc->custom.type.data == NULL);
+ int i;
+
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BMesh *bm = em->bm;
+
+ bool use_origfaces;
+ int cd_loop_mdisp_offset;
+ {
+ const bool has_layer_math = CustomData_has_math(&bm->ldata);
+ cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
+ if ((t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) &&
+ /* don't do this at all for non-basis shape keys, too easy to
+ * accidentally break uv maps or vertex colors then */
+ (bm->shapenr <= 1) && (has_layer_math || (cd_loop_mdisp_offset != -1))) {
+ use_origfaces = true;
+ }
+ else {
+ use_origfaces = false;
+ cd_loop_mdisp_offset = -1;
+ }
+ }
+
+ if (use_origfaces) {
+ /* create copies of faces for customdata projection */
+ bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
+
+ struct GHash *origfaces = BLI_ghash_ptr_new(__func__);
+ struct BMesh *bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){
+ .use_toolflags = false,
+ }));
+
+ /* we need to have matching customdata */
+ BM_mesh_copy_init_customdata(bm_origfaces, bm, NULL);
+
+ int *layer_math_map = NULL;
+ int layer_index_dst = 0;
+ {
+ /* TODO: We don't need `sod->layer_math_map` when there are no loops linked
+ * to one of the sliding vertices. */
+ if (CustomData_has_math(&bm->ldata)) {
+ /* over alloc, only 'math' layers are indexed */
+ layer_math_map = MEM_mallocN(bm->ldata.totlayer * sizeof(int), __func__);
+ for (i = 0; i < bm->ldata.totlayer; i++) {
+ if (CustomData_layer_has_math(&bm->ldata, i)) {
+ layer_math_map[layer_index_dst++] = i;
+ }
+ }
+ BLI_assert(layer_index_dst != 0);
+ }
+ }
+
+ struct TransCustomDataLayer *tcld;
+ tc->custom.type.data = tcld = MEM_mallocN(sizeof(*tcld), __func__);
+ tc->custom.type.free_cb = trans_mesh_customdata_free_cb;
+
+ tcld->bm = bm;
+ tcld->origfaces = origfaces;
+ tcld->bm_origfaces = bm_origfaces;
+ tcld->cd_loop_mdisp_offset = cd_loop_mdisp_offset;
+ tcld->layer_math_map = layer_math_map;
+ tcld->layer_math_map_num = layer_index_dst;
+ tcld->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+
+ int data_len = tc->data_len + tc->mirror.data_len;
+ struct GHash *origverts = BLI_ghash_ptr_new_ex(__func__, data_len);
+ tcld->origverts = origverts;
+
+ struct TransCustomDataLayerVert *tcld_vert, *tcld_vert_iter;
+ tcld_vert = BLI_memarena_alloc(tcld->arena, data_len * sizeof(*tcld_vert));
+ tcld_vert_iter = &tcld_vert[0];
+
+ TransData *tob;
+ for (i = tc->data_len, tob = tc->data; i--; tob++, tcld_vert_iter++) {
+ BMVert *v = tob->extra;
+ create_trans_vert_customdata_layer(v, tcld, tcld_vert_iter);
+ }
+
+ TransDataMirror *tdm;
+ for (i = tc->mirror.data_len, tdm = tc->mirror.data; i--; tdm++, tcld_vert_iter++) {
+ BMVert *v = tdm->extra;
+ create_trans_vert_customdata_layer(v, tcld, tcld_vert_iter);
+ }
+
+ tcld->data = tcld_vert;
+ tcld->data_len = data_len;
+ }
+ }
+}
+
+/**
+ * If we're sliding the vert, return its original location, if not, the current location is good.
+ */
+static const float *trans_vert_orig_co_get(struct TransCustomDataLayer *tcld, BMVert *v)
+{
+ struct TransCustomDataLayerVert *tcld_vert = BLI_ghash_lookup(tcld->origverts, v);
+ return tcld_vert ? tcld_vert->co_orig_3d : v->co;
+}
+
+static void trans_mesh_customdata_correction_apply_vert(struct TransCustomDataLayer *tcld,
+ struct TransCustomDataLayerVert *tcld_vert,
+ bool is_final)
+{
+ BMesh *bm = tcld->bm;
+ BMVert *v = tcld_vert->v;
+ const float *co_orig_3d = tcld_vert->co_orig_3d;
+ struct LinkNode **cd_loop_groups = tcld_vert->cd_loop_groups;
+
+ BMIter liter;
+ int j, l_num;
+ float *loop_weights;
+ const bool is_moved = (len_squared_v3v3(v->co, co_orig_3d) > FLT_EPSILON);
+ const bool do_loop_weight = tcld->layer_math_map_num && is_moved;
+ const bool do_loop_mdisps = is_final && is_moved && (tcld->cd_loop_mdisp_offset != -1);
+ const float *v_proj_axis = v->no;
+ /* original (l->prev, l, l->next) projections for each loop ('l' remains unchanged) */
+ float v_proj[3][3];
+
+ if (do_loop_weight || do_loop_mdisps) {
+ project_plane_normalized_v3_v3v3(v_proj[1], co_orig_3d, v_proj_axis);
+ }
+
+ // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT)
+ BM_iter_init(&liter, bm, BM_LOOPS_OF_VERT, v);
+ l_num = liter.count;
+ loop_weights = do_loop_weight ? BLI_array_alloca(loop_weights, l_num) : NULL;
+ for (j = 0; j < l_num; j++) {
+ BMFace *f_copy; /* the copy of 'f' */
+ BMLoop *l = BM_iter_step(&liter);
+
+ f_copy = BLI_ghash_lookup(tcld->origfaces, l->f);
+
+ /* only loop data, no vertex data since that contains shape keys,
+ * and we do not want to mess up other shape keys */
+ BM_loop_interp_from_face(bm, l, f_copy, false, false);
+
+ /* make sure face-attributes are correct (e.g. #MLoopUV, #MLoopCol) */
+ BM_elem_attrs_copy_ex(tcld->bm_origfaces, bm, f_copy, l->f, 0x0, CD_MASK_NORMAL);
+
+ /* weight the loop */
+ if (do_loop_weight) {
+ const float eps = 1.0e-8f;
+ const BMLoop *l_prev = l->prev;
+ const BMLoop *l_next = l->next;
+ const float *co_prev = trans_vert_orig_co_get(tcld, l_prev->v);
+ const float *co_next = trans_vert_orig_co_get(tcld, l_next->v);
+ bool co_prev_ok;
+ bool co_next_ok;
+
+ /* In the unlikely case that we're next to a zero length edge -
+ * walk around the to the next.
+ *
+ * Since we only need to check if the vertex is in this corner,
+ * its not important _which_ loop - as long as its not overlapping
+ * 'sv->co_orig_3d', see: T45096. */
+ project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
+ while (UNLIKELY(((co_prev_ok = (len_squared_v3v3(v_proj[1], v_proj[0]) > eps)) == false) &&
+ ((l_prev = l_prev->prev) != l->next))) {
+ co_prev = trans_vert_orig_co_get(tcld, l_prev->v);
+ project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
+ }
+ project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis);
+ while (UNLIKELY(((co_next_ok = (len_squared_v3v3(v_proj[1], v_proj[2]) > eps)) == false) &&
+ ((l_next = l_next->next) != l->prev))) {
+ co_next = trans_vert_orig_co_get(tcld, l_next->v);
+ project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis);
+ }
+
+ if (co_prev_ok && co_next_ok) {
+ const float dist = dist_signed_squared_to_corner_v3v3v3(
+ v->co, UNPACK3(v_proj), v_proj_axis);
+
+ loop_weights[j] = (dist >= 0.0f) ? 1.0f : ((dist <= -eps) ? 0.0f : (1.0f + (dist / eps)));
+ if (UNLIKELY(!isfinite(loop_weights[j]))) {
+ loop_weights[j] = 0.0f;
+ }
+ }
+ else {
+ loop_weights[j] = 0.0f;
+ }
+ }
+ }
+
+ if (tcld->layer_math_map_num && cd_loop_groups) {
+ if (do_loop_weight) {
+ for (j = 0; j < tcld->layer_math_map_num; j++) {
+ BM_vert_loop_groups_data_layer_merge_weights(
+ bm, cd_loop_groups[j], tcld->layer_math_map[j], loop_weights);
+ }
+ }
+ else {
+ for (j = 0; j < tcld->layer_math_map_num; j++) {
+ BM_vert_loop_groups_data_layer_merge(bm, cd_loop_groups[j], tcld->layer_math_map[j]);
+ }
+ }
+ }
+
+ /* Special handling for multires
+ *
+ * Interpolate from every other loop (not ideal)
+ * However values will only be taken from loops which overlap other mdisps.
+ * */
+ if (do_loop_mdisps) {
+ float(*faces_center)[3] = BLI_array_alloca(faces_center, l_num);
+ BMLoop *l;
+
+ BM_ITER_ELEM_INDEX (l, &liter, v, BM_LOOPS_OF_VERT, j) {
+ BM_face_calc_center_median(l->f, faces_center[j]);
+ }
+
+ BM_ITER_ELEM_INDEX (l, &liter, v, BM_LOOPS_OF_VERT, j) {
+ BMFace *f_copy = BLI_ghash_lookup(tcld->origfaces, l->f);
+ float f_copy_center[3];
+ BMIter liter_other;
+ BMLoop *l_other;
+ int j_other;
+
+ BM_face_calc_center_median(f_copy, f_copy_center);
+
+ BM_ITER_ELEM_INDEX (l_other, &liter_other, v, BM_LOOPS_OF_VERT, j_other) {
+ BM_face_interp_multires_ex(bm,
+ l_other->f,
+ f_copy,
+ faces_center[j_other],
+ f_copy_center,
+ tcld->cd_loop_mdisp_offset);
+ }
+ }
+ }
+}
+
+void trans_mesh_customdata_correction_apply(struct TransDataContainer *tc, bool is_final)
+{
+ struct TransCustomDataLayer *tcld = tc->custom.type.data;
+ if (!tcld) {
+ return;
+ }
+
+ const bool has_mdisps = (tcld->cd_loop_mdisp_offset != -1);
+ struct TransCustomDataLayerVert *tcld_vert_iter = &tcld->data[0];
+
+ for (int i = tcld->data_len; i--; tcld_vert_iter++) {
+ if (tcld_vert_iter->cd_loop_groups || has_mdisps) {
+ trans_mesh_customdata_correction_apply_vert(tcld, tcld_vert_iter, is_final);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edge (for crease) Transform Creation
+ *
+ * \{ */
+
+void createTransEdge(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ TransData *td = NULL;
+ BMEdge *eed;
+ BMIter iter;
+ float mtx[3][3], smtx[3][3];
+ int count = 0, countsel = 0;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ int cd_edge_float_offset;
+
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ countsel++;
+ }
+ if (is_prop_edit) {
+ count++;
+ }
+ }
+ }
+
+ if (countsel == 0) {
+ tc->data_len = 0;
+ continue;
+ }
+
+ if (is_prop_edit) {
+ tc->data_len = count;
+ }
+ else {
+ tc->data_len = countsel;
+ }
+
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransCrease");
+
+ copy_m3_m4(mtx, tc->obedit->obmat);
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+
+ /* create data we need */
+ if (t->mode == TFM_BWEIGHT) {
+ BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_BWEIGHT);
+ cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
+ }
+ else { // if (t->mode == TFM_CREASE) {
+ BLI_assert(t->mode == TFM_CREASE);
+ BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_CREASE);
+ cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
+ }
+
+ BLI_assert(cd_edge_float_offset != -1);
+
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) &&
+ (BM_elem_flag_test(eed, BM_ELEM_SELECT) || is_prop_edit)) {
+ float *fl_ptr;
+ /* need to set center for center calculations */
+ mid_v3_v3v3(td->center, eed->v1->co, eed->v2->co);
+
+ td->loc = NULL;
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ td->flag = TD_SELECTED;
+ }
+ else {
+ td->flag = 0;
+ }
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+
+ td->ext = NULL;
+
+ fl_ptr = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_float_offset);
+ td->val = fl_ptr;
+ td->ival = *fl_ptr;
+
+ td++;
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UVs Transform Creation
+ *
+ * \{ */
+
+static void UVsToTransData(const float aspect[2],
+ TransData *td,
+ TransData2D *td2d,
+ float *uv,
+ const float *center,
+ bool selected)
+{
+ /* uv coords are scaled by aspects. this is needed for rotations and
+ * proportional editing to be consistent with the stretched uv coords
+ * that are displayed. this also means that for display and numinput,
+ * and when the uv coords are flushed, these are converted each time */
+ td2d->loc[0] = uv[0] * aspect[0];
+ td2d->loc[1] = uv[1] * aspect[1];
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = uv;
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ copy_v2_v2(td->center, center ? center : td->loc);
+ td->center[2] = 0.0f;
+ copy_v3_v3(td->iloc, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ if (selected) {
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+ }
+ else {
+ td->dist = FLT_MAX;
+ }
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+}
+
+void createTransUVs(bContext *C, TransInfo *t)
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = CTX_data_edit_image(C);
+ Scene *scene = t->scene;
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0;
+ const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS);
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BMFace *efa;
+ BMIter iter, liter;
+ UvElementMap *elementmap = NULL;
+ BLI_bitmap *island_enabled = NULL;
+ struct {
+ float co[2];
+ int co_num;
+ } *island_center = NULL;
+ int count = 0, countsel = 0, count_rejected = 0;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (!ED_space_image_show_uvedit(sima, tc->obedit)) {
+ continue;
+ }
+
+ /* count */
+ if (is_prop_connected || is_island_center) {
+ /* create element map with island information */
+ const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0;
+ elementmap = BM_uv_element_map_create(em->bm, use_facesel, false, true);
+ if (elementmap == NULL) {
+ return;
+ }
+
+ if (is_prop_connected) {
+ island_enabled = BLI_BITMAP_NEW(elementmap->totalIslands, "TransIslandData(UV Editing)");
+ }
+
+ if (is_island_center) {
+ island_center = MEM_callocN(sizeof(*island_center) * elementmap->totalIslands, __func__);
+ }
+ }
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BMLoop *l;
+
+ if (!uvedit_face_visible_test(scene, tc->obedit, ima, efa)) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ continue;
+ }
+
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ countsel++;
+
+ if (is_prop_connected || island_center) {
+ UvElement *element = BM_uv_element_get(elementmap, efa, l);
+
+ if (is_prop_connected) {
+ BLI_BITMAP_ENABLE(island_enabled, element->island);
+ }
+
+ if (is_island_center) {
+ if (element->flag == false) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ add_v2_v2(island_center[element->island].co, luv->uv);
+ island_center[element->island].co_num++;
+ element->flag = true;
+ }
+ }
+ }
+ }
+
+ if (is_prop_edit) {
+ count++;
+ }
+ }
+ }
+
+ /* note: in prop mode we need at least 1 selected */
+ if (countsel == 0) {
+ goto finally;
+ }
+
+ if (is_island_center) {
+ int i;
+
+ for (i = 0; i < elementmap->totalIslands; i++) {
+ mul_v2_fl(island_center[i].co, 1.0f / island_center[i].co_num);
+ mul_v2_v2(island_center[i].co, t->aspect);
+ }
+ }
+
+ tc->data_len = (is_prop_edit) ? count : countsel;
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(UV Editing)");
+ /* for each 2d uv coord a 3d vector is allocated, so that they can be
+ * treated just as if they were 3d verts */
+ tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransObData2D(UV Editing)");
+
+ if (sima->flag & SI_CLIP_UV) {
+ t->flag |= T_CLIP_UV;
+ }
+
+ td = tc->data;
+ td2d = tc->data_2d;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BMLoop *l;
+
+ if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ const bool selected = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ MLoopUV *luv;
+ const float *center = NULL;
+
+ if (!is_prop_edit && !selected) {
+ continue;
+ }
+
+ if (is_prop_connected || is_island_center) {
+ UvElement *element = BM_uv_element_get(elementmap, efa, l);
+
+ if (is_prop_connected) {
+ if (!BLI_BITMAP_TEST(island_enabled, element->island)) {
+ count_rejected++;
+ continue;
+ }
+ }
+
+ if (is_island_center) {
+ center = island_center[element->island].co;
+ }
+ }
+
+ BM_elem_flag_enable(l, BM_ELEM_TAG);
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ UVsToTransData(t->aspect, td++, td2d++, luv->uv, center, selected);
+ }
+ }
+
+ if (is_prop_connected) {
+ tc->data_len -= count_rejected;
+ }
+
+ if (sima->flag & SI_LIVE_UNWRAP) {
+ ED_uvedit_live_unwrap_begin(t->scene, tc->obedit);
+ }
+
+ finally:
+ if (is_prop_connected || is_island_center) {
+ BM_uv_element_map_free(elementmap);
+
+ if (is_prop_connected) {
+ MEM_freeN(island_enabled);
+ }
+
+ if (island_center) {
+ MEM_freeN(island_center);
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UVs Transform Flush
+ *
+ * \{ */
+
+void flushTransUVs(TransInfo *t)
+{
+ SpaceImage *sima = t->sa->spacedata.first;
+ const bool use_pixel_snap = ((sima->pixel_snap_mode != SI_PIXEL_SNAP_DISABLED) &&
+ (t->state != TRANS_CANCEL));
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData2D *td;
+ int a;
+ float aspect_inv[2], size[2];
+
+ aspect_inv[0] = 1.0f / t->aspect[0];
+ aspect_inv[1] = 1.0f / t->aspect[1];
+
+ if (use_pixel_snap) {
+ int size_i[2];
+ ED_space_image_get_size(sima, &size_i[0], &size_i[1]);
+ size[0] = size_i[0];
+ size[1] = size_i[1];
+ }
+
+ /* flush to 2d vector from internally used 3d vector */
+ for (a = 0, td = tc->data_2d; a < tc->data_len; a++, td++) {
+ td->loc2d[0] = td->loc[0] * aspect_inv[0];
+ td->loc2d[1] = td->loc[1] * aspect_inv[1];
+
+ if (use_pixel_snap) {
+ td->loc2d[0] *= size[0];
+ td->loc2d[1] *= size[1];
+
+ switch (sima->pixel_snap_mode) {
+ case SI_PIXEL_SNAP_CENTER:
+ td->loc2d[0] = roundf(td->loc2d[0] - 0.5f) + 0.5f;
+ td->loc2d[1] = roundf(td->loc2d[1] - 0.5f) + 0.5f;
+ break;
+ case SI_PIXEL_SNAP_CORNER:
+ td->loc2d[0] = roundf(td->loc2d[0]);
+ td->loc2d[1] = roundf(td->loc2d[1]);
+ break;
+ }
+
+ td->loc2d[0] /= size[0];
+ td->loc2d[1] /= size[1];
+ }
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c
new file mode 100644
index 00000000000..114968ec83f
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_nla.c
@@ -0,0 +1,265 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_anim_types.h"
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_listbase.h"
+
+#include "BKE_nla.h"
+#include "BKE_context.h"
+#include "BKE_report.h"
+
+#include "ED_anim_api.h"
+
+#include "UI_view2d.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name NLA Transform Creation
+ *
+ * \{ */
+
+void createTransNlaData(bContext *C, TransInfo *t)
+{
+ Scene *scene = t->scene;
+ SpaceNla *snla = NULL;
+ TransData *td = NULL;
+ TransDataNla *tdn = NULL;
+
+ bAnimContext ac;
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ int count = 0;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* determine what type of data we are operating on */
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return;
+ }
+ snla = (SpaceNla *)ac.sl;
+
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* which side of the current frame should be allowed */
+ if (t->mode == TFM_TIME_EXTEND) {
+ /* only side on which mouse is gets transformed */
+ float xmouse, ymouse;
+
+ UI_view2d_region_to_view(&ac.ar->v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse);
+ t->frame_side = (xmouse > CFRA) ? 'R' : 'L';
+ }
+ else {
+ /* normal transform - both sides of current frame are considered */
+ t->frame_side = 'B';
+ }
+
+ /* loop 1: count how many strips are selected (consider each strip as 2 points) */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ NlaTrack *nlt = (NlaTrack *)ale->data;
+ NlaStrip *strip;
+
+ /* make some meta-strips for chains of selected strips */
+ BKE_nlastrips_make_metas(&nlt->strips, 1);
+
+ /* only consider selected strips */
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ // TODO: we can make strips have handles later on...
+ /* transition strips can't get directly transformed */
+ if (strip->type != NLASTRIP_TYPE_TRANSITION) {
+ if (strip->flag & NLASTRIP_FLAG_SELECT) {
+ if (FrameOnMouseSide(t->frame_side, strip->start, (float)CFRA)) {
+ count++;
+ }
+ if (FrameOnMouseSide(t->frame_side, strip->end, (float)CFRA)) {
+ count++;
+ }
+ }
+ }
+ }
+ }
+
+ /* stop if trying to build list if nothing selected */
+ if (count == 0) {
+ /* clear temp metas that may have been created but aren't needed now
+ * because they fell on the wrong side of CFRA
+ */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ NlaTrack *nlt = (NlaTrack *)ale->data;
+ BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
+ }
+
+ /* cleanup temp list */
+ ANIM_animdata_freelist(&anim_data);
+ return;
+ }
+
+ /* allocate memory for data */
+ tc->data_len = count;
+
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(NLA Editor)");
+ td = tc->data;
+ tc->custom.type.data = tdn = MEM_callocN(tc->data_len * sizeof(TransDataNla),
+ "TransDataNla (NLA Editor)");
+ tc->custom.type.use_free = true;
+
+ /* loop 2: build transdata array */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ /* only if a real NLA-track */
+ if (ale->type == ANIMTYPE_NLATRACK) {
+ AnimData *adt = ale->adt;
+ NlaTrack *nlt = (NlaTrack *)ale->data;
+ NlaStrip *strip;
+
+ /* only consider selected strips */
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ // TODO: we can make strips have handles later on...
+ /* transition strips can't get directly transformed */
+ if (strip->type != NLASTRIP_TYPE_TRANSITION) {
+ if (strip->flag & NLASTRIP_FLAG_SELECT) {
+ /* our transform data is constructed as follows:
+ * - only the handles on the right side of the current-frame get included
+ * - td structs are transform-elements operated on by the transform system
+ * and represent a single handle. The storage/pointer used (val or loc) depends on
+ * whether we're scaling or transforming. Ultimately though, the handles
+ * the td writes to will simply be a dummy in tdn
+ * - for each strip being transformed, a single tdn struct is used, so in some
+ * cases, there will need to be 1 of these tdn elements in the array skipped...
+ */
+ float center[3], yval;
+
+ /* firstly, init tdn settings */
+ tdn->id = ale->id;
+ tdn->oldTrack = tdn->nlt = nlt;
+ tdn->strip = strip;
+ tdn->trackIndex = BLI_findindex(&adt->nla_tracks, nlt);
+
+ yval = (float)(tdn->trackIndex * NLACHANNEL_STEP(snla));
+
+ tdn->h1[0] = strip->start;
+ tdn->h1[1] = yval;
+ tdn->h2[0] = strip->end;
+ tdn->h2[1] = yval;
+
+ center[0] = (float)CFRA;
+ center[1] = yval;
+ center[2] = 0.0f;
+
+ /* set td's based on which handles are applicable */
+ if (FrameOnMouseSide(t->frame_side, strip->start, (float)CFRA)) {
+ /* just set tdn to assume that it only has one handle for now */
+ tdn->handle = -1;
+
+ /* now, link the transform data up to this data */
+ if (ELEM(t->mode, TFM_TRANSLATION, TFM_TIME_EXTEND)) {
+ td->loc = tdn->h1;
+ copy_v3_v3(td->iloc, tdn->h1);
+
+ /* store all the other gunk that is required by transform */
+ copy_v3_v3(td->center, center);
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0f;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+ }
+ else {
+ /* time scaling only needs single value */
+ td->val = &tdn->h1[0];
+ td->ival = tdn->h1[0];
+ }
+
+ td->extra = tdn;
+ td++;
+ }
+ if (FrameOnMouseSide(t->frame_side, strip->end, (float)CFRA)) {
+ /* if tdn is already holding the start handle,
+ * then we're doing both, otherwise, only end */
+ tdn->handle = (tdn->handle) ? 2 : 1;
+
+ /* now, link the transform data up to this data */
+ if (ELEM(t->mode, TFM_TRANSLATION, TFM_TIME_EXTEND)) {
+ td->loc = tdn->h2;
+ copy_v3_v3(td->iloc, tdn->h2);
+
+ /* store all the other gunk that is required by transform */
+ copy_v3_v3(td->center, center);
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0f;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+ }
+ else {
+ /* time scaling only needs single value */
+ td->val = &tdn->h2[0];
+ td->ival = tdn->h2[0];
+ }
+
+ td->extra = tdn;
+ td++;
+ }
+
+ /* If both handles were used, skip the next tdn (i.e. leave it blank)
+ * since the counting code is dumb.
+ * Otherwise, just advance to the next one.
+ */
+ if (tdn->handle == 2) {
+ tdn += 2;
+ }
+ else {
+ tdn++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* cleanup temp list */
+ ANIM_animdata_freelist(&anim_data);
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.c
new file mode 100644
index 00000000000..41e3a79e4c9
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_node.c
@@ -0,0 +1,195 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_node.h"
+#include "BKE_report.h"
+
+#include "ED_node.h"
+
+#include "UI_interface.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Node Transform Creation
+ *
+ * \{ */
+
+/* transcribe given node into TransData2D for Transforming */
+static void NodeToTransData(TransData *td, TransData2D *td2d, bNode *node, const float dpi_fac)
+{
+ float locx, locy;
+
+ /* account for parents (nested nodes) */
+ if (node->parent) {
+ nodeToView(node->parent, node->locx, node->locy, &locx, &locy);
+ }
+ else {
+ locx = node->locx;
+ locy = node->locy;
+ }
+
+ /* use top-left corner as the transform origin for nodes */
+ /* weirdo - but the node system is a mix of free 2d elements and dpi sensitive UI */
+#ifdef USE_NODE_CENTER
+ td2d->loc[0] = (locx * dpi_fac) + (BLI_rctf_size_x(&node->totr) * +0.5f);
+ td2d->loc[1] = (locy * dpi_fac) + (BLI_rctf_size_y(&node->totr) * -0.5f);
+#else
+ td2d->loc[0] = locx * dpi_fac;
+ td2d->loc[1] = locy * dpi_fac;
+#endif
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = td2d->loc; /* current location */
+
+ td->flag = 0;
+
+ td->loc = td2d->loc;
+ copy_v3_v3(td->iloc, td->loc);
+ /* use node center instead of origin (top-left corner) */
+ td->center[0] = td2d->loc[0];
+ td->center[1] = td2d->loc[1];
+ td->center[2] = 0.0f;
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+
+ td->extra = node;
+}
+
+static bool is_node_parent_select(bNode *node)
+{
+ while ((node = node->parent)) {
+ if (node->flag & NODE_TRANSFORM) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
+{
+ const float dpi_fac = UI_DPI_FAC;
+ TransData *td;
+ TransData2D *td2d;
+ SpaceNode *snode = t->sa->spacedata.first;
+ bNode *node;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ tc->data_len = 0;
+
+ if (!snode->edittree) {
+ return;
+ }
+
+ /* nodes dont support PET and probably never will */
+ t->flag &= ~T_PROP_EDIT_ALL;
+
+ /* set transform flags on nodes */
+ for (node = snode->edittree->nodes.first; node; node = node->next) {
+ if (node->flag & NODE_SELECT && is_node_parent_select(node) == false) {
+ node->flag |= NODE_TRANSFORM;
+ tc->data_len++;
+ }
+ else {
+ node->flag &= ~NODE_TRANSFORM;
+ }
+ }
+
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransNode TransData");
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransNode TransData2D");
+
+ for (node = snode->edittree->nodes.first; node; node = node->next) {
+ if (node->flag & NODE_TRANSFORM) {
+ NodeToTransData(td++, td2d++, node, dpi_fac);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Transform Creation
+ *
+ * \{ */
+
+void flushTransNodes(TransInfo *t)
+{
+ const float dpi_fac = UI_DPI_FAC;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ int a;
+ TransData *td;
+ TransData2D *td2d;
+
+ applyGridAbsolute(t);
+
+ /* flush to 2d vector from internally used 3d vector */
+ for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
+ bNode *node = td->extra;
+ float locx, locy;
+
+ /* weirdo - but the node system is a mix of free 2d elements and dpi sensitive UI */
+#ifdef USE_NODE_CENTER
+ locx = (td2d->loc[0] - (BLI_rctf_size_x(&node->totr)) * +0.5f) / dpi_fac;
+ locy = (td2d->loc[1] - (BLI_rctf_size_y(&node->totr)) * -0.5f) / dpi_fac;
+#else
+ locx = td2d->loc[0] / dpi_fac;
+ locy = td2d->loc[1] / dpi_fac;
+#endif
+
+ /* account for parents (nested nodes) */
+ if (node->parent) {
+ nodeFromView(node->parent, locx, locy, &node->locx, &node->locy);
+ }
+ else {
+ node->locx = locx;
+ node->locy = locy;
+ }
+ }
+
+ /* handle intersection with noodles */
+ if (tc->data_len == 1) {
+ ED_node_link_intersect_test(t->sa, 1);
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c
new file mode 100644
index 00000000000..6e85f6b9bf0
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_object.c
@@ -0,0 +1,949 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_mesh_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_compiler_compat.h"
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_layer.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+#include "BKE_rigidbody.h"
+#include "BKE_scene.h"
+
+#include "ED_object.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Object Mode Custom Data
+ * \{ */
+
+typedef struct TransDataObject {
+
+ /**
+ * Object to object data transform table.
+ * Don't add these to transform data because we may want to include child objects
+ * which aren't being transformed.
+ * - The key is object data #ID.
+ * - The value is #XFormObjectData_Extra.
+ */
+ struct GHash *obdata_in_obmode_map;
+
+ /**
+ * Transform
+ * - The key is object data #Object.
+ * - The value is #XFormObjectSkipChild.
+ */
+ struct GHash *obchild_in_obmode_map;
+
+} TransDataObject;
+
+static void trans_obdata_in_obmode_free_all(TransDataObject *tdo);
+static void trans_obchild_in_obmode_free_all(TransDataObject *tdo);
+
+static void freeTransObjectCustomData(TransInfo *t,
+ TransDataContainer *UNUSED(tc),
+ TransCustomData *custom_data)
+{
+ TransDataObject *tdo = custom_data->data;
+ custom_data->data = NULL;
+
+ if (t->options & CTX_OBMODE_XFORM_OBDATA) {
+ trans_obdata_in_obmode_free_all(tdo);
+ }
+
+ if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) {
+ trans_obchild_in_obmode_free_all(tdo);
+ }
+ MEM_freeN(tdo);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Data in Object Mode
+ *
+ * Use to implement 'Affect Only Origins' feature.
+ * We need this to be detached from transform data because,
+ * unlike transforming regular objects, we need to transform the children.
+ *
+ * \{ */
+
+struct XFormObjectData_Extra {
+ Object *ob;
+ float obmat_orig[4][4];
+ struct XFormObjectData *xod;
+};
+
+static void trans_obdata_in_obmode_ensure_object(TransDataObject *tdo, Object *ob)
+{
+ if (tdo->obdata_in_obmode_map == NULL) {
+ tdo->obdata_in_obmode_map = BLI_ghash_ptr_new(__func__);
+ }
+
+ void **xf_p;
+ if (!BLI_ghash_ensure_p(tdo->obdata_in_obmode_map, ob->data, &xf_p)) {
+ struct XFormObjectData_Extra *xf = MEM_mallocN(sizeof(*xf), __func__);
+ copy_m4_m4(xf->obmat_orig, ob->obmat);
+ xf->ob = ob;
+ /* Result may be NULL, that's OK. */
+ xf->xod = ED_object_data_xform_create(ob->data);
+ *xf_p = xf;
+ }
+}
+
+void trans_obdata_in_obmode_update_all(TransInfo *t)
+{
+ TransDataObject *tdo = t->custom.type.data;
+ if (tdo->obdata_in_obmode_map == NULL) {
+ return;
+ }
+
+ struct Main *bmain = CTX_data_main(t->context);
+ BKE_scene_graph_evaluated_ensure(t->depsgraph, bmain);
+
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, tdo->obdata_in_obmode_map) {
+ ID *id = BLI_ghashIterator_getKey(&gh_iter);
+ struct XFormObjectData_Extra *xf = BLI_ghashIterator_getValue(&gh_iter);
+ if (xf->xod == NULL) {
+ continue;
+ }
+
+ Object *ob_eval = DEG_get_evaluated_object(t->depsgraph, xf->ob);
+ float imat[4][4], dmat[4][4];
+ invert_m4_m4(imat, xf->obmat_orig);
+ mul_m4_m4m4(dmat, imat, ob_eval->obmat);
+ invert_m4(dmat);
+
+ ED_object_data_xform_by_mat4(xf->xod, dmat);
+ if (xf->ob->type == OB_ARMATURE) {
+ /* TODO: none of the current flags properly update armatures, needs investigation. */
+ DEG_id_tag_update(id, 0);
+ }
+ else {
+ DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
+ }
+ }
+}
+
+/** Callback for #GHash free. */
+static void trans_obdata_in_obmode_free_elem(void *xf_p)
+{
+ struct XFormObjectData_Extra *xf = xf_p;
+ if (xf->xod) {
+ ED_object_data_xform_destroy(xf->xod);
+ }
+ MEM_freeN(xf);
+}
+
+static void trans_obdata_in_obmode_free_all(TransDataObject *tdo)
+{
+ if (tdo->obdata_in_obmode_map != NULL) {
+ BLI_ghash_free(tdo->obdata_in_obmode_map, NULL, trans_obdata_in_obmode_free_elem);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Child Skip
+ *
+ * Don't transform unselected children, this is done using the parent inverse matrix.
+ *
+ * \note The complex logic here is caused by mixed selection within a single selection chain,
+ * otherwise we only need #OB_SKIP_CHILD_PARENT_IS_XFORM for single objects.
+ *
+ * \{ */
+
+enum {
+ /**
+ * The parent is transformed, this is held in place.
+ */
+ OB_SKIP_CHILD_PARENT_IS_XFORM = 1,
+ /**
+ * The same as #OB_SKIP_CHILD_PARENT_IS_XFORM,
+ * however this objects parent isn't transformed directly.
+ */
+ OB_SKIP_CHILD_PARENT_IS_XFORM_INDIRECT = 3,
+ /**
+ * Use the parent invert matrix to apply transformation,
+ * this is needed, because breaks in the selection chain prevents this from being transformed.
+ * This is used to add the transform which would have been added
+ * if there weren't breaks in the parent/child chain.
+ */
+ OB_SKIP_CHILD_PARENT_APPLY_TRANSFORM = 2,
+};
+
+struct XFormObjectSkipChild {
+ float obmat_orig[4][4];
+ float parent_obmat_orig[4][4];
+ float parent_obmat_inv_orig[4][4];
+ float parent_recurse_obmat_orig[4][4];
+ float parentinv_orig[4][4];
+ Object *ob_parent_recurse;
+ int mode;
+};
+
+static void trans_obchild_in_obmode_ensure_object(TransDataObject *tdo,
+ Object *ob,
+ Object *ob_parent_recurse,
+ int mode)
+{
+ if (tdo->obchild_in_obmode_map == NULL) {
+ tdo->obchild_in_obmode_map = BLI_ghash_ptr_new(__func__);
+ }
+
+ void **xf_p;
+ if (!BLI_ghash_ensure_p(tdo->obchild_in_obmode_map, ob, &xf_p)) {
+ struct XFormObjectSkipChild *xf = MEM_mallocN(sizeof(*xf), __func__);
+ copy_m4_m4(xf->parentinv_orig, ob->parentinv);
+ copy_m4_m4(xf->obmat_orig, ob->obmat);
+ copy_m4_m4(xf->parent_obmat_orig, ob->parent->obmat);
+ invert_m4_m4(xf->parent_obmat_inv_orig, ob->parent->obmat);
+ if (ob_parent_recurse) {
+ copy_m4_m4(xf->parent_recurse_obmat_orig, ob_parent_recurse->obmat);
+ }
+ xf->mode = mode;
+ xf->ob_parent_recurse = ob_parent_recurse;
+ *xf_p = xf;
+ }
+}
+
+void trans_obchild_in_obmode_update_all(TransInfo *t)
+{
+ TransDataObject *tdo = t->custom.type.data;
+ if (tdo->obchild_in_obmode_map == NULL) {
+ return;
+ }
+
+ struct Main *bmain = CTX_data_main(t->context);
+ BKE_scene_graph_evaluated_ensure(t->depsgraph, bmain);
+
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, tdo->obchild_in_obmode_map) {
+ Object *ob = BLI_ghashIterator_getKey(&gh_iter);
+ struct XFormObjectSkipChild *xf = BLI_ghashIterator_getValue(&gh_iter);
+
+ /* The following blocks below assign 'dmat'. */
+ float dmat[4][4];
+
+ if (xf->mode == OB_SKIP_CHILD_PARENT_IS_XFORM) {
+ /* Parent is transformed, this isn't so compensate. */
+ Object *ob_parent_eval = DEG_get_evaluated_object(t->depsgraph, ob->parent);
+ mul_m4_m4m4(dmat, xf->parent_obmat_inv_orig, ob_parent_eval->obmat);
+ invert_m4(dmat);
+ }
+ else if (xf->mode == OB_SKIP_CHILD_PARENT_IS_XFORM_INDIRECT) {
+ /* Calculate parent matrix (from the root transform). */
+ Object *ob_parent_recurse_eval = DEG_get_evaluated_object(t->depsgraph,
+ xf->ob_parent_recurse);
+ float parent_recurse_obmat_inv[4][4];
+ invert_m4_m4(parent_recurse_obmat_inv, ob_parent_recurse_eval->obmat);
+ mul_m4_m4m4(dmat, xf->parent_recurse_obmat_orig, parent_recurse_obmat_inv);
+ invert_m4(dmat);
+ float parent_obmat_calc[4][4];
+ mul_m4_m4m4(parent_obmat_calc, dmat, xf->parent_obmat_orig);
+
+ /* Apply to the parent inverse matrix. */
+ mul_m4_m4m4(dmat, xf->parent_obmat_inv_orig, parent_obmat_calc);
+ invert_m4(dmat);
+ }
+ else {
+ BLI_assert(xf->mode == OB_SKIP_CHILD_PARENT_APPLY_TRANSFORM);
+ /* Transform this - without transform data. */
+ Object *ob_parent_recurse_eval = DEG_get_evaluated_object(t->depsgraph,
+ xf->ob_parent_recurse);
+ float parent_recurse_obmat_inv[4][4];
+ invert_m4_m4(parent_recurse_obmat_inv, ob_parent_recurse_eval->obmat);
+ mul_m4_m4m4(dmat, xf->parent_recurse_obmat_orig, parent_recurse_obmat_inv);
+ invert_m4(dmat);
+ float obmat_calc[4][4];
+ mul_m4_m4m4(obmat_calc, dmat, xf->obmat_orig);
+ /* obmat_calc is just obmat. */
+
+ /* Get the matrices relative to the parent. */
+ float obmat_parent_relative_orig[4][4];
+ float obmat_parent_relative_calc[4][4];
+ float obmat_parent_relative_inv_orig[4][4];
+
+ mul_m4_m4m4(obmat_parent_relative_orig, xf->parent_obmat_inv_orig, xf->obmat_orig);
+ mul_m4_m4m4(obmat_parent_relative_calc, xf->parent_obmat_inv_orig, obmat_calc);
+ invert_m4_m4(obmat_parent_relative_inv_orig, obmat_parent_relative_orig);
+
+ /* Apply to the parent inverse matrix. */
+ mul_m4_m4m4(dmat, obmat_parent_relative_calc, obmat_parent_relative_inv_orig);
+ }
+
+ mul_m4_m4m4(ob->parentinv, dmat, xf->parentinv_orig);
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+ }
+}
+
+static void trans_obchild_in_obmode_free_all(TransDataObject *tdo)
+{
+ if (tdo->obchild_in_obmode_map != NULL) {
+ BLI_ghash_free(tdo->obchild_in_obmode_map, NULL, MEM_freeN);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Transform Creation
+ *
+ * Instead of transforming the selection, move the 2D/3D cursor.
+ *
+ * \{ */
+
+/* *********************** Object Transform data ******************* */
+
+/* transcribe given object into TransData for Transforming */
+static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
+{
+ Scene *scene = t->scene;
+ bool constinv;
+ bool skip_invert = false;
+
+ if (t->mode != TFM_DUMMY && ob->rigidbody_object) {
+ float rot[3][3], scale[3];
+ float ctime = BKE_scene_frame_get(scene);
+
+ /* only use rigid body transform if simulation is running,
+ * avoids problems with initial setup of rigid bodies */
+ if (BKE_rigidbody_check_sim_running(scene->rigidbody_world, ctime)) {
+
+ /* save original object transform */
+ copy_v3_v3(td->ext->oloc, ob->loc);
+
+ if (ob->rotmode > 0) {
+ copy_v3_v3(td->ext->orot, ob->rot);
+ }
+ else if (ob->rotmode == ROT_MODE_AXISANGLE) {
+ td->ext->orotAngle = ob->rotAngle;
+ copy_v3_v3(td->ext->orotAxis, ob->rotAxis);
+ }
+ else {
+ copy_qt_qt(td->ext->oquat, ob->quat);
+ }
+ /* update object's loc/rot to get current rigid body transform */
+ mat4_to_loc_rot_size(ob->loc, rot, scale, ob->obmat);
+ sub_v3_v3(ob->loc, ob->dloc);
+ BKE_object_mat3_to_rot(ob, rot, false); /* drot is already corrected here */
+ }
+ }
+
+ /* axismtx has the real orientation */
+ copy_m3_m4(td->axismtx, ob->obmat);
+ normalize_m3(td->axismtx);
+
+ td->con = ob->constraints.first;
+
+ /* hack: temporarily disable tracking and/or constraints when getting
+ * object matrix, if tracking is on, or if constraints don't need
+ * inverse correction to stop it from screwing up space conversion
+ * matrix later
+ */
+ constinv = constraints_list_needinv(t, &ob->constraints);
+
+ /* disable constraints inversion for dummy pass */
+ if (t->mode == TFM_DUMMY) {
+ skip_invert = true;
+ }
+
+ /* NOTE: This is not really following copy-on-write design and we should not
+ * be re-evaluating the evaluated object. But as the comment above mentioned
+ * this is part of a hack.
+ * More proper solution would be to make a shallow copy of the object and
+ * evaluate that, and access matrix of that evaluated copy of the object.
+ * Might be more tricky than it sounds, if some logic later on accesses the
+ * object matrix via td->ob->obmat. */
+ Object *object_eval = DEG_get_evaluated_object(t->depsgraph, ob);
+ if (skip_invert == false && constinv == false) {
+ object_eval->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc checks this */
+ /* It is possible to have transform data initialization prior to a
+ * complete dependency graph evaluated. Happens, for example, when
+ * changing transformation mode. */
+ BKE_object_tfm_copy(object_eval, ob);
+ BKE_object_where_is_calc(t->depsgraph, t->scene, object_eval);
+ object_eval->transflag &= ~OB_NO_CONSTRAINTS;
+ }
+ else {
+ BKE_object_where_is_calc(t->depsgraph, t->scene, object_eval);
+ }
+ /* Copy newly evaluated fields to the original object, similar to how
+ * active dependency graph will do it. */
+ copy_m4_m4(ob->obmat, object_eval->obmat);
+ /* Only copy negative scale flag, this is the only flag which is modified by
+ * the BKE_object_where_is_calc(). The rest of the flags we need to keep,
+ * otherwise we might loose dupli flags (see T61787). */
+ ob->transflag &= ~OB_NEG_SCALE;
+ ob->transflag |= (object_eval->transflag & OB_NEG_SCALE);
+
+ td->ob = ob;
+
+ td->loc = ob->loc;
+ copy_v3_v3(td->iloc, td->loc);
+
+ if (ob->rotmode > 0) {
+ td->ext->rot = ob->rot;
+ td->ext->rotAxis = NULL;
+ td->ext->rotAngle = NULL;
+ td->ext->quat = NULL;
+
+ copy_v3_v3(td->ext->irot, ob->rot);
+ copy_v3_v3(td->ext->drot, ob->drot);
+ }
+ else if (ob->rotmode == ROT_MODE_AXISANGLE) {
+ td->ext->rot = NULL;
+ td->ext->rotAxis = ob->rotAxis;
+ td->ext->rotAngle = &ob->rotAngle;
+ td->ext->quat = NULL;
+
+ td->ext->irotAngle = ob->rotAngle;
+ copy_v3_v3(td->ext->irotAxis, ob->rotAxis);
+ // td->ext->drotAngle = ob->drotAngle; // XXX, not implemented
+ // copy_v3_v3(td->ext->drotAxis, ob->drotAxis); // XXX, not implemented
+ }
+ else {
+ td->ext->rot = NULL;
+ td->ext->rotAxis = NULL;
+ td->ext->rotAngle = NULL;
+ td->ext->quat = ob->quat;
+
+ copy_qt_qt(td->ext->iquat, ob->quat);
+ copy_qt_qt(td->ext->dquat, ob->dquat);
+ }
+ td->ext->rotOrder = ob->rotmode;
+
+ td->ext->size = ob->scale;
+ copy_v3_v3(td->ext->isize, ob->scale);
+ copy_v3_v3(td->ext->dscale, ob->dscale);
+
+ copy_v3_v3(td->center, ob->obmat[3]);
+
+ copy_m4_m4(td->ext->obmat, ob->obmat);
+
+ /* is there a need to set the global<->data space conversion matrices? */
+ if (ob->parent || constinv) {
+ float obmtx[3][3], totmat[3][3], obinv[3][3];
+
+ /* Get the effect of parenting, and/or certain constraints.
+ * NOTE: some Constraints, and also Tracking should never get this
+ * done, as it doesn't work well.
+ */
+ BKE_object_to_mat3(ob, obmtx);
+ copy_m3_m4(totmat, ob->obmat);
+ invert_m3_m3(obinv, totmat);
+ mul_m3_m3m3(td->smtx, obmtx, obinv);
+ invert_m3_m3(td->mtx, td->smtx);
+ }
+ else {
+ /* no conversion to/from dataspace */
+ unit_m3(td->smtx);
+ unit_m3(td->mtx);
+ }
+}
+
+static void trans_object_base_deps_flag_prepare(ViewLayer *view_layer)
+{
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ base->object->id.tag &= ~LIB_TAG_DOIT;
+ }
+}
+
+static void set_trans_object_base_deps_flag_cb(ID *id,
+ eDepsObjectComponentType component,
+ void *UNUSED(user_data))
+{
+ /* Here we only handle object IDs. */
+ if (GS(id->name) != ID_OB) {
+ return;
+ }
+ if (!ELEM(component, DEG_OB_COMP_TRANSFORM, DEG_OB_COMP_GEOMETRY)) {
+ return;
+ }
+ id->tag |= LIB_TAG_DOIT;
+}
+
+static void flush_trans_object_base_deps_flag(Depsgraph *depsgraph, Object *object)
+{
+ object->id.tag |= LIB_TAG_DOIT;
+ DEG_foreach_dependent_ID_component(depsgraph,
+ &object->id,
+ DEG_OB_COMP_TRANSFORM,
+ DEG_FOREACH_COMPONENT_IGNORE_TRANSFORM_SOLVERS,
+ set_trans_object_base_deps_flag_cb,
+ NULL);
+}
+
+static void trans_object_base_deps_flag_finish(const TransInfo *t, ViewLayer *view_layer)
+{
+
+ if ((t->options & CTX_OBMODE_XFORM_OBDATA) == 0) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->object->id.tag & LIB_TAG_DOIT) {
+ base->flag_legacy |= BA_SNAP_FIX_DEPS_FIASCO;
+ }
+ }
+ }
+}
+
+/* sets flags in Bases to define whether they take part in transform */
+/* it deselects Bases, so we have to call the clear function always after */
+static void set_trans_object_base_flags(TransInfo *t)
+{
+ Main *bmain = CTX_data_main(t->context);
+ ViewLayer *view_layer = t->view_layer;
+ View3D *v3d = t->view;
+ Scene *scene = t->scene;
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
+ /* NOTE: if Base selected and has parent selected:
+ * base->flag_legacy = BA_WAS_SEL
+ */
+ /* Don't do it if we're not actually going to recalculate anything. */
+ if (t->mode == TFM_DUMMY) {
+ return;
+ }
+ /* Makes sure base flags and object flags are identical. */
+ BKE_scene_base_flag_to_objects(t->view_layer);
+ /* Make sure depsgraph is here. */
+ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
+ /* Clear all flags we need. It will be used to detect dependencies. */
+ trans_object_base_deps_flag_prepare(view_layer);
+ /* Traverse all bases and set all possible flags. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ base->flag_legacy &= ~(BA_WAS_SEL | BA_TRANSFORM_LOCKED_IN_PLACE);
+ if (BASE_SELECTED_EDITABLE(v3d, base)) {
+ Object *ob = base->object;
+ Object *parsel = ob->parent;
+ /* If parent selected, deselect. */
+ while (parsel != NULL) {
+ if (parsel->base_flag & BASE_SELECTED) {
+ Base *parbase = BKE_view_layer_base_find(view_layer, parsel);
+ if (parbase != NULL) { /* in rare cases this can fail */
+ if (BASE_SELECTED_EDITABLE(v3d, parbase)) {
+ break;
+ }
+ }
+ }
+ parsel = parsel->parent;
+ }
+ if (parsel != NULL) {
+ /* Rotation around local centers are allowed to propagate. */
+ if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)) {
+ base->flag_legacy |= BA_TRANSFORM_CHILD;
+ }
+ else {
+ base->flag &= ~BASE_SELECTED;
+ base->flag_legacy |= BA_WAS_SEL;
+ }
+ }
+ flush_trans_object_base_deps_flag(depsgraph, ob);
+ }
+ }
+ /* Store temporary bits in base indicating that base is being modified
+ * (directly or indirectly) by transforming objects.
+ */
+ trans_object_base_deps_flag_finish(t, view_layer);
+}
+
+static bool mark_children(Object *ob)
+{
+ if (ob->flag & (SELECT | BA_TRANSFORM_CHILD)) {
+ return true;
+ }
+
+ if (ob->parent) {
+ if (mark_children(ob->parent)) {
+ ob->flag |= BA_TRANSFORM_CHILD;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int count_proportional_objects(TransInfo *t)
+{
+ int total = 0;
+ ViewLayer *view_layer = t->view_layer;
+ View3D *v3d = t->view;
+ struct Main *bmain = CTX_data_main(t->context);
+ Scene *scene = t->scene;
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
+ /* Clear all flags we need. It will be used to detect dependencies. */
+ trans_object_base_deps_flag_prepare(view_layer);
+ /* Rotations around local centers are allowed to propagate, so we take all objects. */
+ if (!((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL))) {
+ /* Mark all parents. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (BASE_SELECTED_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base)) {
+ Object *parent = base->object->parent;
+ /* flag all parents */
+ while (parent != NULL) {
+ parent->flag |= BA_TRANSFORM_PARENT;
+ parent = parent->parent;
+ }
+ }
+ }
+ /* Mark all children. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ /* all base not already selected or marked that is editable */
+ if ((base->object->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
+ (base->flag & BASE_SELECTED) == 0 &&
+ (BASE_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base))) {
+ mark_children(base->object);
+ }
+ }
+ }
+ /* Flush changed flags to all dependencies. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ Object *ob = base->object;
+ /* If base is not selected, not a parent of selection or not a child of
+ * selection and it is editable and selectable.
+ */
+ if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
+ (base->flag & BASE_SELECTED) == 0 &&
+ (BASE_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base))) {
+ flush_trans_object_base_deps_flag(depsgraph, ob);
+ total += 1;
+ }
+ }
+ /* Store temporary bits in base indicating that base is being modified
+ * (directly or indirectly) by transforming objects.
+ */
+ trans_object_base_deps_flag_finish(t, view_layer);
+ return total;
+}
+
+void clear_trans_object_base_flags(TransInfo *t)
+{
+ ViewLayer *view_layer = t->view_layer;
+ Base *base;
+
+ for (base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->flag_legacy & BA_WAS_SEL) {
+ ED_object_base_select(base, BA_SELECT);
+ }
+
+ base->flag_legacy &= ~(BA_WAS_SEL | BA_SNAP_FIX_DEPS_FIASCO | BA_TEMP_TAG |
+ BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT |
+ BA_TRANSFORM_LOCKED_IN_PLACE);
+ }
+}
+
+void createTransObject(bContext *C, TransInfo *t)
+{
+ TransData *td = NULL;
+ TransDataExtension *tx;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
+ set_trans_object_base_flags(t);
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* count */
+ tc->data_len = CTX_DATA_COUNT(C, selected_bases);
+
+ if (!tc->data_len) {
+ /* clear here, main transform function escapes too */
+ clear_trans_object_base_flags(t);
+ return;
+ }
+
+ if (is_prop_edit) {
+ tc->data_len += count_proportional_objects(t);
+ }
+
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransOb");
+ tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), "TransObExtension");
+
+ TransDataObject *tdo = MEM_callocN(sizeof(*tdo), __func__);
+ t->custom.type.data = tdo;
+ t->custom.type.free_cb = freeTransObjectCustomData;
+
+ CTX_DATA_BEGIN (C, Base *, base, selected_bases) {
+ Object *ob = base->object;
+
+ td->flag = TD_SELECTED;
+ td->protectflag = ob->protectflag;
+ td->ext = tx;
+ td->ext->rotOrder = ob->rotmode;
+
+ if (base->flag & BA_TRANSFORM_CHILD) {
+ td->flag |= TD_NOCENTER;
+ td->flag |= TD_NO_LOC;
+ }
+
+ /* select linked objects, but skip them later */
+ if (ID_IS_LINKED(ob)) {
+ td->flag |= TD_SKIP;
+ }
+
+ if (t->options & CTX_OBMODE_XFORM_OBDATA) {
+ ID *id = ob->data;
+ if (!id || id->lib) {
+ td->flag |= TD_SKIP;
+ }
+ else if (BKE_object_is_in_editmode(ob)) {
+ /* The object could have edit-mode data from another view-layer,
+ * it's such a corner-case it can be skipped for now - Campbell. */
+ td->flag |= TD_SKIP;
+ }
+ }
+
+ if (t->options & CTX_OBMODE_XFORM_OBDATA) {
+ if ((td->flag & TD_SKIP) == 0) {
+ trans_obdata_in_obmode_ensure_object(tdo, ob);
+ }
+ }
+
+ ObjectToTransData(t, td, ob);
+ td->val = NULL;
+ td++;
+ tx++;
+ }
+ CTX_DATA_END;
+
+ if (is_prop_edit) {
+ ViewLayer *view_layer = t->view_layer;
+ View3D *v3d = t->view;
+ Base *base;
+
+ for (base = view_layer->object_bases.first; base; base = base->next) {
+ Object *ob = base->object;
+
+ /* if base is not selected, not a parent of selection
+ * or not a child of selection and it is editable and selectable */
+ if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
+ (base->flag & BASE_SELECTED) == 0 && BASE_EDITABLE(v3d, base) &&
+ BASE_SELECTABLE(v3d, base)) {
+ td->protectflag = ob->protectflag;
+ td->ext = tx;
+ td->ext->rotOrder = ob->rotmode;
+
+ ObjectToTransData(t, td, ob);
+ td->val = NULL;
+ td++;
+ tx++;
+ }
+ }
+ }
+
+ if (t->options & CTX_OBMODE_XFORM_OBDATA) {
+ GSet *objects_in_transdata = BLI_gset_ptr_new_ex(__func__, tc->data_len);
+ td = tc->data;
+ for (int i = 0; i < tc->data_len; i++, td++) {
+ if ((td->flag & TD_SKIP) == 0) {
+ BLI_gset_add(objects_in_transdata, td->ob);
+ }
+ }
+
+ ViewLayer *view_layer = t->view_layer;
+ View3D *v3d = t->view;
+
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ Object *ob = base->object;
+
+ /* if base is not selected, not a parent of selection
+ * or not a child of selection and it is editable and selectable */
+ if ((base->flag_legacy & BA_WAS_SEL) && (base->flag & BASE_SELECTED) == 0 &&
+ BASE_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base)) {
+
+ Object *ob_parent = ob->parent;
+ if (ob_parent != NULL) {
+ if (!BLI_gset_haskey(objects_in_transdata, ob)) {
+ bool parent_in_transdata = false;
+ while (ob_parent != NULL) {
+ if (BLI_gset_haskey(objects_in_transdata, ob_parent)) {
+ parent_in_transdata = true;
+ break;
+ }
+ ob_parent = ob_parent->parent;
+ }
+ if (parent_in_transdata) {
+ trans_obdata_in_obmode_ensure_object(tdo, ob);
+ }
+ }
+ }
+ }
+ }
+ BLI_gset_free(objects_in_transdata, NULL);
+ }
+
+ if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) {
+
+#define BASE_XFORM_INDIRECT(base) \
+ ((base->flag_legacy & BA_WAS_SEL) && (base->flag & BASE_SELECTED) == 0)
+
+ GSet *objects_in_transdata = BLI_gset_ptr_new_ex(__func__, tc->data_len);
+ GHash *objects_parent_root = BLI_ghash_ptr_new_ex(__func__, tc->data_len);
+ td = tc->data;
+ for (int i = 0; i < tc->data_len; i++, td++) {
+ if ((td->flag & TD_SKIP) == 0) {
+ BLI_gset_add(objects_in_transdata, td->ob);
+ }
+ }
+
+ ViewLayer *view_layer = t->view_layer;
+
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ Object *ob = base->object;
+ if (ob->parent != NULL) {
+ if (ob->parent && !BLI_gset_haskey(objects_in_transdata, ob->parent) &&
+ !BLI_gset_haskey(objects_in_transdata, ob)) {
+ if (((base->flag_legacy & BA_WAS_SEL) && (base->flag & BASE_SELECTED) == 0)) {
+ Base *base_parent = BKE_view_layer_base_find(view_layer, ob->parent);
+ if (base_parent && !BASE_XFORM_INDIRECT(base_parent)) {
+ Object *ob_parent_recurse = ob->parent;
+ if (ob_parent_recurse != NULL) {
+ while (ob_parent_recurse != NULL) {
+ if (BLI_gset_haskey(objects_in_transdata, ob_parent_recurse)) {
+ break;
+ }
+ ob_parent_recurse = ob_parent_recurse->parent;
+ }
+
+ if (ob_parent_recurse) {
+ trans_obchild_in_obmode_ensure_object(
+ tdo, ob, ob_parent_recurse, OB_SKIP_CHILD_PARENT_APPLY_TRANSFORM);
+ BLI_ghash_insert(objects_parent_root, ob, ob_parent_recurse);
+ base->flag_legacy |= BA_TRANSFORM_LOCKED_IN_PLACE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ Object *ob = base->object;
+
+ if (BASE_XFORM_INDIRECT(base) || BLI_gset_haskey(objects_in_transdata, ob)) {
+ /* pass. */
+ }
+ else if (ob->parent != NULL) {
+ Base *base_parent = BKE_view_layer_base_find(view_layer, ob->parent);
+ if (base_parent) {
+ if (BASE_XFORM_INDIRECT(base_parent) ||
+ BLI_gset_haskey(objects_in_transdata, ob->parent)) {
+ trans_obchild_in_obmode_ensure_object(tdo, ob, NULL, OB_SKIP_CHILD_PARENT_IS_XFORM);
+ base->flag_legacy |= BA_TRANSFORM_LOCKED_IN_PLACE;
+ }
+ else {
+ Object *ob_parent_recurse = BLI_ghash_lookup(objects_parent_root, ob->parent);
+ if (ob_parent_recurse) {
+ trans_obchild_in_obmode_ensure_object(
+ tdo, ob, ob_parent_recurse, OB_SKIP_CHILD_PARENT_IS_XFORM_INDIRECT);
+ }
+ }
+ }
+ }
+ }
+ BLI_gset_free(objects_in_transdata, NULL);
+ BLI_ghash_free(objects_parent_root, NULL, NULL);
+
+#undef BASE_XFORM_INDIRECT
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Texture Space Transform Creation
+ *
+ * Instead of transforming the selection, move the 2D/3D cursor.
+ *
+ * \{ */
+
+void createTransTexspace(TransInfo *t)
+{
+ ViewLayer *view_layer = t->view_layer;
+ TransData *td;
+ Object *ob;
+ ID *id;
+ short *texflag;
+
+ ob = OBACT(view_layer);
+
+ if (ob == NULL) { // Shouldn't logically happen, but still...
+ return;
+ }
+
+ id = ob->data;
+ if (id == NULL || !ELEM(GS(id->name), ID_ME, ID_CU, ID_MB)) {
+ BKE_report(t->reports, RPT_ERROR, "Unsupported object type for text-space transform");
+ return;
+ }
+
+ if (BKE_object_obdata_is_libdata(ob)) {
+ BKE_report(t->reports, RPT_ERROR, "Linked data can't text-space transform");
+ return;
+ }
+
+ {
+ BLI_assert(t->data_container_len == 1);
+ TransDataContainer *tc = t->data_container;
+ tc->data_len = 1;
+ td = tc->data = MEM_callocN(sizeof(TransData), "TransTexspace");
+ td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
+ }
+
+ td->flag = TD_SELECTED;
+ copy_v3_v3(td->center, ob->obmat[3]);
+ td->ob = ob;
+
+ copy_m3_m4(td->mtx, ob->obmat);
+ copy_m3_m4(td->axismtx, ob->obmat);
+ normalize_m3(td->axismtx);
+ pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
+
+ if (BKE_object_obdata_texspace_get(ob, &texflag, &td->loc, &td->ext->size)) {
+ ob->dtx |= OB_TEXSPACE;
+ *texflag &= ~ME_AUTOSPACE;
+ }
+
+ zero_v3(td->ext->rot);
+
+ copy_v3_v3(td->iloc, td->loc);
+ copy_v3_v3(td->ext->irot, td->ext->rot);
+ copy_v3_v3(td->ext->isize, td->ext->size);
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_paintcurve.c b/source/blender/editors/transform/transform_convert_paintcurve.c
new file mode 100644
index 00000000000..6d46a94214e
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_paintcurve.c
@@ -0,0 +1,227 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_brush_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_paint.h"
+#include "BKE_report.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+typedef struct TransDataPaintCurve {
+ struct PaintCurvePoint *pcp; /* initial curve point */
+ char id;
+} TransDataPaintCurve;
+
+/* -------------------------------------------------------------------- */
+/** \name Paint Curve Transform Creation
+ *
+ * \{ */
+
+#define PC_IS_ANY_SEL(pc) (((pc)->bez.f1 | (pc)->bez.f2 | (pc)->bez.f3) & SELECT)
+
+static void PaintCurveConvertHandle(
+ PaintCurvePoint *pcp, int id, TransData2D *td2d, TransDataPaintCurve *tdpc, TransData *td)
+{
+ BezTriple *bezt = &pcp->bez;
+ copy_v2_v2(td2d->loc, bezt->vec[id]);
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = bezt->vec[id];
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ copy_v3_v3(td->center, bezt->vec[1]);
+ copy_v3_v3(td->iloc, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+
+ tdpc->id = id;
+ tdpc->pcp = pcp;
+}
+
+static void PaintCurvePointToTransData(PaintCurvePoint *pcp,
+ TransData *td,
+ TransData2D *td2d,
+ TransDataPaintCurve *tdpc)
+{
+ BezTriple *bezt = &pcp->bez;
+
+ if (pcp->bez.f2 == SELECT) {
+ int i;
+ for (i = 0; i < 3; i++) {
+ copy_v2_v2(td2d->loc, bezt->vec[i]);
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = bezt->vec[i];
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ copy_v3_v3(td->center, bezt->vec[1]);
+ copy_v3_v3(td->iloc, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+
+ tdpc->id = i;
+ tdpc->pcp = pcp;
+
+ td++;
+ td2d++;
+ tdpc++;
+ }
+ }
+ else {
+ if (bezt->f3 & SELECT) {
+ PaintCurveConvertHandle(pcp, 2, td2d, tdpc, td);
+ td2d++;
+ tdpc++;
+ td++;
+ }
+
+ if (bezt->f1 & SELECT) {
+ PaintCurveConvertHandle(pcp, 0, td2d, tdpc, td);
+ }
+ }
+}
+
+void createTransPaintCurveVerts(bContext *C, TransInfo *t)
+{
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ PaintCurve *pc;
+ PaintCurvePoint *pcp;
+ Brush *br;
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ TransDataPaintCurve *tdpc = NULL;
+ int i;
+ int total = 0;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ tc->data_len = 0;
+
+ if (!paint || !paint->brush || !paint->brush->paint_curve) {
+ return;
+ }
+
+ br = paint->brush;
+ pc = br->paint_curve;
+
+ for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) {
+ if (PC_IS_ANY_SEL(pcp)) {
+ if (pcp->bez.f2 & SELECT) {
+ total += 3;
+ continue;
+ }
+ else {
+ if (pcp->bez.f1 & SELECT) {
+ total++;
+ }
+ if (pcp->bez.f3 & SELECT) {
+ total++;
+ }
+ }
+ }
+ }
+
+ if (!total) {
+ return;
+ }
+
+ tc->data_len = total;
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransData2D");
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData");
+ tc->custom.type.data = tdpc = MEM_callocN(tc->data_len * sizeof(TransDataPaintCurve),
+ "TransDataPaintCurve");
+ tc->custom.type.use_free = true;
+
+ for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) {
+ if (PC_IS_ANY_SEL(pcp)) {
+ PaintCurvePointToTransData(pcp, td, td2d, tdpc);
+
+ if (pcp->bez.f2 & SELECT) {
+ td += 3;
+ td2d += 3;
+ tdpc += 3;
+ }
+ else {
+ if (pcp->bez.f1 & SELECT) {
+ td++;
+ td2d++;
+ tdpc++;
+ }
+ if (pcp->bez.f3 & SELECT) {
+ td++;
+ td2d++;
+ tdpc++;
+ }
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Paint Curve Transform Flush
+ *
+ * \{ */
+
+void flushTransPaintCurve(TransInfo *t)
+{
+ int i;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ TransData2D *td2d = tc->data_2d;
+ TransDataPaintCurve *tdpc = tc->custom.type.data;
+
+ for (i = 0; i < tc->data_len; i++, tdpc++, td2d++) {
+ PaintCurvePoint *pcp = tdpc->pcp;
+ copy_v2_v2(pcp->bez.vec[tdpc->id], td2d->loc);
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_particle.c b/source/blender/editors/transform/transform_convert_particle.c
new file mode 100644
index 00000000000..2a961da018b
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_particle.c
@@ -0,0 +1,248 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_particle_types.h"
+#include "DNA_modifier_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_report.h"
+#include "BKE_particle.h"
+#include "BKE_pointcache.h"
+
+#include "ED_particle.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Particle Edit Transform Creation
+ *
+ * \{ */
+
+void createTransParticleVerts(bContext *C, TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ TransData *td = NULL;
+ TransDataExtension *tx;
+ Object *ob = CTX_data_active_object(C);
+ ParticleEditSettings *pset = PE_settings(t->scene);
+ PTCacheEdit *edit = PE_get_current(t->depsgraph, t->scene, ob);
+ ParticleSystem *psys = NULL;
+ PTCacheEditPoint *point;
+ PTCacheEditKey *key;
+ float mat[4][4];
+ int i, k, transformparticle;
+ int count = 0, hasselected = 0;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
+ if (edit == NULL || t->settings->particle.selectmode == SCE_SELECT_PATH) {
+ return;
+ }
+
+ psys = edit->psys;
+
+ for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) {
+ point->flag &= ~PEP_TRANSFORM;
+ transformparticle = 0;
+
+ if ((point->flag & PEP_HIDE) == 0) {
+ for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
+ if ((key->flag & PEK_HIDE) == 0) {
+ if (key->flag & PEK_SELECT) {
+ hasselected = 1;
+ transformparticle = 1;
+ }
+ else if (is_prop_edit) {
+ transformparticle = 1;
+ }
+ }
+ }
+ }
+
+ if (transformparticle) {
+ count += point->totkey;
+ point->flag |= PEP_TRANSFORM;
+ }
+ }
+
+ /* note: in prop mode we need at least 1 selected */
+ if (hasselected == 0) {
+ return;
+ }
+
+ tc->data_len = count;
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Particle Mode)");
+
+ if (t->mode == TFM_BAKE_TIME) {
+ tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension),
+ "Particle_TransExtension");
+ }
+ else {
+ tx = tc->data_ext = NULL;
+ }
+
+ unit_m4(mat);
+
+ invert_m4_m4(ob->imat, ob->obmat);
+
+ for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) {
+ TransData *head, *tail;
+ head = tail = td;
+
+ if (!(point->flag & PEP_TRANSFORM)) {
+ continue;
+ }
+
+ if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
+ ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
+ psys_mat_hair_to_global(
+ ob, psmd_eval->mesh_final, psys->part->from, psys->particles + i, mat);
+ }
+
+ for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
+ if (key->flag & PEK_USE_WCO) {
+ copy_v3_v3(key->world_co, key->co);
+ mul_m4_v3(mat, key->world_co);
+ td->loc = key->world_co;
+ }
+ else {
+ td->loc = key->co;
+ }
+
+ copy_v3_v3(td->iloc, td->loc);
+ copy_v3_v3(td->center, td->loc);
+
+ if (key->flag & PEK_SELECT) {
+ td->flag |= TD_SELECTED;
+ }
+ else if (!is_prop_edit) {
+ td->flag |= TD_SKIP;
+ }
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+
+ /* don't allow moving roots */
+ if (k == 0 && pset->flag & PE_LOCK_FIRST && (!psys || !(psys->flag & PSYS_GLOBAL_HAIR))) {
+ td->protectflag |= OB_LOCK_LOC;
+ }
+
+ td->ob = ob;
+ td->ext = tx;
+ if (t->mode == TFM_BAKE_TIME) {
+ td->val = key->time;
+ td->ival = *(key->time);
+ /* abuse size and quat for min/max values */
+ td->flag |= TD_NO_EXT;
+ if (k == 0) {
+ tx->size = NULL;
+ }
+ else {
+ tx->size = (key - 1)->time;
+ }
+
+ if (k == point->totkey - 1) {
+ tx->quat = NULL;
+ }
+ else {
+ tx->quat = (key + 1)->time;
+ }
+ }
+
+ td++;
+ if (tx) {
+ tx++;
+ }
+ tail++;
+ }
+ if (is_prop_edit && head != tail) {
+ calc_distanceCurveVerts(head, tail - 1);
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Transform Creation
+ *
+ * \{ */
+
+void flushTransParticles(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Scene *scene = t->scene;
+ ViewLayer *view_layer = t->view_layer;
+ Object *ob = OBACT(view_layer);
+ PTCacheEdit *edit = PE_get_current(t->depsgraph, scene, ob);
+ ParticleSystem *psys = edit->psys;
+ PTCacheEditPoint *point;
+ PTCacheEditKey *key;
+ TransData *td;
+ float mat[4][4], imat[4][4], co[3];
+ int i, k;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
+ /* we do transform in world space, so flush world space position
+ * back to particle local space (only for hair particles) */
+ td = tc->data;
+ for (i = 0, point = edit->points; i < edit->totpoint; i++, point++, td++) {
+ if (!(point->flag & PEP_TRANSFORM)) {
+ continue;
+ }
+
+ if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
+ ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
+ psys_mat_hair_to_global(
+ ob, psmd_eval->mesh_final, psys->part->from, psys->particles + i, mat);
+ invert_m4_m4(imat, mat);
+
+ for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
+ copy_v3_v3(co, key->world_co);
+ mul_m4_v3(imat, co);
+
+ /* optimization for proportional edit */
+ if (!is_prop_edit || !compare_v3v3(key->co, co, 0.0001f)) {
+ copy_v3_v3(key->co, co);
+ point->flag |= PEP_EDIT_RECALC;
+ }
+ }
+ }
+ else {
+ point->flag |= PEP_EDIT_RECALC;
+ }
+ }
+
+ PE_update_object(t->depsgraph, scene, OBACT(view_layer), 1);
+ BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
+ DEG_id_tag_update(&ob->id, ID_RECALC_PSYS_REDO);
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_sculpt.c b/source/blender/editors/transform/transform_convert_sculpt.c
new file mode 100644
index 00000000000..6b584f806b8
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_sculpt.c
@@ -0,0 +1,105 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_paint.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Transform Creation
+ *
+ * \{ */
+
+void createTransSculpt(TransInfo *t)
+{
+ TransData *td;
+
+ Scene *scene = t->scene;
+ if (ID_IS_LINKED(scene)) {
+ BKE_report(t->reports, RPT_ERROR, "Linked data can't text-space transform");
+ return;
+ }
+
+ Object *ob = CTX_data_active_object(t->context);
+ SculptSession *ss = ob->sculpt;
+
+ {
+ BLI_assert(t->data_container_len == 1);
+ TransDataContainer *tc = t->data_container;
+ tc->data_len = 1;
+ tc->is_active = 1;
+ td = tc->data = MEM_callocN(sizeof(TransData), "TransSculpt");
+ td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransSculpt");
+ }
+
+ td->flag = TD_SELECTED;
+ copy_v3_v3(td->center, ss->pivot_pos);
+ mul_m4_v3(ob->obmat, td->center);
+ td->ob = ob;
+
+ td->loc = ss->pivot_pos;
+ copy_v3_v3(td->iloc, ss->pivot_pos);
+
+ if (is_zero_v4(ss->pivot_rot)) {
+ ss->pivot_rot[3] = 1.0f;
+ }
+
+ float obmat_inv[3][3];
+ copy_m3_m4(obmat_inv, ob->obmat);
+ invert_m3(obmat_inv);
+
+ td->ext->rot = NULL;
+ td->ext->rotAxis = NULL;
+ td->ext->rotAngle = NULL;
+ td->ext->quat = ss->pivot_rot;
+ copy_m4_m4(td->ext->obmat, ob->obmat);
+ copy_m3_m3(td->ext->l_smtx, obmat_inv);
+ copy_m3_m4(td->ext->r_mtx, ob->obmat);
+ copy_m3_m3(td->ext->r_smtx, obmat_inv);
+
+ copy_qt_qt(td->ext->iquat, ss->pivot_rot);
+ td->ext->rotOrder = ROT_MODE_QUAT;
+
+ ss->pivot_scale[0] = 1.0f;
+ ss->pivot_scale[1] = 1.0f;
+ ss->pivot_scale[2] = 1.0f;
+ td->ext->size = ss->pivot_scale;
+ copy_v3_v3(ss->init_pivot_scale, ss->pivot_scale);
+ copy_v3_v3(td->ext->isize, ss->init_pivot_scale);
+
+ copy_m3_m3(td->smtx, obmat_inv);
+ copy_m3_m4(td->mtx, ob->obmat);
+ copy_m3_m4(td->axismtx, ob->obmat);
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
new file mode 100644
index 00000000000..86b6ebe3ffa
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -0,0 +1,769 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_sequencer.h"
+#include "BKE_report.h"
+
+#include "UI_view2d.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Sequencer Transform Creation
+ *
+ * \{ */
+
+/* This function applies the rules for transforming a strip so duplicate
+ * checks don't need to be added in multiple places.
+ *
+ * recursive, count and flag MUST be set.
+ *
+ * seq->depth must be set before running this function so we know if the strips
+ * are root level or not
+ */
+static void SeqTransInfo(TransInfo *t, Sequence *seq, int *recursive, int *count, int *flag)
+{
+ /* for extend we need to do some tricks */
+ if (t->mode == TFM_TIME_EXTEND) {
+
+ /* *** Extend Transform *** */
+
+ Scene *scene = t->scene;
+ int cfra = CFRA;
+ int left = BKE_sequence_tx_get_final_left(seq, true);
+ int right = BKE_sequence_tx_get_final_right(seq, true);
+
+ if (seq->depth == 0 && ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK))) {
+ *recursive = false;
+ *count = 0;
+ *flag = 0;
+ }
+ else if (seq->type == SEQ_TYPE_META) {
+
+ /* for meta's we only ever need to extend their children, no matter what depth
+ * just check the meta's are in the bounds */
+ if (t->frame_side == 'R' && right <= cfra) {
+ *recursive = false;
+ }
+ else if (t->frame_side == 'L' && left >= cfra) {
+ *recursive = false;
+ }
+ else {
+ *recursive = true;
+ }
+
+ *count = 1;
+ *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
+ }
+ else {
+
+ *recursive = false; /* not a meta, so no thinking here */
+ *count = 1; /* unless its set to 0, extend will never set 2 handles at once */
+ *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
+
+ if (t->frame_side == 'R') {
+ if (right <= cfra) {
+ *count = *flag = 0;
+ } /* ignore */
+ else if (left > cfra) {
+ } /* keep the selection */
+ else {
+ *flag |= SEQ_RIGHTSEL;
+ }
+ }
+ else {
+ if (left >= cfra) {
+ *count = *flag = 0;
+ } /* ignore */
+ else if (right < cfra) {
+ } /* keep the selection */
+ else {
+ *flag |= SEQ_LEFTSEL;
+ }
+ }
+ }
+ }
+ else {
+
+ t->frame_side = 'B';
+
+ /* *** Normal Transform *** */
+
+ if (seq->depth == 0) {
+
+ /* Count */
+
+ /* Non nested strips (resect selection and handles) */
+ if ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK)) {
+ *recursive = false;
+ *count = 0;
+ *flag = 0;
+ }
+ else {
+ if ((seq->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) == (SEQ_LEFTSEL | SEQ_RIGHTSEL)) {
+ *flag = seq->flag;
+ *count = 2; /* we need 2 transdata's */
+ }
+ else {
+ *flag = seq->flag;
+ *count = 1; /* selected or with a handle selected */
+ }
+
+ /* Recursive */
+
+ if ((seq->type == SEQ_TYPE_META) && ((seq->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) == 0)) {
+ /* if any handles are selected, don't recurse */
+ *recursive = true;
+ }
+ else {
+ *recursive = false;
+ }
+ }
+ }
+ else {
+ /* Nested, different rules apply */
+
+#ifdef SEQ_TX_NESTED_METAS
+ *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
+ *count = 1; /* ignore the selection for nested */
+ *recursive = (seq->type == SEQ_TYPE_META);
+#else
+ if (seq->type == SEQ_TYPE_META) {
+ /* Meta's can only directly be moved between channels since they
+ * don't have their start and length set directly (children affect that)
+ * since this Meta is nested we don't need any of its data in fact.
+ * BKE_sequence_calc() will update its settings when run on the top-level meta. */
+ *flag = 0;
+ *count = 0;
+ *recursive = true;
+ }
+ else {
+ *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
+ *count = 1; /* ignore the selection for nested */
+ *recursive = false;
+ }
+#endif
+ }
+ }
+}
+
+static int SeqTransCount(TransInfo *t, Sequence *parent, ListBase *seqbase, int depth)
+{
+ Sequence *seq;
+ int tot = 0, recursive, count, flag;
+
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ seq->depth = depth;
+
+ /* 'seq->tmp' is used by seq_tx_get_final_{left, right}
+ * to check sequence's range and clamp to it if needed.
+ * It's first place where digging into sequences tree, so store link to parent here. */
+ seq->tmp = parent;
+
+ SeqTransInfo(t, seq, &recursive, &count, &flag); /* ignore the flag */
+ tot += count;
+
+ if (recursive) {
+ tot += SeqTransCount(t, seq, &seq->seqbase, depth + 1);
+ }
+ }
+
+ return tot;
+}
+
+static TransData *SeqToTransData(
+ TransData *td, TransData2D *td2d, TransDataSeq *tdsq, Sequence *seq, int flag, int sel_flag)
+{
+ int start_left;
+
+ switch (sel_flag) {
+ case SELECT:
+ /* Use seq_tx_get_final_left() and an offset here
+ * so transform has the left hand location of the strip.
+ * tdsq->start_offset is used when flushing the tx data back */
+ start_left = BKE_sequence_tx_get_final_left(seq, false);
+ td2d->loc[0] = start_left;
+ tdsq->start_offset = start_left - seq->start; /* use to apply the original location */
+ break;
+ case SEQ_LEFTSEL:
+ start_left = BKE_sequence_tx_get_final_left(seq, false);
+ td2d->loc[0] = start_left;
+ break;
+ case SEQ_RIGHTSEL:
+ td2d->loc[0] = BKE_sequence_tx_get_final_right(seq, false);
+ break;
+ }
+
+ td2d->loc[1] = seq->machine; /* channel - Y location */
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = NULL;
+
+ tdsq->seq = seq;
+
+ /* Use instead of seq->flag for nested strips and other
+ * cases where the selection may need to be modified */
+ tdsq->flag = flag;
+ tdsq->sel_flag = sel_flag;
+
+ td->extra = (void *)tdsq; /* allow us to update the strip from here */
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ copy_v3_v3(td->center, td->loc);
+ copy_v3_v3(td->iloc, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+
+ /* Time Transform (extend) */
+ td->val = td2d->loc;
+ td->ival = td2d->loc[0];
+
+ return td;
+}
+
+static int SeqToTransData_Recursive(
+ TransInfo *t, ListBase *seqbase, TransData *td, TransData2D *td2d, TransDataSeq *tdsq)
+{
+ Sequence *seq;
+ int recursive, count, flag;
+ int tot = 0;
+
+ for (seq = seqbase->first; seq; seq = seq->next) {
+
+ SeqTransInfo(t, seq, &recursive, &count, &flag);
+
+ /* add children first so recalculating metastrips does nested strips first */
+ if (recursive) {
+ int tot_children = SeqToTransData_Recursive(t, &seq->seqbase, td, td2d, tdsq);
+
+ td = td + tot_children;
+ td2d = td2d + tot_children;
+ tdsq = tdsq + tot_children;
+
+ tot += tot_children;
+ }
+
+ /* use 'flag' which is derived from seq->flag but modified for special cases */
+ if (flag & SELECT) {
+ if (flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) {
+ if (flag & SEQ_LEFTSEL) {
+ SeqToTransData(td++, td2d++, tdsq++, seq, flag, SEQ_LEFTSEL);
+ tot++;
+ }
+ if (flag & SEQ_RIGHTSEL) {
+ SeqToTransData(td++, td2d++, tdsq++, seq, flag, SEQ_RIGHTSEL);
+ tot++;
+ }
+ }
+ else {
+ SeqToTransData(td++, td2d++, tdsq++, seq, flag, SELECT);
+ tot++;
+ }
+ }
+ }
+ return tot;
+}
+
+static void SeqTransDataBounds(TransInfo *t, ListBase *seqbase, TransSeq *ts)
+{
+ Sequence *seq;
+ int recursive, count, flag;
+ int max = INT32_MIN, min = INT32_MAX;
+
+ for (seq = seqbase->first; seq; seq = seq->next) {
+
+ /* just to get the flag since there are corner cases where this isn't totally obvious */
+ SeqTransInfo(t, seq, &recursive, &count, &flag);
+
+ /* use 'flag' which is derived from seq->flag but modified for special cases */
+ if (flag & SELECT) {
+ if (flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) {
+ if (flag & SEQ_LEFTSEL) {
+ min = min_ii(seq->startdisp, min);
+ max = max_ii(seq->startdisp, max);
+ }
+ if (flag & SEQ_RIGHTSEL) {
+ min = min_ii(seq->enddisp, min);
+ max = max_ii(seq->enddisp, max);
+ }
+ }
+ else {
+ min = min_ii(seq->startdisp, min);
+ max = max_ii(seq->enddisp, max);
+ }
+ }
+ }
+
+ if (ts) {
+ ts->max = max;
+ ts->min = min;
+ }
+}
+
+static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data)
+{
+ Editing *ed = BKE_sequencer_editing_get(t->scene, false);
+
+ if (ed != NULL) {
+
+ ListBase *seqbasep = ed->seqbasep;
+ TransData *td = tc->data;
+ int a;
+
+ /* prevent updating the same seq twice
+ * if the transdata order is changed this will mess up
+ * but so will TransDataSeq */
+ Sequence *seq_prev = NULL;
+ Sequence *seq;
+
+ if (!(t->state == TRANS_CANCEL)) {
+
+#if 0 // default 2.4 behavior
+
+ /* flush to 2d vector from internally used 3d vector */
+ for (a = 0; a < t->total; a++, td++) {
+ if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) {
+ seq = ((TransDataSeq *)td->extra)->seq;
+ BKE_sequence_base_shuffle(seqbasep, seq, t->scene);
+ }
+
+ seq_prev = seq;
+ }
+
+#else // durian hack
+ {
+ int overlap = 0;
+
+ for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
+ seq = ((TransDataSeq *)td->extra)->seq;
+ if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) {
+ overlap = 1;
+ break;
+ }
+ }
+
+ if (overlap) {
+ bool has_effect_root = false, has_effect_any = false;
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ seq->tmp = NULL;
+ }
+
+ td = tc->data;
+ for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
+ seq = ((TransDataSeq *)td->extra)->seq;
+ if ((seq != seq_prev)) {
+ /* check effects strips, we cant change their time */
+ if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
+ has_effect_any = true;
+ if (seq->depth == 0) {
+ has_effect_root = true;
+ }
+ }
+ else {
+ /* Tag seq with a non zero value, used by
+ * BKE_sequence_base_shuffle_time to identify the ones to shuffle */
+ if (seq->depth == 0) {
+ seq->tmp = (void *)1;
+ }
+ }
+ }
+ }
+
+ if (t->flag & T_ALT_TRANSFORM) {
+ int minframe = MAXFRAME;
+ td = tc->data;
+ for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
+ seq = ((TransDataSeq *)td->extra)->seq;
+ if ((seq != seq_prev) && (seq->depth == 0)) {
+ minframe = min_ii(minframe, seq->startdisp);
+ }
+ }
+
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (!(seq->flag & SELECT)) {
+ if (seq->startdisp >= minframe) {
+ seq->machine += MAXSEQ * 2;
+ }
+ }
+ }
+
+ BKE_sequence_base_shuffle_time(seqbasep, t->scene);
+
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (seq->machine >= MAXSEQ * 2) {
+ seq->machine -= MAXSEQ * 2;
+ seq->tmp = (void *)1;
+ }
+ else {
+ seq->tmp = NULL;
+ }
+ }
+
+ BKE_sequence_base_shuffle_time(seqbasep, t->scene);
+ }
+ else {
+ BKE_sequence_base_shuffle_time(seqbasep, t->scene);
+ }
+
+ if (has_effect_any) {
+ /* update effects strips based on strips just moved in time */
+ td = tc->data;
+ for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
+ seq = ((TransDataSeq *)td->extra)->seq;
+ if ((seq != seq_prev)) {
+ if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
+ BKE_sequence_calc(t->scene, seq);
+ }
+ }
+ }
+ }
+
+ if (has_effect_root) {
+ /* now if any effects _still_ overlap, we need to move them up */
+ td = tc->data;
+ for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
+ seq = ((TransDataSeq *)td->extra)->seq;
+ if ((seq != seq_prev) && (seq->depth == 0)) {
+ if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
+ if (BKE_sequence_test_overlap(seqbasep, seq)) {
+ BKE_sequence_base_shuffle(seqbasep, seq, t->scene);
+ }
+ }
+ }
+ }
+ /* done with effects */
+ }
+ }
+ }
+#endif
+
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ /* We might want to build a list of effects that need to be updated during transform */
+ if (seq->type & SEQ_TYPE_EFFECT) {
+ if (seq->seq1 && seq->seq1->flag & SELECT) {
+ BKE_sequence_calc(t->scene, seq);
+ }
+ else if (seq->seq2 && seq->seq2->flag & SELECT) {
+ BKE_sequence_calc(t->scene, seq);
+ }
+ else if (seq->seq3 && seq->seq3->flag & SELECT) {
+ BKE_sequence_calc(t->scene, seq);
+ }
+ }
+ }
+
+ BKE_sequencer_sort(t->scene);
+ }
+ else {
+ /* Canceled, need to update the strips display */
+ for (a = 0; a < tc->data_len; a++, td++) {
+ seq = ((TransDataSeq *)td->extra)->seq;
+ if ((seq != seq_prev) && (seq->depth == 0)) {
+ if (seq->flag & SEQ_OVERLAP) {
+ BKE_sequence_base_shuffle(seqbasep, seq, t->scene);
+ }
+
+ BKE_sequence_calc_disp(t->scene, seq);
+ }
+ seq_prev = seq;
+ }
+ }
+ }
+
+ if ((custom_data->data != NULL) && custom_data->use_free) {
+ TransSeq *ts = custom_data->data;
+ MEM_freeN(ts->tdseq);
+ MEM_freeN(custom_data->data);
+ custom_data->data = NULL;
+ }
+
+ DEG_id_tag_update(&t->scene->id, ID_RECALC_SEQUENCER_STRIPS);
+}
+
+void createTransSeqData(bContext *C, TransInfo *t)
+{
+#define XXX_DURIAN_ANIM_TX_HACK
+
+ View2D *v2d = UI_view2d_fromcontext(C);
+ Scene *scene = t->scene;
+ Editing *ed = BKE_sequencer_editing_get(t->scene, false);
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ TransDataSeq *tdsq = NULL;
+ TransSeq *ts = NULL;
+ int xmouse;
+
+ int count = 0;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ if (ed == NULL) {
+ tc->data_len = 0;
+ return;
+ }
+
+ tc->custom.type.free_cb = freeSeqData;
+
+ xmouse = (int)UI_view2d_region_to_view_x(v2d, t->mouse.imval[0]);
+
+ /* which side of the current frame should be allowed */
+ if (t->mode == TFM_TIME_EXTEND) {
+ /* only side on which mouse is gets transformed */
+ t->frame_side = (xmouse > CFRA) ? 'R' : 'L';
+ }
+ else {
+ /* normal transform - both sides of current frame are considered */
+ t->frame_side = 'B';
+ }
+
+#ifdef XXX_DURIAN_ANIM_TX_HACK
+ {
+ Sequence *seq;
+ for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ /* hack */
+ if ((seq->flag & SELECT) == 0 && seq->type & SEQ_TYPE_EFFECT) {
+ Sequence *seq_user;
+ int i;
+ for (i = 0; i < 3; i++) {
+ seq_user = *((&seq->seq1) + i);
+ if (seq_user && (seq_user->flag & SELECT) && !(seq_user->flag & SEQ_LOCK) &&
+ !(seq_user->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL))) {
+ seq->flag |= SELECT;
+ }
+ }
+ }
+ }
+ }
+#endif
+
+ count = SeqTransCount(t, NULL, ed->seqbasep, 0);
+
+ /* allocate memory for data */
+ tc->data_len = count;
+
+ /* stop if trying to build list if nothing selected */
+ if (count == 0) {
+ return;
+ }
+
+ tc->custom.type.data = ts = MEM_callocN(sizeof(TransSeq), "transseq");
+ tc->custom.type.use_free = true;
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransSeq TransData");
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransSeq TransData2D");
+ ts->tdseq = tdsq = MEM_callocN(tc->data_len * sizeof(TransDataSeq), "TransSeq TransDataSeq");
+
+ /* loop 2: build transdata array */
+ SeqToTransData_Recursive(t, ed->seqbasep, td, td2d, tdsq);
+ SeqTransDataBounds(t, ed->seqbasep, ts);
+
+ /* set the snap mode based on how close the mouse is at the end/start points */
+ if (abs(xmouse - ts->max) > abs(xmouse - ts->min)) {
+ ts->snap_left = true;
+ }
+
+#undef XXX_DURIAN_ANIM_TX_HACK
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UVs Transform Flush
+ *
+ * \{ */
+
+/* commented _only_ because the meta may have animation data which
+ * needs moving too [#28158] */
+
+#define SEQ_TX_NESTED_METAS
+
+BLI_INLINE void trans_update_seq(Scene *sce, Sequence *seq, int old_start, int sel_flag)
+{
+ if (seq->depth == 0) {
+ /* Calculate this strip and all nested strips.
+ * Children are ALWAYS transformed first so we don't need to do this in another loop.
+ */
+ BKE_sequence_calc(sce, seq);
+ }
+ else {
+ BKE_sequence_calc_disp(sce, seq);
+ }
+
+ if (sel_flag == SELECT) {
+ BKE_sequencer_offset_animdata(sce, seq, seq->start - old_start);
+ }
+}
+
+void flushTransSeq(TransInfo *t)
+{
+ /* Editing null check already done */
+ ListBase *seqbasep = BKE_sequencer_editing_get(t->scene, false)->seqbasep;
+
+ int a, new_frame;
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ TransDataSeq *tdsq = NULL;
+ Sequence *seq;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* prevent updating the same seq twice
+ * if the transdata order is changed this will mess up
+ * but so will TransDataSeq */
+ Sequence *seq_prev = NULL;
+ int old_start_prev = 0, sel_flag_prev = 0;
+
+ /* flush to 2d vector from internally used 3d vector */
+ for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
+ int old_start;
+ tdsq = (TransDataSeq *)td->extra;
+ seq = tdsq->seq;
+ old_start = seq->start;
+ new_frame = round_fl_to_int(td2d->loc[0]);
+
+ switch (tdsq->sel_flag) {
+ case SELECT:
+#ifdef SEQ_TX_NESTED_METAS
+ if ((seq->depth != 0 || BKE_sequence_tx_test(seq))) {
+ /* for meta's, their children move */
+ seq->start = new_frame - tdsq->start_offset;
+ }
+#else
+ if (seq->type != SEQ_TYPE_META && (seq->depth != 0 || seq_tx_test(seq))) {
+ /* for meta's, their children move */
+ seq->start = new_frame - tdsq->start_offset;
+ }
+#endif
+ if (seq->depth == 0) {
+ seq->machine = round_fl_to_int(td2d->loc[1]);
+ CLAMP(seq->machine, 1, MAXSEQ);
+ }
+ break;
+ case SEQ_LEFTSEL: /* no vertical transform */
+ BKE_sequence_tx_set_final_left(seq, new_frame);
+ BKE_sequence_tx_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL);
+
+ /* todo - move this into aftertrans update? - old seq tx needed it anyway */
+ BKE_sequence_single_fix(seq);
+ break;
+ case SEQ_RIGHTSEL: /* no vertical transform */
+ BKE_sequence_tx_set_final_right(seq, new_frame);
+ BKE_sequence_tx_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL);
+
+ /* todo - move this into aftertrans update? - old seq tx needed it anyway */
+ BKE_sequence_single_fix(seq);
+ break;
+ }
+
+ /* Update *previous* seq! Else, we would update a seq after its first transform,
+ * and if it has more than one (like e.g. SEQ_LEFTSEL and SEQ_RIGHTSEL),
+ * the others are not updated! See T38469.
+ */
+ if (seq != seq_prev) {
+ if (seq_prev) {
+ trans_update_seq(t->scene, seq_prev, old_start_prev, sel_flag_prev);
+ }
+
+ seq_prev = seq;
+ old_start_prev = old_start;
+ sel_flag_prev = tdsq->sel_flag;
+ }
+ else {
+ /* We want to accumulate *all* sel_flags for this seq! */
+ sel_flag_prev |= tdsq->sel_flag;
+ }
+ }
+
+ /* Don't forget to update the last seq! */
+ if (seq_prev) {
+ trans_update_seq(t->scene, seq_prev, old_start_prev, sel_flag_prev);
+ }
+
+ /* originally TFM_TIME_EXTEND, transform changes */
+ if (ELEM(t->mode, TFM_SEQ_SLIDE, TFM_TIME_TRANSLATE)) {
+ /* Special annoying case here, need to calc metas with TFM_TIME_EXTEND only */
+
+ /* calc all meta's then effects [#27953] */
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (seq->type == SEQ_TYPE_META && seq->flag & SELECT) {
+ BKE_sequence_calc(t->scene, seq);
+ }
+ }
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (seq->seq1 || seq->seq2 || seq->seq3) {
+ BKE_sequence_calc(t->scene, seq);
+ }
+ }
+
+ /* update effects inside meta's */
+ for (a = 0, seq_prev = NULL, td = tc->data, td2d = tc->data_2d; a < tc->data_len;
+ a++, td++, td2d++, seq_prev = seq) {
+ tdsq = (TransDataSeq *)td->extra;
+ seq = tdsq->seq;
+ if ((seq != seq_prev) && (seq->depth != 0)) {
+ if (seq->seq1 || seq->seq2 || seq->seq3) {
+ BKE_sequence_calc(t->scene, seq);
+ }
+ }
+ }
+ }
+
+ /* need to do the overlap check in a new loop otherwise adjacent strips
+ * will not be updated and we'll get false positives */
+ seq_prev = NULL;
+ for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
+
+ tdsq = (TransDataSeq *)td->extra;
+ seq = tdsq->seq;
+
+ if (seq != seq_prev) {
+ if (seq->depth == 0) {
+ /* test overlap, displays red outline */
+ seq->flag &= ~SEQ_OVERLAP;
+ if (BKE_sequence_test_overlap(seqbasep, seq)) {
+ seq->flag |= SEQ_OVERLAP;
+ }
+ }
+ }
+ seq_prev = seq;
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c
new file mode 100644
index 00000000000..b68b79adbd8
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_tracking.c
@@ -0,0 +1,692 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_movieclip.h"
+#include "BKE_report.h"
+#include "BKE_tracking.h"
+
+#include "ED_clip.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+typedef struct TransDataTracking {
+ int mode, flag;
+
+ /* tracks transformation from main window */
+ int area;
+ const float *relative, *loc;
+ float soffset[2], srelative[2];
+ float offset[2];
+
+ float (*smarkers)[2];
+ int markersnr;
+ MovieTrackingMarker *markers;
+
+ /* marker transformation from curves editor */
+ float *prev_pos, scale;
+ short coord;
+
+ MovieTrackingTrack *track;
+ MovieTrackingPlaneTrack *plane_track;
+} TransDataTracking;
+
+enum transDataTracking_Mode {
+ transDataTracking_ModeTracks = 0,
+ transDataTracking_ModeCurves = 1,
+ transDataTracking_ModePlaneTracks = 2,
+};
+
+/* -------------------------------------------------------------------- */
+/** \name Clip Editor Motion Tracking Transform Creation
+ *
+ * \{ */
+
+static void markerToTransDataInit(TransData *td,
+ TransData2D *td2d,
+ TransDataTracking *tdt,
+ MovieTrackingTrack *track,
+ MovieTrackingMarker *marker,
+ int area,
+ float loc[2],
+ const float rel[2],
+ const float off[2],
+ const float aspect[2])
+{
+ int anchor = area == TRACK_AREA_POINT && off;
+
+ tdt->mode = transDataTracking_ModeTracks;
+
+ if (anchor) {
+ td2d->loc[0] = rel[0] * aspect[0]; /* hold original location */
+ td2d->loc[1] = rel[1] * aspect[1];
+
+ tdt->loc = loc;
+ td2d->loc2d = loc; /* current location */
+ }
+ else {
+ td2d->loc[0] = loc[0] * aspect[0]; /* hold original location */
+ td2d->loc[1] = loc[1] * aspect[1];
+
+ td2d->loc2d = loc; /* current location */
+ }
+ td2d->loc[2] = 0.0f;
+
+ tdt->relative = rel;
+ tdt->area = area;
+
+ tdt->markersnr = track->markersnr;
+ tdt->markers = track->markers;
+ tdt->track = track;
+
+ if (rel) {
+ if (!anchor) {
+ td2d->loc[0] += rel[0] * aspect[0];
+ td2d->loc[1] += rel[1] * aspect[1];
+ }
+
+ copy_v2_v2(tdt->srelative, rel);
+ }
+
+ if (off) {
+ copy_v2_v2(tdt->soffset, off);
+ }
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ copy_v3_v3(td->iloc, td->loc);
+
+ // copy_v3_v3(td->center, td->loc);
+ td->flag |= TD_INDIVIDUAL_SCALE;
+ td->center[0] = marker->pos[0] * aspect[0];
+ td->center[1] = marker->pos[1] * aspect[1];
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+}
+
+static void trackToTransData(const int framenr,
+ TransData *td,
+ TransData2D *td2d,
+ TransDataTracking *tdt,
+ MovieTrackingTrack *track,
+ const float aspect[2])
+{
+ MovieTrackingMarker *marker = BKE_tracking_marker_ensure(track, framenr);
+
+ tdt->flag = marker->flag;
+ marker->flag &= ~(MARKER_DISABLED | MARKER_TRACKED);
+
+ markerToTransDataInit(td++,
+ td2d++,
+ tdt++,
+ track,
+ marker,
+ TRACK_AREA_POINT,
+ track->offset,
+ marker->pos,
+ track->offset,
+ aspect);
+
+ if (track->flag & SELECT) {
+ markerToTransDataInit(
+ td++, td2d++, tdt++, track, marker, TRACK_AREA_POINT, marker->pos, NULL, NULL, aspect);
+ }
+
+ if (track->pat_flag & SELECT) {
+ int a;
+
+ for (a = 0; a < 4; a++) {
+ markerToTransDataInit(td++,
+ td2d++,
+ tdt++,
+ track,
+ marker,
+ TRACK_AREA_PAT,
+ marker->pattern_corners[a],
+ marker->pos,
+ NULL,
+ aspect);
+ }
+ }
+
+ if (track->search_flag & SELECT) {
+ markerToTransDataInit(td++,
+ td2d++,
+ tdt++,
+ track,
+ marker,
+ TRACK_AREA_SEARCH,
+ marker->search_min,
+ marker->pos,
+ NULL,
+ aspect);
+
+ markerToTransDataInit(td++,
+ td2d++,
+ tdt++,
+ track,
+ marker,
+ TRACK_AREA_SEARCH,
+ marker->search_max,
+ marker->pos,
+ NULL,
+ aspect);
+ }
+}
+
+static void planeMarkerToTransDataInit(TransData *td,
+ TransData2D *td2d,
+ TransDataTracking *tdt,
+ MovieTrackingPlaneTrack *plane_track,
+ float corner[2],
+ const float aspect[2])
+{
+ tdt->mode = transDataTracking_ModePlaneTracks;
+ tdt->plane_track = plane_track;
+
+ td2d->loc[0] = corner[0] * aspect[0]; /* hold original location */
+ td2d->loc[1] = corner[1] * aspect[1];
+
+ td2d->loc2d = corner; /* current location */
+ td2d->loc[2] = 0.0f;
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ copy_v3_v3(td->iloc, td->loc);
+ copy_v3_v3(td->center, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+}
+
+static void planeTrackToTransData(const int framenr,
+ TransData *td,
+ TransData2D *td2d,
+ TransDataTracking *tdt,
+ MovieTrackingPlaneTrack *plane_track,
+ const float aspect[2])
+{
+ MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr);
+ int i;
+
+ tdt->flag = plane_marker->flag;
+ plane_marker->flag &= ~PLANE_MARKER_TRACKED;
+
+ for (i = 0; i < 4; i++) {
+ planeMarkerToTransDataInit(td++, td2d++, tdt++, plane_track, plane_marker->corners[i], aspect);
+ }
+}
+
+static void transDataTrackingFree(TransInfo *UNUSED(t),
+ TransDataContainer *UNUSED(tc),
+ TransCustomData *custom_data)
+{
+ if (custom_data->data) {
+ TransDataTracking *tdt = custom_data->data;
+ if (tdt->smarkers) {
+ MEM_freeN(tdt->smarkers);
+ }
+
+ MEM_freeN(tdt);
+ custom_data->data = NULL;
+ }
+}
+
+static void createTransTrackingTracksData(bContext *C, TransInfo *t)
+{
+ TransData *td;
+ TransData2D *td2d;
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
+ MovieTrackingTrack *track;
+ MovieTrackingPlaneTrack *plane_track;
+ TransDataTracking *tdt;
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* count */
+ tc->data_len = 0;
+
+ track = tracksbase->first;
+ while (track) {
+ if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
+ tc->data_len++; /* offset */
+
+ if (track->flag & SELECT) {
+ tc->data_len++;
+ }
+
+ if (track->pat_flag & SELECT) {
+ tc->data_len += 4;
+ }
+
+ if (track->search_flag & SELECT) {
+ tc->data_len += 2;
+ }
+ }
+
+ track = track->next;
+ }
+
+ for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
+ if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
+ tc->data_len += 4;
+ }
+ }
+
+ if (tc->data_len == 0) {
+ return;
+ }
+
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransTracking TransData");
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D),
+ "TransTracking TransData2D");
+ tdt = tc->custom.type.data = MEM_callocN(tc->data_len * sizeof(TransDataTracking),
+ "TransTracking TransDataTracking");
+
+ tc->custom.type.free_cb = transDataTrackingFree;
+
+ /* create actual data */
+ track = tracksbase->first;
+ while (track) {
+ if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
+ trackToTransData(framenr, td, td2d, tdt, track, t->aspect);
+
+ /* offset */
+ td++;
+ td2d++;
+ tdt++;
+
+ if (track->flag & SELECT) {
+ td++;
+ td2d++;
+ tdt++;
+ }
+
+ if (track->pat_flag & SELECT) {
+ td += 4;
+ td2d += 4;
+ tdt += 4;
+ }
+
+ if (track->search_flag & SELECT) {
+ td += 2;
+ td2d += 2;
+ tdt += 2;
+ }
+ }
+
+ track = track->next;
+ }
+
+ for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
+ if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
+ planeTrackToTransData(framenr, td, td2d, tdt, plane_track, t->aspect);
+ td += 4;
+ td2d += 4;
+ tdt += 4;
+ }
+ }
+}
+
+static void markerToTransCurveDataInit(TransData *td,
+ TransData2D *td2d,
+ TransDataTracking *tdt,
+ MovieTrackingTrack *track,
+ MovieTrackingMarker *marker,
+ MovieTrackingMarker *prev_marker,
+ short coord,
+ float size)
+{
+ float frames_delta = (marker->framenr - prev_marker->framenr);
+
+ tdt->flag = marker->flag;
+ marker->flag &= ~MARKER_TRACKED;
+
+ tdt->mode = transDataTracking_ModeCurves;
+ tdt->coord = coord;
+ tdt->scale = 1.0f / size * frames_delta;
+ tdt->prev_pos = prev_marker->pos;
+ tdt->track = track;
+
+ /* calculate values depending on marker's speed */
+ td2d->loc[0] = marker->framenr;
+ td2d->loc[1] = (marker->pos[coord] - prev_marker->pos[coord]) * size / frames_delta;
+ td2d->loc[2] = 0.0f;
+
+ td2d->loc2d = marker->pos; /* current location */
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ copy_v3_v3(td->center, td->loc);
+ copy_v3_v3(td->iloc, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+}
+
+static void createTransTrackingCurvesData(bContext *C, TransInfo *t)
+{
+ TransData *td;
+ TransData2D *td2d;
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ MovieTrackingTrack *track;
+ MovieTrackingMarker *marker, *prev_marker;
+ TransDataTracking *tdt;
+ int i, width, height;
+
+ BKE_movieclip_get_size(clip, &sc->user, &width, &height);
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* count */
+ tc->data_len = 0;
+
+ if ((sc->flag & SC_SHOW_GRAPH_TRACKS_MOTION) == 0) {
+ return;
+ }
+
+ track = tracksbase->first;
+ while (track) {
+ if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
+ for (i = 1; i < track->markersnr; i++) {
+ marker = &track->markers[i];
+ prev_marker = &track->markers[i - 1];
+
+ if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) {
+ continue;
+ }
+
+ if (marker->flag & MARKER_GRAPH_SEL_X) {
+ tc->data_len += 1;
+ }
+
+ if (marker->flag & MARKER_GRAPH_SEL_Y) {
+ tc->data_len += 1;
+ }
+ }
+ }
+
+ track = track->next;
+ }
+
+ if (tc->data_len == 0) {
+ return;
+ }
+
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransTracking TransData");
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D),
+ "TransTracking TransData2D");
+ tc->custom.type.data = tdt = MEM_callocN(tc->data_len * sizeof(TransDataTracking),
+ "TransTracking TransDataTracking");
+ tc->custom.type.free_cb = transDataTrackingFree;
+
+ /* create actual data */
+ track = tracksbase->first;
+ while (track) {
+ if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
+ for (i = 1; i < track->markersnr; i++) {
+ marker = &track->markers[i];
+ prev_marker = &track->markers[i - 1];
+
+ if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) {
+ continue;
+ }
+
+ if (marker->flag & MARKER_GRAPH_SEL_X) {
+ markerToTransCurveDataInit(
+ td, td2d, tdt, track, marker, &track->markers[i - 1], 0, width);
+ td += 1;
+ td2d += 1;
+ tdt += 1;
+ }
+
+ if (marker->flag & MARKER_GRAPH_SEL_Y) {
+ markerToTransCurveDataInit(
+ td, td2d, tdt, track, marker, &track->markers[i - 1], 1, height);
+
+ td += 1;
+ td2d += 1;
+ tdt += 1;
+ }
+ }
+ }
+
+ track = track->next;
+ }
+}
+
+void createTransTrackingData(bContext *C, TransInfo *t)
+{
+ ARegion *ar = CTX_wm_region(C);
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ int width, height;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ tc->data_len = 0;
+
+ if (!clip) {
+ return;
+ }
+
+ BKE_movieclip_get_size(clip, &sc->user, &width, &height);
+
+ if (width == 0 || height == 0) {
+ return;
+ }
+
+ if (ar->regiontype == RGN_TYPE_PREVIEW) {
+ /* transformation was called from graph editor */
+ createTransTrackingCurvesData(C, t);
+ }
+ else {
+ createTransTrackingTracksData(C, t);
+ }
+}
+
+void cancelTransTracking(TransInfo *t)
+{
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+ SpaceClip *sc = t->sa->spacedata.first;
+ int i, framenr = ED_space_clip_get_clip_frame_number(sc);
+ TransDataTracking *tdt_array = tc->custom.type.data;
+
+ i = 0;
+ while (i < tc->data_len) {
+ TransDataTracking *tdt = &tdt_array[i];
+
+ if (tdt->mode == transDataTracking_ModeTracks) {
+ MovieTrackingTrack *track = tdt->track;
+ MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
+
+ marker->flag = tdt->flag;
+
+ if (track->flag & SELECT) {
+ i++;
+ }
+
+ if (track->pat_flag & SELECT) {
+ i += 4;
+ }
+
+ if (track->search_flag & SELECT) {
+ i += 2;
+ }
+ }
+ else if (tdt->mode == transDataTracking_ModeCurves) {
+ MovieTrackingTrack *track = tdt->track;
+ MovieTrackingMarker *marker, *prev_marker;
+ int a;
+
+ for (a = 1; a < track->markersnr; a++) {
+ marker = &track->markers[a];
+ prev_marker = &track->markers[a - 1];
+
+ if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) {
+ continue;
+ }
+
+ if (marker->flag & (MARKER_GRAPH_SEL_X | MARKER_GRAPH_SEL_Y)) {
+ marker->flag = tdt->flag;
+ }
+ }
+ }
+ else if (tdt->mode == transDataTracking_ModePlaneTracks) {
+ MovieTrackingPlaneTrack *plane_track = tdt->plane_track;
+ MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr);
+
+ plane_marker->flag = tdt->flag;
+ i += 3;
+ }
+
+ i++;
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clip Editor Motion Tracking Transform Creation
+ *
+ * \{ */
+
+void flushTransTracking(TransInfo *t)
+{
+ TransData *td;
+ TransData2D *td2d;
+ TransDataTracking *tdt;
+ int a;
+
+ if (t->state == TRANS_CANCEL) {
+ cancelTransTracking(t);
+ }
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* flush to 2d vector from internally used 3d vector */
+ for (a = 0, td = tc->data, td2d = tc->data_2d, tdt = tc->custom.type.data; a < tc->data_len;
+ a++, td2d++, td++, tdt++) {
+ if (tdt->mode == transDataTracking_ModeTracks) {
+ float loc2d[2];
+
+ if (t->mode == TFM_ROTATION && tdt->area == TRACK_AREA_SEARCH) {
+ continue;
+ }
+
+ loc2d[0] = td2d->loc[0] / t->aspect[0];
+ loc2d[1] = td2d->loc[1] / t->aspect[1];
+
+ if (t->flag & T_ALT_TRANSFORM) {
+ if (t->mode == TFM_RESIZE) {
+ if (tdt->area != TRACK_AREA_PAT) {
+ continue;
+ }
+ }
+ else if (t->mode == TFM_TRANSLATION) {
+ if (tdt->area == TRACK_AREA_POINT && tdt->relative) {
+ float d[2], d2[2];
+
+ if (!tdt->smarkers) {
+ tdt->smarkers = MEM_callocN(sizeof(*tdt->smarkers) * tdt->markersnr,
+ "flushTransTracking markers");
+ for (a = 0; a < tdt->markersnr; a++) {
+ copy_v2_v2(tdt->smarkers[a], tdt->markers[a].pos);
+ }
+ }
+
+ sub_v2_v2v2(d, loc2d, tdt->soffset);
+ sub_v2_v2(d, tdt->srelative);
+
+ sub_v2_v2v2(d2, loc2d, tdt->srelative);
+
+ for (a = 0; a < tdt->markersnr; a++) {
+ add_v2_v2v2(tdt->markers[a].pos, tdt->smarkers[a], d2);
+ }
+
+ negate_v2_v2(td2d->loc2d, d);
+ }
+ }
+ }
+
+ if (tdt->area != TRACK_AREA_POINT || tdt->relative == NULL) {
+ td2d->loc2d[0] = loc2d[0];
+ td2d->loc2d[1] = loc2d[1];
+
+ if (tdt->relative) {
+ sub_v2_v2(td2d->loc2d, tdt->relative);
+ }
+ }
+ }
+ else if (tdt->mode == transDataTracking_ModeCurves) {
+ td2d->loc2d[tdt->coord] = tdt->prev_pos[tdt->coord] + td2d->loc[1] * tdt->scale;
+ }
+ else if (tdt->mode == transDataTracking_ModePlaneTracks) {
+ td2d->loc2d[0] = td2d->loc[0] / t->aspect[0];
+ td2d->loc2d[1] = td2d->loc[1] / t->aspect[1];
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 41eb5f1e812..53e36f86a64 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -99,6 +99,7 @@
#include "ED_clip.h"
#include "ED_screen.h"
#include "ED_gpencil.h"
+#include "ED_sculpt.h"
#include "WM_types.h"
#include "WM_api.h"
@@ -109,6 +110,7 @@
#include "UI_view2d.h"
#include "transform.h"
+#include "transform_convert.h"
/* ************************** Functions *************************** */
@@ -222,35 +224,31 @@ static void clipMirrorModifier(TransInfo *t)
}
/* assumes obedit set to mesh object */
-static void editbmesh_apply_to_mirror(TransInfo *t)
+static void transform_apply_to_mirror(TransInfo *t)
{
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- if (tc->mirror.axis_flag) {
- TransData *td = tc->data;
- BMVert *eve;
+ if (tc->mirror.use_mirror_any) {
int i;
-
- for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
- if (td->loc == NULL) {
- break;
- }
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- eve = td->extra;
- if (eve) {
- eve->co[0] = -td->loc[0];
- eve->co[1] = td->loc[1];
- eve->co[2] = td->loc[2];
+ TransData *td;
+ for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
+ if (td->flag & (TD_MIRROR_EDGE_X | TD_MIRROR_EDGE_Y | TD_MIRROR_EDGE_Z)) {
+ if (td->flag & TD_MIRROR_EDGE_X) {
+ td->loc[0] = 0.0f;
+ }
+ if (td->flag & TD_MIRROR_EDGE_Y) {
+ td->loc[1] = 0.0f;
+ }
+ if (td->flag & TD_MIRROR_EDGE_Z) {
+ td->loc[2] = 0.0f;
+ }
}
+ }
- if (td->flag & TD_MIRROR_EDGE) {
- td->loc[0] = 0;
- }
+ TransDataMirror *tdm;
+ for (i = 0, tdm = tc->mirror.data; i < tc->mirror.data_len; i++, tdm++) {
+ tdm->loc_dst[0] = tdm->loc_src[0] * tdm->sign_x;
+ tdm->loc_dst[1] = tdm->loc_src[1] * tdm->sign_y;
+ tdm->loc_dst[2] = tdm->loc_src[2] * tdm->sign_z;
}
}
}
@@ -887,7 +885,7 @@ static void recalcData_objects(TransInfo *t)
clipMirrorModifier(t);
}
if ((t->flag & T_NO_MIRROR) == 0 && (t->options & CTX_NO_MIRROR) == 0) {
- editbmesh_apply_to_mirror(t);
+ transform_apply_to_mirror(t);
}
if (t->mode == TFM_EDGE_SLIDE) {
@@ -1090,12 +1088,12 @@ static void recalcData_objects(TransInfo *t)
GSetIterator gs_iter;
GSET_ITER (gs_iter, motionpath_updates) {
Object *ob = BLI_gsetIterator_getKey(&gs_iter);
- ED_pose_recalculate_paths(t->context, t->scene, ob, true);
+ ED_pose_recalculate_paths(t->context, t->scene, ob, POSE_PATH_CALC_RANGE_CURRENT_FRAME);
}
BLI_gset_free(motionpath_updates, NULL);
}
else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) &&
- PE_get_current(t->scene, base->object)) {
+ PE_get_current(t->depsgraph, t->scene, base->object)) {
if (t->state != TRANS_CANCEL) {
applyProject(t);
}
@@ -1148,10 +1146,14 @@ static void recalcData_objects(TransInfo *t)
if (motionpath_update) {
/* Update motion paths once for all transformed objects. */
- ED_objects_recalculate_paths(t->context, t->scene, true);
+ ED_objects_recalculate_paths(t->context, t->scene, OBJECT_PATH_CALC_RANGE_CHANGED);
+ }
+
+ if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) {
+ trans_obchild_in_obmode_update_all(t);
}
- if (t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) {
+ if (t->options & CTX_OBMODE_XFORM_OBDATA) {
trans_obdata_in_obmode_update_all(t);
}
}
@@ -1201,6 +1203,11 @@ static void recalcData_gpencil_strokes(TransInfo *t)
}
}
+static void recalcData_sculpt(TransInfo *t)
+{
+ ED_sculpt_update_modal_transform(t->context);
+}
+
/* called for updating while transform acts, once per redraw */
void recalcData(TransInfo *t)
{
@@ -1221,6 +1228,9 @@ void recalcData(TransInfo *t)
/* set recalc triangle cache flag */
recalcData_gpencil_strokes(t);
}
+ else if (t->options & CTX_SCULPT) {
+ recalcData_sculpt(t);
+ }
else if (t->spacetype == SPACE_IMAGE) {
recalcData_image(t);
}
@@ -1347,11 +1357,12 @@ void initTransDataContainers_FromObjectData(TransInfo *t,
for (int i = 0; i < objects_len; i++) {
TransDataContainer *tc = &t->data_container[i];
- /* TODO, multiple axes. */
- tc->mirror.axis_flag = (((t->flag & T_NO_MIRROR) == 0) &&
- ((t->options & CTX_NO_MIRROR) == 0) &&
- (objects[i]->type == OB_MESH) &&
- (((Mesh *)objects[i]->data)->editflag & ME_EDIT_MIRROR_X) != 0);
+ if (((t->flag & T_NO_MIRROR) == 0) && ((t->options & CTX_NO_MIRROR) == 0) &&
+ (objects[i]->type == OB_MESH)) {
+ tc->mirror.axis_x = (((Mesh *)objects[i]->data)->editflag & ME_EDIT_MIRROR_X) != 0;
+ tc->mirror.axis_y = (((Mesh *)objects[i]->data)->editflag & ME_EDIT_MIRROR_Y) != 0;
+ tc->mirror.axis_z = (((Mesh *)objects[i]->data)->editflag & ME_EDIT_MIRROR_Z) != 0;
+ }
if (object_mode & OB_MODE_EDIT) {
tc->obedit = objects[i];
@@ -1888,6 +1899,7 @@ void postTrans(bContext *C, TransInfo *t)
MEM_SAFE_FREE(tc->data_ext);
MEM_SAFE_FREE(tc->data_2d);
+ MEM_SAFE_FREE(tc->mirror.data);
}
}
@@ -1923,10 +1935,6 @@ void postTrans(bContext *C, TransInfo *t)
BLI_rng_free(t->rng);
}
- if (t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) {
- trans_obdata_in_obmode_free_all(t);
- }
-
freeSnapping(t);
}
@@ -2339,11 +2347,6 @@ void calculatePropRatio(TransInfo *t)
if (td->flag & TD_SELECTED) {
td->factor = 1.0f;
}
- else if (tc->mirror.axis_flag && (td->loc[0] * tc->mirror.sign) < -0.00001f) {
- td->flag |= TD_SKIP;
- td->factor = 0.0f;
- restoreElement(td);
- }
else if ((connected && (td->flag & TD_NOTCONNECTED || td->dist > t->prop_size)) ||
(connected == 0 && td->rdist > t->prop_size)) {
/*
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index fbfeb4f53de..65fd9c6f5e9 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -55,6 +55,7 @@
#include "BKE_scene.h"
#include "BKE_workspace.h"
#include "BKE_object.h"
+#include "BKE_paint.h"
#include "DEG_depsgraph.h"
@@ -82,13 +83,11 @@
/* local module include */
#include "transform.h"
+#include "transform_convert.h"
#include "MEM_guardedalloc.h"
-#include "GPU_select.h"
#include "GPU_state.h"
-#include "GPU_immediate.h"
-#include "GPU_matrix.h"
#include "DEG_depsgraph_query.h"
@@ -1055,10 +1054,16 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
}
}
else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
- /* pass */
+ if (ob->mode & OB_MODE_SCULPT) {
+ totsel = 1;
+ calc_tw_center_with_matrix(tbounds, ob->sculpt->pivot_pos, false, ob->obmat);
+ mul_m4_v3(ob->obmat, tbounds->center);
+ mul_m4_v3(ob->obmat, tbounds->min);
+ mul_m4_v3(ob->obmat, tbounds->max);
+ }
}
else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) {
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
PTCacheEditPoint *point;
PTCacheEditKey *ek;
int k;
@@ -1163,12 +1168,20 @@ static void gizmo_prepare_mat(const bContext *C,
if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
bGPdata *gpd = CTX_data_gpencil_data(C);
- Object *ob = OBACT(view_layer);
if (gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
/* pass */
}
- else if (ob != NULL) {
- ED_object_calc_active_center(ob, false, rv3d->twmat[3]);
+ else {
+ Object *ob = OBACT(view_layer);
+ if (ob != NULL) {
+ if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) {
+ SculptSession *ss = ob->sculpt;
+ copy_v3_v3(rv3d->twmat[3], ss->pivot_pos);
+ }
+ else {
+ ED_object_calc_active_center(ob, false, rv3d->twmat[3]);
+ }
+ }
}
}
break;
@@ -1284,7 +1297,7 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
PointerRNA toolsettings_ptr;
RNA_pointer_create(&scene->id, &RNA_ToolSettings, scene->toolsettings, &toolsettings_ptr);
- if (type_fn == VIEW3D_GGT_xform_gizmo) {
+ if (ELEM(type_fn, VIEW3D_GGT_xform_gizmo, VIEW3D_GGT_xform_shear)) {
extern PropertyRNA rna_ToolSettings_transform_pivot_point;
const PropertyRNA *props[] = {
&rna_ToolSettings_transform_pivot_point,
@@ -1392,7 +1405,8 @@ void drawDial3d(const TransInfo *t)
scale *= ED_view3d_pixel_size_no_ui_scale(t->ar->regiondata, mat_final[3]);
mul_mat3_m4_fl(mat_final, scale);
- if ((t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) && activeSnap(t)) {
+ if (activeSnap(t) && (!transformModeUseSnap(t) ||
+ (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) {
increment = (t->modifiers & MOD_PRECISION) ? t->snap[2] : t->snap[1];
}
else {
@@ -2294,7 +2308,6 @@ static void WIDGETGROUP_xform_shear_setup(const bContext *UNUSED(C), wmGizmoGrou
interp_v3_v3v3(gz->color, axis_color[i_ortho_a], axis_color[i_ortho_b], 0.75f);
gz->color[3] = 0.5f;
PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_shear, NULL);
- RNA_enum_set(ptr, "shear_axis", 0);
RNA_boolean_set(ptr, "release_confirm", 1);
xgzgroup->gizmo[i][j] = gz;
}
diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c
index e771fe43bd8..2821277ffa0 100644
--- a/source/blender/editors/transform/transform_input.c
+++ b/source/blender/editors/transform/transform_input.c
@@ -389,7 +389,7 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
/* INPUT_VECTOR, INPUT_CUSTOM_RATIO, INPUT_CUSTOM_RATIO_FLIP */
if (t->flag & T_MODAL) {
t->flag |= T_MODAL_CURSOR_SET;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
break;
case HLP_SPRING:
@@ -400,7 +400,7 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
case HLP_CARROW:
if (t->flag & T_MODAL) {
t->flag |= T_MODAL_CURSOR_SET;
- WM_cursor_modal_set(win, CURSOR_NONE);
+ WM_cursor_modal_set(win, WM_CURSOR_NONE);
}
break;
default:
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 1be206e921a..b2d8671fbce 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -53,6 +53,7 @@
#include "ED_mesh.h"
#include "transform.h"
+#include "transform_convert.h"
typedef struct TransformModeItem {
const char *idname;
@@ -301,11 +302,11 @@ static void TRANSFORM_OT_create_orientation(struct wmOperatorType *ot)
WM_operatortype_props_advanced_begin(ot);
RNA_def_boolean(
- ot->srna, "use", false, "Use after creation", "Select orientation after its creation");
+ ot->srna, "use", false, "Use After Creation", "Select orientation after its creation");
RNA_def_boolean(ot->srna,
"overwrite",
false,
- "Overwrite previous",
+ "Overwrite Previous",
"Overwrite previously created orientation with same name");
}
@@ -573,7 +574,7 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
if (flags & P_ORIENT_AXIS_ORTHO) {
prop = RNA_def_property(ot->srna, "orient_axis_ortho", PROP_ENUM, PROP_NONE);
RNA_def_property_ui_text(prop, "Axis Ortho", "");
- RNA_def_property_enum_default(prop, 1);
+ RNA_def_property_enum_default(prop, 0);
RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -910,7 +911,6 @@ static void TRANSFORM_OT_shear(struct wmOperatorType *ot)
ot->poll_property = transform_poll_property;
RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Offset", "", -FLT_MAX, FLT_MAX);
- RNA_def_enum(ot->srna, "shear_axis", rna_enum_axis_xy_items, 0, "Shear Axis", "");
WM_operatortype_props_advanced_begin(ot);
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 14242f6ba40..571ce7a6bc2 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -633,14 +633,12 @@ static void initSnappingMode(TransInfo *t)
(obedit_type == -1)) // Object Mode
{
- if (t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR)) {
+ if (t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR | CTX_OBMODE_XFORM_OBDATA)) {
/* In "Edit Strokes" mode,
* snap tool can perform snap to selected or active objects (see T49632)
- * TODO: perform self snap in gpencil_strokes */
- t->tsnap.modeSelect = SNAP_ALL;
- }
- else if (t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) {
- /* When we're moving the origins, allow snapping onto our own geometry (see T69132). */
+ * TODO: perform self snap in gpencil_strokes.
+ *
+ * When we're moving the origins, allow snapping onto our own geometry (see T69132). */
t->tsnap.modeSelect = SNAP_ALL;
}
else {
@@ -1251,7 +1249,7 @@ static void TargetSnapClosest(TransInfo *t)
for (td = tc->data, i = 0; i < tc->data_len && td->flag & TD_SELECTED; i++, td++) {
const BoundBox *bb = NULL;
- if ((t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) == 0) {
+ if ((t->options & CTX_OBMODE_XFORM_OBDATA) == 0) {
bb = BKE_object_boundbox_get(td->ob);
}
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 7a8a123cf79..1601acb1c8f 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -221,22 +221,40 @@ static void iter_snap_objects(SnapObjectContext *sctx,
Base *base_act = view_layer->basact;
for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) {
- if ((BASE_VISIBLE(v3d, base)) && (base->flag_legacy & BA_SNAP_FIX_DEPS_FIASCO) == 0 &&
- !((snap_select == SNAP_NOT_SELECTED &&
- ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL))) ||
- (snap_select == SNAP_NOT_ACTIVE && base == base_act))) {
- Object *obj_eval = DEG_get_evaluated_object(sctx->depsgraph, base->object);
- if (obj_eval->transflag & OB_DUPLI) {
- DupliObject *dupli_ob;
- ListBase *lb = object_duplilist(sctx->depsgraph, sctx->scene, obj_eval);
- for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
- sob_callback(sctx, use_object_edit_cage, dupli_ob->ob, dupli_ob->mat, data);
- }
- free_object_duplilist(lb);
+
+ if (!BASE_VISIBLE(v3d, base)) {
+ continue;
+ }
+
+ if (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE) {
+ /* pass */
+ }
+ else if (base->flag_legacy & BA_SNAP_FIX_DEPS_FIASCO) {
+ continue;
+ }
+
+ if (snap_select == SNAP_NOT_SELECTED) {
+ if ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL)) {
+ continue;
}
+ }
+ else if (snap_select == SNAP_NOT_ACTIVE) {
+ if (base == base_act) {
+ continue;
+ }
+ }
- sob_callback(sctx, use_object_edit_cage, obj_eval, obj_eval->obmat, data);
+ Object *obj_eval = DEG_get_evaluated_object(sctx->depsgraph, base->object);
+ if (obj_eval->transflag & OB_DUPLI) {
+ DupliObject *dupli_ob;
+ ListBase *lb = object_duplilist(sctx->depsgraph, sctx->scene, obj_eval);
+ for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
+ sob_callback(sctx, use_object_edit_cage, dupli_ob->ob, dupli_ob->mat, data);
+ }
+ free_object_duplilist(lb);
}
+
+ sob_callback(sctx, use_object_edit_cage, obj_eval, obj_eval->obmat, data);
}
}
@@ -336,7 +354,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
const float ray_dir[3],
Object *ob,
Mesh *me,
- float obmat[4][4],
+ const float obmat[4][4],
const unsigned int ob_index,
bool use_hide,
/* read/write args */
@@ -509,7 +527,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
const float ray_dir[3],
Object *ob,
BMEditMesh *em,
- float obmat[4][4],
+ const float obmat[4][4],
const unsigned int ob_index,
/* read/write args */
float *ray_depth,
@@ -692,7 +710,7 @@ static bool raycastObj(SnapObjectContext *sctx,
const float ray_start[3],
const float ray_dir[3],
Object *ob,
- float obmat[4][4],
+ const float obmat[4][4],
const unsigned int ob_index,
bool use_obedit,
bool use_occlusion_test,
@@ -905,10 +923,10 @@ static bool raycastObjects(SnapObjectContext *sctx,
/* Test BoundBox */
static bool snap_bound_box_check_dist(float min[3],
- float max[3],
- float lpmat[4][4],
- float win_size[2],
- float mval[2],
+ const float max[3],
+ const float lpmat[4][4],
+ const float win_size[2],
+ const float mval[2],
float dist_px_sq)
{
/* In vertex and edges you need to get the pixel distance from ray to BoundBox,
@@ -1202,7 +1220,7 @@ static void cb_snap_tri_verts(void *userdata,
static short snap_mesh_polygon(SnapObjectContext *sctx,
SnapData *snapdata,
Object *ob,
- float obmat[4][4],
+ const float obmat[4][4],
/* read/write args */
float *dist_px,
/* return args */
@@ -1254,8 +1272,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
const MPoly *mp = &((SnapObjectData_Mesh *)sod)->poly[*r_index];
const MLoop *ml = &treedata->loop[mp->loopstart];
- if (snapdata->snap_to_flag &
- (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
elem = SCE_SNAP_MODE_EDGE;
BLI_assert(treedata->edge != NULL);
for (int i = mp->totloop; i--; ml++) {
@@ -1292,8 +1309,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
BMFace *f = BM_face_at_index(em->bm, *r_index);
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- if (snapdata->snap_to_flag &
- (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
elem = SCE_SNAP_MODE_EDGE;
BM_mesh_elem_index_ensure(em->bm, BM_EDGE);
BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE);
@@ -1346,7 +1362,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
SnapData *snapdata,
Object *ob,
- float obmat[4][4],
+ const float obmat[4][4],
float original_dist_px,
const float prev_co[3],
/* read/write args */
@@ -1362,22 +1378,6 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
return elem;
}
- float lpmat[4][4];
- mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
-
- struct DistProjectedAABBPrecalc neasrest_precalc;
- dist_squared_to_projected_aabb_precalc(
- &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval);
-
- Nearest2dUserData nearest2d = {
- .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
- };
-
- BVHTreeNearest nearest = {
- .index = -1,
- .dist_sq = SQUARE(original_dist_px),
- };
-
SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob);
if (sod == NULL) {
/* The object is in edit mode, and the key used
@@ -1388,18 +1388,22 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
BLI_assert(sod != NULL);
- if (sod->type == SNAP_MESH) {
- nearest2d.userdata = &((SnapObjectData_Mesh *)sod)->treedata;
- nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get;
- nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get;
- nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy;
- }
- else {
- BLI_assert(sod->type == SNAP_EDIT_MESH);
- nearest2d.userdata = BKE_editmesh_from_object(ob);
- nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get;
- nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get;
- nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy;
+ Nearest2dUserData nearest2d;
+ {
+ nearest2d.is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ if (sod->type == SNAP_MESH) {
+ nearest2d.userdata = &((SnapObjectData_Mesh *)sod)->treedata;
+ nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get;
+ nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get;
+ nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy;
+ }
+ else {
+ BLI_assert(sod->type == SNAP_EDIT_MESH);
+ nearest2d.userdata = BKE_editmesh_from_object(ob);
+ nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get;
+ nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get;
+ nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy;
+ }
}
int vindex[2];
@@ -1409,6 +1413,20 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
nearest2d.get_vert_co(vindex[0], &v_pair[0], nearest2d.userdata);
nearest2d.get_vert_co(vindex[1], &v_pair[1], nearest2d.userdata);
+ struct DistProjectedAABBPrecalc neasrest_precalc;
+ {
+ float lpmat[4][4];
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+
+ dist_squared_to_projected_aabb_precalc(
+ &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval);
+ }
+
+ BVHTreeNearest nearest = {
+ .index = -1,
+ .dist_sq = SQUARE(original_dist_px),
+ };
+
float lambda;
if (!isect_ray_seg_v3(neasrest_precalc.ray_origin,
neasrest_precalc.ray_direction,
@@ -1418,8 +1436,14 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
/* do nothing */
}
else {
- if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
- if (lambda < 0.25f || 0.75f < lambda) {
+ short snap_to_flag = snapdata->snap_to_flag;
+ int e_mode_len = ((snap_to_flag & SCE_SNAP_MODE_EDGE) != 0) +
+ ((snap_to_flag & SCE_SNAP_MODE_VERTEX) != 0) +
+ ((snap_to_flag & SCE_SNAP_MODE_EDGE_MIDPOINT) != 0);
+
+ float range = 1.0f / (2 * e_mode_len - 1);
+ if (snap_to_flag & SCE_SNAP_MODE_VERTEX) {
+ if (lambda < (range) || (1.0f - range) < lambda) {
int v_id = lambda < 0.5f ? 0 : 1;
if (test_projected_vert_dist(&neasrest_precalc,
@@ -1436,8 +1460,9 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
}
}
- if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE_MIDPOINT) {
- if (0.375f < lambda && lambda < 0.625f) {
+ if (snap_to_flag & SCE_SNAP_MODE_EDGE_MIDPOINT) {
+ range *= e_mode_len - 1;
+ if ((range) < lambda && lambda < (1.0f - range)) {
float vmid[3];
mid_v3_v3v3(vmid, v_pair[0], v_pair[1]);
@@ -1468,21 +1493,25 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
if (IN_RANGE(lambda, 0.0f, 1.0f)) {
interp_v3_v3v3(v_near, va_g, vb_g, lambda);
- if ((len_squared_v3v3(prev_co, v_near) > FLT_EPSILON) &&
- test_projected_vert_dist(&neasrest_precalc,
- NULL,
- 0,
- nearest2d.is_persp,
- v_near,
- &nearest.dist_sq,
- nearest.co)) {
- float v_nor[2][3];
- nearest2d.copy_vert_no(vindex[0], v_nor[0], nearest2d.userdata);
- nearest2d.copy_vert_no(vindex[1], v_nor[1], nearest2d.userdata);
- mid_v3_v3v3(nearest.no, v_nor[0], v_nor[1]);
+ if (len_squared_v3v3(prev_co, v_near) > FLT_EPSILON) {
+ dist_squared_to_projected_aabb_precalc(
+ &neasrest_precalc, snapdata->pmat, snapdata->win_size, snapdata->mval);
- nearest.index = *r_index;
- elem = SCE_SNAP_MODE_EDGE_PERPENDICULAR;
+ if (test_projected_vert_dist(&neasrest_precalc,
+ NULL,
+ 0,
+ nearest2d.is_persp,
+ v_near,
+ &nearest.dist_sq,
+ nearest.co)) {
+ float v_nor[2][3];
+ nearest2d.copy_vert_no(vindex[0], v_nor[0], nearest2d.userdata);
+ nearest2d.copy_vert_no(vindex[1], v_nor[1], nearest2d.userdata);
+ mid_v3_v3v3(nearest.no, v_nor[0], v_nor[1]);
+
+ nearest.index = *r_index;
+ elem = SCE_SNAP_MODE_EDGE_PERPENDICULAR;
+ }
}
}
}
@@ -1513,7 +1542,7 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
static short snapArmature(SnapData *snapdata,
Object *ob,
- float obmat[4][4],
+ const float obmat[4][4],
bool use_obedit,
/* read/write args */
float *dist_px,
@@ -1658,7 +1687,7 @@ static short snapArmature(SnapData *snapdata,
static short snapCurve(SnapData *snapdata,
Object *ob,
- float obmat[4][4],
+ const float obmat[4][4],
bool use_obedit,
/* read/write args */
float *dist_px,
@@ -1688,7 +1717,7 @@ static short snapCurve(SnapData *snapdata,
if (use_obedit == false) {
/* Test BoundBox */
- BoundBox *bb = BKE_curve_texspace_get(cu, NULL, NULL, NULL);
+ BoundBox *bb = BKE_curve_boundbox_get(ob);
if (bb && !snap_bound_box_check_dist(
bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) {
return 0;
@@ -1809,7 +1838,7 @@ static short snapCurve(SnapData *snapdata,
/* may extend later (for now just snaps to empty center) */
static short snapEmpty(SnapData *snapdata,
Object *ob,
- float obmat[4][4],
+ const float obmat[4][4],
/* read/write args */
float *dist_px,
/* return args */
@@ -1891,12 +1920,6 @@ static short snapCamera(const SnapObjectContext *sctx,
return retval;
}
- float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
- transpose_m4_m4(tobmat, obmat);
- for (int i = snapdata->clip_plane_len; i--;) {
- mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
- }
-
tracking = &clip->tracking;
BKE_tracking_get_camera_object_matrix(scene, object, orig_camera_mat);
@@ -1942,7 +1965,7 @@ static short snapCamera(const SnapObjectContext *sctx,
mul_m4_v3(vertex_obmat, bundle_pos);
if (test_projected_vert_dist(&neasrest_precalc,
- clip_planes_local,
+ snapdata->clip_plane,
snapdata->clip_plane_len,
is_persp,
bundle_pos,
@@ -1970,7 +1993,7 @@ static short snapMesh(SnapObjectContext *sctx,
SnapData *snapdata,
Object *ob,
Mesh *me,
- float obmat[4][4],
+ const float obmat[4][4],
/* read/write args */
float *dist_px,
/* return args */
@@ -2120,8 +2143,7 @@ static short snapMesh(SnapObjectContext *sctx,
last_index = nearest.index;
}
- if (snapdata->snap_to_flag &
- (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
if (bvhtree[0]) {
/* snap to loose edges */
BLI_bvhtree_find_nearest_projected(bvhtree[0],
@@ -2209,7 +2231,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
SnapData *snapdata,
Object *ob,
BMEditMesh *em,
- float obmat[4][4],
+ const float obmat[4][4],
/* read/write args */
float *dist_px,
/* return args */
@@ -2287,8 +2309,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
}
}
- if (snapdata->snap_to_flag &
- (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
if (sod->bvh_trees[1] == NULL) {
sod->bvh_trees[1] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(**sod->bvh_trees));
}
@@ -2335,7 +2356,6 @@ static short snapEditMesh(SnapObjectContext *sctx,
.index = -1,
.dist_sq = dist_px_sq,
};
- int last_index = nearest.index;
short elem = SCE_SNAP_MODE_VERTEX;
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
@@ -2345,7 +2365,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
}
- if (treedata_vert && snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
+ if (treedata_vert && (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
BLI_bvhtree_find_nearest_projected(treedata_vert->tree,
lpmat,
@@ -2356,12 +2376,11 @@ static short snapEditMesh(SnapObjectContext *sctx,
&nearest,
cb_snap_vert,
&nearest2d);
-
- last_index = nearest.index;
}
- if (treedata_edge && snapdata->snap_to_flag & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT |
- SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ if (treedata_edge && (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE)) {
+ int last_index = nearest.index;
+ nearest.index = -1;
BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_VERT);
BLI_bvhtree_find_nearest_projected(treedata_edge->tree,
lpmat,
@@ -2373,9 +2392,12 @@ static short snapEditMesh(SnapObjectContext *sctx,
cb_snap_edge,
&nearest2d);
- if (last_index != nearest.index) {
+ if (nearest.index != -1) {
elem = SCE_SNAP_MODE_EDGE;
}
+ else {
+ nearest.index = last_index;
+ }
}
if (nearest.index != -1) {
@@ -2770,11 +2792,11 @@ static short transform_snap_context_project_view3d_mixed_impl(
0);
short retval = 0;
- bool has_hit = false;
- int index = -1;
- float loc[3], no[3], obmat[4][4];
+ bool has_hit = false;
Object *ob = NULL;
+ float loc[3], no[3], obmat[4][4];
+ int index = -1;
const ARegion *ar = sctx->v3d_data.ar;
const RegionView3D *rv3d = ar->regiondata;
@@ -2783,7 +2805,6 @@ static short transform_snap_context_project_view3d_mixed_impl(
if (snap_to_flag & SCE_SNAP_MODE_FACE || use_occlusion_test) {
float ray_start[3], ray_normal[3];
-
if (!ED_view3d_win_to_ray_clipped_ex(sctx->depsgraph,
sctx->v3d_data.ar,
sctx->v3d_data.v3d,
@@ -2802,12 +2823,26 @@ static short transform_snap_context_project_view3d_mixed_impl(
if (has_hit && (snap_to_flag & SCE_SNAP_MODE_FACE)) {
retval = SCE_SNAP_MODE_FACE;
+
+ copy_v3_v3(r_loc, loc);
+ if (r_no) {
+ copy_v3_v3(r_no, no);
+ }
+ if (r_ob) {
+ *r_ob = ob;
+ }
+ if (r_obmat) {
+ copy_m4_m4(r_obmat, obmat);
+ }
+ if (r_index) {
+ *r_index = index;
+ }
}
}
if (snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT |
SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
- short elem;
+ short elem_test, elem = 0;
float dist_px_tmp = *dist_px;
SnapData snapdata;
@@ -2815,9 +2850,14 @@ static short transform_snap_context_project_view3d_mixed_impl(
snapdata.win_size[0] = ar->winx;
snapdata.win_size[1] = ar->winy;
copy_v2_v2(snapdata.mval, mval);
- snapdata.snap_to_flag = snap_to_flag;
snapdata.view_proj = rv3d->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO;
+ /* First snap to edge instead of middle or perpendicular. */
+ snapdata.snap_to_flag = snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE);
+ if (snap_to_flag & (SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ snapdata.snap_to_flag |= SCE_SNAP_MODE_EDGE;
+ }
+
planes_from_projmat(
snapdata.pmat, NULL, NULL, NULL, NULL, snapdata.clip_plane[0], snapdata.clip_plane[1]);
@@ -2838,10 +2878,9 @@ static short transform_snap_context_project_view3d_mixed_impl(
new_clipplane[3] += 0.01f;
/* Try to snap only to the polygon. */
- elem = snap_mesh_polygon(sctx, &snapdata, ob, obmat, &dist_px_tmp, loc, no, &index);
-
- if (elem) {
- retval = elem;
+ elem_test = snap_mesh_polygon(sctx, &snapdata, ob, obmat, &dist_px_tmp, loc, no, &index);
+ if (elem_test) {
+ elem = elem_test;
}
/* Add the new clip plane to the beginning of the list. */
@@ -2853,45 +2892,41 @@ static short transform_snap_context_project_view3d_mixed_impl(
snapdata.has_occlusion_plane = true;
}
- elem = snapObjectsRay(sctx, &snapdata, params, &dist_px_tmp, loc, no, &index, &ob, obmat);
-
- if (elem) {
- retval = elem;
+ elem_test = snapObjectsRay(sctx, &snapdata, params, &dist_px_tmp, loc, no, &index, &ob, obmat);
+ if (elem_test) {
+ elem = elem_test;
}
- if ((retval == SCE_SNAP_MODE_EDGE) &&
+ if ((elem == SCE_SNAP_MODE_EDGE) &&
(snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE_MIDPOINT |
SCE_SNAP_MODE_EDGE_PERPENDICULAR))) {
+ snapdata.snap_to_flag = snap_to_flag;
elem = snap_mesh_edge_verts_mixed(
sctx, &snapdata, ob, obmat, *dist_px, prev_co, &dist_px_tmp, loc, no, &index);
}
- if (elem) {
+ if (elem & snap_to_flag) {
retval = elem;
- }
- retval &= snap_to_flag;
- *dist_px = dist_px_tmp;
- }
+ copy_v3_v3(r_loc, loc);
+ if (r_no) {
+ copy_v3_v3(r_no, no);
+ }
+ if (r_ob) {
+ *r_ob = ob;
+ }
+ if (r_obmat) {
+ copy_m4_m4(r_obmat, obmat);
+ }
+ if (r_index) {
+ *r_index = index;
+ }
- if (retval) {
- copy_v3_v3(r_loc, loc);
- if (r_no) {
- copy_v3_v3(r_no, no);
- }
- if (r_ob) {
- *r_ob = ob;
- }
- if (r_obmat) {
- copy_m4_m4(r_obmat, obmat);
- }
- if (r_index) {
- *r_index = index;
+ *dist_px = dist_px_tmp;
}
- return retval;
}
- return 0;
+ return retval;
}
short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index e0f4d1cf465..315a4c73e5f 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -31,12 +31,12 @@
#include "DNA_object_types.h"
#include "BLI_utildefines.h"
-#include "BLI_callbacks.h"
#include "BLI_listbase.h"
#include "BLT_translation.h"
#include "BKE_blender_undo.h"
+#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_main.h"
@@ -172,8 +172,8 @@ static int ed_undo_step_impl(
/* Note: ignore grease pencil for now. */
Main *bmain = CTX_data_main(C);
wm->op_undo_depth++;
- BLI_callback_exec(
- bmain, &scene->id, (step_for_callback > 0) ? BLI_CB_EVT_UNDO_PRE : BLI_CB_EVT_REDO_PRE);
+ BKE_callback_exec_id(
+ bmain, &scene->id, (step_for_callback > 0) ? BKE_CB_EVT_UNDO_PRE : BKE_CB_EVT_REDO_PRE);
wm->op_undo_depth--;
}
@@ -220,8 +220,8 @@ static int ed_undo_step_impl(
Main *bmain = CTX_data_main(C);
scene = CTX_data_scene(C);
wm->op_undo_depth++;
- BLI_callback_exec(
- bmain, &scene->id, step_for_callback > 0 ? BLI_CB_EVT_UNDO_POST : BLI_CB_EVT_REDO_POST);
+ BKE_callback_exec_id(
+ bmain, &scene->id, step_for_callback > 0 ? BKE_CB_EVT_UNDO_POST : BKE_CB_EVT_REDO_POST);
wm->op_undo_depth--;
}
@@ -670,7 +670,7 @@ static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
}
if (item[i].identifier) {
uiItemIntO(column, item[i].name, item[i].icon, op->type->idname, "item", item[i].value);
- ++c;
+ c++;
add_col = true;
}
}
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index c2566d111cf..f5548119e0a 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -245,7 +245,7 @@ bool ED_editors_flush_edits(Main *bmain, bool for_render)
* may cause a flush on saving: T53986. */
if ((ob->sculpt && ob->sculpt->cache) == 0) {
/* flush multires changes (for sculpt) */
- multires_force_update(ob);
+ multires_flush_sculpt_updates(ob);
has_edited = true;
if (for_render) {
diff --git a/source/blender/editors/uvedit/uvedit_buttons.c b/source/blender/editors/uvedit/uvedit_buttons.c
index 2abbe67237e..44bffc76859 100644
--- a/source/blender/editors/uvedit/uvedit_buttons.c
+++ b/source/blender/editors/uvedit/uvedit_buttons.c
@@ -98,7 +98,7 @@ static int uvedit_center(
}
static void uvedit_translate(
- Scene *scene, Object **objects, uint objects_len, Image *ima, float delta[2])
+ Scene *scene, Object **objects, uint objects_len, Image *ima, const float delta[2])
{
BMFace *f;
BMLoop *l;
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index fe761f65702..fafd54804c0 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -54,10 +54,8 @@
#include "GPU_batch.h"
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
-#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
#include "GPU_state.h"
-#include "GPU_draw.h"
#include "ED_image.h"
#include "ED_mesh.h"
@@ -69,6 +67,17 @@
#include "uvedit_intern.h"
+/* Struct containing the needed batches per object.
+ * this optimizes the way how data is requested from
+ * the draw manager. */
+typedef struct UVEditGPUBatches {
+ Object *ob_eval;
+ GPUBatch *faces;
+ GPUBatch *edges;
+ GPUBatch *verts;
+ GPUBatch *facedots;
+} UVEditGPUBatches;
+
static int draw_uvs_face_check(const ToolSettings *ts)
{
/* checks if we are selecting only faces */
@@ -164,40 +173,47 @@ void ED_image_draw_cursor(ARegion *ar, const float cursor[2])
static void uvedit_get_batches(Object *ob,
SpaceImage *sima,
const Scene *scene,
- GPUBatch **faces,
- GPUBatch **edges,
- GPUBatch **verts,
- GPUBatch **facedots)
+ UVEditGPUBatches *batches,
+ float *tot_area,
+ float *tot_area_uv)
{
+ float *tmp_tot_area, *tmp_tot_area_uv;
int drawfaces = draw_uvs_face_check(scene->toolsettings);
const bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0;
const bool draw_faces = (sima->flag & SI_NO_DRAWFACES) == 0;
DRW_mesh_batch_cache_validate(ob->data);
- *edges = DRW_mesh_batch_cache_get_edituv_edges(ob->data);
- *verts = DRW_mesh_batch_cache_get_edituv_verts(ob->data);
+ batches->edges = DRW_mesh_batch_cache_get_edituv_edges(ob->data);
+ batches->verts = DRW_mesh_batch_cache_get_edituv_verts(ob->data);
if (drawfaces) {
- *facedots = DRW_mesh_batch_cache_get_edituv_facedots(ob->data);
+ batches->facedots = DRW_mesh_batch_cache_get_edituv_facedots(ob->data);
}
else {
- *facedots = NULL;
+ batches->facedots = NULL;
}
if (draw_stretch && (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)) {
- *faces = DRW_mesh_batch_cache_get_edituv_faces_strech_area(ob->data);
+ batches->faces = DRW_mesh_batch_cache_get_edituv_faces_stretch_area(
+ ob->data, &tmp_tot_area, &tmp_tot_area_uv);
}
else if (draw_stretch) {
- *faces = DRW_mesh_batch_cache_get_edituv_faces_strech_angle(ob->data);
+ batches->faces = DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(ob->data);
}
else if (draw_faces) {
- *faces = DRW_mesh_batch_cache_get_edituv_faces(ob->data);
+ batches->faces = DRW_mesh_batch_cache_get_edituv_faces(ob->data);
}
else {
- *faces = NULL;
+ batches->faces = NULL;
}
DRW_mesh_batch_cache_create_requested(ob, ob->data, scene, false, false);
+
+ if (draw_stretch && (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)) {
+ /* after create_requested we can load the actual areas */
+ *tot_area += *tmp_tot_area;
+ *tot_area_uv += *tmp_tot_area_uv;
+ }
}
static void draw_uvs_shadow(SpaceImage *UNUSED(sima),
@@ -279,10 +295,14 @@ static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph)
}
/* draws uv's in the image space */
-static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *depsgraph)
+static void draw_uvs(SpaceImage *sima,
+ Scene *scene,
+ Depsgraph *depsgraph,
+ UVEditGPUBatches *batch,
+ float tot_area_ratio,
+ float tot_area_ratio_inv)
{
- GPUBatch *faces, *edges, *verts, *facedots;
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, obedit);
+ Object *ob_eval = batch->ob_eval;
const ToolSettings *ts = scene->toolsettings;
float col1[4], col2[4], col3[4], transparent[4] = {0.0f, 0.0f, 0.0f, 0.0f};
@@ -296,12 +316,10 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
/* When sync selection is enabled, all faces are drawn (except for hidden)
* so if cage is the same as the final, there is no point in drawing this. */
if (!((ts->uv_flag & UV_SYNC_SELECTION) && is_cage_like_final_meshes)) {
- draw_uvs_shadow(sima, scene, obedit, depsgraph);
+ draw_uvs_shadow(sima, scene, ob_eval, depsgraph);
}
}
- uvedit_get_batches(ob_eval, sima, scene, &faces, &edges, &verts, &facedots);
-
bool interpedges;
bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0;
if (ts->uv_flag & UV_SYNC_SELECTION) {
@@ -314,8 +332,8 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
GPU_blend_set_func_separate(
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- if (faces) {
- GPU_batch_program_set_builtin(faces,
+ if (batch->faces) {
+ GPU_batch_program_set_builtin(batch->faces,
(draw_stretch) ? (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA) ?
GPU_SHADER_2D_UV_FACES_STRETCH_AREA :
GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE :
@@ -328,23 +346,27 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
UI_GetThemeColor4fv(TH_FACE_SELECT, col2);
UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, col3);
col3[3] *= 0.2; /* Simulate dithering */
- GPU_batch_uniform_4fv(faces, "faceColor", col1);
- GPU_batch_uniform_4fv(faces, "selectColor", col2);
- GPU_batch_uniform_4fv(faces, "activeColor", col3);
+ GPU_batch_uniform_4fv(batch->faces, "faceColor", col1);
+ GPU_batch_uniform_4fv(batch->faces, "selectColor", col2);
+ GPU_batch_uniform_4fv(batch->faces, "activeColor", col3);
}
else if (sima->dt_uvstretch == SI_UVDT_STRETCH_ANGLE) {
float asp[2];
ED_space_image_get_uv_aspect(sima, &asp[0], &asp[1]);
- GPU_batch_uniform_2fv(faces, "aspect", asp);
+ GPU_batch_uniform_2fv(batch->faces, "aspect", asp);
+ }
+ else if (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA) {
+ GPU_batch_uniform_1f(batch->faces, "totalAreaRatio", tot_area_ratio);
+ GPU_batch_uniform_1f(batch->faces, "totalAreaRatioInv", tot_area_ratio_inv);
}
- GPU_batch_draw(faces);
+ GPU_batch_draw(batch->faces);
if (!draw_stretch) {
GPU_blend(false);
}
}
- if (edges) {
+ if (batch->edges) {
if (sima->flag & SI_SMOOTH_UV) {
GPU_line_smooth(true);
GPU_blend(true);
@@ -356,14 +378,16 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
GPU_viewport_size_get_f(viewport_size);
GPU_line_width(1.0f);
- GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
- GPU_batch_uniform_4fv_array(edges, "colors", 2, (float *)dash_colors);
- GPU_batch_uniform_2f(
- edges, "viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
- GPU_batch_uniform_1i(edges, "colors_len", 2); /* "advanced" mode */
- GPU_batch_uniform_1f(edges, "dash_width", 4.0f);
- GPU_batch_uniform_1f(edges, "dash_factor", 0.5f);
- GPU_batch_draw(edges);
+ GPU_batch_program_set_builtin(batch->edges, GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ GPU_batch_uniform_4fv_array(batch->edges, "colors", 2, (float *)dash_colors);
+ GPU_batch_uniform_2f(batch->edges,
+ "viewport_size",
+ viewport_size[2] / UI_DPI_FAC,
+ viewport_size[3] / UI_DPI_FAC);
+ GPU_batch_uniform_1i(batch->edges, "colors_len", 2); /* "advanced" mode */
+ GPU_batch_uniform_1f(batch->edges, "dash_width", 4.0f);
+ GPU_batch_uniform_1f(batch->edges, "dash_factor", 0.5f);
+ GPU_batch_draw(batch->edges);
break;
}
case SI_UVDT_BLACK:
@@ -376,14 +400,14 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
UI_GetThemeColor4fv(TH_EDGE_SELECT, col2);
GPU_batch_program_set_builtin(
- edges, (interpedges) ? GPU_SHADER_2D_UV_EDGES_SMOOTH : GPU_SHADER_2D_UV_EDGES);
+ batch->edges, (interpedges) ? GPU_SHADER_2D_UV_EDGES_SMOOTH : GPU_SHADER_2D_UV_EDGES);
if (sima->dt_uv == SI_UVDT_OUTLINE) {
/* Black Outline. */
GPU_line_width(3.0f);
- GPU_batch_uniform_4f(edges, "edgeColor", 0.0f, 0.0f, 0.0f, 1.0f);
- GPU_batch_uniform_4f(edges, "selectColor", 0.0f, 0.0f, 0.0f, 1.0f);
- GPU_batch_draw(edges);
+ GPU_batch_uniform_4f(batch->edges, "edgeColor", 0.0f, 0.0f, 0.0f, 1.0f);
+ GPU_batch_uniform_4f(batch->edges, "selectColor", 0.0f, 0.0f, 0.0f, 1.0f);
+ GPU_batch_draw(batch->edges);
UI_GetThemeColor4fv(TH_WIRE_EDIT, col1);
}
@@ -397,9 +421,9 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
/* Inner Line. Use depth test to insure selection is drawn on top. */
GPU_depth_test(true);
GPU_line_width(1.0f);
- GPU_batch_uniform_4fv(edges, "edgeColor", col1);
- GPU_batch_uniform_4fv(edges, "selectColor", col2);
- GPU_batch_draw(edges);
+ GPU_batch_uniform_4fv(batch->edges, "edgeColor", col1);
+ GPU_batch_uniform_4fv(batch->edges, "selectColor", col2);
+ GPU_batch_draw(batch->edges);
GPU_depth_test(false);
glProvokingVertex(GL_LAST_VERTEX_CONVENTION);
@@ -411,44 +435,44 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
GPU_blend(false);
}
}
- if (verts || facedots) {
+ if (batch->verts || batch->facedots) {
UI_GetThemeColor4fv(TH_VERTEX_SELECT, col2);
- if (verts) {
+ if (batch->verts) {
const float point_size = UI_GetThemeValuef(TH_VERTEX_SIZE);
const float pinned_col[4] = {1.0f, 0.0f, 0.0f, 1.0f}; /* TODO Theme? */
UI_GetThemeColor4fv(TH_VERTEX, col1);
GPU_blend(true);
GPU_program_point_size(true);
- GPU_batch_program_set_builtin(verts, GPU_SHADER_2D_UV_VERTS);
- GPU_batch_uniform_4f(verts, "vertColor", col1[0], col1[1], col1[2], 1.0f);
- GPU_batch_uniform_4fv(verts, "selectColor", transparent);
- GPU_batch_uniform_4fv(verts, "pinnedColor", pinned_col);
- GPU_batch_uniform_1f(verts, "pointSize", (point_size + 1.5f) * M_SQRT2);
- GPU_batch_uniform_1f(verts, "outlineWidth", 0.75f);
- GPU_batch_draw(verts);
+ GPU_batch_program_set_builtin(batch->verts, GPU_SHADER_2D_UV_VERTS);
+ GPU_batch_uniform_4f(batch->verts, "vertColor", col1[0], col1[1], col1[2], 1.0f);
+ GPU_batch_uniform_4fv(batch->verts, "selectColor", transparent);
+ GPU_batch_uniform_4fv(batch->verts, "pinnedColor", pinned_col);
+ GPU_batch_uniform_1f(batch->verts, "pointSize", (point_size + 1.5f) * M_SQRT2);
+ GPU_batch_uniform_1f(batch->verts, "outlineWidth", 0.75f);
+ GPU_batch_draw(batch->verts);
/* We have problem in this mode when face order make some verts
* appear unselected because an adjacent face is not selected and
* render after the selected face.
* So, to avoid sorting verts by state we just render selected verts
* on top. A bit overkill but it's simple. */
- GPU_batch_uniform_4fv(verts, "vertColor", transparent);
- GPU_batch_uniform_4fv(verts, "selectColor", col2);
- GPU_batch_draw(verts);
+ GPU_batch_uniform_4fv(batch->verts, "vertColor", transparent);
+ GPU_batch_uniform_4fv(batch->verts, "selectColor", col2);
+ GPU_batch_draw(batch->verts);
GPU_blend(false);
GPU_program_point_size(false);
}
- if (facedots) {
+ if (batch->facedots) {
const float point_size = UI_GetThemeValuef(TH_FACEDOT_SIZE);
GPU_point_size(point_size);
UI_GetThemeColor4fv(TH_WIRE, col1);
- GPU_batch_program_set_builtin(facedots, GPU_SHADER_2D_UV_FACEDOTS);
- GPU_batch_uniform_4fv(facedots, "vertColor", col1);
- GPU_batch_uniform_4fv(facedots, "selectColor", col2);
- GPU_batch_draw(facedots);
+ GPU_batch_program_set_builtin(batch->facedots, GPU_SHADER_2D_UV_FACEDOTS);
+ GPU_batch_uniform_4fv(batch->facedots, "vertColor", col1);
+ GPU_batch_uniform_4fv(batch->facedots, "selectColor", col2);
+ GPU_batch_draw(batch->facedots);
}
}
}
@@ -495,10 +519,32 @@ void ED_uvedit_draw_main(SpaceImage *sima,
GPU_clear_depth(1.0f);
GPU_clear(GPU_DEPTH_BIT);
}
+
+ /* go over all objects and create the batches + add their areas to the total */
+ UVEditGPUBatches *batches = MEM_mallocN(sizeof(UVEditGPUBatches) * objects_len, __func__);
+ float tot_area = 0.0f;
+ float tot_area_uv = 0.0f;
+ float tot_area_ratio = 0.0f;
+ float tot_area_ratio_inv = 0.0f;
+
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *ob_iter = objects[ob_index];
- draw_uvs(sima, scene, ob_iter, depsgraph);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter);
+ batches[ob_index].ob_eval = ob_eval;
+ uvedit_get_batches(ob_eval, sima, scene, &batches[ob_index], &tot_area, &tot_area_uv);
+ }
+
+ if (tot_area > FLT_EPSILON && tot_area_uv > FLT_EPSILON) {
+ tot_area_ratio = tot_area / tot_area_uv;
+ tot_area_ratio_inv = tot_area_uv / tot_area;
+ }
+
+ /* go over all batches created in the previous loop and draw them */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ UVEditGPUBatches *batch = &batches[ob_index];
+ draw_uvs(sima, scene, depsgraph, batch, tot_area_ratio, tot_area_ratio_inv);
}
+ MEM_freeN(batches);
MEM_freeN(objects);
}
else {
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index cd7e5f9ba09..0d258ba542b 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -4458,7 +4458,7 @@ static int uv_select_overlap(bContext *C, const bool extend)
overlap_data[data_index].face_index = face_index;
/* BVH needs 3D, overlap data uses 2D. */
- float tri[3][3] = {
+ const float tri[3][3] = {
{UNPACK2(uv_verts[indices[t][0]]), 0.0f},
{UNPACK2(uv_verts[indices[t][1]]), 0.0f},
{UNPACK2(uv_verts[indices[t][2]]), 0.0f},
@@ -4872,12 +4872,6 @@ static void UV_OT_reveal(wmOperatorType *ot)
/** \name Set 2D Cursor Operator
* \{ */
-static bool uv_set_2d_cursor_poll(bContext *C)
-{
- return ED_operator_uvedit_space_image(C) || ED_space_image_maskedit_poll(C) ||
- ED_space_image_paint_curve(C);
-}
-
static int uv_set_2d_cursor_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -4923,7 +4917,7 @@ static void UV_OT_cursor_set(wmOperatorType *ot)
/* api callbacks */
ot->exec = uv_set_2d_cursor_exec;
ot->invoke = uv_set_2d_cursor_invoke;
- ot->poll = uv_set_2d_cursor_poll;
+ ot->poll = ED_space_image_cursor_poll;
/* properties */
RNA_def_float_vector(ot->srna,
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index 76c3a6d6c4a..5a8301fae67 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -1808,7 +1808,7 @@ static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *ar
GPU_vertbuf_attr_set(
vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + 2]);
- for (j = 1; j < stitch_preview->uvs_per_polygon[i] - 1; ++j) {
+ for (j = 1; j < stitch_preview->uvs_per_polygon[i] - 1; j++) {
GPU_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index]);
GPU_vertbuf_attr_set(
vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 0) * 2]);
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 2d8f40ea5af..1db038bef94 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -1258,7 +1258,7 @@ static void uv_map_rotation_matrix_ex(float result[4][4],
float upangledeg,
float sideangledeg,
float radius,
- float offset[4])
+ const float offset[4])
{
float rotup[4][4], rotside[4][4], viewmatrix[4][4], rotobj[4][4];
float sideangle = 0.0f, upangle = 0.0f;
@@ -2035,9 +2035,9 @@ void UV_OT_reset(wmOperatorType *ot)
/****************** Sphere Project operator ***************/
static void uv_sphere_project(float target[2],
- float source[3],
- float center[3],
- float rotmat[4][4])
+ const float source[3],
+ const float center[3],
+ const float rotmat[4][4])
{
float pv[3];
@@ -2162,9 +2162,9 @@ void UV_OT_sphere_project(wmOperatorType *ot)
/***************** Cylinder Project operator **************/
static void uv_cylinder_project(float target[2],
- float source[3],
- float center[3],
- float rotmat[4][4])
+ const float source[3],
+ const float center[3],
+ const float rotmat[4][4])
{
float pv[3];
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 984a2d01a68..06087cd7fa6 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -105,10 +105,6 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str
freestyle_scene->r.border.xmax = old_scene->r.border.xmax;
freestyle_scene->r.border.ymax = old_scene->r.border.ymax;
strcpy(freestyle_scene->r.pic, old_scene->r.pic);
- freestyle_scene->r.safety.xmin = old_scene->r.safety.xmin;
- freestyle_scene->r.safety.ymin = old_scene->r.safety.ymin;
- freestyle_scene->r.safety.xmax = old_scene->r.safety.xmax;
- freestyle_scene->r.safety.ymax = old_scene->r.safety.ymax;
freestyle_scene->r.dither_intensity = old_scene->r.dither_intensity;
STRNCPY(freestyle_scene->r.engine, old_scene->r.engine);
if (G.debug & G_DEBUG_FREESTYLE) {
@@ -164,7 +160,8 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str
_nodetree_hash = BLI_ghash_ptr_new("BlenderStrokeRenderer::_nodetree_hash");
// Depsgraph
- freestyle_depsgraph = DEG_graph_new(freestyle_scene, view_layer, DAG_EVAL_RENDER);
+ freestyle_depsgraph = DEG_graph_new(
+ freestyle_bmain, freestyle_scene, view_layer, DAG_EVAL_RENDER);
DEG_graph_id_tag_update(freestyle_bmain, freestyle_depsgraph, &freestyle_scene->id, 0);
DEG_graph_id_tag_update(freestyle_bmain, freestyle_depsgraph, &object_camera->id, 0);
DEG_graph_tag_relations_update(freestyle_depsgraph);
@@ -865,7 +862,7 @@ Object *BlenderStrokeRenderer::NewMesh() const
BLI_snprintf(name, MAX_ID_NAME, "0%08xME", mesh_id);
ob->data = BKE_mesh_add(freestyle_bmain, name);
- Collection *collection_master = BKE_collection_master(freestyle_scene);
+ Collection *collection_master = freestyle_scene->master_collection;
BKE_collection_object_add(freestyle_bmain, collection_master, ob);
DEG_graph_tag_relations_update(freestyle_depsgraph);
diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
index 4552ce849f2..07839ac6e61 100644
--- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
+++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
@@ -42,6 +42,7 @@ extern "C" {
#include "DNA_material_types.h"
#include "DNA_text_types.h"
+#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_freestyle.h"
#include "BKE_global.h"
@@ -55,7 +56,6 @@ extern "C" {
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_math_color_blend.h"
-#include "BLI_callbacks.h"
#include "BPY_extern.h"
@@ -80,7 +80,10 @@ static AppView *view = NULL;
static FreestyleLineSet lineset_buffer;
static bool lineset_copied = false;
-static void load_post_callback(struct Main * /*main*/, struct ID * /*id*/, void * /*arg*/)
+static void load_post_callback(struct Main * /*main*/,
+ struct PointerRNA ** /*pointers*/,
+ const int /*num_pointers*/,
+ void * /*arg*/)
{
lineset_copied = false;
}
@@ -111,7 +114,7 @@ void FRS_initialize()
g_freestyle.scene = NULL;
lineset_copied = false;
- BLI_callback_add(&load_post_callback_funcstore, BLI_CB_EVT_LOAD_POST);
+ BKE_callback_add(&load_post_callback_funcstore, BKE_CB_EVT_LOAD_POST);
freestyle_is_initialized = 1;
}
@@ -649,7 +652,7 @@ Render *FRS_do_stroke_rendering(Render *re, ViewLayer *view_layer, int render)
/* Create depsgraph and evaluate scene. */
ViewLayer *scene_view_layer = (ViewLayer *)BLI_findstring(
&re->scene->view_layers, view_layer->name, offsetof(ViewLayer, name));
- Depsgraph *depsgraph = DEG_graph_new(re->scene, scene_view_layer, DAG_EVAL_RENDER);
+ Depsgraph *depsgraph = DEG_graph_new(re->main, re->scene, scene_view_layer, DAG_EVAL_RENDER);
BKE_scene_graph_update_for_newframe(depsgraph, re->main);
// prepare Freestyle:
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
index 5209313f717..2d1a845330b 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -78,17 +78,17 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
bool is_stroke_affected_by_modifier(Object *ob,
char *mlayername,
char *mmaterialname,
- int mpassindex,
- int gpl_passindex,
- int minpoints,
+ const int mpassindex,
+ const int gpl_passindex,
+ const int minpoints,
bGPDlayer *gpl,
bGPDstroke *gps,
- bool inv1,
- bool inv2,
- bool inv3,
- bool inv4)
+ const bool inv1,
+ const bool inv2,
+ const bool inv3,
+ const bool inv4)
{
- Material *ma = give_current_material(ob, gps->mat_nr + 1);
+ Material *ma = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
MaterialGPencilStyle *gp_style = ma->gp_style;
/* omit if filter by layer */
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
index 7f00e072cda..2b1f8dbc71a 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
@@ -35,15 +35,15 @@ struct bGPDstroke;
bool is_stroke_affected_by_modifier(struct Object *ob,
char *mlayername,
char *mmaterialname,
- int mpassindex,
- int gpl_passindex,
- int minpoints,
+ const int mpassindex,
+ const int gpl_passindex,
+ const int minpoints,
bGPDlayer *gpl,
bGPDstroke *gps,
- bool inv1,
- bool inv2,
- bool inv3,
- bool inv4);
+ const bool inv1,
+ const bool inv2,
+ const bool inv3,
+ const bool inv4);
float get_modifier_point_weight(struct MDeformVert *dvert, bool inverse, int def_nr);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
index acf9b5c3642..1f2f0554dd5 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
@@ -158,8 +158,7 @@ static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the armature is missing).
*
- * In other cases it should be impossible to have a type missmatch.
- */
+ * In other cases it should be impossible to have a type mismatch. */
return !mmd->object || mmd->object->type != OB_ARMATURE;
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
index 741acfbe405..cb429b874a2 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
@@ -119,7 +119,7 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData
for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- Material *mat = give_current_material(ob, gps->mat_nr + 1);
+ Material *mat = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
if (mat == NULL) {
continue;
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
index 810a2ba7e25..234b4deeceb 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
@@ -63,8 +63,8 @@ struct GPHookData_cb {
float falloff_sq;
float fac_orig;
- unsigned int use_falloff : 1;
- unsigned int use_uniform : 1;
+ uint use_falloff : 1;
+ uint use_uniform : 1;
float cent[3];
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
index 765967d8346..6b74f96ce31 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
@@ -172,7 +172,7 @@ static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the lattice is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
return !mmd->object || mmd->object->type != OB_LATTICE;
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
index 112dfc2e9dc..e391adde829 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
@@ -126,7 +126,7 @@ static void generateStrokes(GpencilModifierData *md,
int i;
/* check each axis for mirroring */
- for (int xi = 0; xi < 3; ++xi) {
+ for (int xi = 0; xi < 3; xi++) {
if (mmd->flag & (GP_MIRROR_AXIS_X << xi)) {
/* count strokes to avoid infinite loop after adding new strokes to tail of listbase */
@@ -208,7 +208,7 @@ static int getDuplicationFactor(GpencilModifierData *md)
MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md;
int factor = 1;
/* create a duplication for each axis */
- for (int xi = 0; xi < 3; ++xi) {
+ for (int xi = 0; xi < 3; xi++) {
if (mmd->flag & (GP_MIRROR_AXIS_X << xi)) {
factor++;
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
index 346d1e834a6..22610771045 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
@@ -89,38 +89,56 @@ static void deformStroke(GpencilModifierData *md,
return;
}
- if (mmd->modify_color != GP_MODIFY_COLOR_FILL) {
- gps->runtime.tmp_stroke_rgba[3] *= mmd->factor;
- /* if factor is > 1, then force opacity */
- if (mmd->factor > 1.0f) {
- gps->runtime.tmp_stroke_rgba[3] += mmd->factor - 1.0f;
+ if (mmd->opacity_mode == GP_OPACITY_MODE_MATERIAL) {
+ if (mmd->modify_color != GP_MODIFY_COLOR_FILL) {
+ gps->runtime.tmp_stroke_rgba[3] *= mmd->factor;
+ /* if factor is > 1, then force opacity */
+ if (mmd->factor > 1.0f) {
+ gps->runtime.tmp_stroke_rgba[3] += mmd->factor - 1.0f;
+ }
+ CLAMP(gps->runtime.tmp_stroke_rgba[3], 0.0f, 1.0f);
}
- CLAMP(gps->runtime.tmp_stroke_rgba[3], 0.0f, 1.0f);
- }
- if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) {
- gps->runtime.tmp_fill_rgba[3] *= mmd->factor;
- /* if factor is > 1, then force opacity */
- if (mmd->factor > 1.0f && gps->runtime.tmp_fill_rgba[3] > 1e-5) {
- gps->runtime.tmp_fill_rgba[3] += mmd->factor - 1.0f;
+ if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) {
+ gps->runtime.tmp_fill_rgba[3] *= mmd->factor;
+ /* if factor is > 1, then force opacity */
+ if (mmd->factor > 1.0f && gps->runtime.tmp_fill_rgba[3] > 1e-5) {
+ gps->runtime.tmp_fill_rgba[3] += mmd->factor - 1.0f;
+ }
+ CLAMP(gps->runtime.tmp_fill_rgba[3], 0.0f, 1.0f);
}
- CLAMP(gps->runtime.tmp_fill_rgba[3], 0.0f, 1.0f);
- }
- /* if opacity > 1.0, affect the strength of the stroke */
- if (mmd->factor > 1.0f) {
+ /* if opacity > 1.0, affect the strength of the stroke */
+ if (mmd->factor > 1.0f) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ pt->strength += mmd->factor - 1.0f;
+ CLAMP(pt->strength, 0.0f, 1.0f);
+ }
+ }
+ }
+ /* Apply opacity by strength */
+ else {
for (int i = 0; i < gps->totpoints; i++) {
bGPDspoint *pt = &gps->points[i];
MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
/* verify vertex group */
- const float weight = get_modifier_point_weight(
+ float weight = get_modifier_point_weight(
dvert, (mmd->flag & GP_OPACITY_INVERT_VGROUP) != 0, def_nr);
if (weight < 0.0f) {
+ continue;
+ }
+ if (def_nr < 0) {
pt->strength += mmd->factor - 1.0f;
}
else {
- pt->strength += (mmd->factor - 1.0f) * weight;
+ /* High factor values, change weight too. */
+ if ((mmd->factor > 1.0f) && (weight < 1.0f)) {
+ weight += mmd->factor - 1.0f;
+ CLAMP(weight, 0.0f, 1.0f);
+ }
+ pt->strength += (mmd->factor - 1) * weight;
}
CLAMP(pt->strength, 0.0f, 1.0f);
}
@@ -137,7 +155,7 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData
for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- Material *mat = give_current_material(ob, gps->mat_nr + 1);
+ Material *mat = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
if (mat == NULL) {
continue;
}
@@ -152,8 +170,10 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData
deformStroke(md, depsgraph, ob, gpl, gpf, gps);
- gpencil_apply_modifier_material(
- bmain, ob, mat, gh_color, gps, (bool)(mmd->flag & GP_OPACITY_CREATE_COLORS));
+ if (mmd->opacity_mode == GP_OPACITY_MODE_MATERIAL) {
+ gpencil_apply_modifier_material(
+ bmain, ob, mat, gh_color, gps, (bool)(mmd->flag & GP_OPACITY_CREATE_COLORS));
+ }
}
}
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
index 741555722b5..ce75ca59fe1 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
@@ -65,12 +65,16 @@ static void deformStroke(GpencilModifierData *md,
{
SubdivGpencilModifierData *mmd = (SubdivGpencilModifierData *)md;
+ /* It makes sense when adding points to a straight line */
+ /* e.g. for creating thickness variation in later modifiers. */
+ const int minimum_vert = (mmd->flag | GP_SUBDIV_SIMPLE) ? 2 : 3;
+
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
mmd->materialname,
mmd->pass_index,
mmd->layer_pass,
- 3,
+ minimum_vert,
gpl,
gps,
mmd->flag & GP_SUBDIV_INVERT_LAYER,
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
index bfb2c62cef6..f6ddcf89bcf 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
@@ -125,7 +125,7 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData
for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- Material *mat = give_current_material(ob, gps->mat_nr + 1);
+ Material *mat = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
if (mat == NULL) {
continue;
}
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index fb7d3c1ace8..bc08da4b2cb 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -116,6 +116,7 @@ set(SRC
intern/gpu_batch_private.h
intern/gpu_codegen.h
intern/gpu_context_private.h
+ intern/gpu_material_library.h
intern/gpu_matrix_private.h
intern/gpu_primitive_private.h
intern/gpu_private.h
@@ -231,7 +232,94 @@ data_to_c_simple(shaders/gpu_shader_keyframe_diamond_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_keyframe_diamond_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_geometry.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_material.glsl SRC)
+
+data_to_c_simple(shaders/material/gpu_shader_material_add_shader.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_ambient_occlusion.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_anisotropic.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_attribute.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_background.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_bevel.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_blackbody.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_bright_contrast.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_bump.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_camera.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_clamp.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_color_ramp.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_color_util.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_combine_hsv.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_combine_rgb.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_combine_xyz.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_diffuse.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_displacement.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_eevee_specular.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_emission.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_fractal_noise.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_fresnel.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_gamma.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_geometry.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_glass.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_glossy.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_hair_info.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_hash.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_holdout.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_hue_sat_val.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_invert.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_layer_weight.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_light_falloff.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_light_path.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_mapping.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_map_range.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_math.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_math_util.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_mix_rgb.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_mix_shader.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_noise.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_normal.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_normal_map.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_object_info.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_output_material.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_output_world.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_particle_info.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_principled.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_refraction.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_rgb_curves.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_rgb_to_bw.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_separate_hsv.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_separate_rgb.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_separate_xyz.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_set.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_shader_to_rgba.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_squeeze.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_subsurface_scattering.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tangent.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_brick.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_checker.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_environment.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_gradient.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_image.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_magic.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_musgrave.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_noise.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_sky.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_texture_coordinates.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_voronoi.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_wave.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_white_noise.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_toon.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_translucent.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_transparent.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_uv_map.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_vector_curves.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_vector_displacement.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_vector_math.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_velvet.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_vertex_color.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_volume_absorption.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_volume_info.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_volume_principled.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_volume_scatter.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_wireframe.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_world_normals.glsl SRC)
data_to_c_simple(shaders/gpu_shader_gpencil_stroke_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_gpencil_stroke_frag.glsl SRC)
@@ -242,6 +330,8 @@ data_to_c_simple(shaders/gpu_shader_gpencil_fill_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_cfg_world_clip_lib.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_common_obinfos_lib.glsl SRC)
+
if(WITH_MOD_SMOKE)
add_definitions(-DWITH_SMOKE)
diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h
index 175033f70d9..7d8c3347eb4 100644
--- a/source/blender/gpu/GPU_batch.h
+++ b/source/blender/gpu/GPU_batch.h
@@ -193,6 +193,17 @@ GPUBatch *create_BatchInGeneral(GPUPrimType, VertexBufferStuff, ElementListStuff
#endif /* future plans */
+/* GPUDrawList is an API to do lots of similar drawcalls very fast using multidrawindirect.
+ * There is a fallback if the feature is not supported. */
+typedef struct GPUDrawList GPUDrawList;
+
+GPUDrawList *GPU_draw_list_create(int length);
+void GPU_draw_list_discard(GPUDrawList *list);
+void GPU_draw_list_init(GPUDrawList *list, GPUBatch *batch);
+void GPU_draw_list_command_add(
+ GPUDrawList *list, int v_first, int v_count, int i_first, int i_count);
+void GPU_draw_list_submit(GPUDrawList *list);
+
void gpu_batch_init(void);
void gpu_batch_exit(void);
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index 9009c134837..552bad2b0d6 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -41,7 +41,8 @@ struct PBVH;
/* Buffers for drawing from PBVH grids. */
typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers;
-/* build */
+/* Build must be called once before using the other functions, used every time
+ * mesh topology changes. Threaded. */
GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
const struct MPoly *mpoly,
const struct MLoop *mloop,
@@ -54,8 +55,13 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, unsigned int **grid_h
GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading);
-/* update */
+/* Free part of data for update. Not thread safe, must run in OpenGL main thread. */
+void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers);
+void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers,
+ const struct DMFlagMat *grid_flag_mats,
+ int *grid_indices);
+/* Update mesh buffers without topology changes. Threaded. */
enum {
GPU_PBVH_BUFFERS_SHOW_MASK = (1 << 1),
GPU_PBVH_BUFFERS_SHOW_VCOL = (1 << 1),
@@ -85,6 +91,12 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
const struct CCGKey *key,
const int update_flags);
+/* Finish update. Not thread safe, must run in OpenGL main thread. */
+void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers);
+
+/* Free buffers. Not thread safe, must run in OpenGL main thread. */
+void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers);
+
/* draw */
struct GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool wires);
@@ -92,8 +104,4 @@ short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers);
bool GPU_pbvh_buffers_has_mask(GPU_PBVH_Buffers *buffers);
-void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers);
-
-void GPU_pbvh_fix_linking(void);
-
#endif
diff --git a/source/blender/gpu/GPU_shader_interface.h b/source/blender/gpu/GPU_shader_interface.h
index ec97e1b085e..e336aa53d24 100644
--- a/source/blender/gpu/GPU_shader_interface.h
+++ b/source/blender/gpu/GPU_shader_interface.h
@@ -45,13 +45,12 @@ typedef enum {
GPU_UNIFORM_VIEWPROJECTION_INV, /* mat4 ViewProjectionMatrixInverse */
GPU_UNIFORM_NORMAL, /* mat3 NormalMatrix */
- GPU_UNIFORM_ORCO, /* vec3 OrcoTexCoFactors[] */
+ GPU_UNIFORM_ORCO, /* vec4 OrcoTexCoFactors[] */
GPU_UNIFORM_CLIPPLANES, /* vec4 WorldClipPlanes[] */
- GPU_UNIFORM_COLOR, /* vec4 color */
- GPU_UNIFORM_CALLID, /* int callId */
- GPU_UNIFORM_OBJECT_INFO, /* vec3 objectInfo */
- GPU_UNIFORM_OBJECT_COLOR, /* vec4 objectColor */
+ GPU_UNIFORM_COLOR, /* vec4 color */
+ GPU_UNIFORM_BASE_INSTANCE, /* int baseInstance */
+ GPU_UNIFORM_RESOURCE_CHUNK, /* int resourceChunk */
GPU_UNIFORM_CUSTOM, /* custom uniform, not one of the above built-ins */
diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h
index e7600279d6f..4bbcb6a4335 100644
--- a/source/blender/gpu/GPU_viewport.h
+++ b/source/blender/gpu/GPU_viewport.h
@@ -37,14 +37,20 @@ typedef struct GPUViewport GPUViewport;
/* Contains memory pools information */
typedef struct ViewportMemoryPool {
- struct BLI_memblock *calls;
- struct BLI_memblock *states;
+ struct BLI_memblock *commands;
+ struct BLI_memblock *commands_small;
+ struct BLI_memblock *callbuffers;
+ struct BLI_memblock *obmats;
+ struct BLI_memblock *obinfos;
struct BLI_memblock *cullstates;
struct BLI_memblock *shgroups;
struct BLI_memblock *uniforms;
struct BLI_memblock *views;
struct BLI_memblock *passes;
struct BLI_memblock *images;
+ struct GPUUniformBuffer **matrices_ubo;
+ struct GPUUniformBuffer **obinfos_ubo;
+ uint ubo_len;
} ViewportMemoryPool;
/* All FramebufferLists are just the same pointers with different names */
diff --git a/source/blender/gpu/intern/gpu_attr_binding.c b/source/blender/gpu/intern/gpu_attr_binding.c
index 802b15a0c4e..6cb60884620 100644
--- a/source/blender/gpu/intern/gpu_attr_binding.c
+++ b/source/blender/gpu/intern/gpu_attr_binding.c
@@ -67,9 +67,9 @@ void get_attr_locations(const GPUVertFormat *format,
{
AttrBinding_clear(binding);
- for (uint a_idx = 0; a_idx < format->attr_len; ++a_idx) {
+ for (uint a_idx = 0; a_idx < format->attr_len; a_idx++) {
const GPUVertAttr *a = &format->attrs[a_idx];
- for (uint n_idx = 0; n_idx < a->name_len; ++n_idx) {
+ for (uint n_idx = 0; n_idx < a->name_len; n_idx++) {
const char *name = GPU_vertformat_attr_name_get(format, a, n_idx);
const GPUShaderInput *input = GPU_shaderinterface_attr(shaderface, name);
#if TRUST_NO_ONE
diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c
index 583551e3e58..2620ba49799 100644
--- a/source/blender/gpu/intern/gpu_batch.c
+++ b/source/blender/gpu/intern/gpu_batch.c
@@ -39,8 +39,9 @@
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
-static void batch_update_program_bindings(GPUBatch *batch, uint v_first);
+static void batch_update_program_bindings(GPUBatch *batch, uint i_first);
void GPU_batch_vao_cache_clear(GPUBatch *batch)
{
@@ -48,7 +49,7 @@ void GPU_batch_vao_cache_clear(GPUBatch *batch)
return;
}
if (batch->is_dynamic_vao_count) {
- for (int i = 0; i < batch->dynamic_vaos.count; ++i) {
+ for (int i = 0; i < batch->dynamic_vaos.count; i++) {
if (batch->dynamic_vaos.vao_ids[i]) {
GPU_vao_free(batch->dynamic_vaos.vao_ids[i], batch->context);
}
@@ -61,7 +62,7 @@ void GPU_batch_vao_cache_clear(GPUBatch *batch)
MEM_freeN(batch->dynamic_vaos.vao_ids);
}
else {
- for (int i = 0; i < GPU_BATCH_VAO_STATIC_LEN; ++i) {
+ for (int i = 0; i < GPU_BATCH_VAO_STATIC_LEN; i++) {
if (batch->static_vaos.vao_ids[i]) {
GPU_vao_free(batch->static_vaos.vao_ids[i], batch->context);
}
@@ -72,7 +73,7 @@ void GPU_batch_vao_cache_clear(GPUBatch *batch)
}
}
batch->is_dynamic_vao_count = false;
- for (int i = 0; i < GPU_BATCH_VAO_STATIC_LEN; ++i) {
+ for (int i = 0; i < GPU_BATCH_VAO_STATIC_LEN; i++) {
batch->static_vaos.vao_ids[i] = 0;
batch->static_vaos.interfaces[i] = NULL;
}
@@ -98,7 +99,7 @@ void GPU_batch_init_ex(
#endif
batch->verts[0] = verts;
- for (int v = 1; v < GPU_BATCH_VBO_MAX_LEN; ++v) {
+ for (int v = 1; v < GPU_BATCH_VBO_MAX_LEN; v++) {
batch->verts[v] = NULL;
}
batch->inst = NULL;
@@ -116,7 +117,7 @@ void GPU_batch_copy(GPUBatch *batch_dst, GPUBatch *batch_src)
GPU_batch_init_ex(batch_dst, GPU_PRIM_POINTS, batch_src->verts[0], batch_src->elem, 0);
batch_dst->gl_prim_type = batch_src->gl_prim_type;
- for (int v = 1; v < GPU_BATCH_VBO_MAX_LEN; ++v) {
+ for (int v = 1; v < GPU_BATCH_VBO_MAX_LEN; v++) {
batch_dst->verts[v] = batch_src->verts[v];
}
}
@@ -130,7 +131,7 @@ void GPU_batch_clear(GPUBatch *batch)
GPU_vertbuf_discard(batch->inst);
}
if ((batch->owns_flag & ~GPU_BATCH_OWNS_INDEX) != 0) {
- for (int v = 0; v < GPU_BATCH_VBO_MAX_LEN; ++v) {
+ for (int v = 0; v < GPU_BATCH_VBO_MAX_LEN; v++) {
if (batch->verts[v] == NULL) {
break;
}
@@ -207,7 +208,7 @@ int GPU_batch_vertbuf_add_ex(GPUBatch *batch, GPUVertBuf *verts, bool own_vbo)
/* redo the bindings */
GPU_batch_vao_cache_clear(batch);
- for (uint v = 0; v < GPU_BATCH_VBO_MAX_LEN; ++v) {
+ for (uint v = 0; v < GPU_BATCH_VBO_MAX_LEN; v++) {
if (batch->verts[v] == NULL) {
#if TRUST_NO_ONE
/* for now all VertexBuffers must have same vertex_len */
@@ -233,14 +234,14 @@ static GLuint batch_vao_get(GPUBatch *batch)
{
/* Search through cache */
if (batch->is_dynamic_vao_count) {
- for (int i = 0; i < batch->dynamic_vaos.count; ++i) {
+ for (int i = 0; i < batch->dynamic_vaos.count; i++) {
if (batch->dynamic_vaos.interfaces[i] == batch->interface) {
return batch->dynamic_vaos.vao_ids[i];
}
}
}
else {
- for (int i = 0; i < GPU_BATCH_VAO_STATIC_LEN; ++i) {
+ for (int i = 0; i < GPU_BATCH_VAO_STATIC_LEN; i++) {
if (batch->static_vaos.interfaces[i] == batch->interface) {
return batch->static_vaos.vao_ids[i];
}
@@ -265,7 +266,7 @@ static GLuint batch_vao_get(GPUBatch *batch)
GLuint new_vao = 0;
if (!batch->is_dynamic_vao_count) {
int i; /* find first unused slot */
- for (i = 0; i < GPU_BATCH_VAO_STATIC_LEN; ++i) {
+ for (i = 0; i < GPU_BATCH_VAO_STATIC_LEN; i++) {
if (batch->static_vaos.vao_ids[i] == 0) {
break;
}
@@ -279,7 +280,7 @@ static GLuint batch_vao_get(GPUBatch *batch)
/* Not enough place switch to dynamic. */
batch->is_dynamic_vao_count = true;
/* Erase previous entries, they will be added back if drawn again. */
- for (int j = 0; j < GPU_BATCH_VAO_STATIC_LEN; ++j) {
+ for (int j = 0; j < GPU_BATCH_VAO_STATIC_LEN; j++) {
GPU_shaderinterface_remove_batch_ref(
(GPUShaderInterface *)batch->static_vaos.interfaces[j], batch);
GPU_vao_free(batch->static_vaos.vao_ids[j], batch->context);
@@ -295,7 +296,7 @@ static GLuint batch_vao_get(GPUBatch *batch)
if (batch->is_dynamic_vao_count) {
int i; /* find first unused slot */
- for (i = 0; i < batch->dynamic_vaos.count; ++i) {
+ for (i = 0; i < batch->dynamic_vaos.count; i++) {
if (batch->dynamic_vaos.vao_ids[i] == 0) {
break;
}
@@ -351,7 +352,7 @@ void GPU_batch_program_set(GPUBatch *batch, uint32_t program, const GPUShaderInt
void gpu_batch_remove_interface_ref(GPUBatch *batch, const GPUShaderInterface *interface)
{
if (batch->is_dynamic_vao_count) {
- for (int i = 0; i < batch->dynamic_vaos.count; ++i) {
+ for (int i = 0; i < batch->dynamic_vaos.count; i++) {
if (batch->dynamic_vaos.interfaces[i] == interface) {
GPU_vao_free(batch->dynamic_vaos.vao_ids[i], batch->context);
batch->dynamic_vaos.vao_ids[i] = 0;
@@ -362,7 +363,7 @@ void gpu_batch_remove_interface_ref(GPUBatch *batch, const GPUShaderInterface *i
}
else {
int i;
- for (i = 0; i < GPU_BATCH_VAO_STATIC_LEN; ++i) {
+ for (i = 0; i < GPU_BATCH_VAO_STATIC_LEN; i++) {
if (batch->static_vaos.interfaces[i] == interface) {
GPU_vao_free(batch->static_vaos.vao_ids[i], batch->context);
batch->static_vaos.vao_ids[i] = 0;
@@ -386,7 +387,7 @@ static void create_bindings(GPUVertBuf *verts,
GPU_vertbuf_use(verts);
- for (uint a_idx = 0; a_idx < attr_len; ++a_idx) {
+ for (uint a_idx = 0; a_idx < attr_len; a_idx++) {
const GPUVertAttr *a = &format->attrs[a_idx];
if (format->deinterleaved) {
@@ -399,7 +400,7 @@ static void create_bindings(GPUVertBuf *verts,
const GLvoid *pointer = (const GLubyte *)0 + offset + v_first * stride;
- for (uint n_idx = 0; n_idx < a->name_len; ++n_idx) {
+ for (uint n_idx = 0; n_idx < a->name_len; n_idx++) {
const char *name = GPU_vertformat_attr_name_get(format, a, n_idx);
const GPUShaderInput *input = GPU_shaderinterface_attr(interface, name);
@@ -412,7 +413,7 @@ static void create_bindings(GPUVertBuf *verts,
assert(a->fetch_mode == GPU_FETCH_FLOAT);
assert(a->gl_comp_type == GL_FLOAT);
#endif
- for (int i = 0; i < a->comp_len / 4; ++i) {
+ for (int i = 0; i < a->comp_len / 4; i++) {
glEnableVertexAttribArray(input->location + i);
glVertexAttribDivisor(input->location + i, (use_instancing) ? 1 : 0);
glVertexAttribPointer(input->location + i,
@@ -446,16 +447,16 @@ static void create_bindings(GPUVertBuf *verts,
}
}
-static void batch_update_program_bindings(GPUBatch *batch, uint v_first)
+static void batch_update_program_bindings(GPUBatch *batch, uint i_first)
{
/* Reverse order so first vbos have more prevalence (in term of attrib override). */
- for (int v = GPU_BATCH_VBO_MAX_LEN - 1; v > -1; --v) {
+ for (int v = GPU_BATCH_VBO_MAX_LEN - 1; v > -1; v--) {
if (batch->verts[v] != NULL) {
- create_bindings(batch->verts[v], batch->interface, (batch->inst) ? 0 : v_first, false);
+ create_bindings(batch->verts[v], batch->interface, 0, false);
}
}
if (batch->inst) {
- create_bindings(batch->inst, batch->interface, v_first, true);
+ create_bindings(batch->inst, batch->interface, i_first, true);
}
if (batch->elem) {
GPU_indexbuf_use(batch->elem);
@@ -618,12 +619,18 @@ void GPU_batch_draw(GPUBatch *batch)
GPU_batch_program_use_end(batch);
}
+#if GPU_TRACK_INDEX_RANGE
+# define BASE_INDEX(el) ((el)->base_index)
+# define INDEX_TYPE(el) ((el)->gl_index_type)
+#else
+# define BASE_INDEX(el) 0
+# define INDEX_TYPE(el) GL_UNSIGNED_INT
+#endif
+
void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_first, int i_count)
{
-#if TRUST_NO_ONE
BLI_assert(batch->program_in_use);
/* TODO could assert that VAO is bound. */
-#endif
if (v_count == 0) {
v_count = (batch->elem) ? batch->elem->index_len : batch->verts[0]->vertex_len;
@@ -632,8 +639,21 @@ void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_fi
i_count = (batch->inst) ? batch->inst->vertex_len : 1;
}
+ if (v_count == 0 || i_count == 0) {
+ /* Nothing to draw. */
+ return;
+ }
+
+ /* Verify there is enough data do draw. */
+ /* TODO(fclem) Nice to have but this is invalid when using procedural drawcalls.
+ * The right assert would be to check if there is an enabled attrib from each VBO
+ * and check their length. */
+ // BLI_assert(i_first + i_count <= (batch->inst ? batch->inst->vertex_len : INT_MAX));
+ // BLI_assert(v_first + v_count <=
+ // (batch->elem ? batch->elem->index_len : batch->verts[0]->vertex_len));
+
if (!GPU_arb_base_instance_is_supported()) {
- if (i_first > 0 && i_count > 0) {
+ if (i_first > 0) {
/* If using offset drawing with instancing, we must
* use the default VAO and redo bindings. */
glBindVertexArray(GPU_vao_default());
@@ -648,13 +668,8 @@ void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_fi
if (batch->elem) {
const GPUIndexBuf *el = batch->elem;
-#if GPU_TRACK_INDEX_RANGE
- GLenum index_type = el->gl_index_type;
- GLint base_index = el->base_index;
-#else
- GLenum index_type = GL_UNSIGNED_INT;
- GLint base_index = 0;
-#endif
+ GLenum index_type = INDEX_TYPE(el);
+ GLint base_index = BASE_INDEX(el);
void *v_first_ofs = elem_offset(el, v_first);
if (GPU_arb_base_instance_is_supported()) {
@@ -697,6 +712,184 @@ void GPU_draw_primitive(GPUPrimType prim_type, int v_count)
}
/* -------------------------------------------------------------------- */
+/** \name Indirect Draw Calls
+ * \{ */
+
+#if 0
+# define USE_MULTI_DRAW_INDIRECT 0
+#else
+# define USE_MULTI_DRAW_INDIRECT \
+ (GL_ARB_multi_draw_indirect && GPU_arb_base_instance_is_supported())
+#endif
+
+typedef struct GPUDrawCommand {
+ uint v_count;
+ uint i_count;
+ uint v_first;
+ uint i_first;
+} GPUDrawCommand;
+
+typedef struct GPUDrawCommandIndexed {
+ uint v_count;
+ uint i_count;
+ uint v_first;
+ uint base_index;
+ uint i_first;
+} GPUDrawCommandIndexed;
+
+struct GPUDrawList {
+ GPUBatch *batch;
+ uint base_index; /* Avoid dereferencing batch. */
+ uint cmd_offset; /* in bytes, offset inside indirect command buffer. */
+ uint cmd_len; /* Number of used command for the next call. */
+ uint buffer_size; /* in bytes, size of indirect command buffer. */
+ GLuint buffer_id; /* Draw Indirect Buffer id */
+ union {
+ GPUDrawCommand *commands;
+ GPUDrawCommandIndexed *commands_indexed;
+ };
+};
+
+GPUDrawList *GPU_draw_list_create(int length)
+{
+ GPUDrawList *list = MEM_callocN(sizeof(GPUDrawList), "GPUDrawList");
+ /* Alloc the biggest possible command list which is indexed. */
+ list->buffer_size = sizeof(GPUDrawCommandIndexed) * length;
+ if (USE_MULTI_DRAW_INDIRECT) {
+ list->buffer_id = GPU_buf_alloc();
+ glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id);
+ glBufferData(GL_DRAW_INDIRECT_BUFFER, list->buffer_size, NULL, GL_DYNAMIC_DRAW);
+ }
+ else {
+ list->commands = MEM_mallocN(list->buffer_size, "GPUDrawList data");
+ }
+ return list;
+}
+
+void GPU_draw_list_discard(GPUDrawList *list)
+{
+ if (list->buffer_id) {
+ GPU_buf_free(list->buffer_id);
+ }
+ else {
+ MEM_SAFE_FREE(list->commands);
+ }
+ MEM_freeN(list);
+}
+
+void GPU_draw_list_init(GPUDrawList *list, GPUBatch *batch)
+{
+ BLI_assert(batch->phase == GPU_BATCH_READY_TO_DRAW);
+ list->batch = batch;
+ list->base_index = batch->elem ? BASE_INDEX(batch->elem) : UINT_MAX;
+ list->cmd_len = 0;
+
+ if (USE_MULTI_DRAW_INDIRECT) {
+ if (list->commands == NULL) {
+ glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id);
+ if (list->cmd_offset >= list->buffer_size) {
+ /* Orphan buffer data and start fresh. */
+ glBufferData(GL_DRAW_INDIRECT_BUFFER, list->buffer_size, NULL, GL_DYNAMIC_DRAW);
+ list->cmd_offset = 0;
+ }
+ GLenum flags = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT;
+ list->commands = glMapBufferRange(
+ GL_DRAW_INDIRECT_BUFFER, list->cmd_offset, list->buffer_size - list->cmd_offset, flags);
+ }
+ }
+ else {
+ list->cmd_offset = 0;
+ }
+}
+
+void GPU_draw_list_command_add(
+ GPUDrawList *list, int v_first, int v_count, int i_first, int i_count)
+{
+ BLI_assert(list->commands);
+
+ if (v_count == 0 || i_count == 0) {
+ return;
+ }
+
+ if (list->base_index != UINT_MAX) {
+ GPUDrawCommandIndexed *cmd = list->commands_indexed + list->cmd_len;
+ cmd->v_first = v_first;
+ cmd->v_count = v_count;
+ cmd->i_count = i_count;
+ cmd->base_index = list->base_index;
+ cmd->i_first = i_first;
+ }
+ else {
+ GPUDrawCommand *cmd = list->commands + list->cmd_len;
+ cmd->v_first = v_first;
+ cmd->v_count = v_count;
+ cmd->i_count = i_count;
+ cmd->i_first = i_first;
+ }
+
+ list->cmd_len++;
+ uint offset = list->cmd_offset + list->cmd_len * sizeof(GPUDrawCommandIndexed);
+
+ if (offset == list->buffer_size) {
+ GPU_draw_list_submit(list);
+ GPU_draw_list_init(list, list->batch);
+ }
+}
+
+void GPU_draw_list_submit(GPUDrawList *list)
+{
+ GPUBatch *batch = list->batch;
+
+ if (list->cmd_len == 0) {
+ return;
+ }
+
+ BLI_assert(list->commands);
+ BLI_assert(batch->program_in_use);
+ /* TODO could assert that VAO is bound. */
+
+ /* TODO We loose a bit of memory here if we only draw arrays. Fix that. */
+ uintptr_t offset = list->cmd_offset;
+ uint cmd_len = list->cmd_len;
+ size_t bytes_used = cmd_len * sizeof(GPUDrawCommandIndexed);
+ list->cmd_offset += bytes_used;
+ list->cmd_len = 0; /* Avoid reuse. */
+
+ if (USE_MULTI_DRAW_INDIRECT) {
+ GLenum prim = batch->gl_prim_type;
+
+ glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id);
+ glFlushMappedBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, bytes_used);
+ glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER);
+ list->commands = NULL; /* Unmapped */
+
+ if (batch->elem) {
+ glMultiDrawElementsIndirect(prim, INDEX_TYPE(batch->elem), (void *)offset, cmd_len, 0);
+ }
+ else {
+ glMultiDrawArraysIndirect(prim, (void *)offset, cmd_len, 0);
+ }
+ }
+ else {
+ /* Fallback */
+ if (batch->elem) {
+ GPUDrawCommandIndexed *cmd = list->commands_indexed;
+ for (int i = 0; i < cmd_len; i++, cmd++) {
+ GPU_batch_draw_advanced(batch, cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count);
+ }
+ }
+ else {
+ GPUDrawCommand *cmd = list->commands;
+ for (int i = 0; i < cmd_len; i++, cmd++) {
+ GPU_batch_draw_advanced(batch, cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count);
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Utilities
* \{ */
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 6eb8c80c58e..ed606ccb8c6 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -43,10 +43,10 @@
#include "BKE_pbvh.h"
#include "GPU_buffers.h"
-#include "GPU_draw.h"
-#include "GPU_immediate.h"
#include "GPU_batch.h"
+#include "gpu_private.h"
+
#include "bmesh.h"
/* XXX: the rest of the code in this file is used for optimized PBVH
@@ -80,6 +80,7 @@ struct GPU_PBVH_Buffers {
int totgrid;
bool use_bmesh;
+ bool clear_bmesh_on_flush;
uint tot_tri, tot_quad;
@@ -93,8 +94,9 @@ struct GPU_PBVH_Buffers {
};
static struct {
+ GPUVertFormat format;
uint pos, nor, msk, col;
-} g_vbo_id = {0};
+} g_vbo_id = {{0}};
/** \} */
@@ -102,6 +104,27 @@ static struct {
/** \name PBVH Utils
* \{ */
+void gpu_pbvh_init()
+{
+ /* Initialize vertex buffer (match 'VertexBufferFormat'). */
+ if (g_vbo_id.format.attr_len == 0) {
+ g_vbo_id.pos = GPU_vertformat_attr_add(
+ &g_vbo_id.format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ g_vbo_id.nor = GPU_vertformat_attr_add(
+ &g_vbo_id.format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */
+ g_vbo_id.msk = GPU_vertformat_attr_add(
+ &g_vbo_id.format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ g_vbo_id.col = GPU_vertformat_attr_add(
+ &g_vbo_id.format, "ac", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+}
+
+void gpu_pbvh_exit()
+{
+ /* Nothing to do. */
+}
+
/* Allocates a non-initialized buffer to be sent to GPU.
* Return is false it indicates that the memory map failed. */
static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len)
@@ -112,14 +135,7 @@ static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len)
#if 0
if (buffers->vert_buf == NULL) {
/* Initialize vertex buffer (match 'VertexBufferFormat'). */
- static GPUVertFormat format = {0};
- if (format.attr_len == 0) {
- g_vbo_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- g_vbo_id.nor = GPU_vertformat_attr_add(
- &format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- g_vbo_id.msk = GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- }
- buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_DYNAMIC);
+ buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_DYNAMIC);
GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len);
}
else if (vert_len != buffers->vert_buf->vertex_len) {
@@ -128,30 +144,16 @@ static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len)
#else
if (buffers->vert_buf == NULL) {
/* Initialize vertex buffer (match 'VertexBufferFormat'). */
- static GPUVertFormat format = {0};
- if (format.attr_len == 0) {
- g_vbo_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- g_vbo_id.nor = GPU_vertformat_attr_add(
- &format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */
- g_vbo_id.msk = GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- g_vbo_id.col = GPU_vertformat_attr_add(
- &format, "ac", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- }
- buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_STATIC);
+ buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_STATIC);
}
GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len);
#endif
+
return buffers->vert_buf->data != NULL;
}
static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers, GPUPrimType prim)
{
- /* force flushing to the GPU */
- if (buffers->vert_buf->data) {
- GPU_vertbuf_use(buffers->vert_buf);
- }
-
if (buffers->triangles == NULL) {
buffers->triangles = GPU_batch_create(prim,
buffers->vert_buf,
@@ -182,6 +184,7 @@ static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers, GPUPrimType prim)
/** \name Mesh PBVH
* \{ */
+/* Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const MVert *mvert,
const int *vert_indices,
@@ -191,8 +194,8 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const int (*face_vert_indices)[3],
const int update_flags)
{
- const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
- const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
+ const bool show_mask = vmask && (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
+ const bool show_vcol = vcol && (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
bool empty_mask = true;
{
@@ -200,30 +203,38 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
/* Build VBO */
if (gpu_pbvh_vert_buf_data_set(buffers, totelem)) {
+ GPUVertBufRaw pos_step = {0};
+ GPUVertBufRaw nor_step = {0};
+ GPUVertBufRaw msk_step = {0};
+ GPUVertBufRaw col_step = {0};
+
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.pos, &pos_step);
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.nor, &nor_step);
+ if (show_mask) {
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.msk, &msk_step);
+ }
+ if (show_vcol) {
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.col, &col_step);
+ }
+
/* Vertex data is shared if smooth-shaded, but separate
* copies are made for flat shading because normals
* shouldn't be shared. */
if (buffers->smooth) {
- for (uint i = 0; i < totvert; ++i) {
- const MVert *v = &mvert[vert_indices[i]];
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, i, v->co);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, i, v->no);
- }
-
- if (vmask && show_mask) {
- for (uint i = 0; i < buffers->face_indices_len; i++) {
- const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
- for (uint j = 0; j < 3; j++) {
- int vidx = face_vert_indices[i][j];
- int v_index = buffers->mloop[lt->tri[j]].v;
- float fmask = vmask[v_index];
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vidx, &fmask);
- empty_mask = empty_mask && (fmask == 0.0f);
- }
+ for (uint i = 0; i < totvert; i++) {
+ const int vidx = vert_indices[i];
+ const MVert *v = &mvert[vidx];
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), v->co);
+ copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), v->no);
+
+ if (show_mask) {
+ float mask = vmask[vidx];
+ *(float *)GPU_vertbuf_raw_step(&msk_step) = mask;
+ empty_mask = empty_mask && (mask == 0.0f);
}
}
- if (vcol && show_vcol) {
+ if (show_vcol) {
for (uint i = 0; i < buffers->face_indices_len; i++) {
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
for (int j = 0; j < 3; j++) {
@@ -238,8 +249,7 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
else {
/* calculate normal for each polygon only once */
uint mpoly_prev = UINT_MAX;
- short no[3];
- int vbo_index = 0;
+ short no[3] = {0, 0, 0};
for (uint i = 0; i < buffers->face_indices_len; i++) {
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
@@ -263,27 +273,26 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
}
float fmask = 0.0f;
- if (vmask && show_mask) {
+ if (show_mask) {
fmask = (vmask[vtri[0]] + vmask[vtri[1]] + vmask[vtri[2]]) / 3.0f;
}
for (uint j = 0; j < 3; j++) {
const MVert *v = &mvert[vtri[j]];
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index, v->co);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index, no);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index, &fmask);
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), v->co);
+ copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), no);
+ if (show_mask) {
+ *(float *)GPU_vertbuf_raw_step(&msk_step) = fmask;
+ empty_mask = empty_mask && (fmask == 0.0f);
+ }
- if (vcol && show_vcol) {
+ if (show_vcol) {
const uint loop_index = lt->tri[j];
const uchar *elem = &vcol[loop_index].r;
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index, elem);
+ memcpy(GPU_vertbuf_raw_step(&col_step), elem, sizeof(uchar) * 4);
}
-
- vbo_index++;
}
-
- empty_mask = empty_mask && (fmask == 0.0f);
}
}
@@ -300,6 +309,7 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
buffers->mvert = mvert;
}
+/* Threaded - do not call any functions that use OpenGL calls! */
GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
const MPoly *mpoly,
const MLoop *mloop,
@@ -319,7 +329,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
buffers->show_mask = false;
/* Count the number of visible triangles */
- for (i = 0, tottri = 0; i < face_indices_len; ++i) {
+ for (i = 0, tottri = 0; i < face_indices_len; i++) {
const MLoopTri *lt = &looptri[face_indices[i]];
if (!paint_is_face_hidden(lt, mvert, mloop)) {
tottri++;
@@ -338,11 +348,6 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
return buffers;
}
- GPU_BATCH_DISCARD_SAFE(buffers->triangles);
- GPU_BATCH_DISCARD_SAFE(buffers->lines);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
-
/* An element index buffer is used for smooth shading, but flat
* shading requires separate vertex normals so an index buffer
* can't be used there. */
@@ -352,7 +357,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, INT_MAX);
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, INT_MAX);
- for (i = 0; i < face_indices_len; ++i) {
+ for (i = 0; i < face_indices_len; i++) {
const MLoopTri *lt = &looptri[face_indices[i]];
/* Skip hidden faces */
@@ -376,7 +381,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, INT_MAX);
int vert_idx = 0;
- for (i = 0; i < face_indices_len; ++i) {
+ for (i = 0; i < face_indices_len; i++) {
const MLoopTri *lt = &looptri[face_indices[i]];
/* Skip hidden faces */
@@ -431,8 +436,8 @@ static void gpu_pbvh_grid_fill_index_buffers(
BLI_bitmap *gh = buffers->grid_hidden[grid_indices[i]];
- for (int j = 0; j < gridsize - 1; ++j) {
- for (int k = 0; k < gridsize - 1; ++k) {
+ for (int j = 0; j < gridsize - 1; j++) {
+ for (int k = 0; k < gridsize - 1; k++) {
/* Skip hidden grid face */
if (gh && paint_is_grid_face_hidden(gh, gridsize, k, j)) {
continue;
@@ -454,7 +459,10 @@ static void gpu_pbvh_grid_fill_index_buffers(
}
grid_visible = true;
}
- GPU_indexbuf_add_line_verts(&elb_lines, v1, v2);
+
+ if (grid_visible) {
+ GPU_indexbuf_add_line_verts(&elb_lines, v1, v2);
+ }
}
if (grid_visible) {
@@ -506,7 +514,10 @@ static void gpu_pbvh_grid_fill_index_buffers(
}
grid_visible = true;
}
- GPU_indexbuf_add_line_verts(&elb_lines, v1, v2);
+
+ if (grid_visible) {
+ GPU_indexbuf_add_line_verts(&elb_lines, v1, v2);
+ }
}
if (grid_visible) {
@@ -533,6 +544,27 @@ static void gpu_pbvh_grid_fill_index_buffers(
buffers->index_lines_buf_fast = GPU_indexbuf_build(&elb_lines_fast);
}
+void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers,
+ const struct DMFlagMat *grid_flag_mats,
+ int *grid_indices)
+{
+ const bool smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
+
+ if (buffers->smooth != smooth) {
+ buffers->smooth = smooth;
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles);
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast);
+ GPU_BATCH_DISCARD_SAFE(buffers->lines);
+ GPU_BATCH_DISCARD_SAFE(buffers->lines_fast);
+
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf_fast);
+ }
+}
+
+/* Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
CCGElem **grids,
const DMFlagMat *grid_flag_mats,
@@ -546,26 +578,13 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
bool empty_mask = true;
int i, j, k, x, y;
- const bool smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
-
/* Build VBO */
const int has_mask = key->has_mask;
- uint vert_per_grid = (smooth) ? key->grid_area : (SQUARE(key->grid_size - 1) * 4);
- uint vert_count = totgrid * vert_per_grid;
+ buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
- if (buffers->smooth != smooth) {
- buffers->smooth = smooth;
- GPU_BATCH_DISCARD_SAFE(buffers->triangles);
- GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast);
- GPU_BATCH_DISCARD_SAFE(buffers->lines);
- GPU_BATCH_DISCARD_SAFE(buffers->lines_fast);
-
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf_fast);
- }
+ uint vert_per_grid = (buffers->smooth) ? key->grid_area : (SQUARE(key->grid_size - 1) * 4);
+ uint vert_count = totgrid * vert_per_grid;
if (buffers->index_buf == NULL) {
uint visible_quad_len = BKE_pbvh_count_grid_quads(
@@ -589,7 +608,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, totgrid * key->grid_area * 2, vert_count);
}
- for (i = 0; i < totgrid; ++i) {
+ for (i = 0; i < totgrid; i++) {
CCGElem *grid = grids[grid_indices[i]];
int vbo_index = vbo_index_offset;
@@ -688,6 +707,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
buffers->show_mask = !empty_mask;
}
+/* Threaded - do not call any functions that use OpenGL calls! */
GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hidden)
{
GPU_PBVH_Buffers *buffers;
@@ -792,8 +812,24 @@ static int gpu_bmesh_face_visible_count(GSet *bm_faces)
return totface;
}
+void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers)
+{
+ if (buffers->smooth) {
+ /* Smooth needs to recreate index buffer, so we have to invalidate the batch. */
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles);
+ GPU_BATCH_DISCARD_SAFE(buffers->lines);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
+ }
+ else {
+ GPU_BATCH_DISCARD_SAFE(buffers->lines);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
+ }
+}
+
/* Creates a vertex buffer (coordinate, normal, color) and, if smooth
- * shading, an element index buffer. */
+ * shading, an element index buffer.
+ * Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
BMesh *bm,
GSet *bm_faces,
@@ -805,23 +841,16 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
int tottri, totvert, maxvert = 0;
bool empty_mask = true;
- BMFace *f;
+ BMFace *f = NULL;
/* Count visible triangles */
tottri = gpu_bmesh_face_visible_count(bm_faces);
if (buffers->smooth) {
- /* Smooth needs to recreate index buffer, so we have to invalidate the batch. */
- GPU_BATCH_DISCARD_SAFE(buffers->triangles);
- GPU_BATCH_DISCARD_SAFE(buffers->lines);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
/* Count visible vertices */
totvert = gpu_bmesh_vert_visible_count(bm_unique_verts, bm_other_verts);
}
else {
- GPU_BATCH_DISCARD_SAFE(buffers->lines);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
totvert = tottri * 3;
}
@@ -830,9 +859,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
/* Node is just hidden. */
}
else {
- GPU_BATCH_DISCARD_SAFE(buffers->triangles);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
- GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf);
+ buffers->clear_bmesh_on_flush = true;
}
buffers->tot_tri = 0;
return;
@@ -950,7 +977,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
BM_face_as_array_vert_tri(f, v);
- uint idx[3] = {
+ const uint idx[3] = {
BM_elem_index_get(v[0]), BM_elem_index_get(v[1]), BM_elem_index_get(v[2])};
GPU_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]);
@@ -974,7 +1001,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
}
/* Get material index from the last face we iterated on. */
- buffers->material_index = f->mat_nr;
+ buffers->material_index = (f) ? f->mat_nr : 0;
buffers->show_mask = !empty_mask;
@@ -987,6 +1014,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
/** \name Generic
* \{ */
+/* Threaded - do not call any functions that use OpenGL calls! */
GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading)
{
GPU_PBVH_Buffers *buffers;
@@ -1019,6 +1047,21 @@ short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers)
return buffers->material_index;
}
+void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers)
+{
+ /* Free empty bmesh node buffers. */
+ if (buffers->clear_bmesh_on_flush) {
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
+ GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf);
+ }
+
+ /* Force flushing to the GPU. */
+ if (buffers->vert_buf && buffers->vert_buf->data) {
+ GPU_vertbuf_use(buffers->vert_buf);
+ }
+}
+
void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers)
{
if (buffers) {
@@ -1037,7 +1080,3 @@ void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers)
}
/** \} */
-
-void GPU_pbvh_fix_linking()
-{
-}
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 55337596cbe..410e23c9576 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -44,13 +44,13 @@
#include "GPU_glew.h"
#include "GPU_material.h"
#include "GPU_shader.h"
-#include "GPU_texture.h"
#include "GPU_uniformbuffer.h"
#include "GPU_vertex_format.h"
#include "BLI_sys_types.h" /* for intptr_t support */
#include "gpu_codegen.h"
+#include "gpu_material_library.h"
#include <string.h>
#include <stdarg.h>
@@ -58,7 +58,8 @@
extern char datatoc_gpu_shader_material_glsl[];
extern char datatoc_gpu_shader_geometry_glsl[];
-static char *glsl_material_library = NULL;
+extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
+extern char datatoc_common_view_lib_glsl[];
/* -------------------- GPUPass Cache ------------------ */
/**
@@ -147,6 +148,7 @@ typedef struct GPUFunction {
eGPUType paramtype[MAX_PARAMETER];
GPUFunctionQual paramqual[MAX_PARAMETER];
int totparam;
+ GPUMaterialLibrary *library;
} GPUFunction;
/* Indices match the eGPUType enum */
@@ -230,15 +232,17 @@ static char *gpu_str_skip_token(char *str, char *token, int max)
return str;
}
-static void gpu_parse_functions_string(GHash *hash, char *code)
+static void gpu_parse_material_library(GHash *hash, GPUMaterialLibrary *library)
{
GPUFunction *function;
eGPUType type;
GPUFunctionQual qual;
int i;
+ char *code = library->code;
while ((code = strstr(code, "void "))) {
function = MEM_callocN(sizeof(GPUFunction), "GPUFunction");
+ function->library = library;
code = gpu_str_skip_token(code, NULL, 0);
code = gpu_str_skip_token(code, function->name, MAX_FUNCTION_NAME);
@@ -367,11 +371,6 @@ static char *gpu_generate_function_prototyps(GHash *hash)
static GPUFunction *gpu_lookup_function(const char *name)
{
- if (!FUNCTION_HASH) {
- FUNCTION_HASH = BLI_ghash_str_new("GPU_lookup_function gh");
- gpu_parse_functions_string(FUNCTION_HASH, glsl_material_library);
- }
-
return BLI_ghash_lookup(FUNCTION_HASH, (const void *)name);
}
@@ -395,11 +394,6 @@ void gpu_codegen_exit(void)
GPU_shader_free_builtin_shaders();
- if (glsl_material_library) {
- MEM_freeN(glsl_material_library);
- glsl_material_library = NULL;
- }
-
#if 0
if (FUNCTION_PROTOTYPES) {
MEM_freeN(FUNCTION_PROTOTYPES);
@@ -425,7 +419,7 @@ static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *t
}
else if (to == GPU_FLOAT) {
if (from == GPU_VEC4) {
- BLI_dynstr_appendf(ds, "convert_rgba_to_float(%s)", name);
+ BLI_dynstr_appendf(ds, "dot(%s.rgb, vec3(0.2126, 0.7152, 0.0722))", name);
}
else if (from == GPU_VEC3) {
BLI_dynstr_appendf(ds, "(%s.r + %s.g + %s.b) / 3.0", name, name, name);
@@ -790,6 +784,12 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final
else if (input->builtin == GPU_OBJECT_MATRIX) {
BLI_dynstr_append(ds, "objmat");
}
+ else if (input->builtin == GPU_OBJECT_INFO) {
+ BLI_dynstr_append(ds, "ObjectInfo");
+ }
+ else if (input->builtin == GPU_OBJECT_COLOR) {
+ BLI_dynstr_append(ds, "ObjectColor");
+ }
else if (input->builtin == GPU_INVERSE_OBJECT_MATRIX) {
BLI_dynstr_append(ds, "objinv");
}
@@ -852,6 +852,10 @@ static char *code_generate_fragment(GPUMaterial *material,
codegen_set_unique_ids(nodes);
*rbuiltins = builtins = codegen_process_uniforms_functions(material, ds, nodes);
+ if (builtins & (GPU_OBJECT_INFO | GPU_OBJECT_COLOR)) {
+ BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl);
+ }
+
if (builtins & GPU_BARYCENTRIC_TEXCO) {
BLI_dynstr_append(ds, "in vec2 barycentricTexCo;\n");
}
@@ -1000,7 +1004,7 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
/* NOTE : Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */
if (input->attr_type == CD_ORCO) {
/* OPTI : orco is computed from local positions, but only if no modifier is present. */
- BLI_dynstr_append(ds, "uniform vec3 OrcoTexCoFactors[2];\n");
+ BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl);
BLI_dynstr_append(ds, "DEFINE_ATTR(vec4, orco);\n");
}
else if (input->attr_name[0] == '\0') {
@@ -1082,6 +1086,8 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
BLI_dynstr_append(ds, "\n");
+ BLI_dynstr_append(ds, use_geom ? "RESOURCE_ID_VARYING_GEOM\n" : "RESOURCE_ID_VARYING\n");
+
BLI_dynstr_append(ds,
"#define USE_ATTR\n"
"vec3 srgb_to_linear_attr(vec3 c) {\n"
@@ -1091,6 +1097,15 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
"\treturn mix(c1, c2, step(vec3(0.04045), c));\n"
"}\n\n");
+ BLI_dynstr_append(ds,
+ "vec4 srgba_to_linear_attr(vec4 c) {\n"
+ "\tc = max(c, vec4(0.0));\n"
+ "\tvec4 c1 = c * (1.0 / 12.92);\n"
+ "\tvec4 c2 = pow((c + 0.055) * (1.0 / 1.055), vec4(2.4));\n"
+ "\tvec4 final = mix(c1, c2, step(vec4(0.04045), c));"
+ "\treturn vec4(final.xyz, c.a);\n"
+ "}\n\n");
+
/* Prototype because defined later. */
BLI_dynstr_append(ds,
"vec2 hair_get_customdata_vec2(const samplerBuffer);\n"
@@ -1102,6 +1117,8 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
BLI_dynstr_append(ds, "void pass_attr(in vec3 position) {\n");
+ BLI_dynstr_append(ds, use_geom ? "\tPASS_RESOURCE_ID_GEOM\n" : "\tPASS_RESOURCE_ID\n");
+
BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n");
if (builtins & GPU_BARYCENTRIC_TEXCO) {
@@ -1128,8 +1145,8 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
}
else if (input->attr_type == CD_ORCO) {
BLI_dynstr_appendf(ds,
- "\tvar%d%s = OrcoTexCoFactors[0] + (ModelMatrixInverse * "
- "vec4(hair_get_strand_pos(), 1.0)).xyz * OrcoTexCoFactors[1];\n",
+ "\tvar%d%s = OrcoTexCoFactors[0].xyz + (ModelMatrixInverse * "
+ "vec4(hair_get_strand_pos(), 1.0)).xyz * OrcoTexCoFactors[1].xyz;\n",
input->attr_id,
use_geom ? "g" : "");
/* TODO: fix ORCO with modifiers. */
@@ -1184,7 +1201,8 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
}
else if (input->attr_type == CD_ORCO) {
BLI_dynstr_appendf(ds,
- "\tvar%d%s = OrcoTexCoFactors[0] + position * OrcoTexCoFactors[1];\n",
+ "\tvar%d%s = OrcoTexCoFactors[0].xyz + position *"
+ " OrcoTexCoFactors[1].xyz;\n",
input->attr_id,
use_geom ? "g" : "");
/* See mesh_create_loop_orco() for explanation. */
@@ -1195,7 +1213,7 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
}
else if (input->attr_type == CD_MCOL) {
BLI_dynstr_appendf(ds,
- "\tvar%d%s = srgb_to_linear_attr(att%d);\n",
+ "\tvar%d%s = srgba_to_linear_attr(att%d);\n",
input->attr_id,
use_geom ? "g" : "",
input->attr_id);
@@ -1299,6 +1317,8 @@ static char *code_generate_geometry(ListBase *nodes, const char *geom_code, cons
BLI_dynstr_append(ds, "out vec3 worldNormal;\n");
BLI_dynstr_append(ds, "out vec3 viewNormal;\n");
+ BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
+
BLI_dynstr_append(ds, "void main(){\n");
if (builtins & GPU_BARYCENTRIC_DIST) {
@@ -1318,7 +1338,7 @@ static char *code_generate_geometry(ListBase *nodes, const char *geom_code, cons
BLI_dynstr_append(ds, "\tgl_Position = gl_in[2].gl_Position;\n");
BLI_dynstr_append(ds, "\tpass_attr(2);\n");
BLI_dynstr_append(ds, "\tEmitVertex();\n");
- BLI_dynstr_append(ds, "};\n");
+ BLI_dynstr_append(ds, "}\n");
}
}
else {
@@ -1343,9 +1363,13 @@ static char *code_generate_geometry(ListBase *nodes, const char *geom_code, cons
BLI_dynstr_append(ds, "}\n");
}
+ BLI_dynstr_append(ds, "RESOURCE_ID_VARYING\n");
+
/* Generate varying assignments. */
BLI_dynstr_append(ds, "void pass_attr(in int vert) {\n");
+ BLI_dynstr_append(ds, "\tPASS_RESOURCE_ID(vert)\n");
+
/* XXX HACK: Eevee specific. */
if (geom_code == NULL) {
BLI_dynstr_append(ds, "\tworldPosition = worldPositiong[vert];\n");
@@ -1381,20 +1405,15 @@ static char *code_generate_geometry(ListBase *nodes, const char *geom_code, cons
void GPU_code_generate_glsl_lib(void)
{
- DynStr *ds;
-
- /* only initialize the library once */
- if (glsl_material_library) {
+ /* Only parse GLSL shader files once. */
+ if (FUNCTION_HASH) {
return;
}
- ds = BLI_dynstr_new();
-
- BLI_dynstr_append(ds, datatoc_gpu_shader_material_glsl);
-
- glsl_material_library = BLI_dynstr_get_cstring(ds);
-
- BLI_dynstr_free(ds);
+ FUNCTION_HASH = BLI_ghash_str_new("GPU_lookup_function gh");
+ for (int i = 0; gpu_material_libraries[i]; i++) {
+ gpu_parse_material_library(FUNCTION_HASH, gpu_material_libraries[i]);
+ }
}
/* GPU pass binding/unbinding */
@@ -1796,6 +1815,22 @@ GPUNodeLink *GPU_builtin(eGPUBuiltin builtin)
return link;
}
+static void gpu_material_use_library_with_dependencies(GSet *used_libraries,
+ GPUMaterialLibrary *library)
+{
+ if (BLI_gset_add(used_libraries, library->code)) {
+ for (int i = 0; library->dependencies[i]; i++) {
+ gpu_material_use_library_with_dependencies(used_libraries, library->dependencies[i]);
+ }
+ }
+}
+
+static void gpu_material_use_library(GPUMaterial *material, GPUMaterialLibrary *library)
+{
+ GSet *used_libraries = gpu_material_used_libraries(material);
+ gpu_material_use_library_with_dependencies(used_libraries, library);
+}
+
bool GPU_link(GPUMaterial *mat, const char *name, ...)
{
GPUNode *node;
@@ -1810,6 +1845,8 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...)
return false;
}
+ gpu_material_use_library(mat, function->library);
+
node = GPU_node_begin(name);
va_start(params, name);
@@ -1849,6 +1886,8 @@ bool GPU_stack_link(GPUMaterial *material,
return false;
}
+ gpu_material_use_library(material, function->library);
+
node = GPU_node_begin(name);
totin = 0;
totout = 0;
@@ -1962,6 +2001,34 @@ static bool gpu_pass_is_valid(GPUPass *pass)
return (pass->compiled == false || pass->shader != NULL);
}
+static char *code_generate_material_library(GPUMaterial *material, const char *frag_lib)
+{
+ DynStr *ds = BLI_dynstr_new();
+
+ if (frag_lib) {
+ BLI_dynstr_append(ds, frag_lib);
+ }
+
+ GSet *used_libraries = gpu_material_used_libraries(material);
+
+ /* Always include those because they may be needed by the execution function. */
+ gpu_material_use_library_with_dependencies(used_libraries,
+ &gpu_shader_material_world_normals_library);
+
+ /* Add library code in order, for dependencies. */
+ for (int i = 0; gpu_material_libraries[i]; i++) {
+ GPUMaterialLibrary *library = gpu_material_libraries[i];
+ if (BLI_gset_haskey(used_libraries, library->code)) {
+ BLI_dynstr_append(ds, library->code);
+ }
+ }
+
+ char *result = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+
+ return result;
+}
+
GPUPass *GPU_generate_pass(GPUMaterial *material,
GPUNodeLink *frag_outlink,
struct GPUVertAttrLayers *attrs,
@@ -2000,7 +2067,7 @@ GPUPass *GPU_generate_pass(GPUMaterial *material,
/* Either the shader is not compiled or there is a hash collision...
* continue generating the shader strings. */
- char *tmp = BLI_strdupcat(frag_lib, glsl_material_library);
+ char *tmp = code_generate_material_library(material, frag_lib);
geometrycode = code_generate_geometry(nodes, geom_code, defines);
vertexcode = code_generate_vertex(nodes, vert_code, (geometrycode != NULL));
@@ -2097,7 +2164,7 @@ static int count_active_texture_sampler(GPUShader *shader, char *source)
}
/* Catch duplicates. */
bool is_duplicate = false;
- for (int i = 0; i < sampler_len; ++i) {
+ for (int i = 0; i < sampler_len; i++) {
if (samplers_id[i] == id) {
is_duplicate = true;
}
diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h
index 6eb6bc2f05f..4e09f16ebf8 100644
--- a/source/blender/gpu/intern/gpu_codegen.h
+++ b/source/blender/gpu/intern/gpu_codegen.h
@@ -33,6 +33,7 @@ struct GPUNode;
struct GPUOutput;
struct GPUShader;
struct GPUVertAttrLayers;
+struct GSet;
struct ListBase;
/* Pass Generation
@@ -207,4 +208,6 @@ struct GPUTexture **gpu_material_ramp_texture_row_set(GPUMaterial *mat,
float *pixels,
float *row);
+struct GSet *gpu_material_used_libraries(struct GPUMaterial *material);
+
#endif
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index be3655648f5..c9ae6c60293 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -66,9 +66,6 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_glew.h"
-#include "GPU_material.h"
-#include "GPU_matrix.h"
-#include "GPU_shader.h"
#include "GPU_texture.h"
#include "PIL_time.h"
@@ -348,7 +345,7 @@ static void gpu_texture_update_scaled(
}
/* Scale pixels. */
- ImBuf *ibuf = IMB_allocFromBuffer((uint *)rect, rect_float, w, h);
+ ImBuf *ibuf = IMB_allocFromBuffer((uint *)rect, rect_float, w, h, 4);
IMB_scaleImBuf(ibuf, sub_w, sub_h);
if (ibuf->rect_float) {
@@ -648,13 +645,13 @@ void GPU_create_gl_tex(uint *bind,
recth = smaller_power_of_2_limit(recth);
if (frect) {
- ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy);
+ ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy, 4);
IMB_scaleImBuf(ibuf, rectw, recth);
frect = ibuf->rect_float;
}
else {
- ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy);
+ ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy, 4);
IMB_scaleImBuf(ibuf, rectw, recth);
rect = ibuf->rect;
@@ -794,7 +791,7 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf, bool use_srgb)
}
blocksize = (ibuf->dds_data.fourcc == FOURCC_DXT1) ? 8 : 16;
- for (i = 0; i < ibuf->dds_data.nummipmaps && (width || height); ++i) {
+ for (i = 0; i < ibuf->dds_data.nummipmaps && (width || height); i++) {
if (width == 0) {
width = 1;
}
diff --git a/source/blender/gpu/intern/gpu_element.c b/source/blender/gpu/intern/gpu_element.c
index 3f3f246d6d9..166a6236893 100644
--- a/source/blender/gpu/intern/gpu_element.c
+++ b/source/blender/gpu/intern/gpu_element.c
@@ -269,7 +269,7 @@ static uint index_range(const uint values[], uint value_len, uint *min_out, uint
}
uint min_value = RESTART_INDEX;
uint max_value = 0;
- for (uint i = 0; i < value_len; ++i) {
+ for (uint i = 0; i < value_len; i++) {
const uint value = values[i];
if (value == RESTART_INDEX) {
continue;
@@ -307,13 +307,13 @@ static void squeeze_indices_short(GPUIndexBufBuilder *builder,
if (max_index >= 0xFFFF) {
elem->base_index = min_index;
- for (uint i = 0; i < index_len; ++i) {
+ for (uint i = 0; i < index_len; i++) {
data[i] = (values[i] == RESTART_INDEX) ? 0xFFFF : (GLushort)(values[i] - min_index);
}
}
else {
elem->base_index = 0;
- for (uint i = 0; i < index_len; ++i) {
+ for (uint i = 0; i < index_len; i++) {
data[i] = (GLushort)(values[i]);
}
}
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index 5839b34cd19..c6425854ee4 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -365,10 +365,13 @@ void gpu_extensions_init(void)
GG.mip_render_workaround = true;
GG.depth_blitting_workaround = true;
GG.unused_fb_slot_workaround = true;
- GG.context_local_shaders_workaround = true;
+ GG.context_local_shaders_workaround = GLEW_ARB_get_program_binary;
}
/* df/dy calculation factors, those are dependent on driver */
+ GG.dfdyfactors[0] = 1.0;
+ GG.dfdyfactors[1] = 1.0;
+
if ((strstr(vendor, "ATI") && strstr(version, "3.3.10750"))) {
GG.dfdyfactors[0] = 1.0;
GG.dfdyfactors[1] = -1.0;
@@ -383,18 +386,26 @@ void gpu_extensions_init(void)
GG.dfdyfactors[0] = -1.0;
GG.dfdyfactors[1] = 1.0;
}
- else {
- GG.dfdyfactors[0] = 1.0;
- GG.dfdyfactors[1] = 1.0;
- }
if (strstr(version, "Build 10.18.10.3") || strstr(version, "Build 10.18.10.4") ||
- strstr(version, "Build 10.18.14.4") || strstr(version, "Build 10.18.14.5")) {
+ strstr(version, "Build 10.18.10.5") || strstr(version, "Build 10.18.14.4") ||
+ strstr(version, "Build 10.18.14.5")) {
/* Maybe not all of these drivers have problems with `GLEW_ARB_base_instance`.
* But it's hard to test each case. */
GG.glew_arb_base_instance_is_supported = false;
GG.context_local_shaders_workaround = true;
}
+
+ if (strstr(version, "Build 20.19.15.4285")) {
+ /* Somehow fixes armature display issues (see T69743). */
+ GG.context_local_shaders_workaround = true;
+ }
+ }
+ else if ((GG.device == GPU_DEVICE_ATI) && (GG.os == GPU_OS_UNIX) &&
+ (GG.driver == GPU_DRIVER_OPENSOURCE)) {
+ /* See T70187: merging vertices fail. This has been tested from 18.2.2 till 19.3.0~dev of the
+ * Mesa driver */
+ GG.unused_fb_slot_workaround = true;
}
GPU_invalid_tex_init();
diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c
index 7d096058e4c..a531c22365c 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.c
+++ b/source/blender/gpu/intern/gpu_framebuffer.c
@@ -31,7 +31,6 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_framebuffer.h"
-#include "GPU_matrix.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
@@ -46,8 +45,9 @@ typedef enum {
GPU_FB_COLOR_ATTACHMENT2,
GPU_FB_COLOR_ATTACHMENT3,
GPU_FB_COLOR_ATTACHMENT4,
+ GPU_FB_COLOR_ATTACHMENT5,
/* Number of maximum output slots.
- * We support 5 outputs for now (usually we wouldn't need more to preserve fill rate). */
+ * We support 6 outputs for now (usually we wouldn't need more to preserve fill rate). */
/* Keep in mind that GL max is GL_MAX_DRAW_BUFFERS and is at least 8, corresponding to
* the maximum number of COLOR attachments specified by glDrawBuffers. */
GPU_FB_MAX_ATTACHEMENT,
@@ -82,6 +82,7 @@ static GLenum convert_attachment_type_to_gl(GPUAttachmentType type)
[GPU_FB_COLOR_ATTACHMENT2] = GL_COLOR_ATTACHMENT2,
[GPU_FB_COLOR_ATTACHMENT3] = GL_COLOR_ATTACHMENT3,
[GPU_FB_COLOR_ATTACHMENT4] = GL_COLOR_ATTACHMENT4,
+ [GPU_FB_COLOR_ATTACHMENT5] = GL_COLOR_ATTACHMENT5,
};
return table[type];
}
@@ -131,9 +132,11 @@ static void gpu_print_framebuffer_error(GLenum status, char err_out[256])
const char *err = "unknown";
#define FORMAT_STATUS(X) \
- case GL_FRAMEBUFFER_##X: \
+ case GL_FRAMEBUFFER_##X: { \
err = "GL_FRAMEBUFFER_" #X; \
- break;
+ break; \
+ } \
+ ((void)0)
switch (status) {
/* success */
@@ -330,7 +333,7 @@ void GPU_framebuffer_config_array(GPUFrameBuffer *fb, const GPUAttachment *confi
}
int slot = 0;
- for (int i = 1; i < config_len; ++i, ++slot) {
+ for (int i = 1; i < config_len; i++, slot++) {
if (config[i].tex != NULL) {
BLI_assert(GPU_texture_depth(config[i].tex) == false);
gpu_framebuffer_texture_attach_ex(fb, config[i].tex, slot, config[i].layer, config[i].mip);
@@ -384,7 +387,7 @@ static void gpu_framebuffer_update_attachments(GPUFrameBuffer *fb)
BLI_assert(GPU_framebuffer_active_get() == fb);
/* Update attachments */
- for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) {
+ for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; type++) {
if (type >= GPU_FB_COLOR_ATTACHMENT0) {
if (fb->attachments[type].tex) {
@@ -755,7 +758,7 @@ void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *fb,
current_dim[0] = max_ii(current_dim[0] / 2, 1);
current_dim[1] = max_ii(current_dim[1] / 2, 1);
- for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) {
+ for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; type++) {
if (fb->attachments[type].tex != NULL) {
/* Some Intel HDXXX have issue with rendering to a mipmap that is below
* the texture GL_TEXTURE_MAX_LEVEL. So even if it not correct, in this case
@@ -784,7 +787,7 @@ void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *fb,
}
}
- for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) {
+ for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; type++) {
if (fb->attachments[type].tex != NULL) {
/* reset mipmap level range */
GPUTexture *tex = fb->attachments[type].tex;
diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.c
index 0e3019ad122..bed7ab25bb9 100644
--- a/source/blender/gpu/intern/gpu_immediate.c
+++ b/source/blender/gpu/intern/gpu_immediate.c
@@ -72,8 +72,9 @@ typedef struct {
uint16_t prev_enabled_attr_bits; /* <-- only affects this VAO, so we're ok */
} Immediate;
-/* size of internal buffer -- make this adjustable? */
-#define IMM_BUFFER_SIZE (4 * 1024 * 1024)
+/* size of internal buffer */
+#define DEFAULT_INTERNAL_BUFFER_SIZE (4 * 1024 * 1024)
+static uint imm_buffer_size = DEFAULT_INTERNAL_BUFFER_SIZE;
static bool initialized = false;
static Immediate imm;
@@ -87,7 +88,7 @@ void immInit(void)
imm.vbo_id = GPU_buf_alloc();
glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id);
- glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, imm_buffer_size, NULL, GL_DYNAMIC_DRAW);
imm.prim_type = GPU_PRIM_NONE;
imm.strict_vertex_len = true;
@@ -211,26 +212,35 @@ void immBegin(GPUPrimType prim_type, uint vertex_len)
/* how many bytes do we need for this draw call? */
const uint bytes_needed = vertex_buffer_size(&imm.vertex_format, vertex_len);
-#if TRUST_NO_ONE
- assert(bytes_needed <= IMM_BUFFER_SIZE);
-#endif
-
glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id);
/* does the current buffer have enough room? */
- const uint available_bytes = IMM_BUFFER_SIZE - imm.buffer_offset;
- /* ensure vertex data is aligned */
+ const uint available_bytes = imm_buffer_size - imm.buffer_offset;
+ bool recreate_buffer = false;
+ if (bytes_needed > imm_buffer_size) {
+ /* expand the internal buffer */
+ imm_buffer_size = bytes_needed;
+ recreate_buffer = true;
+ }
+ else if (bytes_needed < DEFAULT_INTERNAL_BUFFER_SIZE &&
+ imm_buffer_size > DEFAULT_INTERNAL_BUFFER_SIZE) {
+ /* shrink the internal buffer */
+ imm_buffer_size = DEFAULT_INTERNAL_BUFFER_SIZE;
+ recreate_buffer = true;
+ }
+
+ /* ensure vertex data is aligned */
/* Might waste a little space, but it's safe. */
const uint pre_padding = padding(imm.buffer_offset, imm.vertex_format.stride);
- if ((bytes_needed + pre_padding) <= available_bytes) {
+ if (!recreate_buffer && ((bytes_needed + pre_padding) <= available_bytes)) {
imm.buffer_offset += pre_padding;
}
else {
/* orphan this buffer & start with a fresh one */
/* this method works on all platforms, old & new */
- glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, imm_buffer_size, NULL, GL_DYNAMIC_DRAW);
imm.buffer_offset = 0;
}
@@ -298,7 +308,7 @@ static void immDrawSetup(void)
/* Enable/Disable vertex attributes as needed. */
if (imm.attr_binding.enabled_bits != imm.prev_enabled_attr_bits) {
- for (uint loc = 0; loc < GPU_VERT_ATTR_MAX_LEN; ++loc) {
+ for (uint loc = 0; loc < GPU_VERT_ATTR_MAX_LEN; loc++) {
bool is_enabled = imm.attr_binding.enabled_bits & (1 << loc);
bool was_enabled = imm.prev_enabled_attr_bits & (1 << loc);
@@ -315,7 +325,7 @@ static void immDrawSetup(void)
const uint stride = imm.vertex_format.stride;
- for (uint a_idx = 0; a_idx < imm.vertex_format.attr_len; ++a_idx) {
+ for (uint a_idx = 0; a_idx < imm.vertex_format.attr_len; a_idx++) {
const GPUVertAttr *a = &imm.vertex_format.attrs[a_idx];
const uint offset = imm.buffer_offset + a->offset;
@@ -640,7 +650,7 @@ static void immEndVertex(void) /* and move on to the next vertex */
#if TRUST_NO_ONE
assert(imm.vertex_idx > 0); /* first vertex must have all attributes specified */
#endif
- for (uint a_idx = 0; a_idx < imm.vertex_format.attr_len; ++a_idx) {
+ for (uint a_idx = 0; a_idx < imm.vertex_format.attr_len; a_idx++) {
if ((imm.unassigned_attr_bits >> a_idx) & 1) {
const GPUVertAttr *a = &imm.vertex_format.attrs[a_idx];
diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c
index ca0c2506750..bb3c4344bd4 100644
--- a/source/blender/gpu/intern/gpu_immediate_util.c
+++ b/source/blender/gpu/intern/gpu_immediate_util.c
@@ -28,7 +28,6 @@
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
-#include "GPU_matrix.h"
static const float cube_coords[8][3] = {
{-1, -1, -1},
@@ -167,7 +166,7 @@ static void imm_draw_circle(GPUPrimType prim_type,
int nsegments)
{
immBegin(prim_type, nsegments);
- for (int i = 0; i < nsegments; ++i) {
+ for (int i = 0; i < nsegments; i++) {
const float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments);
immVertex2f(shdr_pos, x + (rad_x * cosf(angle)), y + (rad_y * sinf(angle)));
}
@@ -229,7 +228,7 @@ static void imm_draw_circle_partial(GPUPrimType prim_type,
const float angle_end = -(DEG2RADF(sweep) - angle_start);
nsegments += 1;
immBegin(prim_type, nsegments);
- for (int i = 0; i < nsegments; ++i) {
+ for (int i = 0; i < nsegments; i++) {
const float angle = interpf(angle_start, angle_end, ((float)i / (float)(nsegments - 1)));
const float angle_sin = sinf(angle);
const float angle_cos = cosf(angle);
@@ -263,7 +262,7 @@ static void imm_draw_disk_partial(GPUPrimType prim_type,
const float angle_end = -(DEG2RADF(sweep) - angle_start);
nsegments += 1;
immBegin(prim_type, nsegments * 2);
- for (int i = 0; i < nsegments; ++i) {
+ for (int i = 0; i < nsegments; i++) {
const float angle = interpf(angle_start, angle_end, ((float)i / (float)(nsegments - 1)));
const float angle_sin = sinf(angle);
const float angle_cos = cosf(angle);
@@ -305,7 +304,7 @@ static void imm_draw_circle_3D(
GPUPrimType prim_type, uint pos, float x, float y, float rad, int nsegments)
{
immBegin(prim_type, nsegments);
- for (int i = 0; i < nsegments; ++i) {
+ for (int i = 0; i < nsegments; i++) {
float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments);
immVertex3f(pos, x + rad * cosf(angle), y + rad * sinf(angle), 0.0f);
}
@@ -422,7 +421,7 @@ void imm_draw_cylinder_fill_normal_3d(
uint pos, uint nor, float base, float top, float height, int slices, int stacks)
{
immBegin(GPU_PRIM_TRIS, 6 * slices * stacks);
- for (int i = 0; i < slices; ++i) {
+ for (int i = 0; i < slices; i++) {
const float angle1 = (float)(2 * M_PI) * ((float)i / (float)slices);
const float angle2 = (float)(2 * M_PI) * ((float)(i + 1) / (float)slices);
const float cos1 = cosf(angle1);
@@ -430,7 +429,7 @@ void imm_draw_cylinder_fill_normal_3d(
const float cos2 = cosf(angle2);
const float sin2 = sinf(angle2);
- for (int j = 0; j < stacks; ++j) {
+ for (int j = 0; j < stacks; j++) {
float fac1 = (float)j / (float)stacks;
float fac2 = (float)(j + 1) / (float)stacks;
float r1 = base * (1.f - fac1) + top * fac1;
@@ -478,7 +477,7 @@ void imm_draw_cylinder_wire_3d(
uint pos, float base, float top, float height, int slices, int stacks)
{
immBegin(GPU_PRIM_LINES, 6 * slices * stacks);
- for (int i = 0; i < slices; ++i) {
+ for (int i = 0; i < slices; i++) {
const float angle1 = (float)(2 * M_PI) * ((float)i / (float)slices);
const float angle2 = (float)(2 * M_PI) * ((float)(i + 1) / (float)slices);
const float cos1 = cosf(angle1);
@@ -486,7 +485,7 @@ void imm_draw_cylinder_wire_3d(
const float cos2 = cosf(angle2);
const float sin2 = sinf(angle2);
- for (int j = 0; j < stacks; ++j) {
+ for (int j = 0; j < stacks; j++) {
float fac1 = (float)j / (float)stacks;
float fac2 = (float)(j + 1) / (float)stacks;
float r1 = base * (1.f - fac1) + top * fac1;
@@ -516,7 +515,7 @@ void imm_draw_cylinder_fill_3d(
uint pos, float base, float top, float height, int slices, int stacks)
{
immBegin(GPU_PRIM_TRIS, 6 * slices * stacks);
- for (int i = 0; i < slices; ++i) {
+ for (int i = 0; i < slices; i++) {
const float angle1 = (float)(2 * M_PI) * ((float)i / (float)slices);
const float angle2 = (float)(2 * M_PI) * ((float)(i + 1) / (float)slices);
const float cos1 = cosf(angle1);
@@ -524,7 +523,7 @@ void imm_draw_cylinder_fill_3d(
const float cos2 = cosf(angle2);
const float sin2 = sinf(angle2);
- for (int j = 0; j < stacks; ++j) {
+ for (int j = 0; j < stacks; j++) {
float fac1 = (float)j / (float)stacks;
float fac2 = (float)(j + 1) / (float)stacks;
float r1 = base * (1.f - fac1) + top * fac1;
diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c
index 322ac3be8e2..0009e7d8c47 100644
--- a/source/blender/gpu/intern/gpu_init_exit.c
+++ b/source/blender/gpu/intern/gpu_init_exit.c
@@ -26,7 +26,6 @@
#include "GPU_init_exit.h" /* interface */
#include "GPU_immediate.h"
#include "GPU_batch.h"
-#include "GPU_texture.h"
#include "BKE_global.h"
#include "intern/gpu_codegen.h"
@@ -63,11 +62,13 @@ void GPU_init(void)
immInit();
}
- GPU_pbvh_fix_linking();
+ gpu_pbvh_init();
}
void GPU_exit(void)
{
+ gpu_pbvh_exit();
+
if (!G.background) {
immDestroy();
}
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 20b91c0c95d..2e3a0a8df27 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -37,6 +37,7 @@
#include "BLI_utildefines.h"
#include "BLI_string.h"
#include "BLI_string_utils.h"
+#include "BLI_ghash.h"
#include "BKE_main.h"
#include "BKE_node.h"
@@ -102,6 +103,8 @@ struct GPUMaterial {
GPUTexture *coba_tex; /* 1D Texture array containing all color bands. */
GPUColorBandBuilder *coba_builder;
+ GSet *used_libraries;
+
#ifndef NDEBUG
char name[64];
#endif
@@ -183,6 +186,8 @@ static void gpu_material_free_single(GPUMaterial *material)
if (material->coba_tex != NULL) {
GPU_texture_free(material->coba_tex);
}
+
+ BLI_gset_free(material->used_libraries, NULL);
}
void GPU_material_free(ListBase *gpumaterial)
@@ -328,7 +333,7 @@ static float eval_integral(float x0, float x1, short falloff_type, float sharpne
const float step = range / INTEGRAL_RESOLUTION;
float integral = 0.0f;
- for (int i = 0; i < INTEGRAL_RESOLUTION; ++i) {
+ for (int i = 0; i < INTEGRAL_RESOLUTION; i++) {
float x = x0 + range * ((float)i + 0.5f) / (float)INTEGRAL_RESOLUTION;
float y = eval_profile(x, falloff_type, sharpness, param);
integral += y * step;
@@ -339,7 +344,7 @@ static float eval_integral(float x0, float x1, short falloff_type, float sharpne
#undef INTEGRAL_RESOLUTION
static void compute_sss_kernel(
- GPUSssKernelData *kd, float radii[3], int sample_len, int falloff_type, float sharpness)
+ GPUSssKernelData *kd, const float radii[3], int sample_len, int falloff_type, float sharpness)
{
float rad[3];
/* Minimum radius */
@@ -409,7 +414,7 @@ static void compute_sss_kernel(
sum[2] += kd->kernel[i][2];
}
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
if (sum[i] > 0.0f) {
/* Normalize */
for (int j = 0; j < sample_len; j++) {
@@ -445,7 +450,7 @@ static void compute_sss_translucence_kernel(const GPUSssKernelData *kd,
*output = (float *)texels;
/* Last texel should be black, hence the - 1. */
- for (int i = 0; i < resolution - 1; ++i) {
+ for (int i = 0; i < resolution - 1; i++) {
/* Distance from surface. */
float d = kd->max_radius * ((float)i + 0.00001f) / ((float)resolution);
@@ -582,6 +587,11 @@ void gpu_material_add_node(GPUMaterial *material, GPUNode *node)
BLI_addtail(&material->nodes, node);
}
+GSet *gpu_material_used_libraries(GPUMaterial *material)
+{
+ return material->used_libraries;
+}
+
/* Return true if the material compilation has not yet begin or begin. */
eGPUMaterialStatus GPU_material_status(GPUMaterial *mat)
{
@@ -659,6 +669,9 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene,
UNUSED_VARS(name);
#endif
+ mat->used_libraries = BLI_gset_new(
+ BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUMaterial.used_libraries");
+
/* localize tree to create links for reroute and mute */
bNodeTree *localtree = ntreeLocalize(ntree);
ntreeGPUMaterialNodes(localtree, mat, &has_surface_output, &has_volume_output);
diff --git a/source/blender/gpu/intern/gpu_material_library.h b/source/blender/gpu/intern/gpu_material_library.h
new file mode 100644
index 00000000000..3a38eb5c600
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_material_library.h
@@ -0,0 +1,655 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * List of all gpu_shader_material_*.glsl files used by GLSL materials. These
+ * will be parsed to make all functions in them available to use for GPU_link().
+ *
+ * If a file uses functions from another file, it must be added to the list of
+ * dependencies, and be placed after that file in the list. */
+
+#ifndef __GPU_MATERIAL_LIBRARY_H__
+#define __GPU_MATERIAL_LIBRARY_H__
+
+typedef struct GPUMaterialLibrary {
+ char *code;
+ struct GPUMaterialLibrary *dependencies[8];
+} GPUMaterialLibrary;
+
+extern char datatoc_gpu_shader_material_add_shader_glsl[];
+extern char datatoc_gpu_shader_material_ambient_occlusion_glsl[];
+extern char datatoc_gpu_shader_material_anisotropic_glsl[];
+extern char datatoc_gpu_shader_material_attribute_glsl[];
+extern char datatoc_gpu_shader_material_background_glsl[];
+extern char datatoc_gpu_shader_material_bevel_glsl[];
+extern char datatoc_gpu_shader_material_blackbody_glsl[];
+extern char datatoc_gpu_shader_material_bright_contrast_glsl[];
+extern char datatoc_gpu_shader_material_bump_glsl[];
+extern char datatoc_gpu_shader_material_camera_glsl[];
+extern char datatoc_gpu_shader_material_clamp_glsl[];
+extern char datatoc_gpu_shader_material_color_ramp_glsl[];
+extern char datatoc_gpu_shader_material_color_util_glsl[];
+extern char datatoc_gpu_shader_material_combine_hsv_glsl[];
+extern char datatoc_gpu_shader_material_combine_rgb_glsl[];
+extern char datatoc_gpu_shader_material_combine_xyz_glsl[];
+extern char datatoc_gpu_shader_material_diffuse_glsl[];
+extern char datatoc_gpu_shader_material_displacement_glsl[];
+extern char datatoc_gpu_shader_material_eevee_specular_glsl[];
+extern char datatoc_gpu_shader_material_emission_glsl[];
+extern char datatoc_gpu_shader_material_fractal_noise_glsl[];
+extern char datatoc_gpu_shader_material_fresnel_glsl[];
+extern char datatoc_gpu_shader_material_gamma_glsl[];
+extern char datatoc_gpu_shader_material_geometry_glsl[];
+extern char datatoc_gpu_shader_material_glass_glsl[];
+extern char datatoc_gpu_shader_material_glossy_glsl[];
+extern char datatoc_gpu_shader_material_hair_info_glsl[];
+extern char datatoc_gpu_shader_material_hash_glsl[];
+extern char datatoc_gpu_shader_material_holdout_glsl[];
+extern char datatoc_gpu_shader_material_hue_sat_val_glsl[];
+extern char datatoc_gpu_shader_material_invert_glsl[];
+extern char datatoc_gpu_shader_material_layer_weight_glsl[];
+extern char datatoc_gpu_shader_material_light_falloff_glsl[];
+extern char datatoc_gpu_shader_material_light_path_glsl[];
+extern char datatoc_gpu_shader_material_mapping_glsl[];
+extern char datatoc_gpu_shader_material_map_range_glsl[];
+extern char datatoc_gpu_shader_material_math_glsl[];
+extern char datatoc_gpu_shader_material_math_util_glsl[];
+extern char datatoc_gpu_shader_material_mix_rgb_glsl[];
+extern char datatoc_gpu_shader_material_mix_shader_glsl[];
+extern char datatoc_gpu_shader_material_noise_glsl[];
+extern char datatoc_gpu_shader_material_normal_glsl[];
+extern char datatoc_gpu_shader_material_normal_map_glsl[];
+extern char datatoc_gpu_shader_material_object_info_glsl[];
+extern char datatoc_gpu_shader_material_output_material_glsl[];
+extern char datatoc_gpu_shader_material_output_world_glsl[];
+extern char datatoc_gpu_shader_material_particle_info_glsl[];
+extern char datatoc_gpu_shader_material_principled_glsl[];
+extern char datatoc_gpu_shader_material_refraction_glsl[];
+extern char datatoc_gpu_shader_material_rgb_curves_glsl[];
+extern char datatoc_gpu_shader_material_rgb_to_bw_glsl[];
+extern char datatoc_gpu_shader_material_separate_hsv_glsl[];
+extern char datatoc_gpu_shader_material_separate_rgb_glsl[];
+extern char datatoc_gpu_shader_material_separate_xyz_glsl[];
+extern char datatoc_gpu_shader_material_set_glsl[];
+extern char datatoc_gpu_shader_material_shader_to_rgba_glsl[];
+extern char datatoc_gpu_shader_material_squeeze_glsl[];
+extern char datatoc_gpu_shader_material_subsurface_scattering_glsl[];
+extern char datatoc_gpu_shader_material_tangent_glsl[];
+extern char datatoc_gpu_shader_material_tex_brick_glsl[];
+extern char datatoc_gpu_shader_material_tex_checker_glsl[];
+extern char datatoc_gpu_shader_material_tex_environment_glsl[];
+extern char datatoc_gpu_shader_material_tex_gradient_glsl[];
+extern char datatoc_gpu_shader_material_tex_image_glsl[];
+extern char datatoc_gpu_shader_material_tex_magic_glsl[];
+extern char datatoc_gpu_shader_material_tex_musgrave_glsl[];
+extern char datatoc_gpu_shader_material_tex_noise_glsl[];
+extern char datatoc_gpu_shader_material_tex_sky_glsl[];
+extern char datatoc_gpu_shader_material_texture_coordinates_glsl[];
+extern char datatoc_gpu_shader_material_tex_voronoi_glsl[];
+extern char datatoc_gpu_shader_material_tex_wave_glsl[];
+extern char datatoc_gpu_shader_material_tex_white_noise_glsl[];
+extern char datatoc_gpu_shader_material_toon_glsl[];
+extern char datatoc_gpu_shader_material_translucent_glsl[];
+extern char datatoc_gpu_shader_material_transparent_glsl[];
+extern char datatoc_gpu_shader_material_uv_map_glsl[];
+extern char datatoc_gpu_shader_material_vector_curves_glsl[];
+extern char datatoc_gpu_shader_material_vector_displacement_glsl[];
+extern char datatoc_gpu_shader_material_vector_math_glsl[];
+extern char datatoc_gpu_shader_material_velvet_glsl[];
+extern char datatoc_gpu_shader_material_vertex_color_glsl[];
+extern char datatoc_gpu_shader_material_volume_absorption_glsl[];
+extern char datatoc_gpu_shader_material_volume_info_glsl[];
+extern char datatoc_gpu_shader_material_volume_principled_glsl[];
+extern char datatoc_gpu_shader_material_volume_scatter_glsl[];
+extern char datatoc_gpu_shader_material_wireframe_glsl[];
+extern char datatoc_gpu_shader_material_world_normals_glsl[];
+
+static GPUMaterialLibrary gpu_shader_material_math_util_library = {
+ .code = datatoc_gpu_shader_material_math_util_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_color_util_library = {
+ .code = datatoc_gpu_shader_material_color_util_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_hash_library = {
+ .code = datatoc_gpu_shader_material_hash_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_noise_library = {
+ .code = datatoc_gpu_shader_material_noise_glsl,
+ .dependencies = {&gpu_shader_material_math_util_library,
+ &gpu_shader_material_hash_library,
+ NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_fractal_noise_library = {
+ .code = datatoc_gpu_shader_material_fractal_noise_glsl,
+ .dependencies = {&gpu_shader_material_noise_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_add_shader_library = {
+ .code = datatoc_gpu_shader_material_add_shader_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_ambient_occlusion_library = {
+ .code = datatoc_gpu_shader_material_ambient_occlusion_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_glossy_library = {
+ .code = datatoc_gpu_shader_material_glossy_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_anisotropic_library = {
+ .code = datatoc_gpu_shader_material_anisotropic_glsl,
+ .dependencies = {&gpu_shader_material_glossy_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_attribute_library = {
+ .code = datatoc_gpu_shader_material_attribute_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_background_library = {
+ .code = datatoc_gpu_shader_material_background_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_bevel_library = {
+ .code = datatoc_gpu_shader_material_bevel_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_blackbody_library = {
+ .code = datatoc_gpu_shader_material_blackbody_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_bright_contrast_library = {
+ .code = datatoc_gpu_shader_material_bright_contrast_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_bump_library = {
+ .code = datatoc_gpu_shader_material_bump_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_camera_library = {
+ .code = datatoc_gpu_shader_material_camera_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_clamp_library = {
+ .code = datatoc_gpu_shader_material_clamp_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_color_ramp_library = {
+ .code = datatoc_gpu_shader_material_color_ramp_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_combine_hsv_library = {
+ .code = datatoc_gpu_shader_material_combine_hsv_glsl,
+ .dependencies = {&gpu_shader_material_color_util_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_combine_rgb_library = {
+ .code = datatoc_gpu_shader_material_combine_rgb_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_combine_xyz_library = {
+ .code = datatoc_gpu_shader_material_combine_xyz_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_diffuse_library = {
+ .code = datatoc_gpu_shader_material_diffuse_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_displacement_library = {
+ .code = datatoc_gpu_shader_material_displacement_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_eevee_specular_library = {
+ .code = datatoc_gpu_shader_material_eevee_specular_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_emission_library = {
+ .code = datatoc_gpu_shader_material_emission_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_fresnel_library = {
+ .code = datatoc_gpu_shader_material_fresnel_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_gamma_library = {
+ .code = datatoc_gpu_shader_material_gamma_glsl,
+ .dependencies = {&gpu_shader_material_math_util_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tangent_library = {
+ .code = datatoc_gpu_shader_material_tangent_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_geometry_library = {
+ .code = datatoc_gpu_shader_material_geometry_glsl,
+ .dependencies = {&gpu_shader_material_tangent_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_glass_library = {
+ .code = datatoc_gpu_shader_material_glass_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_hair_info_library = {
+ .code = datatoc_gpu_shader_material_hair_info_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_holdout_library = {
+ .code = datatoc_gpu_shader_material_holdout_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_hue_sat_val_library = {
+ .code = datatoc_gpu_shader_material_hue_sat_val_glsl,
+ .dependencies = {&gpu_shader_material_color_util_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_invert_library = {
+ .code = datatoc_gpu_shader_material_invert_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_layer_weight_library = {
+ .code = datatoc_gpu_shader_material_layer_weight_glsl,
+ .dependencies = {&gpu_shader_material_fresnel_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_light_falloff_library = {
+ .code = datatoc_gpu_shader_material_light_falloff_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_light_path_library = {
+ .code = datatoc_gpu_shader_material_light_path_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_mapping_library = {
+ .code = datatoc_gpu_shader_material_mapping_glsl,
+ .dependencies = {&gpu_shader_material_math_util_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_map_range_library = {
+ .code = datatoc_gpu_shader_material_map_range_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_math_library = {
+ .code = datatoc_gpu_shader_material_math_glsl,
+ .dependencies = {&gpu_shader_material_math_util_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_mix_rgb_library = {
+ .code = datatoc_gpu_shader_material_mix_rgb_glsl,
+ .dependencies = {&gpu_shader_material_color_util_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_mix_shader_library = {
+ .code = datatoc_gpu_shader_material_mix_shader_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_normal_library = {
+ .code = datatoc_gpu_shader_material_normal_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_normal_map_library = {
+ .code = datatoc_gpu_shader_material_normal_map_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_object_info_library = {
+ .code = datatoc_gpu_shader_material_object_info_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_output_material_library = {
+ .code = datatoc_gpu_shader_material_output_material_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_output_world_library = {
+ .code = datatoc_gpu_shader_material_output_world_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_particle_info_library = {
+ .code = datatoc_gpu_shader_material_particle_info_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_principled_library = {
+ .code = datatoc_gpu_shader_material_principled_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_refraction_library = {
+ .code = datatoc_gpu_shader_material_refraction_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_rgb_curves_library = {
+ .code = datatoc_gpu_shader_material_rgb_curves_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_rgb_to_bw_library = {
+ .code = datatoc_gpu_shader_material_rgb_to_bw_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_separate_hsv_library = {
+ .code = datatoc_gpu_shader_material_separate_hsv_glsl,
+ .dependencies = {&gpu_shader_material_color_util_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_separate_rgb_library = {
+ .code = datatoc_gpu_shader_material_separate_rgb_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_separate_xyz_library = {
+ .code = datatoc_gpu_shader_material_separate_xyz_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_set_library = {
+ .code = datatoc_gpu_shader_material_set_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_shader_to_rgba_library = {
+ .code = datatoc_gpu_shader_material_shader_to_rgba_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_squeeze_library = {
+ .code = datatoc_gpu_shader_material_squeeze_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_subsurface_scattering_library = {
+ .code = datatoc_gpu_shader_material_subsurface_scattering_glsl,
+ .dependencies = {&gpu_shader_material_diffuse_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_brick_library = {
+ .code = datatoc_gpu_shader_material_tex_brick_glsl,
+ .dependencies = {&gpu_shader_material_math_util_library,
+ &gpu_shader_material_hash_library,
+ NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_checker_library = {
+ .code = datatoc_gpu_shader_material_tex_checker_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_environment_library = {
+ .code = datatoc_gpu_shader_material_tex_environment_glsl,
+ .dependencies = {&gpu_shader_material_math_util_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_gradient_library = {
+ .code = datatoc_gpu_shader_material_tex_gradient_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_image_library = {
+ .code = datatoc_gpu_shader_material_tex_image_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_magic_library = {
+ .code = datatoc_gpu_shader_material_tex_magic_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_musgrave_library = {
+ .code = datatoc_gpu_shader_material_tex_musgrave_glsl,
+ .dependencies = {&gpu_shader_material_noise_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_noise_library = {
+ .code = datatoc_gpu_shader_material_tex_noise_glsl,
+ .dependencies = {&gpu_shader_material_fractal_noise_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_sky_library = {
+ .code = datatoc_gpu_shader_material_tex_sky_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_texture_coordinates_library = {
+ .code = datatoc_gpu_shader_material_texture_coordinates_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_voronoi_library = {
+ .code = datatoc_gpu_shader_material_tex_voronoi_glsl,
+ .dependencies = {&gpu_shader_material_math_util_library,
+ &gpu_shader_material_hash_library,
+ NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_wave_library = {
+ .code = datatoc_gpu_shader_material_tex_wave_glsl,
+ .dependencies = {&gpu_shader_material_fractal_noise_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_white_noise_library = {
+ .code = datatoc_gpu_shader_material_tex_white_noise_glsl,
+ .dependencies = {&gpu_shader_material_hash_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_toon_library = {
+ .code = datatoc_gpu_shader_material_toon_glsl,
+ .dependencies = {&gpu_shader_material_diffuse_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_translucent_library = {
+ .code = datatoc_gpu_shader_material_translucent_glsl,
+ .dependencies = {&gpu_shader_material_diffuse_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_transparent_library = {
+ .code = datatoc_gpu_shader_material_transparent_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_uv_map_library = {
+ .code = datatoc_gpu_shader_material_uv_map_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_vector_curves_library = {
+ .code = datatoc_gpu_shader_material_vector_curves_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_vector_displacement_library = {
+ .code = datatoc_gpu_shader_material_vector_displacement_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_vector_math_library = {
+ .code = datatoc_gpu_shader_material_vector_math_glsl,
+ .dependencies = {&gpu_shader_material_math_util_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_velvet_library = {
+ .code = datatoc_gpu_shader_material_velvet_glsl,
+ .dependencies = {&gpu_shader_material_diffuse_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_vertex_color_library = {
+ .code = datatoc_gpu_shader_material_vertex_color_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_volume_absorption_library = {
+ .code = datatoc_gpu_shader_material_volume_absorption_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_volume_info_library = {
+ .code = datatoc_gpu_shader_material_volume_info_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_volume_principled_library = {
+ .code = datatoc_gpu_shader_material_volume_principled_glsl,
+ .dependencies = {&gpu_shader_material_blackbody_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_volume_scatter_library = {
+ .code = datatoc_gpu_shader_material_volume_scatter_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_wireframe_library = {
+ .code = datatoc_gpu_shader_material_wireframe_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_world_normals_library = {
+ .code = datatoc_gpu_shader_material_world_normals_glsl,
+ .dependencies = {&gpu_shader_material_texture_coordinates_library, NULL},
+};
+
+static GPUMaterialLibrary *gpu_material_libraries[] = {
+ &gpu_shader_material_math_util_library,
+ &gpu_shader_material_color_util_library,
+ &gpu_shader_material_hash_library,
+ &gpu_shader_material_noise_library,
+ &gpu_shader_material_fractal_noise_library,
+ &gpu_shader_material_add_shader_library,
+ &gpu_shader_material_ambient_occlusion_library,
+ &gpu_shader_material_glossy_library,
+ &gpu_shader_material_anisotropic_library,
+ &gpu_shader_material_attribute_library,
+ &gpu_shader_material_background_library,
+ &gpu_shader_material_bevel_library,
+ &gpu_shader_material_blackbody_library,
+ &gpu_shader_material_bright_contrast_library,
+ &gpu_shader_material_bump_library,
+ &gpu_shader_material_camera_library,
+ &gpu_shader_material_clamp_library,
+ &gpu_shader_material_color_ramp_library,
+ &gpu_shader_material_combine_hsv_library,
+ &gpu_shader_material_combine_rgb_library,
+ &gpu_shader_material_combine_xyz_library,
+ &gpu_shader_material_diffuse_library,
+ &gpu_shader_material_displacement_library,
+ &gpu_shader_material_eevee_specular_library,
+ &gpu_shader_material_emission_library,
+ &gpu_shader_material_fresnel_library,
+ &gpu_shader_material_gamma_library,
+ &gpu_shader_material_tangent_library,
+ &gpu_shader_material_geometry_library,
+ &gpu_shader_material_glass_library,
+ &gpu_shader_material_hair_info_library,
+ &gpu_shader_material_holdout_library,
+ &gpu_shader_material_hue_sat_val_library,
+ &gpu_shader_material_invert_library,
+ &gpu_shader_material_layer_weight_library,
+ &gpu_shader_material_light_falloff_library,
+ &gpu_shader_material_light_path_library,
+ &gpu_shader_material_mapping_library,
+ &gpu_shader_material_map_range_library,
+ &gpu_shader_material_math_library,
+ &gpu_shader_material_mix_rgb_library,
+ &gpu_shader_material_mix_shader_library,
+ &gpu_shader_material_normal_library,
+ &gpu_shader_material_normal_map_library,
+ &gpu_shader_material_object_info_library,
+ &gpu_shader_material_output_material_library,
+ &gpu_shader_material_output_world_library,
+ &gpu_shader_material_particle_info_library,
+ &gpu_shader_material_principled_library,
+ &gpu_shader_material_refraction_library,
+ &gpu_shader_material_rgb_curves_library,
+ &gpu_shader_material_rgb_to_bw_library,
+ &gpu_shader_material_separate_hsv_library,
+ &gpu_shader_material_separate_rgb_library,
+ &gpu_shader_material_separate_xyz_library,
+ &gpu_shader_material_set_library,
+ &gpu_shader_material_shader_to_rgba_library,
+ &gpu_shader_material_squeeze_library,
+ &gpu_shader_material_subsurface_scattering_library,
+ &gpu_shader_material_tex_brick_library,
+ &gpu_shader_material_tex_checker_library,
+ &gpu_shader_material_tex_environment_library,
+ &gpu_shader_material_tex_gradient_library,
+ &gpu_shader_material_tex_image_library,
+ &gpu_shader_material_tex_magic_library,
+ &gpu_shader_material_tex_musgrave_library,
+ &gpu_shader_material_tex_noise_library,
+ &gpu_shader_material_tex_sky_library,
+ &gpu_shader_material_texture_coordinates_library,
+ &gpu_shader_material_tex_voronoi_library,
+ &gpu_shader_material_tex_wave_library,
+ &gpu_shader_material_tex_white_noise_library,
+ &gpu_shader_material_toon_library,
+ &gpu_shader_material_translucent_library,
+ &gpu_shader_material_transparent_library,
+ &gpu_shader_material_uv_map_library,
+ &gpu_shader_material_vector_curves_library,
+ &gpu_shader_material_vector_displacement_library,
+ &gpu_shader_material_vector_math_library,
+ &gpu_shader_material_velvet_library,
+ &gpu_shader_material_vertex_color_library,
+ &gpu_shader_material_volume_absorption_library,
+ &gpu_shader_material_volume_info_library,
+ &gpu_shader_material_volume_principled_library,
+ &gpu_shader_material_volume_scatter_library,
+ &gpu_shader_material_wireframe_library,
+ &gpu_shader_material_world_normals_library,
+ NULL};
+#endif
diff --git a/source/blender/gpu/intern/gpu_private.h b/source/blender/gpu/intern/gpu_private.h
index 43b2da13e28..b9af8f1b38c 100644
--- a/source/blender/gpu/intern/gpu_private.h
+++ b/source/blender/gpu/intern/gpu_private.h
@@ -33,4 +33,8 @@ void gpu_debug_exit(void);
void gpu_framebuffer_module_init(void);
void gpu_framebuffer_module_exit(void);
+/* gpu_pbvh.c */
+void gpu_pbvh_init(void);
+void gpu_pbvh_exit(void);
+
#endif /* __GPU_PRIVATE_H__ */
diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c
index 119aed2f5ed..f12da9ce2f7 100644
--- a/source/blender/gpu/intern/gpu_select.c
+++ b/source/blender/gpu/intern/gpu_select.c
@@ -27,7 +27,6 @@
#include <stdlib.h>
#include "GPU_select.h"
-#include "GPU_extensions.h"
#include "GPU_glew.h"
#include "MEM_guardedalloc.h"
diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c
index 939279d82ff..1fb83b628e1 100644
--- a/source/blender/gpu/intern/gpu_select_pick.c
+++ b/source/blender/gpu/intern/gpu_select_pick.c
@@ -30,7 +30,6 @@
#include "GPU_immediate.h"
#include "GPU_draw.h"
#include "GPU_select.h"
-#include "GPU_extensions.h"
#include "GPU_glew.h"
#include "MEM_guardedalloc.h"
diff --git a/source/blender/gpu/intern/gpu_select_sample_query.c b/source/blender/gpu/intern/gpu_select_sample_query.c
index beea25b4171..6e8b062cff0 100644
--- a/source/blender/gpu/intern/gpu_select_sample_query.c
+++ b/source/blender/gpu/intern/gpu_select_sample_query.c
@@ -29,7 +29,6 @@
#include "GPU_immediate.h"
#include "GPU_draw.h"
#include "GPU_select.h"
-#include "GPU_extensions.h"
#include "GPU_glew.h"
#include "MEM_guardedalloc.h"
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index 3e930d19696..015df078228 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -36,7 +36,6 @@
#include "DNA_space_types.h"
#include "GPU_extensions.h"
-#include "GPU_context.h"
#include "GPU_matrix.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
@@ -249,6 +248,9 @@ static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH])
/* a #version 400 feature, but we use #version 330 maximum so use extension */
strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n");
}
+ if (GLEW_ARB_shader_draw_parameters) {
+ strcat(defines, "#extension GL_ARB_shader_draw_parameters : enable\n");
+ }
}
static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH])
@@ -256,6 +258,9 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH])
/* some useful defines to detect GPU type */
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
strcat(defines, "#define GPU_ATI\n");
+ if (GPU_crappy_amd_driver()) {
+ strcat(defines, "#define GPU_DEPRECATED_AMD_DRIVER\n");
+ }
}
else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY)) {
strcat(defines, "#define GPU_NVIDIA\n");
@@ -275,6 +280,22 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH])
strcat(defines, "#define OS_UNIX\n");
}
+ float derivatives_factors[2];
+ GPU_get_dfdy_factors(derivatives_factors);
+ if (derivatives_factors[0] == 1.0f) {
+ strcat(defines, "#define DFDX_SIGN 1.0\n");
+ }
+ else {
+ strcat(defines, "#define DFDX_SIGN -1.0\n");
+ }
+
+ if (derivatives_factors[1] == 1.0f) {
+ strcat(defines, "#define DFDY_SIGN 1.0\n");
+ }
+ else {
+ strcat(defines, "#define DFDY_SIGN -1.0\n");
+ }
+
return;
}
diff --git a/source/blender/gpu/intern/gpu_shader_interface.c b/source/blender/gpu/intern/gpu_shader_interface.c
index f205ef31ed2..983c5dfc27a 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.c
+++ b/source/blender/gpu/intern/gpu_shader_interface.c
@@ -65,9 +65,8 @@ static const char *BuiltinUniform_name(GPUUniformBuiltin u)
[GPU_UNIFORM_CLIPPLANES] = "WorldClipPlanes",
[GPU_UNIFORM_COLOR] = "color",
- [GPU_UNIFORM_CALLID] = "callId",
- [GPU_UNIFORM_OBJECT_INFO] = "unfobjectinfo",
- [GPU_UNIFORM_OBJECT_COLOR] = "unfobjectcolor",
+ [GPU_UNIFORM_BASE_INSTANCE] = "baseInstance",
+ [GPU_UNIFORM_RESOURCE_CHUNK] = "resourceChunk",
[GPU_UNIFORM_CUSTOM] = NULL,
[GPU_NUM_UNIFORMS] = NULL,
@@ -149,7 +148,7 @@ GPU_INLINE const GPUShaderInput *buckets_lookup(
GPU_INLINE void buckets_free(GPUShaderInput *buckets[GPU_NUM_SHADERINTERFACE_BUCKETS])
{
- for (uint bucket_index = 0; bucket_index < GPU_NUM_SHADERINTERFACE_BUCKETS; ++bucket_index) {
+ for (uint bucket_index = 0; bucket_index < GPU_NUM_SHADERINTERFACE_BUCKETS; bucket_index++) {
GPUShaderInput *input = buckets[bucket_index];
while (input != NULL) {
GPUShaderInput *input_next = input->next;
@@ -164,7 +163,7 @@ static bool setup_builtin_uniform(GPUShaderInput *input, const char *name)
/* TODO: reject DOUBLE, IMAGE, ATOMIC_COUNTER gl_types */
/* detect built-in uniforms (name must match) */
- for (GPUUniformBuiltin u = GPU_UNIFORM_NONE + 1; u < GPU_UNIFORM_CUSTOM; ++u) {
+ for (GPUUniformBuiltin u = GPU_UNIFORM_NONE + 1; u < GPU_UNIFORM_CUSTOM; u++) {
const char *builtin_name = BuiltinUniform_name(u);
if (match(name, builtin_name)) {
input->builtin_type = u;
@@ -236,7 +235,7 @@ GPUShaderInterface *GPU_shaderinterface_create(int32_t program)
shaderface->name_buffer = MEM_mallocN(name_buffer_len, "name_buffer");
/* Attributes */
- for (uint32_t i = 0; i < attr_len; ++i) {
+ for (uint32_t i = 0; i < attr_len; i++) {
GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput Attr");
GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset;
char *name = shaderface->name_buffer + shaderface->name_buffer_offset;
@@ -264,7 +263,7 @@ GPUShaderInterface *GPU_shaderinterface_create(int32_t program)
#endif
}
/* Uniform Blocks */
- for (uint32_t i = 0; i < ubo_len; ++i) {
+ for (uint32_t i = 0; i < ubo_len; i++) {
GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput UBO");
GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset;
char *name = shaderface->name_buffer + shaderface->name_buffer_offset;
@@ -283,7 +282,7 @@ GPUShaderInterface *GPU_shaderinterface_create(int32_t program)
#endif
}
/* Builtin Uniforms */
- for (GPUUniformBuiltin u = GPU_UNIFORM_NONE + 1; u < GPU_UNIFORM_CUSTOM; ++u) {
+ for (GPUUniformBuiltin u = GPU_UNIFORM_NONE + 1; u < GPU_UNIFORM_CUSTOM; u++) {
const char *builtin_name = BuiltinUniform_name(u);
if (glGetUniformLocation(program, builtin_name) != -1) {
add_uniform((GPUShaderInterface *)shaderface, builtin_name);
@@ -306,7 +305,7 @@ void GPU_shaderinterface_discard(GPUShaderInterface *shaderface)
/* Free memory used by name_buffer. */
MEM_freeN(shaderface->name_buffer);
/* Remove this interface from all linked Batches vao cache. */
- for (int i = 0; i < shaderface->batches_len; ++i) {
+ for (int i = 0; i < shaderface->batches_len; i++) {
if (shaderface->batches[i] != NULL) {
gpu_batch_remove_interface_ref(shaderface->batches[i], shaderface);
}
@@ -374,7 +373,7 @@ const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *shaderf
void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *shaderface, GPUBatch *batch)
{
int i; /* find first unused slot */
- for (i = 0; i < shaderface->batches_len; ++i) {
+ for (i = 0; i < shaderface->batches_len; i++) {
if (shaderface->batches[i] == NULL) {
break;
}
@@ -391,7 +390,7 @@ void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *shaderface, GPUBatch
void GPU_shaderinterface_remove_batch_ref(GPUShaderInterface *shaderface, GPUBatch *batch)
{
- for (int i = 0; i < shaderface->batches_len; ++i) {
+ for (int i = 0; i < shaderface->batches_len; i++) {
if (shaderface->batches[i] == batch) {
shaderface->batches[i] = NULL;
break; /* cannot have duplicates */
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index 955b11036ef..a54d90f37f5 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -1471,7 +1471,7 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat gpu_data_format, int mipl
if (GPU_texture_cube(tex)) {
int cube_face_size = buf_size / 6;
- for (int i = 0; i < 6; ++i) {
+ for (int i = 0; i < 6; i++) {
glGetTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
miplvl,
data_format,
@@ -1540,7 +1540,7 @@ void GPU_texture_bind(GPUTexture *tex, int number)
}
if ((G.debug & G_DEBUG)) {
- for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; ++i) {
+ for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; i++) {
if (tex->fb[i] && GPU_framebuffer_bound(tex->fb[i])) {
fprintf(stderr,
"Feedback loop warning!: Attempting to bind "
@@ -1603,7 +1603,7 @@ void GPU_texture_generate_mipmap(GPUTexture *tex)
* GPU_framebuffer_recursive_downsample(). */
int levels = 1 + floor(log2(max_ii(tex->w, tex->h)));
eGPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex->format);
- for (int i = 1; i < levels; ++i) {
+ for (int i = 1; i < levels; i++) {
GPU_texture_add_mipmap(tex, data_format, i, NULL);
}
glBindTexture(tex->target, tex->bindcode);
@@ -1712,7 +1712,7 @@ void GPU_texture_free(GPUTexture *tex)
}
if (tex->refcount == 0) {
- for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; ++i) {
+ for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; i++) {
if (tex->fb[i] != NULL) {
GPU_framebuffer_texture_detach_slot(tex->fb[i], tex, tex->fb_attachment[i]);
}
@@ -1806,7 +1806,7 @@ int GPU_texture_opengl_bindcode(const GPUTexture *tex)
void GPU_texture_attach_framebuffer(GPUTexture *tex, GPUFrameBuffer *fb, int attachment)
{
- for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; ++i) {
+ for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; i++) {
if (tex->fb[i] == NULL) {
tex->fb[i] = fb;
tex->fb_attachment[i] = attachment;
@@ -1820,7 +1820,7 @@ void GPU_texture_attach_framebuffer(GPUTexture *tex, GPUFrameBuffer *fb, int att
/* Return previous attachment point */
int GPU_texture_detach_framebuffer(GPUTexture *tex, GPUFrameBuffer *fb)
{
- for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; ++i) {
+ for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; i++) {
if (tex->fb[i] == fb) {
tex->fb[i] = NULL;
return tex->fb_attachment[i];
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.c b/source/blender/gpu/intern/gpu_vertex_buffer.c
index 2f854fe03ea..eecbcb9ec94 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer.c
+++ b/source/blender/gpu/intern/gpu_vertex_buffer.c
@@ -214,7 +214,7 @@ void GPU_vertbuf_attr_fill_stride(GPUVertBuf *verts, uint a_idx, uint stride, co
}
else {
/* we must copy it per vertex */
- for (uint v = 0; v < vertex_len; ++v) {
+ for (uint v = 0; v < vertex_len; v++) {
memcpy((GLubyte *)verts->data + a->offset + v * format->stride,
(const GLubyte *)data + v * stride,
a->sz);
diff --git a/source/blender/gpu/intern/gpu_vertex_format.c b/source/blender/gpu/intern/gpu_vertex_format.c
index 66e5e254734..65573b71c76 100644
--- a/source/blender/gpu/intern/gpu_vertex_format.c
+++ b/source/blender/gpu/intern/gpu_vertex_format.c
@@ -126,7 +126,7 @@ static uchar copy_attr_name(GPUVertFormat *format, const char *name)
uint available = GPU_VERT_ATTR_NAMES_BUF_LEN - name_offset;
bool terminated = false;
- for (uint i = 0; i < available; ++i) {
+ for (uint i = 0; i < available; i++) {
const char c = name[i];
name_copy[i] = c;
if (c == '\0') {
@@ -303,10 +303,10 @@ uint padding(uint offset, uint alignment)
static void show_pack(uint a_idx, uint sz, uint pad)
{
const char c = 'A' + a_idx;
- for (uint i = 0; i < pad; ++i) {
+ for (uint i = 0; i < pad; i++) {
putchar('-');
}
- for (uint i = 0; i < sz; ++i) {
+ for (uint i = 0; i < sz; i++) {
putchar(c);
}
}
@@ -330,7 +330,7 @@ void VertexFormat_pack(GPUVertFormat *format)
show_pack(0, a0->sz, 0);
#endif
- for (uint a_idx = 1; a_idx < format->attr_len; ++a_idx) {
+ for (uint a_idx = 1; a_idx < format->attr_len; a_idx++) {
GPUVertAttr *a = &format->attrs[a_idx];
uint mid_padding = padding(offset, attr_align(a));
offset += mid_padding;
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index e3c13b0ec14..615af57c1bd 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -39,7 +39,7 @@
#include "GPU_immediate.h"
#include "GPU_texture.h"
#include "GPU_viewport.h"
-#include "GPU_draw.h"
+#include "GPU_uniformbuffer.h"
#include "DRW_engine.h"
@@ -303,7 +303,7 @@ GPUTexture *GPU_viewport_texture_pool_query(
(GPU_texture_width(tmp_tex->texture) == width) &&
(GPU_texture_height(tmp_tex->texture) == height)) {
/* Search if the engine is not already using this texture */
- for (int i = 0; i < MAX_ENGINE_BUFFER_SHARING; ++i) {
+ for (int i = 0; i < MAX_ENGINE_BUFFER_SHARING; i++) {
if (tmp_tex->user[i] == engine) {
break;
}
@@ -339,7 +339,7 @@ static void gpu_viewport_texture_pool_clear_users(GPUViewport *viewport)
for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex_next) {
tmp_tex_next = tmp_tex->next;
bool no_user = true;
- for (int i = 0; i < MAX_ENGINE_BUFFER_SHARING; ++i) {
+ for (int i = 0; i < MAX_ENGINE_BUFFER_SHARING; i++) {
if (tmp_tex->user[i] != NULL) {
tmp_tex->user[i] = NULL;
no_user = false;
@@ -620,11 +620,20 @@ void GPU_viewport_free(GPUViewport *viewport)
MEM_freeN(viewport->fbl);
MEM_freeN(viewport->txl);
- if (viewport->vmempool.calls != NULL) {
- BLI_memblock_destroy(viewport->vmempool.calls, NULL);
+ if (viewport->vmempool.commands != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.commands, NULL);
}
- if (viewport->vmempool.states != NULL) {
- BLI_memblock_destroy(viewport->vmempool.states, NULL);
+ if (viewport->vmempool.commands_small != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.commands_small, NULL);
+ }
+ if (viewport->vmempool.callbuffers != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.callbuffers, NULL);
+ }
+ if (viewport->vmempool.obmats != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.obmats, NULL);
+ }
+ if (viewport->vmempool.obinfos != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.obinfos, NULL);
}
if (viewport->vmempool.cullstates != NULL) {
BLI_memblock_destroy(viewport->vmempool.cullstates, NULL);
@@ -651,6 +660,13 @@ void GPU_viewport_free(GPUViewport *viewport)
BLI_memblock_destroy(viewport->vmempool.images, NULL);
}
+ for (int i = 0; i < viewport->vmempool.ubo_len; i++) {
+ GPU_uniformbuffer_free(viewport->vmempool.matrices_ubo[i]);
+ GPU_uniformbuffer_free(viewport->vmempool.obinfos_ubo[i]);
+ }
+ MEM_SAFE_FREE(viewport->vmempool.matrices_ubo);
+ MEM_SAFE_FREE(viewport->vmempool.obinfos_ubo);
+
DRW_instance_data_list_free(viewport->idatalist);
MEM_freeN(viewport->idatalist);
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl
index 0ce5504dfa8..b0fa9eaed21 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl
@@ -4,12 +4,15 @@ uniform vec2 aspect;
in vec2 pos;
-#ifndef STRETCH_ANGLE
-in float stretch;
-#else
-
+#ifdef STRETCH_ANGLE
in vec2 uv_angles;
in float angle;
+
+#else
+in float ratio;
+uniform float totalAreaRatio;
+uniform float totalAreaRatioInv;
+
#endif
noperspective out vec4 finalColor;
@@ -69,6 +72,12 @@ float angle_normalized_v2v2(vec2 v1, vec2 v2)
return (q) ? a : M_PI - a;
}
+float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_tot_ratio)
+{
+ ratio *= (ratio > 0.0f) ? tot_ratio : -inv_tot_ratio;
+ return (ratio > 1.0f) ? (1.0f / ratio) : ratio;
+}
+
void main()
{
gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
@@ -80,6 +89,9 @@ void main()
float stretch = 1.0 - abs(uv_angle - angle);
stretch = stretch;
stretch = 1.0 - stretch * stretch;
+#else
+ float stretch = 1.0 - area_ratio_to_stretch(ratio, totalAreaRatio, -totalAreaRatioInv);
+
#endif
finalColor = vec4(weight_to_rgb(stretch), 1.0);
diff --git a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
new file mode 100644
index 00000000000..aa1d437c307
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
@@ -0,0 +1,19 @@
+
+/* Need to be included after common_view_lib.glsl for resource_id. */
+#ifndef GPU_OBINFOS_UBO
+#define GPU_OBINFOS_UBO
+struct ObjectInfos {
+ vec4 drw_OrcoTexCoFactors[2];
+ vec4 drw_ObjectColor;
+ vec4 drw_Infos;
+};
+
+layout(std140) uniform infoBlock
+{
+ /* DRW_RESOURCE_CHUNK_LEN = 512 */
+ ObjectInfos drw_infos[512];
+};
+#define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors)
+#define ObjectInfo (drw_infos[resource_id].drw_Infos)
+#define ObjectColor (drw_infos[resource_id].drw_ObjectColor)
+#endif
diff --git a/source/blender/gpu/shaders/gpu_shader_geometry.glsl b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
index f62040589e5..3b4e2e17ccc 100644
--- a/source/blender/gpu/shaders/gpu_shader_geometry.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
@@ -24,7 +24,7 @@ uniform int osd_fvar_count;
{ \
vec2 v[4]; \
int primOffset = (gl_PrimitiveID + PrimitiveIdBase) * 4; \
- for (int i = 0; i < 4; ++i) { \
+ for (int i = 0; i < 4; i++) { \
int index = (primOffset + i) * osd_fvar_count + fvarOffset; \
v[i] = vec2(texelFetch(FVarDataBuffer, index).s, texelFetch(FVarDataBuffer, index + 1).s); \
} \
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl
index 31b359dbe6d..f32c47bcec3 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl
@@ -1,8 +1,5 @@
uniform mat4 ViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
-uniform mat4 ModelMatrix;
-#endif
/* ---- Instantiated Attrs ---- */
in float pos;
@@ -47,11 +44,12 @@ void main()
pPos = vec3(0.0);
}
- gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pPos, 1.0);
+ vec4 wPos = InstanceModelMatrix * vec4(pPos, 1.0);
+ gl_Position = ViewProjectionMatrix * wPos;
finalColor = vec4(color, 1.0);
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * InstanceModelMatrix * vec4(pPos, 1.0)).xyz);
+ world_clip_planes_calc_clip_distance(wPos.xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl
index d9a0ffbbdac..5bd29c55e42 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl
@@ -18,13 +18,14 @@ void main()
{
float len = end - start;
vec3 sta = vec3(0.0, 0.0, -start);
- vec4 pos_4d = vec4(pos * -len + sta, 1.0);
- gl_Position = ViewProjectionMatrix * InstanceModelMatrix * pos_4d;
+ vec4 wPos = InstanceModelMatrix * vec4(pos * -len + sta, 1.0);
+
+ gl_Position = ViewProjectionMatrix * wPos;
gl_PointSize = size;
finalColor = vec4(color, 1.0);
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((InstanceModelMatrix * pos_4d).xyz);
+ world_clip_planes_calc_clip_distance(wPos.xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
index 3e52e43beae..10228a1e985 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
@@ -1,6 +1,5 @@
uniform mat4 ViewProjectionMatrix;
-uniform mat4 ModelMatrix;
/* ---- Instantiated Attrs ---- */
in vec3 pos;
@@ -20,10 +19,10 @@ void main()
{
finalColor = color;
- vec4 pos_4d = vec4(pos * size, 1.0);
- gl_Position = ViewProjectionMatrix * InstanceModelMatrix * pos_4d;
+ vec4 wPos = InstanceModelMatrix * vec4(pos * size, 1.0);
+ gl_Position = ViewProjectionMatrix * wPos;
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * InstanceModelMatrix * pos_4d).xyz);
+ world_clip_planes_calc_clip_distance(wPos.xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl
index 130f46e1e33..32db8d17572 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl
@@ -1,8 +1,6 @@
uniform mat4 ViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
-uniform mat4 ModelMatrix;
-#endif
+
uniform int baseId;
/* ---- Instantiated Attrs ---- */
@@ -21,11 +19,11 @@ flat out uint finalId;
void main()
{
- vec4 pos_4d = vec4(pos * size, 1.0);
- gl_Position = ViewProjectionMatrix * InstanceModelMatrix * pos_4d;
+ vec4 wPos = InstanceModelMatrix * vec4(pos * size, 1.0);
+ gl_Position = ViewProjectionMatrix * wPos;
finalId = uint(baseId + callId);
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * InstanceModelMatrix * pos_4d).xyz);
+ world_clip_planes_calc_clip_distance(wPos.xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl
index eeca6e972fa..b8d31f5540a 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl
@@ -9,5 +9,5 @@ in mat4 InstanceModelMatrix;
void main()
{
- gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pos, 1.0);
+ gl_Position = ViewProjectionMatrix * (InstanceModelMatrix * vec4(pos, 1.0));
}
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
deleted file mode 100644
index 24fef4f05d8..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ /dev/null
@@ -1,3874 +0,0 @@
-
-/* Converters */
-
-float convert_rgba_to_float(vec4 color)
-{
- return dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
-}
-
-float exp_blender(float f)
-{
- return pow(2.71828182846, f);
-}
-
-float compatible_pow(float x, float y)
-{
- if (y == 0.0) { /* x^0 -> 1, including 0^0 */
- return 1.0;
- }
-
- /* glsl pow doesn't accept negative x */
- if (x < 0.0) {
- if (mod(-y, 2.0) == 0.0) {
- return pow(-x, y);
- }
- else {
- return -pow(-x, y);
- }
- }
- else if (x == 0.0) {
- return 0.0;
- }
-
- return pow(x, y);
-}
-
-void rgb_to_hsv(vec4 rgb, out vec4 outcol)
-{
- float cmax, cmin, h, s, v, cdelta;
- vec3 c;
-
- cmax = max(rgb[0], max(rgb[1], rgb[2]));
- cmin = min(rgb[0], min(rgb[1], rgb[2]));
- cdelta = cmax - cmin;
-
- v = cmax;
- if (cmax != 0.0) {
- s = cdelta / cmax;
- }
- else {
- s = 0.0;
- h = 0.0;
- }
-
- if (s == 0.0) {
- h = 0.0;
- }
- else {
- c = (vec3(cmax) - rgb.xyz) / cdelta;
-
- if (rgb.x == cmax) {
- h = c[2] - c[1];
- }
- else if (rgb.y == cmax) {
- h = 2.0 + c[0] - c[2];
- }
- else {
- h = 4.0 + c[1] - c[0];
- }
-
- h /= 6.0;
-
- if (h < 0.0) {
- h += 1.0;
- }
- }
-
- outcol = vec4(h, s, v, rgb.w);
-}
-
-void hsv_to_rgb(vec4 hsv, out vec4 outcol)
-{
- float i, f, p, q, t, h, s, v;
- vec3 rgb;
-
- h = hsv[0];
- s = hsv[1];
- v = hsv[2];
-
- if (s == 0.0) {
- rgb = vec3(v, v, v);
- }
- else {
- if (h == 1.0) {
- h = 0.0;
- }
-
- h *= 6.0;
- i = floor(h);
- f = h - i;
- rgb = vec3(f, f, f);
- p = v * (1.0 - s);
- q = v * (1.0 - (s * f));
- t = v * (1.0 - (s * (1.0 - f)));
-
- if (i == 0.0) {
- rgb = vec3(v, t, p);
- }
- else if (i == 1.0) {
- rgb = vec3(q, v, p);
- }
- else if (i == 2.0) {
- rgb = vec3(p, v, t);
- }
- else if (i == 3.0) {
- rgb = vec3(p, q, v);
- }
- else if (i == 4.0) {
- rgb = vec3(t, p, v);
- }
- else {
- rgb = vec3(v, p, q);
- }
- }
-
- outcol = vec4(rgb, hsv.w);
-}
-
-void color_to_normal_new_shading(vec3 color, out vec3 normal)
-{
- normal = vec3(2.0) * color - vec3(1.0);
-}
-
-void color_to_blender_normal_new_shading(vec3 color, out vec3 normal)
-{
- normal = vec3(2.0, -2.0, -2.0) * color - vec3(1.0);
-}
-
-#ifndef M_PI
-# define M_PI 3.14159265358979323846
-#endif
-#ifndef M_1_PI
-# define M_1_PI 0.318309886183790671538
-#endif
-
-/*********** SHADER NODES ***************/
-
-void particle_info(vec4 sprops,
- vec4 loc,
- vec3 vel,
- vec3 avel,
- out float index,
- out float random,
- out float age,
- out float life_time,
- out vec3 location,
- out float size,
- out vec3 velocity,
- out vec3 angular_velocity)
-{
- index = sprops.x;
- random = loc.w;
- age = sprops.y;
- life_time = sprops.z;
- size = sprops.w;
-
- location = loc.xyz;
- velocity = vel;
- angular_velocity = avel;
-}
-
-void vect_normalize(vec3 vin, out vec3 vout)
-{
- vout = normalize(vin);
-}
-
-void direction_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
-{
- vout = (mat * vec4(vin, 0.0)).xyz;
-}
-
-void normal_transform_transposed_m4v3(vec3 vin, mat4 mat, out vec3 vout)
-{
- vout = transpose(mat3(mat)) * vin;
-}
-
-void point_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
-{
- vout = (mat * vec4(vin, 1.0)).xyz;
-}
-
-void point_texco_remap_square(vec3 vin, out vec3 vout)
-{
- vout = vin * 2.0 - 1.0;
-}
-
-void point_texco_clamp(vec3 vin, sampler2D ima, out vec3 vout)
-{
- vec2 half_texel_size = 0.5 / vec2(textureSize(ima, 0).xy);
- vout = clamp(vin, half_texel_size.xyy, 1.0 - half_texel_size.xyy);
-}
-
-void point_map_to_sphere(vec3 vin, out vec3 vout)
-{
- float len = length(vin);
- float v, u;
- if (len > 0.0) {
- if (vin.x == 0.0 && vin.y == 0.0) {
- u = 0.0;
- }
- else {
- u = (1.0 - atan(vin.x, vin.y) / M_PI) / 2.0;
- }
-
- v = 1.0 - acos(vin.z / len) / M_PI;
- }
- else {
- v = u = 0.0;
- }
-
- vout = vec3(u, v, 0.0);
-}
-
-void point_map_to_tube(vec3 vin, out vec3 vout)
-{
- float u, v;
- v = (vin.z + 1.0) * 0.5;
- float len = sqrt(vin.x * vin.x + vin.y * vin[1]);
- if (len > 0.0) {
- u = (1.0 - (atan(vin.x / len, vin.y / len) / M_PI)) * 0.5;
- }
- else {
- v = u = 0.0;
- }
-
- vout = vec3(u, v, 0.0);
-}
-
-void mapping(
- vec3 vec, vec4 m0, vec4 m1, vec4 m2, vec4 m3, vec3 minvec, vec3 maxvec, out vec3 outvec)
-{
- mat4 mat = mat4(m0, m1, m2, m3);
- outvec = (mat * vec4(vec, 1.0)).xyz;
- outvec = clamp(outvec, minvec, maxvec);
-}
-
-void camera(vec3 co, out vec3 outview, out float outdepth, out float outdist)
-{
- outdepth = abs(co.z);
- outdist = length(co);
- outview = normalize(co);
-}
-
-void math_add(float a, float b, out float result)
-{
- result = a + b;
-}
-
-void math_subtract(float a, float b, out float result)
-{
- result = a - b;
-}
-
-void math_multiply(float a, float b, out float result)
-{
- result = a * b;
-}
-
-void math_divide(float a, float b, out float result)
-{
- result = (b != 0.0) ? a / b : 0.0;
-}
-
-void math_power(float a, float b, out float result)
-{
- if (a >= 0.0) {
- result = compatible_pow(a, b);
- }
- else {
- float fraction = mod(abs(b), 1.0);
- if (fraction > 0.999 || fraction < 0.001) {
- result = compatible_pow(a, floor(b + 0.5));
- }
- else {
- result = 0.0;
- }
- }
-}
-
-void math_logarithm(float a, float b, out float result)
-{
- result = (a > 0.0 && b > 0.0) ? log2(a) / log2(b) : 0.0;
-}
-
-void math_sqrt(float a, float b, out float result)
-{
- result = (a > 0.0) ? sqrt(a) : 0.0;
-}
-
-void math_absolute(float a, float b, out float result)
-{
- result = abs(a);
-}
-
-void math_minimum(float a, float b, out float result)
-{
- result = min(a, b);
-}
-
-void math_maximum(float a, float b, out float result)
-{
- result = max(a, b);
-}
-
-void math_less_than(float a, float b, out float result)
-{
- result = (a < b) ? 1.0 : 0.0;
-}
-
-void math_greater_than(float a, float b, out float result)
-{
- result = (a > b) ? 1.0 : 0.0;
-}
-
-void math_round(float a, float b, out float result)
-{
- result = floor(a + 0.5);
-}
-
-void math_floor(float a, float b, out float result)
-{
- result = floor(a);
-}
-
-void math_ceil(float a, float b, out float result)
-{
- result = ceil(a);
-}
-
-void math_fraction(float a, float b, out float result)
-{
- result = a - floor(a);
-}
-
-/* Change sign to match C convention. mod in GLSL will take absolute for negative numbers.
- * See https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/mod.xhtml
- */
-void math_modulo(float a, float b, out float result)
-{
- result = (b != 0.0) ? sign(a) * mod(abs(a), b) : 0.0;
-}
-
-void math_sine(float a, float b, out float result)
-{
- result = sin(a);
-}
-
-void math_cosine(float a, float b, out float result)
-{
- result = cos(a);
-}
-
-void math_tangent(float a, float b, out float result)
-{
- result = tan(a);
-}
-
-void math_arcsine(float a, float b, out float result)
-{
- result = (a <= 1.0 && a >= -1.0) ? asin(a) : 0.0;
-}
-
-void math_arccosine(float a, float b, out float result)
-{
- result = (a <= 1.0 && a >= -1.0) ? acos(a) : 0.0;
-}
-
-void math_arctangent(float a, float b, out float result)
-{
- result = atan(a);
-}
-
-void math_arctan2(float a, float b, out float result)
-{
- result = atan(a, b);
-}
-
-void squeeze(float val, float width, float center, out float outval)
-{
- outval = 1.0 / (1.0 + pow(2.71828183, -((val - center) * width)));
-}
-
-void map_range(
- float value, float fromMin, float fromMax, float toMin, float toMax, out float result)
-{
- if (fromMax != fromMin) {
- result = toMin + ((value - fromMin) / (fromMax - fromMin)) * (toMax - toMin);
- }
- else {
- result = 0.0;
- }
-}
-
-vec3 safe_divide(vec3 a, vec3 b)
-{
- return vec3((b.x != 0.0) ? a.x / b.x : 0.0,
- (b.y != 0.0) ? a.y / b.y : 0.0,
- (b.z != 0.0) ? a.z / b.z : 0.0);
-}
-
-void vector_math_add(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = a + b;
-}
-
-void vector_math_subtract(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = a - b;
-}
-
-void vector_math_multiply(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = a * b;
-}
-
-void vector_math_divide(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = safe_divide(a, b);
-}
-
-void vector_math_cross(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = cross(a, b);
-}
-
-void vector_math_project(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- float lenSquared = dot(b, b);
- outVector = (lenSquared != 0.0) ? (dot(a, b) / lenSquared) * b : vec3(0.0);
-}
-
-void vector_math_reflect(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = reflect(a, normalize(b));
-}
-
-void vector_math_dot(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outValue = dot(a, b);
-}
-
-void vector_math_distance(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outValue = distance(a, b);
-}
-
-void vector_math_length(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outValue = length(a);
-}
-
-void vector_math_scale(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = a * scale;
-}
-
-void vector_math_normalize(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = normalize(a);
-}
-
-void vector_math_snap(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = floor(safe_divide(a, b)) * b;
-}
-
-void vector_math_floor(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = floor(a);
-}
-
-void vector_math_ceil(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = ceil(a);
-}
-
-void vector_math_modulo(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- math_modulo(a.x, b.x, outVector.x);
- math_modulo(a.y, b.y, outVector.y);
- math_modulo(a.z, b.z, outVector.z);
-}
-
-void vector_math_fraction(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = fract(a);
-}
-
-void vector_math_absolute(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = abs(a);
-}
-
-void vector_math_minimum(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = min(a, b);
-}
-
-void vector_math_maximum(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = max(a, b);
-}
-
-void vector_math_mix(float strength, vec3 a, vec3 b, out vec3 outVector)
-{
- outVector = strength * a + (1 - strength) * b;
-}
-
-void vec_math_negate(vec3 v, out vec3 outv)
-{
- outv = -v;
-}
-
-void invert_z(vec3 v, out vec3 outv)
-{
- v.z = -v.z;
- outv = v;
-}
-
-void normal_new_shading(vec3 nor, vec3 dir, out vec3 outnor, out float outdot)
-{
- outnor = dir;
- outdot = dot(normalize(nor), dir);
-}
-
-void curves_vec(float fac, vec3 vec, sampler1DArray curvemap, float layer, out vec3 outvec)
-{
- vec4 co = vec4(vec * 0.5 + 0.5, layer);
- outvec.x = texture(curvemap, co.xw).x;
- outvec.y = texture(curvemap, co.yw).y;
- outvec.z = texture(curvemap, co.zw).z;
- outvec = mix(vec, outvec, fac);
-}
-
-/* ext is vec4(in_x, in_dy, out_x, out_dy). */
-float curve_extrapolate(float x, float y, vec4 ext)
-{
- if (x < 0.0) {
- return y + x * ext.y;
- }
- else if (x > 1.0) {
- return y + (x - 1.0) * ext.w;
- }
- else {
- return y;
- }
-}
-
-#define RANGE_RESCALE(x, min, range) ((x - min) * range)
-
-void curves_rgb(float fac,
- vec4 col,
- sampler1DArray curvemap,
- float layer,
- vec4 range,
- vec4 ext_r,
- vec4 ext_g,
- vec4 ext_b,
- vec4 ext_a,
- out vec4 outcol)
-{
- vec4 co = vec4(RANGE_RESCALE(col.rgb, ext_a.x, range.a), layer);
- vec3 samp;
- samp.r = texture(curvemap, co.xw).a;
- samp.g = texture(curvemap, co.yw).a;
- samp.b = texture(curvemap, co.zw).a;
-
- samp.r = curve_extrapolate(co.x, samp.r, ext_a);
- samp.g = curve_extrapolate(co.y, samp.g, ext_a);
- samp.b = curve_extrapolate(co.z, samp.b, ext_a);
-
- vec3 rgb_min = vec3(ext_r.x, ext_g.x, ext_b.x);
- co.xyz = RANGE_RESCALE(samp.rgb, rgb_min, range.rgb);
-
- samp.r = texture(curvemap, co.xw).r;
- samp.g = texture(curvemap, co.yw).g;
- samp.b = texture(curvemap, co.zw).b;
-
- outcol.r = curve_extrapolate(co.x, samp.r, ext_r);
- outcol.g = curve_extrapolate(co.y, samp.g, ext_g);
- outcol.b = curve_extrapolate(co.z, samp.b, ext_b);
- outcol.a = col.a;
-
- outcol = mix(col, outcol, fac);
-}
-
-void curves_rgb_opti(float fac,
- vec4 col,
- sampler1DArray curvemap,
- float layer,
- vec4 range,
- vec4 ext_a,
- out vec4 outcol)
-{
- vec4 co = vec4(RANGE_RESCALE(col.rgb, ext_a.x, range.a), layer);
- vec3 samp;
- samp.r = texture(curvemap, co.xw).a;
- samp.g = texture(curvemap, co.yw).a;
- samp.b = texture(curvemap, co.zw).a;
-
- outcol.r = curve_extrapolate(co.x, samp.r, ext_a);
- outcol.g = curve_extrapolate(co.y, samp.g, ext_a);
- outcol.b = curve_extrapolate(co.z, samp.b, ext_a);
- outcol.a = col.a;
-
- outcol = mix(col, outcol, fac);
-}
-
-void set_value(float val, out float outval)
-{
- outval = val;
-}
-
-void set_rgb(vec3 col, out vec3 outcol)
-{
- outcol = col;
-}
-
-void set_rgba(vec4 col, out vec4 outcol)
-{
- outcol = col;
-}
-
-void set_value_zero(out float outval)
-{
- outval = 0.0;
-}
-
-void set_value_one(out float outval)
-{
- outval = 1.0;
-}
-
-void set_rgb_zero(out vec3 outval)
-{
- outval = vec3(0.0);
-}
-
-void set_rgb_one(out vec3 outval)
-{
- outval = vec3(1.0);
-}
-
-void set_rgba_zero(out vec4 outval)
-{
- outval = vec4(0.0);
-}
-
-void set_rgba_one(out vec4 outval)
-{
- outval = vec4(1.0);
-}
-
-void brightness_contrast(vec4 col, float brightness, float contrast, out vec4 outcol)
-{
- float a = 1.0 + contrast;
- float b = brightness - contrast * 0.5;
-
- outcol.r = max(a * col.r + b, 0.0);
- outcol.g = max(a * col.g + b, 0.0);
- outcol.b = max(a * col.b + b, 0.0);
- outcol.a = col.a;
-}
-
-void mix_blend(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- outcol = mix(col1, col2, fac);
- outcol.a = col1.a;
-}
-
-void mix_add(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- outcol = mix(col1, col1 + col2, fac);
- outcol.a = col1.a;
-}
-
-void mix_mult(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- outcol = mix(col1, col1 * col2, fac);
- outcol.a = col1.a;
-}
-
-void mix_screen(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- float facm = 1.0 - fac;
-
- outcol = vec4(1.0) - (vec4(facm) + fac * (vec4(1.0) - col2)) * (vec4(1.0) - col1);
- outcol.a = col1.a;
-}
-
-void mix_overlay(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- float facm = 1.0 - fac;
-
- outcol = col1;
-
- if (outcol.r < 0.5) {
- outcol.r *= facm + 2.0 * fac * col2.r;
- }
- else {
- outcol.r = 1.0 - (facm + 2.0 * fac * (1.0 - col2.r)) * (1.0 - outcol.r);
- }
-
- if (outcol.g < 0.5) {
- outcol.g *= facm + 2.0 * fac * col2.g;
- }
- else {
- outcol.g = 1.0 - (facm + 2.0 * fac * (1.0 - col2.g)) * (1.0 - outcol.g);
- }
-
- if (outcol.b < 0.5) {
- outcol.b *= facm + 2.0 * fac * col2.b;
- }
- else {
- outcol.b = 1.0 - (facm + 2.0 * fac * (1.0 - col2.b)) * (1.0 - outcol.b);
- }
-}
-
-void mix_sub(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- outcol = mix(col1, col1 - col2, fac);
- outcol.a = col1.a;
-}
-
-void mix_div(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- float facm = 1.0 - fac;
-
- outcol = col1;
-
- if (col2.r != 0.0) {
- outcol.r = facm * outcol.r + fac * outcol.r / col2.r;
- }
- if (col2.g != 0.0) {
- outcol.g = facm * outcol.g + fac * outcol.g / col2.g;
- }
- if (col2.b != 0.0) {
- outcol.b = facm * outcol.b + fac * outcol.b / col2.b;
- }
-}
-
-void mix_diff(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- outcol = mix(col1, abs(col1 - col2), fac);
- outcol.a = col1.a;
-}
-
-void mix_dark(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- outcol.rgb = min(col1.rgb, col2.rgb * fac);
- outcol.a = col1.a;
-}
-
-void mix_light(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- outcol.rgb = max(col1.rgb, col2.rgb * fac);
- outcol.a = col1.a;
-}
-
-void mix_dodge(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- outcol = col1;
-
- if (outcol.r != 0.0) {
- float tmp = 1.0 - fac * col2.r;
- if (tmp <= 0.0) {
- outcol.r = 1.0;
- }
- else if ((tmp = outcol.r / tmp) > 1.0) {
- outcol.r = 1.0;
- }
- else {
- outcol.r = tmp;
- }
- }
- if (outcol.g != 0.0) {
- float tmp = 1.0 - fac * col2.g;
- if (tmp <= 0.0) {
- outcol.g = 1.0;
- }
- else if ((tmp = outcol.g / tmp) > 1.0) {
- outcol.g = 1.0;
- }
- else {
- outcol.g = tmp;
- }
- }
- if (outcol.b != 0.0) {
- float tmp = 1.0 - fac * col2.b;
- if (tmp <= 0.0) {
- outcol.b = 1.0;
- }
- else if ((tmp = outcol.b / tmp) > 1.0) {
- outcol.b = 1.0;
- }
- else {
- outcol.b = tmp;
- }
- }
-}
-
-void mix_burn(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- float tmp, facm = 1.0 - fac;
-
- outcol = col1;
-
- tmp = facm + fac * col2.r;
- if (tmp <= 0.0) {
- outcol.r = 0.0;
- }
- else if ((tmp = (1.0 - (1.0 - outcol.r) / tmp)) < 0.0) {
- outcol.r = 0.0;
- }
- else if (tmp > 1.0) {
- outcol.r = 1.0;
- }
- else {
- outcol.r = tmp;
- }
-
- tmp = facm + fac * col2.g;
- if (tmp <= 0.0) {
- outcol.g = 0.0;
- }
- else if ((tmp = (1.0 - (1.0 - outcol.g) / tmp)) < 0.0) {
- outcol.g = 0.0;
- }
- else if (tmp > 1.0) {
- outcol.g = 1.0;
- }
- else {
- outcol.g = tmp;
- }
-
- tmp = facm + fac * col2.b;
- if (tmp <= 0.0) {
- outcol.b = 0.0;
- }
- else if ((tmp = (1.0 - (1.0 - outcol.b) / tmp)) < 0.0) {
- outcol.b = 0.0;
- }
- else if (tmp > 1.0) {
- outcol.b = 1.0;
- }
- else {
- outcol.b = tmp;
- }
-}
-
-void mix_hue(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- float facm = 1.0 - fac;
-
- outcol = col1;
-
- vec4 hsv, hsv2, tmp;
- rgb_to_hsv(col2, hsv2);
-
- if (hsv2.y != 0.0) {
- rgb_to_hsv(outcol, hsv);
- hsv.x = hsv2.x;
- hsv_to_rgb(hsv, tmp);
-
- outcol = mix(outcol, tmp, fac);
- outcol.a = col1.a;
- }
-}
-
-void mix_sat(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- float facm = 1.0 - fac;
-
- outcol = col1;
-
- vec4 hsv, hsv2;
- rgb_to_hsv(outcol, hsv);
-
- if (hsv.y != 0.0) {
- rgb_to_hsv(col2, hsv2);
-
- hsv.y = facm * hsv.y + fac * hsv2.y;
- hsv_to_rgb(hsv, outcol);
- }
-}
-
-void mix_val(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- float facm = 1.0 - fac;
-
- vec4 hsv, hsv2;
- rgb_to_hsv(col1, hsv);
- rgb_to_hsv(col2, hsv2);
-
- hsv.z = facm * hsv.z + fac * hsv2.z;
- hsv_to_rgb(hsv, outcol);
-}
-
-void mix_color(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- float facm = 1.0 - fac;
-
- outcol = col1;
-
- vec4 hsv, hsv2, tmp;
- rgb_to_hsv(col2, hsv2);
-
- if (hsv2.y != 0.0) {
- rgb_to_hsv(outcol, hsv);
- hsv.x = hsv2.x;
- hsv.y = hsv2.y;
- hsv_to_rgb(hsv, tmp);
-
- outcol = mix(outcol, tmp, fac);
- outcol.a = col1.a;
- }
-}
-
-void mix_soft(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- float facm = 1.0 - fac;
-
- vec4 one = vec4(1.0);
- vec4 scr = one - (one - col2) * (one - col1);
- outcol = facm * col1 + fac * ((one - col1) * col2 * col1 + col1 * scr);
-}
-
-void mix_linear(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
-
- outcol = col1 + fac * (2.0 * (col2 - vec4(0.5)));
-}
-
-void valtorgb_opti_constant(
- float fac, float edge, vec4 color1, vec4 color2, out vec4 outcol, out float outalpha)
-{
- outcol = (fac > edge) ? color2 : color1;
- outalpha = outcol.a;
-}
-
-void valtorgb_opti_linear(
- float fac, vec2 mulbias, vec4 color1, vec4 color2, out vec4 outcol, out float outalpha)
-{
- fac = clamp(fac * mulbias.x + mulbias.y, 0.0, 1.0);
- outcol = mix(color1, color2, fac);
- outalpha = outcol.a;
-}
-
-void valtorgb(float fac, sampler1DArray colormap, float layer, out vec4 outcol, out float outalpha)
-{
- outcol = texture(colormap, vec2(fac, layer));
- outalpha = outcol.a;
-}
-
-void valtorgb_nearest(
- float fac, sampler1DArray colormap, float layer, out vec4 outcol, out float outalpha)
-{
- fac = clamp(fac, 0.0, 1.0);
- outcol = texelFetch(colormap, ivec2(fac * (textureSize(colormap, 0).x - 1), layer), 0);
- outalpha = outcol.a;
-}
-
-void rgbtobw(vec4 color, out float outval)
-{
- vec3 factors = vec3(0.2126, 0.7152, 0.0722);
- outval = dot(color.rgb, factors);
-}
-
-void invert(float fac, vec4 col, out vec4 outcol)
-{
- outcol.xyz = mix(col.xyz, vec3(1.0) - col.xyz, fac);
- outcol.w = col.w;
-}
-
-void clamp_vec3(vec3 vec, vec3 min, vec3 max, out vec3 out_vec)
-{
- out_vec = clamp(vec, min, max);
-}
-
-void clamp_value(float value, float min, float max, out float result)
-{
- result = clamp(value, min, max);
-}
-
-void hue_sat(float hue, float sat, float value, float fac, vec4 col, out vec4 outcol)
-{
- vec4 hsv;
-
- rgb_to_hsv(col, hsv);
-
- hsv[0] = fract(hsv[0] + hue + 0.5);
- hsv[1] = clamp(hsv[1] * sat, 0.0, 1.0);
- hsv[2] = hsv[2] * value;
-
- hsv_to_rgb(hsv, outcol);
-
- outcol = mix(col, outcol, fac);
-}
-
-void separate_rgb(vec4 col, out float r, out float g, out float b)
-{
- r = col.r;
- g = col.g;
- b = col.b;
-}
-
-void combine_rgb(float r, float g, float b, out vec4 col)
-{
- col = vec4(r, g, b, 1.0);
-}
-
-void separate_xyz(vec3 vec, out float x, out float y, out float z)
-{
- x = vec.r;
- y = vec.g;
- z = vec.b;
-}
-
-void combine_xyz(float x, float y, float z, out vec3 vec)
-{
- vec = vec3(x, y, z);
-}
-
-void separate_hsv(vec4 col, out float h, out float s, out float v)
-{
- vec4 hsv;
-
- rgb_to_hsv(col, hsv);
- h = hsv[0];
- s = hsv[1];
- v = hsv[2];
-}
-
-void combine_hsv(float h, float s, float v, out vec4 col)
-{
- hsv_to_rgb(vec4(h, s, v, 1.0), col);
-}
-
-void output_node(vec4 rgb, float alpha, out vec4 outrgb)
-{
- outrgb = vec4(rgb.rgb, alpha);
-}
-
-/*********** TEXTURES ***************/
-
-void texco_norm(vec3 normal, out vec3 outnormal)
-{
- /* corresponds to shi->orn, which is negated so cancels
- out blender normal negation */
- outnormal = normalize(normal);
-}
-
-vec3 mtex_2d_mapping(vec3 vec)
-{
- return vec3(vec.xy * 0.5 + vec2(0.5), vec.z);
-}
-
-/** helper method to extract the upper left 3x3 matrix from a 4x4 matrix */
-mat3 to_mat3(mat4 m4)
-{
- mat3 m3;
- m3[0] = m4[0].xyz;
- m3[1] = m4[1].xyz;
- m3[2] = m4[2].xyz;
- return m3;
-}
-
-/*********** NEW SHADER UTILITIES **************/
-
-float fresnel_dielectric_0(float eta)
-{
- /* compute fresnel reflactance at normal incidence => cosi = 1.0 */
- float A = (eta - 1.0) / (eta + 1.0);
-
- return A * A;
-}
-
-float fresnel_dielectric_cos(float cosi, float eta)
-{
- /* compute fresnel reflectance without explicitly computing
- * the refracted direction */
- float c = abs(cosi);
- float g = eta * eta - 1.0 + c * c;
- float result;
-
- if (g > 0.0) {
- g = sqrt(g);
- float A = (g - c) / (g + c);
- float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0);
- result = 0.5 * A * A * (1.0 + B * B);
- }
- else {
- result = 1.0; /* TIR (no refracted component) */
- }
-
- return result;
-}
-
-float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
-{
- /* compute fresnel reflectance without explicitly computing
- * the refracted direction */
- return fresnel_dielectric_cos(dot(Incoming, Normal), eta);
-}
-
-float hypot(float x, float y)
-{
- return sqrt(x * x + y * y);
-}
-
-void generated_from_orco(vec3 orco, out vec3 generated)
-{
-#ifdef VOLUMETRICS
-# ifdef MESH_SHADER
- generated = volumeObjectLocalCoord;
-# else
- generated = worldPosition;
-# endif
-#else
- generated = orco;
-#endif
-}
-
-int floor_to_int(float x)
-{
- return int(floor(x));
-}
-
-int quick_floor(float x)
-{
- return int(x) - ((x < 0) ? 1 : 0);
-}
-
-float integer_noise(int n)
-{
- int nn;
- n = (n + 1013) & 0x7fffffff;
- n = (n >> 13) ^ n;
- nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
- return 0.5 * (float(nn) / 1073741824.0);
-}
-
-/* ***** Jenkins Lookup3 Hash Functions ***** */
-
-/* Source: http://burtleburtle.net/bob/c/lookup3.c */
-
-#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
-
-#define mix(a, b, c) \
- { \
- a -= c; \
- a ^= rot(c, 4); \
- c += b; \
- b -= a; \
- b ^= rot(a, 6); \
- a += c; \
- c -= b; \
- c ^= rot(b, 8); \
- b += a; \
- a -= c; \
- a ^= rot(c, 16); \
- c += b; \
- b -= a; \
- b ^= rot(a, 19); \
- a += c; \
- c -= b; \
- c ^= rot(b, 4); \
- b += a; \
- }
-
-#define final(a, b, c) \
- { \
- c ^= b; \
- c -= rot(b, 14); \
- a ^= c; \
- a -= rot(c, 11); \
- b ^= a; \
- b -= rot(a, 25); \
- c ^= b; \
- c -= rot(b, 16); \
- a ^= c; \
- a -= rot(c, 4); \
- b ^= a; \
- b -= rot(a, 14); \
- c ^= b; \
- c -= rot(b, 24); \
- }
-
-uint hash_uint(uint kx)
-{
- uint a, b, c;
- a = b = c = 0xdeadbeefu + (1u << 2u) + 13u;
-
- a += kx;
- final(a, b, c);
-
- return c;
-}
-
-uint hash_uint2(uint kx, uint ky)
-{
- uint a, b, c;
- a = b = c = 0xdeadbeefu + (2u << 2u) + 13u;
-
- b += ky;
- a += kx;
- final(a, b, c);
-
- return c;
-}
-
-uint hash_uint3(uint kx, uint ky, uint kz)
-{
- uint a, b, c;
- a = b = c = 0xdeadbeefu + (3u << 2u) + 13u;
-
- c += kz;
- b += ky;
- a += kx;
- final(a, b, c);
-
- return c;
-}
-
-uint hash_uint4(uint kx, uint ky, uint kz, uint kw)
-{
- uint a, b, c;
- a = b = c = 0xdeadbeefu + (4u << 2u) + 13u;
-
- a += kx;
- b += ky;
- c += kz;
- mix(a, b, c);
-
- a += kw;
- final(a, b, c);
-
- return c;
-}
-
-#undef rot
-#undef final
-#undef mix
-
-uint hash_int(int kx)
-{
- return hash_uint(uint(kx));
-}
-
-uint hash_int2(int kx, int ky)
-{
- return hash_uint2(uint(kx), uint(ky));
-}
-
-uint hash_int3(int kx, int ky, int kz)
-{
- return hash_uint3(uint(kx), uint(ky), uint(kz));
-}
-
-uint hash_int4(int kx, int ky, int kz, int kw)
-{
- return hash_uint4(uint(kx), uint(ky), uint(kz), uint(kw));
-}
-
-/* Hashing uint or uint[234] into a float in the range [0, 1]. */
-
-float hash_uint_to_float(uint kx)
-{
- return float(hash_uint(kx)) / float(0xFFFFFFFFu);
-}
-
-float hash_uint2_to_float(uint kx, uint ky)
-{
- return float(hash_uint2(kx, ky)) / float(0xFFFFFFFFu);
-}
-
-float hash_uint3_to_float(uint kx, uint ky, uint kz)
-{
- return float(hash_uint3(kx, ky, kz)) / float(0xFFFFFFFFu);
-}
-
-float hash_uint4_to_float(uint kx, uint ky, uint kz, uint kw)
-{
- return float(hash_uint4(kx, ky, kz, kw)) / float(0xFFFFFFFFu);
-}
-
-/* Hashing float or vec[234] into a float in the range [0, 1]. */
-
-float hash_float_to_float(float k)
-{
- return hash_uint_to_float(floatBitsToUint(k));
-}
-
-float hash_vec2_to_float(vec2 k)
-{
- return hash_uint2_to_float(floatBitsToUint(k.x), floatBitsToUint(k.y));
-}
-
-float hash_vec3_to_float(vec3 k)
-{
- return hash_uint3_to_float(floatBitsToUint(k.x), floatBitsToUint(k.y), floatBitsToUint(k.z));
-}
-
-float hash_vec4_to_float(vec4 k)
-{
- return hash_uint4_to_float(
- floatBitsToUint(k.x), floatBitsToUint(k.y), floatBitsToUint(k.z), floatBitsToUint(k.w));
-}
-
-/* Hashing vec[234] into vec[234] of components in the range [0, 1]. */
-
-vec2 hash_vec2_to_vec2(vec2 k)
-{
- return vec2(hash_vec2_to_float(k), hash_vec3_to_float(vec3(k, 1.0)));
-}
-
-vec3 hash_vec3_to_vec3(vec3 k)
-{
- return vec3(
- hash_vec3_to_float(k), hash_vec4_to_float(vec4(k, 1.0)), hash_vec4_to_float(vec4(k, 2.0)));
-}
-
-vec4 hash_vec4_to_vec4(vec4 k)
-{
- return vec4(hash_vec4_to_float(k.xyzw),
- hash_vec4_to_float(k.wxyz),
- hash_vec4_to_float(k.zwxy),
- hash_vec4_to_float(k.yzwx));
-}
-
-/* Hashing float or vec[234] into vec3 of components in range [0, 1]. */
-
-vec3 hash_float_to_vec3(float k)
-{
- return vec3(
- hash_float_to_float(k), hash_vec2_to_float(vec2(k, 1.0)), hash_vec2_to_float(vec2(k, 2.0)));
-}
-
-vec3 hash_vec2_to_vec3(vec2 k)
-{
- return vec3(
- hash_vec2_to_float(k), hash_vec3_to_float(vec3(k, 1.0)), hash_vec3_to_float(vec3(k, 2.0)));
-}
-
-vec3 hash_vec4_to_vec3(vec4 k)
-{
- return vec3(hash_vec4_to_float(k.xyzw), hash_vec4_to_float(k.zxwy), hash_vec4_to_float(k.wzyx));
-}
-
-/* White Noise */
-
-void node_white_noise_1d(vec3 vector, float w, out float value)
-{
- value = hash_float_to_float(w);
-}
-
-void node_white_noise_2d(vec3 vector, float w, out float value)
-{
- value = hash_vec2_to_float(vector.xy);
-}
-
-void node_white_noise_3d(vec3 vector, float w, out float value)
-{
- value = hash_vec3_to_float(vector);
-}
-
-void node_white_noise_4d(vec3 vector, float w, out float value)
-{
- value = hash_vec4_to_float(vec4(vector, w));
-}
-
-/* Cell Noise */
-
-float bits_to_01(uint bits)
-{
- return (float(bits) / 4294967295.0);
-}
-
-float cellnoise(vec3 p)
-{
- int ix = quick_floor(p.x);
- int iy = quick_floor(p.y);
- int iz = quick_floor(p.z);
-
- return hash_uint3_to_float(uint(ix), uint(iy), uint(iz));
-}
-
-vec3 cellnoise_color(vec3 p)
-{
- float r = cellnoise(p.xyz);
- float g = cellnoise(p.yxz);
- float b = cellnoise(p.yzx);
-
- return vec3(r, g, b);
-}
-
-float floorfrac(float x, out int i)
-{
- float x_floor = floor(x);
- i = int(x_floor);
- return x - x_floor;
-}
-
-/* bsdfs */
-
-vec3 tint_from_color(vec3 color)
-{
- float lum = dot(color, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
- return (lum > 0) ? color / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */
-}
-
-void convert_metallic_to_specular_tinted(vec3 basecol,
- vec3 basecol_tint,
- float metallic,
- float specular_fac,
- float specular_tint,
- out vec3 diffuse,
- out vec3 f0)
-{
- vec3 tmp_col = mix(vec3(1.0), basecol_tint, specular_tint);
- f0 = mix((0.08 * specular_fac) * tmp_col, basecol, metallic);
- diffuse = basecol * (1.0 - metallic);
-}
-
-vec3 principled_sheen(float NV, vec3 basecol_tint, float sheen_tint)
-{
- float f = 1.0 - NV;
- /* Temporary fix for T59784. Normal map seems to contain NaNs for tangent space normal maps,
- * therefore we need to clamp value. */
- f = clamp(f, 0.0, 1.0);
- /* Empirical approximation (manual curve fitting). Can be refined. */
- float sheen = f * f * f * 0.077 + f * 0.01 + 0.00026;
- return sheen * mix(vec3(1.0), basecol_tint, sheen_tint);
-}
-
-#ifndef VOLUMETRICS
-void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
-{
- N = normalize(N);
- result = CLOSURE_DEFAULT;
- eevee_closure_diffuse(N, color.rgb, 1.0, result.radiance);
- closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
- result.radiance *= color.rgb;
-}
-
-void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Closure result)
-{
- N = normalize(N);
- vec3 out_spec, ssr_spec;
- eevee_closure_glossy(N, vec3(1.0), vec3(1.0), int(ssr_id), roughness, 1.0, out_spec, ssr_spec);
- vec3 vN = mat3(ViewMatrix) * N;
- result = CLOSURE_DEFAULT;
- result.radiance = out_spec * color.rgb;
- closure_load_ssr_data(ssr_spec * color.rgb, roughness, N, viewCameraVec, int(ssr_id), result);
-}
-
-void node_bsdf_anisotropic(vec4 color,
- float roughness,
- float anisotropy,
- float rotation,
- vec3 N,
- vec3 T,
- out Closure result)
-{
- node_bsdf_glossy(color, roughness, N, -1, result);
-}
-
-void node_bsdf_glass(
- vec4 color, float roughness, float ior, vec3 N, float ssr_id, out Closure result)
-{
- N = normalize(N);
- vec3 out_spec, out_refr, ssr_spec;
- vec3 refr_color = (refractionDepth > 0.0) ? color.rgb * color.rgb :
- color.rgb; /* Simulate 2 transmission event */
- eevee_closure_glass(
- N, vec3(1.0), vec3(1.0), int(ssr_id), roughness, 1.0, ior, out_spec, out_refr, ssr_spec);
- out_refr *= refr_color;
- out_spec *= color.rgb;
- float fresnel = F_eta(ior, dot(N, cameraVec));
- vec3 vN = mat3(ViewMatrix) * N;
- result = CLOSURE_DEFAULT;
- result.radiance = mix(out_refr, out_spec, fresnel);
- closure_load_ssr_data(
- ssr_spec * color.rgb * fresnel, roughness, N, viewCameraVec, int(ssr_id), result);
-}
-
-void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure result)
-{
- node_bsdf_diffuse(color, 0.0, N, result);
-}
-
-void node_bsdf_principled(vec4 base_color,
- float subsurface,
- vec3 subsurface_radius,
- vec4 subsurface_color,
- float metallic,
- float specular,
- float specular_tint,
- float roughness,
- float anisotropic,
- float anisotropic_rotation,
- float sheen,
- float sheen_tint,
- float clearcoat,
- float clearcoat_roughness,
- float ior,
- float transmission,
- float transmission_roughness,
- vec4 emission,
- float alpha,
- vec3 N,
- vec3 CN,
- vec3 T,
- vec3 I,
- float ssr_id,
- float sss_id,
- vec3 sss_scale,
- out Closure result)
-{
- N = normalize(N);
- ior = max(ior, 1e-5);
- metallic = saturate(metallic);
- transmission = saturate(transmission);
- float dielectric = 1.0 - metallic;
- transmission *= dielectric;
- sheen *= dielectric;
- subsurface_color *= dielectric;
-
- vec3 diffuse, f0, out_diff, out_spec, out_trans, out_refr, ssr_spec;
- vec3 ctint = tint_from_color(base_color.rgb);
- convert_metallic_to_specular_tinted(
- base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
-
- float NV = dot(N, cameraVec);
- vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
-
- /* Far from being accurate, but 2 glossy evaluation is too expensive.
- * Most noticeable difference is at grazing angles since the bsdf lut
- * f0 color interpolation is done on top of this interpolation. */
- vec3 f0_glass = mix(vec3(1.0), base_color.rgb, specular_tint);
- float fresnel = F_eta(ior, NV);
- vec3 spec_col = F_color_blend(ior, fresnel, f0_glass) * fresnel;
- f0 = mix(f0, spec_col, transmission);
-
- vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic);
-
- vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
-
- float sss_scalef = avg(sss_scale) * subsurface;
- eevee_closure_principled(N,
- mixed_ss_base_color,
- f0,
- f90,
- int(ssr_id),
- roughness,
- CN,
- clearcoat * 0.25,
- clearcoat_roughness,
- 1.0,
- sss_scalef,
- ior,
- out_diff,
- out_trans,
- out_spec,
- out_refr,
- ssr_spec);
-
- vec3 refr_color = base_color.rgb;
- refr_color *= (refractionDepth > 0.0) ? refr_color :
- vec3(1.0); /* Simulate 2 transmission event */
- out_refr *= refr_color * (1.0 - fresnel) * transmission;
-
- result = CLOSURE_DEFAULT;
- result.radiance = out_spec + out_refr;
- result.radiance += out_diff * out_sheen; /* Coarse approx. */
-
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
-
- vec3 sss_radiance = (out_diff + out_trans) * alpha;
-# ifndef USE_SSS
- result.radiance += sss_radiance * mixed_ss_base_color * (1.0 - transmission);
-# else
-# ifdef USE_SSS_ALBEDO
- vec3 sss_albedo = mixed_ss_base_color;
-# else
- sss_radiance *= mixed_ss_base_color;
-# endif
- sss_radiance *= (1.0 - transmission);
- closure_load_sss_data(sss_scalef,
- sss_radiance,
-# ifdef USE_SSS_ALBEDO
- sss_albedo,
-# endif
- int(sss_id),
- result);
-# endif /* USE_SSS */
-
- result.radiance += emission.rgb;
- result.radiance *= alpha;
- result.transmittance = vec3(1.0 - alpha);
-}
-
-void node_bsdf_principled_dielectric(vec4 base_color,
- float subsurface,
- vec3 subsurface_radius,
- vec4 subsurface_color,
- float metallic,
- float specular,
- float specular_tint,
- float roughness,
- float anisotropic,
- float anisotropic_rotation,
- float sheen,
- float sheen_tint,
- float clearcoat,
- float clearcoat_roughness,
- float ior,
- float transmission,
- float transmission_roughness,
- vec4 emission,
- float alpha,
- vec3 N,
- vec3 CN,
- vec3 T,
- vec3 I,
- float ssr_id,
- float sss_id,
- vec3 sss_scale,
- out Closure result)
-{
- N = normalize(N);
- metallic = saturate(metallic);
- float dielectric = 1.0 - metallic;
-
- vec3 diffuse, f0, out_diff, out_spec, ssr_spec;
- vec3 ctint = tint_from_color(base_color.rgb);
- convert_metallic_to_specular_tinted(
- base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
-
- float NV = dot(N, cameraVec);
- vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
-
- eevee_closure_default(
- N, diffuse, f0, vec3(1.0), int(ssr_id), roughness, 1.0, out_diff, out_spec, ssr_spec);
-
- result = CLOSURE_DEFAULT;
- result.radiance = out_spec + out_diff * (diffuse + out_sheen);
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
- result.radiance += emission.rgb;
- result.radiance *= alpha;
- result.transmittance = vec3(1.0 - alpha);
-}
-
-void node_bsdf_principled_metallic(vec4 base_color,
- float subsurface,
- vec3 subsurface_radius,
- vec4 subsurface_color,
- float metallic,
- float specular,
- float specular_tint,
- float roughness,
- float anisotropic,
- float anisotropic_rotation,
- float sheen,
- float sheen_tint,
- float clearcoat,
- float clearcoat_roughness,
- float ior,
- float transmission,
- float transmission_roughness,
- vec4 emission,
- float alpha,
- vec3 N,
- vec3 CN,
- vec3 T,
- vec3 I,
- float ssr_id,
- float sss_id,
- vec3 sss_scale,
- out Closure result)
-{
- N = normalize(N);
- vec3 out_spec, ssr_spec;
-
- vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
-
- eevee_closure_glossy(N, base_color.rgb, f90, int(ssr_id), roughness, 1.0, out_spec, ssr_spec);
-
- result = CLOSURE_DEFAULT;
- result.radiance = out_spec;
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
- result.radiance += emission.rgb;
- result.radiance *= alpha;
- result.transmittance = vec3(1.0 - alpha);
-}
-
-void node_bsdf_principled_clearcoat(vec4 base_color,
- float subsurface,
- vec3 subsurface_radius,
- vec4 subsurface_color,
- float metallic,
- float specular,
- float specular_tint,
- float roughness,
- float anisotropic,
- float anisotropic_rotation,
- float sheen,
- float sheen_tint,
- float clearcoat,
- float clearcoat_roughness,
- float ior,
- float transmission,
- float transmission_roughness,
- vec4 emission,
- float alpha,
- vec3 N,
- vec3 CN,
- vec3 T,
- vec3 I,
- float ssr_id,
- float sss_id,
- vec3 sss_scale,
- out Closure result)
-{
- vec3 out_spec, ssr_spec;
- N = normalize(N);
-
- vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
-
- eevee_closure_clearcoat(N,
- base_color.rgb,
- f90,
- int(ssr_id),
- roughness,
- CN,
- clearcoat * 0.25,
- clearcoat_roughness,
- 1.0,
- out_spec,
- ssr_spec);
-
- result = CLOSURE_DEFAULT;
- result.radiance = out_spec;
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
- result.radiance += emission.rgb;
- result.radiance *= alpha;
- result.transmittance = vec3(1.0 - alpha);
-}
-
-void node_bsdf_principled_subsurface(vec4 base_color,
- float subsurface,
- vec3 subsurface_radius,
- vec4 subsurface_color,
- float metallic,
- float specular,
- float specular_tint,
- float roughness,
- float anisotropic,
- float anisotropic_rotation,
- float sheen,
- float sheen_tint,
- float clearcoat,
- float clearcoat_roughness,
- float ior,
- float transmission,
- float transmission_roughness,
- vec4 emission,
- float alpha,
- vec3 N,
- vec3 CN,
- vec3 T,
- vec3 I,
- float ssr_id,
- float sss_id,
- vec3 sss_scale,
- out Closure result)
-{
- metallic = saturate(metallic);
- N = normalize(N);
-
- vec3 diffuse, f0, out_diff, out_spec, out_trans, ssr_spec;
- vec3 ctint = tint_from_color(base_color.rgb);
- convert_metallic_to_specular_tinted(
- base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
-
- subsurface_color = subsurface_color * (1.0 - metallic);
- vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
- float sss_scalef = avg(sss_scale) * subsurface;
-
- float NV = dot(N, cameraVec);
- vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
-
- vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
-
- eevee_closure_skin(N,
- mixed_ss_base_color,
- f0,
- f90,
- int(ssr_id),
- roughness,
- 1.0,
- sss_scalef,
- out_diff,
- out_trans,
- out_spec,
- ssr_spec);
-
- result = CLOSURE_DEFAULT;
- result.radiance = out_spec;
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
-
- vec3 sss_radiance = (out_diff + out_trans) * alpha;
-# ifndef USE_SSS
- result.radiance += sss_radiance * mixed_ss_base_color * (1.0 - transmission);
-# else
-# ifdef USE_SSS_ALBEDO
- vec3 sss_albedo = mixed_ss_base_color;
-# else
- sss_radiance *= mixed_ss_base_color;
-# endif
- sss_radiance *= (1.0 - transmission);
- closure_load_sss_data(sss_scalef,
- sss_radiance,
-# ifdef USE_SSS_ALBEDO
- sss_albedo,
-# endif
- int(sss_id),
- result);
-# endif /* USE_SSS */
-
- result.radiance += out_diff * out_sheen;
- result.radiance += emission.rgb;
- result.radiance *= alpha;
- result.transmittance = vec3(1.0 - alpha);
-}
-
-void node_bsdf_principled_glass(vec4 base_color,
- float subsurface,
- vec3 subsurface_radius,
- vec4 subsurface_color,
- float metallic,
- float specular,
- float specular_tint,
- float roughness,
- float anisotropic,
- float anisotropic_rotation,
- float sheen,
- float sheen_tint,
- float clearcoat,
- float clearcoat_roughness,
- float ior,
- float transmission,
- float transmission_roughness,
- vec4 emission,
- float alpha,
- vec3 N,
- vec3 CN,
- vec3 T,
- vec3 I,
- float ssr_id,
- float sss_id,
- vec3 sss_scale,
- out Closure result)
-{
- ior = max(ior, 1e-5);
- N = normalize(N);
-
- vec3 f0, out_spec, out_refr, ssr_spec;
- f0 = mix(vec3(1.0), base_color.rgb, specular_tint);
-
- eevee_closure_glass(
- N, vec3(1.0), vec3(1.0), int(ssr_id), roughness, 1.0, ior, out_spec, out_refr, ssr_spec);
-
- vec3 refr_color = base_color.rgb;
- refr_color *= (refractionDepth > 0.0) ? refr_color :
- vec3(1.0); /* Simulate 2 transmission events */
- out_refr *= refr_color;
-
- float fresnel = F_eta(ior, dot(N, cameraVec));
- vec3 spec_col = F_color_blend(ior, fresnel, f0);
- out_spec *= spec_col;
- ssr_spec *= spec_col * fresnel;
-
- result = CLOSURE_DEFAULT;
- result.radiance = mix(out_refr, out_spec, fresnel);
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
- result.radiance += emission.rgb;
- result.radiance *= alpha;
- result.transmittance = vec3(1.0 - alpha);
-}
-
-void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
-{
- node_bsdf_diffuse(color, 0.0, -N, result);
-}
-
-void node_bsdf_transparent(vec4 color, out Closure result)
-{
- result = CLOSURE_DEFAULT;
- result.radiance = vec3(0.0);
- result.transmittance = abs(color.rgb);
-}
-
-void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out Closure result)
-{
- node_bsdf_diffuse(color, 0.0, N, result);
-}
-
-void node_subsurface_scattering(vec4 color,
- float scale,
- vec3 radius,
- float sharpen,
- float texture_blur,
- vec3 N,
- float sss_id,
- out Closure result)
-{
-# if defined(USE_SSS)
- N = normalize(N);
- vec3 out_diff, out_trans;
- vec3 vN = mat3(ViewMatrix) * N;
- result = CLOSURE_DEFAULT;
- closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
-
- eevee_closure_subsurface(N, color.rgb, 1.0, scale, out_diff, out_trans);
-
- vec3 sss_radiance = out_diff + out_trans;
-# ifdef USE_SSS_ALBEDO
- /* Not perfect for texture_blur not exactly equal to 0.0 or 1.0. */
- vec3 sss_albedo = mix(color.rgb, vec3(1.0), texture_blur);
- sss_radiance *= mix(vec3(1.0), color.rgb, texture_blur);
-# else
- sss_radiance *= color.rgb;
-# endif
- closure_load_sss_data(scale,
- sss_radiance,
-# ifdef USE_SSS_ALBEDO
- sss_albedo,
-# endif
- int(sss_id),
- result);
-# else
- node_bsdf_diffuse(color, 0.0, N, result);
-# endif
-}
-
-void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Closure result)
-{
- N = normalize(N);
- vec3 out_refr;
- color.rgb *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); /* Simulate 2 absorption event. */
- eevee_closure_refraction(N, roughness, ior, out_refr);
- vec3 vN = mat3(ViewMatrix) * N;
- result = CLOSURE_DEFAULT;
- result.ssr_normal = normal_encode(vN, viewCameraVec);
- result.radiance = out_refr * color.rgb;
-}
-
-void node_ambient_occlusion(
- vec4 color, float distance, vec3 normal, out vec4 result_color, out float result_ao)
-{
- vec3 bent_normal;
- vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0);
- result_ao = occlusion_compute(normalize(normal), viewPosition, 1.0, rand, bent_normal);
- result_color = result_ao * color;
-}
-
-void node_wireframe(float size, vec2 barycentric, vec3 barycentric_dist, out float fac)
-{
- vec3 barys = barycentric.xyy;
- barys.z = 1.0 - barycentric.x - barycentric.y;
-
- size *= 0.5;
- vec3 s = step(-size, -barys * barycentric_dist);
-
- fac = max(s.x, max(s.y, s.z));
-}
-
-void node_wireframe_screenspace(float size, vec2 barycentric, out float fac)
-{
- vec3 barys = barycentric.xyy;
- barys.z = 1.0 - barycentric.x - barycentric.y;
-
- size *= (1.0 / 3.0);
- vec3 dx = dFdx(barys);
- vec3 dy = dFdy(barys);
- vec3 deltas = sqrt(dx * dx + dy * dy);
-
- vec3 s = step(-deltas * size, -barys);
-
- fac = max(s.x, max(s.y, s.z));
-}
-
-#else /* VOLUMETRICS */
-
-/* Stub all bsdf functions not compatible with volumetrics. */
-# define node_bsdf_diffuse
-# define node_bsdf_glossy
-# define node_bsdf_anisotropic
-# define node_bsdf_glass
-# define node_bsdf_toon
-# define node_bsdf_principled
-# define node_bsdf_principled_dielectric
-# define node_bsdf_principled_metallic
-# define node_bsdf_principled_clearcoat
-# define node_bsdf_principled_subsurface
-# define node_bsdf_principled_glass
-# define node_bsdf_translucent
-# define node_bsdf_transparent
-# define node_bsdf_velvet
-# define node_subsurface_scattering
-# define node_bsdf_refraction
-# define node_ambient_occlusion
-# define node_wireframe
-# define node_wireframe_screenspace
-
-#endif /* VOLUMETRICS */
-
-/* emission */
-
-void node_emission(vec4 color, float strength, vec3 vN, out Closure result)
-{
- result = CLOSURE_DEFAULT;
-#ifndef VOLUMETRICS
- result.radiance = color.rgb * strength;
- result.ssr_normal = normal_encode(vN, viewCameraVec);
-#else
- result.emission = color.rgb * strength;
-#endif
-}
-
-/* background */
-
-void node_tex_environment_texco(vec3 viewvec, out vec3 worldvec)
-{
-#ifdef MESH_SHADER
- worldvec = worldPosition;
-#else
- vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(viewvec, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
- vec4 co_homogenous = (ProjectionMatrixInverse * v);
-
- vec3 co = co_homogenous.xyz / co_homogenous.w;
-# if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
- worldvec = mat3(ViewMatrixInverse) * co;
-# else
- worldvec = mat3(ModelMatrixInverse) * (mat3(ViewMatrixInverse) * co);
-# endif
-#endif
-}
-
-void node_background(vec4 color, float strength, out Closure result)
-{
-#ifndef VOLUMETRICS
- color *= strength;
- result = CLOSURE_DEFAULT;
- result.radiance = color.rgb;
- result.transmittance = vec3(0.0);
-#else
- result = CLOSURE_DEFAULT;
-#endif
-}
-
-/* volumes */
-
-void node_volume_scatter(vec4 color, float density, float anisotropy, out Closure result)
-{
-#ifdef VOLUMETRICS
- result = Closure(vec3(0.0), color.rgb * density, vec3(0.0), anisotropy);
-#else
- result = CLOSURE_DEFAULT;
-#endif
-}
-
-void node_volume_absorption(vec4 color, float density, out Closure result)
-{
-#ifdef VOLUMETRICS
- result = Closure((1.0 - color.rgb) * density, vec3(0.0), vec3(0.0), 0.0);
-#else
- result = CLOSURE_DEFAULT;
-#endif
-}
-
-void node_blackbody(float temperature, sampler1DArray spectrummap, float layer, out vec4 color)
-{
- if (temperature >= 12000.0) {
- color = vec4(0.826270103, 0.994478524, 1.56626022, 1.0);
- }
- else if (temperature < 965.0) {
- color = vec4(4.70366907, 0.0, 0.0, 1.0);
- }
- else {
- float t = (temperature - 965.0) / (12000.0 - 965.0);
- color = vec4(texture(spectrummap, vec2(t, layer)).rgb, 1.0);
- }
-}
-
-void node_volume_principled(vec4 color,
- float density,
- float anisotropy,
- vec4 absorption_color,
- float emission_strength,
- vec4 emission_color,
- float blackbody_intensity,
- vec4 blackbody_tint,
- float temperature,
- float density_attribute,
- vec4 color_attribute,
- float temperature_attribute,
- sampler1DArray spectrummap,
- float layer,
- out Closure result)
-{
-#ifdef VOLUMETRICS
- vec3 absorption_coeff = vec3(0.0);
- vec3 scatter_coeff = vec3(0.0);
- vec3 emission_coeff = vec3(0.0);
-
- /* Compute density. */
- density = max(density, 0.0);
-
- if (density > 1e-5) {
- density = max(density * density_attribute, 0.0);
- }
-
- if (density > 1e-5) {
- /* Compute scattering and absorption coefficients. */
- vec3 scatter_color = color.rgb * color_attribute.rgb;
-
- scatter_coeff = scatter_color * density;
- absorption_color.rgb = sqrt(max(absorption_color.rgb, 0.0));
- absorption_coeff = max(1.0 - scatter_color, 0.0) * max(1.0 - absorption_color.rgb, 0.0) *
- density;
- }
-
- /* Compute emission. */
- emission_strength = max(emission_strength, 0.0);
-
- if (emission_strength > 1e-5) {
- emission_coeff += emission_strength * emission_color.rgb;
- }
-
- if (blackbody_intensity > 1e-3) {
- /* Add temperature from attribute. */
- float T = max(temperature * max(temperature_attribute, 0.0), 0.0);
-
- /* Stefan-Boltzman law. */
- float T2 = T * T;
- float T4 = T2 * T2;
- float sigma = 5.670373e-8 * 1e-6 / M_PI;
- float intensity = sigma * mix(1.0, T4, blackbody_intensity);
-
- if (intensity > 1e-5) {
- vec4 bb;
- node_blackbody(T, spectrummap, layer, bb);
- emission_coeff += bb.rgb * blackbody_tint.rgb * intensity;
- }
- }
-
- result = Closure(absorption_coeff, scatter_coeff, emission_coeff, anisotropy);
-#else
- result = CLOSURE_DEFAULT;
-#endif
-}
-
-void node_holdout(out Closure result)
-{
- result = CLOSURE_DEFAULT;
-#ifndef VOLUMETRICS
- result.holdout = 1.0;
- result.flag = CLOSURE_HOLDOUT_FLAG;
-#endif
-}
-
-/* closures */
-
-void node_mix_shader(float fac, Closure shader1, Closure shader2, out Closure shader)
-{
- shader = closure_mix(shader1, shader2, fac);
-}
-
-void node_add_shader(Closure shader1, Closure shader2, out Closure shader)
-{
- shader = closure_add(shader1, shader2);
-}
-
-/* fresnel */
-
-void node_fresnel(float ior, vec3 N, vec3 I, out float result)
-{
- N = normalize(N);
- /* handle perspective/orthographic */
- vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
-
- float eta = max(ior, 0.00001);
- result = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? eta : 1.0 / eta);
-}
-
-/* layer_weight */
-
-void node_layer_weight(float blend, vec3 N, vec3 I, out float fresnel, out float facing)
-{
- N = normalize(N);
-
- /* fresnel */
- float eta = max(1.0 - blend, 0.00001);
- vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
-
- fresnel = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? 1.0 / eta : eta);
-
- /* facing */
- facing = abs(dot(I_view, N));
- if (blend != 0.5) {
- blend = clamp(blend, 0.0, 0.99999);
- blend = (blend < 0.5) ? 2.0 * blend : 0.5 / (1.0 - blend);
- facing = pow(facing, blend);
- }
- facing = 1.0 - facing;
-}
-
-/* gamma */
-
-void node_gamma(vec4 col, float gamma, out vec4 outcol)
-{
- outcol = col;
-
- if (col.r > 0.0) {
- outcol.r = compatible_pow(col.r, gamma);
- }
- if (col.g > 0.0) {
- outcol.g = compatible_pow(col.g, gamma);
- }
- if (col.b > 0.0) {
- outcol.b = compatible_pow(col.b, gamma);
- }
-}
-
-/* geometry */
-
-void node_attribute_volume_density(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
-{
-#if defined(MESH_SHADER) && defined(VOLUMETRICS)
- vec3 cos = volumeObjectLocalCoord;
-#else
- vec3 cos = vec3(0.0);
-#endif
- outvec = texture(tex, cos).aaa;
- outcol = vec4(outvec, 1.0);
- outf = avg(outvec);
-}
-
-uniform vec3 volumeColor = vec3(1.0);
-
-void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
-{
-#if defined(MESH_SHADER) && defined(VOLUMETRICS)
- vec3 cos = volumeObjectLocalCoord;
-#else
- vec3 cos = vec3(0.0);
-#endif
-
- vec4 value = texture(tex, cos).rgba;
- /* Density is premultiplied for interpolation, divide it out here. */
- if (value.a > 1e-8) {
- value.rgb /= value.a;
- }
-
- outvec = value.rgb * volumeColor;
- outcol = vec4(outvec, 1.0);
- outf = avg(outvec);
-}
-
-void node_attribute_volume_flame(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
-{
-#if defined(MESH_SHADER) && defined(VOLUMETRICS)
- vec3 cos = volumeObjectLocalCoord;
-#else
- vec3 cos = vec3(0.0);
-#endif
- outf = texture(tex, cos).r;
- outvec = vec3(outf, outf, outf);
- outcol = vec4(outf, outf, outf, 1.0);
-}
-
-void node_attribute_volume_temperature(
- sampler3D tex, vec2 temperature, out vec4 outcol, out vec3 outvec, out float outf)
-{
-#if defined(MESH_SHADER) && defined(VOLUMETRICS)
- vec3 cos = volumeObjectLocalCoord;
-#else
- vec3 cos = vec3(0.0);
-#endif
- float flame = texture(tex, cos).r;
-
- outf = (flame > 0.01) ? temperature.x + flame * (temperature.y - temperature.x) : 0.0;
- outvec = vec3(outf, outf, outf);
- outcol = vec4(outf, outf, outf, 1.0);
-}
-
-void node_volume_info(sampler3D densitySampler,
- sampler3D flameSampler,
- vec2 temperature,
- out vec4 outColor,
- out float outDensity,
- out float outFlame,
- out float outTemprature)
-{
-#if defined(MESH_SHADER) && defined(VOLUMETRICS)
- vec3 p = volumeObjectLocalCoord;
-#else
- vec3 p = vec3(0.0);
-#endif
-
- vec4 density = texture(densitySampler, p);
- outDensity = density.a;
-
- /* Density is premultiplied for interpolation, divide it out here. */
- if (density.a > 1e-8) {
- density.rgb /= density.a;
- }
- outColor = vec4(density.rgb * volumeColor, 1.0);
-
- float flame = texture(flameSampler, p).r;
- outFlame = flame;
-
- outTemprature = (flame > 0.01) ? temperature.x + flame * (temperature.y - temperature.x) : 0.0;
-}
-
-void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf)
-{
- outcol = vec4(attr, 1.0);
- outvec = attr;
- outf = avg(attr);
-}
-
-void node_uvmap(vec3 attr_uv, out vec3 outvec)
-{
- outvec = attr_uv;
-}
-
-void tangent_orco_x(vec3 orco_in, out vec3 orco_out)
-{
- orco_out = orco_in.xzy * vec3(0.0, -0.5, 0.5) + vec3(0.0, 0.25, -0.25);
-}
-
-void tangent_orco_y(vec3 orco_in, out vec3 orco_out)
-{
- orco_out = orco_in.zyx * vec3(-0.5, 0.0, 0.5) + vec3(0.25, 0.0, -0.25);
-}
-
-void tangent_orco_z(vec3 orco_in, out vec3 orco_out)
-{
- orco_out = orco_in.yxz * vec3(-0.5, 0.5, 0.0) + vec3(0.25, -0.25, 0.0);
-}
-
-void node_tangentmap(vec4 attr_tangent, out vec3 tangent)
-{
- tangent = normalize(attr_tangent.xyz);
-}
-
-void node_tangent(vec3 N, vec3 orco, mat4 objmat, out vec3 T)
-{
- T = (objmat * vec4(orco, 0.0)).xyz;
- T = cross(N, normalize(cross(T, N)));
-}
-
-void node_geometry(vec3 I,
- vec3 N,
- vec3 orco,
- mat4 objmat,
- mat4 toworld,
- vec2 barycentric,
- out vec3 position,
- out vec3 normal,
- out vec3 tangent,
- out vec3 true_normal,
- out vec3 incoming,
- out vec3 parametric,
- out float backfacing,
- out float pointiness)
-{
- /* handle perspective/orthographic */
- vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
- incoming = -(toworld * vec4(I_view, 0.0)).xyz;
-
-#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
- position = -incoming;
- true_normal = normal = incoming;
- tangent = parametric = vec3(0.0);
- vec3(0.0);
- backfacing = 0.0;
- pointiness = 0.0;
-#else
-
- position = worldPosition;
-# ifndef VOLUMETRICS
- normal = normalize(N);
- vec3 B = dFdx(worldPosition);
- vec3 T = dFdy(worldPosition);
- true_normal = normalize(cross(B, T));
-# else
- normal = (toworld * vec4(N, 0.0)).xyz;
- true_normal = normal;
-# endif
- tangent_orco_z(orco, orco);
- node_tangent(N, orco, objmat, tangent);
-
- parametric = vec3(barycentric, 0.0);
- backfacing = (gl_FrontFacing) ? 0.0 : 1.0;
- pointiness = 0.5;
-#endif
-}
-
-void generated_texco(vec3 I, vec3 attr_orco, out vec3 generated)
-{
- vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
- vec4 co_homogenous = (ProjectionMatrixInverse * v);
- vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0);
- co.xyz = normalize(co.xyz);
-#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
- generated = (ViewMatrixInverse * co).xyz;
-#else
- generated_from_orco(attr_orco, generated);
-#endif
-}
-
-void node_tex_coord(vec3 I,
- vec3 wN,
- mat4 obmatinv,
- vec4 camerafac,
- vec3 attr_orco,
- vec3 attr_uv,
- out vec3 generated,
- out vec3 normal,
- out vec3 uv,
- out vec3 object,
- out vec3 camera,
- out vec3 window,
- out vec3 reflection)
-{
- generated = attr_orco;
- normal = normalize(normal_world_to_object(wN));
- uv = attr_uv;
- object = (obmatinv * (ViewMatrixInverse * vec4(I, 1.0))).xyz;
- camera = vec3(I.xy, -I.z);
- vec4 projvec = ProjectionMatrix * vec4(I, 1.0);
- window = vec3(mtex_2d_mapping(projvec.xyz / projvec.w).xy * camerafac.xy + camerafac.zw, 0.0);
- reflection = -reflect(cameraVec, normalize(wN));
-}
-
-void node_tex_coord_background(vec3 I,
- vec3 N,
- mat4 obmatinv,
- vec4 camerafac,
- vec3 attr_orco,
- vec3 attr_uv,
- out vec3 generated,
- out vec3 normal,
- out vec3 uv,
- out vec3 object,
- out vec3 camera,
- out vec3 window,
- out vec3 reflection)
-{
- vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
- vec4 co_homogenous = (ProjectionMatrixInverse * v);
-
- vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0);
-
- co = normalize(co);
-
- vec3 coords = (ViewMatrixInverse * co).xyz;
-
- generated = coords;
- normal = -coords;
- uv = vec3(attr_uv.xy, 0.0);
- object = (obmatinv * vec4(coords, 1.0)).xyz;
-
- camera = vec3(co.xy, -co.z);
- window = vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0);
-
- reflection = -coords;
-}
-
-#if defined(WORLD_BACKGROUND) || (defined(PROBE_CAPTURE) && !defined(MESH_SHADER))
-# define node_tex_coord node_tex_coord_background
-#endif
-
-/* textures */
-
-float calc_gradient(vec3 p, int gradient_type)
-{
- float x, y, z;
- x = p.x;
- y = p.y;
- z = p.z;
- if (gradient_type == 0) { /* linear */
- return x;
- }
- else if (gradient_type == 1) { /* quadratic */
- float r = max(x, 0.0);
- return r * r;
- }
- else if (gradient_type == 2) { /* easing */
- float r = min(max(x, 0.0), 1.0);
- float t = r * r;
- return (3.0 * t - 2.0 * t * r);
- }
- else if (gradient_type == 3) { /* diagonal */
- return (x + y) * 0.5;
- }
- else if (gradient_type == 4) { /* radial */
- return atan(y, x) / (M_PI * 2) + 0.5;
- }
- else {
- /* Bias a little bit for the case where p is a unit length vector,
- * to get exactly zero instead of a small random value depending
- * on float precision. */
- float r = max(0.999999 - sqrt(x * x + y * y + z * z), 0.0);
- if (gradient_type == 5) { /* quadratic sphere */
- return r * r;
- }
- else if (gradient_type == 6) { /* sphere */
- return r;
- }
- }
- return 0.0;
-}
-
-void node_tex_gradient(vec3 co, float gradient_type, out vec4 color, out float fac)
-{
- float f = calc_gradient(co, int(gradient_type));
- f = clamp(f, 0.0, 1.0);
-
- color = vec4(f, f, f, 1.0);
- fac = f;
-}
-
-void node_tex_checker(
- vec3 co, vec4 color1, vec4 color2, float scale, out vec4 color, out float fac)
-{
- vec3 p = co * scale;
-
- /* Prevent precision issues on unit coordinates. */
- p = (p + 0.000001) * 0.999999;
-
- int xi = int(abs(floor(p.x)));
- int yi = int(abs(floor(p.y)));
- int zi = int(abs(floor(p.z)));
-
- bool check = ((mod(xi, 2) == mod(yi, 2)) == bool(mod(zi, 2)));
-
- color = check ? color1 : color2;
- fac = check ? 1.0 : 0.0;
-}
-
-vec2 calc_brick_texture(vec3 p,
- float mortar_size,
- float mortar_smooth,
- float bias,
- float brick_width,
- float row_height,
- float offset_amount,
- int offset_frequency,
- float squash_amount,
- int squash_frequency)
-{
- int bricknum, rownum;
- float offset = 0.0;
- float x, y;
-
- rownum = floor_to_int(p.y / row_height);
-
- if (offset_frequency != 0 && squash_frequency != 0) {
- brick_width *= (rownum % squash_frequency != 0) ? 1.0 : squash_amount; /* squash */
- offset = (rownum % offset_frequency != 0) ? 0.0 : (brick_width * offset_amount); /* offset */
- }
-
- bricknum = floor_to_int((p.x + offset) / brick_width);
-
- x = (p.x + offset) - brick_width * bricknum;
- y = p.y - row_height * rownum;
-
- float tint = clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0, 1.0);
-
- float min_dist = min(min(x, y), min(brick_width - x, row_height - y));
- if (min_dist >= mortar_size) {
- return vec2(tint, 0.0);
- }
- else if (mortar_smooth == 0.0) {
- return vec2(tint, 1.0);
- }
- else {
- min_dist = 1.0 - min_dist / mortar_size;
- return vec2(tint, smoothstep(0.0, mortar_smooth, min_dist));
- }
-}
-
-void node_tex_brick(vec3 co,
- vec4 color1,
- vec4 color2,
- vec4 mortar,
- float scale,
- float mortar_size,
- float mortar_smooth,
- float bias,
- float brick_width,
- float row_height,
- float offset_amount,
- float offset_frequency,
- float squash_amount,
- float squash_frequency,
- out vec4 color,
- out float fac)
-{
- vec2 f2 = calc_brick_texture(co * scale,
- mortar_size,
- mortar_smooth,
- bias,
- brick_width,
- row_height,
- offset_amount,
- int(offset_frequency),
- squash_amount,
- int(squash_frequency));
- float tint = f2.x;
- float f = f2.y;
- if (f != 1.0) {
- float facm = 1.0 - tint;
- color1 = facm * color1 + tint * color2;
- }
- color = mix(color1, mortar, f);
- fac = f;
-}
-
-void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac)
-{
- color = vec4(1.0);
- fac = 1.0;
-}
-
-void node_tex_environment_equirectangular(vec3 co, float clamp_size, sampler2D ima, out vec3 uv)
-{
- vec3 nco = normalize(co);
- uv.x = -atan(nco.y, nco.x) / (2.0 * M_PI) + 0.5;
- uv.y = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5;
-
- /* Fix pole bleeding */
- float half_height = clamp_size / float(textureSize(ima, 0).y);
- uv.y = clamp(uv.y, half_height, 1.0 - half_height);
- uv.z = 0.0;
-}
-
-void node_tex_environment_mirror_ball(vec3 co, out vec3 uv)
-{
- vec3 nco = normalize(co);
- nco.y -= 1.0;
-
- float div = 2.0 * sqrt(max(-0.5 * nco.y, 0.0));
- nco /= max(1e-8, div);
-
- uv = 0.5 * nco.xzz + 0.5;
-}
-
-void node_tex_environment_empty(vec3 co, out vec4 color)
-{
- color = vec4(1.0, 0.0, 1.0, 1.0);
-}
-
-/* 16bits floats limits. Higher/Lower values produce +/-inf. */
-#define safe_color(a) (clamp(a, -65520.0, 65520.0))
-
-void tex_color_alpha_clear(vec4 color, out vec4 result)
-{
- result = vec4(color.rgb, 1.0);
-}
-
-void tex_color_alpha_premultiply(vec4 color, out vec4 result)
-{
- result = vec4(color.rgb * color.a, 1.0);
-}
-
-void tex_color_alpha_unpremultiply(vec4 color, out vec4 result)
-{
- if (color.a == 0.0 || color.a == 1.0) {
- result = vec4(color.rgb, 1.0);
- }
- else {
- result = vec4(color.rgb / color.a, 1.0);
- }
-}
-
-void node_tex_image_linear(vec3 co, sampler2D ima, out vec4 color, out float alpha)
-{
- color = safe_color(texture(ima, co.xy));
- alpha = color.a;
-}
-
-void node_tex_image_linear_no_mip(vec3 co, sampler2D ima, out vec4 color, out float alpha)
-{
- color = safe_color(textureLod(ima, co.xy, 0.0));
- alpha = color.a;
-}
-
-void node_tex_image_nearest(vec3 co, sampler2D ima, out vec4 color, out float alpha)
-{
- ivec2 pix = ivec2(fract(co.xy) * textureSize(ima, 0).xy);
- color = safe_color(texelFetch(ima, pix, 0));
- alpha = color.a;
-}
-
-/* @arg f: signed distance to texel center. */
-void cubic_bspline_coefs(vec2 f, out vec2 w0, out vec2 w1, out vec2 w2, out vec2 w3)
-{
- vec2 f2 = f * f;
- vec2 f3 = f2 * f;
- /* Bspline coefs (optimized) */
- w3 = f3 / 6.0;
- w0 = -w3 + f2 * 0.5 - f * 0.5 + 1.0 / 6.0;
- w1 = f3 * 0.5 - f2 * 1.0 + 2.0 / 3.0;
- w2 = 1.0 - w0 - w1 - w3;
-}
-
-void node_tex_image_cubic_ex(
- vec3 co, sampler2D ima, float do_extend, out vec4 color, out float alpha)
-{
- vec2 tex_size = vec2(textureSize(ima, 0).xy);
-
- co.xy *= tex_size;
- /* texel center */
- vec2 tc = floor(co.xy - 0.5) + 0.5;
- vec2 w0, w1, w2, w3;
- cubic_bspline_coefs(co.xy - tc, w0, w1, w2, w3);
-
-#if 1 /* Optimized version using 4 filtered tap. */
- vec2 s0 = w0 + w1;
- vec2 s1 = w2 + w3;
-
- vec2 f0 = w1 / (w0 + w1);
- vec2 f1 = w3 / (w2 + w3);
-
- vec4 final_co;
- final_co.xy = tc - 1.0 + f0;
- final_co.zw = tc + 1.0 + f1;
-
- if (do_extend == 1.0) {
- final_co = clamp(final_co, vec4(0.5), tex_size.xyxy - 0.5);
- }
- final_co /= tex_size.xyxy;
-
- color = safe_color(textureLod(ima, final_co.xy, 0.0)) * s0.x * s0.y;
- color += safe_color(textureLod(ima, final_co.zy, 0.0)) * s1.x * s0.y;
- color += safe_color(textureLod(ima, final_co.xw, 0.0)) * s0.x * s1.y;
- color += safe_color(textureLod(ima, final_co.zw, 0.0)) * s1.x * s1.y;
-
-#else /* Reference bruteforce 16 tap. */
- color = texelFetch(ima, ivec2(tc + vec2(-1.0, -1.0)), 0) * w0.x * w0.y;
- color += texelFetch(ima, ivec2(tc + vec2(0.0, -1.0)), 0) * w1.x * w0.y;
- color += texelFetch(ima, ivec2(tc + vec2(1.0, -1.0)), 0) * w2.x * w0.y;
- color += texelFetch(ima, ivec2(tc + vec2(2.0, -1.0)), 0) * w3.x * w0.y;
-
- color += texelFetch(ima, ivec2(tc + vec2(-1.0, 0.0)), 0) * w0.x * w1.y;
- color += texelFetch(ima, ivec2(tc + vec2(0.0, 0.0)), 0) * w1.x * w1.y;
- color += texelFetch(ima, ivec2(tc + vec2(1.0, 0.0)), 0) * w2.x * w1.y;
- color += texelFetch(ima, ivec2(tc + vec2(2.0, 0.0)), 0) * w3.x * w1.y;
-
- color += texelFetch(ima, ivec2(tc + vec2(-1.0, 1.0)), 0) * w0.x * w2.y;
- color += texelFetch(ima, ivec2(tc + vec2(0.0, 1.0)), 0) * w1.x * w2.y;
- color += texelFetch(ima, ivec2(tc + vec2(1.0, 1.0)), 0) * w2.x * w2.y;
- color += texelFetch(ima, ivec2(tc + vec2(2.0, 1.0)), 0) * w3.x * w2.y;
-
- color += texelFetch(ima, ivec2(tc + vec2(-1.0, 2.0)), 0) * w0.x * w3.y;
- color += texelFetch(ima, ivec2(tc + vec2(0.0, 2.0)), 0) * w1.x * w3.y;
- color += texelFetch(ima, ivec2(tc + vec2(1.0, 2.0)), 0) * w2.x * w3.y;
- color += texelFetch(ima, ivec2(tc + vec2(2.0, 2.0)), 0) * w3.x * w3.y;
-#endif
-
- alpha = color.a;
-}
-
-void node_tex_image_cubic(vec3 co, sampler2D ima, out vec4 color, out float alpha)
-{
- node_tex_image_cubic_ex(co, ima, 0.0, color, alpha);
-}
-
-void node_tex_image_cubic_extend(vec3 co, sampler2D ima, out vec4 color, out float alpha)
-{
- node_tex_image_cubic_ex(co, ima, 1.0, color, alpha);
-}
-
-void node_tex_image_smart(vec3 co, sampler2D ima, out vec4 color, out float alpha)
-{
- /* use cubic for now */
- node_tex_image_cubic_ex(co, ima, 0.0, color, alpha);
-}
-
-void tex_box_sample_linear(
- vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3)
-{
- /* X projection */
- vec2 uv = texco.yz;
- if (N.x < 0.0) {
- uv.x = 1.0 - uv.x;
- }
- color1 = texture(ima, uv);
- /* Y projection */
- uv = texco.xz;
- if (N.y > 0.0) {
- uv.x = 1.0 - uv.x;
- }
- color2 = texture(ima, uv);
- /* Z projection */
- uv = texco.yx;
- if (N.z > 0.0) {
- uv.x = 1.0 - uv.x;
- }
- color3 = texture(ima, uv);
-}
-
-void tex_box_sample_nearest(
- vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3)
-{
- /* X projection */
- vec2 uv = texco.yz;
- if (N.x < 0.0) {
- uv.x = 1.0 - uv.x;
- }
- ivec2 pix = ivec2(uv.xy * textureSize(ima, 0).xy);
- color1 = texelFetch(ima, pix, 0);
- /* Y projection */
- uv = texco.xz;
- if (N.y > 0.0) {
- uv.x = 1.0 - uv.x;
- }
- pix = ivec2(uv.xy * textureSize(ima, 0).xy);
- color2 = texelFetch(ima, pix, 0);
- /* Z projection */
- uv = texco.yx;
- if (N.z > 0.0) {
- uv.x = 1.0 - uv.x;
- }
- pix = ivec2(uv.xy * textureSize(ima, 0).xy);
- color3 = texelFetch(ima, pix, 0);
-}
-
-void tex_box_sample_cubic(
- vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3)
-{
- float alpha;
- /* X projection */
- vec2 uv = texco.yz;
- if (N.x < 0.0) {
- uv.x = 1.0 - uv.x;
- }
- node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color1, alpha);
- /* Y projection */
- uv = texco.xz;
- if (N.y > 0.0) {
- uv.x = 1.0 - uv.x;
- }
- node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color2, alpha);
- /* Z projection */
- uv = texco.yx;
- if (N.z > 0.0) {
- uv.x = 1.0 - uv.x;
- }
- node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color3, alpha);
-}
-
-void tex_box_sample_smart(
- vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3)
-{
- tex_box_sample_cubic(texco, N, ima, color1, color2, color3);
-}
-
-void node_tex_image_box(vec3 texco,
- vec3 N,
- vec4 color1,
- vec4 color2,
- vec4 color3,
- sampler2D ima,
- float blend,
- out vec4 color,
- out float alpha)
-{
- /* project from direction vector to barycentric coordinates in triangles */
- N = abs(N);
- N /= dot(N, vec3(1.0));
-
- /* basic idea is to think of this as a triangle, each corner representing
- * one of the 3 faces of the cube. in the corners we have single textures,
- * in between we blend between two textures, and in the middle we a blend
- * between three textures.
- *
- * the Nxyz values are the barycentric coordinates in an equilateral
- * triangle, which in case of blending, in the middle has a smaller
- * equilateral triangle where 3 textures blend. this divides things into
- * 7 zones, with an if () test for each zone
- * EDIT: Now there is only 4 if's. */
-
- float limit = 0.5 + 0.5 * blend;
-
- vec3 weight;
- weight = N.xyz / (N.xyx + N.yzz);
- weight = clamp((weight - 0.5 * (1.0 - blend)) / max(1e-8, blend), 0.0, 1.0);
-
- /* test for mixes between two textures */
- if (N.z < (1.0 - limit) * (N.y + N.x)) {
- weight.z = 0.0;
- weight.y = 1.0 - weight.x;
- }
- else if (N.x < (1.0 - limit) * (N.y + N.z)) {
- weight.x = 0.0;
- weight.z = 1.0 - weight.y;
- }
- else if (N.y < (1.0 - limit) * (N.x + N.z)) {
- weight.y = 0.0;
- weight.x = 1.0 - weight.z;
- }
- else {
- /* last case, we have a mix between three */
- weight = ((2.0 - limit) * N + (limit - 1.0)) / max(1e-8, blend);
- }
-
- color = weight.x * color1 + weight.y * color2 + weight.z * color3;
- alpha = color.a;
-}
-
-void tex_clip_linear(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
-{
- vec2 tex_size = vec2(textureSize(ima, 0).xy);
- vec2 minco = min(co.xy, 1.0 - co.xy);
- minco = clamp(minco * tex_size + 0.5, 0.0, 1.0);
- float fac = minco.x * minco.y;
-
- color = mix(vec4(0.0), icolor, fac);
- alpha = color.a;
-}
-
-void tex_clip_nearest(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
-{
- vec4 minco = vec4(co.xy, 1.0 - co.xy);
- color = (any(lessThan(minco, vec4(0.0)))) ? vec4(0.0) : icolor;
- alpha = color.a;
-}
-
-void tex_clip_cubic(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
-{
- vec2 tex_size = vec2(textureSize(ima, 0).xy);
-
- co.xy *= tex_size;
- /* texel center */
- vec2 tc = floor(co.xy - 0.5) + 0.5;
- vec2 w0, w1, w2, w3;
- cubic_bspline_coefs(co.xy - tc, w0, w1, w2, w3);
-
- /* TODO Optimize this part. I'm sure there is a smarter way to do that.
- * Could do that when sampling? */
-#define CLIP_CUBIC_SAMPLE(samp, size) \
- (float(all(greaterThan(samp, vec2(-0.5)))) * float(all(lessThan(ivec2(samp), itex_size))))
- ivec2 itex_size = textureSize(ima, 0).xy;
- float fac;
- fac = CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, -1.0), itex_size) * w0.x * w0.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, -1.0), itex_size) * w1.x * w0.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, -1.0), itex_size) * w2.x * w0.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, -1.0), itex_size) * w3.x * w0.y;
-
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 0.0), itex_size) * w0.x * w1.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 0.0), itex_size) * w1.x * w1.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 0.0), itex_size) * w2.x * w1.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 0.0), itex_size) * w3.x * w1.y;
-
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 1.0), itex_size) * w0.x * w2.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 1.0), itex_size) * w1.x * w2.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 1.0), itex_size) * w2.x * w2.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 1.0), itex_size) * w3.x * w2.y;
-
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 2.0), itex_size) * w0.x * w3.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 2.0), itex_size) * w1.x * w3.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 2.0), itex_size) * w2.x * w3.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 2.0), itex_size) * w3.x * w3.y;
-#undef CLIP_CUBIC_SAMPLE
-
- color = mix(vec4(0.0), icolor, fac);
- alpha = color.a;
-}
-
-void tex_clip_smart(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
-{
- tex_clip_cubic(co, ima, icolor, color, alpha);
-}
-
-void node_tex_image_empty(vec3 co, out vec4 color, out float alpha)
-{
- color = vec4(0.0);
- alpha = 0.0;
-}
-
-void node_tex_magic(
- vec3 co, float scale, float distortion, float depth, out vec4 color, out float fac)
-{
- vec3 p = co * scale;
- float x = sin((p.x + p.y + p.z) * 5.0);
- float y = cos((-p.x + p.y - p.z) * 5.0);
- float z = -cos((-p.x - p.y + p.z) * 5.0);
-
- if (depth > 0) {
- x *= distortion;
- y *= distortion;
- z *= distortion;
- y = -cos(x - y + z);
- y *= distortion;
- if (depth > 1) {
- x = cos(x - y - z);
- x *= distortion;
- if (depth > 2) {
- z = sin(-x - y - z);
- z *= distortion;
- if (depth > 3) {
- x = -cos(-x + y - z);
- x *= distortion;
- if (depth > 4) {
- y = -sin(-x + y + z);
- y *= distortion;
- if (depth > 5) {
- y = -cos(-x + y + z);
- y *= distortion;
- if (depth > 6) {
- x = cos(x + y + z);
- x *= distortion;
- if (depth > 7) {
- z = sin(x + y - z);
- z *= distortion;
- if (depth > 8) {
- x = -cos(-x - y + z);
- x *= distortion;
- if (depth > 9) {
- y = -sin(x - y + z);
- y *= distortion;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (distortion != 0.0) {
- distortion *= 2.0;
- x /= distortion;
- y /= distortion;
- z /= distortion;
- }
-
- color = vec4(0.5 - x, 0.5 - y, 0.5 - z, 1.0);
- fac = (color.x + color.y + color.z) / 3.0;
-}
-
-float noise_fade(float t)
-{
- return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
-}
-
-float noise_scale3(float result)
-{
- return 0.9820 * result;
-}
-
-float noise_nerp(float t, float a, float b)
-{
- return (1.0 - t) * a + t * b;
-}
-
-float noise_grad(uint hash, float x, float y, float z)
-{
- uint h = hash & 15u;
- float u = h < 8u ? x : y;
- float vt = ((h == 12u) || (h == 14u)) ? x : z;
- float v = h < 4u ? y : vt;
- return (((h & 1u) != 0u) ? -u : u) + (((h & 2u) != 0u) ? -v : v);
-}
-
-float noise_perlin(float x, float y, float z)
-{
- int X;
- float fx = floorfrac(x, X);
- int Y;
- float fy = floorfrac(y, Y);
- int Z;
- float fz = floorfrac(z, Z);
-
- float u = noise_fade(fx);
- float v = noise_fade(fy);
- float w = noise_fade(fz);
-
- float noise_u[2], noise_v[2];
-
- noise_u[0] = noise_nerp(u,
- noise_grad(hash_int3(X, Y, Z), fx, fy, fz),
- noise_grad(hash_int3(X + 1, Y, Z), fx - 1.0, fy, fz));
-
- noise_u[1] = noise_nerp(u,
- noise_grad(hash_int3(X, Y + 1, Z), fx, fy - 1.0, fz),
- noise_grad(hash_int3(X + 1, Y + 1, Z), fx - 1.0, fy - 1.0, fz));
-
- noise_v[0] = noise_nerp(v, noise_u[0], noise_u[1]);
-
- noise_u[0] = noise_nerp(u,
- noise_grad(hash_int3(X, Y, Z + 1), fx, fy, fz - 1.0),
- noise_grad(hash_int3(X + 1, Y, Z + 1), fx - 1.0, fy, fz - 1.0));
-
- noise_u[1] = noise_nerp(
- u,
- noise_grad(hash_int3(X, Y + 1, Z + 1), fx, fy - 1.0, fz - 1.0),
- noise_grad(hash_int3(X + 1, Y + 1, Z + 1), fx - 1.0, fy - 1.0, fz - 1.0));
-
- noise_v[1] = noise_nerp(v, noise_u[0], noise_u[1]);
-
- float r = noise_scale3(noise_nerp(w, noise_v[0], noise_v[1]));
-
- return (isinf(r)) ? 0.0 : r;
-}
-
-float noise(vec3 p)
-{
- return 0.5 * noise_perlin(p.x, p.y, p.z) + 0.5;
-}
-
-float snoise(vec3 p)
-{
- return noise_perlin(p.x, p.y, p.z);
-}
-
-float noise_turbulence(vec3 p, float octaves, int hard)
-{
- float fscale = 1.0;
- float amp = 1.0;
- float sum = 0.0;
- octaves = clamp(octaves, 0.0, 16.0);
- int n = int(octaves);
- for (int i = 0; i <= n; i++) {
- float t = noise(fscale * p);
- if (hard != 0) {
- t = abs(2.0 * t - 1.0);
- }
- sum += t * amp;
- amp *= 0.5;
- fscale *= 2.0;
- }
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- float t = noise(fscale * p);
- if (hard != 0) {
- t = abs(2.0 * t - 1.0);
- }
- float sum2 = sum + t * amp;
- sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
- sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1));
- return (1.0 - rmd) * sum + rmd * sum2;
- }
- else {
- sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
- return sum;
- }
-}
-
-void node_tex_noise(
- vec3 co, float scale, float detail, float distortion, out vec4 color, out float fac)
-{
- vec3 p = co * scale;
- int hard = 0;
- if (distortion != 0.0) {
- vec3 r, offset = vec3(13.5, 13.5, 13.5);
- r.x = noise(p + offset) * distortion;
- r.y = noise(p) * distortion;
- r.z = noise(p - offset) * distortion;
- p += r;
- }
-
- fac = noise_turbulence(p, detail, hard);
- color = vec4(fac,
- noise_turbulence(vec3(p.y, p.x, p.z), detail, hard),
- noise_turbulence(vec3(p.y, p.z, p.x), detail, hard),
- 1);
-}
-
-/* Musgrave fBm
- *
- * H: fractal increment parameter
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- *
- * from "Texturing and Modelling: A procedural approach"
- */
-
-float noise_musgrave_fBm(vec3 p, float H, float lacunarity, float octaves)
-{
- float rmd;
- float value = 0.0;
- float pwr = 1.0;
- float pwHL = pow(lacunarity, -H);
-
- for (int i = 0; i < int(octaves); i++) {
- value += snoise(p) * pwr;
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- value += rmd * snoise(p) * pwr;
- }
-
- return value;
-}
-
-/* Musgrave Multifractal
- *
- * H: highest fractal dimension
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- */
-
-float noise_musgrave_multi_fractal(vec3 p, float H, float lacunarity, float octaves)
-{
- float rmd;
- float value = 1.0;
- float pwr = 1.0;
- float pwHL = pow(lacunarity, -H);
-
- for (int i = 0; i < int(octaves); i++) {
- value *= (pwr * snoise(p) + 1.0);
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- value *= (rmd * pwr * snoise(p) + 1.0); /* correct? */
- }
-
- return value;
-}
-
-/* Musgrave Heterogeneous Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
-float noise_musgrave_hetero_terrain(vec3 p, float H, float lacunarity, float octaves, float offset)
-{
- float value, increment, rmd;
- float pwHL = pow(lacunarity, -H);
- float pwr = pwHL;
-
- /* first unscaled octave of function; later octaves are scaled */
- value = offset + snoise(p);
- p *= lacunarity;
-
- for (int i = 1; i < int(octaves); i++) {
- increment = (snoise(p) + offset) * pwr * value;
- value += increment;
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- increment = (snoise(p) + offset) * pwr * value;
- value += rmd * increment;
- }
-
- return value;
-}
-
-/* Hybrid Additive/Multiplicative Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
-float noise_musgrave_hybrid_multi_fractal(
- vec3 p, float H, float lacunarity, float octaves, float offset, float gain)
-{
- float result, signal, weight, rmd;
- float pwHL = pow(lacunarity, -H);
- float pwr = pwHL;
-
- result = snoise(p) + offset;
- weight = gain * result;
- p *= lacunarity;
-
- for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
- if (weight > 1.0) {
- weight = 1.0;
- }
-
- signal = (snoise(p) + offset) * pwr;
- pwr *= pwHL;
- result += weight * signal;
- weight *= gain * signal;
- p *= lacunarity;
- }
-
- rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- result += rmd * ((snoise(p) + offset) * pwr);
- }
-
- return result;
-}
-
-/* Ridged Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
-float noise_musgrave_ridged_multi_fractal(
- vec3 p, float H, float lacunarity, float octaves, float offset, float gain)
-{
- float result, signal, weight;
- float pwHL = pow(lacunarity, -H);
- float pwr = pwHL;
-
- signal = offset - abs(snoise(p));
- signal *= signal;
- result = signal;
- weight = 1.0;
-
- for (int i = 1; i < int(octaves); i++) {
- p *= lacunarity;
- weight = clamp(signal * gain, 0.0, 1.0);
- signal = offset - abs(snoise(p));
- signal *= signal;
- signal *= weight;
- result += signal * pwr;
- pwr *= pwHL;
- }
-
- return result;
-}
-
-float svm_musgrave(int type,
- float dimension,
- float lacunarity,
- float octaves,
- float offset,
- float intensity,
- float gain,
- vec3 p)
-{
- if (type == 0 /* NODE_MUSGRAVE_MULTIFRACTAL */) {
- return intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves);
- }
- else if (type == 1 /* NODE_MUSGRAVE_FBM */) {
- return intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves);
- }
- else if (type == 2 /* NODE_MUSGRAVE_HYBRID_MULTIFRACTAL */) {
- return intensity *
- noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
- }
- else if (type == 3 /* NODE_MUSGRAVE_RIDGED_MULTIFRACTAL */) {
- return intensity *
- noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
- }
- else if (type == 4 /* NODE_MUSGRAVE_HETERO_TERRAIN */) {
- return intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, offset);
- }
- return 0.0;
-}
-
-void node_tex_musgrave(vec3 co,
- float scale,
- float detail,
- float dimension,
- float lacunarity,
- float offset,
- float gain,
- float type,
- out vec4 color,
- out float fac)
-{
- fac = svm_musgrave(int(type), dimension, lacunarity, detail, offset, 1.0, gain, co *scale);
-
- color = vec4(fac, fac, fac, 1.0);
-}
-
-void node_tex_sky(vec3 co, out vec4 color)
-{
- color = vec4(1.0);
-}
-
-void node_tex_voronoi(vec3 co,
- float scale,
- float exponent,
- float coloring,
- float metric,
- float feature,
- out vec4 color,
- out float fac)
-{
- vec3 p = co * scale;
- int xx, yy, zz, xi, yi, zi;
- vec4 da = vec4(1e10);
- vec3 pa[4] = vec3[4](vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0));
-
- xi = floor_to_int(p[0]);
- yi = floor_to_int(p[1]);
- zi = floor_to_int(p[2]);
-
- for (xx = xi - 1; xx <= xi + 1; xx++) {
- for (yy = yi - 1; yy <= yi + 1; yy++) {
- for (zz = zi - 1; zz <= zi + 1; zz++) {
- vec3 ip = vec3(xx, yy, zz);
- vec3 vp = cellnoise_color(ip);
- vec3 pd = p - (vp + ip);
-
- float d = 0.0;
- if (metric == 0.0) { /* SHD_VORONOI_DISTANCE 0 */
- d = dot(pd, pd);
- }
- else if (metric == 1.0) { /* SHD_VORONOI_MANHATTAN 1 */
- d = abs(pd[0]) + abs(pd[1]) + abs(pd[2]);
- }
- else if (metric == 2.0) { /* SHD_VORONOI_CHEBYCHEV 2 */
- d = max(abs(pd[0]), max(abs(pd[1]), abs(pd[2])));
- }
- else if (metric == 3.0) { /* SHD_VORONOI_MINKOWSKI 3 */
- d = pow(pow(abs(pd[0]), exponent) + pow(abs(pd[1]), exponent) +
- pow(abs(pd[2]), exponent),
- 1.0 / exponent);
- }
-
- vp += vec3(xx, yy, zz);
- if (d < da[0]) {
- da.yzw = da.xyz;
- da[0] = d;
-
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = pa[0];
- pa[0] = vp;
- }
- else if (d < da[1]) {
- da.zw = da.yz;
- da[1] = d;
-
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = vp;
- }
- else if (d < da[2]) {
- da[3] = da[2];
- da[2] = d;
-
- pa[3] = pa[2];
- pa[2] = vp;
- }
- else if (d < da[3]) {
- da[3] = d;
- pa[3] = vp;
- }
- }
- }
- }
-
- if (coloring == 0.0) {
- /* Intensity output */
- if (feature == 0.0) { /* F1 */
- fac = abs(da[0]);
- }
- else if (feature == 1.0) { /* F2 */
- fac = abs(da[1]);
- }
- else if (feature == 2.0) { /* F3 */
- fac = abs(da[2]);
- }
- else if (feature == 3.0) { /* F4 */
- fac = abs(da[3]);
- }
- else if (feature == 4.0) { /* F2F1 */
- fac = abs(da[1] - da[0]);
- }
- color = vec4(fac, fac, fac, 1.0);
- }
- else {
- /* Color output */
- vec3 col = vec3(fac, fac, fac);
- if (feature == 0.0) { /* F1 */
- col = pa[0];
- }
- else if (feature == 1.0) { /* F2 */
- col = pa[1];
- }
- else if (feature == 2.0) { /* F3 */
- col = pa[2];
- }
- else if (feature == 3.0) { /* F4 */
- col = pa[3];
- }
- else if (feature == 4.0) { /* F2F1 */
- col = abs(pa[1] - pa[0]);
- }
-
- color = vec4(cellnoise_color(col), 1.0);
- fac = (color.x + color.y + color.z) * (1.0 / 3.0);
- }
-}
-
-float calc_wave(
- vec3 p, float distortion, float detail, float detail_scale, int wave_type, int wave_profile)
-{
- float n;
-
- if (wave_type == 0) { /* type bands */
- n = (p.x + p.y + p.z) * 10.0;
- }
- else { /* type rings */
- n = length(p) * 20.0;
- }
-
- if (distortion != 0.0) {
- n += distortion * noise_turbulence(p * detail_scale, detail, 0);
- }
-
- if (wave_profile == 0) { /* profile sin */
- return 0.5 + 0.5 * sin(n);
- }
- else { /* profile saw */
- n /= 2.0 * M_PI;
- n -= int(n);
- return (n < 0.0) ? n + 1.0 : n;
- }
-}
-
-void node_tex_wave(vec3 co,
- float scale,
- float distortion,
- float detail,
- float detail_scale,
- float wave_type,
- float wave_profile,
- out vec4 color,
- out float fac)
-{
- float f;
- f = calc_wave(co * scale, distortion, detail, detail_scale, int(wave_type), int(wave_profile));
-
- color = vec4(f, f, f, 1.0);
- fac = f;
-}
-
-/* light path */
-
-void node_light_path(out float is_camera_ray,
- out float is_shadow_ray,
- out float is_diffuse_ray,
- out float is_glossy_ray,
- out float is_singular_ray,
- out float is_reflection_ray,
- out float is_transmission_ray,
- out float ray_length,
- out float ray_depth,
- out float diffuse_depth,
- out float glossy_depth,
- out float transparent_depth,
- out float transmission_depth)
-{
- /* Supported. */
- is_camera_ray = (rayType == EEVEE_RAY_CAMERA) ? 1.0 : 0.0;
- is_shadow_ray = (rayType == EEVEE_RAY_SHADOW) ? 1.0 : 0.0;
- is_diffuse_ray = (rayType == EEVEE_RAY_DIFFUSE) ? 1.0 : 0.0;
- is_glossy_ray = (rayType == EEVEE_RAY_GLOSSY) ? 1.0 : 0.0;
- /* Kind of supported. */
- is_singular_ray = is_glossy_ray;
- is_reflection_ray = is_glossy_ray;
- is_transmission_ray = is_glossy_ray;
- ray_depth = rayDepth;
- diffuse_depth = (is_diffuse_ray == 1.0) ? rayDepth : 0.0;
- glossy_depth = (is_glossy_ray == 1.0) ? rayDepth : 0.0;
- transmission_depth = (is_transmission_ray == 1.0) ? glossy_depth : 0.0;
- /* Not supported. */
- ray_length = 1.0;
- transparent_depth = 0.0;
-}
-
-void node_light_falloff(
- float strength, float tsmooth, out float quadratic, out float linear, out float constant)
-{
- quadratic = strength;
- linear = strength;
- constant = strength;
-}
-
-void node_object_info(mat4 obmat,
- vec4 obcolor,
- vec4 info,
- float mat_index,
- out vec3 location,
- out vec4 color,
- out float object_index,
- out float material_index,
- out float random)
-{
- location = obmat[3].xyz;
- color = obcolor;
- object_index = info.x;
- material_index = mat_index;
- random = info.z;
-}
-
-void node_normal_map(vec4 info, vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnormal)
-{
- if (all(equal(tangent, vec4(0.0, 0.0, 0.0, 1.0)))) {
- outnormal = normal;
- return;
- }
- tangent *= (gl_FrontFacing ? 1.0 : -1.0);
- vec3 B = tangent.w * cross(normal, tangent.xyz) * info.w;
-
- outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * normal;
- outnormal = normalize(outnormal);
-}
-
-void node_bump(
- float strength, float dist, float height, vec3 N, vec3 surf_pos, float invert, out vec3 result)
-{
- N = mat3(ViewMatrix) * normalize(N);
- dist *= gl_FrontFacing ? invert : -invert;
-
- vec3 dPdx = dFdx(surf_pos);
- vec3 dPdy = dFdy(surf_pos);
-
- /* Get surface tangents from normal. */
- vec3 Rx = cross(dPdy, N);
- vec3 Ry = cross(N, dPdx);
-
- /* Compute surface gradient and determinant. */
- float det = dot(dPdx, Rx);
-
- float dHdx = dFdx(height);
- float dHdy = dFdy(height);
- vec3 surfgrad = dHdx * Rx + dHdy * Ry;
-
- strength = max(strength, 0.0);
-
- result = normalize(abs(det) * N - dist * sign(det) * surfgrad);
- result = normalize(mix(N, result, strength));
-
- result = mat3(ViewMatrixInverse) * result;
-}
-
-void node_bevel(float radius, vec3 N, out vec3 result)
-{
- result = N;
-}
-
-void node_hair_info(out float is_strand,
- out float intercept,
- out float thickness,
- out vec3 tangent,
- out float random)
-{
-#ifdef HAIR_SHADER
- is_strand = 1.0;
- intercept = hairTime;
- thickness = hairThickness;
- tangent = normalize(worldNormal);
- random = wang_hash_noise(
- uint(hairStrandID)); /* TODO: could be precomputed per strand instead. */
-#else
- is_strand = 0.0;
- intercept = 0.0;
- thickness = 0.0;
- tangent = vec3(1.0);
- random = 0.0;
-#endif
-}
-
-void node_displacement_object(
- float height, float midlevel, float scale, vec3 N, mat4 obmat, out vec3 result)
-{
- N = (vec4(N, 0.0) * obmat).xyz;
- result = (height - midlevel) * scale * normalize(N);
- result = (obmat * vec4(result, 0.0)).xyz;
-}
-
-void node_displacement_world(float height, float midlevel, float scale, vec3 N, out vec3 result)
-{
- result = (height - midlevel) * scale * normalize(N);
-}
-
-void node_vector_displacement_tangent(vec4 vector,
- float midlevel,
- float scale,
- vec4 tangent,
- vec3 normal,
- mat4 obmat,
- mat4 viewmat,
- out vec3 result)
-{
- /* TODO(fclem) this is broken. revisit latter. */
- vec3 N_object = normalize(((vec4(normal, 0.0) * viewmat) * obmat).xyz);
- vec3 T_object = normalize(((vec4(tangent.xyz, 0.0) * viewmat) * obmat).xyz);
- vec3 B_object = tangent.w * normalize(cross(N_object, T_object));
-
- vec3 offset = (vector.xyz - vec3(midlevel)) * scale;
- result = offset.x * T_object + offset.y * N_object + offset.z * B_object;
- result = (obmat * vec4(result, 0.0)).xyz;
-}
-
-void node_vector_displacement_object(
- vec4 vector, float midlevel, float scale, mat4 obmat, out vec3 result)
-{
- result = (vector.xyz - vec3(midlevel)) * scale;
- result = (obmat * vec4(result, 0.0)).xyz;
-}
-
-void node_vector_displacement_world(vec4 vector, float midlevel, float scale, out vec3 result)
-{
- result = (vector.xyz - vec3(midlevel)) * scale;
-}
-
-/* output */
-
-void node_output_material(Closure surface, Closure volume, vec3 displacement, out Closure result)
-{
-#ifdef VOLUMETRICS
- result = volume;
-#else
- result = surface;
-#endif
-}
-
-uniform float backgroundAlpha;
-
-void node_output_world(Closure surface, Closure volume, out Closure result)
-{
-#ifndef VOLUMETRICS
- result.radiance = surface.radiance * backgroundAlpha;
- result.transmittance = vec3(1.0 - backgroundAlpha);
-#else
- result = volume;
-#endif /* VOLUMETRICS */
-}
-
-/* TODO : clean this ifdef mess */
-/* EEVEE output */
-void world_normals_get(out vec3 N)
-{
-#ifndef VOLUMETRICS
-# ifdef HAIR_SHADER
- vec3 B = normalize(cross(worldNormal, hairTangent));
- float cos_theta;
- if (hairThicknessRes == 1) {
- vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0);
- /* Random cosine normal distribution on the hair surface. */
- cos_theta = rand.x * 2.0 - 1.0;
- }
- else {
- /* Shade as a cylinder. */
- cos_theta = hairThickTime / hairThickness;
- }
- float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
- N = normalize(worldNormal * sin_theta + B * cos_theta);
-# else
- N = gl_FrontFacing ? worldNormal : -worldNormal;
-# endif
-#else
- generated_from_orco(vec3(0.0), N);
-#endif
-}
-
-#ifndef VOLUMETRICS
-void node_eevee_specular(vec4 diffuse,
- vec4 specular,
- float roughness,
- vec4 emissive,
- float transp,
- vec3 normal,
- float clearcoat,
- float clearcoat_roughness,
- vec3 clearcoat_normal,
- float occlusion,
- float ssr_id,
- out Closure result)
-{
- normal = normalize(normal);
-
- vec3 out_diff, out_spec, ssr_spec;
- eevee_closure_default_clearcoat(normal,
- diffuse.rgb,
- specular.rgb,
- vec3(1.0),
- int(ssr_id),
- roughness,
- clearcoat_normal,
- clearcoat * 0.25,
- clearcoat_roughness,
- occlusion,
- out_diff,
- out_spec,
- ssr_spec);
-
- float alpha = 1.0 - transp;
- result = CLOSURE_DEFAULT;
- result.radiance = out_diff * diffuse.rgb + out_spec + emissive.rgb;
- result.radiance *= alpha;
- result.transmittance = vec3(transp);
-
- closure_load_ssr_data(ssr_spec * alpha, roughness, normal, viewCameraVec, int(ssr_id), result);
-}
-
-void node_shader_to_rgba(Closure cl, out vec4 outcol, out float outalpha)
-{
- vec4 spec_accum = vec4(0.0);
- if (ssrToggle && FLAG_TEST(cl.flag, CLOSURE_SSR_FLAG)) {
- vec3 V = cameraVec;
- vec3 vN = normal_decode(cl.ssr_normal, viewCameraVec);
- vec3 N = transform_direction(ViewMatrixInverse, vN);
- float roughness = cl.ssr_data.a;
- float roughnessSquared = max(1e-3, roughness * roughness);
- fallback_cubemap(N, V, worldPosition, viewPosition, roughness, roughnessSquared, spec_accum);
- }
-
- outalpha = avg(cl.transmittance);
- outcol = vec4((spec_accum.rgb * cl.ssr_data.rgb) + cl.radiance, 1.0);
-
-# ifdef USE_SSS
-# ifdef USE_SSS_ALBEDO
- outcol.rgb += cl.sss_data.rgb * cl.sss_albedo;
-# else
- outcol.rgb += cl.sss_data.rgb;
-# endif
-# endif
-}
-
-#endif /* VOLUMETRICS */
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl
new file mode 100644
index 00000000000..99117400c57
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl
@@ -0,0 +1,4 @@
+void node_add_shader(Closure shader1, Closure shader2, out Closure shader)
+{
+ shader = closure_add(shader1, shader2);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
new file mode 100644
index 00000000000..8f8ebebb5f1
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
@@ -0,0 +1,13 @@
+#ifndef VOLUMETRICS
+void node_ambient_occlusion(
+ vec4 color, float distance, vec3 normal, out vec4 result_color, out float result_ao)
+{
+ vec3 bent_normal;
+ vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0);
+ result_ao = occlusion_compute(normalize(normal), viewPosition, 1.0, rand, bent_normal);
+ result_color = result_ao * color;
+}
+#else
+/* Stub ambient occlusion because it is not compatible with volumetrics. */
+# define node_ambient_occlusion
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl
new file mode 100644
index 00000000000..a8a900b40c6
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl
@@ -0,0 +1,15 @@
+#ifndef VOLUMETRICS
+void node_bsdf_anisotropic(vec4 color,
+ float roughness,
+ float anisotropy,
+ float rotation,
+ vec3 N,
+ vec3 T,
+ out Closure result)
+{
+ node_bsdf_glossy(color, roughness, N, -1, result);
+}
+#else
+/* Stub anisotropic because it is not compatible with volumetrics. */
+# define node_bsdf_anisotropic
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl
new file mode 100644
index 00000000000..10e1b4563bc
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl
@@ -0,0 +1,6 @@
+void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf)
+{
+ outcol = vec4(attr, 1.0);
+ outvec = attr;
+ outf = avg(attr);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_background.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_background.glsl
new file mode 100644
index 00000000000..69ef4dcb7c7
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_background.glsl
@@ -0,0 +1,11 @@
+void node_background(vec4 color, float strength, out Closure result)
+{
+#ifndef VOLUMETRICS
+ color *= strength;
+ result = CLOSURE_DEFAULT;
+ result.radiance = color.rgb;
+ result.transmittance = vec3(0.0);
+#else
+ result = CLOSURE_DEFAULT;
+#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_bevel.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_bevel.glsl
new file mode 100644
index 00000000000..0d99390c2f9
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_bevel.glsl
@@ -0,0 +1,4 @@
+void node_bevel(float radius, vec3 N, out vec3 result)
+{
+ result = N;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_blackbody.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_blackbody.glsl
new file mode 100644
index 00000000000..d0111aa3839
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_blackbody.glsl
@@ -0,0 +1,13 @@
+void node_blackbody(float temperature, sampler1DArray spectrummap, float layer, out vec4 color)
+{
+ if (temperature >= 12000.0) {
+ color = vec4(0.826270103, 0.994478524, 1.56626022, 1.0);
+ }
+ else if (temperature < 965.0) {
+ color = vec4(4.70366907, 0.0, 0.0, 1.0);
+ }
+ else {
+ float t = (temperature - 965.0) / (12000.0 - 965.0);
+ color = vec4(texture(spectrummap, vec2(t, layer)).rgb, 1.0);
+ }
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_bright_contrast.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_bright_contrast.glsl
new file mode 100644
index 00000000000..a5a10833065
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_bright_contrast.glsl
@@ -0,0 +1,10 @@
+void brightness_contrast(vec4 col, float brightness, float contrast, out vec4 outcol)
+{
+ float a = 1.0 + contrast;
+ float b = brightness - contrast * 0.5;
+
+ outcol.r = max(a * col.r + b, 0.0);
+ outcol.g = max(a * col.g + b, 0.0);
+ outcol.b = max(a * col.b + b, 0.0);
+ outcol.a = col.a;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl
new file mode 100644
index 00000000000..9f73f654217
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl
@@ -0,0 +1,44 @@
+void dfdx_v3(vec3 v, out vec3 dy)
+{
+ dy = v + DFDX_SIGN * dFdx(v);
+}
+
+void dfdy_v3(vec3 v, out vec3 dy)
+{
+ dy = v + DFDY_SIGN * dFdy(v);
+}
+
+void node_bump(float strength,
+ float dist,
+ float height,
+ float height_dx,
+ float height_dy,
+ vec3 N,
+ vec3 surf_pos,
+ float invert,
+ out vec3 result)
+{
+ N = mat3(ViewMatrix) * normalize(N);
+ dist *= gl_FrontFacing ? invert : -invert;
+
+ vec3 dPdx = dFdx(surf_pos);
+ vec3 dPdy = dFdy(surf_pos);
+
+ /* Get surface tangents from normal. */
+ vec3 Rx = cross(dPdy, N);
+ vec3 Ry = cross(N, dPdx);
+
+ /* Compute surface gradient and determinant. */
+ float det = dot(dPdx, Rx);
+
+ float dHdx = height_dx - height;
+ float dHdy = height_dy - height;
+ vec3 surfgrad = dHdx * Rx + dHdy * Ry;
+
+ strength = max(strength, 0.0);
+
+ result = normalize(abs(det) * N - dist * sign(det) * surfgrad);
+ result = normalize(mix(N, result, strength));
+
+ result = mat3(ViewMatrixInverse) * result;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl
new file mode 100644
index 00000000000..03e61e9f472
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl
@@ -0,0 +1,6 @@
+void camera(vec3 co, out vec3 outview, out float outdepth, out float outdist)
+{
+ outdepth = abs(co.z);
+ outdist = length(co);
+ outview = normalize(co);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_clamp.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_clamp.glsl
new file mode 100644
index 00000000000..b8842064b6f
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_clamp.glsl
@@ -0,0 +1,4 @@
+void clamp_value(float value, float min, float max, out float result)
+{
+ result = clamp(value, min, max);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_color_ramp.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_color_ramp.glsl
new file mode 100644
index 00000000000..9fe45f91f45
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_color_ramp.glsl
@@ -0,0 +1,28 @@
+void valtorgb_opti_constant(
+ float fac, float edge, vec4 color1, vec4 color2, out vec4 outcol, out float outalpha)
+{
+ outcol = (fac > edge) ? color2 : color1;
+ outalpha = outcol.a;
+}
+
+void valtorgb_opti_linear(
+ float fac, vec2 mulbias, vec4 color1, vec4 color2, out vec4 outcol, out float outalpha)
+{
+ fac = clamp(fac * mulbias.x + mulbias.y, 0.0, 1.0);
+ outcol = mix(color1, color2, fac);
+ outalpha = outcol.a;
+}
+
+void valtorgb(float fac, sampler1DArray colormap, float layer, out vec4 outcol, out float outalpha)
+{
+ outcol = texture(colormap, vec2(fac, layer));
+ outalpha = outcol.a;
+}
+
+void valtorgb_nearest(
+ float fac, sampler1DArray colormap, float layer, out vec4 outcol, out float outalpha)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ outcol = texelFetch(colormap, ivec2(fac * (textureSize(colormap, 0).x - 1), layer), 0);
+ outalpha = outcol.a;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl
new file mode 100644
index 00000000000..a5c3a990d90
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl
@@ -0,0 +1,111 @@
+void rgb_to_hsv(vec4 rgb, out vec4 outcol)
+{
+ float cmax, cmin, h, s, v, cdelta;
+ vec3 c;
+
+ cmax = max(rgb[0], max(rgb[1], rgb[2]));
+ cmin = min(rgb[0], min(rgb[1], rgb[2]));
+ cdelta = cmax - cmin;
+
+ v = cmax;
+ if (cmax != 0.0) {
+ s = cdelta / cmax;
+ }
+ else {
+ s = 0.0;
+ h = 0.0;
+ }
+
+ if (s == 0.0) {
+ h = 0.0;
+ }
+ else {
+ c = (vec3(cmax) - rgb.xyz) / cdelta;
+
+ if (rgb.x == cmax) {
+ h = c[2] - c[1];
+ }
+ else if (rgb.y == cmax) {
+ h = 2.0 + c[0] - c[2];
+ }
+ else {
+ h = 4.0 + c[1] - c[0];
+ }
+
+ h /= 6.0;
+
+ if (h < 0.0) {
+ h += 1.0;
+ }
+ }
+
+ outcol = vec4(h, s, v, rgb.w);
+}
+
+void hsv_to_rgb(vec4 hsv, out vec4 outcol)
+{
+ float i, f, p, q, t, h, s, v;
+ vec3 rgb;
+
+ h = hsv[0];
+ s = hsv[1];
+ v = hsv[2];
+
+ if (s == 0.0) {
+ rgb = vec3(v, v, v);
+ }
+ else {
+ if (h == 1.0) {
+ h = 0.0;
+ }
+
+ h *= 6.0;
+ i = floor(h);
+ f = h - i;
+ rgb = vec3(f, f, f);
+ p = v * (1.0 - s);
+ q = v * (1.0 - (s * f));
+ t = v * (1.0 - (s * (1.0 - f)));
+
+ if (i == 0.0) {
+ rgb = vec3(v, t, p);
+ }
+ else if (i == 1.0) {
+ rgb = vec3(q, v, p);
+ }
+ else if (i == 2.0) {
+ rgb = vec3(p, v, t);
+ }
+ else if (i == 3.0) {
+ rgb = vec3(p, q, v);
+ }
+ else if (i == 4.0) {
+ rgb = vec3(t, p, v);
+ }
+ else {
+ rgb = vec3(v, p, q);
+ }
+ }
+
+ outcol = vec4(rgb, hsv.w);
+}
+
+void color_alpha_clear(vec4 color, out vec4 result)
+{
+ result = vec4(color.rgb, 1.0);
+}
+
+void color_alpha_premultiply(vec4 color, out vec4 result)
+{
+ result = vec4(color.rgb * color.a, 1.0);
+}
+
+void color_alpha_unpremultiply(vec4 color, out vec4 result)
+{
+ if (color.a == 0.0 || color.a == 1.0) {
+ result = vec4(color.rgb, 1.0);
+ }
+ else {
+ result = vec4(color.rgb / color.a, 1.0);
+ }
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl
new file mode 100644
index 00000000000..2ce061da3cb
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl
@@ -0,0 +1,4 @@
+void combine_hsv(float h, float s, float v, out vec4 col)
+{
+ hsv_to_rgb(vec4(h, s, v, 1.0), col);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_combine_rgb.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_combine_rgb.glsl
new file mode 100644
index 00000000000..d9c882a048f
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_combine_rgb.glsl
@@ -0,0 +1,4 @@
+void combine_rgb(float r, float g, float b, out vec4 col)
+{
+ col = vec4(r, g, b, 1.0);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_combine_xyz.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_combine_xyz.glsl
new file mode 100644
index 00000000000..d8d132ff1f9
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_combine_xyz.glsl
@@ -0,0 +1,4 @@
+void combine_xyz(float x, float y, float z, out vec3 vec)
+{
+ vec = vec3(x, y, z);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl
new file mode 100644
index 00000000000..e029905a908
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl
@@ -0,0 +1,13 @@
+#ifndef VOLUMETRICS
+void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
+{
+ N = normalize(N);
+ result = CLOSURE_DEFAULT;
+ eevee_closure_diffuse(N, color.rgb, 1.0, true, result.radiance);
+ closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
+ result.radiance *= color.rgb;
+}
+#else
+/* Stub diffuse because it is not compatible with volumetrics. */
+# define node_bsdf_diffuse
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl
new file mode 100644
index 00000000000..0838b5c8b71
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl
@@ -0,0 +1,12 @@
+void node_displacement_object(
+ float height, float midlevel, float scale, vec3 N, mat4 obmat, out vec3 result)
+{
+ N = (vec4(N, 0.0) * obmat).xyz;
+ result = (height - midlevel) * scale * normalize(N);
+ result = (obmat * vec4(result, 0.0)).xyz;
+}
+
+void node_displacement_world(float height, float midlevel, float scale, vec3 N, out vec3 result)
+{
+ result = (height - midlevel) * scale * normalize(N);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
new file mode 100644
index 00000000000..34062cc8d02
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
@@ -0,0 +1,41 @@
+#ifndef VOLUMETRICS
+void node_eevee_specular(vec4 diffuse,
+ vec4 specular,
+ float roughness,
+ vec4 emissive,
+ float transp,
+ vec3 normal,
+ float clearcoat,
+ float clearcoat_roughness,
+ vec3 clearcoat_normal,
+ float occlusion,
+ float ssr_id,
+ out Closure result)
+{
+ normal = normalize(normal);
+
+ vec3 out_diff, out_spec, ssr_spec;
+ eevee_closure_default_clearcoat(normal,
+ diffuse.rgb,
+ specular.rgb,
+ vec3(1.0),
+ int(ssr_id),
+ roughness,
+ clearcoat_normal,
+ clearcoat * 0.25,
+ clearcoat_roughness,
+ occlusion,
+ true,
+ out_diff,
+ out_spec,
+ ssr_spec);
+
+ float alpha = 1.0 - transp;
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_diff * diffuse.rgb + out_spec + emissive.rgb;
+ result.radiance *= alpha;
+ result.transmittance = vec3(transp);
+
+ closure_load_ssr_data(ssr_spec * alpha, roughness, normal, viewCameraVec, int(ssr_id), result);
+}
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl
new file mode 100644
index 00000000000..092b9ed08bb
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl
@@ -0,0 +1,10 @@
+void node_emission(vec4 color, float strength, vec3 vN, out Closure result)
+{
+ result = CLOSURE_DEFAULT;
+#ifndef VOLUMETRICS
+ result.radiance = color.rgb * strength;
+ result.ssr_normal = normal_encode(vN, viewCameraVec);
+#else
+ result.emission = color.rgb * strength;
+#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl
new file mode 100644
index 00000000000..701b07b4aae
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl
@@ -0,0 +1,111 @@
+/* The fractal_noise functions are all exactly the same except for the input type. */
+float fractal_noise(float p, float octaves)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float sum = 0.0;
+ octaves = clamp(octaves, 0.0, 16.0);
+ int n = int(octaves);
+ for (int i = 0; i <= n; i++) {
+ float t = noise(fscale * p);
+ sum += t * amp;
+ amp *= 0.5;
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = noise(fscale * p);
+ float sum2 = sum + t * amp;
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
+ sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1));
+ return (1.0 - rmd) * sum + rmd * sum2;
+ }
+ else {
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
+ return sum;
+ }
+}
+
+/* The fractal_noise functions are all exactly the same except for the input type. */
+float fractal_noise(vec2 p, float octaves)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float sum = 0.0;
+ octaves = clamp(octaves, 0.0, 16.0);
+ int n = int(octaves);
+ for (int i = 0; i <= n; i++) {
+ float t = noise(fscale * p);
+ sum += t * amp;
+ amp *= 0.5;
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = noise(fscale * p);
+ float sum2 = sum + t * amp;
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
+ sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1));
+ return (1.0 - rmd) * sum + rmd * sum2;
+ }
+ else {
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
+ return sum;
+ }
+}
+
+/* The fractal_noise functions are all exactly the same except for the input type. */
+float fractal_noise(vec3 p, float octaves)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float sum = 0.0;
+ octaves = clamp(octaves, 0.0, 16.0);
+ int n = int(octaves);
+ for (int i = 0; i <= n; i++) {
+ float t = noise(fscale * p);
+ sum += t * amp;
+ amp *= 0.5;
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = noise(fscale * p);
+ float sum2 = sum + t * amp;
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
+ sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1));
+ return (1.0 - rmd) * sum + rmd * sum2;
+ }
+ else {
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
+ return sum;
+ }
+}
+
+/* The fractal_noise functions are all exactly the same except for the input type. */
+float fractal_noise(vec4 p, float octaves)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float sum = 0.0;
+ octaves = clamp(octaves, 0.0, 16.0);
+ int n = int(octaves);
+ for (int i = 0; i <= n; i++) {
+ float t = noise(fscale * p);
+ sum += t * amp;
+ amp *= 0.5;
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = noise(fscale * p);
+ float sum2 = sum + t * amp;
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
+ sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1));
+ return (1.0 - rmd) * sum + rmd * sum2;
+ }
+ else {
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
+ return sum;
+ }
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl
new file mode 100644
index 00000000000..7a4d28f2dd6
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl
@@ -0,0 +1,37 @@
+float fresnel_dielectric_cos(float cosi, float eta)
+{
+ /* compute fresnel reflectance without explicitly computing
+ * the refracted direction */
+ float c = abs(cosi);
+ float g = eta * eta - 1.0 + c * c;
+ float result;
+
+ if (g > 0.0) {
+ g = sqrt(g);
+ float A = (g - c) / (g + c);
+ float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0);
+ result = 0.5 * A * A * (1.0 + B * B);
+ }
+ else {
+ result = 1.0; /* TIR (no refracted component) */
+ }
+
+ return result;
+}
+
+float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
+{
+ /* compute fresnel reflectance without explicitly computing
+ * the refracted direction */
+ return fresnel_dielectric_cos(dot(Incoming, Normal), eta);
+}
+
+void node_fresnel(float ior, vec3 N, vec3 I, out float result)
+{
+ N = normalize(N);
+ /* handle perspective/orthographic */
+ vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
+
+ float eta = max(ior, 0.00001);
+ result = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? eta : 1.0 / eta);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl
new file mode 100644
index 00000000000..5733992f8dd
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl
@@ -0,0 +1,14 @@
+void node_gamma(vec4 col, float gamma, out vec4 outcol)
+{
+ outcol = col;
+
+ if (col.r > 0.0) {
+ outcol.r = compatible_pow(col.r, gamma);
+ }
+ if (col.g > 0.0) {
+ outcol.g = compatible_pow(col.g, gamma);
+ }
+ if (col.b > 0.0) {
+ outcol.b = compatible_pow(col.b, gamma);
+ }
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
new file mode 100644
index 00000000000..79614495499
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
@@ -0,0 +1,46 @@
+void node_geometry(vec3 I,
+ vec3 N,
+ vec3 orco,
+ mat4 objmat,
+ mat4 toworld,
+ vec2 barycentric,
+ out vec3 position,
+ out vec3 normal,
+ out vec3 tangent,
+ out vec3 true_normal,
+ out vec3 incoming,
+ out vec3 parametric,
+ out float backfacing,
+ out float pointiness)
+{
+ /* handle perspective/orthographic */
+ vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
+ incoming = -(toworld * vec4(I_view, 0.0)).xyz;
+
+#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
+ position = -incoming;
+ true_normal = normal = incoming;
+ tangent = parametric = vec3(0.0);
+ vec3(0.0);
+ backfacing = 0.0;
+ pointiness = 0.0;
+#else
+
+ position = worldPosition;
+# ifndef VOLUMETRICS
+ normal = normalize(N);
+ vec3 B = dFdx(worldPosition);
+ vec3 T = dFdy(worldPosition);
+ true_normal = normalize(cross(B, T));
+# else
+ normal = (toworld * vec4(N, 0.0)).xyz;
+ true_normal = normal;
+# endif
+ tangent_orco_z(orco, orco);
+ node_tangent(N, orco, objmat, tangent);
+
+ parametric = vec3(barycentric, 0.0);
+ backfacing = (gl_FrontFacing) ? 0.0 : 1.0;
+ pointiness = 0.5;
+#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl
new file mode 100644
index 00000000000..5038cb3892f
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl
@@ -0,0 +1,32 @@
+#ifndef VOLUMETRICS
+void node_bsdf_glass(
+ vec4 color, float roughness, float ior, vec3 N, float ssr_id, out Closure result)
+{
+ N = normalize(N);
+ vec3 out_spec, out_refr, ssr_spec;
+ vec3 refr_color = (refractionDepth > 0.0) ? color.rgb * color.rgb :
+ color.rgb; /* Simulate 2 transmission event */
+ eevee_closure_glass(N,
+ vec3(1.0),
+ vec3(1.0),
+ int(ssr_id),
+ roughness,
+ 1.0,
+ ior,
+ true,
+ out_spec,
+ out_refr,
+ ssr_spec);
+ out_refr *= refr_color;
+ out_spec *= color.rgb;
+ float fresnel = F_eta(ior, dot(N, cameraVec));
+ vec3 vN = mat3(ViewMatrix) * N;
+ result = CLOSURE_DEFAULT;
+ result.radiance = mix(out_refr, out_spec, fresnel);
+ closure_load_ssr_data(
+ ssr_spec * color.rgb * fresnel, roughness, N, viewCameraVec, int(ssr_id), result);
+}
+#else
+/* Stub glass because it is not compatible with volumetrics. */
+# define node_bsdf_glass
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl
new file mode 100644
index 00000000000..75cc2e770c5
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl
@@ -0,0 +1,16 @@
+#ifndef VOLUMETRICS
+void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Closure result)
+{
+ N = normalize(N);
+ vec3 out_spec, ssr_spec;
+ eevee_closure_glossy(
+ N, vec3(1.0), vec3(1.0), int(ssr_id), roughness, 1.0, true, out_spec, ssr_spec);
+ vec3 vN = mat3(ViewMatrix) * N;
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_spec * color.rgb;
+ closure_load_ssr_data(ssr_spec * color.rgb, roughness, N, viewCameraVec, int(ssr_id), result);
+}
+#else
+/* Stub glossy because it is not compatible with volumetrics. */
+# define node_bsdf_glossy
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
new file mode 100644
index 00000000000..3b23ac976ae
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
@@ -0,0 +1,21 @@
+void node_hair_info(out float is_strand,
+ out float intercept,
+ out float thickness,
+ out vec3 tangent,
+ out float random)
+{
+#ifdef HAIR_SHADER
+ is_strand = 1.0;
+ intercept = hairTime;
+ thickness = hairThickness;
+ tangent = normalize(worldNormal);
+ random = wang_hash_noise(
+ uint(hairStrandID)); /* TODO: could be precomputed per strand instead. */
+#else
+ is_strand = 0.0;
+ intercept = 0.0;
+ thickness = 0.0;
+ tangent = vec3(1.0);
+ random = 0.0;
+#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl
new file mode 100644
index 00000000000..86191451e5f
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl
@@ -0,0 +1,217 @@
+/* ***** Jenkins Lookup3 Hash Functions ***** */
+
+/* Source: http://burtleburtle.net/bob/c/lookup3.c */
+
+#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
+
+#define mix(a, b, c) \
+ { \
+ a -= c; \
+ a ^= rot(c, 4); \
+ c += b; \
+ b -= a; \
+ b ^= rot(a, 6); \
+ a += c; \
+ c -= b; \
+ c ^= rot(b, 8); \
+ b += a; \
+ a -= c; \
+ a ^= rot(c, 16); \
+ c += b; \
+ b -= a; \
+ b ^= rot(a, 19); \
+ a += c; \
+ c -= b; \
+ c ^= rot(b, 4); \
+ b += a; \
+ }
+
+#define final(a, b, c) \
+ { \
+ c ^= b; \
+ c -= rot(b, 14); \
+ a ^= c; \
+ a -= rot(c, 11); \
+ b ^= a; \
+ b -= rot(a, 25); \
+ c ^= b; \
+ c -= rot(b, 16); \
+ a ^= c; \
+ a -= rot(c, 4); \
+ b ^= a; \
+ b -= rot(a, 14); \
+ c ^= b; \
+ c -= rot(b, 24); \
+ }
+
+uint hash_uint(uint kx)
+{
+ uint a, b, c;
+ a = b = c = 0xdeadbeefu + (1u << 2u) + 13u;
+
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+uint hash_uint2(uint kx, uint ky)
+{
+ uint a, b, c;
+ a = b = c = 0xdeadbeefu + (2u << 2u) + 13u;
+
+ b += ky;
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+uint hash_uint3(uint kx, uint ky, uint kz)
+{
+ uint a, b, c;
+ a = b = c = 0xdeadbeefu + (3u << 2u) + 13u;
+
+ c += kz;
+ b += ky;
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+uint hash_uint4(uint kx, uint ky, uint kz, uint kw)
+{
+ uint a, b, c;
+ a = b = c = 0xdeadbeefu + (4u << 2u) + 13u;
+
+ a += kx;
+ b += ky;
+ c += kz;
+ mix(a, b, c);
+
+ a += kw;
+ final(a, b, c);
+
+ return c;
+}
+
+#undef rot
+#undef final
+#undef mix
+
+uint hash_int(int kx)
+{
+ return hash_uint(uint(kx));
+}
+
+uint hash_int2(int kx, int ky)
+{
+ return hash_uint2(uint(kx), uint(ky));
+}
+
+uint hash_int3(int kx, int ky, int kz)
+{
+ return hash_uint3(uint(kx), uint(ky), uint(kz));
+}
+
+uint hash_int4(int kx, int ky, int kz, int kw)
+{
+ return hash_uint4(uint(kx), uint(ky), uint(kz), uint(kw));
+}
+
+/* Hashing uint or uint[234] into a float in the range [0, 1]. */
+
+float hash_uint_to_float(uint kx)
+{
+ return float(hash_uint(kx)) / float(0xFFFFFFFFu);
+}
+
+float hash_uint2_to_float(uint kx, uint ky)
+{
+ return float(hash_uint2(kx, ky)) / float(0xFFFFFFFFu);
+}
+
+float hash_uint3_to_float(uint kx, uint ky, uint kz)
+{
+ return float(hash_uint3(kx, ky, kz)) / float(0xFFFFFFFFu);
+}
+
+float hash_uint4_to_float(uint kx, uint ky, uint kz, uint kw)
+{
+ return float(hash_uint4(kx, ky, kz, kw)) / float(0xFFFFFFFFu);
+}
+
+/* Hashing float or vec[234] into a float in the range [0, 1]. */
+
+float hash_float_to_float(float k)
+{
+ return hash_uint_to_float(floatBitsToUint(k));
+}
+
+float hash_vec2_to_float(vec2 k)
+{
+ return hash_uint2_to_float(floatBitsToUint(k.x), floatBitsToUint(k.y));
+}
+
+float hash_vec3_to_float(vec3 k)
+{
+ return hash_uint3_to_float(floatBitsToUint(k.x), floatBitsToUint(k.y), floatBitsToUint(k.z));
+}
+
+float hash_vec4_to_float(vec4 k)
+{
+ return hash_uint4_to_float(
+ floatBitsToUint(k.x), floatBitsToUint(k.y), floatBitsToUint(k.z), floatBitsToUint(k.w));
+}
+
+/* Hashing vec[234] into vec[234] of components in the range [0, 1]. */
+
+vec2 hash_vec2_to_vec2(vec2 k)
+{
+ return vec2(hash_vec2_to_float(k), hash_vec3_to_float(vec3(k, 1.0)));
+}
+
+vec3 hash_vec3_to_vec3(vec3 k)
+{
+ return vec3(
+ hash_vec3_to_float(k), hash_vec4_to_float(vec4(k, 1.0)), hash_vec4_to_float(vec4(k, 2.0)));
+}
+
+vec4 hash_vec4_to_vec4(vec4 k)
+{
+ return vec4(hash_vec4_to_float(k.xyzw),
+ hash_vec4_to_float(k.wxyz),
+ hash_vec4_to_float(k.zwxy),
+ hash_vec4_to_float(k.yzwx));
+}
+
+/* Hashing float or vec[234] into vec3 of components in range [0, 1]. */
+
+vec3 hash_float_to_vec3(float k)
+{
+ return vec3(
+ hash_float_to_float(k), hash_vec2_to_float(vec2(k, 1.0)), hash_vec2_to_float(vec2(k, 2.0)));
+}
+
+vec3 hash_vec2_to_vec3(vec2 k)
+{
+ return vec3(
+ hash_vec2_to_float(k), hash_vec3_to_float(vec3(k, 1.0)), hash_vec3_to_float(vec3(k, 2.0)));
+}
+
+vec3 hash_vec4_to_vec3(vec4 k)
+{
+ return vec3(hash_vec4_to_float(k.xyzw), hash_vec4_to_float(k.zxwy), hash_vec4_to_float(k.wzyx));
+}
+
+/* Other Hash Functions */
+
+float integer_noise(int n)
+{
+ int nn;
+ n = (n + 1013) & 0x7fffffff;
+ n = (n >> 13) ^ n;
+ nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
+ return 0.5 * (float(nn) / 1073741824.0);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl
new file mode 100644
index 00000000000..50ce2bf2ab8
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl
@@ -0,0 +1,8 @@
+void node_holdout(out Closure result)
+{
+ result = CLOSURE_DEFAULT;
+#ifndef VOLUMETRICS
+ result.holdout = 1.0;
+ result.flag = CLOSURE_HOLDOUT_FLAG;
+#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl
new file mode 100644
index 00000000000..64ac73ecdf3
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl
@@ -0,0 +1,14 @@
+void hue_sat(float hue, float sat, float value, float fac, vec4 col, out vec4 outcol)
+{
+ vec4 hsv;
+
+ rgb_to_hsv(col, hsv);
+
+ hsv[0] = fract(hsv[0] + hue + 0.5);
+ hsv[1] = clamp(hsv[1] * sat, 0.0, 1.0);
+ hsv[2] = hsv[2] * value;
+
+ hsv_to_rgb(hsv, outcol);
+
+ outcol = mix(col, outcol, fac);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_invert.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_invert.glsl
new file mode 100644
index 00000000000..5cf362a9947
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_invert.glsl
@@ -0,0 +1,5 @@
+void invert(float fac, vec4 col, out vec4 outcol)
+{
+ outcol.xyz = mix(col.xyz, vec3(1.0) - col.xyz, fac);
+ outcol.w = col.w;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl
new file mode 100644
index 00000000000..588d295bcc4
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl
@@ -0,0 +1,19 @@
+void node_layer_weight(float blend, vec3 N, vec3 I, out float fresnel, out float facing)
+{
+ N = normalize(N);
+
+ /* fresnel */
+ float eta = max(1.0 - blend, 0.00001);
+ vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
+
+ fresnel = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? 1.0 / eta : eta);
+
+ /* facing */
+ facing = abs(dot(I_view, N));
+ if (blend != 0.5) {
+ blend = clamp(blend, 0.0, 0.99999);
+ blend = (blend < 0.5) ? 2.0 * blend : 0.5 / (1.0 - blend);
+ facing = pow(facing, blend);
+ }
+ facing = 1.0 - facing;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl
new file mode 100644
index 00000000000..f3eae653f95
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl
@@ -0,0 +1,7 @@
+void node_light_falloff(
+ float strength, float tsmooth, out float quadratic, out float linear, out float constant)
+{
+ quadratic = strength;
+ linear = strength;
+ constant = strength;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl
new file mode 100644
index 00000000000..50c87e3f105
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl
@@ -0,0 +1,31 @@
+void node_light_path(out float is_camera_ray,
+ out float is_shadow_ray,
+ out float is_diffuse_ray,
+ out float is_glossy_ray,
+ out float is_singular_ray,
+ out float is_reflection_ray,
+ out float is_transmission_ray,
+ out float ray_length,
+ out float ray_depth,
+ out float diffuse_depth,
+ out float glossy_depth,
+ out float transparent_depth,
+ out float transmission_depth)
+{
+ /* Supported. */
+ is_camera_ray = (rayType == EEVEE_RAY_CAMERA) ? 1.0 : 0.0;
+ is_shadow_ray = (rayType == EEVEE_RAY_SHADOW) ? 1.0 : 0.0;
+ is_diffuse_ray = (rayType == EEVEE_RAY_DIFFUSE) ? 1.0 : 0.0;
+ is_glossy_ray = (rayType == EEVEE_RAY_GLOSSY) ? 1.0 : 0.0;
+ /* Kind of supported. */
+ is_singular_ray = is_glossy_ray;
+ is_reflection_ray = is_glossy_ray;
+ is_transmission_ray = is_glossy_ray;
+ ray_depth = rayDepth;
+ diffuse_depth = (is_diffuse_ray == 1.0) ? rayDepth : 0.0;
+ glossy_depth = (is_glossy_ray == 1.0) ? rayDepth : 0.0;
+ transmission_depth = (is_transmission_ray == 1.0) ? glossy_depth : 0.0;
+ /* Not supported. */
+ ray_length = 1.0;
+ transparent_depth = 0.0;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
new file mode 100644
index 00000000000..a185774f4b3
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
@@ -0,0 +1,10 @@
+void map_range(
+ float value, float fromMin, float fromMax, float toMin, float toMax, out float result)
+{
+ if (fromMax != fromMin) {
+ result = toMin + ((value - fromMin) / (fromMax - fromMin)) * (toMax - toMin);
+ }
+ else {
+ result = 0.0;
+ }
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl
new file mode 100644
index 00000000000..07f152439fe
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl
@@ -0,0 +1,27 @@
+void mapping_mat4(
+ vec3 vec, vec4 m0, vec4 m1, vec4 m2, vec4 m3, vec3 minvec, vec3 maxvec, out vec3 outvec)
+{
+ mat4 mat = mat4(m0, m1, m2, m3);
+ outvec = (mat * vec4(vec, 1.0)).xyz;
+ outvec = clamp(outvec, minvec, maxvec);
+}
+
+void mapping_point(vec3 vector, vec3 location, vec3 rotation, vec3 scale, out vec3 result)
+{
+ result = (euler_to_mat3(rotation) * (vector * scale)) + location;
+}
+
+void mapping_texture(vec3 vector, vec3 location, vec3 rotation, vec3 scale, out vec3 result)
+{
+ result = safe_divide(transpose(euler_to_mat3(rotation)) * (vector - location), scale);
+}
+
+void mapping_vector(vec3 vector, vec3 location, vec3 rotation, vec3 scale, out vec3 result)
+{
+ result = euler_to_mat3(rotation) * (vector * scale);
+}
+
+void mapping_normal(vec3 vector, vec3 location, vec3 rotation, vec3 scale, out vec3 result)
+{
+ result = normalize(euler_to_mat3(rotation) * safe_divide(vector, scale));
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl
new file mode 100644
index 00000000000..4fac770e8fe
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl
@@ -0,0 +1,130 @@
+void math_add(float a, float b, out float result)
+{
+ result = a + b;
+}
+
+void math_subtract(float a, float b, out float result)
+{
+ result = a - b;
+}
+
+void math_multiply(float a, float b, out float result)
+{
+ result = a * b;
+}
+
+void math_divide(float a, float b, out float result)
+{
+ result = safe_divide(a, b);
+}
+
+void math_power(float a, float b, out float result)
+{
+ if (a >= 0.0) {
+ result = compatible_pow(a, b);
+ }
+ else {
+ float fraction = mod(abs(b), 1.0);
+ if (fraction > 0.999 || fraction < 0.001) {
+ result = compatible_pow(a, floor(b + 0.5));
+ }
+ else {
+ result = 0.0;
+ }
+ }
+}
+
+void math_logarithm(float a, float b, out float result)
+{
+ result = (a > 0.0 && b > 0.0) ? log2(a) / log2(b) : 0.0;
+}
+
+void math_sqrt(float a, float b, out float result)
+{
+ result = (a > 0.0) ? sqrt(a) : 0.0;
+}
+
+void math_absolute(float a, float b, out float result)
+{
+ result = abs(a);
+}
+
+void math_minimum(float a, float b, out float result)
+{
+ result = min(a, b);
+}
+
+void math_maximum(float a, float b, out float result)
+{
+ result = max(a, b);
+}
+
+void math_less_than(float a, float b, out float result)
+{
+ result = (a < b) ? 1.0 : 0.0;
+}
+
+void math_greater_than(float a, float b, out float result)
+{
+ result = (a > b) ? 1.0 : 0.0;
+}
+
+void math_round(float a, float b, out float result)
+{
+ result = floor(a + 0.5);
+}
+
+void math_floor(float a, float b, out float result)
+{
+ result = floor(a);
+}
+
+void math_ceil(float a, float b, out float result)
+{
+ result = ceil(a);
+}
+
+void math_fraction(float a, float b, out float result)
+{
+ result = a - floor(a);
+}
+
+void math_modulo(float a, float b, out float result)
+{
+ result = c_mod(a, b);
+}
+
+void math_sine(float a, float b, out float result)
+{
+ result = sin(a);
+}
+
+void math_cosine(float a, float b, out float result)
+{
+ result = cos(a);
+}
+
+void math_tangent(float a, float b, out float result)
+{
+ result = tan(a);
+}
+
+void math_arcsine(float a, float b, out float result)
+{
+ result = (a <= 1.0 && a >= -1.0) ? asin(a) : 0.0;
+}
+
+void math_arccosine(float a, float b, out float result)
+{
+ result = (a <= 1.0 && a >= -1.0) ? acos(a) : 0.0;
+}
+
+void math_arctangent(float a, float b, out float result)
+{
+ result = atan(a);
+}
+
+void math_arctan2(float a, float b, out float result)
+{
+ result = atan(a, b);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
new file mode 100644
index 00000000000..d4f7866b206
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
@@ -0,0 +1,151 @@
+/* Float Math */
+
+float safe_divide(float a, float b)
+{
+ return (b != 0.0) ? a / b : 0.0;
+}
+
+/* Modulo with C sign convention. mod in GLSL will take absolute for negative numbers. */
+float c_mod(float a, float b)
+{
+ return (b != 0.0 && a != b) ? sign(a) * mod(abs(a), b) : 0.0;
+}
+
+float compatible_pow(float x, float y)
+{
+ if (y == 0.0) { /* x^0 -> 1, including 0^0 */
+ return 1.0;
+ }
+
+ /* glsl pow doesn't accept negative x */
+ if (x < 0.0) {
+ if (mod(-y, 2.0) == 0.0) {
+ return pow(-x, y);
+ }
+ else {
+ return -pow(-x, y);
+ }
+ }
+ else if (x == 0.0) {
+ return 0.0;
+ }
+
+ return pow(x, y);
+}
+
+float hypot(float x, float y)
+{
+ return sqrt(x * x + y * y);
+}
+
+int floor_to_int(float x)
+{
+ return int(floor(x));
+}
+
+int quick_floor(float x)
+{
+ return int(x) - ((x < 0) ? 1 : 0);
+}
+
+float floorfrac(float x, out int i)
+{
+ float x_floor = floor(x);
+ i = int(x_floor);
+ return x - x_floor;
+}
+
+/* Vector Math */
+
+vec2 safe_divide(vec2 a, vec2 b)
+{
+ return vec2(safe_divide(a.x, b.x), safe_divide(a.y, b.y));
+}
+
+vec3 safe_divide(vec3 a, vec3 b)
+{
+ return vec3(safe_divide(a.x, b.x), safe_divide(a.y, b.y), safe_divide(a.z, b.z));
+}
+
+vec4 safe_divide(vec4 a, vec4 b)
+{
+ return vec4(
+ safe_divide(a.x, b.x), safe_divide(a.y, b.y), safe_divide(a.z, b.z), safe_divide(a.w, b.w));
+}
+
+vec2 safe_divide(vec2 a, float b)
+{
+ return (b != 0.0) ? a / b : vec2(0.0);
+}
+
+vec3 safe_divide(vec3 a, float b)
+{
+ return (b != 0.0) ? a / b : vec3(0.0);
+}
+
+vec4 safe_divide(vec4 a, float b)
+{
+ return (b != 0.0) ? a / b : vec4(0.0);
+}
+
+vec3 c_mod(vec3 a, vec3 b)
+{
+ return vec3(c_mod(a.x, b.x), c_mod(a.y, b.y), c_mod(a.z, b.z));
+}
+
+void vector_mix(float strength, vec3 a, vec3 b, out vec3 outVector)
+{
+ outVector = strength * a + (1 - strength) * b;
+}
+
+void invert_z(vec3 v, out vec3 outv)
+{
+ v.z = -v.z;
+ outv = v;
+}
+
+void vector_normalize(vec3 normal, out vec3 outnormal)
+{
+ outnormal = normalize(normal);
+}
+
+/* Matirx Math */
+
+mat3 euler_to_mat3(vec3 euler)
+{
+ float cx = cos(euler.x);
+ float cy = cos(euler.y);
+ float cz = cos(euler.z);
+ float sx = sin(euler.x);
+ float sy = sin(euler.y);
+ float sz = sin(euler.z);
+
+ mat3 mat;
+ mat[0][0] = cy * cz;
+ mat[0][1] = cy * sz;
+ mat[0][2] = -sy;
+
+ mat[1][0] = sy * sx * cz - cx * sz;
+ mat[1][1] = sy * sx * sz + cx * cz;
+ mat[1][2] = cy * sx;
+
+ mat[2][0] = sy * cx * cz + sx * sz;
+ mat[2][1] = sy * cx * sz - sx * cz;
+ mat[2][2] = cy * cx;
+ return mat;
+}
+
+void direction_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
+{
+ vout = (mat * vec4(vin, 0.0)).xyz;
+}
+
+void normal_transform_transposed_m4v3(vec3 vin, mat4 mat, out vec3 vout)
+{
+ vout = transpose(mat3(mat)) * vin;
+}
+
+void point_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
+{
+ vout = (mat * vec4(vin, 1.0)).xyz;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl
new file mode 100644
index 00000000000..abe6081489d
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl
@@ -0,0 +1,291 @@
+void mix_blend(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ outcol = mix(col1, col2, fac);
+ outcol.a = col1.a;
+}
+
+void mix_add(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ outcol = mix(col1, col1 + col2, fac);
+ outcol.a = col1.a;
+}
+
+void mix_mult(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ outcol = mix(col1, col1 * col2, fac);
+ outcol.a = col1.a;
+}
+
+void mix_screen(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ float facm = 1.0 - fac;
+
+ outcol = vec4(1.0) - (vec4(facm) + fac * (vec4(1.0) - col2)) * (vec4(1.0) - col1);
+ outcol.a = col1.a;
+}
+
+void mix_overlay(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ float facm = 1.0 - fac;
+
+ outcol = col1;
+
+ if (outcol.r < 0.5) {
+ outcol.r *= facm + 2.0 * fac * col2.r;
+ }
+ else {
+ outcol.r = 1.0 - (facm + 2.0 * fac * (1.0 - col2.r)) * (1.0 - outcol.r);
+ }
+
+ if (outcol.g < 0.5) {
+ outcol.g *= facm + 2.0 * fac * col2.g;
+ }
+ else {
+ outcol.g = 1.0 - (facm + 2.0 * fac * (1.0 - col2.g)) * (1.0 - outcol.g);
+ }
+
+ if (outcol.b < 0.5) {
+ outcol.b *= facm + 2.0 * fac * col2.b;
+ }
+ else {
+ outcol.b = 1.0 - (facm + 2.0 * fac * (1.0 - col2.b)) * (1.0 - outcol.b);
+ }
+}
+
+void mix_sub(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ outcol = mix(col1, col1 - col2, fac);
+ outcol.a = col1.a;
+}
+
+void mix_div(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ float facm = 1.0 - fac;
+
+ outcol = col1;
+
+ if (col2.r != 0.0) {
+ outcol.r = facm * outcol.r + fac * outcol.r / col2.r;
+ }
+ if (col2.g != 0.0) {
+ outcol.g = facm * outcol.g + fac * outcol.g / col2.g;
+ }
+ if (col2.b != 0.0) {
+ outcol.b = facm * outcol.b + fac * outcol.b / col2.b;
+ }
+}
+
+void mix_diff(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ outcol = mix(col1, abs(col1 - col2), fac);
+ outcol.a = col1.a;
+}
+
+void mix_dark(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ outcol.rgb = min(col1.rgb, col2.rgb * fac);
+ outcol.a = col1.a;
+}
+
+void mix_light(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ outcol.rgb = max(col1.rgb, col2.rgb * fac);
+ outcol.a = col1.a;
+}
+
+void mix_dodge(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ outcol = col1;
+
+ if (outcol.r != 0.0) {
+ float tmp = 1.0 - fac * col2.r;
+ if (tmp <= 0.0) {
+ outcol.r = 1.0;
+ }
+ else if ((tmp = outcol.r / tmp) > 1.0) {
+ outcol.r = 1.0;
+ }
+ else {
+ outcol.r = tmp;
+ }
+ }
+ if (outcol.g != 0.0) {
+ float tmp = 1.0 - fac * col2.g;
+ if (tmp <= 0.0) {
+ outcol.g = 1.0;
+ }
+ else if ((tmp = outcol.g / tmp) > 1.0) {
+ outcol.g = 1.0;
+ }
+ else {
+ outcol.g = tmp;
+ }
+ }
+ if (outcol.b != 0.0) {
+ float tmp = 1.0 - fac * col2.b;
+ if (tmp <= 0.0) {
+ outcol.b = 1.0;
+ }
+ else if ((tmp = outcol.b / tmp) > 1.0) {
+ outcol.b = 1.0;
+ }
+ else {
+ outcol.b = tmp;
+ }
+ }
+}
+
+void mix_burn(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ float tmp, facm = 1.0 - fac;
+
+ outcol = col1;
+
+ tmp = facm + fac * col2.r;
+ if (tmp <= 0.0) {
+ outcol.r = 0.0;
+ }
+ else if ((tmp = (1.0 - (1.0 - outcol.r) / tmp)) < 0.0) {
+ outcol.r = 0.0;
+ }
+ else if (tmp > 1.0) {
+ outcol.r = 1.0;
+ }
+ else {
+ outcol.r = tmp;
+ }
+
+ tmp = facm + fac * col2.g;
+ if (tmp <= 0.0) {
+ outcol.g = 0.0;
+ }
+ else if ((tmp = (1.0 - (1.0 - outcol.g) / tmp)) < 0.0) {
+ outcol.g = 0.0;
+ }
+ else if (tmp > 1.0) {
+ outcol.g = 1.0;
+ }
+ else {
+ outcol.g = tmp;
+ }
+
+ tmp = facm + fac * col2.b;
+ if (tmp <= 0.0) {
+ outcol.b = 0.0;
+ }
+ else if ((tmp = (1.0 - (1.0 - outcol.b) / tmp)) < 0.0) {
+ outcol.b = 0.0;
+ }
+ else if (tmp > 1.0) {
+ outcol.b = 1.0;
+ }
+ else {
+ outcol.b = tmp;
+ }
+}
+
+void mix_hue(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ float facm = 1.0 - fac;
+
+ outcol = col1;
+
+ vec4 hsv, hsv2, tmp;
+ rgb_to_hsv(col2, hsv2);
+
+ if (hsv2.y != 0.0) {
+ rgb_to_hsv(outcol, hsv);
+ hsv.x = hsv2.x;
+ hsv_to_rgb(hsv, tmp);
+
+ outcol = mix(outcol, tmp, fac);
+ outcol.a = col1.a;
+ }
+}
+
+void mix_sat(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ float facm = 1.0 - fac;
+
+ outcol = col1;
+
+ vec4 hsv, hsv2;
+ rgb_to_hsv(outcol, hsv);
+
+ if (hsv.y != 0.0) {
+ rgb_to_hsv(col2, hsv2);
+
+ hsv.y = facm * hsv.y + fac * hsv2.y;
+ hsv_to_rgb(hsv, outcol);
+ }
+}
+
+void mix_val(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ float facm = 1.0 - fac;
+
+ vec4 hsv, hsv2;
+ rgb_to_hsv(col1, hsv);
+ rgb_to_hsv(col2, hsv2);
+
+ hsv.z = facm * hsv.z + fac * hsv2.z;
+ hsv_to_rgb(hsv, outcol);
+}
+
+void mix_color(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ float facm = 1.0 - fac;
+
+ outcol = col1;
+
+ vec4 hsv, hsv2, tmp;
+ rgb_to_hsv(col2, hsv2);
+
+ if (hsv2.y != 0.0) {
+ rgb_to_hsv(outcol, hsv);
+ hsv.x = hsv2.x;
+ hsv.y = hsv2.y;
+ hsv_to_rgb(hsv, tmp);
+
+ outcol = mix(outcol, tmp, fac);
+ outcol.a = col1.a;
+ }
+}
+
+void mix_soft(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ float facm = 1.0 - fac;
+
+ vec4 one = vec4(1.0);
+ vec4 scr = one - (one - col2) * (one - col1);
+ outcol = facm * col1 + fac * ((one - col1) * col2 * col1 + col1 * scr);
+}
+
+void mix_linear(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+
+ outcol = col1 + fac * (2.0 * (col2 - vec4(0.5)));
+}
+
+void clamp_color(vec3 vec, vec3 min, vec3 max, out vec3 out_vec)
+{
+ out_vec = clamp(vec, min, max);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl
new file mode 100644
index 00000000000..c303d21d7c1
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl
@@ -0,0 +1,4 @@
+void node_mix_shader(float fac, Closure shader1, Closure shader2, out Closure shader)
+{
+ shader = closure_mix(shader1, shader2, fac);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl
new file mode 100644
index 00000000000..c184c61c269
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl
@@ -0,0 +1,294 @@
+/* Bilinear Interpolation:
+ *
+ * v2 v3
+ * @ + + + + @ y
+ * + + ^
+ * + + |
+ * + + |
+ * @ + + + + @ @------> x
+ * v0 v1
+ *
+ */
+float bi_mix(float v0, float v1, float v2, float v3, float x, float y)
+{
+ float x1 = 1.0 - x;
+ return (1.0 - y) * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x);
+}
+
+/* Trilinear Interpolation:
+ *
+ * v6 v7
+ * @ + + + + + + @
+ * +\ +\
+ * + \ + \
+ * + \ + \
+ * + \ v4 + \ v5
+ * + @ + + + +++ + @ z
+ * + + + + y ^
+ * v2 @ + +++ + + + @ v3 + \ |
+ * \ + \ + \ |
+ * \ + \ + \|
+ * \ + \ + +---------> x
+ * \+ \+
+ * @ + + + + + + @
+ * v0 v1
+ */
+float tri_mix(float v0,
+ float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6,
+ float v7,
+ float x,
+ float y,
+ float z)
+{
+ float x1 = 1.0 - x;
+ float y1 = 1.0 - y;
+ float z1 = 1.0 - z;
+ return z1 * (y1 * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x)) +
+ z * (y1 * (v4 * x1 + v5 * x) + y * (v6 * x1 + v7 * x));
+}
+
+float quad_mix(float v0,
+ float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6,
+ float v7,
+ float v8,
+ float v9,
+ float v10,
+ float v11,
+ float v12,
+ float v13,
+ float v14,
+ float v15,
+ float x,
+ float y,
+ float z,
+ float w)
+{
+ return mix(tri_mix(v0, v1, v2, v3, v4, v5, v6, v7, x, y, z),
+ tri_mix(v8, v9, v10, v11, v12, v13, v14, v15, x, y, z),
+ w);
+}
+
+float fade(float t)
+{
+ return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
+}
+
+float negate_if(float value, uint condition)
+{
+ return (condition != 0u) ? -value : value;
+}
+
+float noise_grad(uint hash, float x)
+{
+ uint h = hash & 15u;
+ float g = 1u + (h & 7u);
+ return negate_if(g, h & 8u) * x;
+}
+
+float noise_grad(uint hash, float x, float y)
+{
+ uint h = hash & 7u;
+ float u = h < 4u ? x : y;
+ float v = 2.0 * (h < 4u ? y : x);
+ return negate_if(u, h & 1u) + negate_if(v, h & 2u);
+}
+
+float noise_grad(uint hash, float x, float y, float z)
+{
+ uint h = hash & 15u;
+ float u = h < 8u ? x : y;
+ float vt = ((h == 12u) || (h == 14u)) ? x : z;
+ float v = h < 4u ? y : vt;
+ return negate_if(u, h & 1u) + negate_if(v, h & 2u);
+}
+
+float noise_grad(uint hash, float x, float y, float z, float w)
+{
+ uint h = hash & 31u;
+ float u = h < 24u ? x : y;
+ float v = h < 16u ? y : z;
+ float s = h < 8u ? z : w;
+ return negate_if(u, h & 1u) + negate_if(v, h & 2u) + negate_if(s, h & 4u);
+}
+
+float noise_perlin(float x)
+{
+ int X;
+ float fx = floorfrac(x, X);
+ float u = fade(fx);
+
+ float r = mix(noise_grad(hash_int(X), fx), noise_grad(hash_int(X + 1), fx - 1.0), u);
+
+ return r;
+}
+
+float noise_perlin(vec2 vec)
+{
+ int X;
+ int Y;
+
+ float fx = floorfrac(vec.x, X);
+ float fy = floorfrac(vec.y, Y);
+
+ float u = fade(fx);
+ float v = fade(fy);
+
+ float r = bi_mix(noise_grad(hash_int2(X, Y), fx, fy),
+ noise_grad(hash_int2(X + 1, Y), fx - 1.0, fy),
+ noise_grad(hash_int2(X, Y + 1), fx, fy - 1.0),
+ noise_grad(hash_int2(X + 1, Y + 1), fx - 1.0, fy - 1.0),
+ u,
+ v);
+
+ return r;
+}
+
+float noise_perlin(vec3 vec)
+{
+ int X;
+ int Y;
+ int Z;
+
+ float fx = floorfrac(vec.x, X);
+ float fy = floorfrac(vec.y, Y);
+ float fz = floorfrac(vec.z, Z);
+
+ float u = fade(fx);
+ float v = fade(fy);
+ float w = fade(fz);
+
+ float r = tri_mix(noise_grad(hash_int3(X, Y, Z), fx, fy, fz),
+ noise_grad(hash_int3(X + 1, Y, Z), fx - 1, fy, fz),
+ noise_grad(hash_int3(X, Y + 1, Z), fx, fy - 1, fz),
+ noise_grad(hash_int3(X + 1, Y + 1, Z), fx - 1, fy - 1, fz),
+ noise_grad(hash_int3(X, Y, Z + 1), fx, fy, fz - 1),
+ noise_grad(hash_int3(X + 1, Y, Z + 1), fx - 1, fy, fz - 1),
+ noise_grad(hash_int3(X, Y + 1, Z + 1), fx, fy - 1, fz - 1),
+ noise_grad(hash_int3(X + 1, Y + 1, Z + 1), fx - 1, fy - 1, fz - 1),
+ u,
+ v,
+ w);
+
+ return r;
+}
+
+float noise_perlin(vec4 vec)
+{
+ int X;
+ int Y;
+ int Z;
+ int W;
+
+ float fx = floorfrac(vec.x, X);
+ float fy = floorfrac(vec.y, Y);
+ float fz = floorfrac(vec.z, Z);
+ float fw = floorfrac(vec.w, W);
+
+ float u = fade(fx);
+ float v = fade(fy);
+ float t = fade(fz);
+ float s = fade(fw);
+
+ float r = quad_mix(
+ noise_grad(hash_int4(X, Y, Z, W), fx, fy, fz, fw),
+ noise_grad(hash_int4(X + 1, Y, Z, W), fx - 1.0, fy, fz, fw),
+ noise_grad(hash_int4(X, Y + 1, Z, W), fx, fy - 1.0, fz, fw),
+ noise_grad(hash_int4(X + 1, Y + 1, Z, W), fx - 1.0, fy - 1.0, fz, fw),
+ noise_grad(hash_int4(X, Y, Z + 1, W), fx, fy, fz - 1.0, fw),
+ noise_grad(hash_int4(X + 1, Y, Z + 1, W), fx - 1.0, fy, fz - 1.0, fw),
+ noise_grad(hash_int4(X, Y + 1, Z + 1, W), fx, fy - 1.0, fz - 1.0, fw),
+ noise_grad(hash_int4(X + 1, Y + 1, Z + 1, W), fx - 1.0, fy - 1.0, fz - 1.0, fw),
+ noise_grad(hash_int4(X, Y, Z, W + 1), fx, fy, fz, fw - 1.0),
+ noise_grad(hash_int4(X + 1, Y, Z, W + 1), fx - 1.0, fy, fz, fw - 1.0),
+ noise_grad(hash_int4(X, Y + 1, Z, W + 1), fx, fy - 1.0, fz, fw - 1.0),
+ noise_grad(hash_int4(X + 1, Y + 1, Z, W + 1), fx - 1.0, fy - 1.0, fz, fw - 1.0),
+ noise_grad(hash_int4(X, Y, Z + 1, W + 1), fx, fy, fz - 1.0, fw - 1.0),
+ noise_grad(hash_int4(X + 1, Y, Z + 1, W + 1), fx - 1.0, fy, fz - 1.0, fw - 1.0),
+ noise_grad(hash_int4(X, Y + 1, Z + 1, W + 1), fx, fy - 1.0, fz - 1.0, fw - 1.0),
+ noise_grad(hash_int4(X + 1, Y + 1, Z + 1, W + 1), fx - 1.0, fy - 1.0, fz - 1.0, fw - 1.0),
+ u,
+ v,
+ t,
+ s);
+
+ return r;
+}
+
+/* Remap the output of noise to a predictable range [-1, 1].
+ * The scale values were computed experimentally by the OSL developers.
+ */
+float noise_scale1(float result)
+{
+ return 0.2500 * result;
+}
+
+float noise_scale2(float result)
+{
+ return 0.6616 * result;
+}
+
+float noise_scale3(float result)
+{
+ return 0.9820 * result;
+}
+
+float noise_scale4(float result)
+{
+ return 0.8344 * result;
+}
+
+/* Safe Signed And Unsigned Noise */
+
+float snoise(float p)
+{
+ float r = noise_perlin(p);
+ return (isinf(r)) ? 0.0 : noise_scale1(r);
+}
+
+float noise(float p)
+{
+ return 0.5 * snoise(p) + 0.5;
+}
+
+float snoise(vec2 p)
+{
+ float r = noise_perlin(p);
+ return (isinf(r)) ? 0.0 : noise_scale2(r);
+}
+
+float noise(vec2 p)
+{
+ return 0.5 * snoise(p) + 0.5;
+}
+
+float snoise(vec3 p)
+{
+ float r = noise_perlin(p);
+ return (isinf(r)) ? 0.0 : noise_scale3(r);
+}
+
+float noise(vec3 p)
+{
+ return 0.5 * snoise(p) + 0.5;
+}
+
+float snoise(vec4 p)
+{
+ float r = noise_perlin(p);
+ return (isinf(r)) ? 0.0 : noise_scale4(r);
+}
+
+float noise(vec4 p)
+{
+ return 0.5 * snoise(p) + 0.5;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_normal.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_normal.glsl
new file mode 100644
index 00000000000..4f6e68909ad
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_normal.glsl
@@ -0,0 +1,5 @@
+void normal_new_shading(vec3 nor, vec3 dir, out vec3 outnor, out float outdot)
+{
+ outnor = dir;
+ outdot = dot(normalize(nor), dir);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl
new file mode 100644
index 00000000000..6930e0c5dad
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl
@@ -0,0 +1,22 @@
+void node_normal_map(vec4 info, vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnormal)
+{
+ if (all(equal(tangent, vec4(0.0, 0.0, 0.0, 1.0)))) {
+ outnormal = normal;
+ return;
+ }
+ tangent *= (gl_FrontFacing ? 1.0 : -1.0);
+ vec3 B = tangent.w * cross(normal, tangent.xyz) * info.w;
+
+ outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * normal;
+ outnormal = normalize(outnormal);
+}
+
+void color_to_normal_new_shading(vec3 color, out vec3 normal)
+{
+ normal = vec3(2.0) * color - vec3(1.0);
+}
+
+void color_to_blender_normal_new_shading(vec3 color, out vec3 normal)
+{
+ normal = vec3(2.0, -2.0, -2.0) * color - vec3(1.0);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl
new file mode 100644
index 00000000000..ff77b0beea2
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl
@@ -0,0 +1,16 @@
+void node_object_info(mat4 obmat,
+ vec4 obcolor,
+ vec4 info,
+ float mat_index,
+ out vec3 location,
+ out vec4 color,
+ out float object_index,
+ out float material_index,
+ out float random)
+{
+ location = obmat[3].xyz;
+ color = obcolor;
+ object_index = info.x;
+ material_index = mat_index;
+ random = info.z;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl
new file mode 100644
index 00000000000..62f76d46088
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl
@@ -0,0 +1,8 @@
+void node_output_material(Closure surface, Closure volume, vec3 displacement, out Closure result)
+{
+#ifdef VOLUMETRICS
+ result = volume;
+#else
+ result = surface;
+#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl
new file mode 100644
index 00000000000..ba391df185e
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl
@@ -0,0 +1,11 @@
+uniform float backgroundAlpha;
+
+void node_output_world(Closure surface, Closure volume, out Closure result)
+{
+#ifndef VOLUMETRICS
+ result.radiance = surface.radiance * backgroundAlpha;
+ result.transmittance = vec3(1.0 - backgroundAlpha);
+#else
+ result = volume;
+#endif /* VOLUMETRICS */
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl
new file mode 100644
index 00000000000..bdd60c20a81
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl
@@ -0,0 +1,23 @@
+void particle_info(vec4 sprops,
+ vec4 loc,
+ vec3 vel,
+ vec3 avel,
+ out float index,
+ out float random,
+ out float age,
+ out float life_time,
+ out vec3 location,
+ out float size,
+ out vec3 velocity,
+ out vec3 angular_velocity)
+{
+ index = sprops.x;
+ random = loc.w;
+ age = sprops.y;
+ life_time = sprops.z;
+ size = sprops.w;
+
+ location = loc.xyz;
+ velocity = vel;
+ angular_velocity = avel;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
new file mode 100644
index 00000000000..140213a9ed9
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
@@ -0,0 +1,418 @@
+#ifndef VOLUMETRICS
+vec3 tint_from_color(vec3 color)
+{
+ float lum = dot(color, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
+ return (lum > 0) ? color / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */
+}
+
+void convert_metallic_to_specular_tinted(vec3 basecol,
+ vec3 basecol_tint,
+ float metallic,
+ float specular_fac,
+ float specular_tint,
+ out vec3 diffuse,
+ out vec3 f0)
+{
+ vec3 tmp_col = mix(vec3(1.0), basecol_tint, specular_tint);
+ f0 = mix((0.08 * specular_fac) * tmp_col, basecol, metallic);
+ diffuse = basecol * (1.0 - metallic);
+}
+
+vec3 principled_sheen(float NV, vec3 basecol_tint, float sheen_tint)
+{
+ float f = 1.0 - NV;
+ /* Temporary fix for T59784. Normal map seems to contain NaNs for tangent space normal maps,
+ * therefore we need to clamp value. */
+ f = clamp(f, 0.0, 1.0);
+ /* Empirical approximation (manual curve fitting). Can be refined. */
+ float sheen = f * f * f * 0.077 + f * 0.01 + 0.00026;
+ return sheen * mix(vec3(1.0), basecol_tint, sheen_tint);
+}
+
+void node_bsdf_principled(vec4 base_color,
+ float subsurface,
+ vec3 subsurface_radius,
+ vec4 subsurface_color,
+ float metallic,
+ float specular,
+ float specular_tint,
+ float roughness,
+ float anisotropic,
+ float anisotropic_rotation,
+ float sheen,
+ float sheen_tint,
+ float clearcoat,
+ float clearcoat_roughness,
+ float ior,
+ float transmission,
+ float transmission_roughness,
+ vec4 emission,
+ float alpha,
+ vec3 N,
+ vec3 CN,
+ vec3 T,
+ vec3 I,
+ float ssr_id,
+ float sss_id,
+ vec3 sss_scale,
+ out Closure result)
+{
+ N = normalize(N);
+ ior = max(ior, 1e-5);
+ metallic = saturate(metallic);
+ transmission = saturate(transmission);
+ float dielectric = 1.0 - metallic;
+ transmission *= dielectric;
+ sheen *= dielectric;
+ subsurface_color *= dielectric;
+
+ vec3 diffuse, f0, out_diff, out_spec, out_refr, ssr_spec;
+ vec3 ctint = tint_from_color(base_color.rgb);
+ convert_metallic_to_specular_tinted(
+ base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
+
+ float NV = dot(N, cameraVec);
+ vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
+
+ /* Far from being accurate, but 2 glossy evaluation is too expensive.
+ * Most noticeable difference is at grazing angles since the bsdf lut
+ * f0 color interpolation is done on top of this interpolation. */
+ vec3 f0_glass = mix(vec3(1.0), base_color.rgb, specular_tint);
+ float fresnel = F_eta(ior, NV);
+ vec3 spec_col = F_color_blend(ior, fresnel, f0_glass) * fresnel;
+ f0 = mix(f0, spec_col, transmission);
+
+ vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic);
+
+ vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
+
+ float sss_scalef = avg(sss_scale) * subsurface;
+ eevee_closure_principled(N,
+ mixed_ss_base_color,
+ f0,
+ f90,
+ int(ssr_id),
+ roughness,
+ CN,
+ clearcoat * 0.25,
+ clearcoat_roughness,
+ 1.0,
+ sss_scalef,
+ ior,
+ true,
+ out_diff,
+ out_spec,
+ out_refr,
+ ssr_spec);
+
+ vec3 refr_color = base_color.rgb;
+ refr_color *= (refractionDepth > 0.0) ? refr_color :
+ vec3(1.0); /* Simulate 2 transmission event */
+ out_refr *= refr_color * (1.0 - fresnel) * transmission;
+
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_spec + out_refr;
+ result.radiance += out_diff * out_sheen; /* Coarse approx. */
+
+ closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
+
+ mixed_ss_base_color *= alpha * (1.0 - transmission);
+ closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result);
+
+ result.radiance += emission.rgb;
+ result.radiance *= alpha;
+ result.transmittance = vec3(1.0 - alpha);
+}
+
+void node_bsdf_principled_dielectric(vec4 base_color,
+ float subsurface,
+ vec3 subsurface_radius,
+ vec4 subsurface_color,
+ float metallic,
+ float specular,
+ float specular_tint,
+ float roughness,
+ float anisotropic,
+ float anisotropic_rotation,
+ float sheen,
+ float sheen_tint,
+ float clearcoat,
+ float clearcoat_roughness,
+ float ior,
+ float transmission,
+ float transmission_roughness,
+ vec4 emission,
+ float alpha,
+ vec3 N,
+ vec3 CN,
+ vec3 T,
+ vec3 I,
+ float ssr_id,
+ float sss_id,
+ vec3 sss_scale,
+ out Closure result)
+{
+ N = normalize(N);
+ metallic = saturate(metallic);
+ float dielectric = 1.0 - metallic;
+
+ vec3 diffuse, f0, out_diff, out_spec, ssr_spec;
+ vec3 ctint = tint_from_color(base_color.rgb);
+ convert_metallic_to_specular_tinted(
+ base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
+
+ float NV = dot(N, cameraVec);
+ vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
+
+ eevee_closure_default(
+ N, diffuse, f0, vec3(1.0), int(ssr_id), roughness, 1.0, true, out_diff, out_spec, ssr_spec);
+
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_spec + out_diff * (diffuse + out_sheen);
+ closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
+ result.radiance += emission.rgb;
+ result.radiance *= alpha;
+ result.transmittance = vec3(1.0 - alpha);
+}
+
+void node_bsdf_principled_metallic(vec4 base_color,
+ float subsurface,
+ vec3 subsurface_radius,
+ vec4 subsurface_color,
+ float metallic,
+ float specular,
+ float specular_tint,
+ float roughness,
+ float anisotropic,
+ float anisotropic_rotation,
+ float sheen,
+ float sheen_tint,
+ float clearcoat,
+ float clearcoat_roughness,
+ float ior,
+ float transmission,
+ float transmission_roughness,
+ vec4 emission,
+ float alpha,
+ vec3 N,
+ vec3 CN,
+ vec3 T,
+ vec3 I,
+ float ssr_id,
+ float sss_id,
+ vec3 sss_scale,
+ out Closure result)
+{
+ N = normalize(N);
+ vec3 out_spec, ssr_spec;
+
+ vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
+
+ eevee_closure_glossy(
+ N, base_color.rgb, f90, int(ssr_id), roughness, 1.0, true, out_spec, ssr_spec);
+
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_spec;
+ closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
+ result.radiance += emission.rgb;
+ result.radiance *= alpha;
+ result.transmittance = vec3(1.0 - alpha);
+}
+
+void node_bsdf_principled_clearcoat(vec4 base_color,
+ float subsurface,
+ vec3 subsurface_radius,
+ vec4 subsurface_color,
+ float metallic,
+ float specular,
+ float specular_tint,
+ float roughness,
+ float anisotropic,
+ float anisotropic_rotation,
+ float sheen,
+ float sheen_tint,
+ float clearcoat,
+ float clearcoat_roughness,
+ float ior,
+ float transmission,
+ float transmission_roughness,
+ vec4 emission,
+ float alpha,
+ vec3 N,
+ vec3 CN,
+ vec3 T,
+ vec3 I,
+ float ssr_id,
+ float sss_id,
+ vec3 sss_scale,
+ out Closure result)
+{
+ vec3 out_spec, ssr_spec;
+ N = normalize(N);
+
+ vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
+
+ eevee_closure_clearcoat(N,
+ base_color.rgb,
+ f90,
+ int(ssr_id),
+ roughness,
+ CN,
+ clearcoat * 0.25,
+ clearcoat_roughness,
+ 1.0,
+ true,
+ out_spec,
+ ssr_spec);
+
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_spec;
+ closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
+ result.radiance += emission.rgb;
+ result.radiance *= alpha;
+ result.transmittance = vec3(1.0 - alpha);
+}
+
+void node_bsdf_principled_subsurface(vec4 base_color,
+ float subsurface,
+ vec3 subsurface_radius,
+ vec4 subsurface_color,
+ float metallic,
+ float specular,
+ float specular_tint,
+ float roughness,
+ float anisotropic,
+ float anisotropic_rotation,
+ float sheen,
+ float sheen_tint,
+ float clearcoat,
+ float clearcoat_roughness,
+ float ior,
+ float transmission,
+ float transmission_roughness,
+ vec4 emission,
+ float alpha,
+ vec3 N,
+ vec3 CN,
+ vec3 T,
+ vec3 I,
+ float ssr_id,
+ float sss_id,
+ vec3 sss_scale,
+ out Closure result)
+{
+ metallic = saturate(metallic);
+ N = normalize(N);
+
+ vec3 diffuse, f0, out_diff, out_spec, ssr_spec;
+ vec3 ctint = tint_from_color(base_color.rgb);
+ convert_metallic_to_specular_tinted(
+ base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
+
+ subsurface_color = subsurface_color * (1.0 - metallic);
+ vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
+ float sss_scalef = avg(sss_scale) * subsurface;
+
+ float NV = dot(N, cameraVec);
+ vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
+
+ vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
+
+ eevee_closure_skin(N,
+ mixed_ss_base_color,
+ f0,
+ f90,
+ int(ssr_id),
+ roughness,
+ 1.0,
+ sss_scalef,
+ true,
+ out_diff,
+ out_spec,
+ ssr_spec);
+
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_spec;
+ closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
+
+ mixed_ss_base_color *= alpha * (1.0 - transmission);
+ closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result);
+
+ result.radiance += out_diff * out_sheen;
+ result.radiance += emission.rgb;
+ result.radiance *= alpha;
+ result.transmittance = vec3(1.0 - alpha);
+}
+
+void node_bsdf_principled_glass(vec4 base_color,
+ float subsurface,
+ vec3 subsurface_radius,
+ vec4 subsurface_color,
+ float metallic,
+ float specular,
+ float specular_tint,
+ float roughness,
+ float anisotropic,
+ float anisotropic_rotation,
+ float sheen,
+ float sheen_tint,
+ float clearcoat,
+ float clearcoat_roughness,
+ float ior,
+ float transmission,
+ float transmission_roughness,
+ vec4 emission,
+ float alpha,
+ vec3 N,
+ vec3 CN,
+ vec3 T,
+ vec3 I,
+ float ssr_id,
+ float sss_id,
+ vec3 sss_scale,
+ out Closure result)
+{
+ ior = max(ior, 1e-5);
+ N = normalize(N);
+
+ vec3 f0, out_spec, out_refr, ssr_spec;
+ f0 = mix(vec3(1.0), base_color.rgb, specular_tint);
+
+ eevee_closure_glass(N,
+ vec3(1.0),
+ vec3(1.0),
+ int(ssr_id),
+ roughness,
+ 1.0,
+ ior,
+ true,
+ out_spec,
+ out_refr,
+ ssr_spec);
+
+ vec3 refr_color = base_color.rgb;
+ refr_color *= (refractionDepth > 0.0) ? refr_color :
+ vec3(1.0); /* Simulate 2 transmission events */
+ out_refr *= refr_color;
+
+ float fresnel = F_eta(ior, dot(N, cameraVec));
+ vec3 spec_col = F_color_blend(ior, fresnel, f0);
+ out_spec *= spec_col;
+ ssr_spec *= spec_col * fresnel;
+
+ result = CLOSURE_DEFAULT;
+ result.radiance = mix(out_refr, out_spec, fresnel);
+ closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
+ result.radiance += emission.rgb;
+ result.radiance *= alpha;
+ result.transmittance = vec3(1.0 - alpha);
+}
+#else
+/* Stub principled because it is not compatible with volumetrics. */
+# define node_bsdf_principled
+# define node_bsdf_principled_dielectric
+# define node_bsdf_principled_metallic
+# define node_bsdf_principled_clearcoat
+# define node_bsdf_principled_subsurface
+# define node_bsdf_principled_glass
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl
new file mode 100644
index 00000000000..906964e1539
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl
@@ -0,0 +1,16 @@
+#ifndef VOLUMETRICS
+void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Closure result)
+{
+ N = normalize(N);
+ vec3 out_refr;
+ color.rgb *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); /* Simulate 2 absorption event. */
+ eevee_closure_refraction(N, roughness, ior, true, out_refr);
+ vec3 vN = mat3(ViewMatrix) * N;
+ result = CLOSURE_DEFAULT;
+ result.ssr_normal = normal_encode(vN, viewCameraVec);
+ result.radiance = out_refr * color.rgb;
+}
+#else
+/* Stub refraction because it is not compatible with volumetrics. */
+# define node_bsdf_refraction
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_rgb_curves.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_rgb_curves.glsl
new file mode 100644
index 00000000000..054fdddf7c3
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_rgb_curves.glsl
@@ -0,0 +1,73 @@
+/* ext is vec4(in_x, in_dy, out_x, out_dy). */
+float curve_extrapolate(float x, float y, vec4 ext)
+{
+ if (x < 0.0) {
+ return y + x * ext.y;
+ }
+ else if (x > 1.0) {
+ return y + (x - 1.0) * ext.w;
+ }
+ else {
+ return y;
+ }
+}
+
+#define RANGE_RESCALE(x, min, range) ((x - min) * range)
+
+void curves_rgb(float fac,
+ vec4 col,
+ sampler1DArray curvemap,
+ float layer,
+ vec4 range,
+ vec4 ext_r,
+ vec4 ext_g,
+ vec4 ext_b,
+ vec4 ext_a,
+ out vec4 outcol)
+{
+ vec4 co = vec4(RANGE_RESCALE(col.rgb, ext_a.x, range.a), layer);
+ vec3 samp;
+ samp.r = texture(curvemap, co.xw).a;
+ samp.g = texture(curvemap, co.yw).a;
+ samp.b = texture(curvemap, co.zw).a;
+
+ samp.r = curve_extrapolate(co.x, samp.r, ext_a);
+ samp.g = curve_extrapolate(co.y, samp.g, ext_a);
+ samp.b = curve_extrapolate(co.z, samp.b, ext_a);
+
+ vec3 rgb_min = vec3(ext_r.x, ext_g.x, ext_b.x);
+ co.xyz = RANGE_RESCALE(samp.rgb, rgb_min, range.rgb);
+
+ samp.r = texture(curvemap, co.xw).r;
+ samp.g = texture(curvemap, co.yw).g;
+ samp.b = texture(curvemap, co.zw).b;
+
+ outcol.r = curve_extrapolate(co.x, samp.r, ext_r);
+ outcol.g = curve_extrapolate(co.y, samp.g, ext_g);
+ outcol.b = curve_extrapolate(co.z, samp.b, ext_b);
+ outcol.a = col.a;
+
+ outcol = mix(col, outcol, fac);
+}
+
+void curves_rgb_opti(float fac,
+ vec4 col,
+ sampler1DArray curvemap,
+ float layer,
+ vec4 range,
+ vec4 ext_a,
+ out vec4 outcol)
+{
+ vec4 co = vec4(RANGE_RESCALE(col.rgb, ext_a.x, range.a), layer);
+ vec3 samp;
+ samp.r = texture(curvemap, co.xw).a;
+ samp.g = texture(curvemap, co.yw).a;
+ samp.b = texture(curvemap, co.zw).a;
+
+ outcol.r = curve_extrapolate(co.x, samp.r, ext_a);
+ outcol.g = curve_extrapolate(co.y, samp.g, ext_a);
+ outcol.b = curve_extrapolate(co.z, samp.b, ext_a);
+ outcol.a = col.a;
+
+ outcol = mix(col, outcol, fac);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_rgb_to_bw.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_rgb_to_bw.glsl
new file mode 100644
index 00000000000..ceca02a2356
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_rgb_to_bw.glsl
@@ -0,0 +1,5 @@
+void rgbtobw(vec4 color, out float outval)
+{
+ vec3 factors = vec3(0.2126, 0.7152, 0.0722);
+ outval = dot(color.rgb, factors);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl
new file mode 100644
index 00000000000..fb64e424c6c
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl
@@ -0,0 +1,9 @@
+void separate_hsv(vec4 col, out float h, out float s, out float v)
+{
+ vec4 hsv;
+
+ rgb_to_hsv(col, hsv);
+ h = hsv[0];
+ s = hsv[1];
+ v = hsv[2];
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_separate_rgb.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_separate_rgb.glsl
new file mode 100644
index 00000000000..4232b4c001e
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_separate_rgb.glsl
@@ -0,0 +1,6 @@
+void separate_rgb(vec4 col, out float r, out float g, out float b)
+{
+ r = col.r;
+ g = col.g;
+ b = col.b;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_separate_xyz.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_separate_xyz.glsl
new file mode 100644
index 00000000000..fac29ccc135
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_separate_xyz.glsl
@@ -0,0 +1,6 @@
+void separate_xyz(vec3 vec, out float x, out float y, out float z)
+{
+ x = vec.r;
+ y = vec.g;
+ z = vec.b;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_set.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_set.glsl
new file mode 100644
index 00000000000..dc2ecb05351
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_set.glsl
@@ -0,0 +1,44 @@
+void set_value(float val, out float outval)
+{
+ outval = val;
+}
+
+void set_rgb(vec3 col, out vec3 outcol)
+{
+ outcol = col;
+}
+
+void set_rgba(vec4 col, out vec4 outcol)
+{
+ outcol = col;
+}
+
+void set_value_zero(out float outval)
+{
+ outval = 0.0;
+}
+
+void set_value_one(out float outval)
+{
+ outval = 1.0;
+}
+
+void set_rgb_zero(out vec3 outval)
+{
+ outval = vec3(0.0);
+}
+
+void set_rgb_one(out vec3 outval)
+{
+ outval = vec3(1.0);
+}
+
+void set_rgba_zero(out vec4 outval)
+{
+ outval = vec4(0.0);
+}
+
+void set_rgba_one(out vec4 outval)
+{
+ outval = vec4(1.0);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl
new file mode 100644
index 00000000000..4f6df238789
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl
@@ -0,0 +1,21 @@
+#ifndef VOLUMETRICS
+void node_shader_to_rgba(Closure cl, out vec4 outcol, out float outalpha)
+{
+ vec4 spec_accum = vec4(0.0);
+ if (ssrToggle && FLAG_TEST(cl.flag, CLOSURE_SSR_FLAG)) {
+ vec3 V = cameraVec;
+ vec3 vN = normal_decode(cl.ssr_normal, viewCameraVec);
+ vec3 N = transform_direction(ViewMatrixInverse, vN);
+ float roughness = cl.ssr_data.a;
+ float roughnessSquared = max(1e-3, roughness * roughness);
+ fallback_cubemap(N, V, worldPosition, viewPosition, roughness, roughnessSquared, spec_accum);
+ }
+
+ outalpha = avg(cl.transmittance);
+ outcol = vec4((spec_accum.rgb * cl.ssr_data.rgb) + cl.radiance, 1.0);
+
+# ifdef USE_SSS
+ outcol.rgb += cl.sss_irradiance.rgb * cl.sss_albedo;
+# endif
+}
+#endif /* VOLUMETRICS */
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_squeeze.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_squeeze.glsl
new file mode 100644
index 00000000000..b73bdebf7f6
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_squeeze.glsl
@@ -0,0 +1,4 @@
+void squeeze(float val, float width, float center, out float outval)
+{
+ outval = 1.0 / (1.0 + pow(2.71828183, -((val - center) * width)));
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl
new file mode 100644
index 00000000000..241228c0d4c
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl
@@ -0,0 +1,27 @@
+#ifndef VOLUMETRICS
+void node_subsurface_scattering(vec4 color,
+ float scale,
+ vec3 radius,
+ float sharpen,
+ float texture_blur,
+ vec3 N,
+ float sss_id,
+ out Closure result)
+{
+ N = normalize(N);
+ vec3 out_diff;
+ vec3 vN = mat3(ViewMatrix) * N;
+ result = CLOSURE_DEFAULT;
+ closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
+
+ eevee_closure_subsurface(N, color.rgb, 1.0, scale, true, out_diff);
+
+ /* Not perfect for texture_blur not exactly equal to 0.0 or 1.0. */
+ vec3 sss_albedo = mix(color.rgb, vec3(1.0), texture_blur);
+ out_diff *= mix(vec3(1.0), color.rgb, texture_blur);
+ closure_load_sss_data(scale, out_diff, sss_albedo, int(sss_id), result);
+}
+#else
+/* Stub subsurface scattering because it is not compatible with volumetrics. */
+# define node_subsurface_scattering
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl
new file mode 100644
index 00000000000..ff2dbc7ead3
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl
@@ -0,0 +1,25 @@
+void tangent_orco_x(vec3 orco_in, out vec3 orco_out)
+{
+ orco_out = orco_in.xzy * vec3(0.0, -0.5, 0.5) + vec3(0.0, 0.25, -0.25);
+}
+
+void tangent_orco_y(vec3 orco_in, out vec3 orco_out)
+{
+ orco_out = orco_in.zyx * vec3(-0.5, 0.0, 0.5) + vec3(0.25, 0.0, -0.25);
+}
+
+void tangent_orco_z(vec3 orco_in, out vec3 orco_out)
+{
+ orco_out = orco_in.yxz * vec3(-0.5, 0.5, 0.0) + vec3(0.25, -0.25, 0.0);
+}
+
+void node_tangentmap(vec4 attr_tangent, out vec3 tangent)
+{
+ tangent = normalize(attr_tangent.xyz);
+}
+
+void node_tangent(vec3 N, vec3 orco, mat4 objmat, out vec3 T)
+{
+ T = (objmat * vec4(orco, 0.0)).xyz;
+ T = cross(N, normalize(cross(T, N)));
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl
new file mode 100644
index 00000000000..e252e5ba726
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl
@@ -0,0 +1,78 @@
+vec2 calc_brick_texture(vec3 p,
+ float mortar_size,
+ float mortar_smooth,
+ float bias,
+ float brick_width,
+ float row_height,
+ float offset_amount,
+ int offset_frequency,
+ float squash_amount,
+ int squash_frequency)
+{
+ int bricknum, rownum;
+ float offset = 0.0;
+ float x, y;
+
+ rownum = floor_to_int(p.y / row_height);
+
+ if (offset_frequency != 0 && squash_frequency != 0) {
+ brick_width *= (rownum % squash_frequency != 0) ? 1.0 : squash_amount; /* squash */
+ offset = (rownum % offset_frequency != 0) ? 0.0 : (brick_width * offset_amount); /* offset */
+ }
+
+ bricknum = floor_to_int((p.x + offset) / brick_width);
+
+ x = (p.x + offset) - brick_width * bricknum;
+ y = p.y - row_height * rownum;
+
+ float tint = clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0, 1.0);
+
+ float min_dist = min(min(x, y), min(brick_width - x, row_height - y));
+ if (min_dist >= mortar_size) {
+ return vec2(tint, 0.0);
+ }
+ else if (mortar_smooth == 0.0) {
+ return vec2(tint, 1.0);
+ }
+ else {
+ min_dist = 1.0 - min_dist / mortar_size;
+ return vec2(tint, smoothstep(0.0, mortar_smooth, min_dist));
+ }
+}
+
+void node_tex_brick(vec3 co,
+ vec4 color1,
+ vec4 color2,
+ vec4 mortar,
+ float scale,
+ float mortar_size,
+ float mortar_smooth,
+ float bias,
+ float brick_width,
+ float row_height,
+ float offset_amount,
+ float offset_frequency,
+ float squash_amount,
+ float squash_frequency,
+ out vec4 color,
+ out float fac)
+{
+ vec2 f2 = calc_brick_texture(co * scale,
+ mortar_size,
+ mortar_smooth,
+ bias,
+ brick_width,
+ row_height,
+ offset_amount,
+ int(offset_frequency),
+ squash_amount,
+ int(squash_frequency));
+ float tint = f2.x;
+ float f = f2.y;
+ if (f != 1.0) {
+ float facm = 1.0 - tint;
+ color1 = facm * color1 + tint * color2;
+ }
+ color = mix(color1, mortar, f);
+ fac = f;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_checker.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_checker.glsl
new file mode 100644
index 00000000000..f534f3bddf3
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_checker.glsl
@@ -0,0 +1,17 @@
+void node_tex_checker(
+ vec3 co, vec4 color1, vec4 color2, float scale, out vec4 color, out float fac)
+{
+ vec3 p = co * scale;
+
+ /* Prevent precision issues on unit coordinates. */
+ p = (p + 0.000001) * 0.999999;
+
+ int xi = int(abs(floor(p.x)));
+ int yi = int(abs(floor(p.y)));
+ int zi = int(abs(floor(p.z)));
+
+ bool check = ((mod(xi, 2) == mod(yi, 2)) == bool(mod(zi, 2)));
+
+ color = check ? color1 : color2;
+ fac = check ? 1.0 : 0.0;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl
new file mode 100644
index 00000000000..9bd36f8a757
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl
@@ -0,0 +1,44 @@
+void node_tex_environment_texco(vec3 viewvec, out vec3 worldvec)
+{
+#ifdef MESH_SHADER
+ worldvec = worldPosition;
+#else
+ vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(viewvec, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
+ vec4 co_homogenous = (ProjectionMatrixInverse * v);
+
+ vec3 co = co_homogenous.xyz / co_homogenous.w;
+# if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
+ worldvec = mat3(ViewMatrixInverse) * co;
+# else
+ worldvec = mat3(ModelMatrixInverse) * (mat3(ViewMatrixInverse) * co);
+# endif
+#endif
+}
+
+void node_tex_environment_equirectangular(vec3 co, float clamp_size, sampler2D ima, out vec3 uv)
+{
+ vec3 nco = normalize(co);
+ uv.x = -atan(nco.y, nco.x) / (2.0 * M_PI) + 0.5;
+ uv.y = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5;
+
+ /* Fix pole bleeding */
+ float half_height = clamp_size / float(textureSize(ima, 0).y);
+ uv.y = clamp(uv.y, half_height, 1.0 - half_height);
+ uv.z = 0.0;
+}
+
+void node_tex_environment_mirror_ball(vec3 co, out vec3 uv)
+{
+ vec3 nco = normalize(co);
+ nco.y -= 1.0;
+
+ float div = 2.0 * sqrt(max(-0.5 * nco.y, 0.0));
+ nco /= max(1e-8, div);
+
+ uv = 0.5 * nco.xzz + 0.5;
+}
+
+void node_tex_environment_empty(vec3 co, out vec4 color)
+{
+ color = vec4(1.0, 0.0, 1.0, 1.0);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_gradient.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_gradient.glsl
new file mode 100644
index 00000000000..f2f7e615267
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_gradient.glsl
@@ -0,0 +1,47 @@
+float calc_gradient(vec3 p, int gradient_type)
+{
+ float x, y, z;
+ x = p.x;
+ y = p.y;
+ z = p.z;
+ if (gradient_type == 0) { /* linear */
+ return x;
+ }
+ else if (gradient_type == 1) { /* quadratic */
+ float r = max(x, 0.0);
+ return r * r;
+ }
+ else if (gradient_type == 2) { /* easing */
+ float r = min(max(x, 0.0), 1.0);
+ float t = r * r;
+ return (3.0 * t - 2.0 * t * r);
+ }
+ else if (gradient_type == 3) { /* diagonal */
+ return (x + y) * 0.5;
+ }
+ else if (gradient_type == 4) { /* radial */
+ return atan(y, x) / (M_PI * 2) + 0.5;
+ }
+ else {
+ /* Bias a little bit for the case where p is a unit length vector,
+ * to get exactly zero instead of a small random value depending
+ * on float precision. */
+ float r = max(0.999999 - sqrt(x * x + y * y + z * z), 0.0);
+ if (gradient_type == 5) { /* quadratic sphere */
+ return r * r;
+ }
+ else if (gradient_type == 6) { /* sphere */
+ return r;
+ }
+ }
+ return 0.0;
+}
+
+void node_tex_gradient(vec3 co, float gradient_type, out vec4 color, out float fac)
+{
+ float f = calc_gradient(co, int(gradient_type));
+ f = clamp(f, 0.0, 1.0);
+
+ color = vec4(f, f, f, 1.0);
+ fac = f;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl
new file mode 100644
index 00000000000..c234e064d36
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl
@@ -0,0 +1,355 @@
+void point_texco_remap_square(vec3 vin, out vec3 vout)
+{
+ vout = vin * 2.0 - 1.0;
+}
+
+void point_texco_clamp(vec3 vin, sampler2D ima, out vec3 vout)
+{
+ vec2 half_texel_size = 0.5 / vec2(textureSize(ima, 0).xy);
+ vout = clamp(vin, half_texel_size.xyy, 1.0 - half_texel_size.xyy);
+}
+
+void point_map_to_sphere(vec3 vin, out vec3 vout)
+{
+ float len = length(vin);
+ float v, u;
+ if (len > 0.0) {
+ if (vin.x == 0.0 && vin.y == 0.0) {
+ u = 0.0;
+ }
+ else {
+ u = (1.0 - atan(vin.x, vin.y) / M_PI) / 2.0;
+ }
+
+ v = 1.0 - acos(vin.z / len) / M_PI;
+ }
+ else {
+ v = u = 0.0;
+ }
+
+ vout = vec3(u, v, 0.0);
+}
+
+void point_map_to_tube(vec3 vin, out vec3 vout)
+{
+ float u, v;
+ v = (vin.z + 1.0) * 0.5;
+ float len = sqrt(vin.x * vin.x + vin.y * vin[1]);
+ if (len > 0.0) {
+ u = (1.0 - (atan(vin.x / len, vin.y / len) / M_PI)) * 0.5;
+ }
+ else {
+ v = u = 0.0;
+ }
+
+ vout = vec3(u, v, 0.0);
+}
+
+/* 16bits floats limits. Higher/Lower values produce +/-inf. */
+#define safe_color(a) (clamp(a, -65520.0, 65520.0))
+
+void node_tex_image_linear(vec3 co, sampler2D ima, out vec4 color, out float alpha)
+{
+ color = safe_color(texture(ima, co.xy));
+ alpha = color.a;
+}
+
+void node_tex_image_linear_no_mip(vec3 co, sampler2D ima, out vec4 color, out float alpha)
+{
+ color = safe_color(textureLod(ima, co.xy, 0.0));
+ alpha = color.a;
+}
+
+void node_tex_image_nearest(vec3 co, sampler2D ima, out vec4 color, out float alpha)
+{
+ ivec2 pix = ivec2(fract(co.xy) * textureSize(ima, 0).xy);
+ color = safe_color(texelFetch(ima, pix, 0));
+ alpha = color.a;
+}
+
+/* @arg f: signed distance to texel center. */
+void cubic_bspline_coefs(vec2 f, out vec2 w0, out vec2 w1, out vec2 w2, out vec2 w3)
+{
+ vec2 f2 = f * f;
+ vec2 f3 = f2 * f;
+ /* Bspline coefs (optimized) */
+ w3 = f3 / 6.0;
+ w0 = -w3 + f2 * 0.5 - f * 0.5 + 1.0 / 6.0;
+ w1 = f3 * 0.5 - f2 * 1.0 + 2.0 / 3.0;
+ w2 = 1.0 - w0 - w1 - w3;
+}
+
+void node_tex_image_cubic_ex(
+ vec3 co, sampler2D ima, float do_extend, out vec4 color, out float alpha)
+{
+ vec2 tex_size = vec2(textureSize(ima, 0).xy);
+
+ co.xy *= tex_size;
+ /* texel center */
+ vec2 tc = floor(co.xy - 0.5) + 0.5;
+ vec2 w0, w1, w2, w3;
+ cubic_bspline_coefs(co.xy - tc, w0, w1, w2, w3);
+
+#if 1 /* Optimized version using 4 filtered tap. */
+ vec2 s0 = w0 + w1;
+ vec2 s1 = w2 + w3;
+
+ vec2 f0 = w1 / (w0 + w1);
+ vec2 f1 = w3 / (w2 + w3);
+
+ vec4 final_co;
+ final_co.xy = tc - 1.0 + f0;
+ final_co.zw = tc + 1.0 + f1;
+
+ if (do_extend == 1.0) {
+ final_co = clamp(final_co, vec4(0.5), tex_size.xyxy - 0.5);
+ }
+ final_co /= tex_size.xyxy;
+
+ color = safe_color(textureLod(ima, final_co.xy, 0.0)) * s0.x * s0.y;
+ color += safe_color(textureLod(ima, final_co.zy, 0.0)) * s1.x * s0.y;
+ color += safe_color(textureLod(ima, final_co.xw, 0.0)) * s0.x * s1.y;
+ color += safe_color(textureLod(ima, final_co.zw, 0.0)) * s1.x * s1.y;
+
+#else /* Reference bruteforce 16 tap. */
+ color = texelFetch(ima, ivec2(tc + vec2(-1.0, -1.0)), 0) * w0.x * w0.y;
+ color += texelFetch(ima, ivec2(tc + vec2(0.0, -1.0)), 0) * w1.x * w0.y;
+ color += texelFetch(ima, ivec2(tc + vec2(1.0, -1.0)), 0) * w2.x * w0.y;
+ color += texelFetch(ima, ivec2(tc + vec2(2.0, -1.0)), 0) * w3.x * w0.y;
+
+ color += texelFetch(ima, ivec2(tc + vec2(-1.0, 0.0)), 0) * w0.x * w1.y;
+ color += texelFetch(ima, ivec2(tc + vec2(0.0, 0.0)), 0) * w1.x * w1.y;
+ color += texelFetch(ima, ivec2(tc + vec2(1.0, 0.0)), 0) * w2.x * w1.y;
+ color += texelFetch(ima, ivec2(tc + vec2(2.0, 0.0)), 0) * w3.x * w1.y;
+
+ color += texelFetch(ima, ivec2(tc + vec2(-1.0, 1.0)), 0) * w0.x * w2.y;
+ color += texelFetch(ima, ivec2(tc + vec2(0.0, 1.0)), 0) * w1.x * w2.y;
+ color += texelFetch(ima, ivec2(tc + vec2(1.0, 1.0)), 0) * w2.x * w2.y;
+ color += texelFetch(ima, ivec2(tc + vec2(2.0, 1.0)), 0) * w3.x * w2.y;
+
+ color += texelFetch(ima, ivec2(tc + vec2(-1.0, 2.0)), 0) * w0.x * w3.y;
+ color += texelFetch(ima, ivec2(tc + vec2(0.0, 2.0)), 0) * w1.x * w3.y;
+ color += texelFetch(ima, ivec2(tc + vec2(1.0, 2.0)), 0) * w2.x * w3.y;
+ color += texelFetch(ima, ivec2(tc + vec2(2.0, 2.0)), 0) * w3.x * w3.y;
+#endif
+
+ alpha = color.a;
+}
+
+void node_tex_image_cubic(vec3 co, sampler2D ima, out vec4 color, out float alpha)
+{
+ node_tex_image_cubic_ex(co, ima, 0.0, color, alpha);
+}
+
+void node_tex_image_cubic_extend(vec3 co, sampler2D ima, out vec4 color, out float alpha)
+{
+ node_tex_image_cubic_ex(co, ima, 1.0, color, alpha);
+}
+
+void node_tex_image_smart(vec3 co, sampler2D ima, out vec4 color, out float alpha)
+{
+ /* use cubic for now */
+ node_tex_image_cubic_ex(co, ima, 0.0, color, alpha);
+}
+
+void tex_box_sample_linear(
+ vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3)
+{
+ /* X projection */
+ vec2 uv = texco.yz;
+ if (N.x < 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ color1 = texture(ima, uv);
+ /* Y projection */
+ uv = texco.xz;
+ if (N.y > 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ color2 = texture(ima, uv);
+ /* Z projection */
+ uv = texco.yx;
+ if (N.z > 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ color3 = texture(ima, uv);
+}
+
+void tex_box_sample_nearest(
+ vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3)
+{
+ /* X projection */
+ vec2 uv = texco.yz;
+ if (N.x < 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ ivec2 pix = ivec2(uv.xy * textureSize(ima, 0).xy);
+ color1 = texelFetch(ima, pix, 0);
+ /* Y projection */
+ uv = texco.xz;
+ if (N.y > 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ pix = ivec2(uv.xy * textureSize(ima, 0).xy);
+ color2 = texelFetch(ima, pix, 0);
+ /* Z projection */
+ uv = texco.yx;
+ if (N.z > 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ pix = ivec2(uv.xy * textureSize(ima, 0).xy);
+ color3 = texelFetch(ima, pix, 0);
+}
+
+void tex_box_sample_cubic(
+ vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3)
+{
+ float alpha;
+ /* X projection */
+ vec2 uv = texco.yz;
+ if (N.x < 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color1, alpha);
+ /* Y projection */
+ uv = texco.xz;
+ if (N.y > 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color2, alpha);
+ /* Z projection */
+ uv = texco.yx;
+ if (N.z > 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color3, alpha);
+}
+
+void tex_box_sample_smart(
+ vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3)
+{
+ tex_box_sample_cubic(texco, N, ima, color1, color2, color3);
+}
+
+void node_tex_image_box(vec3 texco,
+ vec3 N,
+ vec4 color1,
+ vec4 color2,
+ vec4 color3,
+ sampler2D ima,
+ float blend,
+ out vec4 color,
+ out float alpha)
+{
+ /* project from direction vector to barycentric coordinates in triangles */
+ N = abs(N);
+ N /= dot(N, vec3(1.0));
+
+ /* basic idea is to think of this as a triangle, each corner representing
+ * one of the 3 faces of the cube. in the corners we have single textures,
+ * in between we blend between two textures, and in the middle we a blend
+ * between three textures.
+ *
+ * the Nxyz values are the barycentric coordinates in an equilateral
+ * triangle, which in case of blending, in the middle has a smaller
+ * equilateral triangle where 3 textures blend. this divides things into
+ * 7 zones, with an if () test for each zone
+ * EDIT: Now there is only 4 if's. */
+
+ float limit = 0.5 + 0.5 * blend;
+
+ vec3 weight;
+ weight = N.xyz / (N.xyx + N.yzz);
+ weight = clamp((weight - 0.5 * (1.0 - blend)) / max(1e-8, blend), 0.0, 1.0);
+
+ /* test for mixes between two textures */
+ if (N.z < (1.0 - limit) * (N.y + N.x)) {
+ weight.z = 0.0;
+ weight.y = 1.0 - weight.x;
+ }
+ else if (N.x < (1.0 - limit) * (N.y + N.z)) {
+ weight.x = 0.0;
+ weight.z = 1.0 - weight.y;
+ }
+ else if (N.y < (1.0 - limit) * (N.x + N.z)) {
+ weight.y = 0.0;
+ weight.x = 1.0 - weight.z;
+ }
+ else {
+ /* last case, we have a mix between three */
+ weight = ((2.0 - limit) * N + (limit - 1.0)) / max(1e-8, blend);
+ }
+
+ color = weight.x * color1 + weight.y * color2 + weight.z * color3;
+ alpha = color.a;
+}
+
+void tex_clip_linear(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
+{
+ vec2 tex_size = vec2(textureSize(ima, 0).xy);
+ vec2 minco = min(co.xy, 1.0 - co.xy);
+ minco = clamp(minco * tex_size + 0.5, 0.0, 1.0);
+ float fac = minco.x * minco.y;
+
+ color = mix(vec4(0.0), icolor, fac);
+ alpha = color.a;
+}
+
+void tex_clip_nearest(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
+{
+ vec4 minco = vec4(co.xy, 1.0 - co.xy);
+ color = (any(lessThan(minco, vec4(0.0)))) ? vec4(0.0) : icolor;
+ alpha = color.a;
+}
+
+void tex_clip_cubic(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
+{
+ vec2 tex_size = vec2(textureSize(ima, 0).xy);
+
+ co.xy *= tex_size;
+ /* texel center */
+ vec2 tc = floor(co.xy - 0.5) + 0.5;
+ vec2 w0, w1, w2, w3;
+ cubic_bspline_coefs(co.xy - tc, w0, w1, w2, w3);
+
+ /* TODO Optimize this part. I'm sure there is a smarter way to do that.
+ * Could do that when sampling? */
+#define CLIP_CUBIC_SAMPLE(samp, size) \
+ (float(all(greaterThan(samp, vec2(-0.5)))) * float(all(lessThan(ivec2(samp), itex_size))))
+ ivec2 itex_size = textureSize(ima, 0).xy;
+ float fac;
+ fac = CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, -1.0), itex_size) * w0.x * w0.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, -1.0), itex_size) * w1.x * w0.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, -1.0), itex_size) * w2.x * w0.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, -1.0), itex_size) * w3.x * w0.y;
+
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 0.0), itex_size) * w0.x * w1.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 0.0), itex_size) * w1.x * w1.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 0.0), itex_size) * w2.x * w1.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 0.0), itex_size) * w3.x * w1.y;
+
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 1.0), itex_size) * w0.x * w2.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 1.0), itex_size) * w1.x * w2.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 1.0), itex_size) * w2.x * w2.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 1.0), itex_size) * w3.x * w2.y;
+
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 2.0), itex_size) * w0.x * w3.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 2.0), itex_size) * w1.x * w3.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 2.0), itex_size) * w2.x * w3.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 2.0), itex_size) * w3.x * w3.y;
+#undef CLIP_CUBIC_SAMPLE
+
+ color = mix(vec4(0.0), icolor, fac);
+ alpha = color.a;
+}
+
+void tex_clip_smart(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
+{
+ tex_clip_cubic(co, ima, icolor, color, alpha);
+}
+
+void node_tex_image_empty(vec3 co, out vec4 color, out float alpha)
+{
+ color = vec4(0.0);
+ alpha = 0.0;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl
new file mode 100644
index 00000000000..942c507cc38
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl
@@ -0,0 +1,61 @@
+void node_tex_magic(
+ vec3 co, float scale, float distortion, float depth, out vec4 color, out float fac)
+{
+ vec3 p = co * scale;
+ float x = sin((p.x + p.y + p.z) * 5.0);
+ float y = cos((-p.x + p.y - p.z) * 5.0);
+ float z = -cos((-p.x - p.y + p.z) * 5.0);
+
+ if (depth > 0) {
+ x *= distortion;
+ y *= distortion;
+ z *= distortion;
+ y = -cos(x - y + z);
+ y *= distortion;
+ if (depth > 1) {
+ x = cos(x - y - z);
+ x *= distortion;
+ if (depth > 2) {
+ z = sin(-x - y - z);
+ z *= distortion;
+ if (depth > 3) {
+ x = -cos(-x + y - z);
+ x *= distortion;
+ if (depth > 4) {
+ y = -sin(-x + y + z);
+ y *= distortion;
+ if (depth > 5) {
+ y = -cos(-x + y + z);
+ y *= distortion;
+ if (depth > 6) {
+ x = cos(x + y + z);
+ x *= distortion;
+ if (depth > 7) {
+ z = sin(x + y - z);
+ z *= distortion;
+ if (depth > 8) {
+ x = -cos(-x - y + z);
+ x *= distortion;
+ if (depth > 9) {
+ y = -sin(x - y + z);
+ y *= distortion;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (distortion != 0.0) {
+ distortion *= 2.0;
+ x /= distortion;
+ y /= distortion;
+ z /= distortion;
+ }
+
+ color = vec4(0.5 - x, 0.5 - y, 0.5 - z, 1.0);
+ fac = (color.x + color.y + color.z) / 3.0;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl
new file mode 100644
index 00000000000..7ecca286acd
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl
@@ -0,0 +1,887 @@
+/* 1D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+void node_tex_musgrave_fBm_1d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ float p = w * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value += snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * snoise(p) * pwr;
+ }
+
+ fac = value;
+}
+
+/* 1D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+void node_tex_musgrave_multi_fractal_1d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ float p = w * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value *= (pwr * snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * snoise(p) + 1.0); /* correct? */
+ }
+
+ fac = value;
+}
+
+/* 1D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hetero_terrain_1d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ float p = w * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < int(octaves); i++) {
+ float increment = (snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float increment = (snoise(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ fac = value;
+}
+
+/* 1D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hybrid_multi_fractal_1d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ float p = w * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = snoise(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ float signal = (snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * ((snoise(p) + offset) * pwr);
+ }
+
+ fac = value;
+}
+
+/* 1D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_ridged_multi_fractal_1d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ float p = w * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - abs(snoise(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0;
+
+ for (int i = 1; i < int(octaves); i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - abs(snoise(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ fac = value;
+}
+
+/* 2D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+void node_tex_musgrave_fBm_2d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec2 p = co.xy * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value += snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * snoise(p) * pwr;
+ }
+
+ fac = value;
+}
+
+/* 2D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+void node_tex_musgrave_multi_fractal_2d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec2 p = co.xy * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value *= (pwr * snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * snoise(p) + 1.0); /* correct? */
+ }
+
+ fac = value;
+}
+
+/* 2D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hetero_terrain_2d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec2 p = co.xy * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < int(octaves); i++) {
+ float increment = (snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float increment = (snoise(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ fac = value;
+}
+
+/* 2D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hybrid_multi_fractal_2d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec2 p = co.xy * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = snoise(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ float signal = (snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * ((snoise(p) + offset) * pwr);
+ }
+
+ fac = value;
+}
+
+/* 2D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_ridged_multi_fractal_2d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec2 p = co.xy * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - abs(snoise(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0;
+
+ for (int i = 1; i < int(octaves); i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - abs(snoise(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ fac = value;
+}
+
+/* 3D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+void node_tex_musgrave_fBm_3d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec3 p = co * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value += snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * snoise(p) * pwr;
+ }
+
+ fac = value;
+}
+
+/* 3D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+void node_tex_musgrave_multi_fractal_3d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec3 p = co * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value *= (pwr * snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * snoise(p) + 1.0); /* correct? */
+ }
+
+ fac = value;
+}
+
+/* 3D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hetero_terrain_3d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec3 p = co * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < int(octaves); i++) {
+ float increment = (snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float increment = (snoise(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ fac = value;
+}
+
+/* 3D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hybrid_multi_fractal_3d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec3 p = co * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = snoise(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ float signal = (snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * ((snoise(p) + offset) * pwr);
+ }
+
+ fac = value;
+}
+
+/* 3D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_ridged_multi_fractal_3d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec3 p = co * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - abs(snoise(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0;
+
+ for (int i = 1; i < int(octaves); i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - abs(snoise(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ fac = value;
+}
+
+/* 4D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+void node_tex_musgrave_fBm_4d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec4 p = vec4(co, w) * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value += snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * snoise(p) * pwr;
+ }
+
+ fac = value;
+}
+
+/* 4D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+void node_tex_musgrave_multi_fractal_4d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec4 p = vec4(co, w) * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value *= (pwr * snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * snoise(p) + 1.0); /* correct? */
+ }
+
+ fac = value;
+}
+
+/* 4D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hetero_terrain_4d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec4 p = vec4(co, w) * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < int(octaves); i++) {
+ float increment = (snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float increment = (snoise(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ fac = value;
+}
+
+/* 4D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hybrid_multi_fractal_4d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec4 p = vec4(co, w) * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = snoise(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ float signal = (snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * ((snoise(p) + offset) * pwr);
+ }
+
+ fac = value;
+}
+
+/* 4D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_ridged_multi_fractal_4d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec4 p = vec4(co, w) * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - abs(snoise(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0;
+
+ for (int i = 1; i < int(octaves); i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - abs(snoise(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ fac = value;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
new file mode 100644
index 00000000000..e56b4a1d135
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
@@ -0,0 +1,99 @@
+/* The following offset functions generate random offsets to be added to texture
+ * coordinates to act as a seed since the noise functions don't have seed values.
+ * A seed value is needed for generating distortion textures and color outputs.
+ * The offset's components are in the range [100, 200], not too high to cause
+ * bad precision and not to small to be noticeable. We use float seed because
+ * OSL only support float hashes.
+ */
+
+float random_float_offset(float seed)
+{
+ return 100.0 + hash_float_to_float(seed) * 100.0;
+}
+
+vec2 random_vec2_offset(float seed)
+{
+ return vec2(100.0 + hash_vec2_to_float(vec2(seed, 0.0)) * 100.0,
+ 100.0 + hash_vec2_to_float(vec2(seed, 1.0)) * 100.0);
+}
+
+vec3 random_vec3_offset(float seed)
+{
+ return vec3(100.0 + hash_vec2_to_float(vec2(seed, 0.0)) * 100.0,
+ 100.0 + hash_vec2_to_float(vec2(seed, 1.0)) * 100.0,
+ 100.0 + hash_vec2_to_float(vec2(seed, 2.0)) * 100.0);
+}
+
+vec4 random_vec4_offset(float seed)
+{
+ return vec4(100.0 + hash_vec2_to_float(vec2(seed, 0.0)) * 100.0,
+ 100.0 + hash_vec2_to_float(vec2(seed, 1.0)) * 100.0,
+ 100.0 + hash_vec2_to_float(vec2(seed, 2.0)) * 100.0,
+ 100.0 + hash_vec2_to_float(vec2(seed, 3.0)) * 100.0);
+}
+
+void node_noise_texture_1d(
+ vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color)
+{
+ float p = w * scale;
+ if (distortion != 0.0) {
+ p += noise(p + random_float_offset(0.0)) * distortion;
+ }
+
+ value = fractal_noise(p, detail);
+ color = vec4(value,
+ fractal_noise(p + random_float_offset(1.0), detail),
+ fractal_noise(p + random_float_offset(2.0), detail),
+ 1.0);
+}
+
+void node_noise_texture_2d(
+ vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color)
+{
+ vec2 p = co.xy * scale;
+ if (distortion != 0.0) {
+ p += vec2(noise(p + random_vec2_offset(0.0)) * distortion,
+ noise(p + random_vec2_offset(1.0)) * distortion);
+ }
+
+ value = fractal_noise(p, detail);
+ color = vec4(value,
+ fractal_noise(p + random_vec2_offset(2.0), detail),
+ fractal_noise(p + random_vec2_offset(3.0), detail),
+ 1.0);
+}
+
+void node_noise_texture_3d(
+ vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color)
+{
+ vec3 p = co * scale;
+ if (distortion != 0.0) {
+ p += vec3(noise(p + random_vec3_offset(0.0)) * distortion,
+ noise(p + random_vec3_offset(1.0)) * distortion,
+ noise(p + random_vec3_offset(2.0)) * distortion);
+ }
+
+ value = fractal_noise(p, detail);
+ color = vec4(value,
+ fractal_noise(p + random_vec3_offset(3.0), detail),
+ fractal_noise(p + random_vec3_offset(4.0), detail),
+ 1.0);
+}
+
+void node_noise_texture_4d(
+ vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color)
+{
+ vec4 p = vec4(co, w) * scale;
+ if (distortion != 0.0) {
+ p += vec4(noise(p + random_vec4_offset(0.0)) * distortion,
+ noise(p + random_vec4_offset(1.0)) * distortion,
+ noise(p + random_vec4_offset(2.0)) * distortion,
+ noise(p + random_vec4_offset(3.0)) * distortion);
+ }
+
+ value = fractal_noise(p, detail);
+ color = vec4(value,
+ fractal_noise(p + random_vec4_offset(4.0), detail),
+ fractal_noise(p + random_vec4_offset(5.0), detail),
+ 1.0);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl
new file mode 100644
index 00000000000..981d17b4283
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl
@@ -0,0 +1,4 @@
+void node_tex_sky(vec3 co, out vec4 color)
+{
+ color = vec4(1.0);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl
new file mode 100644
index 00000000000..0d8847176c9
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl
@@ -0,0 +1,1064 @@
+/*
+ * Smooth Voronoi:
+ *
+ * - https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi
+ *
+ * Distance To Edge:
+ *
+ * - https://www.shadertoy.com/view/llG3zy
+ *
+ */
+
+/* **** 1D Voronoi **** */
+
+float voronoi_distance(float a, float b, float metric, float exponent)
+{
+ return distance(a, b);
+}
+
+void node_tex_voronoi_f1_1d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ float scaledCoord = w * scale;
+ float cellPosition = floor(scaledCoord);
+ float localPosition = scaledCoord - cellPosition;
+
+ float minDistance = 8.0;
+ float targetOffset, targetPosition;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ outDistance = minDistance;
+ outColor.xyz = hash_float_to_vec3(cellPosition + targetOffset);
+ outW = safe_divide(targetPosition + cellPosition, scale);
+}
+
+void node_tex_voronoi_smooth_f1_1d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+ smoothness = clamp(smoothness / 2.0, 0, 0.5);
+
+ float scaledCoord = w * scale;
+ float cellPosition = floor(scaledCoord);
+ float localPosition = scaledCoord - cellPosition;
+
+ float smoothDistance = 8.0;
+ float smoothPosition = 0.0;
+ vec3 smoothColor = vec3(0.0);
+ for (int i = -2; i <= 2; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0 - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0 + 3.0 * smoothness;
+ vec3 cellColor = hash_float_to_vec3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ outDistance = smoothDistance;
+ outColor.xyz = smoothColor;
+ outW = safe_divide(cellPosition + smoothPosition, scale);
+}
+
+void node_tex_voronoi_f2_1d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ float scaledCoord = w * scale;
+ float cellPosition = floor(scaledCoord);
+ float localPosition = scaledCoord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ float offsetF1 = 0.0;
+ float positionF1 = 0.0;
+ float offsetF2, positionF2;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ outDistance = distanceF2;
+ outColor.xyz = hash_float_to_vec3(cellPosition + offsetF2);
+ outW = safe_divide(positionF2 + cellPosition, scale);
+}
+
+void node_tex_voronoi_distance_to_edge_1d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ float scaledCoord = w * scale;
+ float cellPosition = floor(scaledCoord);
+ float localPosition = scaledCoord - cellPosition;
+
+ float minDistance = 8.0;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ minDistance = min(distanceToPoint, minDistance);
+ }
+ outDistance = minDistance;
+}
+
+void node_tex_voronoi_n_sphere_radius_1d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ float scaledCoord = w * scale;
+ float cellPosition = floor(scaledCoord);
+ float localPosition = scaledCoord - cellPosition;
+
+ float closestPoint;
+ float closestPointOffset;
+ float minDistance = 8.0;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+
+ minDistance = 8.0;
+ float closestPointToClosestPoint;
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0) {
+ continue;
+ }
+ float cellOffset = float(i) + closestPointOffset;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
+
+/* **** 2D Voronoi **** */
+
+float voronoi_distance(vec2 a, vec2 b, float metric, float exponent)
+{
+ if (metric == 0.0) // SHD_VORONOI_EUCLIDEAN
+ {
+ return distance(a, b);
+ }
+ else if (metric == 1.0) // SHD_VORONOI_MANHATTAN
+ {
+ return abs(a.x - b.x) + abs(a.y - b.y);
+ }
+ else if (metric == 2.0) // SHD_VORONOI_CHEBYCHEV
+ {
+ return max(abs(a.x - b.x), abs(a.y - b.y));
+ }
+ else if (metric == 3.0) // SHD_VORONOI_MINKOWSKI
+ {
+ return pow(pow(abs(a.x - b.x), exponent) + pow(abs(a.y - b.y), exponent), 1.0 / exponent);
+ }
+ else {
+ return 0.0;
+ }
+}
+
+void node_tex_voronoi_f1_2d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec2 scaledCoord = coord.xy * scale;
+ vec2 cellPosition = floor(scaledCoord);
+ vec2 localPosition = scaledCoord - cellPosition;
+
+ float minDistance = 8.0;
+ vec2 targetOffset, targetPosition;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 pointPosition = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ outDistance = minDistance;
+ outColor.xyz = hash_vec2_to_vec3(cellPosition + targetOffset);
+ outPosition = vec3(safe_divide(targetPosition + cellPosition, scale), 0.0);
+}
+
+void node_tex_voronoi_smooth_f1_2d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+ smoothness = clamp(smoothness / 2.0, 0, 0.5);
+
+ vec2 scaledCoord = coord.xy * scale;
+ vec2 cellPosition = floor(scaledCoord);
+ vec2 localPosition = scaledCoord - cellPosition;
+
+ float smoothDistance = 8.0;
+ vec3 smoothColor = vec3(0.0);
+ vec2 smoothPosition = vec2(0.0);
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 pointPosition = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0 - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0 + 3.0 * smoothness;
+ vec3 cellColor = hash_vec2_to_vec3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ outDistance = smoothDistance;
+ outColor.xyz = smoothColor;
+ outPosition = vec3(safe_divide(cellPosition + smoothPosition, scale), 0.0);
+}
+
+void node_tex_voronoi_f2_2d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec2 scaledCoord = coord.xy * scale;
+ vec2 cellPosition = floor(scaledCoord);
+ vec2 localPosition = scaledCoord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vec2 offsetF1 = vec2(0.0);
+ vec2 positionF1 = vec2(0.0);
+ vec2 offsetF2, positionF2;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 pointPosition = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ outDistance = distanceF2;
+ outColor.xyz = hash_vec2_to_vec3(cellPosition + offsetF2);
+ outPosition = vec3(safe_divide(positionF2 + cellPosition, scale), 0.0);
+}
+
+void node_tex_voronoi_distance_to_edge_2d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec2 scaledCoord = coord.xy * scale;
+ vec2 cellPosition = floor(scaledCoord);
+ vec2 localPosition = scaledCoord - cellPosition;
+
+ vec2 vectorToClosest;
+ float minDistance = 8.0;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 vectorToPoint = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 vectorToPoint = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness -
+ localPosition;
+ vec2 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ outDistance = minDistance;
+}
+
+void node_tex_voronoi_n_sphere_radius_2d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec2 scaledCoord = coord.xy * scale;
+ vec2 cellPosition = floor(scaledCoord);
+ vec2 localPosition = scaledCoord - cellPosition;
+
+ vec2 closestPoint;
+ vec2 closestPointOffset;
+ float minDistance = 8.0;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 pointPosition = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ vec2 closestPointToClosestPoint;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0) {
+ continue;
+ }
+ vec2 cellOffset = vec2(i, j) + closestPointOffset;
+ vec2 pointPosition = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
+
+/* **** 3D Voronoi **** */
+
+float voronoi_distance(vec3 a, vec3 b, float metric, float exponent)
+{
+ if (metric == 0.0) // SHD_VORONOI_EUCLIDEAN
+ {
+ return distance(a, b);
+ }
+ else if (metric == 1.0) // SHD_VORONOI_MANHATTAN
+ {
+ return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z);
+ }
+ else if (metric == 2.0) // SHD_VORONOI_CHEBYCHEV
+ {
+ return max(abs(a.x - b.x), max(abs(a.y - b.y), abs(a.z - b.z)));
+ }
+ else if (metric == 3.0) // SHD_VORONOI_MINKOWSKI
+ {
+ return pow(pow(abs(a.x - b.x), exponent) + pow(abs(a.y - b.y), exponent) +
+ pow(abs(a.z - b.z), exponent),
+ 1.0 / exponent);
+ }
+ else {
+ return 0.0;
+ }
+}
+
+void node_tex_voronoi_f1_3d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec3 scaledCoord = coord * scale;
+ vec3 cellPosition = floor(scaledCoord);
+ vec3 localPosition = scaledCoord - cellPosition;
+
+ float minDistance = 8.0;
+ vec3 targetOffset, targetPosition;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 pointPosition = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ }
+ outDistance = minDistance;
+ outColor.xyz = hash_vec3_to_vec3(cellPosition + targetOffset);
+ outPosition = safe_divide(targetPosition + cellPosition, scale);
+}
+
+void node_tex_voronoi_smooth_f1_3d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+ smoothness = clamp(smoothness / 2.0, 0, 0.5);
+
+ vec3 scaledCoord = coord * scale;
+ vec3 cellPosition = floor(scaledCoord);
+ vec3 localPosition = scaledCoord - cellPosition;
+
+ float smoothDistance = 8.0;
+ vec3 smoothColor = vec3(0.0);
+ vec3 smoothPosition = vec3(0.0);
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 pointPosition = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(
+ 0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0 - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0 + 3.0 * smoothness;
+ vec3 cellColor = hash_vec3_to_vec3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ }
+ outDistance = smoothDistance;
+ outColor.xyz = smoothColor;
+ outPosition = safe_divide(cellPosition + smoothPosition, scale);
+}
+
+void node_tex_voronoi_f2_3d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec3 scaledCoord = coord * scale;
+ vec3 cellPosition = floor(scaledCoord);
+ vec3 localPosition = scaledCoord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vec3 offsetF1 = vec3(0.0);
+ vec3 positionF1 = vec3(0.0);
+ vec3 offsetF2, positionF2;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 pointPosition = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ }
+ outDistance = distanceF2;
+ outColor.xyz = hash_vec3_to_vec3(cellPosition + offsetF2);
+ outPosition = safe_divide(positionF2 + cellPosition, scale);
+}
+
+void node_tex_voronoi_distance_to_edge_3d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec3 scaledCoord = coord * scale;
+ vec3 cellPosition = floor(scaledCoord);
+ vec3 localPosition = scaledCoord - cellPosition;
+
+ vec3 vectorToClosest;
+ float minDistance = 8.0;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 vectorToPoint = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 vectorToPoint = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness -
+ localPosition;
+ vec3 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ }
+ outDistance = minDistance;
+}
+
+void node_tex_voronoi_n_sphere_radius_3d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec3 scaledCoord = coord * scale;
+ vec3 cellPosition = floor(scaledCoord);
+ vec3 localPosition = scaledCoord - cellPosition;
+
+ vec3 closestPoint;
+ vec3 closestPointOffset;
+ float minDistance = 8.0;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 pointPosition = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ vec3 closestPointToClosestPoint;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0 && k == 0) {
+ continue;
+ }
+ vec3 cellOffset = vec3(i, j, k) + closestPointOffset;
+ vec3 pointPosition = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
+
+/* **** 4D Voronoi **** */
+
+float voronoi_distance(vec4 a, vec4 b, float metric, float exponent)
+{
+ if (metric == 0.0) // SHD_VORONOI_EUCLIDEAN
+ {
+ return distance(a, b);
+ }
+ else if (metric == 1.0) // SHD_VORONOI_MANHATTAN
+ {
+ return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z) + abs(a.w - b.w);
+ }
+ else if (metric == 2.0) // SHD_VORONOI_CHEBYCHEV
+ {
+ return max(abs(a.x - b.x), max(abs(a.y - b.y), max(abs(a.z - b.z), abs(a.w - b.w))));
+ }
+ else if (metric == 3.0) // SHD_VORONOI_MINKOWSKI
+ {
+ return pow(pow(abs(a.x - b.x), exponent) + pow(abs(a.y - b.y), exponent) +
+ pow(abs(a.z - b.z), exponent) + pow(abs(a.w - b.w), exponent),
+ 1.0 / exponent);
+ }
+ else {
+ return 0.0;
+ }
+}
+
+void node_tex_voronoi_f1_4d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec4 scaledCoord = vec4(coord, w) * scale;
+ vec4 cellPosition = floor(scaledCoord);
+ vec4 localPosition = scaledCoord - cellPosition;
+
+ float minDistance = 8.0;
+ vec4 targetOffset, targetPosition;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 pointPosition = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ outDistance = minDistance;
+ outColor.xyz = hash_vec4_to_vec3(cellPosition + targetOffset);
+ vec4 p = safe_divide(targetPosition + cellPosition, scale);
+ outPosition = p.xyz;
+ outW = p.w;
+}
+
+void node_tex_voronoi_smooth_f1_4d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+ smoothness = clamp(smoothness / 2.0, 0, 0.5);
+
+ vec4 scaledCoord = vec4(coord, w) * scale;
+ vec4 cellPosition = floor(scaledCoord);
+ vec4 localPosition = scaledCoord - cellPosition;
+
+ float smoothDistance = 8.0;
+ vec3 smoothColor = vec3(0.0);
+ vec4 smoothPosition = vec4(0.0);
+ for (int u = -2; u <= 2; u++) {
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 pointPosition = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(
+ 0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0 - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0 + 3.0 * smoothness;
+ vec3 cellColor = hash_vec4_to_vec3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ }
+ }
+ outDistance = smoothDistance;
+ outColor.xyz = smoothColor;
+ vec4 p = safe_divide(cellPosition + smoothPosition, scale);
+ outPosition = p.xyz;
+ outW = p.w;
+}
+
+void node_tex_voronoi_f2_4d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec4 scaledCoord = vec4(coord, w) * scale;
+ vec4 cellPosition = floor(scaledCoord);
+ vec4 localPosition = scaledCoord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vec4 offsetF1 = vec4(0.0);
+ vec4 positionF1 = vec4(0.0);
+ vec4 offsetF2, positionF2;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 pointPosition = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ outDistance = distanceF2;
+ outColor.xyz = hash_vec4_to_vec3(cellPosition + offsetF2);
+ vec4 p = safe_divide(positionF2 + cellPosition, scale);
+ outPosition = p.xyz;
+ outW = p.w;
+}
+
+void node_tex_voronoi_distance_to_edge_4d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec4 scaledCoord = vec4(coord, w) * scale;
+ vec4 cellPosition = floor(scaledCoord);
+ vec4 localPosition = scaledCoord - cellPosition;
+
+ vec4 vectorToClosest;
+ float minDistance = 8.0;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 vectorToPoint = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 vectorToPoint = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness -
+ localPosition;
+ vec4 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ }
+ }
+ outDistance = minDistance;
+}
+
+void node_tex_voronoi_n_sphere_radius_4d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec4 scaledCoord = vec4(coord, w) * scale;
+ vec4 cellPosition = floor(scaledCoord);
+ vec4 localPosition = scaledCoord - cellPosition;
+
+ vec4 closestPoint;
+ vec4 closestPointOffset;
+ float minDistance = 8.0;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 pointPosition = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ vec4 closestPointToClosestPoint;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0 && k == 0 && u == 0) {
+ continue;
+ }
+ vec4 cellOffset = vec4(i, j, k, u) + closestPointOffset;
+ vec4 pointPosition = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl
new file mode 100644
index 00000000000..fa79e3dc310
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl
@@ -0,0 +1,42 @@
+float calc_wave(
+ vec3 p, float distortion, float detail, float detail_scale, int wave_type, int wave_profile)
+{
+ float n;
+
+ if (wave_type == 0) { /* type bands */
+ n = (p.x + p.y + p.z) * 10.0;
+ }
+ else { /* type rings */
+ n = length(p) * 20.0;
+ }
+
+ if (distortion != 0.0) {
+ n += distortion * fractal_noise(p * detail_scale, detail);
+ }
+
+ if (wave_profile == 0) { /* profile sin */
+ return 0.5 + 0.5 * sin(n);
+ }
+ else { /* profile saw */
+ n /= 2.0 * M_PI;
+ n -= int(n);
+ return (n < 0.0) ? n + 1.0 : n;
+ }
+}
+
+void node_tex_wave(vec3 co,
+ float scale,
+ float distortion,
+ float detail,
+ float detail_scale,
+ float wave_type,
+ float wave_profile,
+ out vec4 color,
+ out float fac)
+{
+ float f;
+ f = calc_wave(co * scale, distortion, detail, detail_scale, int(wave_type), int(wave_profile));
+
+ color = vec4(f, f, f, 1.0);
+ fac = f;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl
new file mode 100644
index 00000000000..fce511deb79
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl
@@ -0,0 +1,21 @@
+/* White Noise */
+
+void node_white_noise_1d(vec3 vector, float w, out float value)
+{
+ value = hash_float_to_float(w);
+}
+
+void node_white_noise_2d(vec3 vector, float w, out float value)
+{
+ value = hash_vec2_to_float(vector.xy);
+}
+
+void node_white_noise_3d(vec3 vector, float w, out float value)
+{
+ value = hash_vec3_to_float(vector);
+}
+
+void node_white_noise_4d(vec3 vector, float w, out float value)
+{
+ value = hash_vec4_to_float(vec4(vector, w));
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl
new file mode 100644
index 00000000000..24276156d55
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl
@@ -0,0 +1,92 @@
+vec3 mtex_2d_mapping(vec3 vec)
+{
+ return vec3(vec.xy * 0.5 + vec2(0.5), vec.z);
+}
+
+void generated_from_orco(vec3 orco, out vec3 generated)
+{
+#ifdef VOLUMETRICS
+# ifdef MESH_SHADER
+ generated = volumeObjectLocalCoord;
+# else
+ generated = worldPosition;
+# endif
+#else
+ generated = orco;
+#endif
+}
+
+void generated_texco(vec3 I, vec3 attr_orco, out vec3 generated)
+{
+ vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
+ vec4 co_homogenous = (ProjectionMatrixInverse * v);
+ vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0);
+ co.xyz = normalize(co.xyz);
+#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
+ generated = (ViewMatrixInverse * co).xyz;
+#else
+ generated_from_orco(attr_orco, generated);
+#endif
+}
+
+void node_tex_coord(vec3 I,
+ vec3 wN,
+ mat4 obmatinv,
+ vec4 camerafac,
+ vec3 attr_orco,
+ vec3 attr_uv,
+ out vec3 generated,
+ out vec3 normal,
+ out vec3 uv,
+ out vec3 object,
+ out vec3 camera,
+ out vec3 window,
+ out vec3 reflection)
+{
+ generated = attr_orco;
+ normal = normalize(normal_world_to_object(wN));
+ uv = attr_uv;
+ object = (obmatinv * (ViewMatrixInverse * vec4(I, 1.0))).xyz;
+ camera = vec3(I.xy, -I.z);
+ vec4 projvec = ProjectionMatrix * vec4(I, 1.0);
+ window = vec3(mtex_2d_mapping(projvec.xyz / projvec.w).xy * camerafac.xy + camerafac.zw, 0.0);
+ reflection = -reflect(cameraVec, normalize(wN));
+}
+
+void node_tex_coord_background(vec3 I,
+ vec3 N,
+ mat4 obmatinv,
+ vec4 camerafac,
+ vec3 attr_orco,
+ vec3 attr_uv,
+ out vec3 generated,
+ out vec3 normal,
+ out vec3 uv,
+ out vec3 object,
+ out vec3 camera,
+ out vec3 window,
+ out vec3 reflection)
+{
+ vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
+ vec4 co_homogenous = (ProjectionMatrixInverse * v);
+
+ vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0);
+
+ co = normalize(co);
+
+ vec3 coords = (ViewMatrixInverse * co).xyz;
+
+ generated = coords;
+ normal = -coords;
+ uv = vec3(attr_uv.xy, 0.0);
+ object = (obmatinv * vec4(coords, 1.0)).xyz;
+
+ camera = vec3(co.xy, -co.z);
+ window = vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0);
+
+ reflection = -coords;
+}
+
+#if defined(WORLD_BACKGROUND) || (defined(PROBE_CAPTURE) && !defined(MESH_SHADER))
+# define node_tex_coord node_tex_coord_background
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl
new file mode 100644
index 00000000000..02d288d42bf
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl
@@ -0,0 +1,9 @@
+#ifndef VOLUMETRICS
+void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure result)
+{
+ node_bsdf_diffuse(color, 0.0, N, result);
+}
+#else
+/* Stub toon because it is not compatible with volumetrics. */
+# define node_bsdf_toon
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl
new file mode 100644
index 00000000000..749b3a4c11f
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl
@@ -0,0 +1,13 @@
+#ifndef VOLUMETRICS
+void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
+{
+ N = normalize(N);
+ result = CLOSURE_DEFAULT;
+ eevee_closure_diffuse(-N, color.rgb, 1.0, false, result.radiance);
+ closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
+ result.radiance *= color.rgb;
+}
+#else
+/* Stub translucent because it is not compatible with volumetrics. */
+# define node_bsdf_translucent
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl
new file mode 100644
index 00000000000..800d0f81d4a
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl
@@ -0,0 +1,11 @@
+#ifndef VOLUMETRICS
+void node_bsdf_transparent(vec4 color, out Closure result)
+{
+ result = CLOSURE_DEFAULT;
+ result.radiance = vec3(0.0);
+ result.transmittance = abs(color.rgb);
+}
+#else
+/* Stub transparent because it is not compatible with volumetrics. */
+# define node_bsdf_transparent
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_uv_map.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_uv_map.glsl
new file mode 100644
index 00000000000..d8fcbbfc361
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_uv_map.glsl
@@ -0,0 +1,4 @@
+void node_uvmap(vec3 attr_uv, out vec3 outvec)
+{
+ outvec = attr_uv;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl
new file mode 100644
index 00000000000..35d2e903cf4
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl
@@ -0,0 +1,8 @@
+void curves_vec(float fac, vec3 vec, sampler1DArray curvemap, float layer, out vec3 outvec)
+{
+ vec4 co = vec4(vec * 0.5 + 0.5, layer);
+ outvec.x = texture(curvemap, co.xw).x;
+ outvec.y = texture(curvemap, co.yw).y;
+ outvec.z = texture(curvemap, co.zw).z;
+ outvec = mix(vec, outvec, fac);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl
new file mode 100644
index 00000000000..b6b955dcdb4
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl
@@ -0,0 +1,30 @@
+void node_vector_displacement_tangent(vec4 vector,
+ float midlevel,
+ float scale,
+ vec4 tangent,
+ vec3 normal,
+ mat4 obmat,
+ mat4 viewmat,
+ out vec3 result)
+{
+ /* TODO(fclem) this is broken. revisit latter. */
+ vec3 N_object = normalize(((vec4(normal, 0.0) * viewmat) * obmat).xyz);
+ vec3 T_object = normalize(((vec4(tangent.xyz, 0.0) * viewmat) * obmat).xyz);
+ vec3 B_object = tangent.w * normalize(cross(N_object, T_object));
+
+ vec3 offset = (vector.xyz - vec3(midlevel)) * scale;
+ result = offset.x * T_object + offset.y * N_object + offset.z * B_object;
+ result = (obmat * vec4(result, 0.0)).xyz;
+}
+
+void node_vector_displacement_object(
+ vec4 vector, float midlevel, float scale, mat4 obmat, out vec3 result)
+{
+ result = (vector.xyz - vec3(midlevel)) * scale;
+ result = (obmat * vec4(result, 0.0)).xyz;
+}
+
+void node_vector_displacement_world(vec4 vector, float midlevel, float scale, out vec3 result)
+{
+ result = (vector.xyz - vec3(midlevel)) * scale;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl
new file mode 100644
index 00000000000..93132b6044f
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl
@@ -0,0 +1,100 @@
+void vector_math_add(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = a + b;
+}
+
+void vector_math_subtract(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = a - b;
+}
+
+void vector_math_multiply(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = a * b;
+}
+
+void vector_math_divide(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = safe_divide(a, b);
+}
+
+void vector_math_cross(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = cross(a, b);
+}
+
+void vector_math_project(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ float lenSquared = dot(b, b);
+ outVector = (lenSquared != 0.0) ? (dot(a, b) / lenSquared) * b : vec3(0.0);
+}
+
+void vector_math_reflect(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = reflect(a, normalize(b));
+}
+
+void vector_math_dot(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outValue = dot(a, b);
+}
+
+void vector_math_distance(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outValue = distance(a, b);
+}
+
+void vector_math_length(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outValue = length(a);
+}
+
+void vector_math_scale(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = a * scale;
+}
+
+void vector_math_normalize(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = normalize(a);
+}
+
+void vector_math_snap(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = floor(safe_divide(a, b)) * b;
+}
+
+void vector_math_floor(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = floor(a);
+}
+
+void vector_math_ceil(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = ceil(a);
+}
+
+void vector_math_modulo(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = c_mod(a, b);
+}
+
+void vector_math_fraction(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = fract(a);
+}
+
+void vector_math_absolute(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = abs(a);
+}
+
+void vector_math_minimum(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = min(a, b);
+}
+
+void vector_math_maximum(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = max(a, b);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl
new file mode 100644
index 00000000000..9646ffff8ca
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl
@@ -0,0 +1,9 @@
+#ifndef VOLUMETRICS
+void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out Closure result)
+{
+ node_bsdf_diffuse(color, 0.0, N, result);
+}
+#else
+/* Stub velvet because it is not compatible with volumetrics. */
+# define node_bsdf_velvet
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vertex_color.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vertex_color.glsl
new file mode 100644
index 00000000000..551b838daf8
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_vertex_color.glsl
@@ -0,0 +1,5 @@
+void node_vertex_color(vec4 vertexColor, out vec4 outColor, out float outAlpha)
+{
+ outColor = vertexColor;
+ outAlpha = vertexColor.a;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl
new file mode 100644
index 00000000000..e6c0880cd07
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl
@@ -0,0 +1,8 @@
+void node_volume_absorption(vec4 color, float density, out Closure result)
+{
+#ifdef VOLUMETRICS
+ result = Closure((1.0 - color.rgb) * density, vec3(0.0), vec3(0.0), 0.0);
+#else
+ result = CLOSURE_DEFAULT;
+#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl
new file mode 100644
index 00000000000..501aeb6f34e
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl
@@ -0,0 +1,88 @@
+void node_attribute_volume_density(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
+{
+#if defined(MESH_SHADER) && defined(VOLUMETRICS)
+ vec3 cos = volumeObjectLocalCoord;
+#else
+ vec3 cos = vec3(0.0);
+#endif
+ outvec = texture(tex, cos).aaa;
+ outcol = vec4(outvec, 1.0);
+ outf = avg(outvec);
+}
+
+uniform vec3 volumeColor = vec3(1.0);
+
+void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
+{
+#if defined(MESH_SHADER) && defined(VOLUMETRICS)
+ vec3 cos = volumeObjectLocalCoord;
+#else
+ vec3 cos = vec3(0.0);
+#endif
+
+ vec4 value = texture(tex, cos).rgba;
+ /* Density is premultiplied for interpolation, divide it out here. */
+ if (value.a > 1e-8) {
+ value.rgb /= value.a;
+ }
+
+ outvec = value.rgb * volumeColor;
+ outcol = vec4(outvec, 1.0);
+ outf = avg(outvec);
+}
+
+void node_attribute_volume_flame(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
+{
+#if defined(MESH_SHADER) && defined(VOLUMETRICS)
+ vec3 cos = volumeObjectLocalCoord;
+#else
+ vec3 cos = vec3(0.0);
+#endif
+ outf = texture(tex, cos).r;
+ outvec = vec3(outf, outf, outf);
+ outcol = vec4(outf, outf, outf, 1.0);
+}
+
+void node_attribute_volume_temperature(
+ sampler3D tex, vec2 temperature, out vec4 outcol, out vec3 outvec, out float outf)
+{
+#if defined(MESH_SHADER) && defined(VOLUMETRICS)
+ vec3 cos = volumeObjectLocalCoord;
+#else
+ vec3 cos = vec3(0.0);
+#endif
+ float flame = texture(tex, cos).r;
+
+ outf = (flame > 0.01) ? temperature.x + flame * (temperature.y - temperature.x) : 0.0;
+ outvec = vec3(outf, outf, outf);
+ outcol = vec4(outf, outf, outf, 1.0);
+}
+
+void node_volume_info(sampler3D densitySampler,
+ sampler3D flameSampler,
+ vec2 temperature,
+ out vec4 outColor,
+ out float outDensity,
+ out float outFlame,
+ out float outTemprature)
+{
+#if defined(MESH_SHADER) && defined(VOLUMETRICS)
+ vec3 p = volumeObjectLocalCoord;
+#else
+ vec3 p = vec3(0.0);
+#endif
+
+ vec4 density = texture(densitySampler, p);
+ outDensity = density.a;
+
+ /* Density is premultiplied for interpolation, divide it out here. */
+ if (density.a > 1e-8) {
+ density.rgb /= density.a;
+ }
+ outColor = vec4(density.rgb * volumeColor, 1.0);
+
+ float flame = texture(flameSampler, p).r;
+ outFlame = flame;
+
+ outTemprature = (flame > 0.01) ? temperature.x + flame * (temperature.y - temperature.x) : 0.0;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl
new file mode 100644
index 00000000000..884d5415c51
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl
@@ -0,0 +1,67 @@
+void node_volume_principled(vec4 color,
+ float density,
+ float anisotropy,
+ vec4 absorption_color,
+ float emission_strength,
+ vec4 emission_color,
+ float blackbody_intensity,
+ vec4 blackbody_tint,
+ float temperature,
+ float density_attribute,
+ vec4 color_attribute,
+ float temperature_attribute,
+ sampler1DArray spectrummap,
+ float layer,
+ out Closure result)
+{
+#ifdef VOLUMETRICS
+ vec3 absorption_coeff = vec3(0.0);
+ vec3 scatter_coeff = vec3(0.0);
+ vec3 emission_coeff = vec3(0.0);
+
+ /* Compute density. */
+ density = max(density, 0.0);
+
+ if (density > 1e-5) {
+ density = max(density * density_attribute, 0.0);
+ }
+
+ if (density > 1e-5) {
+ /* Compute scattering and absorption coefficients. */
+ vec3 scatter_color = color.rgb * color_attribute.rgb;
+
+ scatter_coeff = scatter_color * density;
+ absorption_color.rgb = sqrt(max(absorption_color.rgb, 0.0));
+ absorption_coeff = max(1.0 - scatter_color, 0.0) * max(1.0 - absorption_color.rgb, 0.0) *
+ density;
+ }
+
+ /* Compute emission. */
+ emission_strength = max(emission_strength, 0.0);
+
+ if (emission_strength > 1e-5) {
+ emission_coeff += emission_strength * emission_color.rgb;
+ }
+
+ if (blackbody_intensity > 1e-3) {
+ /* Add temperature from attribute. */
+ float T = max(temperature * max(temperature_attribute, 0.0), 0.0);
+
+ /* Stefan-Boltzman law. */
+ float T2 = T * T;
+ float T4 = T2 * T2;
+ float sigma = 5.670373e-8 * 1e-6 / M_PI;
+ float intensity = sigma * mix(1.0, T4, blackbody_intensity);
+
+ if (intensity > 1e-5) {
+ vec4 bb;
+ node_blackbody(T, spectrummap, layer, bb);
+ emission_coeff += bb.rgb * blackbody_tint.rgb * intensity;
+ }
+ }
+
+ result = Closure(absorption_coeff, scatter_coeff, emission_coeff, anisotropy);
+#else
+ result = CLOSURE_DEFAULT;
+#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl
new file mode 100644
index 00000000000..02c54658be5
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl
@@ -0,0 +1,8 @@
+void node_volume_scatter(vec4 color, float density, float anisotropy, out Closure result)
+{
+#ifdef VOLUMETRICS
+ result = Closure(vec3(0.0), color.rgb * density, vec3(0.0), anisotropy);
+#else
+ result = CLOSURE_DEFAULT;
+#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl
new file mode 100644
index 00000000000..2fcf1b8d914
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl
@@ -0,0 +1,31 @@
+#ifndef VOLUMETRICS
+void node_wireframe(float size, vec2 barycentric, vec3 barycentric_dist, out float fac)
+{
+ vec3 barys = barycentric.xyy;
+ barys.z = 1.0 - barycentric.x - barycentric.y;
+
+ size *= 0.5;
+ vec3 s = step(-size, -barys * barycentric_dist);
+
+ fac = max(s.x, max(s.y, s.z));
+}
+
+void node_wireframe_screenspace(float size, vec2 barycentric, out float fac)
+{
+ vec3 barys = barycentric.xyy;
+ barys.z = 1.0 - barycentric.x - barycentric.y;
+
+ size *= (1.0 / 3.0);
+ vec3 dx = dFdx(barys);
+ vec3 dy = dFdy(barys);
+ vec3 deltas = sqrt(dx * dx + dy * dy);
+
+ vec3 s = step(-deltas * size, -barys);
+
+ fac = max(s.x, max(s.y, s.z));
+}
+#else
+/* Stub wireframe because it is not compatible with volumetrics. */
+# define node_wireframe
+# define node_wireframe_screenspace
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl
new file mode 100644
index 00000000000..f9691beee6f
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl
@@ -0,0 +1,25 @@
+/* TODO : clean this ifdef mess */
+void world_normals_get(out vec3 N)
+{
+#ifndef VOLUMETRICS
+# ifdef HAIR_SHADER
+ vec3 B = normalize(cross(worldNormal, hairTangent));
+ float cos_theta;
+ if (hairThicknessRes == 1) {
+ vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0);
+ /* Random cosine normal distribution on the hair surface. */
+ cos_theta = rand.x * 2.0 - 1.0;
+ }
+ else {
+ /* Shade as a cylinder. */
+ cos_theta = hairThickTime / hairThickness;
+ }
+ float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
+ N = normalize(worldNormal * sin_theta + B * cos_theta);
+# else
+ N = gl_FrontFacing ? worldNormal : -worldNormal;
+# endif
+#else
+ generated_from_orco(vec3(0.0), N);
+#endif
+}
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index 2ceedca59f7..35910bc32b7 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -795,7 +795,7 @@ static void copypose_error(const iTaSC::ConstraintValues *values,
if (iktarget->controlType & iTaSC::CopyPose::CTL_POSITION) {
// update error
- for (i = 0, error = 0.0, value = values->values; i < values->number; ++i, ++value) {
+ for (i = 0, error = 0.0, value = values->values; i < values->number; i++, value++) {
error += KDL::sqr(value->y - value->yd);
}
iktarget->blenderConstraint->lin_error = (float)KDL::sqrt(error);
@@ -803,7 +803,7 @@ static void copypose_error(const iTaSC::ConstraintValues *values,
}
if (iktarget->controlType & iTaSC::CopyPose::CTL_ROTATION) {
// update error
- for (i = 0, error = 0.0, value = values->values; i < values->number; ++i, ++value) {
+ for (i = 0, error = 0.0, value = values->values; i < values->number; i++, value++) {
error += KDL::sqr(value->y - value->yd);
}
iktarget->blenderConstraint->rot_error = (float)KDL::sqrt(error);
@@ -966,7 +966,7 @@ static int convert_channels(struct Depsgraph *depsgraph,
int a, flag, njoint;
njoint = 0;
- for (a = 0, ikchan = ikscene->channels; a < ikscene->numchan; ++a, ++ikchan) {
+ for (a = 0, ikchan = ikscene->channels; a < ikscene->numchan; a++, ikchan++) {
pchan = tree->pchan[a];
ikchan->pchan = pchan;
ikchan->parent = (a > 0) ? tree->parent[a] : -1;
@@ -1106,7 +1106,7 @@ static void convert_pose(IK_Scene *ikscene)
rot = ikscene->jointArray(0);
for (joint = a = 0, ikchan = ikscene->channels;
a < ikscene->numchan && joint < ikscene->numjoint;
- ++a, ++ikchan) {
+ a++, ikchan++) {
pchan = ikchan->pchan;
bone = pchan->bone;
@@ -1149,7 +1149,7 @@ static void BKE_pose_rest(IK_Scene *ikscene)
rot = ikscene->jointArray(0);
for (joint = a = 0, ikchan = ikscene->channels;
a < ikscene->numchan && joint < ikscene->numjoint;
- ++a, ++ikchan) {
+ a++, ikchan++) {
pchan = ikchan->pchan;
bone = pchan->bone;
@@ -1234,7 +1234,7 @@ static IK_Scene *convert_tree(
BKE_pose_rest(ikscene);
rot = ikscene->jointArray(0);
- for (a = 0, ikchan = ikscene->channels; a < tree->totchannel; ++a, ++ikchan) {
+ for (a = 0, ikchan = ikscene->channels; a < tree->totchannel; a++, ikchan++) {
pchan = ikchan->pchan;
bone = pchan->bone;
@@ -1728,7 +1728,7 @@ static void execute_scene(struct Depsgraph *depsgraph,
int i;
IK_Channel *ikchan;
if (ikparam->flag & ITASC_SIMULATION) {
- for (i = 0, ikchan = ikscene->channels; i < ikscene->numchan; i++, ++ikchan) {
+ for (i = 0, ikchan = ikscene->channels; i < ikscene->numchan; i++, ikchan++) {
// In simulation mode we don't allow external constraint to change our bones,
// mark the channel done also tell Blender that this channel is part of IK tree.
// Cleared on each BKE_pose_where_is()
@@ -1738,7 +1738,7 @@ static void execute_scene(struct Depsgraph *depsgraph,
}
else {
// in animation mode, we must get the bone position from action and constraints
- for (i = 0, ikchan = ikscene->channels; i < ikscene->numchan; i++, ++ikchan) {
+ for (i = 0, ikchan = ikscene->channels; i < ikscene->numchan; i++, ikchan++) {
if (!(ikchan->pchan->flag & POSE_DONE)) {
BKE_pose_where_is_bone(depsgraph, blscene, ikscene->blArmature, ikchan->pchan, ctime, 1);
}
@@ -1749,7 +1749,7 @@ static void execute_scene(struct Depsgraph *depsgraph,
}
}
// only run execute the scene if at least one of our target is enabled
- for (i = ikscene->targets.size(); i > 0; --i) {
+ for (i = ikscene->targets.size(); i > 0; i--) {
IK_Target *iktarget = ikscene->targets[i - 1];
if (!(iktarget->blenderConstraint->flag & CONSTRAINT_OFF)) {
break;
@@ -1816,7 +1816,7 @@ static void execute_scene(struct Depsgraph *depsgraph,
}
}
// compute constraint error
- for (i = ikscene->targets.size(); i > 0; --i) {
+ for (i = ikscene->targets.size(); i > 0; i--) {
IK_Target *iktarget = ikscene->targets[i - 1];
if (!(iktarget->blenderConstraint->flag & CONSTRAINT_OFF) && iktarget->constraint) {
unsigned int nvalues;
@@ -1840,7 +1840,7 @@ static void execute_scene(struct Depsgraph *depsgraph,
float scale;
float length;
float yaxis[3];
- for (i = 0, ikchan = ikscene->channels; i < ikscene->numchan; ++i, ++ikchan) {
+ for (i = 0, ikchan = ikscene->channels; i < ikscene->numchan; i++, ikchan++) {
if (i == 0) {
if (!arm->getRelativeFrame(frame, ikchan->tail)) {
break;
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 571cac41399..9e9c47194e1 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -145,7 +145,8 @@ bool IMB_initImBuf(
struct ImBuf *IMB_allocFromBuffer(const unsigned int *rect,
const float *rectf,
unsigned int w,
- unsigned int h);
+ unsigned int h,
+ unsigned int channels);
/**
*
@@ -217,15 +218,20 @@ typedef enum IMB_BlendMode {
} IMB_BlendMode;
void IMB_blend_color_byte(unsigned char dst[4],
- unsigned char src1[4],
- unsigned char src2[4],
+ const unsigned char src1[4],
+ const unsigned char src2[4],
IMB_BlendMode mode);
-void IMB_blend_color_float(float dst[4], float src1[4], float src2[4], IMB_BlendMode mode);
+void IMB_blend_color_float(float dst[4],
+ const float src1[4],
+ const float src2[4],
+ IMB_BlendMode mode);
void IMB_rect_crop(struct ImBuf *ibuf, const struct rcti *crop);
+void IMB_rect_size_set(struct ImBuf *ibuf, const uint size[2]);
+
void IMB_rectclip(struct ImBuf *dbuf,
- struct ImBuf *sbuf,
+ const struct ImBuf *sbuf,
int *destx,
int *desty,
int *srcx,
@@ -233,7 +239,7 @@ void IMB_rectclip(struct ImBuf *dbuf,
int *width,
int *height);
void IMB_rectcpy(struct ImBuf *drect,
- struct ImBuf *srect,
+ const struct ImBuf *srect,
int destx,
int desty,
int srcx,
@@ -241,11 +247,11 @@ void IMB_rectcpy(struct ImBuf *drect,
int width,
int height);
void IMB_rectblend(struct ImBuf *dbuf,
- struct ImBuf *obuf,
- struct ImBuf *sbuf,
+ const struct ImBuf *obuf,
+ const struct ImBuf *sbuf,
unsigned short *dmask,
- unsigned short *curvemask,
- unsigned short *mmask,
+ const unsigned short *curvemask,
+ const unsigned short *mmask,
float mask_max,
int destx,
int desty,
@@ -258,11 +264,11 @@ void IMB_rectblend(struct ImBuf *dbuf,
IMB_BlendMode mode,
bool accumulate);
void IMB_rectblend_threaded(struct ImBuf *dbuf,
- struct ImBuf *obuf,
- struct ImBuf *sbuf,
+ const struct ImBuf *obuf,
+ const struct ImBuf *sbuf,
unsigned short *dmask,
- unsigned short *curvemask,
- unsigned short *mmask,
+ const unsigned short *curvemask,
+ const unsigned short *mmask,
float mask_max,
int destx,
int desty,
@@ -476,7 +482,7 @@ int imb_get_anim_type(const char *name);
*
* \attention Defined in util.c
*/
-bool IMB_isfloat(struct ImBuf *ibuf);
+bool IMB_isfloat(const struct ImBuf *ibuf);
/* Do byte/float and colorspace conversions need to take alpha into account? */
bool IMB_alpha_affects_rgb(const struct ImBuf *ibuf);
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h
index 065c7e64d07..9ad88f24693 100644
--- a/source/blender/imbuf/intern/IMB_anim.h
+++ b/source/blender/imbuf/intern/IMB_anim.h
@@ -89,7 +89,7 @@ struct anim {
int ib_flags;
int curtype;
int curposition; /* index 0 = 1e, 1 = 2e, enz. */
- int duration;
+ int duration_in_frames;
int frs_sec;
double frs_sec_base;
int x, y;
diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h
index 5048414ac65..52db0b80441 100644
--- a/source/blender/imbuf/intern/IMB_filetype.h
+++ b/source/blender/imbuf/intern/IMB_filetype.h
@@ -33,7 +33,7 @@ typedef struct ImFileType {
int (*is_a)(const unsigned char *buf);
int (*is_a_filepath)(const char *name);
- int (*ftype)(const struct ImFileType *type, struct ImBuf *ibuf);
+ int (*ftype)(const struct ImFileType *type, const struct ImBuf *ibuf);
struct ImBuf *(*load)(const unsigned char *mem,
size_t size,
int flags,
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index 7d2f51af65e..75db3fd3c73 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -428,7 +428,8 @@ bool imb_addrectImBuf(ImBuf *ibuf)
struct ImBuf *IMB_allocFromBuffer(const unsigned int *rect,
const float *rectf,
unsigned int w,
- unsigned int h)
+ unsigned int h,
+ unsigned int channels)
{
ImBuf *ibuf = NULL;
@@ -438,6 +439,7 @@ struct ImBuf *IMB_allocFromBuffer(const unsigned int *rect,
ibuf = IMB_allocImBuf(w, h, 32, 0);
+ ibuf->channels = channels;
if (rectf) {
ibuf->rect_float = MEM_dupallocN(rectf);
ibuf->flags |= IB_rectfloat;
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index 52d8db95054..232a9998ebf 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -199,7 +199,7 @@ static void free_anim_avi(struct anim *anim)
}
# endif
- anim->duration = 0;
+ anim->duration_in_frames = 0;
}
#endif /* WITH_AVI */
@@ -408,7 +408,7 @@ static int startavi(struct anim *anim)
return -1;
}
- anim->duration = anim->avi->header->TotalFrames;
+ anim->duration_in_frames = anim->avi->header->TotalFrames;
anim->params = NULL;
anim->x = anim->avi->header->Width;
@@ -426,7 +426,7 @@ static int startavi(struct anim *anim)
anim->y,
anim->framesize,
anim->interlacing,
- anim->duration);
+ anim->duration_in_frames);
# endif
return 0;
@@ -493,12 +493,13 @@ BLI_INLINE bool need_aligned_ffmpeg_buffer(struct anim *anim)
static int startffmpeg(struct anim *anim)
{
- int i, videoStream;
+ int i, video_stream_index;
AVCodec *pCodec;
AVFormatContext *pFormatCtx = NULL;
AVCodecContext *pCodecCtx;
AVRational frame_rate;
+ AVStream *video_stream;
int frs_num;
double frs_den;
int streamcount;
@@ -528,7 +529,7 @@ static int startffmpeg(struct anim *anim)
av_dump_format(pFormatCtx, 0, anim->name, 0);
/* Find the video stream */
- videoStream = -1;
+ video_stream_index = -1;
for (i = 0; i < pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
@@ -536,17 +537,18 @@ static int startffmpeg(struct anim *anim)
streamcount--;
continue;
}
- videoStream = i;
+ video_stream_index = i;
break;
}
}
- if (videoStream == -1) {
+ if (video_stream_index == -1) {
avformat_close_input(&pFormatCtx);
return -1;
}
- pCodecCtx = pFormatCtx->streams[videoStream]->codec;
+ video_stream = pFormatCtx->streams[video_stream_index];
+ pCodecCtx = video_stream->codec;
/* Find the decoder for the video stream */
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
@@ -567,12 +569,29 @@ static int startffmpeg(struct anim *anim)
return -1;
}
- frame_rate = av_get_r_frame_rate_compat(pFormatCtx, pFormatCtx->streams[videoStream]);
- if (pFormatCtx->streams[videoStream]->nb_frames != 0) {
- anim->duration = pFormatCtx->streams[videoStream]->nb_frames;
+ frame_rate = av_guess_frame_rate(pFormatCtx, video_stream, NULL);
+ anim->duration_in_frames = 0;
+
+ /* Take from the stream if we can. */
+ if (video_stream->nb_frames != 0) {
+ anim->duration_in_frames = video_stream->nb_frames;
+
+ /* Sanity check on the detected duration. This is to work around corruption like reported in
+ * T68091. */
+ if (frame_rate.den != 0 && pFormatCtx->duration > 0) {
+ double stream_sec = anim->duration_in_frames * av_q2d(frame_rate);
+ double container_sec = pFormatCtx->duration / (double)AV_TIME_BASE;
+ if (stream_sec > 4.0 * container_sec) {
+ /* The stream is significantly longer than the container duration, which is
+ * suspicious. */
+ anim->duration_in_frames = 0;
+ }
+ }
}
- else {
- anim->duration = (int)(pFormatCtx->duration * av_q2d(frame_rate) / AV_TIME_BASE + 0.5f);
+ /* Fall back to the container. */
+ if (anim->duration_in_frames == 0) {
+ anim->duration_in_frames = (int)(pFormatCtx->duration * av_q2d(frame_rate) / AV_TIME_BASE +
+ 0.5f);
}
frs_num = frame_rate.num;
@@ -596,7 +615,7 @@ static int startffmpeg(struct anim *anim)
anim->pFormatCtx = pFormatCtx;
anim->pCodecCtx = pCodecCtx;
anim->pCodec = pCodec;
- anim->videoStream = videoStream;
+ anim->videoStream = video_stream_index;
anim->interlacing = 0;
anim->orientation = 0;
@@ -1038,7 +1057,7 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ
v_st = anim->pFormatCtx->streams[anim->videoStream];
- frame_rate = av_q2d(av_get_r_frame_rate_compat(anim->pFormatCtx, v_st));
+ frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL));
st_time = anim->pFormatCtx->start_time;
pts_time_base = av_q2d(v_st->time_base);
@@ -1222,7 +1241,7 @@ static void free_anim_ffmpeg(struct anim *anim)
av_free_packet(&anim->next_packet);
}
}
- anim->duration = 0;
+ anim->duration_in_frames = 0;
}
#endif
@@ -1259,7 +1278,7 @@ static ImBuf *anim_getnew(struct anim *anim)
ibuf = IMB_loadiffname(anim->name, anim->ib_flags, anim->colorspace);
if (ibuf) {
BLI_strncpy(anim->first, anim->name, sizeof(anim->first));
- anim->duration = 1;
+ anim->duration_in_frames = 1;
}
break;
case ANIM_MOVIE:
@@ -1297,7 +1316,7 @@ struct ImBuf *IMB_anim_previewframe(struct anim *anim)
ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
if (ibuf) {
IMB_freeImBuf(ibuf);
- position = anim->duration / 2;
+ position = anim->duration_in_frames / 2;
ibuf = IMB_anim_absolute(anim, position, IMB_TC_NONE, IMB_PROXY_NONE);
}
return ibuf;
@@ -1333,7 +1352,7 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim,
if (position < 0) {
return (NULL);
}
- if (position >= anim->duration) {
+ if (position >= anim->duration_in_frames) {
return (NULL);
}
}
@@ -1398,12 +1417,12 @@ int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc)
{
struct anim_index *idx;
if (tc == IMB_TC_NONE) {
- return anim->duration;
+ return anim->duration_in_frames;
}
idx = IMB_anim_open_index(anim, tc);
if (!idx) {
- return anim->duration;
+ return anim->duration_in_frames;
}
return IMB_indexer_get_duration(idx);
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 36af7ab2571..1b911226c6f 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -3961,8 +3961,7 @@ static void update_glsl_display_processor(const ColorManagedViewSettings *view_s
/* We're using curve mapping's address as a cache ID,
* so we need to make sure re-allocation gives new address here.
- * We do this by allocating new curve mapping before freeing ol one.
- */
+ * We do this by allocating new curve mapping before freeing old one. */
if (use_curve_mapping) {
new_curve_mapping = BKE_curvemapping_copy(view_settings->curve_mapping);
}
diff --git a/source/blender/imbuf/intern/dds/FlipDXT.cpp b/source/blender/imbuf/intern/dds/FlipDXT.cpp
index cf228cea3ea..bfd19f40493 100644
--- a/source/blender/imbuf/intern/dds/FlipDXT.cpp
+++ b/source/blender/imbuf/intern/dds/FlipDXT.cpp
@@ -208,7 +208,7 @@ int FlipDXTCImage(
unsigned int mip_width = width;
unsigned int mip_height = height;
- for (unsigned int i = 0; i < levels; ++i) {
+ for (unsigned int i = 0; i < levels; i++) {
unsigned int blocks_per_row = (mip_width + 3) / 4;
unsigned int blocks_per_col = (mip_height + 3) / 4;
unsigned int blocks = blocks_per_row * blocks_per_col;
@@ -219,13 +219,13 @@ int FlipDXTCImage(
}
else if (mip_height == 2) {
// flip the first 2 lines in each block.
- for (unsigned int i = 0; i < blocks_per_row; ++i) {
+ for (unsigned int i = 0; i < blocks_per_row; i++) {
half_block_function(data + i * block_bytes);
}
}
else {
// flip each block.
- for (unsigned int i = 0; i < blocks; ++i) {
+ for (unsigned int i = 0; i < blocks; i++) {
full_block_function(data + i * block_bytes);
}
@@ -235,7 +235,7 @@ int FlipDXTCImage(
unsigned int row_bytes = block_bytes * blocks_per_row;
uint8_t *temp_line = new uint8_t[row_bytes];
- for (unsigned int y = 0; y < blocks_per_col / 2; ++y) {
+ for (unsigned int y = 0; y < blocks_per_col / 2; y++) {
uint8_t *line1 = data + y * row_bytes;
uint8_t *line2 = data + (blocks_per_col - y - 1) * row_bytes;
diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c
index d1b3bf21e23..c6f8bab325b 100644
--- a/source/blender/imbuf/intern/filetype.c
+++ b/source/blender/imbuf/intern/filetype.c
@@ -40,11 +40,11 @@
# include "dds/dds_api.h"
#endif
-static int imb_ftype_default(const ImFileType *type, ImBuf *ibuf)
+static int imb_ftype_default(const ImFileType *type, const ImBuf *ibuf)
{
return (ibuf->ftype == type->filetype);
}
-static int imb_ftype_iris(const ImFileType *type, ImBuf *ibuf)
+static int imb_ftype_iris(const ImFileType *type, const ImBuf *ibuf)
{
(void)type;
return (ibuf->ftype == IMB_FTYPE_IMAGIC);
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index dd31dafd148..97a0cc85301 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -900,7 +900,7 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
stream_size = avio_size(context->iFormatCtx->pb);
- context->frame_rate = av_q2d(av_get_r_frame_rate_compat(context->iFormatCtx, context->iStream));
+ context->frame_rate = av_q2d(av_guess_frame_rate(context->iFormatCtx, context->iStream, NULL));
context->pts_time_base = av_q2d(context->iStream->time_base);
while (av_read_frame(context->iFormatCtx, &next_packet) >= 0) {
@@ -1150,7 +1150,7 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
/* Don't generate the same file twice! */
if (file_list) {
- for (i = 0; i < IMB_PROXY_MAX_SLOT; ++i) {
+ for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
IMB_Proxy_Size proxy_size = proxy_sizes[i];
if (proxy_size & proxy_sizes_to_build) {
char filename[FILE_MAX];
@@ -1172,7 +1172,7 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
IMB_Proxy_Size built_proxies = IMB_anim_proxy_get_existing(anim);
if (built_proxies != 0) {
- for (i = 0; i < IMB_PROXY_MAX_SLOT; ++i) {
+ for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
IMB_Proxy_Size proxy_size = proxy_sizes[i];
if (proxy_size & built_proxies) {
char filename[FILE_MAX];
@@ -1345,7 +1345,7 @@ IMB_Proxy_Size IMB_anim_proxy_get_existing(struct anim *anim)
const int num_proxy_sizes = IMB_PROXY_MAX_SLOT;
IMB_Proxy_Size existing = 0;
int i;
- for (i = 0; i < num_proxy_sizes; ++i) {
+ for (i = 0; i < num_proxy_sizes; i++) {
IMB_Proxy_Size proxy_size = proxy_sizes[i];
char filename[FILE_MAX];
get_proxy_filename(anim, proxy_size, filename, false);
diff --git a/source/blender/imbuf/intern/jp2.c b/source/blender/imbuf/intern/jp2.c
index 3bf97cb851f..e361df1304a 100644
--- a/source/blender/imbuf/intern/jp2.c
+++ b/source/blender/imbuf/intern/jp2.c
@@ -83,7 +83,7 @@ static OPJ_CODEC_FORMAT format_from_header(const unsigned char mem[JP2_FILEHEADE
int imb_is_a_jp2(const unsigned char *buf)
{
- return check_jp2(buf);
+ return (check_jp2(buf) || check_j2k(buf));
}
/**
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index f18eb2f7303..88dfa42a416 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -1118,7 +1118,7 @@ void IMB_exr_write_channels(void *handle)
if (echan->use_half_float) {
float *rect = echan->rect;
half *cur = current_rect_half;
- for (size_t i = 0; i < num_pixels; ++i, ++cur) {
+ for (size_t i = 0; i < num_pixels; i++, cur++) {
*cur = rect[i * echan->xstride];
}
half *rect_to_write = current_rect_half + (data->height - 1L) * data->width;
@@ -2013,7 +2013,7 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem,
if (!has_rgb && has_luma) {
size_t a;
if (exr_has_chroma(*file)) {
- for (a = 0; a < (size_t)ibuf->x * ibuf->y; ++a) {
+ for (a = 0; a < (size_t)ibuf->x * ibuf->y; a++) {
float *color = ibuf->rect_float + a * 4;
ycc_to_rgb(color[0] * 255.0f,
color[1] * 255.0f,
@@ -2025,7 +2025,7 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem,
}
}
else {
- for (a = 0; a < (size_t)ibuf->x * ibuf->y; ++a) {
+ for (a = 0; a < (size_t)ibuf->x * ibuf->y; a++) {
float *color = ibuf->rect_float + a * 4;
color[1] = color[2] = color[0];
}
diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c
index 76918c216f7..3163a960892 100644
--- a/source/blender/imbuf/intern/rectop.c
+++ b/source/blender/imbuf/intern/rectop.c
@@ -39,8 +39,8 @@
#include "MEM_guardedalloc.h"
void IMB_blend_color_byte(unsigned char dst[4],
- unsigned char src1[4],
- unsigned char src2[4],
+ const unsigned char src1[4],
+ const unsigned char src2[4],
IMB_BlendMode mode)
{
switch (mode) {
@@ -126,7 +126,10 @@ void IMB_blend_color_byte(unsigned char dst[4],
}
}
-void IMB_blend_color_float(float dst[4], float src1[4], float src2[4], IMB_BlendMode mode)
+void IMB_blend_color_float(float dst[4],
+ const float src1[4],
+ const float src2[4],
+ IMB_BlendMode mode)
{
switch (mode) {
case IMB_BLEND_MIX:
@@ -276,10 +279,49 @@ void IMB_rect_crop(ImBuf *ibuf, const rcti *crop)
ibuf->y = size_dst[1];
}
+/** Re-alloc buffers at a new size */
+
+static void rect_realloc_4bytes(void **buf_p, const uint size[2])
+{
+ if (*buf_p == NULL) {
+ return;
+ }
+ MEM_freeN(*buf_p);
+ *buf_p = MEM_mallocN(sizeof(uint) * size[0] * size[1], __func__);
+}
+
+static void rect_realloc_16bytes(void **buf_p, const uint size[2])
+{
+ if (*buf_p == NULL) {
+ return;
+ }
+ MEM_freeN(*buf_p);
+ *buf_p = MEM_mallocN(sizeof(uint[4]) * size[0] * size[1], __func__);
+}
+
+/**
+ * In-place size setting (caller must fill in buffer contents).
+ */
+void IMB_rect_size_set(ImBuf *ibuf, const uint size[2])
+{
+ BLI_assert(size[0] > 0 && size[0] > 0);
+ if ((size[0] == ibuf->x) && (size[1] == ibuf->y)) {
+ return;
+ }
+
+ rect_realloc_4bytes((void **)&ibuf->rect, size);
+ rect_realloc_4bytes((void **)&ibuf->zbuf, size);
+ rect_realloc_4bytes((void **)&ibuf->zbuf_float, size);
+ rect_realloc_16bytes((void **)&ibuf->rect_float, size);
+
+ ibuf->x = size[0];
+ ibuf->y = size[1];
+}
+
/* clipping */
void IMB_rectclip(ImBuf *dbuf,
- ImBuf *sbuf,
+ const ImBuf *sbuf,
int *destx,
int *desty,
int *srcx,
@@ -341,8 +383,8 @@ void IMB_rectclip(ImBuf *dbuf,
}
static void imb_rectclip3(ImBuf *dbuf,
- ImBuf *obuf,
- ImBuf *sbuf,
+ const ImBuf *obuf,
+ const ImBuf *sbuf,
int *destx,
int *desty,
int *origx,
@@ -435,8 +477,14 @@ static void imb_rectclip3(ImBuf *dbuf,
/* copy and blend */
-void IMB_rectcpy(
- ImBuf *dbuf, ImBuf *sbuf, int destx, int desty, int srcx, int srcy, int width, int height)
+void IMB_rectcpy(ImBuf *dbuf,
+ const ImBuf *sbuf,
+ int destx,
+ int desty,
+ int srcx,
+ int srcy,
+ int width,
+ int height)
{
IMB_rectblend(dbuf,
dbuf,
@@ -463,11 +511,11 @@ typedef void (*IMB_blend_func)(unsigned char *dst,
typedef void (*IMB_blend_func_float)(float *dst, const float *src1, const float *src2);
void IMB_rectblend(ImBuf *dbuf,
- ImBuf *obuf,
- ImBuf *sbuf,
+ const ImBuf *obuf,
+ const ImBuf *sbuf,
unsigned short *dmask,
- unsigned short *curvemask,
- unsigned short *texmask,
+ const unsigned short *curvemask,
+ const unsigned short *texmask,
float mask_max,
int destx,
int desty,
@@ -482,9 +530,9 @@ void IMB_rectblend(ImBuf *dbuf,
{
unsigned int *drect = NULL, *orect = NULL, *srect = NULL, *dr, * or, *sr;
float *drectf = NULL, *orectf = NULL, *srectf = NULL, *drf, *orf, *srf;
- unsigned short *cmaskrect = curvemask, *cmr;
+ const unsigned short *cmaskrect = curvemask, *cmr;
unsigned short *dmaskrect = dmask, *dmr;
- unsigned short *texmaskrect = texmask, *tmr;
+ const unsigned short *texmaskrect = texmask, *tmr;
int do_float, do_char, srcskip, destskip, origskip, x;
IMB_blend_func func = NULL;
IMB_blend_func_float func_float = NULL;
@@ -924,8 +972,10 @@ void IMB_rectblend(ImBuf *dbuf,
}
typedef struct RectBlendThreadData {
- ImBuf *dbuf, *obuf, *sbuf;
- unsigned short *dmask, *curvemask, *texmask;
+ ImBuf *dbuf;
+ const ImBuf *obuf, *sbuf;
+ unsigned short *dmask;
+ const unsigned short *curvemask, *texmask;
float mask_max;
int destx, desty, origx, origy;
int srcx, srcy, width;
@@ -956,11 +1006,11 @@ static void rectblend_thread_do(void *data_v, int start_scanline, int num_scanli
}
void IMB_rectblend_threaded(ImBuf *dbuf,
- ImBuf *obuf,
- ImBuf *sbuf,
+ const ImBuf *obuf,
+ const ImBuf *sbuf,
unsigned short *dmask,
- unsigned short *curvemask,
- unsigned short *texmask,
+ const unsigned short *curvemask,
+ const unsigned short *texmask,
float mask_max,
int destx,
int desty,
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
index 44c311eba9d..71750c9c28f 100644
--- a/source/blender/imbuf/intern/stereoimbuf.c
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -68,7 +68,7 @@ static void imb_stereo3d_write_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyp
const int stride_from = width;
const int stride_to = width;
- int anaglyph_encoding[3][3] = {
+ const int anaglyph_encoding[3][3] = {
{0, 1, 1},
{1, 0, 1},
{0, 0, 1},
@@ -810,7 +810,7 @@ static void imb_stereo3d_read_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyph
const int stride_from = width;
const int stride_to = width;
- int anaglyph_encoding[3][3] = {
+ const int anaglyph_encoding[3][3] = {
{0, 1, 1},
{1, 0, 1},
{0, 0, 1},
diff --git a/source/blender/imbuf/intern/targa.c b/source/blender/imbuf/intern/targa.c
index f7b7df52e46..b1077a6ae91 100644
--- a/source/blender/imbuf/intern/targa.c
+++ b/source/blender/imbuf/intern/targa.c
@@ -748,7 +748,7 @@ ImBuf *imb_loadtarga(const unsigned char *mem,
if (cmap) {
/* apply color map */
rect = ibuf->rect;
- for (size = ibuf->x * ibuf->y; size > 0; --size, ++rect) {
+ for (size = ibuf->x * ibuf->y; size > 0; size--, rect++) {
int cmap_index = *rect;
if (cmap_index >= 0 && cmap_index < cmap_max) {
*rect = cmap[cmap_index];
@@ -761,7 +761,7 @@ ImBuf *imb_loadtarga(const unsigned char *mem,
if (tga.pixsize == 16) {
unsigned int col;
rect = ibuf->rect;
- for (size = ibuf->x * ibuf->y; size > 0; --size, ++rect) {
+ for (size = ibuf->x * ibuf->y; size > 0; size--, rect++) {
col = *rect;
cp = (uchar *)rect;
mem = (uchar *)&col;
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c
index ff7cb87960e..27b566e25a2 100644
--- a/source/blender/imbuf/intern/util.c
+++ b/source/blender/imbuf/intern/util.c
@@ -252,6 +252,8 @@ static int isffmpeg(const char *filename)
if (BLI_path_extension_check_n(filename,
".swf",
".jpg",
+ ".jp2",
+ ".j2c",
".png",
".dds",
".tga",
@@ -389,7 +391,7 @@ bool IMB_isanim(const char *filename)
return (type && type != ANIM_SEQUENCE);
}
-bool IMB_isfloat(ImBuf *ibuf)
+bool IMB_isfloat(const ImBuf *ibuf)
{
const ImFileType *type;
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index ef9069acb78..a6212e09567 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -432,10 +432,15 @@ typedef enum ID_Type {
#define ID_BLEND_PATH_FROM_GLOBAL(_id) \
((_id)->lib ? (_id)->lib->filepath : BKE_main_blendfile_path_from_global())
-#define ID_MISSING(_id) (((_id)->tag & LIB_TAG_MISSING) != 0)
+#define ID_MISSING(_id) ((((ID *)(_id))->tag & LIB_TAG_MISSING) != 0)
#define ID_IS_LINKED(_id) (((ID *)(_id))->lib != NULL)
+/* Note that this is a fairly high-level check, should be used at user interaction level, not in
+ * BKE_library_override typically (especially due to the check on LIB_TAG_EXTERN). */
+#define ID_IS_OVERRIDABLE_LIBRARY(_id) \
+ (ID_IS_LINKED(_id) && !ID_MISSING(_id) && (((ID *)(_id))->tag & LIB_TAG_EXTERN) != 0)
+
#define ID_IS_OVERRIDE_LIBRARY(_id) \
(((ID *)(_id))->override_library != NULL && ((ID *)(_id))->override_library->reference != NULL)
@@ -467,7 +472,15 @@ typedef enum ID_Type {
/* id->flag (persitent). */
enum {
+ /* Don't delete the datablock even if unused. */
LIB_FAKEUSER = 1 << 9,
+ /* The datablock structure is a sub-object of a different one.
+ * Direct persistent references are not allowed. */
+ LIB_PRIVATE_DATA = 1 << 10,
+ /* Datablock is from a library and linked indirectly, with LIB_TAG_INDIRECT
+ * tag set. But the current .blend file also has a weak pointer to it that
+ * we want to restore if possible, and silently drop if it's missing. */
+ LIB_INDIRECT_WEAK_LINK = 1 << 11,
};
/**
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index 1718aabc51d..70add4c156f 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -319,6 +319,10 @@ typedef struct DriverTarget {
/** Transform channel index (for DVAR_TYPE_TRANSFORM_CHAN.)*/
short transChan;
+ /** Rotation channel calculation type. */
+ char rotation_mode;
+ char _pad[7];
+
/**
* Flags for the validity of the target
* (NOTE: these get reset every time the types change).
@@ -358,10 +362,36 @@ typedef enum eDriverTarget_TransformChannels {
DTAR_TRANSCHAN_SCALEY,
DTAR_TRANSCHAN_SCALEZ,
DTAR_TRANSCHAN_SCALE_AVG,
+ DTAR_TRANSCHAN_ROTW,
MAX_DTAR_TRANSCHAN_TYPES,
} eDriverTarget_TransformChannels;
+/* Rotation channel mode for Driver Targets */
+typedef enum eDriverTarget_RotationMode {
+ /** Automatic euler mode. */
+ DTAR_ROTMODE_AUTO = 0,
+
+ /** Explicit euler rotation modes - must sync with BLI_math_rotation.h defines. */
+ DTAR_ROTMODE_EULER_XYZ = 1,
+ DTAR_ROTMODE_EULER_XZY,
+ DTAR_ROTMODE_EULER_YXZ,
+ DTAR_ROTMODE_EULER_YZX,
+ DTAR_ROTMODE_EULER_ZXY,
+ DTAR_ROTMODE_EULER_ZYX,
+
+ DTAR_ROTMODE_QUATERNION,
+
+ /** Implements the very common Damped Track + child trick to decompose
+ * rotation into bending followed by twist around the remaining axis. */
+ DTAR_ROTMODE_SWING_TWIST_X,
+ DTAR_ROTMODE_SWING_TWIST_Y,
+ DTAR_ROTMODE_SWING_TWIST_Z,
+
+ DTAR_ROTMODE_EULER_MIN = DTAR_ROTMODE_EULER_XYZ,
+ DTAR_ROTMODE_EULER_MAX = DTAR_ROTMODE_EULER_ZYX,
+} eDriverTarget_RotationMode;
+
/* --- */
/* maximum number of driver targets per variable */
diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h
index 088fd96a5ae..68241df3f93 100644
--- a/source/blender/makesdna/DNA_armature_types.h
+++ b/source/blender/makesdna/DNA_armature_types.h
@@ -60,6 +60,9 @@ typedef struct Bone {
int flag;
+ char inherit_scale_mode;
+ char _pad[7];
+
float arm_head[3];
/** head/tail in Armature Space (rest pos). */
float arm_tail[3];
@@ -229,8 +232,10 @@ typedef enum eBone_Flag {
BONE_UNKEYED = (1 << 13),
/** set to prevent hinge child bones from influencing the transform center */
BONE_HINGE_CHILD_TRANSFORM = (1 << 14),
+#ifdef DNA_DEPRECATED
/** No parent scale */
BONE_NO_SCALE = (1 << 15),
+#endif
/** hidden bone when drawing PoseChannels (for ghost drawing) */
BONE_HIDDEN_PG = (1 << 16),
/** bone should be drawn as OB_WIRE, regardless of draw-types of view+armature */
@@ -254,6 +259,20 @@ typedef enum eBone_Flag {
} eBone_Flag;
+/* bone->inherit_scale_mode */
+typedef enum eBone_InheritScaleMode {
+ /* Inherit all scale and shear. */
+ BONE_INHERIT_SCALE_FULL = 0,
+ /* Inherit scale, but remove final shear. */
+ BONE_INHERIT_SCALE_FIX_SHEAR,
+ /* Inherit average scale. */
+ BONE_INHERIT_SCALE_AVERAGE,
+ /* Inherit no scale or shear. */
+ BONE_INHERIT_SCALE_NONE,
+ /* Inherit effects of shear on parent (same as old disabled Inherit Scale). */
+ BONE_INHERIT_SCALE_NONE_LEGACY,
+} eBone_InheritScaleMode;
+
/* bone->bbone_prev_type, bbone_next_type */
typedef enum eBone_BBoneHandleType {
BBONE_HANDLE_AUTO = 0, /* Default mode based on parents & children. */
diff --git a/source/blender/makesdna/DNA_brush_defaults.h b/source/blender/makesdna/DNA_brush_defaults.h
new file mode 100644
index 00000000000..714c205cda2
--- /dev/null
+++ b/source/blender/makesdna/DNA_brush_defaults.h
@@ -0,0 +1,105 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_BRUSH_DEFAULTS_H__
+#define __DNA_BRUSH_DEFAULTS_H__
+
+#include "DNA_texture_defaults.h"
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Brush Struct
+ * \{ */
+
+#define _DNA_DEFAULT_Brush \
+ { \
+ .blend = 0, \
+ .flag = (BRUSH_ALPHA_PRESSURE | BRUSH_SPACE | BRUSH_SPACE_ATTEN), \
+ \
+ .ob_mode = OB_MODE_ALL_PAINT, \
+ \
+ /* BRUSH SCULPT TOOL SETTINGS */ \
+ .weight = 1.0f, /* weight of brush 0 - 1.0 */ \
+ .size = 35, /* radius of the brush in pixels */ \
+ .alpha = 1.0f, /* brush strength/intensity probably variable should be renamed? */ \
+ .autosmooth_factor = 0.0f, \
+ .topology_rake_factor = 0.0f, \
+ .crease_pinch_factor = 0.5f, \
+ .normal_radius_factor = 0.5f, \
+ .sculpt_plane = SCULPT_DISP_DIR_AREA, \
+ /* How far above or below the plane that is found by averaging the faces. */ \
+ .plane_offset = 0.0f, \
+ .plane_trim = 0.5f, \
+ .clone.alpha = 0.5f, \
+ .normal_weight = 0.0f, \
+ .fill_threshold = 0.2f, \
+ \
+ /* BRUSH PAINT TOOL SETTINGS */ \
+ /* Default rgb color of the brush when painting - white. */ \
+ .rgb = {1.0f, 1.0f, 1.0f}, \
+ \
+ .secondary_rgb = {0, 0, 0}, \
+ \
+ /* BRUSH STROKE SETTINGS */ \
+ /* How far each brush dot should be spaced as a percentage of brush diameter. */ \
+ .spacing = 10, \
+ \
+ .smooth_stroke_radius = 75, \
+ .smooth_stroke_factor = 0.9f, \
+ \
+ /* Time delay between dots of paint or sculpting when doing airbrush mode. */ \
+ .rate = 0.1f, \
+ \
+ .jitter = 0.0f, \
+ \
+ .texture_sample_bias = 0, /* value to added to texture samples */ \
+ .texture_overlay_alpha = 33, \
+ .mask_overlay_alpha = 33, \
+ .cursor_overlay_alpha = 33, \
+ .overlay_flags = 0, \
+ \
+ /* brush appearance */ \
+ \
+ /* add mode color is light red */ \
+ .add_col = {1.0, 0.39, 0.39}, \
+ \
+ /* subtract mode color is light blue */ \
+ .sub_col = {0.39, 0.39, 1.0}, \
+ \
+ .stencil_pos = {256, 256}, \
+ .stencil_dimension = {256, 256}, \
+ \
+ /* sculpting defaults to the draw tool for new brushes */ \
+ .sculpt_tool = SCULPT_TOOL_DRAW, \
+ \
+ /* A kernel radius of 1 has almost no effect (T63233). */ \
+ .blur_kernel_radius = 2, \
+ \
+ .mtex = _DNA_DEFAULT_MTex, \
+ .mask_mtex = _DNA_DEFAULT_MTex, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_BRUSH_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 93ce3d9769b..aec28c0fe75 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -113,7 +113,8 @@ typedef struct BrushGpencilSettings {
float gradient_f;
/** factor xy of shape for dots gradients */
float gradient_s[2];
- char _pad_2[4];
+ /** Simplify adaptive factor */
+ float simplify_f;
struct CurveMapping *curve_sensitivity;
struct CurveMapping *curve_strength;
@@ -184,6 +185,8 @@ typedef enum eGP_BrushIcons {
GP_BRUSH_ICON_ERASE_SOFT = 8,
GP_BRUSH_ICON_ERASE_HARD = 9,
GP_BRUSH_ICON_ERASE_STROKE = 10,
+ GP_BRUSH_ICON_AIRBRUSH = 11,
+ GP_BRUSH_ICON_CHISEL = 12,
} eGP_BrushIcons;
typedef enum eBrushCurvePreset {
@@ -198,6 +201,18 @@ typedef enum eBrushCurvePreset {
BRUSH_CURVE_CONSTANT = 8,
} eBrushCurvePreset;
+typedef enum eBrushElasticDeformType {
+ BRUSH_ELASTIC_DEFORM_GRAB = 0,
+ BRUSH_ELASTIC_DEFORM_GRAB_BISCALE = 1,
+ BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE = 2,
+ BRUSH_ELASTIC_DEFORM_SCALE = 3,
+ BRUSH_ELASTIC_DEFORM_TWIST = 4,
+} eBrushElasticDeformType;
+
+typedef enum eAutomasking_flag {
+ BRUSH_AUTOMASKING_TOPOLOGY = (1 << 0),
+} eAutomasking_flag;
+
typedef struct Brush {
ID id;
@@ -295,6 +310,8 @@ typedef struct Brush {
float crease_pinch_factor;
+ float normal_radius_factor;
+
float plane_trim;
/** Affectable height of brush (layer height for layer tool, i.e.). */
float height;
@@ -302,7 +319,13 @@ typedef struct Brush {
float texture_sample_bias;
int curve_preset;
- char _pad1[4];
+ int automasking_flags;
+
+ int elastic_deform_type;
+ float elastic_deform_volume_preservation;
+
+ /* pose */
+ float pose_offset;
/* overlay */
int texture_overlay_alpha;
@@ -384,8 +407,8 @@ typedef enum eBrushFlags {
BRUSH_SIZE_PRESSURE = (1 << 3),
BRUSH_JITTER_PRESSURE = (1 << 4),
BRUSH_SPACING_PRESSURE = (1 << 5),
- BRUSH_FLAG_UNUSED_6 = (1 << 6), /* cleared */
- BRUSH_FLAG_UNUSED_7 = (1 << 7), /* cleared */
+ BRUSH_ORIGINAL_PLANE = (1 << 6),
+ BRUSH_GRAB_ACTIVE_VERTEX = (1 << 7),
BRUSH_ANCHORED = (1 << 8),
BRUSH_DIR_IN = (1 << 9),
BRUSH_SPACE = (1 << 10),
@@ -395,7 +418,7 @@ typedef enum eBrushFlags {
BRUSH_LOCK_ALPHA = (1 << 14),
BRUSH_ORIGINAL_NORMAL = (1 << 15),
BRUSH_OFFSET_PRESSURE = (1 << 16),
- BRUSH_FLAG_UNUSED_17 = (1 << 17), /* cleared */
+ BRUSH_SCENE_SPACING = (1 << 17),
BRUSH_SPACE_ATTEN = (1 << 18),
BRUSH_ADAPTIVE_SPACE = (1 << 19),
BRUSH_LOCK_SIZE = (1 << 20),
@@ -452,6 +475,9 @@ typedef enum eBrushSculptTool {
SCULPT_TOOL_BLOB = 17,
SCULPT_TOOL_CLAY_STRIPS = 18,
SCULPT_TOOL_MASK = 19,
+ SCULPT_TOOL_DRAW_SHARP = 20,
+ SCULPT_TOOL_ELASTIC_DEFORM = 21,
+ SCULPT_TOOL_POSE = 22,
} eBrushSculptTool;
/* Brush.uv_sculpt_tool */
@@ -465,6 +491,7 @@ typedef enum eBrushUVSculptTool {
#define SCULPT_TOOL_HAS_ACCUMULATE(t) \
ELEM(t, \
SCULPT_TOOL_DRAW, \
+ SCULPT_TOOL_DRAW_SHARP, \
SCULPT_TOOL_CREASE, \
SCULPT_TOOL_BLOB, \
SCULPT_TOOL_LAYER, \
@@ -472,6 +499,7 @@ typedef enum eBrushUVSculptTool {
SCULPT_TOOL_CLAY, \
SCULPT_TOOL_CLAY_STRIPS, \
SCULPT_TOOL_ROTATE, \
+ SCULPT_TOOL_SCRAPE, \
SCULPT_TOOL_FLATTEN)
#define SCULPT_TOOL_HAS_NORMAL_WEIGHT(t) ELEM(t, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK)
@@ -484,8 +512,11 @@ typedef enum eBrushUVSculptTool {
SCULPT_TOOL_ROTATE, \
SCULPT_TOOL_THUMB, \
SCULPT_TOOL_LAYER, \
+ SCULPT_TOOL_DRAW_SHARP, \
+ SCULPT_TOOL_ELASTIC_DEFORM, \
+ SCULPT_TOOL_POSE, \
\
- /* These brushes could handle dynamic topology, \
+ /* These brushes could handle dynamic topology, \ \
* but user feedback indicates it's better not to */ \
SCULPT_TOOL_SMOOTH, \
SCULPT_TOOL_MASK) == 0)
@@ -495,6 +526,7 @@ typedef enum eBrushUVSculptTool {
SCULPT_TOOL_GRAB, \
SCULPT_TOOL_ROTATE, \
SCULPT_TOOL_THUMB, \
+ SCULPT_TOOL_DRAW_SHARP, \
SCULPT_TOOL_MASK) == 0)
/* ImagePaintSettings.tool */
diff --git a/source/blender/makesdna/DNA_cachefile_defaults.h b/source/blender/makesdna/DNA_cachefile_defaults.h
new file mode 100644
index 00000000000..4c4ff53ed90
--- /dev/null
+++ b/source/blender/makesdna/DNA_cachefile_defaults.h
@@ -0,0 +1,49 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_CACHEFILE_DEFAULTS_H__
+#define __DNA_CACHEFILE_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name CacheFile Struct
+ * \{ */
+
+#define _DNA_DEFAULT_CacheFile \
+ { \
+ .filepath[0] = '\0', \
+ .override_frame = false, \
+ .frame = 0.0f, \
+ .is_sequence = false, \
+ .scale = 1.0f, \
+ .object_paths ={NULL, NULL}, \
+ \
+ .handle = NULL, \
+ .handle_filepath[0] = '\0', \
+ .handle_readers = NULL, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_CACHEFILE_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_camera_defaults.h b/source/blender/makesdna/DNA_camera_defaults.h
new file mode 100644
index 00000000000..7a28f673ee4
--- /dev/null
+++ b/source/blender/makesdna/DNA_camera_defaults.h
@@ -0,0 +1,67 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_CAMERA_DEFAULTS_H__
+#define __DNA_CAMERA_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Camera Struct
+ * \{ */
+
+#define _DNA_DEFAULT_CameraDOFSettings \
+ { \
+ .aperture_fstop = 2.8f, \
+ .aperture_ratio = 1.0f, \
+ .focus_distance = 10.0f, \
+ }
+
+#define _DNA_DEFAULT_CameraStereoSettings \
+ { \
+ .interocular_distance = 0.065f, \
+ .convergence_distance = 30.f * 0.065f, \
+ .pole_merge_angle_from = DEG2RADF(60.0f), \
+ .pole_merge_angle_to = DEG2RADF(75.0f), \
+ }
+
+#define _DNA_DEFAULT_Camera \
+ { \
+ .lens = 50.0f, \
+ .sensor_x = DEFAULT_SENSOR_WIDTH, \
+ .sensor_y = DEFAULT_SENSOR_HEIGHT, \
+ .clip_start = 0.1f, \
+ .clip_end = 1000.0f, \
+ .drawsize = 1.0f, \
+ .ortho_scale = 6.0, \
+ .flag = CAM_SHOWPASSEPARTOUT, \
+ .passepartalpha = 0.5f, \
+ \
+ .dof = _DNA_DEFAULT_CameraDOFSettings, \
+ \
+ .stereo = _DNA_DEFAULT_CameraStereoSettings, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_CAMERA_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index eda52fdf14a..83fc4d2a3f7 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -271,7 +271,9 @@ typedef struct bTrackToConstraint {
typedef struct bRotateLikeConstraint {
struct Object *tar;
int flag;
- int reserved1;
+ char euler_order;
+ char mix_mode;
+ char _pad[2];
/** MAX_ID_NAME-2. */
char subtarget[64];
} bRotateLikeConstraint;
@@ -305,6 +307,8 @@ typedef struct bSameVolumeConstraint {
/* Copy Transform Constraint */
typedef struct bTransLikeConstraint {
struct Object *tar;
+ char mix_mode;
+ char _pad[7];
/** MAX_ID_NAME-2. */
char subtarget[64];
} bTransLikeConstraint;
@@ -441,6 +445,18 @@ typedef struct bTransformConstraint {
/** Extrapolate motion? if 0, confine to ranges. */
char expo;
+ /** Input rotation type - uses the same values as driver targets. */
+ char from_rotation_mode;
+ /** Output euler order override. */
+ char to_euler_order;
+
+ /** Mixing modes for location, rotation, and scale. */
+ char mix_mode_loc;
+ char mix_mode_rot;
+ char mix_mode_scale;
+
+ char _pad[3];
+
/** From_min/max defines range of target transform. */
float from_min[3];
/** To map on to to_min/max range. */
@@ -715,6 +731,20 @@ typedef enum eConstraintChannel_Flags {
CONSTRAINT_CHANNEL_PROTECTED = (1 << 1),
} eConstraintChannel_Flags;
+/* Common enum for constraints that support override. */
+typedef enum eConstraint_EulerOrder {
+ /** Automatic euler mode. */
+ CONSTRAINT_EULER_AUTO = 0,
+
+ /** Explicit euler rotation modes - must sync with BLI_math_rotation.h defines. */
+ CONSTRAINT_EULER_XYZ = 1,
+ CONSTRAINT_EULER_XZY,
+ CONSTRAINT_EULER_YXZ,
+ CONSTRAINT_EULER_YZX,
+ CONSTRAINT_EULER_ZXY,
+ CONSTRAINT_EULER_ZYX,
+} eConstraint_EulerOrder;
+
/* -------------------------------------- */
/* bRotateLikeConstraint.flag */
@@ -725,9 +755,25 @@ typedef enum eCopyRotation_Flags {
ROTLIKE_X_INVERT = (1 << 4),
ROTLIKE_Y_INVERT = (1 << 5),
ROTLIKE_Z_INVERT = (1 << 6),
+#ifdef DNA_DEPRECATED
ROTLIKE_OFFSET = (1 << 7),
+#endif
} eCopyRotation_Flags;
+/* bRotateLikeConstraint.mix_mode */
+typedef enum eCopyRotation_MixMode {
+ /* Replace rotation channel values. */
+ ROTLIKE_MIX_REPLACE = 0,
+ /* Legacy Offset mode - don't use. */
+ ROTLIKE_MIX_OFFSET,
+ /* Add Euler components together. */
+ ROTLIKE_MIX_ADD,
+ /* Multiply the copied rotation on the left. */
+ ROTLIKE_MIX_BEFORE,
+ /* Multiply the copied rotation on the right. */
+ ROTLIKE_MIX_AFTER,
+} eCopyRotation_MixMode;
+
/* bLocateLikeConstraint.flag */
typedef enum eCopyLocation_Flags {
LOCLIKE_X = (1 << 0),
@@ -748,8 +794,19 @@ typedef enum eCopyScale_Flags {
SIZELIKE_Z = (1 << 2),
SIZELIKE_OFFSET = (1 << 3),
SIZELIKE_MULTIPLY = (1 << 4),
+ SIZELIKE_UNIFORM = (1 << 5),
} eCopyScale_Flags;
+/* bTransLikeConstraint.mix_mode */
+typedef enum eCopyTransforms_MixMode {
+ /* Replace rotation channel values. */
+ TRANSLIKE_MIX_REPLACE = 0,
+ /* Multiply the copied transformation on the left, with anti-shear scale handling. */
+ TRANSLIKE_MIX_BEFORE,
+ /* Multiply the copied transformation on the right, with anti-shear scale handling. */
+ TRANSLIKE_MIX_AFTER,
+} eCopyTransforms_MixMode;
+
/* bTransformConstraint.to/from */
typedef enum eTransform_ToFrom {
TRANS_LOCATION = 0,
@@ -757,6 +814,34 @@ typedef enum eTransform_ToFrom {
TRANS_SCALE = 2,
} eTransform_ToFrom;
+/* bTransformConstraint.mix_mode_loc */
+typedef enum eTransform_MixModeLoc {
+ /* Add component values together (default). */
+ TRANS_MIXLOC_ADD = 0,
+ /* Replace component values. */
+ TRANS_MIXLOC_REPLACE,
+} eTransform_MixModeLoc;
+
+/* bTransformConstraint.mix_mode_rot */
+typedef enum eTransform_MixModeRot {
+ /* Add component values together (default). */
+ TRANS_MIXROT_ADD = 0,
+ /* Replace component values. */
+ TRANS_MIXROT_REPLACE,
+ /* Multiply the generated rotation on the left. */
+ TRANS_MIXROT_BEFORE,
+ /* Multiply the generated rotation on the right. */
+ TRANS_MIXROT_AFTER,
+} eTransform_MixModeRot;
+
+/* bTransformConstraint.mix_mode_scale */
+typedef enum eTransform_MixModeScale {
+ /* Replace component values (default). */
+ TRANS_MIXSCALE_REPLACE = 0,
+ /* Multiply component values together. */
+ TRANS_MIXSCALE_MULTIPLY,
+} eTransform_MixModeScale;
+
/* bSameVolumeConstraint.free_axis */
typedef enum eSameVolume_Axis {
SAMEVOL_X = 0,
diff --git a/source/blender/makesdna/DNA_curve_defaults.h b/source/blender/makesdna/DNA_curve_defaults.h
new file mode 100644
index 00000000000..0fdfd5713e9
--- /dev/null
+++ b/source/blender/makesdna/DNA_curve_defaults.h
@@ -0,0 +1,59 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_CURVE_DEFAULTS_H__
+#define __DNA_CURVE_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Curve Struct
+ * \{ */
+
+#define _DNA_DEFAULT_Curve \
+ { \
+ .size = {1, 1, 1}, \
+ .flag = CU_DEFORM_BOUNDS_OFF | CU_PATH_RADIUS, \
+ .pathlen = 100, \
+ .resolu = 12, \
+ .resolv = 12, \
+ .width = 1.0, \
+ .wordspace = 1.0, \
+ .spacing = 1.0f, \
+ .linedist = 1.0, \
+ .fsize = 1.0, \
+ .ulheight = 0.05, \
+ .texflag = CU_AUTOSPACE, \
+ .smallcaps_scale = 0.75f, \
+ /* This one seems to be the best one in most cases, at least for curve deform. */ \
+ .twist_mode = CU_TWIST_MINIMUM, \
+ .bevfac1 = 0.0f, \
+ .bevfac2 = 1.0f, \
+ .bevfac1_mapping = CU_BEVFAC_MAP_RESOLU, \
+ .bevfac2_mapping = CU_BEVFAC_MAP_RESOLU, \
+ .bevresol = 4, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_CURVE_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index bdb3db94c89..759029ad618 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -32,7 +32,6 @@
#define MAXTEXTBOX 256 /* used in readfile.c and editfont.c */
struct AnimData;
-struct BoundBox;
struct EditFont;
struct GHash;
struct Ipo;
@@ -212,8 +211,6 @@ typedef struct Curve {
/** Animation data (must be immediately after id for utilities to use it). */
struct AnimData *adt;
- struct BoundBox *bb;
-
/** Actual data, called splines in rna. */
ListBase nurb;
@@ -229,14 +226,13 @@ typedef struct Curve {
/* texture space, copied as one block in editobject.c */
float loc[3];
float size[3];
- float rot[3];
/** Creation-time type of curve datablock. */
short type;
/** Keep a short because of BKE_object_obdata_texspace_get(). */
short texflag;
- char _pad0[2];
+ char _pad0[6];
short twist_mode;
float twist_smooth, smallcaps_scale;
@@ -308,6 +304,7 @@ typedef struct Curve {
/* Curve.texflag */
enum {
CU_AUTOSPACE = 1,
+ CU_AUTOSPACE_EVALUATED = 2,
};
#if 0 /* Moved to overlay options in 2.8 */
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index 14a078d8386..9799489982d 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -197,6 +197,9 @@ typedef enum CustomDataType {
/** Data types that may be defined for all mesh elements types. */
#define CD_MASK_GENERIC_DATA (CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR)
+/** Multires loop data. */
+#define CD_MASK_MULTIRES_GRIDS (CD_MASK_MDISPS | CD_GRID_PAINT_MASK)
+
typedef struct CustomData_MeshMasks {
uint64_t vmask;
uint64_t emask;
diff --git a/source/blender/makesdna/DNA_defaults.h b/source/blender/makesdna/DNA_defaults.h
new file mode 100644
index 00000000000..5b9297ce46a
--- /dev/null
+++ b/source/blender/makesdna/DNA_defaults.h
@@ -0,0 +1,46 @@
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup DNA
+ *
+ * \see dna_defaults.c for details on how to use this system.
+ */
+
+#ifndef __DNA_DEFAULTS_H__
+#define __DNA_DEFAULTS_H__
+
+#include "dna_type_offsets.h"
+
+extern const void *DNA_default_table[SDNA_TYPE_MAX];
+
+char *_DNA_struct_default_alloc_impl(const char *data_src, size_t size, const char *alloc_str);
+
+/**
+ * Wrap with macro that casts correctly.
+ */
+#define DNA_struct_default_get(struct_name) \
+ (const struct_name *)DNA_default_table[SDNA_TYPE_FROM_STRUCT(struct_name)]
+
+#define DNA_struct_default_alloc(struct_name) \
+ (struct_name *)_DNA_struct_default_alloc_impl( \
+ DNA_default_table[SDNA_TYPE_FROM_STRUCT(struct_name)], sizeof(struct_name), __func__)
+
+#endif /* __DNA_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_genfile.h b/source/blender/makesdna/DNA_genfile.h
index dc4f5512b1a..db65da6fa75 100644
--- a/source/blender/makesdna/DNA_genfile.h
+++ b/source/blender/makesdna/DNA_genfile.h
@@ -103,6 +103,8 @@ void *DNA_struct_reconstruct(const struct SDNA *newsdna,
int DNA_elem_offset(struct SDNA *sdna, const char *stype, const char *vartype, const char *name);
+int DNA_elem_size_nr(const struct SDNA *sdna, short type, short name);
+
bool DNA_struct_find(const struct SDNA *sdna, const char *stype);
bool DNA_struct_elem_find(const struct SDNA *sdna,
const char *stype,
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index f094d630fc8..7d407dc85bc 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -200,6 +200,11 @@ typedef enum eModifyColorGpencil_Flag {
GP_MODIFY_COLOR_FILL = 2,
} eModifyColorGpencil_Flag;
+typedef enum eOpacityModesGpencil_Flag {
+ GP_OPACITY_MODE_MATERIAL = 0,
+ GP_OPACITY_MODE_STRENGTH = 1,
+} eOpacityModesGpencil_Flag;
+
typedef struct TintGpencilModifierData {
GpencilModifierData modifier;
/** Layer name. */
@@ -274,7 +279,9 @@ typedef struct OpacityGpencilModifierData {
float factor;
/** Modify stroke, fill or both. */
char modify_color;
- char _pad[3];
+ /** Mode of opacity, colors or strength */
+ char opacity_mode;
+ char _pad[2];
/** Custom index for passes. */
int layer_pass;
char _pad1[4];
diff --git a/source/blender/makesdna/DNA_image_defaults.h b/source/blender/makesdna/DNA_image_defaults.h
new file mode 100644
index 00000000000..e115f9e2b16
--- /dev/null
+++ b/source/blender/makesdna/DNA_image_defaults.h
@@ -0,0 +1,46 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_IMAGE_DEFAULTS_H__
+#define __DNA_IMAGE_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Struct
+ * \{ */
+
+#define _DNA_DEFAULT_Image \
+ { \
+ .aspx = 1.0, \
+ .aspy = 1.0, \
+ .gen_x = 1024, \
+ .gen_y = 1024, \
+ .gen_type = IMA_GENTYPE_GRID, \
+ \
+ .gpuframenr = INT_MAX, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_IMAGE_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_lattice_defaults.h b/source/blender/makesdna/DNA_lattice_defaults.h
new file mode 100644
index 00000000000..052aaba51d7
--- /dev/null
+++ b/source/blender/makesdna/DNA_lattice_defaults.h
@@ -0,0 +1,44 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_LATTICE_DEFAULTS_H__
+#define __DNA_LATTICE_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Lattice Struct
+ * \{ */
+
+#define _DNA_DEFAULT_Lattice \
+ { \
+ .flag = LT_GRID, \
+ .typeu = KEY_BSPLINE, \
+ .typev = KEY_BSPLINE, \
+ .typew = KEY_BSPLINE, \
+ .actbp = LT_ACTBP_NONE, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_LATTICE_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h
index 5f64e3220b7..3af1da46f80 100644
--- a/source/blender/makesdna/DNA_layer_types.h
+++ b/source/blender/makesdna/DNA_layer_types.h
@@ -45,6 +45,8 @@ typedef struct Base {
struct Object *object;
unsigned int lay DNA_DEPRECATED;
int flag_legacy;
+ unsigned short local_collections_bits;
+ short _pad2[3];
/* Pointer to an original base. Is initialized for evaluated view layer.
* NOTE: Only allowed to be accessed from within active dependency graph. */
@@ -66,8 +68,12 @@ typedef struct LayerCollection {
short flag;
short runtime_flag;
char _pad[4];
+
/** Synced with collection->children. */
ListBase layer_collections;
+
+ unsigned short local_collections_bits;
+ short _pad2[3];
} LayerCollection;
typedef struct ViewLayer {
diff --git a/source/blender/makesdna/DNA_light_defaults.h b/source/blender/makesdna/DNA_light_defaults.h
new file mode 100644
index 00000000000..dceaaf7c278
--- /dev/null
+++ b/source/blender/makesdna/DNA_light_defaults.h
@@ -0,0 +1,76 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_LIGHT_DEFAULTS_H__
+#define __DNA_LIGHT_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Light Struct
+ * \{ */
+
+#define _DNA_DEFAULT_Light \
+ { \
+ .r = 1.0f, \
+ .g = 1.0f, \
+ .b = 1.0f, \
+ .k = 1.0f, \
+ .energy = 10.0f, \
+ .dist = 25.0f, \
+ .spotsize = DEG2RADF(45.0f), \
+ .spotblend = 0.15f, \
+ .att2 = 1.0f, \
+ .mode = LA_SHADOW, \
+ .bufsize = 512, \
+ .clipsta = 0.05f, \
+ .clipend = 40.0f, \
+ .bleedexp = 2.5f, \
+ .samp = 3, \
+ .bias = 1.0f, \
+ .soft = 3.0f, \
+ .area_size = 0.25f, \
+ .area_sizey = 0.25f, \
+ .area_sizez = 0.25f, \
+ .buffers = 1, \
+ .preview = NULL, \
+ .falloff_type = LA_FALLOFF_INVSQUARE, \
+ .coeff_const = 1.0f, \
+ .coeff_lin = 0.0f, \
+ .coeff_quad = 0.0f, \
+ .cascade_max_dist = 200.0f, \
+ .cascade_count = 4, \
+ .cascade_exponent = 0.8f, \
+ .cascade_fade = 0.1f, \
+ .contact_dist = 0.2f, \
+ .contact_bias = 0.03f, \
+ .contact_spread = 0.2f, \
+ .contact_thickness = 0.2f, \
+ .spec_fac = 1.0f, \
+ .att_dist = 40.0f, \
+ .sun_angle = DEG2RADF(0.526f), \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_LIGHT_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_light_types.h b/source/blender/makesdna/DNA_light_types.h
index 82cab5d1594..ec83d53da5e 100644
--- a/source/blender/makesdna/DNA_light_types.h
+++ b/source/blender/makesdna/DNA_light_types.h
@@ -58,7 +58,10 @@ typedef struct Light {
char _pad2[2];
float clipsta, clipend;
- float bias, soft, bleedbias, bleedexp;
+ float bias;
+ float soft; /* DEPRECATED kept for compatibility. */
+ float bleedbias; /* DEPRECATED kept for compatibility. */
+ float bleedexp; /* DEPRECATED kept for compatibility. */
short bufsize, samp, buffers, filtertype;
char bufflag, buftype;
@@ -82,7 +85,10 @@ typedef struct Light {
float cascade_fade;
int cascade_count;
- float contact_dist, contact_bias, contact_spread, contact_thickness;
+ float contact_dist;
+ float contact_bias;
+ float contact_spread; /* DEPRECATED kept for compatibility. */
+ float contact_thickness;
float spec_fac, att_dist;
diff --git a/source/blender/makesdna/DNA_lightprobe_defaults.h b/source/blender/makesdna/DNA_lightprobe_defaults.h
new file mode 100644
index 00000000000..7c7732d17e4
--- /dev/null
+++ b/source/blender/makesdna/DNA_lightprobe_defaults.h
@@ -0,0 +1,51 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_LIGHTPROBE_DEFAULTS_H__
+#define __DNA_LIGHTPROBE_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name LightProbe Struct
+ * \{ */
+
+#define _DNA_DEFAULT_LightProbe \
+ { \
+ .grid_resolution_x = 4, \
+ .grid_resolution_y = 4, \
+ .grid_resolution_z = 4, \
+ .distinf = 2.5f, \
+ .distpar = 2.5f, \
+ .falloff = 0.2f, \
+ .clipsta = 0.8f, \
+ .clipend = 40.0f, \
+ .vis_bias = 1.0f, \
+ .vis_blur = 0.2f, \
+ .intensity = 1.0f, \
+ .flag = LIGHTPROBE_FLAG_SHOW_INFLUENCE, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_LIGHTPROBE_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_linestyle_defaults.h b/source/blender/makesdna/DNA_linestyle_defaults.h
new file mode 100644
index 00000000000..2f9203050d1
--- /dev/null
+++ b/source/blender/makesdna/DNA_linestyle_defaults.h
@@ -0,0 +1,61 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_LINESTYLE_DEFAULTS_H__
+#define __DNA_LINESTYLE_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name FreestyleLineStyle Struct
+ * \{ */
+
+#define _DNA_DEFAULT_FreestyleLineStyle \
+ { \
+ .panel = LS_PANEL_STROKES, \
+ .r = 0, \
+ .g = 0, \
+ .b = 0, \
+ .alpha = 1.0f, \
+ .thickness = 3.0f, \
+ .thickness_position = LS_THICKNESS_CENTER, \
+ .thickness_ratio = 0.5f, \
+ .flag = LS_SAME_OBJECT | LS_NO_SORTING | LS_TEXTURE, \
+ .chaining = LS_CHAINING_PLAIN, \
+ .rounds = 3, \
+ .min_angle = DEG2RADF(0.0f), \
+ .max_angle = DEG2RADF(0.0f), \
+ .min_length = 0.0f, \
+ .max_length = 10000.0f, \
+ .split_length = 100, \
+ .chain_count = 10, \
+ .sort_key = LS_SORT_KEY_DISTANCE_FROM_CAMERA, \
+ .integration_type = LS_INTEGRATION_MEAN, \
+ .texstep = 1.0f, \
+ .pr_texture = TEX_PR_TEXTURE, \
+ .caps = LS_CAPS_BUTT, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_LINESTYLE_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_material_defaults.h b/source/blender/makesdna/DNA_material_defaults.h
new file mode 100644
index 00000000000..cdcb1dd45f7
--- /dev/null
+++ b/source/blender/makesdna/DNA_material_defaults.h
@@ -0,0 +1,55 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_MATERIAL_DEFAULTS_H__
+#define __DNA_MATERIAL_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Material Struct
+ * \{ */
+
+#define _DNA_DEFAULT_Material \
+ { \
+ .r = 0.8, \
+ .g = 0.8, \
+ .b = 0.8, \
+ .specr = 1.0, \
+ .specg = 1.0, \
+ .specb = 1.0, \
+ .a = 1.0f, \
+ .spec = 0.5, \
+ \
+ .roughness = 0.4f, \
+ \
+ .pr_type = MA_SPHERE, \
+ \
+ .alpha_threshold = 0.5f, \
+ \
+ .blend_shadow = MA_BS_SOLID, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_MATERIAL_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_mesh_defaults.h b/source/blender/makesdna/DNA_mesh_defaults.h
new file mode 100644
index 00000000000..f605827d120
--- /dev/null
+++ b/source/blender/makesdna/DNA_mesh_defaults.h
@@ -0,0 +1,45 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_MESH_DEFAULTS_H__
+#define __DNA_MESH_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Struct
+ * \{ */
+
+#define _DNA_DEFAULT_Mesh \
+ { \
+ .size = {1.0f, 1.0f, 1.0f}, \
+ .smoothresh = DEG2RADF(30), \
+ .texflag = ME_AUTOSPACE, \
+ .remesh_voxel_size = 0.1f, \
+ .remesh_voxel_adaptivity = 0.0f, \
+ .flag = ME_REMESH_FIX_POLES | ME_REMESH_REPROJECT_VOLUME, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_MESH_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index cb6991ce67a..fb9e522dfa9 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -116,8 +116,6 @@ typedef struct Mesh {
/** Animation data (must be immediately after id for utilities to use it). */
struct AnimData *adt;
- struct BoundBox *bb;
-
/** Old animation system, deprecated for 2.5. */
struct Ipo *ipo DNA_DEPRECATED;
struct Key *key;
@@ -177,7 +175,6 @@ typedef struct Mesh {
/* texture space, copied as one block in editobject.c */
float loc[3];
float size[3];
- float rot[3];
short texflag, flag;
float smoothresh;
@@ -193,7 +190,9 @@ typedef struct Mesh {
short totcol;
float remesh_voxel_size;
- char _pad1[4];
+ float remesh_voxel_adaptivity;
+ char remesh_mode;
+ char _pad1[3];
/** Deprecated multiresolution modeling data, only keep for loading old files. */
struct Multires *mr DNA_DEPRECATED;
@@ -217,6 +216,7 @@ typedef struct TFace {
/* texflag */
enum {
ME_AUTOSPACE = 1,
+ ME_AUTOSPACE_EVALUATED = 2,
};
/* me->editflag */
@@ -252,6 +252,8 @@ enum {
ME_SCULPT_DYNAMIC_TOPOLOGY = 1 << 10,
ME_REMESH_SMOOTH_NORMALS = 1 << 11,
ME_REMESH_REPROJECT_PAINT_MASK = 1 << 12,
+ ME_REMESH_FIX_POLES = 1 << 13,
+ ME_REMESH_REPROJECT_VOLUME = 1 << 14,
};
/* me->cd_flag */
@@ -261,6 +263,12 @@ enum {
ME_CDFLAG_EDGE_CREASE = 1 << 2,
};
+/* me->remesh_mode */
+enum {
+ REMESH_VOXEL = 0,
+ REMESH_QUAD = 1,
+};
+
/* Subsurf Type */
enum {
ME_CC_SUBSURF = 0,
diff --git a/source/blender/makesdna/DNA_meta_defaults.h b/source/blender/makesdna/DNA_meta_defaults.h
new file mode 100644
index 00000000000..723f178ed58
--- /dev/null
+++ b/source/blender/makesdna/DNA_meta_defaults.h
@@ -0,0 +1,44 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_META_DEFAULTS_H__
+#define __DNA_META_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name MetaBall Struct
+ * \{ */
+
+#define _DNA_DEFAULT_MetaBall \
+ { \
+ .size = {1, 1, 1}, \
+ .texflag = MB_AUTOSPACE, \
+ .wiresize = 0.4f, \
+ .rendersize = 0.2f, \
+ .thresh = 0.6f, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_META_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 5243dc1aecd..cceeb9c71d5 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -1594,6 +1594,19 @@ enum {
MOD_LAPLACIANSMOOTH_NORMALIZED = (1 << 5),
};
+typedef struct CorrectiveSmoothDeltaCache {
+ /* delta's between the original positions and the smoothed positions */
+ float (*deltas)[3];
+ unsigned int totverts;
+
+ /* Value of settings when creating the cache.
+ * These are used to check if the cache should be recomputed. */
+ float lambda;
+ short repeat, flag;
+ char smooth_type, rest_source;
+ char _pad[2];
+} CorrectiveSmoothDeltaCache;
+
typedef struct CorrectiveSmoothModifierData {
ModifierData modifier;
@@ -1612,11 +1625,8 @@ typedef struct CorrectiveSmoothModifierData {
/** MAX_VGROUP_NAME. */
char defgrp_name[64];
- /* runtime-only cache (delta's between),
- * delta's between the original positions and the smoothed positions */
- float (*delta_cache)[3];
- unsigned int delta_cache_num;
- char _pad2[4];
+ /* runtime-only cache */
+ CorrectiveSmoothDeltaCache delta_cache;
} CorrectiveSmoothModifierData;
enum {
diff --git a/source/blender/makesdna/DNA_movieclip_types.h b/source/blender/makesdna/DNA_movieclip_types.h
index efda24d6e0e..8de79d9ea2b 100644
--- a/source/blender/makesdna/DNA_movieclip_types.h
+++ b/source/blender/makesdna/DNA_movieclip_types.h
@@ -97,7 +97,7 @@ typedef struct MovieClip {
struct MovieTracking tracking;
/**
* Context of tracking job used to synchronize data
- * like framenumber in SpaceClip clip user.
+ * like frame-number in SpaceClip clip user.
*/
void *tracking_context;
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index af66add01f3..7eecf23195a 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -276,7 +276,10 @@ typedef struct bNode {
short preview_xsize, preview_ysize;
/** Used at runtime when going through the tree. Initialize before use. */
short tmp_flag;
- char _pad2[2];
+ /** Used at runtime to tag derivatives branches. EEVEE only. */
+ char branch_tag;
+ /** Used at runtime when iterating over node branches. */
+ char iter_flag;
/** Runtime during drawing. */
struct uiBlock *block;
@@ -432,7 +435,7 @@ typedef struct bNodeTree {
int flag;
/** Update flags. */
int update;
- /** Flag to prevent reentrant update calls. */
+ /** Flag to prevent re-entrant update calls. */
short is_updating;
/** Generic temporary flag for recursion check (DFS/BFS). */
short done;
@@ -869,20 +872,22 @@ typedef struct NodeTexGradient {
typedef struct NodeTexNoise {
NodeTexBase base;
+ int dimensions;
+ char _pad[4];
} NodeTexNoise;
typedef struct NodeTexVoronoi {
NodeTexBase base;
- int coloring;
- int distance;
+ int dimensions;
int feature;
- char _pad[4];
+ int distance;
+ int coloring DNA_DEPRECATED;
} NodeTexVoronoi;
typedef struct NodeTexMusgrave {
NodeTexBase base;
int musgrave_type;
- char _pad[4];
+ int dimensions;
} NodeTexMusgrave;
typedef struct NodeTexWave {
@@ -994,6 +999,10 @@ typedef struct NodeShaderUVMap {
char uv_map[64];
} NodeShaderUVMap;
+typedef struct NodeShaderVertexColor {
+ char layer_name[64];
+} NodeShaderVertexColor;
+
typedef struct NodeShaderTexIES {
int mode;
@@ -1095,20 +1104,22 @@ typedef struct NodeDenoise {
#define SHD_NOISE_SOFT 0
#define SHD_NOISE_HARD 1
-/* voronoi texture */
-#define SHD_VORONOI_DISTANCE 0
-#define SHD_VORONOI_MANHATTAN 1
-#define SHD_VORONOI_CHEBYCHEV 2
-#define SHD_VORONOI_MINKOWSKI 3
+/* Voronoi Texture */
-#define SHD_VORONOI_INTENSITY 0
-#define SHD_VORONOI_CELLS 1
+enum {
+ SHD_VORONOI_EUCLIDEAN = 0,
+ SHD_VORONOI_MANHATTAN = 1,
+ SHD_VORONOI_CHEBYCHEV = 2,
+ SHD_VORONOI_MINKOWSKI = 3,
+};
-#define SHD_VORONOI_F1 0
-#define SHD_VORONOI_F2 1
-#define SHD_VORONOI_F3 2
-#define SHD_VORONOI_F4 3
-#define SHD_VORONOI_F2F1 4
+enum {
+ SHD_VORONOI_F1 = 0,
+ SHD_VORONOI_F2 = 1,
+ SHD_VORONOI_SMOOTH_F1 = 2,
+ SHD_VORONOI_DISTANCE_TO_EDGE = 3,
+ SHD_VORONOI_N_SPHERE_RADIUS = 4,
+};
/* musgrave texture */
#define SHD_MUSGRAVE_MULTIFRACTAL 0
@@ -1167,6 +1178,14 @@ typedef struct NodeDenoise {
#define SHD_AO_INSIDE 1
#define SHD_AO_LOCAL 2
+/* Mapping node vector types */
+enum {
+ NODE_MAPPING_TYPE_POINT = 0,
+ NODE_MAPPING_TYPE_TEXTURE = 1,
+ NODE_MAPPING_TYPE_VECTOR = 2,
+ NODE_MAPPING_TYPE_NORMAL = 3,
+};
+
/* math node clamp */
#define SHD_MATH_CLAMP 1
diff --git a/source/blender/makesdna/DNA_object_defaults.h b/source/blender/makesdna/DNA_object_defaults.h
new file mode 100644
index 00000000000..1105a8fd4e1
--- /dev/null
+++ b/source/blender/makesdna/DNA_object_defaults.h
@@ -0,0 +1,77 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_OBJECT_DEFAULTS_H__
+#define __DNA_OBJECT_DEFAULTS_H__
+
+#include "DNA_vec_defaults.h"
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Struct
+ * \{ */
+
+#define _DNA_DEFAULT_Object \
+ { \
+ /* Type is not very meaningful as a default, normally changed. */ \
+ .type = OB_EMPTY, \
+ .color = {1, 1, 1, 1}, \
+ \
+ .constinv = _DNA_DEFAULT_UNIT_M4, \
+ .parentinv = _DNA_DEFAULT_UNIT_M4, \
+ .obmat = _DNA_DEFAULT_UNIT_M4, \
+ \
+ .scale = {1, 1, 1}, \
+ .dscale = {1, 1, 1}, \
+ /* Objects should default to having Euler XYZ rotations, \
+ * but rotations default to quaternions. */ \
+ .rotmode = ROT_MODE_EUL, \
+ /** See #unit_axis_angle. */ \
+ .rotAxis = {0, 1, 0}, \
+ .rotAngle = 0, \
+ .drotAxis = {0, 1, 0}, \
+ .drotAngle = 0, \
+ .quat = _DNA_DEFAULT_UNIT_QT, \
+ .dquat = _DNA_DEFAULT_UNIT_QT, \
+ .protectflag = OB_LOCK_ROT4D, \
+ \
+ .dt = OB_TEXTURE, \
+ \
+ .empty_drawtype = OB_PLAINAXES, \
+ .empty_drawsize = 1.0, \
+ .empty_image_depth = OB_EMPTY_IMAGE_DEPTH_DEFAULT, \
+ .ima_ofs = {-0.5, -0.5}, \
+ \
+ .instance_faces_scale = 1, \
+ .col_group = 0x01, \
+ .col_mask = 0xffff, \
+ .preview = NULL, \
+ .duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER, \
+ .fluidsimSettings = NULL, \
+ .pc_ids = {NULL, NULL}, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_OBJECT_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index e006014b71f..82a90dfe7a2 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -162,12 +162,14 @@ typedef struct Object_Runtime {
struct Mesh *mesh_eval;
/**
* Mesh structure created during object evaluation.
- * It has deforemation only modifiers applied on it.
+ * It has deformation only modifiers applied on it.
*/
struct Mesh *mesh_deform_eval;
- /* This is a mesh representation of corresponding object.
- * It created when Python calls `object.to_mesh()`. */
+ /**
+ * This is a mesh representation of corresponding object.
+ * It created when Python calls `object.to_mesh()`.
+ */
struct Mesh *object_as_temp_mesh;
/** Runtime evaluated curve-specific data, not stored in the file. */
@@ -181,7 +183,8 @@ typedef struct Object_Runtime {
/** Runtime grease pencil evaluated data created by modifiers */
struct bGPDframe *gpencil_evaluated_frames;
- void *_pad2; /* Padding is here for win32s unconventional struct alignment rules. */
+ unsigned short local_collections_bits;
+ short _pad2[3];
} Object_Runtime;
typedef struct Object {
@@ -501,7 +504,7 @@ enum {
OB_DUPLIROT = 1 << 5,
OB_TRANSFLAG_UNUSED_6 = 1 << 6, /* cleared */
/* runtime, calculate derivedmesh for dupli before it's used */
- OB_DUPLICALCDERIVED = 1 << 7,
+ OB_TRANSFLAG_UNUSED_7 = 1 << 7, /* dirty */
OB_DUPLICOLLECTION = 1 << 8,
OB_DUPLIFACES = 1 << 9,
OB_DUPLIFACES_SCALE = 1 << 10,
@@ -605,7 +608,11 @@ enum {
/* NOTE: this was used as a proper setting in past, so nullify before using */
#define BA_TEMP_TAG (1 << 5)
-/* #define BA_FROMSET (1 << 7) */ /*UNUSED*/
+/**
+ * Even if this is is tagged for transform, this flag means it's being locked in place.
+ * Use for #SCE_XFORM_SKIP_CHILDREN.
+ */
+#define BA_TRANSFORM_LOCKED_IN_PLACE (1 << 7)
#define BA_TRANSFORM_CHILD (1 << 8) /* child of a transformed object */
#define BA_TRANSFORM_PARENT (1 << 13) /* parent of a transformed object */
@@ -684,6 +691,7 @@ enum {
OB_EMPTY_IMAGE_HIDE_ORTHOGRAPHIC = 1 << 1,
OB_EMPTY_IMAGE_HIDE_BACK = 1 << 2,
OB_EMPTY_IMAGE_HIDE_FRONT = 1 << 3,
+ OB_EMPTY_IMAGE_HIDE_NON_AXIS_ALIGNED = 1 << 4,
};
/** #Object.empty_image_flag */
diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h
new file mode 100644
index 00000000000..8d77e57c959
--- /dev/null
+++ b/source/blender/makesdna/DNA_scene_defaults.h
@@ -0,0 +1,368 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_SCENE_DEFAULTS_H__
+#define __DNA_SCENE_DEFAULTS_H__
+
+#include "DNA_view3d_defaults.h"
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Scene Struct
+ * \{ */
+
+#define _DNA_DEFAULT_ImageFormatData \
+ { \
+ .planes = R_IMF_PLANES_RGBA, \
+ .imtype = R_IMF_IMTYPE_PNG, \
+ .depth = R_IMF_CHAN_DEPTH_8, \
+ .quality = 90, \
+ .compress = 15, \
+ }
+
+#define _DNA_DEFAULT_BakeData \
+ { \
+ .im_format = _DNA_DEFAULT_ImageFormatData, \
+ .filepath = "//", \
+ .flag = R_BAKE_CLEAR, \
+ .pass_filter = R_BAKE_PASS_FILTER_ALL, \
+ .width = 512, \
+ .height = 512, \
+ .margin = 16, \
+ .normal_space = R_BAKE_SPACE_TANGENT, \
+ .normal_swizzle = {R_BAKE_POSX, R_BAKE_POSY, R_BAKE_POSZ}, \
+ }
+
+#define _DNA_DEFAULT_FFMpegCodecData \
+ { \
+ .audio_mixrate = 48000, \
+ .audio_volume = 1.0f, \
+ .audio_bitrate = 192, \
+ .audio_channels = 2, \
+ }
+
+#define _DNA_DEFAULT_DisplaySafeAreas \
+ { \
+ .title = {10.0f / 100.0f, 5.0f / 100.0f}, \
+ .action = {3.5f / 100.0f, 3.5f / 100.0f}, \
+ .title_center = {17.5f / 100.0f, 5.0f / 100.0f}, \
+ .action_center = {15.0f / 100.0f, 5.0f / 100.0f}, \
+ }
+
+#define _DNA_DEFAULT_RenderData \
+ { \
+ .mode = 0, \
+ .cfra = 1, \
+ .sfra = 1, \
+ .efra = 250, \
+ .frame_step = 1, \
+ .xsch = 1920, \
+ .ysch = 1080, \
+ .xasp = 1, \
+ .yasp = 1, \
+ .tilex = 256, \
+ .tiley = 256, \
+ .size = 100, \
+ \
+ .im_format = _DNA_DEFAULT_ImageFormatData, \
+ \
+ .displaymode = R_OUTPUT_WINDOW, \
+ .framapto = 100, \
+ .images = 100, \
+ .framelen = 1.0, \
+ .blurfac = 0.5, \
+ .frs_sec = 24, \
+ .frs_sec_base = 1, \
+ \
+ /* OCIO_TODO: for forwards compatibility only, so if no tone-curve are used, \
+ * images would look in the same way as in current blender \
+ * \
+ * perhaps at some point should be completely deprecated? \
+ */ \
+ .color_mgt_flag = R_COLOR_MANAGEMENT, \
+ \
+ .gauss = 1.5, \
+ .dither_intensity = 1.0f, \
+ \
+ .bake_mode = 0, \
+ .bake_filter = 16, \
+ .bake_flag = R_BAKE_CLEAR, \
+ .bake_samples = 256, \
+ .bake_biasdist = 0.001f, \
+ \
+ /* BakeData */ \
+ .bake = _DNA_DEFAULT_BakeData, \
+ \
+ .scemode = R_DOCOMP | R_DOSEQ | R_EXTENSION, \
+ \
+ .pic = "//", \
+ \
+ .stamp = R_STAMP_TIME | R_STAMP_FRAME | R_STAMP_DATE | R_STAMP_CAMERA | R_STAMP_SCENE | \
+ R_STAMP_FILENAME | R_STAMP_RENDERTIME | R_STAMP_MEMORY, \
+ .stamp_font_id = 12, \
+ .fg_stamp = {0.8f, 0.8f, 0.8f, 1.0f}, \
+ .bg_stamp = {0.0f, 0.0f, 0.0f, 0.25f}, \
+ \
+ .seq_prev_type = OB_SOLID, \
+ .seq_rend_type = OB_SOLID, \
+ .seq_flag = 0, \
+ \
+ .threads = 1, \
+ \
+ .simplify_subsurf = 6, \
+ .simplify_particles = 1.0f, \
+ \
+ .border.xmin = 0.0f, \
+ .border.ymin = 0.0f, \
+ .border.xmax = 1.0f, \
+ .border.ymax = 1.0f, \
+ \
+ .preview_start_resolution = 64, \
+ \
+ .line_thickness_mode = R_LINE_THICKNESS_ABSOLUTE, \
+ .unit_line_thickness = 1.0f, \
+ \
+ .ffcodecdata = _DNA_DEFAULT_FFMpegCodecData, \
+ }
+
+#define _DNA_DEFAULT_AudioData \
+ { \
+ .distance_model = 2.0f, \
+ .doppler_factor = 1.0f, \
+ .speed_of_sound = 343.3f, \
+ .volume = 1.0f, \
+ .flag = AUDIO_SYNC, \
+ }
+
+#define _DNA_DEFAULT_SceneDisplay \
+ { \
+ .light_direction = {M_SQRT1_3, M_SQRT1_3, M_SQRT1_3}, \
+ .shadow_shift = 0.1f, \
+ .shadow_focus = 0.0f, \
+ \
+ .matcap_ssao_distance = 0.2f, \
+ .matcap_ssao_attenuation = 1.0f, \
+ .matcap_ssao_samples = 16, \
+ \
+ .shading = _DNA_DEFAULT_View3DShading, \
+ \
+ .render_aa = SCE_DISPLAY_AA_SAMPLES_8, \
+ .viewport_aa = SCE_DISPLAY_AA_FXAA, \
+ }
+
+#define _DNA_DEFAULT_PhysicsSettings \
+ { \
+ .gravity = {0.0f, 0.0f -9.81f}, \
+ .flag = PHYS_GLOBAL_GRAVITY, \
+ }
+
+#define _DNA_DEFAULT_SceneEEVEE \
+ { \
+ .gi_diffuse_bounces = 3, \
+ .gi_cubemap_resolution = 512, \
+ .gi_visibility_resolution = 32, \
+ .gi_cubemap_draw_size = 0.3f, \
+ .gi_irradiance_draw_size = 0.1f, \
+ .gi_irradiance_smoothing = 0.1f, \
+ .gi_filter_quality = 3.0f, \
+ \
+ .taa_samples = 16, \
+ .taa_render_samples = 64, \
+ \
+ .sss_samples = 7, \
+ .sss_jitter_threshold = 0.3f, \
+ \
+ .ssr_quality = 0.25f, \
+ .ssr_max_roughness = 0.5f, \
+ .ssr_thickness = 0.2f, \
+ .ssr_border_fade = 0.075f, \
+ .ssr_firefly_fac = 10.0f, \
+ \
+ .volumetric_start = 0.1f, \
+ .volumetric_end = 100.0f, \
+ .volumetric_tile_size = 8, \
+ .volumetric_samples = 64, \
+ .volumetric_sample_distribution = 0.8f, \
+ .volumetric_light_clamp = 0.0f, \
+ .volumetric_shadow_samples = 16, \
+ \
+ .gtao_distance = 0.2f, \
+ .gtao_factor = 1.0f, \
+ .gtao_quality = 0.25f, \
+ \
+ .bokeh_max_size = 100.0f, \
+ .bokeh_threshold = 1.0f, \
+ \
+ .bloom_color = {1.0f, 1.0f, 1.0f}, \
+ .bloom_threshold = 0.8f, \
+ .bloom_knee = 0.5f, \
+ .bloom_intensity = 0.05f, \
+ .bloom_radius = 6.5f, \
+ .bloom_clamp = 0.0f, \
+ \
+ .motion_blur_samples = 8, \
+ .motion_blur_shutter = 0.5f, \
+ \
+ .shadow_cube_size = 512, \
+ .shadow_cascade_size = 1024, \
+ \
+ .light_cache = NULL, \
+ .light_threshold = 0.01f, \
+ \
+ .overscan = 3.0f, \
+ \
+ .flag = SCE_EEVEE_VOLUMETRIC_LIGHTS | SCE_EEVEE_GTAO_BENT_NORMALS | \
+ SCE_EEVEE_GTAO_BOUNCE | SCE_EEVEE_TAA_REPROJECTION | \
+ SCE_EEVEE_SSR_HALF_RESOLUTION | SCE_EEVEE_SHADOW_SOFT, \
+ }
+
+#define _DNA_DEFAULT_Scene \
+ { \
+ .cursor = _DNA_DEFAULT_View3DCursor, \
+ .r = _DNA_DEFAULT_RenderData, \
+ .audio = _DNA_DEFAULT_AudioData, \
+ \
+ .display = _DNA_DEFAULT_SceneDisplay, \
+ \
+ .physics_settings = _DNA_DEFAULT_PhysicsSettings, \
+ \
+ .safe_areas = _DNA_DEFAULT_DisplaySafeAreas, \
+ \
+ .eevee = _DNA_DEFAULT_SceneEEVEE, \
+ }
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ToolSettings Struct
+ * \{ */
+
+#define _DNA_DEFAULTS_CurvePaintSettings \
+ { \
+ .curve_type = CU_BEZIER, \
+ .flag = CURVE_PAINT_FLAG_CORNERS_DETECT, \
+ .error_threshold = 8, \
+ .radius_max = 1.0f, \
+ .corner_angle = DEG2RADF(70.0f), \
+ }
+
+#define _DNA_DEFAULTS_ImagePaintSettings \
+ { \
+ .paint.flags = PAINT_SHOW_BRUSH, \
+ .normal_angle = 80, \
+ .seam_bleed = 2, \
+ }
+
+#define _DNA_DEFAULTS_ParticleBrushData \
+ { \
+ .strength = 0.5f, \
+ .size = 50, \
+ .step = 10, \
+ .count = 10, \
+ }
+
+#define _DNA_DEFAULTS_ParticleEditSettings \
+ { \
+ .flag = PE_KEEP_LENGTHS | PE_LOCK_FIRST | PE_DEFLECT_EMITTER | PE_AUTO_VELOCITY, \
+ .emitterdist = 0.25f, \
+ .totrekey = 5, \
+ .totaddkey = 5, \
+ .brushtype = PE_BRUSH_COMB, \
+ \
+ /* Scene init copies this to all other elements. */ \
+ .brush = {_DNA_DEFAULTS_ParticleBrushData}, \
+ \
+ .draw_step = 2, \
+ .fade_frames = 2, \
+ .selectmode = SCE_SELECT_PATH, \
+ }
+
+#define _DNA_DEFAULTS_GP_Sculpt_Guide \
+ { \
+ .spacing = 20.0f, \
+ }
+
+#define _DNA_DEFAULTS_GP_Sculpt_Settings \
+ { \
+ .guide = _DNA_DEFAULTS_GP_Sculpt_Guide, \
+ }
+
+#define _DNA_DEFAULTS_MeshStatVis \
+ { \
+ .overhang_axis = OB_NEGZ, \
+ .overhang_min = 0, \
+ .overhang_max = DEG2RADF(45.0f), \
+ .thickness_max = 0.1f, \
+ .thickness_samples = 1, \
+ .distort_min = DEG2RADF(5.0f), \
+ .distort_max = DEG2RADF(45.0f), \
+ \
+ .sharp_min = DEG2RADF(90.0f), \
+ .sharp_max = DEG2RADF(180.0f), \
+ }
+
+#define _DNA_DEFAULT_ToolSettings \
+ { \
+ .object_flag = SCE_OBJECT_MODE_LOCK, \
+ .doublimit = 0.001, \
+ .vgroup_weight = 1.0f, \
+ .uvcalc_margin = 0.001f, \
+ .uvcalc_flag = UVCALC_TRANSFORM_CORRECT, \
+ .unwrapper = 1, \
+ .select_thresh = 0.01f, \
+ \
+ .selectmode = SCE_SELECT_VERTEX, \
+ .uv_selectmode = UV_SELECT_VERTEX, \
+ .autokey_mode = AUTOKEY_MODE_NORMAL, \
+ \
+ .transform_pivot_point = V3D_AROUND_CENTER_MEDIAN, \
+ .snap_mode = SCE_SNAP_MODE_INCREMENT, \
+ .snap_node_mode = SCE_SNAP_MODE_GRID, \
+ .snap_uv_mode = SCE_SNAP_MODE_INCREMENT, \
+ .snap_transform_mode_flag = SCE_SNAP_TRANSFORM_MODE_TRANSLATE, \
+ \
+ .curve_paint_settings = _DNA_DEFAULTS_CurvePaintSettings, \
+ \
+ .statvis = _DNA_DEFAULTS_MeshStatVis, \
+ \
+ .proportional_size = 1.0f, \
+ \
+ .imapaint = _DNA_DEFAULTS_ImagePaintSettings, \
+ \
+ .particle = _DNA_DEFAULTS_ParticleEditSettings, \
+ \
+ .gp_sculpt = _DNA_DEFAULTS_GP_Sculpt_Settings, \
+ \
+ /* Annotations */ \
+ .annotate_v3d_align = GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR, \
+ .annotate_thickness = 3, \
+ \
+ /* GP Stroke Placement */ \
+ .gpencil_v3d_align = GP_PROJECT_VIEWSPACE, \
+ .gpencil_v2d_align = GP_PROJECT_VIEWSPACE, \
+ .gpencil_seq_align = GP_PROJECT_VIEWSPACE, \
+ .gpencil_ima_align = GP_PROJECT_VIEWSPACE, \
+ }
+
+/* clang-format off */
+
+#endif /* __DNA_SCENE_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 412bf358a44..ca572f1ddf1 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -669,9 +669,8 @@ typedef struct RenderData {
char _pad0[1];
- /* safety, border and display rect */
- rctf safety, border;
- rcti disprect;
+ /** Render border to render sub-resions. */
+ rctf border;
/* information on different layers to be rendered */
/** Converted to Scene->view_layers. */
@@ -1366,6 +1365,12 @@ typedef struct MeshStatVis {
/* *************************************************************** */
/* Tool Settings */
+/* CurvePaintSettings.surface_plane */
+enum {
+ AUTO_MERGE = 1 << 0,
+ AUTO_MERGE_AND_SPLIT = 1 << 1,
+};
+
typedef struct ToolSettings {
/** Vertex paint. */
VPaint *vpaint;
@@ -1631,7 +1636,7 @@ typedef struct SceneEEVEE {
int motion_blur_samples;
float motion_blur_shutter;
- int shadow_method;
+ int shadow_method DNA_DEPRECATED;
int shadow_cube_size;
int shadow_cascade_size;
@@ -1974,6 +1979,8 @@ extern const char *RE_engine_id_CYCLES;
#define BASE_VISIBLE(v3d, base) \
(((v3d == NULL) || ((v3d)->localvd == NULL) || \
((v3d)->local_view_uuid & (base)->local_view_bits)) && \
+ ((v3d == NULL) || (((v3d)->flag & V3D_LOCAL_COLLECTIONS) == 0) || \
+ ((v3d)->local_collections_uuid & (base)->local_collections_bits)) && \
((v3d == NULL) || \
(((1 << (base)->object->type) & (v3d)->object_type_exclude_viewport) == 0)) && \
(((base)->flag & BASE_VISIBLE) != 0))
@@ -1996,6 +2003,8 @@ extern const char *RE_engine_id_CYCLES;
(((workspace)->object_mode & OD_MODE_EDIT) ? OBACT(_view_layer) : NULL)
#define OBEDIT_FROM_OBACT(ob) ((ob) ? (((ob)->mode & OB_MODE_EDIT) ? ob : NULL) : NULL)
#define OBPOSE_FROM_OBACT(ob) ((ob) ? (((ob)->mode & OB_MODE_POSE) ? ob : NULL) : NULL)
+#define OBWEIGHTPAINT_FROM_OBACT(ob) \
+ ((ob) ? (((ob)->mode & OB_MODE_WEIGHT_PAINT) ? ob : NULL) : NULL)
#define OBEDIT_FROM_VIEW_LAYER(view_layer) OBEDIT_FROM_OBACT(OBACT(view_layer))
#define V3D_CAMERA_LOCAL(v3d) ((!(v3d)->scenelock && (v3d)->camera) ? (v3d)->camera : NULL)
@@ -2019,6 +2028,7 @@ extern const char *RE_engine_id_CYCLES;
enum {
SCE_XFORM_AXIS_ALIGN = (1 << 0),
SCE_XFORM_DATA_ORIGIN = (1 << 1),
+ SCE_XFORM_SKIP_CHILDREN = (1 << 2),
};
/* ToolSettings.object_flag */
@@ -2284,6 +2294,8 @@ typedef enum eGPencil_SimplifyFlags {
SIMPLIFY_GPENCIL_FX = (1 << 5),
/* Simplify layer blending */
SIMPLIFY_GPENCIL_BLEND = (1 << 6),
+ /* Simplify layer tint */
+ SIMPLIFY_GPENCIL_TINT = (1 << 7),
} eGPencil_SimplifyFlags;
/* ToolSettings.gpencil_*_align - Stroke Placement mode flags */
@@ -2317,6 +2329,7 @@ typedef enum eGPencil_GuideTypes {
GP_GUIDE_RADIAL,
GP_GUIDE_PARALLEL,
GP_GUIDE_GRID,
+ GP_GUIDE_ISO,
} eGPencil_GuideTypes;
/* ToolSettings.gpencil_guide_references */
@@ -2383,7 +2396,7 @@ enum {
SCE_EEVEE_SHADOW_HIGH_BITDEPTH = (1 << 10),
SCE_EEVEE_TAA_REPROJECTION = (1 << 11),
// SCE_EEVEE_SSS_ENABLED = (1 << 12), /* Unused */
- SCE_EEVEE_SSS_SEPARATE_ALBEDO = (1 << 13),
+ // SCE_EEVEE_SSS_SEPARATE_ALBEDO = (1 << 13), /* Unused */
SCE_EEVEE_SSR_ENABLED = (1 << 14),
SCE_EEVEE_SSR_REFRACTION = (1 << 15),
SCE_EEVEE_SSR_HALF_RESOLUTION = (1 << 16),
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index aab71c15e44..bf491e2eaea 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -458,16 +458,18 @@ enum {
#ifdef DNA_DEPRECATED_ALLOW
AREA_TEMP_INFO = (1 << 3), /* versioned to make slot reusable */
#endif
- /* update size of regions within the area */
+ /** Update size of regions within the area. */
AREA_FLAG_REGION_SIZE_UPDATE = (1 << 3),
AREA_FLAG_ACTIVE_TOOL_UPDATE = (1 << 4),
// AREA_FLAG_UNUSED_5 = (1 << 5),
- /* used to check if we should switch back to prevspace (of a different type) */
+ /** Used to check if we should switch back to prevspace (of a different type). */
AREA_FLAG_TEMP_TYPE = (1 << 6),
- /* for temporary fullscreens (file browser, image editor render)
- * that are opened above user set fullscreens */
+ /**
+ * For temporary full-screens (file browser, image editor render)
+ * that are opened above user set full-screens.
+ */
AREA_FLAG_STACKED_FULLSCREEN = (1 << 7),
- /* update action zones (even if the mouse is not intersecting them) */
+ /** Update action zones (even if the mouse is not intersecting them). */
AREA_FLAG_ACTIONZONES_UPDATE = (1 << 8),
};
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 087d30ce312..8d9dc77c49b 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -270,6 +270,8 @@ typedef struct Editing {
/* Cache control */
float recycle_max_cost;
int cache_flag;
+
+ struct PrefetchJob *prefetch_job;
} Editing;
/* ************* Effect Variable Structs ********* */
@@ -674,6 +676,8 @@ enum {
SEQ_CACHE_VIEW_PREPROCESSED = (1 << 7),
SEQ_CACHE_VIEW_COMPOSITE = (1 << 8),
SEQ_CACHE_VIEW_FINAL_OUT = (1 << 9),
+
+ SEQ_CACHE_PREFETCH_ENABLE = (1 << 10),
};
#endif /* __DNA_SEQUENCE_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 1691d873f9b..0f957a946d9 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -676,9 +676,10 @@ typedef struct FileSelectParams {
short sort;
/** Display mode flag. */
short display;
- short display_previous;
+ /** Details toggles (file size, creation date, etc.) */
+ char details_flags;
+ char _pad2[3];
/** Filter when (flags & FILE_FILTER) is true. */
- char _pad2[2];
int filter;
/** Max number of levels in dirtree to show at once, 0 to disable recursion. */
@@ -736,8 +737,8 @@ typedef struct SpaceFile {
/* FileSelectParams.display */
enum eFileDisplayType {
FILE_DEFAULTDISPLAY = 0,
- FILE_SHORTDISPLAY = 1,
- FILE_LONGDISPLAY = 2,
+ FILE_VERTICALDISPLAY = 1,
+ FILE_HORIZONTALDISPLAY = 2,
FILE_IMGDISPLAY = 3,
};
@@ -750,6 +751,12 @@ enum eFileSortType {
FILE_SORT_SIZE = 4,
};
+/* FileSelectParams.details_flags */
+enum eFileDetails {
+ FILE_DETAILS_SIZE = (1 << 0),
+ FILE_DETAILS_DATETIME = (1 << 1),
+};
+
/* these values need to be hardcoded in structs, dna does not recognize defines */
/* also defined in BKE */
#define FILE_MAXDIR 768
@@ -787,6 +794,9 @@ typedef enum eFileSel_Params_Flag {
FILE_FILTER = (1 << 8),
FILE_PARAMS_FLAG_UNUSED_9 = (1 << 9), /* cleared */
FILE_GROUP_INSTANCE = (1 << 10),
+ FILE_SORT_INVERT = (1 << 11),
+ FILE_HIDE_TOOL_PROPS = (1 << 12),
+ FILE_CHECK_EXISTING = (1 << 13),
} eFileSel_Params_Flag;
/* sfile->params->rename_flag */
@@ -815,7 +825,7 @@ typedef enum eFileSel_File_Types {
FILE_TYPE_FTFONT = (1 << 7),
FILE_TYPE_SOUND = (1 << 8),
FILE_TYPE_TEXT = (1 << 9),
- /* 1 << 10 was FILE_TYPE_MOVIE_ICON, got rid of this so free slot for future type... */
+ FILE_TYPE_ARCHIVE = (1 << 10),
/** represents folders for filtering */
FILE_TYPE_FOLDER = (1 << 11),
FILE_TYPE_BTX = (1 << 12),
@@ -824,6 +834,8 @@ typedef enum eFileSel_File_Types {
FILE_TYPE_OPERATOR = (1 << 14),
FILE_TYPE_APPLICATIONBUNDLE = (1 << 15),
FILE_TYPE_ALEMBIC = (1 << 16),
+ /** For all kinds of recognized import/export formats. No need for specialized types. */
+ FILE_TYPE_OBJECT_IO = (1 << 17),
/** An FS directory (i.e. S_ISDIR on its path is true). */
FILE_TYPE_DIR = (1 << 30),
@@ -882,8 +894,7 @@ typedef struct FileDirEntryRevision {
int64_t time;
/* Temp caching of UI-generated strings... */
char size_str[16];
- char time_str[8];
- char date_str[16];
+ char datetime_str[16 + 8];
} FileDirEntryRevision;
/* Container for a variant, only relevant in asset context.
@@ -1118,8 +1129,6 @@ typedef enum eSpaceImage_Flag {
SI_SHOW_R = (1 << 27),
SI_SHOW_G = (1 << 28),
SI_SHOW_B = (1 << 29),
-
- SI_NO_DRAWEDGES = (1 << 30),
} eSpaceImage_Flag;
/* SpaceImage.other_uv_filter */
diff --git a/source/blender/makesdna/DNA_speaker_defaults.h b/source/blender/makesdna/DNA_speaker_defaults.h
new file mode 100644
index 00000000000..d252a447701
--- /dev/null
+++ b/source/blender/makesdna/DNA_speaker_defaults.h
@@ -0,0 +1,51 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_SPEAKER_DEFAULTS_H__
+#define __DNA_SPEAKER_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Speaker Struct
+ * \{ */
+
+#define _DNA_DEFAULT_Speaker \
+ { \
+ .attenuation = 1.0f, \
+ .cone_angle_inner = 360.0f, \
+ .cone_angle_outer = 360.0f, \
+ .cone_volume_outer = 1.0f, \
+ .distance_max = FLT_MAX, \
+ .distance_reference = 1.0f, \
+ .flag = 0, \
+ .pitch = 1.0f, \
+ .sound = NULL, \
+ .volume = 1.0f, \
+ .volume_max = 1.0f, \
+ .volume_min = 0.0f, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_SPEAKER_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_texture_defaults.h b/source/blender/makesdna/DNA_texture_defaults.h
new file mode 100644
index 00000000000..d5097c5ea21
--- /dev/null
+++ b/source/blender/makesdna/DNA_texture_defaults.h
@@ -0,0 +1,155 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_TEXTURE_DEFAULTS_H__
+#define __DNA_TEXTURE_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Texture Struct
+ * \{ */
+
+#define _DNA_DEFAULT_MTex \
+ { \
+ .texco = TEXCO_UV, \
+ .mapto = MAP_COL, \
+ .object = NULL, \
+ .projx = PROJ_X, \
+ .projy = PROJ_Y, \
+ .projz = PROJ_Z, \
+ .mapping = MTEX_FLAT, \
+ .ofs[0] = 0.0, \
+ .ofs[1] = 0.0, \
+ .ofs[2] = 0.0, \
+ .size[0] = 1.0, \
+ .size[1] = 1.0, \
+ .size[2] = 1.0, \
+ .tex = NULL, \
+ .colormodel = 0, \
+ .r = 1.0, \
+ .g = 0.0, \
+ .b = 1.0, \
+ .k = 1.0, \
+ .def_var = 1.0, \
+ .blendtype = MTEX_BLEND, \
+ .colfac = 1.0, \
+ .norfac = 1.0, \
+ .varfac = 1.0, \
+ .dispfac = 0.2, \
+ .colspecfac = 1.0f, \
+ .mirrfac = 1.0f, \
+ .alphafac = 1.0f, \
+ .difffac = 1.0f, \
+ .specfac = 1.0f, \
+ .emitfac = 1.0f, \
+ .hardfac = 1.0f, \
+ .raymirrfac = 1.0f, \
+ .translfac = 1.0f, \
+ .ambfac = 1.0f, \
+ .colemitfac = 1.0f, \
+ .colreflfac = 1.0f, \
+ .coltransfac = 1.0f, \
+ .densfac = 1.0f, \
+ .scatterfac = 1.0f, \
+ .reflfac = 1.0f, \
+ .shadowfac = 1.0f, \
+ .zenupfac = 1.0f, \
+ .zendownfac = 1.0f, \
+ .blendfac = 1.0f, \
+ .timefac = 1.0f, \
+ .lengthfac = 1.0f, \
+ .clumpfac = 1.0f, \
+ .kinkfac = 1.0f, \
+ .kinkampfac = 1.0f, \
+ .roughfac = 1.0f, \
+ .twistfac = 1.0f, \
+ .padensfac = 1.0f, \
+ .lifefac = 1.0f, \
+ .sizefac = 1.0f, \
+ .ivelfac = 1.0f, \
+ .dampfac = 1.0f, \
+ .gravityfac = 1.0f, \
+ .fieldfac = 1.0f, \
+ .normapspace = MTEX_NSPACE_TANGENT, \
+ .brush_map_mode = MTEX_MAP_MODE_TILED, \
+ .random_angle = 2.0f * (float)M_PI, \
+ .brush_angle_mode = 0, \
+ } \
+
+#define _DNA_DEFAULT_Tex \
+ { \
+ .type = TEX_IMAGE, \
+ .ima = NULL, \
+ .stype = 0, \
+ .flag = TEX_CHECKER_ODD, \
+ .imaflag = TEX_INTERPOL | TEX_MIPMAP | TEX_USEALPHA, \
+ .extend = TEX_REPEAT, \
+ .cropxmin = 0.0, \
+ .cropymin = 0.0, \
+ .cropxmax = 1.0, \
+ .cropymax = 1.0, \
+ .texfilter = TXF_EWA, \
+ .afmax = 8, \
+ .xrepeat = 1, \
+ .yrepeat = 1, \
+ .sfra = 1, \
+ .frames = 0, \
+ .offset = 0, \
+ .noisesize = 0.25, \
+ .noisedepth = 2, \
+ .turbul = 5.0, \
+ .nabla = 0.025, /* also in do_versions. */ \
+ .bright = 1.0, \
+ .contrast = 1.0, \
+ .saturation = 1.0, \
+ .filtersize = 1.0, \
+ .rfac = 1.0, \
+ .gfac = 1.0, \
+ .bfac = 1.0, \
+ /* newnoise: init. */ \
+ .noisebasis = 0, \
+ .noisebasis2 = 0, \
+ /* musgrave */ \
+ .mg_H = 1.0, \
+ .mg_lacunarity = 2.0, \
+ .mg_octaves = 2.0, \
+ .mg_offset = 1.0, \
+ .mg_gain = 1.0, \
+ .ns_outscale = 1.0, \
+ /* distnoise */ \
+ .dist_amount = 1.0, \
+ /* voronoi */ \
+ .vn_w1 = 1.0, \
+ .vn_w2 = 0.0, \
+ .vn_w3 = 0.0, \
+ .vn_w4 = 0.0, \
+ .vn_mexp = 2.5, \
+ .vn_distm = 0, \
+ .vn_coltype = 0, \
+ .preview = NULL, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_TEXTURE_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 3cb96ce8bf8..126b4638ca1 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -64,7 +64,7 @@ typedef struct uiFont {
char _pad0[2];
} uiFont;
-/* this state defines appearance of text */
+/** This state defines appearance of text. */
typedef struct uiFontStyle {
/** Saved in file, 0 is default. */
short uifont_id;
@@ -196,6 +196,9 @@ typedef struct ThemeUI {
unsigned char icon_modifier[4];
/** Shading related items. */
unsigned char icon_shading[4];
+ /** File folders. */
+ unsigned char icon_folder[4];
+ char _pad2[4];
/** Intensity of the border icons. >0 will render an border around themed
* icons. */
float icon_border_intensity;
@@ -342,6 +345,7 @@ typedef struct ThemeSpace {
lock_marker[4];
unsigned char bundle_solid[4];
unsigned char path_before[4], path_after[4];
+ unsigned char path_keyframe_before[4], path_keyframe_after[4];
unsigned char camera_path[4];
unsigned char _pad1[2];
@@ -430,15 +434,22 @@ typedef enum eWireColor_Flags {
TH_WIRECOLOR_TEXTCOLS = (1 << 1),
} eWireColor_Flags;
-/* A theme */
+/**
+ * A theme.
+ *
+ * \note Currently only a single theme is ever used at once.
+ * Different theme presets are stored as external files now.
+ */
typedef struct bTheme {
struct bTheme *next, *prev;
char name[32];
ThemeUI tui;
- /* Individual Spacetypes */
- /* note: ensure UI_THEMESPACE_END is updated when adding */
+ /**
+ * Individual Spacetypes:
+ * \note Ensure #UI_THEMESPACE_END is updated when adding.
+ */
ThemeSpace space_properties;
ThemeSpace space_view3d;
ThemeSpace space_file;
@@ -465,8 +476,10 @@ typedef struct bTheme {
char _pad0[4];
} bTheme;
-#define UI_THEMESPACE_START(btheme) (CHECK_TYPE_INLINE(btheme, bTheme *), &((btheme)->tbuts))
-#define UI_THEMESPACE_END(btheme) (CHECK_TYPE_INLINE(btheme, bTheme *), (&((btheme)->tclip) + 1))
+#define UI_THEMESPACE_START(btheme) \
+ (CHECK_TYPE_INLINE(btheme, bTheme *), &((btheme)->space_properties))
+#define UI_THEMESPACE_END(btheme) \
+ (CHECK_TYPE_INLINE(btheme, bTheme *), (&((btheme)->space_statusbar) + 1))
typedef struct bAddon {
struct bAddon *next, *prev;
@@ -492,7 +505,7 @@ typedef struct bUserMenu {
ListBase items;
} bUserMenu;
-/* May be part of bUserMenu or other list. */
+/** May be part of #bUserMenu or other list. */
typedef struct bUserMenuItem {
struct bUserMenuItem *next, *prev;
char ui_name[64];
@@ -553,16 +566,44 @@ typedef struct UserDef_Runtime {
char _pad0[7];
} UserDef_Runtime;
+/**
+ * Store UI data here instead of the space
+ * since the space is typically a window which is freed.
+ */
+typedef struct UserDef_SpaceData {
+ char section_active;
+ /** #eUserPref_SpaceData_Flag UI options. */
+ char flag;
+ char _pad0[6];
+} UserDef_SpaceData;
+
+/**
+ * Storage for UI data that to keep it even after the window was closed. (Similar to
+ * #UserDef_SpaceData.)
+ */
+typedef struct UserDef_FileSpaceData {
+ int display_type; /* FileSelectParams.display */
+ int thumbnail_size; /* FileSelectParams.thumbnail_size */
+ int sort_type; /* FileSelectParams.sort */
+ int details_flags; /* FileSelectParams.details_flags */
+ int flag; /* FileSelectParams.flag */
+
+ char _pad[4];
+
+ /** Info used when creating the file browser in a temporary window. */
+ int temp_win_sizex;
+ int temp_win_sizey;
+} UserDef_FileSpaceData;
+
typedef struct UserDef {
- /* UserDef has separate do-version handling, and can be read from other files */
+ /** UserDef has separate do-version handling, and can be read from other files. */
int versionfile, subversionfile;
/** #eUserPref_Flag. */
int flag;
/** #eDupli_ID_Flags. */
short dupflag;
- /**
- * #eUserPref_PrefFlag preferences for the preferences. */
+ /** #eUserPref_PrefFlag preferences for the preferences. */
char pref_flag;
char savetime;
char _pad4[4];
@@ -600,14 +641,12 @@ typedef struct UserDef {
/** #eUserpref_UI_Flag2. */
char uiflag2;
char gpu_flag;
- char _pad8[2];
+ char _pad8[6];
/* Experimental flag for app-templates to make changes to behavior
* which are outside the scope of typical preferences. */
- short app_flag;
- short language;
- short userpref;
- char userpref_flag;
+ char app_flag;
char viewzoom;
+ short language;
int mixbufsize;
int audiodevice;
@@ -638,7 +677,7 @@ typedef struct UserDef {
short transopts;
short menuthreshold1, menuthreshold2;
- /* startup template */
+ /** Startup application template. */
char app_template[64];
struct ListBase themes;
@@ -717,7 +756,7 @@ typedef struct UserDef {
/** Overall sensitivity of 3D mouse. */
float ndof_sensitivity;
float ndof_orbit_sensitivity;
- /** Deadzone of 3D mouse. */
+ /** Dead-zone of 3D mouse. */
float ndof_deadzone;
/** #eNdof_Flag, flags for 3D mouse. */
int ndof_flag;
@@ -765,7 +804,6 @@ typedef struct UserDef {
/** Legacy, for backwards compatibility only. */
int compute_device_type;
- char _pad6[4];
/** Opacity of inactive F-Curves in F-Curve Editor. */
float fcu_inactive_alpha;
@@ -787,8 +825,6 @@ typedef struct UserDef {
/** Pie menu distance from center before a direction is set. */
short pie_menu_threshold;
- struct WalkNavigation walk_navigation;
-
short opensubdiv_compute_type;
/** #eMultiSample_Type, amount of samples for Grease Pencil. */
short gpencil_multisamples;
@@ -797,7 +833,15 @@ typedef struct UserDef {
char viewport_aa;
- char _pad5[2];
+ char render_display_type; /* eUserpref_RenderDisplayType */
+ char filebrowser_display_type; /* eUserpref_TempSpaceDisplayType */
+ char _pad5[4];
+
+ struct WalkNavigation walk_navigation;
+
+ /** The UI for the user preferences. */
+ UserDef_SpaceData space_data;
+ UserDef_FileSpaceData file_space_data;
/** Runtime data (keep last). */
UserDef_Runtime runtime;
@@ -811,7 +855,7 @@ extern UserDef U;
/* Toggles for unfinished 2.8 UserPref design. */
//#define WITH_USERDEF_WORKSPACES
-/** #UserDef.userpref (UI active_section) */
+/** #UserDef_SpaceData.section_active (UI active_section) */
typedef enum eUserPref_Section {
USER_SECTION_INTERFACE = 0,
USER_SECTION_EDITING = 1,
@@ -833,11 +877,12 @@ typedef enum eUserPref_Section {
USER_SECTION_FILE_PATHS = 15,
} eUserPref_Section;
-/* UserDef.userpref_flag (State of the user preferences UI). */
-typedef enum eUserPref_SectionFlag {
- /* Hide/expand keymap preferences. */
- USER_SECTION_INPUT_HIDE_UI_KEYCONFIG = (1 << 0),
-} eUserPref_SectionFlag;
+/** #UserDef_SpaceData.flag (State of the user preferences UI). */
+typedef enum eUserPref_SpaceData_Flag {
+ /** Hide/expand key-map preferences. */
+ USER_SPACEDATA_INPUT_HIDE_UI_KEYCONFIG = (1 << 0),
+ USER_SPACEDATA_ADDONS_SHOW_ONLY_ENABLED = (1 << 1),
+} eUserPref_SpaceData_Flag;
/** #UserDef.flag */
typedef enum eUserPref_Flag {
@@ -868,7 +913,7 @@ typedef enum eUserPref_Flag {
USER_NONEGFRAMES = (1 << 24),
USER_TXT_TABSTOSPACES_DISABLE = (1 << 25),
USER_TOOLTIPS_PYTHON = (1 << 26),
- USER_ADDONS_ENABLED_ONLY = (1 << 27),
+ USER_FLAG_UNUSED_27 = (1 << 27), /* dirty */
} eUserPref_Flag;
typedef enum eUserPref_PrefFlag {
@@ -946,7 +991,11 @@ typedef enum eUserpref_UI_Flag {
USER_ZOOM_HORIZ = (1 << 26), /* for CONTINUE and DOLLY zoom */
USER_SPLASH_DISABLE = (1 << 27),
USER_HIDE_RECENT = (1 << 28),
- USER_SHOW_THUMBNAILS = (1 << 29),
+#ifdef DNA_DEPRECATED
+ USER_SHOW_THUMBNAILS =
+ (1 << 29), /* deprecated - We're just trying if there's much desire for this feature, or if
+ we can make it go for good. Should be cleared if so - Julian, Oct. 2019 */
+#endif
USER_SAVE_PROMPT = (1 << 30),
USER_HIDE_SYSTEM_BOOKMARKS = (1u << 31),
} eUserpref_UI_Flag;
@@ -1089,26 +1138,23 @@ typedef enum eColorPicker_Types {
/** Timecode display styles
* #UserDef.timecode_style */
typedef enum eTimecodeStyles {
- /* as little info as is necessary to show relevant info
- * with '+' to denote the frames
- * i.e. HH:MM:SS+FF, MM:SS+FF, SS+FF, or MM:SS
+ /**
+ * As little info as is necessary to show relevant info with '+' to denote the frames
+ * i.e. HH:MM:SS+FF, MM:SS+FF, SS+FF, or MM:SS.
*/
USER_TIMECODE_MINIMAL = 0,
-
- /* reduced SMPTE - (HH:)MM:SS:FF */
+ /** Reduced SMPTE - (HH:)MM:SS:FF */
USER_TIMECODE_SMPTE_MSF = 1,
-
- /* full SMPTE - HH:MM:SS:FF */
+ /** Full SMPTE - HH:MM:SS:FF */
USER_TIMECODE_SMPTE_FULL = 2,
-
- /* milliseconds for sub-frames - HH:MM:SS.sss */
+ /** Milliseconds for sub-frames - HH:MM:SS.sss. */
USER_TIMECODE_MILLISECONDS = 3,
-
- /* seconds only */
+ /** Seconds only. */
USER_TIMECODE_SECONDS_ONLY = 4,
-
- /* Private (not exposed as generic choices) options. */
- /* milliseconds for sub-frames , SubRip format- HH:MM:SS,sss */
+ /**
+ * Private (not exposed as generic choices) options.
+ * milliseconds for sub-frames , SubRip format- HH:MM:SS,sss.
+ */
USER_TIMECODE_SUBRIP = 100,
} eTimecodeStyles;
@@ -1118,15 +1164,14 @@ typedef enum eNdof_Flag {
NDOF_FLY_HELICOPTER = (1 << 1),
NDOF_LOCK_HORIZON = (1 << 2),
- /* the following might not need to be saved between sessions,
- * but they do need to live somewhere accessible... */
+ /* The following might not need to be saved between sessions,
+ * but they do need to live somewhere accessible. */
NDOF_SHOULD_PAN = (1 << 3),
NDOF_SHOULD_ZOOM = (1 << 4),
NDOF_SHOULD_ROTATE = (1 << 5),
- /* orbit navigation modes */
+ /* Orbit navigation modes. */
- /* exposed as Orbit|Explore in the UI */
NDOF_MODE_ORBIT = (1 << 6),
/* actually... users probably don't care about what the mode
@@ -1183,6 +1228,18 @@ typedef enum eUserpref_FactorDisplay {
USER_FACTOR_AS_PERCENTAGE = 1,
} eUserpref_FactorDisplay;
+typedef enum eUserpref_RenderDisplayType {
+ USER_RENDER_DISPLAY_NONE = 0,
+ USER_RENDER_DISPLAY_SCREEN = 1,
+ USER_RENDER_DISPLAY_AREA = 2,
+ USER_RENDER_DISPLAY_WINDOW = 3
+} eUserpref_RenderDisplayType;
+
+typedef enum eUserpref_TempSpaceDisplayType {
+ USER_TEMP_SPACE_DISPLAY_FULLSCREEN,
+ USER_TEMP_SPACE_DISPLAY_WINDOW,
+} eUserpref_TempSpaceDisplayType;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_vec_defaults.h b/source/blender/makesdna/DNA_vec_defaults.h
new file mode 100644
index 00000000000..7242f5ab114
--- /dev/null
+++ b/source/blender/makesdna/DNA_vec_defaults.h
@@ -0,0 +1,55 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_VEC_DEFAULTS_H__
+#define __DNA_VEC_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Generic Defaults
+ * \{ */
+
+/** See #unit_m4. */
+#define _DNA_DEFAULT_UNIT_M4 \
+ { \
+ {1, 0, 0, 0}, \
+ {0, 1, 0, 0}, \
+ {0, 0, 1, 0}, \
+ {0, 0, 0, 1}, \
+ }
+
+#define _DNA_DEFAULT_UNIT_M3 \
+ { \
+ {1, 0, 0}, \
+ {0, 1, 0}, \
+ {0, 0, 1}, \
+ }
+
+/** See #unit_qt. */
+#define _DNA_DEFAULT_UNIT_QT \
+ {1, 0, 0, 0}
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_VEC_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_view3d_defaults.h b/source/blender/makesdna/DNA_view3d_defaults.h
new file mode 100644
index 00000000000..365b1993d80
--- /dev/null
+++ b/source/blender/makesdna/DNA_view3d_defaults.h
@@ -0,0 +1,116 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_VIEW3D_DEFAULTS_H__
+#define __DNA_VIEW3D_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Viewport Struct
+ * \{ */
+
+#define _DNA_DEFAULT_View3DShading \
+ { \
+ .type = OB_SOLID, \
+ .prev_type = OB_SOLID, \
+ .flag = V3D_SHADING_SPECULAR_HIGHLIGHT | V3D_SHADING_XRAY_WIREFRAME | \
+ V3D_SHADING_SCENE_LIGHTS_RENDER | V3D_SHADING_SCENE_WORLD_RENDER, \
+ .light = V3D_LIGHTING_STUDIO, \
+ .shadow_intensity = 0.5f, \
+ .xray_alpha = 0.5f, \
+ .xray_alpha_wire = 0.5f, \
+ .cavity_valley_factor = 1.0f, \
+ .cavity_ridge_factor = 1.0f, \
+ .cavity_type = V3D_SHADING_CAVITY_CURVATURE, \
+ .curvature_ridge_factor = 1.0f, \
+ .curvature_valley_factor = 1.0f, \
+ .single_color = {0.8f, 0.8f, 0.8f}, \
+ .background_color = {0.05f, 0.05f, 0.05f}, \
+ .studiolight_intensity = 1.0f, \
+ }
+
+#define _DNA_DEFAULT_View3DOverlay \
+ { \
+ .wireframe_threshold = 1.0f, \
+ .xray_alpha_bone = 0.5f, \
+ .texture_paint_mode_opacity = 1.0f, \
+ .weight_paint_mode_opacity = 1.0f, \
+ .vertex_paint_mode_opacity = 1.0f, \
+ /* Intentionally different to vertex/paint mode, \
+ * we typically want to see shading too. */ \
+ .sculpt_mode_mask_opacity = 0.75f, \
+ \
+ .edit_flag = V3D_OVERLAY_EDIT_FACES | V3D_OVERLAY_EDIT_SEAMS | \
+ V3D_OVERLAY_EDIT_SHARP | V3D_OVERLAY_EDIT_FREESTYLE_EDGE | \
+ V3D_OVERLAY_EDIT_FREESTYLE_FACE | V3D_OVERLAY_EDIT_EDGES | \
+ V3D_OVERLAY_EDIT_CREASES | V3D_OVERLAY_EDIT_BWEIGHTS | \
+ V3D_OVERLAY_EDIT_CU_HANDLES | V3D_OVERLAY_EDIT_CU_NORMALS, \
+ \
+ .gpencil_paper_opacity = 0.5f, \
+ .gpencil_grid_opacity = 0.9f, \
+ }
+
+#define _DNA_DEFAULT_View3DCursor \
+ { \
+ .rotation_mode = ROT_MODE_XYZ, \
+ .rotation_quaternion = {1, 0, 0, 0}, \
+ .rotation_axis = {0, 1, 0}, \
+ }
+
+#define _DNA_DEFAULT_View3D \
+ { \
+ .spacetype = SPACE_VIEW3D, \
+ .scenelock = true, \
+ .grid = 1.0f, \
+ .gridlines = 16, \
+ .gridsubdiv = 10, \
+ .shading = _DNA_DEFAULT_View3DShading, \
+ .overlay = _DNA_DEFAULT_View3DOverlay, \
+ \
+ .gridflag = V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_FLOOR | V3D_SHOW_ORTHO_GRID, \
+ \
+ .flag = V3D_SELECT_OUTLINE, \
+ .flag2 = V3D_SHOW_RECONSTRUCTION | V3D_SHOW_ANNOTATION, \
+ \
+ .lens = 50.0f, \
+ .clip_start = 0.01f, \
+ .clip_end = 1000.0f, \
+ \
+ .bundle_size = 0.2f, \
+ .bundle_drawtype = OB_PLAINAXES, \
+ \
+ /* stereo */ \
+ .stereo3d_camera = STEREO_3D_ID, \
+ .stereo3d_flag = V3D_S3D_DISPPLANE, \
+ .stereo3d_convergence_alpha = 0.15f, \
+ .stereo3d_volume_alpha = 0.05f, \
+ \
+ /* Grease pencil settings. */ \
+ .vertex_opacity = 1.0f, \
+ .gp_flag = V3D_GP_SHOW_EDIT_LINES, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_VIEW3D_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 51655790fbd..283c361cc56 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -152,7 +152,7 @@ typedef struct View3DShading {
char background_type;
char cavity_type;
char wire_color_type;
- char _pad[6];
+ char _pad[2];
/** FILE_MAXFILE. */
char studio_light[256];
@@ -166,6 +166,7 @@ typedef struct View3DShading {
float studiolight_rot_z;
float studiolight_background;
+ float studiolight_intensity;
float object_outline_color[3];
float xray_alpha;
@@ -179,6 +180,7 @@ typedef struct View3DShading {
float curvature_ridge_factor;
float curvature_valley_factor;
+ struct IDProperty *prop;
} View3DShading;
/** 3D Viewport Overlay settings. */
@@ -264,6 +266,8 @@ typedef struct View3D {
unsigned short local_view_uuid;
char _pad6[2];
int layact DNA_DEPRECATED;
+ unsigned short local_collections_uuid;
+ short _pad7[3];
/** Optional bool for 3d cursor to define center. */
short ob_centre_cursor;
@@ -327,7 +331,7 @@ typedef struct View3D {
#define V3D_S3D_DISPVOLUME (1 << 2)
/** #View3D.flag */
-#define V3D_FLAG_UNUSED_0 (1 << 0) /* cleared */
+#define V3D_LOCAL_COLLECTIONS (1 << 0)
#define V3D_FLAG_UNUSED_1 (1 << 1) /* cleared */
#define V3D_HIDE_HELPLINES (1 << 2)
#define V3D_INVALID_BACKBUF (1 << 3)
@@ -347,6 +351,7 @@ typedef struct View3D {
#define RV3D_CLIPPING (1 << 2)
#define RV3D_NAVIGATING (1 << 3)
#define RV3D_GPULIGHT_UPDATE (1 << 4)
+#define RV3D_PAINTING (1 << 5)
/*#define RV3D_IS_GAME_ENGINE (1 << 5) */ /* UNUSED */
/**
* Disable zbuffer offset, skip calls to #ED_view3d_polygon_offset.
@@ -394,8 +399,9 @@ typedef struct View3D {
#define V3D_GP_SHOW_GRID (1 << 1) /* Activate paper grid */
#define V3D_GP_SHOW_EDIT_LINES (1 << 2)
#define V3D_GP_SHOW_MULTIEDIT_LINES (1 << 3)
-#define V3D_GP_SHOW_ONION_SKIN (1 << 4) /* main switch at view level */
-#define V3D_GP_FADE_NOACTIVE_LAYERS (1 << 5) /* fade layers not active */
+#define V3D_GP_SHOW_ONION_SKIN (1 << 4) /* main switch at view level */
+#define V3D_GP_FADE_NOACTIVE_LAYERS (1 << 5) /* fade layers not active */
+#define V3D_GP_FADE_NOACTIVE_GPENCIL (1 << 6) /* Fade other GPencil objects */
/** #View3DShading.light */
enum {
@@ -418,6 +424,8 @@ enum {
V3D_SHADING_WORLD_ORIENTATION = (1 << 9),
V3D_SHADING_BACKFACE_CULLING = (1 << 10),
V3D_SHADING_DEPTH_OF_FIELD = (1 << 11),
+ V3D_SHADING_SCENE_LIGHTS_RENDER = (1 << 12),
+ V3D_SHADING_SCENE_WORLD_RENDER = (1 << 13),
};
/** #View3DShading.color_type */
diff --git a/source/blender/makesdna/DNA_world_defaults.h b/source/blender/makesdna/DNA_world_defaults.h
new file mode 100644
index 00000000000..c4d934381b4
--- /dev/null
+++ b/source/blender/makesdna/DNA_world_defaults.h
@@ -0,0 +1,49 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_WORLD_DEFAULTS_H__
+#define __DNA_WORLD_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name World Struct
+ * \{ */
+
+#define _DNA_DEFAULT_World \
+ { \
+ .horr = 0.05f, \
+ .horg = 0.05f, \
+ .horb = 0.05f, \
+ \
+ .aodist = 10.0f, \
+ .aoenergy = 1.0f, \
+ \
+ .preview = NULL, \
+ .miststa = 5.0f, \
+ .mistdist = 25.0f, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_WORLD_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt
index 178ef219c4d..bca27442e65 100644
--- a/source/blender/makesdna/intern/CMakeLists.txt
+++ b/source/blender/makesdna/intern/CMakeLists.txt
@@ -77,7 +77,7 @@ add_custom_command(
# -----------------------------------------------------------------------------
# Build bf_dna library
set(INC
-
+ ${CMAKE_CURRENT_BINARY_DIR}
)
set(INC_SYS
@@ -85,6 +85,7 @@ set(INC_SYS
)
set(SRC
+ dna_defaults.c
dna_genfile.c
dna_utils.c
${CMAKE_CURRENT_BINARY_DIR}/dna.c
@@ -126,6 +127,24 @@ set(SRC
../../blenlib/intern/endian_switch.c
../../blenlib/intern/hash_mm2a.c
../../blenlib/intern/listbase.c
+
+ ../DNA_brush_defaults.h
+ ../DNA_cachefile_defaults.h
+ ../DNA_camera_defaults.h
+ ../DNA_curve_defaults.h
+ ../DNA_image_defaults.h
+ ../DNA_lattice_defaults.h
+ ../DNA_light_defaults.h
+ ../DNA_lightprobe_defaults.h
+ ../DNA_linestyle_defaults.h
+ ../DNA_material_defaults.h
+ ../DNA_mesh_defaults.h
+ ../DNA_meta_defaults.h
+ ../DNA_object_defaults.h
+ ../DNA_scene_defaults.h
+ ../DNA_texture_defaults.h
+ ../DNA_vec_defaults.h
+ ../DNA_view3d_defaults.h
)
set(LIB
diff --git a/source/blender/makesdna/intern/dna_defaults.c b/source/blender/makesdna/intern/dna_defaults.c
new file mode 100644
index 00000000000..260f1cd20f6
--- /dev/null
+++ b/source/blender/makesdna/intern/dna_defaults.c
@@ -0,0 +1,273 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * DNA default value access.
+ */
+
+/** \file
+ * \ingroup DNA
+ *
+ * This API provides direct access to DNA default structs
+ * to avoid duplicating values for initialization, versioning and RNA.
+ * This allows DNA default definitions to be defined in a single header along side the types.
+ * So each `DNA_{name}_types.h` can have an optional `DNA_{name}_defaults.h` file along side it.
+ *
+ * Defining the defaults is optional since it doesn't make sense for some structs to have defaults.
+ *
+ * To create these defaults there is a GDB script which can be handy to get started:
+ * `./source/tools/utils/gdb_struct_repr_c99.py`
+ *
+ * Magic numbers should be replaced with flags before committing.
+ *
+ * The main functions to access these are:
+ * - #DNA_struct_default_get
+ * - #DNA_struct_default_alloc
+ *
+ * These access the struct table #DNA_default_table using the struct number.
+ *
+ * \note Struct members only define their members (pointers are left as NULL set).
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_endian_switch.h"
+#include "BLI_memarena.h"
+#include "BLI_math.h"
+
+#include "DNA_defaults.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_cachefile_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_image_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_light_types.h"
+#include "DNA_lightprobe_types.h"
+#include "DNA_linestyle_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_speaker_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_world_types.h"
+
+#include "DNA_brush_defaults.h"
+#include "DNA_cachefile_defaults.h"
+#include "DNA_camera_defaults.h"
+#include "DNA_curve_defaults.h"
+#include "DNA_image_defaults.h"
+#include "DNA_lattice_defaults.h"
+#include "DNA_light_defaults.h"
+#include "DNA_lightprobe_defaults.h"
+#include "DNA_linestyle_defaults.h"
+#include "DNA_material_defaults.h"
+#include "DNA_mesh_defaults.h"
+#include "DNA_meta_defaults.h"
+#include "DNA_object_defaults.h"
+#include "DNA_scene_defaults.h"
+#include "DNA_speaker_defaults.h"
+#include "DNA_texture_defaults.h"
+#include "DNA_world_defaults.h"
+
+#define SDNA_DEFAULT_DECL_STRUCT(struct_name) \
+ static const struct_name DNA_DEFAULT_##struct_name = _DNA_DEFAULT_##struct_name
+
+/* DNA_brush_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Brush);
+
+/* DNA_cachefile_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(CacheFile);
+
+/* DNA_camera_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Camera);
+
+/* DNA_curve_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Curve);
+
+/* DNA_image_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Image);
+
+/* DNA_lattice_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Lattice);
+
+/* DNA_light_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Light);
+
+/* DNA_lightprobe_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(LightProbe);
+
+/* DNA_linestyle_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(FreestyleLineStyle);
+
+/* DNA_material_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Material);
+
+/* DNA_mesh_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Mesh);
+
+/* DNA_meta_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(MetaBall);
+
+/* DNA_object_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Object);
+
+/* DNA_scene_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Scene);
+SDNA_DEFAULT_DECL_STRUCT(ToolSettings);
+
+/* DNA_speaker_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Speaker);
+
+/* DNA_texture_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Tex);
+
+/* DNA_view3d_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(View3D);
+
+/* DNA_world_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(World);
+
+#undef SDNA_DEFAULT_DECL_STRUCT
+
+/* Reuse existing definitions. */
+extern const struct UserDef U_default;
+#define DNA_DEFAULT_UserDef U_default
+
+extern const bTheme U_theme_default;
+#define DNA_DEFAULT_bTheme U_theme_default
+
+/**
+ * Prevent assigning the wrong struct types since all elements in #DNA_default_table are `void *`.
+ */
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+# define SDNA_TYPE_CHECKED(v, t) (&(v) + (_Generic((v), t : 0)))
+#else
+# define SDNA_TYPE_CHECKED(v, t) (&(v))
+#endif
+
+#define SDNA_DEFAULT_DECL(struct_name) \
+ [SDNA_TYPE_FROM_STRUCT(struct_name)] = SDNA_TYPE_CHECKED(DNA_DEFAULT_##struct_name, struct_name)
+
+#define SDNA_DEFAULT_DECL_EX(struct_name, struct_path) \
+ [SDNA_TYPE_FROM_STRUCT(struct_name)] = SDNA_TYPE_CHECKED(DNA_DEFAULT_##struct_path, struct_name)
+
+/** Keep headers sorted. */
+const void *DNA_default_table[SDNA_TYPE_MAX] = {
+
+ /* DNA_brush_defaults.h */
+ SDNA_DEFAULT_DECL(Brush),
+
+ /* DNA_cachefile_defaults.h */
+ SDNA_DEFAULT_DECL(CacheFile),
+
+ /* DNA_camera_defaults.h */
+ SDNA_DEFAULT_DECL(Camera),
+ SDNA_DEFAULT_DECL_EX(CameraDOFSettings, Camera.dof),
+ SDNA_DEFAULT_DECL_EX(CameraStereoSettings, Camera.stereo),
+
+ /* DNA_curve_defaults.h */
+ SDNA_DEFAULT_DECL(Curve),
+
+ /* DNA_image_defaults.h */
+ SDNA_DEFAULT_DECL(Image),
+
+ /* DNA_lattice_defaults.h */
+ SDNA_DEFAULT_DECL(Lattice),
+
+ /* DNA_light_defaults.h */
+ SDNA_DEFAULT_DECL(Light),
+
+ /* DNA_lightprobe_defaults.h */
+ SDNA_DEFAULT_DECL(LightProbe),
+
+ /* DNA_linestyle_defaults.h */
+ SDNA_DEFAULT_DECL(FreestyleLineStyle),
+
+ /* DNA_material_defaults.h */
+ SDNA_DEFAULT_DECL(Material),
+
+ /* DNA_mesh_defaults.h */
+ SDNA_DEFAULT_DECL(Mesh),
+
+ /* DNA_meta_defaults.h */
+ SDNA_DEFAULT_DECL(MetaBall),
+
+ /* DNA_object_defaults.h */
+ SDNA_DEFAULT_DECL(Object),
+
+ /* DNA_scene_defaults.h */
+ SDNA_DEFAULT_DECL(Scene),
+ SDNA_DEFAULT_DECL_EX(RenderData, Scene.r),
+ SDNA_DEFAULT_DECL_EX(ImageFormatData, Scene.r.im_format),
+ SDNA_DEFAULT_DECL_EX(BakeData, Scene.r.bake),
+ SDNA_DEFAULT_DECL_EX(FFMpegCodecData, Scene.r.ffcodecdata),
+ SDNA_DEFAULT_DECL_EX(DisplaySafeAreas, Scene.safe_areas),
+ SDNA_DEFAULT_DECL_EX(AudioData, Scene.audio),
+ SDNA_DEFAULT_DECL_EX(PhysicsSettings, Scene.physics_settings),
+ SDNA_DEFAULT_DECL_EX(SceneDisplay, Scene.display),
+ SDNA_DEFAULT_DECL_EX(SceneEEVEE, Scene.eevee),
+
+ SDNA_DEFAULT_DECL(ToolSettings),
+ SDNA_DEFAULT_DECL_EX(CurvePaintSettings, ToolSettings.curve_paint_settings),
+ SDNA_DEFAULT_DECL_EX(ImagePaintSettings, ToolSettings.imapaint),
+ SDNA_DEFAULT_DECL_EX(ParticleEditSettings, ToolSettings.particle),
+ SDNA_DEFAULT_DECL_EX(ParticleBrushData, ToolSettings.particle.brush[0]),
+ SDNA_DEFAULT_DECL_EX(MeshStatVis, ToolSettings.statvis),
+ SDNA_DEFAULT_DECL_EX(GP_Sculpt_Settings, ToolSettings.gp_sculpt),
+ SDNA_DEFAULT_DECL_EX(GP_Sculpt_Guide, ToolSettings.gp_sculpt.guide),
+
+ /* DNA_speaker_defaults.h */
+ SDNA_DEFAULT_DECL(Speaker),
+
+ /* DNA_texture_defaults.h */
+ SDNA_DEFAULT_DECL(Tex),
+ SDNA_DEFAULT_DECL_EX(MTex, Brush.mtex),
+
+ /* DNA_userdef_types.h */
+ SDNA_DEFAULT_DECL(UserDef),
+ SDNA_DEFAULT_DECL(bTheme),
+ SDNA_DEFAULT_DECL_EX(UserDef_SpaceData, UserDef.space_data),
+ SDNA_DEFAULT_DECL_EX(UserDef_FileSpaceData, UserDef.file_space_data),
+ SDNA_DEFAULT_DECL_EX(WalkNavigation, UserDef.walk_navigation),
+
+ /* DNA_view3d_defaults.h */
+ SDNA_DEFAULT_DECL(View3D),
+ SDNA_DEFAULT_DECL_EX(View3DOverlay, View3D.overlay),
+ SDNA_DEFAULT_DECL_EX(View3DShading, View3D.shading),
+ SDNA_DEFAULT_DECL_EX(View3DCursor, Scene.cursor),
+
+ /* DNA_world_defaults.h */
+ SDNA_DEFAULT_DECL(World),
+};
+#undef SDNA_DEFAULT_DECL
+#undef SDNA_DEFAULT_DECL_EX
+
+char *_DNA_struct_default_alloc_impl(const char *data_src, size_t size, const char *alloc_str)
+{
+ char *data_dst = MEM_mallocN(size, alloc_str);
+ memcpy(data_dst, data_src, size);
+ return data_dst;
+}
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index 86ba306fc6a..6b3095c7925 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -184,7 +184,7 @@ static bool ispointer(const char *name)
* \param name: Index into sdna->names,
* needed to extract possible pointer/array information.
*/
-static int elementsize(const SDNA *sdna, short type, short name)
+int DNA_elem_size_nr(const SDNA *sdna, short type, short name)
{
int len;
const char *cp = sdna->names[name];
@@ -1059,7 +1059,7 @@ static const char *find_elem(const SDNA *sdna,
otype = sdna->types[old[0]];
oname = sdna->names[old[1]];
- len = elementsize(sdna, old[0], old[1]);
+ len = DNA_elem_size_nr(sdna, old[0], old[1]);
if (elem_strcmp(name, oname) == 0) { /* name equal */
if (strcmp(type, otype) == 0) { /* type equal */
@@ -1102,7 +1102,7 @@ static void reconstruct_elem(const SDNA *newsdna,
* - cast type
* - name partially equal (array differs)
* - type equal: memcpy
- * - types casten
+ * - type cast (per element).
* (nzc 2-4-2001 I want the 'unsigned' bit to be parsed as well. Where
* can I force this?)
*/
@@ -1128,7 +1128,7 @@ static void reconstruct_elem(const SDNA *newsdna,
const int old_name_nr = old[1];
otype = oldsdna->types[old[0]];
oname = oldsdna->names[old[1]];
- len = elementsize(oldsdna, old[0], old[1]);
+ len = DNA_elem_size_nr(oldsdna, old[0], old[1]);
if (strcmp(name, oname) == 0) { /* name equal */
@@ -1247,7 +1247,7 @@ static void reconstruct_struct(const SDNA *newsdna,
type = newsdna->types[spc[0]];
name = newsdna->names[spc[1]];
- elen = elementsize(newsdna, spc[0], spc[1]);
+ elen = DNA_elem_size_nr(newsdna, spc[0], spc[1]);
/* Skip pad bytes which must start with '_pad', see makesdna.c 'is_name_legal'.
* for exact rules. Note that if we fail to skip a pad byte it's harmless,
@@ -1269,7 +1269,7 @@ static void reconstruct_struct(const SDNA *newsdna,
mul = newsdna->names_array_len[spc[1]];
mulo = oldsdna->names_array_len[sppo[1]];
- eleno = elementsize(oldsdna, sppo[0], sppo[1]);
+ eleno = DNA_elem_size_nr(oldsdna, sppo[0], sppo[1]);
elen /= mul;
eleno /= mulo;
@@ -1333,8 +1333,8 @@ void DNA_struct_switch_endian(const SDNA *oldsdna, int oldSDNAnr, char *data)
name = oldsdna->names[spc[1]];
const int old_name_array_len = oldsdna->names_array_len[spc[1]];
- /* elementsize = including arraysize */
- elen = elementsize(oldsdna, spc[0], spc[1]);
+ /* DNA_elem_size_nr = including arraysize */
+ elen = DNA_elem_size_nr(oldsdna, spc[0], spc[1]);
/* test: is type a struct? */
if (spc[0] >= firststructtypenr && !ispointer(name)) {
@@ -1639,6 +1639,8 @@ static void sdna_expand_names(SDNA *sdna)
names_expand_len += sp[1];
}
const char **names_expand = MEM_mallocN(sizeof(*names_expand) * names_expand_len, __func__);
+ short *names_array_len_expand = MEM_mallocN(sizeof(*names_array_len_expand) * names_expand_len,
+ __func__);
int names_expand_index = 0;
for (int struct_nr = 0; struct_nr < sdna->structs_len; struct_nr++) {
@@ -1652,6 +1654,7 @@ static void sdna_expand_names(SDNA *sdna)
sp_expand += 2;
for (int i = 0; i < names_len; i++, sp += 2, sp_expand += 2) {
names_expand[names_expand_index] = sdna->names[sp[1]];
+ names_array_len_expand[names_expand_index] = sdna->names_array_len[sp[1]];
BLI_assert(names_expand_index < SHRT_MAX);
sp_expand[1] = names_expand_index;
names_expand_index++;
@@ -1659,6 +1662,10 @@ static void sdna_expand_names(SDNA *sdna)
}
MEM_freeN((void *)sdna->names);
sdna->names = names_expand;
+
+ MEM_freeN((void *)sdna->names_array_len);
+ sdna->names_array_len = names_array_len_expand;
+
sdna->names_len = names_expand_len;
}
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index f03aacf8dbd..cefc5aded7c 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -392,6 +392,7 @@ extern StructRNA RNA_Mesh;
extern StructRNA RNA_MeshCacheModifier;
extern StructRNA RNA_MeshColor;
extern StructRNA RNA_MeshColorLayer;
+extern StructRNA RNA_MeshLoopColor;
extern StructRNA RNA_MeshDeformModifier;
extern StructRNA RNA_MeshEdge;
extern StructRNA RNA_MeshFloatProperty;
@@ -412,6 +413,7 @@ extern StructRNA RNA_MeshTextureFace;
extern StructRNA RNA_MeshTextureFaceLayer;
extern StructRNA RNA_MeshTexturePoly;
extern StructRNA RNA_MeshTexturePolyLayer;
+extern StructRNA RNA_MeshUVLoop;
extern StructRNA RNA_MeshVertex;
extern StructRNA RNA_MessageSensor;
extern StructRNA RNA_MetaBall;
@@ -1151,24 +1153,37 @@ struct PropertyElemRNA {
};
bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, struct ListBase *r_elements);
+struct ID *RNA_find_real_ID_and_path(struct Main *bmain, struct ID *id, const char **r_path);
+
char *RNA_path_from_ID_to_struct(PointerRNA *ptr);
+
+char *RNA_path_from_real_ID_to_struct(struct Main *bmain, PointerRNA *ptr, struct ID **r_real);
+
char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop);
char *RNA_path_from_ID_to_property_index(PointerRNA *ptr,
PropertyRNA *prop,
int array_dim,
int index);
+char *RNA_path_from_real_ID_to_property_index(struct Main *bmain,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ int array_dim,
+ int index,
+ struct ID **r_real_id);
+
char *RNA_path_resolve_from_type_to_property(struct PointerRNA *ptr,
struct PropertyRNA *prop,
const struct StructRNA *type);
-char *RNA_path_full_ID_py(struct ID *id);
-char *RNA_path_full_struct_py(struct PointerRNA *ptr);
-char *RNA_path_full_property_py_ex(PointerRNA *ptr,
- PropertyRNA *prop,
- int index,
- bool use_fallback);
-char *RNA_path_full_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
+char *RNA_path_full_ID_py(struct Main *bmain, struct ID *id);
+char *RNA_path_full_struct_py(struct Main *bmain, struct PointerRNA *ptr);
+char *RNA_path_full_property_py_ex(
+ struct Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback);
+char *RNA_path_full_property_py(struct Main *bmain,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ int index);
char *RNA_path_struct_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
char *RNA_path_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index 02aaef44a1f..e72a55b5a9e 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -91,6 +91,7 @@ extern const EnumPropertyItem rna_enum_beztriple_keyframe_type_items[];
extern const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[];
extern const EnumPropertyItem rna_enum_beztriple_interpolation_easing_items[];
extern const EnumPropertyItem rna_enum_keyframe_handle_type_items[];
+extern const EnumPropertyItem rna_enum_driver_target_rotation_mode_items[];
extern const EnumPropertyItem rna_enum_keyblock_type_items[];
@@ -183,6 +184,7 @@ extern const EnumPropertyItem rna_enum_file_sort_items[];
extern const EnumPropertyItem rna_enum_node_socket_in_out_items[];
extern const EnumPropertyItem rna_enum_node_math_items[];
+extern const EnumPropertyItem rna_enum_mapping_type_items[];
extern const EnumPropertyItem rna_enum_node_vec_math_items[];
extern const EnumPropertyItem rna_enum_node_filter_items[];
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 2745cfa9740..259f656cc8c 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -164,10 +164,19 @@ set(SRC
../../../../intern/guardedalloc/intern/mallocn_guarded_impl.c
../../../../intern/guardedalloc/intern/mallocn_lockfree_impl.c
../../../../intern/guardedalloc/intern/mmap_win.c
+
+ # Needed for defaults.
+ ../../../../release/datafiles/userdef/userdef_default.c
+ ../../../../release/datafiles/userdef/userdef_default_theme.c
)
set(INC
- ../../../../intern/clog
+ ../../../../intern/clog
+
+ # Needed for defaults forward declarations.
+ ../../../blender/blenloader
+
+ ${CMAKE_BINARY_DIR}/source/blender/makesdna/intern
)
set(INC_SYS
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 5aaddc30e07..2d4da942610 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -409,23 +409,30 @@ static void rna_construct_wrapper_function_name(
}
}
+void *rna_alloc_from_buffer(const char *buffer, int buffer_len)
+{
+ AllocDefRNA *alloc = MEM_callocN(sizeof(AllocDefRNA), "AllocDefRNA");
+ alloc->mem = MEM_mallocN(buffer_len, __func__);
+ memcpy(alloc->mem, buffer, buffer_len);
+ rna_addtail(&DefRNA.allocs, alloc);
+ return alloc->mem;
+}
+
+void *rna_calloc(int buffer_len)
+{
+ AllocDefRNA *alloc = MEM_callocN(sizeof(AllocDefRNA), "AllocDefRNA");
+ alloc->mem = MEM_callocN(buffer_len, __func__);
+ rna_addtail(&DefRNA.allocs, alloc);
+ return alloc->mem;
+}
+
static char *rna_alloc_function_name(const char *structname,
const char *propname,
const char *type)
{
- AllocDefRNA *alloc;
char buffer[2048];
- char *result;
-
rna_construct_function_name(buffer, sizeof(buffer), structname, propname, type);
- result = MEM_callocN(sizeof(char) * strlen(buffer) + 1, "rna_alloc_function_name");
- strcpy(result, buffer);
-
- alloc = MEM_callocN(sizeof(AllocDefRNA), "AllocDefRNA");
- alloc->mem = result;
- rna_addtail(&DefRNA.allocs, alloc);
-
- return result;
+ return rna_alloc_from_buffer(buffer, strlen(buffer) + 1);
}
static StructRNA *rna_find_struct(const char *identifier)
@@ -622,8 +629,8 @@ static char *rna_def_property_get_func(
if (prop->type == PROP_FLOAT) {
if (IS_DNATYPE_FLOAT_COMPAT(dp->dnatype) == 0) {
- if (prop->subtype !=
- PROP_COLOR_GAMMA) { /* colors are an exception. these get translated */
+ /* Colors are an exception. these get translated. */
+ if (prop->subtype != PROP_COLOR_GAMMA) {
CLOG_ERROR(&LOG,
"%s.%s is a '%s' but wrapped as type '%s'.",
srna->identifier,
@@ -2532,6 +2539,12 @@ static void rna_def_struct_function_call_impl_cpp(FILE *f, StructRNA *srna, Func
rna_safe_id(dp->prop->identifier));
}
}
+ else if (dp->prop->flag_parameter & PARM_RNAPTR) {
+ fprintf(f,
+ "(::%s *) &%s",
+ rna_parameter_type_name(dp->prop),
+ rna_safe_id(dp->prop->identifier));
+ }
else {
fprintf(f,
"(::%s *) %s.ptr.data",
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 5a4b4a3fa3d..49fdf9c67d5 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -491,13 +491,22 @@ static ID *rna_ID_copy(ID *id, Main *bmain)
return NULL;
}
-static ID *rna_ID_override_create(ID *id, Main *bmain)
+static ID *rna_ID_override_create(ID *id, Main *bmain, bool remap_local_usages)
{
- if (!BKE_override_library_is_enabled() || id->lib == NULL) {
+ if (!BKE_override_library_is_enabled() || !ID_IS_OVERRIDABLE_LIBRARY(id)) {
return NULL;
}
- return BKE_override_library_create_from_id(bmain, id);
+ if (remap_local_usages) {
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, true);
+ }
+
+ ID *local_id = BKE_override_library_create_from_id(bmain, id, remap_local_usages);
+
+ if (remap_local_usages) {
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ }
+ return local_id;
}
static void rna_ID_update_tag(ID *id, Main *bmain, ReportList *reports, int flag)
@@ -1519,6 +1528,12 @@ static void rna_def_ID(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_USE_MAIN);
parm = RNA_def_pointer(func, "id", "ID", "", "New overridden local copy of the ID");
RNA_def_function_return(func, parm);
+ RNA_def_boolean(func,
+ "remap_local_usages",
+ false,
+ "",
+ "Whether local usages of the linked ID should be remapped to the new "
+ "library override of it");
func = RNA_def_function(srna, "user_clear", "rna_ID_user_clear");
RNA_def_function_ui_description(func,
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 8327456f460..71a3be24810 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -41,12 +41,14 @@
#include "BLT_translation.h"
#include "BKE_animsys.h"
+#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_idcode.h"
#include "BKE_idprop.h"
#include "BKE_fcurve.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#include "BKE_node.h"
#include "DEG_depsgraph.h"
@@ -2056,18 +2058,18 @@ int RNA_property_ui_icon(PropertyRNA *prop)
return rna_ensure_property(prop)->icon;
}
-bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop)
+bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop_orig)
{
ID *id = ptr->owner_id;
int flag;
const char *dummy_info;
- prop = rna_ensure_property(prop);
+ PropertyRNA *prop = rna_ensure_property(prop_orig);
flag = prop->editable ? prop->editable(ptr, &dummy_info) : prop->flag;
return ((flag & PROP_EDITABLE) && (flag & PROP_REGISTER) == 0 &&
(!id || ((!ID_IS_LINKED(id) || (prop->flag & PROP_LIB_EXCEPTION)) &&
- (!id->override_library || RNA_property_overridable_get(ptr, prop)))));
+ (!id->override_library || RNA_property_overridable_get(ptr, prop_orig)))));
}
/**
@@ -2079,15 +2081,15 @@ bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char *
ID *id = ptr->owner_id;
int flag;
- prop = rna_ensure_property(prop);
+ PropertyRNA *prop_type = rna_ensure_property(prop);
*r_info = "";
/* get flag */
- if (prop->editable) {
- flag = prop->editable(ptr, r_info);
+ if (prop_type->editable) {
+ flag = prop_type->editable(ptr, r_info);
}
else {
- flag = prop->flag;
+ flag = prop_type->flag;
if ((flag & PROP_EDITABLE) == 0 || (flag & PROP_REGISTER)) {
*r_info = N_("This property is for internal use only and can't be edited");
}
@@ -2095,17 +2097,21 @@ bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char *
/* property from linked data-block */
if (id) {
- if (ID_IS_LINKED(id) && (prop->flag & PROP_LIB_EXCEPTION) == 0) {
+ if (ID_IS_LINKED(id) && (prop_type->flag & PROP_LIB_EXCEPTION) == 0) {
if (!(*r_info)[0]) {
*r_info = N_("Can't edit this property from a linked data-block");
}
return false;
}
- if (id->override_library != NULL && !RNA_property_overridable_get(ptr, prop)) {
- if (!(*r_info)[0]) {
- *r_info = N_("Can't edit this property from an override data-block");
+ if (id->override_library != NULL) {
+ /* We need the real data property in case of IDProperty here... */
+ PropertyRNA *real_prop = rna_ensure_property_realdata(&prop, ptr);
+ if (real_prop == NULL || !RNA_property_overridable_get(ptr, real_prop)) {
+ if (!(*r_info)[0]) {
+ *r_info = N_("Can't edit this property from an override data-block");
+ }
+ return false;
}
- return false;
}
}
@@ -5757,6 +5763,74 @@ static char *rna_path_from_ID_to_idpgroup(PointerRNA *ptr)
}
}
+/**
+ * Find the actual ID pointer and path from it to the given ID.
+ *
+ * \param id: ID reference to search the global owner for.
+ * \param[out] r_path: Path from the real ID to the initial ID.
+ * \return The ID pointer, or NULL in case of failure.
+ */
+ID *RNA_find_real_ID_and_path(Main *bmain, ID *id, const char **r_path)
+{
+ if (r_path) {
+ *r_path = "";
+ }
+
+ if ((id != NULL) && (id->flag & LIB_PRIVATE_DATA)) {
+ switch (GS(id->name)) {
+ case ID_NT:
+ if (r_path) {
+ *r_path = "node_tree";
+ }
+ return BKE_node_tree_find_owner_ID(bmain, (bNodeTree *)id);
+ case ID_GR:
+ if (r_path) {
+ *r_path = "collection";
+ }
+ return (ID *)BKE_collection_master_scene_search(bmain, (Collection *)id);
+
+ default:
+ return NULL;
+ }
+ }
+ else {
+ return id;
+ }
+}
+
+static char *rna_prepend_real_ID_path(Main *bmain, ID *id, char *path, ID **r_real_id)
+{
+ if (r_real_id != NULL) {
+ *r_real_id = NULL;
+ }
+
+ const char *prefix;
+ ID *real_id = RNA_find_real_ID_and_path(bmain, id, &prefix);
+
+ if (r_real_id != NULL) {
+ *r_real_id = real_id;
+ }
+
+ if (path != NULL) {
+ char *new_path = NULL;
+
+ if (real_id) {
+ if (prefix[0]) {
+ new_path = BLI_sprintfN("%s%s%s", prefix, path[0] == '[' ? "" : ".", path);
+ }
+ else {
+ return path;
+ }
+ }
+
+ MEM_freeN(path);
+ return new_path;
+ }
+ else {
+ return prefix[0] != '\0' ? BLI_strdup(prefix) : NULL;
+ }
+}
+
char *RNA_path_from_ID_to_struct(PointerRNA *ptr)
{
char *ptrpath = NULL;
@@ -5799,6 +5873,14 @@ char *RNA_path_from_ID_to_struct(PointerRNA *ptr)
return ptrpath;
}
+char *RNA_path_from_real_ID_to_struct(Main *bmain, PointerRNA *ptr, struct ID **r_real)
+{
+ char *path = RNA_path_from_ID_to_struct(ptr);
+
+ /* NULL path is valid in that case, when given struct is an ID one... */
+ return rna_prepend_real_ID_path(bmain, ptr->owner_id, path, r_real);
+}
+
static void rna_path_array_multi_from_flat_index(const int dimsize[RNA_MAX_ARRAY_LENGTH],
const int totdims,
const int index_dim,
@@ -5905,6 +5987,16 @@ char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop)
return RNA_path_from_ID_to_property_index(ptr, prop, 0, -1);
}
+char *RNA_path_from_real_ID_to_property_index(
+ Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index, ID **r_real_id)
+{
+ char *path = RNA_path_from_ID_to_property_index(ptr, prop, index_dim, index);
+
+ /* NULL path is always an error here, in that case do not return the 'fake ID from real ID' part
+ * of the path either. */
+ return path != NULL ? rna_prepend_real_ID_path(bmain, ptr->owner_id, path, r_real_id) : NULL;
+}
+
/**
* \return the path to given ptr/prop from the closest ancestor of given type,
* if any (else return NULL).
@@ -5951,20 +6043,34 @@ char *RNA_path_resolve_from_type_to_property(PointerRNA *ptr,
* Get the ID as a python representation, eg:
* bpy.data.foo["bar"]
*/
-char *RNA_path_full_ID_py(ID *id)
+char *RNA_path_full_ID_py(Main *bmain, ID *id)
{
+ const char *path;
+ ID *id_real = RNA_find_real_ID_and_path(bmain, id, &path);
+
+ if (id_real) {
+ id = id_real;
+ }
+ else {
+ path = "";
+ }
+
char id_esc[(sizeof(id->name) - 2) * 2];
BLI_strescape(id_esc, id->name + 2, sizeof(id_esc));
- return BLI_sprintfN("bpy.data.%s[\"%s\"]", BKE_idcode_to_name_plural(GS(id->name)), id_esc);
+ return BLI_sprintfN("bpy.data.%s[\"%s\"]%s%s",
+ BKE_idcode_to_name_plural(GS(id->name)),
+ id_esc,
+ path[0] ? "." : "",
+ path);
}
/**
* Get the ID.struct as a python representation, eg:
* bpy.data.foo["bar"].some_struct
*/
-char *RNA_path_full_struct_py(struct PointerRNA *ptr)
+char *RNA_path_full_struct_py(Main *bmain, struct PointerRNA *ptr)
{
char *id_path;
char *data_path;
@@ -5976,7 +6082,7 @@ char *RNA_path_full_struct_py(struct PointerRNA *ptr)
}
/* never fails */
- id_path = RNA_path_full_ID_py(ptr->owner_id);
+ id_path = RNA_path_full_ID_py(bmain, ptr->owner_id);
data_path = RNA_path_from_ID_to_struct(ptr);
@@ -5996,10 +6102,8 @@ char *RNA_path_full_struct_py(struct PointerRNA *ptr)
* Get the ID.struct.property as a python representation, eg:
* bpy.data.foo["bar"].some_struct.some_prop[10]
*/
-char *RNA_path_full_property_py_ex(PointerRNA *ptr,
- PropertyRNA *prop,
- int index,
- bool use_fallback)
+char *RNA_path_full_property_py_ex(
+ Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback)
{
char *id_path;
const char *data_delim;
@@ -6013,7 +6117,7 @@ char *RNA_path_full_property_py_ex(PointerRNA *ptr,
}
/* never fails */
- id_path = RNA_path_full_ID_py(ptr->owner_id);
+ id_path = RNA_path_full_ID_py(bmain, ptr->owner_id);
data_path = RNA_path_from_ID_to_property(ptr, prop);
if (data_path) {
@@ -6046,9 +6150,9 @@ char *RNA_path_full_property_py_ex(PointerRNA *ptr,
return ret;
}
-char *RNA_path_full_property_py(PointerRNA *ptr, PropertyRNA *prop, int index)
+char *RNA_path_full_property_py(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index)
{
- return RNA_path_full_property_py_ex(ptr, prop, index, false);
+ return RNA_path_full_property_py_ex(bmain, ptr, prop, index, false);
}
/**
@@ -6646,16 +6750,16 @@ char *RNA_pointer_as_string_id(bContext *C, PointerRNA *ptr)
return cstring;
}
-static char *rna_pointer_as_string__bldata(PointerRNA *ptr)
+static char *rna_pointer_as_string__bldata(Main *bmain, PointerRNA *ptr)
{
if (ptr->type == NULL || ptr->owner_id == NULL) {
return BLI_strdup("None");
}
else if (RNA_struct_is_ID(ptr->type)) {
- return RNA_path_full_ID_py(ptr->owner_id);
+ return RNA_path_full_ID_py(bmain, ptr->owner_id);
}
else {
- return RNA_path_full_struct_py(ptr);
+ return RNA_path_full_struct_py(bmain, ptr);
}
}
@@ -6672,7 +6776,7 @@ char *RNA_pointer_as_string(bContext *C,
return RNA_pointer_as_string_id(C, ptr_prop);
}
else {
- return rna_pointer_as_string__bldata(ptr_prop);
+ return rna_pointer_as_string__bldata(CTX_data_main(C), ptr_prop);
}
}
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c
index b0a83ea38c6..b061c72157e 100644
--- a/source/blender/makesrna/intern/rna_access_compare_override.c
+++ b/source/blender/makesrna/intern/rna_access_compare_override.c
@@ -76,8 +76,8 @@ bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop)
}
else {
/* If this is a real 'pure' IDProp (aka custom property), we want to use the IDProp flag. */
- return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) &&
- (((IDProperty *)prop)->flag & IDP_FLAG_OVERRIDABLE_LIBRARY);
+ IDProperty *idprop = (IDProperty *)prop;
+ return (idprop->flag & IDP_FLAG_OVERRIDABLE_LIBRARY) != 0;
}
}
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index 6157ec41f19..e1a24326474 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -668,8 +668,7 @@ static FCurve *rna_Driver_new(
return NULL;
}
- short add_mode = 1;
- FCurve *fcu = verify_driver_fcurve(id, rna_path, array_index, add_mode);
+ FCurve *fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_KEYFRAMES);
BLI_assert(fcu != NULL);
DEG_relations_tag_update(bmain);
diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c
index 17a58a61fb5..f539da488ce 100644
--- a/source/blender/makesrna/intern/rna_animviz.c
+++ b/source/blender/makesrna/intern/rna_animviz.c
@@ -144,7 +144,7 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna)
prop = RNA_def_property(srna, "line_thickness", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "line_thickness");
RNA_def_property_range(prop, 1, 6);
- RNA_def_property_ui_text(prop, "Line thickness", "Line thickness for drawing path");
+ RNA_def_property_ui_text(prop, "Line Thickness", "Line thickness for drawing path");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
/* Settings */
@@ -164,7 +164,7 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna)
/* Use custom color */
prop = RNA_def_property(srna, "use_custom_color", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_CUSTOM);
- RNA_def_property_ui_text(prop, "Custom colors", "Use custom color for this motion path");
+ RNA_def_property_ui_text(prop, "Custom Colors", "Use custom color for this motion path");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
/* Draw lines between keyframes */
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index d3bdcf03d4d..4dc383a2460 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -36,6 +36,8 @@
#ifdef RNA_RUNTIME
+# include "BLI_math_vector.h"
+
# include "BKE_action.h"
# include "BKE_context.h"
# include "BKE_global.h"
@@ -303,6 +305,40 @@ static void rna_Bone_layer_set(PointerRNA *ptr, const bool *values)
BKE_armature_refresh_layer_used(arm);
}
+/* TODO: remove the deprecation stubs. */
+static bool rna_use_inherit_scale_get(char inherit_scale_mode)
+{
+ return inherit_scale_mode <= BONE_INHERIT_SCALE_FIX_SHEAR;
+}
+
+static void rna_use_inherit_scale_set(char *inherit_scale_mode, bool value)
+{
+ bool cur_value = (*inherit_scale_mode <= BONE_INHERIT_SCALE_FIX_SHEAR);
+ if (value != cur_value) {
+ *inherit_scale_mode = (value ? BONE_INHERIT_SCALE_FULL : BONE_INHERIT_SCALE_NONE);
+ }
+}
+
+static bool rna_EditBone_use_inherit_scale_get(PointerRNA *ptr)
+{
+ return rna_use_inherit_scale_get(((EditBone *)ptr->data)->inherit_scale_mode);
+}
+
+static void rna_EditBone_use_inherit_scale_set(PointerRNA *ptr, bool value)
+{
+ rna_use_inherit_scale_set(&((EditBone *)ptr->data)->inherit_scale_mode, value);
+}
+
+static bool rna_Bone_use_inherit_scale_get(PointerRNA *ptr)
+{
+ return rna_use_inherit_scale_get(((Bone *)ptr->data)->inherit_scale_mode);
+}
+
+static void rna_Bone_use_inherit_scale_set(PointerRNA *ptr, bool value)
+{
+ rna_use_inherit_scale_set(&((Bone *)ptr->data)->inherit_scale_mode, value);
+}
+
static void rna_Armature_layer_set(PointerRNA *ptr, const bool *values)
{
bArmature *arm = (bArmature *)ptr->data;
@@ -449,6 +485,22 @@ static void rna_EditBone_matrix_set(PointerRNA *ptr, const float *values)
ED_armature_ebone_from_mat4(ebone, (float(*)[4])values);
}
+static float rna_EditBone_length_get(PointerRNA *ptr)
+{
+ EditBone *ebone = (EditBone *)(ptr->data);
+ return len_v3v3(ebone->head, ebone->tail);
+}
+
+static void rna_EditBone_length_set(PointerRNA *ptr, float length)
+{
+ EditBone *ebone = (EditBone *)(ptr->data);
+ float delta[3];
+
+ sub_v3_v3v3(delta, ebone->tail, ebone->head);
+ normalize_v3(delta);
+ madd_v3_v3v3fl(ebone->tail, ebone->head, delta, length);
+}
+
static void rna_Bone_bbone_handle_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bArmature *arm = (bArmature *)ptr->owner_id;
@@ -613,16 +665,19 @@ static void rna_Armature_transform(bArmature *arm, float *mat)
/* Settings for curved bbone settings -
* The posemode values get applied over the top of the editmode ones. */
-void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
+void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone, bool is_editbone)
{
-# define RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone) \
+# define RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone) \
{ \
if (is_posebone) { \
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update"); \
} \
- else { \
+ else if (is_editbone) { \
RNA_def_property_update(prop, 0, "rna_Armature_editbone_transform_update"); \
} \
+ else { \
+ RNA_def_property_update(prop, 0, "rna_Armature_update_data"); \
+ } \
} \
((void)0)
@@ -634,14 +689,14 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
RNA_def_property_ui_range(prop, -M_PI * 2, M_PI * 2, 10, 2);
RNA_def_property_ui_text(
prop, "Roll In", "Roll offset for the start of the B-Bone, adjusts twist");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
prop = RNA_def_property(srna, "bbone_rollout", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "roll2");
RNA_def_property_ui_range(prop, -M_PI * 2, M_PI * 2, 10, 2);
RNA_def_property_ui_text(
prop, "Roll Out", "Roll offset for the end of the B-Bone, adjusts twist");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
if (is_posebone == false) {
prop = RNA_def_property(srna, "use_endroll_as_inroll", PROP_BOOLEAN, PROP_NONE);
@@ -658,28 +713,28 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_ui_text(
prop, "In X", "X-axis handle offset for start of the B-Bone's curve, adjusts curvature");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
prop = RNA_def_property(srna, "bbone_curveiny", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "curve_in_y");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_ui_text(
prop, "In Y", "Y-axis handle offset for start of the B-Bone's curve, adjusts curvature");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
prop = RNA_def_property(srna, "bbone_curveoutx", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "curve_out_x");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_ui_text(
prop, "Out X", "X-axis handle offset for end of the B-Bone's curve, adjusts curvature");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
prop = RNA_def_property(srna, "bbone_curveouty", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "curve_out_y");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_ui_text(
prop, "Out Y", "Y-axis handle offset for end of the B-Bone's curve, adjusts curvature");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
/* Ease In/Out */
prop = RNA_def_property(srna, "bbone_easein", PROP_FLOAT, PROP_NONE);
@@ -687,14 +742,14 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
RNA_def_property_ui_range(prop, -5.0f, 5.0f, 1, 3);
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Ease In", "Length of first Bezier Handle (for B-Bones only)");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
prop = RNA_def_property(srna, "bbone_easeout", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "ease2");
RNA_def_property_ui_range(prop, -5.0f, 5.0f, 1, 3);
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Ease Out", "Length of second Bezier Handle (for B-Bones only)");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
/* Scale In/Out */
prop = RNA_def_property(srna, "bbone_scaleinx", PROP_FLOAT, PROP_NONE);
@@ -706,7 +761,7 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
"Scale In X",
"X-axis scale factor for start of the B-Bone, "
"adjusts thickness (for tapering effects)");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
prop = RNA_def_property(srna, "bbone_scaleiny", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "scale_in_y");
@@ -717,7 +772,7 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
"Scale In Y",
"Y-axis scale factor for start of the B-Bone, "
"adjusts thickness (for tapering effects)");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
prop = RNA_def_property(srna, "bbone_scaleoutx", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "scale_out_x");
@@ -728,7 +783,7 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
"Scale Out X",
"X-axis scale factor for end of the B-Bone, "
"adjusts thickness (for tapering effects)");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
prop = RNA_def_property(srna, "bbone_scaleouty", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "scale_out_y");
@@ -739,7 +794,7 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
"Scale Out Y",
"Y-axis scale factor for end of the B-Bone, "
"adjusts thickness (for tapering effects)");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
# undef RNA_DEF_CURVEBONE_UPDATE
}
@@ -770,6 +825,28 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem prop_inherit_scale_mode[] = {
+ {BONE_INHERIT_SCALE_FULL, "FULL", 0, "Full", "Inherit all effects of parent scaling"},
+ {BONE_INHERIT_SCALE_FIX_SHEAR,
+ "FIX_SHEAR",
+ 0,
+ "Fix Shear",
+ "Inherit scaling, but remove shearing of the child in the rest orientation"},
+ {BONE_INHERIT_SCALE_AVERAGE,
+ "AVERAGE",
+ 0,
+ "Average",
+ "Inherit uniform scaling representing the overall change in the volume of the parent"},
+ {BONE_INHERIT_SCALE_NONE, "NONE", 0, "None", "Completely ignore parent scaling"},
+ {BONE_INHERIT_SCALE_NONE_LEGACY,
+ "NONE_LEGACY",
+ 0,
+ "None (Legacy)",
+ "Ignore parent scaling without compensating for parent shear. "
+ "Replicates the effect of disabling the original Inherit Scale checkbox"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
PropertyRNA *prop;
/* strings */
@@ -829,9 +906,25 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
RNA_def_property_ui_text(prop, "Deform", "Enable Bone to deform geometry");
RNA_def_property_update(prop, 0, "rna_Armature_update_data");
+ prop = RNA_def_property(srna, "inherit_scale", PROP_ENUM, PROP_NONE);
+ RNA_def_property_ui_text(
+ prop, "Inherit Scale", "Specifies how the bone inherits scaling from the parent bone");
+ RNA_def_property_enum_sdna(prop, NULL, "inherit_scale_mode");
+ RNA_def_property_enum_items(prop, prop_inherit_scale_mode);
+ RNA_def_property_update(prop, 0, "rna_Armature_update_data");
+
+ /* TODO: remove the compatibility stub. */
prop = RNA_def_property(srna, "use_inherit_scale", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_ui_text(prop, "Inherit Scale", "Bone inherits scaling from parent bone");
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", BONE_NO_SCALE);
+ RNA_def_property_ui_text(
+ prop, "Inherit Scale", "DEPRECATED: Bone inherits scaling from parent bone");
+ if (editbone) {
+ RNA_def_property_boolean_funcs(
+ prop, "rna_EditBone_use_inherit_scale_get", "rna_EditBone_use_inherit_scale_set");
+ }
+ else {
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Bone_use_inherit_scale_get", "rna_Bone_use_inherit_scale_set");
+ }
RNA_def_property_update(prop, 0, "rna_Armature_update_data");
prop = RNA_def_property(srna, "use_local_location", PROP_BOOLEAN, PROP_NONE);
@@ -1030,7 +1123,7 @@ static void rna_def_bone(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Children", "Bones which are children of this bone");
rna_def_bone_common(srna, 0);
- rna_def_bone_curved_common(srna, 0);
+ rna_def_bone_curved_common(srna, false, false);
/* XXX should we define this in PoseChannel wrapping code instead?
* But PoseChannels directly get some of their flags from here... */
@@ -1066,27 +1159,28 @@ static void rna_def_bone(BlenderRNA *brna)
prop = RNA_def_property(srna, "matrix", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_float_sdna(prop, NULL, "bone_mat");
RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_3x3);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Bone Matrix", "3x3 bone matrix");
prop = RNA_def_property(srna, "matrix_local", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_float_sdna(prop, NULL, "arm_mat");
RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "Bone Armature-Relative Matrix", "4x4 bone matrix relative to armature");
prop = RNA_def_property(srna, "tail", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "tail");
RNA_def_property_array(prop, 3);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Tail", "Location of tail end of the bone");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(
+ prop, "Tail", "Location of tail end of the bone relative to its parent");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
prop = RNA_def_property(srna, "tail_local", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "arm_tail");
RNA_def_property_array(prop, 3);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "Armature-Relative Tail", "Location of tail end of the bone relative to armature");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
@@ -1094,7 +1188,7 @@ static void rna_def_bone(BlenderRNA *brna)
prop = RNA_def_property(srna, "head", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "head");
RNA_def_property_array(prop, 3);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "Head", "Location of head end of the bone relative to its parent");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
@@ -1102,11 +1196,16 @@ static void rna_def_bone(BlenderRNA *brna)
prop = RNA_def_property(srna, "head_local", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "arm_head");
RNA_def_property_array(prop, 3);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "Armature-Relative Head", "Location of head end of the bone relative to armature");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
+ prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "length");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Length", "Length of the bone");
+
RNA_api_bone(srna);
}
@@ -1152,8 +1251,16 @@ static void rna_def_edit_bone(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, 0, "rna_Armature_editbone_transform_update");
+ prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_funcs(prop, "rna_EditBone_length_get", "rna_EditBone_length_set", NULL);
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
+ RNA_def_property_ui_text(prop, "Length", "Length of the bone. Changing moves the tail end");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_Armature_editbone_transform_update");
+
rna_def_bone_common(srna, 1);
- rna_def_bone_curved_common(srna, 0);
+ rna_def_bone_curved_common(srna, false, true);
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_HIDDEN_A);
diff --git a/source/blender/makesrna/intern/rna_armature_api.c b/source/blender/makesrna/intern/rna_armature_api.c
index f3bdef75c9c..2b60dbde39f 100644
--- a/source/blender/makesrna/intern/rna_armature_api.c
+++ b/source/blender/makesrna/intern/rna_armature_api.c
@@ -71,14 +71,15 @@ static void rna_Bone_convert_local_to_pose(Bone *bone,
if (is_zero_m4(parent_pose_mat) || is_zero_m4(parent_arm_mat)) {
/* No parent case. */
- BKE_bone_parent_transform_calc_from_matrices(bone->flag, bone_arm_mat, NULL, NULL, &bpt);
+ BKE_bone_parent_transform_calc_from_matrices(
+ bone->flag, bone->inherit_scale_mode, bone_arm_mat, NULL, NULL, &bpt);
}
else {
invert_m4_m4(offs_bone, parent_arm_mat);
mul_m4_m4m4(offs_bone, offs_bone, bone_arm_mat);
BKE_bone_parent_transform_calc_from_matrices(
- bone->flag, offs_bone, parent_arm_mat, parent_pose_mat, &bpt);
+ bone->flag, bone->inherit_scale_mode, offs_bone, parent_arm_mat, parent_pose_mat, &bpt);
}
if (invert) {
diff --git a/source/blender/makesrna/intern/rna_boid.c b/source/blender/makesrna/intern/rna_boid.c
index 722b7b12271..01d1d1ddddb 100644
--- a/source/blender/makesrna/intern/rna_boid.c
+++ b/source/blender/makesrna/intern/rna_boid.c
@@ -355,7 +355,7 @@ static void rna_def_boidrule_avoid(BlenderRNA *brna)
prop = RNA_def_property(srna, "fear_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0f, 100.0f);
RNA_def_property_ui_text(
- prop, "Fear factor", "Avoid object if danger from it is above this threshold");
+ prop, "Fear Factor", "Avoid object if danger from it is above this threshold");
RNA_def_property_update(prop, 0, "rna_Boids_reset");
}
@@ -379,7 +379,7 @@ static void rna_def_boidrule_avoid_collision(BlenderRNA *brna)
prop = RNA_def_property(srna, "look_ahead", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0f, 100.0f);
- RNA_def_property_ui_text(prop, "Look ahead", "Time to look ahead in seconds");
+ RNA_def_property_ui_text(prop, "Look Ahead", "Time to look ahead in seconds");
RNA_def_property_update(prop, 0, "rna_Boids_reset");
}
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 15602599e4e..d7bb941b266 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -70,6 +70,7 @@ static const EnumPropertyItem sculpt_stroke_method_items[] = {
const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
{SCULPT_TOOL_DRAW, "DRAW", ICON_BRUSH_SCULPT_DRAW, "Draw", ""},
+ {SCULPT_TOOL_DRAW_SHARP, "DRAW_SHARP", ICON_BRUSH_SCULPT_DRAW, "Draw Sharp", ""},
{SCULPT_TOOL_CLAY, "CLAY", ICON_BRUSH_CLAY, "Clay", ""},
{SCULPT_TOOL_CLAY_STRIPS, "CLAY_STRIPS", ICON_BRUSH_CLAY_STRIPS, "Clay Strips", ""},
{SCULPT_TOOL_LAYER, "LAYER", ICON_BRUSH_LAYER, "Layer", ""},
@@ -84,8 +85,10 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
{SCULPT_TOOL_PINCH, "PINCH", ICON_BRUSH_PINCH, "Pinch", ""},
{0, "", 0, NULL, NULL},
{SCULPT_TOOL_GRAB, "GRAB", ICON_BRUSH_GRAB, "Grab", ""},
+ {SCULPT_TOOL_ELASTIC_DEFORM, "ELASTIC_DEFORM", ICON_BRUSH_GRAB, "Elastic Deform", ""},
{SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", ICON_BRUSH_SNAKE_HOOK, "Snake Hook", ""},
{SCULPT_TOOL_THUMB, "THUMB", ICON_BRUSH_THUMB, "Thumb", ""},
+ {SCULPT_TOOL_POSE, "POSE", ICON_BRUSH_GRAB, "Pose", ""},
{SCULPT_TOOL_NUDGE, "NUDGE", ICON_BRUSH_NUDGE, "Nudge", ""},
{SCULPT_TOOL_ROTATE, "ROTATE", ICON_BRUSH_ROTATE, "Rotate", ""},
{0, "", 0, NULL, NULL},
@@ -167,6 +170,8 @@ static EnumPropertyItem rna_enum_gpencil_brush_icons_items[] = {
{GP_BRUSH_ICON_INKNOISE, "INKNOISE", ICON_GPBRUSH_INKNOISE, "Ink Noise", ""},
{GP_BRUSH_ICON_BLOCK, "BLOCK", ICON_GPBRUSH_BLOCK, "Block", ""},
{GP_BRUSH_ICON_MARKER, "MARKER", ICON_GPBRUSH_MARKER, "Marker", ""},
+ {GP_BRUSH_ICON_AIRBRUSH, "AIRBRUSH", ICON_GPBRUSH_AIRBRUSH, "Airbrush", ""},
+ {GP_BRUSH_ICON_CHISEL, "CHISEL", ICON_GPBRUSH_CHISEL, "Chisel", ""},
{GP_BRUSH_ICON_FILL, "FILL", ICON_GPBRUSH_FILL, "Fill", ""},
{GP_BRUSH_ICON_ERASE_SOFT, "SOFT", ICON_GPBRUSH_ERASE_SOFT, "Eraser Soft", ""},
{GP_BRUSH_ICON_ERASE_HARD, "HARD", ICON_GPBRUSH_ERASE_HARD, "Eraser Hard", ""},
@@ -382,6 +387,7 @@ static bool rna_BrushCapabilitiesSculpt_has_direction_get(PointerRNA *ptr)
Brush *br = (Brush *)ptr->data;
return !ELEM(br->sculpt_tool,
SCULPT_TOOL_DRAW,
+ SCULPT_TOOL_DRAW_SHARP,
SCULPT_TOOL_CLAY,
SCULPT_TOOL_CLAY_STRIPS,
SCULPT_TOOL_LAYER,
@@ -645,6 +651,7 @@ static const EnumPropertyItem *rna_Brush_direction_itemf(bContext *C,
case PAINT_MODE_SCULPT:
switch (me->sculpt_tool) {
case SCULPT_TOOL_DRAW:
+ case SCULPT_TOOL_DRAW_SHARP:
case SCULPT_TOOL_CREASE:
case SCULPT_TOOL_BLOB:
case SCULPT_TOOL_LAYER:
@@ -1184,6 +1191,14 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+ /* Simplify factor */
+ prop = RNA_def_property(srna, "simplify_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "simplify_f");
+ RNA_def_property_range(prop, 0, 100.0);
+ RNA_def_property_ui_range(prop, 0, 100.0, 1.0f, 3);
+ RNA_def_property_ui_text(prop, "Simplify", "Factor of Simplify using adaptive algorithm");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
/* Curves for pressure */
prop = RNA_def_property(srna, "curve_sensitivity", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "curve_sensitivity");
@@ -1283,7 +1298,7 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
prop = RNA_def_property(srna, "active_smooth_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "active_smooth");
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Active Smooth", "Amount of smoothing while drawing ");
+ RNA_def_property_ui_text(prop, "Active Smooth", "Amount of smoothing while drawing");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
@@ -1291,7 +1306,7 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "era_strength_f");
RNA_def_property_range(prop, 0.0, 100.0);
RNA_def_property_ui_range(prop, 0.0, 100.0, 10, 1);
- RNA_def_property_ui_text(prop, "Affect Stroke Strength", "Amount of erasing for strength ");
+ RNA_def_property_ui_text(prop, "Affect Stroke Strength", "Amount of erasing for strength");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
@@ -1299,7 +1314,7 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "era_thickness_f");
RNA_def_property_range(prop, 0.0, 100.0);
RNA_def_property_ui_range(prop, 0.0, 100.0, 10, 1);
- RNA_def_property_ui_text(prop, "Affect Stroke Thickness", "Amount of erasing for thickness ");
+ RNA_def_property_ui_text(prop, "Affect Stroke Thickness", "Amount of erasing for thickness");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
@@ -1571,6 +1586,16 @@ static void rna_def_brush(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem brush_spacing_unit_items[] = {
+ {0, "VIEW", 0, "View", "Calculate brush spacing relative to the view"},
+ {BRUSH_SCENE_SPACING,
+ "SCENE",
+ 0,
+ "Scene",
+ "Calculate brush spacing relative to the scene using the stroke location"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
static const EnumPropertyItem brush_curve_preset_items[] = {
{BRUSH_CURVE_CUSTOM, "CUSTOM", ICON_RNDCURVE, "Custom", ""},
{BRUSH_CURVE_SMOOTH, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", ""},
@@ -1584,6 +1609,19 @@ static void rna_def_brush(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem brush_elastic_deform_type_items[] = {
+ {BRUSH_ELASTIC_DEFORM_GRAB, "ELASTIC_DEFORM_GRAB", 0, "Grab", ""},
+ {BRUSH_ELASTIC_DEFORM_GRAB_BISCALE, "ELASTIC_DEFORM_GRAB_BISCALE", 0, "Bi-scale Grab", ""},
+ {BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE,
+ "ELASTIC_DEFORM_GRAB_TRISCALE",
+ 0,
+ "Tri-scale Grab",
+ ""},
+ {BRUSH_ELASTIC_DEFORM_SCALE, "ELASTIC_DEFORM_SCALE", 0, "Scale", ""},
+ {BRUSH_ELASTIC_DEFORM_TWIST, "ELASTIC_DEFORM_TWIST", 0, "Twist", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "Brush", "ID");
RNA_def_struct_ui_text(
srna, "Brush", "Brush data-block for storing brush settings for painting and sculpting");
@@ -1592,7 +1630,7 @@ static void rna_def_brush(BlenderRNA *brna)
/* enums */
prop = RNA_def_property(srna, "blend", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_blend_items);
- RNA_def_property_ui_text(prop, "Blending mode", "Brush blending mode");
+ RNA_def_property_ui_text(prop, "Blending Mode", "Brush blending mode");
RNA_def_property_update(prop, 0, "rna_Brush_update");
/**
@@ -1664,6 +1702,11 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Curve Preset", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "elastic_deform_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, brush_elastic_deform_type_items);
+ RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
/* number values */
prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL);
RNA_def_property_int_funcs(prop, NULL, "rna_Brush_set_size", NULL);
@@ -1675,7 +1718,7 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "unprojected_radius", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_funcs(prop, NULL, "rna_Brush_set_unprojected_radius", NULL);
RNA_def_property_range(prop, 0.001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.001, 1, 0, -1);
+ RNA_def_property_ui_range(prop, 0.001, 1, 1, -1);
RNA_def_property_ui_text(prop, "Unprojected Radius", "Radius of brush in Blender units");
RNA_def_property_update(prop, 0, "rna_Brush_size_update");
@@ -1740,7 +1783,6 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3);
RNA_def_property_ui_text(prop, "Weight", "Vertex weight when brush is applied");
@@ -1748,7 +1790,6 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "alpha");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, 10.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3);
RNA_def_property_ui_text(
@@ -1768,7 +1809,6 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "plane_trim", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "plane_trim");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0, 1.0f);
RNA_def_property_ui_text(
prop,
@@ -1799,6 +1839,16 @@ static void rna_def_brush(BlenderRNA *brna)
prop, "Normal Weight", "How much grab will pull vertexes out of surface during a grab");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "elastic_deform_volume_preservation", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "elastic_deform_volume_preservation");
+ RNA_def_property_range(prop, 0.0f, 0.9f);
+ RNA_def_property_ui_range(prop, 0.0f, 0.9f, 0.01f, 3);
+ RNA_def_property_ui_text(prop,
+ "Volume Preservation",
+ "Poisson ratio for elastic deformation. Higher values preserve volume "
+ "more, but also lead to more bulging");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "rake_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "rake_factor");
RNA_def_property_float_default(prop, 0);
@@ -1809,11 +1859,17 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "crease_pinch_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "crease_pinch_factor");
- RNA_def_property_float_default(prop, 2.0f / 3.0f);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Crease Brush Pinch Factor", "How much the crease brush pinches");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "pose_offset", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "pose_offset");
+ RNA_def_property_range(prop, 0.0f, 2.0f);
+ RNA_def_property_ui_text(
+ prop, "Pose Origin Offset", "Offset of the pose origin in relation to the brush radius");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "auto_smooth_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "autosmooth_factor");
RNA_def_property_float_default(prop, 0);
@@ -1835,6 +1891,16 @@ static void rna_def_brush(BlenderRNA *brna)
"Best used on low-poly meshes as it has a performance impact");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "normal_radius_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "normal_radius_factor");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3);
+ RNA_def_property_ui_text(prop,
+ "Normal Radius",
+ "Ratio between the brush radius and the radius that is going to be "
+ "used to sample the normal");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "stencil_pos", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "stencil_pos");
RNA_def_property_array(prop, 2);
@@ -1879,7 +1945,6 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "blur_kernel_radius", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "blur_kernel_radius");
RNA_def_property_range(prop, 1, 10000);
- RNA_def_property_int_default(prop, 2);
RNA_def_property_ui_range(prop, 1, 50, 1, -1);
RNA_def_property_ui_text(
prop, "Kernel Radius", "Radius of kernel used for soften and sharpen in pixels");
@@ -1920,6 +1985,36 @@ static void rna_def_brush(BlenderRNA *brna)
"When locked keep using normal of surface where stroke was initiated");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "use_original_plane", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ORIGINAL_PLANE);
+ RNA_def_property_ui_text(
+ prop,
+ "Original Plane",
+ "When locked keep using the plane origin of surface where stroke was initiated");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop = RNA_def_property(srna, "use_automasking_topology", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_TOPOLOGY);
+ RNA_def_property_ui_text(prop,
+ "Topology Automasking",
+ "Affect only vertices connected to the active vertex under the brush");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop = RNA_def_property(srna, "use_scene_spacing", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
+ RNA_def_property_enum_items(prop, brush_spacing_unit_items);
+ RNA_def_property_ui_text(
+ prop, "Spacing Distance", "Calculate the brush spacing using view or scene distance");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop = RNA_def_property(srna, "use_grab_active_vertex", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_GRAB_ACTIVE_VERTEX);
+ RNA_def_property_ui_text(
+ prop,
+ "Grab Active Vertex",
+ "Apply the maximum grab strength to the active vertex instead of the cursor location");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "use_pressure_strength", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ALPHA_PRESSURE);
RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index 88083f600f8..47a09233769 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -436,7 +436,6 @@ static void rna_def_camera_dof_settings_data(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dependency_update");
prop = RNA_def_property(srna, "focus_distance", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_default(prop, 10.0f);
// RNA_def_property_pointer_sdna(prop, NULL, "focus_distance");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0f, 5000.0f, 1, 2);
@@ -449,7 +448,6 @@ static void rna_def_camera_dof_settings_data(BlenderRNA *brna)
prop,
"F-Stop",
"F-Stop ratio (lower numbers give more defocus, higher numbers give a sharper image)");
- RNA_def_property_float_default(prop, 5.6f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.1f, 128.0f, 10, 1);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dof_update");
@@ -468,7 +466,6 @@ static void rna_def_camera_dof_settings_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "aperture_ratio", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(prop, "Ratio", "Distortion to simulate anamorphic lens bokeh");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_range(prop, 0.01f, FLT_MAX);
RNA_def_property_ui_range(prop, 1.0f, 2.0f, 0.1, 3);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dof_update");
@@ -525,7 +522,6 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "passepartout_alpha", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "passepartalpha");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_ui_text(
prop, "Passepartout Alpha", "Opacity (alpha) of the darkened overlay in Camera view");
RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL);
@@ -552,14 +548,12 @@ void RNA_def_camera(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_update");
prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_ui_text(prop, "Clip Start", "Camera near clipping distance");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_default(prop, 1000.0f);
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_ui_text(prop, "Clip End", "Camera far clipping distance");
@@ -567,7 +561,6 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "lens", PROP_FLOAT, PROP_DISTANCE_CAMERA);
RNA_def_property_float_sdna(prop, NULL, "lens");
- RNA_def_property_float_default(prop, 50.0f);
RNA_def_property_range(prop, 1.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 1.0f, 5000.0f, 100, 4);
RNA_def_property_ui_text(prop, "Focal Length", "Perspective Camera lens value in millimeters");
@@ -575,7 +568,6 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "sensor_width", PROP_FLOAT, PROP_DISTANCE_CAMERA);
RNA_def_property_float_sdna(prop, NULL, "sensor_x");
- RNA_def_property_float_default(prop, 36.0f);
RNA_def_property_range(prop, 1.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 1.0f, 100.f, 100, 4);
RNA_def_property_ui_text(
@@ -584,7 +576,6 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "sensor_height", PROP_FLOAT, PROP_DISTANCE_CAMERA);
RNA_def_property_float_sdna(prop, NULL, "sensor_y");
- RNA_def_property_float_default(prop, 34.0f);
RNA_def_property_range(prop, 1.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 1.0f, 100.f, 100, 4);
RNA_def_property_ui_text(
@@ -593,7 +584,6 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "ortho_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "ortho_scale");
- RNA_def_property_float_default(prop, 6.0f);
RNA_def_property_range(prop, FLT_MIN, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, 10000.0f, 10, 3);
RNA_def_property_ui_text(
@@ -602,7 +592,6 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "display_size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "drawsize");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_range(prop, 0.01f, 1000.0f);
RNA_def_property_ui_range(prop, 0.01, 100, 1, 2);
RNA_def_property_ui_text(
@@ -645,7 +634,6 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_passepartout", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_SHOWPASSEPARTOUT);
- RNA_def_property_boolean_default(prop, true);
RNA_def_property_ui_text(
prop, "Show Passepartout", "Show a darkened overlay outside the image area in Camera view");
RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL);
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 08d2a03b2a9..7732bf531d8 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -256,6 +256,17 @@ static const EnumPropertyItem track_axis_items[] = {
{0, NULL, 0, NULL, NULL},
};
+static const EnumPropertyItem euler_order_items[] = {
+ {CONSTRAINT_EULER_AUTO, "AUTO", 0, "Default", "Euler using the default rotation order"},
+ {CONSTRAINT_EULER_XYZ, "XYZ", 0, "XYZ Euler", "Euler using the XYZ rotation order"},
+ {CONSTRAINT_EULER_XZY, "XZY", 0, "XZY Euler", "Euler using the XZY rotation order"},
+ {CONSTRAINT_EULER_YXZ, "YXZ", 0, "YXZ Euler", "Euler using the YXZ rotation order"},
+ {CONSTRAINT_EULER_YZX, "YZX", 0, "YZX Euler", "Euler using the YZX rotation order"},
+ {CONSTRAINT_EULER_ZXY, "ZXY", 0, "ZXY Euler", "Euler using the ZXY rotation order"},
+ {CONSTRAINT_EULER_ZYX, "ZYX", 0, "ZYX Euler", "Euler using the ZYX rotation order"},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifdef RNA_RUNTIME
static const EnumPropertyItem space_object_items[] = {
@@ -519,6 +530,24 @@ static void rna_Constraint_ik_type_set(struct PointerRNA *ptr, int value)
}
}
+/* DEPRECATED: use_offset replaced with mix_mode */
+static bool rna_Constraint_RotLike_use_offset_get(struct PointerRNA *ptr)
+{
+ bConstraint *con = ptr->data;
+ bRotateLikeConstraint *rotlike = con->data;
+ return rotlike->mix_mode != ROTLIKE_MIX_REPLACE;
+}
+
+static void rna_Constraint_RotLike_use_offset_set(struct PointerRNA *ptr, bool value)
+{
+ bConstraint *con = ptr->data;
+ bRotateLikeConstraint *rotlike = con->data;
+ bool curval = (rotlike->mix_mode != ROTLIKE_MIX_REPLACE);
+ if (curval != value) {
+ rotlike->mix_mode = (value ? ROTLIKE_MIX_OFFSET : ROTLIKE_MIX_REPLACE);
+ }
+}
+
static const EnumPropertyItem *rna_Constraint_owner_space_itemf(bContext *UNUSED(C),
PointerRNA *ptr,
PropertyRNA *UNUSED(prop),
@@ -1287,6 +1316,28 @@ static void rna_def_constraint_rotate_like(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
+ static const EnumPropertyItem mix_mode_items[] = {
+ {ROTLIKE_MIX_REPLACE, "REPLACE", 0, "Replace", "Replace the original rotation with copied"},
+ {ROTLIKE_MIX_ADD, "ADD", 0, "Add", "Add euler component values together"},
+ {ROTLIKE_MIX_BEFORE,
+ "BEFORE",
+ 0,
+ "Before Original",
+ "Apply copied rotation before original, as if the constraint target is a parent"},
+ {ROTLIKE_MIX_AFTER,
+ "AFTER",
+ 0,
+ "After Original",
+ "Apply copied rotation after original, as if the constraint target is a child"},
+ {ROTLIKE_MIX_OFFSET,
+ "OFFSET",
+ 0,
+ "Offset (Legacy)",
+ "Combine rotations like the original Offset checkbox. Does not work well for "
+ "multiple axis rotations"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "CopyRotationConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Copy Rotation Constraint", "Copy the rotation of the target");
RNA_def_struct_sdna_from(srna, "bRotateLikeConstraint", "data");
@@ -1324,9 +1375,25 @@ static void rna_def_constraint_rotate_like(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Invert Z", "Invert the Z rotation");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ prop = RNA_def_property(srna, "euler_order", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "euler_order");
+ RNA_def_property_enum_items(prop, euler_order_items);
+ RNA_def_property_ui_text(prop, "Euler Order", "Explicitly specify the euler rotation order");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "mix_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mix_mode");
+ RNA_def_property_enum_items(prop, mix_mode_items);
+ RNA_def_property_ui_text(
+ prop, "Mix Mode", "Specify how the copied and existing rotations are combined");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ /* DEPRECATED: replaced with mix_mode */
prop = RNA_def_property(srna, "use_offset", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ROTLIKE_OFFSET);
- RNA_def_property_ui_text(prop, "Offset", "Add original rotation into copied rotation");
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Constraint_RotLike_use_offset_get", "rna_Constraint_RotLike_use_offset_set");
+ RNA_def_property_ui_text(
+ prop, "Offset", "DEPRECATED: Add original rotation into copied rotation");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
}
@@ -1364,6 +1431,14 @@ static void rna_def_constraint_size_like(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Power", "Raise the target's scale to the specified power");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ prop = RNA_def_property(srna, "use_make_uniform", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SIZELIKE_UNIFORM);
+ RNA_def_property_ui_text(prop,
+ "Make Uniform",
+ "Redistribute the copied change in volume equally "
+ "between the three axes of the owner");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
prop = RNA_def_property(srna, "use_offset", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SIZELIKE_OFFSET);
RNA_def_property_ui_text(prop, "Offset", "Combine original scale with copied scale");
@@ -1440,6 +1515,28 @@ static void rna_def_constraint_same_volume(BlenderRNA *brna)
static void rna_def_constraint_transform_like(BlenderRNA *brna)
{
StructRNA *srna;
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem mix_mode_items[] = {
+ {TRANSLIKE_MIX_REPLACE,
+ "REPLACE",
+ 0,
+ "Replace",
+ "Replace the original transformation with copied"},
+ {TRANSLIKE_MIX_BEFORE,
+ "BEFORE",
+ 0,
+ "Before Original",
+ "Apply copied transformation before original, as if the constraint target is a parent. "
+ "Scale is handled specially to avoid creating shear"},
+ {TRANSLIKE_MIX_AFTER,
+ "AFTER",
+ 0,
+ "After Original",
+ "Apply copied transformation after original, as if the constraint target is a child. "
+ "Scale is handled specially to avoid creating shear"},
+ {0, NULL, 0, NULL, NULL},
+ };
srna = RNA_def_struct(brna, "CopyTransformsConstraint", "Constraint");
RNA_def_struct_ui_text(
@@ -1452,6 +1549,13 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna)
RNA_def_struct_ui_icon(srna, ICON_CON_TRANSLIKE);
rna_def_constraint_target_common(srna);
+
+ prop = RNA_def_property(srna, "mix_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mix_mode");
+ RNA_def_property_enum_items(prop, mix_mode_items);
+ RNA_def_property_ui_text(
+ prop, "Mix Mode", "Specify how the copied and existing transformations are combined");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
}
static void rna_def_constraint_minmax(BlenderRNA *brna)
@@ -1830,6 +1934,34 @@ static void rna_def_constraint_transform(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem mix_mode_loc_items[] = {
+ {TRANS_MIXLOC_REPLACE, "REPLACE", 0, "Replace", "Replace component values"},
+ {TRANS_MIXLOC_ADD, "ADD", 0, "Add", "Add component values together"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem mix_mode_rot_items[] = {
+ {TRANS_MIXROT_REPLACE, "REPLACE", 0, "Replace", "Replace component values"},
+ {TRANS_MIXROT_ADD, "ADD", 0, "Add", "Add component values together"},
+ {TRANS_MIXROT_BEFORE,
+ "BEFORE",
+ 0,
+ "Before Original",
+ "Apply new rotation before original, as if it was on a parent"},
+ {TRANS_MIXROT_AFTER,
+ "AFTER",
+ 0,
+ "After Original",
+ "Apply new rotation after original, as if it was on a child"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem mix_mode_scale_items[] = {
+ {TRANS_MIXSCALE_REPLACE, "REPLACE", 0, "Replace", "Replace component values"},
+ {TRANS_MIXSCALE_MULTIPLY, "MULTIPLY", 0, "Multiply", "Multiply component values together"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "TransformConstraint", "Constraint");
RNA_def_struct_ui_text(
srna, "Transformation Constraint", "Map transformations of the target to the object");
@@ -1877,6 +2009,18 @@ static void rna_def_constraint_transform(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Extrapolate Motion", "Extrapolate ranges");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ prop = RNA_def_property(srna, "from_rotation_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "from_rotation_mode");
+ RNA_def_property_enum_items(prop, rna_enum_driver_target_rotation_mode_items);
+ RNA_def_property_ui_text(prop, "From Mode", "Specify the type of rotation channels to use");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "to_euler_order", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "to_euler_order");
+ RNA_def_property_enum_items(prop, euler_order_items);
+ RNA_def_property_ui_text(prop, "To Order", "Explicitly specify the output euler rotation order");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
/* Loc */
prop = RNA_def_property(srna, "from_min_x", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "from_min[0]");
@@ -1950,6 +2094,13 @@ static void rna_def_constraint_transform(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "To Maximum Z", "Top range of Z axis destination motion");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ prop = RNA_def_property(srna, "mix_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mix_mode_loc");
+ RNA_def_property_enum_items(prop, mix_mode_loc_items);
+ RNA_def_property_ui_text(
+ prop, "Location Mix Mode", "Specify how to combine the new location with original");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
/* Rot */
prop = RNA_def_property(srna, "from_min_x_rot", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "from_min_rot[0]");
@@ -2023,6 +2174,13 @@ static void rna_def_constraint_transform(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "To Maximum Z", "Top range of Z axis destination motion");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ prop = RNA_def_property(srna, "mix_mode_rot", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mix_mode_rot");
+ RNA_def_property_enum_items(prop, mix_mode_rot_items);
+ RNA_def_property_ui_text(
+ prop, "Rotation Mix Mode", "Specify how to combine the new rotation with original");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
/* Scale */
prop = RNA_def_property(srna, "from_min_x_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "from_min_scale[0]");
@@ -2095,6 +2253,13 @@ static void rna_def_constraint_transform(BlenderRNA *brna)
RNA_def_property_ui_range(prop, -1000.0f, 1000.0f, 10, 3);
RNA_def_property_ui_text(prop, "To Maximum Z", "Top range of Z axis destination motion");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "mix_mode_scale", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mix_mode_scale");
+ RNA_def_property_enum_items(prop, mix_mode_scale_items);
+ RNA_def_property_ui_text(
+ prop, "Scale Mix Mode", "Specify how to combine the new scale with original");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
}
static void rna_def_constraint_location_limit(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index a7dac4100db..6a3ab632fd4 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -291,9 +291,7 @@ static void rna_Curve_texspace_loc_get(PointerRNA *ptr, float *values)
{
Curve *cu = (Curve *)ptr->data;
- if (!cu->bb) {
- BKE_curve_texspace_calc(cu);
- }
+ BKE_curve_texspace_ensure(cu);
copy_v3_v3(values, cu->loc);
}
@@ -309,9 +307,7 @@ static void rna_Curve_texspace_size_get(PointerRNA *ptr, float *values)
{
Curve *cu = (Curve *)ptr->data;
- if (!cu->bb) {
- BKE_curve_texspace_calc(cu);
- }
+ BKE_curve_texspace_ensure(cu);
copy_v3_v3(values, cu->size);
}
@@ -1761,15 +1757,6 @@ static void rna_def_curve(BlenderRNA *brna)
prop, "rna_Curve_texspace_size_get", "rna_Curve_texspace_size_set", NULL);
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
- /* not supported yet */
-# if 0
- prop = RNA_def_property(srna, "texspace_rot", PROP_FLOAT, PROP_EULER);
- RNA_def_property_float(prop, NULL, "rot");
- RNA_def_property_ui_text(prop, "Texture Space Rotation", "Texture space rotation");
- RNA_def_property_editable_func(prop, texspace_editable);
- RNA_def_property_update(prop, 0, "rna_Curve_update_data");
-# endif
-
prop = RNA_def_property(srna, "use_uv_as_generated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CU_UV_ORCO);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 03ab9da2eff..fc22e9e6c74 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -31,6 +31,7 @@
#include "DNA_genfile.h"
#include "DNA_sdna_types.h"
+#include "DNA_defaults.h"
#include "BLI_listbase.h"
#include "BLI_ghash.h"
@@ -68,6 +69,25 @@ static struct {
} g_version_data;
#endif
+#ifndef RNA_RUNTIME
+/**
+ * When set, report details about which defaults are used.
+ * Noisy but handy when investigating default extraction.
+ */
+static bool debugSRNA_defaults = false;
+
+static void print_defult_info(const PropertyDefRNA *dp)
+{
+ fprintf(stderr,
+ "dna_type=%s, dna_offset=%d, dna_struct=%s, dna_name=%s, id=%s\n",
+ dp->dnatype,
+ dp->dnaoffset,
+ dp->dnastructname,
+ dp->dnaname,
+ dp->prop->identifier);
+}
+#endif /* RNA_RUNTIME */
+
/* Duplicated code since we can't link in blenkernel or blenlib */
/* pedantic check for final '.', note '...' are allowed though. */
@@ -378,6 +398,8 @@ typedef struct DNAStructMember {
const char *name;
int arraylength;
int pointerlevel;
+ int offset;
+ int size;
} DNAStructMember;
static int rna_member_cmp(const char *name, const char *oname)
@@ -420,7 +442,8 @@ static int rna_member_cmp(const char *name, const char *oname)
static int rna_find_sdna_member(SDNA *sdna,
const char *structname,
const char *membername,
- DNAStructMember *smember)
+ DNAStructMember *smember,
+ int *offset)
{
const char *dnaname;
const short *sp;
@@ -432,7 +455,11 @@ static int rna_find_sdna_member(SDNA *sdna,
}
structnr = DNA_struct_find_nr_wrapper(sdna, structname);
+ smember->offset = -1;
if (structnr == -1) {
+ if (offset) {
+ *offset = -1;
+ }
return 0;
}
@@ -441,12 +468,15 @@ static int rna_find_sdna_member(SDNA *sdna,
sp += 2;
for (a = 0; a < totmember; a++, sp += 2) {
+ const int size = DNA_elem_size_nr(sdna, sp[0], sp[1]);
dnaname = sdna->alias.names[sp[1]];
cmp = rna_member_cmp(dnaname, membername);
if (cmp == 1) {
smember->type = sdna->alias.types[sp[0]];
smember->name = dnaname;
+ smember->offset = *offset;
+ smember->size = size;
if (strstr(membername, "[")) {
smember->arraylength = 0;
@@ -465,25 +495,36 @@ static int rna_find_sdna_member(SDNA *sdna,
else if (cmp == 2) {
smember->type = "";
smember->name = dnaname;
+ smember->offset = *offset;
+ smember->size = size;
smember->pointerlevel = 0;
smember->arraylength = 0;
membername = strstr(membername, ".") + strlen(".");
- rna_find_sdna_member(sdna, sdna->alias.types[sp[0]], membername, smember);
+ rna_find_sdna_member(sdna, sdna->alias.types[sp[0]], membername, smember, offset);
return 1;
}
else if (cmp == 3) {
smember->type = "";
smember->name = dnaname;
+ smember->offset = *offset;
+ smember->size = size;
smember->pointerlevel = 0;
smember->arraylength = 0;
+ if (offset) {
+ *offset = -1;
+ }
membername = strstr(membername, "->") + strlen("->");
- rna_find_sdna_member(sdna, sdna->alias.types[sp[0]], membername, smember);
+ rna_find_sdna_member(sdna, sdna->alias.types[sp[0]], membername, smember, offset);
return 1;
}
+
+ if (offset && *offset != -1) {
+ *offset += size;
+ }
}
return 0;
@@ -1647,6 +1688,11 @@ void RNA_def_property_ui_range(
DefRNA.error = 1;
}
+ if (step == 0) {
+ CLOG_ERROR(&LOG, "\"%s.%s\", step is zero.", srna->identifier, prop->identifier);
+ DefRNA.error = 1;
+ }
+
if (precision < -1 || precision > UI_PRECISION_FLOAT_MAX) {
CLOG_ERROR(&LOG, "\"%s.%s\", precision outside range.", srna->identifier, prop->identifier);
DefRNA.error = 1;
@@ -1835,6 +1881,12 @@ void RNA_def_property_boolean_default(PropertyRNA *prop, bool value)
case PROP_BOOLEAN: {
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
BLI_assert(ELEM(value, false, true));
+#ifndef RNA_RUNTIME
+ /* Default may be set from items. */
+ if (bprop->defaultvalue) {
+ CLOG_ERROR(&LOG, "\"%s.%s\", set from DNA.", srna->identifier, prop->identifier);
+ }
+#endif
bprop->defaultvalue = value;
break;
}
@@ -1869,6 +1921,11 @@ void RNA_def_property_int_default(PropertyRNA *prop, int value)
switch (prop->type) {
case PROP_INT: {
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
+#ifndef RNA_RUNTIME
+ if (iprop->defaultvalue != 0) {
+ CLOG_ERROR(&LOG, "\"%s.%s\", set from DNA.", srna->identifier, prop->identifier);
+ }
+#endif
iprop->defaultvalue = value;
break;
}
@@ -1886,6 +1943,11 @@ void RNA_def_property_int_array_default(PropertyRNA *prop, const int *array)
switch (prop->type) {
case PROP_INT: {
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
+#ifndef RNA_RUNTIME
+ if (iprop->defaultarray != NULL) {
+ CLOG_ERROR(&LOG, "\"%s.%s\", set from DNA.", srna->identifier, prop->identifier);
+ }
+#endif
iprop->defaultarray = array;
break;
}
@@ -1903,6 +1965,11 @@ void RNA_def_property_float_default(PropertyRNA *prop, float value)
switch (prop->type) {
case PROP_FLOAT: {
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
+#ifndef RNA_RUNTIME
+ if (fprop->defaultvalue != 0) {
+ CLOG_ERROR(&LOG, "\"%s.%s\", set from DNA.", srna->identifier, prop->identifier);
+ }
+#endif
fprop->defaultvalue = value;
break;
}
@@ -1920,6 +1987,11 @@ void RNA_def_property_float_array_default(PropertyRNA *prop, const float *array)
switch (prop->type) {
case PROP_FLOAT: {
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
+#ifndef RNA_RUNTIME
+ if (fprop->defaultarray != NULL) {
+ CLOG_ERROR(&LOG, "\"%s.%s\", set from DNA.", srna->identifier, prop->identifier);
+ }
+#endif
fprop->defaultarray = array; /* WARNING, this array must not come from the stack and lost */
break;
}
@@ -1956,7 +2028,11 @@ void RNA_def_property_string_default(PropertyRNA *prop, const char *value)
// BLI_assert(0);
break;
}
-
+#ifndef RNA_RUNTIME
+ if (sprop->defaultvalue != NULL && sprop->defaultvalue[0]) {
+ CLOG_ERROR(&LOG, "\"%s.%s\", set from DNA.", srna->identifier, prop->identifier);
+ }
+#endif
sprop->defaultvalue = value;
break;
}
@@ -2047,7 +2123,8 @@ static PropertyDefRNA *rna_def_property_sdna(PropertyRNA *prop,
propname = prop->identifier;
}
- if (!rna_find_sdna_member(DefRNA.sdna, structname, propname, &smember)) {
+ int dnaoffset = 0;
+ if (!rna_find_sdna_member(DefRNA.sdna, structname, propname, &smember, &dnaoffset)) {
if (DefRNA.silent) {
return NULL;
}
@@ -2061,6 +2138,7 @@ static PropertyDefRNA *rna_def_property_sdna(PropertyRNA *prop,
if (prop->type == PROP_POINTER) {
dp->dnapointerlevel = 1;
}
+ dp->dnaoffset = smember.offset;
return dp;
}
else {
@@ -2091,6 +2169,8 @@ static PropertyDefRNA *rna_def_property_sdna(PropertyRNA *prop,
dp->dnatype = smember.type;
dp->dnaarraylength = smember.arraylength;
dp->dnapointerlevel = smember.pointerlevel;
+ dp->dnaoffset = smember.offset;
+ dp->dnasize = smember.size;
return dp;
}
@@ -2101,6 +2181,7 @@ void RNA_def_property_boolean_sdna(PropertyRNA *prop,
int bit)
{
PropertyDefRNA *dp;
+ BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
@@ -2131,6 +2212,57 @@ void RNA_def_property_boolean_sdna(PropertyRNA *prop,
}
dp->booleanbit = bit;
+
+#ifndef RNA_RUNTIME
+ /* Set the default if possible. */
+ if (dp->dnaoffset != -1) {
+ int SDNAnr = DNA_struct_find_nr_wrapper(DefRNA.sdna, dp->dnastructname);
+ if (SDNAnr != -1) {
+ const void *default_data = DNA_default_table[SDNAnr];
+ if (default_data) {
+ default_data = POINTER_OFFSET(default_data, dp->dnaoffset);
+ bool has_default = true;
+ if (prop->totarraylength > 0) {
+ has_default = false;
+ if (debugSRNA_defaults) {
+ fprintf(stderr, "%s default: unsupported boolean array default\n", __func__);
+ }
+ }
+ else {
+ if (STREQ(dp->dnatype, "char")) {
+ bprop->defaultvalue = *(const char *)default_data & bit;
+ }
+ else if (STREQ(dp->dnatype, "short")) {
+ bprop->defaultvalue = *(const short *)default_data & bit;
+ }
+ else if (STREQ(dp->dnatype, "int")) {
+ bprop->defaultvalue = *(const int *)default_data & bit;
+ }
+ else {
+ has_default = false;
+ if (debugSRNA_defaults) {
+ fprintf(
+ stderr, "%s default: unsupported boolean type (%s)\n", __func__, dp->dnatype);
+ }
+ }
+
+ if (has_default) {
+ if (dp->booleannegative) {
+ bprop->defaultvalue = !bprop->defaultvalue;
+ }
+
+ if (debugSRNA_defaults) {
+ fprintf(stderr, "value=%d, ", bprop->defaultvalue);
+ print_defult_info(dp);
+ }
+ }
+ }
+ }
+ }
+ }
+#else
+ UNUSED_VARS(bprop);
+#endif
}
}
@@ -2204,6 +2336,96 @@ void RNA_def_property_int_sdna(PropertyRNA *prop, const char *structname, const
prop->subtype == PROP_FACTOR) {
iprop->hardmin = iprop->softmin = 0;
}
+
+#ifndef RNA_RUNTIME
+ /* Set the default if possible. */
+ if (dp->dnaoffset != -1) {
+ int SDNAnr = DNA_struct_find_nr_wrapper(DefRNA.sdna, dp->dnastructname);
+ if (SDNAnr != -1) {
+ const void *default_data = DNA_default_table[SDNAnr];
+ if (default_data) {
+ default_data = POINTER_OFFSET(default_data, dp->dnaoffset);
+ /* NOTE: Currently doesn't store sign, assume chars are unsigned because
+ * we build with this enabled, otherwise check 'PROP_UNSIGNED'. */
+ bool has_default = true;
+ if (prop->totarraylength > 0) {
+ const void *default_data_end = POINTER_OFFSET(default_data, dp->dnasize);
+ const int size_final = sizeof(int) * prop->totarraylength;
+ if (STREQ(dp->dnatype, "char")) {
+ int *defaultarray = rna_calloc(size_final);
+ for (int i = 0; i < prop->totarraylength && default_data < default_data_end; i++) {
+ defaultarray[i] = *(const char *)default_data;
+ default_data = POINTER_OFFSET(default_data, sizeof(char));
+ }
+ iprop->defaultarray = defaultarray;
+ }
+ else if (STREQ(dp->dnatype, "short")) {
+
+ int *defaultarray = rna_calloc(size_final);
+ for (int i = 0; i < prop->totarraylength && default_data < default_data_end; i++) {
+ defaultarray[i] = (prop->subtype != PROP_UNSIGNED) ? *(const short *)default_data :
+ *(const ushort *)default_data;
+ default_data = POINTER_OFFSET(default_data, sizeof(short));
+ }
+ iprop->defaultarray = defaultarray;
+ }
+ else if (STREQ(dp->dnatype, "int")) {
+ int *defaultarray = rna_calloc(size_final);
+ memcpy(defaultarray, default_data, MIN2(size_final, dp->dnasize));
+ iprop->defaultarray = defaultarray;
+ }
+ else {
+ has_default = false;
+ if (debugSRNA_defaults) {
+ fprintf(stderr,
+ "%s default: unsupported int array type (%s)\n",
+ __func__,
+ dp->dnatype);
+ }
+ }
+
+ if (has_default) {
+ if (debugSRNA_defaults) {
+ fprintf(stderr, "value=(");
+ for (int i = 0; i < prop->totarraylength; i++) {
+ fprintf(stderr, "%d, ", iprop->defaultarray[i]);
+ }
+ fprintf(stderr, "), ");
+ print_defult_info(dp);
+ }
+ }
+ }
+ else {
+ if (STREQ(dp->dnatype, "char")) {
+ iprop->defaultvalue = *(const char *)default_data;
+ }
+ else if (STREQ(dp->dnatype, "short")) {
+ iprop->defaultvalue = (prop->subtype != PROP_UNSIGNED) ?
+ *(const short *)default_data :
+ *(const ushort *)default_data;
+ }
+ else if (STREQ(dp->dnatype, "int")) {
+ iprop->defaultvalue = (prop->subtype != PROP_UNSIGNED) ? *(const int *)default_data :
+ *(const uint *)default_data;
+ }
+ else {
+ has_default = false;
+ if (debugSRNA_defaults) {
+ fprintf(stderr, "%s default: unsupported int type (%s)\n", __func__, dp->dnatype);
+ }
+ }
+
+ if (has_default) {
+ if (debugSRNA_defaults) {
+ fprintf(stderr, "value=%d, ", iprop->defaultvalue);
+ print_defult_info(dp);
+ }
+ }
+ }
+ }
+ }
+ }
+#endif
}
}
@@ -2228,8 +2450,8 @@ void RNA_def_property_float_sdna(PropertyRNA *prop, const char *structname, cons
/* silent is for internal use */
if (DefRNA.silent == 0) {
if (dp->dnatype && *dp->dnatype && IS_DNATYPE_FLOAT_COMPAT(dp->dnatype) == 0) {
- if (prop->subtype !=
- PROP_COLOR_GAMMA) { /* colors are an exception. these get translated */
+ /* Colors are an exception. these get translated. */
+ if (prop->subtype != PROP_COLOR_GAMMA) {
CLOG_ERROR(&LOG,
"%s.%s is a '%s' but wrapped as type '%s'.",
srna->identifier,
@@ -2246,6 +2468,70 @@ void RNA_def_property_float_sdna(PropertyRNA *prop, const char *structname, cons
fprop->hardmin = fprop->softmin = 0.0f;
fprop->hardmax = fprop->softmax = 1.0f;
}
+
+#ifndef RNA_RUNTIME
+ /* Set the default if possible. */
+ if (dp->dnaoffset != -1) {
+ int SDNAnr = DNA_struct_find_nr_wrapper(DefRNA.sdna, dp->dnastructname);
+ if (SDNAnr != -1) {
+ const void *default_data = DNA_default_table[SDNAnr];
+ if (default_data) {
+ default_data = POINTER_OFFSET(default_data, dp->dnaoffset);
+ bool has_default = true;
+ if (prop->totarraylength > 0) {
+ if (STREQ(dp->dnatype, "float")) {
+ const int size_final = sizeof(float) * prop->totarraylength;
+ float *defaultarray = rna_calloc(size_final);
+ memcpy(defaultarray, default_data, MIN2(size_final, dp->dnasize));
+ fprop->defaultarray = defaultarray;
+ }
+ else {
+ has_default = false;
+ if (debugSRNA_defaults) {
+ fprintf(stderr,
+ "%s default: unsupported float array type (%s)\n",
+ __func__,
+ dp->dnatype);
+ }
+ }
+
+ if (has_default) {
+ if (debugSRNA_defaults) {
+ fprintf(stderr, "value=(");
+ for (int i = 0; i < prop->totarraylength; i++) {
+ fprintf(stderr, "%g, ", fprop->defaultarray[i]);
+ }
+ fprintf(stderr, "), ");
+ print_defult_info(dp);
+ }
+ }
+ }
+ else {
+ if (STREQ(dp->dnatype, "float")) {
+ fprop->defaultvalue = *(const float *)default_data;
+ }
+ else if (STREQ(dp->dnatype, "char")) {
+ fprop->defaultvalue = (float)*(const char *)default_data * (1.0f / 255.0f);
+ }
+ else {
+ has_default = false;
+ if (debugSRNA_defaults) {
+ fprintf(
+ stderr, "%s default: unsupported float type (%s)\n", __func__, dp->dnatype);
+ }
+ }
+
+ if (has_default) {
+ if (debugSRNA_defaults) {
+ fprintf(stderr, "value=%g, ", fprop->defaultvalue);
+ print_defult_info(dp);
+ }
+ }
+ }
+ }
+ }
+ }
+#endif
}
rna_def_property_sdna(prop, structname, propname);
@@ -2253,7 +2539,8 @@ void RNA_def_property_float_sdna(PropertyRNA *prop, const char *structname, cons
void RNA_def_property_enum_sdna(PropertyRNA *prop, const char *structname, const char *propname)
{
- /* PropertyDefRNA *dp; */
+ PropertyDefRNA *dp;
+ EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
@@ -2267,7 +2554,7 @@ void RNA_def_property_enum_sdna(PropertyRNA *prop, const char *structname, const
return;
}
- if ((/* dp= */ rna_def_property_sdna(prop, structname, propname))) {
+ if ((dp = rna_def_property_sdna(prop, structname, propname))) {
if (prop->arraydimension) {
prop->arraydimension = 0;
prop->totarraylength = 0;
@@ -2277,6 +2564,44 @@ void RNA_def_property_enum_sdna(PropertyRNA *prop, const char *structname, const
DefRNA.error = 1;
}
}
+
+#ifndef RNA_RUNTIME
+ /* Set the default if possible. */
+ if (dp->dnaoffset != -1) {
+ int SDNAnr = DNA_struct_find_nr_wrapper(DefRNA.sdna, dp->dnastructname);
+ if (SDNAnr != -1) {
+ const void *default_data = DNA_default_table[SDNAnr];
+ if (default_data) {
+ default_data = POINTER_OFFSET(default_data, dp->dnaoffset);
+ bool has_default = true;
+ if (STREQ(dp->dnatype, "char")) {
+ eprop->defaultvalue = *(const char *)default_data;
+ }
+ else if (STREQ(dp->dnatype, "short")) {
+ eprop->defaultvalue = *(const short *)default_data;
+ }
+ else if (STREQ(dp->dnatype, "int")) {
+ eprop->defaultvalue = *(const int *)default_data;
+ }
+ else {
+ has_default = false;
+ if (debugSRNA_defaults) {
+ fprintf(stderr, "%s default: unsupported enum type (%s)\n", __func__, dp->dnatype);
+ }
+ }
+
+ if (has_default) {
+ if (debugSRNA_defaults) {
+ fprintf(stderr, "value=%d, ", eprop->defaultvalue);
+ print_defult_info(dp);
+ }
+ }
+ }
+ }
+ }
+#else
+ UNUSED_VARS(eprop);
+#endif
}
}
@@ -2292,12 +2617,23 @@ void RNA_def_property_enum_bitflag_sdna(PropertyRNA *prop,
if (dp) {
dp->enumbitflags = 1;
+
+#ifndef RNA_RUNTIME
+ int defaultvalue_mask = 0;
+ EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
+ for (int i = 0; i < eprop->totitem; i++) {
+ if (eprop->item[i].identifier[0]) {
+ defaultvalue_mask |= eprop->defaultvalue & eprop->item[i].value;
+ }
+ }
+ eprop->defaultvalue = defaultvalue_mask;
+#endif
}
}
void RNA_def_property_string_sdna(PropertyRNA *prop, const char *structname, const char *propname)
{
- /* PropertyDefRNA *dp; */
+ PropertyDefRNA *dp;
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
StructRNA *srna = DefRNA.laststruct;
@@ -2312,12 +2648,31 @@ void RNA_def_property_string_sdna(PropertyRNA *prop, const char *structname, con
return;
}
- if ((/* dp= */ rna_def_property_sdna(prop, structname, propname))) {
+ if ((dp = rna_def_property_sdna(prop, structname, propname))) {
if (prop->arraydimension) {
sprop->maxlength = prop->totarraylength;
prop->arraydimension = 0;
prop->totarraylength = 0;
}
+
+#ifndef RNA_RUNTIME
+ /* Set the default if possible. */
+ if ((dp->dnaoffset != -1) && (dp->dnapointerlevel != 0)) {
+ int SDNAnr = DNA_struct_find_nr_wrapper(DefRNA.sdna, dp->dnastructname);
+ if (SDNAnr != -1) {
+ const void *default_data = DNA_default_table[SDNAnr];
+ if (default_data) {
+ default_data = POINTER_OFFSET(default_data, dp->dnaoffset);
+ sprop->defaultvalue = default_data;
+
+ if (debugSRNA_defaults) {
+ fprintf(stderr, "value=\"%s\", ", sprop->defaultvalue);
+ print_defult_info(dp);
+ }
+ }
+ }
+ }
+#endif
}
}
@@ -2396,8 +2751,9 @@ void RNA_def_property_collection_sdna(PropertyRNA *prop,
structname = ds->dnaname;
}
+ int dnaoffset = 0;
if (lengthpropname[0] == 0 ||
- rna_find_sdna_member(DefRNA.sdna, structname, lengthpropname, &smember)) {
+ rna_find_sdna_member(DefRNA.sdna, structname, lengthpropname, &smember, &dnaoffset)) {
if (lengthpropname[0] == 0) {
dp->dnalengthfixed = prop->totarraylength;
prop->arraydimension = 0;
diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c
index 30a68a4919e..d7e34ff139c 100644
--- a/source/blender/makesrna/intern/rna_dynamicpaint.c
+++ b/source/blender/makesrna/intern/rna_dynamicpaint.c
@@ -472,7 +472,7 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_antialiasing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DPAINT_ANTIALIAS);
- RNA_def_property_ui_text(prop, "Anti-aliasing", "Use 5x multisampling to smooth paint edges");
+ RNA_def_property_ui_text(prop, "Anti-Aliasing", "Use 5x multisampling to smooth paint edges");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_DynamicPaintSurface_reset");
prop = RNA_def_property(srna, "brush_influence_scale", PROP_FLOAT, PROP_FACTOR);
@@ -610,7 +610,7 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DPAINT_MULALPHA);
RNA_def_property_ui_text(
- prop, "Premultiply alpha", "Multiply color by alpha (recommended for Blender input)");
+ prop, "Premultiply Alpha", "Multiply color by alpha (recommended for Blender input)");
prop = RNA_def_property(srna, "image_output_path", PROP_STRING, PROP_DIRPATH);
RNA_def_property_string_sdna(prop, NULL, "image_output_path");
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 6c546940e6d..254f3bc3710 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -132,6 +132,33 @@ const EnumPropertyItem rna_enum_beztriple_interpolation_easing_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_driver_target_rotation_mode_items[] = {
+ {DTAR_ROTMODE_AUTO, "AUTO", 0, "Auto Euler", "Euler using the rotation order of the target"},
+ {DTAR_ROTMODE_EULER_XYZ, "XYZ", 0, "XYZ Euler", "Euler using the XYZ rotation order"},
+ {DTAR_ROTMODE_EULER_XZY, "XZY", 0, "XZY Euler", "Euler using the XZY rotation order"},
+ {DTAR_ROTMODE_EULER_YXZ, "YXZ", 0, "YXZ Euler", "Euler using the YXZ rotation order"},
+ {DTAR_ROTMODE_EULER_YZX, "YZX", 0, "YZX Euler", "Euler using the YZX rotation order"},
+ {DTAR_ROTMODE_EULER_ZXY, "ZXY", 0, "ZXY Euler", "Euler using the ZXY rotation order"},
+ {DTAR_ROTMODE_EULER_ZYX, "ZYX", 0, "ZYX Euler", "Euler using the ZYX rotation order"},
+ {DTAR_ROTMODE_QUATERNION, "QUATERNION", 0, "Quaternion", "Quaternion rotation"},
+ {DTAR_ROTMODE_SWING_TWIST_X,
+ "SWING_TWIST_X",
+ 0,
+ "Swing and X Twist",
+ "Decompose into a swing rotation to aim the X axis, followed by twist around it"},
+ {DTAR_ROTMODE_SWING_TWIST_Y,
+ "SWING_TWIST_Y",
+ 0,
+ "Swing and Y Twist",
+ "Decompose into a swing rotation to aim the Y axis, followed by twist around it"},
+ {DTAR_ROTMODE_SWING_TWIST_Z,
+ "SWING_TWIST_Z",
+ 0,
+ "Swing and Z Twist",
+ "Decompose into a swing rotation to aim the Z axis, followed by twist around it"},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifdef RNA_RUNTIME
# include "WM_api.h"
@@ -1671,9 +1698,12 @@ static void rna_def_drivertarget(BlenderRNA *brna)
{DTAR_TRANSCHAN_LOCX, "LOC_X", 0, "X Location", ""},
{DTAR_TRANSCHAN_LOCY, "LOC_Y", 0, "Y Location", ""},
{DTAR_TRANSCHAN_LOCZ, "LOC_Z", 0, "Z Location", ""},
+ {0, "", 0, NULL, NULL},
{DTAR_TRANSCHAN_ROTX, "ROT_X", 0, "X Rotation", ""},
{DTAR_TRANSCHAN_ROTY, "ROT_Y", 0, "Y Rotation", ""},
{DTAR_TRANSCHAN_ROTZ, "ROT_Z", 0, "Z Rotation", ""},
+ {DTAR_TRANSCHAN_ROTW, "ROT_W", 0, "W Rotation", ""},
+ {0, "", 0, NULL, NULL},
{DTAR_TRANSCHAN_SCALEX, "SCALE_X", 0, "X Scale", ""},
{DTAR_TRANSCHAN_SCALEY, "SCALE_Y", 0, "Y Scale", ""},
{DTAR_TRANSCHAN_SCALEZ, "SCALE_Z", 0, "Z Scale", ""},
@@ -1749,6 +1779,12 @@ static void rna_def_drivertarget(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Type", "Driver variable type");
RNA_def_property_update(prop, 0, "rna_DriverTarget_update_data");
+ prop = RNA_def_property(srna, "rotation_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "rotation_mode");
+ RNA_def_property_enum_items(prop, rna_enum_driver_target_rotation_mode_items);
+ RNA_def_property_ui_text(prop, "Rotation Mode", "Mode for calculating rotation channel values");
+ RNA_def_property_update(prop, 0, "rna_DriverTarget_update_data");
+
prop = RNA_def_property(srna, "transform_space", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, prop_local_space_items);
diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c
index 5d21e718934..2f09b90a81e 100644
--- a/source/blender/makesrna/intern/rna_fluidsim.c
+++ b/source/blender/makesrna/intern/rna_fluidsim.c
@@ -447,7 +447,7 @@ static void rna_def_fluidsim_domain(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(
prop,
- "Remove air bubbles",
+ "Remove Air Bubbles",
"Removes the air gap between fluid surface and obstacles - WARNING: Can result "
"in a dissolving surface in other areas");
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index bd3321377d3..3ad18fcc7a3 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -151,30 +151,7 @@ static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Pointe
static void rna_GPencil_autolock(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bGPdata *gpd = (bGPdata *)ptr->owner_id;
- bGPDlayer *gpl = NULL;
-
- if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) {
- bGPDlayer *layer = BKE_gpencil_layer_getactive(gpd);
-
- /* Lock all other layers */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* unlock active layer */
- if (gpl == layer) {
- gpl->flag &= ~GP_LAYER_LOCKED;
- }
- else {
- gpl->flag |= GP_LAYER_LOCKED;
- }
- }
- }
- else {
- /* If disable is better unlock all layers by default or it looks there is
- * a problem in the UI because the user expects all layers will be unlocked
- */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- gpl->flag &= ~GP_LAYER_LOCKED;
- }
- }
+ BKE_gpencil_layer_autolock_set(gpd, true);
/* standard update */
rna_GPencil_update(bmain, scene, ptr);
@@ -1884,7 +1861,7 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "onion_keytype");
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_enum_items(prop, rna_enum_onion_keyframe_type_items);
- RNA_def_property_ui_text(prop, "Filter By Type", "Type of keyframe (for filtering)");
+ RNA_def_property_ui_text(prop, "Filter by Type", "Type of keyframe (for filtering)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "use_onion_fade", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 0b40cc9f7f9..d3094eca9fd 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -133,6 +133,16 @@ static const EnumPropertyItem modifier_modify_color_items[] = {
{0, NULL, 0, NULL, NULL},
};
+static const EnumPropertyItem modifier_opacity_mode_items[] = {
+ {GP_OPACITY_MODE_MATERIAL,
+ "MATERIAL",
+ 0,
+ "Material",
+ "Modify opacity using alpha channel of material"},
+ {GP_OPACITY_MODE_STRENGTH, "STRENGTH", 0, "Strength", "Modify opacity using point strength"},
+ {0, NULL, 0, NULL, NULL},
+};
+
static const EnumPropertyItem modifier_gphook_falloff_items[] = {
{eGPHook_Falloff_None, "NONE", 0, "No Falloff", ""},
{eGPHook_Falloff_Curve, "CURVE", 0, "Curve", ""},
@@ -1164,6 +1174,11 @@ static void rna_def_modifier_gpencilopacity(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Mode", "Set what colors of the stroke are affected");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "opacity_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, modifier_opacity_mode_items);
+ RNA_def_property_ui_text(prop, "Opacity Mode", "Set what mode used to define opacity");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "layername");
RNA_def_property_ui_text(prop, "Layer", "Layer name");
@@ -1358,7 +1373,7 @@ static void rna_def_modifier_gpencilinstance(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_KEEP_ONTOP);
RNA_def_property_ui_text(
prop,
- "Keep On Top",
+ "Keep on Top",
"Keep the original stroke in front of new instances (only affect by layer)");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
}
@@ -1734,7 +1749,7 @@ static void rna_def_modifier_gpencilhook(BlenderRNA *brna)
prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_HOOK_INVERT_VGROUP);
- RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_ui_text(prop, "Inverse Vertex Group", "Inverse filter");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
@@ -1770,7 +1785,7 @@ static void rna_def_modifier_gpencilhook(BlenderRNA *brna)
prop = RNA_def_property(srna, "falloff_curve", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "curfalloff");
- RNA_def_property_ui_text(prop, "Falloff Curve", "Custom Light Falloff Curve");
+ RNA_def_property_ui_text(prop, "Falloff Curve", "Custom light falloff curve");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "center", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 26f25e4988d..04a59a48b63 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -74,6 +74,11 @@ typedef struct PropertyDefRNA {
const char *dnatype;
int dnaarraylength;
int dnapointerlevel;
+ /**
+ * Offset in bytes within `dnastructname`.
+ * -1 when unusable (follows pointer for e.g.). */
+ int dnaoffset;
+ int dnasize;
/* for finding length of array collections */
const char *dnalengthstructname;
@@ -223,7 +228,7 @@ bool rna_AnimaData_override_apply(struct Main *bmain,
void rna_def_animviz_common(struct StructRNA *srna);
void rna_def_motionpath_common(struct StructRNA *srna);
-void rna_def_bone_curved_common(struct StructRNA *srna, bool is_posebone);
+void rna_def_bone_curved_common(struct StructRNA *srna, bool is_posebone, bool is_editbone);
void rna_def_texmat_common(struct StructRNA *srna, const char *texspace_editable);
void rna_def_mtex_common(struct BlenderRNA *brna,
@@ -543,6 +548,11 @@ PointerRNA rna_array_lookup_int(
/* Duplicated code since we can't link in blenlib */
+#ifndef RNA_RUNTIME
+void *rna_alloc_from_buffer(const char *buffer, int buffer_len);
+void *rna_calloc(int buffer_len);
+#endif
+
void rna_addtail(struct ListBase *listbase, void *vlink);
void rna_freelinkN(struct ListBase *listbase, void *vlink);
void rna_freelistN(struct ListBase *listbase);
diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c
index 1ad006cbc37..bab7375f01b 100644
--- a/source/blender/makesrna/intern/rna_layer.c
+++ b/source/blender/makesrna/intern/rna_layer.c
@@ -120,6 +120,26 @@ static IDProperty *rna_ViewLayer_idprops(PointerRNA *ptr, bool create)
return view_layer->id_properties;
}
+static bool rna_LayerCollection_visible_get(LayerCollection *layer_collection, bContext *C)
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ const bool runtime_visible = (layer_collection->runtime_flag & LAYER_COLLECTION_VISIBLE) != 0;
+
+ if (v3d == NULL) {
+ return runtime_visible;
+ }
+
+ if ((v3d->flag & V3D_LOCAL_COLLECTIONS) == 0) {
+ return runtime_visible;
+ }
+
+ if (v3d->local_collections_uuid & layer_collection->local_collections_bits) {
+ return true;
+ }
+
+ return false;
+}
+
static void rna_ViewLayer_update_render_passes(ID *id)
{
Scene *scene = (Scene *)id;
@@ -156,7 +176,10 @@ static PointerRNA rna_ViewLayer_depsgraph_get(PointerRNA *ptr)
if (GS(id->name) == ID_SCE) {
Scene *scene = (Scene *)id;
ViewLayer *view_layer = (ViewLayer *)ptr->data;
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false);
+ // NOTE: We don't allocate new depsgraph here, so the bmain is ignored. So it's easier to pass
+ // NULL.
+ // Still weak though.
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(NULL, scene, view_layer, false);
return rna_pointer_inherit_refine(ptr, &RNA_Depsgraph, depsgraph);
}
return PointerRNA_NULL;
@@ -177,7 +200,7 @@ static void rna_ViewLayer_update_tagged(ID *id_ptr, ViewLayer *view_layer, Main
# endif
Scene *scene = (Scene *)id_ptr;
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
/* NOTE: This is similar to CTX_data_depsgraph_pointer(). Ideally such access would be
* de-duplicated across all possible cases, but for now this is safest and easiest way to go.
*
@@ -383,6 +406,13 @@ static void rna_def_layer_collection(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Hide in Viewport", "Temporarily hide in viewport");
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollection_update");
+ func = RNA_def_function(srna, "visible_get", "rna_LayerCollection_visible_get");
+ RNA_def_function_ui_description(func,
+ "Whether this collection is visible, take into account the "
+ "collection parent and the viewport");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_return(func, RNA_def_boolean(func, "result", 0, "", ""));
+
/* Run-time flags. */
prop = RNA_def_property(srna, "is_visible", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "runtime_flag", LAYER_COLLECTION_VISIBLE);
diff --git a/source/blender/makesrna/intern/rna_light.c b/source/blender/makesrna/intern/rna_light.c
index 8640c35f1b8..ecee413a8e0 100644
--- a/source/blender/makesrna/intern/rna_light.c
+++ b/source/blender/makesrna/intern/rna_light.c
@@ -150,7 +150,6 @@ static void rna_def_light(BlenderRNA *brna)
prop = RNA_def_property(srna, "specular_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "spec_fac");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_range(prop, 0.0f, 9999.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01, 2);
RNA_def_property_ui_text(prop, "Specular Factor", "Specular reflection multiplier");
@@ -165,7 +164,6 @@ static void rna_def_light(BlenderRNA *brna)
prop = RNA_def_property(srna, "cutoff_distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "att_dist");
- RNA_def_property_float_default(prop, 40.0f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.01f, 100.0f, 1.0, 2);
RNA_def_property_ui_text(
@@ -196,7 +194,6 @@ static void rna_def_light_energy(StructRNA *srna, bool distant)
/* Distant light strength has no unit defined, it's proportional to
* Watt/m^2 and is not sensitive to scene unit scale. */
prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_default(prop, 10.0f);
RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
RNA_def_property_ui_text(prop, "Strength", "Amount of light emitted");
RNA_def_property_update(prop, 0, "rna_Light_draw_update");
@@ -205,7 +202,6 @@ static void rna_def_light_energy(StructRNA *srna, bool distant)
/* Lights with a location have power in Watt, which is sensitive to
* scene unit scale. */
prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_POWER);
- RNA_def_property_float_default(prop, 10.0f);
RNA_def_property_ui_range(prop, 0.0f, 1000000.0f, 10, 5);
RNA_def_property_ui_text(prop, "Power", "Amount of light emitted");
RNA_def_property_update(prop, 0, "rna_Light_draw_update");
@@ -289,7 +285,6 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
prop = RNA_def_property(srna, "shadow_buffer_clip_start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "clipsta");
- RNA_def_property_float_default(prop, 0.05f);
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_ui_text(prop,
@@ -297,46 +292,13 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
"Shadow map clip start, below which objects will not generate shadows");
RNA_def_property_update(prop, 0, "rna_Light_draw_update");
- prop = RNA_def_property(srna, "shadow_buffer_clip_end", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_sdna(prop, NULL, "clipend");
- RNA_def_property_float_default(prop, 40.0f);
- RNA_def_property_range(prop, 1e-6f, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
- RNA_def_property_ui_text(prop,
- "Shadow Buffer Clip End",
- "Shadow map clip end, beyond which objects will not generate shadows");
- RNA_def_property_update(prop, 0, "rna_Light_draw_update");
-
prop = RNA_def_property(srna, "shadow_buffer_bias", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bias");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_range(prop, 0.001f, 9999.0f);
RNA_def_property_ui_range(prop, 0.001f, 5.0f, 1.0, 3);
RNA_def_property_ui_text(prop, "Shadow Buffer Bias", "Bias for reducing self shadowing");
RNA_def_property_update(prop, 0, "rna_Light_update");
- prop = RNA_def_property(srna, "shadow_buffer_bleed_bias", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "bleedbias");
- RNA_def_property_range(prop, 0.f, 1.f);
- RNA_def_property_ui_text(
- prop, "Shadow Buffer Bleed Bias", "Bias for reducing light-bleed on variance shadow maps");
- RNA_def_property_update(prop, 0, "rna_Light_update");
-
- prop = RNA_def_property(srna, "shadow_buffer_exp", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "bleedexp");
- RNA_def_property_float_default(prop, 2.5f);
- RNA_def_property_range(prop, 1.0f, 9999.0f);
- RNA_def_property_ui_text(
- prop, "Shadow Buffer Exponent", "Bias for reducing light-bleed on exponential shadow maps");
- RNA_def_property_update(prop, 0, "rna_Light_update");
-
- prop = RNA_def_property(srna, "shadow_buffer_soft", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "soft");
- RNA_def_property_float_default(prop, 3.0f);
- RNA_def_property_range(prop, 0.0f, 100.0f);
- RNA_def_property_ui_text(prop, "Shadow Buffer Soft", "Size of shadow buffer sampling area");
- RNA_def_property_update(prop, 0, "rna_Light_update");
-
prop = RNA_def_property(srna, "shadow_buffer_samples", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "samp");
RNA_def_property_range(prop, 1, 16);
@@ -351,7 +313,6 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
prop = RNA_def_property(srna, "shadow_soft_size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "area_size");
- RNA_def_property_float_default(prop, 0.25f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 100, 0.1, 3);
RNA_def_property_ui_text(
@@ -370,7 +331,6 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
prop = RNA_def_property(srna, "contact_shadow_distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "contact_dist");
- RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_range(prop, 0.0f, 9999.0f);
RNA_def_property_ui_text(prop,
"Contact Shadow Distance",
@@ -380,23 +340,13 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
prop = RNA_def_property(srna, "contact_shadow_bias", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "contact_bias");
- RNA_def_property_float_default(prop, 0.03f);
RNA_def_property_range(prop, 0.001f, 9999.0f);
RNA_def_property_ui_range(prop, 0.001f, 5.0f, 1.0, 3);
RNA_def_property_ui_text(prop, "Contact Shadow Bias", "Bias to avoid self shadowing");
RNA_def_property_update(prop, 0, "rna_Light_update");
- prop = RNA_def_property(srna, "contact_shadow_soft_size", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "contact_spread");
- RNA_def_property_float_default(prop, 0.2f);
- RNA_def_property_range(prop, 0.0f, 9999.0f);
- RNA_def_property_ui_text(
- prop, "Contact Shadow Soft", "Control how soft the contact shadows will be");
- RNA_def_property_update(prop, 0, "rna_Light_update");
-
prop = RNA_def_property(srna, "contact_shadow_thickness", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "contact_thickness");
- RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_range(prop, 0.0f, 9999.0f);
RNA_def_property_ui_range(prop, 0, 100, 0.1, 3);
RNA_def_property_ui_text(
@@ -406,7 +356,6 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
if (sun) {
prop = RNA_def_property(srna, "shadow_cascade_max_distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "cascade_max_dist");
- RNA_def_property_float_default(prop, 200.0f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_text(prop,
"Cascade Max Distance",
@@ -415,7 +364,6 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
prop = RNA_def_property(srna, "shadow_cascade_count", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "cascade_count");
- RNA_def_property_int_default(prop, 4);
RNA_def_property_range(prop, 1, 4);
RNA_def_property_ui_text(
prop, "Cascade Count", "Number of texture used by the cascaded shadow map");
@@ -423,7 +371,6 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
prop = RNA_def_property(srna, "shadow_cascade_exponent", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "cascade_exponent");
- RNA_def_property_float_default(prop, 0.8f);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop,
"Exponential Distribution",
@@ -432,7 +379,6 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
prop = RNA_def_property(srna, "shadow_cascade_fade", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "cascade_fade");
- RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(
prop, "Cascade Fade", "How smooth is the transition between each cascade");
@@ -484,7 +430,6 @@ static void rna_def_area_light(BlenderRNA *brna)
prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "area_size");
- RNA_def_property_float_default(prop, 0.25f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 100, 0.1, 3);
RNA_def_property_ui_text(
@@ -493,7 +438,6 @@ static void rna_def_area_light(BlenderRNA *brna)
prop = RNA_def_property(srna, "size_y", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "area_sizey");
- RNA_def_property_float_default(prop, 0.25f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 100, 0.1, 3);
RNA_def_property_ui_text(
@@ -524,14 +468,12 @@ static void rna_def_spot_light(BlenderRNA *brna)
prop = RNA_def_property(srna, "spot_blend", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "spotblend");
- RNA_def_property_float_default(prop, 0.15f);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Spot Blend", "The softness of the spotlight edge");
RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "spot_size", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "spotsize");
- RNA_def_property_float_default(prop, DEG2RADF(45.0f));
RNA_def_property_range(prop, DEG2RADF(1.0f), DEG2RADF(180.0f));
RNA_def_property_ui_text(prop, "Spot Size", "Angle of the spotlight beam");
RNA_def_property_update(prop, 0, "rna_Light_draw_update");
@@ -557,7 +499,6 @@ static void rna_def_sun_light(BlenderRNA *brna)
prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "sun_angle");
- RNA_def_property_float_default(prop, DEG2RADF(0.526f));
RNA_def_property_range(prop, DEG2RADF(0.0f), DEG2RADF(180.0f));
RNA_def_property_ui_text(prop, "Angle", "Angular diameter of the Sun as seen from the Earth");
RNA_def_property_update(prop, 0, "rna_Light_update");
diff --git a/source/blender/makesrna/intern/rna_lightprobe.c b/source/blender/makesrna/intern/rna_lightprobe.c
index 463cefdf3f0..d448bdd9401 100644
--- a/source/blender/makesrna/intern/rna_lightprobe.c
+++ b/source/blender/makesrna/intern/rna_lightprobe.c
@@ -86,7 +86,6 @@ static void rna_def_lightprobe(BlenderRNA *brna)
prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "clipsta");
- RNA_def_property_float_default(prop, 0.8f);
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_ui_text(
@@ -95,7 +94,6 @@ static void rna_def_lightprobe(BlenderRNA *brna)
prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "clipend");
- RNA_def_property_float_default(prop, 40.0f);
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_ui_text(
@@ -120,13 +118,11 @@ static void rna_def_lightprobe(BlenderRNA *brna)
prop = RNA_def_property(srna, "influence_distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "distinf");
- RNA_def_property_float_default(prop, 2.5f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_text(prop, "Influence Distance", "Influence distance of the probe");
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
prop = RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Falloff", "Control how fast the probe influence decreases");
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
@@ -149,7 +145,6 @@ static void rna_def_lightprobe(BlenderRNA *brna)
prop = RNA_def_property(srna, "parallax_distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "distpar");
- RNA_def_property_float_default(prop, 2.5f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_text(prop, "Parallax Radius", "Lowest corner of the parallax bounding box");
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
@@ -157,28 +152,24 @@ static void rna_def_lightprobe(BlenderRNA *brna)
/* irradiance grid */
prop = RNA_def_property(srna, "grid_resolution_x", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 1, 256);
- RNA_def_property_int_default(prop, 4);
RNA_def_property_ui_text(
prop, "Resolution X", "Number of sample along the x axis of the volume");
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
prop = RNA_def_property(srna, "grid_resolution_y", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 1, 256);
- RNA_def_property_int_default(prop, 4);
RNA_def_property_ui_text(
prop, "Resolution Y", "Number of sample along the y axis of the volume");
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
prop = RNA_def_property(srna, "grid_resolution_z", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 1, 256);
- RNA_def_property_int_default(prop, 4);
RNA_def_property_ui_text(
prop, "Resolution Z", "Number of sample along the z axis of the volume");
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
prop = RNA_def_property(srna, "visibility_buffer_bias", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "vis_bias");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_range(prop, 0.001f, 9999.0f);
RNA_def_property_ui_range(prop, 0.001f, 5.0f, 1.0, 3);
RNA_def_property_ui_text(prop, "Visibility Bias", "Bias for reducing self shadowing");
@@ -186,7 +177,6 @@ static void rna_def_lightprobe(BlenderRNA *brna)
prop = RNA_def_property(srna, "visibility_bleed_bias", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "vis_bleedbias");
- RNA_def_property_float_default(prop, 0.0f);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(
prop, "Visibility Bleed Bias", "Bias for reducing light-bleed on variance shadow maps");
@@ -194,14 +184,12 @@ static void rna_def_lightprobe(BlenderRNA *brna)
prop = RNA_def_property(srna, "visibility_blur", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "vis_blur");
- RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Visibility Blur", "Filter size of the visibility blur");
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
prop = RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "intensity");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0f, 3.0f, 1.0, 3);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c
index f6cfc33c82e..f5730885193 100644
--- a/source/blender/makesrna/intern/rna_linestyle.c
+++ b/source/blender/makesrna/intern/rna_linestyle.c
@@ -2179,7 +2179,7 @@ static void rna_def_linestyle(BlenderRNA *brna)
prop = RNA_def_property(srna, "texture_spacing", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "texstep");
RNA_def_property_range(prop, 0.01f, 100.0f);
- RNA_def_property_ui_text(prop, "Texture spacing", "Spacing for textures along stroke length");
+ RNA_def_property_ui_text(prop, "Texture Spacing", "Spacing for textures along stroke length");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
/* anim */
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index 8f627ce36ef..9da17c5f0b1 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -370,7 +370,6 @@ static void rna_def_material_display(StructRNA *srna)
prop = RNA_def_property(srna, "roughness", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "roughness");
- RNA_def_property_float_default(prop, 0.25f);
RNA_def_property_range(prop, 0, 1);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Roughness", "Roughness of the material");
@@ -378,7 +377,6 @@ static void rna_def_material_display(StructRNA *srna)
prop = RNA_def_property(srna, "specular_intensity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "spec");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0, 1);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Specular", "How intense (bright) the specular reflection is");
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 81480eda4d6..d5fc422a9f9 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -55,6 +55,12 @@ const EnumPropertyItem rna_enum_mesh_delimit_mode_items[] = {
{0, NULL, 0, NULL, NULL},
};
+static const EnumPropertyItem rna_enum_mesh_remesh_mode_items[] = {
+ {REMESH_VOXEL, "VOXEL", 0, "Voxel", "Use the voxel remesher"},
+ {REMESH_QUAD, "QUAD", 0, "Quad", "Use the quad remesher"},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifdef RNA_RUNTIME
# include "DNA_scene_types.h"
@@ -497,9 +503,7 @@ static void rna_Mesh_texspace_size_get(PointerRNA *ptr, float values[3])
{
Mesh *me = (Mesh *)ptr->data;
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
+ BKE_mesh_texspace_ensure(me);
copy_v3_v3(values, me->size);
}
@@ -508,9 +512,7 @@ static void rna_Mesh_texspace_loc_get(PointerRNA *ptr, float values[3])
{
Mesh *me = (Mesh *)ptr->data;
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
+ BKE_mesh_texspace_ensure(me);
copy_v3_v3(values, me->loc);
}
@@ -541,7 +543,7 @@ static void rna_MeshVertex_undeformed_co_get(PointerRNA *ptr, float values[3])
/* orco is normalized to 0..1, we do inverse to match mvert->co */
float loc[3], size[3];
- BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, NULL, size);
+ BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, size);
madd_v3_v3v3v3(values, loc, orco[(mvert - me->mvert)], size);
}
else {
@@ -1370,7 +1372,7 @@ static int rna_MeshPolygonStringPropertyLayer_data_length(PointerRNA *ptr)
}
/* XXX, we dont have proper byte string support yet, so for now use the (bytes + 1)
- * bmesh API exposes correct python/bytestring access */
+ * bmesh API exposes correct python/byte-string access. */
void rna_MeshStringProperty_s_get(PointerRNA *ptr, char *value)
{
MStringProperty *ms = (MStringProperty *)ptr->data;
@@ -2205,15 +2207,6 @@ void rna_def_texmat_common(StructRNA *srna, const char *texspace_editable)
RNA_def_property_editable_func(prop, texspace_editable);
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
- /* not supported yet */
-# if 0
- prop = RNA_def_property(srna, "texspace_rot", PROP_FLOAT, PROP_EULER);
- RNA_def_property_float(prop, NULL, "rot");
- RNA_def_property_ui_text(prop, "Texture Space Rotation", "Texture space rotation");
- RNA_def_property_editable_func(prop, texspace_editable);
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-# endif
-
/* materials */
prop = RNA_def_property(srna, "materials", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol");
@@ -2421,7 +2414,7 @@ static void rna_def_uv_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_pointer_funcs(
prop, "rna_Mesh_uv_layer_active_get", "rna_Mesh_uv_layer_active_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK);
- RNA_def_property_ui_text(prop, "Active UV loop layer", "Active UV loop layer");
+ RNA_def_property_ui_text(prop, "Active UV Loop Layer", "Active UV loop layer");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
@@ -2429,7 +2422,7 @@ static void rna_def_uv_layers(BlenderRNA *brna, PropertyRNA *cprop)
"rna_Mesh_uv_layer_active_index_get",
"rna_Mesh_uv_layer_active_index_set",
"rna_Mesh_uv_layer_index_range");
- RNA_def_property_ui_text(prop, "Active UV loop layer Index", "Active UV loop layer index");
+ RNA_def_property_ui_text(prop, "Active UV Loop Layer Index", "Active UV loop layer index");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
}
@@ -2809,28 +2802,28 @@ static void rna_def_mesh(BlenderRNA *brna)
prop, "rna_Mesh_uv_layer_clone_get", "rna_Mesh_uv_layer_clone_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
- prop, "Clone UV loop layer", "UV loop layer to be used as cloning source");
+ prop, "Clone UV Loop Layer", "UV loop layer to be used as cloning source");
prop = RNA_def_property(srna, "uv_layer_clone_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop,
"rna_Mesh_uv_layer_clone_index_get",
"rna_Mesh_uv_layer_clone_index_set",
"rna_Mesh_uv_layer_index_range");
- RNA_def_property_ui_text(prop, "Clone UV loop layer Index", "Clone UV loop layer index");
+ RNA_def_property_ui_text(prop, "Clone UV Loop Layer Index", "Clone UV loop layer index");
prop = RNA_def_property(srna, "uv_layer_stencil", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshUVLoopLayer");
RNA_def_property_pointer_funcs(
prop, "rna_Mesh_uv_layer_stencil_get", "rna_Mesh_uv_layer_stencil_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Mask UV loop layer", "UV loop layer to mask the painted area");
+ RNA_def_property_ui_text(prop, "Mask UV Loop Layer", "UV loop layer to mask the painted area");
prop = RNA_def_property(srna, "uv_layer_stencil_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop,
"rna_Mesh_uv_layer_stencil_index_get",
"rna_Mesh_uv_layer_stencil_index_set",
"rna_Mesh_uv_layer_index_range");
- RNA_def_property_ui_text(prop, "Mask UV loop layer Index", "Mask UV loop layer index");
+ RNA_def_property_ui_text(prop, "Mask UV Loop Layer Index", "Mask UV loop layer index");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
/* Vertex colors */
@@ -2994,18 +2987,41 @@ static void rna_def_mesh(BlenderRNA *brna)
/* Remesh */
prop = RNA_def_property(srna, "remesh_voxel_size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "remesh_voxel_size");
- RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_range(prop, 0.00001f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0001f, FLT_MAX, 0.01, 4);
RNA_def_property_ui_text(prop,
- "Voxel size",
+ "Voxel Size",
"Size of the voxel in object space used for volume evaluation. Lower "
"values preserve finer details");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+ prop = RNA_def_property(srna, "remesh_voxel_adaptivity", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "remesh_voxel_adaptivity");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01, 4);
+ RNA_def_property_ui_text(
+ prop,
+ "Adaptivity",
+ "Reduces the final face count by simplifying geometry where detail is not needed, "
+ "generating triangles. A value greater than 0 disables Fix Poles");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+
prop = RNA_def_property(srna, "remesh_smooth_normals", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_SMOOTH_NORMALS);
- RNA_def_property_ui_text(prop, "Smooth normals", "Smooth the normals of the remesher result");
+ RNA_def_property_ui_text(prop, "Smooth Normals", "Smooth the normals of the remesher result");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+
+ prop = RNA_def_property(srna, "remesh_fix_poles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_FIX_POLES);
+ RNA_def_property_ui_text(prop, "Fix Poles", "Produces less poles and a better topology flow");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+
+ prop = RNA_def_property(srna, "remesh_preserve_volume", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_REPROJECT_VOLUME);
+ RNA_def_property_ui_text(
+ prop,
+ "Preserve Volume",
+ "Projects the mesh to preserve the volume and details of the original mesh");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
prop = RNA_def_property(srna, "remesh_preserve_paint_mask", PROP_BOOLEAN, PROP_NONE);
@@ -3013,6 +3029,13 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_boolean_default(prop, false);
RNA_def_property_ui_text(prop, "Preserve Paint Mask", "Keep the current mask on the new mesh");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+
+ prop = RNA_def_property(srna, "remesh_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "remesh_mode");
+ RNA_def_property_enum_items(prop, rna_enum_mesh_remesh_mode_items);
+ RNA_def_property_ui_text(prop, "Remesh Mode", "");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+
/* End remesh */
prop = RNA_def_property(srna, "use_auto_smooth", PROP_BOOLEAN, PROP_NONE);
@@ -3026,7 +3049,6 @@ static void rna_def_mesh(BlenderRNA *brna)
prop = RNA_def_property(srna, "auto_smooth_angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "smoothresh");
- RNA_def_property_float_default(prop, DEG2RADF(180.0f));
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
RNA_def_property_ui_text(prop,
"Auto Smooth Angle",
@@ -3073,22 +3095,12 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
# endif
- /* not supported yet */
-# if 0
- prop = RNA_def_property(srna, "texspace_rot", PROP_FLOAT, PROP_EULER);
- RNA_def_property_float(prop, NULL, "rot");
- RNA_def_property_ui_text(prop, "Texture Space Rotation", "Texture space rotation");
- RNA_def_property_editable_func(prop, texspace_editable);
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-# endif
-
/* editflag */
prop = RNA_def_property(srna, "use_mirror_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_MIRROR_X);
RNA_def_property_ui_text(prop, "X Mirror", "X Axis mirror editing");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-# if 0
prop = RNA_def_property(srna, "use_mirror_y", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_MIRROR_Y);
RNA_def_property_ui_text(prop, "Y Mirror", "Y Axis mirror editing");
@@ -3096,7 +3108,6 @@ static void rna_def_mesh(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_mirror_z", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_MIRROR_Z);
RNA_def_property_ui_text(prop, "Z Mirror", "Z Axis mirror editing");
-# endif
prop = RNA_def_property(srna, "use_mirror_topology", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_MIRROR_TOPO);
diff --git a/source/blender/makesrna/intern/rna_meta.c b/source/blender/makesrna/intern/rna_meta.c
index 451bdda45f5..2b2a928e280 100644
--- a/source/blender/makesrna/intern/rna_meta.c
+++ b/source/blender/makesrna/intern/rna_meta.c
@@ -332,7 +332,6 @@ static void rna_def_metaball(BlenderRNA *brna)
/* number values */
prop = RNA_def_property(srna, "resolution", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "wiresize");
- RNA_def_property_float_default(prop, 0.4f);
RNA_def_property_range(prop, 0.005f, 10000.0f);
RNA_def_property_ui_range(prop, 0.05f, 1000.0f, 2.5f, 3);
RNA_def_property_ui_text(prop, "Wire Size", "Polygonization resolution in the 3D viewport");
@@ -340,7 +339,6 @@ static void rna_def_metaball(BlenderRNA *brna)
prop = RNA_def_property(srna, "render_resolution", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "rendersize");
- RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_range(prop, 0.005f, 10000.0f);
RNA_def_property_ui_range(prop, 0.025f, 1000.0f, 2.5f, 3);
RNA_def_property_ui_text(prop, "Render Size", "Polygonization resolution in rendering");
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 26bb83fe6e8..2a125625681 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -755,6 +755,47 @@ static void rna_HookModifier_object_set(PointerRNA *ptr,
BKE_object_modifier_hook_reset(owner, hmd);
}
+static bool rna_HookModifier_object_override_apply(Main *UNUSED(bmain),
+ PointerRNA *ptr_dst,
+ PointerRNA *ptr_src,
+ PointerRNA *ptr_storage,
+ PropertyRNA *prop_dst,
+ PropertyRNA *prop_src,
+ PropertyRNA *UNUSED(prop_storage),
+ const int len_dst,
+ const int len_src,
+ const int len_storage,
+ PointerRNA *UNUSED(ptr_item_dst),
+ PointerRNA *UNUSED(ptr_item_src),
+ PointerRNA *UNUSED(ptr_item_storage),
+ IDOverrideLibraryPropertyOperation *opop)
+{
+ BLI_assert(len_dst == len_src && (!ptr_storage || len_dst == len_storage) && len_dst == 0);
+ BLI_assert(opop->operation == IDOVERRIDE_LIBRARY_OP_REPLACE &&
+ "Unsupported RNA override operation on Hook modifier target objet pointer");
+ UNUSED_VARS_NDEBUG(ptr_storage, len_dst, len_src, len_storage, opop);
+
+ /* We need a special handling here because setting hook target resets invert parent matrix,
+ * which is evil in our case. */
+ HookModifierData *hmd = ptr_dst->data;
+ Object *owner = (Object *)ptr_dst->owner_id;
+ Object *target_dst = RNA_property_pointer_get(ptr_dst, prop_dst).data;
+ Object *target_src = RNA_property_pointer_get(ptr_src, prop_src).data;
+
+ BLI_assert(target_dst == hmd->object);
+
+ if (target_src == target_dst) {
+ return false;
+ }
+
+ hmd->object = target_src;
+ if (target_src == NULL) {
+ /* The only case where we do want default behavior (with matrix reset). */
+ BKE_object_modifier_hook_reset(owner, hmd);
+ }
+ return true;
+}
+
static void rna_HookModifier_subtarget_set(PointerRNA *ptr, const char *value)
{
Object *owner = (Object *)ptr->owner_id;
@@ -874,7 +915,7 @@ static void rna_MultiresModifier_type_set(PointerRNA *ptr, int value)
Object *ob = (Object *)ptr->owner_id;
MultiresModifierData *mmd = (MultiresModifierData *)ptr->data;
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
mmd->simple = value;
}
@@ -1346,7 +1387,7 @@ static void rna_CorrectiveSmoothModifier_update(Main *bmain, Scene *scene, Point
{
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)ptr->data;
- MEM_SAFE_FREE(csmd->delta_cache);
+ MEM_SAFE_FREE(csmd->delta_cache.deltas);
rna_Modifier_update(bmain, scene, ptr);
}
@@ -2021,7 +2062,7 @@ static void rna_def_modifier_decimate(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_dissolve_boundaries", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_DECIM_FLAG_ALL_BOUNDARY_VERTS);
RNA_def_property_ui_text(
- prop, "All Boundaries", "Dissolve all vertices inbetween face boundaries (planar only)");
+ prop, "All Boundaries", "Dissolve all vertices in between face boundaries (planar only)");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "delimit", PROP_ENUM, PROP_NONE);
@@ -2289,6 +2330,7 @@ static void rna_def_modifier_hook(BlenderRNA *brna)
prop, "Object", "Parent Object for hook, also recalculates and clears offset");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_override_funcs(prop, NULL, NULL, "rna_HookModifier_object_override_apply");
RNA_def_property_pointer_funcs(prop, NULL, "rna_HookModifier_object_set", NULL, NULL);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
@@ -3040,7 +3082,7 @@ static void rna_def_modifier_cast(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_transform", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_CAST_USE_OB_TRANSFORM);
RNA_def_property_ui_text(
- prop, "Use transform", "Use object transform to control projection shape");
+ prop, "Use Transform", "Use object transform to control projection shape");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_FACTOR);
@@ -5862,7 +5904,7 @@ static void rna_def_modifier_surfacedeform(BlenderRNA *brna)
prop = RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 2.0f, 16.0f);
RNA_def_property_ui_text(
- prop, "Interpolation falloff", "Controls how much nearby polygons influence deformation");
+ prop, "Interpolation Falloff", "Controls how much nearby polygons influence deformation");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "is_bound", PROP_BOOLEAN, PROP_NONE);
@@ -6013,7 +6055,7 @@ void RNA_def_modifier(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_ApplyOnSpline);
RNA_def_property_ui_text(
prop,
- "Apply on spline",
+ "Apply on Spline",
"Apply this and all preceding deformation modifiers on splines' points rather than "
"on filled curve/surface");
RNA_def_property_ui_icon(prop, ICON_SURFACE_DATA, 0);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 0909aa42a4d..48562cf2684 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -102,6 +102,26 @@ static const EnumPropertyItem node_chunksize_items[] = {
};
#endif
+const EnumPropertyItem rna_enum_mapping_type_items[] = {
+ {NODE_MAPPING_TYPE_POINT, "POINT", 0, "Point", "Transform a point"},
+ {NODE_MAPPING_TYPE_TEXTURE,
+ "TEXTURE",
+ 0,
+ "Texture",
+ "Transform a texture by inverse mapping the texture coordinate"},
+ {NODE_MAPPING_TYPE_VECTOR,
+ "VECTOR",
+ 0,
+ "Vector",
+ "Transform a direction vector. Location is ignored"},
+ {NODE_MAPPING_TYPE_NORMAL,
+ "NORMAL",
+ 0,
+ "Normal",
+ "Transform a unit normal vector. Location is ignored"},
+ {0, NULL, 0, NULL, NULL},
+};
+
const EnumPropertyItem rna_enum_node_math_items[] = {
{NODE_MATH_ADD, "ADD", 0, "Add", "A + B"},
{NODE_MATH_SUBTRACT, "SUBTRACT", 0, "Subtract", "A - B"},
@@ -246,7 +266,7 @@ int rna_node_tree_type_to_enum(bNodeTreeType *typeinfo)
result = i;
break;
}
- ++i;
+ i++;
}
NODE_TREE_TYPES_END;
return result;
@@ -260,7 +280,7 @@ int rna_node_tree_idname_to_enum(const char *idname)
result = i;
break;
}
- ++i;
+ i++;
}
NODE_TREE_TYPES_END;
return result;
@@ -275,7 +295,7 @@ bNodeTreeType *rna_node_tree_type_from_enum(int value)
result = nt;
break;
}
- ++i;
+ i++;
}
NODE_TREE_TYPES_END;
return result;
@@ -291,7 +311,7 @@ const EnumPropertyItem *rna_node_tree_type_itemf(void *data,
NODE_TREE_TYPES_BEGIN (nt) {
if (poll && !poll(data, nt)) {
- ++i;
+ i++;
continue;
}
@@ -303,7 +323,7 @@ const EnumPropertyItem *rna_node_tree_type_itemf(void *data,
RNA_enum_item_add(&item, &totitem, &tmp);
- ++i;
+ i++;
}
NODE_TREE_TYPES_END;
@@ -326,7 +346,7 @@ int rna_node_type_to_enum(bNodeType *typeinfo)
result = i;
break;
}
- ++i;
+ i++;
}
NODE_TYPES_END;
return result;
@@ -340,7 +360,7 @@ int rna_node_idname_to_enum(const char *idname)
result = i;
break;
}
- ++i;
+ i++;
}
NODE_TYPES_END;
return result;
@@ -355,7 +375,7 @@ bNodeType *rna_node_type_from_enum(int value)
result = ntype;
break;
}
- ++i;
+ i++;
}
NODE_TYPES_END;
return result;
@@ -371,7 +391,7 @@ const EnumPropertyItem *rna_node_type_itemf(void *data,
NODE_TYPES_BEGIN (ntype) {
if (poll && !poll(data, ntype)) {
- ++i;
+ i++;
continue;
}
@@ -383,7 +403,7 @@ const EnumPropertyItem *rna_node_type_itemf(void *data,
RNA_enum_item_add(&item, &totitem, &tmp);
- ++i;
+ i++;
}
NODE_TYPES_END;
@@ -406,7 +426,7 @@ int rna_node_socket_type_to_enum(bNodeSocketType *typeinfo)
result = i;
break;
}
- ++i;
+ i++;
}
NODE_SOCKET_TYPES_END;
return result;
@@ -420,7 +440,7 @@ int rna_node_socket_idname_to_enum(const char *idname)
result = i;
break;
}
- ++i;
+ i++;
}
NODE_SOCKET_TYPES_END;
return result;
@@ -435,7 +455,7 @@ bNodeSocketType *rna_node_socket_type_from_enum(int value)
result = stype;
break;
}
- ++i;
+ i++;
}
NODE_SOCKET_TYPES_END;
return result;
@@ -452,7 +472,7 @@ const EnumPropertyItem *rna_node_socket_type_itemf(void *data,
NODE_SOCKET_TYPES_BEGIN (stype) {
if (poll && !poll(data, stype)) {
- ++i;
+ i++;
continue;
}
@@ -465,7 +485,7 @@ const EnumPropertyItem *rna_node_socket_type_itemf(void *data,
RNA_enum_item_add(&item, &totitem, &tmp);
- ++i;
+ i++;
}
NODE_SOCKET_TYPES_END;
@@ -1462,7 +1482,7 @@ static void rna_Node_draw_label(bNodeTree *ntree, bNode *node, char *label, int
node->typeinfo->ext.call(NULL, &ptr, func, &list);
RNA_parameter_get_lookup(&list, "label", &ret);
- rlabel = *(char **)ret;
+ rlabel = (char *)ret;
BLI_strncpy(label, rlabel != NULL ? rlabel : "", maxlen);
RNA_parameter_list_free(&list);
@@ -2632,8 +2652,8 @@ static PointerRNA rna_NodeInternal_input_template(StructRNA *srna, int index)
bNodeSocketTemplate *stemp = ntype->inputs;
int i = 0;
while (i < index && stemp->type >= 0) {
- ++i;
- ++stemp;
+ i++;
+ stemp++;
}
if (i == index && stemp->type >= 0) {
PointerRNA ptr;
@@ -2651,8 +2671,8 @@ static PointerRNA rna_NodeInternal_output_template(StructRNA *srna, int index)
bNodeSocketTemplate *stemp = ntype->outputs;
int i = 0;
while (i < index && stemp->type >= 0) {
- ++i;
- ++stemp;
+ i++;
+ stemp++;
}
if (i == index && stemp->type >= 0) {
PointerRNA ptr;
@@ -3213,13 +3233,6 @@ static void rna_Image_Node_update_id(Main *UNUSED(bmain), Scene *UNUSED(scene),
nodeUpdate(ntree, node); /* to update image node sockets */
}
-static void rna_Mapping_Node_update(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- bNode *node = ptr->data;
- BKE_texture_mapping_init(node->storage);
- rna_Node_update(bmain, scene, ptr);
-}
-
static void rna_NodeOutputFile_slots_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
bNode *node = ptr->data;
@@ -4034,68 +4047,13 @@ static void def_sh_output_linestyle(StructRNA *srna)
static void def_sh_mapping(StructRNA *srna)
{
- static const EnumPropertyItem prop_vect_type_items[] = {
- {TEXMAP_TYPE_TEXTURE,
- "TEXTURE",
- 0,
- "Texture",
- "Transform a texture by inverse mapping the texture coordinate"},
- {TEXMAP_TYPE_POINT, "POINT", 0, "Point", "Transform a point"},
- {TEXMAP_TYPE_VECTOR, "VECTOR", 0, "Vector", "Transform a direction vector"},
- {TEXMAP_TYPE_NORMAL, "NORMAL", 0, "Normal", "Transform a normal vector with unit length"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static float default_1[3] = {1.f, 1.f, 1.f};
-
PropertyRNA *prop;
- RNA_def_struct_sdna_from(srna, "TexMapping", "storage");
-
prop = RNA_def_property(srna, "vector_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_vect_type_items);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, rna_enum_mapping_type_items);
RNA_def_property_ui_text(prop, "Type", "Type of vector that the mapping transforms");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- prop = RNA_def_property(srna, "translation", PROP_FLOAT, PROP_TRANSLATION);
- RNA_def_property_float_sdna(prop, NULL, "loc");
- RNA_def_property_ui_text(prop, "Location", "");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- /* Not PROP_XYZ, this is now in radians, no more degrees */
- prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_EULER);
- RNA_def_property_float_sdna(prop, NULL, "rot");
- RNA_def_property_ui_text(prop, "Rotation", "");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "size");
- RNA_def_property_float_array_default(prop, default_1);
- RNA_def_property_flag(prop, PROP_PROPORTIONAL);
- RNA_def_property_ui_text(prop, "Scale", "");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- prop = RNA_def_property(srna, "min", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "min");
- RNA_def_property_ui_text(prop, "Minimum", "Minimum value for clipping");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- prop = RNA_def_property(srna, "max", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "max");
- RNA_def_property_float_array_default(prop, default_1);
- RNA_def_property_ui_text(prop, "Maximum", "Maximum value for clipping");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- prop = RNA_def_property(srna, "use_min", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", TEXMAP_CLIP_MIN);
- RNA_def_property_ui_text(prop, "Has Minimum", "Whether to use minimum clipping value");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- prop = RNA_def_property(srna, "use_max", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", TEXMAP_CLIP_MAX);
- RNA_def_property_ui_text(prop, "Has Maximum", "Whether to use maximum clipping value");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
}
static void def_sh_attribute(StructRNA *srna)
@@ -4346,8 +4304,17 @@ static void def_sh_tex_gradient(StructRNA *srna)
static void def_sh_tex_noise(StructRNA *srna)
{
+ PropertyRNA *prop;
+
RNA_def_struct_sdna_from(srna, "NodeTexNoise", "storage");
def_sh_tex(srna);
+
+ prop = RNA_def_property(srna, "noise_dimensions", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "dimensions");
+ RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
+ RNA_def_property_ui_text(
+ prop, "Dimensions", "The dimensions of the space to evaluate the noise in");
+ RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
}
static void def_sh_tex_checker(StructRNA *srna)
@@ -4422,34 +4389,54 @@ static void def_sh_tex_musgrave(StructRNA *srna)
RNA_def_struct_sdna_from(srna, "NodeTexMusgrave", "storage");
def_sh_tex(srna);
+ prop = RNA_def_property(srna, "musgrave_dimensions", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "dimensions");
+ RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
+ RNA_def_property_ui_text(prop, "Dimensions", "");
+ RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
+
prop = RNA_def_property(srna, "musgrave_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "musgrave_type");
RNA_def_property_enum_items(prop, prop_musgrave_type);
RNA_def_property_ui_text(prop, "Type", "");
- RNA_def_property_update(prop, 0, "rna_Node_update");
+ RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
}
static void def_sh_tex_voronoi(StructRNA *srna)
{
- static const EnumPropertyItem prop_coloring_items[] = {
- {SHD_VORONOI_INTENSITY, "INTENSITY", 0, "Intensity", "Only calculate intensity"},
- {SHD_VORONOI_CELLS, "CELLS", 0, "Cells", "Color cells by position"},
- {0, NULL, 0, NULL, NULL},
- };
-
static EnumPropertyItem prop_distance_items[] = {
- {SHD_VORONOI_DISTANCE, "DISTANCE", 0, "Distance", "Distance"},
- {SHD_VORONOI_MANHATTAN, "MANHATTAN", 0, "Manhattan", "Manhattan (city block) distance"},
+ {SHD_VORONOI_EUCLIDEAN, "EUCLIDEAN", 0, "Euclidean", "Euclidean distance"},
+ {SHD_VORONOI_MANHATTAN, "MANHATTAN", 0, "Manhattan", "Manhattan distance"},
{SHD_VORONOI_CHEBYCHEV, "CHEBYCHEV", 0, "Chebychev", "Chebychev distance"},
{SHD_VORONOI_MINKOWSKI, "MINKOWSKI", 0, "Minkowski", "Minkowski distance"},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem prop_feature_items[] = {
- {SHD_VORONOI_F1, "F1", 0, "Closest", "Closest point"},
- {SHD_VORONOI_F2, "F2", 0, "2nd Closest", "2nd closest point"},
- {SHD_VORONOI_F3, "F3", 0, "3rd Closest", "3rd closest point"},
- {SHD_VORONOI_F4, "F4", 0, "4th Closest", "4th closest point"},
- {SHD_VORONOI_F2F1, "F2F1", 0, "Crackle", "Difference between 2nd and 1st closest point"},
+ {SHD_VORONOI_F1,
+ "F1",
+ 0,
+ "F1",
+ "Computes the distance to the closest point as well as its position and color"},
+ {SHD_VORONOI_F2,
+ "F2",
+ 0,
+ "F2",
+ "Computes the distance to the second closest point as well as its position and color"},
+ {SHD_VORONOI_SMOOTH_F1,
+ "SMOOTH_F1",
+ 0,
+ "Smooth F1",
+ "Smoothed version of F1. Weighted sum of neighbour voronoi cells"},
+ {SHD_VORONOI_DISTANCE_TO_EDGE,
+ "DISTANCE_TO_EDGE",
+ 0,
+ "Distance To Edge",
+ "Computes the distance to the edge of the voronoi cell"},
+ {SHD_VORONOI_N_SPHERE_RADIUS,
+ "N_SPHERE_RADIUS",
+ 0,
+ "N-Sphere Radius",
+ "Computes the radius of the n-sphere inscribed in the voronoi cell"},
{0, NULL, 0, NULL, NULL}};
PropertyRNA *prop;
@@ -4457,11 +4444,11 @@ static void def_sh_tex_voronoi(StructRNA *srna)
RNA_def_struct_sdna_from(srna, "NodeTexVoronoi", "storage");
def_sh_tex(srna);
- prop = RNA_def_property(srna, "coloring", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "coloring");
- RNA_def_property_enum_items(prop, prop_coloring_items);
- RNA_def_property_ui_text(prop, "Coloring", "");
- RNA_def_property_update(prop, 0, "rna_Node_update");
+ prop = RNA_def_property(srna, "voronoi_dimensions", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "dimensions");
+ RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
+ RNA_def_property_ui_text(prop, "Dimensions", "");
+ RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
prop = RNA_def_property(srna, "distance", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "distance");
@@ -4473,7 +4460,7 @@ static void def_sh_tex_voronoi(StructRNA *srna)
RNA_def_property_enum_sdna(prop, NULL, "feature");
RNA_def_property_enum_items(prop, prop_feature_items);
RNA_def_property_ui_text(prop, "Feature Output", "");
- RNA_def_property_update(prop, 0, "rna_Node_update");
+ RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
}
static void def_sh_tex_wave(StructRNA *srna)
@@ -4512,11 +4499,11 @@ static void def_sh_tex_white_noise(StructRNA *srna)
{
PropertyRNA *prop;
- prop = RNA_def_property(srna, "dimensions", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "noise_dimensions", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
RNA_def_property_ui_text(
- prop, "Dimensions", "The number of dimensions to evaluate the noise in");
+ prop, "Dimensions", "The dimensions of the space to evaluate the noise in");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
}
@@ -4880,6 +4867,19 @@ static void def_sh_uvmap(StructRNA *srna)
RNA_def_struct_sdna_from(srna, "bNode", NULL);
}
+static void def_sh_vertex_color(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeShaderVertexColor", "storage");
+
+ prop = RNA_def_property(srna, "layer_name", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Vertex Color", "Vertex Color");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ RNA_def_struct_sdna_from(srna, "bNode", NULL);
+}
+
static void def_sh_uvalongstroke(StructRNA *srna)
{
PropertyRNA *prop;
@@ -5719,7 +5719,7 @@ static void def_cmp_dilate_erode(StructRNA *srna)
prop = RNA_def_property(srna, "distance", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "custom2");
RNA_def_property_range(prop, -5000, 5000);
- RNA_def_property_ui_range(prop, -100, 100, 0, -1);
+ RNA_def_property_ui_range(prop, -100, 100, 1, -1);
RNA_def_property_ui_text(prop, "Distance", "Distance to grow/shrink (number of iterations)");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
@@ -5756,7 +5756,7 @@ static void def_cmp_inpaint(StructRNA *srna)
prop = RNA_def_property(srna, "distance", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "custom2");
- RNA_def_property_range(prop, 1, 10000);
+ RNA_def_property_range(prop, 0, 10000);
RNA_def_property_ui_text(prop, "Distance", "Distance to inpaint (number of iterations)");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
@@ -6955,7 +6955,7 @@ static void def_cmp_boxmask(StructRNA *srna)
prop = RNA_def_property(srna, "mask_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, node_masktype_items);
- RNA_def_property_ui_text(prop, "Mask type", "");
+ RNA_def_property_ui_text(prop, "Mask Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
RNA_def_struct_sdna_from(srna, "NodeBoxMask", "storage");
@@ -7002,7 +7002,7 @@ static void def_cmp_ellipsemask(StructRNA *srna)
prop = RNA_def_property(srna, "mask_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, node_masktype_items);
- RNA_def_property_ui_text(prop, "Mask type", "");
+ RNA_def_property_ui_text(prop, "Mask Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
RNA_def_struct_sdna_from(srna, "NodeEllipseMask", "storage");
@@ -7117,7 +7117,7 @@ static void def_cmp_bokehimage(StructRNA *srna)
RNA_def_property_float_sdna(prop, NULL, "lensshift");
RNA_def_property_float_default(prop, 0.0f);
RNA_def_property_range(prop, -1.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Lens shift", "Shift of the lens components");
+ RNA_def_property_ui_text(prop, "Lens Shift", "Shift of the lens components");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index d605aa6b4f7..75594d1b295 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -546,27 +546,27 @@ static void rna_Object_parent_set(PointerRNA *ptr,
}
}
-bool rna_Object_parent_override_apply(Main *UNUSED(bmain),
- PointerRNA *ptr_dst,
- PointerRNA *ptr_src,
- PointerRNA *ptr_storage,
- PropertyRNA *prop_dst,
- PropertyRNA *prop_src,
- PropertyRNA *UNUSED(prop_storage),
- const int len_dst,
- const int len_src,
- const int len_storage,
- PointerRNA *UNUSED(ptr_item_dst),
- PointerRNA *UNUSED(ptr_item_src),
- PointerRNA *UNUSED(ptr_item_storage),
- IDOverrideLibraryPropertyOperation *opop)
+static bool rna_Object_parent_override_apply(Main *UNUSED(bmain),
+ PointerRNA *ptr_dst,
+ PointerRNA *ptr_src,
+ PointerRNA *ptr_storage,
+ PropertyRNA *prop_dst,
+ PropertyRNA *prop_src,
+ PropertyRNA *UNUSED(prop_storage),
+ const int len_dst,
+ const int len_src,
+ const int len_storage,
+ PointerRNA *UNUSED(ptr_item_dst),
+ PointerRNA *UNUSED(ptr_item_src),
+ PointerRNA *UNUSED(ptr_item_storage),
+ IDOverrideLibraryPropertyOperation *opop)
{
BLI_assert(len_dst == len_src && (!ptr_storage || len_dst == len_storage) && len_dst == 0);
BLI_assert(opop->operation == IDOVERRIDE_LIBRARY_OP_REPLACE &&
- "Unsupported RNA override operation on animdata pointer");
+ "Unsupported RNA override operation on object parent pointer");
UNUSED_VARS_NDEBUG(ptr_storage, len_dst, len_src, len_storage, opop);
- /* We need a special handling here because setting parent resets pinvert parent matrix,
+ /* We need a special handling here because setting parent resets invert parent matrix,
* which is evil in our case. */
Object *ob = (Object *)ptr_dst->data;
Object *parent_dst = RNA_property_pointer_get(ptr_dst, prop_dst).data;
@@ -1410,6 +1410,22 @@ static void rna_Object_constraints_clear(Object *object, Main *bmain)
WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, object);
}
+static void rna_Object_constraints_move(
+ Object *object, Main *bmain, ReportList *reports, int from, int to)
+{
+ if (from == to) {
+ return;
+ }
+
+ if (!BLI_listbase_move_index(&object->constraints, from, to)) {
+ BKE_reportf(reports, RPT_ERROR, "Could not move constraint from index '%d' to '%d'", from, to);
+ return;
+ }
+
+ ED_object_constraint_tag_update(bmain, object, NULL);
+ WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT, object);
+}
+
bool rna_Object_constraints_override_apply(Main *UNUSED(bmain),
PointerRNA *ptr_dst,
PointerRNA *ptr_src,
@@ -2041,6 +2057,15 @@ static void rna_def_object_constraints(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "clear", "rna_Object_constraints_clear");
RNA_def_function_flag(func, FUNC_USE_MAIN);
RNA_def_function_ui_description(func, "Remove all constraint from this object");
+
+ func = RNA_def_function(srna, "move", "rna_Object_constraints_move");
+ RNA_def_function_ui_description(func, "Move a constraint to a different position");
+ RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS);
+ parm = RNA_def_int(
+ func, "from_index", -1, INT_MIN, INT_MAX, "From Index", "Index to move", 0, 10000);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "to_index", -1, INT_MIN, INT_MAX, "To Index", "Target index", 0, 10000);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
/* object.modifiers */
@@ -2537,7 +2562,6 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "quat");
RNA_def_property_editable_array_func(prop, "rna_Object_rotation_4d_editable");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
- RNA_def_property_float_array_default(prop, rna_default_quaternion);
RNA_def_property_ui_text(prop, "Quaternion Rotation", "Rotation in Quaternions");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
@@ -2574,7 +2598,6 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_editable_array_func(prop, "rna_Object_scale_editable");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 3);
- RNA_def_property_float_array_default(prop, rna_default_scale_3d);
RNA_def_property_ui_text(prop, "Scale", "Scaling of the object");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
@@ -2611,7 +2634,6 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "delta_rotation_quaternion", PROP_FLOAT, PROP_QUATERNION);
RNA_def_property_float_sdna(prop, NULL, "dquat");
- RNA_def_property_float_array_default(prop, rna_default_quaternion);
RNA_def_property_ui_text(
prop,
"Delta Rotation (Quaternion)",
@@ -2634,7 +2656,6 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "dscale");
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 3);
- RNA_def_property_float_array_default(prop, rna_default_scale_3d);
RNA_def_property_ui_text(prop, "Delta Scale", "Extra scaling added to the scale of the object");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
@@ -2714,7 +2735,7 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "parentinv");
RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
RNA_def_property_ui_text(
- prop, "Matrix", "Inverse of object's parent matrix at time of parenting");
+ prop, "Parent Inverse Matrix", "Inverse of object's parent matrix at time of parenting");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
/* modifiers */
@@ -2821,6 +2842,14 @@ static void rna_def_object(BlenderRNA *brna)
prop, "Display in Orthographic Mode", "Display image in orthographic mode");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ prop = RNA_def_property(srna, "show_empty_image_only_axis_aligned", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "empty_image_visibility_flag", OB_EMPTY_IMAGE_HIDE_NON_AXIS_ALIGNED);
+ RNA_def_property_ui_text(prop,
+ "Display Only Axis Aligned",
+ "Only display the image when it is aligned with the view axis");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
prop = RNA_def_property(srna, "use_empty_image_alpha", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "empty_image_flag", OB_EMPTY_IMAGE_USE_ALPHA_BLEND);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index d3bdfde86ce..56d25f5bebf 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -37,6 +37,7 @@
#include "DNA_object_types.h"
#include "BKE_layer.h"
+#include "BKE_gpencil.h"
#include "DEG_depsgraph.h"
@@ -220,36 +221,43 @@ static bool rna_Object_indirect_only_get(Object *ob, bContext *C, ViewLayer *vie
return ((base->flag & BASE_INDIRECT_ONLY) != 0);
}
-static Base *rna_Object_local_view_property_helper(
- bScreen *sc, View3D *v3d, Object *ob, ReportList *reports, Scene **r_scene)
+static Base *rna_Object_local_view_property_helper(bScreen *sc,
+ View3D *v3d,
+ ViewLayer *view_layer,
+ Object *ob,
+ ReportList *reports,
+ Scene **r_scene)
{
+ wmWindow *win = NULL;
if (v3d->localvd == NULL) {
BKE_report(reports, RPT_ERROR, "Viewport not in local view");
return NULL;
}
- wmWindow *win = ED_screen_window_find(sc, G_MAIN->wm.first);
- ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ if (view_layer == NULL) {
+ win = ED_screen_window_find(sc, G_MAIN->wm.first);
+ view_layer = WM_window_get_active_view_layer(win);
+ }
+
Base *base = BKE_view_layer_base_find(view_layer, ob);
if (base == NULL) {
BKE_reportf(
reports, RPT_WARNING, "Object %s not in view layer %s", ob->id.name + 2, view_layer->name);
}
- if (r_scene) {
+ if (r_scene != NULL && win != NULL) {
*r_scene = win->scene;
}
return base;
}
-static bool rna_Object_local_view_get(Object *ob, ReportList *reports, PointerRNA *v3d_ptr)
+static bool rna_Object_local_view_get(Object *ob, ReportList *reports, View3D *v3d)
{
- bScreen *sc = (bScreen *)v3d_ptr->owner_id;
- View3D *v3d = v3d_ptr->data;
- Base *base = rna_Object_local_view_property_helper(sc, v3d, ob, reports, NULL);
- if (base == NULL) {
- return false; /* Error reported. */
+ if (v3d->localvd == NULL) {
+ BKE_report(reports, RPT_ERROR, "Viewport not in local view");
+ return false;
}
- return (base->local_view_bits & v3d->local_view_uuid) != 0;
+
+ return ((ob->base_local_view_bits & v3d->local_view_uuid) != 0);
}
static void rna_Object_local_view_set(Object *ob,
@@ -260,7 +268,7 @@ static void rna_Object_local_view_set(Object *ob,
bScreen *sc = (bScreen *)v3d_ptr->owner_id;
View3D *v3d = v3d_ptr->data;
Scene *scene;
- Base *base = rna_Object_local_view_property_helper(sc, v3d, ob, reports, &scene);
+ Base *base = rna_Object_local_view_property_helper(sc, v3d, NULL, ob, reports, &scene);
if (base == NULL) {
return; /* Error reported. */
}
@@ -275,7 +283,8 @@ static void rna_Object_local_view_set(Object *ob,
}
}
-/* Convert a given matrix from a space to another (using the object and/or a bone as reference). */
+/* Convert a given matrix from a space to another (using the object and/or a bone as
+ * reference). */
static void rna_Object_mat_convert_space(Object *ob,
ReportList *reports,
bPoseChannel *pchan,
@@ -465,8 +474,8 @@ static int mesh_looptri_to_poly_index(Mesh *me_eval, const MLoopTri *lt)
return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
}
-/* TOOD(sergey): Make the Python API more clear that evaluation might happen, or requite passing
- * fully evaluated depsgraph. */
+/* TOOD(sergey): Make the Python API more clear that evaluation might happen, or requite
+ * passing fully evaluated depsgraph. */
static Object *eval_object_ensure(Object *ob,
bContext *C,
ReportList *reports,
@@ -504,8 +513,8 @@ static void rna_Object_ray_cast(Object *ob,
{
bool success = false;
- /* TODO(sergey): This isn't very reliable check. It is possible to have non-NULL pointer but
- * which is out of date, and possibly dangling one. */
+ /* TODO(sergey): This isn't very reliable check. It is possible to have non-NULL pointer
+ * but which is out of date, and possibly dangling one. */
if (ob->runtime.mesh_eval == NULL &&
(ob = eval_object_ensure(ob, C, reports, rnaptr_depsgraph)) == NULL) {
return;
@@ -685,6 +694,30 @@ static bool rna_Object_update_from_editmode(Object *ob, Main *bmain)
}
return result;
}
+
+bool rna_Object_generate_gpencil_strokes(Object *ob,
+ bContext *C,
+ ReportList *reports,
+ Object *ob_gpencil,
+ bool gpencil_lines,
+ bool use_collections)
+{
+ if (ob->type != OB_CURVE) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Object '%s' not valid for this operation! Only curves supported.",
+ ob->id.name + 2);
+ return false;
+ }
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+
+ BKE_gpencil_convert_curve(bmain, scene, ob_gpencil, ob, gpencil_lines, use_collections, false);
+
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA, NULL);
+
+ return true;
+}
#else /* RNA_RUNTIME */
void RNA_api_object(StructRNA *srna)
@@ -780,7 +813,7 @@ void RNA_api_object(StructRNA *srna)
RNA_def_function_ui_description(func, "Get the local view state for this object");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "viewport", "SpaceView3D", "", "Viewport in local view");
- RNA_def_parameter_flags(parm, 0, PARM_RNAPTR | PARM_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_boolean(func, "result", 0, "", "Object local view state");
RNA_def_function_return(func, parm);
@@ -1128,6 +1161,20 @@ void RNA_api_object(StructRNA *srna)
RNA_def_function_ui_description(func,
"Release memory used by caches associated with this object. "
"Intended to be used by render engines only");
+
+ /* Convert curve object to gpencil strokes. */
+ func = RNA_def_function(srna, "generate_gpencil_strokes", "rna_Object_generate_gpencil_strokes");
+ RNA_def_function_ui_description(func, "Convert a curve object to grease pencil strokes.");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
+
+ parm = RNA_def_pointer(
+ func, "ob_gpencil", "Object", "", "Grease Pencil object used to create new strokes");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_boolean(func, "gpencil_lines", 0, "", "Create Lines");
+ parm = RNA_def_boolean(func, "use_collections", 1, "", "Use Collections");
+
+ parm = RNA_def_boolean(func, "result", 0, "", "Result");
+ RNA_def_function_return(func, parm);
}
#endif /* RNA_RUNTIME */
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index d082dfc694c..87b14b56504 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -120,18 +120,38 @@ static const EnumPropertyItem empty_vortex_shape_items[] = {
# include "ED_object.h"
+static bool rna_Cache_get_valid_owner_ID(PointerRNA *ptr, Object **ob, Scene **scene)
+{
+ switch (GS(ptr->owner_id->name)) {
+ case ID_OB:
+ *ob = (Object *)ptr->owner_id;
+ break;
+ case ID_SCE:
+ *scene = (Scene *)ptr->owner_id;
+ break;
+ default:
+ BLI_assert(!"Trying to get PTCacheID from an invalid ID type "
+ "(Only scenes and objects are supported).");
+ break;
+ }
+
+ return (*ob != NULL || *scene != NULL);
+}
+
static void rna_Cache_change(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
- Object *ob = (Object *)ptr->owner_id;
- PointCache *cache = (PointCache *)ptr->data;
+ Object *ob = NULL;
+ Scene *scene = NULL;
- if (!ob) {
+ if (!rna_Cache_get_valid_owner_ID(ptr, &ob, &scene)) {
return;
}
+ PointCache *cache = (PointCache *)ptr->data;
+
cache->flag |= PTCACHE_OUTDATED;
- PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
+ PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
@@ -146,14 +166,16 @@ static void rna_Cache_change(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerR
static void rna_Cache_toggle_disk_cache(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
- Object *ob = (Object *)ptr->owner_id;
- PointCache *cache = (PointCache *)ptr->data;
+ Object *ob = NULL;
+ Scene *scene = NULL;
- if (!ob) {
+ if (!rna_Cache_get_valid_owner_ID(ptr, &ob, &scene)) {
return;
}
- PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
+ PointCache *cache = (PointCache *)ptr->data;
+
+ PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
/* smoke can only use disk cache */
if (pid.cache && pid.type != PTCACHE_TYPE_SMOKE_DOMAIN) {
@@ -166,18 +188,20 @@ static void rna_Cache_toggle_disk_cache(Main *UNUSED(bmain), Scene *UNUSED(scene
static void rna_Cache_idname_change(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
- Object *ob = (Object *)ptr->owner_id;
- PointCache *cache = (PointCache *)ptr->data;
- bool use_new_name = true;
+ Object *ob = NULL;
+ Scene *scene = NULL;
- if (!ob) {
+ if (!rna_Cache_get_valid_owner_ID(ptr, &ob, &scene)) {
return;
}
+ PointCache *cache = (PointCache *)ptr->data;
+ bool use_new_name = true;
+
/* TODO: check for proper characters */
if (cache->flag & PTCACHE_EXTERNAL) {
- PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
+ PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
if (pid.cache) {
BKE_ptcache_load_external(&pid);
@@ -190,7 +214,7 @@ static void rna_Cache_idname_change(Main *UNUSED(bmain), Scene *UNUSED(scene), P
PTCacheID *pid = NULL, *pid2 = NULL;
ListBase pidlist;
- BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
+ BKE_ptcache_ids_from_object(&pidlist, ob, scene, 0);
for (pid = pidlist.first; pid; pid = pid->next) {
if (pid->cache == cache) {
@@ -240,13 +264,19 @@ static void rna_Cache_list_begin(CollectionPropertyIterator *iter, PointerRNA *p
static void rna_Cache_active_point_cache_index_range(
PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
{
- Object *ob = (Object *)ptr->owner_id;
- PointCache *cache = ptr->data;
- PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
-
*min = 0;
*max = 0;
+ Object *ob = NULL;
+ Scene *scene = NULL;
+
+ if (!rna_Cache_get_valid_owner_ID(ptr, &ob, &scene)) {
+ return;
+ }
+
+ PointCache *cache = ptr->data;
+ PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
+
if (pid.cache) {
*max = max_ii(0, BLI_listbase_count(pid.ptcaches) - 1);
}
@@ -254,11 +284,18 @@ static void rna_Cache_active_point_cache_index_range(
static int rna_Cache_active_point_cache_index_get(PointerRNA *ptr)
{
- Object *ob = (Object *)ptr->owner_id;
- PointCache *cache = ptr->data;
- PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
int num = 0;
+ Object *ob = NULL;
+ Scene *scene = NULL;
+
+ if (!rna_Cache_get_valid_owner_ID(ptr, &ob, &scene)) {
+ return num;
+ }
+
+ PointCache *cache = ptr->data;
+ PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
+
if (pid.cache) {
num = BLI_findindex(pid.ptcaches, cache);
}
@@ -268,9 +305,15 @@ static int rna_Cache_active_point_cache_index_get(PointerRNA *ptr)
static void rna_Cache_active_point_cache_index_set(struct PointerRNA *ptr, int value)
{
- Object *ob = (Object *)ptr->owner_id;
+ Object *ob = NULL;
+ Scene *scene = NULL;
+
+ if (!rna_Cache_get_valid_owner_ID(ptr, &ob, &scene)) {
+ return;
+ }
+
PointCache *cache = ptr->data;
- PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
+ PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
if (pid.cache) {
*(pid.cache_ptr) = BLI_findlink(pid.ptcaches, value);
@@ -280,13 +323,19 @@ static void rna_Cache_active_point_cache_index_set(struct PointerRNA *ptr, int v
static void rna_PointCache_frame_step_range(
PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
{
- Object *ob = (Object *)ptr->owner_id;
- PointCache *cache = ptr->data;
- PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
-
*min = 1;
*max = 20;
+ Object *ob = NULL;
+ Scene *scene = NULL;
+
+ if (!rna_Cache_get_valid_owner_ID(ptr, &ob, &scene)) {
+ return;
+ }
+
+ PointCache *cache = ptr->data;
+ PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
+
if (pid.cache) {
*max = pid.max_step;
}
@@ -294,14 +343,16 @@ static void rna_PointCache_frame_step_range(
int rna_Cache_info_length(PointerRNA *ptr)
{
- PointCache *cache = (PointCache *)ptr->data;
- Object *ob = (Object *)ptr->owner_id;
+ Object *ob = NULL;
+ Scene *scene = NULL;
- if (!ob) {
+ if (!rna_Cache_get_valid_owner_ID(ptr, &ob, &scene)) {
return 0;
}
- PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
+ PointCache *cache = (PointCache *)ptr->data;
+
+ PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
if (cache->flag & PTCACHE_FLAG_INFO_DIRTY) {
BKE_ptcache_update_info(&pid);
@@ -1262,13 +1313,17 @@ static void rna_def_field(BlenderRNA *brna)
ICON_FORCE_LENNARDJONES,
"Lennard-Jones",
"Forcefield based on the Lennard-Jones potential"},
- {PFIELD_TEXTURE, "TEXTURE", ICON_FORCE_TEXTURE, "Texture", "Forcefield based on a texture"},
+ {PFIELD_TEXTURE, "TEXTURE", ICON_FORCE_TEXTURE, "Texture", "Force field based on a texture"},
{PFIELD_GUIDE,
"GUIDE",
ICON_FORCE_CURVE,
"Curve Guide",
"Create a force along a curve object"},
- {PFIELD_BOID, "BOID", ICON_FORCE_BOID, "Boid", ""},
+ {PFIELD_BOID,
+ "BOID",
+ ICON_FORCE_BOID,
+ "Boid",
+ "Create a force that acts as a boid's predators or target"},
{PFIELD_TURBULENCE,
"TURBULENCE",
ICON_FORCE_TURBULENCE,
@@ -1888,7 +1943,7 @@ static void rna_def_softbody(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_estimate_matrix", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "solverflags", SBSO_ESTIMATEIPO);
- RNA_def_property_ui_text(prop, "Estimate matrix", "Estimate matrix... split to COM, ROT, SCALE");
+ RNA_def_property_ui_text(prop, "Estimate Matrix", "Estimate matrix... split to COM, ROT, SCALE");
/***********************************************************************************/
/* these are not exactly settings, but reading calculated results*/
@@ -1897,7 +1952,7 @@ static void rna_def_softbody(BlenderRNA *brna)
/* translation */
prop = RNA_def_property(srna, "location_mass_center", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "lcom");
- RNA_def_property_ui_text(prop, "Center of mass", "Location of Center of mass");
+ RNA_def_property_ui_text(prop, "Center of Mass", "Location of center of mass");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
/* matrix */
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 98ecb053641..211d9e19ab4 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -1891,7 +1891,7 @@ static void rna_def_fluid_settings(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "viscosity_beta");
RNA_def_property_range(prop, 0.0f, 100.0f);
RNA_def_property_ui_range(prop, 0.0f, 2.0f, 1, 3);
- RNA_def_property_ui_text(prop, "Stiff viscosity", "Creates viscosity for expanding fluid");
+ RNA_def_property_ui_text(prop, "Stiff Viscosity", "Creates viscosity for expanding fluid");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
/* Double density relaxation */
@@ -2398,7 +2398,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_DIE_ON_COL);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(
- prop, "Die on hit", "Particles die when they collide with a deflector object");
+ prop, "Die on Hit", "Particles die when they collide with a deflector object");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop = RNA_def_property(srna, "use_size_deflect", PROP_BOOLEAN, PROP_NONE);
@@ -3297,7 +3297,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "keyed_loops");
RNA_def_property_range(prop, 1.0f, 10000.0f);
RNA_def_property_ui_range(prop, 1.0f, 100.0f, 0.1, 3);
- RNA_def_property_ui_text(prop, "Loop count", "Number of times the keys are looped");
+ RNA_def_property_ui_text(prop, "Loop Count", "Number of times the keys are looped");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
/* modified dm support */
@@ -3594,7 +3594,7 @@ static void rna_def_particle_system(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_keyed_timing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PSYS_KEYED_TIMING);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Keyed timing", "Use key times");
+ RNA_def_property_ui_text(prop, "Keyed Timing", "Use key times");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
prop = RNA_def_property(srna, "targets", PROP_COLLECTION, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index 7637930f37f..0f8f8d39c41 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -274,6 +274,12 @@ static void rna_PoseChannel_rotation_mode_set(PointerRNA *ptr, int value)
pchan->rotmode = value;
}
+static float rna_PoseChannel_length_get(PointerRNA *ptr)
+{
+ bPoseChannel *pchan = ptr->data;
+ return len_v3v3(pchan->pose_head, pchan->pose_tail);
+}
+
static void rna_PoseChannel_name_set(PointerRNA *ptr, const char *value)
{
Object *ob = (Object *)ptr->owner_id;
@@ -601,6 +607,24 @@ static void rna_PoseChannel_constraints_remove(
}
}
+static void rna_PoseChannel_constraints_move(
+ ID *id, bPoseChannel *pchan, Main *bmain, ReportList *reports, int from, int to)
+{
+ Object *ob = (Object *)id;
+
+ if (from == to) {
+ return;
+ }
+
+ if (!BLI_listbase_move_index(&pchan->constraints, from, to)) {
+ BKE_reportf(reports, RPT_ERROR, "Could not move constraint from index '%d' to '%d'", from, to);
+ return;
+ }
+
+ ED_object_constraint_tag_update(bmain, ob, NULL);
+ WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT, ob);
+}
+
bool rna_PoseChannel_constraints_override_apply(Main *UNUSED(bmain),
PointerRNA *ptr_dst,
PointerRNA *ptr_src,
@@ -929,6 +953,15 @@ static void rna_def_pose_channel_constraints(BlenderRNA *brna, PropertyRNA *cpro
parm = RNA_def_pointer(func, "constraint", "Constraint", "", "Removed constraint");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+ func = RNA_def_function(srna, "move", "rna_PoseChannel_constraints_move");
+ RNA_def_function_ui_description(func, "Move a constraint to a different position");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
+ parm = RNA_def_int(
+ func, "from_index", -1, INT_MIN, INT_MAX, "From Index", "Index to move", 0, 10000);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "to_index", -1, INT_MIN, INT_MAX, "To Index", "Target index", 0, 10000);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
static void rna_def_pose_channel(BlenderRNA *brna)
@@ -1044,7 +1077,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
/* Curved bones settings - Applied on top of restpose values */
- rna_def_bone_curved_common(srna, true);
+ rna_def_bone_curved_common(srna, true, false);
/* Custom BBone next/prev sources */
prop = RNA_def_property(srna, "bbone_custom_handle_start", PROP_POINTER, PROP_NONE);
@@ -1108,6 +1141,11 @@ static void rna_def_pose_channel(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Pose Tail Position", "Location of tail of the channel's bone");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
+ prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_funcs(prop, "rna_PoseChannel_length_get", NULL, NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Length", "Length of the bone");
+
/* IK Settings */
prop = RNA_def_property(srna, "is_in_ik_chain", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_PoseChannel_has_ik_get", NULL);
@@ -1261,7 +1299,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Custom Object", "Object that defines custom draw type for this bone");
RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
- RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_dependency_update");
prop = RNA_def_property(srna, "custom_shape_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "custom_scale");
@@ -1419,7 +1457,7 @@ static void rna_def_pose_itasc(BlenderRNA *brna)
prop = RNA_def_property(srna, "step_count", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "numstep");
RNA_def_property_range(prop, 1.f, 50.f);
- RNA_def_property_ui_text(prop, "Num steps", "Divide the frame interval into this many steps");
+ RNA_def_property_ui_text(prop, "Num Steps", "Divide the frame interval into this many steps");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update");
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
@@ -1440,7 +1478,7 @@ static void rna_def_pose_itasc(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_auto_step", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ITASC_AUTO_STEP);
RNA_def_property_ui_text(prop,
- "Auto step",
+ "Auto Step",
"Automatically determine the optimal number of steps for best "
"performance/accuracy trade off");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update");
@@ -1449,14 +1487,14 @@ static void rna_def_pose_itasc(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "minstep");
RNA_def_property_range(prop, 0.0f, 0.1f);
RNA_def_property_ui_text(
- prop, "Min step", "Lower bound for timestep in second in case of automatic substeps");
+ prop, "Min Step", "Lower bound for timestep in second in case of automatic substeps");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update");
prop = RNA_def_property(srna, "step_max", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "maxstep");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(
- prop, "Max step", "Higher bound for timestep in second in case of automatic substeps");
+ prop, "Max Step", "Higher bound for timestep in second in case of automatic substeps");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update");
prop = RNA_def_property(srna, "feedback", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 6e21d02c0b3..26c8df4c7bb 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -613,7 +613,10 @@ static bool rna_Property_overridable_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- return (prop->flag_override & PROPOVERRIDE_OVERRIDABLE_LIBRARY) != 0;
+ IDProperty *idprop = rna_idproperty_check(&prop, ptr);
+
+ return idprop != NULL ? (idprop->flag & IDP_FLAG_OVERRIDABLE_LIBRARY) != 0 :
+ (prop->flag_override & PROPOVERRIDE_OVERRIDABLE_LIBRARY) != 0;
}
static bool rna_Property_use_output_get(PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 7d9a3cf06b8..1f967df7232 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -47,8 +47,6 @@
#include "ED_object.h"
#include "ED_gpencil.h"
-#include "GPU_extensions.h"
-
#include "DRW_engine.h"
#include "RNA_define.h"
@@ -143,7 +141,7 @@ const EnumPropertyItem rna_enum_proportional_falloff_curve_only_items[] = {
/* keep for operators, not used here */
const EnumPropertyItem rna_enum_mesh_select_mode_items[] = {
- {SCE_SELECT_VERTEX, "VERTEX", ICON_VERTEXSEL, "Vertex", "Vertex selection mode"},
+ {SCE_SELECT_VERTEX, "VERT", ICON_VERTEXSEL, "Vertex", "Vertex selection mode"},
{SCE_SELECT_EDGE, "EDGE", ICON_EDGESEL, "Edge", "Edge selection mode"},
{SCE_SELECT_FACE, "FACE", ICON_FACESEL, "Face", "Face selection mode"},
{0, NULL, 0, NULL, NULL},
@@ -712,20 +710,7 @@ static void rna_ToolSettings_snap_mode_set(struct PointerRNA *ptr, int value)
/* Grease Pencil update cache */
static void rna_GPencil_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
- /* mark all grease pencil datablocks of the scene */
- FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, ob) {
- if (ob->type == OB_GPENCIL) {
- bGPdata *gpd = (bGPdata *)ob->data;
- gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- }
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- }
- FOREACH_SCENE_COLLECTION_END;
-
- WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
+ ED_gpencil_tag_scene_gpencil(scene);
}
/* Grease Pencil Interpolation settings */
@@ -749,6 +734,35 @@ static void rna_GPencilInterpolateSettings_type_set(PointerRNA *ptr, int value)
}
}
+static void rna_Gpencil_selectmode_update(bContext *C, PointerRNA *ptr)
+{
+ ToolSettings *ts = (ToolSettings *)ptr->data;
+ /* If the mode is not Stroke, don't extend selection. */
+ if ((ts->gpencil_selectmode_edit & GP_SELECTMODE_STROKE) == 0) {
+ return;
+ }
+
+ /* Extend selection to all points in all selected strokes. */
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ if ((gps->flag & GP_STROKE_SELECT) && (gps->totpoints > 1)) {
+ bGPDspoint *pt;
+ for (int i = 0; i < gps->totpoints; i++) {
+ pt = &gps->points[i];
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ }
+}
+
static void rna_Gpencil_mask_point_update(Main *UNUSED(bmain),
Scene *UNUSED(scene),
PointerRNA *ptr)
@@ -2625,7 +2639,6 @@ static void rna_def_view3d_cursor(BlenderRNA *brna)
prop = RNA_def_property(srna, "rotation_quaternion", PROP_FLOAT, PROP_QUATERNION);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_float_sdna(prop, NULL, "rotation_quaternion");
- RNA_def_property_float_array_default(prop, rna_default_quaternion);
RNA_def_property_ui_text(
prop, "Quaternion Rotation", "Rotation in quaternions (keep normalized)");
RNA_def_property_update(prop, NC_WINDOW, NULL);
@@ -2929,24 +2942,35 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "transform_pivot_point", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "transform_pivot_point");
RNA_def_property_enum_items(prop, rna_enum_transform_pivot_items_full);
- RNA_def_property_ui_text(prop, "Pivot Point", "Pivot center for rotation/scaling");
+ RNA_def_property_ui_text(prop, "Transform Pivot Point", "Pivot center for rotation/scaling");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "use_transform_pivot_point_align", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "transform_flag", SCE_XFORM_AXIS_ALIGN);
RNA_def_property_ui_text(
prop, "Only Locations", "Manipulate origins (object, pose and weight paint mode only)");
- RNA_def_property_update(prop, NC_SCENE, NULL);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "use_transform_data_origin", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "transform_flag", SCE_XFORM_DATA_ORIGIN);
- RNA_def_property_ui_text(prop, "Data Origins", "Manipulate object data");
- RNA_def_property_update(prop, NC_SCENE, NULL);
+ RNA_def_property_ui_text(prop, "Transform Origins", "Manipulate object data");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "use_transform_skip_children", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "transform_flag", SCE_XFORM_SKIP_CHILDREN);
+ RNA_def_property_ui_text(prop, "Transform Parents", "Don't transform children");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "use_mesh_automerge", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "automerge", 0);
+ RNA_def_property_boolean_sdna(prop, NULL, "automerge", AUTO_MERGE);
RNA_def_property_ui_text(
- prop, "Auto Merge", "Automatically merge vertices moved to the same location");
+ prop, "Auto Merge Vertices", "Automatically merge vertices moved to the same location");
+ RNA_def_property_ui_icon(prop, ICON_AUTOMERGE_OFF, 1);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+
+ prop = RNA_def_property(srna, "use_mesh_automerge_and_split", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "automerge", AUTO_MERGE_AND_SPLIT);
+ RNA_def_property_ui_text(prop, "Split Edges & Faces", "Automatically split edges and faces");
RNA_def_property_ui_icon(prop, ICON_AUTOMERGE_OFF, 1);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
@@ -3108,6 +3132,8 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_enum_items(prop, gpencil_selectmode_items);
RNA_def_property_ui_text(prop, "Select Mode", "");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_Gpencil_selectmode_update");
/* Grease Pencil - Select mode Sculpt */
prop = RNA_def_property(srna, "use_gpencil_select_mask_point", PROP_BOOLEAN, PROP_NONE);
@@ -3337,7 +3363,7 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna)
prop, NULL, "rna_UnifiedPaintSettings_unprojected_radius_set", NULL);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_range(prop, 0.001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.001, 1, 0, -1);
+ RNA_def_property_ui_range(prop, 0.001, 1, 1, -1);
RNA_def_property_ui_text(prop, "Unprojected Radius", "Radius of brush in Blender units");
RNA_def_property_update(prop, 0, "rna_UnifiedPaintSettings_radius_update");
@@ -3535,7 +3561,6 @@ static void rna_def_statvis(BlenderRNA *brna)
/* overhang */
prop = RNA_def_property(srna, "overhang_min", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "overhang_min");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 10, 3);
RNA_def_property_ui_text(prop, "Overhang Min", "Minimum angle to display");
@@ -3544,7 +3569,6 @@ static void rna_def_statvis(BlenderRNA *brna)
prop = RNA_def_property(srna, "overhang_max", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "overhang_max");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 10, 3);
RNA_def_property_ui_text(prop, "Overhang Max", "Maximum angle to display");
@@ -3561,7 +3585,6 @@ static void rna_def_statvis(BlenderRNA *brna)
/* thickness */
prop = RNA_def_property(srna, "thickness_min", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "thickness_min");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, 1000.0);
RNA_def_property_ui_range(prop, 0.0f, 100.0, 0.001, 3);
RNA_def_property_ui_text(prop, "Thickness Min", "Minimum for measuring thickness");
@@ -3570,7 +3593,6 @@ static void rna_def_statvis(BlenderRNA *brna)
prop = RNA_def_property(srna, "thickness_max", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "thickness_max");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, 1000.0);
RNA_def_property_ui_range(prop, 0.0f, 100.0, 0.001, 3);
RNA_def_property_ui_text(prop, "Thickness Max", "Maximum for measuring thickness");
@@ -3587,7 +3609,6 @@ static void rna_def_statvis(BlenderRNA *brna)
/* distort */
prop = RNA_def_property(srna, "distort_min", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "distort_min");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 10, 3);
RNA_def_property_ui_text(prop, "Distort Min", "Minimum angle to display");
@@ -3596,7 +3617,6 @@ static void rna_def_statvis(BlenderRNA *brna)
prop = RNA_def_property(srna, "distort_max", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "distort_max");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 10, 3);
RNA_def_property_ui_text(prop, "Distort Max", "Maximum angle to display");
@@ -3606,7 +3626,6 @@ static void rna_def_statvis(BlenderRNA *brna)
/* sharp */
prop = RNA_def_property(srna, "sharp_min", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "sharp_min");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, -DEG2RADF(180.0f), DEG2RADF(180.0f));
RNA_def_property_ui_range(prop, -DEG2RADF(180.0f), DEG2RADF(180.0f), 10, 3);
RNA_def_property_ui_text(prop, "Distort Min", "Minimum angle to display");
@@ -3615,7 +3634,6 @@ static void rna_def_statvis(BlenderRNA *brna)
prop = RNA_def_property(srna, "sharp_max", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "sharp_max");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, -DEG2RADF(180.0f), DEG2RADF(180.0f));
RNA_def_property_ui_range(prop, -DEG2RADF(180.0f), DEG2RADF(180.0f), 10, 3);
RNA_def_property_ui_text(prop, "Distort Max", "Maximum angle to display");
@@ -5379,7 +5397,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 0, 500);
RNA_def_property_int_default(prop, 25);
RNA_def_property_ui_text(prop,
- "Keyframe interval",
+ "Keyframe Interval",
"Distance between key frames, also known as GOP size; "
"influences file size and seekability");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
@@ -5390,14 +5408,14 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 0, 16);
RNA_def_property_ui_text(
prop,
- "Max B-frames",
+ "Max B-Frames",
"Maximum number of B-frames between non-B-frames; influences file size and seekability");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_max_b_frames", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FFMPEG_USE_MAX_B_FRAMES);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Use max B-frames", "Set a maximum number of B-frames");
+ RNA_def_property_ui_text(prop, "Use Max B-Frames", "Set a maximum number of B-frames");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "buffersize", PROP_INT, PROP_NONE);
@@ -5421,7 +5439,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_enum_default(prop, FFM_CRF_MEDIUM);
RNA_def_property_ui_text(
prop,
- "Output quality",
+ "Output Quality",
"Constant Rate Factor (CRF); tradeoff between video quality and file size");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
@@ -5431,7 +5449,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_enum_items(prop, ffmpeg_preset_items);
RNA_def_property_enum_default(prop, FFM_PRESET_GOOD);
RNA_def_property_ui_text(
- prop, "Encoding speed", "Tradeoff between encoding speed and compression ratio");
+ prop, "Encoding Speed", "Tradeoff between encoding speed and compression ratio");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_autosplit", PROP_BOOLEAN, PROP_NONE);
@@ -5491,22 +5509,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem display_mode_items[] = {
- {R_OUTPUT_SCREEN,
- "SCREEN",
- 0,
- "Full Screen",
- "Images are rendered in a maximized Image Editor"},
- {R_OUTPUT_AREA, "AREA", 0, "Image Editor", "Images are rendered in an Image Editor"},
- {R_OUTPUT_WINDOW, "WINDOW", 0, "New Window", "Images are rendered in a new window"},
- {R_OUTPUT_NONE,
- "NONE",
- 0,
- "Keep User Interface",
- "Images are rendered without changing the user interface"},
- {0, NULL, 0, NULL, NULL},
- };
-
/* Bake */
static const EnumPropertyItem bake_mode_items[] = {
//{RE_BAKE_AO, "AO", 0, "Ambient Occlusion", "Bake ambient occlusion"},
@@ -5632,7 +5634,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "preview_start_resolution", PROP_INT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_range(prop, 8, 16384);
- RNA_def_property_int_default(prop, 64);
RNA_def_property_ui_text(prop,
"Start Resolution",
"Resolution to start rendering preview at, "
@@ -5904,13 +5905,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
"(this solves anti-aliasing issues with compositing)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
- prop = RNA_def_property(srna, "display_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "displaymode");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_enum_items(prop, display_mode_items);
- RNA_def_property_ui_text(prop, "Display", "Select where rendered images will be displayed");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
prop = RNA_def_property(srna, "use_lock_interface", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_lock_interface", 1);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -5986,14 +5980,13 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "bake_samples", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "bake_samples");
RNA_def_property_range(prop, 64, 1024);
- RNA_def_property_int_default(prop, 256);
RNA_def_property_ui_text(
prop, "Samples", "Number of samples used for ambient occlusion baking from multires");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_bake_user_scale", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "bake_flag", R_BAKE_USERSCALE);
- RNA_def_property_ui_text(prop, "User scale", "Use a user scale for the derivative map");
+ RNA_def_property_ui_text(prop, "User Scale", "Use a user scale for the derivative map");
prop = RNA_def_property(srna, "bake_user_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bake_user_scale");
@@ -6299,6 +6292,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Layers Blending", "Do not display blend layers");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ prop = RNA_def_property(srna, "simplify_gpencil_tint", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_TINT);
+ RNA_def_property_ui_text(prop, "Layers Tinting", "Do not display layer tint");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
/* persistent data */
prop = RNA_def_property(srna, "use_persistent_data", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_PERSISTENT_DATA);
@@ -6496,12 +6494,6 @@ static void rna_def_display_safe_areas(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static float default_title[2] = {0.1f, 0.05f};
- static float default_action[2] = {0.035f, 0.035f};
-
- static float default_title_center[2] = {0.175f, 0.05f};
- static float default_action_center[2] = {0.15f, 0.05f};
-
srna = RNA_def_struct(brna, "DisplaySafeAreas", NULL);
RNA_def_struct_ui_text(srna, "Safe Areas", "Safe areas used in 3D view and the sequencer");
RNA_def_struct_sdna(srna, "DisplaySafeAreas");
@@ -6511,14 +6503,12 @@ static void rna_def_display_safe_areas(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "title");
RNA_def_property_array(prop, 2);
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_float_array_default(prop, default_title);
RNA_def_property_ui_text(prop, "Title Safe Margins", "Safe area for text and graphics");
RNA_def_property_update(prop, NC_SCENE | ND_DRAW_RENDER_VIEWPORT, NULL);
prop = RNA_def_property(srna, "action", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "action");
RNA_def_property_array(prop, 2);
- RNA_def_property_float_array_default(prop, default_action);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Action Safe Margins", "Safe area for general elements");
RNA_def_property_update(prop, NC_SCENE | ND_DRAW_RENDER_VIEWPORT, NULL);
@@ -6526,7 +6516,6 @@ static void rna_def_display_safe_areas(BlenderRNA *brna)
prop = RNA_def_property(srna, "title_center", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "title_center");
RNA_def_property_array(prop, 2);
- RNA_def_property_float_array_default(prop, default_title_center);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop,
"Center Title Safe Margins",
@@ -6536,7 +6525,6 @@ static void rna_def_display_safe_areas(BlenderRNA *brna)
prop = RNA_def_property(srna, "action_center", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "action_center");
RNA_def_property_array(prop, 2);
- RNA_def_property_float_array_default(prop, default_action_center);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop,
"Center Action Safe Margins",
@@ -6549,8 +6537,6 @@ static void rna_def_scene_display(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static float default_light_direction[3] = {-M_SQRT1_3, -M_SQRT1_3, M_SQRT1_3};
-
srna = RNA_def_struct(brna, "SceneDisplay", NULL);
RNA_def_struct_ui_text(srna, "Scene Display", "Scene display settings for 3d viewport");
RNA_def_struct_sdna(srna, "SceneDisplay");
@@ -6559,13 +6545,11 @@ static void rna_def_scene_display(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "light_direction");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_array(prop, 3);
- RNA_def_property_float_array_default(prop, default_light_direction);
RNA_def_property_ui_text(
prop, "Light Direction", "Direction of the light for shadows and highlights");
RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_set_update");
prop = RNA_def_property(srna, "shadow_shift", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_default(prop, 0.1);
RNA_def_property_ui_text(prop, "Shadow Shift", "Shadow termination angle");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_range(prop, 0.00f, 1.0f, 1, 2);
@@ -6581,20 +6565,17 @@ static void rna_def_scene_display(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_set_update");
prop = RNA_def_property(srna, "matcap_ssao_distance", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_ui_text(
prop, "Distance", "Distance of object that contribute to the Cavity/Edge effect");
RNA_def_property_range(prop, 0.0f, 100000.0f);
RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3);
prop = RNA_def_property(srna, "matcap_ssao_attenuation", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Attenuation", "Attenuation constant");
RNA_def_property_range(prop, 1.0f, 100000.0f);
RNA_def_property_ui_range(prop, 1.0f, 100.0f, 1, 3);
prop = RNA_def_property(srna, "matcap_ssao_samples", PROP_INT, PROP_NONE);
- RNA_def_property_int_default(prop, 16);
RNA_def_property_ui_text(prop, "Samples", "Number of samples");
RNA_def_property_range(prop, 1, 500);
@@ -6620,12 +6601,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem eevee_shadow_method_items[] = {
- {SHADOW_ESM, "ESM", 0, "ESM", "Exponential Shadow Mapping"},
- {SHADOW_VSM, "VSM", 0, "VSM", "Variance Shadow Mapping"},
- {0, NULL, 0, NULL, NULL},
- };
-
static const EnumPropertyItem eevee_shadow_size_items[] = {
{64, "64", 0, "64px", ""},
{128, "128", 0, "128px", ""},
@@ -6653,15 +6628,12 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
- static float default_bloom_color[3] = {1.0f, 1.0f, 1.0f};
-
srna = RNA_def_struct(brna, "SceneEEVEE", NULL);
RNA_def_struct_path_func(srna, "rna_SceneEEVEE_path");
RNA_def_struct_ui_text(srna, "Scene Display", "Scene display settings for 3d viewport");
/* Indirect Lighting */
prop = RNA_def_property(srna, "gi_diffuse_bounces", PROP_INT, PROP_NONE);
- RNA_def_property_int_default(prop, 3);
RNA_def_property_ui_text(prop,
"Diffuse Bounces",
"Number of time the light is reinjected inside light grids, "
@@ -6671,13 +6643,11 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "gi_cubemap_resolution", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, eevee_shadow_size_items);
- RNA_def_property_enum_default(prop, 512);
RNA_def_property_ui_text(prop, "Cubemap Size", "Size of every cubemaps");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
prop = RNA_def_property(srna, "gi_visibility_resolution", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, eevee_gi_visibility_size_items);
- RNA_def_property_enum_default(prop, 32);
RNA_def_property_ui_text(prop,
"Irradiance Visibility Size",
"Size of the shadow map applied to each irradiance sample");
@@ -6686,7 +6656,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "gi_irradiance_smoothing", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 5, 2);
- RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_ui_text(prop,
"Irradiance Smoothing",
"Smoother irradiance interpolation but introduce light bleeding");
@@ -6694,7 +6663,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "gi_glossy_clamp", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_default(prop, 0.0f);
RNA_def_property_ui_text(prop,
"Clamp Glossy",
"Clamp pixel intensity to reduce noise inside glossy reflections "
@@ -6703,7 +6671,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
prop = RNA_def_property(srna, "gi_filter_quality", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_default(prop, 3.0f);
RNA_def_property_ui_text(
prop, "Filter Quality", "Take more samples during cubemap filtering to remove artifacts");
RNA_def_property_range(prop, 1.0f, 8.0f);
@@ -6711,7 +6678,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "gi_show_irradiance", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SHOW_IRRADIANCE);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_icon(prop, ICON_HIDE_ON, 1);
RNA_def_property_ui_text(
prop, "Show Irradiance Cache", "Display irradiance samples in the viewport");
@@ -6720,7 +6686,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "gi_show_cubemaps", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SHOW_CUBEMAPS);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_icon(prop, ICON_HIDE_ON, 1);
RNA_def_property_ui_text(
prop, "Show Cubemap Cache", "Display captured cubemaps in the viewport");
@@ -6730,7 +6695,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "gi_irradiance_display_size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "gi_irradiance_draw_size");
RNA_def_property_range(prop, 0.05f, 10.0f);
- RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_ui_text(prop,
"Irradiance Display Size",
"Size of the irradiance sample spheres to debug captured light");
@@ -6739,14 +6703,12 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "gi_cubemap_display_size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "gi_cubemap_draw_size");
RNA_def_property_range(prop, 0.05f, 10.0f);
- RNA_def_property_float_default(prop, 0.3f);
RNA_def_property_ui_text(
prop, "Cubemap Display Size", "Size of the cubemap spheres to debug captured light");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "gi_auto_bake", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_GI_AUTOBAKE);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "Auto Bake", "Auto bake indirect lighting when editing probes");
prop = RNA_def_property(srna, "gi_cache_info", PROP_STRING, PROP_NONE);
@@ -6756,14 +6718,12 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
/* Temporal Anti-Aliasing (super sampling) */
prop = RNA_def_property(srna, "taa_samples", PROP_INT, PROP_NONE);
- RNA_def_property_int_default(prop, 16);
RNA_def_property_ui_text(prop, "Viewport Samples", "Number of samples, unlimited if 0");
RNA_def_property_range(prop, 0, INT_MAX);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "taa_render_samples", PROP_INT, PROP_NONE);
- RNA_def_property_int_default(prop, 64);
RNA_def_property_ui_text(prop, "Render Samples", "Number of samples per pixels for rendering");
RNA_def_property_range(prop, 1, INT_MAX);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
@@ -6771,7 +6731,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_taa_reprojection", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_TAA_REPROJECTION);
- RNA_def_property_boolean_default(prop, 1);
RNA_def_property_ui_text(prop,
"Viewport Denoising",
"Denoise image using temporal reprojection "
@@ -6781,61 +6740,44 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
/* Screen Space Subsurface Scattering */
prop = RNA_def_property(srna, "sss_samples", PROP_INT, PROP_NONE);
- RNA_def_property_int_default(prop, 7);
RNA_def_property_ui_text(prop, "Samples", "Number of samples to compute the scattering effect");
RNA_def_property_range(prop, 1, 32);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "sss_jitter_threshold", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.3f);
RNA_def_property_ui_text(
prop, "Jitter Threshold", "Rotate samples that are below this threshold");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
- prop = RNA_def_property(srna, "use_sss_separate_albedo", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSS_SEPARATE_ALBEDO);
- RNA_def_property_boolean_default(prop, 0);
- RNA_def_property_ui_text(prop,
- "Separate Albedo",
- "Avoid albedo being blurred by the subsurface scattering "
- "but uses more video memory");
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
/* Screen Space Reflection */
prop = RNA_def_property(srna, "use_ssr", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSR_ENABLED);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "Screen Space Reflections", "Enable screen space reflection");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_ssr_refraction", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSR_REFRACTION);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "Screen Space Refractions", "Enable screen space Refractions");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_ssr_halfres", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSR_HALF_RESOLUTION);
- RNA_def_property_boolean_default(prop, 1);
RNA_def_property_ui_text(prop, "Half Res Trace", "Raytrace at a lower resolution");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "ssr_quality", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.25f);
RNA_def_property_ui_text(prop, "Trace Precision", "Precision of the screen space raytracing");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "ssr_max_roughness", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_ui_text(
prop, "Max Roughness", "Do not raytrace reflections for roughness above this value");
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -6843,7 +6785,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "ssr_thickness", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_ui_text(prop, "Thickness", "Pixel thickness used to detect intersection");
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 5, 3);
@@ -6851,14 +6792,12 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "ssr_border_fade", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.075f);
RNA_def_property_ui_text(prop, "Edge Fading", "Screen percentage used to fade the SSR");
RNA_def_property_range(prop, 0.0f, 0.5f);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "ssr_firefly_fac", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_default(prop, 10.0f);
RNA_def_property_ui_text(prop, "Clamp", "Clamp pixel intensity to remove noise (0 to disabled)");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
@@ -6866,7 +6805,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
/* Volumetrics */
prop = RNA_def_property(srna, "volumetric_start", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_ui_text(prop, "Start", "Start distance of the volumetric effect");
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
@@ -6874,7 +6812,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "volumetric_end", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_default(prop, 100.0f);
RNA_def_property_ui_text(prop, "End", "End distance of the volumetric effect");
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
@@ -6882,7 +6819,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "volumetric_tile_size", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_default(prop, 8);
RNA_def_property_enum_items(prop, eevee_volumetric_tile_size_items);
RNA_def_property_ui_text(prop,
"Tile Size",
@@ -6892,14 +6828,12 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "volumetric_samples", PROP_INT, PROP_NONE);
- RNA_def_property_int_default(prop, 64);
RNA_def_property_ui_text(prop, "Samples", "Number of samples to compute volumetric effects");
RNA_def_property_range(prop, 1, 256);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "volumetric_sample_distribution", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.8f);
RNA_def_property_ui_text(
prop, "Exponential Sampling", "Distribute more samples closer to the camera");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
@@ -6907,14 +6841,12 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_volumetric_lights", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_VOLUMETRIC_LIGHTS);
- RNA_def_property_boolean_default(prop, 1);
RNA_def_property_ui_text(
prop, "Volumetric Lighting", "Enable scene light interactions with volumetrics");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "volumetric_light_clamp", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_default(prop, 0.0f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_text(prop, "Clamp", "Maximum light contribution, reducing noise");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
@@ -6922,14 +6854,12 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_volumetric_shadows", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_VOLUMETRIC_SHADOWS);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(
prop, "Volumetric Shadows", "Generate shadows from volumetric material (Very expensive)");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "volumetric_shadow_samples", PROP_INT, PROP_NONE);
- RNA_def_property_int_default(prop, 16);
RNA_def_property_range(prop, 1, 128);
RNA_def_property_ui_text(
prop, "Volumetric Shadow Samples", "Number of samples to compute volumetric shadowing");
@@ -6939,7 +6869,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
/* Ambient Occlusion */
prop = RNA_def_property(srna, "use_gtao", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_GTAO_ENABLED);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop,
"Ambient Occlusion",
"Enable ambient occlusion to simulate medium scale indirect shadowing");
@@ -6948,7 +6877,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_gtao_bent_normals", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_GTAO_BENT_NORMALS);
- RNA_def_property_boolean_default(prop, 1);
RNA_def_property_ui_text(
prop, "Bent Normals", "Compute main non occluded direction to sample the environment");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
@@ -6956,7 +6884,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_gtao_bounce", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_GTAO_BOUNCE);
- RNA_def_property_boolean_default(prop, 1);
RNA_def_property_ui_text(prop,
"Bounces Approximation",
"An approximation to simulate light bounces "
@@ -6965,7 +6892,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "gtao_factor", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Factor", "Factor for ambient occlusion blending");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1f, 2);
@@ -6973,14 +6899,12 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "gtao_quality", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.25f);
RNA_def_property_ui_text(prop, "Trace Precision", "Precision of the horizon search");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "gtao_distance", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_ui_text(
prop, "Distance", "Distance of object that contribute to the ambient occlusion effect");
RNA_def_property_range(prop, 0.0f, 100000.0f);
@@ -6990,7 +6914,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
/* Depth of Field */
prop = RNA_def_property(srna, "bokeh_max_size", PROP_FLOAT, PROP_PIXEL);
- RNA_def_property_float_default(prop, 100.0f);
RNA_def_property_ui_text(
prop, "Max Size", "Max size of the bokeh shape for the depth of field (lower is faster)");
RNA_def_property_range(prop, 0.0f, 2000.0f);
@@ -6998,7 +6921,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
prop = RNA_def_property(srna, "bokeh_threshold", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(
prop, "Sprite Threshold", "Brightness threshold for using sprite base depth of field");
RNA_def_property_range(prop, 0.0f, 100000.0f);
@@ -7009,13 +6931,11 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
/* Bloom */
prop = RNA_def_property(srna, "use_bloom", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_BLOOM_ENABLED);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "Bloom", "High brightness pixels generate a glowing effect");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "bloom_threshold", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.8f);
RNA_def_property_ui_text(prop, "Threshold", "Filters out pixels under this level of brightness");
RNA_def_property_range(prop, 0.0f, 100000.0f);
RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
@@ -7023,21 +6943,18 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "bloom_color", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_float_array_default(prop, default_bloom_color);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Color", "Color applied to the bloom effect");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "bloom_knee", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_ui_text(prop, "Knee", "Makes transition between under/over-threshold gradual");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "bloom_radius", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 6.5f);
RNA_def_property_ui_text(prop, "Radius", "Bloom spread distance");
RNA_def_property_range(prop, 0.0f, 100.0f);
RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
@@ -7045,7 +6962,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "bloom_clamp", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.0f);
RNA_def_property_ui_text(
prop, "Clamp", "Maximum intensity a bloom pixel can have (0 to disabled)");
RNA_def_property_range(prop, 0.0f, 100000.0f);
@@ -7054,7 +6970,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "bloom_intensity", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.05f);
RNA_def_property_ui_text(prop, "Intensity", "Blend factor");
RNA_def_property_range(prop, 0.0f, 10000.0f);
RNA_def_property_ui_range(prop, 0.0f, 0.1f, 1, 3);
@@ -7064,20 +6979,17 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
/* Motion blur */
prop = RNA_def_property(srna, "use_motion_blur", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_MOTION_BLUR_ENABLED);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "Motion Blur", "Enable motion blur effect (only in camera view)");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "motion_blur_samples", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_default(prop, 8);
RNA_def_property_ui_text(prop, "Samples", "Number of samples to take with motion blur");
RNA_def_property_range(prop, 1, 64);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "motion_blur_shutter", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Shutter", "Time taken in frames between shutter open and close");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.01f, 1.0f, 1, 2);
@@ -7085,15 +6997,7 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
/* Shadows */
- prop = RNA_def_property(srna, "shadow_method", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_default(prop, SHADOW_ESM);
- RNA_def_property_enum_items(prop, eevee_shadow_method_items);
- RNA_def_property_ui_text(prop, "Method", "Technique use to compute the shadows");
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
prop = RNA_def_property(srna, "shadow_cube_size", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_default(prop, 512);
RNA_def_property_enum_items(prop, eevee_shadow_size_items);
RNA_def_property_ui_text(
prop, "Cube Shadows Resolution", "Size of point and area light shadow maps");
@@ -7101,7 +7005,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "shadow_cascade_size", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_default(prop, 1024);
RNA_def_property_enum_items(prop, eevee_shadow_size_items);
RNA_def_property_ui_text(
prop, "Directional Shadows Resolution", "Size of sun light shadow maps");
@@ -7110,21 +7013,18 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_shadow_high_bitdepth", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SHADOW_HIGH_BITDEPTH);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "High Bitdepth", "Use 32bit shadows");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_soft_shadows", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SHADOW_SOFT);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(
prop, "Soft Shadows", "Randomize shadowmaps origin to create soft shadows");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "light_threshold", PROP_FLOAT, PROP_UNSIGNED);
- RNA_def_property_float_default(prop, 0.01f);
RNA_def_property_ui_text(prop,
"Light Threshold",
"Minimum light intensity for a light to contribute to the lighting");
@@ -7136,7 +7036,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
/* Overscan */
prop = RNA_def_property(srna, "use_overscan", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_OVERSCAN);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop,
"Overscan",
"Internally render past the image border to avoid "
@@ -7145,7 +7044,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "overscan_size", PROP_FLOAT, PROP_PERCENTAGE);
RNA_def_property_float_sdna(prop, NULL, "overscan");
- RNA_def_property_float_default(prop, 3.0f);
RNA_def_property_ui_text(prop,
"Overscan Size",
"Percentage of render size to add as overscan to the "
@@ -7261,7 +7159,6 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "r.sfra");
RNA_def_property_int_funcs(prop, NULL, "rna_Scene_start_frame_set", NULL);
RNA_def_property_range(prop, MINFRAME, MAXFRAME);
- RNA_def_property_int_default(prop, 1);
RNA_def_property_ui_text(prop, "Start Frame", "First frame of the playback/rendering range");
RNA_def_property_update(prop, NC_SCENE | ND_FRAME_RANGE, NULL);
@@ -7270,7 +7167,6 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "r.efra");
RNA_def_property_int_funcs(prop, NULL, "rna_Scene_end_frame_set", NULL);
RNA_def_property_range(prop, MINFRAME, MAXFRAME);
- RNA_def_property_int_default(prop, 250);
RNA_def_property_ui_text(prop, "End Frame", "Final frame of the playback/rendering range");
RNA_def_property_update(prop, NC_SCENE | ND_FRAME_RANGE, NULL);
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index bea22d465a9..2b1b23a40f4 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -80,7 +80,7 @@ static void rna_Scene_frame_set(Scene *scene, Main *bmain, int frame, float subf
for (ViewLayer *view_layer = scene->view_layers.first; view_layer != NULL;
view_layer = view_layer->next) {
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
BKE_scene_graph_update_for_newframe(depsgraph, bmain);
}
@@ -156,7 +156,7 @@ static void rna_Scene_ray_cast(Scene *scene,
{
normalize_v3(direction);
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, depsgraph, 0);
bool ret = ED_transform_snap_object_project_ray_ex(sctx,
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 2e3f41d656b..1457bbfd3c3 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -162,24 +162,13 @@ const EnumPropertyItem rna_enum_symmetrize_direction_items[] = {
# include "DEG_depsgraph.h"
+# include "ED_gpencil.h"
# include "ED_particle.h"
static void rna_GPencil_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
/* mark all grease pencil datablocks of the scene */
- FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, ob) {
- if (ob->type == OB_GPENCIL) {
- bGPdata *gpd = (bGPdata *)ob->data;
- gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- }
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- }
- FOREACH_SCENE_COLLECTION_END;
-
- WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
+ ED_gpencil_tag_scene_gpencil(scene);
}
const EnumPropertyItem rna_enum_particle_edit_disconnected_hair_brush_items[] = {
@@ -215,10 +204,11 @@ static PointerRNA rna_ParticleBrush_curve_get(PointerRNA *ptr)
static void rna_ParticleEdit_redo(bContext *C, PointerRNA *UNUSED(ptr))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (!edit) {
return;
@@ -270,8 +260,9 @@ static const EnumPropertyItem *rna_ParticleEdit_tool_itemf(bContext *C,
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
# if 0
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys = edit ? edit->psys : NULL;
# else
/* use this rather than PE_get_current() - because the editing cache is
@@ -296,14 +287,14 @@ static bool rna_ParticleEdit_editable_get(PointerRNA *ptr)
{
ParticleEditSettings *pset = (ParticleEditSettings *)ptr->data;
- return (pset->object && pset->scene && PE_get_current(pset->scene, pset->object));
+ return (pset->object && pset->scene && PE_get_current(NULL, pset->scene, pset->object));
}
static bool rna_ParticleEdit_hair_get(PointerRNA *ptr)
{
ParticleEditSettings *pset = (ParticleEditSettings *)ptr->data;
if (pset->scene) {
- PTCacheEdit *edit = PE_get_current(pset->scene, pset->object);
+ PTCacheEdit *edit = PE_get_current(NULL, pset->scene, pset->object);
return (edit && edit->psys);
}
@@ -657,7 +648,7 @@ static void rna_def_paint(BlenderRNA *brna)
prop = RNA_def_property(srna, "input_samples", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "num_input_samples");
- RNA_def_property_ui_range(prop, 1, PAINT_MAX_INPUT_SAMPLES, 0, -1);
+ RNA_def_property_ui_range(prop, 1, PAINT_MAX_INPUT_SAMPLES, 1, -1);
RNA_def_property_ui_text(
prop, "Input Samples", "Average multiple input samples together to smooth the brush stroke");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
@@ -1032,7 +1023,7 @@ static void rna_def_image_paint(BlenderRNA *brna)
/* integers */
prop = RNA_def_property(srna, "seam_bleed", PROP_INT, PROP_PIXEL);
- RNA_def_property_ui_range(prop, 0, 8, 0, -1);
+ RNA_def_property_ui_range(prop, 0, 8, 1, -1);
RNA_def_property_ui_text(
prop, "Bleed", "Extend paint beyond the faces UVs to reduce seams (in pixels, slower)");
@@ -1047,11 +1038,12 @@ static void rna_def_image_paint(BlenderRNA *brna)
NULL,
0,
0,
- "screen_grab_size",
+ "Screen Grab Size",
"Size to capture the image for re-projecting",
0,
0);
RNA_def_property_range(prop, 512, 16384);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
@@ -1299,6 +1291,7 @@ static void rna_def_gpencil_guides(BlenderRNA *brna)
{GP_GUIDE_RADIAL, "RADIAL", 0, "Radial", "Use single point as direction"},
{GP_GUIDE_PARALLEL, "PARALLEL", 0, "Parallel", "Parallel lines"},
{GP_GUIDE_GRID, "GRID", 0, "Grid", "Grid allows horizontal and vertical lines"},
+ {GP_GUIDE_ISO, "ISO", 0, "Isometric", "Grid allows isometric and vertical lines"},
{0, NULL, 0, NULL, NULL},
};
@@ -1360,7 +1353,6 @@ static void rna_def_gpencil_guides(BlenderRNA *brna)
prop = RNA_def_property(srna, "spacing", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "spacing");
- RNA_def_property_float_default(prop, 0.01f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, 3);
RNA_def_property_ui_text(prop, "Spacing", "Guide spacing");
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 883468fa88e..dc0cc0482aa 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -1740,7 +1740,7 @@ static void rna_def_sequence(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3);
RNA_def_property_float_sdna(prop, NULL, "effect_fader");
- RNA_def_property_ui_text(prop, "Effect fader position", "Custom fade value");
+ RNA_def_property_ui_text(prop, "Effect Fader Position", "Custom fade value");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
@@ -1758,7 +1758,7 @@ static void rna_def_sequence(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "speed_fader");
RNA_def_property_ui_text(
prop,
- "Speed factor",
+ "Speed Factor",
"Multiply the current speed of the sequence with this number or remap current frame "
"to this frame");
RNA_def_property_update(
@@ -1932,12 +1932,19 @@ static void rna_def_editor(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_STORE_FINAL_OUT);
RNA_def_property_ui_text(prop, "Cache Final", "Cache final image for each frame");
+ prop = RNA_def_property(srna, "use_prefetch", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_PREFETCH_ENABLE);
+ RNA_def_property_ui_text(prop,
+ "Prefetch frames",
+ "Render frames ahead of playhead in background for faster playback");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
+
prop = RNA_def_property(srna, "recycle_max_cost", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0f, SEQ_CACHE_COST_MAX);
RNA_def_property_ui_range(prop, 0.0f, SEQ_CACHE_COST_MAX, 0.1f, 1);
RNA_def_property_float_sdna(prop, NULL, "recycle_max_cost");
RNA_def_property_ui_text(
- prop, "Recycle Up To Cost", "Only frames with cost lower than this value will be recycled");
+ prop, "Recycle Up to Cost", "Only frames with cost lower than this value will be recycled");
}
static void rna_def_filter_video(StructRNA *srna)
@@ -1958,12 +1965,6 @@ static void rna_def_filter_video(StructRNA *srna)
{0, NULL, 0, NULL, NULL},
};
- static const EnumPropertyItem playback_direction_items[] = {
- {0, "FORWARD", 0, "Forwards", "Play strip forwards"},
- {SEQ_REVERSE_FRAMES, "BACKWARD", 0, "Backwards", "Play strip backwards"},
- {0, NULL, 0, NULL, NULL},
- };
-
prop = RNA_def_property(srna, "use_deinterlace", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_FILTERY);
RNA_def_property_ui_text(prop, "Deinterlace", "Remove fields from video movies");
@@ -1990,10 +1991,9 @@ static void rna_def_filter_video(StructRNA *srna)
RNA_def_property_ui_text(prop, "Convert Float", "Convert input to float data");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
- prop = RNA_def_property(srna, "playback_direction", PROP_ENUM, PROP_NONE); /* as an enum */
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
- RNA_def_property_enum_items(prop, playback_direction_items);
- RNA_def_property_ui_text(prop, "Playback Direction", "Play strip forwards or backwards");
+ prop = RNA_def_property(srna, "use_reverse_frames", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_REVERSE_FRAMES);
+ RNA_def_property_ui_text(prop, "Reverse Frames", "Reverse frame order");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
prop = RNA_def_property(srna, "color_multiply", PROP_FLOAT, PROP_UNSIGNED);
@@ -2639,8 +2639,7 @@ static void rna_def_solid_color(StructRNA *srna)
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "col");
RNA_def_property_ui_text(prop, "Color", "Effect Strip color");
- RNA_def_property_update(
- prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
}
static void rna_def_speed_control(StructRNA *srna)
@@ -2661,14 +2660,14 @@ static void rna_def_speed_control(StructRNA *srna)
prop = RNA_def_property(srna, "use_as_speed", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_INTEGRATE);
RNA_def_property_ui_text(
- prop, "Use as speed", "Interpret the value as speed instead of a frame number");
+ prop, "Use as Speed", "Interpret the value as speed instead of a frame number");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
prop = RNA_def_property(srna, "use_scale_to_length", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_COMPRESS_IPO_Y);
RNA_def_property_ui_text(
- prop, "Scale to length", "Scale values from 0.0 to 1.0 to target sequence length");
+ prop, "Scale to Length", "Scale values from 0.0 to 1.0 to target sequence length");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
}
@@ -2758,14 +2757,16 @@ static void rna_def_text(StructRNA *srna)
prop = RNA_def_property(srna, "align_x", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "align");
RNA_def_property_enum_items(prop, text_align_x_items);
- RNA_def_property_ui_text(prop, "Align X", "Align the text along the X axis");
+ RNA_def_property_ui_text(
+ prop, "Align X", "Align the text along the X axis, relative to the text midpoint");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
prop = RNA_def_property(srna, "align_y", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "align_y");
RNA_def_property_enum_items(prop, text_align_y_items);
- RNA_def_property_ui_text(prop, "Align Y", "Align the image along the Y axis");
+ RNA_def_property_ui_text(
+ prop, "Align Y", "Align the image along the Y axis, relative to the text midpoint");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
@@ -3013,7 +3014,7 @@ static void rna_def_whitebalance_modifier(BlenderRNA *brna)
prop = RNA_def_property(srna, "white_value", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "white_value");
- RNA_def_property_ui_text(prop, "White value", "This color defines white in the strip");
+ RNA_def_property_ui_text(prop, "White Value", "This color defines white in the strip");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
}
diff --git a/source/blender/makesrna/intern/rna_shader_fx.c b/source/blender/makesrna/intern/rna_shader_fx.c
index acf525e1788..cd4e027ce7c 100644
--- a/source/blender/makesrna/intern/rna_shader_fx.c
+++ b/source/blender/makesrna/intern/rna_shader_fx.c
@@ -260,14 +260,14 @@ static void rna_def_shader_fx_colorize(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "low_color");
RNA_def_property_array(prop, 4);
- RNA_def_property_ui_text(prop, "Low color", "First color used for effect");
+ RNA_def_property_ui_text(prop, "Low Color", "First color used for effect");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "high_color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "high_color");
RNA_def_property_array(prop, 4);
- RNA_def_property_ui_text(prop, "Height color", "Second color used for effect");
+ RNA_def_property_ui_text(prop, "High Color", "Second color used for effect");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
index fa0297ac306..c00cc789eff 100644
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ b/source/blender/makesrna/intern/rna_smoke.c
@@ -588,7 +588,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_high_resolution", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_HIGHRES);
- RNA_def_property_ui_text(prop, "High res", "Enable high resolution (using amplification)");
+ RNA_def_property_ui_text(prop, "High Res", "Enable high resolution (using amplification)");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
@@ -668,7 +668,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_dissolve_smoke_log", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_DISSOLVE_LOG);
- RNA_def_property_ui_text(prop, "Logarithmic dissolve", "Using 1/x ");
+ RNA_def_property_ui_text(prop, "Logarithmic Dissolve", "Using 1/x ");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
@@ -1204,7 +1204,7 @@ static void rna_def_smoke_coll_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "collision_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, smoke_coll_type_items);
- RNA_def_property_ui_text(prop, "Collision type", "Collision type");
+ RNA_def_property_ui_text(prop, "Collision Type", "Collision type");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
}
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 8c855c9e870..56ba6403596 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -343,7 +343,11 @@ static const EnumPropertyItem autosnap_items[] = {
const EnumPropertyItem rna_enum_shading_type_items[] = {
{OB_WIRE, "WIREFRAME", ICON_SHADING_WIRE, "Wireframe", "Display the object as wire edges"},
{OB_SOLID, "SOLID", ICON_SHADING_SOLID, "Solid", "Display in solid mode"},
- {OB_MATERIAL, "MATERIAL", ICON_SHADING_TEXTURE, "Look Dev", "Display in Look Dev mode"},
+ {OB_MATERIAL,
+ "MATERIAL",
+ ICON_SHADING_TEXTURE,
+ "Material Preview",
+ "Display in Material Preview mode"},
{OB_RENDER, "RENDERED", ICON_SHADING_RENDERED, "Rendered", "Display render preview"},
{0, NULL, 0, NULL, NULL},
};
@@ -380,26 +384,30 @@ const EnumPropertyItem rna_enum_clip_editor_mode_items[] = {
* but helps for context-less access (e.g. doc, i18n...). */
static const EnumPropertyItem buttons_context_items[] = {
{BCONTEXT_TOOL, "TOOL", ICON_TOOL_SETTINGS, "Tool", "Active Tool and Workspace settings"},
- {BCONTEXT_SCENE, "SCENE", ICON_SCENE_DATA, "Scene", "Scene"},
- {BCONTEXT_RENDER, "RENDER", ICON_SCENE, "Render", "Render"},
- {BCONTEXT_OUTPUT, "OUTPUT", ICON_OUTPUT, "Output", "Output"},
- {BCONTEXT_VIEW_LAYER, "VIEW_LAYER", ICON_RENDER_RESULT, "View Layer", "View Layer"},
- {BCONTEXT_WORLD, "WORLD", ICON_WORLD, "World", "World"},
- {BCONTEXT_OBJECT, "OBJECT", ICON_OBJECT_DATA, "Object", "Object"},
- {BCONTEXT_CONSTRAINT, "CONSTRAINT", ICON_CONSTRAINT, "Constraints", "Object Constraints"},
- {BCONTEXT_MODIFIER, "MODIFIER", ICON_MODIFIER, "Modifiers", "Modifiers"},
- {BCONTEXT_DATA, "DATA", ICON_NONE, "Data", "Object Data"},
- {BCONTEXT_BONE, "BONE", ICON_BONE_DATA, "Bone", "Bone"},
+ {BCONTEXT_SCENE, "SCENE", ICON_SCENE_DATA, "Scene", "Scene Properties"},
+ {BCONTEXT_RENDER, "RENDER", ICON_SCENE, "Render", "Render Properties"},
+ {BCONTEXT_OUTPUT, "OUTPUT", ICON_OUTPUT, "Output", "Output Properties"},
+ {BCONTEXT_VIEW_LAYER, "VIEW_LAYER", ICON_RENDER_RESULT, "View Layer", "View Layer Properties"},
+ {BCONTEXT_WORLD, "WORLD", ICON_WORLD, "World", "World Properties"},
+ {BCONTEXT_OBJECT, "OBJECT", ICON_OBJECT_DATA, "Object", "Object Properties"},
+ {BCONTEXT_CONSTRAINT,
+ "CONSTRAINT",
+ ICON_CONSTRAINT,
+ "Constraints",
+ "Object Constraint Properties"},
+ {BCONTEXT_MODIFIER, "MODIFIER", ICON_MODIFIER, "Modifiers", "Modifier Properties"},
+ {BCONTEXT_DATA, "DATA", ICON_NONE, "Data", "Object Data Properties"},
+ {BCONTEXT_BONE, "BONE", ICON_BONE_DATA, "Bone", "Bone Properties"},
{BCONTEXT_BONE_CONSTRAINT,
"BONE_CONSTRAINT",
ICON_CONSTRAINT_BONE,
"Bone Constraints",
- "Bone Constraints"},
- {BCONTEXT_MATERIAL, "MATERIAL", ICON_MATERIAL, "Material", "Material"},
- {BCONTEXT_TEXTURE, "TEXTURE", ICON_TEXTURE, "Texture", "Texture"},
- {BCONTEXT_PARTICLE, "PARTICLES", ICON_PARTICLES, "Particles", "Particles"},
- {BCONTEXT_PHYSICS, "PHYSICS", ICON_PHYSICS, "Physics", "Physics"},
- {BCONTEXT_SHADERFX, "SHADERFX", ICON_SHADERFX, "Effects", "Object visual effects"},
+ "Bone Constraint Properties"},
+ {BCONTEXT_MATERIAL, "MATERIAL", ICON_MATERIAL, "Material", "Material Properties"},
+ {BCONTEXT_TEXTURE, "TEXTURE", ICON_TEXTURE, "Texture", "Texture Properties"},
+ {BCONTEXT_PARTICLE, "PARTICLES", ICON_PARTICLES, "Particles", "Particle Properties"},
+ {BCONTEXT_PHYSICS, "PHYSICS", ICON_PHYSICS, "Physics", "Physics Properties"},
+ {BCONTEXT_SHADERFX, "SHADERFX", ICON_SHADERFX, "Effects", "Visual Effects Properties"},
{0, NULL, 0, NULL, NULL},
};
@@ -420,19 +428,19 @@ const EnumPropertyItem rna_enum_file_sort_items[] = {
{FILE_SORT_ALPHA,
"FILE_SORT_ALPHA",
ICON_SORTALPHA,
- "Sort alphabetically",
+ "Name",
"Sort the file list alphabetically"},
{FILE_SORT_EXTENSION,
"FILE_SORT_EXTENSION",
ICON_SORTBYEXT,
- "Sort by extension",
+ "Extension",
"Sort the file list by extension/type"},
{FILE_SORT_TIME,
"FILE_SORT_TIME",
ICON_SORTTIME,
- "Sort by time",
+ "Modified Date",
"Sort files by modification time"},
- {FILE_SORT_SIZE, "FILE_SORT_SIZE", ICON_SORTSIZE, "Sort by size", "Sort files by size"},
+ {FILE_SORT_SIZE, "FILE_SORT_SIZE", ICON_SORTSIZE, "Size", "Sort files by size"},
{0, NULL, 0, NULL, NULL},
};
@@ -450,6 +458,7 @@ const EnumPropertyItem rna_enum_file_sort_items[] = {
# include "BKE_brush.h"
# include "BKE_colortools.h"
# include "BKE_context.h"
+# include "BKE_idprop.h"
# include "BKE_layer.h"
# include "BKE_global.h"
# include "BKE_nla.h"
@@ -930,6 +939,18 @@ static bool rna_RegionView3D_is_orthographic_side_view_get(PointerRNA *ptr)
return RV3D_VIEW_IS_AXIS(rv3d->view);
}
+static IDProperty *rna_View3DShading_idprops(PointerRNA *ptr, bool create)
+{
+ View3DShading *shading = ptr->data;
+
+ if (create && !shading->prop) {
+ IDPropertyTemplate val = {0};
+ shading->prop = IDP_New(IDP_GROUP, &val, "View3DShading ID properties");
+ }
+
+ return shading->prop;
+}
+
static void rna_3DViewShading_type_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
ID *id = ptr->owner_id;
@@ -1054,6 +1075,7 @@ static PointerRNA rna_View3DShading_selected_studio_light_get(PointerRNA *ptr)
sl = BKE_studiolight_find(shading->studio_light, STUDIOLIGHT_FLAG_ALL);
}
else {
+ /* OB_MATERIAL and OB_RENDER */
sl = BKE_studiolight_find(shading->lookdev_light, STUDIOLIGHT_FLAG_ALL);
}
return rna_pointer_inherit_refine(ptr, &RNA_StudioLight, sl);
@@ -1088,21 +1110,32 @@ static const EnumPropertyItem *rna_View3DShading_color_type_itemf(bContext *UNUS
}
}
-/* Studio light */
-static int rna_View3DShading_studio_light_get(PointerRNA *ptr)
+static void rna_View3DShading_studio_light_get_storage(View3DShading *shading,
+ char **dna_storage,
+ int *flag)
{
- View3DShading *shading = (View3DShading *)ptr->data;
- char *dna_storage = shading->studio_light;
+ *dna_storage = shading->studio_light;
- int flag = STUDIOLIGHT_TYPE_STUDIO;
- if (shading->type == OB_SOLID && shading->light == V3D_LIGHTING_MATCAP) {
- flag = STUDIOLIGHT_TYPE_MATCAP;
- dna_storage = shading->matcap;
+ *flag = STUDIOLIGHT_TYPE_STUDIO;
+ if (shading->type == OB_SOLID) {
+ if (shading->light == V3D_LIGHTING_MATCAP) {
+ *flag = STUDIOLIGHT_TYPE_MATCAP;
+ *dna_storage = shading->matcap;
+ }
}
- else if (shading->type == OB_MATERIAL) {
- flag = STUDIOLIGHT_TYPE_WORLD;
- dna_storage = shading->lookdev_light;
+ else {
+ *flag = STUDIOLIGHT_TYPE_WORLD;
+ *dna_storage = shading->lookdev_light;
}
+}
+
+static int rna_View3DShading_studio_light_get(PointerRNA *ptr)
+{
+ View3DShading *shading = (View3DShading *)ptr->data;
+ char *dna_storage;
+ int flag;
+
+ rna_View3DShading_studio_light_get_storage(shading, &dna_storage, &flag);
StudioLight *sl = BKE_studiolight_find(dna_storage, flag);
if (sl) {
BLI_strncpy(dna_storage, sl->name, FILE_MAXFILE);
@@ -1116,17 +1149,10 @@ static int rna_View3DShading_studio_light_get(PointerRNA *ptr)
static void rna_View3DShading_studio_light_set(PointerRNA *ptr, int value)
{
View3DShading *shading = (View3DShading *)ptr->data;
- char *dna_storage = shading->studio_light;
+ char *dna_storage;
+ int flag;
- int flag = STUDIOLIGHT_TYPE_STUDIO;
- if (shading->type == OB_SOLID && shading->light == V3D_LIGHTING_MATCAP) {
- flag = STUDIOLIGHT_TYPE_MATCAP;
- dna_storage = shading->matcap;
- }
- else if (shading->type == OB_MATERIAL) {
- flag = STUDIOLIGHT_TYPE_WORLD;
- dna_storage = shading->lookdev_light;
- }
+ rna_View3DShading_studio_light_get_storage(shading, &dna_storage, &flag);
StudioLight *sl = BKE_studiolight_findindex(value, flag);
if (sl) {
BLI_strncpy(dna_storage, sl->name, FILE_MAXFILE);
@@ -1173,6 +1199,7 @@ static const EnumPropertyItem *rna_View3DShading_studio_light_itemf(bContext *UN
break;
case OB_MATERIAL:
+ case OB_RENDER:
show_studiolight = ((sl->flag & STUDIOLIGHT_TYPE_WORLD) != 0);
icon_id = sl->icon_id_radiance;
break;
@@ -1191,6 +1218,19 @@ static const EnumPropertyItem *rna_View3DShading_studio_light_itemf(bContext *UN
return item;
}
+static void rna_SpaceView3D_use_local_collections_update(bContext *C, PointerRNA *ptr)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = (View3D *)ptr->data;
+
+ if (ED_view3d_local_collections_set(bmain, v3d)) {
+ BKE_layer_collection_local_sync(view_layer, v3d);
+ DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
+ }
+}
+
static const EnumPropertyItem *rna_SpaceView3D_stereo3d_camera_itemf(bContext *C,
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
@@ -2142,6 +2182,18 @@ static void rna_SpaceClipEditor_view_type_update(Main *UNUSED(bmain),
/* File browser. */
+int rna_FileSelectParams_filename_editable(struct PointerRNA *ptr, const char **r_info)
+{
+ FileSelectParams *params = ptr->data;
+
+ if (params && (params->flag & FILE_DIRSEL_ONLY)) {
+ *r_info = "Only directories can be chosen for the current operation.";
+ return 0;
+ }
+
+ return params ? PROP_EDITABLE : 0;
+}
+
static bool rna_FileSelectParams_use_lib_get(PointerRNA *ptr)
{
FileSelectParams *params = ptr->data;
@@ -2711,11 +2763,6 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Display Faces", "Display faces over the image");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
- prop = RNA_def_property(srna, "show_edges", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SI_NO_DRAWEDGES);
- RNA_def_property_ui_text(prop, "Display Edges", "Display edges in vertex select mode");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
-
/* todo: move edge and face drawing options here from G.f */
prop = RNA_def_property(srna, "pixel_snap_mode", PROP_ENUM, PROP_NONE);
@@ -2929,7 +2976,7 @@ static void rna_def_space_outliner(BlenderRNA *brna)
/* Libraries filter. */
prop = RNA_def_property(srna, "use_filter_id_type", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filter", SO_FILTER_ID_TYPE);
- RNA_def_property_ui_text(prop, "Filter By Type", "Show only data-blocks of one type");
+ RNA_def_property_ui_text(prop, "Filter by Type", "Show only data-blocks of one type");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
prop = RNA_def_property(srna, "filter_id_type", PROP_ENUM, PROP_NONE);
@@ -2954,7 +3001,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
"Use a custom color limited to this viewport only"},
{0, NULL, 0, NULL, NULL},
};
- static const float default_background_color[] = {0.05f, 0.05f, 0.05f};
static const EnumPropertyItem cavity_type_items[] = {
{V3D_SHADING_CAVITY_SSAO,
@@ -2977,6 +3023,7 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
RNA_def_struct_path_func(srna, "rna_View3DShading_path");
RNA_def_struct_ui_text(
srna, "3D View Shading Settings", "Settings for shading in the 3D viewport");
+ RNA_def_struct_idprops_func(srna, "rna_View3DShading_idprops");
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_shading_type_items);
@@ -3036,7 +3083,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "curvature_ridge_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "curvature_ridge_factor");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Curvature Ridge", "Factor for the curvature ridges");
RNA_def_property_range(prop, 0.0f, 2.0f);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -3044,7 +3090,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "curvature_valley_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "curvature_valley_factor");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Curvature Valley", "Factor for the curvature valleys");
RNA_def_property_range(prop, 0.0f, 2.0f);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -3052,7 +3097,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "cavity_ridge_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "cavity_ridge_factor");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Cavity Ridge", "Factor for the cavity ridges");
RNA_def_property_range(prop, 0.0f, 250.0f);
RNA_def_property_ui_range(prop, 0.00f, 2.5f, 1, 3);
@@ -3061,7 +3105,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "cavity_valley_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "cavity_valley_factor");
- RNA_def_property_float_default(prop, 1.0);
RNA_def_property_ui_text(prop, "Cavity Valley", "Factor for the cavity valleys");
RNA_def_property_range(prop, 0.0f, 250.0f);
RNA_def_property_ui_range(prop, 0.00f, 2.5f, 1, 3);
@@ -3079,13 +3122,28 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "studiolight_rotate_z", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "studiolight_rot_z");
- RNA_def_property_float_default(prop, 0.0);
RNA_def_property_ui_text(
prop, "Studiolight Rotation", "Rotation of the studiolight around the Z-Axis");
RNA_def_property_range(prop, -M_PI, M_PI);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ prop = RNA_def_property(srna, "studiolight_intensity", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "studiolight_intensity");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Strength", "Strength of the studiolight");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 2.0f, 1, 3);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "studiolight_background_alpha", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "studiolight_background");
+ RNA_def_property_ui_text(prop, "Background", "Show the studiolight in the background");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0.00f, 1.0f, 1, 3);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
prop = RNA_def_property(srna, "color_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "color_type");
RNA_def_property_enum_items(prop, rna_enum_shading_color_type_items);
@@ -3115,7 +3173,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "background_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_array(prop, 3);
- RNA_def_property_float_array_default(prop, default_background_color);
RNA_def_property_ui_text(prop, "Background Color", "Color for custom background color");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -3140,7 +3197,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "xray_alpha", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "xray_alpha");
- RNA_def_property_float_default(prop, 0.5);
RNA_def_property_ui_text(prop, "X-Ray Alpha", "Amount of alpha to use");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -3148,7 +3204,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "xray_alpha_wireframe", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "xray_alpha_wire");
- RNA_def_property_float_default(prop, 0.5);
RNA_def_property_ui_text(prop, "X-Ray Alpha", "Amount of alpha to use");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -3165,12 +3220,26 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_scene_lights", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SCENE_LIGHTS);
+ RNA_def_property_boolean_default(prop, false);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Scene Lights", "Render lights and light probes of the scene");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "use_scene_world", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SCENE_WORLD);
+ RNA_def_property_boolean_default(prop, false);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Scene World", "Use scene world for lighting");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "use_scene_lights_render", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SCENE_LIGHTS_RENDER);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Scene Lights", "Render lights and light probes of the scene");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "use_scene_world_render", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SCENE_WORLD_RENDER);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Scene World", "Use scene world for lighting");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -3190,21 +3259,11 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "shadow_intensity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "shadow_intensity");
- RNA_def_property_float_default(prop, 0.5);
RNA_def_property_ui_text(prop, "Shadow Intensity", "Darkness of shadows");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_range(prop, 0.00f, 1.0f, 1, 3);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "studiolight_background_alpha", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "studiolight_background");
- RNA_def_property_float_default(prop, 0.0);
- RNA_def_property_ui_text(prop, "Background", "Show the studiolight in the background");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_range(prop, 0.00f, 1.0f, 1, 3);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
}
static void rna_def_space_view3d_overlay(BlenderRNA *brna)
@@ -3254,7 +3313,6 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Grid Scale", "Distance between 3D View grid lines");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, 1000.0f, 0.1f, 3);
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "grid_lines", PROP_INT, PROP_NONE);
@@ -3262,14 +3320,12 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Grid Lines", "Number of grid lines to display in perspective view");
RNA_def_property_range(prop, 0, 1024);
- RNA_def_property_int_default(prop, 16);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "grid_subdivisions", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "gridsubdiv");
RNA_def_property_ui_text(prop, "Grid Subdivisions", "Number of subdivisions between grid lines");
RNA_def_property_range(prop, 1, 1024);
- RNA_def_property_int_default(prop, 10);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "grid_scale_unit", PROP_FLOAT, PROP_NONE);
@@ -3342,7 +3398,6 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "xray_alpha_bone", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "overlay.xray_alpha_bone");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_ui_text(prop, "Opacity", "Opacity to use for bone selection");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -3364,7 +3419,7 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_look_dev", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_LOOK_DEV);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Look Dev Preview", "Show look development spheres and palette");
+ RNA_def_property_ui_text(prop, "Look Dev Preview", "Show look development spheres");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "show_wireframes", PROP_BOOLEAN, PROP_NONE);
@@ -3375,7 +3430,6 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "wireframe_threshold", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "overlay.wireframe_threshold");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_ui_text(
prop, "Wireframe Threshold", "Adjust the number of wires displayed (1 for all wires)");
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -3542,7 +3596,6 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "texture_paint_mode_opacity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "overlay.texture_paint_mode_opacity");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(
prop, "Stencil Opacity", "Opacity of the texture paint mode stencil mask overlay");
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -3550,7 +3603,6 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "vertex_paint_mode_opacity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "overlay.vertex_paint_mode_opacity");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(
prop, "Vertex Paint Opacity", "Opacity of the vertex paint mode overlay");
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -3558,7 +3610,6 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "weight_paint_mode_opacity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "overlay.weight_paint_mode_opacity");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(
prop, "Weight Paint Opacity", "Opacity of the weight paint mode overlay");
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -3566,7 +3617,6 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "sculpt_mode_mask_opacity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "overlay.sculpt_mode_mask_opacity");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Sculpt Mask Opacity", "");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -3579,10 +3629,10 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_gpencil_paper", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_PAPER);
- RNA_def_property_ui_text(prop,
- "Use Paper",
- "Cover all viewport with a full color layer to improve visibility "
- "while drawing over complex scenes");
+ RNA_def_property_ui_text(
+ prop,
+ "Fade Objects",
+ "Fade all viewport objects with a full color layer to improve visibility");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "use_gpencil_grid", PROP_BOOLEAN, PROP_NONE);
@@ -3596,10 +3646,15 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop, "Fade Layers", "Toggle fading of Grease Pencil layers except the active one");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+ prop = RNA_def_property(srna, "use_gpencil_fade_objects", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_FADE_NOACTIVE_GPENCIL);
+ RNA_def_property_ui_text(
+ prop, "Fade Grease Pencil Objects", "Fade Grease Pencil Objects, except the active one");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+
prop = RNA_def_property(srna, "gpencil_grid_opacity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "overlay.gpencil_grid_opacity");
RNA_def_property_range(prop, 0.1f, 1.0f);
- RNA_def_property_float_default(prop, 0.9f);
RNA_def_property_ui_text(prop, "Opacity", "Canvas grid opacity");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -3607,8 +3662,7 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "gpencil_paper_opacity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "overlay.gpencil_paper_opacity");
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_float_default(prop, 0.5f);
- RNA_def_property_ui_text(prop, "Opacity", "Paper opacity");
+ RNA_def_property_ui_text(prop, "Opacity", "Fade factor");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
/* Paper opacity factor */
@@ -3756,7 +3810,6 @@ static void rna_def_space_view3d(BlenderRNA *brna)
prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
- RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_ui_text(
prop, "Clip Start", "3D View near clipping distance (perspective view only)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -3764,7 +3817,6 @@ static void rna_def_space_view3d(BlenderRNA *brna)
prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
- RNA_def_property_float_default(prop, 1000.0f);
RNA_def_property_ui_text(prop, "Clip End", "3D View far clipping distance");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -3912,6 +3964,14 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "FX Options", "Options used for real time compositing");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ prop = RNA_def_property(srna, "use_local_collections", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_LOCAL_COLLECTIONS);
+ RNA_def_property_ui_text(
+ prop, "Local Collections", "Display a different set of collections in this viewport");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(
+ prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_use_local_collections_update");
+
/* Stereo Settings */
prop = RNA_def_property(srna, "stereo_3d_eye", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "multiview_eye");
@@ -4153,7 +4213,7 @@ static void rna_def_space_buttons(BlenderRNA *brna)
RNA_def_property_enum_items(prop, buttons_context_items);
RNA_def_property_enum_funcs(
prop, NULL, "rna_SpaceProperties_context_set", "rna_SpaceProperties_context_itemf");
- RNA_def_property_ui_text(prop, "Context", "");
+ RNA_def_property_ui_text(prop, "", "");
RNA_def_property_update(
prop, NC_SPACE | ND_SPACE_PROPERTIES, "rna_SpaceProperties_context_update");
@@ -4222,7 +4282,7 @@ static void rna_def_space_image(BlenderRNA *brna)
prop = RNA_def_property(srna, "sample_histogram", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "sample_line_hist");
RNA_def_property_struct_type(prop, "Histogram");
- RNA_def_property_ui_text(prop, "Line sample", "Sampled colors along line");
+ RNA_def_property_ui_text(prop, "Line Sample", "Sampled colors along line");
prop = RNA_def_property(srna, "zoom", PROP_FLOAT, PROP_NONE);
RNA_def_property_array(prop, 2);
@@ -4659,7 +4719,7 @@ static void rna_def_space_text(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_match_case", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", ST_MATCH_CASE);
RNA_def_property_ui_text(
- prop, "Match case", "Search string is sensitive to uppercase and lowercase letters");
+ prop, "Match Case", "Search string is sensitive to uppercase and lowercase letters");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL);
prop = RNA_def_property(srna, "find_text", PROP_STRING, PROP_NONE);
@@ -5138,25 +5198,25 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
PropertyRNA *prop;
static const EnumPropertyItem file_display_items[] = {
- {FILE_SHORTDISPLAY,
- "LIST_SHORT",
- ICON_SHORTDISPLAY,
- "Short List",
- "Display files as short list"},
- {FILE_LONGDISPLAY,
- "LIST_LONG",
+ {FILE_VERTICALDISPLAY,
+ "LIST_VERTICAL",
ICON_LONGDISPLAY,
- "Long List",
- "Display files as a detailed list"},
+ "Vertical List",
+ "Display files as a vertical list"},
+ {FILE_HORIZONTALDISPLAY,
+ "LIST_HORIZONTAL",
+ ICON_SHORTDISPLAY,
+ "Horizontal List",
+ "Display files as a horizontal list"},
{FILE_IMGDISPLAY, "THUMBNAIL", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem display_size_items[] = {
- {32, "TINY", 0, "Tiny", ""},
- {64, "SMALL", 0, "Small", ""},
+ {64, "TINY", 0, "Tiny", ""},
+ {96, "SMALL", 0, "Small", ""},
{128, "NORMAL", 0, "Regular", ""},
- {256, "LARGE", 0, "Large", ""},
+ {192, "LARGE", 0, "Large", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -5272,7 +5332,10 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Title", "Title for the file browser");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- prop = RNA_def_property(srna, "directory", PROP_STRING, PROP_DIRPATH);
+ /* Use BYTESTRING rather than DIRPATH as subtype so UI code doesn't add OT_directory_browse
+ * button when displaying this prop in the file browser (it would just open a file browser). That
+ * should be the only effective difference between the two. */
+ prop = RNA_def_property(srna, "directory", PROP_STRING, PROP_BYTESTRING);
RNA_def_property_string_sdna(prop, NULL, "dir");
RNA_def_property_ui_text(prop, "Directory", "Directory displayed in the file browser");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
@@ -5280,6 +5343,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
prop = RNA_def_property(srna, "filename", PROP_STRING, PROP_FILENAME);
RNA_def_property_string_sdna(prop, NULL, "file");
RNA_def_property_ui_text(prop, "File Name", "Active file in the file browser");
+ RNA_def_property_editable_func(prop, "rna_FileSelectParams_filename_editable");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
prop = RNA_def_property(srna, "use_library_browsing", PROP_BOOLEAN, PROP_NONE);
@@ -5300,6 +5364,19 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Recursion", "Numbers of dirtree levels to show simultaneously");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+ prop = RNA_def_property(srna, "show_details_size", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "details_flags", FILE_DETAILS_SIZE);
+ RNA_def_property_ui_text(prop, "File Size", "Draw a column listing the size of each file");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+
+ prop = RNA_def_property(srna, "show_details_datetime", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "details_flags", FILE_DETAILS_DATETIME);
+ RNA_def_property_ui_text(
+ prop,
+ "File Modification Date",
+ "Draw a column listing the date and time of modification for each file");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+
prop = RNA_def_property(srna, "use_filter", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FILE_FILTER);
RNA_def_property_ui_text(prop, "Filter Files", "Enable filtering of files");
@@ -5316,6 +5393,12 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Sort", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+ prop = RNA_def_property(srna, "use_sort_invert", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", FILE_SORT_INVERT);
+ RNA_def_property_ui_text(
+ prop, "Reverse Sorting", "Sort items descending, from highest value to lowest");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+
prop = RNA_def_property(srna, "use_filter_image", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filter", FILE_TYPE_IMAGE);
RNA_def_property_ui_text(prop, "Filter Images", "Show image files");
@@ -5331,7 +5414,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_filter_backup", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filter", FILE_TYPE_BLENDER_BACKUP);
RNA_def_property_ui_text(
- prop, "Filter BlenderBackup files", "Show .blend1, .blend2, etc. files");
+ prop, "Filter Blender Backup Files", "Show .blend1, .blend2, etc. files");
RNA_def_property_ui_icon(prop, ICON_FILE_BACKUP, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
@@ -5383,7 +5466,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_enum_items(prop, file_filter_idtypes_items);
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_ui_text(
- prop, "Filter ID types", "Which ID types to show/hide, when browsing a library");
+ prop, "Filter ID Types", "Which ID types to show/hide, when browsing a library");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
prop = RNA_def_property(srna, "filter_id_category", PROP_ENUM, PROP_NONE);
@@ -5391,7 +5474,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_enum_items(prop, file_filter_idcategories_items);
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_ui_text(
- prop, "Filter ID categories", "Which ID categories to show/hide, when browsing a library");
+ prop, "Filter ID Categories", "Which ID categories to show/hide, when browsing a library");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
prop = RNA_def_property(srna, "filter_glob", PROP_STRING, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c
index 52a197240da..cbaa407646f 100644
--- a/source/blender/makesrna/intern/rna_space_api.c
+++ b/source/blender/makesrna/intern/rna_space_api.c
@@ -40,6 +40,7 @@ static void rna_RegionView3D_update(ID *id, RegionView3D *rv3d, bContext *C)
area_region_from_regiondata(sc, rv3d, &sa, &ar);
if (sa && ar && sa->spacetype == SPACE_VIEW3D) {
+ Main *bmain = CTX_data_main(C);
View3D *v3d = sa->spacedata.first;
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win;
@@ -48,7 +49,7 @@ static void rna_RegionView3D_update(ID *id, RegionView3D *rv3d, bContext *C)
if (WM_window_get_active_screen(win) == sc) {
Scene *scene = WM_window_get_active_scene(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, NULL, NULL, NULL, false);
break;
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 2ab08c82b63..356ecd5b4db 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -465,18 +465,6 @@ static void rna_def_texmapping(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
- static const EnumPropertyItem prop_vect_type_items[] = {
- {TEXMAP_TYPE_TEXTURE,
- "TEXTURE",
- 0,
- "Texture",
- "Transform a texture by inverse mapping the texture coordinate"},
- {TEXMAP_TYPE_POINT, "POINT", 0, "Point", "Transform a point"},
- {TEXMAP_TYPE_VECTOR, "VECTOR", 0, "Vector", "Transform a direction vector"},
- {TEXMAP_TYPE_NORMAL, "NORMAL", 0, "Normal", "Transform a normal vector with unit length"},
- {0, NULL, 0, NULL, NULL},
- };
-
static const EnumPropertyItem prop_xyz_mapping_items[] = {
{0, "NONE", 0, "None", ""},
{1, "X", 0, "X", ""},
@@ -493,7 +481,7 @@ static void rna_def_texmapping(BlenderRNA *brna)
prop = RNA_def_property(srna, "vector_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_vect_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_mapping_type_items);
RNA_def_property_ui_text(prop, "Type", "Type of vector that the mapping transforms");
RNA_def_property_update(prop, 0, "rna_Texture_mapping_update");
@@ -581,16 +569,19 @@ static void rna_def_colormapping(BlenderRNA *brna)
prop = RNA_def_property(srna, "brightness", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bright");
RNA_def_property_range(prop, 0, 2);
+ RNA_def_property_ui_range(prop, 0, 2, 1, 3);
RNA_def_property_ui_text(prop, "Brightness", "Adjust the brightness of the texture");
RNA_def_property_update(prop, 0, "rna_Color_mapping_update");
prop = RNA_def_property(srna, "contrast", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 5);
+ RNA_def_property_ui_range(prop, 0, 5, 1, 3);
RNA_def_property_ui_text(prop, "Contrast", "Adjust the contrast of the texture");
RNA_def_property_update(prop, 0, "rna_Color_mapping_update");
prop = RNA_def_property(srna, "saturation", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0, 2);
+ RNA_def_property_ui_range(prop, 0, 2, 1, 3);
RNA_def_property_ui_text(prop, "Saturation", "Adjust the saturation of colors in the texture");
RNA_def_property_update(prop, 0, "rna_Color_mapping_update");
@@ -828,14 +819,14 @@ static void rna_def_texture_clouds(BlenderRNA *brna)
prop = RNA_def_property(srna, "noise_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "noisesize");
RNA_def_property_range(prop, 0.0001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0001, 2, 10, 2);
+ RNA_def_property_ui_range(prop, 0.0001, 2, 1, 2);
RNA_def_property_ui_text(prop, "Noise Size", "Scaling for noise input");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "noise_depth", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "noisedepth");
RNA_def_property_range(prop, 0, 30);
- RNA_def_property_ui_range(prop, 0, 24, 0, 2);
+ RNA_def_property_ui_range(prop, 0, 24, 1, 2);
RNA_def_property_ui_text(prop, "Noise Depth", "Depth of the cloud calculation");
RNA_def_property_update(prop, 0, "rna_Texture_nodes_update");
@@ -892,7 +883,7 @@ static void rna_def_texture_wood(BlenderRNA *brna)
prop = RNA_def_property(srna, "noise_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "noisesize");
RNA_def_property_range(prop, 0.0001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0001, 2, 10, 2);
+ RNA_def_property_ui_range(prop, 0.0001, 2, 1, 2);
RNA_def_property_ui_text(prop, "Noise Size", "Scaling for noise input");
RNA_def_property_update(prop, 0, "rna_Texture_update");
@@ -960,7 +951,7 @@ static void rna_def_texture_marble(BlenderRNA *brna)
prop = RNA_def_property(srna, "noise_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "noisesize");
RNA_def_property_range(prop, 0.0001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0001, 2, 10, 2);
+ RNA_def_property_ui_range(prop, 0.0001, 2, 1, 2);
RNA_def_property_ui_text(prop, "Noise Size", "Scaling for noise input");
RNA_def_property_update(prop, 0, "rna_Texture_update");
@@ -974,7 +965,7 @@ static void rna_def_texture_marble(BlenderRNA *brna)
prop = RNA_def_property(srna, "noise_depth", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "noisedepth");
RNA_def_property_range(prop, 0, 30);
- RNA_def_property_ui_range(prop, 0, 24, 0, 2);
+ RNA_def_property_ui_range(prop, 0, 24, 1, 2);
RNA_def_property_ui_text(prop, "Noise Depth", "Depth of the cloud calculation");
RNA_def_property_update(prop, 0, "rna_Texture_update");
@@ -1028,7 +1019,7 @@ static void rna_def_texture_magic(BlenderRNA *brna)
prop = RNA_def_property(srna, "noise_depth", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "noisedepth");
RNA_def_property_range(prop, 0, 30);
- RNA_def_property_ui_range(prop, 0, 24, 0, 2);
+ RNA_def_property_ui_range(prop, 0, 24, 1, 2);
RNA_def_property_ui_text(prop, "Noise Depth", "Depth of the noise");
RNA_def_property_update(prop, 0, "rna_Texture_update");
}
@@ -1108,7 +1099,7 @@ static void rna_def_texture_stucci(BlenderRNA *brna)
prop = RNA_def_property(srna, "noise_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "noisesize");
RNA_def_property_range(prop, 0.0001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0001, 2, 10, 2);
+ RNA_def_property_ui_range(prop, 0.0001, 2, 1, 2);
RNA_def_property_ui_text(prop, "Noise Size", "Scaling for noise input");
RNA_def_property_update(prop, 0, "rna_Texture_update");
@@ -1332,43 +1323,49 @@ static void rna_def_texture_musgrave(BlenderRNA *brna)
prop = RNA_def_property(srna, "dimension_max", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "mg_H");
RNA_def_property_range(prop, 0.0001, 2);
+ RNA_def_property_ui_range(prop, 0.0001, 2, 1, 2);
RNA_def_property_ui_text(prop, "Highest Dimension", "Highest fractal dimension");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "lacunarity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "mg_lacunarity");
RNA_def_property_range(prop, 0, 6);
+ RNA_def_property_ui_range(prop, 0, 6, 1, 2);
RNA_def_property_ui_text(prop, "Lacunarity", "Gap between successive frequencies");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "octaves", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "mg_octaves");
RNA_def_property_range(prop, 0, 8);
+ RNA_def_property_ui_range(prop, 0, 8, 1, 2);
RNA_def_property_ui_text(prop, "Octaves", "Number of frequencies used");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "mg_offset");
RNA_def_property_range(prop, 0, 6);
+ RNA_def_property_ui_range(prop, 0, 6, 1, 2);
RNA_def_property_ui_text(prop, "Offset", "The fractal offset");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "gain", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "mg_gain");
RNA_def_property_range(prop, 0, 6);
+ RNA_def_property_ui_range(prop, 0, 6, 1, 2);
RNA_def_property_ui_text(prop, "Gain", "The gain multiplier");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "noise_intensity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "ns_outscale");
RNA_def_property_range(prop, 0, 10);
+ RNA_def_property_ui_range(prop, 0, 10, 1, 2);
RNA_def_property_ui_text(prop, "Noise Intensity", "Intensity of the noise");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "noise_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "noisesize");
RNA_def_property_range(prop, 0.0001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0001, 2, 10, 2);
+ RNA_def_property_ui_range(prop, 0.0001, 2, 1, 2);
RNA_def_property_ui_text(prop, "Noise Size", "Scaling for noise input");
RNA_def_property_update(prop, 0, "rna_Texture_update");
@@ -1485,7 +1482,7 @@ static void rna_def_texture_voronoi(BlenderRNA *brna)
prop = RNA_def_property(srna, "noise_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "noisesize");
RNA_def_property_range(prop, 0.0001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0001, 2, 10, 2);
+ RNA_def_property_ui_range(prop, 0.0001, 2, 1, 2);
RNA_def_property_ui_text(prop, "Noise Size", "Scaling for noise input");
RNA_def_property_update(prop, 0, "rna_Texture_update");
@@ -1514,7 +1511,7 @@ static void rna_def_texture_distorted_noise(BlenderRNA *brna)
prop = RNA_def_property(srna, "noise_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "noisesize");
RNA_def_property_range(prop, 0.0001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0001, 2, 10, 2);
+ RNA_def_property_ui_range(prop, 0.0001, 2, 1, 2);
RNA_def_property_ui_text(prop, "Noise Size", "Scaling for noise input");
RNA_def_property_update(prop, 0, "rna_Texture_update");
@@ -1580,16 +1577,19 @@ static void rna_def_texture(BlenderRNA *brna)
prop = RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bright");
RNA_def_property_range(prop, 0, 2);
+ RNA_def_property_ui_range(prop, 0, 2, 1, 3);
RNA_def_property_ui_text(prop, "Brightness", "Adjust the brightness of the texture");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "contrast", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 5);
+ RNA_def_property_ui_range(prop, 0, 5, 1, 3);
RNA_def_property_ui_text(prop, "Contrast", "Adjust the contrast of the texture");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "saturation", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0, 2);
+ RNA_def_property_ui_range(prop, 0, 2, 1, 3);
RNA_def_property_ui_text(prop, "Saturation", "Adjust the saturation of colors in the texture");
RNA_def_property_update(prop, 0, "rna_Texture_update");
@@ -1597,18 +1597,21 @@ static void rna_def_texture(BlenderRNA *brna)
prop = RNA_def_property(srna, "factor_red", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "rfac");
RNA_def_property_range(prop, 0, 2);
+ RNA_def_property_ui_range(prop, 0, 2, 1, 3);
RNA_def_property_ui_text(prop, "Factor Red", "");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "factor_green", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "gfac");
RNA_def_property_range(prop, 0, 2);
+ RNA_def_property_ui_range(prop, 0, 2, 1, 3);
RNA_def_property_ui_text(prop, "Factor Green", "");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "factor_blue", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bfac");
RNA_def_property_range(prop, 0, 2);
+ RNA_def_property_ui_range(prop, 0, 2, 1, 3);
RNA_def_property_ui_text(prop, "Factor Blue", "");
RNA_def_property_update(prop, 0, "rna_Texture_update");
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index 0a824b3c67a..4b232251770 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -1037,7 +1037,7 @@ static void rna_def_trackingSettings(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_enum_items(prop, tracker_motion_model);
- RNA_def_property_ui_text(prop, "Motion model", "Default motion model to use for tracking");
+ RNA_def_property_ui_text(prop, "Motion Model", "Default motion model to use for tracking");
/* default_use_brute */
prop = RNA_def_property(srna, "use_default_brute", PROP_BOOLEAN, PROP_NONE);
@@ -1470,7 +1470,7 @@ static void rna_def_trackingTrack(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_enum_items(prop, tracker_motion_model);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Motion model", "Default motion model to use for tracking");
+ RNA_def_property_ui_text(prop, "Motion Model", "Default motion model to use for tracking");
/* minimum correlation */
prop = RNA_def_property(srna, "correlation_min", PROP_FLOAT, PROP_NONE);
@@ -1849,7 +1849,7 @@ static void rna_def_trackingStabilization(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_2d_stabilization", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", TRACKING_2D_STABILIZATION);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Use 2D stabilization", "Use 2D stabilization for footage");
+ RNA_def_property_ui_text(prop, "Use 2D Stabilization", "Use 2D stabilization for footage");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
/* use_stabilize_rotation */
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index c8b039bd2d6..74d1743dfc1 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -1519,6 +1519,13 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_int(func, "rows", 5, 1, INT_MAX, "", "Maximum number of items to show", 1, INT_MAX);
parm = RNA_def_int(func, "found", 0, 0, INT_MAX, "", "Number of items drawn", 0, INT_MAX);
RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "template_file_select_path", "uiTemplateFileSelectPath");
+ RNA_def_function_ui_description(func,
+ "Item. A text button to set the active file browser path.");
+ parm = RNA_def_pointer(func, "params", "FileSelectParams", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 72a3455b120..c9b6f46ab04 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -912,6 +912,13 @@ static bool rna_UserDef_studiolight_is_user_defined_get(PointerRNA *ptr)
return (sl->flag & STUDIOLIGHT_USER_DEFINED) != 0;
}
+/* StudioLight.is_user_defined */
+static bool rna_UserDef_studiolight_has_specular_highlight_pass_get(PointerRNA *ptr)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ return sl->flag & STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS;
+}
+
/* StudioLight.type */
static int rna_UserDef_studiolight_type_get(PointerRNA *ptr)
@@ -1497,6 +1504,12 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Shading", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+ prop = RNA_def_property(srna, "icon_folder", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "icon_folder");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "File Folders", "Color of folders in the file browser");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
prop = RNA_def_property(srna, "icon_border_intensity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "icon_border_intensity");
RNA_def_property_ui_text(
@@ -3384,6 +3397,16 @@ static void rna_def_userdef_theme_space_clip(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Path After", "Color of path after current frame");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+ prop = RNA_def_property(srna, "path_keyframe_before", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Path Before", "Color of path before current frame");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "path_keyframe_after", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Path After", "Color of path after current frame");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
prop = RNA_def_property(srna, "frame_current", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "cframe");
RNA_def_property_array(prop, 3);
@@ -3700,6 +3723,15 @@ static void rna_def_userdef_studiolight(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "User Defined", "");
+ prop = RNA_def_property(srna, "has_specular_highlight_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_UserDef_studiolight_has_specular_highlight_pass_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(
+ prop,
+ "Has Specular Highlight",
+ "Studio light image file has separate \"diffuse\" and \"specular\" passes");
+
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_studio_light_type_items);
RNA_def_property_enum_funcs(prop, "rna_UserDef_studiolight_type_get", NULL, NULL);
@@ -4022,6 +4054,43 @@ static void rna_def_userdef_view(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem render_display_types[] = {
+ {USER_RENDER_DISPLAY_NONE,
+ "NONE",
+ 0,
+ "Keep User Interface",
+ "Images are rendered without changing the user interface"},
+ {USER_RENDER_DISPLAY_SCREEN,
+ "SCREEN",
+ 0,
+ "Full Screen",
+ "Images are rendered in a maximized Image Editor"},
+ {USER_RENDER_DISPLAY_AREA,
+ "AREA",
+ 0,
+ "Image Editor",
+ "Images are rendered in an Image Editor"},
+ {USER_RENDER_DISPLAY_WINDOW,
+ "WINDOW",
+ 0,
+ "New Window",
+ "Images are rendered in a new window"},
+ {0, NULL, 0, NULL, NULL},
+ };
+ static const EnumPropertyItem temp_space_display_types[] = {
+ {USER_TEMP_SPACE_DISPLAY_FULLSCREEN,
+ "SCREEN", /* Could be FULLSCREEN, but keeping it consistent with render_display_types */
+ 0,
+ "Full Screen",
+ "Open the temporary editor in a maximized screen"},
+ {USER_TEMP_SPACE_DISPLAY_WINDOW,
+ "WINDOW",
+ 0,
+ "New Window",
+ "Open the temporary editor in a new window"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
PropertyRNA *prop;
StructRNA *srna;
@@ -4037,7 +4106,6 @@ static void rna_def_userdef_view(BlenderRNA *brna)
prop, "UI Scale", "Changes the size of the fonts and widgets in the interface");
RNA_def_property_range(prop, 0.25f, 4.0f);
RNA_def_property_ui_range(prop, 0.5f, 2.0f, 1, 2);
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
prop = RNA_def_property(srna, "ui_line_width", PROP_ENUM, PROP_NONE);
@@ -4096,7 +4164,8 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "show_addons_enabled_only", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_ADDONS_ENABLED_ONLY);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "space_data.flag", USER_SPACEDATA_ADDONS_SHOW_ONLY_ENABLED);
RNA_def_property_ui_text(prop,
"Enabled Add-ons Only",
"Only show enabled add-ons. Un-check to see all installed add-ons");
@@ -4150,7 +4219,7 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_MENUOPENAUTO);
RNA_def_property_ui_text(
prop,
- "Open On Mouse Over",
+ "Open on Mouse Over",
"Open menu buttons and pulldowns automatically when the mouse is hovering");
prop = RNA_def_property(srna, "open_toplevel_delay", PROP_INT, PROP_NONE);
@@ -4246,6 +4315,17 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Header Position", "Default header position for new space-types");
RNA_def_property_update(prop, 0, "rna_userdef_screen_update_header_default");
+ prop = RNA_def_property(srna, "render_display_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, render_display_types);
+ RNA_def_property_ui_text(
+ prop, "Render Display Type", "Default location where rendered images will be displayed in");
+
+ prop = RNA_def_property(srna, "filebrowser_display_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, temp_space_display_types);
+ RNA_def_property_ui_text(prop,
+ "File Browser Display Type",
+ "Default location where the File Editor will be displayed in");
+
static const EnumPropertyItem text_hinting_items[] = {
{0, "AUTO", 0, "Auto", ""},
{USER_TEXT_HINTING_NONE, "NONE", 0, "None", ""},
@@ -4302,7 +4382,6 @@ static void rna_def_userdef_view(BlenderRNA *brna)
prop = RNA_def_property(srna, "gizmo_size", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "gizmo_size");
RNA_def_property_range(prop, 10, 200);
- RNA_def_property_int_default(prop, 75);
RNA_def_property_ui_text(prop, "Gizmo Size", "Diameter of the gizmo");
RNA_def_property_update(prop, 0, "rna_userdef_update");
@@ -4310,7 +4389,6 @@ static void rna_def_userdef_view(BlenderRNA *brna)
prop = RNA_def_property(srna, "lookdev_sphere_size", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "lookdev_sphere_size");
RNA_def_property_range(prop, 50, 400);
- RNA_def_property_int_default(prop, 150);
RNA_def_property_ui_text(
prop, "Look Dev Spheres Size", "Maximum diameter of the look development sphere size");
RNA_def_property_update(prop, 0, "rna_userdef_update");
@@ -4340,7 +4418,7 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_enum_items(prop, zoom_frame_modes);
RNA_def_property_enum_sdna(prop, NULL, "view_frame_type");
RNA_def_property_ui_text(
- prop, "Zoom To Frame Type", "How zooming to frame focuses around current frame");
+ prop, "Zoom to Frame Type", "How zooming to frame focuses around current frame");
prop = RNA_def_property(srna, "view_frame_keyframes", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 1, 500);
@@ -5184,7 +5262,7 @@ static void rna_def_userdef_input(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_zoom_to_mouse", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_ZOOM_TO_MOUSEPOS);
RNA_def_property_ui_text(prop,
- "Zoom To Mouse Position",
+ "Zoom to Mouse Position",
"Zoom in towards the mouse pointer's position in the 3D view, "
"rather than the 2D window center");
@@ -5240,7 +5318,6 @@ static void rna_def_userdef_input(BlenderRNA *brna)
prop = RNA_def_property(srna, "view_rotate_sensitivity_turntable", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_range(prop, DEG2RADF(0.001f), DEG2RADF(15.0f));
- RNA_def_property_float_default(prop, DEG2RADF(0.4f));
RNA_def_property_ui_range(prop, DEG2RADF(0.001f), DEG2RADF(15.0f), 1.0f, 2);
RNA_def_property_ui_text(prop,
"Orbit Sensitivity",
@@ -5248,7 +5325,6 @@ static void rna_def_userdef_input(BlenderRNA *brna)
prop = RNA_def_property(srna, "view_rotate_sensitivity_trackball", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.1f, 10.0f);
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_range(prop, 0.1f, 2.0f, 0.01f, 2);
RNA_def_property_ui_text(prop, "Orbit Sensitivity", "Scale trackball orbit sensitivity");
@@ -5288,7 +5364,6 @@ static void rna_def_userdef_input(BlenderRNA *brna)
/* tablet pressure curve */
prop = RNA_def_property(srna, "pressure_threshold_max", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01f, 3);
RNA_def_property_ui_text(
prop, "Max Threshold", "Raw input pressure value that is interpreted as 100% by Blender");
@@ -5447,7 +5522,7 @@ static void rna_def_userdef_keymap(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_ui_keyconfig", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(
- prop, NULL, "userpref_flag", USER_SECTION_INPUT_HIDE_UI_KEYCONFIG);
+ prop, NULL, "space_data.flag", USER_SPACEDATA_INPUT_HIDE_UI_KEYCONFIG);
RNA_def_property_ui_text(prop, "Show UI Key-Config", "");
prop = RNA_def_property(srna, "active_keyconfig", PROP_STRING, PROP_DIRPATH);
@@ -5498,11 +5573,6 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Hide System Bookmarks", "Hide system bookmarks in the file selector");
- prop = RNA_def_property(srna, "show_thumbnails", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_SHOW_THUMBNAILS);
- RNA_def_property_ui_text(
- prop, "Show Thumbnails", "Open in thumbnail view for images and movies");
-
prop = RNA_def_property(srna, "use_relative_paths", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_RELPATHS);
RNA_def_property_ui_text(
@@ -5728,7 +5798,7 @@ void RNA_def_userdef(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Preferences", "Global preferences");
prop = RNA_def_property(srna, "active_section", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "userpref");
+ RNA_def_property_enum_sdna(prop, NULL, "space_data.section_active");
RNA_def_property_enum_items(prop, preference_section_items);
RNA_def_property_ui_text(
prop, "Active Section", "Active section of the preferences shown in the user interface");
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index c3ffeaf6f6f..5f60ecf449b 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -1420,6 +1420,39 @@ static void rna_operator_cancel_cb(bContext *C, wmOperator *op)
RNA_parameter_list_free(&list);
}
+static char *rna_operator_description_cb(bContext *C, wmOperatorType *ot, PointerRNA *prop_ptr)
+{
+ extern FunctionRNA rna_Operator_description_func;
+
+ PointerRNA ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ void *ret;
+ char *result;
+
+ RNA_pointer_create(NULL, ot->ext.srna, NULL, &ptr); /* dummy */
+ func = &rna_Operator_description_func; /* RNA_struct_find_function(&ptr, "description"); */
+
+ RNA_parameter_list_create(&list, &ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ RNA_parameter_set_lookup(&list, "properties", prop_ptr);
+ ot->ext.call(C, &ptr, func, &list);
+
+ RNA_parameter_get_lookup(&list, "result", &ret);
+ result = (char *)ret;
+
+ if (result && result[0]) {
+ result = BLI_strdup(result);
+ }
+ else {
+ result = NULL;
+ }
+
+ RNA_parameter_list_free(&list);
+
+ return result;
+}
+
static void rna_Operator_unregister(struct Main *bmain, StructRNA *type);
/* bpy_operator_wrap.c */
@@ -1437,7 +1470,7 @@ static StructRNA *rna_Operator_register(Main *bmain,
wmOperatorType dummyot = {NULL};
wmOperator dummyop = {NULL};
PointerRNA dummyotr;
- int have_function[7];
+ int have_function[8];
struct {
char idname[OP_MAX_TYPENAME];
@@ -1531,6 +1564,7 @@ static StructRNA *rna_Operator_register(Main *bmain,
dummyot.modal = (have_function[4]) ? rna_operator_modal_cb : NULL;
dummyot.ui = (have_function[5]) ? rna_operator_draw_cb : NULL;
dummyot.cancel = (have_function[6]) ? rna_operator_cancel_cb : NULL;
+ dummyot.get_description = (have_function[7]) ? rna_operator_description_cb : NULL;
WM_operatortype_append_ptr(BPY_RNA_operator_wrapper, (void *)&dummyot);
/* update while blender is running */
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index d9306ba7a65..886258ee45f 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -41,24 +41,27 @@
#include "rna_internal.h" /* own include */
-/* confusingm 2 enums mixed up here */
+/* confusing 2 enums mixed up here */
const EnumPropertyItem rna_enum_window_cursor_items[] = {
- {CURSOR_STD, "DEFAULT", 0, "Default", ""},
- {CURSOR_NONE, "NONE", 0, "None", ""},
- {CURSOR_WAIT, "WAIT", 0, "Wait", ""},
- {CURSOR_EDIT, "CROSSHAIR", 0, "Crosshair", ""},
- {CURSOR_X_MOVE, "MOVE_X", 0, "Move-X", ""},
- {CURSOR_Y_MOVE, "MOVE_Y", 0, "Move-Y", ""},
+ {WM_CURSOR_DEFAULT, "DEFAULT", 0, "Default", ""},
+ {WM_CURSOR_NONE, "NONE", 0, "None", ""},
+ {WM_CURSOR_WAIT, "WAIT", 0, "Wait", ""},
+ {WM_CURSOR_EDIT, "CROSSHAIR", 0, "Crosshair", ""},
+ {WM_CURSOR_X_MOVE, "MOVE_X", 0, "Move-X", ""},
+ {WM_CURSOR_Y_MOVE, "MOVE_Y", 0, "Move-Y", ""},
/* new */
- {BC_KNIFECURSOR, "KNIFE", 0, "Knife", ""},
- {BC_TEXTEDITCURSOR, "TEXT", 0, "Text", ""},
- {BC_PAINTBRUSHCURSOR, "PAINT_BRUSH", 0, "Paint Brush", ""},
- {BC_HANDCURSOR, "HAND", 0, "Hand", ""},
- {BC_EW_SCROLLCURSOR, "SCROLL_X", 0, "Scroll-X", ""},
- {BC_NS_SCROLLCURSOR, "SCROLL_Y", 0, "Scroll-Y", ""},
- {BC_NSEW_SCROLLCURSOR, "SCROLL_XY", 0, "Scroll-XY", ""},
- {BC_EYEDROPPER_CURSOR, "EYEDROPPER", 0, "Eyedropper", ""},
+ {WM_CURSOR_KNIFE, "KNIFE", 0, "Knife", ""},
+ {WM_CURSOR_TEXT_EDIT, "TEXT", 0, "Text", ""},
+ {WM_CURSOR_PAINT_BRUSH, "PAINT_BRUSH", 0, "Paint Brush", ""},
+ {WM_CURSOR_PAINT, "PAINT_CROSS", 0, "Paint Cross", ""},
+ {WM_CURSOR_DOT, "DOT", 0, "Dot Cursor", ""},
+ {WM_CURSOR_ERASER, "ERASER", 0, "Eraser", ""},
+ {WM_CURSOR_HAND, "HAND", 0, "Hand", ""},
+ {WM_CURSOR_EW_SCROLL, "SCROLL_X", 0, "Scroll-X", ""},
+ {WM_CURSOR_NS_SCROLL, "SCROLL_Y", 0, "Scroll-Y", ""},
+ {WM_CURSOR_NSEW_SCROLL, "SCROLL_XY", 0, "Scroll-XY", ""},
+ {WM_CURSOR_EYEDROPPER, "EYEDROPPER", 0, "Eyedropper", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -957,6 +960,19 @@ void RNA_api_operator(StructRNA *srna)
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "context", "Context", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ /* description */
+ func = RNA_def_function(srna, "description", NULL);
+ RNA_def_function_ui_description(func, "Compute a description string that depends on parameters");
+ RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL);
+ parm = RNA_def_string(func, "result", NULL, 4096, "result", "");
+ RNA_def_parameter_clear_flags(parm, PROP_NEVER_NULL, 0);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "properties", "OperatorProperties", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
}
void RNA_api_macro(StructRNA *srna)
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 5116fefde94..1ae1f891e6f 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -141,6 +141,10 @@ if(WITH_MOD_OCEANSIM)
add_definitions(-DWITH_OCEANSIM)
endif()
+if(WITH_OPENSUBDIV)
+ add_definitions(-DWITH_OPENSUBDIV)
+endif()
+
if(WITH_BULLET)
list(APPEND LIB
extern_bullet
diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c
index 522b387411b..9f3802a4fa1 100644
--- a/source/blender/modifiers/intern/MOD_armature.c
+++ b/source/blender/modifiers/intern/MOD_armature.c
@@ -82,7 +82,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the armature is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
return !amd->object || amd->object->type != OB_ARMATURE;
}
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 48718a47419..644ac3a10e8 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -268,9 +268,9 @@ static void dm_mvert_map_doubles(int *doubles_map,
static void mesh_merge_transform(Mesh *result,
Mesh *cap_mesh,
- float cap_offset[4][4],
- unsigned int cap_verts_index,
- unsigned int cap_edges_index,
+ const float cap_offset[4][4],
+ uint cap_verts_index,
+ uint cap_edges_index,
int cap_loops_index,
int cap_polys_index,
int cap_nverts,
@@ -775,7 +775,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the curve/mesh is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
if (amd->curve_ob && amd->curve_ob->type != OB_CURVE) {
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index a05b7023392..0c00bb572be 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -212,7 +212,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
spread,
mesh->smoothresh);
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
/* Make sure we never alloc'd these. */
BLI_assert(bm->vtoolflagpool == NULL && bm->etoolflagpool == NULL && bm->ftoolflagpool == NULL);
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index ea42ddb03f4..9868395c0e8 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -74,7 +74,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the mesh is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
return !bmd->object || bmd->object->type != OB_MESH;
}
@@ -316,7 +316,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
MEM_freeN(looptris);
}
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c
index 3d43c6de88e..56e84423db4 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -118,7 +118,7 @@ static void deformVerts(ModifierData *md,
if (mesh_src) {
float current_time = 0;
- unsigned int mvert_num = 0;
+ uint mvert_num = 0;
BKE_mesh_vert_coords_apply(mesh_src, vertexCos);
BKE_mesh_calc_normals(mesh_src);
diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c
index a234f468e45..ff241550bdc 100644
--- a/source/blender/modifiers/intern/MOD_correctivesmooth.c
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -70,7 +70,7 @@ static void initData(ModifierData *md)
csmd->defgrp_name[0] = '\0';
- csmd->delta_cache = NULL;
+ csmd->delta_cache.deltas = NULL;
}
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
@@ -84,14 +84,14 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
tcsmd->bind_coords = MEM_dupallocN(csmd->bind_coords);
}
- tcsmd->delta_cache = NULL;
- tcsmd->delta_cache_num = 0;
+ tcsmd->delta_cache.deltas = NULL;
+ tcsmd->delta_cache.totverts = 0;
}
static void freeBind(CorrectiveSmoothModifierData *csmd)
{
MEM_SAFE_FREE(csmd->bind_coords);
- MEM_SAFE_FREE(csmd->delta_cache);
+ MEM_SAFE_FREE(csmd->delta_cache.deltas);
csmd->bind_coords_num = 0;
}
@@ -117,11 +117,11 @@ static void requiredDataMask(Object *UNUSED(ob),
/* check individual weights for changes and cache values */
static void mesh_get_weights(MDeformVert *dvert,
const int defgrp_index,
- const unsigned int numVerts,
+ const uint numVerts,
const bool use_invert_vgroup,
float *smooth_weights)
{
- unsigned int i;
+ uint i;
for (i = 0; i < numVerts; i++, dvert++) {
const float w = defvert_find_weight(dvert, defgrp_index);
@@ -140,11 +140,11 @@ static void mesh_get_boundaries(Mesh *mesh, float *smooth_weights)
const MPoly *mpoly = mesh->mpoly;
const MLoop *mloop = mesh->mloop;
const MEdge *medge = mesh->medge;
- unsigned int mpoly_num, medge_num, i;
- unsigned short *boundaries;
+ uint mpoly_num, medge_num, i;
+ ushort *boundaries;
- mpoly_num = (unsigned int)mesh->totpoly;
- medge_num = (unsigned int)mesh->totedge;
+ mpoly_num = (uint)mesh->totpoly;
+ medge_num = (uint)mesh->totedge;
boundaries = MEM_calloc_arrayN(medge_num, sizeof(*boundaries), __func__);
@@ -176,14 +176,14 @@ static void mesh_get_boundaries(Mesh *mesh, float *smooth_weights)
static void smooth_iter__simple(CorrectiveSmoothModifierData *csmd,
Mesh *mesh,
float (*vertexCos)[3],
- unsigned int numVerts,
+ uint numVerts,
const float *smooth_weights,
- unsigned int iterations)
+ uint iterations)
{
const float lambda = csmd->lambda;
- unsigned int i;
+ uint i;
- const unsigned int numEdges = (unsigned int)mesh->totedge;
+ const uint numEdges = (uint)mesh->totedge;
const MEdge *edges = mesh->medge;
float *vertex_edge_count_div;
@@ -252,18 +252,18 @@ static void smooth_iter__simple(CorrectiveSmoothModifierData *csmd,
static void smooth_iter__length_weight(CorrectiveSmoothModifierData *csmd,
Mesh *mesh,
float (*vertexCos)[3],
- unsigned int numVerts,
+ uint numVerts,
const float *smooth_weights,
- unsigned int iterations)
+ uint iterations)
{
const float eps = FLT_EPSILON * 10.0f;
- const unsigned int numEdges = (unsigned int)mesh->totedge;
+ const uint numEdges = (uint)mesh->totedge;
/* note: the way this smoothing method works, its approx half as strong as the simple-smooth,
* and 2.0 rarely spikes, double the value for consistent behavior. */
const float lambda = csmd->lambda * 2.0f;
const MEdge *edges = mesh->medge;
float *vertex_edge_count;
- unsigned int i;
+ uint i;
struct SmoothingData_Weighted {
float delta[3];
@@ -346,9 +346,9 @@ static void smooth_iter__length_weight(CorrectiveSmoothModifierData *csmd,
static void smooth_iter(CorrectiveSmoothModifierData *csmd,
Mesh *mesh,
float (*vertexCos)[3],
- unsigned int numVerts,
+ uint numVerts,
const float *smooth_weights,
- unsigned int iterations)
+ uint iterations)
{
switch (csmd->smooth_type) {
case MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT:
@@ -367,7 +367,7 @@ static void smooth_verts(CorrectiveSmoothModifierData *csmd,
MDeformVert *dvert,
const int defgrp_index,
float (*vertexCos)[3],
- unsigned int numVerts)
+ uint numVerts)
{
float *smooth_weights = NULL;
@@ -391,7 +391,7 @@ static void smooth_verts(CorrectiveSmoothModifierData *csmd,
}
}
- smooth_iter(csmd, mesh, vertexCos, numVerts, smooth_weights, (unsigned int)csmd->repeat);
+ smooth_iter(csmd, mesh, vertexCos, numVerts, smooth_weights, (uint)csmd->repeat);
if (smooth_weights) {
MEM_freeN(smooth_weights);
@@ -454,13 +454,13 @@ static void calc_tangent_loop_accum(const float v_dir_prev[3],
static void calc_tangent_spaces(Mesh *mesh, float (*vertexCos)[3], float (*r_tangent_spaces)[3][3])
{
- const unsigned int mpoly_num = (unsigned int)mesh->totpoly;
+ const uint mpoly_num = (uint)mesh->totpoly;
#ifndef USE_TANGENT_CALC_INLINE
- const unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
+ const uint mvert_num = (uint)dm->getNumVerts(dm);
#endif
const MPoly *mpoly = mesh->mpoly;
const MLoop *mloop = mesh->mloop;
- unsigned int i;
+ uint i;
for (i = 0; i < mpoly_num; i++) {
const MPoly *mp = &mpoly[i];
@@ -502,6 +502,23 @@ static void calc_tangent_spaces(Mesh *mesh, float (*vertexCos)[3], float (*r_tan
#endif
}
+static void store_cache_settings(CorrectiveSmoothModifierData *csmd)
+{
+ csmd->delta_cache.lambda = csmd->lambda;
+ csmd->delta_cache.repeat = csmd->repeat;
+ csmd->delta_cache.flag = csmd->flag;
+ csmd->delta_cache.smooth_type = csmd->smooth_type;
+ csmd->delta_cache.rest_source = csmd->rest_source;
+}
+
+static bool cache_settings_equal(CorrectiveSmoothModifierData *csmd)
+{
+ return (csmd->delta_cache.lambda == csmd->lambda && csmd->delta_cache.repeat == csmd->repeat &&
+ csmd->delta_cache.flag == csmd->flag &&
+ csmd->delta_cache.smooth_type == csmd->smooth_type &&
+ csmd->delta_cache.rest_source == csmd->rest_source);
+}
+
/**
* This calculates #CorrectiveSmoothModifierData.delta_cache
* It's not run on every update (during animation for example).
@@ -511,22 +528,22 @@ static void calc_deltas(CorrectiveSmoothModifierData *csmd,
MDeformVert *dvert,
const int defgrp_index,
const float (*rest_coords)[3],
- unsigned int numVerts)
+ uint numVerts)
{
float(*smooth_vertex_coords)[3] = MEM_dupallocN(rest_coords);
float(*tangent_spaces)[3][3];
- unsigned int i;
+ uint i;
tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__);
- if (csmd->delta_cache_num != numVerts) {
- MEM_SAFE_FREE(csmd->delta_cache);
+ if (csmd->delta_cache.totverts != numVerts) {
+ MEM_SAFE_FREE(csmd->delta_cache.deltas);
}
/* allocate deltas if they have not yet been allocated, otherwise we will just write over them */
- if (!csmd->delta_cache) {
- csmd->delta_cache_num = numVerts;
- csmd->delta_cache = MEM_malloc_arrayN(numVerts, sizeof(float[3]), __func__);
+ if (!csmd->delta_cache.deltas) {
+ csmd->delta_cache.totverts = numVerts;
+ csmd->delta_cache.deltas = MEM_malloc_arrayN(numVerts, sizeof(float[3]), __func__);
}
smooth_verts(csmd, mesh, dvert, defgrp_index, smooth_vertex_coords, numVerts);
@@ -544,7 +561,7 @@ static void calc_deltas(CorrectiveSmoothModifierData *csmd,
if (UNLIKELY(!invert_m3_m3(imat, tangent_spaces[i]))) {
transpose_m3_m3(imat, tangent_spaces[i]);
}
- mul_v3_m3v3(csmd->delta_cache[i], imat, delta);
+ mul_v3_m3v3(csmd->delta_cache.deltas[i], imat, delta);
}
MEM_freeN(tangent_spaces);
@@ -556,13 +573,14 @@ static void correctivesmooth_modifier_do(ModifierData *md,
Object *ob,
Mesh *mesh,
float (*vertexCos)[3],
- unsigned int numVerts,
+ uint numVerts,
struct BMEditMesh *em)
{
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
const bool force_delta_cache_update =
/* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */
+ !cache_settings_equal(csmd) ||
((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) &&
(((ID *)ob->data)->recalc & ID_RECALC_ALL));
@@ -575,7 +593,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
/* if rest bind_coords not are defined, set them (only run during bind) */
if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) &&
/* signal to recalculate, whoever sets MUST also free bind coords */
- (csmd->bind_coords_num == (unsigned int)-1)) {
+ (csmd->bind_coords_num == (uint)-1)) {
if (DEG_is_active(depsgraph)) {
BLI_assert(csmd->bind_coords == NULL);
csmd->bind_coords = MEM_dupallocN(vertexCos);
@@ -617,8 +635,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
goto error;
}
else {
- unsigned int me_numVerts = (unsigned int)((em) ? em->bm->totvert :
- ((Mesh *)ob->data)->totvert);
+ uint me_numVerts = (uint)((em) ? em->bm->totvert : ((Mesh *)ob->data)->totvert);
if (me_numVerts != numVerts) {
modifier_setError(md, "Original vertex count mismatch: %u to %u", me_numVerts, numVerts);
@@ -628,10 +645,13 @@ static void correctivesmooth_modifier_do(ModifierData *md,
}
/* check to see if our deltas are still valid */
- if (!csmd->delta_cache || (csmd->delta_cache_num != numVerts) || force_delta_cache_update) {
+ if (!csmd->delta_cache.deltas || (csmd->delta_cache.totverts != numVerts) ||
+ force_delta_cache_update) {
const float(*rest_coords)[3];
bool is_rest_coords_alloc = false;
+ store_cache_settings(csmd);
+
if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
/* caller needs to do sanity check here */
csmd->bind_coords_num = numVerts;
@@ -642,7 +662,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
rest_coords = em ? BKE_editmesh_vert_coords_alloc_orco(em, &me_numVerts) :
BKE_mesh_vert_coords_alloc(ob->data, &me_numVerts);
- BLI_assert((unsigned int)me_numVerts == numVerts);
+ BLI_assert((uint)me_numVerts == numVerts);
is_rest_coords_alloc = true;
}
@@ -662,7 +682,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
/* this could be a check, but at this point it _must_ be valid */
- BLI_assert(csmd->bind_coords_num == numVerts && csmd->delta_cache);
+ BLI_assert(csmd->bind_coords_num == numVerts && csmd->delta_cache.deltas);
}
#ifdef DEBUG_TIME
@@ -673,7 +693,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, numVerts);
{
- unsigned int i;
+ uint i;
float(*tangent_spaces)[3][3];
@@ -689,7 +709,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
calc_tangent_ortho(tangent_spaces[i]);
#endif
- mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache[i]);
+ mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache.deltas[i]);
add_v3_v3(vertexCos[i], delta);
}
@@ -704,8 +724,8 @@ static void correctivesmooth_modifier_do(ModifierData *md,
/* when the modifier fails to execute */
error:
- MEM_SAFE_FREE(csmd->delta_cache);
- csmd->delta_cache_num = 0;
+ MEM_SAFE_FREE(csmd->delta_cache.deltas);
+ csmd->delta_cache.totverts = 0;
}
static void deformVerts(ModifierData *md,
@@ -717,7 +737,7 @@ static void deformVerts(ModifierData *md,
Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
correctivesmooth_modifier_do(
- md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (unsigned int)numVerts, NULL);
+ md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (uint)numVerts, NULL);
if (mesh_src != mesh) {
BKE_id_free(NULL, mesh_src);
@@ -735,7 +755,7 @@ static void deformVertsEM(ModifierData *md,
ctx->object, editData, mesh, NULL, numVerts, false, false);
correctivesmooth_modifier_do(
- md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (unsigned int)numVerts, editData);
+ md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (uint)numVerts, editData);
if (mesh_src != mesh) {
BKE_id_free(NULL, mesh_src);
diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index bedd6e519eb..f9137572d6f 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -69,7 +69,7 @@ static bool isDisabled(const Scene *UNUSED(scene), ModifierData *md, bool UNUSED
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the curve is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
return !cmd->object || cmd->object->type != OB_CURVE;
}
diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c
index fa60bd2a502..bb032f9725c 100644
--- a/source/blender/modifiers/intern/MOD_datatransfer.c
+++ b/source/blender/modifiers/intern/MOD_datatransfer.c
@@ -146,7 +146,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the mesh is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
return !dtmd->ob_source || dtmd->ob_source->type != OB_MESH;
}
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index cff700e8d45..c113a2767a0 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -140,8 +140,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
MOD_get_vgroup(ctx->object, mesh, dmd->defgrp_name, &dvert, &defgrp_index);
if (dvert) {
- const unsigned int vert_tot = mesh->totvert;
- unsigned int i;
+ const uint vert_tot = mesh->totvert;
+ uint i;
vweights = MEM_malloc_arrayN(vert_tot, sizeof(float), __func__);
@@ -199,7 +199,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
updateFaceCount(ctx, dmd, bm->totface);
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
/* make sure we never alloc'd these */
BLI_assert(bm->vtoolflagpool == NULL && bm->etoolflagpool == NULL && bm->ftoolflagpool == NULL);
BLI_assert(bm->vtable == NULL && bm->etable == NULL && bm->ftable == NULL);
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index ac0d72214c8..9cb694be88b 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -294,6 +294,11 @@ static void displaceModifier_do(DisplaceModifierData *dmd,
mvert = mesh->mvert;
MOD_get_vgroup(ob, mesh, dmd->defgrp_name, &dvert, &defgrp_index);
+ if (defgrp_index >= 0 && dvert == NULL) {
+ /* There is a vertex group, but it has no vertices. */
+ return;
+ }
+
Tex *tex_target = dmd->texture;
if (tex_target != NULL) {
tex_co = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tex_co), "displaceModifier_do tex_co");
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index 59d560b9a4a..69ba4aa2795 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -97,7 +97,7 @@ static Mesh *doEdgeSplit(Mesh *mesh, EdgeSplitModifierData *emd)
/* BM_mesh_validate(bm); */ /* for troubleshooting */
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index 4ed787810a8..5f0bbc8ecf1 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -201,7 +201,7 @@ static void createFacepa(ExplodeModifierData *emd, ParticleSystemModifierData *p
BLI_rng_free(rng);
}
-static int edgecut_get(EdgeHash *edgehash, unsigned int v1, unsigned int v2)
+static int edgecut_get(EdgeHash *edgehash, uint v1, uint v2)
{
return POINTER_AS_INT(BLI_edgehash_lookup(edgehash, v1, v2));
}
@@ -649,7 +649,7 @@ static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh)
int i, v1, v2, v3, v4, esplit, v[4] = {0, 0, 0, 0}, /* To quite gcc barking... */
uv[4] = {0, 0, 0, 0}; /* To quite gcc barking... */
int numlayer;
- unsigned int ed_v1, ed_v2;
+ uint ed_v1, ed_v2;
edgehash = BLI_edgehash_new(__func__);
@@ -906,7 +906,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
const int *facepa = emd->facepa;
int totdup = 0, totvert = 0, totface = 0, totpart = 0, delface = 0;
int i, v, u;
- unsigned int ed_v1, ed_v2, mindex = 0;
+ uint ed_v1, ed_v2, mindex = 0;
MTFace *mtface = NULL, *mtf;
totface = mesh->totface;
@@ -938,10 +938,13 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
continue;
}
}
+ else {
+ pa = NULL;
+ }
/* do mindex + totvert to ensure the vertex index to be the first
* with BLI_edgehashIterator_getKey */
- if (facepa[i] == totpart || cfra < (pars + facepa[i])->time) {
+ if (pa == NULL || cfra < pa->time) {
mindex = totvert + totpart;
}
else {
@@ -1022,6 +1025,9 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
mul_m4_v3(imat, vertco);
}
+ else {
+ pa = NULL;
+ }
}
BLI_edgehashIterator_free(ehi);
@@ -1043,13 +1049,17 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
continue;
}
}
+ else {
+ pa = NULL;
+ }
source = mesh->mface[i];
mf = &explode->mface[u];
orig_v4 = source.v4;
- if (facepa[i] != totpart && cfra < pa->time) {
+ /* Same as above in the first loop over mesh's faces. */
+ if (pa == NULL || cfra < pa->time) {
mindex = totvert + totpart;
}
else {
@@ -1069,7 +1079,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
/* override uv channel for particle age */
if (mtface) {
- float age = (cfra - pa->time) / pa->lifetime;
+ float age = (pa != NULL) ? (cfra - pa->time) / pa->lifetime : 0.0f;
/* Clamp to this range to avoid flipping to the other side of the coordinates. */
CLAMP(age, 0.001f, 0.999f);
diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.c b/source/blender/modifiers/intern/MOD_fluidsim_util.c
index 587aa108fd1..748bf4db4e2 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim_util.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim_util.c
@@ -513,6 +513,12 @@ static Mesh *fluidsim_read_cache(
return NULL;
}
+ BKE_mesh_copy_settings(newmesh, orgmesh);
+
+ /* Fluid simulation has a texture space that based on the bounds of the fluid mesh.
+ * This does not seem particularly useful, but it's backwards compatible. */
+ BKE_mesh_texspace_calc(newmesh);
+
/* load vertex velocities, if they exist...
* TODO? use generate flag as loading flag as well?
* warning, needs original .bobj.gz mesh loading filename */
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index 2f902db9340..1a62010abe7 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -136,8 +136,8 @@ struct HookData_cb {
float falloff_sq;
float fac_orig;
- unsigned int use_falloff : 1;
- unsigned int use_uniform : 1;
+ uint use_falloff : 1;
+ uint use_uniform : 1;
float cent[3];
diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c
index c9e0171c9f2..0fc2e0971da 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -66,7 +66,7 @@ typedef struct LaplacianSystem {
float (*co)[3]; /* Original vertex coordinates */
float (*no)[3]; /* Original vertex normal */
float (*delta)[3]; /* Differential Coordinates */
- unsigned int (*tris)[3]; /* Copy of MLoopTri (tessellation triangle) v1-v3 */
+ uint (*tris)[3]; /* Copy of MLoopTri (tessellation triangle) v1-v3 */
int *index_anchors; /* Static vertex index list */
int *unit_verts; /* Unit vectors of projected edges onto the plane orthogonal to n */
int *ringf_indices; /* Indices of faces per vertex */
@@ -153,7 +153,7 @@ static void createFaceRingMap(const int mvert_tot,
for (i = 0, mlt = mlooptri; i < mtri_tot; i++, mlt++) {
for (j = 0; j < 3; j++) {
- const unsigned int v_index = mloop[mlt->tri[j]].v;
+ const uint v_index = mloop[mlt->tri[j]].v;
map[v_index].count++;
totalr++;
}
@@ -167,7 +167,7 @@ static void createFaceRingMap(const int mvert_tot,
}
for (i = 0, mlt = mlooptri; i < mtri_tot; i++, mlt++) {
for (j = 0; j < 3; j++) {
- const unsigned int v_index = mloop[mlt->tri[j]].v;
+ const uint v_index = mloop[mlt->tri[j]].v;
map[v_index].indices[map[v_index].count] = i;
map[v_index].count++;
}
@@ -253,7 +253,7 @@ static void initLaplacianMatrix(LaplacianSystem *sys)
int idv[3];
for (ti = 0; ti < sys->total_tris; ti++) {
- const unsigned int *vidt = sys->tris[ti];
+ const uint *vidt = sys->tris[ti];
const float *co[3];
co[0] = sys->co[vidt[0]];
@@ -352,7 +352,7 @@ static void rotateDifferentialCoordinates(LaplacianSystem *sys)
zero_v3(ni);
num_fni = sys->ringf_map[i].count;
for (fi = 0; fi < num_fni; fi++) {
- const unsigned int *vin;
+ const uint *vin;
fidn = sys->ringf_map[i].indices;
vin = sys->tris[fidn[fi]];
for (j = 0; j < 3; j++) {
diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
index 4a86c26cdeb..86d4124e5db 100644
--- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c
+++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
@@ -199,7 +199,7 @@ static void init_laplacian_matrix(LaplacianSystem *sys)
float w1, w2, w3;
float areaf;
int i;
- unsigned int idv1, idv2;
+ uint idv1, idv2;
for (i = 0; i < sys->numEdges; i++) {
idv1 = sys->medges[i].v1;
@@ -233,7 +233,7 @@ static void init_laplacian_matrix(LaplacianSystem *sys)
const float *v_prev = sys->vertexCos[l_prev->v];
const float *v_curr = sys->vertexCos[l_curr->v];
const float *v_next = sys->vertexCos[l_next->v];
- const unsigned int l_curr_index = l_curr - sys->mloop;
+ const uint l_curr_index = l_curr - sys->mloop;
sys->numNeFa[l_curr->v] += 1;
@@ -274,7 +274,7 @@ static void init_laplacian_matrix(LaplacianSystem *sys)
static void fill_laplacian_matrix(LaplacianSystem *sys)
{
int i;
- unsigned int idv1, idv2;
+ uint idv1, idv2;
for (i = 0; i < sys->numPolys; i++) {
const MPoly *mp = &sys->mpoly[i];
@@ -284,7 +284,7 @@ static void fill_laplacian_matrix(LaplacianSystem *sys)
const MLoop *l_curr = l_term - 1;
for (; l_next != l_term; l_prev = l_curr, l_curr = l_next, l_next++) {
- const unsigned int l_curr_index = l_curr - sys->mloop;
+ const uint l_curr_index = l_curr - sys->mloop;
/* Is ring if number of faces == number of edges around vertice*/
if (sys->numNeEd[l_curr->v] == sys->numNeFa[l_curr->v] && sys->zerola[l_curr->v] == 0) {
diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c
index aca5b43a7d5..a73e96da975 100644
--- a/source/blender/modifiers/intern/MOD_lattice.c
+++ b/source/blender/modifiers/intern/MOD_lattice.c
@@ -67,7 +67,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the lattice is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
return !lmd->object || lmd->object->type != OB_LATTICE;
}
diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c
index bc218114432..cf7d227e898 100644
--- a/source/blender/modifiers/intern/MOD_mask.c
+++ b/source/blender/modifiers/intern/MOD_mask.c
@@ -160,7 +160,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
* (including selected matches only):
* key = oldindex, value = newindex
*/
- vertHash = BLI_ghash_int_new_ex("mask vert gh", (unsigned int)maxVerts);
+ vertHash = BLI_ghash_int_new_ex("mask vert gh", (uint)maxVerts);
/* add vertices which exist in vertexgroups into vertHash for filtering
* - dv = for each vertex, what vertexgroups does it belong to
@@ -204,7 +204,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
- vertHash = BLI_ghash_int_new_ex("mask vert2 bh", (unsigned int)maxVerts);
+ vertHash = BLI_ghash_int_new_ex("mask vert2 bh", (uint)maxVerts);
/* add vertices which exist in vertexgroup into ghash for filtering */
for (i = 0, dv = dvert; i < maxVerts; i++, dv++) {
@@ -220,8 +220,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
- edgeHash = BLI_ghash_int_new_ex("mask ed2 gh", (unsigned int)maxEdges);
- polyHash = BLI_ghash_int_new_ex("mask fa2 gh", (unsigned int)maxPolys);
+ edgeHash = BLI_ghash_int_new_ex("mask ed2 gh", (uint)maxEdges);
+ polyHash = BLI_ghash_int_new_ex("mask fa2 gh", (uint)maxPolys);
mvert_src = mesh->mvert;
medge_src = mesh->medge;
@@ -353,7 +353,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the armature is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
return mmd->ob_arm && mmd->ob_arm->type != OB_ARMATURE;
}
diff --git a/source/blender/modifiers/intern/MOD_meshcache_mdd.c b/source/blender/modifiers/intern/MOD_meshcache_mdd.c
index 16a118522c5..a3ab0120ff9 100644
--- a/source/blender/modifiers/intern/MOD_meshcache_mdd.c
+++ b/source/blender/modifiers/intern/MOD_meshcache_mdd.c
@@ -168,7 +168,7 @@ bool MOD_meshcache_read_mdd_index(FILE *fp,
if (factor >= 1.0f) {
#if 1
float *vco = *vertexCos;
- unsigned int i;
+ uint i;
for (i = mdd_head.verts_tot; i != 0; i--, vco += 3) {
fread(vco, sizeof(float) * 3, 1, fp);
@@ -192,7 +192,7 @@ bool MOD_meshcache_read_mdd_index(FILE *fp,
else {
const float ifactor = 1.0f - factor;
float *vco = *vertexCos;
- unsigned int i;
+ uint i;
for (i = mdd_head.verts_tot; i != 0; i--, vco += 3) {
float tvec[3];
fread(tvec, sizeof(float) * 3, 1, fp);
diff --git a/source/blender/modifiers/intern/MOD_meshcache_pc2.c b/source/blender/modifiers/intern/MOD_meshcache_pc2.c
index 97a8635ac9e..7b8ad0bd705 100644
--- a/source/blender/modifiers/intern/MOD_meshcache_pc2.c
+++ b/source/blender/modifiers/intern/MOD_meshcache_pc2.c
@@ -153,7 +153,7 @@ bool MOD_meshcache_read_pc2_index(FILE *fp,
if (factor >= 1.0f) {
float *vco = *vertexCos;
- unsigned int i;
+ uint i;
for (i = pc2_head.verts_tot; i != 0; i--, vco += 3) {
fread(vco, sizeof(float) * 3, 1, fp);
@@ -167,7 +167,7 @@ bool MOD_meshcache_read_pc2_index(FILE *fp,
else {
const float ifactor = 1.0f - factor;
float *vco = *vertexCos;
- unsigned int i;
+ uint i;
for (i = pc2_head.verts_tot; i != 0; i--, vco += 3) {
float tvec[3];
fread(tvec, sizeof(float) * 3, 1, fp);
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index 7ddce983c2a..408e38f43ab 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -142,7 +142,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the mesh is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
return !mmd->object || mmd->object->type != OB_MESH;
}
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index 11f001d7a85..47f8528ee94 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -30,6 +30,7 @@
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_mesh.h"
+#include "BKE_mirror.h"
#include "BKE_modifier.h"
#include "BKE_deform.h"
@@ -68,374 +69,6 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
}
}
-static Mesh *doBiscetOnMirrorPlane(
- MirrorModifierData *mmd, const Mesh *mesh, int axis, float plane_co[3], float plane_no[3])
-{
- bool do_bisect_flip_axis = ((axis == 0 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_X) ||
- (axis == 1 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Y) ||
- (axis == 2 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Z));
-
- const float bisect_distance = 0.001f;
-
- Mesh *result;
- BMesh *bm;
- BMIter viter;
- BMVert *v, *v_next;
-
- bm = BKE_mesh_to_bmesh_ex(mesh,
- &(struct BMeshCreateParams){0},
- &(struct BMeshFromMeshParams){
- .calc_face_normal = true,
- .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX,
- .emask = CD_MASK_ORIGINDEX,
- .pmask = CD_MASK_ORIGINDEX},
- });
-
- /* Define bisecting plane (aka mirror plane). */
- float plane[4];
- if (!do_bisect_flip_axis) {
- /* That reversed condition is a tad weird, but for some reason that's how you keep
- * the part of the mesh which is on the non-mirrored side when flip option is disabled,
- * think that that is the expected behavior. */
- negate_v3(plane_no);
- }
- plane_from_point_normal_v3(plane, plane_co, plane_no);
-
- BM_mesh_bisect_plane(bm, plane, false, false, 0, 0, bisect_distance);
-
- /* Plane definitions for vert killing. */
- float plane_offset[4];
- copy_v3_v3(plane_offset, plane);
- plane_offset[3] = plane[3] - bisect_distance;
-
- /* Delete verts across the mirror plane. */
- BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) {
- if (plane_point_side_v3(plane_offset, v->co) > 0.0f) {
- BM_vert_kill(bm, v);
- }
- }
-
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
- BM_mesh_free(bm);
-
- return result;
-}
-
-static Mesh *doMirrorOnAxis(MirrorModifierData *mmd,
- const ModifierEvalContext *UNUSED(ctx),
- Object *ob,
- const Mesh *mesh,
- int axis)
-{
- const float tolerance_sq = mmd->tolerance * mmd->tolerance;
- const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0;
- int tot_vtargetmap = 0; /* total merge vertices */
-
- const bool do_bisect = ((axis == 0 && mmd->flag & MOD_MIR_BISECT_AXIS_X) ||
- (axis == 1 && mmd->flag & MOD_MIR_BISECT_AXIS_Y) ||
- (axis == 2 && mmd->flag & MOD_MIR_BISECT_AXIS_Z));
-
- Mesh *result;
- MVert *mv, *mv_prev;
- MEdge *me;
- MLoop *ml;
- MPoly *mp;
- float mtx[4][4];
- float plane_co[3], plane_no[3];
- int i;
- int a, totshape;
- int *vtargetmap = NULL, *vtmap_a = NULL, *vtmap_b = NULL;
-
- /* mtx is the mirror transformation */
- unit_m4(mtx);
- mtx[axis][axis] = -1.0f;
-
- Object *mirror_ob = mmd->mirror_ob;
- if (mirror_ob != NULL) {
- float tmp[4][4];
- float itmp[4][4];
-
- /* tmp is a transform from coords relative to the object's own origin,
- * to coords relative to the mirror object origin */
- invert_m4_m4(tmp, mirror_ob->obmat);
- mul_m4_m4m4(tmp, tmp, ob->obmat);
-
- /* itmp is the reverse transform back to origin-relative coordinates */
- invert_m4_m4(itmp, tmp);
-
- /* combine matrices to get a single matrix that translates coordinates into
- * mirror-object-relative space, does the mirror, and translates back to
- * origin-relative space */
- mul_m4_series(mtx, itmp, mtx, tmp);
-
- if (do_bisect) {
- copy_v3_v3(plane_co, itmp[3]);
- copy_v3_v3(plane_no, itmp[axis]);
- }
- }
- else if (do_bisect) {
- copy_v3_v3(plane_co, mtx[3]);
- /* Need to negate here, since that axis is inverted (for mirror transform). */
- negate_v3_v3(plane_no, mtx[axis]);
- }
-
- Mesh *mesh_bisect = NULL;
- if (do_bisect) {
- mesh_bisect = doBiscetOnMirrorPlane(mmd, mesh, axis, plane_co, plane_no);
- mesh = mesh_bisect;
- }
-
- const int maxVerts = mesh->totvert;
- const int maxEdges = mesh->totedge;
- const int maxLoops = mesh->totloop;
- const int maxPolys = mesh->totpoly;
-
- result = BKE_mesh_new_nomain_from_template(
- mesh, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2);
-
- /*copy customdata to original geometry*/
- CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, maxVerts);
- CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, maxEdges);
- CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, maxLoops);
- CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, maxPolys);
-
- /* Subsurf for eg won't have mesh data in the custom data arrays.
- * now add mvert/medge/mpoly layers. */
- if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) {
- memcpy(result->mvert, mesh->mvert, sizeof(*result->mvert) * mesh->totvert);
- }
- if (!CustomData_has_layer(&mesh->edata, CD_MEDGE)) {
- memcpy(result->medge, mesh->medge, sizeof(*result->medge) * mesh->totedge);
- }
- if (!CustomData_has_layer(&mesh->pdata, CD_MPOLY)) {
- memcpy(result->mloop, mesh->mloop, sizeof(*result->mloop) * mesh->totloop);
- memcpy(result->mpoly, mesh->mpoly, sizeof(*result->mpoly) * mesh->totpoly);
- }
-
- /* copy customdata to new geometry,
- * copy from its self because this data may have been created in the checks above */
- CustomData_copy_data(&result->vdata, &result->vdata, 0, maxVerts, maxVerts);
- CustomData_copy_data(&result->edata, &result->edata, 0, maxEdges, maxEdges);
- /* loops are copied later */
- CustomData_copy_data(&result->pdata, &result->pdata, 0, maxPolys, maxPolys);
-
- if (do_vtargetmap) {
- /* second half is filled with -1 */
- vtargetmap = MEM_malloc_arrayN(maxVerts, 2 * sizeof(int), "MOD_mirror tarmap");
-
- vtmap_a = vtargetmap;
- vtmap_b = vtargetmap + maxVerts;
- }
-
- /* mirror vertex coordinates */
- mv_prev = result->mvert;
- mv = mv_prev + maxVerts;
- for (i = 0; i < maxVerts; i++, mv++, mv_prev++) {
- mul_m4_v3(mtx, mv->co);
-
- if (do_vtargetmap) {
- /* compare location of the original and mirrored vertex, to see if they
- * should be mapped for merging */
- if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
- *vtmap_a = maxVerts + i;
- tot_vtargetmap++;
-
- /* average location */
- mid_v3_v3v3(mv->co, mv_prev->co, mv->co);
- copy_v3_v3(mv_prev->co, mv->co);
- }
- else {
- *vtmap_a = -1;
- }
-
- *vtmap_b = -1; /* fill here to avoid 2x loops */
-
- vtmap_a++;
- vtmap_b++;
- }
- }
-
- /* handle shape keys */
- totshape = CustomData_number_of_layers(&result->vdata, CD_SHAPEKEY);
- for (a = 0; a < totshape; a++) {
- float(*cos)[3] = CustomData_get_layer_n(&result->vdata, CD_SHAPEKEY, a);
- for (i = maxVerts; i < result->totvert; i++) {
- mul_m4_v3(mtx, cos[i]);
- }
- }
-
- /* adjust mirrored edge vertex indices */
- me = result->medge + maxEdges;
- for (i = 0; i < maxEdges; i++, me++) {
- me->v1 += maxVerts;
- me->v2 += maxVerts;
- }
-
- /* adjust mirrored poly loopstart indices, and reverse loop order (normals) */
- mp = result->mpoly + maxPolys;
- ml = result->mloop;
- for (i = 0; i < maxPolys; i++, mp++) {
- MLoop *ml2;
- int j, e;
-
- /* reverse the loop, but we keep the first vertex in the face the same,
- * to ensure that quads are split the same way as on the other side */
- CustomData_copy_data(
- &result->ldata, &result->ldata, mp->loopstart, mp->loopstart + maxLoops, 1);
-
- for (j = 1; j < mp->totloop; j++) {
- CustomData_copy_data(&result->ldata,
- &result->ldata,
- mp->loopstart + j,
- mp->loopstart + maxLoops + mp->totloop - j,
- 1);
- }
-
- ml2 = ml + mp->loopstart + maxLoops;
- e = ml2[0].e;
- for (j = 0; j < mp->totloop - 1; j++) {
- ml2[j].e = ml2[j + 1].e;
- }
- ml2[mp->totloop - 1].e = e;
-
- mp->loopstart += maxLoops;
- }
-
- /* adjust mirrored loop vertex and edge indices */
- ml = result->mloop + maxLoops;
- for (i = 0; i < maxLoops; i++, ml++) {
- ml->v += maxVerts;
- ml->e += maxEdges;
- }
-
- /* handle uvs,
- * let tessface recalc handle updating the MTFace data */
- if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V) ||
- (is_zero_v2(mmd->uv_offset_copy) == false)) {
- const bool do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0;
- const bool do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0;
-
- const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV);
-
- for (a = 0; a < totuv; a++) {
- MLoopUV *dmloopuv = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, a);
- int j = maxLoops;
- dmloopuv += j; /* second set of loops only */
- for (; j-- > 0; dmloopuv++) {
- if (do_mirr_u) {
- dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0] + mmd->uv_offset[0];
- }
- if (do_mirr_v) {
- dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1] + mmd->uv_offset[1];
- }
- dmloopuv->uv[0] += mmd->uv_offset_copy[0];
- dmloopuv->uv[1] += mmd->uv_offset_copy[1];
- }
- }
- }
-
- /* handle custom split normals */
- if (ob->type == OB_MESH && (((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) &&
- CustomData_has_layer(&result->ldata, CD_CUSTOMLOOPNORMAL)) {
- const int totloop = result->totloop;
- const int totpoly = result->totpoly;
- float(*loop_normals)[3] = MEM_calloc_arrayN((size_t)totloop, sizeof(*loop_normals), __func__);
- CustomData *ldata = &result->ldata;
- short(*clnors)[2] = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
- MLoopNorSpaceArray lnors_spacearr = {NULL};
- float(*poly_normals)[3] = MEM_mallocN(sizeof(*poly_normals) * totpoly, __func__);
-
- /* calculate custom normals into loop_normals, then mirror first half into second half */
-
- BKE_mesh_calc_normals_poly(result->mvert,
- NULL,
- result->totvert,
- result->mloop,
- result->mpoly,
- totloop,
- totpoly,
- poly_normals,
- false);
-
- BKE_mesh_normals_loop_split(result->mvert,
- result->totvert,
- result->medge,
- result->totedge,
- result->mloop,
- loop_normals,
- totloop,
- result->mpoly,
- poly_normals,
- totpoly,
- true,
- mesh->smoothresh,
- &lnors_spacearr,
- clnors,
- NULL);
-
- /* mirroring has to account for loops being reversed in polys in second half */
- mp = result->mpoly;
- for (i = 0; i < maxPolys; i++, mp++) {
- MPoly *mpmirror = result->mpoly + maxPolys + i;
- int j;
-
- for (j = mp->loopstart; j < mp->loopstart + mp->totloop; j++) {
- int mirrorj = mpmirror->loopstart;
- if (j > mp->loopstart) {
- mirrorj += mpmirror->totloop - (j - mp->loopstart);
- }
- copy_v3_v3(loop_normals[mirrorj], loop_normals[j]);
- loop_normals[mirrorj][axis] = -loop_normals[j][axis];
- BKE_lnor_space_custom_normal_to_data(
- lnors_spacearr.lspacearr[mirrorj], loop_normals[mirrorj], clnors[mirrorj]);
- }
- }
-
- MEM_freeN(poly_normals);
- MEM_freeN(loop_normals);
- BKE_lnor_spacearr_free(&lnors_spacearr);
- }
-
- /* handle vgroup stuff */
- if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&result->vdata, CD_MDEFORMVERT)) {
- MDeformVert *dvert = (MDeformVert *)CustomData_get_layer(&result->vdata, CD_MDEFORMVERT) +
- maxVerts;
- int *flip_map = NULL, flip_map_len = 0;
-
- flip_map = defgroup_flip_map(ob, &flip_map_len, false);
-
- if (flip_map) {
- for (i = 0; i < maxVerts; dvert++, i++) {
- /* merged vertices get both groups, others get flipped */
- if (do_vtargetmap && (vtargetmap[i] != -1)) {
- defvert_flip_merged(dvert, flip_map, flip_map_len);
- }
- else {
- defvert_flip(dvert, flip_map, flip_map_len);
- }
- }
-
- MEM_freeN(flip_map);
- }
- }
-
- if (do_vtargetmap) {
- /* slow - so only call if one or more merge verts are found,
- * users may leave this on and not realize there is nothing to merge - campbell */
- if (tot_vtargetmap) {
- result = BKE_mesh_merge_verts(
- result, vtargetmap, tot_vtargetmap, MESH_MERGE_VERTS_DUMP_IF_MAPPED);
- }
- MEM_freeN(vtargetmap);
- }
-
- if (mesh_bisect != NULL) {
- BKE_id_free(NULL, mesh_bisect);
- }
-
- return result;
-}
-
static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
const ModifierEvalContext *ctx,
Object *ob,
@@ -445,11 +78,11 @@ static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
/* check which axes have been toggled and mirror accordingly */
if (mmd->flag & MOD_MIR_AXIS_X) {
- result = doMirrorOnAxis(mmd, ctx, ob, result, 0);
+ result = BKE_mirror_apply_mirror_on_axis(mmd, ctx, ob, result, 0);
}
if (mmd->flag & MOD_MIR_AXIS_Y) {
Mesh *tmp = result;
- result = doMirrorOnAxis(mmd, ctx, ob, result, 1);
+ result = BKE_mirror_apply_mirror_on_axis(mmd, ctx, ob, result, 1);
if (tmp != mesh) {
/* free intermediate results */
BKE_id_free(NULL, tmp);
@@ -457,7 +90,7 @@ static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
}
if (mmd->flag & MOD_MIR_AXIS_Z) {
Mesh *tmp = result;
- result = doMirrorOnAxis(mmd, ctx, ob, result, 2);
+ result = BKE_mirror_apply_mirror_on_axis(mmd, ctx, ob, result, 2);
if (tmp != mesh) {
/* free intermediate results */
BKE_id_free(NULL, tmp);
diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c
index c64d9be1158..53bb579128a 100644
--- a/source/blender/modifiers/intern/MOD_multires.c
+++ b/source/blender/modifiers/intern/MOD_multires.c
@@ -38,6 +38,7 @@
#include "BKE_paint.h"
#include "BKE_subdiv.h"
#include "BKE_subdiv_ccg.h"
+#include "BKE_subdiv_deform.h"
#include "BKE_subdiv_mesh.h"
#include "BKE_subsurf.h"
@@ -168,6 +169,10 @@ static Mesh *multires_as_ccg(MultiresModifierData *mmd,
static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result = mesh;
+#if !defined(WITH_OPENSUBDIV)
+ modifier_setError(md, "Disabled, built without OpenSubdiv");
+ return result;
+#endif
MultiresModifierData *mmd = (MultiresModifierData *)md;
SubdivSettings subdiv_settings;
BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
@@ -223,6 +228,36 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
return result;
}
+static void deformVerts(ModifierData *md,
+ const ModifierEvalContext *UNUSED(ctx),
+ Mesh *mesh,
+ float (*vertex_cos)[3],
+ int num_verts)
+{
+#if !defined(WITH_OPENSUBDIV)
+ modifier_setError(md, "Disabled, built without OpenSubdiv");
+ return;
+#endif
+ MultiresModifierData *mmd = (MultiresModifierData *)md;
+ SubdivSettings subdiv_settings;
+ BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
+ if (subdiv_settings.level == 0) {
+ return;
+ }
+ BKE_subdiv_settings_validate_for_mesh(&subdiv_settings, mesh);
+ MultiresRuntimeData *runtime_data = multires_ensure_runtime(mmd);
+ Subdiv *subdiv = subdiv_descriptor_ensure(mmd, &subdiv_settings, mesh);
+ if (subdiv == NULL) {
+ /* Happens on bad topology, ut also on empty input mesh. */
+ return;
+ }
+ BKE_subdiv_displacement_attach_from_multires(subdiv, mesh, mmd);
+ BKE_subdiv_deform_coarse_vertices(subdiv, mesh, vertex_cos, num_verts);
+ if (subdiv != runtime_data->subdiv) {
+ BKE_subdiv_free(subdiv);
+ }
+}
+
ModifierTypeInfo modifierType_Multires = {
/* name */ "Multires",
/* structName */ "MultiresModifierData",
@@ -233,7 +268,7 @@ ModifierTypeInfo modifierType_Multires = {
/* copyData */ copyData,
- /* deformVerts */ NULL,
+ /* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index aff5b8b071b..97be42367d4 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -268,7 +268,7 @@ static void generate_ocean_geometry_uvs(void *__restrict userdata,
}
}
-static Mesh *generate_ocean_geometry(OceanModifierData *omd)
+static Mesh *generate_ocean_geometry(OceanModifierData *omd, Mesh *mesh_orig)
{
Mesh *result;
@@ -296,6 +296,7 @@ static Mesh *generate_ocean_geometry(OceanModifierData *omd)
gogd.sy /= gogd.ry;
result = BKE_mesh_new_nomain(num_verts, 0, 0, num_polys * 4, num_polys);
+ BKE_mesh_copy_settings(result, mesh_orig);
gogd.mverts = result->mvert;
gogd.mpolys = result->mpoly;
@@ -377,7 +378,7 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes
}
if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) {
- result = generate_ocean_geometry(omd);
+ result = generate_ocean_geometry(omd, mesh);
BKE_mesh_ensure_normals(result);
}
else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) {
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index 01f1aeffdb2..49bb8691764 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -83,7 +83,7 @@ static bool isDisabled(const struct Scene *scene, ModifierData *md, bool useRend
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the mesh is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
if (!pimd->ob || pimd->ob->type != OB_MESH) {
return true;
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index a7c7c207cd6..67a64921bbc 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -168,7 +168,7 @@ static void deformVerts(ModifierData *md,
if (em) {
/* In edit mode get directly from the edit mesh. */
- psmd->mesh_original = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL);
+ psmd->mesh_original = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, mesh);
}
else {
/* Otherwise get regular mesh. */
diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c
index 631401d9d9e..df84f3db55c 100644
--- a/source/blender/modifiers/intern/MOD_remesh.c
+++ b/source/blender/modifiers/intern/MOD_remesh.c
@@ -185,6 +185,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *UNUSED(c
}
}
+ BKE_mesh_copy_settings(result, mesh);
BKE_mesh_calc_edges(result, true, false);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
return result;
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index ac47422fe2f..773cbf72d5b 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -46,18 +46,18 @@
/* used for gathering edge connectivity */
typedef struct ScrewVertConnect {
- float dist; /* distance from the center axis */
- float co[3]; /* location relative to the transformed axis */
- float no[3]; /* calc normal of the vertex */
- unsigned int v[2]; /* 2 verts on either side of this one */
- MEdge *e[2]; /* edges on either side, a bit of a waste since each edge ref's 2 edges */
+ float dist; /* distance from the center axis */
+ float co[3]; /* location relative to the transformed axis */
+ float no[3]; /* calc normal of the vertex */
+ uint v[2]; /* 2 verts on either side of this one */
+ MEdge *e[2]; /* edges on either side, a bit of a waste since each edge ref's 2 edges */
char flag;
} ScrewVertConnect;
typedef struct ScrewVertIter {
ScrewVertConnect *v_array;
ScrewVertConnect *v_poin;
- unsigned int v, v_other;
+ uint v, v_other;
MEdge *e;
} ScrewVertIter;
@@ -67,8 +67,8 @@ typedef struct ScrewVertIter {
static void screwvert_iter_init(ScrewVertIter *iter,
ScrewVertConnect *array,
- unsigned int v_init,
- unsigned int dir)
+ uint v_init,
+ uint dir)
{
iter->v_array = array;
iter->v = v_init;
@@ -187,10 +187,10 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
int *origindex;
int mpoly_index = 0;
- unsigned int step;
- unsigned int i, j;
- unsigned int i1, i2;
- unsigned int step_tot = use_render_params ? ltmd->render_steps : ltmd->steps;
+ uint step;
+ uint i, j;
+ uint i1, i2;
+ uint step_tot = use_render_params ? ltmd->render_steps : ltmd->steps;
const bool do_flip = (ltmd->flag & MOD_SCREW_NORMAL_FLIP) != 0;
const int quad_ord[4] = {
@@ -206,17 +206,16 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
3,
};
- unsigned int maxVerts = 0, maxEdges = 0, maxPolys = 0;
- const unsigned int totvert = (unsigned int)mesh->totvert;
- const unsigned int totedge = (unsigned int)mesh->totedge;
- const unsigned int totpoly = (unsigned int)mesh->totpoly;
+ uint maxVerts = 0, maxEdges = 0, maxPolys = 0;
+ const uint totvert = (uint)mesh->totvert;
+ const uint totedge = (uint)mesh->totedge;
+ const uint totpoly = (uint)mesh->totpoly;
- unsigned int *edge_poly_map = NULL; /* orig edge to orig poly */
- unsigned int *vert_loop_map = NULL; /* orig vert to orig loop */
+ uint *edge_poly_map = NULL; /* orig edge to orig poly */
+ uint *vert_loop_map = NULL; /* orig vert to orig loop */
/* UV Coords */
- const unsigned int mloopuv_layers_tot = (unsigned int)CustomData_number_of_layers(&mesh->ldata,
- CD_MLOOPUV);
+ const uint mloopuv_layers_tot = (uint)CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
MLoopUV **mloopuv_layers = BLI_array_alloca(mloopuv_layers, mloopuv_layers_tot);
float uv_u_scale;
float uv_v_minmax[2] = {FLT_MAX, -FLT_MAX};
@@ -235,11 +234,11 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
float mtx_tx_inv[4][4]; /* inverted */
float mtx_tmp_a[4][4];
- unsigned int vc_tot_linked = 0;
+ uint vc_tot_linked = 0;
short other_axis_1, other_axis_2;
const float *tmpf1, *tmpf2;
- unsigned int edge_offset;
+ uint edge_offset;
MPoly *mpoly_orig, *mpoly_new, *mp_new;
MLoop *mloop_orig, *mloop_new, *ml_new;
@@ -409,7 +408,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
if (mloopuv_layers_tot) {
- unsigned int uv_lay;
+ uint uv_lay;
for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) {
mloopuv_layers[uv_lay] = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, (int)uv_lay);
}
@@ -460,18 +459,18 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
memset(vert_loop_map, 0xff, sizeof(*vert_loop_map) * totvert);
for (i = 0, mp_orig = mpoly_orig; i < totpoly; i++, mp_orig++) {
- unsigned int loopstart = (unsigned int)mp_orig->loopstart;
- unsigned int loopend = loopstart + (unsigned int)mp_orig->totloop;
+ uint loopstart = (uint)mp_orig->loopstart;
+ uint loopend = loopstart + (uint)mp_orig->totloop;
MLoop *ml_orig = &mloop_orig[loopstart];
- unsigned int k;
+ uint k;
for (k = loopstart; k < loopend; k++, ml_orig++) {
edge_poly_map[ml_orig->e] = i;
vert_loop_map[ml_orig->v] = k;
/* also order edges based on faces */
if (medge_new[ml_orig->e].v1 != ml_orig->v) {
- SWAP(unsigned int, medge_new[ml_orig->e].v1, medge_new[ml_orig->e].v2);
+ SWAP(uint, medge_new[ml_orig->e].v1, medge_new[ml_orig->e].v2);
}
}
}
@@ -596,7 +595,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
* so resulting faces are flipped the right way */
vc_tot_linked = 0; /* count the number of linked verts for this loop */
if (vc->flag == 0) {
- unsigned int v_best = SV_UNUSED, ed_loop_closed = 0; /* vert and vert new */
+ uint v_best = SV_UNUSED, ed_loop_closed = 0; /* vert and vert new */
ScrewVertIter lt_iter;
float fl = -1.0f;
@@ -731,7 +730,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
if (lt_iter.v == lt_iter.e->v1) {
if (ed_loop_flip == 0) {
/*printf("\t\t\tFlipping 0\n");*/
- SWAP(unsigned int, lt_iter.e->v1, lt_iter.e->v2);
+ SWAP(uint, lt_iter.e->v1, lt_iter.e->v2);
}
#if 0
else {
@@ -742,7 +741,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
else if (lt_iter.v == lt_iter.e->v2) {
if (ed_loop_flip == 1) {
/*printf("\t\t\tFlipping 1\n");*/
- SWAP(unsigned int, lt_iter.e->v1, lt_iter.e->v2);
+ SWAP(uint, lt_iter.e->v1, lt_iter.e->v2);
}
#if 0
else {
@@ -851,7 +850,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
/* Add Faces */
for (step = 1; step < step_tot; step++) {
- const unsigned int varray_stride = totvert * step;
+ const uint varray_stride = totvert * step;
float step_angle;
float nor_tx[3];
float mat[4][4];
@@ -921,7 +920,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
if (close) {
/* last loop of edges, previous loop doesn't account for the last set of edges */
- const unsigned int varray_stride = (step_tot - 1) * totvert;
+ const uint varray_stride = (step_tot - 1) * totvert;
for (i = 0; i < totvert; i++) {
med_new->v1 = i;
@@ -942,12 +941,12 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
edge_offset = totedge + (totvert * (step_tot - (close ? 0 : 1)));
for (i = 0; i < totedge; i++, med_new_firstloop++) {
- const unsigned int step_last = step_tot - (close ? 1 : 2);
- const unsigned int mpoly_index_orig = totpoly ? edge_poly_map[i] : UINT_MAX;
+ const uint step_last = step_tot - (close ? 1 : 2);
+ const uint mpoly_index_orig = totpoly ? edge_poly_map[i] : UINT_MAX;
const bool has_mpoly_orig = (mpoly_index_orig != UINT_MAX);
float uv_v_offset_a, uv_v_offset_b;
- const unsigned int mloop_index_orig[2] = {
+ const uint mloop_index_orig[2] = {
vert_loop_map ? vert_loop_map[medge_new[i].v1] : UINT_MAX,
vert_loop_map ? vert_loop_map[medge_new[i].v2] : UINT_MAX,
};
@@ -1006,7 +1005,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
&mesh->ldata, &result->ldata, (int)mloop_index_orig[0], l_index + 3, 1);
if (mloopuv_layers_tot) {
- unsigned int uv_lay;
+ uint uv_lay;
const float uv_u_offset_a = (float)(step)*uv_u_scale;
const float uv_u_offset_b = (float)(step + 1) * uv_u_scale;
for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) {
@@ -1023,7 +1022,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
if (mloopuv_layers_tot) {
int l_index = (int)(ml_new - mloop_new);
- unsigned int uv_lay;
+ uint uv_lay;
const float uv_u_offset_a = (float)(step)*uv_u_scale;
const float uv_u_offset_b = (float)(step + 1) * uv_u_scale;
for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) {
@@ -1094,7 +1093,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
unsigned i = 0;
printf("\n");
for (; i < maxPolys * 4; i += 4) {
- unsigned int ii;
+ uint ii;
ml_new = mloop_new + i;
ii = findEd(medge_new, maxEdges, ml_new[0].v, ml_new[1].v);
printf("%d %d -- ", ii, ml_new[0].e);
diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c
index 408ec06a49c..b8d0b19b7bf 100644
--- a/source/blender/modifiers/intern/MOD_shrinkwrap.c
+++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c
@@ -65,8 +65,8 @@ static void requiredDataMask(Object *UNUSED(ob),
if ((smd->shrinkType == MOD_SHRINKWRAP_PROJECT) &&
(smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL)) {
- r_cddata_masks->vmask |=
- CD_MASK_MVERT; /* XXX Really? These should always be present, always... */
+ /* XXX Really? These should always be present, always... */
+ r_cddata_masks->vmask |= CD_MASK_MVERT;
}
}
@@ -79,7 +79,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the mesh is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
if (!smd->target || smd->target->type != OB_MESH) {
return true;
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index 1a541f9fc5a..6e7a0b0dbae 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -103,7 +103,7 @@ typedef struct Frame {
int corner;
/* checked to avoid chaining.
* (merging when we're already been referenced), see T39775 */
- unsigned int is_target : 1;
+ uint is_target : 1;
} merge[4];
/* For hull frames, whether each vertex is detached or not */
@@ -1518,7 +1518,7 @@ static void skin_update_merged_vertices(SkinNode *skin_nodes, int totvert)
{
int v;
- for (v = 0; v < totvert; ++v) {
+ for (v = 0; v < totvert; v++) {
SkinNode *sn = &skin_nodes[v];
int i, j;
@@ -1566,7 +1566,7 @@ static void skin_output_end_nodes(SkinOutput *so, SkinNode *skin_nodes, int totv
{
int v;
- for (v = 0; v < totvert; ++v) {
+ for (v = 0; v < totvert; v++) {
SkinNode *sn = &skin_nodes[v];
/* Assuming here just two frames */
if (sn->flag & SEAM_FRAME) {
@@ -1769,7 +1769,7 @@ static BMesh *build_skin(SkinNode *skin_nodes,
skin_merge_close_frame_verts(skin_nodes, totvert, emap, medge);
/* Write out all frame vertices to the mesh */
- for (v = 0; v < totvert; ++v) {
+ for (v = 0; v < totvert; v++) {
if (skin_nodes[v].totframe) {
output_frames(so.bm, &skin_nodes[v], input_dvert ? &input_dvert[v] : NULL);
}
@@ -1871,7 +1871,7 @@ static Mesh *base_skin(Mesh *origmesh, SkinModifierData *smd)
return NULL;
}
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, origmesh);
BM_mesh_free(bm);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c
index 59d5b2ccbd2..c8bc3aaa484 100644
--- a/source/blender/modifiers/intern/MOD_smooth.c
+++ b/source/blender/modifiers/intern/MOD_smooth.c
@@ -54,16 +54,15 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
bool UNUSED(useRenderParams))
{
SmoothModifierData *smd = (SmoothModifierData *)md;
- short flag;
- flag = smd->flag & (MOD_SMOOTH_X | MOD_SMOOTH_Y | MOD_SMOOTH_Z);
+ const short flag = smd->flag & (MOD_SMOOTH_X | MOD_SMOOTH_Y | MOD_SMOOTH_Z);
/* disable if modifier is off for X, Y and Z or if factor is 0 */
- if ((smd->fac == 0.0f) || flag == 0) {
- return 1;
+ if (smd->fac == 0.0f || flag == 0) {
+ return true;
}
- return 0;
+ return false;
}
static void requiredDataMask(Object *UNUSED(ob),
@@ -81,134 +80,105 @@ static void requiredDataMask(Object *UNUSED(ob),
static void smoothModifier_do(
SmoothModifierData *smd, Object *ob, Mesh *mesh, float (*vertexCos)[3], int numVerts)
{
- MDeformVert *dvert = NULL;
- MEdge *medges = NULL;
-
- int i, j, numDMEdges, defgrp_index;
- unsigned char *uctmp;
- float *ftmp, fac, facm;
+ if (mesh == NULL) {
+ return;
+ }
- ftmp = (float *)MEM_calloc_arrayN(numVerts, 3 * sizeof(float), "smoothmodifier_f");
- if (!ftmp) {
+ float(*accumulated_vecs)[3] = MEM_calloc_arrayN(
+ (size_t)numVerts, sizeof(*accumulated_vecs), __func__);
+ if (!accumulated_vecs) {
return;
}
- uctmp = (unsigned char *)MEM_calloc_arrayN(numVerts, sizeof(unsigned char), "smoothmodifier_uc");
- if (!uctmp) {
- if (ftmp) {
- MEM_freeN(ftmp);
+
+ uint *num_accumulated_vecs = MEM_calloc_arrayN(
+ (size_t)numVerts, sizeof(*num_accumulated_vecs), __func__);
+ if (!num_accumulated_vecs) {
+ if (accumulated_vecs) {
+ MEM_freeN(accumulated_vecs);
}
return;
}
- fac = smd->fac;
- facm = 1 - fac;
+ const float fac_new = smd->fac;
+ const float fac_orig = 1.0f - fac_new;
- if (mesh != NULL) {
- medges = mesh->medge;
- numDMEdges = mesh->totedge;
- }
- else {
- medges = NULL;
- numDMEdges = 0;
- }
+ MEdge *medges = mesh->medge;
+ const int num_edges = mesh->totedge;
+ MDeformVert *dvert;
+ int defgrp_index;
MOD_get_vgroup(ob, mesh, smd->defgrp_name, &dvert, &defgrp_index);
- /* NOTICE: this can be optimized a little bit by moving the
- * if (dvert) out of the loop, if needed */
- for (j = 0; j < smd->repeat; j++) {
- for (i = 0; i < numDMEdges; i++) {
- float fvec[3];
- float *v1, *v2;
- unsigned int idx1, idx2;
-
- idx1 = medges[i].v1;
- idx2 = medges[i].v2;
+ for (int j = 0; j < smd->repeat; j++) {
+ if (j != 0) {
+ memset(accumulated_vecs, 0, sizeof(*accumulated_vecs) * (size_t)numVerts);
+ memset(num_accumulated_vecs, 0, sizeof(*num_accumulated_vecs) * (size_t)numVerts);
+ }
- v1 = vertexCos[idx1];
- v2 = vertexCos[idx2];
+ for (int i = 0; i < num_edges; i++) {
+ float fvec[3];
+ const uint idx1 = medges[i].v1;
+ const uint idx2 = medges[i].v2;
- mid_v3_v3v3(fvec, v1, v2);
+ mid_v3_v3v3(fvec, vertexCos[idx1], vertexCos[idx2]);
- v1 = &ftmp[idx1 * 3];
- v2 = &ftmp[idx2 * 3];
+ num_accumulated_vecs[idx1]++;
+ add_v3_v3(accumulated_vecs[idx1], fvec);
- if (uctmp[idx1] < 255) {
- uctmp[idx1]++;
- add_v3_v3(v1, fvec);
- }
- if (uctmp[idx2] < 255) {
- uctmp[idx2]++;
- add_v3_v3(v2, fvec);
- }
+ num_accumulated_vecs[idx2]++;
+ add_v3_v3(accumulated_vecs[idx2], fvec);
}
+ const short flag = smd->flag;
if (dvert) {
MDeformVert *dv = dvert;
- for (i = 0; i < numVerts; i++, dv++) {
- float f, fm, facw, *fp, *v;
- short flag = smd->flag;
-
- v = vertexCos[i];
- fp = &ftmp[i * 3];
-
- f = defvert_find_weight(dv, defgrp_index);
- if (f <= 0.0f) {
- continue;
+ for (int i = 0; i < numVerts; i++, dv++) {
+ float *vco_orig = vertexCos[i];
+ if (num_accumulated_vecs[0] > 0) {
+ mul_v3_fl(accumulated_vecs[i], 1.0f / (float)num_accumulated_vecs[i]);
}
+ float *vco_new = accumulated_vecs[i];
- f *= fac;
- fm = 1.0f - f;
-
- /* fp is the sum of uctmp[i] verts, so must be averaged */
- facw = 0.0f;
- if (uctmp[i]) {
- facw = f / (float)uctmp[i];
+ const float f_new = defvert_find_weight(dv, defgrp_index) * fac_new;
+ if (f_new <= 0.0f) {
+ continue;
}
+ const float f_orig = 1.0f - f_new;
if (flag & MOD_SMOOTH_X) {
- v[0] = fm * v[0] + facw * fp[0];
+ vco_orig[0] = f_orig * vco_orig[0] + f_new * vco_new[0];
}
if (flag & MOD_SMOOTH_Y) {
- v[1] = fm * v[1] + facw * fp[1];
+ vco_orig[1] = f_orig * vco_orig[1] + f_new * vco_new[1];
}
if (flag & MOD_SMOOTH_Z) {
- v[2] = fm * v[2] + facw * fp[2];
+ vco_orig[2] = f_orig * vco_orig[2] + f_new * vco_new[2];
}
}
}
else { /* no vertex group */
- for (i = 0; i < numVerts; i++) {
- float facw, *fp, *v;
- short flag = smd->flag;
-
- v = vertexCos[i];
- fp = &ftmp[i * 3];
-
- /* fp is the sum of uctmp[i] verts, so must be averaged */
- facw = 0.0f;
- if (uctmp[i]) {
- facw = fac / (float)uctmp[i];
+ for (int i = 0; i < numVerts; i++) {
+ float *vco_orig = vertexCos[i];
+ if (num_accumulated_vecs[0] > 0) {
+ mul_v3_fl(accumulated_vecs[i], 1.0f / (float)num_accumulated_vecs[i]);
}
+ float *vco_new = accumulated_vecs[i];
if (flag & MOD_SMOOTH_X) {
- v[0] = facm * v[0] + facw * fp[0];
+ vco_orig[0] = fac_orig * vco_orig[0] + fac_new * vco_new[0];
}
if (flag & MOD_SMOOTH_Y) {
- v[1] = facm * v[1] + facw * fp[1];
+ vco_orig[1] = fac_orig * vco_orig[1] + fac_new * vco_new[1];
}
if (flag & MOD_SMOOTH_Z) {
- v[2] = facm * v[2] + facw * fp[2];
+ vco_orig[2] = fac_orig * vco_orig[2] + fac_new * vco_new[2];
}
}
}
-
- memset(ftmp, 0, 3 * sizeof(float) * numVerts);
- memset(uctmp, 0, sizeof(unsigned char) * numVerts);
}
- MEM_freeN(ftmp);
- MEM_freeN(uctmp);
+ MEM_freeN(accumulated_vecs);
+ MEM_freeN(num_accumulated_vecs);
}
static void deformVerts(ModifierData *md,
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index 05bcc7f695d..292e659fe03 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -198,11 +198,11 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
MEdge *ed, *medge, *orig_medge;
MLoop *ml, *mloop, *orig_mloop;
MPoly *mp, *mpoly, *orig_mpoly;
- const unsigned int numVerts = (unsigned int)mesh->totvert;
- const unsigned int numEdges = (unsigned int)mesh->totedge;
- const unsigned int numPolys = (unsigned int)mesh->totpoly;
- const unsigned int numLoops = (unsigned int)mesh->totloop;
- unsigned int newLoops = 0, newPolys = 0, newEdges = 0, newVerts = 0, rimVerts = 0;
+ const uint numVerts = (uint)mesh->totvert;
+ const uint numEdges = (uint)mesh->totedge;
+ const uint numPolys = (uint)mesh->totpoly;
+ const uint numLoops = (uint)mesh->totloop;
+ uint newLoops = 0, newPolys = 0, newEdges = 0, newVerts = 0, rimVerts = 0;
/* only use material offsets if we have 2 or more materials */
const short mat_nr_max = ctx->object->totcol > 1 ? ctx->object->totcol - 1 : 0;
@@ -211,16 +211,16 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
/* use for edges */
/* over-alloc new_vert_arr, old_vert_arr */
- unsigned int *new_vert_arr = NULL;
+ uint *new_vert_arr = NULL;
STACK_DECLARE(new_vert_arr);
- unsigned int *new_edge_arr = NULL;
+ uint *new_edge_arr = NULL;
STACK_DECLARE(new_edge_arr);
- unsigned int *old_vert_arr = MEM_calloc_arrayN(
+ uint *old_vert_arr = MEM_calloc_arrayN(
numVerts, sizeof(*old_vert_arr), "old_vert_arr in solidify");
- unsigned int *edge_users = NULL;
+ uint *edge_users = NULL;
char *edge_order = NULL;
float(*vert_nors)[3] = NULL;
@@ -244,7 +244,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
int defgrp_index;
/* array size is doubled in case of using a shell */
- const unsigned int stride = do_shell ? 2 : 1;
+ const uint stride = do_shell ? 2 : 1;
MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index);
@@ -272,11 +272,11 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
if (smd->flag & MOD_SOLIDIFY_RIM) {
BLI_bitmap *orig_mvert_tag = BLI_BITMAP_NEW(numVerts, __func__);
- unsigned int eidx;
- unsigned int i;
+ uint eidx;
+ uint i;
-#define INVALID_UNUSED ((unsigned int)-1)
-#define INVALID_PAIR ((unsigned int)-2)
+#define INVALID_UNUSED ((uint)-1)
+#define INVALID_PAIR ((uint)-2)
new_vert_arr = MEM_malloc_arrayN(numVerts, 2 * sizeof(*new_vert_arr), __func__);
new_edge_arr = MEM_malloc_arrayN(((numEdges * 2) + numVerts), sizeof(*new_edge_arr), __func__);
@@ -442,13 +442,13 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
/* flip normals */
if (do_shell) {
- unsigned int i;
+ uint i;
mp = mpoly + numPolys;
for (i = 0; i < mesh->totpoly; i++, mp++) {
const int loop_end = mp->totloop - 1;
MLoop *ml2;
- unsigned int e;
+ uint e;
int j;
/* reverses the loop direction (MLoop.v as well as custom-data)
@@ -512,7 +512,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
const float offset_sq = offset * offset;
if (do_clamp) {
- unsigned int i;
+ uint i;
vert_lens = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_lens");
copy_vn_fl(vert_lens, (int)numVerts, FLT_MAX);
@@ -524,7 +524,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
if (ofs_new != 0.0f) {
- unsigned int i_orig, i_end;
+ uint i_orig, i_end;
bool do_shell_align;
scalar_short = scalar_short_vgroup = ofs_new / 32767.0f;
@@ -532,7 +532,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
INIT_VERT_ARRAY_OFFSETS(false);
for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
- const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig];
+ const uint i = do_shell_align ? i_orig : new_vert_arr[i_orig];
if (dvert) {
MDeformVert *dv = &dvert[i];
if (defgrp_invert) {
@@ -559,7 +559,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
if (ofs_orig != 0.0f) {
- unsigned int i_orig, i_end;
+ uint i_orig, i_end;
bool do_shell_align;
scalar_short = scalar_short_vgroup = ofs_orig / 32767.0f;
@@ -568,7 +568,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
INIT_VERT_ARRAY_OFFSETS(true);
for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
- const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig];
+ const uint i = do_shell_align ? i_orig : new_vert_arr[i_orig];
if (dvert) {
MDeformVert *dv = &dvert[i];
if (defgrp_invert) {
@@ -606,8 +606,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
float *vert_angles = MEM_calloc_arrayN(
numVerts, 2 * sizeof(float), "mod_solid_pair"); /* 2 in 1 */
float *vert_accum = vert_angles + numVerts;
- unsigned int vidx;
- unsigned int i;
+ uint vidx;
+ uint i;
if (vert_nors == NULL) {
vert_nors = MEM_malloc_arrayN(numVerts, 3 * sizeof(float), "mod_solid_vno");
@@ -707,13 +707,13 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
if (ofs_new != 0.0f) {
- unsigned int i_orig, i_end;
+ uint i_orig, i_end;
bool do_shell_align;
INIT_VERT_ARRAY_OFFSETS(false);
for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
- const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
+ const uint i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
if (vert_accum[i_other]) { /* zero if unselected */
madd_v3_v3fl(
mv->co, vert_nors[i_other], ofs_new * (vert_angles[i_other] / vert_accum[i_other]));
@@ -722,14 +722,14 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
if (ofs_orig != 0.0f) {
- unsigned int i_orig, i_end;
+ uint i_orig, i_end;
bool do_shell_align;
/* same as above but swapped, intentional use of 'ofs_new' */
INIT_VERT_ARRAY_OFFSETS(true);
for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
- const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
+ const uint i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
if (vert_accum[i_other]) { /* zero if unselected */
madd_v3_v3fl(
mv->co, vert_nors[i_other], ofs_orig * (vert_angles[i_other] / vert_accum[i_other]));
@@ -749,7 +749,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
else if (do_shell) {
- unsigned int i;
+ uint i;
/* flip vertex normals for copied verts */
mv = mvert + numVerts;
for (i = 0; i < numVerts; i++, mv++) {
@@ -758,7 +758,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
if (smd->flag & MOD_SOLIDIFY_RIM) {
- unsigned int i;
+ uint i;
/* bugger, need to re-calculate the normals for the new edge faces.
* This could be done in many ways, but probably the quickest way
@@ -781,13 +781,13 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
NULL;
float nor[3];
#endif
- const unsigned char crease_rim = smd->crease_rim * 255.0f;
- const unsigned char crease_outer = smd->crease_outer * 255.0f;
- const unsigned char crease_inner = smd->crease_inner * 255.0f;
+ const uchar crease_rim = smd->crease_rim * 255.0f;
+ const uchar crease_outer = smd->crease_outer * 255.0f;
+ const uchar crease_inner = smd->crease_inner * 255.0f;
int *origindex_edge;
int *orig_ed;
- unsigned int j;
+ uint j;
if (crease_rim || crease_outer || crease_inner) {
result->cd_flag |= ME_CDFLAG_EDGE_CREASE;
@@ -817,8 +817,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
ml = mloop + (numLoops * stride);
j = 0;
for (i = 0; i < newPolys; i++, mp++) {
- unsigned int eidx = new_edge_arr[i];
- unsigned int pidx = edge_users[eidx];
+ uint eidx = new_edge_arr[i];
+ uint pidx = edge_users[eidx];
int k1, k2;
bool flip;
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index 0b1249e263c..55df1b5ddda 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -35,6 +35,7 @@
#include "BKE_scene.h"
#include "BKE_subdiv.h"
#include "BKE_subdiv_ccg.h"
+#include "BKE_subdiv_deform.h"
#include "BKE_subdiv_mesh.h"
#include "BKE_subsurf.h"
@@ -208,6 +209,10 @@ static SubsurfRuntimeData *subsurf_ensure_runtime(SubsurfModifierData *smd)
static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result = mesh;
+#if !defined(WITH_OPENSUBDIV)
+ modifier_setError(md, "Disabled, built without OpenSubdiv");
+ return result;
+#endif
SubsurfModifierData *smd = (SubsurfModifierData *)md;
SubdivSettings subdiv_settings;
subdiv_settings_init(&subdiv_settings, smd);
@@ -236,6 +241,35 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
return result;
}
+static void deformVerts(ModifierData *md,
+ const ModifierEvalContext *UNUSED(ctx),
+ Mesh *mesh,
+ float (*vertex_cos)[3],
+ int num_verts)
+{
+#if !defined(WITH_OPENSUBDIV)
+ modifier_setError(md, "Disabled, built without OpenSubdiv");
+ return;
+#endif
+ SubsurfModifierData *smd = (SubsurfModifierData *)md;
+ SubdivSettings subdiv_settings;
+ subdiv_settings_init(&subdiv_settings, smd);
+ if (subdiv_settings.level == 0) {
+ return;
+ }
+ BKE_subdiv_settings_validate_for_mesh(&subdiv_settings, mesh);
+ SubsurfRuntimeData *runtime_data = subsurf_ensure_runtime(smd);
+ Subdiv *subdiv = subdiv_descriptor_ensure(smd, &subdiv_settings, mesh);
+ if (subdiv == NULL) {
+ /* Happens on bad topology, but also on empty input mesh. */
+ return;
+ }
+ BKE_subdiv_deform_coarse_vertices(subdiv, mesh, vertex_cos, num_verts);
+ if (subdiv != runtime_data->subdiv) {
+ BKE_subdiv_free(subdiv);
+ }
+}
+
ModifierTypeInfo modifierType_Subsurf = {
/* name */ "Subdivision",
/* structName */ "SubsurfModifierData",
@@ -247,7 +281,7 @@ ModifierTypeInfo modifierType_Subsurf = {
/* copyData */ copyData,
- /* deformVerts */ NULL,
+ /* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c
index 840914aa313..97e6bb9e804 100644
--- a/source/blender/modifiers/intern/MOD_surface.c
+++ b/source/blender/modifiers/intern/MOD_surface.c
@@ -125,7 +125,7 @@ static void deformVerts(ModifierData *md,
}
if (surmd->mesh) {
- unsigned int numverts = 0, i = 0;
+ uint numverts = 0, i = 0;
int init = 0;
float *vec;
MVert *x, *v;
diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c
index 93196ea21fb..de32b90a5e3 100644
--- a/source/blender/modifiers/intern/MOD_surfacedeform.c
+++ b/source/blender/modifiers/intern/MOD_surfacedeform.c
@@ -45,16 +45,16 @@
typedef struct SDefAdjacency {
struct SDefAdjacency *next;
- unsigned int index;
+ uint index;
} SDefAdjacency;
typedef struct SDefAdjacencyArray {
SDefAdjacency *first;
- unsigned int num; /* Careful, this is twice the number of polygons (avoids an extra loop) */
+ uint num; /* Careful, this is twice the number of polygons (avoids an extra loop) */
} SDefAdjacencyArray;
typedef struct SDefEdgePolys {
- unsigned int polys[2], num;
+ uint polys[2], num;
} SDefEdgePolys;
typedef struct SDefBindCalcData {
@@ -90,20 +90,20 @@ typedef struct SDefBindPoly {
float point_edgemid_angles[2];
float corner_edgemid_angles[2];
float dominant_angle_weight;
- unsigned int index;
- unsigned int numverts;
- unsigned int loopstart;
- unsigned int edge_inds[2];
- unsigned int edge_vert_inds[2];
- unsigned int corner_ind;
- unsigned int dominant_edge;
+ uint index;
+ uint numverts;
+ uint loopstart;
+ uint edge_inds[2];
+ uint edge_vert_inds[2];
+ uint corner_ind;
+ uint dominant_edge;
bool inside;
} SDefBindPoly;
typedef struct SDefBindWeightData {
SDefBindPoly *bind_polys;
- unsigned int numpoly;
- unsigned int numbinds;
+ uint numpoly;
+ uint numbinds;
} SDefBindWeightData;
typedef struct SDefDeformData {
@@ -217,8 +217,8 @@ static void freeAdjacencyMap(SDefAdjacencyArray *const vert_edges,
static int buildAdjacencyMap(const MPoly *poly,
const MEdge *edge,
const MLoop *const mloop,
- const unsigned int numpoly,
- const unsigned int numedges,
+ const uint numpoly,
+ const uint numedges,
SDefAdjacencyArray *const vert_edges,
SDefAdjacency *adj,
SDefEdgePolys *const edge_polys)
@@ -263,10 +263,10 @@ static int buildAdjacencyMap(const MPoly *poly,
return MOD_SDEF_BIND_RESULT_SUCCESS;
}
-BLI_INLINE void sortPolyVertsEdge(unsigned int *indices,
+BLI_INLINE void sortPolyVertsEdge(uint *indices,
const MLoop *const mloop,
- const unsigned int edge,
- const unsigned int num)
+ const uint edge,
+ const uint num)
{
bool found = false;
@@ -287,10 +287,10 @@ BLI_INLINE void sortPolyVertsEdge(unsigned int *indices,
}
}
-BLI_INLINE void sortPolyVertsTri(unsigned int *indices,
+BLI_INLINE void sortPolyVertsTri(uint *indices,
const MLoop *const mloop,
- const unsigned int loopstart,
- const unsigned int num)
+ const uint loopstart,
+ const uint num)
{
for (int i = loopstart; i < num; i++) {
*indices = mloop[i].v;
@@ -303,7 +303,7 @@ BLI_INLINE void sortPolyVertsTri(unsigned int *indices,
}
}
-BLI_INLINE unsigned int nearestVert(SDefBindCalcData *const data, const float point_co[3])
+BLI_INLINE uint nearestVert(SDefBindCalcData *const data, const float point_co[3])
{
BVHTreeNearest nearest = {
.dist_sq = FLT_MAX,
@@ -315,7 +315,7 @@ BLI_INLINE unsigned int nearestVert(SDefBindCalcData *const data, const float po
float t_point[3];
float max_dist = FLT_MAX;
float dist;
- unsigned int index = 0;
+ uint index = 0;
mul_v3_m4v3(t_point, data->imat, point_co);
@@ -346,7 +346,7 @@ BLI_INLINE unsigned int nearestVert(SDefBindCalcData *const data, const float po
}
}
-BLI_INLINE int isPolyValid(const float coords[][2], const unsigned int nr)
+BLI_INLINE int isPolyValid(const float coords[][2], const uint nr)
{
float prev_co[2];
float curr_vec[2], prev_vec[2];
@@ -408,7 +408,7 @@ BLI_INLINE float computeAngularWeight(const float point_angle, const float edgem
BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data,
const float point_co[3])
{
- const unsigned int nearest = nearestVert(data, point_co);
+ const uint nearest = nearestVert(data, point_co);
const SDefAdjacency *const vert_edges = data->vert_edges[nearest].first;
const SDefEdgePolys *const edge_polys = data->edge_polys;
@@ -444,7 +444,7 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data,
/* Loop over all adjacent edges,
* and build the SDefBindPoly data for each poly adjacent to those. */
for (vedge = vert_edges; vedge; vedge = vedge->next) {
- unsigned int edge_ind = vedge->index;
+ uint edge_ind = vedge->index;
for (int i = 0; i < edge_polys[edge_ind].num; i++) {
{
@@ -603,8 +603,8 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data,
SDefBindPoly *bpolys[2];
const SDefEdgePolys *epolys;
float ang_weights[2];
- unsigned int edge_ind = vedge->index;
- unsigned int edge_on_poly[2];
+ uint edge_ind = vedge->index;
+ uint edge_on_poly[2];
epolys = &edge_polys[edge_ind];
@@ -981,9 +981,9 @@ static void bindVert(void *__restrict userdata,
static bool surfacedeformBind(SurfaceDeformModifierData *smd,
float (*vertexCos)[3],
- unsigned int numverts,
- unsigned int tnumpoly,
- unsigned int tnumverts,
+ uint numverts,
+ uint tnumpoly,
+ uint tnumverts,
Mesh *target)
{
BVHTreeFromMesh treeData = {NULL};
@@ -991,7 +991,7 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd,
const MPoly *mpoly = target->mpoly;
const MEdge *medge = target->medge;
const MLoop *mloop = target->mloop;
- unsigned int tnumedges = target->totedge;
+ uint tnumedges = target->totedge;
int adj_result;
SDefAdjacencyArray *vert_edges;
SDefAdjacency *adj_array;
@@ -1173,12 +1173,12 @@ static void deformVert(void *__restrict userdata,
static void surfacedeformModifier_do(ModifierData *md,
const ModifierEvalContext *ctx,
float (*vertexCos)[3],
- unsigned int numverts,
+ uint numverts,
Object *ob)
{
SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
Mesh *target;
- unsigned int tnumverts, tnumpoly;
+ uint tnumverts, tnumpoly;
/* Exit function if bind flag is not set (free bind data if any). */
if (!(smd->flags & MOD_SDEF_BIND)) {
@@ -1282,7 +1282,7 @@ static bool isDisabled(const Scene *UNUSED(scene), ModifierData *md, bool UNUSED
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the mesh is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
return (smd->target == NULL || smd->target->type != OB_MESH) &&
!(smd->verts != NULL && !(smd->flags & MOD_SDEF_BIND));
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index 1582c27960e..7fba7e864ae 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -65,7 +65,7 @@ static Mesh *triangulate_mesh(Mesh *mesh,
BM_mesh_triangulate(bm, quad_method, ngon_method, min_vertices, false, NULL, NULL, NULL);
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cddata_masks);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cddata_masks, mesh);
BM_mesh_free(bm);
if (keep_clnors) {
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index e7acbd3e32e..1e3c747022c 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -108,12 +108,12 @@ void MOD_get_texture_coords(MappingInfoModifierData *dmd,
mloop_uv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
/* verts are given the UV from the first face that uses them */
- for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp) {
- unsigned int fidx = mp->totloop - 1;
+ for (i = 0, mp = mpoly; i < numPolys; i++, mp++) {
+ uint fidx = mp->totloop - 1;
do {
- unsigned int lidx = mp->loopstart + fidx;
- unsigned int vidx = mloop[lidx].v;
+ uint lidx = mp->loopstart + fidx;
+ uint vidx = mloop[lidx].v;
if (!BLI_BITMAP_TEST(done, vidx)) {
/* remap UVs from [0, 1] to [-1, 1] */
@@ -135,7 +135,7 @@ void MOD_get_texture_coords(MappingInfoModifierData *dmd,
}
MVert *mv = mesh->mvert;
- for (i = 0; i < numVerts; ++i, ++mv, ++r_texco) {
+ for (i = 0; i < numVerts; i++, mv++, r_texco++) {
switch (texmapping) {
case MOD_DISP_MAP_LOCAL:
copy_v3_v3(*r_texco, cos != NULL ? *cos : mv->co);
@@ -182,7 +182,7 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
}
else if (ob->type == OB_MESH) {
if (em) {
- mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL);
+ mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, ob->data);
}
else {
/* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index 5f1eae0297a..9698e150850 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -68,7 +68,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
UVProjectModifierData *umd = (UVProjectModifierData *)md;
int i;
- for (i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i) {
+ for (i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; i++) {
walk(userData, ob, &umd->projectors[i], IDWALK_CB_NOP);
}
}
@@ -86,7 +86,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
{
UVProjectModifierData *umd = (UVProjectModifierData *)md;
bool do_add_own_transform = false;
- for (int i = 0; i < umd->num_projectors; ++i) {
+ for (int i = 0; i < umd->num_projectors; i++) {
if (umd->projectors[i] != NULL) {
DEG_add_object_relation(
ctx->node, umd->projectors[i], DEG_OB_COMP_TRANSFORM, "UV Project Modifier");
@@ -124,7 +124,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
float scay = umd->scaley ? umd->scaley : 1.0f;
int free_uci = 0;
- for (i = 0; i < umd->num_projectors; ++i) {
+ for (i = 0; i < umd->num_projectors; i++) {
if (umd->projectors[i] != NULL) {
projectors[num_projectors++].ob = umd->projectors[i];
}
@@ -144,7 +144,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, umd->uvlayer_name, uvname);
/* calculate a projection matrix and normal for each projector */
- for (i = 0; i < num_projectors; ++i) {
+ for (i = 0; i < num_projectors; i++) {
float tmpmat[4][4];
float offsetmat[4][4];
Camera *cam = NULL;
@@ -207,13 +207,13 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
coords = BKE_mesh_vert_coords_alloc(mesh, &numVerts);
/* convert coords to world space */
- for (i = 0, co = coords; i < numVerts; ++i, ++co) {
+ for (i = 0, co = coords; i < numVerts; i++, co++) {
mul_m4_v3(ob->obmat, *co);
}
/* if only one projector, project coords to UVs */
if (num_projectors == 1 && projectors[0].uci == NULL) {
- for (i = 0, co = coords; i < numVerts; ++i, ++co) {
+ for (i = 0, co = coords; i < numVerts; i++, co++) {
mul_project_m4_v3(projectors[0].projmat, *co);
}
}
@@ -222,22 +222,22 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
mloop = mesh->mloop;
/* apply coords as UVs */
- for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp) {
+ for (i = 0, mp = mpoly; i < numPolys; i++, mp++) {
if (num_projectors == 1) {
if (projectors[0].uci) {
- unsigned int fidx = mp->totloop - 1;
+ uint fidx = mp->totloop - 1;
do {
- unsigned int lidx = mp->loopstart + fidx;
- unsigned int vidx = mloop[lidx].v;
+ uint lidx = mp->loopstart + fidx;
+ uint vidx = mloop[lidx].v;
BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], projectors[0].uci);
} while (fidx--);
}
else {
/* apply transformed coords as UVs */
- unsigned int fidx = mp->totloop - 1;
+ uint fidx = mp->totloop - 1;
do {
- unsigned int lidx = mp->loopstart + fidx;
- unsigned int vidx = mloop[lidx].v;
+ uint lidx = mp->loopstart + fidx;
+ uint vidx = mloop[lidx].v;
copy_v2_v2(mloop_uv[lidx].uv, coords[vidx]);
} while (fidx--);
}
@@ -259,7 +259,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
best_dot = dot_v3v3(projectors[0].normal, face_no);
best_projector = &projectors[0];
- for (j = 1; j < num_projectors; ++j) {
+ for (j = 1; j < num_projectors; j++) {
float tmp_dot = dot_v3v3(projectors[j].normal, face_no);
if (tmp_dot > best_dot) {
best_dot = tmp_dot;
@@ -268,18 +268,18 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
}
if (best_projector->uci) {
- unsigned int fidx = mp->totloop - 1;
+ uint fidx = mp->totloop - 1;
do {
- unsigned int lidx = mp->loopstart + fidx;
- unsigned int vidx = mloop[lidx].v;
+ uint lidx = mp->loopstart + fidx;
+ uint vidx = mloop[lidx].v;
BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], best_projector->uci);
} while (fidx--);
}
else {
- unsigned int fidx = mp->totloop - 1;
+ uint fidx = mp->totloop - 1;
do {
- unsigned int lidx = mp->loopstart + fidx;
- unsigned int vidx = mloop[lidx].v;
+ uint lidx = mp->loopstart + fidx;
+ uint vidx = mloop[lidx].v;
mul_v2_project_m4_v3(mloop_uv[lidx].uv, best_projector->projmat, coords[vidx]);
} while (fidx--);
}
@@ -290,7 +290,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
if (free_uci) {
int j;
- for (j = 0; j < num_projectors; ++j) {
+ for (j = 0; j < num_projectors; j++) {
if (projectors[j].uci) {
MEM_freeN(projectors[j].uci);
}
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c
index 486d5c90bef..4ff07b21ef4 100644
--- a/source/blender/modifiers/intern/MOD_weightvg_util.c
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.c
@@ -76,7 +76,7 @@ void weightvg_do_map(int num, float *new_w, short falloff_type, CurveMapping *cm
}
/* Map each weight (vertex) to its new value, accordingly to the chosen mode. */
- for (i = 0; i < num; ++i) {
+ for (i = 0; i < num; i++) {
float fac = new_w[i];
/* Code borrowed from the warp modifier. */
@@ -164,7 +164,7 @@ void weightvg_do_mask(const ModifierEvalContext *ctx,
MOD_init_texture(&t_map, ctx);
/* For each weight (vertex), make the mix between org and new weights. */
- for (i = 0; i < num; ++i) {
+ for (i = 0; i < num; i++) {
int idx = indices ? indices[i] : i;
TexResult texres;
float hsv[3]; /* For HSV color space. */
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index 95b15b4a924..7e23289433f 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -215,7 +215,7 @@ static void get_vert2ob_distance(
{
/* Vertex and ref object coordinates. */
float v_wco[3];
- unsigned int i = numVerts;
+ uint i = numVerts;
while (i-- > 0) {
/* Get world-coordinates of the vertex (constraints and anim included). */
@@ -241,7 +241,7 @@ static void do_map(
Object *ob, float *weights, const int nidx, const float min_d, const float max_d, short mode)
{
const float range_inv = 1.0f / (max_d - min_d); /* invert since multiplication is faster */
- unsigned int i = nidx;
+ uint i = nidx;
if (max_d == min_d) {
while (i-- > 0) {
weights[i] = (weights[i] >= max_d) ? 1.0f : 0.0f; /* "Step" behavior... */
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index 7af9ef6f5b6..3dd6e00c3a5 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -91,7 +91,7 @@ static Mesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, Mesh *
MAX2(ob->totcol - 1, 0),
false);
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 5cf5e1ac6d3..f618f964b22 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -205,9 +205,10 @@ set(SRC
shader/nodes/node_shader_uvmap.c
shader/nodes/node_shader_valToRgb.c
shader/nodes/node_shader_value.c
- shader/nodes/node_shader_vector_math.c
shader/nodes/node_shader_vectTransform.c
shader/nodes/node_shader_vector_displacement.c
+ shader/nodes/node_shader_vector_math.c
+ shader/nodes/node_shader_vertex_color.c
shader/nodes/node_shader_volume_absorption.c
shader/nodes/node_shader_volume_info.c
shader/nodes/node_shader_volume_principled.c
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index 30673e7cd31..a004090d03d 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -86,6 +86,7 @@ void register_node_type_sh_script(void);
void register_node_type_sh_normal_map(void);
void register_node_type_sh_tangent(void);
void register_node_type_sh_vect_transform(void);
+void register_node_type_sh_vertex_color(void);
void register_node_type_sh_ambient_occlusion(void);
void register_node_type_sh_background(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index d14511504f0..f3bc5a0cafa 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -121,6 +121,7 @@ DefNode(ShaderNode, SH_NODE_VECT_TRANSFORM, def_sh_vect_transform, "VEC
DefNode(ShaderNode, SH_NODE_SEPHSV, 0, "SEPHSV", SeparateHSV, "Separate HSV", "" )
DefNode(ShaderNode, SH_NODE_COMBHSV, 0, "COMBHSV", CombineHSV, "Combine HSV", "" )
DefNode(ShaderNode, SH_NODE_UVMAP, def_sh_uvmap, "UVMAP", UVMap, "UV Map", "" )
+DefNode(ShaderNode, SH_NODE_VERTEX_COLOR, def_sh_vertex_color, "VERTEX_COLOR", VertexColor, "Vertex Color", "" )
DefNode(ShaderNode, SH_NODE_UVALONGSTROKE, def_sh_uvalongstroke, "UVALONGSTROKE", UVAlongStroke, "UV Along Stroke", "" )
DefNode(ShaderNode, SH_NODE_SEPXYZ, 0, "SEPXYZ", SeparateXYZ, "Separate XYZ", "" )
DefNode(ShaderNode, SH_NODE_COMBXYZ, 0, "COMBXYZ", CombineXYZ, "Combine XYZ", "" )
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorbalance.c b/source/blender/nodes/composite/nodes/node_composite_colorbalance.c
index db0689df775..27cf050c658 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorbalance.c
+++ b/source/blender/nodes/composite/nodes/node_composite_colorbalance.c
@@ -46,7 +46,7 @@ void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *UNUSED(ntree), bNode *node)
NodeColorBalance *n = node->storage;
int c;
- for (c = 0; c < 3; ++c) {
+ for (c = 0; c < 3; c++) {
n->slope[c] = (2.0f - n->lift[c]) * n->gain[c];
n->offset[c] = (n->lift[c] - 1.0f) * n->gain[c];
n->power[c] = (n->gamma[c] != 0.0f) ? 1.0f / n->gamma[c] : 1000000.0f;
@@ -58,7 +58,7 @@ void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *UNUSED(ntree), bNode *node)
NodeColorBalance *n = node->storage;
int c;
- for (c = 0; c < 3; ++c) {
+ for (c = 0; c < 3; c++) {
float d = n->slope[c] + n->offset[c];
n->lift[c] = (d != 0.0f ? n->slope[c] + 2.0f * n->offset[c] / d : 0.0f);
n->gain[c] = d;
diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c
index dcd8589cfdd..cbae2c412ea 100644
--- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c
+++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c
@@ -60,7 +60,7 @@ static void cryptomatte_add(NodeCryptomatte *n, float f)
while (start < end) {
/* Ignore leading whitespace. */
while (start < end && n->matte_id[start] == ' ') {
- ++start;
+ start++;
}
/* Find the next separator. */
@@ -139,7 +139,7 @@ static void cryptomatte_remove(NodeCryptomatte *n, float f)
bool skip = false;
/* Ignore leading whitespace or commas. */
while (start < end && ((n->matte_id[start] == ' ') || (n->matte_id[start] == ','))) {
- ++start;
+ start++;
}
/* Find the next separator. */
diff --git a/source/blender/nodes/composite/nodes/node_composite_denoise.c b/source/blender/nodes/composite/nodes/node_composite_denoise.c
index e2fdb08816a..bb62869f470 100644
--- a/source/blender/nodes/composite/nodes/node_composite_denoise.c
+++ b/source/blender/nodes/composite/nodes/node_composite_denoise.c
@@ -33,8 +33,8 @@
static bNodeSocketTemplate cmp_node_denoise_in[] = {
{SOCK_RGBA, 1, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_RGBA, 1, N_("Albedo"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
{SOCK_VECTOR, 0, N_("Normal"), 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f},
+ {SOCK_RGBA, 1, N_("Albedo"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
{-1, 0, ""}};
static bNodeSocketTemplate cmp_node_denoise_out[] = {{SOCK_RGBA, 0, N_("Image")}, {-1, 0, ""}};
diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c
index 24376e39f3d..85c408c40bb 100644
--- a/source/blender/nodes/intern/node_exec.c
+++ b/source/blender/nodes/intern/node_exec.c
@@ -183,7 +183,7 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context,
/* set stack indices */
index = 0;
- for (n = 0; n < totnodes; ++n) {
+ for (n = 0; n < totnodes; n++) {
node = nodelist[n];
node->stack_index = index;
@@ -213,12 +213,12 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context,
exec->stack = MEM_callocN(exec->stacksize * sizeof(bNodeStack), "bNodeStack");
/* all non-const results are considered inputs */
- for (n = 0; n < exec->stacksize; ++n) {
+ for (n = 0; n < exec->stacksize; n++) {
exec->stack[n].hasinput = 1;
}
/* prepare all nodes for execution */
- for (n = 0, nodeexec = exec->nodeexec; n < totnodes; ++n, ++nodeexec) {
+ for (n = 0, nodeexec = exec->nodeexec; n < totnodes; n++, nodeexec++) {
node = nodeexec->node = nodelist[n];
nodeexec->freeexecfunc = node->typeinfo->freeexecfunc;
@@ -265,7 +265,7 @@ void ntree_exec_end(bNodeTreeExec *exec)
MEM_freeN(exec->stack);
}
- for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
+ for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; n++, nodeexec++) {
if (nodeexec->freeexecfunc) {
nodeexec->freeexecfunc(nodeexec->data.data);
}
@@ -317,7 +317,7 @@ bool ntreeExecThreadNodes(bNodeTreeExec *exec, bNodeThreadStack *nts, void *call
/* nodes are presorted, so exec is in order of list */
- for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
+ for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; n++, nodeexec++) {
node = nodeexec->node;
if (node->need_exec) {
node_get_stack(node, nts->stack, nsin, nsout);
diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c
index 0d7f19fb67a..455da4b3881 100644
--- a/source/blender/nodes/intern/node_util.c
+++ b/source/blender/nodes/intern/node_util.c
@@ -130,7 +130,7 @@ static bool node_link_socket_match(bNodeSocket *a, bNodeSocket *b)
*/
int prefix_len = 0;
char *ca = a->name, *cb = b->name;
- for (; *ca != '\0' && *cb != '\0'; ++ca, ++cb) {
+ for (; *ca != '\0' && *cb != '\0'; ca++, cb++) {
/* end of common prefix? */
if (*ca != *cb) {
/* prefix delimited by non-alphabetic char */
@@ -139,7 +139,7 @@ static bool node_link_socket_match(bNodeSocket *a, bNodeSocket *b)
}
break;
}
- ++prefix_len;
+ prefix_len++;
}
return prefix_len > 0;
}
@@ -150,10 +150,10 @@ static int node_count_links(bNodeTree *ntree, bNodeSocket *sock)
int count = 0;
for (link = ntree->links.first; link; link = link->next) {
if (link->fromsock == sock) {
- ++count;
+ count++;
}
if (link->tosock == sock) {
- ++count;
+ count++;
}
}
return count;
@@ -321,7 +321,7 @@ static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output)
int sel_priority = -1;
bool sel_is_linked = false;
- for (input = node->inputs.first, i = 0; input; input = input->next, ++i) {
+ for (input = node->inputs.first, i = 0; input; input = input->next, i++) {
int priority = node_datatype_priority(input->type, output->type);
bool is_linked = (input->link != NULL);
bool preferred;
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index 60a6cc91630..92266600612 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -32,6 +32,7 @@
#include "DNA_linestyle_types.h"
#include "DNA_workspace_types.h"
+#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -212,115 +213,6 @@ void register_node_tree_type_sh(void)
/* GPU material from shader nodes */
-static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
- bNode *node_from,
- bNodeSocket *socket_from,
- bNode *displacement_node,
- bNodeSocket *displacement_socket);
-
-static bNodeSocket *ntree_shader_node_find_input(bNode *node, const char *identifier);
-
-static bNode *ntree_group_output_node(bNodeTree *ntree);
-
-static bNode *ntree_shader_relink_output_from_group(bNodeTree *ntree,
- bNode *group_node,
- bNode *sh_output_node,
- int target)
-{
- int i;
- bNodeTree *group_ntree = (bNodeTree *)group_node->id;
-
- int sock_len = BLI_listbase_count(&sh_output_node->inputs);
- bNodeSocket **group_surface_sockets = BLI_array_alloca(group_surface_sockets, sock_len);
-
- /* Create output sockets to plug output connection to. */
- i = 0;
- for (bNodeSocket *sock = sh_output_node->inputs.first; sock; sock = sock->next, ++i) {
- group_surface_sockets[i] = ntreeAddSocketInterface(
- group_ntree, SOCK_OUT, sock->typeinfo->idname, sock->name);
- }
-
- bNode *group_output_node = ntree_group_output_node(group_ntree);
-
- /* If no group output node is present, we need to create one. */
- if (group_output_node == NULL) {
- group_output_node = nodeAddStaticNode(NULL, group_ntree, NODE_GROUP_OUTPUT);
- }
-
- /* Need to update tree so all node instances nodes gets proper sockets. */
- node_group_update(ntree, group_node);
- node_group_output_update(group_ntree, group_output_node);
- ntreeUpdateTree(G.main, group_ntree);
-
- /* Remove other shader output nodes so that only the new one can be selected as active. */
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
- if (ELEM(node->type, SH_NODE_OUTPUT_MATERIAL, SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LIGHT)) {
- ntreeFreeLocalNode(ntree, node);
- }
- }
-
- /* Create new shader output node outside the group. */
- bNode *new_output_node = nodeAddStaticNode(NULL, ntree, sh_output_node->type);
- new_output_node->custom1 = target;
-
- i = 0;
- for (bNodeSocket *sock = sh_output_node->inputs.first; sock; sock = sock->next, ++i) {
- if (sock->link != NULL) {
- /* Link the shader output node incoming link to the group output sockets */
- bNodeSocket *group_output_node_surface_input_sock = nodeFindSocket(
- group_output_node, SOCK_IN, group_surface_sockets[i]->identifier);
- nodeAddLink(group_ntree,
- sock->link->fromnode,
- sock->link->fromsock,
- group_output_node,
- group_output_node_surface_input_sock);
-
- /* Link the group output sockets to the new shader output node. */
- bNodeSocket *group_node_surface_output = nodeFindSocket(
- group_node, SOCK_OUT, group_surface_sockets[i]->identifier);
- bNodeSocket *output_node_surface_input = ntree_shader_node_find_input(new_output_node,
- sock->name);
-
- nodeAddLink(ntree,
- group_node,
- group_node_surface_output,
- new_output_node,
- output_node_surface_input);
- }
- }
-
- ntreeUpdateTree(G.main, group_ntree);
- ntreeUpdateTree(G.main, ntree);
-
- return new_output_node;
-}
-
-static bNode *ntree_shader_output_node_from_group(bNodeTree *ntree, int target)
-{
- bNode *output_node = NULL;
-
- /* Search if node groups do not contain valid output nodes (recursively). */
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
- if (!ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
- continue;
- }
- if (node->id != NULL) {
- output_node = ntree_shader_output_node_from_group((bNodeTree *)node->id, target);
-
- if (output_node == NULL) {
- output_node = ntreeShaderOutputNode((bNodeTree *)node->id, target);
- }
-
- if (output_node != NULL) {
- /* Output is inside this group node. Create relink to make the output outside the group. */
- output_node = ntree_shader_relink_output_from_group(ntree, node, output_node, target);
- break;
- }
- }
- }
- return output_node;
-}
-
/* Find an output node of the shader tree.
*
* NOTE: it will only return output which is NOT in the group, which isn't how
@@ -368,28 +260,6 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target)
return output_node;
}
-/* Find the active output node of a group nodetree.
- *
- * Does not return the shading output node but the group output node.
- */
-static bNode *ntree_group_output_node(bNodeTree *ntree)
-{
- /* Make sure we only have single node tagged as output. */
- ntreeSetOutput(ntree);
-
- /* Find output node that matches type and target. If there are
- * multiple, we prefer exact target match and active nodes. */
- bNode *output_node = NULL;
-
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
- if ((node->type == NODE_GROUP_OUTPUT) && (node->flag & NODE_DO_OUTPUT)) {
- output_node = node;
- }
- }
-
- return output_node;
-}
-
/* Find socket with a specified identifier. */
static bNodeSocket *ntree_shader_node_find_socket(ListBase *sockets, const char *identifier)
{
@@ -520,6 +390,106 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree)
}
}
+static void flatten_group_do(bNodeTree *ntree, bNode *gnode)
+{
+ bNodeLink *link, *linkn, *tlink;
+ bNode *node, *nextnode;
+ bNodeTree *ngroup;
+ LinkNode *group_interface_nodes = NULL;
+
+ ngroup = (bNodeTree *)gnode->id;
+
+ /* Add the nodes into the ntree */
+ for (node = ngroup->nodes.first; node; node = nextnode) {
+ nextnode = node->next;
+ /* Remove interface nodes.
+ * This also removes remaining links to and from interface nodes.
+ * We must delay removal since sockets will reference this node. see: T52092 */
+ if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
+ BLI_linklist_prepend(&group_interface_nodes, node);
+ }
+ /* migrate node */
+ BLI_remlink(&ngroup->nodes, node);
+ BLI_addtail(&ntree->nodes, node);
+ /* ensure unique node name in the node tree */
+ nodeUniqueName(ntree, node);
+ }
+
+ /* Save first and last link to iterate over flattened group links. */
+ bNodeLink *glinks_first = ntree->links.last;
+
+ /* Add internal links to the ntree */
+ for (link = ngroup->links.first; link; link = linkn) {
+ linkn = link->next;
+ BLI_remlink(&ngroup->links, link);
+ BLI_addtail(&ntree->links, link);
+ }
+
+ bNodeLink *glinks_last = ntree->links.last;
+
+ /* restore external links to and from the gnode */
+ if (glinks_first != NULL) {
+ /* input links */
+ for (link = glinks_first->next; link != glinks_last->next; link = link->next) {
+ if (link->fromnode->type == NODE_GROUP_INPUT) {
+ const char *identifier = link->fromsock->identifier;
+ /* find external links to this input */
+ for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) {
+ if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) {
+ nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode, link->tosock);
+ }
+ }
+ }
+ }
+ /* output links */
+ for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) {
+ if (tlink->fromnode == gnode) {
+ const char *identifier = tlink->fromsock->identifier;
+ /* find internal links to this output */
+ for (link = glinks_first->next; link != glinks_last->next; link = link->next) {
+ /* only use active output node */
+ if (link->tonode->type == NODE_GROUP_OUTPUT && (link->tonode->flag & NODE_DO_OUTPUT)) {
+ if (STREQ(link->tosock->identifier, identifier)) {
+ nodeAddLink(ntree, link->fromnode, link->fromsock, tlink->tonode, tlink->tosock);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ while (group_interface_nodes) {
+ node = BLI_linklist_pop(&group_interface_nodes);
+ ntreeFreeLocalNode(ntree, node);
+ }
+
+ ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+}
+
+/* Flatten group to only have a simple single tree */
+static void ntree_shader_groups_flatten(bNodeTree *localtree)
+{
+ /* This is effectively recursive as the flattened groups will add
+ * nodes at the end of the list, which will also get evaluated. */
+ for (bNode *node = localtree->nodes.first, *node_next; node; node = node_next) {
+ if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id != NULL) {
+ flatten_group_do(localtree, node);
+ /* Continue even on new flattened nodes. */
+ node_next = node->next;
+ /* delete the group instance and its localtree. */
+ bNodeTree *ngroup = (bNodeTree *)node->id;
+ ntreeFreeLocalNode(localtree, node);
+ ntreeFreeTree(ngroup);
+ MEM_freeN(ngroup);
+ }
+ else {
+ node_next = node->next;
+ }
+ }
+
+ ntreeUpdateTree(G.main, localtree);
+}
+
/* Check whether shader has a displacement.
*
* Will also return a node and it's socket which is connected to a displacement
@@ -576,53 +546,10 @@ static void ntree_shader_relink_node_normal(bNodeTree *ntree,
}
}
-static void ntree_shader_link_builtin_group_normal(bNodeTree *ntree,
- bNode *group_node,
- bNode *node_from,
- bNodeSocket *socket_from,
- bNode *displacement_node,
- bNodeSocket *displacement_socket)
-{
- bNodeTree *group_ntree = (bNodeTree *)group_node->id;
- /* Create input socket to plug displacement connection to. */
- bNodeSocket *group_normal_socket = ntreeAddSocketInterface(
- group_ntree, SOCK_IN, "NodeSocketVector", "Normal");
- /* Need to update tree so all node instances nodes gets proper sockets. */
- bNode *group_input_node = ntreeFindType(group_ntree, NODE_GROUP_INPUT);
- node_group_update(ntree, group_node);
- if (group_input_node) {
- node_group_input_update(group_ntree, group_input_node);
- }
- ntreeUpdateTree(G.main, group_ntree);
- /* Assumes sockets are always added at the end. */
- bNodeSocket *group_node_normal_socket = group_node->inputs.last;
- if (displacement_node == group_node) {
- /* This should never happen as all displacement nodes are duplicated and tagged. */
- BLI_assert(0);
- }
- else if (group_input_node) {
- /* Connect group node normal input. */
- nodeAddLink(ntree, node_from, socket_from, group_node, group_node_normal_socket);
- BLI_assert(group_input_node != NULL);
- bNodeSocket *group_input_node_normal_socket = nodeFindSocket(
- group_input_node, SOCK_OUT, group_normal_socket->identifier);
- BLI_assert(group_input_node_normal_socket != NULL);
- /* Relink normals inside of the instanced tree. */
- ntree_shader_link_builtin_normal(group_ntree,
- group_input_node,
- group_input_node_normal_socket,
- displacement_node,
- displacement_socket);
- ntreeUpdateTree(G.main, group_ntree);
- }
-}
-
/* Use specified node and socket as an input for unconnected normal sockets. */
static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
bNode *node_from,
- bNodeSocket *socket_from,
- bNode *displacement_node,
- bNodeSocket *displacement_socket)
+ bNodeSocket *socket_from)
{
for (bNode *node = ntree->nodes.first; node != NULL; node = node->next) {
if (node == node_from) {
@@ -633,16 +560,6 @@ static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
/* This node is used inside the displacement tree. Skip to avoid cycles. */
continue;
}
- if ((ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) && node->id) {
- /* Special re-linking for group nodes. */
- ntree_shader_link_builtin_group_normal(
- ntree, node, node_from, socket_from, displacement_node, displacement_socket);
- continue;
- }
- if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
- /* Group inputs and outputs needs nothing special. */
- continue;
- }
ntree_shader_relink_node_normal(ntree, node, node_from, socket_from);
}
}
@@ -670,36 +587,17 @@ static void ntree_shader_bypass_bump_link(bNodeTree *ntree, bNode *bump_node, bN
static void ntree_shader_bypass_tagged_bump_nodes(bNodeTree *ntree)
{
/* Bypass bump links inside copied nodes */
- bNodeLink *link, *link_next;
- for (link = ntree->links.first; link; link = link_next) {
- /* link might be freed by ntree_shader_bypass_bump_link. */
- link_next = link->next;
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
bNode *node = link->fromnode;
/* If node is a copy. */
if (node->tmp_flag == -2 && node->type == SH_NODE_BUMP) {
ntree_shader_bypass_bump_link(ntree, node, link);
}
}
- /* Do the same inside nodegroups. */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- /* If node is a copy. */
- if (node->tmp_flag == -2 && ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) {
- bNodeTree *group_ntree = (bNodeTree *)node->id;
- /* Tag all nodes inside this group as copies. */
- LISTBASE_FOREACH (bNode *, group_node, &group_ntree->nodes) {
- group_node->tmp_flag = -2;
- }
- /* Recursive. */
- ntree_shader_bypass_tagged_bump_nodes(group_ntree);
- }
- }
ntreeUpdateTree(G.main, ntree);
}
-static bool ntree_branch_count_and_tag_nodes(bNode *fromnode,
- bNode *tonode,
- void *userdata,
- const bool UNUSED(reversed))
+static bool ntree_branch_count_and_tag_nodes(bNode *fromnode, bNode *tonode, void *userdata)
{
int *node_count = (int *)userdata;
if (fromnode->tmp_flag == -1) {
@@ -713,19 +611,22 @@ static bool ntree_branch_count_and_tag_nodes(bNode *fromnode,
return true;
}
-static void ntree_shader_copy_branch_displacement(bNodeTree *ntree,
- bNode *displacement_node,
- bNodeSocket *displacement_socket,
- bNodeLink *displacement_link)
+/* Create a copy of a branch starting from a given node.
+ * callback is executed once for every copied node.
+ * Returns input node copy. */
+static bNode *ntree_shader_copy_branch(bNodeTree *ntree,
+ bNode *start_node,
+ void (*callback)(bNode *node, int user_data),
+ int user_data)
{
/* Init tmp flag. */
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
node->tmp_flag = -1;
}
/* Count and tag all nodes inside the displacement branch of the tree. */
- displacement_node->tmp_flag = 0;
+ start_node->tmp_flag = 0;
int node_count = 1;
- nodeChainIter(ntree, displacement_node, ntree_branch_count_and_tag_nodes, &node_count, true);
+ nodeChainIterBackwards(ntree, start_node, ntree_branch_count_and_tag_nodes, &node_count);
/* Make a full copy of the branch */
bNode **nodes_copy = MEM_mallocN(sizeof(bNode *) * node_count, __func__);
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
@@ -733,9 +634,6 @@ static void ntree_shader_copy_branch_displacement(bNodeTree *ntree,
int id = node->tmp_flag;
nodes_copy[id] = BKE_node_copy_ex(ntree, node, LIB_ID_CREATE_NO_USER_REFCOUNT);
nodes_copy[id]->tmp_flag = -2; /* Copy */
- if (ELEM(nodes_copy[id]->type, NODE_GROUP, NODE_CUSTOM_GROUP) && nodes_copy[id]->id) {
- nodes_copy[id]->id = (ID *)ntreeLocalize((bNodeTree *)nodes_copy[id]->id);
- }
/* Make sure to clear all sockets links as they are invalid. */
LISTBASE_FOREACH (bNodeSocket *, sock, &nodes_copy[id]->inputs) {
sock->link = NULL;
@@ -755,15 +653,30 @@ static void ntree_shader_copy_branch_displacement(bNodeTree *ntree,
nodeAddLink(ntree, fromnode, fromsock, tonode, tosock);
}
}
+ /* Per node callback. */
+ if (callback) {
+ for (int i = 0; i < node_count; i++) {
+ callback(nodes_copy[i], user_data);
+ }
+ }
+ bNode *start_node_copy = nodes_copy[start_node->tmp_flag];
+ MEM_freeN(nodes_copy);
+ return start_node_copy;
+}
+
+static void ntree_shader_copy_branch_displacement(bNodeTree *ntree,
+ bNode *displacement_node,
+ bNodeSocket *displacement_socket,
+ bNodeLink *displacement_link)
+{
/* Replace displacement socket/node/link. */
bNode *tonode = displacement_link->tonode;
bNodeSocket *tosock = displacement_link->tosock;
- displacement_node = nodes_copy[displacement_node->tmp_flag];
+ displacement_node = ntree_shader_copy_branch(ntree, displacement_node, NULL, 0);
displacement_socket = ntree_shader_node_find_output(displacement_node,
displacement_socket->identifier);
nodeRemLink(ntree, displacement_link);
nodeAddLink(ntree, displacement_node, displacement_socket, tonode, tosock);
- MEM_freeN(nodes_copy);
ntreeUpdateTree(G.main, ntree);
}
@@ -802,10 +715,12 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod
bNode *dot_node = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
bNode *geo_node = nodeAddStaticNode(NULL, ntree, SH_NODE_NEW_GEOMETRY);
bNodeSocket *normal_socket = ntree_shader_node_find_output(geo_node, "Normal");
- dot_node->custom1 = 3; /* dot product */
+ bNodeSocket *dot_input1 = dot_node->inputs.first;
+ bNodeSocket *dot_input2 = dot_input1->next;
+ dot_node->custom1 = NODE_VECTOR_MATH_DOT_PRODUCT;
- nodeAddLink(ntree, displacement_node, displacement_socket, dot_node, dot_node->inputs.first);
- nodeAddLink(ntree, geo_node, normal_socket, dot_node, dot_node->inputs.last);
+ nodeAddLink(ntree, displacement_node, displacement_socket, dot_node, dot_input1);
+ nodeAddLink(ntree, geo_node, normal_socket, dot_node, dot_input2);
displacement_node = dot_node;
displacement_socket = ntree_shader_node_find_output(dot_node, "Value");
@@ -830,33 +745,52 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod
ntreeUpdateTree(G.main, ntree);
/* Connect all free-standing Normal inputs and relink geometry/coordinate nodes. */
- ntree_shader_link_builtin_normal(
- ntree, bump_node, bump_output_socket, displacement_node, displacement_socket);
+ ntree_shader_link_builtin_normal(ntree, bump_node, bump_output_socket);
/* We modified the tree, it needs to be updated now. */
ntreeUpdateTree(G.main, ntree);
}
-static bool ntree_tag_bsdf_cb(bNode *fromnode,
- bNode *UNUSED(tonode),
- void *userdata,
- const bool UNUSED(reversed))
+static void node_tag_branch_as_derivative(bNode *node, int dx)
{
- /* Don't evaluate nodes more than once. */
- if (fromnode->tmp_flag) {
- return true;
+ if (dx) {
+ node->branch_tag = 1;
+ }
+ else {
+ node->branch_tag = 2;
}
- fromnode->tmp_flag = 1;
+}
+
+static bool ntree_shader_bump_branches(bNode *UNUSED(fromnode), bNode *tonode, void *userdata)
+{
+ bNodeTree *ntree = (bNodeTree *)userdata;
+ if (tonode->type == SH_NODE_BUMP) {
+ bNodeSocket *height_dx_sock, *height_dy_sock, *bump_socket, *bump_dx_socket, *bump_dy_socket;
+ bNode *bump = tonode;
+ bump_socket = ntree_shader_node_find_input(bump, "Height");
+ bump_dx_socket = ntree_shader_node_find_input(bump, "Height_dx");
+ bump_dy_socket = ntree_shader_node_find_input(bump, "Height_dy");
+ if (bump_dx_socket->link) {
+ /* Avoid reconnecting the same bump twice. */
+ }
+ else if (bump_socket && bump_socket->link) {
+ bNodeLink *link = bump_socket->link;
+ bNode *height = link->fromnode;
+ bNode *height_dx = ntree_shader_copy_branch(ntree, height, node_tag_branch_as_derivative, 1);
+ bNode *height_dy = ntree_shader_copy_branch(ntree, height, node_tag_branch_as_derivative, 0);
+ height_dx_sock = ntree_shader_node_find_output(height_dx, link->fromsock->identifier);
+ height_dy_sock = ntree_shader_node_find_output(height_dy, link->fromsock->identifier);
+ nodeAddLink(ntree, height_dx, height_dx_sock, bump, bump_dx_socket);
+ nodeAddLink(ntree, height_dy, height_dy_sock, bump, bump_dy_socket);
+ /* We could end iter here, but other bump node could be plugged into other input sockets. */
+ }
+ }
+ return true;
+}
+
+static bool ntree_tag_bsdf_cb(bNode *fromnode, bNode *UNUSED(tonode), void *userdata)
+{
switch (fromnode->type) {
- case NODE_GROUP:
- case NODE_CUSTOM_GROUP:
- /* Recursive */
- if (fromnode->id != NULL) {
- bNodeTree *ntree = (bNodeTree *)fromnode->id;
- bNode *group_output = ntree_group_output_node(ntree);
- ntree_shader_tag_nodes(ntree, group_output, (nTreeTags *)userdata);
- }
- break;
case SH_NODE_BSDF_ANISOTROPIC:
case SH_NODE_EEVEE_SPECULAR:
case SH_NODE_BSDF_GLOSSY:
@@ -895,12 +829,7 @@ void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tag
/* Make sure sockets links pointers are correct. */
ntreeUpdateTree(G.main, ntree);
- /* Reset visit flag. */
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
- node->tmp_flag = 0;
- }
-
- nodeChainIter(ntree, output_node, ntree_tag_bsdf_cb, tags, true);
+ nodeChainIterBackwards(ntree, output_node, ntree_tag_bsdf_cb, tags);
}
/* This one needs to work on a local tree. */
@@ -911,18 +840,26 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree,
{
bNodeTreeExec *exec;
- /* Extract output nodes from inside nodegroups. */
- ntree_shader_output_node_from_group(localtree, SHD_OUTPUT_EEVEE);
-
bNode *output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE);
ntree_shader_groups_expand_inputs(localtree);
+ ntree_shader_groups_flatten(localtree);
+
+ if (output == NULL) {
+ /* Search again, now including flattened nodes. */
+ output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE);
+ }
+
/* Perform all needed modifications on the tree in order to support
* displacement/bump mapping.
*/
ntree_shader_relink_displacement(localtree, output);
+ /* Duplicate bump height branches for manual derivatives.
+ */
+ nodeChainIterBackwards(localtree, output, ntree_shader_bump_branches, localtree);
+
/* TODO(fclem): consider moving this to the gpu shader tree evaluation. */
nTreeTags tags = {
.ssr_id = 1.0,
diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c
index 2e8f81979a8..9615c6f01e0 100644
--- a/source/blender/nodes/shader/node_shader_util.c
+++ b/source/blender/nodes/shader/node_shader_util.c
@@ -231,7 +231,7 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node
stack = exec->stack;
- for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
+ for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; n++, nodeexec++) {
node = nodeexec->node;
do_it = false;
@@ -258,6 +258,30 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node
}
}
+void node_shader_gpu_bump_tex_coord(GPUMaterial *mat, bNode *node, GPUNodeLink **link)
+{
+ if (node->branch_tag == 1) {
+ /* Add one time the value fo derivative to the input vector. */
+ GPU_link(mat, "dfdx_v3", *link, link);
+ }
+ else if (node->branch_tag == 2) {
+ /* Add one time the value fo derivative to the input vector. */
+ GPU_link(mat, "dfdy_v3", *link, link);
+ }
+ else {
+ /* nothing to do, reference center value. */
+ }
+}
+
+void node_shader_gpu_default_tex_coord(GPUMaterial *mat, bNode *node, GPUNodeLink **link)
+{
+ if (!*link) {
+ *link = GPU_attribute(CD_ORCO, "");
+ GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), *link, link);
+ node_shader_gpu_bump_tex_coord(mat, node, link);
+ }
+}
+
void node_shader_gpu_tex_mapping(GPUMaterial *mat,
bNode *node,
GPUNodeStack *in,
@@ -280,10 +304,10 @@ void node_shader_gpu_tex_mapping(GPUMaterial *mat,
tmat2 = GPU_uniform((float *)texmap->mat[2]);
tmat3 = GPU_uniform((float *)texmap->mat[3]);
- GPU_link(mat, "mapping", in[0].link, tmat0, tmat1, tmat2, tmat3, tmin, tmax, &in[0].link);
+ GPU_link(mat, "mapping_mat4", in[0].link, tmat0, tmat1, tmat2, tmat3, tmin, tmax, &in[0].link);
if (texmap->type == TEXMAP_TYPE_NORMAL) {
- GPU_link(mat, "texco_norm", in[0].link, &in[0].link);
+ GPU_link(mat, "vector_normalize", in[0].link, &in[0].link);
}
}
}
diff --git a/source/blender/nodes/shader/node_shader_util.h b/source/blender/nodes/shader/node_shader_util.h
index a3c553b983b..9719d0b36f5 100644
--- a/source/blender/nodes/shader/node_shader_util.h
+++ b/source/blender/nodes/shader/node_shader_util.h
@@ -84,6 +84,12 @@ void nodestack_get_vec(float *in, short type_in, bNodeStack *ns);
void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, struct bNodeStack *ns);
void node_data_from_gpu_stack(struct bNodeStack *ns, struct GPUNodeStack *gs);
+void node_shader_gpu_bump_tex_coord(struct GPUMaterial *mat,
+ struct bNode *node,
+ struct GPUNodeLink **link);
+void node_shader_gpu_default_tex_coord(struct GPUMaterial *mat,
+ struct bNode *node,
+ struct GPUNodeLink **link);
void node_shader_gpu_tex_mapping(struct GPUMaterial *mat,
struct bNode *node,
struct GPUNodeStack *in,
diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.c b/source/blender/nodes/shader/nodes/node_shader_attribute.c
index c92ae28f2e6..ecb8c53c312 100644
--- a/source/blender/nodes/shader/nodes/node_shader_attribute.c
+++ b/source/blender/nodes/shader/nodes/node_shader_attribute.c
@@ -67,7 +67,14 @@ static int node_shader_gpu_attribute(GPUMaterial *mat,
}
else {
GPUNodeLink *cd_attr = GPU_attribute(CD_AUTO_FROM_NAME, attr->name);
- return GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr);
+ GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr);
+
+ /* for each output. */
+ for (int i = 0; sh_node_attribute_out[i].type != -1; i++) {
+ node_shader_gpu_bump_tex_coord(mat, node, &out[i].link);
+ }
+
+ return 1;
}
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
index 595ddf27d0a..3340054396d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
@@ -120,6 +120,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
GPU_link(mat, "world_normals_get", &in[20].link);
}
+#if 0 /* Not used at the moment. */
/* Tangents */
if (!in[21].link) {
GPUNodeLink *orco = GPU_attribute(CD_ORCO, "");
@@ -131,6 +132,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
GPU_builtin(GPU_OBJECT_MATRIX),
&in[21].link);
}
+#endif
bool use_diffuse = socket_not_one(4) && socket_not_one(15);
bool use_subsurf = socket_not_zero(1) && use_diffuse && node->sss_id > 0;
diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.c
index d17edae35df..384701d2ddf 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bump.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bump.c
@@ -24,32 +24,17 @@
#include "node_shader_util.h"
/* **************** BUMP ******************** */
+/* clang-format off */
static bNodeSocketTemplate sh_node_bump_in[] = {
{SOCK_FLOAT, 1, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{SOCK_FLOAT, 1, N_("Distance"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_FLOAT,
- 1,
- N_("Height"),
- 1.0f,
- 1.0f,
- 1.0f,
- 1.0f,
- -1000.0f,
- 1000.0f,
- PROP_NONE,
- SOCK_HIDE_VALUE},
- {SOCK_VECTOR,
- 1,
- N_("Normal"),
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- -1.0f,
- 1.0f,
- PROP_NONE,
- SOCK_HIDE_VALUE},
- {-1, 0, ""}};
+ {SOCK_FLOAT, 1, N_("Height"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ {SOCK_FLOAT, 1, N_("Height_dx"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_UNAVAIL},
+ {SOCK_FLOAT, 1, N_("Height_dy"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_UNAVAIL},
+ {SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ {-1, 0, ""}
+};
+/* clang-format on */
static bNodeSocketTemplate sh_node_bump_out[] = {{SOCK_VECTOR, 0, "Normal"}, {-1, 0, ""}};
@@ -59,8 +44,8 @@ static int gpu_shader_bump(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- if (!in[3].link) {
- GPU_link(mat, "world_normals_get", &in[3].link);
+ if (!in[5].link) {
+ GPU_link(mat, "world_normals_get", &in[5].link);
}
float invert = (node->custom1) ? -1.0 : 1.0;
diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.c
index 10f6aadbc5f..257caabcabf 100644
--- a/source/blender/nodes/shader/nodes/node_shader_common.c
+++ b/source/blender/nodes/shader/nodes/node_shader_common.c
@@ -98,7 +98,7 @@ static void group_copy_inputs(bNode *gnode, bNodeStack **in, bNodeStack *gstack)
for (node = ngroup->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP_INPUT) {
- for (sock = node->outputs.first, a = 0; sock; sock = sock->next, ++a) {
+ for (sock = node->outputs.first, a = 0; sock; sock = sock->next, a++) {
ns = node_get_socket_stack(gstack, sock);
if (ns) {
copy_stack(ns, in[a]);
@@ -120,7 +120,7 @@ static void group_move_outputs(bNode *gnode, bNodeStack **out, bNodeStack *gstac
for (node = ngroup->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) {
- for (sock = node->inputs.first, a = 0; sock; sock = sock->next, ++a) {
+ for (sock = node->inputs.first, a = 0; sock; sock = sock->next, a++) {
ns = node_get_socket_stack(gstack, sock);
if (ns) {
move_stack(out[a], ns);
@@ -174,7 +174,7 @@ static void group_gpu_copy_inputs(bNode *gnode, GPUNodeStack *in, bNodeStack *gs
for (node = ngroup->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP_INPUT) {
- for (sock = node->outputs.first, a = 0; sock; sock = sock->next, ++a) {
+ for (sock = node->outputs.first, a = 0; sock; sock = sock->next, a++) {
ns = node_get_socket_stack(gstack, sock);
if (ns) {
/* convert the external gpu stack back to internal node stack data */
@@ -197,7 +197,7 @@ static void group_gpu_move_outputs(bNode *gnode, GPUNodeStack *out, bNodeStack *
for (node = ngroup->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) {
- for (sock = node->inputs.first, a = 0; sock; sock = sock->next, ++a) {
+ for (sock = node->inputs.first, a = 0; sock; sock = sock->next, a++) {
ns = node_get_socket_stack(gstack, sock);
if (ns) {
/* convert the node stack data result back to gpu stack */
diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.c b/source/blender/nodes/shader/nodes/node_shader_curves.c
index baf86951fe0..f5c89e6ba41 100644
--- a/source/blender/nodes/shader/nodes/node_shader_curves.c
+++ b/source/blender/nodes/shader/nodes/node_shader_curves.c
@@ -141,7 +141,7 @@ static int gpu_shader_curve_rgb(GPUMaterial *mat,
float ext_rgba[4][4];
float range_rgba[4];
- for (int a = 0; a < CM_TOT; ++a) {
+ for (int a = 0; a < CM_TOT; a++) {
const CurveMap *cm = &cumap->cm[a];
ext_rgba[a][0] = cm->mintable;
ext_rgba[a][2] = cm->maxtable;
diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.c b/source/blender/nodes/shader/nodes/node_shader_geometry.c
index df9a8ac8318..d94141c3699 100644
--- a/source/blender/nodes/shader/nodes/node_shader_geometry.c
+++ b/source/blender/nodes/shader/nodes/node_shader_geometry.c
@@ -41,9 +41,11 @@ static int node_shader_gpu_geometry(GPUMaterial *mat,
{
/* HACK: Don't request GPU_BARYCENTRIC_TEXCO if not used because it will
* trigger the use of geometry shader (and the performance penalty it implies). */
- float val[2] = {0.0f, 0.0f};
+ float val[4] = {0.0f, 0.0f, 0.0f, 0.0f};
GPUNodeLink *bary_link = (!out[5].hasoutput) ? GPU_constant(val) :
GPU_builtin(GPU_BARYCENTRIC_TEXCO);
+ /* Opti: don't request orco if not needed. */
+ GPUNodeLink *orco_link = (!out[2].hasoutput) ? GPU_constant(val) : GPU_attribute(CD_ORCO, "");
return GPU_stack_link(mat,
node,
@@ -52,7 +54,7 @@ static int node_shader_gpu_geometry(GPUMaterial *mat,
out,
GPU_builtin(GPU_VIEW_POSITION),
GPU_builtin(GPU_WORLD_NORMAL),
- GPU_attribute(CD_ORCO, ""),
+ orco_link,
GPU_builtin(GPU_OBJECT_MATRIX),
GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
bary_link);
diff --git a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
index ea916d25ffd..21d2cdcb3b5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
+++ b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
@@ -39,7 +39,7 @@ static bNodeSocketTemplate sh_node_hue_sat_out[] = {
/* note: it would be possible to use CMP version for both nodes */
static void do_hue_sat_fac(
- bNode *UNUSED(node), float *out, float hue, float sat, float val, float in[4], float fac)
+ bNode *UNUSED(node), float *out, float hue, float sat, float val, const float in[4], float fac)
{
if (fac != 0.0f && (hue != 0.5f || sat != 1.0f || val != 1.0f)) {
float col[3], hsv[3], mfac = 1.0f - fac;
diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.c
index eca0d96f2c8..d607fcdc7a1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mapping.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mapping.c
@@ -25,7 +25,10 @@
/* **************** MAPPING ******************** */
static bNodeSocketTemplate sh_node_mapping_in[] = {
- {SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE},
+ {SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_NONE},
+ {SOCK_VECTOR, 1, N_("Location"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
+ {SOCK_VECTOR, 1, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
+ {SOCK_VECTOR, 1, N_("Scale"), 1.0f, 1.0f, 1.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_XYZ},
{-1, 0, ""},
};
@@ -34,91 +37,27 @@ static bNodeSocketTemplate sh_node_mapping_out[] = {
{-1, 0, ""},
};
-static void *node_shader_initexec_mapping(bNodeExecContext *UNUSED(context),
- bNode *node,
- bNodeInstanceKey UNUSED(key))
-{
- TexMapping *texmap = node->storage;
- BKE_texture_mapping_init(texmap);
- return NULL;
-}
-
-/* do the regular mapping options for blender textures */
-static void node_shader_exec_mapping(void *UNUSED(data),
- int UNUSED(thread),
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- TexMapping *texmap = node->storage;
- float *vec = out[0]->vec;
-
- /* stack order input: vector */
- /* stack order output: vector */
- nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
- mul_m4_v3(texmap->mat, vec);
-
- if (texmap->flag & TEXMAP_CLIP_MIN) {
- if (vec[0] < texmap->min[0]) {
- vec[0] = texmap->min[0];
- }
- if (vec[1] < texmap->min[1]) {
- vec[1] = texmap->min[1];
- }
- if (vec[2] < texmap->min[2]) {
- vec[2] = texmap->min[2];
- }
- }
- if (texmap->flag & TEXMAP_CLIP_MAX) {
- if (vec[0] > texmap->max[0]) {
- vec[0] = texmap->max[0];
- }
- if (vec[1] > texmap->max[1]) {
- vec[1] = texmap->max[1];
- }
- if (vec[2] > texmap->max[2]) {
- vec[2] = texmap->max[2];
- }
- }
-
- if (texmap->type == TEXMAP_TYPE_NORMAL) {
- normalize_v3(vec);
- }
-}
-
-static void node_shader_init_mapping(bNodeTree *UNUSED(ntree), bNode *node)
-{
- node->storage = BKE_texture_mapping_add(TEXMAP_TYPE_POINT);
-}
-
static int gpu_shader_mapping(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
GPUNodeStack *in,
GPUNodeStack *out)
{
- TexMapping *texmap = node->storage;
- float domin = (texmap->flag & TEXMAP_CLIP_MIN) != 0;
- float domax = (texmap->flag & TEXMAP_CLIP_MAX) != 0;
- static float max[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
- static float min[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
- GPUNodeLink *tmin, *tmax, *tmat0, *tmat1, *tmat2, *tmat3;
-
- tmin = GPU_uniform((domin) ? texmap->min : min);
- tmax = GPU_uniform((domax) ? texmap->max : max);
- tmat0 = GPU_uniform((float *)texmap->mat[0]);
- tmat1 = GPU_uniform((float *)texmap->mat[1]);
- tmat2 = GPU_uniform((float *)texmap->mat[2]);
- tmat3 = GPU_uniform((float *)texmap->mat[3]);
-
- GPU_stack_link(mat, node, "mapping", in, out, tmat0, tmat1, tmat2, tmat3, tmin, tmax);
-
- if (texmap->type == TEXMAP_TYPE_NORMAL) {
- GPU_link(mat, "texco_norm", out[0].link, &out[0].link);
- }
+ static const char *names[] = {
+ [NODE_MAPPING_TYPE_POINT] = "mapping_point",
+ [NODE_MAPPING_TYPE_TEXTURE] = "mapping_texture",
+ [NODE_MAPPING_TYPE_VECTOR] = "mapping_vector",
+ [NODE_MAPPING_TYPE_NORMAL] = "mapping_normal",
+ };
+
+ return GPU_stack_link(mat, node, names[node->custom1], in, out);
+}
- return true;
+static void node_shader_update_mapping(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sock = nodeFindSocket(node, SOCK_IN, "Location");
+ nodeSetSocketAvailability(
+ sock, ELEM(node->custom1, NODE_MAPPING_TYPE_POINT, NODE_MAPPING_TYPE_TEXTURE));
}
void register_node_type_sh_mapping(void)
@@ -127,11 +66,8 @@ void register_node_type_sh_mapping(void)
sh_node_type_base(&ntype, SH_NODE_MAPPING, "Mapping", NODE_CLASS_OP_VECTOR, 0);
node_type_socket_templates(&ntype, sh_node_mapping_in, sh_node_mapping_out);
- node_type_size(&ntype, 320, 160, 360);
- node_type_init(&ntype, node_shader_init_mapping);
- node_type_storage(&ntype, "TexMapping", node_free_standard_storage, node_copy_standard_storage);
- node_type_exec(&ntype, node_shader_initexec_mapping, NULL, node_shader_exec_mapping);
node_type_gpu(&ntype, gpu_shader_mapping);
+ node_type_update(&ntype, node_shader_update_mapping);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_mixRgb.c b/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
index 872f4f9da9c..ae2184d8237 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
@@ -92,7 +92,7 @@ static int gpu_shader_mix_rgb(GPUMaterial *mat,
if (ret && node->custom2 & SHD_MIXRGB_CLAMP) {
float min[3] = {0.0f, 0.0f, 0.0f};
float max[3] = {1.0f, 1.0f, 1.0f};
- GPU_link(mat, "clamp_vec3", out[0].link, GPU_constant(min), GPU_constant(max), &out[0].link);
+ GPU_link(mat, "clamp_color", out[0].link, GPU_constant(min), GPU_constant(max), &out[0].link);
}
return ret;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
index 712c64084cc..18015d94f03 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
@@ -114,8 +114,8 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
break;
}
- GPU_link(mat, "vector_math_mix", strength, realnorm, negnorm, &out[0].link);
- GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
+ GPU_link(mat, "vector_mix", strength, realnorm, negnorm, &out[0].link);
+ GPU_link(mat, "vector_normalize", out[0].link, &out[0].link);
return true;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
index 9a0a132b311..9f93dfd837b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
+++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
@@ -61,8 +61,6 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat,
GPU_link(mat, "world_normals_get", &in[5].link);
}
- GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS);
-
if (node->sss_id > 0) {
bNodeSocket *socket = BLI_findlink(&node->original->inputs, 2);
bNodeSocketValueRGBA *socket_data = socket->default_value;
@@ -71,6 +69,10 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat,
/* For some reason it seems that the socket value is in ARGB format. */
GPU_material_sss_profile_create(
mat, &socket_data->value[1], &node->original->custom1, &socket_data_sharp->value);
+
+ /* sss_id is 0 only the node is not connected to any output.
+ * In this case flagging the material would trigger a bug (see T68736). */
+ GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS);
}
return GPU_stack_link(
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
index 92ade999650..9c86e78c3cd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
@@ -157,11 +157,7 @@ static int node_shader_gpu_tex_brick(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- if (!in[0].link) {
- in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
- }
-
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
NodeTexBrick *tex = (NodeTexBrick *)node->storage;
float offset_freq = tex->offset_freq;
@@ -171,9 +167,9 @@ static int node_shader_gpu_tex_brick(GPUMaterial *mat,
"node_tex_brick",
in,
out,
- GPU_constant(&tex->offset),
+ GPU_uniform(&tex->offset),
GPU_constant(&offset_freq),
- GPU_constant(&tex->squash),
+ GPU_uniform(&tex->squash),
GPU_constant(&squash_freq));
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_checker.c b/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
index 9dcb6057589..9b9138802fa 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
@@ -70,11 +70,7 @@ static int node_shader_gpu_tex_checker(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- if (!in[0].link) {
- in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
- }
-
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
return GPU_stack_link(mat, node, "node_tex_checker", in, out);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
index 0e34f2ca9b1..068458b7e1f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
@@ -45,22 +45,27 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat,
GPUNodeLink *inv_obmat = (ob != NULL) ? GPU_uniform(&ob->imat[0][0]) :
GPU_builtin(GPU_INVERSE_OBJECT_MATRIX);
- GPUNodeLink *orco = GPU_attribute(CD_ORCO, "");
+ /* Opti: don't request orco if not needed. */
+ GPUNodeLink *orco = (!out[0].hasoutput) ? GPU_constant((float[4]){0.0f, 0.0f, 0.0f, 0.0f}) :
+ GPU_attribute(CD_ORCO, "");
GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, "");
+ GPUNodeLink *viewpos = GPU_builtin(GPU_VIEW_POSITION);
+ GPUNodeLink *worldnor = GPU_builtin(GPU_WORLD_NORMAL);
+ GPUNodeLink *texcofacs = GPU_builtin(GPU_CAMERA_TEXCO_FACTORS);
- GPU_link(mat, "generated_from_orco", orco, &orco);
+ if (out[0].hasoutput) {
+ GPU_link(mat, "generated_from_orco", orco, &orco);
+ }
- return GPU_stack_link(mat,
- node,
- "node_tex_coord",
- in,
- out,
- GPU_builtin(GPU_VIEW_POSITION),
- GPU_builtin(GPU_WORLD_NORMAL),
- inv_obmat,
- GPU_builtin(GPU_CAMERA_TEXCO_FACTORS),
- orco,
- mtface);
+ GPU_stack_link(
+ mat, node, "node_tex_coord", in, out, viewpos, worldnor, inv_obmat, texcofacs, orco, mtface);
+
+ /* for each output. */
+ for (int i = 0; sh_node_tex_coord_out[i].type != -1; i++) {
+ node_shader_gpu_bump_tex_coord(mat, node, &out[i].link);
+ }
+
+ return 1;
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
index bd8355ec885..6c380efe0b2 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
@@ -75,6 +75,7 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
if (!in[0].link) {
GPU_link(mat, "node_tex_environment_texco", GPU_builtin(GPU_VIEW_POSITION), &in[0].link);
+ node_shader_gpu_bump_tex_coord(mat, node, &in[0].link);
}
node_shader_gpu_tex_mapping(mat, node, in, out);
@@ -124,15 +125,15 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
if (ELEM(ima->alpha_mode, IMA_ALPHA_IGNORE, IMA_ALPHA_CHANNEL_PACKED) ||
IMB_colormanagement_space_name_is_data(ima->colorspace_settings.name)) {
/* Don't let alpha affect color output in these cases. */
- GPU_link(mat, "tex_color_alpha_clear", out[0].link, &out[0].link);
+ GPU_link(mat, "color_alpha_clear", out[0].link, &out[0].link);
}
else {
/* Always output with premultiplied alpha. */
if (ima->alpha_mode == IMA_ALPHA_PREMUL) {
- GPU_link(mat, "tex_color_alpha_clear", out[0].link, &out[0].link);
+ GPU_link(mat, "color_alpha_clear", out[0].link, &out[0].link);
}
else {
- GPU_link(mat, "tex_color_alpha_premultiply", out[0].link, &out[0].link);
+ GPU_link(mat, "color_alpha_premultiply", out[0].link, &out[0].link);
}
}
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
index 9271ba72a05..7f266c06a1b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
@@ -68,11 +68,7 @@ static int node_shader_gpu_tex_gradient(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- if (!in[0].link) {
- in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
- }
-
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
NodeTexGradient *tex = (NodeTexGradient *)node->storage;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
index 6f3614e357d..a6dfb2636fc 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
@@ -118,6 +118,7 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
if (!*texco) {
*texco = GPU_attribute(CD_MTFACE, "");
+ node_shader_gpu_bump_tex_coord(mat, node, texco);
}
node_shader_gpu_tex_mapping(mat, node, in, out);
@@ -183,7 +184,7 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
if (ELEM(ima->alpha_mode, IMA_ALPHA_IGNORE, IMA_ALPHA_CHANNEL_PACKED) ||
IMB_colormanagement_space_name_is_data(ima->colorspace_settings.name)) {
/* Don't let alpha affect color output in these cases. */
- GPU_link(mat, "tex_color_alpha_clear", out[0].link, &out[0].link);
+ GPU_link(mat, "color_alpha_clear", out[0].link, &out[0].link);
}
else {
/* Output premultiplied alpha depending on alpha socket usage. This makes
@@ -192,18 +193,18 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
* not, then there will be no artifacts from zero alpha areas. */
if (ima->alpha_mode == IMA_ALPHA_PREMUL) {
if (out[1].hasoutput) {
- GPU_link(mat, "tex_color_alpha_unpremultiply", out[0].link, &out[0].link);
+ GPU_link(mat, "color_alpha_unpremultiply", out[0].link, &out[0].link);
}
else {
- GPU_link(mat, "tex_color_alpha_clear", out[0].link, &out[0].link);
+ GPU_link(mat, "color_alpha_clear", out[0].link, &out[0].link);
}
}
else {
if (out[1].hasoutput) {
- GPU_link(mat, "tex_color_alpha_clear", out[0].link, &out[0].link);
+ GPU_link(mat, "color_alpha_clear", out[0].link, &out[0].link);
}
else {
- GPU_link(mat, "tex_color_alpha_premultiply", out[0].link, &out[0].link);
+ GPU_link(mat, "color_alpha_premultiply", out[0].link, &out[0].link);
}
}
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_magic.c b/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
index f5dc0435f27..d51594e549d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
@@ -73,11 +73,7 @@ static int node_shader_gpu_tex_magic(GPUMaterial *mat,
NodeTexMagic *tex = (NodeTexMagic *)node->storage;
float depth = tex->depth;
- if (!in[0].link) {
- in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
- }
-
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
return GPU_stack_link(mat, node, "node_tex_magic", in, out, GPU_constant(&depth));
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
index 250a1da3c23..daf4053f182 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
@@ -23,6 +23,7 @@
static bNodeSocketTemplate sh_node_tex_musgrave_in[] = {
{SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ {SOCK_FLOAT, 1, N_("W"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{SOCK_FLOAT, 1, N_("Scale"), 5.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{SOCK_FLOAT, 1, N_("Detail"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 16.0f},
{SOCK_FLOAT, 1, N_("Dimension"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
@@ -33,17 +34,6 @@ static bNodeSocketTemplate sh_node_tex_musgrave_in[] = {
};
static bNodeSocketTemplate sh_node_tex_musgrave_out[] = {
- {SOCK_RGBA,
- 0,
- N_("Color"),
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- PROP_NONE,
- SOCK_NO_INTERNAL_LINK},
{SOCK_FLOAT,
0,
N_("Fac"),
@@ -64,6 +54,7 @@ static void node_shader_init_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *node)
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->musgrave_type = SHD_MUSGRAVE_FBM;
+ tex->dimensions = 3;
node->storage = tex;
}
@@ -74,20 +65,81 @@ static int node_shader_gpu_tex_musgrave(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- if (!in[0].link) {
- in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
- }
-
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
NodeTexMusgrave *tex = (NodeTexMusgrave *)node->storage;
- float type = tex->musgrave_type;
+ int dimensions = tex->dimensions;
+ int type = tex->musgrave_type;
+
+ static const char *names[][5] = {
+ [SHD_MUSGRAVE_MULTIFRACTAL] =
+ {
+ "",
+ "node_tex_musgrave_multi_fractal_1d",
+ "node_tex_musgrave_multi_fractal_2d",
+ "node_tex_musgrave_multi_fractal_3d",
+ "node_tex_musgrave_multi_fractal_4d",
+ },
+ [SHD_MUSGRAVE_FBM] =
+ {
+ "",
+ "node_tex_musgrave_fBm_1d",
+ "node_tex_musgrave_fBm_2d",
+ "node_tex_musgrave_fBm_3d",
+ "node_tex_musgrave_fBm_4d",
+ },
+ [SHD_MUSGRAVE_HYBRID_MULTIFRACTAL] =
+ {
+ "",
+ "node_tex_musgrave_hybrid_multi_fractal_1d",
+ "node_tex_musgrave_hybrid_multi_fractal_2d",
+ "node_tex_musgrave_hybrid_multi_fractal_3d",
+ "node_tex_musgrave_hybrid_multi_fractal_4d",
+ },
+ [SHD_MUSGRAVE_RIDGED_MULTIFRACTAL] =
+ {
+ "",
+ "node_tex_musgrave_ridged_multi_fractal_1d",
+ "node_tex_musgrave_ridged_multi_fractal_2d",
+ "node_tex_musgrave_ridged_multi_fractal_3d",
+ "node_tex_musgrave_ridged_multi_fractal_4d",
+ },
+ [SHD_MUSGRAVE_HETERO_TERRAIN] =
+ {
+ "",
+ "node_tex_musgrave_hetero_terrain_1d",
+ "node_tex_musgrave_hetero_terrain_2d",
+ "node_tex_musgrave_hetero_terrain_3d",
+ "node_tex_musgrave_hetero_terrain_4d",
+ },
+ };
+
+ BLI_assert(type >= 0 && type < 5);
+ BLI_assert(dimensions > 0 && dimensions < 5);
+
+ return GPU_stack_link(mat, node, names[type][dimensions], in, out);
+}
+
+static void node_shader_update_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeTexMusgrave *tex = (NodeTexMusgrave *)node->storage;
+
+ bNodeSocket *inVectorSock = nodeFindSocket(node, SOCK_IN, "Vector");
+ bNodeSocket *inWSock = nodeFindSocket(node, SOCK_IN, "W");
+ bNodeSocket *inOffsetSock = nodeFindSocket(node, SOCK_IN, "Offset");
+ bNodeSocket *inGainSock = nodeFindSocket(node, SOCK_IN, "Gain");
- return GPU_stack_link(mat, node, "node_tex_musgrave", in, out, GPU_constant(&type));
+ nodeSetSocketAvailability(inVectorSock, tex->dimensions != 1);
+ nodeSetSocketAvailability(inWSock, tex->dimensions == 1 || tex->dimensions == 4);
+ nodeSetSocketAvailability(inOffsetSock,
+ tex->musgrave_type != SHD_MUSGRAVE_MULTIFRACTAL &&
+ tex->musgrave_type != SHD_MUSGRAVE_FBM);
+ nodeSetSocketAvailability(inGainSock,
+ tex->musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL &&
+ tex->musgrave_type != SHD_MUSGRAVE_RIDGED_MULTIFRACTAL);
}
-/* node type definition */
void register_node_type_sh_tex_musgrave(void)
{
static bNodeType ntype;
@@ -99,6 +151,7 @@ void register_node_type_sh_tex_musgrave(void)
node_type_storage(
&ntype, "NodeTexMusgrave", node_free_standard_storage, node_copy_standard_storage);
node_type_gpu(&ntype, node_shader_gpu_tex_musgrave);
+ node_type_update(&ntype, node_shader_update_tex_musgrave);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
index 34c4b17f255..0b3b249c3d9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
@@ -23,6 +23,7 @@
static bNodeSocketTemplate sh_node_tex_noise_in[] = {
{SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ {SOCK_FLOAT, 1, N_("W"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{SOCK_FLOAT, 1, N_("Scale"), 5.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{SOCK_FLOAT, 1, N_("Detail"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 16.0f},
{SOCK_FLOAT, 1, N_("Distortion"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
@@ -30,27 +31,27 @@ static bNodeSocketTemplate sh_node_tex_noise_in[] = {
};
static bNodeSocketTemplate sh_node_tex_noise_out[] = {
- {SOCK_RGBA,
+ {SOCK_FLOAT,
0,
- N_("Color"),
+ N_("Fac"),
0.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
- PROP_NONE,
+ PROP_FACTOR,
SOCK_NO_INTERNAL_LINK},
- {SOCK_FLOAT,
+ {SOCK_RGBA,
0,
- N_("Fac"),
+ N_("Color"),
0.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
- PROP_FACTOR,
+ PROP_NONE,
SOCK_NO_INTERNAL_LINK},
{-1, 0, ""},
};
@@ -60,6 +61,7 @@ static void node_shader_init_tex_noise(bNodeTree *UNUSED(ntree), bNode *node)
NodeTexNoise *tex = MEM_callocN(sizeof(NodeTexNoise), "NodeTexNoise");
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
+ tex->dimensions = 3;
node->storage = tex;
}
@@ -70,14 +72,28 @@ static int node_shader_gpu_tex_noise(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- if (!in[0].link) {
- in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
- }
-
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
- return GPU_stack_link(mat, node, "node_tex_noise", in, out);
+ NodeTexNoise *tex = (NodeTexNoise *)node->storage;
+ static const char *names[] = {
+ "",
+ "node_noise_texture_1d",
+ "node_noise_texture_2d",
+ "node_noise_texture_3d",
+ "node_noise_texture_4d",
+ };
+ return GPU_stack_link(mat, node, names[tex->dimensions], in, out);
+}
+
+static void node_shader_update_tex_noise(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector");
+ bNodeSocket *sockW = nodeFindSocket(node, SOCK_IN, "W");
+
+ NodeTexNoise *tex = (NodeTexNoise *)node->storage;
+ nodeSetSocketAvailability(sockVector, tex->dimensions != 1);
+ nodeSetSocketAvailability(sockW, tex->dimensions == 1 || tex->dimensions == 4);
}
/* node type definition */
@@ -91,6 +107,7 @@ void register_node_type_sh_tex_noise(void)
node_type_storage(
&ntype, "NodeTexNoise", node_free_standard_storage, node_copy_standard_storage);
node_type_gpu(&ntype, node_shader_gpu_tex_noise);
+ node_type_update(&ntype, node_shader_update_tex_noise);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
index e0b4de985d8..adcb93d7775 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
@@ -23,12 +23,26 @@
static bNodeSocketTemplate sh_node_tex_voronoi_in[] = {
{SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ {SOCK_FLOAT, 1, N_("W"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{SOCK_FLOAT, 1, N_("Scale"), 5.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
+ {SOCK_FLOAT, 1, N_("Smoothness"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{SOCK_FLOAT, 1, N_("Exponent"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 32.0f},
+ {SOCK_FLOAT, 1, N_("Randomness"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{-1, 0, ""},
};
static bNodeSocketTemplate sh_node_tex_voronoi_out[] = {
+ {SOCK_FLOAT,
+ 0,
+ N_("Distance"),
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ PROP_NONE,
+ SOCK_NO_INTERNAL_LINK},
{SOCK_RGBA,
0,
N_("Color"),
@@ -40,16 +54,28 @@ static bNodeSocketTemplate sh_node_tex_voronoi_out[] = {
1.0f,
PROP_NONE,
SOCK_NO_INTERNAL_LINK},
+ {SOCK_VECTOR,
+ 0,
+ N_("Position"),
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ PROP_NONE,
+ SOCK_NO_INTERNAL_LINK},
+ {SOCK_FLOAT, 0, N_("W"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
{SOCK_FLOAT,
0,
- N_("Fac"),
+ N_("Radius"),
0.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
- PROP_FACTOR,
+ PROP_NONE,
SOCK_NO_INTERNAL_LINK},
{-1, 0, ""},
};
@@ -59,8 +85,8 @@ static void node_shader_init_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node)
NodeTexVoronoi *tex = MEM_callocN(sizeof(NodeTexVoronoi), "NodeTexVoronoi");
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
- tex->coloring = SHD_VORONOI_INTENSITY;
- tex->distance = SHD_VORONOI_DISTANCE;
+ tex->dimensions = 3;
+ tex->distance = SHD_VORONOI_EUCLIDEAN;
tex->feature = SHD_VORONOI_F1;
node->storage = tex;
@@ -72,46 +98,99 @@ static int node_shader_gpu_tex_voronoi(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- if (!in[0].link) {
- in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
- }
-
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
+ static const char *names[][5] = {
+ [SHD_VORONOI_F1] =
+ {
+ "",
+ "node_tex_voronoi_f1_1d",
+ "node_tex_voronoi_f1_2d",
+ "node_tex_voronoi_f1_3d",
+ "node_tex_voronoi_f1_4d",
+ },
+ [SHD_VORONOI_F2] =
+ {
+ "",
+ "node_tex_voronoi_f2_1d",
+ "node_tex_voronoi_f2_2d",
+ "node_tex_voronoi_f2_3d",
+ "node_tex_voronoi_f2_4d",
+ },
+ [SHD_VORONOI_SMOOTH_F1] =
+ {
+ "",
+ "node_tex_voronoi_smooth_f1_1d",
+ "node_tex_voronoi_smooth_f1_2d",
+ "node_tex_voronoi_smooth_f1_3d",
+ "node_tex_voronoi_smooth_f1_4d",
+ },
+ [SHD_VORONOI_DISTANCE_TO_EDGE] =
+ {
+ "",
+ "node_tex_voronoi_distance_to_edge_1d",
+ "node_tex_voronoi_distance_to_edge_2d",
+ "node_tex_voronoi_distance_to_edge_3d",
+ "node_tex_voronoi_distance_to_edge_4d",
+ },
+ [SHD_VORONOI_N_SPHERE_RADIUS] =
+ {
+ "",
+ "node_tex_voronoi_n_sphere_radius_1d",
+ "node_tex_voronoi_n_sphere_radius_2d",
+ "node_tex_voronoi_n_sphere_radius_3d",
+ "node_tex_voronoi_n_sphere_radius_4d",
+ },
+ };
+
NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
- float coloring = tex->coloring;
float metric = tex->distance;
- float feature = tex->feature;
-
- return GPU_stack_link(mat,
- node,
- "node_tex_voronoi",
- in,
- out,
- GPU_constant(&coloring),
- GPU_constant(&metric),
- GPU_constant(&feature));
+
+ BLI_assert(tex->feature >= 0 && tex->feature < 5);
+ BLI_assert(tex->dimensions > 0 && tex->dimensions < 5);
+
+ return GPU_stack_link(
+ mat, node, names[tex->feature][tex->dimensions], in, out, GPU_constant(&metric));
}
static void node_shader_update_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node)
{
+ bNodeSocket *inVectorSock = nodeFindSocket(node, SOCK_IN, "Vector");
+ bNodeSocket *inWSock = nodeFindSocket(node, SOCK_IN, "W");
+ bNodeSocket *inSmoothnessSock = nodeFindSocket(node, SOCK_IN, "Smoothness");
+ bNodeSocket *inExponentSock = nodeFindSocket(node, SOCK_IN, "Exponent");
+
+ bNodeSocket *outDistanceSock = nodeFindSocket(node, SOCK_OUT, "Distance");
+ bNodeSocket *outColorSock = nodeFindSocket(node, SOCK_OUT, "Color");
+ bNodeSocket *outPositionSock = nodeFindSocket(node, SOCK_OUT, "Position");
+ bNodeSocket *outWSock = nodeFindSocket(node, SOCK_OUT, "W");
+ bNodeSocket *outRadiusSock = nodeFindSocket(node, SOCK_OUT, "Radius");
+
NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
- bNodeSocket *sock;
-
- for (sock = node->inputs.first; sock; sock = sock->next) {
- if (STREQ(sock->name, "Exponent")) {
- if (tex->distance == SHD_VORONOI_MINKOWSKI) {
- sock->flag &= ~SOCK_UNAVAIL;
- }
- else {
- sock->flag |= SOCK_UNAVAIL;
- }
- }
- }
+
+ nodeSetSocketAvailability(inWSock, tex->dimensions == 1 || tex->dimensions == 4);
+ nodeSetSocketAvailability(inVectorSock, tex->dimensions != 1);
+ nodeSetSocketAvailability(
+ inExponentSock,
+ tex->distance == SHD_VORONOI_MINKOWSKI && tex->dimensions != 1 &&
+ !ELEM(tex->feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS));
+ nodeSetSocketAvailability(inSmoothnessSock, tex->feature == SHD_VORONOI_SMOOTH_F1);
+ nodeSetSocketAvailability(outDistanceSock, tex->feature != SHD_VORONOI_N_SPHERE_RADIUS);
+ nodeSetSocketAvailability(outColorSock,
+ tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
+ tex->feature != SHD_VORONOI_N_SPHERE_RADIUS);
+ nodeSetSocketAvailability(outPositionSock,
+ tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
+ tex->feature != SHD_VORONOI_N_SPHERE_RADIUS &&
+ tex->dimensions != 1);
+ nodeSetSocketAvailability(outWSock,
+ tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
+ tex->feature != SHD_VORONOI_N_SPHERE_RADIUS &&
+ (tex->dimensions == 1 || tex->dimensions == 4));
+ nodeSetSocketAvailability(outRadiusSock, tex->feature == SHD_VORONOI_N_SPHERE_RADIUS);
}
-/* node type definition */
void register_node_type_sh_tex_voronoi(void)
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c b/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
index 65b78f2923d..b525f4897a9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
@@ -72,11 +72,7 @@ static int node_shader_gpu_tex_wave(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- if (!in[0].link) {
- in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
- }
-
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
NodeTexWave *tex = (NodeTexWave *)node->storage;
diff --git a/source/blender/nodes/shader/nodes/node_shader_uvmap.c b/source/blender/nodes/shader/nodes/node_shader_uvmap.c
index 73fb022e476..a2e47735490 100644
--- a/source/blender/nodes/shader/nodes/node_shader_uvmap.c
+++ b/source/blender/nodes/shader/nodes/node_shader_uvmap.c
@@ -43,7 +43,11 @@ static int node_shader_gpu_uvmap(GPUMaterial *mat,
NodeShaderUVMap *attr = node->storage;
GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, attr->uv_map);
- return GPU_stack_link(mat, node, "node_uvmap", in, out, mtface);
+ GPU_stack_link(mat, node, "node_uvmap", in, out, mtface);
+
+ node_shader_gpu_bump_tex_coord(mat, node, &out[0].link);
+
+ return 1;
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c b/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
index fe0e7b1d638..563ef89162b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
@@ -132,7 +132,7 @@ static int gpu_shader_vect_transform(GPUMaterial *mat,
}
if (nodeprop->type == SHD_VECT_TRANSFORM_TYPE_NORMAL) {
- GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
+ GPU_link(mat, "vector_normalize", out[0].link, &out[0].link);
}
return true;
diff --git a/source/blender/nodes/shader/nodes/node_shader_vertex_color.c b/source/blender/nodes/shader/nodes/node_shader_vertex_color.c
new file mode 100644
index 00000000000..8848fc37c66
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_vertex_color.c
@@ -0,0 +1,58 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "../node_shader_util.h"
+
+static bNodeSocketTemplate sh_node_vertex_color_out[] = {
+ {SOCK_RGBA, 0, N_("Color")},
+ {SOCK_FLOAT, 0, N_("Alpha")},
+ {-1, 0, ""},
+};
+
+static void node_shader_init_vertex_color(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeShaderVertexColor *vertexColor = MEM_callocN(sizeof(NodeShaderVertexColor),
+ "NodeShaderVertexColor");
+ node->storage = vertexColor;
+}
+
+static int node_shader_gpu_vertex_color(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ NodeShaderVertexColor *vertexColor = (NodeShaderVertexColor *)node->storage;
+ GPUNodeLink *vertexColorLink = GPU_attribute(CD_MCOL, vertexColor->layer_name);
+ return GPU_stack_link(mat, node, "node_vertex_color", in, out, vertexColorLink);
+}
+
+void register_node_type_sh_vertex_color(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_VERTEX_COLOR, "Vertex Color", NODE_CLASS_INPUT, 0);
+ node_type_socket_templates(&ntype, NULL, sh_node_vertex_color_out);
+ node_type_init(&ntype, node_shader_init_vertex_color);
+ node_type_storage(
+ &ntype, "NodeShaderVertexColor", node_free_standard_storage, node_copy_standard_storage);
+ node_type_gpu(&ntype, node_shader_gpu_vertex_color);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c
index b8435d3a352..a505bed2458 100644
--- a/source/blender/nodes/texture/nodes/node_texture_common.c
+++ b/source/blender/nodes/texture/nodes/node_texture_common.c
@@ -84,7 +84,7 @@ static void group_copy_inputs(bNode *gnode, bNodeStack **in, bNodeStack *gstack)
for (node = ngroup->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP_INPUT) {
- for (sock = node->outputs.first, a = 0; sock; sock = sock->next, ++a) {
+ for (sock = node->outputs.first, a = 0; sock; sock = sock->next, a++) {
if (in[a]) { /* shouldn't need to check this [#36694] */
ns = node_get_socket_stack(gstack, sock);
if (ns) {
@@ -108,7 +108,7 @@ static void group_copy_outputs(bNode *gnode, bNodeStack **out, bNodeStack *gstac
for (node = ngroup->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) {
- for (sock = node->inputs.first, a = 0; sock; sock = sock->next, ++a) {
+ for (sock = node->inputs.first, a = 0; sock; sock = sock->next, a++) {
if (out[a]) { /* shouldn't need to check this [#36694] */
ns = node_get_socket_stack(gstack, sock);
if (ns) {
diff --git a/source/blender/nodes/texture/nodes/node_texture_proc.c b/source/blender/nodes/texture/nodes/node_texture_proc.c
index b0b646dfd16..5c3b0dc7f55 100644
--- a/source/blender/nodes/texture/nodes/node_texture_proc.c
+++ b/source/blender/nodes/texture/nodes/node_texture_proc.c
@@ -165,83 +165,84 @@ static void voronoi_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short th
tex->ns_outscale = tex_input_value(in[I + 4], p, thread);
tex->noisesize = tex_input_value(in[I + 5], p, thread);
}
-ProcDef(voronoi)
+ProcDef(voronoi);
- /* --- BLEND -- */
- static bNodeSocketTemplate blend_inputs[] = {COMMON_INPUTS, {-1, 0, ""}};
-ProcNoInputs(blend) ProcDef(blend)
+/* --- BLEND -- */
+static bNodeSocketTemplate blend_inputs[] = {COMMON_INPUTS, {-1, 0, ""}};
+ProcNoInputs(blend);
+ProcDef(blend);
- /* -- MAGIC -- */
- static bNodeSocketTemplate magic_inputs[] = {
- COMMON_INPUTS,
- {SOCK_FLOAT, 1, N_("Turbulence"), 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 200.0f, PROP_UNSIGNED},
- {-1, 0, ""}};
+/* -- MAGIC -- */
+static bNodeSocketTemplate magic_inputs[] = {
+ COMMON_INPUTS,
+ {SOCK_FLOAT, 1, N_("Turbulence"), 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 200.0f, PROP_UNSIGNED},
+ {-1, 0, ""}};
static void magic_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short thread)
{
tex->turbul = tex_input_value(in[I + 0], p, thread);
}
-ProcDef(magic)
-
- /* --- MARBLE --- */
- static bNodeSocketTemplate marble_inputs[] = {
- COMMON_INPUTS,
- {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
- {SOCK_FLOAT, 1, N_("Turbulence"), 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 200.0f, PROP_UNSIGNED},
- {-1, 0, ""}};
+ProcDef(magic);
+
+/* --- MARBLE --- */
+static bNodeSocketTemplate marble_inputs[] = {
+ COMMON_INPUTS,
+ {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
+ {SOCK_FLOAT, 1, N_("Turbulence"), 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 200.0f, PROP_UNSIGNED},
+ {-1, 0, ""}};
static void marble_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short thread)
{
tex->noisesize = tex_input_value(in[I + 0], p, thread);
tex->turbul = tex_input_value(in[I + 1], p, thread);
}
-ProcDef(marble)
+ProcDef(marble);
- /* --- CLOUDS --- */
- static bNodeSocketTemplate clouds_inputs[] = {
- COMMON_INPUTS,
- {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
- {-1, 0, ""}};
+/* --- CLOUDS --- */
+static bNodeSocketTemplate clouds_inputs[] = {
+ COMMON_INPUTS,
+ {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
+ {-1, 0, ""}};
static void clouds_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short thread)
{
tex->noisesize = tex_input_value(in[I + 0], p, thread);
}
-ProcDef(clouds)
-
- /* --- DISTORTED NOISE --- */
- static bNodeSocketTemplate distnoise_inputs[] = {
- COMMON_INPUTS,
- {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
- {SOCK_FLOAT, 1, N_("Distortion"), 1.00f, 0.0f, 0.0f, 0.0f, 0.0000f, 10.0f, PROP_UNSIGNED},
- {-1, 0, ""}};
+ProcDef(clouds);
+
+/* --- DISTORTED NOISE --- */
+static bNodeSocketTemplate distnoise_inputs[] = {
+ COMMON_INPUTS,
+ {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
+ {SOCK_FLOAT, 1, N_("Distortion"), 1.00f, 0.0f, 0.0f, 0.0f, 0.0000f, 10.0f, PROP_UNSIGNED},
+ {-1, 0, ""}};
static void distnoise_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short thread)
{
tex->noisesize = tex_input_value(in[I + 0], p, thread);
tex->dist_amount = tex_input_value(in[I + 1], p, thread);
}
-ProcDef(distnoise)
-
- /* --- WOOD --- */
- static bNodeSocketTemplate wood_inputs[] = {
- COMMON_INPUTS,
- {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
- {SOCK_FLOAT, 1, N_("Turbulence"), 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 200.0f, PROP_UNSIGNED},
- {-1, 0, ""}};
+ProcDef(distnoise);
+
+/* --- WOOD --- */
+static bNodeSocketTemplate wood_inputs[] = {
+ COMMON_INPUTS,
+ {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
+ {SOCK_FLOAT, 1, N_("Turbulence"), 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 200.0f, PROP_UNSIGNED},
+ {-1, 0, ""}};
static void wood_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short thread)
{
tex->noisesize = tex_input_value(in[I + 0], p, thread);
tex->turbul = tex_input_value(in[I + 1], p, thread);
}
-ProcDef(wood)
-
- /* --- MUSGRAVE --- */
- static bNodeSocketTemplate musgrave_inputs[] = {
- COMMON_INPUTS,
- {SOCK_FLOAT, 1, N_("H"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
- {SOCK_FLOAT, 1, N_("Lacunarity"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 6.0f, PROP_UNSIGNED},
- {SOCK_FLOAT, 1, N_("Octaves"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 8.0f, PROP_UNSIGNED},
-
- {SOCK_FLOAT, 1, N_("iScale"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 10.0f, PROP_UNSIGNED},
- {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
- {-1, 0, ""}};
+ProcDef(wood);
+
+/* --- MUSGRAVE --- */
+static bNodeSocketTemplate musgrave_inputs[] = {
+ COMMON_INPUTS,
+ {SOCK_FLOAT, 1, N_("H"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
+ {SOCK_FLOAT, 1, N_("Lacunarity"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 6.0f, PROP_UNSIGNED},
+ {SOCK_FLOAT, 1, N_("Octaves"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 8.0f, PROP_UNSIGNED},
+
+ {SOCK_FLOAT, 1, N_("iScale"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 10.0f, PROP_UNSIGNED},
+ {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
+ {-1, 0, ""}};
static void musgrave_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short thread)
{
tex->mg_H = tex_input_value(in[I + 0], p, thread);
@@ -250,28 +251,29 @@ static void musgrave_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short t
tex->ns_outscale = tex_input_value(in[I + 3], p, thread);
tex->noisesize = tex_input_value(in[I + 4], p, thread);
}
-ProcDef(musgrave)
-
- /* --- NOISE --- */
- static bNodeSocketTemplate noise_inputs[] = {COMMON_INPUTS, {-1, 0, ""}};
-ProcNoInputs(noise) ProcDef(noise)
-
- /* --- STUCCI --- */
- static bNodeSocketTemplate stucci_inputs[] = {
- COMMON_INPUTS,
- {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
- {SOCK_FLOAT, 1, N_("Turbulence"), 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 200.0f, PROP_UNSIGNED},
- {-1, 0, ""}};
+ProcDef(musgrave);
+
+/* --- NOISE --- */
+static bNodeSocketTemplate noise_inputs[] = {COMMON_INPUTS, {-1, 0, ""}};
+ProcNoInputs(noise);
+ProcDef(noise);
+
+/* --- STUCCI --- */
+static bNodeSocketTemplate stucci_inputs[] = {
+ COMMON_INPUTS,
+ {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
+ {SOCK_FLOAT, 1, N_("Turbulence"), 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 200.0f, PROP_UNSIGNED},
+ {-1, 0, ""}};
static void stucci_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short thread)
{
tex->noisesize = tex_input_value(in[I + 0], p, thread);
tex->turbul = tex_input_value(in[I + 1], p, thread);
}
-ProcDef(stucci)
+ProcDef(stucci);
- /* --- */
+/* --- */
- static void init(bNodeTree *UNUSED(ntree), bNode *node)
+static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
Tex *tex = MEM_callocN(sizeof(Tex), "Tex");
node->storage = tex;
@@ -303,9 +305,9 @@ ProcDef(stucci)
#define C outputs_color_only
#define CV outputs_both
-TexDef(TEX_VORONOI, CV, voronoi, "Voronoi") TexDef(TEX_BLEND, C, blend, "Blend")
- TexDef(TEX_MAGIC, C, magic, "Magic") TexDef(TEX_MARBLE, CV, marble, "Marble")
- TexDef(TEX_CLOUDS, CV, clouds, "Clouds") TexDef(TEX_WOOD, CV, wood, "Wood")
- TexDef(TEX_MUSGRAVE, CV, musgrave, "Musgrave") TexDef(TEX_NOISE, C, noise, "Noise")
- TexDef(TEX_STUCCI, CV, stucci, "Stucci")
- TexDef(TEX_DISTNOISE, CV, distnoise, "Distorted Noise")
+TexDef(TEX_VORONOI, CV, voronoi, "Voronoi") TexDef(TEX_BLEND, C, blend, "Blend");
+TexDef(TEX_MAGIC, C, magic, "Magic") TexDef(TEX_MARBLE, CV, marble, "Marble");
+TexDef(TEX_CLOUDS, CV, clouds, "Clouds") TexDef(TEX_WOOD, CV, wood, "Wood");
+TexDef(TEX_MUSGRAVE, CV, musgrave, "Musgrave") TexDef(TEX_NOISE, C, noise, "Noise");
+TexDef(TEX_STUCCI, CV, stucci, "Stucci");
+TexDef(TEX_DISTNOISE, CV, distnoise, "Distorted Noise");
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index 07cb3370eec..c057e74b72b 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -231,9 +231,9 @@ static void cloth_setup_constraints(ClothModifierData *clmd,
verts[v].impulse_count = 0;
}
- for (i = 0; i < totcolliders; ++i) {
+ for (i = 0; i < totcolliders; i++) {
ColliderContacts *ct = &contacts[i];
- for (j = 0; j < ct->totcollisions; ++j) {
+ for (j = 0; j < ct->totcollisions; j++) {
CollPair *collpair = &ct->collisions[j];
// float restitution = (1.0f - clmd->coll_parms->damping) * (1.0f - ct->ob->pd->pdef_sbdamp);
float restitution = 0.0f;
@@ -867,8 +867,8 @@ static void cloth_continuum_step(ClothModifierData *clmd, float dt)
clmd->hair_grid_min[(axis + 2) % 3];
BKE_sim_debug_data_clear_category(clmd->debug_data, "grid velocity");
- for (j = 0; j < size; ++j) {
- for (i = 0; i < size; ++i) {
+ for (j = 0; j < size; j++) {
+ for (i = 0; i < size; i++) {
float x[3], v[3], gvel[3], gvel_smooth[3], gdensity;
madd_v3_v3v3fl(x, offset, a, (float)i / (float)(size - 1));
@@ -1111,6 +1111,12 @@ int BPH_cloth_solve(
ImplicitSolverResult result;
if (is_hair) {
+ /* copy velocities for collision */
+ for (i = 0; i < mvert_num; i++) {
+ BPH_mass_spring_get_motion_state(id, i, NULL, verts[i].tv);
+ copy_v3_v3(verts[i].v, verts[i].tv);
+ }
+
/* determine contact points */
if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
cloth_find_point_contacts(depsgraph, ob, clmd, 0.0f, tf, &contacts, &totcolliders);
diff --git a/source/blender/physics/intern/ConstrainedConjugateGradient.h b/source/blender/physics/intern/ConstrainedConjugateGradient.h
index 56151b714a6..c924490f97d 100644
--- a/source/blender/physics/intern/ConstrainedConjugateGradient.h
+++ b/source/blender/physics/intern/ConstrainedConjugateGradient.h
@@ -283,7 +283,7 @@ class ConstrainedConjugateGradient
m_iterations = Base::maxIterations();
m_error = Base::m_tolerance;
- for (int j = 0; j < b.cols(); ++j) {
+ for (int j = 0; j < b.cols(); j++) {
m_iterations = Base::maxIterations();
m_error = Base::m_tolerance;
diff --git a/source/blender/physics/intern/eigen_utils.h b/source/blender/physics/intern/eigen_utils.h
index 273b13e096a..2b50da0d190 100644
--- a/source/blender/physics/intern/eigen_utils.h
+++ b/source/blender/physics/intern/eigen_utils.h
@@ -54,14 +54,14 @@ class Vector3 : public Eigen::Vector3f {
Vector3(const ctype &v)
{
- for (int k = 0; k < 3; ++k) {
+ for (int k = 0; k < 3; k++) {
coeffRef(k) = v[k];
}
}
Vector3 &operator=(const ctype &v)
{
- for (int k = 0; k < 3; ++k) {
+ for (int k = 0; k < 3; k++) {
coeffRef(k) = v[k];
}
return *this;
@@ -86,8 +86,8 @@ class Matrix3 : public Eigen::Matrix3f {
Matrix3(const ctype &v)
{
- for (int k = 0; k < 3; ++k) {
- for (int l = 0; l < 3; ++l) {
+ for (int k = 0; k < 3; k++) {
+ for (int l = 0; l < 3; l++) {
coeffRef(l, k) = v[k][l];
}
}
@@ -95,8 +95,8 @@ class Matrix3 : public Eigen::Matrix3f {
Matrix3 &operator=(const ctype &v)
{
- for (int k = 0; k < 3; ++k) {
- for (int l = 0; l < 3; ++l) {
+ for (int k = 0; k < 3; k++) {
+ for (int l = 0; l < 3; l++) {
coeffRef(l, k) = v[k][l];
}
}
@@ -170,8 +170,8 @@ struct lMatrix3fCtor {
{
i *= 3;
j *= 3;
- for (int k = 0; k < 3; ++k) {
- for (int l = 0; l < 3; ++l) {
+ for (int k = 0; k < 3; k++) {
+ for (int l = 0; l < 3; l++) {
m_trips.push_back(Triplet(i + k, j + l, m.coeff(l, k)));
}
}
@@ -181,8 +181,8 @@ struct lMatrix3fCtor {
{
i *= 3;
j *= 3;
- for (int k = 0; k < 3; ++k) {
- for (int l = 0; l < 3; ++l) {
+ for (int k = 0; k < 3; k++) {
+ for (int l = 0; l < 3; l++) {
m_trips.push_back(Triplet(i + k, j + l, -m.coeff(l, k)));
}
}
@@ -205,7 +205,7 @@ using Eigen::ComputationInfo;
BLI_INLINE void print_lvector(const lVector3f &v)
{
- for (int i = 0; i < v.rows(); ++i) {
+ for (int i = 0; i < v.rows(); i++) {
if (i > 0 && i % 3 == 0) {
printf("\n");
}
@@ -216,12 +216,12 @@ BLI_INLINE void print_lvector(const lVector3f &v)
BLI_INLINE void print_lmatrix(const lMatrix &m)
{
- for (int j = 0; j < m.rows(); ++j) {
+ for (int j = 0; j < m.rows(); j++) {
if (j > 0 && j % 3 == 0) {
printf("\n");
}
- for (int i = 0; i < m.cols(); ++i) {
+ for (int i = 0; i < m.cols(); i++) {
if (i > 0 && i % 3 == 0) {
printf(" ");
}
diff --git a/source/blender/physics/intern/hair_volume.cpp b/source/blender/physics/intern/hair_volume.cpp
index 33c65a0cf95..88913eef7df 100644
--- a/source/blender/physics/intern/hair_volume.cpp
+++ b/source/blender/physics/intern/hair_volume.cpp
@@ -160,7 +160,7 @@ BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid,
if (velocity) {
int k;
- for (k = 0; k < 3; ++k) {
+ for (k = 0; k < 3; k++) {
velocity[k] = muvw[2] *
(muvw[1] * (muvw[0] * data[0].velocity[k] + uvw[0] * data[1].velocity[k]) +
uvw[1] * (muvw[0] * data[2].velocity[k] + uvw[0] * data[3].velocity[k])) +
@@ -172,7 +172,7 @@ BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid,
if (vel_smooth) {
int k;
- for (k = 0; k < 3; ++k) {
+ for (k = 0; k < 3; k++) {
vel_smooth[k] = muvw[2] * (muvw[1] * (muvw[0] * data[0].velocity_smooth[k] +
uvw[0] * data[1].velocity_smooth[k]) +
uvw[1] * (muvw[0] * data[2].velocity_smooth[k] +
@@ -297,7 +297,7 @@ void BPH_hair_volume_grid_clear(HairGrid *grid)
{
const int size = hair_grid_size(grid->res);
int i;
- for (i = 0; i < size; ++i) {
+ for (i = 0; i < size; i++) {
zero_v3(grid->verts[i].velocity);
zero_v3(grid->verts[i].velocity_smooth);
grid->verts[i].density = 0.0f;
@@ -321,7 +321,7 @@ BLI_INLINE float weights_sum(const float weights[8])
{
float totweight = 0.0f;
int i;
- for (i = 0; i < 8; ++i) {
+ for (i = 0; i < 8; i++) {
totweight += weights[i];
}
return totweight;
@@ -377,9 +377,9 @@ void BPH_hair_volume_add_vertex(HairGrid *grid, const float x[3], const float v[
offset = hair_grid_weights(res, grid->gmin, grid->inv_cellsize, x, weights);
- for (di = 0; di < 2; ++di) {
- for (dj = 0; dj < 2; ++dj) {
- for (dk = 0; dk < 2; ++dk) {
+ for (di = 0; di < 2; di++) {
+ for (dj = 0; dj < 2; dj++) {
+ for (dk = 0; dk < 2; dk++) {
int voffset = offset + di + (dj + dk * res[1]) * res[0];
int iw = di + dj * 2 + dk * 4;
@@ -465,12 +465,12 @@ BLI_INLINE void hair_volume_add_segment_2D(HairGrid *grid,
HairGridVert *vert_j = vert + jmin * stride_j;
float loc_j[3] = {loc[0], loc[1], loc[2]};
loc_j[axis_j] += (float)jmin;
- for (j = jmin; j <= jmax; ++j, vert_j += stride_j, loc_j[axis_j] += 1.0f) {
+ for (j = jmin; j <= jmax; j++, vert_j += stride_j, loc_j[axis_j] += 1.0f) {
HairGridVert *vert_k = vert_j + kmin * stride_k;
float loc_k[3] = {loc_j[0], loc_j[1], loc_j[2]};
loc_k[axis_k] += (float)kmin;
- for (k = kmin; k <= kmax; ++k, vert_k += stride_k, loc_k[axis_k] += 1.0f) {
+ for (k = kmin; k <= kmax; k++, vert_k += stride_k, loc_k[axis_k] += 1.0f) {
hair_volume_eval_grid_vertex(vert_k, loc_k, radius, dist_scale, x2, v2, x3, v3);
@@ -553,7 +553,7 @@ void BPH_hair_volume_add_segment(HairGrid *grid,
int j0, k0, j0_prev, k0_prev;
int i;
- for (i = imin; i <= imax; ++i) {
+ for (i = imin; i <= imax; i++) {
float shift1, shift2; /* fraction of a full cell shift [0.0, 1.0) */
int jmin, jmax, kmin, kmax;
@@ -657,7 +657,7 @@ void BPH_hair_volume_add_segment(HairGrid *grid,
int s;
- for (s = 0; s < num_samples; ++s) {
+ for (s = 0; s < num_samples; s++) {
float x[3], v[3];
int i, j, k;
@@ -672,9 +672,9 @@ void BPH_hair_volume_add_segment(HairGrid *grid,
int kmin = max_ii(floor_int(x[2]) - 2, 0);
int kmax = min_ii(floor_int(x[2]) + 2, res[2] - 1);
- for (k = kmin; k <= kmax; ++k) {
- for (j = jmin; j <= jmax; ++j) {
- for (i = imin; i <= imax; ++i) {
+ for (k = kmin; k <= kmax; k++) {
+ for (j = jmin; j <= jmax; j++) {
+ for (i = imin; i <= imax; i++) {
float loc[3] = {(float)i, (float)j, (float)k};
HairGridVert *vert = grid->verts + i * stride[0] + j * stride[1] + k * stride[2];
@@ -761,9 +761,9 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid,
/* Calculate divergence */
lVector B(num_cellsA);
- for (k = 0; k < resA[2]; ++k) {
- for (j = 0; j < resA[1]; ++j) {
- for (i = 0; i < resA[0]; ++i) {
+ for (k = 0; k < resA[2]; k++) {
+ for (j = 0; j < resA[1]; j++) {
+ for (i = 0; i < resA[0]; i++) {
int u = i * strideA0 + j * strideA1 + k * strideA2;
bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 ||
MARGIN_k1;
@@ -855,9 +855,9 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid,
*/
A.reserve(Eigen::VectorXi::Constant(num_cellsA, 7));
- for (k = 0; k < resA[2]; ++k) {
- for (j = 0; j < resA[1]; ++j) {
- for (i = 0; i < resA[0]; ++i) {
+ for (k = 0; k < resA[2]; k++) {
+ for (j = 0; j < resA[1]; j++) {
+ for (i = 0; i < resA[0]; i++) {
int u = i * strideA0 + j * strideA1 + k * strideA2;
bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 ||
MARGIN_k1;
@@ -897,11 +897,11 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid,
/*int liquid_neighbors = neighbors_lo + neighbors_hi;*/
non_solid_neighbors = 6;
- for (n = 0; n < neighbors_lo; ++n) {
+ for (n = 0; n < neighbors_lo; n++) {
A.insert(neighbor_lo_index[n], u) = -1.0f;
}
A.insert(u, u) = (float)non_solid_neighbors;
- for (n = 0; n < neighbors_hi; ++n) {
+ for (n = 0; n < neighbors_hi; n++) {
A.insert(neighbor_hi_index[n], u) = -1.0f;
}
}
@@ -922,9 +922,9 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid,
if (cg.info() == Eigen::Success) {
/* Calculate velocity = grad(p) */
- for (k = 0; k < resA[2]; ++k) {
- for (j = 0; j < resA[1]; ++j) {
- for (i = 0; i < resA[0]; ++i) {
+ for (k = 0; k < resA[2]; k++) {
+ for (j = 0; j < resA[1]; j++) {
+ for (i = 0; i < resA[0]; i++) {
int u = i * strideA0 + j * strideA1 + k * strideA2;
bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 ||
MARGIN_k1;
@@ -965,9 +965,9 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid,
int slice = (offset - grid->gmin[axis]) / grid->cellsize;
- for (k = 0; k < resA[2]; ++k) {
- for (j = 0; j < resA[1]; ++j) {
- for (i = 0; i < resA[0]; ++i) {
+ for (k = 0; k < resA[2]; k++) {
+ for (j = 0; j < resA[1]; j++) {
+ for (i = 0; i < resA[0]; i++) {
int u = i * strideA0 + j * strideA1 + k * strideA2;
bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 ||
MARGIN_k1;
@@ -1034,7 +1034,7 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid,
}
else {
/* Clear result in case of error */
- for (i = 0, vert = grid->verts; i < num_cells; ++i, ++vert) {
+ for (i = 0, vert = grid->verts; i < num_cells; i++, vert++) {
zero_v3(vert->velocity_smooth);
}
@@ -1066,9 +1066,9 @@ BLI_INLINE void hair_volume_filter_box_convolute(
kernel_offset = minp + (minq + minr * res) * res;
kernel_dq = res;
kernel_dr = res * res;
- for (r = minr; r <= maxr; ++r) {
- for (q = minq; q <= maxq; ++q) {
- for (p = minp; p <= maxp; ++p) {
+ for (r = minr; r <= maxr; r++) {
+ for (q = minq; q <= maxq; q++) {
+ for (p = minp; p <= maxp; p++) {
madd_v3_v3fl(vel_smooth, verts[kernel_offset].velocity, invD);
@@ -1096,20 +1096,20 @@ void BPH_hair_volume_vertex_grid_filter_box(HairVertexGrid *grid, int kernel_siz
invD = 1.0f / (float)(tot * tot * tot);
/* clear values for convolution */
- for (i = 0; i < size; ++i) {
+ for (i = 0; i < size; i++) {
zero_v3(grid->verts[i].velocity_smooth);
}
- for (i = 0; i < grid->res; ++i) {
- for (j = 0; j < grid->res; ++j) {
- for (k = 0; k < grid->res; ++k) {
+ for (i = 0; i < grid->res; i++) {
+ for (j = 0; j < grid->res; j++) {
+ for (k = 0; k < grid->res; k++) {
hair_volume_filter_box_convolute(grid, invD, kernel_sizev, i, j, k);
}
}
}
/* apply as new velocity */
- for (i = 0; i < size; ++i) {
+ for (i = 0; i < size; i++) {
copy_v3_v3(grid->verts[i].velocity, grid->verts[i].velocity_smooth);
}
}
@@ -1134,7 +1134,7 @@ HairGrid *BPH_hair_volume_create_vertex_grid(float cellsize,
scale = 1.0f / cellsize;
sub_v3_v3v3(extent, gmax, gmin);
- for (i = 0; i < 3; ++i) {
+ for (i = 0; i < 3; i++) {
resmin[i] = floor_int(gmin[i] * scale);
resmax[i] = floor_int(gmax[i] * scale) + 1;
@@ -1221,7 +1221,7 @@ static HairGridVert *hair_volume_create_collision_grid(ClothModifierData *clmd,
collgrid = MEM_mallocN(sizeof(HairGridVert) * size, "hair collider voxel data");
/* initialize grid */
- for (i = 0; i < size; ++i) {
+ for (i = 0; i < size; i++) {
zero_v3(collgrid[i].velocity);
collgrid[i].density = 0.0f;
}
@@ -1247,9 +1247,9 @@ static HairGridVert *hair_volume_create_collision_grid(ClothModifierData *clmd,
sub_v3_v3v3(vel, loc1->co, loc0->co);
- for (di = 0; di < 2; ++di) {
- for (dj = 0; dj < 2; ++dj) {
- for (dk = 0; dk < 2; ++dk) {
+ for (di = 0; di < 2; di++) {
+ for (dj = 0; dj < 2; dj++) {
+ for (dk = 0; dk < 2; dk++) {
int voffset = offset + di + (dj + dk * res) * res;
int iw = di + dj * 2 + dk * 4;
diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c
index c2eb7b465e1..d8b3f647591 100644
--- a/source/blender/physics/intern/implicit_blender.c
+++ b/source/blender/physics/intern/implicit_blender.c
@@ -300,7 +300,7 @@ static void print_sparse_matrix(fmatrix3x3 *m)
static void print_lvector(lfVector *v, int numverts)
{
int i;
- for (i = 0; i < numverts; ++i) {
+ for (i = 0; i < numverts; i++) {
if (i > 0) {
printf("\n");
}
@@ -320,12 +320,12 @@ static void print_bfmatrix(fmatrix3x3 *m)
float *t = MEM_callocN(sizeof(float) * size * size, "bfmatrix");
int q, i, j;
- for (q = 0; q < tot; ++q) {
+ for (q = 0; q < tot; q++) {
int k = 3 * m[q].r;
int l = 3 * m[q].c;
- for (j = 0; j < 3; ++j) {
- for (i = 0; i < 3; ++i) {
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++) {
// if (t[k + i + (l + j) * size] != 0.0f) {
// printf("warning: overwriting value at %d, %d\n", m[q].r, m[q].c);
// }
@@ -340,12 +340,12 @@ static void print_bfmatrix(fmatrix3x3 *m)
}
}
- for (j = 0; j < size; ++j) {
+ for (j = 0; j < size; j++) {
if (j > 0 && j % 3 == 0) {
printf("\n");
}
- for (i = 0; i < size; ++i) {
+ for (i = 0; i < size; i++) {
if (i > 0 && i % 3 == 0) {
printf(" ");
}
@@ -560,7 +560,7 @@ DO_INLINE fmatrix3x3 *create_bfmatrix(unsigned int verts, unsigned int springs)
temp[0].scount = springs;
/* vertex part of the matrix is diagonal blocks */
- for (i = 0; i < verts; ++i) {
+ for (i = 0; i < verts; i++) {
init_fmatrix(temp + i, i, i);
}
@@ -1289,7 +1289,7 @@ static int BPH_mass_spring_add_block(Implicit_Data *data, int v1, int v2)
void BPH_mass_spring_clear_constraints(Implicit_Data *data)
{
int i, numverts = data->S[0].vcount;
- for (i = 0; i < numverts; ++i) {
+ for (i = 0; i < numverts; i++) {
unit_m3(data->S[i].m);
zero_v3(data->z[i]);
}
@@ -2001,7 +2001,7 @@ BLI_INLINE void spring_hairbend_estimate_dfdx(Implicit_Data *data,
/* XXX TODO offset targets to account for position dependency */
- for (a = 0; a < 3; ++a) {
+ for (a = 0; a < 3; a++) {
spring_hairbend_forces(
data, i, j, k, goal, stiffness, damping, q, dvec_pos[a], dvec_null[a], f);
copy_v3_v3(dfdx[a], f);
@@ -2010,7 +2010,7 @@ BLI_INLINE void spring_hairbend_estimate_dfdx(Implicit_Data *data,
data, i, j, k, goal, stiffness, damping, q, dvec_neg[a], dvec_null[a], f);
sub_v3_v3(dfdx[a], f);
- for (b = 0; b < 3; ++b) {
+ for (b = 0; b < 3; b++) {
dfdx[a][b] /= delta;
}
}
@@ -2040,7 +2040,7 @@ BLI_INLINE void spring_hairbend_estimate_dfdv(Implicit_Data *data,
/* XXX TODO offset targets to account for position dependency */
- for (a = 0; a < 3; ++a) {
+ for (a = 0; a < 3; a++) {
spring_hairbend_forces(
data, i, j, k, goal, stiffness, damping, q, dvec_null[a], dvec_pos[a], f);
copy_v3_v3(dfdv[a], f);
@@ -2049,7 +2049,7 @@ BLI_INLINE void spring_hairbend_estimate_dfdv(Implicit_Data *data,
data, i, j, k, goal, stiffness, damping, q, dvec_null[a], dvec_neg[a], f);
sub_v3_v3(dfdv[a], f);
- for (b = 0; b < 3; ++b) {
+ for (b = 0; b < 3; b++) {
dfdv[a][b] /= delta;
}
}
diff --git a/source/blender/physics/intern/implicit_eigen.cpp b/source/blender/physics/intern/implicit_eigen.cpp
index 277b62fba7c..9e1c03638d7 100644
--- a/source/blender/physics/intern/implicit_eigen.cpp
+++ b/source/blender/physics/intern/implicit_eigen.cpp
@@ -98,14 +98,14 @@ class fVector : public Eigen::Vector3f {
fVector(const ctype &v)
{
- for (int k = 0; k < 3; ++k) {
+ for (int k = 0; k < 3; k++) {
coeffRef(k) = v[k];
}
}
fVector &operator=(const ctype &v)
{
- for (int k = 0; k < 3; ++k) {
+ for (int k = 0; k < 3; k++) {
coeffRef(k) = v[k];
}
return *this;
@@ -130,8 +130,8 @@ class fMatrix : public Eigen::Matrix3f {
fMatrix(const ctype &v)
{
- for (int k = 0; k < 3; ++k) {
- for (int l = 0; l < 3; ++l) {
+ for (int k = 0; k < 3; k++) {
+ for (int l = 0; l < 3; l++) {
coeffRef(l, k) = v[k][l];
}
}
@@ -139,8 +139,8 @@ class fMatrix : public Eigen::Matrix3f {
fMatrix &operator=(const ctype &v)
{
- for (int k = 0; k < 3; ++k) {
- for (int l = 0; l < 3; ++l) {
+ for (int k = 0; k < 3; k++) {
+ for (int l = 0; l < 3; l++) {
coeffRef(l, k) = v[k][l];
}
}
@@ -212,8 +212,8 @@ struct lMatrixCtor {
{
i *= 3;
j *= 3;
- for (int k = 0; k < 3; ++k) {
- for (int l = 0; l < 3; ++l) {
+ for (int k = 0; k < 3; k++) {
+ for (int l = 0; l < 3; l++) {
m_trips.push_back(Triplet(i + k, j + l, m.coeff(l, k)));
}
}
@@ -223,8 +223,8 @@ struct lMatrixCtor {
{
i *= 3;
j *= 3;
- for (int k = 0; k < 3; ++k) {
- for (int l = 0; l < 3; ++l) {
+ for (int k = 0; k < 3; k++) {
+ for (int l = 0; l < 3; l++) {
m_trips.push_back(Triplet(i + k, j + l, -m.coeff(l, k)));
}
}
@@ -255,7 +255,7 @@ using Eigen::ComputationInfo;
static void print_lvector(const lVector &v)
{
- for (int i = 0; i < v.rows(); ++i) {
+ for (int i = 0; i < v.rows(); i++) {
if (i > 0 && i % 3 == 0) {
printf("\n");
}
@@ -266,12 +266,12 @@ static void print_lvector(const lVector &v)
static void print_lmatrix(const lMatrix &m)
{
- for (int j = 0; j < m.rows(); ++j) {
+ for (int j = 0; j < m.rows(); j++) {
if (j > 0 && j % 3 == 0) {
printf("\n");
}
- for (int i = 0; i < m.cols(); ++i) {
+ for (int i = 0; i < m.cols(); i++) {
if (i > 0 && i % 3 == 0) {
printf(" ");
}
@@ -302,8 +302,8 @@ BLI_INLINE void triplets_m3(TripletList &tlist, float m[3][3], int i, int j)
{
i *= 3;
j *= 3;
- for (int l = 0; l < 3; ++l) {
- for (int k = 0; k < 3; ++k) {
+ for (int l = 0; l < 3; l++) {
+ for (int k = 0; k < 3; k++) {
tlist.push_back(Triplet(i + k, j + l, m[k][l]));
}
}
@@ -313,8 +313,8 @@ BLI_INLINE void triplets_m3fl(TripletList &tlist, float m[3][3], int i, int j, f
{
i *= 3;
j *= 3;
- for (int l = 0; l < 3; ++l) {
- for (int k = 0; k < 3; ++k) {
+ for (int l = 0; l < 3; l++) {
+ for (int k = 0; k < 3; k++) {
tlist.push_back(Triplet(i + k, j + l, m[k][l] * factor));
}
}
@@ -667,7 +667,7 @@ void BPH_mass_spring_set_new_velocity(Implicit_Data *data, int index, const floa
void BPH_mass_spring_clear_constraints(Implicit_Data *data)
{
int numverts = data->numverts;
- for (int i = 0; i < numverts; ++i) {
+ for (int i = 0; i < numverts; i++) {
data->iS.add(i, i, I);
zero_v3(data->z.v3(i));
}
@@ -1236,7 +1236,7 @@ BLI_INLINE void spring_angbend_estimate_dfdx(Implicit_Data *data,
/* XXX TODO offset targets to account for position dependency */
- for (a = 0; a < 3; ++a) {
+ for (a = 0; a < 3; a++) {
spring_angbend_forces(
data, i, j, k, goal, stiffness, damping, q, dvec_pos[a], dvec_null[a], f);
copy_v3_v3(dfdx[a], f);
@@ -1245,7 +1245,7 @@ BLI_INLINE void spring_angbend_estimate_dfdx(Implicit_Data *data,
data, i, j, k, goal, stiffness, damping, q, dvec_neg[a], dvec_null[a], f);
sub_v3_v3(dfdx[a], f);
- for (b = 0; b < 3; ++b) {
+ for (b = 0; b < 3; b++) {
dfdx[a][b] /= delta;
}
}
@@ -1275,7 +1275,7 @@ BLI_INLINE void spring_angbend_estimate_dfdv(Implicit_Data *data,
/* XXX TODO offset targets to account for position dependency */
- for (a = 0; a < 3; ++a) {
+ for (a = 0; a < 3; a++) {
spring_angbend_forces(
data, i, j, k, goal, stiffness, damping, q, dvec_null[a], dvec_pos[a], f);
copy_v3_v3(dfdv[a], f);
@@ -1284,7 +1284,7 @@ BLI_INLINE void spring_angbend_estimate_dfdv(Implicit_Data *data,
data, i, j, k, goal, stiffness, damping, q, dvec_null[a], dvec_neg[a], f);
sub_v3_v3(dfdv[a], f);
- for (b = 0; b < 3; ++b) {
+ for (b = 0; b < 3; b++) {
dfdv[a][b] /= delta;
}
}
diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c
index 23be0d68fb0..1b6466dee68 100644
--- a/source/blender/python/generic/bgl.c
+++ b/source/blender/python/generic/bgl.c
@@ -1366,6 +1366,7 @@ BGL_Wrap(GenVertexArrays, void, (GLsizei, GLuintP));
BGL_Wrap(GetStringi, GLstring, (GLenum, GLuint));
BGL_Wrap(IsVertexArray, GLboolean, (GLuint));
BGL_Wrap(RenderbufferStorage, void, (GLenum, GLenum, GLsizei, GLsizei));
+BGL_Wrap(VertexAttribIPointer, void, (GLuint, GLint, GLenum, GLsizei, GLvoidP));
/* GL_VERSION_3_1 */
BGL_Wrap(BindBufferBase, void, (GLenum, GLuint, GLuint));
@@ -1709,6 +1710,7 @@ PyObject *BPyInit_bgl(void)
PY_MOD_ADD_METHOD(GetStringi);
PY_MOD_ADD_METHOD(IsVertexArray);
PY_MOD_ADD_METHOD(RenderbufferStorage);
+ PY_MOD_ADD_METHOD(VertexAttribIPointer);
}
/* GL_VERSION_3_1 */
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index d10d281c1f9..335dea0a2b6 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -688,6 +688,7 @@ bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group,
/* Preserve prev/next links!!! See T42593. */
prop->prev = prop_exist->prev;
prop->next = prop_exist->next;
+ prop->flag = prop_exist->flag;
IDP_FreePropertyContent(prop_exist);
*prop_exist = *prop;
@@ -896,7 +897,7 @@ static PyObject *BPy_IDGroup_pop(BPy_IDProperty *self, PyObject *args)
pyform = BPy_IDGroup_MapDataToPy(idprop);
if (pyform == NULL) {
- /* ok something bad happened with the pyobject,
+ /* ok something bad happened with the #PyObject,
* so don't remove the prop from the group. if pyform is
* NULL, then it already should have raised an exception.*/
return NULL;
diff --git a/source/blender/python/generic/imbuf_py_api.c b/source/blender/python/generic/imbuf_py_api.c
index 22be0429ea5..6a7f899488b 100644
--- a/source/blender/python/generic/imbuf_py_api.c
+++ b/source/blender/python/generic/imbuf_py_api.c
@@ -88,21 +88,37 @@ PyDoc_STRVAR(py_imbuf_resize_doc,
"\n"
" :arg size: New size.\n"
" :type size: pair of ints\n"
- " :arg method: Method of resizing (TODO)\n"
+ " :arg method: Method of resizing ('FAST', 'BILINEAR')\n"
" :type method: str\n");
static PyObject *py_imbuf_resize(Py_ImBuf *self, PyObject *args, PyObject *kw)
{
PY_IMBUF_CHECK_OBJ(self);
uint size[2];
- char *method = NULL;
+
+ enum { FAST, BILINEAR };
+ const struct PyC_StringEnumItems method_items[] = {
+ {FAST, "FAST"},
+ {BILINEAR, "BILINEAR"},
+ {0, NULL},
+ };
+ struct PyC_StringEnum method = {method_items, FAST};
static const char *_keywords[] = {"size", "method", NULL};
- static _PyArg_Parser _parser = {"(II)|s:resize", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &size[0], &size[1], &method)) {
+ static _PyArg_Parser _parser = {"(II)|O&:resize", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser, &size[0], &size[1], PyC_ParseStringEnum, &method)) {
return NULL;
}
- IMB_scaleImBuf(self->ibuf, UNPACK2(size));
+ if (method.value_found == FAST) {
+ IMB_scalefastImBuf(self->ibuf, UNPACK2(size));
+ }
+ else if (method.value_found == BILINEAR) {
+ IMB_scaleImBuf(self->ibuf, UNPACK2(size));
+ }
+ else {
+ BLI_assert(0);
+ }
Py_RETURN_NONE;
}
@@ -227,6 +243,51 @@ static int py_imbuf_ppm_set(Py_ImBuf *self, PyObject *value, void *UNUSED(closur
return 0;
}
+PyDoc_STRVAR(py_imbuf_filepath_doc, "filepath associated with this image.\n\n:type: string");
+static PyObject *py_imbuf_filepath_get(Py_ImBuf *self, void *UNUSED(closure))
+{
+ PY_IMBUF_CHECK_OBJ(self);
+ ImBuf *ibuf = self->ibuf;
+ return PyC_UnicodeFromByte(ibuf->name);
+}
+
+static int py_imbuf_filepath_set(Py_ImBuf *self, PyObject *value, void *UNUSED(closure))
+{
+ PY_IMBUF_CHECK_INT(self);
+
+ if (!PyUnicode_Check(value)) {
+ PyErr_SetString(PyExc_TypeError, "expected a string!");
+ return -1;
+ }
+
+ ImBuf *ibuf = self->ibuf;
+ Py_ssize_t value_str_len_max = sizeof(ibuf->name);
+ Py_ssize_t value_str_len;
+ const char *value_str = _PyUnicode_AsStringAndSize(value, &value_str_len);
+ if (value_str_len >= value_str_len_max) {
+ PyErr_Format(PyExc_TypeError, "filepath length over %zd", value_str_len_max - 1);
+ return -1;
+ }
+ memcpy(ibuf->name, value_str, value_str_len + 1);
+ return 0;
+}
+
+PyDoc_STRVAR(py_imbuf_planes_doc, "Number of bits associated with this image.\n\n:type: int");
+static PyObject *py_imbuf_planes_get(Py_ImBuf *self, void *UNUSED(closure))
+{
+ PY_IMBUF_CHECK_OBJ(self);
+ ImBuf *imbuf = self->ibuf;
+ return PyLong_FromLong(imbuf->planes);
+}
+
+PyDoc_STRVAR(py_imbuf_channels_doc, "Number of bit-planes.\n\n:type: int");
+static PyObject *py_imbuf_channels_get(Py_ImBuf *self, void *UNUSED(closure))
+{
+ PY_IMBUF_CHECK_OBJ(self);
+ ImBuf *imbuf = self->ibuf;
+ return PyLong_FromLong(imbuf->channels);
+}
+
static PyGetSetDef Py_ImBuf_getseters[] = {
{(char *)"size", (getter)py_imbuf_size_get, (setter)NULL, (char *)py_imbuf_size_doc, NULL},
{(char *)"ppm",
@@ -234,6 +295,13 @@ static PyGetSetDef Py_ImBuf_getseters[] = {
(setter)py_imbuf_ppm_set,
(char *)py_imbuf_ppm_doc,
NULL},
+ {(char *)"filepath",
+ (getter)py_imbuf_filepath_get,
+ (setter)py_imbuf_filepath_set,
+ (char *)py_imbuf_filepath_doc,
+ NULL},
+ {(char *)"planes", (getter)py_imbuf_planes_get, NULL, (char *)py_imbuf_planes_doc, NULL},
+ {(char *)"channels", (getter)py_imbuf_channels_get, NULL, (char *)py_imbuf_channels_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
@@ -258,7 +326,7 @@ static PyObject *py_imbuf_repr(Py_ImBuf *self)
const ImBuf *ibuf = self->ibuf;
if (ibuf != NULL) {
return PyUnicode_FromFormat(
- "<imbuf: address=%p, filename='%s', size=(%d, %d)>", ibuf, ibuf->name, ibuf->x, ibuf->y);
+ "<imbuf: address=%p, filepath='%s', size=(%d, %d)>", ibuf, ibuf->name, ibuf->x, ibuf->y);
}
else {
return PyUnicode_FromString("<imbuf: address=0x0>");
@@ -375,73 +443,73 @@ static PyObject *M_imbuf_new(PyObject *UNUSED(self), PyObject *args, PyObject *k
}
PyDoc_STRVAR(M_imbuf_load_doc,
- ".. function:: load(filename)\n"
+ ".. function:: load(filepath)\n"
"\n"
" Load an image from a file.\n"
"\n"
- " :arg filename: the filename of the image.\n"
- " :type filename: string\n"
+ " :arg filepath: the filepath of the image.\n"
+ " :type filepath: string\n"
" :return: the newly loaded image.\n"
" :rtype: :class:`ImBuf`\n");
static PyObject *M_imbuf_load(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- const char *filename;
+ const char *filepath;
- static const char *_keywords[] = {"filename", NULL};
+ static const char *_keywords[] = {"filepath", NULL};
static _PyArg_Parser _parser = {"s:load", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &filename)) {
+ if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &filepath)) {
return NULL;
}
- const int file = BLI_open(filename, O_BINARY | O_RDONLY, 0);
+ const int file = BLI_open(filepath, O_BINARY | O_RDONLY, 0);
if (file == -1) {
- PyErr_Format(PyExc_IOError, "load: %s, failed to open file '%s'", strerror(errno));
+ PyErr_Format(PyExc_IOError, "load: %s, failed to open file '%s'", strerror(errno), filepath);
return NULL;
}
- ImBuf *ibuf = IMB_loadifffile(file, filename, IB_rect, NULL, filename);
+ ImBuf *ibuf = IMB_loadifffile(file, filepath, IB_rect, NULL, filepath);
close(file);
if (ibuf == NULL) {
PyErr_Format(
- PyExc_ValueError, "load: Unable to recognize image format for file '%s'", filename);
+ PyExc_ValueError, "load: Unable to recognize image format for file '%s'", filepath);
return NULL;
}
- BLI_strncpy(ibuf->name, filename, sizeof(ibuf->name));
+ BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
return Py_ImBuf_CreatePyObject(ibuf);
}
PyDoc_STRVAR(M_imbuf_write_doc,
- ".. function:: write(image, filename)\n"
+ ".. function:: write(image, filepath)\n"
"\n"
" Write an image.\n"
"\n"
" :arg image: the image to write.\n"
" :type image: :class:`ImBuf`\n"
- " :arg filename: the filename of the image.\n"
- " :type filename: string\n");
+ " :arg filepath: the filepath of the image.\n"
+ " :type filepath: string\n");
static PyObject *M_imbuf_write(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
Py_ImBuf *py_imb;
- const char *filename = NULL;
+ const char *filepath = NULL;
- static const char *_keywords[] = {"image", "filename", NULL};
+ static const char *_keywords[] = {"image", "filepath", NULL};
static _PyArg_Parser _parser = {"O!|s:write", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &Py_ImBuf_Type, &py_imb, &filename)) {
+ if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &Py_ImBuf_Type, &py_imb, &filepath)) {
return NULL;
}
- if (filename == NULL) {
- filename = py_imb->ibuf->name;
+ if (filepath == NULL) {
+ filepath = py_imb->ibuf->name;
}
- bool ok = IMB_saveiff(py_imb->ibuf, filename, IB_rect);
+ bool ok = IMB_saveiff(py_imb->ibuf, filepath, IB_rect);
if (ok == false) {
PyErr_Format(
- PyExc_IOError, "write: Unable to write image file (%s) '%s'", strerror(errno), filename);
+ PyExc_IOError, "write: Unable to write image file (%s) '%s'", strerror(errno), filepath);
return NULL;
}
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index ca9f15ed01a..a6983c38f0e 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -231,6 +231,37 @@ int PyC_ParseBool(PyObject *o, void *p)
return 1;
}
+/**
+ * Use with PyArg_ParseTuple's "O&" formatting.
+ */
+int PyC_ParseStringEnum(PyObject *o, void *p)
+{
+ struct PyC_StringEnum *e = p;
+ const char *value = _PyUnicode_AsString(o);
+ if (value == NULL) {
+ PyErr_Format(PyExc_ValueError, "expected a string, got %s", Py_TYPE(o)->tp_name);
+ return 0;
+ }
+ int i;
+ for (i = 0; e->items[i].id; i++) {
+ if (STREQ(e->items[i].id, value)) {
+ e->value_found = e->items[i].value;
+ return 1;
+ }
+ }
+
+ /* Set as a precaution. */
+ e->value_found = -1;
+
+ PyObject *enum_items = PyTuple_New(i);
+ for (i = 0; e->items[i].id; i++) {
+ PyTuple_SET_ITEM(enum_items, i, PyUnicode_FromString(e->items[i].id));
+ }
+ PyErr_Format(PyExc_ValueError, "expected a string in %S, got '%s'", enum_items, value);
+ Py_DECREF(enum_items);
+ return 0;
+}
+
/* silly function, we dont use arg. just check its compatible with __deepcopy__ */
int PyC_CheckArgs_DeepCopy(PyObject *args)
{
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index 4454aa11d77..1f552c3d78d 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -126,6 +126,17 @@ bool PyC_RunString_AsString(const char **imports,
int PyC_ParseBool(PyObject *o, void *p);
+struct PyC_StringEnumItems {
+ int value;
+ const char *id;
+};
+struct PyC_StringEnum {
+ const struct PyC_StringEnumItems *items;
+ int value_found;
+};
+
+int PyC_ParseStringEnum(PyObject *o, void *p);
+
int PyC_CheckArgs_DeepCopy(PyObject *args);
/* Integer parsing (with overflow checks), -1 on error. */
diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c
index b5f4d26220a..70f76896898 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.c
+++ b/source/blender/python/gpu/gpu_py_offscreen.c
@@ -32,6 +32,7 @@
#include "BLI_utildefines.h"
+#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_scene.h"
@@ -238,7 +239,7 @@ static PyObject *bpygpu_offscreen_draw_view3d(BPyGPUOffScreen *self,
BLI_assert(BKE_id_is_in_global_main(&scene->id));
- depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ depsgraph = BKE_scene_get_depsgraph(G_MAIN, scene, view_layer, true);
rv3d_mats = ED_view3d_mats_rv3d_backup(ar->regiondata);
diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c
index cccf75513f9..87091e311f3 100644
--- a/source/blender/python/gpu/gpu_py_shader.c
+++ b/source/blender/python/gpu/gpu_py_shader.c
@@ -26,7 +26,6 @@
#include "BLI_utildefines.h"
#include "GPU_shader.h"
-#include "GPU_shader_interface.h"
#include "../generic/py_capi_utils.h"
#include "../generic/python_utildefines.h"
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index fc945562c98..a5f71e92438 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -231,6 +231,10 @@ if(WITH_OPENAL)
add_definitions(-DWITH_OPENAL)
endif()
+if(WITH_OPENSUBDIV)
+ add_definitions(-DWITH_OPENSUBDIV)
+endif()
+
if(WITH_SDL)
list(APPEND INC_SYS
${SDL_INCLUDE_DIR}
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 8c34699b598..52b35478dd0 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -147,39 +147,28 @@ static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObjec
// PyDoc_STRVAR(bpy_user_resource_doc[] = // now in bpy/utils.py
static PyObject *bpy_user_resource(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- const char *type;
+ const struct PyC_StringEnumItems type_items[] = {
+ {BLENDER_USER_DATAFILES, "DATAFILES"},
+ {BLENDER_USER_CONFIG, "CONFIG"},
+ {BLENDER_USER_SCRIPTS, "SCRIPTS"},
+ {BLENDER_USER_AUTOSAVE, "AUTOSAVE"},
+ {0, NULL},
+ };
+ struct PyC_StringEnum type = {type_items};
+
const char *subdir = NULL;
- int folder_id;
const char *path;
static const char *_keywords[] = {"type", "subdir", NULL};
- static _PyArg_Parser _parser = {"s|s:user_resource", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &type, &subdir)) {
- return NULL;
- }
-
- /* stupid string compare */
- if (STREQ(type, "DATAFILES")) {
- folder_id = BLENDER_USER_DATAFILES;
- }
- else if (STREQ(type, "CONFIG")) {
- folder_id = BLENDER_USER_CONFIG;
- }
- else if (STREQ(type, "SCRIPTS")) {
- folder_id = BLENDER_USER_SCRIPTS;
- }
- else if (STREQ(type, "AUTOSAVE")) {
- folder_id = BLENDER_USER_AUTOSAVE;
- }
- else {
- PyErr_SetString(PyExc_ValueError, "invalid resource argument");
+ static _PyArg_Parser _parser = {"O&|s:user_resource", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, PyC_ParseStringEnum, &type, &subdir)) {
return NULL;
}
/* same logic as BKE_appdir_folder_id_create(),
* but best leave it up to the script author to create */
- path = BKE_appdir_folder_id_user_notest(folder_id, subdir);
+ path = BKE_appdir_folder_id_user_notest(type.value_found, subdir);
return PyC_UnicodeFromByte(path ? path : "");
}
@@ -195,34 +184,25 @@ PyDoc_STRVAR(bpy_system_resource_doc,
" :type path: string\n");
static PyObject *bpy_system_resource(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- const char *type;
+ const struct PyC_StringEnumItems type_items[] = {
+ {BLENDER_SYSTEM_DATAFILES, "DATAFILES"},
+ {BLENDER_SYSTEM_SCRIPTS, "SCRIPTS"},
+ {BLENDER_SYSTEM_PYTHON, "PYTHON"},
+ {0, NULL},
+ };
+ struct PyC_StringEnum type = {type_items};
+
const char *subdir = NULL;
- int folder_id;
const char *path;
static const char *_keywords[] = {"type", "path", NULL};
- static _PyArg_Parser _parser = {"s|s:system_resource", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &type, &subdir)) {
+ static _PyArg_Parser _parser = {"O&|s:system_resource", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, PyC_ParseStringEnum, &type, &subdir)) {
return NULL;
}
- /* stupid string compare */
- if (STREQ(type, "DATAFILES")) {
- folder_id = BLENDER_SYSTEM_DATAFILES;
- }
- else if (STREQ(type, "SCRIPTS")) {
- folder_id = BLENDER_SYSTEM_SCRIPTS;
- }
- else if (STREQ(type, "PYTHON")) {
- folder_id = BLENDER_SYSTEM_PYTHON;
- }
- else {
- PyErr_SetString(PyExc_ValueError, "invalid resource argument");
- return NULL;
- }
-
- path = BKE_appdir_folder_id(folder_id, subdir);
+ path = BKE_appdir_folder_id(type.value_found, subdir);
return PyC_UnicodeFromByte(path ? path : "");
}
@@ -243,33 +223,25 @@ PyDoc_STRVAR(
" :rtype: string\n");
static PyObject *bpy_resource_path(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- const char *type;
+ const struct PyC_StringEnumItems type_items[] = {
+ {BLENDER_RESOURCE_PATH_USER, "USER"},
+ {BLENDER_RESOURCE_PATH_LOCAL, "LOCAL"},
+ {BLENDER_RESOURCE_PATH_SYSTEM, "SYSTEM"},
+ {0, NULL},
+ };
+ struct PyC_StringEnum type = {type_items};
+
int major = BLENDER_VERSION / 100, minor = BLENDER_VERSION % 100;
- int folder_id;
const char *path;
static const char *_keywords[] = {"type", "major", "minor", NULL};
- static _PyArg_Parser _parser = {"s|ii:resource_path", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &type, &major, &minor)) {
- return NULL;
- }
-
- /* stupid string compare */
- if (STREQ(type, "USER")) {
- folder_id = BLENDER_RESOURCE_PATH_USER;
- }
- else if (STREQ(type, "LOCAL")) {
- folder_id = BLENDER_RESOURCE_PATH_LOCAL;
- }
- else if (STREQ(type, "SYSTEM")) {
- folder_id = BLENDER_RESOURCE_PATH_SYSTEM;
- }
- else {
- PyErr_SetString(PyExc_ValueError, "invalid resource argument");
+ static _PyArg_Parser _parser = {"O&|ii:resource_path", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser, PyC_ParseStringEnum, &type, &major, &minor)) {
return NULL;
}
- path = BKE_appdir_folder_id_version(folder_id, (major * 100) + minor, false);
+ path = BKE_appdir_folder_id_version(type.value_found, (major * 100) + minor, false);
return PyC_UnicodeFromByte(path ? path : "");
}
diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c
index a841e974e85..afb2f6b3636 100644
--- a/source/blender/python/intern/bpy_app_build_options.c
+++ b/source/blender/python/intern/bpy_app_build_options.c
@@ -46,6 +46,7 @@ static PyStructSequence_Field app_builtopts_info_fields[] = {
{(char *)"audaspace", NULL},
{(char *)"international", NULL},
{(char *)"openal", NULL},
+ {(char *)"opensubdiv", NULL},
{(char *)"sdl", NULL},
{(char *)"sdl_dynload", NULL},
{(char *)"jack", NULL},
@@ -190,6 +191,12 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
+#ifdef WITH_OPENSUBDIV
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
#ifdef WITH_SDL
SetObjIncref(Py_True);
#else
diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c
index dde3d026d47..2fbefe3be74 100644
--- a/source/blender/python/intern/bpy_app_handlers.c
+++ b/source/blender/python/intern/bpy_app_handlers.c
@@ -24,7 +24,8 @@
#include <Python.h>
#include "BLI_utildefines.h"
-#include "BLI_callbacks.h"
+
+#include "BKE_callbacks.h"
#include "RNA_types.h"
#include "RNA_access.h"
@@ -35,7 +36,10 @@
#include "BPY_extern.h"
-void bpy_app_generic_callback(struct Main *main, struct ID *id, void *arg);
+void bpy_app_generic_callback(struct Main *main,
+ struct PointerRNA **pointers,
+ const int num_pointers,
+ void *arg);
static PyTypeObject BlenderAppCbType;
@@ -80,7 +84,7 @@ static PyStructSequence_Desc app_cb_info_desc = {
};
#if 0
-# if (BLI_CB_EVT_TOT != ARRAY_SIZE(app_cb_info_fields))
+# if (BKE_CB_EVT_TOT != ARRAY_SIZE(app_cb_info_fields))
# error "Callbacks are out of sync"
# endif
#endif
@@ -175,7 +179,7 @@ static PyTypeObject BPyPersistent_Type = {
0, /* tp_free */
};
-static PyObject *py_cb_array[BLI_CB_EVT_TOT] = {NULL};
+static PyObject *py_cb_array[BKE_CB_EVT_TOT] = {NULL};
static PyObject *make_app_cb_info(void)
{
@@ -187,7 +191,7 @@ static PyObject *make_app_cb_info(void)
return NULL;
}
- for (pos = 0; pos < BLI_CB_EVT_TOT; pos++) {
+ for (pos = 0; pos < BKE_CB_EVT_TOT; pos++) {
if (app_cb_info_fields[pos].name == NULL) {
Py_FatalError("invalid callback slots 1");
}
@@ -227,16 +231,16 @@ PyObject *BPY_app_handlers_struct(void)
/* assign the C callbacks */
if (ret) {
- static bCallbackFuncStore funcstore_array[BLI_CB_EVT_TOT] = {{NULL}};
+ static bCallbackFuncStore funcstore_array[BKE_CB_EVT_TOT] = {{NULL}};
bCallbackFuncStore *funcstore;
int pos = 0;
- for (pos = 0; pos < BLI_CB_EVT_TOT; pos++) {
+ for (pos = 0; pos < BKE_CB_EVT_TOT; pos++) {
funcstore = &funcstore_array[pos];
funcstore->func = bpy_app_generic_callback;
funcstore->alloc = 0;
funcstore->arg = POINTER_FROM_INT(pos);
- BLI_callback_add(funcstore, pos);
+ BKE_callback_add(funcstore, pos);
}
}
@@ -251,7 +255,7 @@ void BPY_app_handlers_reset(const short do_all)
gilstate = PyGILState_Ensure();
if (do_all) {
- for (pos = 0; pos < BLI_CB_EVT_TOT; pos++) {
+ for (pos = 0; pos < BKE_CB_EVT_TOT; pos++) {
/* clear list */
PyList_SetSlice(py_cb_array[pos], 0, PY_SSIZE_T_MAX, NULL);
}
@@ -260,7 +264,7 @@ void BPY_app_handlers_reset(const short do_all)
/* save string conversion thrashing */
PyObject *perm_id_str = PyUnicode_FromString(PERMINENT_CB_ID);
- for (pos = 0; pos < BLI_CB_EVT_TOT; pos++) {
+ for (pos = 0; pos < BKE_CB_EVT_TOT; pos++) {
/* clear only items without PERMINENT_CB_ID */
PyObject *ls = py_cb_array[pos];
Py_ssize_t i;
@@ -289,32 +293,55 @@ void BPY_app_handlers_reset(const short do_all)
PyGILState_Release(gilstate);
}
+static PyObject *choose_arguments(PyObject *func, PyObject *args_all, PyObject *args_single)
+{
+ if (!PyFunction_Check(func)) {
+ return args_all;
+ }
+ PyCodeObject *code = (PyCodeObject *)PyFunction_GetCode(func);
+ if (code->co_argcount == 1) {
+ return args_single;
+ }
+ return args_all;
+}
+
/* the actual callback - not necessarily called from py */
-void bpy_app_generic_callback(struct Main *UNUSED(main), struct ID *id, void *arg)
+void bpy_app_generic_callback(struct Main *UNUSED(main),
+ struct PointerRNA **pointers,
+ const int num_pointers,
+ void *arg)
{
PyObject *cb_list = py_cb_array[POINTER_AS_INT(arg)];
if (PyList_GET_SIZE(cb_list) > 0) {
PyGILState_STATE gilstate = PyGILState_Ensure();
- PyObject *args = PyTuple_New(1); /* save python creating each call */
+ const int num_arguments = 2;
+ PyObject *args_all = PyTuple_New(num_arguments); /* save python creating each call */
+ PyObject *args_single = PyTuple_New(1);
PyObject *func;
PyObject *ret;
Py_ssize_t pos;
/* setup arguments */
- if (id) {
- PointerRNA id_ptr;
- RNA_id_pointer_create(id, &id_ptr);
- PyTuple_SET_ITEM(args, 0, pyrna_struct_CreatePyObject(&id_ptr));
+ for (int i = 0; i < num_pointers; ++i) {
+ PyTuple_SET_ITEM(args_all, i, pyrna_struct_CreatePyObject(pointers[i]));
+ }
+ for (int i = num_pointers; i < num_arguments; ++i) {
+ PyTuple_SET_ITEM(args_all, i, Py_INCREF_RET(Py_None));
+ }
+
+ if (num_pointers == 0) {
+ PyTuple_SET_ITEM(args_single, 0, Py_INCREF_RET(Py_None));
}
else {
- PyTuple_SET_ITEM(args, 0, Py_INCREF_RET(Py_None));
+ PyTuple_SET_ITEM(args_single, 0, pyrna_struct_CreatePyObject(pointers[0]));
}
/* Iterate the list and run the callbacks
* note: don't store the list size since the scripts may remove themselves */
for (pos = 0; pos < PyList_GET_SIZE(cb_list); pos++) {
func = PyList_GET_ITEM(cb_list, pos);
+ PyObject *args = choose_arguments(func, args_all, args_single);
ret = PyObject_Call(func, args, NULL);
if (ret == NULL) {
/* Don't set last system variables because they might cause some
@@ -331,7 +358,8 @@ void bpy_app_generic_callback(struct Main *UNUSED(main), struct ID *id, void *ar
}
}
- Py_DECREF(args);
+ Py_DECREF(args_all);
+ Py_DECREF(args_single);
PyGILState_Release(gilstate);
}
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 9e734123caa..6b63d1ef2c3 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -480,7 +480,7 @@ static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr,
if (ret == NULL) {
PyC_Err_PrintWithFunc(py_func);
- for (i = 0; i < len; ++i) {
+ for (i = 0; i < len; i++) {
values[i] = false;
}
}
@@ -488,7 +488,7 @@ static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr,
if (PyC_AsArray(values, ret, len, &PyBool_Type, false, "BoolVectorProperty get") == -1) {
PyC_Err_PrintWithFunc(py_func);
- for (i = 0; i < len; ++i) {
+ for (i = 0; i < len; i++) {
values[i] = false;
}
@@ -724,7 +724,7 @@ static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr,
if (ret == NULL) {
PyC_Err_PrintWithFunc(py_func);
- for (i = 0; i < len; ++i) {
+ for (i = 0; i < len; i++) {
values[i] = 0;
}
}
@@ -732,7 +732,7 @@ static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr,
if (PyC_AsArray(values, ret, len, &PyLong_Type, false, "IntVectorProperty get") == -1) {
PyC_Err_PrintWithFunc(py_func);
- for (i = 0; i < len; ++i) {
+ for (i = 0; i < len; i++) {
values[i] = 0;
}
@@ -968,7 +968,7 @@ static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr,
if (ret == NULL) {
PyC_Err_PrintWithFunc(py_func);
- for (i = 0; i < len; ++i) {
+ for (i = 0; i < len; i++) {
values[i] = 0.0f;
}
}
@@ -976,7 +976,7 @@ static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr,
if (PyC_AsArray(values, ret, len, &PyFloat_Type, false, "FloatVectorProperty get") == -1) {
PyC_Err_PrintWithFunc(py_func);
- for (i = 0; i < len; ++i) {
+ for (i = 0; i < len; i++) {
values[i] = 0.0f;
}
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index b85d48b67da..45a7d2dacd1 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -918,21 +918,21 @@ static PyObject *pyrna_struct_repr(BPy_StructRNA *self)
tmp_str = PyUnicode_FromString(id->name + 2);
- if (RNA_struct_is_ID(self->ptr.type)) {
+ if (RNA_struct_is_ID(self->ptr.type) && (id->flag & LIB_PRIVATE_DATA) == 0) {
ret = PyUnicode_FromFormat(
"bpy.data.%s[%R]", BKE_idcode_to_name_plural(GS(id->name)), tmp_str);
}
else {
const char *path;
- path = RNA_path_from_ID_to_struct(&self->ptr);
+ ID *real_id = NULL;
+ path = RNA_path_from_real_ID_to_struct(G_MAIN, &self->ptr, &real_id);
if (path) {
- if (GS(id->name) == ID_NT) { /* Nodetree paths are not accurate. */
- ret = PyUnicode_FromFormat("bpy.data...%s", path);
- }
- else {
- ret = PyUnicode_FromFormat(
- "bpy.data.%s[%R].%s", BKE_idcode_to_name_plural(GS(id->name)), tmp_str, path);
+ if (real_id != id) {
+ Py_DECREF(tmp_str);
+ tmp_str = PyUnicode_FromString(real_id->name + 2);
}
+ ret = PyUnicode_FromFormat(
+ "bpy.data.%s[%R].%s", BKE_idcode_to_name_plural(GS(real_id->name)), tmp_str, path);
MEM_freeN((void *)path);
}
@@ -1033,20 +1033,23 @@ static PyObject *pyrna_prop_repr_ex(BPy_PropertyRNA *self, const int index_dim,
tmp_str = PyUnicode_FromString(id->name + 2);
- path = RNA_path_from_ID_to_property_index(&self->ptr, self->prop, index_dim, index);
+ /* Note that using G_MAIN is absolutely not ideal, but we have no access to actual Main DB from
+ * here. */
+ ID *real_id = NULL;
+ path = RNA_path_from_real_ID_to_property_index(
+ G_MAIN, &self->ptr, self->prop, index_dim, index, &real_id);
if (path) {
- const char *data_delim = (path[0] == '[') ? "" : ".";
- if (GS(id->name) == ID_NT) { /* Nodetree paths are not accurate. */
- ret = PyUnicode_FromFormat("bpy.data...%s", path);
- }
- else {
- ret = PyUnicode_FromFormat("bpy.data.%s[%R]%s%s",
- BKE_idcode_to_name_plural(GS(id->name)),
- tmp_str,
- data_delim,
- path);
+ if (real_id != id) {
+ Py_DECREF(tmp_str);
+ tmp_str = PyUnicode_FromString(real_id->name + 2);
}
+ const char *data_delim = (path[0] == '[') ? "" : ".";
+ ret = PyUnicode_FromFormat("bpy.data.%s[%R]%s%s",
+ BKE_idcode_to_name_plural(GS(real_id->name)),
+ tmp_str,
+ data_delim,
+ path);
MEM_freeN((void *)path);
}
@@ -1765,7 +1768,12 @@ static int pyrna_py_to_prop(
if (value == Py_None) {
if ((RNA_property_flag(prop) & PROP_NEVER_NULL) == 0) {
if (data) {
- *((char **)data) = (char *)NULL;
+ if (RNA_property_flag(prop) & PROP_THICK_WRAP) {
+ *(char *)data = 0;
+ }
+ else {
+ *((char **)data) = (char *)NULL;
+ }
}
else {
RNA_property_string_set(ptr, prop, NULL);
@@ -1810,7 +1818,12 @@ static int pyrna_py_to_prop(
}
else {
if (data) {
- *((char **)data) = (char *)param;
+ if (RNA_property_flag(prop) & PROP_THICK_WRAP) {
+ BLI_strncpy((char *)data, (char *)param, RNA_property_string_maxlength(prop));
+ }
+ else {
+ *((char **)data) = (char *)param;
+ }
}
else {
RNA_property_string_set_bytes(ptr, prop, param, PyBytes_Size(value));
@@ -1859,7 +1872,12 @@ static int pyrna_py_to_prop(
/* XXX, this is suspect, but needed for function calls,
* need to see if there's a better way. */
if (data) {
- *((char **)data) = (char *)param;
+ if (RNA_property_flag(prop) & PROP_THICK_WRAP) {
+ BLI_strncpy((char *)data, (char *)param, RNA_property_string_maxlength(prop));
+ }
+ else {
+ *((char **)data) = (char *)param;
+ }
}
else {
RNA_property_string_set(ptr, prop, param);
@@ -1910,7 +1928,7 @@ static int pyrna_py_to_prop(
* layout.prop(self.properties, "filepath")
*
* we need to do this trick.
- * if the prop is not an operator type and the pyobject is an operator,
+ * if the prop is not an operator type and the PyObject is an operator,
* use its properties in place of itself.
*
* This is so bad that it is almost a good reason to do away with fake
@@ -3692,9 +3710,9 @@ static PyObject *pyrna_struct_is_property_readonly(BPy_StructRNA *self, PyObject
PyDoc_STRVAR(pyrna_struct_is_property_overridable_library_doc,
".. method:: is_property_overridable_library(property)\n"
"\n"
- " Check if a property is statically overridable.\n"
+ " Check if a property is overridable.\n"
"\n"
- " :return: True when the property is statically overridable.\n"
+ " :return: True when the property is overridable.\n"
" :rtype: boolean\n");
static PyObject *pyrna_struct_is_property_overridable_library(BPy_StructRNA *self, PyObject *args)
{
@@ -3718,14 +3736,13 @@ static PyObject *pyrna_struct_is_property_overridable_library(BPy_StructRNA *sel
return PyBool_FromLong((long)RNA_property_overridable_get(&self->ptr, prop));
}
-PyDoc_STRVAR(
- pyrna_struct_property_overridable_library_set_doc,
- ".. method:: property_overridable_library_set(property)\n"
- "\n"
- " Define a property as statically overridable or not (only for custom properties!).\n"
- "\n"
- " :return: True when the overridable status of the property was successfully set.\n"
- " :rtype: boolean\n");
+PyDoc_STRVAR(pyrna_struct_property_overridable_library_set_doc,
+ ".. method:: property_overridable_library_set(property, overridable)\n"
+ "\n"
+ " Define a property as overridable or not (only for custom properties!).\n"
+ "\n"
+ " :return: True when the overridable status of the property was successfully set.\n"
+ " :rtype: boolean\n");
static PyObject *pyrna_struct_property_overridable_library_set(BPy_StructRNA *self, PyObject *args)
{
PropertyRNA *prop;
@@ -3968,7 +3985,7 @@ static PyObject *pyrna_struct_type_recast(BPy_StructRNA *self)
}
/**
- * \note Return value is borrowed, caller must incref.
+ * \note Return value is borrowed, caller must #Py_INCREF.
*/
static PyObject *pyrna_struct_bl_rna_find_subclass_recursive(PyObject *cls, const char *id)
{
@@ -7175,7 +7192,7 @@ static PyObject *pyrna_srna_Subtype(StructRNA *srna)
#endif
/* Newclass will now have 2 ref's, ???,
- * probably 1 is internal since decrefing here segfaults. */
+ * probably 1 is internal since #Py_DECREF here segfaults. */
/* PyC_ObSpit("new class ref", newclass); */
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index 5e535d0e3ce..8aa6aa91fcf 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -277,7 +277,7 @@ static int pyrna_struct_keyframe_parse(PointerRNA *ptr,
char pyrna_struct_keyframe_insert_doc[] =
".. method:: keyframe_insert(data_path, index=-1, frame=bpy.context.scene.frame_current, "
- "group=\"\")\n"
+ "group=\"\", options=set())\n"
"\n"
" Insert a keyframe on the property given, adding fcurves and animation data when "
"necessary.\n"
@@ -294,7 +294,7 @@ char pyrna_struct_keyframe_insert_doc[] =
" :arg group: The name of the group the F-Curve should be added to if it doesn't exist "
"yet.\n"
" :type group: str\n"
- " :arg options: Optional flags:\n"
+ " :arg options: Optional set of flags:\n"
"\n"
" - ``INSERTKEY_NEEDED`` Only insert keyframes where they're needed in the relevant "
"F-Curves.\n"
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
index 267971408bf..2b3aa29a366 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.c
+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
@@ -176,6 +176,50 @@ static PyObject *Quaternion_to_axis_angle(QuaternionObject *self)
return ret;
}
+PyDoc_STRVAR(Quaternion_to_swing_twist_doc,
+ ".. method:: to_swing_twist(axis)\n"
+ "\n"
+ " Split the rotation into a swing quaternion with the specified\n"
+ "axis fixed at zero, and the remaining twist rotation angle.\n"
+ "\n"
+ " :arg axis: twist axis as a string in ['X', 'Y', 'Z']\n"
+ " :return: swing, twist angle.\n"
+ " :rtype: (:class:`Quaternion`, float) pair\n");
+static PyObject *Quaternion_to_swing_twist(QuaternionObject *self, PyObject *axis_arg)
+{
+ PyObject *ret;
+
+ const char *axis_str = NULL;
+ float swing[4], twist;
+ int axis;
+
+ if (axis_arg && PyUnicode_Check(axis_arg)) {
+ axis_str = _PyUnicode_AsString(axis_arg);
+ }
+
+ if (axis_str && axis_str[0] >= 'X' && axis_str[0] <= 'Z' && axis_str[1] == 0) {
+ axis = axis_str[0] - 'X';
+ }
+ else {
+ PyErr_SetString(PyExc_ValueError,
+ "Quaternion.to_swing_twist(): "
+ "the axis agrument must be "
+ "a string in 'X', 'Y', 'Z'");
+ return NULL;
+ }
+
+ if (BaseMath_ReadCallback(self) == -1) {
+ return NULL;
+ }
+
+ twist = quat_split_swing_and_twist(self->quat, axis, swing, NULL);
+
+ ret = PyTuple_New(2);
+ PyTuple_SET_ITEMS(
+ ret, Quaternion_CreatePyObject(swing, Py_TYPE(self)), PyFloat_FromDouble(twist));
+ return ret;
+}
+
PyDoc_STRVAR(
Quaternion_to_exponential_map_doc,
".. method:: to_exponential_map()\n"
@@ -1368,6 +1412,10 @@ static struct PyMethodDef Quaternion_methods[] = {
(PyCFunction)Quaternion_to_axis_angle,
METH_NOARGS,
Quaternion_to_axis_angle_doc},
+ {"to_swing_twist",
+ (PyCFunction)Quaternion_to_swing_twist,
+ METH_O,
+ Quaternion_to_swing_twist_doc},
{"to_exponential_map",
(PyCFunction)Quaternion_to_exponential_map,
METH_NOARGS,
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index aa7cbadde14..0555c707ed3 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -691,7 +691,8 @@ PyDoc_STRVAR(Vector_to_track_quat_doc,
static PyObject *Vector_to_track_quat(VectorObject *self, PyObject *args)
{
float vec[3], quat[4];
- const char *strack, *sup;
+ const char *strack = NULL;
+ const char *sup = NULL;
short track = 2, up = 1;
if (!PyArg_ParseTuple(args, "|ss:to_track_quat", &strack, &sup)) {
@@ -2350,26 +2351,26 @@ static PyObject *Vector_length_squared_get(VectorObject *self, void *UNUSED(clos
*
* axis_dict = {}
* axis_pos = {'x': 0, 'y': 1, 'z': 2, 'w': 3}
- * axises = 'xyzw'
- * while len(axises) >= 2:
- * for axis_0 in axises:
+ * axis_chars = 'xyzw'
+ * while len(axis_chars) >= 2:
+ * for axis_0 in axis_chars:
* axis_0_pos = axis_pos[axis_0]
- * for axis_1 in axises:
+ * for axis_1 in axis_chars:
* axis_1_pos = axis_pos[axis_1]
* axis_dict[axis_0 + axis_1] = (
* '((%s | SWIZZLE_VALID_AXIS) | '
* '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS))' %
* (axis_0_pos, axis_1_pos))
- * if len(axises) > 2:
- * for axis_2 in axises:
+ * if len(axis_chars) > 2:
+ * for axis_2 in axis_chars:
* axis_2_pos = axis_pos[axis_2]
* axis_dict[axis_0 + axis_1 + axis_2] = (
* '((%s | SWIZZLE_VALID_AXIS) | '
* '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | '
* '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)))' %
* (axis_0_pos, axis_1_pos, axis_2_pos))
- * if len(axises) > 3:
- * for axis_3 in axises:
+ * if len(axis_chars) > 3:
+ * for axis_3 in axis_chars:
* axis_3_pos = axis_pos[axis_3]
* axis_dict[axis_0 + axis_1 + axis_2 + axis_3] = (
* '((%s | SWIZZLE_VALID_AXIS) | '
@@ -2379,7 +2380,7 @@ static PyObject *Vector_length_squared_get(VectorObject *self, void *UNUSED(clos
* %
* (axis_0_pos, axis_1_pos, axis_2_pos, axis_3_pos))
*
- * axises = axises[:-1]
+ * axis_chars = axis_chars[:-1]
* items = list(axis_dict.items())
* items.sort(
* key=lambda a: a[0].replace('x', '0').replace('y', '1').replace('z', '2').replace('w', '3')
diff --git a/source/blender/python/mathutils/mathutils_noise.c b/source/blender/python/mathutils/mathutils_noise.c
index b890295d32f..1b438072329 100644
--- a/source/blender/python/mathutils/mathutils_noise.c
+++ b/source/blender/python/mathutils/mathutils_noise.c
@@ -140,11 +140,11 @@ static void next_state(void)
left = N;
next = state;
- for (j = N - M + 1; --j; p++) {
+ for (j = N - M + 1; j--; p++) {
*p = p[M] ^ TWIST(p[0], p[1]);
}
- for (j = M; --j; p++) {
+ for (j = M; j--; p++) {
*p = p[M - N] ^ TWIST(p[0], p[1]);
}
diff --git a/source/blender/python/rna_dump.py b/source/blender/python/rna_dump.py
index c2ede5664f2..7d469d20110 100644
--- a/source/blender/python/rna_dump.py
+++ b/source/blender/python/rna_dump.py
@@ -133,8 +133,10 @@ seek(bpy.data, 'bpy.data', 0)
'''
for d in dir(bpy.types):
t = getattr(bpy.types, d)
- try: r = t.bl_rna
- except: r = None
+ try:
+ r = t.bl_rna
+ except:
+ r = None
if r:
seek(r, 'bpy.types.' + d + '.bl_rna', 0)
'''
diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c
index 4e5a83555eb..e8c349f6c85 100644
--- a/source/blender/render/intern/source/bake_api.c
+++ b/source/blender/render/intern/source/bake_api.c
@@ -172,8 +172,8 @@ void RE_bake_margin(ImBuf *ibuf, char *mask, const int margin)
*/
static void calc_point_from_barycentric_cage(TriTessFace *triangles_low,
TriTessFace *triangles_cage,
- float mat_low[4][4],
- float mat_cage[4][4],
+ const float mat_low[4][4],
+ const float mat_cage[4][4],
int primitive_id,
float u,
float v,
@@ -214,8 +214,8 @@ static void calc_point_from_barycentric_cage(TriTessFace *triangles_low,
* The returned coordinate is extruded along the normal by cage_extrusion
*/
static void calc_point_from_barycentric_extrusion(TriTessFace *triangles,
- float mat[4][4],
- float imat[4][4],
+ const float mat[4][4],
+ const float imat[4][4],
int primitive_id,
float u,
float v,
@@ -316,7 +316,7 @@ static bool cast_ray_highpoly(BVHTreeFromMesh *treeData,
TriTessFace *triangles[],
BakePixel *pixel_array_low,
BakePixel *pixel_array,
- float mat_low[4][4],
+ const float mat_low[4][4],
BakeHighPolyData *highpoly,
const float co[3],
const float dir[3],
diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c
index 0db1a4b81ae..d3080ebe3ed 100644
--- a/source/blender/render/intern/source/external_engine.c
+++ b/source/blender/render/intern/source/external_engine.c
@@ -509,7 +509,7 @@ static void engine_depsgraph_init(RenderEngine *engine, ViewLayer *view_layer)
Main *bmain = engine->re->main;
Scene *scene = engine->re->scene;
- engine->depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
+ engine->depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
DEG_debug_name_set(engine->depsgraph, "RENDER");
if (engine->re->r.scemode & R_BUTS_PREVIEW) {
diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c
index 9672184cec8..dc7288234b3 100644
--- a/source/blender/render/intern/source/imagetexture.c
+++ b/source/blender/render/intern/source/imagetexture.c
@@ -842,8 +842,8 @@ static void area_sample(TexResult *texr, ImBuf *ibuf, float fx, float fy, afdata
xsd = 1.f / xsam;
ysd = 1.f / ysam;
texr->tr = texr->tg = texr->tb = texr->ta = 0.f;
- for (ys = 0; ys < ysam; ++ys) {
- for (xs = 0; xs < xsam; ++xs) {
+ for (ys = 0; ys < ysam; ys++) {
+ for (xs = 0; xs < xsam; xs++) {
const float su = (xs + ((ys & 1) + 0.5f) * 0.5f) * xsd - 0.5f;
const float sv = (ys + ((xs & 1) + 0.5f) * 0.5f) * ysd - 0.5f;
const float pu = fx + su * AFD->dxt[0] + sv * AFD->dyt[0];
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index b4d0c2147f2..c3125cb72a1 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -48,11 +48,11 @@
#include "BLI_timecode.h"
#include "BLI_fileops.h"
#include "BLI_threads.h"
-#include "BLI_callbacks.h"
#include "BLT_translation.h"
#include "BKE_animsys.h" /* <------ should this be here?, needed for sequencer update */
+#include "BKE_callbacks.h"
#include "BKE_camera.h"
#include "BKE_colortools.h"
#include "BKE_context.h" /* XXX needed by wm_window.h */
@@ -134,6 +134,24 @@ static struct {
ListBase renderlist;
} RenderGlobal = {{NULL, NULL}};
+/* ********* callbacks ******** */
+
+static void render_callback_exec_null(Render *re, Main *bmain, eCbEvent evt)
+{
+ if (re->r.scemode & R_BUTS_PREVIEW) {
+ return;
+ }
+ BKE_callback_exec_null(bmain, evt);
+}
+
+static void render_callback_exec_id(Render *re, Main *bmain, ID *id, eCbEvent evt)
+{
+ if (re->r.scemode & R_BUTS_PREVIEW) {
+ return;
+ }
+ BKE_callback_exec_id(bmain, id, evt);
+}
+
/* ********* alloc and free ******** */
static int do_write_image_or_movie(Render *re,
@@ -226,7 +244,7 @@ static void stats_background(void *UNUSED(arg), RenderStats *rs)
/* NOTE: using G_MAIN seems valid here???
* Not sure it's actually even used anyway, we could as well pass NULL? */
- BLI_callback_exec(G_MAIN, NULL, BLI_CB_EVT_RENDER_STATS);
+ BKE_callback_exec_null(G_MAIN, BKE_CB_EVT_RENDER_STATS);
fputc('\n', stdout);
fflush(stdout);
@@ -926,8 +944,8 @@ static void render_result_rescale(Render *re)
scale_x = (float)result->rectx / re->result->rectx;
scale_y = (float)result->recty / re->result->recty;
- for (x = 0; x < re->result->rectx; ++x) {
- for (y = 0; y < re->result->recty; ++y) {
+ for (x = 0; x < re->result->rectx; x++) {
+ for (y = 0; y < re->result->recty; y++) {
int src_x = x * scale_x;
int src_y = y * scale_y;
int dst_index = y * re->result->rectx + x;
@@ -1637,7 +1655,7 @@ static void do_render_seq(Render *re)
BKE_stamp_info_from_imbuf(rr, ibuf_arr[view_id]);
}
- if (recurs_depth == 0) { /* with nested scenes, only free on toplevel... */
+ if (recurs_depth == 0) { /* With nested scenes, only free on top-level. */
Editing *ed = re->pipeline_scene_eval->ed;
if (ed) {
BKE_sequencer_free_imbuf(re->pipeline_scene_eval, &ed->seqbase, true);
@@ -1953,7 +1971,7 @@ static void update_physics_cache(Render *re,
baker.bmain = re->main;
baker.scene = scene;
baker.view_layer = view_layer;
- baker.depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ baker.depsgraph = BKE_scene_get_depsgraph(re->main, scene, view_layer, true);
baker.bake = 0;
baker.render = 1;
baker.anim_init = 1;
@@ -2069,7 +2087,7 @@ static void render_init_depsgraph(Render *re)
Scene *scene = re->scene;
ViewLayer *view_layer = BKE_view_layer_default_render(re->scene);
- re->pipeline_depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
+ re->pipeline_depsgraph = DEG_graph_new(re->main, scene, view_layer, DAG_EVAL_RENDER);
DEG_debug_name_set(re->pipeline_depsgraph, "RENDER PIPELINE");
/* Make sure there is a correct evaluated scene pointer. */
@@ -2090,7 +2108,7 @@ void RE_RenderFrame(Render *re,
int frame,
const bool write_still)
{
- BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_INIT);
+ render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_INIT);
/* Ugly global still...
* is to prevent preview events and signal subsurfs etc to make full resol. */
@@ -2103,9 +2121,9 @@ void RE_RenderFrame(Render *re,
const RenderData rd = scene->r;
MEM_reset_peak_memory();
- render_init_depsgraph(re);
+ render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_PRE);
- BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_PRE);
+ render_init_depsgraph(re);
do_render_all_options(re);
@@ -2131,14 +2149,16 @@ void RE_RenderFrame(Render *re,
}
/* keep after file save */
- BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_POST);
+ render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_POST);
if (write_still) {
- BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_WRITE);
+ render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_WRITE);
}
}
- BLI_callback_exec(
- re->main, (ID *)scene, G.is_break ? BLI_CB_EVT_RENDER_CANCEL : BLI_CB_EVT_RENDER_COMPLETE);
+ render_callback_exec_id(re,
+ re->main,
+ &scene->id,
+ G.is_break ? BKE_CB_EVT_RENDER_CANCEL : BKE_CB_EVT_RENDER_COMPLETE);
RE_CleanAfterRender(re);
@@ -2429,7 +2449,7 @@ static int do_write_image_or_movie(Render *re,
/* NOTE: using G_MAIN seems valid here???
* Not sure it's actually even used anyway, we could as well pass NULL? */
- BLI_callback_exec(G_MAIN, NULL, BLI_CB_EVT_RENDER_STATS);
+ render_callback_exec_null(re, G_MAIN, BKE_CB_EVT_RENDER_STATS);
BLI_timecode_string_from_time_simple(name, sizeof(name), re->i.lastframetime - render_time);
printf(" (Saving: %s)\n", name);
@@ -2486,6 +2506,10 @@ void RE_RenderAnim(Render *re,
int efra,
int tfra)
{
+ /* Call hooks before taking a copy of scene->r, so user can alter the render settings prior to
+ * copying (e.g. alter the output path). */
+ render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_INIT);
+
const RenderData rd = scene->r;
bMovieHandle *mh = NULL;
const int cfrao = rd.cfra;
@@ -2495,8 +2519,6 @@ void RE_RenderAnim(Render *re,
const bool is_multiview_name = ((rd.scemode & R_MULTIVIEW) != 0 &&
(rd.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL));
- BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_INIT);
-
/* do not fully call for each frame, it initializes & pops output window */
if (!render_initialize_from_main(re, &rd, bmain, scene, single_layer, camera_override, 0, 1)) {
return;
@@ -2660,8 +2682,8 @@ void RE_RenderAnim(Render *re,
re->r.cfra = scene->r.cfra; /* weak.... */
- /* run callbacs before rendering, before the scene is updated */
- BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_PRE);
+ /* run callbacks before rendering, before the scene is updated */
+ render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_PRE);
do_render_all_options(re);
totrendered++;
@@ -2712,8 +2734,8 @@ void RE_RenderAnim(Render *re,
if (G.is_break == false) {
/* keep after file save */
- BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_POST);
- BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_WRITE);
+ render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_POST);
+ render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_WRITE);
}
}
}
@@ -2731,8 +2753,10 @@ void RE_RenderAnim(Render *re,
re->flag &= ~R_ANIMATION;
- BLI_callback_exec(
- re->main, (ID *)scene, G.is_break ? BLI_CB_EVT_RENDER_CANCEL : BLI_CB_EVT_RENDER_COMPLETE);
+ render_callback_exec_id(re,
+ re->main,
+ &scene->id,
+ G.is_break ? BKE_CB_EVT_RENDER_CANCEL : BKE_CB_EVT_RENDER_COMPLETE);
BKE_sound_reset_scene_specs(re->pipeline_scene_eval);
RE_CleanAfterRender(re);
diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c
index 3ede55434b9..c99f5d4075f 100644
--- a/source/blender/render/intern/source/pointdensity.c
+++ b/source/blender/render/intern/source/pointdensity.c
@@ -355,11 +355,11 @@ static void pointdensity_cache_vertex_weight(PointDensity *pd,
return;
}
- for (i = 0, dv = mdef; i < totvert; ++i, ++dv, data_color += 3) {
+ for (i = 0, dv = mdef; i < totvert; i++, dv++, data_color += 3) {
MDeformWeight *dw;
int j;
- for (j = 0, dw = dv->dw; j < dv->totweight; ++j, ++dw) {
+ for (j = 0, dw = dv->dw; j < dv->totweight; j++, dw++) {
if (dw->def_nr == mdef_index) {
copy_v3_fl(data_color, dw->weight);
break;
@@ -832,7 +832,7 @@ void RE_point_density_cache(struct Depsgraph *depsgraph, PointDensity *pd)
{
Scene *scene = DEG_get_evaluated_scene(depsgraph);
- /* Same matricies/resolution as dupli_render_particle_set(). */
+ /* Same matrices/resolution as dupli_render_particle_set(). */
BLI_mutex_lock(&sample_mutex);
cache_pointdensity(depsgraph, scene, pd);
BLI_mutex_unlock(&sample_mutex);
@@ -910,8 +910,8 @@ static void point_density_sample_func(void *__restrict data_v,
}
size_t z = (size_t)iter;
- for (size_t y = 0; y < resolution; ++y) {
- for (size_t x = 0; x < resolution; ++x) {
+ for (size_t y = 0; y < resolution; y++) {
+ for (size_t x = 0; x < resolution; x++) {
size_t index = z * resolution2 + y * resolution + x;
float texvec[3];
float age, vec[3], col[3];
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 13be8701c27..2d9fa9e5ab6 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -102,6 +102,8 @@ void WM_init_opengl(struct Main *bmain);
void WM_check(struct bContext *C);
void WM_reinit_gizmomap_all(struct Main *bmain);
+void WM_script_tag_reload(void);
+
uint *WM_window_pixels_read(struct wmWindowManager *wm, struct wmWindow *win, int r_size[2]);
int WM_window_pixels_x(const struct wmWindow *win);
@@ -153,18 +155,9 @@ void WM_opengl_context_dispose(void *context);
void WM_opengl_context_activate(void *context);
void WM_opengl_context_release(void *context);
-/* defines for 'type' WM_window_open_temp */
-enum {
- WM_WINDOW_RENDER = 1,
- WM_WINDOW_USERPREFS,
- WM_WINDOW_DRIVERS,
- WM_WINDOW_INFO,
- // WM_WINDOW_FILESEL // UNUSED
-};
-
struct wmWindow *WM_window_open(struct bContext *C, const struct rcti *rect);
struct wmWindow *WM_window_open_temp(
- struct bContext *C, int x, int y, int sizex, int sizey, int type);
+ struct bContext *C, const char *title, int x, int y, int sizex, int sizey, int space_type);
void WM_window_set_dpi(wmWindow *win);
bool WM_stereo3d_enabled(struct wmWindow *win, bool only_fullscreen_test);
@@ -493,6 +486,8 @@ bool WM_operator_properties_checker_interval_test(const struct CheckerIntervalPa
#define WM_FILESEL_FILENAME (1 << 2)
#define WM_FILESEL_FILEPATH (1 << 3)
#define WM_FILESEL_FILES (1 << 4)
+/* Show the properties sidebar by default. */
+#define WM_FILESEL_SHOW_PROPS (1 << 5)
/* operator as a python command (resultuing string must be freed) */
char *WM_operator_pystring_ex(struct bContext *C,
@@ -545,6 +540,9 @@ struct wmOperatorTypeMacro *WM_operatortype_macro_define(struct wmOperatorType *
const char *idname);
const char *WM_operatortype_name(struct wmOperatorType *ot, struct PointerRNA *properties);
+char *WM_operatortype_description(struct bContext *C,
+ struct wmOperatorType *ot,
+ struct PointerRNA *properties);
/* wm_uilist_type.c */
void WM_uilisttype_init(void);
@@ -681,6 +679,7 @@ enum {
WM_JOB_TYPE_STUDIOLIGHT,
WM_JOB_TYPE_LIGHT_BAKE,
WM_JOB_TYPE_FSMENU_BOOKMARK_VALIDATE,
+ WM_JOB_TYPE_QUADRIFLOW_REMESH,
/* add as needed, bake, seq proxy build
* if having hard coded values is a problem */
};
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 7fdbf79248b..15ad8cbedc4 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -737,6 +737,12 @@ typedef struct wmOperatorType {
*/
const char *(*get_name)(struct wmOperatorType *, struct PointerRNA *);
+ /**
+ * Return a different description to use in the user interface, based on property values.
+ * The returned string must be freed by the caller, unless NULL.
+ */
+ char *(*get_description)(struct bContext *C, struct wmOperatorType *, struct PointerRNA *);
+
/** rna for properties */
struct StructRNA *srna;
@@ -769,6 +775,16 @@ typedef struct wmOperatorType {
} wmOperatorType;
+/**
+ * Wrapper to reference a #wmOperatorType together with some set properties and other relevant
+ * information to invoke the operator in a customizable way.
+ */
+typedef struct wmOperatorCallParams {
+ struct wmOperatorType *optype;
+ struct PointerRNA *opptr;
+ short opcontext;
+} wmOperatorCallParams;
+
#ifdef WITH_INPUT_IME
/* *********** Input Method Editor (IME) *********** */
/**
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
index 8eefea84ff8..dd568d7baf1 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
@@ -30,7 +30,6 @@
#include "GPU_batch.h"
#include "GPU_glew.h"
-#include "GPU_immediate.h"
#include "RNA_access.h"
#include "RNA_define.h"
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
index 50c98630a16..77950c11c63 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
@@ -34,7 +34,6 @@
#include "BLI_buffer.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
-#include "BLI_math.h"
#include "BKE_context.h"
#include "BKE_main.h"
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index cd140eba55a..4b1abeceebb 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -45,48 +45,106 @@
#include "wm_cursors.h"
#include "wm_window.h"
-/* XXX this still is mess from old code */
+/* Blender custom cursor. */
+typedef struct BCursor {
+ char *small_bm;
+ char *small_mask;
-/* Some simple ghost <-> blender conversions */
-static GHOST_TStandardCursor convert_cursor(int curs)
+ char small_sizex;
+ char small_sizey;
+ char small_hotx;
+ char small_hoty;
+
+ char *big_bm;
+ char *big_mask;
+
+ char big_sizex;
+ char big_sizey;
+ char big_hotx;
+ char big_hoty;
+
+ bool can_invert_color;
+} BCursor;
+
+static BCursor *BlenderCursor[WM_CURSOR_NUM] = {0};
+
+/* Blender cursor to GHOST standard cursor conversion. */
+static GHOST_TStandardCursor convert_to_ghost_standard_cursor(WMCursorType curs)
{
switch (curs) {
- default:
- case CURSOR_STD:
+ case WM_CURSOR_DEFAULT:
return GHOST_kStandardCursorDefault;
- case CURSOR_FACESEL:
- return GHOST_kStandardCursorRightArrow;
- case CURSOR_WAIT:
+ case WM_CURSOR_WAIT:
return GHOST_kStandardCursorWait;
- case CURSOR_EDIT:
+ case WM_CURSOR_EDIT:
+ case WM_CURSOR_CROSS:
return GHOST_kStandardCursorCrosshair;
- case CURSOR_HELP:
-#ifdef __APPLE__
- return GHOST_kStandardCursorLeftRight;
-#else
- return GHOST_kStandardCursorHelp;
-#endif
- case CURSOR_X_MOVE:
+ case WM_CURSOR_X_MOVE:
return GHOST_kStandardCursorLeftRight;
- case CURSOR_Y_MOVE:
+ case WM_CURSOR_Y_MOVE:
return GHOST_kStandardCursorUpDown;
- case CURSOR_PENCIL:
- return GHOST_kStandardCursorPencil;
- case CURSOR_COPY:
+ case WM_CURSOR_COPY:
return GHOST_kStandardCursorCopy;
+ case WM_CURSOR_HAND:
+ return GHOST_kStandardCursorMove;
+ case WM_CURSOR_H_SPLIT:
+ return GHOST_kStandardCursorHorizontalSplit;
+ case WM_CURSOR_V_SPLIT:
+ return GHOST_kStandardCursorVerticalSplit;
+ case WM_CURSOR_STOP:
+ return GHOST_kStandardCursorStop;
+ case WM_CURSOR_KNIFE:
+ return GHOST_kStandardCursorKnife;
+ case WM_CURSOR_NSEW_SCROLL:
+ return GHOST_kStandardCursorNSEWScroll;
+ case WM_CURSOR_NS_SCROLL:
+ return GHOST_kStandardCursorNSScroll;
+ case WM_CURSOR_EW_SCROLL:
+ return GHOST_kStandardCursorEWScroll;
+ case WM_CURSOR_EYEDROPPER:
+ return GHOST_kStandardCursorEyedropper;
+ case WM_CURSOR_N_ARROW:
+ return GHOST_kStandardCursorUpArrow;
+ case WM_CURSOR_S_ARROW:
+ return GHOST_kStandardCursorDownArrow;
+ case WM_CURSOR_PAINT:
+ return GHOST_kStandardCursorCrosshairA;
+ case WM_CURSOR_DOT:
+ return GHOST_kStandardCursorCrosshairB;
+ case WM_CURSOR_CROSSC:
+ return GHOST_kStandardCursorCrosshairC;
+ case WM_CURSOR_ERASER:
+ return GHOST_kStandardCursorEraser;
+ case WM_CURSOR_ZOOM_IN:
+ return GHOST_kStandardCursorZoomIn;
+ case WM_CURSOR_ZOOM_OUT:
+ return GHOST_kStandardCursorZoomOut;
+ case WM_CURSOR_TEXT_EDIT:
+ return GHOST_kStandardCursorText;
+ case WM_CURSOR_PAINT_BRUSH:
+ return GHOST_kStandardCursorPencil;
+ case WM_CURSOR_E_ARROW:
+ return GHOST_kStandardCursorRightArrow;
+ case WM_CURSOR_W_ARROW:
+ return GHOST_kStandardCursorLeftArrow;
+ default:
+ return GHOST_kStandardCursorCustom;
}
}
-static void window_set_custom_cursor(
- wmWindow *win, unsigned char mask[16][2], unsigned char bitmap[16][2], int hotx, int hoty)
+static void window_set_custom_cursor(wmWindow *win,
+ unsigned const char mask[16][2],
+ unsigned char bitmap[16][2],
+ int hotx,
+ int hoty)
{
GHOST_SetCustomCursorShape(
win->ghostwin, (GHOST_TUns8 *)bitmap, (GHOST_TUns8 *)mask, 16, 16, hotx, hoty, true);
}
-static void window_set_custom_cursor_ex(wmWindow *win, BCursor *cursor, int useBig)
+static void window_set_custom_cursor_ex(wmWindow *win, BCursor *cursor)
{
- if (useBig) {
+ if (U.curssize && cursor->big_bm) {
GHOST_SetCustomCursorShape(win->ghostwin,
(GHOST_TUns8 *)cursor->big_bm,
(GHOST_TUns8 *)cursor->big_mask,
@@ -108,60 +166,46 @@ static void window_set_custom_cursor_ex(wmWindow *win, BCursor *cursor, int useB
}
}
-/* Cursor Globals */
-static BCursor *BlenderCursor[BC_NUMCURSORS]; /*Points to static BCursor Structs */
-
void WM_cursor_set(wmWindow *win, int curs)
{
-
if (win == NULL || G.background) {
return; /* Can't set custom cursor before Window init */
}
- if (curs == CURSOR_NONE) {
+ if (curs == WM_CURSOR_NONE) {
GHOST_SetCursorVisibility(win->ghostwin, 0);
return;
}
-#ifdef _WIN32
- /* the default win32 cross cursor is barely visible,
- * only 1 pixel thick, use another one instead */
- if (curs == CURSOR_EDIT) {
- curs = BC_CROSSCURSOR;
- }
-#else
- /* in case of large cursor, also use custom cursor because
- * large cursors don't work for system cursors */
- if (U.curssize && curs == CURSOR_EDIT) {
- curs = BC_CROSSCURSOR;
- }
-#endif
-
GHOST_SetCursorVisibility(win->ghostwin, 1);
- if (curs == CURSOR_STD && win->modalcursor) {
+ if (curs == WM_CURSOR_DEFAULT && win->modalcursor) {
curs = win->modalcursor;
}
win->cursor = curs;
- /* detect if we use system cursor or Blender cursor */
- if (curs >= BC_GHOST_CURSORS) {
- GHOST_SetCursorShape(win->ghostwin, convert_cursor(curs));
+ if (curs < 0 || curs >= WM_CURSOR_NUM) {
+ BLI_assert(!"Invalid cursor number");
+ return;
}
- else {
- if ((curs < SYSCURSOR) || (curs >= BC_NUMCURSORS)) {
- return;
- }
- if (curs == SYSCURSOR) { /* System default Cursor */
- GHOST_SetCursorShape(win->ghostwin, convert_cursor(CURSOR_STD));
- }
- else if ((U.curssize == 0) || (BlenderCursor[curs]->big_bm == NULL)) {
- window_set_custom_cursor_ex(win, BlenderCursor[curs], 0);
+ GHOST_TStandardCursor ghost_cursor = convert_to_ghost_standard_cursor(curs);
+
+ if (ghost_cursor != GHOST_kStandardCursorCustom &&
+ GHOST_HasCursorShape(win->ghostwin, ghost_cursor)) {
+ /* Use native GHOST cursor when available. */
+ GHOST_SetCursorShape(win->ghostwin, ghost_cursor);
+ }
+ else {
+ BCursor *bcursor = BlenderCursor[curs];
+ if (bcursor) {
+ /* Use custom bitmap cursor. */
+ window_set_custom_cursor_ex(win, bcursor);
}
else {
- window_set_custom_cursor_ex(win, BlenderCursor[curs], 1);
+ /* Fallback to default cursor if no bitmap found. */
+ GHOST_SetCursorShape(win->ghostwin, GHOST_kStandardCursorDefault);
}
}
}
@@ -173,7 +217,7 @@ bool WM_cursor_set_from_tool(struct wmWindow *win, const ScrArea *sa, const AReg
}
bToolRef_Runtime *tref_rt = (sa && sa->runtime.tool) ? sa->runtime.tool->runtime : NULL;
- if (tref_rt && tref_rt->cursor != CURSOR_STD) {
+ if (tref_rt && tref_rt->cursor != WM_CURSOR_DEFAULT) {
if (win->modalcursor == 0) {
WM_cursor_set(win, tref_rt->cursor);
win->cursor = tref_rt->cursor;
@@ -210,7 +254,7 @@ void WM_cursor_wait(bool val)
for (; win; win = win->next) {
if (val) {
- WM_cursor_modal_set(win, BC_WAITCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_WAIT);
}
else {
WM_cursor_modal_restore(win);
@@ -407,15 +451,39 @@ void wm_init_cursor_data(void)
/********************** NW_ARROW Cursor **************************/
BEGIN_CURSOR_BLOCK;
static char nw_sbm[] = {
- 0x03, 0x00, 0x05, 0x00, 0x09, 0x00, 0x11, 0x00, 0x21, 0x00, 0x41,
- 0x00, 0x81, 0x00, 0x01, 0x01, 0x01, 0x02, 0xc1, 0x03, 0x49, 0x00,
- 0x8d, 0x00, 0x8b, 0x00, 0x10, 0x01, 0x90, 0x01, 0x60, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x1e, 0x00, 0x3e,
+ 0x00, 0x7e, 0x00, 0xfe, 0x00, 0xfe, 0x01, 0xfe, 0x03, 0xfe, 0x07,
+ 0x7e, 0x00, 0x6e, 0x00, 0xc6, 0x00, 0xc2, 0x00, 0x00, 0x00,
};
static char nw_smsk[] = {
0x03, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x3f, 0x00, 0x7f,
- 0x00, 0xff, 0x00, 0xff, 0x01, 0xff, 0x03, 0xff, 0x03, 0x7f, 0x00,
- 0xff, 0x00, 0xfb, 0x00, 0xf0, 0x01, 0xf0, 0x01, 0x60, 0x00,
+ 0x00, 0xff, 0x00, 0xff, 0x01, 0xff, 0x03, 0xff, 0x07, 0xff, 0x0f,
+ 0xff, 0x0f, 0xff, 0x00, 0xef, 0x01, 0xe7, 0x01, 0xc3, 0x00,
+ };
+
+ static char nw_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
+ 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00,
+ 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xfe,
+ 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00,
+ 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x07,
+ 0x00, 0xfe, 0xff, 0x0f, 0x00, 0xfe, 0xff, 0x1f, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xfe, 0x3f,
+ 0x00, 0x00, 0xfe, 0x3e, 0x00, 0x00, 0x7e, 0x7c, 0x00, 0x00, 0x3e, 0x7c, 0x00, 0x00, 0x1e,
+ 0xf8, 0x00, 0x00, 0x0e, 0xf8, 0x00, 0x00, 0x06, 0xf0, 0x01, 0x00, 0x02, 0xf0, 0x01, 0x00,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char nw_lmsk[] = {
+ 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00,
+ 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01,
+ 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff,
+ 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x0f,
+ 0x00, 0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0x3f, 0x00, 0xff, 0xff, 0x7f, 0x00, 0xff, 0x7f,
+ 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x3f,
+ 0xfc, 0x01, 0x00, 0x1f, 0xfc, 0x01, 0x00, 0x0f, 0xf8, 0x03, 0x00, 0x07, 0xf8, 0x03, 0x00,
+ 0x03, 0xf0, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00,
};
static BCursor NWArrowCursor = {
@@ -424,34 +492,60 @@ void wm_init_cursor_data(void)
nw_smsk,
16,
16,
- 6,
- 7,
+ 0,
+ 0,
/* big */
- NULL,
- NULL,
+ nw_lbm,
+ nw_lmsk,
32,
32,
- 15,
- 15,
+ 0,
+ 0,
/* can invert color */
true,
};
- BlenderCursor[BC_NW_ARROWCURSOR] = &NWArrowCursor;
+ BlenderCursor[WM_CURSOR_DEFAULT] = &NWArrowCursor;
+ BlenderCursor[WM_CURSOR_COPY] = &NWArrowCursor;
+ BlenderCursor[WM_CURSOR_NW_ARROW] = &NWArrowCursor;
END_CURSOR_BLOCK;
///********************** NS_ARROW Cursor *************************/
BEGIN_CURSOR_BLOCK;
static char ns_sbm[] = {
- 0x40, 0x01, 0x20, 0x02, 0x10, 0x04, 0x08, 0x08, 0x04, 0x10, 0x3c,
- 0x1e, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x3c, 0x1e,
- 0x04, 0x10, 0x08, 0x08, 0x10, 0x04, 0x20, 0x02, 0x40, 0x01,
+ 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0x80,
+ 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
+ 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00,
};
static char ns_smsk[] = {
- 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc, 0x1f, 0xfc,
- 0x1f, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xfc, 0x1f,
- 0xfc, 0x1f, 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01,
+ 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc,
+ 0x1f, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xfc, 0x1f,
+ 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00,
+ };
+
+ static char ns_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03,
+ 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff,
+ 0x3f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00,
+ 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0,
+ 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
+ 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char ns_lmsk[] = {
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xf8, 0x07,
+ 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff,
+ 0x7f, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x01, 0x00, 0xe0, 0x01, 0x00, 0x00,
+ 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00,
+ 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01,
+ 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0xe0, 0xff,
+ 0xff, 0x01, 0xc0, 0xff, 0xff, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00,
+ 0xfe, 0x1f, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00,
+ 0x00, 0xe0, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00,
};
static BCursor NSArrowCursor = {
@@ -460,11 +554,11 @@ void wm_init_cursor_data(void)
ns_smsk,
16,
16,
- 6,
+ 7,
7,
/* big */
- NULL,
- NULL,
+ ns_lbm,
+ ns_lmsk,
32,
32,
15,
@@ -473,21 +567,46 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_NS_ARROWCURSOR] = &NSArrowCursor;
+ BlenderCursor[WM_CURSOR_Y_MOVE] = &NSArrowCursor;
+ BlenderCursor[WM_CURSOR_NS_ARROW] = &NSArrowCursor;
END_CURSOR_BLOCK;
/********************** EW_ARROW Cursor *************************/
BEGIN_CURSOR_BLOCK;
static char ew_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x38, 0x1c, 0x2c, 0x34, 0xe6,
- 0x67, 0x03, 0xc0, 0x01, 0x80, 0x03, 0xc0, 0xe6, 0x67, 0x2c, 0x34,
- 0x38, 0x1c, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x18,
+ 0x18, 0x1c, 0x38, 0xfe, 0x7f, 0x1c, 0x38, 0x18, 0x18, 0x10, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char ew_smsk[] = {
- 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x38, 0x1c, 0x3c, 0x3c, 0xfe,
- 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0x3c, 0x3c,
- 0x38, 0x1c, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x20, 0x04, 0x30, 0x0c, 0x38, 0x1c, 0x3c,
+ 0x3c, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0x3c, 0x3c, 0x38, 0x1c,
+ 0x30, 0x0c, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char ew_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x80, 0x00, 0x80, 0x01, 0x80, 0x01, 0xc0, 0x01, 0x80, 0x03, 0xe0, 0x01, 0x80, 0x07, 0xf0,
+ 0x01, 0x80, 0x0f, 0xf8, 0x01, 0x80, 0x1f, 0xfc, 0x01, 0x80, 0x3f, 0xfe, 0xff, 0xff, 0x7f,
+ 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0x01, 0x80, 0x3f, 0xf8, 0x01, 0x80, 0x1f, 0xf0, 0x01, 0x80,
+ 0x0f, 0xe0, 0x01, 0x80, 0x07, 0xc0, 0x01, 0x80, 0x03, 0x80, 0x01, 0x80, 0x01, 0x00, 0x01,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char ew_lmsk[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x80, 0x03,
+ 0xc0, 0x01, 0xc0, 0x03, 0xc0, 0x03, 0xe0, 0x03, 0xc0, 0x07, 0xf0, 0x03, 0xc0, 0x0f, 0xf8,
+ 0x03, 0xc0, 0x1f, 0xfc, 0x03, 0xc0, 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0x03, 0xc0, 0x3f, 0xf8, 0x03, 0xc0,
+ 0x1f, 0xf0, 0x03, 0xc0, 0x0f, 0xe0, 0x03, 0xc0, 0x07, 0xc0, 0x03, 0xc0, 0x03, 0x80, 0x03,
+ 0xc0, 0x01, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static BCursor EWArrowCursor = {
@@ -497,10 +616,10 @@ void wm_init_cursor_data(void)
16,
16,
7,
- 6,
+ 7,
/* big */
- NULL,
- NULL,
+ ew_lbm,
+ ew_lmsk,
32,
32,
15,
@@ -509,45 +628,46 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_EW_ARROWCURSOR] = &EWArrowCursor;
+ BlenderCursor[WM_CURSOR_X_MOVE] = &EWArrowCursor;
+ BlenderCursor[WM_CURSOR_EW_ARROW] = &EWArrowCursor;
END_CURSOR_BLOCK;
/********************** Wait Cursor *****************************/
BEGIN_CURSOR_BLOCK;
static char wait_sbm[] = {
- 0xfe, 0x7f, 0x02, 0x40, 0x02, 0x40, 0x84, 0x21, 0xc8, 0x13, 0xd0,
- 0x0b, 0xa0, 0x04, 0x20, 0x05, 0xa0, 0x04, 0x10, 0x09, 0x88, 0x11,
- 0xc4, 0x23, 0xe2, 0x47, 0xfa, 0x5f, 0x02, 0x40, 0xfe, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0xf0, 0x07, 0xb0, 0x06, 0x60,
+ 0x03, 0xc0, 0x01, 0x80, 0x00, 0x80, 0x00, 0xc0, 0x01, 0x60, 0x03,
+ 0x30, 0x06, 0x10, 0x04, 0xf0, 0x07, 0x00, 0x00, 0x00, 0x00,
};
static char wait_smsk[] = {
- 0xfe, 0x7f, 0xfe, 0x7f, 0x06, 0x60, 0x8c, 0x31, 0xd8, 0x1b, 0xf0,
- 0x0f, 0xe0, 0x06, 0x60, 0x07, 0xe0, 0x06, 0x30, 0x0d, 0x98, 0x19,
- 0xcc, 0x33, 0xe6, 0x67, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f,
+ 0xfc, 0x1f, 0xfc, 0x1f, 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f, 0xf0,
+ 0x07, 0xe0, 0x03, 0xc0, 0x01, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07,
+ 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f, 0xfc, 0x1f, 0xfc, 0x1f,
};
static char wait_lbm[] = {
- 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0x0c, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00,
- 0x30, 0x0c, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00, 0x18, 0x18, 0xc0, 0x03, 0x0c, 0x30, 0x20,
- 0x07, 0x06, 0x60, 0xf0, 0x0f, 0x03, 0xc0, 0xd0, 0x8d, 0x01, 0x80, 0x79, 0xcf, 0x00, 0x00,
- 0xf3, 0x67, 0x00, 0x00, 0x66, 0x37, 0x00, 0x00, 0x8c, 0x33, 0x00, 0x00, 0x0c, 0x32, 0x00,
- 0x00, 0xcc, 0x33, 0x00, 0x00, 0x8c, 0x30, 0x00, 0x00, 0x46, 0x61, 0x00, 0x00, 0x03, 0xc3,
- 0x00, 0x80, 0x01, 0x83, 0x01, 0xc0, 0xc0, 0x03, 0x03, 0x60, 0xa0, 0x05, 0x06, 0x30, 0xf0,
- 0x0f, 0x0c, 0x18, 0xf8, 0x1d, 0x18, 0x0c, 0x5c, 0x3f, 0x30, 0x0c, 0xff, 0x5f, 0x30, 0x0c,
- 0xf7, 0xfe, 0x31, 0xcc, 0xfb, 0x9f, 0x33, 0x0c, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00, 0x30,
- 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f,
+ 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff,
+ 0x7f, 0x00, 0x80, 0x07, 0x78, 0x00, 0x00, 0x0f, 0x3c, 0x00, 0x00, 0x1e, 0x1e, 0x00, 0x00,
+ 0x3c, 0x0f, 0x00, 0x00, 0x38, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x30, 0x03,
+ 0x00, 0x00, 0x38, 0x07, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x3e, 0x1f, 0x00, 0x00, 0x1f,
+ 0x3e, 0x00, 0x80, 0x0f, 0x7c, 0x00, 0x80, 0x07, 0x78, 0x00, 0x80, 0x03, 0x70, 0x00, 0x80,
+ 0x01, 0x60, 0x00, 0x80, 0x01, 0x60, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char wait_lmsk[] = {
- 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff,
- 0x3f, 0x3c, 0x00, 0x00, 0x3c, 0x3c, 0x00, 0x00, 0x1e, 0x78, 0xc0, 0x03, 0x0f, 0xf0, 0xa0,
- 0x87, 0x07, 0xe0, 0xf1, 0xcf, 0x03, 0xc0, 0xf3, 0xef, 0x01, 0x80, 0xff, 0xff, 0x00, 0x00,
- 0xff, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0x3c, 0x3f, 0x00,
- 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xbc, 0x3c, 0x00, 0x00, 0xde, 0x79, 0x00, 0x00, 0x0f, 0xf3,
- 0x00, 0x80, 0x07, 0xe3, 0x01, 0xc0, 0xc3, 0xc3, 0x03, 0xe0, 0xe1, 0x87, 0x07, 0xf0, 0xf0,
- 0x0f, 0x0f, 0x78, 0xf8, 0x1f, 0x1e, 0x3c, 0x7c, 0x3f, 0x3c, 0x3c, 0xff, 0x7f, 0x3c, 0xbc,
- 0xff, 0xff, 0x3d, 0xfc, 0xfb, 0xbf, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
- 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
+ 0xf0, 0xff, 0xff, 0x03, 0xf0, 0xff, 0xff, 0x03, 0xf0, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xff,
+ 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff,
+ 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00,
+ 0xfe, 0x1f, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00,
+ 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xf8, 0x07,
+ 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff,
+ 0x7f, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0,
+ 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xf0, 0xff, 0xff, 0x03,
+ 0xf0, 0xff, 0xff, 0x03, 0xf0, 0xff, 0xff, 0x03,
};
static BCursor WaitCursor = {
@@ -565,25 +685,25 @@ void wm_init_cursor_data(void)
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_WAITCURSOR] = &WaitCursor;
+ BlenderCursor[WM_CURSOR_WAIT] = &WaitCursor;
END_CURSOR_BLOCK;
- /********************** Cross Cursor ***************************/
+ /****************** Normal Cross Cursor ************************/
BEGIN_CURSOR_BLOCK;
static char cross_sbm[] = {
- 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
- 0x01, 0x80, 0x01, 0x7e, 0x7e, 0x7e, 0x7e, 0x80, 0x01, 0x80, 0x01,
- 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x00, 0x00,
+ 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
+ 0x01, 0x00, 0x00, 0x3f, 0xfc, 0x3f, 0xfc, 0x00, 0x00, 0x80, 0x01,
+ 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
};
static char cross_smsk[] = {
- 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
- 0x01, 0xc0, 0x03, 0x7f, 0xfe, 0x7f, 0xfe, 0xc0, 0x03, 0x80, 0x01,
- 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
+ 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0,
+ 0x03, 0x7f, 0xfe, 0x3f, 0xfc, 0x3f, 0xfc, 0x7f, 0xfe, 0xc0, 0x03,
+ 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03,
};
static char cross_lbm[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
@@ -601,9 +721,9 @@ void wm_init_cursor_data(void)
0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
- 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x78, 0x1e, 0x00,
- 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x1f, 0xf8, 0xff, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x70, 0x0e,
- 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
+ 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
@@ -624,121 +744,227 @@ void wm_init_cursor_data(void)
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_CROSSCURSOR] = &CrossCursor;
+ BlenderCursor[WM_CURSOR_EDIT] = &CrossCursor;
+ BlenderCursor[WM_CURSOR_CROSS] = &CrossCursor;
END_CURSOR_BLOCK;
- /********************** EditCross Cursor ***********************/
+ /****************** Painting Cursor ************************/
BEGIN_CURSOR_BLOCK;
- static char editcross_sbm[] = {
- 0x0e, 0x00, 0x11, 0x00, 0x1d, 0x00, 0x19, 0x03, 0x1d, 0x03, 0x11,
- 0x03, 0x0e, 0x03, 0x00, 0x03, 0xf8, 0x7c, 0xf8, 0x7c, 0x00, 0x03,
- 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00,
+ static char paint_sbm[] = {
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x8f, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00,
+ };
+
+ static char paint_smsk[] = {
+ 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x8f, 0x78, 0xcf, 0x79, 0x8f, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0x00, 0x00,
+ };
+ static char paint_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
+ 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0x80, 0x01, 0x7f, 0xfe, 0x80, 0x01, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
};
- static char editcross_smsk[] = {
- 0x0e, 0x00, 0x1f, 0x00, 0x1f, 0x03, 0x1f, 0x03, 0x1f, 0x03, 0x1f,
- 0x03, 0x0e, 0x03, 0x80, 0x07, 0xfc, 0xfc, 0xfc, 0xfc, 0x80, 0x07,
- 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
+ static char paint_lmsk[] = {
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03,
+ 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0,
+ 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x01, 0x7f,
+ 0xff, 0xc1, 0x83, 0xff, 0xff, 0xc1, 0x83, 0xff, 0xfe, 0x80, 0x01, 0x7f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00,
+ 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00,
+ 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00,
};
- static BCursor EditCrossCursor = {
+ static BCursor PaintCursor = {
/* small */
- editcross_sbm,
- editcross_smsk,
+ paint_sbm,
+ paint_smsk,
16,
16,
- 9,
- 8,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ paint_lbm,
+ paint_lmsk,
32,
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_EDITCROSSCURSOR] = &EditCrossCursor;
+ BlenderCursor[WM_CURSOR_PAINT] = &PaintCursor;
END_CURSOR_BLOCK;
- /********************** Box Select *************************/
+ /********************** Dot Cursor ***********************/
BEGIN_CURSOR_BLOCK;
- static char box_sbm[32] = {
- 0x7f, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x06, 0x41, 0x06, 0x41,
- 0x06, 0x7f, 0x06, 0x00, 0x06, 0xe0, 0x79, 0xe0, 0x79, 0x00, 0x06,
- 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00,
+ static char dot_sbm[] = {
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x8f, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00,
};
- static char box_smsk[32] = {
- 0x7f, 0x00, 0x7f, 0x00, 0x63, 0x06, 0x63, 0x06, 0x63, 0x06, 0x7f,
- 0x06, 0x7f, 0x06, 0x00, 0x0f, 0xf0, 0xf9, 0xf0, 0xf9, 0x00, 0x0f,
- 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06,
+ static char dot_smsk[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ static char dot_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
- static BCursor BoxSelCursor = {
+ static char dot_lmsk[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00,
+ 0x00, 0xe0, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static BCursor DotCursor = {
/* small */
- box_sbm,
- box_smsk,
+ dot_sbm,
+ dot_smsk,
16,
16,
- 9,
- 8,
+ 7,
+ 7,
+ /* big */
+ dot_lbm,
+ dot_lmsk,
+ 32,
+ 32,
+ 14,
+ 14,
+ /* don't invert color */
+ false,
+ };
+
+ BlenderCursor[WM_CURSOR_DOT] = &DotCursor;
+ END_CURSOR_BLOCK;
+
+ /************* Minimal Crosshair Cursor ***************/
+ BEGIN_CURSOR_BLOCK;
+ static char crossc_sbm[] = {
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0x55, 0x55, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ };
+
+ static char crossc_smsk[] = {
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+ 0x00, 0x80, 0x00, 0x7f, 0x7f, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00,
+ };
+ static char crossc_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char crossc_lmsk[] = {
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
+ 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
+ 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+ 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x78, 0x1e, 0x00,
+ 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x1f, 0xf8, 0xff, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x70, 0x0e,
+ 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
+ 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ };
+
+ static BCursor CrossCursorC = {
+ /* small */
+ crossc_sbm,
+ crossc_smsk,
+ 16,
+ 16,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ crossc_lbm,
+ crossc_lmsk,
32,
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_BOXSELCURSOR] = &BoxSelCursor;
-
+ BlenderCursor[WM_CURSOR_CROSSC] = &CrossCursorC;
END_CURSOR_BLOCK;
+
/********************** Knife Cursor ***********************/
BEGIN_CURSOR_BLOCK;
static char knife_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x2c, 0x00, 0x5a, 0x00,
- 0x34, 0x00, 0x2a, 0x00, 0x17, 0x80, 0x06, 0x40, 0x03, 0xa0, 0x03,
- 0xd0, 0x01, 0x68, 0x00, 0x1c, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00,
+ 0x0c, 0x00, 0x06, 0x00, 0x0f, 0x80, 0x07, 0xc0, 0x03, 0xe0, 0x01,
+ 0xf0, 0x00, 0x78, 0x00, 0x3c, 0x00, 0x0e, 0x00, 0x00, 0x00,
};
static char knife_smsk[] = {
- 0x00, 0x60, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0xfe, 0x00, 0xfe, 0x00,
- 0x7e, 0x00, 0x7f, 0x80, 0x3f, 0xc0, 0x0e, 0x60, 0x07, 0xb0, 0x07,
- 0xd8, 0x03, 0xec, 0x01, 0x7e, 0x00, 0x1f, 0x00, 0x07, 0x00,
+ 0x00, 0x40, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0x78, 0x00, 0x3c, 0x00,
+ 0x1e, 0x00, 0x0f, 0x80, 0x1f, 0xc0, 0x0f, 0xe0, 0x07, 0xf0, 0x03,
+ 0xf8, 0x01, 0xfc, 0x00, 0x7e, 0x00, 0x3f, 0x00, 0x0f, 0x00,
};
static char knife_lbm[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00,
- 0x00, 0x7f, 0x00, 0x00, 0x80, 0xbf, 0x00, 0x00, 0xc0, 0x5f, 0x00, 0x00, 0xc0, 0x6f, 0x00,
- 0x00, 0xc0, 0x37, 0x00, 0x00, 0xa8, 0x1b, 0x00, 0x00, 0x54, 0x0d, 0x00, 0x00, 0xa8, 0x00,
- 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0xc0, 0x07,
- 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xd0, 0x0f, 0x00, 0x00, 0xe8, 0x07, 0x00, 0x00, 0xf4,
- 0x07, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x80, 0x0e, 0x00, 0x00, 0xc0,
- 0x03, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
+ 0x00, 0x07, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x00, 0x00,
+ 0x00, 0x70, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xfe, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0xe0, 0x1f,
+ 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xfe,
+ 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0xe0,
+ 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char knife_lmsk[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
- 0x80, 0xff, 0x00, 0x00, 0xc0, 0xbf, 0x00, 0x00, 0xe0, 0xdf, 0x00, 0x00, 0xe0, 0xef, 0x00,
- 0x00, 0xf8, 0x77, 0x00, 0x00, 0xfc, 0x3b, 0x00, 0x00, 0xfe, 0x1d, 0x00, 0x00, 0xfe, 0x0f,
- 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0xc0, 0xff, 0x00, 0x00, 0xe0, 0x7f,
- 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xd8, 0x1f, 0x00, 0x00, 0xec, 0x0f, 0x00, 0x00, 0xf6,
- 0x0f, 0x00, 0x00, 0xfb, 0x06, 0x00, 0x80, 0xbd, 0x01, 0x00, 0xc0, 0x6e, 0x00, 0x00, 0xe0,
- 0x1b, 0x00, 0x00, 0xf0, 0x06, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
- 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
+ 0x7c, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
+ 0xc0, 0x1f, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xf8, 0x03, 0x00,
+ 0x00, 0xfc, 0x01, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x80, 0xff, 0x01,
+ 0x00, 0xc0, 0xff, 0x03, 0x00, 0xe0, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf8, 0x7f,
+ 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x80, 0xff,
+ 0x07, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xe0, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf8,
+ 0x7f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x03, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
};
static BCursor KnifeCursor = {
@@ -756,11 +982,11 @@ void wm_init_cursor_data(void)
32,
0,
31,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_KNIFECURSOR] = &KnifeCursor;
+ BlenderCursor[WM_CURSOR_KNIFE] = &KnifeCursor;
END_CURSOR_BLOCK;
@@ -768,9 +994,9 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char vloop_sbm[] = {
- 0x00, 0x00, 0x7e, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x66,
- 0x60, 0x62, 0x6f, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x00, 0x00, 0x60, 0x60, 0x60, 0x6f, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0xfe, 0xf0, 0x96,
+ 0x9f, 0x92, 0x90, 0xf0, 0xf0, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40,
+ 0x20, 0x40, 0xf0, 0xf0, 0x90, 0x90, 0x90, 0x9f, 0xf0, 0xf0,
};
static char vloop_smsk[] = {
@@ -780,27 +1006,27 @@ void wm_init_cursor_data(void)
};
static char vloop_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfc, 0x3f, 0x00,
- 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xfc, 0x03,
- 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x3c, 0x3c, 0x00, 0x3c, 0x3c,
- 0x3c, 0x00, 0x3c, 0x0c, 0x3c, 0xff, 0x3c, 0x0c, 0x3c, 0xff, 0x3c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00,
- 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c,
- 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0xff, 0x3c, 0x00, 0x3c, 0xff, 0x3c,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00,
+ 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xfe, 0x01,
+ 0x00, 0x00, 0xfe, 0x7e, 0x00, 0x7e, 0x7e, 0xff, 0x00, 0xff, 0x3e, 0xc3, 0x00, 0xc3, 0x1e,
+ 0xc3, 0xff, 0xc3, 0x0e, 0xc3, 0xff, 0xc3, 0x06, 0xc3, 0x00, 0xc3, 0x02, 0xff, 0x00, 0xff,
+ 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00,
+ 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18,
+ 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0xc3, 0x00, 0xc3, 0x00, 0xc3, 0xff, 0xc3, 0x00, 0xc3, 0xff, 0xc3, 0x00, 0xc3, 0x00, 0xc3,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x7e, 0x00, 0x7e,
};
static char vloop_lmsk[] = {
- 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
- 0x00, 0xff, 0x3f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f,
- 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0x00, 0xff,
- 0x0f, 0xff, 0x00, 0xff, 0x03, 0x3c, 0x00, 0x3c, 0x03, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00,
- 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c,
- 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
- 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
- 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+ 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x7f, 0x00,
+ 0x00, 0xff, 0x3f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x07,
+ 0x00, 0x00, 0xff, 0x7f, 0x00, 0x7e, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x7f,
+ 0xe7, 0xff, 0xe7, 0x3f, 0xe7, 0xff, 0xe7, 0x1f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0x00, 0xff,
+ 0x07, 0x7e, 0x00, 0x7e, 0x03, 0x38, 0x00, 0x38, 0x01, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00,
+ 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38,
+ 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0xe7, 0xff, 0xe7, 0x00, 0xe7, 0xff, 0xe7, 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x7e, 0x00, 0x7e,
};
static BCursor VLoopCursor = {
@@ -818,26 +1044,50 @@ void wm_init_cursor_data(void)
32,
0,
0,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_VLOOPCURSOR] = &VLoopCursor;
+ BlenderCursor[WM_CURSOR_VERTEX_LOOP] = &VLoopCursor;
END_CURSOR_BLOCK;
/********************** TextEdit Cursor ***********************/
BEGIN_CURSOR_BLOCK;
static char textedit_sbm[] = {
- 0xe0, 0x03, 0x10, 0x04, 0x60, 0x03, 0x40, 0x01, 0x40, 0x01, 0x40,
- 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01,
- 0x40, 0x01, 0x40, 0x01, 0x60, 0x03, 0x10, 0x04, 0xe0, 0x03,
+ 0x00, 0x00, 0x70, 0x07, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+ 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x70, 0x07, 0x00, 0x00,
};
static char textedit_smsk[] = {
- 0xe0, 0x03, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0xc0, 0x01, 0xc0,
+ 0x70, 0x07, 0xf8, 0x0f, 0xf0, 0x07, 0xc0, 0x01, 0xc0, 0x01, 0xc0,
0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01,
- 0xc0, 0x01, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xe0, 0x03,
+ 0xc0, 0x01, 0xc0, 0x01, 0xf0, 0x07, 0xf8, 0x0f, 0x70, 0x07,
+ };
+
+ static char textedit_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xe0, 0x01,
+ 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0,
+ 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00,
+ 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0,
+ 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xff, 0x3f, 0x00,
+ 0x00, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char textedit_lmsk[] = {
+ 0x00, 0x3f, 0x3f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f,
+ 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0,
+ 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00,
+ 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00,
+ 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01,
+ 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0,
+ 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00,
+ 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff, 0x7f, 0x00,
+ 0x80, 0xff, 0x7f, 0x00, 0x00, 0x3f, 0x3f, 0x00,
};
static BCursor TextEditCursor = {
@@ -846,35 +1096,58 @@ void wm_init_cursor_data(void)
textedit_smsk,
16,
16,
- 9,
- 8,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ textedit_lbm,
+ textedit_lmsk,
32,
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_TEXTEDITCURSOR] = &TextEditCursor;
+ BlenderCursor[WM_CURSOR_TEXT_EDIT] = &TextEditCursor;
END_CURSOR_BLOCK;
/********************** Paintbrush Cursor ***********************/
BEGIN_CURSOR_BLOCK;
static char paintbrush_sbm[] = {
-
- 0x00, 0xe0, 0x00, 0x98, 0x00, 0x44, 0x00, 0x42, 0x00, 0x21, 0x80,
- 0x20, 0x40, 0x13, 0x40, 0x17, 0xa0, 0x0b, 0x98, 0x05, 0x04, 0x02,
- 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x81, 0x00, 0x7f, 0x00,
+ 0x00, 0x00, 0x00, 0x30, 0x00, 0x78, 0x00, 0x74, 0x00, 0x2e, 0x00,
+ 0x1f, 0x80, 0x0f, 0xc0, 0x07, 0xe0, 0x03, 0xf0, 0x01, 0xf8, 0x00,
+ 0x7c, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x00, 0x00,
};
static char paintbrush_smsk[] = {
- 0x00, 0xe0, 0x00, 0xf8, 0x00, 0x7c, 0x00, 0x7e, 0x00, 0x3f, 0x80,
- 0x3f, 0xc0, 0x1f, 0xc0, 0x1f, 0xe0, 0x0f, 0xf8, 0x07, 0xfc, 0x03,
- 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xff, 0x00, 0x7f, 0x00,
+ 0x00, 0x30, 0x00, 0x78, 0x00, 0xfc, 0x00, 0xfe, 0x00, 0x7f, 0x80,
+ 0x3f, 0xc0, 0x1f, 0xe0, 0x0f, 0xf0, 0x07, 0xf8, 0x03, 0xfc, 0x01,
+ 0xfe, 0x00, 0x7f, 0x00, 0x3f, 0x00, 0x1f, 0x00, 0x0f, 0x00,
+ };
+
+ static char paintbrush_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x0f, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
+ 0x10, 0x1f, 0x00, 0x00, 0x38, 0x0e, 0x00, 0x00, 0x7c, 0x04, 0x00, 0x00, 0xfe, 0x00, 0x00,
+ 0x00, 0xff, 0x01, 0x00, 0x80, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f, 0x00,
+ 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe, 0x03,
+ 0x00, 0x00, 0xff, 0x01, 0x00, 0x80, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f,
+ 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe,
+ 0x03, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char paintbrush_lmsk[] = {
+ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0xc0,
+ 0x3f, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00,
+ 0xfc, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x80, 0xff, 0x0f, 0x00,
+ 0xc0, 0xff, 0x07, 0x00, 0xe0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x00,
+ 0x00, 0xfc, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x80, 0xff, 0x0f,
+ 0x00, 0xc0, 0xff, 0x07, 0x00, 0xe0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf8, 0xff,
+ 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0xff,
+ 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
};
static BCursor PaintBrushCursor = {
@@ -886,32 +1159,116 @@ void wm_init_cursor_data(void)
0,
15,
/* big */
- NULL,
- NULL,
+ paintbrush_lbm,
+ paintbrush_lmsk,
32,
32,
- 15,
- 15,
- /* can invert color */
- true,
+ 0,
+ 31,
+ /* don't invert color */
+ false,
+ };
+
+ BlenderCursor[WM_CURSOR_PAINT_BRUSH] = &PaintBrushCursor;
+ END_CURSOR_BLOCK;
+
+ /********************** Eraser Cursor ***********************/
+ BEGIN_CURSOR_BLOCK;
+ static char eraser_sbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc, 0x07,
+ 0xfe, 0x03, 0xfe, 0x01, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char eraser_smsk[] = {
+ 0x00, 0x00, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x1f, 0x80, 0x3f, 0xc0,
+ 0x7f, 0xe0, 0xff, 0xf0, 0x7f, 0xf8, 0x3f, 0xfc, 0x1f, 0xfe, 0x0f,
+ 0xff, 0x07, 0xff, 0x03, 0xff, 0x01, 0xff, 0x00, 0x00, 0x00,
+ };
+
+ static char eraser_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x78,
+ 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x86, 0x01, 0x00, 0x00, 0x03, 0x03, 0x00, 0x80,
+ 0x01, 0x06, 0x00, 0xc0, 0x00, 0x0c, 0x00, 0x60, 0x00, 0x18, 0x00, 0x30, 0x00, 0x30, 0x00,
+ 0x18, 0x00, 0x60, 0x00, 0x4c, 0x00, 0xc0, 0x00, 0xe6, 0x00, 0xc0, 0x00, 0xf3, 0x01, 0x60,
+ 0x80, 0xf9, 0x03, 0x30, 0xc0, 0xfc, 0x07, 0x18, 0x60, 0xfe, 0x0f, 0x0c, 0x30, 0xff, 0x1f,
+ 0x06, 0x98, 0xff, 0x3f, 0x03, 0xcc, 0xff, 0x9f, 0x01, 0xe6, 0xff, 0xcf, 0x00, 0xf3, 0xff,
+ 0x67, 0x00, 0xf9, 0xff, 0x33, 0x00, 0xfd, 0xff, 0x19, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfd,
+ 0x7f, 0x06, 0x00, 0xfd, 0x3f, 0x03, 0x00, 0x01, 0x80, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char eraser_lmsk[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x78,
+ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x80,
+ 0xff, 0x07, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0x1f, 0x00, 0xf0, 0xff, 0x3f, 0x00,
+ 0xf8, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0xff, 0x00, 0xfe, 0xff, 0xff, 0x00, 0xff, 0xff, 0x7f,
+ 0x80, 0xff, 0xff, 0x3f, 0xc0, 0xff, 0xff, 0x1f, 0xe0, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0xff,
+ 0x07, 0xf8, 0xff, 0xff, 0x03, 0xfc, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0x00, 0xff, 0xff,
+ 0x7f, 0x00, 0xff, 0xff, 0x3f, 0x00, 0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0x0f, 0x00, 0xff,
+ 0xff, 0x07, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static BCursor EraserCursor = {
+ /* small */
+ eraser_sbm,
+ eraser_smsk,
+ 16,
+ 16,
+ 0,
+ 14,
+ /* big */
+ eraser_lbm,
+ eraser_lmsk,
+ 32,
+ 32,
+ 0,
+ 28,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_PAINTBRUSHCURSOR] = &PaintBrushCursor;
+ BlenderCursor[WM_CURSOR_ERASER] = &EraserCursor;
END_CURSOR_BLOCK;
/********************** Hand Cursor ***********************/
BEGIN_CURSOR_BLOCK;
static char hand_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x80, 0x0d, 0x98, 0x6d, 0x98,
- 0x6d, 0xb0, 0x6d, 0xb0, 0x6d, 0xe0, 0x6f, 0xe6, 0x7f, 0xee, 0x7f,
- 0xfc, 0x3f, 0xf8, 0x3f, 0xf0, 0x1f, 0xc0, 0x1f, 0xc0, 0x1f,
+ 0x00, 0x00, 0x80, 0x01, 0x80, 0x0d, 0x98, 0x6d, 0xb8, 0x6d, 0xb0,
+ 0x6d, 0xb0, 0x6d, 0xe0, 0x6f, 0xe6, 0x7f, 0xee, 0x7f, 0x7c, 0x35,
+ 0x78, 0x35, 0x70, 0x15, 0x60, 0x15, 0xc0, 0x1f, 0xc0, 0x1f,
};
static char hand_smsk[] = {
- 0x00, 0x00, 0x80, 0x01, 0xc0, 0x0f, 0xd8, 0x7f, 0xfc, 0xff, 0xfc,
- 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xfe, 0x7f, 0xfc, 0x7f, 0xf8, 0x3f, 0xf0, 0x3f, 0xe0, 0x3f,
+ 0x80, 0x01, 0xc0, 0x0f, 0xd8, 0x7f, 0xfc, 0xff, 0xfc, 0xff, 0xf8,
+ 0xff, 0xf8, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f,
+ 0xfc, 0x7f, 0xf8, 0x3f, 0xf0, 0x3f, 0xe0, 0x3f, 0xe0, 0x3f,
+ };
+
+ static char hand_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x30, 0x0f,
+ 0x00, 0x00, 0x78, 0xcf, 0x00, 0x00, 0x78, 0xef, 0x01, 0x00, 0x78, 0xef, 0x01, 0x00, 0x78,
+ 0xef, 0x01, 0x00, 0x78, 0xef, 0x1d, 0x00, 0x78, 0xef, 0x3d, 0x00, 0x78, 0xef, 0x3d, 0x00,
+ 0x78, 0xef, 0x3d, 0x00, 0x78, 0xef, 0x3d, 0x00, 0x78, 0xef, 0x3d, 0x70, 0x78, 0xef, 0x3d,
+ 0xf0, 0x78, 0xef, 0x3d, 0xf0, 0xf8, 0xff, 0x3d, 0xf0, 0xf8, 0xff, 0x3d, 0xf0, 0xf8, 0xff,
+ 0x3f, 0xf0, 0xb9, 0xf7, 0x3f, 0xe0, 0xbb, 0xf7, 0x3f, 0xe0, 0xbf, 0xf7, 0x3e, 0xe0, 0xbf,
+ 0xf7, 0x3e, 0xc0, 0xbf, 0xf7, 0x3e, 0x80, 0xbf, 0xf7, 0x3e, 0x80, 0xbf, 0xf7, 0x3e, 0x00,
+ 0xbf, 0xf7, 0x1e, 0x00, 0xbe, 0xf7, 0x1e, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x0f,
+ 0x00, 0xf8, 0xff, 0x07, 0x00, 0xf8, 0xff, 0x07,
+ };
+
+ static char hand_lmsk[] = {
+ 0x00, 0x00, 0x0f, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc, 0xff,
+ 0x01, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc,
+ 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x7f, 0x00,
+ 0xfc, 0xff, 0x7f, 0x60, 0xfc, 0xff, 0x7f, 0xf8, 0xfc, 0xff, 0x7f, 0xf8, 0xfd, 0xff, 0x7f,
+ 0xfc, 0xfd, 0xff, 0x7f, 0xfc, 0xfd, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x7f, 0xf8, 0xff, 0xff,
+ 0x7f, 0xf8, 0xff, 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x7f, 0xf0, 0xff,
+ 0xff, 0x7f, 0xe0, 0xff, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0x7f, 0xc0, 0xff, 0xff, 0x7f, 0x80,
+ 0xff, 0xff, 0x7f, 0x80, 0xff, 0xff, 0x3f, 0x00, 0xff, 0xff, 0x3f, 0x00, 0xfe, 0xff, 0x1f,
+ 0x00, 0xfe, 0xff, 0x1f, 0x00, 0xfc, 0xff, 0x1f,
};
static BCursor HandCursor = {
@@ -923,17 +1280,17 @@ void wm_init_cursor_data(void)
8,
8,
/* big */
- NULL,
- NULL,
+ hand_lbm,
+ hand_lmsk,
32,
32,
- 15,
- 15,
- /* can invert color */
- true,
+ 17,
+ 17,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_HANDCURSOR] = &HandCursor;
+ BlenderCursor[WM_CURSOR_HAND] = &HandCursor;
END_CURSOR_BLOCK;
@@ -941,15 +1298,39 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char nsewscroll_sbm[] = {
- 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xc0, 0x03, 0x00, 0x00, 0x00,
- 0x00, 0x0c, 0x30, 0x0e, 0x70, 0x0e, 0x70, 0x0c, 0x30, 0x00, 0x00,
- 0x00, 0x00, 0xc0, 0x03, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0x40, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x30, 0x06, 0x60, 0x06, 0x60, 0x0c, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x02, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00,
};
static char nsewscroll_smsk[] = {
- 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x0c,
- 0x30, 0x1e, 0x78, 0x1f, 0xf8, 0x1f, 0xf8, 0x1e, 0x78, 0x0c, 0x30,
- 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01,
+ 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0x40, 0x02, 0x0c,
+ 0x30, 0x1e, 0x78, 0x0f, 0xf0, 0x0f, 0xf8, 0x1e, 0x78, 0x0c, 0x30,
+ 0x40, 0x02, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01,
+ };
+
+ static char nsewscroll_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07,
+ 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0x38,
+ 0x1c, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x02, 0xe0,
+ 0x00, 0x00, 0x07, 0xf0, 0x01, 0x80, 0x0f, 0xf8, 0x00, 0x00, 0x1f, 0x7c, 0x00, 0x00, 0x3e,
+ 0x3e, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x3e, 0xf8, 0x00, 0x00,
+ 0x1f, 0xf0, 0x01, 0x80, 0x0f, 0xe0, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00,
+ 0xf8, 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xc0, 0x03, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char nsewscroll_lmsk[] = {
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xf0, 0x0f,
+ 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x7c,
+ 0x3e, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x40, 0x10, 0x08, 0x02, 0xe0, 0x00, 0x00, 0x07, 0xf0,
+ 0x01, 0x80, 0x0f, 0xf8, 0x03, 0xc0, 0x1f, 0xfc, 0x01, 0x80, 0x3f, 0xfe, 0x00, 0x00, 0x7f,
+ 0x7f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0x7f, 0xfc, 0x01, 0x80,
+ 0x3f, 0xf8, 0x03, 0xc0, 0x1f, 0xf0, 0x01, 0x80, 0x0f, 0xe0, 0x00, 0x00, 0x07, 0x40, 0x10,
+ 0x08, 0x02, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00,
+ 0xfc, 0x3f, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xe0, 0x07, 0x00,
+ 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00,
};
static BCursor NSEWScrollCursor = {
@@ -958,11 +1339,11 @@ void wm_init_cursor_data(void)
nsewscroll_smsk,
16,
16,
- 8,
- 8,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ nsewscroll_lbm,
+ nsewscroll_lmsk,
32,
32,
15,
@@ -971,7 +1352,7 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_NSEW_SCROLLCURSOR] = &NSEWScrollCursor;
+ BlenderCursor[WM_CURSOR_NSEW_SCROLL] = &NSEWScrollCursor;
END_CURSOR_BLOCK;
@@ -979,15 +1360,39 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char nsscroll_sbm[] = {
- 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xc0, 0x03, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xc0, 0x03, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0x70, 0x07, 0x20,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02,
+ 0x70, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00,
};
static char nsscroll_smsk[] = {
- 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01,
+ 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0x70,
+ 0x07, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x70, 0x07,
+ 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00,
+ };
+
+ static char nsscroll_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03,
+ 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff,
+ 0x3f, 0x00, 0x00, 0x3e, 0x1f, 0x00, 0x00, 0x1c, 0x0e, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x1c,
+ 0x0e, 0x00, 0x00, 0x3e, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
+ 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char nsscroll_lmsk[] = {
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xf8, 0x07,
+ 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff,
+ 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x3e, 0x1f, 0x00, 0x00, 0x1c, 0x0e, 0x00, 0x00,
+ 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x1c, 0x0e, 0x00, 0x00, 0x3e,
+ 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00,
+ 0xfe, 0x1f, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00,
+ 0x00, 0xe0, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00,
};
static BCursor NSScrollCursor = {
@@ -996,11 +1401,11 @@ void wm_init_cursor_data(void)
nsscroll_smsk,
16,
16,
- 8,
- 8,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ nsscroll_lbm,
+ nsscroll_lmsk,
32,
32,
15,
@@ -1009,7 +1414,7 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_NS_SCROLLCURSOR] = &NSScrollCursor;
+ BlenderCursor[WM_CURSOR_NS_SCROLL] = &NSScrollCursor;
END_CURSOR_BLOCK;
@@ -1017,15 +1422,39 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char ewscroll_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x0c, 0x30, 0x0e, 0x70, 0x0e, 0x70, 0x0c, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x38,
+ 0x1c, 0x1c, 0x38, 0x0e, 0x70, 0x1c, 0x38, 0x38, 0x1c, 0x10, 0x08,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char ewscroll_smsk[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c,
- 0x30, 0x1e, 0x78, 0x1f, 0xf8, 0x1f, 0xf8, 0x1e, 0x78, 0x0c, 0x30,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x38, 0x1c, 0x7c,
+ 0x3e, 0x3e, 0x7c, 0x1f, 0xf8, 0x3e, 0x7c, 0x7c, 0x3e, 0x38, 0x1c,
+ 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char ewscroll_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0xc0, 0x01, 0x80, 0x03, 0xe0, 0x03, 0xc0, 0x07, 0xf0,
+ 0x07, 0xe0, 0x0f, 0xf8, 0x03, 0xc0, 0x1f, 0xfc, 0x01, 0x80, 0x3f, 0xfe, 0x00, 0x00, 0x7f,
+ 0xfe, 0x00, 0x00, 0x7f, 0xfc, 0x01, 0x80, 0x3f, 0xf8, 0x03, 0xc0, 0x1f, 0xf0, 0x07, 0xe0,
+ 0x0f, 0xe0, 0x03, 0xc0, 0x07, 0xc0, 0x01, 0x80, 0x03, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char ewscroll_lmsk[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
+ 0x00, 0x01, 0xc0, 0x01, 0x80, 0x03, 0xe0, 0x03, 0xc0, 0x07, 0xf0, 0x07, 0xe0, 0x0f, 0xf8,
+ 0x0f, 0xf0, 0x1f, 0xfc, 0x07, 0xe0, 0x3f, 0xfe, 0x03, 0xc0, 0x7f, 0xff, 0x01, 0x80, 0xff,
+ 0xff, 0x01, 0x80, 0xff, 0xfe, 0x03, 0xc0, 0x7f, 0xfc, 0x07, 0xe0, 0x3f, 0xf8, 0x0f, 0xf0,
+ 0x1f, 0xf0, 0x07, 0xe0, 0x0f, 0xe0, 0x03, 0xc0, 0x07, 0xc0, 0x01, 0x80, 0x03, 0x80, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static BCursor EWScrollCursor = {
@@ -1034,11 +1463,11 @@ void wm_init_cursor_data(void)
ewscroll_smsk,
16,
16,
- 8,
- 8,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ ewscroll_lbm,
+ ewscroll_lmsk,
32,
32,
15,
@@ -1047,7 +1476,7 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_EW_SCROLLCURSOR] = &EWScrollCursor;
+ BlenderCursor[WM_CURSOR_EW_SCROLL] = &EWScrollCursor;
END_CURSOR_BLOCK;
@@ -1055,15 +1484,39 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char eyedropper_sbm[] = {
- 0x00, 0x30, 0x00, 0x48, 0x00, 0x85, 0x80, 0x82, 0x40, 0x40, 0x80,
- 0x20, 0x40, 0x11, 0xa0, 0x23, 0xd0, 0x15, 0xe8, 0x0a, 0x74, 0x01,
- 0xb4, 0x00, 0x4a, 0x00, 0x35, 0x00, 0x08, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x60, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x17, 0x00,
+ 0x0e, 0x00, 0x1d, 0x80, 0x0b, 0xc0, 0x01, 0xe0, 0x00, 0x70, 0x00,
+ 0x38, 0x00, 0x1c, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x00, 0x00,
};
static char eyedropper_smsk[] = {
- 0x00, 0x30, 0x00, 0x78, 0x00, 0xfd, 0x80, 0xff, 0xc0, 0x7f, 0x80,
- 0x3f, 0xc0, 0x1f, 0xe0, 0x3f, 0xf0, 0x1f, 0xf8, 0x0b, 0xfc, 0x01,
- 0xfc, 0x00, 0x7e, 0x00, 0x3f, 0x00, 0x0c, 0x00, 0x04, 0x00,
+ 0x00, 0x60, 0x00, 0xf0, 0x00, 0xfa, 0x00, 0x7f, 0x80, 0x3f, 0x00,
+ 0x1f, 0x80, 0x3f, 0xc0, 0x1f, 0xe0, 0x0b, 0xf0, 0x01, 0xf8, 0x00,
+ 0x7c, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0x0f, 0x00, 0x03, 0x00,
+ };
+
+ static char eyedropper_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x7f, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe4, 0x3f, 0x00, 0x00,
+ 0xee, 0x1f, 0x00, 0x00, 0xdf, 0x0f, 0x00, 0x00, 0xbf, 0x07, 0x00, 0x00, 0x7e, 0x03, 0x00,
+ 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfb, 0x01, 0x00, 0x80, 0xf7, 0x03, 0x00, 0xc0, 0xef, 0x01,
+ 0x00, 0xe0, 0xcf, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xb8, 0x03, 0x00, 0x00, 0xdc, 0x01,
+ 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x80, 0x3b, 0x00, 0x00, 0xc0, 0x1d,
+ 0x00, 0x00, 0xe0, 0x0e, 0x00, 0x00, 0x70, 0x07, 0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, 0xf8,
+ 0x01, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char eyedropper_lmsk[] = {
+ 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x80,
+ 0xff, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0xe4, 0xff, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00,
+ 0xff, 0x3f, 0x00, 0x80, 0xff, 0x1f, 0x00, 0x80, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00,
+ 0x00, 0xff, 0x03, 0x00, 0x80, 0xff, 0x03, 0x00, 0xc0, 0xff, 0x07, 0x00, 0xe0, 0xff, 0x03,
+ 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf8, 0xcf, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe, 0x03,
+ 0x00, 0x00, 0xff, 0x01, 0x00, 0x80, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f,
+ 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfc,
+ 0x03, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
};
static BCursor EyedropperCursor = {
@@ -1072,108 +1525,134 @@ void wm_init_cursor_data(void)
eyedropper_smsk,
16,
16,
- 1,
+ 0,
15,
/* big */
- NULL,
- NULL,
+ eyedropper_lbm,
+ eyedropper_lmsk,
32,
32,
- 15,
- 15,
- /* can invert color */
- true,
+ 1,
+ 30,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_EYEDROPPER_CURSOR] = &EyedropperCursor;
+ BlenderCursor[WM_CURSOR_EYEDROPPER] = &EyedropperCursor;
END_CURSOR_BLOCK;
/********************** Swap Area Cursor ***********************/
BEGIN_CURSOR_BLOCK;
static char swap_sbm[] = {
- 0xc0, 0xff, 0x40, 0x80, 0x40, 0x80, 0x40, 0x9c, 0x40, 0x98, 0x40,
- 0x94, 0x00, 0x82, 0xfe, 0x80, 0x7e, 0xfd, 0xbe, 0x01, 0xda, 0x01,
+ 0xc0, 0xff, 0x40, 0x80, 0x40, 0xbc, 0x40, 0xb8, 0x40, 0xb8, 0x40,
+ 0xa4, 0x00, 0x82, 0xfe, 0x81, 0x7e, 0x81, 0xbe, 0xfd, 0xda, 0x01,
0xe2, 0x01, 0xe2, 0x01, 0xc2, 0x01, 0xfe, 0x01, 0x00, 0x00,
};
static char swap_smsk[] = {
0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0x03,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03,
};
+ static char swap_lbm[] = {
+ 0x00, 0xe0, 0xff, 0xff, 0x00, 0x20, 0x00, 0x80, 0x00, 0x20, 0x00, 0x80, 0x00, 0x20, 0xf8,
+ 0x9f, 0x00, 0x20, 0xf0, 0x9f, 0x00, 0x20, 0xe0, 0x9f, 0x00, 0x20, 0xc0, 0x9f, 0x00, 0x20,
+ 0x80, 0x9f, 0x00, 0x20, 0xc0, 0x9f, 0x00, 0x20, 0xe0, 0x9e, 0x00, 0x20, 0x70, 0x9c, 0x00,
+ 0x20, 0x38, 0x98, 0x00, 0x20, 0x1c, 0x90, 0x00, 0x00, 0x0e, 0x80, 0xfe, 0xff, 0x07, 0x80,
+ 0xfe, 0x7f, 0x03, 0x80, 0xfe, 0x3f, 0x02, 0x80, 0xfe, 0x1f, 0x03, 0x80, 0xfe, 0x8f, 0xfb,
+ 0xff, 0xf6, 0xc7, 0x03, 0x00, 0xe6, 0xe3, 0x03, 0x00, 0xc6, 0xf1, 0x03, 0x00, 0x86, 0xf8,
+ 0x03, 0x00, 0x06, 0xfc, 0x03, 0x00, 0x06, 0xfe, 0x03, 0x00, 0x06, 0xfc, 0x03, 0x00, 0x06,
+ 0xf8, 0x03, 0x00, 0x06, 0xf0, 0x03, 0x00, 0x06, 0xe0, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00,
+ 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char swap_lmsk[] = {
+ 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff,
+ 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0,
+ 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00,
+ 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff,
+ 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff,
+ 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00,
+ 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00,
+ };
+
static BCursor SwapCursor = {
/* small */
swap_sbm,
swap_smsk,
16,
16,
- 8,
- 8,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ swap_lbm,
+ swap_lmsk,
32,
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_SWAPAREA_CURSOR] = &SwapCursor;
+ BlenderCursor[WM_CURSOR_SWAP_AREA] = &SwapCursor;
END_CURSOR_BLOCK;
- /********************** Horizontal Split Cursor ***********************/
+ /********************** Vertical Split Cursor ***********************/
BEGIN_CURSOR_BLOCK;
- static char hsplit_sbm[] = {
- 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x88,
- 0x08, 0x8C, 0x18, 0x8E, 0x38, 0x8C, 0x18, 0x88, 0x08, 0x80, 0x00,
- 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ static char vsplit_sbm[] = {
+ 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x88,
+ 0x11, 0x8c, 0x31, 0x86, 0x61, 0x86, 0x61, 0x8c, 0x31, 0x88, 0x11,
+ 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
};
- static char hsplit_smsk[] = {
- 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0xD0, 0x05, 0xD8, 0x0D, 0xDC,
- 0x1D, 0xDE, 0x3D, 0xDF, 0x7D, 0xDE, 0x3D, 0xDC, 0x1D, 0xD8, 0x0D,
- 0xD0, 0x05, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x00,
+ static char vsplit_smsk[] = {
+ 0xe0, 0x07, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc8, 0x13, 0xdc,
+ 0x3b, 0xde, 0x7b, 0xcf, 0xf3, 0xcf, 0xf3, 0xde, 0x7b, 0xdc, 0x3b,
+ 0xc8, 0x13, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xe0, 0x07,
};
- static char hsplit_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
- 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
- 0x01, 0x00, 0x00, 0x84, 0x21, 0x00, 0x00, 0x86, 0x61, 0x00, 0x00, 0x87, 0xE1, 0x00, 0x80,
- 0x87, 0xE1, 0x01, 0xC0, 0x87, 0xE1, 0x03, 0xE0, 0x87, 0xE1, 0x07, 0xF0, 0x87, 0xE1, 0x0F,
- 0xF8, 0x87, 0xE1, 0x1F, 0xF0, 0x87, 0xE1, 0x0F, 0xE0, 0x87, 0xE1, 0x07, 0xC0, 0x87, 0xE1,
- 0x03, 0x80, 0x87, 0xE1, 0x01, 0x00, 0x87, 0xE1, 0x00, 0x00, 0x86, 0x61, 0x00, 0x00, 0x84,
- 0x21, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
- 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ static char vsplit_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c,
+ 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38,
+ 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x80, 0x38, 0x1c, 0x01, 0xc0, 0x39, 0x9c, 0x03, 0xe0,
+ 0x3b, 0xdc, 0x07, 0xf0, 0x39, 0x9c, 0x0f, 0xf8, 0x38, 0x1c, 0x1f, 0x7c, 0x38, 0x1c, 0x3e,
+ 0x3e, 0x38, 0x1c, 0x7c, 0x3e, 0x38, 0x1c, 0x7c, 0x7c, 0x38, 0x1c, 0x3e, 0xf8, 0x38, 0x1c,
+ 0x1f, 0xf0, 0x39, 0x9c, 0x0f, 0xe0, 0x3b, 0xdc, 0x07, 0xc0, 0x39, 0x9c, 0x03, 0x80, 0x38,
+ 0x1c, 0x01, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00,
+ 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00,
+ 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
- static char hsplit_lmsk[] = {
- 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03,
- 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC8, 0x13, 0x00, 0x00, 0xCC, 0x33, 0x00, 0x00, 0xCE,
- 0x73, 0x00, 0x00, 0xCF, 0xF3, 0x00, 0x80, 0xCF, 0xF3, 0x01, 0xC0, 0xCF, 0xF3, 0x03, 0xE0,
- 0xCF, 0xF3, 0x07, 0xF0, 0xCF, 0xF3, 0x0F, 0xF8, 0xCF, 0xF3, 0x1F, 0xFC, 0xCF, 0xF3, 0x3F,
- 0xFE, 0xCF, 0xF3, 0x7F, 0xFC, 0xCF, 0xF3, 0x3F, 0xF8, 0xCF, 0xF3, 0x1F, 0xF0, 0xCF, 0xF3,
- 0x0F, 0xE0, 0xCF, 0xF3, 0x07, 0xC0, 0xCF, 0xF3, 0x03, 0x80, 0xCF, 0xF3, 0x01, 0x00, 0xCF,
- 0xF3, 0x00, 0x00, 0xCE, 0x73, 0x00, 0x00, 0xCC, 0x33, 0x00, 0x00, 0xC8, 0x13, 0x00, 0x00,
- 0xC8, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00,
- 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00};
+ static char vsplit_lmsk[] = {
+ 0x00, 0x18, 0x18, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e,
+ 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78,
+ 0x1e, 0x00, 0x80, 0x78, 0x1e, 0x01, 0xc0, 0x79, 0x9e, 0x03, 0xe0, 0x7b, 0xde, 0x07, 0xf0,
+ 0x7f, 0xfe, 0x0f, 0xf8, 0x7b, 0xde, 0x1f, 0xfc, 0x79, 0x9e, 0x3f, 0xfe, 0x78, 0x1e, 0x7f,
+ 0x7f, 0x78, 0x1e, 0xfe, 0x7f, 0x78, 0x1e, 0xfe, 0xfe, 0x78, 0x1e, 0x7f, 0xfc, 0x79, 0x9e,
+ 0x3f, 0xf8, 0x7b, 0xde, 0x1f, 0xf0, 0x7f, 0xfe, 0x0f, 0xe0, 0x7b, 0xde, 0x07, 0xc0, 0x79,
+ 0x9e, 0x03, 0x80, 0x78, 0x1e, 0x01, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00,
+ 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00,
+ 0x00, 0x38, 0x1c, 0x00, 0x00, 0x18, 0x18, 0x00,
+ };
- static BCursor HSplitCursor = {
+ static BCursor VSplitCursor = {
/* small */
- hsplit_sbm,
- hsplit_smsk,
+ vsplit_sbm,
+ vsplit_smsk,
16,
16,
7,
7,
/* big */
- hsplit_lbm,
- hsplit_lmsk,
+ vsplit_lbm,
+ vsplit_lmsk,
32,
32,
15,
@@ -1182,58 +1661,60 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_H_SPLITCURSOR] = &HSplitCursor;
+ BlenderCursor[WM_CURSOR_V_SPLIT] = &VSplitCursor;
END_CURSOR_BLOCK;
- /********************** Vertical Split Cursor ***********************/
+ /********************** Horizontal Split Cursor ***********************/
BEGIN_CURSOR_BLOCK;
- static char vsplit_sbm[] = {
- 0x00, 0x00, 0x80, 0x00, 0xC0, 0x01, 0xE0, 0x03, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ static char hsplit_sbm[] = {
+ 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0x60, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x06, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00,
};
- static char vsplit_smsk[] = {
- 0x80, 0x00, 0xC0, 0x01, 0xE0, 0x03, 0xF0, 0x07, 0xF8, 0x0F, 0x00,
- 0x00, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0x00, 0x00, 0xF8, 0x0F,
- 0xF0, 0x07, 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x00,
+ static char hsplit_smsk[] = {
+ 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f, 0x60, 0x06, 0x01,
+ 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x80,
+ 0x60, 0x06, 0xf0, 0x0f, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01,
};
- static char vsplit_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
- 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8,
- 0x0F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xFE, 0xFF, 0xFF, 0x3F, 0xFE, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, 0xFE,
- 0x3F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00,
- 0xE0, 0x03, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ static char hsplit_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07,
+ 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0x3e,
+ 0x7c, 0x00, 0x00, 0x1c, 0x38, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+ 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff,
+ 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x10, 0x00, 0x00, 0x1c, 0x38, 0x00, 0x00, 0x3e, 0x7c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00,
+ 0xf8, 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xc0, 0x03, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
- static char vsplit_lmsk[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x03,
- 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFE,
- 0x3F, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xC0, 0xFF, 0xFF, 0x01, 0xE0,
- 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x7F,
- 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0x01, 0x80, 0xFF,
- 0xFF, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00,
- 0xF8, 0x0F, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xC0, 0x01, 0x00,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ static char hsplit_lmsk[] = {
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xf0, 0x0f,
+ 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x7f,
+ 0xfe, 0x00, 0x00, 0x3e, 0x7c, 0x00, 0x00, 0x1c, 0x38, 0x00, 0x00, 0x08, 0x10, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff,
+ 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x08, 0x10, 0x00, 0x00, 0x1c,
+ 0x38, 0x00, 0x00, 0x3e, 0x7c, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00,
+ 0xfc, 0x3f, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xe0, 0x07, 0x00,
+ 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00,
+ };
- static BCursor VSplitCursor = {
+ static BCursor HSplitCursor = {
/* small */
- vsplit_sbm,
- vsplit_smsk,
+ hsplit_sbm,
+ hsplit_smsk,
16,
16,
7,
7,
/* big */
- vsplit_lbm,
- vsplit_lmsk,
+ hsplit_lbm,
+ hsplit_lmsk,
32,
32,
15,
@@ -1242,7 +1723,7 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_V_SPLITCURSOR] = &VSplitCursor;
+ BlenderCursor[WM_CURSOR_H_SPLIT] = &HSplitCursor;
END_CURSOR_BLOCK;
@@ -1250,38 +1731,40 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char narrow_sbm[] = {
- 0x00, 0x00, 0x80, 0x00, 0xC0, 0x01, 0xE0, 0x03, 0xF0, 0x07, 0xF8,
- 0x0F, 0xFC, 0x1F, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03,
+ 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8,
+ 0x0f, 0x7c, 0x1f, 0x3e, 0x3e, 0x1c, 0x1c, 0x08, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char narrow_smsk[] = {
- 0x80, 0x00, 0xC0, 0x01, 0xE0, 0x03, 0xF0, 0x07, 0xF8, 0x0F, 0xFC,
- 0x1F, 0xFE, 0x3F, 0xFF, 0x7F, 0xF0, 0x07, 0xF0, 0x07, 0xF0, 0x07,
- 0xF0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc,
+ 0x1f, 0xfe, 0x3f, 0x7f, 0x7f, 0x3e, 0x3e, 0x1c, 0x1c, 0x08, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char narrow_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x01,
- 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xFC,
- 0x1F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xC0,
- 0xFF, 0xFF, 0x01, 0xE0, 0xFF, 0xFF, 0x03, 0xF0, 0xFF, 0xFF, 0x07, 0xF8, 0xFF, 0xFF, 0x0F,
- 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F,
- 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC,
- 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x07,
+ 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc,
+ 0x7f, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x80, 0xff, 0xfe, 0x03, 0xc0,
+ 0x7f, 0xfc, 0x07, 0xe0, 0x3f, 0xf8, 0x0f, 0xf0, 0x1f, 0xf0, 0x1f, 0xf8, 0x0f, 0xe0, 0x3f,
+ 0xfc, 0x07, 0xc0, 0x7f, 0xf8, 0x03, 0x80, 0x3f, 0xf0, 0x01, 0x00, 0x1f, 0xe0, 0x00, 0x00,
+ 0x0e, 0x40, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static char narrow_lmsk[] = {
- 0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF0, 0x07,
- 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFF,
- 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xC0, 0xFF, 0xFF, 0x01, 0xE0, 0xFF, 0xFF, 0x03, 0xF0,
- 0xFF, 0xFF, 0x07, 0xF8, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFE, 0xFF, 0xFF, 0x3F,
- 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F,
- 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE,
- 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xe0, 0x0f,
+ 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0xfe,
+ 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xff, 0x07, 0xe0,
+ 0xff, 0xfe, 0x0f, 0xf0, 0x7f, 0xfc, 0x1f, 0xf8, 0x3f, 0xf8, 0x3f, 0xfc, 0x1f, 0xf0, 0x7f,
+ 0xfe, 0x0f, 0xe0, 0xff, 0xfc, 0x07, 0xc0, 0x7f, 0xf8, 0x03, 0x80, 0x3f, 0xf0, 0x01, 0x00,
+ 0x1f, 0xe0, 0x00, 0x00, 0x0e, 0x40, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static BCursor NArrowCursor = {
/* small */
@@ -1290,19 +1773,19 @@ void wm_init_cursor_data(void)
16,
16,
7,
- 4,
+ 5,
/* big */
narrow_lbm,
narrow_lmsk,
32,
32,
- 15,
- 10,
+ 16,
+ 12,
/* can invert color */
true,
};
- BlenderCursor[BC_N_ARROWCURSOR] = &NArrowCursor;
+ BlenderCursor[WM_CURSOR_N_ARROW] = &NArrowCursor;
END_CURSOR_BLOCK;
@@ -1310,38 +1793,40 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char sarrow_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0,
- 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xFC, 0x1F, 0xF8, 0x0F,
- 0xF0, 0x07, 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x08, 0x1c, 0x1c, 0x3e, 0x3e, 0x7c, 0x1f, 0xf8, 0x0f,
+ 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00,
};
static char sarrow_smsk[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0xF0,
- 0x07, 0xF0, 0x07, 0xF0, 0x07, 0xFF, 0x7F, 0xFE, 0x3F, 0xFC, 0x1F,
- 0xF8, 0x0F, 0xF0, 0x07, 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x08, 0x1c, 0x1c, 0x3e, 0x3e, 0x7f, 0x7f, 0xfe, 0x3f, 0xfc, 0x1f,
+ 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00,
};
static char sarrow_lbm[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00,
- 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00,
- 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0xF8, 0xFF, 0xFF, 0x0F, 0xF0, 0xFF, 0xFF,
- 0x07, 0xE0, 0xFF, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
- 0x7F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00,
- 0xF0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x02, 0x70, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x80, 0x0f,
+ 0xfc, 0x01, 0xc0, 0x1f, 0xfe, 0x03, 0xe0, 0x3f, 0xfc, 0x07, 0xf0, 0x1f, 0xf8, 0x0f, 0xf8,
+ 0x0f, 0xf0, 0x1f, 0xfc, 0x07, 0xe0, 0x3f, 0xfe, 0x03, 0xc0, 0x7f, 0xff, 0x01, 0x80, 0xff,
+ 0xff, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00,
+ 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static char sarrow_lmsk[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE,
- 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00,
- 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00,
- 0x00, 0xFE, 0x3F, 0x00, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF,
- 0x1F, 0xF8, 0xFF, 0xFF, 0x0F, 0xF0, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0x03, 0xC0, 0xFF,
- 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00,
- 0xFC, 0x1F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0x00,
- 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
+ 0x00, 0x00, 0x02, 0x70, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x80, 0x0f, 0xfc, 0x01, 0xc0, 0x1f,
+ 0xfe, 0x03, 0xe0, 0x3f, 0xff, 0x07, 0xf0, 0x7f, 0xfe, 0x0f, 0xf8, 0x3f, 0xfc, 0x1f, 0xfc,
+ 0x1f, 0xf8, 0x3f, 0xfe, 0x0f, 0xf0, 0x7f, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x03, 0xc0, 0xff,
+ 0xff, 0x01, 0x80, 0xff, 0xff, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00,
+ 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
+ };
static BCursor SArrowCursor = {
/* small */
@@ -1350,19 +1835,19 @@ void wm_init_cursor_data(void)
16,
16,
7,
- 11,
+ 10,
/* big */
sarrow_lbm,
sarrow_lmsk,
32,
32,
15,
- 21,
+ 18,
/* can invert color */
true,
};
- BlenderCursor[BC_S_ARROWCURSOR] = &SArrowCursor;
+ BlenderCursor[WM_CURSOR_S_ARROW] = &SArrowCursor;
END_CURSOR_BLOCK;
@@ -1370,38 +1855,40 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char earrow_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0E, 0xE0,
- 0x1F, 0xE0, 0x3F, 0xE0, 0x7F, 0xE0, 0x3F, 0xE0, 0x1F, 0x00, 0x0E,
- 0x00, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x0f, 0x00,
+ 0x1f, 0x00, 0x3e, 0x00, 0x7c, 0x00, 0x3e, 0x00, 0x1f, 0x80, 0x0f,
+ 0xc0, 0x07, 0x80, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
};
static char earrow_smsk[] = {
- 0x00, 0x01, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0F, 0xF0, 0x1F, 0xF0,
- 0x3F, 0xF0, 0x7F, 0xF0, 0xFF, 0xF0, 0x7F, 0xF0, 0x3F, 0xF0, 0x1F,
- 0x00, 0x0F, 0x00, 0x07, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xc0, 0x1f, 0x80,
+ 0x3f, 0x00, 0x7f, 0x00, 0xfe, 0x00, 0x7f, 0x80, 0x3f, 0xc0, 0x1f,
+ 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x03, 0x00, 0x01, 0x00, 0x00,
};
static char earrow_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
- 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
- 0x3E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00,
- 0xFF, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xFF, 0x1F,
- 0x00, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0xFF, 0x1F, 0x00, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xFF,
- 0x07, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00,
- 0x7E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00,
- 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x07,
+ 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xc0,
+ 0x7f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00,
+ 0x00, 0xfc, 0x07, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x3f,
+ 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8,
+ 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xff, 0x01, 0x00, 0x80,
+ 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00,
+ 0xe0, 0x0f, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static char earrow_lmsk[] = {
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0F,
- 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00,
- 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0x03, 0x80, 0xFF, 0xFF, 0x07, 0x80,
- 0xFF, 0xFF, 0x0F, 0x80, 0xFF, 0xFF, 0x1F, 0x80, 0xFF, 0xFF, 0x3F, 0x80, 0xFF, 0xFF, 0x7F,
- 0x80, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0x7F, 0x80, 0xFF, 0xFF, 0x3F, 0x80, 0xFF, 0xFF,
- 0x1F, 0x80, 0xFF, 0xFF, 0x0F, 0x80, 0xFF, 0xFF, 0x07, 0x80, 0xFF, 0xFF, 0x03, 0x00, 0x00,
- 0xFF, 0x01, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00,
- 0x00, 0x1F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xe0, 0x0f,
+ 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xe0,
+ 0xff, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x80, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00,
+ 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf0, 0x7f,
+ 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc,
+ 0x1f, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x80, 0xff, 0x03, 0x00, 0xc0,
+ 0xff, 0x01, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00,
+ 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x80, 0x03, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static BCursor EArrowCursor = {
/* small */
@@ -1409,20 +1896,20 @@ void wm_init_cursor_data(void)
earrow_smsk,
16,
16,
- 11,
+ 10,
7,
/* big */
earrow_lbm,
earrow_lmsk,
32,
32,
+ 18,
15,
- 22,
/* can invert color */
true,
};
- BlenderCursor[BC_E_ARROWCURSOR] = &EArrowCursor;
+ BlenderCursor[WM_CURSOR_E_ARROW] = &EArrowCursor;
END_CURSOR_BLOCK;
@@ -1430,38 +1917,40 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char warrow_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x00, 0x70, 0x00, 0xF8,
- 0x07, 0xFC, 0x07, 0xFE, 0x07, 0xFC, 0x07, 0xF8, 0x07, 0x70, 0x00,
- 0x60, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x01, 0xf8,
+ 0x00, 0x7c, 0x00, 0x3e, 0x00, 0x7c, 0x00, 0xf8, 0x00, 0xf0, 0x01,
+ 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char warrow_smsk[] = {
- 0x80, 0x00, 0xC0, 0x00, 0xE0, 0x00, 0xF0, 0x00, 0xF8, 0x0F, 0xFC,
- 0x0F, 0xFE, 0x0F, 0xFF, 0x0F, 0xFE, 0x0F, 0xFC, 0x0F, 0xF8, 0x0F,
- 0xF0, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x03, 0xfc,
+ 0x01, 0xfe, 0x00, 0x7f, 0x00, 0xfe, 0x00, 0xfc, 0x01, 0xf8, 0x03,
+ 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00,
};
static char warrow_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
- 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x7C,
- 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xC0,
- 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x00, 0xF8, 0xFF, 0xFF, 0x00,
- 0xFC, 0xFF, 0xFF, 0x00, 0xF8, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0xFF,
- 0x00, 0xC0, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x7E,
- 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00,
- 0x60, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03,
+ 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe,
+ 0x03, 0x00, 0x00, 0xff, 0x01, 0x00, 0x80, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0,
+ 0x3f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00,
+ 0xfe, 0x03, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00,
+ 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00,
+ 0xf0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static char warrow_lmsk[] = {
- 0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xF0, 0x00,
- 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0xFF,
- 0x00, 0x00, 0x80, 0xFF, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x01, 0xE0, 0xFF, 0xFF, 0x01, 0xF0,
- 0xFF, 0xFF, 0x01, 0xF8, 0xFF, 0xFF, 0x01, 0xFC, 0xFF, 0xFF, 0x01, 0xFE, 0xFF, 0xFF, 0x01,
- 0xFF, 0xFF, 0xFF, 0x01, 0xFE, 0xFF, 0xFF, 0x01, 0xFC, 0xFF, 0xFF, 0x01, 0xF8, 0xFF, 0xFF,
- 0x01, 0xF0, 0xFF, 0xFF, 0x01, 0xE0, 0xFF, 0xFF, 0x01, 0xC0, 0xFF, 0xFF, 0x01, 0x80, 0xFF,
- 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00,
- 0xF8, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x07,
+ 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xff,
+ 0x07, 0x00, 0x80, 0xff, 0x03, 0x00, 0xc0, 0xff, 0x01, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xf0,
+ 0x7f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00,
+ 0xff, 0x07, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00,
+ 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x80, 0xff,
+ 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00,
+ 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static BCursor WArrowCursor = {
/* small */
@@ -1469,20 +1958,20 @@ void wm_init_cursor_data(void)
warrow_smsk,
16,
16,
- 4,
+ 5,
7,
/* big */
warrow_lbm,
warrow_lmsk,
32,
32,
- 15,
+ 18,
15,
/* can invert color */
true,
};
- BlenderCursor[BC_W_ARROWCURSOR] = &WArrowCursor;
+ BlenderCursor[WM_CURSOR_W_ARROW] = &WArrowCursor;
END_CURSOR_BLOCK;
@@ -1490,38 +1979,40 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char stop_sbm[] = {
- 0x00, 0x00, 0xE0, 0x07, 0x38, 0x1C, 0x1C, 0x30, 0x3C, 0x20, 0x76,
- 0x60, 0xE2, 0x40, 0xC2, 0x41, 0x82, 0x43, 0x02, 0x47, 0x06, 0x6E,
- 0x04, 0x3C, 0x0C, 0x38, 0x38, 0x1C, 0xE0, 0x07, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x07, 0xf8, 0x1f, 0x1c, 0x3c, 0x3c, 0x30, 0x76,
+ 0x70, 0xe6, 0x60, 0xc6, 0x61, 0x86, 0x63, 0x06, 0x67, 0x0e, 0x6e,
+ 0x0c, 0x3c, 0x3c, 0x38, 0xf8, 0x1f, 0xe0, 0x07, 0x00, 0x00,
};
static char stop_smsk[] = {
- 0xE0, 0x07, 0xF8, 0x1F, 0xFC, 0x3F, 0x3E, 0x7C, 0x7E, 0x70, 0xFF,
- 0xF0, 0xF7, 0xE1, 0xE7, 0xE3, 0xC7, 0xE7, 0x87, 0xEF, 0x0F, 0xFF,
- 0x0E, 0x7E, 0x3E, 0x7C, 0xFC, 0x3F, 0xF8, 0x1F, 0xE0, 0x07,
+ 0xe0, 0x07, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f, 0x7e, 0x7c, 0xff,
+ 0xf8, 0xff, 0xf1, 0xef, 0xf3, 0xcf, 0xf7, 0x8f, 0xff, 0x1f, 0xff,
+ 0x3e, 0x7e, 0xfe, 0x7f, 0xfc, 0x3f, 0xf8, 0x1f, 0xe0, 0x07,
};
static char stop_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x00, 0x0F, 0xF0,
- 0x00, 0xC0, 0x03, 0xC0, 0x03, 0xE0, 0x01, 0x00, 0x07, 0xF0, 0x01, 0x00, 0x0E, 0xF0, 0x01,
- 0x00, 0x0C, 0xF8, 0x03, 0x00, 0x18, 0x1C, 0x07, 0x00, 0x38, 0x0C, 0x0E, 0x00, 0x30, 0x0C,
- 0x1C, 0x00, 0x30, 0x06, 0x38, 0x00, 0x60, 0x06, 0x70, 0x00, 0x60, 0x06, 0xE0, 0x00, 0x60,
- 0x06, 0xC0, 0x01, 0x60, 0x06, 0x80, 0x03, 0x60, 0x06, 0x00, 0x07, 0x60, 0x06, 0x00, 0x0E,
- 0x60, 0x06, 0x00, 0x1C, 0x60, 0x0C, 0x00, 0x38, 0x30, 0x0C, 0x00, 0x70, 0x30, 0x1C, 0x00,
- 0xE0, 0x38, 0x18, 0x00, 0xC0, 0x1F, 0x30, 0x00, 0x80, 0x0F, 0x70, 0x00, 0x80, 0x0F, 0xE0,
- 0x00, 0x80, 0x07, 0xC0, 0x03, 0xC0, 0x03, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0xFE, 0x7F, 0x00,
- 0x00, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0xc0, 0x1f, 0xf8, 0x03, 0xe0, 0x03, 0xc0, 0x07, 0xf0, 0x01, 0x80, 0x0f, 0xf0, 0x03,
+ 0x00, 0x0f, 0xf8, 0x07, 0x00, 0x1e, 0xbc, 0x0f, 0x00, 0x3c, 0x1c, 0x1f, 0x00, 0x38, 0x1c,
+ 0x3e, 0x00, 0x38, 0x1e, 0x7c, 0x00, 0x78, 0x0e, 0xf8, 0x00, 0x70, 0x0e, 0xf0, 0x01, 0x70,
+ 0x0e, 0xe0, 0x03, 0x70, 0x0e, 0xc0, 0x07, 0x70, 0x0e, 0x80, 0x0f, 0x70, 0x0e, 0x00, 0x1f,
+ 0x70, 0x1e, 0x00, 0x3e, 0x78, 0x1c, 0x00, 0x7c, 0x38, 0x1c, 0x00, 0xf8, 0x38, 0x3c, 0x00,
+ 0xf0, 0x3d, 0x78, 0x00, 0xe0, 0x1f, 0xf0, 0x00, 0xc0, 0x0f, 0xf0, 0x01, 0x80, 0x0f, 0xe0,
+ 0x03, 0xc0, 0x07, 0xc0, 0x1f, 0xf8, 0x03, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0x7f, 0x00,
+ 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static char stop_lmsk[] = {
- 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x01, 0xC0, 0xFF, 0xFF,
- 0x03, 0xE0, 0x1F, 0xF8, 0x07, 0xF0, 0x03, 0xC0, 0x0F, 0xF8, 0x03, 0x80, 0x1F, 0xFC, 0x07,
- 0x00, 0x3F, 0xFC, 0x0F, 0x00, 0x3E, 0xFE, 0x1F, 0x00, 0x7C, 0x9E, 0x3F, 0x00, 0x78, 0x1E,
- 0x7F, 0x00, 0x78, 0x1F, 0xFE, 0x00, 0xF8, 0x0F, 0xFC, 0x01, 0xF0, 0x0F, 0xF8, 0x03, 0xF0,
- 0x0F, 0xF0, 0x07, 0xF0, 0x0F, 0xE0, 0x0F, 0xF0, 0x0F, 0xC0, 0x1F, 0xF0, 0x0F, 0x80, 0x3F,
- 0xF0, 0x1F, 0x00, 0x7F, 0xF8, 0x1E, 0x00, 0xFE, 0x78, 0x1E, 0x00, 0xFC, 0x79, 0x3E, 0x00,
- 0xF8, 0x7F, 0x7C, 0x00, 0xF0, 0x3F, 0xFC, 0x00, 0xE0, 0x3F, 0xF8, 0x01, 0xC0, 0x1F, 0xF0,
- 0x03, 0xC0, 0x0F, 0xE0, 0x1F, 0xF8, 0x07, 0xC0, 0xFF, 0xFF, 0x03, 0x80, 0xFF, 0xFF, 0x01,
- 0x00, 0xFE, 0x7F, 0x00, 0x00, 0xF0, 0x0F, 0x00};
+ 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x01, 0xe0, 0xff, 0xff,
+ 0x07, 0xf0, 0xff, 0xff, 0x0f, 0xf8, 0x3f, 0xfc, 0x1f, 0xf8, 0x07, 0xe0, 0x1f, 0xfc, 0x0f,
+ 0xc0, 0x3f, 0xfe, 0x1f, 0x80, 0x7f, 0xfe, 0x3f, 0x00, 0x7f, 0xfe, 0x7f, 0x00, 0x7e, 0xbf,
+ 0xff, 0x00, 0xfc, 0x3f, 0xff, 0x01, 0xfc, 0x3f, 0xfe, 0x03, 0xfc, 0x1f, 0xfc, 0x07, 0xf8,
+ 0x1f, 0xf8, 0x0f, 0xf8, 0x1f, 0xf0, 0x1f, 0xf8, 0x1f, 0xe0, 0x3f, 0xf8, 0x3f, 0xc0, 0x7f,
+ 0xfc, 0x3f, 0x80, 0xff, 0xfc, 0x3f, 0x00, 0xff, 0xfd, 0x7e, 0x00, 0xfe, 0x7f, 0xfe, 0x00,
+ 0xfc, 0x7f, 0xfe, 0x01, 0xf8, 0x7f, 0xfc, 0x03, 0xf0, 0x3f, 0xf8, 0x07, 0xe0, 0x1f, 0xf8,
+ 0x3f, 0xfc, 0x1f, 0xf0, 0xff, 0xff, 0x0f, 0xe0, 0xff, 0xff, 0x07, 0x80, 0xff, 0xff, 0x01,
+ 0x00, 0xff, 0xff, 0x00, 0x00, 0xf8, 0x1f, 0x00,
+ };
static BCursor StopCursor = {
/* small */
@@ -1538,11 +2029,135 @@ void wm_init_cursor_data(void)
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
+ };
+
+ BlenderCursor[WM_CURSOR_STOP] = &StopCursor;
+
+ END_CURSOR_BLOCK;
+
+ /********************** Zoom In Cursor ***********************/
+ BEGIN_CURSOR_BLOCK;
+
+ static char zoomin_sbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xf8, 0x03, 0xb8, 0x03, 0xbc,
+ 0x07, 0x0c, 0x06, 0xbc, 0x07, 0xb8, 0x03, 0xf8, 0x0b, 0xe0, 0x14,
+ 0x00, 0x22, 0x00, 0x44, 0x00, 0x88, 0x00, 0x90, 0x00, 0x60,
+ };
+
+ static char zoomin_smsk[] = {
+ 0x00, 0x00, 0xe0, 0x00, 0xf8, 0x03, 0xfc, 0x07, 0xfc, 0x07, 0xfe,
+ 0x0f, 0xfe, 0x0f, 0xfe, 0x0f, 0xfc, 0x07, 0xfc, 0x0f, 0xf8, 0x1f,
+ 0xe0, 0x3e, 0x00, 0x7c, 0x00, 0xf8, 0x00, 0xf0, 0x00, 0x60,
+ };
+
+ static char zoomin_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x0f,
+ 0x00, 0xf8, 0xff, 0x1f, 0x00, 0xf8, 0xff, 0x1f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xe7,
+ 0x3f, 0x00, 0xfc, 0xe7, 0x3f, 0x00, 0xfe, 0xe7, 0x7f, 0x00, 0xfe, 0xe7, 0x7f, 0x00, 0x7e,
+ 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0xfe, 0xe7, 0x7f, 0x00, 0xfe, 0xe7, 0x7f, 0x00,
+ 0xfc, 0xe7, 0x3f, 0x00, 0xfc, 0xe7, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0x5f,
+ 0x00, 0xf8, 0xff, 0x9f, 0x00, 0xf0, 0xff, 0x0f, 0x01, 0xc0, 0xff, 0x03, 0x02, 0x00, 0x7e,
+ 0x04, 0x04, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00,
+ 0x00, 0x40, 0x40, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x82,
+ 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x38,
+ };
+
+ static char zoomin_lmsk[] = {
+ 0x00, 0x7e, 0x00, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0xf8, 0xff, 0x1f,
+ 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff,
+ 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x7f,
+ 0x00, 0xfc, 0xff, 0xff, 0x00, 0xf8, 0xff, 0xff, 0x01, 0xf0, 0xff, 0xff, 0x03, 0xc0, 0xff,
+ 0xff, 0x07, 0x00, 0x7e, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x3f, 0x00,
+ 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xfe,
+ 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x38,
+ };
+
+ static BCursor ZoomInCursor = {
+ /* small */
+ zoomin_sbm,
+ zoomin_smsk,
+ 16,
+ 16,
+ 6,
+ 6,
+ /* big */
+ zoomin_lbm,
+ zoomin_lmsk,
+ 32,
+ 32,
+ 11,
+ 11,
+ /* don't invert color */
+ false,
+ };
+
+ BlenderCursor[WM_CURSOR_ZOOM_IN] = &ZoomInCursor;
+
+ END_CURSOR_BLOCK;
+
+ /********************** Zoom Out Cursor ***********************/
+ BEGIN_CURSOR_BLOCK;
+
+ static char zoomout_sbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xf8, 0x03, 0xf8, 0x03, 0xfc,
+ 0x07, 0x0c, 0x06, 0xfc, 0x07, 0xf8, 0x03, 0xf8, 0x0b, 0xe0, 0x14,
+ 0x00, 0x22, 0x00, 0x44, 0x00, 0x88, 0x00, 0x90, 0x00, 0x60,
+ };
+
+ static char zoomout_smsk[] = {
+ 0x00, 0x00, 0xe0, 0x00, 0xf8, 0x03, 0xfc, 0x07, 0xfc, 0x07, 0xfe,
+ 0x0f, 0xfe, 0x0f, 0xfe, 0x0f, 0xfc, 0x07, 0xfc, 0x0f, 0xf8, 0x1f,
+ 0xe0, 0x3e, 0x00, 0x7c, 0x00, 0xf8, 0x00, 0xf0, 0x00, 0x60,
+ };
+
+ static char zoomout_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x0f,
+ 0x00, 0xf8, 0xff, 0x1f, 0x00, 0xf8, 0xff, 0x1f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff,
+ 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0x7e,
+ 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00,
+ 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0x5f,
+ 0x00, 0xf8, 0xff, 0x9f, 0x00, 0xf0, 0xff, 0x0f, 0x01, 0xc0, 0xff, 0x03, 0x02, 0x00, 0x7e,
+ 0x04, 0x04, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00,
+ 0x00, 0x40, 0x40, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x82,
+ 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x38,
+ };
+
+ static char zoomout_lmsk[] = {
+ 0x00, 0x7e, 0x00, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0xf8, 0xff, 0x1f,
+ 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff,
+ 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x7f,
+ 0x00, 0xfc, 0xff, 0xff, 0x00, 0xf8, 0xff, 0xff, 0x01, 0xf0, 0xff, 0xff, 0x03, 0xc0, 0xff,
+ 0xff, 0x07, 0x00, 0x7e, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x3f, 0x00,
+ 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xfe,
+ 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x38,
+ };
+
+ static BCursor ZoomOutCursor = {
+ /* small */
+ zoomout_sbm,
+ zoomout_smsk,
+ 16,
+ 16,
+ 6,
+ 6,
+ /* big */
+ zoomout_lbm,
+ zoomout_lmsk,
+ 32,
+ 32,
+ 11,
+ 11,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_STOPCURSOR] = &StopCursor;
+ BlenderCursor[WM_CURSOR_ZOOM_OUT] = &ZoomOutCursor;
END_CURSOR_BLOCK;
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index ba6a0c4ebe1..901594850dd 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -265,7 +265,7 @@ static void wm_drop_operator_options(bContext *C, wmDrag *drag, const wmEvent *e
if (opname) {
BLI_strncpy(drag->opname, opname, sizeof(drag->opname));
- // WM_cursor_modal_set(win, CURSOR_COPY);
+ // WM_cursor_modal_set(win, WM_CURSOR_COPY);
}
// else
// WM_cursor_modal_restore(win);
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 3bcb955c2b2..2f538a19ba2 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -46,7 +46,6 @@
#include "BKE_main.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
-#include "BKE_workspace.h"
#include "GHOST_C-api.h"
@@ -55,10 +54,8 @@
#include "ED_screen.h"
#include "GPU_draw.h"
-#include "GPU_extensions.h"
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
-#include "GPU_matrix.h"
#include "GPU_state.h"
#include "GPU_texture.h"
#include "GPU_viewport.h"
@@ -436,6 +433,17 @@ static void wm_draw_region_blit(ARegion *ar, int view)
return;
}
+ if (view == -1) {
+ /* Non-stereo drawing. */
+ view = 0;
+ }
+ else if (view > 0) {
+ if (ar->draw_buffer->viewport[view] == NULL && ar->draw_buffer->offscreen[view] == NULL) {
+ /* Region does not need stereo or failed to allocate stereo buffers. */
+ view = 0;
+ }
+ }
+
if (ar->draw_buffer->viewport[view]) {
GPU_viewport_draw_to_screen(ar->draw_buffer->viewport[view], &ar->winrct);
}
@@ -688,7 +696,7 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
}
else {
/* Blit from offscreen buffer. */
- wm_draw_region_blit(ar, 0);
+ wm_draw_region_blit(ar, view);
}
}
}
@@ -820,11 +828,11 @@ static void wm_draw_window(bContext *C, wmWindow *win)
/****************** main update call **********************/
/* quick test to prevent changing window drawable */
-static bool wm_draw_update_test_window(wmWindow *win)
+static bool wm_draw_update_test_window(Main *bmain, wmWindow *win)
{
Scene *scene = WM_window_get_active_scene(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- struct Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ struct Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
bScreen *screen = WM_window_get_active_screen(win);
ARegion *ar;
bool do_draw = false;
@@ -925,7 +933,7 @@ void wm_draw_update(bContext *C)
}
#endif
- if (wm_draw_update_test_window(win)) {
+ if (wm_draw_update_test_window(bmain, win)) {
bScreen *screen = WM_window_get_active_screen(win);
CTX_wm_window_set(C, win);
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 51191b45439..6b4327d5f44 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -50,7 +50,6 @@
#include "BKE_customdata.h"
#include "BKE_idprop.h"
#include "BKE_global.h"
-#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -59,6 +58,8 @@
#include "BKE_sound.h"
+#include "BLT_translation.h"
+
#include "ED_fileselect.h"
#include "ED_info.h"
#include "ED_screen.h"
@@ -360,7 +361,7 @@ void wm_event_do_depsgraph(bContext *C, bool is_after_open_file)
* and for until then we have to accept ambiguities when object is shared
* across visible view layers and has overrides on it.
*/
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
if (is_after_open_file) {
DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
DEG_graph_on_visible_update(bmain, depsgraph, true);
@@ -1804,8 +1805,11 @@ void wm_event_free_handler(wmEventHandler *handler)
/* only set context when area/region is part of screen */
static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const wmEvent *event)
{
- wmWindow *win = CTX_wm_window(C);
- bScreen *screen = CTX_wm_screen(C);
+ wmWindow *win = handler->context.win ? handler->context.win : CTX_wm_window(C);
+ /* It's probably fine to always use WM_window_get_active_screen() to get the screen. But this
+ * code has been getting it through context since forever, so play safe and stick to that when
+ * possible. */
+ bScreen *screen = handler->context.win ? WM_window_get_active_screen(win) : CTX_wm_screen(C);
if (screen && handler->op) {
if (handler->context.area == NULL) {
@@ -2334,50 +2338,39 @@ static int wm_handler_fileselect_do(bContext *C,
int val)
{
wmWindowManager *wm = CTX_wm_manager(C);
- SpaceFile *sfile;
int action = WM_HANDLER_CONTINUE;
switch (val) {
case EVT_FILESELECT_FULL_OPEN: {
- ScrArea *sa;
+ wmWindow *win = CTX_wm_window(C);
+ ScrArea *area;
- /* sa can be null when window A is active, but mouse is over window B
- * in this case, open file select in original window A. Also don't
- * use global areas. */
- if (handler->context.area == NULL || ED_area_is_global(handler->context.area)) {
- bScreen *screen = CTX_wm_screen(C);
- sa = (ScrArea *)screen->areabase.first;
- }
- else {
- sa = handler->context.area;
- }
+ if ((area = ED_screen_temp_space_open(C,
+ IFACE_("Blender File View"),
+ WM_window_pixels_x(win) / 2,
+ WM_window_pixels_y(win) / 2,
+ U.file_space_data.temp_win_sizex * UI_DPI_FAC,
+ U.file_space_data.temp_win_sizey * UI_DPI_FAC,
+ SPACE_FILE,
+ U.filebrowser_display_type))) {
+ ARegion *region_header = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
- if (sa->full) {
- /* ensure the first area becomes the file browser, because the second one is the small
- * top (info-)area which might be too small (in fullscreens we have max two areas) */
- if (sa->prev) {
- sa = sa->prev;
- }
- ED_area_newspace(C, sa, SPACE_FILE, true); /* 'sa' is modified in-place */
- /* we already had a fullscreen here -> mark new space as a stacked fullscreen */
- sa->flag |= (AREA_FLAG_STACKED_FULLSCREEN | AREA_FLAG_TEMP_TYPE);
- }
- else if (sa->spacetype == SPACE_FILE) {
- sa = ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENMAXIMIZED);
- }
- else {
- sa = ED_screen_full_newspace(C, sa, SPACE_FILE); /* sets context */
- }
+ BLI_assert(area->spacetype == SPACE_FILE);
- /* note, getting the 'sa' back from the context causes a nasty bug where the newly created
- * 'sa' != CTX_wm_area(C). removed the line below and set 'sa' in the 'if' above */
- /* sa = CTX_wm_area(C); */
+ region_header->flag |= RGN_FLAG_HIDDEN;
+ /* Header on bottom, AZone triangle to toggle header looks misplaced at the top */
+ region_header->alignment = RGN_ALIGN_BOTTOM;
- /* settings for filebrowser, sfile is not operator owner but sends events */
- sfile = (SpaceFile *)sa->spacedata.first;
- sfile->op = handler->op;
+ /* settings for filebrowser, sfile is not operator owner but sends events */
+ SpaceFile *sfile = (SpaceFile *)area->spacedata.first;
+ sfile->op = handler->op;
- ED_fileselect_set_params(sfile);
+ ED_fileselect_set_params_from_userdef(sfile);
+ }
+ else {
+ BKE_report(&wm->reports, RPT_ERROR, "Failed to open window!");
+ return OPERATOR_CANCELLED;
+ }
action = WM_HANDLER_BREAK;
break;
@@ -2386,22 +2379,69 @@ static int wm_handler_fileselect_do(bContext *C,
case EVT_FILESELECT_EXEC:
case EVT_FILESELECT_CANCEL:
case EVT_FILESELECT_EXTERNAL_CANCEL: {
+ wmWindow *ctx_win = CTX_wm_window(C);
+
/* remlink now, for load file case before removing*/
BLI_remlink(handlers, handler);
- if (val != EVT_FILESELECT_EXTERNAL_CANCEL) {
- ScrArea *sa = CTX_wm_area(C);
+ if (val == EVT_FILESELECT_EXTERNAL_CANCEL) {
+ /* The window might have been freed already. */
+ if (BLI_findindex(&wm->windows, handler->context.win) == -1) {
+ handler->context.win = NULL;
+ }
+ }
+ else {
+ wmWindow *temp_win;
+ ScrArea *ctx_sa = CTX_wm_area(C);
+
+ for (temp_win = wm->windows.first; temp_win; temp_win = temp_win->next) {
+ bScreen *screen = WM_window_get_active_screen(temp_win);
+ ScrArea *file_sa = screen->areabase.first;
+
+ if (screen->temp && (file_sa->spacetype == SPACE_FILE)) {
+ int win_size[2];
+
+ /* Get DPI/pixelsize independent size to be stored in preferences. */
+ WM_window_set_dpi(temp_win); /* Ensure the DPI is taken from the right window. */
+ win_size[0] = WM_window_pixels_x(temp_win) / UI_DPI_FAC;
+ win_size[1] = WM_window_pixels_y(temp_win) / UI_DPI_FAC;
+
+ ED_fileselect_params_to_userdef(file_sa->spacedata.first, win_size);
+
+ if (BLI_listbase_is_single(&file_sa->spacedata)) {
+ BLI_assert(ctx_win != temp_win);
+
+ wm_window_close(C, wm, temp_win);
+
+ CTX_wm_window_set(C, ctx_win); // wm_window_close() NULLs.
+ /* Some operators expect a drawable context (for EVT_FILESELECT_EXEC) */
+ wm_window_make_drawable(wm, ctx_win);
+ /* Ensure correct cursor position, otherwise, popups may close immediately after
+ * opening (UI_BLOCK_MOVEMOUSE_QUIT) */
+ wm_get_cursor_position(ctx_win, &ctx_win->eventstate->x, &ctx_win->eventstate->y);
+ wm->winactive = ctx_win; /* Reports use this... */
+ if (handler->context.win == temp_win) {
+ handler->context.win = NULL;
+ }
+ }
+ else if (file_sa->full) {
+ ED_screen_full_prevspace(C, file_sa);
+ }
+ else {
+ ED_area_prevspace(C, file_sa);
+ }
- if (sa->full) {
- ED_screen_full_prevspace(C, sa);
+ break;
+ }
}
- /* user may have left fullscreen */
- else {
- ED_area_prevspace(C, sa);
+
+ if (!temp_win && ctx_sa->full) {
+ ED_fileselect_params_to_userdef(ctx_sa->spacedata.first, NULL);
+ ED_screen_full_prevspace(C, ctx_sa);
}
}
- wm_handler_op_context(C, handler, CTX_wm_window(C)->eventstate);
+ wm_handler_op_context(C, handler, ctx_win->eventstate);
/* needed for UI_popup_menu_reports */
@@ -3235,9 +3275,10 @@ void wm_event_do_handlers(bContext *C)
wm_event_free_all(win);
}
else {
+ Main *bmain = CTX_data_main(C);
Scene *scene = WM_window_get_active_scene(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, false);
Scene *scene_eval = (depsgraph != NULL) ? DEG_get_evaluated_scene(depsgraph) : NULL;
if (scene_eval != NULL) {
@@ -3511,38 +3552,48 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
+ const bool is_temp_screen = WM_window_is_temp_screen(win);
+ const bool opens_window = (U.filebrowser_display_type == USER_TEMP_SPACE_DISPLAY_WINDOW);
+ /* Don't add the file handler to the temporary window if one is opened, or else it owns the
+ * handlers for itself, causing dangling pointers once it's destructed through a handler. It has
+ * a parent which should hold the handlers itself. */
+ ListBase *modalhandlers = (is_temp_screen && opens_window) ? &win->parent->modalhandlers :
+ &win->modalhandlers;
/* Close any popups, like when opening a file browser from the splash. */
- UI_popup_handlers_remove_all(C, &win->modalhandlers);
+ UI_popup_handlers_remove_all(C, modalhandlers);
- /* only allow 1 file selector open per window */
- LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, &win->modalhandlers) {
- if (handler_base->type == WM_HANDLER_TYPE_OP) {
- wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
- if (handler->is_fileselect == false) {
- continue;
- }
- bScreen *screen = CTX_wm_screen(C);
- bool cancel_handler = true;
+ if (!is_temp_screen) {
+ /* only allow 1 file selector open per window */
+ LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, modalhandlers) {
+ if (handler_base->type == WM_HANDLER_TYPE_OP) {
+ wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
+ if (handler->is_fileselect == false) {
+ continue;
+ }
+ bScreen *screen = CTX_wm_screen(C);
+ bool cancel_handler = true;
- /* find the area with the file selector for this handler */
- ED_screen_areas_iter(win, screen, sa)
- {
- if (sa->spacetype == SPACE_FILE) {
- SpaceFile *sfile = sa->spacedata.first;
+ /* find the area with the file selector for this handler */
+ ED_screen_areas_iter(win, screen, sa)
+ {
+ if (sa->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = sa->spacedata.first;
- if (sfile->op == handler->op) {
- CTX_wm_area_set(C, sa);
- wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_CANCEL);
- cancel_handler = false;
- break;
+ if (sfile->op == handler->op) {
+ CTX_wm_area_set(C, sa);
+ wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_CANCEL);
+ cancel_handler = false;
+ break;
+ }
}
}
- }
- /* if not found we stop the handler without changing the screen */
- if (cancel_handler) {
- wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL);
+ /* if not found we stop the handler without changing the screen */
+ if (cancel_handler) {
+ wm_handler_fileselect_do(
+ C, &win->modalhandlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL);
+ }
}
}
}
@@ -3552,10 +3603,11 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
handler->is_fileselect = true;
handler->op = op;
+ handler->context.win = CTX_wm_window(C);
handler->context.area = CTX_wm_area(C);
handler->context.region = CTX_wm_region(C);
- BLI_addhead(&win->modalhandlers, handler);
+ BLI_addhead(modalhandlers, handler);
/* check props once before invoking if check is available
* ensures initial properties are valid */
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 8546290d281..f96a8c3d7fd 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -52,8 +52,8 @@
#include "BLI_blenlib.h"
#include "BLI_linklist.h"
#include "BLI_utildefines.h"
+#include "BLI_timer.h"
#include "BLI_threads.h"
-#include "BLI_callbacks.h"
#include "BLI_system.h"
#include BLI_SYSTEM_PID_H
@@ -73,7 +73,7 @@
#include "BKE_autoexec.h"
#include "BKE_blender.h"
#include "BKE_blendfile.h"
-#include "BKE_blender_undo.h"
+#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
@@ -101,6 +101,7 @@
#include "ED_datafiles.h"
#include "ED_fileselect.h"
#include "ED_image.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "ED_util.h"
@@ -113,8 +114,6 @@
#include "UI_resources.h"
#include "UI_view2d.h"
-#include "GPU_draw.h"
-
/* only to report a missing engine */
#include "RE_engine.h"
@@ -535,16 +534,16 @@ static void wm_file_read_post(bContext *C,
if (use_userdef) {
if (is_factory_startup) {
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_FACTORY_USERDEF_POST);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_LOAD_FACTORY_USERDEF_POST);
}
}
if (use_data) {
/* important to do before NULL'ing the context */
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_VERSION_UPDATE);
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_POST);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_VERSION_UPDATE);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_LOAD_POST);
if (is_factory_startup) {
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_FACTORY_STARTUP_POST);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_LOAD_FACTORY_STARTUP_POST);
}
}
@@ -607,7 +606,8 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
WM_cursor_wait(1);
- BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_PRE);
+ BKE_callback_exec_null(CTX_data_main(C), BKE_CB_EVT_LOAD_PRE);
+ BLI_timer_on_file_load();
UI_view2d_zoom_cache_reset();
@@ -804,7 +804,8 @@ void wm_homefile_read(bContext *C,
}
if (use_data) {
- BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_PRE);
+ BKE_callback_exec_null(CTX_data_main(C), BKE_CB_EVT_LOAD_PRE);
+ BLI_timer_on_file_load();
G.relbase_valid = 0;
@@ -1204,6 +1205,8 @@ static ImBuf *blend_file_thumb(const bContext *C,
/* will be scaled down, but gives some nice oversampling */
ImBuf *ibuf;
BlendThumbnail *thumb;
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *windrawable_old = wm->windrawable;
char err_out[256] = "unknown";
/* screen if no camera found */
@@ -1269,6 +1272,14 @@ static ImBuf *blend_file_thumb(const bContext *C,
err_out);
}
+ /* Reset to old drawable. */
+ if (windrawable_old) {
+ wm_window_make_drawable(wm, windrawable_old);
+ }
+ else {
+ wm_window_clear_drawable(wm);
+ }
+
if (ibuf) {
float aspect = (scene->r.xsch * scene->r.xasp) / (scene->r.ysch * scene->r.yasp);
@@ -1354,7 +1365,7 @@ static bool wm_file_write(bContext *C, const char *filepath, int fileflags, Repo
/* Call pre-save callbacks before writing preview,
* that way you can generate custom file thumbnail. */
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_SAVE_PRE);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_PRE);
/* Enforce full override check/generation on file save. */
BKE_main_override_library_operations_create(bmain, true);
@@ -1407,7 +1418,7 @@ static bool wm_file_write(bContext *C, const char *filepath, int fileflags, Repo
wm_history_file_update();
}
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_SAVE_POST);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_POST);
/* run this function after because the file cant be written before the blend is */
if (ibuf_thumb) {
@@ -1632,7 +1643,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_SAVE_PRE);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_PRE);
/* check current window and close it if temp */
if (win && WM_window_is_temp_screen(win)) {
@@ -1660,7 +1671,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
G.save_over = 0;
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_SAVE_POST);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_POST);
return OPERATOR_FINISHED;
}
@@ -1753,7 +1764,7 @@ static void wm_userpref_read_exceptions(UserDef *userdef_curr, const UserDef *us
((void)0)
/* Current visible preferences category. */
- USERDEF_RESTORE(userpref);
+ USERDEF_RESTORE(space_data.section_active);
#undef USERDEF_RESTORE
}
@@ -1971,6 +1982,10 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op)
}
}
+ if (G.fileflags & G_FILE_NO_UI) {
+ ED_outliner_select_sync_from_all_tag(C);
+ }
+
return OPERATOR_FINISHED;
}
@@ -2226,6 +2241,10 @@ static int wm_open_mainfile__open(bContext *C, wmOperator *op)
BKE_report_print_level_set(op->reports, RPT_WARNING);
if (success) {
+ if (G.fileflags & G_FILE_NO_UI) {
+ ED_outliner_select_sync_from_all_tag(C);
+ }
+ ED_view3d_local_collections_reset(C, (G.fileflags & G_FILE_NO_UI) != 0);
return OPERATOR_FINISHED;
}
else {
@@ -2314,7 +2333,7 @@ static void wm_open_mainfile_ui(bContext *UNUSED(C), wmOperator *op)
void WM_OT_open_mainfile(wmOperatorType *ot)
{
- ot->name = "Open Blender File";
+ ot->name = "Open";
ot->idname = "WM_OT_open_mainfile";
ot->description = "Open a Blender file";
@@ -2390,7 +2409,10 @@ void WM_OT_revert_mainfile(wmOperatorType *ot)
ot->name = "Revert";
ot->idname = "WM_OT_revert_mainfile";
ot->description = "Reload the saved file";
+
ot->invoke = WM_operator_confirm;
+ ot->exec = wm_revert_mainfile_exec;
+ ot->poll = wm_revert_mainfile_poll;
RNA_def_boolean(ot->srna,
"use_scripts",
@@ -2398,9 +2420,6 @@ void WM_OT_revert_mainfile(wmOperatorType *ot)
"Trusted Source",
"Allow .blend file to execute scripts automatically, default available from "
"system preferences");
-
- ot->exec = wm_revert_mainfile_exec;
- ot->poll = wm_revert_mainfile_poll;
}
/** \} */
@@ -2445,8 +2464,8 @@ void WM_OT_recover_last_session(wmOperatorType *ot)
ot->name = "Recover Last Session";
ot->idname = "WM_OT_recover_last_session";
ot->description = "Open the last closed file (\"" BLENDER_QUIT_FILE "\")";
- ot->invoke = WM_operator_confirm;
+ ot->invoke = WM_operator_confirm;
ot->exec = wm_recover_last_session_exec;
}
@@ -2488,15 +2507,15 @@ void WM_OT_recover_auto_save(wmOperatorType *ot)
ot->idname = "WM_OT_recover_auto_save";
ot->description = "Open an automatically saved file to recover it";
- ot->exec = wm_recover_auto_save_exec;
ot->invoke = wm_recover_auto_save_invoke;
+ ot->exec = wm_recover_auto_save_exec;
WM_operator_properties_filesel(ot,
FILE_TYPE_BLENDER,
FILE_BLENDER,
FILE_OPENFILE,
WM_FILESEL_FILEPATH,
- FILE_LONGDISPLAY,
+ FILE_VERTICALDISPLAY,
FILE_SORT_TIME);
}
@@ -2630,7 +2649,7 @@ void WM_OT_save_as_mainfile(wmOperatorType *ot)
{
PropertyRNA *prop;
- ot->name = "Save As Blender File";
+ ot->name = "Save As";
ot->idname = "WM_OT_save_as_mainfile";
ot->description = "Save the current file in the desired location";
@@ -3038,7 +3057,7 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C, struct ARegi
BLI_path_extension_replace(filename, sizeof(filename), "");
}
else {
- BLI_snprintf(filename, sizeof(filename), IFACE_("Untitled"));
+ STRNCPY(filename, IFACE_("Untitled"));
}
/* Title */
@@ -3074,6 +3093,12 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C, struct ARegi
BKE_reports_init(&reports, RPT_STORE);
uint modified_images_count = ED_image_save_all_modified_info(C, &reports);
+ LISTBASE_FOREACH (Report *, report, &reports.list) {
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiLayoutSetRedAlert(row, true);
+ uiItemL(row, report->message, ICON_CANCEL);
+ }
+
if (modified_images_count > 0) {
char message[64];
BLI_snprintf(message,
@@ -3099,13 +3124,9 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C, struct ARegi
"");
}
- LISTBASE_FOREACH (Report *, report, &reports.list) {
- uiItemL(layout, report->message, ICON_ERROR);
- }
-
BKE_reports_clear(&reports);
- uiItemL(layout, "", ICON_NONE);
+ uiItemS_ex(layout, 3.0f);
/* Buttons */
#ifdef _WIN32
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 5a6606984ba..3374d17cbfd 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -55,7 +55,6 @@
#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_report.h"
-#include "BKE_scene.h"
#include "BKE_idcode.h"
@@ -561,7 +560,7 @@ static void wm_link_append_properties_common(wmOperatorType *ot, bool is_link)
void WM_OT_link(wmOperatorType *ot)
{
- ot->name = "Link from Library";
+ ot->name = "Link";
ot->idname = "WM_OT_link";
ot->description = "Link from a Library .blend file";
@@ -576,7 +575,7 @@ void WM_OT_link(wmOperatorType *ot)
FILE_LOADLIB,
FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME |
- WM_FILESEL_RELPATH | WM_FILESEL_FILES,
+ WM_FILESEL_RELPATH | WM_FILESEL_FILES | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
@@ -585,7 +584,7 @@ void WM_OT_link(wmOperatorType *ot)
void WM_OT_append(wmOperatorType *ot)
{
- ot->name = "Append from Library";
+ ot->name = "Append";
ot->idname = "WM_OT_append";
ot->description = "Append from a Library .blend file";
@@ -600,7 +599,7 @@ void WM_OT_append(wmOperatorType *ot)
FILE_LOADLIB,
FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME |
- WM_FILESEL_FILES,
+ WM_FILESEL_FILES | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 29cb02888ac..70d83153840 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -41,7 +41,6 @@
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
-#include "BLI_callbacks.h"
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
@@ -54,7 +53,7 @@
#include "BKE_blendfile.h"
#include "BKE_blender.h"
-#include "BKE_blender_undo.h"
+#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_font.h"
#include "BKE_global.h"
@@ -120,7 +119,6 @@
#include "GPU_material.h"
#include "GPU_draw.h"
-#include "GPU_immediate.h"
#include "GPU_init_exit.h"
#include "BKE_sound.h"
@@ -215,7 +213,7 @@ static void sound_jack_sync_callback(Main *bmain, int mode, float time)
continue;
}
ViewLayer *view_layer = WM_window_get_active_view_layer(window);
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, false);
if (depsgraph == NULL) {
continue;
}
@@ -288,6 +286,10 @@ void WM_init(bContext *C, int argc, const char **argv)
const bool use_data = true;
const bool use_userdef = true;
+ /* Studio-lights needs to be init before we read the home-file,
+ * otherwise the versioning cannot find the default studio-light. */
+ BKE_studiolight_init();
+
wm_homefile_read(C,
NULL,
G.factory_startup,
@@ -315,8 +317,6 @@ void WM_init(bContext *C, int argc, const char **argv)
UI_init();
}
- BKE_studiolight_init();
-
ED_spacemacros_init();
/* note: there is a bug where python needs initializing before loading the
@@ -376,10 +376,10 @@ void WM_init(bContext *C, int argc, const char **argv)
* note that recovering the last session does its own callbacks. */
CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_VERSION_UPDATE);
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_POST);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_VERSION_UPDATE);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_LOAD_POST);
if (is_factory_startup) {
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_FACTORY_STARTUP_POST);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_LOAD_FACTORY_STARTUP_POST);
}
wm_file_read_report(C, bmain);
@@ -524,6 +524,7 @@ void WM_exit_ex(bContext *C, const bool do_python)
BKE_addon_pref_type_free();
BKE_keyconfig_pref_type_free();
+ BKE_material_gpencil_default_free();
wm_operatortype_free();
wm_dropbox_free();
@@ -680,3 +681,12 @@ void WM_exit(bContext *C)
exit(G.is_break == true);
}
+
+/**
+ * Needed for cases when operators are re-registered
+ * (when operator type pointers are stored).
+ */
+void WM_script_tag_reload(void)
+{
+ UI_interface_tag_script_reload();
+}
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index fcb55d3f801..a8feb22cbf8 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -65,14 +65,14 @@ void WM_operator_properties_filesel(wmOperatorType *ot,
0,
"Default",
"Automatically determine display type for files"},
- {FILE_SHORTDISPLAY,
- "LIST_SHORT",
- ICON_SHORTDISPLAY,
+ {FILE_VERTICALDISPLAY,
+ "LIST_VERTICAL",
+ ICON_SHORTDISPLAY, /* Name of deprecated short list */
"Short List",
"Display files as short list"},
- {FILE_LONGDISPLAY,
- "LIST_LONG",
- ICON_LONGDISPLAY,
+ {FILE_HORIZONTALDISPLAY,
+ "LIST_HORIZONTAL",
+ ICON_LONGDISPLAY, /* Name of deprecated long list */
"Long List",
"Display files as a detailed list"},
{FILE_IMGDISPLAY, "THUMBNAIL", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"},
@@ -99,6 +99,15 @@ void WM_operator_properties_filesel(wmOperatorType *ot,
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
+ if ((flag & WM_FILESEL_SHOW_PROPS) == 0) {
+ prop = RNA_def_boolean(ot->srna,
+ "hide_props_region",
+ true,
+ "Hide Operator Properties",
+ "Collapse the region displaying the operator settings");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ }
+
if (action == FILE_SAVE) {
/* note, this is only used to check if we should highlight the filename area red when the
* filepath is an existing file. */
@@ -138,6 +147,9 @@ void WM_operator_properties_filesel(wmOperatorType *ot,
ot->srna, "filter_text", (filter & FILE_TYPE_TEXT) != 0, "Filter text files", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(
+ ot->srna, "filter_archive", (filter & FILE_TYPE_ARCHIVE) != 0, "Filter archive files", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(
ot->srna, "filter_btx", (filter & FILE_TYPE_BTX) != 0, "Filter btx files", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(
@@ -479,19 +491,26 @@ void WM_operator_properties_mouse_select(wmOperatorType *ot)
*/
void WM_operator_properties_checker_interval(wmOperatorType *ot, bool nth_can_disable)
{
- const int nth_default = nth_can_disable ? 1 : 2;
- const int nth_min = min_ii(nth_default, 2);
+ const int nth_default = nth_can_disable ? 0 : 1;
+ const int nth_min = min_ii(nth_default, 1);
RNA_def_int(ot->srna,
- "nth",
+ "skip",
nth_default,
nth_min,
INT_MAX,
- "Nth Element",
- "Skip every Nth element",
+ "Deselected",
+ "Number of deselected elements in the repetitive sequence",
nth_min,
100);
- RNA_def_int(
- ot->srna, "skip", 1, 1, INT_MAX, "Skip", "Number of elements to skip at once", 1, 100);
+ RNA_def_int(ot->srna,
+ "nth",
+ 1,
+ 1,
+ INT_MAX,
+ "Selected",
+ "Number of selected elements in the repetitive sequence",
+ 1,
+ 100);
RNA_def_int(ot->srna,
"offset",
0,
@@ -506,7 +525,7 @@ void WM_operator_properties_checker_interval(wmOperatorType *ot, bool nth_can_di
void WM_operator_properties_checker_interval_from_op(struct wmOperator *op,
struct CheckerIntervalParams *op_params)
{
- const int nth = RNA_int_get(op->ptr, "nth") - 1;
+ const int nth = RNA_int_get(op->ptr, "nth");
const int skip = RNA_int_get(op->ptr, "skip");
int offset = RNA_int_get(op->ptr, "offset");
@@ -520,6 +539,6 @@ void WM_operator_properties_checker_interval_from_op(struct wmOperator *op,
bool WM_operator_properties_checker_interval_test(const struct CheckerIntervalParams *op_params,
int depth)
{
- return ((op_params->nth == 0) ||
+ return ((op_params->skip == 0) ||
((op_params->offset + depth) % (op_params->skip + op_params->nth) >= op_params->skip));
}
diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c
index 8f3052ace5e..e3fe8892515 100644
--- a/source/blender/windowmanager/intern/wm_operator_type.c
+++ b/source/blender/windowmanager/intern/wm_operator_type.c
@@ -227,8 +227,8 @@ void wm_operatortype_free(void)
*/
void WM_operatortype_props_advanced_begin(wmOperatorType *ot)
{
- if (ot_prop_basic_count ==
- -1) { /* Don't do anything if _begin was called before, but not _end */
+ if (ot_prop_basic_count == -1) {
+ /* Don't do anything if _begin was called before, but not _end */
ot_prop_basic_count = RNA_struct_count_properties(ot->srna);
}
}
@@ -595,4 +595,35 @@ const char *WM_operatortype_name(struct wmOperatorType *ot, struct PointerRNA *p
return (name && name[0]) ? name : RNA_struct_ui_name(ot->srna);
}
+char *WM_operatortype_description(struct bContext *C,
+ struct wmOperatorType *ot,
+ struct PointerRNA *properties)
+{
+ if (ot->get_description && properties) {
+ char *description = ot->get_description(C, ot, properties);
+
+ if (description) {
+ if (description[0]) {
+ return description;
+ }
+ else {
+ MEM_freeN(description);
+ }
+ }
+ }
+
+ const char *info = RNA_struct_ui_description(ot->srna);
+
+ if (!(info && info[0])) {
+ info = RNA_struct_ui_name(ot->srna);
+ }
+
+ if (info && info[0]) {
+ return BLI_strdup(info);
+ }
+ else {
+ return NULL;
+ }
+}
+
/** \} */
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index b10a4ce6794..285379e90c6 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -41,6 +41,7 @@
#include "CLG_log.h"
#include "DNA_ID.h"
+#include "DNA_brush_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_scene_types.h"
@@ -58,6 +59,7 @@
#include "BLI_utildefines.h"
#include "BKE_brush.h"
+#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_icons.h"
@@ -140,13 +142,13 @@ void WM_operator_bl_idname(char *to, const char *from)
if (from) {
const char *sep = strchr(from, '.');
- if (sep) {
- int ofs = (sep - from);
-
+ int from_len;
+ if (sep && (from_len = strlen(from)) < OP_MAX_TYPENAME - 3) {
+ const int ofs = (sep - from);
memcpy(to, from, sizeof(char) * ofs);
BLI_str_toupper_ascii(to, ofs);
- strcpy(to + ofs, "_OT_");
- strcpy(to + (ofs + 4), sep + 1);
+ memcpy(to + ofs, "_OT_", 4);
+ memcpy(to + (ofs + 4), sep + 1, (from_len - ofs));
}
else {
/* should not happen but support just in case */
@@ -539,7 +541,7 @@ char *WM_prop_pystring_assign(bContext *C, PointerRNA *ptr, PropertyRNA *prop, i
if (lhs == NULL) {
/* fallback to bpy.data.foo[id] if we dont find in the context */
- lhs = RNA_path_full_property_py(ptr, prop, index);
+ lhs = RNA_path_full_property_py(CTX_data_main(C), ptr, prop, index);
}
if (!lhs) {
@@ -850,7 +852,7 @@ static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg)
NULL);
/* Move it downwards, mouse over button. */
- UI_block_bounds_set_popup(block, 6, (const int[2]){0, -UI_UNIT_Y});
+ UI_block_bounds_set_popup(block, 0.3f * U.widget_unit, (const int[2]){0, -UI_UNIT_Y});
UI_but_focus_on_enter_event(win, but);
@@ -1126,18 +1128,15 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op)
if (op->type->flag & OPTYPE_MACRO) {
for (op = op->macro.first; op; op = op->next) {
uiTemplateOperatorPropertyButs(
- C, layout, op, UI_BUT_LABEL_ALIGN_SPLIT_COLUMN, UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
- if (op->next) {
- uiItemS(layout);
- }
+ C, layout, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
}
}
else {
uiTemplateOperatorPropertyButs(
- C, layout, op, UI_BUT_LABEL_ALIGN_SPLIT_COLUMN, UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
+ C, layout, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
}
- UI_block_bounds_set_popup(block, 4, NULL);
+ UI_block_bounds_set_popup(block, 6 * U.dpi_fac, NULL);
return block;
}
@@ -1217,7 +1216,8 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData)
}
/* center around the mouse */
- UI_block_bounds_set_popup(block, 4, (const int[2]){data->width / -2, data->height / 2});
+ UI_block_bounds_set_popup(
+ block, 6 * U.dpi_fac, (const int[2]){data->width / -2, data->height / 2});
UI_block_active_only_flagged_buttons(C, ar, block);
@@ -1245,7 +1245,7 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *ar, void *userData)
UI_block_func_set(block, NULL, NULL, NULL);
- UI_block_bounds_set_popup(block, 4, NULL);
+ UI_block_bounds_set_popup(block, 6 * U.dpi_fac, NULL);
UI_block_active_only_flagged_buttons(C, ar, block);
@@ -1516,7 +1516,7 @@ static uiBlock *wm_block_search_menu(bContext *C, ARegion *ar, void *userdata)
NULL);
/* Move it downwards, mouse over button. */
- UI_block_bounds_set_popup(block, 6, (const int[2]){0, -UI_UNIT_Y});
+ UI_block_bounds_set_popup(block, 0.3f * U.widget_unit, (const int[2]){0, -UI_UNIT_Y});
return block;
}
@@ -1864,6 +1864,7 @@ typedef struct {
StructRNA *image_id_srna;
float initial_value, current_value, min_value, max_value;
int initial_mouse[2];
+ int initial_co[2];
int slow_mouse[2];
bool slow_mode;
Dial *dial;
@@ -1926,6 +1927,9 @@ static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *e
rc->initial_mouse[0] = event->x;
rc->initial_mouse[1] = event->y;
+ rc->initial_co[0] = event->x;
+ rc->initial_co[1] = event->y;
+
switch (rc->subtype) {
case PROP_NONE:
case PROP_DISTANCE:
@@ -1937,7 +1941,7 @@ static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *e
WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
break;
case PROP_FACTOR:
- d[0] = (1 - rc->initial_value) * WM_RADIAL_CONTROL_DISPLAY_WIDTH +
+ d[0] = rc->initial_value * WM_RADIAL_CONTROL_DISPLAY_WIDTH +
WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
break;
case PROP_ANGLE:
@@ -1964,8 +1968,10 @@ static void radial_control_set_tex(RadialControl *rc)
switch (RNA_type_to_ID_code(rc->image_id_ptr.type)) {
case ID_BR:
- if ((ibuf = BKE_brush_gen_radial_control_imbuf(rc->image_id_ptr.data,
- rc->use_secondary_tex))) {
+ if ((ibuf = BKE_brush_gen_radial_control_imbuf(
+ rc->image_id_ptr.data,
+ rc->use_secondary_tex,
+ !ELEM(rc->subtype, PROP_NONE, PROP_PIXEL, PROP_DISTANCE)))) {
glGenTextures(1, &rc->gltex);
glBindTexture(GL_TEXTURE_2D, rc->gltex);
glTexImage2D(
@@ -2063,6 +2069,22 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph
immUnbindProgram();
}
+static void radial_control_paint_curve(uint pos, Brush *br, float radius, int line_segments)
+{
+ GPU_line_width(2.0f);
+ immUniformColor4f(0.8f, 0.8f, 0.8f, 0.85f);
+ float step = (radius * 2.0f) / (float)line_segments;
+ BKE_curvemapping_initialize(br->curve);
+ immBegin(GPU_PRIM_LINES, line_segments * 2);
+ for (int i = 0; i < line_segments; i++) {
+ float h1 = BKE_brush_curve_strength_clamped(br, fabsf((i * step) - radius), radius);
+ immVertex2f(pos, -radius + (i * step), h1 * radius);
+ float h2 = BKE_brush_curve_strength_clamped(br, fabsf(((i + 1) * step) - radius), radius);
+ immVertex2f(pos, -radius + ((i + 1) * step), h2 * radius);
+ }
+ immEnd();
+}
+
static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void *customdata)
{
RadialControl *rc = customdata;
@@ -2096,7 +2118,7 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void
alpha = 0.75;
break;
case PROP_FACTOR:
- r1 = (1 - rc->current_value) * WM_RADIAL_CONTROL_DISPLAY_WIDTH +
+ r1 = rc->current_value * WM_RADIAL_CONTROL_DISPLAY_WIDTH +
WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
r2 = tex_radius = WM_RADIAL_CONTROL_DISPLAY_SIZE;
rmin = WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
@@ -2117,9 +2139,17 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void
break;
}
- /* Keep cursor in the original place */
- x = rc->initial_mouse[0];
- y = rc->initial_mouse[1];
+ if (rc->subtype == PROP_ANGLE) {
+ /* Use the initial mouse position to draw the rotation preview. This avoids starting the
+ * rotation in a random direction */
+ x = rc->initial_mouse[0];
+ y = rc->initial_mouse[1];
+ }
+ else {
+ /* Keep cursor in the original place */
+ x = rc->initial_co[0];
+ y = rc->initial_co[1];
+ }
GPU_matrix_translate_2f((float)x, (float)y);
GPU_blend(true);
@@ -2143,7 +2173,6 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor3fvAlpha(col, 0.5f);
if (rc->subtype == PROP_ANGLE) {
GPU_matrix_push();
@@ -2166,25 +2195,40 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void
}
/* draw circles on top */
- imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r1, 40);
- imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r2, 40);
+ GPU_line_width(2.0f);
+ immUniformColor3fvAlpha(col, 0.8f);
+ imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r1, 80);
+
+ GPU_line_width(1.0f);
+ immUniformColor3fvAlpha(col, 0.5f);
+ imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r2, 80);
if (rmin > 0.0f) {
- imm_draw_circle_wire_2d(pos, 0.0, 0.0f, rmin, 40);
+ /* Inner fill circle to increase the contrast of the value */
+ float black[3] = {0.0f};
+ immUniformColor3fvAlpha(black, 0.2f);
+ imm_draw_circle_fill_2d(pos, 0.0, 0.0f, rmin, 80);
+
+ immUniformColor3fvAlpha(col, 0.5f);
+ imm_draw_circle_wire_2d(pos, 0.0, 0.0f, rmin, 80);
}
+
+ /* draw curve falloff preview */
+ if (RNA_type_to_ID_code(rc->image_id_ptr.type) == ID_BR && rc->subtype == PROP_FACTOR) {
+ Brush *br = rc->image_id_ptr.data;
+ if (br) {
+ radial_control_paint_curve(pos, br, r2, 120);
+ }
+ }
+
immUnbindProgram();
- BLF_size(fontid, 1.5 * fstyle_points * U.pixelsize, U.dpi);
- BLF_enable(fontid, BLF_SHADOW);
- BLF_shadow(fontid, 3, (const float[4]){0.0f, 0.0f, 0.0f, 0.5f});
- BLF_shadow_offset(fontid, 1, -1);
+ BLF_size(fontid, 1.75f * fstyle_points * U.pixelsize, U.dpi);
/* draw value */
BLF_width_and_height(fontid, str, strdrawlen, &strwidth, &strheight);
BLF_position(fontid, -0.5f * strwidth, -0.5f * strheight, 0.0f);
BLF_draw(fontid, str, strdrawlen);
- BLF_disable(fontid, BLF_SHADOW);
-
GPU_blend(false);
GPU_line_smooth(false);
}
@@ -2635,6 +2679,8 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
if (snap) {
new_value = ((int)ceil(new_value * 10.f) * 10.0f) / 100.f;
}
+ /* Invert new value to increase the factor moving the mouse to the right */
+ new_value = 1 - new_value;
break;
case PROP_ANGLE:
new_value = atan2f(delta[1], delta[0]) + (float)M_PI + angle_precision;
diff --git a/source/blender/windowmanager/intern/wm_splash_screen.c b/source/blender/windowmanager/intern/wm_splash_screen.c
index 8629997030f..d3f7661a008 100644
--- a/source/blender/windowmanager/intern/wm_splash_screen.c
+++ b/source/blender/windowmanager/intern/wm_splash_screen.c
@@ -113,31 +113,37 @@ static void wm_block_splash_add_label(uiBlock *block, const char *label, int x,
static void wm_block_splash_add_labels(uiBlock *block, int x, int y)
{
/* Version number. */
- const char *version_suffix = NULL;
+ const char *version_cycle = NULL;
bool show_build_info = true;
if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "alpha")) {
- version_suffix = " Alpha";
+ version_cycle = " Alpha";
}
else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "beta")) {
- version_suffix = " Beta";
+ version_cycle = " Beta";
}
else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "rc")) {
- version_suffix = " Release Candidate";
+ version_cycle = " Release Candidate";
show_build_info = false;
}
else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) {
- version_suffix = STRINGIFY(BLENDER_VERSION_CHAR);
+ version_cycle = STRINGIFY(BLENDER_VERSION_CHAR);
show_build_info = false;
}
+ const char *version_cycle_number = "";
+ if (strlen(STRINGIFY(BLENDER_VERSION_CYCLE_NUMBER))) {
+ version_cycle_number = " " STRINGIFY(BLENDER_VERSION_CYCLE_NUMBER);
+ }
+
char version_buf[256] = "\0";
BLI_snprintf(version_buf,
sizeof(version_buf),
- "v %d.%d%s",
+ "v %d.%d%s%s",
BLENDER_VERSION / 100,
BLENDER_VERSION % 100,
- version_suffix);
+ version_cycle,
+ version_cycle_number);
wm_block_splash_add_label(block, version_buf, x, &y);
diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c
index 874f8516caa..9b62e532132 100644
--- a/source/blender/windowmanager/intern/wm_stereo.c
+++ b/source/blender/windowmanager/intern/wm_stereo.c
@@ -43,7 +43,6 @@
#include "ED_screen.h"
#include "GPU_immediate.h"
-#include "GPU_framebuffer.h"
#include "GPU_texture.h"
#include "WM_api.h"
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 47491813f70..2c26a15dce0 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -44,7 +44,6 @@
#include "BLT_translation.h"
-#include "BKE_blender.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_icons.h"
@@ -83,8 +82,6 @@
#include "GPU_framebuffer.h"
#include "GPU_init_exit.h"
#include "GPU_immediate.h"
-#include "GPU_material.h"
-#include "GPU_texture.h"
#include "GPU_context.h"
#include "BLF_api.h"
@@ -709,7 +706,7 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm)
/* without this, cursor restore may fail, T45456 */
if (win->cursor == 0) {
- win->cursor = CURSOR_STD;
+ win->cursor = WM_CURSOR_DEFAULT;
}
wm_window_ghostwindow_add(wm, "Blender", win);
@@ -795,10 +792,11 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect)
* Uses `screen->temp` tag to define what to do, currently it limits
* to only one "temp" window for render out, preferences, filewindow, etc...
*
- * \param type: WM_WINDOW_RENDER, WM_WINDOW_USERPREFS...
- * \return the window or NULL.
+ * \param space_type: SPACE_VIEW3D, SPACE_INFO, ... (eSpace_Type)
+ * \return the window or NULL in case of failure.
*/
-wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, int type)
+wmWindow *WM_window_open_temp(
+ bContext *C, const char *title, int x, int y, int sizex, int sizey, int space_type)
{
Main *bmain = CTX_data_main(C);
wmWindow *win_prev = CTX_wm_window(C);
@@ -807,7 +805,6 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
ScrArea *sa;
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- const char *title;
/* convert to native OS window coordinates */
const float native_pixel_size = GHOST_GetNativePixelSize(win_prev->ghostwin);
@@ -887,46 +884,11 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
sa = screen->areabase.first;
CTX_wm_area_set(C, sa);
- if (type == WM_WINDOW_RENDER) {
- ED_area_newspace(C, sa, SPACE_IMAGE, false);
- }
- else if (type == WM_WINDOW_DRIVERS) {
- ED_area_newspace(C, sa, SPACE_GRAPH, false);
- }
- else if (type == WM_WINDOW_INFO) {
- ED_area_newspace(C, sa, SPACE_INFO, false);
- }
- else {
- ED_area_newspace(C, sa, SPACE_USERPREF, false);
- }
+ ED_area_newspace(C, sa, space_type, false);
ED_screen_change(C, screen);
ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */
- /* do additional setup for specific editor type */
- if (type == WM_WINDOW_DRIVERS) {
- ED_drivers_editor_init(C, sa);
- }
-
- if (sa->spacetype == SPACE_IMAGE) {
- title = IFACE_("Blender Render");
- }
- else if (ELEM(sa->spacetype, SPACE_OUTLINER, SPACE_USERPREF)) {
- title = IFACE_("Blender Preferences");
- }
- else if (sa->spacetype == SPACE_FILE) {
- title = IFACE_("Blender File View");
- }
- else if (sa->spacetype == SPACE_GRAPH) {
- title = IFACE_("Blender Drivers Editor");
- }
- else if (sa->spacetype == SPACE_INFO) {
- title = IFACE_("Blender Info Log");
- }
- else {
- title = "Blender";
- }
-
if (win->ghostwin) {
GHOST_SetTitle(win->ghostwin, title);
return win;
diff --git a/source/blender/windowmanager/wm_cursors.h b/source/blender/windowmanager/wm_cursors.h
index 6793937c413..7a28aeb3c70 100644
--- a/source/blender/windowmanager/wm_cursors.h
+++ b/source/blender/windowmanager/wm_cursors.h
@@ -24,80 +24,57 @@
#ifndef __WM_CURSORS_H__
#define __WM_CURSORS_H__
-void wm_init_cursor_data(void);
-
-#define BC_GHOST_CURSORS 1000
-
-/* old cursors */
-enum {
- CURSOR_FACESEL = BC_GHOST_CURSORS,
- CURSOR_WAIT,
- CURSOR_EDIT,
- CURSOR_X_MOVE,
- CURSOR_Y_MOVE,
- CURSOR_HELP,
- CURSOR_STD,
- CURSOR_NONE,
- CURSOR_PENCIL,
- CURSOR_COPY,
-};
-
-// typedef struct BCursor_s BCursor;
-typedef struct BCursor {
-
- char *small_bm;
- char *small_mask;
-
- char small_sizex;
- char small_sizey;
- char small_hotx;
- char small_hoty;
-
- char *big_bm;
- char *big_mask;
-
- char big_sizex;
- char big_sizey;
- char big_hotx;
- char big_hoty;
-
- bool can_invert_color;
+struct wmEvent;
+struct wmWindow;
-} BCursor;
+typedef enum WMCursorType {
+ WM_CURSOR_DEFAULT = 1,
+ WM_CURSOR_TEXT_EDIT,
+ WM_CURSOR_WAIT,
+ WM_CURSOR_STOP,
+ WM_CURSOR_EDIT,
+ WM_CURSOR_COPY,
+ WM_CURSOR_HAND,
+
+ WM_CURSOR_CROSS,
+ WM_CURSOR_PAINT,
+ WM_CURSOR_DOT,
+ WM_CURSOR_CROSSC,
+
+ WM_CURSOR_KNIFE,
+ WM_CURSOR_VERTEX_LOOP,
+ WM_CURSOR_PAINT_BRUSH,
+ WM_CURSOR_ERASER,
+ WM_CURSOR_EYEDROPPER,
+
+ WM_CURSOR_SWAP_AREA,
+ WM_CURSOR_X_MOVE,
+ WM_CURSOR_Y_MOVE,
+ WM_CURSOR_H_SPLIT,
+ WM_CURSOR_V_SPLIT,
+
+ WM_CURSOR_NW_ARROW,
+ WM_CURSOR_NS_ARROW,
+ WM_CURSOR_EW_ARROW,
+ WM_CURSOR_N_ARROW,
+ WM_CURSOR_S_ARROW,
+ WM_CURSOR_E_ARROW,
+ WM_CURSOR_W_ARROW,
+
+ WM_CURSOR_NSEW_SCROLL,
+ WM_CURSOR_NS_SCROLL,
+ WM_CURSOR_EW_SCROLL,
+
+ WM_CURSOR_ZOOM_IN,
+ WM_CURSOR_ZOOM_OUT,
+
+ WM_CURSOR_NONE,
-#define SYSCURSOR 1
-enum {
- BC_NW_ARROWCURSOR = 2,
- BC_NS_ARROWCURSOR,
- BC_EW_ARROWCURSOR,
- BC_WAITCURSOR,
- BC_CROSSCURSOR,
- BC_EDITCROSSCURSOR,
- BC_BOXSELCURSOR,
- BC_KNIFECURSOR,
- BC_VLOOPCURSOR,
- BC_TEXTEDITCURSOR,
- BC_PAINTBRUSHCURSOR,
- BC_HANDCURSOR,
- BC_NSEW_SCROLLCURSOR,
- BC_NS_SCROLLCURSOR,
- BC_EW_SCROLLCURSOR,
- BC_EYEDROPPER_CURSOR,
- BC_SWAPAREA_CURSOR,
- BC_H_SPLITCURSOR,
- BC_V_SPLITCURSOR,
- BC_N_ARROWCURSOR,
- BC_S_ARROWCURSOR,
- BC_E_ARROWCURSOR,
- BC_W_ARROWCURSOR,
- BC_STOPCURSOR,
/* --- ALWAYS LAST ----- */
- BC_NUMCURSORS,
-};
-
-struct wmEvent;
-struct wmWindow;
+ WM_CURSOR_NUM,
+} WMCursorType;
+void wm_init_cursor_data(void);
bool wm_cursor_arrow_move(struct wmWindow *win, const struct wmEvent *event);
#endif /* __WM_CURSORS_H__ */
diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h
index 53b25a80dce..c53ccda170a 100644
--- a/source/blender/windowmanager/wm_event_system.h
+++ b/source/blender/windowmanager/wm_event_system.h
@@ -116,6 +116,10 @@ typedef struct wmEventHandler_Op {
/** Store context for this handler for derived/modal handlers. */
struct {
+ /* To override the window, and hence the screen. Set for few cases only, usually window/screen
+ * can be taken from current context. */
+ struct wmWindow *win;
+
struct ScrArea *area;
struct ARegion *region;
short region_type;
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index f74fd57252d..8fb4d2905f4 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -133,7 +133,7 @@ if(WIN32 AND NOT UNIX)
string(SUBSTRING ${BLENDER_VERSION} 2 1 bver2)
string(SUBSTRING ${BLENDER_VERSION} 3 1 bver3)
add_definitions(
- -DBLEN_VER_RC_STR=${BLENDER_VERSION}
+ -DBLEN_VER_RC_STR="${BLENDER_VERSION}"
-DBLEN_VER_RC_1=${bver1}
-DBLEN_VER_RC_2=${bver2}
-DBLEN_VER_RC_3=${bver3}
@@ -584,6 +584,7 @@ if(UNIX AND NOT APPLE)
PATTERN "test" EXCLUDE # ./test
PATTERN "turtledemo" EXCLUDE # ./turtledemo
PATTERN "turtle.py" EXCLUDE # ./turtle.py
+ PATTERN "wininst*.exe" EXCLUDE # from distutils, avoid malware false positive
)
# Needed for distutils/pip
@@ -747,13 +748,13 @@ elseif(WIN32)
if(WINDOWS_PYTHON_DEBUG)
install(
- FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.pdb
+ FILES ${LIBDIR}/python/37/libs/python${_PYTHON_VERSION_NO_DOTS}.pdb
DESTINATION "."
CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel
)
install(
- FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}_d.pdb
+ FILES ${LIBDIR}/python/37/libs/python${_PYTHON_VERSION_NO_DOTS}_d.pdb
DESTINATION "."
CONFIGURATIONS Debug
)
@@ -820,18 +821,6 @@ elseif(WIN32)
)
endif()
- if(NOT CMAKE_CL_64)
- install(
- FILES ${LIBDIR}/thumbhandler/lib/BlendThumb.dll
- DESTINATION "."
- )
- endif()
-
- install( # x86 builds can run on x64 Windows, so this is required at all times
- FILES ${LIBDIR}/thumbhandler/lib/BlendThumb64.dll
- DESTINATION "."
- )
-
install(
FILES
${CMAKE_SOURCE_DIR}/release/windows/batch/blender_debug_gpu.cmd
@@ -874,6 +863,7 @@ elseif(APPLE)
PATTERN "test" EXCLUDE # ./test
PATTERN "turtledemo" EXCLUDE # ./turtledemo
PATTERN "turtle.py" EXCLUDE # ./turtle.py
+ PATTERN "wininst*.exe" EXCLUDE # from distutils, avoid malware false positive
)
endmacro()
diff --git a/source/creator/creator.c b/source/creator/creator.c
index 6fd472d24c5..3632eb9eb9a 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -38,7 +38,6 @@
#include "BLI_args.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
-#include "BLI_callbacks.h"
#include "BLI_string.h"
#include "BLI_system.h"
@@ -47,6 +46,7 @@
#include "BKE_blender.h"
#include "BKE_brush.h"
#include "BKE_cachefile.h"
+#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_font.h"
#include "BKE_global.h"
@@ -357,7 +357,7 @@ int main(int argc,
BKE_brush_system_init();
RE_texture_rng_init();
- BLI_callback_global_init();
+ BKE_callback_global_init();
/* first test for background */
#ifndef WITH_PYTHON_MODULE
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index e175dbfbb96..936bdf52c91 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -72,8 +72,6 @@
# include "WM_api.h"
-# include "GPU_draw.h"
-
# ifdef WITH_LIBMV
# include "libmv-capi.h"
# endif
@@ -876,7 +874,7 @@ static int arg_handle_log_set(int argc, const char **argv, void *UNUSED(data))
}
if (str_step_end) {
- /* typically only be one, but don't fail on multiple.*/
+ /* Typically only be one, but don't fail on multiple. */
while (*str_step_end == ',') {
str_step_end++;
}
@@ -1109,14 +1107,14 @@ static int arg_handle_factory_startup_set(int UNUSED(argc),
return 0;
}
-static const char arg_handle_enable_override_library_doc[] =
+static const char arg_handle_disable_override_library_doc[] =
"\n\t"
"Enable Library Override features in the UI.";
-static int arg_handle_enable_override_library(int UNUSED(argc),
- const char **UNUSED(argv),
- void *UNUSED(data))
+static int arg_handle_disable_override_library(int UNUSED(argc),
+ const char **UNUSED(argv),
+ void *UNUSED(data))
{
- BKE_override_library_enable(true);
+ BKE_override_library_enable(false);
return 0;
}
@@ -2174,7 +2172,7 @@ void main_args_setup(bContext *C, bArgs *ba)
BLI_argsAdd(ba, 1, NULL, "--app-template", CB(arg_handle_app_template), NULL);
BLI_argsAdd(ba, 1, NULL, "--factory-startup", CB(arg_handle_factory_startup_set), NULL);
BLI_argsAdd(
- ba, 1, NULL, "--enable-library-override", CB(arg_handle_enable_override_library), NULL);
+ ba, 1, NULL, "--disable-library-override", CB(arg_handle_disable_override_library), NULL);
BLI_argsAdd(ba, 1, NULL, "--enable-event-simulate", CB(arg_handle_enable_event_simulate), NULL);
/* TODO, add user env vars? */
diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c
index 5a5bc74d2d3..e8c6e9251bc 100644
--- a/source/creator/creator_signals.c
+++ b/source/creator/creator_signals.c
@@ -301,6 +301,12 @@ void main_signal_setup(void)
# endif
}
+# ifdef WIN32
+ /* Prevent any error mode dialogs from hanging the application. */
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX |
+ SEM_NOOPENFILEERRORBOX);
+# endif
+
if (app_state.signal.use_abort_handler) {
signal(SIGABRT, sig_handle_abort);
}
diff --git a/source/tools b/source/tools
-Subproject cc8fcc2294682c7608665e6e0180f0449aad230
+Subproject 7b740545cd039ddcadbfb9bffcac842476eee27
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 93bebaed4b2..7d8a1390628 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,4 +1,33 @@
+# Always run tests from install path, so all required scripts and libraries
+# are available and we are testing the actual installation layout.
+#
+# Getting the install path of the executable is somewhat involved, as there are
+# no direct CMake generator expressions to get the install paths of executables.
+if(GENERATOR_IS_MULTI_CONFIG)
+ string(REPLACE "\${BUILD_TYPE}" "$<CONFIG>" TEST_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
+else()
+ string(REPLACE "\${BUILD_TYPE}" "" TEST_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
+endif()
+
+# Path to Blender and Python executables for all platforms.
+if(MSVC)
+ set(TEST_BLENDER_EXE ${TEST_INSTALL_DIR}/blender.exe)
+ set(TEST_PYTHON_EXE "${TEST_INSTALL_DIR}/${BLENDER_VERSION_MAJOR}.${BLENDER_VERSION_MINOR}/python/bin/python$<$<CONFIG:Debug>:_d>")
+elseif(APPLE)
+ set(TEST_BLENDER_EXE ${TEST_INSTALL_DIR}/Blender.app/Contents/MacOS/Blender)
+ set(TEST_PYTHON_EXE)
+else()
+ set(TEST_BLENDER_EXE ${TEST_INSTALL_DIR}/blender)
+ set(TEST_PYTHON_EXE)
+endif()
+
+# For testing with Valgrind
+# set(TEST_BLENDER_EXE valgrind --track-origins=yes --error-limit=no ${TEST_BLENDER_EXE})
+
+# Standard Blender arguments for running tests.
+set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup)
+
# Python CTests
if(WITH_BLENDER AND WITH_PYTHON)
add_subdirectory(python)
diff --git a/tests/gtests/alembic/abc_export_test.cc b/tests/gtests/alembic/abc_export_test.cc
index f8010b02c96..3bddd2df6ba 100644
--- a/tests/gtests/alembic/abc_export_test.cc
+++ b/tests/gtests/alembic/abc_export_test.cc
@@ -54,7 +54,7 @@ class AlembicExportTest : public testing::Test {
/* TODO(sergey): Pass scene layer somehow? */
ViewLayer *view_layer = (ViewLayer *)scene.view_layers.first;
- settings.depsgraph = depsgraph = DEG_graph_new(&scene, view_layer, DAG_EVAL_VIEWPORT);
+ settings.depsgraph = depsgraph = DEG_graph_new(bmain, &scene, view_layer, DAG_EVAL_VIEWPORT);
settings.scene = &scene;
settings.view_layer = view_layer;
diff --git a/tests/gtests/blenlib/BLI_array_ref_test.cc b/tests/gtests/blenlib/BLI_array_ref_test.cc
new file mode 100644
index 00000000000..4507d9e6e84
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_array_ref_test.cc
@@ -0,0 +1,266 @@
+#include "testing/testing.h"
+#include "BLI_array_ref.h"
+#include "BLI_vector.h"
+
+using BLI::IndexRange;
+using IntVector = BLI::Vector<int>;
+using IntArrayRef = BLI::ArrayRef<int>;
+using MutableIntArrayRef = BLI::MutableArrayRef<int>;
+
+TEST(array_ref, FromSmallVector)
+{
+ IntVector a = {1, 2, 3};
+ IntArrayRef a_ref = a;
+ EXPECT_EQ(a_ref.size(), 3);
+ EXPECT_EQ(a_ref[0], 1);
+ EXPECT_EQ(a_ref[1], 2);
+ EXPECT_EQ(a_ref[2], 3);
+}
+
+TEST(array_ref, IsReferencing)
+{
+ int array[] = {3, 5, 8};
+ MutableIntArrayRef ref(array, ARRAY_SIZE(array));
+ EXPECT_EQ(ref.size(), 3);
+ EXPECT_EQ(ref[1], 5);
+ array[1] = 10;
+ EXPECT_EQ(ref[1], 10);
+}
+
+TEST(array_ref, DropBack)
+{
+ IntVector a = {4, 5, 6, 7};
+ auto slice = IntArrayRef(a).drop_back(2);
+ EXPECT_EQ(slice.size(), 2);
+ EXPECT_EQ(slice[0], 4);
+ EXPECT_EQ(slice[1], 5);
+}
+
+TEST(array_ref, DropBackAll)
+{
+ IntVector a = {4, 5, 6, 7};
+ auto slice = IntArrayRef(a).drop_back(a.size());
+ EXPECT_EQ(slice.size(), 0);
+}
+
+TEST(array_ref, DropFront)
+{
+ IntVector a = {4, 5, 6, 7};
+ auto slice = IntArrayRef(a).drop_front(1);
+ EXPECT_EQ(slice.size(), 3);
+ EXPECT_EQ(slice[0], 5);
+ EXPECT_EQ(slice[1], 6);
+ EXPECT_EQ(slice[2], 7);
+}
+
+TEST(array_ref, DropFrontAll)
+{
+ IntVector a = {4, 5, 6, 7};
+ auto slice = IntArrayRef(a).drop_front(a.size());
+ EXPECT_EQ(slice.size(), 0);
+}
+
+TEST(array_ref, TakeFront)
+{
+ IntVector a = {4, 5, 6, 7};
+ auto slice = IntArrayRef(a).take_front(2);
+ EXPECT_EQ(slice.size(), 2);
+ EXPECT_EQ(slice[0], 4);
+ EXPECT_EQ(slice[1], 5);
+}
+
+TEST(array_ref, TakeBack)
+{
+ IntVector a = {5, 6, 7, 8};
+ auto slice = IntArrayRef(a).take_back(2);
+ EXPECT_EQ(slice.size(), 2);
+ EXPECT_EQ(slice[0], 7);
+ EXPECT_EQ(slice[1], 8);
+}
+
+TEST(array_ref, Slice)
+{
+ IntVector a = {4, 5, 6, 7};
+ auto slice = IntArrayRef(a).slice(1, 2);
+ EXPECT_EQ(slice.size(), 2);
+ EXPECT_EQ(slice[0], 5);
+ EXPECT_EQ(slice[1], 6);
+}
+
+TEST(array_ref, SliceEmpty)
+{
+ IntVector a = {4, 5, 6, 7};
+ auto slice = IntArrayRef(a).slice(2, 0);
+ EXPECT_EQ(slice.size(), 0);
+}
+
+TEST(array_ref, SliceRange)
+{
+ IntVector a = {1, 2, 3, 4, 5};
+ auto slice = IntArrayRef(a).slice(IndexRange(2, 2));
+ EXPECT_EQ(slice.size(), 2);
+ EXPECT_EQ(slice[0], 3);
+ EXPECT_EQ(slice[1], 4);
+}
+
+TEST(array_ref, Contains)
+{
+ IntVector a = {4, 5, 6, 7};
+ IntArrayRef a_ref = a;
+ EXPECT_TRUE(a_ref.contains(4));
+ EXPECT_TRUE(a_ref.contains(5));
+ EXPECT_TRUE(a_ref.contains(6));
+ EXPECT_TRUE(a_ref.contains(7));
+ EXPECT_FALSE(a_ref.contains(3));
+ EXPECT_FALSE(a_ref.contains(8));
+}
+
+TEST(array_ref, Count)
+{
+ IntVector a = {2, 3, 4, 3, 3, 2, 2, 2, 2};
+ IntArrayRef a_ref = a;
+ EXPECT_EQ(a_ref.count(1), 0);
+ EXPECT_EQ(a_ref.count(2), 5);
+ EXPECT_EQ(a_ref.count(3), 3);
+ EXPECT_EQ(a_ref.count(4), 1);
+ EXPECT_EQ(a_ref.count(5), 0);
+}
+
+TEST(array_ref, ToSmallVector)
+{
+ IntVector a = {1, 2, 3, 4};
+ IntArrayRef a_ref = a;
+ IntVector b = a_ref;
+ IntVector::all_equal(a, b);
+}
+
+static void test_ref_from_initializer_list(IntArrayRef ref)
+{
+ EXPECT_EQ(ref.size(), 4);
+ EXPECT_EQ(ref[0], 3);
+ EXPECT_EQ(ref[1], 6);
+ EXPECT_EQ(ref[2], 8);
+ EXPECT_EQ(ref[3], 9);
+}
+
+TEST(array_ref, FromInitializerList)
+{
+ test_ref_from_initializer_list({3, 6, 8, 9});
+}
+
+TEST(array_ref, FromVector)
+{
+ std::vector<int> a = {1, 2, 3, 4};
+ IntArrayRef a_ref(a);
+ EXPECT_EQ(a_ref.size(), 4);
+ EXPECT_EQ(a_ref[0], 1);
+ EXPECT_EQ(a_ref[1], 2);
+ EXPECT_EQ(a_ref[2], 3);
+ EXPECT_EQ(a_ref[3], 4);
+}
+
+TEST(array_ref, FromArray)
+{
+ std::array<int, 2> a = {5, 6};
+ IntArrayRef a_ref(a);
+ EXPECT_EQ(a_ref.size(), 2);
+ EXPECT_EQ(a_ref[0], 5);
+ EXPECT_EQ(a_ref[1], 6);
+}
+
+TEST(array_ref, Fill)
+{
+ std::array<int, 5> a = {4, 5, 6, 7, 8};
+ MutableIntArrayRef a_ref(a);
+ a_ref.fill(1);
+ EXPECT_EQ(a[0], 1);
+ EXPECT_EQ(a[1], 1);
+ EXPECT_EQ(a[2], 1);
+ EXPECT_EQ(a[3], 1);
+ EXPECT_EQ(a[4], 1);
+}
+
+TEST(array_ref, FillIndices)
+{
+ std::array<int, 5> a = {0, 0, 0, 0, 0};
+ MutableIntArrayRef a_ref(a);
+ a_ref.fill_indices({0, 2, 3}, 1);
+ EXPECT_EQ(a[0], 1);
+ EXPECT_EQ(a[1], 0);
+ EXPECT_EQ(a[2], 1);
+ EXPECT_EQ(a[3], 1);
+ EXPECT_EQ(a[4], 0);
+}
+
+TEST(array_ref, CopyFrom)
+{
+ std::array<int, 3> a = {3, 4, 5};
+ MutableIntArrayRef a_ref(a);
+ EXPECT_EQ(a[0], 3);
+ EXPECT_EQ(a[1], 4);
+ EXPECT_EQ(a[2], 5);
+ a_ref.copy_from({1, 2, 3});
+ EXPECT_EQ(a[0], 1);
+ EXPECT_EQ(a[1], 2);
+ EXPECT_EQ(a[2], 3);
+}
+
+TEST(array_ref, ByteSize)
+{
+ std::array<int, 10> a;
+ IntArrayRef a_ref(a);
+ EXPECT_EQ(a_ref.byte_size(), sizeof(a));
+ EXPECT_EQ(a_ref.byte_size(), 40);
+}
+
+TEST(array_ref, CopyTo)
+{
+ std::array<int, 3> a = {5, 6, 7};
+ int b[3] = {0};
+ IntArrayRef a_ref(a);
+ a_ref.copy_to(b);
+
+ EXPECT_EQ(b[0], 5);
+ EXPECT_EQ(b[1], 6);
+ EXPECT_EQ(b[2], 7);
+}
+
+TEST(array_ref, FirstLast)
+{
+ std::array<int, 4> a = {6, 7, 8, 9};
+ IntArrayRef a_ref(a);
+ EXPECT_EQ(a_ref.first(), 6);
+ EXPECT_EQ(a_ref.last(), 9);
+}
+
+TEST(array_ref, FirstLast_OneElement)
+{
+ int a = 3;
+ IntArrayRef a_ref(&a, 1);
+ EXPECT_EQ(a_ref.first(), 3);
+ EXPECT_EQ(a_ref.last(), 3);
+}
+
+TEST(array_ref, Get)
+{
+ std::array<int, 3> a = {5, 6, 7};
+ IntArrayRef a_ref(a);
+ EXPECT_EQ(a_ref.get(0, 42), 5);
+ EXPECT_EQ(a_ref.get(1, 42), 6);
+ EXPECT_EQ(a_ref.get(2, 42), 7);
+ EXPECT_EQ(a_ref.get(3, 42), 42);
+ EXPECT_EQ(a_ref.get(4, 42), 42);
+}
+
+TEST(array_ref, ContainsPtr)
+{
+ std::array<int, 3> a = {5, 6, 7};
+ int other = 10;
+ IntArrayRef a_ref(a);
+ EXPECT_TRUE(a_ref.contains_ptr(&a[0] + 0));
+ EXPECT_TRUE(a_ref.contains_ptr(&a[0] + 1));
+ EXPECT_TRUE(a_ref.contains_ptr(&a[0] + 2));
+ EXPECT_FALSE(a_ref.contains_ptr(&a[0] + 3));
+ EXPECT_FALSE(a_ref.contains_ptr(&a[0] - 1));
+ EXPECT_FALSE(a_ref.contains_ptr(&other));
+}
diff --git a/tests/gtests/blenlib/BLI_array_test.cc b/tests/gtests/blenlib/BLI_array_test.cc
new file mode 100644
index 00000000000..33f84928d3d
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_array_test.cc
@@ -0,0 +1,103 @@
+#include "testing/testing.h"
+#include "BLI_array_cxx.h"
+
+using namespace BLI;
+
+TEST(array, DefaultConstructor)
+{
+ Array<int> array;
+ EXPECT_EQ(array.size(), 0);
+}
+
+TEST(array, SizeConstructor)
+{
+ Array<int> array(5);
+ EXPECT_EQ(array.size(), 5);
+}
+
+TEST(array, FillConstructor)
+{
+ Array<int> array(5, 8);
+ EXPECT_EQ(array.size(), 5);
+ EXPECT_EQ(array[0], 8);
+ EXPECT_EQ(array[1], 8);
+ EXPECT_EQ(array[2], 8);
+ EXPECT_EQ(array[3], 8);
+ EXPECT_EQ(array[4], 8);
+}
+
+TEST(array, InitializerListConstructor)
+{
+ Array<int> array = {4, 5, 6, 7};
+ EXPECT_EQ(array.size(), 4);
+ EXPECT_EQ(array[0], 4);
+ EXPECT_EQ(array[1], 5);
+ EXPECT_EQ(array[2], 6);
+ EXPECT_EQ(array[3], 7);
+}
+
+TEST(array, ArrayRefConstructor)
+{
+ int stackarray[4] = {6, 7, 8, 9};
+ ArrayRef<int> array_ref(stackarray, ARRAY_SIZE(stackarray));
+ Array<int> array(array_ref);
+ EXPECT_EQ(array.size(), 4);
+ EXPECT_EQ(array[0], 6);
+ EXPECT_EQ(array[1], 7);
+ EXPECT_EQ(array[2], 8);
+ EXPECT_EQ(array[3], 9);
+}
+
+TEST(array, CopyConstructor)
+{
+ Array<int> array = {5, 6, 7, 8};
+ Array<int> new_array(array);
+
+ EXPECT_EQ(array.size(), 4);
+ EXPECT_EQ(new_array.size(), 4);
+ EXPECT_NE(array.begin(), new_array.begin());
+ EXPECT_EQ(new_array[0], 5);
+ EXPECT_EQ(new_array[1], 6);
+ EXPECT_EQ(new_array[2], 7);
+ EXPECT_EQ(new_array[3], 8);
+}
+
+TEST(array, MoveConstructor)
+{
+ Array<int> array = {5, 6, 7, 8};
+ Array<int> new_array(std::move(array));
+
+ EXPECT_EQ(array.size(), 0);
+ EXPECT_EQ(new_array.size(), 4);
+ EXPECT_EQ(new_array[0], 5);
+ EXPECT_EQ(new_array[1], 6);
+ EXPECT_EQ(new_array[2], 7);
+ EXPECT_EQ(new_array[3], 8);
+}
+
+TEST(array, CopyAssignment)
+{
+ Array<int> array = {1, 2, 3};
+ Array<int> new_array = {4};
+ EXPECT_EQ(new_array.size(), 1);
+ new_array = array;
+ EXPECT_EQ(new_array.size(), 3);
+ EXPECT_EQ(array.size(), 3);
+ EXPECT_NE(array.begin(), new_array.begin());
+ EXPECT_EQ(new_array[0], 1);
+ EXPECT_EQ(new_array[1], 2);
+ EXPECT_EQ(new_array[2], 3);
+}
+
+TEST(array, MoveAssignment)
+{
+ Array<int> array = {1, 2, 3};
+ Array<int> new_array = {4};
+ EXPECT_EQ(new_array.size(), 1);
+ new_array = std::move(array);
+ EXPECT_EQ(new_array.size(), 3);
+ EXPECT_EQ(array.size(), 0);
+ EXPECT_EQ(new_array[0], 1);
+ EXPECT_EQ(new_array[1], 2);
+ EXPECT_EQ(new_array[2], 3);
+}
diff --git a/tests/gtests/blenlib/BLI_delaunay_2d_test.cc b/tests/gtests/blenlib/BLI_delaunay_2d_test.cc
index ce84baf802a..315e5804784 100644
--- a/tests/gtests/blenlib/BLI_delaunay_2d_test.cc
+++ b/tests/gtests/blenlib/BLI_delaunay_2d_test.cc
@@ -15,8 +15,6 @@ extern "C" {
#include <fstream>
#include <sstream>
-#define DLNY_EPSILON 1e-8
-
static void fill_input_verts(CDT_input *r_input, float (*vcos)[2], int nverts)
{
r_input->verts_len = nverts;
@@ -27,7 +25,7 @@ static void fill_input_verts(CDT_input *r_input, float (*vcos)[2], int nverts)
r_input->faces = NULL;
r_input->faces_start_table = NULL;
r_input->faces_len_table = NULL;
- r_input->epsilon = 1e-6f;
+ r_input->epsilon = 1e-5f;
}
static void add_input_edges(CDT_input *r_input, int (*edges)[2], int nedges)
@@ -643,6 +641,32 @@ TEST(delaunay, TwoSquaresOverlap)
BLI_delaunay_2d_cdt_free(out);
}
+TEST(delaunay, TriCutoff)
+{
+ CDT_input in;
+ CDT_result *out;
+ float p[][2] = {
+ {-3.53009f, 1.29403f},
+ {-4.11844f, -1.08375f},
+ {1.56893f, 1.29403f},
+ {0.621034f, 0.897734f},
+ {0.549125f, 1.29403f},
+ };
+ int f[] = {0, 2, 1};
+ int fstart[] = {0};
+ int flen[] = {3};
+ int e[][2] = {{3, 4}};
+
+ fill_input_verts(&in, p, 5);
+ add_input_faces(&in, f, fstart, flen, 1);
+ add_input_edges(&in, e, 1);
+ out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS_VALID_BMESH);
+ EXPECT_EQ(out->verts_len, 5);
+ EXPECT_EQ(out->edges_len, 6);
+ EXPECT_EQ(out->faces_len, 2);
+ BLI_delaunay_2d_cdt_free(out);
+}
+
enum {
RANDOM_PTS,
RANDOM_SEGS,
diff --git a/tests/gtests/blenlib/BLI_index_range_test.cc b/tests/gtests/blenlib/BLI_index_range_test.cc
new file mode 100644
index 00000000000..1944279999d
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_index_range_test.cc
@@ -0,0 +1,131 @@
+#include "testing/testing.h"
+#include "BLI_index_range.h"
+#include "BLI_vector.h"
+
+using BLI::ArrayRef;
+using BLI::IndexRange;
+using IntVector = BLI::Vector<int>;
+
+TEST(index_range, DefaultConstructor)
+{
+ IndexRange range;
+ EXPECT_EQ(range.size(), 0);
+
+ IntVector vector;
+ for (int value : range) {
+ vector.append(value);
+ }
+ EXPECT_EQ(vector.size(), 0);
+}
+
+TEST(index_range, SingleElementRange)
+{
+ IndexRange range(4, 1);
+ EXPECT_EQ(range.size(), 1);
+ EXPECT_EQ(*range.begin(), 4);
+
+ IntVector vector;
+ for (int value : range) {
+ vector.append(value);
+ }
+
+ EXPECT_EQ(vector.size(), 1);
+ EXPECT_EQ(vector[0], 4);
+}
+
+TEST(index_range, MultipleElementRange)
+{
+ IndexRange range(6, 4);
+ EXPECT_EQ(range.size(), 4);
+
+ IntVector vector;
+ for (int value : range) {
+ vector.append(value);
+ }
+
+ EXPECT_EQ(vector.size(), 4);
+ for (uint i = 0; i < 4; i++) {
+ EXPECT_EQ(vector[i], i + 6);
+ }
+}
+
+TEST(index_range, SubscriptOperator)
+{
+ IndexRange range(5, 5);
+ EXPECT_EQ(range[0], 5);
+ EXPECT_EQ(range[1], 6);
+ EXPECT_EQ(range[2], 7);
+}
+
+TEST(index_range, Before)
+{
+ IndexRange range = IndexRange(5, 5).before(3);
+ EXPECT_EQ(range[0], 2);
+ EXPECT_EQ(range[1], 3);
+ EXPECT_EQ(range[2], 4);
+ EXPECT_EQ(range.size(), 3);
+}
+
+TEST(index_range, After)
+{
+ IndexRange range = IndexRange(5, 5).after(4);
+ EXPECT_EQ(range[0], 10);
+ EXPECT_EQ(range[1], 11);
+ EXPECT_EQ(range[2], 12);
+ EXPECT_EQ(range[3], 13);
+ EXPECT_EQ(range.size(), 4);
+}
+
+TEST(index_range, Contains)
+{
+ IndexRange range = IndexRange(5, 3);
+ EXPECT_TRUE(range.contains(5));
+ EXPECT_TRUE(range.contains(6));
+ EXPECT_TRUE(range.contains(7));
+ EXPECT_FALSE(range.contains(4));
+ EXPECT_FALSE(range.contains(8));
+}
+
+TEST(index_range, First)
+{
+ IndexRange range = IndexRange(5, 3);
+ EXPECT_EQ(range.first(), 5);
+}
+
+TEST(index_range, Last)
+{
+ IndexRange range = IndexRange(5, 3);
+ EXPECT_EQ(range.last(), 7);
+}
+
+TEST(index_range, OneAfterEnd)
+{
+ IndexRange range = IndexRange(5, 3);
+ EXPECT_EQ(range.one_after_last(), 8);
+}
+
+TEST(index_range, Start)
+{
+ IndexRange range = IndexRange(6, 2);
+ EXPECT_EQ(range.start(), 6);
+}
+
+TEST(index_range, Slice)
+{
+ IndexRange range = IndexRange(5, 15);
+ IndexRange slice = range.slice(2, 6);
+ EXPECT_EQ(slice.size(), 6);
+ EXPECT_EQ(slice.first(), 7);
+ EXPECT_EQ(slice.last(), 12);
+}
+
+TEST(index_range, AsArrayRef)
+{
+ IndexRange range = IndexRange(4, 6);
+ ArrayRef<uint> ref = range.as_array_ref();
+ EXPECT_EQ(ref.size(), 6);
+ EXPECT_EQ(ref[0], 4);
+ EXPECT_EQ(ref[1], 5);
+ EXPECT_EQ(ref[2], 6);
+ EXPECT_EQ(ref[3], 7);
+}
diff --git a/tests/gtests/blenlib/BLI_map_test.cc b/tests/gtests/blenlib/BLI_map_test.cc
new file mode 100644
index 00000000000..61e7a603d13
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_map_test.cc
@@ -0,0 +1,288 @@
+#include "testing/testing.h"
+#include "BLI_map.h"
+#include "BLI_set.h"
+
+using BLI::Map;
+using IntFloatMap = Map<int, float>;
+
+TEST(map, DefaultConstructor)
+{
+ IntFloatMap map;
+ EXPECT_EQ(map.size(), 0);
+}
+
+TEST(map, AddIncreasesSize)
+{
+ IntFloatMap map;
+ EXPECT_EQ(map.size(), 0);
+ map.add(2, 5.0f);
+ EXPECT_EQ(map.size(), 1);
+ map.add(6, 2.0f);
+ EXPECT_EQ(map.size(), 2);
+}
+
+TEST(map, Contains)
+{
+ IntFloatMap map;
+ EXPECT_FALSE(map.contains(4));
+ map.add(5, 6.0f);
+ EXPECT_FALSE(map.contains(4));
+ map.add(4, 2.0f);
+ EXPECT_TRUE(map.contains(4));
+}
+
+TEST(map, LookupExisting)
+{
+ IntFloatMap map;
+ map.add(2, 6.0f);
+ map.add(4, 1.0f);
+ EXPECT_EQ(map.lookup(2), 6.0f);
+ EXPECT_EQ(map.lookup(4), 1.0f);
+}
+
+TEST(map, LookupNotExisting)
+{
+ IntFloatMap map;
+ map.add(2, 4.0f);
+ map.add(1, 1.0f);
+ EXPECT_EQ(map.lookup_ptr(0), nullptr);
+ EXPECT_EQ(map.lookup_ptr(5), nullptr);
+}
+
+TEST(map, AddMany)
+{
+ IntFloatMap map;
+ for (int i = 0; i < 100; i++) {
+ map.add(i, i);
+ }
+}
+
+TEST(map, PopItem)
+{
+ IntFloatMap map;
+ map.add(2, 3.0f);
+ map.add(1, 9.0f);
+ EXPECT_TRUE(map.contains(2));
+ EXPECT_TRUE(map.contains(1));
+
+ EXPECT_EQ(map.pop(1), 9.0f);
+ EXPECT_TRUE(map.contains(2));
+ EXPECT_FALSE(map.contains(1));
+
+ EXPECT_EQ(map.pop(2), 3.0f);
+ EXPECT_FALSE(map.contains(2));
+ EXPECT_FALSE(map.contains(1));
+}
+
+TEST(map, PopItemMany)
+{
+ IntFloatMap map;
+ for (uint i = 0; i < 100; i++) {
+ map.add_new(i, i);
+ }
+ for (uint i = 25; i < 80; i++) {
+ EXPECT_EQ(map.pop(i), i);
+ }
+ for (uint i = 0; i < 100; i++) {
+ EXPECT_EQ(map.contains(i), i < 25 || i >= 80);
+ }
+}
+
+TEST(map, ValueIterator)
+{
+ IntFloatMap map;
+ map.add(3, 5.0f);
+ map.add(1, 2.0f);
+ map.add(7, -2.0f);
+
+ BLI::Set<float> values;
+
+ uint iterations = 0;
+ for (float value : map.values()) {
+ values.add(value);
+ iterations++;
+ }
+
+ EXPECT_EQ(iterations, 3);
+ EXPECT_TRUE(values.contains(5.0f));
+ EXPECT_TRUE(values.contains(-2.0f));
+ EXPECT_TRUE(values.contains(2.0f));
+}
+
+TEST(map, KeyIterator)
+{
+ IntFloatMap map;
+ map.add(6, 3.0f);
+ map.add(2, 4.0f);
+ map.add(1, 3.0f);
+
+ BLI::Set<int> keys;
+
+ uint iterations = 0;
+ for (int key : map.keys()) {
+ keys.add(key);
+ iterations++;
+ }
+
+ EXPECT_EQ(iterations, 3);
+ EXPECT_TRUE(keys.contains(1));
+ EXPECT_TRUE(keys.contains(2));
+ EXPECT_TRUE(keys.contains(6));
+}
+
+TEST(map, ItemIterator)
+{
+ IntFloatMap map;
+ map.add(5, 3.0f);
+ map.add(2, 9.0f);
+ map.add(1, 0.0f);
+
+ BLI::Set<int> keys;
+ BLI::Set<float> values;
+
+ uint iterations = 0;
+ for (auto item : map.items()) {
+ keys.add(item.key);
+ values.add(item.value);
+ iterations++;
+ }
+
+ EXPECT_EQ(iterations, 3);
+ EXPECT_TRUE(keys.contains(5));
+ EXPECT_TRUE(keys.contains(2));
+ EXPECT_TRUE(keys.contains(1));
+ EXPECT_TRUE(values.contains(3.0f));
+ EXPECT_TRUE(values.contains(9.0f));
+ EXPECT_TRUE(values.contains(0.0f));
+}
+
+float return_42()
+{
+ return 42.0f;
+}
+
+TEST(map, LookupOrAdd_SeparateFunction)
+{
+ IntFloatMap map;
+ EXPECT_EQ(map.lookup_or_add(0, return_42), 42.0f);
+ EXPECT_EQ(map.lookup(0), 42);
+}
+
+TEST(map, LookupOrAdd_Lambdas)
+{
+ IntFloatMap map;
+ auto lambda1 = []() { return 11.0f; };
+ EXPECT_EQ(map.lookup_or_add(0, lambda1), 11.0f);
+ auto lambda2 = []() { return 20.0f; };
+ EXPECT_EQ(map.lookup_or_add(1, lambda2), 20.0f);
+
+ EXPECT_EQ(map.lookup_or_add(0, lambda2), 11.0f);
+ EXPECT_EQ(map.lookup_or_add(1, lambda1), 20.0f);
+}
+
+TEST(map, AddOrModify)
+{
+ IntFloatMap map;
+ auto create_func = [](float *value) {
+ *value = 10.0f;
+ return true;
+ };
+ auto modify_func = [](float *value) {
+ *value += 5;
+ return false;
+ };
+ EXPECT_TRUE(map.add_or_modify(1, create_func, modify_func));
+ EXPECT_EQ(map.lookup(1), 10.0f);
+ EXPECT_FALSE(map.add_or_modify(1, create_func, modify_func));
+ EXPECT_EQ(map.lookup(1), 15.0f);
+}
+
+TEST(map, AddOverride)
+{
+ IntFloatMap map;
+ EXPECT_FALSE(map.contains(3));
+ EXPECT_TRUE(map.add_override(3, 6.0f));
+ EXPECT_EQ(map.lookup(3), 6.0f);
+ EXPECT_FALSE(map.add_override(3, 7.0f));
+ EXPECT_EQ(map.lookup(3), 7.0f);
+ EXPECT_FALSE(map.add(3, 8.0f));
+ EXPECT_EQ(map.lookup(3), 7.0f);
+}
+
+TEST(map, MoveConstructorSmall)
+{
+ IntFloatMap map1;
+ map1.add(1, 2.0f);
+ map1.add(4, 1.0f);
+ IntFloatMap map2(std::move(map1));
+ EXPECT_EQ(map2.size(), 2);
+ EXPECT_EQ(map2.lookup(1), 2.0f);
+ EXPECT_EQ(map2.lookup(4), 1.0f);
+ EXPECT_EQ(map1.size(), 0);
+ EXPECT_EQ(map1.lookup_ptr(4), nullptr);
+}
+
+TEST(map, MoveConstructorLarge)
+{
+ IntFloatMap map1;
+ for (uint i = 0; i < 100; i++) {
+ map1.add_new(i, i);
+ }
+ IntFloatMap map2(std::move(map1));
+ EXPECT_EQ(map2.size(), 100);
+ EXPECT_EQ(map2.lookup(1), 1.0f);
+ EXPECT_EQ(map2.lookup(4), 4.0f);
+ EXPECT_EQ(map1.size(), 0);
+ EXPECT_EQ(map1.lookup_ptr(4), nullptr);
+}
+
+TEST(map, MoveAssignment)
+{
+ IntFloatMap map1;
+ map1.add(1, 2.0f);
+ map1.add(4, 1.0f);
+ IntFloatMap map2 = std::move(map1);
+ EXPECT_EQ(map2.size(), 2);
+ EXPECT_EQ(map2.lookup(1), 2.0f);
+ EXPECT_EQ(map2.lookup(4), 1.0f);
+ EXPECT_EQ(map1.size(), 0);
+ EXPECT_EQ(map1.lookup_ptr(4), nullptr);
+}
+
+TEST(map, Clear)
+{
+ IntFloatMap map;
+ map.add(1, 1.0f);
+ map.add(2, 5.0f);
+
+ EXPECT_EQ(map.size(), 2);
+ EXPECT_TRUE(map.contains(1));
+ EXPECT_TRUE(map.contains(2));
+
+ map.clear();
+
+ EXPECT_EQ(map.size(), 0);
+ EXPECT_FALSE(map.contains(1));
+ EXPECT_FALSE(map.contains(2));
+}
+
+TEST(map, UniquePtrValue)
+{
+ auto value1 = std::unique_ptr<int>(new int());
+ auto value2 = std::unique_ptr<int>(new int());
+ auto value3 = std::unique_ptr<int>(new int());
+
+ int *value1_ptr = value1.get();
+
+ Map<int, std::unique_ptr<int>> map;
+ map.add_new(1, std::move(value1));
+ map.add(2, std::move(value2));
+ map.add_override(3, std::move(value3));
+ map.lookup_or_add(4, []() { return std::unique_ptr<int>(new int()); });
+ map.add_new(5, std::unique_ptr<int>(new int()));
+ map.add(6, std::unique_ptr<int>(new int()));
+ map.add_override(7, std::unique_ptr<int>(new int()));
+
+ EXPECT_EQ(map.lookup(1).get(), value1_ptr);
+ EXPECT_EQ(map.lookup_ptr(100), nullptr);
+}
diff --git a/tests/gtests/blenlib/BLI_math_base_test.cc b/tests/gtests/blenlib/BLI_math_base_test.cc
index d62d0ba274d..dc20c75576d 100644
--- a/tests/gtests/blenlib/BLI_math_base_test.cc
+++ b/tests/gtests/blenlib/BLI_math_base_test.cc
@@ -83,3 +83,33 @@ TEST(math_base, CompareFFRelativeZero)
EXPECT_FALSE(compare_ff_relative(fn0, f1, -1.0f, 1024));
EXPECT_FALSE(compare_ff_relative(f1, fn0, -1.0f, 1024));
}
+
+TEST(math_base, Log2FloorU)
+{
+ EXPECT_EQ(log2_floor_u(0), 0);
+ EXPECT_EQ(log2_floor_u(1), 0);
+ EXPECT_EQ(log2_floor_u(2), 1);
+ EXPECT_EQ(log2_floor_u(3), 1);
+ EXPECT_EQ(log2_floor_u(4), 2);
+ EXPECT_EQ(log2_floor_u(5), 2);
+ EXPECT_EQ(log2_floor_u(6), 2);
+ EXPECT_EQ(log2_floor_u(7), 2);
+ EXPECT_EQ(log2_floor_u(8), 3);
+ EXPECT_EQ(log2_floor_u(9), 3);
+ EXPECT_EQ(log2_floor_u(123456), 16);
+}
+
+TEST(math_base, Log2CeilU)
+{
+ EXPECT_EQ(log2_ceil_u(0), 0);
+ EXPECT_EQ(log2_ceil_u(1), 0);
+ EXPECT_EQ(log2_ceil_u(2), 1);
+ EXPECT_EQ(log2_ceil_u(3), 2);
+ EXPECT_EQ(log2_ceil_u(4), 2);
+ EXPECT_EQ(log2_ceil_u(5), 3);
+ EXPECT_EQ(log2_ceil_u(6), 3);
+ EXPECT_EQ(log2_ceil_u(7), 3);
+ EXPECT_EQ(log2_ceil_u(8), 3);
+ EXPECT_EQ(log2_ceil_u(9), 4);
+ EXPECT_EQ(log2_ceil_u(123456), 17);
+}
diff --git a/tests/gtests/blenlib/BLI_set_test.cc b/tests/gtests/blenlib/BLI_set_test.cc
new file mode 100644
index 00000000000..5baf069557e
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_set_test.cc
@@ -0,0 +1,203 @@
+#include "testing/testing.h"
+#include "BLI_set.h"
+#include "BLI_vector.h"
+
+using BLI::Set;
+using BLI::Vector;
+using IntSet = Set<int>;
+
+TEST(set, Defaultconstructor)
+{
+ IntSet set;
+ EXPECT_EQ(set.size(), 0);
+}
+
+TEST(set, ContainsNotExistant)
+{
+ IntSet set;
+ EXPECT_FALSE(set.contains(3));
+}
+
+TEST(set, ContainsExistant)
+{
+ IntSet set;
+ EXPECT_FALSE(set.contains(5));
+ set.add(5);
+ EXPECT_TRUE(set.contains(5));
+}
+
+TEST(set, AddMany)
+{
+ IntSet set;
+ for (int i = 0; i < 100; i++) {
+ set.add(i);
+ }
+
+ for (int i = 50; i < 100; i++) {
+ EXPECT_TRUE(set.contains(i));
+ }
+ for (int i = 100; i < 150; i++) {
+ EXPECT_FALSE(set.contains(i));
+ }
+}
+
+TEST(set, InitializerListConstructor)
+{
+ IntSet set = {4, 5, 6};
+ EXPECT_EQ(set.size(), 3);
+ EXPECT_TRUE(set.contains(4));
+ EXPECT_TRUE(set.contains(5));
+ EXPECT_TRUE(set.contains(6));
+ EXPECT_FALSE(set.contains(2));
+ EXPECT_FALSE(set.contains(3));
+}
+
+TEST(set, CopyConstructor)
+{
+ IntSet set = {3};
+ EXPECT_TRUE(set.contains(3));
+ EXPECT_FALSE(set.contains(4));
+
+ IntSet set2 = set;
+ set2.add(4);
+ EXPECT_TRUE(set2.contains(3));
+ EXPECT_TRUE(set2.contains(4));
+
+ EXPECT_FALSE(set.contains(4));
+}
+
+TEST(set, MoveConstructor)
+{
+ IntSet set = {1, 2, 3};
+ EXPECT_EQ(set.size(), 3);
+ IntSet set2 = std::move(set);
+ EXPECT_EQ(set.size(), 0);
+ EXPECT_EQ(set2.size(), 3);
+}
+
+TEST(set, Remove)
+{
+ IntSet set = {3, 4, 5};
+ EXPECT_TRUE(set.contains(3));
+ EXPECT_TRUE(set.contains(4));
+ EXPECT_TRUE(set.contains(5));
+ set.remove(4);
+ EXPECT_TRUE(set.contains(3));
+ EXPECT_FALSE(set.contains(4));
+ EXPECT_TRUE(set.contains(5));
+ set.remove(3);
+ EXPECT_FALSE(set.contains(3));
+ EXPECT_FALSE(set.contains(4));
+ EXPECT_TRUE(set.contains(5));
+ set.remove(5);
+ EXPECT_FALSE(set.contains(3));
+ EXPECT_FALSE(set.contains(4));
+ EXPECT_FALSE(set.contains(5));
+}
+
+TEST(set, RemoveMany)
+{
+ IntSet set;
+ for (uint i = 0; i < 1000; i++) {
+ set.add(i);
+ }
+ for (uint i = 100; i < 1000; i++) {
+ set.remove(i);
+ }
+ for (uint i = 900; i < 1000; i++) {
+ set.add(i);
+ }
+
+ for (uint i = 0; i < 1000; i++) {
+ if (i < 100 || i >= 900) {
+ EXPECT_TRUE(set.contains(i));
+ }
+ else {
+ EXPECT_FALSE(set.contains(i));
+ }
+ }
+}
+
+TEST(set, Intersects)
+{
+ IntSet a = {3, 4, 5, 6};
+ IntSet b = {1, 2, 5};
+ EXPECT_TRUE(IntSet::Intersects(a, b));
+ EXPECT_FALSE(IntSet::Disjoint(a, b));
+}
+
+TEST(set, Disjoint)
+{
+ IntSet a = {5, 6, 7, 8};
+ IntSet b = {2, 3, 4, 9};
+ EXPECT_FALSE(IntSet::Intersects(a, b));
+ EXPECT_TRUE(IntSet::Disjoint(a, b));
+}
+
+TEST(set, AddMultiple)
+{
+ IntSet a;
+ a.add_multiple({5, 7});
+ EXPECT_TRUE(a.contains(5));
+ EXPECT_TRUE(a.contains(7));
+ EXPECT_FALSE(a.contains(4));
+ a.add_multiple({2, 4, 7});
+ EXPECT_TRUE(a.contains(4));
+ EXPECT_TRUE(a.contains(2));
+ EXPECT_EQ(a.size(), 4);
+}
+
+TEST(set, AddMultipleNew)
+{
+ IntSet a;
+ a.add_multiple_new({5, 6});
+ EXPECT_TRUE(a.contains(5));
+ EXPECT_TRUE(a.contains(6));
+}
+
+TEST(set, ToSmallVector)
+{
+ IntSet a = {5, 2, 8};
+ BLI::Vector<int> vec = a.to_small_vector();
+ EXPECT_EQ(vec.size(), 3);
+ EXPECT_TRUE(vec.contains(5));
+ EXPECT_TRUE(vec.contains(2));
+ EXPECT_TRUE(vec.contains(8));
+}
+
+TEST(set, Iterator)
+{
+ IntSet set = {1, 3, 2, 5, 4};
+ BLI::Vector<int> vec;
+ for (int value : set) {
+ vec.append(value);
+ }
+ EXPECT_EQ(vec.size(), 5);
+ EXPECT_TRUE(vec.contains(1));
+ EXPECT_TRUE(vec.contains(3));
+ EXPECT_TRUE(vec.contains(2));
+ EXPECT_TRUE(vec.contains(5));
+ EXPECT_TRUE(vec.contains(4));
+}
+
+TEST(set, OftenAddRemove)
+{
+ IntSet set;
+ for (int i = 0; i < 100; i++) {
+ set.add(42);
+ EXPECT_EQ(set.size(), 1);
+ set.remove(42);
+ EXPECT_EQ(set.size(), 0);
+ }
+}
+
+TEST(set, UniquePtrValues)
+{
+ Set<std::unique_ptr<int>> set;
+ set.add_new(std::unique_ptr<int>(new int()));
+ auto value1 = std::unique_ptr<int>(new int());
+ set.add_new(std::move(value1));
+ set.add(std::unique_ptr<int>(new int()));
+
+ EXPECT_EQ(set.size(), 3);
+}
diff --git a/tests/gtests/blenlib/BLI_stack_cxx_test.cc b/tests/gtests/blenlib/BLI_stack_cxx_test.cc
new file mode 100644
index 00000000000..436f1f307b9
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_stack_cxx_test.cc
@@ -0,0 +1,63 @@
+#include "testing/testing.h"
+#include "BLI_stack_cxx.h"
+
+using BLI::Stack;
+using IntStack = Stack<int>;
+
+TEST(stack, DefaultConstructor)
+{
+ IntStack stack;
+ EXPECT_EQ(stack.size(), 0);
+ EXPECT_TRUE(stack.empty());
+}
+
+TEST(stack, ArrayRefConstructor)
+{
+ std::array<int, 3> array = {4, 7, 2};
+ IntStack stack(array);
+ EXPECT_EQ(stack.size(), 3);
+ EXPECT_EQ(stack.pop(), 2);
+ EXPECT_EQ(stack.pop(), 7);
+ EXPECT_EQ(stack.pop(), 4);
+ EXPECT_TRUE(stack.empty());
+}
+
+TEST(stack, Push)
+{
+ IntStack stack;
+ EXPECT_EQ(stack.size(), 0);
+ stack.push(3);
+ EXPECT_EQ(stack.size(), 1);
+ stack.push(5);
+ EXPECT_EQ(stack.size(), 2);
+}
+
+TEST(stack, Pop)
+{
+ IntStack stack;
+ stack.push(4);
+ stack.push(6);
+ EXPECT_EQ(stack.pop(), 6);
+ EXPECT_EQ(stack.pop(), 4);
+}
+
+TEST(stack, Peek)
+{
+ IntStack stack;
+ stack.push(3);
+ stack.push(4);
+ EXPECT_EQ(stack.peek(), 4);
+ EXPECT_EQ(stack.peek(), 4);
+ stack.pop();
+ EXPECT_EQ(stack.peek(), 3);
+}
+
+TEST(stack, UniquePtrValues)
+{
+ Stack<std::unique_ptr<int>> stack;
+ stack.push(std::unique_ptr<int>(new int()));
+ stack.push(std::unique_ptr<int>(new int()));
+ std::unique_ptr<int> a = stack.pop();
+ std::unique_ptr<int> &b = stack.peek();
+ UNUSED_VARS(a, b);
+}
diff --git a/tests/gtests/blenlib/BLI_string_map_test.cc b/tests/gtests/blenlib/BLI_string_map_test.cc
new file mode 100644
index 00000000000..cc02a54e0c8
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_string_map_test.cc
@@ -0,0 +1,210 @@
+#include "testing/testing.h"
+#include "BLI_string_map.h"
+#include "BLI_vector.h"
+
+using namespace BLI;
+
+TEST(string_map, DefaultConstructor)
+{
+ StringMap<int> map;
+ EXPECT_EQ(map.size(), 0);
+}
+
+TEST(string_map, CopyConstructor)
+{
+ StringMap<Vector<int, 4>> map1;
+ map1.add_new("A", {1, 2, 3});
+ map1.add_new("B", {1, 2, 3, 4, 5, 6});
+
+ StringMap<Vector<int>> map2(map1);
+
+ EXPECT_EQ(map1.size(), 2);
+ EXPECT_EQ(map2.size(), 2);
+ EXPECT_EQ(map1.lookup("A")[1], 2);
+ EXPECT_EQ(map2.lookup("A")[1], 2);
+ EXPECT_EQ(map1.lookup("B")[5], 6);
+ EXPECT_EQ(map2.lookup("B")[5], 6);
+}
+
+TEST(string_map, MoveConstructor)
+{
+ StringMap<Vector<int, 4>> map1;
+ map1.add_new("A", {1, 2, 3});
+ map1.add_new("B", {1, 2, 3, 4, 5, 6});
+
+ StringMap<Vector<int>> map2(std::move(map1));
+
+ EXPECT_EQ(map1.size(), 0);
+ EXPECT_FALSE(map1.contains("A"));
+ EXPECT_FALSE(map1.contains("B"));
+
+ EXPECT_EQ(map2.size(), 2);
+ EXPECT_EQ(map2.lookup("A")[1], 2);
+ EXPECT_EQ(map2.lookup("B")[5], 6);
+}
+
+TEST(string_map, AddNew)
+{
+ StringMap<int> map;
+ EXPECT_EQ(map.size(), 0);
+
+ map.add_new("Why", 5);
+ EXPECT_EQ(map.size(), 1);
+ EXPECT_EQ(map.lookup("Why"), 5);
+
+ map.add_new("Where", 6);
+ EXPECT_EQ(map.size(), 2);
+ EXPECT_EQ(map.lookup("Where"), 6);
+}
+
+TEST(string_map, AddNew_Many)
+{
+ StringMap<int> map;
+
+ for (uint i = 0; i < 100; i++) {
+ map.add_new(std::to_string(i), i);
+ }
+ EXPECT_EQ(map.size(), 100);
+}
+
+TEST(string_map, Contains)
+{
+ StringMap<int> map;
+ map.add_new("A", 0);
+ map.add_new("B", 0);
+ EXPECT_TRUE(map.contains("A"));
+ EXPECT_TRUE(map.contains("B"));
+ EXPECT_FALSE(map.contains("C"));
+}
+
+TEST(string_map, Contains_Many)
+{
+ StringMap<int> map;
+ for (uint i = 0; i < 50; i++) {
+ map.add_new(std::to_string(i), i);
+ }
+ for (uint i = 100; i < 200; i++) {
+ map.add_new(std::to_string(i), i);
+ }
+ EXPECT_EQ(map.size(), 150);
+ for (uint i = 0; i < 200; i++) {
+ if (i < 50 || i >= 100) {
+ EXPECT_TRUE(map.contains(std::to_string(i)));
+ }
+ else {
+ EXPECT_FALSE(map.contains(std::to_string(i)));
+ }
+ }
+}
+
+TEST(string_map, Lookup)
+{
+ StringMap<int> map;
+ map.add_new("A", 5);
+ map.add_new("B", 8);
+ map.add_new("C", 10);
+ EXPECT_EQ(map.lookup("A"), 5);
+ EXPECT_EQ(map.lookup("B"), 8);
+ EXPECT_EQ(map.lookup("C"), 10);
+}
+
+TEST(string_map, LookupPtr)
+{
+ StringMap<int> map;
+ map.add_new("test1", 13);
+ map.add_new("test2", 14);
+ map.add_new("test3", 15);
+ EXPECT_EQ(*map.lookup_ptr("test1"), 13);
+ EXPECT_EQ(*map.lookup_ptr("test2"), 14);
+ EXPECT_EQ(*map.lookup_ptr("test3"), 15);
+ EXPECT_EQ(map.lookup_ptr("test4"), nullptr);
+}
+
+TEST(string_map, LookupDefault)
+{
+ StringMap<int> map;
+ EXPECT_EQ(map.lookup_default("test", 42), 42);
+ map.add_new("test", 5);
+ EXPECT_EQ(map.lookup_default("test", 42), 5);
+}
+
+TEST(string_map, FindKeyForValue)
+{
+ StringMap<int> map;
+ map.add_new("A", 1);
+ map.add_new("B", 2);
+ map.add_new("C", 3);
+ EXPECT_EQ(map.find_key_for_value(1), "A");
+ EXPECT_EQ(map.find_key_for_value(2), "B");
+ EXPECT_EQ(map.find_key_for_value(3), "C");
+}
+
+TEST(string_map, ForeachValue)
+{
+ StringMap<int> map;
+ map.add_new("A", 4);
+ map.add_new("B", 5);
+ map.add_new("C", 1);
+
+ Vector<int> values;
+ map.foreach_value([&values](int &value) { values.append(value); });
+ EXPECT_EQ(values.size(), 3);
+ EXPECT_TRUE(values.contains(1));
+ EXPECT_TRUE(values.contains(4));
+ EXPECT_TRUE(values.contains(5));
+}
+
+TEST(string_map, ForeachKey)
+{
+ StringMap<int> map;
+ map.add_new("A", 4);
+ map.add_new("B", 5);
+ map.add_new("C", 1);
+
+ Vector<std::string> keys;
+ map.foreach_key([&keys](StringRefNull key) { keys.append(key); });
+ EXPECT_EQ(keys.size(), 3);
+ EXPECT_TRUE(keys.contains("A"));
+ EXPECT_TRUE(keys.contains("B"));
+ EXPECT_TRUE(keys.contains("C"));
+}
+
+TEST(string_map, ForeachKeyValuePair)
+{
+ StringMap<int> map;
+ map.add_new("A", 4);
+ map.add_new("B", 5);
+ map.add_new("C", 1);
+
+ Vector<std::string> keys;
+ Vector<int> values;
+
+ map.foreach_key_value_pair([&keys, &values](StringRefNull key, int value) {
+ keys.append(key);
+ values.append(value);
+ });
+
+ EXPECT_EQ(keys.size(), 3);
+ EXPECT_EQ(values[keys.index("A")], 4);
+ EXPECT_EQ(values[keys.index("B")], 5);
+ EXPECT_EQ(values[keys.index("C")], 1);
+}
+
+TEST(string_map, WithVectors)
+{
+ StringMap<Vector<int>> map;
+ map.add_new("A", {1, 2, 3});
+ map.add_new("B", {1, 2, 3, 4, 5, 6, 7});
+ EXPECT_EQ(map.size(), 2);
+ EXPECT_EQ(map.lookup("A").size(), 3);
+ EXPECT_EQ(map.lookup("B").size(), 7);
+}
+
+TEST(string_map, UniquePtrValues)
+{
+ StringMap<std::unique_ptr<int>> map;
+ map.add_new("A", std::unique_ptr<int>(new int()));
+ std::unique_ptr<int> &a = map.lookup("A");
+ std::unique_ptr<int> *b = map.lookup_ptr("A");
+ EXPECT_EQ(a.get(), b->get());
+}
diff --git a/tests/gtests/blenlib/BLI_string_ref_test.cc b/tests/gtests/blenlib/BLI_string_ref_test.cc
new file mode 100644
index 00000000000..5605e10ac86
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_string_ref_test.cc
@@ -0,0 +1,230 @@
+#include "testing/testing.h"
+#include "BLI_string_ref.h"
+#include "BLI_vector.h"
+
+using BLI::StringRef;
+using BLI::StringRefNull;
+using BLI::Vector;
+
+TEST(string_ref_null, DefaultConstructor)
+{
+ StringRefNull ref;
+ EXPECT_EQ(ref.size(), 0);
+ EXPECT_EQ(ref[0], '\0');
+}
+
+TEST(string_ref_null, CStringConstructor)
+{
+ const char *str = "Hello";
+ StringRefNull ref(str);
+ EXPECT_EQ(ref.size(), 5);
+ EXPECT_EQ(ref.data(), str);
+}
+
+TEST(string_ref_null, CStringLengthConstructor)
+{
+ const char *str = "Hello";
+ StringRefNull ref(str, 5);
+ EXPECT_EQ(ref.size(), 5);
+ EXPECT_EQ(ref.data(), str);
+}
+
+TEST(string_ref, DefaultConstructor)
+{
+ StringRef ref;
+ EXPECT_EQ(ref.size(), 0);
+}
+
+TEST(string_ref, CStringConstructor)
+{
+ const char *str = "Test";
+ StringRef ref(str);
+ EXPECT_EQ(ref.size(), 4);
+ EXPECT_EQ(ref.data(), str);
+}
+
+TEST(string_ref, PointerWithLengthConstructor)
+{
+ const char *str = "Test";
+ StringRef ref(str, 2);
+ EXPECT_EQ(ref.size(), 2);
+ EXPECT_EQ(ref.data(), str);
+}
+
+TEST(string_ref, StdStringConstructor)
+{
+ std::string str = "Test";
+ StringRef ref(str);
+ EXPECT_EQ(ref.size(), 4);
+ EXPECT_EQ(ref.data(), str.data());
+}
+
+TEST(string_ref, SubscriptOperator)
+{
+ StringRef ref("hello");
+ EXPECT_EQ(ref.size(), 5);
+ EXPECT_EQ(ref[0], 'h');
+ EXPECT_EQ(ref[1], 'e');
+ EXPECT_EQ(ref[2], 'l');
+ EXPECT_EQ(ref[3], 'l');
+ EXPECT_EQ(ref[4], 'o');
+}
+
+TEST(string_ref, ToStdString)
+{
+ StringRef ref("test");
+ std::string str = ref;
+ EXPECT_EQ(str.size(), 4);
+ EXPECT_EQ(str, "test");
+}
+
+TEST(string_ref, Print)
+{
+ StringRef ref("test");
+ std::stringstream ss;
+ ss << ref;
+ ss << ref;
+ std::string str = ss.str();
+ EXPECT_EQ(str.size(), 8);
+ EXPECT_EQ(str, "testtest");
+}
+
+TEST(string_ref, Add)
+{
+ StringRef a("qwe");
+ StringRef b("asd");
+ std::string result = a + b;
+ EXPECT_EQ(result, "qweasd");
+}
+
+TEST(string_ref, AddCharPtr1)
+{
+ StringRef ref("test");
+ std::string result = ref + "qwe";
+ EXPECT_EQ(result, "testqwe");
+}
+
+TEST(string_ref, AddCharPtr2)
+{
+ StringRef ref("test");
+ std::string result = "qwe" + ref;
+ EXPECT_EQ(result, "qwetest");
+}
+
+TEST(string_ref, AddString1)
+{
+ StringRef ref("test");
+ std::string result = ref + std::string("asd");
+ EXPECT_EQ(result, "testasd");
+}
+
+TEST(string_ref, AddString2)
+{
+ StringRef ref("test");
+ std::string result = std::string("asd") + ref;
+ EXPECT_EQ(result, "asdtest");
+}
+
+TEST(string_ref, CompareEqual)
+{
+ StringRef ref1("test");
+ StringRef ref2("test");
+ StringRef ref3("other");
+ EXPECT_TRUE(ref1 == ref2);
+ EXPECT_FALSE(ref1 == ref3);
+ EXPECT_TRUE(ref1 != ref3);
+ EXPECT_FALSE(ref1 != ref2);
+}
+
+TEST(string_ref, CompareEqualCharPtr1)
+{
+ StringRef ref("test");
+ EXPECT_TRUE(ref == "test");
+ EXPECT_FALSE(ref == "other");
+ EXPECT_TRUE(ref != "other");
+ EXPECT_FALSE(ref != "test");
+}
+
+TEST(string_ref, CompareEqualCharPtr2)
+{
+ StringRef ref("test");
+ EXPECT_TRUE("test" == ref);
+ EXPECT_FALSE("other" == ref);
+ EXPECT_TRUE(ref != "other");
+ EXPECT_FALSE(ref != "test");
+}
+
+TEST(string_ref, CompareEqualString1)
+{
+ StringRef ref("test");
+ EXPECT_TRUE(ref == std::string("test"));
+ EXPECT_FALSE(ref == std::string("other"));
+ EXPECT_TRUE(ref != std::string("other"));
+ EXPECT_FALSE(ref != std::string("test"));
+}
+
+TEST(string_ref, CompareEqualString2)
+{
+ StringRef ref("test");
+ EXPECT_TRUE(std::string("test") == ref);
+ EXPECT_FALSE(std::string("other") == ref);
+ EXPECT_TRUE(std::string("other") != ref);
+ EXPECT_FALSE(std::string("test") != ref);
+}
+
+TEST(string_ref, Iterate)
+{
+ StringRef ref("test");
+ Vector<char> chars;
+ for (char c : ref) {
+ chars.append(c);
+ }
+ EXPECT_EQ(chars.size(), 4);
+ EXPECT_EQ(chars[0], 't');
+ EXPECT_EQ(chars[1], 'e');
+ EXPECT_EQ(chars[2], 's');
+ EXPECT_EQ(chars[3], 't');
+}
+
+TEST(string_ref, StartsWith)
+{
+ StringRef ref("test");
+ EXPECT_TRUE(ref.startswith(""));
+ EXPECT_TRUE(ref.startswith("t"));
+ EXPECT_TRUE(ref.startswith("te"));
+ EXPECT_TRUE(ref.startswith("tes"));
+ EXPECT_TRUE(ref.startswith("test"));
+ EXPECT_FALSE(ref.startswith("test "));
+ EXPECT_FALSE(ref.startswith("a"));
+}
+
+TEST(string_ref, EndsWith)
+{
+ StringRef ref("test");
+ EXPECT_TRUE(ref.endswith(""));
+ EXPECT_TRUE(ref.endswith("t"));
+ EXPECT_TRUE(ref.endswith("st"));
+ EXPECT_TRUE(ref.endswith("est"));
+ EXPECT_TRUE(ref.endswith("test"));
+ EXPECT_FALSE(ref.endswith(" test"));
+ EXPECT_FALSE(ref.endswith("a"));
+}
+
+TEST(string_ref, DropPrefixN)
+{
+ StringRef ref("test");
+ StringRef ref2 = ref.drop_prefix(2);
+ StringRef ref3 = ref2.drop_prefix(2);
+ EXPECT_EQ(ref2.size(), 2);
+ EXPECT_EQ(ref3.size(), 0);
+ EXPECT_EQ(ref2, "st");
+ EXPECT_EQ(ref3, "");
+}
+
+TEST(string_ref, DropPrefix)
+{
+ StringRef ref("test");
+ StringRef ref2 = ref.drop_prefix("tes");
+ EXPECT_EQ(ref2.size(), 1);
+ EXPECT_EQ(ref2, "t");
+}
diff --git a/tests/gtests/blenlib/BLI_vector_set_test.cc b/tests/gtests/blenlib/BLI_vector_set_test.cc
new file mode 100644
index 00000000000..675e5a154d5
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_vector_set_test.cc
@@ -0,0 +1,113 @@
+#include "testing/testing.h"
+#include "BLI_vector_set.h"
+
+using BLI::VectorSet;
+using IntVectorSet = VectorSet<int>;
+
+TEST(vector_set, DefaultConstructor)
+{
+ IntVectorSet set;
+ EXPECT_EQ(set.size(), 0);
+}
+
+TEST(vector_set, InitializerListConstructor_WithoutDuplicates)
+{
+ IntVectorSet set = {1, 4, 5};
+ EXPECT_EQ(set.size(), 3);
+ EXPECT_EQ(set[0], 1);
+ EXPECT_EQ(set[1], 4);
+ EXPECT_EQ(set[2], 5);
+}
+
+TEST(vector_set, InitializerListConstructor_WithDuplicates)
+{
+ IntVectorSet set = {1, 3, 3, 2, 1, 5};
+ EXPECT_EQ(set.size(), 4);
+ EXPECT_EQ(set[0], 1);
+ EXPECT_EQ(set[1], 3);
+ EXPECT_EQ(set[2], 2);
+ EXPECT_EQ(set[3], 5);
+}
+
+TEST(vector_set, Copy)
+{
+ IntVectorSet set1 = {1, 2, 3};
+ IntVectorSet set2 = set1;
+ EXPECT_EQ(set1.size(), 3);
+ EXPECT_EQ(set2.size(), 3);
+ EXPECT_EQ(set1.index(2), 1);
+ EXPECT_EQ(set2.index(2), 1);
+}
+
+TEST(vector_set, Move)
+{
+ IntVectorSet set1 = {1, 2, 3};
+ IntVectorSet set2 = std::move(set1);
+ EXPECT_EQ(set1.size(), 0);
+ EXPECT_EQ(set2.size(), 3);
+}
+
+TEST(vector_set, AddNewIncreasesSize)
+{
+ IntVectorSet set;
+ EXPECT_EQ(set.size(), 0);
+ set.add(5);
+ EXPECT_EQ(set.size(), 1);
+}
+
+TEST(vector_set, AddExistingDoesNotIncreaseSize)
+{
+ IntVectorSet set;
+ EXPECT_EQ(set.size(), 0);
+ set.add(5);
+ EXPECT_EQ(set.size(), 1);
+ set.add(5);
+ EXPECT_EQ(set.size(), 1);
+}
+
+TEST(vector_set, Index)
+{
+ IntVectorSet set = {3, 6, 4};
+ EXPECT_EQ(set.index(6), 1);
+ EXPECT_EQ(set.index(3), 0);
+ EXPECT_EQ(set.index(4), 2);
+}
+
+TEST(vector_set, IndexTry)
+{
+ IntVectorSet set = {3, 6, 4};
+ EXPECT_EQ(set.index_try(5), -1);
+ EXPECT_EQ(set.index_try(3), 0);
+ EXPECT_EQ(set.index_try(6), 1);
+ EXPECT_EQ(set.index_try(2), -1);
+}
+
+TEST(vector_set, Remove)
+{
+ IntVectorSet set = {4, 5, 6, 7};
+ EXPECT_EQ(set.size(), 4);
+ set.remove(5);
+ EXPECT_EQ(set.size(), 3);
+ EXPECT_EQ(set[0], 4);
+ EXPECT_EQ(set[1], 7);
+ EXPECT_EQ(set[2], 6);
+ set.remove(6);
+ EXPECT_EQ(set.size(), 2);
+ EXPECT_EQ(set[0], 4);
+ EXPECT_EQ(set[1], 7);
+ set.remove(4);
+ EXPECT_EQ(set.size(), 1);
+ EXPECT_EQ(set[0], 7);
+ set.remove(7);
+ EXPECT_EQ(set.size(), 0);
+}
+
+TEST(vector_set, UniquePtrValue)
+{
+ VectorSet<std::unique_ptr<int>> set;
+ set.add_new(std::unique_ptr<int>(new int()));
+ set.add(std::unique_ptr<int>(new int()));
+ set.index_try(std::unique_ptr<int>(new int()));
+ std::unique_ptr<int> value = set.pop();
+ UNUSED_VARS(value);
+}
diff --git a/tests/gtests/blenlib/BLI_vector_test.cc b/tests/gtests/blenlib/BLI_vector_test.cc
new file mode 100644
index 00000000000..9486c9c0ef2
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_vector_test.cc
@@ -0,0 +1,414 @@
+#include "testing/testing.h"
+#include "BLI_vector.h"
+#include <forward_list>
+
+using BLI::Vector;
+using IntVector = Vector<int>;
+
+TEST(vector, DefaultConstructor)
+{
+ IntVector vec;
+ EXPECT_EQ(vec.size(), 0);
+}
+
+TEST(vector, SizeConstructor)
+{
+ IntVector vec(3);
+ EXPECT_EQ(vec.size(), 3);
+ EXPECT_EQ(vec[0], 0);
+ EXPECT_EQ(vec[1], 0);
+ EXPECT_EQ(vec[2], 0);
+}
+
+TEST(vector, SizeValueConstructor)
+{
+ IntVector vec(4, 10);
+ EXPECT_EQ(vec.size(), 4);
+ EXPECT_EQ(vec[0], 10);
+ EXPECT_EQ(vec[1], 10);
+ EXPECT_EQ(vec[2], 10);
+ EXPECT_EQ(vec[3], 10);
+}
+
+TEST(vector, InitializerListConstructor)
+{
+ IntVector vec = {1, 3, 4, 6};
+ EXPECT_EQ(vec.size(), 4);
+ EXPECT_EQ(vec[0], 1);
+ EXPECT_EQ(vec[1], 3);
+ EXPECT_EQ(vec[2], 4);
+ EXPECT_EQ(vec[3], 6);
+}
+
+struct TestListValue {
+ TestListValue *next, *prev;
+ int value;
+};
+
+TEST(vector, IntrusiveListBaseConstructor)
+{
+ TestListValue *value1 = new TestListValue{0, 0, 4};
+ TestListValue *value2 = new TestListValue{0, 0, 5};
+ TestListValue *value3 = new TestListValue{0, 0, 6};
+
+ ListBase list = {NULL, NULL};
+ BLI_addtail(&list, value1);
+ BLI_addtail(&list, value2);
+ BLI_addtail(&list, value3);
+ Vector<TestListValue *> vec(list, true);
+
+ EXPECT_EQ(vec.size(), 3);
+ EXPECT_EQ(vec[0]->value, 4);
+ EXPECT_EQ(vec[1]->value, 5);
+ EXPECT_EQ(vec[2]->value, 6);
+
+ delete value1;
+ delete value2;
+ delete value3;
+}
+
+TEST(vector, ContainerConstructor)
+{
+ std::forward_list<int> list;
+ list.push_front(3);
+ list.push_front(1);
+ list.push_front(5);
+
+ IntVector vec = IntVector::FromContainer(list);
+ EXPECT_EQ(vec.size(), 3);
+ EXPECT_EQ(vec[0], 5);
+ EXPECT_EQ(vec[1], 1);
+ EXPECT_EQ(vec[2], 3);
+}
+
+TEST(vector, CopyConstructor)
+{
+ IntVector vec1 = {1, 2, 3};
+ IntVector vec2(vec1);
+ EXPECT_EQ(vec2.size(), 3);
+ EXPECT_EQ(vec2[0], 1);
+ EXPECT_EQ(vec2[1], 2);
+ EXPECT_EQ(vec2[2], 3);
+
+ vec1[1] = 5;
+ EXPECT_EQ(vec1[1], 5);
+ EXPECT_EQ(vec2[1], 2);
+}
+
+TEST(vector, CopyConstructor2)
+{
+ Vector<int, 2> vec1 = {1, 2, 3, 4};
+ Vector<int, 3> vec2(vec1);
+
+ EXPECT_EQ(vec1.size(), 4);
+ EXPECT_EQ(vec2.size(), 4);
+ EXPECT_NE(vec1.begin(), vec2.begin());
+ EXPECT_EQ(vec2[0], 1);
+ EXPECT_EQ(vec2[1], 2);
+ EXPECT_EQ(vec2[2], 3);
+ EXPECT_EQ(vec2[3], 4);
+}
+
+TEST(vector, CopyConstructor3)
+{
+ Vector<int, 20> vec1 = {1, 2, 3, 4};
+ Vector<int, 1> vec2(vec1);
+
+ EXPECT_EQ(vec1.size(), 4);
+ EXPECT_EQ(vec2.size(), 4);
+ EXPECT_NE(vec1.begin(), vec2.begin());
+ EXPECT_EQ(vec2[2], 3);
+}
+
+TEST(vector, CopyConstructor4)
+{
+ Vector<int, 5> vec1 = {1, 2, 3, 4};
+ Vector<int, 6> vec2(vec1);
+
+ EXPECT_EQ(vec1.size(), 4);
+ EXPECT_EQ(vec2.size(), 4);
+ EXPECT_NE(vec1.begin(), vec2.begin());
+ EXPECT_EQ(vec2[3], 4);
+}
+
+TEST(vector, MoveConstructor)
+{
+ IntVector vec1 = {1, 2, 3, 4};
+ IntVector vec2(std::move(vec1));
+
+ EXPECT_EQ(vec1.size(), 0);
+ EXPECT_EQ(vec2.size(), 4);
+ EXPECT_EQ(vec2[0], 1);
+ EXPECT_EQ(vec2[1], 2);
+ EXPECT_EQ(vec2[2], 3);
+ EXPECT_EQ(vec2[3], 4);
+}
+
+TEST(vector, MoveConstructor2)
+{
+ Vector<int, 2> vec1 = {1, 2, 3, 4};
+ Vector<int, 3> vec2(std::move(vec1));
+
+ EXPECT_EQ(vec1.size(), 0);
+ EXPECT_EQ(vec2.size(), 4);
+ EXPECT_EQ(vec2[0], 1);
+ EXPECT_EQ(vec2[1], 2);
+ EXPECT_EQ(vec2[2], 3);
+ EXPECT_EQ(vec2[3], 4);
+}
+
+TEST(vector, MoveConstructor3)
+{
+ Vector<int, 20> vec1 = {1, 2, 3, 4};
+ Vector<int, 1> vec2(std::move(vec1));
+
+ EXPECT_EQ(vec1.size(), 0);
+ EXPECT_EQ(vec2.size(), 4);
+ EXPECT_EQ(vec2[2], 3);
+}
+
+TEST(vector, MoveConstructor4)
+{
+ Vector<int, 5> vec1 = {1, 2, 3, 4};
+ Vector<int, 6> vec2(std::move(vec1));
+
+ EXPECT_EQ(vec1.size(), 0);
+ EXPECT_EQ(vec2.size(), 4);
+ EXPECT_EQ(vec2[3], 4);
+}
+
+TEST(vector, MoveAssignment)
+{
+ IntVector vec = {1, 2};
+ EXPECT_EQ(vec.size(), 2);
+ EXPECT_EQ(vec[0], 1);
+ EXPECT_EQ(vec[1], 2);
+
+ vec = IntVector({5});
+ EXPECT_EQ(vec.size(), 1);
+ EXPECT_EQ(vec[0], 5);
+}
+
+TEST(vector, CopyAssignment)
+{
+ IntVector vec1 = {1, 2, 3};
+ IntVector vec2 = {4, 5};
+ EXPECT_EQ(vec1.size(), 3);
+ EXPECT_EQ(vec2.size(), 2);
+
+ vec2 = vec1;
+ EXPECT_EQ(vec2.size(), 3);
+
+ vec1[0] = 7;
+ EXPECT_EQ(vec1[0], 7);
+ EXPECT_EQ(vec2[0], 1);
+}
+
+TEST(vector, Append)
+{
+ IntVector vec;
+ vec.append(3);
+ vec.append(6);
+ vec.append(7);
+ EXPECT_EQ(vec.size(), 3);
+ EXPECT_EQ(vec[0], 3);
+ EXPECT_EQ(vec[1], 6);
+ EXPECT_EQ(vec[2], 7);
+}
+
+TEST(vector, Fill)
+{
+ IntVector vec(5);
+ vec.fill(3);
+ EXPECT_EQ(vec.size(), 5);
+ EXPECT_EQ(vec[0], 3);
+ EXPECT_EQ(vec[1], 3);
+ EXPECT_EQ(vec[2], 3);
+ EXPECT_EQ(vec[3], 3);
+ EXPECT_EQ(vec[4], 3);
+}
+
+TEST(vector, FillIndices)
+{
+ IntVector vec(5, 0);
+ vec.fill_indices({1, 2}, 4);
+ EXPECT_EQ(vec[0], 0);
+ EXPECT_EQ(vec[1], 4);
+ EXPECT_EQ(vec[2], 4);
+ EXPECT_EQ(vec[3], 0);
+ EXPECT_EQ(vec[4], 0);
+}
+
+TEST(vector, Iterator)
+{
+ IntVector vec({1, 4, 9, 16});
+ int i = 1;
+ for (int value : vec) {
+ EXPECT_EQ(value, i * i);
+ i++;
+ }
+}
+
+TEST(vector, BecomeLarge)
+{
+ Vector<int, 4> vec;
+ for (int i = 0; i < 100; i++) {
+ vec.append(i * 5);
+ }
+ EXPECT_EQ(vec.size(), 100);
+ for (int i = 0; i < 100; i++) {
+ EXPECT_EQ(vec[i], i * 5);
+ }
+}
+
+IntVector return_by_value_helper()
+{
+ return IntVector({3, 5, 1});
+}
+
+TEST(vector, ReturnByValue)
+{
+ IntVector vec = return_by_value_helper();
+ EXPECT_EQ(vec.size(), 3);
+ EXPECT_EQ(vec[0], 3);
+ EXPECT_EQ(vec[1], 5);
+ EXPECT_EQ(vec[2], 1);
+}
+
+TEST(vector, VectorOfVectors_Append)
+{
+ Vector<IntVector> vec;
+ EXPECT_EQ(vec.size(), 0);
+
+ IntVector v({1, 2});
+ vec.append(v);
+ vec.append({7, 8});
+ EXPECT_EQ(vec.size(), 2);
+ EXPECT_EQ(vec[0][0], 1);
+ EXPECT_EQ(vec[0][1], 2);
+ EXPECT_EQ(vec[1][0], 7);
+ EXPECT_EQ(vec[1][1], 8);
+}
+
+TEST(vector, VectorOfVectors_Fill)
+{
+ Vector<IntVector> vec(3);
+ vec.fill({4, 5});
+
+ EXPECT_EQ(vec[0][0], 4);
+ EXPECT_EQ(vec[0][1], 5);
+ EXPECT_EQ(vec[1][0], 4);
+ EXPECT_EQ(vec[1][1], 5);
+ EXPECT_EQ(vec[2][0], 4);
+ EXPECT_EQ(vec[2][1], 5);
+}
+
+TEST(vector, RemoveLast)
+{
+ IntVector vec = {5, 6};
+ EXPECT_EQ(vec.size(), 2);
+ vec.remove_last();
+ EXPECT_EQ(vec.size(), 1);
+ vec.remove_last();
+ EXPECT_EQ(vec.size(), 0);
+}
+
+TEST(vector, Empty)
+{
+ IntVector vec;
+ EXPECT_TRUE(vec.empty());
+ vec.append(1);
+ EXPECT_FALSE(vec.empty());
+ vec.remove_last();
+ EXPECT_TRUE(vec.empty());
+}
+
+TEST(vector, RemoveReorder)
+{
+ IntVector vec = {4, 5, 6, 7};
+ vec.remove_and_reorder(1);
+ EXPECT_EQ(vec[0], 4);
+ EXPECT_EQ(vec[1], 7);
+ EXPECT_EQ(vec[2], 6);
+ vec.remove_and_reorder(2);
+ EXPECT_EQ(vec[0], 4);
+ EXPECT_EQ(vec[1], 7);
+ vec.remove_and_reorder(0);
+ EXPECT_EQ(vec[0], 7);
+ vec.remove_and_reorder(0);
+ EXPECT_TRUE(vec.empty());
+}
+
+TEST(vector, AllEqual_False)
+{
+ IntVector a = {1, 2, 3};
+ IntVector b = {1, 2, 4};
+ bool result = IntVector::all_equal(a, b);
+ EXPECT_FALSE(result);
+}
+
+TEST(vector, AllEqual_True)
+{
+ IntVector a = {4, 5, 6};
+ IntVector b = {4, 5, 6};
+ bool result = IntVector::all_equal(a, b);
+ EXPECT_TRUE(result);
+}
+
+TEST(vector, ExtendSmallVector)
+{
+ IntVector a = {2, 3, 4};
+ IntVector b = {11, 12};
+ b.extend(a);
+ EXPECT_EQ(b.size(), 5);
+ EXPECT_EQ(b[0], 11);
+ EXPECT_EQ(b[1], 12);
+ EXPECT_EQ(b[2], 2);
+ EXPECT_EQ(b[3], 3);
+ EXPECT_EQ(b[4], 4);
+}
+
+TEST(vector, ExtendArray)
+{
+ int array[] = {3, 4, 5, 6};
+
+ IntVector a;
+ a.extend(array, 2);
+
+ EXPECT_EQ(a.size(), 2);
+ EXPECT_EQ(a[0], 3);
+ EXPECT_EQ(a[1], 4);
+}
+
+TEST(vector, Last)
+{
+ IntVector a{3, 5, 7};
+ EXPECT_EQ(a.last(), 7);
+}
+
+TEST(vector, AppendNTimes)
+{
+ IntVector a;
+ a.append_n_times(5, 3);
+ a.append_n_times(2, 2);
+ EXPECT_EQ(a.size(), 5);
+ EXPECT_EQ(a[0], 5);
+ EXPECT_EQ(a[1], 5);
+ EXPECT_EQ(a[2], 5);
+ EXPECT_EQ(a[3], 2);
+ EXPECT_EQ(a[4], 2);
+}
+
+TEST(vector, UniquePtrValue)
+{
+ Vector<std::unique_ptr<int>> vec;
+ vec.append(std::unique_ptr<int>(new int()));
+ vec.append(std::unique_ptr<int>(new int()));
+ vec.append(std::unique_ptr<int>(new int()));
+
+ std::unique_ptr<int> &a = vec.last();
+ std::unique_ptr<int> b = vec.pop_last();
+ vec.remove_and_reorder(0);
+
+ UNUSED_VARS(a, b);
+}
diff --git a/tests/gtests/blenlib/CMakeLists.txt b/tests/gtests/blenlib/CMakeLists.txt
index 4e5811d140e..1f52886132f 100644
--- a/tests/gtests/blenlib/CMakeLists.txt
+++ b/tests/gtests/blenlib/CMakeLists.txt
@@ -38,28 +38,38 @@ else()
set(BLI_path_util_extra_libs "bf_blenlib;extern_wcwidth;${ZLIB_LIBRARIES}")
endif()
+BLENDER_TEST(BLI_array "bf_blenlib")
+BLENDER_TEST(BLI_array_ref "bf_blenlib")
BLENDER_TEST(BLI_array_store "bf_blenlib")
BLENDER_TEST(BLI_array_utils "bf_blenlib")
BLENDER_TEST(BLI_delaunay_2d "bf_blenlib")
-BLENDER_TEST(BLI_expr_pylike_eval "bf_blenlib")
BLENDER_TEST(BLI_edgehash "bf_blenlib")
+BLENDER_TEST(BLI_expr_pylike_eval "bf_blenlib")
BLENDER_TEST(BLI_ghash "bf_blenlib")
BLENDER_TEST(BLI_hash_mm2a "bf_blenlib")
BLENDER_TEST(BLI_heap "bf_blenlib")
BLENDER_TEST(BLI_heap_simple "bf_blenlib")
+BLENDER_TEST(BLI_index_range "bf_blenlib")
BLENDER_TEST(BLI_kdopbvh "bf_blenlib;bf_intern_numaapi")
BLENDER_TEST(BLI_linklist_lockfree "bf_blenlib;bf_intern_numaapi")
BLENDER_TEST(BLI_listbase "bf_blenlib")
+BLENDER_TEST(BLI_map "bf_blenlib")
BLENDER_TEST(BLI_math_base "bf_blenlib")
BLENDER_TEST(BLI_math_color "bf_blenlib")
BLENDER_TEST(BLI_math_geom "bf_blenlib")
BLENDER_TEST(BLI_memiter "bf_blenlib")
BLENDER_TEST(BLI_path_util "${BLI_path_util_extra_libs}")
BLENDER_TEST(BLI_polyfill_2d "bf_blenlib")
+BLENDER_TEST(BLI_set "bf_blenlib")
BLENDER_TEST(BLI_stack "bf_blenlib")
+BLENDER_TEST(BLI_stack_cxx "bf_blenlib")
BLENDER_TEST(BLI_string "bf_blenlib")
+BLENDER_TEST(BLI_string_map "bf_blenlib")
+BLENDER_TEST(BLI_string_ref "bf_blenlib")
BLENDER_TEST(BLI_string_utf8 "bf_blenlib")
BLENDER_TEST(BLI_task "bf_blenlib;bf_intern_numaapi")
+BLENDER_TEST(BLI_vector "bf_blenlib")
+BLENDER_TEST(BLI_vector_set "bf_blenlib")
BLENDER_TEST_PERFORMANCE(BLI_ghash_performance "bf_blenlib")
BLENDER_TEST_PERFORMANCE(BLI_task_performance "bf_blenlib")
diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt
index 4793010885e..2c9f91cca8e 100644
--- a/tests/python/CMakeLists.txt
+++ b/tests/python/CMakeLists.txt
@@ -32,24 +32,11 @@ file(MAKE_DIRECTORY ${TEST_OUT_DIR}/io_tests)
#~ message(FATAL_ERROR "CMake test directory not found!")
#~ endif()
-# all calls to blender use this
-# --env-system-scripts allows to run without the install target, but does
-# not work for all configurations.
-if(WITH_CYCLES OR (APPLE AND (${CMAKE_GENERATOR} MATCHES "Xcode")))
- set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup)
-else()
- set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts)
-endif()
-
-# for testing with valgrind prefix: valgrind --track-origins=yes --error-limit=no
-# set(TEST_BLENDER_EXE_BARE ${TEST_BLENDER_EXE})
-# set(TEST_BLENDER_EXE ${TEST_BLENDER_EXE} ${TEST_BLENDER_EXE_PARAMS} )
-
# Run Blender command with parameters.
function(add_blender_test testname)
add_test(
NAME ${testname}
- COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${ARGN}
+ COMMAND "${TEST_BLENDER_EXE}" ${TEST_BLENDER_EXE_PARAMS} ${ARGN}
)
# Don't fail tests on leaks since these often happen in external libraries
@@ -62,9 +49,7 @@ function(add_python_test testname testscript)
if(MSVC)
add_test(
NAME ${testname}
- COMMAND
- "$<TARGET_FILE_DIR:blender>/${BLENDER_VERSION_MAJOR}.${BLENDER_VERSION_MINOR}/python/bin/python$<$<CONFIG:Debug>:_d>"
- ${testscript} ${ARGN}
+ COMMAND ${TEST_PYTHON_EXE} ${testscript} ${ARGN}
)
else()
add_test(
@@ -497,61 +482,68 @@ if(WITH_CYCLES OR WITH_OPENGL_RENDER_TESTS)
elseif(NOT EXISTS "${TEST_SRC_DIR}/render/shader")
MESSAGE(STATUS "Disabling render tests because tests folder does not exist at ${TEST_SRC_DIR}")
else()
- macro(add_cycles_render_test subject)
- if(WITH_CYCLES)
+ set(render_tests
+ bsdf
+ denoise
+ denoise_animation
+ displacement
+ hair
+ image_colorspace
+ image_data_types
+ image_mapping
+ image_texture_limit
+ integrator
+ light
+ mesh
+ motion_blur
+ render_layer
+ reports
+ shader
+ shadow_catcher
+ sss
+ volume
+ )
+
+ if(WITH_OPENGL_RENDER_TESTS)
+ list(APPEND render_tests grease_pencil)
+ endif()
+
+ if(WITH_CYCLES)
+ foreach(render_test bake;${render_tests})
add_python_test(
- cycles_${subject}
+ cycles_${render_test}
${CMAKE_CURRENT_LIST_DIR}/cycles_render_tests.py
- -blender "$<TARGET_FILE:blender>"
- -testdir "${TEST_SRC_DIR}/render/${subject}"
+ -blender "${TEST_BLENDER_EXE}"
+ -testdir "${TEST_SRC_DIR}/render/${render_test}"
-idiff "${OPENIMAGEIO_IDIFF}"
-outdir "${TEST_OUT_DIR}/cycles"
)
- endif()
+ endforeach()
+ endif()
- if(WITH_OPENGL_RENDER_TESTS AND (NOT ${subject} MATCHES "bake"))
+ if(WITH_OPENGL_RENDER_TESTS)
+ foreach(render_test ${render_tests})
add_python_test(
- eevee_${subject}_test
+ eevee_${render_test}_test
${CMAKE_CURRENT_LIST_DIR}/eevee_render_tests.py
- -blender "$<TARGET_FILE:blender>"
- -testdir "${TEST_SRC_DIR}/render/${subject}"
+ -blender "${TEST_BLENDER_EXE}"
+ -testdir "${TEST_SRC_DIR}/render/${render_test}"
-idiff "${OPENIMAGEIO_IDIFF}"
-outdir "${TEST_OUT_DIR}/eevee"
)
+ endforeach()
+ foreach(render_test ${render_tests})
add_python_test(
- workbench_${subject}_test
+ workbench_${render_test}_test
${CMAKE_CURRENT_LIST_DIR}/workbench_render_tests.py
- -blender "$<TARGET_FILE:blender>"
- -testdir "${TEST_SRC_DIR}/render/${subject}"
+ -blender "${TEST_BLENDER_EXE}"
+ -testdir "${TEST_SRC_DIR}/render/${render_test}"
-idiff "${OPENIMAGEIO_IDIFF}"
-outdir "${TEST_OUT_DIR}/workbench"
)
- endif()
- endmacro()
- add_cycles_render_test(bake)
- add_cycles_render_test(bsdf)
- add_cycles_render_test(denoise)
- add_cycles_render_test(denoise_animation)
- add_cycles_render_test(displacement)
- if(WITH_OPENGL_RENDER_TESTS)
- add_cycles_render_test(grease_pencil)
+ endforeach()
endif()
- add_cycles_render_test(hair)
- add_cycles_render_test(image_colorspace)
- add_cycles_render_test(image_data_types)
- add_cycles_render_test(image_mapping)
- add_cycles_render_test(image_texture_limit)
- add_cycles_render_test(integrator)
- add_cycles_render_test(light)
- add_cycles_render_test(mesh)
- add_cycles_render_test(motion_blur)
- add_cycles_render_test(render_layer)
- add_cycles_render_test(reports)
- add_cycles_render_test(shader)
- add_cycles_render_test(shadow_catcher)
- add_cycles_render_test(sss)
- add_cycles_render_test(volume)
endif()
endif()
@@ -572,7 +564,7 @@ if(WITH_OPENGL_DRAW_TESTS)
add_python_test(
opengl_draw_${child}
${CMAKE_CURRENT_LIST_DIR}/opengl_draw_tests.py
- -blender "$<TARGET_FILE:blender>"
+ -blender "${TEST_BLENDER_EXE}"
-testdir "${child_path}"
-idiff "${OPENIMAGEIO_IDIFF}"
-outdir "${TEST_OUT_DIR}/opengl_draw"
@@ -595,7 +587,7 @@ if(WITH_ALEMBIC)
add_python_test(
alembic_tests
${CMAKE_CURRENT_LIST_DIR}/alembic_tests.py
- --blender "$<TARGET_FILE:blender>"
+ --blender "${TEST_BLENDER_EXE}"
--testdir "${TEST_SRC_DIR}/alembic"
--alembic-root "${ALEMBIC_ROOT_DIR}"
)
@@ -612,7 +604,7 @@ if(WITH_CODEC_FFMPEG)
add_python_test(
ffmpeg
${CMAKE_CURRENT_LIST_DIR}/ffmpeg_tests.py
- --blender "$<TARGET_FILE:blender>"
+ --blender "${TEST_BLENDER_EXE}"
--testdir "${TEST_SRC_DIR}/ffmpeg"
)
endif()
diff --git a/tests/python/bl_load_py_modules.py b/tests/python/bl_load_py_modules.py
index 3df0d6310dc..2252af7a02f 100644
--- a/tests/python/bl_load_py_modules.py
+++ b/tests/python/bl_load_py_modules.py
@@ -37,6 +37,8 @@ BLACKLIST = {
"io_export_dxf", # TODO, check on why this fails
'io_import_dxf', # Because of cydxfentity.so dependency
+ # Utility scripts not meant to be used as modules
+ os.path.join("power_sequencer", "scripts"),
# The unpacked wheel is only loaded when actually used, not directly on import:
os.path.join("io_blend_utils", "blender_bam-unpacked.whl"),
}
diff --git a/tests/python/bl_pyapi_idprop_datablock.py b/tests/python/bl_pyapi_idprop_datablock.py
index 5bb2155187c..c020f920eb2 100644
--- a/tests/python/bl_pyapi_idprop_datablock.py
+++ b/tests/python/bl_pyapi_idprop_datablock.py
@@ -232,8 +232,7 @@ def test_restrictions1():
bl_context = "render"
def draw(self, context):
- self.layout.prop_search(context.scene, "prop", bpy.data,
- "objects")
+ self.layout.prop_search(context.scene, "prop", bpy.data, "objects")
self.layout.template_ID(context.scene, "prop1")
self.layout.prop_search(context.scene, "prop2", bpy.data, "node_groups")
diff --git a/tests/python/eevee_render_tests.py b/tests/python/eevee_render_tests.py
index 0875e4b171a..a7130136d0a 100755
--- a/tests/python/eevee_render_tests.py
+++ b/tests/python/eevee_render_tests.py
@@ -18,17 +18,69 @@ def setup():
scene = bpy.context.scene
eevee = scene.eevee
+ eevee.use_soft_shadows = True
+
eevee.use_ssr = True
eevee.use_ssr_refraction = True
+
eevee.use_gtao = True
+ eevee.gtao_distance = 1
eevee.use_volumetric_shadows = True
eevee.volumetric_tile_size = '2'
for mat in bpy.data.materials:
- mat.use_screen_refraction = True
+ # This needs to be enabled case by case,
+ # otherwise we loose SSR and GTAO everywhere.
+ # mat.use_screen_refraction = True
mat.use_sss_translucency = True
+ cubemap = None
+ grid = None
+ # Does not work in edit mode
+ try:
+ # Simple probe setup
+ bpy.ops.object.lightprobe_add(type='CUBEMAP', location=(0.5, 0, 1.5))
+ cubemap = bpy.context.selected_objects[0]
+ cubemap.scale = (2.5,2.5,1.0)
+ cubemap.data.falloff = 0
+ cubemap.data.clip_start = 2.4
+
+ bpy.ops.object.lightprobe_add(type='GRID', location=(0, 0, 0.25))
+ grid = bpy.context.selected_objects[0]
+ grid.scale = (1.735,1.735,1.735)
+ grid.data.grid_resolution_x = 3
+ grid.data.grid_resolution_y = 3
+ grid.data.grid_resolution_z = 2
+ except:
+ pass
+
+ try:
+ # Try to only include the plane in reflections
+ plane = bpy.data.objects['Plane']
+
+ collection = bpy.data.collections.new("Reflection")
+ collection.objects.link(plane)
+ # Add all lights to light the plane
+ if invert == False:
+ for light in bpy.data.objects:
+ if light.type == 'LIGHT':
+ collection.objects.link(light)
+
+ # Add collection to the scene
+ scene.collection.children.link(collection)
+
+ cubemap.data.visibility_collection = collection
+ except:
+ pass
+
+ eevee.gi_diffuse_bounces = 1
+ eevee.gi_cubemap_resolution = '128'
+ eevee.gi_visibility_resolution = '16'
+ eevee.gi_irradiance_smoothing = 0
+
+ bpy.ops.scene.light_cache_bake()
+
# When run from inside Blender, render and exit.
try:
diff --git a/tests/python/ffmpeg_tests.py b/tests/python/ffmpeg_tests.py
index d6e7127c35a..92734b5bc7d 100755
--- a/tests/python/ffmpeg_tests.py
+++ b/tests/python/ffmpeg_tests.py
@@ -86,6 +86,15 @@ class FPSDetectionTest(AbstractFFmpegSequencerTest):
1.0,
places=2)
+ def test_T68091(self):
+ self.assertAlmostEqual(
+ self.get_movie_file_fps('T68091-invalid-nb_frames-at-10fps.mp4'),
+ 10.0,
+ places=2)
+ self.assertEqual(
+ self.get_movie_file_duration('T68091-invalid-nb_frames-at-10fps.mp4'),
+ 10)
+
def test_T54834(self):
self.assertEqual(
self.get_movie_file_duration('T54834.ogg'),